summaryrefslogtreecommitdiffstats
path: root/ansible_collections/community
diff options
context:
space:
mode:
Diffstat (limited to 'ansible_collections/community')
-rw-r--r--ansible_collections/community/aws/.github/workflows/all_green_ckeck.yml42
-rw-r--r--ansible_collections/community/aws/.github/workflows/changelog_and_linters.yml13
-rw-r--r--ansible_collections/community/aws/.github/workflows/galaxy-importer.yml12
-rw-r--r--ansible_collections/community/aws/.github/workflows/release-manual.yml35
-rw-r--r--ansible_collections/community/aws/.github/workflows/release-tag.yml32
-rw-r--r--ansible_collections/community/aws/.github/workflows/sanity.yml10
-rw-r--r--ansible_collections/community/aws/.github/workflows/units.yml10
-rw-r--r--ansible_collections/community/aws/.github/workflows/update-variables.yml17
-rw-r--r--ansible_collections/community/aws/.gitignore2
-rw-r--r--ansible_collections/community/aws/.yamllint15
-rw-r--r--ansible_collections/community/aws/CHANGELOG.rst377
-rw-r--r--ansible_collections/community/aws/CONTRIBUTING.md117
-rw-r--r--ansible_collections/community/aws/FILES.json1934
-rw-r--r--ansible_collections/community/aws/MANIFEST.json10
-rw-r--r--ansible_collections/community/aws/README.md41
-rw-r--r--ansible_collections/community/aws/changelogs/changelog.yaml521
-rw-r--r--ansible_collections/community/aws/changelogs/config.yaml33
-rw-r--r--ansible_collections/community/aws/docs/docsite/links.yml2
-rw-r--r--ansible_collections/community/aws/docs/docsite/rst/CHANGELOG.rst377
-rw-r--r--ansible_collections/community/aws/meta/runtime.yml458
-rw-r--r--ansible_collections/community/aws/plugins/connection/aws_ssm.py347
-rw-r--r--ansible_collections/community/aws/plugins/inventory/aws_mq.py297
-rw-r--r--ansible_collections/community/aws/plugins/module_utils/base.py48
-rw-r--r--ansible_collections/community/aws/plugins/module_utils/common.py8
-rw-r--r--ansible_collections/community/aws/plugins/module_utils/dynamodb.py120
-rw-r--r--ansible_collections/community/aws/plugins/module_utils/ec2.py66
-rw-r--r--ansible_collections/community/aws/plugins/module_utils/etag.py12
-rw-r--r--ansible_collections/community/aws/plugins/module_utils/modules.py19
-rw-r--r--ansible_collections/community/aws/plugins/module_utils/networkfirewall.py885
-rw-r--r--ansible_collections/community/aws/plugins/module_utils/opensearch.py111
-rw-r--r--ansible_collections/community/aws/plugins/module_utils/sns.py146
-rw-r--r--ansible_collections/community/aws/plugins/module_utils/transitgateway.py180
-rw-r--r--ansible_collections/community/aws/plugins/module_utils/wafv2.py100
-rw-r--r--ansible_collections/community/aws/plugins/modules/accessanalyzer_validate_policy_info.py82
-rw-r--r--ansible_collections/community/aws/plugins/modules/acm_certificate.py203
-rw-r--r--ansible_collections/community/aws/plugins/modules/acm_certificate_info.py81
-rw-r--r--ansible_collections/community/aws/plugins/modules/api_gateway.py295
-rw-r--r--ansible_collections/community/aws/plugins/modules/api_gateway_domain.py165
-rw-r--r--ansible_collections/community/aws/plugins/modules/api_gateway_info.py156
-rw-r--r--ansible_collections/community/aws/plugins/modules/application_autoscaling_policy.py262
-rw-r--r--ansible_collections/community/aws/plugins/modules/autoscaling_complete_lifecycle_action.py45
-rw-r--r--ansible_collections/community/aws/plugins/modules/autoscaling_instance_refresh.py130
-rw-r--r--ansible_collections/community/aws/plugins/modules/autoscaling_instance_refresh_info.py93
-rw-r--r--ansible_collections/community/aws/plugins/modules/autoscaling_launch_config.py370
-rw-r--r--ansible_collections/community/aws/plugins/modules/autoscaling_launch_config_find.py91
-rw-r--r--ansible_collections/community/aws/plugins/modules/autoscaling_launch_config_info.py75
-rw-r--r--ansible_collections/community/aws/plugins/modules/autoscaling_lifecycle_hook.py145
-rw-r--r--ansible_collections/community/aws/plugins/modules/autoscaling_policy.py335
-rw-r--r--ansible_collections/community/aws/plugins/modules/autoscaling_scheduled_action.py123
-rw-r--r--ansible_collections/community/aws/plugins/modules/aws_region_info.py98
-rw-r--r--ansible_collections/community/aws/plugins/modules/batch_compute_environment.py206
-rw-r--r--ansible_collections/community/aws/plugins/modules/batch_job_definition.py151
-rw-r--r--ansible_collections/community/aws/plugins/modules/batch_job_queue.py136
-rw-r--r--ansible_collections/community/aws/plugins/modules/cloudformation_exports_info.py57
-rw-r--r--ansible_collections/community/aws/plugins/modules/cloudformation_stack_set.py449
-rw-r--r--ansible_collections/community/aws/plugins/modules/cloudfront_distribution.py1224
-rw-r--r--ansible_collections/community/aws/plugins/modules/cloudfront_distribution_info.py466
-rw-r--r--ansible_collections/community/aws/plugins/modules/cloudfront_invalidation.py127
-rw-r--r--ansible_collections/community/aws/plugins/modules/cloudfront_origin_access_identity.py179
-rw-r--r--ansible_collections/community/aws/plugins/modules/cloudfront_response_headers_policy.py136
-rw-r--r--ansible_collections/community/aws/plugins/modules/codebuild_project.py326
-rw-r--r--ansible_collections/community/aws/plugins/modules/codecommit_repository.py75
-rw-r--r--ansible_collections/community/aws/plugins/modules/codepipeline.py106
-rw-r--r--ansible_collections/community/aws/plugins/modules/config_aggregation_authorization.py81
-rw-r--r--ansible_collections/community/aws/plugins/modules/config_aggregator.py162
-rw-r--r--ansible_collections/community/aws/plugins/modules/config_delivery_channel.py178
-rw-r--r--ansible_collections/community/aws/plugins/modules/config_recorder.py136
-rw-r--r--ansible_collections/community/aws/plugins/modules/config_rule.py216
-rw-r--r--ansible_collections/community/aws/plugins/modules/data_pipeline.py279
-rw-r--r--ansible_collections/community/aws/plugins/modules/directconnect_confirm_connection.py96
-rw-r--r--ansible_collections/community/aws/plugins/modules/directconnect_connection.py156
-rw-r--r--ansible_collections/community/aws/plugins/modules/directconnect_gateway.py172
-rw-r--r--ansible_collections/community/aws/plugins/modules/directconnect_link_aggregation_group.py245
-rw-r--r--ansible_collections/community/aws/plugins/modules/directconnect_virtual_interface.py268
-rw-r--r--ansible_collections/community/aws/plugins/modules/dms_endpoint.py278
-rw-r--r--ansible_collections/community/aws/plugins/modules/dms_replication_subnet_group.py94
-rw-r--r--ansible_collections/community/aws/plugins/modules/dynamodb_table.py577
-rw-r--r--ansible_collections/community/aws/plugins/modules/dynamodb_ttl.py79
-rw-r--r--ansible_collections/community/aws/plugins/modules/ec2_ami_copy.py106
-rw-r--r--ansible_collections/community/aws/plugins/modules/ec2_carrier_gateway.py259
-rw-r--r--ansible_collections/community/aws/plugins/modules/ec2_carrier_gateway_info.py159
-rw-r--r--ansible_collections/community/aws/plugins/modules/ec2_customer_gateway.py154
-rw-r--r--ansible_collections/community/aws/plugins/modules/ec2_customer_gateway_info.py77
-rw-r--r--ansible_collections/community/aws/plugins/modules/ec2_launch_template.py387
-rw-r--r--ansible_collections/community/aws/plugins/modules/ec2_placement_group.py161
-rw-r--r--ansible_collections/community/aws/plugins/modules/ec2_placement_group_info.py79
-rw-r--r--ansible_collections/community/aws/plugins/modules/ec2_snapshot_copy.py75
-rw-r--r--ansible_collections/community/aws/plugins/modules/ec2_transit_gateway.py210
-rw-r--r--ansible_collections/community/aws/plugins/modules/ec2_transit_gateway_info.py75
-rw-r--r--ansible_collections/community/aws/plugins/modules/ec2_transit_gateway_vpc_attachment.py148
-rw-r--r--ansible_collections/community/aws/plugins/modules/ec2_transit_gateway_vpc_attachment_info.py69
-rw-r--r--ansible_collections/community/aws/plugins/modules/ec2_vpc_egress_igw.py116
-rw-r--r--ansible_collections/community/aws/plugins/modules/ec2_vpc_nacl.py274
-rw-r--r--ansible_collections/community/aws/plugins/modules/ec2_vpc_nacl_info.py138
-rw-r--r--ansible_collections/community/aws/plugins/modules/ec2_vpc_peer.py235
-rw-r--r--ansible_collections/community/aws/plugins/modules/ec2_vpc_peering_info.py68
-rw-r--r--ansible_collections/community/aws/plugins/modules/ec2_vpc_vgw.py287
-rw-r--r--ansible_collections/community/aws/plugins/modules/ec2_vpc_vgw_info.py61
-rw-r--r--ansible_collections/community/aws/plugins/modules/ec2_vpc_vpn.py507
-rw-r--r--ansible_collections/community/aws/plugins/modules/ec2_vpc_vpn_info.py72
-rw-r--r--ansible_collections/community/aws/plugins/modules/ec2_win_password.py79
-rw-r--r--ansible_collections/community/aws/plugins/modules/ecs_attribute.py139
-rw-r--r--ansible_collections/community/aws/plugins/modules/ecs_cluster.py197
-rw-r--r--ansible_collections/community/aws/plugins/modules/ecs_ecr.py293
-rw-r--r--ansible_collections/community/aws/plugins/modules/ecs_service.py517
-rw-r--r--ansible_collections/community/aws/plugins/modules/ecs_service_info.py101
-rw-r--r--ansible_collections/community/aws/plugins/modules/ecs_tag.py124
-rw-r--r--ansible_collections/community/aws/plugins/modules/ecs_task.py319
-rw-r--r--ansible_collections/community/aws/plugins/modules/ecs_taskdefinition.py597
-rw-r--r--ansible_collections/community/aws/plugins/modules/ecs_taskdefinition_info.py40
-rw-r--r--ansible_collections/community/aws/plugins/modules/efs.py409
-rw-r--r--ansible_collections/community/aws/plugins/modules/efs_info.py158
-rw-r--r--ansible_collections/community/aws/plugins/modules/efs_tag.py98
-rw-r--r--ansible_collections/community/aws/plugins/modules/eks_cluster.py140
-rw-r--r--ansible_collections/community/aws/plugins/modules/eks_fargate_profile.py164
-rw-r--r--ansible_collections/community/aws/plugins/modules/eks_nodegroup.py439
-rw-r--r--ansible_collections/community/aws/plugins/modules/elasticache.py345
-rw-r--r--ansible_collections/community/aws/plugins/modules/elasticache_info.py85
-rw-r--r--ansible_collections/community/aws/plugins/modules/elasticache_parameter_group.py154
-rw-r--r--ansible_collections/community/aws/plugins/modules/elasticache_snapshot.py99
-rw-r--r--ansible_collections/community/aws/plugins/modules/elasticache_subnet_group.py85
-rw-r--r--ansible_collections/community/aws/plugins/modules/elasticbeanstalk_app.py82
-rw-r--r--ansible_collections/community/aws/plugins/modules/elb_classic_lb_info.py123
-rw-r--r--ansible_collections/community/aws/plugins/modules/elb_instance.py192
-rw-r--r--ansible_collections/community/aws/plugins/modules/elb_network_lb.py152
-rw-r--r--ansible_collections/community/aws/plugins/modules/elb_target.py143
-rw-r--r--ansible_collections/community/aws/plugins/modules/elb_target_group.py465
-rw-r--r--ansible_collections/community/aws/plugins/modules/elb_target_group_info.py93
-rw-r--r--ansible_collections/community/aws/plugins/modules/elb_target_info.py314
-rw-r--r--ansible_collections/community/aws/plugins/modules/glue_connection.py207
-rw-r--r--ansible_collections/community/aws/plugins/modules/glue_crawler.py225
-rw-r--r--ansible_collections/community/aws/plugins/modules/glue_job.py203
-rw-r--r--ansible_collections/community/aws/plugins/modules/iam_access_key.py317
-rw-r--r--ansible_collections/community/aws/plugins/modules/iam_access_key_info.py128
-rw-r--r--ansible_collections/community/aws/plugins/modules/iam_group.py433
-rw-r--r--ansible_collections/community/aws/plugins/modules/iam_managed_policy.py371
-rw-r--r--ansible_collections/community/aws/plugins/modules/iam_mfa_device_info.py104
-rw-r--r--ansible_collections/community/aws/plugins/modules/iam_password_policy.py213
-rw-r--r--ansible_collections/community/aws/plugins/modules/iam_role.py736
-rw-r--r--ansible_collections/community/aws/plugins/modules/iam_role_info.py282
-rw-r--r--ansible_collections/community/aws/plugins/modules/iam_saml_federation.py107
-rw-r--r--ansible_collections/community/aws/plugins/modules/iam_server_certificate.py231
-rw-r--r--ansible_collections/community/aws/plugins/modules/iam_server_certificate_info.py67
-rw-r--r--ansible_collections/community/aws/plugins/modules/inspector_target.py117
-rw-r--r--ansible_collections/community/aws/plugins/modules/kinesis_stream.py674
-rw-r--r--ansible_collections/community/aws/plugins/modules/lightsail.py205
-rw-r--r--ansible_collections/community/aws/plugins/modules/lightsail_snapshot.py205
-rw-r--r--ansible_collections/community/aws/plugins/modules/lightsail_static_ip.py53
-rw-r--r--ansible_collections/community/aws/plugins/modules/mq_broker.py628
-rw-r--r--ansible_collections/community/aws/plugins/modules/mq_broker_config.py224
-rw-r--r--ansible_collections/community/aws/plugins/modules/mq_broker_info.py121
-rw-r--r--ansible_collections/community/aws/plugins/modules/mq_user.py271
-rw-r--r--ansible_collections/community/aws/plugins/modules/mq_user_info.py153
-rw-r--r--ansible_collections/community/aws/plugins/modules/msk_cluster.py169
-rw-r--r--ansible_collections/community/aws/plugins/modules/msk_config.py47
-rw-r--r--ansible_collections/community/aws/plugins/modules/networkfirewall.py112
-rw-r--r--ansible_collections/community/aws/plugins/modules/networkfirewall_info.py53
-rw-r--r--ansible_collections/community/aws/plugins/modules/networkfirewall_policy.py122
-rw-r--r--ansible_collections/community/aws/plugins/modules/networkfirewall_policy_info.py49
-rw-r--r--ansible_collections/community/aws/plugins/modules/networkfirewall_rule_group.py172
-rw-r--r--ansible_collections/community/aws/plugins/modules/networkfirewall_rule_group_info.py72
-rw-r--r--ansible_collections/community/aws/plugins/modules/opensearch.py473
-rw-r--r--ansible_collections/community/aws/plugins/modules/opensearch_info.py80
-rw-r--r--ansible_collections/community/aws/plugins/modules/redshift.py397
-rw-r--r--ansible_collections/community/aws/plugins/modules/redshift_cross_region_snapshots.py97
-rw-r--r--ansible_collections/community/aws/plugins/modules/redshift_info.py66
-rw-r--r--ansible_collections/community/aws/plugins/modules/redshift_subnet_group.py106
-rw-r--r--ansible_collections/community/aws/plugins/modules/route53_wait.py185
-rw-r--r--ansible_collections/community/aws/plugins/modules/s3_bucket_info.py620
-rw-r--r--ansible_collections/community/aws/plugins/modules/s3_bucket_notification.py203
-rw-r--r--ansible_collections/community/aws/plugins/modules/s3_cors.py58
-rw-r--r--ansible_collections/community/aws/plugins/modules/s3_lifecycle.py297
-rw-r--r--ansible_collections/community/aws/plugins/modules/s3_logging.py106
-rw-r--r--ansible_collections/community/aws/plugins/modules/s3_metrics_configuration.py121
-rw-r--r--ansible_collections/community/aws/plugins/modules/s3_sync.py278
-rw-r--r--ansible_collections/community/aws/plugins/modules/s3_website.py121
-rw-r--r--ansible_collections/community/aws/plugins/modules/secretsmanager_secret.py185
-rw-r--r--ansible_collections/community/aws/plugins/modules/ses_identity.py229
-rw-r--r--ansible_collections/community/aws/plugins/modules/ses_identity_policy.py79
-rw-r--r--ansible_collections/community/aws/plugins/modules/ses_rule_set.py94
-rw-r--r--ansible_collections/community/aws/plugins/modules/sns.py89
-rw-r--r--ansible_collections/community/aws/plugins/modules/sns_topic.py326
-rw-r--r--ansible_collections/community/aws/plugins/modules/sns_topic_info.py41
-rw-r--r--ansible_collections/community/aws/plugins/modules/sqs_queue.py183
-rw-r--r--ansible_collections/community/aws/plugins/modules/ssm_inventory_info.py114
-rw-r--r--ansible_collections/community/aws/plugins/modules/ssm_parameter.py217
-rw-r--r--ansible_collections/community/aws/plugins/modules/stepfunctions_state_machine.py130
-rw-r--r--ansible_collections/community/aws/plugins/modules/stepfunctions_state_machine_execution.py119
-rw-r--r--ansible_collections/community/aws/plugins/modules/storagegateway_info.py103
-rw-r--r--ansible_collections/community/aws/plugins/modules/sts_assume_role.py172
-rw-r--r--ansible_collections/community/aws/plugins/modules/sts_session_token.py85
-rw-r--r--ansible_collections/community/aws/plugins/modules/waf_condition.py437
-rw-r--r--ansible_collections/community/aws/plugins/modules/waf_info.py44
-rw-r--r--ansible_collections/community/aws/plugins/modules/waf_rule.py241
-rw-r--r--ansible_collections/community/aws/plugins/modules/waf_web_acl.py229
-rw-r--r--ansible_collections/community/aws/plugins/modules/wafv2_ip_set.py152
-rw-r--r--ansible_collections/community/aws/plugins/modules/wafv2_ip_set_info.py69
-rw-r--r--ansible_collections/community/aws/plugins/modules/wafv2_resources.py80
-rw-r--r--ansible_collections/community/aws/plugins/modules/wafv2_resources_info.py57
-rw-r--r--ansible_collections/community/aws/plugins/modules/wafv2_rule_group.py182
-rw-r--r--ansible_collections/community/aws/plugins/modules/wafv2_rule_group_info.py71
-rw-r--r--ansible_collections/community/aws/plugins/modules/wafv2_web_acl.py200
-rw-r--r--ansible_collections/community/aws/plugins/modules/wafv2_web_acl_info.py55
-rw-r--r--ansible_collections/community/aws/pyproject.toml43
-rw-r--r--ansible_collections/community/aws/requirements.txt4
-rw-r--r--ansible_collections/community/aws/test-requirements.txt6
-rw-r--r--ansible_collections/community/aws/tests/config.yml2
-rw-r--r--ansible_collections/community/aws/tests/integration/constraints.txt10
-rw-r--r--ansible_collections/community/aws/tests/integration/requirements.txt2
-rw-r--r--ansible_collections/community/aws/tests/integration/requirements.yml8
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/accessanalyzer_validate_policy_info/tasks/main.yml8
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/acm_certificate/tasks/full_acm_test.yml76
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/acm_certificate/tasks/main.yml74
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/api_gateway/defaults/main.yml9
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/api_gateway/tasks/lookup.yml211
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/api_gateway/tasks/main.yml56
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/api_gateway/tasks/tagging.yml91
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/api_gateway/templates/minimal-swagger-api.yml.j22
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/api_gateway_domain/tasks/main.yml26
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/autoscaling_complete_lifecycle_action/tasks/env_cleanup.yml6
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/autoscaling_complete_lifecycle_action/tasks/env_setup.yml6
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/autoscaling_complete_lifecycle_action/tasks/main.yml7
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/autoscaling_complete_lifecycle_action/tasks/tests.yml16
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/autoscaling_instance_refresh/tasks/main.yml84
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/autoscaling_instance_refresh/tasks/refresh_and_cancel_three_times.yml14
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/autoscaling_launch_config/tasks/env_cleanup.yml2
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/autoscaling_launch_config/tasks/env_setup.yml2
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/autoscaling_launch_config/tasks/main.yml44
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/autoscaling_lifecycle_hook/main.yml50
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/autoscaling_lifecycle_hook/meta/main.yml1
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/autoscaling_lifecycle_hook/roles/ec2_asg_lifecycle_hook/tasks/create_update_delete.yml75
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/autoscaling_lifecycle_hook/roles/ec2_asg_lifecycle_hook/tasks/env_cleanup.yml57
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/autoscaling_lifecycle_hook/roles/ec2_asg_lifecycle_hook/tasks/env_setup.yml22
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/autoscaling_lifecycle_hook/roles/ec2_asg_lifecycle_hook/tasks/main.yml34
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/autoscaling_policy/tasks/main.yml66
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/autoscaling_scheduled_action/tasks/main.yml72
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/aws_region_info/main.yml5
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/aws_region_info/tasks/main.yml107
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/cloudformation_exports_info/tasks/main.yml6
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/cloudformation_stack_set/tasks/main.yml12
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/cloudfront_distribution/aliases3
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/cloudfront_distribution/tasks/main.yml286
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/cloudfront_invalidation/aliases3
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/cloudfront_invalidation/defaults/main.yml2
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/cloudfront_invalidation/tasks/main.yml85
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/cloudfront_origin_access_identity/aliases3
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/cloudfront_origin_access_identity/defaults/main.yml2
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/cloudfront_origin_access_identity/tasks/main.yml153
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/cloudfront_reponse_headers_policy/task/main.yml8
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/codebuild_project/tasks/description.yml22
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/codebuild_project/tasks/main.yml16
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/codebuild_project/tasks/tagging.yml38
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/codecommit_repository/tasks/main.yml42
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/codepipeline/tasks/main.yml16
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/config/defaults/main.yaml1
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/config/tasks/main.yaml124
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/config/templates/config-kms-policy.json.j251
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/connection/test_assume.yml16
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/connection/test_connection.yml29
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_addressing/aws_ssm_integration_test_setup.yml2
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_centos/aliases (renamed from ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_fedora/aliases)0
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_centos/aws_ssm_integration_test_setup.yml (renamed from ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_fedora/aws_ssm_integration_test_setup.yml)2
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_centos/aws_ssm_integration_test_teardown.yml (renamed from ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_fedora/aws_ssm_integration_test_teardown.yml)0
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_centos/meta/main.yml (renamed from ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_fedora/meta/main.yml)0
-rwxr-xr-xansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_centos/runme.sh (renamed from ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_fedora/runme.sh)0
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_cross_region/aws_ssm_integration_test_setup.yml2
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_encrypted_s3/aws_ssm_integration_test_setup.yml2
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_endpoint/aws_ssm_integration_test_setup.yml2
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_profile/aws_ssm_integration_test_setup.yml2
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_ssm_document/aws_ssm_integration_test_setup.yml2
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_vars/aws_ssm_integration_test_setup.yml2
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_windows/aliases2
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/dms_endpoint/tasks/main.yml6
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/dms_replication_subnet_group/tasks/main.yml6
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/dynamodb_table/aliases2
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/dynamodb_table/defaults/main.yml28
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/dynamodb_table/meta/main.yml5
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/dynamodb_table/tasks/main.yml294
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/dynamodb_table/tasks/test_pay_per_request.yml1
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/ec2_carrier_gateway/aliases9
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/ec2_carrier_gateway/defaults/main.yml3
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/ec2_carrier_gateway/meta/main.yml (renamed from ansible_collections/community/aws/tests/integration/targets/aws_region_info/meta/main.yml)0
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/ec2_carrier_gateway/tasks/main.yml167
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/ec2_carrier_gateway/tasks/tags.yml224
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/ec2_launch_template/meta/main.yml3
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/ec2_launch_template/tasks/instance-metadata.yml50
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/ec2_launch_template/tasks/main.yml6
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/ec2_launch_template/tasks/tags_and_vpc_settings.yml4
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/ec2_placement_group/tasks/env_cleanup.yml2
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/ec2_placement_group/tasks/env_setup.yml2
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/ec2_placement_group/tasks/main.yml36
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/ec2_transit_gateway/tasks/main.yml6
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/ec2_transit_gateway_vpc_attachment/tasks/main.yml6
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/ec2_vpc_egress_igw/tasks/main.yml6
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/ec2_vpc_nacl/tasks/main.yml6
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/ec2_vpc_peer/tasks/main.yml6
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/ec2_vpc_vgw/tasks/main.yml6
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/ec2_vpc_vpn/tasks/main.yml71
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/ecs_cluster/meta/main.yml5
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/ecs_cluster/tasks/01_create_requirements.yml8
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/ecs_cluster/tasks/20_ecs_service.yml101
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/ecs_cluster/tasks/99_terminate_everything.yml12
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/ecs_cluster/tasks/main.yml14
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/ecs_ecr/tasks/main.yml12
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/ecs_tag/tasks/main.yml22
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/efs/tasks/main.yml80
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/eks_cluster/tasks/full_test.yml36
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/eks_cluster/tasks/main.yml6
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/eks_fargate_profile/tasks/cleanup_eks_cluster.yml6
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/eks_fargate_profile/tasks/create_eks_cluster.yml6
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/eks_fargate_profile/tasks/main.yaml6
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/eks_nodegroup/aliases3
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/eks_nodegroup/tasks/cleanup.yml10
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/eks_nodegroup/tasks/dependecies.yml12
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/eks_nodegroup/tasks/full_test.yml17
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/eks_nodegroup/tasks/main.yml6
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/elasticache/tasks/main.yml14
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/elasticache_subnet_group/tasks/main.yml6
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/elasticbeanstalk_app/tasks/main.yml26
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/elb_classic_lb_info/tasks/main.yml56
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/elb_instance/tasks/cleanup_instances.yml4
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/elb_instance/tasks/cleanup_vpc.yml2
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/elb_instance/tasks/main.yml6
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/elb_instance/tasks/manage_asgs.yml2
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/elb_instance/tasks/setup_instances.yml4
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/elb_instance/tasks/setup_vpc.yml4
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/elb_network_lb/tasks/main.yml10
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/elb_network_lb/tasks/test_nlb_tags.yml4
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/elb_network_lb/tasks/test_nlb_with_asg.yml12
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/elb_target/files/ansible_lambda_target.py10
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/elb_target/tasks/alb_target.yml4
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/elb_target/tasks/ec2_target.yml8
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/elb_target/tasks/main.yml6
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/elb_target_info/tasks/main.yml28
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/glue_connection/tasks/main.yml6
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/glue_connection/tasks/test_connection_jdbc.yml12
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/glue_connection/tasks/test_connection_network.yml26
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/glue_crawler/aliases3
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/glue_crawler/tasks/main.yml24
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/glue_job/tasks/main.yml24
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/iam_access_key/aliases9
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/iam_access_key/defaults/main.yml2
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/iam_access_key/tasks/main.yml808
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/iam_group/aliases7
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/iam_group/defaults/main.yml3
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/iam_group/tasks/main.yml127
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/iam_managed_policy/aliases6
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/iam_managed_policy/defaults/main.yml2
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/iam_managed_policy/tasks/main.yml160
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/iam_password_policy/aliases8
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/iam_password_policy/meta/main.yml1
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/iam_password_policy/tasks/main.yaml107
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/iam_role/aliases9
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/iam_role/defaults/main.yml6
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/iam_role/files/deny-all-a.json13
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/iam_role/files/deny-all-b.json13
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/iam_role/files/deny-all.json12
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/iam_role/files/deny-assume.json10
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/iam_role/meta/main.yml1
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/boundary_policy.yml94
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/complex_role_creation.yml131
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/creation_deletion.yml404
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/description_update.yml148
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/inline_policy_update.yml48
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/main.yml119
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/max_session_update.yml71
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/parameter_checks.yml90
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/policy_update.yml250
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/role_removal.yml65
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/tags_update.yml341
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/iam_saml_federation/tasks/main.yml6
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/iam_server_certificate/tasks/main.yml6
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/inspector_target/tasks/main.yml18
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/aliases (renamed from ansible_collections/community/aws/tests/integration/targets/sts_assume_role/aliases)1
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/meta/main.yml (renamed from ansible_collections/community/aws/tests/integration/targets/iam_access_key/meta/main.yml)0
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/create_inventory_config.yml16
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/empty_inventory_config.yml9
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/populate_cache.yml32
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/setup_instance.yml29
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/tasks/find_broker.yml10
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/tasks/mq_instance_create.yml27
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/tasks/mq_instance_delete.yml13
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/test_invalid_aws_mq_inventory_config.yml9
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/test_inventory_cache.yml18
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/test_inventory_no_hosts.yml16
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/test_inventory_with_hostvars_prefix_suffix.yml30
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/test_populating_inventory.yml17
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/test_populating_inventory_with_constructed.yml27
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/vars/main.yml6
-rwxr-xr-xansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/runme.sh72
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/templates/inventory.j212
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/templates/inventory_with_cache.j211
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/templates/inventory_with_constructed.j213
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/templates/inventory_with_hostvars_prefix_suffix.j214
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/kinesis_stream/tasks/main.yml12
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/legacy_missing_tests/aliases3
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/lightsail/tasks/main.yml38
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/lightsail_snapshot/aliases (renamed from ansible_collections/community/aws/tests/integration/targets/aws_region_info/aliases)0
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/lightsail_snapshot/defaults/main.yml3
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/lightsail_snapshot/meta/main.yml (renamed from ansible_collections/community/aws/tests/integration/targets/iam_group/meta/main.yml)0
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/lightsail_snapshot/tasks/main.yml85
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/lightsail_static_ip/tasks/main.yml8
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/mq/aliases13
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/mq/defaults/main.yml9
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/mq/files/broker_cfg.1.xml17
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/mq/files/broker_cfg.1a.xml21
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/mq/files/broker_cfg.2.xml17
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/mq/meta/main.yml (renamed from ansible_collections/community/aws/tests/integration/targets/iam_managed_policy/meta/main.yml)0
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/mq/tasks/broker_cleanup.yml17
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/mq/tasks/broker_config_tests.yml82
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/mq/tasks/broker_delete_tests.yml43
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/mq/tasks/broker_tests.yml120
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/mq/tasks/broker_user_info_tests.yml65
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/mq/tasks/broker_user_tests.yml173
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/mq/tasks/env_cleanup.yml33
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/mq/tasks/env_setup.yml25
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/mq/tasks/main.yml35
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/mq/vars/main.yml1
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/msk_cluster-auth/tasks/main.yml12
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/msk_cluster-auth/tasks/test_create_auth.yml10
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/msk_cluster/tasks/main.yml12
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/msk_cluster/tasks/test_create.yml8
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/msk_cluster/tasks/test_delete.yml6
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/msk_cluster/tasks/test_update.yml6
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/msk_config/tasks/main.yml28
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/networkfirewall/tasks/main.yml6
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/networkfirewall_policy/meta/main.yml5
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/networkfirewall_policy/tasks/default_order.yml8
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/networkfirewall_policy/tasks/main.yml10
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/networkfirewall_policy/tasks/setup.yml3
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/networkfirewall_policy/tasks/strict_order.yml4
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/networkfirewall_rule_group/aliases2
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/networkfirewall_rule_group/meta/main.yml5
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/networkfirewall_rule_group/tasks/main.yml10
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/networkfirewall_rule_group/tasks/stateful.yml20
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/opensearch/meta/main.yml5
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/opensearch/tasks/main.yml8
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/opensearch/tasks/test_create_cert.yml11
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/opensearch/tasks/test_delete_resources.yml6
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/opensearch/tasks/test_delete_vpc_resources.yml4
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/opensearch/tasks/test_vpc_setup.yml4
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/redshift/tasks/main.yml20
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/redshift_subnet_group/tasks/main.yml6
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/route53_wait/aliases (renamed from ansible_collections/community/aws/tests/integration/targets/s3_bucket_info/aliases)0
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/route53_wait/tasks/main.yml245
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/s3_bucket_info/defaults/main.yml5
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/s3_bucket_info/meta/main.yml1
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/s3_bucket_info/tasks/basic.yml72
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/s3_bucket_info/tasks/bucket_ownership_controls.yml81
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/s3_bucket_info/tasks/main.yml30
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/s3_bucket_notification/files/mini_lambda.py10
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/s3_bucket_notification/tasks/main.yml6
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/s3_lifecycle/aliases1
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/s3_lifecycle/meta/main.yml5
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/s3_lifecycle/tasks/main.yml10
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/s3_logging/tasks/main.yml6
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/s3_metrics_configuration/tasks/main.yml8
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/s3_metrics_configuration/tasks/s3_metrics_info.yml6
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/s3_sync/tasks/main.yml24
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/secretsmanager_secret/aliases1
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/secretsmanager_secret/tasks/basic.yml82
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/secretsmanager_secret/tasks/main.yaml6
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/secretsmanager_secret/tasks/replication.yml14
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/secretsmanager_secret/tasks/rotation.yml18
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/ses_identity/tasks/assert_defaults.yaml4
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/ses_identity/tasks/main.yaml195
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/ses_identity_policy/tasks/main.yaml60
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/ses_rule_set/tasks/active-rule-set-tests.yaml70
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/ses_rule_set/tasks/cleanup-lock.yaml6
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/ses_rule_set/tasks/inactive-rule-set-tests.yaml32
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/ses_rule_set/tasks/main.yaml6
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/setup_botocore_pip/defaults/main.yml4
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/setup_connection_aws_ssm/defaults/main.yml12
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/setup_connection_aws_ssm/tasks/cleanup.yml9
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/setup_connection_aws_ssm/tasks/connection_args.yml6
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/setup_connection_aws_ssm/tasks/encryption.yml2
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/setup_connection_aws_ssm/tasks/main.yml6
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/setup_ec2_facts/defaults/main.yml11
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/setup_ec2_facts/meta/main.yml1
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/setup_ec2_facts/tasks/main.yml69
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/setup_sshkey/files/ec2-fingerprint.py20
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/sns/tasks/main.yml6
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/sns_topic/files/sns_topic_lambda/sns_topic_lambda.py5
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/sns_topic/tasks/main.yml12
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/sqs_queue/tasks/main.yml8
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/ssm_parameter/tasks/main.yml234
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/stepfunctions_state_machine/tasks/main.yml50
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/sts_assume_role/defaults/main.yml1
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/sts_assume_role/meta/main.yml1
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/sts_assume_role/tasks/main.yml332
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/sts_assume_role/templates/policy.json.j212
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/sts_session_token/tasks/main.yml12
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/waf_web_acl/tasks/main.yml170
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/wafv2/tasks/alb.yml2
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/wafv2/tasks/main.yml36
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/wafv2/tasks/rule_group.yml3
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/wafv2_ip_set/tasks/main.yml6
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/wafv2_rule_group/tasks/main.yml9
-rw-r--r--ansible_collections/community/aws/tests/integration/targets/wafv2_web_acl/tasks/main.yml6
-rw-r--r--ansible_collections/community/aws/tests/requirements.yml7
-rw-r--r--ansible_collections/community/aws/tests/sanity/ignore-2.11.txt1
-rw-r--r--ansible_collections/community/aws/tests/sanity/ignore-2.12.txt1
-rw-r--r--ansible_collections/community/aws/tests/sanity/ignore-2.13.txt1
-rw-r--r--ansible_collections/community/aws/tests/sanity/ignore-2.14.txt3
-rw-r--r--ansible_collections/community/aws/tests/sanity/ignore-2.15.txt3
-rw-r--r--ansible_collections/community/aws/tests/sanity/ignore-2.16.txt2
-rw-r--r--ansible_collections/community/aws/tests/sanity/ignore-2.17.txt2
-rw-r--r--ansible_collections/community/aws/tests/sanity/ignore-2.9.txt1
-rw-r--r--ansible_collections/community/aws/tests/sanity/requirements.yml5
-rw-r--r--ansible_collections/community/aws/tests/unit/compat/builtins.py9
-rw-r--r--ansible_collections/community/aws/tests/unit/compat/mock.py122
-rw-r--r--ansible_collections/community/aws/tests/unit/compat/unittest.py38
-rw-r--r--ansible_collections/community/aws/tests/unit/constraints.txt6
-rw-r--r--ansible_collections/community/aws/tests/unit/mock/loader.py17
-rw-r--r--ansible_collections/community/aws/tests/unit/mock/path.py5
-rw-r--r--ansible_collections/community/aws/tests/unit/mock/procenv.py19
-rw-r--r--ansible_collections/community/aws/tests/unit/mock/vault_helper.py16
-rw-r--r--ansible_collections/community/aws/tests/unit/mock/yaml_helper.py37
-rw-r--r--ansible_collections/community/aws/tests/unit/plugins/connection/test_aws_ssm.py95
-rw-r--r--ansible_collections/community/aws/tests/unit/plugins/inventory/__init__.py (renamed from ansible_collections/community/fortios/tests/unit/compat/__init__.py)0
-rw-r--r--ansible_collections/community/aws/tests/unit/plugins/inventory/test_aws_mq.py638
-rw-r--r--ansible_collections/community/aws/tests/unit/plugins/modules/conftest.py20
-rw-r--r--ansible_collections/community/aws/tests/unit/plugins/modules/test_acm_certificate.py97
-rw-r--r--ansible_collections/community/aws/tests/unit/plugins/modules/test_api_gateway.py43
-rw-r--r--ansible_collections/community/aws/tests/unit/plugins/modules/test_data_pipeline.py196
-rw-r--r--ansible_collections/community/aws/tests/unit/plugins/modules/test_directconnect_confirm_connection.py80
-rw-r--r--ansible_collections/community/aws/tests/unit/plugins/modules/test_directconnect_connection.py61
-rw-r--r--ansible_collections/community/aws/tests/unit/plugins/modules/test_directconnect_link_aggregation_group.py91
-rw-r--r--ansible_collections/community/aws/tests/unit/plugins/modules/test_directconnect_virtual_interface.py227
-rw-r--r--ansible_collections/community/aws/tests/unit/plugins/modules/test_ec2_vpc_vpn.py261
-rw-r--r--ansible_collections/community/aws/tests/unit/plugins/modules/test_ec2_win_password.py59
-rw-r--r--ansible_collections/community/aws/tests/unit/plugins/modules/test_iam_password_policy.py30
-rw-r--r--ansible_collections/community/aws/tests/unit/plugins/modules/test_opensearch.py109
-rw-r--r--ansible_collections/community/aws/tests/unit/plugins/modules/test_redshift_cross_region_snapshots.py37
-rw-r--r--ansible_collections/community/aws/tests/unit/plugins/modules/test_route53_wait.py240
-rw-r--r--ansible_collections/community/aws/tests/unit/plugins/modules/test_ssm_inventory_info.py117
-rw-r--r--ansible_collections/community/aws/tests/unit/plugins/modules/utils.py26
-rw-r--r--ansible_collections/community/aws/tests/unit/requirements.yml5
-rw-r--r--ansible_collections/community/aws/tox.ini104
-rw-r--r--ansible_collections/community/ciscosmb/CHANGELOG.rst17
-rw-r--r--ansible_collections/community/ciscosmb/FILES.json8
-rw-r--r--ansible_collections/community/ciscosmb/MANIFEST.json4
-rw-r--r--ansible_collections/community/ciscosmb/README.md36
-rw-r--r--ansible_collections/community/ciscosmb/changelogs/changelog.yaml17
-rw-r--r--ansible_collections/community/ciscosmb/plugins/cliconf/ciscosmb.py2
-rw-r--r--ansible_collections/community/crypto/.azure-pipelines/azure-pipelines.yml183
-rw-r--r--ansible_collections/community/crypto/.github/workflows/ansible-test.yml51
-rw-r--r--ansible_collections/community/crypto/.github/workflows/ee.yml8
-rw-r--r--ansible_collections/community/crypto/.github/workflows/import-galaxy.yml20
-rw-r--r--ansible_collections/community/crypto/.github/workflows/reuse.yml12
-rw-r--r--ansible_collections/community/crypto/CHANGELOG.md1350
-rw-r--r--ansible_collections/community/crypto/CHANGELOG.md.license (renamed from ansible_collections/community/docker/tests/sanity/ignore-2.10.txt.license)0
-rw-r--r--ansible_collections/community/crypto/CHANGELOG.rst209
-rw-r--r--ansible_collections/community/crypto/FILES.json532
-rw-r--r--ansible_collections/community/crypto/MANIFEST.json4
-rw-r--r--ansible_collections/community/crypto/README.md82
-rw-r--r--ansible_collections/community/crypto/changelogs/changelog.yaml212
-rw-r--r--ansible_collections/community/crypto/changelogs/config.yaml3
-rw-r--r--ansible_collections/community/crypto/docs/docsite/rst/guide_ownca.rst2
-rw-r--r--ansible_collections/community/crypto/docs/docsite/rst/guide_selfsigned.rst10
-rw-r--r--ansible_collections/community/crypto/plugins/action/openssl_privatekey_pipe.py20
-rw-r--r--ansible_collections/community/crypto/plugins/doc_fragments/acme.py26
-rw-r--r--ansible_collections/community/crypto/plugins/doc_fragments/module_certificate.py168
-rw-r--r--ansible_collections/community/crypto/plugins/doc_fragments/module_csr.py74
-rw-r--r--ansible_collections/community/crypto/plugins/doc_fragments/module_privatekey.py49
-rw-r--r--ansible_collections/community/crypto/plugins/doc_fragments/module_privatekey_convert.py4
-rw-r--r--ansible_collections/community/crypto/plugins/doc_fragments/name_encoding.py10
-rw-r--r--ansible_collections/community/crypto/plugins/filter/gpg_fingerprint.py68
-rw-r--r--ansible_collections/community/crypto/plugins/filter/openssl_csr_info.py65
-rw-r--r--ansible_collections/community/crypto/plugins/filter/openssl_privatekey_info.py33
-rw-r--r--ansible_collections/community/crypto/plugins/filter/openssl_publickey_info.py29
-rw-r--r--ansible_collections/community/crypto/plugins/filter/parse_serial.py66
-rw-r--r--ansible_collections/community/crypto/plugins/filter/to_serial.py68
-rw-r--r--ansible_collections/community/crypto/plugins/filter/x509_certificate_info.py68
-rw-r--r--ansible_collections/community/crypto/plugins/filter/x509_crl_info.py34
-rw-r--r--ansible_collections/community/crypto/plugins/lookup/gpg_fingerprint.py64
-rw-r--r--ansible_collections/community/crypto/plugins/module_utils/acme/account.py18
-rw-r--r--ansible_collections/community/crypto/plugins/module_utils/acme/acme.py10
-rw-r--r--ansible_collections/community/crypto/plugins/module_utils/acme/backend_cryptography.py52
-rw-r--r--ansible_collections/community/crypto/plugins/module_utils/acme/errors.py17
-rw-r--r--ansible_collections/community/crypto/plugins/module_utils/crypto/cryptography_support.py4
-rw-r--r--ansible_collections/community/crypto/plugins/module_utils/crypto/math.py76
-rw-r--r--ansible_collections/community/crypto/plugins/module_utils/crypto/module_backends/privatekey_convert.py2
-rw-r--r--ansible_collections/community/crypto/plugins/module_utils/crypto/module_backends/privatekey_info.py11
-rw-r--r--ansible_collections/community/crypto/plugins/module_utils/crypto/pem.py14
-rw-r--r--ansible_collections/community/crypto/plugins/module_utils/gnupg/cli.py64
-rw-r--r--ansible_collections/community/crypto/plugins/module_utils/openssh/backends/common.py10
-rw-r--r--ansible_collections/community/crypto/plugins/module_utils/openssh/backends/keypair_backend.py14
-rw-r--r--ansible_collections/community/crypto/plugins/module_utils/serial.py56
-rw-r--r--ansible_collections/community/crypto/plugins/modules/acme_account.py30
-rw-r--r--ansible_collections/community/crypto/plugins/modules/acme_account_info.py31
-rw-r--r--ansible_collections/community/crypto/plugins/modules/acme_certificate.py105
-rw-r--r--ansible_collections/community/crypto/plugins/modules/acme_certificate_revoke.py30
-rw-r--r--ansible_collections/community/crypto/plugins/modules/acme_challenge_cert_helper.py16
-rw-r--r--ansible_collections/community/crypto/plugins/modules/acme_inspect.py20
-rw-r--r--ansible_collections/community/crypto/plugins/modules/certificate_complete_chain.py4
-rw-r--r--ansible_collections/community/crypto/plugins/modules/crypto_info.py6
-rw-r--r--ansible_collections/community/crypto/plugins/modules/ecs_certificate.py161
-rw-r--r--ansible_collections/community/crypto/plugins/modules/ecs_domain.py96
-rw-r--r--ansible_collections/community/crypto/plugins/modules/get_certificate.py53
-rw-r--r--ansible_collections/community/crypto/plugins/modules/luks_device.py253
-rw-r--r--ansible_collections/community/crypto/plugins/modules/openssh_cert.py91
-rw-r--r--ansible_collections/community/crypto/plugins/modules/openssh_keypair.py50
-rw-r--r--ansible_collections/community/crypto/plugins/modules/openssl_csr.py10
-rw-r--r--ansible_collections/community/crypto/plugins/modules/openssl_csr_info.py79
-rw-r--r--ansible_collections/community/crypto/plugins/modules/openssl_csr_pipe.py29
-rw-r--r--ansible_collections/community/crypto/plugins/modules/openssl_dhparam.py20
-rw-r--r--ansible_collections/community/crypto/plugins/modules/openssl_pkcs12.py65
-rw-r--r--ansible_collections/community/crypto/plugins/modules/openssl_privatekey.py27
-rw-r--r--ansible_collections/community/crypto/plugins/modules/openssl_privatekey_convert.py8
-rw-r--r--ansible_collections/community/crypto/plugins/modules/openssl_privatekey_info.py58
-rw-r--r--ansible_collections/community/crypto/plugins/modules/openssl_privatekey_pipe.py43
-rw-r--r--ansible_collections/community/crypto/plugins/modules/openssl_publickey.py24
-rw-r--r--ansible_collections/community/crypto/plugins/modules/openssl_publickey_info.py39
-rw-r--r--ansible_collections/community/crypto/plugins/modules/openssl_signature.py8
-rw-r--r--ansible_collections/community/crypto/plugins/modules/openssl_signature_info.py10
-rw-r--r--ansible_collections/community/crypto/plugins/modules/x509_certificate.py16
-rw-r--r--ansible_collections/community/crypto/plugins/modules/x509_certificate_info.py88
-rw-r--r--ansible_collections/community/crypto/plugins/modules/x509_certificate_pipe.py28
-rw-r--r--ansible_collections/community/crypto/plugins/modules/x509_crl.py179
-rw-r--r--ansible_collections/community/crypto/plugins/modules/x509_crl_info.py43
-rw-r--r--ansible_collections/community/crypto/plugins/plugin_utils/gnupg.py51
-rw-r--r--ansible_collections/community/crypto/tests/integration/targets/acme_challenge_cert_helper/tasks/main.yml2
-rw-r--r--ansible_collections/community/crypto/tests/integration/targets/filter_gpg_fingerprint/aliases6
-rw-r--r--ansible_collections/community/crypto/tests/integration/targets/filter_gpg_fingerprint/meta/main.yml9
-rw-r--r--ansible_collections/community/crypto/tests/integration/targets/filter_gpg_fingerprint/tasks/main.yml80
-rw-r--r--ansible_collections/community/crypto/tests/integration/targets/filter_parse_serial/aliases5
-rw-r--r--ansible_collections/community/crypto/tests/integration/targets/filter_parse_serial/tasks/main.yml62
-rw-r--r--ansible_collections/community/crypto/tests/integration/targets/filter_to_serial/aliases5
-rw-r--r--ansible_collections/community/crypto/tests/integration/targets/filter_to_serial/tasks/main.yml35
-rw-r--r--ansible_collections/community/crypto/tests/integration/targets/get_certificate/tests/validate.yml6
-rw-r--r--ansible_collections/community/crypto/tests/integration/targets/lookup_gpg_fingerprint/aliases6
-rw-r--r--ansible_collections/community/crypto/tests/integration/targets/lookup_gpg_fingerprint/meta/main.yml9
-rw-r--r--ansible_collections/community/crypto/tests/integration/targets/lookup_gpg_fingerprint/tasks/main.yml93
-rw-r--r--ansible_collections/community/crypto/tests/integration/targets/luks_device/tasks/tests/keyslot-create-destroy.yml206
-rw-r--r--ansible_collections/community/crypto/tests/integration/targets/luks_device/tasks/tests/keyslot-duplicate.yml40
-rw-r--r--ansible_collections/community/crypto/tests/integration/targets/luks_device/tasks/tests/keyslot-options.yml79
-rw-r--r--ansible_collections/community/crypto/tests/integration/targets/luks_device/tasks/tests/performance.yml6
-rw-r--r--ansible_collections/community/crypto/tests/integration/targets/luks_device/vars/Alpine.yml1
-rw-r--r--ansible_collections/community/crypto/tests/integration/targets/openssh_cert/tests/idempotency.yml2
-rw-r--r--ansible_collections/community/crypto/tests/integration/targets/openssh_keypair/tests/cryptography_backend.yml2
-rw-r--r--ansible_collections/community/crypto/tests/integration/targets/openssh_keypair/tests/options.yml10
-rw-r--r--ansible_collections/community/crypto/tests/integration/targets/openssh_keypair/tests/regenerate.yml41
-rw-r--r--ansible_collections/community/crypto/tests/integration/targets/openssl_pkcs12/tasks/main.yml14
-rw-r--r--ansible_collections/community/crypto/tests/integration/targets/openssl_privatekey/tests/validate.yml2
-rw-r--r--ansible_collections/community/crypto/tests/integration/targets/openssl_publickey/tests/validate.yml2
-rw-r--r--ansible_collections/community/crypto/tests/integration/targets/prepare_jinja2_compat/filter_plugins/ansible_compatibility.py20
-rw-r--r--ansible_collections/community/crypto/tests/integration/targets/prepare_jinja2_compat/filter_plugins/jinja_compatibility.py11
-rw-r--r--ansible_collections/community/crypto/tests/integration/targets/setup_gnupg/meta/main.yml7
-rw-r--r--ansible_collections/community/crypto/tests/integration/targets/setup_gnupg/tasks/main.yml30
-rw-r--r--ansible_collections/community/crypto/tests/integration/targets/setup_gnupg/vars/Alpine.yml8
-rw-r--r--ansible_collections/community/crypto/tests/integration/targets/setup_gnupg/vars/CentOS-6.yml7
-rw-r--r--ansible_collections/community/crypto/tests/integration/targets/setup_gnupg/vars/Darwin.yml7
-rw-r--r--ansible_collections/community/crypto/tests/integration/targets/setup_gnupg/vars/RedHat.yml7
-rw-r--r--ansible_collections/community/crypto/tests/integration/targets/setup_gnupg/vars/default.yml7
-rw-r--r--ansible_collections/community/crypto/tests/integration/targets/setup_python_info/vars/main.yml2
-rw-r--r--ansible_collections/community/crypto/tests/integration/targets/x509_certificate/tests/validate_ownca.yml2
-rw-r--r--ansible_collections/community/crypto/tests/integration/targets/x509_certificate/tests/validate_selfsigned.yml4
-rw-r--r--ansible_collections/community/crypto/tests/integration/targets/x509_crl/tasks/impl.yml14
-rwxr-xr-xansible_collections/community/crypto/tests/sanity/extra/extra-docs.py2
-rw-r--r--ansible_collections/community/crypto/tests/sanity/ignore-2.10.txt15
-rw-r--r--ansible_collections/community/crypto/tests/sanity/ignore-2.11.txt14
-rw-r--r--ansible_collections/community/crypto/tests/sanity/ignore-2.12.txt14
-rw-r--r--ansible_collections/community/crypto/tests/sanity/ignore-2.13.txt12
-rw-r--r--ansible_collections/community/crypto/tests/sanity/ignore-2.14.txt12
-rw-r--r--ansible_collections/community/crypto/tests/sanity/ignore-2.16.txt1
-rw-r--r--ansible_collections/community/crypto/tests/sanity/ignore-2.17.txt2
-rw-r--r--ansible_collections/community/crypto/tests/sanity/ignore-2.17.txt.license (renamed from ansible_collections/community/docker/tests/sanity/ignore-2.9.txt.license)0
-rw-r--r--ansible_collections/community/crypto/tests/sanity/ignore-2.9.txt15
-rw-r--r--ansible_collections/community/crypto/tests/unit/plugins/module_utils/crypto/test_pem.py67
-rw-r--r--ansible_collections/community/crypto/tests/unit/plugins/modules/test_luks_device.py30
-rwxr-xr-xansible_collections/community/crypto/tests/utils/shippable/shippable.sh13
-rw-r--r--ansible_collections/community/digitalocean/.github/workflows/ansible-test-integration.yml36
-rw-r--r--ansible_collections/community/digitalocean/.github/workflows/ansible-test-sanity.yml45
-rw-r--r--ansible_collections/community/digitalocean/.github/workflows/ansible-test-unit.yml44
-rw-r--r--ansible_collections/community/digitalocean/.github/workflows/black.yml11
-rw-r--r--ansible_collections/community/digitalocean/.github/workflows/pull-request-integration.yml197
-rw-r--r--ansible_collections/community/digitalocean/.gitignore3
-rw-r--r--ansible_collections/community/digitalocean/.tool-versions1
-rw-r--r--ansible_collections/community/digitalocean/CHANGELOG.rst53
-rw-r--r--ansible_collections/community/digitalocean/CODEOWNERS1
-rw-r--r--ansible_collections/community/digitalocean/FILES.json189
-rw-r--r--ansible_collections/community/digitalocean/MANIFEST.json7
-rw-r--r--ansible_collections/community/digitalocean/README.md4
-rw-r--r--ansible_collections/community/digitalocean/changelogs/changelog.yaml65
-rw-r--r--ansible_collections/community/digitalocean/plugins/doc_fragments/digital_ocean.py4
-rw-r--r--ansible_collections/community/digitalocean/plugins/inventory/digitalocean.py16
-rw-r--r--ansible_collections/community/digitalocean/plugins/module_utils/digital_ocean.py40
-rw-r--r--ansible_collections/community/digitalocean/plugins/modules/digital_ocean.py4
-rw-r--r--ansible_collections/community/digitalocean/plugins/modules/digital_ocean_block_storage.py4
-rw-r--r--ansible_collections/community/digitalocean/plugins/modules/digital_ocean_cdn_endpoints.py4
-rw-r--r--ansible_collections/community/digitalocean/plugins/modules/digital_ocean_cdn_endpoints_info.py2
-rw-r--r--ansible_collections/community/digitalocean/plugins/modules/digital_ocean_database.py7
-rw-r--r--ansible_collections/community/digitalocean/plugins/modules/digital_ocean_database_info.py2
-rw-r--r--ansible_collections/community/digitalocean/plugins/modules/digital_ocean_domain.py9
-rw-r--r--ansible_collections/community/digitalocean/plugins/modules/digital_ocean_domain_record.py22
-rw-r--r--ansible_collections/community/digitalocean/plugins/modules/digital_ocean_domain_record_info.py3
-rw-r--r--ansible_collections/community/digitalocean/plugins/modules/digital_ocean_droplet.py7
-rw-r--r--ansible_collections/community/digitalocean/plugins/modules/digital_ocean_droplet_info.py1
-rw-r--r--ansible_collections/community/digitalocean/plugins/modules/digital_ocean_firewall.py2
-rw-r--r--ansible_collections/community/digitalocean/plugins/modules/digital_ocean_floating_ip.py4
-rw-r--r--ansible_collections/community/digitalocean/plugins/modules/digital_ocean_kubernetes.py156
-rw-r--r--ansible_collections/community/digitalocean/plugins/modules/digital_ocean_kubernetes_info.py7
-rw-r--r--ansible_collections/community/digitalocean/plugins/modules/digital_ocean_load_balancer.py8
-rw-r--r--ansible_collections/community/digitalocean/plugins/modules/digital_ocean_monitoring_alerts.py2
-rw-r--r--ansible_collections/community/digitalocean/plugins/modules/digital_ocean_monitoring_alerts_info.py1
-rw-r--r--ansible_collections/community/digitalocean/plugins/modules/digital_ocean_project.py2
-rw-r--r--ansible_collections/community/digitalocean/plugins/modules/digital_ocean_project_info.py1
-rw-r--r--ansible_collections/community/digitalocean/plugins/modules/digital_ocean_project_resource_info.py104
-rw-r--r--ansible_collections/community/digitalocean/plugins/modules/digital_ocean_snapshot.py1
-rw-r--r--ansible_collections/community/digitalocean/plugins/modules/digital_ocean_spaces.py1
-rw-r--r--ansible_collections/community/digitalocean/plugins/modules/digital_ocean_spaces_info.py1
-rw-r--r--ansible_collections/community/digitalocean/plugins/modules/digital_ocean_sshkey.py1
-rw-r--r--ansible_collections/community/digitalocean/plugins/modules/digital_ocean_vpc.py1
-rw-r--r--ansible_collections/community/digitalocean/plugins/modules/digital_ocean_vpc_info.py1
-rw-r--r--ansible_collections/community/digitalocean/poetry.lock2491
-rw-r--r--ansible_collections/community/digitalocean/pyproject.toml27
-rwxr-xr-xansible_collections/community/digitalocean/scripts/inventory/digital_ocean.py1
-rw-r--r--ansible_collections/community/digitalocean/tests/integration/integration_config.yml.template1
-rw-r--r--ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_block_storage/defaults/main.yml2
-rw-r--r--ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_cdn_endpoints/aliases1
-rw-r--r--ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_domain_record_info/aliases1
-rw-r--r--ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_droplet/defaults/main.yml4
-rw-r--r--ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_droplet/tasks/main.yml8
-rw-r--r--ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_floating_ip/defaults/main.yml4
-rw-r--r--ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_kubernetes/defaults/main.yml9
-rw-r--r--ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_kubernetes/tasks/main.yml45
-rw-r--r--ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_kubernetes_info/defaults/main.yml4
-rw-r--r--ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_kubernetes_info/tasks/main.yml3
-rw-r--r--ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_load_balancer/defaults/main.yml4
-rw-r--r--ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_monitoring_alerts/aliases1
-rw-r--r--ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_monitoring_alerts/defaults/main.yml4
-rw-r--r--ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_project_resource_info/aliases1
-rw-r--r--ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_project_resource_info/defaults/main.yml2
-rw-r--r--ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_project_resource_info/tasks/main.yml156
-rw-r--r--ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_snapshot/defaults/main.yml6
-rw-r--r--ansible_collections/community/digitalocean/tests/unit/plugins/inventory/test_digitalocean.py4
-rw-r--r--ansible_collections/community/digitalocean/tests/unit/plugins/modules/test_digital_ocean_kubernetes.py46
-rw-r--r--ansible_collections/community/dns/.github/workflows/ansible-test.yml18
-rw-r--r--ansible_collections/community/dns/.github/workflows/check-psl.yml2
-rw-r--r--ansible_collections/community/dns/.github/workflows/ee.yml8
-rw-r--r--ansible_collections/community/dns/.github/workflows/extra-tests.yml6
-rw-r--r--ansible_collections/community/dns/.github/workflows/import-galaxy.yml78
-rw-r--r--ansible_collections/community/dns/.github/workflows/reuse.yml11
-rw-r--r--ansible_collections/community/dns/CHANGELOG.md1013
-rw-r--r--ansible_collections/community/dns/CHANGELOG.md.license (renamed from ansible_collections/community/general/tests/sanity/ignore-2.11.txt.license)0
-rw-r--r--ansible_collections/community/dns/CHANGELOG.rst214
-rw-r--r--ansible_collections/community/dns/FILES.json431
-rw-r--r--ansible_collections/community/dns/MANIFEST.json4
-rw-r--r--ansible_collections/community/dns/README.md13
-rw-r--r--ansible_collections/community/dns/changelogs/changelog.yaml194
-rw-r--r--ansible_collections/community/dns/changelogs/config.yaml3
-rw-r--r--ansible_collections/community/dns/docs/docsite/rst/filter_guide.rst32
-rw-r--r--ansible_collections/community/dns/docs/docsite/rst/hetzner_guide.rst76
-rw-r--r--ansible_collections/community/dns/docs/docsite/rst/hosttech_guide.rst50
-rw-r--r--ansible_collections/community/dns/plugins/doc_fragments/filters.py12
-rw-r--r--ansible_collections/community/dns/plugins/doc_fragments/hetzner.py35
-rw-r--r--ansible_collections/community/dns/plugins/doc_fragments/hosttech.py41
-rw-r--r--ansible_collections/community/dns/plugins/doc_fragments/inventory_records.py12
-rw-r--r--ansible_collections/community/dns/plugins/doc_fragments/module_record.py14
-rw-r--r--ansible_collections/community/dns/plugins/doc_fragments/module_record_info.py16
-rw-r--r--ansible_collections/community/dns/plugins/doc_fragments/module_record_set.py37
-rw-r--r--ansible_collections/community/dns/plugins/doc_fragments/module_record_set_info.py16
-rw-r--r--ansible_collections/community/dns/plugins/doc_fragments/module_record_sets.py26
-rw-r--r--ansible_collections/community/dns/plugins/doc_fragments/module_zone_info.py4
-rw-r--r--ansible_collections/community/dns/plugins/doc_fragments/options.py22
-rw-r--r--ansible_collections/community/dns/plugins/inventory/hetzner_dns_records.py6
-rw-r--r--ansible_collections/community/dns/plugins/inventory/hosttech_dns_records.py6
-rw-r--r--ansible_collections/community/dns/plugins/lookup/lookup.py210
-rw-r--r--ansible_collections/community/dns/plugins/lookup/lookup_as_dict.py497
-rw-r--r--ansible_collections/community/dns/plugins/module_utils/conversion/txt.py4
-rw-r--r--ansible_collections/community/dns/plugins/module_utils/dnspython_records.py135
-rw-r--r--ansible_collections/community/dns/plugins/module_utils/http.py3
-rw-r--r--ansible_collections/community/dns/plugins/module_utils/ips.py37
-rw-r--r--ansible_collections/community/dns/plugins/module_utils/resolver.py187
-rw-r--r--ansible_collections/community/dns/plugins/module_utils/zone_record_helpers.py2
-rw-r--r--ansible_collections/community/dns/plugins/modules/hetzner_dns_record.py1
-rw-r--r--ansible_collections/community/dns/plugins/modules/hetzner_dns_record_info.py9
-rw-r--r--ansible_collections/community/dns/plugins/modules/hetzner_dns_record_set.py6
-rw-r--r--ansible_collections/community/dns/plugins/modules/hetzner_dns_record_set_info.py13
-rw-r--r--ansible_collections/community/dns/plugins/modules/hetzner_dns_record_sets.py1
-rw-r--r--ansible_collections/community/dns/plugins/modules/hetzner_dns_zone_info.py2
-rw-r--r--ansible_collections/community/dns/plugins/modules/hosttech_dns_record.py1
-rw-r--r--ansible_collections/community/dns/plugins/modules/hosttech_dns_record_info.py7
-rw-r--r--ansible_collections/community/dns/plugins/modules/hosttech_dns_record_set.py5
-rw-r--r--ansible_collections/community/dns/plugins/modules/hosttech_dns_record_set_info.py11
-rw-r--r--ansible_collections/community/dns/plugins/modules/hosttech_dns_record_sets.py1
-rw-r--r--ansible_collections/community/dns/plugins/modules/hosttech_dns_records.py1
-rw-r--r--ansible_collections/community/dns/plugins/modules/hosttech_dns_zone_info.py10
-rw-r--r--ansible_collections/community/dns/plugins/modules/nameserver_info.py168
-rw-r--r--ansible_collections/community/dns/plugins/modules/nameserver_record_info.py568
-rw-r--r--ansible_collections/community/dns/plugins/modules/wait_for_txt.py193
-rw-r--r--ansible_collections/community/dns/plugins/plugin_utils/inventory/records.py15
-rw-r--r--ansible_collections/community/dns/plugins/plugin_utils/ips.py27
-rw-r--r--ansible_collections/community/dns/plugins/plugin_utils/resolver.py49
-rw-r--r--ansible_collections/community/dns/plugins/public_suffix_list.dat4214
-rw-r--r--ansible_collections/community/dns/tests/ee/roles/wait_for_txt/tasks/main.yml8
-rwxr-xr-xansible_collections/community/dns/tests/integration/replace-requirements.sh10
-rw-r--r--ansible_collections/community/dns/tests/integration/requirements-stable-2.10.txt7
-rw-r--r--ansible_collections/community/dns/tests/integration/requirements-stable-2.9.txt7
-rw-r--r--ansible_collections/community/dns/tests/integration/requirements.txt7
-rw-r--r--ansible_collections/community/dns/tests/integration/targets/lookup_lookup/aliases5
-rw-r--r--ansible_collections/community/dns/tests/integration/targets/lookup_lookup/tasks/main.yml26
-rw-r--r--ansible_collections/community/dns/tests/integration/targets/lookup_lookup_as_dict/aliases5
-rw-r--r--ansible_collections/community/dns/tests/integration/targets/lookup_lookup_as_dict/tasks/main.yml31
-rw-r--r--ansible_collections/community/dns/tests/integration/targets/nameserver_info/tasks/main.yml78
-rw-r--r--ansible_collections/community/dns/tests/integration/targets/nameserver_record_info/tasks/main.yml56
-rw-r--r--ansible_collections/community/dns/tests/integration/targets/wait_for_txt/aliases1
-rw-r--r--ansible_collections/community/dns/tests/integration/targets/wait_for_txt/tasks/main.yml2
-rwxr-xr-xansible_collections/community/dns/tests/sanity/extra/extra-docs.py2
-rw-r--r--ansible_collections/community/dns/tests/sanity/ignore-2.10.txt7
-rw-r--r--ansible_collections/community/dns/tests/sanity/ignore-2.11.txt4
-rw-r--r--ansible_collections/community/dns/tests/sanity/ignore-2.12.txt4
-rw-r--r--ansible_collections/community/dns/tests/sanity/ignore-2.13.txt4
-rw-r--r--ansible_collections/community/dns/tests/sanity/ignore-2.14.txt4
-rw-r--r--ansible_collections/community/dns/tests/sanity/ignore-2.17.txt1
-rw-r--r--ansible_collections/community/dns/tests/sanity/ignore-2.17.txt.license (renamed from ansible_collections/community/general/tests/sanity/ignore-2.12.txt.license)0
-rw-r--r--ansible_collections/community/dns/tests/sanity/ignore-2.9.txt7
-rw-r--r--ansible_collections/community/dns/tests/unit/plugins/inventory/test_hetzner_dns_records.py3
-rw-r--r--ansible_collections/community/dns/tests/unit/plugins/inventory/test_hosttech_dns_records.py3
-rw-r--r--ansible_collections/community/dns/tests/unit/plugins/lookup/test_lookup.py498
-rw-r--r--ansible_collections/community/dns/tests/unit/plugins/lookup/test_lookup_as_dict.py461
-rw-r--r--ansible_collections/community/dns/tests/unit/plugins/module_utils/conversion/test_txt.py10
-rw-r--r--ansible_collections/community/dns/tests/unit/plugins/module_utils/resolver_helper.py18
-rw-r--r--ansible_collections/community/dns/tests/unit/plugins/module_utils/test_dnspython_records.py376
-rw-r--r--ansible_collections/community/dns/tests/unit/plugins/module_utils/test_ips.py62
-rw-r--r--ansible_collections/community/dns/tests/unit/plugins/module_utils/test_resolver.py541
-rw-r--r--ansible_collections/community/dns/tests/unit/plugins/modules/test_nameserver_info.py395
-rw-r--r--ansible_collections/community/dns/tests/unit/plugins/modules/test_nameserver_record_info.py592
-rw-r--r--ansible_collections/community/dns/tests/unit/plugins/modules/test_wait_for_txt.py58
-rw-r--r--ansible_collections/community/dns/tests/unit/plugins/plugin_utils/test_ips.py39
-rw-r--r--ansible_collections/community/dns/tests/unit/plugins/plugin_utils/test_resolver.py36
-rwxr-xr-xansible_collections/community/dns/tests/unit/replace-requirements.sh10
-rw-r--r--ansible_collections/community/dns/tests/unit/requirements-stable-2.10.txt13
-rw-r--r--ansible_collections/community/dns/tests/unit/requirements-stable-2.9.txt13
-rw-r--r--ansible_collections/community/dns/tests/unit/requirements.txt2
-rwxr-xr-xansible_collections/community/dns/update-docs-fragments.py2
-rw-r--r--ansible_collections/community/docker/.azure-pipelines/azure-pipelines.yml123
-rw-r--r--ansible_collections/community/docker/.github/workflows/ansible-test.yml74
-rw-r--r--ansible_collections/community/docker/.github/workflows/docs-pr.yml1
-rw-r--r--ansible_collections/community/docker/.github/workflows/docs-push.yml1
-rw-r--r--ansible_collections/community/docker/.github/workflows/ee.yml8
-rw-r--r--ansible_collections/community/docker/.github/workflows/import-galaxy.yml20
-rw-r--r--ansible_collections/community/docker/.github/workflows/reuse.yml11
-rw-r--r--ansible_collections/community/docker/CHANGELOG.md1390
-rw-r--r--ansible_collections/community/docker/CHANGELOG.md.license3
-rw-r--r--ansible_collections/community/docker/CHANGELOG.rst218
-rw-r--r--ansible_collections/community/docker/FILES.json1600
-rw-r--r--ansible_collections/community/docker/LICENSES/Apache-2.0.txt6
-rw-r--r--ansible_collections/community/docker/MANIFEST.json10
-rw-r--r--ansible_collections/community/docker/README.md14
-rw-r--r--ansible_collections/community/docker/changelogs/changelog.yaml421
-rw-r--r--ansible_collections/community/docker/changelogs/config.yaml3
-rw-r--r--ansible_collections/community/docker/docs/docsite/config.yml15
-rw-r--r--ansible_collections/community/docker/docs/docsite/rst/scenario_guide.rst216
-rw-r--r--ansible_collections/community/docker/meta/runtime.yml11
-rw-r--r--ansible_collections/community/docker/plugins/action/docker_container_copy_into.py2
-rw-r--r--ansible_collections/community/docker/plugins/connection/docker.py3
-rw-r--r--ansible_collections/community/docker/plugins/connection/docker_api.py3
-rw-r--r--ansible_collections/community/docker/plugins/connection/nsenter.py2
-rw-r--r--ansible_collections/community/docker/plugins/doc_fragments/compose_v2.py63
-rw-r--r--ansible_collections/community/docker/plugins/doc_fragments/docker.py197
-rw-r--r--ansible_collections/community/docker/plugins/inventory/docker_containers.py94
-rw-r--r--ansible_collections/community/docker/plugins/inventory/docker_machine.py71
-rw-r--r--ansible_collections/community/docker/plugins/inventory/docker_swarm.py105
-rw-r--r--ansible_collections/community/docker/plugins/module_utils/_api/api/client.py2
-rw-r--r--ansible_collections/community/docker/plugins/module_utils/_api/errors.py3
-rw-r--r--ansible_collections/community/docker/plugins/module_utils/_api/tls.py5
-rw-r--r--ansible_collections/community/docker/plugins/module_utils/_api/transport/ssladapter.py14
-rw-r--r--ansible_collections/community/docker/plugins/module_utils/_api/utils/socket.py3
-rw-r--r--ansible_collections/community/docker/plugins/module_utils/_api/utils/utils.py16
-rw-r--r--ansible_collections/community/docker/plugins/module_utils/_logfmt.py208
-rw-r--r--ansible_collections/community/docker/plugins/module_utils/_platform.py179
-rw-r--r--ansible_collections/community/docker/plugins/module_utils/common.py38
-rw-r--r--ansible_collections/community/docker/plugins/module_utils/common_api.py12
-rw-r--r--ansible_collections/community/docker/plugins/module_utils/common_cli.py339
-rw-r--r--ansible_collections/community/docker/plugins/module_utils/compose_v2.py618
-rw-r--r--ansible_collections/community/docker/plugins/module_utils/image_archive.py117
-rw-r--r--ansible_collections/community/docker/plugins/module_utils/module_container/base.py47
-rw-r--r--ansible_collections/community/docker/plugins/module_utils/module_container/docker_api.py98
-rw-r--r--ansible_collections/community/docker/plugins/module_utils/module_container/module.py118
-rw-r--r--ansible_collections/community/docker/plugins/module_utils/util.py25
-rw-r--r--ansible_collections/community/docker/plugins/modules/current_container_facts.py8
-rw-r--r--ansible_collections/community/docker/plugins/modules/docker_compose.py82
-rw-r--r--ansible_collections/community/docker/plugins/modules/docker_compose_v2.py638
-rw-r--r--ansible_collections/community/docker/plugins/modules/docker_compose_v2_pull.py163
-rw-r--r--ansible_collections/community/docker/plugins/modules/docker_config.py30
-rw-r--r--ansible_collections/community/docker/plugins/modules/docker_container.py369
-rw-r--r--ansible_collections/community/docker/plugins/modules/docker_container_copy_into.py22
-rw-r--r--ansible_collections/community/docker/plugins/modules/docker_container_exec.py33
-rw-r--r--ansible_collections/community/docker/plugins/modules/docker_container_info.py2
-rw-r--r--ansible_collections/community/docker/plugins/modules/docker_host_info.py34
-rw-r--r--ansible_collections/community/docker/plugins/modules/docker_image.py125
-rw-r--r--ansible_collections/community/docker/plugins/modules/docker_image_build.py316
-rw-r--r--ansible_collections/community/docker/plugins/modules/docker_image_export.py283
-rw-r--r--ansible_collections/community/docker/plugins/modules/docker_image_info.py6
-rw-r--r--ansible_collections/community/docker/plugins/modules/docker_image_load.py9
-rw-r--r--ansible_collections/community/docker/plugins/modules/docker_image_pull.py223
-rw-r--r--ansible_collections/community/docker/plugins/modules/docker_image_push.py197
-rw-r--r--ansible_collections/community/docker/plugins/modules/docker_image_remove.py269
-rw-r--r--ansible_collections/community/docker/plugins/modules/docker_image_tag.py273
-rw-r--r--ansible_collections/community/docker/plugins/modules/docker_login.py10
-rw-r--r--ansible_collections/community/docker/plugins/modules/docker_network.py18
-rw-r--r--ansible_collections/community/docker/plugins/modules/docker_network_info.py2
-rw-r--r--ansible_collections/community/docker/plugins/modules/docker_node.py20
-rw-r--r--ansible_collections/community/docker/plugins/modules/docker_node_info.py12
-rw-r--r--ansible_collections/community/docker/plugins/modules/docker_plugin.py12
-rw-r--r--ansible_collections/community/docker/plugins/modules/docker_prune.py16
-rw-r--r--ansible_collections/community/docker/plugins/modules/docker_secret.py26
-rw-r--r--ansible_collections/community/docker/plugins/modules/docker_stack.py259
-rw-r--r--ansible_collections/community/docker/plugins/modules/docker_stack_info.py83
-rw-r--r--ansible_collections/community/docker/plugins/modules/docker_stack_task_info.py83
-rw-r--r--ansible_collections/community/docker/plugins/modules/docker_swarm.py86
-rw-r--r--ansible_collections/community/docker/plugins/modules/docker_swarm_info.py32
-rw-r--r--ansible_collections/community/docker/plugins/modules/docker_swarm_service.py91
-rw-r--r--ansible_collections/community/docker/plugins/modules/docker_swarm_service_info.py2
-rw-r--r--ansible_collections/community/docker/plugins/modules/docker_volume.py16
-rw-r--r--ansible_collections/community/docker/plugins/modules/docker_volume_info.py2
-rw-r--r--ansible_collections/community/docker/tests/galaxy-importer.cfg8
-rw-r--r--ansible_collections/community/docker/tests/integration/requirements.yml3
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/connection_docker_api/meta/main.yml1
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/connection_docker_api/setup.yml4
-rwxr-xr-xansible_collections/community/docker/tests/integration/targets/connection_nsenter/runme.sh2
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_compose/aliases2
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_compose/meta/main.yml2
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_compose/tasks/main.yml38
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_compose/tasks/run-test.yml4
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_compose_v2/aliases6
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_compose_v2/meta/main.yml10
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_compose_v2/tasks/main.yml48
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_compose_v2/tasks/run-test.yml7
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_compose_v2/tasks/tests/pull.yml211
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_compose_v2/tasks/tests/start-stop.yml262
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_compose_v2_pull/aliases6
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_compose_v2_pull/meta/main.yml10
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_compose_v2_pull/tasks/main.yml48
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_compose_v2_pull/tasks/run-test.yml7
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_compose_v2_pull/tasks/tests/pull.yml192
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_config/meta/main.yml1
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_container/meta/main.yml1
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_container/tasks/main.yml45
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_container/tasks/run-test.yml4
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_container/tasks/tests/comparisons.yml3
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_container/tasks/tests/image-ids.yml8
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_container/tasks/tests/options.yml289
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_container_copy_into/meta/main.yml1
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_container_copy_into/tasks/main.yml22
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_container_copy_into/tasks/run-test.yml4
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_container_exec/meta/main.yml1
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_container_info/meta/main.yml1
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_host_info/meta/main.yml1
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_host_info/tasks/test_host_info.yml10
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image/meta/main.yml1
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image/tasks/run-test.yml4
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image/tasks/test.yml30
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image/tasks/tests/basic.yml2
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image/tasks/tests/docker_image.yml353
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image/tasks/tests/options.yml64
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_build/aliases6
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_build/meta/main.yml10
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_build/tasks/main.yml13
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_build/tasks/run-test.yml7
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_build/tasks/test.yml59
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_build/tasks/tests/options.yml204
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_build/templates/ArgsDockerfile13
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_build/templates/Dockerfile7
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_build/templates/EtcHostsDockerfile7
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_build/templates/MyDockerfile9
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_build/templates/StagedDockerfile11
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_export/aliases6
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_export/meta/main.yml9
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_export/tasks/main.yml13
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_export/tasks/run-test.yml7
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_export/tasks/test.yml39
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_export/tasks/tests/basic.yml69
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_info/meta/main.yml1
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_info/tasks/main.yml7
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_load/meta/main.yml1
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_load/tasks/run-test.yml4
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_load/tasks/test.yml29
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_load/tasks/tests/basic.yml29
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_pull/aliases6
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_pull/meta/main.yml8
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_pull/tasks/main.yml13
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_pull/tasks/run-test.yml7
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_pull/tasks/test.yml39
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_pull/tasks/tests/basic.yml196
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_pull/tasks/tests/image-ids.yml89
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_pull/tasks/tests/registry.yml126
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_push/aliases6
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_push/meta/main.yml8
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_push/tasks/main.yml13
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_push/tasks/run-test.yml7
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_push/tasks/test.yml39
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_push/tasks/tests/basic.yml60
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_push/tasks/tests/registry.yml82
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_remove/aliases6
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_remove/meta/main.yml8
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_remove/tasks/main.yml296
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_tag/aliases6
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_tag/meta/main.yml8
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_image_tag/tasks/main.yml402
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_login/meta/main.yml1
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_login/tasks/run-test.yml4
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_login/tasks/test.yml8
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_network/meta/main.yml2
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_network/tasks/main.yml32
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_network/tasks/run-test.yml4
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_network_info/meta/main.yml1
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_node/meta/main.yml1
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_node/tasks/test_node.yml26
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_node_info/meta/main.yml1
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_plugin/meta/main.yml1
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_plugin/tasks/main.yml18
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_plugin/tasks/run-test.yml4
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_prune/meta/main.yml1
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_secret/meta/main.yml1
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_stack_info/tasks/test_stack_info.yml2
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_stack_task_info/tasks/test_stack_task_info.yml2
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_swarm/meta/main.yml1
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_swarm/tasks/main.yml6
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_swarm/tasks/run-test.yml3
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_swarm_info/meta/main.yml1
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_swarm_info/tasks/test_swarm_info.yml4
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_swarm_service/meta/main.yml1
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_swarm_service/tasks/main.yml16
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_swarm_service/tasks/run-test.yml4
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_swarm_service_info/meta/main.yml1
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_volume/meta/main.yml1
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_volume/tasks/main.yml18
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_volume/tasks/run-test.yml4
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/docker_volume_info/meta/main.yml1
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/generic_connection_tests/meta/main.yml2
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/generic_connection_tests/vars/main.yml4
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/generic_ssh_connection/meta/main.yml1
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/generic_ssh_connection/tasks/main.yml9
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/inventory_docker_containers/meta/main.yml1
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/inventory_docker_containers/playbooks/docker_cleanup.yml9
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/inventory_docker_containers/playbooks/docker_setup.yml6
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/inventory_docker_containers/playbooks/test_inventory_1.yml1
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/inventory_docker_containers/playbooks/test_inventory_2.yml10
-rwxr-xr-xansible_collections/community/docker/tests/integration/targets/inventory_docker_containers/runme.sh14
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/inventory_docker_machine/playbooks/pre-setup.yml4
-rwxr-xr-xansible_collections/community/docker/tests/integration/targets/inventory_docker_machine/runme.sh8
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/inventory_docker_swarm/meta/main.yml1
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/inventory_docker_swarm/playbooks/swarm_cleanup.yml9
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/inventory_docker_swarm/playbooks/swarm_setup.yml4
-rwxr-xr-xansible_collections/community/docker/tests/integration/targets/inventory_docker_swarm/runme.sh8
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker/defaults/main.yml5
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker/handlers/main.yml7
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker/tasks/Alpine.yml3
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker/tasks/main.yml38
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker/vars/RedHat-7.yml3
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker/vars/Ubuntu-14.yml6
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker/vars/main.yml4
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/meta/main.yml7
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/tasks/Alpine.yml13
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/tasks/Archlinux.yml8
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/tasks/Debian.yml7
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/tasks/Fedora.yml7
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/tasks/RedHat-7.yml (renamed from ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/vars/RedHat-7.yml)3
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/tasks/RedHat-8.yml8
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/tasks/RedHat-9.yml7
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/tasks/Suse.yml14
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/tasks/main.yml49
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/tasks/nothing.yml7
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/vars/default.yml (renamed from ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/vars/default.yml)0
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/meta/main.yml7
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/tasks/Alpine.yml13
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/tasks/Archlinux.yml8
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/tasks/Debian.yml7
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/tasks/Fedora.yml7
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/tasks/RedHat-7.yml7
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/tasks/RedHat-8.yml8
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/tasks/RedHat-9.yml7
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/tasks/Suse.yml14
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/tasks/main.yml65
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/tasks/nothing.yml7
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/vars/default.yml4
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/defaults/main.yml15
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/meta/main.yml (renamed from ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/meta/main.yml)0
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/tasks/Alpine.yml (renamed from ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/tasks/Alpine.yml)0
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/tasks/Archlinux.yml (renamed from ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/tasks/Archlinux.yml)0
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/tasks/Debian.yml (renamed from ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/tasks/Debian.yml)0
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/tasks/Fedora.yml (renamed from ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/tasks/Fedora.yml)0
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/tasks/RedHat-7.yml (renamed from ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/tasks/RedHat-7.yml)0
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/tasks/RedHat-8.yml (renamed from ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/tasks/RedHat-8.yml)0
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/tasks/RedHat-9.yml (renamed from ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/tasks/RedHat-9.yml)0
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/tasks/Suse.yml (renamed from ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/tasks/Suse.yml)0
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/tasks/main.yml (renamed from ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/tasks/main.yml)0
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/tasks/setup.yml (renamed from ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/tasks/setup.yml)22
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/Alpine.yml (renamed from ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/defaults/main.yml)3
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/Archlinux.yml9
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/CentOS-8.yml (renamed from ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/vars/CentOS-8.yml)0
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/Debian-11.yml8
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/Debian-12.yml8
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/RedHat-7.yml10
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/RedHat-8.yml (renamed from ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/vars/RedHat-8.yml)0
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/RedHat-9.yml (renamed from ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/vars/RedHat-9.yml)0
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/Suse-py2.yml (renamed from ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/vars/Suse-py2.yml)0
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/Suse-py3.yml (renamed from ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/vars/Suse-py3.yml)2
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/Ubuntu-14.yml9
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/Ubuntu-16.yml (renamed from ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/vars/Ubuntu-16.yml)0
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/Ubuntu-18.yml (renamed from ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/vars/Ubuntu-18.yml)0
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/Ubuntu.yml (renamed from ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/vars/Ubuntu.yml)0
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/default.yml4
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_current_container_network_ip/meta/main.yml7
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_current_container_network_ip/tasks/main.yml25
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_python_deps/aliases5
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_python_deps/defaults/main.yml12
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_python_deps/meta/main.yml8
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_python_deps/tasks/main.yml15
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_python_deps/vars/RedHat-7.yml10
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_python_deps/vars/Ubuntu-14.yml11
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_python_deps/vars/default.yml4
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_registry/aliases1
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_registry/handlers/cleanup.yml3
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_registry/meta/main.yml2
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_registry/tasks/setup.yml10
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_registry/vars/main.yml4
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_sdk_for_python/aliases5
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_sdk_for_python/defaults/main.yml10
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_sdk_for_python/meta/main.yml8
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_sdk_for_python/tasks/main.yml47
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_sdk_for_python/vars/RedHat-7.yml8
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_sdk_for_python/vars/Ubuntu-14.yml9
-rw-r--r--ansible_collections/community/docker/tests/integration/targets/setup_docker_sdk_for_python/vars/default.yml4
-rw-r--r--ansible_collections/community/docker/tests/sanity/extra/action-group.json11
-rw-r--r--ansible_collections/community/docker/tests/sanity/extra/action-group.json.license3
-rwxr-xr-xansible_collections/community/docker/tests/sanity/extra/action-group.py82
-rwxr-xr-xansible_collections/community/docker/tests/sanity/extra/extra-docs.py2
-rw-r--r--ansible_collections/community/docker/tests/sanity/ignore-2.10.txt11
-rw-r--r--ansible_collections/community/docker/tests/sanity/ignore-2.11.txt2
-rw-r--r--ansible_collections/community/docker/tests/sanity/ignore-2.12.txt2
-rw-r--r--ansible_collections/community/docker/tests/sanity/ignore-2.13.txt1
-rw-r--r--ansible_collections/community/docker/tests/sanity/ignore-2.16.txt1
-rw-r--r--ansible_collections/community/docker/tests/sanity/ignore-2.17.txt1
-rw-r--r--ansible_collections/community/docker/tests/sanity/ignore-2.17.txt.license3
-rw-r--r--ansible_collections/community/docker/tests/sanity/ignore-2.9.txt10
-rw-r--r--ansible_collections/community/docker/tests/unit/plugins/connection/test_docker.py7
-rw-r--r--ansible_collections/community/docker/tests/unit/plugins/inventory/test_docker_containers.py58
-rw-r--r--ansible_collections/community/docker/tests/unit/plugins/module_utils/_api/api/test_client.py2
-rw-r--r--ansible_collections/community/docker/tests/unit/plugins/module_utils/_api/transport/test_ssladapter.py11
-rw-r--r--ansible_collections/community/docker/tests/unit/plugins/module_utils/compose_v2_test_cases.py10588
-rw-r--r--ansible_collections/community/docker/tests/unit/plugins/module_utils/test__logfmt.py100
-rw-r--r--ansible_collections/community/docker/tests/unit/plugins/module_utils/test_compose_v2.py242
-rw-r--r--ansible_collections/community/docker/tests/unit/requirements.yml1
-rwxr-xr-xansible_collections/community/docker/tests/utils/shippable/shippable.sh16
-rw-r--r--ansible_collections/community/fortios/.github/workflows/ansible-test.yml117
-rw-r--r--ansible_collections/community/fortios/CHANGELOG.rst23
-rw-r--r--ansible_collections/community/fortios/FILES.json705
-rw-r--r--ansible_collections/community/fortios/MANIFEST.json36
-rw-r--r--ansible_collections/community/fortios/README.md99
-rw-r--r--ansible_collections/community/fortios/changelogs/changelog.yaml18
-rw-r--r--ansible_collections/community/fortios/changelogs/config.yaml29
-rw-r--r--ansible_collections/community/fortios/meta/runtime.yml2
-rw-r--r--ansible_collections/community/fortios/plugins/httpapi/fortianalyzer.py453
-rw-r--r--ansible_collections/community/fortios/plugins/httpapi/fortimanager.py459
-rw-r--r--ansible_collections/community/fortios/plugins/module_utils/fortianalyzer/common.py291
-rw-r--r--ansible_collections/community/fortios/plugins/module_utils/fortianalyzer/fortianalyzer.py476
-rw-r--r--ansible_collections/community/fortios/plugins/modules/faz_device.py432
-rw-r--r--ansible_collections/community/fortios/plugins/modules/fmgr_device.py296
-rw-r--r--ansible_collections/community/fortios/plugins/modules/fmgr_device_config.py231
-rw-r--r--ansible_collections/community/fortios/plugins/modules/fmgr_device_group.py323
-rw-r--r--ansible_collections/community/fortios/plugins/modules/fmgr_device_provision_template.py1546
-rw-r--r--ansible_collections/community/fortios/plugins/modules/fmgr_fwobj_address.py661
-rw-r--r--ansible_collections/community/fortios/plugins/modules/fmgr_fwobj_ippool.py442
-rw-r--r--ansible_collections/community/fortios/plugins/modules/fmgr_fwobj_ippool6.py223
-rw-r--r--ansible_collections/community/fortios/plugins/modules/fmgr_fwobj_service.py617
-rw-r--r--ansible_collections/community/fortios/plugins/modules/fmgr_fwobj_vip.py2424
-rw-r--r--ansible_collections/community/fortios/plugins/modules/fmgr_fwpol_ipv4.py1355
-rw-r--r--ansible_collections/community/fortios/plugins/modules/fmgr_fwpol_package.py479
-rw-r--r--ansible_collections/community/fortios/plugins/modules/fmgr_ha.py349
-rw-r--r--ansible_collections/community/fortios/plugins/modules/fmgr_provisioning.py360
-rw-r--r--ansible_collections/community/fortios/plugins/modules/fmgr_query.py424
-rw-r--r--ansible_collections/community/fortios/plugins/modules/fmgr_script.py262
-rw-r--r--ansible_collections/community/fortios/plugins/modules/fmgr_secprof_appctrl.py516
-rw-r--r--ansible_collections/community/fortios/plugins/modules/fmgr_secprof_av.py1386
-rw-r--r--ansible_collections/community/fortios/plugins/modules/fmgr_secprof_dns.py339
-rw-r--r--ansible_collections/community/fortios/plugins/modules/fmgr_secprof_ips.py664
-rw-r--r--ansible_collections/community/fortios/plugins/modules/fmgr_secprof_profile_group.py287
-rw-r--r--ansible_collections/community/fortios/plugins/modules/fmgr_secprof_proxy.py332
-rw-r--r--ansible_collections/community/fortios/plugins/modules/fmgr_secprof_spam.py607
-rw-r--r--ansible_collections/community/fortios/plugins/modules/fmgr_secprof_ssl_ssh.py954
-rw-r--r--ansible_collections/community/fortios/plugins/modules/fmgr_secprof_voip.py1198
-rw-r--r--ansible_collections/community/fortios/plugins/modules/fmgr_secprof_waf.py1477
-rw-r--r--ansible_collections/community/fortios/plugins/modules/fmgr_secprof_wanopt.py685
-rw-r--r--ansible_collections/community/fortios/plugins/modules/fmgr_secprof_web.py1081
-rw-r--r--ansible_collections/community/fortios/tests/requirements.yml2
-rw-r--r--ansible_collections/community/fortios/tests/sanity/ignore-2.10.txt51
-rw-r--r--ansible_collections/community/fortios/tests/sanity/ignore-2.11.txt51
-rw-r--r--ansible_collections/community/fortios/tests/sanity/ignore-2.9.txt29
-rw-r--r--ansible_collections/community/fortios/tests/unit/compat/mock.py122
-rw-r--r--ansible_collections/community/fortios/tests/unit/compat/unittest.py38
-rw-r--r--ansible_collections/community/fortios/tests/unit/plugins/modules/fixtures/test_fmgr_device.json934
-rw-r--r--ansible_collections/community/fortios/tests/unit/plugins/modules/fixtures/test_fmgr_device_provision_template.json2063
-rw-r--r--ansible_collections/community/fortios/tests/unit/plugins/modules/fixtures/test_fmgr_ha.json241
-rw-r--r--ansible_collections/community/fortios/tests/unit/plugins/modules/fixtures/test_fmgr_secprof_spam.json157
-rw-r--r--ansible_collections/community/fortios/tests/unit/plugins/modules/fixtures/test_fmgr_secprof_ssl_ssh.json214
-rw-r--r--ansible_collections/community/fortios/tests/unit/plugins/modules/fortimanager_module.py64
-rw-r--r--ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_device.py272
-rw-r--r--ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_device_config.py188
-rw-r--r--ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_device_group.py202
-rw-r--r--ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_device_provision_template.py1758
-rw-r--r--ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwobj_address.py156
-rw-r--r--ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwobj_ippool.py90
-rw-r--r--ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwobj_ippool6.py72
-rw-r--r--ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwobj_service.py123
-rw-r--r--ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwobj_vip.py785
-rw-r--r--ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwpol_ipv4.py596
-rw-r--r--ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwpol_package.py97
-rw-r--r--ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_ha.py216
-rw-r--r--ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_provisioning.py64
-rw-r--r--ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_query.py106
-rw-r--r--ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_script.py129
-rw-r--r--ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_appctrl.py78
-rw-r--r--ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_av.py72
-rw-r--r--ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_dns.py88
-rw-r--r--ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_ips.py69
-rw-r--r--ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_profile_group.py112
-rw-r--r--ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_proxy.py72
-rw-r--r--ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_spam.py72
-rw-r--r--ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_ssl_ssh.py69
-rw-r--r--ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_voip.py72
-rw-r--r--ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_waf.py69
-rw-r--r--ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_wanopt.py72
-rw-r--r--ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_web.py67
-rw-r--r--ansible_collections/community/fortios/tests/unit/plugins/modules/utils.py50
-rw-r--r--ansible_collections/community/fortios/tests/unit/requirements.txt4
-rw-r--r--ansible_collections/community/general/.azure-pipelines/azure-pipelines.yml210
-rw-r--r--ansible_collections/community/general/.github/BOTMETA.yml183
-rw-r--r--ansible_collections/community/general/.github/ISSUE_TEMPLATE/bug_report.yml2
-rw-r--r--ansible_collections/community/general/.github/ISSUE_TEMPLATE/documentation_report.yml4
-rw-r--r--ansible_collections/community/general/.github/ISSUE_TEMPLATE/feature_request.yml4
-rw-r--r--ansible_collections/community/general/.github/pull_request_template.md32
-rw-r--r--ansible_collections/community/general/.github/pull_request_template.md.license3
-rw-r--r--ansible_collections/community/general/.github/workflows/ansible-test.yml119
-rw-r--r--ansible_collections/community/general/.github/workflows/codeql-analysis.yml37
-rw-r--r--ansible_collections/community/general/.github/workflows/import-galaxy.yml20
-rw-r--r--ansible_collections/community/general/.github/workflows/reuse.yml11
-rw-r--r--ansible_collections/community/general/.pre-commit-config.yaml23
-rw-r--r--ansible_collections/community/general/CHANGELOG.md708
-rw-r--r--ansible_collections/community/general/CHANGELOG.md.license3
-rw-r--r--ansible_collections/community/general/CHANGELOG.rst1039
-rw-r--r--ansible_collections/community/general/CONTRIBUTING.md18
-rw-r--r--ansible_collections/community/general/FILES.json4316
-rw-r--r--ansible_collections/community/general/MANIFEST.json6
-rw-r--r--ansible_collections/community/general/README.md26
-rw-r--r--ansible_collections/community/general/changelogs/changelog.yaml2604
-rw-r--r--ansible_collections/community/general/changelogs/config.yaml3
-rw-r--r--ansible_collections/community/general/docs/docsite/extra-docs.yml6
-rw-r--r--ansible_collections/community/general/docs/docsite/rst/filter_guide_abstract_informations.rst1
-rw-r--r--ansible_collections/community/general/docs/docsite/rst/filter_guide_abstract_informations_counting_elements_in_sequence.rst2
-rw-r--r--ansible_collections/community/general/docs/docsite/rst/filter_guide_abstract_informations_dictionaries.rst4
-rw-r--r--ansible_collections/community/general/docs/docsite/rst/filter_guide_abstract_informations_grouping.rst2
-rw-r--r--ansible_collections/community/general/docs/docsite/rst/filter_guide_abstract_informations_lists_helper.rst81
-rw-r--r--ansible_collections/community/general/docs/docsite/rst/filter_guide_abstract_informations_merging_lists_of_dictionaries.rst22
-rw-r--r--ansible_collections/community/general/docs/docsite/rst/filter_guide_conversions.rst6
-rw-r--r--ansible_collections/community/general/docs/docsite/rst/filter_guide_creating_identifiers.rst4
-rw-r--r--ansible_collections/community/general/docs/docsite/rst/filter_guide_paths.rst12
-rw-r--r--ansible_collections/community/general/docs/docsite/rst/filter_guide_selecting_json_data.rst4
-rw-r--r--ansible_collections/community/general/docs/docsite/rst/filter_guide_working_with_times.rst22
-rw-r--r--ansible_collections/community/general/docs/docsite/rst/filter_guide_working_with_unicode.rst6
-rw-r--r--ansible_collections/community/general/docs/docsite/rst/filter_guide_working_with_versions.rst2
-rw-r--r--ansible_collections/community/general/docs/docsite/rst/guide_alicloud.rst96
-rw-r--r--ansible_collections/community/general/docs/docsite/rst/guide_online.rst49
-rw-r--r--ansible_collections/community/general/docs/docsite/rst/guide_packet.rst214
-rw-r--r--ansible_collections/community/general/docs/docsite/rst/guide_scaleway.rst320
-rw-r--r--ansible_collections/community/general/docs/docsite/rst/test_guide.rst2
-rw-r--r--ansible_collections/community/general/meta/runtime.yml179
-rw-r--r--ansible_collections/community/general/plugins/action/iptables_state.py2
-rw-r--r--ansible_collections/community/general/plugins/action/shutdown.py88
-rw-r--r--ansible_collections/community/general/plugins/become/machinectl.py3
-rw-r--r--ansible_collections/community/general/plugins/become/pfexec.py2
-rw-r--r--ansible_collections/community/general/plugins/cache/redis.py8
-rw-r--r--ansible_collections/community/general/plugins/callback/cgroup_memory_recap.py4
-rw-r--r--ansible_collections/community/general/plugins/callback/default_without_diff.py46
-rw-r--r--ansible_collections/community/general/plugins/callback/diy.py52
-rw-r--r--ansible_collections/community/general/plugins/callback/elastic.py38
-rw-r--r--ansible_collections/community/general/plugins/callback/logentries.py18
-rw-r--r--ansible_collections/community/general/plugins/callback/mail.py12
-rw-r--r--ansible_collections/community/general/plugins/callback/nrdp.py2
-rw-r--r--ansible_collections/community/general/plugins/callback/null.py4
-rw-r--r--ansible_collections/community/general/plugins/callback/opentelemetry.py65
-rw-r--r--ansible_collections/community/general/plugins/callback/say.py2
-rw-r--r--ansible_collections/community/general/plugins/callback/selective.py21
-rw-r--r--ansible_collections/community/general/plugins/callback/slack.py1
-rw-r--r--ansible_collections/community/general/plugins/callback/splunk.py4
-rw-r--r--ansible_collections/community/general/plugins/callback/sumologic.py6
-rw-r--r--ansible_collections/community/general/plugins/callback/syslog_json.py1
-rw-r--r--ansible_collections/community/general/plugins/callback/unixy.py33
-rw-r--r--ansible_collections/community/general/plugins/connection/chroot.py45
-rw-r--r--ansible_collections/community/general/plugins/connection/funcd.py2
-rw-r--r--ansible_collections/community/general/plugins/connection/incus.py169
-rw-r--r--ansible_collections/community/general/plugins/connection/lxc.py12
-rw-r--r--ansible_collections/community/general/plugins/connection/lxd.py42
-rw-r--r--ansible_collections/community/general/plugins/doc_fragments/alicloud.py58
-rw-r--r--ansible_collections/community/general/plugins/doc_fragments/auth_basic.py8
-rw-r--r--ansible_collections/community/general/plugins/doc_fragments/bitbucket.py10
-rw-r--r--ansible_collections/community/general/plugins/doc_fragments/consul.py60
-rw-r--r--ansible_collections/community/general/plugins/doc_fragments/dimensiondata.py16
-rw-r--r--ansible_collections/community/general/plugins/doc_fragments/dimensiondata_wait.py6
-rw-r--r--ansible_collections/community/general/plugins/doc_fragments/emc.py5
-rw-r--r--ansible_collections/community/general/plugins/doc_fragments/gitlab.py5
-rw-r--r--ansible_collections/community/general/plugins/doc_fragments/hwc.py23
-rw-r--r--ansible_collections/community/general/plugins/doc_fragments/ibm_storage.py3
-rw-r--r--ansible_collections/community/general/plugins/doc_fragments/influxdb.py17
-rw-r--r--ansible_collections/community/general/plugins/doc_fragments/ipa.py45
-rw-r--r--ansible_collections/community/general/plugins/doc_fragments/keycloak.py5
-rw-r--r--ansible_collections/community/general/plugins/doc_fragments/ldap.py30
-rw-r--r--ansible_collections/community/general/plugins/doc_fragments/lxca_common.py7
-rw-r--r--ansible_collections/community/general/plugins/doc_fragments/manageiq.py12
-rw-r--r--ansible_collections/community/general/plugins/doc_fragments/nomad.py8
-rw-r--r--ansible_collections/community/general/plugins/doc_fragments/onepassword.py79
-rw-r--r--ansible_collections/community/general/plugins/doc_fragments/oneview.py16
-rw-r--r--ansible_collections/community/general/plugins/doc_fragments/online.py10
-rw-r--r--ansible_collections/community/general/plugins/doc_fragments/opennebula.py10
-rw-r--r--ansible_collections/community/general/plugins/doc_fragments/openswitch.py26
-rw-r--r--ansible_collections/community/general/plugins/doc_fragments/oracle.py45
-rw-r--r--ansible_collections/community/general/plugins/doc_fragments/oracle_creatable_resource.py4
-rw-r--r--ansible_collections/community/general/plugins/doc_fragments/oracle_display_name_option.py2
-rw-r--r--ansible_collections/community/general/plugins/doc_fragments/oracle_name_option.py2
-rw-r--r--ansible_collections/community/general/plugins/doc_fragments/oracle_wait_options.py8
-rw-r--r--ansible_collections/community/general/plugins/doc_fragments/pritunl.py2
-rw-r--r--ansible_collections/community/general/plugins/doc_fragments/proxmox.py8
-rw-r--r--ansible_collections/community/general/plugins/doc_fragments/purestorage.py14
-rw-r--r--ansible_collections/community/general/plugins/doc_fragments/rackspace.py52
-rw-r--r--ansible_collections/community/general/plugins/doc_fragments/redis.py4
-rw-r--r--ansible_collections/community/general/plugins/doc_fragments/scaleway.py8
-rw-r--r--ansible_collections/community/general/plugins/doc_fragments/utm.py11
-rw-r--r--ansible_collections/community/general/plugins/doc_fragments/vexata.py9
-rw-r--r--ansible_collections/community/general/plugins/doc_fragments/xenserver.py10
-rw-r--r--ansible_collections/community/general/plugins/filter/from_csv.py10
-rw-r--r--ansible_collections/community/general/plugins/filter/from_ini.py99
-rw-r--r--ansible_collections/community/general/plugins/filter/jc.py6
-rw-r--r--ansible_collections/community/general/plugins/filter/lists.py210
-rw-r--r--ansible_collections/community/general/plugins/filter/lists_difference.yml48
-rw-r--r--ansible_collections/community/general/plugins/filter/lists_intersect.yml48
-rw-r--r--ansible_collections/community/general/plugins/filter/lists_mergeby.py4
-rw-r--r--ansible_collections/community/general/plugins/filter/lists_symmetric_difference.yml48
-rw-r--r--ansible_collections/community/general/plugins/filter/lists_union.yml48
-rw-r--r--ansible_collections/community/general/plugins/filter/to_days.yml10
-rw-r--r--ansible_collections/community/general/plugins/filter/to_hours.yml10
-rw-r--r--ansible_collections/community/general/plugins/filter/to_ini.py105
-rw-r--r--ansible_collections/community/general/plugins/filter/to_milliseconds.yml10
-rw-r--r--ansible_collections/community/general/plugins/filter/to_minutes.yml10
-rw-r--r--ansible_collections/community/general/plugins/filter/to_months.yml10
-rw-r--r--ansible_collections/community/general/plugins/filter/to_seconds.yml10
-rw-r--r--ansible_collections/community/general/plugins/filter/to_time_unit.yml10
-rw-r--r--ansible_collections/community/general/plugins/filter/to_weeks.yml10
-rw-r--r--ansible_collections/community/general/plugins/filter/to_years.yml10
-rw-r--r--ansible_collections/community/general/plugins/inventory/cobbler.py134
-rw-r--r--ansible_collections/community/general/plugins/inventory/gitlab_runners.py8
-rw-r--r--ansible_collections/community/general/plugins/inventory/icinga2.py46
-rw-r--r--ansible_collections/community/general/plugins/inventory/linode.py45
-rw-r--r--ansible_collections/community/general/plugins/inventory/lxd.py81
-rw-r--r--ansible_collections/community/general/plugins/inventory/nmap.py52
-rw-r--r--ansible_collections/community/general/plugins/inventory/online.py17
-rw-r--r--ansible_collections/community/general/plugins/inventory/opennebula.py18
-rw-r--r--ansible_collections/community/general/plugins/inventory/proxmox.py70
-rw-r--r--ansible_collections/community/general/plugins/inventory/scaleway.py7
-rw-r--r--ansible_collections/community/general/plugins/inventory/stackpath_compute.py3
-rw-r--r--ansible_collections/community/general/plugins/inventory/virtualbox.py13
-rw-r--r--ansible_collections/community/general/plugins/inventory/xen_orchestra.py11
-rw-r--r--ansible_collections/community/general/plugins/lookup/bitwarden.py121
-rw-r--r--ansible_collections/community/general/plugins/lookup/bitwarden_secrets_manager.py125
-rw-r--r--ansible_collections/community/general/plugins/lookup/collection_version.py29
-rw-r--r--ansible_collections/community/general/plugins/lookup/consul_kv.py13
-rw-r--r--ansible_collections/community/general/plugins/lookup/dependent.py2
-rw-r--r--ansible_collections/community/general/plugins/lookup/dig.py28
-rw-r--r--ansible_collections/community/general/plugins/lookup/dnstxt.py4
-rw-r--r--ansible_collections/community/general/plugins/lookup/dsv.py10
-rw-r--r--ansible_collections/community/general/plugins/lookup/etcd.py10
-rw-r--r--ansible_collections/community/general/plugins/lookup/etcd3.py22
-rw-r--r--ansible_collections/community/general/plugins/lookup/filetree.py2
-rw-r--r--ansible_collections/community/general/plugins/lookup/flattened.py2
-rw-r--r--ansible_collections/community/general/plugins/lookup/github_app_access_token.py156
-rw-r--r--ansible_collections/community/general/plugins/lookup/lmdb_kv.py2
-rw-r--r--ansible_collections/community/general/plugins/lookup/merge_variables.py40
-rw-r--r--ansible_collections/community/general/plugins/lookup/onepassword.py214
-rw-r--r--ansible_collections/community/general/plugins/lookup/onepassword_doc.py104
-rw-r--r--ansible_collections/community/general/plugins/lookup/onepassword_raw.py61
-rw-r--r--ansible_collections/community/general/plugins/lookup/passwordstore.py66
-rw-r--r--ansible_collections/community/general/plugins/lookup/random_string.py39
-rw-r--r--ansible_collections/community/general/plugins/lookup/revbitspss.py4
-rw-r--r--ansible_collections/community/general/plugins/lookup/tss.py195
-rw-r--r--ansible_collections/community/general/plugins/module_utils/cmd_runner.py23
-rw-r--r--ansible_collections/community/general/plugins/module_utils/consul.py321
-rw-r--r--ansible_collections/community/general/plugins/module_utils/dimensiondata.py2
-rw-r--r--ansible_collections/community/general/plugins/module_utils/gio_mime.py32
-rw-r--r--ansible_collections/community/general/plugins/module_utils/gitlab.py71
-rw-r--r--ansible_collections/community/general/plugins/module_utils/hwc_utils.py6
-rw-r--r--ansible_collections/community/general/plugins/module_utils/identity/keycloak/keycloak.py934
-rw-r--r--ansible_collections/community/general/plugins/module_utils/ldap.py18
-rw-r--r--ansible_collections/community/general/plugins/module_utils/locale_gen.py31
-rw-r--r--ansible_collections/community/general/plugins/module_utils/lxd.py10
-rw-r--r--ansible_collections/community/general/plugins/module_utils/memset.py5
-rw-r--r--ansible_collections/community/general/plugins/module_utils/mh/mixins/cmd.py205
-rw-r--r--ansible_collections/community/general/plugins/module_utils/mh/mixins/deps.py14
-rw-r--r--ansible_collections/community/general/plugins/module_utils/mh/mixins/vars.py18
-rw-r--r--ansible_collections/community/general/plugins/module_utils/mh/module_helper.py18
-rw-r--r--ansible_collections/community/general/plugins/module_utils/module_helper.py20
-rw-r--r--ansible_collections/community/general/plugins/module_utils/net_tools/pritunl/api.py14
-rw-r--r--ansible_collections/community/general/plugins/module_utils/ocapi_utils.py2
-rw-r--r--ansible_collections/community/general/plugins/module_utils/oracle/oci_utils.py39
-rw-r--r--ansible_collections/community/general/plugins/module_utils/pipx.py2
-rw-r--r--ansible_collections/community/general/plugins/module_utils/proxmox.py83
-rw-r--r--ansible_collections/community/general/plugins/module_utils/redfish_utils.py625
-rw-r--r--ansible_collections/community/general/plugins/module_utils/redhat.py52
-rw-r--r--ansible_collections/community/general/plugins/module_utils/rundeck.py4
-rw-r--r--ansible_collections/community/general/plugins/module_utils/scaleway.py2
-rw-r--r--ansible_collections/community/general/plugins/module_utils/snap.py48
-rw-r--r--ansible_collections/community/general/plugins/module_utils/vardict.py197
-rw-r--r--ansible_collections/community/general/plugins/module_utils/version.py11
-rw-r--r--ansible_collections/community/general/plugins/module_utils/wdc_redfish_utils.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/airbrake_deployment.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/aix_devices.py8
-rw-r--r--ansible_collections/community/general/plugins/modules/aix_filesystem.py70
-rw-r--r--ansible_collections/community/general/plugins/modules/aix_inittab.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/aix_lvg.py6
-rw-r--r--ansible_collections/community/general/plugins/modules/aix_lvol.py10
-rw-r--r--ansible_collections/community/general/plugins/modules/alerta_customer.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/ali_instance.py30
-rw-r--r--ansible_collections/community/general/plugins/modules/ali_instance_info.py9
-rw-r--r--ansible_collections/community/general/plugins/modules/alternatives.py12
-rw-r--r--ansible_collections/community/general/plugins/modules/ansible_galaxy_install.py139
-rw-r--r--ansible_collections/community/general/plugins/modules/apache2_module.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/apk.py18
-rw-r--r--ansible_collections/community/general/plugins/modules/apt_repo.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/apt_rpm.py76
-rw-r--r--ansible_collections/community/general/plugins/modules/archive.py25
-rw-r--r--ansible_collections/community/general/plugins/modules/atomic_container.py1
-rw-r--r--ansible_collections/community/general/plugins/modules/atomic_host.py3
-rw-r--r--ansible_collections/community/general/plugins/modules/atomic_image.py3
-rw-r--r--ansible_collections/community/general/plugins/modules/awall.py6
-rw-r--r--ansible_collections/community/general/plugins/modules/bearychat.py6
-rw-r--r--ansible_collections/community/general/plugins/modules/bigpanda.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/bitbucket_access_key.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/bitbucket_pipeline_key_pair.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/bitbucket_pipeline_known_host.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/bitbucket_pipeline_variable.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/btrfs_subvolume.py14
-rw-r--r--ansible_collections/community/general/plugins/modules/bundler.py26
-rw-r--r--ansible_collections/community/general/plugins/modules/bzr.py7
-rw-r--r--ansible_collections/community/general/plugins/modules/capabilities.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/cargo.py40
-rw-r--r--ansible_collections/community/general/plugins/modules/catapult.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/circonus_annotation.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/cisco_webex.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/clc_firewall_policy.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/clc_server.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/cloudflare_dns.py114
-rw-r--r--ansible_collections/community/general/plugins/modules/cobbler_sync.py8
-rw-r--r--ansible_collections/community/general/plugins/modules/cobbler_system.py12
-rw-r--r--ansible_collections/community/general/plugins/modules/composer.py19
-rw-r--r--ansible_collections/community/general/plugins/modules/consul.py103
-rw-r--r--ansible_collections/community/general/plugins/modules/consul_acl.py6
-rw-r--r--ansible_collections/community/general/plugins/modules/consul_acl_bootstrap.py108
-rw-r--r--ansible_collections/community/general/plugins/modules/consul_auth_method.py207
-rw-r--r--ansible_collections/community/general/plugins/modules/consul_binding_rule.py183
-rw-r--r--ansible_collections/community/general/plugins/modules/consul_kv.py28
-rw-r--r--ansible_collections/community/general/plugins/modules/consul_policy.py164
-rw-r--r--ansible_collections/community/general/plugins/modules/consul_role.py281
-rw-r--r--ansible_collections/community/general/plugins/modules/consul_session.py186
-rw-r--r--ansible_collections/community/general/plugins/modules/consul_token.py331
-rw-r--r--ansible_collections/community/general/plugins/modules/copr.py26
-rw-r--r--ansible_collections/community/general/plugins/modules/cpanm.py51
-rw-r--r--ansible_collections/community/general/plugins/modules/cronvar.py13
-rw-r--r--ansible_collections/community/general/plugins/modules/crypttab.py20
-rw-r--r--ansible_collections/community/general/plugins/modules/datadog_downtime.py9
-rw-r--r--ansible_collections/community/general/plugins/modules/datadog_event.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/datadog_monitor.py50
-rw-r--r--ansible_collections/community/general/plugins/modules/dconf.py10
-rw-r--r--ansible_collections/community/general/plugins/modules/deploy_helper.py47
-rw-r--r--ansible_collections/community/general/plugins/modules/dimensiondata_network.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/dimensiondata_vlan.py8
-rw-r--r--ansible_collections/community/general/plugins/modules/discord.py6
-rw-r--r--ansible_collections/community/general/plugins/modules/django_manage.py70
-rw-r--r--ansible_collections/community/general/plugins/modules/dnf_config_manager.py225
-rw-r--r--ansible_collections/community/general/plugins/modules/dnf_versionlock.py16
-rw-r--r--ansible_collections/community/general/plugins/modules/dnsimple.py16
-rw-r--r--ansible_collections/community/general/plugins/modules/dnsimple_info.py36
-rw-r--r--ansible_collections/community/general/plugins/modules/dnsmadeeasy.py14
-rw-r--r--ansible_collections/community/general/plugins/modules/dpkg_divert.py26
-rw-r--r--ansible_collections/community/general/plugins/modules/easy_install.py18
-rw-r--r--ansible_collections/community/general/plugins/modules/ejabberd_user.py41
-rw-r--r--ansible_collections/community/general/plugins/modules/elasticsearch_plugin.py1
-rw-r--r--ansible_collections/community/general/plugins/modules/emc_vnx_sg_member.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/etcd3.py8
-rw-r--r--ansible_collections/community/general/plugins/modules/facter.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/facter_facts.py90
-rw-r--r--ansible_collections/community/general/plugins/modules/filesize.py38
-rw-r--r--ansible_collections/community/general/plugins/modules/filesystem.py132
-rw-r--r--ansible_collections/community/general/plugins/modules/flatpak.py14
-rw-r--r--ansible_collections/community/general/plugins/modules/flatpak_remote.py22
-rw-r--r--ansible_collections/community/general/plugins/modules/flowdock.py8
-rw-r--r--ansible_collections/community/general/plugins/modules/gandi_livedns.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/gconftool2.py52
-rw-r--r--ansible_collections/community/general/plugins/modules/gem.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/gio_mime.py108
-rw-r--r--ansible_collections/community/general/plugins/modules/git_config.py172
-rw-r--r--ansible_collections/community/general/plugins/modules/git_config_info.py187
-rw-r--r--ansible_collections/community/general/plugins/modules/github_deploy_key.py12
-rw-r--r--ansible_collections/community/general/plugins/modules/github_key.py16
-rw-r--r--ansible_collections/community/general/plugins/modules/github_release.py8
-rw-r--r--ansible_collections/community/general/plugins/modules/github_repo.py28
-rw-r--r--ansible_collections/community/general/plugins/modules/github_webhook.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/github_webhook_info.py1
-rw-r--r--ansible_collections/community/general/plugins/modules/gitlab_branch.py10
-rw-r--r--ansible_collections/community/general/plugins/modules/gitlab_deploy_key.py16
-rw-r--r--ansible_collections/community/general/plugins/modules/gitlab_group.py35
-rw-r--r--ansible_collections/community/general/plugins/modules/gitlab_group_access_token.py320
-rw-r--r--ansible_collections/community/general/plugins/modules/gitlab_group_members.py57
-rw-r--r--ansible_collections/community/general/plugins/modules/gitlab_group_variable.py130
-rw-r--r--ansible_collections/community/general/plugins/modules/gitlab_hook.py27
-rw-r--r--ansible_collections/community/general/plugins/modules/gitlab_instance_variable.py360
-rw-r--r--ansible_collections/community/general/plugins/modules/gitlab_issue.py408
-rw-r--r--ansible_collections/community/general/plugins/modules/gitlab_label.py500
-rw-r--r--ansible_collections/community/general/plugins/modules/gitlab_merge_request.py416
-rw-r--r--ansible_collections/community/general/plugins/modules/gitlab_milestone.py496
-rw-r--r--ansible_collections/community/general/plugins/modules/gitlab_project.py91
-rw-r--r--ansible_collections/community/general/plugins/modules/gitlab_project_access_token.py318
-rw-r--r--ansible_collections/community/general/plugins/modules/gitlab_project_badge.py17
-rw-r--r--ansible_collections/community/general/plugins/modules/gitlab_project_members.py36
-rw-r--r--ansible_collections/community/general/plugins/modules/gitlab_project_variable.py149
-rw-r--r--ansible_collections/community/general/plugins/modules/gitlab_protected_branch.py16
-rw-r--r--ansible_collections/community/general/plugins/modules/gitlab_runner.py137
-rw-r--r--ansible_collections/community/general/plugins/modules/gitlab_user.py56
-rw-r--r--ansible_collections/community/general/plugins/modules/grove.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/hana_query.py219
-rw-r--r--ansible_collections/community/general/plugins/modules/haproxy.py12
-rw-r--r--ansible_collections/community/general/plugins/modules/heroku_collaborator.py10
-rw-r--r--ansible_collections/community/general/plugins/modules/hg.py7
-rw-r--r--ansible_collections/community/general/plugins/modules/hipchat.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/homebrew.py31
-rw-r--r--ansible_collections/community/general/plugins/modules/homebrew_tap.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/homectl.py30
-rw-r--r--ansible_collections/community/general/plugins/modules/honeybadger_deployment.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/hpilo_info.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/htpasswd.py115
-rw-r--r--ansible_collections/community/general/plugins/modules/hwc_ecs_instance.py8
-rw-r--r--ansible_collections/community/general/plugins/modules/hwc_smn_topic.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/hwc_vpc_eip.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/hwc_vpc_private_ip.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/hwc_vpc_route.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/hwc_vpc_security_group.py14
-rw-r--r--ansible_collections/community/general/plugins/modules/hwc_vpc_security_group_rule.py6
-rw-r--r--ansible_collections/community/general/plugins/modules/hwc_vpc_subnet.py8
-rw-r--r--ansible_collections/community/general/plugins/modules/icinga2_feature.py8
-rw-r--r--ansible_collections/community/general/plugins/modules/icinga2_host.py20
-rw-r--r--ansible_collections/community/general/plugins/modules/idrac_redfish_config.py6
-rw-r--r--ansible_collections/community/general/plugins/modules/idrac_redfish_info.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/ilo_redfish_command.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/imc_rest.py26
-rw-r--r--ansible_collections/community/general/plugins/modules/imgadm.py15
-rw-r--r--ansible_collections/community/general/plugins/modules/influxdb_database.py1
-rw-r--r--ansible_collections/community/general/plugins/modules/influxdb_query.py1
-rw-r--r--ansible_collections/community/general/plugins/modules/influxdb_retention_policy.py9
-rw-r--r--ansible_collections/community/general/plugins/modules/influxdb_user.py1
-rw-r--r--ansible_collections/community/general/plugins/modules/influxdb_write.py1
-rw-r--r--ansible_collections/community/general/plugins/modules/ini_file.py172
-rw-r--r--ansible_collections/community/general/plugins/modules/installp.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/interfaces_file.py54
-rw-r--r--ansible_collections/community/general/plugins/modules/ipa_config.py42
-rw-r--r--ansible_collections/community/general/plugins/modules/ipa_dnsrecord.py31
-rw-r--r--ansible_collections/community/general/plugins/modules/ipa_dnszone.py3
-rw-r--r--ansible_collections/community/general/plugins/modules/ipa_group.py18
-rw-r--r--ansible_collections/community/general/plugins/modules/ipa_hbacrule.py12
-rw-r--r--ansible_collections/community/general/plugins/modules/ipa_host.py3
-rw-r--r--ansible_collections/community/general/plugins/modules/ipa_hostgroup.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/ipa_otptoken.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/ipa_pwpolicy.py89
-rw-r--r--ansible_collections/community/general/plugins/modules/ipa_sudorule.py58
-rw-r--r--ansible_collections/community/general/plugins/modules/ipa_user.py16
-rw-r--r--ansible_collections/community/general/plugins/modules/ipa_vault.py1
-rw-r--r--ansible_collections/community/general/plugins/modules/ipbase_info.py304
-rw-r--r--ansible_collections/community/general/plugins/modules/ipify_facts.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/ipmi_boot.py1
-rw-r--r--ansible_collections/community/general/plugins/modules/ipmi_power.py17
-rw-r--r--ansible_collections/community/general/plugins/modules/iptables_state.py68
-rw-r--r--ansible_collections/community/general/plugins/modules/ipwcli_dns.py16
-rw-r--r--ansible_collections/community/general/plugins/modules/irc.py54
-rw-r--r--ansible_collections/community/general/plugins/modules/iso_create.py21
-rw-r--r--ansible_collections/community/general/plugins/modules/iso_customize.py7
-rw-r--r--ansible_collections/community/general/plugins/modules/iso_extract.py11
-rw-r--r--ansible_collections/community/general/plugins/modules/java_cert.py94
-rw-r--r--ansible_collections/community/general/plugins/modules/java_keystore.py32
-rw-r--r--ansible_collections/community/general/plugins/modules/jboss.py6
-rw-r--r--ansible_collections/community/general/plugins/modules/jenkins_build.py31
-rw-r--r--ansible_collections/community/general/plugins/modules/jenkins_build_info.py210
-rw-r--r--ansible_collections/community/general/plugins/modules/jenkins_job.py14
-rw-r--r--ansible_collections/community/general/plugins/modules/jenkins_job_info.py10
-rw-r--r--ansible_collections/community/general/plugins/modules/jenkins_plugin.py51
-rw-r--r--ansible_collections/community/general/plugins/modules/jenkins_script.py6
-rw-r--r--ansible_collections/community/general/plugins/modules/jira.py30
-rw-r--r--ansible_collections/community/general/plugins/modules/kdeconfig.py8
-rw-r--r--ansible_collections/community/general/plugins/modules/kernel_blacklist.py15
-rw-r--r--ansible_collections/community/general/plugins/modules/keycloak_authentication.py149
-rw-r--r--ansible_collections/community/general/plugins/modules/keycloak_authentication_required_actions.py457
-rw-r--r--ansible_collections/community/general/plugins/modules/keycloak_authz_authorization_scope.py12
-rw-r--r--ansible_collections/community/general/plugins/modules/keycloak_authz_custom_policy.py211
-rw-r--r--ansible_collections/community/general/plugins/modules/keycloak_authz_permission.py433
-rw-r--r--ansible_collections/community/general/plugins/modules/keycloak_authz_permission_info.py173
-rw-r--r--ansible_collections/community/general/plugins/modules/keycloak_client.py117
-rw-r--r--ansible_collections/community/general/plugins/modules/keycloak_client_rolemapping.py61
-rw-r--r--ansible_collections/community/general/plugins/modules/keycloak_clientscope.py52
-rw-r--r--ansible_collections/community/general/plugins/modules/keycloak_clientscope_type.py6
-rw-r--r--ansible_collections/community/general/plugins/modules/keycloak_clientsecret_info.py6
-rw-r--r--ansible_collections/community/general/plugins/modules/keycloak_clienttemplate.py67
-rw-r--r--ansible_collections/community/general/plugins/modules/keycloak_component_info.py169
-rw-r--r--ansible_collections/community/general/plugins/modules/keycloak_group.py10
-rw-r--r--ansible_collections/community/general/plugins/modules/keycloak_identity_provider.py36
-rw-r--r--ansible_collections/community/general/plugins/modules/keycloak_realm.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/keycloak_realm_key.py475
-rw-r--r--ansible_collections/community/general/plugins/modules/keycloak_realm_rolemapping.py391
-rw-r--r--ansible_collections/community/general/plugins/modules/keycloak_role.py81
-rw-r--r--ansible_collections/community/general/plugins/modules/keycloak_user.py542
-rw-r--r--ansible_collections/community/general/plugins/modules/keycloak_user_federation.py69
-rw-r--r--ansible_collections/community/general/plugins/modules/keycloak_user_rolemapping.py8
-rw-r--r--ansible_collections/community/general/plugins/modules/keyring.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/kibana_plugin.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/launchd.py10
-rw-r--r--ansible_collections/community/general/plugins/modules/layman.py15
-rw-r--r--ansible_collections/community/general/plugins/modules/ldap_attrs.py67
-rw-r--r--ansible_collections/community/general/plugins/modules/ldap_entry.py17
-rw-r--r--ansible_collections/community/general/plugins/modules/ldap_passwd.py11
-rw-r--r--ansible_collections/community/general/plugins/modules/ldap_search.py117
-rw-r--r--ansible_collections/community/general/plugins/modules/linode.py7
-rw-r--r--ansible_collections/community/general/plugins/modules/linode_v4.py5
-rw-r--r--ansible_collections/community/general/plugins/modules/listen_ports_facts.py13
-rw-r--r--ansible_collections/community/general/plugins/modules/locale_gen.py334
-rw-r--r--ansible_collections/community/general/plugins/modules/lvg.py367
-rw-r--r--ansible_collections/community/general/plugins/modules/lvg_rename.py170
-rw-r--r--ansible_collections/community/general/plugins/modules/lvol.py43
-rw-r--r--ansible_collections/community/general/plugins/modules/lxc_container.py24
-rw-r--r--ansible_collections/community/general/plugins/modules/lxd_container.py78
-rw-r--r--ansible_collections/community/general/plugins/modules/lxd_profile.py15
-rw-r--r--ansible_collections/community/general/plugins/modules/lxd_project.py17
-rw-r--r--ansible_collections/community/general/plugins/modules/macports.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/mail.py36
-rw-r--r--ansible_collections/community/general/plugins/modules/make.py54
-rw-r--r--ansible_collections/community/general/plugins/modules/manageiq_alert_profiles.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/manageiq_alerts.py6
-rw-r--r--ansible_collections/community/general/plugins/modules/manageiq_group.py22
-rw-r--r--ansible_collections/community/general/plugins/modules/manageiq_policies.py53
-rw-r--r--ansible_collections/community/general/plugins/modules/manageiq_policies_info.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/manageiq_provider.py101
-rw-r--r--ansible_collections/community/general/plugins/modules/manageiq_tags.py45
-rw-r--r--ansible_collections/community/general/plugins/modules/manageiq_tags_info.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/manageiq_tenant.py14
-rw-r--r--ansible_collections/community/general/plugins/modules/manageiq_user.py14
-rw-r--r--ansible_collections/community/general/plugins/modules/mas.py20
-rw-r--r--ansible_collections/community/general/plugins/modules/mattermost.py10
-rw-r--r--ansible_collections/community/general/plugins/modules/maven_artifact.py34
-rw-r--r--ansible_collections/community/general/plugins/modules/memset_dns_reload.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/memset_memstore_info.py5
-rw-r--r--ansible_collections/community/general/plugins/modules/memset_server_info.py5
-rw-r--r--ansible_collections/community/general/plugins/modules/memset_zone.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/memset_zone_domain.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/memset_zone_record.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/modprobe.py12
-rw-r--r--ansible_collections/community/general/plugins/modules/monit.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/mqtt.py6
-rw-r--r--ansible_collections/community/general/plugins/modules/mssql_db.py1
-rw-r--r--ansible_collections/community/general/plugins/modules/mssql_script.py95
-rw-r--r--ansible_collections/community/general/plugins/modules/nagios.py33
-rw-r--r--ansible_collections/community/general/plugins/modules/netcup_dns.py17
-rw-r--r--ansible_collections/community/general/plugins/modules/newrelic_deployment.py46
-rw-r--r--ansible_collections/community/general/plugins/modules/nexmo.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/nictagadm.py14
-rw-r--r--ansible_collections/community/general/plugins/modules/nmcli.py462
-rw-r--r--ansible_collections/community/general/plugins/modules/nomad_job.py14
-rw-r--r--ansible_collections/community/general/plugins/modules/nomad_job_info.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/nomad_token.py301
-rw-r--r--ansible_collections/community/general/plugins/modules/nosh.py20
-rw-r--r--ansible_collections/community/general/plugins/modules/npm.py95
-rw-r--r--ansible_collections/community/general/plugins/modules/nsupdate.py17
-rw-r--r--ansible_collections/community/general/plugins/modules/ocapi_command.py6
-rw-r--r--ansible_collections/community/general/plugins/modules/ocapi_info.py16
-rw-r--r--ansible_collections/community/general/plugins/modules/oci_vcn.py12
-rw-r--r--ansible_collections/community/general/plugins/modules/odbc.py3
-rw-r--r--ansible_collections/community/general/plugins/modules/one_host.py10
-rw-r--r--ansible_collections/community/general/plugins/modules/one_image.py20
-rw-r--r--ansible_collections/community/general/plugins/modules/one_image_info.py13
-rw-r--r--ansible_collections/community/general/plugins/modules/one_service.py16
-rw-r--r--ansible_collections/community/general/plugins/modules/one_template.py24
-rw-r--r--ansible_collections/community/general/plugins/modules/one_vm.py96
-rw-r--r--ansible_collections/community/general/plugins/modules/oneandone_firewall_policy.py1
-rw-r--r--ansible_collections/community/general/plugins/modules/oneandone_load_balancer.py5
-rw-r--r--ansible_collections/community/general/plugins/modules/oneandone_monitoring_policy.py1
-rw-r--r--ansible_collections/community/general/plugins/modules/oneandone_private_network.py1
-rw-r--r--ansible_collections/community/general/plugins/modules/oneandone_public_ip.py1
-rw-r--r--ansible_collections/community/general/plugins/modules/oneandone_server.py3
-rw-r--r--ansible_collections/community/general/plugins/modules/onepassword_info.py9
-rw-r--r--ansible_collections/community/general/plugins/modules/oneview_datacenter_info.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/oneview_enclosure_info.py6
-rw-r--r--ansible_collections/community/general/plugins/modules/oneview_ethernet_network.py6
-rw-r--r--ansible_collections/community/general/plugins/modules/oneview_ethernet_network_info.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/oneview_fc_network.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/oneview_fc_network_info.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/oneview_fcoe_network.py6
-rw-r--r--ansible_collections/community/general/plugins/modules/oneview_fcoe_network_info.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/oneview_logical_interconnect_group.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/oneview_logical_interconnect_group_info.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/oneview_network_set.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/oneview_network_set_info.py6
-rw-r--r--ansible_collections/community/general/plugins/modules/oneview_san_manager.py6
-rw-r--r--ansible_collections/community/general/plugins/modules/oneview_san_manager_info.py10
-rw-r--r--ansible_collections/community/general/plugins/modules/open_iscsi.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/openbsd_pkg.py20
-rw-r--r--ansible_collections/community/general/plugins/modules/openwrt_init.py7
-rw-r--r--ansible_collections/community/general/plugins/modules/opkg.py21
-rw-r--r--ansible_collections/community/general/plugins/modules/osx_defaults.py7
-rw-r--r--ansible_collections/community/general/plugins/modules/ovh_ip_failover.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/ovh_monthly_billing.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/pacemaker_cluster.py8
-rw-r--r--ansible_collections/community/general/plugins/modules/packet_device.py16
-rw-r--r--ansible_collections/community/general/plugins/modules/packet_ip_subnet.py9
-rw-r--r--ansible_collections/community/general/plugins/modules/packet_project.py3
-rw-r--r--ansible_collections/community/general/plugins/modules/packet_sshkey.py3
-rw-r--r--ansible_collections/community/general/plugins/modules/packet_volume.py3
-rw-r--r--ansible_collections/community/general/plugins/modules/packet_volume_attachment.py3
-rw-r--r--ansible_collections/community/general/plugins/modules/pacman.py86
-rw-r--r--ansible_collections/community/general/plugins/modules/pacman_key.py10
-rw-r--r--ansible_collections/community/general/plugins/modules/pagerduty.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/pagerduty_alert.py286
-rw-r--r--ansible_collections/community/general/plugins/modules/pagerduty_change.py6
-rw-r--r--ansible_collections/community/general/plugins/modules/pagerduty_user.py8
-rw-r--r--ansible_collections/community/general/plugins/modules/pam_limits.py39
-rw-r--r--ansible_collections/community/general/plugins/modules/pamd.py24
-rw-r--r--ansible_collections/community/general/plugins/modules/parted.py44
-rw-r--r--ansible_collections/community/general/plugins/modules/pear.py8
-rw-r--r--ansible_collections/community/general/plugins/modules/pids.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/pip_package_info.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/pipx.py26
-rw-r--r--ansible_collections/community/general/plugins/modules/pipx_info.py10
-rw-r--r--ansible_collections/community/general/plugins/modules/pkg5.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/pkgin.py11
-rw-r--r--ansible_collections/community/general/plugins/modules/pkgng.py23
-rw-r--r--ansible_collections/community/general/plugins/modules/pkgutil.py10
-rw-r--r--ansible_collections/community/general/plugins/modules/pmem.py28
-rw-r--r--ansible_collections/community/general/plugins/modules/pnpm.py462
-rw-r--r--ansible_collections/community/general/plugins/modules/portage.py6
-rw-r--r--ansible_collections/community/general/plugins/modules/pritunl_org.py10
-rw-r--r--ansible_collections/community/general/plugins/modules/pritunl_user.py18
-rw-r--r--ansible_collections/community/general/plugins/modules/pritunl_user_info.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/profitbricks.py3
-rw-r--r--ansible_collections/community/general/plugins/modules/profitbricks_datacenter.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/profitbricks_nic.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/profitbricks_volume.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/profitbricks_volume_attachments.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/proxmox.py412
-rw-r--r--ansible_collections/community/general/plugins/modules/proxmox_disk.py188
-rw-r--r--ansible_collections/community/general/plugins/modules/proxmox_kvm.py497
-rw-r--r--ansible_collections/community/general/plugins/modules/proxmox_nic.py10
-rw-r--r--ansible_collections/community/general/plugins/modules/proxmox_node_info.py140
-rw-r--r--ansible_collections/community/general/plugins/modules/proxmox_pool.py180
-rw-r--r--ansible_collections/community/general/plugins/modules/proxmox_pool_member.py238
-rw-r--r--ansible_collections/community/general/plugins/modules/proxmox_snap.py47
-rw-r--r--ansible_collections/community/general/plugins/modules/proxmox_storage_contents_info.py144
-rw-r--r--ansible_collections/community/general/plugins/modules/proxmox_storage_info.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/proxmox_tasks_info.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/proxmox_template.py98
-rw-r--r--ansible_collections/community/general/plugins/modules/proxmox_user_info.py6
-rw-r--r--ansible_collections/community/general/plugins/modules/proxmox_vm_info.py267
-rw-r--r--ansible_collections/community/general/plugins/modules/pubnub_blocks.py21
-rw-r--r--ansible_collections/community/general/plugins/modules/pulp_repo.py16
-rw-r--r--ansible_collections/community/general/plugins/modules/puppet.py18
-rw-r--r--ansible_collections/community/general/plugins/modules/pushbullet.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/python_requirements_info.py7
-rw-r--r--ansible_collections/community/general/plugins/modules/rax.py30
-rw-r--r--ansible_collections/community/general/plugins/modules/rax_cbs.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/rax_cbs_attachments.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/rax_cdb.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/rax_cdb_database.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/rax_cdb_user.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/rax_clb.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/rax_clb_nodes.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/rax_clb_ssl.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/rax_dns.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/rax_dns_record.py10
-rw-r--r--ansible_collections/community/general/plugins/modules/rax_facts.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/rax_files.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/rax_files_objects.py14
-rw-r--r--ansible_collections/community/general/plugins/modules/rax_identity.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/rax_keypair.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/rax_meta.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/rax_mon_alarm.py16
-rw-r--r--ansible_collections/community/general/plugins/modules/rax_mon_check.py66
-rw-r--r--ansible_collections/community/general/plugins/modules/rax_mon_entity.py12
-rw-r--r--ansible_collections/community/general/plugins/modules/rax_mon_notification.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/rax_mon_notification_plan.py12
-rw-r--r--ansible_collections/community/general/plugins/modules/rax_scaling_group.py6
-rw-r--r--ansible_collections/community/general/plugins/modules/rax_scaling_policy.py8
-rw-r--r--ansible_collections/community/general/plugins/modules/read_csv.py18
-rw-r--r--ansible_collections/community/general/plugins/modules/redfish_command.py113
-rw-r--r--ansible_collections/community/general/plugins/modules/redfish_config.py124
-rw-r--r--ansible_collections/community/general/plugins/modules/redfish_info.py51
-rw-r--r--ansible_collections/community/general/plugins/modules/redhat_subscription.py180
-rw-r--r--ansible_collections/community/general/plugins/modules/redis.py10
-rw-r--r--ansible_collections/community/general/plugins/modules/redis_data.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/redis_data_incr.py6
-rw-r--r--ansible_collections/community/general/plugins/modules/redis_info.py48
-rw-r--r--ansible_collections/community/general/plugins/modules/rhevm.py8
-rw-r--r--ansible_collections/community/general/plugins/modules/rhn_channel.py14
-rw-r--r--ansible_collections/community/general/plugins/modules/rhn_register.py18
-rw-r--r--ansible_collections/community/general/plugins/modules/rhsm_release.py8
-rw-r--r--ansible_collections/community/general/plugins/modules/rhsm_repository.py184
-rw-r--r--ansible_collections/community/general/plugins/modules/riak.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/rocketchat.py16
-rw-r--r--ansible_collections/community/general/plugins/modules/rollbar_deployment.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/rpm_ostree_pkg.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/rundeck_acl_policy.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/rundeck_job_run.py6
-rw-r--r--ansible_collections/community/general/plugins/modules/runit.py10
-rw-r--r--ansible_collections/community/general/plugins/modules/sap_task_list_execute.py348
-rw-r--r--ansible_collections/community/general/plugins/modules/sapcar_extract.py228
-rw-r--r--ansible_collections/community/general/plugins/modules/scaleway_compute.py8
-rw-r--r--ansible_collections/community/general/plugins/modules/scaleway_compute_private_network.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/scaleway_container.py8
-rw-r--r--ansible_collections/community/general/plugins/modules/scaleway_container_namespace.py6
-rw-r--r--ansible_collections/community/general/plugins/modules/scaleway_container_registry.py8
-rw-r--r--ansible_collections/community/general/plugins/modules/scaleway_database_backup.py28
-rw-r--r--ansible_collections/community/general/plugins/modules/scaleway_function.py8
-rw-r--r--ansible_collections/community/general/plugins/modules/scaleway_function_namespace.py6
-rw-r--r--ansible_collections/community/general/plugins/modules/scaleway_ip.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/scaleway_private_network.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/scaleway_security_group.py6
-rw-r--r--ansible_collections/community/general/plugins/modules/scaleway_security_group_rule.py23
-rw-r--r--ansible_collections/community/general/plugins/modules/scaleway_sshkey.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/scaleway_volume.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/sefcontext.py36
-rw-r--r--ansible_collections/community/general/plugins/modules/selinux_permissive.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/sendgrid.py5
-rw-r--r--ansible_collections/community/general/plugins/modules/sensu_check.py18
-rw-r--r--ansible_collections/community/general/plugins/modules/sensu_client.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/serverless.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/shutdown.py8
-rw-r--r--ansible_collections/community/general/plugins/modules/simpleinit_msb.py322
-rw-r--r--ansible_collections/community/general/plugins/modules/sl_vm.py3
-rw-r--r--ansible_collections/community/general/plugins/modules/slack.py41
-rw-r--r--ansible_collections/community/general/plugins/modules/slackpkg.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/smartos_image_info.py8
-rw-r--r--ansible_collections/community/general/plugins/modules/snap.py254
-rw-r--r--ansible_collections/community/general/plugins/modules/snap_alias.py33
-rw-r--r--ansible_collections/community/general/plugins/modules/snmp_facts.py18
-rw-r--r--ansible_collections/community/general/plugins/modules/solaris_zone.py24
-rw-r--r--ansible_collections/community/general/plugins/modules/sorcery.py255
-rw-r--r--ansible_collections/community/general/plugins/modules/spectrum_device.py14
-rw-r--r--ansible_collections/community/general/plugins/modules/spectrum_model_attrs.py8
-rw-r--r--ansible_collections/community/general/plugins/modules/spotinst_aws_elastigroup.py21
-rw-r--r--ansible_collections/community/general/plugins/modules/ssh_config.py82
-rw-r--r--ansible_collections/community/general/plugins/modules/stackdriver.py5
-rw-r--r--ansible_collections/community/general/plugins/modules/stacki_host.py14
-rw-r--r--ansible_collections/community/general/plugins/modules/statsd.py12
-rw-r--r--ansible_collections/community/general/plugins/modules/statusio_maintenance.py13
-rw-r--r--ansible_collections/community/general/plugins/modules/sudoers.py36
-rw-r--r--ansible_collections/community/general/plugins/modules/supervisorctl.py33
-rw-r--r--ansible_collections/community/general/plugins/modules/svc.py10
-rw-r--r--ansible_collections/community/general/plugins/modules/svr4pkg.py14
-rw-r--r--ansible_collections/community/general/plugins/modules/swdepot.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/swupd.py6
-rw-r--r--ansible_collections/community/general/plugins/modules/sysrc.py24
-rw-r--r--ansible_collections/community/general/plugins/modules/sysupgrade.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/telegram.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/terraform.py103
-rw-r--r--ansible_collections/community/general/plugins/modules/timezone.py12
-rw-r--r--ansible_collections/community/general/plugins/modules/udm_dns_record.py16
-rw-r--r--ansible_collections/community/general/plugins/modules/udm_dns_zone.py8
-rw-r--r--ansible_collections/community/general/plugins/modules/udm_share.py7
-rw-r--r--ansible_collections/community/general/plugins/modules/udm_user.py36
-rw-r--r--ansible_collections/community/general/plugins/modules/ufw.py44
-rw-r--r--ansible_collections/community/general/plugins/modules/urpmi.py8
-rw-r--r--ansible_collections/community/general/plugins/modules/usb_facts.py113
-rw-r--r--ansible_collections/community/general/plugins/modules/utm_proxy_location.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/utm_proxy_location_info.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/vdo.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/vertica_info.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/vertica_role.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/vertica_schema.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/vertica_user.py8
-rw-r--r--ansible_collections/community/general/plugins/modules/vmadm.py28
-rw-r--r--ansible_collections/community/general/plugins/modules/wdc_redfish_command.py6
-rw-r--r--ansible_collections/community/general/plugins/modules/wdc_redfish_info.py4
-rw-r--r--ansible_collections/community/general/plugins/modules/webfaction_app.py12
-rw-r--r--ansible_collections/community/general/plugins/modules/webfaction_db.py12
-rw-r--r--ansible_collections/community/general/plugins/modules/webfaction_domain.py16
-rw-r--r--ansible_collections/community/general/plugins/modules/webfaction_mailbox.py12
-rw-r--r--ansible_collections/community/general/plugins/modules/webfaction_site.py14
-rw-r--r--ansible_collections/community/general/plugins/modules/xattr.py17
-rw-r--r--ansible_collections/community/general/plugins/modules/xbps.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/xcc_redfish_command.py10
-rw-r--r--ansible_collections/community/general/plugins/modules/xenserver_facts.py2
-rw-r--r--ansible_collections/community/general/plugins/modules/xenserver_guest.py63
-rw-r--r--ansible_collections/community/general/plugins/modules/xenserver_guest_info.py10
-rw-r--r--ansible_collections/community/general/plugins/modules/xenserver_guest_powerstate.py15
-rw-r--r--ansible_collections/community/general/plugins/modules/xfconf.py44
-rw-r--r--ansible_collections/community/general/plugins/modules/xfconf_info.py6
-rw-r--r--ansible_collections/community/general/plugins/modules/xml.py54
-rw-r--r--ansible_collections/community/general/plugins/modules/yum_versionlock.py30
-rw-r--r--ansible_collections/community/general/plugins/modules/zfs.py8
-rw-r--r--ansible_collections/community/general/plugins/modules/zfs_delegate_admin.py18
-rw-r--r--ansible_collections/community/general/plugins/modules/znode.py7
-rw-r--r--ansible_collections/community/general/plugins/modules/zypper.py26
-rw-r--r--ansible_collections/community/general/plugins/modules/zypper_repository.py5
-rw-r--r--ansible_collections/community/general/plugins/test/fqdn_valid.py103
-rw-r--r--ansible_collections/community/general/tests/.gitignore1
-rw-r--r--ansible_collections/community/general/tests/galaxy-importer.cfg8
-rw-r--r--ansible_collections/community/general/tests/integration/targets/aix_filesystem/tasks/main.yml2
-rw-r--r--ansible_collections/community/general/tests/integration/targets/alternatives/tasks/tests_set_priority.yml2
-rw-r--r--ansible_collections/community/general/tests/integration/targets/ansible_galaxy_install/aliases1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/apache2_module/tasks/actualtest.yml2
-rw-r--r--ansible_collections/community/general/tests/integration/targets/apk/aliases13
-rw-r--r--ansible_collections/community/general/tests/integration/targets/apk/tasks/main.yml160
-rw-r--r--ansible_collections/community/general/tests/integration/targets/archive/tests/core.yml10
-rw-r--r--ansible_collections/community/general/tests/integration/targets/archive/tests/remove.yml30
-rw-r--r--ansible_collections/community/general/tests/integration/targets/btrfs_subvolume/aliases2
-rw-r--r--ansible_collections/community/general/tests/integration/targets/callback_default_without_diff/aliases6
-rw-r--r--ansible_collections/community/general/tests/integration/targets/callback_default_without_diff/tasks/main.yml65
-rw-r--r--ansible_collections/community/general/tests/integration/targets/cargo/tasks/main.yml2
-rw-r--r--ansible_collections/community/general/tests/integration/targets/cargo/tasks/setup.yml14
-rw-r--r--ansible_collections/community/general/tests/integration/targets/cargo/tasks/test_rustup_cargo.yml23
-rw-r--r--ansible_collections/community/general/tests/integration/targets/cloud_init_data_facts/tasks/main.yml11
-rw-r--r--ansible_collections/community/general/tests/integration/targets/cmd_runner/action_plugins/_unsafe_assert.py56
-rw-r--r--ansible_collections/community/general/tests/integration/targets/cmd_runner/library/cmd_echo.py5
-rw-r--r--ansible_collections/community/general/tests/integration/targets/cmd_runner/meta/main.yml7
-rw-r--r--ansible_collections/community/general/tests/integration/targets/cmd_runner/tasks/main.yml1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/cmd_runner/tasks/test_cmd_echo.yml28
-rw-r--r--ansible_collections/community/general/tests/integration/targets/cmd_runner/vars/main.yml139
-rw-r--r--ansible_collections/community/general/tests/integration/targets/connection_incus/aliases6
-rwxr-xr-xansible_collections/community/general/tests/integration/targets/connection_incus/runme.sh21
-rw-r--r--ansible_collections/community/general/tests/integration/targets/connection_incus/test_connection.inventory11
-rw-r--r--ansible_collections/community/general/tests/integration/targets/consul/tasks/consul_auth_method.yml74
-rw-r--r--ansible_collections/community/general/tests/integration/targets/consul/tasks/consul_binding_rule.yml73
-rw-r--r--ansible_collections/community/general/tests/integration/targets/consul/tasks/consul_general.yml76
-rw-r--r--ansible_collections/community/general/tests/integration/targets/consul/tasks/consul_kv.yml57
-rw-r--r--ansible_collections/community/general/tests/integration/targets/consul/tasks/consul_policy.yml72
-rw-r--r--ansible_collections/community/general/tests/integration/targets/consul/tasks/consul_role.yml194
-rw-r--r--ansible_collections/community/general/tests/integration/targets/consul/tasks/consul_session.yml57
-rw-r--r--ansible_collections/community/general/tests/integration/targets/consul/tasks/consul_token.yml88
-rw-r--r--ansible_collections/community/general/tests/integration/targets/consul/tasks/main.yml28
-rw-r--r--ansible_collections/community/general/tests/integration/targets/consul/templates/consul_config.hcl.j25
-rw-r--r--ansible_collections/community/general/tests/integration/targets/copr/tasks/main.yml6
-rw-r--r--ansible_collections/community/general/tests/integration/targets/deploy_helper/tasks/main.yml18
-rw-r--r--ansible_collections/community/general/tests/integration/targets/django_manage/aliases5
-rw-r--r--ansible_collections/community/general/tests/integration/targets/ejabberd_user/aliases11
-rw-r--r--ansible_collections/community/general/tests/integration/targets/ejabberd_user/handlers/main.yml9
-rw-r--r--ansible_collections/community/general/tests/integration/targets/ejabberd_user/meta/main.yml7
-rw-r--r--ansible_collections/community/general/tests/integration/targets/ejabberd_user/tasks/main.yml122
-rw-r--r--ansible_collections/community/general/tests/integration/targets/etcd3/aliases1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/filesize/tasks/sparse.yml122
-rw-r--r--ansible_collections/community/general/tests/integration/targets/filesystem/defaults/main.yml28
-rw-r--r--ansible_collections/community/general/tests/integration/targets/filesystem/tasks/main.yml3
-rw-r--r--ansible_collections/community/general/tests/integration/targets/filesystem/tasks/reset_fs_uuid.yml59
-rw-r--r--ansible_collections/community/general/tests/integration/targets/filesystem/tasks/set_fs_uuid_on_creation.yml44
-rw-r--r--ansible_collections/community/general/tests/integration/targets/filesystem/tasks/set_fs_uuid_on_creation_with_opts.yml33
-rw-r--r--ansible_collections/community/general/tests/integration/targets/filter_counter/aliases1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/filter_dict/aliases1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/filter_dict_kv/aliases1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/filter_from_csv/aliases1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/filter_from_ini/tasks/main.yml60
-rw-r--r--ansible_collections/community/general/tests/integration/targets/filter_from_ini/vars/main.yml8
-rw-r--r--ansible_collections/community/general/tests/integration/targets/filter_groupby_as_dict/aliases1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/filter_hashids/aliases1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/filter_jc/aliases3
-rw-r--r--ansible_collections/community/general/tests/integration/targets/filter_json_query/aliases1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/filter_lists/aliases5
-rw-r--r--ansible_collections/community/general/tests/integration/targets/filter_lists/tasks/main.yml64
-rw-r--r--ansible_collections/community/general/tests/integration/targets/filter_lists/vars/main.yml8
-rw-r--r--ansible_collections/community/general/tests/integration/targets/filter_lists_mergeby/aliases1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/filter_path_join_shim/aliases1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/filter_random_mac/aliases1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/filter_time/aliases1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/filter_to_ini/tasks/main.yml58
-rw-r--r--ansible_collections/community/general/tests/integration/targets/filter_to_ini/vars/main.yml8
-rw-r--r--ansible_collections/community/general/tests/integration/targets/filter_unicode_normalize/aliases1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/filter_version_sort/aliases1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/gem/tasks/main.yml2
-rw-r--r--ansible_collections/community/general/tests/integration/targets/git_config/files/gitconfig5
-rw-r--r--ansible_collections/community/general/tests/integration/targets/git_config/tasks/get_set_state_present_file.yml1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/git_config/tasks/main.yml3
-rw-r--r--ansible_collections/community/general/tests/integration/targets/git_config/tasks/set_multi_value.yml79
-rw-r--r--ansible_collections/community/general/tests/integration/targets/git_config/tasks/set_value.yml39
-rw-r--r--ansible_collections/community/general/tests/integration/targets/git_config/tasks/set_value_with_tilde.yml4
-rw-r--r--ansible_collections/community/general/tests/integration/targets/git_config/tasks/unset_multi_value.yml28
-rw-r--r--ansible_collections/community/general/tests/integration/targets/git_config_info/aliases7
-rw-r--r--ansible_collections/community/general/tests/integration/targets/git_config_info/files/gitconfig11
-rw-r--r--ansible_collections/community/general/tests/integration/targets/git_config_info/meta/main.yml7
-rw-r--r--ansible_collections/community/general/tests/integration/targets/git_config_info/tasks/error_handling.yml26
-rw-r--r--ansible_collections/community/general/tests/integration/targets/git_config_info/tasks/get_all_values.yml19
-rw-r--r--ansible_collections/community/general/tests/integration/targets/git_config_info/tasks/get_multi_value.yml20
-rw-r--r--ansible_collections/community/general/tests/integration/targets/git_config_info/tasks/get_simple_value.yml38
-rw-r--r--ansible_collections/community/general/tests/integration/targets/git_config_info/tasks/main.yml33
-rw-r--r--ansible_collections/community/general/tests/integration/targets/git_config_info/tasks/setup.yml15
-rw-r--r--ansible_collections/community/general/tests/integration/targets/git_config_info/tasks/setup_file.yml16
-rw-r--r--ansible_collections/community/general/tests/integration/targets/git_config_info/tasks/setup_global.yml16
-rw-r--r--ansible_collections/community/general/tests/integration/targets/git_config_info/vars/main.yml7
-rw-r--r--ansible_collections/community/general/tests/integration/targets/gitlab_group_access_token/aliases7
-rw-r--r--ansible_collections/community/general/tests/integration/targets/gitlab_group_access_token/defaults/main.yml15
-rw-r--r--ansible_collections/community/general/tests/integration/targets/gitlab_group_access_token/tasks/main.yml221
-rw-r--r--ansible_collections/community/general/tests/integration/targets/gitlab_instance_variable/aliases5
-rw-r--r--ansible_collections/community/general/tests/integration/targets/gitlab_instance_variable/tasks/main.yml606
-rw-r--r--ansible_collections/community/general/tests/integration/targets/gitlab_issue/aliases6
-rw-r--r--ansible_collections/community/general/tests/integration/targets/gitlab_issue/defaults/main.yml15
-rw-r--r--ansible_collections/community/general/tests/integration/targets/gitlab_issue/files/description.md9
-rw-r--r--ansible_collections/community/general/tests/integration/targets/gitlab_issue/tasks/main.yml150
-rw-r--r--ansible_collections/community/general/tests/integration/targets/gitlab_label/README.md19
-rw-r--r--ansible_collections/community/general/tests/integration/targets/gitlab_label/aliases6
-rw-r--r--ansible_collections/community/general/tests/integration/targets/gitlab_label/defaults/main.yml17
-rw-r--r--ansible_collections/community/general/tests/integration/targets/gitlab_label/tasks/main.yml463
-rw-r--r--ansible_collections/community/general/tests/integration/targets/gitlab_merge_request/aliases6
-rw-r--r--ansible_collections/community/general/tests/integration/targets/gitlab_merge_request/defaults/main.yml14
-rw-r--r--ansible_collections/community/general/tests/integration/targets/gitlab_merge_request/files/description.md9
-rw-r--r--ansible_collections/community/general/tests/integration/targets/gitlab_merge_request/tasks/main.yml129
-rw-r--r--ansible_collections/community/general/tests/integration/targets/gitlab_milestone/README.md19
-rw-r--r--ansible_collections/community/general/tests/integration/targets/gitlab_milestone/aliases6
-rw-r--r--ansible_collections/community/general/tests/integration/targets/gitlab_milestone/defaults/main.yml18
-rw-r--r--ansible_collections/community/general/tests/integration/targets/gitlab_milestone/tasks/main.yml388
-rw-r--r--ansible_collections/community/general/tests/integration/targets/gitlab_project_access_token/aliases7
-rw-r--r--ansible_collections/community/general/tests/integration/targets/gitlab_project_access_token/defaults/main.yml15
-rw-r--r--ansible_collections/community/general/tests/integration/targets/gitlab_project_access_token/tasks/main.yml221
-rw-r--r--ansible_collections/community/general/tests/integration/targets/homebrew/aliases1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/homebrew/tasks/casks.yml99
-rw-r--r--ansible_collections/community/general/tests/integration/targets/homebrew/tasks/formulae.yml99
-rw-r--r--ansible_collections/community/general/tests/integration/targets/homebrew/tasks/main.yml92
-rw-r--r--ansible_collections/community/general/tests/integration/targets/homebrew_cask/aliases1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/homectl/aliases2
-rw-r--r--ansible_collections/community/general/tests/integration/targets/htpasswd/aliases7
-rw-r--r--ansible_collections/community/general/tests/integration/targets/htpasswd/handlers/main.yml9
-rw-r--r--ansible_collections/community/general/tests/integration/targets/htpasswd/meta/main.yml7
-rw-r--r--ansible_collections/community/general/tests/integration/targets/htpasswd/tasks/main.yml83
-rw-r--r--ansible_collections/community/general/tests/integration/targets/htpasswd/vars/main.yml6
-rw-r--r--ansible_collections/community/general/tests/integration/targets/ini_file/tasks/main.yml12
-rw-r--r--ansible_collections/community/general/tests/integration/targets/ini_file/tasks/tests/00-basic.yml4
-rw-r--r--ansible_collections/community/general/tests/integration/targets/ini_file/tasks/tests/04-symlink.yml59
-rw-r--r--ansible_collections/community/general/tests/integration/targets/ini_file/tasks/tests/05-ignore_spaces.yml123
-rw-r--r--ansible_collections/community/general/tests/integration/targets/ini_file/tasks/tests/06-modify_inactive_option.yml123
-rw-r--r--ansible_collections/community/general/tests/integration/targets/ini_file/tasks/tests/07-section_name_spaces.yml103
-rw-r--r--ansible_collections/community/general/tests/integration/targets/interfaces_file/tasks/main.yml58
-rw-r--r--ansible_collections/community/general/tests/integration/targets/iptables_state/tasks/main.yml6
-rw-r--r--ansible_collections/community/general/tests/integration/targets/iptables_state/tasks/tests/02-partial-restore.yml66
-rw-r--r--ansible_collections/community/general/tests/integration/targets/iso_create/aliases1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/iso_customize/aliases1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/iso_customize/tasks/iso_customize_exception.yml2
-rw-r--r--ansible_collections/community/general/tests/integration/targets/iso_extract/aliases4
-rw-r--r--ansible_collections/community/general/tests/integration/targets/java_cert/aliases1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/java_cert/files/setupSSLServer.py13
-rw-r--r--ansible_collections/community/general/tests/integration/targets/java_cert/tasks/state_change.yml2
-rw-r--r--ansible_collections/community/general/tests/integration/targets/java_keystore/aliases1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/kernel_blacklist/aliases4
-rw-r--r--ansible_collections/community/general/tests/integration/targets/kernel_blacklist/handlers/main.yml10
-rw-r--r--ansible_collections/community/general/tests/integration/targets/kernel_blacklist/tasks/main.yml72
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_authz_authorization_scope/readme.adoc2
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/aliases5
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/policy/Containerfile4
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/policy/Containerfile.license3
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/policy/META-INF/keycloak-scripts.json14
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/policy/META-INF/keycloak-scripts.json.license3
-rwxr-xr-xansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/policy/build-policy.sh2
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/policy/build-policy.sh.license3
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/policy/policy-1.js1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/policy/policy-1.js.license3
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/policy/policy-2.js1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/policy/policy-2.js.license3
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/readme.adoc27
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/tasks/main.yml168
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/vars/main.yml11
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_authz_permission/aliases6
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_authz_permission/readme.adoc27
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_authz_permission/tasks/main.yml567
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_authz_permission/vars/main.yml11
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_client/README.md20
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_client/docker-compose.yml31
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_client/tasks/main.yml120
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_client/vars/main.yml2
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_component_info/README.md20
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_component_info/aliases5
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_component_info/tasks/main.yml266
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_component_info/vars/main.yml19
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_group/readme.adoc2
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_group_rolemapping/README.md21
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_group_rolemapping/aliases4
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_group_rolemapping/tasks/main.yml160
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_group_rolemapping/vars/main.yml15
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_identity_provider/tasks/main.yml113
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_realm_key/aliases5
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_realm_key/readme.adoc27
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_realm_key/tasks/main.yml373
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_realm_key/vars/main.yml48
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_role/README.md20
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_role/tasks/main.yml233
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_role/vars/main.yml27
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_user/README.md21
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_user/aliases4
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_user/tasks/main.yml114
-rw-r--r--ansible_collections/community/general/tests/integration/targets/keycloak_user/vars/main.yml46
-rw-r--r--ansible_collections/community/general/tests/integration/targets/ldap_search/tasks/tests/auth.yml47
-rw-r--r--ansible_collections/community/general/tests/integration/targets/ldap_search/tasks/tests/basic.yml14
-rw-r--r--ansible_collections/community/general/tests/integration/targets/ldap_search/tasks/tests/pages.yml24
-rw-r--r--ansible_collections/community/general/tests/integration/targets/ldap_search/tasks/tests/schema.yml25
-rw-r--r--ansible_collections/community/general/tests/integration/targets/listen_ports_facts/tasks/main.yml2
-rw-r--r--ansible_collections/community/general/tests/integration/targets/locale_gen/aliases2
-rw-r--r--ansible_collections/community/general/tests/integration/targets/locale_gen/tasks/basic.yml102
-rw-r--r--ansible_collections/community/general/tests/integration/targets/locale_gen/tasks/locale_gen.yml99
-rw-r--r--ansible_collections/community/general/tests/integration/targets/locale_gen/tasks/main.yml10
-rw-r--r--ansible_collections/community/general/tests/integration/targets/locale_gen/vars/main.yml17
-rw-r--r--ansible_collections/community/general/tests/integration/targets/lookup_cartesian/aliases1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/lookup_dependent/aliases1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/lookup_dig/aliases1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/lookup_etcd3/aliases1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/lookup_flattened/aliases1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/lookup_lmdb_kv/aliases1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/lookup_merge_variables/aliases1
-rwxr-xr-xansible_collections/community/general/tests/integration/targets/lookup_merge_variables/runme.sh3
-rw-r--r--ansible_collections/community/general/tests/integration/targets/lookup_merge_variables/test_all_hosts.yml64
-rw-r--r--ansible_collections/community/general/tests/integration/targets/lookup_merge_variables/test_inventory_all_hosts.yml52
-rw-r--r--ansible_collections/community/general/tests/integration/targets/lookup_passwordstore/aliases1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/lookup_random_pet/aliases1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/lookup_random_string/aliases1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/lookup_random_words/aliases1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/lvg/tasks/main.yml10
-rw-r--r--ansible_collections/community/general/tests/integration/targets/lvg/tasks/setup.yml20
-rw-r--r--ansible_collections/community/general/tests/integration/targets/lvg/tasks/setup_missing_pv.yml18
-rw-r--r--ansible_collections/community/general/tests/integration/targets/lvg/tasks/teardown.yml14
-rw-r--r--ansible_collections/community/general/tests/integration/targets/lvg/tasks/teardown_missing_pv.yml8
-rw-r--r--ansible_collections/community/general/tests/integration/targets/lvg/tasks/test_active_change.yml163
-rw-r--r--ansible_collections/community/general/tests/integration/targets/lvg/tasks/test_active_create.yml71
-rw-r--r--ansible_collections/community/general/tests/integration/targets/lvg/tasks/test_pvresize.yml16
-rw-r--r--ansible_collections/community/general/tests/integration/targets/lvg/tasks/test_uuid_reset.yml107
-rw-r--r--ansible_collections/community/general/tests/integration/targets/lvg_rename/aliases13
-rw-r--r--ansible_collections/community/general/tests/integration/targets/lvg_rename/meta/main.yml9
-rw-r--r--ansible_collections/community/general/tests/integration/targets/lvg_rename/tasks/main.yml25
-rw-r--r--ansible_collections/community/general/tests/integration/targets/lvg_rename/tasks/setup.yml50
-rw-r--r--ansible_collections/community/general/tests/integration/targets/lvg_rename/tasks/teardown.yml46
-rw-r--r--ansible_collections/community/general/tests/integration/targets/lvg_rename/tasks/test.yml105
-rw-r--r--ansible_collections/community/general/tests/integration/targets/lvol/aliases12
-rw-r--r--ansible_collections/community/general/tests/integration/targets/lvol/meta/main.yml8
-rw-r--r--ansible_collections/community/general/tests/integration/targets/lvol/tasks/main.yml24
-rw-r--r--ansible_collections/community/general/tests/integration/targets/lvol/tasks/setup.yml57
-rw-r--r--ansible_collections/community/general/tests/integration/targets/lvol/tasks/teardown.yml40
-rw-r--r--ansible_collections/community/general/tests/integration/targets/lvol/tasks/test_pvs.yml64
-rw-r--r--ansible_collections/community/general/tests/integration/targets/mail/tasks/main.yml171
-rw-r--r--ansible_collections/community/general/tests/integration/targets/mas/tasks/main.yml2
-rw-r--r--ansible_collections/community/general/tests/integration/targets/monit/aliases1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/mssql_script/tasks/main.yml37
-rw-r--r--ansible_collections/community/general/tests/integration/targets/nomad/aliases1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/npm/tasks/test.yml13
-rw-r--r--ansible_collections/community/general/tests/integration/targets/odbc/aliases2
-rw-r--r--ansible_collections/community/general/tests/integration/targets/odbc/tasks/main.yml1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/one_host/tasks/main.yml2
-rw-r--r--ansible_collections/community/general/tests/integration/targets/osx_defaults/tasks/main.yml6
-rw-r--r--ansible_collections/community/general/tests/integration/targets/pacman/handlers/main.yml23
-rw-r--r--ansible_collections/community/general/tests/integration/targets/pacman/tasks/locally_installed_package.yml3
-rw-r--r--ansible_collections/community/general/tests/integration/targets/pacman/tasks/main.yml1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/pacman/tasks/remove_nosave.yml6
-rw-r--r--ansible_collections/community/general/tests/integration/targets/pacman/tasks/yay-become.yml66
-rw-r--r--ansible_collections/community/general/tests/integration/targets/pids/tasks/main.yml2
-rw-r--r--ansible_collections/community/general/tests/integration/targets/pids/templates/obtainpid.sh.j2 (renamed from ansible_collections/community/general/tests/integration/targets/pids/templates/obtainpid.sh)0
-rw-r--r--ansible_collections/community/general/tests/integration/targets/pipx/aliases1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/pipx/tasks/main.yml25
-rw-r--r--ansible_collections/community/general/tests/integration/targets/pipx_info/aliases1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/pkgng/tasks/freebsd.yml9
-rw-r--r--ansible_collections/community/general/tests/integration/targets/pnpm/aliases8
-rw-r--r--ansible_collections/community/general/tests/integration/targets/pnpm/meta/main.yml9
-rw-r--r--ansible_collections/community/general/tests/integration/targets/pnpm/tasks/main.yml27
-rw-r--r--ansible_collections/community/general/tests/integration/targets/pnpm/tasks/run.yml322
-rw-r--r--ansible_collections/community/general/tests/integration/targets/pnpm/templates/package.j213
-rw-r--r--ansible_collections/community/general/tests/integration/targets/proxmox/tasks/main.yml36
-rw-r--r--ansible_collections/community/general/tests/integration/targets/proxmox_pool/aliases7
-rw-r--r--ansible_collections/community/general/tests/integration/targets/proxmox_pool/defaults/main.yml7
-rw-r--r--ansible_collections/community/general/tests/integration/targets/proxmox_pool/tasks/main.yml220
-rw-r--r--ansible_collections/community/general/tests/integration/targets/proxmox_template/aliases6
-rw-r--r--ansible_collections/community/general/tests/integration/targets/proxmox_template/tasks/main.yml136
-rw-r--r--ansible_collections/community/general/tests/integration/targets/scaleway_compute/tasks/pagination.yml4
-rw-r--r--ansible_collections/community/general/tests/integration/targets/scaleway_container_registry/tasks/main.yml2
-rw-r--r--ansible_collections/community/general/tests/integration/targets/scaleway_image_info/tasks/main.yml4
-rw-r--r--ansible_collections/community/general/tests/integration/targets/scaleway_ip_info/tasks/main.yml4
-rw-r--r--ansible_collections/community/general/tests/integration/targets/scaleway_organization_info/tasks/main.yml2
-rw-r--r--ansible_collections/community/general/tests/integration/targets/scaleway_security_group_info/tasks/main.yml4
-rw-r--r--ansible_collections/community/general/tests/integration/targets/scaleway_server_info/tasks/main.yml4
-rw-r--r--ansible_collections/community/general/tests/integration/targets/scaleway_snapshot_info/tasks/main.yml4
-rw-r--r--ansible_collections/community/general/tests/integration/targets/scaleway_volume_info/tasks/main.yml4
-rw-r--r--ansible_collections/community/general/tests/integration/targets/setup_docker/handlers/main.yml18
-rw-r--r--ansible_collections/community/general/tests/integration/targets/setup_docker/tasks/main.yml2
-rw-r--r--ansible_collections/community/general/tests/integration/targets/setup_etcd3/tasks/main.yml2
-rw-r--r--ansible_collections/community/general/tests/integration/targets/setup_java_keytool/tasks/main.yml12
-rw-r--r--ansible_collections/community/general/tests/integration/targets/setup_java_keytool/vars/Alpine.yml3
-rw-r--r--ansible_collections/community/general/tests/integration/targets/setup_java_keytool/vars/Archlinux.yml3
-rw-r--r--ansible_collections/community/general/tests/integration/targets/setup_java_keytool/vars/Debian-12.yml8
-rw-r--r--ansible_collections/community/general/tests/integration/targets/setup_java_keytool/vars/Debian.yml3
-rw-r--r--ansible_collections/community/general/tests/integration/targets/setup_java_keytool/vars/RedHat.yml3
-rw-r--r--ansible_collections/community/general/tests/integration/targets/setup_java_keytool/vars/Suse.yml3
-rw-r--r--ansible_collections/community/general/tests/integration/targets/setup_openldap/files/cert_cnconfig.ldif15
-rw-r--r--ansible_collections/community/general/tests/integration/targets/setup_openldap/files/cert_cnconfig.ldif.license3
-rw-r--r--ansible_collections/community/general/tests/integration/targets/setup_openldap/files/initial_config.ldif19
-rw-r--r--ansible_collections/community/general/tests/integration/targets/setup_openldap/tasks/main.yml22
-rw-r--r--ansible_collections/community/general/tests/integration/targets/setup_pkg_mgr/tasks/archlinux.yml5
-rw-r--r--ansible_collections/community/general/tests/integration/targets/setup_postgresql_db/tasks/main.yml26
-rw-r--r--ansible_collections/community/general/tests/integration/targets/setup_postgresql_db/vars/Debian-12-py3.yml13
-rw-r--r--ansible_collections/community/general/tests/integration/targets/setup_snap/tasks/D-RedHat-9.2.yml6
-rw-r--r--ansible_collections/community/general/tests/integration/targets/setup_snap/tasks/D-RedHat-9.3.yml6
-rw-r--r--ansible_collections/community/general/tests/integration/targets/setup_tls/files/ca_certificate.pem4
-rw-r--r--ansible_collections/community/general/tests/integration/targets/setup_tls/files/ca_certificate.pem.license3
-rw-r--r--ansible_collections/community/general/tests/integration/targets/setup_tls/files/ca_key.pem4
-rw-r--r--ansible_collections/community/general/tests/integration/targets/setup_tls/files/ca_key.pem.license3
-rw-r--r--ansible_collections/community/general/tests/integration/targets/setup_tls/files/client_certificate.pem4
-rw-r--r--ansible_collections/community/general/tests/integration/targets/setup_tls/files/client_certificate.pem.license3
-rw-r--r--ansible_collections/community/general/tests/integration/targets/setup_tls/files/client_key.pem4
-rw-r--r--ansible_collections/community/general/tests/integration/targets/setup_tls/files/client_key.pem.license3
-rw-r--r--ansible_collections/community/general/tests/integration/targets/setup_tls/files/server_certificate.pem4
-rw-r--r--ansible_collections/community/general/tests/integration/targets/setup_tls/files/server_certificate.pem.license3
-rw-r--r--ansible_collections/community/general/tests/integration/targets/setup_tls/files/server_key.pem4
-rw-r--r--ansible_collections/community/general/tests/integration/targets/setup_tls/files/server_key.pem.license3
-rw-r--r--ansible_collections/community/general/tests/integration/targets/shutdown/aliases1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/shutdown/tasks/main.yml73
-rw-r--r--ansible_collections/community/general/tests/integration/targets/snap/meta/main.yml1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/snap/tasks/main.yml244
-rw-r--r--ansible_collections/community/general/tests/integration/targets/snap/tasks/test.yml235
-rw-r--r--ansible_collections/community/general/tests/integration/targets/snap/tasks/test_3dash.yml31
-rw-r--r--ansible_collections/community/general/tests/integration/targets/snap/tasks/test_channel.yml81
-rw-r--r--ansible_collections/community/general/tests/integration/targets/snap/tasks/test_dangerous.yml53
-rw-r--r--ansible_collections/community/general/tests/integration/targets/snap/tasks/test_empty_list.yml14
-rw-r--r--ansible_collections/community/general/tests/integration/targets/ssh_config/aliases1
-rw-r--r--ansible_collections/community/general/tests/integration/targets/ssh_config/tasks/options.yml94
-rw-r--r--ansible_collections/community/general/tests/integration/targets/sudoers/tasks/main.yml15
-rw-r--r--ansible_collections/community/general/tests/integration/targets/sysrc/tasks/main.yml4
-rw-r--r--ansible_collections/community/general/tests/integration/targets/terraform/tasks/main.yml2
-rw-r--r--ansible_collections/community/general/tests/integration/targets/test_fqdn_valid/aliases5
-rwxr-xr-xansible_collections/community/general/tests/integration/targets/test_fqdn_valid/runme.sh (renamed from ansible_collections/community/dns/tests/integration/targets/wait_for_txt/runme.sh)3
-rw-r--r--ansible_collections/community/general/tests/integration/targets/test_fqdn_valid/runme.yml (renamed from ansible_collections/community/dns/tests/integration/targets/wait_for_txt/runme.yml)2
-rw-r--r--ansible_collections/community/general/tests/integration/targets/test_fqdn_valid/tasks/fqdn_valid_1.yml58
-rw-r--r--ansible_collections/community/general/tests/integration/targets/test_fqdn_valid/tasks/main.yml7
-rw-r--r--ansible_collections/community/general/tests/integration/targets/test_fqdn_valid/vars/main.yml15
-rw-r--r--ansible_collections/community/general/tests/integration/targets/timezone/tasks/main.yml3
-rw-r--r--ansible_collections/community/general/tests/integration/targets/ufw/aliases2
-rw-r--r--ansible_collections/community/general/tests/integration/targets/xml/tasks/main.yml9
-rwxr-xr-xansible_collections/community/general/tests/sanity/extra/botmeta.py6
-rwxr-xr-xansible_collections/community/general/tests/sanity/extra/extra-docs.py2
-rw-r--r--ansible_collections/community/general/tests/sanity/ignore-2.11.txt28
-rw-r--r--ansible_collections/community/general/tests/sanity/ignore-2.12.txt21
-rw-r--r--ansible_collections/community/general/tests/sanity/ignore-2.13.txt20
-rw-r--r--ansible_collections/community/general/tests/sanity/ignore-2.14.txt20
-rw-r--r--ansible_collections/community/general/tests/sanity/ignore-2.15.txt17
-rw-r--r--ansible_collections/community/general/tests/sanity/ignore-2.16.txt14
-rw-r--r--ansible_collections/community/general/tests/sanity/ignore-2.17.txt17
-rw-r--r--ansible_collections/community/general/tests/sanity/ignore-2.17.txt.license3
-rw-r--r--ansible_collections/community/general/tests/unit/mock/loader.py2
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/become/helper.py2
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/callback/test_loganalytics.py7
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/connection/test_lxc.py134
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/inventory/test_icinga2.py3
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/inventory/test_linode.py18
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/inventory/test_proxmox.py45
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/lookup/conftest.py (renamed from ansible_collections/community/general/tests/unit/plugins/lookup/onepassword_conftest.py)8
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/lookup/onepassword_common.py210
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/lookup/onepassword_fixtures/v2_out_01.json4
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/lookup/onepassword_fixtures/v2_out_04.json67
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/lookup/onepassword_fixtures/v2_out_04.json.license3
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/lookup/onepassword_fixtures/v2_out_05.json102
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/lookup/onepassword_fixtures/v2_out_05.json.license3
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/lookup/test_bitwarden.py47
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/lookup/test_bitwarden_secrets_manager.py83
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/lookup/test_github_app_access_token.py52
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/lookup/test_merge_variables.py161
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/lookup/test_onepassword.py67
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/module_utils/hwc/test_hwc_utils.py25
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/module_utils/test_cmd_runner.py102
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/module_utils/test_module_helper.py80
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/module_utils/test_vardict.py134
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/gitlab.py60
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/helper.py181
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_cpanm.py277
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_cpanm.yaml220
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_dnf_config_manager.py402
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_dnsimple.py4
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_dnsimple_info.py2
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_facter_facts.py14
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_facter_facts.yaml40
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_gconftool2.py106
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_gconftool2.yaml117
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_gconftool2_info.py93
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_gconftool2_info.yaml28
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_gem.py2
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_gio_mime.py (renamed from ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/authentication/conftest.py)10
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_gio_mime.yaml70
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_gitlab_group_access_token.py107
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_gitlab_project_access_token.py107
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_hana_query.py103
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_ini_file.py51
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_ipa_otptoken.py22
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_ipa_pwpolicy.py123
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_ipbase.py187
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_jenkins_build.py40
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_jenkins_build_info.py180
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_keycloak_authentication_required_actions.py835
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_keycloak_client_rolemapping.py7
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_keycloak_role.py370
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_keycloak_user.py354
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_keycloak_user_federation.py4
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_lvg_rename.py160
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_modprobe.py4
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_nmcli.py588
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_nomad_token.py222
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_npm.py38
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_opkg.py231
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_opkg.yaml142
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_pagerduty.py30
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_pagerduty_alert.py113
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_pkgin.py16
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_proxmox_kvm.py164
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_proxmox_snap.py8
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_proxmox_storage_contents_info.py90
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_proxmox_tasks_info.py10
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_proxmox_template.py66
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_proxmox_vm_info.py714
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_puppet.py211
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_puppet.yaml192
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_redhat_subscription.py4
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_redis_info.py36
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_rhsm_release.py14
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_rhsm_repository.py833
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_sap_task_list_execute.py91
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_sapcar_extract.py54
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_simpleinit_msb.py200
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_slack.py6
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_snap.py474
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_usb_facts.py105
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_xfconf.py296
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_xfconf.yaml185
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_xfconf_info.py163
-rw-r--r--ansible_collections/community/general/tests/unit/plugins/modules/test_xfconf_info.yaml83
-rw-r--r--ansible_collections/community/general/tests/unit/requirements.txt14
-rw-r--r--ansible_collections/community/general/tests/utils/constraints.txt2
-rwxr-xr-xansible_collections/community/general/tests/utils/shippable/shippable.sh11
-rw-r--r--ansible_collections/community/google/.github/workflows/ansible-test.yml110
-rw-r--r--ansible_collections/community/google/CHANGELOG.rst23
-rw-r--r--ansible_collections/community/google/FILES.json418
-rw-r--r--ansible_collections/community/google/MANIFEST.json32
-rw-r--r--ansible_collections/community/google/README.md38
-rw-r--r--ansible_collections/community/google/changelogs/changelog.yaml17
-rw-r--r--ansible_collections/community/google/changelogs/config.yaml29
-rw-r--r--ansible_collections/community/google/changelogs/fragments/.keep0
-rw-r--r--ansible_collections/community/google/meta/runtime.yml9
-rw-r--r--ansible_collections/community/google/plugins/doc_fragments/_gcp.py62
-rw-r--r--ansible_collections/community/google/plugins/lookup/gcp_storage_file.py156
-rw-r--r--ansible_collections/community/google/plugins/module_utils/gce.py39
-rw-r--r--ansible_collections/community/google/plugins/module_utils/gcp.py799
-rw-r--r--ansible_collections/community/google/plugins/modules/gc_storage.py497
-rw-r--r--ansible_collections/community/google/plugins/modules/gce_eip.py247
-rw-r--r--ansible_collections/community/google/plugins/modules/gce_img.py211
-rw-r--r--ansible_collections/community/google/plugins/modules/gce_instance_template.py605
-rw-r--r--ansible_collections/community/google/plugins/modules/gce_labels.py350
-rw-r--r--ansible_collections/community/google/plugins/modules/gce_lb.py310
-rw-r--r--ansible_collections/community/google/plugins/modules/gce_mig.py904
-rw-r--r--ansible_collections/community/google/plugins/modules/gce_net.py511
-rw-r--r--ansible_collections/community/google/plugins/modules/gce_pd.py293
-rw-r--r--ansible_collections/community/google/plugins/modules/gce_snapshot.py225
-rw-r--r--ansible_collections/community/google/plugins/modules/gce_tag.py218
-rw-r--r--ansible_collections/community/google/plugins/modules/gcpubsub.py349
-rw-r--r--ansible_collections/community/google/plugins/modules/gcpubsub_info.py164
-rw-r--r--ansible_collections/community/google/scripts/inventory/gce.ini76
-rw-r--r--ansible_collections/community/google/scripts/inventory/gce.py524
-rw-r--r--ansible_collections/community/google/tests/sanity/ignore-2.10.txt22
-rw-r--r--ansible_collections/community/google/tests/sanity/ignore-2.11.txt22
-rw-r--r--ansible_collections/community/google/tests/sanity/ignore-2.9.txt11
-rw-r--r--ansible_collections/community/google/tests/unit/compat/mock.py122
-rw-r--r--ansible_collections/community/google/tests/unit/compat/unittest.py38
-rw-r--r--ansible_collections/community/google/tests/unit/plugins/module_utils/__init__.py0
-rw-r--r--ansible_collections/community/google/tests/unit/plugins/module_utils/test_auth.py162
-rw-r--r--ansible_collections/community/google/tests/unit/plugins/module_utils/test_utils.py361
-rw-r--r--ansible_collections/community/google/tests/unit/plugins/modules/__init__.py0
-rw-r--r--ansible_collections/community/google/tests/unit/plugins/modules/test_gce_tag.py66
-rw-r--r--ansible_collections/community/google/tests/unit/requirements.txt1
-rw-r--r--ansible_collections/community/grafana/.all-contributorsrc23
-rw-r--r--ansible_collections/community/grafana/.config/ansible-lint.yml5
-rw-r--r--ansible_collections/community/grafana/.config/yamllint/config2
-rw-r--r--ansible_collections/community/grafana/.github/CODEOWNERS6
-rw-r--r--ansible_collections/community/grafana/.github/workflows/ansible-test.yml48
-rw-r--r--ansible_collections/community/grafana/.github/workflows/lint.yml36
-rw-r--r--ansible_collections/community/grafana/.gitignore1
-rw-r--r--ansible_collections/community/grafana/CHANGELOG.rst65
-rw-r--r--ansible_collections/community/grafana/FILES.json678
-rw-r--r--ansible_collections/community/grafana/MANIFEST.json4
-rw-r--r--ansible_collections/community/grafana/README.md57
-rw-r--r--ansible_collections/community/grafana/changelogs/changelog.yaml72
-rw-r--r--ansible_collections/community/grafana/changelogs/fragments/238_checkmode.yml2
-rw-r--r--ansible_collections/community/grafana/changelogs/fragments/242_add_grafana_organization_user_module.yml2
-rw-r--r--ansible_collections/community/grafana/changelogs/fragments/285_fix_doc.yml6
-rw-r--r--ansible_collections/community/grafana/changelogs/fragments/294-bump-grafana-version.yml5
-rw-r--r--ansible_collections/community/grafana/changelogs/fragments/300_datasource_prometheus_time_interval.yml2
-rw-r--r--ansible_collections/community/grafana/changelogs/fragments/308_datasource_quickwit.yml2
-rw-r--r--ansible_collections/community/grafana/changelogs/fragments/311_dashboard_check_mode.yml5
-rw-r--r--ansible_collections/community/grafana/changelogs/fragments/318-org_users_by_org_name.yml7
-rw-r--r--ansible_collections/community/grafana/changelogs/fragments/321-action-groups-org-users.yml4
-rw-r--r--ansible_collections/community/grafana/changelogs/fragments/324_formatting.yml2
-rw-r--r--ansible_collections/community/grafana/changelogs/fragments/325_linting.yml2
-rw-r--r--ansible_collections/community/grafana/changelogs/fragments/325_true_false.yml2
-rw-r--r--ansible_collections/community/grafana/changelogs/fragments/331-dashboard-by-org-name.yml8
-rw-r--r--ansible_collections/community/grafana/changelogs/fragments/332-datasource-by-org-name.yml4
-rw-r--r--ansible_collections/community/grafana/changelogs/fragments/335-add-datasource-type-tempo.yml2
-rw-r--r--ansible_collections/community/grafana/changelogs/fragments/339-lint-black.yml3
-rw-r--r--ansible_collections/community/grafana/changelogs/fragments/341-lint-ruff.yml3
-rw-r--r--ansible_collections/community/grafana/changelogs/fragments/342-ruff-findings.yml2
-rw-r--r--ansible_collections/community/grafana/changelogs/fragments/343-telekom-mms-role.yml2
-rw-r--r--ansible_collections/community/grafana/changelogs/fragments/345-datasource-compare-diff-orgid.yml3
-rw-r--r--ansible_collections/community/grafana/changelogs/fragments/347-folder-for-orgs.yml7
-rw-r--r--ansible_collections/community/grafana/changelogs/fragments/349-role-notification-channel.yml4
-rw-r--r--ansible_collections/community/grafana/changelogs/fragments/350-python3.12.yml3
-rw-r--r--ansible_collections/community/grafana/changelogs/fragments/fix-316.yml2
-rw-r--r--ansible_collections/community/grafana/codecov.yml2
-rw-r--r--ansible_collections/community/grafana/hacking/find_grafana_versions.py7
-rw-r--r--ansible_collections/community/grafana/hacking/requirements.txt2
-rw-r--r--ansible_collections/community/grafana/meta/runtime.yml19
-rw-r--r--ansible_collections/community/grafana/molecule/default/converge.yml48
-rw-r--r--ansible_collections/community/grafana/molecule/default/molecule.yml21
-rw-r--r--ansible_collections/community/grafana/molecule/default/test_dashboard.json126
-rw-r--r--ansible_collections/community/grafana/plugins/callback/grafana_annotations.py123
-rw-r--r--ansible_collections/community/grafana/plugins/doc_fragments/api_key.py7
-rw-r--r--ansible_collections/community/grafana/plugins/doc_fragments/basic_auth.py17
-rw-r--r--ansible_collections/community/grafana/plugins/lookup/grafana_dashboard.py106
-rw-r--r--ansible_collections/community/grafana/plugins/module_utils/base.py24
-rw-r--r--ansible_collections/community/grafana/plugins/modules/grafana_dashboard.py585
-rw-r--r--ansible_collections/community/grafana/plugins/modules/grafana_datasource.py596
-rw-r--r--ansible_collections/community/grafana/plugins/modules/grafana_folder.py141
-rw-r--r--ansible_collections/community/grafana/plugins/modules/grafana_notification_channel.py660
-rw-r--r--ansible_collections/community/grafana/plugins/modules/grafana_organization.py70
-rw-r--r--ansible_collections/community/grafana/plugins/modules/grafana_organization_user.py294
-rw-r--r--ansible_collections/community/grafana/plugins/modules/grafana_plugin.py203
-rw-r--r--ansible_collections/community/grafana/plugins/modules/grafana_team.py93
-rw-r--r--ansible_collections/community/grafana/plugins/modules/grafana_user.py89
-rw-r--r--ansible_collections/community/grafana/roles/grafana/README.md190
-rw-r--r--ansible_collections/community/grafana/roles/grafana/defaults/main.yml9
-rw-r--r--ansible_collections/community/grafana/roles/grafana/meta/main.yml14
-rw-r--r--ansible_collections/community/grafana/roles/grafana/tasks/main.yml203
-rw-r--r--ansible_collections/community/grafana/ruff.toml1
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/defaults/main.yml9
-rwxr-xr-xansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/runme.sh5
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/site.yml6
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/dashboard-by-org-name.yml84
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/dashboard-export.yml100
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/dashboard-folder-destination.yml65
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/dashboard-from-file-export.yml90
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/dashboard-from-file.yml44
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/dashboard-from-id.yml80
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/dashboard-from-url.yml79
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/delete-dashboard.yml62
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/main.yml27
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/defaults/main.yml8
-rwxr-xr-xansible_collections/community/grafana/tests/integration/targets/grafana_datasource/runme.sh5
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/site.yml6
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/azure.yml117
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/cloudwatch.yml111
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/elastic.yml378
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/errors.yml12
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/influx.yml71
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/issues.yml59
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/loki.yml73
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/main.yml36
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/postgres.yml65
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/quickwit.yml137
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/redis.yml85
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/tempo.yml79
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/thruk.yml69
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/uid.yml255
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/zabbix.yml107
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_folder/defaults/main.yml8
-rwxr-xr-xansible_collections/community/grafana/tests/integration/targets/grafana_folder/runme.sh6
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_folder/site.yml6
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_folder/tasks/create-delete.yml58
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_folder/tasks/main.yml57
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_folder/tasks/org.yml7
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/defaults/main.yml8
-rwxr-xr-xansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/runme.sh5
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/site.yml6
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/dingding.yml32
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/discord.yml32
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/email.yml42
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/googlechat.yml40
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/hipchat.yml40
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/kafka.yml40
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/line.yml40
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/main.yml50
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/opsgenie.yml42
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/pagerduty.yml40
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/prometheus.yml40
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/pushover.yml40
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/sensu.yml40
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/slack-and-beyond.yml60
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/teams.yml40
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/telegram.yml40
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/threema.yml40
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/victorops.yml40
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/webhook.yml40
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_organization/defaults/main.yml6
-rwxr-xr-xansible_collections/community/grafana/tests/integration/targets/grafana_organization/runme.sh6
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_organization/site.yml6
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_organization/tasks/main.yml45
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_organization_user/defaults/main.yml4
-rwxr-xr-xansible_collections/community/grafana/tests/integration/targets/grafana_organization_user/runme.sh6
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_organization_user/site.yml6
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_organization_user/tasks/main.yml172
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_team/defaults/main.yml8
-rwxr-xr-xansible_collections/community/grafana/tests/integration/targets/grafana_team/runme.sh5
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_team/site.yml6
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_team/tasks/create_user.yml25
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_team/tasks/main.yml273
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_user/defaults/main.yml6
-rwxr-xr-xansible_collections/community/grafana/tests/integration/targets/grafana_user/runme.sh6
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_user/site.yml6
-rw-r--r--ansible_collections/community/grafana/tests/integration/targets/grafana_user/tasks/main.yml186
-rw-r--r--ansible_collections/community/grafana/tests/requirements.yml3
-rw-r--r--ansible_collections/community/grafana/tests/sanity/ignore-2.16.txt4
-rw-r--r--ansible_collections/community/grafana/tests/sanity/ignore-2.17.txt4
-rw-r--r--ansible_collections/community/grafana/tests/unit/modules/grafana/grafana_datasource/test_grafana_datasource.py283
-rw-r--r--ansible_collections/community/grafana/tests/unit/modules/grafana/grafana_plugin/test_grafana_plugin.py35
-rw-r--r--ansible_collections/community/grafana/tests/unit/modules/grafana/grafana_team/test_grafana_team.py572
-rw-r--r--ansible_collections/community/grafana/tests/unit/modules/grafana/grafana_user/test_grafana_user.py239
-rw-r--r--ansible_collections/community/hashi_vault/.github/actions/docker-image-versions/action.yml3
-rwxr-xr-xansible_collections/community/hashi_vault/.github/actions/docker-image-versions/versions.py13
-rw-r--r--ansible_collections/community/hashi_vault/.github/dependabot.yml9
-rw-r--r--ansible_collections/community/hashi_vault/.github/workflows/ansible-builder.yml7
-rw-r--r--ansible_collections/community/hashi_vault/.github/workflows/ansible-test.yml181
-rw-r--r--ansible_collections/community/hashi_vault/.github/workflows/github-release.yml12
-rw-r--r--ansible_collections/community/hashi_vault/CHANGELOG.md828
-rw-r--r--ansible_collections/community/hashi_vault/CHANGELOG.rst97
-rw-r--r--ansible_collections/community/hashi_vault/FILES.json1399
-rw-r--r--ansible_collections/community/hashi_vault/MANIFEST.json4
-rw-r--r--ansible_collections/community/hashi_vault/README.md14
-rw-r--r--ansible_collections/community/hashi_vault/changelogs/changelog.yaml121
-rw-r--r--ansible_collections/community/hashi_vault/changelogs/config.yaml1
-rw-r--r--ansible_collections/community/hashi_vault/docs/docsite/rst/CHANGELOG.rst97
-rw-r--r--ansible_collections/community/hashi_vault/docs/docsite/rst/user_guide.rst11
-rw-r--r--ansible_collections/community/hashi_vault/meta/ee-requirements.txt2
-rw-r--r--ansible_collections/community/hashi_vault/meta/runtime.yml16
-rw-r--r--ansible_collections/community/hashi_vault/plugins/doc_fragments/auth.py6
-rw-r--r--ansible_collections/community/hashi_vault/plugins/lookup/hashi_vault.py5
-rw-r--r--ansible_collections/community/hashi_vault/plugins/lookup/vault_token_create.py2
-rw-r--r--ansible_collections/community/hashi_vault/plugins/lookup/vault_write.py19
-rw-r--r--ansible_collections/community/hashi_vault/plugins/module_utils/_auth_method_token.py2
-rw-r--r--ansible_collections/community/hashi_vault/plugins/module_utils/_connection_options.py8
-rw-r--r--ansible_collections/community/hashi_vault/plugins/module_utils/_hashi_vault_common.py50
-rw-r--r--ansible_collections/community/hashi_vault/plugins/modules/vault_database_connection_configure.py193
-rw-r--r--ansible_collections/community/hashi_vault/plugins/modules/vault_database_connection_delete.py146
-rw-r--r--ansible_collections/community/hashi_vault/plugins/modules/vault_database_connection_read.py162
-rw-r--r--ansible_collections/community/hashi_vault/plugins/modules/vault_database_connection_reset.py145
-rw-r--r--ansible_collections/community/hashi_vault/plugins/modules/vault_database_connections_list.py176
-rw-r--r--ansible_collections/community/hashi_vault/plugins/modules/vault_database_role_create.py207
-rw-r--r--ansible_collections/community/hashi_vault/plugins/modules/vault_database_role_delete.py146
-rw-r--r--ansible_collections/community/hashi_vault/plugins/modules/vault_database_role_read.py175
-rw-r--r--ansible_collections/community/hashi_vault/plugins/modules/vault_database_roles_list.py173
-rw-r--r--ansible_collections/community/hashi_vault/plugins/modules/vault_database_rotate_root_credentials.py150
-rw-r--r--ansible_collections/community/hashi_vault/plugins/modules/vault_database_static_role_create.py188
-rw-r--r--ansible_collections/community/hashi_vault/plugins/modules/vault_database_static_role_get_credentials.py167
-rw-r--r--ansible_collections/community/hashi_vault/plugins/modules/vault_database_static_role_read.py171
-rw-r--r--ansible_collections/community/hashi_vault/plugins/modules/vault_database_static_role_rotate_credentials.py152
-rw-r--r--ansible_collections/community/hashi_vault/plugins/modules/vault_database_static_roles_list.py174
-rw-r--r--ansible_collections/community/hashi_vault/plugins/modules/vault_write.py19
-rw-r--r--ansible_collections/community/hashi_vault/plugins/plugin_utils/_hashi_vault_lookup_base.py7
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/constraints.txt (renamed from ansible_collections/community/hashi_vault/tests/utils/constraints.txt)10
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/requirements.txt20
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/auth_approle/tasks/approle_test_controller.yml2
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/auth_approle/tasks/approle_test_target.yml4
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/auth_approle/tasks/main.yml2
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/auth_aws_iam/tasks/aws_iam_test_target.yml2
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/auth_aws_iam/tasks/main.yml2
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/auth_azure/tasks/azure_test_target.yml4
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/auth_azure/tasks/main.yml2
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/auth_cert/tasks/cert_test_target.yml2
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/auth_cert/tasks/main.yml2
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/auth_jwt/tasks/jwt_test_target.yml2
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/auth_jwt/tasks/main.yml2
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/auth_ldap/tasks/ldap_test_target.yml2
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/auth_ldap/tasks/main.yml2
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/auth_token/tasks/main.yml4
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/auth_token/tasks/token_test_controller.yml2
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/auth_token/tasks/token_test_target.yml2
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/auth_userpass/tasks/main.yml2
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/auth_userpass/tasks/userpass_test_target.yml2
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/connection_options/tasks/controller.yml16
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/connection_options/tasks/target.yml14
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/lookup_hashi_vault/tasks/lookup_test.yml33
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/lookup_vault_write/tasks/lookup_vault_write_test.yml3
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_configure/aliases1
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_configure/meta/main.yml4
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_configure/tasks/main.yml3
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_configure/tasks/module_vault_database_connection_configure_setup.yml9
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_configure/tasks/module_vault_database_connection_configure_test.yml192
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_delete/aliases1
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_delete/meta/main.yml4
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_delete/tasks/main.yml3
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_delete/tasks/module_vault_database_connection_delete_setup.yml36
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_delete/tasks/module_vault_database_connection_delete_test.yml84
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_read/aliases1
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_read/meta/main.yml4
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_read/tasks/main.yml3
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_read/tasks/module_vault_database_connection_read_setup.yml9
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_read/tasks/module_vault_database_connection_read_test.yml134
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_reset/aliases1
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_reset/meta/main.yml4
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_reset/tasks/main.yml3
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_reset/tasks/module_vault_database_connection_reset_setup.yml9
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_reset/tasks/module_vault_database_connection_reset_test.yml84
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connections_list/aliases1
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connections_list/meta/main.yml4
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connections_list/tasks/main.yml3
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connections_list/tasks/module_vault_database_connection_list_setup.yml9
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connections_list/tasks/module_vault_database_connection_list_test.yml72
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_create/aliases1
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_create/meta/main.yml4
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_create/tasks/main.yml3
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_create/tasks/module_vault_database_role_create_setup.yml13
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_create/tasks/module_vault_database_role_create_test.yml92
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_delete/aliases1
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_delete/meta/main.yml4
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_delete/tasks/main.yml3
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_delete/tasks/module_vault_database_role_delete_setup.yml34
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_delete/tasks/module_vault_database_role_delete_test.yml75
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_read/aliases1
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_read/meta/main.yml4
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_read/tasks/main.yml3
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_read/tasks/module_vault_database_role_read_setup.yml9
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_read/tasks/module_vault_database_role_read_test.yml126
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_roles_list/aliases1
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_roles_list/meta/main.yml4
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_roles_list/tasks/main.yml3
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_roles_list/tasks/module_vault_database_roles_list_setup.yml9
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_roles_list/tasks/module_vault_database_roles_list_test.yml65
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/aliases1
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/meta/main.yml4
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/tasks/main.yml10
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/tasks/module_vault_db_rotate_root_creds_cleanup.yml12
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/tasks/module_vault_db_rotate_root_creds_setup.yml46
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/tasks/module_vault_db_rotate_root_creds_test.yml132
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_create/aliases1
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_create/meta/main.yml4
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_create/tasks/main.yml3
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_create/tasks/module_vault_database_static_role_create_setup.yml13
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_create/tasks/module_vault_database_static_role_create_test.yml130
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_get_creds/aliases1
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_get_creds/meta/main.yml4
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_get_creds/tasks/main.yml3
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_get_creds/tasks/module_vault_database_static_role_get_credentials_setup.yml13
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_get_creds/tasks/module_vault_database_static_role_get_credentials_test.yml114
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_read/aliases1
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_read/meta/main.yml4
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_read/tasks/main.yml3
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_read/tasks/module_vault_database_static_role_read_setup.yml9
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_read/tasks/module_vault_database_static_role_read_test.yml123
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_rotate_creds/aliases1
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_rotate_creds/meta/main.yml4
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_rotate_creds/tasks/main.yml8
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_rotate_creds/tasks/module_vault_db_static_role_rotate_creds_setup.yml23
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_rotate_creds/tasks/module_vault_db_static_role_rotate_creds_test.yml120
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_roles_list/aliases1
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_roles_list/meta/main.yml4
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_roles_list/tasks/main.yml3
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_roles_list/tasks/module_vault_database_static_roles_list_setup.yml9
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_roles_list/tasks/module_vault_database_static_roles_list_test.yml91
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_login/tasks/module_vault_login_test.yml2
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_write/tasks/module_vault_write_test.yml14
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/defaults/main.yml12
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/files/playbooks/vault_docker.yml2
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/files/requirements/constraints.txt5
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/files/requirements/requirements.txt1
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/files/sql/init.sql16
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/tasks/main.yml31
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/templates/docker-compose.yml.j217
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/vars/main.yml5
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_gha/files/playbooks/gha.yml2
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/README.md2
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/aliases2
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/meta/main.yml3
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/tasks/configure.yml48
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/tasks/main.yml17
-rw-r--r--ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/vars/main.yml27
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/conftest.py10
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/constraints.txt64
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/fixtures/database_connection_read_response.json20
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/fixtures/database_connections_list_response.json21
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/fixtures/database_role_read_response.json22
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/fixtures/database_roles_list_response.json21
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/fixtures/database_static_role_get_credentials_response.json25
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/fixtures/database_static_role_read_response.json18
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/fixtures/database_static_roles_list_response.json21
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/plugins/lookup/test_vault_token_create.py13
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/plugins/lookup/test_vault_write.py47
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/authentication/test_auth_aws_iam.py2
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/authentication/test_auth_azure.py12
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/authentication/test_auth_token.py6
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/authentication/test_hashi_vault_auth_method_base.py14
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/option_adapter/test_hashi_vault_option_adapter.py74
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/test_hashi_vault_connection_options.py4
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/test_hashi_vault_helper.py10
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_connection_configure.py195
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_connection_delete.py181
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_connection_read.py200
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_connection_reset.py181
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_connections_list.py228
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_role_create.py197
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_role_delete.py180
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_role_read.py200
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_roles_list.py228
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_rotate_root_credentials.py197
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_static_role_create.py192
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_static_role_get_credentials.py202
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_static_role_read.py200
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_static_role_rotate_credentials.py199
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_static_roles_list.py228
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_pki_generate_certificate.py2
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_write.py58
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/authentication/test_auth_token.py54
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/base/test_hashi_vault_lookup_base.py16
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/option_adapter/conftest.py29
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/option_adapter/test_hashi_vault_option_adapter.py2
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/test_hashi_vault_common_stringify.py48
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/test_hashi_vault_helper.py58
-rw-r--r--ansible_collections/community/hashi_vault/tests/unit/requirements.txt18
-rw-r--r--ansible_collections/community/hrobot/.github/workflows/ansible-test.yml4
-rw-r--r--ansible_collections/community/hrobot/.github/workflows/ee.yml100
-rw-r--r--ansible_collections/community/hrobot/.github/workflows/extra-tests.yml6
-rw-r--r--ansible_collections/community/hrobot/.github/workflows/import-galaxy.yml78
-rw-r--r--ansible_collections/community/hrobot/.github/workflows/reuse.yml11
-rw-r--r--ansible_collections/community/hrobot/CHANGELOG.md358
-rw-r--r--ansible_collections/community/hrobot/CHANGELOG.md.license3
-rw-r--r--ansible_collections/community/hrobot/CHANGELOG.rst66
-rw-r--r--ansible_collections/community/hrobot/FILES.json100
-rw-r--r--ansible_collections/community/hrobot/MANIFEST.json4
-rw-r--r--ansible_collections/community/hrobot/README.md6
-rw-r--r--ansible_collections/community/hrobot/changelogs/changelog.yaml70
-rw-r--r--ansible_collections/community/hrobot/changelogs/config.yaml3
-rw-r--r--ansible_collections/community/hrobot/plugins/inventory/robot.py27
-rw-r--r--ansible_collections/community/hrobot/plugins/module_utils/robot.py37
-rw-r--r--ansible_collections/community/hrobot/plugins/modules/boot.py44
-rw-r--r--ansible_collections/community/hrobot/plugins/modules/failover_ip.py8
-rw-r--r--ansible_collections/community/hrobot/plugins/modules/failover_ip_info.py4
-rw-r--r--ansible_collections/community/hrobot/plugins/modules/firewall.py46
-rw-r--r--ansible_collections/community/hrobot/plugins/modules/firewall_info.py20
-rw-r--r--ansible_collections/community/hrobot/plugins/modules/reset.py8
-rw-r--r--ansible_collections/community/hrobot/plugins/modules/reverse_dns.py6
-rw-r--r--ansible_collections/community/hrobot/plugins/modules/server.py2
-rw-r--r--ansible_collections/community/hrobot/plugins/modules/server_info.py24
-rw-r--r--ansible_collections/community/hrobot/plugins/modules/ssh_key.py16
-rw-r--r--ansible_collections/community/hrobot/plugins/modules/v_switch.py6
-rw-r--r--ansible_collections/community/hrobot/tests/sanity/extra/extra-docs.json5
-rwxr-xr-xansible_collections/community/hrobot/tests/sanity/extra/extra-docs.py11
-rw-r--r--ansible_collections/community/hrobot/tests/sanity/ignore-2.16.txt1
-rw-r--r--ansible_collections/community/hrobot/tests/sanity/ignore-2.16.txt.license3
-rw-r--r--ansible_collections/community/hrobot/tests/sanity/ignore-2.17.txt1
-rw-r--r--ansible_collections/community/hrobot/tests/sanity/ignore-2.17.txt.license3
-rw-r--r--ansible_collections/community/hrobot/tests/unit/plugins/inventory/test_robot.py62
-rw-r--r--ansible_collections/community/hrobot/tests/unit/plugins/module_utils/test_failover.py45
-rw-r--r--ansible_collections/community/hrobot/tests/unit/plugins/module_utils/test_robot.py80
-rw-r--r--ansible_collections/community/hrobot/tests/unit/requirements.yml (renamed from ansible_collections/community/hrobot/tests/requirements.yml)2
-rw-r--r--ansible_collections/community/library_inventory_filtering_v1/.github/dependabot.yml11
-rw-r--r--ansible_collections/community/library_inventory_filtering_v1/.github/workflows/ansible-test.yml87
-rw-r--r--ansible_collections/community/library_inventory_filtering_v1/.github/workflows/extra-tests.yml47
-rw-r--r--ansible_collections/community/library_inventory_filtering_v1/.github/workflows/import-galaxy.yml87
-rw-r--r--ansible_collections/community/library_inventory_filtering_v1/.github/workflows/reuse.yml32
-rw-r--r--ansible_collections/community/library_inventory_filtering_v1/.reuse/dep55
-rw-r--r--ansible_collections/community/library_inventory_filtering_v1/CHANGELOG.rst22
-rw-r--r--ansible_collections/community/library_inventory_filtering_v1/CHANGELOG.rst.license3
-rw-r--r--ansible_collections/community/library_inventory_filtering_v1/COPYING (renamed from ansible_collections/community/fortios/LICENSE)0
-rw-r--r--ansible_collections/community/library_inventory_filtering_v1/FILES.json355
-rw-r--r--ansible_collections/community/library_inventory_filtering_v1/LICENSES/GPL-3.0-or-later.txt (renamed from ansible_collections/community/google/LICENSE)0
-rw-r--r--ansible_collections/community/library_inventory_filtering_v1/MANIFEST.json33
-rw-r--r--ansible_collections/community/library_inventory_filtering_v1/README.md52
-rw-r--r--ansible_collections/community/library_inventory_filtering_v1/changelogs/changelog.yaml14
-rw-r--r--ansible_collections/community/library_inventory_filtering_v1/changelogs/changelog.yaml.license3
-rw-r--r--ansible_collections/community/library_inventory_filtering_v1/changelogs/config.yaml (renamed from ansible_collections/community/skydive/changelogs/config.yaml)8
-rw-r--r--ansible_collections/community/library_inventory_filtering_v1/changelogs/fragments/.keep (renamed from ansible_collections/community/fortios/changelogs/fragments/.keep)0
-rw-r--r--ansible_collections/community/library_inventory_filtering_v1/codecov.yml7
-rw-r--r--ansible_collections/community/library_inventory_filtering_v1/meta/runtime.yml6
-rw-r--r--ansible_collections/community/library_inventory_filtering_v1/plugins/doc_fragments/inventory_filter.py36
-rw-r--r--ansible_collections/community/library_inventory_filtering_v1/plugins/plugin_utils/inventory_filter.py91
-rw-r--r--ansible_collections/community/library_inventory_filtering_v1/tests/config.yml9
-rw-r--r--ansible_collections/community/library_inventory_filtering_v1/tests/sanity/extra/extra-docs.json13
-rw-r--r--ansible_collections/community/library_inventory_filtering_v1/tests/sanity/extra/extra-docs.json.license3
-rwxr-xr-xansible_collections/community/library_inventory_filtering_v1/tests/sanity/extra/extra-docs.py29
-rw-r--r--ansible_collections/community/library_inventory_filtering_v1/tests/sanity/extra/licenses.json4
-rw-r--r--ansible_collections/community/library_inventory_filtering_v1/tests/sanity/extra/licenses.json.license3
-rwxr-xr-xansible_collections/community/library_inventory_filtering_v1/tests/sanity/extra/licenses.py110
-rw-r--r--ansible_collections/community/library_inventory_filtering_v1/tests/sanity/extra/licenses.py.license3
-rw-r--r--ansible_collections/community/library_inventory_filtering_v1/tests/sanity/extra/no-unwanted-files.json7
-rw-r--r--ansible_collections/community/library_inventory_filtering_v1/tests/sanity/extra/no-unwanted-files.json.license3
-rwxr-xr-xansible_collections/community/library_inventory_filtering_v1/tests/sanity/extra/no-unwanted-files.py44
-rw-r--r--ansible_collections/community/library_inventory_filtering_v1/tests/unit/plugins/plugin_utils/test_inventory_filter.py114
-rw-r--r--ansible_collections/community/library_inventory_filtering_v1/tests/unit/requirements.txt6
-rw-r--r--ansible_collections/community/library_inventory_filtering_v1/tests/unit/requirements.yml7
-rw-r--r--ansible_collections/community/libvirt/.azure-pipelines/azure-pipelines.yml265
-rw-r--r--ansible_collections/community/libvirt/CHANGELOG.rst25
-rw-r--r--ansible_collections/community/libvirt/CONTRIBUTING.md4
-rw-r--r--ansible_collections/community/libvirt/FILES.json53
-rw-r--r--ansible_collections/community/libvirt/MANIFEST.json4
-rw-r--r--ansible_collections/community/libvirt/REVIEW_CHECKLIST.md3
-rw-r--r--ansible_collections/community/libvirt/changelogs/changelog.yaml32
-rw-r--r--ansible_collections/community/libvirt/plugins/connection/libvirt_qemu.py8
-rw-r--r--ansible_collections/community/libvirt/plugins/doc_fragments/virt.py21
-rw-r--r--ansible_collections/community/libvirt/plugins/inventory/libvirt.py2
-rw-r--r--ansible_collections/community/libvirt/plugins/modules/virt.py352
-rw-r--r--ansible_collections/community/libvirt/plugins/modules/virt_net.py4
-rw-r--r--ansible_collections/community/libvirt/plugins/modules/virt_pool.py21
-rw-r--r--ansible_collections/community/libvirt/tests/sanity/ignore-2.10.txt10
-rw-r--r--ansible_collections/community/libvirt/tests/sanity/ignore-2.11.txt10
-rw-r--r--ansible_collections/community/libvirt/tests/sanity/ignore-2.15.txt3
-rw-r--r--ansible_collections/community/libvirt/tests/sanity/ignore-2.16.txt2
-rw-r--r--ansible_collections/community/libvirt/tests/sanity/ignore-2.17.txt2
-rw-r--r--ansible_collections/community/libvirt/tests/sanity/ignore-2.9.txt10
-rw-r--r--ansible_collections/community/libvirt/tests/unit/mock/loader.py2
-rwxr-xr-xansible_collections/community/libvirt/tests/utils/shippable/check_matrix.py2
-rw-r--r--ansible_collections/community/mongodb/.github/workflows/ansible-test.yml81
-rw-r--r--ansible_collections/community/mongodb/.github/workflows/mongodb-cache.yml56
-rw-r--r--ansible_collections/community/mongodb/.github/workflows/publish_collection.yml10
-rw-r--r--ansible_collections/community/mongodb/.github/workflows/test-roles.yml8
-rw-r--r--ansible_collections/community/mongodb/.github/workflows/x509.yml12
-rw-r--r--ansible_collections/community/mongodb/CHANGELOG.rst110
-rw-r--r--ansible_collections/community/mongodb/FILES.json221
-rw-r--r--ansible_collections/community/mongodb/MANIFEST.json7
-rw-r--r--ansible_collections/community/mongodb/README.md33
-rw-r--r--ansible_collections/community/mongodb/changelogs/changelog.yaml70
-rw-r--r--ansible_collections/community/mongodb/plugins/cache/mongodb.py2
-rw-r--r--ansible_collections/community/mongodb/plugins/doc_fragments/atlas_options.py54
-rw-r--r--ansible_collections/community/mongodb/plugins/module_utils/mongodb_atlas.py220
-rw-r--r--ansible_collections/community/mongodb/plugins/module_utils/mongodb_common.py7
-rw-r--r--ansible_collections/community/mongodb/plugins/modules/mongodb_atlas_cluster.py238
-rw-r--r--ansible_collections/community/mongodb/plugins/modules/mongodb_atlas_ldap_user.py165
-rw-r--r--ansible_collections/community/mongodb/plugins/modules/mongodb_atlas_user.py196
-rw-r--r--ansible_collections/community/mongodb/plugins/modules/mongodb_atlas_whitelist.py111
-rw-r--r--ansible_collections/community/mongodb/plugins/modules/mongodb_balancer.py2
-rw-r--r--ansible_collections/community/mongodb/plugins/modules/mongodb_monitoring.py197
-rw-r--r--ansible_collections/community/mongodb/plugins/modules/mongodb_replicaset.py5
-rw-r--r--ansible_collections/community/mongodb/plugins/modules/mongodb_role.py4
-rw-r--r--ansible_collections/community/mongodb/plugins/modules/mongodb_user.py3
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_auth/defaults/main.yml2
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_auth/molecule/default/molecule.yml4
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_auth/molecule/default/playbook.yml15
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_auth/tasks/main.yml2
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_auth/tasks/mongodb_auth_user.yml2
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_config/README.md32
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_config/defaults/main.yml2
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_config/molecule/custom_db_path/molecule.yml6
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_config/molecule/custom_db_path/playbook.yml15
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_config/molecule/custom_db_path/tests/test_default.py2
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_config/molecule/default/molecule.yml6
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_config/molecule/default/playbook.yml15
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_config/molecule/default/tests/test_default.py2
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_config/templates/configsrv.conf.j26
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_install/files/lock_mongodb_packages.sh10
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_install/molecule/default/molecule.yml4
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_install/molecule/default/prepare.yml10
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_install/molecule/mongodb_hold_packages/molecule.yml4
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_install/molecule/mongodb_hold_packages/prepare.yml4
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_install/molecule/mongodb_hold_packages/tests/test_default.py2
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_install/molecule/mongodb_nohold_packages/molecule.yml4
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_install/molecule/mongodb_nohold_packages/prepare.yml6
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_install/molecule/mongodb_nohold_packages/tests/test_default.py2
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_install/molecule/specific_mongodb_version/molecule.yml12
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_install/molecule/specific_mongodb_version/prepare.yml10
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_install/tasks/main.yml26
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_linux/README.md5
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_linux/defaults/main.yml4
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_linux/files/thp-disable.service1
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_linux/molecule/default/molecule.yml4
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_linux/tasks/main.yml15
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_linux/vars/Debian-12.yml5
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_linux/vars/RedHat-9.yml5
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_mongod/README.md39
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_mongod/defaults/main.yml12
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_mongod/handlers/main.yml5
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/custom_db_path/molecule.yml4
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/custom_db_path/playbook.yml15
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/custom_db_path/tests/test_default.py2
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/default/molecule.yml4
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/default/playbook.yml15
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/default/tests/test_default.py2
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/multiple_bind_ip/molecule.yml4
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/multiple_bind_ip/playbook.yml15
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/multiple_bind_ip/tests/test_default.py2
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_mongod/tasks/logrotate.yml9
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_mongod/tasks/main.yml33
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_mongod/templates/mongod.conf.j29
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_mongod/templates/mongodb.logrotate.j214
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_mongos/README.md30
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_mongos/defaults/main.yml2
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_mongos/molecule/default/molecule.yml6
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_mongos/molecule/default/playbook.yml13
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_mongos/molecule/default/prepare.yml6
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_mongos/templates/mongos.conf.j26
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_repository/molecule/default/molecule.yml4
-rw-r--r--ansible_collections/community/mongodb/roles/mongodb_selinux/molecule/default/molecule.yml4
-rw-r--r--ansible_collections/community/mysql/.github/workflows/ansible-test-plugins.yml42
-rw-r--r--ansible_collections/community/mysql/.github/workflows/ansible-test-roles.yml19
-rw-r--r--ansible_collections/community/mysql/CHANGELOG.rst50
-rw-r--r--ansible_collections/community/mysql/CONTRIBUTING.md81
-rw-r--r--ansible_collections/community/mysql/CONTRIBUTORS2
-rw-r--r--ansible_collections/community/mysql/FILES.json141
-rw-r--r--ansible_collections/community/mysql/MAINTAINERS5
-rw-r--r--ansible_collections/community/mysql/MANIFEST.json4
-rw-r--r--ansible_collections/community/mysql/README.md36
-rw-r--r--ansible_collections/community/mysql/TESTING.md6
-rw-r--r--ansible_collections/community/mysql/changelogs/changelog.yaml60
-rw-r--r--ansible_collections/community/mysql/plugins/doc_fragments/mysql.py3
-rw-r--r--ansible_collections/community/mysql/plugins/module_utils/implementations/mariadb/user.py6
-rw-r--r--ansible_collections/community/mysql/plugins/module_utils/implementations/mysql/user.py6
-rw-r--r--ansible_collections/community/mysql/plugins/module_utils/mysql.py7
-rw-r--r--ansible_collections/community/mysql/plugins/module_utils/user.py370
-rw-r--r--ansible_collections/community/mysql/plugins/modules/mysql_db.py9
-rw-r--r--ansible_collections/community/mysql/plugins/modules/mysql_info.py172
-rw-r--r--ansible_collections/community/mysql/plugins/modules/mysql_query.py6
-rw-r--r--ansible_collections/community/mysql/plugins/modules/mysql_replication.py13
-rw-r--r--ansible_collections/community/mysql/plugins/modules/mysql_role.py35
-rw-r--r--ansible_collections/community/mysql/plugins/modules/mysql_user.py83
-rw-r--r--ansible_collections/community/mysql/plugins/modules/mysql_variables.py7
-rw-r--r--ansible_collections/community/mysql/tests/integration/targets/setup_controller/tasks/verify.yml14
-rw-r--r--ansible_collections/community/mysql/tests/integration/targets/test_mysql_db/tasks/state_dump_import.yml2
-rw-r--r--ansible_collections/community/mysql/tests/integration/targets/test_mysql_info/files/users_info_create_procedure.sql7
-rw-r--r--ansible_collections/community/mysql/tests/integration/targets/test_mysql_info/tasks/filter_users_info.yml280
-rw-r--r--ansible_collections/community/mysql/tests/integration/targets/test_mysql_info/tasks/main.yml4
-rw-r--r--ansible_collections/community/mysql/tests/integration/targets/test_mysql_replication/tasks/mysql_replication_channel.yml78
-rw-r--r--ansible_collections/community/mysql/tests/integration/targets/test_mysql_replication/tasks/mysql_replication_initial.yml30
-rw-r--r--ansible_collections/community/mysql/tests/integration/targets/test_mysql_role/tasks/main.yml4
-rw-r--r--ansible_collections/community/mysql/tests/integration/targets/test_mysql_role/tasks/test_column_case_sensitive.yml149
-rw-r--r--ansible_collections/community/mysql/tests/integration/targets/test_mysql_user/tasks/main.yml17
-rw-r--r--ansible_collections/community/mysql/tests/integration/targets/test_mysql_user/tasks/test_column_case_sensitive.yml134
-rw-r--r--ansible_collections/community/mysql/tests/integration/targets/test_mysql_user/tasks/test_password_expire.yml174
-rw-r--r--ansible_collections/community/mysql/tests/integration/targets/test_mysql_user/tasks/test_user_attributes.yml474
-rw-r--r--ansible_collections/community/mysql/tests/integration/targets/test_mysql_user/tasks/utils/assert_user_password_expire.yml56
-rw-r--r--ansible_collections/community/mysql/tests/sanity/ignore-2.12.txt8
-rw-r--r--ansible_collections/community/mysql/tests/sanity/ignore-2.13.txt8
-rw-r--r--ansible_collections/community/mysql/tests/sanity/ignore-2.14.txt6
-rw-r--r--ansible_collections/community/mysql/tests/sanity/ignore-2.15.txt6
-rw-r--r--ansible_collections/community/mysql/tests/sanity/ignore-2.16.txt6
-rw-r--r--ansible_collections/community/mysql/tests/sanity/ignore-2.17.txt4
-rw-r--r--ansible_collections/community/mysql/tests/unit/plugins/module_utils/test_mysql.py21
-rw-r--r--ansible_collections/community/mysql/tests/unit/plugins/module_utils/test_mysql_user.py21
-rw-r--r--ansible_collections/community/mysql/tests/unit/plugins/modules/test_mysql_info.py14
-rw-r--r--ansible_collections/community/network/.ansible-lint11
-rw-r--r--ansible_collections/community/network/.azure-pipelines/azure-pipelines.yml112
-rw-r--r--ansible_collections/community/network/CHANGELOG.rst30
-rw-r--r--ansible_collections/community/network/FILES.json437
-rw-r--r--ansible_collections/community/network/MANIFEST.json8
-rw-r--r--ansible_collections/community/network/README.md18
-rw-r--r--ansible_collections/community/network/changelogs/changelog.yaml36
-rw-r--r--ansible_collections/community/network/plugins/doc_fragments/a10.py4
-rw-r--r--ansible_collections/community/network/plugins/doc_fragments/enos.py2
-rw-r--r--ansible_collections/community/network/plugins/doc_fragments/ingate.py2
-rw-r--r--ansible_collections/community/network/plugins/doc_fragments/ironware.py4
-rw-r--r--ansible_collections/community/network/plugins/doc_fragments/netscaler.py10
-rw-r--r--ansible_collections/community/network/plugins/lookup/avi.py2
-rw-r--r--ansible_collections/community/network/plugins/module_utils/network/avi/ansible_utils.py12
-rw-r--r--ansible_collections/community/network/plugins/module_utils/network/avi/avi_api.py6
-rw-r--r--ansible_collections/community/network/plugins/module_utils/network/exos/facts/legacy/base.py2
-rw-r--r--ansible_collections/community/network/plugins/module_utils/network/ftd/common.py8
-rw-r--r--ansible_collections/community/network/plugins/modules/a10_server_axapi3.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/aireos_config.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/aruba_config.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/avi_gslb.py4
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_aaa_server.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_aaa_server_host.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_acl.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_acl_advance.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_acl_interface.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_bfd_global.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_bfd_session.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_bfd_view.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_bgp.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_bgp_af.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_bgp_neighbor.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_bgp_neighbor_af.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_command.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_config.py6
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_dldp.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_dldp_interface.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_eth_trunk.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_evpn_bd_vni.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_evpn_bgp.py4
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_evpn_bgp_rr.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_evpn_global.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_facts.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_file_copy.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_info_center_debug.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_info_center_global.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_info_center_log.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_info_center_trap.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_interface.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_interface_ospf.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_ip_interface.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_link_status.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_mlag_config.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_mlag_interface.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_mtu.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_netconf.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_netstream_aging.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_netstream_export.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_netstream_global.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_netstream_template.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_ntp.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_ntp_auth.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_ospf.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_ospf_vrf.py6
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_reboot.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_rollback.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_sflow.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_snmp_community.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_snmp_contact.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_snmp_location.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_snmp_target_host.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_snmp_traps.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_snmp_user.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_startup.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_static_route.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_stp.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_switchport.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_vlan.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_vrf.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_vrf_af.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_vrf_interface.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_vrrp.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_vxlan_arp.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_vxlan_gateway.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_vxlan_global.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_vxlan_tunnel.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ce_vxlan_vap.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/cnos_config.py4
-rw-r--r--ansible_collections/community/network/plugins/modules/cnos_interface.py8
-rw-r--r--ansible_collections/community/network/plugins/modules/cnos_l3_interface.py6
-rw-r--r--ansible_collections/community/network/plugins/modules/cnos_linkagg.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/cnos_system.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/cnos_user.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/cnos_vlan.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/cnos_vrf.py4
-rw-r--r--ansible_collections/community/network/plugins/modules/cv_server_provision.py12
-rw-r--r--ansible_collections/community/network/plugins/modules/dladm_iptun.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/dladm_linkprop.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/dladm_vlan.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/edgeos_command.py10
-rw-r--r--ansible_collections/community/network/plugins/modules/edgeos_config.py4
-rw-r--r--ansible_collections/community/network/plugins/modules/edgeswitch_vlan.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/enos_config.py4
-rw-r--r--ansible_collections/community/network/plugins/modules/enos_facts.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/exos_config.py8
-rw-r--r--ansible_collections/community/network/plugins/modules/exos_facts.py10
-rw-r--r--ansible_collections/community/network/plugins/modules/exos_l2_interfaces.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/exos_lldp_interfaces.py74
-rw-r--r--ansible_collections/community/network/plugins/modules/exos_vlans.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/iap_start_workflow.py4
-rw-r--r--ansible_collections/community/network/plugins/modules/iap_token.py4
-rw-r--r--ansible_collections/community/network/plugins/modules/icx_banner.py6
-rw-r--r--ansible_collections/community/network/plugins/modules/icx_command.py4
-rw-r--r--ansible_collections/community/network/plugins/modules/icx_config.py4
-rw-r--r--ansible_collections/community/network/plugins/modules/icx_interface.py4
-rw-r--r--ansible_collections/community/network/plugins/modules/icx_l3_interface.py11
-rw-r--r--ansible_collections/community/network/plugins/modules/icx_linkagg.py4
-rw-r--r--ansible_collections/community/network/plugins/modules/icx_lldp.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/icx_logging.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/icx_static_route.py4
-rw-r--r--ansible_collections/community/network/plugins/modules/icx_system.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/icx_user.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/icx_vlan.py4
-rw-r--r--ansible_collections/community/network/plugins/modules/ipadm_addr.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/ipadm_addrprop.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/nclu.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/netscaler_cs_action.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/netscaler_cs_policy.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/netscaler_lb_monitor.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/netscaler_lb_vserver.py4
-rw-r--r--ansible_collections/community/network/plugins/modules/netscaler_save_config.py8
-rw-r--r--ansible_collections/community/network/plugins/modules/netscaler_server.py3
-rw-r--r--ansible_collections/community/network/plugins/modules/netscaler_service.py10
-rw-r--r--ansible_collections/community/network/plugins/modules/netscaler_ssl_certkey.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/nos_config.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/nuage_vspk.py4
-rw-r--r--ansible_collections/community/network/plugins/modules/opx_cps.py4
-rw-r--r--ansible_collections/community/network/plugins/modules/pn_access_list.py4
-rw-r--r--ansible_collections/community/network/plugins/modules/pn_access_list_ip.py8
-rw-r--r--ansible_collections/community/network/plugins/modules/pn_admin_service.py38
-rw-r--r--ansible_collections/community/network/plugins/modules/pn_admin_session_timeout.py6
-rw-r--r--ansible_collections/community/network/plugins/modules/pn_admin_syslog.py16
-rw-r--r--ansible_collections/community/network/plugins/modules/pn_connection_stats_settings.py40
-rw-r--r--ansible_collections/community/network/plugins/modules/pn_cpu_class.py10
-rw-r--r--ansible_collections/community/network/plugins/modules/pn_dhcp_filter.py6
-rw-r--r--ansible_collections/community/network/plugins/modules/pn_dscp_map.py8
-rw-r--r--ansible_collections/community/network/plugins/modules/pn_dscp_map_pri_map.py10
-rw-r--r--ansible_collections/community/network/plugins/modules/pn_igmp_snooping.py28
-rw-r--r--ansible_collections/community/network/plugins/modules/pn_port_config.py58
-rw-r--r--ansible_collections/community/network/plugins/modules/pn_port_cos_bw.py14
-rw-r--r--ansible_collections/community/network/plugins/modules/pn_stp_port.py4
-rw-r--r--ansible_collections/community/network/plugins/modules/pn_vrouter_bgp.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/pn_vtep.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/slxos_config.py4
-rw-r--r--ansible_collections/community/network/plugins/modules/slxos_interface.py8
-rw-r--r--ansible_collections/community/network/plugins/modules/slxos_l3_interface.py5
-rw-r--r--ansible_collections/community/network/plugins/modules/slxos_vlan.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/sros_config.py6
-rw-r--r--ansible_collections/community/network/plugins/modules/vdirect_commit.py2
-rw-r--r--ansible_collections/community/network/plugins/modules/voss_config.py4
-rw-r--r--ansible_collections/community/network/requirements.txt1
-rw-r--r--ansible_collections/community/network/tests/integration/requirements.yml3
-rw-r--r--ansible_collections/community/network/tests/integration/targets/cnos_conditional_template/tasks/main.yml4
-rw-r--r--ansible_collections/community/network/tests/integration/targets/cnos_template/tasks/main.yml4
-rw-r--r--ansible_collections/community/network/tests/integration/targets/prepare_nuage_tests/tasks/main.yml1
-rw-r--r--ansible_collections/community/network/tests/requirements.yml4
-rw-r--r--ansible_collections/community/network/tests/sanity/ignore-2.15.txt111
-rw-r--r--ansible_collections/community/network/tests/sanity/ignore-2.16.txt (renamed from ansible_collections/community/network/tests/sanity/ignore-2.11.txt)128
-rw-r--r--ansible_collections/community/network/tests/sanity/ignore-2.17.txt930
-rw-r--r--ansible_collections/community/network/tests/unit/mock/loader.py2
-rw-r--r--ansible_collections/community/network/tests/unit/plugins/modules/cnos_fixtures/show_ip_interface_brief_vrf_all10
-rw-r--r--ansible_collections/community/network/tests/unit/plugins/modules/cnos_fixtures/show_run331
-rw-r--r--ansible_collections/community/network/tests/unit/plugins/modules/cnos_fixtures/show_running-config331
-rw-r--r--ansible_collections/community/network/tests/unit/plugins/modules/exos_fixtures/show_port_config_no-refresh (renamed from ansible_collections/community/network/tests/unit/plugins/modules/exos_fixtures/show_port_config)0
-rw-r--r--ansible_collections/community/network/tests/unit/plugins/modules/test_avi_user.py104
-rw-r--r--ansible_collections/community/network/tests/unit/plugins/modules/test_cnos_command.py104
-rw-r--r--ansible_collections/community/network/tests/unit/plugins/modules/test_cnos_facts.py82
-rw-r--r--ansible_collections/community/network/tests/unit/plugins/modules/test_cnos_static_route.py74
-rw-r--r--ansible_collections/community/network/tests/unit/plugins/modules/test_cv_server_provision.py889
-rw-r--r--ansible_collections/community/network/tests/unit/plugins/modules/test_icx_static_route.py122
-rw-r--r--ansible_collections/community/network/tests/unit/requirements.txt2
-rw-r--r--ansible_collections/community/network/tests/unit/requirements.yml3
-rw-r--r--ansible_collections/community/postgresql/.azure-pipelines/azure-pipelines.yml150
-rwxr-xr-xansible_collections/community/postgresql/.azure-pipelines/scripts/combine-coverage.py3
-rwxr-xr-xansible_collections/community/postgresql/.azure-pipelines/scripts/time-command.py3
-rw-r--r--ansible_collections/community/postgresql/.codespell-exclude-words3
-rw-r--r--ansible_collections/community/postgresql/.codespellrc2
-rw-r--r--ansible_collections/community/postgresql/.flake87
-rw-r--r--ansible_collections/community/postgresql/.pre-commit-config.yaml36
-rw-r--r--ansible_collections/community/postgresql/CHANGELOG.rst132
-rw-r--r--ansible_collections/community/postgresql/CONTRIBUTING.md44
-rw-r--r--ansible_collections/community/postgresql/CONTRIBUTORS230
-rw-r--r--ansible_collections/community/postgresql/FILES.json449
-rw-r--r--ansible_collections/community/postgresql/MAINTAINING.md2
-rw-r--r--ansible_collections/community/postgresql/MANIFEST.json4
-rw-r--r--ansible_collections/community/postgresql/README.md81
-rw-r--r--ansible_collections/community/postgresql/changelogs/changelog.yaml151
-rw-r--r--ansible_collections/community/postgresql/meta/runtime.yml6
-rw-r--r--ansible_collections/community/postgresql/plugins/doc_fragments/postgres.py12
-rw-r--r--ansible_collections/community/postgresql/plugins/module_utils/_version.py3
-rw-r--r--ansible_collections/community/postgresql/plugins/module_utils/database.py7
-rw-r--r--ansible_collections/community/postgresql/plugins/module_utils/postgres.py150
-rw-r--r--ansible_collections/community/postgresql/plugins/module_utils/saslprep.py22
-rw-r--r--ansible_collections/community/postgresql/plugins/module_utils/version.py5
-rw-r--r--ansible_collections/community/postgresql/plugins/modules/postgresql_copy.py30
-rw-r--r--ansible_collections/community/postgresql/plugins/modules/postgresql_db.py157
-rw-r--r--ansible_collections/community/postgresql/plugins/modules/postgresql_ext.py267
-rw-r--r--ansible_collections/community/postgresql/plugins/modules/postgresql_idx.py47
-rw-r--r--ansible_collections/community/postgresql/plugins/modules/postgresql_info.py289
-rw-r--r--ansible_collections/community/postgresql/plugins/modules/postgresql_lang.py25
-rw-r--r--ansible_collections/community/postgresql/plugins/modules/postgresql_membership.py26
-rw-r--r--ansible_collections/community/postgresql/plugins/modules/postgresql_owner.py318
-rw-r--r--ansible_collections/community/postgresql/plugins/modules/postgresql_pg_hba.py42
-rw-r--r--ansible_collections/community/postgresql/plugins/modules/postgresql_ping.py29
-rw-r--r--ansible_collections/community/postgresql/plugins/modules/postgresql_privs.py391
-rw-r--r--ansible_collections/community/postgresql/plugins/modules/postgresql_publication.py74
-rw-r--r--ansible_collections/community/postgresql/plugins/modules/postgresql_query.py166
-rw-r--r--ansible_collections/community/postgresql/plugins/modules/postgresql_schema.py76
-rw-r--r--ansible_collections/community/postgresql/plugins/modules/postgresql_script.py66
-rw-r--r--ansible_collections/community/postgresql/plugins/modules/postgresql_sequence.py52
-rw-r--r--ansible_collections/community/postgresql/plugins/modules/postgresql_set.py117
-rw-r--r--ansible_collections/community/postgresql/plugins/modules/postgresql_slot.py31
-rw-r--r--ansible_collections/community/postgresql/plugins/modules/postgresql_subscription.py79
-rw-r--r--ansible_collections/community/postgresql/plugins/modules/postgresql_table.py35
-rw-r--r--ansible_collections/community/postgresql/plugins/modules/postgresql_tablespace.py132
-rw-r--r--ansible_collections/community/postgresql/plugins/modules/postgresql_user.py202
-rw-r--r--ansible_collections/community/postgresql/plugins/modules/postgresql_user_obj_stat_info.py56
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_db/defaults/main.yml1
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_db/tasks/main.yml3
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_db/tasks/postgresql_db_comment.yml189
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_db/tasks/postgresql_db_initial.yml171
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_ext/tasks/postgresql_ext_initial.yml126
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_ext/tasks/postgresql_ext_version_opt.yml195
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_info/defaults/main.yml5
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_info/meta/main.yml2
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_info/tasks/main.yml6
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_info/tasks/postgresql_info_initial.yml14
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_lang/aliases2
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_lang/meta/main.yml2
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_lang/tasks/main.yml25
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_lang/tasks/postgresql_lang_add_owner_param.yml199
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_lang/tasks/postgresql_lang_initial.yml231
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_lang/vars/CentOS-7.yml3
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_lang/vars/CentOS-8.yml3
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_lang/vars/default.yml0
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_owner/tasks/postgresql_owner_initial.yml2071
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_pg_hba/tasks/postgresql_pg_hba_initial.yml12
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_ping/defaults/main.yml2
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_ping/handlers/main.yml6
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_ping/tasks/main.yml5
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_ping/tasks/postgresql_ping_initial.yml268
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_ping/vars/main.yml5
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_privs/tasks/postgresql_privs_general.yml172
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_privs/tasks/postgresql_privs_initial.yml237
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_privs/tasks/test_target_role.yml2
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_publication/tasks/postgresql_publication_initial.yml84
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_query/files/test0.sql6
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_query/files/test1.sql10
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_query/tasks/postgresql_query_initial.yml101
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_schema/tasks/postgresql_schema_initial.yml199
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_set/tasks/options_coverage.yml60
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_subscription/defaults/main.yml4
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_subscription/meta/main.yml2
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_subscription/tasks/main.yml6
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_subscription/tasks/postgresql_subscription_initial.yml113
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_tablespace/tasks/postgresql_tablespace_initial.yml200
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_user/defaults/main.yml3
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_user/tasks/main.yml4
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_user/tasks/postgresql_user_general.yml254
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_user/tasks/postgresql_user_sql_ascii_db.yml8
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/postgresql_user_obj_stat_info/tasks/postgresql_user_obj_stat_info.yml2
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/defaults/main.yml18
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/tasks/main.yml41
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/tasks/replica.yml59
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/tasks/sql_ascii.yml36
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/Debian-8.yml5
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/Fedora-36-py3.yml7
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/Fedora-38-py3.yml5
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/RedHat-py3.yml5
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/RedHat.yml5
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/Ubuntu-20-py3.yml12
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/Ubuntu-22-py3.yml18
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/default-py3.yml4
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/default.yml4
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_replication/defaults/main.yml26
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_replication/handlers/main.yml24
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_replication/tasks/main.yml13
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_replication/tasks/setup_postgresql_cluster.yml149
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_replication/templates/pg_hba.conf.j27
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_replication/templates/primary_postgresql.conf.j228
-rw-r--r--ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_replication/templates/replica_postgresql.conf.j228
-rwxr-xr-xansible_collections/community/postgresql/tests/sanity/extra/no-unwanted-files.py3
-rw-r--r--ansible_collections/community/postgresql/tests/sanity/ignore-2.12.txt2
-rw-r--r--ansible_collections/community/postgresql/tests/sanity/ignore-2.13.txt2
-rw-r--r--ansible_collections/community/postgresql/tests/sanity/ignore-2.14.txt2
-rw-r--r--ansible_collections/community/postgresql/tests/sanity/ignore-2.15.txt2
-rw-r--r--ansible_collections/community/postgresql/tests/sanity/ignore-2.16.txt2
-rw-r--r--ansible_collections/community/postgresql/tests/sanity/ignore-2.17.txt5
-rw-r--r--ansible_collections/community/postgresql/tests/unit/plugins/module_utils/test_postgres.py64
-rw-r--r--ansible_collections/community/postgresql/tests/unit/plugins/module_utils/test_saslprep.py10
-rw-r--r--ansible_collections/community/postgresql/tests/unit/plugins/modules/test_postgresql_set.py7
-rwxr-xr-xansible_collections/community/postgresql/tests/utils/shippable/check_matrix.py12
-rwxr-xr-xansible_collections/community/postgresql/tests/utils/shippable/shippable.sh1
-rwxr-xr-xansible_collections/community/postgresql/tests/utils/shippable/timing.py3
-rw-r--r--ansible_collections/community/postgresql/tox.ini14
-rw-r--r--ansible_collections/community/routeros/.github/workflows/ansible-test.yml10
-rw-r--r--ansible_collections/community/routeros/.github/workflows/docs-pr.yml2
-rw-r--r--ansible_collections/community/routeros/.github/workflows/docs-push.yml2
-rw-r--r--ansible_collections/community/routeros/.github/workflows/ee.yml8
-rw-r--r--ansible_collections/community/routeros/.github/workflows/extra-tests.yml13
-rw-r--r--ansible_collections/community/routeros/.github/workflows/import-galaxy.yml78
-rw-r--r--ansible_collections/community/routeros/.github/workflows/reuse.yml11
-rw-r--r--ansible_collections/community/routeros/CHANGELOG.md631
-rw-r--r--ansible_collections/community/routeros/CHANGELOG.md.license3
-rw-r--r--ansible_collections/community/routeros/CHANGELOG.rst154
-rw-r--r--ansible_collections/community/routeros/FILES.json96
-rw-r--r--ansible_collections/community/routeros/MANIFEST.json4
-rw-r--r--ansible_collections/community/routeros/README.md4
-rw-r--r--ansible_collections/community/routeros/changelogs/changelog.yaml207
-rw-r--r--ansible_collections/community/routeros/changelogs/config.yaml3
-rw-r--r--ansible_collections/community/routeros/docs/docsite/rst/api-guide.rst24
-rw-r--r--ansible_collections/community/routeros/docs/docsite/rst/quoting.rst12
-rw-r--r--ansible_collections/community/routeros/docs/docsite/rst/ssh-guide.rst16
-rw-r--r--ansible_collections/community/routeros/plugins/doc_fragments/api.py24
-rw-r--r--ansible_collections/community/routeros/plugins/filter/list_to_dict.yml6
-rw-r--r--ansible_collections/community/routeros/plugins/module_utils/_api_data.py6708
-rw-r--r--ansible_collections/community/routeros/plugins/module_utils/api.py7
-rw-r--r--ansible_collections/community/routeros/plugins/modules/api.py58
-rw-r--r--ansible_collections/community/routeros/plugins/modules/api_facts.py46
-rw-r--r--ansible_collections/community/routeros/plugins/modules/api_find_and_modify.py16
-rw-r--r--ansible_collections/community/routeros/plugins/modules/api_info.py100
-rw-r--r--ansible_collections/community/routeros/plugins/modules/api_modify.py175
-rw-r--r--ansible_collections/community/routeros/plugins/modules/command.py12
-rw-r--r--ansible_collections/community/routeros/plugins/modules/facts.py52
-rwxr-xr-xansible_collections/community/routeros/tests/sanity/extra/extra-docs.py2
-rw-r--r--ansible_collections/community/routeros/tests/sanity/ignore-2.10.txt3
-rw-r--r--ansible_collections/community/routeros/tests/sanity/ignore-2.17.txt2
-rw-r--r--ansible_collections/community/routeros/tests/sanity/ignore-2.17.txt.license3
-rw-r--r--ansible_collections/community/routeros/tests/sanity/ignore-2.9.txt3
-rw-r--r--ansible_collections/community/routeros/tests/unit/plugins/module_utils/test__api_data.py40
-rw-r--r--ansible_collections/community/routeros/tests/unit/plugins/modules/fake_api.py43
-rw-r--r--ansible_collections/community/routeros/tests/unit/plugins/modules/test_api_find_and_modify.py21
-rw-r--r--ansible_collections/community/routeros/tests/unit/plugins/modules/test_api_info.py15
-rw-r--r--ansible_collections/community/routeros/tests/unit/plugins/modules/test_api_modify.py44
-rwxr-xr-xansible_collections/community/routeros/update-docs.py7
-rw-r--r--ansible_collections/community/sap/.github/workflows/ansible-test.yml230
-rw-r--r--ansible_collections/community/sap/CHANGELOG.rst42
-rw-r--r--ansible_collections/community/sap/FILES.json142
-rw-r--r--ansible_collections/community/sap/MANIFEST.json10
-rw-r--r--ansible_collections/community/sap/README.md8
-rw-r--r--ansible_collections/community/sap/changelogs/changelog.yaml23
-rw-r--r--ansible_collections/community/sap/changelogs/config.yaml1
-rw-r--r--ansible_collections/community/sap/meta/runtime.yml31
-rw-r--r--ansible_collections/community/sap/plugins/modules/__init__.py (renamed from ansible_collections/community/google/tests/unit/compat/__init__.py)0
-rw-r--r--ansible_collections/community/sap/plugins/modules/database/saphana/hana_query.py238
-rw-r--r--ansible_collections/community/sap/plugins/modules/files/sapcar_extract.py220
-rw-r--r--ansible_collections/community/sap/plugins/modules/hana_query.py238
-rw-r--r--ansible_collections/community/sap/plugins/modules/identity/sap_company.py326
-rw-r--r--ansible_collections/community/sap/plugins/modules/identity/sap_user.py499
-rw-r--r--ansible_collections/community/sap/plugins/modules/sap_company.py326
-rw-r--r--ansible_collections/community/sap/plugins/modules/sap_snote.py258
-rw-r--r--ansible_collections/community/sap/plugins/modules/sap_system_facts.py206
-rw-r--r--ansible_collections/community/sap/plugins/modules/sap_task_list_execute.py340
-rw-r--r--ansible_collections/community/sap/plugins/modules/sap_user.py499
-rw-r--r--ansible_collections/community/sap/plugins/modules/sapcar_extract.py220
-rw-r--r--ansible_collections/community/sap/plugins/modules/system/sap_snote.py258
-rw-r--r--ansible_collections/community/sap/plugins/modules/system/sap_system_facts.py206
-rw-r--r--ansible_collections/community/sap/plugins/modules/system/sap_task_list_execute.py340
-rw-r--r--ansible_collections/community/sap_libs/.github/workflows/ansible-test.yml14
-rw-r--r--ansible_collections/community/sap_libs/FILES.json22
-rw-r--r--ansible_collections/community/sap_libs/MANIFEST.json4
-rw-r--r--ansible_collections/community/sap_libs/README.md18
-rw-r--r--ansible_collections/community/sap_libs/changelogs/changelog.yaml10
-rw-r--r--ansible_collections/community/sap_libs/tests/sanity/ignore-2.16.txt9
-rw-r--r--ansible_collections/community/sap_libs/tests/sanity/ignore-2.17.txt9
-rw-r--r--ansible_collections/community/sap_libs/tests/unit/mock/loader.py7
-rw-r--r--ansible_collections/community/skydive/.github/workflows/ansible-test.yml179
-rw-r--r--ansible_collections/community/skydive/.gitignore132
-rw-r--r--ansible_collections/community/skydive/.yamllint14
-rw-r--r--ansible_collections/community/skydive/CHANGELOG.rst16
-rw-r--r--ansible_collections/community/skydive/FILES.json327
-rw-r--r--ansible_collections/community/skydive/LICENSE674
-rw-r--r--ansible_collections/community/skydive/MANIFEST.json32
-rw-r--r--ansible_collections/community/skydive/README.md3
-rw-r--r--ansible_collections/community/skydive/bindep.txt6
-rw-r--r--ansible_collections/community/skydive/changelogs/changelog.yaml12
-rw-r--r--ansible_collections/community/skydive/meta/runtime.yml2
-rw-r--r--ansible_collections/community/skydive/plugins/doc_fragments/__init__.py0
-rw-r--r--ansible_collections/community/skydive/plugins/doc_fragments/skydive.py55
-rw-r--r--ansible_collections/community/skydive/plugins/lookup/__init__.py0
-rw-r--r--ansible_collections/community/skydive/plugins/lookup/skydive.py79
-rw-r--r--ansible_collections/community/skydive/plugins/module_utils/__init__.py0
-rw-r--r--ansible_collections/community/skydive/plugins/module_utils/network/skydive/__init__.py0
-rw-r--r--ansible_collections/community/skydive/plugins/module_utils/network/skydive/api.py465
-rw-r--r--ansible_collections/community/skydive/plugins/modules/__init__.py0
-rw-r--r--ansible_collections/community/skydive/plugins/modules/skydive_capture.py189
-rw-r--r--ansible_collections/community/skydive/plugins/modules/skydive_edge.py202
-rw-r--r--ansible_collections/community/skydive/plugins/modules/skydive_node.py138
-rw-r--r--ansible_collections/community/skydive/requirements.txt1
-rw-r--r--ansible_collections/community/skydive/test-requirements.txt2
-rw-r--r--ansible_collections/community/skydive/tests/.gitignore1
-rw-r--r--ansible_collections/community/skydive/tests/sanity/ignore-2.10.txt21
-rw-r--r--ansible_collections/community/skydive/tests/sanity/ignore-2.11.txt21
-rw-r--r--ansible_collections/community/skydive/tests/sanity/ignore-2.9.txt16
-rw-r--r--ansible_collections/community/skydive/tests/sanity/requirements.txt4
-rw-r--r--ansible_collections/community/skydive/tests/unit/__init__.py0
-rw-r--r--ansible_collections/community/skydive/tests/unit/requirements.txt42
-rw-r--r--ansible_collections/community/skydive/tox.ini31
-rw-r--r--ansible_collections/community/sops/.github/workflows/ansible-test.yml34
-rw-r--r--ansible_collections/community/sops/.github/workflows/ee.yml6
-rw-r--r--ansible_collections/community/sops/.github/workflows/extra-tests.yml4
-rw-r--r--ansible_collections/community/sops/.github/workflows/import-galaxy.yml6
-rw-r--r--ansible_collections/community/sops/.github/workflows/reuse.yml2
-rw-r--r--ansible_collections/community/sops/CHANGELOG.rst76
-rw-r--r--ansible_collections/community/sops/FILES.json194
-rw-r--r--ansible_collections/community/sops/MANIFEST.json6
-rw-r--r--ansible_collections/community/sops/README.md12
-rw-r--r--ansible_collections/community/sops/changelogs/changelog.yaml75
-rw-r--r--ansible_collections/community/sops/docs/docsite/rst/guide.rst42
-rw-r--r--ansible_collections/community/sops/plugins/doc_fragments/sops.py14
-rw-r--r--ansible_collections/community/sops/plugins/filter/_latest_version.py2
-rw-r--r--ansible_collections/community/sops/plugins/filter/decrypt.py14
-rw-r--r--ansible_collections/community/sops/plugins/lookup/sops.py12
-rw-r--r--ansible_collections/community/sops/plugins/module_utils/sops.py4
-rw-r--r--ansible_collections/community/sops/plugins/modules/load_vars.py21
-rw-r--r--ansible_collections/community/sops/plugins/modules/sops_encrypt.py15
-rw-r--r--ansible_collections/community/sops/plugins/vars/sops.py14
-rw-r--r--ansible_collections/community/sops/roles/install/meta/argument_specs.yml18
-rw-r--r--ansible_collections/community/sops/roles/install/meta/main.yml2
-rw-r--r--ansible_collections/community/sops/roles/install/tasks/github_api.yml2
-rw-r--r--ansible_collections/community/sops/roles/install/tasks/github_latest_release.yml4
-rw-r--r--ansible_collections/community/sops/roles/install/vars/OS-Debian.yml4
-rw-r--r--ansible_collections/community/sops/roles/install/vars/OS-RedHat.yml8
-rw-r--r--ansible_collections/community/sops/tests/ee/all.yml2
-rw-r--r--ansible_collections/community/sops/tests/integration/targets/filter__latest_version/aliases9
-rw-r--r--ansible_collections/community/sops/tests/integration/targets/filter__latest_version/tasks/main.yml39
-rw-r--r--ansible_collections/community/sops/tests/integration/targets/role_install_latest/meta/main.yml7
-rw-r--r--ansible_collections/community/sops/tests/integration/targets/role_install_localhost_remote/meta/main.yml7
-rw-r--r--ansible_collections/community/sops/tests/integration/targets/role_install_version/meta/main.yml7
-rw-r--r--ansible_collections/community/sops/tests/integration/targets/role_install_version/tasks/main.yml18
-rw-r--r--ansible_collections/community/sops/tests/integration/targets/setup_pkg_mgr/tasks/archlinux.yml28
-rw-r--r--ansible_collections/community/sops/tests/integration/targets/setup_pkg_mgr/tasks/main.yml9
-rw-r--r--ansible_collections/community/sops/tests/integration/targets/setup_sops/meta/main.yml7
-rw-r--r--ansible_collections/community/sops/tests/integration/targets/setup_sops/tasks/install.yml4
-rw-r--r--ansible_collections/community/sops/tests/integration/targets/var_sops/README.md2
-rwxr-xr-xansible_collections/community/sops/tests/sanity/extra/extra-docs.py2
-rw-r--r--ansible_collections/community/sops/tests/sanity/ignore-2.10.txt3
-rw-r--r--ansible_collections/community/sops/tests/sanity/ignore-2.11.txt2
-rw-r--r--ansible_collections/community/sops/tests/sanity/ignore-2.12.txt2
-rw-r--r--ansible_collections/community/sops/tests/sanity/ignore-2.13.txt4
-rw-r--r--ansible_collections/community/sops/tests/sanity/ignore-2.14.txt4
-rw-r--r--ansible_collections/community/sops/tests/sanity/ignore-2.17.txt4
-rw-r--r--ansible_collections/community/sops/tests/sanity/ignore-2.17.txt.license3
-rw-r--r--ansible_collections/community/sops/tests/sanity/ignore-2.9.txt3
-rw-r--r--ansible_collections/community/vmware/.github/workflows/ansible-test.yml19
-rw-r--r--ansible_collections/community/vmware/.github/workflows/extra-docs-linting.yml1
-rw-r--r--ansible_collections/community/vmware/.github/workflows/import-galaxy.yml20
-rw-r--r--ansible_collections/community/vmware/.gitignore3
-rw-r--r--ansible_collections/community/vmware/CHANGELOG.rst1072
-rw-r--r--ansible_collections/community/vmware/FILES.json1784
-rw-r--r--ansible_collections/community/vmware/MANIFEST.json4
-rw-r--r--ansible_collections/community/vmware/README.md221
-rw-r--r--ansible_collections/community/vmware/changelogs/changelog.yaml1687
-rw-r--r--ansible_collections/community/vmware/changelogs/config.yaml2
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vcenter_domain_user_group_info_module.rst390
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vcenter_extension_info_module.rst229
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vcenter_extension_module.rst441
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vcenter_folder_module.rst405
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vcenter_license_module.rst361
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vcenter_standard_key_provider_module.rst549
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_about_info_module.rst237
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_category_info_module.rst259
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_category_module.rst413
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_cfg_backup_module.rst312
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_cluster_dpm_module.rst296
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_cluster_drs_module.rst376
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_cluster_drs_recommendations_module.rst265
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_cluster_ha_module.rst699
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_cluster_info_module.rst362
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_cluster_module.rst275
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_cluster_vcls_module.rst287
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_cluster_vsan_module.rst415
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_content_deploy_ovf_template_module.rst461
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_content_deploy_template_module.rst477
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_content_library_info_module.rst284
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_content_library_manager_module.rst439
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_custom_attribute_manager_module.rst347
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_custom_attribute_module.rst279
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_datacenter_info_module.rst336
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_datacenter_module.rst244
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_datastore_cluster_manager_module.rst318
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_datastore_cluster_module.rst424
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_datastore_info_module.rst414
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_datastore_maintenancemode_module.rst328
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_datastore_module.rst345
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_deploy_ovf_module.rst584
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_drs_group_info_module.rst273
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_drs_group_manager_module.rst397
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_drs_group_module.rst364
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_drs_rule_info_module.rst273
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_dvs_host_module.rst411
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_dvs_portgroup_find_module.rst304
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_dvs_portgroup_info_module.rst382
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_dvs_portgroup_module.rst1250
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_dvswitch_info_module.rst349
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_dvswitch_lacp_module.rst405
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_dvswitch_module.rst877
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_dvswitch_nioc_module.rst449
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_dvswitch_pvlans_module.rst323
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_dvswitch_uplink_pg_module.rst552
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_evc_mode_module.rst313
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_export_ovf_module.rst397
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_first_class_disk_module.rst334
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_folder_info_module.rst277
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_guest_boot_info_module.rst323
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_guest_boot_manager_module.rst490
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_guest_controller_module.rst522
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_guest_cross_vc_clone_module.rst566
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_guest_custom_attribute_defs_module.rst281
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_guest_custom_attributes_module.rst446
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_guest_customization_info_module.rst254
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_guest_disk_info_module.rst362
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_guest_disk_module.rst1210
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_guest_file_operation_module.rst631
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_guest_find_module.rst290
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_guest_info_module.rst499
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_guest_instant_clone_module.rst684
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_guest_module.rst2763
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_guest_move_module.rst393
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_guest_network_module.rst736
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_guest_powerstate_module.rst574
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_guest_register_operation_module.rst417
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_guest_screenshot_module.rst386
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_guest_sendkey_module.rst439
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_guest_serial_port_module.rst583
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_guest_snapshot_info_module.rst353
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_guest_snapshot_module.rst604
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_guest_storage_policy_module.rst429
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_guest_tools_info_module.rst369
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_guest_tools_upgrade_module.rst351
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_guest_tools_wait_module.rst407
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_guest_tpm_module.rst355
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_guest_vgpu_info_module.rst345
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_guest_vgpu_module.rst447
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_guest_video_module.rst486
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_acceptance_module.rst334
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_active_directory_module.rst343
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_auto_start_module.rst609
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_capability_info_module.rst271
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_config_info_module.rst269
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_config_manager_module.rst273
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_custom_attributes_module.rst337
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_datastore_module.rst428
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_disk_info_module.rst295
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_dns_info_module.rst270
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_dns_module.rst422
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_facts_module.rst368
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_feature_info_module.rst279
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_firewall_info_module.rst269
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_firewall_manager_module.rst464
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_hyperthreading_module.rst303
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_inventory_inventory.rst776
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_ipv6_module.rst301
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_iscsi_info_module.rst326
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_iscsi_module.rst1148
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_kernel_manager_module.rst309
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_lockdown_exceptions_module.rst308
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_lockdown_module.rst336
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_logbundle_info_module.rst245
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_logbundle_module.rst340
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_module.rst533
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_ntp_info_module.rst273
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_ntp_module.rst361
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_package_info_module.rst273
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_passthrough_module.rst376
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_powermgmt_policy_module.rst292
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_powerstate_module.rst347
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_scanhba_module.rst348
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_scsidisk_info_module.rst271
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_service_info_module.rst274
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_service_manager_module.rst332
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_snmp_module.rst447
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_sriov_module.rst352
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_ssl_info_module.rst288
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_tcpip_stacks_module.rst805
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_user_manager_module.rst364
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_vmhba_info_module.rst275
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_host_vmnic_info_module.rst339
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_httpapi.rst42
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_local_role_info_module.rst236
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_local_role_manager_module.rst465
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_local_user_info_module.rst232
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_local_user_manager_module.rst264
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_maintenancemode_module.rst360
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_migrate_vmk_module.rst316
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_object_custom_attributes_info_module.rst320
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_object_rename_module.rst363
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_object_role_permission_info_module.rst320
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_object_role_permission_module.rst413
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_portgroup_info_module.rst291
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_portgroup_module.rst714
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_recommended_datastore_module.rst266
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_resource_pool_info_module.rst229
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_resource_pool_module.rst571
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_tag_info_module.rst284
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_tag_manager_module.rst430
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_tag_module.rst361
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_target_canonical_info_module.rst314
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_tools_connection.rst326
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_vc_infraprofile_info_module.rst420
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_vcenter_settings_info_module.rst315
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_vcenter_settings_module.rst987
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_vcenter_statistics_module.rst640
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_vm_config_option_module.rst382
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_vm_host_drs_rule_module.rst364
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_vm_info_module.rst615
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_vm_inventory_inventory.rst974
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_vm_shell_module.rst516
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_vm_storage_policy_info_module.rst230
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_vm_storage_policy_module.rst352
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_vm_vm_drs_rule_module.rst392
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_vm_vss_dvs_migrate_module.rst230
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_vmkernel_info_module.rst273
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_vmkernel_module.rst692
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_vmotion_module.rst486
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_vsan_cluster_module.rst226
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_vsan_hcl_db_module.rst228
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_vsan_health_info_module.rst295
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_vsan_release_catalog_module.rst221
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_vspan_session_module.rst622
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_vswitch_info_module.rst296
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vmware_vswitch_module.rst727
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vsan_health_silent_checks_module.rst271
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vsphere_copy_module.rst304
-rw-r--r--ansible_collections/community/vmware/docs/community.vmware.vsphere_file_module.rst265
-rw-r--r--ansible_collections/community/vmware/meta/runtime.yml8
-rw-r--r--ansible_collections/community/vmware/plugins/connection/vmware_tools.py16
-rw-r--r--ansible_collections/community/vmware/plugins/doc_fragments/vmware.py45
-rw-r--r--ansible_collections/community/vmware/plugins/doc_fragments/vmware_rest_client.py16
-rw-r--r--ansible_collections/community/vmware/plugins/inventory/vmware_host_inventory.py38
-rw-r--r--ansible_collections/community/vmware/plugins/inventory/vmware_vm_inventory.py95
-rw-r--r--ansible_collections/community/vmware/plugins/module_utils/version.py28
-rw-r--r--ansible_collections/community/vmware/plugins/module_utils/vmware.py71
-rw-r--r--ansible_collections/community/vmware/plugins/module_utils/vmware_rest_client.py49
-rw-r--r--ansible_collections/community/vmware/plugins/module_utils/vmware_sms.py76
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vcenter_domain_user_group_info.py6
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vcenter_extension.py16
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vcenter_folder.py18
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vcenter_license.py6
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vcenter_root_password_expiration.py157
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vcenter_standard_key_provider.py28
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_category.py20
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_cfg_backup.py12
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_cluster.py4
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_cluster_dpm.py2
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_cluster_drs.py10
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_cluster_ha.py62
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_cluster_info.py15
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_cluster_vsan.py4
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_content_deploy_template.py20
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_content_library_manager.py36
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_custom_attribute.py8
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_custom_attribute_manager.py6
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_datacenter_info.py8
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_datastore.py10
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_datastore_cluster.py6
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_datastore_cluster_manager.py4
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_datastore_info.py12
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_datastore_maintenancemode.py16
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_deploy_ovf.py401
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_drs_group.py14
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_drs_group_info.py5
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_drs_group_manager.py10
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_drs_rule_info.py4
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_dvs_host.py57
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_dvs_portgroup.py42
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_dvs_portgroup_find.py2
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_dvs_portgroup_info.py15
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_dvswitch.py36
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_dvswitch_info.py4
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_dvswitch_lacp.py6
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_dvswitch_nioc.py2
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_dvswitch_pvlans.py8
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_dvswitch_uplink_pg.py2
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_evc_mode.py2
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_export_ovf.py7
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_first_class_disk_info.py143
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_folder_info.py2
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_guest.py380
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_guest_boot_info.py6
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_guest_boot_manager.py14
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_guest_controller.py18
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_guest_cross_vc_clone.py14
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_guest_custom_attribute_defs.py10
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_guest_custom_attributes.py20
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_guest_disk.py71
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_guest_disk_info.py6
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_guest_file_operation.py9
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_guest_find.py4
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_guest_info.py24
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_guest_instant_clone.py13
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_guest_move.py6
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_guest_network.py23
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_guest_powerstate.py16
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_guest_register_operation.py4
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_guest_screenshot.py18
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_guest_sendkey.py21
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_guest_serial_port.py38
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_guest_snapshot.py81
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_guest_snapshot_info.py10
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_guest_storage_policy.py10
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_guest_tools_info.py6
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_guest_tools_upgrade.py21
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_guest_tools_wait.py8
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_guest_tpm.py6
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_guest_vgpu.py11
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_guest_vgpu_info.py6
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_guest_video.py20
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host.py37
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host_acceptance.py89
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host_acceptance_info.py110
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host_active_directory.py4
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host_auto_start.py4
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host_capability_info.py4
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host_config_info.py4
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host_config_manager.py4
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host_custom_attributes.py6
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host_datastore.py132
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host_disk_info.py8
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host_dns.py12
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host_dns_info.py4
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host_facts.py37
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host_feature_info.py4
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host_firewall_info.py4
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host_firewall_manager.py4
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host_graphics.py190
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host_hyperthreading.py4
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host_ipv6.py4
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host_iscsi.py12
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host_iscsi_info.py1
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host_kernel_manager.py4
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host_lockdown.py29
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host_lockdown_exceptions.py14
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host_ntp.py12
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host_ntp_info.py4
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host_package_info.py4
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host_passthrough.py10
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host_powermgmt_policy.py4
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host_powerstate.py16
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host_scanhba.py4
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host_scsidisk_info.py4
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host_service_info.py4
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host_service_manager.py16
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host_snmp.py596
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host_sriov.py8
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host_ssl_info.py4
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host_user_manager.py7
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host_vmhba_info.py8
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_host_vmnic_info.py13
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_local_role_manager.py10
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_local_user_manager.py2
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_maintenancemode.py2
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_migrate_vmk.py1
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_object_custom_attributes_info.py2
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_object_rename.py4
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_object_role_permission.py10
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_object_role_permission_info.py4
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_portgroup.py8
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_portgroup_info.py4
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_resource_pool.py16
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_tag.py16
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_tag_manager.py12
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_target_canonical_info.py4
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_vasa.py260
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_vasa_info.py116
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_vc_infraprofile_info.py6
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_vcenter_settings.py2
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_vcenter_settings_info.py2
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_vcenter_statistics.py2
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_vm_config_option.py18
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_vm_host_drs_rule.py24
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_vm_info.py43
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_vm_shell.py4
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_vm_storage_policy.py20
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_vm_vm_drs_rule.py22
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_vmkernel.py54
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_vmkernel_info.py4
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_vmotion.py9
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_vsan_health_info.py2
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_vspan_session.py10
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_vswitch.py9
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vmware_vswitch_info.py5
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vsan_health_silent_checks.py4
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vsphere_copy.py31
-rw-r--r--ansible_collections/community/vmware/plugins/modules/vsphere_file.py57
-rw-r--r--ansible_collections/community/vmware/testing.md2
-rw-r--r--ansible_collections/community/vmware/tests/integration/targets/prepare_vmware_tests/tasks/setup_virtualmachines.yml4
-rw-r--r--ansible_collections/community/vmware/tests/integration/targets/vcenter_root_password_expiration/aliases3
-rw-r--r--ansible_collections/community/vmware/tests/integration/targets/vcenter_root_password_expiration/tasks/main.yml23
-rw-r--r--ansible_collections/community/vmware/tests/integration/targets/vmware_about_info/tasks/main.yml4
-rw-r--r--ansible_collections/community/vmware/tests/integration/targets/vmware_category/tasks/associable_obj_test.yml2
-rw-r--r--ansible_collections/community/vmware/tests/integration/targets/vmware_category/tasks/main.yml2
-rw-r--r--ansible_collections/community/vmware/tests/integration/targets/vmware_dvs_portgroup/tasks/main.yml4
-rw-r--r--ansible_collections/community/vmware/tests/integration/targets/vmware_first_class_disk_info/aliases3
-rw-r--r--ansible_collections/community/vmware/tests/integration/targets/vmware_first_class_disk_info/tasks/main.yml96
-rw-r--r--ansible_collections/community/vmware/tests/integration/targets/vmware_folder_info/tasks/main.yml2
-rw-r--r--ansible_collections/community/vmware/tests/integration/targets/vmware_guest/tasks/cdrom_d1_c1_f0.yml16
-rw-r--r--ansible_collections/community/vmware/tests/integration/targets/vmware_guest/tasks/check_mode.yml2
-rw-r--r--ansible_collections/community/vmware/tests/integration/targets/vmware_guest/tasks/clone_customize_guest_test.yml2
-rw-r--r--ansible_collections/community/vmware/tests/integration/targets/vmware_guest/tasks/clone_with_convert.yml2
-rw-r--r--ansible_collections/community/vmware/tests/integration/targets/vmware_guest/tasks/windows_vbs_d1_c1_f0.yml4
-rw-r--r--ansible_collections/community/vmware/tests/integration/targets/vmware_guest_controller/tasks/main.yml8
-rw-r--r--ansible_collections/community/vmware/tests/integration/targets/vmware_guest_disk/tasks/main.yml28
-rw-r--r--ansible_collections/community/vmware/tests/integration/targets/vmware_guest_disk_info/tasks/main.yml2
-rw-r--r--ansible_collections/community/vmware/tests/integration/targets/vmware_guest_network/tasks/main.yml22
-rw-r--r--ansible_collections/community/vmware/tests/integration/targets/vmware_guest_powerstate/tasks/main.yml2
-rw-r--r--ansible_collections/community/vmware/tests/integration/targets/vmware_guest_snapshot/tasks/main.yml105
-rw-r--r--ansible_collections/community/vmware/tests/integration/targets/vmware_guest_tools_wait/tasks/main.yml2
-rw-r--r--ansible_collections/community/vmware/tests/integration/targets/vmware_host_acceptance/tasks/main.yml41
-rw-r--r--ansible_collections/community/vmware/tests/integration/targets/vmware_host_acceptance_info/aliases3
-rw-r--r--ansible_collections/community/vmware/tests/integration/targets/vmware_host_acceptance_info/tasks/main.yml22
-rw-r--r--ansible_collections/community/vmware/tests/integration/targets/vmware_host_auto_start/tasks/main.yml4
-rw-r--r--ansible_collections/community/vmware/tests/integration/targets/vmware_host_snmp/aliases2
-rw-r--r--ansible_collections/community/vmware/tests/integration/targets/vmware_host_snmp/tasks/main.yml131
-rw-r--r--ansible_collections/community/vmware/tests/integration/targets/vmware_object_rename/tasks/main.yml2
-rw-r--r--ansible_collections/community/vmware/tests/integration/targets/vmware_tag/tasks/main.yml6
-rw-r--r--ansible_collections/community/vmware/tests/integration/targets/vmware_tag_info/tasks/main.yml2
-rw-r--r--ansible_collections/community/vmware/tests/integration/targets/vmware_tag_manager/tasks/main.yml4
-rw-r--r--ansible_collections/community/vmware/tests/integration/targets/vmware_vm_inventory/prepare_environment.yml2
-rw-r--r--ansible_collections/community/vmware/tests/sanity/ignore-2.13.txt2
-rw-r--r--ansible_collections/community/vmware/tests/sanity/ignore-2.14.txt2
-rw-r--r--ansible_collections/community/vmware/tests/sanity/ignore-2.15.txt2
-rw-r--r--ansible_collections/community/vmware/tests/sanity/ignore-2.16.txt4
-rw-r--r--ansible_collections/community/vmware/tests/sanity/ignore-2.17.txt4
-rw-r--r--ansible_collections/community/vmware/tests/unit/compat/__init__.py0
-rw-r--r--ansible_collections/community/vmware/tests/unit/compat/mock.py122
-rw-r--r--ansible_collections/community/vmware/tests/unit/compat/unittest.py38
-rw-r--r--ansible_collections/community/vmware/tests/unit/mock/path.py3
-rw-r--r--ansible_collections/community/vmware/tests/unit/mock/procenv.py2
-rw-r--r--ansible_collections/community/vmware/tests/unit/module_utils/test_vmware.py11
-rw-r--r--ansible_collections/community/vmware/tests/unit/modules/cloud/vmware/test_vmware_host_sriov.py8
-rw-r--r--ansible_collections/community/vmware/tests/unit/modules/utils.py5
-rw-r--r--ansible_collections/community/vmware/tools/create_documentation_tasks.yml6
-rw-r--r--ansible_collections/community/vmware/tools/prepare_release.yml16
-rw-r--r--ansible_collections/community/vmware/tools/update_documentation.yml4
-rw-r--r--ansible_collections/community/vmware/tox.ini2
-rw-r--r--ansible_collections/community/windows/.ansible-lint11
-rw-r--r--ansible_collections/community/windows/.azure-pipelines/azure-pipelines.yml97
-rw-r--r--ansible_collections/community/windows/.github/workflows/docs-pr.yml4
-rw-r--r--ansible_collections/community/windows/.github/workflows/docs-push.yml6
-rw-r--r--ansible_collections/community/windows/.github/workflows/stale.yml24
-rw-r--r--ansible_collections/community/windows/CHANGELOG.rst78
-rw-r--r--ansible_collections/community/windows/FILES.json292
-rw-r--r--ansible_collections/community/windows/MANIFEST.json6
-rw-r--r--ansible_collections/community/windows/README.md2
-rw-r--r--ansible_collections/community/windows/changelogs/changelog.yaml94
-rw-r--r--ansible_collections/community/windows/changelogs/config.yaml32
-rw-r--r--ansible_collections/community/windows/meta/runtime.yml28
-rw-r--r--ansible_collections/community/windows/plugins/modules/psexec.py2
-rw-r--r--ansible_collections/community/windows/plugins/modules/win_auto_logon.ps17
-rw-r--r--ansible_collections/community/windows/plugins/modules/win_credential.ps13
-rw-r--r--ansible_collections/community/windows/plugins/modules/win_credential.py2
-rw-r--r--ansible_collections/community/windows/plugins/modules/win_dns_record.ps129
-rw-r--r--ansible_collections/community/windows/plugins/modules/win_dns_record.py17
-rw-r--r--ansible_collections/community/windows/plugins/modules/win_domain_computer.py4
-rw-r--r--ansible_collections/community/windows/plugins/modules/win_domain_group.py4
-rw-r--r--ansible_collections/community/windows/plugins/modules/win_domain_group_membership.py4
-rw-r--r--ansible_collections/community/windows/plugins/modules/win_domain_object_info.py4
-rw-r--r--ansible_collections/community/windows/plugins/modules/win_domain_ou.py4
-rw-r--r--ansible_collections/community/windows/plugins/modules/win_domain_user.py4
-rw-r--r--ansible_collections/community/windows/plugins/modules/win_format.ps18
-rw-r--r--ansible_collections/community/windows/plugins/modules/win_iis_webapppool.py8
-rw-r--r--ansible_collections/community/windows/plugins/modules/win_inet_proxy.ps12
-rw-r--r--ansible_collections/community/windows/plugins/modules/win_mapped_drive.ps12
-rw-r--r--ansible_collections/community/windows/plugins/modules/win_nssm.ps155
-rw-r--r--ansible_collections/community/windows/plugins/modules/win_nssm.py7
-rw-r--r--ansible_collections/community/windows/plugins/modules/win_partition.ps17
-rw-r--r--ansible_collections/community/windows/plugins/modules/win_psmodule.ps199
-rw-r--r--ansible_collections/community/windows/plugins/modules/win_psmodule.py6
-rw-r--r--ansible_collections/community/windows/plugins/modules/win_psmodule_info.ps12
-rw-r--r--ansible_collections/community/windows/plugins/modules/win_rabbitmq_plugin.ps115
-rw-r--r--ansible_collections/community/windows/plugins/modules/win_rds_rap.ps110
-rw-r--r--ansible_collections/community/windows/plugins/modules/win_region.ps16
-rw-r--r--ansible_collections/community/windows/plugins/modules/win_regmerge.ps131
-rw-r--r--ansible_collections/community/windows/plugins/modules/win_regmerge.py25
-rw-r--r--ansible_collections/community/windows/plugins/modules/win_robocopy.ps110
-rw-r--r--ansible_collections/community/windows/plugins/modules/win_scheduled_task.ps113
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/setup_win_device/library/win_device.ps13
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_audit_rule/library/test_get_audit_rule.ps14
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_auto_logon/library/test_autologon_info.ps17
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_credential/library/test_cred_facts.ps13
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/tasks/main.yml2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/tasks/pre_test.yml2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_disk_facts/tasks/main.yml2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/main.yml2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_dns_zone/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_domain_ou/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_domain_user/aliases1
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_firewall/aliases2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_format/tasks/main.yml2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_format/tasks/pre_test.yml2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_inet_proxy/library/win_inet_proxy_info.ps12
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_initialize_disk/tasks/main.yml2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_nssm/tasks/tests.yml46
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_partition/tasks/main.yml2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/module/template.psd14
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/module/template.psm117
-rwxr-xr-x[-rw-r--r--]ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/setup_certs.sh6
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/setup_modules.ps118
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psmodule/tasks/main.yml19
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_psmodule/tasks/setup.yml10
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_regmerge/files/settings1c.reg4
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_regmerge/files/settings3c.reg30
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_regmerge/tasks/main.yml99
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_route/tasks/main.yml6
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_scheduled_task/tasks/triggers.yml6
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_scoop/aliases2
-rw-r--r--ansible_collections/community/windows/tests/integration/targets/win_scoop_bucket/aliases2
-rw-r--r--ansible_collections/community/windows/tests/requirements.yml10
-rw-r--r--ansible_collections/community/windows/tests/sanity/ignore-2.12.txt13
-rw-r--r--ansible_collections/community/windows/tests/sanity/ignore-2.13.txt13
-rw-r--r--ansible_collections/community/windows/tests/sanity/ignore-2.14.txt10
-rw-r--r--ansible_collections/community/windows/tests/sanity/ignore-2.15.txt10
-rw-r--r--ansible_collections/community/windows/tests/sanity/ignore-2.16.txt10
-rw-r--r--ansible_collections/community/windows/tests/sanity/ignore-2.17.txt5
-rw-r--r--ansible_collections/community/windows/tests/unit/compat/__init__.py0
-rw-r--r--ansible_collections/community/windows/tests/unit/compat/mock.py42
-rw-r--r--ansible_collections/community/windows/tests/unit/mock/__init__.py0
-rw-r--r--ansible_collections/community/windows/tests/unit/mock/loader.py116
-rw-r--r--ansible_collections/community/windows/tests/unit/mock/path.py8
-rw-r--r--ansible_collections/community/windows/tests/unit/mock/procenv.py90
-rw-r--r--ansible_collections/community/windows/tests/unit/mock/vault_helper.py39
-rw-r--r--ansible_collections/community/windows/tests/unit/mock/yaml_helper.py124
-rw-r--r--ansible_collections/community/windows/tests/unit/modules/__init__.py0
-rw-r--r--ansible_collections/community/windows/tests/unit/modules/utils.py50
-rw-r--r--ansible_collections/community/windows/tests/unit/plugins/lookup/fixtures/avi.json104
-rw-r--r--ansible_collections/community/windows/tests/unit/plugins/lookup/test_laps_password.py2
-rwxr-xr-xansible_collections/community/windows/tests/utils/shippable/lint.sh10
-rw-r--r--ansible_collections/community/zabbix/.github/workflows/agent.yml55
-rw-r--r--ansible_collections/community/zabbix/.github/workflows/javagateway.yml61
-rw-r--r--ansible_collections/community/zabbix/.github/workflows/plugins-integration.yml23
-rw-r--r--ansible_collections/community/zabbix/.github/workflows/proxy.yml71
-rw-r--r--ansible_collections/community/zabbix/.github/workflows/repo-sanity.yml15
-rw-r--r--ansible_collections/community/zabbix/.github/workflows/server.yml67
-rw-r--r--ansible_collections/community/zabbix/.github/workflows/web.yml67
-rw-r--r--ansible_collections/community/zabbix/.gitignore1
-rw-r--r--ansible_collections/community/zabbix/CHANGELOG.rst157
-rw-r--r--ansible_collections/community/zabbix/CONTRIBUTING.md1
-rw-r--r--ansible_collections/community/zabbix/FILES.json907
-rw-r--r--ansible_collections/community/zabbix/MANIFEST.json10
-rw-r--r--ansible_collections/community/zabbix/README.md12
-rw-r--r--ansible_collections/community/zabbix/changelogs/.plugin-cache.yaml42
-rw-r--r--ansible_collections/community/zabbix/changelogs/changelog.yaml216
-rw-r--r--ansible_collections/community/zabbix/changelogs/roles_zabbix64.yml2
-rw-r--r--ansible_collections/community/zabbix/docs/PUBLISHING_TO_GALAXY.md21
-rw-r--r--ansible_collections/community/zabbix/docs/UPGRADE.md194
-rw-r--r--ansible_collections/community/zabbix/docs/ZABBIX_AGENT_ROLE.md109
-rw-r--r--ansible_collections/community/zabbix/docs/ZABBIX_JAVAGATEWAY_ROLE.md51
-rw-r--r--ansible_collections/community/zabbix/docs/ZABBIX_PROXY_ROLE.md278
-rw-r--r--ansible_collections/community/zabbix/docs/ZABBIX_SERVER_ROLE.md241
-rw-r--r--ansible_collections/community/zabbix/docs/ZABBIX_WEB_ROLE.md141
-rw-r--r--ansible_collections/community/zabbix/meta/runtime.yml9
-rw-r--r--ansible_collections/community/zabbix/molecule/requirements.txt12
-rw-r--r--ansible_collections/community/zabbix/molecule/zabbix_agent_tests/common/molecule.yml17
-rw-r--r--ansible_collections/community/zabbix/molecule/zabbix_agent_tests/common/playbooks/prepare.yml18
-rw-r--r--ansible_collections/community/zabbix/molecule/zabbix_agent_tests/common/tests/common/test_agent.py20
-rw-r--r--ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/agent2/tests/common/test_agent.py20
-rw-r--r--ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/agent2autopsk/tests/common/test_agent.py20
-rw-r--r--ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/autopsk/tests/common/test_agent.py20
-rw-r--r--ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/default/tests/common/test_agent.py20
-rw-r--r--ansible_collections/community/zabbix/molecule/zabbix_javagateway/molecule.yml26
-rw-r--r--ansible_collections/community/zabbix/molecule/zabbix_javagateway/prepare.yml16
-rw-r--r--ansible_collections/community/zabbix/molecule/zabbix_proxy/molecule.yml33
-rw-r--r--ansible_collections/community/zabbix/molecule/zabbix_proxy/prepare.yml41
-rw-r--r--ansible_collections/community/zabbix/molecule/zabbix_proxy/tests/test_default.py26
-rw-r--r--ansible_collections/community/zabbix/molecule/zabbix_server/molecule.yml35
-rw-r--r--ansible_collections/community/zabbix/molecule/zabbix_server/prepare.yml24
-rw-r--r--ansible_collections/community/zabbix/molecule/zabbix_server/tests/test_default.py26
-rw-r--r--ansible_collections/community/zabbix/molecule/zabbix_web/molecule.yml73
-rw-r--r--ansible_collections/community/zabbix/molecule/zabbix_web/prepare.yml100
-rw-r--r--ansible_collections/community/zabbix/molecule/zabbix_web/tests/test_default.py31
-rw-r--r--ansible_collections/community/zabbix/plugins/doc_fragments/connection_persistent.py59
-rw-r--r--ansible_collections/community/zabbix/plugins/doc_fragments/zabbix.py43
-rw-r--r--ansible_collections/community/zabbix/plugins/httpapi/zabbix.py11
-rw-r--r--ansible_collections/community/zabbix/plugins/inventory/zabbix_inventory.py154
-rw-r--r--ansible_collections/community/zabbix/plugins/module_utils/api_request.py2
-rw-r--r--ansible_collections/community/zabbix/plugins/module_utils/base.py17
-rw-r--r--ansible_collections/community/zabbix/plugins/module_utils/helpers.py35
-rw-r--r--ansible_collections/community/zabbix/plugins/module_utils/wrappers.py84
-rw-r--r--ansible_collections/community/zabbix/plugins/modules/zabbix_action.py1576
-rw-r--r--ansible_collections/community/zabbix/plugins/modules/zabbix_api_info.py108
-rw-r--r--ansible_collections/community/zabbix/plugins/modules/zabbix_authentication.py570
-rw-r--r--ansible_collections/community/zabbix/plugins/modules/zabbix_autoregister.py86
-rw-r--r--ansible_collections/community/zabbix/plugins/modules/zabbix_discovery_rule.py445
-rw-r--r--ansible_collections/community/zabbix/plugins/modules/zabbix_globalmacro.py151
-rw-r--r--ansible_collections/community/zabbix/plugins/modules/zabbix_group.py34
-rw-r--r--ansible_collections/community/zabbix/plugins/modules/zabbix_group_events_info.py283
-rw-r--r--ansible_collections/community/zabbix/plugins/modules/zabbix_group_facts.py115
-rw-r--r--ansible_collections/community/zabbix/plugins/modules/zabbix_group_info.py39
-rw-r--r--ansible_collections/community/zabbix/plugins/modules/zabbix_host.py748
-rw-r--r--ansible_collections/community/zabbix/plugins/modules/zabbix_host_events_info.py100
-rw-r--r--ansible_collections/community/zabbix/plugins/modules/zabbix_host_facts.py239
-rw-r--r--ansible_collections/community/zabbix/plugins/modules/zabbix_host_info.py106
-rw-r--r--ansible_collections/community/zabbix/plugins/modules/zabbix_hostmacro.py137
-rw-r--r--ansible_collections/community/zabbix/plugins/modules/zabbix_housekeeping.py187
-rw-r--r--ansible_collections/community/zabbix/plugins/modules/zabbix_maintenance.py239
-rw-r--r--ansible_collections/community/zabbix/plugins/modules/zabbix_map.py357
-rw-r--r--ansible_collections/community/zabbix/plugins/modules/zabbix_mediatype.py506
-rw-r--r--ansible_collections/community/zabbix/plugins/modules/zabbix_proxy.py241
-rw-r--r--ansible_collections/community/zabbix/plugins/modules/zabbix_proxy_info.py47
-rw-r--r--ansible_collections/community/zabbix/plugins/modules/zabbix_regexp.py345
-rw-r--r--ansible_collections/community/zabbix/plugins/modules/zabbix_screen.py496
-rw-r--r--ansible_collections/community/zabbix/plugins/modules/zabbix_script.py316
-rw-r--r--ansible_collections/community/zabbix/plugins/modules/zabbix_service.py566
-rw-r--r--ansible_collections/community/zabbix/plugins/modules/zabbix_settings.py1112
-rw-r--r--ansible_collections/community/zabbix/plugins/modules/zabbix_template.py511
-rw-r--r--ansible_collections/community/zabbix/plugins/modules/zabbix_template_info.py187
-rw-r--r--ansible_collections/community/zabbix/plugins/modules/zabbix_templategroup.py180
-rw-r--r--ansible_collections/community/zabbix/plugins/modules/zabbix_token.py288
-rw-r--r--ansible_collections/community/zabbix/plugins/modules/zabbix_user.py799
-rw-r--r--ansible_collections/community/zabbix/plugins/modules/zabbix_user_directory.py444
-rw-r--r--ansible_collections/community/zabbix/plugins/modules/zabbix_user_info.py48
-rw-r--r--ansible_collections/community/zabbix/plugins/modules/zabbix_user_role.py63
-rw-r--r--ansible_collections/community/zabbix/plugins/modules/zabbix_usergroup.py456
-rw-r--r--ansible_collections/community/zabbix/plugins/modules/zabbix_valuemap.py99
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_agent/README.md109
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_agent/defaults/main.yml74
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_agent/handlers/main.yml14
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_agent/molecule/with-server/molecule.yml8
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_agent/molecule/with-server/playbook.yml4
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_agent/molecule/with-server/prepare.yml26
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Darwin.yml177
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Debian.yml237
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Docker.yml5
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Linux.yml93
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_agent/tasks/RedHat.yml124
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Suse.yml55
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Windows.yml118
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Windows_conf.yml25
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_agent/tasks/api.yml12
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_agent/tasks/firewall.yml55
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_agent/tasks/macOS.yml8
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_agent/tasks/main.yml125
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_agent/tasks/remove.yml10
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_agent/tasks/selinux.yml48
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto.yml12
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_agent2.yml8
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_agent2_common.yml29
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_agent2_linux.yml32
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_agent2_windows.yml30
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_common.yml21
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_linux.yml32
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_windows.yml30
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_agent/tasks/userparameter.yml146
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_agent/templates/zabbix_agent2.conf.j217
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_agent/templates/zabbix_agentd.conf.j225
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_agent/vars/Darwin.yml6
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_agent/vars/Debian.yml34
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_agent/vars/RedHat.yml9
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_agent/vars/Sangoma.yml7
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_agent/vars/Suse.yml7
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_agent/vars/Windows.yml5
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_agent/vars/zabbix.yml285
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_javagateway/README.md51
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_javagateway/defaults/main.yml11
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_javagateway/handlers/main.yml4
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_javagateway/tasks/Debian.yml129
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_javagateway/tasks/RedHat.yml15
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_javagateway/tasks/main.yml57
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_javagateway/templates/zabbix_java_gateway.conf.j22
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_javagateway/vars/Debian.yml34
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_javagateway/vars/RedHat.yml18
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_javagateway/vars/zabbix.yml258
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_proxy/README.md278
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_proxy/defaults/main.yml237
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_proxy/handlers/main.yml15
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/Debian.yml266
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/RedHat.yml354
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/main.yml142
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/mysql.yml86
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/postgresql.yml50
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/selinux.yml52
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/sqlite3.yml52
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_proxy/templates/zabbix_proxy.conf.j2305
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_proxy/vars/Amazon.yml2
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_proxy/vars/Debian.yml53
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_proxy/vars/RedHat.yml51
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_proxy/vars/main.yml5
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_proxy/vars/zabbix.yml255
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_server/README.md241
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_server/defaults/main.yml196
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_server/handlers/main.yml15
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_server/tasks/Debian.yml321
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_server/tasks/RedHat.yml300
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_server/tasks/main.yml66
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_server/tasks/mysql.yml196
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_server/tasks/postgresql.yml130
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_server/tasks/scripts.yml18
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_server/tasks/selinux.yml55
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_server/templates/zabbix_server.conf.j2373
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_server/vars/Debian.yml23
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_server/vars/RedHat.yml28
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_server/vars/zabbix.yml261
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_web/README.md141
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_web/defaults/main.yml148
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_web/handlers/main.yml30
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_web/tasks/Debian.yml208
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_web/tasks/RedHat.yml172
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_web/tasks/access.yml32
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_web/tasks/apache.yml84
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_web/tasks/apache_Debian.yml54
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_web/tasks/apache_RedHat.yml17
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_web/tasks/main.yml126
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_web/tasks/nginx.yml186
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_web/tasks/php_Debian.yml43
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_web/tasks/selinux.yml20
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_web/templates/apache_vhost.conf.j288
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_web/templates/nginx_vhost.conf.j2112
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_web/templates/php-fpm.conf.j218
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_web/templates/zabbix.conf.php.j22
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_web/vars/Debian-10.yml3
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_web/vars/Debian-11.yml3
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_web/vars/Debian-8.yml3
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_web/vars/Debian-9.yml3
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_web/vars/Debian.yml30
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_web/vars/RedHat-7.yml8
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_web/vars/RedHat-8.yml8
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_web/vars/RedHat-9.yml8
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_web/vars/RedHat.yml34
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_web/vars/Ubuntu-18.yml3
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_web/vars/Ubuntu-20.yml3
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_web/vars/Ubuntu-22.yml3
-rw-r--r--ansible_collections/community/zabbix/roles/zabbix_web/vars/zabbix.yml258
-rw-r--r--ansible_collections/community/zabbix/scripts/inventory/zabbix.ini10
-rw-r--r--ansible_collections/community/zabbix/scripts/inventory/zabbix.py215
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/setup_zabbix/tasks/main.yml10
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_action/tasks/main.yml1988
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_api_info/meta/main.yml (renamed from ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_screen/meta/main.yml)0
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_api_info/tasks/main.yml9
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_authentication/tasks/main.yml12
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_authentication/tasks/zabbix_authentication_tests.yml223
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_autoregister/tasks/main.yml193
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_discovery_rule/tasks/main.yml483
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_globalmacro/tasks/main.yml63
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_group/tasks/main.yml30
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_group_events_info/files/trigger_testing.json48
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_group_events_info/meta/main.yml3
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_group_events_info/tasks/main.yml58
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_group_info/tasks/main.yml12
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/tasks/main.yml14
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/tasks/zabbix_host_doc.yml14
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/tasks/zabbix_host_setup.yml6
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/tasks/zabbix_host_teardown.yml4
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/tasks/zabbix_host_tests.yml1105
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host_info/tasks/main.yml93
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_hostmacro/tasks/main.yml68
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_housekeeping/tasks/main.yml163
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_maintenance/tasks/main.yml76
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_mediatype/tasks/main.yml824
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_module_defaults_group/tasks/main.yml12
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_proxy/tasks/main.yml134
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_proxy_info/tasks/main.yml32
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_regexp/meta/main.yml3
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_regexp/tasks/main.yml113
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_screen/tasks/main.yml149
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_script/tasks/main.yml976
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_service/tasks/main.yml488
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_settings/meta/main.yml3
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_settings/tasks/main.yml332
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/files/template2_50_lower.xml53
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/tasks/import_54_higher.yml126
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/tasks/import_54_lower.yml120
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/tasks/main.yml362
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template_info/tasks/main.yml40
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_templategroup/meta/main.yml3
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_templategroup/tasks/main.yml59
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_token/meta/main.yml3
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_token/tasks/main.yml99
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user/tasks/for_zabbix_50_lower.yml1044
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user/tasks/for_zabbix_54_higher.yml1100
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user/tasks/main.yml1090
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_directory/tasks/main.yml10
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_directory/tasks/zabbix_user_directory_tests.yml826
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_info/tasks/main.yml242
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_role/tasks/main.yml181
-rw-r--r--ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_usergroup/tasks/main.yml503
-rw-r--r--ansible_collections/community/zabbix/tests/sanity/ignore-2.10.txt34
-rw-r--r--ansible_collections/community/zabbix/tests/sanity/ignore-2.11.txt34
-rw-r--r--ansible_collections/community/zabbix/tests/sanity/ignore-2.12.txt26
-rw-r--r--ansible_collections/community/zabbix/tests/sanity/ignore-2.13.txt26
-rw-r--r--ansible_collections/community/zabbix/tests/sanity/ignore-2.14.txt26
-rw-r--r--ansible_collections/community/zabbix/tests/sanity/ignore-2.15.txt26
-rw-r--r--ansible_collections/community/zabbix/tests/sanity/ignore-2.9.txt30
4129 files changed, 184874 insertions, 205872 deletions
diff --git a/ansible_collections/community/aws/.github/workflows/all_green_ckeck.yml b/ansible_collections/community/aws/.github/workflows/all_green_ckeck.yml
new file mode 100644
index 000000000..daa3e8bdf
--- /dev/null
+++ b/ansible_collections/community/aws/.github/workflows/all_green_ckeck.yml
@@ -0,0 +1,42 @@
+---
+name: all_green
+
+concurrency:
+ group: ${{ github.head_ref }}
+ cancel-in-progress: true
+
+on: # yamllint disable-line rule:truthy
+ pull_request:
+ types:
+ - opened
+ - reopened
+ - labeled
+ - unlabeled
+ - synchronize
+ branches:
+ - main
+ - 'stable-*'
+ tags:
+ - '*'
+
+jobs:
+ changelog-and-linters:
+ uses: ./.github/workflows/changelog_and_linters.yml # use the callable changelog_and_linters job to run tests
+ sanity:
+ uses: ./.github/workflows/sanity.yml # use the callable sanity job to run tests
+ units:
+ uses: ./.github/workflows/units.yml # use the callable units job to run tests
+ all_green:
+ if: ${{ always() }}
+ needs:
+ - changelog-and-linters
+ - sanity
+ - units
+ runs-on: ubuntu-latest
+ steps:
+ - run: >-
+ python -c "assert set([
+ '${{ needs.changelog-and-linters.result }}',
+ '${{ needs.sanity.result }}',
+ '${{ needs.units.result }}'
+ ]) == {'success'}"
diff --git a/ansible_collections/community/aws/.github/workflows/changelog_and_linters.yml b/ansible_collections/community/aws/.github/workflows/changelog_and_linters.yml
new file mode 100644
index 000000000..4029505d0
--- /dev/null
+++ b/ansible_collections/community/aws/.github/workflows/changelog_and_linters.yml
@@ -0,0 +1,13 @@
+---
+name: changelog and linters
+
+on: [workflow_call] # allow this workflow to be called from other workflows
+
+jobs:
+ changelog:
+ uses: ansible-network/github_actions/.github/workflows/changelog.yml@main
+ linters:
+ uses: ansible-network/github_actions/.github/workflows/tox.yml@main
+ with:
+ envname: ""
+ labelname: "lint"
diff --git a/ansible_collections/community/aws/.github/workflows/galaxy-importer.yml b/ansible_collections/community/aws/.github/workflows/galaxy-importer.yml
new file mode 100644
index 000000000..721f7476e
--- /dev/null
+++ b/ansible_collections/community/aws/.github/workflows/galaxy-importer.yml
@@ -0,0 +1,12 @@
+name: Galaxy Importer
+on:
+ push:
+ branches:
+ - main
+ - stable-*
+ pull_request:
+ schedule:
+ - cron: '0 13 * * *'
+jobs:
+ importer:
+ uses: ansible-network/github_actions/.github/workflows/galaxy_importer.yml@main
diff --git a/ansible_collections/community/aws/.github/workflows/release-manual.yml b/ansible_collections/community/aws/.github/workflows/release-manual.yml
new file mode 100644
index 000000000..19f6dc8d6
--- /dev/null
+++ b/ansible_collections/community/aws/.github/workflows/release-manual.yml
@@ -0,0 +1,35 @@
+name: Generate GitHub Release (manual trigger)
+concurrency:
+ group: release-${{ github.head_ref }}
+ cancel-in-progress: true
+on:
+ workflow_dispatch:
+ inputs:
+ release:
+ required: true
+ description: 'Release to generate'
+ type: string
+
+jobs:
+ generate-release-log:
+ permissions:
+ contents: read
+ runs-on: ubuntu-latest
+ steps:
+ - name: Generate Release Log
+ uses: ansible-collections/amazon.aws/.github/actions/ansible_release_log@main
+ with:
+ release: ${{ inputs.release }}
+
+ perform-release:
+ permissions:
+ contents: write
+ runs-on: ubuntu-latest
+ needs:
+ - generate-release-log
+ steps:
+ - name: Generate Release
+ uses: ansible-collections/amazon.aws/.github/actions/ansible_release_tag@main
+ with:
+ release: ${{ inputs.release }}
+ collection-name: community.aws
diff --git a/ansible_collections/community/aws/.github/workflows/release-tag.yml b/ansible_collections/community/aws/.github/workflows/release-tag.yml
new file mode 100644
index 000000000..cfb6c2838
--- /dev/null
+++ b/ansible_collections/community/aws/.github/workflows/release-tag.yml
@@ -0,0 +1,32 @@
+name: Generate GitHub Release
+concurrency:
+ group: release-${{ github.head_ref }}
+ cancel-in-progress: true
+on:
+ push:
+ tags:
+ - '*'
+
+jobs:
+ generate-release-log:
+ permissions:
+ contents: read
+ runs-on: ubuntu-latest
+ steps:
+ - name: Generate Release Log
+ uses: ansible-collections/amazon.aws/.github/actions/ansible_release_log@main
+ with:
+ release: ${{ github.ref_name }}
+
+ perform-release:
+ permissions:
+ contents: write
+ runs-on: ubuntu-latest
+ needs:
+ - generate-release-log
+ steps:
+ - name: Generate Release
+ uses: ansible-collections/amazon.aws/.github/actions/ansible_release_tag@main
+ with:
+ release: ${{ github.ref_name }}
+ collection-name: community.aws
diff --git a/ansible_collections/community/aws/.github/workflows/sanity.yml b/ansible_collections/community/aws/.github/workflows/sanity.yml
new file mode 100644
index 000000000..161dabfe2
--- /dev/null
+++ b/ansible_collections/community/aws/.github/workflows/sanity.yml
@@ -0,0 +1,10 @@
+---
+name: sanity tests
+
+on: [workflow_call] # allow this workflow to be called from other workflows
+
+jobs:
+ sanity:
+ uses: ansible-network/github_actions/.github/workflows/sanity.yml@main
+ with:
+ matrix_include: "[]"
diff --git a/ansible_collections/community/aws/.github/workflows/units.yml b/ansible_collections/community/aws/.github/workflows/units.yml
new file mode 100644
index 000000000..7dddcc610
--- /dev/null
+++ b/ansible_collections/community/aws/.github/workflows/units.yml
@@ -0,0 +1,10 @@
+---
+name: unit tests
+
+on: [workflow_call] # allow this workflow to be called from other workflows
+
+jobs:
+ unit-source:
+ uses: ansible-network/github_actions/.github/workflows/unit_source.yml@main
+ with:
+ collection_pre_install: '-r source/tests/unit/requirements.yml'
diff --git a/ansible_collections/community/aws/.github/workflows/update-variables.yml b/ansible_collections/community/aws/.github/workflows/update-variables.yml
new file mode 100644
index 000000000..f92f77cc6
--- /dev/null
+++ b/ansible_collections/community/aws/.github/workflows/update-variables.yml
@@ -0,0 +1,17 @@
+---
+name: update collection variables
+
+concurrency:
+ group: '${{ github.workflow }} @ ${{ github.sha }}'
+ cancel-in-progress: true
+
+on:
+ push:
+ branches:
+ - main
+ - 'stable-*'
+ pull_request_target:
+
+jobs:
+ update-variables:
+ uses: ansible-network/github_actions/.github/workflows/update_aws_variables.yml@main
diff --git a/ansible_collections/community/aws/.gitignore b/ansible_collections/community/aws/.gitignore
index 3b4462815..ed1c302f0 100644
--- a/ansible_collections/community/aws/.gitignore
+++ b/ansible_collections/community/aws/.gitignore
@@ -1,7 +1,7 @@
# Created by https://www.gitignore.io/api/git,linux,pydev,python,windows,pycharm+all,jupyternotebook,vim,webstorm,emacs,dotenv
# Edit at https://www.gitignore.io/?templates=git,linux,pydev,python,windows,pycharm+all,jupyternotebook,vim,webstorm,emacs,dotenv
-
+tests/integration/inventory
### dotenv ###
.env
diff --git a/ansible_collections/community/aws/.yamllint b/ansible_collections/community/aws/.yamllint
new file mode 100644
index 000000000..ac5297cdf
--- /dev/null
+++ b/ansible_collections/community/aws/.yamllint
@@ -0,0 +1,15 @@
+---
+rules:
+ indentation:
+ ignore: &default_ignores |
+ # automatically generated, we can't control it
+ changelogs/changelog.yaml
+ # Will be gone when we release and automatically reformatted
+ changelogs/fragments/*
+ document-start:
+ ignore: *default_ignores
+ line-length:
+ ignore: *default_ignores
+ max: 160
+
+ignore-from-file: .gitignore
diff --git a/ansible_collections/community/aws/CHANGELOG.rst b/ansible_collections/community/aws/CHANGELOG.rst
index 7b5761863..651b7c763 100644
--- a/ansible_collections/community/aws/CHANGELOG.rst
+++ b/ansible_collections/community/aws/CHANGELOG.rst
@@ -5,6 +5,200 @@ community.aws Release Notes
.. contents:: Topics
+v7.1.0
+======
+
+Release Summary
+---------------
+
+This release includes new features for the ``cloudfront_distribution`` and ``mq_broker`` modules, as well as a bugfix for the ``aws_ssm`` connection plugin needed when connecting to hosts with Bash 5.1.0 and later.
+
+Minor Changes
+-------------
+
+- aws_ssm - Updated the documentation to explicitly state that an S3 bucket is required, the behavior of the files in that bucket, and requirements around that. (https://github.com/ansible-collections/community.aws/issues/1775).
+- cloudfront_distribution - added support for ``cache_policy_id`` and ``origin_request_policy_id`` for behaviors (https://github.com/ansible-collections/community.aws/pull/1589)
+- mq_broker - add support to wait for broker state via ``wait`` and ``wait_timeout`` parameter values (https://github.com/ansible-collections/community.aws/pull/1879).
+
+Bugfixes
+--------
+
+- aws_ssm - disable `enable-bracketed-paste` to fix issue with amazon linux 2023 and other OSes (https://github.com/ansible-collections/community.aws/issues/1756)
+
+v7.0.0
+======
+
+Release Summary
+---------------
+
+This release includes some new features, bugfixes and breaking changes. Several modules have been migrated to amazon.aws and the Fully Qualified Collection Name for these modules needs to be updated. The community.aws collection has dropped support for ``botocore<1.29.0`` and ``boto3<1.26.0``. Due to the AWS SDKs announcing the end of support for Python less than 3.7 (https://aws.amazon.com/blogs/developer/python-support-policy-updates-for-aws-sdks-and-tools/), support for Python less than 3.7 by this collection was deprecated in release 6.0.0 and removed in release 7.0.0. (https://github.com/ansible-collections/amazon.aws/pull/1763).
+
+Minor Changes
+-------------
+
+- api_gateway - use fstrings where appropriate (https://github.com/ansible-collections/amazon.aws/pull/1962).
+- api_gateway_info - use fstrings where appropriate (https://github.com/ansible-collections/amazon.aws/pull/1962).
+- community.aws collection - apply isort code formatting to ensure consistent formatting of code (https://github.com/ansible-collections/community.aws/pull/1962)
+- ecs_taskdefinition - Add parameter ``runtime_platform`` (https://github.com/ansible-collections/community.aws/issues/1891).
+- eks_nodegroup - ensure wait also waits for deletion to complete when ``wait==True`` (https://github.com/ansible-collections/community.aws/pull/1994).
+
+Breaking Changes / Porting Guide
+--------------------------------
+
+- The community.aws collection has dropped support for ``botocore<1.29.0`` and ``boto3<1.26.0``. Most modules will continue to work with older versions of the AWS SDK, however compatability with older versions of the SDK is not guaranteed and will not be tested. When using older versions of the SDK a warning will be emitted by Ansible (https://github.com/ansible-collections/amazon.aws/pull/1763).
+- aws_region_info - The module has been migrated from the ``community.aws`` collection. Playbooks using the Fully Qualified Collection Name for this module should be updated to use ``amazon.aws.aws_region_info``.
+- aws_s3_bucket_info - The module has been migrated from the ``community.aws`` collection. Playbooks using the Fully Qualified Collection Name for this module should be updated to use ``amazon.aws.aws_s3_bucket_info``.
+- community.aws collection - due to the AWS SDKs announcing the end of support for Python less than 3.7 (https://aws.amazon.com/blogs/developer/python-support-policy-updates-for-aws-sdks-and-tools/) support for Python less than 3.7 by this collection wss been deprecated in release 6.0.0 and removed in release 7.0.0. (https://github.com/ansible-collections/amazon.aws/pull/1763).
+- iam_access_key - The module has been migrated from the ``community.aws`` collection. Playbooks using the Fully Qualified Collection Name for this module should be updated to use ``amazon.aws.iam_access_key``.
+- iam_access_key_info - The module has been migrated from the ``community.aws`` collection. Playbooks using the Fully Qualified Collection Name for this module should be updated to use ``amazon.aws.iam_access_key_info``.
+- iam_group - The module has been migrated from the ``community.aws`` collection. Playbooks using the Fully Qualified Collection Name for this module should be updated to use ``amazon.aws.iam_group`` (https://github.com/ansible-collections/community.aws/pull/1945).
+- iam_managed_policy - The module has been migrated from the ``community.aws`` collection. Playbooks using the Fully Qualified Collection Name for this module should be updated to use ``amazon.aws.iam_managed_policy`` (https://github.com/ansible-collections/community.aws/pull/1954).
+- iam_mfa_device_info - The module has been migrated from the ``community.aws`` collection. Playbooks using the Fully Qualified Collection Name for this module should be updated to use ``amazon.aws.iam_mfa_device_info`` (https://github.com/ansible-collections/community.aws/pull/1953).
+- iam_password_policy - The module has been migrated from the ``community.aws`` collection. Playbooks using the Fully Qualified Collection Name for this module should be updated to use ``amazon.aws.iam_password_policy``.
+- iam_role - The module has been migrated from the ``community.aws`` collection. Playbooks using the Fully Qualified Collection Name for this module should be updated to use ``amazon.aws.iam_role`` (https://github.com/ansible-collections/community.aws/pull/1948).
+- iam_role_info - The module has been migrated from the ``community.aws`` collection. Playbooks using the Fully Qualified Collection Name for this module should be updated to use ``amazon.aws.iam_role_info`` (https://github.com/ansible-collections/community.aws/pull/1948).
+- s3_bucket_info - The module has been migrated from the ``community.aws`` collection. Playbooks using the Fully Qualified Collection Name for this module should be updated to use ``amazon.aws.s3_bucket_info``.
+- sts_assume_role - The module has been migrated from the ``community.aws`` collection. Playbooks using the Fully Qualified Collection Name for this module should be updated to use ``amazon.aws.sts_assume_role``.
+
+Bugfixes
+--------
+
+- mq_broker - ensure broker is created with ``tags`` when passed (https://github.com/ansible-collections/community.aws/issues/1832).
+- opensearch - Don't try to read a non existing key from the domain config (https://github.com/ansible-collections/community.aws/pull/1910).
+
+v6.2.0
+======
+
+Release Summary
+---------------
+
+This release includes some new features for the ``community.aws.ec2_vpc_vpn`` and ``community.aws.api_gateway`` modules.
+
+Minor Changes
+-------------
+
+- api_gateway - add support for parameters ``name``, ``lookup``, ``tags`` and ``purge_tags`` (https://github.com/ansible-collections/community.aws/pull/1845).
+- ec2_vpc_vpn - add support for connecting VPNs to a transit gateway (https://github.com/ansible-collections/community.aws/pull/1877).
+
+Bugfixes
+--------
+
+- Remove ``apigateway`` and ``apigateway_deployment`` from meta/runtime.yml (https://github.com/ansible-collections/community.aws/pull/1905).
+
+v6.1.0
+======
+
+Release Summary
+---------------
+
+This release brings a new inventory plugin, some new features, and several bugfixes.
+
+Minor Changes
+-------------
+
+- dynamodb_table - added waiter when updating indexes to avoid concurrency issues (https://github.com/ansible-collections/community.aws/pull/1866).
+- dynamodb_table - increased default timeout based on time to update indexes in CI (https://github.com/ansible-collections/community.aws/pull/1866).
+- iam_group - refactored ARN validation handling (https://github.com/ansible-collections/community.aws/pull/1848).
+- iam_role - refactored ARN validation handling (https://github.com/ansible-collections/community.aws/pull/1848).
+- sns_topic - refactored ARN validation handling (https://github.com/ansible-collections/community.aws/pull/1848).
+
+Bugfixes
+--------
+
+- batch_compute_environment - fixed incorrect handling of Gov Cloud ARNs in ``compute_environment_name`` parameter (https://github.com/ansible-collections/community.aws/issues/1846).
+- cloudfront_distribution - The origins recognises the s3 domains with region part now (https://github.com/ansible-collections/community.aws/issues/1819).
+- cloudfront_distribution - no longer crashes when waiting for completion of creation (https://github.com/ansible-collections/community.aws/issues/255).
+- cloudfront_distribution - now honours the ``enabled`` setting (https://github.com/ansible-collections/community.aws/issues/1823).
+- dynamodb_table - secondary indexes are now created (https://github.com/ansible-collections/community.aws/issues/1825).
+- ec2_launch_template - fixed incorrect handling of Gov Cloud ARNs in ``compute_environment_name`` parameter (https://github.com/ansible-collections/community.aws/issues/1846).
+- elasticache_info - remove hard coded use of ``aws`` partition (https://github.com/ansible-collections/community.aws/issues/1846).
+- iam_role - fixed incorrect rejection of Gov Cloud ARNs in ``boundary`` parameter (https://github.com/ansible-collections/community.aws/issues/1846).
+- msk_cluster - remove hard coded use of ``aws`` partition (https://github.com/ansible-collections/community.aws/issues/1846).
+- redshift - fixed hard coded use of ``aws`` partition (https://github.com/ansible-collections/community.aws/issues/1846).
+
+New Plugins
+-----------
+
+Inventory
+~~~~~~~~~
+
+- aws_mq - MQ broker inventory source
+
+v6.0.0
+======
+
+Release Summary
+---------------
+
+This release brings some new plugins and features. Several bugfixes, breaking changes and deprecated features are also included.
+The community.aws collection has dropped support for ``botocore<1.25.0`` and ``boto3<1.22.0``.
+Support for Python 3.6 has also been dropped.
+
+
+Minor Changes
+-------------
+
+- The ``black`` code formatter has been run across the collection to improve code consistency (https://github.com/ansible-collections/community.aws/pull/1784).
+- aws_config_delivery_channel - add support for encrypted objects in S3 via KMS key (https://github.com/ansible-collections/community.aws/pull/1786).
+- aws_ssm - Updated the documentation to explicitly mention that the ``ansible_user`` and ``remote_user`` variables are not supported by the plugin (https://github.com/ansible-collections/community.aws/pull/1682).
+- bulk migration of ``%`` and ``.format()`` to fstrings (https://github.com/ansible-collections/community.aws/pull/1810).
+- cloudfront_distribution - add ``http3`` support via parameter value ``http2and3`` for parameter ``http_version`` (https://github.com/ansible-collections/community.aws/pull/1753).
+- cloudfront_distribution - add ``origin_shield`` options (https://github.com/ansible-collections/community.aws/pull/1557).
+- cloudfront_distribution - documented ``connection_attempts`` and ``connection_timeout`` the module was already capable of using them
+- community.aws - updated document fragments based on changes in amazon.aws (https://github.com/ansible-collections/community.aws/pull/1738).
+- community.aws - updated imports based on changes in amazon.aws (https://github.com/ansible-collections/community.aws/pull/1738).
+- ecs_ecr - use ``compare_policies`` when comparing lifecycle policies instead of naive ``sort_json_policy_dict`` comparisons (https://github.com/ansible-collections/community.aws/pull/1551).
+- elasticache - Use the ``cache.t3.small`` node type in the example. ``cache.m1.small`` is not deprecated.
+- minor code fixes and enable integration tests for modules cloudfront_distribution, cloudfront_invalidation and cloudfront_origin_access_identity (https://github.com/ansible-collections/community.aws/pull/1596).
+- module_utils.botocore - Add Ansible AWS User-Agent identification (https://github.com/ansible-collections/community.aws/pull/1632).
+- wafv2_rule_group_info - remove unused and deprecated ``state`` parameter (https://github.com/ansible-collections/community.aws/pull/1555).
+
+Breaking Changes / Porting Guide
+--------------------------------
+
+- The community.aws collection has dropped support for ``botocore<1.25.0`` and ``boto3<1.22.0``. Most modules will continue to work with older versions of the AWS SDK, however compatability with older versions of the SDK is not guaranteed and will not be tested. When using older versions of the SDK a warning will be emitted by Ansible (https://github.com/ansible-collections/community.aws/pull/1743).
+- aws_ssm - the AWS SSM plugin was incorrectly prepending ``sudo`` to most commands. This behaviour was incorrect and has been removed. To execute commands as a specific user, including the ``root`` user, the ``become`` and ``become_user`` directives should be used. See the `Ansible documentation for more information <https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_privilege_escalation.html>`_ (https://github.com/ansible-collections/community.aws/issues/853).
+- codebuild_project - ``tags`` parameter now accepts a dict representing the tags, rather than the boto3 format (https://github.com/ansible-collections/community.aws/pull/1643).
+
+Deprecated Features
+-------------------
+
+- community.aws collection - due to the AWS SDKs Python support policies (https://aws.amazon.com/blogs/developer/python-support-policy-updates-for-aws-sdks-and-tools/) support for Python less than 3.8 by this collection is expected to be removed in a release after 2024-12-01 (https://github.com/ansible-collections/community.aws/pull/1743).
+- community.aws collection - due to the AWS SDKs announcing the end of support for Python less than 3.7 (https://aws.amazon.com/blogs/developer/python-support-policy-updates-for-aws-sdks-and-tools/) support for Python less than 3.7 by this collection has been deprecated and will be removed in release 7.0.0. (https://github.com/ansible-collections/community.aws/pull/1743).
+
+Bugfixes
+--------
+
+- opensearch_info - Fix the name of the domain_name key in the example (https://github.com/ansible-collections/community.aws/pull/1811).
+- ses_identity - fix clearing notification topic (https://github.com/ansible-collections/community.aws/issues/150).
+
+New Modules
+-----------
+
+- ec2_carrier_gateway - Manage an AWS VPC Carrier gateway
+- ec2_carrier_gateway_info - Gather information about carrier gateways in AWS
+- lightsail_snapshot - Creates snapshots of AWS Lightsail instances
+- mq_broker - MQ broker management
+- mq_broker_config - Update Amazon MQ broker configuration
+- mq_broker_info - Retrieve MQ Broker details
+- mq_user - Manage users in existing Amazon MQ broker
+- mq_user_info - List users of an Amazon MQ broker
+- ssm_inventory_info - Get SSM inventory information for EC2 instance
+
+v5.5.1
+======
+
+Release Summary
+---------------
+
+This release brings several bugfixes.
+
+Bugfixes
+--------
+
+- cloudfront_distribution - no longer crashes when waiting for completion of creation (https://github.com/ansible-collections/community.aws/issues/255).
+- cloudfront_distribution - now honours the ``enabled`` setting (https://github.com/ansible-collections/community.aws/issues/1823).
+
v5.5.0
======
@@ -156,7 +350,7 @@ Bugfixes
--------
- aws_ssm - fixes S3 bucket region detection by ensuring boto client has correct credentials and exists in correct partition (https://github.com/ansible-collections/community.aws/pull/1428).
-- ec2_snapshot_copy - including tags caused the erorr "Tag specification resource type must have a value". Fix sets the ResourceType to snapshot to resolve this issue (https://github.com/ansible-collections/community.aws/pull/1419).
+- ec2_snapshot_copy - including tags caused the erorr ``Tag specification resource type must have a value``. Fix sets the ResourceType to snapshot to resolve this issue (https://github.com/ansible-collections/community.aws/pull/1419).
- ecs_ecr - fix a ``RepositoryNotFound`` exception when trying to create repositories in check mode (https://github.com/ansible-collections/community.aws/pull/1550).
- opensearch - Fix cluster creation when using advanced security options (https://github.com/ansible-collections/community.aws/pull/1613).
@@ -321,7 +515,7 @@ Bugfixes
- ec2_placement_group - Handle a potential race creation during the creation of a new Placement Group (https://github.com/ansible-collections/community.aws/pull/1477).
- elb_network_lb - fixes bug where ``ip_address_type`` in return value was not updated (https://github.com/ansible-collections/community.aws/pull/1365).
-- rds_cluster - fixes bug where specifiying an rds cluster parameter group raises a `KeyError` (https://github.com/ansible-collections/community.aws/pull/1417).
+- rds_cluster - fixes bug where specifiying an rds cluster parameter group raises a ``KeyError`` (https://github.com/ansible-collections/community.aws/pull/1417).
- s3_sync - fix etag generation when running in FIPS mode (https://github.com/ansible-collections/community.aws/issues/757).
New Modules
@@ -329,6 +523,91 @@ New Modules
- accessanalyzer_validate_policy_info - Performs validation of IAM policies
+v4.5.1
+======
+
+Release Summary
+---------------
+
+This release contains a minor bugfix for the ``sns_topic`` module as well as corrections to the documentation for various modules. This is the last planned release of the 4.x series.
+
+
+Bugfixes
+--------
+
+- sns_topic - avoid fetching attributes from subscribers when not setting them, this can cause permissions issues (https://github.com/ansible-collections/community.aws/pull/1418).
+
+v4.5.0
+======
+
+Release Summary
+---------------
+
+This is the minor release of the ``community.aws`` collection.
+
+Minor Changes
+-------------
+
+- ecs_service - support load balancer update for existing ecs services(https://github.com/ansible-collections/community.aws/pull/1625).
+- iam_role - Drop deprecation warning, because the standard value for purge parametes is ``true`` (https://github.com/ansible-collections/community.aws/pull/1636).
+
+Bugfixes
+--------
+
+- aws_ssm - fix ``invalid literal for int`` error on some operating systems (https://github.com/ansible-collections/community.aws/issues/113).
+- ecs_service - respect ``placement_constraints`` for existing ecs services (https://github.com/ansible-collections/community.aws/pull/1601).
+- s3_lifecycle - Module no longer calls ``put_lifecycle_configuration`` if there is no change. (https://github.com/ansible-collections/community.aws/issues/1624)
+- ssm_parameter - Fix a ``KeyError`` when adding a description to an existing parameter (https://github.com/ansible-collections/community.aws/issues/1471).
+
+v4.4.0
+======
+
+Release Summary
+---------------
+
+This is the minor release of the ``community.aws`` collection.
+This changelog contains all changes to the modules and plugins in this collection
+that have been made after the previous release.
+
+Minor Changes
+-------------
+
+- elasticache_parameter_group - add ``redis6.x`` group family on the module input choices (https://github.com/ansible-collections/community.aws/pull/1476).
+
+Bugfixes
+--------
+
+- aws_ssm - fixes S3 bucket region detection by ensuring boto client has correct credentials and exists in correct partition (https://github.com/ansible-collections/community.aws/pull/1428).
+- ecs_ecr - fix a ``RepositoryNotFound`` exception when trying to create repositories in check mode (https://github.com/ansible-collections/community.aws/pull/1550).
+- opensearch - Fix cluster creation when using advanced security options (https://github.com/ansible-collections/community.aws/pull/1613).
+
+v4.3.0
+======
+
+Release Summary
+---------------
+
+The community.aws 4.3.0 release includes a number of minor bug fixes and improvements.
+Following the release of amazon.aws 5.0.0, backports to the 4.x series will be limited to security issues and bugfixes.
+
+Minor Changes
+-------------
+
+- autoscaling_group_info - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+- cloudfront_distribution - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+- cloudfront_origin_access_identity - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+- cloudtrail - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+- ec2_vpc_nacl - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+- eks_fargate_profile - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+- redshift - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+- s3_bucket_info - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+
+Bugfixes
+--------
+
+- ec2_placement_group - Handle a potential race creation during the creation of a new Placement Group (https://github.com/ansible-collections/community.aws/pull/1477).
+- rds_cluster - fixes bug where specifiying an rds cluster parameter group raises a ``KeyError`` (https://github.com/ansible-collections/community.aws/pull/1417).
+
v4.2.0
======
@@ -385,7 +664,7 @@ Deprecated Features
- community.aws collection - due to the AWS SDKs announcing the end of support for Python less than 3.7 (https://aws.amazon.com/blogs/developer/python-support-policy-updates-for-aws-sdks-and-tools/) support for Python less than 3.7 by this collection has been deprecated and will be removed in a release after 2023-05-31 (https://github.com/ansible-collections/community.aws/pull/1361).
- iam_policy - the ``policies`` return value has been renamed ``policy_names`` and will be removed in a release after 2024-08-01, both values are currently returned (https://github.com/ansible-collections/community.aws/pull/1375).
- lambda_info - The ``function`` return key returns a dictionary of dictionaries and has been deprecated. In a release after 2025-01-01, this key will be removed in favor of ``functions``, which returns a list of dictionaries (https://github.com/ansible-collections/community.aws/pull/1239).
-- route53_info - The CamelCase return values for ``DelegationSets``, ``CheckerIpRanges``, and ``HealthCheck`` have been deprecated, in the future release you must use snake_case return values ``delegation_sets``, ``checker_ip_ranges``, and ``health_check`` instead respectively" (https://github.com/ansible-collections/community.aws/pull/1322).
+- route53_info - The CamelCase return values for ``DelegationSets``, ``CheckerIpRanges``, and ``HealthCheck`` have been deprecated, in the future release you must use snake_case return values ``delegation_sets``, ``checker_ip_ranges``, and ``health_check`` instead respectively (https://github.com/ansible-collections/community.aws/pull/1322).
Bugfixes
--------
@@ -548,7 +827,7 @@ Removed Features (previously deprecated)
----------------------------------------
- aws_kms_info - the unused and deprecated ``keys_attr`` parameter has been removed (https://github.com/ansible-collections/amazon.aws/pull/1172).
-- data_pipeline - the ``version`` option has always been ignored and has been removed (https://github.com/ansible-collections/community.aws/pull/1160"
+- data_pipeline - the ``version`` option has always been ignored and has been removed (https://github.com/ansible-collections/community.aws/pull/1160
- ec2_eip - The ``wait_timeout`` option has been removed. It has always been ignored by the module (https://github.com/ansible-collections/community.aws/pull/1159).
- ec2_lc - the ``associate_public_ip_address`` option has been removed. It has always been ignored by the module (https://github.com/ansible-collections/community.aws/pull/1158).
- ec2_metric_alarm - support for using the ``<=``, ``<``, ``>`` and ``>=`` operators for comparison has been dropped. Please use ``LessThanOrEqualToThreshold``, ``LessThanThreshold``, ``GreaterThanThreshold`` or ``GreaterThanOrEqualToThreshold`` instead (https://github.com/ansible-collections/amazon.aws/pull/1164).
@@ -602,6 +881,33 @@ New Modules
- opensearch_info - obtain information about one or more OpenSearch or ElasticSearch domain
- rds_cluster_snapshot - Manage Amazon RDS snapshots of DB clusters
+v3.6.0
+======
+
+Release Summary
+---------------
+
+Following the release of community.aws 5.0.0, 3.6.0 is a bugfix release and the final planned release for the 3.x series.
+
+
+Minor Changes
+-------------
+
+- autoscaling_group_info - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+- cloudfront_distribution - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+- cloudfront_origin_access_identity - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+- cloudtrail - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+- ec2_asg_lifecycle_hook - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+- ec2_vpc_nacl - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+- redshift - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+- s3_bucket_info - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+
+Bugfixes
+--------
+
+- ec2_placement_group - Handle a potential race creation during the creation of a new Placement Group (https://github.com/ansible-collections/community.aws/pull/1477).
+- s3_lifecycle - fix bug when deleting rules with an empty prefix (https://github.com/ansible-collections/community.aws/pull/1398).
+
v3.5.0
======
@@ -649,7 +955,7 @@ Deprecated Features
-------------------
- aws_codebuild - The ``tags`` parameter currently uses a non-standard format and has been deprecated. In release 6.0.0 this parameter will accept a simple key/value pair dictionary instead of the current list of dictionaries. It is recommended to migrate to using the resource_tags parameter which already accepts the simple dictionary format (https://github.com/ansible-collections/community.aws/pull/1221).
-- route53_info - The CamelCase return values for ``HostedZones``, ``ResourceRecordSets``, and ``HealthChecks`` have been deprecated, in the future release you must use snake_case return values ``hosted_zones``, ``resource_record_sets``, and ``health_checks`` instead respectively".
+- route53_info - The CamelCase return values for ``HostedZones``, ``ResourceRecordSets``, and ``HealthChecks`` have been deprecated, in the future release you must use snake_case return values ``hosted_zones``, ``resource_record_sets``, and ``health_checks`` instead respectively.
Bugfixes
--------
@@ -914,6 +1220,65 @@ Bugfixes
- aws_eks - Fix EKS cluster creation with short names (https://github.com/ansible-collections/community.aws/pull/818).
+v2.6.1
+======
+
+Release Summary
+---------------
+
+Bump collection from 2.6.0 to 2.6.1 due to a publishing error with 2.6.0. This release supersedes 2.6.0 entirely, users should skip 2.6.0.
+
+v2.6.0
+======
+
+Release Summary
+---------------
+
+This is the last planned 2.x release of the ``community.aws`` collection.
+Consider upgrading to the latest version of ``community.aws`` soon.
+
+Minor Changes
+-------------
+
+- ecs_service - ``deployment_circuit_breaker`` has been added as a supported feature (https://github.com/ansible-collections/community.aws/pull/1215).
+- ecs_service - add ``service`` alias to address the ecs service name with the same parameter as the ecs_service_info module is doing (https://github.com/ansible-collections/community.aws/pull/1187).
+- ecs_service_info - add ``name`` alias to address the ecs service name with the same parameter as the ecs_service module is doing (https://github.com/ansible-collections/community.aws/pull/1187).
+
+Bugfixes
+--------
+
+- ecs_service - fix broken change detect of ``health_check_grace_period_seconds`` parameter when not specified (https://github.com/ansible-collections/community.aws/pull/1212).
+- ecs_service - use default cluster name of ``default`` when not input (https://github.com/ansible-collections/community.aws/pull/1212).
+- ecs_task - dont require ``cluster`` and use name of ``default`` when not input (https://github.com/ansible-collections/community.aws/pull/1212).
+- wafv2_ip_set - fix bug where incorrect changed state was returned when only changing the description (https://github.com/ansible-collections/community.aws/pull/1211).
+
+v2.5.0
+======
+
+Release Summary
+---------------
+
+This is the minor release of the ``community.aws`` collection.
+
+Minor Changes
+-------------
+
+- iam_policy - update broken examples and add RETURN section to documentation; add extra integration tests for idempotency check mode runs (https://github.com/ansible-collections/community.aws/pull/1093).
+- iam_role - delete inline policies prior to deleting role (https://github.com/ansible-collections/community.aws/pull/1054).
+- iam_role - remove global vars and refactor accordingly (https://github.com/ansible-collections/community.aws/pull/1054).
+
+Bugfixes
+--------
+
+- ecs_service - add missing change detect of ``health_check_grace_period_seconds`` parameter (https://github.com/ansible-collections/community.aws/pull/1145).
+- ecs_service - fix broken compare of ``task_definition`` that results always in a changed task (https://github.com/ansible-collections/community.aws/pull/1145).
+- ecs_service - fix validation for ``placement_constraints``. It's possible to use ``distinctInstance`` placement constraint now (https://github.com/ansible-collections/community.aws/issues/1058)
+- ecs_taskdefinition - fix broken change detect of ``launch_type`` parameter (https://github.com/ansible-collections/community.aws/pull/1145).
+- execute_lambda - fix check mode and update RETURN documentation (https://github.com/ansible-collections/community.aws/pull/1115).
+- iam_policy - require one of ``policy_document`` and ``policy_json`` when state is present to prevent MalformedPolicyDocumentException from being thrown (https://github.com/ansible-collections/community.aws/pull/1093).
+- s3_lifecycle - add support of value *0* for ``transition_days`` (https://github.com/ansible-collections/community.aws/pull/1077).
+- s3_lifecycle - check that configuration is complete before returning (https://github.com/ansible-collections/community.aws/pull/1085).
+
v2.4.0
======
@@ -1534,7 +1899,7 @@ Bugfixes
- cloudfront_distribution - Always add field_level_encryption_id to cache behaviour to match AWS requirements
- cloudwatchlogs_log_group - Fix a KeyError when updating a log group that does not have a retention period (https://github.com/ansible/ansible/issues/47945)
- cloudwatchlogs_log_group_info - remove limitation of max 50 results
-- ec2_asg - Ensure "wait" is honored during replace operations
+- ec2_asg - Ensure ``wait`` is honored during replace operations
- ec2_launch_template - Update output to include latest_version and default_version, matching the documentation
- ec2_transit_gateway - Use AWSRetry before ClientError is handled when describing transit gateways
- ec2_transit_gateway - fixed issue where auto_attach set to yes was not being honored (https://github.com/ansible/ansible/issues/61907)
diff --git a/ansible_collections/community/aws/CONTRIBUTING.md b/ansible_collections/community/aws/CONTRIBUTING.md
index db74cf119..eb41c9274 100644
--- a/ansible_collections/community/aws/CONTRIBUTING.md
+++ b/ansible_collections/community/aws/CONTRIBUTING.md
@@ -1,15 +1,5 @@
# Contributing
-## Getting Started
-
-General information about setting up your Python environment, testing modules,
-Ansible coding styles, and more can be found in the [Ansible Community Guide](
-https://docs.ansible.com/ansible/latest/community/index.html).
-
-Information about boto library usage, module utils, testing, and more can be
-found in the [AWS Guidelines](https://docs.ansible.com/ansible/devel/dev_guide/platforms/aws_guidelines.html)
-documentation.
-
## AWS Collections
There are two related collections containing AWS content (modules and plugins).
@@ -18,7 +8,7 @@ There are two related collections containing AWS content (modules and plugins).
This collection contains the `module_utils` (shared libraries) used by both collections.
Content in this collection is included downstream in Red Hat Ansible Automation Platform.
-Code standards, test coverage, and other supportability criteria may be higher in this collection.
+Code standards, test coverage, and other supportability criteria may be higher in this collection.
### community.aws
This collection contains modules and plugins contributed and maintained by the Ansible AWS
@@ -30,19 +20,60 @@ Content in this collection that is stable and meets other acceptance criteria ha
to be promoted and migrated into `amazon.aws`.
## Submitting Issues
-All software has bugs, and the `community.aws` collection is no exception. When you find a bug,
+All software has bugs, and the `community.aws` collection is no exception. When you find a bug,
you can help tremendously by [telling us about it](https://github.com/ansible-collections/community.aws/issues/new/choose).
-If you should discover that the bug you're trying to file already exists in an issue,
-you can help by verifying the behavior of the reported bug with a comment in that
+If you should discover that the bug you're trying to file already exists in an issue,
+you can help by verifying the behavior of the reported bug with a comment in that
issue, or by reporting any additional information
-## Pull Requests
-
-All modules MUST have integration tests for new features. Upgrading to boto3 shall be considered a feature request.
-Bug fixes for modules that currently have integration tests SHOULD have tests added.
-New modules should be submitted to the [community.aws](https://github.com/ansible-collections/community.aws) collection
-and MUST have integration tests.
+## Writing New Code
+
+New modules should be submitted to the [community.aws](https://github.com/ansible-collections/community.aws) collection.
+
+For new features and bug fixes on existing modules,
+clone this repository and try to run unit tests and integration tests by following
+[these instructions](https://docs.ansible.com/ansible/latest/community/create_pr_quick_start.html).
+When you get to this part:
+
+```
+ansible-test integration name_of_test_subdirectory --docker -v
+```
+
+Run this from the `tests` directory of this repository.
+Substitute `name_of_test_subdirectory` for the name of the relevant directory within `tests/integration/targets`.
+You'll get this error:
+
+```
+WARNING: Excluding tests marked "cloud/aws" which require config
+(see "/home/dev/ansible/ansible/test/lib/ansible_test/config/cloud-config-aws.ini.template"): ec2_group
+```
+This is because the unit tests don't automatically detect the AWS credentials on your machine
+unlike plain `boto3` and the `aws` cli.
+(Typically because they're run inside Docker, which can't access `~/.aws/credentials`.
+But even when running tests outside docker, the tests ignore `~/.aws/credentials`.)
+You need to explicitly create credentials and load them in to an Ansible-specific file.
+To do this, copy the file mentioned in that error message,
+into the clone of this repo, under `tests/integration/cloud-config-aws.ini`.
+Modify the `@` variables, pasting in an IAM secret credential.
+If you don't need the `secret_token` (most IAM users don't), comment that line out.
+
+You can use an AWS account that already has unrelated resources in it.
+The tests should not touch pre-existing resources, and should tidy up after themselves.
+(Of course for security reasons you may want to run in a dedicated AWS account.)
+
+If you're only writing a pull request for one AWS service
+you are able to create credentials only with permissions required for that test.
+For example, to test the Lambda modules, you only need Lambda permissions,
+and permissions to create IAM roles.
+You could also deploy [the policies used by the CI](https://github.com/mattclay/aws-terminator/tree/master/aws/policy).
+
+All modules MUST have integration tests for new features.
+Bug fixes for modules that currently have integration tests SHOULD have tests added.
+
+Once you're able to run integration tests for the existing code,
+now start by adding tests in `tests/integration/targets`
+for your new feature or tests for the bug(s) you're about to fix.
Expected test criteria:
* Resource creation under check mode
@@ -60,22 +91,48 @@ Expected test criteria:
Where modules have multiple parameters we recommend running through the 4-step modification cycle for each parameter the module accepts, as well as a modification cycle where as most, if not all, parameters are modified at the same time.
-For general information on running the integration tests see the
-[Integration Tests page of the Module Development Guide](https://docs.ansible.com/ansible/devel/dev_guide/testing_integration.html#testing-integration),
-especially the section on configuration for cloud tests. For questions about writing tests the Ansible AWS community can be found on [libera.chat](https://libera.chat/) IRC as detailed below.
+After writing the tests, now write/modify the module code, typically in `plugins/modules`.
+Don't forget to add [a changelog entry](https://docs.ansible.com/ansible/latest/community/collection_development_process.html#collection-changelog-fragments).
+Then create a pull request.
+
+If you're struggling with running integration tests locally, don't worry.
+After creating a pull request the CI bot will automatically test for you.
+
+## More information about contributing
+
+General information about setting up your Python environment, testing modules,
+Ansible coding styles, and more can be found in the [Ansible Community Guide](
+https://docs.ansible.com/ansible/latest/community/index.html).
+
+Information about AWS SDK library usage, module utils, testing, and more can be
+found in the [AWS Guidelines](https://docs.ansible.com/ansible/devel/collections/amazon/aws/docsite/dev_guidelines.html#ansible-collections-amazon-aws-docsite-dev-guide-intro)
+documentation.
+
+For general information on running the integration tests see
+[this page](https://docs.ansible.com/ansible/latest/community/collection_contributors/test_index.html) and
+[Integration Tests page of the Module Development Guide](https://docs.ansible.com/ansible/devel/dev_guide/testing_integration.html#non-destructive-tests).
+Ignore the part about `source hacking/env-setup`. That's only applicable for working on `ansible-core`.
+You should be able to use the `ansible-test` that's installed with Ansible generally.
+Look at [the section on configuration for cloud tests](https://docs.ansible.com/ansible/devel/dev_guide/testing_integration.html#other-configuration-for-cloud-tests).
+For questions about writing tests the Ansible AWS community can
+be found on Libera.Chat IRC as detailed below.
-### Changelog Fragment
-Once a PR has been created, make sure to create a changelog [fragment](https://github.com/ansible-collections/community.aws/tree/main/changelogs/fragments).
+- [Ansible Community Guide](https://docs.ansible.com/ansible/latest/community/index.html) - Details on contributing to Ansible
+- [Contributing to Collections](https://docs.ansible.com/ansible/devel/dev_guide/developing_collections.html#contributing-to-collections) - How to check out collection git repositories correctly
+- [Contributing to Ansible-maintained collections](https://docs.ansible.com/ansible/devel/community/contributing_maintained_collections.html#contributing-maintained-collections)
+- [Guidelines for Ansible Amazon AWS module development](https://docs.ansible.com/ansible/latest/dev_guide/platforms/aws_guidelines.html)
+- [Getting Started With AWS Ansible Module Development and Community Contribution](https://www.ansible.com/blog/getting-started-with-aws-ansible-module-development)
-For more information on changelog fragments then refer to the guide found [here](https://docs.ansible.com/ansible/latest/community/development_process.html#changelogs).
### Code of Conduct
-The `community.aws` collection follows the Ansible project's
-[Code of Conduct](https://docs.ansible.com/ansible/devel/community/code_of_conduct.html).
+The `community.aws` collection follows the Ansible project's
+[Code of Conduct](https://docs.ansible.com/ansible/devel/community/code_of_conduct.html).
Please read and familiarize yourself with this document.
### IRC
-Our IRC channels may require you to register your nickname. If you receive an error when you connect, see [Libera.Chat's Nickname Registration guide](https://libera.chat/guides/registration) for instructions.
+Our IRC channels may require you to register your nickname. If you receive an error when you connect, see
+[Libera.Chat's Nickname Registration guide](https://libera.chat/guides/registration) for instructions.
-The `#ansible-aws` channel on [irc.libera.chat](https://libera.chat/) is the main and official place to discuss use and development of the `community.aws` collection.
+The `#ansible-aws` channel on [irc.libera.chat](https://libera.chat/) is the main and official place to discuss use and development
+of the `community.aws` collection.
diff --git a/ansible_collections/community/aws/FILES.json b/ansible_collections/community/aws/FILES.json
index 7b24063c0..6bc607963 100644
--- a/ansible_collections/community/aws/FILES.json
+++ b/ansible_collections/community/aws/FILES.json
@@ -64,6 +64,20 @@
"format": 1
},
{
+ "name": ".github/workflows/all_green_ckeck.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "dd88632dd1829b9ffa497fdc464a6ae0bad9a11dc474ec0da0f97b8598bd82a5",
+ "format": 1
+ },
+ {
+ "name": ".github/workflows/changelog_and_linters.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "466994abfa3234b3feb307742125dbe26f929c9762461706c907e4cdc8c0a424",
+ "format": 1
+ },
+ {
"name": ".github/workflows/docs-pr.yml",
"ftype": "file",
"chksum_type": "sha256",
@@ -78,6 +92,48 @@
"format": 1
},
{
+ "name": ".github/workflows/galaxy-importer.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "412a395e15c087fa3524eb1cbb4d94f8836f0fe174c2f93eb3883978355d3aa3",
+ "format": 1
+ },
+ {
+ "name": ".github/workflows/release-manual.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0cdc8148954ef8340ea4aa9e56b6df226731e033c5b1a40b052a3e3b15e87bb6",
+ "format": 1
+ },
+ {
+ "name": ".github/workflows/release-tag.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ac9fb7d547e119a1cb2981bf497b72dd26faa4c78ddd1c124eccb7ed0d429f1e",
+ "format": 1
+ },
+ {
+ "name": ".github/workflows/sanity.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "371f8aed1f995954dce749b4017b61c7aabac004e0d3123db97e691b48bca918",
+ "format": 1
+ },
+ {
+ "name": ".github/workflows/units.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "2d2264d8d520315e56ca91fc4c1d6e996c18a7c0115dd47714571528c6f259a1",
+ "format": 1
+ },
+ {
+ "name": ".github/workflows/update-variables.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "757a9b2c25111bb216f6a9c2c9fb2e846c792cdf7eecc1182b2cf1f659e7ef72",
+ "format": 1
+ },
+ {
"name": ".github/BOTMETA.yml",
"ftype": "file",
"chksum_type": "sha256",
@@ -123,14 +179,14 @@
"name": "changelogs/changelog.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "437dc32422a511e613c225a5904460c7a63a1a9364e9d4914746981ba3ac23d8",
+ "chksum_sha256": "71507aa348f024b04b28a249ccb60a22d09d95eaf0e2f503add687640fc648e9",
"format": 1
},
{
"name": "changelogs/config.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a5108e9a705d8037b5e214c95ff2bba76e09c8ff4c391c144f1f6f7a5edb051f",
+ "chksum_sha256": "4bb19a6205bc4e18b0d9adb6dfeeab3005860541d6fd509400fa4439b98749ba",
"format": 1
},
{
@@ -158,7 +214,7 @@
"name": "docs/docsite/rst/CHANGELOG.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "64943fcf1cb90ec0ae493011dcbef073aec7f5c235aaf36e53890a60cbd15826",
+ "chksum_sha256": "5c20e11dfc1704180b5d197a68107a5a6092c324a99739646c42bb0e1a0dc8a4",
"format": 1
},
{
@@ -172,7 +228,7 @@
"name": "docs/docsite/links.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "815bac1d202f434e272fa930267244b093866a43ca97140f4e50dffe59c37683",
+ "chksum_sha256": "d0d10fb4e0294eb17b32c582b70a50aa39d01c0a272c01818f7044ce92b77196",
"format": 1
},
{
@@ -186,7 +242,7 @@
"name": "meta/runtime.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2010a0b72247af5bb2c1e87452ec7a8445b59cbcd08b7d210c9c2b42d06e9341",
+ "chksum_sha256": "6195942600514b3a6fd22586eaba89cccdc9bc09265aff576f7a2de8346c4a6c",
"format": 1
},
{
@@ -214,7 +270,21 @@
"name": "plugins/connection/aws_ssm.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "62d7ec08ed815f9ddcaddedb411083a5feea25d76abc81f53b6520f97ea5345a",
+ "chksum_sha256": "72738ace4fc3fabddcee868e0ad6f01ae82976b1aed13319bdbe5ddef1c8e6c6",
+ "format": 1
+ },
+ {
+ "name": "plugins/inventory",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "plugins/inventory/aws_mq.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "d866336a72b5d493127038989c37f8cf8786e894499040ff956188c051e5e7a3",
"format": 1
},
{
@@ -228,56 +298,77 @@
"name": "plugins/module_utils/base.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3773f38412eed027d84ddb7ad7517a097cc9d47068e0b693093e8b77dc906242",
+ "chksum_sha256": "6582878e32780af41739e599bda223caa0778ec24ac9b1378eb307e6826bb50b",
+ "format": 1
+ },
+ {
+ "name": "plugins/module_utils/common.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9ae9caf904353f2952d5257bea7cb0b4a4e96668dcc9871c82809cd0b4f38f4f",
+ "format": 1
+ },
+ {
+ "name": "plugins/module_utils/dynamodb.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e51e3842505c9a4d57000e629ab98184f9e581f3bde4e584dcb459397700f51e",
"format": 1
},
{
"name": "plugins/module_utils/ec2.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d19154dd983ca303c7e1967cff80581c6bbea9aa7eda9ba9b9debfa1c1a6d3c5",
+ "chksum_sha256": "439eb9e1f59f2ca0cbd5cd5455dc321844d5db5118d6e0949971f56d573fe50c",
"format": 1
},
{
"name": "plugins/module_utils/etag.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1236f420413376bf76dce9ac19e113d270b4d70f80fc42c0902d9e7bd209b483",
+ "chksum_sha256": "2b7faaafc5ea73e79443a8e21eb7a73478a81ad84238bba3068b9c298d548e5d",
+ "format": 1
+ },
+ {
+ "name": "plugins/module_utils/modules.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "2a9add15b7a67440c2984c97698e58cf4f4485f67b905cb709265493280b69c5",
"format": 1
},
{
"name": "plugins/module_utils/networkfirewall.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "766a3b691221bf7da2a98c7690b9e9945285ba88b62ad88bc689311b46abae26",
+ "chksum_sha256": "96f40c4441345006478c54ec163cd0e6cc681b8b7e871bab5ec06f713a719c53",
"format": 1
},
{
"name": "plugins/module_utils/opensearch.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a2a9c1143a5406c9b0ce4cde80b58778c0136e4e6e5fa8805f043012ff50e008",
+ "chksum_sha256": "b1301aece4e36452f82dd529b966e237ba0e5c3c1739d4eb2e7ac3139a9f86cc",
"format": 1
},
{
"name": "plugins/module_utils/sns.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7bf414cf158ebd415be2b7b3360065a7ac65a9e21c99396397ed914e1af1b605",
+ "chksum_sha256": "23d475188d460dd91197220c9b601c378701c70ef31d075ca8177fedd6969b7d",
"format": 1
},
{
"name": "plugins/module_utils/transitgateway.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8b6682e83c3088dc467e953077eb8ad1b850f8ecc851c5d7c7dea030be0f6b70",
+ "chksum_sha256": "5518aa6dc8b009cf0413a4d58cad0f65d2860730d9b51b60960d9c0c52f5af1c",
"format": 1
},
{
"name": "plugins/module_utils/wafv2.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2b16084971bfb7e4c98b7d37d183d30675e8c07ab04af7523436fd3eb4a8dc02",
+ "chksum_sha256": "2b071356932d3f50ba9a2ebb68713917cb0c29c51d67c8f124770ccd244de131",
"format": 1
},
{
@@ -298,1113 +389,1113 @@
"name": "plugins/modules/accessanalyzer_validate_policy_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3b03a1e2a7f09d6b2b9b2ec5d742deb2ead05c703f5078c3feac604911af3e81",
+ "chksum_sha256": "91a5b80934e5876b2212b7e78a1e4cdb7a143be3e20d955d70c4181407825d73",
"format": 1
},
{
"name": "plugins/modules/acm_certificate.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4abea07d633c3f77691a1e51294c3d2c8f0e5a71c17a2fb7565c6e93761a0c18",
+ "chksum_sha256": "6b3a346a4f8afc01050937da428d677ffce23a70e13718bcc8619a343e5308d0",
"format": 1
},
{
"name": "plugins/modules/acm_certificate_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2480e877fae99a6258dd1364bbdc0536a23b99fc229c24a70213f09f9938fcb6",
+ "chksum_sha256": "932191c0d60b934ff3f41a41a158232f3471122d704c5d06ec13c101cbe12aa1",
"format": 1
},
{
"name": "plugins/modules/api_gateway.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e9d46aa61a7b727811bc4b82ff5f93bd65d66898e7f964a35c1eb52d1889d85e",
+ "chksum_sha256": "7f2f87711ce80f6e2e684cd102e8c6dc41940bbebe1293846b9c23b76c18cf9e",
"format": 1
},
{
"name": "plugins/modules/api_gateway_domain.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7a532675a592813db5220342cd0f07669e0e0c4cd206a71e1bc7f1afe54d0d89",
+ "chksum_sha256": "a134bf3499698afa8bd0be89b20461215fbf6edf601c943b7a0bdcbe2f8d689d",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/api_gateway_info.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "41c938185719ace530e2762dad486d389c1689d03d288c340e38d40773e9e9f9",
"format": 1
},
{
"name": "plugins/modules/application_autoscaling_policy.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3cca972ea4fe88a59ebee02e13ca47ae3c8ac16262388e17905caf8cf5d44c9a",
+ "chksum_sha256": "d8c1255b76cb821f38ea5f82ddcb05e495b910b85bbf506164b257d1f99dda73",
"format": 1
},
{
"name": "plugins/modules/autoscaling_complete_lifecycle_action.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "57e9d124e3df8a236889b67e6672f15b13bec2d78418fddc7e0e49b0646249a1",
+ "chksum_sha256": "52f7cf6588c9125e2442b0e8468aa0ba087861cb258698c0a82df4d2c5d8eea9",
"format": 1
},
{
"name": "plugins/modules/autoscaling_instance_refresh.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ddd64bd63aec61c9d9eb89318764ba1d5d85efc0cd715404f1d5c441842cc15c",
+ "chksum_sha256": "6ae892c2473bf0816f187a0b014cebf3fcc253d3f241825adc754d91f01f6079",
"format": 1
},
{
"name": "plugins/modules/autoscaling_instance_refresh_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4017c039bf9dbae7c2e0b6e2025ab0113ca0f4ccd1953f6ef7dae6d8c065be1d",
+ "chksum_sha256": "c372ba8ddec9bc7f0a4ab66630137661b6027d2502f85d21330675e2849f5895",
"format": 1
},
{
"name": "plugins/modules/autoscaling_launch_config.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d0873afdd99f6c65152b20f881994cc427e76df8d9c7b016e1844db5b10fdc19",
+ "chksum_sha256": "30a3e098336211e85205b737758c55c7b5fb6913d9f1e5edcb24d899199a6239",
"format": 1
},
{
"name": "plugins/modules/autoscaling_launch_config_find.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "12084b66d0dbd1d2164ca8bcfad72bba3ee8be63c8a1dd9fc7d503bf1a4c7f98",
+ "chksum_sha256": "fb6e4f2d39dbf4f66307fbac1e09bb469aa111d8b39227d5f409c8dbfb096afe",
"format": 1
},
{
"name": "plugins/modules/autoscaling_launch_config_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e198b4d78942841bdf4fd8153f062e8e524863e43c85d691bff9bb5aa104bc36",
+ "chksum_sha256": "03889bbee2c40eef5a79b958c1adc6acf1dd1385e63bd2cec4a3c73e701d4a18",
"format": 1
},
{
"name": "plugins/modules/autoscaling_lifecycle_hook.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "790375cbd689914a75ee46fda66797a4ed8bbf4b749f732a196ab0d85764afff",
+ "chksum_sha256": "7d277af4f7909bf2e62d03c99fd074ee9410b23c5dc830de1fab6560a5722770",
"format": 1
},
{
"name": "plugins/modules/autoscaling_policy.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "70a22498e64860a1051d55f9b973def78cc8db2ff0d681e4aea570afa93058ff",
+ "chksum_sha256": "30154ce721a8670bab2915d80700cd6dfc73c6713a036be07b22edaabef8512e",
"format": 1
},
{
"name": "plugins/modules/autoscaling_scheduled_action.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "dc0cd4113cb779bb53e7c6a91e59bdd8ca5c2bda38bf87db416f59f3624c0149",
- "format": 1
- },
- {
- "name": "plugins/modules/aws_region_info.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "054292965f42085f31bb80aecb9d907a6a003a2acb0cd1c136e4fc717693ab8a",
+ "chksum_sha256": "82533ffc50b4a218ffbba3e1a611f0f1a0eb928171910ad8eafe9c87e7292569",
"format": 1
},
{
"name": "plugins/modules/batch_compute_environment.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "aacf6a0f458ed02be8d8e30ee9522a0cf0f7bbc65c96fdf747bc2e229d021d2a",
+ "chksum_sha256": "3cd1c9117814c7437f12689097f3c6667d58aedb65f1086fce93ba62917eebcb",
"format": 1
},
{
"name": "plugins/modules/batch_job_definition.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d6ceea456d86137242b06f099ab08ef12a3ef83ec12acd3b1201b1ea2fb4f4c1",
+ "chksum_sha256": "42c9e000ee95ccc76a9af0575d05b4fafc2c8e7c36dc43df0e60ab1b0cd972ba",
"format": 1
},
{
"name": "plugins/modules/batch_job_queue.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5db3c68224a145d267a4ac879588f5cccfaba09db54b06631311fc624bccda80",
+ "chksum_sha256": "9d2915da3b913821b7f7bf466905aa7696ded2b4fac40d8e8e83e75250ce8385",
"format": 1
},
{
"name": "plugins/modules/cloudformation_exports_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c8c0fadffffaa45755a0f37e76921b0fafc8a442f85cf9be1955cad6a286b5f9",
+ "chksum_sha256": "60335fa25825552da02f00c3f3ee40d2aae54d692ba92ed52a548f63c62de4b0",
"format": 1
},
{
"name": "plugins/modules/cloudformation_stack_set.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "93b5ec32d38b341b1a1655a8b71c9bfc16997a6a75d5bc45df1bac6ecbd34a91",
+ "chksum_sha256": "a70f91c9c1dbf233555e8168028d19e6b83184dc026eb9b9ffdb6d845034fb9a",
"format": 1
},
{
"name": "plugins/modules/cloudfront_distribution.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "aa05169646699efe9ecab565cdfd70f9a8b4ecf85a432ee1838a0f14bf87b119",
+ "chksum_sha256": "bec37c5ef58dc850cf02dd989522f212c4245e6776197c220fe370133958dd86",
"format": 1
},
{
"name": "plugins/modules/cloudfront_distribution_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6f280c944ee9268997032ad42f00dc51a5d308f9d033172729a3f01ec008b6f8",
+ "chksum_sha256": "0ac23aa16fd2764eba4f535f19761bcbd7540901bd0eded24fd6cfecc49afec1",
"format": 1
},
{
"name": "plugins/modules/cloudfront_invalidation.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2cc2be4131d7193f6a03b3abc85da0b000a3615a063209aacd3f120baefe6512",
+ "chksum_sha256": "a2472efb0be3c742a9f24082d00a1d424f1404a3cacaad65100f6254ba5d8205",
"format": 1
},
{
"name": "plugins/modules/cloudfront_origin_access_identity.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e0574c3fccdb4351749171424c2cf06916c38e61058e5c375867a84eeb1a9c98",
+ "chksum_sha256": "3fba4261fa7195983427e52ff1c9d4a0a42487ef86d9cfcb2764999acccbe85d",
"format": 1
},
{
"name": "plugins/modules/cloudfront_response_headers_policy.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "aa2783c329492ba3c56005b6addd21761e8fb3c84031b1ad96c923e875067e56",
+ "chksum_sha256": "17c735bd277e79e2cab57ab8708d77e56fa8798900df8709b640682701f1ac4b",
"format": 1
},
{
"name": "plugins/modules/codebuild_project.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "65d1a0b0a08cb4a2abc8974e58709bf8e06e3cdd4eb76ff12e43833bf1c04d7a",
+ "chksum_sha256": "fec10a83e153383a3950dade221fcd8ab9a20fa0de92db78d95a4f20df320f94",
"format": 1
},
{
"name": "plugins/modules/codecommit_repository.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "68fda5f55704559ecdbc477f338c16a9b3c2645a1c91b38668d30de1576fd0d2",
+ "chksum_sha256": "21f047bcf54bdb1f4676e38a711cf8233ade685b836e2ee73ee6c4557bcb9af7",
"format": 1
},
{
"name": "plugins/modules/codepipeline.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ddbc5948f572462620c906acd56a8adc9c3aa5acbfc82f14471009471ef507fa",
+ "chksum_sha256": "cbffb81670cd1fdf321e4574d26b5c933a1860a003fe5ae095ff63c9196f1379",
"format": 1
},
{
"name": "plugins/modules/config_aggregation_authorization.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1c9b127ebdcd0114fc31c0b91824361454b1bd460dc84cf436c994085aac9327",
+ "chksum_sha256": "a6b54e57b64e0d06bd56ccc2a01e4d362b235220ba129f8c1759f5e3ab24042b",
"format": 1
},
{
"name": "plugins/modules/config_aggregator.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a895c00d5b4aff172cf884facd1c0da19346e08ce322b1b4ba20609cf0bb11ab",
+ "chksum_sha256": "3ddb3ddcdb50e164fbd9348739b0a4fc8b550f95f0986a00206473db90b54961",
"format": 1
},
{
"name": "plugins/modules/config_delivery_channel.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "af19b1718ef99e1ddffa558a247a9ba272202b20b9511bce337aac5a4bf68a06",
+ "chksum_sha256": "db7aa8c1ba89189250af04f1e3cd7149096b93d50cfceb2bd3e0e437d545c089",
"format": 1
},
{
"name": "plugins/modules/config_recorder.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5154567bf7d6ed270d2337eb57d8e5bc64a7626206f1a1632ab4ec85a40f5b43",
+ "chksum_sha256": "6e2810e8390a53d33b0c5c20bb16695b806fc6ecdf736ecfd2ac6f0a6dbe38fc",
"format": 1
},
{
"name": "plugins/modules/config_rule.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8b80425a2f13423ce3f4aeaf949c41b880962f2f22110e7ad5236df1b6b1c9f2",
+ "chksum_sha256": "f91e2d9538bc85df593f2ce1b96d3d668c1b80611e3bf8a293dd5af5c405c9c8",
"format": 1
},
{
"name": "plugins/modules/data_pipeline.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ea36eb5952ee7bd9b31ada4d31b30f365f02fb542166836d2af87e118c3ab104",
+ "chksum_sha256": "55b442ad3390de1f976c8004d575291413169b5b150cd106df7c0a2ec9777a92",
"format": 1
},
{
"name": "plugins/modules/directconnect_confirm_connection.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e98ac8cc28ea344fb517aee21adf7df4f11e84cd1685bc5e4258432d2597e1c5",
+ "chksum_sha256": "37672d0dfbdb9e261b9104ae072965bae969e082438c1ebd08e729c70e3267cc",
"format": 1
},
{
"name": "plugins/modules/directconnect_connection.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "98d48050da33e291adbc54f00481a7b5342941e4a2fd4a7acf2d9060cfb5f336",
+ "chksum_sha256": "6b22576c6493e627710238dac7ef944edd1ac8668360d134e7a01e00c033a8bc",
"format": 1
},
{
"name": "plugins/modules/directconnect_gateway.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "608d7e967844f304fba0e8e516f4330b7b532b99d81286381d4cce32c870ed5a",
+ "chksum_sha256": "b9228e0694120ee11917e2eaba46653a3b9efee19616864385326c3f3ca8b2d2",
"format": 1
},
{
"name": "plugins/modules/directconnect_link_aggregation_group.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ef1c4fd126291fdf4dd9da4b7efda630afab53ee10199e6de321b51d019899e6",
+ "chksum_sha256": "133b009324224cac488252e92f13b687f7faa8d4234f1693194a9e3ee40d029c",
"format": 1
},
{
"name": "plugins/modules/directconnect_virtual_interface.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "334afba11f87ad5040b5dc355f3b1655d07411f3733d9676cb290774f77ec08e",
+ "chksum_sha256": "71a217479ab14dae72bf6dc83255bfda191cc483d4e5047093889eff62dad65e",
"format": 1
},
{
"name": "plugins/modules/dms_endpoint.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2198a8a4ec06fbaba11e437960b0df16bab13be4c38e33b15cd6e6285a089092",
+ "chksum_sha256": "6273acbe3d3265cb9479be2a0ef15e4820567096bfc1239385f701b3913d6af6",
"format": 1
},
{
"name": "plugins/modules/dms_replication_subnet_group.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7ae257dab5205b233952cd56ec9bba4dd1d094d8ad5b870349c8f486ae0e611d",
+ "chksum_sha256": "b992d63836770289a6de831b958b43c22924d8070b58dfa62232b3463af29687",
"format": 1
},
{
"name": "plugins/modules/dynamodb_table.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9241e566a64c845475cca35cc8cc6ca5074079251056aef3461ea17563cf36b5",
+ "chksum_sha256": "58334de020e1e49cf8e2837f3c6d4c24ec0ce4e6f99d53e7da5fbb0076ab5cda",
"format": 1
},
{
"name": "plugins/modules/dynamodb_ttl.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a73cec1ba6db8872e212c217a4426179d80c053db8cb2230e79fef32c20eb2aa",
+ "chksum_sha256": "9a01c932f7e26e50d742fa3dfb77170c977c629f81f5020eb2299434f5770d4b",
"format": 1
},
{
"name": "plugins/modules/ec2_ami_copy.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d6e4e1ab4a4490cf18a7dcd59ef085ca5e57d6c1691bb1ca4db695566bf23f05",
+ "chksum_sha256": "49feb92f4f3fe0ac592a4ca5f0f297c1b921ba5937f33f5ab73c3804b0861aaa",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/ec2_carrier_gateway.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "468bf4e88db6fbe32e01a595a5de331484aa9a441e4ce760bb954108ea0f1a3f",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/ec2_carrier_gateway_info.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "92a3475cb1fdd5193f5095ab7e79df0fe25f0810401d1a60240fa24c7c706bdb",
"format": 1
},
{
"name": "plugins/modules/ec2_customer_gateway.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "16c90f2ab42b5f95ed709dbcc96e9d2a1c8b1a02a372503227b17430066a620f",
+ "chksum_sha256": "f2b1486f2bcc3792d276b35b8efd32b430c254a25914e41a93e6a86d21678e17",
"format": 1
},
{
"name": "plugins/modules/ec2_customer_gateway_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b7913db7fd5e857f1006ddc5026b732b5d1bd3ad1ad3926020289c4ed80e00f8",
+ "chksum_sha256": "d99df0970aad4616bc7aece745d143b82963c824e1d0e0ef2b0ae4aaa83e249d",
"format": 1
},
{
"name": "plugins/modules/ec2_launch_template.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1bfc9cb0770930cf7212d81bffbb85369dca777fdece5d242aaa134081bb8fd3",
+ "chksum_sha256": "a67cd95fb55350fd82238b7a4a96495a14c3a580faed5e5081fa63cc8288c4e3",
"format": 1
},
{
"name": "plugins/modules/ec2_placement_group.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f7e67cb1d68e1b55fcb26c6269dcd772021d9c7fc8c8c3b38f90cd44f42bbfb2",
+ "chksum_sha256": "74f9cd9cf6ecd68848380dd936c44f27327b65185ed39aa4f1ca31696bb086ef",
"format": 1
},
{
"name": "plugins/modules/ec2_placement_group_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4fce70bf0edd4edf8330cef39a07550d1587c583031745e30c51fcb6224c87ea",
+ "chksum_sha256": "c2659207293862dfc5e976966f59c90abc46a13cfa2c48643df4296f5287dcf1",
"format": 1
},
{
"name": "plugins/modules/ec2_snapshot_copy.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "72d2274835255197be1fd94547f938f0e5fc7e0441f1f3446aad68573c3eee43",
+ "chksum_sha256": "6a6ed898152fac04ef40b39ca0f8003aadeee92418b96584eb6d1a10c28f5753",
"format": 1
},
{
"name": "plugins/modules/ec2_transit_gateway.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d7b028f8679916db50ca340f7f48d2b8504bb12d107dbd88b6d1f466f28e776f",
+ "chksum_sha256": "1cedc060e15ab793f1c5e2878b948d1803cac0bdff9b682cad66d6d6de3e1007",
"format": 1
},
{
"name": "plugins/modules/ec2_transit_gateway_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "633a9320655e039e22bbb917c0e0ff5c486aec9e9196e134284931d1731accda",
+ "chksum_sha256": "9ca39e62d82cf9008706a2c99d3de1f0f8e4302726538cb92e73ec740d673416",
"format": 1
},
{
"name": "plugins/modules/ec2_transit_gateway_vpc_attachment.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3650b1ea6a795cc7d93d07c6ce95b62173070583f6634202d43b144804cbe0c1",
+ "chksum_sha256": "e6d5968564159c3c27dc3f1c491e6a0d045950742ef1bcafcb23b9276430a1f9",
"format": 1
},
{
"name": "plugins/modules/ec2_transit_gateway_vpc_attachment_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a688b6a8d2d277fcb4a1656b2fef30f5566fa565e1ca14862245036bc5c1d17e",
+ "chksum_sha256": "30d255db13b600aadbe0d23bf1ba8bddbe46dad80b19c725b7f49db3e3703ae4",
"format": 1
},
{
"name": "plugins/modules/ec2_vpc_egress_igw.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "003c1def5e498a76b0ea37d993f6a2777e0a6994c799190493181acc185990b5",
+ "chksum_sha256": "d21b72b863731cb5d7a612bfc7d86f952ea53b467f256b33ced2cd078d594699",
"format": 1
},
{
"name": "plugins/modules/ec2_vpc_nacl.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6e5eb11d4978dc5e84e91b1c3da4e8c77d0f1bb232be469d12d7937cea044926",
+ "chksum_sha256": "5e82dac9601cde049fd2399419a723f08cd9d048942a824a22640eda2c49f69c",
"format": 1
},
{
"name": "plugins/modules/ec2_vpc_nacl_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4dab5c8cdee41ee934141b817bc153b918d0dcb724bcb9b786c3ffc7cd49dfb9",
+ "chksum_sha256": "e92a9df84a5835644da2e2e8873c52210eb9ea8cd87a8955813469101590ee09",
"format": 1
},
{
"name": "plugins/modules/ec2_vpc_peer.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f0468a25317d2dc9b77633e5dcb4b189e5b11e6c8a620b7851d78c0be7da9cbe",
+ "chksum_sha256": "7dd064fc9733f8e75d1d20abe1b70a21a90d5b2d33bc162da2471fdd68f14062",
"format": 1
},
{
"name": "plugins/modules/ec2_vpc_peering_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8d7b6bbbedd3a4ec822e1a54a5a47a2f17144a901550e13d5b25553af8caada2",
+ "chksum_sha256": "9acf092eb29e6aac666f640dc864478b441817b4597521227ebb7f572a0af76a",
"format": 1
},
{
"name": "plugins/modules/ec2_vpc_vgw.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2a39adce133df56debffcf0cefcce2f8d597f97346cade741da6e52c1051a752",
+ "chksum_sha256": "d21bdf9feb57c74235d7ccd0c61e60836ab98a57c9d6aa6f791f5755e51c0e95",
"format": 1
},
{
"name": "plugins/modules/ec2_vpc_vgw_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "98582700e17ec1b999a4f8597498c38c7afdb0611edb4eddee4f98bc044e9779",
+ "chksum_sha256": "0dac532670b6f61d14c8727451dc19cd3411ef8439321832fa04bc315474a59e",
"format": 1
},
{
"name": "plugins/modules/ec2_vpc_vpn.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d6e77f95ccdc077bfaab85340b96e0f8c0ff9eae2e69ac423ac451218178df35",
+ "chksum_sha256": "8fb57b8a50e58d7dac665f493e678f0f184c3a74535f50daa34d18e19709d4e3",
"format": 1
},
{
"name": "plugins/modules/ec2_vpc_vpn_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e1f9ddcd0ed828a739a74147769007f8bd8536f64b8b6889dd68da554c94ec68",
+ "chksum_sha256": "f71d3c29876e7991b4fc9549051a8cb4ecddb1f0b4f0f8c6ef370cae052a43e9",
"format": 1
},
{
"name": "plugins/modules/ec2_win_password.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "191075a30e6e01642f1d8e0d919e7fd94b5b75ce8381edd6cb7dc689a1a58bf4",
+ "chksum_sha256": "6edd69b1e1643216dc68ba5970924c87a1e54540f43d1564308f445dff0e290d",
"format": 1
},
{
"name": "plugins/modules/ecs_attribute.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "262e86caf78bb6c97570acf2760288d1338d9120fd1f2b3bdf4c5d07238958d8",
+ "chksum_sha256": "6df9cca907a46e2d269b4b7bfc4617311d8cec589137e6f0e9dbff4c671eb8d7",
"format": 1
},
{
"name": "plugins/modules/ecs_cluster.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d58db0e241d325c56222646603eaec461ce025268fa0b1885229dc3795cc256e",
+ "chksum_sha256": "717a804b4d98129db71c2dbca9ec78a10c7415e57f8ed3a9811bf114cd7c247d",
"format": 1
},
{
"name": "plugins/modules/ecs_ecr.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1b1d8972cfc4ec26da49c1c3555f98ca4763f9a36cfe9d34b9ae3fe32d52e8d2",
+ "chksum_sha256": "46ce9f12421b38bb7f21636c6ce6179948be092fde76276a13aab461603548be",
"format": 1
},
{
"name": "plugins/modules/ecs_service.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3ec540ff8ef351513945561eac7769dfc0d4b19893b61307545909d016ab9844",
+ "chksum_sha256": "ffb7dd1444fdbaa495d7429b4aaeed4ac117cf04a54430b33493b28b7d6da389",
"format": 1
},
{
"name": "plugins/modules/ecs_service_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3e7c77cb27248d5e5feeb0a3ca66523724825c674b2b260d878c8c7b0943e575",
+ "chksum_sha256": "a470e906c2772bc767b7ec43d5b75f242fe4395afe3502391f9b09fc6fed5d0e",
"format": 1
},
{
"name": "plugins/modules/ecs_tag.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d2c954dd57cc5e2f55281775b476d2bda6920e9ac3ef404c1c87dac1ae603b64",
+ "chksum_sha256": "09ded4d5c5c8ab5c19e451c6bbb65fed4a3337a0771c6adbdb9007a2fe092074",
"format": 1
},
{
"name": "plugins/modules/ecs_task.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2f63242a5a0c0f7a5e4cff7d0dc3fc92595275673cecf1d58100aa186339c9d7",
+ "chksum_sha256": "fa98b35b6b771225e6909bbf5fea572662c2500e2954895bc046be910de8ca14",
"format": 1
},
{
"name": "plugins/modules/ecs_taskdefinition.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "293ca0b43185b449f8fae49050fb7000e0843a9965aeba797ec0cf2a839a555d",
+ "chksum_sha256": "e62d9a1a1891ba8338158a7d043f79a112f35e27a58677f2f8f77ec1b8fc0d07",
"format": 1
},
{
"name": "plugins/modules/ecs_taskdefinition_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "dd11a4a67918661799b119bc3f27022a0aaca8aa51ae3e4781676131ee2188d8",
+ "chksum_sha256": "b118ca5f6b160600641be2f803aa40c0c79e65425a1fc64e8d910469e3395690",
"format": 1
},
{
"name": "plugins/modules/efs.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "633349c53467a9bfaf28a69273a74f6b303d4deb16687579e3c67a8bec6c03bd",
+ "chksum_sha256": "b5dc61da6d44ae7f0268f19dbd7556a210fbcf67292e7ec9ef2c5e7818a19de0",
"format": 1
},
{
"name": "plugins/modules/efs_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "29b2ec0e4fdc9fe25863d4f0507a25096987dddff80a3e6abc50b4c35dbb12fc",
+ "chksum_sha256": "21f1c2140a6de6868eeca7a6ba307e4e12185a8e90a8d4b0cf826abbac63fb87",
"format": 1
},
{
"name": "plugins/modules/efs_tag.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3ecb608fd6d662a6fcf73fad6ff5d0396f54e66951bca0ca656bae6cc3aa9fb8",
+ "chksum_sha256": "0aedd58f21e32af7f0231dae6a756c57a9b72d5237f359918c3fa2278859eafe",
"format": 1
},
{
"name": "plugins/modules/eks_cluster.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b51753c6da9946a352e513d85b4adb29c8b780c9a13fd60e681bd1c06b35d4e3",
+ "chksum_sha256": "8005197d778382c7a5fec9af4aca70ab75319b7d182822c6af60ae05aa8e6c99",
"format": 1
},
{
"name": "plugins/modules/eks_fargate_profile.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "65f4e019649d750270d7becd94e01c22228e0fb0b33e21d51b00733956b25c40",
+ "chksum_sha256": "4b794580bbfea3629ba81541ea598e26431abd6a624059599ef597f5540dbf5f",
"format": 1
},
{
"name": "plugins/modules/eks_nodegroup.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e2a98d3f03802481c7362df750f99cf4fb66b7ae7004cb40c0f72866f4412488",
+ "chksum_sha256": "580cbdc0cd5492631137a3bcb4e4e9292ada3498645ffc2bcfe9dec70e1512d9",
"format": 1
},
{
"name": "plugins/modules/elasticache.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4a92f641d9542c97f9403cf019a627001d59a36c114412a1d2e43f01f28cd692",
+ "chksum_sha256": "57178a9afa917545ac9b31b025f60e3d3c8b1a9d0952c06b95705133aaa3f69a",
"format": 1
},
{
"name": "plugins/modules/elasticache_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7d0485e71308c153a5d60e0593dd72d529418b1feb82df839535d86939de768e",
+ "chksum_sha256": "0c3d2bc62db937a6efce1ac23ea08f6a485e550067df473cd9e01f964ff8c6c5",
"format": 1
},
{
"name": "plugins/modules/elasticache_parameter_group.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f59dbbe07caaade07614201b023f634c824e4e41b0a5b828f04ce29e54b25a3b",
+ "chksum_sha256": "93117fb43d0b04c2d6cb90ae954561f1fb448e6344b4e1ccc6cafca43d31e1d4",
"format": 1
},
{
"name": "plugins/modules/elasticache_snapshot.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c08013e0a43c183c75f298adcd0927353f2f6be8a037edf7343b30bdce7d6a05",
+ "chksum_sha256": "c7b626d1406c64f8c97cdf23435f49954bad0acd20965adfcc4e25ca20717820",
"format": 1
},
{
"name": "plugins/modules/elasticache_subnet_group.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9fee44274b2290b2d3e819b9584c5328b683e6219e2f579fa86b6ddab20a2a38",
+ "chksum_sha256": "29c531f22d8ac0bd082e4f1f1a6a380b2ca7cc501be261fefc55986b22fda859",
"format": 1
},
{
"name": "plugins/modules/elasticbeanstalk_app.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6e57e46d717b5d41503a84f14dcaa7ed4d7c9eb38aaee0534372654748f4983f",
+ "chksum_sha256": "5823a638f54cb2a502ff69ed71cb198becae490f08842bda61cbd430409c2416",
"format": 1
},
{
"name": "plugins/modules/elb_classic_lb_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0b072c0d4fa0acbd980cc1e6a47a75e1f30ad5de67201676d1c253695cde53db",
+ "chksum_sha256": "cb867e0ae455259e39258d4b2364633d251a2fdbcc63850e4777281f453711e8",
"format": 1
},
{
"name": "plugins/modules/elb_instance.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e05c316f9cd70fd9558e646458a57acce9c9bc94b9884b31049b7ddc727fff7e",
+ "chksum_sha256": "bdf03ed3b98544a4261706d40b91f8b53da1a049afb39a09a9037de9c6d0efa3",
"format": 1
},
{
"name": "plugins/modules/elb_network_lb.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "280a8f2cf1c26e031af14c990786e8c0bed286c69a643079831f622811f64cae",
+ "chksum_sha256": "ae3cf0fe9f7072739bf7828b89dce1586b1e042a064c7aa7908e0db68e1e3077",
"format": 1
},
{
"name": "plugins/modules/elb_target.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cbd59326beb6d572dfe319b14de9ad8fda0e68046f07910f8f5f3ee66aa5069d",
+ "chksum_sha256": "c8c5a6ff94ad9933d326e71d052cd5cdbfc573f9ca7696d3698ee649d362f424",
"format": 1
},
{
"name": "plugins/modules/elb_target_group.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "21a57c01e9d05f78d8e7f5ba1ab267656398d8a1b59efcec02c99abb3013cab7",
+ "chksum_sha256": "d7355cd7e58646b7bdd84748009b1c313e8754fb8fe0f0e8adc0696c5d830e59",
"format": 1
},
{
"name": "plugins/modules/elb_target_group_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "87d4087d2d77796f59ffacfb6e10e5c6842e6a2599f3d613e04557865be9d77f",
+ "chksum_sha256": "f889bad86ff6af11220a83bf3a40d9542429388f1b018ba8261afa52a131eb1c",
"format": 1
},
{
"name": "plugins/modules/elb_target_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "80bda0b10537466479746e5d11203e41c062f19019a5dcdce442cb2f3aeba27d",
+ "chksum_sha256": "956ba9cc26be1c3608ceb3539126e8e19d82096bd4564523e21e0c3067297ae4",
"format": 1
},
{
"name": "plugins/modules/glue_connection.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d2c681d7553cbeac81f5b98c0f6e2085bb030ff27ead1f7e8352af0ed4d8b324",
+ "chksum_sha256": "8808e4e2e90365eb34abd7d5496058406abee0e8a7f83241b88ddeeaab66c316",
"format": 1
},
{
"name": "plugins/modules/glue_crawler.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0ecc3c19d2fa2134ec5d73425a2719893a1058c834e2975da8558b84b72112a9",
+ "chksum_sha256": "ee0f7868f918a610252e59706b1efd929aa089a9bd6c8822cdd0a41e18692714",
"format": 1
},
{
"name": "plugins/modules/glue_job.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7b3917b5eefd2d8d3efba6cf99eed9a3000c7b20494dff76ddfa46a70d022054",
+ "chksum_sha256": "b9d5d95b21a49c62e1f86bd8f5e30ab45a9ec0bc81dc680a5f3233e712833108",
"format": 1
},
{
- "name": "plugins/modules/iam_access_key.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "a4670292f901959f4985fbdd702d127c708717b3b9e3bbfc8122e2829633f5c9",
- "format": 1
- },
- {
- "name": "plugins/modules/iam_access_key_info.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "2769addeade637b0bf8cfcfc25129df28253e939746f433afbb63e3773b998f6",
- "format": 1
- },
- {
- "name": "plugins/modules/iam_group.py",
+ "name": "plugins/modules/iam_saml_federation.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "427c30b17fca1d67adec7b8dd6cdf28835062e35e4ea43372295602b86c11fe7",
+ "chksum_sha256": "4bd0088d72d37180886f21da3542c8ce7949b83677d3f53523bc019d4dd2d658",
"format": 1
},
{
- "name": "plugins/modules/iam_managed_policy.py",
+ "name": "plugins/modules/iam_server_certificate.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "192a68f51deba569835389181460a12f83242b6d2a542a6a914cec99b626dfbe",
+ "chksum_sha256": "d38e7e31661fb0aee3c42942573f4c8a98df6bd9bf570073351b264e93cce3c6",
"format": 1
},
{
- "name": "plugins/modules/iam_mfa_device_info.py",
+ "name": "plugins/modules/iam_server_certificate_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "715af8b066c34ff069d73618990712b04b5d780ca6ba5370a9aa92aa3be51a02",
+ "chksum_sha256": "ed7406a4ffb74582e2d4eecd786ed7cb2ea5c84ad4cb4c15e4158c2d66898396",
"format": 1
},
{
- "name": "plugins/modules/iam_password_policy.py",
+ "name": "plugins/modules/inspector_target.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8f33138009d8bf7e8e11d81cd4d088b82b239632efb8b37c2bcc50b63bf6383b",
+ "chksum_sha256": "dd8d72824e24dae8cd1d95fff482a2a1868766e5436837ea3e71469c8bf7bf99",
"format": 1
},
{
- "name": "plugins/modules/iam_role.py",
+ "name": "plugins/modules/kinesis_stream.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1ce190e56a817cc3541c9cf5e68c6e9a271b8590511193fe901702b63f29bdb5",
+ "chksum_sha256": "a2aab3b2655fe8b79fb874a51657e92705bc51c3ae2a468b82f36cf795e26bcf",
"format": 1
},
{
- "name": "plugins/modules/iam_role_info.py",
+ "name": "plugins/modules/lightsail.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c47138c3118c33bb62c8471078ff86990127c057cabe04dbb0e6a20bdf5b53a1",
+ "chksum_sha256": "bd3d2daf8cdd5c2f048dc06e76bef128d83825afc47db990ed5779007712147f",
"format": 1
},
{
- "name": "plugins/modules/iam_saml_federation.py",
+ "name": "plugins/modules/lightsail_snapshot.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "844e900f889075e6928a6f8efd1d0641ca6540b14a2bf77e14599de99f6d80aa",
+ "chksum_sha256": "1f9ee3c0be77be010e91bebbdc6634eacb5b02f49e580d8177104eec475caf91",
"format": 1
},
{
- "name": "plugins/modules/iam_server_certificate.py",
+ "name": "plugins/modules/lightsail_static_ip.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "49b7f82a61b94c864c2bb6468f4c641eadaca1f0f2f604d05a209bd15334e9f6",
+ "chksum_sha256": "fd86fba01655efa861a4edbb4b68c682ee2c1cb6c52a4927ff2c1deb1cf73320",
"format": 1
},
{
- "name": "plugins/modules/iam_server_certificate_info.py",
+ "name": "plugins/modules/mq_broker.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e3b0ee06988c8f0cd2fa0af8cd1b388f9988e104f358120ea6d34d5f5cacefee",
+ "chksum_sha256": "ca46c2156ab5ab7de5f23540026bef89b31ff890fabda448605be028ca6c389f",
"format": 1
},
{
- "name": "plugins/modules/inspector_target.py",
+ "name": "plugins/modules/mq_broker_config.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b4f8434fd2dd9ae678ec010918fb882ce8b6dcb17ef8f1c6ed7cfb4c6cb9ae6c",
+ "chksum_sha256": "2728e73959eaa5af6f40932e378db4234aa7de989d3fb06689c203502d59b571",
"format": 1
},
{
- "name": "plugins/modules/kinesis_stream.py",
+ "name": "plugins/modules/mq_broker_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "84d1c2f25c82b967fb44edd2a73ad5436c3ae5db80e22feb3979787da7046527",
+ "chksum_sha256": "fe23c22370cdf0efc2b68cfad9eed17beb1c0f1d2870b25bd379ce149037873d",
"format": 1
},
{
- "name": "plugins/modules/lightsail.py",
+ "name": "plugins/modules/mq_user.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "847ea99d4c77c51a5bb53c2295bb12c0bf8cf3a421d285b73775d4dfb96d8654",
+ "chksum_sha256": "32a171b4465cc24b3f9b0636e28cb7a791c2685e00dca790ec4d9966bd552c8e",
"format": 1
},
{
- "name": "plugins/modules/lightsail_static_ip.py",
+ "name": "plugins/modules/mq_user_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "697c2762936ea292d23252a495835f3d713e0ce37d9f1fe6f47724ed10388ed5",
+ "chksum_sha256": "f579eb5e29fe7fa20530d9637f5cd18dcf65b09a7a113055480538468c9d0087",
"format": 1
},
{
"name": "plugins/modules/msk_cluster.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6754af908ab38fafdea2c2de23e5cf682d579f09ffce712cd9232c7b5a86fa52",
+ "chksum_sha256": "c4211d04238671d5f57b0214e55d12e541c9619b6275c120868019fd3eaf56b4",
"format": 1
},
{
"name": "plugins/modules/msk_config.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5b2cad825b29977b0f53cb494923b165a264a2274fd750bab6d53bbf642440c1",
+ "chksum_sha256": "c3653136affcfcdeb7521aff5b9abe8413d864b23c4d0aa923e951cfe4599d7a",
"format": 1
},
{
"name": "plugins/modules/networkfirewall.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4e754a0658b8f53307b5bf41d5a20616d92a09aaf59928d7482073bc0808de3d",
+ "chksum_sha256": "b03f192eb185bde65bf5cb5774657ad27af7a6ed80458af6fe05b604cf8c7a13",
"format": 1
},
{
"name": "plugins/modules/networkfirewall_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f842953dff0636d0d5c48d1dfd25ff9a04efbd347a77e778fe358abbf901f859",
+ "chksum_sha256": "6de2084632bbed197a8022c9825a8268540c8aa4614ae791c27a4157c6db8328",
"format": 1
},
{
"name": "plugins/modules/networkfirewall_policy.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ef715b14aa6936b4a41ab9ac5d45f521a6a2a5bcc29282da38651ebd9320d22b",
+ "chksum_sha256": "b313db78d1bed198b586c3b45dcaa6fff480a92dfa6c97235aa2ea8453f1dd23",
"format": 1
},
{
"name": "plugins/modules/networkfirewall_policy_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "374651dee9fa00d661c269e273234c76b687445f2a5b96b00794a008f49b8ccb",
+ "chksum_sha256": "3bed6422a18ece0f215a4e13a26d1e6c78498edc8ae70320a9f33acfb61f276c",
"format": 1
},
{
"name": "plugins/modules/networkfirewall_rule_group.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "286e657c966f030c981d8c70fa8736d864cb300c97607348a98e8ced67c4b24e",
+ "chksum_sha256": "b9a890d65f42e53df5e09289a0c34b71a66e2e2975189a45b8b22500d90d4de3",
"format": 1
},
{
"name": "plugins/modules/networkfirewall_rule_group_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9c47f94128c9a55a80c1b28d8919c121f5b501a62e538fb136f7cfc1398765ca",
+ "chksum_sha256": "6fabc2b367796a16b091b8a98527ef4d163bae7183a79d80671d471a110fb463",
"format": 1
},
{
"name": "plugins/modules/opensearch.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3f8ca1c05aacb93678b956ac5afd1bd178fbd682376d00ea338a54e2c9573195",
+ "chksum_sha256": "59e5149a92d69f805d44e02ae2453a61575d6a09e7c329351852ebb6ac349b50",
"format": 1
},
{
"name": "plugins/modules/opensearch_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fa9ed71b95685a580e2433cbcf08d36a1abd0fa660409719fb6bf6e39a9bda2d",
+ "chksum_sha256": "8a414409b642f1ec6793d7f6872e8420f6bfdf083c4db1e5d6cf92b3dd3cf83a",
"format": 1
},
{
"name": "plugins/modules/redshift.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "30b250cec0c633624dd0e6b80adb6b1ac74d6e3f38e53200fc802dfeb408689b",
+ "chksum_sha256": "19316f40735b597e92399f19aeca9136c4a29d5bf6a4e60e3abd4e003c388a7a",
"format": 1
},
{
"name": "plugins/modules/redshift_cross_region_snapshots.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "78352756b9b4972fff14df17afe6c670f15900bea01390cb9238f07e68cbe888",
+ "chksum_sha256": "0144f93c383d3266fbd00dd988fb08903a61b9da0ac84f471750354e7c18a276",
"format": 1
},
{
"name": "plugins/modules/redshift_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f21b66e80da414866d2495fc0097eb5704c9f0f4c721e73fc421278d4f9226ca",
+ "chksum_sha256": "852e12c141e900c634b9b9eab98cbc83eab21b5859df4a564fae67402c00be70",
"format": 1
},
{
"name": "plugins/modules/redshift_subnet_group.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6e462b88c3da004840ba167cfb2cae72535842c57195c47374df2ab844d8579d",
+ "chksum_sha256": "b7e0ff95fdb0694d66bb4dc5acd5a00bf37fec964f23cade4fa12a9315e45ad5",
"format": 1
},
{
- "name": "plugins/modules/s3_bucket_info.py",
+ "name": "plugins/modules/route53_wait.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "992dbcbb48a88c14263e36288ba89b1a9757b6f0df7897d69cff20f2efead3a8",
+ "chksum_sha256": "f0fc29354954f2c99912b7f4c97f6d972bdd2f3cabc4add36357b5a147d503ce",
"format": 1
},
{
"name": "plugins/modules/s3_bucket_notification.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7e7275ca49bc005e0c278f2f475288b86a60a51afd1aae7df9a71a812d2bfbad",
+ "chksum_sha256": "3bffcf152108c5c10f946c796ff2318a389d75966de354cb5fcaf4be443e5aa8",
"format": 1
},
{
"name": "plugins/modules/s3_cors.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1968a322226e5d79cfc5fafb7f9bc49c579b6651ed82e990144af8d262401a08",
+ "chksum_sha256": "043a00712d2e58c116fdafd688121de5ef609cdfd44c957d630bc70cbe065241",
"format": 1
},
{
"name": "plugins/modules/s3_lifecycle.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cb57b02322198c34915fa3eedf668526cfa3b3b8cad411867fec0a3bb4a7ef21",
+ "chksum_sha256": "0fe546391c85523a7aa6bdb46e8ed8153f0fd469e6d72de402803821a2d5b97f",
"format": 1
},
{
"name": "plugins/modules/s3_logging.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "85235617fea255d699380fb5cb49be9eb6325584d1cb1104e17f0261b0af431b",
+ "chksum_sha256": "776d4b3884a2f605a55171d0d8538f42afd9906a8f4b360fe878e02d79a6ebc5",
"format": 1
},
{
"name": "plugins/modules/s3_metrics_configuration.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e813b8c6bf6ae1a2a3bf04731839303c4953d7e699875d0a211995f45607a9bf",
+ "chksum_sha256": "44628adf7b33f58899a690b486522d308bfa6c6dc3ed0deda30934310bb57a9a",
"format": 1
},
{
"name": "plugins/modules/s3_sync.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d3bd7cc04a7c7676c797601d1478d826fca715de0e41157dfeb21440f64b8d6b",
+ "chksum_sha256": "ae070b5854145ff8778654e54b571adbc41870e6a4d3c7dfacde1b7e56a8d8a8",
"format": 1
},
{
"name": "plugins/modules/s3_website.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "86dd4795fb1fc5e4fcd4592804a69d7e65ec78f7211eb0f5eb28e001a97876ec",
+ "chksum_sha256": "e4d5f6c4b2dd20e0c540d9047f8149cfc6f0453b72b2d56ef3e4d463f553b9be",
"format": 1
},
{
"name": "plugins/modules/secretsmanager_secret.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "00ea602c8aea327d56a5d2d2df12e69f4d804648b6311a68805414f90b69080e",
+ "chksum_sha256": "08b16b0a2c0493cf7a42667ab08bd83cd6008a0fda034302f71a43bcf80410e1",
"format": 1
},
{
"name": "plugins/modules/ses_identity.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9af2d01ebebd7862d7b91fba1688e4229b2370df93ff7b4c5e3e0749cf510c49",
+ "chksum_sha256": "4e2f56bd12a23aa3eb8657902bed9127955428cf37064323be05047814aead91",
"format": 1
},
{
"name": "plugins/modules/ses_identity_policy.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "db543c3c458ebb3b8f2d16cbf53cc1db41b522e8990e4ad20b7357b1e2cab5e0",
+ "chksum_sha256": "61140f4cba88ca8c7b63a8db7324f18eed51bc8f1426ff5b67ece2cdd1523eb2",
"format": 1
},
{
"name": "plugins/modules/ses_rule_set.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "52ff6a2cea01348663c7e8f91104652de66026cf2ea5e8aaaf4f9718248047f9",
+ "chksum_sha256": "3432beed464e6296038ff25baa2e885bbc15ee8a4b592fadc8b1848908147fcb",
"format": 1
},
{
"name": "plugins/modules/sns.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "552fda976295b4149037110979d8f213ba0cb55f30558fa6ec46c7e2d3243a89",
+ "chksum_sha256": "e0e6033b806c8bf45156ccc977fe8f3ffaedab36508a6c0d3f8d23b14231e1e7",
"format": 1
},
{
"name": "plugins/modules/sns_topic.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9ead09ad248206d691b054f022e8d0eb5f89902dd10a605358977c40143928d3",
+ "chksum_sha256": "6df7188cc1348ad61e0d4ec34ec0ecdbaa357a33752d7c672d61048c6ab110c7",
"format": 1
},
{
"name": "plugins/modules/sns_topic_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c3b94209a8edd13b09bb89334dac28df5f28798d8e00f3602fab26e36f3facb9",
+ "chksum_sha256": "766ce9aa35ee04fd5f21abb0762fbf748af725eab43e167459d335049fe51e81",
"format": 1
},
{
"name": "plugins/modules/sqs_queue.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f9f9925cda9e5a0b7a0ff4a29e33a6509d84fcd139b78cd4cf791a935b4322e3",
+ "chksum_sha256": "d90b03038bf0623f02f72923548be73871e534d55d87fe01cf7de1050d2487ca",
"format": 1
},
{
- "name": "plugins/modules/ssm_parameter.py",
+ "name": "plugins/modules/ssm_inventory_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a8a5e9e5589b7a0b43f01cd74110fce1ce83aa28c6923bc0843910f094d00716",
+ "chksum_sha256": "89540d1b5ab592090a69bf0da9788c0ae8e18cfa7d618e0184c00da1843ca995",
"format": 1
},
{
- "name": "plugins/modules/stepfunctions_state_machine.py",
+ "name": "plugins/modules/ssm_parameter.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e8b54e0d3036b5f54fa6e5be136bde47d7ae6b9d6ae51c570f36a72b61a4eaa5",
+ "chksum_sha256": "a9ecd97cdc61788613a0377c5828a0bc96692af077f3c1c997fddecd6dded38b",
"format": 1
},
{
- "name": "plugins/modules/stepfunctions_state_machine_execution.py",
+ "name": "plugins/modules/stepfunctions_state_machine.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "99db0e45db51162e18b183014bc5facd8902bd6677f9f829e51a45651a3a7e4f",
+ "chksum_sha256": "6b6eaeaaf6722b4cb2eaee5f03ac2701778e19fcdd3a8f0488198ab7926530d2",
"format": 1
},
{
- "name": "plugins/modules/storagegateway_info.py",
+ "name": "plugins/modules/stepfunctions_state_machine_execution.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6f8a4c49bca4062099f0dee4a4a4f6285f4d65dcb6bd1f6514d1512787eacf02",
+ "chksum_sha256": "70c62ea742a48da90db3cebd1f750befd2c381be337faf5206a5e8fbe4cb05b4",
"format": 1
},
{
- "name": "plugins/modules/sts_assume_role.py",
+ "name": "plugins/modules/storagegateway_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "eaa03efc62a365c4ab2cb5a6d5c76848d5e20463dce1c3bcaeec0cc4d16ec264",
+ "chksum_sha256": "85b799638af3111e64ba398c7a81e52b4cfaeb450efcf6116be642b9bf1c645e",
"format": 1
},
{
"name": "plugins/modules/sts_session_token.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d6f6c506bbe4f6a55c65ae37b9d6fde68150121232fcfed130caefa8e8f68fa6",
+ "chksum_sha256": "3458c1a42dfde7200a8741178aad6a82ebab6e51a179e5b0306db5fb310d3dba",
"format": 1
},
{
"name": "plugins/modules/waf_condition.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ad44df69bc13238975adfae18771a43d633326f2b010f58591702df7fac37e49",
+ "chksum_sha256": "5131a929fdad6e9e29a80fb16245405c3fce9ef342f7133a9f5e9a1daa4ffb42",
"format": 1
},
{
"name": "plugins/modules/waf_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5b1cf5c43d6124f7160e375864c8d1db4f415a151c17982d14c8f264d40250cd",
+ "chksum_sha256": "8c3f06e42a478cfdaad04b783cd4383e3cbe2cb3fe5074debc8c51f77c2c72db",
"format": 1
},
{
"name": "plugins/modules/waf_rule.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f4e5a637198188c2dd7319e29a502f3d86c39900495cabe9b8591881d817a489",
+ "chksum_sha256": "a3d58f6ae7281668698f8c09ed05e995d723ba82dbe7a906d2a9f3d73d34a2c0",
"format": 1
},
{
"name": "plugins/modules/waf_web_acl.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "303bd8bf3ec0c46a3c63ce60d9df9f576d45d6f976bcaa8a611011943b8da97c",
+ "chksum_sha256": "0bcd8d012655999abcd84e2aa55f07efd937b14e175e05122d01ecb398c3f834",
"format": 1
},
{
"name": "plugins/modules/wafv2_ip_set.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7ebb40850cdcc1bf578bcc9b4bd22a7f1152d1062ed5df5ebfcec19c36fa8c63",
+ "chksum_sha256": "86b4623dd939d290b36e5c1602e51def048838c0e256795827cae2d88de91f6c",
"format": 1
},
{
"name": "plugins/modules/wafv2_ip_set_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "068e15f4b25b179442e2c6a5e55bd40d10f2e05028d664c6fcad0a562804a8ab",
+ "chksum_sha256": "374ecab062fe0f58172737e3f65193fa489a11cd61f7cf04f0303b567cf0256b",
"format": 1
},
{
"name": "plugins/modules/wafv2_resources.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "33775d642a721637605c90ba93e5d1a302de9d35663c7be8ad3f07ffd0899d49",
+ "chksum_sha256": "02c16135fb21ce18966c1793752390f1cf4d7290dc73461b4432b52f2f3babb7",
"format": 1
},
{
"name": "plugins/modules/wafv2_resources_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c60bff7b7b868d6f0b603f0269994c8ad3d678d87b6689af0182dd89954e61e8",
+ "chksum_sha256": "92ddd60fb4eb0d47cb47c4b3b49852b62b31fdd0a259cf1e24a516754707a65e",
"format": 1
},
{
"name": "plugins/modules/wafv2_rule_group.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0658b07ef2b67ebaacfb04b28406a20f43839038537c995e3873920799e30c09",
+ "chksum_sha256": "8198c99f2aabada884cd0ec0290ddb2c8537fe1728db4fad851a5d0004929231",
"format": 1
},
{
"name": "plugins/modules/wafv2_rule_group_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "911ad9b1ad0ee33dc4d4ff422ee334ad93e8d512b5ceb4c532e1f8b14d3d74dc",
+ "chksum_sha256": "6c72bc5de1a02e96f90489c5e34e6a3c5b56199bbdc8b13bfdab337513d401b1",
"format": 1
},
{
"name": "plugins/modules/wafv2_web_acl.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "61259cdf2da767a1ac0cc740eb713c4e5c45c358a8e420b0efae76c44c95b869",
+ "chksum_sha256": "7e7c3e615c736e9293f00b1fa117ab54d29e491947768632e2d94c9cec22b299",
"format": 1
},
{
"name": "plugins/modules/wafv2_web_acl_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bbfec040c28e6ef02777fb66146e7844b4c47c3aa7ce8950f58a891f4534ba24",
+ "chksum_sha256": "55e31c9e9d5998433db9dd05e18997148261588d5ed8a3cf074cd03c1bcd23bb",
"format": 1
},
{
@@ -1460,7 +1551,7 @@
"name": "tests/integration/targets/accessanalyzer_validate_policy_info/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3324b44b193f56e98a3a2e7445000f0f6be1c9ea536ee24bf069f0640ba4a8e4",
+ "chksum_sha256": "4c7945a42c1169a9555fa71f9e611ef84a0c6d7a0ed622d88fc05a3592d32bf5",
"format": 1
},
{
@@ -1516,14 +1607,14 @@
"name": "tests/integration/targets/acm_certificate/tasks/full_acm_test.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6436083f5c3ddee3de639eea75ff4d1cd31e9b09e89426784afcf38930caa874",
+ "chksum_sha256": "96b94947415c47f4e25a1c4fc7d55306818d3d8ca0aee04b569562ca75d82a25",
"format": 1
},
{
"name": "tests/integration/targets/acm_certificate/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5e46e7b16be4fd32417dc8180ddb449d051accf097ed501b67f0cc00c2517ea9",
+ "chksum_sha256": "f081b2bd5a77f435ec588d145134c6af52e2b5bd19d5d3cae924d8be5f8d5076",
"format": 1
},
{
@@ -1541,6 +1632,20 @@
"format": 1
},
{
+ "name": "tests/integration/targets/api_gateway/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/api_gateway/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "3783a6ec2f0c3e19c80e694d98debe68e697ac3662dcd267502175c4f42f6725",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/api_gateway/meta",
"ftype": "dir",
"chksum_type": null,
@@ -1562,10 +1667,24 @@
"format": 1
},
{
+ "name": "tests/integration/targets/api_gateway/tasks/lookup.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0627b871a1e95649ba6e6a0b446be1d9af65f375d809bff21e1afd4774292238",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/api_gateway/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6bca5f941b24b308bec9c4c0e61948d4e7964fdfe6d995e9796bd7f09612bc3d",
+ "chksum_sha256": "ed6c215c9cbd954d4ba3b993fde9cea42f0568a9979c90a47436eba98ea9e677",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/api_gateway/tasks/tagging.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "199cd270708ad990b2ee27e08cebdd50fd5ffe1e24394b4ea6db415c87f1b7f5",
"format": 1
},
{
@@ -1579,7 +1698,7 @@
"name": "tests/integration/targets/api_gateway/templates/minimal-swagger-api.yml.j2",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5713f02e2af48506bdc7c6f98e4cd97bf32964f359d7e1c16155314b65ecf6e2",
+ "chksum_sha256": "832a1bfb8d582187942658a4a1dca0e20c99272ee581cf6991aca1f0aa112f8f",
"format": 1
},
{
@@ -1649,7 +1768,7 @@
"name": "tests/integration/targets/api_gateway_domain/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b2200ffad1f5b49dd1dbadec58f4949e0945a7df938ded994e315f3f88cb3b51",
+ "chksum_sha256": "3ed62d2700519e4c2b10b09d36caf775fae12dee42d5890c89c3934ef51621e7",
"format": 1
},
{
@@ -1705,28 +1824,28 @@
"name": "tests/integration/targets/autoscaling_complete_lifecycle_action/tasks/env_cleanup.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "983bd310159995c21c07ad87cf2066c455a50d562277b400c47e7cc3cef942d5",
+ "chksum_sha256": "9529a0b3a876a0a110c24729fc7665f1726be8c9e1cdfd0ffdf3a1de03490251",
"format": 1
},
{
"name": "tests/integration/targets/autoscaling_complete_lifecycle_action/tasks/env_setup.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ac545b82e17c3397d0e775ee189b24f8a325e79972c83a270461df9c0cfc58d8",
+ "chksum_sha256": "627b7cc23d9b082e44dd06f6fe2f14021dddab5cfb1d04c5a94d3640a4c401c4",
"format": 1
},
{
"name": "tests/integration/targets/autoscaling_complete_lifecycle_action/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c0f317084365948900d155d9c1336d4baf90526fffbddd3b996e8579ec8c19b7",
+ "chksum_sha256": "5fcedb43730fd42a8540d49a159b193934e270f2a33e3ad6db09100f282e04d5",
"format": 1
},
{
"name": "tests/integration/targets/autoscaling_complete_lifecycle_action/tasks/tests.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "559d9e7f665a6464bdf917e7b25ff41cdd823995d01a8d6bb5376cabdba3ea40",
+ "chksum_sha256": "d39aa45a691c590577ecd92f93ee155d86f9dd5a7f369d16d89351adb29f30b7",
"format": 1
},
{
@@ -1782,14 +1901,14 @@
"name": "tests/integration/targets/autoscaling_instance_refresh/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "64a08168d1e07128b4c5d545d984ba4b2c8953eaf1e76e74d36280df7c600753",
+ "chksum_sha256": "9b2aece1a35caa3b7acb6ee95a3b123f135733dc1f8e59549a2fcb97e80b8d29",
"format": 1
},
{
"name": "tests/integration/targets/autoscaling_instance_refresh/tasks/refresh_and_cancel_three_times.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6f7f271b0256e2c817776db8d02ca561bd370a5ae78b026533412d3a38519314",
+ "chksum_sha256": "810aa0ae80975186b86942dd7de03773cb2e054c7d0f5f54b5b4efdec89b19df",
"format": 1
},
{
@@ -1859,21 +1978,21 @@
"name": "tests/integration/targets/autoscaling_launch_config/tasks/env_cleanup.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "554a62c6b081150c0d1e241b860a74e38bcca31e44bec9bc5fee4ef48ed59153",
+ "chksum_sha256": "d6b904d6a49be157ab02776b7db6fa68090d0d3b4ef0d64a88d09fc071ada2c6",
"format": 1
},
{
"name": "tests/integration/targets/autoscaling_launch_config/tasks/env_setup.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "61658f73c20b9db76c17cf247fe3f8305f7b0df51ae3a4b41640222b3c2449fc",
+ "chksum_sha256": "b38a850ad910d17efdabc6056ded17b7bcee26f7e893d86c5957943df8870d80",
"format": 1
},
{
"name": "tests/integration/targets/autoscaling_launch_config/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c91c2929ca15e7837e8bfe2fef71ddb22c4146f7b82f87bbb427e67b57eda1d2",
+ "chksum_sha256": "3bc1a5513987d5b5318be598ce6735c461eea652c906eeeab583893dcdfe31b9",
"format": 1
},
{
@@ -1915,7 +2034,7 @@
"name": "tests/integration/targets/autoscaling_lifecycle_hook/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1c33088718db08689d0331e05f8f62ffba98125ee70cc597b822a2d8abdc2513",
+ "chksum_sha256": "a40e2863b1aa0d204462a204195c41e057eaec7ead4757f31d9ea0b350a6ef69",
"format": 1
},
{
@@ -1957,28 +2076,28 @@
"name": "tests/integration/targets/autoscaling_lifecycle_hook/roles/ec2_asg_lifecycle_hook/tasks/create_update_delete.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "91f97b1be311a231ce16dee2c3d94f683fb75cff327b3c8c730549bd1fa59669",
+ "chksum_sha256": "cd7f919350f80a211e3f84dfda92a6a539f8d68a852a9513b8248aae04ace3da",
"format": 1
},
{
"name": "tests/integration/targets/autoscaling_lifecycle_hook/roles/ec2_asg_lifecycle_hook/tasks/env_cleanup.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "589715d4041cae20e7f28b7d4d50d4892eb25446437838408fbd27dbb4ed6d8d",
+ "chksum_sha256": "9b84714a9f521785a9eb822a24a45acee898f02321e74b12367fe73cc668c63d",
"format": 1
},
{
"name": "tests/integration/targets/autoscaling_lifecycle_hook/roles/ec2_asg_lifecycle_hook/tasks/env_setup.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bfedb707d03835770cb2aaf3edfbd97b1472881fd04cfd85559bc3675bf599f8",
+ "chksum_sha256": "5c74ce79ae8bf5f5fafbd856a0ad3e7582c49d2e1da4c008f5c77ac19a96227f",
"format": 1
},
{
"name": "tests/integration/targets/autoscaling_lifecycle_hook/roles/ec2_asg_lifecycle_hook/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "54e107dc11e2d7a141046b7933e6e5eeabf0c3860ab856b3f3a74af20e4252a5",
+ "chksum_sha256": "11e4191a8fb247be972aaf5e8a7b2fbc12e514ef53f1736ca90b11d21785b50e",
"format": 1
},
{
@@ -1999,7 +2118,7 @@
"name": "tests/integration/targets/autoscaling_lifecycle_hook/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "36ed879c8f6bfe8198b7e23c3ca879aa3280613a09f76e879e65d8d2d934b040",
+ "chksum_sha256": "365c26c94d84d4e82a379b3a77e69c07e27e7144209cb9a7d54b6b6d71c86cbc",
"format": 1
},
{
@@ -2055,7 +2174,7 @@
"name": "tests/integration/targets/autoscaling_policy/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fbc367e921406afcd6205835b7ad6c224fb79169221e276e47edae0fca758975",
+ "chksum_sha256": "16babd09f0f0e1ebca1fd89cee72568a88dfa304319a9733f85c6e999ecd0081",
"format": 1
},
{
@@ -2111,7 +2230,7 @@
"name": "tests/integration/targets/autoscaling_scheduled_action/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b03e212eaa3df04e3275fe6ef47915daa0c383af25bc88aa2c8cedf2cec8855c",
+ "chksum_sha256": "753fd24292d2402c3aed13ecc9df608588006afff84d462216487471bb9532c1",
"format": 1
},
{
@@ -2122,55 +2241,6 @@
"format": 1
},
{
- "name": "tests/integration/targets/aws_region_info",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/integration/targets/aws_region_info/meta",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/integration/targets/aws_region_info/meta/main.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "568c092a1d4f28424e3df8d8aa2d2fc738e14c32d8854f970d69bb480e476afd",
- "format": 1
- },
- {
- "name": "tests/integration/targets/aws_region_info/tasks",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/integration/targets/aws_region_info/tasks/main.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "e9e08c8cb8631a42b7c94756551b06830cfc35f765f3e16f4dfad800f2197449",
- "format": 1
- },
- {
- "name": "tests/integration/targets/aws_region_info/aliases",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "7289894f07e47a82972994ae89cfaef863f54310114e1c5d7122f7fc08bc19fe",
- "format": 1
- },
- {
- "name": "tests/integration/targets/aws_region_info/main.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "ce48a8661f558765a481c8bbcc58b9570c97a411f6803851ee0668d3c3f74b28",
- "format": 1
- },
- {
"name": "tests/integration/targets/cloudformation_exports_info",
"ftype": "dir",
"chksum_type": null,
@@ -2230,7 +2300,7 @@
"name": "tests/integration/targets/cloudformation_exports_info/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cae31f7031f4f2201fa51c73db0fbd74dece2dba3051d22e67b1f9f385897179",
+ "chksum_sha256": "7818687dbab72fb72a2408a34c1ac6b2ecef45256d614e4858078c0186c242bf",
"format": 1
},
{
@@ -2293,7 +2363,7 @@
"name": "tests/integration/targets/cloudformation_stack_set/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8bf5d5d7a4a0cccefd6dd03a99b3f07c892ac79eebfab23eda2895905b2e8940",
+ "chksum_sha256": "4626d159b88503a0fdf49ffccc6367591d5412bd38e967a7b13771f0d937d3eb",
"format": 1
},
{
@@ -2349,14 +2419,98 @@
"name": "tests/integration/targets/cloudfront_distribution/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "471012cf65610e30d80b1c3fb23237881ab73360a5b644c40eb4f2b73cddc993",
+ "chksum_sha256": "884fdd74c1d1a3a8c6b47d3865e87b2148784ab6ee43fc69636ed719fcede58f",
"format": 1
},
{
"name": "tests/integration/targets/cloudfront_distribution/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ca9356675e8b56f45f8139b71097e596da9d951156d673e3adc37f637b230070",
+ "chksum_sha256": "7289894f07e47a82972994ae89cfaef863f54310114e1c5d7122f7fc08bc19fe",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cloudfront_invalidation",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cloudfront_invalidation/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cloudfront_invalidation/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ebbd605a81b0283d658d5307bf361c9d652f0122cb23f4742f7c3d136798878d",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cloudfront_invalidation/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cloudfront_invalidation/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "af750b27abe783562efcbef32248fc4116dc1a6b704d33632048ebc692fb53f7",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cloudfront_invalidation/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "2b58f6ba7516bc781cf36f6245d279062e8ddb6b1c2a6fedb1a07161358d6921",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cloudfront_origin_access_identity",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cloudfront_origin_access_identity/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cloudfront_origin_access_identity/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ebbd605a81b0283d658d5307bf361c9d652f0122cb23f4742f7c3d136798878d",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cloudfront_origin_access_identity/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cloudfront_origin_access_identity/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f1531bdf02a3c33a25abd3e9dd6fa7975c71f9a7e999487baadbade0c181ee8d",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cloudfront_origin_access_identity/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "2b58f6ba7516bc781cf36f6245d279062e8ddb6b1c2a6fedb1a07161358d6921",
"format": 1
},
{
@@ -2391,7 +2545,7 @@
"name": "tests/integration/targets/cloudfront_reponse_headers_policy/task/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4d1b4aadb4ef86523e8723e030487ca40b648b6af05537fa80390ddcb0e16fa1",
+ "chksum_sha256": "1516ab8a89d11cd27b3ff43454262102638c03bf2c313607a47b05d8628c9f74",
"format": 1
},
{
@@ -2461,21 +2615,21 @@
"name": "tests/integration/targets/codebuild_project/tasks/description.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7084db0a1e42a1ad274b37f780d37683431f36cfe5a42f287fb7e178c6771dd4",
+ "chksum_sha256": "0c98e0916f712ae85828f9099a0c0f6ff5c385430ba4d7c5877c859a2cfdf999",
"format": 1
},
{
"name": "tests/integration/targets/codebuild_project/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "885a36655b52cbe6c23dfd89eca74b9adcb2d570a3bafa18a62ca6e3e6d639cd",
+ "chksum_sha256": "c7d6e6f7629bf2e8c2fbdbbda47625aa310dfc2ae4dbdc74272dec45d4d6c2ba",
"format": 1
},
{
"name": "tests/integration/targets/codebuild_project/tasks/tagging.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6d4aec1182b71dd3aa574518efacc0f080cadc3f9cb05e3287fc2a070011c996",
+ "chksum_sha256": "adb5420dc5967ef8464fc00e9b5ea805a8ecac46b72cfadcc3b4ec3a170118e2",
"format": 1
},
{
@@ -2531,7 +2685,7 @@
"name": "tests/integration/targets/codecommit_repository/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7fb530f4e7c9cfede1195502bf20b5cca69dc6357da43457c6392d42b5e148e1",
+ "chksum_sha256": "92346dc3c9f5ef48ccec4448e6dbf2d1546b6771461bfd562c97a745f23f6bef",
"format": 1
},
{
@@ -2601,7 +2755,7 @@
"name": "tests/integration/targets/codepipeline/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e755c6e946c725a23a9457a0999730ae3cd1f7583c449c5405d8c9dd63997d62",
+ "chksum_sha256": "bb8700530ffe1964ba3da4ff9fd4745630418ee7265d9b47a93eefc21afb5802",
"format": 1
},
{
@@ -2629,7 +2783,7 @@
"name": "tests/integration/targets/config/defaults/main.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f94b2d41159b50f2e3d48fb790068af4bc91fa788267f800775ea7fae5573853",
+ "chksum_sha256": "0ec3fb53dbb1ee15167f5ab44435d598e66ae0cb77f473507d6a1c7dd90841b6",
"format": 1
},
{
@@ -2671,7 +2825,7 @@
"name": "tests/integration/targets/config/tasks/main.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3362b38bb4d1b1806ea300b5285b3f1ea386e25a96e87ab34eeb4331b1b7ccba",
+ "chksum_sha256": "2daab797eb69d23bff5a3d30e0f05384d037c650dda9f83f12e3d932be107178",
"format": 1
},
{
@@ -2682,6 +2836,13 @@
"format": 1
},
{
+ "name": "tests/integration/targets/config/templates/config-kms-policy.json.j2",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0bb13e44d2bce37023410704a168930a1f3969a444ae587eb4dcbdfa546bb81f",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/config/templates/config-s3-policy.json.j2",
"ftype": "file",
"chksum_type": "sha256",
@@ -2717,10 +2878,17 @@
"format": 1
},
{
+ "name": "tests/integration/targets/connection/test_assume.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "844265d0d1bc33f7c262bc3aa628e130c0833449cf2102a9766167049afb33e0",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/connection/test_connection.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "922f40a2d273045274511b3b426ddfbafbca7193cd72ad22de6719529bfd4d0e",
+ "chksum_sha256": "9956dba8bd31e66488ee81a932f69a5775367b025ef1e17ed9d85fa75ed04960",
"format": 1
},
{
@@ -2755,7 +2923,7 @@
"name": "tests/integration/targets/connection_aws_ssm_addressing/aws_ssm_integration_test_setup.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "22056e63edccac88c747444d60a990c4af4b548ddb1a86a9d75deb058a0d00aa",
+ "chksum_sha256": "2b7963e4faeef91fa0375fa47d6defb1c3ac50da36a0b4a6fe7c64569d46749e",
"format": 1
},
{
@@ -2822,196 +2990,196 @@
"format": 1
},
{
- "name": "tests/integration/targets/connection_aws_ssm_cross_region",
+ "name": "tests/integration/targets/connection_aws_ssm_centos",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/connection_aws_ssm_cross_region/meta",
+ "name": "tests/integration/targets/connection_aws_ssm_centos/meta",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/connection_aws_ssm_cross_region/meta/main.yml",
+ "name": "tests/integration/targets/connection_aws_ssm_centos/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "a935dc258dfa740bfab5f6e4a47c4dece05a773cb3177c50f45b58181a9b1e74",
"format": 1
},
{
- "name": "tests/integration/targets/connection_aws_ssm_cross_region/aliases",
+ "name": "tests/integration/targets/connection_aws_ssm_centos/aliases",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "9cf20049d8039a9fcb954c467ea44b85e2890bf06ebe4d5ec35a62d1d49d7b9e",
"format": 1
},
{
- "name": "tests/integration/targets/connection_aws_ssm_cross_region/aws_ssm_integration_test_setup.yml",
+ "name": "tests/integration/targets/connection_aws_ssm_centos/aws_ssm_integration_test_setup.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "074a8d6623529ab13e645a2746b38fa0aa37577eab5d2ffb0ad97ff86d74417d",
+ "chksum_sha256": "eb4403d62e54790741388975ce54a8c4f431182776545c5416a5226a1e9ee87d",
"format": 1
},
{
- "name": "tests/integration/targets/connection_aws_ssm_cross_region/aws_ssm_integration_test_teardown.yml",
+ "name": "tests/integration/targets/connection_aws_ssm_centos/aws_ssm_integration_test_teardown.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "68e17efa882ec51dc465da88117ed7d3bdb822103ca51acd282cce7e2f68dd38",
"format": 1
},
{
- "name": "tests/integration/targets/connection_aws_ssm_cross_region/runme.sh",
+ "name": "tests/integration/targets/connection_aws_ssm_centos/runme.sh",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "ff344e2c3c7404d48af1e93312e4d47bf935e9a28413a0bbf7c6fd54b74ca900",
"format": 1
},
{
- "name": "tests/integration/targets/connection_aws_ssm_encrypted_s3",
+ "name": "tests/integration/targets/connection_aws_ssm_cross_region",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/connection_aws_ssm_encrypted_s3/meta",
+ "name": "tests/integration/targets/connection_aws_ssm_cross_region/meta",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/connection_aws_ssm_encrypted_s3/meta/main.yml",
+ "name": "tests/integration/targets/connection_aws_ssm_cross_region/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "a935dc258dfa740bfab5f6e4a47c4dece05a773cb3177c50f45b58181a9b1e74",
"format": 1
},
{
- "name": "tests/integration/targets/connection_aws_ssm_encrypted_s3/aliases",
+ "name": "tests/integration/targets/connection_aws_ssm_cross_region/aliases",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "9cf20049d8039a9fcb954c467ea44b85e2890bf06ebe4d5ec35a62d1d49d7b9e",
"format": 1
},
{
- "name": "tests/integration/targets/connection_aws_ssm_encrypted_s3/aws_ssm_integration_test_setup.yml",
+ "name": "tests/integration/targets/connection_aws_ssm_cross_region/aws_ssm_integration_test_setup.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "592b2da3cacbbbc971e5546738c28906f6d1ed9bba273c791706c69fc017e826",
+ "chksum_sha256": "8b71ed17b15a333184c83ff9b16b3b6633bad5ec7c6c3ec8e61f104c60d2a63a",
"format": 1
},
{
- "name": "tests/integration/targets/connection_aws_ssm_encrypted_s3/aws_ssm_integration_test_teardown.yml",
+ "name": "tests/integration/targets/connection_aws_ssm_cross_region/aws_ssm_integration_test_teardown.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "68e17efa882ec51dc465da88117ed7d3bdb822103ca51acd282cce7e2f68dd38",
"format": 1
},
{
- "name": "tests/integration/targets/connection_aws_ssm_encrypted_s3/runme.sh",
+ "name": "tests/integration/targets/connection_aws_ssm_cross_region/runme.sh",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "ff344e2c3c7404d48af1e93312e4d47bf935e9a28413a0bbf7c6fd54b74ca900",
"format": 1
},
{
- "name": "tests/integration/targets/connection_aws_ssm_endpoint",
+ "name": "tests/integration/targets/connection_aws_ssm_encrypted_s3",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/connection_aws_ssm_endpoint/meta",
+ "name": "tests/integration/targets/connection_aws_ssm_encrypted_s3/meta",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/connection_aws_ssm_endpoint/meta/main.yml",
+ "name": "tests/integration/targets/connection_aws_ssm_encrypted_s3/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "a935dc258dfa740bfab5f6e4a47c4dece05a773cb3177c50f45b58181a9b1e74",
"format": 1
},
{
- "name": "tests/integration/targets/connection_aws_ssm_endpoint/aliases",
+ "name": "tests/integration/targets/connection_aws_ssm_encrypted_s3/aliases",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "9cf20049d8039a9fcb954c467ea44b85e2890bf06ebe4d5ec35a62d1d49d7b9e",
"format": 1
},
{
- "name": "tests/integration/targets/connection_aws_ssm_endpoint/aws_ssm_integration_test_setup.yml",
+ "name": "tests/integration/targets/connection_aws_ssm_encrypted_s3/aws_ssm_integration_test_setup.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8e3892a17060475e23c133887e84451e6c32709892480f99f1e2c7cacd1be05d",
+ "chksum_sha256": "240cfda6ad757bab0742479862686d5bda600d6a68dd4f2c65f47eb1007672e0",
"format": 1
},
{
- "name": "tests/integration/targets/connection_aws_ssm_endpoint/aws_ssm_integration_test_teardown.yml",
+ "name": "tests/integration/targets/connection_aws_ssm_encrypted_s3/aws_ssm_integration_test_teardown.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "68e17efa882ec51dc465da88117ed7d3bdb822103ca51acd282cce7e2f68dd38",
"format": 1
},
{
- "name": "tests/integration/targets/connection_aws_ssm_endpoint/runme.sh",
+ "name": "tests/integration/targets/connection_aws_ssm_encrypted_s3/runme.sh",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "ff344e2c3c7404d48af1e93312e4d47bf935e9a28413a0bbf7c6fd54b74ca900",
"format": 1
},
{
- "name": "tests/integration/targets/connection_aws_ssm_fedora",
+ "name": "tests/integration/targets/connection_aws_ssm_endpoint",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/connection_aws_ssm_fedora/meta",
+ "name": "tests/integration/targets/connection_aws_ssm_endpoint/meta",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/connection_aws_ssm_fedora/meta/main.yml",
+ "name": "tests/integration/targets/connection_aws_ssm_endpoint/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "a935dc258dfa740bfab5f6e4a47c4dece05a773cb3177c50f45b58181a9b1e74",
"format": 1
},
{
- "name": "tests/integration/targets/connection_aws_ssm_fedora/aliases",
+ "name": "tests/integration/targets/connection_aws_ssm_endpoint/aliases",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "9cf20049d8039a9fcb954c467ea44b85e2890bf06ebe4d5ec35a62d1d49d7b9e",
"format": 1
},
{
- "name": "tests/integration/targets/connection_aws_ssm_fedora/aws_ssm_integration_test_setup.yml",
+ "name": "tests/integration/targets/connection_aws_ssm_endpoint/aws_ssm_integration_test_setup.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0bf5b563bfd9f546398b3e7918753a794b20aef0e8d1ff1c96de51401c78ccad",
+ "chksum_sha256": "93e7d9024988ad93cb9aed3050fccaaac2444ea0432712b597e4a2355ef61f4c",
"format": 1
},
{
- "name": "tests/integration/targets/connection_aws_ssm_fedora/aws_ssm_integration_test_teardown.yml",
+ "name": "tests/integration/targets/connection_aws_ssm_endpoint/aws_ssm_integration_test_teardown.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "68e17efa882ec51dc465da88117ed7d3bdb822103ca51acd282cce7e2f68dd38",
"format": 1
},
{
- "name": "tests/integration/targets/connection_aws_ssm_fedora/runme.sh",
+ "name": "tests/integration/targets/connection_aws_ssm_endpoint/runme.sh",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "ff344e2c3c7404d48af1e93312e4d47bf935e9a28413a0bbf7c6fd54b74ca900",
@@ -3049,7 +3217,7 @@
"name": "tests/integration/targets/connection_aws_ssm_profile/aws_ssm_integration_test_setup.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2fbddb4b12de01cb5032a1197f88bbe6d099a0f10bf726fa5ae2ea8800f748bf",
+ "chksum_sha256": "1a4e1f76cd9bcb4c59113bdc0444626b526371014355e2ce3732919136ed3f1f",
"format": 1
},
{
@@ -3098,7 +3266,7 @@
"name": "tests/integration/targets/connection_aws_ssm_ssm_document/aws_ssm_integration_test_setup.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e451c4bfa160e675abbc79d9481ef7bbe952f22e64fba32177e4937d11ee8d1d",
+ "chksum_sha256": "54dd0b9662038c9ff6eb3d077b085fd579f662f0299ec78e62d0102bb697cabc",
"format": 1
},
{
@@ -3196,7 +3364,7 @@
"name": "tests/integration/targets/connection_aws_ssm_vars/aws_ssm_integration_test_setup.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4908450b802a3d8e314b5f4ff49ad1127b3a496a642ed84581cad03c38c4370b",
+ "chksum_sha256": "ea5a811a2f45d9e3781e2b9b9fe59911ae86318ce0f299ea514f0353212d86c9",
"format": 1
},
{
@@ -3238,7 +3406,7 @@
"name": "tests/integration/targets/connection_aws_ssm_windows/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9cf20049d8039a9fcb954c467ea44b85e2890bf06ebe4d5ec35a62d1d49d7b9e",
+ "chksum_sha256": "ad01935111c0178fe8ae2ee5dc08015f1d8a8511e0944896c441537742a0b4f5",
"format": 1
},
{
@@ -3308,7 +3476,7 @@
"name": "tests/integration/targets/dms_endpoint/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0e86bd37884e4ea99725bd4a7819531a795322d19b500a7cb09cec70e3afea61",
+ "chksum_sha256": "2ed33a12d9f3e10eee1f5b7f5dd028f39ef988fc3c52faa852d6fb35ba00ce31",
"format": 1
},
{
@@ -3385,7 +3553,7 @@
"name": "tests/integration/targets/dms_replication_subnet_group/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "20e8c1ea3ac3946c1c0b79223f418d3f1140ea6e55e37baa695fbdf149bb0f0e",
+ "chksum_sha256": "f9ad7c0b73e03b9f3eb518af151af70f904f2922e1321adbeaccad089974f7e3",
"format": 1
},
{
@@ -3413,7 +3581,7 @@
"name": "tests/integration/targets/dynamodb_table/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f6100a743768782dbd903d1dfd203aa9a934e58c0e7d57500f50c25763b7906d",
+ "chksum_sha256": "508a88a997fdcbf17b1251a7d9c89cf49fa8444027fef82e9031ec299e8763d7",
"format": 1
},
{
@@ -3427,7 +3595,7 @@
"name": "tests/integration/targets/dynamodb_table/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "30812647bdc4e6916e32ca6e0d8e9450e6d96fd7d4cd8696b66a0eadf9bd95e2",
+ "chksum_sha256": "568c092a1d4f28424e3df8d8aa2d2fc738e14c32d8854f970d69bb480e476afd",
"format": 1
},
{
@@ -3441,21 +3609,84 @@
"name": "tests/integration/targets/dynamodb_table/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ebf5e776f8d7b0cdbf6902b0b055d9447157978123ada7a973d4d9963a57fc9c",
+ "chksum_sha256": "564f5d43b5e448142ce041267325d9149d1743af5027a7875064248ba656ce22",
"format": 1
},
{
"name": "tests/integration/targets/dynamodb_table/tasks/test_pay_per_request.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a9f60025548dde76cf817eea7c6e5e4da25dc5b9af756d48096ef3f2f437f886",
+ "chksum_sha256": "45cf53627344eb31b7bb79bddca9d6e53d9a04a84136c5c2118e4ffd5b3e3694",
"format": 1
},
{
"name": "tests/integration/targets/dynamodb_table/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6a25dbd24e5726254fa451c380cd6ffb9b21c20a864a01fb47896ab92d0c0945",
+ "chksum_sha256": "69f6e741c00c835192318ad216acc1aeca5bc6bc928066a3676ebbc457d483a4",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/ec2_carrier_gateway",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/ec2_carrier_gateway/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/ec2_carrier_gateway/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "53741eeeb63ec126b9a7cd1970775b838663d385e84362e05b5a616fe907ef8c",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/ec2_carrier_gateway/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/ec2_carrier_gateway/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "568c092a1d4f28424e3df8d8aa2d2fc738e14c32d8854f970d69bb480e476afd",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/ec2_carrier_gateway/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/ec2_carrier_gateway/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6e9aac0df49a54677a2aba40cd0749e878704833388eea416102ca8990ba7c02",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/ec2_carrier_gateway/tasks/tags.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "b3810e1940f7dcbec8039adb39d983bb1c8d690e0fc4368ca6db1c615fff9a49",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/ec2_carrier_gateway/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "868ad2099a29b0f4de834a35f57bb18fa7072a1cc1e065435d2e7c6e322384d2",
"format": 1
},
{
@@ -3504,7 +3735,7 @@
"name": "tests/integration/targets/ec2_launch_template/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ba5fe384d872545f0fe7608470b5582b10c7dfadd5c45e2bd7fbcf6e71438b57",
+ "chksum_sha256": "1c33088718db08689d0331e05f8f62ffba98125ee70cc597b822a2d8abdc2513",
"format": 1
},
{
@@ -3532,14 +3763,14 @@
"name": "tests/integration/targets/ec2_launch_template/tasks/instance-metadata.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c85e9a789d61afbbc9b44bc498c8fd7460f1a889cf2f797d106784cb9d5f6a92",
+ "chksum_sha256": "c2c2a5a2987708baec107e0516971a21bbb4b580876aacb9a769333bc9c2bc07",
"format": 1
},
{
"name": "tests/integration/targets/ec2_launch_template/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9099b69e60a867e884055e9848aad0a7bc75e9222bc02927e9479701998206a2",
+ "chksum_sha256": "c4eee433d04b596c8143d418fa3e93b65b894b930ff6c6bffa194db167d1a3ae",
"format": 1
},
{
@@ -3553,7 +3784,7 @@
"name": "tests/integration/targets/ec2_launch_template/tasks/tags_and_vpc_settings.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6a4c60154f998d018b6c1c82fc522d8a0d08e38c26554e1e7199e76a1a7a0af5",
+ "chksum_sha256": "fd1a5eeb9430b66903a192f11b6822236a77d29e47086c46e5d8f785bbfbe7bc",
"format": 1
},
{
@@ -3616,21 +3847,21 @@
"name": "tests/integration/targets/ec2_placement_group/tasks/env_cleanup.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "554a62c6b081150c0d1e241b860a74e38bcca31e44bec9bc5fee4ef48ed59153",
+ "chksum_sha256": "d6b904d6a49be157ab02776b7db6fa68090d0d3b4ef0d64a88d09fc071ada2c6",
"format": 1
},
{
"name": "tests/integration/targets/ec2_placement_group/tasks/env_setup.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "61658f73c20b9db76c17cf247fe3f8305f7b0df51ae3a4b41640222b3c2449fc",
+ "chksum_sha256": "b38a850ad910d17efdabc6056ded17b7bcee26f7e893d86c5957943df8870d80",
"format": 1
},
{
"name": "tests/integration/targets/ec2_placement_group/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "059a8ef0b4d579012203884b54ca9384fdf1f4104c426fd8bb239228bb59ad78",
+ "chksum_sha256": "5a2c9200376e712afaf49067b0a6f8051ac5b52df6feb53cf251a7d87caf2d88",
"format": 1
},
{
@@ -3686,7 +3917,7 @@
"name": "tests/integration/targets/ec2_transit_gateway/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cf12ed96541acd4ed57ca3ddb61abf3f61869c073f66c66c59db3595f3ae9123",
+ "chksum_sha256": "9d9b2f61f864ccee1f302f93b6ac61aaaa52ec1ed7e96c270540a25958f311c1",
"format": 1
},
{
@@ -3756,7 +3987,7 @@
"name": "tests/integration/targets/ec2_transit_gateway_vpc_attachment/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "095b2eb8958113887af57fa69d067d5dc652d79579eca75370f3d507470ccbc6",
+ "chksum_sha256": "ca24ff6b034b97d4ad38bee106733c3c62d239245ccafc89af2ba1d0dcc895ee",
"format": 1
},
{
@@ -3812,7 +4043,7 @@
"name": "tests/integration/targets/ec2_vpc_egress_igw/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "af43e67395e34f85699165403bd325c658be8666f05a477b09d17064a65d586f",
+ "chksum_sha256": "8cb118c93bcf55328affb7e0e2a4680b544273972b30eed08d8846221fcaf174",
"format": 1
},
{
@@ -3882,7 +4113,7 @@
"name": "tests/integration/targets/ec2_vpc_nacl/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ffffd97b51783b27d97267c3c1f5c404963e41f96de2cd3e89752b0bbbe001f5",
+ "chksum_sha256": "345314177dac44a8f9cffa690cea4e9ee7ca571ab90466297612b172b8bfce34",
"format": 1
},
{
@@ -3959,7 +4190,7 @@
"name": "tests/integration/targets/ec2_vpc_peer/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "28e43fcefd17e48e6496391fb2ad2f71f4f56ca87a187e96be1b10f8c2ea8ff3",
+ "chksum_sha256": "8e2e5176309859bf2ec19716bf80c79de8b30a2018b47236fa38fbd2b222db9c",
"format": 1
},
{
@@ -4015,7 +4246,7 @@
"name": "tests/integration/targets/ec2_vpc_vgw/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8d37d14f9b9d93d90c337fe644c2029957a6b929fce7e8b4d547aa9e78196931",
+ "chksum_sha256": "92e57ee807a32575150a6ff277d698687ad7c17da0ac35a8e57b81c786d2c22c",
"format": 1
},
{
@@ -4064,7 +4295,7 @@
"name": "tests/integration/targets/ec2_vpc_vpn/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "46d2b0133a0ef966ff701062c6e0dabd69c8756212c6ae067208c4fce73edffb",
+ "chksum_sha256": "0c65eca77fbdfc44ce24b2a0ef1286f2b54d5f5f90977cd5c1012ed7678bf82b",
"format": 1
},
{
@@ -4134,7 +4365,7 @@
"name": "tests/integration/targets/ecs_cluster/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "80a8830c4e171ebcf66a9bbb2dccf8e4c6fb39bca5d4077ed0194e2873251340",
+ "chksum_sha256": "568c092a1d4f28424e3df8d8aa2d2fc738e14c32d8854f970d69bb480e476afd",
"format": 1
},
{
@@ -4148,7 +4379,7 @@
"name": "tests/integration/targets/ecs_cluster/tasks/01_create_requirements.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bb415c8d13620e6c1e16b5fae42ba508a0e3a56508595a019043da97223b5a76",
+ "chksum_sha256": "efd45aed9d07ce65678fe5fd85bad06e52d8330e8f7b1384a044a8848d1e6285",
"format": 1
},
{
@@ -4162,21 +4393,21 @@
"name": "tests/integration/targets/ecs_cluster/tasks/20_ecs_service.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2a01b7482a53eef389f3099b34476c7a79350c505b494310254f5e8b6fa72893",
+ "chksum_sha256": "e7c2cef87ceeb6202914dd1e3afab3d965bc3309037e08f0e96bfbd273583674",
"format": 1
},
{
"name": "tests/integration/targets/ecs_cluster/tasks/99_terminate_everything.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "490ae3411eb43eb65a8bc9f68250a00ce9bb9fe9be951ad943e4ccb7e2b77404",
+ "chksum_sha256": "a93853097a3c134e3b08d8498a5a6b9218d12c403a4ff4aab3964c88db6b0365",
"format": 1
},
{
"name": "tests/integration/targets/ecs_cluster/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "af10b2d8ff5befbe177d1a28c9663a9ce186e51033d270674b1d8558835b836b",
+ "chksum_sha256": "8b0d543a58d4adc01b5ec515c3c3974b7e520b0ccfc2cc22b7ab3c5ecd4e698f",
"format": 1
},
{
@@ -4232,7 +4463,7 @@
"name": "tests/integration/targets/ecs_ecr/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "08d279ab610a6d73302bcf40e5e6cccedbe5886d2dd603a54ba1ecb7e2fcdd4d",
+ "chksum_sha256": "2d617767cd0a8218bd504d9f1d76c56158b5f3aea48de96b8bdc73db6e3ee477",
"format": 1
},
{
@@ -4288,7 +4519,7 @@
"name": "tests/integration/targets/ecs_tag/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3c7b629c0ade54768336a2489a1f4818b261fb068fcfde43e1136114135fe424",
+ "chksum_sha256": "fa309fb0e7e8d61f85a6d0e65aa1939a00c2d45d6421cfb77a0f405d355dbc9f",
"format": 1
},
{
@@ -4344,7 +4575,7 @@
"name": "tests/integration/targets/efs/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "29aacf6bd6dcbaae5975d09e89044b9961f7592138a0eb99179e1702761c1e8c",
+ "chksum_sha256": "ea0c07cb022eeea0f23dad750aa26861e199f64e5fd605562595ab08c3efcfa5",
"format": 1
},
{
@@ -4414,14 +4645,14 @@
"name": "tests/integration/targets/eks_cluster/tasks/full_test.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "afcebd96f550de9993c2e416130c2f601f3e1b012d4448d146aaa87fdc64482d",
+ "chksum_sha256": "4eb39903b378d06cb7f278a0df8f58d36a168a97a412407d3ea73e299c37d1ad",
"format": 1
},
{
"name": "tests/integration/targets/eks_cluster/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "914f612a4166d146c9ff3224f3289f6e5ae42f2d925d2be14351836582b329d8",
+ "chksum_sha256": "bd552efddedf35e2323431cd159bf009a60d4115a4c02073938bb4bb362d9770",
"format": 1
},
{
@@ -4498,14 +4729,14 @@
"name": "tests/integration/targets/eks_fargate_profile/tasks/cleanup_eks_cluster.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2ac41fa3c2fdd78753733a08ebf36d6846e08d16ecb8299d8fbf9d4e85d12cba",
+ "chksum_sha256": "0f41043002e78a5bb1aeeab852b73cdf34339ee9b98414b82ba86bb8cf6540ef",
"format": 1
},
{
"name": "tests/integration/targets/eks_fargate_profile/tasks/create_eks_cluster.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1ddf80999c0a9aba256cf821ebc12d3177e7977f35a8a75c688d98cb13a36219",
+ "chksum_sha256": "568f82698281c509f6b951355dc20ccd4e119533a10a53c0fc8b3d24887a599c",
"format": 1
},
{
@@ -4519,7 +4750,7 @@
"name": "tests/integration/targets/eks_fargate_profile/tasks/main.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fce8e75016b18cec52e460b6254c7a83210637e99ec512438ca1ea46172a6432",
+ "chksum_sha256": "3fe610d444fbca34ba4211c95b5bdac3a892a893345b893e839908f2a605f5b9",
"format": 1
},
{
@@ -4582,35 +4813,35 @@
"name": "tests/integration/targets/eks_nodegroup/tasks/cleanup.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "38057bbd60926be52ca44f37b397c6d27d42a5ff1c7c2b92c1166161e58ec656",
+ "chksum_sha256": "e4a514b77594c21ce75f89b65ed0c2a534feae994d09523ef4039fe503f0a5d6",
"format": 1
},
{
"name": "tests/integration/targets/eks_nodegroup/tasks/dependecies.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bae338ee4b13aad2cfa9ac2fc328a8166729b8ac6e76c8121b27e20741ada6b5",
+ "chksum_sha256": "a878bdf097055ba6a0007ec40d00ec9371c99f1a306eea6e8f3b87b06f9ee7dc",
"format": 1
},
{
"name": "tests/integration/targets/eks_nodegroup/tasks/full_test.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7ebc60cd509bdce61d904ea0e77b02ea84e83577d5bd918e1571c8ba7c84bca5",
+ "chksum_sha256": "e82734eafe0d1922e57f535fcf82ddb27b485d2bf21e14814f569a622501b0ef",
"format": 1
},
{
"name": "tests/integration/targets/eks_nodegroup/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d337eb087d1ec3b2a1ce9a1d21e1ff8244b21fcef9080225a1e3b9725e8a1062",
+ "chksum_sha256": "022e78f68b60306da54d7c785bcd0ed38645595aa20bc1dd6666b62c173f34a3",
"format": 1
},
{
"name": "tests/integration/targets/eks_nodegroup/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f9fe17586a25ccaae77eb0ed119358964b244bef37696d37152ef3964a0a7afe",
+ "chksum_sha256": "aab55ff735b17633ec85d2050fea115ef0082e8246cba061964b335a60765b93",
"format": 1
},
{
@@ -4659,7 +4890,7 @@
"name": "tests/integration/targets/elasticache/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f9c9dcb2e847ee6ed349b3f28bd95b7b20f04b5f5862f391e9d49c228bfe89b8",
+ "chksum_sha256": "ab4eb1547afcaf928245196b661323b9a4c63ec76fa441873a38719e619be7bd",
"format": 1
},
{
@@ -4715,7 +4946,7 @@
"name": "tests/integration/targets/elasticache_subnet_group/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fc6760c7c485b93e3c094e633b832d0de8be11ec7e69157b86c365021f5aa373",
+ "chksum_sha256": "4f30e4a5c9eb2d3e14282787e8894c4524fac7705ee1c72120fe38fd473c83a5",
"format": 1
},
{
@@ -4771,7 +5002,7 @@
"name": "tests/integration/targets/elasticbeanstalk_app/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "49e6ec472ac39b7d6aff31a7f0f2a0d60aee79639c31c49a27c24388551e7287",
+ "chksum_sha256": "1c2e07d35a32ad5778559d018ea20aca13071ef7bb242fbe8ee059258755d068",
"format": 1
},
{
@@ -4827,7 +5058,7 @@
"name": "tests/integration/targets/elb_classic_lb_info/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4db2eddb0c919f943ab6540d90e7c44515dea128ccf63baf59692cc88ac3fad8",
+ "chksum_sha256": "fb42cd42fd956ad9097e38d06432eabaedb9ad38698ce49ed592ce68bc7ce382",
"format": 1
},
{
@@ -4904,28 +5135,28 @@
"name": "tests/integration/targets/elb_instance/tasks/cleanup_instances.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ed7b62c33be962daf2d99ecee1b0a27647d9f3100b53c8d0a5393a35ff4623b3",
+ "chksum_sha256": "7e74a9bbeae3d7a8573ce2dfee36a306a91122b73627ada6a3f3ef6ac5004210",
"format": 1
},
{
"name": "tests/integration/targets/elb_instance/tasks/cleanup_vpc.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7863ce99f4e345a5f70daa74cbd23a61773566608179eac0c980443ab2043846",
+ "chksum_sha256": "9c344918188ee98c9cef56dd89c18a3411fd15c04394539726af5069c2716ed5",
"format": 1
},
{
"name": "tests/integration/targets/elb_instance/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "01ad4c93b6036d4c021eccaae757778a6c0ae7719676558dcc4747e73d59a59f",
+ "chksum_sha256": "eca19e252f67e0b7d29e151c90a6612888567c3a8335e0a5f6cfff8f47efb93b",
"format": 1
},
{
"name": "tests/integration/targets/elb_instance/tasks/manage_asgs.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3892ab7c1d852b66306d71ed5fd6e7e2e8242ba309087bcb83c0fc6bcd76dee7",
+ "chksum_sha256": "a23171e68941eea22224e160edfed116936a7e1822e50030b1cca3d35b392871",
"format": 1
},
{
@@ -4946,14 +5177,14 @@
"name": "tests/integration/targets/elb_instance/tasks/setup_instances.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d4464aa09bac5cb90830889381cea1f4d82352ec28d97c6dc241d48838ef7fc4",
+ "chksum_sha256": "ce1a93aeadcb4c48ba22354d6284a933b93e6ead6230a38fca94e462a929679f",
"format": 1
},
{
"name": "tests/integration/targets/elb_instance/tasks/setup_vpc.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "28e80e8a1b51a99405c190083ac25872c15fb87359877b3fca9f5f9b7de40b3e",
+ "chksum_sha256": "c7b33704d4015d41ae521c7b3833453376b4e270ee3b92b088acd41ee77a3a12",
"format": 1
},
{
@@ -5030,7 +5261,7 @@
"name": "tests/integration/targets/elb_network_lb/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "71756275db9e6db7ba16600fd050489261b8e298f6882a4d43c0645ae58b7b3a",
+ "chksum_sha256": "6102f98e978e90ac3e528d10af42b0fb2cb60133473fe7a12adb9d6d4df86d32",
"format": 1
},
{
@@ -5072,14 +5303,14 @@
"name": "tests/integration/targets/elb_network_lb/tasks/test_nlb_tags.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "00b7cbe5b33ab9501bce47c2de5f41fc079e2b8f15d63d2314a1656775026844",
+ "chksum_sha256": "c2b12faeade2c2b44e5f185f0695b353c23321790fdf8268d94a8f58dac3dcce",
"format": 1
},
{
"name": "tests/integration/targets/elb_network_lb/tasks/test_nlb_with_asg.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f0022885dd65c8abe35f1d5f8d16aabaa0010e802801193db0ca0533c560649a",
+ "chksum_sha256": "a2fc0323c04333db2084fe91a1bcf8d0c96b7daf8c84c15c22d20bbd84f5df6c",
"format": 1
},
{
@@ -5121,7 +5352,7 @@
"name": "tests/integration/targets/elb_target/files/ansible_lambda_target.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "10263eec202a91c1c9dbfefe781da519abedf417b08f45c12cc087e2b87b499f",
+ "chksum_sha256": "04b46c135ce7052cf1ea685bab2ac2e01214059144718f06bcf014fa783c56ac",
"format": 1
},
{
@@ -5156,14 +5387,14 @@
"name": "tests/integration/targets/elb_target/tasks/alb_target.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7edf690ca74786ce2fbd7196241b4f520824ba6b5d2a599020a7b38e987aab7a",
+ "chksum_sha256": "533b3914aece3fef59642804eebf8022a9313afa95f9c76fa7d3a690befd4175",
"format": 1
},
{
"name": "tests/integration/targets/elb_target/tasks/ec2_target.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "72955f4944464ba33f66da28b4a77fcfb1c4210cc9c0e0a37e2647b39224764a",
+ "chksum_sha256": "73c51ac261b2d4409810771fafa5b2b0eff05c6e1165886d677f3545db753aeb",
"format": 1
},
{
@@ -5184,7 +5415,7 @@
"name": "tests/integration/targets/elb_target/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "76af6ebb3dbebac09e1aa99fdfff90253d7fac9f00c41accd39b0f79ee504069",
+ "chksum_sha256": "f9cea12c70ea54ca1552137254d1f1d584bef46267e7d077043a55081634ae25",
"format": 1
},
{
@@ -5240,7 +5471,7 @@
"name": "tests/integration/targets/elb_target_info/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "959fe482146c396f9a5fd0e870d028bcec9d810b355c96ec987523b1f7624df3",
+ "chksum_sha256": "2436f263a22b7fd7fc7c8d2275b59cb7da9aa33a67c116e121db9f13f8a57373",
"format": 1
},
{
@@ -5282,21 +5513,21 @@
"name": "tests/integration/targets/glue_connection/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4b3d8eae5617e123c403013215e25e140b5c5b6dbe8acc22f1dc6766180e3431",
+ "chksum_sha256": "af12da62144c9fff643ca8078424341c20fe82d268a810366ac77bd660bea374",
"format": 1
},
{
"name": "tests/integration/targets/glue_connection/tasks/test_connection_jdbc.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f7017a59cf2a7eff8b666f2976c9617e77c3e5948d1cb5c8851288d13c5f6f77",
+ "chksum_sha256": "a6ca87586892f6fafdca924670feee3fd3bff6058f7d21afcd21bba39602bada",
"format": 1
},
{
"name": "tests/integration/targets/glue_connection/tasks/test_connection_network.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0b60289a10890047041107242e0eb7757742650ad4205784a7244e43119ec379",
+ "chksum_sha256": "017e8427360e87a5e4ae292feadf713406732cf3a82d62b184b674013dd0c226",
"format": 1
},
{
@@ -5352,14 +5583,14 @@
"name": "tests/integration/targets/glue_crawler/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "dcb66c43d91e12b6408ca21c9494307c89a358acb75f174c0c424174214d5f50",
+ "chksum_sha256": "75af09096eb14843c8637cc7b8c92d76444cc553cb56507e1e993503638359b8",
"format": 1
},
{
"name": "tests/integration/targets/glue_crawler/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7289894f07e47a82972994ae89cfaef863f54310114e1c5d7122f7fc08bc19fe",
+ "chksum_sha256": "5f308323f63a3796fb5c025859d3a05e574ec8751abe10625b44875c32b2fb47",
"format": 1
},
{
@@ -5408,7 +5639,7 @@
"name": "tests/integration/targets/glue_job/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "219b03f1827959550bc291b524eeb3755062239e14846766c771a7ea7a41ad33",
+ "chksum_sha256": "3a16879d1bdea7ac04a46c190b7c4e8b7ef5b3d5180248f9edbb3f611b967bda",
"format": 1
},
{
@@ -5419,766 +5650,794 @@
"format": 1
},
{
- "name": "tests/integration/targets/iam_access_key",
+ "name": "tests/integration/targets/iam_saml_federation",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/iam_access_key/defaults",
+ "name": "tests/integration/targets/iam_saml_federation/defaults",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/iam_access_key/defaults/main.yml",
+ "name": "tests/integration/targets/iam_saml_federation/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "99213b23eae590103e3c4f8ee5aaa8429b55940f3c0b7a6de7dcb3a166e987a2",
+ "chksum_sha256": "6a07f3ca3a595c6a2919329c01b4e6b89cfba9ca4f83ef7f4410f629fa2ed48d",
"format": 1
},
{
- "name": "tests/integration/targets/iam_access_key/meta",
+ "name": "tests/integration/targets/iam_saml_federation/files",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/iam_access_key/meta/main.yml",
+ "name": "tests/integration/targets/iam_saml_federation/files/example1.xml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f8ba8ea297b04e2716e80fa638ac17896608394165d3d74b553ee95a6e2f8a50",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/iam_saml_federation/files/example2.xml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "3bd82bdc35dff86ad1fac766a10557de55de5bc5b5c1118965f791f9b76fb065",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/iam_saml_federation/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/iam_saml_federation/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "568c092a1d4f28424e3df8d8aa2d2fc738e14c32d8854f970d69bb480e476afd",
"format": 1
},
{
- "name": "tests/integration/targets/iam_access_key/tasks",
+ "name": "tests/integration/targets/iam_saml_federation/tasks",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/iam_access_key/tasks/main.yml",
+ "name": "tests/integration/targets/iam_saml_federation/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d82e33425e32743539216716f3f6a12a3f6482b8a986cde0dde26bd8a5d7be3f",
+ "chksum_sha256": "7f07265800e47c83e9210e0e2cb34c25958344a09f954ef10d2d10041d6d3bb6",
"format": 1
},
{
- "name": "tests/integration/targets/iam_access_key/aliases",
+ "name": "tests/integration/targets/iam_saml_federation/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "de04f53b045a9a81f3292eb82ffb295c2f0fe852269cb835b39ee0b2f94036e2",
+ "chksum_sha256": "7289894f07e47a82972994ae89cfaef863f54310114e1c5d7122f7fc08bc19fe",
"format": 1
},
{
- "name": "tests/integration/targets/iam_group",
+ "name": "tests/integration/targets/iam_server_certificate",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/iam_group/defaults",
+ "name": "tests/integration/targets/iam_server_certificate/defaults",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/iam_group/defaults/main.yml",
+ "name": "tests/integration/targets/iam_server_certificate/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3e088e1e0f22d3326400c757e02d0cd269e0f80663893ca5f479dfcc5ce75bc9",
+ "chksum_sha256": "5a80455c98b3da97451eec41c4911c1267377f610680daa969aeb6f8488a069f",
"format": 1
},
{
- "name": "tests/integration/targets/iam_group/meta",
+ "name": "tests/integration/targets/iam_server_certificate/meta",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/iam_group/meta/main.yml",
+ "name": "tests/integration/targets/iam_server_certificate/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "568c092a1d4f28424e3df8d8aa2d2fc738e14c32d8854f970d69bb480e476afd",
+ "chksum_sha256": "1e8d632f9db7209967c5b2f6d734bede09841acc7b898dafc19f31c72cee9929",
"format": 1
},
{
- "name": "tests/integration/targets/iam_group/tasks",
+ "name": "tests/integration/targets/iam_server_certificate/tasks",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/iam_group/tasks/main.yml",
+ "name": "tests/integration/targets/iam_server_certificate/tasks/generate-certs.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ac0c912c7bb892a7a8d5f17dc33de657d481210b10e7820b503a5373499dcf94",
+ "chksum_sha256": "0d73d7b651da3aa9d2609198f0c409d73d883486a296e4ff03236a70b93b0dbf",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/iam_server_certificate/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "cbde69a30d446d0b54a0f73482a019035549d19ce9ddb0f46a9e5a636b067606",
"format": 1
},
{
- "name": "tests/integration/targets/iam_group/aliases",
+ "name": "tests/integration/targets/iam_server_certificate/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "62ba9bb260bd69bc568279317f0af0d68080353adbc971f67b4ad3005634590e",
+ "chksum_sha256": "f7d1dbebc857ca0831944c1cb727aa57a0c85e7bdf4aea3bc25f690219dcc430",
"format": 1
},
{
- "name": "tests/integration/targets/iam_managed_policy",
+ "name": "tests/integration/targets/inspector_target",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/iam_managed_policy/defaults",
+ "name": "tests/integration/targets/inspector_target/defaults",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/iam_managed_policy/defaults/main.yml",
+ "name": "tests/integration/targets/inspector_target/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "be9824257f10b034325d892bb2df9e94c8825853c3f6fa8464a628b3523a53e6",
+ "chksum_sha256": "df451e67bd5645db1e553585459f2cc2a0197d4b804575e269669ea818a78e3a",
"format": 1
},
{
- "name": "tests/integration/targets/iam_managed_policy/meta",
+ "name": "tests/integration/targets/inspector_target/meta",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/iam_managed_policy/meta/main.yml",
+ "name": "tests/integration/targets/inspector_target/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "568c092a1d4f28424e3df8d8aa2d2fc738e14c32d8854f970d69bb480e476afd",
"format": 1
},
{
- "name": "tests/integration/targets/iam_managed_policy/tasks",
+ "name": "tests/integration/targets/inspector_target/tasks",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/iam_managed_policy/tasks/main.yml",
+ "name": "tests/integration/targets/inspector_target/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5e31080a6e936679c85218b356a77a4a8085db5b349cf72d9b2bbd66edc33d5d",
+ "chksum_sha256": "59e3367883093bd580b3ce83affeb6a449dbfad24c798bf7855fcd3f2dcb729f",
"format": 1
},
{
- "name": "tests/integration/targets/iam_managed_policy/aliases",
+ "name": "tests/integration/targets/inspector_target/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "51fe5871cae0634e784a3f226472c196a014820f9d1d62921b4f1c2ded249776",
+ "chksum_sha256": "34e5bb66d1cc63ebcae3934911776ed49e9f97d2016bd28c2029f6ccea543743",
"format": 1
},
{
- "name": "tests/integration/targets/iam_password_policy",
+ "name": "tests/integration/targets/inventory_aws_mq",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/iam_password_policy/meta",
+ "name": "tests/integration/targets/inventory_aws_mq/meta",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/iam_password_policy/meta/main.yml",
+ "name": "tests/integration/targets/inventory_aws_mq/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "568c092a1d4f28424e3df8d8aa2d2fc738e14c32d8854f970d69bb480e476afd",
"format": 1
},
{
- "name": "tests/integration/targets/iam_password_policy/tasks",
+ "name": "tests/integration/targets/inventory_aws_mq/playbooks",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/iam_password_policy/tasks/main.yaml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "d5cb01e8acdb276cd9dfd70b6c5f8b4c0c1abeb55c5005921df9ed8c4d310b26",
+ "name": "tests/integration/targets/inventory_aws_mq/playbooks/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/iam_password_policy/aliases",
+ "name": "tests/integration/targets/inventory_aws_mq/playbooks/tasks/find_broker.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a105d3cbc44ce95af2909fcd91224a9ed31faec15ddcd14db212cbe0098f2b75",
- "format": 1
- },
- {
- "name": "tests/integration/targets/iam_role",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
+ "chksum_sha256": "130e20cade65bbc57ba18d16772d846adccf6cee5ab9f6a38e02763f3965f619",
"format": 1
},
{
- "name": "tests/integration/targets/iam_role/defaults",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
+ "name": "tests/integration/targets/inventory_aws_mq/playbooks/tasks/mq_instance_create.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "34966187803d181c469e08c7a4dcafbf58616ddbbd8db0ef989c9e1a9564e39c",
"format": 1
},
{
- "name": "tests/integration/targets/iam_role/defaults/main.yml",
+ "name": "tests/integration/targets/inventory_aws_mq/playbooks/tasks/mq_instance_delete.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1982a4ea0d640a55c9aef81bb7b7e65bfa1755db7b7b0bb972726556c3c07c88",
+ "chksum_sha256": "204f89811b053b6e564d031a048c1b7487b939720e452c5437d3f100ce704fc3",
"format": 1
},
{
- "name": "tests/integration/targets/iam_role/files",
+ "name": "tests/integration/targets/inventory_aws_mq/playbooks/vars",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/iam_role/files/deny-all-a.json",
+ "name": "tests/integration/targets/inventory_aws_mq/playbooks/vars/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a7aec67c944af4a9861e41e4bd0df9cc39a380e44ebfab585d0e5a4a0770a18b",
+ "chksum_sha256": "6fec9f37dd6526f4e91b3b87f506bc9affb24ae8d7a8b6eff1c90dbaca9dcc8c",
"format": 1
},
{
- "name": "tests/integration/targets/iam_role/files/deny-all-b.json",
+ "name": "tests/integration/targets/inventory_aws_mq/playbooks/create_inventory_config.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d97b3f666d3daa474b035db329d8d39b4bff4ff6059ea42ebede391226681bb6",
+ "chksum_sha256": "3776cdbd09671c982db46a9cc70479f001a18fa42a0438b055acb4bb133dc8e9",
"format": 1
},
{
- "name": "tests/integration/targets/iam_role/files/deny-all.json",
+ "name": "tests/integration/targets/inventory_aws_mq/playbooks/empty_inventory_config.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d55efc743254858a5f881bf83db9d77024bee4519607261ad81417883ec3865b",
+ "chksum_sha256": "e5ed1deef488792c766710357155adc4c93554a3aee60229879547c957336b8e",
"format": 1
},
{
- "name": "tests/integration/targets/iam_role/files/deny-assume.json",
+ "name": "tests/integration/targets/inventory_aws_mq/playbooks/populate_cache.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "252bc63ef45bb6343320a9afacb88299ac8badf8b2cfbb2ecfd0a443dc28fa2f",
+ "chksum_sha256": "6f11b4980369826c6213479c20067aea4d155e9e77521853e6fc8d6855f0c163",
"format": 1
},
{
- "name": "tests/integration/targets/iam_role/meta",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/integration/targets/iam_role/meta/main.yml",
+ "name": "tests/integration/targets/inventory_aws_mq/playbooks/setup_instance.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "568c092a1d4f28424e3df8d8aa2d2fc738e14c32d8854f970d69bb480e476afd",
+ "chksum_sha256": "2a6f5fc609c3da574711edb90d343b177dc4fa0c5719b879eb558f6b33c8b235",
"format": 1
},
{
- "name": "tests/integration/targets/iam_role/tasks",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
+ "name": "tests/integration/targets/inventory_aws_mq/playbooks/test_invalid_aws_mq_inventory_config.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f6b405ef5a1076c851e42127eff82061a140c518bde73d0e30a8ed016e279861",
"format": 1
},
{
- "name": "tests/integration/targets/iam_role/tasks/boundary_policy.yml",
+ "name": "tests/integration/targets/inventory_aws_mq/playbooks/test_inventory_cache.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "aea923db757c0adc020df34045dcec9e18525a54d6b5f754bd63561670b1bc87",
+ "chksum_sha256": "e869abd699257c933eca478ad5fa463987a55872646ab43d97c86dcf001e3e7c",
"format": 1
},
{
- "name": "tests/integration/targets/iam_role/tasks/complex_role_creation.yml",
+ "name": "tests/integration/targets/inventory_aws_mq/playbooks/test_inventory_no_hosts.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7e63f22d7ab7421252e22b08c866a7806a068f1b44ea104eb496b53b90a20803",
+ "chksum_sha256": "99e6674b7c3a9f5ed8f2b32ef4a234f4976690f1f2ece48dc45efb90dd8eb934",
"format": 1
},
{
- "name": "tests/integration/targets/iam_role/tasks/creation_deletion.yml",
+ "name": "tests/integration/targets/inventory_aws_mq/playbooks/test_inventory_with_hostvars_prefix_suffix.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7688d37cd53363ac698cd415f40f9524f5a3c2216f905c0cedf0847b9f7e6652",
+ "chksum_sha256": "450af18658de10dae7d079614fea912bde84be21f869016df9ca79e28880a018",
"format": 1
},
{
- "name": "tests/integration/targets/iam_role/tasks/description_update.yml",
+ "name": "tests/integration/targets/inventory_aws_mq/playbooks/test_populating_inventory.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cc6bd8aeaa144cdc6aabb723d463e891b7e741b1acc5546e0087f891d4cd9be4",
+ "chksum_sha256": "19f2d7d72754eeb8f4d17fa6122cf19302d9d6c05c1eab276a55193e4177c4a1",
"format": 1
},
{
- "name": "tests/integration/targets/iam_role/tasks/inline_policy_update.yml",
+ "name": "tests/integration/targets/inventory_aws_mq/playbooks/test_populating_inventory_with_constructed.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cd98b995e62c3592ee32165ba9937ffb0c7db943d179f8a81d85237daaaed546",
+ "chksum_sha256": "2dc4c41ebac8d853338f52bb869cb7b11ebe81e9e2ff0921ebba241388594564",
"format": 1
},
{
- "name": "tests/integration/targets/iam_role/tasks/main.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "46745078e247345abb75ffe8ee2f448286916d86b0a492498542875cf11c9557",
+ "name": "tests/integration/targets/inventory_aws_mq/templates",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/iam_role/tasks/max_session_update.yml",
+ "name": "tests/integration/targets/inventory_aws_mq/templates/inventory.j2",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ccd7f9976ed55a32780181039bd857dfc9799b89e5c18b4d3a564fa55fd125e2",
+ "chksum_sha256": "605948bfa1c2df50c72b727154c525cfcfd048404b8dedab5cdab7b6ae9f3844",
"format": 1
},
{
- "name": "tests/integration/targets/iam_role/tasks/parameter_checks.yml",
+ "name": "tests/integration/targets/inventory_aws_mq/templates/inventory_with_cache.j2",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "56fed457d2502b5f295c36de6217ed085745bd0b5a4af177e5eae2cef6e96801",
+ "chksum_sha256": "e6c14cc965385e9780e55398b73557720496a8f7248a2c4bfb637c36eb2bbefa",
"format": 1
},
{
- "name": "tests/integration/targets/iam_role/tasks/policy_update.yml",
+ "name": "tests/integration/targets/inventory_aws_mq/templates/inventory_with_constructed.j2",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "43164d5214899ca9ff30794c037fd76602b2825659deb7a95cc1b316c95f4193",
+ "chksum_sha256": "c6a2ddaab5a6f5235c1c6532eba49152221885eaff65704d45256095a18a892c",
"format": 1
},
{
- "name": "tests/integration/targets/iam_role/tasks/role_removal.yml",
+ "name": "tests/integration/targets/inventory_aws_mq/templates/inventory_with_hostvars_prefix_suffix.j2",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0c83916a080b19600cc6705cb502584e8bcf555a3c6c0252e18a8eabc0617c1e",
+ "chksum_sha256": "23ae87d2d8f8657b81fc876522e817dc141d0a12a82c16c4962e02b8f8e235e7",
"format": 1
},
{
- "name": "tests/integration/targets/iam_role/tasks/tags_update.yml",
+ "name": "tests/integration/targets/inventory_aws_mq/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5f9bdd35dac1f840e2d4155dad4b59e7873639e6c23536d87293ee70f6af945f",
+ "chksum_sha256": "145ea3960d3bb31522c85234d7aa3a034de27220b6b9a7cb71de615a26408dc5",
"format": 1
},
{
- "name": "tests/integration/targets/iam_role/aliases",
+ "name": "tests/integration/targets/inventory_aws_mq/runme.sh",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "97a5ed23d5e2692fa5bcf34e35534a92ae914467b71a3f846b6459d4f28cddf4",
+ "chksum_sha256": "15f08fc1eb97f83e018413408f4eccd5f63d720c1cb3133cf4b0ed70d1a2514c",
"format": 1
},
{
- "name": "tests/integration/targets/iam_saml_federation",
+ "name": "tests/integration/targets/kinesis_stream",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/iam_saml_federation/defaults",
+ "name": "tests/integration/targets/kinesis_stream/defaults",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/iam_saml_federation/defaults/main.yml",
+ "name": "tests/integration/targets/kinesis_stream/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6a07f3ca3a595c6a2919329c01b4e6b89cfba9ca4f83ef7f4410f629fa2ed48d",
+ "chksum_sha256": "af176362a6d7494b15c3cb413f4a455d85e9d5ac42ef519f66b496c042e34e2a",
"format": 1
},
{
- "name": "tests/integration/targets/iam_saml_federation/files",
+ "name": "tests/integration/targets/kinesis_stream/meta",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/iam_saml_federation/files/example1.xml",
+ "name": "tests/integration/targets/kinesis_stream/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f8ba8ea297b04e2716e80fa638ac17896608394165d3d74b553ee95a6e2f8a50",
+ "chksum_sha256": "568c092a1d4f28424e3df8d8aa2d2fc738e14c32d8854f970d69bb480e476afd",
"format": 1
},
{
- "name": "tests/integration/targets/iam_saml_federation/files/example2.xml",
+ "name": "tests/integration/targets/kinesis_stream/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/kinesis_stream/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3bd82bdc35dff86ad1fac766a10557de55de5bc5b5c1118965f791f9b76fb065",
+ "chksum_sha256": "c8f0a40573fd9bc37570a0439aebb357d2a745c8f25a89522f16d975e40630f9",
"format": 1
},
{
- "name": "tests/integration/targets/iam_saml_federation/meta",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
+ "name": "tests/integration/targets/kinesis_stream/tasks/test_encryption.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "88b6f0dd4b2ceb7e4689b4b6ad84c29b6ea6d323f5a1e4e217085ae057b477d5",
"format": 1
},
{
- "name": "tests/integration/targets/iam_saml_federation/meta/main.yml",
+ "name": "tests/integration/targets/kinesis_stream/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "568c092a1d4f28424e3df8d8aa2d2fc738e14c32d8854f970d69bb480e476afd",
+ "chksum_sha256": "d691899dadb2cbc37b7f0b9234ff8728c38fadedfda3dbcfcbcdda9c6142436e",
"format": 1
},
{
- "name": "tests/integration/targets/iam_saml_federation/tasks",
+ "name": "tests/integration/targets/legacy_missing_tests",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/iam_saml_federation/tasks/main.yml",
+ "name": "tests/integration/targets/legacy_missing_tests/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/legacy_missing_tests/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "10c9a45641b9b1b275ea36b025ba4350fb058a9962cbe02604810f3aceb9dd28",
+ "chksum_sha256": "568c092a1d4f28424e3df8d8aa2d2fc738e14c32d8854f970d69bb480e476afd",
"format": 1
},
{
- "name": "tests/integration/targets/iam_saml_federation/aliases",
+ "name": "tests/integration/targets/legacy_missing_tests/README.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7289894f07e47a82972994ae89cfaef863f54310114e1c5d7122f7fc08bc19fe",
+ "chksum_sha256": "6b5def9406496656df49a49402ce869edc3db0ed88c2e2796e1a3bb6d486cb38",
"format": 1
},
{
- "name": "tests/integration/targets/iam_server_certificate",
+ "name": "tests/integration/targets/legacy_missing_tests/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "a9d7997aa08e6b143d74e6dcd8cf9b2bbf78bd89b225c181478f9c5d76a13d02",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/lightsail",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/iam_server_certificate/defaults",
+ "name": "tests/integration/targets/lightsail/defaults",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/iam_server_certificate/defaults/main.yml",
+ "name": "tests/integration/targets/lightsail/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5a80455c98b3da97451eec41c4911c1267377f610680daa969aeb6f8488a069f",
+ "chksum_sha256": "412ce5355682725393405de038e10eaeaf708b843a10aa1a77f6b9b59ce5a332",
"format": 1
},
{
- "name": "tests/integration/targets/iam_server_certificate/meta",
+ "name": "tests/integration/targets/lightsail/meta",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/iam_server_certificate/meta/main.yml",
+ "name": "tests/integration/targets/lightsail/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1e8d632f9db7209967c5b2f6d734bede09841acc7b898dafc19f31c72cee9929",
+ "chksum_sha256": "568c092a1d4f28424e3df8d8aa2d2fc738e14c32d8854f970d69bb480e476afd",
"format": 1
},
{
- "name": "tests/integration/targets/iam_server_certificate/tasks",
+ "name": "tests/integration/targets/lightsail/tasks",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/iam_server_certificate/tasks/generate-certs.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "0d73d7b651da3aa9d2609198f0c409d73d883486a296e4ff03236a70b93b0dbf",
- "format": 1
- },
- {
- "name": "tests/integration/targets/iam_server_certificate/tasks/main.yml",
+ "name": "tests/integration/targets/lightsail/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "98a7106748593f81b6c138395afe4e7b7ed97b427ee0028b9d8314b8bafa7b29",
+ "chksum_sha256": "b9868e14ab6d1fb24841a6f2d2f5a7e4a290ec0e52a6bb05ea327b0b1f41793a",
"format": 1
},
{
- "name": "tests/integration/targets/iam_server_certificate/aliases",
+ "name": "tests/integration/targets/lightsail/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f7d1dbebc857ca0831944c1cb727aa57a0c85e7bdf4aea3bc25f690219dcc430",
+ "chksum_sha256": "7289894f07e47a82972994ae89cfaef863f54310114e1c5d7122f7fc08bc19fe",
"format": 1
},
{
- "name": "tests/integration/targets/inspector_target",
+ "name": "tests/integration/targets/lightsail_snapshot",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/inspector_target/defaults",
+ "name": "tests/integration/targets/lightsail_snapshot/defaults",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/inspector_target/defaults/main.yml",
+ "name": "tests/integration/targets/lightsail_snapshot/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "df451e67bd5645db1e553585459f2cc2a0197d4b804575e269669ea818a78e3a",
+ "chksum_sha256": "702f2ba8c0d93c651ad246ba5f791f549f5f7f41ef141ce9b72185cd14df75a2",
"format": 1
},
{
- "name": "tests/integration/targets/inspector_target/meta",
+ "name": "tests/integration/targets/lightsail_snapshot/meta",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/inspector_target/meta/main.yml",
+ "name": "tests/integration/targets/lightsail_snapshot/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "568c092a1d4f28424e3df8d8aa2d2fc738e14c32d8854f970d69bb480e476afd",
"format": 1
},
{
- "name": "tests/integration/targets/inspector_target/tasks",
+ "name": "tests/integration/targets/lightsail_snapshot/tasks",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/inspector_target/tasks/main.yml",
+ "name": "tests/integration/targets/lightsail_snapshot/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "59d66364df7f01a095e473081885ef143aad97f3edf43ab6d21029a19fab2ea7",
+ "chksum_sha256": "f8d88a6fb793610b17d30ae07ae901844ef86a59c4fc4afe4eb53278241c7343",
"format": 1
},
{
- "name": "tests/integration/targets/inspector_target/aliases",
+ "name": "tests/integration/targets/lightsail_snapshot/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "34e5bb66d1cc63ebcae3934911776ed49e9f97d2016bd28c2029f6ccea543743",
- "format": 1
- },
- {
- "name": "tests/integration/targets/kinesis_stream",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
+ "chksum_sha256": "7289894f07e47a82972994ae89cfaef863f54310114e1c5d7122f7fc08bc19fe",
"format": 1
},
{
- "name": "tests/integration/targets/kinesis_stream/defaults",
+ "name": "tests/integration/targets/lightsail_static_ip",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/kinesis_stream/defaults/main.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "af176362a6d7494b15c3cb413f4a455d85e9d5ac42ef519f66b496c042e34e2a",
- "format": 1
- },
- {
- "name": "tests/integration/targets/kinesis_stream/meta",
+ "name": "tests/integration/targets/lightsail_static_ip/defaults",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/kinesis_stream/meta/main.yml",
+ "name": "tests/integration/targets/lightsail_static_ip/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "568c092a1d4f28424e3df8d8aa2d2fc738e14c32d8854f970d69bb480e476afd",
+ "chksum_sha256": "1fda63eccc1ffd3f1b83fe4538498c152a594647be1911bf550b0afd1cf73e56",
"format": 1
},
{
- "name": "tests/integration/targets/kinesis_stream/tasks",
+ "name": "tests/integration/targets/lightsail_static_ip/tasks",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/kinesis_stream/tasks/main.yml",
+ "name": "tests/integration/targets/lightsail_static_ip/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e4a11066a45915cb86de6f86349a5e75eb55ea4965625f2839c40a1bb08b7164",
+ "chksum_sha256": "e4ab3a46dc1c5192a960d3f20e69aa274e3cf19ef76ee928abf02b6186f6b0f1",
"format": 1
},
{
- "name": "tests/integration/targets/kinesis_stream/tasks/test_encryption.yml",
+ "name": "tests/integration/targets/lightsail_static_ip/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "88b6f0dd4b2ceb7e4689b4b6ad84c29b6ea6d323f5a1e4e217085ae057b477d5",
+ "chksum_sha256": "7289894f07e47a82972994ae89cfaef863f54310114e1c5d7122f7fc08bc19fe",
"format": 1
},
{
- "name": "tests/integration/targets/kinesis_stream/aliases",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "d691899dadb2cbc37b7f0b9234ff8728c38fadedfda3dbcfcbcdda9c6142436e",
+ "name": "tests/integration/targets/mq",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/legacy_missing_tests",
+ "name": "tests/integration/targets/mq/defaults",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/legacy_missing_tests/meta",
+ "name": "tests/integration/targets/mq/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "23afa4e31a7b706d88d6511814b6475d1a284bfaf89f674f011b9e24682f0ffc",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/mq/files",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/legacy_missing_tests/meta/main.yml",
+ "name": "tests/integration/targets/mq/files/broker_cfg.1.xml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "568c092a1d4f28424e3df8d8aa2d2fc738e14c32d8854f970d69bb480e476afd",
+ "chksum_sha256": "7ab097f5f6e9f5139ce2dfed5015aafa235c3b1b2222fc93c3b6c6a8cbb7b9e8",
"format": 1
},
{
- "name": "tests/integration/targets/legacy_missing_tests/README.md",
+ "name": "tests/integration/targets/mq/files/broker_cfg.1a.xml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6b5def9406496656df49a49402ce869edc3db0ed88c2e2796e1a3bb6d486cb38",
+ "chksum_sha256": "45ec2a4d3a6963916da6215971ef65cc99143779e8cb5cf3c73fa3d9eed5f9bd",
"format": 1
},
{
- "name": "tests/integration/targets/legacy_missing_tests/aliases",
+ "name": "tests/integration/targets/mq/files/broker_cfg.2.xml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ac8293442cce4eca766c53485a5012b1bdb5845f80c06a1cbcb1597323cf3ab0",
+ "chksum_sha256": "504e0e18bf825921be2c0e599c061dddda5b215aee9b0afdafc1f2b00c139626",
"format": 1
},
{
- "name": "tests/integration/targets/lightsail",
+ "name": "tests/integration/targets/mq/meta",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/lightsail/defaults",
+ "name": "tests/integration/targets/mq/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "568c092a1d4f28424e3df8d8aa2d2fc738e14c32d8854f970d69bb480e476afd",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/mq/tasks",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/lightsail/defaults/main.yml",
+ "name": "tests/integration/targets/mq/tasks/broker_cleanup.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "412ce5355682725393405de038e10eaeaf708b843a10aa1a77f6b9b59ce5a332",
+ "chksum_sha256": "7849533decca144b6aea20936fd1bf99896f0a075a7cdd63d1bf6d09374848ec",
"format": 1
},
{
- "name": "tests/integration/targets/lightsail/meta",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
+ "name": "tests/integration/targets/mq/tasks/broker_config_tests.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "b5cd6b42f31159d72000b3452e8c0adf68f6701924356f006f97ebaf253f9c36",
"format": 1
},
{
- "name": "tests/integration/targets/lightsail/meta/main.yml",
+ "name": "tests/integration/targets/mq/tasks/broker_delete_tests.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "568c092a1d4f28424e3df8d8aa2d2fc738e14c32d8854f970d69bb480e476afd",
+ "chksum_sha256": "1aff980ae48a08a717e88e9da9be8325c95f6f228e044cdf0744257505421b63",
"format": 1
},
{
- "name": "tests/integration/targets/lightsail/tasks",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
+ "name": "tests/integration/targets/mq/tasks/broker_tests.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "a0c7a612de2e8f4541a3aa1710798cf9dc72244fa7e8ad6f4c34d7030160dd3a",
"format": 1
},
{
- "name": "tests/integration/targets/lightsail/tasks/main.yml",
+ "name": "tests/integration/targets/mq/tasks/broker_user_info_tests.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6b3334073c295665f4eed394c039c45c274bddfea692b7b4bc2c9496f97080b9",
+ "chksum_sha256": "70044dc25ce55f9181017231b40495182bfc19d5b85817ce930deac653083591",
"format": 1
},
{
- "name": "tests/integration/targets/lightsail/aliases",
+ "name": "tests/integration/targets/mq/tasks/broker_user_tests.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7289894f07e47a82972994ae89cfaef863f54310114e1c5d7122f7fc08bc19fe",
+ "chksum_sha256": "361b8f4b9341c56df652066066ddeaf24aa79c75b34cec1471b5121d76406c8f",
"format": 1
},
{
- "name": "tests/integration/targets/lightsail_static_ip",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
+ "name": "tests/integration/targets/mq/tasks/env_cleanup.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "625fd0423b76e3e78fc7f3c0359ce919f9d7d93f74f64bf92b94f9988351a0fe",
"format": 1
},
{
- "name": "tests/integration/targets/lightsail_static_ip/defaults",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
+ "name": "tests/integration/targets/mq/tasks/env_setup.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fd3497e98587a07515fd2fd6c30455c90d97dd5da384ed6acd0ecda124b82664",
"format": 1
},
{
- "name": "tests/integration/targets/lightsail_static_ip/defaults/main.yml",
+ "name": "tests/integration/targets/mq/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1fda63eccc1ffd3f1b83fe4538498c152a594647be1911bf550b0afd1cf73e56",
+ "chksum_sha256": "12550040834d414ea54a8939bda4292cf0b077ece00f0edd80ece06995dfbc24",
"format": 1
},
{
- "name": "tests/integration/targets/lightsail_static_ip/tasks",
+ "name": "tests/integration/targets/mq/vars",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/lightsail_static_ip/tasks/main.yml",
+ "name": "tests/integration/targets/mq/vars/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5747d0da6dccc9cf15411438ce07223e3c412d14287944213d5c0c8750c822ec",
+ "chksum_sha256": "f52d711103d50a437830c6fbcd04fb4bab49a0f82f6d26d1c791c6e8488dd090",
"format": 1
},
{
- "name": "tests/integration/targets/lightsail_static_ip/aliases",
+ "name": "tests/integration/targets/mq/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7289894f07e47a82972994ae89cfaef863f54310114e1c5d7122f7fc08bc19fe",
+ "chksum_sha256": "0a258e27c31a3495929692dd2809edc2c43c434790ca756f841f19a57d20cd08",
"format": 1
},
{
@@ -6227,14 +6486,14 @@
"name": "tests/integration/targets/msk_cluster-auth/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a0230610bafd4916f640e41e03004852ae28d262909d7c018aa6306cf8615b05",
+ "chksum_sha256": "ecea6a84ede483a243de16e53c3fa7d08174b09eabae1a24c921c808465b16b6",
"format": 1
},
{
"name": "tests/integration/targets/msk_cluster-auth/tasks/test_create_auth.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9c16cb829596c3b2a09b00ab1906409ede7b37ca30318477e86610415962033c",
+ "chksum_sha256": "1f87bc8634bb38d681db1598f3cf0560638b667a7b4ccf8cdc420703d1a895d2",
"format": 1
},
{
@@ -6290,28 +6549,28 @@
"name": "tests/integration/targets/msk_cluster/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a4032a16508df0c6c9ad877dd4b6abef591c11d37dc4e8a0fefe75a1cc9008a6",
+ "chksum_sha256": "1cc1783a8eab0c579d89dc0d4536deb84219b32d6a8956337b1e6ac60468dc1f",
"format": 1
},
{
"name": "tests/integration/targets/msk_cluster/tasks/test_create.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "999cb11aa1ca7044c3e10856c6141b2bbfcbd454acdc9593b6bfe4996ffff00a",
+ "chksum_sha256": "6065cb2d3e5d9b69c4393cc7598f9ca3acb9dd8b674086b090ee6ae58b777505",
"format": 1
},
{
"name": "tests/integration/targets/msk_cluster/tasks/test_delete.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a3dc9b8d60fd23db2dc9cca33b3be0169c2302fd2a39cbff4f838f21e3ff8561",
+ "chksum_sha256": "52f026ae8229bd30d731ba6d90f3d37c60b172d5614c9a79eaa7fe1cfb206460",
"format": 1
},
{
"name": "tests/integration/targets/msk_cluster/tasks/test_update.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2baca7e803d0b95bade9371668b8c3f39f5b1fd58e8af6e59b12874df2cb67bb",
+ "chksum_sha256": "aa6b80606d428610d10fae177b9387a58793eef3dd488b29070c1e35ec2df6c1",
"format": 1
},
{
@@ -6367,7 +6626,7 @@
"name": "tests/integration/targets/msk_config/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "32707ed8df23393a4aba3d346bc01a3ca0cb96e4ae2ffa32ad00eb946be7edc3",
+ "chksum_sha256": "3f2d8717cf6ec5a0be82042daff04341a84a9b17e0ee4bab36926437e4ce6728",
"format": 1
},
{
@@ -6437,7 +6696,7 @@
"name": "tests/integration/targets/networkfirewall/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b8cbd969a439ec671c632a75147634023d23c1f1af0da49e133b860f397609d6",
+ "chksum_sha256": "61c31c35650bee38558f91ff72dfe03abb4bc97f30f6ee6372e6a7d4baf48e72",
"format": 1
},
{
@@ -6493,7 +6752,7 @@
"name": "tests/integration/targets/networkfirewall_policy/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "43088f43a4d8ce8720c7af4dd83ae833d4f1de0a7eccefba52daec468797c4dc",
+ "chksum_sha256": "568c092a1d4f28424e3df8d8aa2d2fc738e14c32d8854f970d69bb480e476afd",
"format": 1
},
{
@@ -6528,28 +6787,28 @@
"name": "tests/integration/targets/networkfirewall_policy/tasks/default_order.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "89cad87a3b5189c4f12ad91ad0f65b1ff3bbbdb807bcdcb82a979208aab9c3fe",
+ "chksum_sha256": "e3beb8ace412edc213ee95d80d93406e4fba4f2dc6c138db49dc631276e8486b",
"format": 1
},
{
"name": "tests/integration/targets/networkfirewall_policy/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0c5d7a955ead7a3fce020dbc75956d640a59c7f6a9ee2676e33607315306ef91",
+ "chksum_sha256": "768efc0bcf3a4c68df4a94121bcc1280b8e20bbd829284e74f10479954ad78dc",
"format": 1
},
{
"name": "tests/integration/targets/networkfirewall_policy/tasks/setup.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "277304c5175b3cd3a6a1fc08d0697a2d10e70314e37043d939278a0ae6570149",
+ "chksum_sha256": "599e0ef3d77995c82aa051d947a1ce7232c9e1829490f030fb988a11588af4f6",
"format": 1
},
{
"name": "tests/integration/targets/networkfirewall_policy/tasks/strict_order.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ab171d5fd73cde4f8f6d56a58474b088b47a112aefb51633ba511304e6ce90bc",
+ "chksum_sha256": "5b00d462ddfbf7e633ede3449b3e2347045102d0e0e183aa13ab08d79c1c518e",
"format": 1
},
{
@@ -6591,7 +6850,7 @@
"name": "tests/integration/targets/networkfirewall_rule_group/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "43088f43a4d8ce8720c7af4dd83ae833d4f1de0a7eccefba52daec468797c4dc",
+ "chksum_sha256": "568c092a1d4f28424e3df8d8aa2d2fc738e14c32d8854f970d69bb480e476afd",
"format": 1
},
{
@@ -6626,7 +6885,7 @@
"name": "tests/integration/targets/networkfirewall_rule_group/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "86a3101c318f618ae832ccfcac5ca5a994f53aa4132d01935622ca96f99189b4",
+ "chksum_sha256": "87fbae761f586d4825ce8318835862caed45eb4e0948f96396766045daa3c5e5",
"format": 1
},
{
@@ -6654,14 +6913,14 @@
"name": "tests/integration/targets/networkfirewall_rule_group/tasks/stateful.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3677e8d078f43ddb3a0de49677bbcd0f218ae8dfcfeb5b787a9c62cf3f3afc0f",
+ "chksum_sha256": "90dee38138d48c688ed47aac6314878de5859707e0c8e1f18d4cf1491a262850",
"format": 1
},
{
"name": "tests/integration/targets/networkfirewall_rule_group/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "35a0c2d65024dae4341e373aa598a54a614ef858cf11c795ed83ea10adaf0238",
+ "chksum_sha256": "c1656176c76d62eac2c32ffebbeef63835ec7c1d49aa37a64ce00bb343594ea9",
"format": 1
},
{
@@ -6710,7 +6969,7 @@
"name": "tests/integration/targets/opensearch/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e415851f75e86d82f70418129acffd9a207e6640a0d7fc34d30fa88560bbb153",
+ "chksum_sha256": "568c092a1d4f28424e3df8d8aa2d2fc738e14c32d8854f970d69bb480e476afd",
"format": 1
},
{
@@ -6724,28 +6983,28 @@
"name": "tests/integration/targets/opensearch/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "71e6a4750f3c03cd4847f6b0d55836dc2fcb63b8b6fd2da9f43e0c8c833d6099",
+ "chksum_sha256": "61fe1f21f3bc7660715b3ca1a40af263e2da797ae79b723723aff3996d8be321",
"format": 1
},
{
"name": "tests/integration/targets/opensearch/tasks/test_create_cert.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "aae6d7c07a94e14ae26295cc57194f53b546022df9e79e343f3ee3ad970950f4",
+ "chksum_sha256": "4902ef5fd11c259a4c1bff5159d2e6b890a7497979702d4ca3ccc3c796e51f62",
"format": 1
},
{
"name": "tests/integration/targets/opensearch/tasks/test_delete_resources.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "274556ec5aaabba73d362bff3565a6acfd6b14a603f8fa511e58846f3e8af080",
+ "chksum_sha256": "95c3d1dce9453b5cf1809d6b71b495c079d3a4a70ab16f56e3ffbf46b700e1e2",
"format": 1
},
{
"name": "tests/integration/targets/opensearch/tasks/test_delete_vpc_resources.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0ae272b8fa61fecd36a3b381c4cb05c48e81d6ccc517464a25ace1573332d816",
+ "chksum_sha256": "448095d236463c59f566fee92a3685abbadeaaf18c07a03ddb8767afc1dab370",
"format": 1
},
{
@@ -6759,7 +7018,7 @@
"name": "tests/integration/targets/opensearch/tasks/test_vpc_setup.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0fa749aca00d80d1ec1986ca702270c0f9c8bb276c4fd44493124a825bb1d20f",
+ "chksum_sha256": "f9b2a4628ad4585bc49a9fa83eda6443b38917f28a93304bbaa7615b8055b50d",
"format": 1
},
{
@@ -6829,7 +7088,7 @@
"name": "tests/integration/targets/redshift/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1c223ce7894790cae476629878079b47a13c9dd18c6f3805a91feaf72957811a",
+ "chksum_sha256": "861e2a9f87f02cd39c99af7a9ed2ab0a283891e432677738a79c77aff6ca124f",
"format": 1
},
{
@@ -6885,7 +7144,7 @@
"name": "tests/integration/targets/redshift_subnet_group/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1e311cba6981a7094c303486231d73b4f227388d3449e23d743cbd39f75584cb",
+ "chksum_sha256": "0357fd5816f9a6363c5fd3557b2fcb9d6e75af20d443971b50a74b22640fe71f",
"format": 1
},
{
@@ -6896,70 +7155,28 @@
"format": 1
},
{
- "name": "tests/integration/targets/s3_bucket_info",
+ "name": "tests/integration/targets/route53_wait",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/s3_bucket_info/defaults",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/integration/targets/s3_bucket_info/defaults/main.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "33402070a2915fd11eed690eae64db9b6f22f4557e808dff121ed456bebdd66d",
- "format": 1
- },
- {
- "name": "tests/integration/targets/s3_bucket_info/meta",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/integration/targets/s3_bucket_info/meta/main.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "568c092a1d4f28424e3df8d8aa2d2fc738e14c32d8854f970d69bb480e476afd",
- "format": 1
- },
- {
- "name": "tests/integration/targets/s3_bucket_info/tasks",
+ "name": "tests/integration/targets/route53_wait/tasks",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/s3_bucket_info/tasks/basic.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "2ee7b012473cfeaa0b7ddd2cfb6810facf41db62a9939c1b7ab9865caadec952",
- "format": 1
- },
- {
- "name": "tests/integration/targets/s3_bucket_info/tasks/bucket_ownership_controls.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "f617729c54e82e71a5d983ca0e96750a1a4f0db1b465c9a1e7875badb055aa7d",
- "format": 1
- },
- {
- "name": "tests/integration/targets/s3_bucket_info/tasks/main.yml",
+ "name": "tests/integration/targets/route53_wait/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0befaabe1ba20aa95d63f544d87e369c10ffe2d7c9a03e3b644310982d5c61b5",
+ "chksum_sha256": "f8da2c6560642436a25efc07bea2a785ee03f107bf5b5642a4eece46dd9b91a4",
"format": 1
},
{
- "name": "tests/integration/targets/s3_bucket_info/aliases",
+ "name": "tests/integration/targets/route53_wait/aliases",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "7289894f07e47a82972994ae89cfaef863f54310114e1c5d7122f7fc08bc19fe",
@@ -7004,7 +7221,7 @@
"name": "tests/integration/targets/s3_bucket_notification/files/mini_lambda.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5b6c842868fed1950e92f8d1824c098cecbbdd2d86cfa47aac01f16182af33b3",
+ "chksum_sha256": "671d4727fcf4c863c14fd3175714ac081cc990fa4c4e53d329fd36640945f473",
"format": 1
},
{
@@ -7032,7 +7249,7 @@
"name": "tests/integration/targets/s3_bucket_notification/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ff216849a0c08ade565ccc1e4a568dd252119c9b2c121d5ccd79608bcdd23ce2",
+ "chksum_sha256": "71876709f82e0937857ce1deb288d098217836f24fe92c0e267a766e06367411",
"format": 1
},
{
@@ -7088,7 +7305,7 @@
"name": "tests/integration/targets/s3_lifecycle/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4b50f8037d4988b787046cea58b8cf5f8fed70b81c6de886552d5fc8af2f8d30",
+ "chksum_sha256": "568c092a1d4f28424e3df8d8aa2d2fc738e14c32d8854f970d69bb480e476afd",
"format": 1
},
{
@@ -7102,14 +7319,14 @@
"name": "tests/integration/targets/s3_lifecycle/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "714b6d0f74ba602bfe6771187d386952d8343129e679b47393b91c9d1fd7c6fa",
+ "chksum_sha256": "72423890b54eaae16093a60debac1f8038eb7b9e2c2032c9672958d6736aa826",
"format": 1
},
{
"name": "tests/integration/targets/s3_lifecycle/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7289894f07e47a82972994ae89cfaef863f54310114e1c5d7122f7fc08bc19fe",
+ "chksum_sha256": "4a15fa78cf44660cba4c272436a92a637c1625a7febd23da07f9ebbf9f6c9c30",
"format": 1
},
{
@@ -7158,7 +7375,7 @@
"name": "tests/integration/targets/s3_logging/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6cc04364e8ab882de972a10f892efc1f3fc520582e8bba8fab9949810b30153c",
+ "chksum_sha256": "076b0a36063f816bc24017b40f6ccba5fc48dc8914ebe4ad06a0b36bb8373780",
"format": 1
},
{
@@ -7214,14 +7431,14 @@
"name": "tests/integration/targets/s3_metrics_configuration/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b08f6993b03927d884628237ed15a3fa3e7b916360702e0b1367cc77470ca477",
+ "chksum_sha256": "89d19c53d47f6202592167fd0f12d5b9a7d1fd895bd0e57f5fcf17a7142bc910",
"format": 1
},
{
"name": "tests/integration/targets/s3_metrics_configuration/tasks/s3_metrics_info.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f961c7cc94b4f019821227b0b68a7e25d18f45a0558ecc7e709d1a4660bd560c",
+ "chksum_sha256": "9477908a7bca8d7f957ec883e6235dd9d562967de81491d0ced566a696b0307f",
"format": 1
},
{
@@ -7305,7 +7522,7 @@
"name": "tests/integration/targets/s3_sync/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c17f555cfa7fb2639a149b4b3e08e94a4a6a68b5998ce3f9ab2a807451083dd4",
+ "chksum_sha256": "06e5560596ffbbada8288f0014d82d90b0c51111b0c5341b6199ddefebd7f841",
"format": 1
},
{
@@ -7382,28 +7599,28 @@
"name": "tests/integration/targets/secretsmanager_secret/tasks/basic.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6d4548f6028cd71381f59f8ec815a160cc53300c56d77f7314c487b4a48d2259",
+ "chksum_sha256": "7f4ff9f7987b18b686263d997d7e0d811448daf51fa4c81b77b100b3d226dd00",
"format": 1
},
{
"name": "tests/integration/targets/secretsmanager_secret/tasks/main.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9b3456cfb720c2ca7ff84800db3292959fdf0da58fd287e166f8a0f35317ac5b",
+ "chksum_sha256": "56cb7a83210085d2419a7e93c47f33966110e07b33f67bd1f09fb4edf479910b",
"format": 1
},
{
"name": "tests/integration/targets/secretsmanager_secret/tasks/replication.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ee785f54c4e4da1ae179c6239948be24a0f847bcb17c0876ab96b5147bef2871",
+ "chksum_sha256": "6d683df89cb14081f2c14d18fc2c87e0b57c411f04e9ca1693789ff8e3a71abe",
"format": 1
},
{
"name": "tests/integration/targets/secretsmanager_secret/tasks/rotation.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3be0b1305907aa6486e80aa0883f991ed51f3cba6e1774284e23836599fcebe0",
+ "chksum_sha256": "01d2a81ec50be52c30ed22608cc917025834e709a3e43ded577e7676c34e5e57",
"format": 1
},
{
@@ -7424,7 +7641,7 @@
"name": "tests/integration/targets/secretsmanager_secret/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7289894f07e47a82972994ae89cfaef863f54310114e1c5d7122f7fc08bc19fe",
+ "chksum_sha256": "f2acc4ab3ba6bf2b9cb8a3f28e7b5d4fb6a592d08fabe6b685a15a2b7b63095e",
"format": 1
},
{
@@ -7473,14 +7690,14 @@
"name": "tests/integration/targets/ses_identity/tasks/assert_defaults.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "03dcfcf5b99e5ffe1945e0e38aaab20b6604cc456b760801875fe070ff79042b",
+ "chksum_sha256": "a606c70c84e58947d1dc5922a284c37eda59cb7919995182ca63f9cb085e6fa2",
"format": 1
},
{
"name": "tests/integration/targets/ses_identity/tasks/main.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "93b1492cdcb8a8572cce9d07df4227bf22e90f325003215591329e51f1e4b221",
+ "chksum_sha256": "b5733e39813cc6c8ca99162d22143f0118fe22f518375d2f8260793f031e3a5b",
"format": 1
},
{
@@ -7536,7 +7753,7 @@
"name": "tests/integration/targets/ses_identity_policy/tasks/main.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "db37298600b429e677db25e1455dceb1f11b29a0b5fdb1f894449a56ec34f343",
+ "chksum_sha256": "623ebf3939139a5ff8e41e48e32068ed4bb078030affd81cbc45f7b7f7f06cf6",
"format": 1
},
{
@@ -7606,28 +7823,28 @@
"name": "tests/integration/targets/ses_rule_set/tasks/active-rule-set-tests.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e91a4532657a8afbf178548d91a0957ddb795245cc9be739395ba7a0375c0a29",
+ "chksum_sha256": "bf5e5f71623fe45f5350598341675684e3900cbde393c47bef674fe8c5b07a86",
"format": 1
},
{
"name": "tests/integration/targets/ses_rule_set/tasks/cleanup-lock.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8b863fce4c771fe11a9c455767c38756ea09178f41289eff6ea6914e3c45bd39",
+ "chksum_sha256": "0cbab74ce7c6a4e160178f241e2e450e9b151d781e3e54f60bd6649575558e75",
"format": 1
},
{
"name": "tests/integration/targets/ses_rule_set/tasks/inactive-rule-set-tests.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6b5cac1e3eb4ec04f71871404dc1d365388cbb6b7e797832ab6fde48d607e8e2",
+ "chksum_sha256": "ece5ab84368bc2e61850b0afa3df96a68594e771b6192ed40026def5b4915227",
"format": 1
},
{
"name": "tests/integration/targets/ses_rule_set/tasks/main.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c5877efea4d17f0f90623dbd47d93887c1da81dfa4b394e39dcb2a68447cb7ff",
+ "chksum_sha256": "9c31992c53e3208b7792b3fd03c4a2e3f4bd86f98560622eaa469b3539ca74bf",
"format": 1
},
{
@@ -7669,7 +7886,7 @@
"name": "tests/integration/targets/setup_botocore_pip/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "982778216860d979fd936609ed62defea823593c1607059c898dc75e08d7498e",
+ "chksum_sha256": "d895b8c4daee4f5a0a8e38789b1916b13193855a395c7d601f1b27bf30bef11e",
"format": 1
},
{
@@ -7739,7 +7956,7 @@
"name": "tests/integration/targets/setup_connection_aws_ssm/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "22db11d66aa0d3996727b793db5152e2277188feb1814f1046289249341dcaaa",
+ "chksum_sha256": "3c7a991fa08be350bcf60746b7c3e5db931090b82cb4f32488da548d74641fa5",
"format": 1
},
{
@@ -7774,14 +7991,14 @@
"name": "tests/integration/targets/setup_connection_aws_ssm/tasks/cleanup.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "68f1fb1a192947f04812322a2540d6b167662e599e0226ac6d41bd574976c49a",
+ "chksum_sha256": "6bf05a9289910a43c5d6adfd078beb2d30e232721147226d9b3c0ae6d16fe92a",
"format": 1
},
{
"name": "tests/integration/targets/setup_connection_aws_ssm/tasks/connection_args.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3024b12fcc79bdaf6bc5b153492ba13a895f22ec29a27dcb6f5ecc60b6e8589b",
+ "chksum_sha256": "5d5f6ae82bb735bb77cee3b614e98c1becc1455c5783b0603b8147cbf6485513",
"format": 1
},
{
@@ -7802,14 +8019,14 @@
"name": "tests/integration/targets/setup_connection_aws_ssm/tasks/encryption.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ca7c1eff754826a0bb0dc6dc411681c650f0d5144f038514c4052fda0dd60fb0",
+ "chksum_sha256": "bf5f7e849621f7a2902b7e69070d797c4af79c2fd179cc7165323e56c06a6a70",
"format": 1
},
{
"name": "tests/integration/targets/setup_connection_aws_ssm/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c67410eea59d53200e8f15f6417b100dc8a65a3e67c348f16a40feefe0f0d3ea",
+ "chksum_sha256": "9d1a04bf9a501b2ed63be47f389981c012043e4fe736e107c812c709fe1e9c2e",
"format": 1
},
{
@@ -7921,7 +8138,7 @@
"name": "tests/integration/targets/setup_ec2_facts/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c08635426696cb1d74d61cf8101bb4f912c66b5b4e17d78cdbdc45f73fcb0b91",
+ "chksum_sha256": "ce17a592baaac4abb366317269ef9c96ef83d3820126ff3e768e58e81d1ec3aa",
"format": 1
},
{
@@ -7935,7 +8152,7 @@
"name": "tests/integration/targets/setup_ec2_facts/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "568c092a1d4f28424e3df8d8aa2d2fc738e14c32d8854f970d69bb480e476afd",
+ "chksum_sha256": "ec4fa30fc4a7b9e002d1c7b3932286ace72ba36e4f532e2cc79f49d07e0794c3",
"format": 1
},
{
@@ -7949,7 +8166,7 @@
"name": "tests/integration/targets/setup_ec2_facts/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7d03d30a328d5758d05cec67692df82d906021b2d9823c6a67e8c3f51cd057d1",
+ "chksum_sha256": "b96ad83df89f7d55f3f7c7d2ba558a9d1277420e4e9be8c577a07b9733a8cf15",
"format": 1
},
{
@@ -8047,7 +8264,7 @@
"name": "tests/integration/targets/setup_sshkey/files/ec2-fingerprint.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fc12adf84deacbe3a14c4da31f5b7bbfcf57e4dc2cd7e4693e5a991a6efbaf3b",
+ "chksum_sha256": "6eef2cb8a0cdc57026118069bf9899304e544e2f9a0b36864f9d5420cd010055",
"format": 1
},
{
@@ -8124,7 +8341,7 @@
"name": "tests/integration/targets/sns/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bcdbf0fb7a0f8da36e9d01bb163cb3127a6843fe44117f1a7073ca41b28d5766",
+ "chksum_sha256": "645340198ebd7969210eae8b7e09036f4ad061c900ac415955b11f30e4f01559",
"format": 1
},
{
@@ -8173,7 +8390,7 @@
"name": "tests/integration/targets/sns_topic/files/sns_topic_lambda/sns_topic_lambda.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "26dc52059ed47d477d85a8c8fb6ae3e3dfec306d05e2ff29d62dcad98d2fb665",
+ "chksum_sha256": "8f8328a6a87a4aa960fd6473bb44380943474b40012f24df9f31458a1b811315",
"format": 1
},
{
@@ -8208,7 +8425,7 @@
"name": "tests/integration/targets/sns_topic/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bfe7c8f2d0853490e5968ff41eea72fe9a4cacff8c5d04013180800a3c444a85",
+ "chksum_sha256": "00bff28386d44b4c5681c9ab8852075291b3999c2bd8490798605ad84d8d4154",
"format": 1
},
{
@@ -8285,7 +8502,7 @@
"name": "tests/integration/targets/sqs_queue/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fc5ddbcf2f3769f063e416edbb723fd2c3dae40e7352948ac142ee709b85a3df",
+ "chksum_sha256": "bd73c6b8ceaa04b0e0e4c2f0f7a050972c8b7c00899523f4a156be93f37bdf27",
"format": 1
},
{
@@ -8341,7 +8558,7 @@
"name": "tests/integration/targets/ssm_parameter/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ba7ec7d2d63618f7542cb8d9a7c7fdd28dc2524e0a1f703542ab5e9269c6d03c",
+ "chksum_sha256": "be7c36734a74e07b0be2a976cd73be59fae415504c60153deba28dc8c865e0f2",
"format": 1
},
{
@@ -8425,7 +8642,7 @@
"name": "tests/integration/targets/stepfunctions_state_machine/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b24edc9fa457fd5cb5439cd92c14a1d5dd5cf52ba497522f9067e187735a78a3",
+ "chksum_sha256": "3c54bb8bbddeff16ad77febc3d67ba6d370f1a177e1671296acef81607a08048",
"format": 1
},
{
@@ -8436,76 +8653,6 @@
"format": 1
},
{
- "name": "tests/integration/targets/sts_assume_role",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/integration/targets/sts_assume_role/defaults",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/integration/targets/sts_assume_role/defaults/main.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "8cb5b3eb32b87c1acba7a138fb9a444d9c1dcbd740a73a60ac2edd376b88b44b",
- "format": 1
- },
- {
- "name": "tests/integration/targets/sts_assume_role/meta",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/integration/targets/sts_assume_role/meta/main.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "568c092a1d4f28424e3df8d8aa2d2fc738e14c32d8854f970d69bb480e476afd",
- "format": 1
- },
- {
- "name": "tests/integration/targets/sts_assume_role/tasks",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/integration/targets/sts_assume_role/tasks/main.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "272702cb0ed24cb574e8b0f13f3003bdcb3d26aa5eeb5fdcb17856e02786b678",
- "format": 1
- },
- {
- "name": "tests/integration/targets/sts_assume_role/templates",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/integration/targets/sts_assume_role/templates/policy.json.j2",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "aad7dcbd5c5a4650004b5455525bcff7ef9780b55b09bbf1b49369456ad7ae06",
- "format": 1
- },
- {
- "name": "tests/integration/targets/sts_assume_role/aliases",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "7289894f07e47a82972994ae89cfaef863f54310114e1c5d7122f7fc08bc19fe",
- "format": 1
- },
- {
"name": "tests/integration/targets/sts_session_token",
"ftype": "dir",
"chksum_type": null,
@@ -8551,7 +8698,7 @@
"name": "tests/integration/targets/sts_session_token/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "797a6ce7ecbd4bcce15322cf96da3d40c724ce61aaf76f239e5cdfdc1334dc58",
+ "chksum_sha256": "2f9b107bbc83c7c23ddf46839de59eeda2a89768d0f16a25e8427369ca5f7cfe",
"format": 1
},
{
@@ -8593,7 +8740,7 @@
"name": "tests/integration/targets/waf_web_acl/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "518493cfc795471221b563e655f94121d1d74adbb344507dd0b319a8e92db773",
+ "chksum_sha256": "65de73f34f03fd5404a791767b52ffb9c281a99546e9047e79612aa0ec25f696",
"format": 1
},
{
@@ -8649,7 +8796,7 @@
"name": "tests/integration/targets/wafv2/tasks/alb.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "dcc31d4757a797b348bf05e2aec8ed8cd50b04b1d8c2420b3043b8bea6f5190a",
+ "chksum_sha256": "fd78c3784d0bb94a107e00206183ed8d532c9ee45b9da7e3e5f8ee226f2dda98",
"format": 1
},
{
@@ -8663,14 +8810,14 @@
"name": "tests/integration/targets/wafv2/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6162da42e4339277ba6e75a16f3c0305846f78b765ab7b434eb235c2d855b1de",
+ "chksum_sha256": "ce26fcde81d142e1df4fd4a578fecc539a10d23907530f0cb5de167edcfc431e",
"format": 1
},
{
"name": "tests/integration/targets/wafv2/tasks/rule_group.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3cb05e8025e20292761a7b7140fe94406c7d7d61c14c068845058775a94bc623",
+ "chksum_sha256": "3e384c797bc89155b8eda4f752cc9fb05b9e5f06f14236d01f5c2b44542edf44",
"format": 1
},
{
@@ -8747,7 +8894,7 @@
"name": "tests/integration/targets/wafv2_ip_set/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4ba143352356e853990e43c1b5016edde2bf5cf036575636f8c161b631790704",
+ "chksum_sha256": "9c78b0aee774c364d76c7d47f0dcc312f3181352f1c43869c98d33271a2f6710",
"format": 1
},
{
@@ -8817,7 +8964,7 @@
"name": "tests/integration/targets/wafv2_rule_group/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6e64e904f4c4eb5473040c571b31359a88a00c26b9120dfccb7dfe6b6440c165",
+ "chksum_sha256": "98381c4b8670f0377735ec370a9ade0c85d967ef7d6f5aa68ff2ff327ad76379",
"format": 1
},
{
@@ -8887,7 +9034,7 @@
"name": "tests/integration/targets/wafv2_web_acl/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7308daea89d3121825b445219272e2aa8e318cfac7ce513f80f9c9467cc23285",
+ "chksum_sha256": "de8d980b4ab53a80311cb5ccf6e987909497ab0046496817ebe76bf16c44c37f",
"format": 1
},
{
@@ -8915,14 +9062,21 @@
"name": "tests/integration/constraints.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "591bc7bcc41461d47b97991b920ce187502c20e877eb412259f6797a1a7388f2",
+ "chksum_sha256": "13f897a645a2679a509e2921a3aa296e516a7c43f6b18a8372cd9bfae095a4fe",
"format": 1
},
{
"name": "tests/integration/requirements.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "70888db5be6bfe5255337eb4a26a9e206ebc2e9bf6c3b18976514c2777fa7df9",
+ "chksum_sha256": "54e83176165f41d8e11335c6c7a408328692e04f45c705ce0f2bd64a0f391746",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/requirements.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "2c74b1d99da40fb88dcd091936b54a61fe73c0dfcf9fe175cee4607ccb3bd8cf",
"format": 1
},
{
@@ -8943,42 +9097,63 @@
"name": "tests/sanity/ignore-2.11.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8720584a97c2e8e28e7c8c51a50c783f9ea031383dc2122a3681ecc507662f6d",
+ "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"format": 1
},
{
"name": "tests/sanity/ignore-2.12.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8720584a97c2e8e28e7c8c51a50c783f9ea031383dc2122a3681ecc507662f6d",
+ "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"format": 1
},
{
"name": "tests/sanity/ignore-2.13.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8720584a97c2e8e28e7c8c51a50c783f9ea031383dc2122a3681ecc507662f6d",
+ "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"format": 1
},
{
"name": "tests/sanity/ignore-2.14.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8720584a97c2e8e28e7c8c51a50c783f9ea031383dc2122a3681ecc507662f6d",
+ "chksum_sha256": "c9271c547f92773ba4ed8df6eb56394c85deefb66078ae7336b285aee9d252d9",
"format": 1
},
{
"name": "tests/sanity/ignore-2.15.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8720584a97c2e8e28e7c8c51a50c783f9ea031383dc2122a3681ecc507662f6d",
+ "chksum_sha256": "c9271c547f92773ba4ed8df6eb56394c85deefb66078ae7336b285aee9d252d9",
+ "format": 1
+ },
+ {
+ "name": "tests/sanity/ignore-2.16.txt",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c9271c547f92773ba4ed8df6eb56394c85deefb66078ae7336b285aee9d252d9",
+ "format": 1
+ },
+ {
+ "name": "tests/sanity/ignore-2.17.txt",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c9271c547f92773ba4ed8df6eb56394c85deefb66078ae7336b285aee9d252d9",
"format": 1
},
{
"name": "tests/sanity/ignore-2.9.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "41aa5d215ac45215b5398be241ab9f33ae157cf6874cc3c8a8179bb3a84e8655",
+ "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ "format": 1
+ },
+ {
+ "name": "tests/sanity/requirements.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "71afcdc49ddb153ed00b7af0d3e15b9821d5921fe8af6447e9e8867463b28c01",
"format": 1
},
{
@@ -9006,21 +9181,7 @@
"name": "tests/unit/compat/builtins.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7163336aa20ba9db9643835a38c25097c8a01d558ca40869b2b4c82af25a009c",
- "format": 1
- },
- {
- "name": "tests/unit/compat/mock.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "0af958450cf6de3fbafe94b1111eae8ba5a8dbe1d785ffbb9df81f26e4946d99",
- "format": 1
- },
- {
- "name": "tests/unit/compat/unittest.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "5401a046e5ce71fa19b6d905abd0f9bdf816c0c635f7bdda6730b3ef06e67096",
+ "chksum_sha256": "9f93829747b69dc5f5feafae69e9dd73bcf093425a6784b720ffafd98be2eb4d",
"format": 1
},
{
@@ -9041,35 +9202,35 @@
"name": "tests/unit/mock/loader.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cfe3480f0eae6d3723ee62d01d00a0e9f58fcdc082ea1d8e4836157c56d4fa95",
+ "chksum_sha256": "b5fc5835142013d1fface268232ec402bf512e170c5a19f787e8ebf997287209",
"format": 1
},
{
"name": "tests/unit/mock/path.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "245e913b4f4cd7bc334b3f4dfc851dc4ec0d297f57bba03703b987a48df9c76c",
+ "chksum_sha256": "43365b95bab3fd31d1a1af3429d9abd0b8be39c7a6273390982da71dc03a9633",
"format": 1
},
{
"name": "tests/unit/mock/procenv.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cba88dd59128f6e70be7d022fe05201689a171c307a100a19142431ab3a707dd",
+ "chksum_sha256": "e0fef92aba32287e1a98d3e3def0aeb99c630cc661f17c8ea4d50d2f39a8f1ce",
"format": 1
},
{
"name": "tests/unit/mock/vault_helper.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1c5bb024ac2f936a8755eca00fb6e43f2a72dac131fe07f1ed0249dc29504ee0",
+ "chksum_sha256": "d4396f88cc9fcfa2eb2f64cc74cb34836dfc53bd64caba1cd2c702abacfe877a",
"format": 1
},
{
"name": "tests/unit/mock/yaml_helper.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cd95a4807e52e9123a8d40132a5f52b75cbc1496e1a32b104b2655bf631cfee4",
+ "chksum_sha256": "0faf6b227f7dda38b0294634f0642370e1cf527b1d7f2383805090aceadd2c4a",
"format": 1
},
{
@@ -9097,7 +9258,28 @@
"name": "tests/unit/plugins/connection/test_aws_ssm.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2ee7c115d8f0af46509d68f2e6072a217004b97ca569d1fadf10e2d66ce71e4e",
+ "chksum_sha256": "5a11663cddcfe3a4bdb8ab0ec4eb4d2080ad4d558809a786f4e9074cc6b5f0a3",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/inventory",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/inventory/__init__.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/inventory/test_aws_mq.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "035408796c251f8ff8c12879dad71c963c50c0c224a2b777a218bf07b996198c",
"format": 1
},
{
@@ -12954,98 +13136,105 @@
"name": "tests/unit/plugins/modules/conftest.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "909818cefd5093894a41494d1e43bd625538f57821375a564c52fe4219960967",
+ "chksum_sha256": "81e71af2ccd3142d9920cc5556b457be917c22e53e6053ed6267a452982b4147",
"format": 1
},
{
"name": "tests/unit/plugins/modules/test_acm_certificate.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c8d9dc4d3b222057ea2dd88de45b4edfefe570103c25df6b9cd7791d2a5ed441",
+ "chksum_sha256": "8b111ce566fca4947c766db075a9b2f31080cc43ace00d12e2fddf4ede754e00",
"format": 1
},
{
"name": "tests/unit/plugins/modules/test_api_gateway.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5f3e50f86d71c39b638654e4beaa912bf8d872cf485d08dfa885d388e48cb635",
+ "chksum_sha256": "d4c41a79ca896e841e24c40e7d3f5a285eb78dd72551ae63c180f7934d6e9bdb",
"format": 1
},
{
"name": "tests/unit/plugins/modules/test_data_pipeline.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8b71a110087842ba2670f50c69dca631e6cab624fc6a691291242423e4a654ed",
+ "chksum_sha256": "a8697fb31630a20574f5f81f467adc50257040116cdcead6438410cea736df3d",
"format": 1
},
{
"name": "tests/unit/plugins/modules/test_directconnect_confirm_connection.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "16c2fd15a17f38f268b9502f50fdf5436531709a70122b9d6b38130e04d78aed",
+ "chksum_sha256": "2b5240fde9db0aa9e3e14f254b06a9972793804cf1b075d2a1b1bb028428d017",
"format": 1
},
{
"name": "tests/unit/plugins/modules/test_directconnect_connection.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f52f6e3aa547e323a44fd9a8b6dfffc393b9f9414d76d4c09ed0be8998fa6490",
+ "chksum_sha256": "81c66fbda98ccbac133e8e6fe1e9f0277e3419c129134c9cf918502871b929bc",
"format": 1
},
{
"name": "tests/unit/plugins/modules/test_directconnect_link_aggregation_group.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e9d9280af13327edd0d08012655c65fdc6cc2db796b83ab27542323cfbdf5b3e",
+ "chksum_sha256": "996521133d39909cfa46ec11427f9eeeae33de0f6c52684273508677c3a3870a",
"format": 1
},
{
"name": "tests/unit/plugins/modules/test_directconnect_virtual_interface.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1e16f8fb2dce702bb3ff65a7bcc34bfb460c2d45965ffb1b202a814e85cfc1a5",
+ "chksum_sha256": "ca4e6235b712aa1fdfb3140db626d29b048a06bbe09a051820496af9f8c42acc",
"format": 1
},
{
"name": "tests/unit/plugins/modules/test_ec2_vpc_vpn.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6811508e0027e7f15f32983c4952c83f91f3fa0a9bb2ab8b4a8be2175d33964c",
+ "chksum_sha256": "94fb060fbaf50535f6ea148564a2edc422b7cbc446edecf0f75d02a992695f2c",
"format": 1
},
{
"name": "tests/unit/plugins/modules/test_ec2_win_password.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0baf51af954156925dc18084ae4acf860b826165fb8f0d4eebfd07cde8c3835c",
+ "chksum_sha256": "fea620774cb090935afe45f7ed859293fcc5bbc3d959dcb1dacd7b96dead8a6d",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/modules/test_opensearch.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "940d1424565b5b47244263dcccbeb3ce40fa52703b11d7abb021344684a46329",
"format": 1
},
{
- "name": "tests/unit/plugins/modules/test_iam_password_policy.py",
+ "name": "tests/unit/plugins/modules/test_redshift_cross_region_snapshots.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "49e13f05a469cee2a210d11d3014aedb7223dd26f607e2330d9a8be776f6ba72",
+ "chksum_sha256": "c58e54120724d9cca27440a55466fb44940420f0fabce15ba512183d34b7edcf",
"format": 1
},
{
- "name": "tests/unit/plugins/modules/test_opensearch.py",
+ "name": "tests/unit/plugins/modules/test_route53_wait.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8da1eb0aaffc76cedccfeef40a874b88ef98a5d678cccd299627b76cddc48fa1",
+ "chksum_sha256": "052e79e5bf916a83235def24c6ad2fef6c32239dad53ab2e597220c9ca4bea5d",
"format": 1
},
{
- "name": "tests/unit/plugins/modules/test_redshift_cross_region_snapshots.py",
+ "name": "tests/unit/plugins/modules/test_ssm_inventory_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "47804b0d95dc8868f340c09678cf8ae4cccdc2990c0b40786fa0ae6416b01f50",
+ "chksum_sha256": "02a8d350f832fd87c4805c66d0c4086b3854b5f84fe951ef753720c466e1015e",
"format": 1
},
{
"name": "tests/unit/plugins/modules/utils.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6dbf5791f5fb392bbc72347d7da850058fdd613b51966a68e1f8022f8ac69eba",
+ "chksum_sha256": "5c553ea4bf90da544abac8dd1bda0b8714ddb22d8a39d17d178ccd9222db688d",
"format": 1
},
{
@@ -13066,7 +13255,7 @@
"name": "tests/unit/constraints.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "591bc7bcc41461d47b97991b920ce187502c20e877eb412259f6797a1a7388f2",
+ "chksum_sha256": "bc0121f23632af60e317c297eeebd434aebe98064c9631c2a69e8e5880eb725f",
"format": 1
},
{
@@ -13077,6 +13266,13 @@
"format": 1
},
{
+ "name": "tests/unit/requirements.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "71afcdc49ddb153ed00b7af0d3e15b9821d5921fe8af6447e9e8867463b28c01",
+ "format": 1
+ },
+ {
"name": "tests/.gitignore",
"ftype": "file",
"chksum_type": "sha256",
@@ -13087,7 +13283,7 @@
"name": "tests/config.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9d75ecdecbd76691b04ec2d5fcf9241a4366801e6a1e5db09785453cd429c862",
+ "chksum_sha256": "1c08c8ebb64b4244179f4ceee7e9074c0e0a7696f299bd9659fe09381a2eebdb",
"format": 1
},
{
@@ -13098,31 +13294,31 @@
"format": 1
},
{
- "name": "tests/requirements.yml",
+ "name": ".gitignore",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "66fad8a0eb762fc61d4aa6c516d876f6bb89e73cfad5c005e78c3f4a2fd91aa5",
+ "chksum_sha256": "554f1be4f521490671cb70f96f35a8a98c2d7f92b751ea76ce7665869b283d9a",
"format": 1
},
{
- "name": ".gitignore",
+ "name": ".yamllint",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ec8428728dab8be96951a9aa637a77e33ef67bd444a56295d2867e2426d481d9",
+ "chksum_sha256": "20f14c567d8ba0813a1ae58e298093a8004e4657baed321e4567de0f676beeaf",
"format": 1
},
{
"name": "CHANGELOG.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "64943fcf1cb90ec0ae493011dcbef073aec7f5c235aaf36e53890a60cbd15826",
+ "chksum_sha256": "5c20e11dfc1704180b5d197a68107a5a6092c324a99739646c42bb0e1a0dc8a4",
"format": 1
},
{
"name": "CONTRIBUTING.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ae3f61010c5c9821d0a566b841867f78dd594a948abac7fdc784029c5222f4fc",
+ "chksum_sha256": "550c8671e9531921c7c20bb2b6c926060a527f6dfc0bd9fc76b25d6a0651100a",
"format": 1
},
{
@@ -13136,7 +13332,7 @@
"name": "README.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "db5e1c1064e561f142f8dc83a5105353497b31e55c23bcc756e67030e728b0a6",
+ "chksum_sha256": "258051287346af763659d20980984c8c5689e0b5d3e6ce2bdaa1f597a2013ded",
"format": 1
},
{
@@ -13147,17 +13343,31 @@
"format": 1
},
{
+ "name": "pyproject.toml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "da49e18617bd8f6350e2e92c4ef5366aa8423c1aa9de01cff6bfdd7fa604ab4e",
+ "format": 1
+ },
+ {
"name": "requirements.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "69d234edeaedcedfa2e796dc5f0f9ddabad4bfb3959100d8814a07cedf702c2f",
+ "chksum_sha256": "2c71169e5f0cdc74b4e423519a95fe50a499c1c9163d9550ccd7cba56e9901a6",
"format": 1
},
{
"name": "test-requirements.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "be6aa80a131f3e7fac406bccaae2e693de33f22e82ef9bdb6e2cbbdf008c4a21",
+ "chksum_sha256": "5dcd51d5a5f8631fa8466420f4eb6302cec4ce4e5ea10ee3199602bd36a2bc75",
+ "format": 1
+ },
+ {
+ "name": "tox.ini",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "1201123003e01af03ffb7cf8669ea1fc7a8ddc0bff1a181c2484d0bd0087ed5e",
"format": 1
}
],
diff --git a/ansible_collections/community/aws/MANIFEST.json b/ansible_collections/community/aws/MANIFEST.json
index 437a04742..224e6ba06 100644
--- a/ansible_collections/community/aws/MANIFEST.json
+++ b/ansible_collections/community/aws/MANIFEST.json
@@ -2,7 +2,7 @@
"collection_info": {
"namespace": "community",
"name": "aws",
- "version": "5.5.0",
+ "version": "7.1.0",
"authors": [
"Ansible (https://github.com/ansible)"
],
@@ -13,14 +13,14 @@
"cloud",
"amazon"
],
- "description": null,
+ "description": "A variety of Ansible content to help automate the management of AWS services.",
"license": [],
"license_file": "COPYING",
"dependencies": {
- "amazon.aws": ">=5.0.0"
+ "amazon.aws": ">=7.0.0,<8.0.0"
},
"repository": "https://github.com/ansible-collections/community.aws",
- "documentation": "https://ansible-collections.github.io/community.aws/branch/stable-5/collections/community/aws/index.html",
+ "documentation": "https://ansible-collections.github.io/community.aws/branch/stable-7/collections/community/aws/index.html",
"homepage": "https://github.com/ansible-collections/community.aws",
"issues": "https://github.com/ansible-collections/community.aws/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc"
},
@@ -28,7 +28,7 @@
"name": "FILES.json",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "91fe278d2365d772b572ea028dcb97117d3e98e74569adf6c63b6e7d89e8c74e",
+ "chksum_sha256": "efadd5485c903284fc4f80439e50ff696569304185ef6c966c442c2b5603c5c8",
"format": 1
},
"format": 1
diff --git a/ansible_collections/community/aws/README.md b/ansible_collections/community/aws/README.md
index 1a4bf3232..ba02cf6db 100644
--- a/ansible_collections/community/aws/README.md
+++ b/ansible_collections/community/aws/README.md
@@ -1,12 +1,12 @@
# Community AWS Collection
-The Ansible Community AWS collection includes a variety of Ansible content to help automate the management of AWS instances. This collection is maintained by the Ansible community.
+The Ansible Community AWS collection includes a variety of Ansible content to help automate the management of AWS services. This collection is maintained by the Ansible community.
AWS related modules and plugins supported by the Ansible Cloud team are in the [amazon.aws](https://github.com/ansible-collections/amazon.aws) collection.
## Ansible version compatibility
-Tested with the Ansible Core 2.12, and 2.13 releases, and the current development version of Ansible. Ansible Core versions before 2.11.0 are not supported. In particular, Ansible Core 2.10 and Ansible 2.9 are not supported.
+Tested with the Ansible Core >= 2.12.0 versions, and the current development version of Ansible. Ansible Core versions before 2.12.0 are not supported.
Use community.aws 4.x.y if you are using Ansible 2.9 or Ansible Core 2.10.
@@ -14,24 +14,39 @@ Use community.aws 4.x.y if you are using Ansible 2.9 or Ansible Core 2.10.
This collection depends on the AWS SDK for Python (Boto3 and Botocore). Due to the
[AWS SDK Python Support Policy](https://aws.amazon.com/blogs/developer/python-support-policy-updates-for-aws-sdks-and-tools/)
-this collection requires Python 3.6 or greater.
-
-Amazon have also announced the end of support for
-[Python less than 3.7](https://aws.amazon.com/blogs/developer/python-support-policy-updates-for-aws-sdks-and-tools/).
-As such support for Python less than 3.7 by this collection has been deprecated and will be removed in a release
-after 2023-05-31.
+this collection requires Python 3.7 or greater.
+
+Amazon have also announced the planned end of support for
+[Python less than 3.8](https://aws.amazon.com/blogs/developer/python-support-policy-updates-for-aws-sdks-and-tools/).
+As such support for Python less than 3.8 will be removed in a release after 2024-12-01.
+
+<!---
+### End of Support by Python Versions:
+
+| Python Version | AWS SDK | Collection |
+| -------------- | -------- | ---------- |
+| 2.7 | July 2021 | Release 2.0.0 (September 2021) |
+| 3.4 | February 2021 | Release 1.0.0 (June 2020) |
+| 3.5 | February 2021 | Release 2.0.0 (September 2021) |
+| 3.6 | May 2022 | Release 7.0.0 (November 2023) |
+| 3.7 | December 2023 | *After December 2024* |
+| 3.8 | April 2025 | *After April 2026* |
+| 3.9 | April 2026 | *After April 2027* |
+| 3.10 | April 2027 | *After April 2028* |
+| 3.11 | April 2028 | *After April 2029* |
+--->
## AWS SDK version compatibility
Starting with the 2.0.0 releases of amazon.aws and community.aws, it is generally the collection's policy to support the versions of `botocore` and `boto3` that were released 12 months prior to the most recent major collection release, following semantic versioning (for example, 2.0.0, 3.0.0).
-Version 5.0.0 of this collection supports `boto3 >= 1.18.0` and `botocore >= 1.21.0`
+Version 7.0.0 of this collection supports `boto3 >= 1.26.0` and `botocore >= 1.29.0`
All support for the original AWS SDK `boto` was removed in release 4.0.0.
## Included content
<!--start collection content-->
-See the complete list of collection content in the [Plugin Index](https://ansible-collections.github.io/community.aws/branch/stable-5/collections/community/aws/index.html#plugin-index).
+See the complete list of collection content in the [Plugin Index](https://ansible-collections.github.io/community.aws/branch/stable-7/collections/community/aws/index.html#plugin-index).
<!--end collection content-->
@@ -90,7 +105,7 @@ You can either call modules by their Fully Qualified Collection Name (FQCN), suc
### See Also:
-* [Amazon Web Services Guide](https://docs.ansible.com/ansible/latest/scenario_guides/guide_aws.html)
+* [Amazon Web Services Guide](https://docs.ansible.com/ansible/latest/collections/amazon/aws/docsite/guide_aws.html)
* [Ansible Using collections](https://docs.ansible.com/ansible/latest/user_guide/collections_using.html) for more details.
## Contributing to this collection
@@ -106,12 +121,12 @@ You can also join us on:
- [Ansible Community Guide](https://docs.ansible.com/ansible/latest/community/index.html) - Details on contributing to Ansible
- [Contributing to Collections](https://docs.ansible.com/ansible/devel/dev_guide/developing_collections.html#contributing-to-collections) - How to check out collection git repositories correctly
-- [Guidelines for Ansible Amazon AWS module development](https://docs.ansible.com/ansible/latest/dev_guide/platforms/aws_guidelines.html)
+- [Guidelines for Ansible Amazon AWS module development](https://docs.ansible.com/ansible/latest/collections/amazon/aws/docsite/dev_guidelines.html)
- [Getting Started With AWS Ansible Module Development and Community Contribution](https://www.ansible.com/blog/getting-started-with-aws-ansible-module-development)
## Release notes
-See the [rendered changelog](https://ansible-collections.github.io/community.aws/branch/stable-5/collections/community/aws/docsite/CHANGELOG.html) or the [raw generated changelog](https://github.com/ansible-collections/community.aws/tree/stable-5/CHANGELOG.rst).
+See the [rendered changelog](https://ansible-collections.github.io/community.aws/branch/stable-7/collections/community/aws/docsite/CHANGELOG.html) or the [raw generated changelog](https://github.com/ansible-collections/community.aws/tree/stable-7/CHANGELOG.rst).
## Roadmap
diff --git a/ansible_collections/community/aws/changelogs/changelog.yaml b/ansible_collections/community/aws/changelogs/changelog.yaml
index ee3f2b9ab..ea65a58be 100644
--- a/ansible_collections/community/aws/changelogs/changelog.yaml
+++ b/ansible_collections/community/aws/changelogs/changelog.yaml
@@ -28,7 +28,7 @@ releases:
- cloudwatchlogs_log_group - Fix a KeyError when updating a log group that does
not have a retention period (https://github.com/ansible/ansible/issues/47945)
- cloudwatchlogs_log_group_info - remove limitation of max 50 results
- - ec2_asg - Ensure "wait" is honored during replace operations
+ - ec2_asg - Ensure ``wait`` is honored during replace operations
- ec2_launch_template - Update output to include latest_version and default_version,
matching the documentation
- ec2_transit_gateway - Use AWSRetry before ClientError is handled when describing
@@ -1581,6 +1581,73 @@ releases:
- 970-redshift_info-boto-import.yml
- 977-add-backoff-logic-elb-info.yml
release_date: '2022-03-30'
+ 2.5.0:
+ changes:
+ bugfixes:
+ - ecs_service - add missing change detect of ``health_check_grace_period_seconds``
+ parameter (https://github.com/ansible-collections/community.aws/pull/1145).
+ - ecs_service - fix broken compare of ``task_definition`` that results always
+ in a changed task (https://github.com/ansible-collections/community.aws/pull/1145).
+ - ecs_service - fix validation for ``placement_constraints``. It's possible
+ to use ``distinctInstance`` placement constraint now (https://github.com/ansible-collections/community.aws/issues/1058)
+ - ecs_taskdefinition - fix broken change detect of ``launch_type`` parameter
+ (https://github.com/ansible-collections/community.aws/pull/1145).
+ - execute_lambda - fix check mode and update RETURN documentation (https://github.com/ansible-collections/community.aws/pull/1115).
+ - iam_policy - require one of ``policy_document`` and ``policy_json`` when state
+ is present to prevent MalformedPolicyDocumentException from being thrown (https://github.com/ansible-collections/community.aws/pull/1093).
+ - s3_lifecycle - add support of value *0* for ``transition_days`` (https://github.com/ansible-collections/community.aws/pull/1077).
+ - s3_lifecycle - check that configuration is complete before returning (https://github.com/ansible-collections/community.aws/pull/1085).
+ minor_changes:
+ - iam_policy - update broken examples and add RETURN section to documentation;
+ add extra integration tests for idempotency check mode runs (https://github.com/ansible-collections/community.aws/pull/1093).
+ - iam_role - delete inline policies prior to deleting role (https://github.com/ansible-collections/community.aws/pull/1054).
+ - iam_role - remove global vars and refactor accordingly (https://github.com/ansible-collections/community.aws/pull/1054).
+ release_summary: This is the minor release of the ``community.aws`` collection.
+ fragments:
+ - 0000-ecs_taskdefinition_fix.yml
+ - 1054-iam_role-delete-inline-policies-and-refactor.yml
+ - 1077-s3_lifecycle-transition-days-zero.yml
+ - 1085-s3_lifecycle-check-that-configuration-is-complete-before-returning.yml
+ - 1093-iam_policy-update-docs-and-add-required_if.yml
+ - 1115-execute_lambda-checkmode-fix-update-return-docs.yml
+ - 1300-ecs_service-placementConstraints.yml
+ - 2.5.0.yml
+ release_date: '2022-05-30'
+ 2.6.0:
+ changes:
+ bugfixes:
+ - ecs_service - fix broken change detect of ``health_check_grace_period_seconds``
+ parameter when not specified (https://github.com/ansible-collections/community.aws/pull/1212).
+ - ecs_service - use default cluster name of ``default`` when not input (https://github.com/ansible-collections/community.aws/pull/1212).
+ - ecs_task - dont require ``cluster`` and use name of ``default`` when not input
+ (https://github.com/ansible-collections/community.aws/pull/1212).
+ - wafv2_ip_set - fix bug where incorrect changed state was returned when only
+ changing the description (https://github.com/ansible-collections/community.aws/pull/1211).
+ minor_changes:
+ - ecs_service - ``deployment_circuit_breaker`` has been added as a supported
+ feature (https://github.com/ansible-collections/community.aws/pull/1215).
+ - ecs_service - add ``service`` alias to address the ecs service name with the
+ same parameter as the ecs_service_info module is doing (https://github.com/ansible-collections/community.aws/pull/1187).
+ - ecs_service_info - add ``name`` alias to address the ecs service name with
+ the same parameter as the ecs_service module is doing (https://github.com/ansible-collections/community.aws/pull/1187).
+ release_summary: 'This is the last planned 2.x release of the ``community.aws``
+ collection.
+
+ Consider upgrading to the latest version of ``community.aws`` soon.'
+ fragments:
+ - 0001-ecs-service-aliases.yml
+ - 1211-wafv2_ip_set-description.yml
+ - 1212-ecs_service-fix-broken-change-detect.yml
+ - 1215-ecs-service-deployment-circuit-breaker-support.yml
+ - 2.6.0.yml
+ release_date: '2022-06-22'
+ 2.6.1:
+ changes:
+ release_summary: Bump collection from 2.6.0 to 2.6.1 due to a publishing error
+ with 2.6.0. This release supersedes 2.6.0 entirely, users should skip 2.6.0.
+ fragments:
+ - 261_increase.yml
+ release_date: '2022-06-22'
3.0.0:
changes:
breaking_changes:
@@ -1988,7 +2055,7 @@ releases:
- route53_info - The CamelCase return values for ``HostedZones``, ``ResourceRecordSets``,
and ``HealthChecks`` have been deprecated, in the future release you must
use snake_case return values ``hosted_zones``, ``resource_record_sets``, and
- ``health_checks`` instead respectively".
+ ``health_checks`` instead respectively.
minor_changes:
- aws_codebuild - add support for ``purge_tags`` parameter (https://github.com/ansible-collections/community.aws/pull/1221).
- aws_codebuild - add the ``resource_tags`` parameter which takes the dictionary
@@ -2063,6 +2130,31 @@ releases:
- 580-vpc_peer-idempotency.yml
- 645-aws_config_aggregator-fix-update-and-idempotency.yml
release_date: '2022-08-03'
+ 3.6.0:
+ changes:
+ bugfixes:
+ - ec2_placement_group - Handle a potential race creation during the creation
+ of a new Placement Group (https://github.com/ansible-collections/community.aws/pull/1477).
+ - s3_lifecycle - fix bug when deleting rules with an empty prefix (https://github.com/ansible-collections/community.aws/pull/1398).
+ minor_changes:
+ - autoscaling_group_info - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+ - cloudfront_distribution - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+ - cloudfront_origin_access_identity - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+ - cloudtrail - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+ - ec2_asg_lifecycle_hook - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+ - ec2_vpc_nacl - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+ - redshift - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+ - s3_bucket_info - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+ release_summary: 'Following the release of community.aws 5.0.0, 3.6.0 is a bugfix
+ release and the final planned release for the 3.x series.
+
+ '
+ fragments:
+ - 1398-s3_lifecycle-no-prefix.yml
+ - 1410-linting.yml
+ - RELEASE-3.6.0.yml
+ - ec2_placement_group_race_on_create.yaml
+ release_date: '2022-10-06'
4.0.0:
changes:
breaking_changes:
@@ -2328,7 +2420,7 @@ releases:
- aws_kms_info - the unused and deprecated ``keys_attr`` parameter has been
removed (https://github.com/ansible-collections/amazon.aws/pull/1172).
- data_pipeline - the ``version`` option has always been ignored and has been
- removed (https://github.com/ansible-collections/community.aws/pull/1160"
+ removed (https://github.com/ansible-collections/community.aws/pull/1160
- ec2_eip - The ``wait_timeout`` option has been removed. It has always been
ignored by the module (https://github.com/ansible-collections/community.aws/pull/1159).
- ec2_lc - the ``associate_public_ip_address`` option has been removed. It has
@@ -2485,7 +2577,7 @@ releases:
- route53_info - The CamelCase return values for ``DelegationSets``, ``CheckerIpRanges``,
and ``HealthCheck`` have been deprecated, in the future release you must use
snake_case return values ``delegation_sets``, ``checker_ip_ranges``, and ``health_check``
- instead respectively" (https://github.com/ansible-collections/community.aws/pull/1322).
+ instead respectively (https://github.com/ansible-collections/community.aws/pull/1322).
minor_changes:
- aws_glue_connection - added new ``raw_connection_parameters`` return key which
doesn't snake case the connection parameters (https://github.com/ansible-collections/community.aws/pull/518).
@@ -2590,6 +2682,102 @@ releases:
fragments:
- 1398-s3_lifecycle-no-prefix.yml
release_date: '2022-09-14'
+ 4.3.0:
+ changes:
+ bugfixes:
+ - ec2_placement_group - Handle a potential race creation during the creation
+ of a new Placement Group (https://github.com/ansible-collections/community.aws/pull/1477).
+ - rds_cluster - fixes bug where specifiying an rds cluster parameter group raises
+ a ``KeyError`` (https://github.com/ansible-collections/community.aws/pull/1417).
+ minor_changes:
+ - autoscaling_group_info - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+ - cloudfront_distribution - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+ - cloudfront_origin_access_identity - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+ - cloudtrail - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+ - ec2_vpc_nacl - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+ - eks_fargate_profile - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+ - redshift - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+ - s3_bucket_info - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+ release_summary: 'The community.aws 4.3.0 release includes a number of minor
+ bug fixes and improvements.
+
+ Following the release of amazon.aws 5.0.0, backports to the 4.x series will
+ be limited to security issues and bugfixes.'
+ fragments:
+ - 1410-linting.yml
+ - 1417-cluster-param-group-keyerror.yml
+ - RELEASE-4.3.0.yml
+ - ec2_placement_group_race_on_create.yaml
+ release_date: '2022-10-06'
+ 4.4.0:
+ changes:
+ bugfixes:
+ - aws_ssm - fixes S3 bucket region detection by ensuring boto client has correct
+ credentials and exists in correct partition (https://github.com/ansible-collections/community.aws/pull/1428).
+ - ecs_ecr - fix a ``RepositoryNotFound`` exception when trying to create repositories
+ in check mode (https://github.com/ansible-collections/community.aws/pull/1550).
+ - opensearch - Fix cluster creation when using advanced security options (https://github.com/ansible-collections/community.aws/pull/1613).
+ minor_changes:
+ - elasticache_parameter_group - add ``redis6.x`` group family on the module
+ input choices (https://github.com/ansible-collections/community.aws/pull/1476).
+ release_summary: 'This is the minor release of the ``community.aws`` collection.
+
+ This changelog contains all changes to the modules and plugins in this collection
+
+ that have been made after the previous release.'
+ fragments:
+ - 1428-aws-ssm-missing-credentials.yml
+ - 1476-add-redis6x-cache-parameter-group-family.yml
+ - 1550-ecs_ecr-RepositoryNotFound.yml
+ - 1565-healthCheck-docs.yml
+ - 1579-ec2_vpc_vgw-deleted.yml
+ - 1613-opensearch.yml
+ - 20221026-pytest-forked.yml
+ - 4.4.0.yml
+ release_date: '2022-12-08'
+ 4.5.0:
+ changes:
+ bugfixes:
+ - aws_ssm - fix ``invalid literal for int`` error on some operating systems
+ (https://github.com/ansible-collections/community.aws/issues/113).
+ - ecs_service - respect ``placement_constraints`` for existing ecs services
+ (https://github.com/ansible-collections/community.aws/pull/1601).
+ - s3_lifecycle - Module no longer calls ``put_lifecycle_configuration`` if there
+ is no change. (https://github.com/ansible-collections/community.aws/issues/1624)
+ - ssm_parameter - Fix a ``KeyError`` when adding a description to an existing
+ parameter (https://github.com/ansible-collections/community.aws/issues/1471).
+ minor_changes:
+ - ecs_service - support load balancer update for existing ecs services(https://github.com/ansible-collections/community.aws/pull/1625).
+ - iam_role - Drop deprecation warning, because the standard value for purge
+ parametes is ``true`` (https://github.com/ansible-collections/community.aws/pull/1636).
+ release_summary: This is the minor release of the ``community.aws`` collection.
+ fragments:
+ - 1601-ecs_service-support_constraints_and_strategy_update.yml
+ - 1624-s3-lifecycle-idempotent.yml
+ - 1625-ecs_service-support-load-balancer-update.yml
+ - 1627-ssm_parameter-KeyError-when-adding-description.yml
+ - 20230112-aws_ssm-tests.yml
+ - 4.5.0.yml
+ - 558-ssm_connection-invalid-literal.yml
+ - iam_role_purge_policy.yml
+ release_date: '2023-01-25'
+ 4.5.1:
+ changes:
+ bugfixes:
+ - sns_topic - avoid fetching attributes from subscribers when not setting them,
+ this can cause permissions issues (https://github.com/ansible-collections/community.aws/pull/1418).
+ release_summary: 'This release contains a minor bugfix for the ``sns_topic``
+ module as well as corrections to the documentation for various modules. This
+ is the last planned release of the 4.x series.
+
+ '
+ fragments:
+ - 1576-defaults.yml
+ - 1757-config_rule-evaluation-mode.yml
+ - iam_access_key_docs_fix.yml
+ - release-notes.yml
+ - sns_topic-cross-account.yml
+ release_date: '2023-05-05'
5.0.0:
changes:
breaking_changes:
@@ -2751,7 +2939,7 @@ releases:
- elb_network_lb - fixes bug where ``ip_address_type`` in return value was not
updated (https://github.com/ansible-collections/community.aws/pull/1365).
- rds_cluster - fixes bug where specifiying an rds cluster parameter group raises
- a `KeyError` (https://github.com/ansible-collections/community.aws/pull/1417).
+ a ``KeyError`` (https://github.com/ansible-collections/community.aws/pull/1417).
- s3_sync - fix etag generation when running in FIPS mode (https://github.com/ansible-collections/community.aws/issues/757).
deprecated_features:
- community.aws collection - due to the AWS SDKs announcing the end of support
@@ -3004,8 +3192,8 @@ releases:
bugfixes:
- aws_ssm - fixes S3 bucket region detection by ensuring boto client has correct
credentials and exists in correct partition (https://github.com/ansible-collections/community.aws/pull/1428).
- - ec2_snapshot_copy - including tags caused the erorr "Tag specification resource
- type must have a value". Fix sets the ResourceType to snapshot to resolve
+ - ec2_snapshot_copy - including tags caused the erorr ``Tag specification resource
+ type must have a value``. Fix sets the ResourceType to snapshot to resolve
this issue (https://github.com/ansible-collections/community.aws/pull/1419).
- ecs_ecr - fix a ``RepositoryNotFound`` exception when trying to create repositories
in check mode (https://github.com/ansible-collections/community.aws/pull/1550).
@@ -3227,3 +3415,322 @@ releases:
- elasticache_info-ignore-CacheClusterNotFound-when-reading-tags.yaml
- release-notes.yml
release_date: '2023-05-05'
+ 5.5.1:
+ changes:
+ bugfixes:
+ - cloudfront_distribution - no longer crashes when waiting for completion of
+ creation (https://github.com/ansible-collections/community.aws/issues/255).
+ - cloudfront_distribution - now honours the ``enabled`` setting (https://github.com/ansible-collections/community.aws/issues/1823).
+ release_summary: This release brings several bugfixes.
+ fragments:
+ - 1823-cloudfront_distribution_always_created_enabled.yml
+ - 20230627-ci-fixup.yml
+ - 20230701-ci-fixup.yml
+ - 20230704-github_workflows.yml
+ - 255-cloudfront_distribution_create_wait_crash.yml
+ - release_summary.yml
+ - test-reqs.yml
+ - tests-requirements.yml
+ release_date: '2023-07-05'
+ 6.0.0:
+ changes:
+ breaking_changes:
+ - The community.aws collection has dropped support for ``botocore<1.25.0`` and
+ ``boto3<1.22.0``. Most modules will continue to work with older versions of
+ the AWS SDK, however compatability with older versions of the SDK is not guaranteed
+ and will not be tested. When using older versions of the SDK a warning will
+ be emitted by Ansible (https://github.com/ansible-collections/community.aws/pull/1743).
+ - aws_ssm - the AWS SSM plugin was incorrectly prepending ``sudo`` to most commands. This
+ behaviour was incorrect and has been removed. To execute commands as a specific
+ user, including the ``root`` user, the ``become`` and ``become_user`` directives
+ should be used. See the `Ansible documentation for more information <https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_privilege_escalation.html>`_
+ (https://github.com/ansible-collections/community.aws/issues/853).
+ - codebuild_project - ``tags`` parameter now accepts a dict representing the
+ tags, rather than the boto3 format (https://github.com/ansible-collections/community.aws/pull/1643).
+ bugfixes:
+ - opensearch_info - Fix the name of the domain_name key in the example (https://github.com/ansible-collections/community.aws/pull/1811).
+ - ses_identity - fix clearing notification topic (https://github.com/ansible-collections/community.aws/issues/150).
+ deprecated_features:
+ - community.aws collection - due to the AWS SDKs Python support policies (https://aws.amazon.com/blogs/developer/python-support-policy-updates-for-aws-sdks-and-tools/)
+ support for Python less than 3.8 by this collection is expected to be removed
+ in a release after 2024-12-01 (https://github.com/ansible-collections/community.aws/pull/1743).
+ - community.aws collection - due to the AWS SDKs announcing the end of support
+ for Python less than 3.7 (https://aws.amazon.com/blogs/developer/python-support-policy-updates-for-aws-sdks-and-tools/)
+ support for Python less than 3.7 by this collection has been deprecated and
+ will be removed in release 7.0.0. (https://github.com/ansible-collections/community.aws/pull/1743).
+ minor_changes:
+ - The ``black`` code formatter has been run across the collection to improve
+ code consistency (https://github.com/ansible-collections/community.aws/pull/1784).
+ - aws_config_delivery_channel - add support for encrypted objects in S3 via
+ KMS key (https://github.com/ansible-collections/community.aws/pull/1786).
+ - aws_ssm - Updated the documentation to explicitly mention that the ``ansible_user``
+ and ``remote_user`` variables are not supported by the plugin (https://github.com/ansible-collections/community.aws/pull/1682).
+ - bulk migration of ``%`` and ``.format()`` to fstrings (https://github.com/ansible-collections/community.aws/pull/1810).
+ - cloudfront_distribution - add ``http3`` support via parameter value ``http2and3``
+ for parameter ``http_version`` (https://github.com/ansible-collections/community.aws/pull/1753).
+ - cloudfront_distribution - add ``origin_shield`` options (https://github.com/ansible-collections/community.aws/pull/1557).
+ - cloudfront_distribution - documented ``connection_attempts`` and ``connection_timeout``
+ the module was already capable of using them
+ - community.aws - updated document fragments based on changes in amazon.aws
+ (https://github.com/ansible-collections/community.aws/pull/1738).
+ - community.aws - updated imports based on changes in amazon.aws (https://github.com/ansible-collections/community.aws/pull/1738).
+ - ecs_ecr - use ``compare_policies`` when comparing lifecycle policies instead
+ of naive ``sort_json_policy_dict`` comparisons (https://github.com/ansible-collections/community.aws/pull/1551).
+ - elasticache - Use the ``cache.t3.small`` node type in the example. ``cache.m1.small``
+ is not deprecated.
+ - minor code fixes and enable integration tests for modules cloudfront_distribution,
+ cloudfront_invalidation and cloudfront_origin_access_identity (https://github.com/ansible-collections/community.aws/pull/1596).
+ - module_utils.botocore - Add Ansible AWS User-Agent identification (https://github.com/ansible-collections/community.aws/pull/1632).
+ - wafv2_rule_group_info - remove unused and deprecated ``state`` parameter (https://github.com/ansible-collections/community.aws/pull/1555).
+ release_summary: 'This release brings some new plugins and features. Several
+ bugfixes, breaking changes and deprecated features are also included.
+
+ The community.aws collection has dropped support for ``botocore<1.25.0`` and
+ ``boto3<1.22.0``.
+
+ Support for Python 3.6 has also been dropped.
+
+ '
+ fragments:
+ - 1435-connection-attempt-timeout.yml
+ - 1551-ecs_ecr-sort_json_policy.yml
+ - 1555-wafv2_rule_group_info.yml
+ - 1557-cloudfront-add-origin-shield.yml
+ - 1634-networkfirewall_rule_group-tests.yml
+ - 1643-codebuild_project.yml
+ - 1730-ses-identity-fix-clearing-notification-topic.yml
+ - 1738-headers.yml
+ - 1753-cloudfront-add-http3.yml
+ - 1784-black.yml
+ - 1798-aws_ssm-black.yml
+ - 20221103-autoscaling_scheduled_action.yml
+ - 20230307-blueprint.yml
+ - 20230423-update_readme_and_runtime.yml
+ - 20230424-config-delivery-channel.yml
+ - 6.0.0-release.yml
+ - 853-aws_ssm-sudo.yml
+ - ansible-user-agent-identification.yaml
+ - botocore-tests.yml
+ - cloudfront_integration_tests_activate.yaml
+ - elasticache-use-up-to-date-node-type-in-example.yaml
+ - fstring-1.yml
+ - integration_tests_max_duration_increase.yaml
+ - opensearch_info_example_key_name.yaml
+ - python37.yml
+ - release-6-botocore.yml
+ - version_added.yml
+ modules:
+ - description: Manage an AWS VPC Carrier gateway
+ name: ec2_carrier_gateway
+ namespace: ''
+ - description: Gather information about carrier gateways in AWS
+ name: ec2_carrier_gateway_info
+ namespace: ''
+ - description: Creates snapshots of AWS Lightsail instances
+ name: lightsail_snapshot
+ namespace: ''
+ - description: MQ broker management
+ name: mq_broker
+ namespace: ''
+ - description: Update Amazon MQ broker configuration
+ name: mq_broker_config
+ namespace: ''
+ - description: Retrieve MQ Broker details
+ name: mq_broker_info
+ namespace: ''
+ - description: Manage users in existing Amazon MQ broker
+ name: mq_user
+ namespace: ''
+ - description: List users of an Amazon MQ broker
+ name: mq_user_info
+ namespace: ''
+ - description: Get SSM inventory information for EC2 instance
+ name: ssm_inventory_info
+ namespace: ''
+ release_date: '2023-05-10'
+ 6.1.0:
+ changes:
+ bugfixes:
+ - batch_compute_environment - fixed incorrect handling of Gov Cloud ARNs in
+ ``compute_environment_name`` parameter (https://github.com/ansible-collections/community.aws/issues/1846).
+ - cloudfront_distribution - The origins recognises the s3 domains with region
+ part now (https://github.com/ansible-collections/community.aws/issues/1819).
+ - cloudfront_distribution - no longer crashes when waiting for completion of
+ creation (https://github.com/ansible-collections/community.aws/issues/255).
+ - cloudfront_distribution - now honours the ``enabled`` setting (https://github.com/ansible-collections/community.aws/issues/1823).
+ - dynamodb_table - secondary indexes are now created (https://github.com/ansible-collections/community.aws/issues/1825).
+ - ec2_launch_template - fixed incorrect handling of Gov Cloud ARNs in ``compute_environment_name``
+ parameter (https://github.com/ansible-collections/community.aws/issues/1846).
+ - elasticache_info - remove hard coded use of ``aws`` partition (https://github.com/ansible-collections/community.aws/issues/1846).
+ - iam_role - fixed incorrect rejection of Gov Cloud ARNs in ``boundary`` parameter
+ (https://github.com/ansible-collections/community.aws/issues/1846).
+ - msk_cluster - remove hard coded use of ``aws`` partition (https://github.com/ansible-collections/community.aws/issues/1846).
+ - redshift - fixed hard coded use of ``aws`` partition (https://github.com/ansible-collections/community.aws/issues/1846).
+ minor_changes:
+ - dynamodb_table - added waiter when updating indexes to avoid concurrency issues
+ (https://github.com/ansible-collections/community.aws/pull/1866).
+ - dynamodb_table - increased default timeout based on time to update indexes
+ in CI (https://github.com/ansible-collections/community.aws/pull/1866).
+ - iam_group - refactored ARN validation handling (https://github.com/ansible-collections/community.aws/pull/1848).
+ - iam_role - refactored ARN validation handling (https://github.com/ansible-collections/community.aws/pull/1848).
+ - sns_topic - refactored ARN validation handling (https://github.com/ansible-collections/community.aws/pull/1848).
+ release_summary: This release brings a new inventory plugin, some new features,
+ and several bugfixes.
+ fragments:
+ - 1819-cloudfront-distribution-s3-domain-recognise.yaml
+ - 1823-cloudfront_distribution_always_created_enabled.yml
+ - 1825-dynamodb-table-no-secondary-indexes.yml
+ - 1846-arn.yml
+ - 20230531-mq-fix_fqdn.yml
+ - 20230613-black.yml
+ - 20230627-ci-fixup.yml
+ - 20230701-ci-fixup.yml
+ - 20230702-dynamodb_waiter.yml
+ - 255-cloudfront_distribution_create_wait_crash.yml
+ - 6.0.0.yml
+ - release_summary.yml
+ - test-reqs.yml
+ - tests-requirements.yml
+ plugins:
+ inventory:
+ - description: MQ broker inventory source
+ name: aws_mq
+ namespace: null
+ release_date: '2023-07-07'
+ 6.2.0:
+ changes:
+ bugfixes:
+ - Remove ``apigateway`` and ``apigateway_deployment`` from meta/runtime.yml
+ (https://github.com/ansible-collections/community.aws/pull/1905).
+ minor_changes:
+ - api_gateway - add support for parameters ``name``, ``lookup``, ``tags`` and
+ ``purge_tags`` (https://github.com/ansible-collections/community.aws/pull/1845).
+ - ec2_vpc_vpn - add support for connecting VPNs to a transit gateway (https://github.com/ansible-collections/community.aws/pull/1877).
+ release_summary: This release includes some new features for the ``community.aws.ec2_vpc_vpn``
+ and ``community.aws.api_gateway`` modules.
+ fragments:
+ - 20230620-api_gateway-add-optional-name.yml
+ - 20230804-update-meta-runtime.yaml
+ - release_summary.yml
+ - transit_gateway_to_vpn.yaml
+ release_date: '2023-08-04'
+ 7.0.0:
+ changes:
+ breaking_changes:
+ - The community.aws collection has dropped support for ``botocore<1.29.0`` and
+ ``boto3<1.26.0``. Most modules will continue to work with older versions of
+ the AWS SDK, however compatability with older versions of the SDK is not guaranteed
+ and will not be tested. When using older versions of the SDK a warning will
+ be emitted by Ansible (https://github.com/ansible-collections/amazon.aws/pull/1763).
+ - aws_region_info - The module has been migrated from the ``community.aws``
+ collection. Playbooks using the Fully Qualified Collection Name for this module
+ should be updated to use ``amazon.aws.aws_region_info``.
+ - aws_s3_bucket_info - The module has been migrated from the ``community.aws``
+ collection. Playbooks using the Fully Qualified Collection Name for this module
+ should be updated to use ``amazon.aws.aws_s3_bucket_info``.
+ - community.aws collection - due to the AWS SDKs announcing the end of support
+ for Python less than 3.7 (https://aws.amazon.com/blogs/developer/python-support-policy-updates-for-aws-sdks-and-tools/)
+ support for Python less than 3.7 by this collection wss been deprecated in
+ release 6.0.0 and removed in release 7.0.0. (https://github.com/ansible-collections/amazon.aws/pull/1763).
+ - iam_access_key - The module has been migrated from the ``community.aws`` collection.
+ Playbooks using the Fully Qualified Collection Name for this module should
+ be updated to use ``amazon.aws.iam_access_key``.
+ - iam_access_key_info - The module has been migrated from the ``community.aws``
+ collection. Playbooks using the Fully Qualified Collection Name for this module
+ should be updated to use ``amazon.aws.iam_access_key_info``.
+ - iam_group - The module has been migrated from the ``community.aws`` collection.
+ Playbooks using the Fully Qualified Collection Name for this module should
+ be updated to use ``amazon.aws.iam_group`` (https://github.com/ansible-collections/community.aws/pull/1945).
+ - iam_managed_policy - The module has been migrated from the ``community.aws``
+ collection. Playbooks using the Fully Qualified Collection Name for this module
+ should be updated to use ``amazon.aws.iam_managed_policy`` (https://github.com/ansible-collections/community.aws/pull/1954).
+ - iam_mfa_device_info - The module has been migrated from the ``community.aws``
+ collection. Playbooks using the Fully Qualified Collection Name for this module
+ should be updated to use ``amazon.aws.iam_mfa_device_info`` (https://github.com/ansible-collections/community.aws/pull/1953).
+ - iam_password_policy - The module has been migrated from the ``community.aws``
+ collection. Playbooks using the Fully Qualified Collection Name for this module
+ should be updated to use ``amazon.aws.iam_password_policy``.
+ - iam_role - The module has been migrated from the ``community.aws`` collection.
+ Playbooks using the Fully Qualified Collection Name for this module should
+ be updated to use ``amazon.aws.iam_role`` (https://github.com/ansible-collections/community.aws/pull/1948).
+ - iam_role_info - The module has been migrated from the ``community.aws`` collection.
+ Playbooks using the Fully Qualified Collection Name for this module should
+ be updated to use ``amazon.aws.iam_role_info`` (https://github.com/ansible-collections/community.aws/pull/1948).
+ - s3_bucket_info - The module has been migrated from the ``community.aws`` collection.
+ Playbooks using the Fully Qualified Collection Name for this module should
+ be updated to use ``amazon.aws.s3_bucket_info``.
+ - sts_assume_role - The module has been migrated from the ``community.aws``
+ collection. Playbooks using the Fully Qualified Collection Name for this module
+ should be updated to use ``amazon.aws.sts_assume_role``.
+ bugfixes:
+ - mq_broker - ensure broker is created with ``tags`` when passed (https://github.com/ansible-collections/community.aws/issues/1832).
+ - opensearch - Don't try to read a non existing key from the domain config (https://github.com/ansible-collections/community.aws/pull/1910).
+ minor_changes:
+ - api_gateway - use fstrings where appropriate (https://github.com/ansible-collections/amazon.aws/pull/1962).
+ - api_gateway_info - use fstrings where appropriate (https://github.com/ansible-collections/amazon.aws/pull/1962).
+ - community.aws collection - apply isort code formatting to ensure consistent
+ formatting of code (https://github.com/ansible-collections/community.aws/pull/1962)
+ - ecs_taskdefinition - Add parameter ``runtime_platform`` (https://github.com/ansible-collections/community.aws/issues/1891).
+ - eks_nodegroup - ensure wait also waits for deletion to complete when ``wait==True``
+ (https://github.com/ansible-collections/community.aws/pull/1994).
+ release_summary: This release includes some new features, bugfixes and breaking
+ changes. Several modules have been migrated to amazon.aws and the Fully Qualified
+ Collection Name for these modules needs to be updated. The community.aws collection
+ has dropped support for ``botocore<1.29.0`` and ``boto3<1.26.0``. Due to the
+ AWS SDKs announcing the end of support for Python less than 3.7 (https://aws.amazon.com/blogs/developer/python-support-policy-updates-for-aws-sdks-and-tools/),
+ support for Python less than 3.7 by this collection was deprecated in release
+ 6.0.0 and removed in release 7.0.0. (https://github.com/ansible-collections/amazon.aws/pull/1763).
+ fragments:
+ - 1832-mq_broker_tags.yml
+ - 1891_ecs-task-definition-add-runtime-platform.yml
+ - 1904-route53_wait.yml
+ - 1962-isort.yml
+ - 20230623-black-cloudfront.yml
+ - 20230702-isort.yml
+ - 20230801-fix-linters.yml
+ - 20230906-galaxy.yml
+ - 20230906-route53_wait.yml
+ - 20230908-alias-cleanup.yml
+ - 20230915_migrate_iam_role_and_iam_role_info.yml
+ - 7.0.0-dev0.yml
+ - botocore.yml
+ - botocore_params-cleanup.yml
+ - eks_nodegroup-integration-wait-delete.yml
+ - galaxy_importer.yml
+ - migrate_aws_region_info.yml
+ - migrate_iam_access_key.yml
+ - migrate_iam_group.yml
+ - migrate_iam_managed_policy.yml
+ - migrate_iam_mfa_device_info.yml
+ - migrate_iam_password_policy.yml
+ - migrate_s3_bucket_info.yml
+ - migrate_sts_assume_role.yml
+ - opensearch_domainconfig_no_options.yaml
+ - python37.yml
+ - release_summary.yml
+ - workflow-requirements.yml
+ release_date: '2023-11-06'
+ 7.1.0:
+ changes:
+ bugfixes:
+ - aws_ssm - disable `enable-bracketed-paste` to fix issue with amazon linux
+ 2023 and other OSes (https://github.com/ansible-collections/community.aws/issues/1756)
+ minor_changes:
+ - aws_ssm - Updated the documentation to explicitly state that an S3 bucket
+ is required, the behavior of the files in that bucket, and requirements around
+ that. (https://github.com/ansible-collections/community.aws/issues/1775).
+ - cloudfront_distribution - added support for ``cache_policy_id`` and ``origin_request_policy_id``
+ for behaviors (https://github.com/ansible-collections/community.aws/pull/1589)
+ - mq_broker - add support to wait for broker state via ``wait`` and ``wait_timeout``
+ parameter values (https://github.com/ansible-collections/community.aws/pull/1879).
+ release_summary: This release includes new features for the ``cloudfront_distribution``
+ and ``mq_broker`` modules, as well as a bugfix for the ``aws_ssm`` connection
+ plugin needed when connecting to hosts with Bash 5.1.0 and later.
+ fragments:
+ - 1589-cloudfront_distribution-add-policies.yml
+ - 1775-aws_ssm-s3-docs.yaml
+ - 1839-disable-bracketed-paste.yml
+ - 1879-mq_broker-add-wait.yml
+ - release.yml
+ - ssm-fedora34.yml
+ release_date: '2024-01-10'
diff --git a/ansible_collections/community/aws/changelogs/config.yaml b/ansible_collections/community/aws/changelogs/config.yaml
index df8a7220c..6ac07f935 100644
--- a/ansible_collections/community/aws/changelogs/config.yaml
+++ b/ansible_collections/community/aws/changelogs/config.yaml
@@ -1,3 +1,4 @@
+---
changelog_filename_template: ../CHANGELOG.rst
changelog_filename_version_depth: 0
changes_file: changelog.yaml
@@ -9,21 +10,21 @@ notesdir: fragments
prelude_section_name: release_summary
prelude_section_title: Release Summary
sections:
-- - major_changes
- - Major Changes
-- - minor_changes
- - Minor Changes
-- - breaking_changes
- - Breaking Changes / Porting Guide
-- - deprecated_features
- - Deprecated Features
-- - removed_features
- - Removed Features (previously deprecated)
-- - security_fixes
- - Security Fixes
-- - bugfixes
- - Bugfixes
-- - known_issues
- - Known Issues
+ - - major_changes
+ - Major Changes
+ - - minor_changes
+ - Minor Changes
+ - - breaking_changes
+ - Breaking Changes / Porting Guide
+ - - deprecated_features
+ - Deprecated Features
+ - - removed_features
+ - Removed Features (previously deprecated)
+ - - security_fixes
+ - Security Fixes
+ - - bugfixes
+ - Bugfixes
+ - - known_issues
+ - Known Issues
title: community.aws
trivial_section_name: trivial
diff --git a/ansible_collections/community/aws/docs/docsite/links.yml b/ansible_collections/community/aws/docs/docsite/links.yml
index 3369b815f..b38e48055 100644
--- a/ansible_collections/community/aws/docs/docsite/links.yml
+++ b/ansible_collections/community/aws/docs/docsite/links.yml
@@ -7,7 +7,7 @@
# functionality for your collection.
edit_on_github:
repository: ansible-collections/community.aws
- branch: main
+ branch: stable-7
# If your collection root (the directory containing galaxy.yml) does not coincide with your
# repository's root, you have to specify the path to the collection root here. For example,
# if the collection root is in a subdirectory ansible_collections/community/REPO_NAME
diff --git a/ansible_collections/community/aws/docs/docsite/rst/CHANGELOG.rst b/ansible_collections/community/aws/docs/docsite/rst/CHANGELOG.rst
index 7b5761863..651b7c763 100644
--- a/ansible_collections/community/aws/docs/docsite/rst/CHANGELOG.rst
+++ b/ansible_collections/community/aws/docs/docsite/rst/CHANGELOG.rst
@@ -5,6 +5,200 @@ community.aws Release Notes
.. contents:: Topics
+v7.1.0
+======
+
+Release Summary
+---------------
+
+This release includes new features for the ``cloudfront_distribution`` and ``mq_broker`` modules, as well as a bugfix for the ``aws_ssm`` connection plugin needed when connecting to hosts with Bash 5.1.0 and later.
+
+Minor Changes
+-------------
+
+- aws_ssm - Updated the documentation to explicitly state that an S3 bucket is required, the behavior of the files in that bucket, and requirements around that. (https://github.com/ansible-collections/community.aws/issues/1775).
+- cloudfront_distribution - added support for ``cache_policy_id`` and ``origin_request_policy_id`` for behaviors (https://github.com/ansible-collections/community.aws/pull/1589)
+- mq_broker - add support to wait for broker state via ``wait`` and ``wait_timeout`` parameter values (https://github.com/ansible-collections/community.aws/pull/1879).
+
+Bugfixes
+--------
+
+- aws_ssm - disable `enable-bracketed-paste` to fix issue with amazon linux 2023 and other OSes (https://github.com/ansible-collections/community.aws/issues/1756)
+
+v7.0.0
+======
+
+Release Summary
+---------------
+
+This release includes some new features, bugfixes and breaking changes. Several modules have been migrated to amazon.aws and the Fully Qualified Collection Name for these modules needs to be updated. The community.aws collection has dropped support for ``botocore<1.29.0`` and ``boto3<1.26.0``. Due to the AWS SDKs announcing the end of support for Python less than 3.7 (https://aws.amazon.com/blogs/developer/python-support-policy-updates-for-aws-sdks-and-tools/), support for Python less than 3.7 by this collection was deprecated in release 6.0.0 and removed in release 7.0.0. (https://github.com/ansible-collections/amazon.aws/pull/1763).
+
+Minor Changes
+-------------
+
+- api_gateway - use fstrings where appropriate (https://github.com/ansible-collections/amazon.aws/pull/1962).
+- api_gateway_info - use fstrings where appropriate (https://github.com/ansible-collections/amazon.aws/pull/1962).
+- community.aws collection - apply isort code formatting to ensure consistent formatting of code (https://github.com/ansible-collections/community.aws/pull/1962)
+- ecs_taskdefinition - Add parameter ``runtime_platform`` (https://github.com/ansible-collections/community.aws/issues/1891).
+- eks_nodegroup - ensure wait also waits for deletion to complete when ``wait==True`` (https://github.com/ansible-collections/community.aws/pull/1994).
+
+Breaking Changes / Porting Guide
+--------------------------------
+
+- The community.aws collection has dropped support for ``botocore<1.29.0`` and ``boto3<1.26.0``. Most modules will continue to work with older versions of the AWS SDK, however compatability with older versions of the SDK is not guaranteed and will not be tested. When using older versions of the SDK a warning will be emitted by Ansible (https://github.com/ansible-collections/amazon.aws/pull/1763).
+- aws_region_info - The module has been migrated from the ``community.aws`` collection. Playbooks using the Fully Qualified Collection Name for this module should be updated to use ``amazon.aws.aws_region_info``.
+- aws_s3_bucket_info - The module has been migrated from the ``community.aws`` collection. Playbooks using the Fully Qualified Collection Name for this module should be updated to use ``amazon.aws.aws_s3_bucket_info``.
+- community.aws collection - due to the AWS SDKs announcing the end of support for Python less than 3.7 (https://aws.amazon.com/blogs/developer/python-support-policy-updates-for-aws-sdks-and-tools/) support for Python less than 3.7 by this collection wss been deprecated in release 6.0.0 and removed in release 7.0.0. (https://github.com/ansible-collections/amazon.aws/pull/1763).
+- iam_access_key - The module has been migrated from the ``community.aws`` collection. Playbooks using the Fully Qualified Collection Name for this module should be updated to use ``amazon.aws.iam_access_key``.
+- iam_access_key_info - The module has been migrated from the ``community.aws`` collection. Playbooks using the Fully Qualified Collection Name for this module should be updated to use ``amazon.aws.iam_access_key_info``.
+- iam_group - The module has been migrated from the ``community.aws`` collection. Playbooks using the Fully Qualified Collection Name for this module should be updated to use ``amazon.aws.iam_group`` (https://github.com/ansible-collections/community.aws/pull/1945).
+- iam_managed_policy - The module has been migrated from the ``community.aws`` collection. Playbooks using the Fully Qualified Collection Name for this module should be updated to use ``amazon.aws.iam_managed_policy`` (https://github.com/ansible-collections/community.aws/pull/1954).
+- iam_mfa_device_info - The module has been migrated from the ``community.aws`` collection. Playbooks using the Fully Qualified Collection Name for this module should be updated to use ``amazon.aws.iam_mfa_device_info`` (https://github.com/ansible-collections/community.aws/pull/1953).
+- iam_password_policy - The module has been migrated from the ``community.aws`` collection. Playbooks using the Fully Qualified Collection Name for this module should be updated to use ``amazon.aws.iam_password_policy``.
+- iam_role - The module has been migrated from the ``community.aws`` collection. Playbooks using the Fully Qualified Collection Name for this module should be updated to use ``amazon.aws.iam_role`` (https://github.com/ansible-collections/community.aws/pull/1948).
+- iam_role_info - The module has been migrated from the ``community.aws`` collection. Playbooks using the Fully Qualified Collection Name for this module should be updated to use ``amazon.aws.iam_role_info`` (https://github.com/ansible-collections/community.aws/pull/1948).
+- s3_bucket_info - The module has been migrated from the ``community.aws`` collection. Playbooks using the Fully Qualified Collection Name for this module should be updated to use ``amazon.aws.s3_bucket_info``.
+- sts_assume_role - The module has been migrated from the ``community.aws`` collection. Playbooks using the Fully Qualified Collection Name for this module should be updated to use ``amazon.aws.sts_assume_role``.
+
+Bugfixes
+--------
+
+- mq_broker - ensure broker is created with ``tags`` when passed (https://github.com/ansible-collections/community.aws/issues/1832).
+- opensearch - Don't try to read a non existing key from the domain config (https://github.com/ansible-collections/community.aws/pull/1910).
+
+v6.2.0
+======
+
+Release Summary
+---------------
+
+This release includes some new features for the ``community.aws.ec2_vpc_vpn`` and ``community.aws.api_gateway`` modules.
+
+Minor Changes
+-------------
+
+- api_gateway - add support for parameters ``name``, ``lookup``, ``tags`` and ``purge_tags`` (https://github.com/ansible-collections/community.aws/pull/1845).
+- ec2_vpc_vpn - add support for connecting VPNs to a transit gateway (https://github.com/ansible-collections/community.aws/pull/1877).
+
+Bugfixes
+--------
+
+- Remove ``apigateway`` and ``apigateway_deployment`` from meta/runtime.yml (https://github.com/ansible-collections/community.aws/pull/1905).
+
+v6.1.0
+======
+
+Release Summary
+---------------
+
+This release brings a new inventory plugin, some new features, and several bugfixes.
+
+Minor Changes
+-------------
+
+- dynamodb_table - added waiter when updating indexes to avoid concurrency issues (https://github.com/ansible-collections/community.aws/pull/1866).
+- dynamodb_table - increased default timeout based on time to update indexes in CI (https://github.com/ansible-collections/community.aws/pull/1866).
+- iam_group - refactored ARN validation handling (https://github.com/ansible-collections/community.aws/pull/1848).
+- iam_role - refactored ARN validation handling (https://github.com/ansible-collections/community.aws/pull/1848).
+- sns_topic - refactored ARN validation handling (https://github.com/ansible-collections/community.aws/pull/1848).
+
+Bugfixes
+--------
+
+- batch_compute_environment - fixed incorrect handling of Gov Cloud ARNs in ``compute_environment_name`` parameter (https://github.com/ansible-collections/community.aws/issues/1846).
+- cloudfront_distribution - The origins recognises the s3 domains with region part now (https://github.com/ansible-collections/community.aws/issues/1819).
+- cloudfront_distribution - no longer crashes when waiting for completion of creation (https://github.com/ansible-collections/community.aws/issues/255).
+- cloudfront_distribution - now honours the ``enabled`` setting (https://github.com/ansible-collections/community.aws/issues/1823).
+- dynamodb_table - secondary indexes are now created (https://github.com/ansible-collections/community.aws/issues/1825).
+- ec2_launch_template - fixed incorrect handling of Gov Cloud ARNs in ``compute_environment_name`` parameter (https://github.com/ansible-collections/community.aws/issues/1846).
+- elasticache_info - remove hard coded use of ``aws`` partition (https://github.com/ansible-collections/community.aws/issues/1846).
+- iam_role - fixed incorrect rejection of Gov Cloud ARNs in ``boundary`` parameter (https://github.com/ansible-collections/community.aws/issues/1846).
+- msk_cluster - remove hard coded use of ``aws`` partition (https://github.com/ansible-collections/community.aws/issues/1846).
+- redshift - fixed hard coded use of ``aws`` partition (https://github.com/ansible-collections/community.aws/issues/1846).
+
+New Plugins
+-----------
+
+Inventory
+~~~~~~~~~
+
+- aws_mq - MQ broker inventory source
+
+v6.0.0
+======
+
+Release Summary
+---------------
+
+This release brings some new plugins and features. Several bugfixes, breaking changes and deprecated features are also included.
+The community.aws collection has dropped support for ``botocore<1.25.0`` and ``boto3<1.22.0``.
+Support for Python 3.6 has also been dropped.
+
+
+Minor Changes
+-------------
+
+- The ``black`` code formatter has been run across the collection to improve code consistency (https://github.com/ansible-collections/community.aws/pull/1784).
+- aws_config_delivery_channel - add support for encrypted objects in S3 via KMS key (https://github.com/ansible-collections/community.aws/pull/1786).
+- aws_ssm - Updated the documentation to explicitly mention that the ``ansible_user`` and ``remote_user`` variables are not supported by the plugin (https://github.com/ansible-collections/community.aws/pull/1682).
+- bulk migration of ``%`` and ``.format()`` to fstrings (https://github.com/ansible-collections/community.aws/pull/1810).
+- cloudfront_distribution - add ``http3`` support via parameter value ``http2and3`` for parameter ``http_version`` (https://github.com/ansible-collections/community.aws/pull/1753).
+- cloudfront_distribution - add ``origin_shield`` options (https://github.com/ansible-collections/community.aws/pull/1557).
+- cloudfront_distribution - documented ``connection_attempts`` and ``connection_timeout`` the module was already capable of using them
+- community.aws - updated document fragments based on changes in amazon.aws (https://github.com/ansible-collections/community.aws/pull/1738).
+- community.aws - updated imports based on changes in amazon.aws (https://github.com/ansible-collections/community.aws/pull/1738).
+- ecs_ecr - use ``compare_policies`` when comparing lifecycle policies instead of naive ``sort_json_policy_dict`` comparisons (https://github.com/ansible-collections/community.aws/pull/1551).
+- elasticache - Use the ``cache.t3.small`` node type in the example. ``cache.m1.small`` is not deprecated.
+- minor code fixes and enable integration tests for modules cloudfront_distribution, cloudfront_invalidation and cloudfront_origin_access_identity (https://github.com/ansible-collections/community.aws/pull/1596).
+- module_utils.botocore - Add Ansible AWS User-Agent identification (https://github.com/ansible-collections/community.aws/pull/1632).
+- wafv2_rule_group_info - remove unused and deprecated ``state`` parameter (https://github.com/ansible-collections/community.aws/pull/1555).
+
+Breaking Changes / Porting Guide
+--------------------------------
+
+- The community.aws collection has dropped support for ``botocore<1.25.0`` and ``boto3<1.22.0``. Most modules will continue to work with older versions of the AWS SDK, however compatability with older versions of the SDK is not guaranteed and will not be tested. When using older versions of the SDK a warning will be emitted by Ansible (https://github.com/ansible-collections/community.aws/pull/1743).
+- aws_ssm - the AWS SSM plugin was incorrectly prepending ``sudo`` to most commands. This behaviour was incorrect and has been removed. To execute commands as a specific user, including the ``root`` user, the ``become`` and ``become_user`` directives should be used. See the `Ansible documentation for more information <https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_privilege_escalation.html>`_ (https://github.com/ansible-collections/community.aws/issues/853).
+- codebuild_project - ``tags`` parameter now accepts a dict representing the tags, rather than the boto3 format (https://github.com/ansible-collections/community.aws/pull/1643).
+
+Deprecated Features
+-------------------
+
+- community.aws collection - due to the AWS SDKs Python support policies (https://aws.amazon.com/blogs/developer/python-support-policy-updates-for-aws-sdks-and-tools/) support for Python less than 3.8 by this collection is expected to be removed in a release after 2024-12-01 (https://github.com/ansible-collections/community.aws/pull/1743).
+- community.aws collection - due to the AWS SDKs announcing the end of support for Python less than 3.7 (https://aws.amazon.com/blogs/developer/python-support-policy-updates-for-aws-sdks-and-tools/) support for Python less than 3.7 by this collection has been deprecated and will be removed in release 7.0.0. (https://github.com/ansible-collections/community.aws/pull/1743).
+
+Bugfixes
+--------
+
+- opensearch_info - Fix the name of the domain_name key in the example (https://github.com/ansible-collections/community.aws/pull/1811).
+- ses_identity - fix clearing notification topic (https://github.com/ansible-collections/community.aws/issues/150).
+
+New Modules
+-----------
+
+- ec2_carrier_gateway - Manage an AWS VPC Carrier gateway
+- ec2_carrier_gateway_info - Gather information about carrier gateways in AWS
+- lightsail_snapshot - Creates snapshots of AWS Lightsail instances
+- mq_broker - MQ broker management
+- mq_broker_config - Update Amazon MQ broker configuration
+- mq_broker_info - Retrieve MQ Broker details
+- mq_user - Manage users in existing Amazon MQ broker
+- mq_user_info - List users of an Amazon MQ broker
+- ssm_inventory_info - Get SSM inventory information for EC2 instance
+
+v5.5.1
+======
+
+Release Summary
+---------------
+
+This release brings several bugfixes.
+
+Bugfixes
+--------
+
+- cloudfront_distribution - no longer crashes when waiting for completion of creation (https://github.com/ansible-collections/community.aws/issues/255).
+- cloudfront_distribution - now honours the ``enabled`` setting (https://github.com/ansible-collections/community.aws/issues/1823).
+
v5.5.0
======
@@ -156,7 +350,7 @@ Bugfixes
--------
- aws_ssm - fixes S3 bucket region detection by ensuring boto client has correct credentials and exists in correct partition (https://github.com/ansible-collections/community.aws/pull/1428).
-- ec2_snapshot_copy - including tags caused the erorr "Tag specification resource type must have a value". Fix sets the ResourceType to snapshot to resolve this issue (https://github.com/ansible-collections/community.aws/pull/1419).
+- ec2_snapshot_copy - including tags caused the erorr ``Tag specification resource type must have a value``. Fix sets the ResourceType to snapshot to resolve this issue (https://github.com/ansible-collections/community.aws/pull/1419).
- ecs_ecr - fix a ``RepositoryNotFound`` exception when trying to create repositories in check mode (https://github.com/ansible-collections/community.aws/pull/1550).
- opensearch - Fix cluster creation when using advanced security options (https://github.com/ansible-collections/community.aws/pull/1613).
@@ -321,7 +515,7 @@ Bugfixes
- ec2_placement_group - Handle a potential race creation during the creation of a new Placement Group (https://github.com/ansible-collections/community.aws/pull/1477).
- elb_network_lb - fixes bug where ``ip_address_type`` in return value was not updated (https://github.com/ansible-collections/community.aws/pull/1365).
-- rds_cluster - fixes bug where specifiying an rds cluster parameter group raises a `KeyError` (https://github.com/ansible-collections/community.aws/pull/1417).
+- rds_cluster - fixes bug where specifiying an rds cluster parameter group raises a ``KeyError`` (https://github.com/ansible-collections/community.aws/pull/1417).
- s3_sync - fix etag generation when running in FIPS mode (https://github.com/ansible-collections/community.aws/issues/757).
New Modules
@@ -329,6 +523,91 @@ New Modules
- accessanalyzer_validate_policy_info - Performs validation of IAM policies
+v4.5.1
+======
+
+Release Summary
+---------------
+
+This release contains a minor bugfix for the ``sns_topic`` module as well as corrections to the documentation for various modules. This is the last planned release of the 4.x series.
+
+
+Bugfixes
+--------
+
+- sns_topic - avoid fetching attributes from subscribers when not setting them, this can cause permissions issues (https://github.com/ansible-collections/community.aws/pull/1418).
+
+v4.5.0
+======
+
+Release Summary
+---------------
+
+This is the minor release of the ``community.aws`` collection.
+
+Minor Changes
+-------------
+
+- ecs_service - support load balancer update for existing ecs services(https://github.com/ansible-collections/community.aws/pull/1625).
+- iam_role - Drop deprecation warning, because the standard value for purge parametes is ``true`` (https://github.com/ansible-collections/community.aws/pull/1636).
+
+Bugfixes
+--------
+
+- aws_ssm - fix ``invalid literal for int`` error on some operating systems (https://github.com/ansible-collections/community.aws/issues/113).
+- ecs_service - respect ``placement_constraints`` for existing ecs services (https://github.com/ansible-collections/community.aws/pull/1601).
+- s3_lifecycle - Module no longer calls ``put_lifecycle_configuration`` if there is no change. (https://github.com/ansible-collections/community.aws/issues/1624)
+- ssm_parameter - Fix a ``KeyError`` when adding a description to an existing parameter (https://github.com/ansible-collections/community.aws/issues/1471).
+
+v4.4.0
+======
+
+Release Summary
+---------------
+
+This is the minor release of the ``community.aws`` collection.
+This changelog contains all changes to the modules and plugins in this collection
+that have been made after the previous release.
+
+Minor Changes
+-------------
+
+- elasticache_parameter_group - add ``redis6.x`` group family on the module input choices (https://github.com/ansible-collections/community.aws/pull/1476).
+
+Bugfixes
+--------
+
+- aws_ssm - fixes S3 bucket region detection by ensuring boto client has correct credentials and exists in correct partition (https://github.com/ansible-collections/community.aws/pull/1428).
+- ecs_ecr - fix a ``RepositoryNotFound`` exception when trying to create repositories in check mode (https://github.com/ansible-collections/community.aws/pull/1550).
+- opensearch - Fix cluster creation when using advanced security options (https://github.com/ansible-collections/community.aws/pull/1613).
+
+v4.3.0
+======
+
+Release Summary
+---------------
+
+The community.aws 4.3.0 release includes a number of minor bug fixes and improvements.
+Following the release of amazon.aws 5.0.0, backports to the 4.x series will be limited to security issues and bugfixes.
+
+Minor Changes
+-------------
+
+- autoscaling_group_info - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+- cloudfront_distribution - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+- cloudfront_origin_access_identity - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+- cloudtrail - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+- ec2_vpc_nacl - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+- eks_fargate_profile - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+- redshift - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+- s3_bucket_info - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+
+Bugfixes
+--------
+
+- ec2_placement_group - Handle a potential race creation during the creation of a new Placement Group (https://github.com/ansible-collections/community.aws/pull/1477).
+- rds_cluster - fixes bug where specifiying an rds cluster parameter group raises a ``KeyError`` (https://github.com/ansible-collections/community.aws/pull/1417).
+
v4.2.0
======
@@ -385,7 +664,7 @@ Deprecated Features
- community.aws collection - due to the AWS SDKs announcing the end of support for Python less than 3.7 (https://aws.amazon.com/blogs/developer/python-support-policy-updates-for-aws-sdks-and-tools/) support for Python less than 3.7 by this collection has been deprecated and will be removed in a release after 2023-05-31 (https://github.com/ansible-collections/community.aws/pull/1361).
- iam_policy - the ``policies`` return value has been renamed ``policy_names`` and will be removed in a release after 2024-08-01, both values are currently returned (https://github.com/ansible-collections/community.aws/pull/1375).
- lambda_info - The ``function`` return key returns a dictionary of dictionaries and has been deprecated. In a release after 2025-01-01, this key will be removed in favor of ``functions``, which returns a list of dictionaries (https://github.com/ansible-collections/community.aws/pull/1239).
-- route53_info - The CamelCase return values for ``DelegationSets``, ``CheckerIpRanges``, and ``HealthCheck`` have been deprecated, in the future release you must use snake_case return values ``delegation_sets``, ``checker_ip_ranges``, and ``health_check`` instead respectively" (https://github.com/ansible-collections/community.aws/pull/1322).
+- route53_info - The CamelCase return values for ``DelegationSets``, ``CheckerIpRanges``, and ``HealthCheck`` have been deprecated, in the future release you must use snake_case return values ``delegation_sets``, ``checker_ip_ranges``, and ``health_check`` instead respectively (https://github.com/ansible-collections/community.aws/pull/1322).
Bugfixes
--------
@@ -548,7 +827,7 @@ Removed Features (previously deprecated)
----------------------------------------
- aws_kms_info - the unused and deprecated ``keys_attr`` parameter has been removed (https://github.com/ansible-collections/amazon.aws/pull/1172).
-- data_pipeline - the ``version`` option has always been ignored and has been removed (https://github.com/ansible-collections/community.aws/pull/1160"
+- data_pipeline - the ``version`` option has always been ignored and has been removed (https://github.com/ansible-collections/community.aws/pull/1160
- ec2_eip - The ``wait_timeout`` option has been removed. It has always been ignored by the module (https://github.com/ansible-collections/community.aws/pull/1159).
- ec2_lc - the ``associate_public_ip_address`` option has been removed. It has always been ignored by the module (https://github.com/ansible-collections/community.aws/pull/1158).
- ec2_metric_alarm - support for using the ``<=``, ``<``, ``>`` and ``>=`` operators for comparison has been dropped. Please use ``LessThanOrEqualToThreshold``, ``LessThanThreshold``, ``GreaterThanThreshold`` or ``GreaterThanOrEqualToThreshold`` instead (https://github.com/ansible-collections/amazon.aws/pull/1164).
@@ -602,6 +881,33 @@ New Modules
- opensearch_info - obtain information about one or more OpenSearch or ElasticSearch domain
- rds_cluster_snapshot - Manage Amazon RDS snapshots of DB clusters
+v3.6.0
+======
+
+Release Summary
+---------------
+
+Following the release of community.aws 5.0.0, 3.6.0 is a bugfix release and the final planned release for the 3.x series.
+
+
+Minor Changes
+-------------
+
+- autoscaling_group_info - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+- cloudfront_distribution - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+- cloudfront_origin_access_identity - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+- cloudtrail - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+- ec2_asg_lifecycle_hook - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+- ec2_vpc_nacl - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+- redshift - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+- s3_bucket_info - minor sanity test fixes (https://github.com/ansible-collections/community.aws/pull/1410).
+
+Bugfixes
+--------
+
+- ec2_placement_group - Handle a potential race creation during the creation of a new Placement Group (https://github.com/ansible-collections/community.aws/pull/1477).
+- s3_lifecycle - fix bug when deleting rules with an empty prefix (https://github.com/ansible-collections/community.aws/pull/1398).
+
v3.5.0
======
@@ -649,7 +955,7 @@ Deprecated Features
-------------------
- aws_codebuild - The ``tags`` parameter currently uses a non-standard format and has been deprecated. In release 6.0.0 this parameter will accept a simple key/value pair dictionary instead of the current list of dictionaries. It is recommended to migrate to using the resource_tags parameter which already accepts the simple dictionary format (https://github.com/ansible-collections/community.aws/pull/1221).
-- route53_info - The CamelCase return values for ``HostedZones``, ``ResourceRecordSets``, and ``HealthChecks`` have been deprecated, in the future release you must use snake_case return values ``hosted_zones``, ``resource_record_sets``, and ``health_checks`` instead respectively".
+- route53_info - The CamelCase return values for ``HostedZones``, ``ResourceRecordSets``, and ``HealthChecks`` have been deprecated, in the future release you must use snake_case return values ``hosted_zones``, ``resource_record_sets``, and ``health_checks`` instead respectively.
Bugfixes
--------
@@ -914,6 +1220,65 @@ Bugfixes
- aws_eks - Fix EKS cluster creation with short names (https://github.com/ansible-collections/community.aws/pull/818).
+v2.6.1
+======
+
+Release Summary
+---------------
+
+Bump collection from 2.6.0 to 2.6.1 due to a publishing error with 2.6.0. This release supersedes 2.6.0 entirely, users should skip 2.6.0.
+
+v2.6.0
+======
+
+Release Summary
+---------------
+
+This is the last planned 2.x release of the ``community.aws`` collection.
+Consider upgrading to the latest version of ``community.aws`` soon.
+
+Minor Changes
+-------------
+
+- ecs_service - ``deployment_circuit_breaker`` has been added as a supported feature (https://github.com/ansible-collections/community.aws/pull/1215).
+- ecs_service - add ``service`` alias to address the ecs service name with the same parameter as the ecs_service_info module is doing (https://github.com/ansible-collections/community.aws/pull/1187).
+- ecs_service_info - add ``name`` alias to address the ecs service name with the same parameter as the ecs_service module is doing (https://github.com/ansible-collections/community.aws/pull/1187).
+
+Bugfixes
+--------
+
+- ecs_service - fix broken change detect of ``health_check_grace_period_seconds`` parameter when not specified (https://github.com/ansible-collections/community.aws/pull/1212).
+- ecs_service - use default cluster name of ``default`` when not input (https://github.com/ansible-collections/community.aws/pull/1212).
+- ecs_task - dont require ``cluster`` and use name of ``default`` when not input (https://github.com/ansible-collections/community.aws/pull/1212).
+- wafv2_ip_set - fix bug where incorrect changed state was returned when only changing the description (https://github.com/ansible-collections/community.aws/pull/1211).
+
+v2.5.0
+======
+
+Release Summary
+---------------
+
+This is the minor release of the ``community.aws`` collection.
+
+Minor Changes
+-------------
+
+- iam_policy - update broken examples and add RETURN section to documentation; add extra integration tests for idempotency check mode runs (https://github.com/ansible-collections/community.aws/pull/1093).
+- iam_role - delete inline policies prior to deleting role (https://github.com/ansible-collections/community.aws/pull/1054).
+- iam_role - remove global vars and refactor accordingly (https://github.com/ansible-collections/community.aws/pull/1054).
+
+Bugfixes
+--------
+
+- ecs_service - add missing change detect of ``health_check_grace_period_seconds`` parameter (https://github.com/ansible-collections/community.aws/pull/1145).
+- ecs_service - fix broken compare of ``task_definition`` that results always in a changed task (https://github.com/ansible-collections/community.aws/pull/1145).
+- ecs_service - fix validation for ``placement_constraints``. It's possible to use ``distinctInstance`` placement constraint now (https://github.com/ansible-collections/community.aws/issues/1058)
+- ecs_taskdefinition - fix broken change detect of ``launch_type`` parameter (https://github.com/ansible-collections/community.aws/pull/1145).
+- execute_lambda - fix check mode and update RETURN documentation (https://github.com/ansible-collections/community.aws/pull/1115).
+- iam_policy - require one of ``policy_document`` and ``policy_json`` when state is present to prevent MalformedPolicyDocumentException from being thrown (https://github.com/ansible-collections/community.aws/pull/1093).
+- s3_lifecycle - add support of value *0* for ``transition_days`` (https://github.com/ansible-collections/community.aws/pull/1077).
+- s3_lifecycle - check that configuration is complete before returning (https://github.com/ansible-collections/community.aws/pull/1085).
+
v2.4.0
======
@@ -1534,7 +1899,7 @@ Bugfixes
- cloudfront_distribution - Always add field_level_encryption_id to cache behaviour to match AWS requirements
- cloudwatchlogs_log_group - Fix a KeyError when updating a log group that does not have a retention period (https://github.com/ansible/ansible/issues/47945)
- cloudwatchlogs_log_group_info - remove limitation of max 50 results
-- ec2_asg - Ensure "wait" is honored during replace operations
+- ec2_asg - Ensure ``wait`` is honored during replace operations
- ec2_launch_template - Update output to include latest_version and default_version, matching the documentation
- ec2_transit_gateway - Use AWSRetry before ClientError is handled when describing transit gateways
- ec2_transit_gateway - fixed issue where auto_attach set to yes was not being honored (https://github.com/ansible/ansible/issues/61907)
diff --git a/ansible_collections/community/aws/meta/runtime.yml b/ansible_collections/community/aws/meta/runtime.yml
index 6fd39ee0f..5d05436df 100644
--- a/ansible_collections/community/aws/meta/runtime.yml
+++ b/ansible_collections/community/aws/meta/runtime.yml
@@ -1,223 +1,221 @@
---
-requires_ansible: '>=2.11.0'
+requires_ansible: '>=2.12.0'
action_groups:
aws:
- - accessanalyzer_validate_policy_info
- - acm_certificate
- - acm_certificate_info
- - api_gateway
- - api_gateway_domain
- - application_autoscaling_policy
- - autoscaling_complete_lifecycle_action
- - autoscaling_instance_refresh_info
- - autoscaling_instance_refresh
- - autoscaling_launch_config_find
- - autoscaling_launch_config_info
- - autoscaling_launch_config
- - autoscaling_lifecycle_hook
- - autoscaling_policy
- - autoscaling_scheduled_action
- - aws_acm
- - aws_acm_info
- - aws_api_gateway
- - aws_api_gateway_domain
- - aws_application_scaling_policy
- - aws_batch_compute_environment
- - aws_batch_job_definition
- - aws_batch_job_queue
- - aws_codebuild
- - aws_codecommit
- - aws_codepipeline
- - aws_config_aggregation_authorization
- - aws_config_aggregator
- - aws_config_delivery_channel
- - aws_config_recorder
- - aws_config_rule
- - aws_direct_connect_confirm_connection
- - aws_direct_connect_connection
- - aws_direct_connect_gateway
- - aws_direct_connect_link_aggregation_group
- - aws_direct_connect_virtual_interface
- - aws_eks_cluster
- - aws_elasticbeanstalk_app
- - aws_glue_connection
- - aws_glue_crawler
- - aws_glue_job
- - aws_inspector_target
- - aws_msk_cluster
- - aws_msk_config
- - aws_region_info
- - aws_s3_bucket_info
- - aws_s3_cors
- - aws_secret
- - aws_ses_identity
- - aws_ses_identity_policy
- - aws_ses_rule_set
- - aws_sgw_info
- - aws_ssm_parameter_store
- - aws_step_functions_state_machine
- - aws_step_functions_state_machine_execution
- - aws_waf_condition
- - aws_waf_info
- - aws_waf_rule
- - aws_waf_web_acl
- - batch_compute_environment
- - batch_job_definition
- - batch_job_queue
- - cloudformation_exports_info
- - cloudformation_stack_set
- - cloudfront_distribution
- - cloudfront_distribution_info
- - cloudfront_info
- - cloudfront_invalidation
- - cloudfront_origin_access_identity
- - cloudfront_response_headers_policy
- - codebuild_project
- - codecommit_repository
- - codepipeline
- - config_aggregation_authorization
- - config_aggregator
- - config_delivery_channel
- - config_recorder
- - config_rule
- - data_pipeline
- - directconnect_confirm_connection
- - directconnect_connection
- - directconnect_gateway
- - directconnect_link_aggregation_group
- - directconnect_virtual_interface
- - dms_endpoint
- - dms_replication_subnet_group
- - dynamodb_table
- - dynamodb_ttl
- - ec2_ami_copy
- - ec2_asg
- - ec2_asg_info
- - ec2_asg_scheduled_action
- - ec2_asg_instance_refresh
- - ec2_asg_instance_refresh_info
- - ec2_asg_lifecycle_hook
- - ec2_customer_gateway
- - ec2_customer_gateway_info
- - ec2_elb
- - ec2_launch_template
- - ec2_lc
- - ec2_lc_find
- - ec2_lc_info
- - ec2_metric_alarm
- - ec2_placement_group
- - ec2_placement_group_info
- - ec2_scaling_policy
- - ec2_snapshot_copy
- - ec2_transit_gateway
- - ec2_transit_gateway_info
- - ec2_transit_gateway_vpc_attachment
- - ec2_transit_gateway_vpc_attachment_info
- - ec2_vpc_egress_igw
- - ec2_vpc_nacl
- - ec2_vpc_nacl_info
- - ec2_vpc_peer
- - ec2_vpc_peering_info
- - ec2_vpc_vgw
- - ec2_vpc_vgw_info
- - ec2_vpc_vpn
- - ec2_vpc_vpn_info
- - ec2_win_password
- - ecs_attribute
- - ecs_cluster
- - ecs_ecr
- - ecs_service
- - ecs_service_info
- - ecs_tag
- - ecs_task
- - ecs_taskdefinition
- - ecs_taskdefinition_info
- - efs
- - efs_info
- - eks_cluster
- - efs_tag
- - eks_fargate_profile
- - eks_nodegroup
- - elasticbeanstalk_app
- - elasticache
- - elasticache_info
- - elasticache_parameter_group
- - elasticache_snapshot
- - elasticache_subnet_group
- - elb_classic_lb
- - elb_classic_lb_info
- - elb_instance
- - elb_network_lb
- - elb_target
- - elb_target_group
- - elb_target_group_info
- - elb_target_info
- - glue_connection
- - glue_crawler
- - glue_job
- - iam_access_key
- - iam_access_key_info
- - iam_group
- - iam_managed_policy
- - iam_mfa_device_info
- - iam_password_policy
- - iam_role
- - iam_role_info
- - iam_saml_federation
- - iam_server_certificate
- - iam_server_certificate_info
- - inspector_target
- - kinesis_stream
- - lightsail
- - lightsail_static_ip
- - msk_cluster
- - msk_config
- - networkfirewall
- - networkfirewall_info
- - networkfirewall_policy
- - networkfirewall_policy_info
- - networkfirewall_rule_group
- - networkfirewall_rule_group_info
- - opensearch
- - opensearch_info
- - redshift
- - redshift_cross_region_snapshots
- - redshift_info
- - redshift_subnet_group
- - s3_bucket_notification
- - s3_bucket_info
- - s3_cors
- - s3_lifecycle
- - s3_logging
- - s3_metrics_configuration
- - s3_sync
- - s3_website
- - secretsmanager_secret
- - ses_identity
- - ses_identity_policy
- - ses_rule_set
- - sns
- - sns_topic
- - sns_topic_info
- - sqs_queue
- - ssm_parameter
- - stepfunctions_state_machine
- - stepfunctions_state_machine_execution
- - sts_assume_role
- - sts_session_token
- - storagegateway_info
- - waf_condition
- - waf_info
- - waf_rule
- - waf_web_acl
- - wafv2_ip_set
- - wafv2_ip_set_info
- - wafv2_resources
- - wafv2_resources_info
- - wafv2_rule_group
- - wafv2_rule_group_info
- - wafv2_web_acl
- - wafv2_web_acl_info
+ - accessanalyzer_validate_policy_info
+ - acm_certificate
+ - acm_certificate_info
+ - api_gateway
+ - api_gateway_domain
+ - api_gateway_info
+ - application_autoscaling_policy
+ - autoscaling_complete_lifecycle_action
+ - autoscaling_instance_refresh
+ - autoscaling_instance_refresh_info
+ - autoscaling_launch_config
+ - autoscaling_launch_config_find
+ - autoscaling_launch_config_info
+ - autoscaling_lifecycle_hook
+ - autoscaling_policy
+ - autoscaling_scheduled_action
+ - aws_acm
+ - aws_acm_info
+ - aws_api_gateway
+ - aws_api_gateway_domain
+ - aws_application_scaling_policy
+ - aws_batch_compute_environment
+ - aws_batch_job_definition
+ - aws_batch_job_queue
+ - aws_codebuild
+ - aws_codecommit
+ - aws_codepipeline
+ - aws_config_aggregation_authorization
+ - aws_config_aggregator
+ - aws_config_delivery_channel
+ - aws_config_recorder
+ - aws_config_rule
+ - aws_direct_connect_confirm_connection
+ - aws_direct_connect_connection
+ - aws_direct_connect_gateway
+ - aws_direct_connect_link_aggregation_group
+ - aws_direct_connect_virtual_interface
+ - aws_eks_cluster
+ - aws_elasticbeanstalk_app
+ - aws_glue_connection
+ - aws_glue_crawler
+ - aws_glue_job
+ - aws_inspector_target
+ - aws_msk_cluster
+ - aws_msk_config
+ - aws_region_info
+ - aws_s3_cors
+ - aws_secret
+ - aws_ses_identity
+ - aws_ses_identity_policy
+ - aws_ses_rule_set
+ - aws_sgw_info
+ - aws_ssm_parameter_store
+ - aws_step_functions_state_machine
+ - aws_step_functions_state_machine_execution
+ - aws_waf_condition
+ - aws_waf_info
+ - aws_waf_rule
+ - aws_waf_web_acl
+ - batch_compute_environment
+ - batch_job_definition
+ - batch_job_queue
+ - cloudformation_exports_info
+ - cloudformation_stack_set
+ - cloudfront_distribution
+ - cloudfront_distribution_info
+ - cloudfront_info
+ - cloudfront_invalidation
+ - cloudfront_origin_access_identity
+ - cloudfront_response_headers_policy
+ - codebuild_project
+ - codecommit_repository
+ - codepipeline
+ - config_aggregation_authorization
+ - config_aggregator
+ - config_delivery_channel
+ - config_recorder
+ - config_rule
+ - data_pipeline
+ - directconnect_confirm_connection
+ - directconnect_connection
+ - directconnect_gateway
+ - directconnect_link_aggregation_group
+ - directconnect_virtual_interface
+ - dms_endpoint
+ - dms_replication_subnet_group
+ - dynamodb_table
+ - dynamodb_ttl
+ - ec2_ami_copy
+ - ec2_asg
+ - ec2_asg_info
+ - ec2_asg_instance_refresh
+ - ec2_asg_instance_refresh_info
+ - ec2_asg_lifecycle_hook
+ - ec2_asg_scheduled_action
+ - ec2_customer_gateway
+ - ec2_customer_gateway_info
+ - ec2_elb
+ - ec2_launch_template
+ - ec2_lc
+ - ec2_lc_find
+ - ec2_lc_info
+ - ec2_metric_alarm
+ - ec2_placement_group
+ - ec2_placement_group_info
+ - ec2_scaling_policy
+ - ec2_snapshot_copy
+ - ec2_transit_gateway
+ - ec2_transit_gateway_info
+ - ec2_transit_gateway_vpc_attachment
+ - ec2_transit_gateway_vpc_attachment_info
+ - ec2_vpc_egress_igw
+ - ec2_vpc_nacl
+ - ec2_vpc_nacl_info
+ - ec2_vpc_peer
+ - ec2_vpc_peering_info
+ - ec2_vpc_vgw
+ - ec2_vpc_vgw_info
+ - ec2_vpc_vpn
+ - ec2_vpc_vpn_info
+ - ec2_win_password
+ - ecs_attribute
+ - ecs_cluster
+ - ecs_ecr
+ - ecs_service
+ - ecs_service_info
+ - ecs_tag
+ - ecs_task
+ - ecs_taskdefinition
+ - ecs_taskdefinition_info
+ - efs
+ - efs_info
+ - efs_tag
+ - eks_cluster
+ - eks_fargate_profile
+ - eks_nodegroup
+ - elasticache
+ - elasticache_info
+ - elasticache_parameter_group
+ - elasticache_snapshot
+ - elasticache_subnet_group
+ - elasticbeanstalk_app
+ - elb_classic_lb
+ - elb_classic_lb_info
+ - elb_instance
+ - elb_network_lb
+ - elb_target
+ - elb_target_group
+ - elb_target_group_info
+ - elb_target_info
+ - glue_connection
+ - glue_crawler
+ - glue_job
+ - iam_saml_federation
+ - iam_server_certificate
+ - iam_server_certificate_info
+ - inspector_target
+ - kinesis_stream
+ - lightsail
+ - lightsail_snapshot
+ - lightsail_static_ip
+ - mq_broker
+ - mq_broker_config
+ - mq_broker_info
+ - mq_user
+ - mq_user_info
+ - msk_cluster
+ - msk_config
+ - networkfirewall
+ - networkfirewall_info
+ - networkfirewall_policy
+ - networkfirewall_policy_info
+ - networkfirewall_rule_group
+ - networkfirewall_rule_group_info
+ - opensearch
+ - opensearch_info
+ - redshift
+ - redshift_cross_region_snapshots
+ - redshift_info
+ - redshift_subnet_group
+ - route53_wait
+ - s3_bucket_notification
+ - s3_cors
+ - s3_lifecycle
+ - s3_logging
+ - s3_metrics_configuration
+ - s3_sync
+ - s3_website
+ - secretsmanager_secret
+ - ses_identity
+ - ses_identity_policy
+ - ses_rule_set
+ - sns
+ - sns_topic
+ - sns_topic_info
+ - sqs_queue
+ - ssm_inventory_info
+ - ssm_parameter
+ - stepfunctions_state_machine
+ - stepfunctions_state_machine_execution
+ - storagegateway_info
+ - sts_session_token
+ - waf_condition
+ - waf_info
+ - waf_rule
+ - waf_web_acl
+ - wafv2_ip_set
+ - wafv2_ip_set_info
+ - wafv2_resources
+ - wafv2_resources_info
+ - wafv2_rule_group
+ - wafv2_rule_group_info
+ - wafv2_web_acl
+ - wafv2_web_acl_info
plugin_routing:
modules:
autoscaling_group_info:
@@ -317,9 +315,11 @@ plugin_routing:
aws_msk_config:
# Deprecation for this alias should not *start* prior to 2024-09-01
redirect: community.aws.msk_config
+ aws_region_info:
+ redirect: amazon.aws.aws_region_info
aws_s3_bucket_info:
# Deprecation for this alias should not *start* prior to 2024-09-01
- redirect: community.aws.s3_bucket_info
+ redirect: amazon.aws.s3_bucket_info
aws_s3_cors:
# Deprecation for this alias should not *start* prior to 2024-09-01
redirect: community.aws.s3_cors
@@ -445,10 +445,26 @@ plugin_routing:
execute_lambda:
# Deprecation for this alias should not *start* prior to 2024-09-01
redirect: amazon.aws.lambda_execute
+ iam_access_key:
+ redirect: amazon.aws.iam_access_key
+ iam_access_key_info:
+ redirect: amazon.aws.iam_access_key_info
+ iam_group:
+ redirect: amazon.aws.iam_group
+ iam_managed_policy:
+ redirect: amazon.aws.iam_managed_policy
+ iam_mfa_device_info:
+ redirect: amazon.aws.iam_mfa_device_info
+ iam_password_policy:
+ redirect: amazon.aws.iam_password_policy
iam_policy:
redirect: amazon.aws.iam_policy
iam_policy_info:
redirect: amazon.aws.iam_policy_info
+ iam_role:
+ redirect: amazon.aws.iam_role
+ iam_role_info:
+ redirect: amazon.aws.iam_role_info
iam_user:
redirect: amazon.aws.iam_user
iam_user_info:
@@ -499,6 +515,10 @@ plugin_routing:
redirect: amazon.aws.route53_info
route53_zone:
redirect: amazon.aws.route53_zone
+ s3_bucket_info:
+ redirect: amazon.aws.s3_bucket_info
+ sts_assume_role:
+ redirect: amazon.aws.sts_assume_role
module_utils:
route53:
- redirect: amazon.aws.route53
+ redirect: amazon.aws.route53 \ No newline at end of file
diff --git a/ansible_collections/community/aws/plugins/connection/aws_ssm.py b/ansible_collections/community/aws/plugins/connection/aws_ssm.py
index 68d761c9d..5186179f4 100644
--- a/ansible_collections/community/aws/plugins/connection/aws_ssm.py
+++ b/ansible_collections/community/aws/plugins/connection/aws_ssm.py
@@ -1,24 +1,47 @@
-# Based on the ssh connection plugin by Michael DeHaan
-#
+# -*- coding: utf-8 -*-
+
# Copyright: (c) 2018, Pat Sharkey <psharkey@cleo.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
+# Based on the ssh connection plugin by Michael DeHaan
-DOCUMENTATION = '''
-author:
-- Pat Sharkey (@psharkey) <psharkey@cleo.com>
-- HanumanthaRao MVL (@hanumantharaomvl) <hanumanth@flux7.com>
-- Gaurav Ashtikar (@gau1991) <gaurav.ashtikar@flux7.com>
+DOCUMENTATION = r"""
name: aws_ssm
-short_description: execute via AWS Systems Manager
+author:
+ - Pat Sharkey (@psharkey) <psharkey@cleo.com>
+ - HanumanthaRao MVL (@hanumantharaomvl) <hanumanth@flux7.com>
+ - Gaurav Ashtikar (@gau1991) <gaurav.ashtikar@flux7.com>
+
+short_description: connect to EC2 instances via AWS Systems Manager
description:
-- This connection plugin allows ansible to execute tasks on an EC2 instance via the aws ssm CLI.
+ - This connection plugin allows Ansible to execute tasks on an EC2 instance via an AWS SSM Session.
+notes:
+ - The C(community.aws.aws_ssm) connection plugin does not support using the ``remote_user`` and
+ ``ansible_user`` variables to configure the remote user. The ``become_user`` parameter should
+ be used to configure which user to run commands as. Remote commands will often default to
+ running as the ``ssm-agent`` user, however this will also depend on how SSM has been configured.
+ - This plugin requires an S3 bucket to send files to/from the remote instance. This is required even for modules
+ which do not explicitly send files (such as the C(shell) or C(command) modules), because Ansible sends over the C(.py) files of the module itself, via S3.
+ - Files sent via S3 will be named in S3 with the EC2 host ID (e.g. C(i-123abc/)) as the prefix.
+ - The files in S3 will be deleted by the end of the playbook run. If the play is terminated ungracefully, the files may remain in the bucket.
+ If the bucket has versioning enabled, the files will remain in version history. If your tasks involve sending secrets to/from the remote instance
+ (e.g. within a C(shell) command, or a SQL password in the C(community.postgresql.postgresql_query) module) then those passwords will be included in
+ plaintext in those files in S3 indefinitely, visible to anyone with access to that bucket. Therefore it is recommended to use a bucket with versioning
+ disabled/suspended.
+ - The files in S3 will be deleted even if the C(keep_remote_files) setting is C(true).
+
requirements:
-- The remote EC2 instance must be running the AWS Systems Manager Agent (SSM Agent).
-- The control machine must have the aws session manager plugin installed.
-- The remote EC2 linux instance must have the curl installed.
+ - The remote EC2 instance must be running the AWS Systems Manager Agent (SSM Agent).
+ U(https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-getting-started.html)
+ - The control machine must have the AWS session manager plugin installed.
+ U(https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html)
+ - The remote EC2 Linux instance must have curl installed.
+ - The remote EC2 Linux instance and the controller both need network connectivity to S3.
+ - The remote instance does not require IAM credentials for S3. This module will generate a presigned URL for S3 from the controller,
+ and then will pass that URL to the target over SSM, telling the target to download/upload from S3 with C(curl).
+ - The controller requires IAM permissions to upload, download and delete files from the specified S3 bucket. This includes
+ `s3:GetObject`, `s3:PutObject`, `s3:ListBucket`, `s3:DeleteObject` and `s3:GetBucketLocation`.
+
options:
access_key_id:
description: The STS access key to use when connecting via session-manager.
@@ -99,7 +122,11 @@ options:
vars:
- name: ansible_aws_ssm_bucket_sse_kms_key_id
ssm_document:
- description: SSM document to use when connecting.
+ description:
+ - SSM Session document to use when connecting.
+ - To configure the remote_user (when C(become=False), it is possible to use an SSM Session
+ document and define the C(runAsEnabled) and C(runAsDefaultUser) parameters. See also
+ U(https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-schema.html)
vars:
- name: ansible_aws_ssm_document
version_added: 5.2.0
@@ -115,10 +142,10 @@ options:
version_added: 5.2.0
vars:
- name: ansible_aws_ssm_s3_addressing_style
-'''
-
-EXAMPLES = r'''
+"""
+EXAMPLES = r"""
+---
# Wait for SSM Agent to be available on the Instance
- name: Wait for connection to be available
vars:
@@ -171,17 +198,19 @@ EXAMPLES = r'''
path: C:\Windows\temp
state: directory
+---
+
# Making use of Dynamic Inventory Plugin
# =======================================
-# aws_ec2.yml (Dynamic Inventory - Linux)
-# This will return the Instance IDs matching the filter
-#plugin: aws_ec2
-#regions:
-# - us-east-1
-#hostnames:
-# - instance-id
-#filters:
-# tag:SSMTag: ssmlinux
+# # aws_ec2.yml (Dynamic Inventory - Linux)
+# plugin: aws_ec2
+# regions:
+# - us-east-1
+# hostnames:
+# - instance-id
+# # This will return the Instances with the tag "SSMTag" set to "ssmlinux"
+# filters:
+# tag:SSMTag: ssmlinux
# -----------------------
- name: install aws-cli
hosts: all
@@ -191,20 +220,23 @@ EXAMPLES = r'''
ansible_aws_ssm_bucket_name: nameofthebucket
ansible_aws_ssm_region: us-east-1
tasks:
- - name: aws-cli
- raw: yum install -y awscli
- tags: aws-cli
+ - name: aws-cli
+ raw: yum install -y awscli
+ tags: aws-cli
+
+---
+
# Execution: ansible-playbook linux.yaml -i aws_ec2.yml
-# The playbook tasks will get executed on the instance ids returned from the dynamic inventory plugin using ssm connection.
# =====================================================
-# aws_ec2.yml (Dynamic Inventory - Windows)
-#plugin: aws_ec2
-#regions:
-# - us-east-1
-#hostnames:
-# - instance-id
-#filters:
-# tag:SSMTag: ssmwindows
+# # aws_ec2.yml (Dynamic Inventory - Windows)
+# plugin: aws_ec2
+# regions:
+# - us-east-1
+# hostnames:
+# - instance-id
+# # This will return the Instances with the tag "SSMTag" set to "ssmwindows"
+# filters:
+# tag:SSMTag: ssmwindows
# -----------------------
- name: Create a dir.
hosts: all
@@ -219,10 +251,13 @@ EXAMPLES = r'''
win_file:
path: C:\Temp\SSM_Testing5
state: directory
+
+---
+
# Execution: ansible-playbook win_file.yaml -i aws_ec2.yml
# The playbook tasks will get executed on the instance ids returned from the dynamic inventory plugin using ssm connection.
-# Install a Nginx Package on Linux Instance; with specific SSE for file transfer
+# Install a Nginx Package on Linux Instance; with specific SSE CMK used for the file transfer
- name: Install a Nginx Package
vars:
ansible_connection: aws_ssm
@@ -236,7 +271,7 @@ EXAMPLES = r'''
name: nginx
state: present
-# Install a Nginx Package on Linux Instance; with dedicated SSM document
+# Install a Nginx Package on Linux Instance; using the specified SSM document
- name: Install a Nginx Package
vars:
ansible_connection: aws_ssm
@@ -248,7 +283,7 @@ EXAMPLES = r'''
yum:
name: nginx
state: present
-'''
+"""
import os
import getpass
@@ -292,9 +327,10 @@ def _ssm_retry(func):
* remaining_tries is <2
* retries limit reached
"""
+
@wraps(func)
def wrapped(self, *args, **kwargs):
- remaining_tries = int(self.get_option('reconnection_retries')) + 1
+ remaining_tries = int(self.get_option("reconnection_retries")) + 1
cmd_summary = f"{args[0]}..."
for attempt in range(remaining_tries):
try:
@@ -305,7 +341,7 @@ def _ssm_retry(func):
except (AnsibleConnectionFailure, Exception) as e:
if attempt == remaining_tries - 1:
raise
- pause = 2 ** attempt - 1
+ pause = 2**attempt - 1
pause = min(pause, 30)
if isinstance(e, AnsibleConnectionFailure):
@@ -325,28 +361,32 @@ def _ssm_retry(func):
continue
return return_tuple
+
return wrapped
def chunks(lst, n):
"""Yield successive n-sized chunks from lst."""
for i in range(0, len(lst), n):
- yield lst[i:i + n]
+ yield lst[i:i + n] # fmt: skip
class Connection(ConnectionBase):
- ''' AWS SSM based connections '''
+ """AWS SSM based connections"""
+
+ transport = "community.aws.aws_ssm"
+ default_user = ""
- transport = 'community.aws.aws_ssm'
allow_executable = False
allow_extras = True
has_pipelining = False
is_windows = False
+
_client = None
_s3_client = None
_session = None
_stdout = None
- _session_id = ''
+ _session_id = ""
_timeout = False
MARK_LENGTH = 26
@@ -377,18 +417,20 @@ class Connection(ConnectionBase):
(new AWS regions and new buckets in a region other than the one we're running in)
"""
- region_name = self.get_option('region') or 'us-east-1'
- profile_name = self.get_option('profile') or ''
+ region_name = self.get_option("region") or "us-east-1"
+ profile_name = self.get_option("profile") or ""
self._vvvv("_get_bucket_endpoint: S3 (global)")
tmp_s3_client = self._get_boto_client(
- 's3', region_name=region_name, profile_name=profile_name,
+ "s3",
+ region_name=region_name,
+ profile_name=profile_name,
)
# Fetch the location of the bucket so we can open a client against the 'right' endpoint
# This /should/ always work
bucket_location = tmp_s3_client.get_bucket_location(
- Bucket=(self.get_option('bucket_name')),
+ Bucket=(self.get_option("bucket_name")),
)
- bucket_region = bucket_location['LocationConstraint']
+ bucket_region = bucket_location["LocationConstraint"]
if self.get_option("bucket_endpoint_url"):
return self.get_option("bucket_endpoint_url"), bucket_region
@@ -396,28 +438,35 @@ class Connection(ConnectionBase):
# Create another client for the region the bucket lives in, so we can nab the endpoint URL
self._vvvv(f"_get_bucket_endpoint: S3 (bucket region) - {bucket_region}")
s3_bucket_client = self._get_boto_client(
- 's3', region_name=bucket_region, profile_name=profile_name,
+ "s3",
+ region_name=bucket_region,
+ profile_name=profile_name,
)
return s3_bucket_client.meta.endpoint_url, s3_bucket_client.meta.region_name
def _init_clients(self):
self._vvvv("INITIALIZE BOTO3 CLIENTS")
- profile_name = self.get_option('profile') or ''
- region_name = self.get_option('region')
+ profile_name = self.get_option("profile") or ""
+ region_name = self.get_option("region")
# The SSM Boto client, currently used to initiate and manage the session
# Note: does not handle the actual SSM session traffic
self._vvvv("SETUP BOTO3 CLIENTS: SSM")
ssm_client = self._get_boto_client(
- 'ssm', region_name=region_name, profile_name=profile_name,
+ "ssm",
+ region_name=region_name,
+ profile_name=profile_name,
)
self._client = ssm_client
s3_endpoint_url, s3_region_name = self._get_bucket_endpoint()
self._vvvv(f"SETUP BOTO3 CLIENTS: S3 {s3_endpoint_url}")
s3_bucket_client = self._get_boto_client(
- 's3', region_name=s3_region_name, endpoint_url=s3_endpoint_url, profile_name=profile_name,
+ "s3",
+ region_name=s3_region_name,
+ endpoint_url=s3_endpoint_url,
+ profile_name=profile_name,
)
self._s3_client = s3_bucket_client
@@ -430,21 +479,21 @@ class Connection(ConnectionBase):
self.host = self._play_context.remote_addr
- if getattr(self._shell, "SHELL_FAMILY", '') == 'powershell':
+ if getattr(self._shell, "SHELL_FAMILY", "") == "powershell":
self.delegate = None
self.has_native_async = True
self.always_pipeline_modules = True
- self.module_implementation_preferences = ('.ps1', '.exe', '')
+ self.module_implementation_preferences = (".ps1", ".exe", "")
self.protocol = None
self.shell_id = None
- self._shell_type = 'powershell'
+ self._shell_type = "powershell"
self.is_windows = True
def __del__(self):
self.close()
def _connect(self):
- ''' connect to the host via ssm '''
+ """connect to the host via ssm"""
self._play_context.remote_user = getpass.getuser()
@@ -453,36 +502,37 @@ class Connection(ConnectionBase):
return self
def reset(self):
- ''' start a fresh ssm session '''
- self._vvvv('reset called on ssm connection')
+ """start a fresh ssm session"""
+ self._vvvv("reset called on ssm connection")
+ self.close()
return self.start_session()
def start_session(self):
- ''' start ssm session '''
+ """start ssm session"""
- if self.get_option('instance_id') is None:
+ if self.get_option("instance_id") is None:
self.instance_id = self.host
else:
- self.instance_id = self.get_option('instance_id')
+ self.instance_id = self.get_option("instance_id")
self._vvv(f"ESTABLISH SSM CONNECTION TO: {self.instance_id}")
- executable = self.get_option('plugin')
- if not os.path.exists(to_bytes(executable, errors='surrogate_or_strict')):
+ executable = self.get_option("plugin")
+ if not os.path.exists(to_bytes(executable, errors="surrogate_or_strict")):
raise AnsibleError(f"failed to find the executable specified {executable}.")
self._init_clients()
self._vvvv(f"START SSM SESSION: {self.instance_id}")
start_session_args = dict(Target=self.instance_id, Parameters={})
- document_name = self.get_option('ssm_document')
+ document_name = self.get_option("ssm_document")
if document_name is not None:
- start_session_args['DocumentName'] = document_name
+ start_session_args["DocumentName"] = document_name
response = self._client.start_session(**start_session_args)
- self._session_id = response['SessionId']
+ self._session_id = response["SessionId"]
- region_name = self.get_option('region')
- profile_name = self.get_option('profile') or ''
+ region_name = self.get_option("region")
+ profile_name = self.get_option("profile") or ""
cmd = [
executable,
json.dumps(response),
@@ -506,7 +556,7 @@ class Connection(ConnectionBase):
)
os.close(stdout_w)
- self._stdout = os.fdopen(stdout_r, 'rb', 0)
+ self._stdout = os.fdopen(stdout_r, "rb", 0)
self._session = session
self._poll_stdout = select.poll()
self._poll_stdout.register(self._stdout, select.POLLIN)
@@ -520,7 +570,7 @@ class Connection(ConnectionBase):
@_ssm_retry
def exec_command(self, cmd, in_data=None, sudoable=True):
- ''' run a command on the ssm host '''
+ """run a command on the ssm host"""
super().exec_command(cmd, in_data=in_data, sudoable=sudoable)
@@ -541,20 +591,19 @@ class Connection(ConnectionBase):
self._flush_stderr(session)
for chunk in chunks(cmd, 1024):
- session.stdin.write(to_bytes(chunk, errors='surrogate_or_strict'))
+ session.stdin.write(to_bytes(chunk, errors="surrogate_or_strict"))
# Read stdout between the markers
- stdout = ''
- win_line = ''
+ stdout = ""
+ win_line = ""
begin = False
- stop_time = int(round(time.time())) + self.get_option('ssm_timeout')
+ stop_time = int(round(time.time())) + self.get_option("ssm_timeout")
while session.poll() is None:
remaining = stop_time - int(round(time.time()))
if remaining < 1:
self._timeout = True
self._vvvv(f"EXEC timeout stdout: \n{to_text(stdout)}")
- raise AnsibleConnectionFailure(
- f"SSM exec_command timeout on host: {self.instance_id}")
+ raise AnsibleConnectionFailure(f"SSM exec_command timeout on host: {self.instance_id}")
if self._poll_stdout.poll(1000):
line = self._filter_ansi(self._stdout.readline())
self._vvvv(f"EXEC stdout line: \n{to_text(line)}")
@@ -569,7 +618,7 @@ class Connection(ConnectionBase):
if mark_start in line:
begin = True
if not line.startswith(mark_start):
- stdout = ''
+ stdout = ""
continue
if begin:
if mark_end in line:
@@ -584,7 +633,7 @@ class Connection(ConnectionBase):
return (returncode, stdout, stderr)
def _prepare_terminal(self):
- ''' perform any one-time terminal settings '''
+ """perform any one-time terminal settings"""
# No windows setup for now
if self.is_windows:
return
@@ -599,16 +648,12 @@ class Connection(ConnectionBase):
disable_echo_cmd = to_bytes("stty -echo\n", errors="surrogate_or_strict")
disable_prompt_complete = None
- end_mark = "".join(
- [random.choice(string.ascii_letters) for i in xrange(self.MARK_LENGTH)]
- )
+ end_mark = "".join([random.choice(string.ascii_letters) for i in xrange(self.MARK_LENGTH)])
disable_prompt_cmd = to_bytes(
- "PS1='' ; printf '\\n%s\\n' '" + end_mark + "'\n",
+ "PS1='' ; bind 'set enable-bracketed-paste off'; printf '\\n%s\\n' '" + end_mark + "'\n",
errors="surrogate_or_strict",
)
- disable_prompt_reply = re.compile(
- r"\r\r\n" + re.escape(end_mark) + r"\r\r\n", re.MULTILINE
- )
+ disable_prompt_reply = re.compile(r"\r\r\n" + re.escape(end_mark) + r"\r\r\n", re.MULTILINE)
stdout = ""
# Custom command execution for when we're waiting for startup
@@ -618,9 +663,7 @@ class Connection(ConnectionBase):
if remaining < 1:
self._timeout = True
self._vvvv(f"PRE timeout stdout: \n{to_bytes(stdout)}")
- raise AnsibleConnectionFailure(
- f"SSM start_session timeout on host: {self.instance_id}"
- )
+ raise AnsibleConnectionFailure(f"SSM start_session timeout on host: {self.instance_id}")
if self._poll_stdout.poll(1000):
stdout += to_text(self._stdout.read(1024))
self._vvvv(f"PRE stdout line: \n{to_bytes(stdout)}")
@@ -654,36 +697,32 @@ class Connection(ConnectionBase):
if disable_prompt_complete is False:
match = disable_prompt_reply.search(stdout)
if match:
- stdout = stdout[match.end():]
+ stdout = stdout[match.end():] # fmt: skip
disable_prompt_complete = True
if not disable_prompt_complete:
- raise AnsibleConnectionFailure(
- f"SSM process closed during _prepare_terminal on host: {self.instance_id}"
- )
+ raise AnsibleConnectionFailure(f"SSM process closed during _prepare_terminal on host: {self.instance_id}")
self._vvvv("PRE Terminal configured")
def _wrap_command(self, cmd, sudoable, mark_start, mark_end):
- ''' wrap command so stdout and status can be extracted '''
+ """wrap command so stdout and status can be extracted"""
if self.is_windows:
if not cmd.startswith(" ".join(_common_args) + " -EncodedCommand"):
cmd = self._shell._encode_script(cmd, preserve_rc=True)
cmd = cmd + "; echo " + mark_start + "\necho " + mark_end + "\n"
else:
- if sudoable:
- cmd = "sudo " + cmd
cmd = (
f"printf '%s\\n' '{mark_start}';\n"
f"echo | {cmd};\n"
f"printf '\\n%s\\n%s\\n' \"$?\" '{mark_end}';\n"
- )
+ ) # fmt: skip
self._vvvv(f"_wrap_command: \n'{to_text(cmd)}'")
return cmd
def _post_process(self, stdout, mark_begin):
- ''' extract command status and strip unwanted lines '''
+ """extract command status and strip unwanted lines"""
if not self.is_windows:
# Get command return code
@@ -691,50 +730,50 @@ class Connection(ConnectionBase):
# Throw away final lines
for _x in range(0, 3):
- stdout = stdout[:stdout.rfind('\n')]
+ stdout = stdout[:stdout.rfind('\n')] # fmt: skip
return (returncode, stdout)
# Windows is a little more complex
# Value of $LASTEXITCODE will be the line after the mark
- trailer = stdout[stdout.rfind(mark_begin):]
+ trailer = stdout[stdout.rfind(mark_begin):] # fmt: skip
last_exit_code = trailer.splitlines()[1]
if last_exit_code.isdigit:
returncode = int(last_exit_code)
else:
returncode = -1
# output to keep will be before the mark
- stdout = stdout[:stdout.rfind(mark_begin)]
+ stdout = stdout[:stdout.rfind(mark_begin)] # fmt: skip
# If it looks like JSON remove any newlines
- if stdout.startswith('{'):
- stdout = stdout.replace('\n', '')
+ if stdout.startswith("{"):
+ stdout = stdout.replace("\n", "")
return (returncode, stdout)
def _filter_ansi(self, line):
- ''' remove any ANSI terminal control codes '''
+ """remove any ANSI terminal control codes"""
line = to_text(line)
if self.is_windows:
- osc_filter = re.compile(r'\x1b\][^\x07]*\x07')
- line = osc_filter.sub('', line)
- ansi_filter = re.compile(r'(\x9B|\x1B\[)[0-?]*[ -/]*[@-~]')
- line = ansi_filter.sub('', line)
+ osc_filter = re.compile(r"\x1b\][^\x07]*\x07")
+ line = osc_filter.sub("", line)
+ ansi_filter = re.compile(r"(\x9B|\x1B\[)[0-?]*[ -/]*[@-~]")
+ line = ansi_filter.sub("", line)
# Replace or strip sequence (at terminal width)
- line = line.replace('\r\r\n', '\n')
+ line = line.replace("\r\r\n", "\n")
if len(line) == 201:
line = line[:-1]
return line
def _flush_stderr(self, session_process):
- ''' read and return stderr with minimal blocking '''
+ """read and return stderr with minimal blocking"""
poll_stderr = select.poll()
poll_stderr.register(session_process.stderr, select.POLLIN)
- stderr = ''
+ stderr = ""
while session_process.poll() is None:
if not poll_stderr.poll(1):
@@ -746,20 +785,20 @@ class Connection(ConnectionBase):
return stderr
def _get_url(self, client_method, bucket_name, out_path, http_method, extra_args=None):
- ''' Generate URL for get_object / put_object '''
+ """Generate URL for get_object / put_object"""
client = self._s3_client
- params = {'Bucket': bucket_name, 'Key': out_path}
+ params = {"Bucket": bucket_name, "Key": out_path}
if extra_args is not None:
params.update(extra_args)
return client.generate_presigned_url(client_method, Params=params, ExpiresIn=3600, HttpMethod=http_method)
def _get_boto_client(self, service, region_name=None, profile_name=None, endpoint_url=None):
- ''' Gets a boto3 client based on the STS token '''
+ """Gets a boto3 client based on the STS token"""
- aws_access_key_id = self.get_option('access_key_id')
- aws_secret_access_key = self.get_option('secret_access_key')
- aws_session_token = self.get_option('session_token')
+ aws_access_key_id = self.get_option("access_key_id")
+ aws_secret_access_key = self.get_option("secret_access_key")
+ aws_session_token = self.get_option("session_token")
session_args = dict(
aws_access_key_id=aws_access_key_id,
@@ -768,7 +807,7 @@ class Connection(ConnectionBase):
region_name=region_name,
)
if profile_name:
- session_args['profile_name'] = profile_name
+ session_args["profile_name"] = profile_name
session = boto3.session.Session(**session_args)
client = session.client(
@@ -776,8 +815,8 @@ class Connection(ConnectionBase):
endpoint_url=endpoint_url,
config=Config(
signature_version="s3v4",
- s3={'addressing_style': self.get_option('s3_addressing_style')}
- )
+ s3={"addressing_style": self.get_option("s3_addressing_style")},
+ ),
)
return client
@@ -787,21 +826,21 @@ class Connection(ConnectionBase):
def _generate_encryption_settings(self):
put_args = {}
put_headers = {}
- if not self.get_option('bucket_sse_mode'):
+ if not self.get_option("bucket_sse_mode"):
return put_args, put_headers
- put_args['ServerSideEncryption'] = self.get_option('bucket_sse_mode')
- put_headers['x-amz-server-side-encryption'] = self.get_option('bucket_sse_mode')
- if self.get_option('bucket_sse_mode') == 'aws:kms' and self.get_option('bucket_sse_kms_key_id'):
- put_args['SSEKMSKeyId'] = self.get_option('bucket_sse_kms_key_id')
- put_headers['x-amz-server-side-encryption-aws-kms-key-id'] = self.get_option('bucket_sse_kms_key_id')
+ put_args["ServerSideEncryption"] = self.get_option("bucket_sse_mode")
+ put_headers["x-amz-server-side-encryption"] = self.get_option("bucket_sse_mode")
+ if self.get_option("bucket_sse_mode") == "aws:kms" and self.get_option("bucket_sse_kms_key_id"):
+ put_args["SSEKMSKeyId"] = self.get_option("bucket_sse_kms_key_id")
+ put_headers["x-amz-server-side-encryption-aws-kms-key-id"] = self.get_option("bucket_sse_kms_key_id")
return put_args, put_headers
def _generate_commands(self, bucket_name, s3_path, in_path, out_path):
put_args, put_headers = self._generate_encryption_settings()
- put_url = self._get_url('put_object', bucket_name, s3_path, 'PUT', extra_args=put_args)
- get_url = self._get_url('get_object', bucket_name, s3_path, 'GET')
+ put_url = self._get_url("put_object", bucket_name, s3_path, "PUT", extra_args=put_args)
+ get_url = self._get_url("get_object", bucket_name, s3_path, "GET")
if self.is_windows:
put_command_headers = "; ".join([f"'{h}' = '{v}'" for h, v in put_headers.items()])
@@ -813,14 +852,14 @@ class Connection(ConnectionBase):
f"-Uri '{put_url}' "
f"-UseBasicParsing"
),
- ]
+ ] # fmt: skip
get_commands = [
(
"Invoke-WebRequest "
f"'{get_url}' "
f"-OutFile '{out_path}'"
),
- ]
+ ] # fmt: skip
else:
put_command_headers = " ".join([f"-H '{h}: {v}'" for h, v in put_headers.items()])
put_commands = [
@@ -830,7 +869,7 @@ class Connection(ConnectionBase):
f"--upload-file '{in_path}' "
f"'{put_url}'"
),
- ]
+ ] # fmt: skip
get_commands = [
(
"curl "
@@ -846,20 +885,18 @@ class Connection(ConnectionBase):
"touch "
f"'{out_path}'"
)
- ]
+ ] # fmt: skip
return get_commands, put_commands, put_args
def _exec_transport_commands(self, in_path, out_path, commands):
- stdout_combined, stderr_combined = '', ''
+ stdout_combined, stderr_combined = "", ""
for command in commands:
(returncode, stdout, stderr) = self.exec_command(command, in_data=None, sudoable=False)
# Check the return code
if returncode != 0:
- raise AnsibleError(
- f"failed to transfer file to {in_path} {out_path}:\n"
- f"{stdout}\n{stderr}")
+ raise AnsibleError(f"failed to transfer file to {in_path} {out_path}:\n{stdout}\n{stderr}")
stdout_combined += stdout
stderr_combined += stderr
@@ -868,24 +905,27 @@ class Connection(ConnectionBase):
@_ssm_retry
def _file_transport_command(self, in_path, out_path, ssm_action):
- ''' transfer a file to/from host using an intermediate S3 bucket '''
+ """transfer a file to/from host using an intermediate S3 bucket"""
bucket_name = self.get_option("bucket_name")
s3_path = self._escape_path(f"{self.instance_id}/{out_path}")
get_commands, put_commands, put_args = self._generate_commands(
- bucket_name, s3_path, in_path, out_path,
+ bucket_name,
+ s3_path,
+ in_path,
+ out_path,
)
client = self._s3_client
try:
- if ssm_action == 'get':
+ if ssm_action == "get":
(returncode, stdout, stderr) = self._exec_transport_commands(in_path, out_path, put_commands)
- with open(to_bytes(out_path, errors='surrogate_or_strict'), 'wb') as data:
+ with open(to_bytes(out_path, errors="surrogate_or_strict"), "wb") as data:
client.download_fileobj(bucket_name, s3_path, data)
else:
- with open(to_bytes(in_path, errors='surrogate_or_strict'), 'rb') as data:
+ with open(to_bytes(in_path, errors="surrogate_or_strict"), "rb") as data:
client.upload_fileobj(data, bucket_name, s3_path, ExtraArgs=put_args)
(returncode, stdout, stderr) = self._exec_transport_commands(in_path, out_path, get_commands)
return (returncode, stdout, stderr)
@@ -894,28 +934,27 @@ class Connection(ConnectionBase):
client.delete_object(Bucket=bucket_name, Key=s3_path)
def put_file(self, in_path, out_path):
- ''' transfer a file from local to remote '''
+ """transfer a file from local to remote"""
super().put_file(in_path, out_path)
self._vvv(f"PUT {in_path} TO {out_path}")
- if not os.path.exists(to_bytes(in_path, errors='surrogate_or_strict')):
+ if not os.path.exists(to_bytes(in_path, errors="surrogate_or_strict")):
raise AnsibleFileNotFound(f"file or module does not exist: {in_path}")
- return self._file_transport_command(in_path, out_path, 'put')
+ return self._file_transport_command(in_path, out_path, "put")
def fetch_file(self, in_path, out_path):
- ''' fetch a file from remote to local '''
+ """fetch a file from remote to local"""
super().fetch_file(in_path, out_path)
self._vvv(f"FETCH {in_path} TO {out_path}")
- return self._file_transport_command(in_path, out_path, 'get')
+ return self._file_transport_command(in_path, out_path, "get")
def close(self):
- ''' terminate the connection '''
+ """terminate the connection"""
if self._session_id:
-
self._vvv(f"CLOSING SSM CONNECTION TO: {self.instance_id}")
if self._timeout:
self._session.terminate()
@@ -925,4 +964,4 @@ class Connection(ConnectionBase):
self._vvvv(f"TERMINATE SSM SESSION: {self._session_id}")
self._client.terminate_session(SessionId=self._session_id)
- self._session_id = ''
+ self._session_id = ""
diff --git a/ansible_collections/community/aws/plugins/inventory/aws_mq.py b/ansible_collections/community/aws/plugins/inventory/aws_mq.py
new file mode 100644
index 000000000..3ca1a6a97
--- /dev/null
+++ b/ansible_collections/community/aws/plugins/inventory/aws_mq.py
@@ -0,0 +1,297 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2023 Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r"""
+name: aws_mq
+version_added: 6.1.0
+short_description: MQ broker inventory source
+description:
+ - Get brokers from Amazon Web Services MQ.
+ - Uses a YAML configuration file that ends with aws_mq.(yml|yaml).
+options:
+ regions:
+ description:
+ - A list of regions in which to describe MQ brokers. Available regions are listed here
+ U(https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services/)
+ type: list
+ elements: str
+ default: []
+ strict_permissions:
+ description: By default if an AccessDenied exception is encountered this plugin will fail. You can set I(strict_permissions) to
+ C(False) in the inventory config file which will allow the restrictions to be gracefully skipped.
+ type: bool
+ default: True
+ statuses:
+ description:
+ - A list of desired states for brokers to be added to inventory. Set to C(['all']) as a shorthand to find everything.
+ Possible value are listed here U(https://docs.aws.amazon.com/amazon-mq/latest/developer-guide/broker-statuses.html)
+ type: list
+ elements: str
+ default:
+ - RUNNING
+ - CREATION_IN_PROGRESS
+ hostvars_prefix:
+ description:
+ - The prefix for host variables names coming from AWS.
+ type: str
+ hostvars_suffix:
+ description:
+ - The suffix for host variables names coming from AWS.
+ type: str
+extends_documentation_fragment:
+ - inventory_cache
+ - constructed
+ - amazon.aws.boto3
+ - amazon.aws.common.plugins
+ - amazon.aws.region.plugins
+ - amazon.aws.assume_role.plugins
+author:
+ - Ali AlKhalidi (@doteast)
+"""
+
+EXAMPLES = r"""
+---
+# Minimal example using AWS credentials from environment vars or instance role credentials
+# Get all brokers in us-east-1 region
+plugin: community.aws.aws_mq
+regions:
+ - ca-central-1
+
+---
+
+# Example multiple regions, ignoring permission errors, and only brokers with state RUNNING
+plugin: community.aws.aws_mq
+regions:
+ - us-east-1
+ - us-east-2
+strict_permissions: false
+statuses:
+ - RUNNING
+
+---
+
+# Example group by engine, hostvars custom prefix-suffix, and compose variable from tags
+plugin: community.aws.aws_mq
+regions:
+ - ca-central-1
+keyed_groups:
+ - key: engine_type
+ prefix: mq
+compose:
+ app: 'tags.Applications|split(",")'
+hostvars_prefix: aws_
+hostvars_suffix: _mq
+"""
+
+try:
+ import botocore
+except ImportError:
+ pass # will be captured by imported HAS_BOTO3
+
+from ansible.errors import AnsibleError
+from ansible.module_utils._text import to_native
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.plugin_utils.inventory import AWSInventoryBase
+
+broker_attr = [
+ "MaintenanceWindowStartTime",
+ "AutoMinorVersionUpgrade",
+ "AuthenticationStrategy",
+ "PubliclyAccessible",
+ "EncryptionOptions",
+ "HostInstanceType",
+ "BrokerInstances",
+ "SecurityGroups",
+ "DeploymentMode",
+ "EngineVersion",
+ "StorageType",
+ "BrokerState",
+ "EngineType",
+ "SubnetIds",
+ "BrokerArn",
+ "BrokerId",
+ "Created",
+ "Logs",
+]
+
+inventory_group = "aws_mq"
+
+
+def _find_hosts_matching_statuses(hosts, statuses):
+ if not statuses:
+ statuses = ["RUNNING", "CREATION_IN_PROGRESS"]
+ if "all" in statuses:
+ return hosts
+ valid_hosts = []
+ for host in hosts:
+ if host.get("BrokerState") in statuses:
+ valid_hosts.append(host)
+ return valid_hosts
+
+
+def _get_mq_hostname(host):
+ if host.get("BrokerName"):
+ return host["BrokerName"]
+
+
+def _get_broker_host_tags(detail):
+ tags = []
+ if "Tags" in detail:
+ for key, value in detail["Tags"].items():
+ tags.append({"Key": key, "Value": value})
+ return tags
+
+
+def _add_details_to_hosts(connection, hosts, strict):
+ for host in hosts:
+ detail = None
+ resource_id = host["BrokerId"]
+ try:
+ detail = connection.describe_broker(BrokerId=resource_id)
+ except is_boto3_error_code("AccessDenied") as e:
+ if not strict:
+ pass
+ else:
+ raise AnsibleError(f"Failed to query MQ: {to_native(e)}")
+ except (
+ botocore.exceptions.BotoCoreError,
+ botocore.exceptions.ClientError,
+ ) as e: # pylint: disable=duplicate-except
+ raise AnsibleError(f"Failed to query MQ: {to_native(e)}")
+
+ if detail:
+ # special handling of tags
+ host["Tags"] = _get_broker_host_tags(detail)
+
+ # collect rest of attributes
+ for attr in broker_attr:
+ if attr in detail:
+ host[attr] = detail[attr]
+
+
+class InventoryModule(AWSInventoryBase):
+ NAME = "community.aws.aws_mq"
+ INVENTORY_FILE_SUFFIXES = ("aws_mq.yml", "aws_mq.yaml")
+
+ def __init__(self):
+ super(InventoryModule, self).__init__()
+
+ def _get_broker_hosts(self, connection, strict):
+ def _boto3_paginate_wrapper(func, *args, **kwargs):
+ results = []
+ try:
+ results = func(*args, **kwargs)
+ results = results["BrokerSummaries"]
+ _add_details_to_hosts(connection, results, strict)
+ except is_boto3_error_code("AccessDenied") as e: # pylint: disable=duplicate-except
+ if not strict:
+ results = []
+ else:
+ raise AnsibleError(f"Failed to query MQ: {to_native(e)}")
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
+ raise AnsibleError(f"Failed to query MQ: {to_native(e)}")
+ return results
+
+ return _boto3_paginate_wrapper
+
+ def _get_all_hosts(self, regions, strict, statuses):
+ """
+ :param regions: a list of regions in which to describe hosts
+ :param strict: a boolean determining whether to fail or ignore 403 error codes
+ :param statuses: a list of statuses that the returned hosts should match
+ :return A list of host dictionaries
+ """
+ all_instances = []
+
+ for connection, _region in self.all_clients("mq"):
+ paginator = connection.get_paginator("list_brokers")
+ all_instances.extend(self._get_broker_hosts(connection, strict)(paginator.paginate().build_full_result))
+ sorted_hosts = list(sorted(all_instances, key=lambda x: x["BrokerName"]))
+ return _find_hosts_matching_statuses(sorted_hosts, statuses)
+
+ def _populate_from_cache(self, cache_data):
+ hostvars = cache_data.pop("_meta", {}).get("hostvars", {})
+ for group in cache_data:
+ if group == "all":
+ continue
+ self.inventory.add_group(group)
+ hosts = cache_data[group].get("hosts", [])
+ for host in hosts:
+ self._populate_host_vars([host], hostvars.get(host, {}), group)
+ self.inventory.add_child("all", group)
+
+ def _populate(self, hosts):
+ group = inventory_group
+ self.inventory.add_group(group)
+ if hosts:
+ self._add_hosts(hosts=hosts, group=group)
+ self.inventory.add_child("all", group)
+
+ def _format_inventory(self, hosts):
+ results = {"_meta": {"hostvars": {}}}
+ group = inventory_group
+ results[group] = {"hosts": []}
+ for host in hosts:
+ hostname = _get_mq_hostname(host)
+ results[group]["hosts"].append(hostname)
+ h = self.inventory.get_host(hostname)
+ results["_meta"]["hostvars"][h.name] = h.vars
+ return results
+
+ def _add_hosts(self, hosts, group):
+ """
+ :param hosts: a list of hosts to add to the group
+ :param group: name of the group the host list belongs to
+ """
+ for host in hosts:
+ hostname = _get_mq_hostname(host)
+ host = camel_dict_to_snake_dict(host, ignore_list=["Tags", "EngineType"])
+ host["tags"] = boto3_tag_list_to_ansible_dict(host.get("tags", []))
+ if host.get("engine_type"):
+ # align value with API spec of all upper
+ host["engine_type"] = host.get("engine_type", "").upper()
+
+ self.inventory.add_host(hostname, group=group)
+ new_vars = dict()
+ hostvars_prefix = self.get_option("hostvars_prefix")
+ hostvars_suffix = self.get_option("hostvars_suffix")
+ for hostvar, hostval in host.items():
+ if hostvars_prefix:
+ hostvar = hostvars_prefix + hostvar
+ if hostvars_suffix:
+ hostvar = hostvar + hostvars_suffix
+ new_vars[hostvar] = hostval
+ self.inventory.set_variable(hostname, hostvar, hostval)
+ host.update(new_vars)
+
+ strict = self.get_option("strict")
+ self._set_composite_vars(self.get_option("compose"), host, hostname, strict=strict)
+ self._add_host_to_composed_groups(self.get_option("groups"), host, hostname, strict=strict)
+ self._add_host_to_keyed_groups(self.get_option("keyed_groups"), host, hostname, strict=strict)
+
+ def parse(self, inventory, loader, path, cache=True):
+ super().parse(inventory, loader, path, cache=cache)
+
+ # get user specifications
+ regions = self.get_option("regions")
+ strict_permissions = self.get_option("strict_permissions")
+ statuses = self.get_option("statuses")
+
+ result_was_cached, results = self.get_cached_result(path, cache)
+ if result_was_cached:
+ self._populate_from_cache(results)
+ return
+
+ results = self._get_all_hosts(regions, strict_permissions, statuses)
+ self._populate(results)
+
+ formatted_inventory = self._format_inventory(results)
+ self.update_cached_result(path, cache, formatted_inventory)
diff --git a/ansible_collections/community/aws/plugins/module_utils/base.py b/ansible_collections/community/aws/plugins/module_utils/base.py
index 1ce732d7a..86b846c63 100644
--- a/ansible_collections/community/aws/plugins/module_utils/base.py
+++ b/ansible_collections/community/aws/plugins/module_utils/base.py
@@ -1,3 +1,5 @@
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
@@ -7,9 +9,6 @@
# sense for it to start life in community.aws.
#
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
from copy import deepcopy
from functools import wraps
@@ -23,7 +22,7 @@ from ansible.module_utils.common.dict_transformations import camel_dict_to_snake
from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
-class BaseWaiterFactory():
+class BaseWaiterFactory:
"""
A helper class used for creating additional waiters.
Unlike the waiters available directly from botocore these waiters will
@@ -40,6 +39,7 @@ class BaseWaiterFactory():
waiter = waiters.get_waiter('my_waiter_name')
waiter.wait(**params)
"""
+
module = None
client = None
@@ -114,9 +114,14 @@ class BaseWaiterFactory():
def _inject_ratelimit_retries(self, model):
extra_retries = [
- 'RequestLimitExceeded', 'Unavailable', 'ServiceUnavailable',
- 'InternalFailure', 'InternalError', 'TooManyRequestsException',
- 'Throttling']
+ "RequestLimitExceeded",
+ "Unavailable",
+ "ServiceUnavailable",
+ "InternalFailure",
+ "InternalError",
+ "TooManyRequestsException",
+ "Throttling",
+ ]
acceptors = []
for error in extra_retries:
@@ -131,15 +136,15 @@ class BaseWaiterFactory():
def get_waiter(self, waiter_name):
waiters = self._model.waiter_names
if waiter_name not in waiters:
- self.module.fail_json(
- 'Unable to find waiter {0}. Available_waiters: {1}'
- .format(waiter_name, waiters))
+ self.module.fail_json(f"Unable to find waiter {waiter_name}. Available_waiters: {waiters}")
return botocore.waiter.create_waiter_with_client(
- waiter_name, self._model, self.client,
+ waiter_name,
+ self._model,
+ self.client,
)
-class Boto3Mixin():
+class Boto3Mixin:
@staticmethod
def aws_error_handler(description):
r"""
@@ -177,11 +182,13 @@ class Boto3Mixin():
extra_ouput = _self._extra_error_output()
try:
return func(_self, *args, **kwargs)
- except (botocore.exceptions.WaiterError) as e:
- _self.module.fail_json_aws(e, msg='Failed waiting for {DESC}'.format(DESC=description), **extra_ouput)
+ except botocore.exceptions.WaiterError as e:
+ _self.module.fail_json_aws(e, msg=f"Failed waiting for {description}", **extra_ouput)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- _self.module.fail_json_aws(e, msg='Failed to {DESC}'.format(DESC=description), **extra_ouput)
+ _self.module.fail_json_aws(e, msg=f"Failed to {description}", **extra_ouput)
+
return handler
+
return wrapper
def _normalize_boto3_resource(self, resource, add_tags=False):
@@ -199,7 +206,7 @@ class Boto3Mixin():
if resource is None:
return None
- tags = resource.get('Tags', None)
+ tags = resource.get("Tags", None)
if tags:
tags = boto3_tag_list_to_ansible_dict(tags)
elif add_tags or tags is not None:
@@ -207,7 +214,7 @@ class Boto3Mixin():
normalized_resource = camel_dict_to_snake_dict(resource)
if tags is not None:
- normalized_resource['tags'] = tags
+ normalized_resource["tags"] = tags
return normalized_resource
def _extra_error_output(self):
@@ -262,9 +269,9 @@ class BaseResourceManager(Boto3Mixin):
params = dict()
if self._wait_timeout:
delay = min(5, self._wait_timeout)
- max_attempts = (self._wait_timeout // delay)
+ max_attempts = self._wait_timeout // delay
config = dict(Delay=delay, MaxAttempts=max_attempts)
- params['WaiterConfig'] = config
+ params["WaiterConfig"] = config
return params
def _wait_for_deletion(self):
@@ -347,8 +354,7 @@ class BaseResourceManager(Boto3Mixin):
if immutable and self.original_resource:
if description is None:
description = key
- self.module.fail_json(msg='{0} can not be updated after creation'
- .format(description))
+ self.module.fail_json(msg=f"{description} can not be updated after creation")
self._resource_updates[key] = value
self.changed = True
return True
diff --git a/ansible_collections/community/aws/plugins/module_utils/common.py b/ansible_collections/community/aws/plugins/module_utils/common.py
new file mode 100644
index 000000000..0c4374729
--- /dev/null
+++ b/ansible_collections/community/aws/plugins/module_utils/common.py
@@ -0,0 +1,8 @@
+# -*- coding: utf-8 -*-
+
+# Copyright: Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+
+COMMUNITY_AWS_COLLECTION_NAME = "community.aws"
+COMMUNITY_AWS_COLLECTION_VERSION = "7.1.0"
diff --git a/ansible_collections/community/aws/plugins/module_utils/dynamodb.py b/ansible_collections/community/aws/plugins/module_utils/dynamodb.py
new file mode 100644
index 000000000..d48029c1b
--- /dev/null
+++ b/ansible_collections/community/aws/plugins/module_utils/dynamodb.py
@@ -0,0 +1,120 @@
+# -*- coding: utf-8 -*-
+
+# Copyright: Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+try:
+ import botocore
+except ImportError:
+ pass # Handled by AnsibleAWSModule
+
+from ansible_collections.community.aws.plugins.module_utils.base import BaseWaiterFactory
+
+
+class DynamodbWaiterFactory(BaseWaiterFactory):
+ def __init__(self, module):
+ # the AWSRetry wrapper doesn't support the wait functions (there's no
+ # public call we can cleanly wrap)
+ client = module.client("dynamodb")
+ super().__init__(module, client)
+
+ @property
+ def _waiter_model_data(self):
+ data = super()._waiter_model_data
+ ddb_data = dict(
+ table_exists=dict(
+ operation="DescribeTable",
+ delay=20,
+ maxAttempts=25,
+ acceptors=[
+ dict(expected="ACTIVE", matcher="path", state="success", argument="Table.TableStatus"),
+ dict(expected="ResourceNotFoundException", matcher="error", state="retry"),
+ ],
+ ),
+ table_not_exists=dict(
+ operation="DescribeTable",
+ delay=20,
+ maxAttempts=25,
+ acceptors=[
+ dict(expected="ResourceNotFoundException", matcher="error", state="success"),
+ ],
+ ),
+ global_indexes_active=dict(
+ operation="DescribeTable",
+ delay=20,
+ maxAttempts=25,
+ acceptors=[
+ dict(expected="ResourceNotFoundException", matcher="error", state="failure"),
+ # If there are no secondary indexes, simply return
+ dict(
+ expected=False,
+ matcher="path",
+ state="success",
+ argument="contains(keys(Table), `GlobalSecondaryIndexes`)",
+ ),
+ dict(
+ expected="ACTIVE",
+ matcher="pathAll",
+ state="success",
+ argument="Table.GlobalSecondaryIndexes[].IndexStatus",
+ ),
+ dict(
+ expected="CREATING",
+ matcher="pathAny",
+ state="retry",
+ argument="Table.GlobalSecondaryIndexes[].IndexStatus",
+ ),
+ dict(
+ expected="UPDATING",
+ matcher="pathAny",
+ state="retry",
+ argument="Table.GlobalSecondaryIndexes[].IndexStatus",
+ ),
+ dict(
+ expected="DELETING",
+ matcher="pathAny",
+ state="retry",
+ argument="Table.GlobalSecondaryIndexes[].IndexStatus",
+ ),
+ dict(
+ expected=True,
+ matcher="path",
+ state="success",
+ argument="length(Table.GlobalSecondaryIndexes) == `0`",
+ ),
+ ],
+ ),
+ )
+ data.update(ddb_data)
+ return data
+
+
+def _do_wait(module, waiter_name, action_description, wait_timeout, table_name):
+ delay = min(wait_timeout, 5)
+ max_attempts = wait_timeout // delay
+
+ try:
+ waiter = DynamodbWaiterFactory(module).get_waiter(waiter_name)
+ waiter.wait(
+ WaiterConfig={"Delay": delay, "MaxAttempts": max_attempts},
+ TableName=table_name,
+ )
+ except botocore.exceptions.WaiterError as e:
+ module.fail_json_aws(e, msg=f"Timeout while waiting for {action_description}")
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(e, msg=f"Failed while waiting for {action_description}")
+
+
+def wait_table_exists(module, wait_timeout, table_name):
+ _do_wait(module, "table_exists", "table creation", wait_timeout, table_name)
+
+
+def wait_table_not_exists(module, wait_timeout, table_name):
+ _do_wait(module, "table_not_exists", "table deletion", wait_timeout, table_name)
+
+
+def wait_indexes_active(module, wait_timeout, table_name):
+ _do_wait(module, "global_indexes_active", "secondary index updates", wait_timeout, table_name)
diff --git a/ansible_collections/community/aws/plugins/module_utils/ec2.py b/ansible_collections/community/aws/plugins/module_utils/ec2.py
index 5ae789857..59b617f20 100644
--- a/ansible_collections/community/aws/plugins/module_utils/ec2.py
+++ b/ansible_collections/community/aws/plugins/module_utils/ec2.py
@@ -1,18 +1,17 @@
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
from copy import deepcopy
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_filter_list
-from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
from ansible_collections.amazon.aws.plugins.module_utils.tagging import ansible_dict_to_boto3_tag_list
-from ansible_collections.amazon.aws.plugins.module_utils.tagging import compare_aws_tags
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_specifications
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import compare_aws_tags
+from ansible_collections.amazon.aws.plugins.module_utils.transformation import ansible_dict_to_boto3_filter_list
from ansible_collections.community.aws.plugins.module_utils.base import BaseResourceManager
from ansible_collections.community.aws.plugins.module_utils.base import BaseWaiterFactory
@@ -23,7 +22,7 @@ class Ec2WaiterFactory(BaseWaiterFactory):
def __init__(self, module):
# the AWSRetry wrapper doesn't support the wait functions (there's no
# public call we can cleanly wrap)
- client = module.client('ec2')
+ client = module.client("ec2")
super(Ec2WaiterFactory, self).__init__(module, client)
@property
@@ -33,30 +32,28 @@ class Ec2WaiterFactory(BaseWaiterFactory):
class Ec2Boto3Mixin(Boto3Mixin):
-
@AWSRetry.jittered_backoff()
def _paginated_describe_subnets(self, **params):
- paginator = self.client.get_paginator('describe_subnets')
+ paginator = self.client.get_paginator("describe_subnets")
return paginator.paginate(**params).build_full_result()
- @Boto3Mixin.aws_error_handler('describe subnets')
+ @Boto3Mixin.aws_error_handler("describe subnets")
def _describe_subnets(self, **params):
try:
result = self._paginated_describe_subnets(**params)
- except is_boto3_error_code('SubnetID.NotFound'):
+ except is_boto3_error_code("SubnetID.NotFound"):
return None
- return result.get('Subnets', None)
+ return result.get("Subnets", None)
class BaseEc2Manager(Ec2Boto3Mixin, BaseResourceManager):
-
resource_id = None
TAG_RESOURCE_TYPE = None
# This can be overridden by a subclass *if* 'Tags' isn't returned as a part of
# the standard Resource description
TAGS_ON_RESOURCE = True
# If the resource supports using "TagSpecifications" on creation we can
- TAGS_ON_CREATE = 'TagSpecifications'
+ TAGS_ON_CREATE = "TagSpecifications"
def __init__(self, module, id=None):
r"""
@@ -79,27 +76,27 @@ class BaseEc2Manager(Ec2Boto3Mixin, BaseResourceManager):
changed |= super(BaseEc2Manager, self)._flush_update()
return changed
- @Boto3Mixin.aws_error_handler('connect to AWS')
- def _create_client(self, client_name='ec2'):
+ @Boto3Mixin.aws_error_handler("connect to AWS")
+ def _create_client(self, client_name="ec2"):
client = self.module.client(client_name, retry_decorator=AWSRetry.jittered_backoff())
return client
- @Boto3Mixin.aws_error_handler('set tags on resource')
+ @Boto3Mixin.aws_error_handler("set tags on resource")
def _add_tags(self, **params):
self.client.create_tags(aws_retry=True, **params)
return True
- @Boto3Mixin.aws_error_handler('unset tags on resource')
+ @Boto3Mixin.aws_error_handler("unset tags on resource")
def _remove_tags(self, **params):
self.client.delete_tags(aws_retry=True, **params)
return True
@AWSRetry.jittered_backoff()
def _paginated_describe_tags(self, **params):
- paginator = self.client.get_paginator('describe_tags')
+ paginator = self.client.get_paginator("describe_tags")
return paginator.paginate(**params).build_full_result()
- @Boto3Mixin.aws_error_handler('list tags on resource')
+ @Boto3Mixin.aws_error_handler("list tags on resource")
def _describe_tags(self, id=None):
if not id:
id = self.resource_id
@@ -112,7 +109,7 @@ class BaseEc2Manager(Ec2Boto3Mixin, BaseResourceManager):
id = self.resource_id
# If the Tags are available from the resource, then use them
if self.TAGS_ON_RESOURCE:
- tags = self._preupdate_resource.get('Tags', [])
+ tags = self._preupdate_resource.get("Tags", [])
# Otherwise we'll have to look them up
else:
tags = self._describe_tags(id=id)
@@ -120,8 +117,8 @@ class BaseEc2Manager(Ec2Boto3Mixin, BaseResourceManager):
def _do_tagging(self):
changed = False
- tags_to_add = self._tagging_updates.get('add')
- tags_to_remove = self._tagging_updates.get('remove')
+ tags_to_add = self._tagging_updates.get("add")
+ tags_to_remove = self._tagging_updates.get("remove")
if tags_to_add:
changed = True
@@ -137,25 +134,22 @@ class BaseEc2Manager(Ec2Boto3Mixin, BaseResourceManager):
return changed
def _merge_resource_changes(self, filter_immutable=True, creation=False):
-
resource = super(BaseEc2Manager, self)._merge_resource_changes(
- filter_immutable=filter_immutable,
- creation=creation
+ filter_immutable=filter_immutable, creation=creation
)
if creation:
if not self.TAGS_ON_CREATE:
- resource.pop('Tags', None)
- elif self.TAGS_ON_CREATE == 'TagSpecifications':
- tags = boto3_tag_list_to_ansible_dict(resource.pop('Tags', []))
+ resource.pop("Tags", None)
+ elif self.TAGS_ON_CREATE == "TagSpecifications":
+ tags = boto3_tag_list_to_ansible_dict(resource.pop("Tags", []))
tag_specs = boto3_tag_specifications(tags, types=[self.TAG_RESOURCE_TYPE])
if tag_specs:
- resource['TagSpecifications'] = tag_specs
+ resource["TagSpecifications"] = tag_specs
return resource
def set_tags(self, tags, purge_tags):
-
if tags is None:
return False
changed = False
@@ -174,16 +168,16 @@ class BaseEc2Manager(Ec2Boto3Mixin, BaseResourceManager):
tags_to_add, tags_to_remove = compare_aws_tags(current_tags, tags, purge_tags)
if tags_to_add:
- self._tagging_updates['add'] = tags_to_add
+ self._tagging_updates["add"] = tags_to_add
changed = True
if tags_to_remove:
- self._tagging_updates['remove'] = tags_to_remove
+ self._tagging_updates["remove"] = tags_to_remove
changed = True
if changed:
# Tags are a stored as a list, but treated like a list, the
# simplisic '==' in _set_resource_value doesn't do the comparison
# properly
- return self._set_resource_value('Tags', ansible_dict_to_boto3_tag_list(desired_tags))
+ return self._set_resource_value("Tags", ansible_dict_to_boto3_tag_list(desired_tags))
return False
diff --git a/ansible_collections/community/aws/plugins/module_utils/etag.py b/ansible_collections/community/aws/plugins/module_utils/etag.py
index a8cab5082..95c5ac94f 100644
--- a/ansible_collections/community/aws/plugins/module_utils/etag.py
+++ b/ansible_collections/community/aws/plugins/module_utils/etag.py
@@ -1,3 +1,5 @@
+# -*- coding: utf-8 -*-
+
# source: https://github.com/tlastowka/calculate_multipart_etag/blob/master/calculate_multipart_etag.py
#
# calculate_multipart_etag Copyright (C) 2015
@@ -22,6 +24,7 @@ import hashlib
try:
from boto3.s3.transfer import TransferConfig
+
DEFAULT_CHUNK_SIZE = TransferConfig().multipart_chunksize
except ImportError:
DEFAULT_CHUNK_SIZE = 5 * 1024 * 1024
@@ -40,23 +43,22 @@ def calculate_multipart_etag(source_path, chunk_size=DEFAULT_CHUNK_SIZE):
md5s = []
- with open(source_path, 'rb') as fp:
+ with open(source_path, "rb") as fp:
while True:
-
data = fp.read(chunk_size)
if not data:
break
- md5 = hashlib.new('md5', usedforsecurity=False)
+ md5 = hashlib.new("md5", usedforsecurity=False)
md5.update(data)
md5s.append(md5)
if len(md5s) == 1:
- new_etag = '"{0}"'.format(md5s[0].hexdigest())
+ new_etag = f'"{md5s[0].hexdigest()}"'
else: # > 1
digests = b"".join(m.digest() for m in md5s)
new_md5 = hashlib.md5(digests)
- new_etag = '"{0}-{1}"'.format(new_md5.hexdigest(), len(md5s))
+ new_etag = f'"{new_md5.hexdigest()}-{len(md5s)}"'
return new_etag
diff --git a/ansible_collections/community/aws/plugins/module_utils/modules.py b/ansible_collections/community/aws/plugins/module_utils/modules.py
new file mode 100644
index 000000000..2d484aa1a
--- /dev/null
+++ b/ansible_collections/community/aws/plugins/module_utils/modules.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+
+# Copyright: Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from ansible_collections.amazon.aws.plugins.module_utils.common import set_collection_info
+from ansible_collections.amazon.aws.plugins.module_utils.modules import AnsibleAWSModule
+
+from ansible_collections.community.aws.plugins.module_utils.common import COMMUNITY_AWS_COLLECTION_NAME
+from ansible_collections.community.aws.plugins.module_utils.common import COMMUNITY_AWS_COLLECTION_VERSION
+
+
+class AnsibleCommunityAWSModule(AnsibleAWSModule):
+ def __init__(self, **kwargs):
+ super(AnsibleCommunityAWSModule, self).__init__(**kwargs)
+ set_collection_info(
+ collection_name=COMMUNITY_AWS_COLLECTION_NAME,
+ collection_version=COMMUNITY_AWS_COLLECTION_VERSION,
+ )
diff --git a/ansible_collections/community/aws/plugins/module_utils/networkfirewall.py b/ansible_collections/community/aws/plugins/module_utils/networkfirewall.py
index 920c9f092..19a372514 100644
--- a/ansible_collections/community/aws/plugins/module_utils/networkfirewall.py
+++ b/ansible_collections/community/aws/plugins/module_utils/networkfirewall.py
@@ -1,27 +1,25 @@
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-from copy import deepcopy
import time
+from copy import deepcopy
from ansible.module_utils._text import to_text
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
from ansible.module_utils.six import string_types
from ansible_collections.amazon.aws.plugins.module_utils.arn import parse_aws_arn
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
from ansible_collections.amazon.aws.plugins.module_utils.tagging import ansible_dict_to_boto3_tag_list
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
from ansible_collections.amazon.aws.plugins.module_utils.tagging import compare_aws_tags
-from ansible_collections.community.aws.plugins.module_utils.base import Boto3Mixin
from ansible_collections.community.aws.plugins.module_utils.base import BaseResourceManager
from ansible_collections.community.aws.plugins.module_utils.base import BaseWaiterFactory
-
+from ansible_collections.community.aws.plugins.module_utils.base import Boto3Mixin
from ansible_collections.community.aws.plugins.module_utils.ec2 import BaseEc2Manager
@@ -63,7 +61,7 @@ class NetworkFirewallWaiterFactory(BaseWaiterFactory):
def __init__(self, module):
# the AWSRetry wrapper doesn't support the wait functions (there's no
# public call we can cleanly wrap)
- client = module.client('network-firewall')
+ client = module.client("network-firewall")
super(NetworkFirewallWaiterFactory, self).__init__(module, client)
@property
@@ -71,63 +69,104 @@ class NetworkFirewallWaiterFactory(BaseWaiterFactory):
data = super(NetworkFirewallWaiterFactory, self)._waiter_model_data
nw_data = dict(
rule_group_active=dict(
- operation='DescribeRuleGroup',
- delay=5, maxAttempts=120,
+ operation="DescribeRuleGroup",
+ delay=5,
+ maxAttempts=120,
acceptors=[
- dict(state='failure', matcher='path', expected='DELETING', argument='RuleGroupResponse.RuleGroupStatus'),
- dict(state='success', matcher='path', expected='ACTIVE', argument='RuleGroupResponse.RuleGroupStatus'),
- ]
+ dict(
+ state="failure",
+ matcher="path",
+ expected="DELETING",
+ argument="RuleGroupResponse.RuleGroupStatus",
+ ),
+ dict(
+ state="success", matcher="path", expected="ACTIVE", argument="RuleGroupResponse.RuleGroupStatus"
+ ),
+ ],
),
rule_group_deleted=dict(
- operation='DescribeRuleGroup',
- delay=5, maxAttempts=120,
+ operation="DescribeRuleGroup",
+ delay=5,
+ maxAttempts=120,
acceptors=[
- dict(state='retry', matcher='path', expected='DELETING', argument='RuleGroupResponse.RuleGroupStatus'),
- dict(state='success', matcher='error', expected='ResourceNotFoundException'),
- ]
+ dict(
+ state="retry", matcher="path", expected="DELETING", argument="RuleGroupResponse.RuleGroupStatus"
+ ),
+ dict(state="success", matcher="error", expected="ResourceNotFoundException"),
+ ],
),
policy_active=dict(
- operation='DescribeFirewallPolicy',
- delay=5, maxAttempts=120,
+ operation="DescribeFirewallPolicy",
+ delay=5,
+ maxAttempts=120,
acceptors=[
- dict(state='failure', matcher='path', expected='DELETING', argument='FirewallPolicyResponse.FirewallPolicyStatus'),
- dict(state='success', matcher='path', expected='ACTIVE', argument='FirewallPolicyResponse.FirewallPolicyStatus'),
- ]
+ dict(
+ state="failure",
+ matcher="path",
+ expected="DELETING",
+ argument="FirewallPolicyResponse.FirewallPolicyStatus",
+ ),
+ dict(
+ state="success",
+ matcher="path",
+ expected="ACTIVE",
+ argument="FirewallPolicyResponse.FirewallPolicyStatus",
+ ),
+ ],
),
policy_deleted=dict(
- operation='DescribeFirewallPolicy',
- delay=5, maxAttempts=120,
+ operation="DescribeFirewallPolicy",
+ delay=5,
+ maxAttempts=120,
acceptors=[
- dict(state='retry', matcher='path', expected='DELETING', argument='FirewallPolicyResponse.FirewallPolicyStatus'),
- dict(state='success', matcher='error', expected='ResourceNotFoundException'),
- ]
+ dict(
+ state="retry",
+ matcher="path",
+ expected="DELETING",
+ argument="FirewallPolicyResponse.FirewallPolicyStatus",
+ ),
+ dict(state="success", matcher="error", expected="ResourceNotFoundException"),
+ ],
),
firewall_active=dict(
- operation='DescribeFirewall',
- delay=5, maxAttempts=120,
+ operation="DescribeFirewall",
+ delay=5,
+ maxAttempts=120,
acceptors=[
- dict(state='failure', matcher='path', expected='DELETING', argument='FirewallStatus.Status'),
- dict(state='retry', matcher='path', expected='PROVISIONING', argument='FirewallStatus.Status'),
- dict(state='success', matcher='path', expected='READY', argument='FirewallStatus.Status'),
- ]
+ dict(state="failure", matcher="path", expected="DELETING", argument="FirewallStatus.Status"),
+ dict(state="retry", matcher="path", expected="PROVISIONING", argument="FirewallStatus.Status"),
+ dict(state="success", matcher="path", expected="READY", argument="FirewallStatus.Status"),
+ ],
),
firewall_updated=dict(
- operation='DescribeFirewall',
- delay=5, maxAttempts=240,
+ operation="DescribeFirewall",
+ delay=5,
+ maxAttempts=240,
acceptors=[
- dict(state='failure', matcher='path', expected='DELETING', argument='FirewallStatus.Status'),
- dict(state='retry', matcher='path', expected='PROVISIONING', argument='FirewallStatus.Status'),
- dict(state='retry', matcher='path', expected='PENDING', argument='FirewallStatus.ConfigurationSyncStateSummary'),
- dict(state='success', matcher='path', expected='IN_SYNC', argument='FirewallStatus.ConfigurationSyncStateSummary'),
- ]
+ dict(state="failure", matcher="path", expected="DELETING", argument="FirewallStatus.Status"),
+ dict(state="retry", matcher="path", expected="PROVISIONING", argument="FirewallStatus.Status"),
+ dict(
+ state="retry",
+ matcher="path",
+ expected="PENDING",
+ argument="FirewallStatus.ConfigurationSyncStateSummary",
+ ),
+ dict(
+ state="success",
+ matcher="path",
+ expected="IN_SYNC",
+ argument="FirewallStatus.ConfigurationSyncStateSummary",
+ ),
+ ],
),
firewall_deleted=dict(
- operation='DescribeFirewall',
- delay=5, maxAttempts=240,
+ operation="DescribeFirewall",
+ delay=5,
+ maxAttempts=240,
acceptors=[
- dict(state='retry', matcher='path', expected='DELETING', argument='FirewallStatus.Status'),
- dict(state='success', matcher='error', expected='ResourceNotFoundException'),
- ]
+ dict(state="retry", matcher="path", expected="DELETING", argument="FirewallStatus.Status"),
+ dict(state="success", matcher="error", expected="ResourceNotFoundException"),
+ ],
),
)
data.update(nw_data)
@@ -150,65 +189,65 @@ class NFRuleGroupBoto3Mixin(NetworkFirewallBoto3Mixin):
# retry - retries the full fetch, but better than simply giving up.
@AWSRetry.jittered_backoff()
def _paginated_list_rule_groups(self, **params):
- paginator = self.client.get_paginator('list_rule_groups')
+ paginator = self.client.get_paginator("list_rule_groups")
result = paginator.paginate(**params).build_full_result()
- return result.get('RuleGroups', None)
+ return result.get("RuleGroups", None)
- @Boto3Mixin.aws_error_handler('list all rule groups')
+ @Boto3Mixin.aws_error_handler("list all rule groups")
def _list_rule_groups(self, **params):
return self._paginated_list_rule_groups(**params)
- @Boto3Mixin.aws_error_handler('describe rule group')
+ @Boto3Mixin.aws_error_handler("describe rule group")
def _describe_rule_group(self, **params):
try:
result = self.client.describe_rule_group(aws_retry=True, **params)
- except is_boto3_error_code('ResourceNotFoundException'):
+ except is_boto3_error_code("ResourceNotFoundException"):
return None
- update_token = result.get('UpdateToken', None)
+ update_token = result.get("UpdateToken", None)
if update_token:
self._update_token = update_token
- rule_group = result.get('RuleGroup', None)
- metadata = result.get('RuleGroupResponse', None)
+ rule_group = result.get("RuleGroup", None)
+ metadata = result.get("RuleGroupResponse", None)
return dict(RuleGroup=rule_group, RuleGroupMetadata=metadata)
- @Boto3Mixin.aws_error_handler('create rule group')
+ @Boto3Mixin.aws_error_handler("create rule group")
def _create_rule_group(self, **params):
result = self.client.create_rule_group(aws_retry=True, **params)
- update_token = result.get('UpdateToken', None)
+ update_token = result.get("UpdateToken", None)
if update_token:
self._update_token = update_token
- return result.get('RuleGroupResponse', None)
+ return result.get("RuleGroupResponse", None)
- @Boto3Mixin.aws_error_handler('update rule group')
+ @Boto3Mixin.aws_error_handler("update rule group")
def _update_rule_group(self, **params):
- if self._update_token and 'UpdateToken' not in params:
- params['UpdateToken'] = self._update_token
+ if self._update_token and "UpdateToken" not in params:
+ params["UpdateToken"] = self._update_token
result = self.client.update_rule_group(aws_retry=True, **params)
- update_token = result.get('UpdateToken', None)
+ update_token = result.get("UpdateToken", None)
if update_token:
self._update_token = update_token
- return result.get('RuleGroupResponse', None)
+ return result.get("RuleGroupResponse", None)
- @Boto3Mixin.aws_error_handler('delete rule group')
+ @Boto3Mixin.aws_error_handler("delete rule group")
def _delete_rule_group(self, **params):
try:
result = self.client.delete_rule_group(aws_retry=True, **params)
- except is_boto3_error_code('ResourceNotFoundException'):
+ except is_boto3_error_code("ResourceNotFoundException"):
return None
- return result.get('RuleGroupResponse', None)
+ return result.get("RuleGroupResponse", None)
- @Boto3Mixin.aws_error_handler('firewall rule to finish deleting')
+ @Boto3Mixin.aws_error_handler("firewall rule to finish deleting")
def _wait_rule_group_deleted(self, **params):
- waiter = self.nf_waiter_factory.get_waiter('rule_group_deleted')
+ waiter = self.nf_waiter_factory.get_waiter("rule_group_deleted")
waiter.wait(**params)
- @Boto3Mixin.aws_error_handler('firewall rule to become active')
+ @Boto3Mixin.aws_error_handler("firewall rule to become active")
def _wait_rule_group_active(self, **params):
- waiter = self.nf_waiter_factory.get_waiter('rule_group_active')
+ waiter = self.nf_waiter_factory.get_waiter("rule_group_active")
waiter.wait(**params)
@@ -217,65 +256,65 @@ class NFPolicyBoto3Mixin(NetworkFirewallBoto3Mixin):
# retry - retries the full fetch, but better than simply giving up.
@AWSRetry.jittered_backoff()
def _paginated_list_policies(self, **params):
- paginator = self.client.get_paginator('list_firewall_policies')
+ paginator = self.client.get_paginator("list_firewall_policies")
result = paginator.paginate(**params).build_full_result()
- return result.get('FirewallPolicies', None)
+ return result.get("FirewallPolicies", None)
- @Boto3Mixin.aws_error_handler('list all firewall policies')
+ @Boto3Mixin.aws_error_handler("list all firewall policies")
def _list_policies(self, **params):
return self._paginated_list_policies(**params)
- @Boto3Mixin.aws_error_handler('describe firewall policy')
+ @Boto3Mixin.aws_error_handler("describe firewall policy")
def _describe_policy(self, **params):
try:
result = self.client.describe_firewall_policy(aws_retry=True, **params)
- except is_boto3_error_code('ResourceNotFoundException'):
+ except is_boto3_error_code("ResourceNotFoundException"):
return None
- update_token = result.get('UpdateToken', None)
+ update_token = result.get("UpdateToken", None)
if update_token:
self._update_token = update_token
- policy = result.get('FirewallPolicy', None)
- metadata = result.get('FirewallPolicyResponse', None)
+ policy = result.get("FirewallPolicy", None)
+ metadata = result.get("FirewallPolicyResponse", None)
return dict(FirewallPolicy=policy, FirewallPolicyMetadata=metadata)
- @Boto3Mixin.aws_error_handler('create firewall policy')
+ @Boto3Mixin.aws_error_handler("create firewall policy")
def _create_policy(self, **params):
result = self.client.create_firewall_policy(aws_retry=True, **params)
- update_token = result.get('UpdateToken', None)
+ update_token = result.get("UpdateToken", None)
if update_token:
self._update_token = update_token
- return result.get('FirewallPolicyResponse', None)
+ return result.get("FirewallPolicyResponse", None)
- @Boto3Mixin.aws_error_handler('update firewall policy')
+ @Boto3Mixin.aws_error_handler("update firewall policy")
def _update_policy(self, **params):
- if self._update_token and 'UpdateToken' not in params:
- params['UpdateToken'] = self._update_token
+ if self._update_token and "UpdateToken" not in params:
+ params["UpdateToken"] = self._update_token
result = self.client.update_firewall_policy(aws_retry=True, **params)
- update_token = result.get('UpdateToken', None)
+ update_token = result.get("UpdateToken", None)
if update_token:
self._update_token = update_token
- return result.get('FirewallPolicyResponse', None)
+ return result.get("FirewallPolicyResponse", None)
- @Boto3Mixin.aws_error_handler('delete firewall policy')
+ @Boto3Mixin.aws_error_handler("delete firewall policy")
def _delete_policy(self, **params):
try:
result = self.client.delete_firewall_policy(aws_retry=True, **params)
- except is_boto3_error_code('ResourceNotFoundException'):
+ except is_boto3_error_code("ResourceNotFoundException"):
return None
- return result.get('FirewallPolicyResponse', None)
+ return result.get("FirewallPolicyResponse", None)
- @Boto3Mixin.aws_error_handler('firewall policy to finish deleting')
+ @Boto3Mixin.aws_error_handler("firewall policy to finish deleting")
def _wait_policy_deleted(self, **params):
- waiter = self.nf_waiter_factory.get_waiter('policy_deleted')
+ waiter = self.nf_waiter_factory.get_waiter("policy_deleted")
waiter.wait(**params)
- @Boto3Mixin.aws_error_handler('firewall policy to become active')
+ @Boto3Mixin.aws_error_handler("firewall policy to become active")
def _wait_policy_active(self, **params):
- waiter = self.nf_waiter_factory.get_waiter('policy_active')
+ waiter = self.nf_waiter_factory.get_waiter("policy_active")
waiter.wait(**params)
@@ -284,136 +323,136 @@ class NFFirewallBoto3Mixin(NetworkFirewallBoto3Mixin):
# retry - retries the full fetch, but better than simply giving up.
@AWSRetry.jittered_backoff()
def _paginated_list_firewalls(self, **params):
- paginator = self.client.get_paginator('list_firewalls')
+ paginator = self.client.get_paginator("list_firewalls")
result = paginator.paginate(**params).build_full_result()
- return result.get('Firewalls', None)
+ return result.get("Firewalls", None)
- @Boto3Mixin.aws_error_handler('list all firewalls')
+ @Boto3Mixin.aws_error_handler("list all firewalls")
def _list_firewalls(self, **params):
return self._paginated_list_firewalls(**params)
- @Boto3Mixin.aws_error_handler('describe firewall')
+ @Boto3Mixin.aws_error_handler("describe firewall")
def _describe_firewall(self, **params):
try:
result = self.client.describe_firewall(aws_retry=True, **params)
- except is_boto3_error_code('ResourceNotFoundException'):
+ except is_boto3_error_code("ResourceNotFoundException"):
return None
- update_token = result.get('UpdateToken', None)
+ update_token = result.get("UpdateToken", None)
if update_token:
self._update_token = update_token
- firewall = result.get('Firewall', None)
- metadata = result.get('FirewallStatus', None)
+ firewall = result.get("Firewall", None)
+ metadata = result.get("FirewallStatus", None)
return dict(Firewall=firewall, FirewallMetadata=metadata)
- @Boto3Mixin.aws_error_handler('create firewall')
+ @Boto3Mixin.aws_error_handler("create firewall")
def _create_firewall(self, **params):
result = self.client.create_firewall(aws_retry=True, **params)
- update_token = result.get('UpdateToken', None)
+ update_token = result.get("UpdateToken", None)
if update_token:
self._update_token = update_token
- return result.get('FirewallStatus', None)
+ return result.get("FirewallStatus", None)
- @Boto3Mixin.aws_error_handler('update firewall description')
+ @Boto3Mixin.aws_error_handler("update firewall description")
def _update_firewall_description(self, **params):
- if self._update_token and 'UpdateToken' not in params:
- params['UpdateToken'] = self._update_token
+ if self._update_token and "UpdateToken" not in params:
+ params["UpdateToken"] = self._update_token
result = self.client.update_firewall_description(aws_retry=True, **params)
- update_token = result.get('UpdateToken', None)
+ update_token = result.get("UpdateToken", None)
if update_token:
self._update_token = update_token
- return result.get('FirewallName', None)
+ return result.get("FirewallName", None)
- @Boto3Mixin.aws_error_handler('update firewall subnet change protection')
+ @Boto3Mixin.aws_error_handler("update firewall subnet change protection")
def _update_subnet_change_protection(self, **params):
- if self._update_token and 'UpdateToken' not in params:
- params['UpdateToken'] = self._update_token
+ if self._update_token and "UpdateToken" not in params:
+ params["UpdateToken"] = self._update_token
result = self.client.update_subnet_change_protection(aws_retry=True, **params)
- update_token = result.get('UpdateToken', None)
+ update_token = result.get("UpdateToken", None)
if update_token:
self._update_token = update_token
- return result.get('FirewallName', None)
+ return result.get("FirewallName", None)
- @Boto3Mixin.aws_error_handler('update firewall policy change protection')
+ @Boto3Mixin.aws_error_handler("update firewall policy change protection")
def _update_firewall_policy_change_protection(self, **params):
- if self._update_token and 'UpdateToken' not in params:
- params['UpdateToken'] = self._update_token
+ if self._update_token and "UpdateToken" not in params:
+ params["UpdateToken"] = self._update_token
result = self.client.update_firewall_policy_change_protection(aws_retry=True, **params)
- update_token = result.get('UpdateToken', None)
+ update_token = result.get("UpdateToken", None)
if update_token:
self._update_token = update_token
- return result.get('FirewallName', None)
+ return result.get("FirewallName", None)
- @Boto3Mixin.aws_error_handler('update firewall deletion protection')
+ @Boto3Mixin.aws_error_handler("update firewall deletion protection")
def _update_firewall_delete_protection(self, **params):
- if self._update_token and 'UpdateToken' not in params:
- params['UpdateToken'] = self._update_token
+ if self._update_token and "UpdateToken" not in params:
+ params["UpdateToken"] = self._update_token
result = self.client.update_firewall_delete_protection(aws_retry=True, **params)
- update_token = result.get('UpdateToken', None)
+ update_token = result.get("UpdateToken", None)
if update_token:
self._update_token = update_token
- return result.get('FirewallName', None)
+ return result.get("FirewallName", None)
- @Boto3Mixin.aws_error_handler('associate policy with firewall')
+ @Boto3Mixin.aws_error_handler("associate policy with firewall")
def _associate_firewall_policy(self, **params):
- if self._update_token and 'UpdateToken' not in params:
- params['UpdateToken'] = self._update_token
+ if self._update_token and "UpdateToken" not in params:
+ params["UpdateToken"] = self._update_token
result = self.client.associate_firewall_policy(aws_retry=True, **params)
- update_token = result.get('UpdateToken', None)
+ update_token = result.get("UpdateToken", None)
if update_token:
self._update_token = update_token
- return result.get('FirewallName', None)
+ return result.get("FirewallName", None)
- @Boto3Mixin.aws_error_handler('associate subnets with firewall')
+ @Boto3Mixin.aws_error_handler("associate subnets with firewall")
def _associate_subnets(self, **params):
- if self._update_token and 'UpdateToken' not in params:
- params['UpdateToken'] = self._update_token
+ if self._update_token and "UpdateToken" not in params:
+ params["UpdateToken"] = self._update_token
result = self.client.associate_subnets(aws_retry=True, **params)
- update_token = result.get('UpdateToken', None)
+ update_token = result.get("UpdateToken", None)
if update_token:
self._update_token = update_token
- return result.get('FirewallName', None)
+ return result.get("FirewallName", None)
- @Boto3Mixin.aws_error_handler('disassociate subnets from firewall')
+ @Boto3Mixin.aws_error_handler("disassociate subnets from firewall")
def _disassociate_subnets(self, **params):
- if self._update_token and 'UpdateToken' not in params:
- params['UpdateToken'] = self._update_token
+ if self._update_token and "UpdateToken" not in params:
+ params["UpdateToken"] = self._update_token
result = self.client.disassociate_subnets(aws_retry=True, **params)
- update_token = result.get('UpdateToken', None)
+ update_token = result.get("UpdateToken", None)
if update_token:
self._update_token = update_token
- return result.get('FirewallName', None)
+ return result.get("FirewallName", None)
- @Boto3Mixin.aws_error_handler('delete firewall')
+ @Boto3Mixin.aws_error_handler("delete firewall")
def _delete_firewall(self, **params):
try:
result = self.client.delete_firewall(aws_retry=True, **params)
- except is_boto3_error_code('ResourceNotFoundException'):
+ except is_boto3_error_code("ResourceNotFoundException"):
return None
- return result.get('FirewallStatus', None)
+ return result.get("FirewallStatus", None)
- @Boto3Mixin.aws_error_handler('firewall to finish deleting')
+ @Boto3Mixin.aws_error_handler("firewall to finish deleting")
def _wait_firewall_deleted(self, **params):
- waiter = self.nf_waiter_factory.get_waiter('firewall_deleted')
+ waiter = self.nf_waiter_factory.get_waiter("firewall_deleted")
waiter.wait(**params)
- @Boto3Mixin.aws_error_handler('firewall to finish updating')
+ @Boto3Mixin.aws_error_handler("firewall to finish updating")
def _wait_firewall_updated(self, **params):
- waiter = self.nf_waiter_factory.get_waiter('firewall_updated')
+ waiter = self.nf_waiter_factory.get_waiter("firewall_updated")
waiter.wait(**params)
- @Boto3Mixin.aws_error_handler('firewall to become active')
+ @Boto3Mixin.aws_error_handler("firewall to become active")
def _wait_firewall_active(self, **params):
- waiter = self.nf_waiter_factory.get_waiter('firewall_active')
+ waiter = self.nf_waiter_factory.get_waiter("firewall_active")
waiter.wait(**params)
@@ -433,8 +472,8 @@ class BaseNetworkFirewallManager(BaseResourceManager):
self._metadata_updates = dict()
self._tagging_updates = dict()
- @Boto3Mixin.aws_error_handler('connect to AWS')
- def _create_client(self, client_name='network-firewall'):
+ @Boto3Mixin.aws_error_handler("connect to AWS")
+ def _create_client(self, client_name="network-firewall"):
client = self.module.client(client_name, retry_decorator=AWSRetry.jittered_backoff())
return client
@@ -473,7 +512,9 @@ class BaseNetworkFirewallManager(BaseResourceManager):
Removes information from the metadata which can't be updated.
Returns a *copy* of the metadata dictionary.
"""
- return deepcopy(metadata)
+ meta = deepcopy(metadata)
+ meta.pop("LastModifiedTime", None)
+ return meta
def _flush_create(self):
changed = super(BaseNetworkFirewallManager, self)._flush_create()
@@ -485,18 +526,18 @@ class BaseNetworkFirewallManager(BaseResourceManager):
self._metadata_updates = dict()
return changed
- @BaseResourceManager.aws_error_handler('set tags on resource')
+ @BaseResourceManager.aws_error_handler("set tags on resource")
def _add_tags(self, **params):
self.client.tag_resource(aws_retry=True, **params)
return True
- @BaseResourceManager.aws_error_handler('unset tags on resource')
+ @BaseResourceManager.aws_error_handler("unset tags on resource")
def _remove_tags(self, **params):
self.client.untag_resource(aws_retry=True, **params)
return True
def _get_preupdate_arn(self):
- return self._preupdate_metadata.get('Arn')
+ return self._preupdate_metadata.get("Arn")
def _set_metadata_value(self, key, value, description=None, immutable=False):
if value is None:
@@ -506,8 +547,7 @@ class BaseNetworkFirewallManager(BaseResourceManager):
if immutable and self.original_resource:
if description is None:
description = key
- self.module.fail_json(msg='{0} can not be updated after creation'
- .format(description))
+ self.module.fail_json(msg=f"{description} can not be updated after creation")
self._metadata_updates[key] = value
self.changed = True
return True
@@ -516,15 +556,15 @@ class BaseNetworkFirewallManager(BaseResourceManager):
return self._metadata_updates.get(key, self._preupdate_metadata.get(key, default))
def _set_tag_values(self, desired_tags):
- return self._set_metadata_value('Tags', ansible_dict_to_boto3_tag_list(desired_tags))
+ return self._set_metadata_value("Tags", ansible_dict_to_boto3_tag_list(desired_tags))
def _get_tag_values(self):
- return self._get_metadata_value('Tags', [])
+ return self._get_metadata_value("Tags", [])
def _flush_tagging(self):
changed = False
- tags_to_add = self._tagging_updates.get('add')
- tags_to_remove = self._tagging_updates.get('remove')
+ tags_to_add = self._tagging_updates.get("add")
+ tags_to_remove = self._tagging_updates.get("remove")
resource_arn = self._get_preupdate_arn()
if not resource_arn:
@@ -543,7 +583,6 @@ class BaseNetworkFirewallManager(BaseResourceManager):
return changed
def set_tags(self, tags, purge_tags):
-
if tags is None:
return False
changed = False
@@ -562,10 +601,10 @@ class BaseNetworkFirewallManager(BaseResourceManager):
tags_to_add, tags_to_remove = compare_aws_tags(current_tags, tags, purge_tags)
if tags_to_add:
- self._tagging_updates['add'] = tags_to_add
+ self._tagging_updates["add"] = tags_to_add
changed = True
if tags_to_remove:
- self._tagging_updates['remove'] = tags_to_remove
+ self._tagging_updates["remove"] = tags_to_remove
changed = True
if changed:
@@ -578,9 +617,7 @@ class BaseNetworkFirewallManager(BaseResourceManager):
class NetworkFirewallRuleManager(NFRuleGroupBoto3Mixin, BaseNetworkFirewallManager):
-
- RULE_TYPES = frozenset(['StatelessRulesAndCustomActions', 'StatefulRules',
- 'RulesSourceList', 'RulesString'])
+ RULE_TYPES = frozenset(["StatelessRulesAndCustomActions", "StatefulRules", "RulesSourceList", "RulesString"])
name = None
rule_type = None
@@ -599,28 +636,28 @@ class NetworkFirewallRuleManager(NFRuleGroupBoto3Mixin, BaseNetworkFirewallManag
def _extra_error_output(self):
output = super(NetworkFirewallRuleManager, self)._extra_error_output()
if self.name:
- output['RuleGroupName'] = self.name
+ output["RuleGroupName"] = self.name
if self.rule_type:
- output['Type'] = self.rule_type
+ output["Type"] = self.rule_type
if self.arn:
- output['RuleGroupArn'] = self.arn
+ output["RuleGroupArn"] = self.arn
return output
def _filter_immutable_metadata_attributes(self, metadata):
metadata = super(NetworkFirewallRuleManager, self)._filter_immutable_metadata_attributes(metadata)
- metadata.pop('RuleGroupArn', None)
- metadata.pop('RuleGroupName', None)
- metadata.pop('RuleGroupId', None)
- metadata.pop('Type', None)
- metadata.pop('Capacity', None)
- metadata.pop('RuleGroupStatus', None)
- metadata.pop('Tags', None)
- metadata.pop('ConsumedCapacity', None)
- metadata.pop('NumberOfAssociations', None)
+ metadata.pop("RuleGroupArn", None)
+ metadata.pop("RuleGroupName", None)
+ metadata.pop("RuleGroupId", None)
+ metadata.pop("Type", None)
+ metadata.pop("Capacity", None)
+ metadata.pop("RuleGroupStatus", None)
+ metadata.pop("Tags", None)
+ metadata.pop("ConsumedCapacity", None)
+ metadata.pop("NumberOfAssociations", None)
return metadata
def _get_preupdate_arn(self):
- return self._get_metadata_value('RuleGroupArn')
+ return self._get_metadata_value("RuleGroupArn")
def _get_id_params(self, name=None, rule_type=None, arn=None):
if arn:
@@ -635,7 +672,7 @@ class NetworkFirewallRuleManager(NFRuleGroupBoto3Mixin, BaseNetworkFirewallManag
rule_type = rule_type.upper()
if not rule_type or not name:
# Users should never see this, but let's cover ourself
- self.module.fail_json(msg='Rule identifier parameters missing')
+ self.module.fail_json(msg="Rule identifier parameters missing")
return dict(RuleGroupName=name, Type=rule_type)
@staticmethod
@@ -647,7 +684,6 @@ class NetworkFirewallRuleManager(NFRuleGroupBoto3Mixin, BaseNetworkFirewallManag
return {k: dict(Definition=_string_list(v)) for (k, v) in variables.items()}
def delete(self, name=None, rule_type=None, arn=None):
-
id_params = self._get_id_params(name=name, rule_type=rule_type, arn=arn)
result = self._get_rule_group(**id_params)
@@ -657,8 +693,8 @@ class NetworkFirewallRuleManager(NFRuleGroupBoto3Mixin, BaseNetworkFirewallManag
self.updated_resource = dict()
# Rule Group is already in the process of being deleted (takes time)
- rule_status = self._get_metadata_value('RuleGroupStatus', '').upper()
- if rule_status == 'DELETING':
+ rule_status = self._get_metadata_value("RuleGroupStatus", "").upper()
+ if rule_status == "DELETING":
self._wait_for_deletion()
return False
@@ -675,37 +711,37 @@ class NetworkFirewallRuleManager(NFRuleGroupBoto3Mixin, BaseNetworkFirewallManag
params = dict()
if scope:
scope = scope.upper()
- params['Scope'] = scope
+ params["Scope"] = scope
rule_groups = self._list_rule_groups(**params)
if not rule_groups:
return list()
- return [r.get('Arn', None) for r in rule_groups]
+ return [r.get("Arn", None) for r in rule_groups]
def _normalize_rule_variable(self, variable):
if variable is None:
return None
- return {k: variable.get(k, dict()).get('Definition', []) for k in variable.keys()}
+ return {k: variable.get(k, dict()).get("Definition", []) for k in variable.keys()}
def _normalize_rule_variables(self, variables):
if variables is None:
return None
result = dict()
- ip_sets = self._normalize_rule_variable(variables.get('IPSets', None))
+ ip_sets = self._normalize_rule_variable(variables.get("IPSets", None))
if ip_sets:
- result['ip_sets'] = ip_sets
- port_sets = self._normalize_rule_variable(variables.get('PortSets', None))
+ result["ip_sets"] = ip_sets
+ port_sets = self._normalize_rule_variable(variables.get("PortSets", None))
if port_sets:
- result['port_sets'] = port_sets
+ result["port_sets"] = port_sets
return result
def _normalize_rule_group(self, rule_group):
if rule_group is None:
return None
- rule_variables = self._normalize_rule_variables(rule_group.get('RuleVariables', None))
+ rule_variables = self._normalize_rule_variables(rule_group.get("RuleVariables", None))
rule_group = self._normalize_boto3_resource(rule_group)
if rule_variables is not None:
- rule_group['rule_variables'] = rule_variables
+ rule_group["rule_variables"] = rule_variables
return rule_group
def _normalize_rule_group_metadata(self, rule_group_metadata):
@@ -714,20 +750,19 @@ class NetworkFirewallRuleManager(NFRuleGroupBoto3Mixin, BaseNetworkFirewallManag
def _normalize_rule_group_result(self, result):
if result is None:
return None
- rule_group = self._normalize_rule_group(result.get('RuleGroup', None))
- rule_group_metadata = self._normalize_rule_group_metadata(result.get('RuleGroupMetadata', None))
+ rule_group = self._normalize_rule_group(result.get("RuleGroup", None))
+ rule_group_metadata = self._normalize_rule_group_metadata(result.get("RuleGroupMetadata", None))
result = camel_dict_to_snake_dict(result)
if rule_group:
- result['rule_group'] = rule_group
+ result["rule_group"] = rule_group
if rule_group_metadata:
- result['rule_group_metadata'] = rule_group_metadata
+ result["rule_group_metadata"] = rule_group_metadata
return result
def _normalize_resource(self, resource):
return self._normalize_rule_group_result(resource)
def get_rule_group(self, name=None, rule_type=None, arn=None):
-
id_params = self._get_id_params(name=name, rule_type=rule_type, arn=arn)
result = self._get_rule_group(**id_params)
@@ -738,35 +773,32 @@ class NetworkFirewallRuleManager(NFRuleGroupBoto3Mixin, BaseNetworkFirewallManag
return rule_group
def set_description(self, description):
- return self._set_metadata_value('Description', description)
+ return self._set_metadata_value("Description", description)
def set_capacity(self, capacity):
- return self._set_metadata_value(
- 'Capacity', capacity,
- description="Reserved Capacity", immutable=True)
+ return self._set_metadata_value("Capacity", capacity, description="Reserved Capacity", immutable=True)
def _set_rule_option(self, option_name, description, value, immutable=False, default_value=None):
if value is None:
return False
- rule_options = deepcopy(self._get_resource_value('StatefulRuleOptions', dict()))
+ rule_options = deepcopy(self._get_resource_value("StatefulRuleOptions", dict()))
if value == rule_options.get(option_name, default_value):
return False
if immutable and self.original_resource:
- self.module.fail_json(msg='{0} can not be updated after creation'
- .format(description))
+ self.module.fail_json(msg=f"{description} can not be updated after creation")
rule_options[option_name] = value
- return self._set_resource_value('StatefulRuleOptions', rule_options)
+ return self._set_resource_value("StatefulRuleOptions", rule_options)
def set_rule_order(self, order):
RULE_ORDER_MAP = {
- 'default': 'DEFAULT_ACTION_ORDER',
- 'strict': 'STRICT_ORDER',
+ "default": "DEFAULT_ACTION_ORDER",
+ "strict": "STRICT_ORDER",
}
value = RULE_ORDER_MAP.get(order)
- changed = self._set_rule_option('RuleOrder', 'Rule order', value, True, 'DEFAULT_ACTION_ORDER')
+ changed = self._set_rule_option("RuleOrder", "Rule order", value, True, "DEFAULT_ACTION_ORDER")
self.changed |= changed
return changed
@@ -776,7 +808,7 @@ class NetworkFirewallRuleManager(NFRuleGroupBoto3Mixin, BaseNetworkFirewallManag
variables = self._transform_rule_variables(variables)
- all_variables = deepcopy(self._get_resource_value('RuleVariables', self._empty_rule_variables()))
+ all_variables = deepcopy(self._get_resource_value("RuleVariables", self._empty_rule_variables()))
current_variables = all_variables.get(set_name, dict())
updated_variables = _merge_dict(current_variables, variables, purge)
@@ -786,49 +818,50 @@ class NetworkFirewallRuleManager(NFRuleGroupBoto3Mixin, BaseNetworkFirewallManag
all_variables[set_name] = updated_variables
- return self._set_resource_value('RuleVariables', all_variables)
+ return self._set_resource_value("RuleVariables", all_variables)
def set_ip_variables(self, variables, purge):
- return self._set_rule_variables('IPSets', variables, purge)
+ return self._set_rule_variables("IPSets", variables, purge)
def set_port_variables(self, variables, purge):
- return self._set_rule_variables('PortSets', variables, purge)
+ return self._set_rule_variables("PortSets", variables, purge)
def _set_rule_source(self, rule_type, rules):
if not rules:
return False
conflicting_types = self.RULE_TYPES.difference({rule_type})
- rules_source = deepcopy(self._get_resource_value('RulesSource', dict()))
+ rules_source = deepcopy(self._get_resource_value("RulesSource", dict()))
current_keys = set(rules_source.keys())
conflicting_rule_type = conflicting_types.intersection(current_keys)
if conflicting_rule_type:
- self.module.fail_json('Unable to add {0} rules, {1} rules already set'
- .format(rule_type, " and ".join(conflicting_rule_type)))
+ self.module.fail_json(
+ f"Unable to add {rule_type} rules, {' and '.join(conflicting_rule_type)} rules already set"
+ )
original_rules = rules_source.get(rule_type, None)
if rules == original_rules:
return False
rules_source[rule_type] = rules
- return self._set_resource_value('RulesSource', rules_source)
+ return self._set_resource_value("RulesSource", rules_source)
def set_rule_string(self, rule):
if rule is None:
return False
if not rule:
- self.module.fail_json('Rule string must include at least one rule')
+ self.module.fail_json("Rule string must include at least one rule")
rule = "\n".join(_string_list(rule))
- return self._set_rule_source('RulesString', rule)
+ return self._set_rule_source("RulesString", rule)
def set_domain_list(self, options):
if not options:
return False
changed = False
- domain_names = options.get('domain_names')
- home_net = options.get('source_ips', None)
- action = options.get('action')
- filter_http = options.get('filter_http', False)
- filter_https = options.get('filter_https', False)
+ domain_names = options.get("domain_names")
+ home_net = options.get("source_ips", None)
+ action = options.get("action")
+ filter_http = options.get("filter_http", False)
+ filter_https = options.get("filter_https", False)
if home_net:
# Seems a little kludgy but the HOME_NET ip variable is how you
@@ -840,14 +873,14 @@ class NetworkFirewallRuleManager(NFRuleGroupBoto3Mixin, BaseNetworkFirewallManag
# Perform some transformations
target_types = []
if filter_http:
- target_types.append('HTTP_HOST')
+ target_types.append("HTTP_HOST")
if filter_https:
- target_types.append('TLS_SNI')
+ target_types.append("TLS_SNI")
- if action == 'allow':
- action = 'ALLOWLIST'
+ if action == "allow":
+ action = "ALLOWLIST"
else:
- action = 'DENYLIST'
+ action = "DENYLIST"
# Finally build the 'rule'
rule = dict(
@@ -855,37 +888,37 @@ class NetworkFirewallRuleManager(NFRuleGroupBoto3Mixin, BaseNetworkFirewallManag
TargetTypes=target_types,
GeneratedRulesType=action,
)
- changed |= self._set_rule_source('RulesSourceList', rule)
+ changed |= self._set_rule_source("RulesSourceList", rule)
return changed
def _format_rule_options(self, options, sid):
formatted_options = []
- opt = dict(Keyword='sid:{0}'.format(sid))
+ opt = dict(Keyword=f"sid:{sid}")
formatted_options.append(opt)
if options:
for option in sorted(options.keys()):
opt = dict(Keyword=option)
settings = options.get(option)
if settings:
- opt['Settings'] = _string_list(settings)
+ opt["Settings"] = _string_list(settings)
formatted_options.append(opt)
return formatted_options
def _format_stateful_rule(self, rule):
options = self._format_rule_options(
- rule.get('rule_options', dict()),
- rule.get('sid'),
+ rule.get("rule_options", dict()),
+ rule.get("sid"),
)
formatted_rule = dict(
- Action=rule.get('action').upper(),
+ Action=rule.get("action").upper(),
RuleOptions=options,
Header=dict(
- Protocol=rule.get('protocol').upper(),
- Source=rule.get('source'),
- SourcePort=rule.get('source_port'),
- Direction=rule.get('direction').upper(),
- Destination=rule.get('destination'),
- DestinationPort=rule.get('destination_port'),
+ Protocol=rule.get("protocol").upper(),
+ Source=rule.get("source"),
+ SourcePort=rule.get("source_port"),
+ Direction=rule.get("direction").upper(),
+ Destination=rule.get("destination"),
+ DestinationPort=rule.get("destination_port"),
),
)
return formatted_rule
@@ -894,40 +927,39 @@ class NetworkFirewallRuleManager(NFRuleGroupBoto3Mixin, BaseNetworkFirewallManag
if rules is None:
return False
if not rules:
- self.module.fail_json(msg='Rule list must include at least one rule')
+ self.module.fail_json(msg="Rule list must include at least one rule")
formatted_rules = [self._format_stateful_rule(r) for r in rules]
- return self._set_rule_source('StatefulRules', formatted_rules)
+ return self._set_rule_source("StatefulRules", formatted_rules)
def _do_create_resource(self):
metadata, resource = self._merge_changes(filter_metadata=False)
params = metadata
params.update(self._get_id_params())
- params['RuleGroup'] = resource
+ params["RuleGroup"] = resource
response = self._create_rule_group(**params)
return bool(response)
def _generate_updated_resource(self):
metadata, resource = self._merge_changes(filter_metadata=False)
metadata.update(self._get_id_params())
- updated_resource = dict(
- RuleGroup=resource,
- RuleGroupMetadata=metadata
- )
+ updated_resource = dict(RuleGroup=resource, RuleGroupMetadata=metadata)
return updated_resource
def _flush_create(self):
# Apply some pre-flight tests before trying to run the creation.
- if 'Capacity' not in self._metadata_updates:
- self.module.fail_json('Capacity must be provided when creating a new Rule Group')
+ if "Capacity" not in self._metadata_updates:
+ self.module.fail_json("Capacity must be provided when creating a new Rule Group")
- rules_source = self._get_resource_value('RulesSource', dict())
+ rules_source = self._get_resource_value("RulesSource", dict())
rule_type = self.RULE_TYPES.intersection(set(rules_source.keys()))
if len(rule_type) != 1:
- self.module.fail_json('Exactly one of rule strings, domain list or rule list'
- ' must be provided when creating a new rule group',
- rule_type=rule_type, keys=self._resource_updates.keys(),
- types=self.RULE_TYPES)
+ self.module.fail_json(
+ "Exactly one of rule strings, domain list or rule list must be provided when creating a new rule group",
+ rule_type=rule_type,
+ keys=self._resource_updates.keys(),
+ types=self.RULE_TYPES,
+ )
return super(NetworkFirewallRuleManager, self)._flush_create()
@@ -942,7 +974,7 @@ class NetworkFirewallRuleManager(NFRuleGroupBoto3Mixin, BaseNetworkFirewallManag
params = metadata
params.update(self._get_id_params())
- params['RuleGroup'] = resource
+ params["RuleGroup"] = resource
if not self.module.check_mode:
response = self._update_rule_group(**params)
@@ -960,8 +992,8 @@ class NetworkFirewallRuleManager(NFRuleGroupBoto3Mixin, BaseNetworkFirewallManag
if not result:
return None
- rule_group = result.get('RuleGroup', None)
- metadata = result.get('RuleGroupMetadata', None)
+ rule_group = result.get("RuleGroup", None)
+ metadata = result.get("RuleGroupMetadata", None)
self._preupdate_resource = deepcopy(rule_group)
self._preupdate_metadata = deepcopy(metadata)
return dict(RuleGroup=rule_group, RuleGroupMetadata=metadata)
@@ -981,7 +1013,6 @@ class NetworkFirewallRuleManager(NFRuleGroupBoto3Mixin, BaseNetworkFirewallManag
class NetworkFirewallPolicyManager(NFPolicyBoto3Mixin, NFRuleGroupBoto3Mixin, BaseNetworkFirewallManager):
-
name = None
arn = None
_group_name_cache = None
@@ -998,25 +1029,25 @@ class NetworkFirewallPolicyManager(NFPolicyBoto3Mixin, NFRuleGroupBoto3Mixin, Ba
def _extra_error_output(self):
output = super(NetworkFirewallPolicyManager, self)._extra_error_output()
if self.name:
- output['FirewallPolicyName'] = self.name
+ output["FirewallPolicyName"] = self.name
if self.arn:
- output['FirewallPolicyArn'] = self.arn
+ output["FirewallPolicyArn"] = self.arn
return output
def _filter_immutable_metadata_attributes(self, metadata):
metadata = super(NetworkFirewallPolicyManager, self)._filter_immutable_metadata_attributes(metadata)
- metadata.pop('FirewallPolicyArn', None)
- metadata.pop('FirewallPolicyName', None)
- metadata.pop('FirewallPolicyId', None)
- metadata.pop('FirewallPolicyStatus', None)
- metadata.pop('ConsumedStatelessRuleCapacity', None)
- metadata.pop('ConsumedStatefulRuleCapacity', None)
- metadata.pop('Tags', None)
- metadata.pop('NumberOfAssociations', None)
+ metadata.pop("FirewallPolicyArn", None)
+ metadata.pop("FirewallPolicyName", None)
+ metadata.pop("FirewallPolicyId", None)
+ metadata.pop("FirewallPolicyStatus", None)
+ metadata.pop("ConsumedStatelessRuleCapacity", None)
+ metadata.pop("ConsumedStatefulRuleCapacity", None)
+ metadata.pop("Tags", None)
+ metadata.pop("NumberOfAssociations", None)
return metadata
def _get_preupdate_arn(self):
- return self._get_metadata_value('FirewallPolicyArn')
+ return self._get_metadata_value("FirewallPolicyArn")
def _get_id_params(self, name=None, arn=None):
if arn:
@@ -1028,7 +1059,6 @@ class NetworkFirewallPolicyManager(NFPolicyBoto3Mixin, NFRuleGroupBoto3Mixin, Ba
return dict(FirewallPolicyName=name)
def delete(self, name=None, arn=None):
-
id_params = self._get_id_params(name=name, arn=arn)
result = self._get_policy(**id_params)
@@ -1038,8 +1068,8 @@ class NetworkFirewallPolicyManager(NFPolicyBoto3Mixin, NFRuleGroupBoto3Mixin, Ba
self.updated_resource = dict()
# Policy is already in the process of being deleted (takes time)
- rule_status = self._get_metadata_value('FirewallPolicyStatus', '').upper()
- if rule_status == 'DELETING':
+ rule_status = self._get_metadata_value("FirewallPolicyStatus", "").upper()
+ if rule_status == "DELETING":
self._wait_for_deletion()
return False
@@ -1058,7 +1088,7 @@ class NetworkFirewallPolicyManager(NFPolicyBoto3Mixin, NFRuleGroupBoto3Mixin, Ba
if not policies:
return list()
- return [p.get('Arn', None) for p in policies]
+ return [p.get("Arn", None) for p in policies]
@property
def _rule_group_name_cache(self):
@@ -1068,16 +1098,16 @@ class NetworkFirewallPolicyManager(NFPolicyBoto3Mixin, NFRuleGroupBoto3Mixin, Ba
if not results:
return dict()
- group_cache = {r.get('Name', None): r.get('Arn', None) for r in results}
+ group_cache = {r.get("Name", None): r.get("Arn", None) for r in results}
self._group_name_cache = group_cache
return group_cache
@property
def _stateful_rule_order(self):
- engine_options = self._get_resource_value('StatefulEngineOptions', None)
+ engine_options = self._get_resource_value("StatefulEngineOptions", None)
if not engine_options:
- return 'DEFAULT_ACTION_ORDER'
- return engine_options.get('RuleOrder', 'DEFAULT_ACTION_ORDER')
+ return "DEFAULT_ACTION_ORDER"
+ return engine_options.get("RuleOrder", "DEFAULT_ACTION_ORDER")
def _canonicalize_rule_group(self, name, group_type):
"""Iterates through a mixed list of ARNs and Names converting them to
@@ -1085,20 +1115,22 @@ class NetworkFirewallPolicyManager(NFPolicyBoto3Mixin, NFRuleGroupBoto3Mixin, Ba
"""
arn = None
# : is only valid in ARNs
- if ':' in name:
+ if ":" in name:
arn = name
else:
arn = self._rule_group_name_cache.get(name, None)
if not arn:
- self.module.fail_json('Unable to fetch ARN for rule group', name=name,
- group_name_cache=self._rule_group_name_cache)
+ self.module.fail_json(
+ "Unable to fetch ARN for rule group", name=name, group_name_cache=self._rule_group_name_cache
+ )
arn_info = parse_aws_arn(arn)
if not arn_info:
- self.module.fail_json('Unable to parse ARN for rule group', arn=arn, arn_info=arn_info)
- arn_type = arn_info['resource'].split('/')[0]
+ self.module.fail_json("Unable to parse ARN for rule group", arn=arn, arn_info=arn_info)
+ arn_type = arn_info["resource"].split("/")[0]
if arn_type != group_type:
- self.module.fail_json('Rule group not of expected type', name=name,
- arn=arn, expected_type=group_type, found_type=arn_type)
+ self.module.fail_json(
+ "Rule group not of expected type", name=name, arn=arn, expected_type=group_type, found_type=arn_type
+ )
return arn
@@ -1107,15 +1139,15 @@ class NetworkFirewallPolicyManager(NFPolicyBoto3Mixin, NFRuleGroupBoto3Mixin, Ba
for idx, arn in enumerate(groups):
entry = dict(ResourceArn=arn)
if strict_order:
- entry['Priority'] = idx + 1
+ entry["Priority"] = idx + 1
formated_groups.append(entry)
return formated_groups
def _rulegroup_references_list(self, groups):
- return [g.get('ResourceArn') for g in groups]
+ return [g.get("ResourceArn") for g in groups]
def _sorted_rulegroup_references_list(self, groups):
- sorted_list = sorted(groups, key=lambda g: g.get('Priority', None))
+ sorted_list = sorted(groups, key=lambda g: g.get("Priority", None))
return self._rulegroup_references_list(sorted_list)
def _compare_rulegroup_references(self, current_groups, desired_groups, strict_order):
@@ -1132,23 +1164,22 @@ class NetworkFirewallPolicyManager(NFPolicyBoto3Mixin, NFRuleGroupBoto3Mixin, Ba
if value is None:
return False
- engine_options = deepcopy(self._get_resource_value('StatefulEngineOptions', dict()))
+ engine_options = deepcopy(self._get_resource_value("StatefulEngineOptions", dict()))
if value == engine_options.get(option_name, default_value):
return False
if immutable and self.original_resource:
- self.module.fail_json(msg='{0} can not be updated after creation'
- .format(description))
+ self.module.fail_json(msg=f"{description} can not be updated after creation")
engine_options[option_name] = value
- return self._set_resource_value('StatefulEngineOptions', engine_options)
+ return self._set_resource_value("StatefulEngineOptions", engine_options)
def set_stateful_rule_order(self, order):
RULE_ORDER_MAP = {
- 'default': 'DEFAULT_ACTION_ORDER',
- 'strict': 'STRICT_ORDER',
+ "default": "DEFAULT_ACTION_ORDER",
+ "strict": "STRICT_ORDER",
}
value = RULE_ORDER_MAP.get(order)
- changed = self._set_engine_option('RuleOrder', 'Rule order', value, True, 'DEFAULT_ACTION_ORDER')
+ changed = self._set_engine_option("RuleOrder", "Rule order", value, True, "DEFAULT_ACTION_ORDER")
self.changed |= changed
return changed
@@ -1163,14 +1194,11 @@ class NetworkFirewallPolicyManager(NFPolicyBoto3Mixin, NFRuleGroupBoto3Mixin, Ba
return self._set_resource_value(parameter_name, formated_groups)
def set_stateful_rule_groups(self, groups):
- strict_order = self._stateful_rule_order == 'STRICT_ORDER'
- return self._set_rule_groups(groups, 'stateful-rulegroup',
- 'StatefulRuleGroupReferences',
- strict_order)
+ strict_order = self._stateful_rule_order == "STRICT_ORDER"
+ return self._set_rule_groups(groups, "stateful-rulegroup", "StatefulRuleGroupReferences", strict_order)
def set_stateless_rule_groups(self, groups):
- return self._set_rule_groups(groups, 'stateless-rulegroup',
- 'StatelessRuleGroupReferences', True)
+ return self._set_rule_groups(groups, "stateless-rulegroup", "StatelessRuleGroupReferences", True)
def set_default_actions(self, key, actions, valid_actions=None):
if actions is None:
@@ -1179,38 +1207,35 @@ class NetworkFirewallPolicyManager(NFPolicyBoto3Mixin, NFRuleGroupBoto3Mixin, Ba
invalid_actions = list(set(actions) - set(valid_actions or []))
if valid_actions and invalid_actions:
self.module.fail_json(
- msg='{0} contains invalid actions'.format(key),
- valid_actions=valid_actions, invalid_actions=invalid_actions,
- actions=actions)
+ msg=f"{key} contains invalid actions",
+ valid_actions=valid_actions,
+ invalid_actions=invalid_actions,
+ actions=actions,
+ )
return self._set_resource_value(key, actions)
def set_stateful_default_actions(self, actions):
if actions is None:
return False
- if self._stateful_rule_order != 'STRICT_ORDER':
- self.module.fail_json(msg='Stateful default actions can only be set when using strict rule order')
+ if self._stateful_rule_order != "STRICT_ORDER":
+ self.module.fail_json(msg="Stateful default actions can only be set when using strict rule order")
- valid_actions = [
- 'aws:drop_strict', 'aws:drop_established',
- 'aws:alert_strict', 'aws:alert_established'
- ]
- return self.set_default_actions('StatefulDefaultActions', actions, valid_actions)
+ valid_actions = ["aws:drop_strict", "aws:drop_established", "aws:alert_strict", "aws:alert_established"]
+ return self.set_default_actions("StatefulDefaultActions", actions, valid_actions)
def _set_stateless_default_actions(self, key, actions):
- valid_actions = [
- 'aws:pass', 'aws:drop', 'aws:forward_to_sfe'
- ]
- custom_actions = self._get_resource_value('StatelessCustomActions', dict())
- custom_action_names = [a['ActionName'] for a in custom_actions]
+ valid_actions = ["aws:pass", "aws:drop", "aws:forward_to_sfe"]
+ custom_actions = self._get_resource_value("StatelessCustomActions", dict())
+ custom_action_names = [a["ActionName"] for a in custom_actions]
valid_actions.extend(custom_action_names)
return self.set_default_actions(key, actions, valid_actions)
def set_stateless_default_actions(self, actions):
- return self._set_stateless_default_actions('StatelessDefaultActions', actions)
+ return self._set_stateless_default_actions("StatelessDefaultActions", actions)
def set_stateless_fragment_default_actions(self, actions):
- return self._set_stateless_default_actions('StatelessFragmentDefaultActions', actions)
+ return self._set_stateless_default_actions("StatelessFragmentDefaultActions", actions)
def _normalize_policy(self, policy):
if policy is None:
@@ -1226,20 +1251,19 @@ class NetworkFirewallPolicyManager(NFPolicyBoto3Mixin, NFRuleGroupBoto3Mixin, Ba
def _normalize_policy_result(self, result):
if result is None:
return None
- policy = self._normalize_policy(result.get('FirewallPolicy', None))
- policy_metadata = self._normalize_policy_metadata(result.get('FirewallPolicyMetadata', None))
+ policy = self._normalize_policy(result.get("FirewallPolicy", None))
+ policy_metadata = self._normalize_policy_metadata(result.get("FirewallPolicyMetadata", None))
result = dict()
if policy:
- result['policy'] = policy
+ result["policy"] = policy
if policy_metadata:
- result['policy_metadata'] = policy_metadata
+ result["policy_metadata"] = policy_metadata
return result
def _normalize_resource(self, resource):
return self._normalize_policy_result(resource)
def get_policy(self, name=None, arn=None):
-
id_params = self._get_id_params(name=name, arn=arn)
result = self._get_policy(**id_params)
@@ -1251,21 +1275,21 @@ class NetworkFirewallPolicyManager(NFPolicyBoto3Mixin, NFRuleGroupBoto3Mixin, Ba
def _format_custom_action(self, action):
formatted_action = dict(
- ActionName=action['name'],
+ ActionName=action["name"],
)
action_definition = dict()
- if 'publish_metric_dimension_value' in action:
- values = _string_list(action['publish_metric_dimension_value'])
+ if "publish_metric_dimension_value" in action:
+ values = _string_list(action["publish_metric_dimension_value"])
dimensions = [dict(Value=v) for v in values]
- action_definition['PublishMetricAction'] = dict(
+ action_definition["PublishMetricAction"] = dict(
Dimensions=dimensions,
)
if action_definition:
- formatted_action['ActionDefinition'] = action_definition
+ formatted_action["ActionDefinition"] = action_definition
return formatted_action
def _custom_action_map(self, actions):
- return {a['ActionName']: a['ActionDefinition'] for a in actions}
+ return {a["ActionName"]: a["ActionDefinition"] for a in actions}
def set_custom_stateless_actions(self, actions, purge_actions):
if actions is None:
@@ -1273,9 +1297,7 @@ class NetworkFirewallPolicyManager(NFPolicyBoto3Mixin, NFRuleGroupBoto3Mixin, Ba
new_action_list = [self._format_custom_action(a) for a in actions]
new_action_map = self._custom_action_map(new_action_list)
- existing_action_map = self._custom_action_map(
- self._get_resource_value('StatelessCustomActions', [])
- )
+ existing_action_map = self._custom_action_map(self._get_resource_value("StatelessCustomActions", []))
if purge_actions:
desired_action_map = dict()
else:
@@ -1286,34 +1308,31 @@ class NetworkFirewallPolicyManager(NFPolicyBoto3Mixin, NFRuleGroupBoto3Mixin, Ba
return False
action_list = [dict(ActionName=k, ActionDefinition=v) for k, v in desired_action_map.items()]
- self._set_resource_value('StatelessCustomActions', action_list)
+ self._set_resource_value("StatelessCustomActions", action_list)
def set_description(self, description):
- return self._set_metadata_value('Description', description)
+ return self._set_metadata_value("Description", description)
def _do_create_resource(self):
metadata, resource = self._merge_changes(filter_metadata=False)
params = metadata
params.update(self._get_id_params())
- params['FirewallPolicy'] = resource
+ params["FirewallPolicy"] = resource
response = self._create_policy(**params)
return bool(response)
def _generate_updated_resource(self):
metadata, resource = self._merge_changes(filter_metadata=False)
metadata.update(self._get_id_params())
- updated_resource = dict(
- FirewallPolicy=resource,
- FirewallPolicyMetadata=metadata
- )
+ updated_resource = dict(FirewallPolicy=resource, FirewallPolicyMetadata=metadata)
return updated_resource
def _flush_create(self):
# Set some defaults
- if self._get_resource_value('StatelessDefaultActions', None) is None:
- self._set_resource_value('StatelessDefaultActions', ['aws:forward_to_sfe'])
- if self._get_resource_value('StatelessFragmentDefaultActions', None) is None:
- self._set_resource_value('StatelessFragmentDefaultActions', ['aws:forward_to_sfe'])
+ if self._get_resource_value("StatelessDefaultActions", None) is None:
+ self._set_resource_value("StatelessDefaultActions", ["aws:forward_to_sfe"])
+ if self._get_resource_value("StatelessFragmentDefaultActions", None) is None:
+ self._set_resource_value("StatelessFragmentDefaultActions", ["aws:forward_to_sfe"])
return super(NetworkFirewallPolicyManager, self)._flush_create()
def _do_update_resource(self):
@@ -1327,7 +1346,7 @@ class NetworkFirewallPolicyManager(NFPolicyBoto3Mixin, NFRuleGroupBoto3Mixin, Ba
params = metadata
params.update(self._get_id_params())
- params['FirewallPolicy'] = resource
+ params["FirewallPolicy"] = resource
if not self.module.check_mode:
response = self._update_policy(**params)
@@ -1345,13 +1364,13 @@ class NetworkFirewallPolicyManager(NFPolicyBoto3Mixin, NFRuleGroupBoto3Mixin, Ba
if not result:
return None
- policy = result.get('FirewallPolicy', None)
+ policy = result.get("FirewallPolicy", None)
# During deletion, there's a phase where this will return Metadata but
# no policy
if policy is None:
policy = dict()
- metadata = result.get('FirewallPolicyMetadata', None)
+ metadata = result.get("FirewallPolicyMetadata", None)
self._preupdate_resource = deepcopy(policy)
self._preupdate_metadata = deepcopy(metadata)
return dict(FirewallPolicy=policy, FirewallPolicyMetadata=metadata)
@@ -1371,7 +1390,6 @@ class NetworkFirewallPolicyManager(NFPolicyBoto3Mixin, NFRuleGroupBoto3Mixin, Ba
class NetworkFirewallManager(NFFirewallBoto3Mixin, NFPolicyBoto3Mixin, BaseNetworkFirewallManager):
-
name = None
arn = None
ec2_manager = None
@@ -1393,13 +1411,13 @@ class NetworkFirewallManager(NFFirewallBoto3Mixin, NFPolicyBoto3Mixin, BaseNetwo
def _extra_error_output(self):
output = super(NetworkFirewallManager, self)._extra_error_output()
if self.name:
- output['FirewallName'] = self.name
+ output["FirewallName"] = self.name
if self.arn:
- output['FirewallArn'] = self.arn
+ output["FirewallArn"] = self.arn
return output
def _get_preupdate_arn(self):
- return self._get_resource_value('FirewallArn')
+ return self._get_resource_value("FirewallArn")
def _get_id_params(self, name=None, arn=None):
if arn:
@@ -1410,11 +1428,10 @@ class NetworkFirewallManager(NFFirewallBoto3Mixin, NFPolicyBoto3Mixin, BaseNetwo
name = self.name
if not name:
# Users should never see this, but let's cover ourself
- self.module.fail_json(msg='Firewall identifier parameters missing')
+ self.module.fail_json(msg="Firewall identifier parameters missing")
return dict(FirewallName=name)
def delete(self, name=None, arn=None):
-
id_params = self._get_id_params(name=name, arn=arn)
result = self._get_firewall(**id_params)
@@ -1424,8 +1441,8 @@ class NetworkFirewallManager(NFFirewallBoto3Mixin, NFPolicyBoto3Mixin, BaseNetwo
self.updated_resource = dict()
# Firewall is already in the process of being deleted (takes time)
- firewall_status = self._get_metadata_value('Status', '').upper()
- if firewall_status == 'DELETING':
+ firewall_status = self._get_metadata_value("Status", "").upper()
+ if firewall_status == "DELETING":
self._wait_for_deletion()
return False
@@ -1433,9 +1450,10 @@ class NetworkFirewallManager(NFFirewallBoto3Mixin, NFPolicyBoto3Mixin, BaseNetwo
self.changed = True
return True
- if 'DeleteProtection' in self._resource_updates:
+ if "DeleteProtection" in self._resource_updates:
self._update_firewall_delete_protection(
- DeleteProtection=self._resource_updates['DeleteProtection'], **id_params,
+ DeleteProtection=self._resource_updates["DeleteProtection"],
+ **id_params,
)
result = self._delete_firewall(**id_params)
@@ -1446,55 +1464,54 @@ class NetworkFirewallManager(NFFirewallBoto3Mixin, NFPolicyBoto3Mixin, BaseNetwo
def list(self, vpc_ids=None):
params = dict()
if vpc_ids:
- params['VpcIds'] = vpc_ids
+ params["VpcIds"] = vpc_ids
firewalls = self._list_firewalls(**params)
if not firewalls:
return list()
- return [f.get('FirewallArn', None) for f in firewalls]
+ return [f.get("FirewallArn", None) for f in firewalls]
def _normalize_firewall(self, firewall):
if firewall is None:
return None
- subnets = [s.get('SubnetId') for s in firewall.get('SubnetMappings', [])]
+ subnets = [s.get("SubnetId") for s in firewall.get("SubnetMappings", [])]
firewall = self._normalize_boto3_resource(firewall, add_tags=True)
- firewall['subnets'] = subnets
+ firewall["subnets"] = subnets
return firewall
def _normalize_sync_state_config(self, policy):
return self._normalize_boto3_resource(policy)
def _normalize_sync_state(self, state):
- config = {k: self._normalize_sync_state_config(v) for k, v in state.pop('Config', {}).items()}
+ config = {k: self._normalize_sync_state_config(v) for k, v in state.pop("Config", {}).items()}
state = self._normalize_boto3_resource(state)
- state['config'] = config or {}
+ state["config"] = config or {}
return state
def _normalize_firewall_metadata(self, firewall_metadata):
if firewall_metadata is None:
return None
- states = {k: self._normalize_sync_state(v) for k, v in firewall_metadata.pop('SyncStates', {}).items()}
+ states = {k: self._normalize_sync_state(v) for k, v in firewall_metadata.pop("SyncStates", {}).items()}
metadata = self._normalize_boto3_resource(firewall_metadata, add_tags=False)
- metadata['sync_states'] = states or {}
+ metadata["sync_states"] = states or {}
return metadata
def _normalize_firewall_result(self, result):
if result is None:
return None
- firewall = self._normalize_firewall(result.get('Firewall', None))
- firewall_metadata = self._normalize_firewall_metadata(result.get('FirewallMetadata', None))
+ firewall = self._normalize_firewall(result.get("Firewall", None))
+ firewall_metadata = self._normalize_firewall_metadata(result.get("FirewallMetadata", None))
result = camel_dict_to_snake_dict(result)
if firewall:
- result['firewall'] = firewall
+ result["firewall"] = firewall
if firewall_metadata:
- result['firewall_metadata'] = firewall_metadata
+ result["firewall_metadata"] = firewall_metadata
return result
def _normalize_resource(self, resource):
return self._normalize_firewall_result(resource)
def get_firewall(self, name=None, arn=None):
-
id_params = self._get_id_params(name=name, arn=arn)
result = self._get_firewall(**id_params)
@@ -1506,8 +1523,8 @@ class NetworkFirewallManager(NFFirewallBoto3Mixin, NFPolicyBoto3Mixin, BaseNetwo
@property
def _subnets(self):
- subnet_mappings = self._get_resource_value('SubnetMappings', [])
- subnets = [s.get('SubnetId') for s in subnet_mappings]
+ subnet_mappings = self._get_resource_value("SubnetMappings", [])
+ subnets = [s.get("SubnetId") for s in subnet_mappings]
return subnets
def _subnets_to_vpc(self, subnets, subnet_details=None):
@@ -1515,11 +1532,13 @@ class NetworkFirewallManager(NFFirewallBoto3Mixin, NFPolicyBoto3Mixin, BaseNetwo
return None
if not subnet_details:
subnet_details = self.ec2_manager._describe_subnets(SubnetIds=list(subnets))
- vpcs = [s.get('VpcId') for s in subnet_details]
+ vpcs = [s.get("VpcId") for s in subnet_details]
if len(set(vpcs)) > 1:
self.module.fail_json(
- msg='Firewall subnets may only be in one VPC, multiple VPCs found',
- vpcs=list(set(vpcs)), subnets=subnet_details)
+ msg="Firewall subnets may only be in one VPC, multiple VPCs found",
+ vpcs=list(set(vpcs)),
+ subnets=subnet_details,
+ )
return vpcs[0]
def _format_subnet_mapping(self, subnets):
@@ -1535,7 +1554,7 @@ class NetworkFirewallManager(NFFirewallBoto3Mixin, NFPolicyBoto3Mixin, BaseNetwo
if not results:
return dict()
- policy_cache = {p.get('Name', None): p.get('Arn', None) for p in results}
+ policy_cache = {p.get("Name", None): p.get("Arn", None) for p in results}
self._policy_list_cache = policy_cache
return policy_cache
@@ -1545,20 +1564,26 @@ class NetworkFirewallManager(NFFirewallBoto3Mixin, NFPolicyBoto3Mixin, BaseNetwo
"""
arn = None
# : is only valid in ARNs
- if ':' in name:
+ if ":" in name:
arn = name
else:
arn = self._policy_name_cache.get(name, None)
if not arn:
- self.module.fail_json('Unable to fetch ARN for policy', name=name,
- policy_name_cache=self._policy_name_cache)
+ self.module.fail_json(
+ "Unable to fetch ARN for policy", name=name, policy_name_cache=self._policy_name_cache
+ )
arn_info = parse_aws_arn(arn)
if not arn_info:
- self.module.fail_json('Unable to parse ARN for policy', arn=arn, arn_info=arn_info)
- arn_type = arn_info['resource'].split('/')[0]
- if arn_type != 'firewall-policy':
- self.module.fail_json('Policy ARN not of expected resource type', name=name,
- arn=arn, expected_type='firewall-policy', found_type=arn_type)
+ self.module.fail_json("Unable to parse ARN for policy", arn=arn, arn_info=arn_info)
+ arn_type = arn_info["resource"].split("/")[0]
+ if arn_type != "firewall-policy":
+ self.module.fail_json(
+ "Policy ARN not of expected resource type",
+ name=name,
+ arn=arn,
+ expected_type="firewall-policy",
+ found_type=arn_type,
+ )
return arn
@@ -1569,15 +1594,15 @@ class NetworkFirewallManager(NFFirewallBoto3Mixin, NFPolicyBoto3Mixin, BaseNetwo
# Because the canonicalization of a non-ARN policy name will require an API call,
# try comparing the current name to the policy name we've been passed.
# If they match we don't need to perform the lookup.
- current_policy = self._get_resource_value('FirewallPolicyArn', None)
+ current_policy = self._get_resource_value("FirewallPolicyArn", None)
if current_policy:
arn_info = parse_aws_arn(current_policy)
- current_name = arn_info['resource'].split('/')[-1]
+ current_name = arn_info["resource"].split("/")[-1]
if current_name == policy:
return False
policy = self._canonicalize_policy(policy)
- return self._set_resource_value('FirewallPolicyArn', policy)
+ return self._set_resource_value("FirewallPolicyArn", policy)
def set_subnets(self, subnets, purge=True):
if subnets is None:
@@ -1593,31 +1618,31 @@ class NetworkFirewallManager(NFFirewallBoto3Mixin, NFPolicyBoto3Mixin, BaseNetwo
subnet_details = self.ec2_manager._describe_subnets(SubnetIds=list(desired_subnets))
vpc = self._subnets_to_vpc(desired_subnets, subnet_details)
- self._set_resource_value('VpcId', vpc, description='firewall VPC', immutable=True)
+ self._set_resource_value("VpcId", vpc, description="firewall VPC", immutable=True)
- azs = [s.get('AvailabilityZoneId') for s in subnet_details]
+ azs = [s.get("AvailabilityZoneId") for s in subnet_details]
if len(azs) != len(set(azs)):
self.module.fail_json(
- msg='Only one subnet per availability zone may set.',
- availability_zones=azs, subnets=subnet_details)
+ msg="Only one subnet per availability zone may set.", availability_zones=azs, subnets=subnet_details
+ )
subnets_to_add = list(desired_subnets.difference(current_subnets))
subnets_to_remove = list(current_subnets.difference(desired_subnets))
self._subnet_updates = dict(add=subnets_to_add, remove=subnets_to_remove)
- self._set_resource_value('SubnetMappings', self._format_subnet_mapping(desired_subnets))
+ self._set_resource_value("SubnetMappings", self._format_subnet_mapping(desired_subnets))
return True
def set_policy_change_protection(self, protection):
- return self._set_resource_value('FirewallPolicyChangeProtection', protection)
+ return self._set_resource_value("FirewallPolicyChangeProtection", protection)
def set_subnet_change_protection(self, protection):
- return self._set_resource_value('SubnetChangeProtection', protection)
+ return self._set_resource_value("SubnetChangeProtection", protection)
def set_delete_protection(self, protection):
- return self._set_resource_value('DeleteProtection', protection)
+ return self._set_resource_value("DeleteProtection", protection)
def set_description(self, description):
- return self._set_resource_value('Description', description)
+ return self._set_resource_value("Description", description)
def _do_create_resource(self):
metadata, resource = self._merge_changes(filter_metadata=False)
@@ -1630,10 +1655,7 @@ class NetworkFirewallManager(NFFirewallBoto3Mixin, NFPolicyBoto3Mixin, BaseNetwo
def _generate_updated_resource(self):
metadata, resource = self._merge_changes(filter_metadata=False)
resource.update(self._get_id_params())
- updated_resource = dict(
- Firewall=resource,
- FirewallMetadata=metadata
- )
+ updated_resource = dict(Firewall=resource, FirewallMetadata=metadata)
return updated_resource
def _flush_create(self):
@@ -1655,59 +1677,60 @@ class NetworkFirewallManager(NFFirewallBoto3Mixin, NFPolicyBoto3Mixin, BaseNetwo
# There's no tool for 'bulk' updates, we need to iterate through these
# one at a time...
- if 'Description' in resource_updates:
+ if "Description" in resource_updates:
self._update_firewall_description(
- Description=resource_updates['Description'], **id_params,
+ Description=resource_updates["Description"],
+ **id_params,
)
- if 'DeleteProtection' in resource_updates:
+ if "DeleteProtection" in resource_updates:
self._update_firewall_delete_protection(
- DeleteProtection=resource_updates['DeleteProtection'], **id_params,
+ DeleteProtection=resource_updates["DeleteProtection"],
+ **id_params,
)
# Disable Change Protection...
# When disabling change protection, do so *before* making changes
- if 'FirewallPolicyChangeProtection' in resource_updates:
- if not self._get_resource_value('FirewallPolicyChangeProtection'):
+ if "FirewallPolicyChangeProtection" in resource_updates:
+ if not self._get_resource_value("FirewallPolicyChangeProtection"):
self._update_firewall_policy_change_protection(
- FirewallPolicyChangeProtection=resource_updates['FirewallPolicyChangeProtection'], **id_params,
+ FirewallPolicyChangeProtection=resource_updates["FirewallPolicyChangeProtection"],
+ **id_params,
)
- if 'SubnetChangeProtection' in resource_updates:
- if not self._get_resource_value('SubnetChangeProtection'):
+ if "SubnetChangeProtection" in resource_updates:
+ if not self._get_resource_value("SubnetChangeProtection"):
self._update_subnet_change_protection(
- SubnetChangeProtection=resource_updates['SubnetChangeProtection'], **id_params,
+ SubnetChangeProtection=resource_updates["SubnetChangeProtection"],
+ **id_params,
)
# General Changes
- if 'SubnetMappings' in resource_updates:
+ if "SubnetMappings" in resource_updates:
self._slow_start_change = True
- subnets_to_add = self._subnet_updates.get('add', None)
- subnets_to_remove = self._subnet_updates.get('remove', None)
+ subnets_to_add = self._subnet_updates.get("add", None)
+ subnets_to_remove = self._subnet_updates.get("remove", None)
if subnets_to_remove:
- self._disassociate_subnets(
- SubnetIds=subnets_to_remove, **id_params)
+ self._disassociate_subnets(SubnetIds=subnets_to_remove, **id_params)
if subnets_to_add:
subnets_to_add = self._format_subnet_mapping(subnets_to_add)
- self._associate_subnets(
- SubnetMappings=subnets_to_add, **id_params)
+ self._associate_subnets(SubnetMappings=subnets_to_add, **id_params)
- if 'FirewallPolicyArn' in resource_updates:
+ if "FirewallPolicyArn" in resource_updates:
self._slow_start_change = True
- self._associate_firewall_policy(
- FirewallPolicyArn=resource_updates['FirewallPolicyArn'],
- **id_params
- )
+ self._associate_firewall_policy(FirewallPolicyArn=resource_updates["FirewallPolicyArn"], **id_params)
# Enable Change Protection.
# When enabling change protection, do so *after* making changes
- if 'FirewallPolicyChangeProtection' in resource_updates:
- if self._get_resource_value('FirewallPolicyChangeProtection'):
+ if "FirewallPolicyChangeProtection" in resource_updates:
+ if self._get_resource_value("FirewallPolicyChangeProtection"):
self._update_firewall_policy_change_protection(
- FirewallPolicyChangeProtection=resource_updates['FirewallPolicyChangeProtection'], **id_params,
+ FirewallPolicyChangeProtection=resource_updates["FirewallPolicyChangeProtection"],
+ **id_params,
)
- if 'SubnetChangeProtection' in resource_updates:
- if self._get_resource_value('SubnetChangeProtection'):
+ if "SubnetChangeProtection" in resource_updates:
+ if self._get_resource_value("SubnetChangeProtection"):
self._update_subnet_change_protection(
- SubnetChangeProtection=resource_updates['SubnetChangeProtection'], **id_params,
+ SubnetChangeProtection=resource_updates["SubnetChangeProtection"],
+ **id_params,
)
return True
@@ -1724,8 +1747,8 @@ class NetworkFirewallManager(NFFirewallBoto3Mixin, NFPolicyBoto3Mixin, BaseNetwo
if not result:
return None
- firewall = result.get('Firewall', None)
- metadata = result.get('FirewallMetadata', None)
+ firewall = result.get("Firewall", None)
+ metadata = result.get("FirewallMetadata", None)
self._preupdate_resource = deepcopy(firewall)
self._preupdate_metadata = deepcopy(metadata)
return dict(Firewall=firewall, FirewallMetadata=metadata)
@@ -1756,7 +1779,7 @@ class NetworkFirewallManager(NFFirewallBoto3Mixin, NFPolicyBoto3Mixin, BaseNetwo
# Unlike RuleGroups and Policies for some reason Firewalls have the tags set
# directly on the resource.
def _set_tag_values(self, desired_tags):
- return self._set_resource_value('Tags', ansible_dict_to_boto3_tag_list(desired_tags))
+ return self._set_resource_value("Tags", ansible_dict_to_boto3_tag_list(desired_tags))
def _get_tag_values(self):
- return self._get_resource_value('Tags', [])
+ return self._get_resource_value("Tags", [])
diff --git a/ansible_collections/community/aws/plugins/module_utils/opensearch.py b/ansible_collections/community/aws/plugins/module_utils/opensearch.py
index 8189378e5..13d90bd6a 100644
--- a/ansible_collections/community/aws/plugins/module_utils/opensearch.py
+++ b/ansible_collections/community/aws/plugins/module_utils/opensearch.py
@@ -1,31 +1,26 @@
-# This file is part of Ansible
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
+# -*- coding: utf-8 -*-
-__metaclass__ = type
+# Copyright: Contributors to the Ansible project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from copy import deepcopy
import datetime
import functools
import time
+from copy import deepcopy
try:
import botocore
except ImportError:
pass # caught by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import (
- ansible_dict_to_boto3_tag_list,
- camel_dict_to_snake_dict,
- compare_aws_tags,
-)
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.tagging import (
- boto3_tag_list_to_ansible_dict,
-)
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
from ansible.module_utils.six import string_types
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import ansible_dict_to_boto3_tag_list
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import compare_aws_tags
+
def get_domain_status(client, module, domain_name):
"""
@@ -35,8 +30,11 @@ def get_domain_status(client, module, domain_name):
response = client.describe_domain(DomainName=domain_name)
except is_boto3_error_code("ResourceNotFoundException"):
return None
- except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, msg="Couldn't get domain {0}".format(domain_name))
+ except (
+ botocore.exceptions.BotoCoreError,
+ botocore.exceptions.ClientError,
+ ) as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(e, msg=f"Couldn't get domain {domain_name}")
return response["DomainStatus"]
@@ -54,13 +52,17 @@ def get_domain_config(client, module, domain_name):
response = client.describe_domain_config(DomainName=domain_name)
except is_boto3_error_code("ResourceNotFoundException"):
return (None, None)
- except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, msg="Couldn't get domain {0}".format(domain_name))
+ except (
+ botocore.exceptions.BotoCoreError,
+ botocore.exceptions.ClientError,
+ ) as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(e, msg=f"Couldn't get domain {domain_name}")
domain_config = {}
arn = None
if response is not None:
for k in response["DomainConfig"]:
- domain_config[k] = response["DomainConfig"][k]["Options"]
+ if "Options" in response["DomainConfig"][k]:
+ domain_config[k] = response["DomainConfig"][k]["Options"]
domain_config["DomainName"] = domain_name
# If ES cluster is attached to the Internet, the "VPCOptions" property is not present.
if "VPCOptions" in domain_config:
@@ -93,13 +95,9 @@ def normalize_opensearch(client, module, domain):
convert the attributes from camel case to snake case, and return the object.
"""
try:
- domain["Tags"] = boto3_tag_list_to_ansible_dict(
- client.list_tags(ARN=domain["ARN"], aws_retry=True)["TagList"]
- )
+ domain["Tags"] = boto3_tag_list_to_ansible_dict(client.list_tags(ARN=domain["ARN"], aws_retry=True)["TagList"])
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(
- e, "Couldn't get tags for domain %s" % domain["domain_name"]
- )
+ module.fail_json_aws(e, f"Couldn't get tags for domain {domain['domain_name']}")
except KeyError:
module.fail_json(msg=str(domain))
@@ -133,16 +131,14 @@ def wait_for_domain_status(client, module, domain_name, waiter_name):
return
time.sleep(15)
# Timeout occured.
- module.fail_json(
- msg=f"Timeout waiting for wait state '{waiter_name}'. {status_msg}"
- )
+ module.fail_json(msg=f"Timeout waiting for wait state '{waiter_name}'. {status_msg}")
def parse_version(engine_version):
- '''
+ """
Parse the engine version, which should be Elasticsearch_X.Y or OpenSearch_X.Y
Return dict { 'engine_type': engine_type, 'major': major, 'minor': minor }
- '''
+ """
version = engine_version.split("_")
if len(version) != 2:
return None
@@ -150,19 +146,19 @@ def parse_version(engine_version):
if len(semver) != 2:
return None
engine_type = version[0]
- if engine_type not in ['Elasticsearch', 'OpenSearch']:
+ if engine_type not in ["Elasticsearch", "OpenSearch"]:
return None
if not (semver[0].isdigit() and semver[1].isdigit()):
return None
major = int(semver[0])
minor = int(semver[1])
- return {'engine_type': engine_type, 'major': major, 'minor': minor}
+ return {"engine_type": engine_type, "major": major, "minor": minor}
def compare_domain_versions(version1, version2):
supported_engines = {
- 'Elasticsearch': 1,
- 'OpenSearch': 2,
+ "Elasticsearch": 1,
+ "OpenSearch": 2,
}
if isinstance(version1, string_types):
version1 = parse_version(version1)
@@ -174,21 +170,21 @@ def compare_domain_versions(version1, version2):
return 1
elif version1 is None and version2 is None:
return 0
- e1 = supported_engines.get(version1.get('engine_type'))
- e2 = supported_engines.get(version2.get('engine_type'))
+ e1 = supported_engines.get(version1.get("engine_type"))
+ e2 = supported_engines.get(version2.get("engine_type"))
if e1 < e2:
return -1
elif e1 > e2:
return 1
else:
- if version1.get('major') < version2.get('major'):
+ if version1.get("major") < version2.get("major"):
return -1
- elif version1.get('major') > version2.get('major'):
+ elif version1.get("major") > version2.get("major"):
return 1
else:
- if version1.get('minor') < version2.get('minor'):
+ if version1.get("minor") < version2.get("minor"):
return -1
- elif version1.get('minor') > version2.get('minor'):
+ elif version1.get("minor") > version2.get("minor"):
return 1
else:
return 0
@@ -208,22 +204,15 @@ def get_target_increment_version(client, module, domain_name, target_version):
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
module.fail_json_aws(
e,
- msg="Couldn't get compatible versions for domain {0}".format(
- domain_name),
+ msg=f"Couldn't get compatible versions for domain {domain_name}",
)
- compat = api_compatible_versions.get('CompatibleVersions')
+ compat = api_compatible_versions.get("CompatibleVersions")
if compat is None:
- module.fail_json(
- "Unable to determine list of compatible versions",
- compatible_versions=api_compatible_versions)
+ module.fail_json("Unable to determine list of compatible versions", compatible_versions=api_compatible_versions)
if len(compat) == 0:
- module.fail_json(
- "Unable to determine list of compatible versions",
- compatible_versions=api_compatible_versions)
+ module.fail_json("Unable to determine list of compatible versions", compatible_versions=api_compatible_versions)
if compat[0].get("TargetVersions") is None:
- module.fail_json(
- "No compatible versions found",
- compatible_versions=api_compatible_versions)
+ module.fail_json("No compatible versions found", compatible_versions=api_compatible_versions)
compatible_versions = []
for v in compat[0].get("TargetVersions"):
if target_version == v:
@@ -248,9 +237,7 @@ def ensure_tags(client, module, resource_arn, existing_tags, tags, purge_tags):
changed = bool(tags_to_add or tags_to_remove)
if tags_to_add:
if module.check_mode:
- module.exit_json(
- changed=True, msg="Would have added tags to domain if not in check mode"
- )
+ module.exit_json(changed=True, msg="Would have added tags to domain if not in check mode")
try:
client.add_tags(
ARN=resource_arn,
@@ -260,21 +247,15 @@ def ensure_tags(client, module, resource_arn, existing_tags, tags, purge_tags):
botocore.exceptions.ClientError,
botocore.exceptions.BotoCoreError,
) as e:
- module.fail_json_aws(
- e, "Couldn't add tags to domain {0}".format(resource_arn)
- )
+ module.fail_json_aws(e, f"Couldn't add tags to domain {resource_arn}")
if tags_to_remove:
if module.check_mode:
- module.exit_json(
- changed=True, msg="Would have removed tags if not in check mode"
- )
+ module.exit_json(changed=True, msg="Would have removed tags if not in check mode")
try:
client.remove_tags(ARN=resource_arn, TagKeys=tags_to_remove)
except (
botocore.exceptions.ClientError,
botocore.exceptions.BotoCoreError,
) as e:
- module.fail_json_aws(
- e, "Couldn't remove tags from domain {0}".format(resource_arn)
- )
+ module.fail_json_aws(e, f"Couldn't remove tags from domain {resource_arn}")
return changed
diff --git a/ansible_collections/community/aws/plugins/module_utils/sns.py b/ansible_collections/community/aws/plugins/module_utils/sns.py
index 44327d493..3c4e2a436 100644
--- a/ansible_collections/community/aws/plugins/module_utils/sns.py
+++ b/ansible_collections/community/aws/plugins/module_utils/sns.py
@@ -1,53 +1,57 @@
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
+# -*- coding: utf-8 -*-
+
+# Copyright: Contributors to the Ansible project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-import re
import copy
+import re
try:
import botocore
except ImportError:
pass # handled by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_tag_list
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import compare_aws_tags
+
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import ansible_dict_to_boto3_tag_list
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import compare_aws_tags
@AWSRetry.jittered_backoff()
def _list_topics_with_backoff(client):
- paginator = client.get_paginator('list_topics')
- return paginator.paginate().build_full_result()['Topics']
+ paginator = client.get_paginator("list_topics")
+ return paginator.paginate().build_full_result()["Topics"]
-@AWSRetry.jittered_backoff(catch_extra_error_codes=['NotFound'])
+@AWSRetry.jittered_backoff(catch_extra_error_codes=["NotFound"])
def _list_topic_subscriptions_with_backoff(client, topic_arn):
- paginator = client.get_paginator('list_subscriptions_by_topic')
- return paginator.paginate(TopicArn=topic_arn).build_full_result()['Subscriptions']
+ paginator = client.get_paginator("list_subscriptions_by_topic")
+ return paginator.paginate(TopicArn=topic_arn).build_full_result()["Subscriptions"]
-@AWSRetry.jittered_backoff(catch_extra_error_codes=['NotFound'])
+@AWSRetry.jittered_backoff(catch_extra_error_codes=["NotFound"])
def _list_subscriptions_with_backoff(client):
- paginator = client.get_paginator('list_subscriptions')
- return paginator.paginate().build_full_result()['Subscriptions']
+ paginator = client.get_paginator("list_subscriptions")
+ return paginator.paginate().build_full_result()["Subscriptions"]
def list_topic_subscriptions(client, module, topic_arn):
try:
return _list_topic_subscriptions_with_backoff(client, topic_arn)
- except is_boto3_error_code('AuthorizationError'):
+ except is_boto3_error_code("AuthorizationError"):
try:
# potentially AuthorizationError when listing subscriptions for third party topic
- return [sub for sub in _list_subscriptions_with_backoff(client)
- if sub['TopicArn'] == topic_arn]
+ return [sub for sub in _list_subscriptions_with_backoff(client) if sub["TopicArn"] == topic_arn]
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Couldn't get subscriptions list for topic %s" % topic_arn)
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, msg="Couldn't get subscriptions list for topic %s" % topic_arn)
+ module.fail_json_aws(e, msg=f"Couldn't get subscriptions list for topic {topic_arn}")
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(e, msg=f"Couldn't get subscriptions list for topic {topic_arn}")
def list_topics(client, module):
@@ -55,13 +59,13 @@ def list_topics(client, module):
topics = _list_topics_with_backoff(client)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Couldn't get topic list")
- return [t['TopicArn'] for t in topics]
+ return [t["TopicArn"] for t in topics]
def topic_arn_lookup(client, module, name):
# topic names cannot have colons, so this captures the full topic name
all_topics = list_topics(client, module)
- lookup_topic = ':%s' % name
+ lookup_topic = f":{name}"
for topic in all_topics:
if topic.endswith(lookup_topic):
return topic
@@ -72,13 +76,13 @@ def compare_delivery_policies(policy_a, policy_b):
_policy_b = copy.deepcopy(policy_b)
# AWS automatically injects disableSubscriptionOverrides if you set an
# http policy
- if 'http' in policy_a:
- if 'disableSubscriptionOverrides' not in policy_a['http']:
- _policy_a['http']['disableSubscriptionOverrides'] = False
- if 'http' in policy_b:
- if 'disableSubscriptionOverrides' not in policy_b['http']:
- _policy_b['http']['disableSubscriptionOverrides'] = False
- comparison = (_policy_a != _policy_b)
+ if "http" in policy_a:
+ if "disableSubscriptionOverrides" not in policy_a["http"]:
+ _policy_a["http"]["disableSubscriptionOverrides"] = False
+ if "http" in policy_b:
+ if "disableSubscriptionOverrides" not in policy_b["http"]:
+ _policy_b["http"]["disableSubscriptionOverrides"] = False
+ comparison = _policy_a != _policy_b
return comparison
@@ -86,15 +90,15 @@ def canonicalize_endpoint(protocol, endpoint):
# AWS SNS expects phone numbers in
# and canonicalizes to E.164 format
# See <https://docs.aws.amazon.com/sns/latest/dg/sms_publish-to-phone.html>
- if protocol == 'sms':
- return re.sub('[^0-9+]*', '', endpoint)
+ if protocol == "sms":
+ return re.sub("[^0-9+]*", "", endpoint)
return endpoint
def get_tags(client, module, topic_arn):
try:
- return boto3_tag_list_to_ansible_dict(client.list_tags_for_resource(ResourceArn=topic_arn)['Tags'])
- except is_boto3_error_code('AuthorizationError'):
+ return boto3_tag_list_to_ansible_dict(client.list_tags_for_resource(ResourceArn=topic_arn)["Tags"])
+ except is_boto3_error_code("AuthorizationError"):
module.warn("Permission denied accessing tags")
return {}
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
@@ -102,52 +106,53 @@ def get_tags(client, module, topic_arn):
def get_info(connection, module, topic_arn):
- name = module.params.get('name')
- topic_type = module.params.get('topic_type')
- state = module.params.get('state')
- subscriptions = module.params.get('subscriptions')
- purge_subscriptions = module.params.get('purge_subscriptions')
- content_based_deduplication = module.params.get('content_based_deduplication')
- subscriptions_existing = module.params.get('subscriptions_existing', [])
- subscriptions_deleted = module.params.get('subscriptions_deleted', [])
- subscriptions_added = module.params.get('subscriptions_added', [])
- subscriptions_added = module.params.get('subscriptions_added', [])
- topic_created = module.params.get('topic_created', False)
- topic_deleted = module.params.get('topic_deleted', False)
- attributes_set = module.params.get('attributes_set', [])
+ name = module.params.get("name")
+ topic_type = module.params.get("topic_type")
+ state = module.params.get("state")
+ subscriptions = module.params.get("subscriptions")
+ purge_subscriptions = module.params.get("purge_subscriptions")
+ content_based_deduplication = module.params.get("content_based_deduplication")
+ subscriptions_existing = module.params.get("subscriptions_existing", [])
+ subscriptions_deleted = module.params.get("subscriptions_deleted", [])
+ subscriptions_added = module.params.get("subscriptions_added", [])
+ subscriptions_added = module.params.get("subscriptions_added", [])
+ topic_created = module.params.get("topic_created", False)
+ topic_deleted = module.params.get("topic_deleted", False)
+ attributes_set = module.params.get("attributes_set", [])
check_mode = module.check_mode
info = {
- 'name': name,
- 'topic_type': topic_type,
- 'state': state,
- 'subscriptions_new': subscriptions,
- 'subscriptions_existing': subscriptions_existing,
- 'subscriptions_deleted': subscriptions_deleted,
- 'subscriptions_added': subscriptions_added,
- 'subscriptions_purge': purge_subscriptions,
- 'content_based_deduplication': content_based_deduplication,
- 'check_mode': check_mode,
- 'topic_created': topic_created,
- 'topic_deleted': topic_deleted,
- 'attributes_set': attributes_set,
+ "name": name,
+ "topic_type": topic_type,
+ "state": state,
+ "subscriptions_new": subscriptions,
+ "subscriptions_existing": subscriptions_existing,
+ "subscriptions_deleted": subscriptions_deleted,
+ "subscriptions_added": subscriptions_added,
+ "subscriptions_purge": purge_subscriptions,
+ "content_based_deduplication": content_based_deduplication,
+ "check_mode": check_mode,
+ "topic_created": topic_created,
+ "topic_deleted": topic_deleted,
+ "attributes_set": attributes_set,
}
- if state != 'absent':
+ if state != "absent":
if topic_arn in list_topics(connection, module):
- info.update(camel_dict_to_snake_dict(connection.get_topic_attributes(TopicArn=topic_arn)['Attributes']))
- info['delivery_policy'] = info.pop('effective_delivery_policy')
- info['subscriptions'] = [camel_dict_to_snake_dict(sub) for sub in list_topic_subscriptions(connection, module, topic_arn)]
+ info.update(camel_dict_to_snake_dict(connection.get_topic_attributes(TopicArn=topic_arn)["Attributes"]))
+ info["delivery_policy"] = info.pop("effective_delivery_policy")
+ info["subscriptions"] = [
+ camel_dict_to_snake_dict(sub) for sub in list_topic_subscriptions(connection, module, topic_arn)
+ ]
info["tags"] = get_tags(connection, module, topic_arn)
return info
def update_tags(client, module, topic_arn):
-
- if module.params.get('tags') is None:
+ if module.params.get("tags") is None:
return False
existing_tags = get_tags(client, module, topic_arn)
- to_update, to_delete = compare_aws_tags(existing_tags, module.params['tags'], module.params['purge_tags'])
+ to_update, to_delete = compare_aws_tags(existing_tags, module.params["tags"], module.params["purge_tags"])
if not bool(to_delete or to_update):
return False
@@ -157,8 +162,7 @@ def update_tags(client, module, topic_arn):
if to_update:
try:
- client.tag_resource(ResourceArn=topic_arn,
- Tags=ansible_dict_to_boto3_tag_list(to_update))
+ client.tag_resource(ResourceArn=topic_arn, Tags=ansible_dict_to_boto3_tag_list(to_update))
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Couldn't add tags to topic")
if to_delete:
diff --git a/ansible_collections/community/aws/plugins/module_utils/transitgateway.py b/ansible_collections/community/aws/plugins/module_utils/transitgateway.py
index 3ec198abd..5f0e934d1 100644
--- a/ansible_collections/community/aws/plugins/module_utils/transitgateway.py
+++ b/ansible_collections/community/aws/plugins/module_utils/transitgateway.py
@@ -1,14 +1,13 @@
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
from copy import deepcopy
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_filter_list
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.transformation import ansible_dict_to_boto3_filter_list
from ansible_collections.community.aws.plugins.module_utils.ec2 import BaseEc2Manager
from ansible_collections.community.aws.plugins.module_utils.ec2 import Boto3Mixin
@@ -22,21 +21,43 @@ class TgwWaiterFactory(Ec2WaiterFactory):
# split the TGW waiters so we can keep them close to everything else.
tgw_data = dict(
tgw_attachment_available=dict(
- operation='DescribeTransitGatewayAttachments',
- delay=5, maxAttempts=120,
+ operation="DescribeTransitGatewayAttachments",
+ delay=5,
+ maxAttempts=120,
acceptors=[
- dict(state='success', matcher='pathAll', expected='available', argument='TransitGatewayAttachments[].State'),
- ]
+ dict(
+ state="success",
+ matcher="pathAll",
+ expected="available",
+ argument="TransitGatewayAttachments[].State",
+ ),
+ ],
),
tgw_attachment_deleted=dict(
- operation='DescribeTransitGatewayAttachments',
- delay=5, maxAttempts=120,
+ operation="DescribeTransitGatewayAttachments",
+ delay=5,
+ maxAttempts=120,
acceptors=[
- dict(state='retry', matcher='pathAll', expected='deleting', argument='TransitGatewayAttachments[].State'),
- dict(state='success', matcher='pathAll', expected='deleted', argument='TransitGatewayAttachments[].State'),
- dict(state='success', matcher='path', expected=True, argument='length(TransitGatewayAttachments[]) == `0`'),
- dict(state='success', matcher='error', expected='InvalidRouteTableID.NotFound'),
- ]
+ dict(
+ state="retry",
+ matcher="pathAll",
+ expected="deleting",
+ argument="TransitGatewayAttachments[].State",
+ ),
+ dict(
+ state="success",
+ matcher="pathAll",
+ expected="deleted",
+ argument="TransitGatewayAttachments[].State",
+ ),
+ dict(
+ state="success",
+ matcher="path",
+ expected=True,
+ argument="length(TransitGatewayAttachments[]) == `0`",
+ ),
+ dict(state="success", matcher="error", expected="InvalidRouteTableID.NotFound"),
+ ],
),
)
data.update(tgw_data)
@@ -52,40 +73,40 @@ class TGWAttachmentBoto3Mixin(Boto3Mixin):
# retry - retries the full fetch, but better than simply giving up.
@AWSRetry.jittered_backoff()
def _paginated_describe_transit_gateway_vpc_attachments(self, **params):
- paginator = self.client.get_paginator('describe_transit_gateway_vpc_attachments')
+ paginator = self.client.get_paginator("describe_transit_gateway_vpc_attachments")
return paginator.paginate(**params).build_full_result()
- @Boto3Mixin.aws_error_handler('describe transit gateway attachments')
+ @Boto3Mixin.aws_error_handler("describe transit gateway attachments")
def _describe_vpc_attachments(self, **params):
result = self._paginated_describe_transit_gateway_vpc_attachments(**params)
- return result.get('TransitGatewayVpcAttachments', None)
+ return result.get("TransitGatewayVpcAttachments", None)
- @Boto3Mixin.aws_error_handler('create transit gateway attachment')
+ @Boto3Mixin.aws_error_handler("create transit gateway attachment")
def _create_vpc_attachment(self, **params):
result = self.client.create_transit_gateway_vpc_attachment(aws_retry=True, **params)
- return result.get('TransitGatewayVpcAttachment', None)
+ return result.get("TransitGatewayVpcAttachment", None)
- @Boto3Mixin.aws_error_handler('modify transit gateway attachment')
+ @Boto3Mixin.aws_error_handler("modify transit gateway attachment")
def _modify_vpc_attachment(self, **params):
result = self.client.modify_transit_gateway_vpc_attachment(aws_retry=True, **params)
- return result.get('TransitGatewayVpcAttachment', None)
+ return result.get("TransitGatewayVpcAttachment", None)
- @Boto3Mixin.aws_error_handler('delete transit gateway attachment')
+ @Boto3Mixin.aws_error_handler("delete transit gateway attachment")
def _delete_vpc_attachment(self, **params):
try:
result = self.client.delete_transit_gateway_vpc_attachment(aws_retry=True, **params)
- except is_boto3_error_code('ResourceNotFoundException'):
+ except is_boto3_error_code("ResourceNotFoundException"):
return None
- return result.get('TransitGatewayVpcAttachment', None)
+ return result.get("TransitGatewayVpcAttachment", None)
- @Boto3Mixin.aws_error_handler('transit gateway attachment to finish deleting')
+ @Boto3Mixin.aws_error_handler("transit gateway attachment to finish deleting")
def _wait_tgw_attachment_deleted(self, **params):
- waiter = self.tgw_waiter_factory.get_waiter('tgw_attachment_deleted')
+ waiter = self.tgw_waiter_factory.get_waiter("tgw_attachment_deleted")
waiter.wait(**params)
- @Boto3Mixin.aws_error_handler('transit gateway attachment to become available')
+ @Boto3Mixin.aws_error_handler("transit gateway attachment to become available")
def _wait_tgw_attachment_available(self, **params):
- waiter = self.tgw_waiter_factory.get_waiter('tgw_attachment_available')
+ waiter = self.tgw_waiter_factory.get_waiter("tgw_attachment_available")
waiter.wait(**params)
def _normalize_tgw_attachment(self, rtb):
@@ -104,11 +125,10 @@ class TGWAttachmentBoto3Mixin(Boto3Mixin):
class BaseTGWManager(BaseEc2Manager):
-
- @Boto3Mixin.aws_error_handler('connect to AWS')
- def _create_client(self, client_name='ec2'):
- if client_name == 'ec2':
- error_codes = ['IncorrectState']
+ @Boto3Mixin.aws_error_handler("connect to AWS")
+ def _create_client(self, client_name="ec2"):
+ if client_name == "ec2":
+ error_codes = ["IncorrectState"]
else:
error_codes = []
@@ -120,8 +140,7 @@ class BaseTGWManager(BaseEc2Manager):
class TransitGatewayVpcAttachmentManager(TGWAttachmentBoto3Mixin, BaseTGWManager):
-
- TAG_RESOURCE_TYPE = 'transit-gateway-attachment'
+ TAG_RESOURCE_TYPE = "transit-gateway-attachment"
def __init__(self, module, id=None):
self._subnet_updates = dict()
@@ -132,7 +151,7 @@ class TransitGatewayVpcAttachmentManager(TGWAttachmentBoto3Mixin, BaseTGWManager
id = self.resource_id
if not id:
# Users should never see this, but let's cover ourself
- self.module.fail_json(msg='Attachment identifier parameter missing')
+ self.module.fail_json(msg="Attachment identifier parameter missing")
if id_list:
return dict(TransitGatewayAttachmentIds=[id])
@@ -141,18 +160,18 @@ class TransitGatewayVpcAttachmentManager(TGWAttachmentBoto3Mixin, BaseTGWManager
def _extra_error_output(self):
output = super(TransitGatewayVpcAttachmentManager, self)._extra_error_output()
if self.resource_id:
- output['TransitGatewayAttachmentId'] = self.resource_id
+ output["TransitGatewayAttachmentId"] = self.resource_id
return output
def _filter_immutable_resource_attributes(self, resource):
resource = super(TransitGatewayVpcAttachmentManager, self)._filter_immutable_resource_attributes(resource)
- resource.pop('TransitGatewayId', None)
- resource.pop('VpcId', None)
- resource.pop('VpcOwnerId', None)
- resource.pop('State', None)
- resource.pop('SubnetIds', None)
- resource.pop('CreationTime', None)
- resource.pop('Tags', None)
+ resource.pop("TransitGatewayId", None)
+ resource.pop("VpcId", None)
+ resource.pop("VpcOwnerId", None)
+ resource.pop("State", None)
+ resource.pop("SubnetIds", None)
+ resource.pop("CreationTime", None)
+ resource.pop("Tags", None)
return resource
def _set_option(self, name, value):
@@ -160,36 +179,36 @@ class TransitGatewayVpcAttachmentManager(TGWAttachmentBoto3Mixin, BaseTGWManager
return False
# For now VPC Attachment options are all enable/disable
if value:
- value = 'enable'
+ value = "enable"
else:
- value = 'disable'
+ value = "disable"
- options = deepcopy(self._preupdate_resource.get('Options', dict()))
- options.update(self._resource_updates.get('Options', dict()))
+ options = deepcopy(self._preupdate_resource.get("Options", dict()))
+ options.update(self._resource_updates.get("Options", dict()))
options[name] = value
- return self._set_resource_value('Options', options)
+ return self._set_resource_value("Options", options)
def set_dns_support(self, value):
- return self._set_option('DnsSupport', value)
+ return self._set_option("DnsSupport", value)
def set_ipv6_support(self, value):
- return self._set_option('Ipv6Support', value)
+ return self._set_option("Ipv6Support", value)
def set_appliance_mode_support(self, value):
- return self._set_option('ApplianceModeSupport', value)
+ return self._set_option("ApplianceModeSupport", value)
def set_transit_gateway(self, tgw_id):
- return self._set_resource_value('TransitGatewayId', tgw_id)
+ return self._set_resource_value("TransitGatewayId", tgw_id)
def set_vpc(self, vpc_id):
- return self._set_resource_value('VpcId', vpc_id)
+ return self._set_resource_value("VpcId", vpc_id)
def set_subnets(self, subnets=None, purge=True):
if subnets is None:
return False
- current_subnets = set(self._preupdate_resource.get('SubnetIds', []))
+ current_subnets = set(self._preupdate_resource.get("SubnetIds", []))
desired_subnets = set(subnets)
if not purge:
desired_subnets = desired_subnets.union(current_subnets)
@@ -198,21 +217,23 @@ class TransitGatewayVpcAttachmentManager(TGWAttachmentBoto3Mixin, BaseTGWManager
# information we 'know'.
subnet_details = self._describe_subnets(SubnetIds=list(desired_subnets))
vpc_id = self.subnets_to_vpc(desired_subnets, subnet_details)
- self._set_resource_value('VpcId', vpc_id, immutable=True)
+ self._set_resource_value("VpcId", vpc_id, immutable=True)
# Only one subnet per-AZ is permitted
- azs = [s.get('AvailabilityZoneId') for s in subnet_details]
+ azs = [s.get("AvailabilityZoneId") for s in subnet_details]
if len(azs) != len(set(azs)):
self.module.fail_json(
- msg='Only one attachment subnet per availability zone may be set.',
- availability_zones=azs, subnets=subnet_details)
+ msg="Only one attachment subnet per availability zone may be set.",
+ availability_zones=azs,
+ subnets=subnet_details,
+ )
subnets_to_add = list(desired_subnets.difference(current_subnets))
subnets_to_remove = list(current_subnets.difference(desired_subnets))
if not subnets_to_remove and not subnets_to_add:
return False
self._subnet_updates = dict(add=subnets_to_add, remove=subnets_to_remove)
- self._set_resource_value('SubnetIds', list(desired_subnets))
+ self._set_resource_value("SubnetIds", list(desired_subnets))
return True
def subnets_to_vpc(self, subnets, subnet_details=None):
@@ -222,11 +243,13 @@ class TransitGatewayVpcAttachmentManager(TGWAttachmentBoto3Mixin, BaseTGWManager
if subnet_details is None:
subnet_details = self._describe_subnets(SubnetIds=list(subnets))
- vpcs = [s.get('VpcId') for s in subnet_details]
+ vpcs = [s.get("VpcId") for s in subnet_details]
if len(set(vpcs)) > 1:
self.module.fail_json(
- msg='Attachment subnets may only be in one VPC, multiple VPCs found',
- vpcs=list(set(vpcs)), subnets=subnet_details)
+ msg="Attachment subnets may only be in one VPC, multiple VPCs found",
+ vpcs=list(set(vpcs)),
+ subnets=subnet_details,
+ )
return vpcs[0]
@@ -249,26 +272,25 @@ class TransitGatewayVpcAttachmentManager(TGWAttachmentBoto3Mixin, BaseTGWManager
params = self._merge_resource_changes(filter_immutable=False, creation=True)
response = self._create_vpc_attachment(**params)
if response:
- self.resource_id = response.get('TransitGatewayAttachmentId', None)
+ self.resource_id = response.get("TransitGatewayAttachmentId", None)
return response
def _do_update_resource(self):
- if self._preupdate_resource.get('State', None) == 'pending':
+ if self._preupdate_resource.get("State", None) == "pending":
# Resources generally don't like it if you try to update before creation
# is complete. If things are in a 'pending' state they'll often throw
# exceptions.
self._wait_for_creation()
- elif self._preupdate_resource.get('State', None) == 'deleting':
- self.module.fail_json(msg='Deletion in progress, unable to update',
- route_tables=[self.original_resource])
+ elif self._preupdate_resource.get("State", None) == "deleting":
+ self.module.fail_json(msg="Deletion in progress, unable to update", route_tables=[self.original_resource])
updates = self._filter_immutable_resource_attributes(self._resource_updates)
- subnets_to_add = self._subnet_updates.get('add', [])
- subnets_to_remove = self._subnet_updates.get('remove', [])
+ subnets_to_add = self._subnet_updates.get("add", [])
+ subnets_to_remove = self._subnet_updates.get("remove", [])
if subnets_to_add:
- updates['AddSubnetIds'] = subnets_to_add
+ updates["AddSubnetIds"] = subnets_to_add
if subnets_to_remove:
- updates['RemoveSubnetIds'] = subnets_to_remove
+ updates["RemoveSubnetIds"] = subnets_to_remove
if not updates:
return False
@@ -284,7 +306,6 @@ class TransitGatewayVpcAttachmentManager(TGWAttachmentBoto3Mixin, BaseTGWManager
return self.get_attachment()
def delete(self, id=None):
-
if id:
id_params = self._get_id_params(id=id, id_list=True)
result = self._get_tgw_vpc_attachment(**id_params)
@@ -296,7 +317,7 @@ class TransitGatewayVpcAttachmentManager(TGWAttachmentBoto3Mixin, BaseTGWManager
if not result:
return False
- if result.get('State') == 'deleting':
+ if result.get("State") == "deleting":
self._wait_for_deletion()
return False
@@ -316,9 +337,9 @@ class TransitGatewayVpcAttachmentManager(TGWAttachmentBoto3Mixin, BaseTGWManager
def list(self, filters=None, id=None):
params = dict()
if id:
- params['TransitGatewayAttachmentIds'] = [id]
+ params["TransitGatewayAttachmentIds"] = [id]
if filters:
- params['Filters'] = ansible_dict_to_boto3_filter_list(filters)
+ params["Filters"] = ansible_dict_to_boto3_filter_list(filters)
attachments = self._describe_vpc_attachments(**params)
if not attachments:
return list()
@@ -326,7 +347,6 @@ class TransitGatewayVpcAttachmentManager(TGWAttachmentBoto3Mixin, BaseTGWManager
return [self._normalize_tgw_attachment(a) for a in attachments]
def get_attachment(self, id=None):
-
# RouteTable needs a list, Association/Propagation needs a single ID
id_params = self._get_id_params(id=id, id_list=True)
id_param = self._get_id_params(id=id, id_list=False)
diff --git a/ansible_collections/community/aws/plugins/module_utils/wafv2.py b/ansible_collections/community/aws/plugins/module_utils/wafv2.py
index 18f19974d..c0eb363ef 100644
--- a/ansible_collections/community/aws/plugins/module_utils/wafv2.py
+++ b/ansible_collections/community/aws/plugins/module_utils/wafv2.py
@@ -1,12 +1,15 @@
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
+# -*- coding: utf-8 -*-
+
+# Copyright: Contributors to the Ansible project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
try:
- from botocore.exceptions import ClientError, BotoCoreError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
except ImportError:
pass # caught by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
from ansible_collections.amazon.aws.plugins.module_utils.tagging import ansible_dict_to_boto3_tag_list
from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
from ansible_collections.amazon.aws.plugins.module_utils.tagging import compare_aws_tags
@@ -16,7 +19,7 @@ from ansible_collections.amazon.aws.plugins.module_utils.tagging import compare_
def _list_tags(wafv2, arn, fail_json_aws, next_marker=None):
params = dict(ResourceARN=arn)
if next_marker:
- params['NextMarker'] = next_marker
+ params["NextMarker"] = next_marker
try:
return wafv2.list_tags_for_resource(**params)
except (BotoCoreError, ClientError) as e:
@@ -29,9 +32,9 @@ def describe_wafv2_tags(wafv2, arn, fail_json_aws):
# there is currently no paginator for wafv2
while True:
responce = _list_tags(wafv2, arn, fail_json_aws)
- next_marker = responce.get('NextMarker', None)
- tag_info = responce.get('TagInfoForResource', {})
- tag_list.extend(tag_info.get('TagList', []))
+ next_marker = responce.get("NextMarker", None)
+ tag_info = responce.get("TagInfoForResource", {})
+ tag_list.extend(tag_info.get("TagList", []))
if not next_marker:
break
return boto3_tag_list_to_ansible_dict(tag_list)
@@ -66,39 +69,37 @@ def ensure_wafv2_tags(wafv2, arn, tags, purge_tags, fail_json_aws, check_mode):
def wafv2_list_web_acls(wafv2, scope, fail_json_aws, nextmarker=None):
# there is currently no paginator for wafv2
- req_obj = {
- 'Scope': scope,
- 'Limit': 100
- }
+ req_obj = {"Scope": scope, "Limit": 100}
if nextmarker:
- req_obj['NextMarker'] = nextmarker
+ req_obj["NextMarker"] = nextmarker
try:
response = wafv2.list_web_acls(**req_obj)
except (BotoCoreError, ClientError) as e:
fail_json_aws(e, msg="Failed to list wafv2 web acl")
- if response.get('NextMarker'):
- response['WebACLs'] += wafv2_list_web_acls(wafv2, scope, fail_json_aws, nextmarker=response.get('NextMarker')).get('WebACLs')
+ if response.get("NextMarker"):
+ response["WebACLs"] += wafv2_list_web_acls(
+ wafv2, scope, fail_json_aws, nextmarker=response.get("NextMarker")
+ ).get("WebACLs")
return response
def wafv2_list_rule_groups(wafv2, scope, fail_json_aws, nextmarker=None):
# there is currently no paginator for wafv2
- req_obj = {
- 'Scope': scope,
- 'Limit': 100
- }
+ req_obj = {"Scope": scope, "Limit": 100}
if nextmarker:
- req_obj['NextMarker'] = nextmarker
+ req_obj["NextMarker"] = nextmarker
try:
response = wafv2.list_rule_groups(**req_obj)
except (BotoCoreError, ClientError) as e:
fail_json_aws(e, msg="Failed to list wafv2 rule group")
- if response.get('NextMarker'):
- response['RuleGroups'] += wafv2_list_rule_groups(wafv2, scope, fail_json_aws, nextmarker=response.get('NextMarker')).get('RuleGroups')
+ if response.get("NextMarker"):
+ response["RuleGroups"] += wafv2_list_rule_groups(
+ wafv2, scope, fail_json_aws, nextmarker=response.get("NextMarker")
+ ).get("RuleGroups")
return response
@@ -109,20 +110,20 @@ def wafv2_snake_dict_to_camel_dict(a):
retval = {}
for item in a.keys():
if isinstance(a.get(item), dict):
- if 'Ip' in item:
- retval[item.replace('Ip', 'IP')] = wafv2_snake_dict_to_camel_dict(a.get(item))
- elif 'Arn' == item:
- retval['ARN'] = wafv2_snake_dict_to_camel_dict(a.get(item))
+ if "Ip" in item:
+ retval[item.replace("Ip", "IP")] = wafv2_snake_dict_to_camel_dict(a.get(item))
+ elif "Arn" == item:
+ retval["ARN"] = wafv2_snake_dict_to_camel_dict(a.get(item))
else:
retval[item] = wafv2_snake_dict_to_camel_dict(a.get(item))
elif isinstance(a.get(item), list):
retval[item] = []
for idx in range(len(a.get(item))):
retval[item].append(wafv2_snake_dict_to_camel_dict(a.get(item)[idx]))
- elif 'Ip' in item:
- retval[item.replace('Ip', 'IP')] = a.get(item)
- elif 'Arn' == item:
- retval['ARN'] = a.get(item)
+ elif "Ip" in item:
+ retval[item.replace("Ip", "IP")] = a.get(item)
+ elif "Arn" == item:
+ retval["ARN"] = a.get(item)
else:
retval[item] = a.get(item)
return retval
@@ -135,24 +136,31 @@ def nested_byte_values_to_strings(rule, keyname):
- AndStatement
- NotStatement
"""
- if rule.get('Statement', {}).get(keyname):
- for idx in range(len(rule.get('Statement', {}).get(keyname, {}).get('Statements'))):
- if rule['Statement'][keyname]['Statements'][idx].get('ByteMatchStatement'):
- rule['Statement'][keyname]['Statements'][idx]['ByteMatchStatement']['SearchString'] = \
- rule.get('Statement').get(keyname).get('Statements')[idx].get('ByteMatchStatement').get('SearchString').decode('utf-8')
+ if rule.get("Statement", {}).get(keyname):
+ for idx in range(len(rule.get("Statement", {}).get(keyname, {}).get("Statements"))):
+ if rule["Statement"][keyname]["Statements"][idx].get("ByteMatchStatement"):
+ rule["Statement"][keyname]["Statements"][idx]["ByteMatchStatement"]["SearchString"] = (
+ rule.get("Statement")
+ .get(keyname)
+ .get("Statements")[idx]
+ .get("ByteMatchStatement")
+ .get("SearchString")
+ .decode("utf-8")
+ )
return rule
def byte_values_to_strings_before_compare(rules):
for idx in range(len(rules)):
- if rules[idx].get('Statement', {}).get('ByteMatchStatement', {}).get('SearchString'):
- rules[idx]['Statement']['ByteMatchStatement']['SearchString'] = \
- rules[idx].get('Statement').get('ByteMatchStatement').get('SearchString').decode('utf-8')
+ if rules[idx].get("Statement", {}).get("ByteMatchStatement", {}).get("SearchString"):
+ rules[idx]["Statement"]["ByteMatchStatement"]["SearchString"] = (
+ rules[idx].get("Statement").get("ByteMatchStatement").get("SearchString").decode("utf-8")
+ )
else:
- for statement in ['AndStatement', 'OrStatement', 'NotStatement']:
- if rules[idx].get('Statement', {}).get(statement):
+ for statement in ["AndStatement", "OrStatement", "NotStatement"]:
+ if rules[idx].get("Statement", {}).get(statement):
rules[idx] = nested_byte_values_to_strings(rules[idx], statement)
return rules
@@ -160,11 +168,11 @@ def byte_values_to_strings_before_compare(rules):
def compare_priority_rules(existing_rules, requested_rules, purge_rules, state):
diff = False
- existing_rules = sorted(existing_rules, key=lambda k: k['Priority'])
+ existing_rules = sorted(existing_rules, key=lambda k: k["Priority"])
existing_rules = byte_values_to_strings_before_compare(existing_rules)
- requested_rules = sorted(requested_rules, key=lambda k: k['Priority'])
+ requested_rules = sorted(requested_rules, key=lambda k: k["Priority"])
- if purge_rules and state == 'present':
+ if purge_rules and state == "present":
merged_rules = requested_rules
if len(existing_rules) == len(requested_rules):
for idx in range(len(existing_rules)):
@@ -182,8 +190,8 @@ def compare_priority_rules(existing_rules, requested_rules, purge_rules, state):
ex_idx_pop = []
for existing_idx in range(len(existing_rules)):
for requested_idx in range(len(requested_rules)):
- if existing_rules[existing_idx].get('Priority') == requested_rules[requested_idx].get('Priority'):
- if state == 'present':
+ if existing_rules[existing_idx].get("Priority") == requested_rules[requested_idx].get("Priority"):
+ if state == "present":
ex_idx_pop.append(existing_idx)
if existing_rules[existing_idx] != requested_rules[requested_idx]:
diff = True
@@ -195,7 +203,7 @@ def compare_priority_rules(existing_rules, requested_rules, purge_rules, state):
for idx in ex_idx_pop:
existing_rules.pop(idx)
- if state == 'present':
+ if state == "present":
merged_rules = existing_rules + requested_rules
if len(merged_rules) != prev_count:
diff --git a/ansible_collections/community/aws/plugins/modules/accessanalyzer_validate_policy_info.py b/ansible_collections/community/aws/plugins/modules/accessanalyzer_validate_policy_info.py
index e589d0cb0..fab777175 100644
--- a/ansible_collections/community/aws/plugins/modules/accessanalyzer_validate_policy_info.py
+++ b/ansible_collections/community/aws/plugins/modules/accessanalyzer_validate_policy_info.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: accessanalyzer_validate_policy_info
version_added: 5.0.0
@@ -63,19 +61,19 @@ options:
author:
- Mark Chappell (@tremble)
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
# Validate a policy
- name: Validate a simple IAM policy
community.aws.accessanalyzer_validate_policy_info:
policy: "{{ lookup('template', 'managed_policy.json.j2') }}"
-'''
+"""
-RETURN = r'''
+RETURN = r"""
findings:
description: The list of findings in a policy returned by IAM Access Analyzer based on its suite of policy checks.
returned: success
@@ -160,7 +158,7 @@ findings:
description: The offset within the policy that corresponds to the position, starting from C(0).
type: int
returned: success
-'''
+"""
try:
import botocore
@@ -169,8 +167,9 @@ except ImportError:
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def filter_findings(findings, type_filter):
@@ -178,11 +177,10 @@ def filter_findings(findings, type_filter):
return findings
# Convert type_filter to the findingType strings returned by the API
- filter_map = dict(error='ERROR', security='SECURITY_WARNING',
- suggestion='SUGGESTION', warning='WARNING')
+ filter_map = dict(error="ERROR", security="SECURITY_WARNING", suggestion="SUGGESTION", warning="WARNING")
allowed_types = [filter_map[t] for t in type_filter]
- filtered_results = [f for f in findings if f.get('findingType', None) in allowed_types]
+ filtered_results = [f for f in findings if f.get("findingType", None) in allowed_types]
return filtered_results
@@ -191,47 +189,47 @@ def main():
# values are likely to be expanded, let's avoid hard coding limits which might not hold true in
# the long term...
argument_spec = dict(
- policy=dict(required=True, type='json', aliases=['policy_document']),
- locale=dict(required=False, type='str', default='EN'),
- policy_type=dict(required=False, type='str', default='identity',
- choices=['identity', 'resource', 'service_control']),
- resource_type=dict(required=False, type='str'),
- results_filter=dict(required=False, type='list', elements='str',
- choices=['error', 'security', 'suggestion', 'warning']),
+ policy=dict(required=True, type="json", aliases=["policy_document"]),
+ locale=dict(required=False, type="str", default="EN"),
+ policy_type=dict(
+ required=False, type="str", default="identity", choices=["identity", "resource", "service_control"]
+ ),
+ resource_type=dict(required=False, type="str"),
+ results_filter=dict(
+ required=False, type="list", elements="str", choices=["error", "security", "suggestion", "warning"]
+ ),
)
- module = AnsibleAWSModule(
- argument_spec=argument_spec,
- supports_check_mode=True
- )
+ module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
- policy_type_map = dict(identity='IDENTITY_POLICY', resource='RESOURCE_POLICY',
- service_control='SERVICE_CONTROL_POLICY')
+ policy_type_map = dict(
+ identity="IDENTITY_POLICY", resource="RESOURCE_POLICY", service_control="SERVICE_CONTROL_POLICY"
+ )
- policy = module.params.get('policy')
- policy_type = policy_type_map[module.params.get('policy_type')]
- locale = module.params.get('locale').upper()
- resource_type = module.params.get('resource_type')
- results_filter = module.params.get('results_filter')
+ policy = module.params.get("policy")
+ policy_type = policy_type_map[module.params.get("policy_type")]
+ locale = module.params.get("locale").upper()
+ resource_type = module.params.get("resource_type")
+ results_filter = module.params.get("results_filter")
try:
- client = module.client('accessanalyzer', retry_decorator=AWSRetry.jittered_backoff())
+ client = module.client("accessanalyzer", retry_decorator=AWSRetry.jittered_backoff())
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to connect to AWS')
+ module.fail_json_aws(e, msg="Failed to connect to AWS")
params = dict(locale=locale, policyDocument=policy, policyType=policy_type)
- if policy_type == 'RESOURCE_POLICY' and resource_type:
- params['policyType'] = resource_type
+ if policy_type == "RESOURCE_POLICY" and resource_type:
+ params["policyType"] = resource_type
results = client.validate_policy(aws_retry=True, **params)
- findings = filter_findings(results.get('findings', []), results_filter)
- results['findings'] = findings
+ findings = filter_findings(results.get("findings", []), results_filter)
+ results["findings"] = findings
results = camel_dict_to_snake_dict(results)
module.exit_json(changed=False, **results)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/acm_certificate.py b/ansible_collections/community/aws/plugins/modules/acm_certificate.py
index abdecadcc..0b4f7037a 100644
--- a/ansible_collections/community/aws/plugins/modules/acm_certificate.py
+++ b/ansible_collections/community/aws/plugins/modules/acm_certificate.py
@@ -1,31 +1,14 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
-#
+
# Copyright (c) 2019 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-#
-# This module is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This software is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this software. If not, see <http://www.gnu.org/licenses/>.
-#
+
# Author:
# - Matthew Davis <Matthew.Davis.2@team.telstra.com>
# on behalf of Telstra Corporation Limited
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: acm_certificate
short_description: Upload and delete certificates in the AWS Certificate Manager service
@@ -175,23 +158,23 @@ notes:
author:
- Matthew Davis (@matt-telstra) on behalf of Telstra Corporation Limited
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
- - amazon.aws.boto3
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.tags
-'''
+ - amazon.aws.boto3
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
- name: upload a self-signed certificate
- community.aws.aws_acm:
+ community.aws.acm_certificate:
certificate: "{{ lookup('file', 'cert.pem' ) }}"
privateKey: "{{ lookup('file', 'key.pem' ) }}"
name_tag: my_cert # to be applied through an AWS tag as "Name":"my_cert"
region: ap-southeast-2 # AWS region
- name: create/update a certificate with a chain
- community.aws.aws_acm:
+ community.aws.acm_certificate:
certificate: "{{ lookup('file', 'cert.pem' ) }}"
private_key: "{{ lookup('file', 'key.pem' ) }}"
name_tag: my_cert
@@ -205,34 +188,34 @@ EXAMPLES = '''
var: cert_create.certificate.arn
- name: delete the cert we just created
- community.aws.aws_acm:
+ community.aws.acm_certificate:
name_tag: my_cert
state: absent
region: ap-southeast-2
- name: delete a certificate with a particular ARN
- community.aws.aws_acm:
+ community.aws.acm_certificate:
certificate_arn: "arn:aws:acm:ap-southeast-2:123456789012:certificate/01234567-abcd-abcd-abcd-012345678901"
state: absent
region: ap-southeast-2
- name: delete all certificates with a particular domain name
- community.aws.aws_acm:
+ community.aws.acm_certificate:
domain_name: acm.ansible.com
state: absent
region: ap-southeast-2
- name: add tags to an existing certificate with a particular ARN
- community.aws.aws_acm:
+ community.aws.acm_certificate:
certificate_arn: "arn:aws:acm:ap-southeast-2:123456789012:certificate/01234567-abcd-abcd-abcd-012345678901"
tags:
Name: my_certificate
Application: search
Environment: development
purge_tags: true
-'''
+"""
-RETURN = '''
+RETURN = r"""
certificate:
description: Information about the certificate which was uploaded
type: complex
@@ -255,27 +238,27 @@ arns:
returned: when I(state=absent)
sample:
- "arn:aws:acm:ap-southeast-2:123456789012:certificate/01234567-abcd-abcd-abcd-012345678901"
-'''
+"""
import base64
-from copy import deepcopy
import re # regex library
+from copy import deepcopy
try:
import botocore
except ImportError:
pass # handled by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.acm import ACMServiceManager
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import compare_aws_tags
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import (
- boto3_tag_list_to_ansible_dict,
- ansible_dict_to_boto3_tag_list,
-)
from ansible.module_utils._text import to_text
+from ansible_collections.amazon.aws.plugins.module_utils.acm import ACMServiceManager
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import ansible_dict_to_boto3_tag_list
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import compare_aws_tags
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
+
def ensure_tags(client, module, resource_arn, existing_tags, tags, purge_tags):
if tags is None:
@@ -293,12 +276,10 @@ def ensure_tags(client, module, resource_arn, existing_tags, tags, purge_tags):
botocore.exceptions.ClientError,
botocore.exceptions.BotoCoreError,
) as e:
- module.fail_json_aws(
- e, "Couldn't add tags to certificate {0}".format(resource_arn)
- )
+ module.fail_json_aws(e, f"Couldn't add tags to certificate {resource_arn}")
if tags_to_remove and not module.check_mode:
# remove_tags_from_certificate wants a list of key, value pairs, not a list of keys.
- tags_list = [{'Key': key, 'Value': existing_tags.get(key)} for key in tags_to_remove]
+ tags_list = [{"Key": key, "Value": existing_tags.get(key)} for key in tags_to_remove]
try:
client.remove_tags_from_certificate(
CertificateArn=resource_arn,
@@ -308,9 +289,7 @@ def ensure_tags(client, module, resource_arn, existing_tags, tags, purge_tags):
botocore.exceptions.ClientError,
botocore.exceptions.BotoCoreError,
) as e:
- module.fail_json_aws(
- e, "Couldn't remove tags from certificate {0}".format(resource_arn)
- )
+ module.fail_json_aws(e, f"Couldn't remove tags from certificate {resource_arn}")
new_tags = deepcopy(existing_tags)
for key, value in tags_to_add.items():
new_tags[key] = value
@@ -325,7 +304,6 @@ def ensure_tags(client, module, resource_arn, existing_tags, tags, purge_tags):
# May include some lines between each chain in the cert, e.g. "Subject: ..."
# Returns True iff the chains/certs are functionally identical (including chain order)
def chain_compare(module, a, b):
-
chain_a_pem = pem_chain_split(module, a)
chain_b_pem = pem_chain_split(module, b)
@@ -333,7 +311,7 @@ def chain_compare(module, a, b):
return False
# Chain length is the same
- for (ca, cb) in zip(chain_a_pem, chain_b_pem):
+ for ca, cb in zip(chain_a_pem, chain_b_pem):
der_a = PEM_body_to_DER(module, ca)
der_b = PEM_body_to_DER(module, cb)
if der_a != der_b:
@@ -353,7 +331,9 @@ def PEM_body_to_DER(module, pem):
# Store this globally to avoid repeated recompilation
-pem_chain_split_regex = re.compile(r"------?BEGIN [A-Z0-9. ]*CERTIFICATE------?([a-zA-Z0-9\+\/=\s]+)------?END [A-Z0-9. ]*CERTIFICATE------?")
+pem_chain_split_regex = re.compile(
+ r"------?BEGIN [A-Z0-9. ]*CERTIFICATE------?([a-zA-Z0-9\+\/=\s]+)------?END [A-Z0-9. ]*CERTIFICATE------?"
+)
# Use regex to split up a chain or single cert into an array of base64 encoded data
@@ -361,7 +341,6 @@ pem_chain_split_regex = re.compile(r"------?BEGIN [A-Z0-9. ]*CERTIFICATE------?(
# Noting that some chains have non-pem data in between each cert
# This function returns only what's between the headers, excluding the headers
def pem_chain_split(module, pem):
-
pem_arr = re.findall(pem_chain_split_regex, to_text(pem))
if len(pem_arr) == 0:
@@ -376,53 +355,55 @@ def update_imported_certificate(client, module, acm, old_cert, desired_tags):
Update the existing certificate that was previously imported in ACM.
"""
module.debug("Existing certificate found in ACM")
- if ('tags' not in old_cert) or ('Name' not in old_cert['tags']):
+ if ("tags" not in old_cert) or ("Name" not in old_cert["tags"]):
# shouldn't happen
module.fail_json(msg="Internal error, unsure which certificate to update", certificate=old_cert)
- if module.params.get('name_tag') is not None and (old_cert['tags']['Name'] != module.params.get('name_tag')):
+ if module.params.get("name_tag") is not None and (old_cert["tags"]["Name"] != module.params.get("name_tag")):
# This could happen if the user identified the certificate using 'certificate_arn' or 'domain_name',
# and the 'Name' tag in the AWS API does not match the ansible 'name_tag'.
module.fail_json(msg="Internal error, Name tag does not match", certificate=old_cert)
- if 'certificate' not in old_cert:
+ if "certificate" not in old_cert:
# shouldn't happen
module.fail_json(msg="Internal error, unsure what the existing cert in ACM is", certificate=old_cert)
cert_arn = None
# Are the existing certificate in ACM and the local certificate the same?
same = True
- if module.params.get('certificate') is not None:
- same &= chain_compare(module, old_cert['certificate'], module.params['certificate'])
- if module.params['certificate_chain']:
+ if module.params.get("certificate") is not None:
+ same &= chain_compare(module, old_cert["certificate"], module.params["certificate"])
+ if module.params["certificate_chain"]:
# Need to test this
# not sure if Amazon appends the cert itself to the chain when self-signed
- same &= chain_compare(module, old_cert['certificate_chain'], module.params['certificate_chain'])
+ same &= chain_compare(module, old_cert["certificate_chain"], module.params["certificate_chain"])
else:
# When there is no chain with a cert
# it seems Amazon returns the cert itself as the chain
- same &= chain_compare(module, old_cert['certificate_chain'], module.params['certificate'])
+ same &= chain_compare(module, old_cert["certificate_chain"], module.params["certificate"])
if same:
module.debug("Existing certificate in ACM is the same")
- cert_arn = old_cert['certificate_arn']
+ cert_arn = old_cert["certificate_arn"]
changed = False
else:
- absent_args = ['certificate', 'name_tag', 'private_key']
+ absent_args = ["certificate", "name_tag", "private_key"]
if sum([(module.params[a] is not None) for a in absent_args]) < 3:
- module.fail_json(msg="When importing a certificate, all of 'name_tag', 'certificate' and 'private_key' must be specified")
+ module.fail_json(
+ msg="When importing a certificate, all of 'name_tag', 'certificate' and 'private_key' must be specified"
+ )
module.debug("Existing certificate in ACM is different, overwriting")
changed = True
if module.check_mode:
- cert_arn = old_cert['certificate_arn']
+ cert_arn = old_cert["certificate_arn"]
# note: returned domain will be the domain of the previous cert
else:
# update cert in ACM
cert_arn = acm.import_certificate(
client,
module,
- certificate=module.params['certificate'],
- private_key=module.params['private_key'],
- certificate_chain=module.params['certificate_chain'],
- arn=old_cert['certificate_arn'],
+ certificate=module.params["certificate"],
+ private_key=module.params["private_key"],
+ certificate_chain=module.params["certificate_chain"],
+ arn=old_cert["certificate_arn"],
tags=desired_tags,
)
return (changed, cert_arn)
@@ -433,22 +414,24 @@ def import_certificate(client, module, acm, desired_tags):
Import a certificate to ACM.
"""
# Validate argument requirements
- absent_args = ['certificate', 'name_tag', 'private_key']
+ absent_args = ["certificate", "name_tag", "private_key"]
cert_arn = None
if sum([(module.params[a] is not None) for a in absent_args]) < 3:
- module.fail_json(msg="When importing a new certificate, all of 'name_tag', 'certificate' and 'private_key' must be specified")
+ module.fail_json(
+ msg="When importing a new certificate, all of 'name_tag', 'certificate' and 'private_key' must be specified"
+ )
module.debug("No certificate in ACM. Creating new one.")
changed = True
if module.check_mode:
- domain = 'example.com'
+ domain = "example.com"
module.exit_json(certificate=dict(domain_name=domain), changed=True)
else:
cert_arn = acm.import_certificate(
client,
module,
- certificate=module.params['certificate'],
- private_key=module.params['private_key'],
- certificate_chain=module.params['certificate_chain'],
+ certificate=module.params["certificate"],
+ private_key=module.params["private_key"],
+ certificate_chain=module.params["certificate_chain"],
tags=desired_tags,
)
return (changed, cert_arn)
@@ -458,7 +441,7 @@ def ensure_certificates_present(client, module, acm, certificates, desired_tags,
cert_arn = None
changed = False
if len(certificates) > 1:
- msg = "More than one certificate with Name=%s exists in ACM in this region" % module.params['name_tag']
+ msg = f"More than one certificate with Name={module.params['name_tag']} exists in ACM in this region"
module.fail_json(msg=msg, certificates=certificates)
elif len(certificates) == 1:
# Update existing certificate that was previously imported to ACM.
@@ -469,11 +452,13 @@ def ensure_certificates_present(client, module, acm, certificates, desired_tags,
# Add/remove tags to/from certificate
try:
- existing_tags = boto3_tag_list_to_ansible_dict(client.list_tags_for_certificate(CertificateArn=cert_arn)['Tags'])
+ existing_tags = boto3_tag_list_to_ansible_dict(
+ client.list_tags_for_certificate(CertificateArn=cert_arn)["Tags"]
+ )
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, "Couldn't get tags for certificate")
- purge_tags = module.params.get('purge_tags')
+ purge_tags = module.params.get("purge_tags")
(c, new_tags) = ensure_tags(client, module, cert_arn, existing_tags, desired_tags, purge_tags)
changed |= c
domain = acm.get_domain_of_cert(client=client, module=module, arn=cert_arn)
@@ -483,21 +468,21 @@ def ensure_certificates_present(client, module, acm, certificates, desired_tags,
def ensure_certificates_absent(client, module, acm, certificates):
for cert in certificates:
if not module.check_mode:
- acm.delete_certificate(client, module, cert['certificate_arn'])
- module.exit_json(arns=[cert['certificate_arn'] for cert in certificates], changed=(len(certificates) > 0))
+ acm.delete_certificate(client, module, cert["certificate_arn"])
+ module.exit_json(arns=[cert["certificate_arn"] for cert in certificates], changed=(len(certificates) > 0))
def main():
argument_spec = dict(
certificate=dict(),
- certificate_arn=dict(aliases=['arn']),
+ certificate_arn=dict(aliases=["arn"]),
certificate_chain=dict(),
- domain_name=dict(aliases=['domain']),
- name_tag=dict(aliases=['name']),
+ domain_name=dict(aliases=["domain"]),
+ name_tag=dict(aliases=["name"]),
private_key=dict(no_log=True),
- tags=dict(type='dict', aliases=['resource_tags']),
- purge_tags=dict(type='bool', default=True),
- state=dict(default='present', choices=['present', 'absent']),
+ tags=dict(type="dict", aliases=["resource_tags"]),
+ purge_tags=dict(type="bool", default=True),
+ state=dict(default="present", choices=["present", "absent"]),
)
module = AnsibleAWSModule(
argument_spec=argument_spec,
@@ -506,62 +491,66 @@ def main():
acm = ACMServiceManager(module)
# Check argument requirements
- if module.params['state'] == 'present':
+ if module.params["state"] == "present":
# at least one of these should be specified.
- absent_args = ['certificate_arn', 'domain_name', 'name_tag']
+ absent_args = ["certificate_arn", "domain_name", "name_tag"]
if sum([(module.params[a] is not None) for a in absent_args]) < 1:
for a in absent_args:
- module.debug("%s is %s" % (a, module.params[a]))
- module.fail_json(msg="If 'state' is specified as 'present' then at least one of 'name_tag', 'certificate_arn' or 'domain_name' must be specified")
+ module.debug(f"{a} is {module.params[a]}")
+ module.fail_json(
+ msg="If 'state' is specified as 'present' then at least one of 'name_tag', 'certificate_arn' or 'domain_name' must be specified"
+ )
else: # absent
# exactly one of these should be specified
- absent_args = ['certificate_arn', 'domain_name', 'name_tag']
+ absent_args = ["certificate_arn", "domain_name", "name_tag"]
if sum([(module.params[a] is not None) for a in absent_args]) != 1:
for a in absent_args:
- module.debug("%s is %s" % (a, module.params[a]))
- module.fail_json(msg="If 'state' is specified as 'absent' then exactly one of 'name_tag', 'certificate_arn' or 'domain_name' must be specified")
+ module.debug(f"{a} is {module.params[a]}")
+ module.fail_json(
+ msg="If 'state' is specified as 'absent' then exactly one of 'name_tag', 'certificate_arn' or 'domain_name' must be specified"
+ )
filter_tags = None
desired_tags = None
- if module.params.get('tags') is not None:
- desired_tags = module.params['tags']
+ if module.params.get("tags") is not None:
+ desired_tags = module.params["tags"]
else:
# Because we're setting the Name tag, we need to explicitly not purge when tags isn't passed
- module.params['purge_tags'] = False
- if module.params.get('name_tag') is not None:
+ module.params["purge_tags"] = False
+ if module.params.get("name_tag") is not None:
# The module was originally implemented to filter certificates based on the 'Name' tag.
# Other tags are not used to filter certificates.
# It would make sense to replace the existing name_tag, domain, certificate_arn attributes
# with a 'filter' attribute, but that would break backwards-compatibility.
- filter_tags = dict(Name=module.params['name_tag'])
+ filter_tags = dict(Name=module.params["name_tag"])
if desired_tags is not None:
- if 'Name' in desired_tags:
- if desired_tags['Name'] != module.params['name_tag']:
+ if "Name" in desired_tags:
+ if desired_tags["Name"] != module.params["name_tag"]:
module.fail_json(msg="Value of 'name_tag' conflicts with value of 'tags.Name'")
else:
- desired_tags['Name'] = module.params['name_tag']
+ desired_tags["Name"] = module.params["name_tag"]
else:
desired_tags = deepcopy(filter_tags)
- client = module.client('acm')
+ client = module.client("acm")
# fetch the list of certificates currently in ACM
certificates = acm.get_certificates(
client=client,
module=module,
- domain_name=module.params['domain_name'],
- arn=module.params['certificate_arn'],
+ domain_name=module.params["domain_name"],
+ arn=module.params["certificate_arn"],
only_tags=filter_tags,
)
- module.debug("Found %d corresponding certificates in ACM" % len(certificates))
- if module.params['state'] == 'present':
+ module.debug(f"Found {len(certificates)} corresponding certificates in ACM")
+ if module.params["state"] == "present":
ensure_certificates_present(client, module, acm, certificates, desired_tags, filter_tags)
else: # state == absent
ensure_certificates_absent(client, module, acm, certificates)
-if __name__ == '__main__':
+if __name__ == "__main__":
# tests()
main()
diff --git a/ansible_collections/community/aws/plugins/modules/acm_certificate_info.py b/ansible_collections/community/aws/plugins/modules/acm_certificate_info.py
index a84d7c0b0..73da208f1 100644
--- a/ansible_collections/community/aws/plugins/modules/acm_certificate_info.py
+++ b/ansible_collections/community/aws/plugins/modules/acm_certificate_info.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
module: acm_certificate_info
short_description: Retrieve certificate information from AWS Certificate Manager service
version_added: 1.0.0
@@ -43,26 +41,26 @@ options:
author:
- Will Thames (@willthames)
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
- name: obtain all ACM certificates
- community.aws.aws_acm_info:
+ community.aws.acm_certificate_info:
- name: obtain all information for a single ACM certificate
- community.aws.aws_acm_info:
+ community.aws.acm_certificate_info:
domain_name: "*.example_com"
- name: obtain all certificates pending validation
- community.aws.aws_acm_info:
+ community.aws.acm_certificate_info:
statuses:
- - PENDING_VALIDATION
+ - PENDING_VALIDATION
- name: obtain all certificates with tag Name=foo and myTag=bar
- community.aws.aws_acm_info:
+ community.aws.acm_certificate_info:
tags:
Name: foo
myTag: bar
@@ -70,12 +68,11 @@ EXAMPLES = r'''
# The output is still a list of certificates, just one item long.
- name: obtain information about a certificate with a particular ARN
- community.aws.aws_acm_info:
- certificate_arn: "arn:aws:acm:ap-southeast-2:123456789012:certificate/abcdeabc-abcd-1234-4321-abcdeabcde12"
+ community.aws.acm_certificate_info:
+ certificate_arn: "arn:aws:acm:ap-southeast-2:123456789012:certificate/abcdeabc-abcd-1234-4321-abcdeabcde12"
+"""
-'''
-
-RETURN = r'''
+RETURN = r"""
certificates:
description: A list of certificates
returned: always
@@ -257,39 +254,51 @@ certificates:
returned: always
sample: AMAZON_ISSUED
type: str
-'''
+"""
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
from ansible_collections.amazon.aws.plugins.module_utils.acm import ACMServiceManager
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
+
def main():
argument_spec = dict(
- certificate_arn=dict(aliases=['arn']),
- domain_name=dict(aliases=['name']),
+ certificate_arn=dict(aliases=["arn"]),
+ domain_name=dict(aliases=["name"]),
statuses=dict(
- type='list',
- elements='str',
- choices=['PENDING_VALIDATION', 'ISSUED', 'INACTIVE', 'EXPIRED', 'VALIDATION_TIMED_OUT', 'REVOKED', 'FAILED']
+ type="list",
+ elements="str",
+ choices=[
+ "PENDING_VALIDATION",
+ "ISSUED",
+ "INACTIVE",
+ "EXPIRED",
+ "VALIDATION_TIMED_OUT",
+ "REVOKED",
+ "FAILED",
+ ],
),
- tags=dict(type='dict'),
+ tags=dict(type="dict"),
)
module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
acm_info = ACMServiceManager(module)
- client = module.client('acm')
+ client = module.client("acm")
- certificates = acm_info.get_certificates(client, module,
- domain_name=module.params['domain_name'],
- statuses=module.params['statuses'],
- arn=module.params['certificate_arn'],
- only_tags=module.params['tags'])
+ certificates = acm_info.get_certificates(
+ client,
+ module,
+ domain_name=module.params["domain_name"],
+ statuses=module.params["statuses"],
+ arn=module.params["certificate_arn"],
+ only_tags=module.params["tags"],
+ )
- if module.params['certificate_arn'] and len(certificates) != 1:
- module.fail_json(msg="No certificate exists in this region with ARN %s" % module.params['certificate_arn'])
+ if module.params["certificate_arn"] and len(certificates) != 1:
+ module.fail_json(msg=f"No certificate exists in this region with ARN {module.params['certificate_arn']}")
module.exit_json(certificates=certificates)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/api_gateway.py b/ansible_collections/community/aws/plugins/modules/api_gateway.py
index a084bf93e..af4432387 100644
--- a/ansible_collections/community/aws/plugins/modules/api_gateway.py
+++ b/ansible_collections/community/aws/plugins/modules/api_gateway.py
@@ -4,11 +4,7 @@
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: api_gateway
version_added: 1.0.0
@@ -102,21 +98,34 @@ options:
choices: ['EDGE', 'REGIONAL', 'PRIVATE']
type: str
default: EDGE
+ name:
+ description:
+ - The name of the RestApi.
+ type: str
+ version_added: 6.2.0
+ lookup:
+ description:
+ - Look up API gateway by either I(tags) (and I(name) if supplied) or by I(api_id).
+ - If I(lookup=tag) and I(tags) is not specified then no lookup for an existing API gateway
+ is performed and a new API gateway will be created.
+ - When using I(lookup=tag), multiple matches being found will result in a failure and no changes will be made.
+ - To change the tags of a API gateway use I(lookup=id).
+ default: tag
+ choices: [ 'tag', 'id' ]
+ type: str
+ version_added: 6.2.0
author:
- 'Michael De La Rue (@mikedlr)'
+notes:
+ - 'Tags are used to uniquely identify API gateway when the I(api_id) is not supplied. version_added=6.2.0'
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
+ - amazon.aws.tags
+"""
-notes:
- - A future version of this module will probably use tags or another
- ID so that an API can be created only once.
- - As an early work around an intermediate version will probably do
- the same using a tag embedded in the API name.
-'''
-
-EXAMPLES = '''
+EXAMPLES = r"""
- name: Setup AWS API Gateway setup on AWS and deploy API definition
community.aws.api_gateway:
swagger_file: my_api.yml
@@ -143,11 +152,22 @@ EXAMPLES = '''
swagger_file: my_api.yml
cache_enabled: true
cache_size: '6.1'
- canary_settings: { percentTraffic: 50.0, deploymentId: '123', useStageCache: True }
+ canary_settings:
+ percentTraffic: 50.0
+ deploymentId: '123'
+ useStageCache: true
state: present
-'''
-RETURN = '''
+- name: Delete API gateway
+ amazon.aws.api_gateway:
+ name: ansible-rest-api
+ tags:
+ automation: ansible
+ lookup: tags
+ state: absent
+"""
+
+RETURN = r"""
api_id:
description: API id of the API endpoint created
returned: success
@@ -168,7 +188,7 @@ resource_actions:
returned: always
type: list
sample: ["apigateway:CreateRestApi", "apigateway:CreateDeployment", "apigateway:PutRestApi"]
-'''
+"""
import json
import traceback
@@ -180,70 +200,134 @@ except ImportError:
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import compare_aws_tags
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def main():
argument_spec = dict(
- api_id=dict(type='str', required=False),
- state=dict(type='str', default='present', choices=['present', 'absent']),
- swagger_file=dict(type='path', default=None, aliases=['src', 'api_file']),
- swagger_dict=dict(type='json', default=None),
- swagger_text=dict(type='str', default=None),
- stage=dict(type='str', default=None),
- deploy_desc=dict(type='str', default="Automatic deployment by Ansible."),
- cache_enabled=dict(type='bool', default=False),
- cache_size=dict(type='str', default='0.5', choices=['0.5', '1.6', '6.1', '13.5', '28.4', '58.2', '118', '237']),
- stage_variables=dict(type='dict', default={}),
- stage_canary_settings=dict(type='dict', default={}),
- tracing_enabled=dict(type='bool', default=False),
- endpoint_type=dict(type='str', default='EDGE', choices=['EDGE', 'REGIONAL', 'PRIVATE'])
+ api_id=dict(type="str", required=False),
+ state=dict(type="str", default="present", choices=["present", "absent"]),
+ swagger_file=dict(type="path", default=None, aliases=["src", "api_file"]),
+ swagger_dict=dict(type="json", default=None),
+ swagger_text=dict(type="str", default=None),
+ stage=dict(type="str", default=None),
+ deploy_desc=dict(type="str", default="Automatic deployment by Ansible."),
+ cache_enabled=dict(type="bool", default=False),
+ cache_size=dict(type="str", default="0.5", choices=["0.5", "1.6", "6.1", "13.5", "28.4", "58.2", "118", "237"]),
+ stage_variables=dict(type="dict", default={}),
+ stage_canary_settings=dict(type="dict", default={}),
+ tracing_enabled=dict(type="bool", default=False),
+ endpoint_type=dict(type="str", default="EDGE", choices=["EDGE", "REGIONAL", "PRIVATE"]),
+ name=dict(type="str"),
+ lookup=dict(type="str", choices=["tag", "id"], default="tag"),
+ tags=dict(type="dict", aliases=["resource_tags"]),
+ purge_tags=dict(default=True, type="bool"),
)
- mutually_exclusive = [['swagger_file', 'swagger_dict', 'swagger_text']] # noqa: F841
+ mutually_exclusive = [["swagger_file", "swagger_dict", "swagger_text"]] # noqa: F841
module = AnsibleAWSModule(
argument_spec=argument_spec,
- supports_check_mode=False,
+ supports_check_mode=True,
mutually_exclusive=mutually_exclusive,
)
- api_id = module.params.get('api_id')
- state = module.params.get('state') # noqa: F841
- swagger_file = module.params.get('swagger_file')
- swagger_dict = module.params.get('swagger_dict')
- swagger_text = module.params.get('swagger_text')
- endpoint_type = module.params.get('endpoint_type')
+ api_id = module.params.get("api_id")
+ state = module.params.get("state") # noqa: F841
+ swagger_file = module.params.get("swagger_file")
+ swagger_dict = module.params.get("swagger_dict")
+ swagger_text = module.params.get("swagger_text")
+ endpoint_type = module.params.get("endpoint_type")
+ name = module.params.get("name")
+ tags = module.params.get("tags")
+ lookup = module.params.get("lookup")
- client = module.client('apigateway')
+ client = module.client("apigateway")
- changed = True # for now it will stay that way until we can sometimes avoid change
+ changed = True # for now it will stay that way until we can sometimes avoid change
conf_res = None
dep_res = None
del_res = None
if state == "present":
if api_id is None:
- api_id = create_empty_api(module, client, endpoint_type)
- api_data = get_api_definitions(module, swagger_file=swagger_file,
- swagger_dict=swagger_dict, swagger_text=swagger_text)
- conf_res, dep_res = ensure_api_in_correct_state(module, client, api_id, api_data)
+ # lookup API gateway using tags
+ if tags and lookup == "tag":
+ rest_api = get_api_by_tags(client, module, name, tags)
+ if rest_api:
+ api_id = rest_api["id"]
+ if module.check_mode:
+ module.exit_json(changed=True, msg="Create/update operation skipped - running in check mode.")
+ if api_id is None:
+ api_data = get_api_definitions(
+ module, swagger_file=swagger_file, swagger_dict=swagger_dict, swagger_text=swagger_text
+ )
+ # create new API gateway as non were provided and/or found using lookup=tag
+ api_id = create_empty_api(module, client, name, endpoint_type, tags)
+ conf_res, dep_res = ensure_api_in_correct_state(module, client, api_id, api_data)
+ tags = module.params.get("tags")
+ purge_tags = module.params.get("purge_tags")
+ if tags:
+ if not conf_res:
+ conf_res = get_rest_api(module, client, api_id=api_id)
+ tag_changed, tag_result = ensure_apigateway_tags(
+ module, client, api_id=api_id, current_tags=conf_res.get("tags"), new_tags=tags, purge_tags=purge_tags
+ )
+ if tag_changed:
+ changed |= tag_changed
+ conf_res = tag_result
if state == "absent":
+ if api_id is None:
+ if lookup != "tag" or not tags:
+ module.fail_json(
+ msg="API gateway id must be supplied to delete API gateway or provided tag with lookup=tag to identify API gateway id."
+ )
+ rest_api = get_api_by_tags(client, module, name, tags)
+ if not rest_api:
+ module.exit_json(changed=False, msg="No API gateway identified with tags provided")
+ api_id = rest_api["id"]
+ elif not describe_api(client, module, api_id):
+ module.exit_json(changed=False, msg=f"API gateway id '{api_id}' does not exist.")
+
+ if module.check_mode:
+ module.exit_json(changed=True, msg="Delete operation skipped - running in check mode.", api_id=api_id)
+
del_res = delete_rest_api(module, client, api_id)
exit_args = {"changed": changed, "api_id": api_id}
if conf_res is not None:
- exit_args['configure_response'] = camel_dict_to_snake_dict(conf_res)
+ exit_args["configure_response"] = camel_dict_to_snake_dict(conf_res)
if dep_res is not None:
- exit_args['deploy_response'] = camel_dict_to_snake_dict(dep_res)
+ exit_args["deploy_response"] = camel_dict_to_snake_dict(dep_res)
if del_res is not None:
- exit_args['delete_response'] = camel_dict_to_snake_dict(del_res)
+ exit_args["delete_response"] = camel_dict_to_snake_dict(del_res)
module.exit_json(**exit_args)
+def ensure_apigateway_tags(module, client, api_id, current_tags, new_tags, purge_tags):
+ changed = False
+ tag_result = {}
+ tags_to_set, tags_to_delete = compare_aws_tags(current_tags, new_tags, purge_tags)
+ if tags_to_set or tags_to_delete:
+ changed = True
+ apigateway_arn = f"arn:aws:apigateway:{module.region}::/restapis/{api_id}"
+ # Remove tags from Resource
+ if tags_to_delete:
+ client.untag_resource(resourceArn=apigateway_arn, tagKeys=tags_to_delete)
+ # add new tags to resource
+ if tags_to_set:
+ client.tag_resource(resourceArn=apigateway_arn, tags=tags_to_set)
+ # Describe API gateway
+ tag_result = get_rest_api(module, client, api_id=api_id)
+ return changed, tag_result
+
+
def get_api_definitions(module, swagger_file=None, swagger_dict=None, swagger_text=None):
apidata = None
if swagger_file is not None:
@@ -251,7 +335,7 @@ def get_api_definitions(module, swagger_file=None, swagger_dict=None, swagger_te
with open(swagger_file) as f:
apidata = f.read()
except OSError as e:
- msg = "Failed trying to read swagger file {0}: {1}".format(str(swagger_file), str(e))
+ msg = f"Failed trying to read swagger file {str(swagger_file)}: {str(e)}"
module.fail_json(msg=msg, exception=traceback.format_exc())
if swagger_dict is not None:
apidata = json.dumps(swagger_dict)
@@ -259,11 +343,20 @@ def get_api_definitions(module, swagger_file=None, swagger_dict=None, swagger_te
apidata = swagger_text
if apidata is None:
- module.fail_json(msg='module error - no swagger info provided')
+ module.fail_json(msg="module error - no swagger info provided")
return apidata
-def create_empty_api(module, client, endpoint_type):
+def get_rest_api(module, client, api_id):
+ try:
+ response = client.get_rest_api(restApiId=api_id)
+ response.pop("ResponseMetadata", None)
+ return response
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ module.fail_json_aws(e, msg=f"failed to get REST API with api_id={api_id}")
+
+
+def create_empty_api(module, client, name, endpoint_type, tags):
"""
creates a new empty API ready to be configured. The description is
temporarily set to show the API as incomplete but should be
@@ -271,7 +364,8 @@ def create_empty_api(module, client, endpoint_type):
"""
desc = "Incomplete API creation by ansible api_gateway module"
try:
- awsret = create_api(client, name="ansible-temp-api", description=desc, endpoint_type=endpoint_type)
+ rest_api_name = name or "ansible-temp-api"
+ awsret = create_api(client, name=rest_api_name, description=desc, endpoint_type=endpoint_type, tags=tags)
except (botocore.exceptions.ClientError, botocore.exceptions.EndpointConnectionError) as e:
module.fail_json_aws(e, msg="creating API")
return awsret["id"]
@@ -284,7 +378,7 @@ def delete_rest_api(module, client, api_id):
try:
delete_response = delete_api(client, api_id)
except (botocore.exceptions.ClientError, botocore.exceptions.EndpointConnectionError) as e:
- module.fail_json_aws(e, msg="deleting API {0}".format(api_id))
+ module.fail_json_aws(e, msg=f"deleting API {api_id}")
return delete_response
@@ -301,28 +395,56 @@ def ensure_api_in_correct_state(module, client, api_id, api_data):
configure_response = None
try:
configure_response = configure_api(client, api_id, api_data=api_data)
+ configure_response.pop("ResponseMetadata", None)
except (botocore.exceptions.ClientError, botocore.exceptions.EndpointConnectionError) as e:
- module.fail_json_aws(e, msg="configuring API {0}".format(api_id))
+ module.fail_json_aws(e, msg=f"configuring API {api_id}")
deploy_response = None
- stage = module.params.get('stage')
+ stage = module.params.get("stage")
if stage:
try:
deploy_response = create_deployment(client, api_id, **module.params)
+ deploy_response.pop("ResponseMetadata", None)
except (botocore.exceptions.ClientError, botocore.exceptions.EndpointConnectionError) as e:
- msg = "deploying api {0} to stage {1}".format(api_id, stage)
+ msg = f"deploying api {api_id} to stage {stage}"
module.fail_json_aws(e, msg)
return configure_response, deploy_response
-retry_params = {"retries": 10, "delay": 10, "catch_extra_error_codes": ['TooManyRequestsException']}
+def get_api_by_tags(client, module, name, tags):
+ count = 0
+ result = None
+ for api in list_apis(client):
+ if name and api["name"] != name:
+ continue
+ api_tags = api.get("tags", {})
+ if all((tag_key in api_tags and api_tags[tag_key] == tag_value for tag_key, tag_value in tags.items())):
+ result = api
+ count += 1
+
+ if count > 1:
+ args = "Tags"
+ if name:
+ args += " and name"
+ module.fail_json(msg=f"{args} provided do not identify a unique API gateway")
+ return result
+
+
+retry_params = {"retries": 10, "delay": 10, "catch_extra_error_codes": ["TooManyRequestsException"]}
@AWSRetry.jittered_backoff(**retry_params)
-def create_api(client, name=None, description=None, endpoint_type=None):
- return client.create_rest_api(name="ansible-temp-api", description=description, endpointConfiguration={'types': [endpoint_type]})
+def create_api(client, name, description=None, endpoint_type=None, tags=None):
+ params = {"name": name}
+ if description:
+ params["description"] = description
+ if endpoint_type:
+ params["endpointConfiguration"] = {"types": [endpoint_type]}
+ if tags:
+ params["tags"] = tags
+ return client.create_rest_api(**params)
@AWSRetry.jittered_backoff(**retry_params)
@@ -337,32 +459,53 @@ def configure_api(client, api_id, api_data=None, mode="overwrite"):
@AWSRetry.jittered_backoff(**retry_params)
def create_deployment(client, rest_api_id, **params):
- canary_settings = params.get('stage_canary_settings')
+ canary_settings = params.get("stage_canary_settings")
if canary_settings and len(canary_settings) > 0:
result = client.create_deployment(
restApiId=rest_api_id,
- stageName=params.get('stage'),
- description=params.get('deploy_desc'),
- cacheClusterEnabled=params.get('cache_enabled'),
- cacheClusterSize=params.get('cache_size'),
- variables=params.get('stage_variables'),
+ stageName=params.get("stage"),
+ description=params.get("deploy_desc"),
+ cacheClusterEnabled=params.get("cache_enabled"),
+ cacheClusterSize=params.get("cache_size"),
+ variables=params.get("stage_variables"),
canarySettings=canary_settings,
- tracingEnabled=params.get('tracing_enabled')
+ tracingEnabled=params.get("tracing_enabled"),
)
else:
result = client.create_deployment(
restApiId=rest_api_id,
- stageName=params.get('stage'),
- description=params.get('deploy_desc'),
- cacheClusterEnabled=params.get('cache_enabled'),
- cacheClusterSize=params.get('cache_size'),
- variables=params.get('stage_variables'),
- tracingEnabled=params.get('tracing_enabled')
+ stageName=params.get("stage"),
+ description=params.get("deploy_desc"),
+ cacheClusterEnabled=params.get("cache_enabled"),
+ cacheClusterSize=params.get("cache_size"),
+ variables=params.get("stage_variables"),
+ tracingEnabled=params.get("tracing_enabled"),
)
return result
-if __name__ == '__main__':
+@AWSRetry.jittered_backoff(**retry_params)
+def list_apis(client):
+ paginator = client.get_paginator("get_rest_apis")
+ return paginator.paginate().build_full_result().get("items", [])
+
+
+@AWSRetry.jittered_backoff(**retry_params)
+def describe_api(client, module, rest_api_id):
+ try:
+ response = client.get_rest_api(restApiId=rest_api_id)
+ response.pop("ResponseMetadata")
+ except is_boto3_error_code("ResourceNotFoundException"):
+ response = {}
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(e, msg=f"Trying to get Rest API '{rest_api_id}'.")
+ return response
+
+
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/api_gateway_domain.py b/ansible_collections/community/aws/plugins/modules/api_gateway_domain.py
index 9b4ec8572..8ffbdaf20 100644
--- a/ansible_collections/community/aws/plugins/modules/api_gateway_domain.py
+++ b/ansible_collections/community/aws/plugins/modules/api_gateway_domain.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: api_gateway_domain
short_description: Manage AWS API Gateway custom domains
@@ -57,17 +55,17 @@ options:
default: present
choices: [ 'present', 'absent' ]
type: str
-extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
- - amazon.aws.boto3
notes:
- Does not create a DNS entry on Route53, for that use the M(community.aws.route53) module.
- Only supports TLS certificates from AWS ACM that can just be referenced by the ARN, while the AWS API still offers (deprecated)
options to add own Certificates.
-'''
+extends_documentation_fragment:
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
- name: Setup endpoint for a custom domain for your API Gateway HTTP API
community.aws.api_gateway_domain:
domain_name: myapi.foobar.com
@@ -75,7 +73,8 @@ EXAMPLES = '''
security_policy: TLS_1_2
endpoint_type: EDGE
domain_mappings:
- - { rest_api_id: abc123, stage: production }
+ - rest_api_id: abc123
+ stage: production
state: present
register: api_gw_domain_result
@@ -88,9 +87,9 @@ EXAMPLES = '''
zone: foobar.com
alias_hosted_zone_id: "{{ api_gw_domain_result.response.domain.distribution_hosted_zone_id }}"
command: create
-'''
+"""
-RETURN = '''
+RETURN = r"""
response:
description: The data returned by create_domain_name (or update and delete) and create_base_path_mapping methods by boto3.
returned: success
@@ -110,27 +109,33 @@ response:
path_mappings: [
{ base_path: '(empty)', rest_api_id: 'abcd123', stage: 'production' }
]
-'''
+"""
+
+import copy
try:
- from botocore.exceptions import ClientError, BotoCoreError, EndpointConnectionError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
+ from botocore.exceptions import EndpointConnectionError
except ImportError:
pass # caught by imported AnsibleAWSModule
-import copy
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+from ansible.module_utils.common.dict_transformations import snake_dict_to_camel_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule, is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict, snake_dict_to_camel_dict
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def get_domain(module, client):
- domain_name = module.params.get('domain_name')
+ domain_name = module.params.get("domain_name")
result = {}
try:
- result['domain'] = get_domain_name(client, domain_name)
- result['path_mappings'] = get_domain_mappings(client, domain_name)
- except is_boto3_error_code('NotFoundException'):
+ result["domain"] = get_domain_name(client, domain_name)
+ result["path_mappings"] = get_domain_mappings(client, domain_name)
+ except is_boto3_error_code("NotFoundException"):
return None
except (ClientError, BotoCoreError, EndpointConnectionError) as e: # pylint: disable=duplicate-except
module.fail_json_aws(e, msg="getting API GW domain")
@@ -138,28 +143,28 @@ def get_domain(module, client):
def create_domain(module, client):
- path_mappings = module.params.get('domain_mappings', [])
- domain_name = module.params.get('domain_name')
- result = {'domain': {}, 'path_mappings': []}
+ path_mappings = module.params.get("domain_mappings", [])
+ domain_name = module.params.get("domain_name")
+ result = {"domain": {}, "path_mappings": []}
try:
- result['domain'] = create_domain_name(
+ result["domain"] = create_domain_name(
module,
client,
domain_name,
- module.params.get('certificate_arn'),
- module.params.get('endpoint_type'),
- module.params.get('security_policy')
+ module.params.get("certificate_arn"),
+ module.params.get("endpoint_type"),
+ module.params.get("security_policy"),
)
for mapping in path_mappings:
- base_path = mapping.get('base_path', '')
- rest_api_id = mapping.get('rest_api_id')
- stage = mapping.get('stage')
+ base_path = mapping.get("base_path", "")
+ rest_api_id = mapping.get("rest_api_id")
+ stage = mapping.get("stage")
if rest_api_id is None or stage is None:
- module.fail_json('Every domain mapping needs a rest_api_id and stage name')
+ module.fail_json("Every domain mapping needs a rest_api_id and stage name")
- result['path_mappings'].append(add_domain_mapping(client, domain_name, base_path, rest_api_id, stage))
+ result["path_mappings"].append(add_domain_mapping(client, domain_name, base_path, rest_api_id, stage))
except (ClientError, BotoCoreError, EndpointConnectionError) as e:
module.fail_json_aws(e, msg="creating API GW domain")
@@ -167,54 +172,56 @@ def create_domain(module, client):
def update_domain(module, client, existing_domain):
- domain_name = module.params.get('domain_name')
+ domain_name = module.params.get("domain_name")
result = existing_domain
- result['updated'] = False
+ result["updated"] = False
- domain = existing_domain.get('domain')
+ domain = existing_domain.get("domain")
# Compare only relevant set of domain arguments.
# As get_domain_name gathers all kind of state information that can't be set anyways.
# Also this module doesn't support custom TLS cert setup params as they are kind of deprecated already and would increase complexity.
existing_domain_settings = {
- 'certificate_arn': domain.get('certificate_arn'),
- 'security_policy': domain.get('security_policy'),
- 'endpoint_type': domain.get('endpoint_configuration').get('types')[0]
+ "certificate_arn": domain.get("certificate_arn"),
+ "security_policy": domain.get("security_policy"),
+ "endpoint_type": domain.get("endpoint_configuration").get("types")[0],
}
specified_domain_settings = {
- 'certificate_arn': module.params.get('certificate_arn'),
- 'security_policy': module.params.get('security_policy'),
- 'endpoint_type': module.params.get('endpoint_type')
+ "certificate_arn": module.params.get("certificate_arn"),
+ "security_policy": module.params.get("security_policy"),
+ "endpoint_type": module.params.get("endpoint_type"),
}
if specified_domain_settings != existing_domain_settings:
try:
- result['domain'] = update_domain_name(client, domain_name, **snake_dict_to_camel_dict(specified_domain_settings))
- result['updated'] = True
+ result["domain"] = update_domain_name(
+ client, domain_name, **snake_dict_to_camel_dict(specified_domain_settings)
+ )
+ result["updated"] = True
except (ClientError, BotoCoreError, EndpointConnectionError) as e:
module.fail_json_aws(e, msg="updating API GW domain")
- existing_mappings = copy.deepcopy(existing_domain.get('path_mappings', []))
+ existing_mappings = copy.deepcopy(existing_domain.get("path_mappings", []))
# Cleanout `base_path: "(none)"` elements from dicts as those won't match with specified mappings
for mapping in existing_mappings:
- if mapping.get('base_path', 'missing') == '(none)':
- mapping.pop('base_path')
+ if mapping.get("base_path", "missing") == "(none)":
+ mapping.pop("base_path")
- specified_mappings = copy.deepcopy(module.params.get('domain_mappings', []))
+ specified_mappings = copy.deepcopy(module.params.get("domain_mappings", []))
# Cleanout `base_path: ""` elements from dicts as those won't match with existing mappings
for mapping in specified_mappings:
- if mapping.get('base_path', 'missing') == '':
- mapping.pop('base_path')
+ if mapping.get("base_path", "missing") == "":
+ mapping.pop("base_path")
if specified_mappings != existing_mappings:
try:
# When lists missmatch delete all existing mappings before adding new ones as specified
- for mapping in existing_domain.get('path_mappings', []):
- delete_domain_mapping(client, domain_name, mapping['base_path'])
- for mapping in module.params.get('domain_mappings', []):
- result['path_mappings'] = add_domain_mapping(
- client, domain_name, mapping.get('base_path', ''), mapping.get('rest_api_id'), mapping.get('stage')
+ for mapping in existing_domain.get("path_mappings", []):
+ delete_domain_mapping(client, domain_name, mapping["base_path"])
+ for mapping in module.params.get("domain_mappings", []):
+ result["path_mappings"] = add_domain_mapping(
+ client, domain_name, mapping.get("base_path", ""), mapping.get("rest_api_id"), mapping.get("stage")
)
- result['updated'] = True
+ result["updated"] = True
except (ClientError, BotoCoreError, EndpointConnectionError) as e:
module.fail_json_aws(e, msg="updating API GW domain mapping")
@@ -222,7 +229,7 @@ def update_domain(module, client, existing_domain):
def delete_domain(module, client):
- domain_name = module.params.get('domain_name')
+ domain_name = module.params.get("domain_name")
try:
result = delete_domain_name(client, domain_name)
except (ClientError, BotoCoreError, EndpointConnectionError) as e:
@@ -240,19 +247,19 @@ def get_domain_name(client, domain_name):
@AWSRetry.jittered_backoff(**retry_params)
def get_domain_mappings(client, domain_name):
- return client.get_base_path_mappings(domainName=domain_name, limit=200).get('items', [])
+ return client.get_base_path_mappings(domainName=domain_name, limit=200).get("items", [])
@AWSRetry.jittered_backoff(**retry_params)
def create_domain_name(module, client, domain_name, certificate_arn, endpoint_type, security_policy):
- endpoint_configuration = {'types': [endpoint_type]}
+ endpoint_configuration = {"types": [endpoint_type]}
- if endpoint_type == 'EDGE':
+ if endpoint_type == "EDGE":
return client.create_domain_name(
domainName=domain_name,
certificateArn=certificate_arn,
endpointConfiguration=endpoint_configuration,
- securityPolicy=security_policy
+ securityPolicy=security_policy,
)
else:
# Use regionalCertificateArn for regional domain deploys
@@ -260,13 +267,15 @@ def create_domain_name(module, client, domain_name, certificate_arn, endpoint_ty
domainName=domain_name,
regionalCertificateArn=certificate_arn,
endpointConfiguration=endpoint_configuration,
- securityPolicy=security_policy
+ securityPolicy=security_policy,
)
@AWSRetry.jittered_backoff(**retry_params)
def add_domain_mapping(client, domain_name, base_path, rest_api_id, stage):
- return client.create_base_path_mapping(domainName=domain_name, basePath=base_path, restApiId=rest_api_id, stage=stage)
+ return client.create_base_path_mapping(
+ domainName=domain_name, basePath=base_path, restApiId=rest_api_id, stage=stage
+ )
@AWSRetry.jittered_backoff(**retry_params)
@@ -294,29 +303,29 @@ def delete_domain_mapping(client, domain_name, base_path):
def main():
argument_spec = dict(
- domain_name=dict(type='str', required=True),
- certificate_arn=dict(type='str', required=True),
- security_policy=dict(type='str', default='TLS_1_2', choices=['TLS_1_0', 'TLS_1_2']),
- endpoint_type=dict(type='str', default='EDGE', choices=['EDGE', 'REGIONAL', 'PRIVATE']),
- domain_mappings=dict(type='list', required=True, elements='dict'),
- state=dict(type='str', default='present', choices=['present', 'absent'])
+ domain_name=dict(type="str", required=True),
+ certificate_arn=dict(type="str", required=True),
+ security_policy=dict(type="str", default="TLS_1_2", choices=["TLS_1_0", "TLS_1_2"]),
+ endpoint_type=dict(type="str", default="EDGE", choices=["EDGE", "REGIONAL", "PRIVATE"]),
+ domain_mappings=dict(type="list", required=True, elements="dict"),
+ state=dict(type="str", default="present", choices=["present", "absent"]),
)
module = AnsibleAWSModule(
argument_spec=argument_spec,
- supports_check_mode=False
+ supports_check_mode=False,
)
- client = module.client('apigateway')
+ client = module.client("apigateway")
- state = module.params.get('state')
+ state = module.params.get("state")
changed = False
if state == "present":
existing_domain = get_domain(module, client)
if existing_domain is not None:
result = update_domain(module, client, existing_domain)
- changed = result['updated']
+ changed = result["updated"]
else:
result = create_domain(module, client)
changed = True
@@ -327,10 +336,10 @@ def main():
exit_args = {"changed": changed}
if result is not None:
- exit_args['response'] = result
+ exit_args["response"] = result
module.exit_json(**exit_args)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/api_gateway_info.py b/ansible_collections/community/aws/plugins/modules/api_gateway_info.py
new file mode 100644
index 000000000..fd38d795a
--- /dev/null
+++ b/ansible_collections/community/aws/plugins/modules/api_gateway_info.py
@@ -0,0 +1,156 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: Contributors to the Ansible project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r"""
+---
+module: api_gateway_info
+version_added: 6.1.0
+short_description: Gather information about ec2 instances in AWS
+description:
+ - Gather information about ec2 instances in AWS
+options:
+ ids:
+ description:
+ - The list of the string identifiers of the associated RestApis.
+ type: list
+ elements: str
+author:
+ - Aubin Bikouo (@abikouo)
+extends_documentation_fragment:
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
+
+EXAMPLES = r"""
+---
+# List all API gateway
+- name: List all for a specific function
+ community.aws.api_gateway_info:
+
+# Get information for a specific API gateway
+- name: List all for a specific function
+ community.aws.api_gateway_info:
+ ids:
+ - 012345678a
+ - abcdefghij
+"""
+
+RETURN = r"""
+---
+rest_apis:
+ description: A list of API gateway.
+ returned: always
+ type: complex
+ contains:
+ name:
+ description: The name of the API.
+ returned: success
+ type: str
+ sample: 'ansible-tmp-api'
+ id:
+ description: The identifier of the API.
+ returned: success
+ type: str
+ sample: 'abcdefgh'
+ api_key_source:
+ description: The source of the API key for metering requests according to a usage plan.
+ returned: success
+ type: str
+ sample: 'HEADER'
+ created_date:
+ description: The timestamp when the API was created.
+ returned: success
+ type: str
+ sample: "2020-01-01T11:37:59+00:00"
+ description:
+ description: The description of the API.
+ returned: success
+ type: str
+ sample: "Automatic deployment by Ansible."
+ disable_execute_api_endpoint:
+ description: Specifies whether clients can invoke your API by using the default execute-api endpoint.
+ returned: success
+ type: bool
+ sample: False
+ endpoint_configuration:
+ description: The endpoint configuration of this RestApi showing the endpoint types of the API.
+ returned: success
+ type: dict
+ sample: {"types": ["REGIONAL"]}
+ tags:
+ description: The collection of tags.
+ returned: success
+ type: dict
+ sample: {"key": "value"}
+"""
+
+
+try:
+ import botocore
+except ImportError:
+ pass # caught by AnsibleAWSModule
+
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.modules import AnsibleAWSModule
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+
+
+@AWSRetry.jittered_backoff()
+def _list_rest_apis(connection, **params):
+ paginator = connection.get_paginator("get_rest_apis")
+ return paginator.paginate(**params).build_full_result().get("items", [])
+
+
+@AWSRetry.jittered_backoff()
+def _describe_rest_api(connection, module, rest_api_id):
+ try:
+ response = connection.get_rest_api(restApiId=rest_api_id)
+ response.pop("ResponseMetadata")
+ except is_boto3_error_code("ResourceNotFoundException"):
+ response = {}
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(e, msg=f"Trying to get Rest API '{rest_api_id}'.")
+ return response
+
+
+def main():
+ argument_spec = dict(
+ ids=dict(type="list", elements="str"),
+ )
+
+ module = AnsibleAWSModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
+
+ try:
+ connection = module.client("apigateway")
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ module.fail_json_aws(e, msg="Failed to connect to AWS")
+
+ ids = module.params.get("ids")
+ if ids:
+ rest_apis = []
+ for rest_api_id in ids:
+ result = _describe_rest_api(connection, module, rest_api_id)
+ if result:
+ rest_apis.append(result)
+ else:
+ rest_apis = _list_rest_apis(connection)
+
+ # Turn the boto3 result in to ansible_friendly_snaked_names
+ snaked_rest_apis = [camel_dict_to_snake_dict(item) for item in rest_apis]
+ module.exit_json(changed=False, rest_apis=snaked_rest_apis)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/aws/plugins/modules/application_autoscaling_policy.py b/ansible_collections/community/aws/plugins/modules/application_autoscaling_policy.py
index d20c107de..beb2247ac 100644
--- a/ansible_collections/community/aws/plugins/modules/application_autoscaling_policy.py
+++ b/ansible_collections/community/aws/plugins/modules/application_autoscaling_policy.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: application_autoscaling_policy
version_added: 1.0.0
@@ -104,12 +102,12 @@ options:
required: false
type: bool
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide for details.
# Create step scaling policy for ECS Service
@@ -160,9 +158,9 @@ EXAMPLES = '''
service_namespace: ecs
resource_id: service/cluster-name/service-name
scalable_dimension: ecs:service:DesiredCount
-'''
+"""
-RETURN = '''
+RETURN = r"""
alarms:
description: List of the CloudWatch alarms associated with the scaling policy
returned: when state present
@@ -283,27 +281,29 @@ creation_time:
returned: when state present
type: str
sample: '2017-09-28T08:22:51.881000-03:00'
-''' # NOQA
-
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import _camel_to_snake, camel_dict_to_snake_dict
+"""
try:
import botocore
except ImportError:
pass # handled by AnsibleAWSModule
+from ansible.module_utils.common.dict_transformations import _camel_to_snake
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
+
# Merge the results of the scalable target creation and policy deletion/creation
# There's no risk in overriding values since mutual keys have the same values in our case
def merge_results(scalable_target_result, policy_result):
- if scalable_target_result['changed'] or policy_result['changed']:
+ if scalable_target_result["changed"] or policy_result["changed"]:
changed = True
else:
changed = False
- merged_response = scalable_target_result['response'].copy()
- merged_response.update(policy_result['response'])
+ merged_response = scalable_target_result["response"].copy()
+ merged_response.update(policy_result["response"])
return {"changed": changed, "response": merged_response}
@@ -312,22 +312,22 @@ def delete_scaling_policy(connection, module):
changed = False
try:
scaling_policy = connection.describe_scaling_policies(
- ServiceNamespace=module.params.get('service_namespace'),
- ResourceId=module.params.get('resource_id'),
- ScalableDimension=module.params.get('scalable_dimension'),
- PolicyNames=[module.params.get('policy_name')],
- MaxResults=1
+ ServiceNamespace=module.params.get("service_namespace"),
+ ResourceId=module.params.get("resource_id"),
+ ScalableDimension=module.params.get("scalable_dimension"),
+ PolicyNames=[module.params.get("policy_name")],
+ MaxResults=1,
)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Failed to describe scaling policies")
- if scaling_policy['ScalingPolicies']:
+ if scaling_policy["ScalingPolicies"]:
try:
connection.delete_scaling_policy(
- ServiceNamespace=module.params.get('service_namespace'),
- ResourceId=module.params.get('resource_id'),
- ScalableDimension=module.params.get('scalable_dimension'),
- PolicyName=module.params.get('policy_name'),
+ ServiceNamespace=module.params.get("service_namespace"),
+ ResourceId=module.params.get("resource_id"),
+ ScalableDimension=module.params.get("scalable_dimension"),
+ PolicyName=module.params.get("policy_name"),
)
changed = True
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
@@ -341,11 +341,11 @@ def create_scalable_target(connection, module):
try:
scalable_targets = connection.describe_scalable_targets(
- ServiceNamespace=module.params.get('service_namespace'),
+ ServiceNamespace=module.params.get("service_namespace"),
ResourceIds=[
- module.params.get('resource_id'),
+ module.params.get("resource_id"),
],
- ScalableDimension=module.params.get('scalable_dimension')
+ ScalableDimension=module.params.get("scalable_dimension"),
)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Failed to describe scalable targets")
@@ -353,41 +353,38 @@ def create_scalable_target(connection, module):
# Scalable target registration will occur if:
# 1. There is no scalable target registered for this service
# 2. A scalable target exists, different min/max values are defined and override is set to "yes"
- if (
- not scalable_targets['ScalableTargets']
- or (
- module.params.get('override_task_capacity')
- and (
- scalable_targets['ScalableTargets'][0]['MinCapacity'] != module.params.get('minimum_tasks')
- or scalable_targets['ScalableTargets'][0]['MaxCapacity'] != module.params.get('maximum_tasks')
- )
+ if not scalable_targets["ScalableTargets"] or (
+ module.params.get("override_task_capacity")
+ and (
+ scalable_targets["ScalableTargets"][0]["MinCapacity"] != module.params.get("minimum_tasks")
+ or scalable_targets["ScalableTargets"][0]["MaxCapacity"] != module.params.get("maximum_tasks")
)
):
changed = True
try:
connection.register_scalable_target(
- ServiceNamespace=module.params.get('service_namespace'),
- ResourceId=module.params.get('resource_id'),
- ScalableDimension=module.params.get('scalable_dimension'),
- MinCapacity=module.params.get('minimum_tasks'),
- MaxCapacity=module.params.get('maximum_tasks')
+ ServiceNamespace=module.params.get("service_namespace"),
+ ResourceId=module.params.get("resource_id"),
+ ScalableDimension=module.params.get("scalable_dimension"),
+ MinCapacity=module.params.get("minimum_tasks"),
+ MaxCapacity=module.params.get("maximum_tasks"),
)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Failed to register scalable target")
try:
response = connection.describe_scalable_targets(
- ServiceNamespace=module.params.get('service_namespace'),
+ ServiceNamespace=module.params.get("service_namespace"),
ResourceIds=[
- module.params.get('resource_id'),
+ module.params.get("resource_id"),
],
- ScalableDimension=module.params.get('scalable_dimension')
+ ScalableDimension=module.params.get("scalable_dimension"),
)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Failed to describe scalable targets")
- if (response['ScalableTargets']):
- snaked_response = camel_dict_to_snake_dict(response['ScalableTargets'][0])
+ if response["ScalableTargets"]:
+ snaked_response = camel_dict_to_snake_dict(response["ScalableTargets"][0])
else:
snaked_response = {}
@@ -397,78 +394,82 @@ def create_scalable_target(connection, module):
def create_scaling_policy(connection, module):
try:
scaling_policy = connection.describe_scaling_policies(
- ServiceNamespace=module.params.get('service_namespace'),
- ResourceId=module.params.get('resource_id'),
- ScalableDimension=module.params.get('scalable_dimension'),
- PolicyNames=[module.params.get('policy_name')],
- MaxResults=1
+ ServiceNamespace=module.params.get("service_namespace"),
+ ResourceId=module.params.get("resource_id"),
+ ScalableDimension=module.params.get("scalable_dimension"),
+ PolicyNames=[module.params.get("policy_name")],
+ MaxResults=1,
)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Failed to describe scaling policies")
changed = False
- if scaling_policy['ScalingPolicies']:
- scaling_policy = scaling_policy['ScalingPolicies'][0]
+ if scaling_policy["ScalingPolicies"]:
+ scaling_policy = scaling_policy["ScalingPolicies"][0]
# check if the input parameters are equal to what's already configured
- for attr in ('PolicyName',
- 'ServiceNamespace',
- 'ResourceId',
- 'ScalableDimension',
- 'PolicyType',
- 'StepScalingPolicyConfiguration',
- 'TargetTrackingScalingPolicyConfiguration'):
+ for attr in (
+ "PolicyName",
+ "ServiceNamespace",
+ "ResourceId",
+ "ScalableDimension",
+ "PolicyType",
+ "StepScalingPolicyConfiguration",
+ "TargetTrackingScalingPolicyConfiguration",
+ ):
if attr in scaling_policy and scaling_policy[attr] != module.params.get(_camel_to_snake(attr)):
changed = True
scaling_policy[attr] = module.params.get(_camel_to_snake(attr))
else:
changed = True
scaling_policy = {
- 'PolicyName': module.params.get('policy_name'),
- 'ServiceNamespace': module.params.get('service_namespace'),
- 'ResourceId': module.params.get('resource_id'),
- 'ScalableDimension': module.params.get('scalable_dimension'),
- 'PolicyType': module.params.get('policy_type'),
- 'StepScalingPolicyConfiguration': module.params.get('step_scaling_policy_configuration'),
- 'TargetTrackingScalingPolicyConfiguration': module.params.get('target_tracking_scaling_policy_configuration')
+ "PolicyName": module.params.get("policy_name"),
+ "ServiceNamespace": module.params.get("service_namespace"),
+ "ResourceId": module.params.get("resource_id"),
+ "ScalableDimension": module.params.get("scalable_dimension"),
+ "PolicyType": module.params.get("policy_type"),
+ "StepScalingPolicyConfiguration": module.params.get("step_scaling_policy_configuration"),
+ "TargetTrackingScalingPolicyConfiguration": module.params.get(
+ "target_tracking_scaling_policy_configuration"
+ ),
}
if changed:
try:
- if (module.params.get('step_scaling_policy_configuration')):
+ if module.params.get("step_scaling_policy_configuration"):
connection.put_scaling_policy(
- PolicyName=scaling_policy['PolicyName'],
- ServiceNamespace=scaling_policy['ServiceNamespace'],
- ResourceId=scaling_policy['ResourceId'],
- ScalableDimension=scaling_policy['ScalableDimension'],
- PolicyType=scaling_policy['PolicyType'],
- StepScalingPolicyConfiguration=scaling_policy['StepScalingPolicyConfiguration']
+ PolicyName=scaling_policy["PolicyName"],
+ ServiceNamespace=scaling_policy["ServiceNamespace"],
+ ResourceId=scaling_policy["ResourceId"],
+ ScalableDimension=scaling_policy["ScalableDimension"],
+ PolicyType=scaling_policy["PolicyType"],
+ StepScalingPolicyConfiguration=scaling_policy["StepScalingPolicyConfiguration"],
)
- elif (module.params.get('target_tracking_scaling_policy_configuration')):
+ elif module.params.get("target_tracking_scaling_policy_configuration"):
connection.put_scaling_policy(
- PolicyName=scaling_policy['PolicyName'],
- ServiceNamespace=scaling_policy['ServiceNamespace'],
- ResourceId=scaling_policy['ResourceId'],
- ScalableDimension=scaling_policy['ScalableDimension'],
- PolicyType=scaling_policy['PolicyType'],
- TargetTrackingScalingPolicyConfiguration=scaling_policy['TargetTrackingScalingPolicyConfiguration']
+ PolicyName=scaling_policy["PolicyName"],
+ ServiceNamespace=scaling_policy["ServiceNamespace"],
+ ResourceId=scaling_policy["ResourceId"],
+ ScalableDimension=scaling_policy["ScalableDimension"],
+ PolicyType=scaling_policy["PolicyType"],
+ TargetTrackingScalingPolicyConfiguration=scaling_policy["TargetTrackingScalingPolicyConfiguration"],
)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Failed to create scaling policy")
try:
response = connection.describe_scaling_policies(
- ServiceNamespace=module.params.get('service_namespace'),
- ResourceId=module.params.get('resource_id'),
- ScalableDimension=module.params.get('scalable_dimension'),
- PolicyNames=[module.params.get('policy_name')],
- MaxResults=1
+ ServiceNamespace=module.params.get("service_namespace"),
+ ResourceId=module.params.get("resource_id"),
+ ScalableDimension=module.params.get("scalable_dimension"),
+ PolicyNames=[module.params.get("policy_name")],
+ MaxResults=1,
)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Failed to describe scaling policies")
- if (response['ScalingPolicies']):
- snaked_response = camel_dict_to_snake_dict(response['ScalingPolicies'][0])
+ if response["ScalingPolicies"]:
+ snaked_response = camel_dict_to_snake_dict(response["ScalingPolicies"][0])
else:
snaked_response = {}
@@ -477,52 +478,63 @@ def create_scaling_policy(connection, module):
def main():
argument_spec = dict(
- state=dict(type='str', required=True, choices=['present', 'absent']),
- policy_name=dict(type='str', required=True),
- service_namespace=dict(type='str', required=True, choices=['appstream', 'dynamodb', 'ec2', 'ecs', 'elasticmapreduce']),
- resource_id=dict(type='str', required=True),
- scalable_dimension=dict(type='str',
- required=True,
- choices=['ecs:service:DesiredCount',
- 'ec2:spot-fleet-request:TargetCapacity',
- 'elasticmapreduce:instancegroup:InstanceCount',
- 'appstream:fleet:DesiredCapacity',
- 'dynamodb:table:ReadCapacityUnits',
- 'dynamodb:table:WriteCapacityUnits',
- 'dynamodb:index:ReadCapacityUnits',
- 'dynamodb:index:WriteCapacityUnits']),
- policy_type=dict(type='str', required=True, choices=['StepScaling', 'TargetTrackingScaling']),
- step_scaling_policy_configuration=dict(type='dict'),
+ state=dict(type="str", required=True, choices=["present", "absent"]),
+ policy_name=dict(type="str", required=True),
+ service_namespace=dict(
+ type="str", required=True, choices=["appstream", "dynamodb", "ec2", "ecs", "elasticmapreduce"]
+ ),
+ resource_id=dict(type="str", required=True),
+ scalable_dimension=dict(
+ type="str",
+ required=True,
+ choices=[
+ "ecs:service:DesiredCount",
+ "ec2:spot-fleet-request:TargetCapacity",
+ "elasticmapreduce:instancegroup:InstanceCount",
+ "appstream:fleet:DesiredCapacity",
+ "dynamodb:table:ReadCapacityUnits",
+ "dynamodb:table:WriteCapacityUnits",
+ "dynamodb:index:ReadCapacityUnits",
+ "dynamodb:index:WriteCapacityUnits",
+ ],
+ ),
+ policy_type=dict(type="str", required=True, choices=["StepScaling", "TargetTrackingScaling"]),
+ step_scaling_policy_configuration=dict(type="dict"),
target_tracking_scaling_policy_configuration=dict(
- type='dict',
+ type="dict",
options=dict(
- CustomizedMetricSpecification=dict(type='dict'),
- DisableScaleIn=dict(type='bool'),
- PredefinedMetricSpecification=dict(type='dict'),
- ScaleInCooldown=dict(type='int'),
- ScaleOutCooldown=dict(type='int'),
- TargetValue=dict(type='float'),
- )
+ CustomizedMetricSpecification=dict(type="dict"),
+ DisableScaleIn=dict(type="bool"),
+ PredefinedMetricSpecification=dict(type="dict"),
+ ScaleInCooldown=dict(type="int"),
+ ScaleOutCooldown=dict(type="int"),
+ TargetValue=dict(type="float"),
+ ),
),
- minimum_tasks=dict(type='int'),
- maximum_tasks=dict(type='int'),
- override_task_capacity=dict(type='bool'),
+ minimum_tasks=dict(type="int"),
+ maximum_tasks=dict(type="int"),
+ override_task_capacity=dict(type="bool"),
)
module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
- connection = module.client('application-autoscaling')
+ connection = module.client("application-autoscaling")
# Remove any target_tracking_scaling_policy_configuration suboptions that are None
policy_config_options = [
- 'CustomizedMetricSpecification', 'DisableScaleIn', 'PredefinedMetricSpecification', 'ScaleInCooldown', 'ScaleOutCooldown', 'TargetValue'
+ "CustomizedMetricSpecification",
+ "DisableScaleIn",
+ "PredefinedMetricSpecification",
+ "ScaleInCooldown",
+ "ScaleOutCooldown",
+ "TargetValue",
]
- if isinstance(module.params['target_tracking_scaling_policy_configuration'], dict):
+ if isinstance(module.params["target_tracking_scaling_policy_configuration"], dict):
for option in policy_config_options:
- if module.params['target_tracking_scaling_policy_configuration'][option] is None:
- module.params['target_tracking_scaling_policy_configuration'].pop(option)
+ if module.params["target_tracking_scaling_policy_configuration"][option] is None:
+ module.params["target_tracking_scaling_policy_configuration"].pop(option)
- if module.params.get("state") == 'present':
+ if module.params.get("state") == "present":
# A scalable target must be registered prior to creating a scaling policy
scalable_target_result = create_scalable_target(connection, module)
policy_result = create_scaling_policy(connection, module)
@@ -535,5 +547,5 @@ def main():
module.exit_json(**policy_result)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/autoscaling_complete_lifecycle_action.py b/ansible_collections/community/aws/plugins/modules/autoscaling_complete_lifecycle_action.py
index 8f585a102..94a8d031f 100644
--- a/ansible_collections/community/aws/plugins/modules/autoscaling_complete_lifecycle_action.py
+++ b/ansible_collections/community/aws/plugins/modules/autoscaling_complete_lifecycle_action.py
@@ -1,11 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: autoscaling_complete_lifecycle_action
short_description: Completes the lifecycle action of an instance
@@ -37,12 +36,12 @@ options:
type: str
required: true
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide for details.
# Complete the lifecycle action
- aws_asg_complete_lifecycle_action:
@@ -50,47 +49,47 @@ EXAMPLES = '''
lifecycle_hook_name: my-lifecycle-hook
lifecycle_action_result: CONTINUE
instance_id: i-123knm1l2312
-'''
+"""
-RETURN = '''
+RETURN = r"""
---
status:
description: How things went
returned: success
type: str
sample: ["OK"]
-'''
+"""
try:
import botocore
except ImportError:
pass # caught by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def main():
argument_spec = dict(
- asg_name=dict(required=True, type='str'),
- lifecycle_hook_name=dict(required=True, type='str'),
- lifecycle_action_result=dict(required=True, type='str', choices=['CONTINUE', 'ABANDON']),
- instance_id=dict(required=True, type='str')
+ asg_name=dict(required=True, type="str"),
+ lifecycle_hook_name=dict(required=True, type="str"),
+ lifecycle_action_result=dict(required=True, type="str", choices=["CONTINUE", "ABANDON"]),
+ instance_id=dict(required=True, type="str"),
)
module = AnsibleAWSModule(argument_spec=argument_spec)
- asg_name = module.params.get('asg_name')
- lifecycle_hook_name = module.params.get('lifecycle_hook_name')
- lifecycle_action_result = module.params.get('lifecycle_action_result')
- instance_id = module.params.get('instance_id')
+ asg_name = module.params.get("asg_name")
+ lifecycle_hook_name = module.params.get("lifecycle_hook_name")
+ lifecycle_action_result = module.params.get("lifecycle_action_result")
+ instance_id = module.params.get("instance_id")
- autoscaling = module.client('autoscaling')
+ autoscaling = module.client("autoscaling")
try:
results = autoscaling.complete_lifecycle_action(
LifecycleHookName=lifecycle_hook_name,
AutoScalingGroupName=asg_name,
LifecycleActionResult=lifecycle_action_result,
- InstanceId=instance_id
+ InstanceId=instance_id,
)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Failed to completes the lifecycle action")
@@ -98,5 +97,5 @@ def main():
module.exit_json(results=results)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/autoscaling_instance_refresh.py b/ansible_collections/community/aws/plugins/modules/autoscaling_instance_refresh.py
index 94c2bb38c..b301fea94 100644
--- a/ansible_collections/community/aws/plugins/modules/autoscaling_instance_refresh.py
+++ b/ansible_collections/community/aws/plugins/modules/autoscaling_instance_refresh.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: autoscaling_instance_refresh
version_added: 3.2.0
@@ -61,12 +59,12 @@ options:
type: int
type: dict
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide for details.
- name: Start a refresh
@@ -86,10 +84,9 @@ EXAMPLES = '''
preferences:
min_healthy_percentage: 91
instance_warmup: 60
+"""
-'''
-
-RETURN = '''
+RETURN = r"""
---
instance_refresh_id:
description: instance refresh id
@@ -137,20 +134,22 @@ instances_to_update:
returned: success
type: int
sample: 5
-'''
+"""
try:
- from botocore.exceptions import BotoCoreError, ClientError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
except ImportError:
pass # caught by AnsibleAWSModule
-
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import scrub_none_parameters
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
from ansible.module_utils.common.dict_transformations import snake_dict_to_camel_dict
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.transformation import scrub_none_parameters
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
+
def start_or_cancel_instance_refresh(conn, module):
"""
@@ -179,75 +178,75 @@ def start_or_cancel_instance_refresh(conn, module):
}
"""
- asg_state = module.params.get('state')
- asg_name = module.params.get('name')
- preferences = module.params.get('preferences')
+ asg_state = module.params.get("state")
+ asg_name = module.params.get("name")
+ preferences = module.params.get("preferences")
args = {}
- args['AutoScalingGroupName'] = asg_name
- if asg_state == 'started':
- args['Strategy'] = module.params.get('strategy')
+ args["AutoScalingGroupName"] = asg_name
+ if asg_state == "started":
+ args["Strategy"] = module.params.get("strategy")
if preferences:
- if asg_state == 'cancelled':
- module.fail_json(msg='can not pass preferences dict when canceling a refresh')
+ if asg_state == "cancelled":
+ module.fail_json(msg="can not pass preferences dict when canceling a refresh")
_prefs = scrub_none_parameters(preferences)
- args['Preferences'] = snake_dict_to_camel_dict(_prefs, capitalize_first=True)
+ args["Preferences"] = snake_dict_to_camel_dict(_prefs, capitalize_first=True)
cmd_invocations = {
- 'cancelled': conn.cancel_instance_refresh,
- 'started': conn.start_instance_refresh,
+ "cancelled": conn.cancel_instance_refresh,
+ "started": conn.start_instance_refresh,
}
try:
if module.check_mode:
- if asg_state == 'started':
- ongoing_refresh = conn.describe_instance_refreshes(AutoScalingGroupName=asg_name).get('InstanceRefreshes', '[]')
+ if asg_state == "started":
+ ongoing_refresh = conn.describe_instance_refreshes(AutoScalingGroupName=asg_name).get(
+ "InstanceRefreshes", "[]"
+ )
if ongoing_refresh:
- module.exit_json(changed=False, msg='In check_mode - Instance Refresh is already in progress, can not start new instance refresh.')
+ module.exit_json(
+ changed=False,
+ msg="In check_mode - Instance Refresh is already in progress, can not start new instance refresh.",
+ )
else:
- module.exit_json(changed=True, msg='Would have started instance refresh if not in check mode.')
- elif asg_state == 'cancelled':
- ongoing_refresh = conn.describe_instance_refreshes(AutoScalingGroupName=asg_name).get('InstanceRefreshes', '[]')[0]
- if ongoing_refresh.get('Status', '') in ['Cancelling', 'Cancelled']:
- module.exit_json(changed=False, msg='In check_mode - Instance Refresh already cancelled or is pending cancellation.')
+ module.exit_json(changed=True, msg="Would have started instance refresh if not in check mode.")
+ elif asg_state == "cancelled":
+ ongoing_refresh = conn.describe_instance_refreshes(AutoScalingGroupName=asg_name).get(
+ "InstanceRefreshes", "[]"
+ )[0]
+ if ongoing_refresh.get("Status", "") in ["Cancelling", "Cancelled"]:
+ module.exit_json(
+ changed=False,
+ msg="In check_mode - Instance Refresh already cancelled or is pending cancellation.",
+ )
elif not ongoing_refresh:
- module.exit_json(chaned=False, msg='In check_mode - No active referesh found, nothing to cancel.')
+ module.exit_json(chaned=False, msg="In check_mode - No active referesh found, nothing to cancel.")
else:
- module.exit_json(changed=True, msg='Would have cancelled instance refresh if not in check mode.')
+ module.exit_json(changed=True, msg="Would have cancelled instance refresh if not in check mode.")
result = cmd_invocations[asg_state](aws_retry=True, **args)
- instance_refreshes = conn.describe_instance_refreshes(AutoScalingGroupName=asg_name, InstanceRefreshIds=[result['InstanceRefreshId']])
- result = dict(
- instance_refreshes=camel_dict_to_snake_dict(instance_refreshes['InstanceRefreshes'][0])
+ instance_refreshes = conn.describe_instance_refreshes(
+ AutoScalingGroupName=asg_name, InstanceRefreshIds=[result["InstanceRefreshId"]]
)
+ result = dict(instance_refreshes=camel_dict_to_snake_dict(instance_refreshes["InstanceRefreshes"][0]))
return module.exit_json(**result)
except (BotoCoreError, ClientError) as e:
- module.fail_json_aws(
- e,
- msg='Failed to {0} InstanceRefresh'.format(
- asg_state.replace('ed', '')
- )
- )
+ module.fail_json_aws(e, msg=f"Failed to {asg_state.replace('ed', '')} InstanceRefresh")
def main():
-
argument_spec = dict(
state=dict(
- type='str',
+ type="str",
required=True,
- choices=['started', 'cancelled'],
+ choices=["started", "cancelled"],
),
name=dict(required=True),
- strategy=dict(
- type='str',
- default='Rolling',
- required=False
- ),
+ strategy=dict(type="str", default="Rolling", required=False),
preferences=dict(
- type='dict',
+ type="dict",
required=False,
options=dict(
- min_healthy_percentage=dict(type='int', default=90),
- instance_warmup=dict(type='int'),
- )
+ min_healthy_percentage=dict(type="int", default=90),
+ instance_warmup=dict(type="int"),
+ ),
),
)
@@ -256,15 +255,12 @@ def main():
supports_check_mode=True,
)
autoscaling = module.client(
- 'autoscaling',
- retry_decorator=AWSRetry.jittered_backoff(
- retries=10,
- catch_extra_error_codes=['InstanceRefreshInProgress']
- )
+ "autoscaling",
+ retry_decorator=AWSRetry.jittered_backoff(retries=10, catch_extra_error_codes=["InstanceRefreshInProgress"]),
)
start_or_cancel_instance_refresh(autoscaling, module)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/autoscaling_instance_refresh_info.py b/ansible_collections/community/aws/plugins/modules/autoscaling_instance_refresh_info.py
index 3037d0b52..639940b1b 100644
--- a/ansible_collections/community/aws/plugins/modules/autoscaling_instance_refresh_info.py
+++ b/ansible_collections/community/aws/plugins/modules/autoscaling_instance_refresh_info.py
@@ -1,14 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-
-
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: autoscaling_instance_refresh_info
version_added: 3.2.0
@@ -18,7 +14,8 @@ description:
- You can determine the status of a request by looking at the I(status) parameter.
- Prior to release 5.0.0 this module was called C(community.aws.ec2_asg_instance_refresh_info).
The usage did not change.
-author: "Dan Khersonsky (@danquixote)"
+author:
+ - "Dan Khersonsky (@danquixote)"
options:
name:
description:
@@ -41,12 +38,12 @@ options:
type: int
required: false
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide for details.
- name: Find an refresh by ASG name
@@ -70,9 +67,9 @@ EXAMPLES = '''
name: somename-asg
next_token: 'some-token-123'
register: asgs
-'''
+"""
-RETURN = '''
+RETURN = r"""
---
instance_refresh_id:
description: instance refresh id
@@ -120,16 +117,19 @@ instances_to_update:
returned: success
type: int
sample: 5
-'''
+"""
try:
- from botocore.exceptions import BotoCoreError, ClientError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
except ImportError:
pass # caught by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def find_asg_instance_refreshes(conn, module):
@@ -158,51 +158,51 @@ def find_asg_instance_refreshes(conn, module):
],
'next_token': 'string'
}
- """
+ """
- asg_name = module.params.get('name')
- asg_ids = module.params.get('ids')
- asg_next_token = module.params.get('next_token')
- asg_max_records = module.params.get('max_records')
+ asg_name = module.params.get("name")
+ asg_ids = module.params.get("ids")
+ asg_next_token = module.params.get("next_token")
+ asg_max_records = module.params.get("max_records")
args = {}
- args['AutoScalingGroupName'] = asg_name
+ args["AutoScalingGroupName"] = asg_name
if asg_ids:
- args['InstanceRefreshIds'] = asg_ids
+ args["InstanceRefreshIds"] = asg_ids
if asg_next_token:
- args['NextToken'] = asg_next_token
+ args["NextToken"] = asg_next_token
if asg_max_records:
- args['MaxRecords'] = asg_max_records
+ args["MaxRecords"] = asg_max_records
try:
instance_refreshes_result = {}
response = conn.describe_instance_refreshes(**args)
- if 'InstanceRefreshes' in response:
+ if "InstanceRefreshes" in response:
instance_refreshes_dict = dict(
- instance_refreshes=response['InstanceRefreshes'], next_token=response.get('next_token', ''))
- instance_refreshes_result = camel_dict_to_snake_dict(
- instance_refreshes_dict)
+ instance_refreshes=response["InstanceRefreshes"], next_token=response.get("next_token", "")
+ )
+ instance_refreshes_result = camel_dict_to_snake_dict(instance_refreshes_dict)
- while 'NextToken' in response:
- args['NextToken'] = response['NextToken']
+ while "NextToken" in response:
+ args["NextToken"] = response["NextToken"]
response = conn.describe_instance_refreshes(**args)
- if 'InstanceRefreshes' in response:
- instance_refreshes_dict = camel_dict_to_snake_dict(dict(
- instance_refreshes=response['InstanceRefreshes'], next_token=response.get('next_token', '')))
+ if "InstanceRefreshes" in response:
+ instance_refreshes_dict = camel_dict_to_snake_dict(
+ dict(instance_refreshes=response["InstanceRefreshes"], next_token=response.get("next_token", ""))
+ )
instance_refreshes_result.update(instance_refreshes_dict)
return module.exit_json(**instance_refreshes_result)
except (BotoCoreError, ClientError) as e:
- module.fail_json_aws(e, msg='Failed to describe InstanceRefreshes')
+ module.fail_json_aws(e, msg="Failed to describe InstanceRefreshes")
def main():
-
argument_spec = dict(
- name=dict(required=True, type='str'),
- ids=dict(required=False, default=[], elements='str', type='list'),
- next_token=dict(required=False, default=None, type='str', no_log=True),
- max_records=dict(required=False, type='int'),
+ name=dict(required=True, type="str"),
+ ids=dict(required=False, default=[], elements="str", type="list"),
+ next_token=dict(required=False, default=None, type="str", no_log=True),
+ max_records=dict(required=False, type="int"),
)
module = AnsibleAWSModule(
@@ -210,12 +210,9 @@ def main():
supports_check_mode=True,
)
- autoscaling = module.client(
- 'autoscaling',
- retry_decorator=AWSRetry.jittered_backoff(retries=10)
- )
+ autoscaling = module.client("autoscaling", retry_decorator=AWSRetry.jittered_backoff(retries=10))
find_asg_instance_refreshes(autoscaling, module)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/autoscaling_launch_config.py b/ansible_collections/community/aws/plugins/modules/autoscaling_launch_config.py
index 1b13d1027..78b7ee233 100644
--- a/ansible_collections/community/aws/plugins/modules/autoscaling_launch_config.py
+++ b/ansible_collections/community/aws/plugins/modules/autoscaling_launch_config.py
@@ -1,13 +1,10 @@
#!/usr/bin/python
-# This file is part of Ansible
-#
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
+# -*- coding: utf-8 -*-
+# Copyright: Contributors to the Ansible project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: autoscaling_launch_config
version_added: 1.0.0
@@ -183,80 +180,86 @@ options:
type: str
choices: ['default', 'dedicated']
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
- name: create a launch configuration with an encrypted volume
community.aws.autoscaling_launch_config:
name: special
image_id: ami-XXX
key_name: default
- security_groups: ['group', 'group2' ]
+ security_groups:
+ - 'group'
+ - 'group2'
instance_type: t1.micro
volumes:
- - device_name: /dev/sda1
- volume_size: 100
- volume_type: io1
- iops: 3000
- delete_on_termination: true
- encrypted: true
- - device_name: /dev/sdb
- ephemeral: ephemeral0
+ - device_name: /dev/sda1
+ volume_size: 100
+ volume_type: io1
+ iops: 3000
+ delete_on_termination: true
+ encrypted: true
+ - device_name: /dev/sdb
+ ephemeral: ephemeral0
- name: create a launch configuration using a running instance id as a basis
community.aws.autoscaling_launch_config:
name: special
instance_id: i-00a48b207ec59e948
key_name: default
- security_groups: ['launch-wizard-2' ]
+ security_groups:
+ - 'launch-wizard-2'
volumes:
- - device_name: /dev/sda1
- volume_size: 120
- volume_type: io1
- iops: 3000
- delete_on_termination: true
+ - device_name: /dev/sda1
+ volume_size: 120
+ volume_type: io1
+ iops: 3000
+ delete_on_termination: true
- name: create a launch configuration to omit the /dev/sdf EBS device that is included in the AMI image
community.aws.autoscaling_launch_config:
name: special
image_id: ami-XXX
key_name: default
- security_groups: ['group', 'group2' ]
+ security_groups:
+ - 'group'
+ - 'group2'
instance_type: t1.micro
volumes:
- - device_name: /dev/sdf
- no_device: true
+ - device_name: /dev/sdf
+ no_device: true
- name: Use EBS snapshot ID for volume
block:
- - name: Set Volume Facts
- ansible.builtin.set_fact:
- volumes:
- - device_name: /dev/sda1
- volume_size: 20
- ebs:
- snapshot: snap-XXXX
- volume_type: gp2
- delete_on_termination: true
- encrypted: false
-
- - name: Create launch configuration
- community.aws.autoscaling_launch_config:
- name: lc1
- image_id: ami-xxxx
- assign_public_ip: true
- instance_type: t2.medium
- key_name: my-key
- security_groups: "['sg-xxxx']"
- volumes: "{{ volumes }}"
- register: lc_info
-'''
-
-RETURN = r'''
+ - name: Set Volume Facts
+ ansible.builtin.set_fact:
+ volumes:
+ - device_name: /dev/sda1
+ volume_size: 20
+ ebs:
+ snapshot: snap-XXXX
+ volume_type: gp2
+ delete_on_termination: true
+ encrypted: false
+
+ - name: Create launch configuration
+ community.aws.autoscaling_launch_config:
+ name: lc1
+ image_id: ami-xxxx
+ assign_public_ip: true
+ instance_type: t2.medium
+ key_name: my-key
+ security_groups:
+ - 'sg-xxxx'
+ volumes: "{{ volumes }}"
+ register: lc_info
+"""
+
+RETURN = r"""
arn:
description: The Amazon Resource Name of the launch configuration.
returned: when I(state=present)
@@ -440,7 +443,7 @@ security_groups:
type: list
sample:
- sg-5e27db2f
-'''
+"""
import traceback
@@ -454,181 +457,220 @@ from ansible.module_utils._text import to_text
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
from ansible.module_utils.common.dict_transformations import snake_dict_to_camel_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import get_ec2_security_group_ids_from_names
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
+
def create_block_device_meta(module, volume):
- if 'snapshot' not in volume and 'ephemeral' not in volume and 'no_device' not in volume:
- if 'volume_size' not in volume:
- module.fail_json(msg='Size must be specified when creating a new volume or modifying the root volume')
- if 'snapshot' in volume:
- if volume.get('volume_type') == 'io1' and 'iops' not in volume:
- module.fail_json(msg='io1 volumes must have an iops value set')
- if 'ephemeral' in volume:
- if 'snapshot' in volume:
- module.fail_json(msg='Cannot set both ephemeral and snapshot')
+ if "snapshot" not in volume and "ephemeral" not in volume and "no_device" not in volume:
+ if "volume_size" not in volume:
+ module.fail_json(msg="Size must be specified when creating a new volume or modifying the root volume")
+ if "snapshot" in volume:
+ if volume.get("volume_type") == "io1" and "iops" not in volume:
+ module.fail_json(msg="io1 volumes must have an iops value set")
+ if "ephemeral" in volume:
+ if "snapshot" in volume:
+ module.fail_json(msg="Cannot set both ephemeral and snapshot")
return_object = {}
- if 'ephemeral' in volume:
- return_object['VirtualName'] = volume.get('ephemeral')
+ if "ephemeral" in volume:
+ return_object["VirtualName"] = volume.get("ephemeral")
- if 'device_name' in volume:
- return_object['DeviceName'] = volume.get('device_name')
+ if "device_name" in volume:
+ return_object["DeviceName"] = volume.get("device_name")
- if 'no_device' in volume:
- return_object['NoDevice'] = volume.get('no_device')
+ if "no_device" in volume:
+ return_object["NoDevice"] = volume.get("no_device")
- if any(key in volume for key in ['snapshot', 'volume_size', 'volume_type', 'delete_on_termination', 'iops', 'throughput', 'encrypted']):
- return_object['Ebs'] = {}
+ if any(
+ key in volume
+ for key in [
+ "snapshot",
+ "volume_size",
+ "volume_type",
+ "delete_on_termination",
+ "iops",
+ "throughput",
+ "encrypted",
+ ]
+ ):
+ return_object["Ebs"] = {}
- if 'snapshot' in volume:
- return_object['Ebs']['SnapshotId'] = volume.get('snapshot')
+ if "snapshot" in volume:
+ return_object["Ebs"]["SnapshotId"] = volume.get("snapshot")
- if 'volume_size' in volume:
- return_object['Ebs']['VolumeSize'] = int(volume.get('volume_size', 0))
+ if "volume_size" in volume:
+ return_object["Ebs"]["VolumeSize"] = int(volume.get("volume_size", 0))
- if 'volume_type' in volume:
- return_object['Ebs']['VolumeType'] = volume.get('volume_type')
+ if "volume_type" in volume:
+ return_object["Ebs"]["VolumeType"] = volume.get("volume_type")
- if 'delete_on_termination' in volume:
- return_object['Ebs']['DeleteOnTermination'] = volume.get('delete_on_termination', False)
+ if "delete_on_termination" in volume:
+ return_object["Ebs"]["DeleteOnTermination"] = volume.get("delete_on_termination", False)
- if 'iops' in volume:
- return_object['Ebs']['Iops'] = volume.get('iops')
+ if "iops" in volume:
+ return_object["Ebs"]["Iops"] = volume.get("iops")
- if 'throughput' in volume:
- if volume.get('volume_type') != 'gp3':
- module.fail_json(msg='The throughput parameter is supported only for GP3 volumes.')
- return_object['Ebs']['Throughput'] = volume.get('throughput')
+ if "throughput" in volume:
+ if volume.get("volume_type") != "gp3":
+ module.fail_json(msg="The throughput parameter is supported only for GP3 volumes.")
+ return_object["Ebs"]["Throughput"] = volume.get("throughput")
- if 'encrypted' in volume:
- return_object['Ebs']['Encrypted'] = volume.get('encrypted')
+ if "encrypted" in volume:
+ return_object["Ebs"]["Encrypted"] = volume.get("encrypted")
return return_object
def create_launch_config(connection, module):
- name = module.params.get('name')
- vpc_id = module.params.get('vpc_id')
+ name = module.params.get("name")
+ vpc_id = module.params.get("vpc_id")
try:
- ec2_connection = module.client('ec2')
+ ec2_connection = module.client("ec2")
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to connect to AWS')
+ module.fail_json_aws(e, msg="Failed to connect to AWS")
try:
- security_groups = get_ec2_security_group_ids_from_names(module.params.get('security_groups'), ec2_connection, vpc_id=vpc_id, boto3=True)
+ security_groups = get_ec2_security_group_ids_from_names(
+ module.params.get("security_groups"), ec2_connection, vpc_id=vpc_id, boto3=True
+ )
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to get Security Group IDs')
+ module.fail_json_aws(e, msg="Failed to get Security Group IDs")
except ValueError as e:
module.fail_json(msg="Failed to get Security Group IDs", exception=traceback.format_exc())
- user_data = module.params.get('user_data')
- user_data_path = module.params.get('user_data_path')
- volumes = module.params['volumes']
- instance_monitoring = module.params.get('instance_monitoring')
- assign_public_ip = module.params.get('assign_public_ip')
- instance_profile_name = module.params.get('instance_profile_name')
- ebs_optimized = module.params.get('ebs_optimized')
- classic_link_vpc_id = module.params.get('classic_link_vpc_id')
- classic_link_vpc_security_groups = module.params.get('classic_link_vpc_security_groups')
+ user_data = module.params.get("user_data")
+ user_data_path = module.params.get("user_data_path")
+ volumes = module.params["volumes"]
+ instance_monitoring = module.params.get("instance_monitoring")
+ assign_public_ip = module.params.get("assign_public_ip")
+ instance_profile_name = module.params.get("instance_profile_name")
+ ebs_optimized = module.params.get("ebs_optimized")
+ classic_link_vpc_id = module.params.get("classic_link_vpc_id")
+ classic_link_vpc_security_groups = module.params.get("classic_link_vpc_security_groups")
block_device_mapping = []
- convert_list = ['image_id', 'instance_type', 'instance_type', 'instance_id', 'placement_tenancy', 'key_name', 'kernel_id', 'ramdisk_id', 'spot_price']
-
- launch_config = (snake_dict_to_camel_dict(dict((k.capitalize(), str(v)) for k, v in module.params.items() if v is not None and k in convert_list)))
+ convert_list = [
+ "image_id",
+ "instance_type",
+ "instance_type",
+ "instance_id",
+ "placement_tenancy",
+ "key_name",
+ "kernel_id",
+ "ramdisk_id",
+ "spot_price",
+ ]
+
+ launch_config = snake_dict_to_camel_dict(
+ dict((k.capitalize(), str(v)) for k, v in module.params.items() if v is not None and k in convert_list)
+ )
if user_data_path:
try:
- with open(user_data_path, 'r') as user_data_file:
+ with open(user_data_path, "r") as user_data_file:
user_data = user_data_file.read()
except IOError as e:
module.fail_json(msg="Failed to open file for reading", exception=traceback.format_exc())
if volumes:
for volume in volumes:
- if 'device_name' not in volume:
- module.fail_json(msg='Device name must be set for volume')
+ if "device_name" not in volume:
+ module.fail_json(msg="Device name must be set for volume")
# Minimum volume size is 1GiB. We'll use volume size explicitly set to 0 to be a signal not to create this volume
- if 'volume_size' not in volume or int(volume['volume_size']) > 0:
+ if "volume_size" not in volume or int(volume["volume_size"]) > 0:
block_device_mapping.append(create_block_device_meta(module, volume))
try:
- launch_configs = connection.describe_launch_configurations(LaunchConfigurationNames=[name]).get('LaunchConfigurations')
+ launch_configs = connection.describe_launch_configurations(LaunchConfigurationNames=[name]).get(
+ "LaunchConfigurations"
+ )
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Failed to describe launch configuration by name")
changed = False
result = {}
- launch_config['LaunchConfigurationName'] = name
+ launch_config["LaunchConfigurationName"] = name
if security_groups is not None:
- launch_config['SecurityGroups'] = security_groups
+ launch_config["SecurityGroups"] = security_groups
if classic_link_vpc_id is not None:
- launch_config['ClassicLinkVPCId'] = classic_link_vpc_id
+ launch_config["ClassicLinkVPCId"] = classic_link_vpc_id
if instance_monitoring is not None:
- launch_config['InstanceMonitoring'] = {'Enabled': instance_monitoring}
+ launch_config["InstanceMonitoring"] = {"Enabled": instance_monitoring}
if classic_link_vpc_security_groups is not None:
- launch_config['ClassicLinkVPCSecurityGroups'] = classic_link_vpc_security_groups
+ launch_config["ClassicLinkVPCSecurityGroups"] = classic_link_vpc_security_groups
if block_device_mapping:
- launch_config['BlockDeviceMappings'] = block_device_mapping
+ launch_config["BlockDeviceMappings"] = block_device_mapping
if instance_profile_name is not None:
- launch_config['IamInstanceProfile'] = instance_profile_name
+ launch_config["IamInstanceProfile"] = instance_profile_name
if assign_public_ip is not None:
- launch_config['AssociatePublicIpAddress'] = assign_public_ip
+ launch_config["AssociatePublicIpAddress"] = assign_public_ip
if user_data is not None:
- launch_config['UserData'] = user_data
+ launch_config["UserData"] = user_data
if ebs_optimized is not None:
- launch_config['EbsOptimized'] = ebs_optimized
+ launch_config["EbsOptimized"] = ebs_optimized
if len(launch_configs) == 0:
try:
connection.create_launch_configuration(**launch_config)
- launch_configs = connection.describe_launch_configurations(LaunchConfigurationNames=[name]).get('LaunchConfigurations')
+ launch_configs = connection.describe_launch_configurations(LaunchConfigurationNames=[name]).get(
+ "LaunchConfigurations"
+ )
changed = True
if launch_configs:
launch_config = launch_configs[0]
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Failed to create launch configuration")
- result = (dict((k, v) for k, v in launch_config.items()
- if k not in ['Connection', 'CreatedTime', 'InstanceMonitoring', 'BlockDeviceMappings']))
+ result = dict(
+ (k, v)
+ for k, v in launch_config.items()
+ if k not in ["Connection", "CreatedTime", "InstanceMonitoring", "BlockDeviceMappings"]
+ )
- result['CreatedTime'] = to_text(launch_config.get('CreatedTime'))
+ result["CreatedTime"] = to_text(launch_config.get("CreatedTime"))
try:
- result['InstanceMonitoring'] = module.boolean(launch_config.get('InstanceMonitoring').get('Enabled'))
+ result["InstanceMonitoring"] = module.boolean(launch_config.get("InstanceMonitoring").get("Enabled"))
except AttributeError:
- result['InstanceMonitoring'] = False
-
- result['BlockDeviceMappings'] = []
-
- for block_device_mapping in launch_config.get('BlockDeviceMappings', []):
- result['BlockDeviceMappings'].append(dict(device_name=block_device_mapping.get('DeviceName'), virtual_name=block_device_mapping.get('VirtualName')))
- if block_device_mapping.get('Ebs') is not None:
- result['BlockDeviceMappings'][-1]['ebs'] = dict(
- snapshot_id=block_device_mapping.get('Ebs').get('SnapshotId'), volume_size=block_device_mapping.get('Ebs').get('VolumeSize'))
+ result["InstanceMonitoring"] = False
+
+ result["BlockDeviceMappings"] = []
+
+ for block_device_mapping in launch_config.get("BlockDeviceMappings", []):
+ result["BlockDeviceMappings"].append(
+ dict(
+ device_name=block_device_mapping.get("DeviceName"), virtual_name=block_device_mapping.get("VirtualName")
+ )
+ )
+ if block_device_mapping.get("Ebs") is not None:
+ result["BlockDeviceMappings"][-1]["ebs"] = dict(
+ snapshot_id=block_device_mapping.get("Ebs").get("SnapshotId"),
+ volume_size=block_device_mapping.get("Ebs").get("VolumeSize"),
+ )
if user_data_path:
- result['UserData'] = "hidden" # Otherwise, we dump binary to the user's terminal
+ result["UserData"] = "hidden" # Otherwise, we dump binary to the user's terminal
return_object = {
- 'Name': result.get('LaunchConfigurationName'),
- 'CreatedTime': result.get('CreatedTime'),
- 'ImageId': result.get('ImageId'),
- 'Arn': result.get('LaunchConfigurationARN'),
- 'SecurityGroups': result.get('SecurityGroups'),
- 'InstanceType': result.get('InstanceType'),
- 'Result': result
+ "Name": result.get("LaunchConfigurationName"),
+ "CreatedTime": result.get("CreatedTime"),
+ "ImageId": result.get("ImageId"),
+ "Arn": result.get("LaunchConfigurationARN"),
+ "SecurityGroups": result.get("SecurityGroups"),
+ "InstanceType": result.get("InstanceType"),
+ "Result": result,
}
module.exit_json(changed=changed, **camel_dict_to_snake_dict(return_object))
@@ -636,10 +678,14 @@ def create_launch_config(connection, module):
def delete_launch_config(connection, module):
try:
- name = module.params.get('name')
- launch_configs = connection.describe_launch_configurations(LaunchConfigurationNames=[name]).get('LaunchConfigurations')
+ name = module.params.get("name")
+ launch_configs = connection.describe_launch_configurations(LaunchConfigurationNames=[name]).get(
+ "LaunchConfigurations"
+ )
if launch_configs:
- connection.delete_launch_configuration(LaunchConfigurationName=launch_configs[0].get('LaunchConfigurationName'))
+ connection.delete_launch_configuration(
+ LaunchConfigurationName=launch_configs[0].get("LaunchConfigurationName")
+ )
module.exit_json(changed=True)
else:
module.exit_json(changed=False)
@@ -653,42 +699,42 @@ def main():
image_id=dict(),
instance_id=dict(),
key_name=dict(),
- security_groups=dict(default=[], type='list', elements='str'),
+ security_groups=dict(default=[], type="list", elements="str"),
user_data=dict(),
- user_data_path=dict(type='path'),
+ user_data_path=dict(type="path"),
kernel_id=dict(),
- volumes=dict(type='list', elements='dict'),
+ volumes=dict(type="list", elements="dict"),
instance_type=dict(),
- state=dict(default='present', choices=['present', 'absent']),
- spot_price=dict(type='float'),
+ state=dict(default="present", choices=["present", "absent"]),
+ spot_price=dict(type="float"),
ramdisk_id=dict(),
instance_profile_name=dict(),
- ebs_optimized=dict(default=False, type='bool'),
- instance_monitoring=dict(default=False, type='bool'),
- assign_public_ip=dict(type='bool'),
- classic_link_vpc_security_groups=dict(type='list', elements='str'),
+ ebs_optimized=dict(default=False, type="bool"),
+ instance_monitoring=dict(default=False, type="bool"),
+ assign_public_ip=dict(type="bool"),
+ classic_link_vpc_security_groups=dict(type="list", elements="str"),
classic_link_vpc_id=dict(),
vpc_id=dict(),
- placement_tenancy=dict(choices=['default', 'dedicated'])
+ placement_tenancy=dict(choices=["default", "dedicated"]),
)
module = AnsibleAWSModule(
argument_spec=argument_spec,
- mutually_exclusive=[['user_data', 'user_data_path']],
+ mutually_exclusive=[["user_data", "user_data_path"]],
)
try:
- connection = module.client('autoscaling')
+ connection = module.client("autoscaling")
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="unable to establish connection")
- state = module.params.get('state')
+ state = module.params.get("state")
- if state == 'present':
+ if state == "present":
create_launch_config(connection, module)
- elif state == 'absent':
+ elif state == "absent":
delete_launch_config(connection, module)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/autoscaling_launch_config_find.py b/ansible_collections/community/aws/plugins/modules/autoscaling_launch_config_find.py
index ae8f187c0..037c21ed9 100644
--- a/ansible_collections/community/aws/plugins/modules/autoscaling_launch_config_find.py
+++ b/ansible_collections/community/aws/plugins/modules/autoscaling_launch_config_find.py
@@ -1,14 +1,10 @@
#!/usr/bin/python
-# encoding: utf-8
+# -*- coding: utf-8 -*-
# (c) 2015, Jose Armesto <jose@armesto.net>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: autoscaling_launch_config_find
version_added: 1.0.0
@@ -40,12 +36,12 @@ options:
- Corresponds to Python slice notation like list[:limit].
type: int
extends_documentation_fragment:
- - amazon.aws.ec2
- - amazon.aws.aws
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide for details.
- name: Search for the Launch Configurations that start with "app"
@@ -53,9 +49,9 @@ EXAMPLES = '''
name_regex: app.*
sort_order: descending
limit: 2
-'''
+"""
-RETURN = '''
+RETURN = r"""
image_id:
description: AMI id
returned: when Launch Configuration was found
@@ -132,7 +128,8 @@ associate_public_address:
type: bool
sample: True
...
-'''
+"""
+
import re
try:
@@ -140,54 +137,50 @@ try:
except ImportError:
pass # Handled by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def find_launch_configs(client, module):
- name_regex = module.params.get('name_regex')
- sort_order = module.params.get('sort_order')
- limit = module.params.get('limit')
+ name_regex = module.params.get("name_regex")
+ sort_order = module.params.get("sort_order")
+ limit = module.params.get("limit")
- paginator = client.get_paginator('describe_launch_configurations')
+ paginator = client.get_paginator("describe_launch_configurations")
- response_iterator = paginator.paginate(
- PaginationConfig={
- 'MaxItems': 1000,
- 'PageSize': 100
- }
- )
+ response_iterator = paginator.paginate(PaginationConfig={"MaxItems": 1000, "PageSize": 100})
results = []
for response in response_iterator:
- response['LaunchConfigurations'] = filter(lambda lc: re.compile(name_regex).match(lc['LaunchConfigurationName']),
- response['LaunchConfigurations'])
+ response["LaunchConfigurations"] = filter(
+ lambda lc: re.compile(name_regex).match(lc["LaunchConfigurationName"]), response["LaunchConfigurations"]
+ )
- for lc in response['LaunchConfigurations']:
+ for lc in response["LaunchConfigurations"]:
data = {
- 'name': lc['LaunchConfigurationName'],
- 'arn': lc['LaunchConfigurationARN'],
- 'created_time': lc['CreatedTime'],
- 'user_data': lc['UserData'],
- 'instance_type': lc['InstanceType'],
- 'image_id': lc['ImageId'],
- 'ebs_optimized': lc['EbsOptimized'],
- 'instance_monitoring': lc['InstanceMonitoring'],
- 'classic_link_vpc_security_groups': lc['ClassicLinkVPCSecurityGroups'],
- 'block_device_mappings': lc['BlockDeviceMappings'],
- 'keyname': lc['KeyName'],
- 'security_groups': lc['SecurityGroups'],
- 'kernel_id': lc['KernelId'],
- 'ram_disk_id': lc['RamdiskId'],
- 'associate_public_address': lc.get('AssociatePublicIpAddress', False),
+ "name": lc["LaunchConfigurationName"],
+ "arn": lc["LaunchConfigurationARN"],
+ "created_time": lc["CreatedTime"],
+ "user_data": lc["UserData"],
+ "instance_type": lc["InstanceType"],
+ "image_id": lc["ImageId"],
+ "ebs_optimized": lc["EbsOptimized"],
+ "instance_monitoring": lc["InstanceMonitoring"],
+ "classic_link_vpc_security_groups": lc["ClassicLinkVPCSecurityGroups"],
+ "block_device_mappings": lc["BlockDeviceMappings"],
+ "keyname": lc["KeyName"],
+ "security_groups": lc["SecurityGroups"],
+ "kernel_id": lc["KernelId"],
+ "ram_disk_id": lc["RamdiskId"],
+ "associate_public_address": lc.get("AssociatePublicIpAddress", False),
}
results.append(data)
- results.sort(key=lambda e: e['name'], reverse=(sort_order == 'descending'))
+ results.sort(key=lambda e: e["name"], reverse=(sort_order == "descending"))
if limit:
- results = results[:int(limit)]
+ results = results[:int(limit)] # fmt: skip
module.exit_json(changed=False, results=results)
@@ -195,8 +188,8 @@ def find_launch_configs(client, module):
def main():
argument_spec = dict(
name_regex=dict(required=True),
- sort_order=dict(required=False, default='ascending', choices=['ascending', 'descending']),
- limit=dict(required=False, type='int'),
+ sort_order=dict(required=False, default="ascending", choices=["ascending", "descending"]),
+ limit=dict(required=False, type="int"),
)
module = AnsibleAWSModule(
@@ -204,12 +197,12 @@ def main():
)
try:
- client = module.client('autoscaling')
+ client = module.client("autoscaling")
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to connect to AWS')
+ module.fail_json_aws(e, msg="Failed to connect to AWS")
find_launch_configs(client, module)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/autoscaling_launch_config_info.py b/ansible_collections/community/aws/plugins/modules/autoscaling_launch_config_info.py
index 1c98d7588..f5123c2ef 100644
--- a/ansible_collections/community/aws/plugins/modules/autoscaling_launch_config_info.py
+++ b/ansible_collections/community/aws/plugins/modules/autoscaling_launch_config_info.py
@@ -1,13 +1,10 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: autoscaling_launch_config_info
version_added: 1.0.0
@@ -48,12 +45,12 @@ options:
- Corresponds to Python slice notation.
type: int
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide for details.
- name: Gather information about all launch configurations
@@ -67,9 +64,9 @@ EXAMPLES = r'''
community.aws.autoscaling_launch_config_info:
sort: created_time
sort_order: descending
-'''
+"""
-RETURN = r'''
+RETURN = r"""
block_device_mapping:
description: Block device mapping for the instances of launch configuration.
type: list
@@ -149,43 +146,41 @@ user_data:
description: User data available.
type: str
returned: always
-'''
+"""
try:
import botocore
- from botocore.exceptions import ClientError
except ImportError:
pass # Handled by AnsibleAWSModule
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def list_launch_configs(connection, module):
-
launch_config_name = module.params.get("name")
- sort = module.params.get('sort')
- sort_order = module.params.get('sort_order')
- sort_start = module.params.get('sort_start')
- sort_end = module.params.get('sort_end')
+ sort = module.params.get("sort")
+ sort_order = module.params.get("sort_order")
+ sort_start = module.params.get("sort_start")
+ sort_end = module.params.get("sort_end")
try:
- pg = connection.get_paginator('describe_launch_configurations')
+ pg = connection.get_paginator("describe_launch_configurations")
launch_configs = pg.paginate(LaunchConfigurationNames=launch_config_name).build_full_result()
- except ClientError as e:
+ except botocore.exceptions.ClientError as e:
module.fail_json_aws(e, msg="Failed to list launch configs")
snaked_launch_configs = []
- for launch_config in launch_configs['LaunchConfigurations']:
+ for launch_config in launch_configs["LaunchConfigurations"]:
snaked_launch_configs.append(camel_dict_to_snake_dict(launch_config))
for launch_config in snaked_launch_configs:
- if 'CreatedTime' in launch_config:
- launch_config['CreatedTime'] = str(launch_config['CreatedTime'])
+ if "CreatedTime" in launch_config:
+ launch_config["CreatedTime"] = str(launch_config["CreatedTime"])
if sort:
- snaked_launch_configs.sort(key=lambda e: e[sort], reverse=(sort_order == 'descending'))
+ snaked_launch_configs.sort(key=lambda e: e[sort], reverse=(sort_order == "descending"))
if sort and sort_start and sort_end:
snaked_launch_configs = snaked_launch_configs[sort_start:sort_end]
@@ -199,13 +194,23 @@ def list_launch_configs(connection, module):
def main():
argument_spec = dict(
- name=dict(required=False, default=[], type='list', elements='str'),
- sort=dict(required=False, default=None,
- choices=['launch_configuration_name', 'image_id', 'created_time', 'instance_type', 'kernel_id', 'ramdisk_id', 'key_name']),
- sort_order=dict(required=False, default='ascending',
- choices=['ascending', 'descending']),
- sort_start=dict(required=False, type='int'),
- sort_end=dict(required=False, type='int'),
+ name=dict(required=False, default=[], type="list", elements="str"),
+ sort=dict(
+ required=False,
+ default=None,
+ choices=[
+ "launch_configuration_name",
+ "image_id",
+ "created_time",
+ "instance_type",
+ "kernel_id",
+ "ramdisk_id",
+ "key_name",
+ ],
+ ),
+ sort_order=dict(required=False, default="ascending", choices=["ascending", "descending"]),
+ sort_start=dict(required=False, type="int"),
+ sort_end=dict(required=False, type="int"),
)
module = AnsibleAWSModule(
@@ -214,12 +219,12 @@ def main():
)
try:
- connection = module.client('autoscaling')
+ connection = module.client("autoscaling")
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to connect to AWS')
+ module.fail_json_aws(e, msg="Failed to connect to AWS")
list_launch_configs(connection, module)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/autoscaling_lifecycle_hook.py b/ansible_collections/community/aws/plugins/modules/autoscaling_lifecycle_hook.py
index cf07b7681..a77fcce0a 100644
--- a/ansible_collections/community/aws/plugins/modules/autoscaling_lifecycle_hook.py
+++ b/ansible_collections/community/aws/plugins/modules/autoscaling_lifecycle_hook.py
@@ -1,13 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
# Copyright: (c) 2017, Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: autoscaling_lifecycle_hook
version_added: 1.0.0
@@ -74,12 +71,12 @@ options:
default: ABANDON
type: str
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
- name: Create / Update lifecycle hook
community.aws.autoscaling_lifecycle_hook:
region: eu-central-1
@@ -96,9 +93,9 @@ EXAMPLES = '''
state: absent
autoscaling_group_name: example
lifecycle_hook_name: example
-'''
+"""
-RETURN = '''
+RETURN = r"""
---
auto_scaling_group_name:
description: The unique name of the auto scaling group.
@@ -130,7 +127,7 @@ lifecycle_transition:
returned: success
type: str
sample: "autoscaling:EC2_INSTANCE_LAUNCHING"
-'''
+"""
try:
@@ -138,61 +135,64 @@ try:
except ImportError:
pass # handled by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
-def create_lifecycle_hook(connection, module):
- lch_name = module.params.get('lifecycle_hook_name')
- asg_name = module.params.get('autoscaling_group_name')
- transition = module.params.get('transition')
- role_arn = module.params.get('role_arn')
- notification_target_arn = module.params.get('notification_target_arn')
- notification_meta_data = module.params.get('notification_meta_data')
- heartbeat_timeout = module.params.get('heartbeat_timeout')
- default_result = module.params.get('default_result')
+def create_lifecycle_hook(connection, module):
+ lch_name = module.params.get("lifecycle_hook_name")
+ asg_name = module.params.get("autoscaling_group_name")
+ transition = module.params.get("transition")
+ role_arn = module.params.get("role_arn")
+ notification_target_arn = module.params.get("notification_target_arn")
+ notification_meta_data = module.params.get("notification_meta_data")
+ heartbeat_timeout = module.params.get("heartbeat_timeout")
+ default_result = module.params.get("default_result")
return_object = {}
- return_object['changed'] = False
+ return_object["changed"] = False
lch_params = {
- 'LifecycleHookName': lch_name,
- 'AutoScalingGroupName': asg_name,
- 'LifecycleTransition': transition
+ "LifecycleHookName": lch_name,
+ "AutoScalingGroupName": asg_name,
+ "LifecycleTransition": transition,
}
if role_arn:
- lch_params['RoleARN'] = role_arn
+ lch_params["RoleARN"] = role_arn
if notification_target_arn:
- lch_params['NotificationTargetARN'] = notification_target_arn
+ lch_params["NotificationTargetARN"] = notification_target_arn
if notification_meta_data:
- lch_params['NotificationMetadata'] = notification_meta_data
+ lch_params["NotificationMetadata"] = notification_meta_data
if heartbeat_timeout:
- lch_params['HeartbeatTimeout'] = heartbeat_timeout
+ lch_params["HeartbeatTimeout"] = heartbeat_timeout
if default_result:
- lch_params['DefaultResult'] = default_result
+ lch_params["DefaultResult"] = default_result
try:
existing_hook = connection.describe_lifecycle_hooks(
AutoScalingGroupName=asg_name,
- LifecycleHookNames=[lch_name]
- )['LifecycleHooks']
+ LifecycleHookNames=[lch_name],
+ )["LifecycleHooks"]
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Failed to get Lifecycle Hook")
if not existing_hook:
try:
if module.check_mode:
- module.exit_json(changed=True, msg="Would have created AutoScalingGroup Lifecycle Hook if not in check_mode.")
- return_object['changed'] = True
+ module.exit_json(
+ changed=True, msg="Would have created AutoScalingGroup Lifecycle Hook if not in check_mode."
+ )
+ return_object["changed"] = True
connection.put_lifecycle_hook(**lch_params)
- return_object['lifecycle_hook_info'] = connection.describe_lifecycle_hooks(
- AutoScalingGroupName=asg_name, LifecycleHookNames=[lch_name])['LifecycleHooks']
+ return_object["lifecycle_hook_info"] = connection.describe_lifecycle_hooks(
+ AutoScalingGroupName=asg_name, LifecycleHookNames=[lch_name]
+ )["LifecycleHooks"]
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Failed to create LifecycleHook")
@@ -201,11 +201,14 @@ def create_lifecycle_hook(connection, module):
if modified:
try:
if module.check_mode:
- module.exit_json(changed=True, msg="Would have modified AutoScalingGroup Lifecycle Hook if not in check_mode.")
- return_object['changed'] = True
+ module.exit_json(
+ changed=True, msg="Would have modified AutoScalingGroup Lifecycle Hook if not in check_mode."
+ )
+ return_object["changed"] = True
connection.put_lifecycle_hook(**lch_params)
- return_object['lifecycle_hook_info'] = connection.describe_lifecycle_hooks(
- AutoScalingGroupName=asg_name, LifecycleHookNames=[lch_name])['LifecycleHooks']
+ return_object["lifecycle_hook_info"] = connection.describe_lifecycle_hooks(
+ AutoScalingGroupName=asg_name, LifecycleHookNames=[lch_name]
+ )["LifecycleHooks"]
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Failed to create LifecycleHook")
@@ -229,33 +232,37 @@ def dict_compare(d1, d2):
def delete_lifecycle_hook(connection, module):
-
- lch_name = module.params.get('lifecycle_hook_name')
- asg_name = module.params.get('autoscaling_group_name')
+ lch_name = module.params.get("lifecycle_hook_name")
+ asg_name = module.params.get("autoscaling_group_name")
return_object = {}
- return_object['changed'] = False
+ return_object["changed"] = False
try:
all_hooks = connection.describe_lifecycle_hooks(
- AutoScalingGroupName=asg_name
+ AutoScalingGroupName=asg_name,
)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Failed to get Lifecycle Hooks")
- for hook in all_hooks['LifecycleHooks']:
- if hook['LifecycleHookName'] == lch_name:
+ for hook in all_hooks["LifecycleHooks"]:
+ if hook["LifecycleHookName"] == lch_name:
lch_params = {
- 'LifecycleHookName': lch_name,
- 'AutoScalingGroupName': asg_name
+ "LifecycleHookName": lch_name,
+ "AutoScalingGroupName": asg_name,
}
try:
if module.check_mode:
- module.exit_json(changed=True, msg="Would have deleted AutoScalingGroup Lifecycle Hook if not in check_mode.")
+ module.exit_json(
+ changed=True, msg="Would have deleted AutoScalingGroup Lifecycle Hook if not in check_mode."
+ )
connection.delete_lifecycle_hook(**lch_params)
- return_object['changed'] = True
- return_object['lifecycle_hook_removed'] = {'LifecycleHookName': lch_name, 'AutoScalingGroupName': asg_name}
+ return_object["changed"] = True
+ return_object["lifecycle_hook_removed"] = {
+ "LifecycleHookName": lch_name,
+ "AutoScalingGroupName": asg_name,
+ }
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Failed to delete LifecycleHook")
else:
@@ -266,34 +273,36 @@ def delete_lifecycle_hook(connection, module):
def main():
argument_spec = dict(
- autoscaling_group_name=dict(required=True, type='str'),
- lifecycle_hook_name=dict(required=True, type='str'),
- transition=dict(type='str', choices=['autoscaling:EC2_INSTANCE_TERMINATING', 'autoscaling:EC2_INSTANCE_LAUNCHING']),
- role_arn=dict(type='str'),
- notification_target_arn=dict(type='str'),
- notification_meta_data=dict(type='str'),
- heartbeat_timeout=dict(type='int'),
- default_result=dict(default='ABANDON', choices=['ABANDON', 'CONTINUE']),
- state=dict(default='present', choices=['present', 'absent'])
+ autoscaling_group_name=dict(required=True, type="str"),
+ lifecycle_hook_name=dict(required=True, type="str"),
+ transition=dict(
+ type="str", choices=["autoscaling:EC2_INSTANCE_TERMINATING", "autoscaling:EC2_INSTANCE_LAUNCHING"]
+ ),
+ role_arn=dict(type="str"),
+ notification_target_arn=dict(type="str"),
+ notification_meta_data=dict(type="str"),
+ heartbeat_timeout=dict(type="int"),
+ default_result=dict(default="ABANDON", choices=["ABANDON", "CONTINUE"]),
+ state=dict(default="present", choices=["present", "absent"]),
)
module = AnsibleAWSModule(
argument_spec=argument_spec,
supports_check_mode=True,
- required_if=[['state', 'present', ['transition']]],
+ required_if=[["state", "present", ["transition"]]],
)
- state = module.params.get('state')
+ state = module.params.get("state")
- connection = module.client('autoscaling')
+ connection = module.client("autoscaling")
changed = False
- if state == 'present':
+ if state == "present":
create_lifecycle_hook(connection, module)
- elif state == 'absent':
+ elif state == "absent":
delete_lifecycle_hook(connection, module)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/autoscaling_policy.py b/ansible_collections/community/aws/plugins/modules/autoscaling_policy.py
index a29389b0e..6d69d8492 100644
--- a/ansible_collections/community/aws/plugins/modules/autoscaling_policy.py
+++ b/ansible_collections/community/aws/plugins/modules/autoscaling_policy.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
module: autoscaling_policy
short_description: Create or delete AWS scaling policies for Autoscaling groups
version_added: 1.0.0
@@ -189,11 +187,12 @@ options:
description:
- The estimated time, in seconds, until a newly launched instance can contribute to the CloudWatch metrics.
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
-EXAMPLES = '''
+"""
+
+EXAMPLES = r"""
- name: Simple Scale Down policy
community.aws.autoscaling_policy:
state: present
@@ -224,7 +223,7 @@ EXAMPLES = '''
asg_name: "application-asg"
- name: create TargetTracking predefined policy
- ec2_scaling_policy:
+ community.aws.autoscaling_policy:
name: "predefined-policy-1"
policy_type: TargetTrackingScaling
target_tracking_config:
@@ -235,7 +234,7 @@ EXAMPLES = '''
register: result
- name: create TargetTracking predefined policy with resource_label
- ec2_scaling_policy:
+ community.aws.autoscaling_policy:
name: "predefined-policy-1"
policy_type: TargetTrackingScaling
target_tracking_config:
@@ -247,7 +246,7 @@ EXAMPLES = '''
register: result
- name: create TargetTrackingScaling custom policy
- ec2_scaling_policy:
+ community.aws.autoscaling_policy:
name: "custom-policy-1"
policy_type: TargetTrackingScaling
target_tracking_config:
@@ -261,9 +260,9 @@ EXAMPLES = '''
target_value: 98.0
asg_name: asg-test-1
register: result
-'''
+"""
-RETURN = '''
+RETURN = r"""
adjustment_type:
description: Scaling policy adjustment type.
returned: always
@@ -349,137 +348,146 @@ step_adjustments:
returned: always
type: int
sample: 50
-'''
+"""
try:
import botocore
except ImportError:
pass # caught by imported AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
-def build_target_specification(target_tracking_config):
+def build_target_specification(target_tracking_config):
# Initialize an empty dict() for building TargetTrackingConfiguration policies,
# which will be returned
targetTrackingConfig = dict()
- if target_tracking_config.get('target_value'):
- targetTrackingConfig['TargetValue'] = target_tracking_config['target_value']
+ if target_tracking_config.get("target_value"):
+ targetTrackingConfig["TargetValue"] = target_tracking_config["target_value"]
- if target_tracking_config.get('disable_scalein'):
- targetTrackingConfig['DisableScaleIn'] = target_tracking_config['disable_scalein']
+ if target_tracking_config.get("disable_scalein"):
+ targetTrackingConfig["DisableScaleIn"] = target_tracking_config["disable_scalein"]
else:
# Accounting for boto3 response
- targetTrackingConfig['DisableScaleIn'] = False
+ targetTrackingConfig["DisableScaleIn"] = False
- if target_tracking_config['predefined_metric_spec'] is not None:
+ if target_tracking_config["predefined_metric_spec"] is not None:
# Build spec for predefined_metric_spec
- targetTrackingConfig['PredefinedMetricSpecification'] = dict()
- if target_tracking_config['predefined_metric_spec'].get('predefined_metric_type'):
- targetTrackingConfig['PredefinedMetricSpecification']['PredefinedMetricType'] = \
- target_tracking_config['predefined_metric_spec']['predefined_metric_type']
-
- if target_tracking_config['predefined_metric_spec'].get('resource_label'):
- targetTrackingConfig['PredefinedMetricSpecification']['ResourceLabel'] = \
- target_tracking_config['predefined_metric_spec']['resource_label']
-
- elif target_tracking_config['customized_metric_spec'] is not None:
+ targetTrackingConfig["PredefinedMetricSpecification"] = dict()
+ if target_tracking_config["predefined_metric_spec"].get("predefined_metric_type"):
+ targetTrackingConfig["PredefinedMetricSpecification"]["PredefinedMetricType"] = target_tracking_config[
+ "predefined_metric_spec"
+ ]["predefined_metric_type"]
+
+ if target_tracking_config["predefined_metric_spec"].get("resource_label"):
+ targetTrackingConfig["PredefinedMetricSpecification"]["ResourceLabel"] = target_tracking_config[
+ "predefined_metric_spec"
+ ]["resource_label"]
+
+ elif target_tracking_config["customized_metric_spec"] is not None:
# Build spec for customized_metric_spec
- targetTrackingConfig['CustomizedMetricSpecification'] = dict()
- if target_tracking_config['customized_metric_spec'].get('metric_name'):
- targetTrackingConfig['CustomizedMetricSpecification']['MetricName'] = \
- target_tracking_config['customized_metric_spec']['metric_name']
-
- if target_tracking_config['customized_metric_spec'].get('namespace'):
- targetTrackingConfig['CustomizedMetricSpecification']['Namespace'] = \
- target_tracking_config['customized_metric_spec']['namespace']
-
- if target_tracking_config['customized_metric_spec'].get('dimensions'):
- targetTrackingConfig['CustomizedMetricSpecification']['Dimensions'] = \
- target_tracking_config['customized_metric_spec']['dimensions']
-
- if target_tracking_config['customized_metric_spec'].get('statistic'):
- targetTrackingConfig['CustomizedMetricSpecification']['Statistic'] = \
- target_tracking_config['customized_metric_spec']['statistic']
-
- if target_tracking_config['customized_metric_spec'].get('unit'):
- targetTrackingConfig['CustomizedMetricSpecification']['Unit'] = \
- target_tracking_config['customized_metric_spec']['unit']
+ targetTrackingConfig["CustomizedMetricSpecification"] = dict()
+ if target_tracking_config["customized_metric_spec"].get("metric_name"):
+ targetTrackingConfig["CustomizedMetricSpecification"]["MetricName"] = target_tracking_config[
+ "customized_metric_spec"
+ ]["metric_name"]
+
+ if target_tracking_config["customized_metric_spec"].get("namespace"):
+ targetTrackingConfig["CustomizedMetricSpecification"]["Namespace"] = target_tracking_config[
+ "customized_metric_spec"
+ ]["namespace"]
+
+ if target_tracking_config["customized_metric_spec"].get("dimensions"):
+ targetTrackingConfig["CustomizedMetricSpecification"]["Dimensions"] = target_tracking_config[
+ "customized_metric_spec"
+ ]["dimensions"]
+
+ if target_tracking_config["customized_metric_spec"].get("statistic"):
+ targetTrackingConfig["CustomizedMetricSpecification"]["Statistic"] = target_tracking_config[
+ "customized_metric_spec"
+ ]["statistic"]
+
+ if target_tracking_config["customized_metric_spec"].get("unit"):
+ targetTrackingConfig["CustomizedMetricSpecification"]["Unit"] = target_tracking_config[
+ "customized_metric_spec"
+ ]["unit"]
return targetTrackingConfig
def create_scaling_policy(connection, module):
changed = False
- asg_name = module.params['asg_name']
- policy_type = module.params['policy_type']
- policy_name = module.params['name']
-
- if policy_type == 'TargetTrackingScaling':
- params = dict(PolicyName=policy_name,
- PolicyType=policy_type,
- AutoScalingGroupName=asg_name)
+ asg_name = module.params["asg_name"]
+ policy_type = module.params["policy_type"]
+ policy_name = module.params["name"]
+
+ if policy_type == "TargetTrackingScaling":
+ params = dict(PolicyName=policy_name, PolicyType=policy_type, AutoScalingGroupName=asg_name)
else:
- params = dict(PolicyName=policy_name,
- PolicyType=policy_type,
- AutoScalingGroupName=asg_name,
- AdjustmentType=module.params['adjustment_type'])
+ params = dict(
+ PolicyName=policy_name,
+ PolicyType=policy_type,
+ AutoScalingGroupName=asg_name,
+ AdjustmentType=module.params["adjustment_type"],
+ )
# min_adjustment_step attribute is only relevant if the adjustment_type
# is set to percentage change in capacity, so it is a special case
- if module.params['adjustment_type'] == 'PercentChangeInCapacity':
- if module.params['min_adjustment_step']:
- params['MinAdjustmentMagnitude'] = module.params['min_adjustment_step']
+ if module.params["adjustment_type"] == "PercentChangeInCapacity":
+ if module.params["min_adjustment_step"]:
+ params["MinAdjustmentMagnitude"] = module.params["min_adjustment_step"]
- if policy_type == 'SimpleScaling':
+ if policy_type == "SimpleScaling":
# can't use required_if because it doesn't allow multiple criteria -
# it's only required if policy is SimpleScaling and state is present
- if not module.params['scaling_adjustment']:
- module.fail_json(msg='scaling_adjustment is required when policy_type is SimpleScaling '
- 'and state is present')
- params['ScalingAdjustment'] = module.params['scaling_adjustment']
- if module.params['cooldown']:
- params['Cooldown'] = module.params['cooldown']
-
- elif policy_type == 'StepScaling':
- if not module.params['step_adjustments']:
- module.fail_json(msg='step_adjustments is required when policy_type is StepScaling'
- 'and state is present')
- params['StepAdjustments'] = []
- for step_adjustment in module.params['step_adjustments']:
- step_adjust_params = dict(
- ScalingAdjustment=step_adjustment['scaling_adjustment'])
- if step_adjustment.get('lower_bound'):
- step_adjust_params['MetricIntervalLowerBound'] = step_adjustment['lower_bound']
- if step_adjustment.get('upper_bound'):
- step_adjust_params['MetricIntervalUpperBound'] = step_adjustment['upper_bound']
- params['StepAdjustments'].append(step_adjust_params)
- if module.params['metric_aggregation']:
- params['MetricAggregationType'] = module.params['metric_aggregation']
- if module.params['estimated_instance_warmup']:
- params['EstimatedInstanceWarmup'] = module.params['estimated_instance_warmup']
-
- elif policy_type == 'TargetTrackingScaling':
- if not module.params['target_tracking_config']:
- module.fail_json(msg='target_tracking_config is required when policy_type is '
- 'TargetTrackingScaling and state is present')
+ if not module.params["scaling_adjustment"]:
+ module.fail_json(
+ msg="scaling_adjustment is required when policy_type is SimpleScaling and state is present"
+ )
+ params["ScalingAdjustment"] = module.params["scaling_adjustment"]
+ if module.params["cooldown"]:
+ params["Cooldown"] = module.params["cooldown"]
+
+ elif policy_type == "StepScaling":
+ if not module.params["step_adjustments"]:
+ module.fail_json(msg="step_adjustments is required when policy_type is StepScaling and state is present")
+ params["StepAdjustments"] = []
+ for step_adjustment in module.params["step_adjustments"]:
+ step_adjust_params = dict(ScalingAdjustment=step_adjustment["scaling_adjustment"])
+ if step_adjustment.get("lower_bound"):
+ step_adjust_params["MetricIntervalLowerBound"] = step_adjustment["lower_bound"]
+ if step_adjustment.get("upper_bound"):
+ step_adjust_params["MetricIntervalUpperBound"] = step_adjustment["upper_bound"]
+ params["StepAdjustments"].append(step_adjust_params)
+ if module.params["metric_aggregation"]:
+ params["MetricAggregationType"] = module.params["metric_aggregation"]
+ if module.params["estimated_instance_warmup"]:
+ params["EstimatedInstanceWarmup"] = module.params["estimated_instance_warmup"]
+
+ elif policy_type == "TargetTrackingScaling":
+ if not module.params["target_tracking_config"]:
+ module.fail_json(
+ msg="target_tracking_config is required when policy_type is TargetTrackingScaling and state is present"
+ )
else:
- params['TargetTrackingConfiguration'] = build_target_specification(module.params.get('target_tracking_config'))
- if module.params['estimated_instance_warmup']:
- params['EstimatedInstanceWarmup'] = module.params['estimated_instance_warmup']
+ params["TargetTrackingConfiguration"] = build_target_specification(
+ module.params.get("target_tracking_config")
+ )
+ if module.params["estimated_instance_warmup"]:
+ params["EstimatedInstanceWarmup"] = module.params["estimated_instance_warmup"]
# Ensure idempotency with policies
try:
- policies = connection.describe_policies(aws_retry=True,
- AutoScalingGroupName=asg_name,
- PolicyNames=[policy_name])['ScalingPolicies']
+ policies = connection.describe_policies(
+ aws_retry=True, AutoScalingGroupName=asg_name, PolicyNames=[policy_name]
+ )["ScalingPolicies"]
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(
- e, msg="Failed to obtain autoscaling policy %s" % policy_name)
+ module.fail_json_aws(e, msg=f"Failed to obtain autoscaling policy {policy_name}")
before = after = {}
if not policies:
@@ -499,41 +507,39 @@ def create_scaling_policy(connection, module):
module.fail_json_aws(e, msg="Failed to create autoscaling policy")
try:
- policies = connection.describe_policies(aws_retry=True,
- AutoScalingGroupName=asg_name,
- PolicyNames=[policy_name])['ScalingPolicies']
+ policies = connection.describe_policies(
+ aws_retry=True, AutoScalingGroupName=asg_name, PolicyNames=[policy_name]
+ )["ScalingPolicies"]
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(
- e, msg="Failed to obtain autoscaling policy %s" % policy_name)
+ module.fail_json_aws(e, msg=f"Failed to obtain autoscaling policy {policy_name}")
policy = camel_dict_to_snake_dict(policies[0])
# Backward compatible return values
- policy['arn'] = policy['policy_arn']
- policy['as_name'] = policy['auto_scaling_group_name']
- policy['name'] = policy['policy_name']
+ policy["arn"] = policy["policy_arn"]
+ policy["as_name"] = policy["auto_scaling_group_name"]
+ policy["name"] = policy["policy_name"]
if before and after:
- module.exit_json(changed=changed, diff=dict(
- before=before, after=after), **policy)
+ module.exit_json(changed=changed, diff=dict(before=before, after=after), **policy)
else:
module.exit_json(changed=changed, **policy)
def delete_scaling_policy(connection, module):
- policy_name = module.params.get('name')
+ policy_name = module.params.get("name")
try:
- policy = connection.describe_policies(
- aws_retry=True, PolicyNames=[policy_name])
+ policy = connection.describe_policies(aws_retry=True, PolicyNames=[policy_name])
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(
- e, msg="Failed to obtain autoscaling policy %s" % policy_name)
+ module.fail_json_aws(e, msg=f"Failed to obtain autoscaling policy {policy_name}")
- if policy['ScalingPolicies']:
+ if policy["ScalingPolicies"]:
try:
- connection.delete_policy(aws_retry=True,
- AutoScalingGroupName=policy['ScalingPolicies'][0]['AutoScalingGroupName'],
- PolicyName=policy_name)
+ connection.delete_policy(
+ aws_retry=True,
+ AutoScalingGroupName=policy["ScalingPolicies"][0]["AutoScalingGroupName"],
+ PolicyName=policy_name,
+ )
module.exit_json(changed=True)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Failed to delete autoscaling policy")
@@ -543,65 +549,62 @@ def delete_scaling_policy(connection, module):
def main():
step_adjustment_spec = dict(
- lower_bound=dict(type='int'),
- upper_bound=dict(type='int'),
- scaling_adjustment=dict(type='int', required=True)
+ lower_bound=dict(type="int"), upper_bound=dict(type="int"), scaling_adjustment=dict(type="int", required=True)
)
predefined_metric_spec = dict(
- predefined_metric_type=dict(type='str', choices=['ASGAverageCPUUtilization',
- 'ASGAverageNetworkIn',
- 'ASGAverageNetworkOut',
- 'ALBRequestCountPerTarget'], required=True),
- resource_label=dict(type='str')
+ predefined_metric_type=dict(
+ type="str",
+ choices=[
+ "ASGAverageCPUUtilization",
+ "ASGAverageNetworkIn",
+ "ASGAverageNetworkOut",
+ "ALBRequestCountPerTarget",
+ ],
+ required=True,
+ ),
+ resource_label=dict(type="str"),
)
customized_metric_spec = dict(
- metric_name=dict(type='str', required=True),
- namespace=dict(type='str', required=True),
- statistic=dict(type='str', required=True, choices=['Average', 'Minimum', 'Maximum', 'SampleCount', 'Sum']),
- dimensions=dict(type='list', elements='dict'),
- unit=dict(type='str')
+ metric_name=dict(type="str", required=True),
+ namespace=dict(type="str", required=True),
+ statistic=dict(type="str", required=True, choices=["Average", "Minimum", "Maximum", "SampleCount", "Sum"]),
+ dimensions=dict(type="list", elements="dict"),
+ unit=dict(type="str"),
)
target_tracking_spec = dict(
- disable_scalein=dict(type='bool'),
- target_value=dict(type='float', required=True),
- predefined_metric_spec=dict(type='dict',
- options=predefined_metric_spec),
- customized_metric_spec=dict(type='dict',
- options=customized_metric_spec)
+ disable_scalein=dict(type="bool"),
+ target_value=dict(type="float", required=True),
+ predefined_metric_spec=dict(type="dict", options=predefined_metric_spec),
+ customized_metric_spec=dict(type="dict", options=customized_metric_spec),
)
argument_spec = dict(
name=dict(required=True),
- adjustment_type=dict(choices=['ChangeInCapacity', 'ExactCapacity', 'PercentChangeInCapacity']),
+ adjustment_type=dict(choices=["ChangeInCapacity", "ExactCapacity", "PercentChangeInCapacity"]),
asg_name=dict(),
- scaling_adjustment=dict(type='int'),
- min_adjustment_step=dict(type='int'),
- cooldown=dict(type='int'),
- state=dict(default='present', choices=['present', 'absent']),
- metric_aggregation=dict(default='Average', choices=[
- 'Minimum', 'Maximum', 'Average']),
- policy_type=dict(default='SimpleScaling', choices=[
- 'SimpleScaling', 'StepScaling', 'TargetTrackingScaling']),
- target_tracking_config=dict(type='dict', options=target_tracking_spec),
- step_adjustments=dict(
- type='list', options=step_adjustment_spec, elements='dict'),
- estimated_instance_warmup=dict(type='int')
+ scaling_adjustment=dict(type="int"),
+ min_adjustment_step=dict(type="int"),
+ cooldown=dict(type="int"),
+ state=dict(default="present", choices=["present", "absent"]),
+ metric_aggregation=dict(default="Average", choices=["Minimum", "Maximum", "Average"]),
+ policy_type=dict(default="SimpleScaling", choices=["SimpleScaling", "StepScaling", "TargetTrackingScaling"]),
+ target_tracking_config=dict(type="dict", options=target_tracking_spec),
+ step_adjustments=dict(type="list", options=step_adjustment_spec, elements="dict"),
+ estimated_instance_warmup=dict(type="int"),
)
- module = AnsibleAWSModule(argument_spec=argument_spec,
- required_if=[['state', 'present', ['asg_name']]])
+ module = AnsibleAWSModule(argument_spec=argument_spec, required_if=[["state", "present", ["asg_name"]]])
- connection = module.client(
- 'autoscaling', retry_decorator=AWSRetry.jittered_backoff())
- state = module.params.get('state')
+ connection = module.client("autoscaling", retry_decorator=AWSRetry.jittered_backoff())
+ state = module.params.get("state")
- if state == 'present':
+ if state == "present":
create_scaling_policy(connection, module)
- elif state == 'absent':
+ elif state == "absent":
delete_scaling_policy(connection, module)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/autoscaling_scheduled_action.py b/ansible_collections/community/aws/plugins/modules/autoscaling_scheduled_action.py
index f1433c522..9bfb70b83 100644
--- a/ansible_collections/community/aws/plugins/modules/autoscaling_scheduled_action.py
+++ b/ansible_collections/community/aws/plugins/modules/autoscaling_scheduled_action.py
@@ -1,4 +1,5 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
# Copyright: (c) 2021, Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
@@ -6,10 +7,7 @@
# Based off of https://github.com/mmochan/ansible-aws-ec2-asg-scheduled-actions/blob/master/library/ec2_asg_scheduled_action.py
# (c) 2016, Mike Mochan <@mmochan>
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: autoscaling_scheduled_action
version_added: 2.2.0
@@ -67,14 +65,15 @@ options:
required: false
default: present
choices: ['present', 'absent']
-author: Mark Woolley(@marknet15)
+author:
+ - Mark Woolley(@marknet15)
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
-'''
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
# Create a scheduled action for a autoscaling group.
- name: Create a minimal scheduled action for autoscaling group
community.aws.autoscaling_scheduled_action:
@@ -108,9 +107,9 @@ EXAMPLES = r'''
autoscaling_group_name: test_asg
scheduled_action_name: test_scheduled_action
state: absent
-'''
+"""
-RETURN = r'''
+RETURN = r"""
scheduled_action_name:
description: The name of the scheduled action.
returned: when I(state=present)
@@ -151,7 +150,7 @@ desired_capacity:
returned: when I(state=present)
type: int
sample: 1
-'''
+"""
try:
import botocore
@@ -160,39 +159,41 @@ except ImportError:
try:
from dateutil.parser import parse as timedate_parse
+
HAS_DATEUTIL = True
except ImportError:
HAS_DATEUTIL = False
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def format_request():
params = dict(
- AutoScalingGroupName=module.params.get('autoscaling_group_name'),
- ScheduledActionName=module.params.get('scheduled_action_name'),
- Recurrence=module.params.get('recurrence')
+ AutoScalingGroupName=module.params.get("autoscaling_group_name"),
+ ScheduledActionName=module.params.get("scheduled_action_name"),
+ Recurrence=module.params.get("recurrence"),
)
# Some of these params are optional
- if module.params.get('desired_capacity') is not None:
- params['DesiredCapacity'] = module.params.get('desired_capacity')
+ if module.params.get("desired_capacity") is not None:
+ params["DesiredCapacity"] = module.params.get("desired_capacity")
- if module.params.get('min_size') is not None:
- params['MinSize'] = module.params.get('min_size')
+ if module.params.get("min_size") is not None:
+ params["MinSize"] = module.params.get("min_size")
- if module.params.get('max_size') is not None:
- params['MaxSize'] = module.params.get('max_size')
+ if module.params.get("max_size") is not None:
+ params["MaxSize"] = module.params.get("max_size")
- if module.params.get('time_zone') is not None:
- params['TimeZone'] = module.params.get('time_zone')
+ if module.params.get("time_zone") is not None:
+ params["TimeZone"] = module.params.get("time_zone")
- if module.params.get('start_time') is not None:
- params['StartTime'] = module.params.get('start_time')
+ if module.params.get("start_time") is not None:
+ params["StartTime"] = module.params.get("start_time")
- if module.params.get('end_time') is not None:
- params['EndTime'] = module.params.get('end_time')
+ if module.params.get("end_time") is not None:
+ params["EndTime"] = module.params.get("end_time")
return params
@@ -205,8 +206,8 @@ def delete_scheduled_action(current_actions):
return True
params = dict(
- AutoScalingGroupName=module.params.get('autoscaling_group_name'),
- ScheduledActionName=module.params.get('scheduled_action_name')
+ AutoScalingGroupName=module.params.get("autoscaling_group_name"),
+ ScheduledActionName=module.params.get("scheduled_action_name"),
)
try:
@@ -219,8 +220,8 @@ def delete_scheduled_action(current_actions):
def get_scheduled_actions():
params = dict(
- AutoScalingGroupName=module.params.get('autoscaling_group_name'),
- ScheduledActionNames=[module.params.get('scheduled_action_name')]
+ AutoScalingGroupName=module.params.get("autoscaling_group_name"),
+ ScheduledActionNames=[module.params.get("scheduled_action_name")],
)
try:
@@ -270,55 +271,53 @@ def main():
global client
argument_spec = dict(
- autoscaling_group_name=dict(required=True, type='str'),
- scheduled_action_name=dict(required=True, type='str'),
- start_time=dict(default=None, type='str'),
- end_time=dict(default=None, type='str'),
- time_zone=dict(default=None, type='str'),
- recurrence=dict(type='str'),
- min_size=dict(default=None, type='int'),
- max_size=dict(default=None, type='int'),
- desired_capacity=dict(default=None, type='int'),
- state=dict(default='present', choices=['present', 'absent'])
+ autoscaling_group_name=dict(required=True, type="str"),
+ scheduled_action_name=dict(required=True, type="str"),
+ start_time=dict(default=None, type="str"),
+ end_time=dict(default=None, type="str"),
+ time_zone=dict(default=None, type="str"),
+ recurrence=dict(type="str"),
+ min_size=dict(default=None, type="int"),
+ max_size=dict(default=None, type="int"),
+ desired_capacity=dict(default=None, type="int"),
+ state=dict(default="present", choices=["present", "absent"]),
)
module = AnsibleAWSModule(
- argument_spec=argument_spec,
- required_if=[['state', 'present', ['recurrence']]],
- supports_check_mode=True
+ argument_spec=argument_spec, required_if=[["state", "present", ["recurrence"]]], supports_check_mode=True
)
if not HAS_DATEUTIL:
- module.fail_json(msg='dateutil is required for this module')
+ module.fail_json(msg="dateutil is required for this module")
if not module.botocore_at_least("1.20.24"):
- module.fail_json(msg='botocore version >= 1.20.24 is required for this module')
+ module.fail_json(msg="botocore version >= 1.20.24 is required for this module")
- client = module.client('autoscaling', retry_decorator=AWSRetry.jittered_backoff())
+ client = module.client("autoscaling", retry_decorator=AWSRetry.jittered_backoff())
current_actions = get_scheduled_actions()
- state = module.params.get('state')
+ state = module.params.get("state")
results = dict()
- if state == 'present':
+ if state == "present":
changed = put_scheduled_update_group_action(current_actions)
if not module.check_mode:
updated_action = get_scheduled_actions()[0]
results = dict(
- scheduled_action_name=updated_action.get('ScheduledActionName'),
- start_time=updated_action.get('StartTime'),
- end_time=updated_action.get('EndTime'),
- time_zone=updated_action.get('TimeZone'),
- recurrence=updated_action.get('Recurrence'),
- min_size=updated_action.get('MinSize'),
- max_size=updated_action.get('MaxSize'),
- desired_capacity=updated_action.get('DesiredCapacity')
+ scheduled_action_name=updated_action.get("ScheduledActionName"),
+ start_time=updated_action.get("StartTime"),
+ end_time=updated_action.get("EndTime"),
+ time_zone=updated_action.get("TimeZone"),
+ recurrence=updated_action.get("Recurrence"),
+ min_size=updated_action.get("MinSize"),
+ max_size=updated_action.get("MaxSize"),
+ desired_capacity=updated_action.get("DesiredCapacity"),
)
else:
changed = delete_scheduled_action(current_actions)
- results['changed'] = changed
+ results["changed"] = changed
module.exit_json(**results)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/aws_region_info.py b/ansible_collections/community/aws/plugins/modules/aws_region_info.py
deleted file mode 100644
index 126455a8c..000000000
--- a/ansible_collections/community/aws/plugins/modules/aws_region_info.py
+++ /dev/null
@@ -1,98 +0,0 @@
-#!/usr/bin/python
-# Copyright (c) 2017 Ansible Project
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
-module: aws_region_info
-short_description: Gather information about AWS regions
-version_added: 1.0.0
-description:
- - Gather information about AWS regions.
-author:
- - 'Henrique Rodrigues (@Sodki)'
-options:
- filters:
- description:
- - A dict of filters to apply.
- - Each dict item consists of a filter key and a filter value.
- - See U(https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeRegions.html) for possible filters.
- - Filter names and values are case sensitive.
- - You can use underscores instead of dashes (-) in the filter keys.
- - Filter keys with underscores will take precedence in case of conflict.
- default: {}
- type: dict
-extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
- - amazon.aws.boto3
-'''
-
-EXAMPLES = '''
-# Note: These examples do not set authentication details, see the AWS Guide for details.
-
-# Gather information about all regions
-- community.aws.aws_region_info:
-
-# Gather information about a single region
-- community.aws.aws_region_info:
- filters:
- region-name: eu-west-1
-'''
-
-RETURN = '''
-regions:
- returned: on success
- description: >
- Regions that match the provided filters. Each element consists of a dict with all the information related
- to that region.
- type: list
- sample: "[{
- 'endpoint': 'ec2.us-west-1.amazonaws.com',
- 'region_name': 'us-west-1'
- }]"
-'''
-
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_filter_list
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict
-
-try:
- from botocore.exceptions import ClientError, BotoCoreError
-except ImportError:
- pass # Handled by AnsibleAWSModule
-
-
-def main():
- argument_spec = dict(
- filters=dict(default={}, type='dict')
- )
-
- module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
-
- connection = module.client('ec2', retry_decorator=AWSRetry.jittered_backoff())
-
- # Replace filter key underscores with dashes, for compatibility
- sanitized_filters = dict(module.params.get('filters'))
- for k in module.params.get('filters').keys():
- if "_" in k:
- sanitized_filters[k.replace('_', '-')] = sanitized_filters[k]
- del sanitized_filters[k]
-
- try:
- regions = connection.describe_regions(
- aws_retry=True,
- Filters=ansible_dict_to_boto3_filter_list(sanitized_filters)
- )
- except (BotoCoreError, ClientError) as e:
- module.fail_json_aws(e, msg="Unable to describe regions.")
-
- module.exit_json(regions=[camel_dict_to_snake_dict(r) for r in regions['Regions']])
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/aws/plugins/modules/batch_compute_environment.py b/ansible_collections/community/aws/plugins/modules/batch_compute_environment.py
index 555cfccbe..e9a17f9a0 100644
--- a/ansible_collections/community/aws/plugins/modules/batch_compute_environment.py
+++ b/ansible_collections/community/aws/plugins/modules/batch_compute_environment.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright (c) 2017 Jon Meran <jonathan.meran@sonos.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: batch_compute_environment
version_added: 1.0.0
@@ -120,12 +118,12 @@ options:
- The Amazon Resource Name (ARN) of the Amazon EC2 Spot Fleet IAM role applied to a SPOT compute environment.
type: str
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
- name: My Batch Compute Environment
community.aws.batch_compute_environment:
compute_environment_name: computeEnvironmentName
@@ -155,9 +153,9 @@ EXAMPLES = r'''
- name: show results
ansible.builtin.debug:
var: aws_batch_compute_environment_action
-'''
+"""
-RETURN = r'''
+RETURN = r"""
---
output:
description: "returns what action was taken, whether something was changed, invocation and response"
@@ -167,15 +165,15 @@ output:
changed: false
invocation:
module_args:
- aws_access_key: ~
- aws_secret_key: ~
+ access_key: ~
+ secret_key: ~
bid_percentage: ~
compute_environment_name: <name>
compute_environment_state: ENABLED
compute_resource_type: EC2
desiredv_cpus: 0
ec2_key_pair: ~
- ec2_url: ~
+ endpoint_url: ~
image_id: ~
instance_role: "arn:aws:iam::..."
instance_types:
@@ -222,17 +220,22 @@ output:
statusReason: "ComputeEnvironment Healthy"
type: MANAGED
type: dict
-'''
+"""
import re
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import snake_dict_to_camel_dict, camel_dict_to_snake_dict
try:
- from botocore.exceptions import ClientError, BotoCoreError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
except ImportError:
pass # Handled by AnsibleAWSModule
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+from ansible.module_utils.common.dict_transformations import snake_dict_to_camel_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.arn import validate_aws_arn
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
# ---------------------------------------------------------------------------------------------------
#
@@ -240,6 +243,7 @@ except ImportError:
#
# ---------------------------------------------------------------------------------------------------
+
def set_api_params(module, module_params):
"""
Sets module parameters to those expected by the boto3 API.
@@ -260,18 +264,16 @@ def validate_params(module):
:return:
"""
- compute_environment_name = module.params['compute_environment_name']
+ compute_environment_name = module.params["compute_environment_name"]
# validate compute environment name
- if not re.search(r'^[\w\_:]+$', compute_environment_name):
+ if not re.search(r"^[\w\_:]+$", compute_environment_name):
module.fail_json(
- msg="Function compute_environment_name {0} is invalid. Names must contain only alphanumeric characters "
- "and underscores.".format(compute_environment_name)
+ msg=f"Function compute_environment_name {compute_environment_name} is invalid. Names must contain only alphanumeric characters and underscores."
)
- if not compute_environment_name.startswith('arn:aws:batch:'):
+ if not validate_aws_arn(compute_environment_name, service="batch"):
if len(compute_environment_name) > 128:
- module.fail_json(msg='compute_environment_name "{0}" exceeds 128 character limit'
- .format(compute_environment_name))
+ module.fail_json(msg=f'compute_environment_name "{compute_environment_name}" exceeds 128 character limit')
return
@@ -282,13 +284,14 @@ def validate_params(module):
#
# ---------------------------------------------------------------------------------------------------
+
def get_current_compute_environment(module, client):
try:
environments = client.describe_compute_environments(
- computeEnvironments=[module.params['compute_environment_name']]
+ computeEnvironments=[module.params["compute_environment_name"]]
)
- if len(environments['computeEnvironments']) > 0:
- return environments['computeEnvironments'][0]
+ if len(environments["computeEnvironments"]) > 0:
+ return environments["computeEnvironments"][0]
else:
return None
except ClientError:
@@ -297,42 +300,52 @@ def get_current_compute_environment(module, client):
def create_compute_environment(module, client):
"""
- Adds a Batch compute environment
+ Adds a Batch compute environment
- :param module:
- :param client:
- :return:
- """
+ :param module:
+ :param client:
+ :return:
+ """
changed = False
# set API parameters
- params = (
- 'compute_environment_name', 'type', 'service_role')
+ params = ("compute_environment_name", "type", "service_role")
api_params = set_api_params(module, params)
- if module.params['compute_environment_state'] is not None:
- api_params['state'] = module.params['compute_environment_state']
-
- compute_resources_param_list = ('minv_cpus', 'maxv_cpus', 'desiredv_cpus', 'instance_types', 'image_id', 'subnets',
- 'security_group_ids', 'ec2_key_pair', 'instance_role', 'tags', 'bid_percentage',
- 'spot_iam_fleet_role')
+ if module.params["compute_environment_state"] is not None:
+ api_params["state"] = module.params["compute_environment_state"]
+
+ compute_resources_param_list = (
+ "minv_cpus",
+ "maxv_cpus",
+ "desiredv_cpus",
+ "instance_types",
+ "image_id",
+ "subnets",
+ "security_group_ids",
+ "ec2_key_pair",
+ "instance_role",
+ "tags",
+ "bid_percentage",
+ "spot_iam_fleet_role",
+ )
compute_resources_params = set_api_params(module, compute_resources_param_list)
- if module.params['compute_resource_type'] is not None:
- compute_resources_params['type'] = module.params['compute_resource_type']
+ if module.params["compute_resource_type"] is not None:
+ compute_resources_params["type"] = module.params["compute_resource_type"]
# if module.params['minv_cpus'] is not None:
# compute_resources_params['minvCpus'] = module.params['minv_cpus']
- api_params['computeResources'] = compute_resources_params
+ api_params["computeResources"] = compute_resources_params
try:
if not module.check_mode:
client.create_compute_environment(**api_params)
changed = True
except (ClientError, BotoCoreError) as e:
- module.fail_json_aws(e, msg='Error creating compute environment')
+ module.fail_json_aws(e, msg="Error creating compute environment")
return changed
@@ -349,29 +362,29 @@ def remove_compute_environment(module, client):
changed = False
# set API parameters
- api_params = {'computeEnvironment': module.params['compute_environment_name']}
+ api_params = {"computeEnvironment": module.params["compute_environment_name"]}
try:
if not module.check_mode:
client.delete_compute_environment(**api_params)
changed = True
except (ClientError, BotoCoreError) as e:
- module.fail_json_aws(e, msg='Error removing compute environment')
+ module.fail_json_aws(e, msg="Error removing compute environment")
return changed
def manage_state(module, client):
changed = False
- current_state = 'absent'
- state = module.params['state']
- compute_environment_state = module.params['compute_environment_state']
- compute_environment_name = module.params['compute_environment_name']
- service_role = module.params['service_role']
- minv_cpus = module.params['minv_cpus']
- maxv_cpus = module.params['maxv_cpus']
- desiredv_cpus = module.params['desiredv_cpus']
- action_taken = 'none'
- update_env_response = ''
+ current_state = "absent"
+ state = module.params["state"]
+ compute_environment_state = module.params["compute_environment_state"]
+ compute_environment_name = module.params["compute_environment_name"]
+ service_role = module.params["service_role"]
+ minv_cpus = module.params["minv_cpus"]
+ maxv_cpus = module.params["maxv_cpus"]
+ desiredv_cpus = module.params["desiredv_cpus"]
+ action_taken = "none"
+ update_env_response = ""
check_mode = module.check_mode
@@ -379,37 +392,40 @@ def manage_state(module, client):
current_compute_environment = get_current_compute_environment(module, client)
response = current_compute_environment
if current_compute_environment:
- current_state = 'present'
+ current_state = "present"
- if state == 'present':
- if current_state == 'present':
+ if state == "present":
+ if current_state == "present":
updates = False
# Update Batch Compute Environment configuration
- compute_kwargs = {'computeEnvironment': compute_environment_name}
+ compute_kwargs = {"computeEnvironment": compute_environment_name}
# Update configuration if needed
compute_resources = {}
- if compute_environment_state and current_compute_environment['state'] != compute_environment_state:
- compute_kwargs.update({'state': compute_environment_state})
+ if compute_environment_state and current_compute_environment["state"] != compute_environment_state:
+ compute_kwargs.update({"state": compute_environment_state})
updates = True
- if service_role and current_compute_environment['serviceRole'] != service_role:
- compute_kwargs.update({'serviceRole': service_role})
+ if service_role and current_compute_environment["serviceRole"] != service_role:
+ compute_kwargs.update({"serviceRole": service_role})
updates = True
- if minv_cpus is not None and current_compute_environment['computeResources']['minvCpus'] != minv_cpus:
- compute_resources['minvCpus'] = minv_cpus
- if maxv_cpus is not None and current_compute_environment['computeResources']['maxvCpus'] != maxv_cpus:
- compute_resources['maxvCpus'] = maxv_cpus
- if desiredv_cpus is not None and current_compute_environment['computeResources']['desiredvCpus'] != desiredv_cpus:
- compute_resources['desiredvCpus'] = desiredv_cpus
+ if minv_cpus is not None and current_compute_environment["computeResources"]["minvCpus"] != minv_cpus:
+ compute_resources["minvCpus"] = minv_cpus
+ if maxv_cpus is not None and current_compute_environment["computeResources"]["maxvCpus"] != maxv_cpus:
+ compute_resources["maxvCpus"] = maxv_cpus
+ if (
+ desiredv_cpus is not None
+ and current_compute_environment["computeResources"]["desiredvCpus"] != desiredv_cpus
+ ):
+ compute_resources["desiredvCpus"] = desiredv_cpus
if len(compute_resources) > 0:
- compute_kwargs['computeResources'] = compute_resources
+ compute_kwargs["computeResources"] = compute_resources
updates = True
if updates:
try:
if not check_mode:
update_env_response = client.update_compute_environment(**compute_kwargs)
if not update_env_response:
- module.fail_json(msg='Unable to get compute environment information after creating')
+ module.fail_json(msg="Unable to get compute environment information after creating")
changed = True
action_taken = "updated"
except (BotoCoreError, ClientError) as e:
@@ -419,15 +435,15 @@ def manage_state(module, client):
# Create Batch Compute Environment
changed = create_compute_environment(module, client)
# Describe compute environment
- action_taken = 'added'
+ action_taken = "added"
response = get_current_compute_environment(module, client)
if not response:
- module.fail_json(msg='Unable to get compute environment information after creating')
+ module.fail_json(msg="Unable to get compute environment information after creating")
else:
- if current_state == 'present':
+ if current_state == "present":
# remove the compute environment
changed = remove_compute_environment(module, client)
- action_taken = 'deleted'
+ action_taken = "deleted"
return dict(changed=changed, batch_compute_environment_action=action_taken, response=response)
@@ -437,6 +453,7 @@ def manage_state(module, client):
#
# ---------------------------------------------------------------------------------------------------
+
def main():
"""
Main entry point.
@@ -445,39 +462,36 @@ def main():
"""
argument_spec = dict(
- state=dict(default='present', choices=['present', 'absent']),
+ state=dict(default="present", choices=["present", "absent"]),
compute_environment_name=dict(required=True),
- type=dict(required=True, choices=['MANAGED', 'UNMANAGED']),
- compute_environment_state=dict(required=False, default='ENABLED', choices=['ENABLED', 'DISABLED']),
+ type=dict(required=True, choices=["MANAGED", "UNMANAGED"]),
+ compute_environment_state=dict(required=False, default="ENABLED", choices=["ENABLED", "DISABLED"]),
service_role=dict(required=True),
- compute_resource_type=dict(required=True, choices=['EC2', 'SPOT']),
- minv_cpus=dict(type='int', required=True),
- maxv_cpus=dict(type='int', required=True),
- desiredv_cpus=dict(type='int'),
- instance_types=dict(type='list', required=True, elements='str'),
+ compute_resource_type=dict(required=True, choices=["EC2", "SPOT"]),
+ minv_cpus=dict(type="int", required=True),
+ maxv_cpus=dict(type="int", required=True),
+ desiredv_cpus=dict(type="int"),
+ instance_types=dict(type="list", required=True, elements="str"),
image_id=dict(),
- subnets=dict(type='list', required=True, elements='str'),
- security_group_ids=dict(type='list', required=True, elements='str'),
+ subnets=dict(type="list", required=True, elements="str"),
+ security_group_ids=dict(type="list", required=True, elements="str"),
ec2_key_pair=dict(no_log=False),
instance_role=dict(required=True),
- tags=dict(type='dict'),
- bid_percentage=dict(type='int'),
+ tags=dict(type="dict"),
+ bid_percentage=dict(type="int"),
spot_iam_fleet_role=dict(),
)
- module = AnsibleAWSModule(
- argument_spec=argument_spec,
- supports_check_mode=True
- )
+ module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
- client = module.client('batch')
+ client = module.client("batch")
validate_params(module)
results = manage_state(module, client)
- module.exit_json(**camel_dict_to_snake_dict(results, ignore_list=['Tags']))
+ module.exit_json(**camel_dict_to_snake_dict(results, ignore_list=["Tags"]))
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/batch_job_definition.py b/ansible_collections/community/aws/plugins/modules/batch_job_definition.py
index 79ace0534..fb2b1996d 100644
--- a/ansible_collections/community/aws/plugins/modules/batch_job_definition.py
+++ b/ansible_collections/community/aws/plugins/modules/batch_job_definition.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright (c) 2017 Jon Meran <jonathan.meran@sonos.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: batch_job_definition
version_added: 1.0.0
@@ -179,12 +177,12 @@ options:
many times.
type: int
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
---
- name: My Batch Job Definition
community.aws.batch_job_definition:
@@ -207,9 +205,9 @@ EXAMPLES = r'''
- name: show results
ansible.builtin.debug: var=job_definition_create_result
-'''
+"""
-RETURN = r'''
+RETURN = r"""
---
output:
description: "returns what action was taken, whether something was changed, invocation and response"
@@ -223,17 +221,20 @@ output:
status: INACTIVE
type: container
type: dict
-'''
-
-from ansible_collections.amazon.aws.plugins.module_utils.batch import cc, set_api_params
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict
+"""
try:
- from botocore.exceptions import ClientError, BotoCoreError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
except ImportError:
pass # Handled by AnsibleAWSModule
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.batch import cc
+from ansible_collections.amazon.aws.plugins.module_utils.batch import set_api_params
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
# ---------------------------------------------------------------------------------------------------
#
@@ -263,15 +264,15 @@ def validate_params(module, batch_client):
#
# ---------------------------------------------------------------------------------------------------
+
def get_current_job_definition(module, batch_client):
try:
- environments = batch_client.describe_job_definitions(
- jobDefinitionName=module.params['job_definition_name']
- )
- if len(environments['jobDefinitions']) > 0:
- latest_revision = max(map(lambda d: d['revision'], environments['jobDefinitions']))
- latest_definition = next((x for x in environments['jobDefinitions'] if x['revision'] == latest_revision),
- None)
+ environments = batch_client.describe_job_definitions(jobDefinitionName=module.params["job_definition_name"])
+ if len(environments["jobDefinitions"]) > 0:
+ latest_revision = max(map(lambda d: d["revision"], environments["jobDefinitions"]))
+ latest_definition = next(
+ (x for x in environments["jobDefinitions"] if x["revision"] == latest_revision), None
+ )
return latest_definition
return None
except ClientError:
@@ -280,12 +281,12 @@ def get_current_job_definition(module, batch_client):
def create_job_definition(module, batch_client):
"""
- Adds a Batch job definition
+ Adds a Batch job definition
- :param module:
- :param batch_client:
- :return:
- """
+ :param module:
+ :param batch_client:
+ :return:
+ """
changed = False
@@ -294,36 +295,48 @@ def create_job_definition(module, batch_client):
container_properties_params = set_api_params(module, get_container_property_params())
retry_strategy_params = set_api_params(module, get_retry_strategy_params())
- api_params['retryStrategy'] = retry_strategy_params
- api_params['containerProperties'] = container_properties_params
+ api_params["retryStrategy"] = retry_strategy_params
+ api_params["containerProperties"] = container_properties_params
try:
if not module.check_mode:
batch_client.register_job_definition(**api_params)
changed = True
except (BotoCoreError, ClientError) as e:
- module.fail_json_aws(e, msg='Error registering job definition')
+ module.fail_json_aws(e, msg="Error registering job definition")
return changed
def get_retry_strategy_params():
- return ('attempts',)
+ return ("attempts",)
def get_container_property_params():
- return ('image', 'vcpus', 'memory', 'command', 'job_role_arn', 'volumes', 'environment', 'mount_points',
- 'readonly_root_filesystem', 'privileged', 'ulimits', 'user')
+ return (
+ "image",
+ "vcpus",
+ "memory",
+ "command",
+ "job_role_arn",
+ "volumes",
+ "environment",
+ "mount_points",
+ "readonly_root_filesystem",
+ "privileged",
+ "ulimits",
+ "user",
+ )
def get_base_params():
- return 'job_definition_name', 'type', 'parameters'
+ return "job_definition_name", "type", "parameters"
def get_compute_environment_order_list(module):
compute_environment_order_list = []
- for ceo in module.params['compute_environment_order']:
- compute_environment_order_list.append(dict(order=ceo['order'], computeEnvironment=ceo['compute_environment']))
+ for ceo in module.params["compute_environment_order"]:
+ compute_environment_order_list.append(dict(order=ceo["order"], computeEnvironment=ceo["compute_environment"]))
return compute_environment_order_list
@@ -340,10 +353,10 @@ def remove_job_definition(module, batch_client):
try:
if not module.check_mode:
- batch_client.deregister_job_definition(jobDefinition=module.params['job_definition_arn'])
+ batch_client.deregister_job_definition(jobDefinition=module.params["job_definition_arn"])
changed = True
except (BotoCoreError, ClientError) as e:
- module.fail_json_aws(e, msg='Error removing job definition')
+ module.fail_json_aws(e, msg="Error removing job definition")
return changed
@@ -356,12 +369,12 @@ def job_definition_equal(module, current_definition):
break
for param in get_container_property_params():
- if module.params.get(param) != current_definition.get('containerProperties').get(cc(param)):
+ if module.params.get(param) != current_definition.get("containerProperties").get(cc(param)):
equal = False
break
for param in get_retry_strategy_params():
- if module.params.get(param) != current_definition.get('retryStrategy').get(cc(param)):
+ if module.params.get(param) != current_definition.get("retryStrategy").get(cc(param)):
equal = False
break
@@ -370,10 +383,10 @@ def job_definition_equal(module, current_definition):
def manage_state(module, batch_client):
changed = False
- current_state = 'absent'
- state = module.params['state']
- job_definition_name = module.params['job_definition_name']
- action_taken = 'none'
+ current_state = "absent"
+ state = module.params["state"]
+ job_definition_name = module.params["job_definition_name"]
+ action_taken = "none"
response = None
check_mode = module.check_mode
@@ -381,28 +394,28 @@ def manage_state(module, batch_client):
# check if the job definition exists
current_job_definition = get_current_job_definition(module, batch_client)
if current_job_definition:
- current_state = 'present'
+ current_state = "present"
- if state == 'present':
- if current_state == 'present':
+ if state == "present":
+ if current_state == "present":
# check if definition has changed and register a new version if necessary
if not job_definition_equal(module, current_job_definition):
create_job_definition(module, batch_client)
- action_taken = 'updated with new version'
+ action_taken = "updated with new version"
changed = True
else:
# Create Job definition
changed = create_job_definition(module, batch_client)
- action_taken = 'added'
+ action_taken = "added"
response = get_current_job_definition(module, batch_client)
if not response:
- module.fail_json(msg='Unable to get job definition information after creating/updating')
+ module.fail_json(msg="Unable to get job definition information after creating/updating")
else:
- if current_state == 'present':
+ if current_state == "present":
# remove the Job definition
changed = remove_job_definition(module, batch_client)
- action_taken = 'deregistered'
+ action_taken = "deregistered"
return dict(changed=changed, batch_job_definition_action=action_taken, response=response)
@@ -412,6 +425,7 @@ def manage_state(module, batch_client):
#
# ---------------------------------------------------------------------------------------------------
+
def main():
"""
Main entry point.
@@ -420,32 +434,29 @@ def main():
"""
argument_spec = dict(
- state=dict(required=False, default='present', choices=['present', 'absent']),
+ state=dict(required=False, default="present", choices=["present", "absent"]),
job_definition_name=dict(required=True),
job_definition_arn=dict(),
type=dict(required=True),
- parameters=dict(type='dict'),
+ parameters=dict(type="dict"),
image=dict(required=True),
- vcpus=dict(type='int', required=True),
- memory=dict(type='int', required=True),
- command=dict(type='list', default=[], elements='str'),
+ vcpus=dict(type="int", required=True),
+ memory=dict(type="int", required=True),
+ command=dict(type="list", default=[], elements="str"),
job_role_arn=dict(),
- volumes=dict(type='list', default=[], elements='dict'),
- environment=dict(type='list', default=[], elements='dict'),
- mount_points=dict(type='list', default=[], elements='dict'),
+ volumes=dict(type="list", default=[], elements="dict"),
+ environment=dict(type="list", default=[], elements="dict"),
+ mount_points=dict(type="list", default=[], elements="dict"),
readonly_root_filesystem=dict(),
privileged=dict(),
- ulimits=dict(type='list', default=[], elements='dict'),
+ ulimits=dict(type="list", default=[], elements="dict"),
user=dict(),
- attempts=dict(type='int')
+ attempts=dict(type="int"),
)
- module = AnsibleAWSModule(
- argument_spec=argument_spec,
- supports_check_mode=True
- )
+ module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
- batch_client = module.client('batch')
+ batch_client = module.client("batch")
validate_params(module, batch_client)
@@ -454,5 +465,5 @@ def main():
module.exit_json(**camel_dict_to_snake_dict(results))
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/batch_job_queue.py b/ansible_collections/community/aws/plugins/modules/batch_job_queue.py
index ef48896a4..4be42cbc5 100644
--- a/ansible_collections/community/aws/plugins/modules/batch_job_queue.py
+++ b/ansible_collections/community/aws/plugins/modules/batch_job_queue.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright (c) 2017 Jon Meran <jonathan.meran@sonos.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: batch_job_queue
version_added: 1.0.0
@@ -63,12 +61,12 @@ options:
type: str
description: The name of the compute environment.
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
- name: My Batch Job Queue
community.aws.batch_job_queue:
job_queue_name: jobQueueName
@@ -77,18 +75,18 @@ EXAMPLES = '''
job_queue_state: ENABLED
priority: 1
compute_environment_order:
- - order: 1
- compute_environment: my_compute_env1
- - order: 2
- compute_environment: my_compute_env2
+ - order: 1
+ compute_environment: my_compute_env1
+ - order: 2
+ compute_environment: my_compute_env2
register: batch_job_queue_action
- name: show results
ansible.builtin.debug:
var: batch_job_queue_action
-'''
+"""
-RETURN = r'''
+RETURN = r"""
---
output:
description: "returns what action was taken, whether something was changed, invocation and response"
@@ -104,17 +102,20 @@ output:
status: UPDATING
status_reason: "JobQueue Healthy"
type: dict
-'''
-
-from ansible_collections.amazon.aws.plugins.module_utils.batch import set_api_params
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict
+"""
try:
- from botocore.exceptions import BotoCoreError, ClientError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
except ImportError:
pass # Handled by AnsibleAWSModule
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.batch import set_api_params
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
+
# ---------------------------------------------------------------------------------------------------
#
# Helper Functions & classes
@@ -137,50 +138,49 @@ def validate_params(module):
#
# ---------------------------------------------------------------------------------------------------
+
def get_current_job_queue(module, client):
try:
- environments = client.describe_job_queues(
- jobQueues=[module.params['job_queue_name']]
- )
- return environments['jobQueues'][0] if len(environments['jobQueues']) > 0 else None
+ environments = client.describe_job_queues(jobQueues=[module.params["job_queue_name"]])
+ return environments["jobQueues"][0] if len(environments["jobQueues"]) > 0 else None
except ClientError:
return None
def create_job_queue(module, client):
"""
- Adds a Batch job queue
+ Adds a Batch job queue
- :param module:
- :param client:
- :return:
- """
+ :param module:
+ :param client:
+ :return:
+ """
changed = False
# set API parameters
- params = ('job_queue_name', 'priority')
+ params = ("job_queue_name", "priority")
api_params = set_api_params(module, params)
- if module.params['job_queue_state'] is not None:
- api_params['state'] = module.params['job_queue_state']
+ if module.params["job_queue_state"] is not None:
+ api_params["state"] = module.params["job_queue_state"]
- api_params['computeEnvironmentOrder'] = get_compute_environment_order_list(module)
+ api_params["computeEnvironmentOrder"] = get_compute_environment_order_list(module)
try:
if not module.check_mode:
client.create_job_queue(**api_params)
changed = True
except (BotoCoreError, ClientError) as e:
- module.fail_json_aws(e, msg='Error creating compute environment')
+ module.fail_json_aws(e, msg="Error creating compute environment")
return changed
def get_compute_environment_order_list(module):
compute_environment_order_list = []
- for ceo in module.params['compute_environment_order']:
- compute_environment_order_list.append(dict(order=ceo['order'], computeEnvironment=ceo['compute_environment']))
+ for ceo in module.params["compute_environment_order"]:
+ compute_environment_order_list.append(dict(order=ceo["order"], computeEnvironment=ceo["compute_environment"]))
return compute_environment_order_list
@@ -196,25 +196,25 @@ def remove_job_queue(module, client):
changed = False
# set API parameters
- api_params = {'jobQueue': module.params['job_queue_name']}
+ api_params = {"jobQueue": module.params["job_queue_name"]}
try:
if not module.check_mode:
client.delete_job_queue(**api_params)
changed = True
except (BotoCoreError, ClientError) as e:
- module.fail_json_aws(e, msg='Error removing job queue')
+ module.fail_json_aws(e, msg="Error removing job queue")
return changed
def manage_state(module, client):
changed = False
- current_state = 'absent'
- state = module.params['state']
- job_queue_state = module.params['job_queue_state']
- job_queue_name = module.params['job_queue_name']
- priority = module.params['priority']
- action_taken = 'none'
+ current_state = "absent"
+ state = module.params["state"]
+ job_queue_state = module.params["job_queue_state"]
+ job_queue_name = module.params["job_queue_name"]
+ priority = module.params["priority"]
+ action_taken = "none"
response = None
check_mode = module.check_mode
@@ -222,25 +222,25 @@ def manage_state(module, client):
# check if the job queue exists
current_job_queue = get_current_job_queue(module, client)
if current_job_queue:
- current_state = 'present'
+ current_state = "present"
- if state == 'present':
- if current_state == 'present':
+ if state == "present":
+ if current_state == "present":
updates = False
# Update Batch Job Queue configuration
- job_kwargs = {'jobQueue': job_queue_name}
+ job_kwargs = {"jobQueue": job_queue_name}
# Update configuration if needed
- if job_queue_state and current_job_queue['state'] != job_queue_state:
- job_kwargs.update({'state': job_queue_state})
+ if job_queue_state and current_job_queue["state"] != job_queue_state:
+ job_kwargs.update({"state": job_queue_state})
updates = True
- if priority is not None and current_job_queue['priority'] != priority:
- job_kwargs.update({'priority': priority})
+ if priority is not None and current_job_queue["priority"] != priority:
+ job_kwargs.update({"priority": priority})
updates = True
new_compute_environment_order_list = get_compute_environment_order_list(module)
- if new_compute_environment_order_list != current_job_queue['computeEnvironmentOrder']:
- job_kwargs['computeEnvironmentOrder'] = new_compute_environment_order_list
+ if new_compute_environment_order_list != current_job_queue["computeEnvironmentOrder"]:
+ job_kwargs["computeEnvironmentOrder"] = new_compute_environment_order_list
updates = True
if updates:
@@ -255,17 +255,17 @@ def manage_state(module, client):
else:
# Create Job Queue
changed = create_job_queue(module, client)
- action_taken = 'added'
+ action_taken = "added"
# Describe job queue
response = get_current_job_queue(module, client)
if not response:
- module.fail_json(msg='Unable to get job queue information after creating/updating')
+ module.fail_json(msg="Unable to get job queue information after creating/updating")
else:
- if current_state == 'present':
+ if current_state == "present":
# remove the Job Queue
changed = remove_job_queue(module, client)
- action_taken = 'deleted'
+ action_taken = "deleted"
return dict(changed=changed, batch_job_queue_action=action_taken, response=response)
@@ -275,6 +275,7 @@ def manage_state(module, client):
#
# ---------------------------------------------------------------------------------------------------
+
def main():
"""
Main entry point.
@@ -283,19 +284,16 @@ def main():
"""
argument_spec = dict(
- state=dict(required=False, default='present', choices=['present', 'absent']),
+ state=dict(required=False, default="present", choices=["present", "absent"]),
job_queue_name=dict(required=True),
- job_queue_state=dict(required=False, default='ENABLED', choices=['ENABLED', 'DISABLED']),
- priority=dict(type='int', required=True),
- compute_environment_order=dict(type='list', required=True, elements='dict'),
+ job_queue_state=dict(required=False, default="ENABLED", choices=["ENABLED", "DISABLED"]),
+ priority=dict(type="int", required=True),
+ compute_environment_order=dict(type="list", required=True, elements="dict"),
)
- module = AnsibleAWSModule(
- argument_spec=argument_spec,
- supports_check_mode=True
- )
+ module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
- client = module.client('batch')
+ client = module.client("batch")
validate_params(module)
@@ -304,5 +302,5 @@ def main():
module.exit_json(**camel_dict_to_snake_dict(results))
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/cloudformation_exports_info.py b/ansible_collections/community/aws/plugins/modules/cloudformation_exports_info.py
index f7e71e2f8..ff32b2124 100644
--- a/ansible_collections/community/aws/plugins/modules/cloudformation_exports_info.py
+++ b/ansible_collections/community/aws/plugins/modules/cloudformation_exports_info.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
module: cloudformation_exports_info
short_description: Read a value from CloudFormation Exports
version_added: 1.0.0
@@ -15,63 +13,60 @@ description:
author:
- "Michael Moyle (@mmoyle)"
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
-'''
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
+# Note: These examples do not set authentication details, see the AWS Guide for details.
- name: Get Exports
- community.aws.cloudformation_exports_info:
- profile: 'my_aws_profile'
- region: 'my_region'
+ community.aws.cloudformation_exports_info: {}
register: cf_exports
- ansible.builtin.debug:
msg: "{{ cf_exports }}"
-'''
+"""
-RETURN = '''
+RETURN = r"""
export_items:
description: A dictionary of Exports items names and values.
returned: Always
type: dict
-'''
-
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
+"""
try:
- from botocore.exceptions import ClientError
from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
except ImportError:
pass # handled by AnsibleAWSModule
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
+
@AWSRetry.exponential_backoff()
def list_exports(cloudformation_client):
- '''Get Exports Names and Values and return in dictionary '''
- list_exports_paginator = cloudformation_client.get_paginator('list_exports')
- exports = list_exports_paginator.paginate().build_full_result()['Exports']
+ """Get Exports Names and Values and return in dictionary"""
+ list_exports_paginator = cloudformation_client.get_paginator("list_exports")
+ exports = list_exports_paginator.paginate().build_full_result()["Exports"]
export_items = dict()
for item in exports:
- export_items[item['Name']] = item['Value']
+ export_items[item["Name"]] = item["Value"]
return export_items
def main():
argument_spec = dict()
- result = dict(
- changed=False,
- original_message=''
- )
+ result = dict(changed=False, original_message="")
module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
- cloudformation_client = module.client('cloudformation')
+ cloudformation_client = module.client("cloudformation")
try:
- result['export_items'] = list_exports(cloudformation_client)
+ result["export_items"] = list_exports(cloudformation_client)
except (ClientError, BotoCoreError) as e:
module.fail_json_aws(e)
@@ -80,5 +75,5 @@ def main():
module.exit_json(**result)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/cloudformation_stack_set.py b/ansible_collections/community/aws/plugins/modules/cloudformation_stack_set.py
index c6771db5e..ebb9403e8 100644
--- a/ansible_collections/community/aws/plugins/modules/cloudformation_stack_set.py
+++ b/ansible_collections/community/aws/plugins/modules/cloudformation_stack_set.py
@@ -1,20 +1,18 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: (c) 2018, Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: cloudformation_stack_set
version_added: 1.0.0
short_description: Manage groups of CloudFormation stacks
description:
- - Launches/updates/deletes AWS CloudFormation Stack Sets.
+ - Launches/updates/deletes AWS CloudFormation Stack Sets.
notes:
- - To make an individual stack, you want the M(amazon.aws.cloudformation) module.
+ - To make an individual stack, you want the M(amazon.aws.cloudformation) module.
options:
name:
description:
@@ -169,14 +167,15 @@ options:
- Note that this setting lets you specify the maximum for operations.
For large deployments, under certain circumstances the actual count may be lower.
-author: "Ryan Scott Brown (@ryansb)"
+author:
+ - "Ryan Scott Brown (@ryansb)"
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
-'''
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
- name: Create a stack set with instances in two accounts
community.aws.cloudformation_stack_set:
name: my-stack
@@ -202,7 +201,7 @@ EXAMPLES = r'''
- 123456789012
- 234567890123
regions:
- - us-east-1
+ - us-east-1
- name: The same type of update, but wait for the update to complete in all stacks
community.aws.cloudformation_stack_set:
@@ -218,7 +217,7 @@ EXAMPLES = r'''
- 123456789012
- 234567890123
regions:
- - us-east-1
+ - us-east-1
- name: Register new accounts (create new stack instances) with an existing stack set.
community.aws.cloudformation_stack_set:
@@ -235,10 +234,10 @@ EXAMPLES = r'''
- 234567890123
- 345678901234
regions:
- - us-east-1
-'''
+ - us-east-1
+"""
-RETURN = r'''
+RETURN = r"""
operations_log:
type: list
description: Most recent events in CloudFormation's event log. This may be from a previous run in some cases.
@@ -316,8 +315,7 @@ stack_set:
other:
Type: "AWS::SNS::Topic"
Properties: {}
-
-''' # NOQA
+"""
import datetime
import itertools
@@ -325,7 +323,8 @@ import time
import uuid
try:
- from botocore.exceptions import ClientError, BotoCoreError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
except ImportError:
# handled by AnsibleAWSModule
pass
@@ -333,19 +332,20 @@ except ImportError:
from ansible.module_utils._text import to_native
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_tag_list
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import ansible_dict_to_boto3_tag_list
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def create_stack_set(module, stack_params, cfn):
try:
cfn.create_stack_set(aws_retry=True, **stack_params)
- return await_stack_set_exists(cfn, stack_params['StackSetName'])
+ return await_stack_set_exists(cfn, stack_params["StackSetName"])
except (ClientError, BotoCoreError) as err:
- module.fail_json_aws(err, msg="Failed to create stack set {0}.".format(stack_params.get('StackSetName')))
+ module.fail_json_aws(err, msg=f"Failed to create stack set {stack_params.get('StackSetName')}.")
def update_stack_set(module, stack_params, cfn):
@@ -354,22 +354,34 @@ def update_stack_set(module, stack_params, cfn):
# don't need to be updated.
try:
cfn.update_stack_set(**stack_params)
- except is_boto3_error_code('StackSetNotFound') as err: # pylint: disable=duplicate-except
+ except is_boto3_error_code("StackSetNotFound") as err: # pylint: disable=duplicate-except
module.fail_json_aws(err, msg="Failed to find stack set. Check the name & region.")
- except is_boto3_error_code('StackInstanceNotFound') as err: # pylint: disable=duplicate-except
- module.fail_json_aws(err, msg="One or more stack instances were not found for this stack set. Double check "
- "the `accounts` and `regions` parameters.")
- except is_boto3_error_code('OperationInProgressException') as err: # pylint: disable=duplicate-except
+ except is_boto3_error_code("StackInstanceNotFound") as err: # pylint: disable=duplicate-except
module.fail_json_aws(
- err, msg="Another operation is already in progress on this stack set - please try again later. When making "
- "multiple cloudformation_stack_set calls, it's best to enable `wait: true` to avoid unfinished op errors.")
+ err,
+ msg=(
+ "One or more stack instances were not found for this stack set. Double check "
+ "the `accounts` and `regions` parameters."
+ ),
+ )
+ except is_boto3_error_code("OperationInProgressException") as err: # pylint: disable=duplicate-except
+ module.fail_json_aws(
+ err,
+ msg=(
+ "Another operation is already in progress on this stack set - please try again later. When making"
+ " multiple cloudformation_stack_set calls, it's best to enable `wait: true` to avoid unfinished op"
+ " errors."
+ ),
+ )
except (ClientError, BotoCoreError) as err: # pylint: disable=duplicate-except
module.fail_json_aws(err, msg="Could not update stack set.")
- if module.params.get('wait'):
+ if module.params.get("wait"):
await_stack_set_operation(
- module, cfn, operation_id=stack_params['OperationId'],
- stack_set_name=stack_params['StackSetName'],
- max_wait=module.params.get('wait_timeout'),
+ module,
+ cfn,
+ operation_id=stack_params["OperationId"],
+ stack_set_name=stack_params["StackSetName"],
+ max_wait=module.params.get("wait_timeout"),
)
return True
@@ -379,20 +391,24 @@ def compare_stack_instances(cfn, stack_set_name, accounts, regions):
instance_list = cfn.list_stack_instances(
aws_retry=True,
StackSetName=stack_set_name,
- )['Summaries']
+ )["Summaries"]
desired_stack_instances = set(itertools.product(accounts, regions))
- existing_stack_instances = set((i['Account'], i['Region']) for i in instance_list)
+ existing_stack_instances = set((i["Account"], i["Region"]) for i in instance_list)
# new stacks, existing stacks, unspecified stacks
- return (desired_stack_instances - existing_stack_instances), existing_stack_instances, (existing_stack_instances - desired_stack_instances)
+ return (
+ (desired_stack_instances - existing_stack_instances),
+ existing_stack_instances,
+ (existing_stack_instances - desired_stack_instances),
+ )
@AWSRetry.jittered_backoff(retries=3, delay=4)
def stack_set_facts(cfn, stack_set_name):
try:
- ss = cfn.describe_stack_set(StackSetName=stack_set_name)['StackSet']
- ss['Tags'] = boto3_tag_list_to_ansible_dict(ss['Tags'])
+ ss = cfn.describe_stack_set(StackSetName=stack_set_name)["StackSet"]
+ ss["Tags"] = boto3_tag_list_to_ansible_dict(ss["Tags"])
return ss
- except cfn.exceptions.from_code('StackSetNotFound'):
+ except cfn.exceptions.from_code("StackSetNotFound"):
# Return None if the stack doesn't exist
return
@@ -403,29 +419,29 @@ def await_stack_set_operation(module, cfn, stack_set_name, operation_id, max_wai
for i in range(max_wait // 15):
try:
operation = cfn.describe_stack_set_operation(StackSetName=stack_set_name, OperationId=operation_id)
- if operation['StackSetOperation']['Status'] not in ('RUNNING', 'STOPPING'):
+ if operation["StackSetOperation"]["Status"] not in ("RUNNING", "STOPPING"):
# Stack set has completed operation
break
- except is_boto3_error_code('StackSetNotFound'): # pylint: disable=duplicate-except
+ except is_boto3_error_code("StackSetNotFound"): # pylint: disable=duplicate-except
pass
- except is_boto3_error_code('OperationNotFound'): # pylint: disable=duplicate-except
+ except is_boto3_error_code("OperationNotFound"): # pylint: disable=duplicate-except
pass
time.sleep(15)
- if operation and operation['StackSetOperation']['Status'] not in ('FAILED', 'STOPPED'):
+ if operation and operation["StackSetOperation"]["Status"] not in ("FAILED", "STOPPED"):
await_stack_instance_completion(
- module, cfn,
+ module,
+ cfn,
stack_set_name=stack_set_name,
# subtract however long we waited already
max_wait=int(max_wait - (datetime.datetime.now() - wait_start).total_seconds()),
)
- elif operation and operation['StackSetOperation']['Status'] in ('FAILED', 'STOPPED'):
+ elif operation and operation["StackSetOperation"]["Status"] in ("FAILED", "STOPPED"):
pass
else:
module.warn(
- "Timed out waiting for operation {0} on stack set {1} after {2} seconds. Returning unfinished operation".format(
- operation_id, stack_set_name, max_wait
- )
+ f"Timed out waiting for operation {operation_id} on stack set {stack_set_name} after {max_wait} seconds."
+ " Returning unfinished operation"
)
@@ -434,84 +450,83 @@ def await_stack_instance_completion(module, cfn, stack_set_name, max_wait):
for i in range(max_wait // 15):
try:
stack_instances = cfn.list_stack_instances(StackSetName=stack_set_name)
- to_await = [inst for inst in stack_instances['Summaries']
- if inst['Status'] != 'CURRENT']
+ to_await = [inst for inst in stack_instances["Summaries"] if inst["Status"] != "CURRENT"]
if not to_await:
- return stack_instances['Summaries']
- except is_boto3_error_code('StackSetNotFound'): # pylint: disable=duplicate-except
+ return stack_instances["Summaries"]
+ except is_boto3_error_code("StackSetNotFound"): # pylint: disable=duplicate-except
# this means the deletion beat us, or the stack set is not yet propagated
pass
time.sleep(15)
module.warn(
- "Timed out waiting for stack set {0} instances {1} to complete after {2} seconds. Returning unfinished operation".format(
- stack_set_name, ', '.join(s['StackId'] for s in to_await), max_wait
- )
+ f"Timed out waiting for stack set {stack_set_name} instances {', '.join(s['StackId'] for s in to_await)} to"
+ f" complete after {max_wait} seconds. Returning unfinished operation"
)
def await_stack_set_exists(cfn, stack_set_name):
# AWSRetry will retry on `StackSetNotFound` errors for us
- ss = cfn.describe_stack_set(StackSetName=stack_set_name, aws_retry=True)['StackSet']
- ss['Tags'] = boto3_tag_list_to_ansible_dict(ss['Tags'])
- return camel_dict_to_snake_dict(ss, ignore_list=('Tags',))
+ ss = cfn.describe_stack_set(StackSetName=stack_set_name, aws_retry=True)["StackSet"]
+ ss["Tags"] = boto3_tag_list_to_ansible_dict(ss["Tags"])
+ return camel_dict_to_snake_dict(ss, ignore_list=("Tags",))
def describe_stack_tree(module, stack_set_name, operation_ids=None):
- jittered_backoff_decorator = AWSRetry.jittered_backoff(retries=5, delay=3, max_delay=5, catch_extra_error_codes=['StackSetNotFound'])
- cfn = module.client('cloudformation', retry_decorator=jittered_backoff_decorator)
+ jittered_backoff_decorator = AWSRetry.jittered_backoff(
+ retries=5, delay=3, max_delay=5, catch_extra_error_codes=["StackSetNotFound"]
+ )
+ cfn = module.client("cloudformation", retry_decorator=jittered_backoff_decorator)
result = dict()
- result['stack_set'] = camel_dict_to_snake_dict(
+ result["stack_set"] = camel_dict_to_snake_dict(
cfn.describe_stack_set(
StackSetName=stack_set_name,
aws_retry=True,
- )['StackSet']
+ )["StackSet"]
)
- result['stack_set']['tags'] = boto3_tag_list_to_ansible_dict(result['stack_set']['tags'])
- result['operations_log'] = sorted(
+ result["stack_set"]["tags"] = boto3_tag_list_to_ansible_dict(result["stack_set"]["tags"])
+ result["operations_log"] = sorted(
camel_dict_to_snake_dict(
cfn.list_stack_set_operations(
StackSetName=stack_set_name,
aws_retry=True,
)
- )['summaries'],
- key=lambda x: x['creation_timestamp']
+ )["summaries"],
+ key=lambda x: x["creation_timestamp"],
)
- result['stack_instances'] = sorted(
- [
- camel_dict_to_snake_dict(i) for i in
- cfn.list_stack_instances(StackSetName=stack_set_name)['Summaries']
- ],
- key=lambda i: i['region'] + i['account']
+ result["stack_instances"] = sorted(
+ [camel_dict_to_snake_dict(i) for i in cfn.list_stack_instances(StackSetName=stack_set_name)["Summaries"]],
+ key=lambda i: i["region"] + i["account"],
)
if operation_ids:
- result['operations'] = []
+ result["operations"] = []
for op_id in operation_ids:
try:
- result['operations'].append(camel_dict_to_snake_dict(
- cfn.describe_stack_set_operation(
- StackSetName=stack_set_name,
- OperationId=op_id,
- )['StackSetOperation']
- ))
- except is_boto3_error_code('OperationNotFoundException'): # pylint: disable=duplicate-except
+ result["operations"].append(
+ camel_dict_to_snake_dict(
+ cfn.describe_stack_set_operation(
+ StackSetName=stack_set_name,
+ OperationId=op_id,
+ )["StackSetOperation"]
+ )
+ )
+ except is_boto3_error_code("OperationNotFoundException"): # pylint: disable=duplicate-except
pass
return result
def get_operation_preferences(module):
params = dict()
- if module.params.get('regions'):
- params['RegionOrder'] = list(module.params['regions'])
+ if module.params.get("regions"):
+ params["RegionOrder"] = list(module.params["regions"])
for param, api_name in {
- 'fail_count': 'FailureToleranceCount',
- 'fail_percentage': 'FailureTolerancePercentage',
- 'parallel_percentage': 'MaxConcurrentPercentage',
- 'parallel_count': 'MaxConcurrentCount',
+ "fail_count": "FailureToleranceCount",
+ "fail_percentage": "FailureTolerancePercentage",
+ "parallel_percentage": "MaxConcurrentPercentage",
+ "parallel_count": "MaxConcurrentCount",
}.items():
- if module.params.get('failure_tolerance', {}).get(param):
- params[api_name] = module.params.get('failure_tolerance', {}).get(param)
+ if module.params.get("failure_tolerance", {}).get(param):
+ params[api_name] = module.params.get("failure_tolerance", {}).get(param)
return params
@@ -519,148 +534,154 @@ def main():
argument_spec = dict(
name=dict(required=True),
description=dict(),
- wait=dict(type='bool', default=False),
- wait_timeout=dict(type='int', default=900),
- state=dict(default='present', choices=['present', 'absent']),
- purge_stacks=dict(type='bool', default=True),
- parameters=dict(type='dict', default={}),
- template=dict(type='path'),
+ wait=dict(type="bool", default=False),
+ wait_timeout=dict(type="int", default=900),
+ state=dict(default="present", choices=["present", "absent"]),
+ purge_stacks=dict(type="bool", default=True),
+ parameters=dict(type="dict", default={}),
+ template=dict(type="path"),
template_url=dict(),
template_body=dict(),
- capabilities=dict(type='list', elements='str', choices=['CAPABILITY_IAM', 'CAPABILITY_NAMED_IAM']),
- regions=dict(type='list', elements='str'),
- accounts=dict(type='list', elements='str'),
+ capabilities=dict(type="list", elements="str", choices=["CAPABILITY_IAM", "CAPABILITY_NAMED_IAM"]),
+ regions=dict(type="list", elements="str"),
+ accounts=dict(type="list", elements="str"),
failure_tolerance=dict(
- type='dict',
+ type="dict",
default={},
options=dict(
- fail_count=dict(type='int'),
- fail_percentage=dict(type='int'),
- parallel_percentage=dict(type='int'),
- parallel_count=dict(type='int'),
+ fail_count=dict(type="int"),
+ fail_percentage=dict(type="int"),
+ parallel_percentage=dict(type="int"),
+ parallel_count=dict(type="int"),
),
mutually_exclusive=[
- ['fail_count', 'fail_percentage'],
- ['parallel_count', 'parallel_percentage'],
+ ["fail_count", "fail_percentage"],
+ ["parallel_count", "parallel_percentage"],
],
),
- administration_role_arn=dict(aliases=['admin_role_arn', 'administration_role', 'admin_role']),
- execution_role_name=dict(aliases=['execution_role', 'exec_role', 'exec_role_name']),
- tags=dict(type='dict'),
+ administration_role_arn=dict(aliases=["admin_role_arn", "administration_role", "admin_role"]),
+ execution_role_name=dict(aliases=["execution_role", "exec_role", "exec_role_name"]),
+ tags=dict(type="dict"),
)
module = AnsibleAWSModule(
argument_spec=argument_spec,
- mutually_exclusive=[['template_url', 'template', 'template_body']],
- supports_check_mode=True
+ mutually_exclusive=[["template_url", "template", "template_body"]],
+ supports_check_mode=True,
)
# Wrap the cloudformation client methods that this module uses with
# automatic backoff / retry for throttling error codes
- jittered_backoff_decorator = AWSRetry.jittered_backoff(retries=10, delay=3, max_delay=30, catch_extra_error_codes=['StackSetNotFound'])
- cfn = module.client('cloudformation', retry_decorator=jittered_backoff_decorator)
- existing_stack_set = stack_set_facts(cfn, module.params['name'])
+ jittered_backoff_decorator = AWSRetry.jittered_backoff(
+ retries=10, delay=3, max_delay=30, catch_extra_error_codes=["StackSetNotFound"]
+ )
+ cfn = module.client("cloudformation", retry_decorator=jittered_backoff_decorator)
+ existing_stack_set = stack_set_facts(cfn, module.params["name"])
operation_uuid = to_native(uuid.uuid4())
operation_ids = []
# collect the parameters that are passed to boto3. Keeps us from having so many scalars floating around.
stack_params = {}
- state = module.params['state']
- if state == 'present' and not module.params['accounts']:
+ state = module.params["state"]
+ if state == "present" and not module.params["accounts"]:
module.fail_json(
- msg="Can't create a stack set without choosing at least one account. "
+ msg=(
+ "Can't create a stack set without choosing at least one account. "
"To get the ID of the current account, use the aws_caller_info module."
+ )
)
- module.params['accounts'] = [to_native(a) for a in module.params['accounts']]
+ module.params["accounts"] = [to_native(a) for a in module.params["accounts"]]
- stack_params['StackSetName'] = module.params['name']
- if module.params.get('description'):
- stack_params['Description'] = module.params['description']
+ stack_params["StackSetName"] = module.params["name"]
+ if module.params.get("description"):
+ stack_params["Description"] = module.params["description"]
- if module.params.get('capabilities'):
- stack_params['Capabilities'] = module.params['capabilities']
+ if module.params.get("capabilities"):
+ stack_params["Capabilities"] = module.params["capabilities"]
- if module.params['template'] is not None:
- with open(module.params['template'], 'r') as tpl:
- stack_params['TemplateBody'] = tpl.read()
- elif module.params['template_body'] is not None:
- stack_params['TemplateBody'] = module.params['template_body']
- elif module.params['template_url'] is not None:
- stack_params['TemplateURL'] = module.params['template_url']
+ if module.params["template"] is not None:
+ with open(module.params["template"], "r") as tpl:
+ stack_params["TemplateBody"] = tpl.read()
+ elif module.params["template_body"] is not None:
+ stack_params["TemplateBody"] = module.params["template_body"]
+ elif module.params["template_url"] is not None:
+ stack_params["TemplateURL"] = module.params["template_url"]
else:
# no template is provided, but if the stack set exists already, we can use the existing one.
if existing_stack_set:
- stack_params['UsePreviousTemplate'] = True
+ stack_params["UsePreviousTemplate"] = True
else:
module.fail_json(
- msg="The Stack Set {0} does not exist, and no template was provided. Provide one of `template`, "
- "`template_body`, or `template_url`".format(module.params['name'])
+ msg=(
+ f"The Stack Set {module.params['name']} does not exist, and no template was provided. Provide one"
+ " of `template`, `template_body`, or `template_url`"
+ )
)
- stack_params['Parameters'] = []
- for k, v in module.params['parameters'].items():
+ stack_params["Parameters"] = []
+ for k, v in module.params["parameters"].items():
if isinstance(v, dict):
# set parameter based on a dict to allow additional CFN Parameter Attributes
param = dict(ParameterKey=k)
- if 'value' in v:
- param['ParameterValue'] = to_native(v['value'])
+ if "value" in v:
+ param["ParameterValue"] = to_native(v["value"])
- if 'use_previous_value' in v and bool(v['use_previous_value']):
- param['UsePreviousValue'] = True
- param.pop('ParameterValue', None)
+ if "use_previous_value" in v and bool(v["use_previous_value"]):
+ param["UsePreviousValue"] = True
+ param.pop("ParameterValue", None)
- stack_params['Parameters'].append(param)
+ stack_params["Parameters"].append(param)
else:
# allow default k/v configuration to set a template parameter
- stack_params['Parameters'].append({'ParameterKey': k, 'ParameterValue': str(v)})
+ stack_params["Parameters"].append({"ParameterKey": k, "ParameterValue": str(v)})
- if module.params.get('tags') and isinstance(module.params.get('tags'), dict):
- stack_params['Tags'] = ansible_dict_to_boto3_tag_list(module.params['tags'])
+ if module.params.get("tags") and isinstance(module.params.get("tags"), dict):
+ stack_params["Tags"] = ansible_dict_to_boto3_tag_list(module.params["tags"])
- if module.params.get('administration_role_arn'):
+ if module.params.get("administration_role_arn"):
# TODO loosen the semantics here to autodetect the account ID and build the ARN
- stack_params['AdministrationRoleARN'] = module.params['administration_role_arn']
- if module.params.get('execution_role_name'):
- stack_params['ExecutionRoleName'] = module.params['execution_role_name']
+ stack_params["AdministrationRoleARN"] = module.params["administration_role_arn"]
+ if module.params.get("execution_role_name"):
+ stack_params["ExecutionRoleName"] = module.params["execution_role_name"]
result = {}
if module.check_mode:
- if state == 'absent' and existing_stack_set:
- module.exit_json(changed=True, msg='Stack set would be deleted', meta=[])
- elif state == 'absent' and not existing_stack_set:
- module.exit_json(changed=False, msg='Stack set doesn\'t exist', meta=[])
- elif state == 'present' and not existing_stack_set:
- module.exit_json(changed=True, msg='New stack set would be created', meta=[])
- elif state == 'present' and existing_stack_set:
+ if state == "absent" and existing_stack_set:
+ module.exit_json(changed=True, msg="Stack set would be deleted", meta=[])
+ elif state == "absent" and not existing_stack_set:
+ module.exit_json(changed=False, msg="Stack set doesn't exist", meta=[])
+ elif state == "present" and not existing_stack_set:
+ module.exit_json(changed=True, msg="New stack set would be created", meta=[])
+ elif state == "present" and existing_stack_set:
new_stacks, existing_stacks, unspecified_stacks = compare_stack_instances(
cfn,
- module.params['name'],
- module.params['accounts'],
- module.params['regions'],
+ module.params["name"],
+ module.params["accounts"],
+ module.params["regions"],
)
if new_stacks:
- module.exit_json(changed=True, msg='New stack instance(s) would be created', meta=[])
- elif unspecified_stacks and module.params.get('purge_stack_instances'):
- module.exit_json(changed=True, msg='Old stack instance(s) would be deleted', meta=[])
+ module.exit_json(changed=True, msg="New stack instance(s) would be created", meta=[])
+ elif unspecified_stacks and module.params.get("purge_stack_instances"):
+ module.exit_json(changed=True, msg="Old stack instance(s) would be deleted", meta=[])
else:
# TODO: need to check the template and other settings for correct check mode
- module.exit_json(changed=False, msg='No changes detected', meta=[])
+ module.exit_json(changed=False, msg="No changes detected", meta=[])
changed = False
- if state == 'present':
+ if state == "present":
if not existing_stack_set:
# on create this parameter has a different name, and cannot be referenced later in the job log
- stack_params['ClientRequestToken'] = 'Ansible-StackSet-Create-{0}'.format(operation_uuid)
+ stack_params["ClientRequestToken"] = f"Ansible-StackSet-Create-{operation_uuid}"
changed = True
create_stack_set(module, stack_params, cfn)
else:
- stack_params['OperationId'] = 'Ansible-StackSet-Update-{0}'.format(operation_uuid)
- operation_ids.append(stack_params['OperationId'])
- if module.params.get('regions'):
- stack_params['OperationPreferences'] = get_operation_preferences(module)
+ stack_params["OperationId"] = f"Ansible-StackSet-Update-{operation_uuid}"
+ operation_ids.append(stack_params["OperationId"])
+ if module.params.get("regions"):
+ stack_params["OperationPreferences"] = get_operation_preferences(module)
changed |= update_stack_set(module, stack_params, cfn)
await_stack_set_operation(
@@ -674,24 +695,24 @@ def main():
# now create/update any appropriate stack instances
new_stack_instances, existing_stack_instances, unspecified_stack_instances = compare_stack_instances(
cfn,
- module.params['name'],
- module.params['accounts'],
- module.params['regions'],
+ module.params["name"],
+ module.params["accounts"],
+ module.params["regions"],
)
if new_stack_instances:
- operation_ids.append('Ansible-StackInstance-Create-{0}'.format(operation_uuid))
+ operation_ids.append(f"Ansible-StackInstance-Create-{operation_uuid}")
changed = True
cfn.create_stack_instances(
- StackSetName=module.params['name'],
+ StackSetName=module.params["name"],
Accounts=list(set(acct for acct, region in new_stack_instances)),
Regions=list(set(region for acct, region in new_stack_instances)),
OperationPreferences=get_operation_preferences(module),
OperationId=operation_ids[-1],
)
else:
- operation_ids.append('Ansible-StackInstance-Update-{0}'.format(operation_uuid))
+ operation_ids.append(f"Ansible-StackInstance-Update-{operation_uuid}")
cfn.update_stack_instances(
- StackSetName=module.params['name'],
+ StackSetName=module.params["name"],
Accounts=list(set(acct for acct, region in existing_stack_instances)),
Regions=list(set(region for acct, region in existing_stack_instances)),
OperationPreferences=get_operation_preferences(module),
@@ -699,55 +720,67 @@ def main():
)
for op in operation_ids:
await_stack_set_operation(
- module, cfn, operation_id=op,
- stack_set_name=module.params['name'],
- max_wait=module.params.get('wait_timeout'),
+ module,
+ cfn,
+ operation_id=op,
+ stack_set_name=module.params["name"],
+ max_wait=module.params.get("wait_timeout"),
)
- elif state == 'absent':
+ elif state == "absent":
if not existing_stack_set:
- module.exit_json(msg='Stack set {0} does not exist'.format(module.params['name']))
- if module.params.get('purge_stack_instances') is False:
+ module.exit_json(msg=f"Stack set {module.params['name']} does not exist")
+ if module.params.get("purge_stack_instances") is False:
pass
try:
cfn.delete_stack_set(
- StackSetName=module.params['name'],
+ StackSetName=module.params["name"],
+ )
+ module.exit_json(msg=f"Stack set {module.params['name']} deleted")
+ except is_boto3_error_code("OperationInProgressException") as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(
+ e, msg=f"Cannot delete stack {module.params['name']} while there is an operation in progress"
)
- module.exit_json(msg='Stack set {0} deleted'.format(module.params['name']))
- except is_boto3_error_code('OperationInProgressException') as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, msg='Cannot delete stack {0} while there is an operation in progress'.format(module.params['name']))
- except is_boto3_error_code('StackSetNotEmptyException'): # pylint: disable=duplicate-except
- delete_instances_op = 'Ansible-StackInstance-Delete-{0}'.format(operation_uuid)
+ except is_boto3_error_code("StackSetNotEmptyException"): # pylint: disable=duplicate-except
+ delete_instances_op = f"Ansible-StackInstance-Delete-{operation_uuid}"
cfn.delete_stack_instances(
- StackSetName=module.params['name'],
- Accounts=module.params['accounts'],
- Regions=module.params['regions'],
- RetainStacks=(not module.params.get('purge_stacks')),
- OperationId=delete_instances_op
+ StackSetName=module.params["name"],
+ Accounts=module.params["accounts"],
+ Regions=module.params["regions"],
+ RetainStacks=(not module.params.get("purge_stacks")),
+ OperationId=delete_instances_op,
)
await_stack_set_operation(
- module, cfn, operation_id=delete_instances_op,
- stack_set_name=stack_params['StackSetName'],
- max_wait=module.params.get('wait_timeout'),
+ module,
+ cfn,
+ operation_id=delete_instances_op,
+ stack_set_name=stack_params["StackSetName"],
+ max_wait=module.params.get("wait_timeout"),
)
try:
cfn.delete_stack_set(
- StackSetName=module.params['name'],
+ StackSetName=module.params["name"],
)
- except is_boto3_error_code('StackSetNotEmptyException') as exc: # pylint: disable=duplicate-except
+ except is_boto3_error_code("StackSetNotEmptyException") as exc: # pylint: disable=duplicate-except
# this time, it is likely that either the delete failed or there are more stacks.
instances = cfn.list_stack_instances(
- StackSetName=module.params['name'],
+ StackSetName=module.params["name"],
+ )
+ stack_states = ", ".join(
+ "(account={Account}, region={Region}, state={Status})".format(**i) for i in instances["Summaries"]
+ )
+ module.fail_json_aws(
+ exc,
+ msg="Could not purge all stacks, or not all accounts/regions were chosen for deletion: "
+ + stack_states,
)
- stack_states = ', '.join('(account={Account}, region={Region}, state={Status})'.format(**i) for i in instances['Summaries'])
- module.fail_json_aws(exc, msg='Could not purge all stacks, or not all accounts/regions were chosen for deletion: ' + stack_states)
- module.exit_json(changed=True, msg='Stack set {0} deleted'.format(module.params['name']))
+ module.exit_json(changed=True, msg=f"Stack set {module.params['name']} deleted")
- result.update(**describe_stack_tree(module, stack_params['StackSetName'], operation_ids=operation_ids))
- if any(o['status'] == 'FAILED' for o in result['operations']):
+ result.update(**describe_stack_tree(module, stack_params["StackSetName"], operation_ids=operation_ids))
+ if any(o["status"] == "FAILED" for o in result["operations"]):
module.fail_json(msg="One or more operations failed to execute", **result)
module.exit_json(changed=changed, **result)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/cloudfront_distribution.py b/ansible_collections/community/aws/plugins/modules/cloudfront_distribution.py
index 447fd994e..13718cfb8 100644
--- a/ansible_collections/community/aws/plugins/modules/cloudfront_distribution.py
+++ b/ansible_collections/community/aws/plugins/modules/cloudfront_distribution.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
version_added: 1.0.0
@@ -21,12 +19,6 @@ author:
- Willem van Ketwich (@wilvk)
- Will Thames (@willthames)
-extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
- - amazon.aws.boto3
- - amazon.aws.tags
-
options:
state:
@@ -119,6 +111,17 @@ options:
origin_path:
description: Tells CloudFront to request your content from a directory in your Amazon S3 bucket or your custom origin.
type: str
+ origin_shield:
+ description: Specify origin shield options for the origin.
+ type: dict
+ suboptions:
+ enabled:
+ description: Indicate whether you want the origin to have Origin Shield enabled or not.
+ type: bool
+ origin_shield_region:
+ description: Specify which AWS region will be used for Origin Shield. Required if Origin Shield is enabled.
+ type: str
+ version_added: 6.0.0
custom_headers:
description:
- Custom headers you wish to add to the request before passing it to the origin.
@@ -169,7 +172,18 @@ options:
origin_keepalive_timeout:
description: A keep-alive timeout (in seconds).
type: int
-
+ connection_attempts:
+ description: The number of times that CloudFront attempts to connect to the origin.
+ The minimum number is C(1), the maximum is C(3).
+ type: int
+ default: 3
+ version_added: 6.0.0
+ connection_timeout:
+ description: The number of seconds that CloudFront waits when trying to establish a connection to the origin.
+ The minimum timeout is C(1) second, the maximum is C(10) seconds.
+ type: int
+ default: 10
+ version_added: 6.0.0
purge_origins:
description: Whether to remove any origins that aren't listed in I(origins).
default: false
@@ -191,9 +205,25 @@ options:
description:
- The ID of the header policy that CloudFront adds to responses that it sends to viewers.
type: str
+ cache_policy_id:
+ version_added: 7.1.0
+ description:
+ - The ID of the cache policy for CloudFront to use for the default cache behavior.
+ - A behavior should use either a C(cache_policy_id) or a C(forwarded_values) option.
+ - For more information see the CloudFront documentation
+ at U(https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/controlling-the-cache-key.html)
+ type: str
+ origin_request_policy_id:
+ version_added: 7.1.0
+ description:
+ - The ID of the origin request policy for CloudFront to use for the default cache behavior.
+ - For more information see the CloudFront documentation
+ at U(https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/controlling-origin-requests.html)
+ type: str
forwarded_values:
description:
- A dict that specifies how CloudFront handles query strings and cookies.
+ - A behavior should use either a C(cache_policy_id) or a C(forwarded_values) option.
type: dict
suboptions:
query_string:
@@ -312,9 +342,25 @@ options:
description:
- The ID of the header policy that CloudFront adds to responses that it sends to viewers.
type: str
+ cache_policy_id:
+ version_added: 7.1.0
+ description:
+ - The ID of the cache policy for CloudFront to use for the cache behavior.
+ - A behavior should use either a C(cache_policy_id) or a C(forwarded_values) option.
+ - For more information see the CloudFront documentation
+ at U(https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/controlling-the-cache-key.html)
+ type: str
+ origin_request_policy_id:
+ version_added: 7.1.0
+ description:
+ - The ID of the origin request policy for CloudFront to use for the cache behavior.
+ - For more information see the CloudFront documentation
+ at U(https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/controlling-origin-requests.html)
+ type: str
forwarded_values:
description:
- A dict that specifies how CloudFront handles query strings and cookies.
+ - A behavior should use either a C(cache_policy_id) or a C(forwarded_values) option.
type: dict
suboptions:
query_string:
@@ -556,7 +602,7 @@ options:
description:
- The version of the http protocol to use for the distribution.
- AWS defaults this to C(http2).
- - Valid values are C(http1.1) and C(http2).
+ - Valid values are C(http1.1), C(http2), C(http3) and C(http2and3).
type: str
ipv6_enabled:
@@ -577,9 +623,14 @@ options:
default: 1800
type: int
-'''
+extends_documentation_fragment:
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.tags
+ - amazon.aws.boto3
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
- name: create a basic distribution with defaults and tags
community.aws.cloudfront_distribution:
state: present
@@ -606,7 +657,9 @@ EXAMPLES = r'''
state: present
distribution_id: E1RP5A2MJ8073O
comment: modified by cloudfront.py again
- aliases: [ 'www.my-distribution-source.com', 'zzz.aaa.io' ]
+ aliases:
+ - 'www.my-distribution-source.com'
+ - 'zzz.aaa.io'
- name: update a distribution's aliases and comment using an alias as a reference
community.aws.cloudfront_distribution:
@@ -633,12 +686,12 @@ EXAMPLES = r'''
state: present
caller_reference: unique test distribution ID
origins:
- - id: 'my test origin-000111'
- domain_name: www.example.com
- origin_path: /production
- custom_headers:
- - header_name: MyCustomHeaderName
- header_value: MyCustomHeaderValue
+ - id: 'my test origin-000111'
+ domain_name: www.example.com
+ origin_path: /production
+ custom_headers:
+ - header_name: MyCustomHeaderName
+ header_value: MyCustomHeaderValue
default_cache_behavior:
target_origin_id: 'my test origin-000111'
forwarded_values:
@@ -646,7 +699,7 @@ EXAMPLES = r'''
cookies:
forward: all
headers:
- - '*'
+ - '*'
viewer_protocol_policy: allow-all
smooth_streaming: true
compress: true
@@ -669,9 +722,9 @@ EXAMPLES = r'''
community.aws.cloudfront_distribution:
state: absent
caller_reference: replaceable distribution
-'''
+"""
-RETURN = r'''
+RETURN = r"""
active_trusted_signers:
description: Key pair IDs that CloudFront is aware of for each trusted signer.
returned: always
@@ -1278,6 +1331,32 @@ origins:
returned: always
type: str
sample: ''
+ connection_attempts:
+ description: The number of times that CloudFront attempts to connect to the origin.
+ returned: always
+ type: int
+ sample: 3
+ connection_timeout:
+ description: The number of seconds that CloudFront waits when trying to establish a connection to the origin.
+ returned: always
+ type: int
+ sample: 10
+ origin_shield:
+ description: Configuration of the origin Origin Shield.
+ returned: always
+ type: complex
+ contains:
+ enabled:
+ description: Whether Origin Shield is enabled or not.
+ returned: always
+ type: bool
+ sample: false
+ origin_shield_region:
+ description: Which region is used by Origin Shield.
+ returned: when enabled is true
+ type: str
+ sample: us-east-1
+ version_added: 6.0.0
s3_origin_config:
description: Origin access identity configuration for S3 Origin.
returned: when s3_origin_access_identity_enabled is true
@@ -1368,29 +1447,31 @@ web_acl_id:
returned: always
type: str
sample: abcd1234-1234-abcd-abcd-abcd12345678
-'''
+"""
-from ansible.module_utils._text import to_text, to_native
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.cloudfront_facts import CloudFrontFactsServiceManager
-from ansible.module_utils.common.dict_transformations import recursive_diff
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry, compare_aws_tags, ansible_dict_to_boto3_tag_list, boto3_tag_list_to_ansible_dict
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict, snake_dict_to_camel_dict
import datetime
-
-try:
- from collections import OrderedDict
-except ImportError:
- try:
- from ordereddict import OrderedDict
- except ImportError:
- pass # caught by AnsibleAWSModule (as python 2.6 + boto3 => ordereddict is installed)
+import re
+from collections import OrderedDict
try:
import botocore
except ImportError:
pass # caught by AnsibleAWSModule
+from ansible.module_utils._text import to_native
+from ansible.module_utils._text import to_text
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+from ansible.module_utils.common.dict_transformations import recursive_diff
+from ansible.module_utils.common.dict_transformations import snake_dict_to_camel_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.cloudfront_facts import CloudFrontFactsServiceManager
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import ansible_dict_to_boto3_tag_list
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import compare_aws_tags
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
+
def change_dict_key_name(dictionary, old_key, new_key):
if old_key in dictionary:
@@ -1417,43 +1498,44 @@ def ansible_list_to_cloudfront_list(list_items=None, include_quantity=True):
if list_items is None:
list_items = []
if not isinstance(list_items, list):
- raise ValueError('Expected a list, got a {0} with value {1}'.format(type(list_items).__name__, str(list_items)))
+ raise ValueError(f"Expected a list, got a {type(list_items).__name__} with value {str(list_items)}")
result = {}
if include_quantity:
- result['quantity'] = len(list_items)
+ result["quantity"] = len(list_items)
if len(list_items) > 0:
- result['items'] = list_items
+ result["items"] = list_items
return result
def create_distribution(client, module, config, tags):
try:
if not tags:
- return client.create_distribution(aws_retry=True, DistributionConfig=config)['Distribution']
+ return client.create_distribution(aws_retry=True, DistributionConfig=config)["Distribution"]
else:
- distribution_config_with_tags = {
- 'DistributionConfig': config,
- 'Tags': {
- 'Items': tags
- }
- }
- return client.create_distribution_with_tags(aws_retry=True, DistributionConfigWithTags=distribution_config_with_tags)['Distribution']
+ distribution_config_with_tags = {"DistributionConfig": config, "Tags": {"Items": tags}}
+ return client.create_distribution_with_tags(
+ aws_retry=True, DistributionConfigWithTags=distribution_config_with_tags
+ )["Distribution"]
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Error creating distribution")
def delete_distribution(client, module, distribution):
try:
- return client.delete_distribution(aws_retry=True, Id=distribution['Distribution']['Id'], IfMatch=distribution['ETag'])
+ return client.delete_distribution(
+ aws_retry=True, Id=distribution["Distribution"]["Id"], IfMatch=distribution["ETag"]
+ )
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Error deleting distribution %s" % to_native(distribution['Distribution']))
+ module.fail_json_aws(e, msg=f"Error deleting distribution {to_native(distribution['Distribution'])}")
def update_distribution(client, module, config, distribution_id, e_tag):
try:
- return client.update_distribution(aws_retry=True, DistributionConfig=config, Id=distribution_id, IfMatch=e_tag)['Distribution']
+ return client.update_distribution(aws_retry=True, DistributionConfig=config, Id=distribution_id, IfMatch=e_tag)[
+ "Distribution"
+ ]
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Error updating distribution to %s" % to_native(config))
+ module.fail_json_aws(e, msg=f"Error updating distribution to {to_native(config)}")
def tag_resource(client, module, arn, tags):
@@ -1473,7 +1555,7 @@ def untag_resource(client, module, arn, tag_keys):
def list_tags_for_resource(client, module, arn):
try:
response = client.list_tags_for_resource(aws_retry=True, Resource=arn)
- return boto3_tag_list_to_ansible_dict(response.get('Tags').get('Items'))
+ return boto3_tag_list_to_ansible_dict(response.get("Tags").get("Items"))
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Error listing tags for resource")
@@ -1505,103 +1587,131 @@ class CloudFrontValidationManager(object):
self.__default_https_port = 443
self.__default_ipv6_enabled = False
self.__default_origin_ssl_protocols = [
- 'TLSv1',
- 'TLSv1.1',
- 'TLSv1.2'
+ "TLSv1",
+ "TLSv1.1",
+ "TLSv1.2",
]
- self.__default_custom_origin_protocol_policy = 'match-viewer'
+ self.__default_custom_origin_protocol_policy = "match-viewer"
self.__default_custom_origin_read_timeout = 30
self.__default_custom_origin_keepalive_timeout = 5
- self.__default_datetime_string = datetime.datetime.now().strftime('%Y-%m-%dT%H:%M:%S.%f')
+ self.__default_datetime_string = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%f")
self.__default_cache_behavior_min_ttl = 0
self.__default_cache_behavior_max_ttl = 31536000
self.__default_cache_behavior_default_ttl = 86400
self.__default_cache_behavior_compress = False
- self.__default_cache_behavior_viewer_protocol_policy = 'allow-all'
+ self.__default_cache_behavior_viewer_protocol_policy = "allow-all"
self.__default_cache_behavior_smooth_streaming = False
- self.__default_cache_behavior_forwarded_values_forward_cookies = 'none'
+ self.__default_cache_behavior_forwarded_values_forward_cookies = "none"
self.__default_cache_behavior_forwarded_values_query_string = True
self.__default_trusted_signers_enabled = False
- self.__valid_price_classes = set([
- 'PriceClass_100',
- 'PriceClass_200',
- 'PriceClass_All'
- ])
- self.__valid_origin_protocol_policies = set([
- 'http-only',
- 'match-viewer',
- 'https-only'
- ])
- self.__valid_origin_ssl_protocols = set([
- 'SSLv3',
- 'TLSv1',
- 'TLSv1.1',
- 'TLSv1.2'
- ])
- self.__valid_cookie_forwarding = set([
- 'none',
- 'whitelist',
- 'all'
- ])
- self.__valid_viewer_protocol_policies = set([
- 'allow-all',
- 'https-only',
- 'redirect-to-https'
- ])
- self.__valid_methods = set([
- 'GET',
- 'HEAD',
- 'POST',
- 'PUT',
- 'PATCH',
- 'OPTIONS',
- 'DELETE'
- ])
+ self.__valid_price_classes = set(
+ [
+ "PriceClass_100",
+ "PriceClass_200",
+ "PriceClass_All",
+ ]
+ )
+ self.__valid_origin_protocol_policies = set(
+ [
+ "http-only",
+ "match-viewer",
+ "https-only",
+ ]
+ )
+ self.__valid_origin_ssl_protocols = set(
+ [
+ "SSLv3",
+ "TLSv1",
+ "TLSv1.1",
+ "TLSv1.2",
+ ]
+ )
+ self.__valid_cookie_forwarding = set(
+ [
+ "none",
+ "whitelist",
+ "all",
+ ]
+ )
+ self.__valid_viewer_protocol_policies = set(
+ [
+ "allow-all",
+ "https-only",
+ "redirect-to-https",
+ ]
+ )
+ self.__valid_methods = set(
+ [
+ "GET",
+ "HEAD",
+ "POST",
+ "PUT",
+ "PATCH",
+ "OPTIONS",
+ "DELETE",
+ ]
+ )
self.__valid_methods_cached_methods = [
- set([
- 'GET',
- 'HEAD'
- ]),
- set([
- 'GET',
- 'HEAD',
- 'OPTIONS'
- ])
+ set(
+ [
+ "GET",
+ "HEAD",
+ ]
+ ),
+ set(
+ [
+ "GET",
+ "HEAD",
+ "OPTIONS",
+ ]
+ ),
]
self.__valid_methods_allowed_methods = [
self.__valid_methods_cached_methods[0],
self.__valid_methods_cached_methods[1],
- self.__valid_methods
+ self.__valid_methods,
]
- self.__valid_lambda_function_association_event_types = set([
- 'viewer-request',
- 'viewer-response',
- 'origin-request',
- 'origin-response'
- ])
- self.__valid_viewer_certificate_ssl_support_methods = set([
- 'sni-only',
- 'vip'
- ])
- self.__valid_viewer_certificate_minimum_protocol_versions = set([
- 'SSLv3',
- 'TLSv1',
- 'TLSv1_2016',
- 'TLSv1.1_2016',
- 'TLSv1.2_2018',
- 'TLSv1.2_2019',
- 'TLSv1.2_2021'
- ])
- self.__valid_viewer_certificate_certificate_sources = set([
- 'cloudfront',
- 'iam',
- 'acm'
- ])
- self.__valid_http_versions = set([
- 'http1.1',
- 'http2'
- ])
- self.__s3_bucket_domain_identifier = '.s3.amazonaws.com'
+ self.__valid_lambda_function_association_event_types = set(
+ [
+ "viewer-request",
+ "viewer-response",
+ "origin-request",
+ "origin-response",
+ ]
+ )
+ self.__valid_viewer_certificate_ssl_support_methods = set(
+ [
+ "sni-only",
+ "vip",
+ ]
+ )
+ self.__valid_viewer_certificate_minimum_protocol_versions = set(
+ [
+ "SSLv3",
+ "TLSv1",
+ "TLSv1_2016",
+ "TLSv1.1_2016",
+ "TLSv1.2_2018",
+ "TLSv1.2_2019",
+ "TLSv1.2_2021",
+ ]
+ )
+ self.__valid_viewer_certificate_certificate_sources = set(
+ [
+ "cloudfront",
+ "iam",
+ "acm",
+ ]
+ )
+ self.__valid_http_versions = set(
+ [
+ "http1.1",
+ "http2",
+ "http3",
+ "http2and3",
+ ]
+ )
+ self.__s3_bucket_domain_regex = re.compile(r"\.s3(?:\.[^.]+)?\.amazonaws\.com$")
def add_missing_key(self, dict_object, key_to_set, value_to_set):
if key_to_set not in dict_object and value_to_set is not None:
@@ -1615,7 +1725,9 @@ class CloudFrontValidationManager(object):
dict_object = change_dict_key_name(dict_object, old_key, new_key)
return dict_object
- def add_key_else_validate(self, dict_object, key_name, attribute_name, value_to_set, valid_values, to_aws_list=False):
+ def add_key_else_validate(
+ self, dict_object, key_name, attribute_name, value_to_set, valid_values, to_aws_list=False
+ ):
if key_name in dict_object:
self.validate_attribute_with_allowed_values(value_to_set, attribute_name, valid_values)
else:
@@ -1630,26 +1742,36 @@ class CloudFrontValidationManager(object):
if logging is None:
return None
valid_logging = {}
- if logging and not set(['enabled', 'include_cookies', 'bucket', 'prefix']).issubset(logging):
- self.module.fail_json(msg="The logging parameters enabled, include_cookies, bucket and prefix must be specified.")
- valid_logging['include_cookies'] = logging.get('include_cookies')
- valid_logging['enabled'] = logging.get('enabled')
- valid_logging['bucket'] = logging.get('bucket')
- valid_logging['prefix'] = logging.get('prefix')
+ if logging and not set(["enabled", "include_cookies", "bucket", "prefix"]).issubset(logging):
+ self.module.fail_json(
+ msg="The logging parameters enabled, include_cookies, bucket and prefix must be specified."
+ )
+ valid_logging["include_cookies"] = logging.get("include_cookies")
+ valid_logging["enabled"] = logging.get("enabled")
+ valid_logging["bucket"] = logging.get("bucket")
+ valid_logging["prefix"] = logging.get("prefix")
return valid_logging
except Exception as e:
self.module.fail_json_aws(e, msg="Error validating distribution logging")
def validate_is_list(self, list_to_validate, list_name):
if not isinstance(list_to_validate, list):
- self.module.fail_json(msg='%s is of type %s. Must be a list.' % (list_name, type(list_to_validate).__name__))
+ self.module.fail_json(msg=f"{list_name} is of type {type(list_to_validate).__name__}. Must be a list.")
def validate_required_key(self, key_name, full_key_name, dict_object):
if key_name not in dict_object:
- self.module.fail_json(msg="%s must be specified." % full_key_name)
-
- def validate_origins(self, client, config, origins, default_origin_domain_name,
- default_origin_path, create_distribution, purge_origins=False):
+ self.module.fail_json(msg=f"{full_key_name} must be specified.")
+
+ def validate_origins(
+ self,
+ client,
+ config,
+ origins,
+ default_origin_domain_name,
+ default_origin_path,
+ create_distribution,
+ purge_origins=False,
+ ):
try:
if origins is None:
if default_origin_domain_name is None and not create_distribution:
@@ -1658,23 +1780,24 @@ class CloudFrontValidationManager(object):
else:
return ansible_list_to_cloudfront_list(config)
if default_origin_domain_name is not None:
- origins = [{
- 'domain_name': default_origin_domain_name,
- 'origin_path': default_origin_path or ''
- }]
+ origins = [{"domain_name": default_origin_domain_name, "origin_path": default_origin_path or ""}]
else:
origins = []
- self.validate_is_list(origins, 'origins')
+ self.validate_is_list(origins, "origins")
if not origins and default_origin_domain_name is None and create_distribution:
- self.module.fail_json(msg="Both origins[] and default_origin_domain_name have not been specified. Please specify at least one.")
+ self.module.fail_json(
+ msg="Both origins[] and default_origin_domain_name have not been specified. Please specify at least one."
+ )
all_origins = OrderedDict()
new_domains = list()
for origin in config:
- all_origins[origin.get('domain_name')] = origin
+ all_origins[origin.get("domain_name")] = origin
for origin in origins:
- origin = self.validate_origin(client, all_origins.get(origin.get('domain_name'), {}), origin, default_origin_path)
- all_origins[origin['domain_name']] = origin
- new_domains.append(origin['domain_name'])
+ origin = self.validate_origin(
+ client, all_origins.get(origin.get("domain_name"), {}), origin, default_origin_path
+ )
+ all_origins[origin["domain_name"]] = origin
+ new_domains.append(origin["domain_name"])
if purge_origins:
for domain in list(all_origins.keys()):
if domain not in new_domains:
@@ -1684,37 +1807,55 @@ class CloudFrontValidationManager(object):
self.module.fail_json_aws(e, msg="Error validating distribution origins")
def validate_s3_origin_configuration(self, client, existing_config, origin):
- if origin.get('s3_origin_config', {}).get('origin_access_identity'):
- return origin['s3_origin_config']['origin_access_identity']
+ if origin.get("s3_origin_config", {}).get("origin_access_identity"):
+ return origin["s3_origin_config"]["origin_access_identity"]
- if existing_config.get('s3_origin_config', {}).get('origin_access_identity'):
- return existing_config['s3_origin_config']['origin_access_identity']
+ if existing_config.get("s3_origin_config", {}).get("origin_access_identity"):
+ return existing_config["s3_origin_config"]["origin_access_identity"]
try:
- comment = "access-identity-by-ansible-%s-%s" % (origin.get('domain_name'), self.__default_datetime_string)
- caller_reference = "%s-%s" % (origin.get('domain_name'), self.__default_datetime_string)
- cfoai_config = dict(CloudFrontOriginAccessIdentityConfig=dict(CallerReference=caller_reference,
- Comment=comment))
- oai = client.create_cloud_front_origin_access_identity(**cfoai_config)['CloudFrontOriginAccessIdentity']['Id']
+ comment = f"access-identity-by-ansible-{origin.get('domain_name')}-{self.__default_datetime_string}"
+ caller_reference = f"{origin.get('domain_name')}-{self.__default_datetime_string}"
+ cfoai_config = dict(
+ CloudFrontOriginAccessIdentityConfig=dict(CallerReference=caller_reference, Comment=comment)
+ )
+ oai = client.create_cloud_front_origin_access_identity(**cfoai_config)["CloudFrontOriginAccessIdentity"][
+ "Id"
+ ]
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
- self.module.fail_json_aws(e, msg="Couldn't create Origin Access Identity for id %s" % origin['id'])
- return "origin-access-identity/cloudfront/%s" % oai
+ self.module.fail_json_aws(e, msg=f"Couldn't create Origin Access Identity for id {origin['id']}")
+ return f"origin-access-identity/cloudfront/{oai}"
def validate_origin(self, client, existing_config, origin, default_origin_path):
try:
- origin = self.add_missing_key(origin, 'origin_path', existing_config.get('origin_path', default_origin_path or ''))
- self.validate_required_key('origin_path', 'origins[].origin_path', origin)
- origin = self.add_missing_key(origin, 'id', existing_config.get('id', self.__default_datetime_string))
- if 'custom_headers' in origin and len(origin.get('custom_headers')) > 0:
- for custom_header in origin.get('custom_headers'):
- if 'header_name' not in custom_header or 'header_value' not in custom_header:
- self.module.fail_json(msg="Both origins[].custom_headers.header_name and origins[].custom_headers.header_value must be specified.")
- origin['custom_headers'] = ansible_list_to_cloudfront_list(origin.get('custom_headers'))
+ origin = self.add_missing_key(
+ origin, "origin_path", existing_config.get("origin_path", default_origin_path or "")
+ )
+ self.validate_required_key("origin_path", "origins[].origin_path", origin)
+ origin = self.add_missing_key(origin, "id", existing_config.get("id", self.__default_datetime_string))
+ if "custom_headers" in origin and len(origin.get("custom_headers")) > 0:
+ for custom_header in origin.get("custom_headers"):
+ if "header_name" not in custom_header or "header_value" not in custom_header:
+ self.module.fail_json(
+ msg="Both origins[].custom_headers.header_name and origins[].custom_headers.header_value must be specified."
+ )
+ origin["custom_headers"] = ansible_list_to_cloudfront_list(origin.get("custom_headers"))
else:
- origin['custom_headers'] = ansible_list_to_cloudfront_list()
- if self.__s3_bucket_domain_identifier in origin.get('domain_name').lower():
+ origin["custom_headers"] = ansible_list_to_cloudfront_list()
+ if "origin_shield" in origin:
+ origin_shield = origin.get("origin_shield")
+ if origin_shield.get("enabled"):
+ origin_shield_region = origin_shield.get("origin_shield_region")
+ if origin_shield_region is None:
+ self.module.fail_json(
+ msg="origins[].origin_shield.origin_shield_region must be specified"
+ " when origins[].origin_shield.enabled is true."
+ )
+ else:
+ origin_shield_region = origin_shield_region.lower()
+ if self.__s3_bucket_domain_regex.search(origin.get("domain_name").lower()):
if origin.get("s3_origin_access_identity_enabled") is not None:
- if origin['s3_origin_access_identity_enabled']:
+ if origin["s3_origin_access_identity_enabled"]:
s3_origin_config = self.validate_s3_origin_configuration(client, existing_config, origin)
else:
s3_origin_config = None
@@ -1728,26 +1869,47 @@ class CloudFrontValidationManager(object):
origin["s3_origin_config"] = dict(origin_access_identity=oai)
- if 'custom_origin_config' in origin:
- self.module.fail_json(msg="s3_origin_access_identity_enabled and custom_origin_config are mutually exclusive")
+ if "custom_origin_config" in origin:
+ self.module.fail_json(
+ msg="s3 origin domains and custom_origin_config are mutually exclusive",
+ )
else:
- origin = self.add_missing_key(origin, 'custom_origin_config', existing_config.get('custom_origin_config', {}))
- custom_origin_config = origin.get('custom_origin_config')
- custom_origin_config = self.add_key_else_validate(custom_origin_config, 'origin_protocol_policy',
- 'origins[].custom_origin_config.origin_protocol_policy',
- self.__default_custom_origin_protocol_policy, self.__valid_origin_protocol_policies)
- custom_origin_config = self.add_missing_key(custom_origin_config, 'origin_read_timeout', self.__default_custom_origin_read_timeout)
- custom_origin_config = self.add_missing_key(custom_origin_config, 'origin_keepalive_timeout', self.__default_custom_origin_keepalive_timeout)
- custom_origin_config = self.add_key_else_change_dict_key(custom_origin_config, 'http_port', 'h_t_t_p_port', self.__default_http_port)
- custom_origin_config = self.add_key_else_change_dict_key(custom_origin_config, 'https_port', 'h_t_t_p_s_port', self.__default_https_port)
- if custom_origin_config.get('origin_ssl_protocols', {}).get('items'):
- custom_origin_config['origin_ssl_protocols'] = custom_origin_config['origin_ssl_protocols']['items']
- if custom_origin_config.get('origin_ssl_protocols'):
- self.validate_attribute_list_with_allowed_list(custom_origin_config['origin_ssl_protocols'], 'origins[].origin_ssl_protocols',
- self.__valid_origin_ssl_protocols)
+ origin = self.add_missing_key(
+ origin, "custom_origin_config", existing_config.get("custom_origin_config", {})
+ )
+ custom_origin_config = origin.get("custom_origin_config")
+ custom_origin_config = self.add_key_else_validate(
+ custom_origin_config,
+ "origin_protocol_policy",
+ "origins[].custom_origin_config.origin_protocol_policy",
+ self.__default_custom_origin_protocol_policy,
+ self.__valid_origin_protocol_policies,
+ )
+ custom_origin_config = self.add_missing_key(
+ custom_origin_config, "origin_read_timeout", self.__default_custom_origin_read_timeout
+ )
+ custom_origin_config = self.add_missing_key(
+ custom_origin_config, "origin_keepalive_timeout", self.__default_custom_origin_keepalive_timeout
+ )
+ custom_origin_config = self.add_key_else_change_dict_key(
+ custom_origin_config, "http_port", "h_t_t_p_port", self.__default_http_port
+ )
+ custom_origin_config = self.add_key_else_change_dict_key(
+ custom_origin_config, "https_port", "h_t_t_p_s_port", self.__default_https_port
+ )
+ if custom_origin_config.get("origin_ssl_protocols", {}).get("items"):
+ custom_origin_config["origin_ssl_protocols"] = custom_origin_config["origin_ssl_protocols"]["items"]
+ if custom_origin_config.get("origin_ssl_protocols"):
+ self.validate_attribute_list_with_allowed_list(
+ custom_origin_config["origin_ssl_protocols"],
+ "origins[].origin_ssl_protocols",
+ self.__valid_origin_ssl_protocols,
+ )
else:
- custom_origin_config['origin_ssl_protocols'] = self.__default_origin_ssl_protocols
- custom_origin_config['origin_ssl_protocols'] = ansible_list_to_cloudfront_list(custom_origin_config['origin_ssl_protocols'])
+ custom_origin_config["origin_ssl_protocols"] = self.__default_origin_ssl_protocols
+ custom_origin_config["origin_ssl_protocols"] = ansible_list_to_cloudfront_list(
+ custom_origin_config["origin_ssl_protocols"]
+ )
return origin
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
self.module.fail_json_aws(e, msg="Error validating distribution origin")
@@ -1761,13 +1923,16 @@ class CloudFrontValidationManager(object):
# is true (if purge_cache_behaviors is not true, we can't really know the full new order)
if not purge_cache_behaviors:
for behavior in config:
- all_cache_behaviors[behavior['path_pattern']] = behavior
+ all_cache_behaviors[behavior["path_pattern"]] = behavior
for cache_behavior in cache_behaviors:
- valid_cache_behavior = self.validate_cache_behavior(all_cache_behaviors.get(cache_behavior.get('path_pattern'), {}),
- cache_behavior, valid_origins)
- all_cache_behaviors[cache_behavior['path_pattern']] = valid_cache_behavior
+ valid_cache_behavior = self.validate_cache_behavior(
+ all_cache_behaviors.get(cache_behavior.get("path_pattern"), {}), cache_behavior, valid_origins
+ )
+ all_cache_behaviors[cache_behavior["path_pattern"]] = valid_cache_behavior
if purge_cache_behaviors:
- for target_origin_id in set(all_cache_behaviors.keys()) - set([cb['path_pattern'] for cb in cache_behaviors]):
+ for target_origin_id in set(all_cache_behaviors.keys()) - set(
+ [cb["path_pattern"] for cb in cache_behaviors]
+ ):
del all_cache_behaviors[target_origin_id]
return ansible_list_to_cloudfront_list(list(all_cache_behaviors.values()))
except Exception as e:
@@ -1778,40 +1943,79 @@ class CloudFrontValidationManager(object):
cache_behavior = {}
if cache_behavior is None and valid_origins is not None:
return config
- cache_behavior = self.validate_cache_behavior_first_level_keys(config, cache_behavior, valid_origins, is_default_cache)
- cache_behavior = self.validate_forwarded_values(config, cache_behavior.get('forwarded_values'), cache_behavior)
- cache_behavior = self.validate_allowed_methods(config, cache_behavior.get('allowed_methods'), cache_behavior)
- cache_behavior = self.validate_lambda_function_associations(config, cache_behavior.get('lambda_function_associations'), cache_behavior)
- cache_behavior = self.validate_trusted_signers(config, cache_behavior.get('trusted_signers'), cache_behavior)
- cache_behavior = self.validate_field_level_encryption_id(config, cache_behavior.get('field_level_encryption_id'), cache_behavior)
+ cache_behavior = self.validate_cache_behavior_first_level_keys(
+ config, cache_behavior, valid_origins, is_default_cache
+ )
+ if cache_behavior.get("cache_policy_id") is None:
+ cache_behavior = self.validate_forwarded_values(
+ config, cache_behavior.get("forwarded_values"), cache_behavior
+ )
+ cache_behavior = self.validate_allowed_methods(config, cache_behavior.get("allowed_methods"), cache_behavior)
+ cache_behavior = self.validate_lambda_function_associations(
+ config, cache_behavior.get("lambda_function_associations"), cache_behavior
+ )
+ cache_behavior = self.validate_trusted_signers(config, cache_behavior.get("trusted_signers"), cache_behavior)
+ cache_behavior = self.validate_field_level_encryption_id(
+ config, cache_behavior.get("field_level_encryption_id"), cache_behavior
+ )
return cache_behavior
def validate_cache_behavior_first_level_keys(self, config, cache_behavior, valid_origins, is_default_cache):
+ if cache_behavior.get("cache_policy_id") is not None and cache_behavior.get("forwarded_values") is not None:
+ if is_default_cache:
+ cache_behavior_name = "Default cache behavior"
+ else:
+ cache_behavior_name = f"Cache behavior for path {cache_behavior['path_pattern']}"
+ self.module.fail_json(
+ msg=f"{cache_behavior_name} cannot have both a cache_policy_id and a forwarded_values option."
+ )
try:
- cache_behavior = self.add_key_else_change_dict_key(cache_behavior, 'min_ttl', 'min_t_t_l',
- config.get('min_t_t_l', self.__default_cache_behavior_min_ttl))
- cache_behavior = self.add_key_else_change_dict_key(cache_behavior, 'max_ttl', 'max_t_t_l',
- config.get('max_t_t_l', self.__default_cache_behavior_max_ttl))
- cache_behavior = self.add_key_else_change_dict_key(cache_behavior, 'default_ttl', 'default_t_t_l',
- config.get('default_t_t_l', self.__default_cache_behavior_default_ttl))
- cache_behavior = self.add_missing_key(cache_behavior, 'compress', config.get('compress', self.__default_cache_behavior_compress))
- target_origin_id = cache_behavior.get('target_origin_id', config.get('target_origin_id'))
+ if cache_behavior.get("cache_policy_id") is None:
+ cache_behavior = self.add_key_else_change_dict_key(
+ cache_behavior,
+ "min_ttl",
+ "min_t_t_l",
+ config.get("min_t_t_l", self.__default_cache_behavior_min_ttl),
+ )
+ cache_behavior = self.add_key_else_change_dict_key(
+ cache_behavior,
+ "max_ttl",
+ "max_t_t_l",
+ config.get("max_t_t_l", self.__default_cache_behavior_max_ttl),
+ )
+ cache_behavior = self.add_key_else_change_dict_key(
+ cache_behavior,
+ "default_ttl",
+ "default_t_t_l",
+ config.get("default_t_t_l", self.__default_cache_behavior_default_ttl),
+ )
+ cache_behavior = self.add_missing_key(
+ cache_behavior, "compress", config.get("compress", self.__default_cache_behavior_compress)
+ )
+ target_origin_id = cache_behavior.get("target_origin_id", config.get("target_origin_id"))
if not target_origin_id:
target_origin_id = self.get_first_origin_id_for_default_cache_behavior(valid_origins)
- if target_origin_id not in [origin['id'] for origin in valid_origins.get('items', [])]:
+ if target_origin_id not in [origin["id"] for origin in valid_origins.get("items", [])]:
if is_default_cache:
- cache_behavior_name = 'Default cache behavior'
+ cache_behavior_name = "Default cache behavior"
else:
- cache_behavior_name = 'Cache behavior for path %s' % cache_behavior['path_pattern']
- self.module.fail_json(msg="%s has target_origin_id pointing to an origin that does not exist." %
- cache_behavior_name)
- cache_behavior['target_origin_id'] = target_origin_id
- cache_behavior = self.add_key_else_validate(cache_behavior, 'viewer_protocol_policy', 'cache_behavior.viewer_protocol_policy',
- config.get('viewer_protocol_policy',
- self.__default_cache_behavior_viewer_protocol_policy),
- self.__valid_viewer_protocol_policies)
- cache_behavior = self.add_missing_key(cache_behavior, 'smooth_streaming',
- config.get('smooth_streaming', self.__default_cache_behavior_smooth_streaming))
+ cache_behavior_name = f"Cache behavior for path {cache_behavior['path_pattern']}"
+ self.module.fail_json(
+ msg=f"{cache_behavior_name} has target_origin_id pointing to an origin that does not exist."
+ )
+ cache_behavior["target_origin_id"] = target_origin_id
+ cache_behavior = self.add_key_else_validate(
+ cache_behavior,
+ "viewer_protocol_policy",
+ "cache_behavior.viewer_protocol_policy",
+ config.get("viewer_protocol_policy", self.__default_cache_behavior_viewer_protocol_policy),
+ self.__valid_viewer_protocol_policies,
+ )
+ cache_behavior = self.add_missing_key(
+ cache_behavior,
+ "smooth_streaming",
+ config.get("smooth_streaming", self.__default_cache_behavior_smooth_streaming),
+ )
return cache_behavior
except Exception as e:
self.module.fail_json_aws(e, msg="Error validating distribution cache behavior first level keys")
@@ -1820,30 +2024,40 @@ class CloudFrontValidationManager(object):
try:
if not forwarded_values:
forwarded_values = dict()
- existing_config = config.get('forwarded_values', {})
- headers = forwarded_values.get('headers', existing_config.get('headers', {}).get('items'))
+ existing_config = config.get("forwarded_values", {})
+ headers = forwarded_values.get("headers", existing_config.get("headers", {}).get("items"))
if headers:
headers.sort()
- forwarded_values['headers'] = ansible_list_to_cloudfront_list(headers)
- if 'cookies' not in forwarded_values:
- forward = existing_config.get('cookies', {}).get('forward', self.__default_cache_behavior_forwarded_values_forward_cookies)
- forwarded_values['cookies'] = {'forward': forward}
+ forwarded_values["headers"] = ansible_list_to_cloudfront_list(headers)
+ if "cookies" not in forwarded_values:
+ forward = existing_config.get("cookies", {}).get(
+ "forward", self.__default_cache_behavior_forwarded_values_forward_cookies
+ )
+ forwarded_values["cookies"] = {"forward": forward}
else:
- existing_whitelist = existing_config.get('cookies', {}).get('whitelisted_names', {}).get('items')
- whitelist = forwarded_values.get('cookies').get('whitelisted_names', existing_whitelist)
+ existing_whitelist = existing_config.get("cookies", {}).get("whitelisted_names", {}).get("items")
+ whitelist = forwarded_values.get("cookies").get("whitelisted_names", existing_whitelist)
if whitelist:
- self.validate_is_list(whitelist, 'forwarded_values.whitelisted_names')
- forwarded_values['cookies']['whitelisted_names'] = ansible_list_to_cloudfront_list(whitelist)
- cookie_forwarding = forwarded_values.get('cookies').get('forward', existing_config.get('cookies', {}).get('forward'))
- self.validate_attribute_with_allowed_values(cookie_forwarding, 'cache_behavior.forwarded_values.cookies.forward',
- self.__valid_cookie_forwarding)
- forwarded_values['cookies']['forward'] = cookie_forwarding
- query_string_cache_keys = forwarded_values.get('query_string_cache_keys', existing_config.get('query_string_cache_keys', {}).get('items', []))
- self.validate_is_list(query_string_cache_keys, 'forwarded_values.query_string_cache_keys')
- forwarded_values['query_string_cache_keys'] = ansible_list_to_cloudfront_list(query_string_cache_keys)
- forwarded_values = self.add_missing_key(forwarded_values, 'query_string',
- existing_config.get('query_string', self.__default_cache_behavior_forwarded_values_query_string))
- cache_behavior['forwarded_values'] = forwarded_values
+ self.validate_is_list(whitelist, "forwarded_values.whitelisted_names")
+ forwarded_values["cookies"]["whitelisted_names"] = ansible_list_to_cloudfront_list(whitelist)
+ cookie_forwarding = forwarded_values.get("cookies").get(
+ "forward", existing_config.get("cookies", {}).get("forward")
+ )
+ self.validate_attribute_with_allowed_values(
+ cookie_forwarding, "cache_behavior.forwarded_values.cookies.forward", self.__valid_cookie_forwarding
+ )
+ forwarded_values["cookies"]["forward"] = cookie_forwarding
+ query_string_cache_keys = forwarded_values.get(
+ "query_string_cache_keys", existing_config.get("query_string_cache_keys", {}).get("items", [])
+ )
+ self.validate_is_list(query_string_cache_keys, "forwarded_values.query_string_cache_keys")
+ forwarded_values["query_string_cache_keys"] = ansible_list_to_cloudfront_list(query_string_cache_keys)
+ forwarded_values = self.add_missing_key(
+ forwarded_values,
+ "query_string",
+ existing_config.get("query_string", self.__default_cache_behavior_forwarded_values_query_string),
+ )
+ cache_behavior["forwarded_values"] = forwarded_values
return cache_behavior
except Exception as e:
self.module.fail_json_aws(e, msg="Error validating forwarded values")
@@ -1851,57 +2065,68 @@ class CloudFrontValidationManager(object):
def validate_lambda_function_associations(self, config, lambda_function_associations, cache_behavior):
try:
if lambda_function_associations is not None:
- self.validate_is_list(lambda_function_associations, 'lambda_function_associations')
+ self.validate_is_list(lambda_function_associations, "lambda_function_associations")
for association in lambda_function_associations:
- association = change_dict_key_name(association, 'lambda_function_arn', 'lambda_function_a_r_n')
- self.validate_attribute_with_allowed_values(association.get('event_type'), 'cache_behaviors[].lambda_function_associations.event_type',
- self.__valid_lambda_function_association_event_types)
- cache_behavior['lambda_function_associations'] = ansible_list_to_cloudfront_list(lambda_function_associations)
+ association = change_dict_key_name(association, "lambda_function_arn", "lambda_function_a_r_n")
+ self.validate_attribute_with_allowed_values(
+ association.get("event_type"),
+ "cache_behaviors[].lambda_function_associations.event_type",
+ self.__valid_lambda_function_association_event_types,
+ )
+ cache_behavior["lambda_function_associations"] = ansible_list_to_cloudfront_list(
+ lambda_function_associations
+ )
else:
- if 'lambda_function_associations' in config:
- cache_behavior['lambda_function_associations'] = config.get('lambda_function_associations')
+ if "lambda_function_associations" in config:
+ cache_behavior["lambda_function_associations"] = config.get("lambda_function_associations")
else:
- cache_behavior['lambda_function_associations'] = ansible_list_to_cloudfront_list([])
+ cache_behavior["lambda_function_associations"] = ansible_list_to_cloudfront_list([])
return cache_behavior
except Exception as e:
self.module.fail_json_aws(e, msg="Error validating lambda function associations")
def validate_field_level_encryption_id(self, config, field_level_encryption_id, cache_behavior):
if field_level_encryption_id is not None:
- cache_behavior['field_level_encryption_id'] = field_level_encryption_id
- elif 'field_level_encryption_id' in config:
- cache_behavior['field_level_encryption_id'] = config.get('field_level_encryption_id')
+ cache_behavior["field_level_encryption_id"] = field_level_encryption_id
+ elif "field_level_encryption_id" in config:
+ cache_behavior["field_level_encryption_id"] = config.get("field_level_encryption_id")
else:
- cache_behavior['field_level_encryption_id'] = ""
+ cache_behavior["field_level_encryption_id"] = ""
return cache_behavior
def validate_allowed_methods(self, config, allowed_methods, cache_behavior):
try:
if allowed_methods is not None:
- self.validate_required_key('items', 'cache_behavior.allowed_methods.items[]', allowed_methods)
- temp_allowed_items = allowed_methods.get('items')
- self.validate_is_list(temp_allowed_items, 'cache_behavior.allowed_methods.items')
- self.validate_attribute_list_with_allowed_list(temp_allowed_items, 'cache_behavior.allowed_methods.items[]',
- self.__valid_methods_allowed_methods)
- cached_items = allowed_methods.get('cached_methods')
- if 'cached_methods' in allowed_methods:
- self.validate_is_list(cached_items, 'cache_behavior.allowed_methods.cached_methods')
- self.validate_attribute_list_with_allowed_list(cached_items, 'cache_behavior.allowed_items.cached_methods[]',
- self.__valid_methods_cached_methods)
+ self.validate_required_key("items", "cache_behavior.allowed_methods.items[]", allowed_methods)
+ temp_allowed_items = allowed_methods.get("items")
+ self.validate_is_list(temp_allowed_items, "cache_behavior.allowed_methods.items")
+ self.validate_attribute_list_with_allowed_list(
+ temp_allowed_items, "cache_behavior.allowed_methods.items[]", self.__valid_methods_allowed_methods
+ )
+ cached_items = allowed_methods.get("cached_methods")
+ if "cached_methods" in allowed_methods:
+ self.validate_is_list(cached_items, "cache_behavior.allowed_methods.cached_methods")
+ self.validate_attribute_list_with_allowed_list(
+ cached_items,
+ "cache_behavior.allowed_items.cached_methods[]",
+ self.__valid_methods_cached_methods,
+ )
# we don't care if the order of how cloudfront stores the methods differs - preserving existing
# order reduces likelihood of making unnecessary changes
- if 'allowed_methods' in config and set(config['allowed_methods']['items']) == set(temp_allowed_items):
- cache_behavior['allowed_methods'] = config['allowed_methods']
+ if "allowed_methods" in config and set(config["allowed_methods"]["items"]) == set(temp_allowed_items):
+ cache_behavior["allowed_methods"] = config["allowed_methods"]
else:
- cache_behavior['allowed_methods'] = ansible_list_to_cloudfront_list(temp_allowed_items)
+ cache_behavior["allowed_methods"] = ansible_list_to_cloudfront_list(temp_allowed_items)
- if cached_items and set(cached_items) == set(config.get('allowed_methods', {}).get('cached_methods', {}).get('items', [])):
- cache_behavior['allowed_methods']['cached_methods'] = config['allowed_methods']['cached_methods']
+ if cached_items and set(cached_items) == set(
+ config.get("allowed_methods", {}).get("cached_methods", {}).get("items", [])
+ ):
+ cache_behavior["allowed_methods"]["cached_methods"] = config["allowed_methods"]["cached_methods"]
else:
- cache_behavior['allowed_methods']['cached_methods'] = ansible_list_to_cloudfront_list(cached_items)
+ cache_behavior["allowed_methods"]["cached_methods"] = ansible_list_to_cloudfront_list(cached_items)
else:
- if 'allowed_methods' in config:
- cache_behavior['allowed_methods'] = config.get('allowed_methods')
+ if "allowed_methods" in config:
+ cache_behavior["allowed_methods"] = config.get("allowed_methods")
return cache_behavior
except Exception as e:
self.module.fail_json_aws(e, msg="Error validating allowed methods")
@@ -1910,14 +2135,16 @@ class CloudFrontValidationManager(object):
try:
if trusted_signers is None:
trusted_signers = {}
- if 'items' in trusted_signers:
- valid_trusted_signers = ansible_list_to_cloudfront_list(trusted_signers.get('items'))
+ if "items" in trusted_signers:
+ valid_trusted_signers = ansible_list_to_cloudfront_list(trusted_signers.get("items"))
else:
- valid_trusted_signers = dict(quantity=config.get('quantity', 0))
- if 'items' in config:
- valid_trusted_signers = dict(items=config['items'])
- valid_trusted_signers['enabled'] = trusted_signers.get('enabled', config.get('enabled', self.__default_trusted_signers_enabled))
- cache_behavior['trusted_signers'] = valid_trusted_signers
+ valid_trusted_signers = dict(quantity=config.get("quantity", 0))
+ if "items" in config:
+ valid_trusted_signers = dict(items=config["items"])
+ valid_trusted_signers["enabled"] = trusted_signers.get(
+ "enabled", config.get("enabled", self.__default_trusted_signers_enabled)
+ )
+ cache_behavior["trusted_signers"] = valid_trusted_signers
return cache_behavior
except Exception as e:
self.module.fail_json_aws(e, msg="Error validating trusted signers")
@@ -1926,19 +2153,37 @@ class CloudFrontValidationManager(object):
try:
if viewer_certificate is None:
return None
- if viewer_certificate.get('cloudfront_default_certificate') and viewer_certificate.get('ssl_support_method') is not None:
- self.module.fail_json(msg="viewer_certificate.ssl_support_method should not be specified with viewer_certificate_cloudfront_default" +
- "_certificate set to true.")
- self.validate_attribute_with_allowed_values(viewer_certificate.get('ssl_support_method'), 'viewer_certificate.ssl_support_method',
- self.__valid_viewer_certificate_ssl_support_methods)
- self.validate_attribute_with_allowed_values(viewer_certificate.get('minimum_protocol_version'), 'viewer_certificate.minimum_protocol_version',
- self.__valid_viewer_certificate_minimum_protocol_versions)
- self.validate_attribute_with_allowed_values(viewer_certificate.get('certificate_source'), 'viewer_certificate.certificate_source',
- self.__valid_viewer_certificate_certificate_sources)
- viewer_certificate = change_dict_key_name(viewer_certificate, 'cloudfront_default_certificate', 'cloud_front_default_certificate')
- viewer_certificate = change_dict_key_name(viewer_certificate, 'ssl_support_method', 's_s_l_support_method')
- viewer_certificate = change_dict_key_name(viewer_certificate, 'iam_certificate_id', 'i_a_m_certificate_id')
- viewer_certificate = change_dict_key_name(viewer_certificate, 'acm_certificate_arn', 'a_c_m_certificate_arn')
+ if (
+ viewer_certificate.get("cloudfront_default_certificate")
+ and viewer_certificate.get("ssl_support_method") is not None
+ ):
+ self.module.fail_json(
+ msg="viewer_certificate.ssl_support_method should not be specified with viewer_certificate_cloudfront_default"
+ + "_certificate set to true."
+ )
+ self.validate_attribute_with_allowed_values(
+ viewer_certificate.get("ssl_support_method"),
+ "viewer_certificate.ssl_support_method",
+ self.__valid_viewer_certificate_ssl_support_methods,
+ )
+ self.validate_attribute_with_allowed_values(
+ viewer_certificate.get("minimum_protocol_version"),
+ "viewer_certificate.minimum_protocol_version",
+ self.__valid_viewer_certificate_minimum_protocol_versions,
+ )
+ self.validate_attribute_with_allowed_values(
+ viewer_certificate.get("certificate_source"),
+ "viewer_certificate.certificate_source",
+ self.__valid_viewer_certificate_certificate_sources,
+ )
+ viewer_certificate = change_dict_key_name(
+ viewer_certificate, "cloudfront_default_certificate", "cloud_front_default_certificate"
+ )
+ viewer_certificate = change_dict_key_name(viewer_certificate, "ssl_support_method", "s_s_l_support_method")
+ viewer_certificate = change_dict_key_name(viewer_certificate, "iam_certificate_id", "i_a_m_certificate_id")
+ viewer_certificate = change_dict_key_name(
+ viewer_certificate, "acm_certificate_arn", "a_c_m_certificate_arn"
+ )
return viewer_certificate
except Exception as e:
self.module.fail_json_aws(e, msg="Error validating viewer certificate")
@@ -1947,16 +2192,18 @@ class CloudFrontValidationManager(object):
try:
if custom_error_responses is None and not purge_custom_error_responses:
return ansible_list_to_cloudfront_list(config)
- self.validate_is_list(custom_error_responses, 'custom_error_responses')
+ self.validate_is_list(custom_error_responses, "custom_error_responses")
result = list()
- existing_responses = dict((response['error_code'], response) for response in custom_error_responses)
+ existing_responses = dict((response["error_code"], response) for response in custom_error_responses)
for custom_error_response in custom_error_responses:
- self.validate_required_key('error_code', 'custom_error_responses[].error_code', custom_error_response)
- custom_error_response = change_dict_key_name(custom_error_response, 'error_caching_min_ttl', 'error_caching_min_t_t_l')
- if 'response_code' in custom_error_response:
- custom_error_response['response_code'] = str(custom_error_response['response_code'])
- if custom_error_response['error_code'] in existing_responses:
- del existing_responses[custom_error_response['error_code']]
+ self.validate_required_key("error_code", "custom_error_responses[].error_code", custom_error_response)
+ custom_error_response = change_dict_key_name(
+ custom_error_response, "error_caching_min_ttl", "error_caching_min_t_t_l"
+ )
+ if "response_code" in custom_error_response:
+ custom_error_response["response_code"] = str(custom_error_response["response_code"])
+ if custom_error_response["error_code"] in existing_responses:
+ del existing_responses[custom_error_response["error_code"]]
result.append(custom_error_response)
if not purge_custom_error_responses:
result.extend(existing_responses.values())
@@ -1972,54 +2219,72 @@ class CloudFrontValidationManager(object):
return None
else:
return config
- self.validate_required_key('geo_restriction', 'restrictions.geo_restriction', restrictions)
- geo_restriction = restrictions.get('geo_restriction')
- self.validate_required_key('restriction_type', 'restrictions.geo_restriction.restriction_type', geo_restriction)
- existing_restrictions = config.get('geo_restriction', {}).get(geo_restriction['restriction_type'], {}).get('items', [])
- geo_restriction_items = geo_restriction.get('items')
+ self.validate_required_key("geo_restriction", "restrictions.geo_restriction", restrictions)
+ geo_restriction = restrictions.get("geo_restriction")
+ self.validate_required_key(
+ "restriction_type", "restrictions.geo_restriction.restriction_type", geo_restriction
+ )
+ existing_restrictions = (
+ config.get("geo_restriction", {}).get(geo_restriction["restriction_type"], {}).get("items", [])
+ )
+ geo_restriction_items = geo_restriction.get("items")
if not purge_restrictions:
- geo_restriction_items.extend([rest for rest in existing_restrictions if
- rest not in geo_restriction_items])
+ geo_restriction_items.extend(
+ [rest for rest in existing_restrictions if rest not in geo_restriction_items]
+ )
valid_restrictions = ansible_list_to_cloudfront_list(geo_restriction_items)
- valid_restrictions['restriction_type'] = geo_restriction.get('restriction_type')
- return {'geo_restriction': valid_restrictions}
+ valid_restrictions["restriction_type"] = geo_restriction.get("restriction_type")
+ return {"geo_restriction": valid_restrictions}
except Exception as e:
self.module.fail_json_aws(e, msg="Error validating restrictions")
- def validate_distribution_config_parameters(self, config, default_root_object, ipv6_enabled, http_version, web_acl_id):
+ def validate_distribution_config_parameters(
+ self, config, default_root_object, ipv6_enabled, http_version, web_acl_id
+ ):
try:
- config['default_root_object'] = default_root_object or config.get('default_root_object', '')
- config['is_i_p_v6_enabled'] = ipv6_enabled if ipv6_enabled is not None else config.get('is_i_p_v6_enabled', self.__default_ipv6_enabled)
- if http_version is not None or config.get('http_version'):
- self.validate_attribute_with_allowed_values(http_version, 'http_version', self.__valid_http_versions)
- config['http_version'] = http_version or config.get('http_version')
- if web_acl_id or config.get('web_a_c_l_id'):
- config['web_a_c_l_id'] = web_acl_id or config.get('web_a_c_l_id')
+ config["default_root_object"] = default_root_object or config.get("default_root_object", "")
+ config["is_i_p_v6_enabled"] = (
+ ipv6_enabled
+ if ipv6_enabled is not None
+ else config.get("is_i_p_v6_enabled", self.__default_ipv6_enabled)
+ )
+ if http_version is not None or config.get("http_version"):
+ self.validate_attribute_with_allowed_values(http_version, "http_version", self.__valid_http_versions)
+ config["http_version"] = http_version or config.get("http_version")
+ if web_acl_id or config.get("web_a_c_l_id"):
+ config["web_a_c_l_id"] = web_acl_id or config.get("web_a_c_l_id")
return config
except Exception as e:
self.module.fail_json_aws(e, msg="Error validating distribution config parameters")
- def validate_common_distribution_parameters(self, config, enabled, aliases, logging, price_class, purge_aliases=False):
+ def validate_common_distribution_parameters(
+ self, config, enabled, aliases, logging, price_class, purge_aliases=False
+ ):
try:
if config is None:
config = {}
if aliases is not None:
if not purge_aliases:
- aliases.extend([alias for alias in config.get('aliases', {}).get('items', [])
- if alias not in aliases])
- config['aliases'] = ansible_list_to_cloudfront_list(aliases)
+ aliases.extend(
+ [alias for alias in config.get("aliases", {}).get("items", []) if alias not in aliases]
+ )
+ config["aliases"] = ansible_list_to_cloudfront_list(aliases)
if logging is not None:
- config['logging'] = self.validate_logging(logging)
- config['enabled'] = enabled or config.get('enabled', self.__default_distribution_enabled)
+ config["logging"] = self.validate_logging(logging)
+ config["enabled"] = (
+ enabled if enabled is not None else config.get("enabled", self.__default_distribution_enabled)
+ )
if price_class is not None:
- self.validate_attribute_with_allowed_values(price_class, 'price_class', self.__valid_price_classes)
- config['price_class'] = price_class
+ self.validate_attribute_with_allowed_values(price_class, "price_class", self.__valid_price_classes)
+ config["price_class"] = price_class
return config
except Exception as e:
self.module.fail_json_aws(e, msg="Error validating common distribution parameters")
def validate_comment(self, config, comment):
- config['comment'] = comment or config.get('comment', "Distribution created by Ansible with datetime stamp " + self.__default_datetime_string)
+ config["comment"] = comment or config.get(
+ "comment", "Distribution created by Ansible with datetime stamp " + self.__default_datetime_string
+ )
return config
def validate_caller_reference(self, caller_reference):
@@ -2028,37 +2293,52 @@ class CloudFrontValidationManager(object):
def get_first_origin_id_for_default_cache_behavior(self, valid_origins):
try:
if valid_origins is not None:
- valid_origins_list = valid_origins.get('items')
- if valid_origins_list is not None and isinstance(valid_origins_list, list) and len(valid_origins_list) > 0:
- return str(valid_origins_list[0].get('id'))
- self.module.fail_json(msg="There are no valid origins from which to specify a target_origin_id for the default_cache_behavior configuration.")
+ valid_origins_list = valid_origins.get("items")
+ if (
+ valid_origins_list is not None
+ and isinstance(valid_origins_list, list)
+ and len(valid_origins_list) > 0
+ ):
+ return str(valid_origins_list[0].get("id"))
+ self.module.fail_json(
+ msg="There are no valid origins from which to specify a target_origin_id for the default_cache_behavior configuration."
+ )
except Exception as e:
self.module.fail_json_aws(e, msg="Error getting first origin_id for default cache behavior")
def validate_attribute_list_with_allowed_list(self, attribute_list, attribute_list_name, allowed_list):
try:
self.validate_is_list(attribute_list, attribute_list_name)
- if (isinstance(allowed_list, list) and set(attribute_list) not in allowed_list or
- isinstance(allowed_list, set) and not set(allowed_list).issuperset(attribute_list)):
- self.module.fail_json(msg='The attribute list {0} must be one of [{1}]'.format(attribute_list_name, ' '.join(str(a) for a in allowed_list)))
+ if (
+ isinstance(allowed_list, list)
+ and set(attribute_list) not in allowed_list
+ or isinstance(allowed_list, set)
+ and not set(allowed_list).issuperset(attribute_list)
+ ):
+ attribute_list = " ".join(str(a) for a in allowed_list)
+ self.module.fail_json(msg=f"The attribute list {attribute_list_name} must be one of [{attribute_list}]")
except Exception as e:
self.module.fail_json_aws(e, msg="Error validating attribute list with allowed value list")
def validate_attribute_with_allowed_values(self, attribute, attribute_name, allowed_list):
if attribute is not None and attribute not in allowed_list:
- self.module.fail_json(msg='The attribute {0} must be one of [{1}]'.format(attribute_name, ' '.join(str(a) for a in allowed_list)))
+ attribute_list = " ".join(str(a) for a in allowed_list)
+ self.module.fail_json(msg=f"The attribute {attribute_name} must be one of [{attribute_list}]")
def validate_distribution_from_caller_reference(self, caller_reference):
try:
- distributions = self.__cloudfront_facts_mgr.list_distributions(False)
- distribution_name = 'Distribution'
- distribution_config_name = 'DistributionConfig'
- distribution_ids = [dist.get('Id') for dist in distributions]
+ distributions = self.__cloudfront_facts_mgr.list_distributions(keyed=False)
+ distribution_name = "Distribution"
+ distribution_config_name = "DistributionConfig"
+ distribution_ids = [dist.get("Id") for dist in distributions]
for distribution_id in distribution_ids:
- distribution = self.__cloudfront_facts_mgr.get_distribution(distribution_id)
+ distribution = self.__cloudfront_facts_mgr.get_distribution(id=distribution_id)
if distribution is not None:
distribution_config = distribution[distribution_name].get(distribution_config_name)
- if distribution_config is not None and distribution_config.get('CallerReference') == caller_reference:
+ if (
+ distribution_config is not None
+ and distribution_config.get("CallerReference") == caller_reference
+ ):
distribution[distribution_name][distribution_config_name] = distribution_config
return distribution
@@ -2073,68 +2353,73 @@ class CloudFrontValidationManager(object):
if aliases and distribution_id is None:
distribution_id = self.validate_distribution_id_from_alias(aliases)
if distribution_id:
- return self.__cloudfront_facts_mgr.get_distribution(distribution_id)
+ return self.__cloudfront_facts_mgr.get_distribution(id=distribution_id)
return None
except Exception as e:
- self.module.fail_json_aws(e, msg="Error validating distribution_id from alias, aliases and caller reference")
+ self.module.fail_json_aws(
+ e, msg="Error validating distribution_id from alias, aliases and caller reference"
+ )
def validate_distribution_id_from_alias(self, aliases):
- distributions = self.__cloudfront_facts_mgr.list_distributions(False)
+ distributions = self.__cloudfront_facts_mgr.list_distributions(keyed=False)
if distributions:
for distribution in distributions:
- distribution_aliases = distribution.get('Aliases', {}).get('Items', [])
+ distribution_aliases = distribution.get("Aliases", {}).get("Items", [])
if set(aliases) & set(distribution_aliases):
- return distribution['Id']
+ return distribution["Id"]
return None
def wait_until_processed(self, client, wait_timeout, distribution_id, caller_reference):
if distribution_id is None:
- distribution_id = self.validate_distribution_from_caller_reference(caller_reference=caller_reference)['Id']
+ distribution = self.validate_distribution_from_caller_reference(caller_reference=caller_reference)
+ distribution_id = distribution["Distribution"]["Id"]
try:
- waiter = client.get_waiter('distribution_deployed')
+ waiter = client.get_waiter("distribution_deployed")
attempts = 1 + int(wait_timeout / 60)
- waiter.wait(Id=distribution_id, WaiterConfig={'MaxAttempts': attempts})
+ waiter.wait(Id=distribution_id, WaiterConfig={"MaxAttempts": attempts})
except botocore.exceptions.WaiterError as e:
- self.module.fail_json_aws(e, msg="Timeout waiting for CloudFront action."
- " Waited for {0} seconds before timeout.".format(to_text(wait_timeout)))
+ self.module.fail_json_aws(
+ e,
+ msg=f"Timeout waiting for CloudFront action. Waited for {to_text(wait_timeout)} seconds before timeout.",
+ )
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, msg="Error getting distribution {0}".format(distribution_id))
+ self.module.fail_json_aws(e, msg=f"Error getting distribution {distribution_id}")
def main():
argument_spec = dict(
- state=dict(choices=['present', 'absent'], default='present'),
+ state=dict(choices=["present", "absent"], default="present"),
caller_reference=dict(),
comment=dict(),
distribution_id=dict(),
e_tag=dict(),
- tags=dict(type='dict', aliases=['resource_tags']),
- purge_tags=dict(type='bool', default=True),
+ tags=dict(type="dict", aliases=["resource_tags"]),
+ purge_tags=dict(type="bool", default=True),
alias=dict(),
- aliases=dict(type='list', default=[], elements='str'),
- purge_aliases=dict(type='bool', default=False),
+ aliases=dict(type="list", default=[], elements="str"),
+ purge_aliases=dict(type="bool", default=False),
default_root_object=dict(),
- origins=dict(type='list', elements='dict'),
- purge_origins=dict(type='bool', default=False),
- default_cache_behavior=dict(type='dict'),
- cache_behaviors=dict(type='list', elements='dict'),
- purge_cache_behaviors=dict(type='bool', default=False),
- custom_error_responses=dict(type='list', elements='dict'),
- purge_custom_error_responses=dict(type='bool', default=False),
- logging=dict(type='dict'),
+ origins=dict(type="list", elements="dict"),
+ purge_origins=dict(type="bool", default=False),
+ default_cache_behavior=dict(type="dict"),
+ cache_behaviors=dict(type="list", elements="dict"),
+ purge_cache_behaviors=dict(type="bool", default=False),
+ custom_error_responses=dict(type="list", elements="dict"),
+ purge_custom_error_responses=dict(type="bool", default=False),
+ logging=dict(type="dict"),
price_class=dict(),
- enabled=dict(type='bool'),
- viewer_certificate=dict(type='dict'),
- restrictions=dict(type='dict'),
+ enabled=dict(type="bool"),
+ viewer_certificate=dict(type="dict"),
+ restrictions=dict(type="dict"),
web_acl_id=dict(),
http_version=dict(),
- ipv6_enabled=dict(type='bool'),
+ ipv6_enabled=dict(type="bool"),
default_origin_domain_name=dict(),
default_origin_path=dict(),
- wait=dict(default=False, type='bool'),
- wait_timeout=dict(default=1800, type='int')
+ wait=dict(default=False, type="bool"),
+ wait_timeout=dict(default=1800, type="int"),
)
result = {}
@@ -2144,129 +2429,154 @@ def main():
argument_spec=argument_spec,
supports_check_mode=False,
mutually_exclusive=[
- ['distribution_id', 'alias'],
- ['default_origin_domain_name', 'distribution_id'],
- ['default_origin_domain_name', 'alias'],
- ]
+ ["distribution_id", "alias"],
+ ["default_origin_domain_name", "distribution_id"],
+ ["default_origin_domain_name", "alias"],
+ ],
)
- client = module.client('cloudfront', retry_decorator=AWSRetry.jittered_backoff())
+ client = module.client("cloudfront", retry_decorator=AWSRetry.jittered_backoff())
validation_mgr = CloudFrontValidationManager(module)
- state = module.params.get('state')
- caller_reference = module.params.get('caller_reference')
- comment = module.params.get('comment')
- e_tag = module.params.get('e_tag')
- tags = module.params.get('tags')
- purge_tags = module.params.get('purge_tags')
- distribution_id = module.params.get('distribution_id')
- alias = module.params.get('alias')
- aliases = module.params.get('aliases')
- purge_aliases = module.params.get('purge_aliases')
- default_root_object = module.params.get('default_root_object')
- origins = module.params.get('origins')
- purge_origins = module.params.get('purge_origins')
- default_cache_behavior = module.params.get('default_cache_behavior')
- cache_behaviors = module.params.get('cache_behaviors')
- purge_cache_behaviors = module.params.get('purge_cache_behaviors')
- custom_error_responses = module.params.get('custom_error_responses')
- purge_custom_error_responses = module.params.get('purge_custom_error_responses')
- logging = module.params.get('logging')
- price_class = module.params.get('price_class')
- enabled = module.params.get('enabled')
- viewer_certificate = module.params.get('viewer_certificate')
- restrictions = module.params.get('restrictions')
- purge_restrictions = module.params.get('purge_restrictions')
- web_acl_id = module.params.get('web_acl_id')
- http_version = module.params.get('http_version')
- ipv6_enabled = module.params.get('ipv6_enabled')
- default_origin_domain_name = module.params.get('default_origin_domain_name')
- default_origin_path = module.params.get('default_origin_path')
- wait = module.params.get('wait')
- wait_timeout = module.params.get('wait_timeout')
+ state = module.params.get("state")
+ caller_reference = module.params.get("caller_reference")
+ comment = module.params.get("comment")
+ e_tag = module.params.get("e_tag")
+ tags = module.params.get("tags")
+ purge_tags = module.params.get("purge_tags")
+ distribution_id = module.params.get("distribution_id")
+ alias = module.params.get("alias")
+ aliases = module.params.get("aliases")
+ purge_aliases = module.params.get("purge_aliases")
+ default_root_object = module.params.get("default_root_object")
+ origins = module.params.get("origins")
+ purge_origins = module.params.get("purge_origins")
+ default_cache_behavior = module.params.get("default_cache_behavior")
+ cache_behaviors = module.params.get("cache_behaviors")
+ purge_cache_behaviors = module.params.get("purge_cache_behaviors")
+ custom_error_responses = module.params.get("custom_error_responses")
+ purge_custom_error_responses = module.params.get("purge_custom_error_responses")
+ logging = module.params.get("logging")
+ price_class = module.params.get("price_class")
+ enabled = module.params.get("enabled")
+ viewer_certificate = module.params.get("viewer_certificate")
+ restrictions = module.params.get("restrictions")
+ purge_restrictions = module.params.get("purge_restrictions")
+ web_acl_id = module.params.get("web_acl_id")
+ http_version = module.params.get("http_version")
+ ipv6_enabled = module.params.get("ipv6_enabled")
+ default_origin_domain_name = module.params.get("default_origin_domain_name")
+ default_origin_path = module.params.get("default_origin_path")
+ wait = module.params.get("wait")
+ wait_timeout = module.params.get("wait_timeout")
if alias and alias not in aliases:
aliases.append(alias)
- distribution = validation_mgr.validate_distribution_from_aliases_caller_reference(distribution_id, aliases, caller_reference)
+ distribution = validation_mgr.validate_distribution_from_aliases_caller_reference(
+ distribution_id, aliases, caller_reference
+ )
- update = state == 'present' and distribution
- create = state == 'present' and not distribution
- delete = state == 'absent' and distribution
+ update = state == "present" and distribution
+ create = state == "present" and not distribution
+ delete = state == "absent" and distribution
if not (update or create or delete):
module.exit_json(changed=False)
+ config = {}
if update or delete:
- config = distribution['Distribution']['DistributionConfig']
- e_tag = distribution['ETag']
- distribution_id = distribution['Distribution']['Id']
- else:
- config = dict()
+ config = distribution["Distribution"]["DistributionConfig"]
+ e_tag = distribution["ETag"]
+ distribution_id = distribution["Distribution"]["Id"]
+
if update:
config = camel_dict_to_snake_dict(config, reversible=True)
if create or update:
- config = validation_mgr.validate_common_distribution_parameters(config, enabled, aliases, logging, price_class, purge_aliases)
- config = validation_mgr.validate_distribution_config_parameters(config, default_root_object, ipv6_enabled, http_version, web_acl_id)
- config['origins'] = validation_mgr.validate_origins(client, config.get('origins', {}).get('items', []), origins, default_origin_domain_name,
- default_origin_path, create, purge_origins)
- config['cache_behaviors'] = validation_mgr.validate_cache_behaviors(config.get('cache_behaviors', {}).get('items', []),
- cache_behaviors, config['origins'], purge_cache_behaviors)
- config['default_cache_behavior'] = validation_mgr.validate_cache_behavior(config.get('default_cache_behavior', {}),
- default_cache_behavior, config['origins'], True)
- config['custom_error_responses'] = validation_mgr.validate_custom_error_responses(config.get('custom_error_responses', {}).get('items', []),
- custom_error_responses, purge_custom_error_responses)
- valid_restrictions = validation_mgr.validate_restrictions(config.get('restrictions', {}), restrictions, purge_restrictions)
+ config = validation_mgr.validate_common_distribution_parameters(
+ config, enabled, aliases, logging, price_class, purge_aliases
+ )
+ config = validation_mgr.validate_distribution_config_parameters(
+ config, default_root_object, ipv6_enabled, http_version, web_acl_id
+ )
+ config["origins"] = validation_mgr.validate_origins(
+ client,
+ config.get("origins", {}).get("items", []),
+ origins,
+ default_origin_domain_name,
+ default_origin_path,
+ create,
+ purge_origins,
+ )
+ config["cache_behaviors"] = validation_mgr.validate_cache_behaviors(
+ config.get("cache_behaviors", {}).get("items", []),
+ cache_behaviors,
+ config["origins"],
+ purge_cache_behaviors,
+ )
+ config["default_cache_behavior"] = validation_mgr.validate_cache_behavior(
+ config.get("default_cache_behavior", {}), default_cache_behavior, config["origins"], True
+ )
+ config["custom_error_responses"] = validation_mgr.validate_custom_error_responses(
+ config.get("custom_error_responses", {}).get("items", []),
+ custom_error_responses,
+ purge_custom_error_responses,
+ )
+ valid_restrictions = validation_mgr.validate_restrictions(
+ config.get("restrictions", {}), restrictions, purge_restrictions
+ )
if valid_restrictions:
- config['restrictions'] = valid_restrictions
+ config["restrictions"] = valid_restrictions
valid_viewer_certificate = validation_mgr.validate_viewer_certificate(viewer_certificate)
- config = merge_validation_into_config(config, valid_viewer_certificate, 'viewer_certificate')
+ config = merge_validation_into_config(config, valid_viewer_certificate, "viewer_certificate")
config = validation_mgr.validate_comment(config, comment)
config = snake_dict_to_camel_dict(config, capitalize_first=True)
if create:
- config['CallerReference'] = validation_mgr.validate_caller_reference(caller_reference)
+ config["CallerReference"] = validation_mgr.validate_caller_reference(caller_reference)
result = create_distribution(client, module, config, ansible_dict_to_boto3_tag_list(tags or {}))
result = camel_dict_to_snake_dict(result)
- result['tags'] = list_tags_for_resource(client, module, result['arn'])
+ result["tags"] = list_tags_for_resource(client, module, result["arn"])
if delete:
- if config['Enabled']:
- config['Enabled'] = False
+ if config["Enabled"]:
+ config["Enabled"] = False
result = update_distribution(client, module, config, distribution_id, e_tag)
- validation_mgr.wait_until_processed(client, wait_timeout, distribution_id, config.get('CallerReference'))
- distribution = validation_mgr.validate_distribution_from_aliases_caller_reference(distribution_id, aliases, caller_reference)
+ validation_mgr.wait_until_processed(client, wait_timeout, distribution_id, config.get("CallerReference"))
+ distribution = validation_mgr.validate_distribution_from_aliases_caller_reference(
+ distribution_id, aliases, caller_reference
+ )
# e_tag = distribution['ETag']
result = delete_distribution(client, module, distribution)
if update:
- changed = config != distribution['Distribution']['DistributionConfig']
+ changed = config != distribution["Distribution"]["DistributionConfig"]
if changed:
result = update_distribution(client, module, config, distribution_id, e_tag)
else:
- result = distribution['Distribution']
- existing_tags = list_tags_for_resource(client, module, result['ARN'])
- distribution['Distribution']['DistributionConfig']['tags'] = existing_tags
- changed |= update_tags(client, module, existing_tags, tags, purge_tags, result['ARN'])
+ result = distribution["Distribution"]
+ existing_tags = list_tags_for_resource(client, module, result["ARN"])
+ distribution["Distribution"]["DistributionConfig"]["tags"] = existing_tags
+ changed |= update_tags(client, module, existing_tags, tags, purge_tags, result["ARN"])
result = camel_dict_to_snake_dict(result)
- result['distribution_config']['tags'] = config['tags'] = list_tags_for_resource(client, module, result['arn'])
- result['diff'] = dict()
- diff = recursive_diff(distribution['Distribution']['DistributionConfig'], config)
+ result["distribution_config"]["tags"] = config["tags"] = list_tags_for_resource(client, module, result["arn"])
+ result["diff"] = dict()
+ diff = recursive_diff(distribution["Distribution"]["DistributionConfig"], config)
if diff:
- result['diff']['before'] = diff[0]
- result['diff']['after'] = diff[1]
+ result["diff"]["before"] = diff[0]
+ result["diff"]["after"] = diff[1]
if wait and (create or update):
- validation_mgr.wait_until_processed(client, wait_timeout, distribution_id, config.get('CallerReference'))
+ validation_mgr.wait_until_processed(client, wait_timeout, distribution_id, config.get("CallerReference"))
- if 'distribution_config' in result:
- result.update(result['distribution_config'])
- del result['distribution_config']
+ if "distribution_config" in result:
+ result.update(result["distribution_config"])
+ del result["distribution_config"]
module.exit_json(changed=changed, **result)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/cloudfront_distribution_info.py b/ansible_collections/community/aws/plugins/modules/cloudfront_distribution_info.py
index cb97664fa..3bd20868a 100644
--- a/ansible_collections/community/aws/plugins/modules/cloudfront_distribution_info.py
+++ b/ansible_collections/community/aws/plugins/modules/cloudfront_distribution_info.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# This file is part of Ansible
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: cloudfront_distribution_info
version_added: 1.0.0
@@ -143,12 +141,12 @@ options:
type: bool
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide for details.
- name: Get a summary of distributions
@@ -191,9 +189,9 @@ EXAMPLES = '''
- name: Get all information about lists not requiring parameters (ie. list_origin_access_identities, list_distributions, list_streaming_distributions)
community.aws.cloudfront_distribution_info:
all_lists: true
-'''
+"""
-RETURN = '''
+RETURN = r"""
origin_access_identity:
description: Describes the origin access identity information. Requires I(origin_access_identity_id) to be set.
returned: only if I(origin_access_identity) is true
@@ -242,405 +240,169 @@ result:
as figuring out the DistributionId is usually the reason one uses this module in the first place.
returned: always
type: dict
-'''
-
-import traceback
-
-try:
- import botocore
-except ImportError:
- pass # Handled by AnsibleAWSModule
-
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-
-
-class CloudFrontServiceManager:
- """Handles CloudFront Services"""
-
- def __init__(self, module):
- self.module = module
-
- try:
- self.client = module.client('cloudfront', retry_decorator=AWSRetry.jittered_backoff())
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to connect to AWS')
-
- def get_distribution(self, distribution_id):
- try:
- distribution = self.client.get_distribution(aws_retry=True, Id=distribution_id)
- return distribution
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, msg="Error describing distribution")
-
- def get_distribution_config(self, distribution_id):
- try:
- distribution = self.client.get_distribution_config(aws_retry=True, Id=distribution_id)
- return distribution
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, msg="Error describing distribution configuration")
-
- def get_origin_access_identity(self, origin_access_identity_id):
- try:
- origin_access_identity = self.client.get_cloud_front_origin_access_identity(aws_retry=True, Id=origin_access_identity_id)
- return origin_access_identity
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, msg="Error describing origin access identity")
-
- def get_origin_access_identity_config(self, origin_access_identity_id):
- try:
- origin_access_identity = self.client.get_cloud_front_origin_access_identity_config(aws_retry=True, Id=origin_access_identity_id)
- return origin_access_identity
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, msg="Error describing origin access identity configuration")
-
- def get_invalidation(self, distribution_id, invalidation_id):
- try:
- invalidation = self.client.get_invalidation(aws_retry=True, DistributionId=distribution_id, Id=invalidation_id)
- return invalidation
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, msg="Error describing invalidation")
-
- def get_streaming_distribution(self, distribution_id):
- try:
- streaming_distribution = self.client.get_streaming_distribution(aws_retry=True, Id=distribution_id)
- return streaming_distribution
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, msg="Error describing streaming distribution")
-
- def get_streaming_distribution_config(self, distribution_id):
- try:
- streaming_distribution = self.client.get_streaming_distribution_config(aws_retry=True, Id=distribution_id)
- return streaming_distribution
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, msg="Error describing streaming distribution")
-
- # Split out paginator to allow for the backoff decorator to function
- @AWSRetry.jittered_backoff()
- def _paginated_result(self, paginator_name, **params):
- paginator = self.client.get_paginator(paginator_name)
- results = paginator.paginate(**params).build_full_result()
- return results
-
- def list_origin_access_identities(self):
- try:
- results = self._paginated_result('list_cloud_front_origin_access_identities')
- origin_access_identity_list = results.get('CloudFrontOriginAccessIdentityList', {'Items': []})
-
- if len(origin_access_identity_list['Items']) > 0:
- return origin_access_identity_list['Items']
- return {}
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, msg="Error listing cloud front origin access identities")
-
- def list_distributions(self, keyed=True):
- try:
- results = self._paginated_result('list_distributions')
- distribution_list = results.get('DistributionList', {'Items': []})
-
- if len(distribution_list['Items']) > 0:
- distribution_list = distribution_list['Items']
- else:
- return {}
-
- if not keyed:
- return distribution_list
- return self.keyed_list_helper(distribution_list)
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, msg="Error listing distributions")
-
- def list_distributions_by_web_acl_id(self, web_acl_id):
- try:
- results = self._paginated_result('list_cloud_front_origin_access_identities', WebAclId=web_acl_id)
- distribution_list = results.get('DistributionList', {'Items': []})
-
- if len(distribution_list['Items']) > 0:
- distribution_list = distribution_list['Items']
- else:
- return {}
- return self.keyed_list_helper(distribution_list)
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, msg="Error listing distributions by web acl id")
-
- def list_invalidations(self, distribution_id):
- try:
- results = self._paginated_result('list_invalidations', DistributionId=distribution_id)
- invalidation_list = results.get('InvalidationList', {'Items': []})
-
- if len(invalidation_list['Items']) > 0:
- return invalidation_list['Items']
- return {}
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, msg="Error listing invalidations")
-
- def list_streaming_distributions(self, keyed=True):
- try:
- results = self._paginated_result('list_streaming_distributions')
- streaming_distribution_list = results.get('StreamingDistributionList', {'Items': []})
-
- if len(streaming_distribution_list['Items']) > 0:
- streaming_distribution_list = streaming_distribution_list['Items']
- else:
- return {}
-
- if not keyed:
- return streaming_distribution_list
- return self.keyed_list_helper(streaming_distribution_list)
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, msg="Error listing streaming distributions")
-
- def summary(self):
- summary_dict = {}
- summary_dict.update(self.summary_get_distribution_list(False))
- summary_dict.update(self.summary_get_distribution_list(True))
- summary_dict.update(self.summary_get_origin_access_identity_list())
- return summary_dict
-
- def summary_get_origin_access_identity_list(self):
- try:
- origin_access_identity_list = {'origin_access_identities': []}
- origin_access_identities = self.list_origin_access_identities()
- for origin_access_identity in origin_access_identities:
- oai_id = origin_access_identity['Id']
- oai_full_response = self.get_origin_access_identity(oai_id)
- oai_summary = {'Id': oai_id, 'ETag': oai_full_response['ETag']}
- origin_access_identity_list['origin_access_identities'].append(oai_summary)
- return origin_access_identity_list
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, msg="Error generating summary of origin access identities")
-
- def summary_get_distribution_list(self, streaming=False):
- try:
- list_name = 'streaming_distributions' if streaming else 'distributions'
- key_list = ['Id', 'ARN', 'Status', 'LastModifiedTime', 'DomainName', 'Comment', 'PriceClass', 'Enabled']
- distribution_list = {list_name: []}
- distributions = self.list_streaming_distributions(False) if streaming else self.list_distributions(False)
- for dist in distributions:
- temp_distribution = {}
- for key_name in key_list:
- temp_distribution[key_name] = dist[key_name]
- temp_distribution['Aliases'] = [alias for alias in dist['Aliases'].get('Items', [])]
- temp_distribution['ETag'] = self.get_etag_from_distribution_id(dist['Id'], streaming)
- if not streaming:
- temp_distribution['WebACLId'] = dist['WebACLId']
- invalidation_ids = self.get_list_of_invalidation_ids_from_distribution_id(dist['Id'])
- if invalidation_ids:
- temp_distribution['Invalidations'] = invalidation_ids
- resource_tags = self.client.list_tags_for_resource(Resource=dist['ARN'])
- temp_distribution['Tags'] = boto3_tag_list_to_ansible_dict(resource_tags['Tags'].get('Items', []))
- distribution_list[list_name].append(temp_distribution)
- return distribution_list
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, msg="Error generating summary of distributions")
- except Exception as e:
- self.module.fail_json(msg="Error generating summary of distributions - " + str(e),
- exception=traceback.format_exc())
-
- def get_etag_from_distribution_id(self, distribution_id, streaming):
- distribution = {}
- if not streaming:
- distribution = self.get_distribution(distribution_id)
- else:
- distribution = self.get_streaming_distribution(distribution_id)
- return distribution['ETag']
-
- def get_list_of_invalidation_ids_from_distribution_id(self, distribution_id):
- try:
- invalidation_ids = []
- invalidations = self.list_invalidations(distribution_id)
- for invalidation in invalidations:
- invalidation_ids.append(invalidation['Id'])
- return invalidation_ids
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, msg="Error getting list of invalidation ids")
-
- def get_distribution_id_from_domain_name(self, domain_name):
- try:
- distribution_id = ""
- distributions = self.list_distributions(False)
- distributions += self.list_streaming_distributions(False)
- for dist in distributions:
- if 'Items' in dist['Aliases']:
- for alias in dist['Aliases']['Items']:
- if str(alias).lower() == domain_name.lower():
- distribution_id = dist['Id']
- break
- return distribution_id
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, msg="Error getting distribution id from domain name")
-
- def get_aliases_from_distribution_id(self, distribution_id):
- aliases = []
- try:
- distributions = self.list_distributions(False)
- for dist in distributions:
- if dist['Id'] == distribution_id and 'Items' in dist['Aliases']:
- for alias in dist['Aliases']['Items']:
- aliases.append(alias)
- break
- return aliases
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, msg="Error getting list of aliases from distribution_id")
-
- def keyed_list_helper(self, list_to_key):
- keyed_list = dict()
- for item in list_to_key:
- distribution_id = item['Id']
- if 'Items' in item['Aliases']:
- aliases = item['Aliases']['Items']
- for alias in aliases:
- keyed_list.update({alias: item})
- keyed_list.update({distribution_id: item})
- return keyed_list
+"""
+
+from ansible_collections.amazon.aws.plugins.module_utils.cloudfront_facts import CloudFrontFactsServiceManager
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def set_facts_for_distribution_id_and_alias(details, facts, distribution_id, aliases):
- facts[distribution_id].update(details)
+ facts[distribution_id] = details
# also have a fixed key for accessing results/details returned
- facts['result'] = details
- facts['result']['DistributionId'] = distribution_id
+ facts["result"] = details
+ facts["result"]["DistributionId"] = distribution_id
for alias in aliases:
- facts[alias].update(details)
+ facts[alias] = details
return facts
def main():
argument_spec = dict(
- distribution_id=dict(required=False, type='str'),
- invalidation_id=dict(required=False, type='str'),
- origin_access_identity_id=dict(required=False, type='str'),
- domain_name_alias=dict(required=False, type='str'),
- all_lists=dict(required=False, default=False, type='bool'),
- distribution=dict(required=False, default=False, type='bool'),
- distribution_config=dict(required=False, default=False, type='bool'),
- origin_access_identity=dict(required=False, default=False, type='bool'),
- origin_access_identity_config=dict(required=False, default=False, type='bool'),
- invalidation=dict(required=False, default=False, type='bool'),
- streaming_distribution=dict(required=False, default=False, type='bool'),
- streaming_distribution_config=dict(required=False, default=False, type='bool'),
- list_origin_access_identities=dict(required=False, default=False, type='bool'),
- list_distributions=dict(required=False, default=False, type='bool'),
- list_distributions_by_web_acl_id=dict(required=False, default=False, type='bool'),
- list_invalidations=dict(required=False, default=False, type='bool'),
- list_streaming_distributions=dict(required=False, default=False, type='bool'),
- summary=dict(required=False, default=False, type='bool'),
+ distribution_id=dict(required=False, type="str"),
+ invalidation_id=dict(required=False, type="str"),
+ origin_access_identity_id=dict(required=False, type="str"),
+ domain_name_alias=dict(required=False, type="str"),
+ all_lists=dict(required=False, default=False, type="bool"),
+ distribution=dict(required=False, default=False, type="bool"),
+ distribution_config=dict(required=False, default=False, type="bool"),
+ origin_access_identity=dict(required=False, default=False, type="bool"),
+ origin_access_identity_config=dict(required=False, default=False, type="bool"),
+ invalidation=dict(required=False, default=False, type="bool"),
+ streaming_distribution=dict(required=False, default=False, type="bool"),
+ streaming_distribution_config=dict(required=False, default=False, type="bool"),
+ list_origin_access_identities=dict(required=False, default=False, type="bool"),
+ list_distributions=dict(required=False, default=False, type="bool"),
+ list_distributions_by_web_acl_id=dict(required=False, default=False, type="bool"),
+ list_invalidations=dict(required=False, default=False, type="bool"),
+ list_streaming_distributions=dict(required=False, default=False, type="bool"),
+ summary=dict(required=False, default=False, type="bool"),
)
module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
- service_mgr = CloudFrontServiceManager(module)
-
- distribution_id = module.params.get('distribution_id')
- invalidation_id = module.params.get('invalidation_id')
- origin_access_identity_id = module.params.get('origin_access_identity_id')
- web_acl_id = module.params.get('web_acl_id')
- domain_name_alias = module.params.get('domain_name_alias')
- all_lists = module.params.get('all_lists')
- distribution = module.params.get('distribution')
- distribution_config = module.params.get('distribution_config')
- origin_access_identity = module.params.get('origin_access_identity')
- origin_access_identity_config = module.params.get('origin_access_identity_config')
- invalidation = module.params.get('invalidation')
- streaming_distribution = module.params.get('streaming_distribution')
- streaming_distribution_config = module.params.get('streaming_distribution_config')
- list_origin_access_identities = module.params.get('list_origin_access_identities')
- list_distributions = module.params.get('list_distributions')
- list_distributions_by_web_acl_id = module.params.get('list_distributions_by_web_acl_id')
- list_invalidations = module.params.get('list_invalidations')
- list_streaming_distributions = module.params.get('list_streaming_distributions')
- summary = module.params.get('summary')
+ service_mgr = CloudFrontFactsServiceManager(module)
+
+ distribution_id = module.params.get("distribution_id")
+ invalidation_id = module.params.get("invalidation_id")
+ origin_access_identity_id = module.params.get("origin_access_identity_id")
+ web_acl_id = module.params.get("web_acl_id")
+ domain_name_alias = module.params.get("domain_name_alias")
+ all_lists = module.params.get("all_lists")
+ distribution = module.params.get("distribution")
+ distribution_config = module.params.get("distribution_config")
+ origin_access_identity = module.params.get("origin_access_identity")
+ origin_access_identity_config = module.params.get("origin_access_identity_config")
+ invalidation = module.params.get("invalidation")
+ streaming_distribution = module.params.get("streaming_distribution")
+ streaming_distribution_config = module.params.get("streaming_distribution_config")
+ list_origin_access_identities = module.params.get("list_origin_access_identities")
+ list_distributions = module.params.get("list_distributions")
+ list_distributions_by_web_acl_id = module.params.get("list_distributions_by_web_acl_id")
+ list_invalidations = module.params.get("list_invalidations")
+ list_streaming_distributions = module.params.get("list_streaming_distributions")
+ summary = module.params.get("summary")
aliases = []
- result = {'cloudfront': {}}
+ result = {"cloudfront": {}}
facts = {}
- require_distribution_id = (distribution or distribution_config or invalidation or streaming_distribution or
- streaming_distribution_config or list_invalidations)
+ require_distribution_id = (
+ distribution
+ or distribution_config
+ or invalidation
+ or streaming_distribution
+ or streaming_distribution_config
+ or list_invalidations
+ )
# set default to summary if no option specified
- summary = summary or not (distribution or distribution_config or origin_access_identity or
- origin_access_identity_config or invalidation or streaming_distribution or streaming_distribution_config or
- list_origin_access_identities or list_distributions_by_web_acl_id or list_invalidations or
- list_streaming_distributions or list_distributions)
+ summary = summary or not (
+ distribution
+ or distribution_config
+ or origin_access_identity
+ or origin_access_identity_config
+ or invalidation
+ or streaming_distribution
+ or streaming_distribution_config
+ or list_origin_access_identities
+ or list_distributions_by_web_acl_id
+ or list_invalidations
+ or list_streaming_distributions
+ or list_distributions
+ )
# validations
if require_distribution_id and distribution_id is None and domain_name_alias is None:
- module.fail_json(msg='Error distribution_id or domain_name_alias have not been specified.')
- if (invalidation and invalidation_id is None):
- module.fail_json(msg='Error invalidation_id has not been specified.')
+ module.fail_json(msg="Error distribution_id or domain_name_alias have not been specified.")
+ if invalidation and invalidation_id is None:
+ module.fail_json(msg="Error invalidation_id has not been specified.")
if (origin_access_identity or origin_access_identity_config) and origin_access_identity_id is None:
- module.fail_json(msg='Error origin_access_identity_id has not been specified.')
+ module.fail_json(msg="Error origin_access_identity_id has not been specified.")
if list_distributions_by_web_acl_id and web_acl_id is None:
- module.fail_json(msg='Error web_acl_id has not been specified.')
+ module.fail_json(msg="Error web_acl_id has not been specified.")
# get distribution id from domain name alias
if require_distribution_id and distribution_id is None:
distribution_id = service_mgr.get_distribution_id_from_domain_name(domain_name_alias)
if not distribution_id:
- module.fail_json(msg='Error unable to source a distribution id from domain_name_alias')
+ module.fail_json(msg="Error unable to source a distribution id from domain_name_alias")
# set appropriate cloudfront id
- if distribution_id and not list_invalidations:
- facts = {distribution_id: {}}
- aliases = service_mgr.get_aliases_from_distribution_id(distribution_id)
- for alias in aliases:
- facts.update({alias: {}})
- if invalidation_id:
- facts.update({invalidation_id: {}})
- elif distribution_id and list_invalidations:
- facts = {distribution_id: {}}
- aliases = service_mgr.get_aliases_from_distribution_id(distribution_id)
- for alias in aliases:
- facts.update({alias: {}})
- elif origin_access_identity_id:
- facts = {origin_access_identity_id: {}}
- elif web_acl_id:
- facts = {web_acl_id: {}}
+ if invalidation_id is not None and invalidation:
+ facts.update({invalidation_id: {}})
+ if origin_access_identity_id and (origin_access_identity or origin_access_identity_config):
+ facts.update({origin_access_identity_id: {}})
+ if web_acl_id:
+ facts.update({web_acl_id: {}})
# get details based on options
if distribution:
- facts_to_set = service_mgr.get_distribution(distribution_id)
+ facts_to_set = service_mgr.get_distribution(id=distribution_id)
if distribution_config:
- facts_to_set = service_mgr.get_distribution_config(distribution_id)
+ facts_to_set = service_mgr.get_distribution_config(id=distribution_id)
if origin_access_identity:
- facts[origin_access_identity_id].update(service_mgr.get_origin_access_identity(origin_access_identity_id))
+ facts[origin_access_identity_id].update(service_mgr.get_origin_access_identity(id=origin_access_identity_id))
if origin_access_identity_config:
- facts[origin_access_identity_id].update(service_mgr.get_origin_access_identity_config(origin_access_identity_id))
+ facts[origin_access_identity_id].update(
+ service_mgr.get_origin_access_identity_config(id=origin_access_identity_id)
+ )
if invalidation:
- facts_to_set = service_mgr.get_invalidation(distribution_id, invalidation_id)
+ facts_to_set = service_mgr.get_invalidation(distribution_id=distribution_id, id=invalidation_id)
facts[invalidation_id].update(facts_to_set)
if streaming_distribution:
- facts_to_set = service_mgr.get_streaming_distribution(distribution_id)
+ facts_to_set = service_mgr.get_streaming_distribution(id=distribution_id)
if streaming_distribution_config:
- facts_to_set = service_mgr.get_streaming_distribution_config(distribution_id)
+ facts_to_set = service_mgr.get_streaming_distribution_config(id=distribution_id)
if list_invalidations:
- facts_to_set = {'invalidations': service_mgr.list_invalidations(distribution_id)}
- if 'facts_to_set' in vars():
+ invalidations = service_mgr.list_invalidations(distribution_id=distribution_id) or {}
+ facts_to_set = {"invalidations": invalidations}
+ if "facts_to_set" in vars():
+ aliases = service_mgr.get_aliases_from_distribution_id(distribution_id)
facts = set_facts_for_distribution_id_and_alias(facts_to_set, facts, distribution_id, aliases)
# get list based on options
if all_lists or list_origin_access_identities:
- facts['origin_access_identities'] = service_mgr.list_origin_access_identities()
+ facts["origin_access_identities"] = service_mgr.list_origin_access_identities() or {}
if all_lists or list_distributions:
- facts['distributions'] = service_mgr.list_distributions()
+ facts["distributions"] = service_mgr.list_distributions() or {}
if all_lists or list_streaming_distributions:
- facts['streaming_distributions'] = service_mgr.list_streaming_distributions()
+ facts["streaming_distributions"] = service_mgr.list_streaming_distributions() or {}
if list_distributions_by_web_acl_id:
- facts['distributions_by_web_acl_id'] = service_mgr.list_distributions_by_web_acl_id(web_acl_id)
+ facts["distributions_by_web_acl_id"] = service_mgr.list_distributions_by_web_acl_id(web_acl_id=web_acl_id) or {}
if list_invalidations:
- facts['invalidations'] = service_mgr.list_invalidations(distribution_id)
+ facts["invalidations"] = service_mgr.list_invalidations(distribution_id=distribution_id) or {}
# default summary option
if summary:
- facts['summary'] = service_mgr.summary()
+ facts["summary"] = service_mgr.summary()
- result['changed'] = False
- result['cloudfront'].update(facts)
+ result["changed"] = False
+ result["cloudfront"].update(facts)
module.exit_json(msg="Retrieved CloudFront info.", **result)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/cloudfront_invalidation.py b/ansible_collections/community/aws/plugins/modules/cloudfront_invalidation.py
index 767a1d181..732d135e1 100644
--- a/ansible_collections/community/aws/plugins/modules/cloudfront_invalidation.py
+++ b/ansible_collections/community/aws/plugins/modules/cloudfront_invalidation.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
version_added: 1.0.0
@@ -14,15 +12,10 @@ module: cloudfront_invalidation
short_description: create invalidations for AWS CloudFront distributions
description:
- - Allows for invalidation of a batch of paths for a CloudFront distribution.
-
-author: Willem van Ketwich (@wilvk)
-
-extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
+ - Allows for invalidation of a batch of paths for a CloudFront distribution.
+author:
+ - Willem van Ketwich (@wilvk)
options:
distribution_id:
@@ -52,10 +45,13 @@ options:
notes:
- does not support check mode
-'''
-
-EXAMPLES = r'''
+extends_documentation_fragment:
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
+EXAMPLES = r"""
- name: create a batch of invalidations using a distribution_id for a reference
community.aws.cloudfront_invalidation:
distribution_id: E15BU8SDCGSG57
@@ -73,10 +69,9 @@ EXAMPLES = r'''
- /testpathone/test4.css
- /testpathtwo/test5.js
- /testpaththree/*
+"""
-'''
-
-RETURN = r'''
+RETURN = r"""
invalidation:
description: The invalidation's information.
returned: always
@@ -130,7 +125,7 @@ location:
returned: always
type: str
sample: https://cloudfront.amazonaws.com/2017-03-25/distribution/E1ZID6KZJECZY7/invalidation/I2G9MOWJZFV622
-'''
+"""
import datetime
@@ -142,60 +137,61 @@ except ImportError:
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
from ansible.module_utils.common.dict_transformations import snake_dict_to_camel_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_message
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_message
from ansible_collections.amazon.aws.plugins.module_utils.cloudfront_facts import CloudFrontFactsServiceManager
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
+
class CloudFrontInvalidationServiceManager(object):
"""
Handles CloudFront service calls to AWS for invalidations
"""
- def __init__(self, module):
+ def __init__(self, module, cloudfront_facts_mgr):
self.module = module
- self.client = module.client('cloudfront')
+ self.client = module.client("cloudfront")
+ self.__cloudfront_facts_mgr = cloudfront_facts_mgr
def create_invalidation(self, distribution_id, invalidation_batch):
- current_invalidation_response = self.get_invalidation(distribution_id, invalidation_batch['CallerReference'])
+ current_invalidation_response = self.get_invalidation(distribution_id, invalidation_batch["CallerReference"])
try:
- response = self.client.create_invalidation(DistributionId=distribution_id, InvalidationBatch=invalidation_batch)
- response.pop('ResponseMetadata', None)
+ response = self.client.create_invalidation(
+ DistributionId=distribution_id, InvalidationBatch=invalidation_batch
+ )
+ response.pop("ResponseMetadata", None)
if current_invalidation_response:
return response, False
else:
return response, True
- except is_boto3_error_message('Your request contains a caller reference that was used for a previous invalidation '
- 'batch for the same distribution.'):
- self.module.warn("InvalidationBatch target paths are not modifiable. "
- "To make a new invalidation please update caller_reference.")
+ except is_boto3_error_message(
+ "Your request contains a caller reference that was used for a previous invalidation "
+ "batch for the same distribution."
+ ):
+ self.module.warn(
+ "InvalidationBatch target paths are not modifiable. "
+ "To make a new invalidation please update caller_reference."
+ )
return current_invalidation_response, False
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
self.module.fail_json_aws(e, msg="Error creating CloudFront invalidations.")
def get_invalidation(self, distribution_id, caller_reference):
- current_invalidation = {}
# find all invalidations for the distribution
- try:
- paginator = self.client.get_paginator('list_invalidations')
- invalidations = paginator.paginate(DistributionId=distribution_id).build_full_result().get('InvalidationList', {}).get('Items', [])
- invalidation_ids = [inv['Id'] for inv in invalidations]
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, msg="Error listing CloudFront invalidations.")
+ invalidations = self.__cloudfront_facts_mgr.list_invalidations(distribution_id=distribution_id)
# check if there is an invalidation with the same caller reference
- for inv_id in invalidation_ids:
- try:
- invalidation = self.client.get_invalidation(DistributionId=distribution_id, Id=inv_id)['Invalidation']
- caller_ref = invalidation.get('InvalidationBatch', {}).get('CallerReference')
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, msg="Error getting CloudFront invalidation {0}".format(inv_id))
- if caller_ref == caller_reference:
- current_invalidation = invalidation
- break
-
- current_invalidation.pop('ResponseMetadata', None)
- return current_invalidation
+ for invalidation in invalidations:
+ invalidation_info = self.__cloudfront_facts_mgr.get_invalidation(
+ distribution_id=distribution_id, id=invalidation["Id"]
+ )
+ if invalidation_info.get("InvalidationBatch", {}).get("CallerReference") == caller_reference:
+ invalidation_info.pop("ResponseMetadata", None)
+ return invalidation_info
+ return {}
class CloudFrontInvalidationValidationManager(object):
@@ -203,9 +199,9 @@ class CloudFrontInvalidationValidationManager(object):
Manages CloudFront validations for invalidation batches
"""
- def __init__(self, module):
+ def __init__(self, module, cloudfront_facts_mgr):
self.module = module
- self.__cloudfront_facts_mgr = CloudFrontFactsServiceManager(module)
+ self.__cloudfront_facts_mgr = cloudfront_facts_mgr
def validate_distribution_id(self, distribution_id, alias):
try:
@@ -230,8 +226,8 @@ class CloudFrontInvalidationValidationManager(object):
else:
valid_caller_reference = datetime.datetime.now().isoformat()
valid_invalidation_batch = {
- 'paths': self.create_aws_list(invalidation_batch),
- 'caller_reference': valid_caller_reference
+ "paths": self.create_aws_list(invalidation_batch),
+ "caller_reference": valid_caller_reference,
}
return valid_invalidation_batch
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
@@ -243,18 +239,21 @@ def main():
caller_reference=dict(),
distribution_id=dict(),
alias=dict(),
- target_paths=dict(required=True, type='list', elements='str')
+ target_paths=dict(required=True, type="list", elements="str"),
)
- module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=False, mutually_exclusive=[['distribution_id', 'alias']])
+ module = AnsibleAWSModule(
+ argument_spec=argument_spec, supports_check_mode=False, mutually_exclusive=[["distribution_id", "alias"]]
+ )
- validation_mgr = CloudFrontInvalidationValidationManager(module)
- service_mgr = CloudFrontInvalidationServiceManager(module)
+ cloudfront_facts_mgr = CloudFrontFactsServiceManager(module)
+ validation_mgr = CloudFrontInvalidationValidationManager(module, cloudfront_facts_mgr)
+ service_mgr = CloudFrontInvalidationServiceManager(module, cloudfront_facts_mgr)
- caller_reference = module.params.get('caller_reference')
- distribution_id = module.params.get('distribution_id')
- alias = module.params.get('alias')
- target_paths = module.params.get('target_paths')
+ caller_reference = module.params.get("caller_reference")
+ distribution_id = module.params.get("distribution_id")
+ alias = module.params.get("alias")
+ target_paths = module.params.get("target_paths")
result = {}
@@ -266,5 +265,5 @@ def main():
module.exit_json(changed=changed, **camel_dict_to_snake_dict(result))
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/cloudfront_origin_access_identity.py b/ansible_collections/community/aws/plugins/modules/cloudfront_origin_access_identity.py
index c6879d0c5..bb5e3a017 100644
--- a/ansible_collections/community/aws/plugins/modules/cloudfront_origin_access_identity.py
+++ b/ansible_collections/community/aws/plugins/modules/cloudfront_origin_access_identity.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
version_added: 1.0.0
@@ -16,16 +14,11 @@ short_description: Create, update and delete origin access identities for a
CloudFront distribution
description:
- - Allows for easy creation, updating and deletion of origin access
- identities.
-
-author: Willem van Ketwich (@wilvk)
-
-extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
+ - Allows for easy creation, updating and deletion of origin access
+ identities.
+author:
+ - Willem van Ketwich (@wilvk)
options:
state:
@@ -54,9 +47,13 @@ options:
notes:
- Does not support check mode.
-'''
+extends_documentation_fragment:
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
- name: create an origin access identity
community.aws.cloudfront_origin_access_identity:
@@ -66,19 +63,18 @@ EXAMPLES = '''
- name: update an existing origin access identity using caller_reference as an identifier
community.aws.cloudfront_origin_access_identity:
- origin_access_identity_id: E17DRN9XUOAHZX
- caller_reference: this is an example reference
- comment: this is a new comment
+ origin_access_identity_id: E17DRN9XUOAHZX
+ caller_reference: this is an example reference
+ comment: this is a new comment
- name: delete an existing origin access identity using caller_reference as an identifier
community.aws.cloudfront_origin_access_identity:
- state: absent
- caller_reference: this is an example reference
- comment: this is a new comment
-
-'''
+ state: absent
+ caller_reference: this is an example reference
+ comment: this is a new comment
+"""
-RETURN = '''
+RETURN = r"""
cloud_front_origin_access_identity:
description: The origin access identity's information.
returned: always
@@ -113,20 +109,22 @@ location:
description: The fully qualified URI of the new origin access identity just created.
returned: when initially created
type: str
-
-'''
+"""
import datetime
try:
- from botocore.exceptions import ClientError, BotoCoreError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
except ImportError:
pass # caught by imported AnsibleAWSModule
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
from ansible_collections.amazon.aws.plugins.module_utils.cloudfront_facts import CloudFrontFactsServiceManager
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
class CloudFrontOriginAccessIdentityServiceManager(object):
@@ -136,35 +134,31 @@ class CloudFrontOriginAccessIdentityServiceManager(object):
def __init__(self, module):
self.module = module
- self.client = module.client('cloudfront')
+ self.client = module.client("cloudfront")
def create_origin_access_identity(self, caller_reference, comment):
try:
return self.client.create_cloud_front_origin_access_identity(
- CloudFrontOriginAccessIdentityConfig={
- 'CallerReference': caller_reference,
- 'Comment': comment
- }
+ CloudFrontOriginAccessIdentityConfig={"CallerReference": caller_reference, "Comment": comment}
)
except (ClientError, BotoCoreError) as e:
self.module.fail_json_aws(e, msg="Error creating cloud front origin access identity.")
def delete_origin_access_identity(self, origin_access_identity_id, e_tag):
try:
- return self.client.delete_cloud_front_origin_access_identity(Id=origin_access_identity_id, IfMatch=e_tag)
+ result = self.client.delete_cloud_front_origin_access_identity(Id=origin_access_identity_id, IfMatch=e_tag)
+ return result, True
except (ClientError, BotoCoreError) as e:
- self.module.fail_json_aws(e, msg="Error updating Origin Access Identity.")
+ self.module.fail_json_aws(e, msg="Error deleting Origin Access Identity.")
def update_origin_access_identity(self, caller_reference, comment, origin_access_identity_id, e_tag):
changed = False
- new_config = {
- 'CallerReference': caller_reference,
- 'Comment': comment
- }
+ new_config = {"CallerReference": caller_reference, "Comment": comment}
try:
- current_config = self.client.get_cloud_front_origin_access_identity_config(
- Id=origin_access_identity_id)['CloudFrontOriginAccessIdentityConfig']
+ current_config = self.client.get_cloud_front_origin_access_identity_config(Id=origin_access_identity_id)[
+ "CloudFrontOriginAccessIdentityConfig"
+ ]
except (ClientError, BotoCoreError) as e:
self.module.fail_json_aws(e, msg="Error getting Origin Access Identity config.")
@@ -194,38 +188,54 @@ class CloudFrontOriginAccessIdentityValidationManager(object):
self.module = module
self.__cloudfront_facts_mgr = CloudFrontFactsServiceManager(module)
- def validate_etag_from_origin_access_identity_id(self, origin_access_identity_id):
+ def describe_origin_access_identity(self, origin_access_identity_id, fail_if_missing=True):
try:
- if origin_access_identity_id is None:
- return
- oai = self.__cloudfront_facts_mgr.get_origin_access_identity(origin_access_identity_id)
- if oai is not None:
- return oai.get('ETag')
- except (ClientError, BotoCoreError) as e:
+ return self.__cloudfront_facts_mgr.get_origin_access_identity(
+ id=origin_access_identity_id, fail_if_error=False
+ )
+ except is_boto3_error_code("NoSuchCloudFrontOriginAccessIdentity") as e: # pylint: disable=duplicate-except
+ if fail_if_missing:
+ self.module.fail_json_aws(e, msg="Error getting etag from origin_access_identity.")
+ return {}
+ except (ClientError, BotoCoreError) as e: # pylint: disable=duplicate-except
self.module.fail_json_aws(e, msg="Error getting etag from origin_access_identity.")
- def validate_origin_access_identity_id_from_caller_reference(
- self, caller_reference):
- try:
- origin_access_identities = self.__cloudfront_facts_mgr.list_origin_access_identities()
- origin_origin_access_identity_ids = [oai.get('Id') for oai in origin_access_identities]
- for origin_access_identity_id in origin_origin_access_identity_ids:
- oai_config = (self.__cloudfront_facts_mgr.get_origin_access_identity_config(origin_access_identity_id))
- temp_caller_reference = oai_config.get('CloudFrontOriginAccessIdentityConfig').get('CallerReference')
- if temp_caller_reference == caller_reference:
- return origin_access_identity_id
- except (ClientError, BotoCoreError) as e:
- self.module.fail_json_aws(e, msg="Error getting Origin Access Identity from caller_reference.")
+ def validate_etag_from_origin_access_identity_id(self, origin_access_identity_id, fail_if_missing):
+ oai = self.describe_origin_access_identity(origin_access_identity_id, fail_if_missing)
+ if oai is not None:
+ return oai.get("ETag")
+
+ def validate_origin_access_identity_id_from_caller_reference(self, caller_reference):
+ origin_access_identities = self.__cloudfront_facts_mgr.list_origin_access_identities()
+ origin_origin_access_identity_ids = [oai.get("Id") for oai in origin_access_identities]
+ for origin_access_identity_id in origin_origin_access_identity_ids:
+ oai_config = self.__cloudfront_facts_mgr.get_origin_access_identity_config(id=origin_access_identity_id)
+ temp_caller_reference = oai_config.get("CloudFrontOriginAccessIdentityConfig").get("CallerReference")
+ if temp_caller_reference == caller_reference:
+ return origin_access_identity_id
def validate_comment(self, comment):
if comment is None:
- return "origin access identity created by Ansible with datetime " + datetime.datetime.now().strftime('%Y-%m-%dT%H:%M:%S.%f')
+ return "origin access identity created by Ansible with datetime " + datetime.datetime.now().strftime(
+ "%Y-%m-%dT%H:%M:%S.%f"
+ )
return comment
+ def validate_caller_reference_from_origin_access_identity_id(self, origin_access_identity_id, caller_reference):
+ if caller_reference is None:
+ if origin_access_identity_id is None:
+ return datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%f")
+ oai = self.describe_origin_access_identity(origin_access_identity_id, fail_if_missing=True)
+ origin_access_config = oai.get("CloudFrontOriginAccessIdentity", {}).get(
+ "CloudFrontOriginAccessIdentityConfig", {}
+ )
+ return origin_access_config.get("CallerReference")
+ return caller_reference
+
def main():
argument_spec = dict(
- state=dict(choices=['present', 'absent'], default='present'),
+ state=dict(choices=["present", "absent"], default="present"),
origin_access_identity_id=dict(),
caller_reference=dict(),
comment=dict(),
@@ -239,32 +249,41 @@ def main():
service_mgr = CloudFrontOriginAccessIdentityServiceManager(module)
validation_mgr = CloudFrontOriginAccessIdentityValidationManager(module)
- state = module.params.get('state')
- caller_reference = module.params.get('caller_reference')
+ state = module.params.get("state")
+ caller_reference = module.params.get("caller_reference")
- comment = module.params.get('comment')
- origin_access_identity_id = module.params.get('origin_access_identity_id')
+ comment = module.params.get("comment")
+ origin_access_identity_id = module.params.get("origin_access_identity_id")
if origin_access_identity_id is None and caller_reference is not None:
- origin_access_identity_id = validation_mgr.validate_origin_access_identity_id_from_caller_reference(caller_reference)
-
- e_tag = validation_mgr.validate_etag_from_origin_access_identity_id(origin_access_identity_id)
- comment = validation_mgr.validate_comment(comment)
-
- if state == 'present':
- if origin_access_identity_id is not None and e_tag is not None:
- result, changed = service_mgr.update_origin_access_identity(caller_reference, comment, origin_access_identity_id, e_tag)
+ origin_access_identity_id = validation_mgr.validate_origin_access_identity_id_from_caller_reference(
+ caller_reference
+ )
+
+ if state == "present":
+ comment = validation_mgr.validate_comment(comment)
+ caller_reference = validation_mgr.validate_caller_reference_from_origin_access_identity_id(
+ origin_access_identity_id, caller_reference
+ )
+ if origin_access_identity_id is not None:
+ e_tag = validation_mgr.validate_etag_from_origin_access_identity_id(origin_access_identity_id, True)
+ # update cloudfront origin access identity
+ result, changed = service_mgr.update_origin_access_identity(
+ caller_reference, comment, origin_access_identity_id, e_tag
+ )
else:
+ # create cloudfront origin access identity
result = service_mgr.create_origin_access_identity(caller_reference, comment)
changed = True
- elif state == 'absent' and origin_access_identity_id is not None and e_tag is not None:
- result = service_mgr.delete_origin_access_identity(origin_access_identity_id, e_tag)
- changed = True
+ else:
+ e_tag = validation_mgr.validate_etag_from_origin_access_identity_id(origin_access_identity_id, False)
+ if e_tag:
+ result, changed = service_mgr.delete_origin_access_identity(origin_access_identity_id, e_tag)
- result.pop('ResponseMetadata', None)
+ result.pop("ResponseMetadata", None)
module.exit_json(changed=changed, **camel_dict_to_snake_dict(result))
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/cloudfront_response_headers_policy.py b/ansible_collections/community/aws/plugins/modules/cloudfront_response_headers_policy.py
index 01b38a3bd..a7558e8a8 100644
--- a/ansible_collections/community/aws/plugins/modules/cloudfront_response_headers_policy.py
+++ b/ansible_collections/community/aws/plugins/modules/cloudfront_response_headers_policy.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
version_added: 3.2.0
module: cloudfront_response_headers_policy
@@ -14,16 +12,11 @@ module: cloudfront_response_headers_policy
short_description: Create, update and delete response headers policies to be used in a Cloudfront distribution
description:
- - Create, update and delete response headers policies to be used in a Cloudfront distribution for inserting custom headers
- - See docs at U(https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/cloudfront.html#CloudFront.Client.create_response_headers_policy)
-
-author: Stefan Horning (@stefanhorning)
-
-extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
+ - Create, update and delete response headers policies to be used in a Cloudfront distribution for inserting custom headers
+ - See docs at U(https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/cloudfront.html#CloudFront.Client.create_response_headers_policy)
+author:
+ - Stefan Horning (@stefanhorning)
options:
state:
@@ -57,9 +50,13 @@ options:
default: {}
type: dict
-'''
+extends_documentation_fragment:
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
- name: Creationg a Cloudfront header policy using all predefined header features and a custom header for demonstration
community.aws.cloudfront_response_headers_policy:
name: my-header-policy
@@ -113,9 +110,9 @@ EXAMPLES = '''
community.aws.cloudfront_response_headers_policy:
name: my-header-policy
state: absent
-'''
+"""
-RETURN = '''
+RETURN = r"""
response_headers_policy:
description: The policy's information
returned: success
@@ -141,40 +138,43 @@ response_headers_policy:
type: str
returned: always
sample: my-header-policy
-'''
+"""
+
+import datetime
try:
- from botocore.exceptions import ClientError, ParamValidationError, BotoCoreError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
except ImportError:
pass # caught by imported AnsibleAWSModule
-from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict, snake_dict_to_camel_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-import datetime
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+from ansible.module_utils.common.dict_transformations import snake_dict_to_camel_dict
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
-class CloudfrontResponseHeadersPolicyService(object):
+class CloudfrontResponseHeadersPolicyService(object):
def __init__(self, module):
self.module = module
- self.client = module.client('cloudfront')
+ self.client = module.client("cloudfront")
self.check_mode = module.check_mode
def find_response_headers_policy(self, name):
try:
- policies = self.client.list_response_headers_policies()['ResponseHeadersPolicyList']['Items']
+ policies = self.client.list_response_headers_policies()["ResponseHeadersPolicyList"]["Items"]
for policy in policies:
- if policy['ResponseHeadersPolicy']['ResponseHeadersPolicyConfig']['Name'] == name:
- policy_id = policy['ResponseHeadersPolicy']['Id']
+ if policy["ResponseHeadersPolicy"]["ResponseHeadersPolicyConfig"]["Name"] == name:
+ policy_id = policy["ResponseHeadersPolicy"]["Id"]
# as the list_ request does not contain the Etag (which we need), we need to do another get_ request here
- matching_policy = self.client.get_response_headers_policy(Id=policy['ResponseHeadersPolicy']['Id'])
+ matching_policy = self.client.get_response_headers_policy(Id=policy["ResponseHeadersPolicy"]["Id"])
break
else:
matching_policy = None
return matching_policy
- except (ParamValidationError, ClientError, BotoCoreError) as e:
+ except (ClientError, BotoCoreError) as e:
self.module.fail_json_aws(e, msg="Error fetching policy information")
def create_response_header_policy(self, name, comment, cors_config, security_headers_config, custom_headers_config):
@@ -182,17 +182,17 @@ class CloudfrontResponseHeadersPolicyService(object):
security_headers_config = snake_dict_to_camel_dict(security_headers_config, capitalize_first=True)
# Little helper for turning xss_protection into XSSProtection and not into XssProtection
- if 'XssProtection' in security_headers_config:
- security_headers_config['XSSProtection'] = security_headers_config.pop('XssProtection')
+ if "XssProtection" in security_headers_config:
+ security_headers_config["XSSProtection"] = security_headers_config.pop("XssProtection")
custom_headers_config = snake_dict_to_camel_dict(custom_headers_config, capitalize_first=True)
config = {
- 'Name': name,
- 'Comment': comment,
- 'CorsConfig': self.insert_quantities(cors_config),
- 'SecurityHeadersConfig': security_headers_config,
- 'CustomHeadersConfig': self.insert_quantities(custom_headers_config)
+ "Name": name,
+ "Comment": comment,
+ "CorsConfig": self.insert_quantities(cors_config),
+ "SecurityHeadersConfig": security_headers_config,
+ "CustomHeadersConfig": self.insert_quantities(custom_headers_config),
}
config = {k: v for k, v in config.items() if v}
@@ -208,22 +208,24 @@ class CloudfrontResponseHeadersPolicyService(object):
try:
result = self.client.create_response_headers_policy(ResponseHeadersPolicyConfig=config)
changed = True
- except (ParamValidationError, ClientError, BotoCoreError) as e:
+ except (ClientError, BotoCoreError) as e:
self.module.fail_json_aws(e, msg="Error creating policy")
else:
- policy_id = matching_policy['ResponseHeadersPolicy']['Id']
- etag = matching_policy['ETag']
+ policy_id = matching_policy["ResponseHeadersPolicy"]["Id"]
+ etag = matching_policy["ETag"]
try:
- result = self.client.update_response_headers_policy(Id=policy_id, IfMatch=etag, ResponseHeadersPolicyConfig=config)
+ result = self.client.update_response_headers_policy(
+ Id=policy_id, IfMatch=etag, ResponseHeadersPolicyConfig=config
+ )
- changed_time = result['ResponseHeadersPolicy']['LastModifiedTime']
+ changed_time = result["ResponseHeadersPolicy"]["LastModifiedTime"]
seconds = 3 # threshhold for returned timestamp age
- seconds_ago = (datetime.datetime.now(changed_time.tzinfo) - datetime.timedelta(0, seconds))
+ seconds_ago = datetime.datetime.now(changed_time.tzinfo) - datetime.timedelta(0, seconds)
# consider change made by this execution of the module if returned timestamp was very recent
if changed_time > seconds_ago:
changed = True
- except (ParamValidationError, ClientError, BotoCoreError) as e:
+ except (ClientError, BotoCoreError) as e:
self.module.fail_json_aws(e, msg="Updating creating policy")
self.module.exit_json(changed=changed, **camel_dict_to_snake_dict(result))
@@ -234,14 +236,14 @@ class CloudfrontResponseHeadersPolicyService(object):
if matching_policy is None:
self.module.exit_json(msg="Didn't find a matching policy by that name, not deleting")
else:
- policy_id = matching_policy['ResponseHeadersPolicy']['Id']
- etag = matching_policy['ETag']
+ policy_id = matching_policy["ResponseHeadersPolicy"]["Id"]
+ etag = matching_policy["ETag"]
if self.check_mode:
result = {}
else:
try:
result = self.client.delete_response_headers_policy(Id=policy_id, IfMatch=etag)
- except (ParamValidationError, ClientError, BotoCoreError) as e:
+ except (ClientError, BotoCoreError) as e:
self.module.fail_json_aws(e, msg="Error deleting policy")
self.module.exit_json(changed=True, **camel_dict_to_snake_dict(result))
@@ -250,43 +252,45 @@ class CloudfrontResponseHeadersPolicyService(object):
@staticmethod
def insert_quantities(dict_with_items):
# Items on top level case
- if 'Items' in dict_with_items and isinstance(dict_with_items['Items'], list):
- dict_with_items['Quantity'] = len(dict_with_items['Items'])
+ if "Items" in dict_with_items and isinstance(dict_with_items["Items"], list):
+ dict_with_items["Quantity"] = len(dict_with_items["Items"])
# Items on second level case
for k, v in dict_with_items.items():
- if isinstance(v, dict) and 'Items' in v:
- v['Quantity'] = len(v['Items'])
+ if isinstance(v, dict) and "Items" in v:
+ v["Quantity"] = len(v["Items"])
return dict_with_items
def main():
argument_spec = dict(
- name=dict(required=True, type='str'),
- comment=dict(type='str'),
- cors_config=dict(type='dict', default=dict()),
- security_headers_config=dict(type='dict', default=dict()),
- custom_headers_config=dict(type='dict', default=dict()),
- state=dict(choices=['present', 'absent'], type='str', default='present'),
+ name=dict(required=True, type="str"),
+ comment=dict(type="str"),
+ cors_config=dict(type="dict", default=dict()),
+ security_headers_config=dict(type="dict", default=dict()),
+ custom_headers_config=dict(type="dict", default=dict()),
+ state=dict(choices=["present", "absent"], type="str", default="present"),
)
module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
- name = module.params.get('name')
- comment = module.params.get('comment', '')
- cors_config = module.params.get('cors_config')
- security_headers_config = module.params.get('security_headers_config')
- custom_headers_config = module.params.get('custom_headers_config')
- state = module.params.get('state')
+ name = module.params.get("name")
+ comment = module.params.get("comment", "")
+ cors_config = module.params.get("cors_config")
+ security_headers_config = module.params.get("security_headers_config")
+ custom_headers_config = module.params.get("custom_headers_config")
+ state = module.params.get("state")
service = CloudfrontResponseHeadersPolicyService(module)
- if state == 'absent':
+ if state == "absent":
service.delete_response_header_policy(name)
else:
- service.create_response_header_policy(name, comment, cors_config, security_headers_config, custom_headers_config)
+ service.create_response_header_policy(
+ name, comment, cors_config, security_headers_config, custom_headers_config
+ )
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/codebuild_project.py b/ansible_collections/community/aws/plugins/modules/codebuild_project.py
index 873b74010..1f4630f73 100644
--- a/ansible_collections/community/aws/plugins/modules/codebuild_project.py
+++ b/ansible_collections/community/aws/plugins/modules/codebuild_project.py
@@ -1,19 +1,17 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: codebuild_project
version_added: 1.0.0
short_description: Create or delete an AWS CodeBuild project
notes:
- For details of the parameters and returns see U(http://boto3.readthedocs.io/en/latest/reference/services/codebuild.html).
+ - I(tags) changed from boto3 format to standard dict format in release 6.0.0.
description:
- Create or delete a CodeBuild projects on AWS, used for building code artifacts from source code.
- Prior to release 5.0.0 this module was called C(community.aws.aws_codebuild).
@@ -137,23 +135,6 @@ options:
description:
- The AWS Key Management Service (AWS KMS) customer master key (CMK) to be used for encrypting the build output artifacts.
type: str
- tags:
- description:
- - A set of tags for the build project.
- - Mutually exclusive with the I(resource_tags) parameter.
- - In release 6.0.0 this parameter will accept a simple dictionary
- instead of the list of dictionaries format. To use the simple
- dictionary format prior to release 6.0.0 the I(resource_tags) can
- be used instead of I(tags).
- type: list
- elements: dict
- suboptions:
- key:
- description: The name of the Tag.
- type: str
- value:
- description: The value of the Tag.
- type: str
vpc_config:
description:
- The VPC config enables AWS CodeBuild to access resources in an Amazon VPC.
@@ -164,35 +145,15 @@ options:
default: 'present'
choices: ['present', 'absent']
type: str
- resource_tags:
- description:
- - A dictionary representing the tags to be applied to the build project.
- - If the I(resource_tags) parameter is not set then tags will not be modified.
- - Mutually exclusive with the I(tags) parameter.
- type: dict
- required: false
- purge_tags:
- description:
- - If I(purge_tags=true) and I(tags) is set, existing tags will be purged
- from the resource to match exactly what is defined by I(tags) parameter.
- - If the I(resource_tags) parameter is not set then tags will not be modified, even
- if I(purge_tags=True).
- - Tag keys beginning with C(aws:) are reserved by Amazon and can not be
- modified. As such they will be ignored for the purposes of the
- I(purge_tags) parameter. See the Amazon documentation for more information
- U(https://docs.aws.amazon.com/general/latest/gr/aws_tagging.html#tag-conventions).
- type: bool
- default: true
- required: false
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
- - amazon.aws.boto3
+ - amazon.aws.boto3.modules
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.tags.modules
+"""
-'''
-
-EXAMPLES = r'''
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide for details.
- community.aws.codebuild_project:
@@ -200,27 +161,28 @@ EXAMPLES = r'''
description: My nice little project
service_role: "arn:aws:iam::123123:role/service-role/code-build-service-role"
source:
- # Possible values: BITBUCKET, CODECOMMIT, CODEPIPELINE, GITHUB, S3
- type: CODEPIPELINE
- buildspec: ''
+ # Possible values: BITBUCKET, CODECOMMIT, CODEPIPELINE, GITHUB, S3
+ type: CODEPIPELINE
+ buildspec: ''
artifacts:
- namespaceType: NONE
- packaging: NONE
- type: CODEPIPELINE
- name: my_project
+ namespaceType: NONE
+ packaging: NONE
+ type: CODEPIPELINE
+ name: my_project
environment:
- computeType: BUILD_GENERAL1_SMALL
- privilegedMode: "true"
- image: "aws/codebuild/docker:17.09.0"
- type: LINUX_CONTAINER
- environmentVariables:
- - { name: 'PROFILE', value: 'staging' }
+ computeType: BUILD_GENERAL1_SMALL
+ privilegedMode: "true"
+ image: "aws/codebuild/docker:17.09.0"
+ type: LINUX_CONTAINER
+ environmentVariables:
+ - name: 'PROFILE'
+ value: 'staging'
encryption_key: "arn:aws:kms:us-east-1:123123:alias/aws/s3"
region: us-east-1
state: present
-'''
+"""
-RETURN = r'''
+RETURN = r"""
project:
description: Returns the dictionary describing the code project configuration.
returned: success
@@ -324,118 +286,162 @@ project:
returned: always
type: str
sample: "2018-04-17T16:56:03.245000+02:00"
-'''
+"""
+
+try:
+ import botocore
+except ImportError:
+ pass # Handled by AnsibleAWSModule
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
from ansible.module_utils.common.dict_transformations import snake_dict_to_camel_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import get_boto3_client_method_parameters
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import get_boto3_client_method_parameters
+from ansible_collections.amazon.aws.plugins.module_utils.exceptions import AnsibleAWSError
from ansible_collections.amazon.aws.plugins.module_utils.tagging import ansible_dict_to_boto3_tag_list
from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
-try:
- import botocore
-except ImportError:
- pass # Handled by AnsibleAWSModule
+class CodeBuildAnsibleAWSError(AnsibleAWSError):
+ pass
-def create_or_update_project(client, params, module):
- resp = {}
- name = params['name']
- # clean up params
- formatted_params = snake_dict_to_camel_dict(dict((k, v) for k, v in params.items() if v is not None))
- permitted_create_params = get_boto3_client_method_parameters(client, 'create_project')
- permitted_update_params = get_boto3_client_method_parameters(client, 'update_project')
- formatted_create_params = dict((k, v) for k, v in formatted_params.items() if k in permitted_create_params)
- formatted_update_params = dict((k, v) for k, v in formatted_params.items() if k in permitted_update_params)
+def do_create_project(client, params, formatted_params):
+ if params["source"] is None or params["artifacts"] is None:
+ raise CodeBuildAnsibleAWSError(
+ message="The source and artifacts parameters must be provided when creating a new project. No existing project was found."
+ )
- # Check if project with that name already exists and if so update existing:
- found = describe_project(client=client, name=name, module=module)
- changed = False
+ if params["tags"] is not None:
+ formatted_params["tags"] = ansible_dict_to_boto3_tag_list(
+ params["tags"], tag_name_key_name="key", tag_value_key_name="value"
+ )
+
+ permitted_create_params = get_boto3_client_method_parameters(client, "create_project")
+ formatted_create_params = dict((k, v) for k, v in formatted_params.items() if k in permitted_create_params)
- if 'name' in found:
- found_project = found
- found_tags = found_project.pop('tags', [])
- # Support tagging using a dict instead of the list of dicts
- if params['resource_tags'] is not None:
- if params['purge_tags']:
- tags = dict()
- else:
- tags = boto3_tag_list_to_ansible_dict(found_tags)
- tags.update(params['resource_tags'])
- formatted_update_params['tags'] = ansible_dict_to_boto3_tag_list(tags, tag_name_key_name='key', tag_value_key_name='value')
-
- resp = update_project(client=client, params=formatted_update_params, module=module)
- updated_project = resp['project']
-
- # Prep both dicts for sensible change comparison:
- found_project.pop('lastModified')
- updated_project.pop('lastModified')
- updated_tags = updated_project.pop('tags', [])
- found_project['ResourceTags'] = boto3_tag_list_to_ansible_dict(found_tags)
- updated_project['ResourceTags'] = boto3_tag_list_to_ansible_dict(updated_tags)
-
- if updated_project != found_project:
- changed = True
- updated_project['tags'] = updated_tags
- return resp, changed
# Or create new project:
try:
- if params['source'] is None or params['artifacts'] is None:
- module.fail_json(
- "The source and artifacts parameters must be provided when "
- "creating a new project. No existing project was found.")
resp = client.create_project(**formatted_create_params)
changed = True
return resp, changed
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Unable to create CodeBuild project")
+ raise CodeBuildAnsibleAWSError(
+ message="Unable to create CodeBuild project",
+ exception=e,
+ )
+
+
+def merge_tags(found_tags, tags, purge_tags):
+ if purge_tags:
+ return tags
+
+ merged_tags = boto3_tag_list_to_ansible_dict(found_tags)
+ merged_tags.update(tags)
+ return merged_tags
+
+
+def format_tags(tags):
+ return ansible_dict_to_boto3_tag_list(
+ tags,
+ tag_name_key_name="key",
+ tag_value_key_name="value",
+ )
+
+
+def do_update_project(client, params, formatted_params, found_project):
+ permitted_update_params = get_boto3_client_method_parameters(client, "update_project")
+ formatted_update_params = dict((k, v) for k, v in formatted_params.items() if k in permitted_update_params)
+
+ found_tags = found_project.pop("tags", [])
+ if params["tags"] is not None:
+ formatted_update_params["tags"] = format_tags(
+ merge_tags(found_tags, params["tags"], params["purge_tags"]),
+ )
+
+ resp = update_project(client=client, params=formatted_update_params)
+ updated_project = resp["project"]
+
+ # Prep both dicts for sensible change comparison:
+ found_project.pop("lastModified")
+ updated_project.pop("lastModified")
+ updated_tags = updated_project.pop("tags", [])
+ found_project["ResourceTags"] = boto3_tag_list_to_ansible_dict(found_tags)
+ updated_project["ResourceTags"] = boto3_tag_list_to_ansible_dict(updated_tags)
+
+ changed = updated_project != found_project
+
+ updated_project["tags"] = updated_tags
+ return resp, changed
-def update_project(client, params, module):
- name = params['name']
+def create_or_update_project(client, params):
+ resp = {}
+ name = params["name"]
+ # clean up params
+ formatted_params = snake_dict_to_camel_dict(dict((k, v) for k, v in params.items() if v is not None))
+
+ # Check if project with that name already exists and if so update existing:
+ found = describe_project(client=client, name=name)
+ changed = False
+
+ if "name" not in found:
+ return do_create_project(client, params, formatted_params)
+
+ return do_update_project(client, params, formatted_params, found)
+
+
+def update_project(client, params):
+ name = params["name"]
try:
resp = client.update_project(**params)
return resp
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Unable to update CodeBuild project")
+ raise CodeBuildAnsibleAWSError(
+ message="Unable to update CodeBuild project",
+ exception=e,
+ )
-def delete_project(client, name, module):
- found = describe_project(client=client, name=name, module=module)
- changed = False
- if 'name' in found:
- # Mark as changed when a project with that name existed before calling delete
- changed = True
+def delete_project(client, name):
+ found = describe_project(client=client, name=name)
+ if "name" not in found:
+ return {}, False
+
try:
resp = client.delete_project(name=name)
- return resp, changed
+ return resp, True
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Unable to delete CodeBuild project")
+ raise CodeBuildAnsibleAWSError(
+ message="Unable to update CodeBuild project",
+ exception=e,
+ )
-def describe_project(client, name, module):
+def describe_project(client, name):
project = {}
try:
- projects = client.batch_get_projects(names=[name])['projects']
+ projects = client.batch_get_projects(names=[name])["projects"]
if len(projects) > 0:
project = projects[0]
return project
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Unable to describe CodeBuild projects")
+ raise CodeBuildAnsibleAWSError(
+ message="Unable to describe CodeBuild projects",
+ exception=e,
+ )
def format_project_result(project_result):
formated_result = camel_dict_to_snake_dict(project_result)
- project = project_result.get('project', {})
+ project = project_result.get("project", {})
if project:
- tags = project.get('tags', [])
- formated_result['project']['resource_tags'] = boto3_tag_list_to_ansible_dict(tags)
- formated_result['ORIGINAL'] = project_result
+ tags = project.get("tags", [])
+ formated_result["project"]["resource_tags"] = boto3_tag_list_to_ansible_dict(tags)
+ formated_result["ORIGINAL"] = project_result
return formated_result
@@ -443,46 +449,44 @@ def main():
argument_spec = dict(
name=dict(required=True),
description=dict(),
- source=dict(type='dict'),
- artifacts=dict(type='dict'),
- cache=dict(type='dict'),
- environment=dict(type='dict'),
+ source=dict(type="dict"),
+ artifacts=dict(type="dict"),
+ cache=dict(type="dict"),
+ environment=dict(type="dict"),
service_role=dict(),
- timeout_in_minutes=dict(type='int', default=60),
+ timeout_in_minutes=dict(type="int", default=60),
encryption_key=dict(no_log=False),
- tags=dict(type='list', elements='dict'),
- resource_tags=dict(type='dict'),
- purge_tags=dict(type='bool', default=True),
- vpc_config=dict(type='dict'),
- state=dict(choices=['present', 'absent'], default='present')
+ tags=dict(type="dict", aliases=["resource_tags"]),
+ purge_tags=dict(type="bool", default=True),
+ vpc_config=dict(type="dict"),
+ state=dict(choices=["present", "absent"], default="present"),
)
module = AnsibleAWSModule(argument_spec=argument_spec)
- client_conn = module.client('codebuild')
+ client_conn = module.client("codebuild")
- state = module.params.get('state')
+ state = module.params.get("state")
changed = False
- if module.params['tags']:
- module.deprecate(
- 'The tags parameter currently uses a non-standard format and has '
- 'been deprecated. In release 6.0.0 this paramater will accept '
- 'a simple key/value pair dictionary instead of the current list '
- 'of dictionaries. It is recommended to migrate to using the '
- 'resource_tags parameter which already accepts the simple dictionary '
- 'format.', version='6.0.0', collection_name='community.aws')
-
- if state == 'present':
- project_result, changed = create_or_update_project(
- client=client_conn,
- params=module.params,
- module=module)
- elif state == 'absent':
- project_result, changed = delete_project(client=client_conn, name=module.params['name'], module=module)
+ try:
+ if state == "present":
+ project_result, changed = create_or_update_project(
+ client=client_conn,
+ params=module.params,
+ )
+ elif state == "absent":
+ project_result, changed = delete_project(
+ client=client_conn,
+ name=module.params["name"],
+ )
+ except CodeBuildAnsibleAWSError as e:
+ if e.exception:
+ module.fail_json_aws(e.exception, msg=e.message)
+ module.fail_json(msg=e.message)
formatted_result = format_project_result(project_result)
module.exit_json(changed=changed, **formatted_result)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/codecommit_repository.py b/ansible_collections/community/aws/plugins/modules/codecommit_repository.py
index fce4d15d6..14b08bd88 100644
--- a/ansible_collections/community/aws/plugins/modules/codecommit_repository.py
+++ b/ansible_collections/community/aws/plugins/modules/codecommit_repository.py
@@ -1,13 +1,10 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
+
# Copyright: (c) 2018, Shuang Wang <ooocamel@icloud.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: codecommit_repository
version_added: 1.0.0
@@ -17,7 +14,8 @@ description:
- See U(https://aws.amazon.com/codecommit/) for more information about CodeCommit.
- Prior to release 5.0.0 this module was called C(community.aws.aws_codecommit).
The usage did not change.
-author: Shuang Wang (@ptux)
+author:
+ - Shuang Wang (@ptux)
options:
name:
description:
@@ -39,12 +37,12 @@ options:
choices: [ 'present', 'absent' ]
type: str
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-RETURN = '''
+RETURN = r"""
repository_metadata:
description: "Information about the repository."
returned: always
@@ -120,9 +118,9 @@ response_metadata:
returned: always
type: str
sample: "0"
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
# Create a new repository
- community.aws.codecommit_repository:
name: repo
@@ -132,53 +130,54 @@ EXAMPLES = '''
- community.aws.codecommit_repository:
name: repo
state: absent
-'''
+"""
try:
import botocore
except ImportError:
pass # Handled by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
class CodeCommit(object):
def __init__(self, module=None):
self._module = module
- self._client = self._module.client('codecommit')
+ self._client = self._module.client("codecommit")
self._check_mode = self._module.check_mode
def process(self):
result = dict(changed=False)
- if self._module.params['state'] == 'present':
+ if self._module.params["state"] == "present":
if not self._repository_exists():
if not self._check_mode:
result = self._create_repository()
- result['changed'] = True
+ result["changed"] = True
else:
- metadata = self._get_repository()['repositoryMetadata']
- if not metadata.get('repositoryDescription'):
- metadata['repositoryDescription'] = ''
- if metadata['repositoryDescription'] != self._module.params['description']:
+ metadata = self._get_repository()["repositoryMetadata"]
+ if not metadata.get("repositoryDescription"):
+ metadata["repositoryDescription"] = ""
+ if metadata["repositoryDescription"] != self._module.params["description"]:
if not self._check_mode:
self._update_repository()
- result['changed'] = True
+ result["changed"] = True
result.update(self._get_repository())
- if self._module.params['state'] == 'absent' and self._repository_exists():
+ if self._module.params["state"] == "absent" and self._repository_exists():
if not self._check_mode:
result = self._delete_repository()
- result['changed'] = True
+ result["changed"] = True
return result
def _repository_exists(self):
try:
- paginator = self._client.get_paginator('list_repositories')
+ paginator = self._client.get_paginator("list_repositories")
for page in paginator.paginate():
- repositories = page['repositories']
+ repositories = page["repositories"]
for item in repositories:
- if self._module.params['name'] in item.values():
+ if self._module.params["name"] in item.values():
return True
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
self._module.fail_json_aws(e, msg="couldn't get repository")
@@ -187,7 +186,7 @@ class CodeCommit(object):
def _get_repository(self):
try:
result = self._client.get_repository(
- repositoryName=self._module.params['name']
+ repositoryName=self._module.params["name"],
)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
self._module.fail_json_aws(e, msg="couldn't get repository")
@@ -196,8 +195,8 @@ class CodeCommit(object):
def _update_repository(self):
try:
result = self._client.update_repository_description(
- repositoryName=self._module.params['name'],
- repositoryDescription=self._module.params['description']
+ repositoryName=self._module.params["name"],
+ repositoryDescription=self._module.params["description"],
)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
self._module.fail_json_aws(e, msg="couldn't create repository")
@@ -206,8 +205,8 @@ class CodeCommit(object):
def _create_repository(self):
try:
result = self._client.create_repository(
- repositoryName=self._module.params['name'],
- repositoryDescription=self._module.params['description']
+ repositoryName=self._module.params["name"],
+ repositoryDescription=self._module.params["description"],
)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
self._module.fail_json_aws(e, msg="couldn't create repository")
@@ -216,7 +215,7 @@ class CodeCommit(object):
def _delete_repository(self):
try:
result = self._client.delete_repository(
- repositoryName=self._module.params['name']
+ repositoryName=self._module.params["name"],
)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
self._module.fail_json_aws(e, msg="couldn't delete repository")
@@ -226,13 +225,13 @@ class CodeCommit(object):
def main():
argument_spec = dict(
name=dict(required=True),
- state=dict(choices=['present', 'absent'], required=True),
- description=dict(default='', aliases=['comment'])
+ state=dict(choices=["present", "absent"], required=True),
+ description=dict(default="", aliases=["comment"]),
)
ansible_aws_module = AnsibleAWSModule(
argument_spec=argument_spec,
- supports_check_mode=True
+ supports_check_mode=True,
)
aws_codecommit = CodeCommit(module=ansible_aws_module)
@@ -240,5 +239,5 @@ def main():
ansible_aws_module.exit_json(**camel_dict_to_snake_dict(result))
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/codepipeline.py b/ansible_collections/community/aws/plugins/modules/codepipeline.py
index 5c5935cb9..b1fe60476 100644
--- a/ansible_collections/community/aws/plugins/modules/codepipeline.py
+++ b/ansible_collections/community/aws/plugins/modules/codepipeline.py
@@ -1,13 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: codepipeline
version_added: 1.0.0
@@ -75,16 +72,16 @@ options:
choices: ['present', 'absent']
type: str
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide for details.
# Example for creating a pipeline for continuous deploy of Github code to an ECS cluster (container)
-- community.aws.aws_codepipeline:
+- community.aws.codepipeline:
name: my_deploy_pipeline
role_arn: arn:aws:iam::123456:role/AWS-CodePipeline-Service
artifact_store:
@@ -147,9 +144,9 @@ EXAMPLES = r'''
FileName: imagedefinitions.json
region: us-east-1
state: present
-'''
+"""
-RETURN = r'''
+RETURN = r"""
pipeline:
description: Returns the dictionary describing the CodePipeline configuration.
returned: success
@@ -194,7 +191,7 @@ pipeline:
- This number is auto incremented when CodePipeline params are changed.
returned: always
type: int
-'''
+"""
import copy
@@ -205,20 +202,21 @@ except ImportError:
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import compare_policies
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.policy import compare_policies
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def create_pipeline(client, name, role_arn, artifact_store, stages, version, module):
- pipeline_dict = {'name': name, 'roleArn': role_arn, 'artifactStore': artifact_store, 'stages': stages}
+ pipeline_dict = {"name": name, "roleArn": role_arn, "artifactStore": artifact_store, "stages": stages}
if version:
- pipeline_dict['version'] = version
+ pipeline_dict["version"] = version
try:
resp = client.create_pipeline(pipeline=pipeline_dict)
return resp
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Unable create pipeline {0}".format(pipeline_dict['name']))
+ module.fail_json_aws(e, msg=f"Unable create pipeline {pipeline_dict['name']}")
def update_pipeline(client, pipeline_dict, module):
@@ -226,7 +224,7 @@ def update_pipeline(client, pipeline_dict, module):
resp = client.update_pipeline(pipeline=pipeline_dict)
return resp
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Unable update pipeline {0}".format(pipeline_dict['name']))
+ module.fail_json_aws(e, msg=f"Unable update pipeline {pipeline_dict['name']}")
def delete_pipeline(client, name, module):
@@ -234,7 +232,7 @@ def delete_pipeline(client, name, module):
resp = client.delete_pipeline(name=name)
return resp
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Unable delete pipeline {0}".format(name))
+ module.fail_json_aws(e, msg=f"Unable delete pipeline {name}")
def describe_pipeline(client, name, version, module):
@@ -246,63 +244,69 @@ def describe_pipeline(client, name, version, module):
else:
pipeline = client.get_pipeline(name=name)
return pipeline
- except is_boto3_error_code('PipelineNotFoundException'):
+ except is_boto3_error_code("PipelineNotFoundException"):
return pipeline
- except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e: # pylint: disable=duplicate-except
+ except (
+ botocore.exceptions.BotoCoreError,
+ botocore.exceptions.ClientError,
+ ) as e: # pylint: disable=duplicate-except
module.fail_json_aws(e)
def main():
argument_spec = dict(
- name=dict(required=True, type='str'),
- role_arn=dict(required=True, type='str'),
- artifact_store=dict(required=True, type='dict'),
- stages=dict(required=True, type='list', elements='dict'),
- version=dict(type='int'),
- state=dict(choices=['present', 'absent'], default='present')
+ name=dict(required=True, type="str"),
+ role_arn=dict(required=True, type="str"),
+ artifact_store=dict(required=True, type="dict"),
+ stages=dict(required=True, type="list", elements="dict"),
+ version=dict(type="int"),
+ state=dict(choices=["present", "absent"], default="present"),
)
module = AnsibleAWSModule(argument_spec=argument_spec)
- client_conn = module.client('codepipeline')
+ client_conn = module.client("codepipeline")
- state = module.params.get('state')
+ state = module.params.get("state")
changed = False
# Determine if the CodePipeline exists
- found_code_pipeline = describe_pipeline(client=client_conn, name=module.params['name'], version=module.params['version'], module=module)
+ found_code_pipeline = describe_pipeline(
+ client=client_conn, name=module.params["name"], version=module.params["version"], module=module
+ )
pipeline_result = {}
- if state == 'present':
- if 'pipeline' in found_code_pipeline:
- pipeline_dict = copy.deepcopy(found_code_pipeline['pipeline'])
+ if state == "present":
+ if "pipeline" in found_code_pipeline:
+ pipeline_dict = copy.deepcopy(found_code_pipeline["pipeline"])
# Update dictionary with provided module params:
- pipeline_dict['roleArn'] = module.params['role_arn']
- pipeline_dict['artifactStore'] = module.params['artifact_store']
- pipeline_dict['stages'] = module.params['stages']
- if module.params['version'] is not None:
- pipeline_dict['version'] = module.params['version']
+ pipeline_dict["roleArn"] = module.params["role_arn"]
+ pipeline_dict["artifactStore"] = module.params["artifact_store"]
+ pipeline_dict["stages"] = module.params["stages"]
+ if module.params["version"] is not None:
+ pipeline_dict["version"] = module.params["version"]
pipeline_result = update_pipeline(client=client_conn, pipeline_dict=pipeline_dict, module=module)
- if compare_policies(found_code_pipeline['pipeline'], pipeline_result['pipeline']):
+ if compare_policies(found_code_pipeline["pipeline"], pipeline_result["pipeline"]):
changed = True
else:
pipeline_result = create_pipeline(
client=client_conn,
- name=module.params['name'],
- role_arn=module.params['role_arn'],
- artifact_store=module.params['artifact_store'],
- stages=module.params['stages'],
- version=module.params['version'],
- module=module)
+ name=module.params["name"],
+ role_arn=module.params["role_arn"],
+ artifact_store=module.params["artifact_store"],
+ stages=module.params["stages"],
+ version=module.params["version"],
+ module=module,
+ )
changed = True
- elif state == 'absent':
+ elif state == "absent":
if found_code_pipeline:
- pipeline_result = delete_pipeline(client=client_conn, name=module.params['name'], module=module)
+ pipeline_result = delete_pipeline(client=client_conn, name=module.params["name"], module=module)
changed = True
module.exit_json(changed=changed, **camel_dict_to_snake_dict(pipeline_result))
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/config_aggregation_authorization.py b/ansible_collections/community/aws/plugins/modules/config_aggregation_authorization.py
index 7b92abb7f..903d5a5e1 100644
--- a/ansible_collections/community/aws/plugins/modules/config_aggregation_authorization.py
+++ b/ansible_collections/community/aws/plugins/modules/config_aggregation_authorization.py
@@ -1,13 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
# Copyright: (c) 2018, Aaron Smith <ajsmith10381@gmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: config_aggregation_authorization
version_added: 1.0.0
@@ -36,12 +33,12 @@ options:
type: str
required: true
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
- name: Get current account ID
community.aws.aws_caller_info:
register: whoami
@@ -49,26 +46,26 @@ EXAMPLES = '''
state: present
authorized_account_id: '{{ whoami.account }}'
authorized_aws_region: us-east-1
-'''
-
-RETURN = '''#'''
+"""
+RETURN = r"""#"""
try:
import botocore
except ImportError:
pass # handled by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def resource_exists(client, module, params):
try:
- current_authorizations = client.describe_aggregation_authorizations()['AggregationAuthorizations']
+ current_authorizations = client.describe_aggregation_authorizations()["AggregationAuthorizations"]
authorization_exists = next(
- (item for item in current_authorizations if item["AuthorizedAccountId"] == params['AuthorizedAccountId']),
- None
+ (item for item in current_authorizations if item["AuthorizedAccountId"] == params["AuthorizedAccountId"]),
+ None,
)
if authorization_exists:
return True
@@ -79,32 +76,32 @@ def resource_exists(client, module, params):
def create_resource(client, module, params, result):
try:
response = client.put_aggregation_authorization(
- AuthorizedAccountId=params['AuthorizedAccountId'],
- AuthorizedAwsRegion=params['AuthorizedAwsRegion']
+ AuthorizedAccountId=params["AuthorizedAccountId"],
+ AuthorizedAwsRegion=params["AuthorizedAwsRegion"],
)
- result['changed'] = True
+ result["changed"] = True
return result
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Couldn't create AWS Aggregation authorization")
def update_resource(client, module, params, result):
- current_authorizations = client.describe_aggregation_authorizations()['AggregationAuthorizations']
+ current_authorizations = client.describe_aggregation_authorizations()["AggregationAuthorizations"]
current_params = next(
- (item for item in current_authorizations if item["AuthorizedAccountId"] == params['AuthorizedAccountId']),
- None
+ (item for item in current_authorizations if item["AuthorizedAccountId"] == params["AuthorizedAccountId"]),
+ None,
)
- del current_params['AggregationAuthorizationArn']
- del current_params['CreationTime']
+ del current_params["AggregationAuthorizationArn"]
+ del current_params["CreationTime"]
if params != current_params:
try:
response = client.put_aggregation_authorization(
- AuthorizedAccountId=params['AuthorizedAccountId'],
- AuthorizedAwsRegion=params['AuthorizedAwsRegion']
+ AuthorizedAccountId=params["AuthorizedAccountId"],
+ AuthorizedAwsRegion=params["AuthorizedAwsRegion"],
)
- result['changed'] = True
+ result["changed"] = True
return result
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Couldn't create AWS Aggregation authorization")
@@ -113,10 +110,10 @@ def update_resource(client, module, params, result):
def delete_resource(client, module, params, result):
try:
response = client.delete_aggregation_authorization(
- AuthorizedAccountId=params['AuthorizedAccountId'],
- AuthorizedAwsRegion=params['AuthorizedAwsRegion']
+ AuthorizedAccountId=params["AuthorizedAccountId"],
+ AuthorizedAwsRegion=params["AuthorizedAwsRegion"],
)
- result['changed'] = True
+ result["changed"] = True
return result
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Couldn't delete AWS Aggregation authorization")
@@ -125,35 +122,35 @@ def delete_resource(client, module, params, result):
def main():
module = AnsibleAWSModule(
argument_spec={
- 'state': dict(type='str', choices=['present', 'absent'], default='present'),
- 'authorized_account_id': dict(type='str', required=True),
- 'authorized_aws_region': dict(type='str', required=True),
+ "state": dict(type="str", choices=["present", "absent"], default="present"),
+ "authorized_account_id": dict(type="str", required=True),
+ "authorized_aws_region": dict(type="str", required=True),
},
supports_check_mode=False,
)
- result = {'changed': False}
+ result = {"changed": False}
params = {
- 'AuthorizedAccountId': module.params.get('authorized_account_id'),
- 'AuthorizedAwsRegion': module.params.get('authorized_aws_region'),
+ "AuthorizedAccountId": module.params.get("authorized_account_id"),
+ "AuthorizedAwsRegion": module.params.get("authorized_aws_region"),
}
- client = module.client('config', retry_decorator=AWSRetry.jittered_backoff())
+ client = module.client("config", retry_decorator=AWSRetry.jittered_backoff())
resource_status = resource_exists(client, module, params)
- if module.params.get('state') == 'present':
+ if module.params.get("state") == "present":
if not resource_status:
create_resource(client, module, params, result)
else:
update_resource(client, module, params, result)
- if module.params.get('state') == 'absent':
+ if module.params.get("state") == "absent":
if resource_status:
delete_resource(client, module, params, result)
- module.exit_json(changed=result['changed'])
+ module.exit_json(changed=result["changed"])
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/config_aggregator.py b/ansible_collections/community/aws/plugins/modules/config_aggregator.py
index 3dc4c6faa..48771080b 100644
--- a/ansible_collections/community/aws/plugins/modules/config_aggregator.py
+++ b/ansible_collections/community/aws/plugins/modules/config_aggregator.py
@@ -1,13 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
# Copyright: (c) 2018, Aaron Smith <ajsmith10381@gmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: config_aggregator
version_added: 1.0.0
@@ -71,25 +68,25 @@ options:
type: dict
required: true
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
- name: Create cross-account aggregator
community.aws.config_aggregator:
name: test_config_rule
state: present
account_sources:
account_ids:
- - 1234567890
- - 0123456789
- - 9012345678
+ - 1234567890
+ - 0123456789
+ - 9012345678
all_aws_regions: true
-'''
+"""
-RETURN = r'''#'''
+RETURN = r"""#"""
try:
@@ -97,57 +94,64 @@ try:
except ImportError:
pass # handled by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule, is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry, camel_dict_to_snake_dict
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def resource_exists(client, module, params):
try:
aggregator = client.describe_configuration_aggregators(
- ConfigurationAggregatorNames=[params['ConfigurationAggregatorName']]
+ ConfigurationAggregatorNames=[params["ConfigurationAggregatorName"]]
)
- return aggregator['ConfigurationAggregators'][0]
- except is_boto3_error_code('NoSuchConfigurationAggregatorException'):
+ return aggregator["ConfigurationAggregators"][0]
+ except is_boto3_error_code("NoSuchConfigurationAggregatorException"):
return
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
module.fail_json_aws(e)
def create_resource(client, module, params, result):
try:
client.put_configuration_aggregator(
- ConfigurationAggregatorName=params['ConfigurationAggregatorName'],
- AccountAggregationSources=params['AccountAggregationSources'],
- OrganizationAggregationSource=params['OrganizationAggregationSource']
+ ConfigurationAggregatorName=params["ConfigurationAggregatorName"],
+ AccountAggregationSources=params["AccountAggregationSources"],
+ OrganizationAggregationSource=params["OrganizationAggregationSource"],
)
- result['changed'] = True
- result['aggregator'] = camel_dict_to_snake_dict(resource_exists(client, module, params))
+ result["changed"] = True
+ result["aggregator"] = camel_dict_to_snake_dict(resource_exists(client, module, params))
return result
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Couldn't create AWS Config configuration aggregator")
def update_resource(client, module, params, result):
- result['changed'] = False
+ result["changed"] = False
current_params = client.describe_configuration_aggregators(
- ConfigurationAggregatorNames=[params['ConfigurationAggregatorName']]
- )['ConfigurationAggregators'][0]
+ ConfigurationAggregatorNames=[params["ConfigurationAggregatorName"]]
+ )["ConfigurationAggregators"][0]
- if params['AccountAggregationSources'] != current_params.get('AccountAggregationSources', []):
- result['changed'] = True
+ if params["AccountAggregationSources"] != current_params.get("AccountAggregationSources", []):
+ result["changed"] = True
- if params['OrganizationAggregationSource'] != current_params.get('OrganizationAggregationSource', {}):
- result['changed'] = True
+ if params["OrganizationAggregationSource"] != current_params.get("OrganizationAggregationSource", {}):
+ result["changed"] = True
- if result['changed']:
+ if result["changed"]:
try:
client.put_configuration_aggregator(
- ConfigurationAggregatorName=params['ConfigurationAggregatorName'],
- AccountAggregationSources=params['AccountAggregationSources'],
- OrganizationAggregationSource=params['OrganizationAggregationSource']
+ ConfigurationAggregatorName=params["ConfigurationAggregatorName"],
+ AccountAggregationSources=params["AccountAggregationSources"],
+ OrganizationAggregationSource=params["OrganizationAggregationSource"],
)
- result['aggregator'] = camel_dict_to_snake_dict(resource_exists(client, module, params))
+ result["aggregator"] = camel_dict_to_snake_dict(resource_exists(client, module, params))
return result
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Couldn't create AWS Config configuration aggregator")
@@ -155,10 +159,8 @@ def update_resource(client, module, params, result):
def delete_resource(client, module, params, result):
try:
- client.delete_configuration_aggregator(
- ConfigurationAggregatorName=params['ConfigurationAggregatorName']
- )
- result['changed'] = True
+ client.delete_configuration_aggregator(ConfigurationAggregatorName=params["ConfigurationAggregatorName"])
+ result["changed"] = True
return result
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Couldn't delete AWS Config configuration aggregator")
@@ -167,66 +169,64 @@ def delete_resource(client, module, params, result):
def main():
module = AnsibleAWSModule(
argument_spec={
- 'name': dict(type='str', required=True),
- 'state': dict(type='str', choices=['present', 'absent'], default='present'),
- 'account_sources': dict(type='list', required=True, elements='dict'),
- 'organization_source': dict(type='dict', required=True)
+ "name": dict(type="str", required=True),
+ "state": dict(type="str", choices=["present", "absent"], default="present"),
+ "account_sources": dict(type="list", required=True, elements="dict"),
+ "organization_source": dict(type="dict", required=True),
},
supports_check_mode=False,
)
- result = {
- 'changed': False
- }
+ result = {"changed": False}
- name = module.params.get('name')
- state = module.params.get('state')
+ name = module.params.get("name")
+ state = module.params.get("state")
params = {}
if name:
- params['ConfigurationAggregatorName'] = name
- params['AccountAggregationSources'] = []
- if module.params.get('account_sources'):
- for i in module.params.get('account_sources'):
+ params["ConfigurationAggregatorName"] = name
+ params["AccountAggregationSources"] = []
+ if module.params.get("account_sources"):
+ for i in module.params.get("account_sources"):
tmp_dict = {}
- if i.get('account_ids'):
- tmp_dict['AccountIds'] = i.get('account_ids')
- if i.get('aws_regions'):
- tmp_dict['AwsRegions'] = i.get('aws_regions')
- if i.get('all_aws_regions') is not None:
- tmp_dict['AllAwsRegions'] = i.get('all_aws_regions')
- params['AccountAggregationSources'].append(tmp_dict)
- if module.params.get('organization_source'):
- params['OrganizationAggregationSource'] = {}
- if module.params.get('organization_source').get('role_arn'):
- params['OrganizationAggregationSource'].update({
- 'RoleArn': module.params.get('organization_source').get('role_arn')
- })
- if module.params.get('organization_source').get('aws_regions'):
- params['OrganizationAggregationSource'].update({
- 'AwsRegions': module.params.get('organization_source').get('aws_regions')
- })
- if module.params.get('organization_source').get('all_aws_regions') is not None:
- params['OrganizationAggregationSource'].update({
- 'AllAwsRegions': module.params.get('organization_source').get('all_aws_regions')
- })
-
- client = module.client('config', retry_decorator=AWSRetry.jittered_backoff())
+ if i.get("account_ids"):
+ tmp_dict["AccountIds"] = i.get("account_ids")
+ if i.get("aws_regions"):
+ tmp_dict["AwsRegions"] = i.get("aws_regions")
+ if i.get("all_aws_regions") is not None:
+ tmp_dict["AllAwsRegions"] = i.get("all_aws_regions")
+ params["AccountAggregationSources"].append(tmp_dict)
+ if module.params.get("organization_source"):
+ params["OrganizationAggregationSource"] = {}
+ if module.params.get("organization_source").get("role_arn"):
+ params["OrganizationAggregationSource"].update(
+ {"RoleArn": module.params.get("organization_source").get("role_arn")}
+ )
+ if module.params.get("organization_source").get("aws_regions"):
+ params["OrganizationAggregationSource"].update(
+ {"AwsRegions": module.params.get("organization_source").get("aws_regions")}
+ )
+ if module.params.get("organization_source").get("all_aws_regions") is not None:
+ params["OrganizationAggregationSource"].update(
+ {"AllAwsRegions": module.params.get("organization_source").get("all_aws_regions")}
+ )
+
+ client = module.client("config", retry_decorator=AWSRetry.jittered_backoff())
resource_status = resource_exists(client, module, params)
- if state == 'present':
+ if state == "present":
if not resource_status:
create_resource(client, module, params, result)
else:
update_resource(client, module, params, result)
- if state == 'absent':
+ if state == "absent":
if resource_status:
delete_resource(client, module, params, result)
- module.exit_json(changed=result['changed'])
+ module.exit_json(changed=result["changed"])
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/config_delivery_channel.py b/ansible_collections/community/aws/plugins/modules/config_delivery_channel.py
index 371bd6685..1c3a3acdc 100644
--- a/ansible_collections/community/aws/plugins/modules/config_delivery_channel.py
+++ b/ansible_collections/community/aws/plugins/modules/config_delivery_channel.py
@@ -1,13 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
# Copyright: (c) 2018, Aaron Smith <ajsmith10381@gmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: config_delivery_channel
version_added: 1.0.0
@@ -39,6 +36,10 @@ options:
description:
- The prefix for the specified Amazon S3 bucket.
type: str
+ kms_key_arn:
+ description:
+ - The ARN of a KMS key used to encrypt objects delivered by Config. The key must belong to the same region as the destination S3 bucket.
+ type: str
sns_topic_arn:
description:
- The Amazon Resource Name (ARN) of the Amazon SNS topic to which AWS Config sends notifications about configuration changes.
@@ -49,22 +50,31 @@ options:
choices: ['One_Hour', 'Three_Hours', 'Six_Hours', 'Twelve_Hours', 'TwentyFour_Hours']
type: str
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
+
+EXAMPLES = r"""
+- name: Create a delivery channel for AWS Config
+ community.aws.config_delivery_channel:
+ name: test_delivery_channel
+ state: present
+ s3_bucket: 'test_aws_config_bucket'
+ sns_topic_arn: 'arn:aws:sns:us-east-1:123456789012:aws_config_topic:1234ab56-cdef-7g89-01hi-2jk34l5m67no'
+ delivery_frequency: 'Twelve_Hours'
-EXAMPLES = '''
-- name: Create Delivery Channel for AWS Config
+- name: Create a delivery channel with encrypted objects
community.aws.config_delivery_channel:
name: test_delivery_channel
state: present
s3_bucket: 'test_aws_config_bucket'
+ kms_key_arn: 'arn:aws:kms:us-east-1:123456789012:key/160f41cb-e660-4fa0-8bf6-976f53bf7851'
sns_topic_arn: 'arn:aws:sns:us-east-1:123456789012:aws_config_topic:1234ab56-cdef-7g89-01hi-2jk34l5m67no'
delivery_frequency: 'Twelve_Hours'
-'''
+"""
-RETURN = '''#'''
+RETURN = r"""#"""
try:
@@ -74,28 +84,31 @@ except ImportError:
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
# this waits for an IAM role to become fully available, at the cost of
# taking a long time to fail when the IAM role/policy really is invalid
retry_unavailable_iam_on_put_delivery = AWSRetry.jittered_backoff(
- catch_extra_error_codes=['InsufficientDeliveryPolicyException'],
+ catch_extra_error_codes=["InsufficientDeliveryPolicyException"],
)
def resource_exists(client, module, params):
try:
channel = client.describe_delivery_channels(
- DeliveryChannelNames=[params['name']],
+ DeliveryChannelNames=[params["name"]],
aws_retry=True,
)
- return channel['DeliveryChannels'][0]
- except is_boto3_error_code('NoSuchDeliveryChannelException'):
+ return channel["DeliveryChannels"][0]
+ except is_boto3_error_code("NoSuchDeliveryChannelException"):
return
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
module.fail_json_aws(e)
@@ -106,49 +119,63 @@ def create_resource(client, module, params, result):
)(
DeliveryChannel=params,
)
- result['changed'] = True
- result['channel'] = camel_dict_to_snake_dict(resource_exists(client, module, params))
+ result["changed"] = True
+ result["channel"] = camel_dict_to_snake_dict(resource_exists(client, module, params))
return result
- except is_boto3_error_code('InvalidS3KeyPrefixException') as e:
- module.fail_json_aws(e, msg="The `s3_prefix` parameter was invalid. Try '/' for no prefix")
- except is_boto3_error_code('InsufficientDeliveryPolicyException') as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, msg="The `s3_prefix` or `s3_bucket` parameter is invalid. "
- "Make sure the bucket exists and is available")
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, msg="Couldn't create AWS Config delivery channel")
+ except is_boto3_error_code("InvalidS3KeyPrefixException") as e:
+ module.fail_json_aws(
+ e,
+ msg="The `s3_prefix` parameter was invalid. Try '/' for no prefix",
+ )
+ except is_boto3_error_code("InsufficientDeliveryPolicyException") as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(
+ e,
+ msg="The `s3_prefix` or `s3_bucket` parameter is invalid. Make sure the bucket exists and is available",
+ )
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(
+ e,
+ msg="Couldn't create AWS Config delivery channel",
+ )
def update_resource(client, module, params, result):
current_params = client.describe_delivery_channels(
- DeliveryChannelNames=[params['name']],
+ DeliveryChannelNames=[params["name"]],
aws_retry=True,
)
- if params != current_params['DeliveryChannels'][0]:
+ if params != current_params["DeliveryChannels"][0]:
try:
retry_unavailable_iam_on_put_delivery(
client.put_delivery_channel,
)(
DeliveryChannel=params,
)
- result['changed'] = True
- result['channel'] = camel_dict_to_snake_dict(resource_exists(client, module, params))
+ result["changed"] = True
+ result["channel"] = camel_dict_to_snake_dict(resource_exists(client, module, params))
return result
- except is_boto3_error_code('InvalidS3KeyPrefixException') as e:
+ except is_boto3_error_code("InvalidS3KeyPrefixException") as e:
module.fail_json_aws(e, msg="The `s3_prefix` parameter was invalid. Try '/' for no prefix")
- except is_boto3_error_code('InsufficientDeliveryPolicyException') as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, msg="The `s3_prefix` or `s3_bucket` parameter is invalid. "
- "Make sure the bucket exists and is available")
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
+ except is_boto3_error_code("InsufficientDeliveryPolicyException") as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(
+ e,
+ msg="The `s3_prefix` or `s3_bucket` parameter is invalid. Make sure the bucket exists and is available",
+ )
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
module.fail_json_aws(e, msg="Couldn't create AWS Config delivery channel")
def delete_resource(client, module, params, result):
try:
- response = client.delete_delivery_channel(
- DeliveryChannelName=params['name']
- )
- result['changed'] = True
+ response = client.delete_delivery_channel(DeliveryChannelName=params["name"])
+ result["changed"] = True
return result
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Couldn't delete AWS Config delivery channel")
@@ -157,62 +184,61 @@ def delete_resource(client, module, params, result):
def main():
module = AnsibleAWSModule(
argument_spec={
- 'name': dict(type='str', required=True),
- 'state': dict(type='str', choices=['present', 'absent'], default='present'),
- 's3_bucket': dict(type='str', required=True),
- 's3_prefix': dict(type='str'),
- 'sns_topic_arn': dict(type='str'),
- 'delivery_frequency': dict(
- type='str',
+ "name": dict(type="str", required=True),
+ "state": dict(type="str", choices=["present", "absent"], default="present"),
+ "s3_bucket": dict(type="str", required=True),
+ "s3_prefix": dict(type="str"),
+ "kms_key_arn": dict(type="str", no_log=True),
+ "sns_topic_arn": dict(type="str"),
+ "delivery_frequency": dict(
+ type="str",
choices=[
- 'One_Hour',
- 'Three_Hours',
- 'Six_Hours',
- 'Twelve_Hours',
- 'TwentyFour_Hours'
- ]
+ "One_Hour",
+ "Three_Hours",
+ "Six_Hours",
+ "Twelve_Hours",
+ "TwentyFour_Hours",
+ ],
),
},
supports_check_mode=False,
)
- result = {
- 'changed': False
- }
+ result = {"changed": False}
- name = module.params.get('name')
- state = module.params.get('state')
+ name = module.params.get("name")
+ state = module.params.get("state")
params = {}
if name:
- params['name'] = name
- if module.params.get('s3_bucket'):
- params['s3BucketName'] = module.params.get('s3_bucket')
- if module.params.get('s3_prefix'):
- params['s3KeyPrefix'] = module.params.get('s3_prefix')
- if module.params.get('sns_topic_arn'):
- params['snsTopicARN'] = module.params.get('sns_topic_arn')
- if module.params.get('delivery_frequency'):
- params['configSnapshotDeliveryProperties'] = {
- 'deliveryFrequency': module.params.get('delivery_frequency')
- }
-
- client = module.client('config', retry_decorator=AWSRetry.jittered_backoff())
+ params["name"] = name
+ if module.params.get("s3_bucket"):
+ params["s3BucketName"] = module.params.get("s3_bucket")
+ if module.params.get("s3_prefix"):
+ params["s3KeyPrefix"] = module.params.get("s3_prefix")
+ if module.params.get("kms_key_arn"):
+ params["s3KmsKeyArn"] = module.params.get("kms_key_arn")
+ if module.params.get("sns_topic_arn"):
+ params["snsTopicARN"] = module.params.get("sns_topic_arn")
+ if module.params.get("delivery_frequency"):
+ params["configSnapshotDeliveryProperties"] = {"deliveryFrequency": module.params.get("delivery_frequency")}
+
+ client = module.client("config", retry_decorator=AWSRetry.jittered_backoff())
resource_status = resource_exists(client, module, params)
- if state == 'present':
+ if state == "present":
if not resource_status:
create_resource(client, module, params, result)
if resource_status:
update_resource(client, module, params, result)
- if state == 'absent':
+ if state == "absent":
if resource_status:
delete_resource(client, module, params, result)
module.exit_json(**result)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/config_recorder.py b/ansible_collections/community/aws/plugins/modules/config_recorder.py
index d90ce46cd..510bbaa23 100644
--- a/ansible_collections/community/aws/plugins/modules/config_recorder.py
+++ b/ansible_collections/community/aws/plugins/modules/config_recorder.py
@@ -1,13 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
# Copyright: (c) 2018, Aaron Smith <ajsmith10381@gmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: config_recorder
version_added: 1.0.0
@@ -62,23 +59,23 @@ options:
- Before you can set this option, you must set I(all_supported=false).
type: dict
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
- name: Create Configuration Recorder for AWS Config
community.aws.config_recorder:
name: test_configuration_recorder
state: present
role_arn: 'arn:aws:iam::123456789012:role/AwsConfigRecorder'
recording_group:
- all_supported: true
- include_global_types: true
-'''
+ all_supported: true
+ include_global_types: true
+"""
-RETURN = '''#'''
+RETURN = r"""#"""
try:
@@ -88,47 +85,43 @@ except ImportError:
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def resource_exists(client, module, params):
try:
- recorder = client.describe_configuration_recorders(
- ConfigurationRecorderNames=[params['name']]
- )
- return recorder['ConfigurationRecorders'][0]
- except is_boto3_error_code('NoSuchConfigurationRecorderException'):
+ recorder = client.describe_configuration_recorders(ConfigurationRecorderNames=[params["name"]])
+ return recorder["ConfigurationRecorders"][0]
+ except is_boto3_error_code("NoSuchConfigurationRecorderException"):
return
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
module.fail_json_aws(e)
def create_resource(client, module, params, result):
try:
- response = client.put_configuration_recorder(
- ConfigurationRecorder=params
- )
- result['changed'] = True
- result['recorder'] = camel_dict_to_snake_dict(resource_exists(client, module, params))
+ response = client.put_configuration_recorder(ConfigurationRecorder=params)
+ result["changed"] = True
+ result["recorder"] = camel_dict_to_snake_dict(resource_exists(client, module, params))
return result
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Couldn't create AWS Config configuration recorder")
def update_resource(client, module, params, result):
- current_params = client.describe_configuration_recorders(
- ConfigurationRecorderNames=[params['name']]
- )
+ current_params = client.describe_configuration_recorders(ConfigurationRecorderNames=[params["name"]])
- if params != current_params['ConfigurationRecorders'][0]:
+ if params != current_params["ConfigurationRecorders"][0]:
try:
- response = client.put_configuration_recorder(
- ConfigurationRecorder=params
- )
- result['changed'] = True
- result['recorder'] = camel_dict_to_snake_dict(resource_exists(client, module, params))
+ response = client.put_configuration_recorder(ConfigurationRecorder=params)
+ result["changed"] = True
+ result["recorder"] = camel_dict_to_snake_dict(resource_exists(client, module, params))
return result
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Couldn't update AWS Config configuration recorder")
@@ -136,77 +129,68 @@ def update_resource(client, module, params, result):
def delete_resource(client, module, params, result):
try:
- response = client.delete_configuration_recorder(
- ConfigurationRecorderName=params['name']
- )
- result['changed'] = True
+ response = client.delete_configuration_recorder(ConfigurationRecorderName=params["name"])
+ result["changed"] = True
return result
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Couldn't delete AWS Config configuration recorder")
def main():
-
module = AnsibleAWSModule(
argument_spec={
- 'name': dict(type='str', required=True),
- 'state': dict(type='str', choices=['present', 'absent'], default='present'),
- 'role_arn': dict(type='str'),
- 'recording_group': dict(type='dict'),
+ "name": dict(type="str", required=True),
+ "state": dict(type="str", choices=["present", "absent"], default="present"),
+ "role_arn": dict(type="str"),
+ "recording_group": dict(type="dict"),
},
supports_check_mode=False,
required_if=[
- ('state', 'present', ['role_arn', 'recording_group']),
+ ("state", "present", ["role_arn", "recording_group"]),
],
)
- result = {
- 'changed': False
- }
+ result = {"changed": False}
- name = module.params.get('name')
- state = module.params.get('state')
+ name = module.params.get("name")
+ state = module.params.get("state")
params = {}
if name:
- params['name'] = name
- if module.params.get('role_arn'):
- params['roleARN'] = module.params.get('role_arn')
- if module.params.get('recording_group'):
- params['recordingGroup'] = {}
- if module.params.get('recording_group').get('all_supported') is not None:
- params['recordingGroup'].update({
- 'allSupported': module.params.get('recording_group').get('all_supported')
- })
- if module.params.get('recording_group').get('include_global_types') is not None:
- params['recordingGroup'].update({
- 'includeGlobalResourceTypes': module.params.get('recording_group').get('include_global_types')
- })
- if module.params.get('recording_group').get('resource_types'):
- params['recordingGroup'].update({
- 'resourceTypes': module.params.get('recording_group').get('resource_types')
- })
+ params["name"] = name
+ if module.params.get("role_arn"):
+ params["roleARN"] = module.params.get("role_arn")
+ if module.params.get("recording_group"):
+ params["recordingGroup"] = {}
+ if module.params.get("recording_group").get("all_supported") is not None:
+ params["recordingGroup"].update({"allSupported": module.params.get("recording_group").get("all_supported")})
+ if module.params.get("recording_group").get("include_global_types") is not None:
+ params["recordingGroup"].update(
+ {"includeGlobalResourceTypes": module.params.get("recording_group").get("include_global_types")}
+ )
+ if module.params.get("recording_group").get("resource_types"):
+ params["recordingGroup"].update(
+ {"resourceTypes": module.params.get("recording_group").get("resource_types")}
+ )
else:
- params['recordingGroup'].update({
- 'resourceTypes': []
- })
+ params["recordingGroup"].update({"resourceTypes": []})
- client = module.client('config', retry_decorator=AWSRetry.jittered_backoff())
+ client = module.client("config", retry_decorator=AWSRetry.jittered_backoff())
resource_status = resource_exists(client, module, params)
- if state == 'present':
+ if state == "present":
if not resource_status:
create_resource(client, module, params, result)
if resource_status:
update_resource(client, module, params, result)
- if state == 'absent':
+ if state == "absent":
if resource_status:
delete_resource(client, module, params, result)
- module.exit_json(changed=result['changed'])
+ module.exit_json(changed=result["changed"])
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/config_rule.py b/ansible_collections/community/aws/plugins/modules/config_rule.py
index d5cb717fd..b86a528dd 100644
--- a/ansible_collections/community/aws/plugins/modules/config_rule.py
+++ b/ansible_collections/community/aws/plugins/modules/config_rule.py
@@ -1,13 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
# Copyright: (c) 2018, Aaron Smith <ajsmith10381@gmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: config_rule
version_added: 1.0.0
@@ -86,27 +83,26 @@ options:
choices: ['One_Hour', 'Three_Hours', 'Six_Hours', 'Twelve_Hours', 'TwentyFour_Hours']
type: str
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
- name: Create Config Rule for AWS Config
community.aws.config_rule:
name: test_config_rule
state: present
description: 'This AWS Config rule checks for public write access on S3 buckets'
scope:
- compliance_types:
- - 'AWS::S3::Bucket'
+ compliance_types:
+ - 'AWS::S3::Bucket'
source:
- owner: AWS
- identifier: 'S3_BUCKET_PUBLIC_WRITE_PROHIBITED'
-
-'''
+ owner: AWS
+ identifier: 'S3_BUCKET_PUBLIC_WRITE_PROHIBITED'
+"""
-RETURN = '''#'''
+RETURN = r"""#"""
try:
@@ -116,30 +112,32 @@ except ImportError:
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def rule_exists(client, module, params):
try:
rule = client.describe_config_rules(
- ConfigRuleNames=[params['ConfigRuleName']],
+ ConfigRuleNames=[params["ConfigRuleName"]],
aws_retry=True,
)
- return rule['ConfigRules'][0]
- except is_boto3_error_code('NoSuchConfigRuleException'):
+ return rule["ConfigRules"][0]
+ except is_boto3_error_code("NoSuchConfigRuleException"):
return
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
module.fail_json_aws(e)
def create_resource(client, module, params, result):
try:
- client.put_config_rule(
- ConfigRule=params
- )
- result['changed'] = True
+ client.put_config_rule(ConfigRule=params)
+ result["changed"] = True
return result
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Couldn't create AWS Config rule")
@@ -147,21 +145,19 @@ def create_resource(client, module, params, result):
def update_resource(client, module, params, result):
current_params = client.describe_config_rules(
- ConfigRuleNames=[params['ConfigRuleName']],
+ ConfigRuleNames=[params["ConfigRuleName"]],
aws_retry=True,
)
- del current_params['ConfigRules'][0]['ConfigRuleArn']
- del current_params['ConfigRules'][0]['ConfigRuleId']
- del current_params['ConfigRules'][0]['EvaluationModes']
+ del current_params["ConfigRules"][0]["ConfigRuleArn"]
+ del current_params["ConfigRules"][0]["ConfigRuleId"]
+ del current_params["ConfigRules"][0]["EvaluationModes"]
- if params != current_params['ConfigRules'][0]:
+ if params != current_params["ConfigRules"][0]:
try:
- client.put_config_rule(
- ConfigRule=params
- )
- result['changed'] = True
- result['rule'] = camel_dict_to_snake_dict(rule_exists(client, module, params))
+ client.put_config_rule(ConfigRule=params)
+ result["changed"] = True
+ result["rule"] = camel_dict_to_snake_dict(rule_exists(client, module, params))
return result
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Couldn't create AWS Config rule")
@@ -170,11 +166,11 @@ def update_resource(client, module, params, result):
def delete_resource(client, module, params, result):
try:
response = client.delete_config_rule(
- ConfigRuleName=params['ConfigRuleName'],
+ ConfigRuleName=params["ConfigRuleName"],
aws_retry=True,
)
- result['changed'] = True
- result['rule'] = {}
+ result["changed"] = True
+ result["rule"] = {}
return result
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Couldn't delete AWS Config rule")
@@ -183,93 +179,105 @@ def delete_resource(client, module, params, result):
def main():
module = AnsibleAWSModule(
argument_spec={
- 'name': dict(type='str', required=True),
- 'state': dict(type='str', choices=['present', 'absent'], default='present'),
- 'description': dict(type='str'),
- 'scope': dict(type='dict'),
- 'source': dict(type='dict', required=True),
- 'input_parameters': dict(type='str'),
- 'execution_frequency': dict(
- type='str',
+ "name": dict(type="str", required=True),
+ "state": dict(type="str", choices=["present", "absent"], default="present"),
+ "description": dict(type="str"),
+ "scope": dict(type="dict"),
+ "source": dict(type="dict", required=True),
+ "input_parameters": dict(type="str"),
+ "execution_frequency": dict(
+ type="str",
choices=[
- 'One_Hour',
- 'Three_Hours',
- 'Six_Hours',
- 'Twelve_Hours',
- 'TwentyFour_Hours'
- ]
+ "One_Hour",
+ "Three_Hours",
+ "Six_Hours",
+ "Twelve_Hours",
+ "TwentyFour_Hours",
+ ],
),
},
supports_check_mode=False,
)
- result = {
- 'changed': False
- }
+ result = {"changed": False}
- name = module.params.get('name')
- resource_type = module.params.get('resource_type')
- state = module.params.get('state')
+ name = module.params.get("name")
+ resource_type = module.params.get("resource_type")
+ state = module.params.get("state")
params = {}
if name:
- params['ConfigRuleName'] = name
- if module.params.get('description'):
- params['Description'] = module.params.get('description')
- if module.params.get('scope'):
- params['Scope'] = {}
- if module.params.get('scope').get('compliance_types'):
- params['Scope'].update({
- 'ComplianceResourceTypes': module.params.get('scope').get('compliance_types')
- })
- if module.params.get('scope').get('tag_key'):
- params['Scope'].update({
- 'TagKey': module.params.get('scope').get('tag_key')
- })
- if module.params.get('scope').get('tag_value'):
- params['Scope'].update({
- 'TagValue': module.params.get('scope').get('tag_value')
- })
- if module.params.get('scope').get('compliance_id'):
- params['Scope'].update({
- 'ComplianceResourceId': module.params.get('scope').get('compliance_id')
- })
- if module.params.get('source'):
- params['Source'] = {}
- if module.params.get('source').get('owner'):
- params['Source'].update({
- 'Owner': module.params.get('source').get('owner')
- })
- if module.params.get('source').get('identifier'):
- params['Source'].update({
- 'SourceIdentifier': module.params.get('source').get('identifier')
- })
- if module.params.get('source').get('details'):
- params['Source'].update({
- 'SourceDetails': module.params.get('source').get('details')
- })
- if module.params.get('input_parameters'):
- params['InputParameters'] = module.params.get('input_parameters')
- if module.params.get('execution_frequency'):
- params['MaximumExecutionFrequency'] = module.params.get('execution_frequency')
- params['ConfigRuleState'] = 'ACTIVE'
+ params["ConfigRuleName"] = name
+ if module.params.get("description"):
+ params["Description"] = module.params.get("description")
+ if module.params.get("scope"):
+ params["Scope"] = {}
+ if module.params.get("scope").get("compliance_types"):
+ params["Scope"].update(
+ {
+ "ComplianceResourceTypes": module.params.get("scope").get("compliance_types"),
+ }
+ )
+ if module.params.get("scope").get("tag_key"):
+ params["Scope"].update(
+ {
+ "TagKey": module.params.get("scope").get("tag_key"),
+ }
+ )
+ if module.params.get("scope").get("tag_value"):
+ params["Scope"].update(
+ {
+ "TagValue": module.params.get("scope").get("tag_value"),
+ }
+ )
+ if module.params.get("scope").get("compliance_id"):
+ params["Scope"].update(
+ {
+ "ComplianceResourceId": module.params.get("scope").get("compliance_id"),
+ }
+ )
+ if module.params.get("source"):
+ params["Source"] = {}
+ if module.params.get("source").get("owner"):
+ params["Source"].update(
+ {
+ "Owner": module.params.get("source").get("owner"),
+ }
+ )
+ if module.params.get("source").get("identifier"):
+ params["Source"].update(
+ {
+ "SourceIdentifier": module.params.get("source").get("identifier"),
+ }
+ )
+ if module.params.get("source").get("details"):
+ params["Source"].update(
+ {
+ "SourceDetails": module.params.get("source").get("details"),
+ }
+ )
+ if module.params.get("input_parameters"):
+ params["InputParameters"] = module.params.get("input_parameters")
+ if module.params.get("execution_frequency"):
+ params["MaximumExecutionFrequency"] = module.params.get("execution_frequency")
+ params["ConfigRuleState"] = "ACTIVE"
- client = module.client('config', retry_decorator=AWSRetry.jittered_backoff())
+ client = module.client("config", retry_decorator=AWSRetry.jittered_backoff())
existing_rule = rule_exists(client, module, params)
- if state == 'present':
+ if state == "present":
if not existing_rule:
create_resource(client, module, params, result)
else:
update_resource(client, module, params, result)
- if state == 'absent':
+ if state == "absent":
if existing_rule:
delete_resource(client, module, params, result)
module.exit_json(**result)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/data_pipeline.py b/ansible_collections/community/aws/plugins/modules/data_pipeline.py
index fc441c10c..85849324f 100644
--- a/ansible_collections/community/aws/plugins/modules/data_pipeline.py
+++ b/ansible_collections/community/aws/plugins/modules/data_pipeline.py
@@ -1,13 +1,10 @@
#!/usr/bin/python
-#
+# -*- coding: utf-8 -*-
+
# Copyright (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: data_pipeline
version_added: 1.0.0
@@ -15,10 +12,6 @@ author:
- Raghu Udiyar (@raags) <raghusiddarth@gmail.com>
- Sloane Hertel (@s-hertel) <shertel@redhat.com>
short_description: Create and manage AWS Datapipelines
-extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
- - amazon.aws.boto3
description:
- Create and manage AWS Datapipelines. Creation is not idempotent in AWS, so the C(uniqueId) is created by hashing the options (minus objects)
given to the datapipeline.
@@ -126,9 +119,13 @@ options:
type: dict
default: {}
aliases: ['resource_tags']
-'''
+extends_documentation_fragment:
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide for details.
# Create pipeline
@@ -147,23 +144,30 @@ EXAMPLES = r'''
- community.aws.data_pipeline:
name: test-dp
objects:
- - "id": "DefaultSchedule"
- "name": "Every 1 day"
- "fields":
+ - id: "DefaultSchedule"
+ name: "Every 1 day"
+ fields:
- "key": "period"
"stringValue": "1 days"
- "key": "type"
"stringValue": "Schedule"
- "key": "startAt"
"stringValue": "FIRST_ACTIVATION_DATE_TIME"
- - "id": "Default"
- "name": "Default"
- "fields": [ { "key": "resourceRole", "stringValue": "my_resource_role" },
- { "key": "role", "stringValue": "DataPipelineDefaultRole" },
- { "key": "pipelineLogUri", "stringValue": "s3://my_s3_log.txt" },
- { "key": "scheduleType", "stringValue": "cron" },
- { "key": "schedule", "refValue": "DefaultSchedule" },
- { "key": "failureAndRerunMode", "stringValue": "CASCADE" } ]
+ - id: "Default"
+ name: "Default"
+ fields:
+ - "key": "resourceRole"
+ "stringValue": "my_resource_role"
+ - "key": "role"
+ "stringValue": "DataPipelineDefaultRole"
+ - "key": "pipelineLogUri"
+ "stringValue": "s3://my_s3_log.txt"
+ - "key": "scheduleType"
+ "stringValue": "cron"
+ - "key": "schedule"
+ "refValue": "DefaultSchedule"
+ - "key": "failureAndRerunMode"
+ "stringValue": "CASCADE"
state: active
# Activate pipeline
@@ -177,10 +181,9 @@ EXAMPLES = r'''
name: test-dp
region: us-west-2
state: absent
+"""
-'''
-
-RETURN = r'''
+RETURN = r"""
changed:
description: whether the data pipeline has been modified
type: bool
@@ -195,7 +198,7 @@ result:
data_pipeline will be an empty dict. The msg describes the status of the operation.
returned: always
type: dict
-'''
+"""
import hashlib
import json
@@ -209,15 +212,15 @@ except ImportError:
from ansible.module_utils._text import to_text
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
-DP_ACTIVE_STATES = ['ACTIVE', 'SCHEDULED']
-DP_INACTIVE_STATES = ['INACTIVE', 'PENDING', 'FINISHED', 'DELETING']
-DP_ACTIVATING_STATE = 'ACTIVATING'
-DP_DEACTIVATING_STATE = 'DEACTIVATING'
-PIPELINE_DOESNT_EXIST = '^.*Pipeline with id: {0} does not exist$'
+DP_ACTIVE_STATES = ["ACTIVE", "SCHEDULED"]
+DP_INACTIVE_STATES = ["INACTIVE", "PENDING", "FINISHED", "DELETING"]
+DP_ACTIVATING_STATE = "ACTIVATING"
+DP_DEACTIVATING_STATE = "DEACTIVATING"
+PIPELINE_DOESNT_EXIST = "^.*Pipeline with id: {0} does not exist$"
class DataPipelineNotFound(Exception):
@@ -238,9 +241,9 @@ def pipeline_id(client, name):
"""
pipelines = client.list_pipelines()
- for dp in pipelines['pipelineIdList']:
- if dp['name'] == name:
- return dp['id']
+ for dp in pipelines["pipelineIdList"]:
+ if dp["name"] == name:
+ return dp["id"]
raise DataPipelineNotFound
@@ -254,7 +257,7 @@ def pipeline_description(client, dp_id):
"""
try:
return client.describe_pipelines(pipelineIds=[dp_id])
- except is_boto3_error_code(['PipelineNotFoundException', 'PipelineDeletedException']):
+ except is_boto3_error_code(["PipelineNotFoundException", "PipelineDeletedException"]):
raise DataPipelineNotFound
@@ -270,10 +273,10 @@ def pipeline_field(client, dp_id, field):
"""
dp_description = pipeline_description(client, dp_id)
- for field_key in dp_description['pipelineDescriptionList'][0]['fields']:
- if field_key['key'] == field:
- return field_key['stringValue']
- raise KeyError("Field key {0} not found!".format(field))
+ for field_key in dp_description["pipelineDescriptionList"][0]["fields"]:
+ if field_key["key"] == field:
+ return field_key["stringValue"]
+ raise KeyError(f"Field key {field} not found!")
def run_with_timeout(timeout, func, *func_args, **func_kwargs):
@@ -345,70 +348,70 @@ def pipeline_exists_timeout(client, dp_id, timeout):
def activate_pipeline(client, module):
- """Activates pipeline
-
- """
- dp_name = module.params.get('name')
- timeout = module.params.get('timeout')
+ """Activates pipeline"""
+ dp_name = module.params.get("name")
+ timeout = module.params.get("timeout")
try:
dp_id = pipeline_id(client, dp_name)
except DataPipelineNotFound:
- module.fail_json(msg='Data Pipeline {0} not found'.format(dp_name))
+ module.fail_json(msg=f"Data Pipeline {dp_name} not found")
if pipeline_field(client, dp_id, field="@pipelineState") in DP_ACTIVE_STATES:
changed = False
else:
try:
client.activate_pipeline(pipelineId=dp_id)
- except is_boto3_error_code('InvalidRequestException'):
+ except is_boto3_error_code("InvalidRequestException"):
module.fail_json(msg="You need to populate your pipeline before activation.")
try:
- pipeline_status_timeout(client, dp_id, status=DP_ACTIVE_STATES,
- timeout=timeout)
+ pipeline_status_timeout(client, dp_id, status=DP_ACTIVE_STATES, timeout=timeout)
except TimeOutException:
if pipeline_field(client, dp_id, field="@pipelineState") == "FINISHED":
# activated but completed more rapidly than it was checked
pass
else:
- module.fail_json(msg=('Data Pipeline {0} failed to activate '
- 'within timeout {1} seconds').format(dp_name, timeout))
+ module.fail_json(
+ msg=f"Data Pipeline {dp_name} failed to activate within timeout {timeout} seconds",
+ )
changed = True
data_pipeline = get_result(client, dp_id)
- result = {'data_pipeline': data_pipeline,
- 'msg': 'Data Pipeline {0} activated.'.format(dp_name)}
+ result = {
+ "data_pipeline": data_pipeline,
+ "msg": f"Data Pipeline {dp_name} activated.",
+ }
return (changed, result)
def deactivate_pipeline(client, module):
- """Deactivates pipeline
-
- """
- dp_name = module.params.get('name')
- timeout = module.params.get('timeout')
+ """Deactivates pipeline"""
+ dp_name = module.params.get("name")
+ timeout = module.params.get("timeout")
try:
dp_id = pipeline_id(client, dp_name)
except DataPipelineNotFound:
- module.fail_json(msg='Data Pipeline {0} not found'.format(dp_name))
+ module.fail_json(msg=f"Data Pipeline {dp_name} not found")
if pipeline_field(client, dp_id, field="@pipelineState") in DP_INACTIVE_STATES:
changed = False
else:
client.deactivate_pipeline(pipelineId=dp_id)
try:
- pipeline_status_timeout(client, dp_id, status=DP_INACTIVE_STATES,
- timeout=timeout)
+ pipeline_status_timeout(client, dp_id, status=DP_INACTIVE_STATES, timeout=timeout)
except TimeOutException:
- module.fail_json(msg=('Data Pipeline {0} failed to deactivate'
- 'within timeout {1} seconds').format(dp_name, timeout))
+ module.fail_json(
+ msg=f"Data Pipeline {dp_name} failed to deactivate within timeout {timeout} seconds",
+ )
changed = True
data_pipeline = get_result(client, dp_id)
- result = {'data_pipeline': data_pipeline,
- 'msg': 'Data Pipeline {0} deactivated.'.format(dp_name)}
+ result = {
+ "data_pipeline": data_pipeline,
+ "msg": f"Data Pipeline {dp_name} deactivated.",
+ }
return (changed, result)
@@ -422,11 +425,9 @@ def _delete_dp_with_check(dp_id, client, timeout):
def delete_pipeline(client, module):
- """Deletes pipeline
-
- """
- dp_name = module.params.get('name')
- timeout = module.params.get('timeout')
+ """Deletes pipeline"""
+ dp_name = module.params.get("name")
+ timeout = module.params.get("timeout")
try:
dp_id = pipeline_id(client, dp_name)
@@ -435,10 +436,13 @@ def delete_pipeline(client, module):
except DataPipelineNotFound:
changed = False
except TimeOutException:
- module.fail_json(msg=('Data Pipeline {0} failed to delete'
- 'within timeout {1} seconds').format(dp_name, timeout))
- result = {'data_pipeline': {},
- 'msg': 'Data Pipeline {0} deleted'.format(dp_name)}
+ module.fail_json(
+ msg=f"Data Pipeline {dp_name} failed to delete within timeout {timeout} seconds",
+ )
+ result = {
+ "data_pipeline": {},
+ "msg": f"Data Pipeline {dp_name} deleted",
+ }
return (changed, result)
@@ -446,14 +450,14 @@ def delete_pipeline(client, module):
def build_unique_id(module):
data = dict(module.params)
# removing objects from the unique id so we can update objects or populate the pipeline after creation without needing to make a new pipeline
- [data.pop(each, None) for each in ('objects', 'timeout')]
+ [data.pop(each, None) for each in ("objects", "timeout")]
json_data = json.dumps(data, sort_keys=True).encode("utf-8")
hashed_data = hashlib.md5(json_data).hexdigest()
return hashed_data
def format_tags(tags):
- """ Reformats tags
+ """Reformats tags
:param dict tags: dict of data pipeline tags (e.g. {key1: val1, key2: val2, key3: val3})
:returns: list of dicts (e.g. [{key: key1, value: val1}, {key: key2, value: val2}, {key: key3, value: val3}])
@@ -463,16 +467,16 @@ def format_tags(tags):
def get_result(client, dp_id):
- """ Get the current state of the data pipeline and reformat it to snake_case for exit_json
+ """Get the current state of the data pipeline and reformat it to snake_case for exit_json
:param object client: boto3 datapipeline client
:param string dp_id: pipeline id
:returns: reformatted dict of pipeline description
- """
+ """
# pipeline_description returns a pipelineDescriptionList of length 1
# dp is a dict with keys "description" (str), "fields" (list), "name" (str), "pipelineId" (str), "tags" (dict)
- dp = pipeline_description(client, dp_id)['pipelineDescriptionList'][0]
+ dp = pipeline_description(client, dp_id)["pipelineDescriptionList"][0]
# Get uniqueId and pipelineState in fields to add to the exit_json result
dp["unique_id"] = pipeline_field(client, dp_id, field="uniqueId")
@@ -489,8 +493,7 @@ def get_result(client, dp_id):
def diff_pipeline(client, module, objects, unique_id, dp_name):
- """Check if there's another pipeline with the same unique_id and if so, checks if the object needs to be updated
- """
+ """Check if there's another pipeline with the same unique_id and if so, checks if the object needs to be updated"""
result = {}
changed = False
create_dp = False
@@ -506,16 +509,18 @@ def diff_pipeline(client, module, objects, unique_id, dp_name):
create_dp = True
# Unique ids are the same - check if pipeline needs modification
else:
- dp_objects = client.get_pipeline_definition(pipelineId=dp_id)['pipelineObjects']
+ dp_objects = client.get_pipeline_definition(pipelineId=dp_id)["pipelineObjects"]
# Definition needs to be updated
if dp_objects != objects:
changed, msg = define_pipeline(client, module, objects, dp_id)
# No changes
else:
- msg = 'Data Pipeline {0} is present'.format(dp_name)
+ msg = f"Data Pipeline {dp_name} is present"
data_pipeline = get_result(client, dp_id)
- result = {'data_pipeline': data_pipeline,
- 'msg': msg}
+ result = {
+ "data_pipeline": data_pipeline,
+ "msg": msg,
+ }
except DataPipelineNotFound:
create_dp = True
@@ -523,30 +528,32 @@ def diff_pipeline(client, module, objects, unique_id, dp_name):
def define_pipeline(client, module, objects, dp_id):
- """Puts pipeline definition
-
- """
- dp_name = module.params.get('name')
+ """Puts pipeline definition"""
+ dp_name = module.params.get("name")
if pipeline_field(client, dp_id, field="@pipelineState") == "FINISHED":
- msg = 'Data Pipeline {0} is unable to be updated while in state FINISHED.'.format(dp_name)
+ msg = f"Data Pipeline {dp_name} is unable to be updated while in state FINISHED."
changed = False
elif objects:
- parameters = module.params.get('parameters')
- values = module.params.get('values')
+ parameters = module.params.get("parameters")
+ values = module.params.get("values")
try:
- client.put_pipeline_definition(pipelineId=dp_id,
- pipelineObjects=objects,
- parameterObjects=parameters,
- parameterValues=values)
- msg = 'Data Pipeline {0} has been updated.'.format(dp_name)
+ client.put_pipeline_definition(
+ pipelineId=dp_id, pipelineObjects=objects, parameterObjects=parameters, parameterValues=values
+ )
+ msg = f"Data Pipeline {dp_name} has been updated."
changed = True
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Failed to put the definition for pipeline {0}. Check that string/reference fields"
- "are not empty and that the number of objects in the pipeline does not exceed maximum allowed"
- "objects".format(dp_name))
+ module.fail_json_aws(
+ e,
+ msg=(
+ f"Failed to put the definition for pipeline {dp_name}. Check that string/reference fields"
+ "are not empty and that the number of objects in the pipeline does not exceed maximum allowed"
+ "objects"
+ ),
+ )
else:
changed = False
msg = ""
@@ -555,14 +562,12 @@ def define_pipeline(client, module, objects, dp_id):
def create_pipeline(client, module):
- """Creates datapipeline. Uses uniqueId to achieve idempotency.
-
- """
- dp_name = module.params.get('name')
- objects = module.params.get('objects', None)
- description = module.params.get('description', '')
- tags = module.params.get('tags')
- timeout = module.params.get('timeout')
+ """Creates datapipeline. Uses uniqueId to achieve idempotency."""
+ dp_name = module.params.get("name")
+ objects = module.params.get("objects", None)
+ description = module.params.get("description", "")
+ tags = module.params.get("tags")
+ timeout = module.params.get("timeout")
unique_id = build_unique_id(module)
create_dp, changed, result = diff_pipeline(client, module, objects, unique_id, dp_name)
@@ -576,24 +581,27 @@ def create_pipeline(client, module):
# Make pipeline
try:
tags = format_tags(tags)
- dp = client.create_pipeline(name=dp_name,
- uniqueId=unique_id,
- description=description,
- tags=tags)
- dp_id = dp['pipelineId']
+ dp = client.create_pipeline(name=dp_name, uniqueId=unique_id, description=description, tags=tags)
+ dp_id = dp["pipelineId"]
pipeline_exists_timeout(client, dp_id, timeout)
except TimeOutException:
- module.fail_json(msg=('Data Pipeline {0} failed to create'
- 'within timeout {1} seconds').format(dp_name, timeout))
+ module.fail_json(
+ msg=f"Data Pipeline {dp_name} failed to create within timeout {timeout} seconds",
+ )
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Failed to create the data pipeline {0}.".format(dp_name))
+ module.fail_json_aws(
+ e,
+ msg=f"Failed to create the data pipeline {dp_name}.",
+ )
# Put pipeline definition
changed, msg = define_pipeline(client, module, objects, dp_id)
changed = True
data_pipeline = get_result(client, dp_id)
- result = {'data_pipeline': data_pipeline,
- 'msg': 'Data Pipeline {0} created.'.format(dp_name) + msg}
+ result = {
+ "data_pipeline": data_pipeline,
+ "msg": f"Data Pipeline {dp_name} created." + msg,
+ }
return (changed, result)
@@ -601,34 +609,33 @@ def create_pipeline(client, module):
def main():
argument_spec = dict(
name=dict(required=True),
- description=dict(required=False, default=''),
- objects=dict(required=False, type='list', default=[], elements='dict'),
- parameters=dict(required=False, type='list', default=[], elements='dict'),
- timeout=dict(required=False, type='int', default=300),
- state=dict(default='present', choices=['present', 'absent',
- 'active', 'inactive']),
- tags=dict(required=False, type='dict', default={}, aliases=['resource_tags']),
- values=dict(required=False, type='list', default=[], elements='dict'),
+ description=dict(required=False, default=""),
+ objects=dict(required=False, type="list", default=[], elements="dict"),
+ parameters=dict(required=False, type="list", default=[], elements="dict"),
+ timeout=dict(required=False, type="int", default=300),
+ state=dict(default="present", choices=["present", "absent", "active", "inactive"]),
+ tags=dict(required=False, type="dict", default={}, aliases=["resource_tags"]),
+ values=dict(required=False, type="list", default=[], elements="dict"),
)
module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=False)
try:
- client = module.client('datapipeline')
+ client = module.client("datapipeline")
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to connect to AWS')
+ module.fail_json_aws(e, msg="Failed to connect to AWS")
- state = module.params.get('state')
- if state == 'present':
+ state = module.params.get("state")
+ if state == "present":
changed, result = create_pipeline(client, module)
- elif state == 'absent':
+ elif state == "absent":
changed, result = delete_pipeline(client, module)
- elif state == 'active':
+ elif state == "active":
changed, result = activate_pipeline(client, module)
- elif state == 'inactive':
+ elif state == "inactive":
changed, result = deactivate_pipeline(client, module)
module.exit_json(result=result, changed=changed)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/directconnect_confirm_connection.py b/ansible_collections/community/aws/plugins/modules/directconnect_confirm_connection.py
index 45180ac6c..1e99fd5ea 100644
--- a/ansible_collections/community/aws/plugins/modules/directconnect_confirm_connection.py
+++ b/ansible_collections/community/aws/plugins/modules/directconnect_confirm_connection.py
@@ -1,15 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: directconnect_confirm_connection
short_description: Confirms the creation of a hosted DirectConnect connection
@@ -21,10 +16,6 @@ description:
The usage did not change.
author:
- "Matt Traynham (@mtraynham)"
-extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
- - amazon.aws.boto3
options:
name:
description:
@@ -36,9 +27,13 @@ options:
- The ID of the Direct Connect connection.
- One of I(connection_id) or I(name) must be specified.
type: str
-'''
+extends_documentation_fragment:
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
# confirm a Direct Connect by name
- name: confirm the connection id
@@ -49,29 +44,31 @@ EXAMPLES = '''
- name: confirm the connection id
community.aws.directconnect_confirm_connection:
connection_id: dxcon-xxxxxxxx
-'''
+"""
-RETURN = '''
+RETURN = r"""
connection_state:
description: The state of the connection.
returned: always
type: str
sample: pending
-'''
+"""
import traceback
try:
- from botocore.exceptions import BotoCoreError, ClientError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
except ImportError:
pass # handled by imported AnsibleAWSModule
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
from ansible_collections.amazon.aws.plugins.module_utils.direct_connect import DirectConnectError
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
retry_params = {"retries": 10, "delay": 5, "backoff": 1.2, "catch_extra_error_codes": ["DirectConnectClientException"]}
@@ -84,26 +81,28 @@ def describe_connections(client, params):
def find_connection_id(client, connection_id=None, connection_name=None):
params = {}
if connection_id:
- params['connectionId'] = connection_id
+ params["connectionId"] = connection_id
try:
response = describe_connections(client, params)
except (BotoCoreError, ClientError) as e:
if connection_id:
- msg = "Failed to describe DirectConnect ID {0}".format(connection_id)
+ msg = f"Failed to describe DirectConnect ID {connection_id}"
else:
msg = "Failed to describe DirectConnect connections"
- raise DirectConnectError(msg=msg,
- last_traceback=traceback.format_exc(),
- exception=e)
+ raise DirectConnectError(
+ msg=msg,
+ last_traceback=traceback.format_exc(),
+ exception=e,
+ )
match = []
- if len(response.get('connections', [])) == 1 and connection_id:
- if response['connections'][0]['connectionState'] != 'deleted':
- match.append(response['connections'][0]['connectionId'])
+ if len(response.get("connections", [])) == 1 and connection_id:
+ if response["connections"][0]["connectionState"] != "deleted":
+ match.append(response["connections"][0]["connectionId"])
- for conn in response.get('connections', []):
- if connection_name == conn['connectionName'] and conn['connectionState'] != 'deleted':
- match.append(conn['connectionId'])
+ for conn in response.get("connections", []):
+ if connection_name == conn["connectionName"] and conn["connectionState"] != "deleted":
+ match.append(conn["connectionId"])
if len(match) == 1:
return match[0]
@@ -114,34 +113,33 @@ def find_connection_id(client, connection_id=None, connection_name=None):
def get_connection_state(client, connection_id):
try:
response = describe_connections(client, dict(connectionId=connection_id))
- return response['connections'][0]['connectionState']
+ return response["connections"][0]["connectionState"]
except (BotoCoreError, ClientError, IndexError) as e:
- raise DirectConnectError(msg="Failed to describe DirectConnect connection {0} state".format(connection_id),
- last_traceback=traceback.format_exc(),
- exception=e)
+ raise DirectConnectError(
+ msg=f"Failed to describe DirectConnect connection {connection_id} state",
+ last_traceback=traceback.format_exc(),
+ exception=e,
+ )
def main():
- argument_spec = dict(
- connection_id=dict(),
- name=dict()
+ argument_spec = dict(connection_id=dict(), name=dict())
+ module = AnsibleAWSModule(
+ argument_spec=argument_spec,
+ mutually_exclusive=[["connection_id", "name"]],
+ required_one_of=[["connection_id", "name"]],
)
- module = AnsibleAWSModule(argument_spec=argument_spec,
- mutually_exclusive=[['connection_id', 'name']],
- required_one_of=[['connection_id', 'name']])
- client = module.client('directconnect')
+ client = module.client("directconnect")
- connection_id = module.params['connection_id']
- connection_name = module.params['name']
+ connection_id = module.params["connection_id"]
+ connection_name = module.params["name"]
changed = False
connection_state = None
try:
- connection_id = find_connection_id(client,
- connection_id,
- connection_name)
+ connection_id = find_connection_id(client, connection_id, connection_name)
connection_state = get_connection_state(client, connection_id)
- if connection_state == 'ordering':
+ if connection_state == "ordering":
client.confirm_connection(connectionId=connection_id)
changed = True
connection_state = get_connection_state(client, connection_id)
@@ -154,5 +152,5 @@ def main():
module.exit_json(changed=changed, connection_state=connection_state)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/directconnect_connection.py b/ansible_collections/community/aws/plugins/modules/directconnect_connection.py
index 28d86717d..40e9bc913 100644
--- a/ansible_collections/community/aws/plugins/modules/directconnect_connection.py
+++ b/ansible_collections/community/aws/plugins/modules/directconnect_connection.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: directconnect_connection
version_added: 1.0.0
@@ -19,10 +17,6 @@ description:
The usage did not change.
author:
- "Sloane Hertel (@s-hertel)"
-extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
- - amazon.aws.boto3
options:
state:
description:
@@ -68,9 +62,13 @@ options:
- By default this will not happen. This option must be explicitly set to C(true) to change I(bandwith) or I(location).
type: bool
default: false
-'''
+extends_documentation_fragment:
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-EXAMPLES = """
+EXAMPLES = r"""
# create a Direct Connect connection
- community.aws.directconnect_connection:
@@ -102,7 +100,7 @@ EXAMPLES = """
name: ansible-test-connection
"""
-RETURN = """
+RETURN = r"""
connection:
description: The attributes of the direct connect connection.
type: complex
@@ -158,18 +156,20 @@ connection:
import traceback
try:
- from botocore.exceptions import BotoCoreError, ClientError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
except ImportError:
pass # handled by imported AnsibleAWSModule
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
from ansible_collections.amazon.aws.plugins.module_utils.direct_connect import DirectConnectError
from ansible_collections.amazon.aws.plugins.module_utils.direct_connect import associate_connection_and_lag
from ansible_collections.amazon.aws.plugins.module_utils.direct_connect import delete_connection
from ansible_collections.amazon.aws.plugins.module_utils.direct_connect import disassociate_connection_and_lag
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
retry_params = {"retries": 10, "delay": 5, "backoff": 1.2, "catch_extra_error_codes": ["DirectConnectClientException"]}
@@ -181,31 +181,29 @@ def connection_status(client, connection_id):
def connection_exists(client, connection_id=None, connection_name=None, verify=True):
params = {}
if connection_id:
- params['connectionId'] = connection_id
+ params["connectionId"] = connection_id
try:
response = AWSRetry.jittered_backoff(**retry_params)(client.describe_connections)(**params)
except (BotoCoreError, ClientError) as e:
if connection_id:
- msg = "Failed to describe DirectConnect ID {0}".format(connection_id)
+ msg = f"Failed to describe DirectConnect ID {connection_id}"
else:
msg = "Failed to describe DirectConnect connections"
- raise DirectConnectError(msg=msg,
- last_traceback=traceback.format_exc(),
- exception=e)
+ raise DirectConnectError(msg=msg, last_traceback=traceback.format_exc(), exception=e)
match = []
connection = []
# look for matching connections
- if len(response.get('connections', [])) == 1 and connection_id:
- if response['connections'][0]['connectionState'] != 'deleted':
- match.append(response['connections'][0]['connectionId'])
- connection.extend(response['connections'])
+ if len(response.get("connections", [])) == 1 and connection_id:
+ if response["connections"][0]["connectionState"] != "deleted":
+ match.append(response["connections"][0]["connectionId"])
+ connection.extend(response["connections"])
- for conn in response.get('connections', []):
- if connection_name == conn['connectionName'] and conn['connectionState'] != 'deleted':
- match.append(conn['connectionId'])
+ for conn in response.get("connections", []):
+ if connection_name == conn["connectionName"] and conn["connectionState"] != "deleted":
+ match.append(conn["connectionId"])
connection.append(conn)
# verifying if the connections exists; if true, return connection identifier, otherwise return False
@@ -215,33 +213,35 @@ def connection_exists(client, connection_id=None, connection_name=None, verify=T
return False
# not verifying if the connection exists; just return current connection info
elif len(connection) == 1:
- return {'connection': connection[0]}
- return {'connection': {}}
+ return {"connection": connection[0]}
+ return {"connection": {}}
def create_connection(client, location, bandwidth, name, lag_id):
if not name:
raise DirectConnectError(msg="Failed to create a Direct Connect connection: name required.")
params = {
- 'location': location,
- 'bandwidth': bandwidth,
- 'connectionName': name,
+ "location": location,
+ "bandwidth": bandwidth,
+ "connectionName": name,
}
if lag_id:
- params['lagId'] = lag_id
+ params["lagId"] = lag_id
try:
connection = AWSRetry.jittered_backoff(**retry_params)(client.create_connection)(**params)
except (BotoCoreError, ClientError) as e:
- raise DirectConnectError(msg="Failed to create DirectConnect connection {0}".format(name),
- last_traceback=traceback.format_exc(),
- exception=e)
- return connection['connectionId']
+ raise DirectConnectError(
+ msg=f"Failed to create DirectConnect connection {name}",
+ last_traceback=traceback.format_exc(),
+ exception=e,
+ )
+ return connection["connectionId"]
def changed_properties(current_status, location, bandwidth):
- current_bandwidth = current_status['bandwidth']
- current_location = current_status['location']
+ current_bandwidth = current_status["bandwidth"]
+ current_location = current_status["location"]
return current_bandwidth != bandwidth or current_location != location
@@ -249,10 +249,10 @@ def changed_properties(current_status, location, bandwidth):
@AWSRetry.jittered_backoff(**retry_params)
def update_associations(client, latest_state, connection_id, lag_id):
changed = False
- if 'lagId' in latest_state and lag_id != latest_state['lagId']:
- disassociate_connection_and_lag(client, connection_id, lag_id=latest_state['lagId'])
+ if "lagId" in latest_state and lag_id != latest_state["lagId"]:
+ disassociate_connection_and_lag(client, connection_id, lag_id=latest_state["lagId"])
changed = True
- if (changed and lag_id) or (lag_id and 'lagId' not in latest_state):
+ if (changed and lag_id) or (lag_id and "lagId" not in latest_state):
associate_connection_and_lag(client, connection_id, lag_id)
changed = True
return changed
@@ -261,16 +261,18 @@ def update_associations(client, latest_state, connection_id, lag_id):
def ensure_present(client, connection_id, connection_name, location, bandwidth, lag_id, forced_update):
# the connection is found; get the latest state and see if it needs to be updated
if connection_id:
- latest_state = connection_status(client, connection_id=connection_id)['connection']
+ latest_state = connection_status(client, connection_id=connection_id)["connection"]
if changed_properties(latest_state, location, bandwidth) and forced_update:
ensure_absent(client, connection_id)
- return ensure_present(client=client,
- connection_id=None,
- connection_name=connection_name,
- location=location,
- bandwidth=bandwidth,
- lag_id=lag_id,
- forced_update=forced_update)
+ return ensure_present(
+ client=client,
+ connection_id=None,
+ connection_name=connection_name,
+ location=location,
+ bandwidth=bandwidth,
+ lag_id=lag_id,
+ forced_update=forced_update,
+ )
elif update_associations(client, latest_state, connection_id, lag_id):
return True, connection_id
@@ -293,53 +295,59 @@ def ensure_absent(client, connection_id):
def main():
argument_spec = dict(
- state=dict(required=True, choices=['present', 'absent']),
+ state=dict(required=True, choices=["present", "absent"]),
name=dict(),
location=dict(),
- bandwidth=dict(choices=['1Gbps', '10Gbps']),
+ bandwidth=dict(choices=["1Gbps", "10Gbps"]),
link_aggregation_group=dict(),
connection_id=dict(),
- forced_update=dict(type='bool', default=False)
+ forced_update=dict(type="bool", default=False),
)
module = AnsibleAWSModule(
argument_spec=argument_spec,
- required_one_of=[('connection_id', 'name')],
- required_if=[('state', 'present', ('location', 'bandwidth'))]
+ required_one_of=[("connection_id", "name")],
+ required_if=[("state", "present", ("location", "bandwidth"))],
)
- connection = module.client('directconnect')
+ connection = module.client("directconnect")
- state = module.params.get('state')
+ state = module.params.get("state")
try:
connection_id = connection_exists(
- connection,
- connection_id=module.params.get('connection_id'),
- connection_name=module.params.get('name')
+ connection, connection_id=module.params.get("connection_id"), connection_name=module.params.get("name")
)
- if not connection_id and module.params.get('connection_id'):
- module.fail_json(msg="The Direct Connect connection {0} does not exist.".format(module.params.get('connection_id')))
-
- if state == 'present':
- changed, connection_id = ensure_present(connection,
- connection_id=connection_id,
- connection_name=module.params.get('name'),
- location=module.params.get('location'),
- bandwidth=module.params.get('bandwidth'),
- lag_id=module.params.get('link_aggregation_group'),
- forced_update=module.params.get('forced_update'))
+ if not connection_id and module.params.get("connection_id"):
+ module.fail_json(
+ msg=f"The Direct Connect connection {module.params['connection_id']} does not exist.",
+ )
+
+ if state == "present":
+ changed, connection_id = ensure_present(
+ connection,
+ connection_id=connection_id,
+ connection_name=module.params.get("name"),
+ location=module.params.get("location"),
+ bandwidth=module.params.get("bandwidth"),
+ lag_id=module.params.get("link_aggregation_group"),
+ forced_update=module.params.get("forced_update"),
+ )
response = connection_status(connection, connection_id)
- elif state == 'absent':
+ elif state == "absent":
changed = ensure_absent(connection, connection_id)
response = {}
except DirectConnectError as e:
if e.last_traceback:
- module.fail_json(msg=e.msg, exception=e.last_traceback, **camel_dict_to_snake_dict(e.exception.response))
+ module.fail_json(
+ msg=e.msg,
+ exception=e.last_traceback,
+ **camel_dict_to_snake_dict(e.exception.response),
+ )
else:
module.fail_json(msg=e.msg)
module.exit_json(changed=changed, **camel_dict_to_snake_dict(response))
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/directconnect_gateway.py b/ansible_collections/community/aws/plugins/modules/directconnect_gateway.py
index 1433b387b..b231f0e8f 100644
--- a/ansible_collections/community/aws/plugins/modules/directconnect_gateway.py
+++ b/ansible_collections/community/aws/plugins/modules/directconnect_gateway.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
module: directconnect_gateway
author:
- Gobin Sougrakpam (@gobins)
@@ -19,10 +17,6 @@ description:
- Detaches Virtual Gateways to Direct Connect Gateway.
- Prior to release 5.0.0 this module was called C(community.aws.aws_direct_connect_gateway).
The usage did not change.
-extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
- - amazon.aws.boto3
options:
state:
description:
@@ -54,9 +48,13 @@ options:
- How long to wait for the association to be deleted.
type: int
default: 320
-'''
+extends_documentation_fragment:
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
- name: Create a new direct connect gateway attached to virtual private gateway
community.aws.directconnect_gateway:
state: present
@@ -71,9 +69,9 @@ EXAMPLES = '''
name: my-dx-gateway
amazon_asn: 7224
register: created_dxgw
-'''
+"""
-RETURN = '''
+RETURN = r"""
result:
description:
- The attributes of the Direct Connect Gateway
@@ -95,7 +93,7 @@ result:
owner_account:
description: The AWS account ID of the owner of the direct connect gateway.
type: str
-'''
+"""
import time
@@ -106,17 +104,18 @@ except ImportError:
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def dx_gateway_info(client, gateway_id, module):
try:
resp = client.describe_direct_connect_gateways(
- directConnectGatewayId=gateway_id)
+ directConnectGatewayId=gateway_id,
+ )
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
module.fail_json_aws(e, msg="Failed to fetch gateway information.")
- if resp['directConnectGateways']:
- return resp['directConnectGateways'][0]
+ if resp["directConnectGateways"]:
+ return resp["directConnectGateways"][0]
def wait_for_status(client, module, gateway_id, virtual_gateway_id, status):
@@ -130,9 +129,10 @@ def wait_for_status(client, module, gateway_id, virtual_gateway_id, status):
client,
module,
gateway_id=gateway_id,
- virtual_gateway_id=virtual_gateway_id)
- if response['directConnectGatewayAssociations']:
- if response['directConnectGatewayAssociations'][0]['associationState'] == status:
+ virtual_gateway_id=virtual_gateway_id,
+ )
+ if response["directConnectGatewayAssociations"]:
+ if response["directConnectGatewayAssociations"][0]["associationState"] == status:
status_achieved = True
break
else:
@@ -149,17 +149,18 @@ def wait_for_status(client, module, gateway_id, virtual_gateway_id, status):
def associate_direct_connect_gateway(client, module, gateway_id):
params = dict()
- params['virtual_gateway_id'] = module.params.get('virtual_gateway_id')
+ params["virtual_gateway_id"] = module.params.get("virtual_gateway_id")
try:
response = client.create_direct_connect_gateway_association(
directConnectGatewayId=gateway_id,
- virtualGatewayId=params['virtual_gateway_id'])
+ virtualGatewayId=params["virtual_gateway_id"],
+ )
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
- module.fail_json_aws(e, 'Failed to associate gateway')
+ module.fail_json_aws(e, "Failed to associate gateway")
- status_achieved, dxgw = wait_for_status(client, module, gateway_id, params['virtual_gateway_id'], 'associating')
+ status_achieved, dxgw = wait_for_status(client, module, gateway_id, params["virtual_gateway_id"], "associating")
if not status_achieved:
- module.fail_json(msg='Error waiting for dxgw to attach to vpg - please check the AWS console')
+ module.fail_json(msg="Error waiting for dxgw to attach to vpg - please check the AWS console")
result = response
return result
@@ -169,13 +170,14 @@ def delete_association(client, module, gateway_id, virtual_gateway_id):
try:
response = client.delete_direct_connect_gateway_association(
directConnectGatewayId=gateway_id,
- virtualGatewayId=virtual_gateway_id)
+ virtualGatewayId=virtual_gateway_id,
+ )
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
module.fail_json_aws(e, msg="Failed to delete gateway association.")
- status_achieved, dxgw = wait_for_status(client, module, gateway_id, virtual_gateway_id, 'disassociating')
+ status_achieved, dxgw = wait_for_status(client, module, gateway_id, virtual_gateway_id, "disassociating")
if not status_achieved:
- module.fail_json(msg='Error waiting for dxgw to detach from vpg - please check the AWS console')
+ module.fail_json(msg="Error waiting for dxgw to detach from vpg - please check the AWS console")
result = response
return result
@@ -183,12 +185,13 @@ def delete_association(client, module, gateway_id, virtual_gateway_id):
def create_dx_gateway(client, module):
params = dict()
- params['name'] = module.params.get('name')
- params['amazon_asn'] = module.params.get('amazon_asn')
+ params["name"] = module.params.get("name")
+ params["amazon_asn"] = module.params.get("amazon_asn")
try:
response = client.create_direct_connect_gateway(
- directConnectGatewayName=params['name'],
- amazonSideAsn=int(params['amazon_asn']))
+ directConnectGatewayName=params["name"],
+ amazonSideAsn=int(params["amazon_asn"]),
+ )
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
module.fail_json_aws(e, msg="Failed to create direct connect gateway.")
@@ -200,21 +203,21 @@ def find_dx_gateway(client, module, gateway_id=None):
params = dict()
gateways = list()
if gateway_id is not None:
- params['directConnectGatewayId'] = gateway_id
+ params["directConnectGatewayId"] = gateway_id
while True:
try:
resp = client.describe_direct_connect_gateways(**params)
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
module.fail_json_aws(e, msg="Failed to describe gateways")
- gateways.extend(resp['directConnectGateways'])
- if 'nextToken' in resp:
- params['nextToken'] = resp['nextToken']
+ gateways.extend(resp["directConnectGateways"])
+ if "nextToken" in resp:
+ params["nextToken"] = resp["nextToken"]
else:
break
if gateways != []:
count = 0
for gateway in gateways:
- if module.params.get('name') == gateway['directConnectGatewayName']:
+ if module.params.get("name") == gateway["directConnectGatewayName"]:
count += 1
return gateway
return None
@@ -224,7 +227,7 @@ def check_dxgw_association(client, module, gateway_id, virtual_gateway_id=None):
try:
if virtual_gateway_id is None:
resp = client.describe_direct_connect_gateway_associations(
- directConnectGatewayId=gateway_id
+ directConnectGatewayId=gateway_id,
)
else:
resp = client.describe_direct_connect_gateway_associations(
@@ -243,22 +246,20 @@ def ensure_present(client, module):
changed = False
params = dict()
result = dict()
- params['name'] = module.params.get('name')
- params['amazon_asn'] = module.params.get('amazon_asn')
- params['virtual_gateway_id'] = module.params.get('virtual_gateway_id')
+ params["name"] = module.params.get("name")
+ params["amazon_asn"] = module.params.get("amazon_asn")
+ params["virtual_gateway_id"] = module.params.get("virtual_gateway_id")
# check if a gateway matching our module args already exists
existing_dxgw = find_dx_gateway(client, module)
- if existing_dxgw is not None and existing_dxgw['directConnectGatewayState'] != 'deleted':
- gateway_id = existing_dxgw['directConnectGatewayId']
+ if existing_dxgw is not None and existing_dxgw["directConnectGatewayState"] != "deleted":
+ gateway_id = existing_dxgw["directConnectGatewayId"]
# if a gateway_id was provided, check if it is attach to the DXGW
- if params['virtual_gateway_id']:
+ if params["virtual_gateway_id"]:
resp = check_dxgw_association(
- client,
- module,
- gateway_id=gateway_id,
- virtual_gateway_id=params['virtual_gateway_id'])
+ client, module, gateway_id=gateway_id, virtual_gateway_id=params["virtual_gateway_id"]
+ )
if not resp["directConnectGatewayAssociations"]:
# attach the dxgw to the supplied virtual_gateway_id
associate_direct_connect_gateway(client, module, gateway_id)
@@ -269,26 +270,28 @@ def ensure_present(client, module):
resp = check_dxgw_association(client, module, gateway_id=gateway_id)
if resp["directConnectGatewayAssociations"]:
- for association in resp['directConnectGatewayAssociations']:
- if association['associationState'] not in ['disassociating', 'disassociated']:
+ for association in resp["directConnectGatewayAssociations"]:
+ if association["associationState"] not in ["disassociating", "disassociated"]:
delete_association(
client,
module,
gateway_id=gateway_id,
- virtual_gateway_id=association['virtualGatewayId'])
+ virtual_gateway_id=association["virtualGatewayId"],
+ )
else:
# create a new dxgw
new_dxgw = create_dx_gateway(client, module)
changed = True
- gateway_id = new_dxgw['directConnectGateway']['directConnectGatewayId']
+ gateway_id = new_dxgw["directConnectGateway"]["directConnectGatewayId"]
# if a vpc-id was supplied, attempt to attach it to the dxgw
- if params['virtual_gateway_id']:
+ if params["virtual_gateway_id"]:
associate_direct_connect_gateway(client, module, gateway_id)
- resp = check_dxgw_association(client,
- module,
- gateway_id=gateway_id
- )
+ resp = check_dxgw_association(
+ client,
+ module,
+ gateway_id=gateway_id,
+ )
if resp["directConnectGatewayAssociations"]:
changed = True
@@ -302,23 +305,23 @@ def ensure_absent(client, module):
changed = False
result = dict()
- dx_gateway_id = module.params.get('direct_connect_gateway_id')
+ dx_gateway_id = module.params.get("direct_connect_gateway_id")
existing_dxgw = find_dx_gateway(client, module, dx_gateway_id)
if existing_dxgw is not None:
- resp = check_dxgw_association(client, module,
- gateway_id=dx_gateway_id)
+ resp = check_dxgw_association(client, module, gateway_id=dx_gateway_id)
if resp["directConnectGatewayAssociations"]:
- for association in resp['directConnectGatewayAssociations']:
- if association['associationState'] not in ['disassociating', 'disassociated']:
- delete_association(client, module,
- gateway_id=dx_gateway_id,
- virtual_gateway_id=association['virtualGatewayId'])
+ for association in resp["directConnectGatewayAssociations"]:
+ if association["associationState"] not in ["disassociating", "disassociated"]:
+ delete_association(
+ client,
+ module,
+ gateway_id=dx_gateway_id,
+ virtual_gateway_id=association["virtualGatewayId"],
+ )
# wait for deleting association
- timeout = time.time() + module.params.get('wait_timeout')
+ timeout = time.time() + module.params.get("wait_timeout")
while time.time() < timeout:
- resp = check_dxgw_association(client,
- module,
- gateway_id=dx_gateway_id)
+ resp = check_dxgw_association(client, module, gateway_id=dx_gateway_id)
if resp["directConnectGatewayAssociations"] != []:
time.sleep(15)
else:
@@ -326,43 +329,44 @@ def ensure_absent(client, module):
try:
resp = client.delete_direct_connect_gateway(
- directConnectGatewayId=dx_gateway_id
+ directConnectGatewayId=dx_gateway_id,
)
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
module.fail_json_aws(e, msg="Failed to delete gateway")
- result = resp['directConnectGateway']
+ result = resp["directConnectGateway"]
return changed
def main():
argument_spec = dict(
- state=dict(default='present', choices=['present', 'absent']),
+ state=dict(default="present", choices=["present", "absent"]),
name=dict(),
amazon_asn=dict(),
virtual_gateway_id=dict(),
direct_connect_gateway_id=dict(),
- wait_timeout=dict(type='int', default=320),
+ wait_timeout=dict(type="int", default=320),
+ )
+ required_if = [("state", "present", ["name", "amazon_asn"]), ("state", "absent", ["direct_connect_gateway_id"])]
+ module = AnsibleAWSModule(
+ argument_spec=argument_spec,
+ required_if=required_if,
)
- required_if = [('state', 'present', ['name', 'amazon_asn']),
- ('state', 'absent', ['direct_connect_gateway_id'])]
- module = AnsibleAWSModule(argument_spec=argument_spec,
- required_if=required_if)
- state = module.params.get('state')
+ state = module.params.get("state")
try:
- client = module.client('directconnect')
+ client = module.client("directconnect")
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to connect to AWS')
+ module.fail_json_aws(e, msg="Failed to connect to AWS")
- if state == 'present':
+ if state == "present":
(changed, results) = ensure_present(client, module)
- elif state == 'absent':
+ elif state == "absent":
changed = ensure_absent(client, module)
results = {}
module.exit_json(changed=changed, **camel_dict_to_snake_dict(results))
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/directconnect_link_aggregation_group.py b/ansible_collections/community/aws/plugins/modules/directconnect_link_aggregation_group.py
index cc7122712..99224fee0 100644
--- a/ansible_collections/community/aws/plugins/modules/directconnect_link_aggregation_group.py
+++ b/ansible_collections/community/aws/plugins/modules/directconnect_link_aggregation_group.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: directconnect_link_aggregation_group
version_added: 1.0.0
@@ -17,10 +15,6 @@ description:
The usage did not change.
author:
- "Sloane Hertel (@s-hertel)"
-extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
- - amazon.aws.boto3
options:
state:
description:
@@ -81,9 +75,13 @@ options:
- The duration in seconds to wait if I(wait=true).
default: 120
type: int
-'''
+extends_documentation_fragment:
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-EXAMPLES = """
+EXAMPLES = r"""
# create a Direct Connect connection
- community.aws.directconnect_link_aggregation_group:
@@ -93,7 +91,7 @@ EXAMPLES = """
bandwidth: 1Gbps
"""
-RETURN = """
+RETURN = r"""
changed:
type: str
description: Whether or not the LAG has changed.
@@ -163,8 +161,8 @@ region:
returned: when I(state=present)
"""
-import traceback
import time
+import traceback
try:
import botocore
@@ -173,13 +171,13 @@ except ImportError:
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-
from ansible_collections.amazon.aws.plugins.module_utils.direct_connect import DirectConnectError
from ansible_collections.amazon.aws.plugins.module_utils.direct_connect import delete_connection
from ansible_collections.amazon.aws.plugins.module_utils.direct_connect import delete_virtual_interface
from ansible_collections.amazon.aws.plugins.module_utils.direct_connect import disassociate_connection_and_lag
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def lag_status(client, lag_id):
@@ -187,8 +185,8 @@ def lag_status(client, lag_id):
def lag_exists(client, lag_id=None, lag_name=None, verify=True):
- """ If verify=True, returns the LAG ID or None
- If verify=False, returns the LAG's data (or an empty dict)
+ """If verify=True, returns the LAG ID or None
+ If verify=False, returns the LAG's data (or an empty dict)
"""
try:
if lag_id:
@@ -202,26 +200,24 @@ def lag_exists(client, lag_id=None, lag_name=None, verify=True):
return {}
else:
failed_op = "Failed to describe DirectConnect link aggregation groups."
- raise DirectConnectError(msg=failed_op,
- last_traceback=traceback.format_exc(),
- exception=e)
+ raise DirectConnectError(msg=failed_op, last_traceback=traceback.format_exc(), exception=e)
match = [] # List of LAG IDs that are exact matches
lag = [] # List of LAG data that are exact matches
# look for matching connections
- if len(response.get('lags', [])) == 1 and lag_id:
- if response['lags'][0]['lagState'] != 'deleted':
- match.append(response['lags'][0]['lagId'])
- lag.append(response['lags'][0])
+ if len(response.get("lags", [])) == 1 and lag_id:
+ if response["lags"][0]["lagState"] != "deleted":
+ match.append(response["lags"][0]["lagId"])
+ lag.append(response["lags"][0])
else:
- for each in response.get('lags', []):
- if each['lagState'] != 'deleted':
+ for each in response.get("lags", []):
+ if each["lagState"] != "deleted":
if not lag_id:
- if lag_name == each['lagName']:
- match.append(each['lagId'])
+ if lag_name == each["lagName"]:
+ match.append(each["lagId"])
else:
- match.append(each['lagId'])
+ match.append(each["lagId"])
# verifying if the connections exists; if true, return connection identifier, otherwise return False
if verify and len(match) == 1:
@@ -239,36 +235,41 @@ def lag_exists(client, lag_id=None, lag_name=None, verify=True):
def create_lag(client, num_connections, location, bandwidth, name, connection_id):
if not name:
- raise DirectConnectError(msg="Failed to create a Direct Connect link aggregation group: name required.",
- last_traceback=None,
- exception="")
-
- parameters = dict(numberOfConnections=num_connections,
- location=location,
- connectionsBandwidth=bandwidth,
- lagName=name)
+ raise DirectConnectError(
+ msg="Failed to create a Direct Connect link aggregation group: name required.",
+ last_traceback=None,
+ exception="",
+ )
+
+ parameters = dict(
+ numberOfConnections=num_connections, location=location, connectionsBandwidth=bandwidth, lagName=name
+ )
if connection_id:
parameters.update(connectionId=connection_id)
try:
lag = client.create_lag(**parameters)
except botocore.exceptions.ClientError as e:
- raise DirectConnectError(msg="Failed to create DirectConnect link aggregation group {0}".format(name),
- last_traceback=traceback.format_exc(),
- exception=e)
+ raise DirectConnectError(
+ msg=f"Failed to create DirectConnect link aggregation group {name}",
+ last_traceback=traceback.format_exc(),
+ exception=e,
+ )
- return lag['lagId']
+ return lag["lagId"]
def delete_lag(client, lag_id):
try:
client.delete_lag(lagId=lag_id)
except botocore.exceptions.ClientError as e:
- raise DirectConnectError(msg="Failed to delete Direct Connect link aggregation group {0}.".format(lag_id),
- last_traceback=traceback.format_exc(),
- exception=e)
+ raise DirectConnectError(
+ msg=f"Failed to delete Direct Connect link aggregation group {lag_id}.",
+ last_traceback=traceback.format_exc(),
+ exception=e,
+ )
-@AWSRetry.jittered_backoff(retries=5, delay=2, backoff=2.0, catch_extra_error_codes=['DirectConnectClientException'])
+@AWSRetry.jittered_backoff(retries=5, delay=2, backoff=2.0, catch_extra_error_codes=["DirectConnectClientException"])
def _update_lag(client, lag_id, lag_name, min_links):
params = {}
if min_links:
@@ -284,10 +285,9 @@ def update_lag(client, lag_id, lag_name, min_links, num_connections, wait, wait_
if min_links and min_links > num_connections:
raise DirectConnectError(
- msg="The number of connections {0} must be greater than the minimum number of links "
- "{1} to update the LAG {2}".format(num_connections, min_links, lag_id),
+ msg=f"The number of connections {num_connections} must be greater than the minimum number of links {min_links} to update the LAG {lag_id}",
last_traceback=None,
- exception=None
+ exception=None,
)
while True:
@@ -296,27 +296,29 @@ def update_lag(client, lag_id, lag_name, min_links, num_connections, wait, wait_
except botocore.exceptions.ClientError as e:
if wait and time.time() - start <= wait_timeout:
continue
- msg = "Failed to update Direct Connect link aggregation group {0}.".format(lag_id)
- if "MinimumLinks cannot be set higher than the number of connections" in e.response['Error']['Message']:
- msg += "Unable to set the min number of links to {0} while the LAG connections are being requested".format(min_links)
- raise DirectConnectError(msg=msg,
- last_traceback=traceback.format_exc(),
- exception=e)
+ msg = f"Failed to update Direct Connect link aggregation group {lag_id}."
+ if "MinimumLinks cannot be set higher than the number of connections" in e.response["Error"]["Message"]:
+ msg += f"Unable to set the min number of links to {min_links} while the LAG connections are being requested"
+ raise DirectConnectError(msg=msg, last_traceback=traceback.format_exc(), exception=e)
else:
break
def lag_changed(current_status, name, min_links):
- """ Determines if a modifiable link aggregation group attribute has been modified. """
- return (name and name != current_status['lagName']) or (min_links and min_links != current_status['minimumLinks'])
+ """Determines if a modifiable link aggregation group attribute has been modified."""
+ return (name and name != current_status["lagName"]) or (min_links and min_links != current_status["minimumLinks"])
-def ensure_present(client, num_connections, lag_id, lag_name, location, bandwidth, connection_id, min_links, wait, wait_timeout):
+def ensure_present(
+ client, num_connections, lag_id, lag_name, location, bandwidth, connection_id, min_links, wait, wait_timeout
+):
exists = lag_exists(client, lag_id, lag_name)
if not exists and lag_id:
- raise DirectConnectError(msg="The Direct Connect link aggregation group {0} does not exist.".format(lag_id),
- last_traceback=None,
- exception="")
+ raise DirectConnectError(
+ msg=f"The Direct Connect link aggregation group {lag_id} does not exist.",
+ last_traceback=None,
+ exception="",
+ )
# the connection is found; get the latest state and see if it needs to be updated
if exists:
@@ -338,27 +340,31 @@ def describe_virtual_interfaces(client, lag_id):
try:
response = client.describe_virtual_interfaces(connectionId=lag_id)
except botocore.exceptions.ClientError as e:
- raise DirectConnectError(msg="Failed to describe any virtual interfaces associated with LAG: {0}".format(lag_id),
- last_traceback=traceback.format_exc(),
- exception=e)
- return response.get('virtualInterfaces', [])
+ raise DirectConnectError(
+ msg=f"Failed to describe any virtual interfaces associated with LAG: {lag_id}",
+ last_traceback=traceback.format_exc(),
+ exception=e,
+ )
+ return response.get("virtualInterfaces", [])
def get_connections_and_virtual_interfaces(client, lag_id):
virtual_interfaces = describe_virtual_interfaces(client, lag_id)
- connections = lag_status(client, lag_id=lag_id).get('connections', [])
+ connections = lag_status(client, lag_id=lag_id).get("connections", [])
return virtual_interfaces, connections
def disassociate_vis(client, lag_id, virtual_interfaces):
for vi in virtual_interfaces:
- delete_virtual_interface(client, vi['virtualInterfaceId'])
+ delete_virtual_interface(client, vi["virtualInterfaceId"])
try:
- response = client.delete_virtual_interface(virtualInterfaceId=vi['virtualInterfaceId'])
+ response = client.delete_virtual_interface(virtualInterfaceId=vi["virtualInterfaceId"])
except botocore.exceptions.ClientError as e:
- raise DirectConnectError(msg="Could not delete virtual interface {0} to delete link aggregation group {1}.".format(vi, lag_id),
- last_traceback=traceback.format_exc(),
- exception=e)
+ raise DirectConnectError(
+ msg=f"Could not delete virtual interface {vi} to delete link aggregation group {lag_id}.",
+ last_traceback=traceback.format_exc(),
+ exception=e,
+ )
def ensure_absent(client, lag_id, lag_name, force_delete, delete_with_disassociation, wait, wait_timeout):
@@ -372,32 +378,41 @@ def ensure_absent(client, lag_id, lag_name, force_delete, delete_with_disassocia
virtual_interfaces, connections = get_connections_and_virtual_interfaces(client, lag_id)
# If min_links is not 0, there are associated connections, or if there are virtual interfaces, ask for force_delete
- if any((latest_status['minimumLinks'], virtual_interfaces, connections)) and not force_delete:
- raise DirectConnectError(msg="There are a minimum number of links, hosted connections, or associated virtual interfaces for LAG {0}. "
- "To force deletion of the LAG use delete_force: True (if the LAG has virtual interfaces they will be deleted). "
- "Optionally, to ensure hosted connections are deleted after disassociation use delete_with_disassociation: True "
- "and wait: True (as Virtual Interfaces may take a few moments to delete)".format(lag_id),
- last_traceback=None,
- exception=None)
+ if any((latest_status["minimumLinks"], virtual_interfaces, connections)) and not force_delete:
+ raise DirectConnectError(
+ msg=(
+ "There are a minimum number of links, hosted connections, or associated virtual interfaces for LAG"
+ f" {lag_id}. To force deletion of the LAG use delete_force: True (if the LAG has virtual interfaces"
+ " they will be deleted). Optionally, to ensure hosted connections are deleted after disassociation use"
+ " delete_with_disassociation: True and wait: True (as Virtual Interfaces may take a few moments to"
+ " delete)"
+ ),
+ last_traceback=None,
+ exception=None,
+ )
# update min_links to be 0 so we can remove the LAG
update_lag(client, lag_id, None, 0, len(connections), wait, wait_timeout)
# if virtual_interfaces and not delete_vi_with_disassociation: Raise failure; can't delete while vi attached
for connection in connections:
- disassociate_connection_and_lag(client, connection['connectionId'], lag_id)
+ disassociate_connection_and_lag(client, connection["connectionId"], lag_id)
if delete_with_disassociation:
- delete_connection(client, connection['connectionId'])
+ delete_connection(client, connection["connectionId"])
for vi in virtual_interfaces:
- delete_virtual_interface(client, vi['virtualInterfaceId'])
+ delete_virtual_interface(client, vi["virtualInterfaceId"])
start_time = time.time()
while True:
try:
delete_lag(client, lag_id)
except DirectConnectError as e:
- if ('until its Virtual Interfaces are deleted' in e.exception) and (time.time() - start_time < wait_timeout) and wait:
+ if (
+ ("until its Virtual Interfaces are deleted" in e.exception)
+ and (time.time() - start_time < wait_timeout)
+ and wait
+ ):
continue
else:
return True
@@ -405,54 +420,58 @@ def ensure_absent(client, lag_id, lag_name, force_delete, delete_with_disassocia
def main():
argument_spec = dict(
- state=dict(required=True, choices=['present', 'absent']),
+ state=dict(required=True, choices=["present", "absent"]),
name=dict(),
link_aggregation_group_id=dict(),
- num_connections=dict(type='int'),
- min_links=dict(type='int'),
+ num_connections=dict(type="int"),
+ min_links=dict(type="int"),
location=dict(),
bandwidth=dict(),
connection_id=dict(),
- delete_with_disassociation=dict(type='bool', default=False),
- force_delete=dict(type='bool', default=False),
- wait=dict(type='bool', default=False),
- wait_timeout=dict(type='int', default=120),
+ delete_with_disassociation=dict(type="bool", default=False),
+ force_delete=dict(type="bool", default=False),
+ wait=dict(type="bool", default=False),
+ wait_timeout=dict(type="int", default=120),
)
module = AnsibleAWSModule(
argument_spec=argument_spec,
- required_one_of=[('link_aggregation_group_id', 'name')],
- required_if=[('state', 'present', ('location', 'bandwidth'))],
+ required_one_of=[("link_aggregation_group_id", "name")],
+ required_if=[("state", "present", ("location", "bandwidth"))],
)
try:
- connection = module.client('directconnect')
+ connection = module.client("directconnect")
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to connect to AWS')
+ module.fail_json_aws(e, msg="Failed to connect to AWS")
- state = module.params.get('state')
+ state = module.params.get("state")
response = {}
try:
- if state == 'present':
- changed, lag_id = ensure_present(connection,
- num_connections=module.params.get("num_connections"),
- lag_id=module.params.get("link_aggregation_group_id"),
- lag_name=module.params.get("name"),
- location=module.params.get("location"),
- bandwidth=module.params.get("bandwidth"),
- connection_id=module.params.get("connection_id"),
- min_links=module.params.get("min_links"),
- wait=module.params.get("wait"),
- wait_timeout=module.params.get("wait_timeout"))
+ if state == "present":
+ changed, lag_id = ensure_present(
+ connection,
+ num_connections=module.params.get("num_connections"),
+ lag_id=module.params.get("link_aggregation_group_id"),
+ lag_name=module.params.get("name"),
+ location=module.params.get("location"),
+ bandwidth=module.params.get("bandwidth"),
+ connection_id=module.params.get("connection_id"),
+ min_links=module.params.get("min_links"),
+ wait=module.params.get("wait"),
+ wait_timeout=module.params.get("wait_timeout"),
+ )
response = lag_status(connection, lag_id)
elif state == "absent":
- changed = ensure_absent(connection,
- lag_id=module.params.get("link_aggregation_group_id"),
- lag_name=module.params.get("name"),
- force_delete=module.params.get("force_delete"),
- delete_with_disassociation=module.params.get("delete_with_disassociation"),
- wait=module.params.get('wait'),
- wait_timeout=module.params.get('wait_timeout'))
+ changed = ensure_absent(
+ connection,
+ lag_id=module.params.get("link_aggregation_group_id"),
+ lag_name=module.params.get("name"),
+ force_delete=module.params.get("force_delete"),
+ delete_with_disassociation=module.params.get("delete_with_disassociation"),
+ wait=module.params.get("wait"),
+ wait_timeout=module.params.get("wait_timeout"),
+ )
except DirectConnectError as e:
if e.last_traceback:
module.fail_json(msg=e.msg, exception=e.last_traceback, **camel_dict_to_snake_dict(e.exception))
@@ -462,5 +481,5 @@ def main():
module.exit_json(changed=changed, **camel_dict_to_snake_dict(response))
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/directconnect_virtual_interface.py b/ansible_collections/community/aws/plugins/modules/directconnect_virtual_interface.py
index 059cd7425..da76d5737 100644
--- a/ansible_collections/community/aws/plugins/modules/directconnect_virtual_interface.py
+++ b/ansible_collections/community/aws/plugins/modules/directconnect_virtual_interface.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: directconnect_virtual_interface
version_added: 1.0.0
@@ -86,12 +84,12 @@ options:
- The virtual interface ID.
type: str
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-RETURN = r'''
+RETURN = r"""
address_family:
description: The address family for the BGP peer.
returned: always
@@ -228,9 +226,9 @@ vlan:
returned: always
type: int
sample: 100
-'''
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
---
- name: create an association between a LAG and connection
community.aws.directconnect_virtual_interface:
@@ -244,81 +242,87 @@ EXAMPLES = r'''
state: absent
connection_id: dxcon-XXXXXXXX
virtual_interface_id: dxv-XXXXXXXX
-
-'''
+"""
import traceback
try:
- from botocore.exceptions import ClientError, BotoCoreError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
except ImportError:
# handled by AnsibleAWSModule
pass
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
from ansible_collections.amazon.aws.plugins.module_utils.direct_connect import DirectConnectError
from ansible_collections.amazon.aws.plugins.module_utils.direct_connect import delete_virtual_interface
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def try_except_ClientError(failure_msg):
- '''
- Wrapper for boto3 calls that uses AWSRetry and handles exceptions
- '''
+ """
+ Wrapper for boto3 calls that uses AWSRetry and handles exceptions
+ """
+
def wrapper(f):
def run_func(*args, **kwargs):
try:
- result = AWSRetry.jittered_backoff(retries=8, delay=5, catch_extra_error_codes=['DirectConnectClientException'])(f)(*args, **kwargs)
+ result = AWSRetry.jittered_backoff(
+ retries=8, delay=5, catch_extra_error_codes=["DirectConnectClientException"]
+ )(f)(*args, **kwargs)
except (ClientError, BotoCoreError) as e:
raise DirectConnectError(failure_msg, traceback.format_exc(), e)
return result
+
return run_func
+
return wrapper
def find_unique_vi(client, connection_id, virtual_interface_id, name):
- '''
- Determines if the virtual interface exists. Returns the virtual interface ID if an exact match is found.
- If multiple matches are found False is returned. If no matches are found None is returned.
- '''
+ """
+ Determines if the virtual interface exists. Returns the virtual interface ID if an exact match is found.
+ If multiple matches are found False is returned. If no matches are found None is returned.
+ """
# Get the virtual interfaces, filtering by the ID if provided.
vi_params = {}
if virtual_interface_id:
- vi_params = {'virtualInterfaceId': virtual_interface_id}
+ vi_params = {"virtualInterfaceId": virtual_interface_id}
- virtual_interfaces = try_except_ClientError(
- failure_msg="Failed to describe virtual interface")(
- client.describe_virtual_interfaces)(**vi_params).get('virtualInterfaces')
+ virtual_interfaces = try_except_ClientError(failure_msg="Failed to describe virtual interface")(
+ client.describe_virtual_interfaces
+ )(**vi_params).get("virtualInterfaces")
# Remove deleting/deleted matches from the results.
- virtual_interfaces = [vi for vi in virtual_interfaces if vi['virtualInterfaceState'] not in ('deleting', 'deleted')]
+ virtual_interfaces = [vi for vi in virtual_interfaces if vi["virtualInterfaceState"] not in ("deleting", "deleted")]
matching_virtual_interfaces = filter_virtual_interfaces(virtual_interfaces, name, connection_id)
return exact_match(matching_virtual_interfaces)
def exact_match(virtual_interfaces):
- '''
- Returns the virtual interface ID if one was found,
- None if the virtual interface ID needs to be created,
- False if an exact match was not found
- '''
+ """
+ Returns the virtual interface ID if one was found,
+ None if the virtual interface ID needs to be created,
+ False if an exact match was not found
+ """
if not virtual_interfaces:
return None
if len(virtual_interfaces) == 1:
- return virtual_interfaces[0]['virtualInterfaceId']
+ return virtual_interfaces[0]["virtualInterfaceId"]
else:
return False
def filter_virtual_interfaces(virtual_interfaces, name, connection_id):
- '''
- Filters the available virtual interfaces to try to find a unique match
- '''
+ """
+ Filters the available virtual interfaces to try to find a unique match
+ """
# Filter by name if provided.
if name:
matching_by_name = find_virtual_interface_by_name(virtual_interfaces, name)
@@ -339,52 +343,56 @@ def filter_virtual_interfaces(virtual_interfaces, name, connection_id):
def find_virtual_interface_by_connection_id(virtual_interfaces, connection_id):
- '''
- Return virtual interfaces that have the connection_id associated
- '''
- return [vi for vi in virtual_interfaces if vi['connectionId'] == connection_id]
+ """
+ Return virtual interfaces that have the connection_id associated
+ """
+ return [vi for vi in virtual_interfaces if vi["connectionId"] == connection_id]
def find_virtual_interface_by_name(virtual_interfaces, name):
- '''
- Return virtual interfaces that match the provided name
- '''
- return [vi for vi in virtual_interfaces if vi['virtualInterfaceName'] == name]
+ """
+ Return virtual interfaces that match the provided name
+ """
+ return [vi for vi in virtual_interfaces if vi["virtualInterfaceName"] == name]
def vi_state(client, virtual_interface_id):
- '''
- Returns the state of the virtual interface.
- '''
- err_msg = "Failed to describe virtual interface: {0}".format(virtual_interface_id)
- vi = try_except_ClientError(failure_msg=err_msg)(client.describe_virtual_interfaces)(virtualInterfaceId=virtual_interface_id)
- return vi['virtualInterfaces'][0]
+ """
+ Returns the state of the virtual interface.
+ """
+ err_msg = f"Failed to describe virtual interface: {virtual_interface_id}"
+ vi = try_except_ClientError(failure_msg=err_msg)(client.describe_virtual_interfaces)(
+ virtualInterfaceId=virtual_interface_id
+ )
+ return vi["virtualInterfaces"][0]
def assemble_params_for_creating_vi(params):
- '''
- Returns kwargs to use in the call to create the virtual interface
-
- Params for public virtual interfaces:
- virtualInterfaceName, vlan, asn, authKey, amazonAddress, customerAddress, addressFamily, cidr
- Params for private virtual interfaces:
- virtualInterfaceName, vlan, asn, authKey, amazonAddress, customerAddress, addressFamily, virtualGatewayId
- '''
-
- public = params['public']
- name = params['name']
- vlan = params['vlan']
- bgp_asn = params['bgp_asn']
- auth_key = params['authentication_key']
- amazon_addr = params['amazon_address']
- customer_addr = params['customer_address']
- family_addr = params['address_type']
- cidr = params['cidr']
- virtual_gateway_id = params['virtual_gateway_id']
- direct_connect_gateway_id = params['direct_connect_gateway_id']
+ """
+ Returns kwargs to use in the call to create the virtual interface
+
+ Params for public virtual interfaces:
+ virtualInterfaceName, vlan, asn, authKey, amazonAddress, customerAddress, addressFamily, cidr
+ Params for private virtual interfaces:
+ virtualInterfaceName, vlan, asn, authKey, amazonAddress, customerAddress, addressFamily, virtualGatewayId
+ """
+
+ public = params["public"]
+ name = params["name"]
+ vlan = params["vlan"]
+ bgp_asn = params["bgp_asn"]
+ auth_key = params["authentication_key"]
+ amazon_addr = params["amazon_address"]
+ customer_addr = params["customer_address"]
+ family_addr = params["address_type"]
+ cidr = params["cidr"]
+ virtual_gateway_id = params["virtual_gateway_id"]
+ direct_connect_gateway_id = params["direct_connect_gateway_id"]
parameters = dict(virtualInterfaceName=name, vlan=vlan, asn=bgp_asn)
- opt_params = dict(authKey=auth_key, amazonAddress=amazon_addr, customerAddress=customer_addr, addressFamily=family_addr)
+ opt_params = dict(
+ authKey=auth_key, amazonAddress=amazon_addr, customerAddress=customer_addr, addressFamily=family_addr
+ )
for name, value in opt_params.items():
if value:
@@ -392,68 +400,74 @@ def assemble_params_for_creating_vi(params):
# virtual interface type specific parameters
if public and cidr:
- parameters['routeFilterPrefixes'] = [{'cidr': c} for c in cidr]
+ parameters["routeFilterPrefixes"] = [{"cidr": c} for c in cidr]
if not public:
if virtual_gateway_id:
- parameters['virtualGatewayId'] = virtual_gateway_id
+ parameters["virtualGatewayId"] = virtual_gateway_id
elif direct_connect_gateway_id:
- parameters['directConnectGatewayId'] = direct_connect_gateway_id
+ parameters["directConnectGatewayId"] = direct_connect_gateway_id
return parameters
def create_vi(client, public, associated_id, creation_params):
- '''
- :param public: a boolean
- :param associated_id: a link aggregation group ID or connection ID to associate
- with the virtual interface.
- :param creation_params: a dict of parameters to use in the AWS SDK call
- :return The ID of the created virtual interface
- '''
+ """
+ :param public: a boolean
+ :param associated_id: a link aggregation group ID or connection ID to associate
+ with the virtual interface.
+ :param creation_params: a dict of parameters to use in the AWS SDK call
+ :return The ID of the created virtual interface
+ """
err_msg = "Failed to create virtual interface"
if public:
- vi = try_except_ClientError(failure_msg=err_msg)(client.create_public_virtual_interface)(connectionId=associated_id,
- newPublicVirtualInterface=creation_params)
+ vi = try_except_ClientError(failure_msg=err_msg)(client.create_public_virtual_interface)(
+ connectionId=associated_id, newPublicVirtualInterface=creation_params
+ )
else:
- vi = try_except_ClientError(failure_msg=err_msg)(client.create_private_virtual_interface)(connectionId=associated_id,
- newPrivateVirtualInterface=creation_params)
- return vi['virtualInterfaceId']
+ vi = try_except_ClientError(failure_msg=err_msg)(client.create_private_virtual_interface)(
+ connectionId=associated_id, newPrivateVirtualInterface=creation_params
+ )
+ return vi["virtualInterfaceId"]
def modify_vi(client, virtual_interface_id, connection_id):
- '''
- Associate a new connection ID
- '''
- err_msg = "Unable to associate {0} with virtual interface {1}".format(connection_id, virtual_interface_id)
- try_except_ClientError(failure_msg=err_msg)(client.associate_virtual_interface)(virtualInterfaceId=virtual_interface_id,
- connectionId=connection_id)
+ """
+ Associate a new connection ID
+ """
+ err_msg = f"Unable to associate {connection_id} with virtual interface {virtual_interface_id}"
+ try_except_ClientError(failure_msg=err_msg)(client.associate_virtual_interface)(
+ virtualInterfaceId=virtual_interface_id, connectionId=connection_id
+ )
def needs_modification(client, virtual_interface_id, connection_id):
- '''
- Determine if the associated connection ID needs to be updated
- '''
- return vi_state(client, virtual_interface_id).get('connectionId') != connection_id
+ """
+ Determine if the associated connection ID needs to be updated
+ """
+ return vi_state(client, virtual_interface_id).get("connectionId") != connection_id
def ensure_state(connection, module):
changed = False
- state = module.params['state']
- connection_id = module.params['id_to_associate']
- public = module.params['public']
- name = module.params['name']
+ state = module.params["state"]
+ connection_id = module.params["id_to_associate"]
+ public = module.params["public"]
+ name = module.params["name"]
- virtual_interface_id = find_unique_vi(connection, connection_id, module.params.get('virtual_interface_id'), name)
+ virtual_interface_id = find_unique_vi(connection, connection_id, module.params.get("virtual_interface_id"), name)
if virtual_interface_id is False:
- module.fail_json(msg="Multiple virtual interfaces were found. Use the virtual_interface_id, name, "
- "and connection_id options if applicable to find a unique match.")
-
- if state == 'present':
+ module.fail_json(
+ msg=(
+ "Multiple virtual interfaces were found. Use the virtual_interface_id, name, "
+ "and connection_id options if applicable to find a unique match."
+ )
+ )
- if not virtual_interface_id and module.params['virtual_interface_id']:
- module.fail_json(msg="The virtual interface {0} does not exist.".format(module.params['virtual_interface_id']))
+ if state == "present":
+ if not virtual_interface_id and module.params["virtual_interface_id"]:
+ module.fail_json(msg=f"The virtual interface {module.params['virtual_interface_id']} does not exist.")
elif not virtual_interface_id:
assembled_params = assemble_params_for_creating_vi(module.params)
@@ -478,31 +492,35 @@ def ensure_state(connection, module):
def main():
argument_spec = dict(
- state=dict(required=True, choices=['present', 'absent']),
- id_to_associate=dict(required=True, aliases=['link_aggregation_group_id', 'connection_id']),
- public=dict(type='bool'),
+ state=dict(required=True, choices=["present", "absent"]),
+ id_to_associate=dict(required=True, aliases=["link_aggregation_group_id", "connection_id"]),
+ public=dict(type="bool"),
name=dict(),
- vlan=dict(type='int', default=100),
- bgp_asn=dict(type='int', default=65000),
+ vlan=dict(type="int", default=100),
+ bgp_asn=dict(type="int", default=65000),
authentication_key=dict(no_log=True),
amazon_address=dict(),
customer_address=dict(),
address_type=dict(),
- cidr=dict(type='list', elements='str'),
+ cidr=dict(type="list", elements="str"),
virtual_gateway_id=dict(),
direct_connect_gateway_id=dict(),
- virtual_interface_id=dict()
+ virtual_interface_id=dict(),
)
- module = AnsibleAWSModule(argument_spec=argument_spec,
- required_one_of=[['virtual_interface_id', 'name']],
- required_if=[['state', 'present', ['public']],
- ['public', True, ['amazon_address']],
- ['public', True, ['customer_address']],
- ['public', True, ['cidr']]],
- mutually_exclusive=[['virtual_gateway_id', 'direct_connect_gateway_id']])
+ module = AnsibleAWSModule(
+ argument_spec=argument_spec,
+ required_one_of=[["virtual_interface_id", "name"]],
+ required_if=[
+ ["state", "present", ["public"]],
+ ["public", True, ["amazon_address"]],
+ ["public", True, ["customer_address"]],
+ ["public", True, ["cidr"]],
+ ],
+ mutually_exclusive=[["virtual_gateway_id", "direct_connect_gateway_id"]],
+ )
- connection = module.client('directconnect')
+ connection = module.client("directconnect")
try:
changed, latest_state = ensure_state(connection, module)
@@ -515,5 +533,5 @@ def main():
module.exit_json(changed=changed, **camel_dict_to_snake_dict(latest_state))
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/dms_endpoint.py b/ansible_collections/community/aws/plugins/modules/dms_endpoint.py
index fb899d669..f67a1263e 100644
--- a/ansible_collections/community/aws/plugins/modules/dms_endpoint.py
+++ b/ansible_collections/community/aws/plugins/modules/dms_endpoint.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
-# This file is part of Ansible
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
+# -*- coding: utf-8 -*-
+# Copyright: Contributors to the Ansible project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: dms_endpoint
version_added: 1.0.0
@@ -143,13 +141,13 @@ options:
author:
- "Rui Moreira (@ruimoreira)"
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
- amazon.aws.tags
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
# Note: These examples do not set authentication details
- name: Endpoint Creation
community.aws.dms_endpoint:
@@ -164,9 +162,9 @@ EXAMPLES = '''
databasename: 'testdb'
sslmode: none
wait: false
-'''
+"""
-RETURN = '''
+RETURN = r"""
endpoint:
description:
- A description of the DMS endpoint.
@@ -325,7 +323,7 @@ endpoint:
- Additional settings for Redis endpoints.
type: dict
returned: when the I(endpoint_type) is C(redshift)
-'''
+"""
try:
import botocore
@@ -334,20 +332,21 @@ except ImportError:
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
from ansible_collections.amazon.aws.plugins.module_utils.tagging import ansible_dict_to_boto3_tag_list
from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
from ansible_collections.amazon.aws.plugins.module_utils.tagging import compare_aws_tags
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
+
backoff_params = dict(retries=5, delay=1, backoff=1.5)
@AWSRetry.jittered_backoff(**backoff_params)
def dms_describe_tags(connection, **params):
- """ checks if the endpoint exists """
- tags = connection.list_tags_for_resource(**params).get('TagList', [])
+ """checks if the endpoint exists"""
+ tags = connection.list_tags_for_resource(**params).get("TagList", [])
return boto3_tag_list_to_ansible_dict(tags)
@@ -355,15 +354,14 @@ def dms_describe_tags(connection, **params):
def dms_describe_endpoints(connection, **params):
try:
endpoints = connection.describe_endpoints(**params)
- except is_boto3_error_code('ResourceNotFoundFault'):
+ except is_boto3_error_code("ResourceNotFoundFault"):
return None
- return endpoints.get('Endpoints', None)
+ return endpoints.get("Endpoints", None)
def describe_endpoint(connection, endpoint_identifier):
- """ checks if the endpoint exists """
- endpoint_filter = dict(Name='endpoint-id',
- Values=[endpoint_identifier])
+ """checks if the endpoint exists"""
+ endpoint_filter = dict(Name="endpoint-id", Values=[endpoint_identifier])
try:
endpoints = dms_describe_endpoints(connection, Filters=[endpoint_filter])
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
@@ -374,8 +372,8 @@ def describe_endpoint(connection, endpoint_identifier):
endpoint = endpoints[0]
try:
- tags = dms_describe_tags(connection, ResourceArn=endpoint['EndpointArn'])
- endpoint['tags'] = tags
+ tags = dms_describe_tags(connection, ResourceArn=endpoint["EndpointArn"])
+ endpoint["tags"] = tags
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Failed to describe the DMS endpoint tags")
return endpoint
@@ -384,7 +382,7 @@ def describe_endpoint(connection, endpoint_identifier):
@AWSRetry.jittered_backoff(**backoff_params)
def dms_delete_endpoint(client, **params):
"""deletes the DMS endpoint based on the EndpointArn"""
- if module.params.get('wait'):
+ if module.params.get("wait"):
return delete_dms_endpoint(client)
else:
return client.delete_endpoint(**params)
@@ -392,19 +390,19 @@ def dms_delete_endpoint(client, **params):
@AWSRetry.jittered_backoff(**backoff_params)
def dms_create_endpoint(client, **params):
- """ creates the DMS endpoint"""
+ """creates the DMS endpoint"""
return client.create_endpoint(**params)
@AWSRetry.jittered_backoff(**backoff_params)
def dms_modify_endpoint(client, **params):
- """ updates the endpoint"""
+ """updates the endpoint"""
return client.modify_endpoint(**params)
@AWSRetry.jittered_backoff(**backoff_params)
def get_endpoint_deleted_waiter(client):
- return client.get_waiter('endpoint_deleted')
+ return client.get_waiter("endpoint_deleted")
@AWSRetry.jittered_backoff(**backoff_params)
@@ -418,32 +416,22 @@ def dms_add_tags(client, **params):
def endpoint_exists(endpoint):
- """ Returns boolean based on the existence of the endpoint
+ """Returns boolean based on the existence of the endpoint
:param endpoint: dict containing the described endpoint
:return: bool
"""
- return bool(len(endpoint['Endpoints']))
+ return bool(len(endpoint["Endpoints"]))
def delete_dms_endpoint(connection, endpoint_arn):
try:
- delete_arn = dict(
- EndpointArn=endpoint_arn
- )
- if module.params.get('wait'):
-
+ delete_arn = dict(EndpointArn=endpoint_arn)
+ if module.params.get("wait"):
delete_output = connection.delete_endpoint(**delete_arn)
delete_waiter = get_endpoint_deleted_waiter(connection)
delete_waiter.wait(
- Filters=[{
- 'Name': 'endpoint-arn',
- 'Values': [endpoint_arn]
-
- }],
- WaiterConfig={
- 'Delay': module.params.get('timeout'),
- 'MaxAttempts': module.params.get('retries')
- }
+ Filters=[{"Name": "endpoint-arn", "Values": [endpoint_arn]}],
+ WaiterConfig={"Delay": module.params.get("timeout"), "MaxAttempts": module.params.get("retries")},
)
return delete_output
else:
@@ -458,71 +446,62 @@ def create_module_params():
:return: dict
"""
endpoint_parameters = dict(
- EndpointIdentifier=module.params.get('endpointidentifier'),
- EndpointType=module.params.get('endpointtype'),
- EngineName=module.params.get('enginename'),
- Username=module.params.get('username'),
- Password=module.params.get('password'),
- ServerName=module.params.get('servername'),
- Port=module.params.get('port'),
- DatabaseName=module.params.get('databasename'),
- SslMode=module.params.get('sslmode')
+ EndpointIdentifier=module.params.get("endpointidentifier"),
+ EndpointType=module.params.get("endpointtype"),
+ EngineName=module.params.get("enginename"),
+ Username=module.params.get("username"),
+ Password=module.params.get("password"),
+ ServerName=module.params.get("servername"),
+ Port=module.params.get("port"),
+ DatabaseName=module.params.get("databasename"),
+ SslMode=module.params.get("sslmode"),
)
- if module.params.get('EndpointArn'):
- endpoint_parameters['EndpointArn'] = module.params.get('EndpointArn')
- if module.params.get('certificatearn'):
- endpoint_parameters['CertificateArn'] = \
- module.params.get('certificatearn')
+ if module.params.get("EndpointArn"):
+ endpoint_parameters["EndpointArn"] = module.params.get("EndpointArn")
+ if module.params.get("certificatearn"):
+ endpoint_parameters["CertificateArn"] = module.params.get("certificatearn")
- if module.params.get('dmstransfersettings'):
- endpoint_parameters['DmsTransferSettings'] = \
- module.params.get('dmstransfersettings')
+ if module.params.get("dmstransfersettings"):
+ endpoint_parameters["DmsTransferSettings"] = module.params.get("dmstransfersettings")
- if module.params.get('extraconnectionattributes'):
- endpoint_parameters['ExtraConnectionAttributes'] =\
- module.params.get('extraconnectionattributes')
+ if module.params.get("extraconnectionattributes"):
+ endpoint_parameters["ExtraConnectionAttributes"] = module.params.get("extraconnectionattributes")
- if module.params.get('kmskeyid'):
- endpoint_parameters['KmsKeyId'] = module.params.get('kmskeyid')
+ if module.params.get("kmskeyid"):
+ endpoint_parameters["KmsKeyId"] = module.params.get("kmskeyid")
- if module.params.get('tags'):
- endpoint_parameters['Tags'] = module.params.get('tags')
+ if module.params.get("tags"):
+ endpoint_parameters["Tags"] = module.params.get("tags")
- if module.params.get('serviceaccessrolearn'):
- endpoint_parameters['ServiceAccessRoleArn'] = \
- module.params.get('serviceaccessrolearn')
+ if module.params.get("serviceaccessrolearn"):
+ endpoint_parameters["ServiceAccessRoleArn"] = module.params.get("serviceaccessrolearn")
- if module.params.get('externaltabledefinition'):
- endpoint_parameters['ExternalTableDefinition'] = \
- module.params.get('externaltabledefinition')
+ if module.params.get("externaltabledefinition"):
+ endpoint_parameters["ExternalTableDefinition"] = module.params.get("externaltabledefinition")
- if module.params.get('dynamodbsettings'):
- endpoint_parameters['DynamoDbSettings'] = \
- module.params.get('dynamodbsettings')
+ if module.params.get("dynamodbsettings"):
+ endpoint_parameters["DynamoDbSettings"] = module.params.get("dynamodbsettings")
- if module.params.get('s3settings'):
- endpoint_parameters['S3Settings'] = module.params.get('s3settings')
+ if module.params.get("s3settings"):
+ endpoint_parameters["S3Settings"] = module.params.get("s3settings")
- if module.params.get('mongodbsettings'):
- endpoint_parameters['MongoDbSettings'] = \
- module.params.get('mongodbsettings')
+ if module.params.get("mongodbsettings"):
+ endpoint_parameters["MongoDbSettings"] = module.params.get("mongodbsettings")
- if module.params.get('kinesissettings'):
- endpoint_parameters['KinesisSettings'] = \
- module.params.get('kinesissettings')
+ if module.params.get("kinesissettings"):
+ endpoint_parameters["KinesisSettings"] = module.params.get("kinesissettings")
- if module.params.get('elasticsearchsettings'):
- endpoint_parameters['ElasticsearchSettings'] = \
- module.params.get('elasticsearchsettings')
+ if module.params.get("elasticsearchsettings"):
+ endpoint_parameters["ElasticsearchSettings"] = module.params.get("elasticsearchsettings")
- if module.params.get('wait'):
- endpoint_parameters['wait'] = module.boolean(module.params.get('wait'))
+ if module.params.get("wait"):
+ endpoint_parameters["wait"] = module.boolean(module.params.get("wait"))
- if module.params.get('timeout'):
- endpoint_parameters['timeout'] = module.params.get('timeout')
+ if module.params.get("timeout"):
+ endpoint_parameters["timeout"] = module.params.get("timeout")
- if module.params.get('retries'):
- endpoint_parameters['retries'] = module.params.get('retries')
+ if module.params.get("retries"):
+ endpoint_parameters["retries"] = module.params.get("retries")
return endpoint_parameters
@@ -538,14 +517,16 @@ def compare_params(param_described):
param_described = dict(param_described)
modparams = create_module_params()
# modify can't update tags
- param_described.pop('Tags', None)
- modparams.pop('Tags', None)
+ param_described.pop("Tags", None)
+ modparams.pop("Tags", None)
changed = False
for paramname in modparams:
- if paramname == 'Password' or paramname in param_described \
- and param_described[paramname] == modparams[paramname] or \
- str(param_described[paramname]).lower() \
- == modparams[paramname]:
+ if (
+ paramname == "Password"
+ or paramname in param_described
+ and param_described[paramname] == modparams[paramname]
+ or str(param_described[paramname]).lower() == modparams[paramname]
+ ):
pass
else:
changed = True
@@ -553,25 +534,24 @@ def compare_params(param_described):
def modify_dms_endpoint(connection, endpoint):
- arn = endpoint['EndpointArn']
+ arn = endpoint["EndpointArn"]
try:
params = create_module_params()
# modify can't update tags
- params.pop('Tags', None)
+ params.pop("Tags", None)
return dms_modify_endpoint(connection, EndpointArn=arn, **params)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Failed to update DMS endpoint.", params=params)
def ensure_tags(connection, endpoint):
- desired_tags = module.params.get('tags', None)
+ desired_tags = module.params.get("tags", None)
if desired_tags is None:
return False
- current_tags = endpoint.get('tags', {})
+ current_tags = endpoint.get("tags", {})
- tags_to_add, tags_to_remove = compare_aws_tags(current_tags, desired_tags,
- module.params.get('purge_tags'))
+ tags_to_add, tags_to_remove = compare_aws_tags(current_tags, desired_tags, module.params.get("purge_tags"))
if not tags_to_remove and not tags_to_add:
return False
@@ -579,7 +559,7 @@ def ensure_tags(connection, endpoint):
if module.check_mode:
return True
- arn = endpoint.get('EndpointArn')
+ arn = endpoint.get("EndpointArn")
try:
if tags_to_remove:
@@ -609,36 +589,49 @@ def create_dms_endpoint(connection):
def main():
argument_spec = dict(
- state=dict(choices=['present', 'absent'], default='present'),
+ state=dict(choices=["present", "absent"], default="present"),
endpointidentifier=dict(required=True),
- endpointtype=dict(choices=['source', 'target']),
- enginename=dict(choices=['mysql', 'oracle', 'postgres', 'mariadb',
- 'aurora', 'redshift', 's3', 'db2', 'azuredb',
- 'sybase', 'dynamodb', 'mongodb', 'sqlserver'],
- required=False),
+ endpointtype=dict(choices=["source", "target"]),
+ enginename=dict(
+ choices=[
+ "mysql",
+ "oracle",
+ "postgres",
+ "mariadb",
+ "aurora",
+ "redshift",
+ "s3",
+ "db2",
+ "azuredb",
+ "sybase",
+ "dynamodb",
+ "mongodb",
+ "sqlserver",
+ ],
+ required=False,
+ ),
username=dict(),
password=dict(no_log=True),
servername=dict(),
- port=dict(type='int'),
+ port=dict(type="int"),
databasename=dict(),
extraconnectionattributes=dict(),
kmskeyid=dict(no_log=False),
- tags=dict(type='dict', aliases=['resource_tags']),
- purge_tags=dict(type='bool', default=True),
+ tags=dict(type="dict", aliases=["resource_tags"]),
+ purge_tags=dict(type="bool", default=True),
certificatearn=dict(),
- sslmode=dict(choices=['none', 'require', 'verify-ca', 'verify-full'],
- default='none'),
+ sslmode=dict(choices=["none", "require", "verify-ca", "verify-full"], default="none"),
serviceaccessrolearn=dict(),
externaltabledefinition=dict(),
- dynamodbsettings=dict(type='dict'),
- s3settings=dict(type='dict'),
- dmstransfersettings=dict(type='dict'),
- mongodbsettings=dict(type='dict'),
- kinesissettings=dict(type='dict'),
- elasticsearchsettings=dict(type='dict'),
- wait=dict(type='bool', default=False),
- timeout=dict(type='int'),
- retries=dict(type='int')
+ dynamodbsettings=dict(type="dict"),
+ s3settings=dict(type="dict"),
+ dmstransfersettings=dict(type="dict"),
+ mongodbsettings=dict(type="dict"),
+ kinesissettings=dict(type="dict"),
+ elasticsearchsettings=dict(type="dict"),
+ wait=dict(type="bool", default=False),
+ timeout=dict(type="int"),
+ retries=dict(type="int"),
)
global module
module = AnsibleAWSModule(
@@ -650,49 +643,48 @@ def main():
["wait", "True", ["timeout"]],
["wait", "True", ["retries"]],
],
- supports_check_mode=False
+ supports_check_mode=False,
)
exit_message = None
changed = False
- state = module.params.get('state')
+ state = module.params.get("state")
- dmsclient = module.client('dms')
- endpoint = describe_endpoint(dmsclient,
- module.params.get('endpointidentifier'))
- if state == 'present':
+ dmsclient = module.client("dms")
+ endpoint = describe_endpoint(dmsclient, module.params.get("endpointidentifier"))
+ if state == "present":
if endpoint:
changed |= ensure_tags(dmsclient, endpoint)
params_changed = compare_params(endpoint)
if params_changed:
updated_dms = modify_dms_endpoint(dmsclient, endpoint)
exit_message = updated_dms
- endpoint = exit_message.get('Endpoint')
+ endpoint = exit_message.get("Endpoint")
changed = True
else:
exit_message = "Endpoint Already Exists"
else:
exit_message = create_dms_endpoint(dmsclient)
- endpoint = exit_message.get('Endpoint')
+ endpoint = exit_message.get("Endpoint")
changed = True
if changed:
# modify and create don't return tags
- tags = dms_describe_tags(dmsclient, ResourceArn=endpoint['EndpointArn'])
- endpoint['tags'] = tags
- elif state == 'absent':
+ tags = dms_describe_tags(dmsclient, ResourceArn=endpoint["EndpointArn"])
+ endpoint["tags"] = tags
+ elif state == "absent":
if endpoint:
- delete_results = delete_dms_endpoint(dmsclient, endpoint['EndpointArn'])
+ delete_results = delete_dms_endpoint(dmsclient, endpoint["EndpointArn"])
exit_message = delete_results
endpoint = None
changed = True
else:
changed = False
- exit_message = 'DMS Endpoint does not exist'
+ exit_message = "DMS Endpoint does not exist"
- endpoint = camel_dict_to_snake_dict(endpoint or {}, ignore_list=['tags'])
+ endpoint = camel_dict_to_snake_dict(endpoint or {}, ignore_list=["tags"])
module.exit_json(changed=changed, endpoint=endpoint, msg=exit_message)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/dms_replication_subnet_group.py b/ansible_collections/community/aws/plugins/modules/dms_replication_subnet_group.py
index fb5d59613..772a54aa1 100644
--- a/ansible_collections/community/aws/plugins/modules/dms_replication_subnet_group.py
+++ b/ansible_collections/community/aws/plugins/modules/dms_replication_subnet_group.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: dms_replication_subnet_group
version_added: 1.0.0
@@ -43,29 +41,29 @@ options:
author:
- "Rui Moreira (@ruimoreira)"
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-'''
-
-EXAMPLES = '''
+EXAMPLES = r"""
- community.aws.dms_replication_subnet_group:
state: present
identifier: "dev-sngroup"
description: "Development Subnet Group asdasdas"
- subnet_ids: ['subnet-id1','subnet-id2']
-'''
+ subnet_ids: ['subnet-id1', 'subnet-id2']
+"""
-RETURN = ''' # '''
+RETURN = r""" # """
try:
import botocore
except ImportError:
pass # caught by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
backoff_params = dict(retries=5, delay=1, backoff=1.5)
@@ -74,16 +72,15 @@ backoff_params = dict(retries=5, delay=1, backoff=1.5)
def describe_subnet_group(connection, subnet_group):
"""checks if instance exists"""
try:
- subnet_group_filter = dict(Name='replication-subnet-group-id',
- Values=[subnet_group])
+ subnet_group_filter = dict(Name="replication-subnet-group-id", Values=[subnet_group])
return connection.describe_replication_subnet_groups(Filters=[subnet_group_filter])
except botocore.exceptions.ClientError:
- return {'ReplicationSubnetGroups': []}
+ return {"ReplicationSubnetGroups": []}
@AWSRetry.jittered_backoff(**backoff_params)
def replication_subnet_group_create(connection, **params):
- """ creates the replication subnet group """
+ """creates the replication subnet group"""
return connection.create_replication_subnet_group(**params)
@@ -94,17 +91,17 @@ def replication_subnet_group_modify(connection, **modify_params):
@AWSRetry.jittered_backoff(**backoff_params)
def replication_subnet_group_delete(module, connection):
- subnetid = module.params.get('identifier')
+ subnetid = module.params.get("identifier")
delete_parameters = dict(ReplicationSubnetGroupIdentifier=subnetid)
return connection.delete_replication_subnet_group(**delete_parameters)
def replication_subnet_exists(subnet):
- """ Returns boolean based on the existence of the endpoint
+ """Returns boolean based on the existence of the endpoint
:param endpoint: dict containing the described endpoint
:return: bool
"""
- return bool(len(subnet['ReplicationSubnetGroups']))
+ return bool(len(subnet["ReplicationSubnetGroups"]))
def create_module_params(module):
@@ -114,9 +111,9 @@ def create_module_params(module):
"""
instance_parameters = dict(
# ReplicationSubnetGroupIdentifier gets translated to lower case anyway by the API
- ReplicationSubnetGroupIdentifier=module.params.get('identifier').lower(),
- ReplicationSubnetGroupDescription=module.params.get('description'),
- SubnetIds=module.params.get('subnet_ids'),
+ ReplicationSubnetGroupIdentifier=module.params.get("identifier").lower(),
+ ReplicationSubnetGroupDescription=module.params.get("description"),
+ SubnetIds=module.params.get("subnet_ids"),
)
return instance_parameters
@@ -133,19 +130,18 @@ def compare_params(module, param_described):
modparams = create_module_params(module)
changed = False
# need to sanitize values that get returned from the API
- if 'VpcId' in param_described.keys():
- param_described.pop('VpcId')
- if 'SubnetGroupStatus' in param_described.keys():
- param_described.pop('SubnetGroupStatus')
+ if "VpcId" in param_described.keys():
+ param_described.pop("VpcId")
+ if "SubnetGroupStatus" in param_described.keys():
+ param_described.pop("SubnetGroupStatus")
for paramname in modparams.keys():
- if paramname in param_described.keys() and \
- param_described.get(paramname) == modparams[paramname]:
+ if paramname in param_described.keys() and param_described.get(paramname) == modparams[paramname]:
pass
- elif paramname == 'SubnetIds':
+ elif paramname == "SubnetIds":
subnets = []
- for subnet in param_described.get('Subnets'):
- subnets.append(subnet.get('SubnetIdentifier'))
- for modulesubnet in modparams['SubnetIds']:
+ for subnet in param_described.get("Subnets"):
+ subnets.append(subnet.get("SubnetIdentifier"))
+ for modulesubnet in modparams["SubnetIds"]:
if modulesubnet in subnets:
pass
else:
@@ -171,23 +167,19 @@ def modify_replication_subnet_group(module, connection):
def main():
argument_spec = dict(
- state=dict(type='str', choices=['present', 'absent'], default='present'),
- identifier=dict(type='str', required=True),
- description=dict(type='str', required=True),
- subnet_ids=dict(type='list', elements='str', required=True),
- )
- module = AnsibleAWSModule(
- argument_spec=argument_spec,
- supports_check_mode=True
+ state=dict(type="str", choices=["present", "absent"], default="present"),
+ identifier=dict(type="str", required=True),
+ description=dict(type="str", required=True),
+ subnet_ids=dict(type="list", elements="str", required=True),
)
+ module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
exit_message = None
changed = False
- state = module.params.get('state')
- dmsclient = module.client('dms')
- subnet_group = describe_subnet_group(dmsclient,
- module.params.get('identifier'))
- if state == 'present':
+ state = module.params.get("state")
+ dmsclient = module.client("dms")
+ subnet_group = describe_subnet_group(dmsclient, module.params.get("identifier"))
+ if state == "present":
if replication_subnet_exists(subnet_group):
if compare_params(module, subnet_group["ReplicationSubnetGroups"][0]):
if not module.check_mode:
@@ -204,7 +196,7 @@ def main():
else:
exit_message = "Check mode enabled"
- elif state == 'absent':
+ elif state == "absent":
if replication_subnet_exists(subnet_group):
if not module.check_mode:
replication_subnet_group_delete(module, dmsclient)
@@ -221,5 +213,5 @@ def main():
module.exit_json(changed=changed, msg=exit_message)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/dynamodb_table.py b/ansible_collections/community/aws/plugins/modules/dynamodb_table.py
index 28d334fc9..86ba2f05e 100644
--- a/ansible_collections/community/aws/plugins/modules/dynamodb_table.py
+++ b/ansible_collections/community/aws/plugins/modules/dynamodb_table.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: dynamodb_table
version_added: 1.0.0
@@ -125,30 +123,31 @@ options:
table_class:
description:
- The class of the table.
- - Requires at least botocore version 1.23.18.
choices: ['STANDARD', 'STANDARD_INFREQUENT_ACCESS']
type: str
version_added: 3.1.0
wait_timeout:
description:
- How long (in seconds) to wait for creation / update / deletion to complete.
+ - AWS only allows secondary indexies to be updated one at a time, this module will automatically update them
+ in serial, and the timeout will be separately applied for each index.
aliases: ['wait_for_active_timeout']
- default: 300
+ default: 900
type: int
wait:
description:
- When I(wait=True) the module will wait for up to I(wait_timeout) seconds
- for table creation or deletion to complete before returning.
+ for index updates, table creation or deletion to complete before returning.
default: True
type: bool
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
- - amazon.aws.boto3
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.tags
-'''
+ - amazon.aws.boto3
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
- name: Create dynamo table with hash and range primary key
community.aws.dynamodb_table:
name: my-table
@@ -197,9 +196,9 @@ EXAMPLES = r'''
name: my-table
region: us-east-1
state: absent
-'''
+"""
-RETURN = r'''
+RETURN = r"""
table:
description: The returned table params from the describe API call.
returned: success
@@ -243,29 +242,39 @@ table_status:
returned: success
type: str
sample: ACTIVE
-'''
+"""
try:
import botocore
except ImportError:
pass # Handled by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict
-
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_tag_list
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import compare_aws_tags
-
-
-DYNAMO_TYPE_DEFAULT = 'STRING'
-INDEX_REQUIRED_OPTIONS = ['name', 'type', 'hash_key_name']
-INDEX_OPTIONS = INDEX_REQUIRED_OPTIONS + ['hash_key_type', 'range_key_name', 'range_key_type', 'includes', 'read_capacity', 'write_capacity']
-INDEX_TYPE_OPTIONS = ['all', 'global_all', 'global_include', 'global_keys_only', 'include', 'keys_only']
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import ansible_dict_to_boto3_tag_list
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import compare_aws_tags
+
+from ansible_collections.community.aws.plugins.module_utils.dynamodb import wait_indexes_active
+from ansible_collections.community.aws.plugins.module_utils.dynamodb import wait_table_exists
+from ansible_collections.community.aws.plugins.module_utils.dynamodb import wait_table_not_exists
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
+
+DYNAMO_TYPE_DEFAULT = "STRING"
+INDEX_REQUIRED_OPTIONS = ["name", "type", "hash_key_name"]
+INDEX_OPTIONS = INDEX_REQUIRED_OPTIONS + [
+ "hash_key_type",
+ "range_key_name",
+ "range_key_type",
+ "includes",
+ "read_capacity",
+ "write_capacity",
+]
+INDEX_TYPE_OPTIONS = ["all", "global_all", "global_include", "global_keys_only", "include", "keys_only"]
# Map in both directions
-DYNAMO_TYPE_MAP_LONG = {'STRING': 'S', 'NUMBER': 'N', 'BINARY': 'B'}
+DYNAMO_TYPE_MAP_LONG = {"STRING": "S", "NUMBER": "N", "BINARY": "B"}
DYNAMO_TYPE_MAP_SHORT = dict((v, k) for k, v in DYNAMO_TYPE_MAP_LONG.items())
KEY_TYPE_CHOICES = list(DYNAMO_TYPE_MAP_LONG.keys())
@@ -274,58 +283,43 @@ KEY_TYPE_CHOICES = list(DYNAMO_TYPE_MAP_LONG.keys())
# LimitExceededException/ResourceInUseException exceptions at you. This can be
# pretty slow, so add plenty of retries...
@AWSRetry.jittered_backoff(
- retries=45, delay=5, max_delay=30,
- catch_extra_error_codes=['LimitExceededException', 'ResourceInUseException', 'ResourceNotFoundException'],
+ retries=45,
+ delay=5,
+ max_delay=30,
+ catch_extra_error_codes=["ResourceInUseException", "ResourceNotFoundException"],
)
def _update_table_with_long_retry(**changes):
- return client.update_table(
- TableName=module.params.get('name'),
- **changes
- )
+ return client.update_table(TableName=module.params.get("name"), **changes)
# ResourceNotFoundException is expected here if the table doesn't exist
-@AWSRetry.jittered_backoff(catch_extra_error_codes=['LimitExceededException', 'ResourceInUseException'])
+@AWSRetry.jittered_backoff(catch_extra_error_codes=["LimitExceededException", "ResourceInUseException"])
def _describe_table(**params):
return client.describe_table(**params)
def wait_exists():
- table_name = module.params.get('name')
- wait_timeout = module.params.get('wait_timeout')
-
- delay = min(wait_timeout, 5)
- max_attempts = wait_timeout // delay
-
- try:
- waiter = client.get_waiter('table_exists')
- waiter.wait(
- WaiterConfig={'Delay': delay, 'MaxAttempts': max_attempts},
- TableName=table_name,
- )
- except botocore.exceptions.WaiterError as e:
- module.fail_json_aws(e, msg='Timeout while waiting on table creation')
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, msg='Failed while waiting on table creation')
+ wait_table_exists(
+ module,
+ module.params.get("wait_timeout"),
+ module.params.get("name"),
+ )
def wait_not_exists():
- table_name = module.params.get('name')
- wait_timeout = module.params.get('wait_timeout')
+ wait_table_not_exists(
+ module,
+ module.params.get("wait_timeout"),
+ module.params.get("name"),
+ )
- delay = min(wait_timeout, 5)
- max_attempts = wait_timeout // delay
- try:
- waiter = client.get_waiter('table_not_exists')
- waiter.wait(
- WaiterConfig={'Delay': delay, 'MaxAttempts': max_attempts},
- TableName=table_name,
- )
- except botocore.exceptions.WaiterError as e:
- module.fail_json_aws(e, msg='Timeout while waiting on table deletion')
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, msg='Failed while waiting on table deletion')
+def wait_indexes():
+ wait_indexes_active(
+ module,
+ module.params.get("wait_timeout"),
+ module.params.get("name"),
+ )
def _short_type_to_long(short_key):
@@ -361,21 +355,21 @@ def _decode_primary_index(current_table):
# The schema/attribute definitions are a list of dicts which need the same
# treatment as boto3's tag lists
schema = boto3_tag_list_to_ansible_dict(
- current_table.get('key_schema', []),
+ current_table.get("key_schema", []),
# Map from 'HASH'/'RANGE' to attribute name
- tag_name_key_name='key_type',
- tag_value_key_name='attribute_name',
+ tag_name_key_name="key_type",
+ tag_value_key_name="attribute_name",
)
attributes = boto3_tag_list_to_ansible_dict(
- current_table.get('attribute_definitions', []),
+ current_table.get("attribute_definitions", []),
# Map from attribute name to 'S'/'N'/'B'.
- tag_name_key_name='attribute_name',
- tag_value_key_name='attribute_type',
+ tag_name_key_name="attribute_name",
+ tag_value_key_name="attribute_type",
)
- hash_key_name = schema.get('HASH')
+ hash_key_name = schema.get("HASH")
hash_key_type = _short_type_to_long(attributes.get(hash_key_name, None))
- range_key_name = schema.get('RANGE', None)
+ range_key_name = schema.get("RANGE", None)
range_key_type = _short_type_to_long(attributes.get(range_key_name, None))
return dict(
@@ -386,56 +380,56 @@ def _decode_primary_index(current_table):
)
-def _decode_index(index_data, attributes, type_prefix=''):
+def _decode_index(index_data, attributes, type_prefix=""):
try:
index_map = dict(
- name=index_data['index_name'],
+ name=index_data["index_name"],
)
index_data = dict(index_data)
- index_data['attribute_definitions'] = attributes
+ index_data["attribute_definitions"] = attributes
index_map.update(_decode_primary_index(index_data))
- throughput = index_data.get('provisioned_throughput', {})
- index_map['provisioned_throughput'] = throughput
+ throughput = index_data.get("provisioned_throughput", {})
+ index_map["provisioned_throughput"] = throughput
if throughput:
- index_map['read_capacity'] = throughput.get('read_capacity_units')
- index_map['write_capacity'] = throughput.get('write_capacity_units')
+ index_map["read_capacity"] = throughput.get("read_capacity_units")
+ index_map["write_capacity"] = throughput.get("write_capacity_units")
- projection = index_data.get('projection', {})
+ projection = index_data.get("projection", {})
if projection:
- index_map['type'] = type_prefix + projection.get('projection_type')
- index_map['includes'] = projection.get('non_key_attributes', [])
+ index_map["type"] = type_prefix + projection.get("projection_type")
+ index_map["includes"] = projection.get("non_key_attributes", [])
return index_map
except Exception as e:
- module.fail_json_aws(e, msg='Decode failure', index_data=index_data)
+ module.fail_json_aws(e, msg="Decode failure", index_data=index_data)
def compatability_results(current_table):
if not current_table:
return dict()
- billing_mode = current_table.get('billing_mode')
+ billing_mode = current_table.get("billing_mode")
primary_indexes = _decode_primary_index(current_table)
- hash_key_name = primary_indexes.get('hash_key_name')
- hash_key_type = primary_indexes.get('hash_key_type')
- range_key_name = primary_indexes.get('range_key_name')
- range_key_type = primary_indexes.get('range_key_type')
+ hash_key_name = primary_indexes.get("hash_key_name")
+ hash_key_type = primary_indexes.get("hash_key_type")
+ range_key_name = primary_indexes.get("range_key_name")
+ range_key_type = primary_indexes.get("range_key_type")
indexes = list()
- global_indexes = current_table.get('_global_index_map', {})
- local_indexes = current_table.get('_local_index_map', {})
+ global_indexes = current_table.get("_global_index_map", {})
+ local_indexes = current_table.get("_local_index_map", {})
for index in global_indexes:
idx = dict(global_indexes[index])
- idx.pop('provisioned_throughput', None)
+ idx.pop("provisioned_throughput", None)
indexes.append(idx)
for index in local_indexes:
idx = dict(local_indexes[index])
- idx.pop('provisioned_throughput', None)
+ idx.pop("provisioned_throughput", None)
indexes.append(idx)
compat_results = dict(
@@ -446,72 +440,78 @@ def compatability_results(current_table):
indexes=indexes,
billing_mode=billing_mode,
region=module.region,
- table_name=current_table.get('table_name', None),
- table_class=current_table.get('table_class_summary', {}).get('table_class', None),
- table_status=current_table.get('table_status', None),
- tags=current_table.get('tags', {}),
+ table_name=current_table.get("table_name", None),
+ table_class=current_table.get("table_class_summary", {}).get("table_class", None),
+ table_status=current_table.get("table_status", None),
+ tags=current_table.get("tags", {}),
)
if billing_mode == "PROVISIONED":
- throughput = current_table.get('provisioned_throughput', {})
- compat_results['read_capacity'] = throughput.get('read_capacity_units', None)
- compat_results['write_capacity'] = throughput.get('write_capacity_units', None)
+ throughput = current_table.get("provisioned_throughput", {})
+ compat_results["read_capacity"] = throughput.get("read_capacity_units", None)
+ compat_results["write_capacity"] = throughput.get("write_capacity_units", None)
return compat_results
def get_dynamodb_table():
- table_name = module.params.get('name')
+ table_name = module.params.get("name")
try:
table = _describe_table(TableName=table_name)
- except is_boto3_error_code('ResourceNotFoundException'):
+ except is_boto3_error_code("ResourceNotFoundException"):
return None
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, msg='Failed to describe table')
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(e, msg="Failed to describe table")
- table = table['Table']
+ table = table["Table"]
try:
- tags = client.list_tags_of_resource(aws_retry=True, ResourceArn=table['TableArn'])['Tags']
- except is_boto3_error_code('AccessDeniedException'):
- module.warn('Permission denied when listing tags')
+ tags = client.list_tags_of_resource(aws_retry=True, ResourceArn=table["TableArn"])["Tags"]
+ except is_boto3_error_code("AccessDeniedException"):
+ module.warn("Permission denied when listing tags")
tags = []
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, msg='Failed to list table tags')
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(e, msg="Failed to list table tags")
tags = boto3_tag_list_to_ansible_dict(tags)
table = camel_dict_to_snake_dict(table)
# Put some of the values into places people will expect them
- table['arn'] = table['table_arn']
- table['name'] = table['table_name']
- table['status'] = table['table_status']
- table['id'] = table['table_id']
- table['size'] = table['table_size_bytes']
- table['tags'] = tags
+ table["arn"] = table["table_arn"]
+ table["name"] = table["table_name"]
+ table["status"] = table["table_status"]
+ table["id"] = table["table_id"]
+ table["size"] = table["table_size_bytes"]
+ table["tags"] = tags
- if 'table_class_summary' in table:
- table['table_class'] = table['table_class_summary']['table_class']
+ if "table_class_summary" in table:
+ table["table_class"] = table["table_class_summary"]["table_class"]
# billing_mode_summary doesn't always seem to be set but is always set for PAY_PER_REQUEST
# and when updating the billing_mode
- if 'billing_mode_summary' in table:
- table['billing_mode'] = table['billing_mode_summary']['billing_mode']
+ if "billing_mode_summary" in table:
+ table["billing_mode"] = table["billing_mode_summary"]["billing_mode"]
else:
- table['billing_mode'] = "PROVISIONED"
+ table["billing_mode"] = "PROVISIONED"
# convert indexes into something we can easily search against
- attributes = table['attribute_definitions']
+ attributes = table["attribute_definitions"]
global_index_map = dict()
local_index_map = dict()
- for index in table.get('global_secondary_indexes', []):
- idx = _decode_index(index, attributes, type_prefix='global_')
- global_index_map[idx['name']] = idx
- for index in table.get('local_secondary_indexes', []):
+ for index in table.get("global_secondary_indexes", []):
+ idx = _decode_index(index, attributes, type_prefix="global_")
+ global_index_map[idx["name"]] = idx
+ for index in table.get("local_secondary_indexes", []):
idx = _decode_index(index, attributes)
- local_index_map[idx['name']] = idx
- table['_global_index_map'] = global_index_map
- table['_local_index_map'] = local_index_map
+ local_index_map[idx["name"]] = idx
+ table["_global_index_map"] = global_index_map
+ table["_local_index_map"] = local_index_map
return table
@@ -522,19 +522,19 @@ def _generate_attribute_map():
"""
attributes = dict()
- for index in (module.params, *module.params.get('indexes')):
+ for index in (module.params, *module.params.get("indexes")):
# run through hash_key_name and range_key_name
- for t in ['hash', 'range']:
- key_name = index.get(t + '_key_name')
+ for t in ["hash", "range"]:
+ key_name = index.get(t + "_key_name")
if not key_name:
continue
- key_type = index.get(t + '_key_type') or DYNAMO_TYPE_DEFAULT
+ key_type = index.get(t + "_key_type") or DYNAMO_TYPE_DEFAULT
_type = _long_type_to_short(key_type)
if key_name in attributes:
if _type != attributes[key_name]:
- module.fail_json(msg='Conflicting attribute type',
- type_1=_type, type_2=attributes[key_name],
- key_name=key_name)
+ module.fail_json(
+ msg="Conflicting attribute type", type_1=_type, type_2=attributes[key_name], key_name=key_name
+ )
else:
attributes[key_name] = _type
@@ -547,9 +547,7 @@ def _generate_attributes():
# Use ansible_dict_to_boto3_tag_list to generate the list of dicts
# format we need
attrs = ansible_dict_to_boto3_tag_list(
- attributes,
- tag_name_key_name='AttributeName',
- tag_value_key_name='AttributeType'
+ attributes, tag_name_key_name="AttributeName", tag_value_key_name="AttributeType"
)
return list(attrs)
@@ -558,8 +556,8 @@ def _generate_throughput(params=None):
if not params:
params = module.params
- read_capacity = params.get('read_capacity') or 1
- write_capacity = params.get('write_capacity') or 1
+ read_capacity = params.get("read_capacity") or 1
+ write_capacity = params.get("write_capacity") or 1
throughput = dict(
ReadCapacityUnits=read_capacity,
WriteCapacityUnits=write_capacity,
@@ -573,56 +571,54 @@ def _generate_schema(params=None):
params = module.params
schema = list()
- hash_key_name = params.get('hash_key_name')
- range_key_name = params.get('range_key_name')
+ hash_key_name = params.get("hash_key_name")
+ range_key_name = params.get("range_key_name")
if hash_key_name:
- entry = _schema_dict(hash_key_name, 'HASH')
+ entry = _schema_dict(hash_key_name, "HASH")
schema.append(entry)
if range_key_name:
- entry = _schema_dict(range_key_name, 'RANGE')
+ entry = _schema_dict(range_key_name, "RANGE")
schema.append(entry)
return schema
def _primary_index_changes(current_table):
-
primary_index = _decode_primary_index(current_table)
- hash_key_name = primary_index.get('hash_key_name')
- _hash_key_name = module.params.get('hash_key_name')
- hash_key_type = primary_index.get('hash_key_type')
- _hash_key_type = module.params.get('hash_key_type')
- range_key_name = primary_index.get('range_key_name')
- _range_key_name = module.params.get('range_key_name')
- range_key_type = primary_index.get('range_key_type')
- _range_key_type = module.params.get('range_key_type')
+ hash_key_name = primary_index.get("hash_key_name")
+ _hash_key_name = module.params.get("hash_key_name")
+ hash_key_type = primary_index.get("hash_key_type")
+ _hash_key_type = module.params.get("hash_key_type")
+ range_key_name = primary_index.get("range_key_name")
+ _range_key_name = module.params.get("range_key_name")
+ range_key_type = primary_index.get("range_key_type")
+ _range_key_type = module.params.get("range_key_type")
changed = list()
if _hash_key_name and (_hash_key_name != hash_key_name):
- changed.append('hash_key_name')
+ changed.append("hash_key_name")
if _hash_key_type and (_hash_key_type != hash_key_type):
- changed.append('hash_key_type')
+ changed.append("hash_key_type")
if _range_key_name and (_range_key_name != range_key_name):
- changed.append('range_key_name')
+ changed.append("range_key_name")
if _range_key_type and (_range_key_type != range_key_type):
- changed.append('range_key_type')
+ changed.append("range_key_type")
return changed
def _throughput_changes(current_table, params=None):
-
if not params:
params = module.params
- throughput = current_table.get('provisioned_throughput', {})
- read_capacity = throughput.get('read_capacity_units', None)
- _read_capacity = params.get('read_capacity') or read_capacity
- write_capacity = throughput.get('write_capacity_units', None)
- _write_capacity = params.get('write_capacity') or write_capacity
+ throughput = current_table.get("provisioned_throughput", {})
+ read_capacity = throughput.get("read_capacity_units", None)
+ _read_capacity = params.get("read_capacity") or read_capacity
+ write_capacity = throughput.get("write_capacity_units", None)
+ _write_capacity = params.get("write_capacity") or write_capacity
if (read_capacity != _read_capacity) or (write_capacity != _write_capacity):
return dict(
@@ -642,14 +638,14 @@ def _generate_global_indexes(billing_mode):
if billing_mode == "PAY_PER_REQUEST":
include_throughput = False
- for index in module.params.get('indexes'):
- if index.get('type') not in ['global_all', 'global_include', 'global_keys_only']:
+ for index in module.params.get("indexes"):
+ if index.get("type") not in ["global_all", "global_include", "global_keys_only"]:
continue
- name = index.get('name')
+ name = index.get("name")
if name in index_exists:
- module.fail_json(msg='Duplicate key {0} in list of global indexes'.format(name))
+ module.fail_json(msg=f"Duplicate key {name} in list of global indexes")
# Convert the type name to upper case and remove the global_
- index['type'] = index['type'].upper()[7:]
+ index["type"] = index["type"].upper()[7:]
index = _generate_index(index, include_throughput)
index_exists[name] = True
indexes.append(index)
@@ -661,14 +657,13 @@ def _generate_local_indexes():
index_exists = dict()
indexes = list()
- for index in module.params.get('indexes'):
- index = dict()
- if index.get('type') not in ['all', 'include', 'keys_only']:
+ for index in module.params.get("indexes"):
+ if index.get("type") not in ["all", "include", "keys_only"]:
continue
- name = index.get('name')
+ name = index.get("name")
if name in index_exists:
- module.fail_json(msg='Duplicate key {0} in list of local indexes'.format(name))
- index['type'] = index['type'].upper()
+ module.fail_json(msg=f"Duplicate key {name} in list of local indexes")
+ index["type"] = index["type"].upper()
index = _generate_index(index, False)
index_exists[name] = True
indexes.append(index)
@@ -678,32 +673,32 @@ def _generate_local_indexes():
def _generate_global_index_map(current_table):
global_index_map = dict()
- existing_indexes = current_table['_global_index_map']
- for index in module.params.get('indexes'):
- if index.get('type') not in ['global_all', 'global_include', 'global_keys_only']:
+ existing_indexes = current_table["_global_index_map"]
+ for index in module.params.get("indexes"):
+ if index.get("type") not in ["global_all", "global_include", "global_keys_only"]:
continue
- name = index.get('name')
+ name = index.get("name")
if name in global_index_map:
- module.fail_json(msg='Duplicate key {0} in list of global indexes'.format(name))
+ module.fail_json(msg=f"Duplicate key {name} in list of global indexes")
idx = _merge_index_params(index, existing_indexes.get(name, {}))
# Convert the type name to upper case and remove the global_
- idx['type'] = idx['type'].upper()[7:]
+ idx["type"] = idx["type"].upper()[7:]
global_index_map[name] = idx
return global_index_map
def _generate_local_index_map(current_table):
local_index_map = dict()
- existing_indexes = current_table['_local_index_map']
- for index in module.params.get('indexes'):
- if index.get('type') not in ['all', 'include', 'keys_only']:
+ existing_indexes = current_table["_local_index_map"]
+ for index in module.params.get("indexes"):
+ if index.get("type") not in ["all", "include", "keys_only"]:
continue
- name = index.get('name')
+ name = index.get("name")
if name in local_index_map:
- module.fail_json(msg='Duplicate key {0} in list of local indexes'.format(name))
+ module.fail_json(msg=f"Duplicate key {name} in list of local indexes")
idx = _merge_index_params(index, existing_indexes.get(name, {}))
# Convert the type name to upper case
- idx['type'] = idx['type'].upper()
+ idx["type"] = idx["type"].upper()
local_index_map[name] = idx
return local_index_map
@@ -711,27 +706,28 @@ def _generate_local_index_map(current_table):
def _generate_index(index, include_throughput=True):
key_schema = _generate_schema(index)
throughput = _generate_throughput(index)
- non_key_attributes = index['includes'] or []
+ non_key_attributes = index["includes"] or []
projection = dict(
- ProjectionType=index['type'],
+ ProjectionType=index["type"],
)
- if index['type'] != 'ALL':
+ if index["type"] != "ALL":
if non_key_attributes:
- projection['NonKeyAttributes'] = non_key_attributes
+ projection["NonKeyAttributes"] = non_key_attributes
else:
if non_key_attributes:
module.fail_json(
- "DynamoDB does not support specifying non-key-attributes ('includes') for "
- "indexes of type 'all'. Index name: {0}".format(index['name']))
+ "DynamoDB does not support specifying non-key-attributes ('includes') for indexes of type 'all'. Index"
+ f" name: {index['name']}"
+ )
idx = dict(
- IndexName=index['name'],
+ IndexName=index["name"],
KeySchema=key_schema,
Projection=projection,
)
if include_throughput:
- idx['ProvisionedThroughput'] = throughput
+ idx["ProvisionedThroughput"] = throughput
return idx
@@ -742,15 +738,15 @@ def _attribute_changes(current_table):
def _global_index_changes(current_table):
- current_global_index_map = current_table['_global_index_map']
+ current_global_index_map = current_table["_global_index_map"]
global_index_map = _generate_global_index_map(current_table)
- current_billing_mode = current_table.get('billing_mode')
+ current_billing_mode = current_table.get("billing_mode")
- if module.params.get('billing_mode') is None:
+ if module.params.get("billing_mode") is None:
billing_mode = current_billing_mode
else:
- billing_mode = module.params.get('billing_mode')
+ billing_mode = module.params.get("billing_mode")
include_throughput = True
@@ -761,7 +757,6 @@ def _global_index_changes(current_table):
# TODO (future) it would be nice to add support for deleting an index
for name in global_index_map:
-
idx = dict(_generate_index(global_index_map[name], include_throughput=include_throughput))
if name not in current_global_index_map:
index_changes.append(dict(Create=idx))
@@ -798,37 +793,37 @@ def _update_table(current_table):
# Get throughput / billing_mode changes
throughput_changes = _throughput_changes(current_table)
if throughput_changes:
- changes['ProvisionedThroughput'] = throughput_changes
+ changes["ProvisionedThroughput"] = throughput_changes
- current_billing_mode = current_table.get('billing_mode')
- new_billing_mode = module.params.get('billing_mode')
+ current_billing_mode = current_table.get("billing_mode")
+ new_billing_mode = module.params.get("billing_mode")
if new_billing_mode is None:
new_billing_mode = current_billing_mode
if current_billing_mode != new_billing_mode:
- changes['BillingMode'] = new_billing_mode
+ changes["BillingMode"] = new_billing_mode
# Update table_class use exisiting if none is defined
- if module.params.get('table_class'):
- if module.params.get('table_class') != current_table.get('table_class'):
- changes['TableClass'] = module.params.get('table_class')
+ if module.params.get("table_class"):
+ if module.params.get("table_class") != current_table.get("table_class"):
+ changes["TableClass"] = module.params.get("table_class")
global_index_changes = _global_index_changes(current_table)
if global_index_changes:
- changes['GlobalSecondaryIndexUpdates'] = global_index_changes
+ changes["GlobalSecondaryIndexUpdates"] = global_index_changes
# Only one index can be changed at a time except if changing the billing mode, pass the first during the
# main update and deal with the others on a slow retry to wait for
# completion
if current_billing_mode == new_billing_mode:
if len(global_index_changes) > 1:
- changes['GlobalSecondaryIndexUpdates'] = [global_index_changes[0]]
+ changes["GlobalSecondaryIndexUpdates"] = [global_index_changes[0]]
additional_global_index_changes = global_index_changes[1:]
local_index_changes = _local_index_changes(current_table)
if local_index_changes:
- changes['LocalSecondaryIndexUpdates'] = local_index_changes
+ changes["LocalSecondaryIndexUpdates"] = local_index_changes
if not changes:
return False
@@ -837,38 +832,39 @@ def _update_table(current_table):
return True
if global_index_changes or local_index_changes:
- changes['AttributeDefinitions'] = _generate_attributes()
+ changes["AttributeDefinitions"] = _generate_attributes()
try:
- client.update_table(
- aws_retry=True,
- TableName=module.params.get('name'),
- **changes
- )
+ client.update_table(aws_retry=True, TableName=module.params.get("name"), **changes)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Failed to update table")
if additional_global_index_changes:
for index in additional_global_index_changes:
+ wait_indexes()
try:
- _update_table_with_long_retry(GlobalSecondaryIndexUpdates=[index], AttributeDefinitions=changes['AttributeDefinitions'])
+ _update_table_with_long_retry(
+ GlobalSecondaryIndexUpdates=[index], AttributeDefinitions=changes["AttributeDefinitions"]
+ )
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Failed to update table", changes=changes,
- additional_global_index_changes=additional_global_index_changes)
-
- if module.params.get('wait'):
- wait_exists()
+ module.fail_json_aws(
+ e,
+ msg="Failed to update table",
+ changes=changes,
+ additional_global_index_changes=additional_global_index_changes,
+ )
return True
def _update_tags(current_table):
- _tags = module.params.get('tags')
+ _tags = module.params.get("tags")
if _tags is None:
return False
- tags_to_add, tags_to_remove = compare_aws_tags(current_table['tags'], module.params.get('tags'),
- purge_tags=module.params.get('purge_tags'))
+ tags_to_add, tags_to_remove = compare_aws_tags(
+ current_table["tags"], module.params.get("tags"), purge_tags=module.params.get("purge_tags")
+ )
# If neither need updating we can return already
if not (tags_to_add or tags_to_remove):
@@ -881,7 +877,7 @@ def _update_tags(current_table):
try:
client.tag_resource(
aws_retry=True,
- ResourceArn=current_table['arn'],
+ ResourceArn=current_table["arn"],
Tags=ansible_dict_to_boto3_tag_list(tags_to_add),
)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
@@ -890,7 +886,7 @@ def _update_tags(current_table):
try:
client.untag_resource(
aws_retry=True,
- ResourceArn=current_table['arn'],
+ ResourceArn=current_table["arn"],
TagKeys=tags_to_remove,
)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
@@ -902,28 +898,31 @@ def _update_tags(current_table):
def update_table(current_table):
primary_index_changes = _primary_index_changes(current_table)
if primary_index_changes:
- module.fail_json("DynamoDB does not support updating the Primary keys on a table. Changed paramters are: {0}".format(primary_index_changes))
+ module.fail_json(
+ f"DynamoDB does not support updating the Primary keys on a table. Changed paramters are: {primary_index_changes}"
+ )
changed = False
changed |= _update_table(current_table)
changed |= _update_tags(current_table)
- if module.params.get('wait'):
+ if module.params.get("wait"):
wait_exists()
+ wait_indexes()
return changed
def create_table():
- table_name = module.params.get('name')
- table_class = module.params.get('table_class')
- hash_key_name = module.params.get('hash_key_name')
- billing_mode = module.params.get('billing_mode')
+ table_name = module.params.get("name")
+ table_class = module.params.get("table_class")
+ hash_key_name = module.params.get("hash_key_name")
+ billing_mode = module.params.get("billing_mode")
if billing_mode is None:
billing_mode = "PROVISIONED"
- tags = ansible_dict_to_boto3_tag_list(module.params.get('tags') or {})
+ tags = ansible_dict_to_boto3_tag_list(module.params.get("tags") or {})
if not hash_key_name:
module.fail_json('"hash_key_name" must be provided when creating a new table.')
@@ -951,21 +950,22 @@ def create_table():
)
if table_class:
- params['TableClass'] = table_class
+ params["TableClass"] = table_class
if billing_mode == "PROVISIONED":
- params['ProvisionedThroughput'] = throughput
+ params["ProvisionedThroughput"] = throughput
if local_indexes:
- params['LocalSecondaryIndexes'] = local_indexes
+ params["LocalSecondaryIndexes"] = local_indexes
if global_indexes:
- params['GlobalSecondaryIndexes'] = global_indexes
+ params["GlobalSecondaryIndexes"] = global_indexes
try:
client.create_table(aws_retry=True, **params)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to create table')
+ module.fail_json_aws(e, msg="Failed to create table")
- if module.params.get('wait'):
+ if module.params.get("wait"):
wait_exists()
+ wait_indexes()
return True
@@ -977,30 +977,34 @@ def delete_table(current_table):
if module.check_mode:
return True
- table_name = module.params.get('name')
+ table_name = module.params.get("name")
# If an index is mid-update then we have to wait for the update to complete
# before deletion will succeed
long_retry = AWSRetry.jittered_backoff(
- retries=45, delay=5, max_delay=30,
- catch_extra_error_codes=['LimitExceededException', 'ResourceInUseException'],
+ retries=45,
+ delay=5,
+ max_delay=30,
+ catch_extra_error_codes=["LimitExceededException", "ResourceInUseException"],
)
try:
long_retry(client.delete_table)(TableName=table_name)
- except is_boto3_error_code('ResourceNotFoundException'):
+ except is_boto3_error_code("ResourceNotFoundException"):
return False
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, msg='Failed to delete table')
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(e, msg="Failed to delete table")
- if module.params.get('wait'):
+ if module.params.get("wait"):
wait_not_exists()
return True
def main():
-
global module
global client
@@ -1008,36 +1012,36 @@ def main():
# different parameters, use a separate namespace for names,
# and local indexes can't be updated.
index_options = dict(
- name=dict(type='str', required=True),
+ name=dict(type="str", required=True),
# It would be nice to make this optional, but because Local and Global
# indexes are mixed in here we need this to be able to tell to which
# group of indexes the index belongs.
- type=dict(type='str', required=True, choices=INDEX_TYPE_OPTIONS),
- hash_key_name=dict(type='str', required=False),
- hash_key_type=dict(type='str', required=False, choices=KEY_TYPE_CHOICES),
- range_key_name=dict(type='str', required=False),
- range_key_type=dict(type='str', required=False, choices=KEY_TYPE_CHOICES),
- includes=dict(type='list', required=False, elements='str'),
- read_capacity=dict(type='int', required=False),
- write_capacity=dict(type='int', required=False),
+ type=dict(type="str", required=True, choices=INDEX_TYPE_OPTIONS),
+ hash_key_name=dict(type="str", required=False),
+ hash_key_type=dict(type="str", required=False, choices=KEY_TYPE_CHOICES),
+ range_key_name=dict(type="str", required=False),
+ range_key_type=dict(type="str", required=False, choices=KEY_TYPE_CHOICES),
+ includes=dict(type="list", required=False, elements="str"),
+ read_capacity=dict(type="int", required=False),
+ write_capacity=dict(type="int", required=False),
)
argument_spec = dict(
- state=dict(default='present', choices=['present', 'absent']),
- name=dict(required=True, type='str'),
- hash_key_name=dict(type='str'),
- hash_key_type=dict(type='str', choices=KEY_TYPE_CHOICES),
- range_key_name=dict(type='str'),
- range_key_type=dict(type='str', choices=KEY_TYPE_CHOICES),
- billing_mode=dict(type='str', choices=['PROVISIONED', 'PAY_PER_REQUEST']),
- read_capacity=dict(type='int'),
- write_capacity=dict(type='int'),
- indexes=dict(default=[], type='list', elements='dict', options=index_options),
- table_class=dict(type='str', choices=['STANDARD', 'STANDARD_INFREQUENT_ACCESS']),
- tags=dict(type='dict', aliases=['resource_tags']),
- purge_tags=dict(type='bool', default=True),
- wait=dict(type='bool', default=True),
- wait_timeout=dict(default=300, type='int', aliases=['wait_for_active_timeout']),
+ state=dict(default="present", choices=["present", "absent"]),
+ name=dict(required=True, type="str"),
+ hash_key_name=dict(type="str"),
+ hash_key_type=dict(type="str", choices=KEY_TYPE_CHOICES),
+ range_key_name=dict(type="str"),
+ range_key_type=dict(type="str", choices=KEY_TYPE_CHOICES),
+ billing_mode=dict(type="str", choices=["PROVISIONED", "PAY_PER_REQUEST"]),
+ read_capacity=dict(type="int"),
+ write_capacity=dict(type="int"),
+ indexes=dict(default=[], type="list", elements="dict", options=index_options),
+ table_class=dict(type="str", choices=["STANDARD", "STANDARD_INFREQUENT_ACCESS"]),
+ tags=dict(type="dict", aliases=["resource_tags"]),
+ purge_tags=dict(type="bool", default=True),
+ wait=dict(type="bool", default=True),
+ wait_timeout=dict(default=900, type="int", aliases=["wait_for_active_timeout"]),
)
module = AnsibleAWSModule(
@@ -1047,41 +1051,38 @@ def main():
)
retry_decorator = AWSRetry.jittered_backoff(
- catch_extra_error_codes=['LimitExceededException', 'ResourceInUseException', 'ResourceNotFoundException'],
+ catch_extra_error_codes=["LimitExceededException", "ResourceInUseException", "ResourceNotFoundException"],
)
- client = module.client('dynamodb', retry_decorator=retry_decorator)
-
- if module.params.get('table_class'):
- module.require_botocore_at_least('1.23.18', reason='to set table_class')
+ client = module.client("dynamodb", retry_decorator=retry_decorator)
current_table = get_dynamodb_table()
changed = False
table = None
results = dict()
- state = module.params.get('state')
- if state == 'present':
+ state = module.params.get("state")
+ if state == "present":
if current_table:
changed |= update_table(current_table)
else:
changed |= create_table()
table = get_dynamodb_table()
- elif state == 'absent':
+ elif state == "absent":
changed |= delete_table(current_table)
compat_results = compatability_results(table)
if compat_results:
results.update(compat_results)
- results['changed'] = changed
+ results["changed"] = changed
if table:
# These are used to pass computed data about, not needed for users
- table.pop('_global_index_map', None)
- table.pop('_local_index_map', None)
- results['table'] = table
+ table.pop("_global_index_map", None)
+ table.pop("_local_index_map", None)
+ results["table"] = table
module.exit_json(**results)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/dynamodb_ttl.py b/ansible_collections/community/aws/plugins/modules/dynamodb_ttl.py
index 9cbbb3e5e..eca236cf4 100644
--- a/ansible_collections/community/aws/plugins/modules/dynamodb_ttl.py
+++ b/ansible_collections/community/aws/plugins/modules/dynamodb_ttl.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: dynamodb_ttl
version_added: 1.0.0
@@ -32,14 +30,15 @@ options:
required: true
type: str
-author: Ted Timmons (@tedder)
+author:
+- Ted Timmons (@tedder)
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
+- amazon.aws.common.modules
+- amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
- name: enable TTL on my cowfacts table
community.aws.dynamodb_ttl:
state: enable
@@ -51,9 +50,9 @@ EXAMPLES = '''
state: disable
table_name: cowfacts
attribute_name: cow_deleted_date
-'''
+"""
-RETURN = '''
+RETURN = r"""
current_status:
description: current or new TTL specification.
type: dict
@@ -61,59 +60,59 @@ current_status:
sample:
- { "AttributeName": "deploy_timestamp", "TimeToLiveStatus": "ENABLED" }
- { "AttributeName": "deploy_timestamp", "Enabled": true }
-'''
+"""
try:
import botocore
except ImportError:
pass # Handled by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def get_current_ttl_state(c, table_name):
- '''Fetch the state dict for a table.'''
+ """Fetch the state dict for a table."""
current_state = c.describe_time_to_live(TableName=table_name)
- return current_state.get('TimeToLiveDescription')
+ return current_state.get("TimeToLiveDescription")
def does_state_need_changing(attribute_name, desired_state, current_spec):
- '''Run checks to see if the table needs to be modified. Basically a dirty check.'''
+ """Run checks to see if the table needs to be modified. Basically a dirty check."""
if not current_spec:
# we don't have an entry (or a table?)
return True
- if desired_state.lower() == 'enable' and current_spec.get('TimeToLiveStatus') not in ['ENABLING', 'ENABLED']:
+ if desired_state.lower() == "enable" and current_spec.get("TimeToLiveStatus") not in ["ENABLING", "ENABLED"]:
return True
- if desired_state.lower() == 'disable' and current_spec.get('TimeToLiveStatus') not in ['DISABLING', 'DISABLED']:
+ if desired_state.lower() == "disable" and current_spec.get("TimeToLiveStatus") not in ["DISABLING", "DISABLED"]:
return True
- if attribute_name != current_spec.get('AttributeName'):
+ if attribute_name != current_spec.get("AttributeName"):
return True
return False
def set_ttl_state(c, table_name, state, attribute_name):
- '''Set our specification. Returns the update_time_to_live specification dict,
- which is different than the describe_* call.'''
+ """Set our specification. Returns the update_time_to_live specification dict,
+ which is different than the describe_* call."""
is_enabled = False
- if state.lower() == 'enable':
+ if state.lower() == "enable":
is_enabled = True
ret = c.update_time_to_live(
TableName=table_name,
TimeToLiveSpecification={
- 'Enabled': is_enabled,
- 'AttributeName': attribute_name
- }
+ "Enabled": is_enabled,
+ "AttributeName": attribute_name,
+ },
)
- return ret.get('TimeToLiveSpecification')
+ return ret.get("TimeToLiveSpecification")
def main():
argument_spec = dict(
- state=dict(choices=['enable', 'disable']),
+ state=dict(choices=["enable", "disable"]),
table_name=dict(required=True),
attribute_name=dict(required=True),
)
@@ -122,26 +121,28 @@ def main():
)
try:
- dbclient = module.client('dynamodb')
+ dbclient = module.client("dynamodb")
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to connect to AWS')
+ module.fail_json_aws(e, msg="Failed to connect to AWS")
- result = {'changed': False}
- state = module.params['state']
+ result = {"changed": False}
+ state = module.params["state"]
# wrap all our calls to catch the standard exceptions. We don't pass `module` in to the
# methods so it's easier to do here.
try:
- current_state = get_current_ttl_state(dbclient, module.params['table_name'])
+ current_state = get_current_ttl_state(dbclient, module.params["table_name"])
- if does_state_need_changing(module.params['attribute_name'], module.params['state'], current_state):
+ if does_state_need_changing(module.params["attribute_name"], module.params["state"], current_state):
# changes needed
- new_state = set_ttl_state(dbclient, module.params['table_name'], module.params['state'], module.params['attribute_name'])
- result['current_status'] = new_state
- result['changed'] = True
+ new_state = set_ttl_state(
+ dbclient, module.params["table_name"], module.params["state"], module.params["attribute_name"]
+ )
+ result["current_status"] = new_state
+ result["changed"] = True
else:
# no changes needed
- result['current_status'] = current_state
+ result["current_status"] = current_state
except botocore.exceptions.ClientError as e:
module.fail_json_aws(e, msg="Failed to get or update ttl state")
@@ -153,5 +154,5 @@ def main():
module.exit_json(**result)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/ec2_ami_copy.py b/ansible_collections/community/aws/plugins/modules/ec2_ami_copy.py
index 15a69163d..bb5a30ea1 100644
--- a/ansible_collections/community/aws/plugins/modules/ec2_ami_copy.py
+++ b/ansible_collections/community/aws/plugins/modules/ec2_ami_copy.py
@@ -1,13 +1,10 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
+
# This file is part of Ansible
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: ec2_ami_copy
version_added: 1.0.0
@@ -72,12 +69,12 @@ author:
- Amir Moulavi (@amir343) <amir.moulavi@gmail.com>
- Tim C (@defunctio) <defunct@defunct.io>
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
- name: Basic AMI Copy
community.aws.ec2_ami_copy:
source_region: us-east-1
@@ -107,8 +104,8 @@ EXAMPLES = '''
region: eu-west-1
source_image_id: ami-xxxxxxx
tags:
- Name: My-Super-AMI
- Patch: 1.2.3
+ Name: My-Super-AMI
+ Patch: 1.2.3
tag_equality: true
- name: Encrypted AMI copy
@@ -125,26 +122,29 @@ EXAMPLES = '''
source_image_id: ami-xxxxxxx
encrypted: true
kms_key_id: arn:aws:kms:us-east-1:XXXXXXXXXXXX:key/746de6ea-50a4-4bcb-8fbc-e3b29f2d367b
-'''
+"""
-RETURN = '''
+RETURN = r"""
image_id:
description: AMI ID of the copied AMI
returned: always
type: str
sample: ami-e689729e
-'''
+"""
try:
- from botocore.exceptions import ClientError, WaiterError, BotoCoreError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
+ from botocore.exceptions import WaiterError
except ImportError:
pass # caught by AnsibleAWSModule
from ansible.module_utils._text import to_native
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_tag_list
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import ansible_dict_to_boto3_tag_list
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def copy_image(module, ec2):
@@ -157,67 +157,67 @@ def copy_image(module, ec2):
image = None
changed = False
- tags = module.params.get('tags')
-
- params = {'SourceRegion': module.params.get('source_region'),
- 'SourceImageId': module.params.get('source_image_id'),
- 'Name': module.params.get('name'),
- 'Description': module.params.get('description'),
- 'Encrypted': module.params.get('encrypted'),
- }
- if module.params.get('kms_key_id'):
- params['KmsKeyId'] = module.params.get('kms_key_id')
+ tags = module.params.get("tags")
+
+ params = {
+ "SourceRegion": module.params.get("source_region"),
+ "SourceImageId": module.params.get("source_image_id"),
+ "Name": module.params.get("name"),
+ "Description": module.params.get("description"),
+ "Encrypted": module.params.get("encrypted"),
+ }
+ if module.params.get("kms_key_id"):
+ params["KmsKeyId"] = module.params.get("kms_key_id")
try:
- if module.params.get('tag_equality'):
- filters = [{'Name': 'tag:%s' % k, 'Values': [v]} for (k, v) in module.params.get('tags').items()]
- filters.append(dict(Name='state', Values=['available', 'pending']))
+ if module.params.get("tag_equality"):
+ filters = [{"Name": f"tag:{k}", "Values": [v]} for (k, v) in module.params.get("tags").items()]
+ filters.append(dict(Name="state", Values=["available", "pending"]))
images = ec2.describe_images(Filters=filters)
- if len(images['Images']) > 0:
- image = images['Images'][0]
+ if len(images["Images"]) > 0:
+ image = images["Images"][0]
if not image:
image = ec2.copy_image(**params)
- image_id = image['ImageId']
+ image_id = image["ImageId"]
if tags:
- ec2.create_tags(Resources=[image_id],
- Tags=ansible_dict_to_boto3_tag_list(tags))
+ ec2.create_tags(Resources=[image_id], Tags=ansible_dict_to_boto3_tag_list(tags))
changed = True
- if module.params.get('wait'):
+ if module.params.get("wait"):
delay = 15
- max_attempts = module.params.get('wait_timeout') // delay
- image_id = image.get('ImageId')
- ec2.get_waiter('image_available').wait(
- ImageIds=[image_id],
- WaiterConfig={'Delay': delay, 'MaxAttempts': max_attempts}
+ max_attempts = module.params.get("wait_timeout") // delay
+ image_id = image.get("ImageId")
+ ec2.get_waiter("image_available").wait(
+ ImageIds=[image_id], WaiterConfig={"Delay": delay, "MaxAttempts": max_attempts}
)
module.exit_json(changed=changed, **camel_dict_to_snake_dict(image))
except WaiterError as e:
- module.fail_json_aws(e, msg='An error occurred waiting for the image to become available')
+ module.fail_json_aws(e, msg="An error occurred waiting for the image to become available")
except (ClientError, BotoCoreError) as e:
module.fail_json_aws(e, msg="Could not copy AMI")
except Exception as e:
- module.fail_json(msg='Unhandled exception. (%s)' % to_native(e))
+ module.fail_json(msg=f"Unhandled exception. ({to_native(e)})")
def main():
argument_spec = dict(
source_region=dict(required=True),
source_image_id=dict(required=True),
- name=dict(default='default'),
- description=dict(default=''),
- encrypted=dict(type='bool', default=False, required=False),
- kms_key_id=dict(type='str', required=False),
- wait=dict(type='bool', default=False),
- wait_timeout=dict(type='int', default=600),
- tags=dict(type='dict', aliases=['resource_tags']),
- tag_equality=dict(type='bool', default=False))
+ name=dict(default="default"),
+ description=dict(default=""),
+ encrypted=dict(type="bool", default=False, required=False),
+ kms_key_id=dict(type="str", required=False),
+ wait=dict(type="bool", default=False),
+ wait_timeout=dict(type="int", default=600),
+ tags=dict(type="dict", aliases=["resource_tags"]),
+ tag_equality=dict(type="bool", default=False),
+ )
module = AnsibleAWSModule(argument_spec=argument_spec)
- ec2 = module.client('ec2')
+ ec2 = module.client("ec2")
copy_image(module, ec2)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/ec2_carrier_gateway.py b/ansible_collections/community/aws/plugins/modules/ec2_carrier_gateway.py
new file mode 100644
index 000000000..97d62b5fc
--- /dev/null
+++ b/ansible_collections/community/aws/plugins/modules/ec2_carrier_gateway.py
@@ -0,0 +1,259 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r"""
+---
+module: ec2_carrier_gateway
+version_added: 6.0.0
+short_description: Manage an AWS VPC Carrier gateway
+description:
+ - Manage an AWS VPC Carrier gateway.
+author:
+ - "Marco Braga (@mtulio)"
+options:
+ vpc_id:
+ description:
+ - The VPC ID for the VPC in which to manage the Carrier Gateway.
+ required: true
+ type: str
+ carrier_gateway_id:
+ description:
+ - The Carrier Gateway ID to manage the Carrier Gateway.
+ required: false
+ type: str
+ state:
+ description:
+ - Create or terminate the Carrier Gateway.
+ default: present
+ choices: [ 'present', 'absent' ]
+ type: str
+extends_documentation_fragment:
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.tags
+ - amazon.aws.boto3
+"""
+
+EXAMPLES = r"""
+# Note: These examples do not set authentication details, see the AWS Guide for details.
+
+# Ensure that the VPC has an Carrier Gateway.
+# The Carrier Gateway ID can be accessed via {{cagw.carrier_gateway_id}} for use in setting up Route tables etc.
+- name: Create Carrier gateway
+ community.aws.ec2_carrier_gateway:
+ vpc_id: vpc-abcdefgh
+ state: present
+ register: cagw
+
+- name: Create Carrier gateway with tags
+ community.aws.ec2_carrier_gateway:
+ vpc_id: vpc-abcdefgh
+ state: present
+ tags:
+ Tag1: tag1
+ Tag2: tag2
+ register: cagw
+
+- name: Delete Carrier gateway
+ community.aws.ec2_carrier_gateway:
+ vpc_id: vpc-abcdefgh
+ carrier_gateway_id: "cagw-123"
+ state: absent
+ register: vpc_cagw_delete
+"""
+
+RETURN = r"""
+changed:
+ description: If any changes have been made to the Carrier Gateway.
+ type: bool
+ returned: always
+ sample:
+ changed: false
+carrier_gateway_id:
+ description: The unique identifier for the Carrier Gateway.
+ type: str
+ returned: I(state=present)
+ sample:
+ carrier_gateway_id: "cagw-XXXXXXXX"
+tags:
+ description: The tags associated the Carrier Gateway.
+ type: dict
+ returned: I(state=present)
+ sample:
+ tags:
+ "Ansible": "Test"
+vpc_id:
+ description: The VPC ID associated with the Carrier Gateway.
+ type: str
+ returned: I(state=present)
+ sample:
+ vpc_id: "vpc-XXXXXXXX"
+"""
+
+try:
+ import botocore
+except ImportError:
+ pass # caught by AnsibleAWSModule
+
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_message
+from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ensure_ec2_tags
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.transformation import ansible_dict_to_boto3_filter_list
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
+
+
+@AWSRetry.jittered_backoff(retries=10, delay=10)
+def describe_cagws_with_backoff(connection, **params):
+ paginator = connection.get_paginator("describe_carrier_gateways")
+ return paginator.paginate(**params).build_full_result()["CarrierGateways"]
+
+
+class AnsibleEc2Cagw:
+ def __init__(self, module, results):
+ self._module = module
+ self._results = results
+ self._connection = self._module.client("ec2", retry_decorator=AWSRetry.jittered_backoff())
+ self._check_mode = self._module.check_mode
+
+ def process(self):
+ vpc_id = self._module.params.get("vpc_id")
+ state = self._module.params.get("state", "present")
+ tags = self._module.params.get("tags")
+ purge_tags = self._module.params.get("purge_tags")
+
+ if state == "present":
+ self.ensure_cagw_present(vpc_id, tags, purge_tags)
+ elif state == "absent":
+ self.ensure_cagw_absent(vpc_id)
+
+ def get_matching_cagw(self, vpc_id, carrier_gateway_id=None):
+ """
+ Returns the carrier gateway found.
+ Parameters:
+ vpc_id (str): VPC ID
+ carrier_gateway_id (str): Carrier Gateway ID, if specified
+ Returns:
+ cagw (dict): dict of cagw found, None if none found
+ """
+ filters = ansible_dict_to_boto3_filter_list({"vpc-id": vpc_id})
+ try:
+ if not carrier_gateway_id:
+ cagws = describe_cagws_with_backoff(
+ self._connection,
+ Filters=filters,
+ )
+ else:
+ cagws = describe_cagws_with_backoff(
+ self._connection,
+ CarrierGatewayIds=[carrier_gateway_id],
+ )
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ self._module.fail_json_aws(e)
+
+ cagw = None
+ if len(cagws) > 1:
+ self._module.fail_json(msg=f"EC2 returned more than one Carrier Gateway for VPC {vpc_id}, aborting")
+ elif cagws:
+ cagw = camel_dict_to_snake_dict(cagws[0])
+
+ return cagw
+
+ @staticmethod
+ def get_cagw_info(cagw, vpc_id):
+ return {
+ "carrier_gateway_id": cagw["carrier_gateway_id"],
+ "tags": boto3_tag_list_to_ansible_dict(cagw["tags"]),
+ "vpc_id": vpc_id,
+ }
+
+ def ensure_cagw_absent(self, vpc_id):
+ cagw = self.get_matching_cagw(vpc_id)
+ if cagw is None:
+ return self._results
+
+ if self._check_mode:
+ self._results["changed"] = True
+ return self._results
+
+ try:
+ self._results["changed"] = True
+ self._connection.delete_carrier_gateway(
+ aws_retry=True,
+ CarrierGatewayId=cagw["carrier_gateway_id"],
+ )
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ self._module.fail_json_aws(e, msg="Unable to delete Carrier Gateway")
+
+ return self._results
+
+ def ensure_cagw_present(self, vpc_id, tags, purge_tags):
+ cagw = self.get_matching_cagw(vpc_id)
+
+ if cagw is None:
+ if self._check_mode:
+ self._results["changed"] = True
+ self._results["carrier_gateway_id"] = None
+ return self._results
+
+ try:
+ response = self._connection.create_carrier_gateway(VpcId=vpc_id, aws_retry=True)
+ cagw = camel_dict_to_snake_dict(response["CarrierGateway"])
+ self._results["changed"] = True
+ except is_boto3_error_message("You must be opted into a wavelength zone to create a carrier gateway.") as e:
+ self._module.fail_json(msg="You must be opted into a wavelength zone to create a carrier gateway")
+ except botocore.exceptions.WaiterError as e:
+ self._module.fail_json_aws(e, msg="No Carrier Gateway exists.")
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ self._module.fail_json_aws(e, msg="Unable to create Carrier Gateway")
+
+ # Modify tags
+ self._results["changed"] |= ensure_ec2_tags(
+ self._connection,
+ self._module,
+ cagw["carrier_gateway_id"],
+ resource_type="carrier-gateway",
+ tags=tags,
+ purge_tags=purge_tags,
+ retry_codes="InvalidCarrierGatewayID.NotFound",
+ )
+
+ # Update cagw
+ cagw = self.get_matching_cagw(vpc_id, carrier_gateway_id=cagw["carrier_gateway_id"])
+ cagw_info = self.get_cagw_info(cagw, vpc_id)
+ self._results.update(cagw_info)
+
+ return self._results
+
+
+def main():
+ argument_spec = dict(
+ carrier_gateway_id=dict(required=False),
+ vpc_id=dict(required=True),
+ state=dict(default="present", choices=["present", "absent"]),
+ tags=dict(required=False, type="dict", aliases=["resource_tags"]),
+ purge_tags=dict(default=True, type="bool"),
+ )
+
+ module = AnsibleAWSModule(
+ argument_spec=argument_spec,
+ required_one_of=[["vpc_id", "carrier_gateway_id"]],
+ supports_check_mode=True,
+ )
+ results = dict(
+ changed=False,
+ )
+ cagw_manager = AnsibleEc2Cagw(module=module, results=results)
+ cagw_manager.process()
+
+ module.exit_json(**results)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/aws/plugins/modules/ec2_carrier_gateway_info.py b/ansible_collections/community/aws/plugins/modules/ec2_carrier_gateway_info.py
new file mode 100644
index 000000000..67ee30e55
--- /dev/null
+++ b/ansible_collections/community/aws/plugins/modules/ec2_carrier_gateway_info.py
@@ -0,0 +1,159 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r"""
+---
+module: ec2_carrier_gateway_info
+version_added: 6.0.0
+short_description: Gather information about carrier gateways in AWS
+description:
+ - Gather information about carrier gateways in AWS.
+author:
+ - "Marco Braga (@mtulio)"
+options:
+ filters:
+ description:
+ - A dict of filters to apply. Each dict item consists of a filter key and a filter value.
+ See U(https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeCarrierGateways.html) for possible filters.
+ required: false
+ default: {}
+ type: dict
+ carrier_gateway_ids:
+ description:
+ - Get details of specific Carrier Gateway ID.
+ required: false
+ type: list
+ elements: str
+extends_documentation_fragment:
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
+
+EXAMPLES = r"""
+# # Note: These examples do not set authentication details, see the AWS Guide for details.
+
+- name: Gather information about all Carrier Gateways for an account or profile
+ community.aws.ec2_carrier_gateway_info:
+ region: ap-southeast-2
+ register: cagw_info
+
+- name: Gather information about a filtered list of Carrier Gateways
+ community.aws.ec2_carrier_gateway_info:
+ region: ap-southeast-2
+ filters:
+ "tag:Name": "cagw-123"
+ register: cagw_info
+
+- name: Gather information about a specific carrier gateway by CarrierGatewayId
+ community.aws.ec2_carrier_gateway_info:
+ region: ap-southeast-2
+ carrier_gateway_ids: cagw-c1231234
+ register: cagw_info
+"""
+
+RETURN = r"""
+changed:
+ description: True if listing the carrier gateways succeeds.
+ type: bool
+ returned: always
+ sample: "false"
+carrier_gateways:
+ description: The carrier gateways for the account.
+ returned: always
+ type: complex
+ contains:
+ vpc_id:
+ description: The ID of the VPC.
+ returned: I(state=present)
+ type: str
+ sample: vpc-02123b67
+ carrier_gateway_id:
+ description: The ID of the carrier gateway.
+ returned: I(state=present)
+ type: str
+ sample: cagw-2123634d
+ tags:
+ description: Any tags assigned to the carrier gateway.
+ returned: I(state=present)
+ type: dict
+ sample:
+ tags:
+ "Ansible": "Test"
+"""
+
+try:
+ import botocore
+except ImportError:
+ pass # Handled by AnsibleAWSModule
+
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.transformation import ansible_dict_to_boto3_filter_list
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
+
+
+def get_carrier_gateway_info(carrier_gateway):
+ tags = boto3_tag_list_to_ansible_dict(carrier_gateway["Tags"])
+ ignore_list = []
+ carrier_gateway_info = {
+ "CarrierGatewayId": carrier_gateway["CarrierGatewayId"],
+ "VpcId": carrier_gateway["VpcId"],
+ "Tags": tags,
+ }
+
+ carrier_gateway_info = camel_dict_to_snake_dict(carrier_gateway_info, ignore_list=ignore_list)
+ return carrier_gateway_info
+
+
+def list_carrier_gateways(connection, module):
+ params = dict()
+
+ params["Filters"] = ansible_dict_to_boto3_filter_list(module.params.get("filters"))
+ if module.params.get("carrier_gateway_ids"):
+ params["CarrierGatewayIds"] = module.params.get("carrier_gateway_ids")
+
+ try:
+ all_carrier_gateways = connection.describe_carrier_gateways(aws_retry=True, **params)
+ except is_boto3_error_code("InvalidCarrierGatewayID.NotFound"):
+ module.fail_json("CarrierGateway not found")
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(e, "Unable to describe carrier gateways")
+
+ return [get_carrier_gateway_info(cagw) for cagw in all_carrier_gateways["CarrierGateways"]]
+
+
+def main():
+ argument_spec = dict(
+ carrier_gateway_ids=dict(default=None, elements="str", type="list"),
+ filters=dict(default={}, type="dict"),
+ )
+
+ module = AnsibleAWSModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
+
+ # Validate Requirements
+ try:
+ connection = module.client("ec2", retry_decorator=AWSRetry.jittered_backoff())
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ module.fail_json_aws(e, msg="Failed to connect to AWS")
+
+ results = list_carrier_gateways(connection, module)
+
+ module.exit_json(carrier_gateways=results)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/aws/plugins/modules/ec2_customer_gateway.py b/ansible_collections/community/aws/plugins/modules/ec2_customer_gateway.py
index 3b176b5ee..19fc8eab7 100644
--- a/ansible_collections/community/aws/plugins/modules/ec2_customer_gateway.py
+++ b/ansible_collections/community/aws/plugins/modules/ec2_customer_gateway.py
@@ -1,25 +1,24 @@
#!/usr/bin/python
-#
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
+# -*- coding: utf-8 -*-
+# Copyright: Contributors to the Ansible project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: ec2_customer_gateway
version_added: 1.0.0
short_description: Manage an AWS customer gateway
description:
- - Manage an AWS customer gateway.
-author: Michael Baydoun (@MichaelBaydoun)
+ - Manage an AWS customer gateway.
+author:
+ - Michael Baydoun (@MichaelBaydoun)
notes:
- - You cannot create more than one customer gateway with the same IP address. If you run an identical request more than one time, the
- first request creates the customer gateway, and subsequent requests return information about the existing customer gateway. The subsequent
- requests do not create new customer gateway resources.
- - Return values contain customer_gateway and customer_gateways keys which are identical dicts. You should use
- customer_gateway. See U(https://github.com/ansible/ansible-modules-extras/issues/2773) for details.
+ - You cannot create more than one customer gateway with the same IP address. If you run an identical request more than one time, the
+ first request creates the customer gateway, and subsequent requests return information about the existing customer gateway. The subsequent
+ requests do not create new customer gateway resources.
+ - Return values contain customer_gateway and customer_gateways keys which are identical dicts. You should use
+ customer_gateway. See U(https://github.com/ansible/ansible-modules-extras/issues/2773) for details.
options:
bgp_asn:
description:
@@ -49,13 +48,12 @@ options:
choices: [ 'present', 'absent' ]
type: str
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
-
-'''
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
- name: Create Customer Gateway
community.aws.ec2_customer_gateway:
bgp_asn: 12345
@@ -71,9 +69,9 @@ EXAMPLES = '''
state: absent
region: us-east-1
register: cgw
-'''
+"""
-RETURN = '''
+RETURN = r"""
gateway.customer_gateways:
description: details about the gateway that was created.
returned: success
@@ -108,7 +106,7 @@ gateway.customer_gateways:
returned: when gateway exists and is available.
sample: ipsec.1
type: str
-'''
+"""
try:
import botocore
@@ -117,26 +115,23 @@ except ImportError:
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
-class Ec2CustomerGatewayManager:
+class Ec2CustomerGatewayManager:
def __init__(self, module):
self.module = module
try:
- self.ec2 = module.client('ec2')
+ self.ec2 = module.client("ec2")
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to connect to AWS')
+ module.fail_json_aws(e, msg="Failed to connect to AWS")
- @AWSRetry.jittered_backoff(delay=2, max_delay=30, retries=6, catch_extra_error_codes=['IncorrectState'])
+ @AWSRetry.jittered_backoff(delay=2, max_delay=30, retries=6, catch_extra_error_codes=["IncorrectState"])
def ensure_cgw_absent(self, gw_id):
- response = self.ec2.delete_customer_gateway(
- DryRun=False,
- CustomerGatewayId=gw_id
- )
+ response = self.ec2.delete_customer_gateway(DryRun=False, CustomerGatewayId=gw_id)
return response
def ensure_cgw_present(self, bgp_asn, ip_address):
@@ -144,7 +139,7 @@ class Ec2CustomerGatewayManager:
bgp_asn = 65000
response = self.ec2.create_customer_gateway(
DryRun=False,
- Type='ipsec.1',
+ Type="ipsec.1",
PublicIp=ip_address,
BgpAsn=bgp_asn,
)
@@ -157,11 +152,8 @@ class Ec2CustomerGatewayManager:
gw_id,
],
Tags=[
- {
- 'Key': 'Name',
- 'Value': name
- },
- ]
+ {"Key": "Name", "Value": name},
+ ],
)
return response
@@ -170,86 +162,84 @@ class Ec2CustomerGatewayManager:
DryRun=False,
Filters=[
{
- 'Name': 'state',
- 'Values': [
- 'available',
- ]
+ "Name": "state",
+ "Values": [
+ "available",
+ ],
},
{
- 'Name': 'ip-address',
- 'Values': [
+ "Name": "ip-address",
+ "Values": [
ip_address,
- ]
- }
- ]
+ ],
+ },
+ ],
)
return response
def main():
argument_spec = dict(
- bgp_asn=dict(required=False, type='int'),
+ bgp_asn=dict(required=False, type="int"),
ip_address=dict(required=True),
name=dict(required=True),
- routing=dict(default='dynamic', choices=['dynamic', 'static']),
- state=dict(default='present', choices=['present', 'absent']),
+ routing=dict(default="dynamic", choices=["dynamic", "static"]),
+ state=dict(default="present", choices=["present", "absent"]),
)
module = AnsibleAWSModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
- ('routing', 'dynamic', ['bgp_asn'])
- ]
+ ("routing", "dynamic", ["bgp_asn"]),
+ ],
)
gw_mgr = Ec2CustomerGatewayManager(module)
- name = module.params.get('name')
+ name = module.params.get("name")
- existing = gw_mgr.describe_gateways(module.params['ip_address'])
+ existing = gw_mgr.describe_gateways(module.params["ip_address"])
results = dict(changed=False)
- if module.params['state'] == 'present':
- if existing['CustomerGateways']:
- existing['CustomerGateway'] = existing['CustomerGateways'][0]
- results['gateway'] = existing
- if existing['CustomerGateway']['Tags']:
- tag_array = existing['CustomerGateway']['Tags']
+ if module.params["state"] == "present":
+ if existing["CustomerGateways"]:
+ existing["CustomerGateway"] = existing["CustomerGateways"][0]
+ results["gateway"] = existing
+ if existing["CustomerGateway"]["Tags"]:
+ tag_array = existing["CustomerGateway"]["Tags"]
for key, value in enumerate(tag_array):
- if value['Key'] == 'Name':
- current_name = value['Value']
+ if value["Key"] == "Name":
+ current_name = value["Value"]
if current_name != name:
- results['name'] = gw_mgr.tag_cgw_name(
- results['gateway']['CustomerGateway']['CustomerGatewayId'],
- module.params['name'],
+ results["name"] = gw_mgr.tag_cgw_name(
+ results["gateway"]["CustomerGateway"]["CustomerGatewayId"],
+ module.params["name"],
)
- results['changed'] = True
+ results["changed"] = True
else:
if not module.check_mode:
- results['gateway'] = gw_mgr.ensure_cgw_present(
- module.params['bgp_asn'],
- module.params['ip_address'],
+ results["gateway"] = gw_mgr.ensure_cgw_present(
+ module.params["bgp_asn"],
+ module.params["ip_address"],
)
- results['name'] = gw_mgr.tag_cgw_name(
- results['gateway']['CustomerGateway']['CustomerGatewayId'],
- module.params['name'],
+ results["name"] = gw_mgr.tag_cgw_name(
+ results["gateway"]["CustomerGateway"]["CustomerGatewayId"],
+ module.params["name"],
)
- results['changed'] = True
+ results["changed"] = True
- elif module.params['state'] == 'absent':
- if existing['CustomerGateways']:
- existing['CustomerGateway'] = existing['CustomerGateways'][0]
- results['gateway'] = existing
+ elif module.params["state"] == "absent":
+ if existing["CustomerGateways"]:
+ existing["CustomerGateway"] = existing["CustomerGateways"][0]
+ results["gateway"] = existing
if not module.check_mode:
- results['gateway'] = gw_mgr.ensure_cgw_absent(
- existing['CustomerGateway']['CustomerGatewayId']
- )
- results['changed'] = True
+ results["gateway"] = gw_mgr.ensure_cgw_absent(existing["CustomerGateway"]["CustomerGatewayId"])
+ results["changed"] = True
pretty_results = camel_dict_to_snake_dict(results)
module.exit_json(**pretty_results)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/ec2_customer_gateway_info.py b/ansible_collections/community/aws/plugins/modules/ec2_customer_gateway_info.py
index 429ba2083..18c1a366a 100644
--- a/ansible_collections/community/aws/plugins/modules/ec2_customer_gateway_info.py
+++ b/ansible_collections/community/aws/plugins/modules/ec2_customer_gateway_info.py
@@ -1,19 +1,18 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: ec2_customer_gateway_info
version_added: 1.0.0
short_description: Gather information about customer gateways in AWS
description:
- - Gather information about customer gateways in AWS.
-author: Madhura Naniwadekar (@Madhura-CSI)
+ - Gather information about customer gateways in AWS.
+author:
+ - Madhura Naniwadekar (@Madhura-CSI)
options:
filters:
description:
@@ -28,13 +27,12 @@ options:
elements: str
default: []
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-'''
-
-EXAMPLES = r'''
+EXAMPLES = r"""
# # Note: These examples do not set authentication details, see the AWS Guide for details.
- name: Gather information about all customer gateways
@@ -55,9 +53,9 @@ EXAMPLES = r'''
- 'cgw-48841a09'
- 'cgw-fec021ce'
register: cust_gw_info
-'''
+"""
-RETURN = r'''
+RETURN = r"""
customer_gateways:
description: List of one or more customer gateways.
returned: always
@@ -78,60 +76,65 @@ customer_gateways:
"type": "ipsec.1"
}
]
-'''
+"""
import json
+
try:
- from botocore.exceptions import ClientError, BotoCoreError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
except ImportError:
pass # caught by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import (ansible_dict_to_boto3_filter_list,
- boto3_tag_list_to_ansible_dict,
- camel_dict_to_snake_dict,
- )
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.transformation import ansible_dict_to_boto3_filter_list
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def date_handler(obj):
- return obj.isoformat() if hasattr(obj, 'isoformat') else obj
+ return obj.isoformat() if hasattr(obj, "isoformat") else obj
def list_customer_gateways(connection, module):
params = dict()
- params['Filters'] = ansible_dict_to_boto3_filter_list(module.params.get('filters'))
- params['CustomerGatewayIds'] = module.params.get('customer_gateway_ids')
+ params["Filters"] = ansible_dict_to_boto3_filter_list(module.params.get("filters"))
+ params["CustomerGatewayIds"] = module.params.get("customer_gateway_ids")
try:
result = json.loads(json.dumps(connection.describe_customer_gateways(**params), default=date_handler))
except (ClientError, BotoCoreError) as e:
module.fail_json_aws(e, msg="Could not describe customer gateways")
- snaked_customer_gateways = [camel_dict_to_snake_dict(gateway) for gateway in result['CustomerGateways']]
+ snaked_customer_gateways = [camel_dict_to_snake_dict(gateway) for gateway in result["CustomerGateways"]]
if snaked_customer_gateways:
for customer_gateway in snaked_customer_gateways:
- customer_gateway['tags'] = boto3_tag_list_to_ansible_dict(customer_gateway.get('tags', []))
- customer_gateway_name = customer_gateway['tags'].get('Name')
+ customer_gateway["tags"] = boto3_tag_list_to_ansible_dict(customer_gateway.get("tags", []))
+ customer_gateway_name = customer_gateway["tags"].get("Name")
if customer_gateway_name:
- customer_gateway['customer_gateway_name'] = customer_gateway_name
+ customer_gateway["customer_gateway_name"] = customer_gateway_name
module.exit_json(changed=False, customer_gateways=snaked_customer_gateways)
def main():
-
argument_spec = dict(
- customer_gateway_ids=dict(default=[], type='list', elements='str'),
- filters=dict(default={}, type='dict')
+ customer_gateway_ids=dict(default=[], type="list", elements="str"), filters=dict(default={}, type="dict")
)
- module = AnsibleAWSModule(argument_spec=argument_spec,
- mutually_exclusive=[['customer_gateway_ids', 'filters']],
- supports_check_mode=True)
+ module = AnsibleAWSModule(
+ argument_spec=argument_spec,
+ mutually_exclusive=[
+ ["customer_gateway_ids", "filters"],
+ ],
+ supports_check_mode=True,
+ )
- connection = module.client('ec2')
+ connection = module.client("ec2")
list_customer_gateways(connection, module)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/ec2_launch_template.py b/ansible_collections/community/aws/plugins/modules/ec2_launch_template.py
index 67fb0f43b..9fd32711f 100644
--- a/ansible_collections/community/aws/plugins/modules/ec2_launch_template.py
+++ b/ansible_collections/community/aws/plugins/modules/ec2_launch_template.py
@@ -1,11 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright (c) 2018 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: ec2_launch_template
version_added: 1.0.0
@@ -16,10 +15,6 @@ description:
- The M(amazon.aws.ec2_instance) and M(community.aws.autoscaling_group) modules can, instead of specifying all
parameters on those tasks, be passed a Launch Template which contains
settings like instance size, disk type, subnet, and more.
-extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
author:
- Ryan Scott Brown (@ryansb)
options:
@@ -373,7 +368,6 @@ options:
type: str
description: >
- Wether the instance metadata endpoint is available via IPv6 (C(enabled)) or not (C(disabled)).
- - Requires botocore >= 1.21.29
choices: [enabled, disabled]
default: 'disabled'
instance_metadata_tags:
@@ -381,12 +375,15 @@ options:
type: str
description:
- Wether the instance tags are availble (C(enabled)) via metadata endpoint or not (C(disabled)).
- - Requires botocore >= 1.23.30
choices: [enabled, disabled]
default: 'disabled'
-'''
+extends_documentation_fragment:
+- amazon.aws.common.modules
+- amazon.aws.region.modules
+- amazon.aws.boto3
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
- name: Create an ec2 launch template
community.aws.ec2_launch_template:
name: "my_template"
@@ -410,9 +407,9 @@ EXAMPLES = '''
state: absent
# This module does not yet allow deletion of specific versions of launch templates
-'''
+"""
-RETURN = '''
+RETURN = r"""
latest_version:
description: Latest available version of the launch template
returned: when state=present
@@ -421,82 +418,110 @@ default_version:
description: The version that will be used if only the template name is specified. Often this is the same as the latest version, but not always.
returned: when state=present
type: int
-'''
-import re
+"""
+
from uuid import uuid4
+try:
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
+ from botocore.exceptions import WaiterError
+except ImportError:
+ pass # caught by AnsibleAWSModule
+
from ansible.module_utils._text import to_text
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
from ansible.module_utils.common.dict_transformations import snake_dict_to_camel_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.core import scrub_none_parameters
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_tag_list
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.arn import validate_aws_arn
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import ansible_dict_to_boto3_tag_list
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.transformation import scrub_none_parameters
-try:
- from botocore.exceptions import ClientError, BotoCoreError, WaiterError
-except ImportError:
- pass # caught by AnsibleAWSModule
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def determine_iam_role(module, name_or_arn):
- if re.match(r'^arn:aws:iam::\d+:instance-profile/[\w+=/,.@-]+$', name_or_arn):
- return {'arn': name_or_arn}
- iam = module.client('iam', retry_decorator=AWSRetry.jittered_backoff())
+ if validate_aws_arn(name_or_arn, service="iam", resource_type="instance-profile"):
+ return {"arn": name_or_arn}
+ iam = module.client("iam", retry_decorator=AWSRetry.jittered_backoff())
try:
role = iam.get_instance_profile(InstanceProfileName=name_or_arn, aws_retry=True)
- return {'arn': role['InstanceProfile']['Arn']}
- except is_boto3_error_code('NoSuchEntity') as e:
- module.fail_json_aws(e, msg="Could not find instance_role {0}".format(name_or_arn))
+ return {"arn": role["InstanceProfile"]["Arn"]}
+ except is_boto3_error_code("NoSuchEntity") as e:
+ module.fail_json_aws(e, msg=f"Could not find instance_role {name_or_arn}")
except (BotoCoreError, ClientError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, msg="An error occurred while searching for instance_role {0}. Please try supplying the full ARN.".format(name_or_arn))
+ module.fail_json_aws(
+ e,
+ msg=f"An error occurred while searching for instance_role {name_or_arn}. Please try supplying the full ARN.",
+ )
def existing_templates(module):
- ec2 = module.client('ec2', retry_decorator=AWSRetry.jittered_backoff())
+ ec2 = module.client("ec2", retry_decorator=AWSRetry.jittered_backoff())
matches = None
try:
- if module.params.get('template_id'):
- matches = ec2.describe_launch_templates(LaunchTemplateIds=[module.params.get('template_id')], aws_retry=True)
- elif module.params.get('template_name'):
- matches = ec2.describe_launch_templates(LaunchTemplateNames=[module.params.get('template_name')], aws_retry=True)
- except is_boto3_error_code('InvalidLaunchTemplateName.NotFoundException') as e:
+ if module.params.get("template_id"):
+ matches = ec2.describe_launch_templates(
+ LaunchTemplateIds=[module.params.get("template_id")], aws_retry=True
+ )
+ elif module.params.get("template_name"):
+ matches = ec2.describe_launch_templates(
+ LaunchTemplateNames=[module.params.get("template_name")], aws_retry=True
+ )
+ except is_boto3_error_code("InvalidLaunchTemplateName.NotFoundException") as e:
# no named template was found, return nothing/empty versions
return None, []
- except is_boto3_error_code('InvalidLaunchTemplateId.Malformed') as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, msg='Launch template with ID {0} is not a valid ID. It should start with `lt-....`'.format(
- module.params.get('launch_template_id')))
- except is_boto3_error_code('InvalidLaunchTemplateId.NotFoundException') as e: # pylint: disable=duplicate-except
+ except is_boto3_error_code("InvalidLaunchTemplateId.Malformed") as e: # pylint: disable=duplicate-except
module.fail_json_aws(
- e, msg='Launch template with ID {0} could not be found, please supply a name '
- 'instead so that a new template can be created'.format(module.params.get('launch_template_id')))
+ e,
+ msg=(
+ f"Launch template with ID {module.params.get('launch_template_id')} is not a valid ID. It should start"
+ " with `lt-....`"
+ ),
+ )
+ except is_boto3_error_code("InvalidLaunchTemplateId.NotFoundException") as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(
+ e,
+ msg=(
+ f"Launch template with ID {module.params.get('launch_template_id')} could not be found, please supply a"
+ " name instead so that a new template can be created"
+ ),
+ )
except (ClientError, BotoCoreError, WaiterError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, msg='Could not check existing launch templates. This may be an IAM permission problem.')
+ module.fail_json_aws(e, msg="Could not check existing launch templates. This may be an IAM permission problem.")
else:
- template = matches['LaunchTemplates'][0]
- template_id, template_version, template_default = template['LaunchTemplateId'], template['LatestVersionNumber'], template['DefaultVersionNumber']
+ template = matches["LaunchTemplates"][0]
+ template_id, template_version, template_default = (
+ template["LaunchTemplateId"],
+ template["LatestVersionNumber"],
+ template["DefaultVersionNumber"],
+ )
try:
- return template, ec2.describe_launch_template_versions(LaunchTemplateId=template_id, aws_retry=True)['LaunchTemplateVersions']
+ return (
+ template,
+ ec2.describe_launch_template_versions(LaunchTemplateId=template_id, aws_retry=True)[
+ "LaunchTemplateVersions"
+ ],
+ )
except (ClientError, BotoCoreError, WaiterError) as e:
- module.fail_json_aws(e, msg='Could not find launch template versions for {0} (ID: {1}).'.format(template['LaunchTemplateName'], template_id))
+ module.fail_json_aws(
+ e,
+ msg=f"Could not find launch template versions for {template['LaunchTemplateName']} (ID: {template_id}).",
+ )
def params_to_launch_data(module, template_params):
- if template_params.get('tags'):
- tag_list = ansible_dict_to_boto3_tag_list(template_params.get('tags'))
- template_params['tag_specifications'] = [
- {
- 'resource_type': r_type,
- 'tags': tag_list
- }
- for r_type in ('instance', 'volume')
+ if template_params.get("tags"):
+ tag_list = ansible_dict_to_boto3_tag_list(template_params.get("tags"))
+ template_params["tag_specifications"] = [
+ {"resource_type": r_type, "tags": tag_list} for r_type in ("instance", "volume")
]
- del template_params['tags']
- if module.params.get('iam_instance_profile'):
- template_params['iam_instance_profile'] = determine_iam_role(module, module.params['iam_instance_profile'])
+ del template_params["tags"]
+ if module.params.get("iam_instance_profile"):
+ template_params["iam_instance_profile"] = determine_iam_role(module, module.params["iam_instance_profile"])
params = snake_dict_to_camel_dict(
dict((k, v) for k, v in template_params.items() if v is not None),
capitalize_first=True,
@@ -505,71 +530,61 @@ def params_to_launch_data(module, template_params):
def delete_template(module):
- ec2 = module.client('ec2', retry_decorator=AWSRetry.jittered_backoff())
+ ec2 = module.client("ec2", retry_decorator=AWSRetry.jittered_backoff())
template, template_versions = existing_templates(module)
deleted_versions = []
if template or template_versions:
- non_default_versions = [to_text(t['VersionNumber']) for t in template_versions if not t['DefaultVersion']]
+ non_default_versions = [to_text(t["VersionNumber"]) for t in template_versions if not t["DefaultVersion"]]
if non_default_versions:
try:
v_resp = ec2.delete_launch_template_versions(
- LaunchTemplateId=template['LaunchTemplateId'],
+ LaunchTemplateId=template["LaunchTemplateId"],
Versions=non_default_versions,
aws_retry=True,
)
- if v_resp['UnsuccessfullyDeletedLaunchTemplateVersions']:
- module.warn('Failed to delete template versions {0} on launch template {1}'.format(
- v_resp['UnsuccessfullyDeletedLaunchTemplateVersions'],
- template['LaunchTemplateId'],
- ))
- deleted_versions = [camel_dict_to_snake_dict(v) for v in v_resp['SuccessfullyDeletedLaunchTemplateVersions']]
+ if v_resp["UnsuccessfullyDeletedLaunchTemplateVersions"]:
+ module.warn(
+ f"Failed to delete template versions {v_resp['UnsuccessfullyDeletedLaunchTemplateVersions']} on"
+ f" launch template {template['LaunchTemplateId']}"
+ )
+ deleted_versions = [
+ camel_dict_to_snake_dict(v) for v in v_resp["SuccessfullyDeletedLaunchTemplateVersions"]
+ ]
except (ClientError, BotoCoreError) as e:
- module.fail_json_aws(e, msg="Could not delete existing versions of the launch template {0}".format(template['LaunchTemplateId']))
+ module.fail_json_aws(
+ e,
+ msg=f"Could not delete existing versions of the launch template {template['LaunchTemplateId']}",
+ )
try:
resp = ec2.delete_launch_template(
- LaunchTemplateId=template['LaunchTemplateId'],
+ LaunchTemplateId=template["LaunchTemplateId"],
aws_retry=True,
)
except (ClientError, BotoCoreError) as e:
- module.fail_json_aws(e, msg="Could not delete launch template {0}".format(template['LaunchTemplateId']))
+ module.fail_json_aws(e, msg=f"Could not delete launch template {template['LaunchTemplateId']}")
return {
- 'deleted_versions': deleted_versions,
- 'deleted_template': camel_dict_to_snake_dict(resp['LaunchTemplate']),
- 'changed': True,
+ "deleted_versions": deleted_versions,
+ "deleted_template": camel_dict_to_snake_dict(resp["LaunchTemplate"]),
+ "changed": True,
}
else:
- return {'changed': False}
+ return {"changed": False}
def create_or_update(module, template_options):
- ec2 = module.client('ec2', retry_decorator=AWSRetry.jittered_backoff(catch_extra_error_codes=['InvalidLaunchTemplateId.NotFound']))
+ ec2 = module.client(
+ "ec2", retry_decorator=AWSRetry.jittered_backoff(catch_extra_error_codes=["InvalidLaunchTemplateId.NotFound"])
+ )
template, template_versions = existing_templates(module)
out = {}
lt_data = params_to_launch_data(module, dict((k, v) for k, v in module.params.items() if k in template_options))
lt_data = scrub_none_parameters(lt_data, descend_into_lists=True)
- if lt_data.get('MetadataOptions'):
- if not module.botocore_at_least('1.23.30'):
- # fail only if enabled is requested
- if lt_data['MetadataOptions'].get('InstanceMetadataTags') == 'enabled':
- module.require_botocore_at_least('1.23.30', reason='to set instance_metadata_tags')
- # pop if it's not requested to keep backwards compatibility.
- # otherwise the modules failes because parameters are set due default values
- lt_data['MetadataOptions'].pop('InstanceMetadataTags')
-
- if not module.botocore_at_least('1.21.29'):
- # fail only if enabled is requested
- if lt_data['MetadataOptions'].get('HttpProtocolIpv6') == 'enabled':
- module.require_botocore_at_least('1.21.29', reason='to set http_protocol_ipv6')
- # pop if it's not requested to keep backwards compatibility.
- # otherwise the modules failes because parameters are set due default values
- lt_data['MetadataOptions'].pop('HttpProtocolIpv6')
-
if not (template or template_versions):
# create a full new one
try:
resp = ec2.create_launch_template(
- LaunchTemplateName=module.params['template_name'],
+ LaunchTemplateName=module.params["template_name"],
LaunchTemplateData=lt_data,
ClientToken=uuid4().hex,
aws_retry=True,
@@ -577,26 +592,26 @@ def create_or_update(module, template_options):
except (ClientError, BotoCoreError) as e:
module.fail_json_aws(e, msg="Couldn't create launch template")
template, template_versions = existing_templates(module)
- out['changed'] = True
+ out["changed"] = True
elif template and template_versions:
most_recent = sorted(template_versions, key=lambda x: x["VersionNumber"])[-1]
if lt_data == most_recent["LaunchTemplateData"] and module.params["version_description"] == most_recent.get(
"VersionDescription", ""
):
- out['changed'] = False
+ out["changed"] = False
return out
try:
- if module.params.get('source_version') in (None, ''):
+ if module.params.get("source_version") in (None, ""):
resp = ec2.create_launch_template_version(
- LaunchTemplateId=template['LaunchTemplateId'],
+ LaunchTemplateId=template["LaunchTemplateId"],
LaunchTemplateData=lt_data,
ClientToken=uuid4().hex,
VersionDescription=str(module.params["version_description"]),
aws_retry=True,
)
- elif module.params.get('source_version') == 'latest':
+ elif module.params.get("source_version") == "latest":
resp = ec2.create_launch_template_version(
- LaunchTemplateId=template['LaunchTemplateId'],
+ LaunchTemplateId=template["LaunchTemplateId"],
LaunchTemplateData=lt_data,
ClientToken=uuid4().hex,
SourceVersion=str(most_recent["VersionNumber"]),
@@ -605,15 +620,22 @@ def create_or_update(module, template_options):
)
else:
try:
- int(module.params.get('source_version'))
+ int(module.params.get("source_version"))
except ValueError:
- module.fail_json(msg='source_version param was not a valid integer, got "{0}"'.format(module.params.get('source_version')))
+ module.fail_json(
+ msg=f"source_version param was not a valid integer, got \"{module.params.get('source_version')}\""
+ )
# get source template version
- source_version = next((v for v in template_versions if v['VersionNumber'] == int(module.params.get('source_version'))), None)
+ source_version = next(
+ (v for v in template_versions if v["VersionNumber"] == int(module.params.get("source_version"))),
+ None,
+ )
if source_version is None:
- module.fail_json(msg='source_version does not exist, got "{0}"'.format(module.params.get('source_version')))
+ module.fail_json(
+ msg=f"source_version does not exist, got \"{module.params.get('source_version')}\""
+ )
resp = ec2.create_launch_template_version(
- LaunchTemplateId=template['LaunchTemplateId'],
+ LaunchTemplateId=template["LaunchTemplateId"],
LaunchTemplateData=lt_data,
ClientToken=uuid4().hex,
SourceVersion=str(source_version["VersionNumber"]),
@@ -621,31 +643,33 @@ def create_or_update(module, template_options):
aws_retry=True,
)
- if module.params.get('default_version') in (None, ''):
+ if module.params.get("default_version") in (None, ""):
# no need to do anything, leave the existing version as default
pass
- elif module.params.get('default_version') == 'latest':
+ elif module.params.get("default_version") == "latest":
set_default = ec2.modify_launch_template(
- LaunchTemplateId=template['LaunchTemplateId'],
- DefaultVersion=to_text(resp['LaunchTemplateVersion']['VersionNumber']),
+ LaunchTemplateId=template["LaunchTemplateId"],
+ DefaultVersion=to_text(resp["LaunchTemplateVersion"]["VersionNumber"]),
ClientToken=uuid4().hex,
aws_retry=True,
)
else:
try:
- int(module.params.get('default_version'))
+ int(module.params.get("default_version"))
except ValueError:
- module.fail_json(msg='default_version param was not a valid integer, got "{0}"'.format(module.params.get('default_version')))
+ module.fail_json(
+ msg=f"default_version param was not a valid integer, got \"{module.params.get('default_version')}\""
+ )
set_default = ec2.modify_launch_template(
- LaunchTemplateId=template['LaunchTemplateId'],
- DefaultVersion=to_text(int(module.params.get('default_version'))),
+ LaunchTemplateId=template["LaunchTemplateId"],
+ DefaultVersion=to_text(int(module.params.get("default_version"))),
ClientToken=uuid4().hex,
aws_retry=True,
)
except (ClientError, BotoCoreError) as e:
module.fail_json_aws(e, msg="Couldn't create subsequent launch template version")
template, template_versions = existing_templates(module)
- out['changed'] = True
+ out["changed"] = True
return out
@@ -655,43 +679,38 @@ def format_module_output(module):
template = camel_dict_to_snake_dict(template)
template_versions = [camel_dict_to_snake_dict(v) for v in template_versions]
for v in template_versions:
- for ts in (v['launch_template_data'].get('tag_specifications') or []):
- ts['tags'] = boto3_tag_list_to_ansible_dict(ts.pop('tags'))
+ for ts in v["launch_template_data"].get("tag_specifications") or []:
+ ts["tags"] = boto3_tag_list_to_ansible_dict(ts.pop("tags"))
output.update(dict(template=template, versions=template_versions))
- output['default_template'] = [
- v for v in template_versions
- if v.get('default_version')
- ][0]
- output['latest_template'] = [
- v for v in template_versions
- if (
- v.get('version_number') and
- int(v['version_number']) == int(template['latest_version_number'])
- )
+ output["default_template"] = [v for v in template_versions if v.get("default_version")][0]
+ output["latest_template"] = [
+ v
+ for v in template_versions
+ if (v.get("version_number") and int(v["version_number"]) == int(template["latest_version_number"]))
][0]
- if "version_number" in output['default_template']:
- output['default_version'] = output['default_template']['version_number']
- if "version_number" in output['latest_template']:
- output['latest_version'] = output['latest_template']['version_number']
+ if "version_number" in output["default_template"]:
+ output["default_version"] = output["default_template"]["version_number"]
+ if "version_number" in output["latest_template"]:
+ output["latest_version"] = output["latest_template"]["version_number"]
return output
def main():
template_options = dict(
block_device_mappings=dict(
- type='list',
- elements='dict',
+ type="list",
+ elements="dict",
options=dict(
device_name=dict(),
ebs=dict(
- type='dict',
+ type="dict",
options=dict(
- delete_on_termination=dict(type='bool'),
- encrypted=dict(type='bool'),
- iops=dict(type='int'),
+ delete_on_termination=dict(type="bool"),
+ encrypted=dict(type="bool"),
+ iops=dict(type="int"),
kms_key_id=dict(),
snapshot_id=dict(),
- volume_size=dict(type='int'),
+ volume_size=dict(type="int"),
volume_type=dict(),
),
),
@@ -700,39 +719,39 @@ def main():
),
),
cpu_options=dict(
- type='dict',
+ type="dict",
options=dict(
- core_count=dict(type='int'),
- threads_per_core=dict(type='int'),
+ core_count=dict(type="int"),
+ threads_per_core=dict(type="int"),
),
),
credit_specification=dict(
- dict(type='dict'),
+ dict(type="dict"),
options=dict(
cpu_credits=dict(),
),
),
- disable_api_termination=dict(type='bool'),
- ebs_optimized=dict(type='bool'),
+ disable_api_termination=dict(type="bool"),
+ ebs_optimized=dict(type="bool"),
elastic_gpu_specifications=dict(
options=dict(type=dict()),
- type='list',
- elements='dict',
+ type="list",
+ elements="dict",
),
iam_instance_profile=dict(),
image_id=dict(),
- instance_initiated_shutdown_behavior=dict(choices=['stop', 'terminate']),
+ instance_initiated_shutdown_behavior=dict(choices=["stop", "terminate"]),
instance_market_options=dict(
- type='dict',
+ type="dict",
options=dict(
market_type=dict(),
spot_options=dict(
- type='dict',
+ type="dict",
options=dict(
- block_duration_minutes=dict(type='int'),
- instance_interruption_behavior=dict(choices=['hibernate', 'stop', 'terminate']),
+ block_duration_minutes=dict(type="int"),
+ instance_interruption_behavior=dict(choices=["hibernate", "stop", "terminate"]),
max_price=dict(),
- spot_instance_type=dict(choices=['one-time', 'persistent']),
+ spot_instance_type=dict(choices=["one-time", "persistent"]),
),
),
),
@@ -741,32 +760,30 @@ def main():
kernel_id=dict(),
key_name=dict(),
monitoring=dict(
- type='dict',
- options=dict(
- enabled=dict(type='bool')
- ),
+ type="dict",
+ options=dict(enabled=dict(type="bool")),
),
metadata_options=dict(
- type='dict',
+ type="dict",
options=dict(
- http_endpoint=dict(choices=['enabled', 'disabled'], default='enabled'),
- http_put_response_hop_limit=dict(type='int', default=1),
- http_tokens=dict(choices=['optional', 'required'], default='optional'),
- http_protocol_ipv6=dict(choices=['disabled', 'enabled'], default='disabled'),
- instance_metadata_tags=dict(choices=['disabled', 'enabled'], default='disabled'),
- )
+ http_endpoint=dict(choices=["enabled", "disabled"], default="enabled"),
+ http_put_response_hop_limit=dict(type="int", default=1),
+ http_tokens=dict(choices=["optional", "required"], default="optional"),
+ http_protocol_ipv6=dict(choices=["disabled", "enabled"], default="disabled"),
+ instance_metadata_tags=dict(choices=["disabled", "enabled"], default="disabled"),
+ ),
),
network_interfaces=dict(
- type='list',
- elements='dict',
+ type="list",
+ elements="dict",
options=dict(
- associate_public_ip_address=dict(type='bool'),
- delete_on_termination=dict(type='bool'),
+ associate_public_ip_address=dict(type="bool"),
+ delete_on_termination=dict(type="bool"),
description=dict(),
- device_index=dict(type='int'),
- groups=dict(type='list', elements='str'),
- ipv6_address_count=dict(type='int'),
- ipv6_addresses=dict(type='list', elements='str'),
+ device_index=dict(type="int"),
+ groups=dict(type="list", elements="str"),
+ ipv6_address_count=dict(type="int"),
+ ipv6_addresses=dict(type="list", elements="str"),
network_interface_id=dict(),
private_ip_address=dict(),
subnet_id=dict(),
@@ -780,12 +797,12 @@ def main():
host_id=dict(),
tenancy=dict(),
),
- type='dict',
+ type="dict",
),
ram_disk_id=dict(),
- security_group_ids=dict(type='list', elements='str'),
- security_groups=dict(type='list', elements='str'),
- tags=dict(type='dict', aliases=['resource_tags']),
+ security_group_ids=dict(type="list", elements="str"),
+ security_groups=dict(type="list", elements="str"),
+ tags=dict(type="dict", aliases=["resource_tags"]),
user_data=dict(),
)
@@ -803,25 +820,25 @@ def main():
module = AnsibleAWSModule(
argument_spec=arg_spec,
required_one_of=[
- ('template_name', 'template_id')
+ ("template_name", "template_id"),
],
- supports_check_mode=True
+ supports_check_mode=True,
)
- for interface in (module.params.get('network_interfaces') or []):
- if interface.get('ipv6_addresses'):
- interface['ipv6_addresses'] = [{'ipv6_address': x} for x in interface['ipv6_addresses']]
+ for interface in module.params.get("network_interfaces") or []:
+ if interface.get("ipv6_addresses"):
+ interface["ipv6_addresses"] = [{"ipv6_address": x} for x in interface["ipv6_addresses"]]
- if module.params.get('state') == 'present':
+ if module.params.get("state") == "present":
out = create_or_update(module, template_options)
out.update(format_module_output(module))
- elif module.params.get('state') == 'absent':
+ elif module.params.get("state") == "absent":
out = delete_template(module)
else:
- module.fail_json(msg='Unsupported value "{0}" for `state` parameter'.format(module.params.get('state')))
+ module.fail_json(msg=f"Unsupported value \"{module.params.get('state')}\" for `state` parameter")
module.exit_json(**out)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/ec2_placement_group.py b/ansible_collections/community/aws/plugins/modules/ec2_placement_group.py
index c27917df9..3cdb5be21 100644
--- a/ansible_collections/community/aws/plugins/modules/ec2_placement_group.py
+++ b/ansible_collections/community/aws/plugins/modules/ec2_placement_group.py
@@ -1,22 +1,21 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: ec2_placement_group
version_added: 1.0.0
short_description: Create or delete an EC2 Placement Group
description:
- - Create an EC2 Placement Group; if the placement group already exists,
- nothing is done. Or, delete an existing placement group. If the placement
- group is absent, do nothing. See also
- U(https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/placement-groups.html)
-author: "Brad Macpherson (@iiibrad)"
+ - Create an EC2 Placement Group; if the placement group already exists,
+ nothing is done. Or, delete an existing placement group. If the placement
+ group is absent, do nothing. See also
+ U(https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/placement-groups.html)
+author:
+ - "Brad Macpherson (@iiibrad)"
options:
name:
description:
@@ -45,12 +44,12 @@ options:
choices: [ 'cluster', 'spread', 'partition' ]
type: str
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
-'''
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide
# for details.
@@ -76,11 +75,9 @@ EXAMPLES = '''
community.aws.ec2_placement_group:
name: my-cluster
state: absent
+"""
-'''
-
-
-RETURN = '''
+RETURN = r"""
placement_group:
description: Placement group attributes
returned: when state != absent
@@ -98,17 +95,17 @@ placement_group:
description: PG strategy
type: str
sample: "cluster"
-
-'''
+"""
try:
import botocore
except ImportError:
pass # caught by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
@AWSRetry.exponential_backoff()
@@ -118,40 +115,32 @@ def search_placement_group(connection, module):
"""
name = module.params.get("name")
try:
- response = connection.describe_placement_groups(
- Filters=[{
- "Name": "group-name",
- "Values": [name]
- }])
+ response = connection.describe_placement_groups(Filters=[{"Name": "group-name", "Values": [name]}])
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(
- e,
- msg="Couldn't find placement group named [%s]" % name)
+ module.fail_json_aws(e, msg=f"Couldn't find placement group named [{name}]")
- if len(response['PlacementGroups']) != 1:
+ if len(response["PlacementGroups"]) != 1:
return None
else:
- placement_group = response['PlacementGroups'][0]
+ placement_group = response["PlacementGroups"][0]
return {
- "name": placement_group['GroupName'],
- "state": placement_group['State'],
- "strategy": placement_group['Strategy'],
+ "name": placement_group["GroupName"],
+ "state": placement_group["State"],
+ "strategy": placement_group["Strategy"],
}
-@AWSRetry.exponential_backoff(catch_extra_error_codes=['InvalidPlacementGroup.Unknown'])
+@AWSRetry.exponential_backoff(catch_extra_error_codes=["InvalidPlacementGroup.Unknown"])
def get_placement_group_information(connection, name):
"""
Retrieve information about a placement group.
"""
- response = connection.describe_placement_groups(
- GroupNames=[name]
- )
- placement_group = response['PlacementGroups'][0]
+ response = connection.describe_placement_groups(GroupNames=[name])
+ placement_group = response["PlacementGroups"][0]
return {
- "name": placement_group['GroupName'],
- "state": placement_group['State'],
- "strategy": placement_group['Strategy'],
+ "name": placement_group["GroupName"],
+ "state": placement_group["State"],
+ "strategy": placement_group["Strategy"],
}
@@ -161,32 +150,34 @@ def create_placement_group(connection, module):
strategy = module.params.get("strategy")
partition_count = module.params.get("partition_count")
- if strategy != 'partition' and partition_count:
- module.fail_json(
- msg="'partition_count' can only be set when strategy is set to 'partition'.")
+ if strategy != "partition" and partition_count:
+ module.fail_json(msg="'partition_count' can only be set when strategy is set to 'partition'.")
params = {}
- params['GroupName'] = name
- params['Strategy'] = strategy
+ params["GroupName"] = name
+ params["Strategy"] = strategy
if partition_count:
- params['PartitionCount'] = partition_count
- params['DryRun'] = module.check_mode
+ params["PartitionCount"] = partition_count
+ params["DryRun"] = module.check_mode
try:
connection.create_placement_group(**params)
- except is_boto3_error_code('DryRunOperation'):
- module.exit_json(changed=True, placement_group={
- "name": name,
- "state": 'DryRun',
- "strategy": strategy,
- })
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(
- e,
- msg="Couldn't create placement group [%s]" % name)
-
- module.exit_json(changed=True,
- placement_group=get_placement_group_information(connection, name))
+ except is_boto3_error_code("DryRunOperation"):
+ module.exit_json(
+ changed=True,
+ placement_group={
+ "name": name,
+ "state": "DryRun",
+ "strategy": strategy,
+ },
+ )
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(e, msg=f"Couldn't create placement group [{name}]")
+
+ module.exit_json(changed=True, placement_group=get_placement_group_information(connection, name))
@AWSRetry.exponential_backoff()
@@ -194,52 +185,42 @@ def delete_placement_group(connection, module):
name = module.params.get("name")
try:
- connection.delete_placement_group(
- GroupName=name, DryRun=module.check_mode)
+ connection.delete_placement_group(GroupName=name, DryRun=module.check_mode)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(
- e,
- msg="Couldn't delete placement group [%s]" % name)
+ module.fail_json_aws(e, msg=f"Couldn't delete placement group [{name}]")
module.exit_json(changed=True)
def main():
argument_spec = dict(
- name=dict(required=True, type='str'),
- partition_count=dict(type='int'),
- state=dict(default='present', choices=['present', 'absent']),
- strategy=dict(default='cluster', choices=['cluster', 'spread', 'partition'])
+ name=dict(required=True, type="str"),
+ partition_count=dict(type="int"),
+ state=dict(default="present", choices=["present", "absent"]),
+ strategy=dict(default="cluster", choices=["cluster", "spread", "partition"]),
)
- module = AnsibleAWSModule(
- argument_spec=argument_spec,
- supports_check_mode=True
- )
+ module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
- connection = module.client('ec2')
+ connection = module.client("ec2")
state = module.params.get("state")
- if state == 'present':
+ if state == "present":
placement_group = search_placement_group(connection, module)
if placement_group is None:
create_placement_group(connection, module)
else:
strategy = module.params.get("strategy")
- if placement_group['strategy'] == strategy:
- module.exit_json(
- changed=False, placement_group=placement_group)
+ if placement_group["strategy"] == strategy:
+ module.exit_json(changed=False, placement_group=placement_group)
else:
name = module.params.get("name")
module.fail_json(
- msg=("Placement group '{}' exists, can't change strategy" +
- " from '{}' to '{}'").format(
- name,
- placement_group['strategy'],
- strategy))
+ msg=f"Placement group '{name}' exists, can't change strategy from '{placement_group['strategy']}' to '{strategy}'"
+ )
- elif state == 'absent':
+ elif state == "absent":
placement_group = search_placement_group(connection, module)
if placement_group is None:
module.exit_json(changed=False)
@@ -247,5 +228,5 @@ def main():
delete_placement_group(connection, module)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/ec2_placement_group_info.py b/ansible_collections/community/aws/plugins/modules/ec2_placement_group_info.py
index d22f133ae..05b37488c 100644
--- a/ansible_collections/community/aws/plugins/modules/ec2_placement_group_info.py
+++ b/ansible_collections/community/aws/plugins/modules/ec2_placement_group_info.py
@@ -1,19 +1,18 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: ec2_placement_group_info
version_added: 1.0.0
short_description: List EC2 Placement Group(s) details
description:
- - List details of EC2 Placement Group(s).
-author: "Brad Macpherson (@iiibrad)"
+ - List details of EC2 Placement Group(s).
+author:
+ - "Brad Macpherson (@iiibrad)"
options:
names:
description:
@@ -24,13 +23,12 @@ options:
required: false
default: []
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
-
-'''
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
# Note: These examples do not set authentication details or the AWS region,
# see the AWS Guide for details.
@@ -41,18 +39,17 @@ EXAMPLES = r'''
- name: List two placement groups.
community.aws.ec2_placement_group_info:
names:
- - my-cluster
- - my-other-cluster
+ - my-cluster
+ - my-other-cluster
register: specific_ec2_placement_groups
- ansible.builtin.debug:
msg: >
{{ specific_ec2_placement_groups | json_query("[?name=='my-cluster']") }}
+"""
-'''
-
-RETURN = r'''
+RETURN = r"""
placement_groups:
description: Placement group attributes
returned: always
@@ -70,57 +67,61 @@ placement_groups:
description: PG strategy
type: str
sample: "cluster"
+"""
-'''
-
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
try:
- from botocore.exceptions import (BotoCoreError, ClientError)
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
except ImportError:
pass # caught by AnsibleAWSModule
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
+
def get_placement_groups_details(connection, module):
names = module.params.get("names")
try:
if len(names) > 0:
response = connection.describe_placement_groups(
- Filters=[{
- "Name": "group-name",
- "Values": names
- }])
+ Filters=[
+ {
+ "Name": "group-name",
+ "Values": names,
+ }
+ ]
+ )
else:
response = connection.describe_placement_groups()
except (BotoCoreError, ClientError) as e:
- module.fail_json_aws(
- e,
- msg="Couldn't find placement groups named [%s]" % names)
+ module.fail_json_aws(e, msg=f"Couldn't find placement groups named [{names}]")
results = []
- for placement_group in response['PlacementGroups']:
- results.append({
- "name": placement_group['GroupName'],
- "state": placement_group['State'],
- "strategy": placement_group['Strategy'],
- })
+ for placement_group in response["PlacementGroups"]:
+ results.append(
+ {
+ "name": placement_group["GroupName"],
+ "state": placement_group["State"],
+ "strategy": placement_group["Strategy"],
+ }
+ )
return results
def main():
argument_spec = dict(
- names=dict(type='list', default=[], elements='str')
+ names=dict(type="list", default=[], elements="str"),
)
module = AnsibleAWSModule(
argument_spec=argument_spec,
- supports_check_mode=True
+ supports_check_mode=True,
)
- connection = module.client('ec2')
+ connection = module.client("ec2")
placement_groups = get_placement_groups_details(connection, module)
module.exit_json(changed=False, placement_groups=placement_groups)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/ec2_snapshot_copy.py b/ansible_collections/community/aws/plugins/modules/ec2_snapshot_copy.py
index f45be4417..2cf994caa 100644
--- a/ansible_collections/community/aws/plugins/modules/ec2_snapshot_copy.py
+++ b/ansible_collections/community/aws/plugins/modules/ec2_snapshot_copy.py
@@ -1,13 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
# Copyright: (c) 2017, Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: ec2_snapshot_copy
version_added: 1.0.0
@@ -57,12 +54,12 @@ options:
author:
- Deepak Kothandan (@Deepakkothandan) <deepak.kdy@gmail.com>
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
- name: Basic Snapshot Copy
community.aws.ec2_snapshot_copy:
source_region: eu-central-1
@@ -84,7 +81,7 @@ EXAMPLES = '''
region: eu-west-1
source_snapshot_id: snap-xxxxxxx
tags:
- Name: Snapshot-Name
+ Name: Snapshot-Name
- name: Encrypted Snapshot copy
community.aws.ec2_snapshot_copy:
@@ -100,24 +97,25 @@ EXAMPLES = '''
source_snapshot_id: snap-xxxxxxx
encrypted: true
kms_key_id: arn:aws:kms:eu-central-1:XXXXXXXXXXXX:key/746de6ea-50a4-4bcb-8fbc-e3b29f2d367b
-'''
+"""
-RETURN = '''
+RETURN = r"""
snapshot_id:
description: snapshot id of the newly created snapshot
returned: when snapshot copy is successful
type: str
sample: "snap-e9095e8c"
-'''
+"""
try:
import botocore
except ImportError:
pass # Handled by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_specifications
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
+
def copy_snapshot(module, ec2):
"""
@@ -128,34 +126,33 @@ def copy_snapshot(module, ec2):
"""
params = {
- 'SourceRegion': module.params.get('source_region'),
- 'SourceSnapshotId': module.params.get('source_snapshot_id'),
- 'Description': module.params.get('description')
+ "SourceRegion": module.params.get("source_region"),
+ "SourceSnapshotId": module.params.get("source_snapshot_id"),
+ "Description": module.params.get("description"),
}
- if module.params.get('encrypted'):
- params['Encrypted'] = True
+ if module.params.get("encrypted"):
+ params["Encrypted"] = True
- if module.params.get('kms_key_id'):
- params['KmsKeyId'] = module.params.get('kms_key_id')
+ if module.params.get("kms_key_id"):
+ params["KmsKeyId"] = module.params.get("kms_key_id")
- if module.params.get('tags'):
- params['TagSpecifications'] = boto3_tag_specifications(module.params.get('tags'), types=['snapshot'])
+ if module.params.get("tags"):
+ params["TagSpecifications"] = boto3_tag_specifications(module.params.get("tags"), types=["snapshot"])
try:
- snapshot_id = ec2.copy_snapshot(**params)['SnapshotId']
- if module.params.get('wait'):
+ snapshot_id = ec2.copy_snapshot(**params)["SnapshotId"]
+ if module.params.get("wait"):
delay = 15
# Add one to max_attempts as wait() increment
# its counter before assessing it for time.sleep()
- max_attempts = (module.params.get('wait_timeout') // delay) + 1
- ec2.get_waiter('snapshot_completed').wait(
- SnapshotIds=[snapshot_id],
- WaiterConfig=dict(Delay=delay, MaxAttempts=max_attempts)
+ max_attempts = (module.params.get("wait_timeout") // delay) + 1
+ ec2.get_waiter("snapshot_completed").wait(
+ SnapshotIds=[snapshot_id], WaiterConfig=dict(Delay=delay, MaxAttempts=max_attempts)
)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='An error occurred waiting for the snapshot to become available.')
+ module.fail_json_aws(e, msg="An error occurred waiting for the snapshot to become available.")
module.exit_json(changed=True, snapshot_id=snapshot_id)
@@ -164,23 +161,23 @@ def main():
argument_spec = dict(
source_region=dict(required=True),
source_snapshot_id=dict(required=True),
- description=dict(default=''),
- encrypted=dict(type='bool', default=False, required=False),
- kms_key_id=dict(type='str', required=False),
- wait=dict(type='bool', default=False),
- wait_timeout=dict(type='int', default=600),
- tags=dict(type='dict', aliases=['resource_tags']),
+ description=dict(default=""),
+ encrypted=dict(type="bool", default=False, required=False),
+ kms_key_id=dict(type="str", required=False),
+ wait=dict(type="bool", default=False),
+ wait_timeout=dict(type="int", default=600),
+ tags=dict(type="dict", aliases=["resource_tags"]),
)
module = AnsibleAWSModule(argument_spec=argument_spec)
try:
- client = module.client('ec2')
+ client = module.client("ec2")
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to connect to AWS')
+ module.fail_json_aws(e, msg="Failed to connect to AWS")
copy_snapshot(module, client)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/ec2_transit_gateway.py b/ansible_collections/community/aws/plugins/modules/ec2_transit_gateway.py
index 298646cf8..19876984d 100644
--- a/ansible_collections/community/aws/plugins/modules/ec2_transit_gateway.py
+++ b/ansible_collections/community/aws/plugins/modules/ec2_transit_gateway.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
module: ec2_transit_gateway
short_description: Create and delete AWS Transit Gateways
version_added: 1.0.0
@@ -74,13 +72,13 @@ options:
author:
- "Bob Boldin (@BobBoldin)"
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
- amazon.aws.tags
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
- name: Create a new transit gateway using defaults
community.aws.ec2_transit_gateway:
state: present
@@ -93,9 +91,9 @@ EXAMPLES = '''
asn: 64514
auto_associate: false
auto_propagate: false
- dns_support: True
+ dns_support: true
description: "nonprod transit gateway"
- purge_tags: False
+ purge_tags: false
state: present
region: us-east-1
tags:
@@ -114,9 +112,9 @@ EXAMPLES = '''
region: ap-southeast-2
transit_gateway_id: tgw-3a9aa123
register: deleted_tgw
-'''
+"""
-RETURN = '''
+RETURN = r"""
transit_gateway:
description: The attributes of the transit gateway.
type: complex
@@ -210,49 +208,53 @@ transit_gateway:
returned: always
type: str
sample: tgw-3a9aa123
-'''
+"""
+
+from time import sleep
+from time import time
try:
- from botocore.exceptions import BotoCoreError, ClientError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
except ImportError:
pass # handled by imported AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from time import sleep, time
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_filter_list
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ensure_ec2_tags
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.transformation import ansible_dict_to_boto3_filter_list
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
-class AnsibleEc2Tgw(object):
+class AnsibleEc2Tgw(object):
def __init__(self, module, results):
self._module = module
self._results = results
retry_decorator = AWSRetry.jittered_backoff(
- catch_extra_error_codes=['IncorrectState'],
+ catch_extra_error_codes=["IncorrectState"],
)
- connection = module.client('ec2', retry_decorator=retry_decorator)
+ connection = module.client("ec2", retry_decorator=retry_decorator)
self._connection = connection
self._check_mode = self._module.check_mode
def process(self):
- """ Process the request based on state parameter .
- state = present will search for an existing tgw based and return the object data.
- if no object is found it will be created
-
- state = absent will attempt to remove the tgw however will fail if it still has
- attachments or associations
- """
- description = self._module.params.get('description')
- state = self._module.params.get('state', 'present')
- tgw_id = self._module.params.get('transit_gateway_id')
-
- if state == 'present':
+ """Process the request based on state parameter .
+ state = present will search for an existing tgw based and return the object data.
+ if no object is found it will be created
+
+ state = absent will attempt to remove the tgw however will fail if it still has
+ attachments or associations
+ """
+ description = self._module.params.get("description")
+ state = self._module.params.get("state", "present")
+ tgw_id = self._module.params.get("transit_gateway_id")
+
+ if state == "present":
self.ensure_tgw_present(tgw_id, description)
- elif state == 'absent':
+ elif state == "absent":
self.ensure_tgw_absent(tgw_id, description)
def wait_for_status(self, wait_timeout, tgw_id, status, skip_deleted=True):
@@ -276,13 +278,13 @@ class AnsibleEc2Tgw(object):
if transit_gateway:
if self._check_mode:
- transit_gateway['state'] = status
+ transit_gateway["state"] = status
- if transit_gateway.get('state') == status:
+ if transit_gateway.get("state") == status:
status_achieved = True
break
- elif transit_gateway.get('state') == 'failed':
+ elif transit_gateway.get("state") == "failed":
break
else:
@@ -292,13 +294,12 @@ class AnsibleEc2Tgw(object):
self._module.fail_json_aws(e)
if not status_achieved:
- self._module.fail_json(
- msg="Wait time out reached, while waiting for results")
+ self._module.fail_json(msg="Wait time out reached, while waiting for results")
return transit_gateway
def get_matching_tgw(self, tgw_id, description=None, skip_deleted=True):
- """ search for an existing tgw by either tgw_id or description
+ """search for an existing tgw by either tgw_id or description
:param tgw_id: The AWS id of the transit gateway
:param description: The description of the transit gateway.
:param skip_deleted: ignore deleted transit gateways
@@ -306,7 +307,7 @@ class AnsibleEc2Tgw(object):
"""
filters = []
if tgw_id:
- filters = ansible_dict_to_boto3_filter_list({'transit-gateway-id': tgw_id})
+ filters = ansible_dict_to_boto3_filter_list({"transit-gateway-id": tgw_id})
try:
response = AWSRetry.exponential_backoff()(self._connection.describe_transit_gateways)(Filters=filters)
@@ -316,20 +317,21 @@ class AnsibleEc2Tgw(object):
tgw = None
tgws = []
- if len(response.get('TransitGateways', [])) == 1 and tgw_id:
- if (response['TransitGateways'][0]['State'] != 'deleted') or not skip_deleted:
- tgws.extend(response['TransitGateways'])
+ if len(response.get("TransitGateways", [])) == 1 and tgw_id:
+ if (response["TransitGateways"][0]["State"] != "deleted") or not skip_deleted:
+ tgws.extend(response["TransitGateways"])
- for gateway in response.get('TransitGateways', []):
- if description == gateway['Description'] and gateway['State'] != 'deleted':
+ for gateway in response.get("TransitGateways", []):
+ if description == gateway["Description"] and gateway["State"] != "deleted":
tgws.append(gateway)
if len(tgws) > 1:
self._module.fail_json(
- msg='EC2 returned more than one transit Gateway for description {0}, aborting'.format(description))
+ msg=f"EC2 returned more than one transit Gateway for description {description}, aborting"
+ )
elif tgws:
- tgw = camel_dict_to_snake_dict(tgws[0], ignore_list=['Tags'])
- tgw['tags'] = boto3_tag_list_to_ansible_dict(tgws[0]['Tags'])
+ tgw = camel_dict_to_snake_dict(tgws[0], ignore_list=["Tags"])
+ tgw["tags"] = boto3_tag_list_to_ansible_dict(tgws[0]["Tags"])
return tgw
@@ -349,31 +351,31 @@ class AnsibleEc2Tgw(object):
:return dict: transit gateway object
"""
options = dict()
- wait = self._module.params.get('wait')
- wait_timeout = self._module.params.get('wait_timeout')
+ wait = self._module.params.get("wait")
+ wait_timeout = self._module.params.get("wait_timeout")
- if self._module.params.get('asn'):
- options['AmazonSideAsn'] = self._module.params.get('asn')
+ if self._module.params.get("asn"):
+ options["AmazonSideAsn"] = self._module.params.get("asn")
- options['AutoAcceptSharedAttachments'] = self.enable_option_flag(self._module.params.get('auto_attach'))
- options['DefaultRouteTableAssociation'] = self.enable_option_flag(self._module.params.get('auto_associate'))
- options['DefaultRouteTablePropagation'] = self.enable_option_flag(self._module.params.get('auto_propagate'))
- options['VpnEcmpSupport'] = self.enable_option_flag(self._module.params.get('vpn_ecmp_support'))
- options['DnsSupport'] = self.enable_option_flag(self._module.params.get('dns_support'))
+ options["AutoAcceptSharedAttachments"] = self.enable_option_flag(self._module.params.get("auto_attach"))
+ options["DefaultRouteTableAssociation"] = self.enable_option_flag(self._module.params.get("auto_associate"))
+ options["DefaultRouteTablePropagation"] = self.enable_option_flag(self._module.params.get("auto_propagate"))
+ options["VpnEcmpSupport"] = self.enable_option_flag(self._module.params.get("vpn_ecmp_support"))
+ options["DnsSupport"] = self.enable_option_flag(self._module.params.get("dns_support"))
try:
response = self._connection.create_transit_gateway(Description=description, Options=options)
except (ClientError, BotoCoreError) as e:
self._module.fail_json_aws(e)
- tgw_id = response['TransitGateway']['TransitGatewayId']
+ tgw_id = response["TransitGateway"]["TransitGatewayId"]
if wait:
result = self.wait_for_status(wait_timeout=wait_timeout, tgw_id=tgw_id, status="available")
else:
result = self.get_matching_tgw(tgw_id=tgw_id)
- self._results['msg'] = (' Transit gateway {0} created'.format(result['transit_gateway_id']))
+ self._results["msg"] = f" Transit gateway {result['transit_gateway_id']} created"
return result
@@ -384,8 +386,8 @@ class AnsibleEc2Tgw(object):
:param tgw_id: The id of the transit gateway
:return dict: transit gateway object
"""
- wait = self._module.params.get('wait')
- wait_timeout = self._module.params.get('wait_timeout')
+ wait = self._module.params.get("wait")
+ wait_timeout = self._module.params.get("wait_timeout")
try:
response = self._connection.delete_transit_gateway(TransitGatewayId=tgw_id)
@@ -393,11 +395,13 @@ class AnsibleEc2Tgw(object):
self._module.fail_json_aws(e)
if wait:
- result = self.wait_for_status(wait_timeout=wait_timeout, tgw_id=tgw_id, status="deleted", skip_deleted=False)
+ result = self.wait_for_status(
+ wait_timeout=wait_timeout, tgw_id=tgw_id, status="deleted", skip_deleted=False
+ )
else:
result = self.get_matching_tgw(tgw_id=tgw_id, skip_deleted=False)
- self._results['msg'] = (' Transit gateway {0} deleted'.format(tgw_id))
+ self._results["msg"] = f" Transit gateway {tgw_id} deleted"
return result
@@ -414,25 +418,27 @@ class AnsibleEc2Tgw(object):
if tgw is None:
if self._check_mode:
- self._results['changed'] = True
- self._results['transit_gateway_id'] = None
+ self._results["changed"] = True
+ self._results["transit_gateway_id"] = None
return self._results
try:
if not description:
self._module.fail_json(msg="Failed to create Transit Gateway: description argument required")
tgw = self.create_tgw(description)
- self._results['changed'] = True
+ self._results["changed"] = True
except (BotoCoreError, ClientError) as e:
- self._module.fail_json_aws(e, msg='Unable to create Transit Gateway')
-
- self._results['changed'] |= ensure_ec2_tags(
- self._connection, self._module, tgw['transit_gateway_id'],
- tags=self._module.params.get('tags'),
- purge_tags=self._module.params.get('purge_tags'),
+ self._module.fail_json_aws(e, msg="Unable to create Transit Gateway")
+
+ self._results["changed"] |= ensure_ec2_tags(
+ self._connection,
+ self._module,
+ tgw["transit_gateway_id"],
+ tags=self._module.params.get("tags"),
+ purge_tags=self._module.params.get("purge_tags"),
)
- self._results['transit_gateway'] = self.get_matching_tgw(tgw_id=tgw['transit_gateway_id'])
+ self._results["transit_gateway"] = self.get_matching_tgw(tgw_id=tgw["transit_gateway_id"])
return self._results
@@ -444,21 +450,22 @@ class AnsibleEc2Tgw(object):
:param description: The description of the transit gateway.
:return doct: transit gateway object
"""
- self._results['transit_gateway_id'] = None
+ self._results["transit_gateway_id"] = None
tgw = self.get_matching_tgw(tgw_id, description)
if tgw is not None:
if self._check_mode:
- self._results['changed'] = True
+ self._results["changed"] = True
return self._results
try:
- tgw = self.delete_tgw(tgw_id=tgw['transit_gateway_id'])
- self._results['changed'] = True
- self._results['transit_gateway'] = self.get_matching_tgw(tgw_id=tgw['transit_gateway_id'],
- skip_deleted=False)
+ tgw = self.delete_tgw(tgw_id=tgw["transit_gateway_id"])
+ self._results["changed"] = True
+ self._results["transit_gateway"] = self.get_matching_tgw(
+ tgw_id=tgw["transit_gateway_id"], skip_deleted=False
+ )
except (BotoCoreError, ClientError) as e:
- self._module.fail_json_aws(e, msg='Unable to delete Transit Gateway')
+ self._module.fail_json_aws(e, msg="Unable to delete Transit Gateway")
return self._results
@@ -470,24 +477,24 @@ def setup_module_object():
"""
argument_spec = dict(
- asn=dict(type='int'),
- auto_associate=dict(type='bool', default=True),
- auto_attach=dict(type='bool', default=False),
- auto_propagate=dict(type='bool', default=True),
- description=dict(type='str'),
- dns_support=dict(type='bool', default=True),
- purge_tags=dict(type='bool', default=True),
- state=dict(default='present', choices=['present', 'absent']),
- tags=dict(type='dict', aliases=['resource_tags']),
- transit_gateway_id=dict(type='str'),
- vpn_ecmp_support=dict(type='bool', default=True),
- wait=dict(type='bool', default=True),
- wait_timeout=dict(type='int', default=300)
+ asn=dict(type="int"),
+ auto_associate=dict(type="bool", default=True),
+ auto_attach=dict(type="bool", default=False),
+ auto_propagate=dict(type="bool", default=True),
+ description=dict(type="str"),
+ dns_support=dict(type="bool", default=True),
+ purge_tags=dict(type="bool", default=True),
+ state=dict(default="present", choices=["present", "absent"]),
+ tags=dict(type="dict", aliases=["resource_tags"]),
+ transit_gateway_id=dict(type="str"),
+ vpn_ecmp_support=dict(type="bool", default=True),
+ wait=dict(type="bool", default=True),
+ wait_timeout=dict(type="int", default=300),
)
module = AnsibleAWSModule(
argument_spec=argument_spec,
- required_one_of=[('description', 'transit_gateway_id')],
+ required_one_of=[("description", "transit_gateway_id")],
supports_check_mode=True,
)
@@ -495,12 +502,9 @@ def setup_module_object():
def main():
-
module = setup_module_object()
- results = dict(
- changed=False
- )
+ results = dict(changed=False)
tgw_manager = AnsibleEc2Tgw(module=module, results=results)
tgw_manager.process()
@@ -508,5 +512,5 @@ def main():
module.exit_json(**results)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/ec2_transit_gateway_info.py b/ansible_collections/community/aws/plugins/modules/ec2_transit_gateway_info.py
index 5ce3dc6a4..b25346b84 100644
--- a/ansible_collections/community/aws/plugins/modules/ec2_transit_gateway_info.py
+++ b/ansible_collections/community/aws/plugins/modules/ec2_transit_gateway_info.py
@@ -1,19 +1,17 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
module: ec2_transit_gateway_info
short_description: Gather information about ec2 transit gateways in AWS
version_added: 1.0.0
description:
- - Gather information about ec2 transit gateways in AWS
-author: "Bob Boldin (@BobBoldin)"
+ - Gather information about ec2 transit gateways in AWS
+author:
+ - "Bob Boldin (@BobBoldin)"
options:
transit_gateway_ids:
description:
@@ -29,13 +27,12 @@ options:
type: dict
default: {}
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
-
-'''
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide for details.
- name: Gather info about all transit gateways
@@ -57,9 +54,9 @@ EXAMPLES = r'''
transit_gateway_ids:
- tgw-02c42332e6b7da829
- tgw-03c53443d5a8cb716
-'''
+"""
-RETURN = r'''
+RETURN = r"""
transit_gateways:
description: >
Transit gateways that match the provided filters. Each element consists of a dict with all the information
@@ -162,7 +159,7 @@ transit_gateways:
returned: always
type: str
sample: "tgw-02c42332e6b7da829"
-'''
+"""
try:
import botocore
@@ -171,19 +168,19 @@ except ImportError:
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_filter_list
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.transformation import ansible_dict_to_boto3_filter_list
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
-class AnsibleEc2TgwInfo(object):
+class AnsibleEc2TgwInfo(object):
def __init__(self, module, results):
self._module = module
self._results = results
- self._connection = self._module.client('ec2')
+ self._connection = self._module.client("ec2")
self._check_mode = self._module.check_mode
@AWSRetry.exponential_backoff()
@@ -195,8 +192,8 @@ class AnsibleEc2TgwInfo(object):
connection : boto3 client connection object
"""
# collect parameters
- filters = ansible_dict_to_boto3_filter_list(self._module.params['filters'])
- transit_gateway_ids = self._module.params['transit_gateway_ids']
+ filters = ansible_dict_to_boto3_filter_list(self._module.params["filters"])
+ transit_gateway_ids = self._module.params["transit_gateway_ids"]
# init empty list for return vars
transit_gateway_info = list()
@@ -204,17 +201,18 @@ class AnsibleEc2TgwInfo(object):
# Get the basic transit gateway info
try:
response = self._connection.describe_transit_gateways(
- TransitGatewayIds=transit_gateway_ids, Filters=filters)
- except is_boto3_error_code('InvalidTransitGatewayID.NotFound'):
- self._results['transit_gateways'] = []
+ TransitGatewayIds=transit_gateway_ids, Filters=filters
+ )
+ except is_boto3_error_code("InvalidTransitGatewayID.NotFound"):
+ self._results["transit_gateways"] = []
return
- for transit_gateway in response['TransitGateways']:
- transit_gateway_info.append(camel_dict_to_snake_dict(transit_gateway, ignore_list=['Tags']))
+ for transit_gateway in response["TransitGateways"]:
+ transit_gateway_info.append(camel_dict_to_snake_dict(transit_gateway, ignore_list=["Tags"]))
# convert tag list to ansible dict
- transit_gateway_info[-1]['tags'] = boto3_tag_list_to_ansible_dict(transit_gateway.get('Tags', []))
+ transit_gateway_info[-1]["tags"] = boto3_tag_list_to_ansible_dict(transit_gateway.get("Tags", []))
- self._results['transit_gateways'] = transit_gateway_info
+ self._results["transit_gateways"] = transit_gateway_info
return
@@ -225,8 +223,8 @@ def setup_module_object():
"""
argument_spec = dict(
- transit_gateway_ids=dict(type='list', default=[], elements='str', aliases=['transit_gateway_id']),
- filters=dict(type='dict', default={})
+ transit_gateway_ids=dict(type="list", default=[], elements="str", aliases=["transit_gateway_id"]),
+ filters=dict(type="dict", default={}),
)
module = AnsibleAWSModule(
@@ -238,12 +236,9 @@ def setup_module_object():
def main():
-
module = setup_module_object()
- results = dict(
- changed=False
- )
+ results = dict(changed=False)
tgwf_manager = AnsibleEc2TgwInfo(module=module, results=results)
try:
@@ -254,5 +249,5 @@ def main():
module.exit_json(**results)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/ec2_transit_gateway_vpc_attachment.py b/ansible_collections/community/aws/plugins/modules/ec2_transit_gateway_vpc_attachment.py
index 554059021..cfb6809a8 100644
--- a/ansible_collections/community/aws/plugins/modules/ec2_transit_gateway_vpc_attachment.py
+++ b/ansible_collections/community/aws/plugins/modules/ec2_transit_gateway_vpc_attachment.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
module: ec2_transit_gateway_vpc_attachment
short_description: Create and delete AWS Transit Gateway VPC attachments
version_added: 4.0.0
@@ -98,26 +96,26 @@ options:
author:
- "Mark Chappell (@tremble)"
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
- - amazon.aws.boto3
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.tags
-'''
+ - amazon.aws.boto3
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
# Create a Transit Gateway attachment
- community.aws.ec2_transit_gateway_vpc_attachment:
state: present
transit_gateway: 'tgw-123456789abcdef01'
name: AnsibleTest-1
subnets:
- - subnet-00000000000000000
- - subnet-11111111111111111
- - subnet-22222222222222222
- ipv6_support: True
- purge_subnets: True
- dns_support: True
- appliance_mode_support: True
+ - subnet-00000000000000000
+ - subnet-11111111111111111
+ - subnet-22222222222222222
+ ipv6_support: true
+ purge_subnets: true
+ dns_support: true
+ appliance_mode_support: true
tags:
TestTag: changed data in Test Tag
@@ -126,18 +124,18 @@ EXAMPLES = '''
state: present
id: 'tgw-attach-0c0c5fd0b0f01d1c9'
name: AnsibleTest-1
- ipv6_support: True
- purge_subnets: False
- dns_support: False
- appliance_mode_support: True
+ ipv6_support: true
+ purge_subnets: false
+ dns_support: false
+ appliance_mode_support: true
# Delete the transit gateway
- community.aws.ec2_transit_gateway_vpc_attachment:
state: absent
id: 'tgw-attach-0c0c5fd0b0f01d1c9'
-'''
+"""
-RETURN = '''
+RETURN = r"""
transit_gateway_attachments:
description: The attributes of the Transit Gateway attachments.
type: list
@@ -216,34 +214,31 @@ transit_gateway_attachments:
type: str
returned: success
example: '123456789012'
-'''
-
-
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
+"""
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
from ansible_collections.community.aws.plugins.module_utils.transitgateway import TransitGatewayVpcAttachmentManager
def main():
-
argument_spec = dict(
- state=dict(type='str', required=False, default='present', choices=['absent', 'present']),
- transit_gateway=dict(type='str', required=False, aliases=['transit_gateway_id']),
- id=dict(type='str', required=False, aliases=['attachment_id']),
- name=dict(type='str', required=False),
- subnets=dict(type='list', elements='str', required=False),
- purge_subnets=dict(type='bool', required=False, default=True),
- tags=dict(type='dict', required=False, aliases=['resource_tags']),
- purge_tags=dict(type='bool', required=False, default=True),
- appliance_mode_support=dict(type='bool', required=False),
- dns_support=dict(type='bool', required=False),
- ipv6_support=dict(type='bool', required=False),
- wait=dict(type='bool', required=False, default=True),
- wait_timeout=dict(type='int', required=False),
+ state=dict(type="str", required=False, default="present", choices=["absent", "present"]),
+ transit_gateway=dict(type="str", required=False, aliases=["transit_gateway_id"]),
+ id=dict(type="str", required=False, aliases=["attachment_id"]),
+ name=dict(type="str", required=False),
+ subnets=dict(type="list", elements="str", required=False),
+ purge_subnets=dict(type="bool", required=False, default=True),
+ tags=dict(type="dict", required=False, aliases=["resource_tags"]),
+ purge_tags=dict(type="bool", required=False, default=True),
+ appliance_mode_support=dict(type="bool", required=False),
+ dns_support=dict(type="bool", required=False),
+ ipv6_support=dict(type="bool", required=False),
+ wait=dict(type="bool", required=False, default=True),
+ wait_timeout=dict(type="int", required=False),
)
one_of = [
- ['id', 'transit_gateway', 'name'],
+ ["id", "transit_gateway", "name"],
]
module = AnsibleAWSModule(
@@ -252,55 +247,68 @@ def main():
required_one_of=one_of,
)
- attach_id = module.params.get('id', None)
- tgw = module.params.get('transit_gateway', None)
- name = module.params.get('name', None)
- tags = module.params.get('tags', None)
- purge_tags = module.params.get('purge_tags')
- state = module.params.get('state')
- subnets = module.params.get('subnets', None)
- purge_subnets = module.params.get('purge_subnets')
+ attach_id = module.params.get("id", None)
+ tgw = module.params.get("transit_gateway", None)
+ name = module.params.get("name", None)
+ tags = module.params.get("tags", None)
+ purge_tags = module.params.get("purge_tags")
+ state = module.params.get("state")
+ subnets = module.params.get("subnets", None)
+ purge_subnets = module.params.get("purge_subnets")
# When not provided with an ID see if one exists.
if not attach_id:
search_manager = TransitGatewayVpcAttachmentManager(module=module)
filters = dict()
if tgw:
- filters['transit-gateway-id'] = tgw
+ filters["transit-gateway-id"] = tgw
if name:
- filters['tag:Name'] = name
+ filters["tag:Name"] = name
if subnets:
vpc_id = search_manager.subnets_to_vpc(subnets)
- filters['vpc-id'] = vpc_id
+ filters["vpc-id"] = vpc_id
# Attachments lurk in a 'deleted' state, for a while, ignore them so we
# can reuse the names
- filters['state'] = [
- 'available', 'deleting', 'failed', 'failing', 'initiatingRequest', 'modifying',
- 'pendingAcceptance', 'pending', 'rollingBack', 'rejected', 'rejecting'
+ filters["state"] = [
+ "available",
+ "deleting",
+ "failed",
+ "failing",
+ "initiatingRequest",
+ "modifying",
+ "pendingAcceptance",
+ "pending",
+ "rollingBack",
+ "rejected",
+ "rejecting",
]
attachments = search_manager.list(filters=filters)
if len(attachments) > 1:
- module.fail_json('Multiple matching attachments found, provide an ID', attachments=attachments)
+ module.fail_json("Multiple matching attachments found, provide an ID", attachments=attachments)
# If we find a match then we'll modify it by ID, otherwise we'll be
# creating a new RTB.
if attachments:
- attach_id = attachments[0]['transit_gateway_attachment_id']
+ attach_id = attachments[0]["transit_gateway_attachment_id"]
manager = TransitGatewayVpcAttachmentManager(module=module, id=attach_id)
- manager.set_wait(module.params.get('wait', None))
- manager.set_wait_timeout(module.params.get('wait_timeout', None))
+ manager.set_wait(module.params.get("wait", None))
+ manager.set_wait_timeout(module.params.get("wait_timeout", None))
- if state == 'absent':
+ if state == "absent":
manager.delete()
else:
if not attach_id:
if not tgw:
- module.fail_json('No existing attachment found. To create a new attachment'
- ' the `transit_gateway` parameter must be provided.')
+ module.fail_json(
+ "No existing attachment found. To create a new attachment"
+ " the `transit_gateway` parameter must be provided."
+ )
if not subnets:
- module.fail_json('No existing attachment found. To create a new attachment'
- ' the `subnets` parameter must be provided.')
+ module.fail_json(
+ "No existing attachment found. To create a new attachment"
+ " the `subnets` parameter must be provided."
+ )
# name is just a special case of tags.
if name:
@@ -314,9 +322,9 @@ def main():
manager.set_transit_gateway(tgw)
manager.set_subnets(subnets, purge_subnets)
manager.set_tags(tags, purge_tags)
- manager.set_dns_support(module.params.get('dns_support', None))
- manager.set_ipv6_support(module.params.get('ipv6_support', None))
- manager.set_appliance_mode_support(module.params.get('appliance_mode_support', None))
+ manager.set_dns_support(module.params.get("dns_support", None))
+ manager.set_ipv6_support(module.params.get("ipv6_support", None))
+ manager.set_appliance_mode_support(module.params.get("appliance_mode_support", None))
manager.flush_changes()
results = dict(
@@ -324,7 +332,7 @@ def main():
attachments=[manager.updated_resource],
)
if manager.changed:
- results['diff'] = dict(
+ results["diff"] = dict(
before=manager.original_resource,
after=manager.updated_resource,
)
@@ -332,5 +340,5 @@ def main():
module.exit_json(**results)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/ec2_transit_gateway_vpc_attachment_info.py b/ansible_collections/community/aws/plugins/modules/ec2_transit_gateway_vpc_attachment_info.py
index b76b0b0f7..a665e4080 100644
--- a/ansible_collections/community/aws/plugins/modules/ec2_transit_gateway_vpc_attachment_info.py
+++ b/ansible_collections/community/aws/plugins/modules/ec2_transit_gateway_vpc_attachment_info.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
module: ec2_transit_gateway_vpc_attachment_info
short_description: describes AWS Transit Gateway VPC attachments
version_added: 4.0.0
@@ -39,14 +37,15 @@ options:
type: bool
required: false
default: false
-author: "Mark Chappell (@tremble)"
+author:
+ - "Mark Chappell (@tremble)"
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
# Describe a specific Transit Gateway attachment.
- community.aws.ec2_transit_gateway_vpc_attachment_info:
id: 'tgw-attach-0123456789abcdef0'
@@ -60,9 +59,9 @@ EXAMPLES = '''
- community.aws.ec2_transit_gateway_vpc_attachment_info:
filters:
transit-gateway-id: tgw-0fedcba9876543210'
-'''
+"""
-RETURN = '''
+RETURN = r"""
transit_gateway_attachments:
description: The attributes of the Transit Gateway attachments.
type: list
@@ -141,26 +140,23 @@ transit_gateway_attachments:
type: str
returned: success
example: '123456789012'
-'''
-
-
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
+"""
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
from ansible_collections.community.aws.plugins.module_utils.transitgateway import TransitGatewayVpcAttachmentManager
def main():
-
argument_spec = dict(
- id=dict(type='str', required=False, aliases=['attachment_id']),
- name=dict(type='str', required=False),
- filters=dict(type='dict', required=False),
- include_deleted=dict(type='bool', required=False, default=False)
+ id=dict(type="str", required=False, aliases=["attachment_id"]),
+ name=dict(type="str", required=False),
+ filters=dict(type="dict", required=False),
+ include_deleted=dict(type="bool", required=False, default=False),
)
mutually_exclusive = [
- ['id', 'name'],
- ['id', 'filters'],
+ ["id", "name"],
+ ["id", "filters"],
]
module = AnsibleAWSModule(
@@ -168,22 +164,31 @@ def main():
supports_check_mode=True,
)
- name = module.params.get('name', None)
- id = module.params.get('id', None)
- opt_filters = module.params.get('filters', None)
+ name = module.params.get("name", None)
+ id = module.params.get("id", None)
+ opt_filters = module.params.get("filters", None)
search_manager = TransitGatewayVpcAttachmentManager(module=module)
filters = dict()
if name:
- filters['tag:Name'] = name
+ filters["tag:Name"] = name
- if not module.params.get('include_deleted'):
+ if not module.params.get("include_deleted"):
# Attachments lurk in a 'deleted' state, for a while, ignore them so we
# can reuse the names
- filters['state'] = [
- 'available', 'deleting', 'failed', 'failing', 'initiatingRequest', 'modifying',
- 'pendingAcceptance', 'pending', 'rollingBack', 'rejected', 'rejecting'
+ filters["state"] = [
+ "available",
+ "deleting",
+ "failed",
+ "failing",
+ "initiatingRequest",
+ "modifying",
+ "pendingAcceptance",
+ "pending",
+ "rollingBack",
+ "rejected",
+ "rejecting",
]
if opt_filters:
@@ -194,5 +199,5 @@ def main():
module.exit_json(changed=False, attachments=attachments, filters=filters)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/ec2_vpc_egress_igw.py b/ansible_collections/community/aws/plugins/modules/ec2_vpc_egress_igw.py
index dbcf15b12..1bd65f501 100644
--- a/ansible_collections/community/aws/plugins/modules/ec2_vpc_egress_igw.py
+++ b/ansible_collections/community/aws/plugins/modules/ec2_vpc_egress_igw.py
@@ -1,19 +1,18 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: ec2_vpc_egress_igw
version_added: 1.0.0
short_description: Manage an AWS VPC Egress Only Internet gateway
description:
- - Manage an AWS VPC Egress Only Internet gateway
-author: Daniel Shepherd (@shepdelacreme)
+ - Manage an AWS VPC Egress Only Internet gateway
+author:
+ - Daniel Shepherd (@shepdelacreme)
options:
vpc_id:
description:
@@ -27,13 +26,12 @@ options:
choices: [ 'present', 'absent' ]
type: str
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-'''
-
-EXAMPLES = '''
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide for details.
# Ensure that the VPC has an Internet Gateway.
@@ -42,10 +40,9 @@ EXAMPLES = '''
vpc_id: vpc-abcdefgh
state: present
register: eigw
+"""
-'''
-
-RETURN = '''
+RETURN = r"""
gateway_id:
description: The ID of the Egress Only Internet Gateway or Null.
returned: always
@@ -56,7 +53,7 @@ vpc_id:
returned: always
type: str
sample: vpc-012345678
-'''
+"""
try:
import botocore
@@ -65,9 +62,10 @@ except ImportError:
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def delete_eigw(module, connection, eigw_id):
@@ -82,16 +80,18 @@ def delete_eigw(module, connection, eigw_id):
try:
response = connection.delete_egress_only_internet_gateway(
- aws_retry=True,
- DryRun=module.check_mode,
- EgressOnlyInternetGatewayId=eigw_id)
- except is_boto3_error_code('DryRunOperation'):
+ aws_retry=True, DryRun=module.check_mode, EgressOnlyInternetGatewayId=eigw_id
+ )
+ except is_boto3_error_code("DryRunOperation"):
changed = True
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, msg="Could not delete Egress-Only Internet Gateway {0} from VPC {1}".format(eigw_id, module.vpc_id))
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(e, msg=f"Could not delete Egress-Only Internet Gateway {eigw_id} from VPC {module.vpc_id}")
if not module.check_mode:
- changed = response.get('ReturnCode', False)
+ changed = response.get("ReturnCode", False)
return changed
@@ -109,29 +109,33 @@ def create_eigw(module, connection, vpc_id):
try:
response = connection.create_egress_only_internet_gateway(
- aws_retry=True,
- DryRun=module.check_mode,
- VpcId=vpc_id)
- except is_boto3_error_code('DryRunOperation'):
+ aws_retry=True, DryRun=module.check_mode, VpcId=vpc_id
+ )
+ except is_boto3_error_code("DryRunOperation"):
# When boto3 method is run with DryRun=True it returns an error on success
# We need to catch the error and return something valid
changed = True
- except is_boto3_error_code('InvalidVpcID.NotFound') as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, msg="invalid vpc ID '{0}' provided".format(vpc_id))
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, msg="Could not create Egress-Only Internet Gateway for vpc ID {0}".format(vpc_id))
+ except is_boto3_error_code("InvalidVpcID.NotFound") as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(e, msg=f"invalid vpc ID '{vpc_id}' provided")
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(e, msg=f"Could not create Egress-Only Internet Gateway for vpc ID {vpc_id}")
if not module.check_mode:
- gateway = response.get('EgressOnlyInternetGateway', {})
- state = gateway.get('Attachments', [{}])[0].get('State')
- gateway_id = gateway.get('EgressOnlyInternetGatewayId')
+ gateway = response.get("EgressOnlyInternetGateway", {})
+ state = gateway.get("Attachments", [{}])[0].get("State")
+ gateway_id = gateway.get("EgressOnlyInternetGatewayId")
- if gateway_id and state in ('attached', 'attaching'):
+ if gateway_id and state in ("attached", "attaching"):
changed = True
else:
# EIGW gave back a bad attachment state or an invalid response so we error out
- module.fail_json(msg='Unable to create and attach Egress Only Internet Gateway to VPCId: {0}. Bad or no state in response'.format(vpc_id),
- **camel_dict_to_snake_dict(response))
+ module.fail_json(
+ msg=f"Unable to create and attach Egress Only Internet Gateway to VPCId: {vpc_id}. Bad or no state in response",
+ **camel_dict_to_snake_dict(response),
+ )
return changed, gateway_id
@@ -147,45 +151,41 @@ def describe_eigws(module, connection, vpc_id):
gateway_id = None
try:
- response = connection.describe_egress_only_internet_gateways(
- aws_retry=True)
+ response = connection.describe_egress_only_internet_gateways(aws_retry=True)
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
module.fail_json_aws(e, msg="Could not get list of existing Egress-Only Internet Gateways")
- for eigw in response.get('EgressOnlyInternetGateways', []):
- for attachment in eigw.get('Attachments', []):
- if attachment.get('VpcId') == vpc_id and attachment.get('State') in ('attached', 'attaching'):
- gateway_id = eigw.get('EgressOnlyInternetGatewayId')
+ for eigw in response.get("EgressOnlyInternetGateways", []):
+ for attachment in eigw.get("Attachments", []):
+ if attachment.get("VpcId") == vpc_id and attachment.get("State") in ("attached", "attaching"):
+ gateway_id = eigw.get("EgressOnlyInternetGatewayId")
return gateway_id
def main():
- argument_spec = dict(
- vpc_id=dict(required=True),
- state=dict(default='present', choices=['present', 'absent'])
- )
+ argument_spec = dict(vpc_id=dict(required=True), state=dict(default="present", choices=["present", "absent"]))
module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
retry_decorator = AWSRetry.jittered_backoff(retries=10)
- connection = module.client('ec2', retry_decorator=retry_decorator)
+ connection = module.client("ec2", retry_decorator=retry_decorator)
- vpc_id = module.params.get('vpc_id')
- state = module.params.get('state')
+ vpc_id = module.params.get("vpc_id")
+ state = module.params.get("state")
eigw_id = describe_eigws(module, connection, vpc_id)
result = dict(gateway_id=eigw_id, vpc_id=vpc_id)
changed = False
- if state == 'present' and not eigw_id:
- changed, result['gateway_id'] = create_eigw(module, connection, vpc_id)
- elif state == 'absent' and eigw_id:
+ if state == "present" and not eigw_id:
+ changed, result["gateway_id"] = create_eigw(module, connection, vpc_id)
+ elif state == "absent" and eigw_id:
changed = delete_eigw(module, connection, eigw_id)
module.exit_json(changed=changed, **result)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/ec2_vpc_nacl.py b/ansible_collections/community/aws/plugins/modules/ec2_vpc_nacl.py
index e11df3de5..cf109de1c 100644
--- a/ansible_collections/community/aws/plugins/modules/ec2_vpc_nacl.py
+++ b/ansible_collections/community/aws/plugins/modules/ec2_vpc_nacl.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
module: ec2_vpc_nacl
short_description: create and delete Network ACLs
version_added: 1.0.0
@@ -73,18 +71,18 @@ options:
type: str
choices: ['present', 'absent']
default: present
-author: Mike Mochan (@mmochan)
+author:
+ - Mike Mochan (@mmochan)
+notes:
+ - Support for I(purge_tags) was added in release 4.0.0.
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
- amazon.aws.tags
-notes:
- - Support for I(purge_tags) was added in release 4.0.0.
-'''
-
-EXAMPLES = r'''
+"""
+EXAMPLES = r"""
# Complete example to create and delete a network ACL
# that allows SSH, HTTP and ICMP in, and all traffic out.
- name: "Create and associate production DMZ network ACL with DMZ subnets"
@@ -98,16 +96,16 @@ EXAMPLES = r'''
Project: phoenix
Description: production DMZ
ingress:
- # rule no, protocol, allow/deny, cidr, icmp_type, icmp_code,
- # port from, port to
- - [100, 'tcp', 'allow', '0.0.0.0/0', null, null, 22, 22]
- - [200, 'tcp', 'allow', '0.0.0.0/0', null, null, 80, 80]
- - [205, 'tcp', 'allow', '::/0', null, null, 80, 80]
- - [300, 'icmp', 'allow', '0.0.0.0/0', 0, 8]
- - [305, 'ipv6-icmp', 'allow', '::/0', 0, 8]
+ # rule no, protocol, allow/deny, cidr, icmp_type, icmp_code,
+ # port from, port to
+ - [100, 'tcp', 'allow', '0.0.0.0/0', null, null, 22, 22]
+ - [200, 'tcp', 'allow', '0.0.0.0/0', null, null, 80, 80]
+ - [205, 'tcp', 'allow', '::/0', null, null, 80, 80]
+ - [300, 'icmp', 'allow', '0.0.0.0/0', 0, 8]
+ - [305, 'ipv6-icmp', 'allow', '::/0', 0, 8]
egress:
- - [100, 'all', 'allow', '0.0.0.0/0', null, null, null, null]
- - [105, 'all', 'allow', '::/0', null, null, null, null]
+ - [100, 'all', 'allow', '0.0.0.0/0', null, null, null, null]
+ - [105, 'all', 'allow', '::/0', null, null, null, null]
state: 'present'
- name: "Remove the ingress and egress rules - defaults to deny all"
@@ -141,8 +139,9 @@ EXAMPLES = r'''
community.aws.ec2_vpc_nacl:
nacl_id: acl-33b4ee5b
state: absent
-'''
-RETURN = r'''
+"""
+
+RETURN = r"""
task:
description: The result of the create, or delete action.
returned: success
@@ -152,47 +151,48 @@ nacl_id:
returned: success
type: str
sample: acl-123456789abcdef01
-'''
+"""
try:
import botocore
except ImportError:
pass # Handled by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ensure_ec2_tags
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_specifications
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
+
# VPC-supported IANA protocol numbers
# http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
-PROTOCOL_NUMBERS = {'all': -1, 'icmp': 1, 'tcp': 6, 'udp': 17, 'ipv6-icmp': 58}
+PROTOCOL_NUMBERS = {"all": -1, "icmp": 1, "tcp": 6, "udp": 17, "ipv6-icmp": 58}
# Utility methods
def icmp_present(entry):
- if len(entry) == 6 and entry[1] in ['icmp', 'ipv6-icmp'] or entry[1] in [1, 58]:
+ if len(entry) == 6 and entry[1] in ["icmp", "ipv6-icmp"] or entry[1] in [1, 58]:
return True
def subnets_removed(nacl_id, subnets, client, module):
results = find_acl_by_id(nacl_id, client, module)
- associations = results['NetworkAcls'][0]['Associations']
- subnet_ids = [assoc['SubnetId'] for assoc in associations]
+ associations = results["NetworkAcls"][0]["Associations"]
+ subnet_ids = [assoc["SubnetId"] for assoc in associations]
return [subnet for subnet in subnet_ids if subnet not in subnets]
def subnets_added(nacl_id, subnets, client, module):
results = find_acl_by_id(nacl_id, client, module)
- associations = results['NetworkAcls'][0]['Associations']
- subnet_ids = [assoc['SubnetId'] for assoc in associations]
+ associations = results["NetworkAcls"][0]["Associations"]
+ subnet_ids = [assoc["SubnetId"] for assoc in associations]
return [subnet for subnet in subnets if subnet not in subnet_ids]
def subnets_changed(nacl, client, module):
changed = False
- vpc_id = module.params.get('vpc_id')
- nacl_id = nacl['NetworkAcls'][0]['NetworkAclId']
+ vpc_id = module.params.get("vpc_id")
+ nacl_id = nacl["NetworkAcls"][0]["NetworkAclId"]
subnets = subnets_to_associate(nacl, client, module)
if not subnets:
default_nacl_id = find_default_vpc_nacl(vpc_id, client, module)[0]
@@ -218,40 +218,41 @@ def subnets_changed(nacl, client, module):
def nacls_changed(nacl, client, module):
changed = False
params = dict()
- params['egress'] = module.params.get('egress')
- params['ingress'] = module.params.get('ingress')
+ params["egress"] = module.params.get("egress")
+ params["ingress"] = module.params.get("ingress")
- nacl_id = nacl['NetworkAcls'][0]['NetworkAclId']
+ nacl_id = nacl["NetworkAcls"][0]["NetworkAclId"]
nacl = describe_network_acl(client, module)
- entries = nacl['NetworkAcls'][0]['Entries']
- egress = [rule for rule in entries if rule['Egress'] is True and rule['RuleNumber'] < 32767]
- ingress = [rule for rule in entries if rule['Egress'] is False and rule['RuleNumber'] < 32767]
- if rules_changed(egress, params['egress'], True, nacl_id, client, module):
+ entries = nacl["NetworkAcls"][0]["Entries"]
+ egress = [rule for rule in entries if rule["Egress"] is True and rule["RuleNumber"] < 32767]
+ ingress = [rule for rule in entries if rule["Egress"] is False and rule["RuleNumber"] < 32767]
+ if rules_changed(egress, params["egress"], True, nacl_id, client, module):
changed = True
- if rules_changed(ingress, params['ingress'], False, nacl_id, client, module):
+ if rules_changed(ingress, params["ingress"], False, nacl_id, client, module):
changed = True
return changed
def tags_changed(nacl_id, client, module):
- tags = module.params.get('tags')
- name = module.params.get('name')
- purge_tags = module.params.get('purge_tags')
+ tags = module.params.get("tags")
+ name = module.params.get("name")
+ purge_tags = module.params.get("purge_tags")
if name is None and tags is None:
return False
- if module.params.get('tags') is None:
+ if module.params.get("tags") is None:
# Only purge tags if tags is explicitly set to {} and purge_tags is True
purge_tags = False
new_tags = dict()
- if module.params.get('name') is not None:
- new_tags['Name'] = module.params.get('name')
- new_tags.update(module.params.get('tags') or {})
+ if module.params.get("name") is not None:
+ new_tags["Name"] = module.params.get("name")
+ new_tags.update(module.params.get("tags") or {})
- return ensure_ec2_tags(client, module, nacl_id, tags=new_tags,
- purge_tags=purge_tags, retry_codes=['InvalidNetworkAclID.NotFound'])
+ return ensure_ec2_tags(
+ client, module, nacl_id, tags=new_tags, purge_tags=purge_tags, retry_codes=["InvalidNetworkAclID.NotFound"]
+ )
def rules_changed(aws_rules, param_rules, Egress, nacl_id, client, module):
@@ -266,60 +267,60 @@ def rules_changed(aws_rules, param_rules, Egress, nacl_id, client, module):
if removed_rules:
params = dict()
for rule in removed_rules:
- params['NetworkAclId'] = nacl_id
- params['RuleNumber'] = rule['RuleNumber']
- params['Egress'] = Egress
+ params["NetworkAclId"] = nacl_id
+ params["RuleNumber"] = rule["RuleNumber"]
+ params["Egress"] = Egress
delete_network_acl_entry(params, client, module)
changed = True
added_rules = [x for x in rules if x not in aws_rules]
if added_rules:
for rule in added_rules:
- rule['NetworkAclId'] = nacl_id
+ rule["NetworkAclId"] = nacl_id
create_network_acl_entry(rule, client, module)
changed = True
return changed
def is_ipv6(cidr):
- return ':' in cidr
+ return ":" in cidr
def process_rule_entry(entry, Egress):
params = dict()
- params['RuleNumber'] = entry[0]
- params['Protocol'] = str(PROTOCOL_NUMBERS[entry[1]])
- params['RuleAction'] = entry[2]
- params['Egress'] = Egress
+ params["RuleNumber"] = entry[0]
+ params["Protocol"] = str(PROTOCOL_NUMBERS[entry[1]])
+ params["RuleAction"] = entry[2]
+ params["Egress"] = Egress
if is_ipv6(entry[3]):
- params['Ipv6CidrBlock'] = entry[3]
+ params["Ipv6CidrBlock"] = entry[3]
else:
- params['CidrBlock'] = entry[3]
+ params["CidrBlock"] = entry[3]
if icmp_present(entry):
- params['IcmpTypeCode'] = {"Type": int(entry[4]), "Code": int(entry[5])}
+ params["IcmpTypeCode"] = {"Type": int(entry[4]), "Code": int(entry[5])}
else:
if entry[6] or entry[7]:
- params['PortRange'] = {"From": entry[6], 'To': entry[7]}
+ params["PortRange"] = {"From": entry[6], "To": entry[7]}
return params
def restore_default_associations(assoc_ids, default_nacl_id, client, module):
if assoc_ids:
params = dict()
- params['NetworkAclId'] = default_nacl_id[0]
+ params["NetworkAclId"] = default_nacl_id[0]
for assoc_id in assoc_ids:
- params['AssociationId'] = assoc_id
+ params["AssociationId"] = assoc_id
restore_default_acl_association(params, client, module)
return True
def construct_acl_entries(nacl, client, module):
- for entry in module.params.get('ingress'):
+ for entry in module.params.get("ingress"):
params = process_rule_entry(entry, Egress=False)
- params['NetworkAclId'] = nacl['NetworkAcl']['NetworkAclId']
+ params["NetworkAclId"] = nacl["NetworkAcl"]["NetworkAclId"]
create_network_acl_entry(params, client, module)
- for rule in module.params.get('egress'):
+ for rule in module.params.get("egress"):
params = process_rule_entry(rule, Egress=True)
- params['NetworkAclId'] = nacl['NetworkAcl']['NetworkAclId']
+ params["NetworkAclId"] = nacl["NetworkAcl"]["NetworkAclId"]
create_network_acl_entry(params, client, module)
@@ -327,21 +328,21 @@ def construct_acl_entries(nacl, client, module):
def setup_network_acl(client, module):
changed = False
nacl = describe_network_acl(client, module)
- if not nacl['NetworkAcls']:
+ if not nacl["NetworkAcls"]:
tags = {}
- if module.params.get('name'):
- tags['Name'] = module.params.get('name')
- tags.update(module.params.get('tags') or {})
- nacl = create_network_acl(module.params.get('vpc_id'), client, module, tags)
- nacl_id = nacl['NetworkAcl']['NetworkAclId']
+ if module.params.get("name"):
+ tags["Name"] = module.params.get("name")
+ tags.update(module.params.get("tags") or {})
+ nacl = create_network_acl(module.params.get("vpc_id"), client, module, tags)
+ nacl_id = nacl["NetworkAcl"]["NetworkAclId"]
subnets = subnets_to_associate(nacl, client, module)
replace_network_acl_association(nacl_id, subnets, client, module)
construct_acl_entries(nacl, client, module)
changed = True
- return changed, nacl['NetworkAcl']['NetworkAclId']
+ return changed, nacl["NetworkAcl"]["NetworkAclId"]
else:
changed = False
- nacl_id = nacl['NetworkAcls'][0]['NetworkAclId']
+ nacl_id = nacl["NetworkAcls"][0]["NetworkAclId"]
changed |= subnets_changed(nacl, client, module)
changed |= nacls_changed(nacl, client, module)
changed |= tags_changed(nacl_id, client, module)
@@ -352,11 +353,11 @@ def remove_network_acl(client, module):
changed = False
result = dict()
nacl = describe_network_acl(client, module)
- if nacl['NetworkAcls']:
- nacl_id = nacl['NetworkAcls'][0]['NetworkAclId']
- vpc_id = nacl['NetworkAcls'][0]['VpcId']
- associations = nacl['NetworkAcls'][0]['Associations']
- assoc_ids = [a['NetworkAclAssociationId'] for a in associations]
+ if nacl["NetworkAcls"]:
+ nacl_id = nacl["NetworkAcls"][0]["NetworkAclId"]
+ vpc_id = nacl["NetworkAcls"][0]["VpcId"]
+ associations = nacl["NetworkAcls"][0]["Associations"]
+ assoc_ids = [a["NetworkAclAssociationId"] for a in associations]
default_nacl_id = find_default_vpc_nacl(vpc_id, client, module)
if not default_nacl_id:
result = {vpc_id: "Default NACL ID not found - Check the VPC ID"}
@@ -383,7 +384,7 @@ def _create_network_acl(client, *args, **kwargs):
def create_network_acl(vpc_id, client, module, tags):
params = dict(VpcId=vpc_id)
if tags:
- params['TagSpecifications'] = boto3_tag_specifications(tags, ['network-acl'])
+ params["TagSpecifications"] = boto3_tag_specifications(tags, ["network-acl"])
try:
if module.check_mode:
nacl = dict(NetworkAcl=dict(NetworkAclId="nacl-00000000"))
@@ -394,7 +395,7 @@ def create_network_acl(vpc_id, client, module, tags):
return nacl
-@AWSRetry.jittered_backoff(catch_extra_error_codes=['InvalidNetworkAclID.NotFound'])
+@AWSRetry.jittered_backoff(catch_extra_error_codes=["InvalidNetworkAclID.NotFound"])
def _create_network_acl_entry(client, *args, **kwargs):
return client.create_network_acl_entry(*args, **kwargs)
@@ -420,7 +421,7 @@ def delete_network_acl(nacl_id, client, module):
module.fail_json_aws(e)
-@AWSRetry.jittered_backoff(catch_extra_error_codes=['InvalidNetworkAclID.NotFound'])
+@AWSRetry.jittered_backoff(catch_extra_error_codes=["InvalidNetworkAclID.NotFound"])
def _delete_network_acl_entry(client, *args, **kwargs):
return client.delete_network_acl_entry(*args, **kwargs)
@@ -438,7 +439,7 @@ def _describe_network_acls(client, **kwargs):
return client.describe_network_acls(**kwargs)
-@AWSRetry.jittered_backoff(catch_extra_error_codes=['InvalidNetworkAclID.NotFound'])
+@AWSRetry.jittered_backoff(catch_extra_error_codes=["InvalidNetworkAclID.NotFound"])
def _describe_network_acls_retry_missing(client, **kwargs):
return client.describe_network_acls(**kwargs)
@@ -447,25 +448,23 @@ def describe_acl_associations(subnets, client, module):
if not subnets:
return []
try:
- results = _describe_network_acls_retry_missing(client, Filters=[
- {'Name': 'association.subnet-id', 'Values': subnets}
- ])
+ results = _describe_network_acls_retry_missing(
+ client, Filters=[{"Name": "association.subnet-id", "Values": subnets}]
+ )
except botocore.exceptions.ClientError as e:
module.fail_json_aws(e)
- associations = results['NetworkAcls'][0]['Associations']
- return [a['NetworkAclAssociationId'] for a in associations if a['SubnetId'] in subnets]
+ associations = results["NetworkAcls"][0]["Associations"]
+ return [a["NetworkAclAssociationId"] for a in associations if a["SubnetId"] in subnets]
def describe_network_acl(client, module):
try:
- if module.params.get('nacl_id'):
- nacl = _describe_network_acls(client, Filters=[
- {'Name': 'network-acl-id', 'Values': [module.params.get('nacl_id')]}
- ])
+ if module.params.get("nacl_id"):
+ nacl = _describe_network_acls(
+ client, Filters=[{"Name": "network-acl-id", "Values": [module.params.get("nacl_id")]}]
+ )
else:
- nacl = _describe_network_acls(client, Filters=[
- {'Name': 'tag:Name', 'Values': [module.params.get('name')]}
- ])
+ nacl = _describe_network_acls(client, Filters=[{"Name": "tag:Name", "Values": [module.params.get("name")]}])
except botocore.exceptions.ClientError as e:
module.fail_json_aws(e)
return nacl
@@ -480,38 +479,37 @@ def find_acl_by_id(nacl_id, client, module):
def find_default_vpc_nacl(vpc_id, client, module):
try:
- response = _describe_network_acls_retry_missing(client, Filters=[
- {'Name': 'vpc-id', 'Values': [vpc_id]}])
+ response = _describe_network_acls_retry_missing(client, Filters=[{"Name": "vpc-id", "Values": [vpc_id]}])
except botocore.exceptions.ClientError as e:
module.fail_json_aws(e)
- nacls = response['NetworkAcls']
- return [n['NetworkAclId'] for n in nacls if n['IsDefault'] is True]
+ nacls = response["NetworkAcls"]
+ return [n["NetworkAclId"] for n in nacls if n["IsDefault"] is True]
def find_subnet_ids_by_nacl_id(nacl_id, client, module):
try:
- results = _describe_network_acls_retry_missing(client, Filters=[
- {'Name': 'association.network-acl-id', 'Values': [nacl_id]}
- ])
+ results = _describe_network_acls_retry_missing(
+ client, Filters=[{"Name": "association.network-acl-id", "Values": [nacl_id]}]
+ )
except botocore.exceptions.ClientError as e:
module.fail_json_aws(e)
- if results['NetworkAcls']:
- associations = results['NetworkAcls'][0]['Associations']
- return [s['SubnetId'] for s in associations if s['SubnetId']]
+ if results["NetworkAcls"]:
+ associations = results["NetworkAcls"][0]["Associations"]
+ return [s["SubnetId"] for s in associations if s["SubnetId"]]
else:
return []
-@AWSRetry.jittered_backoff(catch_extra_error_codes=['InvalidNetworkAclID.NotFound'])
+@AWSRetry.jittered_backoff(catch_extra_error_codes=["InvalidNetworkAclID.NotFound"])
def _replace_network_acl_association(client, *args, **kwargs):
return client.replace_network_acl_association(*args, **kwargs)
def replace_network_acl_association(nacl_id, subnets, client, module):
params = dict()
- params['NetworkAclId'] = nacl_id
+ params["NetworkAclId"] = nacl_id
for association in describe_acl_associations(subnets, client, module):
- params['AssociationId'] = association
+ params["AssociationId"] = association
try:
if not module.check_mode:
_replace_network_acl_association(client, **params)
@@ -519,7 +517,7 @@ def replace_network_acl_association(nacl_id, subnets, client, module):
module.fail_json_aws(e)
-@AWSRetry.jittered_backoff(catch_extra_error_codes=['InvalidNetworkAclID.NotFound'])
+@AWSRetry.jittered_backoff(catch_extra_error_codes=["InvalidNetworkAclID.NotFound"])
def _replace_network_acl_entry(client, *args, **kwargs):
return client.replace_network_acl_entry(*args, **kwargs)
@@ -527,7 +525,7 @@ def _replace_network_acl_entry(client, *args, **kwargs):
def replace_network_acl_entry(entries, Egress, nacl_id, client, module):
for entry in entries:
params = entry
- params['NetworkAclId'] = nacl_id
+ params["NetworkAclId"] = nacl_id
try:
if not module.check_mode:
_replace_network_acl_entry(client, **params)
@@ -535,7 +533,7 @@ def replace_network_acl_entry(entries, Egress, nacl_id, client, module):
module.fail_json_aws(e)
-@AWSRetry.jittered_backoff(catch_extra_error_codes=['InvalidNetworkAclID.NotFound'])
+@AWSRetry.jittered_backoff(catch_extra_error_codes=["InvalidNetworkAclID.NotFound"])
def _replace_network_acl_association(client, *args, **kwargs):
return client.replace_network_acl_association(*args, **kwargs)
@@ -554,25 +552,23 @@ def _describe_subnets(client, *args, **kwargs):
def subnets_to_associate(nacl, client, module):
- params = list(module.params.get('subnets'))
+ params = list(module.params.get("subnets"))
if not params:
return []
all_found = []
if any(x.startswith("subnet-") for x in params):
try:
- subnets = _describe_subnets(client, Filters=[
- {'Name': 'subnet-id', 'Values': params}])
- all_found.extend(subnets.get('Subnets', []))
+ subnets = _describe_subnets(client, Filters=[{"Name": "subnet-id", "Values": params}])
+ all_found.extend(subnets.get("Subnets", []))
except botocore.exceptions.ClientError as e:
module.fail_json_aws(e)
if len(params) != len(all_found):
try:
- subnets = _describe_subnets(client, Filters=[
- {'Name': 'tag:Name', 'Values': params}])
- all_found.extend(subnets.get('Subnets', []))
+ subnets = _describe_subnets(client, Filters=[{"Name": "tag:Name", "Values": params}])
+ all_found.extend(subnets.get("Subnets", []))
except botocore.exceptions.ClientError as e:
module.fail_json_aws(e)
- return list(set(s['SubnetId'] for s in all_found if s.get('SubnetId')))
+ return list(set(s["SubnetId"] for s in all_found if s.get("SubnetId")))
def main():
@@ -580,29 +576,31 @@ def main():
vpc_id=dict(),
name=dict(),
nacl_id=dict(),
- subnets=dict(required=False, type='list', default=list(), elements='str'),
- tags=dict(required=False, type='dict', aliases=['resource_tags']),
- purge_tags=dict(required=False, type='bool', default=True),
- ingress=dict(required=False, type='list', default=list(), elements='list'),
- egress=dict(required=False, type='list', default=list(), elements='list'),
- state=dict(default='present', choices=['present', 'absent']),
+ subnets=dict(required=False, type="list", default=list(), elements="str"),
+ tags=dict(required=False, type="dict", aliases=["resource_tags"]),
+ purge_tags=dict(required=False, type="bool", default=True),
+ ingress=dict(required=False, type="list", default=list(), elements="list"),
+ egress=dict(required=False, type="list", default=list(), elements="list"),
+ state=dict(default="present", choices=["present", "absent"]),
+ )
+ module = AnsibleAWSModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_one_of=[["name", "nacl_id"]],
+ required_if=[["state", "present", ["vpc_id"]]],
)
- module = AnsibleAWSModule(argument_spec=argument_spec,
- supports_check_mode=True,
- required_one_of=[['name', 'nacl_id']],
- required_if=[['state', 'present', ['vpc_id']]])
- state = module.params.get('state').lower()
+ state = module.params.get("state").lower()
- client = module.client('ec2')
+ client = module.client("ec2")
invocations = {
"present": setup_network_acl,
- "absent": remove_network_acl
+ "absent": remove_network_acl,
}
(changed, results) = invocations[state](client, module)
module.exit_json(changed=changed, nacl_id=results)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/ec2_vpc_nacl_info.py b/ansible_collections/community/aws/plugins/modules/ec2_vpc_nacl_info.py
index b85c94236..d95508a89 100644
--- a/ansible_collections/community/aws/plugins/modules/ec2_vpc_nacl_info.py
+++ b/ansible_collections/community/aws/plugins/modules/ec2_vpc_nacl_info.py
@@ -1,18 +1,18 @@
#!/usr/bin/python
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
+# -*- coding: utf-8 -*-
+# Copyright: Contributors to the Ansible project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: ec2_vpc_nacl_info
version_added: 1.0.0
short_description: Gather information about Network ACLs in an AWS VPC
description:
- - Gather information about Network ACLs in an AWS VPC
-author: "Brad Davidson (@brandond)"
+ - Gather information about Network ACLs in an AWS VPC
+author:
+ - "Brad Davidson (@brandond)"
options:
nacl_ids:
description:
@@ -34,12 +34,12 @@ notes:
- By default, the module will return all Network ACLs.
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
-'''
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide for details.
# Gather information about all Network ACLs:
@@ -55,9 +55,9 @@ EXAMPLES = r'''
filters:
'default': 'true'
register: default_nacls
-'''
+"""
-RETURN = r'''
+RETURN = r"""
nacls:
description: Returns an array of complex objects as described below.
returned: success
@@ -100,7 +100,7 @@ nacls:
type: list
elements: list
sample: [[100, 'all', 'allow', '0.0.0.0/0', null, null, null, null]]
-'''
+"""
try:
import botocore
@@ -109,20 +109,19 @@ except ImportError:
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_filter_list
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.transformation import ansible_dict_to_boto3_filter_list
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
# VPC-supported IANA protocol numbers
# http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
-PROTOCOL_NAMES = {'-1': 'all', '1': 'icmp', '6': 'tcp', '17': 'udp'}
+PROTOCOL_NAMES = {"-1": "all", "1": "icmp", "6": "tcp", "17": "udp"}
def list_ec2_vpc_nacls(connection, module):
-
nacl_ids = module.params.get("nacl_ids")
filters = ansible_dict_to_boto3_filter_list(module.params.get("filters"))
@@ -131,86 +130,97 @@ def list_ec2_vpc_nacls(connection, module):
try:
nacls = connection.describe_network_acls(aws_retry=True, NetworkAclIds=nacl_ids, Filters=filters)
- except is_boto3_error_code('InvalidNetworkAclID.NotFound'):
- module.fail_json(msg='Unable to describe ACL. NetworkAcl does not exist')
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, msg="Unable to describe network ACLs {0}".format(nacl_ids))
+ except is_boto3_error_code("InvalidNetworkAclID.NotFound"):
+ module.fail_json(msg="Unable to describe ACL. NetworkAcl does not exist")
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(e, msg=f"Unable to describe network ACLs {nacl_ids}")
# Turn the boto3 result in to ansible_friendly_snaked_names
snaked_nacls = []
- for nacl in nacls['NetworkAcls']:
+ for nacl in nacls["NetworkAcls"]:
snaked_nacls.append(camel_dict_to_snake_dict(nacl))
# Turn the boto3 result in to ansible friendly tag dictionary
for nacl in snaked_nacls:
- if 'tags' in nacl:
- nacl['tags'] = boto3_tag_list_to_ansible_dict(nacl['tags'], 'key', 'value')
- if 'entries' in nacl:
- nacl['egress'] = [nacl_entry_to_list(entry) for entry in nacl['entries']
- if entry['rule_number'] < 32767 and entry['egress']]
- nacl['ingress'] = [nacl_entry_to_list(entry) for entry in nacl['entries']
- if entry['rule_number'] < 32767 and not entry['egress']]
- del nacl['entries']
- if 'associations' in nacl:
- nacl['subnets'] = [a['subnet_id'] for a in nacl['associations']]
- del nacl['associations']
- if 'network_acl_id' in nacl:
- nacl['nacl_id'] = nacl['network_acl_id']
- del nacl['network_acl_id']
+ if "tags" in nacl:
+ nacl["tags"] = boto3_tag_list_to_ansible_dict(nacl["tags"], "key", "value")
+ if "entries" in nacl:
+ nacl["egress"] = [
+ nacl_entry_to_list(entry)
+ for entry in nacl["entries"]
+ if entry["rule_number"] < 32767 and entry["egress"]
+ ]
+ nacl["ingress"] = [
+ nacl_entry_to_list(entry)
+ for entry in nacl["entries"]
+ if entry["rule_number"] < 32767 and not entry["egress"]
+ ]
+ del nacl["entries"]
+ if "associations" in nacl:
+ nacl["subnets"] = [a["subnet_id"] for a in nacl["associations"]]
+ del nacl["associations"]
+ if "network_acl_id" in nacl:
+ nacl["nacl_id"] = nacl["network_acl_id"]
+ del nacl["network_acl_id"]
module.exit_json(nacls=snaked_nacls)
def nacl_entry_to_list(entry):
-
# entry list format
# [ rule_num, protocol name or number, allow or deny, ipv4/6 cidr, icmp type, icmp code, port from, port to]
elist = []
- elist.append(entry['rule_number'])
+ elist.append(entry["rule_number"])
- if entry.get('protocol') in PROTOCOL_NAMES:
- elist.append(PROTOCOL_NAMES[entry['protocol']])
+ if entry.get("protocol") in PROTOCOL_NAMES:
+ elist.append(PROTOCOL_NAMES[entry["protocol"]])
else:
- elist.append(entry.get('protocol'))
+ elist.append(entry.get("protocol"))
- elist.append(entry['rule_action'])
+ elist.append(entry["rule_action"])
- if entry.get('cidr_block'):
- elist.append(entry['cidr_block'])
- elif entry.get('ipv6_cidr_block'):
- elist.append(entry['ipv6_cidr_block'])
+ if entry.get("cidr_block"):
+ elist.append(entry["cidr_block"])
+ elif entry.get("ipv6_cidr_block"):
+ elist.append(entry["ipv6_cidr_block"])
else:
elist.append(None)
elist = elist + [None, None, None, None]
- if entry['protocol'] in ('1', '58'):
- elist[4] = entry.get('icmp_type_code', {}).get('type')
- elist[5] = entry.get('icmp_type_code', {}).get('code')
+ if entry["protocol"] in ("1", "58"):
+ elist[4] = entry.get("icmp_type_code", {}).get("type")
+ elist[5] = entry.get("icmp_type_code", {}).get("code")
- if entry['protocol'] not in ('1', '6', '17', '58'):
+ if entry["protocol"] not in ("1", "6", "17", "58"):
elist[6] = 0
elist[7] = 65535
- elif 'port_range' in entry:
- elist[6] = entry['port_range']['from']
- elist[7] = entry['port_range']['to']
+ elif "port_range" in entry:
+ elist[6] = entry["port_range"]["from"]
+ elist[7] = entry["port_range"]["to"]
return elist
def main():
-
argument_spec = dict(
- nacl_ids=dict(default=[], type='list', aliases=['nacl_id'], elements='str'),
- filters=dict(default={}, type='dict'))
+ nacl_ids=dict(default=[], type="list", aliases=["nacl_id"], elements="str"),
+ filters=dict(default={}, type="dict"),
+ )
- module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
+ module = AnsibleAWSModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
- connection = module.client('ec2', retry_decorator=AWSRetry.jittered_backoff())
+ connection = module.client("ec2", retry_decorator=AWSRetry.jittered_backoff())
list_ec2_vpc_nacls(connection, module)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/ec2_vpc_peer.py b/ansible_collections/community/aws/plugins/modules/ec2_vpc_peer.py
index f23ffae19..2a731bf23 100644
--- a/ansible_collections/community/aws/plugins/modules/ec2_vpc_peer.py
+++ b/ansible_collections/community/aws/plugins/modules/ec2_vpc_peer.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
module: ec2_vpc_peer
short_description: create, delete, accept, and reject VPC peering connections between two VPCs.
version_added: 1.0.0
@@ -57,13 +55,13 @@ notes:
author:
- Mike Mochan (@mmochan)
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
- - amazon.aws.boto3
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.tags
-'''
+ - amazon.aws.boto3
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
# Complete example to create and accept a local peering connection.
- name: Create local account VPC peering Connection
community.aws.ec2_vpc_peer:
@@ -211,9 +209,9 @@ EXAMPLES = '''
peering_id: "{{ vpc_peer.peering_id }}"
profile: bot03_profile_for_cross_account
state: reject
+"""
-'''
-RETURN = '''
+RETURN = r"""
peering_id:
description: The id of the VPC peering connection created/deleted.
returned: always
@@ -352,33 +350,33 @@ vpc_peering_connection:
returned: success
type: str
example: "pcx-0123456789abcdef0"
-'''
+"""
try:
import botocore
except ImportError:
pass # Handled by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_filter_list
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import add_ec2_tags
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ensure_ec2_tags
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.transformation import ansible_dict_to_boto3_filter_list
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def wait_for_state(client, module, state, pcx_id):
- waiter = client.get_waiter('vpc_peering_connection_exists')
+ waiter = client.get_waiter("vpc_peering_connection_exists")
peer_filter = {
- 'vpc-peering-connection-id': pcx_id,
- 'status-code': state,
+ "vpc-peering-connection-id": pcx_id,
+ "status-code": state,
}
try:
- waiter.wait(
- Filters=ansible_dict_to_boto3_filter_list(peer_filter)
- )
+ waiter.wait(Filters=ansible_dict_to_boto3_filter_list(peer_filter))
except botocore.exceptions.WaiterError as e:
module.fail_json_aws(e, "Failed to wait for state change")
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
@@ -387,18 +385,18 @@ def wait_for_state(client, module, state, pcx_id):
def describe_peering_connections(params, client):
peer_filter = {
- 'requester-vpc-info.vpc-id': params['VpcId'],
- 'accepter-vpc-info.vpc-id': params['PeerVpcId'],
+ "requester-vpc-info.vpc-id": params["VpcId"],
+ "accepter-vpc-info.vpc-id": params["PeerVpcId"],
}
result = client.describe_vpc_peering_connections(
aws_retry=True,
Filters=ansible_dict_to_boto3_filter_list(peer_filter),
)
- if result['VpcPeeringConnections'] == []:
+ if result["VpcPeeringConnections"] == []:
# Try again with the VPC/Peer relationship reversed
peer_filter = {
- 'requester-vpc-info.vpc-id': params['PeerVpcId'],
- 'accepter-vpc-info.vpc-id': params['VpcId'],
+ "requester-vpc-info.vpc-id": params["PeerVpcId"],
+ "accepter-vpc-info.vpc-id": params["VpcId"],
}
result = client.describe_vpc_peering_connections(
aws_retry=True,
@@ -409,29 +407,32 @@ def describe_peering_connections(params, client):
def is_active(peering_conn):
- return peering_conn['Status']['Code'] == 'active'
+ return peering_conn["Status"]["Code"] == "active"
def is_pending(peering_conn):
- return peering_conn['Status']['Code'] == 'pending-acceptance'
+ return peering_conn["Status"]["Code"] == "pending-acceptance"
def create_peer_connection(client, module):
changed = False
params = dict()
- params['VpcId'] = module.params.get('vpc_id')
- params['PeerVpcId'] = module.params.get('peer_vpc_id')
- if module.params.get('peer_region'):
- params['PeerRegion'] = module.params.get('peer_region')
- if module.params.get('peer_owner_id'):
- params['PeerOwnerId'] = str(module.params.get('peer_owner_id'))
+ params["VpcId"] = module.params.get("vpc_id")
+ params["PeerVpcId"] = module.params.get("peer_vpc_id")
+ if module.params.get("peer_region"):
+ params["PeerRegion"] = module.params.get("peer_region")
+ if module.params.get("peer_owner_id"):
+ params["PeerOwnerId"] = str(module.params.get("peer_owner_id"))
peering_conns = describe_peering_connections(params, client)
- for peering_conn in peering_conns['VpcPeeringConnections']:
- pcx_id = peering_conn['VpcPeeringConnectionId']
- if ensure_ec2_tags(client, module, pcx_id,
- purge_tags=module.params.get('purge_tags'),
- tags=module.params.get('tags'),
- ):
+ for peering_conn in peering_conns["VpcPeeringConnections"]:
+ pcx_id = peering_conn["VpcPeeringConnectionId"]
+ if ensure_ec2_tags(
+ client,
+ module,
+ pcx_id,
+ purge_tags=module.params.get("purge_tags"),
+ tags=module.params.get("tags"),
+ ):
changed = True
if is_active(peering_conn):
return (changed, peering_conn)
@@ -439,54 +440,59 @@ def create_peer_connection(client, module):
return (changed, peering_conn)
try:
peering_conn = client.create_vpc_peering_connection(aws_retry=True, **params)
- pcx_id = peering_conn['VpcPeeringConnection']['VpcPeeringConnectionId']
- if module.params.get('tags'):
+ pcx_id = peering_conn["VpcPeeringConnection"]["VpcPeeringConnectionId"]
+ if module.params.get("tags"):
# Once the minimum botocore version is bumped to > 1.17.24
# (hopefully community.aws 3.0.0) we can add the tags to the
# creation parameters
- add_ec2_tags(client, module, pcx_id, module.params.get('tags'),
- retry_codes=['InvalidVpcPeeringConnectionID.NotFound'])
- if module.params.get('wait'):
- wait_for_state(client, module, 'pending-acceptance', pcx_id)
+ add_ec2_tags(
+ client,
+ module,
+ pcx_id,
+ module.params.get("tags"),
+ retry_codes=["InvalidVpcPeeringConnectionID.NotFound"],
+ )
+ if module.params.get("wait"):
+ wait_for_state(client, module, "pending-acceptance", pcx_id)
changed = True
- return (changed, peering_conn['VpcPeeringConnection'])
+ return (changed, peering_conn["VpcPeeringConnection"])
except botocore.exceptions.ClientError as e:
module.fail_json(msg=str(e))
def remove_peer_connection(client, module):
- pcx_id = module.params.get('peering_id')
+ pcx_id = module.params.get("peering_id")
if pcx_id:
peering_conn = get_peering_connection_by_id(pcx_id, client, module)
else:
params = dict()
- params['VpcId'] = module.params.get('vpc_id')
- params['PeerVpcId'] = module.params.get('peer_vpc_id')
- params['PeerRegion'] = module.params.get('peer_region')
- if module.params.get('peer_owner_id'):
- params['PeerOwnerId'] = str(module.params.get('peer_owner_id'))
- peering_conn = describe_peering_connections(params, client)['VpcPeeringConnections'][0]
+ params["VpcId"] = module.params.get("vpc_id")
+ params["PeerVpcId"] = module.params.get("peer_vpc_id")
+ params["PeerRegion"] = module.params.get("peer_region")
+ if module.params.get("peer_owner_id"):
+ params["PeerOwnerId"] = str(module.params.get("peer_owner_id"))
+ peering_conn = describe_peering_connections(params, client)["VpcPeeringConnections"][0]
if not peering_conn:
module.exit_json(changed=False)
else:
- pcx_id = pcx_id or peering_conn['VpcPeeringConnectionId']
+ pcx_id = pcx_id or peering_conn["VpcPeeringConnectionId"]
- if peering_conn['Status']['Code'] == 'deleted':
- module.exit_json(msg='Connection in deleted state.', changed=False, peering_id=pcx_id)
- if peering_conn['Status']['Code'] == 'rejected':
+ if peering_conn["Status"]["Code"] == "deleted":
+ module.exit_json(msg="Connection in deleted state.", changed=False, peering_id=pcx_id)
+ if peering_conn["Status"]["Code"] == "rejected":
module.exit_json(
- msg='Connection has been rejected. State cannot be changed and will be removed automatically by AWS',
+ msg="Connection has been rejected. State cannot be changed and will be removed automatically by AWS",
changed=False,
- peering_id=pcx_id
+ peering_id=pcx_id,
)
try:
params = dict()
- params['VpcPeeringConnectionId'] = pcx_id
+ params["VpcPeeringConnectionId"] = pcx_id
client.delete_vpc_peering_connection(aws_retry=True, **params)
- if module.params.get('wait'):
- wait_for_state(client, module, 'deleted', pcx_id)
+ if module.params.get("wait"):
+ wait_for_state(client, module, "deleted", pcx_id)
module.exit_json(changed=True, peering_id=pcx_id)
except botocore.exceptions.ClientError as e:
module.fail_json(msg=str(e))
@@ -494,44 +500,55 @@ def remove_peer_connection(client, module):
def get_peering_connection_by_id(peering_id, client, module):
params = dict()
- params['VpcPeeringConnectionIds'] = [peering_id]
+ params["VpcPeeringConnectionIds"] = [peering_id]
try:
vpc_peering_connection = client.describe_vpc_peering_connections(aws_retry=True, **params)
- return vpc_peering_connection['VpcPeeringConnections'][0]
- except is_boto3_error_code('InvalidVpcPeeringConnectionId.Malformed') as e:
- module.fail_json_aws(e, msg='Malformed connection ID')
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, msg='Error while describing peering connection by peering_id')
+ return vpc_peering_connection["VpcPeeringConnections"][0]
+ except is_boto3_error_code("InvalidVpcPeeringConnectionId.Malformed") as e:
+ module.fail_json_aws(e, msg="Malformed connection ID")
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(e, msg="Error while describing peering connection by peering_id")
def accept_reject(state, client, module):
changed = False
params = dict()
- peering_id = module.params.get('peering_id')
- params['VpcPeeringConnectionId'] = peering_id
+ peering_id = module.params.get("peering_id")
+ params["VpcPeeringConnectionId"] = peering_id
vpc_peering_connection = get_peering_connection_by_id(peering_id, client, module)
- peering_status = vpc_peering_connection['Status']['Code']
+ peering_status = vpc_peering_connection["Status"]["Code"]
- if peering_status not in ['active', 'rejected']:
+ if peering_status not in ["active", "rejected"]:
try:
- if state == 'accept':
+ if state == "accept":
client.accept_vpc_peering_connection(aws_retry=True, **params)
- target_state = 'active'
+ target_state = "active"
else:
client.reject_vpc_peering_connection(aws_retry=True, **params)
- target_state = 'rejected'
- if module.params.get('tags'):
- add_ec2_tags(client, module, peering_id, module.params.get('tags'),
- retry_codes=['InvalidVpcPeeringConnectionID.NotFound'])
+ target_state = "rejected"
+ if module.params.get("tags"):
+ add_ec2_tags(
+ client,
+ module,
+ peering_id,
+ module.params.get("tags"),
+ retry_codes=["InvalidVpcPeeringConnectionID.NotFound"],
+ )
changed = True
- if module.params.get('wait'):
+ if module.params.get("wait"):
wait_for_state(client, module, target_state, peering_id)
except botocore.exceptions.ClientError as e:
module.fail_json(msg=str(e))
- if ensure_ec2_tags(client, module, peering_id,
- purge_tags=module.params.get('purge_tags'),
- tags=module.params.get('tags'),
- ):
+ if ensure_ec2_tags(
+ client,
+ module,
+ peering_id,
+ purge_tags=module.params.get("purge_tags"),
+ tags=module.params.get("tags"),
+ ):
changed = True
# Relaod peering conection infos to return latest state/params
@@ -546,34 +563,36 @@ def main():
peer_region=dict(),
peering_id=dict(),
peer_owner_id=dict(),
- tags=dict(required=False, type='dict', aliases=['resource_tags']),
- purge_tags=dict(default=True, type='bool'),
- state=dict(default='present', choices=['present', 'absent', 'accept', 'reject']),
- wait=dict(default=False, type='bool'),
+ tags=dict(required=False, type="dict", aliases=["resource_tags"]),
+ purge_tags=dict(default=True, type="bool"),
+ state=dict(default="present", choices=["present", "absent", "accept", "reject"]),
+ wait=dict(default=False, type="bool"),
)
required_if = [
- ('state', 'present', ['vpc_id', 'peer_vpc_id']),
- ('state', 'accept', ['peering_id']),
- ('state', 'reject', ['peering_id'])
+ ("state", "present", ["vpc_id", "peer_vpc_id"]),
+ ("state", "accept", ["peering_id"]),
+ ("state", "reject", ["peering_id"]),
]
module = AnsibleAWSModule(argument_spec=argument_spec, required_if=required_if)
- state = module.params.get('state')
- peering_id = module.params.get('peering_id')
- vpc_id = module.params.get('vpc_id')
- peer_vpc_id = module.params.get('peer_vpc_id')
+ state = module.params.get("state")
+ peering_id = module.params.get("peering_id")
+ vpc_id = module.params.get("vpc_id")
+ peer_vpc_id = module.params.get("peer_vpc_id")
try:
- client = module.client('ec2', retry_decorator=AWSRetry.jittered_backoff())
+ client = module.client("ec2", retry_decorator=AWSRetry.jittered_backoff())
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to connect to AWS')
+ module.fail_json_aws(e, msg="Failed to connect to AWS")
- if state == 'present':
+ if state == "present":
(changed, results) = create_peer_connection(client, module)
- elif state == 'absent':
+ elif state == "absent":
if not peering_id and (not vpc_id or not peer_vpc_id):
- module.fail_json(msg='state is absent but one of the following is missing: peering_id or [vpc_id, peer_vpc_id]')
+ module.fail_json(
+ msg="state is absent but one of the following is missing: peering_id or [vpc_id, peer_vpc_id]"
+ )
remove_peer_connection(client, module)
else:
@@ -581,10 +600,12 @@ def main():
formatted_results = camel_dict_to_snake_dict(results)
# Turn the resource tags from boto3 into an ansible friendly tag dictionary
- formatted_results['tags'] = boto3_tag_list_to_ansible_dict(formatted_results.get('tags', []))
+ formatted_results["tags"] = boto3_tag_list_to_ansible_dict(formatted_results.get("tags", []))
- module.exit_json(changed=changed, vpc_peering_connection=formatted_results, peering_id=results['VpcPeeringConnectionId'])
+ module.exit_json(
+ changed=changed, vpc_peering_connection=formatted_results, peering_id=results["VpcPeeringConnectionId"]
+ )
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/ec2_vpc_peering_info.py b/ansible_collections/community/aws/plugins/modules/ec2_vpc_peering_info.py
index 680fa3b68..badc9f8fd 100644
--- a/ansible_collections/community/aws/plugins/modules/ec2_vpc_peering_info.py
+++ b/ansible_collections/community/aws/plugins/modules/ec2_vpc_peering_info.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
module: ec2_vpc_peering_info
short_description: Retrieves AWS VPC Peering details using AWS methods.
version_added: 1.0.0
@@ -25,15 +23,15 @@ options:
for possible filters.
type: dict
default: {}
-author: Karen Cheng (@Etherdaemon)
+author:
+ - Karen Cheng (@Etherdaemon)
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
-
-'''
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
# Simple example of listing all VPC Peers
- name: List all vpc peers
community.aws.ec2_vpc_peering_info:
@@ -58,9 +56,9 @@ EXAMPLES = r'''
filters:
status-code: ['pending-acceptance']
register: pending_vpc_peers
-'''
+"""
-RETURN = r'''
+RETURN = r"""
vpc_peering_connections:
description: Details of the matching VPC peering connections.
returned: success
@@ -199,58 +197,62 @@ result:
description: The result of the describe.
returned: success
type: list
-'''
+"""
try:
import botocore
except ImportError:
pass # Handled by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import normalize_boto3_result
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_filter_list
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import normalize_boto3_result
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.transformation import ansible_dict_to_boto3_filter_list
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def get_vpc_peers(client, module):
params = dict()
- params['Filters'] = ansible_dict_to_boto3_filter_list(module.params.get('filters'))
- if module.params.get('peer_connection_ids'):
- params['VpcPeeringConnectionIds'] = module.params.get('peer_connection_ids')
+ params["Filters"] = ansible_dict_to_boto3_filter_list(module.params.get("filters"))
+ if module.params.get("peer_connection_ids"):
+ params["VpcPeeringConnectionIds"] = module.params.get("peer_connection_ids")
try:
result = client.describe_vpc_peering_connections(aws_retry=True, **params)
result = normalize_boto3_result(result)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Failed to describe peering connections")
- return result['VpcPeeringConnections']
+ return result["VpcPeeringConnections"]
def main():
argument_spec = dict(
- filters=dict(default=dict(), type='dict'),
- peer_connection_ids=dict(default=None, type='list', elements='str'),
+ filters=dict(default=dict(), type="dict"),
+ peer_connection_ids=dict(default=None, type="list", elements="str"),
)
- module = AnsibleAWSModule(argument_spec=argument_spec,
- supports_check_mode=True,)
+ module = AnsibleAWSModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
try:
- ec2 = module.client('ec2', retry_decorator=AWSRetry.jittered_backoff())
+ ec2 = module.client("ec2", retry_decorator=AWSRetry.jittered_backoff())
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to connect to AWS')
+ module.fail_json_aws(e, msg="Failed to connect to AWS")
# Turn the boto3 result in to ansible friendly_snaked_names
results = [camel_dict_to_snake_dict(peer) for peer in get_vpc_peers(ec2, module)]
# Turn the boto3 result in to ansible friendly tag dictionary
for peer in results:
- peer['tags'] = boto3_tag_list_to_ansible_dict(peer.get('tags', []))
+ peer["tags"] = boto3_tag_list_to_ansible_dict(peer.get("tags", []))
module.exit_json(result=results, vpc_peering_connections=results)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/ec2_vpc_vgw.py b/ansible_collections/community/aws/plugins/modules/ec2_vpc_vgw.py
index 8332e1006..135658f76 100644
--- a/ansible_collections/community/aws/plugins/modules/ec2_vpc_vgw.py
+++ b/ansible_collections/community/aws/plugins/modules/ec2_vpc_vgw.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
module: ec2_vpc_vgw
short_description: Create and delete AWS VPN Virtual Gateways
version_added: 1.0.0
@@ -55,13 +53,13 @@ notes:
author:
- Nick Aslanidis (@naslanidis)
extends_documentation_fragment:
- - amazon.aws.ec2
- - amazon.aws.aws
- - amazon.aws.boto3
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.tags
-'''
+ - amazon.aws.boto3
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
- name: Create a new VGW attached to a specific VPC
community.aws.ec2_vpc_vgw:
state: present
@@ -100,9 +98,9 @@ EXAMPLES = '''
profile: personal
vpn_gateway_id: vgw-3a9aa123
register: deleted_vgw
-'''
+"""
-RETURN = '''
+RETURN = r"""
vgw:
description: A description of the VGW
returned: success
@@ -133,7 +131,7 @@ vgw:
type: str
returned: success
example: vpc-123456789abcdef01
-'''
+"""
import time
@@ -142,13 +140,14 @@ try:
except ImportError:
pass # Handled by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ensure_ec2_tags
-from ansible_collections.amazon.aws.plugins.module_utils.waiters import get_waiter
-from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_specifications
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_specifications
+from ansible_collections.amazon.aws.plugins.module_utils.waiters import get_waiter
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
# AWS uses VpnGatewayLimitExceeded for both 'Too many VGWs' and 'Too many concurrent changes'
@@ -156,11 +155,14 @@ from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_ta
class VGWRetry(AWSRetry):
@staticmethod
def status_code_from_exception(error):
- return (error.response['Error']['Code'], error.response['Error']['Message'],)
+ return (
+ error.response["Error"]["Code"],
+ error.response["Error"]["Message"],
+ )
@staticmethod
def found(response_code, catch_extra_error_codes=None):
- retry_on = ['The maximum number of mutating objects has been reached.']
+ retry_on = ["The maximum number of mutating objects has been reached."]
if catch_extra_error_codes:
retry_on.extend(catch_extra_error_codes)
@@ -180,37 +182,37 @@ def get_vgw_info(vgws):
for vgw in vgws:
vgw_info = {
- 'id': vgw['VpnGatewayId'],
- 'type': vgw['Type'],
- 'state': vgw['State'],
- 'vpc_id': None,
- 'tags': dict()
+ "id": vgw["VpnGatewayId"],
+ "type": vgw["Type"],
+ "state": vgw["State"],
+ "vpc_id": None,
+ "tags": dict(),
}
- if vgw['Tags']:
- vgw_info['tags'] = boto3_tag_list_to_ansible_dict(vgw['Tags'])
+ if vgw["Tags"]:
+ vgw_info["tags"] = boto3_tag_list_to_ansible_dict(vgw["Tags"])
- if len(vgw['VpcAttachments']) != 0 and vgw['VpcAttachments'][0]['State'] == 'attached':
- vgw_info['vpc_id'] = vgw['VpcAttachments'][0]['VpcId']
+ if len(vgw["VpcAttachments"]) != 0 and vgw["VpcAttachments"][0]["State"] == "attached":
+ vgw_info["vpc_id"] = vgw["VpcAttachments"][0]["VpcId"]
return vgw_info
def wait_for_status(client, module, vpn_gateway_id, status):
polling_increment_secs = 15
- max_retries = (module.params.get('wait_timeout') // polling_increment_secs)
+ max_retries = module.params.get("wait_timeout") // polling_increment_secs
status_achieved = False
for x in range(0, max_retries):
try:
response = find_vgw(client, module, vpn_gateway_id)
- if response[0]['VpcAttachments'][0]['State'] == status:
+ if response[0]["VpcAttachments"][0]["State"] == status:
status_achieved = True
break
else:
time.sleep(polling_increment_secs)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failure while waiting for status update')
+ module.fail_json_aws(e, msg="Failure while waiting for status update")
result = response
return status_achieved, result
@@ -218,22 +220,21 @@ def wait_for_status(client, module, vpn_gateway_id, status):
def attach_vgw(client, module, vpn_gateway_id):
params = dict()
- params['VpcId'] = module.params.get('vpc_id')
+ params["VpcId"] = module.params.get("vpc_id")
try:
# Immediately after a detachment, the EC2 API sometimes will report the VpnGateways[0].State
# as available several seconds before actually permitting a new attachment.
# So we catch and retry that error. See https://github.com/ansible/ansible/issues/53185
- response = VGWRetry.jittered_backoff(retries=5,
- catch_extra_error_codes=['InvalidParameterValue']
- )(client.attach_vpn_gateway)(VpnGatewayId=vpn_gateway_id,
- VpcId=params['VpcId'])
+ response = VGWRetry.jittered_backoff(retries=5, catch_extra_error_codes=["InvalidParameterValue"])(
+ client.attach_vpn_gateway
+ )(VpnGatewayId=vpn_gateway_id, VpcId=params["VpcId"])
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to attach VPC')
+ module.fail_json_aws(e, msg="Failed to attach VPC")
- status_achieved, vgw = wait_for_status(client, module, [vpn_gateway_id], 'attached')
+ status_achieved, vgw = wait_for_status(client, module, [vpn_gateway_id], "attached")
if not status_achieved:
- module.fail_json(msg='Error waiting for vpc to attach to vgw - please check the AWS console')
+ module.fail_json(msg="Error waiting for vpc to attach to vgw - please check the AWS console")
result = response
return result
@@ -241,19 +242,19 @@ def attach_vgw(client, module, vpn_gateway_id):
def detach_vgw(client, module, vpn_gateway_id, vpc_id=None):
params = dict()
- params['VpcId'] = module.params.get('vpc_id')
+ params["VpcId"] = module.params.get("vpc_id")
try:
if vpc_id:
response = client.detach_vpn_gateway(VpnGatewayId=vpn_gateway_id, VpcId=vpc_id, aws_retry=True)
else:
- response = client.detach_vpn_gateway(VpnGatewayId=vpn_gateway_id, VpcId=params['VpcId'], aws_retry=True)
+ response = client.detach_vpn_gateway(VpnGatewayId=vpn_gateway_id, VpcId=params["VpcId"], aws_retry=True)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, 'Failed to detach gateway')
+ module.fail_json_aws(e, "Failed to detach gateway")
- status_achieved, vgw = wait_for_status(client, module, [vpn_gateway_id], 'detached')
+ status_achieved, vgw = wait_for_status(client, module, [vpn_gateway_id], "detached")
if not status_achieved:
- module.fail_json(msg='Error waiting for vpc to detach from vgw - please check the AWS console')
+ module.fail_json(msg="Error waiting for vpc to detach from vgw - please check the AWS console")
result = response
return result
@@ -261,37 +262,37 @@ def detach_vgw(client, module, vpn_gateway_id, vpc_id=None):
def create_vgw(client, module):
params = dict()
- params['Type'] = module.params.get('type')
- tags = module.params.get('tags') or {}
- tags['Name'] = module.params.get('name')
- params['TagSpecifications'] = boto3_tag_specifications(tags, ['vpn-gateway'])
- if module.params.get('asn'):
- params['AmazonSideAsn'] = module.params.get('asn')
+ params["Type"] = module.params.get("type")
+ tags = module.params.get("tags") or {}
+ tags["Name"] = module.params.get("name")
+ params["TagSpecifications"] = boto3_tag_specifications(tags, ["vpn-gateway"])
+ if module.params.get("asn"):
+ params["AmazonSideAsn"] = module.params.get("asn")
try:
response = client.create_vpn_gateway(aws_retry=True, **params)
- get_waiter(
- client, 'vpn_gateway_exists'
- ).wait(
- VpnGatewayIds=[response['VpnGateway']['VpnGatewayId']]
- )
+ get_waiter(client, "vpn_gateway_exists").wait(VpnGatewayIds=[response["VpnGateway"]["VpnGatewayId"]])
except botocore.exceptions.WaiterError as e:
- module.fail_json_aws(e, msg="Failed to wait for Vpn Gateway {0} to be available".format(response['VpnGateway']['VpnGatewayId']))
- except is_boto3_error_code('VpnGatewayLimitExceeded') as e:
+ module.fail_json_aws(
+ e, msg=f"Failed to wait for Vpn Gateway {response['VpnGateway']['VpnGatewayId']} to be available"
+ )
+ except is_boto3_error_code("VpnGatewayLimitExceeded") as e:
module.fail_json_aws(e, msg="Too many VPN gateways exist in this account.")
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, msg='Failed to create gateway')
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(e, msg="Failed to create gateway")
result = response
return result
def delete_vgw(client, module, vpn_gateway_id):
-
try:
response = client.delete_vpn_gateway(VpnGatewayId=vpn_gateway_id, aws_retry=True)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to delete gateway')
+ module.fail_json_aws(e, msg="Failed to delete gateway")
# return the deleted VpnGatewayId as this is not included in the above response
result = vpn_gateway_id
@@ -300,13 +301,13 @@ def delete_vgw(client, module, vpn_gateway_id):
def find_vpc(client, module):
params = dict()
- params['vpc_id'] = module.params.get('vpc_id')
+ params["vpc_id"] = module.params.get("vpc_id")
- if params['vpc_id']:
+ if params["vpc_id"]:
try:
- response = client.describe_vpcs(VpcIds=[params['vpc_id']], aws_retry=True)
+ response = client.describe_vpcs(VpcIds=[params["vpc_id"]], aws_retry=True)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to describe VPC')
+ module.fail_json_aws(e, msg="Failed to describe VPC")
result = response
return result
@@ -315,66 +316,68 @@ def find_vpc(client, module):
def find_vgw(client, module, vpn_gateway_id=None):
params = dict()
if vpn_gateway_id:
- params['VpnGatewayIds'] = vpn_gateway_id
+ params["VpnGatewayIds"] = vpn_gateway_id
else:
- params['Filters'] = [
- {'Name': 'type', 'Values': [module.params.get('type')]},
- {'Name': 'tag:Name', 'Values': [module.params.get('name')]},
+ params["Filters"] = [
+ {"Name": "type", "Values": [module.params.get("type")]},
+ {"Name": "tag:Name", "Values": [module.params.get("name")]},
]
- if module.params.get('state') == 'present':
- params['Filters'].append({'Name': 'state', 'Values': ['pending', 'available']})
+ if module.params.get("state") == "present":
+ params["Filters"].append({"Name": "state", "Values": ["pending", "available"]})
try:
response = client.describe_vpn_gateways(aws_retry=True, **params)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to describe gateway using filters')
+ module.fail_json_aws(e, msg="Failed to describe gateway using filters")
- return sorted(response['VpnGateways'], key=lambda k: k['VpnGatewayId'])
+ return sorted(response["VpnGateways"], key=lambda k: k["VpnGatewayId"])
def ensure_vgw_present(client, module):
-
# If an existing vgw name and type matches our args, then a match is considered to have been
# found and we will not create another vgw.
changed = False
params = dict()
result = dict()
- params['Name'] = module.params.get('name')
- params['VpcId'] = module.params.get('vpc_id')
- params['Type'] = module.params.get('type')
- params['Tags'] = module.params.get('tags')
- params['VpnGatewayIds'] = module.params.get('vpn_gateway_id')
+ params["Name"] = module.params.get("name")
+ params["VpcId"] = module.params.get("vpc_id")
+ params["Type"] = module.params.get("type")
+ params["Tags"] = module.params.get("tags")
+ params["VpnGatewayIds"] = module.params.get("vpn_gateway_id")
# check that the vpc_id exists. If not, an exception is thrown
- if params['VpcId']:
+ if params["VpcId"]:
vpc = find_vpc(client, module)
# check if a gateway matching our module args already exists
existing_vgw = find_vgw(client, module)
if existing_vgw != []:
- vpn_gateway_id = existing_vgw[0]['VpnGatewayId']
- desired_tags = module.params.get('tags')
- purge_tags = module.params.get('purge_tags')
+ vpn_gateway_id = existing_vgw[0]["VpnGatewayId"]
+ desired_tags = module.params.get("tags")
+ purge_tags = module.params.get("purge_tags")
if desired_tags is None:
desired_tags = dict()
purge_tags = False
- tags = dict(Name=module.params.get('name'))
+ tags = dict(Name=module.params.get("name"))
tags.update(desired_tags)
- changed = ensure_ec2_tags(client, module, vpn_gateway_id, resource_type='vpn-gateway',
- tags=tags, purge_tags=purge_tags)
+ changed = ensure_ec2_tags(
+ client, module, vpn_gateway_id, resource_type="vpn-gateway", tags=tags, purge_tags=purge_tags
+ )
# if a vpc_id was provided, check if it exists and if it's attached
- if params['VpcId']:
-
- current_vpc_attachments = existing_vgw[0]['VpcAttachments']
-
- if current_vpc_attachments != [] and current_vpc_attachments[0]['State'] == 'attached':
- if current_vpc_attachments[0]['VpcId'] != params['VpcId'] or current_vpc_attachments[0]['State'] != 'attached':
+ if params["VpcId"]:
+ current_vpc_attachments = existing_vgw[0]["VpcAttachments"]
+
+ if current_vpc_attachments != [] and current_vpc_attachments[0]["State"] == "attached":
+ if (
+ current_vpc_attachments[0]["VpcId"] != params["VpcId"]
+ or current_vpc_attachments[0]["State"] != "attached"
+ ):
# detach the existing vpc from the virtual gateway
- vpc_to_detach = current_vpc_attachments[0]['VpcId']
+ vpc_to_detach = current_vpc_attachments[0]["VpcId"]
detach_vgw(client, module, vpn_gateway_id, vpc_to_detach)
- get_waiter(client, 'vpn_gateway_detached').wait(VpnGatewayIds=[vpn_gateway_id])
+ get_waiter(client, "vpn_gateway_detached").wait(VpnGatewayIds=[vpn_gateway_id])
attached_vgw = attach_vgw(client, module, vpn_gateway_id)
changed = True
else:
@@ -386,10 +389,10 @@ def ensure_vgw_present(client, module):
else:
existing_vgw = find_vgw(client, module, [vpn_gateway_id])
- if existing_vgw[0]['VpcAttachments'] != []:
- if existing_vgw[0]['VpcAttachments'][0]['State'] == 'attached':
+ if existing_vgw[0]["VpcAttachments"] != []:
+ if existing_vgw[0]["VpcAttachments"][0]["State"] == "attached":
# detach the vpc from the vgw
- vpc_to_detach = existing_vgw[0]['VpcAttachments'][0]['VpcId']
+ vpc_to_detach = existing_vgw[0]["VpcAttachments"][0]["VpcId"]
detach_vgw(client, module, vpn_gateway_id, vpc_to_detach)
changed = True
@@ -397,10 +400,10 @@ def ensure_vgw_present(client, module):
# create a new vgw
new_vgw = create_vgw(client, module)
changed = True
- vpn_gateway_id = new_vgw['VpnGateway']['VpnGatewayId']
+ vpn_gateway_id = new_vgw["VpnGateway"]["VpnGatewayId"]
# if a vpc-id was supplied, attempt to attach it to the vgw
- if params['VpcId']:
+ if params["VpcId"]:
attached_vgw = attach_vgw(client, module, vpn_gateway_id)
changed = True
@@ -411,45 +414,46 @@ def ensure_vgw_present(client, module):
def ensure_vgw_absent(client, module):
-
# If an existing vgw name and type matches our args, then a match is considered to have been
# found and we will take steps to delete it.
changed = False
params = dict()
result = dict()
- params['Name'] = module.params.get('name')
- params['VpcId'] = module.params.get('vpc_id')
- params['Type'] = module.params.get('type')
- params['Tags'] = module.params.get('tags')
- params['VpnGatewayIds'] = module.params.get('vpn_gateway_id')
+ params["Name"] = module.params.get("name")
+ params["VpcId"] = module.params.get("vpc_id")
+ params["Type"] = module.params.get("type")
+ params["Tags"] = module.params.get("tags")
+ params["VpnGatewayIds"] = module.params.get("vpn_gateway_id")
# check if a gateway matching our module args already exists
- if params['VpnGatewayIds']:
- existing_vgw_with_id = find_vgw(client, module, [params['VpnGatewayIds']])
- if existing_vgw_with_id != [] and existing_vgw_with_id[0]['State'] != 'deleted':
+ if params["VpnGatewayIds"]:
+ existing_vgw_with_id = find_vgw(client, module, [params["VpnGatewayIds"]])
+ if existing_vgw_with_id != [] and existing_vgw_with_id[0]["State"] != "deleted":
existing_vgw = existing_vgw_with_id
- if existing_vgw[0]['VpcAttachments'] != [] and existing_vgw[0]['VpcAttachments'][0]['State'] == 'attached':
- if params['VpcId']:
- if params['VpcId'] != existing_vgw[0]['VpcAttachments'][0]['VpcId']:
- module.fail_json(msg='The vpc-id provided does not match the vpc-id currently attached - please check the AWS console')
+ if existing_vgw[0]["VpcAttachments"] != [] and existing_vgw[0]["VpcAttachments"][0]["State"] == "attached":
+ if params["VpcId"]:
+ if params["VpcId"] != existing_vgw[0]["VpcAttachments"][0]["VpcId"]:
+ module.fail_json(
+ msg="The vpc-id provided does not match the vpc-id currently attached - please check the AWS console"
+ )
else:
# detach the vpc from the vgw
- detach_vgw(client, module, params['VpnGatewayIds'], params['VpcId'])
- deleted_vgw = delete_vgw(client, module, params['VpnGatewayIds'])
+ detach_vgw(client, module, params["VpnGatewayIds"], params["VpcId"])
+ deleted_vgw = delete_vgw(client, module, params["VpnGatewayIds"])
changed = True
else:
# attempt to detach any attached vpcs
- vpc_to_detach = existing_vgw[0]['VpcAttachments'][0]['VpcId']
- detach_vgw(client, module, params['VpnGatewayIds'], vpc_to_detach)
- deleted_vgw = delete_vgw(client, module, params['VpnGatewayIds'])
+ vpc_to_detach = existing_vgw[0]["VpcAttachments"][0]["VpcId"]
+ detach_vgw(client, module, params["VpnGatewayIds"], vpc_to_detach)
+ deleted_vgw = delete_vgw(client, module, params["VpnGatewayIds"])
changed = True
else:
# no vpc's are attached so attempt to delete the vgw
- deleted_vgw = delete_vgw(client, module, params['VpnGatewayIds'])
+ deleted_vgw = delete_vgw(client, module, params["VpnGatewayIds"])
changed = True
else:
@@ -458,20 +462,22 @@ def ensure_vgw_absent(client, module):
else:
# Check that a name and type argument has been supplied if no vgw-id
- if not module.params.get('name') or not module.params.get('type'):
- module.fail_json(msg='A name and type is required when no vgw-id and a status of \'absent\' is supplied')
+ if not module.params.get("name") or not module.params.get("type"):
+ module.fail_json(msg="A name and type is required when no vgw-id and a status of 'absent' is supplied")
existing_vgw = find_vgw(client, module)
- if existing_vgw != [] and existing_vgw[0]['State'] != 'deleted':
- vpn_gateway_id = existing_vgw[0]['VpnGatewayId']
- if existing_vgw[0]['VpcAttachments'] != [] and existing_vgw[0]['VpcAttachments'][0]['State'] == 'attached':
- if params['VpcId']:
- if params['VpcId'] != existing_vgw[0]['VpcAttachments'][0]['VpcId']:
- module.fail_json(msg='The vpc-id provided does not match the vpc-id currently attached - please check the AWS console')
+ if existing_vgw != [] and existing_vgw[0]["State"] != "deleted":
+ vpn_gateway_id = existing_vgw[0]["VpnGatewayId"]
+ if existing_vgw[0]["VpcAttachments"] != [] and existing_vgw[0]["VpcAttachments"][0]["State"] == "attached":
+ if params["VpcId"]:
+ if params["VpcId"] != existing_vgw[0]["VpcAttachments"][0]["VpcId"]:
+ module.fail_json(
+ msg="The vpc-id provided does not match the vpc-id currently attached - please check the AWS console"
+ )
else:
# detach the vpc from the vgw
- detach_vgw(client, module, vpn_gateway_id, params['VpcId'])
+ detach_vgw(client, module, vpn_gateway_id, params["VpcId"])
# now that the vpc has been detached, delete the vgw
deleted_vgw = delete_vgw(client, module, vpn_gateway_id)
@@ -479,7 +485,7 @@ def ensure_vgw_absent(client, module):
else:
# attempt to detach any attached vpcs
- vpc_to_detach = existing_vgw[0]['VpcAttachments'][0]['VpcId']
+ vpc_to_detach = existing_vgw[0]["VpcAttachments"][0]["VpcId"]
detach_vgw(client, module, vpn_gateway_id, vpc_to_detach)
changed = True
@@ -501,29 +507,28 @@ def ensure_vgw_absent(client, module):
def main():
argument_spec = dict(
- state=dict(default='present', choices=['present', 'absent']),
+ state=dict(default="present", choices=["present", "absent"]),
name=dict(),
vpn_gateway_id=dict(),
vpc_id=dict(),
- asn=dict(type='int'),
- wait_timeout=dict(type='int', default=320),
- type=dict(default='ipsec.1', choices=['ipsec.1']),
- tags=dict(default=None, required=False, type='dict', aliases=['resource_tags']),
- purge_tags=dict(default=True, type='bool'),
+ asn=dict(type="int"),
+ wait_timeout=dict(type="int", default=320),
+ type=dict(default="ipsec.1", choices=["ipsec.1"]),
+ tags=dict(default=None, required=False, type="dict", aliases=["resource_tags"]),
+ purge_tags=dict(default=True, type="bool"),
)
- module = AnsibleAWSModule(argument_spec=argument_spec,
- required_if=[['state', 'present', ['name']]])
+ module = AnsibleAWSModule(argument_spec=argument_spec, required_if=[["state", "present", ["name"]]])
- state = module.params.get('state').lower()
+ state = module.params.get("state").lower()
- client = module.client('ec2', retry_decorator=VGWRetry.jittered_backoff(retries=10))
+ client = module.client("ec2", retry_decorator=VGWRetry.jittered_backoff(retries=10))
- if state == 'present':
+ if state == "present":
(changed, results) = ensure_vgw_present(client, module)
else:
(changed, results) = ensure_vgw_absent(client, module)
module.exit_json(changed=changed, vgw=results)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/ec2_vpc_vgw_info.py b/ansible_collections/community/aws/plugins/modules/ec2_vpc_vgw_info.py
index fcb520cf0..6ab311c03 100644
--- a/ansible_collections/community/aws/plugins/modules/ec2_vpc_vgw_info.py
+++ b/ansible_collections/community/aws/plugins/modules/ec2_vpc_vgw_info.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: ec2_vpc_vgw_info
version_added: 1.0.0
@@ -28,12 +26,12 @@ options:
author:
- "Nick Aslanidis (@naslanidis)"
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
# # Note: These examples do not set authentication details, see the AWS Guide for details.
- name: Gather information about all virtual gateways for an account or profile
@@ -47,7 +45,7 @@ EXAMPLES = r'''
region: ap-southeast-2
profile: production
filters:
- "tag:Name": "main-virt-gateway"
+ "tag:Name": "main-virt-gateway"
register: vgw_info
- name: Gather information about a specific virtual gateway by VpnGatewayIds
@@ -56,9 +54,9 @@ EXAMPLES = r'''
profile: production
vpn_gateway_ids: vgw-c432f6a7
register: vgw_info
-'''
+"""
-RETURN = r'''
+RETURN = r"""
virtual_gateways:
description: The virtual gateways for the account.
returned: always
@@ -121,7 +119,7 @@ virtual_gateways:
type: dict
returned: success
example: {"MyKey": "MyValue"}
-'''
+"""
try:
import botocore
@@ -130,19 +128,20 @@ except ImportError:
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_filter_list
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.transformation import ansible_dict_to_boto3_filter_list
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def get_virtual_gateway_info(virtual_gateway):
- tags = virtual_gateway.get('Tags', [])
+ tags = virtual_gateway.get("Tags", [])
resource_tags = boto3_tag_list_to_ansible_dict(tags)
virtual_gateway_info = dict(
- VpnGatewayId=virtual_gateway['VpnGatewayId'],
- State=virtual_gateway['State'],
- Type=virtual_gateway['Type'],
- VpcAttachments=virtual_gateway['VpcAttachments'],
+ VpnGatewayId=virtual_gateway["VpnGatewayId"],
+ State=virtual_gateway["State"],
+ Type=virtual_gateway["Type"],
+ VpcAttachments=virtual_gateway["VpcAttachments"],
Tags=tags,
ResourceTags=resource_tags,
)
@@ -152,32 +151,34 @@ def get_virtual_gateway_info(virtual_gateway):
def list_virtual_gateways(client, module):
params = dict()
- params['Filters'] = ansible_dict_to_boto3_filter_list(module.params.get('filters'))
+ params["Filters"] = ansible_dict_to_boto3_filter_list(module.params.get("filters"))
if module.params.get("vpn_gateway_ids"):
- params['VpnGatewayIds'] = module.params.get("vpn_gateway_ids")
+ params["VpnGatewayIds"] = module.params.get("vpn_gateway_ids")
try:
all_virtual_gateways = client.describe_vpn_gateways(**params)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Failed to list gateways")
- return [camel_dict_to_snake_dict(get_virtual_gateway_info(vgw), ignore_list=['ResourceTags'])
- for vgw in all_virtual_gateways['VpnGateways']]
+ return [
+ camel_dict_to_snake_dict(get_virtual_gateway_info(vgw), ignore_list=["ResourceTags"])
+ for vgw in all_virtual_gateways["VpnGateways"]
+ ]
def main():
argument_spec = dict(
- filters=dict(type='dict', default=dict()),
- vpn_gateway_ids=dict(type='list', default=None, elements='str'),
+ filters=dict(type="dict", default=dict()),
+ vpn_gateway_ids=dict(type="list", default=None, elements="str"),
)
module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
try:
- connection = module.client('ec2')
+ connection = module.client("ec2")
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to connect to AWS')
+ module.fail_json_aws(e, msg="Failed to connect to AWS")
# call your function here
results = list_virtual_gateways(connection, module)
@@ -185,5 +186,5 @@ def main():
module.exit_json(virtual_gateways=results)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/ec2_vpc_vpn.py b/ansible_collections/community/aws/plugins/modules/ec2_vpc_vpn.py
index 77a994aaa..abc97f796 100644
--- a/ansible_collections/community/aws/plugins/modules/ec2_vpc_vpn.py
+++ b/ansible_collections/community/aws/plugins/modules/ec2_vpc_vpn.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: ec2_vpc_vpn
version_added: 1.0.0
@@ -14,11 +12,6 @@ short_description: Create, modify, and delete EC2 VPN connections
description:
- This module creates, modifies, and deletes VPN connections. Idempotence is achieved by using the filters
option or specifying the VPN connection identifier.
-extends_documentation_fragment:
- - amazon.aws.ec2
- - amazon.aws.aws
- - amazon.aws.boto3
- - amazon.aws.tags
author:
- "Sloane Hertel (@s-hertel)"
options:
@@ -42,6 +35,7 @@ options:
vpn_gateway_id:
description:
- The ID of the virtual private gateway.
+ - Mutually exclusive with I(transit_gateway_id).
type: str
vpn_connection_id:
description:
@@ -53,6 +47,12 @@ options:
default: False
type: bool
required: false
+ transit_gateway_id:
+ description:
+ - The ID of the transit gateway.
+ - Mutually exclusive with I(vpn_gateway_id).
+ type: str
+ version_added: 6.2.0
tunnel_options:
description:
- An optional list object containing no more than two dict members, each of which may contain I(TunnelInsideCidr)
@@ -135,18 +135,28 @@ options:
required: false
type: int
default: 15
-'''
+extends_documentation_fragment:
+ - amazon.aws.region.modules
+ - amazon.aws.common.modules
+ - amazon.aws.tags
+ - amazon.aws.boto3
+"""
EXAMPLES = r"""
-# Note: None of these examples set aws_access_key, aws_secret_key, or region.
-# It is assumed that their matching environment variables are set.
+# Note: These examples do not set authentication details, see the AWS Guide for details.
-- name: create a VPN connection
+- name: create a VPN connection with vpn_gateway_id
community.aws.ec2_vpc_vpn:
state: present
vpn_gateway_id: vgw-XXXXXXXX
customer_gateway_id: cgw-XXXXXXXX
+- name: Attach a vpn connection to transit gateway
+ community.aws.ec2_vpc_vpn:
+ state: present
+ transit_gateway_id: tgw-XXXXXXXX
+ customer_gateway_id: cgw-XXXXXXXX
+
- name: modify VPN connection tags
community.aws.ec2_vpc_vpn:
state: present
@@ -233,6 +243,12 @@ vpn_gateway_id:
returned: I(state=present)
sample:
vpn_gateway_id: vgw-cb0ae2a2
+transit_gateway_id:
+ description: The transit gateway id to which the vpn connection can be attached.
+ type: str
+ returned: I(state=present)
+ sample:
+ transit_gateway_id: tgw-cb0ae2a2
options:
description: The VPN connection options (currently only containing static_routes_only).
type: complex
@@ -293,19 +309,23 @@ vpn_connection_id:
vpn_connection_id: vpn-781e0e19
"""
-from ansible.module_utils._text import to_text
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_tag_list
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import compare_aws_tags
-
try:
- from botocore.exceptions import BotoCoreError, ClientError, WaiterError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
+ from botocore.exceptions import WaiterError
except ImportError:
pass # Handled by AnsibleAWSModule
+from ansible.module_utils._text import to_text
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import ansible_dict_to_boto3_tag_list
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import compare_aws_tags
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
+
class VPNConnectionException(Exception):
def __init__(self, msg, exception=None):
@@ -319,11 +339,14 @@ class VPNConnectionException(Exception):
class VPNRetry(AWSRetry):
@staticmethod
def status_code_from_exception(error):
- return (error.response['Error']['Code'], error.response['Error']['Message'],)
+ return (
+ error.response["Error"]["Code"],
+ error.response["Error"]["Message"],
+ )
@staticmethod
def found(response_code, catch_extra_error_codes=None):
- retry_on = ['The maximum number of mutating objects has been reached.']
+ retry_on = ["The maximum number of mutating objects has been reached."]
if catch_extra_error_codes:
retry_on.extend(catch_extra_error_codes)
@@ -338,14 +361,14 @@ class VPNRetry(AWSRetry):
def find_connection(connection, module_params, vpn_connection_id=None):
- ''' Looks for a unique VPN connection. Uses find_connection_response() to return the connection found, None,
- or raise an error if there were multiple viable connections. '''
+ """Looks for a unique VPN connection. Uses find_connection_response() to return the connection found, None,
+ or raise an error if there were multiple viable connections."""
- filters = module_params.get('filters')
+ filters = module_params.get("filters")
# vpn_connection_id may be provided via module option; takes precedence over any filter values
- if not vpn_connection_id and module_params.get('vpn_connection_id'):
- vpn_connection_id = module_params.get('vpn_connection_id')
+ if not vpn_connection_id and module_params.get("vpn_connection_id"):
+ vpn_connection_id = module_params.get("vpn_connection_id")
if not isinstance(vpn_connection_id, list) and vpn_connection_id:
vpn_connection_id = [to_text(vpn_connection_id)]
@@ -360,14 +383,13 @@ def find_connection(connection, module_params, vpn_connection_id=None):
# see if there is a unique matching connection
try:
if vpn_connection_id:
- existing_conn = connection.describe_vpn_connections(aws_retry=True,
- VpnConnectionIds=vpn_connection_id,
- Filters=formatted_filter)
+ existing_conn = connection.describe_vpn_connections(
+ aws_retry=True, VpnConnectionIds=vpn_connection_id, Filters=formatted_filter
+ )
else:
existing_conn = connection.describe_vpn_connections(aws_retry=True, Filters=formatted_filter)
except (BotoCoreError, ClientError) as e:
- raise VPNConnectionException(msg="Failed while describing VPN connection.",
- exception=e)
+ raise VPNConnectionException(msg="Failed while describing VPN connection.", exception=e)
return find_connection_response(connections=existing_conn)
@@ -375,48 +397,56 @@ def find_connection(connection, module_params, vpn_connection_id=None):
def add_routes(connection, vpn_connection_id, routes_to_add):
for route in routes_to_add:
try:
- connection.create_vpn_connection_route(aws_retry=True,
- VpnConnectionId=vpn_connection_id,
- DestinationCidrBlock=route)
+ connection.create_vpn_connection_route(
+ aws_retry=True, VpnConnectionId=vpn_connection_id, DestinationCidrBlock=route
+ )
except (BotoCoreError, ClientError) as e:
- raise VPNConnectionException(msg="Failed while adding route {0} to the VPN connection {1}.".format(route, vpn_connection_id),
- exception=e)
+ raise VPNConnectionException(
+ msg=f"Failed while adding route {route} to the VPN connection {vpn_connection_id}.",
+ exception=e,
+ )
def remove_routes(connection, vpn_connection_id, routes_to_remove):
for route in routes_to_remove:
try:
- connection.delete_vpn_connection_route(aws_retry=True,
- VpnConnectionId=vpn_connection_id,
- DestinationCidrBlock=route)
+ connection.delete_vpn_connection_route(
+ aws_retry=True, VpnConnectionId=vpn_connection_id, DestinationCidrBlock=route
+ )
except (BotoCoreError, ClientError) as e:
- raise VPNConnectionException(msg="Failed to remove route {0} from the VPN connection {1}.".format(route, vpn_connection_id),
- exception=e)
+ raise VPNConnectionException(
+ msg=f"Failed to remove route {route} from the VPN connection {vpn_connection_id}.",
+ exception=e,
+ )
def create_filter(module_params, provided_filters):
- """ Creates a filter using the user-specified parameters and unmodifiable options that may have been specified in the task """
- boto3ify_filter = {'cgw-config': 'customer-gateway-configuration',
- 'static-routes-only': 'option.static-routes-only',
- 'cidr': 'route.destination-cidr-block',
- 'bgp': 'bgp-asn',
- 'vpn': 'vpn-connection-id',
- 'vgw': 'vpn-gateway-id',
- 'tag-keys': 'tag-key',
- 'tag-values': 'tag-value',
- 'tags': 'tag',
- 'cgw': 'customer-gateway-id'}
+ """Creates a filter using the user-specified parameters and unmodifiable options that may have been specified in the task"""
+ boto3ify_filter = {
+ "cgw-config": "customer-gateway-configuration",
+ "static-routes-only": "option.static-routes-only",
+ "cidr": "route.destination-cidr-block",
+ "bgp": "bgp-asn",
+ "vpn": "vpn-connection-id",
+ "vgw": "vpn-gateway-id",
+ "tag-keys": "tag-key",
+ "tag-values": "tag-value",
+ "tags": "tag",
+ "cgw": "customer-gateway-id",
+ }
# unmodifiable options and their filter name counterpart
- param_to_filter = {"customer_gateway_id": "customer-gateway-id",
- "vpn_gateway_id": "vpn-gateway-id",
- "vpn_connection_id": "vpn-connection-id"}
+ param_to_filter = {
+ "customer_gateway_id": "customer-gateway-id",
+ "vpn_gateway_id": "vpn-gateway-id",
+ "transit_gateway_id": "transit-gateway-id",
+ "vpn_connection_id": "vpn-connection-id",
+ }
flat_filter_dict = {}
formatted_filter = []
for raw_param in dict(provided_filters):
-
# fix filter names to be recognized by boto3
if raw_param in boto3ify_filter:
param = boto3ify_filter[raw_param]
@@ -424,17 +454,17 @@ def create_filter(module_params, provided_filters):
elif raw_param in list(boto3ify_filter.items()):
param = raw_param
else:
- raise VPNConnectionException(msg="{0} is not a valid filter.".format(raw_param))
+ raise VPNConnectionException(msg=f"{raw_param} is not a valid filter.")
# reformat filters with special formats
- if param == 'tag':
+ if param == "tag":
for key in provided_filters[param]:
- formatted_key = 'tag:' + key
+ formatted_key = "tag:" + key
if isinstance(provided_filters[param][key], list):
flat_filter_dict[formatted_key] = str(provided_filters[param][key])
else:
flat_filter_dict[formatted_key] = [str(provided_filters[param][key])]
- elif param == 'option.static-routes-only':
+ elif param == "option.static-routes-only":
flat_filter_dict[param] = [str(provided_filters[param]).lower()]
else:
if isinstance(provided_filters[param], list):
@@ -448,25 +478,25 @@ def create_filter(module_params, provided_filters):
flat_filter_dict[param_to_filter[param]] = [module_params.get(param)]
# change the flat dict into something boto3 will understand
- formatted_filter = [{'Name': key, 'Values': value} for key, value in flat_filter_dict.items()]
+ formatted_filter = [{"Name": key, "Values": value} for key, value in flat_filter_dict.items()]
return formatted_filter
def find_connection_response(connections=None):
- """ Determine if there is a viable unique match in the connections described. Returns the unique VPN connection if one is found,
- returns None if the connection does not exist, raise an error if multiple matches are found. """
+ """Determine if there is a viable unique match in the connections described. Returns the unique VPN connection if one is found,
+ returns None if the connection does not exist, raise an error if multiple matches are found."""
# Found no connections
- if not connections or 'VpnConnections' not in connections:
+ if not connections or "VpnConnections" not in connections:
return None
# Too many results
- elif connections and len(connections['VpnConnections']) > 1:
+ elif connections and len(connections["VpnConnections"]) > 1:
viable = []
- for each in connections['VpnConnections']:
+ for each in connections["VpnConnections"]:
# deleted connections are not modifiable
- if each['State'] not in ("deleted", "deleting"):
+ if each["State"] not in ("deleted", "deleting"):
viable.append(each)
if len(viable) == 1:
# Found one viable result; return unique match
@@ -475,20 +505,34 @@ def find_connection_response(connections=None):
# Found a result but it was deleted already; since there was only one viable result create a new one
return None
else:
- raise VPNConnectionException(msg="More than one matching VPN connection was found. "
- "To modify or delete a VPN please specify vpn_connection_id or add filters.")
+ raise VPNConnectionException(
+ msg=(
+ "More than one matching VPN connection was found. "
+ "To modify or delete a VPN please specify vpn_connection_id or add filters."
+ )
+ )
# Found unique match
- elif connections and len(connections['VpnConnections']) == 1:
+ elif connections and len(connections["VpnConnections"]) == 1:
# deleted connections are not modifiable
- if connections['VpnConnections'][0]['State'] not in ("deleted", "deleting"):
- return connections['VpnConnections'][0]
-
-
-def create_connection(connection, customer_gateway_id, static_only, vpn_gateway_id, connection_type, max_attempts, delay, tunnel_options=None):
- """ Creates a VPN connection """
-
- options = {'StaticRoutesOnly': static_only}
+ if connections["VpnConnections"][0]["State"] not in ("deleted", "deleting"):
+ return connections["VpnConnections"][0]
+
+
+def create_connection(
+ connection,
+ customer_gateway_id,
+ static_only,
+ vpn_gateway_id,
+ transit_gateway_id,
+ connection_type,
+ max_attempts,
+ delay,
+ tunnel_options=None,
+):
+ """Creates a VPN connection"""
+
+ options = {"StaticRoutesOnly": static_only}
if tunnel_options and len(tunnel_options) <= 2:
t_opt = []
for m in tunnel_options:
@@ -498,108 +542,106 @@ def create_connection(connection, customer_gateway_id, static_only, vpn_gateway_
raise TypeError("non-dict list member")
t_opt.append(m)
if t_opt:
- options['TunnelOptions'] = t_opt
+ options["TunnelOptions"] = t_opt
+
+ if not (customer_gateway_id and (vpn_gateway_id or transit_gateway_id)):
+ raise VPNConnectionException(
+ msg=(
+ "No matching connection was found. To create a new connection you must provide "
+ "customer_gateway_id and one of either transit_gateway_id or vpn_gateway_id."
+ )
+ )
+ vpn_connection_params = {"Type": connection_type, "CustomerGatewayId": customer_gateway_id, "Options": options}
+ if vpn_gateway_id:
+ vpn_connection_params["VpnGatewayId"] = vpn_gateway_id
+ if transit_gateway_id:
+ vpn_connection_params["TransitGatewayId"] = transit_gateway_id
- if not (customer_gateway_id and vpn_gateway_id):
- raise VPNConnectionException(msg="No matching connection was found. To create a new connection you must provide "
- "both vpn_gateway_id and customer_gateway_id.")
try:
- vpn = connection.create_vpn_connection(Type=connection_type,
- CustomerGatewayId=customer_gateway_id,
- VpnGatewayId=vpn_gateway_id,
- Options=options)
- connection.get_waiter('vpn_connection_available').wait(
- VpnConnectionIds=[vpn['VpnConnection']['VpnConnectionId']],
- WaiterConfig={'Delay': delay, 'MaxAttempts': max_attempts}
+ vpn = connection.create_vpn_connection(**vpn_connection_params)
+ connection.get_waiter("vpn_connection_available").wait(
+ VpnConnectionIds=[vpn["VpnConnection"]["VpnConnectionId"]],
+ WaiterConfig={"Delay": delay, "MaxAttempts": max_attempts},
)
except WaiterError as e:
- raise VPNConnectionException(msg="Failed to wait for VPN connection {0} to be available".format(vpn['VpnConnection']['VpnConnectionId']),
- exception=e)
+ raise VPNConnectionException(
+ msg=f"Failed to wait for VPN connection {vpn['VpnConnection']['VpnConnectionId']} to be available",
+ exception=e,
+ )
except (BotoCoreError, ClientError) as e:
- raise VPNConnectionException(msg="Failed to create VPN connection",
- exception=e)
+ raise VPNConnectionException(msg="Failed to create VPN connection", exception=e)
- return vpn['VpnConnection']
+ return vpn["VpnConnection"]
def delete_connection(connection, vpn_connection_id, delay, max_attempts):
- """ Deletes a VPN connection """
+ """Deletes a VPN connection"""
try:
connection.delete_vpn_connection(aws_retry=True, VpnConnectionId=vpn_connection_id)
- connection.get_waiter('vpn_connection_deleted').wait(
- VpnConnectionIds=[vpn_connection_id],
- WaiterConfig={'Delay': delay, 'MaxAttempts': max_attempts}
+ connection.get_waiter("vpn_connection_deleted").wait(
+ VpnConnectionIds=[vpn_connection_id], WaiterConfig={"Delay": delay, "MaxAttempts": max_attempts}
)
except WaiterError as e:
- raise VPNConnectionException(msg="Failed to wait for VPN connection {0} to be removed".format(vpn_connection_id),
- exception=e)
+ raise VPNConnectionException(
+ msg=f"Failed to wait for VPN connection {vpn_connection_id} to be removed", exception=e
+ )
except (BotoCoreError, ClientError) as e:
- raise VPNConnectionException(msg="Failed to delete the VPN connection: {0}".format(vpn_connection_id),
- exception=e)
+ raise VPNConnectionException(msg=f"Failed to delete the VPN connection: {vpn_connection_id}", exception=e)
def add_tags(connection, vpn_connection_id, add):
try:
- connection.create_tags(aws_retry=True,
- Resources=[vpn_connection_id],
- Tags=add)
+ connection.create_tags(aws_retry=True, Resources=[vpn_connection_id], Tags=add)
except (BotoCoreError, ClientError) as e:
- raise VPNConnectionException(msg="Failed to add the tags: {0}.".format(add),
- exception=e)
+ raise VPNConnectionException(msg=f"Failed to add the tags: {add}.", exception=e)
def remove_tags(connection, vpn_connection_id, remove):
# format tags since they are a list in the format ['tag1', 'tag2', 'tag3']
- key_dict_list = [{'Key': tag} for tag in remove]
+ key_dict_list = [{"Key": tag} for tag in remove]
try:
- connection.delete_tags(aws_retry=True,
- Resources=[vpn_connection_id],
- Tags=key_dict_list)
+ connection.delete_tags(aws_retry=True, Resources=[vpn_connection_id], Tags=key_dict_list)
except (BotoCoreError, ClientError) as e:
- raise VPNConnectionException(msg="Failed to remove the tags: {0}.".format(remove),
- exception=e)
+ raise VPNConnectionException(msg=f"Failed to remove the tags: {remove}.", exception=e)
def check_for_update(connection, module_params, vpn_connection_id):
- """ Determines if there are any tags or routes that need to be updated. Ensures non-modifiable attributes aren't expected to change. """
- tags = module_params.get('tags')
- routes = module_params.get('routes')
- purge_tags = module_params.get('purge_tags')
- purge_routes = module_params.get('purge_routes')
+ """Determines if there are any tags or routes that need to be updated. Ensures non-modifiable attributes aren't expected to change."""
+ tags = module_params.get("tags")
+ routes = module_params.get("routes")
+ purge_tags = module_params.get("purge_tags")
+ purge_routes = module_params.get("purge_routes")
vpn_connection = find_connection(connection, module_params, vpn_connection_id=vpn_connection_id)
current_attrs = camel_dict_to_snake_dict(vpn_connection)
# Initialize changes dict
- changes = {'tags_to_add': [],
- 'tags_to_remove': [],
- 'routes_to_add': [],
- 'routes_to_remove': []}
+ changes = {"tags_to_add": [], "tags_to_remove": [], "routes_to_add": [], "routes_to_remove": []}
# Get changes to tags
- current_tags = boto3_tag_list_to_ansible_dict(current_attrs.get('tags', []), u'key', u'value')
+ current_tags = boto3_tag_list_to_ansible_dict(current_attrs.get("tags", []), "key", "value")
if tags is None:
- changes['tags_to_remove'] = []
- changes['tags_to_add'] = []
+ changes["tags_to_remove"] = []
+ changes["tags_to_add"] = []
else:
- tags_to_add, changes['tags_to_remove'] = compare_aws_tags(current_tags, tags, purge_tags)
- changes['tags_to_add'] = ansible_dict_to_boto3_tag_list(tags_to_add)
+ tags_to_add, changes["tags_to_remove"] = compare_aws_tags(current_tags, tags, purge_tags)
+ changes["tags_to_add"] = ansible_dict_to_boto3_tag_list(tags_to_add)
# Get changes to routes
- if 'Routes' in vpn_connection:
- current_routes = [route['DestinationCidrBlock'] for route in vpn_connection['Routes']]
+ if "Routes" in vpn_connection:
+ current_routes = [route["DestinationCidrBlock"] for route in vpn_connection["Routes"]]
if purge_routes:
- changes['routes_to_remove'] = [old_route for old_route in current_routes if old_route not in routes]
- changes['routes_to_add'] = [new_route for new_route in routes if new_route not in current_routes]
+ changes["routes_to_remove"] = [old_route for old_route in current_routes if old_route not in routes]
+ changes["routes_to_add"] = [new_route for new_route in routes if new_route not in current_routes]
# Check if nonmodifiable attributes are attempted to be modified
for attribute in current_attrs:
if attribute in ("tags", "routes", "state"):
continue
- elif attribute == 'options':
- will_be = module_params.get('static_only', None)
- is_now = bool(current_attrs[attribute]['static_routes_only'])
- attribute = 'static_only'
- elif attribute == 'type':
+ elif attribute == "options":
+ will_be = module_params.get("static_only", None)
+ is_now = bool(current_attrs[attribute]["static_routes_only"])
+ attribute = "static_only"
+ elif attribute == "type":
will_be = module_params.get("connection_type", None)
is_now = current_attrs[attribute]
else:
@@ -607,110 +649,118 @@ def check_for_update(connection, module_params, vpn_connection_id):
will_be = module_params.get(attribute, None)
if will_be is not None and to_text(will_be) != to_text(is_now):
- raise VPNConnectionException(msg="You cannot modify {0}, the current value of which is {1}. Modifiable VPN "
- "connection attributes are tags and routes. The value you tried to change it to "
- "is {2}.".format(attribute, is_now, will_be))
+ raise VPNConnectionException(
+ msg=(
+ f"You cannot modify {attribute}, the current value of which is {is_now}. Modifiable VPN connection"
+ f" attributes are tags and routes. The value you tried to change it to is {will_be}."
+ )
+ )
return changes
def make_changes(connection, vpn_connection_id, changes):
- """ changes is a dict with the keys 'tags_to_add', 'tags_to_remove', 'routes_to_add', 'routes_to_remove',
- the values of which are lists (generated by check_for_update()).
+ """changes is a dict with the keys 'tags_to_add', 'tags_to_remove', 'routes_to_add', 'routes_to_remove',
+ the values of which are lists (generated by check_for_update()).
"""
changed = False
- if changes['tags_to_add']:
+ if changes["tags_to_add"]:
changed = True
- add_tags(connection, vpn_connection_id, changes['tags_to_add'])
+ add_tags(connection, vpn_connection_id, changes["tags_to_add"])
- if changes['tags_to_remove']:
+ if changes["tags_to_remove"]:
changed = True
- remove_tags(connection, vpn_connection_id, changes['tags_to_remove'])
+ remove_tags(connection, vpn_connection_id, changes["tags_to_remove"])
- if changes['routes_to_add']:
+ if changes["routes_to_add"]:
changed = True
- add_routes(connection, vpn_connection_id, changes['routes_to_add'])
+ add_routes(connection, vpn_connection_id, changes["routes_to_add"])
- if changes['routes_to_remove']:
+ if changes["routes_to_remove"]:
changed = True
- remove_routes(connection, vpn_connection_id, changes['routes_to_remove'])
+ remove_routes(connection, vpn_connection_id, changes["routes_to_remove"])
return changed
def get_check_mode_results(connection, module_params, vpn_connection_id=None, current_state=None):
- """ Returns the changes that would be made to a VPN Connection """
- state = module_params.get('state')
- if state == 'absent':
+ """Returns the changes that would be made to a VPN Connection"""
+ state = module_params.get("state")
+ if state == "absent":
if vpn_connection_id:
return True, {}
else:
return False, {}
changed = False
- results = {'customer_gateway_configuration': '',
- 'customer_gateway_id': module_params.get('customer_gateway_id'),
- 'vpn_gateway_id': module_params.get('vpn_gateway_id'),
- 'options': {'static_routes_only': module_params.get('static_only')},
- 'routes': [module_params.get('routes')]}
+ results = {
+ "customer_gateway_configuration": "",
+ "customer_gateway_id": module_params.get("customer_gateway_id"),
+ "vpn_gateway_id": module_params.get("vpn_gateway_id"),
+ "transit_gateway_id": module_params.get("transit_gateway_id"),
+ "options": {"static_routes_only": module_params.get("static_only")},
+ "routes": [module_params.get("routes")],
+ }
# get combined current tags and tags to set
- present_tags = module_params.get('tags')
+ present_tags = module_params.get("tags")
if present_tags is None:
pass
- elif current_state and 'Tags' in current_state:
- current_tags = boto3_tag_list_to_ansible_dict(current_state['Tags'])
- tags_to_add, tags_to_remove = compare_aws_tags(current_tags, present_tags, module_params.get('purge_tags'))
+ elif current_state and "Tags" in current_state:
+ current_tags = boto3_tag_list_to_ansible_dict(current_state["Tags"])
+ tags_to_add, tags_to_remove = compare_aws_tags(current_tags, present_tags, module_params.get("purge_tags"))
changed |= bool(tags_to_remove) or bool(tags_to_add)
- if module_params.get('purge_tags'):
+ if module_params.get("purge_tags"):
current_tags = {}
current_tags.update(present_tags)
- results['tags'] = current_tags
- elif module_params.get('tags'):
+ results["tags"] = current_tags
+ elif module_params.get("tags"):
changed = True
if present_tags:
- results['tags'] = present_tags
+ results["tags"] = present_tags
# get combined current routes and routes to add
- present_routes = module_params.get('routes')
- if current_state and 'Routes' in current_state:
- current_routes = [route['DestinationCidrBlock'] for route in current_state['Routes']]
- if module_params.get('purge_routes'):
+ present_routes = module_params.get("routes")
+ if current_state and "Routes" in current_state:
+ current_routes = [route["DestinationCidrBlock"] for route in current_state["Routes"]]
+ if module_params.get("purge_routes"):
if set(current_routes) != set(present_routes):
changed = True
elif set(present_routes) != set(current_routes):
if not set(present_routes) < set(current_routes):
changed = True
present_routes.extend([route for route in current_routes if route not in present_routes])
- elif module_params.get('routes'):
+ elif module_params.get("routes"):
changed = True
- results['routes'] = [{"destination_cidr_block": cidr, "state": "available"} for cidr in present_routes]
+ results["routes"] = [{"destination_cidr_block": cidr, "state": "available"} for cidr in present_routes]
# return the vpn_connection_id if it's known
if vpn_connection_id:
- results['vpn_connection_id'] = vpn_connection_id
+ results["vpn_connection_id"] = vpn_connection_id
else:
changed = True
- results['vpn_connection_id'] = 'vpn-XXXXXXXX'
+ results["vpn_connection_id"] = "vpn-XXXXXXXX"
return changed, results
def ensure_present(connection, module_params, check_mode=False):
- """ Creates and adds tags to a VPN connection. If the connection already exists update tags. """
+ """Creates and adds tags to a VPN connection. If the connection already exists update tags."""
vpn_connection = find_connection(connection, module_params)
changed = False
- delay = module_params.get('delay')
- max_attempts = module_params.get('wait_timeout') // delay
+ delay = module_params.get("delay")
+ max_attempts = module_params.get("wait_timeout") // delay
# No match but vpn_connection_id was specified.
- if not vpn_connection and module_params.get('vpn_connection_id'):
- raise VPNConnectionException(msg="There is no VPN connection available or pending with that id. Did you delete it?")
+ if not vpn_connection and module_params.get("vpn_connection_id"):
+ raise VPNConnectionException(
+ msg="There is no VPN connection available or pending with that id. Did you delete it?"
+ )
# Unique match was found. Check if attributes provided differ.
elif vpn_connection:
- vpn_connection_id = vpn_connection['VpnConnectionId']
+ vpn_connection_id = vpn_connection["VpnConnectionId"]
# check_for_update returns a dict with the keys tags_to_add, tags_to_remove, routes_to_add, routes_to_remove
changes = check_for_update(connection, module_params, vpn_connection_id)
if check_mode:
@@ -722,38 +772,43 @@ def ensure_present(connection, module_params, check_mode=False):
changed = True
if check_mode:
return get_check_mode_results(connection, module_params)
- vpn_connection = create_connection(connection,
- customer_gateway_id=module_params.get('customer_gateway_id'),
- static_only=module_params.get('static_only'),
- vpn_gateway_id=module_params.get('vpn_gateway_id'),
- connection_type=module_params.get('connection_type'),
- tunnel_options=module_params.get('tunnel_options'),
- max_attempts=max_attempts,
- delay=delay)
- changes = check_for_update(connection, module_params, vpn_connection['VpnConnectionId'])
- make_changes(connection, vpn_connection['VpnConnectionId'], changes)
+ vpn_connection = create_connection(
+ connection,
+ customer_gateway_id=module_params.get("customer_gateway_id"),
+ static_only=module_params.get("static_only"),
+ vpn_gateway_id=module_params.get("vpn_gateway_id"),
+ transit_gateway_id=module_params.get("transit_gateway_id"),
+ connection_type=module_params.get("connection_type"),
+ tunnel_options=module_params.get("tunnel_options"),
+ max_attempts=max_attempts,
+ delay=delay,
+ )
+ changes = check_for_update(connection, module_params, vpn_connection["VpnConnectionId"])
+ make_changes(connection, vpn_connection["VpnConnectionId"], changes)
# get latest version if a change has been made and make tags output nice before returning it
if vpn_connection:
- vpn_connection = find_connection(connection, module_params, vpn_connection['VpnConnectionId'])
- if 'Tags' in vpn_connection:
- vpn_connection['Tags'] = boto3_tag_list_to_ansible_dict(vpn_connection['Tags'])
+ vpn_connection = find_connection(connection, module_params, vpn_connection["VpnConnectionId"])
+ if "Tags" in vpn_connection:
+ vpn_connection["Tags"] = boto3_tag_list_to_ansible_dict(vpn_connection["Tags"])
return changed, vpn_connection
def ensure_absent(connection, module_params, check_mode=False):
- """ Deletes a VPN connection if it exists. """
+ """Deletes a VPN connection if it exists."""
vpn_connection = find_connection(connection, module_params)
if check_mode:
- return get_check_mode_results(connection, module_params, vpn_connection['VpnConnectionId'] if vpn_connection else None)
+ return get_check_mode_results(
+ connection, module_params, vpn_connection["VpnConnectionId"] if vpn_connection else None
+ )
- delay = module_params.get('delay')
- max_attempts = module_params.get('wait_timeout') // delay
+ delay = module_params.get("delay")
+ max_attempts = module_params.get("wait_timeout") // delay
if vpn_connection:
- delete_connection(connection, vpn_connection['VpnConnectionId'], delay=delay, max_attempts=max_attempts)
+ delete_connection(connection, vpn_connection["VpnConnectionId"], delay=delay, max_attempts=max_attempts)
changed = True
else:
changed = False
@@ -763,32 +818,40 @@ def ensure_absent(connection, module_params, check_mode=False):
def main():
argument_spec = dict(
- state=dict(type='str', default='present', choices=['present', 'absent']),
- filters=dict(type='dict', default={}),
- vpn_gateway_id=dict(type='str'),
- tags=dict(type='dict', aliases=['resource_tags']),
- connection_type=dict(default='ipsec.1', type='str'),
- tunnel_options=dict(no_log=True, type='list', default=[], elements='dict'),
- static_only=dict(default=False, type='bool'),
- customer_gateway_id=dict(type='str'),
- vpn_connection_id=dict(type='str'),
- purge_tags=dict(type='bool', default=True),
- routes=dict(type='list', default=[], elements='str'),
- purge_routes=dict(type='bool', default=False),
- wait_timeout=dict(type='int', default=600),
- delay=dict(type='int', default=15),
+ state=dict(type="str", default="present", choices=["present", "absent"]),
+ filters=dict(type="dict", default={}),
+ vpn_gateway_id=dict(type="str"),
+ tags=dict(type="dict", aliases=["resource_tags"]),
+ connection_type=dict(default="ipsec.1", type="str"),
+ transit_gateway_id=dict(type="str"),
+ tunnel_options=dict(no_log=True, type="list", default=[], elements="dict"),
+ static_only=dict(default=False, type="bool"),
+ customer_gateway_id=dict(type="str"),
+ vpn_connection_id=dict(type="str"),
+ purge_tags=dict(type="bool", default=True),
+ routes=dict(type="list", default=[], elements="str"),
+ purge_routes=dict(type="bool", default=False),
+ wait_timeout=dict(type="int", default=600),
+ delay=dict(type="int", default=15),
+ )
+ mutually_exclusive = [
+ ["vpn_gateway_id", "transit_gateway_id"],
+ ]
+
+ module = AnsibleAWSModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ mutually_exclusive=mutually_exclusive,
)
- module = AnsibleAWSModule(argument_spec=argument_spec,
- supports_check_mode=True)
- connection = module.client('ec2', retry_decorator=VPNRetry.jittered_backoff(retries=10))
+ connection = module.client("ec2", retry_decorator=VPNRetry.jittered_backoff(retries=10))
- state = module.params.get('state')
+ state = module.params.get("state")
parameters = dict(module.params)
try:
- if state == 'present':
+ if state == "present":
changed, response = ensure_present(connection, parameters, module.check_mode)
- elif state == 'absent':
+ elif state == "absent":
changed, response = ensure_absent(connection, parameters, module.check_mode)
except VPNConnectionException as e:
if e.exception:
@@ -799,5 +862,5 @@ def main():
module.exit_json(changed=changed, **camel_dict_to_snake_dict(response))
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/ec2_vpc_vpn_info.py b/ansible_collections/community/aws/plugins/modules/ec2_vpc_vpn_info.py
index c7a71f154..d304e4568 100644
--- a/ansible_collections/community/aws/plugins/modules/ec2_vpc_vpn_info.py
+++ b/ansible_collections/community/aws/plugins/modules/ec2_vpc_vpn_info.py
@@ -1,19 +1,18 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: ec2_vpc_vpn_info
version_added: 1.0.0
short_description: Gather information about VPN Connections in AWS.
description:
- - Gather information about VPN Connections in AWS.
-author: Madhura Naniwadekar (@Madhura-CSI)
+ - Gather information about VPN Connections in AWS.
+author:
+ - Madhura Naniwadekar (@Madhura-CSI)
options:
filters:
description:
@@ -30,13 +29,12 @@ options:
elements: str
default: []
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-'''
-
-EXAMPLES = r'''
+EXAMPLES = r"""
# # Note: These examples do not set authentication details, see the AWS Guide for details.
- name: Gather information about all vpn connections
community.aws.ec2_vpc_vpn_info:
@@ -52,9 +50,9 @@ EXAMPLES = r'''
filters:
vpn-gateway-id: vgw-cbe66beb
register: vpn_conn_info
-'''
+"""
-RETURN = r'''
+RETURN = r"""
vpn_connections:
description: List of one or more VPN Connections.
returned: always
@@ -158,30 +156,33 @@ vpn_connections:
returned: always
type: str
sample: vgw-cbe56bfb
-'''
+"""
import json
+
try:
- from botocore.exceptions import ClientError, BotoCoreError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
except ImportError:
pass # caught by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import (ansible_dict_to_boto3_filter_list,
- boto3_tag_list_to_ansible_dict,
- camel_dict_to_snake_dict,
- )
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.transformation import ansible_dict_to_boto3_filter_list
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def date_handler(obj):
- return obj.isoformat() if hasattr(obj, 'isoformat') else obj
+ return obj.isoformat() if hasattr(obj, "isoformat") else obj
def list_vpn_connections(connection, module):
params = dict()
- params['Filters'] = ansible_dict_to_boto3_filter_list(module.params.get('filters'))
- params['VpnConnectionIds'] = module.params.get('vpn_connection_ids')
+ params["Filters"] = ansible_dict_to_boto3_filter_list(module.params.get("filters"))
+ params["VpnConnectionIds"] = module.params.get("vpn_connection_ids")
try:
result = json.loads(json.dumps(connection.describe_vpn_connections(**params), default=date_handler))
@@ -189,28 +190,29 @@ def list_vpn_connections(connection, module):
module.fail_json_aws(e, msg="Cannot validate JSON data")
except (ClientError, BotoCoreError) as e:
module.fail_json_aws(e, msg="Could not describe customer gateways")
- snaked_vpn_connections = [camel_dict_to_snake_dict(vpn_connection) for vpn_connection in result['VpnConnections']]
+ snaked_vpn_connections = [camel_dict_to_snake_dict(vpn_connection) for vpn_connection in result["VpnConnections"]]
if snaked_vpn_connections:
for vpn_connection in snaked_vpn_connections:
- vpn_connection['tags'] = boto3_tag_list_to_ansible_dict(vpn_connection.get('tags', []))
+ vpn_connection["tags"] = boto3_tag_list_to_ansible_dict(vpn_connection.get("tags", []))
module.exit_json(changed=False, vpn_connections=snaked_vpn_connections)
def main():
-
argument_spec = dict(
- vpn_connection_ids=dict(default=[], type='list', elements='str'),
- filters=dict(default={}, type='dict')
+ vpn_connection_ids=dict(default=[], type="list", elements="str"),
+ filters=dict(default={}, type="dict"),
)
- module = AnsibleAWSModule(argument_spec=argument_spec,
- mutually_exclusive=[['vpn_connection_ids', 'filters']],
- supports_check_mode=True)
+ module = AnsibleAWSModule(
+ argument_spec=argument_spec,
+ mutually_exclusive=[["vpn_connection_ids", "filters"]],
+ supports_check_mode=True,
+ )
- connection = module.client('ec2')
+ connection = module.client("ec2")
list_vpn_connections(connection, module)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/ec2_win_password.py b/ansible_collections/community/aws/plugins/modules/ec2_win_password.py
index 9b92c3e4f..a9ca8e94c 100644
--- a/ansible_collections/community/aws/plugins/modules/ec2_win_password.py
+++ b/ansible_collections/community/aws/plugins/modules/ec2_win_password.py
@@ -1,19 +1,18 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: ec2_win_password
version_added: 1.0.0
short_description: Gets the default administrator password for EC2 Windows instances
description:
- - Gets the default administrator password from any EC2 Windows instance. The instance is referenced by its id (e.g. C(i-XXXXXXX)).
-author: "Rick Mendes (@rickmendes)"
+ - Gets the default administrator password from any EC2 Windows instance. The instance is referenced by its id (e.g. C(i-XXXXXXX)).
+author:
+ - "Rick Mendes (@rickmendes)"
options:
instance_id:
description:
@@ -48,16 +47,18 @@ options:
default: 120
type: int
+requirements:
+ - cryptography
+
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-requirements:
-- cryptography
-'''
+RETURN = r""" # """
-EXAMPLES = '''
+EXAMPLES = r"""
# Example of getting a password
- name: get the Administrator password
community.aws.ec2_win_password:
@@ -92,7 +93,7 @@ EXAMPLES = '''
key_file: "~/aws-creds/my_test_key.pem"
wait: true
wait_timeout: 45
-'''
+"""
import datetime
import time
@@ -102,6 +103,7 @@ try:
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric.padding import PKCS1v15
from cryptography.hazmat.primitives.serialization import load_pem_private_key
+
HAS_CRYPTOGRAPHY = True
except ImportError:
HAS_CRYPTOGRAPHY = False
@@ -113,47 +115,48 @@ except ImportError:
from ansible.module_utils._text import to_bytes
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def setup_module_object():
argument_spec = dict(
instance_id=dict(required=True),
- key_file=dict(required=False, default=None, type='path'),
+ key_file=dict(required=False, default=None, type="path"),
key_passphrase=dict(no_log=True, default=None, required=False),
key_data=dict(no_log=True, default=None, required=False),
- wait=dict(type='bool', default=False, required=False),
- wait_timeout=dict(default=120, required=False, type='int'),
+ wait=dict(type="bool", default=False, required=False),
+ wait_timeout=dict(default=120, required=False, type="int"),
)
- mutually_exclusive = [['key_file', 'key_data']]
+ mutually_exclusive = [["key_file", "key_data"]]
module = AnsibleAWSModule(argument_spec=argument_spec, mutually_exclusive=mutually_exclusive)
return module
def _get_password(module, client, instance_id):
try:
- data = client.get_password_data(aws_retry=True, InstanceId=instance_id)['PasswordData']
+ data = client.get_password_data(aws_retry=True, InstanceId=instance_id)["PasswordData"]
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
- module.fail_json_aws(e, msg='Failed to get password data')
+ module.fail_json_aws(e, msg="Failed to get password data")
return data
def ec2_win_password(module):
- instance_id = module.params.get('instance_id')
- key_file = module.params.get('key_file')
- if module.params.get('key_passphrase') is None:
+ instance_id = module.params.get("instance_id")
+ key_file = module.params.get("key_file")
+ if module.params.get("key_passphrase") is None:
b_key_passphrase = None
else:
- b_key_passphrase = to_bytes(module.params.get('key_passphrase'), errors='surrogate_or_strict')
- if module.params.get('key_data') is None:
+ b_key_passphrase = to_bytes(module.params.get("key_passphrase"), errors="surrogate_or_strict")
+ if module.params.get("key_data") is None:
b_key_data = None
else:
- b_key_data = to_bytes(module.params.get('key_data'), errors='surrogate_or_strict')
- wait = module.params.get('wait')
- wait_timeout = module.params.get('wait_timeout')
+ b_key_data = to_bytes(module.params.get("key_data"), errors="surrogate_or_strict")
+ wait = module.params.get("wait")
+ wait_timeout = module.params.get("wait_timeout")
- client = module.client('ec2', retry_decorator=AWSRetry.jittered_backoff())
+ client = module.client("ec2", retry_decorator=AWSRetry.jittered_backoff())
if wait:
start = datetime.datetime.now()
@@ -171,15 +174,15 @@ def ec2_win_password(module):
decoded = b64decode(data)
if wait and datetime.datetime.now() >= end:
- module.fail_json(msg="wait for password timeout after %d seconds" % wait_timeout)
+ module.fail_json(msg=f"wait for password timeout after {int(wait_timeout)} seconds")
if key_file is not None and b_key_data is None:
try:
- with open(key_file, 'rb') as f:
+ with open(key_file, "rb") as f:
key = load_pem_private_key(f.read(), b_key_passphrase, default_backend())
except IOError as e:
# Handle bad files
- module.fail_json(msg="I/O error (%d) opening key file: %s" % (e.errno, e.strerror))
+ module.fail_json(msg=f"I/O error ({int(e.errno)}) opening key file: {e.strerror}")
except (ValueError, TypeError) as e:
# Handle issues loading key
module.fail_json(msg="unable to parse key file")
@@ -195,7 +198,7 @@ def ec2_win_password(module):
decrypted = None
if decrypted is None:
- module.fail_json(msg="unable to decrypt password", win_password='', changed=False)
+ module.fail_json(msg="unable to decrypt password", win_password="", changed=False)
else:
if wait:
elapsed = datetime.datetime.now() - start
@@ -208,10 +211,10 @@ def main():
module = setup_module_object()
if not HAS_CRYPTOGRAPHY:
- module.fail_json(msg='cryptography package required for this module.')
+ module.fail_json(msg="cryptography package required for this module.")
ec2_win_password(module)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/ecs_attribute.py b/ansible_collections/community/aws/plugins/modules/ecs_attribute.py
index 6efe701d1..682014675 100644
--- a/ansible_collections/community/aws/plugins/modules/ecs_attribute.py
+++ b/ansible_collections/community/aws/plugins/modules/ecs_attribute.py
@@ -1,19 +1,18 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: ecs_attribute
version_added: 1.0.0
short_description: manage ecs attributes
description:
- - Create, update or delete ECS container instance attributes.
-author: Andrej Svenke (@anryko)
+ - Create, update or delete ECS container instance attributes.
+author:
+ - Andrej Svenke (@anryko)
options:
cluster:
description:
@@ -54,13 +53,12 @@ options:
required: true
type: str
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
-
-'''
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide for details.
- name: Set attributes
@@ -82,9 +80,9 @@ EXAMPLES = r'''
- flavor: test
- migrated
delegate_to: localhost
-'''
+"""
-RETURN = r'''
+RETURN = r"""
attributes:
description: attributes
type: complex
@@ -108,15 +106,16 @@ attributes:
description: value of the attribute
returned: if present
type: str
-'''
+"""
try:
import botocore
- from botocore.exceptions import ClientError, EndpointConnectionError
+ from botocore.exceptions import ClientError
+ from botocore.exceptions import EndpointConnectionError
except ImportError:
pass # Handled by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
class EcsAttributes(object):
@@ -136,29 +135,27 @@ class EcsAttributes(object):
@staticmethod
def _validate_attrs(attrs):
- return all(tuple(attr.keys()) in (('name', 'value'), ('value', 'name')) for attr in attrs)
+ return all(tuple(attr.keys()) in (("name", "value"), ("value", "name")) for attr in attrs)
def _parse_attrs(self, attrs):
attrs_parsed = []
for attr in attrs:
if isinstance(attr, dict):
if len(attr) != 1:
- self.module.fail_json(msg="Incorrect attribute format - %s" % str(attr))
+ self.module.fail_json(msg=f"Incorrect attribute format - {str(attr)}")
name, value = list(attr.items())[0]
- attrs_parsed.append({'name': name, 'value': value})
+ attrs_parsed.append({"name": name, "value": value})
elif isinstance(attr, str):
- attrs_parsed.append({'name': attr, 'value': None})
+ attrs_parsed.append({"name": attr, "value": None})
else:
- self.module.fail_json(msg="Incorrect attributes format - %s" % str(attrs))
+ self.module.fail_json(msg=f"Incorrect attributes format - {str(attrs)}")
return attrs_parsed
def _setup_attr_obj(self, ecs_arn, name, value=None, skip_value=False):
- attr_obj = {'targetType': 'container-instance',
- 'targetId': ecs_arn,
- 'name': name}
+ attr_obj = {"targetType": "container-instance", "targetId": ecs_arn, "name": name}
if not skip_value and value is not None:
- attr_obj['value'] = value
+ attr_obj["value"] = value
return attr_obj
@@ -187,41 +184,43 @@ class Ec2EcsInstance(object):
self.ec2_id = ec2_id
try:
- self.ecs = module.client('ecs')
+ self.ecs = module.client("ecs")
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to connect to AWS')
+ module.fail_json_aws(e, msg="Failed to connect to AWS")
self.ecs_arn = self._get_ecs_arn()
def _get_ecs_arn(self):
try:
- ecs_instances_arns = self.ecs.list_container_instances(cluster=self.cluster)['containerInstanceArns']
- ec2_instances = self.ecs.describe_container_instances(cluster=self.cluster,
- containerInstances=ecs_instances_arns)['containerInstances']
+ ecs_instances_arns = self.ecs.list_container_instances(cluster=self.cluster)["containerInstanceArns"]
+ ec2_instances = self.ecs.describe_container_instances(
+ cluster=self.cluster, containerInstances=ecs_instances_arns
+ )["containerInstances"]
except (ClientError, EndpointConnectionError) as e:
- self.module.fail_json(msg="Can't connect to the cluster - %s" % str(e))
+ self.module.fail_json(msg=f"Can't connect to the cluster - {str(e)}")
try:
- ecs_arn = next(inst for inst in ec2_instances
- if inst['ec2InstanceId'] == self.ec2_id)['containerInstanceArn']
+ ecs_arn = next(inst for inst in ec2_instances if inst["ec2InstanceId"] == self.ec2_id)[
+ "containerInstanceArn"
+ ]
except StopIteration:
- self.module.fail_json(msg="EC2 instance Id not found in ECS cluster - %s" % str(self.cluster))
+ self.module.fail_json(msg=f"EC2 instance Id not found in ECS cluster - {str(self.cluster)}")
return ecs_arn
def attrs_put(self, attrs):
"""Puts attributes on ECS container instance"""
try:
- self.ecs.put_attributes(cluster=self.cluster,
- attributes=attrs.get_for_ecs_arn(self.ecs_arn))
+ self.ecs.put_attributes(cluster=self.cluster, attributes=attrs.get_for_ecs_arn(self.ecs_arn))
except ClientError as e:
self.module.fail_json(msg=str(e))
def attrs_delete(self, attrs):
"""Deletes attributes from ECS container instance."""
try:
- self.ecs.delete_attributes(cluster=self.cluster,
- attributes=attrs.get_for_ecs_arn(self.ecs_arn, skip_value=True))
+ self.ecs.delete_attributes(
+ cluster=self.cluster, attributes=attrs.get_for_ecs_arn(self.ecs_arn, skip_value=True)
+ )
except ClientError as e:
self.module.fail_json(msg=str(e))
@@ -230,33 +229,33 @@ class Ec2EcsInstance(object):
Returns EcsAttributes object containing attributes from ECS container instance with names
matching to attrs.attributes (EcsAttributes Object).
"""
- attr_objs = [{'targetType': 'container-instance', 'attributeName': attr['name']}
- for attr in attrs]
+ attr_objs = [{"targetType": "container-instance", "attributeName": attr["name"]} for attr in attrs]
try:
- matched_ecs_targets = [attr_found for attr_obj in attr_objs
- for attr_found in self.ecs.list_attributes(cluster=self.cluster, **attr_obj)['attributes']]
+ matched_ecs_targets = [
+ attr_found
+ for attr_obj in attr_objs
+ for attr_found in self.ecs.list_attributes(cluster=self.cluster, **attr_obj)["attributes"]
+ ]
except ClientError as e:
- self.module.fail_json(msg="Can't connect to the cluster - %s" % str(e))
+ self.module.fail_json(msg=f"Can't connect to the cluster - {str(e)}")
- matched_objs = [target for target in matched_ecs_targets
- if target['targetId'] == self.ecs_arn]
+ matched_objs = [target for target in matched_ecs_targets if target["targetId"] == self.ecs_arn]
- results = [{'name': match['name'], 'value': match.get('value', None)}
- for match in matched_objs]
+ results = [{"name": match["name"], "value": match.get("value", None)} for match in matched_objs]
return EcsAttributes(self.module, results)
def main():
argument_spec = dict(
- state=dict(required=False, default='present', choices=['present', 'absent']),
- cluster=dict(required=True, type='str'),
- ec2_instance_id=dict(required=True, type='str'),
- attributes=dict(required=True, type='list', elements='dict'),
+ state=dict(required=False, default="present", choices=["present", "absent"]),
+ cluster=dict(required=True, type="str"),
+ ec2_instance_id=dict(required=True, type="str"),
+ attributes=dict(required=True, type="list", elements="dict"),
)
- required_together = [['cluster', 'ec2_instance_id', 'attributes']]
+ required_together = [["cluster", "ec2_instance_id", "attributes"]]
module = AnsibleAWSModule(
argument_spec=argument_spec,
@@ -264,39 +263,43 @@ def main():
required_together=required_together,
)
- cluster = module.params['cluster']
- ec2_instance_id = module.params['ec2_instance_id']
- attributes = module.params['attributes']
+ cluster = module.params["cluster"]
+ ec2_instance_id = module.params["ec2_instance_id"]
+ attributes = module.params["attributes"]
conti = Ec2EcsInstance(module, cluster, ec2_instance_id)
attrs = EcsAttributes(module, attributes)
- results = {'changed': False,
- 'attributes': [
- {'cluster': cluster,
- 'ec2_instance_id': ec2_instance_id,
- 'attributes': attributes}
- ]}
+ results = {
+ "changed": False,
+ "attributes": [
+ {
+ "cluster": cluster,
+ "ec2_instance_id": ec2_instance_id,
+ "attributes": attributes,
+ }
+ ],
+ }
attrs_present = conti.attrs_get_by_name(attrs)
- if module.params['state'] == 'present':
+ if module.params["state"] == "present":
attrs_diff = attrs.diff(attrs_present)
if not attrs_diff:
module.exit_json(**results)
conti.attrs_put(attrs_diff)
- results['changed'] = True
+ results["changed"] = True
- elif module.params['state'] == 'absent':
+ elif module.params["state"] == "absent":
if not attrs_present:
module.exit_json(**results)
conti.attrs_delete(attrs_present)
- results['changed'] = True
+ results["changed"] = True
module.exit_json(**results)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/ecs_cluster.py b/ansible_collections/community/aws/plugins/modules/ecs_cluster.py
index 347e2173e..7d427a58d 100644
--- a/ansible_collections/community/aws/plugins/modules/ecs_cluster.py
+++ b/ansible_collections/community/aws/plugins/modules/ecs_cluster.py
@@ -1,22 +1,21 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: ecs_cluster
version_added: 1.0.0
short_description: Create or terminate ECS clusters.
notes:
- - When deleting a cluster, the information returned is the state of the cluster prior to deletion.
- - It will also wait for a cluster to have instances registered to it.
+ - When deleting a cluster, the information returned is the state of the cluster prior to deletion.
+ - It will also wait for a cluster to have instances registered to it.
description:
- - Creates or terminates ecs clusters.
-author: Mark Chance (@Java1Guy)
+ - Creates or terminates ecs clusters.
+author:
+ - Mark Chance (@Java1Guy)
options:
state:
description:
@@ -78,13 +77,12 @@ options:
type: bool
default: false
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
-
-'''
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide for details.
- name: Cluster creation
@@ -105,7 +103,7 @@ EXAMPLES = '''
weight: 1
- capacity_provider: FARGATE_SPOT
weight: 100
- purge_capacity_providers: True
+ purge_capacity_providers: true
- name: Cluster deletion
community.aws.ecs_cluster:
@@ -119,9 +117,9 @@ EXAMPLES = '''
delay: 10
repeat: 10
register: task_output
+"""
-'''
-RETURN = '''
+RETURN = r"""
activeServicesCount:
description: how many services are active in this cluster
returned: 0 if a new cluster
@@ -163,7 +161,7 @@ status:
returned: always
type: str
sample: ACTIVE
-'''
+"""
import time
@@ -172,9 +170,10 @@ try:
except ImportError:
pass # Handled by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible.module_utils.common.dict_transformations import snake_dict_to_camel_dict
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+from ansible.module_utils.common.dict_transformations import snake_dict_to_camel_dict
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
class EcsClusterManager:
@@ -183,76 +182,75 @@ class EcsClusterManager:
def __init__(self, module):
self.module = module
try:
- self.ecs = module.client('ecs')
+ self.ecs = module.client("ecs")
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to connect to AWS')
+ module.fail_json_aws(e, msg="Failed to connect to AWS")
- def find_in_array(self, array_of_clusters, cluster_name, field_name='clusterArn'):
+ def find_in_array(self, array_of_clusters, cluster_name, field_name="clusterArn"):
for c in array_of_clusters:
if c[field_name].endswith(cluster_name):
return c
return None
def describe_cluster(self, cluster_name):
- response = self.ecs.describe_clusters(clusters=[
- cluster_name
- ])
- if len(response['failures']) > 0:
- c = self.find_in_array(response['failures'], cluster_name, 'arn')
- if c and c['reason'] == 'MISSING':
+ response = self.ecs.describe_clusters(clusters=[cluster_name])
+ if len(response["failures"]) > 0:
+ c = self.find_in_array(response["failures"], cluster_name, "arn")
+ if c and c["reason"] == "MISSING":
return None
# fall thru and look through found ones
- if len(response['clusters']) > 0:
- c = self.find_in_array(response['clusters'], cluster_name)
+ if len(response["clusters"]) > 0:
+ c = self.find_in_array(response["clusters"], cluster_name)
if c:
return c
- raise Exception("Unknown problem describing cluster %s." % cluster_name)
+ raise Exception(f"Unknown problem describing cluster {cluster_name}.")
def create_cluster(self, cluster_name, capacity_providers, capacity_provider_strategy):
params = dict(clusterName=cluster_name)
if capacity_providers:
- params['capacityProviders'] = snake_dict_to_camel_dict(capacity_providers)
+ params["capacityProviders"] = snake_dict_to_camel_dict(capacity_providers)
if capacity_provider_strategy:
- params['defaultCapacityProviderStrategy'] = snake_dict_to_camel_dict(capacity_provider_strategy)
+ params["defaultCapacityProviderStrategy"] = snake_dict_to_camel_dict(capacity_provider_strategy)
response = self.ecs.create_cluster(**params)
- return response['cluster']
+ return response["cluster"]
def update_cluster(self, cluster_name, capacity_providers, capacity_provider_strategy):
params = dict(cluster=cluster_name)
if capacity_providers:
- params['capacityProviders'] = snake_dict_to_camel_dict(capacity_providers)
+ params["capacityProviders"] = snake_dict_to_camel_dict(capacity_providers)
else:
- params['capacityProviders'] = []
+ params["capacityProviders"] = []
if capacity_provider_strategy:
- params['defaultCapacityProviderStrategy'] = snake_dict_to_camel_dict(capacity_provider_strategy)
+ params["defaultCapacityProviderStrategy"] = snake_dict_to_camel_dict(capacity_provider_strategy)
else:
- params['defaultCapacityProviderStrategy'] = []
+ params["defaultCapacityProviderStrategy"] = []
response = self.ecs.put_cluster_capacity_providers(**params)
- return response['cluster']
+ return response["cluster"]
def delete_cluster(self, clusterName):
return self.ecs.delete_cluster(cluster=clusterName)
def main():
-
argument_spec = dict(
- state=dict(required=True, choices=['present', 'absent', 'has_instances']),
- name=dict(required=True, type='str'),
- delay=dict(required=False, type='int', default=10),
- repeat=dict(required=False, type='int', default=10),
- purge_capacity_providers=dict(required=False, type='bool', default=False),
- capacity_providers=dict(required=False, type='list', elements='str'),
- capacity_provider_strategy=dict(required=False,
- type='list',
- elements='dict',
- options=dict(capacity_provider=dict(type='str'),
- weight=dict(type='int'),
- base=dict(type='int', default=0)
- )
- ),
+ state=dict(required=True, choices=["present", "absent", "has_instances"]),
+ name=dict(required=True, type="str"),
+ delay=dict(required=False, type="int", default=10),
+ repeat=dict(required=False, type="int", default=10),
+ purge_capacity_providers=dict(required=False, type="bool", default=False),
+ capacity_providers=dict(required=False, type="list", elements="str"),
+ capacity_provider_strategy=dict(
+ required=False,
+ type="list",
+ elements="dict",
+ options=dict(
+ capacity_provider=dict(type="str"),
+ weight=dict(type="int"),
+ base=dict(type="int", default=0),
+ ),
+ ),
)
- required_together = [['state', 'name']]
+ required_together = [["state", "name"]]
module = AnsibleAWSModule(
argument_spec=argument_spec,
@@ -262,19 +260,19 @@ def main():
cluster_mgr = EcsClusterManager(module)
try:
- existing = cluster_mgr.describe_cluster(module.params['name'])
+ existing = cluster_mgr.describe_cluster(module.params["name"])
except Exception as e:
- module.fail_json(msg="Exception describing cluster '" + module.params['name'] + "': " + str(e))
+ module.fail_json(msg="Exception describing cluster '" + module.params["name"] + "': " + str(e))
results = dict(changed=False)
- if module.params['state'] == 'present':
+ if module.params["state"] == "present":
# Pull requested and existing capacity providers and strategies.
- purge_capacity_providers = module.params['purge_capacity_providers']
- requested_cp = module.params['capacity_providers']
- requested_cps = module.params['capacity_provider_strategy']
- if existing and 'status' in existing and existing['status'] == "ACTIVE":
- existing_cp = existing['capacityProviders']
- existing_cps = existing['defaultCapacityProviderStrategy']
+ purge_capacity_providers = module.params["purge_capacity_providers"]
+ requested_cp = module.params["capacity_providers"]
+ requested_cps = module.params["capacity_provider_strategy"]
+ if existing and "status" in existing and existing["status"] == "ACTIVE":
+ existing_cp = existing["capacityProviders"]
+ existing_cps = existing["defaultCapacityProviderStrategy"]
if requested_cp is None:
requested_cp = []
@@ -293,9 +291,12 @@ def main():
# Unless purge_capacity_providers is true, we will not be updating the providers or strategy.
if not purge_capacity_providers:
- module.deprecate('After 2024-06-01 the default value of purge_capacity_providers will change from false to true.'
- ' To maintain the existing behaviour explicitly set purge_capacity_providers=true',
- date='2024-06-01', collection_name='community.aws')
+ module.deprecate(
+ "After 2024-06-01 the default value of purge_capacity_providers will change from false to true."
+ " To maintain the existing behaviour explicitly set purge_capacity_providers=true",
+ date="2024-06-01",
+ collection_name="community.aws",
+ )
cps_update_needed = False
requested_cp = existing_cp
requested_cps = existing_cps
@@ -303,57 +304,67 @@ def main():
# If either the providers or strategy differ, update the cluster.
if requested_cp != existing_cp or cps_update_needed:
if not module.check_mode:
- results['cluster'] = cluster_mgr.update_cluster(cluster_name=module.params['name'],
- capacity_providers=requested_cp,
- capacity_provider_strategy=requested_cps)
- results['changed'] = True
+ results["cluster"] = cluster_mgr.update_cluster(
+ cluster_name=module.params["name"],
+ capacity_providers=requested_cp,
+ capacity_provider_strategy=requested_cps,
+ )
+ results["changed"] = True
else:
- results['cluster'] = existing
+ results["cluster"] = existing
else:
if not module.check_mode:
# doesn't exist. create it.
- results['cluster'] = cluster_mgr.create_cluster(cluster_name=module.params['name'],
- capacity_providers=requested_cp,
- capacity_provider_strategy=requested_cps)
- results['changed'] = True
+ results["cluster"] = cluster_mgr.create_cluster(
+ cluster_name=module.params["name"],
+ capacity_providers=requested_cp,
+ capacity_provider_strategy=requested_cps,
+ )
+ results["changed"] = True
# delete the cluster
- elif module.params['state'] == 'absent':
+ elif module.params["state"] == "absent":
if not existing:
pass
else:
# it exists, so we should delete it and mark changed.
# return info about the cluster deleted
- results['cluster'] = existing
- if 'status' in existing and existing['status'] == "INACTIVE":
- results['changed'] = False
+ results["cluster"] = existing
+ if "status" in existing and existing["status"] == "INACTIVE":
+ results["changed"] = False
else:
if not module.check_mode:
- cluster_mgr.delete_cluster(module.params['name'])
- results['changed'] = True
- elif module.params['state'] == 'has_instances':
+ cluster_mgr.delete_cluster(module.params["name"])
+ results["changed"] = True
+ elif module.params["state"] == "has_instances":
if not existing:
- module.fail_json(msg="Cluster '" + module.params['name'] + " not found.")
+ module.fail_json(msg="Cluster '" + module.params["name"] + " not found.")
return
# it exists, so we should delete it and mark changed.
# return info about the cluster deleted
- delay = module.params['delay']
- repeat = module.params['repeat']
+ delay = module.params["delay"]
+ repeat = module.params["repeat"]
time.sleep(delay)
count = 0
for i in range(repeat):
- existing = cluster_mgr.describe_cluster(module.params['name'])
- count = existing['registeredContainerInstancesCount']
+ existing = cluster_mgr.describe_cluster(module.params["name"])
+ count = existing["registeredContainerInstancesCount"]
if count > 0:
- results['changed'] = True
+ results["changed"] = True
break
time.sleep(delay)
if count == 0 and i is repeat - 1:
- module.fail_json(msg="Cluster instance count still zero after " + str(repeat) + " tries of " + str(delay) + " seconds each.")
+ module.fail_json(
+ msg="Cluster instance count still zero after "
+ + str(repeat)
+ + " tries of "
+ + str(delay)
+ + " seconds each."
+ )
return
module.exit_json(**results)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/ecs_ecr.py b/ansible_collections/community/aws/plugins/modules/ecs_ecr.py
index d83d5af2e..545b82742 100644
--- a/ansible_collections/community/aws/plugins/modules/ecs_ecr.py
+++ b/ansible_collections/community/aws/plugins/modules/ecs_ecr.py
@@ -1,15 +1,10 @@
#!/usr/bin/python
-# -*- coding: utf-8 -*
+# -*- coding: utf-8 -*-
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: ecs_ecr
version_added: 1.0.0
@@ -104,15 +99,14 @@ options:
type: dict
version_added: 5.2.0
author:
- - David M. Lee (@leedm777)
+ - David M. Lee (@leedm777)
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
-
-'''
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
# If the repository does not exist, it is created. If it does exist, would not
# affect any policies already on it.
- name: ecr-repo
@@ -186,9 +180,9 @@ EXAMPLES = '''
encryption_configuration:
encryption_type: KMS
kms_key: custom-kms-key-alias
-'''
+"""
-RETURN = '''
+RETURN = r"""
state:
type: str
description: The asserted state of the repository (present, absent)
@@ -216,7 +210,7 @@ repository:
repositoryArn: arn:aws:ecr:us-east-1:123456789012:repository/ecr-test-1484664090
repositoryName: ecr-test-1484664090
repositoryUri: 123456789012.dkr.ecr.us-east-1.amazonaws.com/ecr-test-1484664090
-'''
+"""
import json
import traceback
@@ -229,11 +223,11 @@ except ImportError:
from ansible.module_utils.common.dict_transformations import snake_dict_to_camel_dict
from ansible.module_utils.six import string_types
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto_exception
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import compare_policies
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import sort_json_policy_dict
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import boto_exception
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.policy import compare_policies
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def build_kwargs(registry_id):
@@ -251,45 +245,45 @@ def build_kwargs(registry_id):
class EcsEcr:
def __init__(self, module):
- self.ecr = module.client('ecr')
- self.sts = module.client('sts')
+ self.ecr = module.client("ecr")
+ self.sts = module.client("sts")
self.check_mode = module.check_mode
self.changed = False
self.skipped = False
def get_repository(self, registry_id, name):
try:
- res = self.ecr.describe_repositories(
- repositoryNames=[name], **build_kwargs(registry_id))
- repos = res.get('repositories')
+ res = self.ecr.describe_repositories(repositoryNames=[name], **build_kwargs(registry_id))
+ repos = res.get("repositories")
return repos and repos[0]
- except is_boto3_error_code('RepositoryNotFoundException'):
+ except is_boto3_error_code("RepositoryNotFoundException"):
return None
def get_repository_policy(self, registry_id, name):
try:
- res = self.ecr.get_repository_policy(
- repositoryName=name, **build_kwargs(registry_id))
- text = res.get('policyText')
+ res = self.ecr.get_repository_policy(repositoryName=name, **build_kwargs(registry_id))
+ text = res.get("policyText")
return text and json.loads(text)
- except is_boto3_error_code(['RepositoryNotFoundException', 'RepositoryPolicyNotFoundException']):
+ except is_boto3_error_code(["RepositoryNotFoundException", "RepositoryPolicyNotFoundException"]):
return None
def create_repository(self, registry_id, name, image_tag_mutability, encryption_configuration):
if registry_id:
- default_registry_id = self.sts.get_caller_identity().get('Account')
+ default_registry_id = self.sts.get_caller_identity().get("Account")
if registry_id != default_registry_id:
- raise Exception('Cannot create repository in registry {0}.'
- 'Would be created in {1} instead.'.format(registry_id, default_registry_id))
+ raise Exception(
+ f"Cannot create repository in registry {registry_id}. Would be created in {default_registry_id} instead."
+ )
if encryption_configuration is None:
- encryption_configuration = dict(encryptionType='AES256')
+ encryption_configuration = dict(encryptionType="AES256")
if not self.check_mode:
repo = self.ecr.create_repository(
repositoryName=name,
imageTagMutability=image_tag_mutability,
- encryptionConfiguration=encryption_configuration).get('repository')
+ encryptionConfiguration=encryption_configuration,
+ ).get("repository")
self.changed = True
return repo
else:
@@ -299,10 +293,8 @@ class EcsEcr:
def set_repository_policy(self, registry_id, name, policy_text, force):
if not self.check_mode:
policy = self.ecr.set_repository_policy(
- repositoryName=name,
- policyText=policy_text,
- force=force,
- **build_kwargs(registry_id))
+ repositoryName=name, policyText=policy_text, force=force, **build_kwargs(registry_id)
+ )
self.changed = True
return policy
else:
@@ -310,15 +302,13 @@ class EcsEcr:
if self.get_repository(registry_id, name) is None:
printable = name
if registry_id:
- printable = '{0}:{1}'.format(registry_id, name)
- raise Exception(
- 'could not find repository {0}'.format(printable))
+ printable = f"{registry_id}:{name}"
+ raise Exception(f"could not find repository {printable}")
return
def delete_repository(self, registry_id, name, force):
if not self.check_mode:
- repo = self.ecr.delete_repository(
- repositoryName=name, force=force, **build_kwargs(registry_id))
+ repo = self.ecr.delete_repository(repositoryName=name, force=force, **build_kwargs(registry_id))
self.changed = True
return repo
else:
@@ -330,8 +320,7 @@ class EcsEcr:
def delete_repository_policy(self, registry_id, name):
if not self.check_mode:
- policy = self.ecr.delete_repository_policy(
- repositoryName=name, **build_kwargs(registry_id))
+ policy = self.ecr.delete_repository_policy(repositoryName=name, **build_kwargs(registry_id))
self.changed = True
return policy
else:
@@ -343,36 +332,33 @@ class EcsEcr:
def put_image_tag_mutability(self, registry_id, name, new_mutability_configuration):
repo = self.get_repository(registry_id, name)
- current_mutability_configuration = repo.get('imageTagMutability')
+ current_mutability_configuration = repo.get("imageTagMutability")
if current_mutability_configuration != new_mutability_configuration:
if not self.check_mode:
self.ecr.put_image_tag_mutability(
- repositoryName=name,
- imageTagMutability=new_mutability_configuration,
- **build_kwargs(registry_id))
+ repositoryName=name, imageTagMutability=new_mutability_configuration, **build_kwargs(registry_id)
+ )
else:
self.skipped = True
self.changed = True
- repo['imageTagMutability'] = new_mutability_configuration
+ repo["imageTagMutability"] = new_mutability_configuration
return repo
def get_lifecycle_policy(self, registry_id, name):
try:
- res = self.ecr.get_lifecycle_policy(
- repositoryName=name, **build_kwargs(registry_id))
- text = res.get('lifecyclePolicyText')
+ res = self.ecr.get_lifecycle_policy(repositoryName=name, **build_kwargs(registry_id))
+ text = res.get("lifecyclePolicyText")
return text and json.loads(text)
- except is_boto3_error_code(['LifecyclePolicyNotFoundException', 'RepositoryNotFoundException']):
+ except is_boto3_error_code(["LifecyclePolicyNotFoundException", "RepositoryNotFoundException"]):
return None
def put_lifecycle_policy(self, registry_id, name, policy_text):
if not self.check_mode:
policy = self.ecr.put_lifecycle_policy(
- repositoryName=name,
- lifecyclePolicyText=policy_text,
- **build_kwargs(registry_id))
+ repositoryName=name, lifecyclePolicyText=policy_text, **build_kwargs(registry_id)
+ )
self.changed = True
return policy
else:
@@ -380,15 +366,13 @@ class EcsEcr:
if self.get_repository(registry_id, name) is None:
printable = name
if registry_id:
- printable = '{0}:{1}'.format(registry_id, name)
- raise Exception(
- 'could not find repository {0}'.format(printable))
+ printable = f"{registry_id}:{name}"
+ raise Exception(f"could not find repository {printable}")
return
def purge_lifecycle_policy(self, registry_id, name):
if not self.check_mode:
- policy = self.ecr.delete_lifecycle_policy(
- repositoryName=name, **build_kwargs(registry_id))
+ policy = self.ecr.delete_lifecycle_policy(repositoryName=name, **build_kwargs(registry_id))
self.changed = True
return policy
else:
@@ -402,14 +386,11 @@ class EcsEcr:
if not self.check_mode:
if registry_id:
scan = self.ecr.put_image_scanning_configuration(
- registryId=registry_id,
- repositoryName=name,
- imageScanningConfiguration={'scanOnPush': scan_on_push}
+ registryId=registry_id, repositoryName=name, imageScanningConfiguration={"scanOnPush": scan_on_push}
)
else:
scan = self.ecr.put_image_scanning_configuration(
- repositoryName=name,
- imageScanningConfiguration={'scanOnPush': scan_on_push}
+ repositoryName=name, imageScanningConfiguration={"scanOnPush": scan_on_push}
)
self.changed = True
return scan
@@ -419,11 +400,11 @@ class EcsEcr:
def sort_lists_of_strings(policy):
- for statement_index in range(0, len(policy.get('Statement', []))):
- for key in policy['Statement'][statement_index]:
- value = policy['Statement'][statement_index][key]
+ for statement_index in range(0, len(policy.get("Statement", []))):
+ for key in policy["Statement"][statement_index]:
+ value = policy["Statement"][statement_index][key]
if isinstance(value, list) and all(isinstance(item, string_types) for item in value):
- policy['Statement'][statement_index][key] = sorted(value)
+ policy["Statement"][statement_index][key] = sorted(value)
return policy
@@ -431,151 +412,138 @@ def run(ecr, params):
# type: (EcsEcr, dict, int) -> Tuple[bool, dict]
result = {}
try:
- name = params['name']
- state = params['state']
- policy_text = params['policy']
- purge_policy = params['purge_policy']
- force_absent = params['force_absent']
- registry_id = params['registry_id']
- force_set_policy = params['force_set_policy']
- image_tag_mutability = params['image_tag_mutability'].upper()
- lifecycle_policy_text = params['lifecycle_policy']
- purge_lifecycle_policy = params['purge_lifecycle_policy']
- scan_on_push = params['scan_on_push']
- encryption_configuration = snake_dict_to_camel_dict(params['encryption_configuration'])
+ name = params["name"]
+ state = params["state"]
+ policy_text = params["policy"]
+ purge_policy = params["purge_policy"]
+ force_absent = params["force_absent"]
+ registry_id = params["registry_id"]
+ force_set_policy = params["force_set_policy"]
+ image_tag_mutability = params["image_tag_mutability"].upper()
+ lifecycle_policy_text = params["lifecycle_policy"]
+ purge_lifecycle_policy = params["purge_lifecycle_policy"]
+ scan_on_push = params["scan_on_push"]
+ encryption_configuration = snake_dict_to_camel_dict(params["encryption_configuration"])
# Parse policies, if they are given
try:
policy = policy_text and json.loads(policy_text)
except ValueError:
- result['policy'] = policy_text
- result['msg'] = 'Could not parse policy'
+ result["policy"] = policy_text
+ result["msg"] = "Could not parse policy"
return False, result
try:
- lifecycle_policy = \
- lifecycle_policy_text and json.loads(lifecycle_policy_text)
+ lifecycle_policy = lifecycle_policy_text and json.loads(lifecycle_policy_text)
except ValueError:
- result['lifecycle_policy'] = lifecycle_policy_text
- result['msg'] = 'Could not parse lifecycle_policy'
+ result["lifecycle_policy"] = lifecycle_policy_text
+ result["msg"] = "Could not parse lifecycle_policy"
return False, result
- result['state'] = state
- result['created'] = False
+ result["state"] = state
+ result["created"] = False
repo = ecr.get_repository(registry_id, name)
- if state == 'present':
- result['created'] = False
+ if state == "present":
+ result["created"] = False
if not repo:
- repo = ecr.create_repository(
- registry_id, name, image_tag_mutability, encryption_configuration)
- result['changed'] = True
- result['created'] = True
+ repo = ecr.create_repository(registry_id, name, image_tag_mutability, encryption_configuration)
+ result["changed"] = True
+ result["created"] = True
else:
if encryption_configuration is not None:
- if repo.get('encryptionConfiguration') != encryption_configuration:
- result['msg'] = 'Cannot modify repository encryption type'
+ if repo.get("encryptionConfiguration") != encryption_configuration:
+ result["msg"] = "Cannot modify repository encryption type"
return False, result
repo = ecr.put_image_tag_mutability(registry_id, name, image_tag_mutability)
- result['repository'] = repo
+ result["repository"] = repo
if purge_lifecycle_policy:
- original_lifecycle_policy = \
- ecr.get_lifecycle_policy(registry_id, name)
+ original_lifecycle_policy = ecr.get_lifecycle_policy(registry_id, name)
- result['lifecycle_policy'] = None
+ result["lifecycle_policy"] = None
if original_lifecycle_policy:
ecr.purge_lifecycle_policy(registry_id, name)
- result['changed'] = True
+ result["changed"] = True
elif lifecycle_policy_text is not None:
try:
- lifecycle_policy = sort_json_policy_dict(lifecycle_policy)
- result['lifecycle_policy'] = lifecycle_policy
+ result["lifecycle_policy"] = lifecycle_policy
+ original_lifecycle_policy = ecr.get_lifecycle_policy(registry_id, name)
- original_lifecycle_policy = ecr.get_lifecycle_policy(
- registry_id, name)
-
- if original_lifecycle_policy:
- original_lifecycle_policy = sort_json_policy_dict(
- original_lifecycle_policy)
-
- if original_lifecycle_policy != lifecycle_policy:
- ecr.put_lifecycle_policy(registry_id, name,
- lifecycle_policy_text)
- result['changed'] = True
+ if compare_policies(original_lifecycle_policy, lifecycle_policy):
+ ecr.put_lifecycle_policy(registry_id, name, lifecycle_policy_text)
+ result["changed"] = True
except Exception:
# Some failure w/ the policy. It's helpful to know what the
# policy is.
- result['lifecycle_policy'] = lifecycle_policy_text
+ result["lifecycle_policy"] = lifecycle_policy_text
raise
if purge_policy:
original_policy = ecr.get_repository_policy(registry_id, name)
- result['policy'] = None
+ result["policy"] = None
if original_policy:
ecr.delete_repository_policy(registry_id, name)
- result['changed'] = True
+ result["changed"] = True
elif policy_text is not None:
try:
# Sort any lists containing only string types
policy = sort_lists_of_strings(policy)
- result['policy'] = policy
+ result["policy"] = policy
- original_policy = ecr.get_repository_policy(
- registry_id, name)
+ original_policy = ecr.get_repository_policy(registry_id, name)
if original_policy:
original_policy = sort_lists_of_strings(original_policy)
if compare_policies(original_policy, policy):
- ecr.set_repository_policy(
- registry_id, name, policy_text, force_set_policy)
- result['changed'] = True
+ ecr.set_repository_policy(registry_id, name, policy_text, force_set_policy)
+ result["changed"] = True
except Exception:
# Some failure w/ the policy. It's helpful to know what the
# policy is.
- result['policy'] = policy_text
+ result["policy"] = policy_text
raise
else:
original_policy = ecr.get_repository_policy(registry_id, name)
if original_policy:
- result['policy'] = original_policy
+ result["policy"] = original_policy
original_scan_on_push = ecr.get_repository(registry_id, name)
if original_scan_on_push is not None:
- if scan_on_push != original_scan_on_push['imageScanningConfiguration']['scanOnPush']:
- result['changed'] = True
- result['repository']['imageScanningConfiguration']['scanOnPush'] = scan_on_push
+ if scan_on_push != original_scan_on_push["imageScanningConfiguration"]["scanOnPush"]:
+ result["changed"] = True
+ result["repository"]["imageScanningConfiguration"]["scanOnPush"] = scan_on_push
response = ecr.put_image_scanning_configuration(registry_id, name, scan_on_push)
- elif state == 'absent':
- result['name'] = name
+ elif state == "absent":
+ result["name"] = name
if repo:
ecr.delete_repository(registry_id, name, force_absent)
- result['changed'] = True
+ result["changed"] = True
except Exception as err:
msg = str(err)
if isinstance(err, botocore.exceptions.ClientError):
msg = boto_exception(err)
- result['msg'] = msg
- result['exception'] = traceback.format_exc()
+ result["msg"] = msg
+ result["exception"] = traceback.format_exc()
return False, result
if ecr.skipped:
- result['skipped'] = True
+ result["skipped"] = True
if ecr.changed:
- result['changed'] = True
+ result["changed"] = True
return True, result
@@ -584,34 +552,37 @@ def main():
argument_spec = dict(
name=dict(required=True),
registry_id=dict(required=False),
- state=dict(required=False, choices=['present', 'absent'],
- default='present'),
- force_absent=dict(required=False, type='bool', default=False),
- force_set_policy=dict(required=False, type='bool', default=False),
- policy=dict(required=False, type='json'),
- image_tag_mutability=dict(required=False, choices=['mutable', 'immutable'],
- default='mutable'),
- purge_policy=dict(required=False, type='bool'),
- lifecycle_policy=dict(required=False, type='json'),
- purge_lifecycle_policy=dict(required=False, type='bool'),
- scan_on_push=(dict(required=False, type='bool', default=False)),
+ state=dict(required=False, choices=["present", "absent"], default="present"),
+ force_absent=dict(required=False, type="bool", default=False),
+ force_set_policy=dict(required=False, type="bool", default=False),
+ policy=dict(required=False, type="json"),
+ image_tag_mutability=dict(required=False, choices=["mutable", "immutable"], default="mutable"),
+ purge_policy=dict(required=False, type="bool"),
+ lifecycle_policy=dict(required=False, type="json"),
+ purge_lifecycle_policy=dict(required=False, type="bool"),
+ scan_on_push=(dict(required=False, type="bool", default=False)),
encryption_configuration=dict(
required=False,
- type='dict',
+ type="dict",
options=dict(
- encryption_type=dict(required=False, type='str', default='AES256', choices=['AES256', 'KMS']),
- kms_key=dict(required=False, type='str', no_log=False),
+ encryption_type=dict(required=False, type="str", default="AES256", choices=["AES256", "KMS"]),
+ kms_key=dict(required=False, type="str", no_log=False),
),
required_if=[
- ['encryption_type', 'KMS', ['kms_key']],
+ ["encryption_type", "KMS", ["kms_key"]],
],
),
)
mutually_exclusive = [
- ['policy', 'purge_policy'],
- ['lifecycle_policy', 'purge_lifecycle_policy']]
-
- module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True, mutually_exclusive=mutually_exclusive)
+ ["policy", "purge_policy"],
+ ["lifecycle_policy", "purge_lifecycle_policy"],
+ ]
+
+ module = AnsibleAWSModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ mutually_exclusive=mutually_exclusive,
+ )
ecr = EcsEcr(module)
passed, result = run(ecr, module.params)
@@ -622,5 +593,5 @@ def main():
module.fail_json(**result)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/ecs_service.py b/ansible_collections/community/aws/plugins/modules/ecs_service.py
index 2d86a6bd5..e832fa3b5 100644
--- a/ansible_collections/community/aws/plugins/modules/ecs_service.py
+++ b/ansible_collections/community/aws/plugins/modules/ecs_service.py
@@ -1,11 +1,10 @@
#!/usr/bin/python
-# This file is part of Ansible
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+# -*- coding: utf-8 -*-
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
+# Copyright: Contributors to the Ansible project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: ecs_service
version_added: 1.0.0
@@ -297,12 +296,12 @@ options:
required: false
version_added: 4.1.0
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide for details.
# Basic provisioning example
- community.aws.ecs_service:
@@ -321,10 +320,10 @@ EXAMPLES = r'''
desired_count: 0
network_configuration:
subnets:
- - subnet-abcd1234
+ - subnet-abcd1234
security_groups:
- - sg-aaaa1111
- - my_security_group
+ - sg-aaaa1111
+ - my_security_group
# Simple example to delete
- community.aws.ecs_service:
@@ -358,8 +357,8 @@ EXAMPLES = r'''
desired_count: 3
deployment_configuration:
deployment_circuit_breaker:
- enable: True
- rollback: True
+ enable: true
+ rollback: true
# With capacity_provider_strategy (added in version 4.0)
- community.aws.ecs_service:
@@ -384,9 +383,9 @@ EXAMPLES = r'''
Firstname: jane
lastName: doe
propagate_tags: SERVICE
-'''
+"""
-RETURN = r'''
+RETURN = r"""
service:
description: Details of created service.
returned: when creating a service
@@ -678,31 +677,33 @@ ansible_facts:
returned: always
type: str
-'''
-import time
+"""
-DEPLOYMENT_CONTROLLER_TYPE_MAP = {
- 'type': 'str',
-}
+import time
-DEPLOYMENT_CONFIGURATION_TYPE_MAP = {
- 'maximum_percent': 'int',
- 'minimum_healthy_percent': 'int',
- 'deployment_circuit_breaker': 'dict',
-}
+try:
+ import botocore
+except ImportError:
+ pass # caught by AnsibleAWSModule
from ansible.module_utils.common.dict_transformations import snake_dict_to_camel_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import map_complex_type
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import get_ec2_security_group_ids_from_names
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_tag_list
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import ansible_dict_to_boto3_tag_list
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.transformation import map_complex_type
-try:
- import botocore
-except ImportError:
- pass # caught by AnsibleAWSModule
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
+
+DEPLOYMENT_CONTROLLER_TYPE_MAP = {
+ "type": "str",
+}
+
+DEPLOYMENT_CONFIGURATION_TYPE_MAP = {
+ "maximum_percent": "int",
+ "minimum_healthy_percent": "int",
+ "deployment_circuit_breaker": "dict",
+}
class EcsServiceManager:
@@ -710,32 +711,32 @@ class EcsServiceManager:
def __init__(self, module):
self.module = module
- self.ecs = module.client('ecs')
- self.ec2 = module.client('ec2')
+ self.ecs = module.client("ecs")
+ self.ec2 = module.client("ec2")
def format_network_configuration(self, network_config):
result = dict()
- if network_config['subnets'] is not None:
- result['subnets'] = network_config['subnets']
+ if network_config["subnets"] is not None:
+ result["subnets"] = network_config["subnets"]
else:
self.module.fail_json(msg="Network configuration must include subnets")
- if network_config['security_groups'] is not None:
- groups = network_config['security_groups']
- if any(not sg.startswith('sg-') for sg in groups):
+ if network_config["security_groups"] is not None:
+ groups = network_config["security_groups"]
+ if any(not sg.startswith("sg-") for sg in groups):
try:
- vpc_id = self.ec2.describe_subnets(SubnetIds=[result['subnets'][0]])['Subnets'][0]['VpcId']
+ vpc_id = self.ec2.describe_subnets(SubnetIds=[result["subnets"][0]])["Subnets"][0]["VpcId"]
groups = get_ec2_security_group_ids_from_names(groups, self.ec2, vpc_id)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
self.module.fail_json_aws(e, msg="Couldn't look up security groups")
- result['securityGroups'] = groups
- if network_config['assign_public_ip'] is not None:
- if network_config['assign_public_ip'] is True:
- result['assignPublicIp'] = "ENABLED"
+ result["securityGroups"] = groups
+ if network_config["assign_public_ip"] is not None:
+ if network_config["assign_public_ip"] is True:
+ result["assignPublicIp"] = "ENABLED"
else:
- result['assignPublicIp'] = "DISABLED"
+ result["assignPublicIp"] = "DISABLED"
return dict(awsvpcConfiguration=result)
- def find_in_array(self, array_of_services, service_name, field_name='serviceArn'):
+ def find_in_array(self, array_of_services, service_name, field_name="serviceArn"):
for c in array_of_services:
if c[field_name].endswith(service_name):
return c
@@ -745,42 +746,42 @@ class EcsServiceManager:
response = self.ecs.describe_services(
cluster=cluster_name,
services=[service_name],
- include=['TAGS'],
+ include=["TAGS"],
)
- msg = ''
+ msg = ""
- if len(response['failures']) > 0:
- c = self.find_in_array(response['failures'], service_name, 'arn')
- msg += ", failure reason is " + c['reason']
- if c and c['reason'] == 'MISSING':
+ if len(response["failures"]) > 0:
+ c = self.find_in_array(response["failures"], service_name, "arn")
+ msg += ", failure reason is " + c["reason"]
+ if c and c["reason"] == "MISSING":
return None
# fall thru and look through found ones
- if len(response['services']) > 0:
- c = self.find_in_array(response['services'], service_name)
+ if len(response["services"]) > 0:
+ c = self.find_in_array(response["services"], service_name)
if c:
return c
- raise Exception("Unknown problem describing service %s." % service_name)
+ raise Exception(f"Unknown problem describing service {service_name}.")
def is_matching_service(self, expected, existing):
# aws returns the arn of the task definition
# arn:aws:ecs:eu-central-1:123456789:task-definition/ansible-fargate-nginx:3
# but the user is just entering
# ansible-fargate-nginx:3
- if expected['task_definition'] != existing['taskDefinition'].split('/')[-1]:
- if existing.get('deploymentController', {}).get('type', None) != 'CODE_DEPLOY':
+ if expected["task_definition"] != existing["taskDefinition"].split("/")[-1]:
+ if existing.get("deploymentController", {}).get("type", None) != "CODE_DEPLOY":
return False
- if expected.get('health_check_grace_period_seconds'):
- if expected.get('health_check_grace_period_seconds') != existing.get('healthCheckGracePeriodSeconds'):
+ if expected.get("health_check_grace_period_seconds"):
+ if expected.get("health_check_grace_period_seconds") != existing.get("healthCheckGracePeriodSeconds"):
return False
- if (expected['load_balancers'] or []) != existing['loadBalancers']:
+ if (expected["load_balancers"] or []) != existing["loadBalancers"]:
return False
- if (expected['propagate_tags'] or "NONE") != existing['propagateTags']:
+ if (expected["propagate_tags"] or "NONE") != existing["propagateTags"]:
return False
- if boto3_tag_list_to_ansible_dict(existing.get('tags', [])) != (expected['tags'] or {}):
+ if boto3_tag_list_to_ansible_dict(existing.get("tags", [])) != (expected["tags"] or {}):
return False
if (expected["enable_execute_command"] or False) != existing.get("enableExecuteCommand", False):
@@ -788,8 +789,8 @@ class EcsServiceManager:
# expected is params. DAEMON scheduling strategy returns desired count equal to
# number of instances running; don't check desired count if scheduling strat is daemon
- if (expected['scheduling_strategy'] != 'DAEMON'):
- if (expected['desired_count'] or 0) != existing['desiredCount']:
+ if expected["scheduling_strategy"] != "DAEMON":
+ if (expected["desired_count"] or 0) != existing["desiredCount"]:
return False
return True
@@ -818,7 +819,6 @@ class EcsServiceManager:
propagate_tags,
enable_execute_command,
):
-
params = dict(
cluster=cluster_name,
serviceName=service_name,
@@ -827,47 +827,49 @@ class EcsServiceManager:
clientToken=client_token,
role=role,
deploymentConfiguration=deployment_configuration,
- placementStrategy=placement_strategy
+ placementStrategy=placement_strategy,
)
if network_configuration:
- params['networkConfiguration'] = network_configuration
+ params["networkConfiguration"] = network_configuration
if deployment_controller:
- params['deploymentController'] = deployment_controller
+ params["deploymentController"] = deployment_controller
if launch_type:
- params['launchType'] = launch_type
+ params["launchType"] = launch_type
if platform_version:
- params['platformVersion'] = platform_version
+ params["platformVersion"] = platform_version
if self.health_check_setable(params) and health_check_grace_period_seconds is not None:
- params['healthCheckGracePeriodSeconds'] = health_check_grace_period_seconds
+ params["healthCheckGracePeriodSeconds"] = health_check_grace_period_seconds
if service_registries:
- params['serviceRegistries'] = service_registries
+ params["serviceRegistries"] = service_registries
# filter placement_constraint and left only those where value is not None
# use-case: `distinctInstance` type should never contain `expression`, but None will fail `str` type validation
if placement_constraints:
- params['placementConstraints'] = [{key: value for key, value in constraint.items() if value is not None}
- for constraint in placement_constraints]
+ params["placementConstraints"] = [
+ {key: value for key, value in constraint.items() if value is not None}
+ for constraint in placement_constraints
+ ]
# desired count is not required if scheduling strategy is daemon
if desired_count is not None:
- params['desiredCount'] = desired_count
+ params["desiredCount"] = desired_count
if capacity_provider_strategy:
- params['capacityProviderStrategy'] = capacity_provider_strategy
+ params["capacityProviderStrategy"] = capacity_provider_strategy
if propagate_tags:
- params['propagateTags'] = propagate_tags
+ params["propagateTags"] = propagate_tags
# desired count is not required if scheduling strategy is daemon
if desired_count is not None:
- params['desiredCount'] = desired_count
+ params["desiredCount"] = desired_count
if tags:
- params['tags'] = ansible_dict_to_boto3_tag_list(tags, 'key', 'value')
+ params["tags"] = ansible_dict_to_boto3_tag_list(tags, "key", "value")
if scheduling_strategy:
- params['schedulingStrategy'] = scheduling_strategy
+ params["schedulingStrategy"] = scheduling_strategy
if enable_execute_command:
params["enableExecuteCommand"] = enable_execute_command
response = self.ecs.create_service(**params)
- return self.jsonize(response['service'])
+ return self.jsonize(response["service"])
def update_service(
self,
@@ -891,242 +893,262 @@ class EcsServiceManager:
cluster=cluster_name,
service=service_name,
taskDefinition=task_definition,
- deploymentConfiguration=deployment_configuration)
+ deploymentConfiguration=deployment_configuration,
+ )
# filter placement_constraint and left only those where value is not None
# use-case: `distinctInstance` type should never contain `expression`, but None will fail `str` type validation
if placement_constraints:
- params['placementConstraints'] = [{key: value for key, value in constraint.items() if value is not None}
- for constraint in placement_constraints]
+ params["placementConstraints"] = [
+ {key: value for key, value in constraint.items() if value is not None}
+ for constraint in placement_constraints
+ ]
if purge_placement_constraints and not placement_constraints:
- params['placementConstraints'] = []
+ params["placementConstraints"] = []
if placement_strategy:
- params['placementStrategy'] = placement_strategy
+ params["placementStrategy"] = placement_strategy
if purge_placement_strategy and not placement_strategy:
- params['placementStrategy'] = []
+ params["placementStrategy"] = []
if network_configuration:
- params['networkConfiguration'] = network_configuration
+ params["networkConfiguration"] = network_configuration
if force_new_deployment:
- params['forceNewDeployment'] = force_new_deployment
+ params["forceNewDeployment"] = force_new_deployment
if capacity_provider_strategy:
- params['capacityProviderStrategy'] = capacity_provider_strategy
+ params["capacityProviderStrategy"] = capacity_provider_strategy
if health_check_grace_period_seconds is not None:
- params['healthCheckGracePeriodSeconds'] = health_check_grace_period_seconds
+ params["healthCheckGracePeriodSeconds"] = health_check_grace_period_seconds
# desired count is not required if scheduling strategy is daemon
if desired_count is not None:
- params['desiredCount'] = desired_count
+ params["desiredCount"] = desired_count
if enable_execute_command is not None:
params["enableExecuteCommand"] = enable_execute_command
if load_balancers:
- params['loadBalancers'] = load_balancers
+ params["loadBalancers"] = load_balancers
response = self.ecs.update_service(**params)
- return self.jsonize(response['service'])
+ return self.jsonize(response["service"])
def jsonize(self, service):
# some fields are datetime which is not JSON serializable
# make them strings
- if 'createdAt' in service:
- service['createdAt'] = str(service['createdAt'])
- if 'deployments' in service:
- for d in service['deployments']:
- if 'createdAt' in d:
- d['createdAt'] = str(d['createdAt'])
- if 'updatedAt' in d:
- d['updatedAt'] = str(d['updatedAt'])
- if 'events' in service:
- for e in service['events']:
- if 'createdAt' in e:
- e['createdAt'] = str(e['createdAt'])
+ if "createdAt" in service:
+ service["createdAt"] = str(service["createdAt"])
+ if "deployments" in service:
+ for d in service["deployments"]:
+ if "createdAt" in d:
+ d["createdAt"] = str(d["createdAt"])
+ if "updatedAt" in d:
+ d["updatedAt"] = str(d["updatedAt"])
+ if "events" in service:
+ for e in service["events"]:
+ if "createdAt" in e:
+ e["createdAt"] = str(e["createdAt"])
return service
def delete_service(self, service, cluster=None, force=False):
return self.ecs.delete_service(cluster=cluster, service=service, force=force)
def health_check_setable(self, params):
- load_balancers = params.get('loadBalancers', [])
+ load_balancers = params.get("loadBalancers", [])
return len(load_balancers) > 0
def main():
argument_spec = dict(
- state=dict(required=True, choices=['present', 'absent', 'deleting']),
- name=dict(required=True, type='str', aliases=['service']),
- cluster=dict(required=False, type='str', default='default'),
- task_definition=dict(required=False, type='str'),
- load_balancers=dict(required=False, default=[], type='list', elements='dict'),
- desired_count=dict(required=False, type='int'),
- client_token=dict(required=False, default='', type='str', no_log=False),
- role=dict(required=False, default='', type='str'),
- delay=dict(required=False, type='int', default=10),
- repeat=dict(required=False, type='int', default=10),
- force_new_deployment=dict(required=False, default=False, type='bool'),
- force_deletion=dict(required=False, default=False, type='bool'),
- deployment_controller=dict(required=False, default={}, type='dict'),
- deployment_configuration=dict(required=False, default={}, type='dict'),
- wait=dict(required=False, default=False, type='bool'),
+ state=dict(required=True, choices=["present", "absent", "deleting"]),
+ name=dict(required=True, type="str", aliases=["service"]),
+ cluster=dict(required=False, type="str", default="default"),
+ task_definition=dict(required=False, type="str"),
+ load_balancers=dict(required=False, default=[], type="list", elements="dict"),
+ desired_count=dict(required=False, type="int"),
+ client_token=dict(required=False, default="", type="str", no_log=False),
+ role=dict(required=False, default="", type="str"),
+ delay=dict(required=False, type="int", default=10),
+ repeat=dict(required=False, type="int", default=10),
+ force_new_deployment=dict(required=False, default=False, type="bool"),
+ force_deletion=dict(required=False, default=False, type="bool"),
+ deployment_controller=dict(required=False, default={}, type="dict"),
+ deployment_configuration=dict(required=False, default={}, type="dict"),
+ wait=dict(required=False, default=False, type="bool"),
placement_constraints=dict(
required=False,
default=[],
- type='list',
- elements='dict',
- options=dict(
- type=dict(type='str'),
- expression=dict(required=False, type='str')
- )
+ type="list",
+ elements="dict",
+ options=dict(type=dict(type="str"), expression=dict(required=False, type="str")),
),
- purge_placement_constraints=dict(required=False, default=False, type='bool'),
+ purge_placement_constraints=dict(required=False, default=False, type="bool"),
placement_strategy=dict(
required=False,
default=[],
- type='list',
- elements='dict',
+ type="list",
+ elements="dict",
+ options=dict(
+ type=dict(type="str"),
+ field=dict(type="str"),
+ ),
+ ),
+ purge_placement_strategy=dict(required=False, default=False, type="bool"),
+ health_check_grace_period_seconds=dict(required=False, type="int"),
+ network_configuration=dict(
+ required=False,
+ type="dict",
options=dict(
- type=dict(type='str'),
- field=dict(type='str'),
- )
+ subnets=dict(type="list", elements="str"),
+ security_groups=dict(type="list", elements="str"),
+ assign_public_ip=dict(type="bool"),
+ ),
),
- purge_placement_strategy=dict(required=False, default=False, type='bool'),
- health_check_grace_period_seconds=dict(required=False, type='int'),
- network_configuration=dict(required=False, type='dict', options=dict(
- subnets=dict(type='list', elements='str'),
- security_groups=dict(type='list', elements='str'),
- assign_public_ip=dict(type='bool')
- )),
- launch_type=dict(required=False, choices=['EC2', 'FARGATE']),
- platform_version=dict(required=False, type='str'),
- service_registries=dict(required=False, type='list', default=[], elements='dict'),
- scheduling_strategy=dict(required=False, choices=['DAEMON', 'REPLICA']),
+ launch_type=dict(required=False, choices=["EC2", "FARGATE"]),
+ platform_version=dict(required=False, type="str"),
+ service_registries=dict(required=False, type="list", default=[], elements="dict"),
+ scheduling_strategy=dict(required=False, choices=["DAEMON", "REPLICA"]),
capacity_provider_strategy=dict(
required=False,
- type='list',
+ type="list",
default=[],
- elements='dict',
+ elements="dict",
options=dict(
- capacity_provider=dict(type='str'),
- weight=dict(type='int'),
- base=dict(type='int')
- )
+ capacity_provider=dict(type="str"),
+ weight=dict(type="int"),
+ base=dict(type="int"),
+ ),
),
propagate_tags=dict(required=False, choices=["TASK_DEFINITION", "SERVICE"]),
tags=dict(required=False, type="dict"),
enable_execute_command=dict(required=False, type="bool"),
)
- module = AnsibleAWSModule(argument_spec=argument_spec,
- supports_check_mode=True,
- required_if=[('launch_type', 'FARGATE', ['network_configuration'])],
- required_together=[['load_balancers', 'role']],
- mutually_exclusive=[['launch_type', 'capacity_provider_strategy']])
+ module = AnsibleAWSModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[("launch_type", "FARGATE", ["network_configuration"])],
+ required_together=[["load_balancers", "role"]],
+ mutually_exclusive=[["launch_type", "capacity_provider_strategy"]],
+ )
- if module.params['state'] == 'present':
- if module.params['scheduling_strategy'] == 'REPLICA' and module.params['desired_count'] is None:
- module.fail_json(msg='state is present, scheduling_strategy is REPLICA; missing desired_count')
- if module.params['task_definition'] is None and not module.params['force_new_deployment']:
- module.fail_json(msg='Either task_definition or force_new_deployment is required when status is present.')
+ if module.params["state"] == "present":
+ if module.params["scheduling_strategy"] == "REPLICA" and module.params["desired_count"] is None:
+ module.fail_json(msg="state is present, scheduling_strategy is REPLICA; missing desired_count")
+ if module.params["task_definition"] is None and not module.params["force_new_deployment"]:
+ module.fail_json(msg="Either task_definition or force_new_deployment is required when status is present.")
- if len(module.params['capacity_provider_strategy']) > 6:
- module.fail_json(msg='AWS allows a maximum of six capacity providers in the strategy.')
+ if len(module.params["capacity_provider_strategy"]) > 6:
+ module.fail_json(msg="AWS allows a maximum of six capacity providers in the strategy.")
service_mgr = EcsServiceManager(module)
- if module.params['network_configuration']:
- network_configuration = service_mgr.format_network_configuration(module.params['network_configuration'])
+ if module.params["network_configuration"]:
+ network_configuration = service_mgr.format_network_configuration(module.params["network_configuration"])
else:
network_configuration = None
- deployment_controller = map_complex_type(module.params['deployment_controller'],
- DEPLOYMENT_CONTROLLER_TYPE_MAP)
+ deployment_controller = map_complex_type(module.params["deployment_controller"], DEPLOYMENT_CONTROLLER_TYPE_MAP)
deploymentController = snake_dict_to_camel_dict(deployment_controller)
- deployment_configuration = map_complex_type(module.params['deployment_configuration'],
- DEPLOYMENT_CONFIGURATION_TYPE_MAP)
+ deployment_configuration = map_complex_type(
+ module.params["deployment_configuration"], DEPLOYMENT_CONFIGURATION_TYPE_MAP
+ )
deploymentConfiguration = snake_dict_to_camel_dict(deployment_configuration)
- serviceRegistries = list(map(snake_dict_to_camel_dict, module.params['service_registries']))
- capacityProviders = list(map(snake_dict_to_camel_dict, module.params['capacity_provider_strategy']))
+ serviceRegistries = list(map(snake_dict_to_camel_dict, module.params["service_registries"]))
+ capacityProviders = list(map(snake_dict_to_camel_dict, module.params["capacity_provider_strategy"]))
try:
- existing = service_mgr.describe_service(module.params['cluster'], module.params['name'])
+ existing = service_mgr.describe_service(module.params["cluster"], module.params["name"])
except Exception as e:
- module.fail_json_aws(e,
- msg="Exception describing service '{0}' in cluster '{1}'"
- .format(module.params['name'], module.params['cluster']))
+ module.fail_json_aws(
+ e,
+ msg=f"Exception describing service '{module.params['name']}' in cluster '{module.params['cluster']}'",
+ )
results = dict(changed=False)
- if module.params['state'] == 'present':
-
+ if module.params["state"] == "present":
matching = False
update = False
- if existing and 'status' in existing and existing['status'] == "ACTIVE":
- if module.params['force_new_deployment']:
+ if existing and "status" in existing and existing["status"] == "ACTIVE":
+ if module.params["force_new_deployment"]:
update = True
elif service_mgr.is_matching_service(module.params, existing):
matching = True
- results['service'] = existing
+ results["service"] = existing
else:
update = True
if not matching:
if not module.check_mode:
-
- role = module.params['role']
- clientToken = module.params['client_token']
+ role = module.params["role"]
+ clientToken = module.params["client_token"]
loadBalancers = []
- for loadBalancer in module.params['load_balancers']:
- if 'containerPort' in loadBalancer:
- loadBalancer['containerPort'] = int(loadBalancer['containerPort'])
+ for loadBalancer in module.params["load_balancers"]:
+ if "containerPort" in loadBalancer:
+ loadBalancer["containerPort"] = int(loadBalancer["containerPort"])
loadBalancers.append(loadBalancer)
for loadBalancer in loadBalancers:
- if 'containerPort' in loadBalancer:
- loadBalancer['containerPort'] = int(loadBalancer['containerPort'])
+ if "containerPort" in loadBalancer:
+ loadBalancer["containerPort"] = int(loadBalancer["containerPort"])
if update:
# check various parameters and AWS SDK versions and give a helpful error if the SDK is not new enough for feature
- if module.params['scheduling_strategy']:
- if (existing['schedulingStrategy']) != module.params['scheduling_strategy']:
- module.fail_json(msg="It is not possible to update the scheduling strategy of an existing service")
-
- if module.params['service_registries']:
- if (existing['serviceRegistries'] or []) != serviceRegistries:
- module.fail_json(msg="It is not possible to update the service registries of an existing service")
- if module.params['capacity_provider_strategy']:
- if 'launchType' in existing.keys():
- module.fail_json(msg="It is not possible to change an existing service from launch_type to capacity_provider_strategy.")
- if module.params['launch_type']:
- if 'capacityProviderStrategy' in existing.keys():
- module.fail_json(msg="It is not possible to change an existing service from capacity_provider_strategy to launch_type.")
- if (existing['loadBalancers'] or []) != loadBalancers:
+ if module.params["scheduling_strategy"]:
+ if (existing["schedulingStrategy"]) != module.params["scheduling_strategy"]:
+ module.fail_json(
+ msg="It is not possible to update the scheduling strategy of an existing service"
+ )
+
+ if module.params["service_registries"]:
+ if (existing["serviceRegistries"] or []) != serviceRegistries:
+ module.fail_json(
+ msg="It is not possible to update the service registries of an existing service"
+ )
+ if module.params["capacity_provider_strategy"]:
+ if "launchType" in existing.keys():
+ module.fail_json(
+ msg="It is not possible to change an existing service from launch_type to capacity_provider_strategy."
+ )
+ if module.params["launch_type"]:
+ if "capacityProviderStrategy" in existing.keys():
+ module.fail_json(
+ msg="It is not possible to change an existing service from capacity_provider_strategy to launch_type."
+ )
+ if (existing["loadBalancers"] or []) != loadBalancers:
# fails if deployment type is not CODE_DEPLOY or ECS
- if existing['deploymentController']['type'] not in ['CODE_DEPLOY', 'ECS']:
- module.fail_json(msg="It is not possible to update the load balancers of an existing service")
+ if existing["deploymentController"]["type"] not in ["CODE_DEPLOY", "ECS"]:
+ module.fail_json(
+ msg="It is not possible to update the load balancers of an existing service"
+ )
- if existing.get('deploymentController', {}).get('type', None) == 'CODE_DEPLOY':
- task_definition = ''
+ if existing.get("deploymentController", {}).get("type", None) == "CODE_DEPLOY":
+ task_definition = ""
network_configuration = []
else:
- task_definition = module.params['task_definition']
+ task_definition = module.params["task_definition"]
- if module.params['propagate_tags'] and module.params['propagate_tags'] != existing['propagateTags']:
- module.fail_json(msg="It is not currently supported to enable propagation tags of an existing service")
+ if module.params["propagate_tags"] and module.params["propagate_tags"] != existing["propagateTags"]:
+ module.fail_json(
+ msg="It is not currently supported to enable propagation tags of an existing service"
+ )
- if module.params['tags'] and boto3_tag_list_to_ansible_dict(existing['tags']) != module.params['tags']:
+ if (
+ module.params["tags"]
+ and boto3_tag_list_to_ansible_dict(existing["tags"]) != module.params["tags"]
+ ):
module.fail_json(msg="It is not currently supported to change tags of an existing service")
- updatedLoadBalancers = loadBalancers if existing['deploymentController']['type'] == 'ECS' else []
+ updatedLoadBalancers = loadBalancers if existing["deploymentController"]["type"] == "ECS" else []
- if task_definition is None and module.params['force_new_deployment']:
- task_definition = existing['taskDefinition']
+ if task_definition is None and module.params["force_new_deployment"]:
+ task_definition = existing["taskDefinition"]
try:
# update required
@@ -1178,76 +1200,73 @@ def main():
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
module.fail_json_aws(e, msg="Couldn't create service")
- if response.get('tags', None):
- response['tags'] = boto3_tag_list_to_ansible_dict(response['tags'])
- results['service'] = response
+ if response.get("tags", None):
+ response["tags"] = boto3_tag_list_to_ansible_dict(response["tags"])
+ results["service"] = response
- results['changed'] = True
+ results["changed"] = True
- elif module.params['state'] == 'absent':
+ elif module.params["state"] == "absent":
if not existing:
pass
else:
# it exists, so we should delete it and mark changed.
# return info about the cluster deleted
- del existing['deployments']
- del existing['events']
- results['ansible_facts'] = existing
- if 'status' in existing and existing['status'] == "INACTIVE":
- results['changed'] = False
+ del existing["deployments"]
+ del existing["events"]
+ results["ansible_facts"] = existing
+ if "status" in existing and existing["status"] == "INACTIVE":
+ results["changed"] = False
else:
if not module.check_mode:
try:
service_mgr.delete_service(
- module.params['name'],
- module.params['cluster'],
- module.params['force_deletion'],
+ module.params["name"],
+ module.params["cluster"],
+ module.params["force_deletion"],
)
# Wait for service to be INACTIVE prior to exiting
- if module.params['wait']:
- waiter = service_mgr.ecs.get_waiter('services_inactive')
+ if module.params["wait"]:
+ waiter = service_mgr.ecs.get_waiter("services_inactive")
try:
waiter.wait(
- services=[module.params['name']],
- cluster=module.params['cluster'],
+ services=[module.params["name"]],
+ cluster=module.params["cluster"],
WaiterConfig={
- 'Delay': module.params['delay'],
- 'MaxAttempts': module.params['repeat']
- }
+ "Delay": module.params["delay"],
+ "MaxAttempts": module.params["repeat"],
+ },
)
except botocore.exceptions.WaiterError as e:
- module.fail_json_aws(e, 'Timeout waiting for service removal')
+ module.fail_json_aws(e, "Timeout waiting for service removal")
except botocore.exceptions.ClientError as e:
module.fail_json_aws(e, msg="Couldn't delete service")
- results['changed'] = True
+ results["changed"] = True
- elif module.params['state'] == 'deleting':
+ elif module.params["state"] == "deleting":
if not existing:
- module.fail_json(msg="Service '" + module.params['name'] + " not found.")
+ module.fail_json(msg="Service '" + module.params["name"] + " not found.")
return
# it exists, so we should delete it and mark changed.
# return info about the cluster deleted
- delay = module.params['delay']
- repeat = module.params['repeat']
+ delay = module.params["delay"]
+ repeat = module.params["repeat"]
time.sleep(delay)
for i in range(repeat):
- existing = service_mgr.describe_service(module.params['cluster'], module.params['name'])
- status = existing['status']
+ existing = service_mgr.describe_service(module.params["cluster"], module.params["name"])
+ status = existing["status"]
if status == "INACTIVE":
- results['changed'] = True
+ results["changed"] = True
break
time.sleep(delay)
if i is repeat - 1:
- module.fail_json(
- msg="Service still not deleted after {0} tries of {1} seconds each."
- .format(repeat, delay)
- )
+ module.fail_json(msg=f"Service still not deleted after {repeat} tries of {delay} seconds each.")
return
module.exit_json(**results)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/ecs_service_info.py b/ansible_collections/community/aws/plugins/modules/ecs_service_info.py
index f174a31cd..02a6abff2 100644
--- a/ansible_collections/community/aws/plugins/modules/ecs_service_info.py
+++ b/ansible_collections/community/aws/plugins/modules/ecs_service_info.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: ecs_service_info
version_added: 1.0.0
@@ -42,13 +40,12 @@ options:
elements: str
aliases: ['name']
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-'''
-
-EXAMPLES = r'''
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide for details.
# Basic listing example
@@ -62,9 +59,9 @@ EXAMPLES = r'''
- community.aws.ecs_service_info:
cluster: test-cluster
register: output
-'''
+"""
-RETURN = r'''
+RETURN = r"""
services:
description: When details is false, returns an array of service ARNs, otherwise an array of complex objects as described below.
returned: success
@@ -132,16 +129,17 @@ services:
returned: when events is true
type: list
elements: dict
-''' # NOQA
+"""
try:
import botocore
except ImportError:
pass # caught by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
class EcsServiceManager:
@@ -149,14 +147,14 @@ class EcsServiceManager:
def __init__(self, module):
self.module = module
- self.ecs = module.client('ecs')
+ self.ecs = module.client("ecs")
@AWSRetry.jittered_backoff(retries=5, delay=5, backoff=2.0)
def list_services_with_backoff(self, **kwargs):
- paginator = self.ecs.get_paginator('list_services')
+ paginator = self.ecs.get_paginator("list_services")
try:
return paginator.paginate(**kwargs).build_full_result()
- except is_boto3_error_code('ClusterNotFoundException') as e:
+ except is_boto3_error_code("ClusterNotFoundException") as e:
self.module.fail_json_aws(e, "Could not find cluster to list services")
@AWSRetry.jittered_backoff(retries=5, delay=5, backoff=2.0)
@@ -166,43 +164,43 @@ class EcsServiceManager:
def list_services(self, cluster):
fn_args = dict()
if cluster and cluster is not None:
- fn_args['cluster'] = cluster
+ fn_args["cluster"] = cluster
try:
response = self.list_services_with_backoff(**fn_args)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
self.module.fail_json_aws(e, msg="Couldn't list ECS services")
- relevant_response = dict(services=response['serviceArns'])
+ relevant_response = dict(services=response["serviceArns"])
return relevant_response
def describe_services(self, cluster, services):
fn_args = dict()
if cluster and cluster is not None:
- fn_args['cluster'] = cluster
- fn_args['services'] = services
+ fn_args["cluster"] = cluster
+ fn_args["services"] = services
try:
response = self.describe_services_with_backoff(**fn_args)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
self.module.fail_json_aws(e, msg="Couldn't describe ECS services")
- running_services = [self.extract_service_from(service) for service in response.get('services', [])]
- services_not_running = response.get('failures', [])
+ running_services = [self.extract_service_from(service) for service in response.get("services", [])]
+ services_not_running = response.get("failures", [])
return running_services, services_not_running
def extract_service_from(self, service):
# some fields are datetime which is not JSON serializable
# make them strings
- if 'deployments' in service:
- for d in service['deployments']:
- if 'createdAt' in d:
- d['createdAt'] = str(d['createdAt'])
- if 'updatedAt' in d:
- d['updatedAt'] = str(d['updatedAt'])
- if 'events' in service:
- if not self.module.params['events']:
- del service['events']
+ if "deployments" in service:
+ for d in service["deployments"]:
+ if "createdAt" in d:
+ d["createdAt"] = str(d["createdAt"])
+ if "updatedAt" in d:
+ d["updatedAt"] = str(d["updatedAt"])
+ if "events" in service:
+ if not self.module.params["events"]:
+ del service["events"]
else:
- for e in service['events']:
- if 'createdAt' in e:
- e['createdAt'] = str(e['createdAt'])
+ for e in service["events"]:
+ if "createdAt" in e:
+ e["createdAt"] = str(e["createdAt"])
return service
@@ -210,38 +208,37 @@ def chunks(l, n):
"""Yield successive n-sized chunks from l."""
""" https://stackoverflow.com/a/312464 """
for i in range(0, len(l), n):
- yield l[i:i + n]
+ yield l[i:i + n] # fmt: skip
def main():
-
argument_spec = dict(
- details=dict(type='bool', default=False),
- events=dict(type='bool', default=True),
+ details=dict(type="bool", default=False),
+ events=dict(type="bool", default=True),
cluster=dict(),
- service=dict(type='list', elements='str', aliases=['name'])
+ service=dict(type="list", elements="str", aliases=["name"]),
)
module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
- show_details = module.params.get('details')
+ show_details = module.params.get("details")
task_mgr = EcsServiceManager(module)
if show_details:
- if module.params['service']:
- services = module.params['service']
+ if module.params["service"]:
+ services = module.params["service"]
else:
- services = task_mgr.list_services(module.params['cluster'])['services']
+ services = task_mgr.list_services(module.params["cluster"])["services"]
ecs_info = dict(services=[], services_not_running=[])
for chunk in chunks(services, 10):
- running_services, services_not_running = task_mgr.describe_services(module.params['cluster'], chunk)
- ecs_info['services'].extend(running_services)
- ecs_info['services_not_running'].extend(services_not_running)
+ running_services, services_not_running = task_mgr.describe_services(module.params["cluster"], chunk)
+ ecs_info["services"].extend(running_services)
+ ecs_info["services_not_running"].extend(services_not_running)
else:
- ecs_info = task_mgr.list_services(module.params['cluster'])
+ ecs_info = task_mgr.list_services(module.params["cluster"])
module.exit_json(changed=False, **ecs_info)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/ecs_tag.py b/ansible_collections/community/aws/plugins/modules/ecs_tag.py
index 8698a7bbd..dd09096ea 100644
--- a/ansible_collections/community/aws/plugins/modules/ecs_tag.py
+++ b/ansible_collections/community/aws/plugins/modules/ecs_tag.py
@@ -1,20 +1,17 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
+
# Copyright: (c) 2019, Michael Pechner <mikey@mikey.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: ecs_tag
version_added: 1.0.0
short_description: create and remove tags on Amazon ECS resources
-notes:
- - none
description:
- - Creates and removes tags for Amazon ECS resources.
- - Resources are referenced by their cluster name.
+ - Creates and removes tags for Amazon ECS resources.
+ - Resources are referenced by their cluster name.
author:
- Michael Pechner (@mpechner)
options:
@@ -53,13 +50,12 @@ options:
type: bool
default: false
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-'''
-
-EXAMPLES = r'''
+EXAMPLES = r"""
- name: Ensure tags are present on a resource
community.aws.ecs_tag:
cluster_name: mycluster
@@ -90,12 +86,12 @@ EXAMPLES = r'''
cluster_name: mycluster
resource_type: cluster
tags:
- Name: foo
+ Name: foo
state: absent
purge_tags: true
-'''
+"""
-RETURN = r'''
+RETURN = r"""
tags:
description: A dict containing the tags on the resource
returned: always
@@ -108,47 +104,49 @@ removed_tags:
description: A dict of tags that were removed from the resource
returned: If tags were removed
type: dict
-'''
-
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict, ansible_dict_to_boto3_tag_list, compare_aws_tags
+"""
try:
- from botocore.exceptions import BotoCoreError, ClientError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
except ImportError:
- pass # Handled by AnsibleAWSModule
-__metaclass__ = type
+ pass # Handled by AnsibleAWSModule
+
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import ansible_dict_to_boto3_tag_list
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import compare_aws_tags
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def get_tags(ecs, module, resource):
try:
- return boto3_tag_list_to_ansible_dict(ecs.list_tags_for_resource(resourceArn=resource)['tags'])
+ return boto3_tag_list_to_ansible_dict(ecs.list_tags_for_resource(resourceArn=resource)["tags"])
except (BotoCoreError, ClientError) as e:
- module.fail_json_aws(e, msg='Failed to fetch tags for resource {0}'.format(resource))
+ module.fail_json_aws(e, msg=f"Failed to fetch tags for resource {resource}")
def get_arn(ecs, module, cluster_name, resource_type, resource):
-
try:
- if resource_type == 'cluster':
+ if resource_type == "cluster":
description = ecs.describe_clusters(clusters=[resource])
- resource_arn = description['clusters'][0]['clusterArn']
- elif resource_type == 'task':
+ resource_arn = description["clusters"][0]["clusterArn"]
+ elif resource_type == "task":
description = ecs.describe_tasks(cluster=cluster_name, tasks=[resource])
- resource_arn = description['tasks'][0]['taskArn']
- elif resource_type == 'service':
+ resource_arn = description["tasks"][0]["taskArn"]
+ elif resource_type == "service":
description = ecs.describe_services(cluster=cluster_name, services=[resource])
- resource_arn = description['services'][0]['serviceArn']
- elif resource_type == 'task_definition':
+ resource_arn = description["services"][0]["serviceArn"]
+ elif resource_type == "task_definition":
description = ecs.describe_task_definition(taskDefinition=resource)
- resource_arn = description['taskDefinition']['taskDefinitionArn']
- elif resource_type == 'container':
+ resource_arn = description["taskDefinition"]["taskDefinitionArn"]
+ elif resource_type == "container":
description = ecs.describe_container_instances(clusters=[resource])
- resource_arn = description['containerInstances'][0]['containerInstanceArn']
+ resource_arn = description["containerInstances"][0]["containerInstanceArn"]
except (IndexError, KeyError):
- module.fail_json(msg='Failed to find {0} {1}'.format(resource_type, resource))
+ module.fail_json(msg=f"Failed to find {resource_type} {resource}")
except (BotoCoreError, ClientError) as e:
- module.fail_json_aws(e, msg='Failed to find {0} {1}'.format(resource_type, resource))
+ module.fail_json_aws(e, msg=f"Failed to find {resource_type} {resource}")
return resource_arn
@@ -157,28 +155,28 @@ def main():
argument_spec = dict(
cluster_name=dict(required=True),
resource=dict(required=False),
- tags=dict(type='dict', aliases=['resource_tags']),
- purge_tags=dict(type='bool', default=False),
- state=dict(default='present', choices=['present', 'absent']),
- resource_type=dict(default='cluster', choices=['cluster', 'task', 'service', 'task_definition', 'container'])
+ tags=dict(type="dict", aliases=["resource_tags"]),
+ purge_tags=dict(type="bool", default=False),
+ state=dict(default="present", choices=["present", "absent"]),
+ resource_type=dict(default="cluster", choices=["cluster", "task", "service", "task_definition", "container"]),
)
- required_if = [('state', 'present', ['tags']), ('state', 'absent', ['tags'])]
+ required_if = [("state", "present", ["tags"]), ("state", "absent", ["tags"])]
module = AnsibleAWSModule(argument_spec=argument_spec, required_if=required_if, supports_check_mode=True)
- resource_type = module.params['resource_type']
- cluster_name = module.params['cluster_name']
- if resource_type == 'cluster':
+ resource_type = module.params["resource_type"]
+ cluster_name = module.params["cluster_name"]
+ if resource_type == "cluster":
resource = cluster_name
else:
- resource = module.params['resource']
- tags = module.params['tags']
- state = module.params['state']
- purge_tags = module.params['purge_tags']
+ resource = module.params["resource"]
+ tags = module.params["tags"]
+ state = module.params["state"]
+ purge_tags = module.params["purge_tags"]
- result = {'changed': False}
+ result = {"changed": False}
- ecs = module.client('ecs')
+ ecs = module.client("ecs")
resource_arn = get_arn(ecs, module, cluster_name, resource_type, resource)
@@ -187,7 +185,7 @@ def main():
add_tags, remove = compare_aws_tags(current_tags, tags, purge_tags=purge_tags)
remove_tags = {}
- if state == 'absent':
+ if state == "absent":
for key in tags:
if key in current_tags and (tags[key] is None or current_tags[key] == tags[key]):
remove_tags[key] = current_tags[key]
@@ -196,28 +194,28 @@ def main():
remove_tags[key] = current_tags[key]
if remove_tags:
- result['changed'] = True
- result['removed_tags'] = remove_tags
+ result["changed"] = True
+ result["removed_tags"] = remove_tags
if not module.check_mode:
try:
ecs.untag_resource(resourceArn=resource_arn, tagKeys=list(remove_tags.keys()))
except (BotoCoreError, ClientError) as e:
- module.fail_json_aws(e, msg='Failed to remove tags {0} from resource {1}'.format(remove_tags, resource))
+ module.fail_json_aws(e, msg=f"Failed to remove tags {remove_tags} from resource {resource}")
- if state == 'present' and add_tags:
- result['changed'] = True
- result['added_tags'] = add_tags
+ if state == "present" and add_tags:
+ result["changed"] = True
+ result["added_tags"] = add_tags
current_tags.update(add_tags)
if not module.check_mode:
try:
- tags = ansible_dict_to_boto3_tag_list(add_tags, tag_name_key_name='key', tag_value_key_name='value')
+ tags = ansible_dict_to_boto3_tag_list(add_tags, tag_name_key_name="key", tag_value_key_name="value")
ecs.tag_resource(resourceArn=resource_arn, tags=tags)
except (BotoCoreError, ClientError) as e:
- module.fail_json_aws(e, msg='Failed to set tags {0} on resource {1}'.format(add_tags, resource))
+ module.fail_json_aws(e, msg=f"Failed to set tags {add_tags} on resource {resource}")
- result['tags'] = get_tags(ecs, module, resource_arn)
+ result["tags"] = get_tags(ecs, module, resource_arn)
module.exit_json(**result)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/ecs_task.py b/ansible_collections/community/aws/plugins/modules/ecs_task.py
index 54948ce21..169ff4c7b 100644
--- a/ansible_collections/community/aws/plugins/modules/ecs_task.py
+++ b/ansible_collections/community/aws/plugins/modules/ecs_task.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: ecs_task
version_added: 1.0.0
@@ -99,13 +97,12 @@ options:
default: false
version_added: 4.1.0
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
+"""
-'''
-
-EXAMPLES = r'''
+EXAMPLES = r"""
# Simple example of run task
- name: Run task
community.aws.ecs_task:
@@ -120,65 +117,66 @@ EXAMPLES = r'''
- name: Start a task
community.aws.ecs_task:
- operation: start
- cluster: console-sample-app-static-cluster
- task_definition: console-sample-app-static-taskdef
- task: "arn:aws:ecs:us-west-2:123456789012:task/3f8353d1-29a8-4689-bbf6-ad79937ffe8a"
- tags:
- resourceName: a_task_for_ansible_to_run
- type: long_running_task
- network: internal
- version: 1.4
- container_instances:
+ operation: start
+ cluster: console-sample-app-static-cluster
+ task_definition: console-sample-app-static-taskdef
+ task: "arn:aws:ecs:us-west-2:123456789012:task/3f8353d1-29a8-4689-bbf6-ad79937ffe8a"
+ tags:
+ resourceName: a_task_for_ansible_to_run
+ type: long_running_task
+ network: internal
+ version: 1.4
+ container_instances:
- arn:aws:ecs:us-west-2:123456789012:container-instance/79c23f22-876c-438a-bddf-55c98a3538a8
- started_by: ansible_user
- network_configuration:
- subnets:
+ started_by: ansible_user
+ network_configuration:
+ subnets:
- subnet-abcd1234
- security_groups:
+ security_groups:
- sg-aaaa1111
- my_security_group
register: task_output
- name: RUN a task on Fargate
community.aws.ecs_task:
- operation: run
- cluster: console-sample-app-static-cluster
- task_definition: console-sample-app-static-taskdef
- task: "arn:aws:ecs:us-west-2:123456789012:task/3f8353d1-29a8-4689-bbf6-ad79937ffe8a"
- started_by: ansible_user
- launch_type: FARGATE
- network_configuration:
- subnets:
+ operation: run
+ cluster: console-sample-app-static-cluster
+ task_definition: console-sample-app-static-taskdef
+ task: "arn:aws:ecs:us-west-2:123456789012:task/3f8353d1-29a8-4689-bbf6-ad79937ffe8a"
+ started_by: ansible_user
+ launch_type: FARGATE
+ network_configuration:
+ subnets:
- subnet-abcd1234
- security_groups:
+ security_groups:
- sg-aaaa1111
- my_security_group
register: task_output
- name: RUN a task on Fargate with public ip assigned
community.aws.ecs_task:
- operation: run
- count: 2
- cluster: console-sample-app-static-cluster
- task_definition: console-sample-app-static-taskdef
- task: "arn:aws:ecs:us-west-2:123456789012:task/3f8353d1-29a8-4689-bbf6-ad79937ffe8a"
- started_by: ansible_user
- launch_type: FARGATE
- network_configuration:
- assign_public_ip: true
- subnets:
+ operation: run
+ count: 2
+ cluster: console-sample-app-static-cluster
+ task_definition: console-sample-app-static-taskdef
+ task: "arn:aws:ecs:us-west-2:123456789012:task/3f8353d1-29a8-4689-bbf6-ad79937ffe8a"
+ started_by: ansible_user
+ launch_type: FARGATE
+ network_configuration:
+ assign_public_ip: true
+ subnets:
- subnet-abcd1234
register: task_output
- name: Stop a task
community.aws.ecs_task:
- operation: stop
- cluster: console-sample-app-static-cluster
- task_definition: console-sample-app-static-taskdef
- task: "arn:aws:ecs:us-west-2:123456789012:task/3f8353d1-29a8-4689-bbf6-ad79937ffe8a"
-'''
-RETURN = r'''
+ operation: stop
+ cluster: console-sample-app-static-cluster
+ task_definition: console-sample-app-static-taskdef
+ task: "arn:aws:ecs:us-west-2:123456789012:task/3f8353d1-29a8-4689-bbf6-ad79937ffe8a"
+"""
+
+RETURN = r"""
task:
description: details about the task that was started
returned: success
@@ -242,45 +240,47 @@ task:
description: The launch type on which to run your task.
returned: always
type: str
-'''
-
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import get_ec2_security_group_ids_from_names, ansible_dict_to_boto3_tag_list
+"""
try:
import botocore
except ImportError:
pass # caught by AnsibleAWSModule
+from ansible_collections.amazon.aws.plugins.module_utils.ec2 import get_ec2_security_group_ids_from_names
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import ansible_dict_to_boto3_tag_list
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
+
class EcsExecManager:
"""Handles ECS Tasks"""
def __init__(self, module):
self.module = module
- self.ecs = module.client('ecs')
- self.ec2 = module.client('ec2')
+ self.ecs = module.client("ecs")
+ self.ec2 = module.client("ec2")
def format_network_configuration(self, network_config):
result = dict()
- if 'subnets' in network_config:
- result['subnets'] = network_config['subnets']
+ if "subnets" in network_config:
+ result["subnets"] = network_config["subnets"]
else:
self.module.fail_json(msg="Network configuration must include subnets")
- if 'security_groups' in network_config:
- groups = network_config['security_groups']
- if any(not sg.startswith('sg-') for sg in groups):
+ if "security_groups" in network_config:
+ groups = network_config["security_groups"]
+ if any(not sg.startswith("sg-") for sg in groups):
try:
- vpc_id = self.ec2.describe_subnets(SubnetIds=[result['subnets'][0]])['Subnets'][0]['VpcId']
+ vpc_id = self.ec2.describe_subnets(SubnetIds=[result["subnets"][0]])["Subnets"][0]["VpcId"]
groups = get_ec2_security_group_ids_from_names(groups, self.ec2, vpc_id)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
self.module.fail_json_aws(e, msg="Couldn't look up security groups")
- result['securityGroups'] = groups
- if 'assign_public_ip' in network_config:
- if network_config['assign_public_ip'] is True:
- result['assignPublicIp'] = "ENABLED"
+ result["securityGroups"] = groups
+ if "assign_public_ip" in network_config:
+ if network_config["assign_public_ip"] is True:
+ result["assignPublicIp"] = "ENABLED"
else:
- result['assignPublicIp'] = "DISABLED"
+ result["assignPublicIp"] = "DISABLED"
return dict(awsvpcConfiguration=result)
@@ -288,10 +288,10 @@ class EcsExecManager:
response = self.ecs.list_tasks(
cluster=cluster_name,
family=service_name,
- desiredStatus=status
+ desiredStatus=status,
)
- if len(response['taskArns']) > 0:
- for c in response['taskArns']:
+ if len(response["taskArns"]) > 0:
+ for c in response["taskArns"]:
if c.endswith(service_name):
return c
return None
@@ -299,14 +299,17 @@ class EcsExecManager:
def run_task(self, cluster, task_definition, overrides, count, startedBy, launch_type, tags):
if overrides is None:
overrides = dict()
- params = dict(cluster=cluster, taskDefinition=task_definition,
- overrides=overrides, count=count, startedBy=startedBy)
- if self.module.params['network_configuration']:
- params['networkConfiguration'] = self.format_network_configuration(self.module.params['network_configuration'])
+ params = dict(
+ cluster=cluster, taskDefinition=task_definition, overrides=overrides, count=count, startedBy=startedBy
+ )
+ if self.module.params["network_configuration"]:
+ params["networkConfiguration"] = self.format_network_configuration(
+ self.module.params["network_configuration"]
+ )
if launch_type:
- params['launchType'] = launch_type
+ params["launchType"] = launch_type
if tags:
- params['tags'] = ansible_dict_to_boto3_tag_list(tags, 'key', 'value')
+ params["tags"] = ansible_dict_to_boto3_tag_list(tags, "key", "value")
# TODO: need to check if long arn format enabled.
try:
@@ -314,168 +317,164 @@ class EcsExecManager:
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
self.module.fail_json_aws(e, msg="Couldn't run task")
# include tasks and failures
- return response['tasks']
+ return response["tasks"]
def start_task(self, cluster, task_definition, overrides, container_instances, startedBy, tags):
args = dict()
if cluster:
- args['cluster'] = cluster
+ args["cluster"] = cluster
if task_definition:
- args['taskDefinition'] = task_definition
+ args["taskDefinition"] = task_definition
if overrides:
- args['overrides'] = overrides
+ args["overrides"] = overrides
if container_instances:
- args['containerInstances'] = container_instances
+ args["containerInstances"] = container_instances
if startedBy:
- args['startedBy'] = startedBy
- if self.module.params['network_configuration']:
- args['networkConfiguration'] = self.format_network_configuration(self.module.params['network_configuration'])
+ args["startedBy"] = startedBy
+ if self.module.params["network_configuration"]:
+ args["networkConfiguration"] = self.format_network_configuration(
+ self.module.params["network_configuration"]
+ )
if tags:
- args['tags'] = ansible_dict_to_boto3_tag_list(tags, 'key', 'value')
+ args["tags"] = ansible_dict_to_boto3_tag_list(tags, "key", "value")
try:
response = self.ecs.start_task(**args)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
self.module.fail_json_aws(e, msg="Couldn't start task")
# include tasks and failures
- return response['tasks']
+ return response["tasks"]
def stop_task(self, cluster, task):
response = self.ecs.stop_task(cluster=cluster, task=task)
- return response['task']
+ return response["task"]
def ecs_task_long_format_enabled(self):
- account_support = self.ecs.list_account_settings(name='taskLongArnFormat', effectiveSettings=True)
- return account_support['settings'][0]['value'] == 'enabled'
+ account_support = self.ecs.list_account_settings(name="taskLongArnFormat", effectiveSettings=True)
+ return account_support["settings"][0]["value"] == "enabled"
def main():
argument_spec = dict(
- operation=dict(required=True, choices=['run', 'start', 'stop']),
- cluster=dict(required=False, type='str', default='default'), # R S P
- task_definition=dict(required=False, type='str'), # R* S*
- overrides=dict(required=False, type='dict'), # R S
- count=dict(required=False, type='int'), # R
- task=dict(required=False, type='str'), # P*
- container_instances=dict(required=False, type='list', elements='str'), # S*
- started_by=dict(required=False, type='str'), # R S
- network_configuration=dict(required=False, type='dict'),
- launch_type=dict(required=False, choices=['EC2', 'FARGATE']),
- tags=dict(required=False, type='dict', aliases=['resource_tags']),
- wait=dict(required=False, default=False, type='bool'),
+ operation=dict(required=True, choices=["run", "start", "stop"]),
+ cluster=dict(required=False, type="str", default="default"), # R S P
+ task_definition=dict(required=False, type="str"), # R* S*
+ overrides=dict(required=False, type="dict"), # R S
+ count=dict(required=False, type="int"), # R
+ task=dict(required=False, type="str"), # P*
+ container_instances=dict(required=False, type="list", elements="str"), # S*
+ started_by=dict(required=False, type="str"), # R S
+ network_configuration=dict(required=False, type="dict"),
+ launch_type=dict(required=False, choices=["EC2", "FARGATE"]),
+ tags=dict(required=False, type="dict", aliases=["resource_tags"]),
+ wait=dict(required=False, default=False, type="bool"),
)
- module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True,
- required_if=[
- ('launch_type', 'FARGATE', ['network_configuration']),
- ('operation', 'run', ['task_definition']),
- ('operation', 'start', [
- 'task_definition',
- 'container_instances'
- ]),
- ('operation', 'stop', ['task_definition', 'task']),
- ])
+ module = AnsibleAWSModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ("launch_type", "FARGATE", ["network_configuration"]),
+ ("operation", "run", ["task_definition"]),
+ ("operation", "start", ["task_definition", "container_instances"]),
+ ("operation", "stop", ["task_definition", "task"]),
+ ],
+ )
# Validate Inputs
- if module.params['operation'] == 'run':
- task_to_list = module.params['task_definition']
+ if module.params["operation"] == "run":
+ task_to_list = module.params["task_definition"]
status_type = "RUNNING"
- if module.params['operation'] == 'start':
- task_to_list = module.params['task']
+ if module.params["operation"] == "start":
+ task_to_list = module.params["task"]
status_type = "RUNNING"
- if module.params['operation'] == 'stop':
- task_to_list = module.params['task_definition']
+ if module.params["operation"] == "stop":
+ task_to_list = module.params["task_definition"]
status_type = "STOPPED"
service_mgr = EcsExecManager(module)
- if module.params['tags']:
+ if module.params["tags"]:
if not service_mgr.ecs_task_long_format_enabled():
module.fail_json(msg="Cannot set task tags: long format task arns are required to set tags")
- existing = service_mgr.list_tasks(module.params['cluster'], task_to_list, status_type)
+ existing = service_mgr.list_tasks(module.params["cluster"], task_to_list, status_type)
results = dict(changed=False)
- if module.params['operation'] == 'run':
+ if module.params["operation"] == "run":
if existing:
# TBD - validate the rest of the details
- results['task'] = existing
+ results["task"] = existing
else:
if not module.check_mode:
-
# run_task returns a list of tasks created
tasks = service_mgr.run_task(
- module.params['cluster'],
- module.params['task_definition'],
- module.params['overrides'],
- module.params['count'],
- module.params['started_by'],
- module.params['launch_type'],
- module.params['tags'],
+ module.params["cluster"],
+ module.params["task_definition"],
+ module.params["overrides"],
+ module.params["count"],
+ module.params["started_by"],
+ module.params["launch_type"],
+ module.params["tags"],
)
# Wait for task(s) to be running prior to exiting
- if module.params['wait']:
-
- waiter = service_mgr.ecs.get_waiter('tasks_running')
+ if module.params["wait"]:
+ waiter = service_mgr.ecs.get_waiter("tasks_running")
try:
waiter.wait(
- tasks=[task['taskArn'] for task in tasks],
- cluster=module.params['cluster'],
+ tasks=[task["taskArn"] for task in tasks],
+ cluster=module.params["cluster"],
)
except botocore.exceptions.WaiterError as e:
- module.fail_json_aws(e, 'Timeout waiting for tasks to run')
+ module.fail_json_aws(e, "Timeout waiting for tasks to run")
- results['task'] = tasks
+ results["task"] = tasks
- results['changed'] = True
+ results["changed"] = True
- elif module.params['operation'] == 'start':
+ elif module.params["operation"] == "start":
if existing:
# TBD - validate the rest of the details
- results['task'] = existing
+ results["task"] = existing
else:
if not module.check_mode:
- results['task'] = service_mgr.start_task(
- module.params['cluster'],
- module.params['task_definition'],
- module.params['overrides'],
- module.params['container_instances'],
- module.params['started_by'],
- module.params['tags'],
+ results["task"] = service_mgr.start_task(
+ module.params["cluster"],
+ module.params["task_definition"],
+ module.params["overrides"],
+ module.params["container_instances"],
+ module.params["started_by"],
+ module.params["tags"],
)
- results['changed'] = True
+ results["changed"] = True
- elif module.params['operation'] == 'stop':
+ elif module.params["operation"] == "stop":
if existing:
- results['task'] = existing
+ results["task"] = existing
else:
if not module.check_mode:
# it exists, so we should delete it and mark changed.
# return info about the cluster deleted
- results['task'] = service_mgr.stop_task(
- module.params['cluster'],
- module.params['task']
- )
+ results["task"] = service_mgr.stop_task(module.params["cluster"], module.params["task"])
# Wait for task to be stopped prior to exiting
- if module.params['wait']:
-
- waiter = service_mgr.ecs.get_waiter('tasks_stopped')
+ if module.params["wait"]:
+ waiter = service_mgr.ecs.get_waiter("tasks_stopped")
try:
waiter.wait(
- tasks=[module.params['task']],
- cluster=module.params['cluster'],
+ tasks=[module.params["task"]],
+ cluster=module.params["cluster"],
)
except botocore.exceptions.WaiterError as e:
- module.fail_json_aws(e, 'Timeout waiting for task to stop')
+ module.fail_json_aws(e, "Timeout waiting for task to stop")
- results['changed'] = True
+ results["changed"] = True
module.exit_json(**results)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/ecs_taskdefinition.py b/ansible_collections/community/aws/plugins/modules/ecs_taskdefinition.py
index a8b5e97d8..25a786e4f 100644
--- a/ansible_collections/community/aws/plugins/modules/ecs_taskdefinition.py
+++ b/ansible_collections/community/aws/plugins/modules/ecs_taskdefinition.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
-# This file is part of Ansible
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
+# -*- coding: utf-8 -*-
+# Copyright: Contributors to the Ansible project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: ecs_taskdefinition
version_added: 1.0.0
@@ -629,50 +627,72 @@ options:
expression:
description: A cluster query language expression to apply to the constraint.
type: str
+ runtime_platform:
+ version_added: 6.4.0
+ description:
+ - runtime platform configuration for the task
+ required: false
+ type: dict
+ default: {
+ "operatingSystemFamily": "LINUX",
+ "cpuArchitecture": "X86_64"
+ }
+ suboptions:
+ cpuArchitecture:
+ description: The CPU Architecture type to be used by the task
+ type: str
+ required: false
+ choices: ['X86_64', 'ARM64']
+ operatingSystemFamily:
+ description: OS type to be used by the task
+ type: str
+ required: false
+ choices: ['LINUX', 'WINDOWS_SERVER_2019_FULL', 'WINDOWS_SERVER_2019_CORE', 'WINDOWS_SERVER_2022_FULL', 'WINDOWS_SERVER_2022_CORE']
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
-'''
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
- name: Create task definition
community.aws.ecs_taskdefinition:
containers:
- - name: simple-app
- cpu: 10
- essential: true
- image: "httpd:2.4"
- memory: 300
- mountPoints:
- - containerPath: /usr/local/apache2/htdocs
- sourceVolume: my-vol
- portMappings:
- - containerPort: 80
- hostPort: 80
- logConfiguration:
- logDriver: awslogs
- options:
- awslogs-group: /ecs/test-cluster-taskdef
- awslogs-region: us-west-2
- awslogs-stream-prefix: ecs
- - name: busybox
- command:
- - >
- /bin/sh -c "while true; do echo '<html><head><title>Amazon ECS Sample App</title></head><body><div><h1>Amazon ECS Sample App</h1><h2>Congratulations!
- </h2><p>Your application is now running on a container in Amazon ECS.</p>' > top; /bin/date > date ; echo '</div></body></html>' > bottom;
- cat top date bottom > /usr/local/apache2/htdocs/index.html ; sleep 1; done"
- cpu: 10
- entryPoint:
- - sh
- - "-c"
- essential: false
- image: busybox
- memory: 200
- volumesFrom:
- - sourceContainer: simple-app
+ - name: simple-app
+ cpu: 10
+ essential: true
+ image: "httpd:2.4"
+ memory: 300
+ mountPoints:
+ - containerPath: /usr/local/apache2/htdocs
+ sourceVolume: my-vol
+ portMappings:
+ - containerPort: 80
+ hostPort: 80
+ logConfiguration:
+ logDriver: awslogs
+ options:
+ awslogs-group: /ecs/test-cluster-taskdef
+ awslogs-region: us-west-2
+ awslogs-stream-prefix: ecs
+ - name: busybox
+ command:
+ - >
+ /bin/sh -c "while true; do echo '<html><head><title>Amazon ECS Sample App</title></head><body><div><h1>Amazon ECS Sample App</h1>
+ <h2>Congratulations!</h2>
+ <p>Your application is now running on a container in Amazon ECS.</p>' > top; /bin/date > date ; echo '</div></body></html>' > bottom;
+ cat top date bottom > /usr/local/apache2/htdocs/index.html ; sleep 1; done"
+ cpu: 10
+ entryPoint:
+ - sh
+ - "-c"
+ essential: false
+ image: busybox
+ memory: 200
+ volumesFrom:
+ - sourceContainer: simple-app
volumes:
- - name: my-vol
+ - name: my-vol
family: test-cluster-taskdef
state: present
register: task_output
@@ -681,26 +701,26 @@ EXAMPLES = r'''
community.aws.ecs_taskdefinition:
family: nginx
containers:
- - name: nginx
- essential: true
- image: "nginx"
- portMappings:
- - containerPort: 8080
- hostPort: 8080
- cpu: 512
- memory: 1024
+ - name: nginx
+ essential: true
+ image: "nginx"
+ portMappings:
+ - containerPort: 8080
+ hostPort: 8080
+ cpu: 512
+ memory: 1024
state: present
- name: Create task definition
community.aws.ecs_taskdefinition:
family: nginx
containers:
- - name: nginx
- essential: true
- image: "nginx"
- portMappings:
- - containerPort: 8080
- hostPort: 8080
+ - name: nginx
+ essential: true
+ image: "nginx"
+ portMappings:
+ - containerPort: 8080
+ hostPort: 8080
launch_type: FARGATE
cpu: 512
memory: 1024
@@ -711,36 +731,36 @@ EXAMPLES = r'''
community.aws.ecs_taskdefinition:
family: nginx
containers:
- - name: nginx
- essential: true
- image: "nginx"
- portMappings:
- - containerPort: 8080
- hostPort: 8080
- cpu: 512
- memory: 1024
- dependsOn:
- - containerName: "simple-app"
- condition: "start"
+ - name: nginx
+ essential: true
+ image: "nginx"
+ portMappings:
+ - containerPort: 8080
+ hostPort: 8080
+ cpu: 512
+ memory: 1024
+ dependsOn:
+ - containerName: "simple-app"
+ condition: "start"
# Create Task Definition with Environment Variables and Secrets
- name: Create task definition
community.aws.ecs_taskdefinition:
family: nginx
containers:
- - name: nginx
- essential: true
- image: "nginx"
- environment:
- - name: "PORT"
- value: "8080"
- secrets:
- # For variables stored in Secrets Manager
- - name: "NGINX_HOST"
- valueFrom: "arn:aws:secretsmanager:us-west-2:123456789012:secret:nginx/NGINX_HOST"
- # For variables stored in Parameter Store
- - name: "API_KEY"
- valueFrom: "arn:aws:ssm:us-west-2:123456789012:parameter/nginx/API_KEY"
+ - name: nginx
+ essential: true
+ image: "nginx"
+ environment:
+ - name: "PORT"
+ value: "8080"
+ secrets:
+ # For variables stored in Secrets Manager
+ - name: "NGINX_HOST"
+ valueFrom: "arn:aws:secretsmanager:us-west-2:123456789012:secret:nginx/NGINX_HOST"
+ # For variables stored in Parameter Store
+ - name: "API_KEY"
+ valueFrom: "arn:aws:ssm:us-west-2:123456789012:parameter/nginx/API_KEY"
launch_type: FARGATE
cpu: 512
memory: 1GB
@@ -752,39 +772,40 @@ EXAMPLES = r'''
community.aws.ecs_taskdefinition:
family: nginx
containers:
- - name: nginx
- essential: true
- image: "nginx"
- portMappings:
- - containerPort: 8080
- hostPort: 8080
- cpu: 512
- memory: 1024
- healthCheck:
- command:
+ - name: nginx
+ essential: true
+ image: "nginx"
+ portMappings:
+ - containerPort: 8080
+ hostPort: 8080
+ cpu: 512
+ memory: 1024
+ healthCheck:
+ command:
- CMD-SHELL
- /app/healthcheck.py
- interval: 60
- retries: 3
- startPeriod: 15
- timeout: 15
+ interval: 60
+ retries: 3
+ startPeriod: 15
+ timeout: 15
state: present
-'''
-RETURN = r'''
+"""
+
+RETURN = r"""
taskdefinition:
description: a reflection of the input parameters
type: dict
returned: always
-'''
+"""
try:
import botocore
except ImportError:
pass # caught by AnsibleAWSModule
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
class EcsTaskManager:
@@ -793,49 +814,65 @@ class EcsTaskManager:
def __init__(self, module):
self.module = module
- self.ecs = module.client('ecs', AWSRetry.jittered_backoff())
+ self.ecs = module.client("ecs", AWSRetry.jittered_backoff())
def describe_task(self, task_name):
try:
response = self.ecs.describe_task_definition(aws_retry=True, taskDefinition=task_name)
- return response['taskDefinition']
+ return response["taskDefinition"]
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
return None
- def register_task(self, family, task_role_arn, execution_role_arn, network_mode, container_definitions,
- volumes, launch_type, cpu, memory, placement_constraints):
+ def register_task(
+ self,
+ family,
+ task_role_arn,
+ execution_role_arn,
+ network_mode,
+ container_definitions,
+ volumes,
+ launch_type,
+ cpu,
+ memory,
+ placement_constraints,
+ runtime_platform,
+ ):
validated_containers = []
# Ensures the number parameters are int as required by the AWS SDK
for container in container_definitions:
- for param in ('memory', 'cpu', 'memoryReservation', 'startTimeout', 'stopTimeout'):
+ for param in ("memory", "cpu", "memoryReservation", "startTimeout", "stopTimeout"):
if param in container:
container[param] = int(container[param])
- if 'portMappings' in container:
- for port_mapping in container['portMappings']:
- for port in ('hostPort', 'containerPort'):
+ if "portMappings" in container:
+ for port_mapping in container["portMappings"]:
+ for port in ("hostPort", "containerPort"):
if port in port_mapping:
port_mapping[port] = int(port_mapping[port])
- if network_mode == 'awsvpc' and 'hostPort' in port_mapping:
- if port_mapping['hostPort'] != port_mapping.get('containerPort'):
- self.module.fail_json(msg="In awsvpc network mode, host port must be set to the same as "
- "container port or not be set")
-
- if 'linuxParameters' in container:
- for linux_param in container.get('linuxParameters'):
- if linux_param == 'tmpfs':
- for tmpfs_param in container['linuxParameters']['tmpfs']:
- if 'size' in tmpfs_param:
- tmpfs_param['size'] = int(tmpfs_param['size'])
-
- for param in ('maxSwap', 'swappiness', 'sharedMemorySize'):
+ if network_mode == "awsvpc" and "hostPort" in port_mapping:
+ if port_mapping["hostPort"] != port_mapping.get("containerPort"):
+ self.module.fail_json(
+ msg=(
+ "In awsvpc network mode, host port must be set to the same as "
+ "container port or not be set"
+ )
+ )
+
+ if "linuxParameters" in container:
+ for linux_param in container.get("linuxParameters"):
+ if linux_param == "tmpfs":
+ for tmpfs_param in container["linuxParameters"]["tmpfs"]:
+ if "size" in tmpfs_param:
+ tmpfs_param["size"] = int(tmpfs_param["size"])
+
+ for param in ("maxSwap", "swappiness", "sharedMemorySize"):
if param in linux_param:
- container['linuxParameters'][param] = int(container['linuxParameters'][param])
+ container["linuxParameters"][param] = int(container["linuxParameters"][param])
- if 'ulimits' in container:
- for limits_mapping in container['ulimits']:
- for limit in ('softLimit', 'hardLimit'):
+ if "ulimits" in container:
+ for limits_mapping in container["ulimits"]:
+ for limit in ("softLimit", "hardLimit"):
if limit in limits_mapping:
limits_mapping[limit] = int(limits_mapping[limit])
@@ -845,47 +882,44 @@ class EcsTaskManager:
family=family,
taskRoleArn=task_role_arn,
containerDefinitions=container_definitions,
- volumes=volumes
+ volumes=volumes,
)
- if network_mode != 'default':
- params['networkMode'] = network_mode
+ if network_mode != "default":
+ params["networkMode"] = network_mode
if cpu:
- params['cpu'] = cpu
+ params["cpu"] = cpu
if memory:
- params['memory'] = memory
+ params["memory"] = memory
if launch_type:
- params['requiresCompatibilities'] = [launch_type]
+ params["requiresCompatibilities"] = [launch_type]
if execution_role_arn:
- params['executionRoleArn'] = execution_role_arn
+ params["executionRoleArn"] = execution_role_arn
if placement_constraints:
- params['placementConstraints'] = placement_constraints
+ params["placementConstraints"] = placement_constraints
+ if runtime_platform:
+ params["runtimePlatform"] = runtime_platform
try:
response = self.ecs.register_task_definition(aws_retry=True, **params)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
self.module.fail_json_aws(e, msg="Failed to register task")
- return response['taskDefinition']
+ return response["taskDefinition"]
def describe_task_definitions(self, family):
- data = {
- "taskDefinitionArns": [],
- "nextToken": None
- }
+ data = {"taskDefinitionArns": [], "nextToken": None}
def fetch():
# Boto3 is weird about params passed, so only pass nextToken if we have a value
- params = {
- 'familyPrefix': family
- }
+ params = {"familyPrefix": family}
- if data['nextToken']:
- params['nextToken'] = data['nextToken']
+ if data["nextToken"]:
+ params["nextToken"] = data["nextToken"]
result = self.ecs.list_task_definitions(**params)
- data['taskDefinitionArns'] += result['taskDefinitionArns']
- data['nextToken'] = result.get('nextToken', None)
- return data['nextToken'] is not None
+ data["taskDefinitionArns"] += result["taskDefinitionArns"]
+ data["nextToken"] = result.get("nextToken", None)
+ return data["nextToken"] is not None
# Fetch all the arns, possibly across multiple pages
while fetch():
@@ -894,118 +928,154 @@ class EcsTaskManager:
# Return the full descriptions of the task definitions, sorted ascending by revision
return list(
sorted(
- [self.ecs.describe_task_definition(taskDefinition=arn)['taskDefinition'] for arn in data['taskDefinitionArns']],
- key=lambda td: td['revision']
+ [
+ self.ecs.describe_task_definition(taskDefinition=arn)["taskDefinition"]
+ for arn in data["taskDefinitionArns"]
+ ],
+ key=lambda td: td["revision"],
)
)
def deregister_task(self, taskArn):
response = self.ecs.deregister_task_definition(taskDefinition=taskArn)
- return response['taskDefinition']
+ return response["taskDefinition"]
def main():
argument_spec = dict(
- state=dict(required=True, choices=['present', 'absent']),
- arn=dict(required=False, type='str'),
- family=dict(required=False, type='str'),
- revision=dict(required=False, type='int'),
- force_create=dict(required=False, default=False, type='bool'),
- containers=dict(required=True, type='list', elements='dict'),
- network_mode=dict(required=False, default='bridge', choices=['default', 'bridge', 'host', 'none', 'awsvpc'], type='str'),
- task_role_arn=dict(required=False, default='', type='str'),
- execution_role_arn=dict(required=False, default='', type='str'),
- volumes=dict(required=False, type='list', elements='dict'),
- launch_type=dict(required=False, choices=['EC2', 'FARGATE']),
+ state=dict(required=True, choices=["present", "absent"]),
+ arn=dict(required=False, type="str"),
+ family=dict(required=False, type="str"),
+ revision=dict(required=False, type="int"),
+ force_create=dict(required=False, default=False, type="bool"),
+ containers=dict(required=True, type="list", elements="dict"),
+ network_mode=dict(
+ required=False, default="bridge", choices=["default", "bridge", "host", "none", "awsvpc"], type="str"
+ ),
+ task_role_arn=dict(required=False, default="", type="str"),
+ execution_role_arn=dict(required=False, default="", type="str"),
+ volumes=dict(required=False, type="list", elements="dict"),
+ launch_type=dict(required=False, choices=["EC2", "FARGATE"]),
cpu=dict(),
- memory=dict(required=False, type='str'),
- placement_constraints=dict(required=False, type='list', elements='dict',
- options=dict(type=dict(type='str'), expression=dict(type='str'))),
+ memory=dict(required=False, type="str"),
+ placement_constraints=dict(
+ required=False,
+ type="list",
+ elements="dict",
+ options=dict(type=dict(type="str"), expression=dict(type="str")),
+ ),
+ runtime_platform=dict(
+ required=False,
+ default={"operatingSystemFamily": "LINUX", "cpuArchitecture": "X86_64"},
+ type="dict",
+ options=dict(
+ cpuArchitecture=dict(required=False, choices=["X86_64", "ARM64"]),
+ operatingSystemFamily=dict(
+ required=False,
+ choices=[
+ "LINUX",
+ "WINDOWS_SERVER_2019_FULL",
+ "WINDOWS_SERVER_2019_CORE",
+ "WINDOWS_SERVER_2022_FULL",
+ "WINDOWS_SERVER_2022_CORE",
+ ],
+ ),
+ ),
+ ),
)
- module = AnsibleAWSModule(argument_spec=argument_spec,
- supports_check_mode=True,
- required_if=[('launch_type', 'FARGATE', ['cpu', 'memory'])]
- )
+ module = AnsibleAWSModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[("launch_type", "FARGATE", ["cpu", "memory"])],
+ )
task_to_describe = None
task_mgr = EcsTaskManager(module)
results = dict(changed=False)
- if module.params['state'] == 'present':
- if 'containers' not in module.params or not module.params['containers']:
+ if module.params["state"] == "present":
+ if "containers" not in module.params or not module.params["containers"]:
module.fail_json(msg="To use task definitions, a list of containers must be specified")
- if 'family' not in module.params or not module.params['family']:
+ if "family" not in module.params or not module.params["family"]:
module.fail_json(msg="To use task definitions, a family must be specified")
- network_mode = module.params['network_mode']
- launch_type = module.params['launch_type']
- placement_constraints = module.params['placement_constraints']
- if launch_type == 'FARGATE':
- if network_mode != 'awsvpc':
+ network_mode = module.params["network_mode"]
+ launch_type = module.params["launch_type"]
+ placement_constraints = module.params["placement_constraints"]
+ if launch_type == "FARGATE":
+ if network_mode != "awsvpc":
module.fail_json(msg="To use FARGATE launch type, network_mode must be awsvpc")
if placement_constraints:
module.fail_json(msg="Task placement constraints are not supported for tasks run on Fargate")
- for container in module.params['containers']:
- if container.get('links') and network_mode == 'awsvpc':
- module.fail_json(msg='links parameter is not supported if network mode is awsvpc.')
+ for container in module.params["containers"]:
+ if container.get("links") and network_mode == "awsvpc":
+ module.fail_json(msg="links parameter is not supported if network mode is awsvpc.")
- for environment in container.get('environment', []):
- environment['value'] = environment['value']
+ for environment in container.get("environment", []):
+ environment["value"] = environment["value"]
- for environment_file in container.get('environmentFiles', []):
- if environment_file['type'] != 's3':
- module.fail_json(msg='The only supported value for environmentFiles is s3.')
+ for environment_file in container.get("environmentFiles", []):
+ if environment_file["type"] != "s3":
+ module.fail_json(msg="The only supported value for environmentFiles is s3.")
- for linux_param in container.get('linuxParameters', {}):
- if linux_param == 'maxSwap' and launch_type == 'FARGATE':
- module.fail_json(msg='devices parameter is not supported with the FARGATE launch type.')
+ for linux_param in container.get("linuxParameters", {}):
+ if linux_param == "maxSwap" and launch_type == "FARGATE":
+ module.fail_json(msg="devices parameter is not supported with the FARGATE launch type.")
- if linux_param == 'maxSwap' and launch_type == 'FARGATE':
- module.fail_json(msg='maxSwap parameter is not supported with the FARGATE launch type.')
- elif linux_param == 'maxSwap' and int(container['linuxParameters']['maxSwap']) < 0:
- module.fail_json(msg='Accepted values for maxSwap are 0 or any positive integer.')
+ if linux_param == "maxSwap" and launch_type == "FARGATE":
+ module.fail_json(msg="maxSwap parameter is not supported with the FARGATE launch type.")
+ elif linux_param == "maxSwap" and int(container["linuxParameters"]["maxSwap"]) < 0:
+ module.fail_json(msg="Accepted values for maxSwap are 0 or any positive integer.")
- if (
- linux_param == 'swappiness' and
- (int(container['linuxParameters']['swappiness']) < 0 or int(container['linuxParameters']['swappiness']) > 100)
+ if linux_param == "swappiness" and (
+ int(container["linuxParameters"]["swappiness"]) < 0
+ or int(container["linuxParameters"]["swappiness"]) > 100
):
- module.fail_json(msg='Accepted values for swappiness are whole numbers between 0 and 100.')
+ module.fail_json(msg="Accepted values for swappiness are whole numbers between 0 and 100.")
- if linux_param == 'sharedMemorySize' and launch_type == 'FARGATE':
- module.fail_json(msg='sharedMemorySize parameter is not supported with the FARGATE launch type.')
+ if linux_param == "sharedMemorySize" and launch_type == "FARGATE":
+ module.fail_json(msg="sharedMemorySize parameter is not supported with the FARGATE launch type.")
- if linux_param == 'tmpfs' and launch_type == 'FARGATE':
- module.fail_json(msg='tmpfs parameter is not supported with the FARGATE launch type.')
+ if linux_param == "tmpfs" and launch_type == "FARGATE":
+ module.fail_json(msg="tmpfs parameter is not supported with the FARGATE launch type.")
- if container.get('hostname') and network_mode == 'awsvpc':
- module.fail_json(msg='hostname parameter is not supported when the awsvpc network mode is used.')
+ if container.get("hostname") and network_mode == "awsvpc":
+ module.fail_json(msg="hostname parameter is not supported when the awsvpc network mode is used.")
- if container.get('extraHosts') and network_mode == 'awsvpc':
- module.fail_json(msg='extraHosts parameter is not supported when the awsvpc network mode is used.')
+ if container.get("extraHosts") and network_mode == "awsvpc":
+ module.fail_json(msg="extraHosts parameter is not supported when the awsvpc network mode is used.")
- family = module.params['family']
- existing_definitions_in_family = task_mgr.describe_task_definitions(module.params['family'])
+ family = module.params["family"]
+ existing_definitions_in_family = task_mgr.describe_task_definitions(module.params["family"])
- if 'revision' in module.params and module.params['revision']:
+ if "revision" in module.params and module.params["revision"]:
# The definition specifies revision. We must guarantee that an active revision of that number will result from this.
- revision = int(module.params['revision'])
+ revision = int(module.params["revision"])
# A revision has been explicitly specified. Attempt to locate a matching revision
- tasks_defs_for_revision = [td for td in existing_definitions_in_family if td['revision'] == revision]
+ tasks_defs_for_revision = [td for td in existing_definitions_in_family if td["revision"] == revision]
existing = tasks_defs_for_revision[0] if len(tasks_defs_for_revision) > 0 else None
- if existing and existing['status'] != "ACTIVE":
+ if existing and existing["status"] != "ACTIVE":
# We cannot reactivate an inactive revision
- module.fail_json(msg="A task in family '%s' already exists for revision %d, but it is inactive" % (family, revision))
+ module.fail_json(
+ msg=f"A task in family '{family}' already exists for revision {int(revision)}, but it is inactive"
+ )
elif not existing:
if not existing_definitions_in_family and revision != 1:
- module.fail_json(msg="You have specified a revision of %d but a created revision would be 1" % revision)
- elif existing_definitions_in_family and existing_definitions_in_family[-1]['revision'] + 1 != revision:
- module.fail_json(msg="You have specified a revision of %d but a created revision would be %d" %
- (revision, existing_definitions_in_family[-1]['revision'] + 1))
+ module.fail_json(
+ msg=f"You have specified a revision of {int(revision)} but a created revision would be 1"
+ )
+ elif existing_definitions_in_family and existing_definitions_in_family[-1]["revision"] + 1 != revision:
+ module.fail_json(
+ msg=(
+ f"You have specified a revision of {int(revision)} but a created revision would be"
+ f" {int(existing_definitions_in_family[-1]['revision'] + 1)}"
+ )
+ )
else:
existing = None
@@ -1025,9 +1095,9 @@ def main():
if list_val not in right_list:
# if list_val is the port mapping, the key 'protocol' may be absent (but defaults to 'tcp')
# fill in that default if absent and see if it is in right_list then
- if isinstance(list_val, dict) and not list_val.get('protocol'):
+ if isinstance(list_val, dict) and not list_val.get("protocol"):
modified_list_val = dict(list_val)
- modified_list_val.update(protocol='tcp')
+ modified_list_val.update(protocol="tcp")
if modified_list_val in right_list:
continue
else:
@@ -1037,24 +1107,32 @@ def main():
for k, v in right.items():
if v and k not in left:
# 'essential' defaults to True when not specified
- if k == 'essential' and v is True:
+ if k == "essential" and v is True:
pass
else:
return False
return True
- def _task_definition_matches(requested_volumes, requested_containers, requested_task_role_arn, requested_launch_type, existing_task_definition):
- if td['status'] != "ACTIVE":
+ def _task_definition_matches(
+ requested_volumes,
+ requested_containers,
+ requested_task_role_arn,
+ requested_launch_type,
+ existing_task_definition,
+ ):
+ if td["status"] != "ACTIVE":
return None
- if requested_task_role_arn != td.get('taskRoleArn', ""):
+ if requested_task_role_arn != td.get("taskRoleArn", ""):
return None
- if requested_launch_type is not None and requested_launch_type not in td.get('requiresCompatibilities', []):
+ if requested_launch_type is not None and requested_launch_type not in td.get(
+ "requiresCompatibilities", []
+ ):
return None
- existing_volumes = td.get('volumes', []) or []
+ existing_volumes = td.get("volumes", []) or []
if len(requested_volumes) != len(existing_volumes):
# Nope.
@@ -1072,7 +1150,7 @@ def main():
if not found:
return None
- existing_containers = td.get('containerDefinitions', []) or []
+ existing_containers = td.get("containerDefinitions", []) or []
if len(requested_containers) != len(existing_containers):
# Nope.
@@ -1093,42 +1171,51 @@ def main():
# No revision explicitly specified. Attempt to find an active, matching revision that has all the properties requested
for td in existing_definitions_in_family:
- requested_volumes = module.params['volumes'] or []
- requested_containers = module.params['containers'] or []
- requested_task_role_arn = module.params['task_role_arn']
- requested_launch_type = module.params['launch_type']
- existing = _task_definition_matches(requested_volumes, requested_containers, requested_task_role_arn, requested_launch_type, td)
+ requested_volumes = module.params["volumes"] or []
+ requested_containers = module.params["containers"] or []
+ requested_task_role_arn = module.params["task_role_arn"]
+ requested_launch_type = module.params["launch_type"]
+ existing = _task_definition_matches(
+ requested_volumes, requested_containers, requested_task_role_arn, requested_launch_type, td
+ )
if existing:
break
- if existing and not module.params.get('force_create'):
+ if existing and not module.params.get("force_create"):
# Awesome. Have an existing one. Nothing to do.
- results['taskdefinition'] = existing
+ results["taskdefinition"] = existing
else:
if not module.check_mode:
# Doesn't exist. create it.
- volumes = module.params.get('volumes', []) or []
- results['taskdefinition'] = task_mgr.register_task(module.params['family'],
- module.params['task_role_arn'],
- module.params['execution_role_arn'],
- module.params['network_mode'],
- module.params['containers'],
- volumes,
- module.params['launch_type'],
- module.params['cpu'],
- module.params['memory'],
- module.params['placement_constraints'],)
- results['changed'] = True
-
- elif module.params['state'] == 'absent':
+ volumes = module.params.get("volumes", []) or []
+ results["taskdefinition"] = task_mgr.register_task(
+ module.params["family"],
+ module.params["task_role_arn"],
+ module.params["execution_role_arn"],
+ module.params["network_mode"],
+ module.params["containers"],
+ volumes,
+ module.params["launch_type"],
+ module.params["cpu"],
+ module.params["memory"],
+ module.params["placement_constraints"],
+ module.params["runtime_platform"],
+ )
+ results["changed"] = True
+
+ elif module.params["state"] == "absent":
# When de-registering a task definition, we can specify the ARN OR the family and revision.
- if module.params['state'] == 'absent':
- if 'arn' in module.params and module.params['arn'] is not None:
- task_to_describe = module.params['arn']
- elif 'family' in module.params and module.params['family'] is not None and 'revision' in module.params and \
- module.params['revision'] is not None:
- task_to_describe = module.params['family'] + ":" + str(module.params['revision'])
+ if module.params["state"] == "absent":
+ if "arn" in module.params and module.params["arn"] is not None:
+ task_to_describe = module.params["arn"]
+ elif (
+ "family" in module.params
+ and module.params["family"] is not None
+ and "revision" in module.params
+ and module.params["revision"] is not None
+ ):
+ task_to_describe = module.params["family"] + ":" + str(module.params["revision"])
else:
module.fail_json(msg="To use task definitions, an arn or family and revision must be specified")
@@ -1138,16 +1225,16 @@ def main():
pass
else:
# It exists, so we should delete it and mark changed. Return info about the task definition deleted
- results['taskdefinition'] = existing
- if 'status' in existing and existing['status'] == "INACTIVE":
- results['changed'] = False
+ results["taskdefinition"] = existing
+ if "status" in existing and existing["status"] == "INACTIVE":
+ results["changed"] = False
else:
if not module.check_mode:
task_mgr.deregister_task(task_to_describe)
- results['changed'] = True
+ results["changed"] = True
module.exit_json(**results)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/ecs_taskdefinition_info.py b/ansible_collections/community/aws/plugins/modules/ecs_taskdefinition_info.py
index 6fbc41731..5e235096d 100644
--- a/ansible_collections/community/aws/plugins/modules/ecs_taskdefinition_info.py
+++ b/ansible_collections/community/aws/plugins/modules/ecs_taskdefinition_info.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: ecs_taskdefinition_info
version_added: 1.0.0
@@ -27,20 +25,19 @@ options:
required: true
type: str
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
-
-'''
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide for details.
- community.aws.ecs_taskdefinition_info:
task_definition: test-td
-'''
+"""
-RETURN = '''
+RETURN = r"""
container_definitions:
description: Returns a list of complex objects representing the containers
returned: success
@@ -348,33 +345,34 @@ placement_constraints:
description: A cluster query language expression to apply to the constraint.
returned: when present
type: str
-'''
-
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict
+"""
try:
import botocore
except ImportError:
pass # caught by AnsibleAWSModule
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
+
def main():
argument_spec = dict(
- task_definition=dict(required=True, type='str')
+ task_definition=dict(required=True, type="str"),
)
module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
- ecs = module.client('ecs')
+ ecs = module.client("ecs")
try:
- ecs_td = ecs.describe_task_definition(taskDefinition=module.params['task_definition'])['taskDefinition']
+ ecs_td = ecs.describe_task_definition(taskDefinition=module.params["task_definition"])["taskDefinition"]
except botocore.exceptions.ClientError:
ecs_td = {}
module.exit_json(changed=False, **camel_dict_to_snake_dict(ecs_td))
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/efs.py b/ansible_collections/community/aws/plugins/modules/efs.py
index de1d563fb..6b9390f2b 100644
--- a/ansible_collections/community/aws/plugins/modules/efs.py
+++ b/ansible_collections/community/aws/plugins/modules/efs.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: efs
version_added: 1.0.0
@@ -102,34 +100,33 @@ options:
version_added: 2.1.0
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.tags
- amazon.aws.boto3
+"""
-'''
-
-EXAMPLES = r'''
+EXAMPLES = r"""
- name: EFS provisioning
community.aws.efs:
state: present
name: myTestEFS
tags:
- Name: myTestNameTag
- purpose: file-storage
+ Name: myTestNameTag
+ purpose: file-storage
targets:
- - subnet_id: subnet-748c5d03
- security_groups: [ "sg-1a2b3c4d" ]
+ - subnet_id: subnet-748c5d03
+ security_groups: ["sg-1a2b3c4d"]
- name: Modifying EFS data
community.aws.efs:
state: present
name: myTestEFS
tags:
- name: myAnotherTestTag
+ name: myAnotherTestTag
targets:
- - subnet_id: subnet-7654fdca
- security_groups: [ "sg-4c5d6f7a" ]
+ - subnet_id: subnet-7654fdca
+ security_groups: ["sg-4c5d6f7a"]
- name: Set a lifecycle policy
community.aws.efs:
@@ -137,8 +134,8 @@ EXAMPLES = r'''
name: myTestEFS
transition_to_ia: 7
targets:
- - subnet_id: subnet-7654fdca
- security_groups: [ "sg-4c5d6f7a" ]
+ - subnet_id: subnet-7654fdca
+ security_groups: ["sg-4c5d6f7a"]
- name: Remove a lifecycle policy
community.aws.efs:
@@ -146,16 +143,16 @@ EXAMPLES = r'''
name: myTestEFS
transition_to_ia: None
targets:
- - subnet_id: subnet-7654fdca
- security_groups: [ "sg-4c5d6f7a" ]
+ - subnet_id: subnet-7654fdca
+ security_groups: ["sg-4c5d6f7a"]
- name: Deleting EFS
community.aws.efs:
state: absent
name: myTestEFS
-'''
+"""
-RETURN = r'''
+RETURN = r"""
creation_time:
description: timestamp of creation date
returned: always
@@ -244,8 +241,7 @@ tags:
"name": "my-efs",
"key": "Value"
}
-
-'''
+"""
from time import sleep
from time import time as timestamp
@@ -257,11 +253,12 @@ except ImportError as e:
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_tag_list
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import compare_aws_tags
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import ansible_dict_to_boto3_tag_list
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import compare_aws_tags
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def _index_by_key(key, items):
@@ -269,35 +266,34 @@ def _index_by_key(key, items):
class EFSConnection(object):
-
DEFAULT_WAIT_TIMEOUT_SECONDS = 0
- STATE_CREATING = 'creating'
- STATE_AVAILABLE = 'available'
- STATE_DELETING = 'deleting'
- STATE_DELETED = 'deleted'
+ STATE_CREATING = "creating"
+ STATE_AVAILABLE = "available"
+ STATE_DELETING = "deleting"
+ STATE_DELETED = "deleted"
def __init__(self, module):
- self.connection = module.client('efs')
+ self.connection = module.client("efs")
region = module.region
self.module = module
self.region = region
- self.wait = module.params.get('wait')
- self.wait_timeout = module.params.get('wait_timeout')
+ self.wait = module.params.get("wait")
+ self.wait_timeout = module.params.get("wait_timeout")
def get_file_systems(self, **kwargs):
"""
- Returns generator of file systems including all attributes of FS
+ Returns generator of file systems including all attributes of FS
"""
items = iterate_all(
- 'FileSystems',
+ "FileSystems",
self.connection.describe_file_systems,
- **kwargs
+ **kwargs,
)
for item in items:
- item['Name'] = item['CreationToken']
- item['CreationTime'] = str(item['CreationTime'])
+ item["Name"] = item["CreationToken"]
+ item["CreationTime"] = str(item["CreationTime"])
"""
In the time when MountPoint was introduced there was a need to add a suffix of network path before one could use it
AWS updated it and now there is no need to add a suffix. MountPoint is left for back-compatibility purpose
@@ -305,90 +301,92 @@ class EFSConnection(object):
AWS documentation is available here:
https://docs.aws.amazon.com/efs/latest/ug/gs-step-three-connect-to-ec2-instance.html
"""
- item['MountPoint'] = '.%s.efs.%s.amazonaws.com:/' % (item['FileSystemId'], self.region)
- item['FilesystemAddress'] = '%s.efs.%s.amazonaws.com:/' % (item['FileSystemId'], self.region)
- if 'Timestamp' in item['SizeInBytes']:
- item['SizeInBytes']['Timestamp'] = str(item['SizeInBytes']['Timestamp'])
- if item['LifeCycleState'] == self.STATE_AVAILABLE:
- item['Tags'] = self.get_tags(FileSystemId=item['FileSystemId'])
- item['MountTargets'] = list(self.get_mount_targets(FileSystemId=item['FileSystemId']))
+ item["MountPoint"] = f".{item['FileSystemId']}.efs.{self.region}.amazonaws.com:/"
+ item["FilesystemAddress"] = f"{item['FileSystemId']}.efs.{self.region}.amazonaws.com:/"
+ if "Timestamp" in item["SizeInBytes"]:
+ item["SizeInBytes"]["Timestamp"] = str(item["SizeInBytes"]["Timestamp"])
+ if item["LifeCycleState"] == self.STATE_AVAILABLE:
+ item["Tags"] = self.get_tags(FileSystemId=item["FileSystemId"])
+ item["MountTargets"] = list(self.get_mount_targets(FileSystemId=item["FileSystemId"]))
else:
- item['Tags'] = {}
- item['MountTargets'] = []
+ item["Tags"] = {}
+ item["MountTargets"] = []
yield item
def get_tags(self, **kwargs):
"""
- Returns tag list for selected instance of EFS
+ Returns tag list for selected instance of EFS
"""
- tags = self.connection.describe_tags(**kwargs)['Tags']
+ tags = self.connection.describe_tags(**kwargs)["Tags"]
return tags
def get_mount_targets(self, **kwargs):
"""
- Returns mount targets for selected instance of EFS
+ Returns mount targets for selected instance of EFS
"""
targets = iterate_all(
- 'MountTargets',
+ "MountTargets",
self.connection.describe_mount_targets,
- **kwargs
+ **kwargs,
)
for target in targets:
- if target['LifeCycleState'] == self.STATE_AVAILABLE:
- target['SecurityGroups'] = list(self.get_security_groups(
- MountTargetId=target['MountTargetId']
- ))
+ if target["LifeCycleState"] == self.STATE_AVAILABLE:
+ target["SecurityGroups"] = list(self.get_security_groups(MountTargetId=target["MountTargetId"]))
else:
- target['SecurityGroups'] = []
+ target["SecurityGroups"] = []
yield target
def get_security_groups(self, **kwargs):
"""
- Returns security groups for selected instance of EFS
+ Returns security groups for selected instance of EFS
"""
return iterate_all(
- 'SecurityGroups',
+ "SecurityGroups",
self.connection.describe_mount_target_security_groups,
- **kwargs
+ **kwargs,
)
def get_file_system_id(self, name):
"""
- Returns ID of instance by instance name
+ Returns ID of instance by instance name
"""
- info = first_or_default(iterate_all(
- 'FileSystems',
- self.connection.describe_file_systems,
- CreationToken=name
- ))
- return info and info['FileSystemId'] or None
+ info = first_or_default(
+ iterate_all(
+ "FileSystems",
+ self.connection.describe_file_systems,
+ CreationToken=name,
+ )
+ )
+ return info and info["FileSystemId"] or None
def get_file_system_state(self, name, file_system_id=None):
"""
- Returns state of filesystem by EFS id/name
+ Returns state of filesystem by EFS id/name
"""
- info = first_or_default(iterate_all(
- 'FileSystems',
- self.connection.describe_file_systems,
- CreationToken=name,
- FileSystemId=file_system_id
- ))
- return info and info['LifeCycleState'] or self.STATE_DELETED
+ info = first_or_default(
+ iterate_all(
+ "FileSystems",
+ self.connection.describe_file_systems,
+ CreationToken=name,
+ FileSystemId=file_system_id,
+ )
+ )
+ return info and info["LifeCycleState"] or self.STATE_DELETED
def get_mount_targets_in_state(self, file_system_id, states=None):
"""
- Returns states of mount targets of selected EFS with selected state(s) (optional)
+ Returns states of mount targets of selected EFS with selected state(s) (optional)
"""
targets = iterate_all(
- 'MountTargets',
+ "MountTargets",
self.connection.describe_mount_targets,
- FileSystemId=file_system_id
+ FileSystemId=file_system_id,
)
if states:
if not isinstance(states, list):
states = [states]
- targets = filter(lambda target: target['LifeCycleState'] in states, targets)
+ targets = filter(lambda target: target["LifeCycleState"] in states, targets)
return list(targets)
@@ -396,47 +394,53 @@ class EFSConnection(object):
"""
Returns throughput mode for selected EFS instance
"""
- info = first_or_default(iterate_all(
- 'FileSystems',
- self.connection.describe_file_systems,
- **kwargs
- ))
+ info = first_or_default(
+ iterate_all(
+ "FileSystems",
+ self.connection.describe_file_systems,
+ **kwargs,
+ )
+ )
- return info and info['ThroughputMode'] or None
+ return info and info["ThroughputMode"] or None
def get_provisioned_throughput_in_mibps(self, **kwargs):
"""
Returns throughput mode for selected EFS instance
"""
- info = first_or_default(iterate_all(
- 'FileSystems',
- self.connection.describe_file_systems,
- **kwargs
- ))
- return info.get('ProvisionedThroughputInMibps', None)
+ info = first_or_default(
+ iterate_all(
+ "FileSystems",
+ self.connection.describe_file_systems,
+ **kwargs,
+ )
+ )
+ return info.get("ProvisionedThroughputInMibps", None)
- def create_file_system(self, name, performance_mode, encrypt, kms_key_id, throughput_mode, provisioned_throughput_in_mibps):
+ def create_file_system(
+ self, name, performance_mode, encrypt, kms_key_id, throughput_mode, provisioned_throughput_in_mibps
+ ):
"""
- Creates new filesystem with selected name
+ Creates new filesystem with selected name
"""
changed = False
state = self.get_file_system_state(name)
params = {}
- params['CreationToken'] = name
- params['PerformanceMode'] = performance_mode
+ params["CreationToken"] = name
+ params["PerformanceMode"] = performance_mode
if encrypt:
- params['Encrypted'] = encrypt
+ params["Encrypted"] = encrypt
if kms_key_id is not None:
- params['KmsKeyId'] = kms_key_id
+ params["KmsKeyId"] = kms_key_id
if throughput_mode:
- params['ThroughputMode'] = throughput_mode
+ params["ThroughputMode"] = throughput_mode
if provisioned_throughput_in_mibps:
- params['ProvisionedThroughputInMibps'] = provisioned_throughput_in_mibps
+ params["ProvisionedThroughputInMibps"] = provisioned_throughput_in_mibps
if state in [self.STATE_DELETING, self.STATE_DELETED]:
wait_for(
lambda: self.get_file_system_state(name),
- self.STATE_DELETED
+ self.STATE_DELETED,
)
try:
self.connection.create_file_system(**params)
@@ -450,7 +454,7 @@ class EFSConnection(object):
wait_for(
lambda: self.get_file_system_state(name),
self.STATE_AVAILABLE,
- self.wait_timeout
+ self.wait_timeout,
)
return changed
@@ -467,14 +471,14 @@ class EFSConnection(object):
current_throughput = self.get_provisioned_throughput_in_mibps(FileSystemId=fs_id)
params = dict()
if throughput_mode and throughput_mode != current_mode:
- params['ThroughputMode'] = throughput_mode
+ params["ThroughputMode"] = throughput_mode
if provisioned_throughput_in_mibps and provisioned_throughput_in_mibps != current_throughput:
- params['ProvisionedThroughputInMibps'] = provisioned_throughput_in_mibps
+ params["ProvisionedThroughputInMibps"] = provisioned_throughput_in_mibps
if len(params) > 0:
wait_for(
lambda: self.get_file_system_state(name),
self.STATE_AVAILABLE,
- self.wait_timeout
+ self.wait_timeout,
)
try:
self.connection.update_file_system(FileSystemId=fs_id, **params)
@@ -492,11 +496,11 @@ class EFSConnection(object):
if state in [self.STATE_AVAILABLE, self.STATE_CREATING]:
fs_id = self.get_file_system_id(name)
current_policies = self.connection.describe_lifecycle_configuration(FileSystemId=fs_id)
- if transition_to_ia == 'None':
+ if transition_to_ia == "None":
LifecyclePolicies = []
else:
- LifecyclePolicies = [{'TransitionToIA': 'AFTER_' + transition_to_ia + '_DAYS'}]
- if current_policies.get('LifecyclePolicies') != LifecyclePolicies:
+ LifecyclePolicies = [{"TransitionToIA": "AFTER_" + transition_to_ia + "_DAYS"}]
+ if current_policies.get("LifecyclePolicies") != LifecyclePolicies:
response = self.connection.put_lifecycle_configuration(
FileSystemId=fs_id,
LifecyclePolicies=LifecyclePolicies,
@@ -506,20 +510,19 @@ class EFSConnection(object):
def converge_file_system(self, name, tags, purge_tags, targets, throughput_mode, provisioned_throughput_in_mibps):
"""
- Change attributes (mount targets and tags) of filesystem by name
+ Change attributes (mount targets and tags) of filesystem by name
"""
result = False
fs_id = self.get_file_system_id(name)
if tags is not None:
- tags_need_modify, tags_to_delete = compare_aws_tags(boto3_tag_list_to_ansible_dict(self.get_tags(FileSystemId=fs_id)), tags, purge_tags)
+ tags_need_modify, tags_to_delete = compare_aws_tags(
+ boto3_tag_list_to_ansible_dict(self.get_tags(FileSystemId=fs_id)), tags, purge_tags
+ )
if tags_to_delete:
try:
- self.connection.delete_tags(
- FileSystemId=fs_id,
- TagKeys=tags_to_delete
- )
+ self.connection.delete_tags(FileSystemId=fs_id, TagKeys=tags_to_delete)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
self.module.fail_json_aws(e, msg="Unable to delete tags.")
@@ -528,8 +531,7 @@ class EFSConnection(object):
if tags_need_modify:
try:
self.connection.create_tags(
- FileSystemId=fs_id,
- Tags=ansible_dict_to_boto3_tag_list(tags_need_modify)
+ FileSystemId=fs_id, Tags=ansible_dict_to_boto3_tag_list(tags_need_modify)
)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
self.module.fail_json_aws(e, msg="Unable to create tags.")
@@ -540,54 +542,56 @@ class EFSConnection(object):
incomplete_states = [self.STATE_CREATING, self.STATE_DELETING]
wait_for(
lambda: len(self.get_mount_targets_in_state(fs_id, incomplete_states)),
- 0
+ 0,
)
- current_targets = _index_by_key('SubnetId', self.get_mount_targets(FileSystemId=fs_id))
- targets = _index_by_key('SubnetId', targets)
+ current_targets = _index_by_key("SubnetId", self.get_mount_targets(FileSystemId=fs_id))
+ targets = _index_by_key("SubnetId", targets)
- targets_to_create, intersection, targets_to_delete = dict_diff(current_targets,
- targets, True)
+ targets_to_create, intersection, targets_to_delete = dict_diff(current_targets, targets, True)
# To modify mount target it should be deleted and created again
- changed = [sid for sid in intersection if not targets_equal(['SubnetId', 'IpAddress', 'NetworkInterfaceId'],
- current_targets[sid], targets[sid])]
+ changed = [
+ sid
+ for sid in intersection
+ if not targets_equal(
+ ["SubnetId", "IpAddress", "NetworkInterfaceId"], current_targets[sid], targets[sid]
+ )
+ ]
targets_to_delete = list(targets_to_delete) + changed
targets_to_create = list(targets_to_create) + changed
if targets_to_delete:
for sid in targets_to_delete:
- self.connection.delete_mount_target(
- MountTargetId=current_targets[sid]['MountTargetId']
- )
+ self.connection.delete_mount_target(MountTargetId=current_targets[sid]["MountTargetId"])
wait_for(
lambda: len(self.get_mount_targets_in_state(fs_id, incomplete_states)),
- 0
+ 0,
)
result = True
if targets_to_create:
for sid in targets_to_create:
- self.connection.create_mount_target(
- FileSystemId=fs_id,
- **targets[sid]
- )
+ self.connection.create_mount_target(FileSystemId=fs_id, **targets[sid])
wait_for(
lambda: len(self.get_mount_targets_in_state(fs_id, incomplete_states)),
0,
- self.wait_timeout
+ self.wait_timeout,
)
result = True
# If no security groups were passed into the module, then do not change it.
- security_groups_to_update = [sid for sid in intersection if
- 'SecurityGroups' in targets[sid] and
- current_targets[sid]['SecurityGroups'] != targets[sid]['SecurityGroups']]
+ security_groups_to_update = [
+ sid
+ for sid in intersection
+ if "SecurityGroups" in targets[sid]
+ and current_targets[sid]["SecurityGroups"] != targets[sid]["SecurityGroups"]
+ ]
if security_groups_to_update:
for sid in security_groups_to_update:
self.connection.modify_mount_target_security_groups(
- MountTargetId=current_targets[sid]['MountTargetId'],
- SecurityGroups=targets[sid].get('SecurityGroups', None)
+ MountTargetId=current_targets[sid]["MountTargetId"],
+ SecurityGroups=targets[sid].get("SecurityGroups", None),
)
result = True
@@ -595,14 +599,14 @@ class EFSConnection(object):
def delete_file_system(self, name, file_system_id=None):
"""
- Removes EFS instance by id/name
+ Removes EFS instance by id/name
"""
result = False
state = self.get_file_system_state(name, file_system_id)
if state in [self.STATE_CREATING, self.STATE_AVAILABLE]:
wait_for(
lambda: self.get_file_system_state(name),
- self.STATE_AVAILABLE
+ self.STATE_AVAILABLE,
)
if not file_system_id:
file_system_id = self.get_file_system_id(name)
@@ -614,27 +618,27 @@ class EFSConnection(object):
wait_for(
lambda: self.get_file_system_state(name),
self.STATE_DELETED,
- self.wait_timeout
+ self.wait_timeout,
)
return result
def delete_mount_targets(self, file_system_id):
"""
- Removes mount targets by EFS id
+ Removes mount targets by EFS id
"""
wait_for(
lambda: len(self.get_mount_targets_in_state(file_system_id, self.STATE_CREATING)),
- 0
+ 0,
)
targets = self.get_mount_targets_in_state(file_system_id, self.STATE_AVAILABLE)
for target in targets:
- self.connection.delete_mount_target(MountTargetId=target['MountTargetId'])
+ self.connection.delete_mount_target(MountTargetId=target["MountTargetId"])
wait_for(
lambda: len(self.get_mount_targets_in_state(file_system_id, self.STATE_DELETING)),
- 0
+ 0,
)
return len(targets) > 0
@@ -642,7 +646,7 @@ class EFSConnection(object):
def iterate_all(attr, map_method, **kwargs):
"""
- Method creates iterator from result set
+ Method creates iterator from result set
"""
args = dict((key, value) for (key, value) in kwargs.items() if value is not None)
wait = 1
@@ -651,11 +655,11 @@ def iterate_all(attr, map_method, **kwargs):
data = map_method(**args)
for elm in data[attr]:
yield elm
- if 'NextMarker' in data:
- args['Marker'] = data['Nextmarker']
+ if "NextMarker" in data:
+ args["Marker"] = data["Nextmarker"]
continue
break
- except is_boto3_error_code('ThrottlingException'):
+ except is_boto3_error_code("ThrottlingException"):
if wait < 600:
sleep(wait)
wait = wait * 2
@@ -666,7 +670,7 @@ def iterate_all(attr, map_method, **kwargs):
def targets_equal(keys, a, b):
"""
- Method compare two mount targets by specified attributes
+ Method compare two mount targets by specified attributes
"""
for key in keys:
if key in b and a[key] != b[key]:
@@ -677,7 +681,7 @@ def targets_equal(keys, a, b):
def dict_diff(dict1, dict2, by_key=False):
"""
- Helper method to calculate difference of two dictionaries
+ Helper method to calculate difference of two dictionaries
"""
keys1 = set(dict1.keys() if by_key else dict1.items())
keys2 = set(dict2.keys() if by_key else dict2.items())
@@ -689,7 +693,7 @@ def dict_diff(dict1, dict2, by_key=False):
def first_or_default(items, default=None):
"""
- Helper method to fetch first element of list (if exists)
+ Helper method to fetch first element of list (if exists)
"""
for item in items:
return item
@@ -698,13 +702,13 @@ def first_or_default(items, default=None):
def wait_for(callback, value, timeout=EFSConnection.DEFAULT_WAIT_TIMEOUT_SECONDS):
"""
- Helper method to wait for desired value returned by callback method
+ Helper method to wait for desired value returned by callback method
"""
wait_start = timestamp()
while True:
if callback() != value:
if timeout != 0 and (timestamp() - wait_start > timeout):
- raise RuntimeError('Wait timeout exceeded (' + str(timeout) + ' sec)')
+ raise RuntimeError("Wait timeout exceeded (" + str(timeout) + " sec)")
else:
sleep(5)
continue
@@ -713,67 +717,82 @@ def wait_for(callback, value, timeout=EFSConnection.DEFAULT_WAIT_TIMEOUT_SECONDS
def main():
"""
- Module action handler
+ Module action handler
"""
argument_spec = dict(
encrypt=dict(required=False, type="bool", default=False),
- state=dict(required=False, type='str', choices=["present", "absent"], default="present"),
- kms_key_id=dict(required=False, type='str', default=None),
- purge_tags=dict(default=True, type='bool'),
- id=dict(required=False, type='str', default=None),
- name=dict(required=False, type='str', default=None),
- tags=dict(required=False, type="dict", aliases=['resource_tags']),
- targets=dict(required=False, type="list", default=[], elements='dict'),
- performance_mode=dict(required=False, type='str', choices=["general_purpose", "max_io"], default="general_purpose"),
- transition_to_ia=dict(required=False, type='str', choices=["None", "7", "14", "30", "60", "90"], default=None),
- throughput_mode=dict(required=False, type='str', choices=["bursting", "provisioned"], default=None),
- provisioned_throughput_in_mibps=dict(required=False, type='float'),
+ state=dict(required=False, type="str", choices=["present", "absent"], default="present"),
+ kms_key_id=dict(required=False, type="str", default=None),
+ purge_tags=dict(default=True, type="bool"),
+ id=dict(required=False, type="str", default=None),
+ name=dict(required=False, type="str", default=None),
+ tags=dict(required=False, type="dict", aliases=["resource_tags"]),
+ targets=dict(required=False, type="list", default=[], elements="dict"),
+ performance_mode=dict(
+ required=False, type="str", choices=["general_purpose", "max_io"], default="general_purpose"
+ ),
+ transition_to_ia=dict(required=False, type="str", choices=["None", "7", "14", "30", "60", "90"], default=None),
+ throughput_mode=dict(required=False, type="str", choices=["bursting", "provisioned"], default=None),
+ provisioned_throughput_in_mibps=dict(required=False, type="float"),
wait=dict(required=False, type="bool", default=False),
- wait_timeout=dict(required=False, type="int", default=0)
+ wait_timeout=dict(required=False, type="int", default=0),
)
module = AnsibleAWSModule(argument_spec=argument_spec)
connection = EFSConnection(module)
- name = module.params.get('name')
- fs_id = module.params.get('id')
- tags = module.params.get('tags')
+ name = module.params.get("name")
+ fs_id = module.params.get("id")
+ tags = module.params.get("tags")
target_translations = {
- 'ip_address': 'IpAddress',
- 'security_groups': 'SecurityGroups',
- 'subnet_id': 'SubnetId'
+ "ip_address": "IpAddress",
+ "security_groups": "SecurityGroups",
+ "subnet_id": "SubnetId",
}
- targets = [dict((target_translations[key], value) for (key, value) in x.items()) for x in module.params.get('targets')]
+ targets = [
+ dict((target_translations[key], value) for (key, value) in x.items()) for x in module.params.get("targets")
+ ]
performance_mode_translations = {
- 'general_purpose': 'generalPurpose',
- 'max_io': 'maxIO'
+ "general_purpose": "generalPurpose",
+ "max_io": "maxIO",
}
- encrypt = module.params.get('encrypt')
- kms_key_id = module.params.get('kms_key_id')
- performance_mode = performance_mode_translations[module.params.get('performance_mode')]
- purge_tags = module.params.get('purge_tags')
- transition_to_ia = module.params.get('transition_to_ia')
- throughput_mode = module.params.get('throughput_mode')
- provisioned_throughput_in_mibps = module.params.get('provisioned_throughput_in_mibps')
- state = str(module.params.get('state')).lower()
+ encrypt = module.params.get("encrypt")
+ kms_key_id = module.params.get("kms_key_id")
+ performance_mode = performance_mode_translations[module.params.get("performance_mode")]
+ purge_tags = module.params.get("purge_tags")
+ transition_to_ia = module.params.get("transition_to_ia")
+ throughput_mode = module.params.get("throughput_mode")
+ provisioned_throughput_in_mibps = module.params.get("provisioned_throughput_in_mibps")
+ state = str(module.params.get("state")).lower()
changed = False
- if state == 'present':
+ if state == "present":
if not name:
- module.fail_json(msg='Name parameter is required for create')
+ module.fail_json(msg="Name parameter is required for create")
- changed = connection.create_file_system(name, performance_mode, encrypt, kms_key_id, throughput_mode, provisioned_throughput_in_mibps)
+ changed = connection.create_file_system(
+ name, performance_mode, encrypt, kms_key_id, throughput_mode, provisioned_throughput_in_mibps
+ )
changed = connection.update_file_system(name, throughput_mode, provisioned_throughput_in_mibps) or changed
- changed = connection.converge_file_system(name=name, tags=tags, purge_tags=purge_tags, targets=targets,
- throughput_mode=throughput_mode, provisioned_throughput_in_mibps=provisioned_throughput_in_mibps) or changed
+ changed = (
+ connection.converge_file_system(
+ name=name,
+ tags=tags,
+ purge_tags=purge_tags,
+ targets=targets,
+ throughput_mode=throughput_mode,
+ provisioned_throughput_in_mibps=provisioned_throughput_in_mibps,
+ )
+ or changed
+ )
if transition_to_ia:
changed |= connection.update_lifecycle_policy(name, transition_to_ia)
result = first_or_default(connection.get_file_systems(CreationToken=name))
- elif state == 'absent':
+ elif state == "absent":
if not name and not fs_id:
- module.fail_json(msg='Either name or id parameter is required for delete')
+ module.fail_json(msg="Either name or id parameter is required for delete")
changed = connection.delete_file_system(name, fs_id)
result = None
@@ -782,5 +801,5 @@ def main():
module.exit_json(changed=changed, efs=result)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/efs_info.py b/ansible_collections/community/aws/plugins/modules/efs_info.py
index 5ef436f3c..3a170a391 100644
--- a/ansible_collections/community/aws/plugins/modules/efs_info.py
+++ b/ansible_collections/community/aws/plugins/modules/efs_info.py
@@ -1,21 +1,19 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: efs_info
version_added: 1.0.0
short_description: Get information about Amazon EFS file systems
description:
- - This module can be used to search Amazon EFS file systems.
- Note that the M(community.aws.efs_info) module no longer returns C(ansible_facts)!
+- This module can be used to search Amazon EFS file systems.
+ Note that the M(community.aws.efs_info) module no longer returns C(ansible_facts)!
author:
- - "Ryan Sydnor (@ryansydnor)"
+- "Ryan Sydnor (@ryansydnor)"
options:
name:
description:
@@ -39,13 +37,12 @@ options:
elements: str
default: []
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
+- amazon.aws.common.modules
+- amazon.aws.region.modules
- amazon.aws.boto3
+"""
-'''
-
-EXAMPLES = r'''
+EXAMPLES = r"""
- name: Find all existing efs
community.aws.efs_info:
register: result
@@ -58,17 +55,17 @@ EXAMPLES = r'''
- name: Searching all EFS instances with tag Name = 'myTestNameTag', in subnet 'subnet-1a2b3c4d' and with security group 'sg-4d3c2b1a'
community.aws.efs_info:
tags:
- Name: myTestNameTag
+ Name: myTestNameTag
targets:
- - subnet-1a2b3c4d
- - sg-4d3c2b1a
+ - subnet-1a2b3c4d
+ - sg-4d3c2b1a
register: result
- ansible.builtin.debug:
msg: "{{ result['efs'] }}"
-'''
+"""
-RETURN = r'''
+RETURN = r"""
creation_time:
description: timestamp of creation date
returned: always
@@ -167,8 +164,7 @@ tags:
"name": "my-efs",
"key": "Value"
}
-
-'''
+"""
from collections import defaultdict
@@ -180,90 +176,94 @@ except ImportError:
from ansible.module_utils._text import to_native
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
class EFSConnection(object):
- STATE_CREATING = 'creating'
- STATE_AVAILABLE = 'available'
- STATE_DELETING = 'deleting'
- STATE_DELETED = 'deleted'
+ STATE_CREATING = "creating"
+ STATE_AVAILABLE = "available"
+ STATE_DELETING = "deleting"
+ STATE_DELETED = "deleted"
def __init__(self, module):
try:
- self.connection = module.client('efs')
+ self.connection = module.client("efs")
self.module = module
except Exception as e:
- module.fail_json(msg="Failed to connect to AWS: %s" % to_native(e))
+ module.fail_json(msg=f"Failed to connect to AWS: {to_native(e)}")
self.region = module.region
- @AWSRetry.exponential_backoff(catch_extra_error_codes=['ThrottlingException'])
+ @AWSRetry.exponential_backoff(catch_extra_error_codes=["ThrottlingException"])
def list_file_systems(self, **kwargs):
"""
Returns generator of file systems including all attributes of FS
"""
- paginator = self.connection.get_paginator('describe_file_systems')
- return paginator.paginate(**kwargs).build_full_result()['FileSystems']
+ paginator = self.connection.get_paginator("describe_file_systems")
+ return paginator.paginate(**kwargs).build_full_result()["FileSystems"]
- @AWSRetry.exponential_backoff(catch_extra_error_codes=['ThrottlingException'])
+ @AWSRetry.exponential_backoff(catch_extra_error_codes=["ThrottlingException"])
def get_tags(self, file_system_id):
"""
Returns tag list for selected instance of EFS
"""
- paginator = self.connection.get_paginator('describe_tags')
- return boto3_tag_list_to_ansible_dict(paginator.paginate(FileSystemId=file_system_id).build_full_result()['Tags'])
+ paginator = self.connection.get_paginator("describe_tags")
+ return boto3_tag_list_to_ansible_dict(
+ paginator.paginate(FileSystemId=file_system_id).build_full_result()["Tags"]
+ )
- @AWSRetry.exponential_backoff(catch_extra_error_codes=['ThrottlingException'])
+ @AWSRetry.exponential_backoff(catch_extra_error_codes=["ThrottlingException"])
def get_mount_targets(self, file_system_id):
"""
Returns mount targets for selected instance of EFS
"""
- paginator = self.connection.get_paginator('describe_mount_targets')
- return paginator.paginate(FileSystemId=file_system_id).build_full_result()['MountTargets']
+ paginator = self.connection.get_paginator("describe_mount_targets")
+ return paginator.paginate(FileSystemId=file_system_id).build_full_result()["MountTargets"]
- @AWSRetry.jittered_backoff(catch_extra_error_codes=['ThrottlingException'])
+ @AWSRetry.jittered_backoff(catch_extra_error_codes=["ThrottlingException"])
def get_security_groups(self, mount_target_id):
"""
Returns security groups for selected instance of EFS
"""
- return self.connection.describe_mount_target_security_groups(MountTargetId=mount_target_id)['SecurityGroups']
+ return self.connection.describe_mount_target_security_groups(MountTargetId=mount_target_id)["SecurityGroups"]
def get_mount_targets_data(self, file_systems):
for item in file_systems:
- if item['life_cycle_state'] == self.STATE_AVAILABLE:
+ if item["life_cycle_state"] == self.STATE_AVAILABLE:
try:
- mount_targets = self.get_mount_targets(item['file_system_id'])
+ mount_targets = self.get_mount_targets(item["file_system_id"])
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
self.module.fail_json_aws(e, msg="Couldn't get EFS targets")
for mt in mount_targets:
- item['mount_targets'].append(camel_dict_to_snake_dict(mt))
+ item["mount_targets"].append(camel_dict_to_snake_dict(mt))
return file_systems
def get_security_groups_data(self, file_systems):
for item in file_systems:
- if item['life_cycle_state'] == self.STATE_AVAILABLE:
- for target in item['mount_targets']:
- if target['life_cycle_state'] == self.STATE_AVAILABLE:
+ if item["life_cycle_state"] == self.STATE_AVAILABLE:
+ for target in item["mount_targets"]:
+ if target["life_cycle_state"] == self.STATE_AVAILABLE:
try:
- target['security_groups'] = self.get_security_groups(target['mount_target_id'])
+ target["security_groups"] = self.get_security_groups(target["mount_target_id"])
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
self.module.fail_json_aws(e, msg="Couldn't get EFS security groups")
else:
- target['security_groups'] = []
+ target["security_groups"] = []
else:
- item['tags'] = {}
- item['mount_targets'] = []
+ item["tags"] = {}
+ item["mount_targets"] = []
return file_systems
def get_file_systems(self, file_system_id=None, creation_token=None):
kwargs = dict()
if file_system_id:
- kwargs['FileSystemId'] = file_system_id
+ kwargs["FileSystemId"] = file_system_id
if creation_token:
- kwargs['CreationToken'] = creation_token
+ kwargs["CreationToken"] = creation_token
try:
file_systems = self.list_file_systems(**kwargs)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
@@ -271,7 +271,7 @@ class EFSConnection(object):
results = list()
for item in file_systems:
- item['CreationTime'] = str(item['CreationTime'])
+ item["CreationTime"] = str(item["CreationTime"])
"""
In the time when MountPoint was introduced there was a need to add a suffix of network path before one could use it
AWS updated it and now there is no need to add a suffix. MountPoint is left for back-compatibility purpose
@@ -279,18 +279,18 @@ class EFSConnection(object):
AWS documentation is available here:
U(https://docs.aws.amazon.com/efs/latest/ug/gs-step-three-connect-to-ec2-instance.html)
"""
- item['MountPoint'] = '.%s.efs.%s.amazonaws.com:/' % (item['FileSystemId'], self.region)
- item['FilesystemAddress'] = '%s.efs.%s.amazonaws.com:/' % (item['FileSystemId'], self.region)
+ item["MountPoint"] = f".{item['FileSystemId']}.efs.{self.region}.amazonaws.com:/"
+ item["FilesystemAddress"] = f"{item['FileSystemId']}.efs.{self.region}.amazonaws.com:/"
- if 'Timestamp' in item['SizeInBytes']:
- item['SizeInBytes']['Timestamp'] = str(item['SizeInBytes']['Timestamp'])
+ if "Timestamp" in item["SizeInBytes"]:
+ item["SizeInBytes"]["Timestamp"] = str(item["SizeInBytes"]["Timestamp"])
result = camel_dict_to_snake_dict(item)
- result['tags'] = {}
- result['mount_targets'] = []
+ result["tags"] = {}
+ result["mount_targets"] = []
# Set tags *after* doing camel to snake
- if result['life_cycle_state'] == self.STATE_AVAILABLE:
+ if result["life_cycle_state"] == self.STATE_AVAILABLE:
try:
- result['tags'] = self.get_tags(result['file_system_id'])
+ result["tags"] = self.get_tags(result["file_system_id"])
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
self.module.fail_json_aws(e, msg="Couldn't get EFS tags")
results.append(result)
@@ -302,13 +302,14 @@ def prefix_to_attr(attr_id):
Helper method to convert ID prefix to mount target attribute
"""
attr_by_prefix = {
- 'fsmt-': 'mount_target_id',
- 'subnet-': 'subnet_id',
- 'eni-': 'network_interface_id',
- 'sg-': 'security_groups'
+ "fsmt-": "mount_target_id",
+ "subnet-": "subnet_id",
+ "eni-": "network_interface_id",
+ "sg-": "security_groups",
}
- return first_or_default([attr_name for (prefix, attr_name) in attr_by_prefix.items()
- if str(attr_id).startswith(prefix)], 'ip_address')
+ return first_or_default(
+ [attr_name for (prefix, attr_name) in attr_by_prefix.items() if str(attr_id).startswith(prefix)], "ip_address"
+ )
def first_or_default(items, default=None):
@@ -335,7 +336,7 @@ def has_targets(available, required):
Helper method to determine if mount target requested already exists
"""
grouped = group_list_of_dict(available)
- for (value, field) in required:
+ for value, field in required:
if field not in grouped or value not in grouped[field]:
return False
return True
@@ -358,35 +359,34 @@ def main():
"""
argument_spec = dict(
id=dict(),
- name=dict(aliases=['creation_token']),
+ name=dict(aliases=["creation_token"]),
tags=dict(type="dict", default={}),
- targets=dict(type="list", default=[], elements='str')
+ targets=dict(type="list", default=[], elements="str"),
)
- module = AnsibleAWSModule(argument_spec=argument_spec,
- supports_check_mode=True)
+ module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
connection = EFSConnection(module)
- name = module.params.get('name')
- fs_id = module.params.get('id')
- tags = module.params.get('tags')
- targets = module.params.get('targets')
+ name = module.params.get("name")
+ fs_id = module.params.get("id")
+ tags = module.params.get("tags")
+ targets = module.params.get("targets")
file_systems_info = connection.get_file_systems(fs_id, name)
if tags:
- file_systems_info = [item for item in file_systems_info if has_tags(item['tags'], tags)]
+ file_systems_info = [item for item in file_systems_info if has_tags(item["tags"], tags)]
file_systems_info = connection.get_mount_targets_data(file_systems_info)
file_systems_info = connection.get_security_groups_data(file_systems_info)
if targets:
targets = [(item, prefix_to_attr(item)) for item in targets]
- file_systems_info = [item for item in file_systems_info if has_targets(item['mount_targets'], targets)]
+ file_systems_info = [item for item in file_systems_info if has_targets(item["mount_targets"], targets)]
module.exit_json(changed=False, efs=file_systems_info)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/efs_tag.py b/ansible_collections/community/aws/plugins/modules/efs_tag.py
index 1529fa944..0f5143471 100644
--- a/ansible_collections/community/aws/plugins/modules/efs_tag.py
+++ b/ansible_collections/community/aws/plugins/modules/efs_tag.py
@@ -1,21 +1,17 @@
#!/usr/bin/python
-"""
-Copyright: (c) 2021, Milan Zink <zeten30@gmail.com>
-GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-"""
+# -*- coding: utf-8 -*-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
+# Copyright: (c) 2021, Milan Zink <zeten30@gmail.com>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: efs_tag
version_added: 2.0.0
short_description: create and remove tags on Amazon EFS resources
description:
- - Creates and removes tags for Amazon EFS resources.
- - Resources are referenced by their ID (filesystem or filesystem access point).
+ - Creates and removes tags for Amazon EFS resources.
+ - Resources are referenced by their ID (filesystem or filesystem access point).
author:
- Milan Zink (@zeten30)
options:
@@ -44,13 +40,12 @@ options:
type: bool
default: false
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
-
-'''
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
- name: Ensure tags are present on a resource
community.aws.efs_tag:
resource: fs-123456ab
@@ -71,7 +66,7 @@ EXAMPLES = r'''
resource: fsap-78945ff
state: absent
tags:
- Name: foo
+ Name: foo
purge_tags: true
- name: Remove all tags
@@ -80,9 +75,9 @@ EXAMPLES = r'''
state: absent
tags: {}
purge_tags: true
-'''
+"""
-RETURN = r'''
+RETURN = r"""
tags:
description: A dict containing the tags on the resource
returned: always
@@ -95,51 +90,56 @@ removed_tags:
description: A dict of tags that were removed from the resource
returned: If tags were removed
type: dict
-'''
+"""
try:
- from botocore.exceptions import BotoCoreError, ClientError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
except ImportError:
# Handled by AnsibleAWSModule
pass
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict, ansible_dict_to_boto3_tag_list, compare_aws_tags, AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import ansible_dict_to_boto3_tag_list
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import compare_aws_tags
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
MAX_AWS_RETRIES = 10 # How many retries to perform when an API call is failing
WAIT_RETRY = 5 # how many seconds to wait between propagation status polls
def get_tags(efs, module, resource):
- '''
+ """
Get resource tags
- '''
+ """
try:
- return boto3_tag_list_to_ansible_dict(efs.list_tags_for_resource(aws_retry=True, ResourceId=resource)['Tags'])
+ return boto3_tag_list_to_ansible_dict(efs.list_tags_for_resource(aws_retry=True, ResourceId=resource)["Tags"])
except (BotoCoreError, ClientError) as get_tags_error:
- module.fail_json_aws(get_tags_error, msg='Failed to fetch tags for resource {0}'.format(resource))
+ module.fail_json_aws(get_tags_error, msg=f"Failed to fetch tags for resource {resource}")
def main():
- '''
+ """
MAIN
- '''
+ """
argument_spec = dict(
resource=dict(required=True),
- tags=dict(type='dict', required=True, aliases=['resource_tags']),
- purge_tags=dict(type='bool', default=False),
- state=dict(default='present', choices=['present', 'absent'])
+ tags=dict(type="dict", required=True, aliases=["resource_tags"]),
+ purge_tags=dict(type="bool", default=False),
+ state=dict(default="present", choices=["present", "absent"]),
)
module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
- resource = module.params['resource']
- tags = module.params['tags']
- state = module.params['state']
- purge_tags = module.params['purge_tags']
+ resource = module.params["resource"]
+ tags = module.params["tags"]
+ state = module.params["state"]
+ purge_tags = module.params["purge_tags"]
- result = {'changed': False}
+ result = {"changed": False}
- efs = module.client('efs', retry_decorator=AWSRetry.jittered_backoff())
+ efs = module.client("efs", retry_decorator=AWSRetry.jittered_backoff())
current_tags = get_tags(efs, module, resource)
@@ -147,7 +147,7 @@ def main():
remove_tags = {}
- if state == 'absent':
+ if state == "absent":
for key in tags:
if key in current_tags and (tags[key] is None or current_tags[key] == tags[key]):
remove_tags[key] = current_tags[key]
@@ -156,28 +156,30 @@ def main():
remove_tags[key] = current_tags[key]
if remove_tags:
- result['changed'] = True
- result['removed_tags'] = remove_tags
+ result["changed"] = True
+ result["removed_tags"] = remove_tags
if not module.check_mode:
try:
efs.untag_resource(aws_retry=True, ResourceId=resource, TagKeys=list(remove_tags.keys()))
except (BotoCoreError, ClientError) as remove_tag_error:
- module.fail_json_aws(remove_tag_error, msg='Failed to remove tags {0} from resource {1}'.format(remove_tags, resource))
+ module.fail_json_aws(
+ remove_tag_error, msg=f"Failed to remove tags {remove_tags} from resource {resource}"
+ )
- if state == 'present' and add_tags:
- result['changed'] = True
- result['added_tags'] = add_tags
+ if state == "present" and add_tags:
+ result["changed"] = True
+ result["added_tags"] = add_tags
current_tags.update(add_tags)
if not module.check_mode:
try:
tags = ansible_dict_to_boto3_tag_list(add_tags)
efs.tag_resource(aws_retry=True, ResourceId=resource, Tags=tags)
except (BotoCoreError, ClientError) as set_tag_error:
- module.fail_json_aws(set_tag_error, msg='Failed to set tags {0} on resource {1}'.format(add_tags, resource))
+ module.fail_json_aws(set_tag_error, msg=f"Failed to set tags {add_tags} on resource {resource}")
- result['tags'] = get_tags(efs, module, resource)
+ result["tags"] = get_tags(efs, module, resource)
module.exit_json(**result)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/eks_cluster.py b/ansible_collections/community/aws/plugins/modules/eks_cluster.py
index 18a5055e9..a445def55 100644
--- a/ansible_collections/community/aws/plugins/modules/eks_cluster.py
+++ b/ansible_collections/community/aws/plugins/modules/eks_cluster.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: eks_cluster
version_added: 1.0.0
@@ -63,13 +61,12 @@ options:
default: 1200
type: int
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
+"""
-'''
-
-EXAMPLES = r'''
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide for details.
- name: Create an EKS cluster
@@ -89,9 +86,9 @@ EXAMPLES = r'''
name: my_cluster
wait: true
state: absent
-'''
+"""
-RETURN = r'''
+RETURN = r"""
arn:
description: ARN of the EKS cluster
returned: when state is present
@@ -163,42 +160,45 @@ version:
returned: when state is present
type: str
sample: '1.10'
-'''
-
-
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule, is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict, get_ec2_security_group_ids_from_names
-from ansible_collections.amazon.aws.plugins.module_utils.waiters import get_waiter
+"""
try:
- import botocore.exceptions
+ import botocore
except ImportError:
pass # caught by AnsibleAWSModule
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.ec2 import get_ec2_security_group_ids_from_names
+from ansible_collections.amazon.aws.plugins.module_utils.waiters import get_waiter
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
+
def ensure_present(client, module):
- name = module.params.get('name')
- subnets = module.params['subnets']
- groups = module.params['security_groups']
- wait = module.params.get('wait')
+ name = module.params.get("name")
+ subnets = module.params["subnets"]
+ groups = module.params["security_groups"]
+ wait = module.params.get("wait")
cluster = get_cluster(client, module)
try:
- ec2 = module.client('ec2')
- vpc_id = ec2.describe_subnets(SubnetIds=[subnets[0]])['Subnets'][0]['VpcId']
+ ec2 = module.client("ec2")
+ vpc_id = ec2.describe_subnets(SubnetIds=[subnets[0]])["Subnets"][0]["VpcId"]
groups = get_ec2_security_group_ids_from_names(groups, ec2, vpc_id)
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
module.fail_json_aws(e, msg="Couldn't lookup security groups")
if cluster:
- if set(cluster['resourcesVpcConfig']['subnetIds']) != set(subnets):
+ if set(cluster["resourcesVpcConfig"]["subnetIds"]) != set(subnets):
module.fail_json(msg="Cannot modify subnets of existing cluster")
- if set(cluster['resourcesVpcConfig']['securityGroupIds']) != set(groups):
+ if set(cluster["resourcesVpcConfig"]["securityGroupIds"]) != set(groups):
module.fail_json(msg="Cannot modify security groups of existing cluster")
- if module.params.get('version') and module.params.get('version') != cluster['version']:
+ if module.params.get("version") and module.params.get("version") != cluster["version"]:
module.fail_json(msg="Cannot modify version of existing cluster")
if wait:
- wait_until(client, module, 'cluster_active')
+ wait_until(client, module, "cluster_active")
# Ensure that fields that are only available for active clusters are
# included in the returned value
cluster = get_cluster(client, module)
@@ -208,24 +208,23 @@ def ensure_present(client, module):
if module.check_mode:
module.exit_json(changed=True)
try:
- params = dict(name=name,
- roleArn=module.params['role_arn'],
- resourcesVpcConfig=dict(
- subnetIds=subnets,
- securityGroupIds=groups),
- )
- if module.params['version']:
- params['version'] = module.params['version']
- if module.params['tags']:
- params['tags'] = module.params['tags']
- cluster = client.create_cluster(**params)['cluster']
+ params = dict(
+ name=name,
+ roleArn=module.params["role_arn"],
+ resourcesVpcConfig=dict(subnetIds=subnets, securityGroupIds=groups),
+ )
+ if module.params["version"]:
+ params["version"] = module.params["version"]
+ if module.params["tags"]:
+ params["tags"] = module.params["tags"]
+ cluster = client.create_cluster(**params)["cluster"]
except botocore.exceptions.EndpointConnectionError as e:
- module.fail_json(msg="Region %s is not supported by EKS" % client.meta.region_name)
+ module.fail_json(msg=f"Region {client.meta.region_name} is not supported by EKS")
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
- module.fail_json_aws(e, msg="Couldn't create cluster %s" % name)
+ module.fail_json_aws(e, msg=f"Couldn't create cluster {name}")
if wait:
- wait_until(client, module, 'cluster_active')
+ wait_until(client, module, "cluster_active")
# Ensure that fields that are only available for active clusters are
# included in the returned value
cluster = get_cluster(client, module)
@@ -234,44 +233,47 @@ def ensure_present(client, module):
def ensure_absent(client, module):
- name = module.params.get('name')
+ name = module.params.get("name")
existing = get_cluster(client, module)
- wait = module.params.get('wait')
+ wait = module.params.get("wait")
if not existing:
module.exit_json(changed=False)
if not module.check_mode:
try:
- client.delete_cluster(name=module.params['name'])
+ client.delete_cluster(name=module.params["name"])
except botocore.exceptions.EndpointConnectionError as e:
- module.fail_json(msg="Region %s is not supported by EKS" % client.meta.region_name)
+ module.fail_json(msg=f"Region {client.meta.region_name} is not supported by EKS")
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
- module.fail_json_aws(e, msg="Couldn't delete cluster %s" % name)
+ module.fail_json_aws(e, msg=f"Couldn't delete cluster {name}")
if wait:
- wait_until(client, module, 'cluster_deleted')
+ wait_until(client, module, "cluster_deleted")
module.exit_json(changed=True)
def get_cluster(client, module):
- name = module.params.get('name')
+ name = module.params.get("name")
try:
- return client.describe_cluster(name=name)['cluster']
- except is_boto3_error_code('ResourceNotFoundException'):
+ return client.describe_cluster(name=name)["cluster"]
+ except is_boto3_error_code("ResourceNotFoundException"):
return None
except botocore.exceptions.EndpointConnectionError as e: # pylint: disable=duplicate-except
- module.fail_json(msg="Region %s is not supported by EKS" % client.meta.region_name)
- except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, msg="Couldn't get cluster %s" % name)
+ module.fail_json(msg=f"Region {client.meta.region_name} is not supported by EKS")
+ except (
+ botocore.exceptions.BotoCoreError,
+ botocore.exceptions.ClientError,
+ ) as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(e, msg=f"Couldn't get cluster {name}")
-def wait_until(client, module, waiter_name='cluster_active'):
- name = module.params.get('name')
- wait_timeout = module.params.get('wait_timeout')
+def wait_until(client, module, waiter_name="cluster_active"):
+ name = module.params.get("name")
+ wait_timeout = module.params.get("wait_timeout")
waiter = get_waiter(client, waiter_name)
attempts = 1 + int(wait_timeout / waiter.config.delay)
- waiter.wait(name=name, WaiterConfig={'MaxAttempts': attempts})
+ waiter.wait(name=name, WaiterConfig={"MaxAttempts": attempts})
def main():
@@ -279,27 +281,27 @@ def main():
name=dict(required=True),
version=dict(),
role_arn=dict(),
- subnets=dict(type='list', elements='str'),
- security_groups=dict(type='list', elements='str'),
- state=dict(choices=['absent', 'present'], default='present'),
- tags=dict(type='dict', required=False),
- wait=dict(default=False, type='bool'),
- wait_timeout=dict(default=1200, type='int')
+ subnets=dict(type="list", elements="str"),
+ security_groups=dict(type="list", elements="str"),
+ state=dict(choices=["absent", "present"], default="present"),
+ tags=dict(type="dict", required=False),
+ wait=dict(default=False, type="bool"),
+ wait_timeout=dict(default=1200, type="int"),
)
module = AnsibleAWSModule(
argument_spec=argument_spec,
- required_if=[['state', 'present', ['role_arn', 'subnets', 'security_groups']]],
+ required_if=[["state", "present", ["role_arn", "subnets", "security_groups"]]],
supports_check_mode=True,
)
- client = module.client('eks')
+ client = module.client("eks")
- if module.params.get('state') == 'present':
+ if module.params.get("state") == "present":
ensure_present(client, module)
else:
ensure_absent(client, module)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/eks_fargate_profile.py b/ansible_collections/community/aws/plugins/modules/eks_fargate_profile.py
index d78cbbe2d..131f0651b 100644
--- a/ansible_collections/community/aws/plugins/modules/eks_fargate_profile.py
+++ b/ansible_collections/community/aws/plugins/modules/eks_fargate_profile.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright (c) 2022 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: eks_fargate_profile
version_added: 4.0.0
@@ -68,14 +66,13 @@ options:
default: 1200
type: int
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
- - amazon.aws.boto3
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.tags
+ - amazon.aws.boto3
+"""
-'''
-
-EXAMPLES = r'''
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide for details.
- name: Create an EKS Fargate Profile
@@ -98,9 +95,9 @@ EXAMPLES = r'''
cluster_name: test_cluster
wait: true
state: absent
-'''
+"""
-RETURN = r'''
+RETURN = r"""
fargate_profile_name:
description: Name of Fargate Profile.
returned: when state is present
@@ -164,74 +161,77 @@ status:
sample:
- CREATING
- ACTIVE
-'''
-
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule, is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import compare_aws_tags
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.waiters import get_waiter
+"""
try:
- import botocore.exceptions
+ import botocore
except ImportError:
pass
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import compare_aws_tags
+from ansible_collections.amazon.aws.plugins.module_utils.waiters import get_waiter
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
+
def validate_tags(client, module, fargate_profile):
changed = False
- desired_tags = module.params.get('tags')
+ desired_tags = module.params.get("tags")
if desired_tags is None:
return False
try:
- existing_tags = client.list_tags_for_resource(resourceArn=fargate_profile['fargateProfileArn'])['tags']
- tags_to_add, tags_to_remove = compare_aws_tags(existing_tags, desired_tags, module.params.get('purge_tags'))
+ existing_tags = client.list_tags_for_resource(resourceArn=fargate_profile["fargateProfileArn"])["tags"]
+ tags_to_add, tags_to_remove = compare_aws_tags(existing_tags, desired_tags, module.params.get("purge_tags"))
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Unable to list or compare tags for Fargate Profile %s' % module.params.get('name'))
+ module.fail_json_aws(e, msg=f"Unable to list or compare tags for Fargate Profile {module.params.get('name')}")
if tags_to_remove:
changed = True
if not module.check_mode:
try:
- client.untag_resource(resourceArn=fargate_profile['fargateProfileArn'], tagKeys=tags_to_remove)
+ client.untag_resource(resourceArn=fargate_profile["fargateProfileArn"], tagKeys=tags_to_remove)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Unable to set tags for Fargate Profile %s' % module.params.get('name'))
+ module.fail_json_aws(e, msg=f"Unable to set tags for Fargate Profile {module.params.get('name')}")
if tags_to_add:
changed = True
if not module.check_mode:
try:
- client.tag_resource(resourceArn=fargate_profile['fargateProfileArn'], tags=tags_to_add)
+ client.tag_resource(resourceArn=fargate_profile["fargateProfileArn"], tags=tags_to_add)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Unable to set tags for Fargate Profile %s' % module.params.get('name'))
+ module.fail_json_aws(e, msg=f"Unable to set tags for Fargate Profile {module.params.get('name')}")
return changed
def create_or_update_fargate_profile(client, module):
- name = module.params.get('name')
- subnets = module.params['subnets']
- role_arn = module.params['role_arn']
- cluster_name = module.params['cluster_name']
- selectors = module.params['selectors']
- tags = module.params['tags'] or {}
- wait = module.params.get('wait')
+ name = module.params.get("name")
+ subnets = module.params["subnets"]
+ role_arn = module.params["role_arn"]
+ cluster_name = module.params["cluster_name"]
+ selectors = module.params["selectors"]
+ tags = module.params["tags"] or {}
+ wait = module.params.get("wait")
fargate_profile = get_fargate_profile(client, module, name, cluster_name)
if fargate_profile:
changed = False
- if set(fargate_profile['podExecutionRoleArn']) != set(role_arn):
+ if set(fargate_profile["podExecutionRoleArn"]) != set(role_arn):
module.fail_json(msg="Cannot modify Execution Role")
- if set(fargate_profile['subnets']) != set(subnets):
+ if set(fargate_profile["subnets"]) != set(subnets):
module.fail_json(msg="Cannot modify Subnets")
- if fargate_profile['selectors'] != selectors:
+ if fargate_profile["selectors"] != selectors:
module.fail_json(msg="Cannot modify Selectors")
changed = validate_tags(client, module, fargate_profile)
if wait:
- wait_until(client, module, 'fargate_profile_active', name, cluster_name)
+ wait_until(client, module, "fargate_profile_active", name, cluster_name)
fargate_profile = get_fargate_profile(client, module, name, cluster_name)
module.exit_json(changed=changed, **camel_dict_to_snake_dict(fargate_profile))
@@ -242,29 +242,30 @@ def create_or_update_fargate_profile(client, module):
check_profiles_status(client, module, cluster_name)
try:
- params = dict(fargateProfileName=name,
- podExecutionRoleArn=role_arn,
- subnets=subnets,
- clusterName=cluster_name,
- selectors=selectors,
- tags=tags
- )
+ params = dict(
+ fargateProfileName=name,
+ podExecutionRoleArn=role_arn,
+ subnets=subnets,
+ clusterName=cluster_name,
+ selectors=selectors,
+ tags=tags,
+ )
fargate_profile = client.create_fargate_profile(**params)
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
- module.fail_json_aws(e, msg="Couldn't create fargate profile %s" % name)
+ module.fail_json_aws(e, msg=f"Couldn't create fargate profile {name}")
if wait:
- wait_until(client, module, 'fargate_profile_active', name, cluster_name)
+ wait_until(client, module, "fargate_profile_active", name, cluster_name)
fargate_profile = get_fargate_profile(client, module, name, cluster_name)
module.exit_json(changed=True, **camel_dict_to_snake_dict(fargate_profile))
def delete_fargate_profile(client, module):
- name = module.params.get('name')
- cluster_name = module.params['cluster_name']
+ name = module.params.get("name")
+ cluster_name = module.params["cluster_name"]
existing = get_fargate_profile(client, module, name, cluster_name)
- wait = module.params.get('wait')
+ wait = module.params.get("wait")
if not existing or existing["status"] == "DELETING":
module.exit_json(changed=False)
@@ -273,20 +274,23 @@ def delete_fargate_profile(client, module):
try:
client.delete_fargate_profile(clusterName=cluster_name, fargateProfileName=name)
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
- module.fail_json_aws(e, msg="Couldn't delete fargate profile %s" % name)
+ module.fail_json_aws(e, msg=f"Couldn't delete fargate profile {name}")
if wait:
- wait_until(client, module, 'fargate_profile_deleted', name, cluster_name)
+ wait_until(client, module, "fargate_profile_deleted", name, cluster_name)
module.exit_json(changed=True)
def get_fargate_profile(client, module, name, cluster_name):
try:
- return client.describe_fargate_profile(clusterName=cluster_name, fargateProfileName=name)['fargateProfile']
- except is_boto3_error_code('ResourceNotFoundException'):
+ return client.describe_fargate_profile(clusterName=cluster_name, fargateProfileName=name)["fargateProfile"]
+ except is_boto3_error_code("ResourceNotFoundException"):
return None
- except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e: # pylint: disable=duplicate-except
+ except (
+ botocore.exceptions.BotoCoreError,
+ botocore.exceptions.ClientError,
+ ) as e: # pylint: disable=duplicate-except
module.fail_json_aws(e, msg="Couldn't get fargate profile")
@@ -297,20 +301,24 @@ def check_profiles_status(client, module, cluster_name):
for name in list_profiles["fargateProfileNames"]:
fargate_profile = get_fargate_profile(client, module, name, cluster_name)
- if fargate_profile["status"] == 'CREATING':
- wait_until(client, module, 'fargate_profile_active', fargate_profile["fargateProfileName"], cluster_name)
- elif fargate_profile["status"] == 'DELETING':
- wait_until(client, module, 'fargate_profile_deleted', fargate_profile["fargateProfileName"], cluster_name)
+ if fargate_profile["status"] == "CREATING":
+ wait_until(
+ client, module, "fargate_profile_active", fargate_profile["fargateProfileName"], cluster_name
+ )
+ elif fargate_profile["status"] == "DELETING":
+ wait_until(
+ client, module, "fargate_profile_deleted", fargate_profile["fargateProfileName"], cluster_name
+ )
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
module.fail_json_aws(e, msg="Couldn't not find EKS cluster")
def wait_until(client, module, waiter_name, name, cluster_name):
- wait_timeout = module.params.get('wait_timeout')
+ wait_timeout = module.params.get("wait_timeout")
waiter = get_waiter(client, waiter_name)
attempts = 1 + int(wait_timeout / waiter.config.delay)
try:
- waiter.wait(clusterName=cluster_name, fargateProfileName=name, WaiterConfig={'MaxAttempts': attempts})
+ waiter.wait(clusterName=cluster_name, fargateProfileName=name, WaiterConfig={"MaxAttempts": attempts})
except botocore.exceptions.WaiterError as e:
module.fail_json_aws(e, msg="An error occurred waiting")
@@ -320,34 +328,38 @@ def main():
name=dict(required=True),
cluster_name=dict(required=True),
role_arn=dict(),
- subnets=dict(type='list', elements='str'),
- selectors=dict(type='list', elements='dict', options=dict(
- namespace=dict(type='str'),
- labels=dict(type='dict', default={})
- )),
- tags=dict(type='dict', aliases=['resource_tags']),
- purge_tags=dict(type='bool', default=True),
- state=dict(choices=['absent', 'present'], default='present'),
- wait=dict(default=False, type='bool'),
- wait_timeout=dict(default=1200, type='int')
+ subnets=dict(type="list", elements="str"),
+ selectors=dict(
+ type="list",
+ elements="dict",
+ options=dict(
+ namespace=dict(type="str"),
+ labels=dict(type="dict", default={}),
+ ),
+ ),
+ tags=dict(type="dict", aliases=["resource_tags"]),
+ purge_tags=dict(type="bool", default=True),
+ state=dict(choices=["absent", "present"], default="present"),
+ wait=dict(default=False, type="bool"),
+ wait_timeout=dict(default=1200, type="int"),
)
module = AnsibleAWSModule(
argument_spec=argument_spec,
- required_if=[['state', 'present', ['role_arn', 'subnets', 'selectors']]],
+ required_if=[["state", "present", ["role_arn", "subnets", "selectors"]]],
supports_check_mode=True,
)
try:
- client = module.client('eks')
+ client = module.client("eks")
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
module.fail_json_aws(e, msg="Couldn't connect to AWS")
- if module.params.get('state') == 'present':
+ if module.params.get("state") == "present":
create_or_update_fargate_profile(client, module)
else:
delete_fargate_profile(client, module)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/eks_nodegroup.py b/ansible_collections/community/aws/plugins/modules/eks_nodegroup.py
index 78979afc2..f9bbb7857 100644
--- a/ansible_collections/community/aws/plugins/modules/eks_nodegroup.py
+++ b/ansible_collections/community/aws/plugins/modules/eks_nodegroup.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright (c) 2022 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: eks_nodegroup
version_added: 5.3.0
@@ -169,12 +167,11 @@ options:
default: 1200
type: int
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+"""
-'''
-
-EXAMPLES = r'''
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide for details.
- name: create nodegroup
@@ -187,29 +184,29 @@ EXAMPLES = r'''
- subnet-qwerty123
- subnet-asdfg456
scaling_config:
- - min_size: 1
- - max_size: 2
- - desired_size: 1
+ min_size: 1
+ max_size: 2
+ desired_size: 1
disk_size: 20
instance_types: 't3.micro'
ami_type: 'AL2_x86_64'
labels:
- - 'teste': 'test'
+ 'teste': 'test'
taints:
- key: 'test'
value: 'test'
effect: 'NO_SCHEDULE'
- capacity_type: 'on_demand'
+ capacity_type: 'ON_DEMAND'
- name: Remove an EKS Nodegrop
community.aws.eks_nodegroup:
name: test_nodegroup
cluster_name: test_cluster
- wait: yes
+ wait: true
state: absent
-'''
+"""
-RETURN = r'''
+RETURN = r"""
nodegroup_name:
description: The name associated with an Amazon EKS managed node group.
returned: when state is present
@@ -345,45 +342,49 @@ tags:
type: dict
sample:
foo: bar
-'''
-
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule, is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import compare_aws_tags
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict, snake_dict_to_camel_dict
-from ansible_collections.amazon.aws.plugins.module_utils.waiters import get_waiter
+"""
try:
- import botocore.exceptions
+ import botocore
except ImportError:
pass
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+from ansible.module_utils.common.dict_transformations import snake_dict_to_camel_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import compare_aws_tags
+from ansible_collections.amazon.aws.plugins.module_utils.waiters import get_waiter
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
+
def validate_tags(client, module, nodegroup):
changed = False
- desired_tags = module.params.get('tags')
+ desired_tags = module.params.get("tags")
if desired_tags is None:
return False
try:
- existing_tags = client.list_tags_for_resource(resourceArn=nodegroup['nodegroupArn'])['tags']
- tags_to_add, tags_to_remove = compare_aws_tags(existing_tags, desired_tags, module.params.get('purge_tags'))
+ existing_tags = client.list_tags_for_resource(resourceArn=nodegroup["nodegroupArn"])["tags"]
+ tags_to_add, tags_to_remove = compare_aws_tags(existing_tags, desired_tags, module.params.get("purge_tags"))
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Unable to list or compare tags for Nodegroup %s.' % module.params.get('name'))
+ module.fail_json_aws(e, msg=f"Unable to list or compare tags for Nodegroup {module.params.get('name')}.")
if tags_to_remove:
if not module.check_mode:
changed = True
try:
- client.untag_resource(aws_retry=True, ResourceArn=nodegroup['nodegroupArn'], tagKeys=tags_to_remove)
+ client.untag_resource(aws_retry=True, ResourceArn=nodegroup["nodegroupArn"], tagKeys=tags_to_remove)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Unable to set tags for Nodegroup %s.' % module.params.get('name'))
+ module.fail_json_aws(e, msg=f"Unable to set tags for Nodegroup {module.params.get('name')}.")
if tags_to_add:
if not module.check_mode:
changed = True
try:
- client.tag_resource(aws_retry=True, ResourceArn=nodegroup['nodegroupArn'], tags=tags_to_add)
+ client.tag_resource(aws_retry=True, ResourceArn=nodegroup["nodegroupArn"], tags=tags_to_add)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Unable to set tags for Nodegroup %s.' % module.params.get('name'))
+ module.fail_json_aws(e, msg=f"Unable to set tags for Nodegroup {module.params.get('name')}.")
return changed
@@ -404,24 +405,24 @@ def compare_taints(nodegroup_taints, param_taints):
def validate_taints(client, module, nodegroup, param_taints):
changed = False
params = dict()
- params['clusterName'] = nodegroup['clusterName']
- params['nodegroupName'] = nodegroup['nodegroupName']
- params['taints'] = []
- if 'taints' not in nodegroup:
- nodegroup['taints'] = []
- taints_to_add_or_update, taints_to_unset = compare_taints(nodegroup['taints'], param_taints)
+ params["clusterName"] = nodegroup["clusterName"]
+ params["nodegroupName"] = nodegroup["nodegroupName"]
+ params["taints"] = []
+ if "taints" not in nodegroup:
+ nodegroup["taints"] = []
+ taints_to_add_or_update, taints_to_unset = compare_taints(nodegroup["taints"], param_taints)
if taints_to_add_or_update:
- params['taints']['addOrUpdateTaints'] = taints_to_add_or_update
+ params["taints"]["addOrUpdateTaints"] = taints_to_add_or_update
if taints_to_unset:
- params['taints']['removeTaints'] = taints_to_unset
- if params['taints']:
+ params["taints"]["removeTaints"] = taints_to_unset
+ if params["taints"]:
if not module.check_mode:
changed = True
try:
client.update_nodegroup_config(**params)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Unable to set taints for Nodegroup %s.' % params['nodegroupName'])
+ module.fail_json_aws(e, msg=f"Unable to set taints for Nodegroup {params['nodegroupName']}.")
return changed
@@ -442,109 +443,114 @@ def compare_labels(nodegroup_labels, param_labels):
def validate_labels(client, module, nodegroup, param_labels):
changed = False
params = dict()
- params['clusterName'] = nodegroup['clusterName']
- params['nodegroupName'] = nodegroup['nodegroupName']
- params['labels'] = {}
- labels_to_add_or_update, labels_to_unset = compare_labels(nodegroup['labels'], param_labels)
+ params["clusterName"] = nodegroup["clusterName"]
+ params["nodegroupName"] = nodegroup["nodegroupName"]
+ params["labels"] = {}
+ labels_to_add_or_update, labels_to_unset = compare_labels(nodegroup["labels"], param_labels)
if labels_to_add_or_update:
- params['labels']['addOrUpdateLabels'] = labels_to_add_or_update
+ params["labels"]["addOrUpdateLabels"] = labels_to_add_or_update
if labels_to_unset:
- params['labels']['removeLabels'] = labels_to_unset
- if params['labels']:
+ params["labels"]["removeLabels"] = labels_to_unset
+ if params["labels"]:
if not module.check_mode:
changed = True
try:
client.update_nodegroup_config(**params)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Unable to set labels for Nodegroup %s.' % params['nodegroupName'])
+ module.fail_json_aws(e, msg=f"Unable to set labels for Nodegroup {params['nodegroupName']}.")
return changed
def compare_params(module, params, nodegroup):
- for param in ['nodeRole', 'subnets', 'diskSize', 'instanceTypes', 'amiTypes', 'remoteAccess', 'capacityType']:
+ for param in ["nodeRole", "subnets", "diskSize", "instanceTypes", "amiTypes", "remoteAccess", "capacityType"]:
if (param in nodegroup) and (param in params):
- if (nodegroup[param] != params[param]):
- module.fail_json(msg="Cannot modify parameter %s." % param)
- if ('launchTemplate' not in nodegroup) and ('launchTemplate' in params):
+ if nodegroup[param] != params[param]:
+ module.fail_json(msg=f"Cannot modify parameter {param}.")
+ if ("launchTemplate" not in nodegroup) and ("launchTemplate" in params):
module.fail_json(msg="Cannot add Launch Template in this Nodegroup.")
- if nodegroup['updateConfig'] != params['updateConfig']:
+ if nodegroup["updateConfig"] != params["updateConfig"]:
return True
- if nodegroup['scalingConfig'] != params['scalingConfig']:
+ if nodegroup["scalingConfig"] != params["scalingConfig"]:
return True
return False
def compare_params_launch_template(module, params, nodegroup):
- if 'launchTemplate' not in params:
+ if "launchTemplate" not in params:
module.fail_json(msg="Cannot exclude Launch Template in this Nodegroup.")
else:
- for key in ['name', 'id']:
- if (key in params['launchTemplate']) and (params['launchTemplate'][key] != nodegroup['launchTemplate'][key]):
- module.fail_json(msg="Cannot modify Launch Template %s." % key)
- if ('version' in params['launchTemplate']) and (params['launchTemplate']['version'] != nodegroup['launchTemplate']['version']):
+ for key in ["name", "id"]:
+ if (key in params["launchTemplate"]) and (
+ params["launchTemplate"][key] != nodegroup["launchTemplate"][key]
+ ):
+ module.fail_json(msg=f"Cannot modify Launch Template {key}.")
+ if ("version" in params["launchTemplate"]) and (
+ params["launchTemplate"]["version"] != nodegroup["launchTemplate"]["version"]
+ ):
return True
return False
def create_or_update_nodegroups(client, module):
-
changed = False
params = dict()
- params['nodegroupName'] = module.params['name']
- params['clusterName'] = module.params['cluster_name']
- params['nodeRole'] = module.params['node_role']
- params['subnets'] = module.params['subnets']
- params['tags'] = module.params['tags'] or {}
- if module.params['ami_type'] is not None:
- params['amiType'] = module.params['ami_type']
- if module.params['disk_size'] is not None:
- params['diskSize'] = module.params['disk_size']
- if module.params['instance_types'] is not None:
- params['instanceTypes'] = module.params['instance_types']
- if module.params['launch_template'] is not None:
- params['launchTemplate'] = dict()
- if module.params['launch_template']['id'] is not None:
- params['launchTemplate']['id'] = module.params['launch_template']['id']
- if module.params['launch_template']['version'] is not None:
- params['launchTemplate']['version'] = module.params['launch_template']['version']
- if module.params['launch_template']['name'] is not None:
- params['launchTemplate']['name'] = module.params['launch_template']['name']
- if module.params['release_version'] is not None:
- params['releaseVersion'] = module.params['release_version']
- if module.params['remote_access'] is not None:
- params['remoteAccess'] = dict()
- if module.params['remote_access']['ec2_ssh_key'] is not None:
- params['remoteAccess']['ec2SshKey'] = module.params['remote_access']['ec2_ssh_key']
- if module.params['remote_access']['source_sg'] is not None:
- params['remoteAccess']['sourceSecurityGroups'] = module.params['remote_access']['source_sg']
- if module.params['capacity_type'] is not None:
- params['capacityType'] = module.params['capacity_type'].upper()
- if module.params['labels'] is not None:
- params['labels'] = module.params['labels']
- if module.params['taints'] is not None:
- params['taints'] = module.params['taints']
- if module.params['update_config'] is not None:
- params['updateConfig'] = dict()
- if module.params['update_config']['max_unavailable'] is not None:
- params['updateConfig']['maxUnavailable'] = module.params['update_config']['max_unavailable']
- if module.params['update_config']['max_unavailable_percentage'] is not None:
- params['updateConfig']['maxUnavailablePercentage'] = module.params['update_config']['max_unavailable_percentage']
- if module.params['scaling_config'] is not None:
- params['scalingConfig'] = snake_dict_to_camel_dict(module.params['scaling_config'])
-
- wait = module.params.get('wait')
- nodegroup = get_nodegroup(client, module, params['nodegroupName'], params['clusterName'])
+ params["nodegroupName"] = module.params["name"]
+ params["clusterName"] = module.params["cluster_name"]
+ params["nodeRole"] = module.params["node_role"]
+ params["subnets"] = module.params["subnets"]
+ params["tags"] = module.params["tags"] or {}
+ if module.params["ami_type"] is not None:
+ params["amiType"] = module.params["ami_type"]
+ if module.params["disk_size"] is not None:
+ params["diskSize"] = module.params["disk_size"]
+ if module.params["instance_types"] is not None:
+ params["instanceTypes"] = module.params["instance_types"]
+ if module.params["launch_template"] is not None:
+ params["launchTemplate"] = dict()
+ if module.params["launch_template"]["id"] is not None:
+ params["launchTemplate"]["id"] = module.params["launch_template"]["id"]
+ if module.params["launch_template"]["version"] is not None:
+ params["launchTemplate"]["version"] = module.params["launch_template"]["version"]
+ if module.params["launch_template"]["name"] is not None:
+ params["launchTemplate"]["name"] = module.params["launch_template"]["name"]
+ if module.params["release_version"] is not None:
+ params["releaseVersion"] = module.params["release_version"]
+ if module.params["remote_access"] is not None:
+ params["remoteAccess"] = dict()
+ if module.params["remote_access"]["ec2_ssh_key"] is not None:
+ params["remoteAccess"]["ec2SshKey"] = module.params["remote_access"]["ec2_ssh_key"]
+ if module.params["remote_access"]["source_sg"] is not None:
+ params["remoteAccess"]["sourceSecurityGroups"] = module.params["remote_access"]["source_sg"]
+ if module.params["capacity_type"] is not None:
+ params["capacityType"] = module.params["capacity_type"].upper()
+ if module.params["labels"] is not None:
+ params["labels"] = module.params["labels"]
+ if module.params["taints"] is not None:
+ params["taints"] = module.params["taints"]
+ if module.params["update_config"] is not None:
+ params["updateConfig"] = dict()
+ if module.params["update_config"]["max_unavailable"] is not None:
+ params["updateConfig"]["maxUnavailable"] = module.params["update_config"]["max_unavailable"]
+ if module.params["update_config"]["max_unavailable_percentage"] is not None:
+ params["updateConfig"]["maxUnavailablePercentage"] = module.params["update_config"][
+ "max_unavailable_percentage"
+ ]
+ if module.params["scaling_config"] is not None:
+ params["scalingConfig"] = snake_dict_to_camel_dict(module.params["scaling_config"])
+
+ wait = module.params.get("wait")
+ nodegroup = get_nodegroup(client, module, params["nodegroupName"], params["clusterName"])
if nodegroup:
update_params = dict()
- update_params['clusterName'] = params['clusterName']
- update_params['nodegroupName'] = params['nodegroupName']
+ update_params["clusterName"] = params["clusterName"]
+ update_params["nodegroupName"] = params["nodegroupName"]
- if 'launchTemplate' in nodegroup:
+ if "launchTemplate" in nodegroup:
if compare_params_launch_template(module, params, nodegroup):
- update_params['launchTemplate'] = params['launchTemplate']
+ update_params["launchTemplate"] = params["launchTemplate"]
if not module.check_mode:
try:
client.update_nodegroup_version(**update_params)
@@ -554,10 +560,10 @@ def create_or_update_nodegroups(client, module):
if compare_params(module, params, nodegroup):
try:
- if 'launchTemplate' in update_params:
- update_params.pop('launchTemplate')
- update_params['scalingConfig'] = params['scalingConfig']
- update_params['updateConfig'] = params['updateConfig']
+ if "launchTemplate" in update_params:
+ update_params.pop("launchTemplate")
+ update_params["scalingConfig"] = params["scalingConfig"]
+ update_params["updateConfig"] = params["updateConfig"]
if not module.check_mode:
client.update_nodegroup_config(**update_params)
@@ -569,15 +575,15 @@ def create_or_update_nodegroups(client, module):
changed |= validate_tags(client, module, nodegroup)
- changed |= validate_labels(client, module, nodegroup, params['labels'])
+ changed |= validate_labels(client, module, nodegroup, params["labels"])
- if 'taints' in nodegroup:
- changed |= validate_taints(client, module, nodegroup, params['taints'])
+ if "taints" in nodegroup:
+ changed |= validate_taints(client, module, nodegroup, params["taints"])
if wait:
- wait_until(client, module, 'nodegroup_active', params['nodegroupName'], params['clusterName'])
+ wait_until(client, module, "nodegroup_active", params["nodegroupName"], params["clusterName"])
- nodegroup = get_nodegroup(client, module, params['nodegroupName'], params['clusterName'])
+ nodegroup = get_nodegroup(client, module, params["nodegroupName"], params["clusterName"])
module.exit_json(changed=changed, **camel_dict_to_snake_dict(nodegroup))
@@ -587,127 +593,172 @@ def create_or_update_nodegroups(client, module):
try:
nodegroup = client.create_nodegroup(**params)
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
- module.fail_json_aws(e, msg="Couldn't create Nodegroup %s." % params['nodegroupName'])
+ module.fail_json_aws(e, msg=f"Couldn't create Nodegroup {params['nodegroupName']}.")
if wait:
- wait_until(client, module, 'nodegroup_active', params['nodegroupName'], params['clusterName'])
- nodegroup = get_nodegroup(client, module, params['nodegroupName'], params['clusterName'])
+ wait_until(client, module, "nodegroup_active", params["nodegroupName"], params["clusterName"])
+ nodegroup = get_nodegroup(client, module, params["nodegroupName"], params["clusterName"])
module.exit_json(changed=True, **camel_dict_to_snake_dict(nodegroup))
def delete_nodegroups(client, module):
- name = module.params.get('name')
- clusterName = module.params['cluster_name']
+ name = module.params.get("name")
+ clusterName = module.params["cluster_name"]
existing = get_nodegroup(client, module, name, clusterName)
- wait = module.params.get('wait')
- if not existing or existing['status'] == 'DELETING':
- module.exit_json(changed=False, msg='Nodegroup not exists or in DELETING status.')
- if not module.check_mode:
- try:
- client.delete_nodegroup(clusterName=clusterName, nodegroupName=name)
- except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
- module.fail_json_aws(e, msg="Couldn't delete Nodegroup %s." % name)
+ wait = module.params.get("wait")
+ if not existing:
+ module.exit_json(changed=False, msg="Nodegroup '{name}' does not exist")
+
+ if existing["status"] == "DELETING":
if wait:
- wait_until(client, module, 'nodegroup_deleted', name, clusterName)
+ wait_until(client, module, "nodegroup_deleted", name, clusterName)
+ module.exit_json(changed=False, msg="Nodegroup '{name}' deletion complete")
+ module.exit_json(changed=False, msg="Nodegroup '{name}' already in DELETING state")
+
+ if module.check_mode:
+ module.exit_json(changed=True, msg="Nodegroup '{name}' deletion would be started (check mode)")
+
+ try:
+ client.delete_nodegroup(clusterName=clusterName, nodegroupName=name)
+ except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
+ module.fail_json_aws(e, msg=f"Couldn't delete Nodegroup '{name}'.")
+
+ if wait:
+ wait_until(client, module, "nodegroup_deleted", name, clusterName)
+ module.exit_json(changed=True, msg="Nodegroup '{name}' deletion complete")
- module.exit_json(changed=True)
+ module.exit_json(changed=True, msg="Nodegroup '{name}' deletion started")
def get_nodegroup(client, module, nodegroup_name, cluster_name):
try:
- return client.describe_nodegroup(clusterName=cluster_name, nodegroupName=nodegroup_name)['nodegroup']
- except is_boto3_error_code('ResourceNotFoundException'):
+ return client.describe_nodegroup(clusterName=cluster_name, nodegroupName=nodegroup_name)["nodegroup"]
+ except is_boto3_error_code("ResourceNotFoundException"):
return None
- except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, msg="Couldn't get Nodegroup %s." % nodegroup_name)
+ except (
+ botocore.exceptions.BotoCoreError,
+ botocore.exceptions.ClientError,
+ ) as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(e, msg=f"Couldn't get Nodegroup {nodegroup_name}.")
def wait_until(client, module, waiter_name, nodegroup_name, cluster_name):
- wait_timeout = module.params.get('wait_timeout')
+ wait_timeout = module.params.get("wait_timeout")
waiter = get_waiter(client, waiter_name)
attempts = 1 + int(wait_timeout / waiter.config.delay)
try:
- waiter.wait(clusterName=cluster_name, nodegroupName=nodegroup_name, WaiterConfig={'MaxAttempts': attempts})
+ waiter.wait(clusterName=cluster_name, nodegroupName=nodegroup_name, WaiterConfig={"MaxAttempts": attempts})
except botocore.exceptions.WaiterError as e:
module.fail_json_aws(e, msg="An error occurred waiting")
def main():
argument_spec = dict(
- name=dict(type='str', required=True),
- cluster_name=dict(type='str', required=True),
+ name=dict(type="str", required=True),
+ cluster_name=dict(type="str", required=True),
node_role=dict(),
- subnets=dict(type='list', elements='str'),
- scaling_config=dict(type='dict', default={'min_size': 1, 'max_size': 2, 'desired_size': 1}, options=dict(
- min_size=dict(type='int'),
- max_size=dict(type='int'),
- desired_size=dict(type='int')
- )),
- disk_size=dict(type='int'),
- instance_types=dict(type='list', elements='str'),
- ami_type=dict(choices=['AL2_x86_64', 'AL2_x86_64_GPU', 'AL2_ARM_64', 'CUSTOM', 'BOTTLEROCKET_ARM_64', 'BOTTLEROCKET_x86_64']),
- remote_access=dict(type='dict', options=dict(
- ec2_ssh_key=dict(no_log=True),
- source_sg=dict(type='list', elements='str')
- )),
- update_config=dict(type='dict', default={'max_unavailable': 1}, options=dict(
- max_unavailable=dict(type='int'),
- max_unavailable_percentage=dict(type='int')
- )),
- labels=dict(type='dict', default={}),
- taints=dict(type='list', elements='dict', default=[], options=dict(
- key=dict(type='str', no_log=False,),
- value=dict(type='str'),
- effect=dict(type='str', choices=['NO_SCHEDULE', 'NO_EXECUTE', 'PREFER_NO_SCHEDULE'])
- )),
- launch_template=dict(type='dict', options=dict(
- name=dict(type='str'),
- version=dict(type='str'),
- id=dict(type='str')
- )),
- capacity_type=dict(choices=['ON_DEMAND', 'SPOT'], default='ON_DEMAND'),
+ subnets=dict(type="list", elements="str"),
+ scaling_config=dict(
+ type="dict",
+ default={"min_size": 1, "max_size": 2, "desired_size": 1},
+ options=dict(
+ min_size=dict(type="int"),
+ max_size=dict(type="int"),
+ desired_size=dict(type="int"),
+ ),
+ ),
+ disk_size=dict(type="int"),
+ instance_types=dict(type="list", elements="str"),
+ ami_type=dict(
+ choices=[
+ "AL2_x86_64",
+ "AL2_x86_64_GPU",
+ "AL2_ARM_64",
+ "CUSTOM",
+ "BOTTLEROCKET_ARM_64",
+ "BOTTLEROCKET_x86_64",
+ ]
+ ),
+ remote_access=dict(
+ type="dict",
+ options=dict(
+ ec2_ssh_key=dict(no_log=True),
+ source_sg=dict(type="list", elements="str"),
+ ),
+ ),
+ update_config=dict(
+ type="dict",
+ default={"max_unavailable": 1},
+ options=dict(
+ max_unavailable=dict(type="int"),
+ max_unavailable_percentage=dict(type="int"),
+ ),
+ ),
+ labels=dict(type="dict", default={}),
+ taints=dict(
+ type="list",
+ elements="dict",
+ default=[],
+ options=dict(
+ key=dict(
+ type="str",
+ no_log=False,
+ ),
+ value=dict(type="str"),
+ effect=dict(type="str", choices=["NO_SCHEDULE", "NO_EXECUTE", "PREFER_NO_SCHEDULE"]),
+ ),
+ ),
+ launch_template=dict(
+ type="dict",
+ options=dict(
+ name=dict(type="str"),
+ version=dict(type="str"),
+ id=dict(type="str"),
+ ),
+ ),
+ capacity_type=dict(choices=["ON_DEMAND", "SPOT"], default="ON_DEMAND"),
release_version=dict(),
- tags=dict(type='dict', aliases=['resource_tags']),
- purge_tags=dict(type='bool', default=True),
- state=dict(choices=['absent', 'present'], default='present'),
- wait=dict(default=False, type='bool'),
- wait_timeout=dict(default=1200, type='int')
+ tags=dict(type="dict", aliases=["resource_tags"]),
+ purge_tags=dict(type="bool", default=True),
+ state=dict(choices=["absent", "present"], default="present"),
+ wait=dict(default=False, type="bool"),
+ wait_timeout=dict(default=1200, type="int"),
)
module = AnsibleAWSModule(
argument_spec=argument_spec,
- required_if=[['state', 'present', ['node_role', 'subnets']]],
+ required_if=[["state", "present", ["node_role", "subnets"]]],
mutually_exclusive=[
- ('launch_template', 'instance_types'),
- ('launch_template', 'disk_size'),
- ('launch_template', 'remote_access'),
- ('launch_template', 'ami_type')
+ ("launch_template", "instance_types"),
+ ("launch_template", "disk_size"),
+ ("launch_template", "remote_access"),
+ ("launch_template", "ami_type"),
],
supports_check_mode=True,
)
- if module.params['launch_template'] is None:
- if module.params['disk_size'] is None:
- module.params['disk_size'] = 20
- if module.params['ami_type'] is None:
- module.params['ami_type'] = "AL2_x86_64"
- if module.params['instance_types'] is None:
- module.params['instance_types'] = ["t3.medium"]
+ if module.params["launch_template"] is None:
+ if module.params["disk_size"] is None:
+ module.params["disk_size"] = 20
+ if module.params["ami_type"] is None:
+ module.params["ami_type"] = "AL2_x86_64"
+ if module.params["instance_types"] is None:
+ module.params["instance_types"] = ["t3.medium"]
else:
- if (module.params['launch_template']['id'] is None) and (module.params['launch_template']['name'] is None):
- module.exit_json(changed=False, msg='To use launch_template, it is necessary to inform the id or name.')
+ if (module.params["launch_template"]["id"] is None) and (module.params["launch_template"]["name"] is None):
+ module.exit_json(changed=False, msg="To use launch_template, it is necessary to inform the id or name.")
try:
- client = module.client('eks')
+ client = module.client("eks")
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
module.fail_json_aws(e, msg="Couldn't connect to AWS.")
- if module.params.get('state') == 'present':
+ if module.params.get("state") == "present":
create_or_update_nodegroups(client, module)
else:
delete_nodegroups(client, module)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/elasticache.py b/ansible_collections/community/aws/plugins/modules/elasticache.py
index 454baafe3..d45509cb6 100644
--- a/ansible_collections/community/aws/plugins/modules/elasticache.py
+++ b/ansible_collections/community/aws/plugins/modules/elasticache.py
@@ -1,13 +1,10 @@
#!/usr/bin/python
-#
+# -*- coding: utf-8 -*-
+
# Copyright (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: elasticache
version_added: 1.0.0
@@ -15,7 +12,8 @@ short_description: Manage cache clusters in Amazon ElastiCache
description:
- Manage cache clusters in Amazon ElastiCache.
- Returns information about the specified cache cluster.
-author: "Jim Dalton (@jsdalton)"
+author:
+ - "Jim Dalton (@jsdalton)"
options:
state:
description:
@@ -97,15 +95,15 @@ options:
- Defaults to C(false).
type: bool
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-'''
+RETURN = r""" # """
EXAMPLES = r"""
-# Note: None of these examples set aws_access_key, aws_secret_key, or region.
-# It is assumed that their matching environment variables are set.
+# Note: These examples do not set authentication details, see the AWS Guide for details.
- name: Basic example
community.aws.elasticache:
@@ -113,7 +111,7 @@ EXAMPLES = r"""
state: present
engine: memcached
cache_engine_version: 1.4.14
- node_type: cache.m1.small
+ node_type: cache.m3.small
num_nodes: 1
cache_port: 11211
cache_security_groups:
@@ -130,8 +128,8 @@ EXAMPLES = r"""
community.aws.elasticache:
name: "test-please-delete"
state: rebooted
-
"""
+
from time import sleep
try:
@@ -139,21 +137,34 @@ try:
except ImportError:
pass # Handled by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import get_aws_connection_info
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
-class ElastiCacheManager(object):
- """Handles elasticache creation and destruction"""
+class ElastiCacheManager:
- EXIST_STATUSES = ['available', 'creating', 'rebooting', 'modifying']
+ """Handles elasticache creation and destruction"""
- def __init__(self, module, name, engine, cache_engine_version, node_type,
- num_nodes, cache_port, cache_parameter_group, cache_subnet_group,
- cache_security_groups, security_group_ids, zone, wait,
- hard_modify, region, **aws_connect_kwargs):
+ EXIST_STATUSES = ["available", "creating", "rebooting", "modifying"]
+
+ def __init__(
+ self,
+ module,
+ name,
+ engine,
+ cache_engine_version,
+ node_type,
+ num_nodes,
+ cache_port,
+ cache_parameter_group,
+ cache_subnet_group,
+ cache_security_groups,
+ security_group_ids,
+ zone,
+ wait,
+ hard_modify,
+ ):
self.module = module
self.name = name
self.engine = engine.lower()
@@ -169,12 +180,9 @@ class ElastiCacheManager(object):
self.wait = wait
self.hard_modify = hard_modify
- self.region = region
- self.aws_connect_kwargs = aws_connect_kwargs
-
self.changed = False
self.data = None
- self.status = 'gone'
+ self.status = "gone"
self.conn = self._get_elasticache_connection()
self._refresh_data()
@@ -199,32 +207,33 @@ class ElastiCacheManager(object):
def create(self):
"""Create an ElastiCache cluster"""
- if self.status == 'available':
+ if self.status == "available":
return
- if self.status in ['creating', 'rebooting', 'modifying']:
+ if self.status in ["creating", "rebooting", "modifying"]:
if self.wait:
- self._wait_for_status('available')
+ self._wait_for_status("available")
return
- if self.status == 'deleting':
+ if self.status == "deleting":
if self.wait:
- self._wait_for_status('gone')
+ self._wait_for_status("gone")
else:
- msg = "'%s' is currently deleting. Cannot create."
- self.module.fail_json(msg=msg % self.name)
-
- kwargs = dict(CacheClusterId=self.name,
- NumCacheNodes=self.num_nodes,
- CacheNodeType=self.node_type,
- Engine=self.engine,
- EngineVersion=self.cache_engine_version,
- CacheSecurityGroupNames=self.cache_security_groups,
- SecurityGroupIds=self.security_group_ids,
- CacheParameterGroupName=self.cache_parameter_group,
- CacheSubnetGroupName=self.cache_subnet_group)
+ self.module.fail_json(msg=f"'{self.name}' is currently deleting. Cannot create.")
+
+ kwargs = dict(
+ CacheClusterId=self.name,
+ NumCacheNodes=self.num_nodes,
+ CacheNodeType=self.node_type,
+ Engine=self.engine,
+ EngineVersion=self.cache_engine_version,
+ CacheSecurityGroupNames=self.cache_security_groups,
+ SecurityGroupIds=self.security_group_ids,
+ CacheParameterGroupName=self.cache_parameter_group,
+ CacheSubnetGroupName=self.cache_subnet_group,
+ )
if self.cache_port is not None:
- kwargs['Port'] = self.cache_port
+ kwargs["Port"] = self.cache_port
if self.zone is not None:
- kwargs['PreferredAvailabilityZone'] = self.zone
+ kwargs["PreferredAvailabilityZone"] = self.zone
try:
self.conn.create_cache_cluster(**kwargs)
@@ -236,45 +245,43 @@ class ElastiCacheManager(object):
self.changed = True
if self.wait:
- self._wait_for_status('available')
+ self._wait_for_status("available")
return True
def delete(self):
"""Destroy an ElastiCache cluster"""
- if self.status == 'gone':
+ if self.status == "gone":
return
- if self.status == 'deleting':
+ if self.status == "deleting":
if self.wait:
- self._wait_for_status('gone')
+ self._wait_for_status("gone")
return
- if self.status in ['creating', 'rebooting', 'modifying']:
+ if self.status in ["creating", "rebooting", "modifying"]:
if self.wait:
- self._wait_for_status('available')
+ self._wait_for_status("available")
else:
- msg = "'%s' is currently %s. Cannot delete."
- self.module.fail_json(msg=msg % (self.name, self.status))
+ self.module.fail_json(msg=f"'{self.name}' is currently {self.status}. Cannot delete.")
try:
response = self.conn.delete_cache_cluster(CacheClusterId=self.name)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
self.module.fail_json_aws(e, msg="Failed to delete cache cluster")
- cache_cluster_data = response['CacheCluster']
+ cache_cluster_data = response["CacheCluster"]
self._refresh_data(cache_cluster_data)
self.changed = True
if self.wait:
- self._wait_for_status('gone')
+ self._wait_for_status("gone")
def sync(self):
"""Sync settings to cluster if required"""
if not self.exists():
- msg = "'%s' is %s. Cannot sync."
- self.module.fail_json(msg=msg % (self.name, self.status))
+ self.module.fail_json(msg=f"'{self.name}' is {self.status}. Cannot sync.")
- if self.status in ['creating', 'rebooting', 'modifying']:
+ if self.status in ["creating", "rebooting", "modifying"]:
if self.wait:
- self._wait_for_status('available')
+ self._wait_for_status("available")
else:
# Cluster can only be synced if available. If we can't wait
# for this, then just be done.
@@ -282,11 +289,13 @@ class ElastiCacheManager(object):
if self._requires_destroy_and_create():
if not self.hard_modify:
- msg = "'%s' requires destructive modification. 'hard_modify' must be set to true to proceed."
- self.module.fail_json(msg=msg % self.name)
+ self.module.fail_json(
+ msg=f"'{self.name}' requires destructive modification. 'hard_modify' must be set to true to proceed."
+ )
if not self.wait:
- msg = "'%s' requires destructive modification. 'wait' must be set to true."
- self.module.fail_json(msg=msg % self.name)
+ self.module.fail_json(
+ msg=f"'{self.name}' requires destructive modification. 'wait' must be set to true to proceed."
+ )
self.delete()
self.create()
return
@@ -298,14 +307,16 @@ class ElastiCacheManager(object):
"""Modify the cache cluster. Note it's only possible to modify a few select options."""
nodes_to_remove = self._get_nodes_to_remove()
try:
- self.conn.modify_cache_cluster(CacheClusterId=self.name,
- NumCacheNodes=self.num_nodes,
- CacheNodeIdsToRemove=nodes_to_remove,
- CacheSecurityGroupNames=self.cache_security_groups,
- CacheParameterGroupName=self.cache_parameter_group,
- SecurityGroupIds=self.security_group_ids,
- ApplyImmediately=True,
- EngineVersion=self.cache_engine_version)
+ self.conn.modify_cache_cluster(
+ CacheClusterId=self.name,
+ NumCacheNodes=self.num_nodes,
+ CacheNodeIdsToRemove=nodes_to_remove,
+ CacheSecurityGroupNames=self.cache_security_groups,
+ CacheParameterGroupName=self.cache_parameter_group,
+ SecurityGroupIds=self.security_group_ids,
+ ApplyImmediately=True,
+ EngineVersion=self.cache_engine_version,
+ )
except botocore.exceptions.ClientError as e:
self.module.fail_json_aws(e, msg="Failed to modify cache cluster")
@@ -313,27 +324,24 @@ class ElastiCacheManager(object):
self.changed = True
if self.wait:
- self._wait_for_status('available')
+ self._wait_for_status("available")
def reboot(self):
"""Reboot the cache cluster"""
if not self.exists():
- msg = "'%s' is %s. Cannot reboot."
- self.module.fail_json(msg=msg % (self.name, self.status))
- if self.status == 'rebooting':
+ self.module.fail_json(msg=f"'{self.name}' is {self.status}. Cannot reboot.")
+ if self.status == "rebooting":
return
- if self.status in ['creating', 'modifying']:
+ if self.status in ["creating", "modifying"]:
if self.wait:
- self._wait_for_status('available')
+ self._wait_for_status("available")
else:
- msg = "'%s' is currently %s. Cannot reboot."
- self.module.fail_json(msg=msg % (self.name, self.status))
+ self.module.fail_json(msg=f"'{self.name}' is currently {self.status}. Cannot reboot.")
# Collect ALL nodes for reboot
- cache_node_ids = [cn['CacheNodeId'] for cn in self.data['CacheNodes']]
+ cache_node_ids = [cn["CacheNodeId"] for cn in self.data["CacheNodes"]]
try:
- self.conn.reboot_cache_cluster(CacheClusterId=self.name,
- CacheNodeIdsToReboot=cache_node_ids)
+ self.conn.reboot_cache_cluster(CacheClusterId=self.name, CacheNodeIdsToReboot=cache_node_ids)
except botocore.exceptions.ClientError as e:
self.module.fail_json_aws(e, msg="Failed to reboot cache cluster")
@@ -341,36 +349,28 @@ class ElastiCacheManager(object):
self.changed = True
if self.wait:
- self._wait_for_status('available')
+ self._wait_for_status("available")
def get_info(self):
"""Return basic info about the cache cluster"""
- info = {
- 'name': self.name,
- 'status': self.status
- }
+ info = {"name": self.name, "status": self.status}
if self.data:
- info['data'] = self.data
+ info["data"] = self.data
return info
def _wait_for_status(self, awaited_status):
"""Wait for status to change from present status to awaited_status"""
- status_map = {
- 'creating': 'available',
- 'rebooting': 'available',
- 'modifying': 'available',
- 'deleting': 'gone'
- }
+ status_map = {"creating": "available", "rebooting": "available", "modifying": "available", "deleting": "gone"}
if self.status == awaited_status:
# No need to wait, we're already done
return
if status_map[self.status] != awaited_status:
- msg = "Invalid awaited status. '%s' cannot transition to '%s'"
- self.module.fail_json(msg=msg % (self.status, awaited_status))
+ self.module.fail_json(
+ msg=f"Invalid awaited status. '{self.status}' cannot transition to '{awaited_status}'"
+ )
if awaited_status not in set(status_map.values()):
- msg = "'%s' is not a valid awaited status."
- self.module.fail_json(msg=msg % awaited_status)
+ self.module.fail_json(msg=f"'{awaited_status}' is not a valid awaited status.")
while True:
sleep(1)
@@ -381,27 +381,24 @@ class ElastiCacheManager(object):
def _requires_modification(self):
"""Check if cluster requires (nondestructive) modification"""
# Check modifiable data attributes
- modifiable_data = {
- 'NumCacheNodes': self.num_nodes,
- 'EngineVersion': self.cache_engine_version
- }
+ modifiable_data = {"NumCacheNodes": self.num_nodes, "EngineVersion": self.cache_engine_version}
for key, value in modifiable_data.items():
if value is not None and value and self.data[key] != value:
return True
# Check cache security groups
cache_security_groups = []
- for sg in self.data['CacheSecurityGroups']:
- cache_security_groups.append(sg['CacheSecurityGroupName'])
+ for sg in self.data["CacheSecurityGroups"]:
+ cache_security_groups.append(sg["CacheSecurityGroupName"])
if set(cache_security_groups) != set(self.cache_security_groups):
return True
# check vpc security groups
if self.security_group_ids:
vpc_security_groups = []
- security_groups = self.data.get('SecurityGroups', [])
+ security_groups = self.data.get("SecurityGroups", [])
for sg in security_groups:
- vpc_security_groups.append(sg['SecurityGroupId'])
+ vpc_security_groups.append(sg["SecurityGroupId"])
if set(vpc_security_groups) != set(self.security_group_ids):
return True
@@ -412,13 +409,13 @@ class ElastiCacheManager(object):
Check whether a destroy and create is required to synchronize cluster.
"""
unmodifiable_data = {
- 'node_type': self.data['CacheNodeType'],
- 'engine': self.data['Engine'],
- 'cache_port': self._get_port()
+ "node_type": self.data["CacheNodeType"],
+ "engine": self.data["Engine"],
+ "cache_port": self._get_port(),
}
# Only check for modifications if zone is specified
if self.zone is not None:
- unmodifiable_data['zone'] = self.data['PreferredAvailabilityZone']
+ unmodifiable_data["zone"] = self.data["PreferredAvailabilityZone"]
for key, value in unmodifiable_data.items():
if getattr(self, key) is not None and getattr(self, key) != value:
return True
@@ -427,18 +424,18 @@ class ElastiCacheManager(object):
def _get_elasticache_connection(self):
"""Get an elasticache connection"""
try:
- return self.module.client('elasticache')
+ return self.module.client("elasticache")
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, msg='Failed to connect to AWS')
+ self.module.fail_json_aws(e, msg="Failed to connect to AWS")
def _get_port(self):
"""Get the port. Where this information is retrieved from is engine dependent."""
- if self.data['Engine'] == 'memcached':
- return self.data['ConfigurationEndpoint']['Port']
- elif self.data['Engine'] == 'redis':
+ if self.data["Engine"] == "memcached":
+ return self.data["ConfigurationEndpoint"]["Port"]
+ elif self.data["Engine"] == "redis":
# Redis only supports a single node (presently) so just use
# the first and only
- return self.data['CacheNodes'][0]['Endpoint']['Port']
+ return self.data["CacheNodes"][0]["Endpoint"]["Port"]
def _refresh_data(self, cache_cluster_data=None):
"""Refresh data about this cache cluster"""
@@ -446,104 +443,110 @@ class ElastiCacheManager(object):
if cache_cluster_data is None:
try:
response = self.conn.describe_cache_clusters(CacheClusterId=self.name, ShowCacheNodeInfo=True)
- except is_boto3_error_code('CacheClusterNotFound'):
+ except is_boto3_error_code("CacheClusterNotFound"):
self.data = None
- self.status = 'gone'
+ self.status = "gone"
return
except botocore.exceptions.ClientError as e: # pylint: disable=duplicate-except
self.module.fail_json_aws(e, msg="Failed to describe cache clusters")
- cache_cluster_data = response['CacheClusters'][0]
+ cache_cluster_data = response["CacheClusters"][0]
self.data = cache_cluster_data
- self.status = self.data['CacheClusterStatus']
+ self.status = self.data["CacheClusterStatus"]
# The documentation for elasticache lies -- status on rebooting is set
# to 'rebooting cache cluster nodes' instead of 'rebooting'. Fix it
# here to make status checks etc. more sane.
- if self.status == 'rebooting cache cluster nodes':
- self.status = 'rebooting'
+ if self.status == "rebooting cache cluster nodes":
+ self.status = "rebooting"
def _get_nodes_to_remove(self):
"""If there are nodes to remove, it figures out which need to be removed"""
- num_nodes_to_remove = self.data['NumCacheNodes'] - self.num_nodes
+ num_nodes_to_remove = self.data["NumCacheNodes"] - self.num_nodes
if num_nodes_to_remove <= 0:
return []
if not self.hard_modify:
- msg = "'%s' requires removal of cache nodes. 'hard_modify' must be set to true to proceed."
- self.module.fail_json(msg=msg % self.name)
+ self.module.fail_json(
+ msg=f"'{self.name}' requires removal of cache nodes. 'hard_modify' must be set to true to proceed."
+ )
- cache_node_ids = [cn['CacheNodeId'] for cn in self.data['CacheNodes']]
+ cache_node_ids = [cn["CacheNodeId"] for cn in self.data["CacheNodes"]]
return cache_node_ids[-num_nodes_to_remove:]
def main():
- """ elasticache ansible module """
+ """elasticache ansible module"""
argument_spec = dict(
- state=dict(required=True, choices=['present', 'absent', 'rebooted']),
+ state=dict(required=True, choices=["present", "absent", "rebooted"]),
name=dict(required=True),
- engine=dict(default='memcached'),
+ engine=dict(default="memcached"),
cache_engine_version=dict(default=""),
- node_type=dict(default='cache.t2.small'),
- num_nodes=dict(default=1, type='int'),
+ node_type=dict(default="cache.t2.small"),
+ num_nodes=dict(default=1, type="int"),
# alias for compat with the original PR 1950
- cache_parameter_group=dict(default="", aliases=['parameter_group']),
- cache_port=dict(type='int'),
+ cache_parameter_group=dict(default="", aliases=["parameter_group"]),
+ cache_port=dict(type="int"),
cache_subnet_group=dict(default=""),
- cache_security_groups=dict(default=[], type='list', elements='str'),
- security_group_ids=dict(default=[], type='list', elements='str'),
+ cache_security_groups=dict(default=[], type="list", elements="str"),
+ security_group_ids=dict(default=[], type="list", elements="str"),
zone=dict(),
- wait=dict(default=True, type='bool'),
- hard_modify=dict(type='bool'),
+ wait=dict(default=True, type="bool"),
+ hard_modify=dict(type="bool"),
)
module = AnsibleAWSModule(
argument_spec=argument_spec,
)
- region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module)
-
- name = module.params['name']
- state = module.params['state']
- engine = module.params['engine']
- cache_engine_version = module.params['cache_engine_version']
- node_type = module.params['node_type']
- num_nodes = module.params['num_nodes']
- cache_port = module.params['cache_port']
- cache_subnet_group = module.params['cache_subnet_group']
- cache_security_groups = module.params['cache_security_groups']
- security_group_ids = module.params['security_group_ids']
- zone = module.params['zone']
- wait = module.params['wait']
- hard_modify = module.params['hard_modify']
- cache_parameter_group = module.params['cache_parameter_group']
+ name = module.params["name"]
+ state = module.params["state"]
+ engine = module.params["engine"]
+ cache_engine_version = module.params["cache_engine_version"]
+ node_type = module.params["node_type"]
+ num_nodes = module.params["num_nodes"]
+ cache_port = module.params["cache_port"]
+ cache_subnet_group = module.params["cache_subnet_group"]
+ cache_security_groups = module.params["cache_security_groups"]
+ security_group_ids = module.params["security_group_ids"]
+ zone = module.params["zone"]
+ wait = module.params["wait"]
+ hard_modify = module.params["hard_modify"]
+ cache_parameter_group = module.params["cache_parameter_group"]
if cache_subnet_group and cache_security_groups:
module.fail_json(msg="Can't specify both cache_subnet_group and cache_security_groups")
- if state == 'present' and not num_nodes:
+ if state == "present" and not num_nodes:
module.fail_json(msg="'num_nodes' is a required parameter. Please specify num_nodes > 0")
- elasticache_manager = ElastiCacheManager(module, name, engine,
- cache_engine_version, node_type,
- num_nodes, cache_port,
- cache_parameter_group,
- cache_subnet_group,
- cache_security_groups,
- security_group_ids, zone, wait,
- hard_modify, region, **aws_connect_kwargs)
+ elasticache_manager = ElastiCacheManager(
+ module,
+ name,
+ engine,
+ cache_engine_version,
+ node_type,
+ num_nodes,
+ cache_port,
+ cache_parameter_group,
+ cache_subnet_group,
+ cache_security_groups,
+ security_group_ids,
+ zone,
+ wait,
+ hard_modify,
+ )
- if state == 'present':
+ if state == "present":
elasticache_manager.ensure_present()
- elif state == 'absent':
+ elif state == "absent":
elasticache_manager.ensure_absent()
- elif state == 'rebooted':
+ elif state == "rebooted":
elasticache_manager.ensure_rebooted()
- facts_result = dict(changed=elasticache_manager.changed,
- elasticache=elasticache_manager.get_info())
+ facts_result = dict(changed=elasticache_manager.changed, elasticache=elasticache_manager.get_info())
module.exit_json(**facts_result)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/elasticache_info.py b/ansible_collections/community/aws/plugins/modules/elasticache_info.py
index f6c34629e..50a8cb5ff 100644
--- a/ansible_collections/community/aws/plugins/modules/elasticache_info.py
+++ b/ansible_collections/community/aws/plugins/modules/elasticache_info.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
module: elasticache_info
short_description: Retrieve information for AWS ElastiCache clusters
version_added: 1.0.0
@@ -20,21 +18,21 @@ options:
author:
- Will Thames (@willthames)
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
- name: obtain all ElastiCache information
community.aws.elasticache_info:
- name: obtain all information for a single ElastiCache cluster
community.aws.elasticache_info:
name: test_elasticache
-'''
+"""
-RETURN = '''
+RETURN = r"""
elasticache_clusters:
description: List of ElastiCache clusters.
returned: always
@@ -402,93 +400,82 @@ elasticache_clusters:
sample:
Application: web
Environment: test
-'''
-
-from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict
-
+"""
try:
import botocore
except ImportError:
pass # caught by AnsibleAWSModule
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.iam import get_aws_account_info
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
+
@AWSRetry.exponential_backoff()
def describe_cache_clusters_with_backoff(client, cluster_id=None):
- paginator = client.get_paginator('describe_cache_clusters')
+ paginator = client.get_paginator("describe_cache_clusters")
params = dict(ShowCacheNodeInfo=True)
if cluster_id:
- params['CacheClusterId'] = cluster_id
+ params["CacheClusterId"] = cluster_id
try:
response = paginator.paginate(**params).build_full_result()
- except is_boto3_error_code('CacheClusterNotFound'):
+ except is_boto3_error_code("CacheClusterNotFound"):
return []
- return response['CacheClusters']
+ return response["CacheClusters"]
@AWSRetry.exponential_backoff()
def describe_replication_group_with_backoff(client, replication_group_id):
try:
response = client.describe_replication_groups(ReplicationGroupId=replication_group_id)
- except is_boto3_error_code('ReplicationGroupNotFoundFault'):
+ except is_boto3_error_code("ReplicationGroupNotFoundFault"):
return None
- return response['ReplicationGroups'][0]
+ return response["ReplicationGroups"][0]
@AWSRetry.exponential_backoff()
def get_elasticache_tags_with_backoff(client, cluster_id):
- return client.list_tags_for_resource(ResourceName=cluster_id)['TagList']
-
-
-def get_aws_account_id(module):
- try:
- client = module.client('sts')
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Can't authorize connection")
-
- try:
- return client.get_caller_identity()['Account']
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Couldn't obtain AWS account id")
+ return client.list_tags_for_resource(ResourceName=cluster_id)["TagList"]
def get_elasticache_clusters(client, module):
region = module.region
try:
- clusters = describe_cache_clusters_with_backoff(client, cluster_id=module.params.get('name'))
+ clusters = describe_cache_clusters_with_backoff(client, cluster_id=module.params.get("name"))
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Couldn't obtain cache cluster info")
- account_id = get_aws_account_id(module)
+ account_id, partition = get_aws_account_info(module)
results = []
for cluster in clusters:
-
cluster = camel_dict_to_snake_dict(cluster)
- arn = "arn:aws:elasticache:%s:%s:cluster:%s" % (region, account_id, cluster['cache_cluster_id'])
+ arn = f"arn:{partition}:elasticache:{region}:{account_id}:cluster:{cluster['cache_cluster_id']}"
try:
tags = get_elasticache_tags_with_backoff(client, arn)
except is_boto3_error_code("CacheClusterNotFound"):
# e.g: Cluster was listed but is in deleting state
continue
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Couldn't get tags for cluster %s")
+ module.fail_json_aws(e, msg=f"Couldn't get tags for cluster {cluster['cache_cluster_id']}")
- cluster['tags'] = boto3_tag_list_to_ansible_dict(tags)
+ cluster["tags"] = boto3_tag_list_to_ansible_dict(tags)
- if cluster.get('replication_group_id', None):
+ if cluster.get("replication_group_id", None):
try:
- replication_group = describe_replication_group_with_backoff(client, cluster['replication_group_id'])
+ replication_group = describe_replication_group_with_backoff(client, cluster["replication_group_id"])
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Couldn't obtain replication group info")
if replication_group is not None:
replication_group = camel_dict_to_snake_dict(replication_group)
- cluster['replication_group'] = replication_group
+ cluster["replication_group"] = replication_group
results.append(cluster)
return results
@@ -500,10 +487,10 @@ def main():
)
module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
- client = module.client('elasticache')
+ client = module.client("elasticache")
module.exit_json(elasticache_clusters=get_elasticache_clusters(client, module))
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/elasticache_parameter_group.py b/ansible_collections/community/aws/plugins/modules/elasticache_parameter_group.py
index 247dd0bab..fa7f87a2f 100644
--- a/ansible_collections/community/aws/plugins/modules/elasticache_parameter_group.py
+++ b/ansible_collections/community/aws/plugins/modules/elasticache_parameter_group.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
-# This file is part of Ansible
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
+# -*- coding: utf-8 -*-
+# Copyright: Contributors to the Ansible project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: elasticache_parameter_group
version_added: 1.0.0
@@ -14,11 +12,8 @@ short_description: Manage cache parameter groups in Amazon ElastiCache.
description:
- Manage cache security groups in Amazon ElastiCache.
- Returns information about the specified cache cluster.
-author: "Sloane Hertel (@s-hertel)"
-extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
+author:
+ - "Sloane Hertel (@s-hertel)"
options:
group_family:
@@ -47,13 +42,17 @@ options:
description:
- A user-specified dictionary of parameters to reset or modify for the cache parameter group.
type: dict
-'''
-EXAMPLES = """
-# Note: None of these examples set aws_access_key, aws_secret_key, or region.
-# It is assumed that their matching environment variables are set.
----
-- hosts: localhost
+extends_documentation_fragment:
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
+
+EXAMPLES = r"""
+# Note: These examples do not set authentication details, see the AWS Guide for details.
+- name: Create, modify and delete a parameter group
+ hosts: localhost
connection: local
tasks:
- name: 'Create a test parameter group'
@@ -66,7 +65,7 @@ EXAMPLES = """
community.aws.elasticache_parameter_group:
name: 'test-param-group'
values:
- activerehashing: yes
+ activerehashing: true
client-output-buffer-limit-normal-hard-limit: 4
state: 'present'
- name: 'Reset all modifiable parameters for the test parameter group'
@@ -79,7 +78,7 @@ EXAMPLES = """
state: 'absent'
"""
-RETURN = """
+RETURN = r"""
elasticache:
description: cache parameter group information and response metadata
returned: always
@@ -115,13 +114,15 @@ from ansible.module_utils._text import to_text
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
from ansible.module_utils.six import string_types
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def create(module, conn, name, group_family, description):
- """ Create ElastiCache parameter group. """
+ """Create ElastiCache parameter group."""
try:
- response = conn.create_cache_parameter_group(CacheParameterGroupName=name, CacheParameterGroupFamily=group_family, Description=description)
+ response = conn.create_cache_parameter_group(
+ CacheParameterGroupName=name, CacheParameterGroupFamily=group_family, Description=description
+ )
changed = True
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Unable to create cache parameter group.")
@@ -129,7 +130,7 @@ def create(module, conn, name, group_family, description):
def delete(module, conn, name):
- """ Delete ElastiCache parameter group. """
+ """Delete ElastiCache parameter group."""
try:
conn.delete_cache_parameter_group(CacheParameterGroupName=name)
response = {}
@@ -140,10 +141,10 @@ def delete(module, conn, name):
def make_current_modifiable_param_dict(module, conn, name):
- """ Gets the current state of the cache parameter group and creates a dict with the format: {ParameterName: [Allowed_Values, DataType, ParameterValue]}"""
+ """Gets the current state of the cache parameter group and creates a dict with the format: {ParameterName: [Allowed_Values, DataType, ParameterValue]}"""
current_info = get_info(conn, name)
if current_info is False:
- module.fail_json(msg="Could not connect to the cache parameter group %s." % name)
+ module.fail_json(msg=f"Could not connect to the cache parameter group {name}.")
parameters = current_info["Parameters"]
modifiable_params = {}
@@ -157,7 +158,7 @@ def make_current_modifiable_param_dict(module, conn, name):
def check_valid_modification(module, values, modifiable_params):
- """ Check if the parameters and values in values are valid. """
+ """Check if the parameters and values in values are valid."""
changed_with_update = False
for parameter in values:
@@ -165,7 +166,9 @@ def check_valid_modification(module, values, modifiable_params):
# check valid modifiable parameters
if parameter not in modifiable_params:
- module.fail_json(msg="%s is not a modifiable parameter. Valid parameters to modify are: %s." % (parameter, modifiable_params.keys()))
+ module.fail_json(
+ msg=f"{parameter} is not a modifiable parameter. Valid parameters to modify are: {modifiable_params.keys()}."
+ )
# check allowed datatype for modified parameters
str_to_type = {"integer": int, "string": string_types}
@@ -180,18 +183,27 @@ def check_valid_modification(module, values, modifiable_params):
if isinstance(new_value, bool):
values[parameter] = 1 if new_value else 0
else:
- module.fail_json(msg="%s (type %s) is not an allowed value for the parameter %s. Expected a type %s." %
- (new_value, type(new_value), parameter, modifiable_params[parameter][1]))
+ module.fail_json(
+ msg=(
+ f"{new_value} (type {type(new_value)}) is not an allowed value for the parameter"
+ f" {parameter}. Expected a type {modifiable_params[parameter][1]}."
+ )
+ )
else:
- module.fail_json(msg="%s (type %s) is not an allowed value for the parameter %s. Expected a type %s." %
- (new_value, type(new_value), parameter, modifiable_params[parameter][1]))
+ module.fail_json(
+ msg=(
+ f"{new_value} (type {type(new_value)}) is not an allowed value for the parameter {parameter}."
+ f" Expected a type {modifiable_params[parameter][1]}."
+ )
+ )
# check allowed values for modifiable parameters
choices = modifiable_params[parameter][0]
if choices:
if not (to_text(new_value) in choices or isinstance(new_value, int)):
- module.fail_json(msg="%s is not an allowed value for the parameter %s. Valid parameters are: %s." %
- (new_value, parameter, choices))
+ module.fail_json(
+ msg=f"{new_value} is not an allowed value for the parameter {parameter}. Valid parameters are: {choices}."
+ )
# check if a new value is different from current value
if to_text(values[parameter]) != modifiable_params[parameter][2]:
@@ -201,7 +213,7 @@ def check_valid_modification(module, values, modifiable_params):
def check_changed_parameter_values(values, old_parameters, new_parameters):
- """ Checking if the new values are different than the old values. """
+ """Checking if the new values are different than the old values."""
changed_with_update = False
# if the user specified parameters to reset, only check those for change
@@ -221,21 +233,23 @@ def check_changed_parameter_values(values, old_parameters, new_parameters):
def modify(module, conn, name, values):
- """ Modify ElastiCache parameter group to reflect the new information if it differs from the current. """
+ """Modify ElastiCache parameter group to reflect the new information if it differs from the current."""
# compares current group parameters with the parameters we've specified to to a value to see if this will change the group
format_parameters = []
for key in values:
value = to_text(values[key])
- format_parameters.append({'ParameterName': key, 'ParameterValue': value})
+ format_parameters.append({"ParameterName": key, "ParameterValue": value})
try:
- response = conn.modify_cache_parameter_group(CacheParameterGroupName=name, ParameterNameValues=format_parameters)
+ response = conn.modify_cache_parameter_group(
+ CacheParameterGroupName=name, ParameterNameValues=format_parameters
+ )
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Unable to modify cache parameter group.")
return response
def reset(module, conn, name, values):
- """ Reset ElastiCache parameter group if the current information is different from the new information. """
+ """Reset ElastiCache parameter group if the current information is different from the new information."""
# used to compare with the reset parameters' dict to see if there have been changes
old_parameters_dict = make_current_modifiable_param_dict(module, conn, name)
@@ -247,12 +261,14 @@ def reset(module, conn, name, values):
format_parameters = []
for key in values:
value = to_text(values[key])
- format_parameters.append({'ParameterName': key, 'ParameterValue': value})
+ format_parameters.append({"ParameterName": key, "ParameterValue": value})
else:
all_parameters = True
try:
- response = conn.reset_cache_parameter_group(CacheParameterGroupName=name, ParameterNameValues=format_parameters, ResetAllParameters=all_parameters)
+ response = conn.reset_cache_parameter_group(
+ CacheParameterGroupName=name, ParameterNameValues=format_parameters, ResetAllParameters=all_parameters
+ )
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Unable to reset cache parameter group.")
@@ -264,7 +280,7 @@ def reset(module, conn, name, values):
def get_info(conn, name):
- """ Gets info about the ElastiCache parameter group. Returns false if it doesn't exist or we don't have access. """
+ """Gets info about the ElastiCache parameter group. Returns false if it doesn't exist or we don't have access."""
try:
data = conn.describe_cache_parameters(CacheParameterGroupName=name)
return data
@@ -274,36 +290,50 @@ def get_info(conn, name):
def main():
argument_spec = dict(
- group_family=dict(type='str', choices=['memcached1.4', 'memcached1.5', 'redis2.6', 'redis2.8', 'redis3.2', 'redis4.0', 'redis5.0', 'redis6.x']),
- name=dict(required=True, type='str'),
- description=dict(default='', type='str'),
- state=dict(required=True, choices=['present', 'absent', 'reset']),
- values=dict(type='dict'),
+ group_family=dict(
+ type="str",
+ choices=[
+ "memcached1.4",
+ "memcached1.5",
+ "redis2.6",
+ "redis2.8",
+ "redis3.2",
+ "redis4.0",
+ "redis5.0",
+ "redis6.x",
+ ],
+ ),
+ name=dict(required=True, type="str"),
+ description=dict(default="", type="str"),
+ state=dict(required=True, choices=["present", "absent", "reset"]),
+ values=dict(type="dict"),
)
module = AnsibleAWSModule(argument_spec=argument_spec)
- parameter_group_family = module.params.get('group_family')
- parameter_group_name = module.params.get('name')
- group_description = module.params.get('description')
- state = module.params.get('state')
- values = module.params.get('values')
+ parameter_group_family = module.params.get("group_family")
+ parameter_group_name = module.params.get("name")
+ group_description = module.params.get("description")
+ state = module.params.get("state")
+ values = module.params.get("values")
try:
- connection = module.client('elasticache')
+ connection = module.client("elasticache")
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to connect to AWS')
+ module.fail_json_aws(e, msg="Failed to connect to AWS")
exists = get_info(connection, parameter_group_name)
# check that the needed requirements are available
- if state == 'present' and not (exists or parameter_group_family):
+ if state == "present" and not (exists or parameter_group_family):
module.fail_json(msg="Creating a group requires a family group.")
- elif state == 'reset' and not exists:
- module.fail_json(msg="No group %s to reset. Please create the group before using the state 'reset'." % parameter_group_name)
+ elif state == "reset" and not exists:
+ module.fail_json(
+ msg=f"No group {parameter_group_name} to reset. Please create the group before using the state 'reset'."
+ )
# Taking action
changed = False
- if state == 'present':
+ if state == "present":
if exists:
# confirm that the group exists without any actions
if not values:
@@ -316,19 +346,21 @@ def main():
response = modify(module, connection, parameter_group_name, values)
# create group
else:
- response, changed = create(module, connection, parameter_group_name, parameter_group_family, group_description)
+ response, changed = create(
+ module, connection, parameter_group_name, parameter_group_family, group_description
+ )
if values:
modifiable_params = make_current_modifiable_param_dict(module, connection, parameter_group_name)
changed, values = check_valid_modification(module, values, modifiable_params)
response = modify(module, connection, parameter_group_name, values)
- elif state == 'absent':
+ elif state == "absent":
if exists:
# delete group
response, changed = delete(module, connection, parameter_group_name)
else:
response = {}
changed = False
- elif state == 'reset':
+ elif state == "reset":
response, changed = reset(module, connection, parameter_group_name, values)
facts_result = dict(changed=changed, elasticache=camel_dict_to_snake_dict(response))
@@ -336,5 +368,5 @@ def main():
module.exit_json(**facts_result)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/elasticache_snapshot.py b/ansible_collections/community/aws/plugins/modules/elasticache_snapshot.py
index fa18b80c0..0816527fb 100644
--- a/ansible_collections/community/aws/plugins/modules/elasticache_snapshot.py
+++ b/ansible_collections/community/aws/plugins/modules/elasticache_snapshot.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: elasticache_snapshot
version_added: 1.0.0
@@ -14,11 +12,8 @@ short_description: Manage cache snapshots in Amazon ElastiCache
description:
- Manage cache snapshots in Amazon ElastiCache.
- Returns information about the specified snapshot.
-author: "Sloane Hertel (@s-hertel)"
-extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
+author:
+ - "Sloane Hertel (@s-hertel)"
options:
name:
description:
@@ -47,11 +42,14 @@ options:
description:
- The s3 bucket to which the snapshot is exported.
type: str
-'''
+extends_documentation_fragment:
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-EXAMPLES = """
-# Note: None of these examples set aws_access_key, aws_secret_key, or region.
-# It is assumed that their matching environment variables are set.
+EXAMPLES = r"""
+# Note: These examples do not set authentication details, see the AWS Guide for details.
- name: 'Create a snapshot'
community.aws.elasticache_snapshot:
@@ -61,7 +59,7 @@ EXAMPLES = """
replication_id: '{{ replication }}'
"""
-RETURN = """
+RETURN = r"""
response_metadata:
description: response metadata about the snapshot
returned: always
@@ -117,18 +115,19 @@ except ImportError:
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def create(module, connection, replication_id, cluster_id, name):
- """ Create an ElastiCache backup. """
+ """Create an ElastiCache backup."""
try:
- response = connection.create_snapshot(ReplicationGroupId=replication_id,
- CacheClusterId=cluster_id,
- SnapshotName=name)
+ response = connection.create_snapshot(
+ ReplicationGroupId=replication_id, CacheClusterId=cluster_id, SnapshotName=name
+ )
changed = True
- except is_boto3_error_code('SnapshotAlreadyExistsFault'):
+ except is_boto3_error_code("SnapshotAlreadyExistsFault"):
response = {}
changed = False
except botocore.exceptions.ClientError as e: # pylint: disable=duplicate-except
@@ -137,11 +136,9 @@ def create(module, connection, replication_id, cluster_id, name):
def copy(module, connection, name, target, bucket):
- """ Copy an ElastiCache backup. """
+ """Copy an ElastiCache backup."""
try:
- response = connection.copy_snapshot(SourceSnapshotName=name,
- TargetSnapshotName=target,
- TargetBucket=bucket)
+ response = connection.copy_snapshot(SourceSnapshotName=name, TargetSnapshotName=target, TargetBucket=bucket)
changed = True
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Unable to copy the snapshot.")
@@ -149,16 +146,20 @@ def copy(module, connection, name, target, bucket):
def delete(module, connection, name):
- """ Delete an ElastiCache backup. """
+ """Delete an ElastiCache backup."""
try:
response = connection.delete_snapshot(SnapshotName=name)
changed = True
- except is_boto3_error_code('SnapshotNotFoundFault'):
+ except is_boto3_error_code("SnapshotNotFoundFault"):
response = {}
changed = False
- except is_boto3_error_code('InvalidSnapshotState'): # pylint: disable=duplicate-except
- module.fail_json(msg="Error: InvalidSnapshotState. The snapshot is not in an available state or failed state to allow deletion."
- "You may need to wait a few minutes.")
+ except is_boto3_error_code("InvalidSnapshotState"): # pylint: disable=duplicate-except
+ module.fail_json(
+ msg=(
+ "Error: InvalidSnapshotState. The snapshot is not in an available state or failed state to allow"
+ " deletion.You may need to wait a few minutes."
+ )
+ )
except botocore.exceptions.ClientError as e: # pylint: disable=duplicate-except
module.fail_json_aws(e, msg="Unable to delete the snapshot.")
return response, changed
@@ -166,38 +167,38 @@ def delete(module, connection, name):
def main():
argument_spec = dict(
- name=dict(required=True, type='str'),
- state=dict(required=True, type='str', choices=['present', 'absent', 'copy']),
- replication_id=dict(type='str'),
- cluster_id=dict(type='str'),
- target=dict(type='str'),
- bucket=dict(type='str'),
+ name=dict(required=True, type="str"),
+ state=dict(required=True, type="str", choices=["present", "absent", "copy"]),
+ replication_id=dict(type="str"),
+ cluster_id=dict(type="str"),
+ target=dict(type="str"),
+ bucket=dict(type="str"),
)
module = AnsibleAWSModule(argument_spec=argument_spec)
- name = module.params.get('name')
- state = module.params.get('state')
- replication_id = module.params.get('replication_id')
- cluster_id = module.params.get('cluster_id')
- target = module.params.get('target')
- bucket = module.params.get('bucket')
+ name = module.params.get("name")
+ state = module.params.get("state")
+ replication_id = module.params.get("replication_id")
+ cluster_id = module.params.get("cluster_id")
+ target = module.params.get("target")
+ bucket = module.params.get("bucket")
try:
- connection = module.client('elasticache')
+ connection = module.client("elasticache")
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to connect to AWS')
+ module.fail_json_aws(e, msg="Failed to connect to AWS")
changed = False
response = {}
- if state == 'present':
+ if state == "present":
if not all((replication_id, cluster_id)):
module.fail_json(msg="The state 'present' requires options: 'replication_id' and 'cluster_id'")
response, changed = create(module, connection, replication_id, cluster_id, name)
- elif state == 'absent':
+ elif state == "absent":
response, changed = delete(module, connection, name)
- elif state == 'copy':
+ elif state == "copy":
if not all((target, bucket)):
module.fail_json(msg="The state 'copy' requires options: 'target' and 'bucket'.")
response, changed = copy(module, connection, name, target, bucket)
@@ -207,5 +208,5 @@ def main():
module.exit_json(**facts_result)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/elasticache_subnet_group.py b/ansible_collections/community/aws/plugins/modules/elasticache_subnet_group.py
index 0f5f5e75e..f7740e696 100644
--- a/ansible_collections/community/aws/plugins/modules/elasticache_subnet_group.py
+++ b/ansible_collections/community/aws/plugins/modules/elasticache_subnet_group.py
@@ -1,18 +1,16 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: elasticache_subnet_group
version_added: 1.0.0
short_description: manage ElastiCache subnet groups
description:
- - Creates, modifies, and deletes ElastiCache subnet groups.
+ - Creates, modifies, and deletes ElastiCache subnet groups.
options:
state:
description:
@@ -40,12 +38,12 @@ options:
author:
- "Tim Mahoney (@timmahoney)"
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
- name: Add or change a subnet group
community.aws.elasticache_subnet_group:
state: present
@@ -59,9 +57,9 @@ EXAMPLES = r'''
community.aws.elasticache_subnet_group:
state: absent
name: norwegian-blue
-'''
+"""
-RETURN = r'''
+RETURN = r"""
cache_subnet_group:
description: Description of the Elasticache Subnet Group.
returned: always
@@ -95,7 +93,7 @@ cache_subnet_group:
sample:
- subnet-aaaaaaaa
- subnet-bbbbbbbb
-'''
+"""
try:
import botocore
@@ -104,9 +102,10 @@ except ImportError:
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def get_subnet_group(name):
@@ -114,10 +113,13 @@ def get_subnet_group(name):
groups = client.describe_cache_subnet_groups(
aws_retry=True,
CacheSubnetGroupName=name,
- )['CacheSubnetGroups']
- except is_boto3_error_code('CacheSubnetGroupNotFoundFault'):
+ )["CacheSubnetGroups"]
+ except is_boto3_error_code("CacheSubnetGroupNotFoundFault"):
return None
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
module.fail_json_aws(e, msg="Failed to describe subnet group")
if not groups:
@@ -131,19 +133,18 @@ def get_subnet_group(name):
subnet_group = camel_dict_to_snake_dict(groups[0])
- subnet_group['name'] = subnet_group['cache_subnet_group_name']
- subnet_group['description'] = subnet_group['cache_subnet_group_description']
+ subnet_group["name"] = subnet_group["cache_subnet_group_name"]
+ subnet_group["description"] = subnet_group["cache_subnet_group_description"]
- subnet_ids = list(s['subnet_identifier'] for s in subnet_group['subnets'])
- subnet_group['subnet_ids'] = subnet_ids
+ subnet_ids = list(s["subnet_identifier"] for s in subnet_group["subnets"])
+ subnet_group["subnet_ids"] = subnet_ids
return subnet_group
def create_subnet_group(name, description, subnets):
-
if not subnets:
- module.fail_json(msg='At least one subnet must be provided when creating a subnet group')
+ module.fail_json(msg="At least one subnet must be provided when creating a subnet group")
if module.check_mode:
return True
@@ -164,13 +165,13 @@ def create_subnet_group(name, description, subnets):
def update_subnet_group(subnet_group, name, description, subnets):
update_params = dict()
- if description and subnet_group['description'] != description:
- update_params['CacheSubnetGroupDescription'] = description
+ if description and subnet_group["description"] != description:
+ update_params["CacheSubnetGroupDescription"] = description
if subnets:
- old_subnets = set(subnet_group['subnet_ids'])
+ old_subnets = set(subnet_group["subnet_ids"])
new_subnets = set(subnets)
if old_subnets != new_subnets:
- update_params['SubnetIds'] = list(subnets)
+ update_params["SubnetIds"] = list(subnets)
if not update_params:
return False
@@ -191,7 +192,6 @@ def update_subnet_group(subnet_group, name, description, subnets):
def delete_subnet_group(name):
-
if module.check_mode:
return True
@@ -201,20 +201,23 @@ def delete_subnet_group(name):
CacheSubnetGroupName=name,
)
return True
- except is_boto3_error_code('CacheSubnetGroupNotFoundFault'):
+ except is_boto3_error_code("CacheSubnetGroupNotFoundFault"):
# AWS is "eventually consistent", cope with the race conditions where
# deletion hadn't completed when we ran describe
return False
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
module.fail_json_aws(e, msg="Failed to delete subnet group")
def main():
argument_spec = dict(
- state=dict(default='present', choices=['present', 'absent']),
+ state=dict(default="present", choices=["present", "absent"]),
name=dict(required=True),
description=dict(required=False),
- subnets=dict(required=False, type='list', elements='str'),
+ subnets=dict(required=False, type="list", elements="str"),
)
global module
@@ -225,17 +228,17 @@ def main():
supports_check_mode=True,
)
- state = module.params.get('state')
- name = module.params.get('name').lower()
- description = module.params.get('description')
- subnets = module.params.get('subnets')
+ state = module.params.get("state")
+ name = module.params.get("name").lower()
+ description = module.params.get("description")
+ subnets = module.params.get("subnets")
- client = module.client('elasticache', retry_decorator=AWSRetry.jittered_backoff())
+ client = module.client("elasticache", retry_decorator=AWSRetry.jittered_backoff())
subnet_group = get_subnet_group(name)
changed = False
- if state == 'present':
+ if state == "present":
if not subnet_group:
result = create_subnet_group(name, description, subnets)
changed |= result
@@ -252,5 +255,5 @@ def main():
module.exit_json(changed=changed, cache_subnet_group=subnet_group)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/elasticbeanstalk_app.py b/ansible_collections/community/aws/plugins/modules/elasticbeanstalk_app.py
index b5b32c178..1aaa4c4d8 100644
--- a/ansible_collections/community/aws/plugins/modules/elasticbeanstalk_app.py
+++ b/ansible_collections/community/aws/plugins/modules/elasticbeanstalk_app.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: elasticbeanstalk_app
version_added: 1.0.0
@@ -43,12 +41,12 @@ author:
- Harpreet Singh (@hsingh)
- Stephen Granger (@viper233)
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
# Create or update an application
- community.aws.elasticbeanstalk_app:
app_name: Sample_App
@@ -59,10 +57,9 @@ EXAMPLES = '''
- community.aws.elasticbeanstalk_app:
app_name: Sample_App
state: absent
+"""
-'''
-
-RETURN = '''
+RETURN = r"""
app:
description: Beanstalk application.
returned: always
@@ -83,15 +80,16 @@ output:
returned: in check mode
type: str
sample: App is up-to-date
-'''
+"""
try:
import botocore
except ImportError:
pass # handled by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_message
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_message
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def describe_app(ebs, app_name, module):
@@ -113,24 +111,24 @@ def list_apps(ebs, app_name, module):
def check_app(ebs, app, module):
- app_name = module.params['app_name']
- description = module.params['description']
- state = module.params['state']
- terminate_by_force = module.params['terminate_by_force']
+ app_name = module.params["app_name"]
+ description = module.params["description"]
+ state = module.params["state"]
+ terminate_by_force = module.params["terminate_by_force"]
result = {}
- if state == 'present' and app is None:
+ if state == "present" and app is None:
result = dict(changed=True, output="App would be created")
- elif state == 'present' and app.get("Description", None) != description:
+ elif state == "present" and app.get("Description", None) != description:
result = dict(changed=True, output="App would be updated", app=app)
- elif state == 'present' and app.get("Description", None) == description:
+ elif state == "present" and app.get("Description", None) == description:
result = dict(changed=False, output="App is up-to-date", app=app)
- elif state == 'absent' and app is None:
+ elif state == "absent" and app is None:
result = dict(changed=False, output="App does not exist", app={})
- elif state == 'absent' and app is not None:
+ elif state == "absent" and app is not None:
result = dict(changed=True, output="App will be deleted", app=app)
- elif state == 'absent' and app is not None and terminate_by_force is True:
+ elif state == "absent" and app is not None and terminate_by_force is True:
result = dict(changed=True, output="Running environments terminated before the App will be deleted", app=app)
module.exit_json(**result)
@@ -146,37 +144,36 @@ def filter_empty(**kwargs):
def main():
argument_spec = dict(
- app_name=dict(aliases=['name'], type='str', required=False),
+ app_name=dict(aliases=["name"], type="str", required=False),
description=dict(),
- state=dict(choices=['present', 'absent'], default='present'),
- terminate_by_force=dict(type='bool', default=False, required=False)
+ state=dict(choices=["present", "absent"], default="present"),
+ terminate_by_force=dict(type="bool", default=False, required=False),
)
module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
- app_name = module.params['app_name']
- description = module.params['description']
- state = module.params['state']
- terminate_by_force = module.params['terminate_by_force']
+ app_name = module.params["app_name"]
+ description = module.params["description"]
+ state = module.params["state"]
+ terminate_by_force = module.params["terminate_by_force"]
if app_name is None:
module.fail_json(msg='Module parameter "app_name" is required')
result = {}
- ebs = module.client('elasticbeanstalk')
+ ebs = module.client("elasticbeanstalk")
app = describe_app(ebs, app_name, module)
if module.check_mode:
check_app(ebs, app, module)
- module.fail_json(msg='ASSERTION FAILURE: check_app() should not return control.')
+ module.fail_json(msg="ASSERTION FAILURE: check_app() should not return control.")
- if state == 'present':
+ if state == "present":
if app is None:
try:
- create_app = ebs.create_application(**filter_empty(ApplicationName=app_name,
- Description=description))
+ create_app = ebs.create_application(**filter_empty(ApplicationName=app_name, Description=description))
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Could not create application")
@@ -201,7 +198,7 @@ def main():
else:
if app is None:
- result = dict(changed=False, output='Application not found', app={})
+ result = dict(changed=False, output="Application not found", app={})
else:
try:
if terminate_by_force:
@@ -210,9 +207,12 @@ def main():
else:
ebs.delete_application(ApplicationName=app_name)
changed = True
- except is_boto3_error_message('It is currently pending deletion'):
+ except is_boto3_error_message("It is currently pending deletion"):
changed = False
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
module.fail_json_aws(e, msg="Cannot terminate app")
result = dict(changed=changed, app=app)
@@ -220,5 +220,5 @@ def main():
module.exit_json(**result)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/elb_classic_lb_info.py b/ansible_collections/community/aws/plugins/modules/elb_classic_lb_info.py
index 4cbeb9589..5329e5b81 100644
--- a/ansible_collections/community/aws/plugins/modules/elb_classic_lb_info.py
+++ b/ansible_collections/community/aws/plugins/modules/elb_classic_lb_info.py
@@ -1,29 +1,16 @@
#!/usr/bin/python
-#
-# This is a free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This Ansible library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this library. If not, see <http://www.gnu.org/licenses/>.
-
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+# -*- coding: utf-8 -*-
+
+# Copyright: Contributors to the Ansible project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r"""
---
module: elb_classic_lb_info
version_added: 1.0.0
short_description: Gather information about EC2 Elastic Load Balancers in AWS
description:
- - Gather information about EC2 Elastic Load Balancers in AWS
+ - Gather information about EC2 Elastic Load Balancers in AWS
author:
- "Michael Schultz (@mjschultz)"
- "Fernando Jose Pando (@nand0p)"
@@ -35,12 +22,12 @@ options:
elements: str
default: []
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
-'''
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide for details.
# Output format tries to match amazon.aws.ec2_elb_lb module input parameters
@@ -63,17 +50,16 @@ EXAMPLES = r'''
# Gather information about a set of ELBs
- community.aws.elb_classic_lb_info:
names:
- - frontend-prod-elb
- - backend-prod-elb
+ - frontend-prod-elb
+ - backend-prod-elb
register: elb_info
- ansible.builtin.debug:
msg: "{{ item.dns_name }}"
loop: "{{ elb_info.elbs }}"
+"""
-'''
-
-RETURN = r'''
+RETURN = r"""
elbs:
description: a list of load balancers
returned: always
@@ -137,20 +123,21 @@ elbs:
- subnet-XXXXXXXX
tags: {}
vpc_id: vpc-c248fda4
-'''
-
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule, is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import (
- AWSRetry,
- camel_dict_to_snake_dict,
- boto3_tag_list_to_ansible_dict
-)
+"""
try:
import botocore
except ImportError:
pass # caught by AnsibleAWSModule
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
+
MAX_AWS_RETRIES = 5
MAX_AWS_DELAY = 5
@@ -172,63 +159,79 @@ def list_elbs(connection, load_balancer_names):
def describe_elb(connection, lb):
description = camel_dict_to_snake_dict(lb)
- name = lb['LoadBalancerName']
- instances = lb.get('Instances', [])
- description['tags'] = get_tags(connection, name)
- description['instances_inservice'], description['instances_inservice_count'] = lb_instance_health(connection, name, instances, 'InService')
- description['instances_outofservice'], description['instances_outofservice_count'] = lb_instance_health(connection, name, instances, 'OutOfService')
- description['instances_unknownservice'], description['instances_unknownservice_count'] = lb_instance_health(connection, name, instances, 'Unknown')
- description['attributes'] = get_lb_attributes(connection, name)
+ name = lb["LoadBalancerName"]
+ instances = lb.get("Instances", [])
+ description["tags"] = get_tags(connection, name)
+ description["instances_inservice"], description["instances_inservice_count"] = lb_instance_health(
+ connection, name, instances, "InService"
+ )
+ description["instances_outofservice"], description["instances_outofservice_count"] = lb_instance_health(
+ connection, name, instances, "OutOfService"
+ )
+ description["instances_unknownservice"], description["instances_unknownservice_count"] = lb_instance_health(
+ connection, name, instances, "Unknown"
+ )
+ description["attributes"] = get_lb_attributes(connection, name)
return description
@AWSRetry.jittered_backoff()
def get_all_lb(connection):
- paginator = connection.get_paginator('describe_load_balancers')
- return paginator.paginate().build_full_result()['LoadBalancerDescriptions']
+ paginator = connection.get_paginator("describe_load_balancers")
+ return paginator.paginate().build_full_result()["LoadBalancerDescriptions"]
def get_lb(connection, load_balancer_name):
try:
- return connection.describe_load_balancers(aws_retry=True, LoadBalancerNames=[load_balancer_name])['LoadBalancerDescriptions'][0]
- except is_boto3_error_code('LoadBalancerNotFound'):
+ return connection.describe_load_balancers(aws_retry=True, LoadBalancerNames=[load_balancer_name])[
+ "LoadBalancerDescriptions"
+ ][0]
+ except is_boto3_error_code("LoadBalancerNotFound"):
return []
def get_lb_attributes(connection, load_balancer_name):
- attributes = connection.describe_load_balancer_attributes(aws_retry=True, LoadBalancerName=load_balancer_name).get('LoadBalancerAttributes', {})
+ attributes = connection.describe_load_balancer_attributes(aws_retry=True, LoadBalancerName=load_balancer_name).get(
+ "LoadBalancerAttributes", {}
+ )
return camel_dict_to_snake_dict(attributes)
def get_tags(connection, load_balancer_name):
- tags = connection.describe_tags(aws_retry=True, LoadBalancerNames=[load_balancer_name])['TagDescriptions']
+ tags = connection.describe_tags(aws_retry=True, LoadBalancerNames=[load_balancer_name])["TagDescriptions"]
if not tags:
return {}
- return boto3_tag_list_to_ansible_dict(tags[0]['Tags'])
+ return boto3_tag_list_to_ansible_dict(tags[0]["Tags"])
def lb_instance_health(connection, load_balancer_name, instances, state):
- instance_states = connection.describe_instance_health(LoadBalancerName=load_balancer_name, Instances=instances).get('InstanceStates', [])
- instate = [instance['InstanceId'] for instance in instance_states if instance['State'] == state]
+ instance_states = connection.describe_instance_health(LoadBalancerName=load_balancer_name, Instances=instances).get(
+ "InstanceStates", []
+ )
+ instate = [instance["InstanceId"] for instance in instance_states if instance["State"] == state]
return instate, len(instate)
def main():
argument_spec = dict(
- names=dict(default=[], type='list', elements='str')
+ names=dict(default=[], type="list", elements="str"),
+ )
+ module = AnsibleAWSModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
)
- module = AnsibleAWSModule(argument_spec=argument_spec,
- supports_check_mode=True)
- connection = module.client('elb', retry_decorator=AWSRetry.jittered_backoff(retries=MAX_AWS_RETRIES, delay=MAX_AWS_DELAY))
+ connection = module.client(
+ "elb", retry_decorator=AWSRetry.jittered_backoff(retries=MAX_AWS_RETRIES, delay=MAX_AWS_DELAY)
+ )
try:
- elbs = list_elbs(connection, module.params.get('names'))
+ elbs = list_elbs(connection, module.params.get("names"))
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Failed to get load balancer information.")
module.exit_json(elbs=elbs)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/elb_instance.py b/ansible_collections/community/aws/plugins/modules/elb_instance.py
index ecea32a63..6489a86bc 100644
--- a/ansible_collections/community/aws/plugins/modules/elb_instance.py
+++ b/ansible_collections/community/aws/plugins/modules/elb_instance.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: elb_instance
version_added: 1.0.0
@@ -15,7 +13,8 @@ description:
- This module de-registers or registers an AWS EC2 instance from the ELBs
that it belongs to.
- Will be marked changed when called only if there are ELBs found to operate on.
-author: "John Jarvis (@jarv)"
+author:
+ - "John Jarvis (@jarv)"
options:
state:
description:
@@ -55,13 +54,13 @@ options:
default: 0
type: int
notes:
-- The ec2_elbs fact previously set by this module was deprecated in release 2.1.0 and since release
- 4.0.0 is no longer set.
+ - The ec2_elbs fact previously set by this module was deprecated in release 2.1.0 and since release
+ 4.0.0 is no longer set.
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
-'''
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
EXAMPLES = r"""
# basic pre_task and post_task example
@@ -83,22 +82,23 @@ post_tasks:
delegate_to: localhost
"""
-RETURN = '''
+RETURN = r"""
updated_elbs:
description: A list of ELB names that the instance has been added to or removed from.
returned: always
type: list
elements: str
-'''
+"""
try:
import botocore
except ImportError:
pass # Handled by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
class ElbManager:
@@ -107,9 +107,9 @@ class ElbManager:
def __init__(self, module, instance_id=None, ec2_elbs=None):
retry_decorator = AWSRetry.jittered_backoff()
self.module = module
- self.client_asg = module.client('autoscaling', retry_decorator=retry_decorator)
- self.client_ec2 = module.client('ec2', retry_decorator=retry_decorator)
- self.client_elb = module.client('elb', retry_decorator=retry_decorator)
+ self.client_asg = module.client("autoscaling", retry_decorator=retry_decorator)
+ self.client_ec2 = module.client("ec2", retry_decorator=retry_decorator)
+ self.client_elb = module.client("elb", retry_decorator=retry_decorator)
self.instance_id = instance_id
self.lbs = self._get_instance_lbs(ec2_elbs)
self.changed = False
@@ -120,11 +120,11 @@ class ElbManager:
to report it out-of-service"""
for lb in self.lbs:
- instance_ids = [i['InstanceId'] for i in lb['Instances']]
+ instance_ids = [i["InstanceId"] for i in lb["Instances"]]
if self.instance_id not in instance_ids:
continue
- self.updated_elbs.add(lb['LoadBalancerName'])
+ self.updated_elbs.add(lb["LoadBalancerName"])
if self.module.check_mode:
self.changed = True
@@ -133,12 +133,13 @@ class ElbManager:
try:
self.client_elb.deregister_instances_from_load_balancer(
aws_retry=True,
- LoadBalancerName=lb['LoadBalancerName'],
+ LoadBalancerName=lb["LoadBalancerName"],
Instances=[{"InstanceId": self.instance_id}],
)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, 'Failed to deregister instance from load balancer',
- load_balancer=lb, instance=self.instance_id)
+ self.module.fail_json_aws(
+ e, "Failed to deregister instance from load balancer", load_balancer=lb, instance=self.instance_id
+ )
# The ELB is changing state in some way. Either an instance that's
# InService is moving to OutOfService, or an instance that's
@@ -147,17 +148,17 @@ class ElbManager:
if wait:
for lb in self.lbs:
- self._await_elb_instance_state(lb, 'Deregistered', timeout)
+ self._await_elb_instance_state(lb, "Deregistered", timeout)
def register(self, wait, enable_availability_zone, timeout):
"""Register the instance for all ELBs and wait for the ELB
to report the instance in-service"""
for lb in self.lbs:
- instance_ids = [i['InstanceId'] for i in lb['Instances']]
+ instance_ids = [i["InstanceId"] for i in lb["Instances"]]
if self.instance_id in instance_ids:
continue
- self.updated_elbs.add(lb['LoadBalancerName'])
+ self.updated_elbs.add(lb["LoadBalancerName"])
if enable_availability_zone:
self.changed |= self._enable_availailability_zone(lb)
@@ -169,31 +170,32 @@ class ElbManager:
try:
self.client_elb.register_instances_with_load_balancer(
aws_retry=True,
- LoadBalancerName=lb['LoadBalancerName'],
+ LoadBalancerName=lb["LoadBalancerName"],
Instances=[{"InstanceId": self.instance_id}],
)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, 'Failed to register instance with load balancer',
- load_balancer=lb, instance=self.instance_id)
+ self.module.fail_json_aws(
+ e, "Failed to register instance with load balancer", load_balancer=lb, instance=self.instance_id
+ )
self.changed = True
if wait:
for lb in self.lbs:
- self._await_elb_instance_state(lb, 'InService', timeout)
+ self._await_elb_instance_state(lb, "InService", timeout)
@AWSRetry.jittered_backoff()
def _describe_elbs(self, **params):
- paginator = self.client_elb.get_paginator('describe_load_balancers')
+ paginator = self.client_elb.get_paginator("describe_load_balancers")
results = paginator.paginate(**params).build_full_result()
- return results['LoadBalancerDescriptions']
+ return results["LoadBalancerDescriptions"]
def exists(self, lbtest):
- """ Verify that the named ELB actually exists """
+ """Verify that the named ELB actually exists"""
found = False
for lb in self.lbs:
- if lb['LoadBalancerName'] == lbtest:
+ if lb["LoadBalancerName"] == lbtest:
found = True
break
return found
@@ -203,9 +205,9 @@ class ElbManager:
Returns True if the zone was enabled or False if no change was made.
lb: load balancer"""
instance = self._get_instance()
- desired_zone = instance['Placement']['AvailabilityZone']
+ desired_zone = instance["Placement"]["AvailabilityZone"]
- if desired_zone in lb['AvailabilityZones']:
+ if desired_zone in lb["AvailabilityZones"]:
return False
if self.module.check_mode:
@@ -214,12 +216,11 @@ class ElbManager:
try:
self.client_elb.enable_availability_zones_for_load_balancer(
aws_retry=True,
- LoadBalancerName=lb['LoadBalancerName'],
+ LoadBalancerName=lb["LoadBalancerName"],
AvailabilityZones=[desired_zone],
)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, 'Failed to enable AZ on load balancers',
- load_balancer=lb, zone=desired_zone)
+ self.module.fail_json_aws(e, "Failed to enable AZ on load balancers", load_balancer=lb, zone=desired_zone)
return True
@@ -233,27 +234,29 @@ class ElbManager:
if awaited_state == initial_state:
return
- if awaited_state == 'InService':
- waiter = self.client_elb.get_waiter('instance_in_service')
- elif awaited_state == 'Deregistered':
- waiter = self.client_elb.get_waiter('instance_deregistered')
- elif awaited_state == 'OutOfService':
- waiter = self.client_elb.get_waiter('instance_deregistered')
+ if awaited_state == "InService":
+ waiter = self.client_elb.get_waiter("instance_in_service")
+ elif awaited_state == "Deregistered":
+ waiter = self.client_elb.get_waiter("instance_deregistered")
+ elif awaited_state == "OutOfService":
+ waiter = self.client_elb.get_waiter("instance_deregistered")
else:
- self.module.fail_json(msg='Could not wait for unknown state', awaited_state=awaited_state)
+ self.module.fail_json(msg="Could not wait for unknown state", awaited_state=awaited_state)
try:
waiter.wait(
- LoadBalancerName=lb['LoadBalancerName'],
+ LoadBalancerName=lb["LoadBalancerName"],
Instances=[{"InstanceId": self.instance_id}],
- WaiterConfig={'Delay': 1, 'MaxAttempts': timeout},
+ WaiterConfig={"Delay": 1, "MaxAttempts": timeout},
)
except botocore.exceptions.WaiterError as e:
- self.module.fail_json_aws(e, msg='Timeout waiting for instance to reach desired state',
- awaited_state=awaited_state)
+ self.module.fail_json_aws(
+ e, msg="Timeout waiting for instance to reach desired state", awaited_state=awaited_state
+ )
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, msg='Error while waiting for instance to reach desired state',
- awaited_state=awaited_state)
+ self.module.fail_json_aws(
+ e, msg="Error while waiting for instance to reach desired state", awaited_state=awaited_state
+ )
return
@@ -265,18 +268,21 @@ class ElbManager:
try:
status = self.client_elb.describe_instance_health(
aws_retry=True,
- LoadBalancerName=lb['LoadBalancerName'],
- Instances=[{'InstanceId': self.instance_id}],
- )['InstanceStates']
- except is_boto3_error_code('InvalidInstance'):
+ LoadBalancerName=lb["LoadBalancerName"],
+ Instances=[{"InstanceId": self.instance_id}],
+ )["InstanceStates"]
+ except is_boto3_error_code("InvalidInstance"):
return None
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
- self.module.fail_json_aws(e, msg='Failed to get instance health')
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
+ self.module.fail_json_aws(e, msg="Failed to get instance health")
if not status:
return None
- return status[0]['State']
+ return status[0]["State"]
def _get_instance_lbs(self, ec2_elbs=None):
"""Returns a list of ELBs attached to self.instance_id
@@ -289,12 +295,12 @@ class ElbManager:
ec2_elbs = self._get_auto_scaling_group_lbs()
if ec2_elbs:
- list_params['LoadBalancerNames'] = ec2_elbs
+ list_params["LoadBalancerNames"] = ec2_elbs
try:
elbs = self._describe_elbs(**list_params)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, 'Failed to describe load balancers')
+ self.module.fail_json_aws(e, "Failed to describe load balancers")
if ec2_elbs:
return elbs
@@ -303,7 +309,7 @@ class ElbManager:
# of.
lbs = []
for lb in elbs:
- instance_ids = [i['InstanceId'] for i in lb['Instances']]
+ instance_ids = [i["InstanceId"] for i in lb["Instances"]]
if self.instance_id in instance_ids:
lbs.append(lb)
@@ -311,14 +317,14 @@ class ElbManager:
def _get_auto_scaling_group_lbs(self):
"""Returns a list of ELBs associated with self.instance_id
- indirectly through its auto scaling group membership"""
+ indirectly through its auto scaling group membership"""
try:
asg_instances = self.client_asg.describe_auto_scaling_instances(
- aws_retry=True,
- InstanceIds=[self.instance_id])['AutoScalingInstances']
+ aws_retry=True, InstanceIds=[self.instance_id]
+ )["AutoScalingInstances"]
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, msg='Failed to describe ASG Instance')
+ self.module.fail_json_aws(e, msg="Failed to describe ASG Instance")
if len(asg_instances) > 1:
self.module.fail_json(msg="Illegal state, expected one auto scaling group instance.")
@@ -327,42 +333,40 @@ class ElbManager:
# Instance isn't a member of an ASG
return []
- asg_name = asg_instances[0]['AutoScalingGroupName']
+ asg_name = asg_instances[0]["AutoScalingGroupName"]
try:
asg_instances = self.client_asg.describe_auto_scaling_groups(
- aws_retry=True,
- AutoScalingGroupNames=[asg_name])['AutoScalingGroups']
+ aws_retry=True, AutoScalingGroupNames=[asg_name]
+ )["AutoScalingGroups"]
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, msg='Failed to describe ASG Instance')
+ self.module.fail_json_aws(e, msg="Failed to describe ASG Instance")
if len(asg_instances) != 1:
self.module.fail_json(msg="Illegal state, expected one auto scaling group.")
- return asg_instances[0]['LoadBalancerNames']
+ return asg_instances[0]["LoadBalancerNames"]
def _get_instance(self):
"""Returns the description of an instance"""
try:
- result = self.client_ec2.describe_instances(
- aws_retry=True,
- InstanceIds=[self.instance_id])
+ result = self.client_ec2.describe_instances(aws_retry=True, InstanceIds=[self.instance_id])
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, msg='Failed to describe ASG Instance')
- return result['Reservations'][0]['Instances'][0]
+ self.module.fail_json_aws(e, msg="Failed to describe ASG Instance")
+ return result["Reservations"][0]["Instances"][0]
def main():
argument_spec = dict(
- state={'required': True, 'choices': ['present', 'absent']},
- instance_id={'required': True},
- ec2_elbs={'default': None, 'required': False, 'type': 'list', 'elements': 'str'},
- enable_availability_zone={'default': True, 'required': False, 'type': 'bool'},
- wait={'required': False, 'default': True, 'type': 'bool'},
- wait_timeout={'required': False, 'default': 0, 'type': 'int'},
+ state={"required": True, "choices": ["present", "absent"]},
+ instance_id={"required": True},
+ ec2_elbs={"default": None, "required": False, "type": "list", "elements": "str"},
+ enable_availability_zone={"default": True, "required": False, "type": "bool"},
+ wait={"required": False, "default": True, "type": "bool"},
+ wait_timeout={"required": False, "default": 0, "type": "int"},
)
required_if = [
- ('state', 'present', ['ec2_elbs']),
+ ("state", "present", ["ec2_elbs"]),
]
module = AnsibleAWSModule(
@@ -371,22 +375,22 @@ def main():
supports_check_mode=True,
)
- ec2_elbs = module.params['ec2_elbs']
- wait = module.params['wait']
- enable_availability_zone = module.params['enable_availability_zone']
- timeout = module.params['wait_timeout']
- instance_id = module.params['instance_id']
+ ec2_elbs = module.params["ec2_elbs"]
+ wait = module.params["wait"]
+ enable_availability_zone = module.params["enable_availability_zone"]
+ timeout = module.params["wait_timeout"]
+ instance_id = module.params["instance_id"]
elb_man = ElbManager(module, instance_id, ec2_elbs)
if ec2_elbs is not None:
for elb in ec2_elbs:
if not elb_man.exists(elb):
- module.fail_json(msg="ELB {0} does not exist".format(elb))
+ module.fail_json(msg=f"ELB {elb} does not exist")
- if module.params['state'] == 'present':
+ if module.params["state"] == "present":
elb_man.register(wait, enable_availability_zone, timeout)
- elif module.params['state'] == 'absent':
+ elif module.params["state"] == "absent":
elb_man.deregister(wait, timeout)
module.exit_json(
@@ -395,5 +399,5 @@ def main():
)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/elb_network_lb.py b/ansible_collections/community/aws/plugins/modules/elb_network_lb.py
index 6dcdfd209..86d8f0872 100644
--- a/ansible_collections/community/aws/plugins/modules/elb_network_lb.py
+++ b/ansible_collections/community/aws/plugins/modules/elb_network_lb.py
@@ -1,13 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
# Copyright: (c) 2018, Rob White (@wimnat)
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: elb_network_lb
version_added: 1.0.0
@@ -126,17 +123,17 @@ options:
- Sets the type of IP addresses used by the subnets of the specified Application Load Balancer.
choices: [ 'ipv4', 'dualstack' ]
type: str
-extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
- - amazon.aws.boto3
- - amazon.aws.tags
notes:
- Listeners are matched based on port. If a listener's port is changed then a new listener will be created.
- Listener rules are matched based on priority. If a rule's priority is changed then a new rule will be created.
-'''
+extends_documentation_fragment:
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.tags
+ - amazon.aws.boto3
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide for details.
- name: Create an ELB and attach a listener
@@ -186,10 +183,9 @@ EXAMPLES = r'''
community.aws.elb_network_lb:
name: myelb
state: absent
+"""
-'''
-
-RETURN = r'''
+RETURN = r"""
load_balancer:
description: A representation of the Network Load Balancer
returned: when state is present
@@ -328,11 +324,17 @@ load_balancer:
returned: when state is present
type: str
sample: vpc-0011223344
-'''
+"""
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict, boto3_tag_list_to_ansible_dict, compare_aws_tags
-from ansible_collections.amazon.aws.plugins.module_utils.elbv2 import NetworkLoadBalancer, ELBListeners, ELBListener
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.elbv2 import ELBListener
+from ansible_collections.amazon.aws.plugins.module_utils.elbv2 import ELBListeners
+from ansible_collections.amazon.aws.plugins.module_utils.elbv2 import NetworkLoadBalancer
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import compare_aws_tags
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def create_or_update_elb(elb_obj):
@@ -346,10 +348,12 @@ def create_or_update_elb(elb_obj):
# Tags - only need to play with tags if tags parameter has been set to something
if elb_obj.tags is not None:
-
# Delete necessary tags
- tags_need_modify, tags_to_delete = compare_aws_tags(boto3_tag_list_to_ansible_dict(elb_obj.elb['tags']),
- boto3_tag_list_to_ansible_dict(elb_obj.tags), elb_obj.purge_tags)
+ tags_need_modify, tags_to_delete = compare_aws_tags(
+ boto3_tag_list_to_ansible_dict(elb_obj.elb["tags"]),
+ boto3_tag_list_to_ansible_dict(elb_obj.tags),
+ elb_obj.purge_tags,
+ )
if tags_to_delete:
elb_obj.delete_tags(tags_to_delete)
@@ -366,25 +370,29 @@ def create_or_update_elb(elb_obj):
elb_obj.modify_elb_attributes()
# Listeners
- listeners_obj = ELBListeners(elb_obj.connection, elb_obj.module, elb_obj.elb['LoadBalancerArn'])
+ listeners_obj = ELBListeners(elb_obj.connection, elb_obj.module, elb_obj.elb["LoadBalancerArn"])
listeners_to_add, listeners_to_modify, listeners_to_delete = listeners_obj.compare_listeners()
# Delete listeners
for listener_to_delete in listeners_to_delete:
- listener_obj = ELBListener(elb_obj.connection, elb_obj.module, listener_to_delete, elb_obj.elb['LoadBalancerArn'])
+ listener_obj = ELBListener(
+ elb_obj.connection, elb_obj.module, listener_to_delete, elb_obj.elb["LoadBalancerArn"]
+ )
listener_obj.delete()
listeners_obj.changed = True
# Add listeners
for listener_to_add in listeners_to_add:
- listener_obj = ELBListener(elb_obj.connection, elb_obj.module, listener_to_add, elb_obj.elb['LoadBalancerArn'])
+ listener_obj = ELBListener(elb_obj.connection, elb_obj.module, listener_to_add, elb_obj.elb["LoadBalancerArn"])
listener_obj.add()
listeners_obj.changed = True
# Modify listeners
for listener_to_modify in listeners_to_modify:
- listener_obj = ELBListener(elb_obj.connection, elb_obj.module, listener_to_modify, elb_obj.elb['LoadBalancerArn'])
+ listener_obj = ELBListener(
+ elb_obj.connection, elb_obj.module, listener_to_modify, elb_obj.elb["LoadBalancerArn"]
+ )
listener_obj.modify()
listeners_obj.changed = True
@@ -393,8 +401,8 @@ def create_or_update_elb(elb_obj):
elb_obj.changed = True
# Update ELB ip address type only if option has been provided
- if elb_obj.module.params.get('ip_address_type') is not None:
- elb_obj.modify_ip_address_type(elb_obj.module.params.get('ip_address_type'))
+ if elb_obj.module.params.get("ip_address_type") is not None:
+ elb_obj.modify_ip_address_type(elb_obj.module.params.get("ip_address_type"))
# Update the objects to pickup changes
# Get the ELB again
@@ -407,24 +415,20 @@ def create_or_update_elb(elb_obj):
# Convert to snake_case and merge in everything we want to return to the user
snaked_elb = camel_dict_to_snake_dict(elb_obj.elb)
snaked_elb.update(camel_dict_to_snake_dict(elb_obj.elb_attributes))
- snaked_elb['listeners'] = []
+ snaked_elb["listeners"] = []
for listener in listeners_obj.current_listeners:
- snaked_elb['listeners'].append(camel_dict_to_snake_dict(listener))
+ snaked_elb["listeners"].append(camel_dict_to_snake_dict(listener))
# Change tags to ansible friendly dict
- snaked_elb['tags'] = boto3_tag_list_to_ansible_dict(snaked_elb['tags'])
+ snaked_elb["tags"] = boto3_tag_list_to_ansible_dict(snaked_elb["tags"])
# ip address type
- snaked_elb['ip_address_type'] = elb_obj.get_elb_ip_address_type()
+ snaked_elb["ip_address_type"] = elb_obj.get_elb_ip_address_type()
- elb_obj.module.exit_json(
- changed=elb_obj.changed,
- load_balancer=snaked_elb,
- **snaked_elb)
+ elb_obj.module.exit_json(changed=elb_obj.changed, load_balancer=snaked_elb, **snaked_elb)
def delete_elb(elb_obj):
-
if elb_obj.elb:
elb_obj.delete()
@@ -432,42 +436,42 @@ def delete_elb(elb_obj):
def main():
-
- argument_spec = (
- dict(
- cross_zone_load_balancing=dict(type='bool'),
- deletion_protection=dict(type='bool'),
- listeners=dict(type='list',
- elements='dict',
- options=dict(
- Protocol=dict(type='str', required=True),
- Port=dict(type='int', required=True),
- SslPolicy=dict(type='str'),
- Certificates=dict(type='list', elements='dict'),
- DefaultActions=dict(type='list', required=True, elements='dict')
- )
- ),
- name=dict(required=True, type='str'),
- purge_listeners=dict(default=True, type='bool'),
- purge_tags=dict(default=True, type='bool'),
- subnets=dict(type='list', elements='str'),
- subnet_mappings=dict(type='list', elements='dict'),
- scheme=dict(default='internet-facing', choices=['internet-facing', 'internal']),
- state=dict(choices=['present', 'absent'], type='str', default='present'),
- tags=dict(type='dict', aliases=['resource_tags']),
- wait_timeout=dict(type='int'),
- wait=dict(type='bool'),
- ip_address_type=dict(type='str', choices=['ipv4', 'dualstack'])
- )
+ argument_spec = dict(
+ cross_zone_load_balancing=dict(type="bool"),
+ deletion_protection=dict(type="bool"),
+ listeners=dict(
+ type="list",
+ elements="dict",
+ options=dict(
+ Protocol=dict(type="str", required=True),
+ Port=dict(type="int", required=True),
+ SslPolicy=dict(type="str"),
+ Certificates=dict(type="list", elements="dict"),
+ DefaultActions=dict(type="list", required=True, elements="dict"),
+ ),
+ ),
+ name=dict(required=True, type="str"),
+ purge_listeners=dict(default=True, type="bool"),
+ purge_tags=dict(default=True, type="bool"),
+ subnets=dict(type="list", elements="str"),
+ subnet_mappings=dict(type="list", elements="dict"),
+ scheme=dict(default="internet-facing", choices=["internet-facing", "internal"]),
+ state=dict(choices=["present", "absent"], type="str", default="present"),
+ tags=dict(type="dict", aliases=["resource_tags"]),
+ wait_timeout=dict(type="int"),
+ wait=dict(type="bool"),
+ ip_address_type=dict(type="str", choices=["ipv4", "dualstack"]),
)
required_if = [
- ('state', 'present', ('subnets', 'subnet_mappings',), True)
+ ["state", "present", ["subnets", "subnet_mappings"], True],
]
- module = AnsibleAWSModule(argument_spec=argument_spec,
- required_if=required_if,
- mutually_exclusive=[['subnets', 'subnet_mappings']])
+ module = AnsibleAWSModule(
+ argument_spec=argument_spec,
+ required_if=required_if,
+ mutually_exclusive=[["subnets", "subnet_mappings"]],
+ )
# Check for subnets or subnet_mappings if state is present
state = module.params.get("state")
@@ -477,20 +481,20 @@ def main():
if listeners is not None:
for listener in listeners:
for key in listener.keys():
- protocols_list = ['TCP', 'TLS', 'UDP', 'TCP_UDP']
- if key == 'Protocol' and listener[key] not in protocols_list:
+ protocols_list = ["TCP", "TLS", "UDP", "TCP_UDP"]
+ if key == "Protocol" and listener[key] not in protocols_list:
module.fail_json(msg="'Protocol' must be either " + ", ".join(protocols_list))
- connection = module.client('elbv2')
- connection_ec2 = module.client('ec2')
+ connection = module.client("elbv2")
+ connection_ec2 = module.client("ec2")
elb = NetworkLoadBalancer(connection, connection_ec2, module)
- if state == 'present':
+ if state == "present":
create_or_update_elb(elb)
else:
delete_elb(elb)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/elb_target.py b/ansible_collections/community/aws/plugins/modules/elb_target.py
index cff46a62a..22074d496 100644
--- a/ansible_collections/community/aws/plugins/modules/elb_target.py
+++ b/ansible_collections/community/aws/plugins/modules/elb_target.py
@@ -1,19 +1,18 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: elb_target
version_added: 1.0.0
short_description: Manage a target in a target group
description:
- - Used to register or deregister a target in a target group.
-author: "Rob White (@wimnat)"
+ - Used to register or deregister a target in a target group.
+author:
+ - "Rob White (@wimnat)"
options:
deregister_unused:
description:
@@ -68,16 +67,17 @@ options:
required: true
choices: [ 'present', 'absent' ]
type: str
-extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
notes:
- If you specified a port override when you registered a target, you must specify both the target ID and the port when you deregister it.
-'''
-EXAMPLES = '''
+extends_documentation_fragment:
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
+
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide for details.
- name: Register an IP address target to a target group
@@ -105,14 +105,13 @@ EXAMPLES = '''
target_id: i-1234567
target_port: 8080
state: present
+"""
-'''
-
-RETURN = '''
-
-'''
+RETURN = r"""
+"""
-from time import time, sleep
+from time import sleep
+from time import time
try:
import botocore
@@ -121,28 +120,28 @@ except ImportError:
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
-@AWSRetry.jittered_backoff(retries=10, delay=10, catch_extra_error_codes=['TargetGroupNotFound'])
+
+@AWSRetry.jittered_backoff(retries=10, delay=10, catch_extra_error_codes=["TargetGroupNotFound"])
def describe_target_groups_with_backoff(connection, tg_name):
return connection.describe_target_groups(Names=[tg_name])
def convert_tg_name_to_arn(connection, module, tg_name):
-
try:
response = describe_target_groups_with_backoff(connection, tg_name)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Unable to describe target group {0}".format(tg_name))
+ module.fail_json_aws(e, msg=f"Unable to describe target group {tg_name}")
- tg_arn = response['TargetGroups'][0]['TargetGroupArn']
+ tg_arn = response["TargetGroups"][0]["TargetGroupArn"]
return tg_arn
-@AWSRetry.jittered_backoff(retries=10, delay=10, catch_extra_error_codes=['TargetGroupNotFound'])
+@AWSRetry.jittered_backoff(retries=10, delay=10, catch_extra_error_codes=["TargetGroupNotFound"])
def describe_targets_with_backoff(connection, tg_arn, target):
if target is None:
tg = []
@@ -153,7 +152,6 @@ def describe_targets_with_backoff(connection, tg_arn, target):
def describe_targets(connection, module, tg_arn, target=None):
-
"""
Describe targets in a target group
@@ -165,12 +163,12 @@ def describe_targets(connection, module, tg_arn, target=None):
"""
try:
- targets = describe_targets_with_backoff(connection, tg_arn, target)['TargetHealthDescriptions']
+ targets = describe_targets_with_backoff(connection, tg_arn, target)["TargetHealthDescriptions"]
if not targets:
return {}
return targets[0]
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Unable to describe target health for target {0}".format(target))
+ module.fail_json_aws(e, msg=f"Unable to describe target health for target {target}")
@AWSRetry.jittered_backoff(retries=10, delay=10)
@@ -179,7 +177,6 @@ def register_target_with_backoff(connection, target_group_arn, target):
def register_target(connection, module):
-
"""
Registers a target to a target group
@@ -201,26 +198,32 @@ def register_target(connection, module):
target = dict(Id=target_id)
if target_az:
- target['AvailabilityZone'] = target_az
+ target["AvailabilityZone"] = target_az
if target_port:
- target['Port'] = target_port
+ target["Port"] = target_port
target_description = describe_targets(connection, module, target_group_arn, target)
- if 'Reason' in target_description['TargetHealth']:
- if target_description['TargetHealth']['Reason'] == "Target.NotRegistered":
+ if "Reason" in target_description["TargetHealth"]:
+ if target_description["TargetHealth"]["Reason"] == "Target.NotRegistered":
try:
register_target_with_backoff(connection, target_group_arn, target)
changed = True
if target_status:
- target_status_check(connection, module, target_group_arn, target, target_status, target_status_timeout)
+ target_status_check(
+ connection, module, target_group_arn, target, target_status, target_status_timeout
+ )
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Unable to deregister target {0}".format(target))
+ module.fail_json_aws(e, msg=f"Unable to deregister target {target}")
# Get all targets for the target group
target_descriptions = describe_targets(connection, module, target_group_arn)
- module.exit_json(changed=changed, target_health_descriptions=camel_dict_to_snake_dict(target_descriptions), target_group_arn=target_group_arn)
+ module.exit_json(
+ changed=changed,
+ target_health_descriptions=camel_dict_to_snake_dict(target_descriptions),
+ target_group_arn=target_group_arn,
+ )
@AWSRetry.jittered_backoff(retries=10, delay=10)
@@ -229,7 +232,6 @@ def deregister_target_with_backoff(connection, target_group_arn, target):
def deregister_target(connection, module):
-
"""
Deregisters a target to a target group
@@ -251,18 +253,18 @@ def deregister_target(connection, module):
target = dict(Id=target_id)
if target_port:
- target['Port'] = target_port
+ target["Port"] = target_port
target_description = describe_targets(connection, module, target_group_arn, target)
- current_target_state = target_description['TargetHealth']['State']
- current_target_reason = target_description['TargetHealth'].get('Reason')
+ current_target_state = target_description["TargetHealth"]["State"]
+ current_target_reason = target_description["TargetHealth"].get("Reason")
needs_deregister = False
- if deregister_unused and current_target_state == 'unused':
- if current_target_reason != 'Target.NotRegistered':
+ if deregister_unused and current_target_state == "unused":
+ if current_target_reason != "Target.NotRegistered":
needs_deregister = True
- elif current_target_state not in ['unused', 'draining']:
+ elif current_target_state not in ["unused", "draining"]:
needs_deregister = True
if needs_deregister:
@@ -270,11 +272,13 @@ def deregister_target(connection, module):
deregister_target_with_backoff(connection, target_group_arn, target)
changed = True
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json(msg="Unable to deregister target {0}".format(target))
+ module.fail_json(msg=f"Unable to deregister target {target}")
else:
- if current_target_reason != 'Target.NotRegistered' and current_target_state != 'draining':
- module.warn(warning="Your specified target has an 'unused' state but is still registered to the target group. " +
- "To force deregistration use the 'deregister_unused' option.")
+ if current_target_reason != "Target.NotRegistered" and current_target_state != "draining":
+ module.warn(
+ warning="Your specified target has an 'unused' state but is still registered to the target group. "
+ + "To force deregistration use the 'deregister_unused' option."
+ )
if target_status:
target_status_check(connection, module, target_group_arn, target, target_status, target_status_timeout)
@@ -282,53 +286,60 @@ def deregister_target(connection, module):
# Get all targets for the target group
target_descriptions = describe_targets(connection, module, target_group_arn)
- module.exit_json(changed=changed, target_health_descriptions=camel_dict_to_snake_dict(target_descriptions), target_group_arn=target_group_arn)
+ module.exit_json(
+ changed=changed,
+ target_health_descriptions=camel_dict_to_snake_dict(target_descriptions),
+ target_group_arn=target_group_arn,
+ )
def target_status_check(connection, module, target_group_arn, target, target_status, target_status_timeout):
reached_state = False
timeout = target_status_timeout + time()
while time() < timeout:
- health_state = describe_targets(connection, module, target_group_arn, target)['TargetHealth']['State']
+ health_state = describe_targets(connection, module, target_group_arn, target)["TargetHealth"]["State"]
if health_state == target_status:
reached_state = True
break
sleep(1)
if not reached_state:
- module.fail_json(msg='Status check timeout of {0} exceeded, last status was {1}: '.format(target_status_timeout, health_state))
+ module.fail_json(
+ msg=f"Status check timeout of {target_status_timeout} exceeded, last status was {health_state}: "
+ )
def main():
-
argument_spec = dict(
- deregister_unused=dict(type='bool', default=False),
- target_az=dict(type='str'),
- target_group_arn=dict(type='str'),
- target_group_name=dict(type='str'),
- target_id=dict(type='str', required=True),
- target_port=dict(type='int'),
- target_status=dict(choices=['initial', 'healthy', 'unhealthy', 'unused', 'draining', 'unavailable'], type='str'),
- target_status_timeout=dict(type='int', default=60),
- state=dict(required=True, choices=['present', 'absent'], type='str'),
+ deregister_unused=dict(type="bool", default=False),
+ target_az=dict(type="str"),
+ target_group_arn=dict(type="str"),
+ target_group_name=dict(type="str"),
+ target_id=dict(type="str", required=True),
+ target_port=dict(type="int"),
+ target_status=dict(
+ choices=["initial", "healthy", "unhealthy", "unused", "draining", "unavailable"], type="str"
+ ),
+ target_status_timeout=dict(type="int", default=60),
+ state=dict(required=True, choices=["present", "absent"], type="str"),
)
module = AnsibleAWSModule(
argument_spec=argument_spec,
- mutually_exclusive=[['target_group_arn', 'target_group_name']],
+ mutually_exclusive=[["target_group_arn", "target_group_name"]],
)
try:
- connection = module.client('elbv2')
+ connection = module.client("elbv2")
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to connect to AWS')
+ module.fail_json_aws(e, msg="Failed to connect to AWS")
state = module.params.get("state")
- if state == 'present':
+ if state == "present":
register_target(connection, module)
else:
deregister_target(connection, module)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/elb_target_group.py b/ansible_collections/community/aws/plugins/modules/elb_target_group.py
index 45a6e7ae9..71a859ead 100644
--- a/ansible_collections/community/aws/plugins/modules/elb_target_group.py
+++ b/ansible_collections/community/aws/plugins/modules/elb_target_group.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: elb_target_group
version_added: 1.0.0
@@ -204,17 +202,18 @@ options:
- The time to wait for the target group.
default: 200
type: int
-extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
- - amazon.aws.boto3
- - amazon.aws.tags
notes:
- Once a target group has been created, only its health check can then be modified using subsequent calls
-'''
-EXAMPLES = r'''
+extends_documentation_fragment:
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.tags
+ - amazon.aws.boto3
+"""
+
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide for details.
- name: Create a target group with a default health check
@@ -271,7 +270,7 @@ EXAMPLES = r'''
Port: 80
state: present
wait_timeout: 200
- wait: True
+ wait: true
- name: Create a target group with IP address targets
community.aws.elb_target_group:
@@ -291,7 +290,7 @@ EXAMPLES = r'''
Port: 80
state: present
wait_timeout: 200
- wait: True
+ wait: true
# Using lambda as targets require that the target group
# itself is allow to invoke the lambda function.
@@ -304,7 +303,7 @@ EXAMPLES = r'''
name: my-lambda-targetgroup
target_type: lambda
state: present
- modify_targets: False
+ modify_targets: false
register: out
- name: second, allow invoke of the lambda
@@ -322,11 +321,10 @@ EXAMPLES = r'''
target_type: lambda
state: present
targets:
- - Id: arn:aws:lambda:eu-central-1:123456789012:function:my-lambda-function
-
-'''
+ - Id: arn:aws:lambda:eu-central-1:123456789012:function:my-lambda-function
+"""
-RETURN = r'''
+RETURN = r"""
deregistration_delay_timeout_seconds:
description: The amount time for Elastic Load Balancing to wait before changing the state of a deregistering target from draining to unused.
returned: when state present
@@ -437,7 +435,7 @@ vpc_id:
returned: when state present
type: str
sample: vpc-0123456
-'''
+"""
import time
@@ -448,56 +446,64 @@ except ImportError:
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_tag_list
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import compare_aws_tags
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import ansible_dict_to_boto3_tag_list
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import compare_aws_tags
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def get_tg_attributes(connection, module, tg_arn):
try:
_attributes = connection.describe_target_group_attributes(TargetGroupArn=tg_arn, aws_retry=True)
- tg_attributes = boto3_tag_list_to_ansible_dict(_attributes['Attributes'])
+ tg_attributes = boto3_tag_list_to_ansible_dict(_attributes["Attributes"])
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Couldn't get target group attributes")
# Replace '.' with '_' in attribute key names to make it more Ansible friendly
- return dict((k.replace('.', '_'), v) for k, v in tg_attributes.items())
+ return dict((k.replace(".", "_"), v) for k, v in tg_attributes.items())
def get_target_group_tags(connection, module, target_group_arn):
try:
_tags = connection.describe_tags(ResourceArns=[target_group_arn], aws_retry=True)
- return _tags['TagDescriptions'][0]['Tags']
+ return _tags["TagDescriptions"][0]["Tags"]
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Couldn't get target group tags")
def get_target_group(connection, module, retry_missing=False):
- extra_codes = ['TargetGroupNotFound'] if retry_missing else []
+ extra_codes = ["TargetGroupNotFound"] if retry_missing else []
try:
- target_group_paginator = connection.get_paginator('describe_target_groups').paginate(Names=[module.params.get("name")])
+ target_group_paginator = connection.get_paginator("describe_target_groups").paginate(
+ Names=[module.params.get("name")]
+ )
jittered_retry = AWSRetry.jittered_backoff(retries=10, catch_extra_error_codes=extra_codes)
result = jittered_retry(target_group_paginator.build_full_result)()
- except is_boto3_error_code('TargetGroupNotFound'):
+ except is_boto3_error_code("TargetGroupNotFound"):
return None
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
module.fail_json_aws(e, msg="Couldn't get target group")
- return result['TargetGroups'][0]
+ return result["TargetGroups"][0]
def wait_for_status(connection, module, target_group_arn, targets, status):
polling_increment_secs = 5
- max_retries = (module.params.get('wait_timeout') // polling_increment_secs)
+ max_retries = module.params.get("wait_timeout") // polling_increment_secs
status_achieved = False
for x in range(0, max_retries):
try:
- response = connection.describe_target_health(TargetGroupArn=target_group_arn, Targets=targets, aws_retry=True)
- if response['TargetHealthDescriptions'][0]['TargetHealth']['State'] == status:
+ response = connection.describe_target_health(
+ TargetGroupArn=target_group_arn, Targets=targets, aws_retry=True
+ )
+ if response["TargetHealthDescriptions"][0]["TargetHealth"]["State"] == status:
status_achieved = True
break
else:
@@ -527,156 +533,186 @@ def create_or_update_attributes(connection, module, target_group, new_target_gro
update_attributes = []
# Get current attributes
- current_tg_attributes = get_tg_attributes(connection, module, target_group['TargetGroupArn'])
+ current_tg_attributes = get_tg_attributes(connection, module, target_group["TargetGroupArn"])
if deregistration_delay_timeout is not None:
- if str(deregistration_delay_timeout) != current_tg_attributes['deregistration_delay_timeout_seconds']:
- update_attributes.append({'Key': 'deregistration_delay.timeout_seconds', 'Value': str(deregistration_delay_timeout)})
+ if str(deregistration_delay_timeout) != current_tg_attributes["deregistration_delay_timeout_seconds"]:
+ update_attributes.append(
+ {"Key": "deregistration_delay.timeout_seconds", "Value": str(deregistration_delay_timeout)}
+ )
if deregistration_connection_termination is not None:
- if deregistration_connection_termination and current_tg_attributes.get('deregistration_delay_connection_termination_enabled') != "true":
- update_attributes.append({'Key': 'deregistration_delay.connection_termination.enabled', 'Value': 'true'})
+ if (
+ deregistration_connection_termination
+ and current_tg_attributes.get("deregistration_delay_connection_termination_enabled") != "true"
+ ):
+ update_attributes.append({"Key": "deregistration_delay.connection_termination.enabled", "Value": "true"})
if stickiness_enabled is not None:
- if stickiness_enabled and current_tg_attributes['stickiness_enabled'] != "true":
- update_attributes.append({'Key': 'stickiness.enabled', 'Value': 'true'})
+ if stickiness_enabled and current_tg_attributes["stickiness_enabled"] != "true":
+ update_attributes.append({"Key": "stickiness.enabled", "Value": "true"})
if stickiness_lb_cookie_duration is not None:
- if str(stickiness_lb_cookie_duration) != current_tg_attributes['stickiness_lb_cookie_duration_seconds']:
- update_attributes.append({'Key': 'stickiness.lb_cookie.duration_seconds', 'Value': str(stickiness_lb_cookie_duration)})
+ if str(stickiness_lb_cookie_duration) != current_tg_attributes["stickiness_lb_cookie_duration_seconds"]:
+ update_attributes.append(
+ {"Key": "stickiness.lb_cookie.duration_seconds", "Value": str(stickiness_lb_cookie_duration)}
+ )
if stickiness_type is not None:
- if stickiness_type != current_tg_attributes.get('stickiness_type'):
- update_attributes.append({'Key': 'stickiness.type', 'Value': stickiness_type})
+ if stickiness_type != current_tg_attributes.get("stickiness_type"):
+ update_attributes.append({"Key": "stickiness.type", "Value": stickiness_type})
if stickiness_app_cookie_name is not None:
- if stickiness_app_cookie_name != current_tg_attributes.get('stickiness_app_cookie_name'):
- update_attributes.append({'Key': 'stickiness.app_cookie.cookie_name', 'Value': str(stickiness_app_cookie_name)})
+ if stickiness_app_cookie_name != current_tg_attributes.get("stickiness_app_cookie_name"):
+ update_attributes.append(
+ {"Key": "stickiness.app_cookie.cookie_name", "Value": str(stickiness_app_cookie_name)}
+ )
if stickiness_app_cookie_duration is not None:
- if str(stickiness_app_cookie_duration) != current_tg_attributes['stickiness_app_cookie_duration_seconds']:
- update_attributes.append({'Key': 'stickiness.app_cookie.duration_seconds', 'Value': str(stickiness_app_cookie_duration)})
+ if str(stickiness_app_cookie_duration) != current_tg_attributes["stickiness_app_cookie_duration_seconds"]:
+ update_attributes.append(
+ {"Key": "stickiness.app_cookie.duration_seconds", "Value": str(stickiness_app_cookie_duration)}
+ )
if preserve_client_ip_enabled is not None:
- if target_type not in ('udp', 'tcp_udp'):
- if str(preserve_client_ip_enabled).lower() != current_tg_attributes.get('preserve_client_ip_enabled'):
- update_attributes.append({'Key': 'preserve_client_ip.enabled', 'Value': str(preserve_client_ip_enabled).lower()})
+ if target_type not in ("udp", "tcp_udp"):
+ if str(preserve_client_ip_enabled).lower() != current_tg_attributes.get("preserve_client_ip_enabled"):
+ update_attributes.append(
+ {"Key": "preserve_client_ip.enabled", "Value": str(preserve_client_ip_enabled).lower()}
+ )
if proxy_protocol_v2_enabled is not None:
- if str(proxy_protocol_v2_enabled).lower() != current_tg_attributes.get('proxy_protocol_v2_enabled'):
- update_attributes.append({'Key': 'proxy_protocol_v2.enabled', 'Value': str(proxy_protocol_v2_enabled).lower()})
+ if str(proxy_protocol_v2_enabled).lower() != current_tg_attributes.get("proxy_protocol_v2_enabled"):
+ update_attributes.append(
+ {"Key": "proxy_protocol_v2.enabled", "Value": str(proxy_protocol_v2_enabled).lower()}
+ )
if load_balancing_algorithm_type is not None:
- if str(load_balancing_algorithm_type) != current_tg_attributes['load_balancing_algorithm_type']:
- update_attributes.append({'Key': 'load_balancing.algorithm.type', 'Value': str(load_balancing_algorithm_type)})
+ if str(load_balancing_algorithm_type) != current_tg_attributes["load_balancing_algorithm_type"]:
+ update_attributes.append(
+ {"Key": "load_balancing.algorithm.type", "Value": str(load_balancing_algorithm_type)}
+ )
if update_attributes:
try:
- connection.modify_target_group_attributes(TargetGroupArn=target_group['TargetGroupArn'], Attributes=update_attributes, aws_retry=True)
+ connection.modify_target_group_attributes(
+ TargetGroupArn=target_group["TargetGroupArn"], Attributes=update_attributes, aws_retry=True
+ )
changed = True
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
# Something went wrong setting attributes. If this target group was created during this task, delete it to leave a consistent state
if new_target_group:
- connection.delete_target_group(TargetGroupArn=target_group['TargetGroupArn'], aws_retry=True)
+ connection.delete_target_group(TargetGroupArn=target_group["TargetGroupArn"], aws_retry=True)
module.fail_json_aws(e, msg="Couldn't delete target group")
return changed
def create_or_update_target_group(connection, module):
-
changed = False
new_target_group = False
params = dict()
target_type = module.params.get("target_type")
- params['Name'] = module.params.get("name")
- params['TargetType'] = target_type
+ params["Name"] = module.params.get("name")
+ params["TargetType"] = target_type
if target_type != "lambda":
- params['Protocol'] = module.params.get("protocol").upper()
- if module.params.get('protocol_version') is not None:
- params['ProtocolVersion'] = module.params.get('protocol_version')
- params['Port'] = module.params.get("port")
- params['VpcId'] = module.params.get("vpc_id")
+ params["Protocol"] = module.params.get("protocol").upper()
+ if module.params.get("protocol_version") is not None:
+ params["ProtocolVersion"] = module.params.get("protocol_version")
+ params["Port"] = module.params.get("port")
+ params["VpcId"] = module.params.get("vpc_id")
tags = module.params.get("tags")
purge_tags = module.params.get("purge_tags")
health_option_keys = [
- "health_check_path", "health_check_protocol", "health_check_interval", "health_check_timeout",
- "healthy_threshold_count", "unhealthy_threshold_count", "successful_response_codes"
+ "health_check_path",
+ "health_check_protocol",
+ "health_check_interval",
+ "health_check_timeout",
+ "healthy_threshold_count",
+ "unhealthy_threshold_count",
+ "successful_response_codes",
]
health_options = any(module.params[health_option_key] is not None for health_option_key in health_option_keys)
# Set health check if anything set
if health_options:
-
if module.params.get("health_check_protocol") is not None:
- params['HealthCheckProtocol'] = module.params.get("health_check_protocol").upper()
+ params["HealthCheckProtocol"] = module.params.get("health_check_protocol").upper()
if module.params.get("health_check_port") is not None:
- params['HealthCheckPort'] = module.params.get("health_check_port")
+ params["HealthCheckPort"] = module.params.get("health_check_port")
if module.params.get("health_check_interval") is not None:
- params['HealthCheckIntervalSeconds'] = module.params.get("health_check_interval")
+ params["HealthCheckIntervalSeconds"] = module.params.get("health_check_interval")
if module.params.get("health_check_timeout") is not None:
- params['HealthCheckTimeoutSeconds'] = module.params.get("health_check_timeout")
+ params["HealthCheckTimeoutSeconds"] = module.params.get("health_check_timeout")
if module.params.get("healthy_threshold_count") is not None:
- params['HealthyThresholdCount'] = module.params.get("healthy_threshold_count")
+ params["HealthyThresholdCount"] = module.params.get("healthy_threshold_count")
if module.params.get("unhealthy_threshold_count") is not None:
- params['UnhealthyThresholdCount'] = module.params.get("unhealthy_threshold_count")
+ params["UnhealthyThresholdCount"] = module.params.get("unhealthy_threshold_count")
# Only need to check response code and path for http(s) health checks
protocol = module.params.get("health_check_protocol")
- if protocol is not None and protocol.upper() in ['HTTP', 'HTTPS']:
-
+ if protocol is not None and protocol.upper() in ["HTTP", "HTTPS"]:
if module.params.get("health_check_path") is not None:
- params['HealthCheckPath'] = module.params.get("health_check_path")
+ params["HealthCheckPath"] = module.params.get("health_check_path")
if module.params.get("successful_response_codes") is not None:
- params['Matcher'] = {}
- code_key = 'HttpCode'
- protocol_version = module.params.get('protocol_version')
+ params["Matcher"] = {}
+ code_key = "HttpCode"
+ protocol_version = module.params.get("protocol_version")
if protocol_version is not None and protocol_version.upper() == "GRPC":
- code_key = 'GrpcCode'
- params['Matcher'][code_key] = module.params.get("successful_response_codes")
+ code_key = "GrpcCode"
+ params["Matcher"][code_key] = module.params.get("successful_response_codes")
# Get target group
target_group = get_target_group(connection, module)
if target_group:
- diffs = [param for param in ('Port', 'Protocol', 'VpcId')
- if target_group.get(param) != params.get(param)]
+ diffs = [param for param in ("Port", "Protocol", "VpcId") if target_group.get(param) != params.get(param)]
if diffs:
- module.fail_json(msg="Cannot modify %s parameter(s) for a target group" %
- ", ".join(diffs))
+ module.fail_json(msg=f"Cannot modify {', '.join(diffs)} parameter(s) for a target group")
# Target group exists so check health check parameters match what has been passed
health_check_params = dict()
# Modify health check if anything set
if health_options:
-
# Health check protocol
- if 'HealthCheckProtocol' in params and target_group['HealthCheckProtocol'] != params['HealthCheckProtocol']:
- health_check_params['HealthCheckProtocol'] = params['HealthCheckProtocol']
+ if "HealthCheckProtocol" in params and target_group["HealthCheckProtocol"] != params["HealthCheckProtocol"]:
+ health_check_params["HealthCheckProtocol"] = params["HealthCheckProtocol"]
# Health check port
- if 'HealthCheckPort' in params and target_group['HealthCheckPort'] != params['HealthCheckPort']:
- health_check_params['HealthCheckPort'] = params['HealthCheckPort']
+ if "HealthCheckPort" in params and target_group["HealthCheckPort"] != params["HealthCheckPort"]:
+ health_check_params["HealthCheckPort"] = params["HealthCheckPort"]
# Health check interval
- if 'HealthCheckIntervalSeconds' in params and target_group['HealthCheckIntervalSeconds'] != params['HealthCheckIntervalSeconds']:
- health_check_params['HealthCheckIntervalSeconds'] = params['HealthCheckIntervalSeconds']
+ if (
+ "HealthCheckIntervalSeconds" in params
+ and target_group["HealthCheckIntervalSeconds"] != params["HealthCheckIntervalSeconds"]
+ ):
+ health_check_params["HealthCheckIntervalSeconds"] = params["HealthCheckIntervalSeconds"]
# Health check timeout
- if 'HealthCheckTimeoutSeconds' in params and target_group['HealthCheckTimeoutSeconds'] != params['HealthCheckTimeoutSeconds']:
- health_check_params['HealthCheckTimeoutSeconds'] = params['HealthCheckTimeoutSeconds']
+ if (
+ "HealthCheckTimeoutSeconds" in params
+ and target_group["HealthCheckTimeoutSeconds"] != params["HealthCheckTimeoutSeconds"]
+ ):
+ health_check_params["HealthCheckTimeoutSeconds"] = params["HealthCheckTimeoutSeconds"]
# Healthy threshold
- if 'HealthyThresholdCount' in params and target_group['HealthyThresholdCount'] != params['HealthyThresholdCount']:
- health_check_params['HealthyThresholdCount'] = params['HealthyThresholdCount']
+ if (
+ "HealthyThresholdCount" in params
+ and target_group["HealthyThresholdCount"] != params["HealthyThresholdCount"]
+ ):
+ health_check_params["HealthyThresholdCount"] = params["HealthyThresholdCount"]
# Unhealthy threshold
- if 'UnhealthyThresholdCount' in params and target_group['UnhealthyThresholdCount'] != params['UnhealthyThresholdCount']:
- health_check_params['UnhealthyThresholdCount'] = params['UnhealthyThresholdCount']
+ if (
+ "UnhealthyThresholdCount" in params
+ and target_group["UnhealthyThresholdCount"] != params["UnhealthyThresholdCount"]
+ ):
+ health_check_params["UnhealthyThresholdCount"] = params["UnhealthyThresholdCount"]
# Only need to check response code and path for http(s) health checks
- if target_group['HealthCheckProtocol'] in ['HTTP', 'HTTPS']:
+ if target_group["HealthCheckProtocol"] in ["HTTP", "HTTPS"]:
# Health check path
- if 'HealthCheckPath' in params and target_group['HealthCheckPath'] != params['HealthCheckPath']:
- health_check_params['HealthCheckPath'] = params['HealthCheckPath']
+ if "HealthCheckPath" in params and target_group["HealthCheckPath"] != params["HealthCheckPath"]:
+ health_check_params["HealthCheckPath"] = params["HealthCheckPath"]
# Matcher (successful response codes)
# TODO: required and here?
@@ -687,12 +723,14 @@ def create_or_update_target_group(connection, module):
current_matcher_list = target_group["Matcher"][code_key].split(",")
requested_matcher_list = params["Matcher"][code_key].split(",")
if set(current_matcher_list) != set(requested_matcher_list):
- health_check_params['Matcher'] = {}
- health_check_params['Matcher'][code_key] = ','.join(requested_matcher_list)
+ health_check_params["Matcher"] = {}
+ health_check_params["Matcher"][code_key] = ",".join(requested_matcher_list)
try:
if health_check_params:
- connection.modify_target_group(TargetGroupArn=target_group['TargetGroupArn'], aws_retry=True, **health_check_params)
+ connection.modify_target_group(
+ TargetGroupArn=target_group["TargetGroupArn"], aws_retry=True, **health_check_params
+ )
changed = True
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Couldn't update target group")
@@ -703,27 +741,27 @@ def create_or_update_target_group(connection, module):
# describe_target_health seems to be the only way to get them
try:
current_targets = connection.describe_target_health(
- TargetGroupArn=target_group['TargetGroupArn'], aws_retry=True)
+ TargetGroupArn=target_group["TargetGroupArn"], aws_retry=True
+ )
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Couldn't get target group health")
if module.params.get("targets"):
-
if target_type != "lambda":
- params['Targets'] = module.params.get("targets")
+ params["Targets"] = module.params.get("targets")
# Correct type of target ports
- for target in params['Targets']:
- target['Port'] = int(target.get('Port', module.params.get('port')))
+ for target in params["Targets"]:
+ target["Port"] = int(target.get("Port", module.params.get("port")))
current_instance_ids = []
- for instance in current_targets['TargetHealthDescriptions']:
- current_instance_ids.append(instance['Target']['Id'])
+ for instance in current_targets["TargetHealthDescriptions"]:
+ current_instance_ids.append(instance["Target"]["Id"])
new_instance_ids = []
- for instance in params['Targets']:
- new_instance_ids.append(instance['Id'])
+ for instance in params["Targets"]:
+ new_instance_ids.append(instance["Id"])
add_instances = set(new_instance_ids) - set(current_instance_ids)
@@ -738,37 +776,49 @@ def create_or_update_target_group(connection, module):
changed = True
try:
- connection.register_targets(TargetGroupArn=target_group['TargetGroupArn'], Targets=instances_to_add, aws_retry=True)
+ connection.register_targets(
+ TargetGroupArn=target_group["TargetGroupArn"], Targets=instances_to_add, aws_retry=True
+ )
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Couldn't register targets")
if module.params.get("wait"):
status_achieved, registered_instances = wait_for_status(
- connection, module, target_group['TargetGroupArn'], instances_to_add, 'healthy')
+ connection, module, target_group["TargetGroupArn"], instances_to_add, "healthy"
+ )
if not status_achieved:
module.fail_json(
- msg='Error waiting for target registration to be healthy - please check the AWS console')
+ msg="Error waiting for target registration to be healthy - please check the AWS console"
+ )
remove_instances = set(current_instance_ids) - set(new_instance_ids)
if remove_instances:
instances_to_remove = []
- for target in current_targets['TargetHealthDescriptions']:
- if target['Target']['Id'] in remove_instances:
- instances_to_remove.append({'Id': target['Target']['Id'], 'Port': target['Target']['Port']})
+ for target in current_targets["TargetHealthDescriptions"]:
+ if target["Target"]["Id"] in remove_instances:
+ instances_to_remove.append(
+ {"Id": target["Target"]["Id"], "Port": target["Target"]["Port"]}
+ )
changed = True
try:
- connection.deregister_targets(TargetGroupArn=target_group['TargetGroupArn'], Targets=instances_to_remove, aws_retry=True)
+ connection.deregister_targets(
+ TargetGroupArn=target_group["TargetGroupArn"],
+ Targets=instances_to_remove,
+ aws_retry=True,
+ )
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Couldn't remove targets")
if module.params.get("wait"):
status_achieved, registered_instances = wait_for_status(
- connection, module, target_group['TargetGroupArn'], instances_to_remove, 'unused')
+ connection, module, target_group["TargetGroupArn"], instances_to_remove, "unused"
+ )
if not status_achieved:
module.fail_json(
- msg='Error waiting for target deregistration - please check the AWS console')
+ msg="Error waiting for target deregistration - please check the AWS console"
+ )
# register lambda target
else:
@@ -786,40 +836,40 @@ def create_or_update_target_group(connection, module):
if changed:
if target.get("Id"):
response = connection.register_targets(
- TargetGroupArn=target_group['TargetGroupArn'],
- Targets=[
- {
- "Id": target['Id']
- }
- ],
- aws_retry=True
+ TargetGroupArn=target_group["TargetGroupArn"],
+ Targets=[{"Id": target["Id"]}],
+ aws_retry=True,
)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(
- e, msg="Couldn't register targets")
+ module.fail_json_aws(e, msg="Couldn't register targets")
else:
if target_type != "lambda":
-
- current_instances = current_targets['TargetHealthDescriptions']
+ current_instances = current_targets["TargetHealthDescriptions"]
if current_instances:
instances_to_remove = []
- for target in current_targets['TargetHealthDescriptions']:
- instances_to_remove.append({'Id': target['Target']['Id'], 'Port': target['Target']['Port']})
+ for target in current_targets["TargetHealthDescriptions"]:
+ instances_to_remove.append({"Id": target["Target"]["Id"], "Port": target["Target"]["Port"]})
changed = True
try:
- connection.deregister_targets(TargetGroupArn=target_group['TargetGroupArn'], Targets=instances_to_remove, aws_retry=True)
+ connection.deregister_targets(
+ TargetGroupArn=target_group["TargetGroupArn"],
+ Targets=instances_to_remove,
+ aws_retry=True,
+ )
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Couldn't remove targets")
if module.params.get("wait"):
status_achieved, registered_instances = wait_for_status(
- connection, module, target_group['TargetGroupArn'], instances_to_remove, 'unused')
+ connection, module, target_group["TargetGroupArn"], instances_to_remove, "unused"
+ )
if not status_achieved:
module.fail_json(
- msg='Error waiting for target deregistration - please check the AWS console')
+ msg="Error waiting for target deregistration - please check the AWS console"
+ )
# remove lambda targets
else:
@@ -830,7 +880,10 @@ def create_or_update_target_group(connection, module):
target_to_remove = current_targets["TargetHealthDescriptions"][0]["Target"]["Id"]
if changed:
connection.deregister_targets(
- TargetGroupArn=target_group['TargetGroupArn'], Targets=[{"Id": target_to_remove}], aws_retry=True)
+ TargetGroupArn=target_group["TargetGroupArn"],
+ Targets=[{"Id": target_to_remove}],
+ aws_retry=True,
+ )
else:
try:
connection.create_target_group(aws_retry=True, **params)
@@ -843,33 +896,32 @@ def create_or_update_target_group(connection, module):
if module.params.get("targets"):
if target_type != "lambda":
- params['Targets'] = module.params.get("targets")
+ params["Targets"] = module.params.get("targets")
try:
- connection.register_targets(TargetGroupArn=target_group['TargetGroupArn'], Targets=params['Targets'], aws_retry=True)
+ connection.register_targets(
+ TargetGroupArn=target_group["TargetGroupArn"], Targets=params["Targets"], aws_retry=True
+ )
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Couldn't register targets")
if module.params.get("wait"):
- status_achieved, registered_instances = wait_for_status(connection, module, target_group['TargetGroupArn'], params['Targets'], 'healthy')
+ status_achieved, registered_instances = wait_for_status(
+ connection, module, target_group["TargetGroupArn"], params["Targets"], "healthy"
+ )
if not status_achieved:
- module.fail_json(msg='Error waiting for target registration to be healthy - please check the AWS console')
+ module.fail_json(
+ msg="Error waiting for target registration to be healthy - please check the AWS console"
+ )
else:
try:
target = module.params.get("targets")[0]
response = connection.register_targets(
- TargetGroupArn=target_group['TargetGroupArn'],
- Targets=[
- {
- "Id": target["Id"]
- }
- ],
- aws_retry=True
+ TargetGroupArn=target_group["TargetGroupArn"], Targets=[{"Id": target["Id"]}], aws_retry=True
)
changed = True
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(
- e, msg="Couldn't register targets")
+ module.fail_json_aws(e, msg="Couldn't register targets")
attributes_update = create_or_update_attributes(connection, module, target_group, new_target_group)
@@ -879,13 +931,17 @@ def create_or_update_target_group(connection, module):
# Tags - only need to play with tags if tags parameter has been set to something
if tags is not None:
# Get tags
- current_tags = get_target_group_tags(connection, module, target_group['TargetGroupArn'])
+ current_tags = get_target_group_tags(connection, module, target_group["TargetGroupArn"])
# Delete necessary tags
- tags_need_modify, tags_to_delete = compare_aws_tags(boto3_tag_list_to_ansible_dict(current_tags), tags, purge_tags)
+ tags_need_modify, tags_to_delete = compare_aws_tags(
+ boto3_tag_list_to_ansible_dict(current_tags), tags, purge_tags
+ )
if tags_to_delete:
try:
- connection.remove_tags(ResourceArns=[target_group['TargetGroupArn']], TagKeys=tags_to_delete, aws_retry=True)
+ connection.remove_tags(
+ ResourceArns=[target_group["TargetGroupArn"]], TagKeys=tags_to_delete, aws_retry=True
+ )
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Couldn't delete tags from target group")
changed = True
@@ -893,7 +949,11 @@ def create_or_update_target_group(connection, module):
# Add/update tags
if tags_need_modify:
try:
- connection.add_tags(ResourceArns=[target_group['TargetGroupArn']], Tags=ansible_dict_to_boto3_tag_list(tags_need_modify), aws_retry=True)
+ connection.add_tags(
+ ResourceArns=[target_group["TargetGroupArn"]],
+ Tags=ansible_dict_to_boto3_tag_list(tags_need_modify),
+ aws_retry=True,
+ )
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Couldn't add tags to target group")
changed = True
@@ -902,12 +962,14 @@ def create_or_update_target_group(connection, module):
target_group = get_target_group(connection, module)
# Get the target group attributes again
- target_group.update(get_tg_attributes(connection, module, target_group['TargetGroupArn']))
+ target_group.update(get_tg_attributes(connection, module, target_group["TargetGroupArn"]))
# Convert target_group to snake_case
snaked_tg = camel_dict_to_snake_dict(target_group)
- snaked_tg['tags'] = boto3_tag_list_to_ansible_dict(get_target_group_tags(connection, module, target_group['TargetGroupArn']))
+ snaked_tg["tags"] = boto3_tag_list_to_ansible_dict(
+ get_target_group_tags(connection, module, target_group["TargetGroupArn"])
+ )
module.exit_json(changed=changed, **snaked_tg)
@@ -918,7 +980,7 @@ def delete_target_group(connection, module):
if tg:
try:
- connection.delete_target_group(TargetGroupArn=tg['TargetGroupArn'], aws_retry=True)
+ connection.delete_target_group(TargetGroupArn=tg["TargetGroupArn"], aws_retry=True)
changed = True
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Couldn't delete target group")
@@ -927,66 +989,69 @@ def delete_target_group(connection, module):
def main():
- protocols_list = ['http', 'https', 'tcp', 'tls', 'udp', 'tcp_udp', 'HTTP',
- 'HTTPS', 'TCP', 'TLS', 'UDP', 'TCP_UDP']
+ protocols_list = ["http", "https", "tcp", "tls", "udp", "tcp_udp", "HTTP", "HTTPS", "TCP", "TLS", "UDP", "TCP_UDP"]
argument_spec = dict(
- deregistration_delay_timeout=dict(type='int'),
- deregistration_connection_termination=dict(type='bool', default=False),
+ deregistration_delay_timeout=dict(type="int"),
+ deregistration_connection_termination=dict(type="bool", default=False),
health_check_protocol=dict(choices=protocols_list),
health_check_port=dict(),
health_check_path=dict(),
- health_check_interval=dict(type='int'),
- health_check_timeout=dict(type='int'),
- healthy_threshold_count=dict(type='int'),
- modify_targets=dict(default=True, type='bool'),
+ health_check_interval=dict(type="int"),
+ health_check_timeout=dict(type="int"),
+ healthy_threshold_count=dict(type="int"),
+ modify_targets=dict(default=True, type="bool"),
name=dict(required=True),
- port=dict(type='int'),
+ port=dict(type="int"),
protocol=dict(choices=protocols_list),
- protocol_version=dict(type='str', choices=['GRPC', 'HTTP1', 'HTTP2']),
- purge_tags=dict(default=True, type='bool'),
- stickiness_enabled=dict(type='bool'),
+ protocol_version=dict(type="str", choices=["GRPC", "HTTP1", "HTTP2"]),
+ purge_tags=dict(default=True, type="bool"),
+ stickiness_enabled=dict(type="bool"),
stickiness_type=dict(),
- stickiness_lb_cookie_duration=dict(type='int'),
- stickiness_app_cookie_duration=dict(type='int'),
+ stickiness_lb_cookie_duration=dict(type="int"),
+ stickiness_app_cookie_duration=dict(type="int"),
stickiness_app_cookie_name=dict(),
- load_balancing_algorithm_type=dict(type='str', choices=['round_robin', 'least_outstanding_requests']),
- state=dict(required=True, choices=['present', 'absent']),
+ load_balancing_algorithm_type=dict(type="str", choices=["round_robin", "least_outstanding_requests"]),
+ state=dict(required=True, choices=["present", "absent"]),
successful_response_codes=dict(),
- tags=dict(type='dict', aliases=['resource_tags']),
- target_type=dict(choices=['instance', 'ip', 'lambda', 'alb']),
- targets=dict(type='list', elements='dict'),
- unhealthy_threshold_count=dict(type='int'),
+ tags=dict(type="dict", aliases=["resource_tags"]),
+ target_type=dict(choices=["instance", "ip", "lambda", "alb"]),
+ targets=dict(type="list", elements="dict"),
+ unhealthy_threshold_count=dict(type="int"),
vpc_id=dict(),
- preserve_client_ip_enabled=dict(type='bool'),
- proxy_protocol_v2_enabled=dict(type='bool'),
- wait_timeout=dict(type='int', default=200),
- wait=dict(type='bool', default=False)
+ preserve_client_ip_enabled=dict(type="bool"),
+ proxy_protocol_v2_enabled=dict(type="bool"),
+ wait_timeout=dict(type="int", default=200),
+ wait=dict(type="bool", default=False),
)
required_by = dict(
- health_check_path=['health_check_protocol'],
- successful_response_codes=['health_check_protocol'],
+ health_check_path=["health_check_protocol"],
+ successful_response_codes=["health_check_protocol"],
)
required_if = [
- ['target_type', 'instance', ['protocol', 'port', 'vpc_id']],
- ['target_type', 'ip', ['protocol', 'port', 'vpc_id']],
- ['target_type', 'alb', ['protocol', 'port', 'vpc_id']],
+ ["target_type", "instance", ["protocol", "port", "vpc_id"]],
+ ["target_type", "ip", ["protocol", "port", "vpc_id"]],
+ ["target_type", "alb", ["protocol", "port", "vpc_id"]],
]
module = AnsibleAWSModule(argument_spec=argument_spec, required_by=required_by, required_if=required_if)
- if module.params.get('target_type') is None:
- module.params['target_type'] = 'instance'
+ if module.params.get("target_type") is None:
+ module.params["target_type"] = "instance"
- connection = module.client('elbv2', retry_decorator=AWSRetry.jittered_backoff(retries=10))
+ connection = module.client("elbv2", retry_decorator=AWSRetry.jittered_backoff(retries=10))
- if module.params.get('state') == 'present':
- if module.params.get('protocol') in ['http', 'https', 'HTTP', 'HTTPS'] and module.params.get('deregistration_connection_termination', None):
- module.fail_json(msg="A target group with HTTP/S protocol does not support setting deregistration_connection_termination")
+ if module.params.get("state") == "present":
+ if module.params.get("protocol") in ["http", "https", "HTTP", "HTTPS"] and module.params.get(
+ "deregistration_connection_termination", None
+ ):
+ module.fail_json(
+ msg="A target group with HTTP/S protocol does not support setting deregistration_connection_termination"
+ )
create_or_update_target_group(connection, module)
else:
delete_target_group(connection, module)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/elb_target_group_info.py b/ansible_collections/community/aws/plugins/modules/elb_target_group_info.py
index 86cc03782..d0b013bfd 100644
--- a/ansible_collections/community/aws/plugins/modules/elb_target_group_info.py
+++ b/ansible_collections/community/aws/plugins/modules/elb_target_group_info.py
@@ -1,19 +1,18 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: elb_target_group_info
version_added: 1.0.0
short_description: Gather information about ELB target groups in AWS
description:
- - Gather information about ELB target groups in AWS
-author: Rob White (@wimnat)
+ - Gather information about ELB target groups in AWS
+author:
+ - Rob White (@wimnat)
options:
load_balancer_arn:
description:
@@ -40,13 +39,12 @@ options:
type: bool
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
+- amazon.aws.common.modules
+- amazon.aws.region.modules
- amazon.aws.boto3
+"""
-'''
-
-EXAMPLES = r'''
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide for details.
- name: Gather information about all target groups
@@ -61,10 +59,9 @@ EXAMPLES = r'''
names:
- tg1
- tg2
+"""
-'''
-
-RETURN = r'''
+RETURN = r"""
target_groups:
description: a list of target groups
returned: always
@@ -204,7 +201,7 @@ target_groups:
returned: always
type: str
sample: vpc-0123456
-'''
+"""
try:
import botocore
@@ -213,47 +210,48 @@ except ImportError:
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry, boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
@AWSRetry.jittered_backoff(retries=10)
def get_paginator(**kwargs):
- paginator = client.get_paginator('describe_target_groups')
+ paginator = client.get_paginator("describe_target_groups")
return paginator.paginate(**kwargs).build_full_result()
def get_target_group_attributes(target_group_arn):
-
try:
- target_group_attributes = boto3_tag_list_to_ansible_dict(client.describe_target_group_attributes(TargetGroupArn=target_group_arn)['Attributes'])
+ target_group_attributes = boto3_tag_list_to_ansible_dict(
+ client.describe_target_group_attributes(TargetGroupArn=target_group_arn)["Attributes"]
+ )
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Failed to describe target group attributes")
# Replace '.' with '_' in attribute key names to make it more Ansibley
- return dict((k.replace('.', '_'), v)
- for (k, v) in target_group_attributes.items())
+ return dict((k.replace(".", "_"), v) for (k, v) in target_group_attributes.items())
def get_target_group_tags(target_group_arn):
-
try:
- return boto3_tag_list_to_ansible_dict(client.describe_tags(ResourceArns=[target_group_arn])['TagDescriptions'][0]['Tags'])
+ return boto3_tag_list_to_ansible_dict(
+ client.describe_tags(ResourceArns=[target_group_arn])["TagDescriptions"][0]["Tags"]
+ )
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Failed to describe group tags")
def get_target_group_targets_health(target_group_arn):
-
try:
- return client.describe_target_health(TargetGroupArn=target_group_arn)['TargetHealthDescriptions']
+ return client.describe_target_health(TargetGroupArn=target_group_arn)["TargetHealthDescriptions"]
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Failed to get target health")
def list_target_groups():
-
load_balancer_arn = module.params.get("load_balancer_arn")
target_group_arns = module.params.get("target_group_arns")
names = module.params.get("names")
@@ -268,24 +266,29 @@ def list_target_groups():
target_groups = get_paginator(TargetGroupArns=target_group_arns)
if names:
target_groups = get_paginator(Names=names)
- except is_boto3_error_code('TargetGroupNotFound'):
+ except is_boto3_error_code("TargetGroupNotFound"):
module.exit_json(target_groups=[])
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
module.fail_json_aws(e, msg="Failed to list target groups")
# Get the attributes and tags for each target group
- for target_group in target_groups['TargetGroups']:
- target_group.update(get_target_group_attributes(target_group['TargetGroupArn']))
+ for target_group in target_groups["TargetGroups"]:
+ target_group.update(get_target_group_attributes(target_group["TargetGroupArn"]))
# Turn the boto3 result in to ansible_friendly_snaked_names
- snaked_target_groups = [camel_dict_to_snake_dict(target_group) for target_group in target_groups['TargetGroups']]
+ snaked_target_groups = [camel_dict_to_snake_dict(target_group) for target_group in target_groups["TargetGroups"]]
# Get tags for each target group
for snaked_target_group in snaked_target_groups:
- snaked_target_group['tags'] = get_target_group_tags(snaked_target_group['target_group_arn'])
+ snaked_target_group["tags"] = get_target_group_tags(snaked_target_group["target_group_arn"])
if collect_targets_health:
- snaked_target_group['targets_health_description'] = [camel_dict_to_snake_dict(
- target) for target in get_target_group_targets_health(snaked_target_group['target_group_arn'])]
+ snaked_target_group["targets_health_description"] = [
+ camel_dict_to_snake_dict(target)
+ for target in get_target_group_targets_health(snaked_target_group["target_group_arn"])
+ ]
module.exit_json(target_groups=snaked_target_groups)
@@ -295,25 +298,25 @@ def main():
global client
argument_spec = dict(
- load_balancer_arn=dict(type='str'),
- target_group_arns=dict(type='list', elements='str'),
- names=dict(type='list', elements='str'),
- collect_targets_health=dict(default=False, type='bool', required=False),
+ load_balancer_arn=dict(type="str"),
+ target_group_arns=dict(type="list", elements="str"),
+ names=dict(type="list", elements="str"),
+ collect_targets_health=dict(default=False, type="bool", required=False),
)
module = AnsibleAWSModule(
argument_spec=argument_spec,
- mutually_exclusive=[['load_balancer_arn', 'target_group_arns', 'names']],
+ mutually_exclusive=[["load_balancer_arn", "target_group_arns", "names"]],
supports_check_mode=True,
)
try:
- client = module.client('elbv2', retry_decorator=AWSRetry.jittered_backoff(retries=10))
+ client = module.client("elbv2", retry_decorator=AWSRetry.jittered_backoff(retries=10))
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to connect to AWS')
+ module.fail_json_aws(e, msg="Failed to connect to AWS")
list_target_groups()
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/elb_target_info.py b/ansible_collections/community/aws/plugins/modules/elb_target_info.py
index 4f91ac7f3..ad0b3c74b 100644
--- a/ansible_collections/community/aws/plugins/modules/elb_target_info.py
+++ b/ansible_collections/community/aws/plugins/modules/elb_target_info.py
@@ -1,10 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: (c) 2018, Yaakov Kuperman <ykuperman@gmail.com>
# GNU General Public License v3.0+ # (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: elb_target_info
version_added: 1.0.0
@@ -12,8 +12,8 @@ short_description: Gathers which target groups a target is associated with.
description:
- This module will search through every target group in a region to find
which ones have registered a given instance ID or IP.
-
-author: "Yaakov Kuperman (@yaakov-github)"
+author:
+ - "Yaakov Kuperman (@yaakov-github)"
options:
instance_id:
description:
@@ -25,109 +25,108 @@ options:
- Whether or not to get target groups not used by any load balancers.
type: bool
default: true
-extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
-'''
+extends_documentation_fragment:
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-EXAMPLES = """
+EXAMPLES = r"""
# practical use case - dynamically de-registering and re-registering nodes
- - name: Get EC2 Metadata
- amazon.aws.ec2_metadata_facts:
-
- - name: Get initial list of target groups
- delegate_to: localhost
- community.aws.elb_target_info:
- instance_id: "{{ ansible_ec2_instance_id }}"
- region: "{{ ansible_ec2_placement_region }}"
- register: target_info
-
- - name: save fact for later
- ansible.builtin.set_fact:
- original_tgs: "{{ target_info.instance_target_groups }}"
-
- - name: Deregister instance from all target groups
- delegate_to: localhost
- community.aws.elb_target:
- target_group_arn: "{{ item.0.target_group_arn }}"
- target_port: "{{ item.1.target_port }}"
- target_az: "{{ item.1.target_az }}"
- target_id: "{{ item.1.target_id }}"
- state: absent
- target_status: "draining"
- region: "{{ ansible_ec2_placement_region }}"
- with_subelements:
- - "{{ original_tgs }}"
- - "targets"
-
- # This avoids having to wait for 'elb_target' to serially deregister each
- # target group. An alternative would be to run all of the 'elb_target'
- # tasks async and wait for them to finish.
-
- - name: wait for all targets to deregister simultaneously
- delegate_to: localhost
- community.aws.elb_target_info:
- get_unused_target_groups: false
- instance_id: "{{ ansible_ec2_instance_id }}"
- region: "{{ ansible_ec2_placement_region }}"
- register: target_info
- until: (target_info.instance_target_groups | length) == 0
- retries: 60
- delay: 10
-
- - name: reregister in elbv2s
- community.aws.elb_target:
- region: "{{ ansible_ec2_placement_region }}"
- target_group_arn: "{{ item.0.target_group_arn }}"
- target_port: "{{ item.1.target_port }}"
- target_az: "{{ item.1.target_az }}"
- target_id: "{{ item.1.target_id }}"
- state: present
- target_status: "initial"
- with_subelements:
- - "{{ original_tgs }}"
- - "targets"
-
- # wait until all groups associated with this instance are 'healthy' or
- # 'unused'
- - name: wait for registration
- community.aws.elb_target_info:
- get_unused_target_groups: false
- instance_id: "{{ ansible_ec2_instance_id }}"
- region: "{{ ansible_ec2_placement_region }}"
- register: target_info
- until: (target_info.instance_target_groups |
- map(attribute='targets') |
- flatten |
- map(attribute='target_health') |
- rejectattr('state', 'equalto', 'healthy') |
- rejectattr('state', 'equalto', 'unused') |
- list |
- length) == 0
- retries: 61
- delay: 10
+- name: Get EC2 Metadata
+ amazon.aws.ec2_metadata_facts:
+
+- name: Get initial list of target groups
+ delegate_to: localhost
+ community.aws.elb_target_info:
+ instance_id: "{{ ansible_ec2_instance_id }}"
+ region: "{{ ansible_ec2_placement_region }}"
+ register: target_info
+
+- name: save fact for later
+ ansible.builtin.set_fact:
+ original_tgs: "{{ target_info.instance_target_groups }}"
+
+- name: Deregister instance from all target groups
+ delegate_to: localhost
+ community.aws.elb_target:
+ target_group_arn: "{{ item.0.target_group_arn }}"
+ target_port: "{{ item.1.target_port }}"
+ target_az: "{{ item.1.target_az }}"
+ target_id: "{{ item.1.target_id }}"
+ state: absent
+ target_status: "draining"
+ region: "{{ ansible_ec2_placement_region }}"
+ with_subelements:
+ - "{{ original_tgs }}"
+ - "targets"
+
+ # This avoids having to wait for 'elb_target' to serially deregister each
+ # target group. An alternative would be to run all of the 'elb_target'
+ # tasks async and wait for them to finish.
+
+- name: wait for all targets to deregister simultaneously
+ delegate_to: localhost
+ community.aws.elb_target_info:
+ get_unused_target_groups: false
+ instance_id: "{{ ansible_ec2_instance_id }}"
+ region: "{{ ansible_ec2_placement_region }}"
+ register: target_info
+ until: (target_info.instance_target_groups | length) == 0
+ retries: 60
+ delay: 10
+
+- name: reregister in elbv2s
+ community.aws.elb_target:
+ region: "{{ ansible_ec2_placement_region }}"
+ target_group_arn: "{{ item.0.target_group_arn }}"
+ target_port: "{{ item.1.target_port }}"
+ target_az: "{{ item.1.target_az }}"
+ target_id: "{{ item.1.target_id }}"
+ state: present
+ target_status: "initial"
+ with_subelements:
+ - "{{ original_tgs }}"
+ - "targets"
+
+# wait until all groups associated with this instance are 'healthy' or
+# 'unused'
+- name: wait for registration
+ community.aws.elb_target_info:
+ get_unused_target_groups: false
+ instance_id: "{{ ansible_ec2_instance_id }}"
+ region: "{{ ansible_ec2_placement_region }}"
+ register: target_info
+ until: (target_info.instance_target_groups |
+ map(attribute='targets') |
+ flatten |
+ map(attribute='target_health') |
+ rejectattr('state', 'equalto', 'healthy') |
+ rejectattr('state', 'equalto', 'unused') |
+ list |
+ length) == 0
+ retries: 61
+ delay: 10
# using the target groups to generate AWS CLI commands to reregister the
# instance - useful in case the playbook fails mid-run and manual
# rollback is required
- - name: "reregistration commands: ELBv2s"
- ansible.builtin.debug:
- msg: >
- aws --region {{ansible_ec2_placement_region}} elbv2
- register-targets --target-group-arn {{item.target_group_arn}}
- --targets{%for target in item.targets%}
- Id={{target.target_id}},
- Port={{target.target_port}}{%if target.target_az%},AvailabilityZone={{target.target_az}}
- {%endif%}
- {%endfor%}
- loop: "{{target_info.instance_target_groups}}"
-
+- name: "reregistration commands: ELBv2s"
+ ansible.builtin.debug:
+ msg: >
+ aws --region {{ansible_ec2_placement_region}} elbv2
+ register-targets --target-group-arn {{item.target_group_arn}}
+ --targets{%for target in item.targets%}
+ Id={{target.target_id}},
+ Port={{target.target_port}}{%if target.target_az%},AvailabilityZone={{target.target_az}}
+ {%endif%}
+ {%endfor%}
+ loop: "{{target_info.instance_target_groups}}"
"""
-RETURN = """
+RETURN = r"""
instance_target_groups:
description: a list of target groups to which the instance is registered to
returned: always
@@ -204,20 +203,23 @@ instance_target_groups:
type: str
"""
-__metaclass__ = type
-
try:
- from botocore.exceptions import ClientError, BotoCoreError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
except ImportError:
# we can handle the lack of boto3 based on the ec2 module
pass
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict, AWSRetry
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
class Target(object):
"""Models a target in a target group"""
+
def __init__(self, target_id, port, az, raw_target_health):
self.target_port = port
self.target_id = target_id
@@ -238,10 +240,7 @@ class TargetGroup(object):
self.targets = []
def add_target(self, target_id, target_port, target_az, raw_target_health):
- self.targets.append(Target(target_id,
- target_port,
- target_az,
- raw_target_health))
+ self.targets.append(Target(target_id, target_port, target_az, raw_target_health))
def to_dict(self):
object_dict = vars(self)
@@ -253,28 +252,17 @@ class TargetGroup(object):
class TargetInfoGatherer(object):
-
def __init__(self, module, instance_id, get_unused_target_groups):
self.module = module
try:
- self.ec2 = self.module.client(
- "ec2",
- retry_decorator=AWSRetry.jittered_backoff(retries=10)
- )
+ self.ec2 = self.module.client("ec2", retry_decorator=AWSRetry.jittered_backoff(retries=10))
except (ClientError, BotoCoreError) as e:
- self.module.fail_json_aws(e,
- msg="Couldn't connect to ec2"
- )
+ self.module.fail_json_aws(e, msg="Couldn't connect to ec2")
try:
- self.elbv2 = self.module.client(
- "elbv2",
- retry_decorator=AWSRetry.jittered_backoff(retries=10)
- )
+ self.elbv2 = self.module.client("elbv2", retry_decorator=AWSRetry.jittered_backoff(retries=10))
except (BotoCoreError, ClientError) as e:
- self.module.fail_json_aws(e,
- msg="Could not connect to elbv2"
- )
+ self.module.fail_json_aws(e, msg="Could not connect to elbv2")
self.instance_id = instance_id
self.get_unused_target_groups = get_unused_target_groups
@@ -282,25 +270,19 @@ class TargetInfoGatherer(object):
def _get_instance_ips(self):
"""Fetch all IPs associated with this instance so that we can determine
- whether or not an instance is in an IP-based target group"""
+ whether or not an instance is in an IP-based target group"""
try:
# get ahold of the instance in the API
- reservations = self.ec2.describe_instances(
- InstanceIds=[self.instance_id],
- aws_retry=True
- )["Reservations"]
+ reservations = self.ec2.describe_instances(InstanceIds=[self.instance_id], aws_retry=True)["Reservations"]
except (BotoCoreError, ClientError) as e:
# typically this will happen if the instance doesn't exist
- self.module.fail_json_aws(e,
- msg="Could not get instance info" +
- " for instance '%s'" %
- (self.instance_id)
- )
+ self.module.fail_json_aws(
+ e,
+ msg=f"Could not get instance info for instance '{self.instance_id}'",
+ )
if len(reservations) < 1:
- self.module.fail_json(
- msg="Instance ID %s could not be found" % self.instance_id
- )
+ self.module.fail_json(msg=f"Instance ID {self.instance_id} could not be found")
instance = reservations[0]["Instances"][0]
@@ -317,38 +299,36 @@ class TargetInfoGatherer(object):
def _get_target_group_objects(self):
"""helper function to build a list of TargetGroup objects based on
- the AWS API"""
+ the AWS API"""
try:
- paginator = self.elbv2.get_paginator(
- "describe_target_groups"
- )
+ paginator = self.elbv2.get_paginator("describe_target_groups")
tg_response = paginator.paginate().build_full_result()
except (BotoCoreError, ClientError) as e:
- self.module.fail_json_aws(e,
- msg="Could not describe target" +
- " groups"
- )
+ self.module.fail_json_aws(
+ e,
+ msg="Could not describe target groups",
+ )
# build list of TargetGroup objects representing every target group in
# the system
target_groups = []
for each_tg in tg_response["TargetGroups"]:
- if not self.get_unused_target_groups and \
- len(each_tg["LoadBalancerArns"]) < 1:
+ if not self.get_unused_target_groups and len(each_tg["LoadBalancerArns"]) < 1:
# only collect target groups that actually are connected
# to LBs
continue
target_groups.append(
- TargetGroup(target_group_arn=each_tg["TargetGroupArn"],
- target_group_type=each_tg["TargetType"],
- )
+ TargetGroup(
+ target_group_arn=each_tg["TargetGroupArn"],
+ target_group_type=each_tg["TargetType"],
+ )
)
return target_groups
def _get_target_descriptions(self, target_groups):
"""Helper function to build a list of all the target descriptions
- for this target in a target group"""
+ for this target in a target group"""
# Build a list of all the target groups pointing to this instance
# based on the previous list
tgs = set()
@@ -356,37 +336,25 @@ class TargetInfoGatherer(object):
for tg in target_groups:
try:
# Get the list of targets for that target group
- response = self.elbv2.describe_target_health(
- TargetGroupArn=tg.target_group_arn,
- aws_retry=True
- )
+ response = self.elbv2.describe_target_health(TargetGroupArn=tg.target_group_arn, aws_retry=True)
except (BotoCoreError, ClientError) as e:
- self.module.fail_json_aws(e,
- msg="Could not describe target " +
- "health for target group %s" %
- tg.target_group_arn
- )
+ self.module.fail_json_aws(
+ e, msg="Could not describe target " + f"health for target group {tg.target_group_arn}"
+ )
for t in response["TargetHealthDescriptions"]:
# If the target group has this instance as a target, add to
# list. This logic also accounts for the possibility of a
# target being in the target group multiple times with
# overridden ports
- if t["Target"]["Id"] == self.instance_id or \
- t["Target"]["Id"] in self.instance_ips:
-
+ if t["Target"]["Id"] == self.instance_id or t["Target"]["Id"] in self.instance_ips:
# The 'AvailabilityZone' parameter is a weird one, see the
# API docs for more. Basically it's only supposed to be
# there under very specific circumstances, so we need
# to account for that
- az = t["Target"]["AvailabilityZone"] \
- if "AvailabilityZone" in t["Target"] \
- else None
-
- tg.add_target(t["Target"]["Id"],
- t["Target"]["Port"],
- az,
- t["TargetHealth"])
+ az = t["Target"]["AvailabilityZone"] if "AvailabilityZone" in t["Target"] else None
+
+ tg.add_target(t["Target"]["Id"], t["Target"]["Port"], az, t["TargetHealth"])
# since tgs is a set, each target group will be added only
# once, even though we call add on each successful match
tgs.add(tg)
@@ -404,8 +372,7 @@ class TargetInfoGatherer(object):
def main():
argument_spec = dict(
instance_id={"required": True, "type": "str"},
- get_unused_target_groups={"required": False,
- "default": True, "type": "bool"}
+ get_unused_target_groups={"required": False, "default": True, "type": "bool"},
)
module = AnsibleAWSModule(
@@ -416,10 +383,7 @@ def main():
instance_id = module.params["instance_id"]
get_unused_target_groups = module.params["get_unused_target_groups"]
- tg_gatherer = TargetInfoGatherer(module,
- instance_id,
- get_unused_target_groups
- )
+ tg_gatherer = TargetInfoGatherer(module, instance_id, get_unused_target_groups)
instance_target_groups = [each.to_dict() for each in tg_gatherer.tgs]
diff --git a/ansible_collections/community/aws/plugins/modules/glue_connection.py b/ansible_collections/community/aws/plugins/modules/glue_connection.py
index bcfacb171..18039a861 100644
--- a/ansible_collections/community/aws/plugins/modules/glue_connection.py
+++ b/ansible_collections/community/aws/plugins/modules/glue_connection.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: (c) 2018, Rob White (@wimnat)
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: glue_connection
version_added: 1.0.0
@@ -72,12 +70,12 @@ options:
- Required when I(connection_type=NETWORK).
type: str
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide for details.
# Create an AWS Glue connection
@@ -106,9 +104,9 @@ EXAMPLES = r'''
- community.aws.glue_connection:
name: my-glue-connection
state: absent
-'''
+"""
-RETURN = r'''
+RETURN = r"""
connection_properties:
description:
- (deprecated) A dict of key-value pairs (converted to lowercase) used as parameters for this connection.
@@ -157,11 +155,11 @@ raw_connection_properties:
returned: when state is present
type: dict
sample: {'JDBC_CONNECTION_URL':'jdbc:mysql://mydb:3306/databasename','USERNAME':'x','PASSWORD':'y'}
-'''
+"""
-# Non-ansible imports
import copy
import time
+
try:
import botocore
except ImportError:
@@ -169,10 +167,11 @@ except ImportError:
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import get_ec2_security_group_ids_from_names
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def _get_glue_connection(connection, module):
@@ -187,13 +186,13 @@ def _get_glue_connection(connection, module):
connection_name = module.params.get("name")
connection_catalog_id = module.params.get("catalog_id")
- params = {'Name': connection_name}
+ params = {"Name": connection_name}
if connection_catalog_id is not None:
- params['CatalogId'] = connection_catalog_id
+ params["CatalogId"] = connection_catalog_id
try:
- return connection.get_connection(aws_retry=True, **params)['Connection']
- except is_boto3_error_code('EntityNotFoundException'):
+ return connection.get_connection(aws_retry=True, **params)["Connection"]
+ except is_boto3_error_code("EntityNotFoundException"):
return None
@@ -209,37 +208,50 @@ def _compare_glue_connection_params(user_params, current_params):
# Weirdly, boto3 doesn't return some keys if the value is empty e.g. Description
# To counter this, add the key if it's missing with a blank value
- if 'Description' not in current_params:
- current_params['Description'] = ""
- if 'MatchCriteria' not in current_params:
- current_params['MatchCriteria'] = list()
- if 'PhysicalConnectionRequirements' not in current_params:
- current_params['PhysicalConnectionRequirements'] = dict()
- current_params['PhysicalConnectionRequirements']['SecurityGroupIdList'] = []
- current_params['PhysicalConnectionRequirements']['SubnetId'] = ""
-
- if 'ConnectionProperties' in user_params['ConnectionInput'] and user_params['ConnectionInput']['ConnectionProperties'] \
- != current_params['ConnectionProperties']:
+ if "Description" not in current_params:
+ current_params["Description"] = ""
+ if "MatchCriteria" not in current_params:
+ current_params["MatchCriteria"] = list()
+ if "PhysicalConnectionRequirements" not in current_params:
+ current_params["PhysicalConnectionRequirements"] = dict()
+ current_params["PhysicalConnectionRequirements"]["SecurityGroupIdList"] = []
+ current_params["PhysicalConnectionRequirements"]["SubnetId"] = ""
+
+ if (
+ "ConnectionProperties" in user_params["ConnectionInput"]
+ and user_params["ConnectionInput"]["ConnectionProperties"] != current_params["ConnectionProperties"]
+ ):
return True
- if 'ConnectionType' in user_params['ConnectionInput'] and user_params['ConnectionInput']['ConnectionType'] \
- != current_params['ConnectionType']:
+ if (
+ "ConnectionType" in user_params["ConnectionInput"]
+ and user_params["ConnectionInput"]["ConnectionType"] != current_params["ConnectionType"]
+ ):
return True
- if 'Description' in user_params['ConnectionInput'] and user_params['ConnectionInput']['Description'] != current_params['Description']:
+ if (
+ "Description" in user_params["ConnectionInput"]
+ and user_params["ConnectionInput"]["Description"] != current_params["Description"]
+ ):
return True
- if 'MatchCriteria' in user_params['ConnectionInput'] and set(user_params['ConnectionInput']['MatchCriteria']) != set(current_params['MatchCriteria']):
+ if "MatchCriteria" in user_params["ConnectionInput"] and set(
+ user_params["ConnectionInput"]["MatchCriteria"]
+ ) != set(current_params["MatchCriteria"]):
return True
- if 'PhysicalConnectionRequirements' in user_params['ConnectionInput']:
- if 'SecurityGroupIdList' in user_params['ConnectionInput']['PhysicalConnectionRequirements'] and \
- set(user_params['ConnectionInput']['PhysicalConnectionRequirements']['SecurityGroupIdList']) \
- != set(current_params['PhysicalConnectionRequirements']['SecurityGroupIdList']):
+ if "PhysicalConnectionRequirements" in user_params["ConnectionInput"]:
+ if "SecurityGroupIdList" in user_params["ConnectionInput"]["PhysicalConnectionRequirements"] and set(
+ user_params["ConnectionInput"]["PhysicalConnectionRequirements"]["SecurityGroupIdList"]
+ ) != set(current_params["PhysicalConnectionRequirements"]["SecurityGroupIdList"]):
return True
- if 'SubnetId' in user_params['ConnectionInput']['PhysicalConnectionRequirements'] and \
- user_params['ConnectionInput']['PhysicalConnectionRequirements']['SubnetId'] \
- != current_params['PhysicalConnectionRequirements']['SubnetId']:
+ if (
+ "SubnetId" in user_params["ConnectionInput"]["PhysicalConnectionRequirements"]
+ and user_params["ConnectionInput"]["PhysicalConnectionRequirements"]["SubnetId"]
+ != current_params["PhysicalConnectionRequirements"]["SubnetId"]
+ ):
return True
- if 'AvailabilityZone' in user_params['ConnectionInput']['PhysicalConnectionRequirements'] and \
- user_params['ConnectionInput']['PhysicalConnectionRequirements']['AvailabilityZone'] \
- != current_params['PhysicalConnectionRequirements']['AvailabilityZone']:
+ if (
+ "AvailabilityZone" in user_params["ConnectionInput"]["PhysicalConnectionRequirements"]
+ and user_params["ConnectionInput"]["PhysicalConnectionRequirements"]["AvailabilityZone"]
+ != current_params["PhysicalConnectionRequirements"]["AvailabilityZone"]
+ ):
return True
return False
@@ -253,11 +265,11 @@ def _await_glue_connection(connection, module):
while wait_timeout > time.time():
glue_connection = _get_glue_connection(connection, module)
- if glue_connection and glue_connection.get('Name'):
+ if glue_connection and glue_connection.get("Name"):
return glue_connection
time.sleep(check_interval)
- module.fail_json(msg='Timeout waiting for Glue connection %s' % module.params.get('name'))
+ module.fail_json(msg=f"Timeout waiting for Glue connection {module.params.get('name')}")
def create_or_update_glue_connection(connection, connection_ec2, module, glue_connection):
@@ -272,26 +284,30 @@ def create_or_update_glue_connection(connection, connection_ec2, module, glue_co
changed = False
params = dict()
- params['ConnectionInput'] = dict()
- params['ConnectionInput']['Name'] = module.params.get("name")
- params['ConnectionInput']['ConnectionType'] = module.params.get("connection_type")
- params['ConnectionInput']['ConnectionProperties'] = module.params.get("connection_properties")
+ params["ConnectionInput"] = dict()
+ params["ConnectionInput"]["Name"] = module.params.get("name")
+ params["ConnectionInput"]["ConnectionType"] = module.params.get("connection_type")
+ params["ConnectionInput"]["ConnectionProperties"] = module.params.get("connection_properties")
if module.params.get("catalog_id") is not None:
- params['CatalogId'] = module.params.get("catalog_id")
+ params["CatalogId"] = module.params.get("catalog_id")
if module.params.get("description") is not None:
- params['ConnectionInput']['Description'] = module.params.get("description")
+ params["ConnectionInput"]["Description"] = module.params.get("description")
if module.params.get("match_criteria") is not None:
- params['ConnectionInput']['MatchCriteria'] = module.params.get("match_criteria")
+ params["ConnectionInput"]["MatchCriteria"] = module.params.get("match_criteria")
if module.params.get("security_groups") is not None or module.params.get("subnet_id") is not None:
- params['ConnectionInput']['PhysicalConnectionRequirements'] = dict()
+ params["ConnectionInput"]["PhysicalConnectionRequirements"] = dict()
if module.params.get("security_groups") is not None:
# Get security group IDs from names
- security_group_ids = get_ec2_security_group_ids_from_names(module.params.get('security_groups'), connection_ec2, boto3=True)
- params['ConnectionInput']['PhysicalConnectionRequirements']['SecurityGroupIdList'] = security_group_ids
+ security_group_ids = get_ec2_security_group_ids_from_names(
+ module.params.get("security_groups"), connection_ec2, boto3=True
+ )
+ params["ConnectionInput"]["PhysicalConnectionRequirements"]["SecurityGroupIdList"] = security_group_ids
if module.params.get("subnet_id") is not None:
- params['ConnectionInput']['PhysicalConnectionRequirements']['SubnetId'] = module.params.get("subnet_id")
+ params["ConnectionInput"]["PhysicalConnectionRequirements"]["SubnetId"] = module.params.get("subnet_id")
if module.params.get("availability_zone") is not None:
- params['ConnectionInput']['PhysicalConnectionRequirements']['AvailabilityZone'] = module.params.get("availability_zone")
+ params["ConnectionInput"]["PhysicalConnectionRequirements"]["AvailabilityZone"] = module.params.get(
+ "availability_zone"
+ )
# If glue_connection is not None then check if it needs to be modified, else create it
if glue_connection:
@@ -299,7 +315,7 @@ def create_or_update_glue_connection(connection, connection_ec2, module, glue_co
try:
# We need to slightly modify the params for an update
update_params = copy.deepcopy(params)
- update_params['Name'] = update_params['ConnectionInput']['Name']
+ update_params["Name"] = update_params["ConnectionInput"]["Name"]
if not module.check_mode:
connection.update_connection(aws_retry=True, **update_params)
changed = True
@@ -318,12 +334,19 @@ def create_or_update_glue_connection(connection, connection_ec2, module, glue_co
glue_connection = _await_glue_connection(connection, module)
if glue_connection:
- module.deprecate("The 'connection_properties' return key is deprecated and will be replaced"
- " by 'raw_connection_properties'. Both values are returned for now.",
- date='2024-06-01', collection_name='community.aws')
- glue_connection['RawConnectionProperties'] = glue_connection['ConnectionProperties']
+ module.deprecate(
+ (
+ "The 'connection_properties' return key is deprecated and will be replaced"
+ " by 'raw_connection_properties'. Both values are returned for now."
+ ),
+ date="2024-06-01",
+ collection_name="community.aws",
+ )
+ glue_connection["RawConnectionProperties"] = glue_connection["ConnectionProperties"]
- module.exit_json(changed=changed, **camel_dict_to_snake_dict(glue_connection or {}, ignore_list=['RawConnectionProperties']))
+ module.exit_json(
+ changed=changed, **camel_dict_to_snake_dict(glue_connection or {}, ignore_list=["RawConnectionProperties"])
+ )
def delete_glue_connection(connection, module, glue_connection):
@@ -337,9 +360,9 @@ def delete_glue_connection(connection, module, glue_connection):
"""
changed = False
- params = {'ConnectionName': module.params.get("name")}
+ params = {"ConnectionName": module.params.get("name")}
if module.params.get("catalog_id") is not None:
- params['CatalogId'] = module.params.get("catalog_id")
+ params["CatalogId"] = module.params.get("catalog_id")
if glue_connection:
try:
@@ -353,41 +376,41 @@ def delete_glue_connection(connection, module, glue_connection):
def main():
-
- argument_spec = (
- dict(
- availability_zone=dict(type='str'),
- catalog_id=dict(type='str'),
- connection_properties=dict(type='dict'),
- connection_type=dict(type='str', default='JDBC', choices=['CUSTOM', 'JDBC', 'KAFKA', 'MARKETPLACE', 'MONGODB', 'NETWORK']),
- description=dict(type='str'),
- match_criteria=dict(type='list', elements='str'),
- name=dict(required=True, type='str'),
- security_groups=dict(type='list', elements='str'),
- state=dict(required=True, choices=['present', 'absent'], type='str'),
- subnet_id=dict(type='str')
- )
+ argument_spec = dict(
+ availability_zone=dict(type="str"),
+ catalog_id=dict(type="str"),
+ connection_properties=dict(type="dict"),
+ connection_type=dict(
+ type="str", default="JDBC", choices=["CUSTOM", "JDBC", "KAFKA", "MARKETPLACE", "MONGODB", "NETWORK"]
+ ),
+ description=dict(type="str"),
+ match_criteria=dict(type="list", elements="str"),
+ name=dict(required=True, type="str"),
+ security_groups=dict(type="list", elements="str"),
+ state=dict(required=True, choices=["present", "absent"], type="str"),
+ subnet_id=dict(type="str"),
)
- module = AnsibleAWSModule(argument_spec=argument_spec,
- required_if=[
- ('state', 'present', ['connection_properties']),
- ('connection_type', 'NETWORK', ['availability_zone', 'security_groups', 'subnet_id'])
- ],
- supports_check_mode=True
- )
+ module = AnsibleAWSModule(
+ argument_spec=argument_spec,
+ required_if=[
+ ("state", "present", ["connection_properties"]),
+ ("connection_type", "NETWORK", ["availability_zone", "security_groups", "subnet_id"]),
+ ],
+ supports_check_mode=True,
+ )
retry_decorator = AWSRetry.jittered_backoff(retries=10)
- connection_glue = module.client('glue', retry_decorator=retry_decorator)
- connection_ec2 = module.client('ec2', retry_decorator=retry_decorator)
+ connection_glue = module.client("glue", retry_decorator=retry_decorator)
+ connection_ec2 = module.client("ec2", retry_decorator=retry_decorator)
glue_connection = _get_glue_connection(connection_glue, module)
- if module.params.get("state") == 'present':
+ if module.params.get("state") == "present":
create_or_update_glue_connection(connection_glue, connection_ec2, module, glue_connection)
else:
delete_glue_connection(connection_glue, module, glue_connection)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/glue_crawler.py b/ansible_collections/community/aws/plugins/modules/glue_crawler.py
index a47b8eb3f..5d92219df 100644
--- a/ansible_collections/community/aws/plugins/modules/glue_crawler.py
+++ b/ansible_collections/community/aws/plugins/modules/glue_crawler.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: (c) 2018, Rob White (@wimnat)
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: glue_crawler
version_added: 4.1.0
@@ -77,13 +75,13 @@ options:
- Required when I(state=present).
type: dict
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
- - amazon.aws.boto3
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.tags
-'''
+ - amazon.aws.boto3
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide for details.
# Create an AWS Glue crawler
@@ -109,9 +107,9 @@ EXAMPLES = r'''
- community.aws.glue_crawler:
name: my-glue-crawler
state: absent
-'''
+"""
-RETURN = r'''
+RETURN = r"""
creation_time:
description: The time and date that this crawler definition was created.
returned: when state is present
@@ -198,7 +196,7 @@ targets:
description: List of catalog targets.
returned: when state is present
type: list
-'''
+"""
try:
import botocore
@@ -208,22 +206,26 @@ except ImportError:
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
from ansible.module_utils.common.dict_transformations import snake_dict_to_camel_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import compare_aws_tags
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
from ansible_collections.amazon.aws.plugins.module_utils.iam import get_aws_account_info
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import compare_aws_tags
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def _get_glue_crawler(connection, module, glue_crawler_name):
- '''
+ """
Get an AWS Glue crawler based on name. If not found, return None.
- '''
+ """
try:
- return connection.get_crawler(aws_retry=True, Name=glue_crawler_name)['Crawler']
- except is_boto3_error_code('EntityNotFoundException'):
+ return connection.get_crawler(aws_retry=True, Name=glue_crawler_name)["Crawler"]
+ except is_boto3_error_code("EntityNotFoundException"):
return None
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
module.fail_json_aws(e)
@@ -239,39 +241,58 @@ def _trim_target(target):
if not target:
return None
retval = target.copy()
- if not retval.get('Exclusions', None):
- retval.pop('Exclusions', None)
+ if not retval.get("Exclusions", None):
+ retval.pop("Exclusions", None)
return retval
def _compare_glue_crawler_params(user_params, current_params):
- '''
+ """
Compare Glue crawler params. If there is a difference, return True immediately else return False
- '''
- if 'DatabaseName' in user_params and user_params['DatabaseName'] != current_params['DatabaseName']:
+ """
+ if "DatabaseName" in user_params and user_params["DatabaseName"] != current_params["DatabaseName"]:
return True
- if 'Description' in user_params and user_params['Description'] != current_params['Description']:
+ if "Description" in user_params and user_params["Description"] != current_params["Description"]:
return True
- if 'RecrawlPolicy' in user_params and user_params['RecrawlPolicy'] != current_params['RecrawlPolicy']:
+ if "RecrawlPolicy" in user_params and user_params["RecrawlPolicy"] != current_params["RecrawlPolicy"]:
return True
- if 'Role' in user_params and user_params['Role'] != current_params['Role']:
+ if "Role" in user_params and user_params["Role"] != current_params["Role"]:
return True
- if 'SchemaChangePolicy' in user_params and user_params['SchemaChangePolicy'] != current_params['SchemaChangePolicy']:
+ if (
+ "SchemaChangePolicy" in user_params
+ and user_params["SchemaChangePolicy"] != current_params["SchemaChangePolicy"]
+ ):
return True
- if 'TablePrefix' in user_params and user_params['TablePrefix'] != current_params['TablePrefix']:
+ if "TablePrefix" in user_params and user_params["TablePrefix"] != current_params["TablePrefix"]:
return True
- if 'Targets' in user_params:
- if 'S3Targets' in user_params['Targets']:
- if _trim_targets(user_params['Targets']['S3Targets']) != _trim_targets(current_params['Targets']['S3Targets']):
+ if "Targets" in user_params:
+ if "S3Targets" in user_params["Targets"]:
+ if _trim_targets(user_params["Targets"]["S3Targets"]) != _trim_targets(
+ current_params["Targets"]["S3Targets"]
+ ):
return True
- if 'JdbcTargets' in user_params['Targets'] and user_params['Targets']['JdbcTargets'] != current_params['Targets']['JdbcTargets']:
- if _trim_targets(user_params['Targets']['JdbcTargets']) != _trim_targets(current_params['Targets']['JdbcTargets']):
+ if (
+ "JdbcTargets" in user_params["Targets"]
+ and user_params["Targets"]["JdbcTargets"] != current_params["Targets"]["JdbcTargets"]
+ ):
+ if _trim_targets(user_params["Targets"]["JdbcTargets"]) != _trim_targets(
+ current_params["Targets"]["JdbcTargets"]
+ ):
return True
- if 'MongoDBTargets' in user_params['Targets'] and user_params['Targets']['MongoDBTargets'] != current_params['Targets']['MongoDBTargets']:
+ if (
+ "MongoDBTargets" in user_params["Targets"]
+ and user_params["Targets"]["MongoDBTargets"] != current_params["Targets"]["MongoDBTargets"]
+ ):
return True
- if 'DynamoDBTargets' in user_params['Targets'] and user_params['Targets']['DynamoDBTargets'] != current_params['Targets']['DynamoDBTargets']:
+ if (
+ "DynamoDBTargets" in user_params["Targets"]
+ and user_params["Targets"]["DynamoDBTargets"] != current_params["Targets"]["DynamoDBTargets"]
+ ):
return True
- if 'CatalogTargets' in user_params['Targets'] and user_params['Targets']['CatalogTargets'] != current_params['Targets']['CatalogTargets']:
+ if (
+ "CatalogTargets" in user_params["Targets"]
+ and user_params["Targets"]["CatalogTargets"] != current_params["Targets"]["CatalogTargets"]
+ ):
return True
return False
@@ -280,21 +301,23 @@ def _compare_glue_crawler_params(user_params, current_params):
def ensure_tags(connection, module, glue_crawler):
changed = False
- if module.params.get('tags') is None:
+ if module.params.get("tags") is None:
return False
account_id, partition = get_aws_account_info(module)
- arn = 'arn:{0}:glue:{1}:{2}:crawler/{3}'.format(partition, module.region, account_id, module.params.get('name'))
+ arn = f"arn:{partition}:glue:{module.region}:{account_id}:crawler/{module.params.get('name')}"
try:
- existing_tags = connection.get_tags(aws_retry=True, ResourceArn=arn).get('Tags', {})
+ existing_tags = connection.get_tags(aws_retry=True, ResourceArn=arn).get("Tags", {})
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
if module.check_mode:
existing_tags = {}
else:
- module.fail_json_aws(e, msg='Unable to get tags for Glue crawler %s' % module.params.get('name'))
+ module.fail_json_aws(e, msg=f"Unable to get tags for Glue crawler {module.params.get('name')}")
- tags_to_add, tags_to_remove = compare_aws_tags(existing_tags, module.params.get('tags'), module.params.get('purge_tags'))
+ tags_to_add, tags_to_remove = compare_aws_tags(
+ existing_tags, module.params.get("tags"), module.params.get("purge_tags")
+ )
if tags_to_remove:
changed = True
@@ -302,7 +325,7 @@ def ensure_tags(connection, module, glue_crawler):
try:
connection.untag_resource(aws_retry=True, ResourceArn=arn, TagsToRemove=tags_to_remove)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Unable to set tags for Glue crawler %s' % module.params.get('name'))
+ module.fail_json_aws(e, msg=f"Unable to set tags for Glue crawler {module.params.get('name')}")
if tags_to_add:
changed = True
@@ -310,35 +333,37 @@ def ensure_tags(connection, module, glue_crawler):
try:
connection.tag_resource(aws_retry=True, ResourceArn=arn, TagsToAdd=tags_to_add)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Unable to set tags for Glue crawler %s' % module.params.get('name'))
+ module.fail_json_aws(e, msg=f"Unable to set tags for Glue crawler {module.params.get('name')}")
return changed
def create_or_update_glue_crawler(connection, module, glue_crawler):
- '''
+ """
Create or update an AWS Glue crawler
- '''
+ """
changed = False
params = dict()
- params['Name'] = module.params.get('name')
- params['Role'] = module.params.get('role')
- params['Targets'] = module.params.get('targets')
- if module.params.get('database_name') is not None:
- params['DatabaseName'] = module.params.get('database_name')
- if module.params.get('description') is not None:
- params['Description'] = module.params.get('description')
- if module.params.get('recrawl_policy') is not None:
- params['RecrawlPolicy'] = snake_dict_to_camel_dict(module.params.get('recrawl_policy'), capitalize_first=True)
- if module.params.get('role') is not None:
- params['Role'] = module.params.get('role')
- if module.params.get('schema_change_policy') is not None:
- params['SchemaChangePolicy'] = snake_dict_to_camel_dict(module.params.get('schema_change_policy'), capitalize_first=True)
- if module.params.get('table_prefix') is not None:
- params['TablePrefix'] = module.params.get('table_prefix')
- if module.params.get('targets') is not None:
- params['Targets'] = module.params.get('targets')
+ params["Name"] = module.params.get("name")
+ params["Role"] = module.params.get("role")
+ params["Targets"] = module.params.get("targets")
+ if module.params.get("database_name") is not None:
+ params["DatabaseName"] = module.params.get("database_name")
+ if module.params.get("description") is not None:
+ params["Description"] = module.params.get("description")
+ if module.params.get("recrawl_policy") is not None:
+ params["RecrawlPolicy"] = snake_dict_to_camel_dict(module.params.get("recrawl_policy"), capitalize_first=True)
+ if module.params.get("role") is not None:
+ params["Role"] = module.params.get("role")
+ if module.params.get("schema_change_policy") is not None:
+ params["SchemaChangePolicy"] = snake_dict_to_camel_dict(
+ module.params.get("schema_change_policy"), capitalize_first=True
+ )
+ if module.params.get("table_prefix") is not None:
+ params["TablePrefix"] = module.params.get("table_prefix")
+ if module.params.get("targets") is not None:
+ params["Targets"] = module.params.get("targets")
if glue_crawler:
if _compare_glue_crawler_params(params, glue_crawler):
@@ -356,23 +381,26 @@ def create_or_update_glue_crawler(connection, module, glue_crawler):
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e)
- glue_crawler = _get_glue_crawler(connection, module, params['Name'])
+ glue_crawler = _get_glue_crawler(connection, module, params["Name"])
changed |= ensure_tags(connection, module, glue_crawler)
- module.exit_json(changed=changed, **camel_dict_to_snake_dict(glue_crawler or {}, ignore_list=['SchemaChangePolicy', 'RecrawlPolicy', 'Targets']))
+ module.exit_json(
+ changed=changed,
+ **camel_dict_to_snake_dict(glue_crawler or {}, ignore_list=["SchemaChangePolicy", "RecrawlPolicy", "Targets"]),
+ )
def delete_glue_crawler(connection, module, glue_crawler):
- '''
+ """
Delete an AWS Glue crawler
- '''
+ """
changed = False
if glue_crawler:
try:
if not module.check_mode:
- connection.delete_crawler(aws_retry=True, Name=glue_crawler['Name'])
+ connection.delete_crawler(aws_retry=True, Name=glue_crawler["Name"])
changed = True
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e)
@@ -381,46 +409,39 @@ def delete_glue_crawler(connection, module, glue_crawler):
def main():
-
- argument_spec = (
- dict(
- database_name=dict(type='str'),
- description=dict(type='str'),
- name=dict(required=True, type='str'),
- purge_tags=dict(type='bool', default=True),
- recrawl_policy=dict(type='dict', options=dict(
- recrawl_behavior=dict(type='str')
- )),
- role=dict(type='str'),
- schema_change_policy=dict(type='dict', options=dict(
- delete_behavior=dict(type='str'),
- update_behavior=dict(type='str')
- )),
- state=dict(required=True, choices=['present', 'absent'], type='str'),
- table_prefix=dict(type='str'),
- tags=dict(type='dict', aliases=['resource_tags']),
- targets=dict(type='dict')
- )
+ argument_spec = dict(
+ database_name=dict(type="str"),
+ description=dict(type="str"),
+ name=dict(required=True, type="str"),
+ purge_tags=dict(type="bool", default=True),
+ recrawl_policy=dict(type="dict", options=dict(recrawl_behavior=dict(type="str"))),
+ role=dict(type="str"),
+ schema_change_policy=dict(
+ type="dict", options=dict(delete_behavior=dict(type="str"), update_behavior=dict(type="str"))
+ ),
+ state=dict(required=True, choices=["present", "absent"], type="str"),
+ table_prefix=dict(type="str"),
+ tags=dict(type="dict", aliases=["resource_tags"]),
+ targets=dict(type="dict"),
)
- module = AnsibleAWSModule(argument_spec=argument_spec,
- required_if=[
- ('state', 'present', ['role', 'targets'])
- ],
- supports_check_mode=True
- )
+ module = AnsibleAWSModule(
+ argument_spec=argument_spec,
+ required_if=[("state", "present", ["role", "targets"])],
+ supports_check_mode=True,
+ )
- connection = module.client('glue', retry_decorator=AWSRetry.jittered_backoff(retries=10))
+ connection = module.client("glue", retry_decorator=AWSRetry.jittered_backoff(retries=10))
- state = module.params.get('state')
+ state = module.params.get("state")
- glue_crawler = _get_glue_crawler(connection, module, module.params.get('name'))
+ glue_crawler = _get_glue_crawler(connection, module, module.params.get("name"))
- if state == 'present':
+ if state == "present":
create_or_update_glue_crawler(connection, module, glue_crawler)
else:
delete_glue_crawler(connection, module, glue_crawler)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/glue_job.py b/ansible_collections/community/aws/plugins/modules/glue_job.py
index 47d6156d7..256779975 100644
--- a/ansible_collections/community/aws/plugins/modules/glue_job.py
+++ b/ansible_collections/community/aws/plugins/modules/glue_job.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: (c) 2018, Rob White (@wimnat)
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: glue_job
version_added: 1.0.0
@@ -103,13 +101,13 @@ options:
notes:
- Support for I(tags) and I(purge_tags) was added in release 2.2.0.
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
- - amazon.aws.boto3
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.tags
-'''
+ - amazon.aws.boto3
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide for details.
# Create an AWS Glue job
@@ -126,9 +124,9 @@ EXAMPLES = r'''
- community.aws.glue_job:
name: my-glue-job
state: absent
-'''
+"""
-RETURN = r'''
+RETURN = r"""
allocated_capacity:
description: The number of AWS Glue data processing units (DPUs) allocated to runs of this job. From 2 to
100 DPUs can be allocated; the default is 10. A DPU is a relative measure of processing power
@@ -223,10 +221,10 @@ timeout:
returned: when state is present
type: int
sample: 300
-'''
+"""
-# Non-ansible imports
import copy
+
try:
import botocore
except ImportError:
@@ -234,11 +232,12 @@ except ImportError:
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import compare_aws_tags
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
from ansible_collections.amazon.aws.plugins.module_utils.iam import get_aws_account_info
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import compare_aws_tags
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def _get_glue_job(connection, module, glue_job_name):
@@ -251,10 +250,13 @@ def _get_glue_job(connection, module, glue_job_name):
:return: boto3 Glue job dict or None if not found
"""
try:
- return connection.get_job(aws_retry=True, JobName=glue_job_name)['Job']
- except is_boto3_error_code('EntityNotFoundException'):
+ return connection.get_job(aws_retry=True, JobName=glue_job_name)["Job"]
+ except is_boto3_error_code("EntityNotFoundException"):
return None
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
module.fail_json_aws(e)
@@ -269,39 +271,43 @@ def _compare_glue_job_params(user_params, current_params):
# Weirdly, boto3 doesn't return some keys if the value is empty e.g. Description
# To counter this, add the key if it's missing with a blank value
- if 'Description' not in current_params:
- current_params['Description'] = ""
- if 'DefaultArguments' not in current_params:
- current_params['DefaultArguments'] = dict()
+ if "Description" not in current_params:
+ current_params["Description"] = ""
+ if "DefaultArguments" not in current_params:
+ current_params["DefaultArguments"] = dict()
- if 'AllocatedCapacity' in user_params and user_params['AllocatedCapacity'] != current_params['AllocatedCapacity']:
+ if "AllocatedCapacity" in user_params and user_params["AllocatedCapacity"] != current_params["AllocatedCapacity"]:
return True
- if 'Command' in user_params:
- if user_params['Command']['ScriptLocation'] != current_params['Command']['ScriptLocation']:
+ if "Command" in user_params:
+ if user_params["Command"]["ScriptLocation"] != current_params["Command"]["ScriptLocation"]:
return True
- if user_params['Command']['PythonVersion'] != current_params['Command']['PythonVersion']:
+ if user_params["Command"]["PythonVersion"] != current_params["Command"]["PythonVersion"]:
return True
- if 'Connections' in user_params and user_params['Connections'] != current_params['Connections']:
+ if "Connections" in user_params and user_params["Connections"] != current_params["Connections"]:
return True
- if 'DefaultArguments' in user_params and user_params['DefaultArguments'] != current_params['DefaultArguments']:
+ if "DefaultArguments" in user_params and user_params["DefaultArguments"] != current_params["DefaultArguments"]:
return True
- if 'Description' in user_params and user_params['Description'] != current_params['Description']:
+ if "Description" in user_params and user_params["Description"] != current_params["Description"]:
return True
- if 'ExecutionProperty' in user_params and user_params['ExecutionProperty']['MaxConcurrentRuns'] != current_params['ExecutionProperty']['MaxConcurrentRuns']:
+ if (
+ "ExecutionProperty" in user_params
+ and user_params["ExecutionProperty"]["MaxConcurrentRuns"]
+ != current_params["ExecutionProperty"]["MaxConcurrentRuns"]
+ ):
return True
- if 'GlueVersion' in user_params and user_params['GlueVersion'] != current_params['GlueVersion']:
+ if "GlueVersion" in user_params and user_params["GlueVersion"] != current_params["GlueVersion"]:
return True
- if 'MaxRetries' in user_params and user_params['MaxRetries'] != current_params['MaxRetries']:
+ if "MaxRetries" in user_params and user_params["MaxRetries"] != current_params["MaxRetries"]:
return True
- if 'Role' in user_params and user_params['Role'] != current_params['Role']:
+ if "Role" in user_params and user_params["Role"] != current_params["Role"]:
return True
- if 'Timeout' in user_params and user_params['Timeout'] != current_params['Timeout']:
+ if "Timeout" in user_params and user_params["Timeout"] != current_params["Timeout"]:
return True
- if 'GlueVersion' in user_params and user_params['GlueVersion'] != current_params['GlueVersion']:
+ if "GlueVersion" in user_params and user_params["GlueVersion"] != current_params["GlueVersion"]:
return True
- if 'WorkerType' in user_params and user_params['WorkerType'] != current_params['WorkerType']:
+ if "WorkerType" in user_params and user_params["WorkerType"] != current_params["WorkerType"]:
return True
- if 'NumberOfWorkers' in user_params and user_params['NumberOfWorkers'] != current_params['NumberOfWorkers']:
+ if "NumberOfWorkers" in user_params and user_params["NumberOfWorkers"] != current_params["NumberOfWorkers"]:
return True
return False
@@ -310,21 +316,23 @@ def _compare_glue_job_params(user_params, current_params):
def ensure_tags(connection, module, glue_job):
changed = False
- if module.params.get('tags') is None:
+ if module.params.get("tags") is None:
return False
account_id, partition = get_aws_account_info(module)
- arn = 'arn:{0}:glue:{1}:{2}:job/{3}'.format(partition, module.region, account_id, module.params.get('name'))
+ arn = f"arn:{partition}:glue:{module.region}:{account_id}:job/{module.params.get('name')}"
try:
- existing_tags = connection.get_tags(aws_retry=True, ResourceArn=arn).get('Tags', {})
+ existing_tags = connection.get_tags(aws_retry=True, ResourceArn=arn).get("Tags", {})
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
if module.check_mode:
existing_tags = {}
else:
- module.fail_json_aws(e, msg='Unable to get tags for Glue job %s' % module.params.get('name'))
+ module.fail_json_aws(e, msg=f"Unable to get tags for Glue job {module.params.get('name')}")
- tags_to_add, tags_to_remove = compare_aws_tags(existing_tags, module.params.get('tags'), module.params.get('purge_tags'))
+ tags_to_add, tags_to_remove = compare_aws_tags(
+ existing_tags, module.params.get("tags"), module.params.get("purge_tags")
+ )
if tags_to_remove:
changed = True
@@ -332,7 +340,7 @@ def ensure_tags(connection, module, glue_job):
try:
connection.untag_resource(aws_retry=True, ResourceArn=arn, TagsToRemove=tags_to_remove)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Unable to set tags for Glue job %s' % module.params.get('name'))
+ module.fail_json_aws(e, msg=f"Unable to set tags for Glue job {module.params.get('name')}")
if tags_to_add:
changed = True
@@ -340,7 +348,7 @@ def ensure_tags(connection, module, glue_job):
try:
connection.tag_resource(aws_retry=True, ResourceArn=arn, TagsToAdd=tags_to_add)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Unable to set tags for Glue job %s' % module.params.get('name'))
+ module.fail_json_aws(e, msg=f"Unable to set tags for Glue job {module.params.get('name')}")
return changed
@@ -357,42 +365,45 @@ def create_or_update_glue_job(connection, module, glue_job):
changed = False
params = dict()
- params['Name'] = module.params.get("name")
- params['Role'] = module.params.get("role")
+ params["Name"] = module.params.get("name")
+ params["Role"] = module.params.get("role")
if module.params.get("allocated_capacity") is not None:
- params['AllocatedCapacity'] = module.params.get("allocated_capacity")
+ params["AllocatedCapacity"] = module.params.get("allocated_capacity")
if module.params.get("command_script_location") is not None:
- params['Command'] = {'Name': module.params.get("command_name"), 'ScriptLocation': module.params.get("command_script_location")}
+ params["Command"] = {
+ "Name": module.params.get("command_name"),
+ "ScriptLocation": module.params.get("command_script_location"),
+ }
if module.params.get("command_python_version") is not None:
- params['Command']['PythonVersion'] = module.params.get("command_python_version")
+ params["Command"]["PythonVersion"] = module.params.get("command_python_version")
if module.params.get("connections") is not None:
- params['Connections'] = {'Connections': module.params.get("connections")}
+ params["Connections"] = {"Connections": module.params.get("connections")}
if module.params.get("default_arguments") is not None:
- params['DefaultArguments'] = module.params.get("default_arguments")
+ params["DefaultArguments"] = module.params.get("default_arguments")
if module.params.get("description") is not None:
- params['Description'] = module.params.get("description")
+ params["Description"] = module.params.get("description")
if module.params.get("glue_version") is not None:
- params['GlueVersion'] = module.params.get("glue_version")
+ params["GlueVersion"] = module.params.get("glue_version")
if module.params.get("max_concurrent_runs") is not None:
- params['ExecutionProperty'] = {'MaxConcurrentRuns': module.params.get("max_concurrent_runs")}
+ params["ExecutionProperty"] = {"MaxConcurrentRuns": module.params.get("max_concurrent_runs")}
if module.params.get("max_retries") is not None:
- params['MaxRetries'] = module.params.get("max_retries")
+ params["MaxRetries"] = module.params.get("max_retries")
if module.params.get("timeout") is not None:
- params['Timeout'] = module.params.get("timeout")
+ params["Timeout"] = module.params.get("timeout")
if module.params.get("glue_version") is not None:
- params['GlueVersion'] = module.params.get("glue_version")
+ params["GlueVersion"] = module.params.get("glue_version")
if module.params.get("worker_type") is not None:
- params['WorkerType'] = module.params.get("worker_type")
+ params["WorkerType"] = module.params.get("worker_type")
if module.params.get("number_of_workers") is not None:
- params['NumberOfWorkers'] = module.params.get("number_of_workers")
+ params["NumberOfWorkers"] = module.params.get("number_of_workers")
# If glue_job is not None then check if it needs to be modified, else create it
if glue_job:
if _compare_glue_job_params(params, glue_job):
try:
# Update job needs slightly modified params
- update_params = {'JobName': params['Name'], 'JobUpdate': copy.deepcopy(params)}
- del update_params['JobUpdate']['Name']
+ update_params = {"JobName": params["Name"], "JobUpdate": copy.deepcopy(params)}
+ del update_params["JobUpdate"]["Name"]
if not module.check_mode:
connection.update_job(aws_retry=True, **update_params)
changed = True
@@ -406,11 +417,11 @@ def create_or_update_glue_job(connection, module, glue_job):
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e)
- glue_job = _get_glue_job(connection, module, params['Name'])
+ glue_job = _get_glue_job(connection, module, params["Name"])
changed |= ensure_tags(connection, module, glue_job)
- module.exit_json(changed=changed, **camel_dict_to_snake_dict(glue_job or {}, ignore_list=['DefaultArguments']))
+ module.exit_json(changed=changed, **camel_dict_to_snake_dict(glue_job or {}, ignore_list=["DefaultArguments"]))
def delete_glue_job(connection, module, glue_job):
@@ -427,7 +438,7 @@ def delete_glue_job(connection, module, glue_job):
if glue_job:
try:
if not module.check_mode:
- connection.delete_job(aws_retry=True, JobName=glue_job['Name'])
+ connection.delete_job(aws_retry=True, JobName=glue_job["Name"])
changed = True
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e)
@@ -436,49 +447,45 @@ def delete_glue_job(connection, module, glue_job):
def main():
-
- argument_spec = (
- dict(
- allocated_capacity=dict(type='int'),
- command_name=dict(type='str', default='glueetl'),
- command_python_version=dict(type='str'),
- command_script_location=dict(type='str'),
- connections=dict(type='list', elements='str'),
- default_arguments=dict(type='dict'),
- description=dict(type='str'),
- glue_version=dict(type='str'),
- max_concurrent_runs=dict(type='int'),
- max_retries=dict(type='int'),
- name=dict(required=True, type='str'),
- number_of_workers=dict(type='int'),
- purge_tags=dict(type='bool', default=True),
- role=dict(type='str'),
- state=dict(required=True, choices=['present', 'absent'], type='str'),
- tags=dict(type='dict', aliases=['resource_tags']),
- timeout=dict(type='int'),
- worker_type=dict(choices=['Standard', 'G.1X', 'G.2X'], type='str'),
- )
+ argument_spec = dict(
+ allocated_capacity=dict(type="int"),
+ command_name=dict(type="str", default="glueetl"),
+ command_python_version=dict(type="str"),
+ command_script_location=dict(type="str"),
+ connections=dict(type="list", elements="str"),
+ default_arguments=dict(type="dict"),
+ description=dict(type="str"),
+ glue_version=dict(type="str"),
+ max_concurrent_runs=dict(type="int"),
+ max_retries=dict(type="int"),
+ name=dict(required=True, type="str"),
+ number_of_workers=dict(type="int"),
+ purge_tags=dict(type="bool", default=True),
+ role=dict(type="str"),
+ state=dict(required=True, choices=["present", "absent"], type="str"),
+ tags=dict(type="dict", aliases=["resource_tags"]),
+ timeout=dict(type="int"),
+ worker_type=dict(choices=["Standard", "G.1X", "G.2X"], type="str"),
)
- module = AnsibleAWSModule(argument_spec=argument_spec,
- required_if=[
- ('state', 'present', ['role', 'command_script_location'])
- ],
- supports_check_mode=True
- )
+ module = AnsibleAWSModule(
+ argument_spec=argument_spec,
+ required_if=[("state", "present", ["role", "command_script_location"])],
+ supports_check_mode=True,
+ )
retry_decorator = AWSRetry.jittered_backoff(retries=10)
- connection = module.client('glue', retry_decorator=retry_decorator)
+ connection = module.client("glue", retry_decorator=retry_decorator)
state = module.params.get("state")
glue_job = _get_glue_job(connection, module, module.params.get("name"))
- if state == 'present':
+ if state == "present":
create_or_update_glue_job(connection, module, glue_job)
else:
delete_glue_job(connection, module, glue_job)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/iam_access_key.py b/ansible_collections/community/aws/plugins/modules/iam_access_key.py
deleted file mode 100644
index ad61b5b2a..000000000
--- a/ansible_collections/community/aws/plugins/modules/iam_access_key.py
+++ /dev/null
@@ -1,317 +0,0 @@
-#!/usr/bin/python
-# Copyright (c) 2021 Ansible Project
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
----
-module: iam_access_key
-version_added: 2.1.0
-short_description: Manage AWS IAM User access keys
-description:
- - Manage AWS IAM user access keys.
-author: Mark Chappell (@tremble)
-options:
- user_name:
- description:
- - The name of the IAM User to which the key belongs.
- required: true
- type: str
- aliases: ['username']
- id:
- description:
- - The ID of the access key.
- - Required when I(state=absent).
- - Mutually exclusive with I(rotate_keys).
- required: false
- type: str
- state:
- description:
- - Create or remove the access key.
- - When I(state=present) and I(id) is not defined a new key will be created.
- required: false
- type: str
- default: 'present'
- choices: [ 'present', 'absent' ]
- active:
- description:
- - Whether the key should be enabled or disabled.
- - Defaults to C(true) when creating a new key.
- required: false
- type: bool
- aliases: ['enabled']
- rotate_keys:
- description:
- - When there are already 2 access keys attached to the IAM user the oldest
- key will be removed and a new key created.
- - Ignored if I(state=absent)
- - Mutually exclusive with I(id).
- required: false
- type: bool
- default: false
-
-extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
-'''
-
-EXAMPLES = r'''
-# Note: These examples do not set authentication details, see the AWS Guide for details.
-
-- name: Create a new access key
- community.aws.iam_access_key:
- user_name: example_user
- state: present
-
-- name: Delete the access_key
- community.aws.iam_access_key:
- user_name: example_user
- id: AKIA1EXAMPLE1EXAMPLE
- state: absent
-'''
-
-RETURN = r'''
-access_key:
- description: A dictionary containing all the access key information.
- returned: When the key exists.
- type: complex
- contains:
- access_key_id:
- description: The ID for the access key.
- returned: success
- type: str
- sample: AKIA1EXAMPLE1EXAMPLE
- create_date:
- description: The date and time, in ISO 8601 date-time format, when the access key was created.
- returned: success
- type: str
- sample: "2021-10-09T13:25:42+00:00"
- user_name:
- description: The name of the IAM user to which the key is attached.
- returned: success
- type: str
- sample: example_user
- status:
- description:
- - The status of the key.
- - C(Active) means it can be used.
- - C(Inactive) means it can not be used.
- returned: success
- type: str
- sample: Inactive
-secret_access_key:
- description:
- - The secret access key.
- - A secret access key is the equivalent of a password which can not be changed and as such should be considered sensitive data.
- - Secret access keys can only be accessed at creation time.
- returned: When a new key is created.
- type: str
- sample: example/Example+EXAMPLE+example/Example
-deleted_access_key_id:
- description:
- - The access key deleted during rotation.
- returned: When a key was deleted during the rotation of access keys
- type: str
- sample: AKIA1EXAMPLE1EXAMPLE
-'''
-
-try:
- import botocore
-except ImportError:
- pass # caught by AnsibleAWSModule
-
-from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.core import normalize_boto3_result
-from ansible_collections.amazon.aws.plugins.module_utils.core import scrub_none_parameters
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-
-
-def delete_access_key(access_keys, user, access_key_id):
- if not access_key_id:
- return False
-
- if access_key_id not in access_keys:
- return False
-
- if module.check_mode:
- return True
-
- try:
- client.delete_access_key(
- aws_retry=True,
- UserName=user,
- AccessKeyId=access_key_id,
- )
- except is_boto3_error_code('NoSuchEntityException'):
- # Generally occurs when race conditions have happened and someone
- # deleted the key while we were checking to see if it existed.
- return False
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(
- e, msg='Failed to delete access key "{0}" for user "{1}"'.format(access_key_id, user)
- )
-
- return True
-
-
-def update_access_key(access_keys, user, access_key_id, enabled):
- if access_key_id not in access_keys:
- module.fail_json(
- msg='Access key "{0}" not found attached to User "{1}"'.format(access_key_id, user),
- )
-
- changes = dict()
- access_key = access_keys.get(access_key_id)
-
- if enabled is not None:
- desired_status = 'Active' if enabled else 'Inactive'
- if access_key.get('status') != desired_status:
- changes['Status'] = desired_status
-
- if not changes:
- return False
-
- if module.check_mode:
- return True
-
- try:
- client.update_access_key(
- aws_retry=True,
- UserName=user,
- AccessKeyId=access_key_id,
- **changes
- )
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(
- e, changes=changes,
- msg='Failed to update access key "{0}" for user "{1}"'.format(access_key_id, user),
- )
- return True
-
-
-def create_access_key(access_keys, user, rotate_keys, enabled):
- changed = False
- oldest_key = False
-
- if len(access_keys) > 1 and rotate_keys:
- sorted_keys = sorted(list(access_keys), key=lambda k: access_keys[k].get('create_date', None))
- oldest_key = sorted_keys[0]
- changed |= delete_access_key(access_keys, user, oldest_key)
-
- if module.check_mode:
- if changed:
- return dict(deleted_access_key=oldest_key)
- return True
-
- try:
- results = client.create_access_key(aws_retry=True, UserName=user)
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to create access key for user "{0}"'.format(user))
- results = camel_dict_to_snake_dict(results)
- access_key = results.get('access_key')
- access_key = normalize_boto3_result(access_key)
-
- # Update settings which can't be managed on creation
- if enabled is False:
- access_key_id = access_key['access_key_id']
- access_keys = {access_key_id: access_key}
- update_access_key(access_keys, user, access_key_id, enabled)
- access_key['status'] = 'Inactive'
-
- if oldest_key:
- access_key['deleted_access_key'] = oldest_key
-
- return access_key
-
-
-def get_access_keys(user):
- try:
- results = client.list_access_keys(aws_retry=True, UserName=user)
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(
- e, msg='Failed to get access keys for user "{0}"'.format(user)
- )
- if not results:
- return None
-
- results = camel_dict_to_snake_dict(results)
- access_keys = results.get('access_key_metadata', [])
- if not access_keys:
- return []
-
- access_keys = normalize_boto3_result(access_keys)
- access_keys = {k['access_key_id']: k for k in access_keys}
- return access_keys
-
-
-def main():
-
- global module
- global client
-
- argument_spec = dict(
- user_name=dict(required=True, type='str', aliases=['username']),
- id=dict(required=False, type='str'),
- state=dict(required=False, choices=['present', 'absent'], default='present'),
- active=dict(required=False, type='bool', aliases=['enabled']),
- rotate_keys=dict(required=False, type='bool', default=False),
- )
-
- required_if = [
- ['state', 'absent', ('id')],
- ]
- mutually_exclusive = [
- ['rotate_keys', 'id'],
- ]
-
- module = AnsibleAWSModule(
- argument_spec=argument_spec,
- supports_check_mode=True
- )
-
- client = module.client('iam', retry_decorator=AWSRetry.jittered_backoff())
-
- changed = False
- state = module.params.get('state')
- user = module.params.get('user_name')
- access_key_id = module.params.get('id')
- rotate_keys = module.params.get('rotate_keys')
- enabled = module.params.get('active')
-
- access_keys = get_access_keys(user)
- results = dict()
-
- if state == 'absent':
- changed |= delete_access_key(access_keys, user, access_key_id)
- else:
- # If we have an ID then we should try to update it
- if access_key_id:
- changed |= update_access_key(access_keys, user, access_key_id, enabled)
- access_keys = get_access_keys(user)
- results['access_key'] = access_keys.get(access_key_id, None)
- # Otherwise we try to create a new one
- else:
- secret_key = create_access_key(access_keys, user, rotate_keys, enabled)
- if isinstance(secret_key, bool):
- changed |= secret_key
- else:
- changed = True
- results['access_key_id'] = secret_key.get('access_key_id', None)
- results['secret_access_key'] = secret_key.pop('secret_access_key', None)
- results['deleted_access_key_id'] = secret_key.pop('deleted_access_key', None)
- if secret_key:
- results['access_key'] = secret_key
- results = scrub_none_parameters(results)
-
- module.exit_json(changed=changed, **results)
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/aws/plugins/modules/iam_access_key_info.py b/ansible_collections/community/aws/plugins/modules/iam_access_key_info.py
deleted file mode 100644
index 91429eff9..000000000
--- a/ansible_collections/community/aws/plugins/modules/iam_access_key_info.py
+++ /dev/null
@@ -1,128 +0,0 @@
-#!/usr/bin/python
-# Copyright (c) 2021 Ansible Project
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
----
-module: iam_access_key_info
-version_added: 2.1.0
-short_description: fetch information about AWS IAM User access keys
-description:
- - 'Fetches information AWS IAM user access keys.'
- - 'Note: It is not possible to fetch the secret access key.'
-author: Mark Chappell (@tremble)
-options:
- user_name:
- description:
- - The name of the IAM User to which the keys belong.
- required: true
- type: str
- aliases: ['username']
-
-extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
-'''
-
-EXAMPLES = r'''
-# Note: These examples do not set authentication details, see the AWS Guide for details.
-
-- name: Fetch Access keys for a user
- community.aws.iam_access_key_info:
- user_name: example_user
-'''
-
-RETURN = r'''
-access_key:
- description: A dictionary containing all the access key information.
- returned: When the key exists.
- type: list
- elements: dict
- contains:
- access_key_id:
- description: The ID for the access key.
- returned: success
- type: str
- sample: AKIA1EXAMPLE1EXAMPLE
- create_date:
- description: The date and time, in ISO 8601 date-time format, when the access key was created.
- returned: success
- type: str
- sample: "2021-10-09T13:25:42+00:00"
- user_name:
- description: The name of the IAM user to which the key is attached.
- returned: success
- type: str
- sample: example_user
- status:
- description:
- - The status of the key.
- - C(Active) means it can be used.
- - C(Inactive) means it can not be used.
- returned: success
- type: str
- sample: Inactive
-'''
-
-try:
- import botocore
-except ImportError:
- pass # caught by AnsibleAWSModule
-
-from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import normalize_boto3_result
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-
-
-def get_access_keys(user):
- try:
- results = client.list_access_keys(aws_retry=True, UserName=user)
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(
- e, msg='Failed to get access keys for user "{0}"'.format(user)
- )
- if not results:
- return None
-
- results = camel_dict_to_snake_dict(results)
- access_keys = results.get('access_key_metadata', [])
- if not access_keys:
- return []
-
- access_keys = normalize_boto3_result(access_keys)
- access_keys = sorted(access_keys, key=lambda d: d.get('create_date', None))
- return access_keys
-
-
-def main():
-
- global module
- global client
-
- argument_spec = dict(
- user_name=dict(required=True, type='str', aliases=['username']),
- )
-
- module = AnsibleAWSModule(
- argument_spec=argument_spec,
- supports_check_mode=True
- )
-
- client = module.client('iam', retry_decorator=AWSRetry.jittered_backoff())
-
- changed = False
- user = module.params.get('user_name')
- access_keys = get_access_keys(user)
-
- module.exit_json(changed=changed, access_keys=access_keys)
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/aws/plugins/modules/iam_group.py b/ansible_collections/community/aws/plugins/modules/iam_group.py
deleted file mode 100644
index 31987ef1d..000000000
--- a/ansible_collections/community/aws/plugins/modules/iam_group.py
+++ /dev/null
@@ -1,433 +0,0 @@
-#!/usr/bin/python
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
----
-module: iam_group
-version_added: 1.0.0
-short_description: Manage AWS IAM groups
-description:
- - Manage AWS IAM groups.
-author:
-- Nick Aslanidis (@naslanidis)
-- Maksym Postument (@infectsoldier)
-options:
- name:
- description:
- - The name of the group to create.
- required: true
- type: str
- managed_policies:
- description:
- - A list of managed policy ARNs or friendly names to attach to the role.
- - To embed an inline policy, use M(community.aws.iam_policy).
- required: false
- type: list
- elements: str
- default: []
- aliases: ['managed_policy']
- users:
- description:
- - A list of existing users to add as members of the group.
- required: false
- type: list
- elements: str
- default: []
- state:
- description:
- - Create or remove the IAM group.
- required: true
- choices: [ 'present', 'absent' ]
- type: str
- purge_policies:
- description:
- - When I(purge_policies=true) any managed policies not listed in I(managed_policies) will be detatched.
- required: false
- default: false
- type: bool
- aliases: ['purge_policy', 'purge_managed_policies']
- purge_users:
- description:
- - When I(purge_users=true) users which are not included in I(users) will be detached.
- required: false
- default: false
- type: bool
-extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
-'''
-
-EXAMPLES = r'''
-# Note: These examples do not set authentication details, see the AWS Guide for details.
-
-- name: Create a group
- community.aws.iam_group:
- name: testgroup1
- state: present
-
-- name: Create a group and attach a managed policy using its ARN
- community.aws.iam_group:
- name: testgroup1
- managed_policies:
- - arn:aws:iam::aws:policy/AmazonSNSFullAccess
- state: present
-
-- name: Create a group with users as members and attach a managed policy using its ARN
- community.aws.iam_group:
- name: testgroup1
- managed_policies:
- - arn:aws:iam::aws:policy/AmazonSNSFullAccess
- users:
- - test_user1
- - test_user2
- state: present
-
-- name: Remove all managed policies from an existing group with an empty list
- community.aws.iam_group:
- name: testgroup1
- state: present
- purge_policies: true
-
-- name: Remove all group members from an existing group
- community.aws.iam_group:
- name: testgroup1
- managed_policies:
- - arn:aws:iam::aws:policy/AmazonSNSFullAccess
- purge_users: true
- state: present
-
-- name: Delete the group
- community.aws.iam_group:
- name: testgroup1
- state: absent
-
-'''
-RETURN = r'''
-iam_group:
- description: dictionary containing all the group information including group membership
- returned: success
- type: complex
- contains:
- group:
- description: dictionary containing all the group information
- returned: success
- type: complex
- contains:
- arn:
- description: the Amazon Resource Name (ARN) specifying the group
- type: str
- sample: "arn:aws:iam::1234567890:group/testgroup1"
- create_date:
- description: the date and time, in ISO 8601 date-time format, when the group was created
- type: str
- sample: "2017-02-08T04:36:28+00:00"
- group_id:
- description: the stable and unique string identifying the group
- type: str
- sample: AGPA12345EXAMPLE54321
- group_name:
- description: the friendly name that identifies the group
- type: str
- sample: testgroup1
- path:
- description: the path to the group
- type: str
- sample: /
- users:
- description: list containing all the group members
- returned: success
- type: complex
- contains:
- arn:
- description: the Amazon Resource Name (ARN) specifying the user
- type: str
- sample: "arn:aws:iam::1234567890:user/test_user1"
- create_date:
- description: the date and time, in ISO 8601 date-time format, when the user was created
- type: str
- sample: "2017-02-08T04:36:28+00:00"
- user_id:
- description: the stable and unique string identifying the user
- type: str
- sample: AIDA12345EXAMPLE54321
- user_name:
- description: the friendly name that identifies the user
- type: str
- sample: testgroup1
- path:
- description: the path to the user
- type: str
- sample: /
-'''
-
-try:
- import botocore
-except ImportError:
- pass # caught by AnsibleAWSModule
-
-from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-
-
-def compare_attached_group_policies(current_attached_policies, new_attached_policies):
-
- # If new_attached_policies is None it means we want to remove all policies
- if len(current_attached_policies) > 0 and new_attached_policies is None:
- return False
-
- current_attached_policies_arn_list = []
- for policy in current_attached_policies:
- current_attached_policies_arn_list.append(policy['PolicyArn'])
-
- if set(current_attached_policies_arn_list) == set(new_attached_policies):
- return True
- else:
- return False
-
-
-def compare_group_members(current_group_members, new_group_members):
-
- # If new_attached_policies is None it means we want to remove all policies
- if len(current_group_members) > 0 and new_group_members is None:
- return False
- if set(current_group_members) == set(new_group_members):
- return True
- else:
- return False
-
-
-def convert_friendly_names_to_arns(connection, module, policy_names):
-
- if not any(not policy.startswith('arn:') for policy in policy_names if policy is not None):
- return policy_names
- allpolicies = {}
- paginator = connection.get_paginator('list_policies')
- policies = paginator.paginate().build_full_result()['Policies']
-
- for policy in policies:
- allpolicies[policy['PolicyName']] = policy['Arn']
- allpolicies[policy['Arn']] = policy['Arn']
- try:
- return [allpolicies[policy] for policy in policy_names]
- except KeyError as e:
- module.fail_json(msg="Couldn't find policy: " + str(e))
-
-
-def create_or_update_group(connection, module):
-
- params = dict()
- params['GroupName'] = module.params.get('name')
- managed_policies = module.params.get('managed_policies')
- users = module.params.get('users')
- purge_users = module.params.get('purge_users')
- purge_policies = module.params.get('purge_policies')
- changed = False
- if managed_policies:
- managed_policies = convert_friendly_names_to_arns(connection, module, managed_policies)
-
- # Get group
- try:
- group = get_group(connection, module, params['GroupName'])
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Couldn't get group")
-
- # If group is None, create it
- if group is None:
- # Check mode means we would create the group
- if module.check_mode:
- module.exit_json(changed=True)
-
- try:
- group = connection.create_group(**params)
- changed = True
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Couldn't create group")
-
- # Manage managed policies
- current_attached_policies = get_attached_policy_list(connection, module, params['GroupName'])
- if not compare_attached_group_policies(current_attached_policies, managed_policies):
- current_attached_policies_arn_list = []
- for policy in current_attached_policies:
- current_attached_policies_arn_list.append(policy['PolicyArn'])
-
- # If managed_policies has a single empty element we want to remove all attached policies
- if purge_policies:
- # Detach policies not present
- for policy_arn in list(set(current_attached_policies_arn_list) - set(managed_policies)):
- changed = True
- if not module.check_mode:
- try:
- connection.detach_group_policy(GroupName=params['GroupName'], PolicyArn=policy_arn)
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Couldn't detach policy from group %s" % params['GroupName'])
- # If there are policies to adjust that aren't in the current list, then things have changed
- # Otherwise the only changes were in purging above
- if set(managed_policies) - set(current_attached_policies_arn_list):
- changed = True
- # If there are policies in managed_policies attach each policy
- if managed_policies != [None] and not module.check_mode:
- for policy_arn in managed_policies:
- try:
- connection.attach_group_policy(GroupName=params['GroupName'], PolicyArn=policy_arn)
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Couldn't attach policy to group %s" % params['GroupName'])
-
- # Manage group memberships
- try:
- current_group_members = get_group(connection, module, params['GroupName'])['Users']
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, "Couldn't get group %s" % params['GroupName'])
-
- current_group_members_list = []
- for member in current_group_members:
- current_group_members_list.append(member['UserName'])
-
- if not compare_group_members(current_group_members_list, users):
-
- if purge_users:
- for user in list(set(current_group_members_list) - set(users)):
- # Ensure we mark things have changed if any user gets purged
- changed = True
- # Skip actions for check mode
- if not module.check_mode:
- try:
- connection.remove_user_from_group(GroupName=params['GroupName'], UserName=user)
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Couldn't remove user %s from group %s" % (user, params['GroupName']))
- # If there are users to adjust that aren't in the current list, then things have changed
- # Otherwise the only changes were in purging above
- if set(users) - set(current_group_members_list):
- changed = True
- # Skip actions for check mode
- if users != [None] and not module.check_mode:
- for user in users:
- try:
- connection.add_user_to_group(GroupName=params['GroupName'], UserName=user)
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Couldn't add user %s to group %s" % (user, params['GroupName']))
- if module.check_mode:
- module.exit_json(changed=changed)
-
- # Get the group again
- try:
- group = get_group(connection, module, params['GroupName'])
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, "Couldn't get group %s" % params['GroupName'])
-
- module.exit_json(changed=changed, iam_group=camel_dict_to_snake_dict(group))
-
-
-def destroy_group(connection, module):
-
- params = dict()
- params['GroupName'] = module.params.get('name')
-
- try:
- group = get_group(connection, module, params['GroupName'])
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, "Couldn't get group %s" % params['GroupName'])
- if group:
- # Check mode means we would remove this group
- if module.check_mode:
- module.exit_json(changed=True)
-
- # Remove any attached policies otherwise deletion fails
- try:
- for policy in get_attached_policy_list(connection, module, params['GroupName']):
- connection.detach_group_policy(GroupName=params['GroupName'], PolicyArn=policy['PolicyArn'])
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Couldn't remove policy from group %s" % params['GroupName'])
-
- # Remove any users in the group otherwise deletion fails
- current_group_members_list = []
- try:
- current_group_members = get_group(connection, module, params['GroupName'])['Users']
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, "Couldn't get group %s" % params['GroupName'])
- for member in current_group_members:
- current_group_members_list.append(member['UserName'])
- for user in current_group_members_list:
- try:
- connection.remove_user_from_group(GroupName=params['GroupName'], UserName=user)
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, "Couldn't remove user %s from group %s" % (user, params['GroupName']))
-
- try:
- connection.delete_group(**params)
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, "Couldn't delete group %s" % params['GroupName'])
-
- else:
- module.exit_json(changed=False)
-
- module.exit_json(changed=True)
-
-
-@AWSRetry.exponential_backoff()
-def get_group(connection, module, name):
- try:
- paginator = connection.get_paginator('get_group')
- return paginator.paginate(GroupName=name).build_full_result()
- except is_boto3_error_code('NoSuchEntity'):
- return None
-
-
-@AWSRetry.exponential_backoff()
-def get_attached_policy_list(connection, module, name):
-
- try:
- paginator = connection.get_paginator('list_attached_group_policies')
- return paginator.paginate(GroupName=name).build_full_result()['AttachedPolicies']
- except is_boto3_error_code('NoSuchEntity'):
- return None
-
-
-def main():
-
- argument_spec = dict(
- name=dict(required=True),
- managed_policies=dict(default=[], type='list', aliases=['managed_policy'], elements='str'),
- users=dict(default=[], type='list', elements='str'),
- state=dict(choices=['present', 'absent'], required=True),
- purge_users=dict(default=False, type='bool'),
- purge_policies=dict(default=False, type='bool', aliases=['purge_policy', 'purge_managed_policies'])
- )
-
- module = AnsibleAWSModule(
- argument_spec=argument_spec,
- supports_check_mode=True
- )
-
- connection = module.client('iam')
-
- state = module.params.get("state")
-
- if state == 'present':
- create_or_update_group(connection, module)
- else:
- destroy_group(connection, module)
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/aws/plugins/modules/iam_managed_policy.py b/ansible_collections/community/aws/plugins/modules/iam_managed_policy.py
deleted file mode 100644
index f86f019d5..000000000
--- a/ansible_collections/community/aws/plugins/modules/iam_managed_policy.py
+++ /dev/null
@@ -1,371 +0,0 @@
-#!/usr/bin/python
-# Copyright: Ansible Project
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
----
-module: iam_managed_policy
-version_added: 1.0.0
-short_description: Manage User Managed IAM policies
-description:
- - Allows creating and removing managed IAM policies
-options:
- policy_name:
- description:
- - The name of the managed policy.
- required: True
- type: str
- policy_description:
- description:
- - A helpful description of this policy, this value is immutable and only set when creating a new policy.
- default: ''
- type: str
- policy:
- description:
- - A properly json formatted policy
- type: json
- make_default:
- description:
- - Make this revision the default revision.
- default: True
- type: bool
- only_version:
- description:
- - Remove all other non default revisions, if this is used with C(make_default) it will result in all other versions of this policy being deleted.
- type: bool
- default: false
- state:
- description:
- - Should this managed policy be present or absent. Set to absent to detach all entities from this policy and remove it if found.
- default: present
- choices: [ "present", "absent" ]
- type: str
-
-author: "Dan Kozlowski (@dkhenry)"
-extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
-'''
-
-EXAMPLES = r'''
-# Create a policy
-- name: Create IAM Managed Policy
- community.aws.iam_managed_policy:
- policy_name: "ManagedPolicy"
- policy_description: "A Helpful managed policy"
- policy: "{{ lookup('template', 'managed_policy.json.j2') }}"
- state: present
-
-# Update a policy with a new default version
-- name: Update an IAM Managed Policy with new default version
- community.aws.iam_managed_policy:
- policy_name: "ManagedPolicy"
- policy: "{{ lookup('file', 'managed_policy_update.json') }}"
- state: present
-
-# Update a policy with a new non default version
-- name: Update an IAM Managed Policy with a non default version
- community.aws.iam_managed_policy:
- policy_name: "ManagedPolicy"
- policy:
- Version: "2012-10-17"
- Statement:
- - Effect: "Allow"
- Action: "logs:CreateLogGroup"
- Resource: "*"
- make_default: false
- state: present
-
-# Update a policy and make it the only version and the default version
-- name: Update an IAM Managed Policy with default version as the only version
- community.aws.iam_managed_policy:
- policy_name: "ManagedPolicy"
- policy: |
- {
- "Version": "2012-10-17",
- "Statement":[{
- "Effect": "Allow",
- "Action": "logs:PutRetentionPolicy",
- "Resource": "*"
- }]
- }
- only_version: true
- state: present
-
-# Remove a policy
-- name: Remove an existing IAM Managed Policy
- community.aws.iam_managed_policy:
- policy_name: "ManagedPolicy"
- state: absent
-'''
-
-RETURN = r'''
-policy:
- description: Returns the policy json structure, when state == absent this will return the value of the removed policy.
- returned: success
- type: complex
- contains: {}
- sample: '{
- "arn": "arn:aws:iam::aws:policy/AdministratorAccess "
- "attachment_count": 0,
- "create_date": "2017-03-01T15:42:55.981000+00:00",
- "default_version_id": "v1",
- "is_attachable": true,
- "path": "/",
- "policy_id": "ANPA1245EXAMPLE54321",
- "policy_name": "AdministratorAccess",
- "update_date": "2017-03-01T15:42:55.981000+00:00"
- }'
-'''
-
-import json
-
-try:
- import botocore
-except ImportError:
- pass # Handled by AnsibleAWSModule
-
-from ansible.module_utils._text import to_native
-from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import compare_policies
-
-
-@AWSRetry.jittered_backoff(retries=5, delay=5, backoff=2.0)
-def list_policies_with_backoff():
- paginator = client.get_paginator('list_policies')
- return paginator.paginate(Scope='Local').build_full_result()
-
-
-def get_policy_by_name(name):
- try:
- response = list_policies_with_backoff()
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Couldn't list policies")
- for policy in response['Policies']:
- if policy['PolicyName'] == name:
- return policy
- return None
-
-
-def delete_oldest_non_default_version(policy):
- try:
- versions = [v for v in client.list_policy_versions(PolicyArn=policy['Arn'])['Versions']
- if not v['IsDefaultVersion']]
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Couldn't list policy versions")
- versions.sort(key=lambda v: v['CreateDate'], reverse=True)
- for v in versions[-1:]:
- try:
- client.delete_policy_version(PolicyArn=policy['Arn'], VersionId=v['VersionId'])
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Couldn't delete policy version")
-
-
-# This needs to return policy_version, changed
-def get_or_create_policy_version(policy, policy_document):
- try:
- versions = client.list_policy_versions(PolicyArn=policy['Arn'])['Versions']
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Couldn't list policy versions")
-
- for v in versions:
- try:
- document = client.get_policy_version(PolicyArn=policy['Arn'], VersionId=v['VersionId'])['PolicyVersion']['Document']
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Couldn't get policy version {0}".format(v['VersionId']))
-
- if module.check_mode and compare_policies(document, json.loads(to_native(policy_document))):
- return v, True
-
- # If the current policy matches the existing one
- if not compare_policies(document, json.loads(to_native(policy_document))):
- return v, False
-
- # No existing version so create one
- # There is a service limit (typically 5) of policy versions.
- #
- # Rather than assume that it is 5, we'll try to create the policy
- # and if that doesn't work, delete the oldest non default policy version
- # and try again.
- try:
- version = client.create_policy_version(PolicyArn=policy['Arn'], PolicyDocument=policy_document)['PolicyVersion']
- return version, True
- except is_boto3_error_code('LimitExceeded'):
- delete_oldest_non_default_version(policy)
- try:
- version = client.create_policy_version(PolicyArn=policy['Arn'], PolicyDocument=policy_document)['PolicyVersion']
- return version, True
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as second_e:
- module.fail_json_aws(second_e, msg="Couldn't create policy version")
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, msg="Couldn't create policy version")
-
-
-def set_if_default(policy, policy_version, is_default):
- if is_default and not policy_version['IsDefaultVersion']:
- try:
- client.set_default_policy_version(PolicyArn=policy['Arn'], VersionId=policy_version['VersionId'])
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Couldn't set default policy version")
- return True
- return False
-
-
-def set_if_only(policy, policy_version, is_only):
- if is_only:
- try:
- versions = [v for v in client.list_policy_versions(PolicyArn=policy['Arn'])[
- 'Versions'] if not v['IsDefaultVersion']]
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Couldn't list policy versions")
- for v in versions:
- try:
- client.delete_policy_version(PolicyArn=policy['Arn'], VersionId=v['VersionId'])
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Couldn't delete policy version")
- return len(versions) > 0
- return False
-
-
-def detach_all_entities(policy, **kwargs):
- try:
- entities = client.list_entities_for_policy(PolicyArn=policy['Arn'], **kwargs)
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Couldn't detach list entities for policy {0}".format(policy['PolicyName']))
-
- for g in entities['PolicyGroups']:
- try:
- client.detach_group_policy(PolicyArn=policy['Arn'], GroupName=g['GroupName'])
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Couldn't detach group policy {0}".format(g['GroupName']))
- for u in entities['PolicyUsers']:
- try:
- client.detach_user_policy(PolicyArn=policy['Arn'], UserName=u['UserName'])
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Couldn't detach user policy {0}".format(u['UserName']))
- for r in entities['PolicyRoles']:
- try:
- client.detach_role_policy(PolicyArn=policy['Arn'], RoleName=r['RoleName'])
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Couldn't detach role policy {0}".format(r['RoleName']))
- if entities['IsTruncated']:
- detach_all_entities(policy, marker=entities['Marker'])
-
-
-def create_or_update_policy(existing_policy):
- name = module.params.get('policy_name')
- description = module.params.get('policy_description')
- default = module.params.get('make_default')
- only = module.params.get('only_version')
-
- policy = None
-
- if module.params.get('policy') is not None:
- policy = json.dumps(json.loads(module.params.get('policy')))
-
- if existing_policy is None:
- if module.check_mode:
- module.exit_json(changed=True)
-
- # Create policy when none already exists
- try:
- rvalue = client.create_policy(PolicyName=name, Path='/', PolicyDocument=policy, Description=description)
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Couldn't create policy {0}".format(name))
-
- module.exit_json(changed=True, policy=camel_dict_to_snake_dict(rvalue['Policy']))
- else:
- policy_version, changed = get_or_create_policy_version(existing_policy, policy)
- changed = set_if_default(existing_policy, policy_version, default) or changed
- changed = set_if_only(existing_policy, policy_version, only) or changed
-
- # If anything has changed we need to refresh the policy
- if changed:
- try:
- updated_policy = client.get_policy(PolicyArn=existing_policy['Arn'])['Policy']
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json(msg="Couldn't get policy")
-
- module.exit_json(changed=changed, policy=camel_dict_to_snake_dict(updated_policy))
- else:
- module.exit_json(changed=changed, policy=camel_dict_to_snake_dict(existing_policy))
-
-
-def delete_policy(existing_policy):
- # Check for existing policy
- if existing_policy:
- if module.check_mode:
- module.exit_json(changed=True)
-
- # Detach policy
- detach_all_entities(existing_policy)
- # Delete Versions
- try:
- versions = client.list_policy_versions(PolicyArn=existing_policy['Arn'])['Versions']
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Couldn't list policy versions")
- for v in versions:
- if not v['IsDefaultVersion']:
- try:
- client.delete_policy_version(PolicyArn=existing_policy['Arn'], VersionId=v['VersionId'])
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(
- e, msg="Couldn't delete policy version {0}".format(v['VersionId']))
- # Delete policy
- try:
- client.delete_policy(PolicyArn=existing_policy['Arn'])
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Couldn't delete policy {0}".format(existing_policy['PolicyName']))
-
- # This is the one case where we will return the old policy
- module.exit_json(changed=True, policy=camel_dict_to_snake_dict(existing_policy))
- else:
- module.exit_json(changed=False, policy=None)
-
-
-def main():
- global module
- global client
-
- argument_spec = dict(
- policy_name=dict(required=True),
- policy_description=dict(default=''),
- policy=dict(type='json'),
- make_default=dict(type='bool', default=True),
- only_version=dict(type='bool', default=False),
- state=dict(default='present', choices=['present', 'absent']),
- )
-
- module = AnsibleAWSModule(
- argument_spec=argument_spec,
- required_if=[['state', 'present', ['policy']]],
- supports_check_mode=True
- )
-
- name = module.params.get('policy_name')
- state = module.params.get('state')
-
- try:
- client = module.client('iam', retry_decorator=AWSRetry.jittered_backoff())
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to connect to AWS')
-
- existing_policy = get_policy_by_name(name)
-
- if state == 'present':
- create_or_update_policy(existing_policy)
- else:
- delete_policy(existing_policy)
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/aws/plugins/modules/iam_mfa_device_info.py b/ansible_collections/community/aws/plugins/modules/iam_mfa_device_info.py
deleted file mode 100644
index 16abae170..000000000
--- a/ansible_collections/community/aws/plugins/modules/iam_mfa_device_info.py
+++ /dev/null
@@ -1,104 +0,0 @@
-#!/usr/bin/python
-# Copyright: Ansible Project
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
----
-module: iam_mfa_device_info
-version_added: 1.0.0
-short_description: List the MFA (Multi-Factor Authentication) devices registered for a user
-description:
- - List the MFA (Multi-Factor Authentication) devices registered for a user
-author: Victor Costan (@pwnall)
-options:
- user_name:
- description:
- - The name of the user whose MFA devices will be listed
- type: str
-extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
-'''
-
-RETURN = """
-mfa_devices:
- description: The MFA devices registered for the given user
- returned: always
- type: list
- sample:
- - enable_date: "2016-03-11T23:25:36+00:00"
- serial_number: arn:aws:iam::123456789012:mfa/example
- user_name: example
- - enable_date: "2016-03-11T23:25:37+00:00"
- serial_number: arn:aws:iam::123456789012:mfa/example
- user_name: example
-"""
-
-EXAMPLES = r'''
-# Note: These examples do not set authentication details, see the AWS Guide for details.
-
-# more details: https://docs.aws.amazon.com/IAM/latest/APIReference/API_ListMFADevices.html
-- name: List MFA devices
- community.aws.iam_mfa_device_info:
- register: mfa_devices
-
-# more details: https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html
-- name: Assume an existing role
- community.aws.sts_assume_role:
- mfa_serial_number: "{{ mfa_devices.mfa_devices[0].serial_number }}"
- role_arn: "arn:aws:iam::123456789012:role/someRole"
- role_session_name: "someRoleSession"
- register: assumed_role
-'''
-
-try:
- import botocore
- from botocore.exceptions import ClientError
-except ImportError:
- pass # Handled by AnsibleAWSModule
-
-from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-
-
-def list_mfa_devices(connection, module):
- user_name = module.params.get('user_name')
- changed = False
-
- args = {}
- if user_name is not None:
- args['UserName'] = user_name
- try:
- response = connection.list_mfa_devices(**args)
- except ClientError as e:
- module.fail_json_aws(e, msg="Failed to list MFA devices")
-
- module.exit_json(changed=changed, **camel_dict_to_snake_dict(response))
-
-
-def main():
- argument_spec = dict(
- user_name=dict(required=False, default=None),
- )
-
- module = AnsibleAWSModule(
- argument_spec=argument_spec,
- supports_check_mode=True,
- )
-
- try:
- connection = module.client('iam')
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to connect to AWS')
-
- list_mfa_devices(connection, module)
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/aws/plugins/modules/iam_password_policy.py b/ansible_collections/community/aws/plugins/modules/iam_password_policy.py
deleted file mode 100644
index 19614d26d..000000000
--- a/ansible_collections/community/aws/plugins/modules/iam_password_policy.py
+++ /dev/null
@@ -1,213 +0,0 @@
-#!/usr/bin/python
-
-# Copyright: (c) 2018, Aaron Smith <ajsmith10381@gmail.com>
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
----
-module: iam_password_policy
-version_added: 1.0.0
-short_description: Update an IAM Password Policy
-description:
- - Module updates an IAM Password Policy on a given AWS account
-author:
- - "Aaron Smith (@slapula)"
-options:
- state:
- description:
- - Specifies the overall state of the password policy.
- required: true
- choices: ['present', 'absent']
- type: str
- min_pw_length:
- description:
- - Minimum password length.
- default: 6
- aliases: [minimum_password_length]
- type: int
- require_symbols:
- description:
- - Require symbols in password.
- default: false
- type: bool
- require_numbers:
- description:
- - Require numbers in password.
- default: false
- type: bool
- require_uppercase:
- description:
- - Require uppercase letters in password.
- default: false
- type: bool
- require_lowercase:
- description:
- - Require lowercase letters in password.
- default: false
- type: bool
- allow_pw_change:
- description:
- - Allow users to change their password.
- default: false
- type: bool
- aliases: [allow_password_change]
- pw_max_age:
- description:
- - Maximum age for a password in days. When this option is 0 then passwords
- do not expire automatically.
- default: 0
- aliases: [password_max_age]
- type: int
- pw_reuse_prevent:
- description:
- - Prevent re-use of passwords.
- default: 0
- aliases: [password_reuse_prevent, prevent_reuse]
- type: int
- pw_expire:
- description:
- - Prevents users from change an expired password.
- default: false
- type: bool
- aliases: [password_expire, expire]
-extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
-
-'''
-
-EXAMPLES = '''
-- name: Password policy for AWS account
- community.aws.iam_password_policy:
- state: present
- min_pw_length: 8
- require_symbols: false
- require_numbers: true
- require_uppercase: true
- require_lowercase: true
- allow_pw_change: true
- pw_max_age: 60
- pw_reuse_prevent: 5
- pw_expire: false
-'''
-
-RETURN = ''' # '''
-
-try:
- import botocore
-except ImportError:
- pass # caught by AnsibleAWSModule
-
-from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-
-
-class IAMConnection(object):
- def __init__(self, module):
- try:
- self.connection = module.resource('iam')
- self.module = module
- except Exception as e:
- module.fail_json(msg="Failed to connect to AWS: %s" % str(e))
-
- def policy_to_dict(self, policy):
- policy_attributes = [
- 'allow_users_to_change_password', 'expire_passwords', 'hard_expiry',
- 'max_password_age', 'minimum_password_length', 'password_reuse_prevention',
- 'require_lowercase_characters', 'require_numbers', 'require_symbols', 'require_uppercase_characters'
- ]
- ret = {}
- for attr in policy_attributes:
- ret[attr] = getattr(policy, attr)
- return ret
-
- def update_password_policy(self, module, policy):
- min_pw_length = module.params.get('min_pw_length')
- require_symbols = module.params.get('require_symbols')
- require_numbers = module.params.get('require_numbers')
- require_uppercase = module.params.get('require_uppercase')
- require_lowercase = module.params.get('require_lowercase')
- allow_pw_change = module.params.get('allow_pw_change')
- pw_max_age = module.params.get('pw_max_age')
- pw_reuse_prevent = module.params.get('pw_reuse_prevent')
- pw_expire = module.params.get('pw_expire')
-
- update_parameters = dict(
- MinimumPasswordLength=min_pw_length,
- RequireSymbols=require_symbols,
- RequireNumbers=require_numbers,
- RequireUppercaseCharacters=require_uppercase,
- RequireLowercaseCharacters=require_lowercase,
- AllowUsersToChangePassword=allow_pw_change,
- HardExpiry=pw_expire
- )
- if pw_reuse_prevent:
- update_parameters.update(PasswordReusePrevention=pw_reuse_prevent)
- if pw_max_age:
- update_parameters.update(MaxPasswordAge=pw_max_age)
-
- try:
- original_policy = self.policy_to_dict(policy)
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- original_policy = {}
-
- try:
- results = policy.update(**update_parameters)
- policy.reload()
- updated_policy = self.policy_to_dict(policy)
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, msg="Couldn't update IAM Password Policy")
-
- changed = (original_policy != updated_policy)
- return (changed, updated_policy, camel_dict_to_snake_dict(results))
-
- def delete_password_policy(self, policy):
- try:
- results = policy.delete()
- except is_boto3_error_code('NoSuchEntity'):
- self.module.exit_json(changed=False, task_status={'IAM': "Couldn't find IAM Password Policy"})
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
- self.module.fail_json_aws(e, msg="Couldn't delete IAM Password Policy")
- return camel_dict_to_snake_dict(results)
-
-
-def main():
- module = AnsibleAWSModule(
- argument_spec={
- 'state': dict(choices=['present', 'absent'], required=True),
- 'min_pw_length': dict(type='int', aliases=['minimum_password_length'], default=6),
- 'require_symbols': dict(type='bool', default=False),
- 'require_numbers': dict(type='bool', default=False),
- 'require_uppercase': dict(type='bool', default=False),
- 'require_lowercase': dict(type='bool', default=False),
- 'allow_pw_change': dict(type='bool', aliases=['allow_password_change'], default=False),
- 'pw_max_age': dict(type='int', aliases=['password_max_age'], default=0),
- 'pw_reuse_prevent': dict(type='int', aliases=['password_reuse_prevent', 'prevent_reuse'], default=0),
- 'pw_expire': dict(type='bool', aliases=['password_expire', 'expire'], default=False),
- },
- supports_check_mode=True,
- )
-
- resource = IAMConnection(module)
- policy = resource.connection.AccountPasswordPolicy()
-
- state = module.params.get('state')
-
- if state == 'present':
- (changed, new_policy, update_result) = resource.update_password_policy(module, policy)
- module.exit_json(changed=changed, task_status={'IAM': update_result}, policy=new_policy)
-
- if state == 'absent':
- delete_result = resource.delete_password_policy(policy)
- module.exit_json(changed=True, task_status={'IAM': delete_result})
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/aws/plugins/modules/iam_role.py b/ansible_collections/community/aws/plugins/modules/iam_role.py
deleted file mode 100644
index 4add6a525..000000000
--- a/ansible_collections/community/aws/plugins/modules/iam_role.py
+++ /dev/null
@@ -1,736 +0,0 @@
-#!/usr/bin/python
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
----
-module: iam_role
-version_added: 1.0.0
-short_description: Manage AWS IAM roles
-description:
- - Manage AWS IAM roles.
-author:
- - "Rob White (@wimnat)"
-options:
- path:
- description:
- - The path to the role. For more information about paths, see U(https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html).
- default: "/"
- type: str
- name:
- description:
- - The name of the role to create.
- required: true
- type: str
- description:
- description:
- - Provides a description of the role.
- type: str
- boundary:
- description:
- - The ARN of an IAM managed policy to use to restrict the permissions this role can pass on to IAM roles/users that it creates.
- - Boundaries cannot be set on Instance Profiles, as such if this option is specified then I(create_instance_profile) must be C(false).
- - This is intended for roles/users that have permissions to create new IAM objects.
- - For more information on boundaries, see U(https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_boundaries.html).
- aliases: [boundary_policy_arn]
- type: str
- assume_role_policy_document:
- description:
- - The trust relationship policy document that grants an entity permission to assume the role.
- - This parameter is required when I(state=present).
- type: json
- managed_policies:
- description:
- - A list of managed policy ARNs, managed policy ARNs or friendly names.
- - To remove all policies set I(purge_polices=true) and I(managed_policies=[None]).
- - To embed an inline policy, use M(community.aws.iam_policy).
- aliases: ['managed_policy']
- type: list
- elements: str
- max_session_duration:
- description:
- - The maximum duration (in seconds) of a session when assuming the role.
- - Valid values are between 1 and 12 hours (3600 and 43200 seconds).
- type: int
- purge_policies:
- description:
- - When I(purge_policies=true) any managed policies not listed in I(managed_policies) will be detatched.
- type: bool
- aliases: ['purge_policy', 'purge_managed_policies']
- default: true
- state:
- description:
- - Create or remove the IAM role.
- default: present
- choices: [ present, absent ]
- type: str
- create_instance_profile:
- description:
- - Creates an IAM instance profile along with the role.
- default: true
- type: bool
- delete_instance_profile:
- description:
- - When I(delete_instance_profile=true) and I(state=absent) deleting a role will also delete the instance
- profile created with the same I(name) as the role.
- - Only applies when I(state=absent).
- default: false
- type: bool
- wait_timeout:
- description:
- - How long (in seconds) to wait for creation / update to complete.
- default: 120
- type: int
- wait:
- description:
- - When I(wait=True) the module will wait for up to I(wait_timeout) seconds
- for IAM role creation before returning.
- default: True
- type: bool
-extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
- - amazon.aws.boto3
- - amazon.aws.tags
-'''
-
-EXAMPLES = r'''
-# Note: These examples do not set authentication details, see the AWS Guide for details.
-
-- name: Create a role with description and tags
- community.aws.iam_role:
- name: mynewrole
- assume_role_policy_document: "{{ lookup('file','policy.json') }}"
- description: This is My New Role
- tags:
- env: dev
-
-- name: "Create a role and attach a managed policy called 'PowerUserAccess'"
- community.aws.iam_role:
- name: mynewrole
- assume_role_policy_document: "{{ lookup('file','policy.json') }}"
- managed_policies:
- - arn:aws:iam::aws:policy/PowerUserAccess
-
-- name: Keep the role created above but remove all managed policies
- community.aws.iam_role:
- name: mynewrole
- assume_role_policy_document: "{{ lookup('file','policy.json') }}"
- managed_policies: []
-
-- name: Delete the role
- community.aws.iam_role:
- name: mynewrole
- assume_role_policy_document: "{{ lookup('file', 'policy.json') }}"
- state: absent
-
-'''
-RETURN = r'''
-iam_role:
- description: dictionary containing the IAM Role data
- returned: success
- type: complex
- contains:
- path:
- description: the path to the role
- type: str
- returned: always
- sample: /
- role_name:
- description: the friendly name that identifies the role
- type: str
- returned: always
- sample: myrole
- role_id:
- description: the stable and unique string identifying the role
- type: str
- returned: always
- sample: ABCDEFF4EZ4ABCDEFV4ZC
- arn:
- description: the Amazon Resource Name (ARN) specifying the role
- type: str
- returned: always
- sample: "arn:aws:iam::1234567890:role/mynewrole"
- create_date:
- description: the date and time, in ISO 8601 date-time format, when the role was created
- type: str
- returned: always
- sample: "2016-08-14T04:36:28+00:00"
- assume_role_policy_document:
- description:
- - the policy that grants an entity permission to assume the role
- - |
- note: the case of keys in this dictionary are currently converted from CamelCase to
- snake_case. In a release after 2023-12-01 this behaviour will change
- type: dict
- returned: always
- sample: {
- 'statement': [
- {
- 'action': 'sts:AssumeRole',
- 'effect': 'Allow',
- 'principal': {
- 'service': 'ec2.amazonaws.com'
- },
- 'sid': ''
- }
- ],
- 'version': '2012-10-17'
- }
- assume_role_policy_document_raw:
- description: the policy that grants an entity permission to assume the role
- type: dict
- returned: always
- version_added: 5.3.0
- sample: {
- 'Statement': [
- {
- 'Action': 'sts:AssumeRole',
- 'Effect': 'Allow',
- 'Principal': {
- 'Service': 'ec2.amazonaws.com'
- },
- 'Sid': ''
- }
- ],
- 'Version': '2012-10-17'
- }
-
- attached_policies:
- description: a list of dicts containing the name and ARN of the managed IAM policies attached to the role
- type: list
- returned: always
- sample: [
- {
- 'policy_arn': 'arn:aws:iam::aws:policy/PowerUserAccess',
- 'policy_name': 'PowerUserAccess'
- }
- ]
- tags:
- description: role tags
- type: dict
- returned: always
- sample: '{"Env": "Prod"}'
-'''
-
-import json
-
-try:
- import botocore
-except ImportError:
- pass # caught by AnsibleAWSModule
-
-from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_tag_list
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import compare_aws_tags
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import compare_policies
-
-
-@AWSRetry.jittered_backoff()
-def _list_policies(client):
- paginator = client.get_paginator('list_policies')
- return paginator.paginate().build_full_result()['Policies']
-
-
-def wait_iam_exists(module, client):
- if module.check_mode:
- return
- if not module.params.get('wait'):
- return
-
- role_name = module.params.get('name')
- wait_timeout = module.params.get('wait_timeout')
-
- delay = min(wait_timeout, 5)
- max_attempts = wait_timeout // delay
-
- try:
- waiter = client.get_waiter('role_exists')
- waiter.wait(
- WaiterConfig={'Delay': delay, 'MaxAttempts': max_attempts},
- RoleName=role_name,
- )
- except botocore.exceptions.WaiterError as e:
- module.fail_json_aws(e, msg='Timeout while waiting on IAM role creation')
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed while waiting on IAM role creation')
-
-
-def convert_friendly_names_to_arns(module, client, policy_names):
- if not any(not policy.startswith('arn:') for policy in policy_names):
- return policy_names
-
- allpolicies = {}
- policies = _list_policies(client)
-
- for policy in policies:
- allpolicies[policy['PolicyName']] = policy['Arn']
- allpolicies[policy['Arn']] = policy['Arn']
- try:
- return [allpolicies[policy] for policy in policy_names]
- except KeyError as e:
- module.fail_json_aws(e, msg="Couldn't find policy")
-
-
-def attach_policies(module, client, policies_to_attach, role_name):
- if module.check_mode and policies_to_attach:
- return True
-
- changed = False
- for policy_arn in policies_to_attach:
- try:
- client.attach_role_policy(RoleName=role_name, PolicyArn=policy_arn, aws_retry=True)
- changed = True
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Unable to attach policy {0} to role {1}".format(policy_arn, role_name))
- return changed
-
-
-def remove_policies(module, client, policies_to_remove, role_name):
- if module.check_mode and policies_to_remove:
- return True
-
- changed = False
- for policy in policies_to_remove:
- try:
- client.detach_role_policy(RoleName=role_name, PolicyArn=policy, aws_retry=True)
- changed = True
- except is_boto3_error_code('NoSuchEntityException'):
- pass
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, msg="Unable to detach policy {0} from {1}".format(policy, role_name))
- return changed
-
-
-def remove_inline_policies(module, client, role_name):
- current_inline_policies = get_inline_policy_list(module, client, role_name)
- for policy in current_inline_policies:
- try:
- client.delete_role_policy(RoleName=role_name, PolicyName=policy, aws_retry=True)
- except is_boto3_error_code('NoSuchEntityException'):
- pass
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, msg="Unable to delete policy {0} embedded in {1}".format(policy, role_name))
-
-
-def generate_create_params(module):
- params = dict()
- params['Path'] = module.params.get('path')
- params['RoleName'] = module.params.get('name')
- params['AssumeRolePolicyDocument'] = module.params.get('assume_role_policy_document')
- if module.params.get('description') is not None:
- params['Description'] = module.params.get('description')
- if module.params.get('max_session_duration') is not None:
- params['MaxSessionDuration'] = module.params.get('max_session_duration')
- if module.params.get('boundary') is not None:
- params['PermissionsBoundary'] = module.params.get('boundary')
- if module.params.get('tags') is not None:
- params['Tags'] = ansible_dict_to_boto3_tag_list(module.params.get('tags'))
-
- return params
-
-
-def create_basic_role(module, client):
- """
- Perform the Role creation.
- Assumes tests for the role existing have already been performed.
- """
- if module.check_mode:
- module.exit_json(changed=True)
-
- try:
- params = generate_create_params(module)
- role = client.create_role(aws_retry=True, **params)
- # 'Description' is documented as key of the role returned by create_role
- # but appears to be an AWS bug (the value is not returned using the AWS CLI either).
- # Get the role after creating it.
- role = get_role_with_backoff(module, client, params['RoleName'])
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Unable to create role")
-
- return role
-
-
-def update_role_assumed_policy(module, client, role_name, target_assumed_policy, current_assumed_policy):
- # Check Assumed Policy document
- if target_assumed_policy is None or not compare_policies(current_assumed_policy, json.loads(target_assumed_policy)):
- return False
-
- if module.check_mode:
- return True
-
- try:
- client.update_assume_role_policy(
- RoleName=role_name,
- PolicyDocument=target_assumed_policy,
- aws_retry=True)
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Unable to update assume role policy for role {0}".format(role_name))
- return True
-
-
-def update_role_description(module, client, role_name, target_description, current_description):
- # Check Description update
- if target_description is None or current_description == target_description:
- return False
-
- if module.check_mode:
- return True
-
- try:
- client.update_role(RoleName=role_name, Description=target_description, aws_retry=True)
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Unable to update description for role {0}".format(role_name))
- return True
-
-
-def update_role_max_session_duration(module, client, role_name, target_duration, current_duration):
- # Check MaxSessionDuration update
- if target_duration is None or current_duration == target_duration:
- return False
-
- if module.check_mode:
- return True
-
- try:
- client.update_role(RoleName=role_name, MaxSessionDuration=target_duration, aws_retry=True)
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Unable to update maximum session duration for role {0}".format(role_name))
- return True
-
-
-def update_role_permissions_boundary(module, client, role_name, target_permissions_boundary, current_permissions_boundary):
- # Check PermissionsBoundary
- if target_permissions_boundary is None or target_permissions_boundary == current_permissions_boundary:
- return False
-
- if module.check_mode:
- return True
-
- if target_permissions_boundary == '':
- try:
- client.delete_role_permissions_boundary(RoleName=role_name, aws_retry=True)
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Unable to remove permission boundary for role {0}".format(role_name))
- else:
- try:
- client.put_role_permissions_boundary(RoleName=role_name, PermissionsBoundary=target_permissions_boundary, aws_retry=True)
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Unable to update permission boundary for role {0}".format(role_name))
- return True
-
-
-def update_managed_policies(module, client, role_name, managed_policies, purge_policies):
- # Check Managed Policies
- if managed_policies is None:
- return False
-
- # Get list of current attached managed policies
- current_attached_policies = get_attached_policy_list(module, client, role_name)
- current_attached_policies_arn_list = [policy['PolicyArn'] for policy in current_attached_policies]
-
- if len(managed_policies) == 1 and managed_policies[0] is None:
- managed_policies = []
-
- policies_to_remove = set(current_attached_policies_arn_list) - set(managed_policies)
- policies_to_attach = set(managed_policies) - set(current_attached_policies_arn_list)
-
- changed = False
- if purge_policies and policies_to_remove:
- if module.check_mode:
- return True
- else:
- changed |= remove_policies(module, client, policies_to_remove, role_name)
-
- if policies_to_attach:
- if module.check_mode:
- return True
- else:
- changed |= attach_policies(module, client, policies_to_attach, role_name)
-
- return changed
-
-
-def create_or_update_role(module, client):
-
- role_name = module.params.get('name')
- assumed_policy = module.params.get('assume_role_policy_document')
- create_instance_profile = module.params.get('create_instance_profile')
- description = module.params.get('description')
- duration = module.params.get('max_session_duration')
- path = module.params.get('path')
- permissions_boundary = module.params.get('boundary')
- purge_tags = module.params.get('purge_tags')
- tags = ansible_dict_to_boto3_tag_list(module.params.get('tags')) if module.params.get('tags') else None
- purge_policies = module.params.get('purge_policies')
- managed_policies = module.params.get('managed_policies')
- if managed_policies:
- # Attempt to list the policies early so we don't leave things behind if we can't find them.
- managed_policies = convert_friendly_names_to_arns(module, client, managed_policies)
-
- changed = False
-
- # Get role
- role = get_role(module, client, role_name)
-
- # If role is None, create it
- if role is None:
- role = create_basic_role(module, client)
-
- if not module.check_mode and module.params.get('wait'):
- wait_iam_exists(module, client)
-
- changed = True
- else:
- # Role exists - get current attributes
- current_assumed_policy = role.get('AssumeRolePolicyDocument')
- current_description = role.get('Description')
- current_duration = role.get('MaxSessionDuration')
- current_permissions_boundary = role.get('PermissionsBoundary', {}).get('PermissionsBoundaryArn', '')
-
- # Update attributes
- changed |= update_role_tags(module, client, role_name, tags, purge_tags)
- changed |= update_role_assumed_policy(module, client, role_name, assumed_policy, current_assumed_policy)
- changed |= update_role_description(module, client, role_name, description, current_description)
- changed |= update_role_max_session_duration(module, client, role_name, duration, current_duration)
- changed |= update_role_permissions_boundary(module, client, role_name, permissions_boundary, current_permissions_boundary)
-
- if not module.check_mode and module.params.get('wait'):
- wait_iam_exists(module, client)
-
- if create_instance_profile:
- changed |= create_instance_profiles(module, client, role_name, path)
-
- if not module.check_mode and module.params.get('wait'):
- wait_iam_exists(module, client)
-
- changed |= update_managed_policies(module, client, role_name, managed_policies, purge_policies)
- wait_iam_exists(module, client)
-
- # Get the role again
- role = get_role(module, client, role_name)
- role['AttachedPolicies'] = get_attached_policy_list(module, client, role_name)
- role['tags'] = get_role_tags(module, client)
-
- camel_role = camel_dict_to_snake_dict(role, ignore_list=['tags'])
- camel_role["assume_role_policy_document_raw"] = role.get("AssumeRolePolicyDocument", {})
- module.exit_json(changed=changed, iam_role=camel_role, **camel_role)
-
-
-def create_instance_profiles(module, client, role_name, path):
-
- # Fetch existing Profiles
- try:
- instance_profiles = client.list_instance_profiles_for_role(RoleName=role_name, aws_retry=True)['InstanceProfiles']
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Unable to list instance profiles for role {0}".format(role_name))
-
- # Profile already exists
- if any(p['InstanceProfileName'] == role_name for p in instance_profiles):
- return False
-
- if module.check_mode:
- return True
-
- # Make sure an instance profile is created
- try:
- client.create_instance_profile(InstanceProfileName=role_name, Path=path, aws_retry=True)
- except is_boto3_error_code('EntityAlreadyExists'):
- # If the profile already exists, no problem, move on.
- # Implies someone's changing things at the same time...
- return False
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, msg="Unable to create instance profile for role {0}".format(role_name))
-
- # And attach the role to the profile
- try:
- client.add_role_to_instance_profile(InstanceProfileName=role_name, RoleName=role_name, aws_retry=True)
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Unable to attach role {0} to instance profile {0}".format(role_name))
-
- return True
-
-
-def remove_instance_profiles(module, client, role_name):
- delete_profiles = module.params.get("delete_instance_profile")
-
- try:
- instance_profiles = client.list_instance_profiles_for_role(aws_retry=True, RoleName=role_name)['InstanceProfiles']
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Unable to list instance profiles for role {0}".format(role_name))
-
- # Remove the role from the instance profile(s)
- for profile in instance_profiles:
- profile_name = profile['InstanceProfileName']
- try:
- if not module.check_mode:
- client.remove_role_from_instance_profile(aws_retry=True, InstanceProfileName=profile_name, RoleName=role_name)
- if profile_name == role_name:
- if delete_profiles:
- try:
- client.delete_instance_profile(InstanceProfileName=profile_name, aws_retry=True)
- except is_boto3_error_code('NoSuchEntityException'):
- pass
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, msg="Unable to remove instance profile {0}".format(profile_name))
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Unable to remove role {0} from instance profile {1}".format(role_name, profile_name))
-
-
-def destroy_role(module, client):
-
- role_name = module.params.get('name')
- role = get_role(module, client, role_name)
-
- if role is None:
- module.exit_json(changed=False)
-
- if not module.check_mode:
- # Before we try to delete the role we need to remove any
- # - attached instance profiles
- # - attached managed policies
- # - embedded inline policies
- remove_instance_profiles(module, client, role_name)
- update_managed_policies(module, client, role_name, [], True)
- remove_inline_policies(module, client, role_name)
- try:
- client.delete_role(aws_retry=True, RoleName=role_name)
- except is_boto3_error_code('NoSuchEntityException'):
- module.exit_json(changed=False)
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, msg="Unable to delete role")
-
- module.exit_json(changed=True)
-
-
-def get_role_with_backoff(module, client, name):
- try:
- return AWSRetry.jittered_backoff(catch_extra_error_codes=['NoSuchEntity'])(client.get_role)(RoleName=name)['Role']
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Unable to get role {0}".format(name))
-
-
-def get_role(module, client, name):
- try:
- return client.get_role(RoleName=name, aws_retry=True)['Role']
- except is_boto3_error_code('NoSuchEntity'):
- return None
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, msg="Unable to get role {0}".format(name))
-
-
-def get_attached_policy_list(module, client, name):
- try:
- return client.list_attached_role_policies(RoleName=name, aws_retry=True)['AttachedPolicies']
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Unable to list attached policies for role {0}".format(name))
-
-
-def get_inline_policy_list(module, client, name):
- try:
- return client.list_role_policies(RoleName=name, aws_retry=True)['PolicyNames']
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Unable to list attached policies for role {0}".format(name))
-
-
-def get_role_tags(module, client):
- role_name = module.params.get('name')
- try:
- return boto3_tag_list_to_ansible_dict(client.list_role_tags(RoleName=role_name, aws_retry=True)['Tags'])
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Unable to list tags for role {0}".format(role_name))
-
-
-def update_role_tags(module, client, role_name, new_tags, purge_tags):
- if new_tags is None:
- return False
- new_tags = boto3_tag_list_to_ansible_dict(new_tags)
-
- try:
- existing_tags = boto3_tag_list_to_ansible_dict(client.list_role_tags(RoleName=role_name, aws_retry=True)['Tags'])
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError, KeyError):
- existing_tags = {}
-
- tags_to_add, tags_to_remove = compare_aws_tags(existing_tags, new_tags, purge_tags=purge_tags)
-
- if not module.check_mode:
- try:
- if tags_to_remove:
- client.untag_role(RoleName=role_name, TagKeys=tags_to_remove, aws_retry=True)
- if tags_to_add:
- client.tag_role(RoleName=role_name, Tags=ansible_dict_to_boto3_tag_list(tags_to_add), aws_retry=True)
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Unable to set tags for role %s' % role_name)
-
- changed = bool(tags_to_add) or bool(tags_to_remove)
- return changed
-
-
-def main():
-
- argument_spec = dict(
- name=dict(type='str', required=True),
- path=dict(type='str', default="/"),
- assume_role_policy_document=dict(type='json'),
- managed_policies=dict(type='list', aliases=['managed_policy'], elements='str'),
- max_session_duration=dict(type='int'),
- state=dict(type='str', choices=['present', 'absent'], default='present'),
- description=dict(type='str'),
- boundary=dict(type='str', aliases=['boundary_policy_arn']),
- create_instance_profile=dict(type='bool', default=True),
- delete_instance_profile=dict(type='bool', default=False),
- purge_policies=dict(default=True, type='bool', aliases=['purge_policy', 'purge_managed_policies']),
- tags=dict(type='dict', aliases=['resource_tags']),
- purge_tags=dict(type='bool', default=True),
- wait=dict(type='bool', default=True),
- wait_timeout=dict(default=120, type='int'),
- )
-
- module = AnsibleAWSModule(argument_spec=argument_spec,
- required_if=[('state', 'present', ['assume_role_policy_document'])],
- supports_check_mode=True)
-
- module.deprecate("All return values other than iam_role and changed have been deprecated and "
- "will be removed in a release after 2023-12-01.",
- date="2023-12-01", collection_name="community.aws")
-
- module.deprecate("In a release after 2023-12-01 the contents of iam_role.assume_role_policy_document "
- "will no longer be converted from CamelCase to snake_case. The "
- "iam_role.assume_role_policy_document_raw return value already returns the "
- "policy document in this future format.",
- date="2023-12-01", collection_name="community.aws")
-
- if module.params.get('boundary'):
- if module.params.get('create_instance_profile'):
- module.fail_json(msg="When using a boundary policy, `create_instance_profile` must be set to `false`.")
- if not module.params.get('boundary').startswith('arn:aws:iam'):
- module.fail_json(msg="Boundary policy must be an ARN")
- if module.params.get('max_session_duration'):
- max_session_duration = module.params.get('max_session_duration')
- if max_session_duration < 3600 or max_session_duration > 43200:
- module.fail_json(msg="max_session_duration must be between 1 and 12 hours (3600 and 43200 seconds)")
- if module.params.get('path'):
- path = module.params.get('path')
- if not path.endswith('/') or not path.startswith('/'):
- module.fail_json(msg="path must begin and end with /")
-
- client = module.client('iam', retry_decorator=AWSRetry.jittered_backoff())
-
- state = module.params.get("state")
-
- if state == 'present':
- create_or_update_role(module, client)
- elif state == 'absent':
- destroy_role(module, client)
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/aws/plugins/modules/iam_role_info.py b/ansible_collections/community/aws/plugins/modules/iam_role_info.py
deleted file mode 100644
index d66be487a..000000000
--- a/ansible_collections/community/aws/plugins/modules/iam_role_info.py
+++ /dev/null
@@ -1,282 +0,0 @@
-#!/usr/bin/python
-# Copyright: Ansible Project
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
----
-module: iam_role_info
-version_added: 1.0.0
-short_description: Gather information on IAM roles
-description:
- - Gathers information about IAM roles.
-author:
- - "Will Thames (@willthames)"
-options:
- name:
- description:
- - Name of a role to search for.
- - Mutually exclusive with I(path_prefix).
- aliases:
- - role_name
- type: str
- path_prefix:
- description:
- - Prefix of role to restrict IAM role search for.
- - Mutually exclusive with I(name).
- type: str
-extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
-
-'''
-
-EXAMPLES = '''
-- name: find all existing IAM roles
- community.aws.iam_role_info:
- register: result
-
-- name: describe a single role
- community.aws.iam_role_info:
- name: MyIAMRole
-
-- name: describe all roles matching a path prefix
- community.aws.iam_role_info:
- path_prefix: /application/path
-'''
-
-RETURN = '''
-iam_roles:
- description: List of IAM roles
- returned: always
- type: complex
- contains:
- arn:
- description: Amazon Resource Name for IAM role.
- returned: always
- type: str
- sample: arn:aws:iam::123456789012:role/AnsibleTestRole
- assume_role_policy_document:
- description:
- - The policy that grants an entity permission to assume the role
- - |
- Note: the case of keys in this dictionary are currently converted from CamelCase to
- snake_case. In a release after 2023-12-01 this behaviour will change.
- returned: always
- type: dict
- assume_role_policy_document_raw:
- description: The policy document describing what can assume the role.
- returned: always
- type: dict
- version_added: 5.3.0
- create_date:
- description: Date IAM role was created.
- returned: always
- type: str
- sample: '2017-10-23T00:05:08+00:00'
- inline_policies:
- description: List of names of inline policies.
- returned: always
- type: list
- sample: []
- managed_policies:
- description: List of attached managed policies.
- returned: always
- type: complex
- contains:
- policy_arn:
- description: Amazon Resource Name for the policy.
- returned: always
- type: str
- sample: arn:aws:iam::123456789012:policy/AnsibleTestEC2Policy
- policy_name:
- description: Name of managed policy.
- returned: always
- type: str
- sample: AnsibleTestEC2Policy
- instance_profiles:
- description: List of attached instance profiles.
- returned: always
- type: complex
- contains:
- arn:
- description: Amazon Resource Name for the instance profile.
- returned: always
- type: str
- sample: arn:aws:iam::123456789012:instance-profile/AnsibleTestEC2Policy
- create_date:
- description: Date instance profile was created.
- returned: always
- type: str
- sample: '2017-10-23T00:05:08+00:00'
- instance_profile_id:
- description: Amazon Identifier for the instance profile.
- returned: always
- type: str
- sample: AROAII7ABCD123456EFGH
- instance_profile_name:
- description: Name of instance profile.
- returned: always
- type: str
- sample: AnsibleTestEC2Policy
- path:
- description: Path of instance profile.
- returned: always
- type: str
- sample: /
- roles:
- description: List of roles associated with this instance profile.
- returned: always
- type: list
- sample: []
- path:
- description: Path of role.
- returned: always
- type: str
- sample: /
- role_id:
- description: Amazon Identifier for the role.
- returned: always
- type: str
- sample: AROAII7ABCD123456EFGH
- role_name:
- description: Name of the role.
- returned: always
- type: str
- sample: AnsibleTestRole
- tags:
- description: Role tags.
- type: dict
- returned: always
- sample: '{"Env": "Prod"}'
-'''
-
-try:
- import botocore
-except ImportError:
- pass # caught by AnsibleAWSModule
-
-from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict
-
-
-@AWSRetry.jittered_backoff()
-def list_iam_roles_with_backoff(client, **kwargs):
- paginator = client.get_paginator('list_roles')
- return paginator.paginate(**kwargs).build_full_result()
-
-
-@AWSRetry.jittered_backoff()
-def list_iam_role_policies_with_backoff(client, role_name):
- paginator = client.get_paginator('list_role_policies')
- return paginator.paginate(RoleName=role_name).build_full_result()['PolicyNames']
-
-
-@AWSRetry.jittered_backoff()
-def list_iam_attached_role_policies_with_backoff(client, role_name):
- paginator = client.get_paginator('list_attached_role_policies')
- return paginator.paginate(RoleName=role_name).build_full_result()['AttachedPolicies']
-
-
-@AWSRetry.jittered_backoff()
-def list_iam_instance_profiles_for_role_with_backoff(client, role_name):
- paginator = client.get_paginator('list_instance_profiles_for_role')
- return paginator.paginate(RoleName=role_name).build_full_result()['InstanceProfiles']
-
-
-def describe_iam_role(module, client, role):
- name = role['RoleName']
- try:
- role['InlinePolicies'] = list_iam_role_policies_with_backoff(client, name)
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Couldn't get inline policies for role %s" % name)
- try:
- role['ManagedPolicies'] = list_iam_attached_role_policies_with_backoff(client, name)
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Couldn't get managed policies for role %s" % name)
- try:
- role['InstanceProfiles'] = list_iam_instance_profiles_for_role_with_backoff(client, name)
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Couldn't get instance profiles for role %s" % name)
- try:
- role['tags'] = boto3_tag_list_to_ansible_dict(role['Tags'])
- del role['Tags']
- except KeyError:
- role['tags'] = {}
- return role
-
-
-def describe_iam_roles(module, client):
- name = module.params['name']
- path_prefix = module.params['path_prefix']
- if name:
- try:
- roles = [client.get_role(RoleName=name, aws_retry=True)['Role']]
- except is_boto3_error_code('NoSuchEntity'):
- return []
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, msg="Couldn't get IAM role %s" % name)
- else:
- params = dict()
- if path_prefix:
- if not path_prefix.startswith('/'):
- path_prefix = '/' + path_prefix
- if not path_prefix.endswith('/'):
- path_prefix = path_prefix + '/'
- params['PathPrefix'] = path_prefix
- try:
- roles = list_iam_roles_with_backoff(client, **params)['Roles']
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Couldn't list IAM roles")
- return [normalize_role(describe_iam_role(module, client, role)) for role in roles]
-
-
-def normalize_profile(profile):
- new_profile = camel_dict_to_snake_dict(profile)
- if profile.get("Roles"):
- profile["roles"] = [normalize_role(role) for role in profile.get("Roles")]
- return new_profile
-
-
-def normalize_role(role):
- new_role = camel_dict_to_snake_dict(role, ignore_list=['tags'])
- new_role["assume_role_policy_document_raw"] = role.get("AssumeRolePolicyDocument")
- if role.get("InstanceProfiles"):
- role["instance_profiles"] = [normalize_profile(profile) for profile in role.get("InstanceProfiles")]
- return new_role
-
-
-def main():
- """
- Module action handler
- """
- argument_spec = dict(
- name=dict(aliases=['role_name']),
- path_prefix=dict(),
- )
-
- module = AnsibleAWSModule(argument_spec=argument_spec,
- supports_check_mode=True,
- mutually_exclusive=[['name', 'path_prefix']])
-
- client = module.client('iam', retry_decorator=AWSRetry.jittered_backoff())
-
- module.deprecate("In a release after 2023-12-01 the contents of assume_role_policy_document "
- "will no longer be converted from CamelCase to snake_case. The "
- ".assume_role_policy_document_raw return value already returns the "
- "policy document in this future format.",
- date="2023-12-01", collection_name="community.aws")
-
- module.exit_json(changed=False, iam_roles=describe_iam_roles(module, client))
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/aws/plugins/modules/iam_saml_federation.py b/ansible_collections/community/aws/plugins/modules/iam_saml_federation.py
index f79e4c2c6..acaaa38fc 100644
--- a/ansible_collections/community/aws/plugins/modules/iam_saml_federation.py
+++ b/ansible_collections/community/aws/plugins/modules/iam_saml_federation.py
@@ -1,25 +1,10 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+
+# Copyright: Contributors to the Ansible project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r"""
---
module: iam_saml_federation
version_added: 1.0.0
@@ -42,17 +27,18 @@ options:
default: present
choices: [ "present", "absent" ]
type: str
-extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
author:
- Tony (@axc450)
- Aidan Rowe (@aidan-)
-'''
-EXAMPLES = '''
+extends_documentation_fragment:
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
+
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide for details.
# It is assumed that their matching environment variables are set.
# Creates a new iam saml identity provider if not present
@@ -74,9 +60,9 @@ EXAMPLES = '''
community.aws.iam_saml_federation:
name: example3
state: absent
-'''
+"""
-RETURN = '''
+RETURN = r"""
saml_provider:
description: Details of the SAML Identity Provider that was created/modified.
type: complex
@@ -101,15 +87,16 @@ saml_provider:
type: str
returned: present
sample: "2017-02-08T04:36:28+00:00"
-'''
+"""
try:
- import botocore.exceptions
+ import botocore
except ImportError:
pass
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
class SAMLProviderManager:
@@ -119,7 +106,7 @@ class SAMLProviderManager:
self.module = module
try:
- self.conn = module.client('iam')
+ self.conn = module.client("iam")
except botocore.exceptions.ClientError as e:
self.module.fail_json_aws(e, msg="Unknown AWS SDK error")
@@ -146,10 +133,10 @@ class SAMLProviderManager:
def _get_provider_arn(self, name):
providers = self._list_saml_providers()
- for p in providers['SAMLProviderList']:
- provider_name = p['Arn'].split('/', 1)[1]
+ for p in providers["SAMLProviderList"]:
+ provider_name = p["Arn"].split("/", 1)[1]
if name == provider_name:
- return p['Arn']
+ return p["Arn"]
return None
@@ -157,55 +144,55 @@ class SAMLProviderManager:
if not metadata:
self.module.fail_json(msg="saml_metadata_document must be defined for present state")
- res = {'changed': False}
+ res = {"changed": False}
try:
arn = self._get_provider_arn(name)
except (botocore.exceptions.ValidationError, botocore.exceptions.ClientError) as e:
- self.module.fail_json_aws(e, msg="Could not get the ARN of the identity provider '{0}'".format(name))
+ self.module.fail_json_aws(e, msg=f"Could not get the ARN of the identity provider '{name}'")
if arn: # see if metadata needs updating
try:
resp = self._get_saml_provider(arn)
except (botocore.exceptions.ValidationError, botocore.exceptions.ClientError) as e:
- self.module.fail_json_aws(e, msg="Could not retrieve the identity provider '{0}'".format(name))
+ self.module.fail_json_aws(e, msg=f"Could not retrieve the identity provider '{name}'")
- if metadata.strip() != resp['SAMLMetadataDocument'].strip():
+ if metadata.strip() != resp["SAMLMetadataDocument"].strip():
# provider needs updating
- res['changed'] = True
+ res["changed"] = True
if not self.module.check_mode:
try:
resp = self._update_saml_provider(arn, metadata)
- res['saml_provider'] = self._build_res(resp['SAMLProviderArn'])
+ res["saml_provider"] = self._build_res(resp["SAMLProviderArn"])
except botocore.exceptions.ClientError as e:
- self.module.fail_json_aws(e, msg="Could not update the identity provider '{0}'".format(name))
+ self.module.fail_json_aws(e, msg=f"Could not update the identity provider '{name}'")
else:
- res['saml_provider'] = self._build_res(arn)
+ res["saml_provider"] = self._build_res(arn)
else: # create
- res['changed'] = True
+ res["changed"] = True
if not self.module.check_mode:
try:
resp = self._create_saml_provider(metadata, name)
- res['saml_provider'] = self._build_res(resp['SAMLProviderArn'])
+ res["saml_provider"] = self._build_res(resp["SAMLProviderArn"])
except botocore.exceptions.ClientError as e:
- self.module.fail_json_aws(e, msg="Could not create the identity provider '{0}'".format(name))
+ self.module.fail_json_aws(e, msg=f"Could not create the identity provider '{name}'")
self.module.exit_json(**res)
def delete_saml_provider(self, name):
- res = {'changed': False}
+ res = {"changed": False}
try:
arn = self._get_provider_arn(name)
except (botocore.exceptions.ValidationError, botocore.exceptions.ClientError) as e:
- self.module.fail_json_aws(e, msg="Could not get the ARN of the identity provider '{0}'".format(name))
+ self.module.fail_json_aws(e, msg=f"Could not get the ARN of the identity provider '{name}'")
if arn: # delete
- res['changed'] = True
+ res["changed"] = True
if not self.module.check_mode:
try:
self._delete_saml_provider(arn)
except botocore.exceptions.ClientError as e:
- self.module.fail_json_aws(e, msg="Could not delete the identity provider '{0}'".format(name))
+ self.module.fail_json_aws(e, msg=f"Could not delete the identity provider '{name}'")
self.module.exit_json(**res)
@@ -215,7 +202,7 @@ class SAMLProviderManager:
"arn": arn,
"metadata_document": saml_provider["SAMLMetadataDocument"],
"create_date": saml_provider["CreateDate"].isoformat(),
- "expire_date": saml_provider["ValidUntil"].isoformat()
+ "expire_date": saml_provider["ValidUntil"].isoformat(),
}
@@ -223,26 +210,26 @@ def main():
argument_spec = dict(
name=dict(required=True),
saml_metadata_document=dict(default=None, required=False),
- state=dict(default='present', required=False, choices=['present', 'absent']),
+ state=dict(default="present", required=False, choices=["present", "absent"]),
)
module = AnsibleAWSModule(
argument_spec=argument_spec,
supports_check_mode=True,
- required_if=[('state', 'present', ['saml_metadata_document'])]
+ required_if=[("state", "present", ["saml_metadata_document"])],
)
- name = module.params['name']
- state = module.params.get('state')
- saml_metadata_document = module.params.get('saml_metadata_document')
+ name = module.params["name"]
+ state = module.params.get("state")
+ saml_metadata_document = module.params.get("saml_metadata_document")
sp_man = SAMLProviderManager(module)
- if state == 'present':
+ if state == "present":
sp_man.create_or_update_saml_provider(name, saml_metadata_document)
- elif state == 'absent':
+ elif state == "absent":
sp_man.delete_saml_provider(name)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/iam_server_certificate.py b/ansible_collections/community/aws/plugins/modules/iam_server_certificate.py
index f3d5c5808..6a7734aca 100644
--- a/ansible_collections/community/aws/plugins/modules/iam_server_certificate.py
+++ b/ansible_collections/community/aws/plugins/modules/iam_server_certificate.py
@@ -1,24 +1,10 @@
#!/usr/bin/python
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+# -*- coding: utf-8 -*-
+
+# Copyright: Contributors to the Ansible project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r"""
---
module: iam_server_certificate
version_added: 1.0.0
@@ -76,12 +62,14 @@ options:
author:
- Jonathan I. Davila (@defionscode)
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
+
+RETURN = r""" # """
-EXAMPLES = '''
+EXAMPLES = r"""
- name: Basic server certificate upload from local file
community.aws.iam_server_certificate:
name: very_ssl
@@ -104,7 +92,7 @@ EXAMPLES = '''
name: very_ssl
new_name: new_very_ssl
state: present
-'''
+"""
try:
import botocore
@@ -113,29 +101,30 @@ except ImportError:
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
@AWSRetry.jittered_backoff()
def _list_server_certficates():
- paginator = client.get_paginator('list_server_certificates')
- return paginator.paginate().build_full_result()['ServerCertificateMetadataList']
+ paginator = client.get_paginator("list_server_certificates")
+ return paginator.paginate().build_full_result()["ServerCertificateMetadataList"]
def check_duplicate_cert(new_cert):
- orig_cert_names = list(c['ServerCertificateName'] for c in _list_server_certficates())
+ orig_cert_names = list(c["ServerCertificateName"] for c in _list_server_certficates())
for cert_name in orig_cert_names:
cert = get_server_certificate(cert_name)
if not cert:
continue
- cert_body = cert.get('certificate_body', None)
+ cert_body = cert.get("certificate_body", None)
if not _compare_cert(new_cert, cert_body):
continue
module.fail_json(
changed=False,
- msg='This certificate already exists under the name {0} and dup_ok=False'.format(cert_name),
+ msg=f"This certificate already exists under the name {cert_name} and dup_ok=False",
duplicate_cert=cert,
)
@@ -148,25 +137,25 @@ def _compare_cert(cert_a, cert_b):
# Trim out the whitespace before comparing the certs. While this could mean
# an invalid cert 'matches' a valid cert, that's better than some stray
# whitespace breaking things
- cert_a.replace('\r', '')
- cert_a.replace('\n', '')
- cert_a.replace(' ', '')
- cert_b.replace('\r', '')
- cert_b.replace('\n', '')
- cert_b.replace(' ', '')
+ cert_a.replace("\r", "")
+ cert_a.replace("\n", "")
+ cert_a.replace(" ", "")
+ cert_b.replace("\r", "")
+ cert_b.replace("\n", "")
+ cert_b.replace(" ", "")
return cert_a == cert_b
def update_server_certificate(current_cert):
changed = False
- cert = module.params.get('cert')
- cert_chain = module.params.get('cert_chain')
+ cert = module.params.get("cert")
+ cert_chain = module.params.get("cert_chain")
- if not _compare_cert(cert, current_cert.get('certificate_body', None)):
- module.fail_json(msg='Modifying the certificate body is not supported by AWS')
- if not _compare_cert(cert_chain, current_cert.get('certificate_chain', None)):
- module.fail_json(msg='Modifying the chaining certificate is not supported by AWS')
+ if not _compare_cert(cert, current_cert.get("certificate_body", None)):
+ module.fail_json(msg="Modifying the certificate body is not supported by AWS")
+ if not _compare_cert(cert_chain, current_cert.get("certificate_chain", None)):
+ module.fail_json(msg="Modifying the chaining certificate is not supported by AWS")
# We can't compare keys.
if module.check_mode:
@@ -179,15 +168,15 @@ def update_server_certificate(current_cert):
def create_server_certificate():
- cert = module.params.get('cert')
- key = module.params.get('key')
- cert_chain = module.params.get('cert_chain')
+ cert = module.params.get("cert")
+ key = module.params.get("key")
+ cert_chain = module.params.get("cert_chain")
- if not module.params.get('dup_ok'):
+ if not module.params.get("dup_ok"):
check_duplicate_cert(cert)
- path = module.params.get('path')
- name = module.params.get('name')
+ path = module.params.get("path")
+ name = module.params.get("name")
params = dict(
ServerCertificateName=name,
@@ -196,28 +185,25 @@ def create_server_certificate():
)
if cert_chain:
- params['CertificateChain'] = cert_chain
+ params["CertificateChain"] = cert_chain
if path:
- params['Path'] = path
+ params["Path"] = path
if module.check_mode:
return True
try:
- client.upload_server_certificate(
- aws_retry=True,
- **params
- )
+ client.upload_server_certificate(aws_retry=True, **params)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to update server certificate {0}'.format(name))
+ module.fail_json_aws(e, msg=f"Failed to update server certificate {name}")
return True
def rename_server_certificate(current_cert):
- name = module.params.get('name')
- new_name = module.params.get('new_name')
- new_path = module.params.get('new_path')
+ name = module.params.get("name")
+ new_name = module.params.get("new_name")
+ new_path = module.params.get("new_path")
changes = dict()
@@ -226,16 +212,16 @@ def rename_server_certificate(current_cert):
current_cert = get_server_certificate(new_name)
else:
if new_name:
- changes['NewServerCertificateName'] = new_name
+ changes["NewServerCertificateName"] = new_name
- cert_metadata = current_cert.get('server_certificate_metadata', {})
+ cert_metadata = current_cert.get("server_certificate_metadata", {})
if not current_cert:
- module.fail_json(msg='Unable to find certificate {0}'.format(name))
+ module.fail_json(msg=f"Unable to find certificate {name}")
- current_path = cert_metadata.get('path', None)
+ current_path = cert_metadata.get("path", None)
if new_path and current_path != new_path:
- changes['NewPath'] = new_path
+ changes["NewPath"] = new_path
if not changes:
return False
@@ -244,14 +230,9 @@ def rename_server_certificate(current_cert):
return True
try:
- client.update_server_certificate(
- aws_retry=True,
- ServerCertificateName=name,
- **changes
- )
+ client.update_server_certificate(aws_retry=True, ServerCertificateName=name, **changes)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to update server certificate {0}'.format(name),
- changes=changes)
+ module.fail_json_aws(e, msg=f"Failed to update server certificate {name}", changes=changes)
return True
@@ -263,17 +244,20 @@ def delete_server_certificate(current_cert):
if module.check_mode:
return True
- name = module.params.get('name')
+ name = module.params.get("name")
try:
result = client.delete_server_certificate(
aws_retry=True,
ServerCertificateName=name,
)
- except is_boto3_error_code('NoSuchEntity'):
+ except is_boto3_error_code("NoSuchEntity"):
return None
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, msg='Failed to delete server certificate {0}'.format(name))
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(e, msg=f"Failed to delete server certificate {name}")
return True
@@ -286,11 +270,14 @@ def get_server_certificate(name):
aws_retry=True,
ServerCertificateName=name,
)
- except is_boto3_error_code('NoSuchEntity'):
+ except is_boto3_error_code("NoSuchEntity"):
return None
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, msg='Failed to get server certificate {0}'.format(name))
- cert = dict(camel_dict_to_snake_dict(result.get('ServerCertificate')))
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(e, msg=f"Failed to get server certificate {name}")
+ cert = dict(camel_dict_to_snake_dict(result.get("ServerCertificate")))
return cert
@@ -300,75 +287,74 @@ def compatability_results(current_cert):
if not current_cert:
return compat_results
- metadata = current_cert.get('server_certificate_metadata', {})
-
- if current_cert.get('certificate_body', None):
- compat_results['cert_body'] = current_cert.get('certificate_body')
- if current_cert.get('certificate_chain', None):
- compat_results['chain_cert_body'] = current_cert.get('certificate_chain')
- if metadata.get('arn', None):
- compat_results['arn'] = metadata.get('arn')
- if metadata.get('expiration', None):
- compat_results['expiration_date'] = metadata.get('expiration')
- if metadata.get('path', None):
- compat_results['cert_path'] = metadata.get('path')
- if metadata.get('server_certificate_name', None):
- compat_results['name'] = metadata.get('server_certificate_name')
- if metadata.get('upload_date', None):
- compat_results['upload_date'] = metadata.get('upload_date')
+ metadata = current_cert.get("server_certificate_metadata", {})
+
+ if current_cert.get("certificate_body", None):
+ compat_results["cert_body"] = current_cert.get("certificate_body")
+ if current_cert.get("certificate_chain", None):
+ compat_results["chain_cert_body"] = current_cert.get("certificate_chain")
+ if metadata.get("arn", None):
+ compat_results["arn"] = metadata.get("arn")
+ if metadata.get("expiration", None):
+ compat_results["expiration_date"] = metadata.get("expiration")
+ if metadata.get("path", None):
+ compat_results["cert_path"] = metadata.get("path")
+ if metadata.get("server_certificate_name", None):
+ compat_results["name"] = metadata.get("server_certificate_name")
+ if metadata.get("upload_date", None):
+ compat_results["upload_date"] = metadata.get("upload_date")
return compat_results
def main():
-
global module
global client
argument_spec = dict(
- state=dict(required=True, choices=['present', 'absent']),
+ state=dict(required=True, choices=["present", "absent"]),
name=dict(required=True),
cert=dict(),
key=dict(no_log=True),
cert_chain=dict(),
new_name=dict(),
- path=dict(default='/'),
+ path=dict(default="/"),
new_path=dict(),
- dup_ok=dict(type='bool', default=True),
+ dup_ok=dict(type="bool", default=True),
)
module = AnsibleAWSModule(
argument_spec=argument_spec,
mutually_exclusive=[
- ['new_path', 'key'],
- ['new_path', 'cert'],
- ['new_path', 'cert_chain'],
- ['new_name', 'key'],
- ['new_name', 'cert'],
- ['new_name', 'cert_chain'],
+ ["new_path", "key"],
+ ["new_path", "cert"],
+ ["new_path", "cert_chain"],
+ ["new_name", "key"],
+ ["new_name", "cert"],
+ ["new_name", "cert_chain"],
],
supports_check_mode=True,
)
- client = module.client('iam', retry_decorator=AWSRetry.jittered_backoff())
+ client = module.client("iam", retry_decorator=AWSRetry.jittered_backoff())
- state = module.params.get('state')
- name = module.params.get('name')
- path = module.params.get('path')
- new_name = module.params.get('new_name')
- new_path = module.params.get('new_path')
- dup_ok = module.params.get('dup_ok')
+ state = module.params.get("state")
+ name = module.params.get("name")
+ path = module.params.get("path")
+ new_name = module.params.get("new_name")
+ new_path = module.params.get("new_path")
+ dup_ok = module.params.get("dup_ok")
current_cert = get_server_certificate(name)
results = dict()
- if state == 'absent':
+ if state == "absent":
changed = delete_server_certificate(current_cert)
if changed:
- results['deleted_cert'] = name
+ results["deleted_cert"] = name
else:
- msg = 'Certificate with the name {0} already absent'.format(name)
- results['msg'] = msg
+ msg = f"Certificate with the name {name} already absent"
+ results["msg"] = msg
else:
if new_name or new_path:
changed = rename_server_certificate(current_cert)
@@ -382,16 +368,13 @@ def main():
changed = create_server_certificate()
updated_cert = get_server_certificate(name)
- results['server_certificate'] = updated_cert
+ results["server_certificate"] = updated_cert
compat_results = compatability_results(updated_cert)
if compat_results:
results.update(compat_results)
- module.exit_json(
- changed=changed,
- **results
- )
+ module.exit_json(changed=changed, **results)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/iam_server_certificate_info.py b/ansible_collections/community/aws/plugins/modules/iam_server_certificate_info.py
index ee0dc590d..5504cb746 100644
--- a/ansible_collections/community/aws/plugins/modules/iam_server_certificate_info.py
+++ b/ansible_collections/community/aws/plugins/modules/iam_server_certificate_info.py
@@ -1,32 +1,30 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: iam_server_certificate_info
version_added: 1.0.0
short_description: Retrieve the information of a server certificate
description:
- Retrieve the attributes of a server certificate.
-author: "Allen Sanabria (@linuxdynasty)"
+author:
+ - "Allen Sanabria (@linuxdynasty)"
options:
name:
description:
- The name of the server certificate you are retrieving attributes for.
type: str
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
-
-'''
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
- name: Retrieve server certificate
community.aws.iam_server_certificate_info:
name: production-cert
@@ -37,9 +35,9 @@ EXAMPLES = '''
name: production-cert
register: server_cert
failed_when: "{{ server_cert.results | length == 0 }}"
-'''
+"""
-RETURN = '''
+RETURN = r"""
server_certificate_id:
description: The 21 character certificate id
returned: success
@@ -75,16 +73,15 @@ upload_date:
returned: success
type: str
sample: "2015-04-25T00:36:40+00:00"
-'''
+"""
try:
import botocore
- import botocore.exceptions
except ImportError:
pass # Handled by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def get_server_certs(iam, name=None):
@@ -113,22 +110,24 @@ def get_server_certs(iam, name=None):
results = dict()
try:
if name:
- server_certs = [iam.get_server_certificate(ServerCertificateName=name)['ServerCertificate']]
+ server_certs = [iam.get_server_certificate(ServerCertificateName=name)["ServerCertificate"]]
else:
- server_certs = iam.list_server_certificates()['ServerCertificateMetadataList']
+ server_certs = iam.list_server_certificates()["ServerCertificateMetadataList"]
for server_cert in server_certs:
if not name:
- server_cert = iam.get_server_certificate(ServerCertificateName=server_cert['ServerCertificateName'])['ServerCertificate']
- cert_md = server_cert['ServerCertificateMetadata']
- results[cert_md['ServerCertificateName']] = {
- 'certificate_body': server_cert['CertificateBody'],
- 'server_certificate_id': cert_md['ServerCertificateId'],
- 'server_certificate_name': cert_md['ServerCertificateName'],
- 'arn': cert_md['Arn'],
- 'path': cert_md['Path'],
- 'expiration': cert_md['Expiration'].isoformat(),
- 'upload_date': cert_md['UploadDate'].isoformat(),
+ server_cert = iam.get_server_certificate(ServerCertificateName=server_cert["ServerCertificateName"])[
+ "ServerCertificate"
+ ]
+ cert_md = server_cert["ServerCertificateMetadata"]
+ results[cert_md["ServerCertificateName"]] = {
+ "certificate_body": server_cert["CertificateBody"],
+ "server_certificate_id": cert_md["ServerCertificateId"],
+ "server_certificate_name": cert_md["ServerCertificateName"],
+ "arn": cert_md["Arn"],
+ "path": cert_md["Path"],
+ "expiration": cert_md["Expiration"].isoformat(),
+ "upload_date": cert_md["UploadDate"].isoformat(),
}
except botocore.exceptions.ClientError:
@@ -139,7 +138,7 @@ def get_server_certs(iam, name=None):
def main():
argument_spec = dict(
- name=dict(type='str'),
+ name=dict(type="str"),
)
module = AnsibleAWSModule(
@@ -148,14 +147,14 @@ def main():
)
try:
- iam = module.client('iam')
+ iam = module.client("iam")
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to connect to AWS')
+ module.fail_json_aws(e, msg="Failed to connect to AWS")
- cert_name = module.params.get('name')
+ cert_name = module.params.get("name")
results = get_server_certs(iam, cert_name)
module.exit_json(results=results)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/inspector_target.py b/ansible_collections/community/aws/plugins/modules/inspector_target.py
index 2ec9e9a0e..f9ec6d53a 100644
--- a/ansible_collections/community/aws/plugins/modules/inspector_target.py
+++ b/ansible_collections/community/aws/plugins/modules/inspector_target.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright (c) 2018 Dennis Conrad for Sainsbury's
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: inspector_target
version_added: 1.0.0
@@ -39,12 +37,12 @@ options:
- Required if I(state=present).
type: dict
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
- name: Create my_target Assessment Target
community.aws.inspector_target:
name: my_target
@@ -62,9 +60,9 @@ EXAMPLES = '''
community.aws.inspector_target:
name: my_target
state: absent
-'''
+"""
-RETURN = '''
+RETURN = r"""
arn:
description: The ARN that specifies the Amazon Inspector assessment target.
returned: success
@@ -97,32 +95,32 @@ updated_at:
returned: success
type: str
sample: "2018-01-29T13:48:51.958000+00:00"
-'''
-
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import (
- ansible_dict_to_boto3_tag_list,
- boto3_tag_list_to_ansible_dict,
- camel_dict_to_snake_dict,
- compare_aws_tags,
-)
+"""
try:
import botocore
except ImportError:
pass # caught by AnsibleAWSModule
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import ansible_dict_to_boto3_tag_list
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import compare_aws_tags
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
+
@AWSRetry.jittered_backoff(retries=5, delay=5, backoff=2.0)
def main():
argument_spec = dict(
name=dict(required=True),
- state=dict(choices=['absent', 'present'], default='present'),
- tags=dict(type='dict'),
+ state=dict(choices=["absent", "present"], default="present"),
+ tags=dict(type="dict"),
)
- required_if = [['state', 'present', ['tags']]]
+ required_if = [["state", "present", ["tags"]]]
module = AnsibleAWSModule(
argument_spec=argument_spec,
@@ -130,29 +128,37 @@ def main():
required_if=required_if,
)
- name = module.params.get('name')
- state = module.params.get('state').lower()
- tags = module.params.get('tags')
+ name = module.params.get("name")
+ state = module.params.get("state").lower()
+ tags = module.params.get("tags")
if tags:
- tags = ansible_dict_to_boto3_tag_list(tags, 'key', 'value')
+ tags = ansible_dict_to_boto3_tag_list(tags, "key", "value")
- client = module.client('inspector')
+ client = module.client("inspector")
try:
existing_target_arn = client.list_assessment_targets(
- filter={'assessmentTargetNamePattern': name},
- ).get('assessmentTargetArns')[0]
+ filter={"assessmentTargetNamePattern": name},
+ ).get(
+ "assessmentTargetArns"
+ )[0]
existing_target = camel_dict_to_snake_dict(
client.describe_assessment_targets(
assessmentTargetArns=[existing_target_arn],
- ).get('assessmentTargets')[0]
+ ).get(
+ "assessmentTargets"
+ )[0]
)
- existing_resource_group_arn = existing_target.get('resource_group_arn')
- existing_resource_group_tags = client.describe_resource_groups(
- resourceGroupArns=[existing_resource_group_arn],
- ).get('resourceGroups')[0].get('tags')
+ existing_resource_group_arn = existing_target.get("resource_group_arn")
+ existing_resource_group_tags = (
+ client.describe_resource_groups(
+ resourceGroupArns=[existing_resource_group_arn],
+ )
+ .get("resourceGroups")[0]
+ .get("tags")
+ )
target_exists = True
except (
@@ -163,23 +169,18 @@ def main():
except IndexError:
target_exists = False
- if state == 'present' and target_exists:
+ if state == "present" and target_exists:
ansible_dict_tags = boto3_tag_list_to_ansible_dict(tags)
- ansible_dict_existing_tags = boto3_tag_list_to_ansible_dict(
- existing_resource_group_tags
- )
- tags_to_add, tags_to_remove = compare_aws_tags(
- ansible_dict_tags,
- ansible_dict_existing_tags
- )
+ ansible_dict_existing_tags = boto3_tag_list_to_ansible_dict(existing_resource_group_tags)
+ tags_to_add, tags_to_remove = compare_aws_tags(ansible_dict_tags, ansible_dict_existing_tags)
if not (tags_to_add or tags_to_remove):
- existing_target.update({'tags': ansible_dict_existing_tags})
+ existing_target.update({"tags": ansible_dict_existing_tags})
module.exit_json(changed=False, **existing_target)
else:
try:
updated_resource_group_arn = client.create_resource_group(
resourceGroupTags=tags,
- ).get('resourceGroupArn')
+ ).get("resourceGroupArn")
client.update_assessment_target(
assessmentTargetArn=existing_target_arn,
@@ -190,10 +191,12 @@ def main():
updated_target = camel_dict_to_snake_dict(
client.describe_assessment_targets(
assessmentTargetArns=[existing_target_arn],
- ).get('assessmentTargets')[0]
+ ).get(
+ "assessmentTargets"
+ )[0]
)
- updated_target.update({'tags': ansible_dict_tags})
+ updated_target.update({"tags": ansible_dict_tags})
module.exit_json(changed=True, **updated_target)
except (
botocore.exceptions.BotoCoreError,
@@ -201,24 +204,26 @@ def main():
) as e:
module.fail_json_aws(e, msg="trying to update target")
- elif state == 'present' and not target_exists:
+ elif state == "present" and not target_exists:
try:
new_resource_group_arn = client.create_resource_group(
resourceGroupTags=tags,
- ).get('resourceGroupArn')
+ ).get("resourceGroupArn")
new_target_arn = client.create_assessment_target(
assessmentTargetName=name,
resourceGroupArn=new_resource_group_arn,
- ).get('assessmentTargetArn')
+ ).get("assessmentTargetArn")
new_target = camel_dict_to_snake_dict(
client.describe_assessment_targets(
assessmentTargetArns=[new_target_arn],
- ).get('assessmentTargets')[0]
+ ).get(
+ "assessmentTargets"
+ )[0]
)
- new_target.update({'tags': boto3_tag_list_to_ansible_dict(tags)})
+ new_target.update({"tags": boto3_tag_list_to_ansible_dict(tags)})
module.exit_json(changed=True, **new_target)
except (
botocore.exceptions.BotoCoreError,
@@ -226,7 +231,7 @@ def main():
) as e:
module.fail_json_aws(e, msg="trying to create target")
- elif state == 'absent' and target_exists:
+ elif state == "absent" and target_exists:
try:
client.delete_assessment_target(
assessmentTargetArn=existing_target_arn,
@@ -238,9 +243,9 @@ def main():
) as e:
module.fail_json_aws(e, msg="trying to delete target")
- elif state == 'absent' and not target_exists:
+ elif state == "absent" and not target_exists:
module.exit_json(changed=False)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/kinesis_stream.py b/ansible_collections/community/aws/plugins/modules/kinesis_stream.py
index e4c5d76df..d1ba65c86 100644
--- a/ansible_collections/community/aws/plugins/modules/kinesis_stream.py
+++ b/ansible_collections/community/aws/plugins/modules/kinesis_stream.py
@@ -1,22 +1,21 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: kinesis_stream
version_added: 1.0.0
short_description: Manage a Kinesis Stream.
description:
- - Create or Delete a Kinesis Stream.
- - Update the retention period of a Kinesis Stream.
- - Update Tags on a Kinesis Stream.
- - Enable/disable server side encryption on a Kinesis Stream.
-author: Allen Sanabria (@linuxdynasty)
+ - Create or Delete a Kinesis Stream.
+ - Update the retention period of a Kinesis Stream.
+ - Update Tags on a Kinesis Stream.
+ - Enable/disable server side encryption on a Kinesis Stream.
+author:
+ - Allen Sanabria (@linuxdynasty)
options:
name:
description:
@@ -73,13 +72,12 @@ options:
- The GUID or alias for the KMS key.
type: str
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-'''
-
-EXAMPLES = '''
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide for details.
# Basic creation example:
@@ -148,9 +146,9 @@ EXAMPLES = '''
wait: true
wait_timeout: 600
register: test_stream
-'''
+"""
-RETURN = '''
+RETURN = r"""
stream_name:
description: The name of the Kinesis Stream.
returned: when state == present.
@@ -179,7 +177,7 @@ tags:
"Name": "Splunk",
"Env": "development"
}
-'''
+"""
import time
@@ -191,9 +189,10 @@ except ImportError:
from ansible.module_utils._text import to_native
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import compare_aws_tags
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import compare_aws_tags
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def get_tags(client, stream_name):
@@ -210,16 +209,14 @@ def get_tags(client, stream_name):
Returns:
Tuple (bool, str, dict)
"""
- err_msg = ''
+ err_msg = ""
success = False
params = {
- 'StreamName': stream_name,
+ "StreamName": stream_name,
}
results = dict()
try:
- results = (
- client.list_tags_for_stream(**params)['Tags']
- )
+ results = client.list_tags_for_stream(**params)["Tags"]
success = True
except botocore.exceptions.ClientError as e:
err_msg = to_native(e)
@@ -240,28 +237,26 @@ def find_stream(client, stream_name):
Returns:
Tuple (bool, str, dict)
"""
- err_msg = ''
+ err_msg = ""
success = False
params = {
- 'StreamName': stream_name,
+ "StreamName": stream_name,
}
results = dict()
has_more_shards = True
shards = list()
try:
while has_more_shards:
- results = (
- client.describe_stream(**params)['StreamDescription']
- )
- shards.extend(results.pop('Shards'))
- has_more_shards = results['HasMoreShards']
+ results = client.describe_stream(**params)["StreamDescription"]
+ shards.extend(results.pop("Shards"))
+ has_more_shards = results["HasMoreShards"]
if has_more_shards:
- params['ExclusiveStartShardId'] = shards[-1]['ShardId']
- results['Shards'] = shards
- num_closed_shards = len([s for s in shards if 'EndingSequenceNumber' in s['SequenceNumberRange']])
- results['OpenShardsCount'] = len(shards) - num_closed_shards
- results['ClosedShardsCount'] = num_closed_shards
- results['ShardsCount'] = len(shards)
+ params["ExclusiveStartShardId"] = shards[-1]["ShardId"]
+ results["Shards"] = shards
+ num_closed_shards = len([s for s in shards if "EndingSequenceNumber" in s["SequenceNumberRange"]])
+ results["OpenShardsCount"] = len(shards) - num_closed_shards
+ results["ClosedShardsCount"] = num_closed_shards
+ results["ShardsCount"] = len(shards)
success = True
except botocore.exceptions.ClientError as e:
err_msg = to_native(e)
@@ -269,8 +264,7 @@ def find_stream(client, stream_name):
return success, err_msg, results
-def wait_for_status(client, stream_name, status, wait_timeout=300,
- check_mode=False):
+def wait_for_status(client, stream_name, status, wait_timeout=300, check_mode=False):
"""Wait for the status to change for a Kinesis Stream.
Args:
client (botocore.client.EC2): Boto3 client
@@ -299,16 +293,14 @@ def wait_for_status(client, stream_name, status, wait_timeout=300,
while wait_timeout > time.time():
try:
- find_success, find_msg, stream = (
- find_stream(client, stream_name)
- )
+ find_success, find_msg, stream = find_stream(client, stream_name)
if check_mode:
status_achieved = True
break
- elif status != 'DELETING':
+ elif status != "DELETING":
if find_success and stream:
- if stream.get('StreamStatus') == status:
+ if stream.get("StreamStatus") == status:
status_achieved = True
break
@@ -325,12 +317,12 @@ def wait_for_status(client, stream_name, status, wait_timeout=300,
if not status_achieved:
err_msg = "Wait time out reached, while waiting for results"
else:
- err_msg = "Status {0} achieved successfully".format(status)
+ err_msg = f"Status {status} achieved successfully"
return status_achieved, err_msg, stream
-def tags_action(client, stream_name, tags, action='create', check_mode=False):
+def tags_action(client, stream_name, tags, action="create", check_mode=False):
"""Create or delete multiple tags from a Kinesis Stream.
Args:
client (botocore.client.EC2): Boto3 client.
@@ -357,26 +349,26 @@ def tags_action(client, stream_name, tags, action='create', check_mode=False):
"""
success = False
err_msg = ""
- params = {'StreamName': stream_name}
+ params = {"StreamName": stream_name}
try:
if not check_mode:
- if action == 'create':
- params['Tags'] = tags
+ if action == "create":
+ params["Tags"] = tags
client.add_tags_to_stream(**params)
success = True
- elif action == 'delete':
- params['TagKeys'] = tags
+ elif action == "delete":
+ params["TagKeys"] = tags
client.remove_tags_from_stream(**params)
success = True
else:
- err_msg = 'Invalid action {0}'.format(action)
+ err_msg = f"Invalid action {action}"
else:
- if action == 'create':
+ if action == "create":
success = True
- elif action == 'delete':
+ elif action == "delete":
success = True
else:
- err_msg = 'Invalid action {0}'.format(action)
+ err_msg = f"Invalid action {action}"
except botocore.exceptions.ClientError as e:
err_msg = to_native(e)
@@ -406,32 +398,25 @@ def update_tags(client, stream_name, tags, check_mode=False):
"""
success = False
changed = False
- err_msg = ''
- tag_success, tag_msg, current_tags = (
- get_tags(client, stream_name)
- )
+ err_msg = ""
+ tag_success, tag_msg, current_tags = get_tags(client, stream_name)
tags_to_set, tags_to_delete = compare_aws_tags(
- current_tags, tags,
+ current_tags,
+ tags,
purge_tags=True,
)
if tags_to_delete:
- delete_success, delete_msg = (
- tags_action(
- client, stream_name, tags_to_delete, action='delete',
- check_mode=check_mode
- )
+ delete_success, delete_msg = tags_action(
+ client, stream_name, tags_to_delete, action="delete", check_mode=check_mode
)
if not delete_success:
return delete_success, changed, delete_msg
- tag_msg = 'Tags removed'
+ tag_msg = "Tags removed"
if tags_to_set:
- create_success, create_msg = (
- tags_action(
- client, stream_name, tags_to_set, action='create',
- check_mode=check_mode
- )
+ create_success, create_msg = tags_action(
+ client, stream_name, tags_to_set, action="create", check_mode=check_mode
)
if create_success:
changed = True
@@ -440,8 +425,7 @@ def update_tags(client, stream_name, tags, check_mode=False):
return success, changed, err_msg
-def stream_action(client, stream_name, shard_count=1, action='create',
- timeout=300, check_mode=False):
+def stream_action(client, stream_name, shard_count=1, action="create", timeout=300, check_mode=False):
"""Create or Delete an Amazon Kinesis Stream.
Args:
client (botocore.client.EC2): Boto3 client.
@@ -465,28 +449,26 @@ def stream_action(client, stream_name, shard_count=1, action='create',
List (bool, str)
"""
success = False
- err_msg = ''
- params = {
- 'StreamName': stream_name
- }
+ err_msg = ""
+ params = {"StreamName": stream_name}
try:
if not check_mode:
- if action == 'create':
- params['ShardCount'] = shard_count
+ if action == "create":
+ params["ShardCount"] = shard_count
client.create_stream(**params)
success = True
- elif action == 'delete':
+ elif action == "delete":
client.delete_stream(**params)
success = True
else:
- err_msg = 'Invalid action {0}'.format(action)
+ err_msg = f"Invalid action {action}"
else:
- if action == 'create':
+ if action == "create":
success = True
- elif action == 'delete':
+ elif action == "delete":
success = True
else:
- err_msg = 'Invalid action {0}'.format(action)
+ err_msg = f"Invalid action {action}"
except botocore.exceptions.ClientError as e:
err_msg = to_native(e)
@@ -494,8 +476,9 @@ def stream_action(client, stream_name, shard_count=1, action='create',
return success, err_msg
-def stream_encryption_action(client, stream_name, action='start_encryption', encryption_type='', key_id='',
- timeout=300, check_mode=False):
+def stream_encryption_action(
+ client, stream_name, action="start_encryption", encryption_type="", key_id="", timeout=300, check_mode=False
+):
"""Create, Encrypt or Delete an Amazon Kinesis Stream.
Args:
client (botocore.client.EC2): Boto3 client.
@@ -521,31 +504,29 @@ def stream_encryption_action(client, stream_name, action='start_encryption', enc
List (bool, str)
"""
success = False
- err_msg = ''
- params = {
- 'StreamName': stream_name
- }
+ err_msg = ""
+ params = {"StreamName": stream_name}
try:
if not check_mode:
- if action == 'start_encryption':
- params['EncryptionType'] = encryption_type
- params['KeyId'] = key_id
+ if action == "start_encryption":
+ params["EncryptionType"] = encryption_type
+ params["KeyId"] = key_id
client.start_stream_encryption(**params)
success = True
- elif action == 'stop_encryption':
- params['EncryptionType'] = encryption_type
- params['KeyId'] = key_id
+ elif action == "stop_encryption":
+ params["EncryptionType"] = encryption_type
+ params["KeyId"] = key_id
client.stop_stream_encryption(**params)
success = True
else:
- err_msg = 'Invalid encryption action {0}'.format(action)
+ err_msg = f"Invalid encryption action {action}"
else:
- if action == 'start_encryption':
+ if action == "start_encryption":
success = True
- elif action == 'stop_encryption':
+ elif action == "stop_encryption":
success = True
else:
- err_msg = 'Invalid encryption action {0}'.format(action)
+ err_msg = f"Invalid encryption action {action}"
except botocore.exceptions.ClientError as e:
err_msg = to_native(e)
@@ -553,8 +534,7 @@ def stream_encryption_action(client, stream_name, action='start_encryption', enc
return success, err_msg
-def retention_action(client, stream_name, retention_period=24,
- action='increase', check_mode=False):
+def retention_action(client, stream_name, retention_period=24, action="increase", check_mode=False):
"""Increase or Decrease the retention of messages in the Kinesis stream.
Args:
client (botocore.client.EC2): Boto3 client.
@@ -579,35 +559,29 @@ def retention_action(client, stream_name, retention_period=24,
Tuple (bool, str)
"""
success = False
- err_msg = ''
- params = {
- 'StreamName': stream_name
- }
+ err_msg = ""
+ params = {"StreamName": stream_name}
try:
if not check_mode:
- if action == 'increase':
- params['RetentionPeriodHours'] = retention_period
+ if action == "increase":
+ params["RetentionPeriodHours"] = retention_period
client.increase_stream_retention_period(**params)
success = True
- err_msg = (
- 'Retention Period increased successfully to {0}'.format(retention_period)
- )
- elif action == 'decrease':
- params['RetentionPeriodHours'] = retention_period
+ err_msg = f"Retention Period increased successfully to {retention_period}"
+ elif action == "decrease":
+ params["RetentionPeriodHours"] = retention_period
client.decrease_stream_retention_period(**params)
success = True
- err_msg = (
- 'Retention Period decreased successfully to {0}'.format(retention_period)
- )
+ err_msg = f"Retention Period decreased successfully to {retention_period}"
else:
- err_msg = 'Invalid action {0}'.format(action)
+ err_msg = f"Invalid action {action}"
else:
- if action == 'increase':
+ if action == "increase":
success = True
- elif action == 'decrease':
+ elif action == "decrease":
success = True
else:
- err_msg = 'Invalid action {0}'.format(action)
+ err_msg = f"Invalid action {action}"
except botocore.exceptions.ClientError as e:
err_msg = to_native(e)
@@ -637,13 +611,10 @@ def update_shard_count(client, stream_name, number_of_shards=1, check_mode=False
Tuple (bool, str)
"""
success = True
- err_msg = ''
- params = {
- 'StreamName': stream_name,
- 'ScalingType': 'UNIFORM_SCALING'
- }
+ err_msg = ""
+ params = {"StreamName": stream_name, "ScalingType": "UNIFORM_SCALING"}
if not check_mode:
- params['TargetShardCount'] = number_of_shards
+ params["TargetShardCount"] = number_of_shards
try:
client.update_shard_count(**params)
except botocore.exceptions.ClientError as e:
@@ -652,8 +623,17 @@ def update_shard_count(client, stream_name, number_of_shards=1, check_mode=False
return success, err_msg
-def update(client, current_stream, stream_name, number_of_shards=1, retention_period=None,
- tags=None, wait=False, wait_timeout=300, check_mode=False):
+def update(
+ client,
+ current_stream,
+ stream_name,
+ number_of_shards=1,
+ retention_period=None,
+ tags=None,
+ wait=False,
+ wait_timeout=300,
+ check_mode=False,
+):
"""Update an Amazon Kinesis Stream.
Args:
client (botocore.client.EC2): Boto3 client.
@@ -693,44 +673,29 @@ def update(client, current_stream, stream_name, number_of_shards=1, retention_pe
"""
success = True
changed = False
- err_msg = ''
+ err_msg = ""
if retention_period:
if wait:
- wait_success, wait_msg, current_stream = (
- wait_for_status(
- client, stream_name, 'ACTIVE', wait_timeout,
- check_mode=check_mode
- )
+ wait_success, wait_msg, current_stream = wait_for_status(
+ client, stream_name, "ACTIVE", wait_timeout, check_mode=check_mode
)
if not wait_success:
return wait_success, False, wait_msg
- if current_stream.get('StreamStatus') == 'ACTIVE':
+ if current_stream.get("StreamStatus") == "ACTIVE":
retention_changed = False
- if retention_period > current_stream['RetentionPeriodHours']:
- retention_changed, retention_msg = (
- retention_action(
- client, stream_name, retention_period, action='increase',
- check_mode=check_mode
- )
+ if retention_period > current_stream["RetentionPeriodHours"]:
+ retention_changed, retention_msg = retention_action(
+ client, stream_name, retention_period, action="increase", check_mode=check_mode
)
- elif retention_period < current_stream['RetentionPeriodHours']:
- retention_changed, retention_msg = (
- retention_action(
- client, stream_name, retention_period, action='decrease',
- check_mode=check_mode
- )
+ elif retention_period < current_stream["RetentionPeriodHours"]:
+ retention_changed, retention_msg = retention_action(
+ client, stream_name, retention_period, action="decrease", check_mode=check_mode
)
- elif retention_period == current_stream['RetentionPeriodHours']:
- retention_msg = (
- 'Retention {0} is the same as {1}'
- .format(
- retention_period,
- current_stream['RetentionPeriodHours']
- )
- )
+ elif retention_period == current_stream["RetentionPeriodHours"]:
+ retention_msg = f"Retention {retention_period} is the same as {current_stream['RetentionPeriodHours']}"
success = True
if retention_changed:
@@ -739,36 +704,26 @@ def update(client, current_stream, stream_name, number_of_shards=1, retention_pe
err_msg = retention_msg
if changed and wait:
- wait_success, wait_msg, current_stream = (
- wait_for_status(
- client, stream_name, 'ACTIVE', wait_timeout,
- check_mode=check_mode
- )
+ wait_success, wait_msg, current_stream = wait_for_status(
+ client, stream_name, "ACTIVE", wait_timeout, check_mode=check_mode
)
if not wait_success:
return wait_success, False, wait_msg
elif changed and not wait:
- stream_found, stream_msg, current_stream = (
- find_stream(client, stream_name)
- )
+ stream_found, stream_msg, current_stream = find_stream(client, stream_name)
if stream_found:
- if current_stream['StreamStatus'] != 'ACTIVE':
- err_msg = (
- 'Retention Period for {0} is in the process of updating'
- .format(stream_name)
- )
+ if current_stream["StreamStatus"] != "ACTIVE":
+ err_msg = f"Retention Period for {stream_name} is in the process of updating"
return success, changed, err_msg
else:
err_msg = (
- 'StreamStatus has to be ACTIVE in order to modify the retention period. Current status is {0}'
- .format(current_stream.get('StreamStatus', 'UNKNOWN'))
+ "StreamStatus has to be ACTIVE in order to modify the retention period."
+ f" Current status is {current_stream.get('StreamStatus', 'UNKNOWN')}"
)
return success, changed, err_msg
- if current_stream['OpenShardsCount'] != number_of_shards:
- success, err_msg = (
- update_shard_count(client, stream_name, number_of_shards, check_mode=check_mode)
- )
+ if current_stream["OpenShardsCount"] != number_of_shards:
+ success, err_msg = update_shard_count(client, stream_name, number_of_shards, check_mode=check_mode)
if not success:
return success, changed, err_msg
@@ -776,47 +731,42 @@ def update(client, current_stream, stream_name, number_of_shards=1, retention_pe
changed = True
if wait:
- wait_success, wait_msg, current_stream = (
- wait_for_status(
- client, stream_name, 'ACTIVE', wait_timeout,
- check_mode=check_mode
- )
+ wait_success, wait_msg, current_stream = wait_for_status(
+ client, stream_name, "ACTIVE", wait_timeout, check_mode=check_mode
)
if not wait_success:
return wait_success, changed, wait_msg
else:
- stream_found, stream_msg, current_stream = (
- find_stream(client, stream_name)
- )
- if stream_found and current_stream['StreamStatus'] != 'ACTIVE':
- err_msg = (
- 'Number of shards for {0} is in the process of updating'
- .format(stream_name)
- )
+ stream_found, stream_msg, current_stream = find_stream(client, stream_name)
+ if stream_found and current_stream["StreamStatus"] != "ACTIVE":
+ err_msg = f"Number of shards for {stream_name} is in the process of updating"
return success, changed, err_msg
if tags:
- tag_success, tag_changed, err_msg = (
- update_tags(client, stream_name, tags, check_mode=check_mode)
- )
+ tag_success, tag_changed, err_msg = update_tags(client, stream_name, tags, check_mode=check_mode)
changed |= tag_changed
if wait:
- success, err_msg, status_stream = (
- wait_for_status(
- client, stream_name, 'ACTIVE', wait_timeout,
- check_mode=check_mode
- )
+ success, err_msg, status_stream = wait_for_status(
+ client, stream_name, "ACTIVE", wait_timeout, check_mode=check_mode
)
if success and changed:
- err_msg = 'Kinesis Stream {0} updated successfully.'.format(stream_name)
+ err_msg = f"Kinesis Stream {stream_name} updated successfully."
elif success and not changed:
- err_msg = 'Kinesis Stream {0} did not change.'.format(stream_name)
+ err_msg = f"Kinesis Stream {stream_name} did not change."
return success, changed, err_msg
-def create_stream(client, stream_name, number_of_shards=1, retention_period=None,
- tags=None, wait=False, wait_timeout=300, check_mode=False):
+def create_stream(
+ client,
+ stream_name,
+ number_of_shards=1,
+ retention_period=None,
+ tags=None,
+ wait=False,
+ wait_timeout=300,
+ check_mode=False,
+):
"""Create an Amazon Kinesis Stream.
Args:
client (botocore.client.EC2): Boto3 client.
@@ -848,79 +798,59 @@ def create_stream(client, stream_name, number_of_shards=1, retention_period=None
"""
success = False
changed = False
- err_msg = ''
+ err_msg = ""
results = dict()
- stream_found, stream_msg, current_stream = (
- find_stream(client, stream_name)
- )
+ stream_found, stream_msg, current_stream = find_stream(client, stream_name)
- if stream_found and current_stream.get('StreamStatus') == 'DELETING' and wait:
- wait_success, wait_msg, current_stream = (
- wait_for_status(
- client, stream_name, 'ACTIVE', wait_timeout,
- check_mode=check_mode
- )
+ if stream_found and current_stream.get("StreamStatus") == "DELETING" and wait:
+ wait_success, wait_msg, current_stream = wait_for_status(
+ client, stream_name, "ACTIVE", wait_timeout, check_mode=check_mode
)
- if stream_found and current_stream.get('StreamStatus') != 'DELETING':
+ if stream_found and current_stream.get("StreamStatus") != "DELETING":
success, changed, err_msg = update(
- client, current_stream, stream_name, number_of_shards,
- retention_period, tags, wait, wait_timeout, check_mode=check_mode
+ client,
+ current_stream,
+ stream_name,
+ number_of_shards,
+ retention_period,
+ tags,
+ wait,
+ wait_timeout,
+ check_mode=check_mode,
)
else:
- create_success, create_msg = (
- stream_action(
- client, stream_name, number_of_shards, action='create',
- check_mode=check_mode
- )
+ create_success, create_msg = stream_action(
+ client, stream_name, number_of_shards, action="create", check_mode=check_mode
)
if not create_success:
changed = True
- err_msg = 'Failed to create Kinesis stream: {0}'.format(create_msg)
+ err_msg = f"Failed to create Kinesis stream: {create_msg}"
return False, True, err_msg, {}
else:
changed = True
if wait:
- wait_success, wait_msg, results = (
- wait_for_status(
- client, stream_name, 'ACTIVE', wait_timeout,
- check_mode=check_mode
- )
- )
- err_msg = (
- 'Kinesis Stream {0} is in the process of being created'
- .format(stream_name)
+ wait_success, wait_msg, results = wait_for_status(
+ client, stream_name, "ACTIVE", wait_timeout, check_mode=check_mode
)
+ err_msg = f"Kinesis Stream {stream_name} is in the process of being created"
if not wait_success:
return wait_success, True, wait_msg, results
else:
- err_msg = (
- 'Kinesis Stream {0} created successfully'
- .format(stream_name)
- )
+ err_msg = f"Kinesis Stream {stream_name} created successfully"
if tags:
- changed, err_msg = (
- tags_action(
- client, stream_name, tags, action='create',
- check_mode=check_mode
- )
- )
+ changed, err_msg = tags_action(client, stream_name, tags, action="create", check_mode=check_mode)
if changed:
success = True
if not success:
return success, changed, err_msg, results
- stream_found, stream_msg, current_stream = (
- find_stream(client, stream_name)
- )
- if retention_period and current_stream.get('StreamStatus') == 'ACTIVE':
- changed, err_msg = (
- retention_action(
- client, stream_name, retention_period, action='increase',
- check_mode=check_mode
- )
+ stream_found, stream_msg, current_stream = find_stream(client, stream_name)
+ if retention_period and current_stream.get("StreamStatus") == "ACTIVE":
+ changed, err_msg = retention_action(
+ client, stream_name, retention_period, action="increase", check_mode=check_mode
)
if changed:
success = True
@@ -928,19 +858,15 @@ def create_stream(client, stream_name, number_of_shards=1, retention_period=None
return success, changed, err_msg, results
else:
err_msg = (
- 'StreamStatus has to be ACTIVE in order to modify the retention period. Current status is {0}'
- .format(current_stream.get('StreamStatus', 'UNKNOWN'))
+ "StreamStatus has to be ACTIVE in order to modify the retention period."
+ f" Current status is {current_stream.get('StreamStatus', 'UNKNOWN')}"
)
success = create_success
changed = True
if success:
- stream_found, stream_msg, results = (
- find_stream(client, stream_name)
- )
- tag_success, tag_msg, current_tags = (
- get_tags(client, stream_name)
- )
+ stream_found, stream_msg, results = find_stream(client, stream_name)
+ tag_success, tag_msg, current_tags = get_tags(client, stream_name)
if check_mode:
current_tags = tags
@@ -948,13 +874,12 @@ def create_stream(client, stream_name, number_of_shards=1, retention_period=None
current_tags = dict()
results = camel_dict_to_snake_dict(results)
- results['tags'] = current_tags
+ results["tags"] = current_tags
return success, changed, err_msg, results
-def delete_stream(client, stream_name, wait=False, wait_timeout=300,
- check_mode=False):
+def delete_stream(client, stream_name, wait=False, wait_timeout=300, check_mode=False):
"""Delete an Amazon Kinesis Stream.
Args:
client (botocore.client.EC2): Boto3 client.
@@ -978,44 +903,33 @@ def delete_stream(client, stream_name, wait=False, wait_timeout=300,
"""
success = False
changed = False
- err_msg = ''
+ err_msg = ""
results = dict()
- stream_found, stream_msg, current_stream = (
- find_stream(client, stream_name)
- )
+ stream_found, stream_msg, current_stream = find_stream(client, stream_name)
if stream_found:
- success, err_msg = (
- stream_action(
- client, stream_name, action='delete', check_mode=check_mode
- )
- )
+ success, err_msg = stream_action(client, stream_name, action="delete", check_mode=check_mode)
if success:
changed = True
if wait:
- success, err_msg, results = (
- wait_for_status(
- client, stream_name, 'DELETING', wait_timeout,
- check_mode=check_mode
- )
+ success, err_msg, results = wait_for_status(
+ client, stream_name, "DELETING", wait_timeout, check_mode=check_mode
)
- err_msg = 'Stream {0} deleted successfully'.format(stream_name)
+ err_msg = f"Stream {stream_name} deleted successfully"
if not success:
return success, True, err_msg, results
else:
- err_msg = (
- 'Stream {0} is in the process of being deleted'
- .format(stream_name)
- )
+ err_msg = f"Stream {stream_name} is in the process of being deleted"
else:
success = True
changed = False
- err_msg = 'Stream {0} does not exist'.format(stream_name)
+ err_msg = f"Stream {stream_name} does not exist"
return success, changed, err_msg, results
-def start_stream_encryption(client, stream_name, encryption_type='', key_id='',
- wait=False, wait_timeout=300, check_mode=False):
+def start_stream_encryption(
+ client, stream_name, encryption_type="", key_id="", wait=False, wait_timeout=300, check_mode=False
+):
"""Start encryption on an Amazon Kinesis Stream.
Args:
client (botocore.client.EC2): Boto3 client.
@@ -1043,65 +957,56 @@ def start_stream_encryption(client, stream_name, encryption_type='', key_id='',
"""
success = False
changed = False
- err_msg = ''
- params = {
- 'StreamName': stream_name
- }
+ err_msg = ""
+ params = {"StreamName": stream_name}
results = dict()
- stream_found, stream_msg, current_stream = (
- find_stream(client, stream_name)
- )
+ stream_found, stream_msg, current_stream = find_stream(client, stream_name)
if stream_found:
- if (current_stream.get("EncryptionType") == encryption_type and current_stream.get("KeyId") == key_id):
+ if current_stream.get("EncryptionType") == encryption_type and current_stream.get("KeyId") == key_id:
changed = False
success = True
- err_msg = 'Kinesis Stream {0} encryption already configured.'.format(stream_name)
+ err_msg = f"Kinesis Stream {stream_name} encryption already configured."
else:
- success, err_msg = (
- stream_encryption_action(
- client, stream_name, action='start_encryption', encryption_type=encryption_type, key_id=key_id, check_mode=check_mode
- )
+ success, err_msg = stream_encryption_action(
+ client,
+ stream_name,
+ action="start_encryption",
+ encryption_type=encryption_type,
+ key_id=key_id,
+ check_mode=check_mode,
)
if success:
changed = True
if wait:
- success, err_msg, results = (
- wait_for_status(
- client, stream_name, 'ACTIVE', wait_timeout,
- check_mode=check_mode
- )
+ success, err_msg, results = wait_for_status(
+ client, stream_name, "ACTIVE", wait_timeout, check_mode=check_mode
)
- err_msg = 'Kinesis Stream {0} encryption started successfully.'.format(stream_name)
+ err_msg = f"Kinesis Stream {stream_name} encryption started successfully."
if not success:
return success, True, err_msg, results
else:
- err_msg = (
- 'Kinesis Stream {0} is in the process of starting encryption.'.format(stream_name)
- )
+ err_msg = f"Kinesis Stream {stream_name} is in the process of starting encryption."
else:
success = True
changed = False
- err_msg = 'Kinesis Stream {0} does not exist'.format(stream_name)
+ err_msg = f"Kinesis Stream {stream_name} does not exist"
if success:
- stream_found, stream_msg, results = (
- find_stream(client, stream_name)
- )
- tag_success, tag_msg, current_tags = (
- get_tags(client, stream_name)
- )
+ stream_found, stream_msg, results = find_stream(client, stream_name)
+ tag_success, tag_msg, current_tags = get_tags(client, stream_name)
if not current_tags:
current_tags = dict()
results = camel_dict_to_snake_dict(results)
- results['tags'] = current_tags
+ results["tags"] = current_tags
return success, changed, err_msg, results
-def stop_stream_encryption(client, stream_name, encryption_type='', key_id='',
- wait=True, wait_timeout=300, check_mode=False):
+def stop_stream_encryption(
+ client, stream_name, encryption_type="", key_id="", wait=True, wait_timeout=300, check_mode=False
+):
"""Stop encryption on an Amazon Kinesis Stream.
Args:
client (botocore.client.EC2): Boto3 client.
@@ -1127,57 +1032,47 @@ def stop_stream_encryption(client, stream_name, encryption_type='', key_id='',
"""
success = False
changed = False
- err_msg = ''
- params = {
- 'StreamName': stream_name
- }
+ err_msg = ""
+ params = {"StreamName": stream_name}
results = dict()
- stream_found, stream_msg, current_stream = (
- find_stream(client, stream_name)
- )
+ stream_found, stream_msg, current_stream = find_stream(client, stream_name)
if stream_found:
- if current_stream.get('EncryptionType') == 'KMS':
- success, err_msg = (
- stream_encryption_action(
- client, stream_name, action='stop_encryption', key_id=key_id, encryption_type=encryption_type, check_mode=check_mode
- )
+ if current_stream.get("EncryptionType") == "KMS":
+ success, err_msg = stream_encryption_action(
+ client,
+ stream_name,
+ action="stop_encryption",
+ key_id=key_id,
+ encryption_type=encryption_type,
+ check_mode=check_mode,
)
changed = success
if wait:
- success, err_msg, results = (
- wait_for_status(
- client, stream_name, 'ACTIVE', wait_timeout,
- check_mode=check_mode
- )
+ success, err_msg, results = wait_for_status(
+ client, stream_name, "ACTIVE", wait_timeout, check_mode=check_mode
)
if not success:
return success, True, err_msg, results
- err_msg = 'Kinesis Stream {0} encryption stopped successfully.'.format(stream_name)
+ err_msg = f"Kinesis Stream {stream_name} encryption stopped successfully."
else:
- err_msg = (
- 'Stream {0} is in the process of stopping encryption.'.format(stream_name)
- )
- elif current_stream.get('EncryptionType') == 'NONE':
+ err_msg = f"Stream {stream_name} is in the process of stopping encryption."
+ elif current_stream.get("EncryptionType") == "NONE":
success = True
- err_msg = 'Kinesis Stream {0} encryption already stopped.'.format(stream_name)
+ err_msg = f"Kinesis Stream {stream_name} encryption already stopped."
else:
success = True
changed = False
- err_msg = 'Stream {0} does not exist.'.format(stream_name)
+ err_msg = f"Stream {stream_name} does not exist."
if success:
- stream_found, stream_msg, results = (
- find_stream(client, stream_name)
- )
- tag_success, tag_msg, current_tags = (
- get_tags(client, stream_name)
- )
+ stream_found, stream_msg, results = find_stream(client, stream_name)
+ tag_success, tag_msg, current_tags = get_tags(client, stream_name)
if not current_tags:
current_tags = dict()
results = camel_dict_to_snake_dict(results)
- results['tags'] = current_tags
+ results["tags"] = current_tags
return success, changed, err_msg, results
@@ -1185,78 +1080,65 @@ def stop_stream_encryption(client, stream_name, encryption_type='', key_id='',
def main():
argument_spec = dict(
name=dict(required=True),
- shards=dict(default=None, required=False, type='int'),
- retention_period=dict(default=None, required=False, type='int'),
- tags=dict(default=None, required=False, type='dict', aliases=['resource_tags']),
- wait=dict(default=True, required=False, type='bool'),
- wait_timeout=dict(default=300, required=False, type='int'),
- state=dict(default='present', choices=['present', 'absent']),
- encryption_type=dict(required=False, choices=['NONE', 'KMS']),
- key_id=dict(required=False, type='str'),
- encryption_state=dict(required=False, choices=['enabled', 'disabled']),
+ shards=dict(default=None, required=False, type="int"),
+ retention_period=dict(default=None, required=False, type="int"),
+ tags=dict(default=None, required=False, type="dict", aliases=["resource_tags"]),
+ wait=dict(default=True, required=False, type="bool"),
+ wait_timeout=dict(default=300, required=False, type="int"),
+ state=dict(default="present", choices=["present", "absent"]),
+ encryption_type=dict(required=False, choices=["NONE", "KMS"]),
+ key_id=dict(required=False, type="str"),
+ encryption_state=dict(required=False, choices=["enabled", "disabled"]),
)
module = AnsibleAWSModule(
argument_spec=argument_spec,
supports_check_mode=True,
)
- retention_period = module.params.get('retention_period')
- stream_name = module.params.get('name')
- shards = module.params.get('shards')
- state = module.params.get('state')
- tags = module.params.get('tags')
- wait = module.params.get('wait')
- wait_timeout = module.params.get('wait_timeout')
- encryption_type = module.params.get('encryption_type')
- key_id = module.params.get('key_id')
- encryption_state = module.params.get('encryption_state')
+ retention_period = module.params.get("retention_period")
+ stream_name = module.params.get("name")
+ shards = module.params.get("shards")
+ state = module.params.get("state")
+ tags = module.params.get("tags")
+ wait = module.params.get("wait")
+ wait_timeout = module.params.get("wait_timeout")
+ encryption_type = module.params.get("encryption_type")
+ key_id = module.params.get("key_id")
+ encryption_state = module.params.get("encryption_state")
- if state == 'present' and not shards:
- module.fail_json(msg='Shards is required when state == present.')
+ if state == "present" and not shards:
+ module.fail_json(msg="Shards is required when state == present.")
if retention_period:
if retention_period < 24:
- module.fail_json(msg='Retention period can not be less than 24 hours.')
+ module.fail_json(msg="Retention period can not be less than 24 hours.")
check_mode = module.check_mode
try:
- client = module.client('kinesis')
+ client = module.client("kinesis")
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to connect to AWS')
+ module.fail_json_aws(e, msg="Failed to connect to AWS")
- if state == 'present':
- success, changed, err_msg, results = (
- create_stream(
- client, stream_name, shards, retention_period, tags,
- wait, wait_timeout, check_mode
- )
+ if state == "present":
+ success, changed, err_msg, results = create_stream(
+ client, stream_name, shards, retention_period, tags, wait, wait_timeout, check_mode
)
- if encryption_state == 'enabled':
- success, changed, err_msg, results = (
- start_stream_encryption(
- client, stream_name, encryption_type, key_id, wait, wait_timeout, check_mode
- )
+ if encryption_state == "enabled":
+ success, changed, err_msg, results = start_stream_encryption(
+ client, stream_name, encryption_type, key_id, wait, wait_timeout, check_mode
)
- elif encryption_state == 'disabled':
- success, changed, err_msg, results = (
- stop_stream_encryption(
- client, stream_name, encryption_type, key_id, wait, wait_timeout, check_mode
- )
+ elif encryption_state == "disabled":
+ success, changed, err_msg, results = stop_stream_encryption(
+ client, stream_name, encryption_type, key_id, wait, wait_timeout, check_mode
)
- elif state == 'absent':
- success, changed, err_msg, results = (
- delete_stream(client, stream_name, wait, wait_timeout, check_mode)
- )
+ elif state == "absent":
+ success, changed, err_msg, results = delete_stream(client, stream_name, wait, wait_timeout, check_mode)
if success:
- module.exit_json(
- success=success, changed=changed, msg=err_msg, **results
- )
+ module.exit_json(success=success, changed=changed, msg=err_msg, **results)
else:
- module.fail_json(
- success=success, changed=changed, msg=err_msg, result=results
- )
+ module.fail_json(success=success, changed=changed, msg=err_msg, result=results)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/lightsail.py b/ansible_collections/community/aws/plugins/modules/lightsail.py
index 5e4035154..16b4338e7 100644
--- a/ansible_collections/community/aws/plugins/modules/lightsail.py
+++ b/ansible_collections/community/aws/plugins/modules/lightsail.py
@@ -1,23 +1,20 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: lightsail
version_added: 1.0.0
short_description: Manage instances in AWS Lightsail
description:
- - Manage instances in AWS Lightsail.
- - Instance tagging is not yet supported in this module.
+ - Manage instances in AWS Lightsail.
+ - Instance tagging is not yet supported in this module.
author:
- - "Nick Ball (@nickball)"
- - "Prasad Katti (@prasadkatti)"
+ - "Nick Ball (@nickball)"
+ - "Prasad Katti (@prasadkatti)"
options:
state:
description:
@@ -50,6 +47,38 @@ options:
- Launch script that can configure the instance with additional data.
type: str
default: ''
+ public_ports:
+ description:
+ - A list of dictionaries to describe the ports to open for the specified instance.
+ type: list
+ elements: dict
+ suboptions:
+ from_port:
+ description: The first port in a range of open ports on the instance.
+ type: int
+ required: true
+ to_port:
+ description: The last port in a range of open ports on the instance.
+ type: int
+ required: true
+ protocol:
+ description: The IP protocol name accepted for the defined range of open ports.
+ type: str
+ choices: ['tcp', 'all', 'udp', 'icmp']
+ required: true
+ cidrs:
+ description:
+ - The IPv4 address, or range of IPv4 addresses (in CIDR notation) that are allowed to connect to the instance through the ports, and the protocol.
+ - One of I(cidrs) or I(ipv6_cidrs) must be specified.
+ type: list
+ elements: str
+ ipv6_cidrs:
+ description:
+ - The IPv6 address, or range of IPv6 addresses (in CIDR notation) that are allowed to connect to the instance through the ports, and the protocol.
+ - One of I(cidrs) or I(ipv6_cidrs) must be specified.
+ type: list
+ elements: str
+ version_added: 6.0.0
key_pair_name:
description:
- Name of the key pair to use with the instance.
@@ -69,14 +98,13 @@ options:
type: int
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
-
-'''
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
- name: Create a new Lightsail instance
community.aws.lightsail:
state: present
@@ -87,6 +115,12 @@ EXAMPLES = '''
bundle_id: nano_1_0
key_pair_name: id_rsa
user_data: " echo 'hello world' > /home/ubuntu/test.txt"
+ public_ports:
+ - from_port: 22
+ to_port: 22
+ protocol: "tcp"
+ cidrs: ["0.0.0.0/0"]
+ ipv6_cidrs: ["::/0"]
register: my_instance
- name: Delete an instance
@@ -94,10 +128,9 @@ EXAMPLES = '''
state: absent
region: us-east-1
name: my_instance
+"""
-'''
-
-RETURN = '''
+RETURN = r"""
changed:
description: if a snapshot has been modified/created
returned: always
@@ -149,7 +182,7 @@ instance:
name: running
support_code: "123456789012/i-0997c97831ee21e33"
username: "ubuntu"
-'''
+"""
import time
@@ -160,22 +193,23 @@ except ImportError:
pass
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+from ansible.module_utils.common.dict_transformations import snake_dict_to_camel_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
-def find_instance_info(module, client, instance_name, fail_if_not_found=False):
+def find_instance_info(module, client, instance_name, fail_if_not_found=False):
try:
res = client.get_instance(instanceName=instance_name)
- except is_boto3_error_code('NotFoundException') as e:
+ except is_boto3_error_code("NotFoundException") as e:
if fail_if_not_found:
module.fail_json_aws(e)
return None
except botocore.exceptions.ClientError as e: # pylint: disable=duplicate-except
module.fail_json_aws(e)
- return res['instance']
+ return res["instance"]
def wait_for_instance_state(module, client, instance_name, states):
@@ -183,53 +217,69 @@ def wait_for_instance_state(module, client, instance_name, states):
`states` is a list of instance states that we are waiting for.
"""
- wait_timeout = module.params.get('wait_timeout')
+ wait_timeout = module.params.get("wait_timeout")
wait_max = time.time() + wait_timeout
while wait_max > time.time():
try:
instance = find_instance_info(module, client, instance_name)
- if instance['state']['name'] in states:
+ if instance["state"]["name"] in states:
break
time.sleep(5)
except botocore.exceptions.ClientError as e:
module.fail_json_aws(e)
else:
- module.fail_json(msg='Timed out waiting for instance "{0}" to get to one of the following states -'
- ' {1}'.format(instance_name, states))
+ module.fail_json(
+ msg=f'Timed out waiting for instance "{instance_name}" to get to one of the following states - {states}'
+ )
-def create_instance(module, client, instance_name):
+def update_public_ports(module, client, instance_name):
+ try:
+ client.put_instance_public_ports(
+ portInfos=snake_dict_to_camel_dict(module.params.get("public_ports")),
+ instanceName=instance_name,
+ )
+ except botocore.exceptions.ClientError as e:
+ module.fail_json_aws(e)
+
+def create_or_update_instance(module, client, instance_name):
inst = find_instance_info(module, client, instance_name)
- if inst:
- module.exit_json(changed=False, instance=camel_dict_to_snake_dict(inst))
- else:
- create_params = {'instanceNames': [instance_name],
- 'availabilityZone': module.params.get('zone'),
- 'blueprintId': module.params.get('blueprint_id'),
- 'bundleId': module.params.get('bundle_id'),
- 'userData': module.params.get('user_data')}
- key_pair_name = module.params.get('key_pair_name')
+ if not inst:
+ create_params = {
+ "instanceNames": [instance_name],
+ "availabilityZone": module.params.get("zone"),
+ "blueprintId": module.params.get("blueprint_id"),
+ "bundleId": module.params.get("bundle_id"),
+ "userData": module.params.get("user_data"),
+ }
+
+ key_pair_name = module.params.get("key_pair_name")
if key_pair_name:
- create_params['keyPairName'] = key_pair_name
+ create_params["keyPairName"] = key_pair_name
try:
client.create_instances(**create_params)
except botocore.exceptions.ClientError as e:
module.fail_json_aws(e)
- wait = module.params.get('wait')
+ wait = module.params.get("wait")
if wait:
- desired_states = ['running']
+ desired_states = ["running"]
wait_for_instance_state(module, client, instance_name, desired_states)
- inst = find_instance_info(module, client, instance_name, fail_if_not_found=True)
- module.exit_json(changed=True, instance=camel_dict_to_snake_dict(inst))
+ if module.params.get("public_ports") is not None:
+ update_public_ports(module, client, instance_name)
+ after_update_inst = find_instance_info(module, client, instance_name, fail_if_not_found=True)
+ module.exit_json(
+ changed=after_update_inst != inst,
+ instance=camel_dict_to_snake_dict(after_update_inst),
+ )
-def delete_instance(module, client, instance_name):
+def delete_instance(module, client, instance_name):
changed = False
inst = find_instance_info(module, client, instance_name)
@@ -237,7 +287,7 @@ def delete_instance(module, client, instance_name):
module.exit_json(changed=changed, instance={})
# Wait for instance to exit transition state before deleting
- desired_states = ['running', 'stopped']
+ desired_states = ["running", "stopped"]
wait_for_instance_state(module, client, instance_name, desired_states)
try:
@@ -278,13 +328,13 @@ def start_or_stop_instance(module, client, instance_name, state):
inst = find_instance_info(module, client, instance_name, fail_if_not_found=True)
# Wait for instance to exit transition state before state change
- desired_states = ['running', 'stopped']
+ desired_states = ["running", "stopped"]
wait_for_instance_state(module, client, instance_name, desired_states)
# Try state change
- if inst and inst['state']['name'] != state:
+ if inst and inst["state"]["name"] != state:
try:
- if state == 'running':
+ if state == "running":
client.start_instance(instanceName=instance_name)
else:
client.stop_instance(instanceName=instance_name)
@@ -294,7 +344,7 @@ def start_or_stop_instance(module, client, instance_name, state):
# Grab current instance info
inst = find_instance_info(module, client, instance_name)
- wait = module.params.get('wait')
+ wait = module.params.get("wait")
if wait:
desired_states = [state]
wait_for_instance_state(module, client, instance_name, desired_states)
@@ -304,37 +354,50 @@ def start_or_stop_instance(module, client, instance_name, state):
def main():
-
argument_spec = dict(
- name=dict(type='str', required=True),
- state=dict(type='str', default='present', choices=['present', 'absent', 'stopped', 'running', 'restarted',
- 'rebooted']),
- zone=dict(type='str'),
- blueprint_id=dict(type='str'),
- bundle_id=dict(type='str'),
- key_pair_name=dict(type='str'),
- user_data=dict(type='str', default=''),
- wait=dict(type='bool', default=True),
- wait_timeout=dict(default=300, type='int'),
+ name=dict(type="str", required=True),
+ state=dict(
+ type="str", default="present", choices=["present", "absent", "stopped", "running", "restarted", "rebooted"]
+ ),
+ zone=dict(type="str"),
+ blueprint_id=dict(type="str"),
+ bundle_id=dict(type="str"),
+ key_pair_name=dict(type="str"),
+ user_data=dict(type="str", default=""),
+ wait=dict(type="bool", default=True),
+ wait_timeout=dict(default=300, type="int"),
+ public_ports=dict(
+ type="list",
+ elements="dict",
+ options=dict(
+ from_port=dict(type="int", required=True),
+ to_port=dict(type="int", required=True),
+ protocol=dict(type="str", choices=["tcp", "all", "udp", "icmp"], required=True),
+ cidrs=dict(type="list", elements="str"),
+ ipv6_cidrs=dict(type="list", elements="str"),
+ ),
+ required_one_of=[("cidrs", "ipv6_cidrs")],
+ ),
)
- module = AnsibleAWSModule(argument_spec=argument_spec,
- required_if=[['state', 'present', ('zone', 'blueprint_id', 'bundle_id')]])
+ module = AnsibleAWSModule(
+ argument_spec=argument_spec, required_if=[["state", "present", ("zone", "blueprint_id", "bundle_id")]]
+ )
- client = module.client('lightsail')
+ client = module.client("lightsail")
- name = module.params.get('name')
- state = module.params.get('state')
+ name = module.params.get("name")
+ state = module.params.get("state")
- if state == 'present':
- create_instance(module, client, name)
- elif state == 'absent':
+ if state == "present":
+ create_or_update_instance(module, client, name)
+ elif state == "absent":
delete_instance(module, client, name)
- elif state in ('running', 'stopped'):
+ elif state in ("running", "stopped"):
start_or_stop_instance(module, client, name, state)
- elif state in ('restarted', 'rebooted'):
+ elif state in ("restarted", "rebooted"):
restart_instance(module, client, name)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/lightsail_snapshot.py b/ansible_collections/community/aws/plugins/modules/lightsail_snapshot.py
new file mode 100644
index 000000000..1d0d178aa
--- /dev/null
+++ b/ansible_collections/community/aws/plugins/modules/lightsail_snapshot.py
@@ -0,0 +1,205 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: Contributors to the Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r"""
+---
+module: lightsail_snapshot
+version_added: "6.0.0"
+short_description: Creates snapshots of AWS Lightsail instances
+description:
+ - Creates snapshots of AWS Lightsail instances.
+author:
+ - "Nuno Saavedra (@Nfsaavedra)"
+options:
+ state:
+ description:
+ - Indicate desired state of the target.
+ default: present
+ choices: ['present', 'absent']
+ type: str
+ snapshot_name:
+ description: Name of the new instance snapshot.
+ required: true
+ type: str
+ instance_name:
+ description:
+ - Name of the instance to create the snapshot.
+ - Required when I(state=present).
+ type: str
+ wait:
+ description:
+ - Wait for the instance snapshot to be created before returning.
+ type: bool
+ default: true
+ wait_timeout:
+ description:
+ - How long before I(wait) gives up, in seconds.
+ default: 300
+ type: int
+
+extends_documentation_fragment:
+- amazon.aws.common.modules
+- amazon.aws.region.modules
+- amazon.aws.boto3
+"""
+
+EXAMPLES = r"""
+- name: Create AWS Lightsail snapshot
+ lightsail_snapshot:
+ region: us-east-1
+ snapshot_name: "my_instance_snapshot"
+ instance_name: "my_instance"
+
+- name: Delete AWS Lightsail snapshot
+ lightsail_snapshot:
+ region: us-east-1
+ snapshot_name: "my_instance_snapshot"
+ state: absent
+"""
+
+RETURN = r"""
+changed:
+ description: if a snapshot has been modified/created
+ returned: always
+ type: bool
+ sample:
+ changed: true
+snapshot:
+ description: instance snapshot data
+ type: dict
+ returned: always
+ sample:
+ arn: "arn:aws:lightsail:us-east-1:070807442430:InstanceSnapshot/54b0f785-7132-443d-9e32-95a6825636a4"
+ created_at: "2023-02-23T18:46:11.183000+00:00"
+ from_attached_disks: []
+ from_blueprint_id: "amazon_linux_2"
+ from_bundle_id: "nano_2_0"
+ from_instance_arn: "arn:aws:lightsail:us-east-1:070807442430:Instance/5ca1e7ca-a994-4e19-bb82-deb9d79e9ca3"
+ from_instance_name: "my_instance"
+ is_from_auto_snapshot: false
+ location:
+ availability_zone: "all"
+ region_name: "us-east-1"
+ name: "my_instance_snapshot"
+ resource_type: "InstanceSnapshot"
+ size_in_gb: 20
+ state: "available"
+ support_code: "351201681302/ami-06b48e5589f1e248b"
+ tags: []
+"""
+
+import time
+
+try:
+ import botocore
+except ImportError:
+ # will be caught by AnsibleAWSModule
+ pass
+
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
+
+
+def find_instance_snapshot_info(module, client, instance_snapshot_name, fail_if_not_found=False):
+ try:
+ res = client.get_instance_snapshot(instanceSnapshotName=instance_snapshot_name)
+ except is_boto3_error_code("NotFoundException") as e:
+ if fail_if_not_found:
+ module.fail_json_aws(e)
+ return None
+ except botocore.exceptions.ClientError as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(e)
+ return res["instanceSnapshot"]
+
+
+def wait_for_instance_snapshot(module, client, instance_snapshot_name):
+ wait_timeout = module.params.get("wait_timeout")
+ wait_max = time.time() + wait_timeout
+ snapshot = find_instance_snapshot_info(module, client, instance_snapshot_name)
+
+ while wait_max > time.time():
+ snapshot = find_instance_snapshot_info(module, client, instance_snapshot_name)
+ current_state = snapshot["state"]
+ if current_state != "pending":
+ break
+ time.sleep(5)
+ else:
+ module.fail_json(msg=f'Timed out waiting for instance snapshot "{instance_snapshot_name}" to be created.')
+
+ return snapshot
+
+
+def create_snapshot(module, client):
+ snapshot = find_instance_snapshot_info(module, client, module.params.get("snapshot_name"))
+ new_instance = snapshot is None
+
+ if module.check_mode or not new_instance:
+ snapshot = snapshot if snapshot is not None else {}
+ module.exit_json(
+ changed=new_instance,
+ instance_snapshot=camel_dict_to_snake_dict(snapshot),
+ )
+
+ try:
+ snapshot = client.create_instance_snapshot(
+ instanceSnapshotName=module.params.get("snapshot_name"),
+ instanceName=module.params.get("instance_name"),
+ )
+ except botocore.exceptions.ClientError as e:
+ module.fail_json_aws(e)
+
+ if module.params.get("wait"):
+ snapshot = wait_for_instance_snapshot(module, client, module.params.get("snapshot_name"))
+
+ module.exit_json(
+ changed=new_instance,
+ instance_snapshot=camel_dict_to_snake_dict(snapshot),
+ )
+
+
+def delete_snapshot(module, client):
+ snapshot = find_instance_snapshot_info(module, client, module.params.get("snapshot_name"))
+ if module.check_mode or snapshot is None:
+ changed = not (snapshot is None)
+ instance = snapshot if changed else {}
+ module.exit_json(changed=changed, instance=instance)
+
+ try:
+ client.delete_instance_snapshot(instanceSnapshotName=module.params.get("snapshot_name"))
+ except botocore.exceptions.ClientError as e:
+ module.fail_json_aws(e)
+
+ module.exit_json(changed=True, instance=camel_dict_to_snake_dict(snapshot))
+
+
+def main():
+ argument_spec = dict(
+ state=dict(type="str", default="present", choices=["present", "absent"]),
+ snapshot_name=dict(type="str", required=True),
+ instance_name=dict(type="str"),
+ wait=dict(type="bool", default=True),
+ wait_timeout=dict(default=300, type="int"),
+ )
+ required_if = [
+ ["state", "present", ("instance_name",)],
+ ]
+
+ module = AnsibleAWSModule(argument_spec=argument_spec, required_if=required_if, supports_check_mode=True)
+ client = module.client("lightsail")
+
+ state = module.params.get("state")
+
+ if state == "present":
+ create_snapshot(module, client)
+ elif state == "absent":
+ delete_snapshot(module, client)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/aws/plugins/modules/lightsail_static_ip.py b/ansible_collections/community/aws/plugins/modules/lightsail_static_ip.py
index 799ff629d..40d10a86b 100644
--- a/ansible_collections/community/aws/plugins/modules/lightsail_static_ip.py
+++ b/ansible_collections/community/aws/plugins/modules/lightsail_static_ip.py
@@ -1,14 +1,10 @@
#!/usr/bin/python
-
# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: lightsail_static_ip
version_added: 4.1.0
@@ -29,13 +25,13 @@ options:
required: true
type: str
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
- name: Provision a Lightsail static IP
community.aws.lightsail_static_ip:
state: present
@@ -46,9 +42,9 @@ EXAMPLES = '''
community.aws.lightsail_static_ip:
state: absent
name: my_static_ip
-'''
+"""
-RETURN = '''
+RETURN = r"""
static_ip:
description: static_ipinstance data
returned: always
@@ -64,7 +60,7 @@ static_ip:
name: "static_ip"
resource_type: StaticIp
support_code: "123456789012/192.0.2.5"
-'''
+"""
try:
import botocore
@@ -74,30 +70,29 @@ except ImportError:
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
-def find_static_ip_info(module, client, static_ip_name, fail_if_not_found=False):
+def find_static_ip_info(module, client, static_ip_name, fail_if_not_found=False):
try:
res = client.get_static_ip(staticIpName=static_ip_name)
- except is_boto3_error_code('NotFoundException') as e:
+ except is_boto3_error_code("NotFoundException") as e:
if fail_if_not_found:
module.fail_json_aws(e)
return None
except botocore.exceptions.ClientError as e: # pylint: disable=duplicate-except
module.fail_json_aws(e)
- return res['staticIp']
+ return res["staticIp"]
def create_static_ip(module, client, static_ip_name):
-
inst = find_static_ip_info(module, client, static_ip_name)
if inst:
module.exit_json(changed=False, static_ip=camel_dict_to_snake_dict(inst))
else:
- create_params = {'staticIpName': static_ip_name}
+ create_params = {"staticIpName": static_ip_name}
try:
client.allocate_static_ip(**create_params)
@@ -110,7 +105,6 @@ def create_static_ip(module, client, static_ip_name):
def delete_static_ip(module, client, static_ip_name):
-
inst = find_static_ip_info(module, client, static_ip_name)
if inst is None:
module.exit_json(changed=False, static_ip={})
@@ -126,24 +120,23 @@ def delete_static_ip(module, client, static_ip_name):
def main():
-
argument_spec = dict(
- name=dict(type='str', required=True),
- state=dict(type='str', default='present', choices=['present', 'absent']),
+ name=dict(type="str", required=True),
+ state=dict(type="str", default="present", choices=["present", "absent"]),
)
module = AnsibleAWSModule(argument_spec=argument_spec)
- client = module.client('lightsail')
+ client = module.client("lightsail")
- name = module.params.get('name')
- state = module.params.get('state')
+ name = module.params.get("name")
+ state = module.params.get("state")
- if state == 'present':
+ if state == "present":
create_static_ip(module, client, name)
- elif state == 'absent':
+ elif state == "absent":
delete_static_ip(module, client, name)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/mq_broker.py b/ansible_collections/community/aws/plugins/modules/mq_broker.py
new file mode 100644
index 000000000..5a97fda92
--- /dev/null
+++ b/ansible_collections/community/aws/plugins/modules/mq_broker.py
@@ -0,0 +1,628 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: Contributors to the Ansible project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r"""
+---
+module: mq_broker
+version_added: 6.0.0
+short_description: MQ broker management
+description:
+ - Create/update/delete a broker.
+ - Reboot a broker.
+author:
+ - FCO (@fotto)
+options:
+ broker_name:
+ description:
+ - The Name of the MQ broker to work on.
+ type: str
+ required: true
+ state:
+ description:
+ - "C(present): Create/update broker."
+ - "C(absent): Delete broker."
+ - "C(restarted): Reboot broker."
+ choices: [ 'present', 'absent', 'restarted' ]
+ default: present
+ type: str
+ deployment_mode:
+ description:
+ - Set broker deployment type.
+ - Can be used only during creation.
+ - Defaults to C(SINGLE_INSTANCE).
+ choices: [ 'SINGLE_INSTANCE', 'ACTIVE_STANDBY_MULTI_AZ', 'CLUSTER_MULTI_AZ' ]
+ type: str
+ use_aws_owned_key:
+ description:
+ - Must be set to C(false) if I(kms_key_id) is provided as well.
+ - Can be used only during creation.
+ - Defaults to C(true).
+ type: bool
+ kms_key_id:
+ description:
+ - Use referenced key to encrypt broker data at rest.
+ - Can be used only during creation.
+ type: str
+ engine_type:
+ description:
+ - Set broker engine type.
+ - Can be used only during creation.
+ - Defaults to C(ACTIVEMQ).
+ choices: [ 'ACTIVEMQ', 'RABBITMQ' ]
+ type: str
+ maintenance_window_start_time:
+ description:
+ - Set maintenance window for automatic minor upgrades.
+ - Can be used only during creation.
+ - Not providing any value means "no maintenance window".
+ type: dict
+ publicly_accessible:
+ description:
+ - Allow/disallow public access.
+ - Can be used only during creation.
+ - Defaults to C(false).
+ type: bool
+ storage_type:
+ description:
+ - Set underlying storage type.
+ - Can be used only during creation.
+ - Defaults to C(EFS).
+ choices: [ 'EBS', 'EFS' ]
+ type: str
+ subnet_ids:
+ description:
+ - Defines where deploy broker instances to.
+ - Minimum required number depends on deployment type.
+ - Can be used only during creation.
+ type: list
+ elements: str
+ users:
+ description:
+ - This parameter allows to use a custom set of initial user(s).
+ - M(community.aws.mq_user) is the preferred way to manage (local) users
+ however a broker cannot be created without any user.
+ - If nothing is specified a default C(admin) user will be created along with brokers.
+ - Can be used only during creation. Use M(community.aws.mq_user) module for updates.
+ type: list
+ elements: dict
+ tags:
+ description:
+ - Tag newly created brokers.
+ - Can be used only during creation.
+ type: dict
+ authentication_strategy:
+ description: Choose between locally and remotely managed users.
+ choices: [ 'SIMPLE', 'LDAP' ]
+ type: str
+ auto_minor_version_upgrade:
+ description: Allow/disallow automatic minor version upgrades.
+ type: bool
+ default: true
+ engine_version:
+ description:
+ - Set engine version of broker.
+ - The special value C(latest) will pick the latest available version.
+ - The special value C(latest) is ignored on update.
+ type: str
+ host_instance_type:
+ description: Instance type of broker instances.
+ type: str
+ enable_audit_log:
+ description: Enable/disable to push audit logs to AWS CloudWatch.
+ type: bool
+ default: false
+ enable_general_log:
+ description: Enable/disable to push general logs to AWS CloudWatch.
+ type: bool
+ default: false
+ security_groups:
+ description:
+ - Associate security groups with broker.
+ - At least one must be provided during creation.
+ type: list
+ elements: str
+ wait:
+ description:
+ - Specifies whether the module waits for the desired C(state).
+ - The time to wait can be controlled by setting I(wait_timeout).
+ type: bool
+ default: false
+ version_added: 7.1.0
+ wait_timeout:
+ description:
+ - How long to wait (in seconds) for the broker to reach the desired state if I(wait=true).
+ default: 900
+ type: int
+ version_added: 7.1.0
+
+extends_documentation_fragment:
+ - amazon.aws.boto3
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+"""
+
+
+EXAMPLES = r"""
+- name: create broker (if missing) with minimal required parameters
+ community.aws.mq_broker:
+ broker_name: "{{ broker_name }}"
+ security_groups:
+ - sg_xxxxxxx
+ subnet_ids:
+ - subnet_xxx
+ - subnet_yyy
+ register: result
+
+- set_fact:
+ broker_id: "{{ result.broker['BrokerId'] }}"
+
+- name: use mq_broker_info to wait until broker is ready
+ community.aws.mq_broker_info:
+ broker_id: "{{ broker_id }}"
+ register: result
+ until: "result.broker['BrokerState'] == 'RUNNING'"
+ retries: 15
+ delay: 60
+
+- name: create or update broker with almost all parameter set including credentials
+ community.aws.mq_broker:
+ broker_name: "my_broker_2"
+ state: present
+ deployment_mode: 'ACTIVE_STANDBY_MULTI_AZ'
+ use_aws_owned_key: false
+ kms_key_id: 'my-precreted-key-id'
+ engine_type: 'ACTIVEMQ'
+ maintenance_window_start_time:
+ DayOfWeek: 'MONDAY'
+ TimeOfDay: '03:15'
+ TimeZone: 'Europe/Berlin'
+ publicly_accessible: true
+ storage_type: 'EFS'
+ security_groups:
+ - sg_xxxxxxx
+ subnet_ids:
+ - subnet_xxx
+ - subnet_yyy
+ users:
+ - Username: 'initial-user'
+ Password': 'plain-text-password'
+ ConsoleAccess: true
+ tags:
+ env: Test
+ creator: ansible
+ authentication_strategy: 'SIMPLE'
+ auto_minor_version_upgrade: true
+ engine_version: "5.15.13"
+ host_instance_type: 'mq.t3.micro'
+ enable_audit_log: true
+ enable_general_log: true
+
+- name: reboot a broker
+ community.aws.mq_broker:
+ broker_name: "my_broker_2"
+ state: restarted
+
+- name: delete a broker
+ community.aws.mq_broker:
+ broker_name: "my_broker_2"
+ state: absent
+"""
+
+RETURN = r"""
+broker:
+ description:
+ - "All API responses are converted to snake yaml except 'Tags'"
+ - "'state=present': API response of create_broker() or update_broker() call"
+ - "'state=absent': result of describe_broker() call before delete_broker() is triggerd"
+ - "'state=restarted': result of describe_broker() after reboot has been triggered"
+ type: dict
+ returned: success
+"""
+
+try:
+ import botocore
+except ImportError:
+ # handled by AnsibleAWSModule
+ pass
+
+from time import sleep
+from time import time
+
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.modules import AnsibleAWSModule
+
+PARAMS_MAP = {
+ "authentication_strategy": "AuthenticationStrategy",
+ "auto_minor_version_upgrade": "AutoMinorVersionUpgrade",
+ "broker_name": "BrokerName",
+ "deployment_mode": "DeploymentMode",
+ "use_aws_owned_key": "EncryptionOptions/UseAwsOwnedKey",
+ "kms_key_id": "EncryptionOptions/KmsKeyId",
+ "engine_type": "EngineType",
+ "engine_version": "EngineVersion",
+ "host_instance_type": "HostInstanceType",
+ "enable_audit_log": "Logs/Audit",
+ "enable_general_log": "Logs/General",
+ "maintenance_window_start_time": "MaintenanceWindowStartTime",
+ "publicly_accessible": "PubliclyAccessible",
+ "security_groups": "SecurityGroups",
+ "storage_type": "StorageType",
+ "subnet_ids": "SubnetIds",
+ "users": "Users",
+ "tags": "Tags",
+}
+
+
+DEFAULTS = {
+ "authentication_strategy": "SIMPLE",
+ "auto_minor_version_upgrade": False,
+ "deployment_mode": "SINGLE_INSTANCE",
+ "use_aws_owned_key": True,
+ "engine_type": "ACTIVEMQ",
+ "engine_version": "latest",
+ "host_instance_type": "mq.t3.micro",
+ "enable_audit_log": False,
+ "enable_general_log": False,
+ "publicly_accessible": False,
+ "storage_type": "EFS",
+}
+
+CREATE_ONLY_PARAMS = [
+ "deployment_mode",
+ "use_aws_owned_key",
+ "kms_key_id",
+ "engine_type",
+ "maintenance_window_start_time",
+ "publicly_accessible",
+ "storage_type",
+ "subnet_ids",
+ "users",
+ "tags",
+]
+
+
+def _set_kwarg(kwargs, key, value):
+ mapped_key = PARAMS_MAP[key]
+ if "/" in mapped_key:
+ key_list = mapped_key.split("/")
+ key_list.reverse()
+ else:
+ key_list = [mapped_key]
+ data = kwargs
+ while len(key_list) > 1:
+ this_key = key_list.pop()
+ if this_key not in data:
+ data[this_key] = {}
+ #
+ data = data[this_key]
+ data[key_list[0]] = value
+
+
+def _fill_kwargs(module, apply_defaults=True, ignore_create_params=False):
+ kwargs = {}
+ if apply_defaults:
+ for p_name, p_value in DEFAULTS.items():
+ _set_kwarg(kwargs, p_name, p_value)
+ for p_name in module.params:
+ if ignore_create_params and p_name in CREATE_ONLY_PARAMS:
+ # silently ignore CREATE_ONLY_PARAMS on update to
+ # make playbooks idempotent
+ continue
+ if p_name in PARAMS_MAP and module.params[p_name] is not None:
+ _set_kwarg(kwargs, p_name, module.params[p_name])
+ else:
+ # ignore
+ pass
+ return kwargs
+
+
+def __list_needs_change(current, desired):
+ if len(current) != len(desired):
+ return True
+ # equal length:
+ c_sorted = sorted(current)
+ d_sorted = sorted(desired)
+ for index, value in enumerate(current):
+ if value != desired[index]:
+ return True
+ #
+ return False
+
+
+def __dict_needs_change(current, desired):
+ # values contained in 'current' but not specified in 'desired' are ignored
+ # value contained in 'desired' but not in 'current' (unsupported attributes) are ignored
+ for key in desired:
+ if key in current:
+ if desired[key] != current[key]:
+ return True
+ #
+ return False
+
+
+def _needs_change(current, desired):
+ needs_change = False
+ for key in desired:
+ current_value = current[key]
+ desired_value = desired[key]
+ if isinstance(current_value, (int, str, bool)):
+ if current_value != desired_value:
+ needs_change = True
+ break
+ elif isinstance(current_value, list):
+ # assumption: all 'list' type settings we allow changes for have scalar values
+ if __list_needs_change(current_value, desired_value):
+ needs_change = True
+ break
+ elif isinstance(current_value, dict):
+ # assumption: all 'dict' type settings we allow changes for have scalar values
+ if __dict_needs_change(current_value, desired_value):
+ needs_change = True
+ break
+ else:
+ # unexpected type
+ needs_change = True
+ break
+ #
+ return needs_change
+
+
+def get_latest_engine_version(conn, module, engine_type):
+ try:
+ response = conn.describe_broker_engine_types(EngineType=engine_type)
+ return response["BrokerEngineTypes"][0]["EngineVersions"][0]["Name"]
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ module.fail_json_aws(e, msg="Couldn't list engine versions")
+
+
+def get_broker_id(conn, module):
+ try:
+ broker_name = module.params["broker_name"]
+ broker_id = None
+ response = conn.list_brokers(MaxResults=100)
+ for broker in response["BrokerSummaries"]:
+ if broker["BrokerName"] == broker_name:
+ broker_id = broker["BrokerId"]
+ break
+ return broker_id
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ module.fail_json_aws(e, msg="Couldn't list broker brokers.")
+
+
+def get_broker_info(conn, module, broker_id):
+ try:
+ return conn.describe_broker(BrokerId=broker_id)
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ module.fail_json_aws(e, msg="Couldn't get broker details.")
+
+
+def wait_for_status(conn, module):
+ interval_secs = 5
+ timeout = module.params.get("wait_timeout", 900)
+ broker_name = module.params.get("broker_name")
+ desired_state = module.params.get("state")
+ done = False
+
+ paginator = conn.get_paginator("list_brokers")
+ page_iterator = paginator.paginate(PaginationConfig={"MaxItems": 100, "PageSize": 100, "StartingToken": ""})
+ wait_timeout = time() + timeout
+
+ while wait_timeout > time():
+ try:
+ filtered_iterator = page_iterator.search(f"BrokerSummaries[?BrokerName == `{broker_name}`][]")
+ broker_list = list(filtered_iterator)
+
+ if module.check_mode:
+ return
+
+ if len(broker_list) < 1 and desired_state == "absent":
+ done = True
+ break
+
+ if desired_state in ["present", "rebooted"] and broker_list[0]["BrokerState"] == "RUNNING":
+ done = True
+ break
+
+ if broker_list[0]["BrokerState"] == "CREATION_FAILED":
+ break
+
+ sleep(interval_secs)
+
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ module.fail_json_aws(e, msg="Couldn't paginate brokers.")
+
+ if not done:
+ module.fail_json(msg="desired state not reached")
+
+
+def reboot_broker(conn, module, broker_id):
+ wait = module.params.get("wait")
+
+ try:
+ response = conn.reboot_broker(BrokerId=broker_id)
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ module.fail_json_aws(e, msg="Couldn't reboot broker.")
+
+ if wait:
+ wait_for_status(conn, module)
+
+ return response
+
+
+def delete_broker(conn, module, broker_id):
+ wait = module.params.get("wait")
+
+ try:
+ response = conn.delete_broker(BrokerId=broker_id)
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ module.fail_json_aws(e, msg="Couldn't delete broker.")
+
+ if wait:
+ wait_for_status(conn, module)
+
+ return response
+
+
+def create_broker(conn, module):
+ kwargs = _fill_kwargs(module)
+ wait = module.params.get("wait")
+
+ if "EngineVersion" in kwargs and kwargs["EngineVersion"] == "latest":
+ kwargs["EngineVersion"] = get_latest_engine_version(conn, module, kwargs["EngineType"])
+ if kwargs["AuthenticationStrategy"] == "LDAP":
+ module.fail_json(msg="'AuthenticationStrategy=LDAP' not supported, yet")
+ if "Users" not in kwargs:
+ # add some stupid default (cannot create broker without any users)
+ kwargs["Users"] = [{"Username": "admin", "Password": "adminPassword", "ConsoleAccess": True, "Groups": []}]
+ if "EncryptionOptions" in kwargs and "UseAwsOwnedKey" in kwargs["EncryptionOptions"]:
+ kwargs["EncryptionOptions"]["UseAwsOwnedKey"] = False
+ #
+ if "SecurityGroups" not in kwargs or len(kwargs["SecurityGroups"]) == 0:
+ module.fail_json(msg="At least one security group must be specified on broker creation")
+ #
+ changed = True
+ result = conn.create_broker(**kwargs)
+ #
+ if wait:
+ wait_for_status(conn, module)
+
+ return {"broker": camel_dict_to_snake_dict(result, ignore_list=["Tags"]), "changed": changed}
+
+
+def update_broker(conn, module, broker_id):
+ kwargs = _fill_kwargs(module, apply_defaults=False, ignore_create_params=True)
+ wait = module.params.get("wait")
+ # replace name with id
+ broker_name = kwargs["BrokerName"]
+ del kwargs["BrokerName"]
+ kwargs["BrokerId"] = broker_id
+ # get current state for comparison:
+ api_result = get_broker_info(conn, module, broker_id)
+ if api_result["BrokerState"] != "RUNNING":
+ module.fail_json(
+ msg=f"Cannot trigger update while broker ({broker_id}) is in state {api_result['BrokerState']}",
+ )
+ # engine version of 'latest' is taken as "keep current one"
+ # i.e. do not request upgrade on playbook rerun
+ if "EngineVersion" in kwargs and kwargs["EngineVersion"] == "latest":
+ kwargs["EngineVersion"] = api_result["EngineVersion"]
+ result = {"broker_id": broker_id, "broker_name": broker_name}
+ changed = False
+ if _needs_change(api_result, kwargs):
+ changed = True
+ if not module.check_mode:
+ api_result = conn.update_broker(**kwargs)
+ #
+ #
+ if wait:
+ wait_for_status(conn, module)
+
+ return {"broker": result, "changed": changed}
+
+
+def ensure_absent(conn, module):
+ result = {"broker_name": module.params["broker_name"], "broker_id": None}
+ if module.check_mode:
+ return {"broker": camel_dict_to_snake_dict(result, ignore_list=["Tags"]), "changed": True}
+ broker_id = get_broker_id(conn, module)
+ result["broker_id"] = broker_id
+
+ if not broker_id:
+ # silently ignore delete of unknown broker (to make it idempotent)
+ return {"broker": result, "changed": False}
+
+ try:
+ # check for pending delete (small race condition possible here
+ api_result = get_broker_info(conn, module, broker_id)
+ if api_result["BrokerState"] == "DELETION_IN_PROGRESS":
+ return {"broker": result, "changed": False}
+ delete_broker(conn, module, broker_id)
+ except botocore.exceptions.ClientError as e:
+ module.fail_json_aws(e)
+
+ return {"broker": result, "changed": True}
+
+
+def ensure_present(conn, module):
+ if module.check_mode:
+ return {"broker": {"broker_arn": "fakeArn", "broker_id": "fakeId"}, "changed": True}
+
+ broker_id = get_broker_id(conn, module)
+ if broker_id:
+ return update_broker(conn, module, broker_id)
+
+ return create_broker(conn, module)
+
+
+def main():
+ argument_spec = dict(
+ broker_name=dict(required=True, type="str"),
+ state=dict(default="present", choices=["present", "absent", "restarted"]),
+ wait=dict(default=False, type="bool"),
+ wait_timeout=dict(default=900, type="int"),
+ # parameters only allowed on create
+ deployment_mode=dict(choices=["SINGLE_INSTANCE", "ACTIVE_STANDBY_MULTI_AZ", "CLUSTER_MULTI_AZ"]),
+ use_aws_owned_key=dict(type="bool"),
+ kms_key_id=dict(type="str"),
+ engine_type=dict(choices=["ACTIVEMQ", "RABBITMQ"], type="str"),
+ maintenance_window_start_time=dict(type="dict"),
+ publicly_accessible=dict(type="bool"),
+ storage_type=dict(choices=["EBS", "EFS"]),
+ subnet_ids=dict(type="list", elements="str"),
+ users=dict(type="list", elements="dict"),
+ tags=dict(type="dict"),
+ # parameters allowed on update as well
+ authentication_strategy=dict(choices=["SIMPLE", "LDAP"]),
+ auto_minor_version_upgrade=dict(default=True, type="bool"),
+ engine_version=dict(type="str"),
+ host_instance_type=dict(type="str"),
+ enable_audit_log=dict(default=False, type="bool"),
+ enable_general_log=dict(default=False, type="bool"),
+ security_groups=dict(type="list", elements="str"),
+ )
+
+ module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
+
+ connection = module.client("mq")
+
+ if module.params["state"] == "present":
+ try:
+ compound_result = ensure_present(connection, module)
+ except botocore.exceptions.ClientError as e:
+ module.fail_json_aws(e)
+ #
+ module.exit_json(**compound_result)
+
+ if module.params["state"] == "absent":
+ try:
+ compound_result = ensure_absent(connection, module)
+ except botocore.exceptions.ClientError as e:
+ module.fail_json_aws(e)
+ #
+ module.exit_json(**compound_result)
+
+ if module.params["state"] == "restarted":
+ broker_id = get_broker_id(connection, module)
+ if module.check_mode:
+ module.exit_json(broker={"broker_id": broker_id if broker_id else "fakeId"}, changed=True)
+ if not broker_id:
+ module.fail_json(
+ msg="Cannot find broker with name {module.params['broker_name']}.",
+ )
+ try:
+ changed = True
+ if not module.check_mode:
+ reboot_broker(connection, module, broker_id)
+ #
+ result = get_broker_info(connection, module, broker_id)
+ except botocore.exceptions.ClientError as e:
+ module.fail_json_aws(e)
+ module.exit_json(broker=result, changed=changed)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/aws/plugins/modules/mq_broker_config.py b/ansible_collections/community/aws/plugins/modules/mq_broker_config.py
new file mode 100644
index 000000000..781bbb7d5
--- /dev/null
+++ b/ansible_collections/community/aws/plugins/modules/mq_broker_config.py
@@ -0,0 +1,224 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: Contributors to the Ansible project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r"""
+---
+module: mq_broker_config
+version_added: 6.0.0
+short_description: Update Amazon MQ broker configuration
+description:
+ - Update configuration for an MQ broker.
+ - If new configuration differs from the current one a new configuration
+ is created and the new version is assigned to the broker.
+ - Optionally allows broker reboot to make changes effective immediately.
+author:
+ - FCO (@fotto)
+options:
+ broker_id:
+ description:
+ - The ID of the MQ broker to work on.
+ type: str
+ required: true
+ config_xml:
+ description:
+ - The maximum number of results to return.
+ type: str
+ required: true
+ config_description:
+ description:
+ - Description to set on new configuration revision.
+ type: str
+ reboot:
+ description:
+ - Reboot broker after new config has been applied.
+ type: bool
+ default: false
+extends_documentation_fragment:
+ - amazon.aws.boto3
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+"""
+
+EXAMPLES = r"""
+- name: send new XML config to broker relying on credentials from environment
+ community.aws.mq_broker_config:
+ broker_id: "aws-mq-broker-id"
+ config_xml: "{{ lookup('file', 'activemq.xml' )}}"
+ region: "{{ aws_region }}"
+
+- name: send new XML config to broker and reboot if necessary
+ community.aws.mq_broker_config:
+ broker_id: "aws-mq-broker-id"
+ config_xml: "{{ lookup('file', 'activemq2.xml' )}}"
+ reboot: true
+
+- name: send new broker config and set all credentials explicitly
+ community.aws.mq_broker_config:
+ broker_id: "{{ broker_id }}"
+ config_xml: "{{ lookup('file', 'activemq3.xml')}}"
+ config_description: "custom description for configuration object"
+ register: result
+"""
+
+RETURN = r"""
+broker:
+ description: API response of describe_broker() converted to snake yaml after changes have been applied.
+ type: dict
+ returned: success
+configuration:
+ description: Details about new configuration object.
+ returned: I(changed=true)
+ type: complex
+ contains:
+ id:
+ description: Configuration ID of broker configuration.
+ type: str
+ example: c-386541b8-3139-42c2-9c2c-a4c267c1714f
+ revision:
+ description: Revision of the configuration that will be active after next reboot.
+ type: int
+ example: 4
+"""
+
+import base64
+import re
+
+try:
+ import botocore
+except ImportError:
+ # handled by AnsibleAWSModule
+ pass
+
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.modules import AnsibleAWSModule
+
+DEFAULTS = {"reboot": False}
+FULL_DEBUG = False
+
+
+def is_same_config(old, new):
+ # we a simple comparision here: strip down spaces and compare the rest
+ # TODO: use same XML normalizer on new as used by AWS before comparing strings
+ old_stripped = re.sub(r"\s+", " ", old, flags=re.S).rstrip()
+ new_stripped = re.sub(r"\s+", " ", new, flags=re.S).rstrip()
+ return old_stripped == new_stripped
+
+
+def get_broker_info(conn, module):
+ try:
+ return conn.describe_broker(BrokerId=module.params["broker_id"])
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ if module.check_mode:
+ return {
+ "broker_id": module.params["broker_id"],
+ }
+ module.fail_json_aws(e, msg="Couldn't get broker details.")
+
+
+def get_current_configuration(conn, module, cfg_id, cfg_revision):
+ try:
+ return conn.describe_configuration_revision(ConfigurationId=cfg_id, ConfigurationRevision=str(cfg_revision))
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ module.fail_json_aws(e, msg="Couldn't get configuration revision.")
+
+
+def create_and_assign_config(conn, module, broker_id, cfg_id, cfg_xml_encoded):
+ kwargs = {"ConfigurationId": cfg_id, "Data": cfg_xml_encoded}
+ if "config_description" in module.params and module.params["config_description"]:
+ kwargs["Description"] = module.params["config_description"]
+ else:
+ kwargs["Description"] = "Updated through community.aws.mq_broker_config ansible module"
+ #
+ try:
+ c_response = conn.update_configuration(**kwargs)
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ module.fail_json_aws(e, msg="Couldn't create new configuration revision.")
+ #
+ new_config_revision = c_response["LatestRevision"]["Revision"]
+ try:
+ b_response = conn.update_broker(
+ BrokerId=broker_id, Configuration={"Id": cfg_id, "Revision": new_config_revision}
+ )
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ module.fail_json_aws(e, msg="Couldn't assign new configuration revision to broker.")
+ #
+ return (c_response, b_response)
+
+
+def reboot_broker(conn, module, broker_id):
+ try:
+ return conn.reboot_broker(BrokerId=broker_id)
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ module.fail_json_aws(e, msg="Couldn't reboot broker.")
+
+
+def ensure_config(conn, module):
+ broker_id = module.params["broker_id"]
+ broker_info = get_broker_info(conn, module)
+ changed = False
+ if module.check_mode and "Configurations" not in broker_info:
+ # not result from get_broker_info(). use requeste config
+ current_cfg_decoded = module.params["config_xml"]
+ else:
+ current_cfg = broker_info["Configurations"]["Current"]
+ if "Pending" in broker_info["Configurations"]:
+ current_cfg = broker_info["Configurations"]["Pending"]
+ current_cfg_encoded = get_current_configuration(conn, module, current_cfg["Id"], current_cfg["Revision"])[
+ "Data"
+ ]
+ current_cfg_decoded = base64.b64decode(current_cfg_encoded.encode()).decode()
+
+ if is_same_config(current_cfg_decoded, module.params["config_xml"]):
+ return {"changed": changed, "broker": camel_dict_to_snake_dict(broker_info, ignore_list=["Tags"])}
+
+ (c_response, _b_response) = (None, None)
+ if not module.check_mode:
+ new_cfg_encoded = base64.b64encode(module.params["config_xml"].encode()).decode()
+ (c_response, _b_response) = create_and_assign_config(
+ conn, module, broker_id, current_cfg["Id"], new_cfg_encoded
+ )
+ #
+ changed = True
+
+ if changed and module.params["reboot"] and not module.check_mode:
+ reboot_broker(conn, module, broker_id)
+ #
+ broker_info = get_broker_info(conn, module)
+ return_struct = {
+ "changed": changed,
+ "broker": camel_dict_to_snake_dict(broker_info, ignore_list=["Tags"]),
+ "configuration": {"id": c_response["Id"], "revision": c_response["LatestRevision"]["Revision"]},
+ }
+ if FULL_DEBUG:
+ return_struct["old_config_xml"] = base64.b64decode(current_cfg_encoded)
+ return_struct["new_config_xml"] = module.params["config_xml"]
+ return_struct["old_config_revision"] = current_cfg["Revision"]
+ return return_struct
+
+
+def main():
+ argument_spec = dict(
+ broker_id=dict(required=True, type="str"),
+ config_xml=dict(required=True, type="str"),
+ config_description=dict(required=False, type="str"),
+ reboot=dict(required=False, type="bool", default=DEFAULTS["reboot"]),
+ )
+
+ module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
+
+ connection = module.client("mq")
+
+ try:
+ result = ensure_config(connection, module)
+ except botocore.exceptions.ClientError as e:
+ module.fail_json_aws(e)
+
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/aws/plugins/modules/mq_broker_info.py b/ansible_collections/community/aws/plugins/modules/mq_broker_info.py
new file mode 100644
index 000000000..e760e0179
--- /dev/null
+++ b/ansible_collections/community/aws/plugins/modules/mq_broker_info.py
@@ -0,0 +1,121 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: Contributors to the Ansible project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r"""
+---
+module: mq_broker_info
+version_added: 6.0.0
+short_description: Retrieve MQ Broker details
+description:
+ - Get details about a broker.
+author:
+ - FCO (@fotto)
+options:
+ broker_id:
+ description: Get details for broker with specified ID.
+ type: str
+ broker_name:
+ description:
+ - Get details for broker with specified Name.
+ - Is ignored if I(broker_id) is specified.
+ type: str
+extends_documentation_fragment:
+ - amazon.aws.boto3
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+"""
+
+
+EXAMPLES = r"""
+- name: get current broker settings by id
+ community.aws.mq_broker_info:
+ broker_id: "aws-mq-broker-id"
+ register: broker_info
+
+- name: get current broker settings by name setting all credential parameters explicitly
+ community.aws.mq_broker_info:
+ broker_name: "aws-mq-broker-name"
+ register: broker_info
+"""
+
+RETURN = r"""
+broker:
+ description: API response of describe_broker() converted to snake yaml.
+ type: dict
+ returned: success
+"""
+
+try:
+ import botocore
+except ImportError:
+ # handled by AnsibleAWSModule
+ pass
+
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.modules import AnsibleAWSModule
+
+
+def get_broker_id(conn, module):
+ try:
+ broker_name = module.params["broker_name"]
+ broker_id = None
+ response = conn.list_brokers(MaxResults=100)
+ for broker in response["BrokerSummaries"]:
+ if broker["BrokerName"] == broker_name:
+ broker_id = broker["BrokerId"]
+ break
+ return broker_id
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ module.fail_json_aws(e, msg="Couldn't list broker brokers.")
+
+
+def get_broker_info(conn, module, broker_id):
+ try:
+ return conn.describe_broker(BrokerId=broker_id)
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ if module.check_mode:
+ module.exit_json(broker={"broker_id": broker_id, "broker_name": "fakeName"})
+ else:
+ module.fail_json_aws(e, msg="Couldn't get broker details.")
+
+
+def main():
+ argument_spec = dict(broker_id=dict(type="str"), broker_name=dict(type="str"))
+ required_one_of = (
+ (
+ "broker_name",
+ "broker_id",
+ ),
+ )
+
+ module = AnsibleAWSModule(
+ argument_spec=argument_spec,
+ required_one_of=required_one_of,
+ supports_check_mode=True,
+ )
+ broker_id = module.params["broker_id"]
+ broker_name = module.params["broker_name"]
+
+ connection = module.client("mq")
+
+ try:
+ if not broker_id:
+ broker_id = get_broker_id(connection, module)
+ if not broker_id:
+ if module.check_mode:
+ module.exit_json(
+ broker={"broker_id": "fakeId", "broker_name": broker_name if broker_name else "fakeName"}
+ )
+ result = get_broker_info(connection, module, broker_id)
+ except botocore.exceptions.ClientError as e:
+ module.fail_json_aws(e)
+ #
+ module.exit_json(broker=camel_dict_to_snake_dict(result, ignore_list=["Tags"]))
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/aws/plugins/modules/mq_user.py b/ansible_collections/community/aws/plugins/modules/mq_user.py
new file mode 100644
index 000000000..68e1fd629
--- /dev/null
+++ b/ansible_collections/community/aws/plugins/modules/mq_user.py
@@ -0,0 +1,271 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r"""
+---
+module: mq_user
+version_added: 6.0.0
+short_description: Manage users in existing Amazon MQ broker
+description:
+ - Manage Amazon MQ users.
+ - Pending changes are taking into account for idempotency.
+author:
+ - FCO (@fotto)
+options:
+ broker_id:
+ description:
+ - The ID of the MQ broker to work on.
+ type: str
+ required: true
+ username:
+ description:
+ - The name of the user to create/update/delete.
+ type: str
+ required: true
+ state:
+ description:
+ - Create/Update vs Delete of user.
+ default: present
+ choices: [ 'present', 'absent' ]
+ type: str
+ console_access:
+ description:
+ - Whether the user can access the MQ Console.
+ - Defaults to C(false) on creation.
+ type: bool
+ groups:
+ description:
+ - Set group memberships for user.
+ - Defaults to C([]) on creation.
+ type: list
+ elements: str
+ password:
+ description:
+ - Set password for user.
+ - Defaults to a random password on creation.
+ - Ignored unless I(allow_pw_update=true).
+ type: str
+ allow_pw_update:
+ description:
+ - When I(allow_pw_update=true) and I(password) is set, the password
+ will always be updated for the user.
+ default: false
+ type: bool
+extends_documentation_fragment:
+ - amazon.aws.boto3
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+"""
+
+EXAMPLES = r"""
+- name: create/update user - set provided password if user doesn't exist, yet
+ community.aws.mq_user:
+ state: present
+ broker_id: "aws-mq-broker-id"
+ username: "sample_user1"
+ console_access: false
+ groups: ["g1", "g2"]
+ password: "plain-text-password"
+
+- name: allow console access and update group list - relying on default state
+ community.aws.mq_user:
+ broker_id: "aws-mq-broker-id"
+ username: "sample_user1"
+ region: "{{ aws_region }}"
+ console_access: true
+ groups: ["g1", "g2", "g3"]
+
+- name: remove user - setting all credentials explicitly
+ community.aws.mq_user:
+ state: absent
+ broker_id: "aws-mq-broker-id"
+ username: "other_user"
+"""
+
+RETURN = r"""
+user:
+ description:
+ - just echos the username
+ - "only present when state=present"
+ type: str
+ returned: success
+"""
+
+import secrets
+
+try:
+ import botocore
+except ImportError as ex:
+ # handled by AnsibleAWSModule
+ pass
+
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.modules import AnsibleAWSModule
+
+CREATE_DEFAULTS = {
+ "console_access": False,
+ "groups": [],
+}
+
+
+def _group_change_required(user_response, requested_groups):
+ current_groups = []
+ if "Groups" in user_response:
+ current_groups = user_response["Groups"]
+ elif "Pending" in user_response:
+ # to support automatic testing without broker reboot
+ current_groups = user_response["Pending"]["Groups"]
+ if len(current_groups) != len(requested_groups):
+ return True
+ if len(current_groups) != len(set(current_groups) & set(requested_groups)):
+ return True
+ #
+ return False
+
+
+def _console_access_change_required(user_response, requested_boolean):
+ current_boolean = CREATE_DEFAULTS["console_access"]
+ if "ConsoleAccess" in user_response:
+ current_boolean = user_response["ConsoleAccess"]
+ elif "Pending" in user_response:
+ # to support automatic testing without broker reboot
+ current_boolean = user_response["Pending"]["ConsoleAccess"]
+ #
+ return current_boolean != requested_boolean
+
+
+def generate_password():
+ return secrets.token_hex(20)
+
+
+# returns API response object
+def _create_user(conn, module):
+ kwargs = {"BrokerId": module.params["broker_id"], "Username": module.params["username"]}
+ if "groups" in module.params and module.params["groups"] is not None:
+ kwargs["Groups"] = module.params["groups"]
+ else:
+ kwargs["Groups"] = CREATE_DEFAULTS["groups"]
+ if "password" in module.params and module.params["password"]:
+ kwargs["Password"] = module.params["password"]
+ else:
+ kwargs["Password"] = generate_password()
+ if "console_access" in module.params and module.params["console_access"] is not None:
+ kwargs["ConsoleAccess"] = module.params["console_access"]
+ else:
+ kwargs["ConsoleAccess"] = CREATE_DEFAULTS["console_access"]
+ try:
+ response = conn.create_user(**kwargs)
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ module.fail_json_aws(e, msg="Couldn't create user")
+ return response
+
+
+# returns API response object
+def _update_user(conn, module, kwargs):
+ try:
+ response = conn.update_user(**kwargs)
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ module.fail_json_aws(e, msg="Couldn't update user")
+ return response
+
+
+def get_matching_user(conn, module, broker_id, username):
+ try:
+ response = conn.describe_user(BrokerId=broker_id, Username=username)
+ except is_boto3_error_code("NotFoundException"):
+ return None
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ module.fail_json_aws(e, msg="Couldn't get user details")
+ return response
+
+
+def ensure_user_present(conn, module):
+ user = get_matching_user(conn, module, module.params["broker_id"], module.params["username"])
+ changed = False
+
+ if user is None:
+ if not module.check_mode:
+ _response = _create_user(conn, module)
+ changed = True
+ else:
+ kwargs = {}
+ if "groups" in module.params and module.params["groups"] is not None:
+ if _group_change_required(user, module.params["groups"]):
+ kwargs["Groups"] = module.params["groups"]
+ if "console_access" in module.params and module.params["console_access"] is not None:
+ if _console_access_change_required(user, module.params["console_access"]):
+ kwargs["ConsoleAccess"] = module.params["console_access"]
+ if "password" in module.params and module.params["password"]:
+ if "allow_pw_update" in module.params and module.params["allow_pw_update"]:
+ kwargs["Password"] = module.params["password"]
+ if len(kwargs) == 0:
+ changed = False
+ else:
+ if not module.check_mode:
+ kwargs["BrokerId"] = module.params["broker_id"]
+ kwargs["Username"] = module.params["username"]
+ response = _update_user(conn, module, kwargs)
+ #
+ changed = True
+ #
+ user = get_matching_user(conn, module, module.params["broker_id"], module.params["username"])
+
+ return {"changed": changed, "user": camel_dict_to_snake_dict(user, ignore_list=["Tags"])}
+
+
+def ensure_user_absent(conn, module):
+ user = get_matching_user(conn, module, module.params["broker_id"], module.params["username"])
+ result = {"changed": False}
+ if user is None:
+ return result
+ # better support for testing
+ if "Pending" in user and "PendingChange" in user["Pending"] and user["Pending"]["PendingChange"] == "DELETE":
+ return result
+
+ result = {"changed": True}
+ if module.check_mode:
+ return result
+
+ try:
+ conn.delete_user(BrokerId=user["BrokerId"], Username=user["Username"])
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ module.fail_json_aws(e, msg="Couldn't delete user")
+
+ return result
+
+
+def main():
+ argument_spec = dict(
+ broker_id=dict(required=True, type="str"),
+ username=dict(required=True, type="str"),
+ console_access=dict(required=False, type="bool"),
+ groups=dict(required=False, type="list", elements="str"),
+ password=dict(required=False, type="str", no_log=True),
+ allow_pw_update=dict(default=False, required=False, type="bool"),
+ state=dict(default="present", choices=["present", "absent"]),
+ )
+
+ module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
+
+ connection = module.client("mq")
+
+ state = module.params.get("state")
+
+ try:
+ if state == "present":
+ result = ensure_user_present(connection, module)
+ elif state == "absent":
+ result = ensure_user_absent(connection, module)
+ except botocore.exceptions.ClientError as e:
+ module.fail_json_aws(e)
+
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/aws/plugins/modules/mq_user_info.py b/ansible_collections/community/aws/plugins/modules/mq_user_info.py
new file mode 100644
index 000000000..64cf92da7
--- /dev/null
+++ b/ansible_collections/community/aws/plugins/modules/mq_user_info.py
@@ -0,0 +1,153 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: Contributors to the Ansible project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r"""
+---
+module: mq_user_info
+version_added: 6.0.0
+short_description: List users of an Amazon MQ broker
+description:
+ - List users for the specified broker ID.
+ - Pending creations and deletions can be skipped by options.
+author:
+ - FCO (@fotto)
+options:
+ broker_id:
+ description:
+ - The ID of the MQ broker to work on.
+ type: str
+ required: true
+ max_results:
+ description:
+ - The maximum number of results to return.
+ type: int
+ default: 100
+ skip_pending_create:
+ description:
+ - Will skip pending creates from the result set.
+ type: bool
+ default: false
+ skip_pending_delete:
+ description:
+ - Will skip pending deletes from the result set.
+ type: bool
+ default: false
+ as_dict:
+ description:
+ - Convert result into lookup table by username.
+ type: bool
+ default: false
+
+extends_documentation_fragment:
+ - amazon.aws.boto3
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+"""
+
+
+EXAMPLES = r"""
+- name: get all users as list - relying on environment for API credentials
+ community.aws.mq_user_info:
+ broker_id: "aws-mq-broker-id"
+ max_results: 50
+ register: result
+
+- name: get users as dict - explicitly specifying all credentials
+ community.aws.mq_user_info:
+ broker_id: "aws-mq-broker-id"
+ register: result
+
+- name: get list of users to decide which may need to be deleted
+ community.aws.mq_user_info:
+ broker_id: "aws-mq-broker-id"
+ skip_pending_delete: true
+
+- name: get list of users to decide which may need to be created
+ community.aws.mq_user_info:
+ broker_id: "aws-mq-broker-id"
+ skip_pending_create: true
+"""
+
+RETURN = r"""
+users:
+ type: dict
+ returned: success
+ description:
+ - dict key is username
+ - each entry is the record for a user as returned by API but converted to snake yaml
+"""
+
+try:
+ import botocore
+except ImportError as ex:
+ # handled by AnsibleAWSModule
+ pass
+
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
+
+DEFAULTS = {"max_results": 100, "skip_pending_create": False, "skip_pending_delete": False, "as_dict": True}
+
+
+def get_user_info(conn, module):
+ try:
+ response = conn.list_users(BrokerId=module.params["broker_id"], MaxResults=module.params["max_results"])
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ if module.check_mode:
+ # return empty set for unknown broker in check mode
+ if DEFAULTS["as_dict"]:
+ return {}
+ return []
+ module.fail_json_aws(e, msg="Failed to describe users")
+ #
+ if not module.params["skip_pending_create"] and not module.params["skip_pending_delete"]:
+ # we can simply return the sub-object from the response
+ records = response["Users"]
+ else:
+ records = []
+ for record in response["Users"]:
+ if "PendingChange" in record:
+ if record["PendingChange"] == "CREATE" and module.params["skip_pending_create"]:
+ continue
+ if record["PendingChange"] == "DELETE" and module.params["skip_pending_delete"]:
+ continue
+ #
+ records.append(record)
+ #
+ if DEFAULTS["as_dict"]:
+ user_records = {}
+ for record in records:
+ user_records[record["Username"]] = record
+ #
+ return camel_dict_to_snake_dict(user_records, ignore_list=["Tags"])
+
+ return camel_dict_to_snake_dict(records, ignore_list=["Tags"])
+
+
+def main():
+ argument_spec = dict(
+ broker_id=dict(required=True, type="str"),
+ max_results=dict(required=False, type="int", default=DEFAULTS["max_results"]),
+ skip_pending_create=dict(required=False, type="bool", default=DEFAULTS["skip_pending_create"]),
+ skip_pending_delete=dict(required=False, type="bool", default=DEFAULTS["skip_pending_delete"]),
+ as_dict=dict(required=False, type="bool", default=False),
+ )
+
+ module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
+
+ connection = module.client("mq")
+
+ try:
+ user_records = get_user_info(connection, module)
+ except botocore.exceptions.ClientError as e:
+ module.fail_json_aws(e)
+
+ module.exit_json(users=user_records)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/aws/plugins/modules/msk_cluster.py b/ansible_collections/community/aws/plugins/modules/msk_cluster.py
index 75c7fa829..aa0383294 100644
--- a/ansible_collections/community/aws/plugins/modules/msk_cluster.py
+++ b/ansible_collections/community/aws/plugins/modules/msk_cluster.py
@@ -1,12 +1,9 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: (c) 2021, Daniil Kupchenko (@oukooveu)
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-
-__metaclass__ = type
-
-
DOCUMENTATION = r"""
---
module: msk_cluster
@@ -207,16 +204,16 @@ options:
description: How many seconds to wait. Cluster creation can take up to 20-30 minutes.
type: int
default: 3600
-extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
- - amazon.aws.boto3
- - amazon.aws.tags
notes:
- All operations are time consuming, for example create takes 20-30 minutes,
update kafka version -- more than one hour, update configuration -- 10-15 minutes;
- Cluster's brokers get evenly distributed over a number of availability zones
that's equal to the number of subnets.
+extends_documentation_fragment:
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+ - amazon.aws.tags
"""
EXAMPLES = r"""
@@ -274,12 +271,12 @@ try:
except ImportError:
pass # handled by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import (
- camel_dict_to_snake_dict,
- compare_aws_tags,
- AWSRetry,
-)
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import compare_aws_tags
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
@AWSRetry.jittered_backoff(retries=5, delay=5)
@@ -304,7 +301,7 @@ def find_cluster_by_name(client, module, cluster_name):
module.fail_json_aws(e, "Failed to find kafka cluster by name")
if cluster_list:
if len(cluster_list) != 1:
- module.fail_json(msg="Found more than one cluster with name '{0}'".format(cluster_name))
+ module.fail_json(msg=f"Found more than one cluster with name '{cluster_name}'")
return cluster_list[0]
return {}
@@ -343,11 +340,7 @@ def wait_for_cluster_state(client, module, arn, state="ACTIVE"):
if current_state == state:
return
if time.time() - start > timeout:
- module.fail_json(
- msg="Timeout waiting for cluster {0} (desired state is '{1}')".format(
- current_state, state
- )
- )
+ module.fail_json(msg=f"Timeout waiting for cluster {current_state} (desired state is '{state}')")
time.sleep(check_interval)
@@ -367,7 +360,7 @@ def prepare_create_options(module):
"BrokerNodeGroupInfo": {
"ClientSubnets": module.params["subnets"],
"InstanceType": module.params["instance_type"],
- }
+ },
}
if module.params["security_groups"] and len(module.params["security_groups"]) != 0:
@@ -375,9 +368,7 @@ def prepare_create_options(module):
if module.params["ebs_volume_size"]:
c_params["BrokerNodeGroupInfo"]["StorageInfo"] = {
- "EbsStorageInfo": {
- "VolumeSize": module.params.get("ebs_volume_size")
- }
+ "EbsStorageInfo": {"VolumeSize": module.params.get("ebs_volume_size")}
}
if module.params["encryption"]:
@@ -388,7 +379,7 @@ def prepare_create_options(module):
}
c_params["EncryptionInfo"]["EncryptionInTransit"] = {
"ClientBroker": module.params["encryption"]["in_transit"].get("client_broker", "TLS"),
- "InCluster": module.params["encryption"]["in_transit"].get("in_cluster", True)
+ "InCluster": module.params["encryption"]["in_transit"].get("in_cluster", True),
}
if module.params["authentication"]:
@@ -428,12 +419,8 @@ def prepare_open_monitoring_options(module):
open_monitoring = module.params["open_monitoring"] or {}
m_params["OpenMonitoring"] = {
"Prometheus": {
- "JmxExporter": {
- "EnabledInBroker": open_monitoring.get("jmx_exporter", False)
- },
- "NodeExporter": {
- "EnabledInBroker": open_monitoring.get("node_exporter", False)
- }
+ "JmxExporter": {"EnabledInBroker": open_monitoring.get("jmx_exporter", False)},
+ "NodeExporter": {"EnabledInBroker": open_monitoring.get("node_exporter", False)},
}
}
return m_params
@@ -445,36 +432,26 @@ def prepare_logging_options(module):
if logging.get("cloudwatch"):
l_params["CloudWatchLogs"] = {
"Enabled": module.params["logging"]["cloudwatch"].get("enabled"),
- "LogGroup": module.params["logging"]["cloudwatch"].get("log_group")
+ "LogGroup": module.params["logging"]["cloudwatch"].get("log_group"),
}
else:
- l_params["CloudWatchLogs"] = {
- "Enabled": False
- }
+ l_params["CloudWatchLogs"] = {"Enabled": False}
if logging.get("firehose"):
l_params["Firehose"] = {
"Enabled": module.params["logging"]["firehose"].get("enabled"),
- "DeliveryStream": module.params["logging"]["firehose"].get("delivery_stream")
+ "DeliveryStream": module.params["logging"]["firehose"].get("delivery_stream"),
}
else:
- l_params["Firehose"] = {
- "Enabled": False
- }
+ l_params["Firehose"] = {"Enabled": False}
if logging.get("s3"):
l_params["S3"] = {
"Enabled": module.params["logging"]["s3"].get("enabled"),
"Bucket": module.params["logging"]["s3"].get("bucket"),
- "Prefix": module.params["logging"]["s3"].get("prefix")
+ "Prefix": module.params["logging"]["s3"].get("prefix"),
}
else:
- l_params["S3"] = {
- "Enabled": False
- }
- return {
- "LoggingInfo": {
- "BrokerLogs": l_params
- }
- }
+ l_params["S3"] = {"Enabled": False}
+ return {"LoggingInfo": {"BrokerLogs": l_params}}
def create_or_update_cluster(client, module):
@@ -488,7 +465,6 @@ def create_or_update_cluster(client, module):
cluster = find_cluster_by_name(client, module, module.params["name"])
if not cluster:
-
changed = True
if module.check_mode:
@@ -508,7 +484,6 @@ def create_or_update_cluster(client, module):
wait_for_cluster_state(client, module, arn=response["ClusterArn"], state="ACTIVE")
else:
-
response["ClusterArn"] = cluster["ClusterArn"]
response["changes"] = {}
@@ -517,9 +492,7 @@ def create_or_update_cluster(client, module):
"broker_count": {
"current_value": cluster["NumberOfBrokerNodes"],
"target_value": module.params.get("nodes"),
- "update_params": {
- "TargetNumberOfBrokerNodes": module.params.get("nodes")
- }
+ "update_params": {"TargetNumberOfBrokerNodes": module.params.get("nodes")},
},
"broker_storage": {
"current_value": cluster["BrokerNodeGroupInfo"]["StorageInfo"]["EbsStorageInfo"]["VolumeSize"],
@@ -528,14 +501,12 @@ def create_or_update_cluster(client, module):
"TargetBrokerEBSVolumeInfo": [
{"KafkaBrokerNodeId": "All", "VolumeSizeGB": module.params.get("ebs_volume_size")}
]
- }
+ },
},
"broker_type": {
"current_value": cluster["BrokerNodeGroupInfo"]["InstanceType"],
"target_value": module.params.get("instance_type"),
- "update_params": {
- "TargetInstanceType": module.params.get("instance_type")
- }
+ "update_params": {"TargetInstanceType": module.params.get("instance_type")},
},
"cluster_configuration": {
"current_value": {
@@ -549,51 +520,44 @@ def create_or_update_cluster(client, module):
"update_params": {
"ConfigurationInfo": {
"Arn": module.params.get("configuration_arn"),
- "Revision": module.params.get("configuration_revision")
+ "Revision": module.params.get("configuration_revision"),
}
- }
+ },
},
"cluster_kafka_version": {
"current_value": cluster["CurrentBrokerSoftwareInfo"]["KafkaVersion"],
"target_value": module.params.get("version"),
- "update_params": {
- "TargetKafkaVersion": module.params.get("version")
- }
+ "update_params": {"TargetKafkaVersion": module.params.get("version")},
},
"enhanced_monitoring": {
"current_value": cluster["EnhancedMonitoring"],
"target_value": module.params.get("enhanced_monitoring"),
"update_method": "update_monitoring",
- "update_params": prepare_enhanced_monitoring_options(module)
+ "update_params": prepare_enhanced_monitoring_options(module),
},
"open_monitoring": {
- "current_value": {
- "OpenMonitoring": cluster["OpenMonitoring"]
- },
+ "current_value": {"OpenMonitoring": cluster["OpenMonitoring"]},
"target_value": prepare_open_monitoring_options(module),
"update_method": "update_monitoring",
- "update_params": prepare_open_monitoring_options(module)
+ "update_params": prepare_open_monitoring_options(module),
},
"logging": {
- "current_value": {
- "LoggingInfo": cluster["LoggingInfo"]
- },
+ "current_value": {"LoggingInfo": cluster["LoggingInfo"]},
"target_value": prepare_logging_options(module),
"update_method": "update_monitoring",
- "update_params": prepare_logging_options(module)
- }
+ "update_params": prepare_logging_options(module),
+ },
}
for method, options in msk_cluster_changes.items():
-
- if 'botocore_version' in options:
+ if "botocore_version" in options:
if not module.botocore_at_least(options["botocore_version"]):
continue
try:
update_method = getattr(client, options.get("update_method", "update_" + method))
except AttributeError as e:
- module.fail_json_aws(e, "There is no update method 'update_{0}'".format(method))
+ module.fail_json_aws(e, f"There is no update method 'update_{method}'")
if options["current_value"] != options["target_value"]:
changed = True
@@ -609,23 +573,17 @@ def create_or_update_cluster(client, module):
wait_for_cluster_state(client, module, arn=cluster["ClusterArn"], state="ACTIVE")
else:
module.fail_json(
- msg="Cluster can be updated only in active state, current state is '{0}'. check cluster state or use wait option".format(
- state
- )
+ msg=f"Cluster can be updated only in active state, current state is '{state}'. check cluster state or use wait option"
)
try:
response["changes"][method] = update_method(
- ClusterArn=cluster["ClusterArn"],
- CurrentVersion=version,
- **options["update_params"]
+ ClusterArn=cluster["ClusterArn"], CurrentVersion=version, **options["update_params"]
)
except (
botocore.exceptions.BotoCoreError,
botocore.exceptions.ClientError,
) as e:
- module.fail_json_aws(
- e, "Failed to update cluster via 'update_{0}'".format(method)
- )
+ module.fail_json_aws(e, f"Failed to update cluster via 'update_{method}'")
if module.params["wait"]:
wait_for_cluster_state(client, module, arn=cluster["ClusterArn"], state="ACTIVE")
@@ -636,15 +594,15 @@ def create_or_update_cluster(client, module):
def update_cluster_tags(client, module, arn):
- new_tags = module.params.get('tags')
+ new_tags = module.params.get("tags")
if new_tags is None:
return False
- purge_tags = module.params.get('purge_tags')
+ purge_tags = module.params.get("purge_tags")
try:
- existing_tags = client.list_tags_for_resource(ResourceArn=arn, aws_retry=True)['Tags']
+ existing_tags = client.list_tags_for_resource(ResourceArn=arn, aws_retry=True)["Tags"]
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Unable to retrieve tags for cluster '{0}'".format(arn))
+ module.fail_json_aws(e, msg=f"Unable to retrieve tags for cluster '{arn}'")
tags_to_add, tags_to_remove = compare_aws_tags(existing_tags, new_tags, purge_tags=purge_tags)
@@ -655,14 +613,13 @@ def update_cluster_tags(client, module, arn):
if tags_to_add:
client.tag_resource(ResourceArn=arn, Tags=tags_to_add, aws_retry=True)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg="Unable to set tags for cluster '{0}'".format(arn))
+ module.fail_json_aws(e, msg=f"Unable to set tags for cluster '{arn}'")
changed = bool(tags_to_add) or bool(tags_to_remove)
return changed
def delete_cluster(client, module):
-
cluster = find_cluster_by_name(client, module, module.params["name"])
if module.check_mode:
@@ -691,7 +648,6 @@ def delete_cluster(client, module):
def main():
-
module_args = dict(
name=dict(type="str", required=True),
state=dict(type="str", choices=["present", "absent"], default="present"),
@@ -720,10 +676,7 @@ def main():
type="dict",
options=dict(
in_cluster=dict(type="bool", default=True),
- client_broker=dict(
- choices=["TLS", "TLS_PLAINTEXT", "PLAINTEXT"],
- default="TLS"
- ),
+ client_broker=dict(choices=["TLS", "TLS_PLAINTEXT", "PLAINTEXT"], default="TLS"),
),
),
),
@@ -783,30 +736,28 @@ def main():
),
wait=dict(type="bool", default=False),
wait_timeout=dict(type="int", default=3600),
- tags=dict(type='dict', aliases=['resource_tags']),
- purge_tags=dict(type='bool', default=True),
+ tags=dict(type="dict", aliases=["resource_tags"]),
+ purge_tags=dict(type="bool", default=True),
)
module = AnsibleAWSModule(
argument_spec=module_args,
- required_if=[['state', 'present', ['version', 'configuration_arn', 'configuration_revision', 'subnets']]],
- supports_check_mode=True
+ required_if=[["state", "present", ["version", "configuration_arn", "configuration_revision", "subnets"]]],
+ supports_check_mode=True,
)
client = module.client("kafka", retry_decorator=AWSRetry.jittered_backoff())
if module.params["state"] == "present":
if len(module.params["subnets"]) < 2:
- module.fail_json(
- msg="At least two client subnets should be provided"
- )
+ module.fail_json(msg="At least two client subnets should be provided")
if int(module.params["nodes"]) % int(len(module.params["subnets"])) != 0:
module.fail_json(
msg="The number of broker nodes must be a multiple of availability zones in the subnets parameter"
)
if len(module.params["name"]) > 64:
module.fail_json(
- module.fail_json(msg='Cluster name "{0}" exceeds 64 character limit'.format(module.params["name"]))
+ module.fail_json(msg=f"Cluster name \"{module.params['name']}\" exceeds 64 character limit")
)
changed, response = create_or_update_cluster(client, module)
elif module.params["state"] == "absent":
@@ -816,9 +767,7 @@ def main():
bootstrap_broker_string = {}
if response.get("ClusterArn") and module.params["state"] == "present":
try:
- cluster_info = client.describe_cluster(ClusterArn=response["ClusterArn"], aws_retry=True)[
- "ClusterInfo"
- ]
+ cluster_info = client.describe_cluster(ClusterArn=response["ClusterArn"], aws_retry=True)["ClusterInfo"]
if cluster_info.get("State") == "ACTIVE":
brokers = client.get_bootstrap_brokers(ClusterArn=response["ClusterArn"], aws_retry=True)
if brokers.get("BootstrapBrokerString"):
@@ -831,9 +780,7 @@ def main():
) as e:
module.fail_json_aws(
e,
- "Can not obtain information about cluster {0}".format(
- response["ClusterArn"]
- ),
+ f"Can not obtain information about cluster {response['ClusterArn']}",
)
module.exit_json(
diff --git a/ansible_collections/community/aws/plugins/modules/msk_config.py b/ansible_collections/community/aws/plugins/modules/msk_config.py
index 812eba16d..2469f9598 100644
--- a/ansible_collections/community/aws/plugins/modules/msk_config.py
+++ b/ansible_collections/community/aws/plugins/modules/msk_config.py
@@ -1,12 +1,9 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: (c) 2021, Daniil Kupchenko (@oukooveu)
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-
-__metaclass__ = type
-
-
DOCUMENTATION = r"""
---
module: msk_config
@@ -44,8 +41,8 @@ options:
type: list
elements: str
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
"""
@@ -99,18 +96,19 @@ try:
except ImportError:
pass # handled by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import (
- camel_dict_to_snake_dict,
- AWSRetry,
-)
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.iam import get_aws_account_info
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def dict_to_prop(d):
"""convert dictionary to multi-line properties"""
if len(d) == 0:
return ""
- return "\n".join("{0}={1}".format(k, v) for k, v in d.items())
+ return "\n".join(f"{k}={v}" for k, v in d.items())
def prop_to_dict(p):
@@ -146,19 +144,13 @@ def find_active_config(client, module):
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="failed to obtain kafka configurations")
- active_configs = list(
- item
- for item in all_configs
- if item["Name"] == name and item["State"] == "ACTIVE"
- )
+ active_configs = list(item for item in all_configs if item["Name"] == name and item["State"] == "ACTIVE")
if active_configs:
if len(active_configs) == 1:
return active_configs[0]
else:
- module.fail_json_aws(
- msg="found more than one active config with name '{0}'".format(name)
- )
+ module.fail_json_aws(msg=f"found more than one active config with name '{name}'")
return None
@@ -195,7 +187,6 @@ def create_config(client, module):
# create new configuration
if not config:
-
if module.check_mode:
return True, {}
@@ -205,7 +196,7 @@ def create_config(client, module):
Description=module.params.get("description"),
KafkaVersions=module.params.get("kafka_versions"),
ServerProperties=dict_to_prop(module.params.get("config")).encode(),
- aws_retry=True
+ aws_retry=True,
)
except (
botocore.exceptions.BotoCoreError,
@@ -216,7 +207,9 @@ def create_config(client, module):
# update existing configuration (creates new revision)
else:
# it's required because 'config' doesn't contain 'ServerProperties'
- response = get_configuration_revision(client, module, arn=config["Arn"], revision=config["LatestRevision"]["Revision"])
+ response = get_configuration_revision(
+ client, module, arn=config["Arn"], revision=config["LatestRevision"]["Revision"]
+ )
if not is_configuration_changed(module, response):
return False, response
@@ -229,7 +222,7 @@ def create_config(client, module):
Arn=config["Arn"],
Description=module.params.get("description"),
ServerProperties=dict_to_prop(module.params.get("config")).encode(),
- aws_retry=True
+ aws_retry=True,
)
except (
botocore.exceptions.BotoCoreError,
@@ -270,7 +263,6 @@ def delete_config(client, module):
def main():
-
module_args = dict(
name=dict(type="str", required=True),
description=dict(type="str", default=""),
@@ -292,7 +284,8 @@ def main():
# return some useless staff in check mode if configuration doesn't exists
# can be useful when these options are referenced by other modules during check mode run
if module.check_mode and not response.get("Arn"):
- arn = "arn:aws:kafka:region:account:configuration/name/id"
+ account_id, partition = get_aws_account_info(module)
+ arn = f"arn:{partition}:kafka:{module.region}:{account_id}:configuration/{module.params['name']}/id"
revision = 1
server_properties = ""
else:
diff --git a/ansible_collections/community/aws/plugins/modules/networkfirewall.py b/ansible_collections/community/aws/plugins/modules/networkfirewall.py
index 9bb6ebb75..f7fe63f33 100644
--- a/ansible_collections/community/aws/plugins/modules/networkfirewall.py
+++ b/ansible_collections/community/aws/plugins/modules/networkfirewall.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
module: networkfirewall
short_description: manage AWS Network Firewall firewalls
version_added: 4.0.0
@@ -104,34 +102,34 @@ options:
author:
- Mark Chappell (@tremble)
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
- - amazon.aws.boto3
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.tags
-'''
+ - amazon.aws.boto3
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
# Create an AWS Network Firewall
- community.aws.networkfirewall:
name: 'ExampleFirewall'
state: present
policy: 'ExamplePolicy'
subnets:
- - 'subnet-123456789abcdef01'
+ - 'subnet-123456789abcdef01'
# Create an AWS Network Firewall with various options, don't wait for creation
# to finish.
- community.aws.networkfirewall:
name: 'ExampleFirewall'
state: present
- delete_protection: True
+ delete_protection: true
description: "An example Description"
policy: 'ExamplePolicy'
- policy_change_protection: True
+ policy_change_protection: true
subnets:
- - 'subnet-123456789abcdef01'
- - 'subnet-abcdef0123456789a'
- subnet_change_protection: True
+ - 'subnet-123456789abcdef01'
+ - 'subnet-abcdef0123456789a'
+ subnet_change_protection: true
tags:
ExampleTag: Example Value
another_tag: another_example
@@ -142,9 +140,9 @@ EXAMPLES = '''
- community.aws.networkfirewall:
state: absent
name: 'ExampleFirewall'
-'''
+"""
-RETURN = '''
+RETURN = r"""
firewall:
description: The full details of the firewall
returned: success
@@ -269,37 +267,35 @@ firewall:
}
}
}
-'''
-
+"""
-from ansible_collections.amazon.aws.plugins.module_utils.modules import AnsibleAWSModule
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
from ansible_collections.community.aws.plugins.module_utils.networkfirewall import NetworkFirewallManager
def main():
-
argument_spec = dict(
- name=dict(type='str', required=False, aliases=['firewall_name']),
- arn=dict(type='str', required=False, aliases=['firewall_arn']),
- state=dict(type='str', required=False, default='present', choices=['present', 'absent']),
- description=dict(type='str', required=False),
- tags=dict(type='dict', required=False, aliases=['resource_tags']),
- purge_tags=dict(type='bool', required=False, default=True),
- wait=dict(type='bool', required=False, default=True),
- wait_timeout=dict(type='int', required=False),
- subnet_change_protection=dict(type='bool', required=False),
- policy_change_protection=dict(type='bool', required=False, aliases=['firewall_policy_change_protection']),
- delete_protection=dict(type='bool', required=False),
- subnets=dict(type='list', elements='str', required=False),
- purge_subnets=dict(type='bool', required=False, default=True),
- policy=dict(type='str', required=False, aliases=['firewall_policy_arn']),
+ name=dict(type="str", required=False, aliases=["firewall_name"]),
+ arn=dict(type="str", required=False, aliases=["firewall_arn"]),
+ state=dict(type="str", required=False, default="present", choices=["present", "absent"]),
+ description=dict(type="str", required=False),
+ tags=dict(type="dict", required=False, aliases=["resource_tags"]),
+ purge_tags=dict(type="bool", required=False, default=True),
+ wait=dict(type="bool", required=False, default=True),
+ wait_timeout=dict(type="int", required=False),
+ subnet_change_protection=dict(type="bool", required=False),
+ policy_change_protection=dict(type="bool", required=False, aliases=["firewall_policy_change_protection"]),
+ delete_protection=dict(type="bool", required=False),
+ subnets=dict(type="list", elements="str", required=False),
+ purge_subnets=dict(type="bool", required=False, default=True),
+ policy=dict(type="str", required=False, aliases=["firewall_policy_arn"]),
)
mutually_exclusive = [
- ('arn', 'name',)
+ ["arn", "name"],
]
required_one_of = [
- ('arn', 'name',)
+ ["arn", "name"],
]
module = AnsibleAWSModule(
@@ -309,30 +305,30 @@ def main():
required_one_of=required_one_of,
)
- arn = module.params.get('arn')
- name = module.params.get('name')
- state = module.params.get('state')
+ arn = module.params.get("arn")
+ name = module.params.get("name")
+ state = module.params.get("state")
manager = NetworkFirewallManager(module, name=name, arn=arn)
- manager.set_wait(module.params.get('wait', None))
- manager.set_wait_timeout(module.params.get('wait_timeout', None))
+ manager.set_wait(module.params.get("wait", None))
+ manager.set_wait_timeout(module.params.get("wait_timeout", None))
- if state == 'absent':
- manager.set_delete_protection(module.params.get('delete_protection', None))
+ if state == "absent":
+ manager.set_delete_protection(module.params.get("delete_protection", None))
manager.delete()
else:
if not manager.original_resource:
- if not module.params.get('subnets', None):
- module.fail_json('The subnets parameter must be provided on creation.')
- if not module.params.get('policy', None):
- module.fail_json('The policy parameter must be provided on creation.')
- manager.set_description(module.params.get('description', None))
- manager.set_tags(module.params.get('tags', None), module.params.get('purge_tags', None))
- manager.set_subnet_change_protection(module.params.get('subnet_change_protection', None))
- manager.set_policy_change_protection(module.params.get('policy_change_protection', None))
- manager.set_delete_protection(module.params.get('delete_protection', None))
- manager.set_subnets(module.params.get('subnets', None), module.params.get('purge_subnets', None))
- manager.set_policy(module.params.get('policy', None))
+ if not module.params.get("subnets", None):
+ module.fail_json("The subnets parameter must be provided on creation.")
+ if not module.params.get("policy", None):
+ module.fail_json("The policy parameter must be provided on creation.")
+ manager.set_description(module.params.get("description", None))
+ manager.set_tags(module.params.get("tags", None), module.params.get("purge_tags", None))
+ manager.set_subnet_change_protection(module.params.get("subnet_change_protection", None))
+ manager.set_policy_change_protection(module.params.get("policy_change_protection", None))
+ manager.set_delete_protection(module.params.get("delete_protection", None))
+ manager.set_subnets(module.params.get("subnets", None), module.params.get("purge_subnets", None))
+ manager.set_policy(module.params.get("policy", None))
manager.flush_changes()
results = dict(
@@ -344,9 +340,9 @@ def main():
before=manager.original_resource,
after=manager.updated_resource,
)
- results['diff'] = diff
+ results["diff"] = diff
module.exit_json(**results)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/networkfirewall_info.py b/ansible_collections/community/aws/plugins/modules/networkfirewall_info.py
index 85df6b026..262a31067 100644
--- a/ansible_collections/community/aws/plugins/modules/networkfirewall_info.py
+++ b/ansible_collections/community/aws/plugins/modules/networkfirewall_info.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
module: networkfirewall_info
short_description: describe AWS Network Firewall firewalls
version_added: 4.0.0
@@ -34,14 +32,15 @@ options:
elements: str
aliases: ['vpcs', 'vpc_id']
-author: Mark Chappell (@tremble)
+author:
+ - Mark Chappell (@tremble)
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
# Describe all firewalls in an account
- community.aws.networkfirewall_info: {}
@@ -53,9 +52,9 @@ EXAMPLES = '''
# Describe a firewall by name
- community.aws.networkfirewall_info:
name: ExampleFirewall
-'''
+"""
-RETURN = '''
+RETURN = r"""
firewall_list:
description: A list of ARNs of the matching firewalls.
type: list
@@ -184,32 +183,30 @@ firewalls:
}
}
}
-'''
+"""
-
-from ansible_collections.amazon.aws.plugins.module_utils.modules import AnsibleAWSModule
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
from ansible_collections.community.aws.plugins.module_utils.networkfirewall import NetworkFirewallManager
def main():
-
argument_spec = dict(
- name=dict(type='str', required=False),
- arn=dict(type='str', required=False),
- vpc_ids=dict(type='list', required=False, elements='str', aliases=['vpcs', 'vpc_id']),
+ name=dict(type="str", required=False),
+ arn=dict(type="str", required=False),
+ vpc_ids=dict(type="list", required=False, elements="str", aliases=["vpcs", "vpc_id"]),
)
module = AnsibleAWSModule(
argument_spec=argument_spec,
supports_check_mode=True,
mutually_exclusive=[
- ('arn', 'name', 'vpc_ids',),
+ ["arn", "name", "vpc_ids"],
],
)
- arn = module.params.get('arn')
- name = module.params.get('name')
- vpcs = module.params.get('vpc_ids')
+ arn = module.params.get("arn")
+ name = module.params.get("name")
+ vpcs = module.params.get("vpc_ids")
manager = NetworkFirewallManager(module)
@@ -218,20 +215,20 @@ def main():
if name or arn:
firewall = manager.get_firewall(name=name, arn=arn)
if firewall:
- results['firewalls'] = [firewall]
+ results["firewalls"] = [firewall]
else:
- results['firewalls'] = []
+ results["firewalls"] = []
else:
if vpcs:
firewall_list = manager.list(vpc_ids=vpcs)
else:
firewall_list = manager.list()
- results['firewall_list'] = firewall_list
+ results["firewall_list"] = firewall_list
firewalls = [manager.get_firewall(arn=f) for f in firewall_list]
- results['firewalls'] = firewalls
+ results["firewalls"] = firewalls
module.exit_json(**results)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/networkfirewall_policy.py b/ansible_collections/community/aws/plugins/modules/networkfirewall_policy.py
index 1026138a6..c742c9546 100644
--- a/ansible_collections/community/aws/plugins/modules/networkfirewall_policy.py
+++ b/ansible_collections/community/aws/plugins/modules/networkfirewall_policy.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
module: networkfirewall_policy
short_description: manage AWS Network Firewall policies
version_added: 4.0.0
@@ -78,7 +76,6 @@ options:
C(aws:alert_strict) and C(aws:alert_established).
- Only valid for policies where I(strict_rule_order=true).
- When creating a new policy defaults to C(aws:drop_strict).
- - I(stateful_default_actions) requires botocore>=1.21.52.
required: false
type: list
elements: str
@@ -88,7 +85,6 @@ options:
- When I(strict_rule_order='strict') rules and rule groups are evaluated in
the order that they're defined.
- Cannot be updated after creation.
- - I(stateful_rule_order) requires botocore>=1.21.52.
required: false
type: str
choices: ['default', 'strict']
@@ -139,17 +135,16 @@ options:
type: int
required: false
-
author:
- Mark Chappell (@tremble)
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
- amazon.aws.tags
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
# Create an AWS Network Firewall Policy with default rule order
- community.aws.networkfirewall_policy:
stateful_rule_order: 'default'
@@ -178,9 +173,9 @@ EXAMPLES = '''
- community.aws.networkfirewall_policy:
state: absent
name: 'ExampleDropPolicy'
-'''
+"""
-RETURN = '''
+RETURN = r"""
policy:
description: The details of the policy
type: dict
@@ -336,48 +331,53 @@ policy:
type: dict
returned: success
example: {'tagName': 'Some Value'}
-'''
-
+"""
-from ansible_collections.amazon.aws.plugins.module_utils.modules import AnsibleAWSModule
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
from ansible_collections.community.aws.plugins.module_utils.networkfirewall import NetworkFirewallPolicyManager
def main():
-
custom_action_options = dict(
- name=dict(type='str', required=True),
+ name=dict(type="str", required=True),
# Poorly documented, but "publishMetricAction.dimensions ... must have length less than or equal to 1"
- publish_metric_dimension_value=dict(type='str', required=False, aliases=['publish_metric_dimension_values']),
+ publish_metric_dimension_value=dict(type="str", required=False, aliases=["publish_metric_dimension_values"]),
# NetworkFirewallPolicyManager can cope with a list for future-proofing
# publish_metric_dimension_values=dict(type='list', elements='str', required=False, aliases=['publish_metric_dimension_value']),
)
argument_spec = dict(
- name=dict(type='str', required=False),
- arn=dict(type='str', required=False),
- state=dict(type='str', required=False, default='present', choices=['present', 'absent']),
- description=dict(type='str', required=False),
- tags=dict(type='dict', required=False, aliases=['resource_tags']),
- purge_tags=dict(type='bool', required=False, default=True),
- stateful_rule_groups=dict(type='list', elements='str', required=False, aliases=['stateful_groups']),
- stateless_rule_groups=dict(type='list', elements='str', required=False, aliases=['stateless_groups']),
- stateful_default_actions=dict(type='list', elements='str', required=False),
- stateless_default_actions=dict(type='list', elements='str', required=False),
- stateless_fragment_default_actions=dict(type='list', elements='str', required=False),
- stateful_rule_order=dict(type='str', required=False, choices=['strict', 'default'], aliases=['rule_order']),
- stateless_custom_actions=dict(type='list', elements='dict', required=False,
- options=custom_action_options, aliases=['custom_stateless_actions']),
- purge_stateless_custom_actions=dict(type='bool', required=False, default=True, aliases=['purge_custom_stateless_actions']),
- wait=dict(type='bool', required=False, default=True),
- wait_timeout=dict(type='int', required=False),
+ name=dict(type="str", required=False),
+ arn=dict(type="str", required=False),
+ state=dict(type="str", required=False, default="present", choices=["present", "absent"]),
+ description=dict(type="str", required=False),
+ tags=dict(type="dict", required=False, aliases=["resource_tags"]),
+ purge_tags=dict(type="bool", required=False, default=True),
+ stateful_rule_groups=dict(type="list", elements="str", required=False, aliases=["stateful_groups"]),
+ stateless_rule_groups=dict(type="list", elements="str", required=False, aliases=["stateless_groups"]),
+ stateful_default_actions=dict(type="list", elements="str", required=False),
+ stateless_default_actions=dict(type="list", elements="str", required=False),
+ stateless_fragment_default_actions=dict(type="list", elements="str", required=False),
+ stateful_rule_order=dict(type="str", required=False, choices=["strict", "default"], aliases=["rule_order"]),
+ stateless_custom_actions=dict(
+ type="list",
+ elements="dict",
+ required=False,
+ options=custom_action_options,
+ aliases=["custom_stateless_actions"],
+ ),
+ purge_stateless_custom_actions=dict(
+ type="bool", required=False, default=True, aliases=["purge_custom_stateless_actions"]
+ ),
+ wait=dict(type="bool", required=False, default=True),
+ wait_timeout=dict(type="int", required=False),
)
mutually_exclusive = [
- ('arn', 'name',)
+ ["arn", "name"],
]
required_one_of = [
- ('arn', 'name',)
+ ["arn", "name"],
]
module = AnsibleAWSModule(
@@ -387,36 +387,32 @@ def main():
required_one_of=required_one_of,
)
- arn = module.params.get('arn')
- name = module.params.get('name')
- state = module.params.get('state')
+ arn = module.params.get("arn")
+ name = module.params.get("name")
+ state = module.params.get("state")
manager = NetworkFirewallPolicyManager(module, name=name, arn=arn)
- manager.set_wait(module.params.get('wait', None))
- manager.set_wait_timeout(module.params.get('wait_timeout', None))
+ manager.set_wait(module.params.get("wait", None))
+ manager.set_wait_timeout(module.params.get("wait_timeout", None))
- rule_order = module.params.get('stateful_rule_order')
- if rule_order and rule_order != "default":
- module.require_botocore_at_least('1.21.52', reason='to set the rule order')
- if module.params.get('stateful_default_actions'):
- module.require_botocore_at_least(
- '1.21.52', reason='to set the default actions for stateful flows')
+ rule_order = module.params.get("stateful_rule_order")
- if state == 'absent':
+ if state == "absent":
manager.delete()
else:
- manager.set_description(module.params.get('description', None))
- manager.set_tags(module.params.get('tags', None), module.params.get('purge_tags', None))
+ manager.set_description(module.params.get("description", None))
+ manager.set_tags(module.params.get("tags", None), module.params.get("purge_tags", None))
# Actions need to be defined before potentially consuming them
manager.set_custom_stateless_actions(
- module.params.get('stateless_custom_actions', None),
- module.params.get('purge_stateless_custom_actions', True)),
- manager.set_stateful_rule_order(module.params.get('stateful_rule_order', None))
- manager.set_stateful_rule_groups(module.params.get('stateful_rule_groups', None))
- manager.set_stateless_rule_groups(module.params.get('stateless_rule_groups', None))
- manager.set_stateful_default_actions(module.params.get('stateful_default_actions', None))
- manager.set_stateless_default_actions(module.params.get('stateless_default_actions', None))
- manager.set_stateless_fragment_default_actions(module.params.get('stateless_fragment_default_actions', None))
+ module.params.get("stateless_custom_actions", None),
+ module.params.get("purge_stateless_custom_actions", True),
+ ),
+ manager.set_stateful_rule_order(module.params.get("stateful_rule_order", None))
+ manager.set_stateful_rule_groups(module.params.get("stateful_rule_groups", None))
+ manager.set_stateless_rule_groups(module.params.get("stateless_rule_groups", None))
+ manager.set_stateful_default_actions(module.params.get("stateful_default_actions", None))
+ manager.set_stateless_default_actions(module.params.get("stateless_default_actions", None))
+ manager.set_stateless_fragment_default_actions(module.params.get("stateless_fragment_default_actions", None))
manager.flush_changes()
@@ -429,9 +425,9 @@ def main():
before=manager.original_resource,
after=manager.updated_resource,
)
- results['diff'] = diff
+ results["diff"] = diff
module.exit_json(**results)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/networkfirewall_policy_info.py b/ansible_collections/community/aws/plugins/modules/networkfirewall_policy_info.py
index 1f170f5b3..3bb921745 100644
--- a/ansible_collections/community/aws/plugins/modules/networkfirewall_policy_info.py
+++ b/ansible_collections/community/aws/plugins/modules/networkfirewall_policy_info.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
module: networkfirewall_policy_info
short_description: describe AWS Network Firewall policies
version_added: 4.0.0
@@ -26,14 +24,15 @@ options:
required: false
type: str
-author: Mark Chappell (@tremble)
+author:
+ - Mark Chappell (@tremble)
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
# Describe all Firewall policies in an account
- community.aws.networkfirewall_policy_info: {}
@@ -45,9 +44,9 @@ EXAMPLES = '''
# Describe a Firewall policy by name
- community.aws.networkfirewall_policy_info:
name: ExamplePolicy
-'''
+"""
-RETURN = '''
+RETURN = r"""
policy_list:
description: A list of ARNs of the matching policies.
type: list
@@ -212,30 +211,28 @@ policies:
type: dict
returned: success
example: {'tagName': 'Some Value'}
-'''
+"""
-
-from ansible_collections.amazon.aws.plugins.module_utils.modules import AnsibleAWSModule
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
from ansible_collections.community.aws.plugins.module_utils.networkfirewall import NetworkFirewallPolicyManager
def main():
-
argument_spec = dict(
- name=dict(type='str', required=False),
- arn=dict(type='str', required=False),
+ name=dict(type="str", required=False),
+ arn=dict(type="str", required=False),
)
module = AnsibleAWSModule(
argument_spec=argument_spec,
supports_check_mode=True,
mutually_exclusive=[
- ('arn', 'name',),
+ ["arn", "name"],
],
)
- arn = module.params.get('arn')
- name = module.params.get('name')
+ arn = module.params.get("arn")
+ name = module.params.get("name")
manager = NetworkFirewallPolicyManager(module)
@@ -244,17 +241,17 @@ def main():
if name or arn:
policy = manager.get_policy(name=name, arn=arn)
if policy:
- results['policies'] = [policy]
+ results["policies"] = [policy]
else:
- results['policies'] = []
+ results["policies"] = []
else:
policy_list = manager.list()
- results['policy_list'] = policy_list
+ results["policy_list"] = policy_list
policies = [manager.get_policy(arn=p) for p in policy_list]
- results['policies'] = policies
+ results["policies"] = policies
module.exit_json(**results)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/networkfirewall_rule_group.py b/ansible_collections/community/aws/plugins/modules/networkfirewall_rule_group.py
index c8e2ea38b..9300036c5 100644
--- a/ansible_collections/community/aws/plugins/modules/networkfirewall_rule_group.py
+++ b/ansible_collections/community/aws/plugins/modules/networkfirewall_rule_group.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
module: networkfirewall_rule_group
short_description: create, delete and modify AWS Network Firewall rule groups
version_added: 4.0.0
@@ -60,7 +58,6 @@ options:
- Mutually exclusive with I(rule_type=stateless).
- For more information on how rules are evaluated read the AWS documentation
U(https://docs.aws.amazon.com/network-firewall/latest/developerguide/suricata-rule-evaluation-order.html).
- - I(rule_order) requires botocore>=1.23.23.
type: str
required: false
choices: ['default', 'strict']
@@ -263,17 +260,16 @@ options:
type: int
required: false
-
author:
- Mark Chappell (@tremble)
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
- - amazon.aws.boto3
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.tags
-'''
+ - amazon.aws.boto3
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
# Create a rule group
- name: Create a minimal AWS Network Firewall Rule Group
community.aws.networkfirewall_rule_group:
@@ -369,8 +365,8 @@ EXAMPLES = '''
domain_names:
- 'example.com'
- '.example.net'
- filter_https: True
- filter_http: True
+ filter_https: true
+ filter_http: true
action: allow
source_ips: '192.0.2.0/24'
@@ -396,10 +392,9 @@ EXAMPLES = '''
name: 'MinimalGroup'
type: 'stateful'
state: absent
+"""
-'''
-
-RETURN = '''
+RETURN = r"""
rule_group:
description: Details of the rules in the rule group
type: dict
@@ -708,109 +703,104 @@ rule_group:
type: str
returned: success
example: 'STATEFUL'
-'''
-
+"""
-from ansible_collections.amazon.aws.plugins.module_utils.modules import AnsibleAWSModule
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
from ansible_collections.community.aws.plugins.module_utils.networkfirewall import NetworkFirewallRuleManager
def main():
-
domain_list_spec = dict(
- domain_names=dict(type='list', elements='str', required=True),
- filter_http=dict(type='bool', required=False, default=False),
- filter_https=dict(type='bool', required=False, default=False),
- action=dict(type='str', required=True, choices=['allow', 'deny']),
- source_ips=dict(type='list', elements='str', required=False),
+ domain_names=dict(type="list", elements="str", required=True),
+ filter_http=dict(type="bool", required=False, default=False),
+ filter_https=dict(type="bool", required=False, default=False),
+ action=dict(type="str", required=True, choices=["allow", "deny"]),
+ source_ips=dict(type="list", elements="str", required=False),
)
rule_list_spec = dict(
- action=dict(type='str', required=True, choices=['pass', 'drop', 'alert']),
- protocol=dict(type='str', required=True),
- source=dict(type='str', required=True),
- source_port=dict(type='str', required=True),
- direction=dict(type='str', required=False, default='forward', choices=['forward', 'any']),
- destination=dict(type='str', required=True),
- destination_port=dict(type='str', required=True),
- sid=dict(type='int', required=True),
- rule_options=dict(type='dict', required=False),
+ action=dict(type="str", required=True, choices=["pass", "drop", "alert"]),
+ protocol=dict(type="str", required=True),
+ source=dict(type="str", required=True),
+ source_port=dict(type="str", required=True),
+ direction=dict(type="str", required=False, default="forward", choices=["forward", "any"]),
+ destination=dict(type="str", required=True),
+ destination_port=dict(type="str", required=True),
+ sid=dict(type="int", required=True),
+ rule_options=dict(type="dict", required=False),
)
argument_spec = dict(
- arn=dict(type='str', required=False),
- name=dict(type='str', required=False),
- rule_type=dict(type='str', required=False, aliases=['type'], choices=['stateful']),
+ arn=dict(type="str", required=False),
+ name=dict(type="str", required=False),
+ rule_type=dict(type="str", required=False, aliases=["type"], choices=["stateful"]),
# rule_type=dict(type='str', required=True, aliases=['type'], choices=['stateless', 'stateful']),
- state=dict(type='str', required=False, choices=['present', 'absent'], default='present'),
- capacity=dict(type='int', required=False),
- rule_order=dict(type='str', required=False, aliases=['stateful_rule_order'], choices=['default', 'strict']),
- description=dict(type='str', required=False),
- ip_variables=dict(type='dict', required=False, aliases=['ip_set_variables']),
- purge_ip_variables=dict(type='bool', required=False, aliases=['purge_ip_set_variables'], default=True),
- port_variables=dict(type='dict', required=False, aliases=['port_set_variables']),
- purge_port_variables=dict(type='bool', required=False, aliases=['purge_port_set_variables'], default=True),
- rule_strings=dict(type='list', elements='str', required=False),
- domain_list=dict(type='dict', options=domain_list_spec, required=False),
- rule_list=dict(type='list', elements='dict', aliases=['stateful_rule_list'], options=rule_list_spec, required=False),
- tags=dict(type='dict', required=False, aliases=['resource_tags']),
- purge_tags=dict(type='bool', required=False, default=True),
- wait=dict(type='bool', required=False, default=True),
- wait_timeout=dict(type='int', required=False),
+ state=dict(type="str", required=False, choices=["present", "absent"], default="present"),
+ capacity=dict(type="int", required=False),
+ rule_order=dict(type="str", required=False, aliases=["stateful_rule_order"], choices=["default", "strict"]),
+ description=dict(type="str", required=False),
+ ip_variables=dict(type="dict", required=False, aliases=["ip_set_variables"]),
+ purge_ip_variables=dict(type="bool", required=False, aliases=["purge_ip_set_variables"], default=True),
+ port_variables=dict(type="dict", required=False, aliases=["port_set_variables"]),
+ purge_port_variables=dict(type="bool", required=False, aliases=["purge_port_set_variables"], default=True),
+ rule_strings=dict(type="list", elements="str", required=False),
+ domain_list=dict(type="dict", options=domain_list_spec, required=False),
+ rule_list=dict(
+ type="list", elements="dict", aliases=["stateful_rule_list"], options=rule_list_spec, required=False
+ ),
+ tags=dict(type="dict", required=False, aliases=["resource_tags"]),
+ purge_tags=dict(type="bool", required=False, default=True),
+ wait=dict(type="bool", required=False, default=True),
+ wait_timeout=dict(type="int", required=False),
)
module = AnsibleAWSModule(
argument_spec=argument_spec,
supports_check_mode=True,
mutually_exclusive=[
- ('name', 'arn'),
- ('rule_strings', 'domain_list', 'rule_list'),
- ('domain_list', 'ip_variables'),
+ ["name", "arn"],
+ ["rule_strings", "domain_list", "rule_list"],
+ ["domain_list", "ip_variables"],
],
required_together=[
- ('name', 'rule_type'),
+ ["name", "rule_type"],
],
required_one_of=[
- ('name', 'arn'),
+ ["name", "arn"],
],
)
- module.require_botocore_at_least('1.19.20')
-
- state = module.params.get('state')
- name = module.params.get('name')
- arn = module.params.get('arn')
- rule_type = module.params.get('rule_type')
-
- if rule_type == 'stateless':
- if module.params.get('rule_order'):
- module.fail_json('rule_order can not be set for stateless rule groups')
- if module.params.get('rule_strings'):
- module.fail_json('rule_strings can only be used for stateful rule groups')
- if module.params.get('rule_list'):
- module.fail_json('rule_list can only be used for stateful rule groups')
- if module.params.get('domain_list'):
- module.fail_json('domain_list can only be used for stateful rule groups')
-
- if module.params.get('rule_order'):
- module.require_botocore_at_least('1.23.23', reason='to set the rule order')
+ state = module.params.get("state")
+ name = module.params.get("name")
+ arn = module.params.get("arn")
+ rule_type = module.params.get("rule_type")
+
+ if rule_type == "stateless":
+ if module.params.get("rule_order"):
+ module.fail_json("rule_order can not be set for stateless rule groups")
+ if module.params.get("rule_strings"):
+ module.fail_json("rule_strings can only be used for stateful rule groups")
+ if module.params.get("rule_list"):
+ module.fail_json("rule_list can only be used for stateful rule groups")
+ if module.params.get("domain_list"):
+ module.fail_json("domain_list can only be used for stateful rule groups")
manager = NetworkFirewallRuleManager(module, arn=arn, name=name, rule_type=rule_type)
- manager.set_wait(module.params.get('wait', None))
- manager.set_wait_timeout(module.params.get('wait_timeout', None))
+ manager.set_wait(module.params.get("wait", None))
+ manager.set_wait_timeout(module.params.get("wait_timeout", None))
- if state == 'absent':
+ if state == "absent":
manager.delete()
else:
- manager.set_description(module.params.get('description'))
- manager.set_capacity(module.params.get('capacity'))
- manager.set_rule_order(module.params.get('rule_order'))
- manager.set_ip_variables(module.params.get('ip_variables'), module.params.get('purge_ip_variables'))
- manager.set_port_variables(module.params.get('port_variables'), module.params.get('purge_port_variables'))
- manager.set_rule_string(module.params.get('rule_strings'))
- manager.set_domain_list(module.params.get('domain_list'))
- manager.set_rule_list(module.params.get('rule_list'))
- manager.set_tags(module.params.get('tags'), module.params.get('purge_tags'))
+ manager.set_description(module.params.get("description"))
+ manager.set_capacity(module.params.get("capacity"))
+ manager.set_rule_order(module.params.get("rule_order"))
+ manager.set_ip_variables(module.params.get("ip_variables"), module.params.get("purge_ip_variables"))
+ manager.set_port_variables(module.params.get("port_variables"), module.params.get("purge_port_variables"))
+ manager.set_rule_string(module.params.get("rule_strings"))
+ manager.set_domain_list(module.params.get("domain_list"))
+ manager.set_rule_list(module.params.get("rule_list"))
+ manager.set_tags(module.params.get("tags"), module.params.get("purge_tags"))
manager.flush_changes()
@@ -823,9 +813,9 @@ def main():
before=manager.original_resource,
after=manager.updated_resource,
)
- results['diff'] = diff
+ results["diff"] = diff
module.exit_json(**results)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/networkfirewall_rule_group_info.py b/ansible_collections/community/aws/plugins/modules/networkfirewall_rule_group_info.py
index a9cec3778..8b3c9d230 100644
--- a/ansible_collections/community/aws/plugins/modules/networkfirewall_rule_group_info.py
+++ b/ansible_collections/community/aws/plugins/modules/networkfirewall_rule_group_info.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
module: networkfirewall_rule_group_info
short_description: describe AWS Network Firewall rule groups
version_added: 4.0.0
@@ -38,19 +36,19 @@ options:
- When I(scope='account') returns a description of all rule groups in the account.
- When I(scope='managed') returns a list of available managed rule group arns.
- By default searches only at the account scope.
- - I(scope='managed') requires botocore>=1.23.23.
required: false
choices: ['managed', 'account']
type: str
-author: Mark Chappell (@tremble)
+author:
+ - Mark Chappell (@tremble)
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
# Describe all Rule Groups in an account (excludes managed groups)
- community.aws.networkfirewall_rule_group_info: {}
@@ -68,10 +66,9 @@ EXAMPLES = '''
- community.aws.networkfirewall_rule_group_info:
name: ExampleRuleGroup
type: stateful
+"""
-'''
-
-RETURN = '''
+RETURN = r"""
rule_list:
description: A list of ARNs of the matching rule groups.
type: list
@@ -387,43 +384,36 @@ rule_groups:
type: str
returned: success
example: 'STATEFUL'
-'''
-
+"""
-from ansible_collections.amazon.aws.plugins.module_utils.modules import AnsibleAWSModule
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
from ansible_collections.community.aws.plugins.module_utils.networkfirewall import NetworkFirewallRuleManager
def main():
-
argument_spec = dict(
- name=dict(type='str', required=False),
- rule_type=dict(type='str', required=False, aliases=['type'], choices=['stateless', 'stateful']),
- arn=dict(type='str', required=False),
- scope=dict(type='str', required=False, choices=['managed', 'account']),
+ name=dict(type="str", required=False),
+ rule_type=dict(type="str", required=False, aliases=["type"], choices=["stateless", "stateful"]),
+ arn=dict(type="str", required=False),
+ scope=dict(type="str", required=False, choices=["managed", "account"]),
)
module = AnsibleAWSModule(
argument_spec=argument_spec,
supports_check_mode=True,
mutually_exclusive=[
- ('arn', 'name',),
- ('arn', 'rule_type'),
+ ["arn", "name"],
+ ["arn", "rule_type"],
],
required_together=[
- ('name', 'rule_type'),
- ]
+ ["name", "rule_type"],
+ ],
)
- module.require_botocore_at_least('1.19.20')
-
- arn = module.params.get('arn')
- name = module.params.get('name')
- rule_type = module.params.get('rule_type')
- scope = module.params.get('scope')
-
- if module.params.get('scope') == 'managed':
- module.require_botocore_at_least('1.23.23', reason='to list managed rules')
+ arn = module.params.get("arn")
+ name = module.params.get("name")
+ rule_type = module.params.get("rule_type")
+ scope = module.params.get("scope")
manager = NetworkFirewallRuleManager(module, name=name, rule_type=rule_type)
@@ -432,18 +422,18 @@ def main():
if name or arn:
rule = manager.get_rule_group(name=name, rule_type=rule_type, arn=arn)
if rule:
- results['rule_groups'] = [rule]
+ results["rule_groups"] = [rule]
else:
- results['rule_groups'] = []
+ results["rule_groups"] = []
else:
rule_list = manager.list(scope=scope)
- results['rule_list'] = rule_list
- if scope != 'managed':
+ results["rule_list"] = rule_list
+ if scope != "managed":
rules = [manager.get_rule_group(arn=r) for r in rule_list]
- results['rule_groups'] = rules
+ results["rule_groups"] = rules
module.exit_json(**results)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/opensearch.py b/ansible_collections/community/aws/plugins/modules/opensearch.py
index 7ed8c0722..d89e173bb 100644
--- a/ansible_collections/community/aws/plugins/modules/opensearch.py
+++ b/ansible_collections/community/aws/plugins/modules/opensearch.py
@@ -1,20 +1,18 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = """
+DOCUMENTATION = r"""
---
module: opensearch
short_description: Creates OpenSearch or ElasticSearch domain
description:
- Creates or modify a Amazon OpenSearch Service domain.
version_added: 4.0.0
-author: "Sebastien Rosset (@sebastien-rosset)"
+author:
+ - "Sebastien Rosset (@sebastien-rosset)"
options:
state:
description:
@@ -387,16 +385,16 @@ options:
- how long before wait gives up, in seconds.
default: 300
type: int
-requirements:
- - botocore >= 1.21.38
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
- - amazon.aws.boto3
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.tags
+ - amazon.aws.boto3
"""
-EXAMPLES = """
+RETURN = r""" # """
+
+EXAMPLES = r"""
- name: Create OpenSearch domain for dev environment, no zone awareness, no dedicated masters
community.aws.opensearch:
@@ -452,16 +450,16 @@ EXAMPLES = """
auto_tune_options:
enabled: true
maintenance_schedules:
- - start_at: "2025-01-12"
- duration:
- value: 1
- unit: "HOURS"
- cron_expression_for_recurrence: "cron(0 12 * * ? *)"
- - start_at: "2032-01-12"
- duration:
- value: 2
- unit: "HOURS"
- cron_expression_for_recurrence: "cron(0 12 * * ? *)"
+ - start_at: "2025-01-12"
+ duration:
+ value: 1
+ unit: "HOURS"
+ cron_expression_for_recurrence: "cron(0 12 * * ? *)"
+ - start_at: "2032-01-12"
+ duration:
+ value: 2
+ unit: "HOURS"
+ cron_expression_for_recurrence: "cron(0 12 * * ? *)"
tags:
Environment: Development
Application: Search
@@ -480,12 +478,11 @@ EXAMPLES = """
cluster_config:
instance_count: 40
wait: true
-
"""
-from copy import deepcopy
import datetime
import json
+from copy import deepcopy
try:
import botocore
@@ -494,26 +491,20 @@ except ImportError:
from ansible.module_utils.six import string_types
-# import module snippets
-from ansible_collections.amazon.aws.plugins.module_utils.core import (
- AnsibleAWSModule,
- is_boto3_error_code,
-)
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import (
- AWSRetry,
- boto3_tag_list_to_ansible_dict,
- compare_policies,
-)
-from ansible_collections.community.aws.plugins.module_utils.opensearch import (
- compare_domain_versions,
- ensure_tags,
- get_domain_status,
- get_domain_config,
- get_target_increment_version,
- normalize_opensearch,
- parse_version,
- wait_for_domain_status,
-)
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.policy import compare_policies
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
+from ansible_collections.community.aws.plugins.module_utils.opensearch import compare_domain_versions
+from ansible_collections.community.aws.plugins.module_utils.opensearch import ensure_tags
+from ansible_collections.community.aws.plugins.module_utils.opensearch import get_domain_config
+from ansible_collections.community.aws.plugins.module_utils.opensearch import get_domain_status
+from ansible_collections.community.aws.plugins.module_utils.opensearch import get_target_increment_version
+from ansible_collections.community.aws.plugins.module_utils.opensearch import normalize_opensearch
+from ansible_collections.community.aws.plugins.module_utils.opensearch import parse_version
+from ansible_collections.community.aws.plugins.module_utils.opensearch import wait_for_domain_status
def ensure_domain_absent(client, module):
@@ -522,16 +513,17 @@ def ensure_domain_absent(client, module):
domain = get_domain_status(client, module, domain_name)
if module.check_mode:
- module.exit_json(
- changed=True, msg="Would have deleted domain if not in check mode"
- )
+ module.exit_json(changed=True, msg="Would have deleted domain if not in check mode")
try:
client.delete_domain(DomainName=domain_name)
changed = True
except is_boto3_error_code("ResourceNotFoundException"):
# The resource does not exist, or it has already been deleted
return dict(changed=False)
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
module.fail_json_aws(e, msg="trying to delete domain")
# If we're not waiting for a delete to complete then we're all done
@@ -543,7 +535,10 @@ def ensure_domain_absent(client, module):
return dict(changed=changed)
except is_boto3_error_code("ResourceNotFoundException"):
return dict(changed=changed)
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
module.fail_json_aws(e, "awaiting domain deletion")
@@ -568,8 +563,9 @@ def upgrade_domain(client, module, source_version, target_engine_version):
# It's not possible to upgrade directly to the target version.
# Check the module parameters to determine if this is allowed or not.
if not module.params.get("allow_intermediate_upgrades"):
- module.fail_json(msg="Cannot upgrade from {0} to version {1}. The highest compatible version is {2}".format(
- source_version, target_engine_version, next_version))
+ module.fail_json(
+ msg=f"Cannot upgrade from {source_version} to version {target_engine_version}. The highest compatible version is {next_version}"
+ )
parameters = {
"DomainName": domain_name,
@@ -592,17 +588,13 @@ def upgrade_domain(client, module, source_version, target_engine_version):
# raised if it's not possible to upgrade to the target version.
module.fail_json_aws(
e,
- msg="Couldn't upgrade domain {0} from {1} to {2}".format(
- domain_name, current_version, next_version
- ),
+ msg=f"Couldn't upgrade domain {domain_name} from {current_version} to {next_version}",
)
if module.check_mode:
module.exit_json(
changed=True,
- msg="Would have upgraded domain from {0} to {1} if not in check mode".format(
- current_version, next_version
- ),
+ msg=f"Would have upgraded domain from {current_version} to {next_version} if not in check mode",
)
current_version = next_version
@@ -610,9 +602,7 @@ def upgrade_domain(client, module, source_version, target_engine_version):
wait_for_domain_status(client, module, domain_name, "domain_available")
-def set_cluster_config(
- module, current_domain_config, desired_domain_config, change_set
-):
+def set_cluster_config(module, current_domain_config, desired_domain_config, change_set):
changed = False
cluster_config = desired_domain_config["ClusterConfig"]
@@ -627,24 +617,16 @@ def set_cluster_config(
if cluster_config["ZoneAwarenessEnabled"]:
if cluster_opts.get("availability_zone_count") is not None:
cluster_config["ZoneAwarenessConfig"] = {
- "AvailabilityZoneCount": cluster_opts.get(
- "availability_zone_count"
- ),
+ "AvailabilityZoneCount": cluster_opts.get("availability_zone_count"),
}
if cluster_opts.get("dedicated_master") is not None:
- cluster_config["DedicatedMasterEnabled"] = cluster_opts.get(
- "dedicated_master"
- )
+ cluster_config["DedicatedMasterEnabled"] = cluster_opts.get("dedicated_master")
if cluster_config["DedicatedMasterEnabled"]:
if cluster_opts.get("dedicated_master_instance_type") is not None:
- cluster_config["DedicatedMasterType"] = cluster_opts.get(
- "dedicated_master_instance_type"
- )
+ cluster_config["DedicatedMasterType"] = cluster_opts.get("dedicated_master_instance_type")
if cluster_opts.get("dedicated_master_instance_count") is not None:
- cluster_config["DedicatedMasterCount"] = cluster_opts.get(
- "dedicated_master_instance_count"
- )
+ cluster_config["DedicatedMasterCount"] = cluster_opts.get("dedicated_master_instance_count")
if cluster_opts.get("warm_enabled") is not None:
cluster_config["WarmEnabled"] = cluster_opts.get("warm_enabled")
@@ -665,32 +647,19 @@ def set_cluster_config(
if cold_storage_opts is not None and cold_storage_opts.get("enabled"):
module.fail_json(msg="Cold Storage is not supported")
cluster_config.pop("ColdStorageOptions", None)
- if (
- current_domain_config is not None
- and "ClusterConfig" in current_domain_config
- ):
+ if current_domain_config is not None and "ClusterConfig" in current_domain_config:
# Remove 'ColdStorageOptions' from the current domain config, otherwise the actual vs desired diff
# will indicate a change must be done.
current_domain_config["ClusterConfig"].pop("ColdStorageOptions", None)
else:
# Elasticsearch 7.9 and above support ColdStorageOptions.
- if (
- cold_storage_opts is not None
- and cold_storage_opts.get("enabled") is not None
- ):
+ if cold_storage_opts is not None and cold_storage_opts.get("enabled") is not None:
cluster_config["ColdStorageOptions"] = {
"Enabled": cold_storage_opts.get("enabled"),
}
- if (
- current_domain_config is not None
- and current_domain_config["ClusterConfig"] != cluster_config
- ):
- change_set.append(
- "ClusterConfig changed from {0} to {1}".format(
- current_domain_config["ClusterConfig"], cluster_config
- )
- )
+ if current_domain_config is not None and current_domain_config["ClusterConfig"] != cluster_config:
+ change_set.append(f"ClusterConfig changed from {current_domain_config['ClusterConfig']} to {cluster_config}")
changed = True
return changed
@@ -716,22 +685,13 @@ def set_ebs_options(module, current_domain_config, desired_domain_config, change
if ebs_opts.get("iops") is not None:
ebs_config["Iops"] = ebs_opts.get("iops")
- if (
- current_domain_config is not None
- and current_domain_config["EBSOptions"] != ebs_config
- ):
- change_set.append(
- "EBSOptions changed from {0} to {1}".format(
- current_domain_config["EBSOptions"], ebs_config
- )
- )
+ if current_domain_config is not None and current_domain_config["EBSOptions"] != ebs_config:
+ change_set.append(f"EBSOptions changed from {current_domain_config['EBSOptions']} to {ebs_config}")
changed = True
return changed
-def set_encryption_at_rest_options(
- module, current_domain_config, desired_domain_config, change_set
-):
+def set_encryption_at_rest_options(module, current_domain_config, desired_domain_config, change_set):
changed = False
encryption_at_rest_config = desired_domain_config["EncryptionAtRestOptions"]
encryption_at_rest_opts = module.params.get("encryption_at_rest_options")
@@ -745,50 +705,36 @@ def set_encryption_at_rest_options(
}
else:
if encryption_at_rest_opts.get("kms_key_id") is not None:
- encryption_at_rest_config["KmsKeyId"] = encryption_at_rest_opts.get(
- "kms_key_id"
- )
+ encryption_at_rest_config["KmsKeyId"] = encryption_at_rest_opts.get("kms_key_id")
if (
current_domain_config is not None
- and current_domain_config["EncryptionAtRestOptions"]
- != encryption_at_rest_config
+ and current_domain_config["EncryptionAtRestOptions"] != encryption_at_rest_config
):
change_set.append(
- "EncryptionAtRestOptions changed from {0} to {1}".format(
- current_domain_config["EncryptionAtRestOptions"],
- encryption_at_rest_config,
- )
+ f"EncryptionAtRestOptions changed from {current_domain_config['EncryptionAtRestOptions']} to"
+ f" {encryption_at_rest_config}"
)
changed = True
return changed
-def set_node_to_node_encryption_options(
- module, current_domain_config, desired_domain_config, change_set
-):
+def set_node_to_node_encryption_options(module, current_domain_config, desired_domain_config, change_set):
changed = False
- node_to_node_encryption_config = desired_domain_config[
- "NodeToNodeEncryptionOptions"
- ]
+ node_to_node_encryption_config = desired_domain_config["NodeToNodeEncryptionOptions"]
node_to_node_encryption_opts = module.params.get("node_to_node_encryption_options")
if node_to_node_encryption_opts is None:
return changed
if node_to_node_encryption_opts.get("enabled") is not None:
- node_to_node_encryption_config["Enabled"] = node_to_node_encryption_opts.get(
- "enabled"
- )
+ node_to_node_encryption_config["Enabled"] = node_to_node_encryption_opts.get("enabled")
if (
current_domain_config is not None
- and current_domain_config["NodeToNodeEncryptionOptions"]
- != node_to_node_encryption_config
+ and current_domain_config["NodeToNodeEncryptionOptions"] != node_to_node_encryption_config
):
change_set.append(
- "NodeToNodeEncryptionOptions changed from {0} to {1}".format(
- current_domain_config["NodeToNodeEncryptionOptions"],
- node_to_node_encryption_config,
- )
+ f"NodeToNodeEncryptionOptions changed from {current_domain_config['NodeToNodeEncryptionOptions']} to"
+ f" {node_to_node_encryption_config}"
)
changed = True
return changed
@@ -846,53 +792,36 @@ def set_vpc_options(module, current_domain_config, desired_domain_config, change
pass
else:
# Note the subnets may be the same but be listed in a different order.
- if set(current_domain_config["VPCOptions"]["SubnetIds"]) != set(
- vpc_config["SubnetIds"]
- ):
+ if set(current_domain_config["VPCOptions"]["SubnetIds"]) != set(vpc_config["SubnetIds"]):
change_set.append(
- "SubnetIds changed from {0} to {1}".format(
- current_domain_config["VPCOptions"]["SubnetIds"],
- vpc_config["SubnetIds"],
- )
+ f"SubnetIds changed from {current_domain_config['VPCOptions']['SubnetIds']} to"
+ f" {vpc_config['SubnetIds']}"
)
changed = True
- if set(current_domain_config["VPCOptions"]["SecurityGroupIds"]) != set(
- vpc_config["SecurityGroupIds"]
- ):
+ if set(current_domain_config["VPCOptions"]["SecurityGroupIds"]) != set(vpc_config["SecurityGroupIds"]):
change_set.append(
- "SecurityGroup changed from {0} to {1}".format(
- current_domain_config["VPCOptions"]["SecurityGroupIds"],
- vpc_config["SecurityGroupIds"],
- )
+ f"SecurityGroup changed from {current_domain_config['VPCOptions']['SecurityGroupIds']} to"
+ f" {vpc_config['SecurityGroupIds']}"
)
changed = True
return changed
-def set_snapshot_options(
- module, current_domain_config, desired_domain_config, change_set
-):
+def set_snapshot_options(module, current_domain_config, desired_domain_config, change_set):
changed = False
snapshot_config = desired_domain_config["SnapshotOptions"]
snapshot_opts = module.params.get("snapshot_options")
if snapshot_opts is None:
return changed
if snapshot_opts.get("automated_snapshot_start_hour") is not None:
- snapshot_config["AutomatedSnapshotStartHour"] = snapshot_opts.get(
- "automated_snapshot_start_hour"
- )
- if (
- current_domain_config is not None
- and current_domain_config["SnapshotOptions"] != snapshot_config
- ):
+ snapshot_config["AutomatedSnapshotStartHour"] = snapshot_opts.get("automated_snapshot_start_hour")
+ if current_domain_config is not None and current_domain_config["SnapshotOptions"] != snapshot_config:
change_set.append("SnapshotOptions changed")
changed = True
return changed
-def set_cognito_options(
- module, current_domain_config, desired_domain_config, change_set
-):
+def set_cognito_options(module, current_domain_config, desired_domain_config, change_set):
changed = False
cognito_config = desired_domain_config["CognitoOptions"]
cognito_opts = module.params.get("cognito_options")
@@ -908,28 +837,17 @@ def set_cognito_options(
if cognito_opts.get("cognito_user_pool_id") is not None:
cognito_config["UserPoolId"] = cognito_opts.get("cognito_user_pool_id")
if cognito_opts.get("cognito_identity_pool_id") is not None:
- cognito_config["IdentityPoolId"] = cognito_opts.get(
- "cognito_identity_pool_id"
- )
+ cognito_config["IdentityPoolId"] = cognito_opts.get("cognito_identity_pool_id")
if cognito_opts.get("cognito_role_arn") is not None:
cognito_config["RoleArn"] = cognito_opts.get("cognito_role_arn")
- if (
- current_domain_config is not None
- and current_domain_config["CognitoOptions"] != cognito_config
- ):
- change_set.append(
- "CognitoOptions changed from {0} to {1}".format(
- current_domain_config["CognitoOptions"], cognito_config
- )
- )
+ if current_domain_config is not None and current_domain_config["CognitoOptions"] != cognito_config:
+ change_set.append(f"CognitoOptions changed from {current_domain_config['CognitoOptions']} to {cognito_config}")
changed = True
return changed
-def set_advanced_security_options(
- module, current_domain_config, desired_domain_config, change_set
-):
+def set_advanced_security_options(module, current_domain_config, desired_domain_config, change_set):
changed = False
advanced_security_config = desired_domain_config["AdvancedSecurityOptions"]
advanced_security_opts = module.params.get("advanced_security_options")
@@ -943,121 +861,87 @@ def set_advanced_security_options(
}
else:
if advanced_security_opts.get("internal_user_database_enabled") is not None:
- advanced_security_config[
- "InternalUserDatabaseEnabled"
- ] = advanced_security_opts.get("internal_user_database_enabled")
+ advanced_security_config["InternalUserDatabaseEnabled"] = advanced_security_opts.get(
+ "internal_user_database_enabled"
+ )
master_user_opts = advanced_security_opts.get("master_user_options")
if master_user_opts is not None:
advanced_security_config.setdefault("MasterUserOptions", {})
if master_user_opts.get("master_user_arn") is not None:
- advanced_security_config["MasterUserOptions"][
- "MasterUserARN"
- ] = master_user_opts.get("master_user_arn")
+ advanced_security_config["MasterUserOptions"]["MasterUserARN"] = master_user_opts.get("master_user_arn")
if master_user_opts.get("master_user_name") is not None:
- advanced_security_config["MasterUserOptions"][
- "MasterUserName"
- ] = master_user_opts.get("master_user_name")
+ advanced_security_config["MasterUserOptions"]["MasterUserName"] = master_user_opts.get(
+ "master_user_name"
+ )
if master_user_opts.get("master_user_password") is not None:
- advanced_security_config["MasterUserOptions"][
- "MasterUserPassword"
- ] = master_user_opts.get("master_user_password")
+ advanced_security_config["MasterUserOptions"]["MasterUserPassword"] = master_user_opts.get(
+ "master_user_password"
+ )
saml_opts = advanced_security_opts.get("saml_options")
if saml_opts is not None:
if saml_opts.get("enabled") is not None:
- advanced_security_config["SamlOptions"]["Enabled"] = saml_opts.get(
- "enabled"
- )
+ advanced_security_config["SamlOptions"]["Enabled"] = saml_opts.get("enabled")
idp_opts = saml_opts.get("idp")
if idp_opts is not None:
if idp_opts.get("metadata_content") is not None:
- advanced_security_config["SamlOptions"]["Idp"][
- "MetadataContent"
- ] = idp_opts.get("metadata_content")
+ advanced_security_config["SamlOptions"]["Idp"]["MetadataContent"] = idp_opts.get("metadata_content")
if idp_opts.get("entity_id") is not None:
- advanced_security_config["SamlOptions"]["Idp"][
- "EntityId"
- ] = idp_opts.get("entity_id")
+ advanced_security_config["SamlOptions"]["Idp"]["EntityId"] = idp_opts.get("entity_id")
if saml_opts.get("master_user_name") is not None:
- advanced_security_config["SamlOptions"][
- "MasterUserName"
- ] = saml_opts.get("master_user_name")
+ advanced_security_config["SamlOptions"]["MasterUserName"] = saml_opts.get("master_user_name")
if saml_opts.get("master_backend_role") is not None:
- advanced_security_config["SamlOptions"][
- "MasterBackendRole"
- ] = saml_opts.get("master_backend_role")
+ advanced_security_config["SamlOptions"]["MasterBackendRole"] = saml_opts.get("master_backend_role")
if saml_opts.get("subject_key") is not None:
- advanced_security_config["SamlOptions"]["SubjectKey"] = saml_opts.get(
- "subject_key"
- )
+ advanced_security_config["SamlOptions"]["SubjectKey"] = saml_opts.get("subject_key")
if saml_opts.get("roles_key") is not None:
- advanced_security_config["SamlOptions"]["RolesKey"] = saml_opts.get(
- "roles_key"
- )
+ advanced_security_config["SamlOptions"]["RolesKey"] = saml_opts.get("roles_key")
if saml_opts.get("session_timeout_minutes") is not None:
- advanced_security_config["SamlOptions"][
- "SessionTimeoutMinutes"
- ] = saml_opts.get("session_timeout_minutes")
+ advanced_security_config["SamlOptions"]["SessionTimeoutMinutes"] = saml_opts.get(
+ "session_timeout_minutes"
+ )
if (
current_domain_config is not None
and current_domain_config["AdvancedSecurityOptions"] != advanced_security_config
):
change_set.append(
- "AdvancedSecurityOptions changed from {0} to {1}".format(
- current_domain_config["AdvancedSecurityOptions"],
- advanced_security_config,
- )
+ f"AdvancedSecurityOptions changed from {current_domain_config['AdvancedSecurityOptions']} to"
+ f" {advanced_security_config}"
)
changed = True
return changed
-def set_domain_endpoint_options(
- module, current_domain_config, desired_domain_config, change_set
-):
+def set_domain_endpoint_options(module, current_domain_config, desired_domain_config, change_set):
changed = False
domain_endpoint_config = desired_domain_config["DomainEndpointOptions"]
domain_endpoint_opts = module.params.get("domain_endpoint_options")
if domain_endpoint_opts is None:
return changed
if domain_endpoint_opts.get("enforce_https") is not None:
- domain_endpoint_config["EnforceHTTPS"] = domain_endpoint_opts.get(
- "enforce_https"
- )
+ domain_endpoint_config["EnforceHTTPS"] = domain_endpoint_opts.get("enforce_https")
if domain_endpoint_opts.get("tls_security_policy") is not None:
- domain_endpoint_config["TLSSecurityPolicy"] = domain_endpoint_opts.get(
- "tls_security_policy"
- )
+ domain_endpoint_config["TLSSecurityPolicy"] = domain_endpoint_opts.get("tls_security_policy")
if domain_endpoint_opts.get("custom_endpoint_enabled") is not None:
- domain_endpoint_config["CustomEndpointEnabled"] = domain_endpoint_opts.get(
- "custom_endpoint_enabled"
- )
+ domain_endpoint_config["CustomEndpointEnabled"] = domain_endpoint_opts.get("custom_endpoint_enabled")
if domain_endpoint_config["CustomEndpointEnabled"]:
if domain_endpoint_opts.get("custom_endpoint") is not None:
- domain_endpoint_config["CustomEndpoint"] = domain_endpoint_opts.get(
- "custom_endpoint"
- )
+ domain_endpoint_config["CustomEndpoint"] = domain_endpoint_opts.get("custom_endpoint")
if domain_endpoint_opts.get("custom_endpoint_certificate_arn") is not None:
- domain_endpoint_config[
- "CustomEndpointCertificateArn"
- ] = domain_endpoint_opts.get("custom_endpoint_certificate_arn")
+ domain_endpoint_config["CustomEndpointCertificateArn"] = domain_endpoint_opts.get(
+ "custom_endpoint_certificate_arn"
+ )
- if (
- current_domain_config is not None
- and current_domain_config["DomainEndpointOptions"] != domain_endpoint_config
- ):
+ if current_domain_config is not None and current_domain_config["DomainEndpointOptions"] != domain_endpoint_config:
change_set.append(
- "DomainEndpointOptions changed from {0} to {1}".format(
- current_domain_config["DomainEndpointOptions"], domain_endpoint_config
- )
+ f"DomainEndpointOptions changed from {current_domain_config['DomainEndpointOptions']} to"
+ f" {domain_endpoint_config}"
)
changed = True
return changed
-def set_auto_tune_options(
- module, current_domain_config, desired_domain_config, change_set
-):
+def set_auto_tune_options(module, current_domain_config, desired_domain_config, change_set):
changed = False
auto_tune_config = desired_domain_config["AutoTuneOptions"]
auto_tune_opts = module.params.get("auto_tune_options")
@@ -1088,31 +972,20 @@ def set_auto_tune_options(
if duration_opt.get("unit") is not None:
schedule_entry["Duration"]["Unit"] = duration_opt.get("unit")
if s.get("cron_expression_for_recurrence") is not None:
- schedule_entry["CronExpressionForRecurrence"] = s.get(
- "cron_expression_for_recurrence"
- )
+ schedule_entry["CronExpressionForRecurrence"] = s.get("cron_expression_for_recurrence")
auto_tune_config["MaintenanceSchedules"].append(schedule_entry)
if current_domain_config is not None:
- if (
- current_domain_config["AutoTuneOptions"]["DesiredState"]
- != auto_tune_config["DesiredState"]
- ):
+ if current_domain_config["AutoTuneOptions"]["DesiredState"] != auto_tune_config["DesiredState"]:
change_set.append(
- "AutoTuneOptions.DesiredState changed from {0} to {1}".format(
- current_domain_config["AutoTuneOptions"]["DesiredState"],
- auto_tune_config["DesiredState"],
- )
+ "AutoTuneOptions.DesiredState changed from"
+ f" {current_domain_config['AutoTuneOptions']['DesiredState']} to {auto_tune_config['DesiredState']}"
)
changed = True
- if (
- auto_tune_config["MaintenanceSchedules"]
- != current_domain_config["AutoTuneOptions"]["MaintenanceSchedules"]
- ):
+ if auto_tune_config["MaintenanceSchedules"] != current_domain_config["AutoTuneOptions"]["MaintenanceSchedules"]:
change_set.append(
- "AutoTuneOptions.MaintenanceSchedules changed from {0} to {1}".format(
- current_domain_config["AutoTuneOptions"]["MaintenanceSchedules"],
- auto_tune_config["MaintenanceSchedules"],
- )
+ "AutoTuneOptions.MaintenanceSchedules changed from"
+ f" {current_domain_config['AutoTuneOptions']['MaintenanceSchedules']} to"
+ f" {auto_tune_config['MaintenanceSchedules']}"
)
changed = True
return changed
@@ -1127,18 +1000,12 @@ def set_access_policy(module, current_domain_config, desired_domain_config, chan
try:
access_policy_config = json.dumps(access_policy_opt)
except Exception as e:
- module.fail_json(
- msg="Failed to convert the policy into valid JSON: %s" % str(e)
- )
+ module.fail_json(msg=f"Failed to convert the policy into valid JSON: {str(e)}")
if current_domain_config is not None:
# Updating existing domain
current_access_policy = json.loads(current_domain_config["AccessPolicies"])
if not compare_policies(current_access_policy, access_policy_opt):
- change_set.append(
- "AccessPolicy changed from {0} to {1}".format(
- current_access_policy, access_policy_opt
- )
- )
+ change_set.append(f"AccessPolicy changed from {current_access_policy} to {access_policy_opt}")
changed = True
desired_domain_config["AccessPolicies"] = access_policy_config
else:
@@ -1201,53 +1068,26 @@ def ensure_domain_present(client, module):
# Validate the engine_version
v = parse_version(module.params.get("engine_version"))
if v is None:
- module.fail_json(
- "Invalid engine_version. Must be Elasticsearch_X.Y or OpenSearch_X.Y"
- )
+ module.fail_json("Invalid engine_version. Must be Elasticsearch_X.Y or OpenSearch_X.Y")
desired_domain_config["EngineVersion"] = module.params.get("engine_version")
changed = False
change_set = [] # For check mode purpose
- changed |= set_cluster_config(
- module, current_domain_config, desired_domain_config, change_set
- )
- changed |= set_ebs_options(
- module, current_domain_config, desired_domain_config, change_set
- )
- changed |= set_encryption_at_rest_options(
- module, current_domain_config, desired_domain_config, change_set
- )
- changed |= set_node_to_node_encryption_options(
- module, current_domain_config, desired_domain_config, change_set
- )
- changed |= set_vpc_options(
- module, current_domain_config, desired_domain_config, change_set
- )
- changed |= set_snapshot_options(
- module, current_domain_config, desired_domain_config, change_set
- )
- changed |= set_cognito_options(
- module, current_domain_config, desired_domain_config, change_set
- )
- changed |= set_advanced_security_options(
- module, current_domain_config, desired_domain_config, change_set
- )
- changed |= set_domain_endpoint_options(
- module, current_domain_config, desired_domain_config, change_set
- )
- changed |= set_auto_tune_options(
- module, current_domain_config, desired_domain_config, change_set
- )
- changed |= set_access_policy(
- module, current_domain_config, desired_domain_config, change_set
- )
+ changed |= set_cluster_config(module, current_domain_config, desired_domain_config, change_set)
+ changed |= set_ebs_options(module, current_domain_config, desired_domain_config, change_set)
+ changed |= set_encryption_at_rest_options(module, current_domain_config, desired_domain_config, change_set)
+ changed |= set_node_to_node_encryption_options(module, current_domain_config, desired_domain_config, change_set)
+ changed |= set_vpc_options(module, current_domain_config, desired_domain_config, change_set)
+ changed |= set_snapshot_options(module, current_domain_config, desired_domain_config, change_set)
+ changed |= set_cognito_options(module, current_domain_config, desired_domain_config, change_set)
+ changed |= set_advanced_security_options(module, current_domain_config, desired_domain_config, change_set)
+ changed |= set_domain_endpoint_options(module, current_domain_config, desired_domain_config, change_set)
+ changed |= set_auto_tune_options(module, current_domain_config, desired_domain_config, change_set)
+ changed |= set_access_policy(module, current_domain_config, desired_domain_config, change_set)
if current_domain_config is not None:
- if (
- desired_domain_config["EngineVersion"]
- != current_domain_config["EngineVersion"]
- ):
+ if desired_domain_config["EngineVersion"] != current_domain_config["EngineVersion"]:
changed = True
change_set.append("EngineVersion changed")
upgrade_domain(
@@ -1271,22 +1111,16 @@ def ensure_domain_present(client, module):
botocore.exceptions.BotoCoreError,
botocore.exceptions.ClientError,
) as e:
- module.fail_json_aws(
- e, msg="Couldn't update domain {0}".format(domain_name)
- )
+ module.fail_json_aws(e, msg=f"Couldn't update domain {domain_name}")
else:
# Create new OpenSearch cluster
if module.params.get("access_policies") is None:
- module.fail_json(
- "state is present but the following is missing: access_policies"
- )
+ module.fail_json("state is present but the following is missing: access_policies")
changed = True
if module.check_mode:
- module.exit_json(
- changed=True, msg="Would have created a domain if not in check mode"
- )
+ module.exit_json(changed=True, msg="Would have created a domain if not in check mode")
try:
response = client.create_domain(**desired_domain_config)
domain = response["DomainStatus"]
@@ -1295,22 +1129,16 @@ def ensure_domain_present(client, module):
botocore.exceptions.BotoCoreError,
botocore.exceptions.ClientError,
) as e:
- module.fail_json_aws(
- e, msg="Couldn't update domain {0}".format(domain_name)
- )
+ module.fail_json_aws(e, msg=f"Couldn't update domain {domain_name}")
try:
- existing_tags = boto3_tag_list_to_ansible_dict(
- client.list_tags(ARN=domain_arn, aws_retry=True)["TagList"]
- )
+ existing_tags = boto3_tag_list_to_ansible_dict(client.list_tags(ARN=domain_arn, aws_retry=True)["TagList"])
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, "Couldn't get tags for domain %s" % domain_name)
+ module.fail_json_aws(e, f"Couldn't get tags for domain {domain_name}")
desired_tags = module.params["tags"]
purge_tags = module.params["purge_tags"]
- changed |= ensure_tags(
- client, module, domain_arn, existing_tags, desired_tags, purge_tags
- )
+ changed |= ensure_tags(client, module, domain_arn, existing_tags, desired_tags, purge_tags)
if module.params.get("wait") and not module.check_mode:
wait_for_domain_status(client, module, domain_name, "domain_available")
@@ -1321,7 +1149,6 @@ def ensure_domain_present(client, module):
def main():
-
module = AnsibleAWSModule(
argument_spec=dict(
state=dict(choices=["present", "absent"], default="present"),
@@ -1482,8 +1309,6 @@ def main():
supports_check_mode=True,
)
- module.require_botocore_at_least("1.21.38")
-
try:
client = module.client("opensearch", retry_decorator=AWSRetry.jittered_backoff())
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
diff --git a/ansible_collections/community/aws/plugins/modules/opensearch_info.py b/ansible_collections/community/aws/plugins/modules/opensearch_info.py
index 700ad26fd..98fce3e03 100644
--- a/ansible_collections/community/aws/plugins/modules/opensearch_info.py
+++ b/ansible_collections/community/aws/plugins/modules/opensearch_info.py
@@ -1,20 +1,18 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = """
+DOCUMENTATION = r"""
---
module: opensearch_info
short_description: obtain information about one or more OpenSearch or ElasticSearch domain
description:
- Obtain information about one Amazon OpenSearch Service domain.
version_added: 4.0.0
-author: "Sebastien Rosset (@sebastien-rosset)"
+author:
+ - "Sebastien Rosset (@sebastien-rosset)"
options:
domain_name:
description:
@@ -28,18 +26,16 @@ options:
all tag key, value pairs.
required: false
type: dict
-requirements:
- - botocore >= 1.21.38
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
"""
-EXAMPLES = '''
+EXAMPLES = r"""
- name: Get information about an OpenSearch domain instance
community.aws.opensearch_info:
- domain-name: my-search-cluster
+ domain_name: my-search-cluster
register: new_cluster_info
- name: Get all OpenSearch instances
@@ -50,9 +46,9 @@ EXAMPLES = '''
tags:
Applications: search
Environment: Development
-'''
+"""
-RETURN = '''
+RETURN = r"""
instances:
description: List of OpenSearch domain instances
returned: always
@@ -441,7 +437,7 @@ instances:
description: The name of the OpenSearch domain.
returned: always
type: str
-'''
+"""
try:
@@ -449,62 +445,63 @@ try:
except ImportError:
pass # handled by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import (
- AWSRetry,
- boto3_tag_list_to_ansible_dict,
- camel_dict_to_snake_dict,
-)
-from ansible_collections.community.aws.plugins.module_utils.opensearch import (
- get_domain_config,
- get_domain_status,
-)
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
+from ansible_collections.community.aws.plugins.module_utils.opensearch import get_domain_config
+from ansible_collections.community.aws.plugins.module_utils.opensearch import get_domain_status
def domain_info(client, module):
- domain_name = module.params.get('domain_name')
- filter_tags = module.params.get('tags')
+ domain_name = module.params.get("domain_name")
+ filter_tags = module.params.get("tags")
domain_list = []
if domain_name:
domain_status = get_domain_status(client, module, domain_name)
if domain_status:
- domain_list.append({'DomainStatus': domain_status})
+ domain_list.append({"DomainStatus": domain_status})
else:
- domain_summary_list = client.list_domain_names()['DomainNames']
+ domain_summary_list = client.list_domain_names()["DomainNames"]
for d in domain_summary_list:
- domain_status = get_domain_status(client, module, d['DomainName'])
+ domain_status = get_domain_status(client, module, d["DomainName"])
if domain_status:
- domain_list.append({'DomainStatus': domain_status})
+ domain_list.append({"DomainStatus": domain_status})
# Get the domain tags
for domain in domain_list:
current_domain_tags = None
- domain_arn = domain['DomainStatus']['ARN']
+ domain_arn = domain["DomainStatus"]["ARN"]
try:
current_domain_tags = client.list_tags(ARN=domain_arn, aws_retry=True)["TagList"]
- domain['Tags'] = boto3_tag_list_to_ansible_dict(current_domain_tags)
+ domain["Tags"] = boto3_tag_list_to_ansible_dict(current_domain_tags)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
# This could potentially happen if a domain is deleted between the time
# its domain status was queried and the tags were queried.
- domain['Tags'] = {}
+ domain["Tags"] = {}
# Filter by tags
if filter_tags:
for tag_key in filter_tags:
try:
- domain_list = [c for c in domain_list if ('Tags' in c) and (tag_key in c['Tags']) and (c['Tags'][tag_key] == filter_tags[tag_key])]
+ domain_list = [
+ c
+ for c in domain_list
+ if ("Tags" in c) and (tag_key in c["Tags"]) and (c["Tags"][tag_key] == filter_tags[tag_key])
+ ]
except (TypeError, AttributeError) as e:
module.fail_json(msg="OpenSearch tag filtering error", exception=e)
# Get the domain config
for idx, domain in enumerate(domain_list):
- domain_name = domain['DomainStatus']['DomainName']
+ domain_name = domain["DomainStatus"]["DomainName"]
(domain_config, arn) = get_domain_config(client, module, domain_name)
if domain_config:
- domain['DomainConfig'] = domain_config
- domain_list[idx] = camel_dict_to_snake_dict(domain,
- ignore_list=['AdvancedOptions', 'Endpoints', 'Tags'])
+ domain["DomainConfig"] = domain_config
+ domain_list[idx] = camel_dict_to_snake_dict(domain, ignore_list=["AdvancedOptions", "Endpoints", "Tags"])
return dict(changed=False, domains=domain_list)
@@ -513,11 +510,10 @@ def main():
module = AnsibleAWSModule(
argument_spec=dict(
domain_name=dict(required=False),
- tags=dict(type='dict', required=False),
+ tags=dict(type="dict", required=False),
),
supports_check_mode=True,
)
- module.require_botocore_at_least("1.21.38")
try:
client = module.client("opensearch", retry_decorator=AWSRetry.jittered_backoff())
@@ -527,5 +523,5 @@ def main():
module.exit_json(**domain_info(client, module))
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/redshift.py b/ansible_collections/community/aws/plugins/modules/redshift.py
index 27e959893..4463722e5 100644
--- a/ansible_collections/community/aws/plugins/modules/redshift.py
+++ b/ansible_collections/community/aws/plugins/modules/redshift.py
@@ -1,14 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
# Copyright 2014 Jens Carl, Hothead Games Inc.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
author:
- "Jens Carl (@j-carl), Hothead Games Inc."
@@ -170,13 +166,13 @@ options:
notes:
- Support for I(tags) and I(purge_tags) was added in release 1.3.0.
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
- - amazon.aws.boto3
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.tags
-'''
+ - amazon.aws.boto3
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
- name: Basic cluster provisioning example
community.aws.redshift:
command: create
@@ -191,9 +187,9 @@ EXAMPLES = r'''
identifier: new_cluster
skip_final_cluster_snapshot: true
wait: true
-'''
+"""
-RETURN = r'''
+RETURN = r"""
cluster:
description: dictionary containing all the cluster information
returned: success
@@ -257,31 +253,33 @@ cluster:
description: aws tags for cluster.
returned: success
type: dict
-'''
+"""
try:
import botocore
except ImportError:
pass # caught by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_tag_list
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import compare_aws_tags
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import snake_dict_to_camel_dict
-from ansible_collections.amazon.aws.plugins.module_utils.iam import get_aws_account_id
+from ansible.module_utils.common.dict_transformations import snake_dict_to_camel_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.iam import get_aws_account_info
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import ansible_dict_to_boto3_tag_list
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import compare_aws_tags
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def _ensure_tags(redshift, identifier, existing_tags, module):
"""Compares and update resource tags"""
- account_id = get_aws_account_id(module)
- region = module.params.get('region')
- resource_arn = "arn:aws:redshift:{0}:{1}:cluster:{2}" .format(region, account_id, identifier)
- tags = module.params.get('tags')
- purge_tags = module.params.get('purge_tags')
+ account_id, partition = get_aws_account_info(module)
+ region = module.region
+ resource_arn = f"arn:{partition}:redshift:{region}:{account_id}:cluster:{identifier}"
+ tags = module.params.get("tags")
+ purge_tags = module.params.get("purge_tags")
tags_to_add, tags_to_remove = compare_aws_tags(boto3_tag_list_to_ansible_dict(existing_tags), tags, purge_tags)
@@ -304,78 +302,77 @@ def _ensure_tags(redshift, identifier, existing_tags, module):
def _collect_facts(resource):
"""Transform cluster information to dict."""
facts = {
- 'identifier': resource['ClusterIdentifier'],
- 'status': resource['ClusterStatus'],
- 'username': resource['MasterUsername'],
- 'db_name': resource['DBName'],
- 'maintenance_window': resource['PreferredMaintenanceWindow'],
- 'enhanced_vpc_routing': resource['EnhancedVpcRouting']
-
+ "identifier": resource["ClusterIdentifier"],
+ "status": resource["ClusterStatus"],
+ "username": resource["MasterUsername"],
+ "db_name": resource["DBName"],
+ "maintenance_window": resource["PreferredMaintenanceWindow"],
+ "enhanced_vpc_routing": resource["EnhancedVpcRouting"],
}
- for node in resource['ClusterNodes']:
- if node['NodeRole'] in ('SHARED', 'LEADER'):
- facts['private_ip_address'] = node['PrivateIPAddress']
- if facts['enhanced_vpc_routing'] is False:
- facts['public_ip_address'] = node['PublicIPAddress']
+ for node in resource["ClusterNodes"]:
+ if node["NodeRole"] in ("SHARED", "LEADER"):
+ facts["private_ip_address"] = node["PrivateIPAddress"]
+ if facts["enhanced_vpc_routing"] is False:
+ facts["public_ip_address"] = node["PublicIPAddress"]
else:
- facts['public_ip_address'] = None
+ facts["public_ip_address"] = None
break
# Some parameters are not ready instantly if you don't wait for available
# cluster status
- facts['create_time'] = None
- facts['url'] = None
- facts['port'] = None
- facts['availability_zone'] = None
- facts['tags'] = {}
-
- if resource['ClusterStatus'] != "creating":
- facts['create_time'] = resource['ClusterCreateTime']
- facts['url'] = resource['Endpoint']['Address']
- facts['port'] = resource['Endpoint']['Port']
- facts['availability_zone'] = resource['AvailabilityZone']
- facts['tags'] = boto3_tag_list_to_ansible_dict(resource['Tags'])
+ facts["create_time"] = None
+ facts["url"] = None
+ facts["port"] = None
+ facts["availability_zone"] = None
+ facts["tags"] = {}
+
+ if resource["ClusterStatus"] != "creating":
+ facts["create_time"] = resource["ClusterCreateTime"]
+ facts["url"] = resource["Endpoint"]["Address"]
+ facts["port"] = resource["Endpoint"]["Port"]
+ facts["availability_zone"] = resource["AvailabilityZone"]
+ facts["tags"] = boto3_tag_list_to_ansible_dict(resource["Tags"])
return facts
@AWSRetry.jittered_backoff()
def _describe_cluster(redshift, identifier):
- '''
+ """
Basic wrapper around describe_clusters with a retry applied
- '''
- return redshift.describe_clusters(ClusterIdentifier=identifier)['Clusters'][0]
+ """
+ return redshift.describe_clusters(ClusterIdentifier=identifier)["Clusters"][0]
@AWSRetry.jittered_backoff()
def _create_cluster(redshift, **kwargs):
- '''
+ """
Basic wrapper around create_cluster with a retry applied
- '''
+ """
return redshift.create_cluster(**kwargs)
# Simple wrapper around delete, try to avoid throwing an error if some other
# operation is in progress
-@AWSRetry.jittered_backoff(catch_extra_error_codes=['InvalidClusterState'])
+@AWSRetry.jittered_backoff(catch_extra_error_codes=["InvalidClusterState"])
def _delete_cluster(redshift, **kwargs):
- '''
+ """
Basic wrapper around delete_cluster with a retry applied.
Explicitly catches 'InvalidClusterState' (~ Operation in progress) so that
we can still delete a cluster if some kind of change operation was in
progress.
- '''
+ """
return redshift.delete_cluster(**kwargs)
-@AWSRetry.jittered_backoff(catch_extra_error_codes=['InvalidClusterState'])
+@AWSRetry.jittered_backoff(catch_extra_error_codes=["InvalidClusterState"])
def _modify_cluster(redshift, **kwargs):
- '''
+ """
Basic wrapper around modify_cluster with a retry applied.
Explicitly catches 'InvalidClusterState' (~ Operation in progress) for cases
where another modification is still in progress
- '''
+ """
return redshift.modify_cluster(**kwargs)
@@ -389,59 +386,71 @@ def create_cluster(module, redshift):
Returns:
"""
- identifier = module.params.get('identifier')
- node_type = module.params.get('node_type')
- username = module.params.get('username')
- password = module.params.get('password')
- d_b_name = module.params.get('db_name')
- wait = module.params.get('wait')
- wait_timeout = module.params.get('wait_timeout')
- tags = module.params.get('tags')
+ identifier = module.params.get("identifier")
+ node_type = module.params.get("node_type")
+ username = module.params.get("username")
+ password = module.params.get("password")
+ d_b_name = module.params.get("db_name")
+ wait = module.params.get("wait")
+ wait_timeout = module.params.get("wait_timeout")
+ tags = module.params.get("tags")
changed = True
# Package up the optional parameters
params = {}
- for p in ('cluster_type', 'cluster_security_groups',
- 'vpc_security_group_ids', 'cluster_subnet_group_name',
- 'availability_zone', 'preferred_maintenance_window',
- 'cluster_parameter_group_name',
- 'automated_snapshot_retention_period', 'port',
- 'cluster_version', 'allow_version_upgrade',
- 'number_of_nodes', 'publicly_accessible', 'encrypted',
- 'elastic_ip', 'enhanced_vpc_routing'):
+ for p in (
+ "cluster_type",
+ "cluster_security_groups",
+ "vpc_security_group_ids",
+ "cluster_subnet_group_name",
+ "availability_zone",
+ "preferred_maintenance_window",
+ "cluster_parameter_group_name",
+ "automated_snapshot_retention_period",
+ "port",
+ "cluster_version",
+ "allow_version_upgrade",
+ "number_of_nodes",
+ "publicly_accessible",
+ "encrypted",
+ "elastic_ip",
+ "enhanced_vpc_routing",
+ ):
# https://github.com/boto/boto3/issues/400
if module.params.get(p) is not None:
params[p] = module.params.get(p)
if d_b_name:
- params['d_b_name'] = d_b_name
+ params["d_b_name"] = d_b_name
if tags:
tags = ansible_dict_to_boto3_tag_list(tags)
- params['tags'] = tags
+ params["tags"] = tags
try:
_describe_cluster(redshift, identifier)
changed = False
- except is_boto3_error_code('ClusterNotFound'):
+ except is_boto3_error_code("ClusterNotFound"):
try:
- _create_cluster(redshift,
- ClusterIdentifier=identifier,
- NodeType=node_type,
- MasterUsername=username,
- MasterUserPassword=password,
- **snake_dict_to_camel_dict(params, capitalize_first=True))
+ _create_cluster(
+ redshift,
+ ClusterIdentifier=identifier,
+ NodeType=node_type,
+ MasterUsername=username,
+ MasterUserPassword=password,
+ **snake_dict_to_camel_dict(params, capitalize_first=True),
+ )
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
module.fail_json_aws(e, msg="Failed to create cluster")
- except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e: # pylint: disable=duplicate-except
+ except (
+ botocore.exceptions.BotoCoreError,
+ botocore.exceptions.ClientError,
+ ) as e: # pylint: disable=duplicate-except
module.fail_json_aws(e, msg="Failed to describe cluster")
if wait:
attempts = wait_timeout // 60
- waiter = redshift.get_waiter('cluster_available')
+ waiter = redshift.get_waiter("cluster_available")
try:
- waiter.wait(
- ClusterIdentifier=identifier,
- WaiterConfig=dict(MaxAttempts=attempts)
- )
+ waiter.wait(ClusterIdentifier=identifier, WaiterConfig=dict(MaxAttempts=attempts))
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Timeout waiting for the cluster creation")
try:
@@ -450,7 +459,7 @@ def create_cluster(module, redshift):
module.fail_json_aws(e, msg="Failed to describe cluster")
if tags:
- if _ensure_tags(redshift, identifier, resource['Tags'], module):
+ if _ensure_tags(redshift, identifier, resource["Tags"], module):
changed = True
resource = _describe_cluster(redshift, identifier)
@@ -464,7 +473,7 @@ def describe_cluster(module, redshift):
module: Ansible module object
redshift: authenticated redshift connection object
"""
- identifier = module.params.get('identifier')
+ identifier = module.params.get("identifier")
try:
resource = _describe_cluster(redshift, identifier)
@@ -482,13 +491,12 @@ def delete_cluster(module, redshift):
redshift: authenticated redshift connection object
"""
- identifier = module.params.get('identifier')
- wait = module.params.get('wait')
- wait_timeout = module.params.get('wait_timeout')
+ identifier = module.params.get("identifier")
+ wait = module.params.get("wait")
+ wait_timeout = module.params.get("wait_timeout")
params = {}
- for p in ('skip_final_cluster_snapshot',
- 'final_cluster_snapshot_identifier'):
+ for p in ("skip_final_cluster_snapshot", "final_cluster_snapshot_identifier"):
if p in module.params:
# https://github.com/boto/boto3/issues/400
if module.params.get(p) is not None:
@@ -496,22 +504,21 @@ def delete_cluster(module, redshift):
try:
_delete_cluster(
- redshift,
- ClusterIdentifier=identifier,
- **snake_dict_to_camel_dict(params, capitalize_first=True))
- except is_boto3_error_code('ClusterNotFound'):
+ redshift, ClusterIdentifier=identifier, **snake_dict_to_camel_dict(params, capitalize_first=True)
+ )
+ except is_boto3_error_code("ClusterNotFound"):
return False, {}
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
module.fail_json_aws(e, msg="Failed to delete cluster")
if wait:
attempts = wait_timeout // 60
- waiter = redshift.get_waiter('cluster_deleted')
+ waiter = redshift.get_waiter("cluster_deleted")
try:
- waiter.wait(
- ClusterIdentifier=identifier,
- WaiterConfig=dict(MaxAttempts=attempts)
- )
+ waiter.wait(ClusterIdentifier=identifier, WaiterConfig=dict(MaxAttempts=attempts))
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Timeout deleting the cluster")
@@ -526,148 +533,160 @@ def modify_cluster(module, redshift):
redshift: authenticated redshift connection object
"""
- identifier = module.params.get('identifier')
- wait = module.params.get('wait')
- wait_timeout = module.params.get('wait_timeout')
+ identifier = module.params.get("identifier")
+ wait = module.params.get("wait")
+ wait_timeout = module.params.get("wait_timeout")
# Package up the optional parameters
params = {}
- for p in ('cluster_type', 'cluster_security_groups',
- 'vpc_security_group_ids', 'cluster_subnet_group_name',
- 'availability_zone', 'preferred_maintenance_window',
- 'cluster_parameter_group_name',
- 'automated_snapshot_retention_period', 'port', 'cluster_version',
- 'allow_version_upgrade', 'number_of_nodes', 'new_cluster_identifier'):
+ for p in (
+ "cluster_type",
+ "cluster_security_groups",
+ "vpc_security_group_ids",
+ "cluster_subnet_group_name",
+ "availability_zone",
+ "preferred_maintenance_window",
+ "cluster_parameter_group_name",
+ "automated_snapshot_retention_period",
+ "port",
+ "cluster_version",
+ "allow_version_upgrade",
+ "number_of_nodes",
+ "new_cluster_identifier",
+ ):
# https://github.com/boto/boto3/issues/400
if module.params.get(p) is not None:
params[p] = module.params.get(p)
# enhanced_vpc_routing parameter change needs an exclusive request
- if module.params.get('enhanced_vpc_routing') is not None:
+ if module.params.get("enhanced_vpc_routing") is not None:
try:
_modify_cluster(
- redshift,
- ClusterIdentifier=identifier,
- EnhancedVpcRouting=module.params.get('enhanced_vpc_routing'))
+ redshift, ClusterIdentifier=identifier, EnhancedVpcRouting=module.params.get("enhanced_vpc_routing")
+ )
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
- module.fail_json_aws(e, msg="Couldn't modify redshift cluster %s " % identifier)
+ module.fail_json_aws(e, msg=f"Couldn't modify redshift cluster {identifier} ")
if wait:
attempts = wait_timeout // 60
- waiter = redshift.get_waiter('cluster_available')
+ waiter = redshift.get_waiter("cluster_available")
try:
- waiter.wait(
- ClusterIdentifier=identifier,
- WaiterConfig=dict(MaxAttempts=attempts))
+ waiter.wait(ClusterIdentifier=identifier, WaiterConfig=dict(MaxAttempts=attempts))
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e,
- msg="Timeout waiting for cluster enhanced vpc routing modification")
+ module.fail_json_aws(e, msg="Timeout waiting for cluster enhanced vpc routing modification")
# change the rest
try:
_modify_cluster(
- redshift,
- ClusterIdentifier=identifier,
- **snake_dict_to_camel_dict(params, capitalize_first=True))
+ redshift, ClusterIdentifier=identifier, **snake_dict_to_camel_dict(params, capitalize_first=True)
+ )
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
- module.fail_json_aws(e, msg="Couldn't modify redshift cluster %s " % identifier)
+ module.fail_json_aws(e, msg=f"Couldn't modify redshift cluster {identifier} ")
- if module.params.get('new_cluster_identifier'):
- identifier = module.params.get('new_cluster_identifier')
+ if module.params.get("new_cluster_identifier"):
+ identifier = module.params.get("new_cluster_identifier")
if wait:
attempts = wait_timeout // 60
- waiter2 = redshift.get_waiter('cluster_available')
+ waiter2 = redshift.get_waiter("cluster_available")
try:
- waiter2.wait(
- ClusterIdentifier=identifier,
- WaiterConfig=dict(MaxAttempts=attempts)
- )
+ waiter2.wait(ClusterIdentifier=identifier, WaiterConfig=dict(MaxAttempts=attempts))
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Timeout waiting for cluster modification")
try:
resource = _describe_cluster(redshift, identifier)
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
- module.fail_json_aws(e, msg="Couldn't modify redshift cluster %s " % identifier)
+ module.fail_json_aws(e, msg=f"Couldn't modify redshift cluster {identifier} ")
- if _ensure_tags(redshift, identifier, resource['Tags'], module):
- resource = redshift.describe_clusters(ClusterIdentifier=identifier)['Clusters'][0]
+ if _ensure_tags(redshift, identifier, resource["Tags"], module):
+ resource = redshift.describe_clusters(ClusterIdentifier=identifier)["Clusters"][0]
return True, _collect_facts(resource)
def main():
argument_spec = dict(
- command=dict(choices=['create', 'facts', 'delete', 'modify'], required=True),
+ command=dict(choices=["create", "facts", "delete", "modify"], required=True),
identifier=dict(required=True),
- node_type=dict(choices=['ds1.xlarge', 'ds1.8xlarge', 'ds2.xlarge',
- 'ds2.8xlarge', 'dc1.large', 'dc2.large',
- 'dc1.8xlarge', 'dw1.xlarge', 'dw1.8xlarge',
- 'dw2.large', 'dw2.8xlarge'], required=False),
+ node_type=dict(
+ choices=[
+ "ds1.xlarge",
+ "ds1.8xlarge",
+ "ds2.xlarge",
+ "ds2.8xlarge",
+ "dc1.large",
+ "dc2.large",
+ "dc1.8xlarge",
+ "dw1.xlarge",
+ "dw1.8xlarge",
+ "dw2.large",
+ "dw2.8xlarge",
+ ],
+ required=False,
+ ),
username=dict(required=False),
password=dict(no_log=True, required=False),
db_name=dict(required=False),
- cluster_type=dict(choices=['multi-node', 'single-node'], default='single-node'),
- cluster_security_groups=dict(aliases=['security_groups'], type='list', elements='str'),
- vpc_security_group_ids=dict(aliases=['vpc_security_groups'], type='list', elements='str'),
- skip_final_cluster_snapshot=dict(aliases=['skip_final_snapshot'],
- type='bool', default=False),
- final_cluster_snapshot_identifier=dict(aliases=['final_snapshot_id'], required=False),
- cluster_subnet_group_name=dict(aliases=['subnet']),
- availability_zone=dict(aliases=['aws_zone', 'zone']),
- preferred_maintenance_window=dict(aliases=['maintance_window', 'maint_window']),
- cluster_parameter_group_name=dict(aliases=['param_group_name']),
- automated_snapshot_retention_period=dict(aliases=['retention_period'], type='int'),
- port=dict(type='int'),
- cluster_version=dict(aliases=['version'], choices=['1.0']),
- allow_version_upgrade=dict(aliases=['version_upgrade'], type='bool', default=True),
- number_of_nodes=dict(type='int'),
- publicly_accessible=dict(type='bool', default=False),
- encrypted=dict(type='bool', default=False),
+ cluster_type=dict(choices=["multi-node", "single-node"], default="single-node"),
+ cluster_security_groups=dict(aliases=["security_groups"], type="list", elements="str"),
+ vpc_security_group_ids=dict(aliases=["vpc_security_groups"], type="list", elements="str"),
+ skip_final_cluster_snapshot=dict(aliases=["skip_final_snapshot"], type="bool", default=False),
+ final_cluster_snapshot_identifier=dict(aliases=["final_snapshot_id"], required=False),
+ cluster_subnet_group_name=dict(aliases=["subnet"]),
+ availability_zone=dict(aliases=["aws_zone", "zone"]),
+ preferred_maintenance_window=dict(aliases=["maintance_window", "maint_window"]),
+ cluster_parameter_group_name=dict(aliases=["param_group_name"]),
+ automated_snapshot_retention_period=dict(aliases=["retention_period"], type="int"),
+ port=dict(type="int"),
+ cluster_version=dict(aliases=["version"], choices=["1.0"]),
+ allow_version_upgrade=dict(aliases=["version_upgrade"], type="bool", default=True),
+ number_of_nodes=dict(type="int"),
+ publicly_accessible=dict(type="bool", default=False),
+ encrypted=dict(type="bool", default=False),
elastic_ip=dict(required=False),
- new_cluster_identifier=dict(aliases=['new_identifier']),
- enhanced_vpc_routing=dict(type='bool', default=False),
- wait=dict(type='bool', default=False),
- wait_timeout=dict(type='int', default=300),
- tags=dict(type='dict', aliases=['resource_tags']),
- purge_tags=dict(type='bool', default=True)
+ new_cluster_identifier=dict(aliases=["new_identifier"]),
+ enhanced_vpc_routing=dict(type="bool", default=False),
+ wait=dict(type="bool", default=False),
+ wait_timeout=dict(type="int", default=300),
+ tags=dict(type="dict", aliases=["resource_tags"]),
+ purge_tags=dict(type="bool", default=True),
)
required_if = [
- ('command', 'delete', ['skip_final_cluster_snapshot']),
- ('command', 'create', ['node_type',
- 'username',
- 'password'])
+ ("command", "delete", ["skip_final_cluster_snapshot"]),
+ ("command", "create", ["node_type", "username", "password"]),
]
module = AnsibleAWSModule(
argument_spec=argument_spec,
- required_if=required_if
+ required_if=required_if,
)
- command = module.params.get('command')
- skip_final_cluster_snapshot = module.params.get('skip_final_cluster_snapshot')
- final_cluster_snapshot_identifier = module.params.get('final_cluster_snapshot_identifier')
+ command = module.params.get("command")
+ skip_final_cluster_snapshot = module.params.get("skip_final_cluster_snapshot")
+ final_cluster_snapshot_identifier = module.params.get("final_cluster_snapshot_identifier")
# can't use module basic required_if check for this case
- if command == 'delete' and skip_final_cluster_snapshot is False and final_cluster_snapshot_identifier is None:
- module.fail_json(msg="Need to specify final_cluster_snapshot_identifier if skip_final_cluster_snapshot is False")
+ if command == "delete" and skip_final_cluster_snapshot is False and final_cluster_snapshot_identifier is None:
+ module.fail_json(
+ msg="Need to specify final_cluster_snapshot_identifier if skip_final_cluster_snapshot is False"
+ )
- conn = module.client('redshift')
+ conn = module.client("redshift")
changed = True
- if command == 'create':
+ if command == "create":
(changed, cluster) = create_cluster(module, conn)
- elif command == 'facts':
+ elif command == "facts":
(changed, cluster) = describe_cluster(module, conn)
- elif command == 'delete':
+ elif command == "delete":
(changed, cluster) = delete_cluster(module, conn)
- elif command == 'modify':
+ elif command == "modify":
(changed, cluster) = modify_cluster(module, conn)
module.exit_json(changed=changed, cluster=cluster)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/redshift_cross_region_snapshots.py b/ansible_collections/community/aws/plugins/modules/redshift_cross_region_snapshots.py
index 1c42ea802..d2894dfcb 100644
--- a/ansible_collections/community/aws/plugins/modules/redshift_cross_region_snapshots.py
+++ b/ansible_collections/community/aws/plugins/modules/redshift_cross_region_snapshots.py
@@ -1,13 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
# Copyright: (c) 2018, JR Kerkstra <jrkerkstra@example.org>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: redshift_cross_region_snapshots
version_added: 1.0.0
@@ -15,7 +12,8 @@ short_description: Manage Redshift Cross Region Snapshots
description:
- Manage Redshift Cross Region Snapshots. Supports KMS-Encrypted Snapshots.
- For more information, see U(https://docs.aws.amazon.com/redshift/latest/mgmt/working-with-snapshots.html#cross-region-snapshot-copy)
-author: JR Kerkstra (@captainkerk)
+author:
+ - JR Kerkstra (@captainkerk)
options:
cluster_name:
description:
@@ -54,13 +52,12 @@ options:
aliases: [ "retention_period" ]
type: int
extends_documentation_fragment:
-- amazon.aws.ec2
-- amazon.aws.aws
-- amazon.aws.boto3
-
-'''
+ - amazon.aws.region.modules
+ - amazon.aws.common.modules
+ - amazon.aws.boto3
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
- name: configure cross-region snapshot on cluster `johniscool`
community.aws.redshift_cross_region_snapshots:
cluster_name: johniscool
@@ -84,24 +81,21 @@ EXAMPLES = '''
state: absent
region: us-east-1
destination_region: us-west-2
-'''
+"""
-RETURN = ''' # '''
+RETURN = r""" # """
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
class SnapshotController(object):
-
def __init__(self, client, cluster_name):
self.client = client
self.cluster_name = cluster_name
def get_cluster_snapshot_copy_status(self):
- response = self.client.describe_clusters(
- ClusterIdentifier=self.cluster_name
- )
- return response['Clusters'][0].get('ClusterSnapshotCopyStatus')
+ response = self.client.describe_clusters(ClusterIdentifier=self.cluster_name)
+ return response["Clusters"][0].get("ClusterSnapshotCopyStatus")
def enable_snapshot_copy(self, destination_region, grant_name, retention_period):
if grant_name:
@@ -119,78 +113,79 @@ class SnapshotController(object):
)
def disable_snapshot_copy(self):
- self.client.disable_snapshot_copy(
- ClusterIdentifier=self.cluster_name
- )
+ self.client.disable_snapshot_copy(ClusterIdentifier=self.cluster_name)
def modify_snapshot_copy_retention_period(self, retention_period):
self.client.modify_snapshot_copy_retention_period(
- ClusterIdentifier=self.cluster_name,
- RetentionPeriod=retention_period
+ ClusterIdentifier=self.cluster_name, RetentionPeriod=retention_period
)
def requesting_unsupported_modifications(actual, requested):
- if (actual['SnapshotCopyGrantName'] != requested['snapshot_copy_grant'] or
- actual['DestinationRegion'] != requested['destination_region']):
+ if (
+ actual["SnapshotCopyGrantName"] != requested["snapshot_copy_grant"]
+ or actual["DestinationRegion"] != requested["destination_region"]
+ ):
return True
return False
def needs_update(actual, requested):
- if actual['RetentionPeriod'] != requested['snapshot_retention_period']:
+ if actual["RetentionPeriod"] != requested["snapshot_retention_period"]:
return True
return False
def run_module():
argument_spec = dict(
- cluster_name=dict(type='str', required=True, aliases=['cluster']),
- state=dict(type='str', choices=['present', 'absent'], default='present'),
- region=dict(type='str', required=True, aliases=['source']),
- destination_region=dict(type='str', required=True, aliases=['destination']),
- snapshot_copy_grant=dict(type='str', aliases=['copy_grant']),
- snapshot_retention_period=dict(type='int', required=True, aliases=['retention_period']),
+ cluster_name=dict(type="str", required=True, aliases=["cluster"]),
+ state=dict(type="str", choices=["present", "absent"], default="present"),
+ region=dict(type="str", required=True, aliases=["source"]),
+ destination_region=dict(type="str", required=True, aliases=["destination"]),
+ snapshot_copy_grant=dict(type="str", aliases=["copy_grant"]),
+ snapshot_retention_period=dict(type="int", required=True, aliases=["retention_period"]),
)
module = AnsibleAWSModule(
argument_spec=argument_spec,
- supports_check_mode=True
+ supports_check_mode=True,
)
result = dict(
changed=False,
- message=''
+ message="",
)
- connection = module.client('redshift')
+ connection = module.client("redshift")
- snapshot_controller = SnapshotController(client=connection,
- cluster_name=module.params.get('cluster_name'))
+ snapshot_controller = SnapshotController(client=connection, cluster_name=module.params.get("cluster_name"))
current_config = snapshot_controller.get_cluster_snapshot_copy_status()
if current_config is not None:
- if module.params.get('state') == 'present':
+ if module.params.get("state") == "present":
if requesting_unsupported_modifications(current_config, module.params):
- message = 'Cannot modify destination_region or grant_name. ' \
- 'Please disable cross-region snapshots, and re-run.'
+ message = (
+ "Cannot modify destination_region or grant_name. Please disable cross-region snapshots, and re-run."
+ )
module.fail_json(msg=message, **result)
if needs_update(current_config, module.params):
- result['changed'] = True
+ result["changed"] = True
if not module.check_mode:
snapshot_controller.modify_snapshot_copy_retention_period(
- module.params.get('snapshot_retention_period')
+ module.params.get("snapshot_retention_period")
)
else:
- result['changed'] = True
+ result["changed"] = True
if not module.check_mode:
snapshot_controller.disable_snapshot_copy()
else:
- if module.params.get('state') == 'present':
- result['changed'] = True
+ if module.params.get("state") == "present":
+ result["changed"] = True
if not module.check_mode:
- snapshot_controller.enable_snapshot_copy(module.params.get('destination_region'),
- module.params.get('snapshot_copy_grant'),
- module.params.get('snapshot_retention_period'))
+ snapshot_controller.enable_snapshot_copy(
+ module.params.get("destination_region"),
+ module.params.get("snapshot_copy_grant"),
+ module.params.get("snapshot_retention_period"),
+ )
module.exit_json(**result)
@@ -198,5 +193,5 @@ def main():
run_module()
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/redshift_info.py b/ansible_collections/community/aws/plugins/modules/redshift_info.py
index ff4da774e..2a346167e 100644
--- a/ansible_collections/community/aws/plugins/modules/redshift_info.py
+++ b/ansible_collections/community/aws/plugins/modules/redshift_info.py
@@ -1,17 +1,15 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: redshift_info
version_added: 1.0.0
-author: "Jens Carl (@j-carl)"
+author:
+ - "Jens Carl (@j-carl)"
short_description: Gather information about Redshift cluster(s)
description:
- Gather information about Redshift cluster(s).
@@ -30,13 +28,12 @@ options:
required: false
type: dict
extends_documentation_fragment:
-- amazon.aws.ec2
-- amazon.aws.aws
-- amazon.aws.boto3
-
-'''
+ - amazon.aws.region.modules
+ - amazon.aws.common.modules
+ - amazon.aws.boto3
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
# Note: These examples do net set authentication details, see the AWS guide for details.
- name: Find all clusters
@@ -65,9 +62,9 @@ EXAMPLES = '''
stack: db
register: redshift_user
failed_when: "{{ redshift_user.results | length == 0 }}"
-'''
+"""
-RETURN = '''
+RETURN = r"""
# For more information see U(http://boto3.readthedocs.io/en/latest/reference/services/redshift.html#Redshift.Client.describe_clusters)
---
cluster_identifier:
@@ -273,46 +270,46 @@ iam_roles:
returned: success
type: list
sample: []
-'''
+"""
import re
try:
- from botocore.exceptions import BotoCoreError, ClientError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
except ImportError:
pass # caught by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def match_tags(tags_to_match, cluster):
for key, value in tags_to_match.items():
- for tag in cluster['Tags']:
- if key == tag['Key'] and value == tag['Value']:
+ for tag in cluster["Tags"]:
+ if key == tag["Key"] and value == tag["Value"]:
return True
return False
def find_clusters(conn, module, identifier=None, tags=None):
-
try:
- cluster_paginator = conn.get_paginator('describe_clusters')
+ cluster_paginator = conn.get_paginator("describe_clusters")
clusters = cluster_paginator.paginate().build_full_result()
except (BotoCoreError, ClientError) as e:
- module.fail_json_aws(e, msg='Failed to fetch clusters.')
+ module.fail_json_aws(e, msg="Failed to fetch clusters.")
matched_clusters = []
if identifier is not None:
- identifier_prog = re.compile('^' + identifier)
-
- for cluster in clusters['Clusters']:
+ identifier_prog = re.compile("^" + identifier)
+ for cluster in clusters["Clusters"]:
matched_identifier = True
if identifier:
- matched_identifier = identifier_prog.search(cluster['ClusterIdentifier'])
+ matched_identifier = identifier_prog.search(cluster["ClusterIdentifier"])
matched_tags = True
if tags:
@@ -325,24 +322,23 @@ def find_clusters(conn, module, identifier=None, tags=None):
def main():
-
argument_spec = dict(
- cluster_identifier=dict(type='str', aliases=['identifier', 'name']),
- tags=dict(type='dict')
+ cluster_identifier=dict(type="str", aliases=["identifier", "name"]),
+ tags=dict(type="dict"),
)
module = AnsibleAWSModule(
argument_spec=argument_spec,
- supports_check_mode=True
+ supports_check_mode=True,
)
- cluster_identifier = module.params.get('cluster_identifier')
- cluster_tags = module.params.get('tags')
+ cluster_identifier = module.params.get("cluster_identifier")
+ cluster_tags = module.params.get("tags")
- redshift = module.client('redshift')
+ redshift = module.client("redshift")
results = find_clusters(redshift, module, identifier=cluster_identifier, tags=cluster_tags)
module.exit_json(results=results)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/redshift_subnet_group.py b/ansible_collections/community/aws/plugins/modules/redshift_subnet_group.py
index 3c7ca31f5..2ae3a2405 100644
--- a/ansible_collections/community/aws/plugins/modules/redshift_subnet_group.py
+++ b/ansible_collections/community/aws/plugins/modules/redshift_subnet_group.py
@@ -1,13 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
# Copyright 2014 Jens Carl, Hothead Games Inc.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: redshift_subnet_group
version_added: 1.0.0
@@ -40,30 +37,30 @@ options:
type: list
elements: str
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
author:
- "Jens Carl (@j-carl), Hothead Games Inc."
-'''
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
- name: Create a Redshift subnet group
community.aws.redshift_subnet_group:
state: present
group_name: redshift-subnet
group_description: Redshift subnet
group_subnets:
- - 'subnet-aaaaa'
- - 'subnet-bbbbb'
+ - 'subnet-aaaaa'
+ - 'subnet-bbbbb'
- name: Remove subnet group
community.aws.redshift_subnet_group:
state: absent
group_name: redshift-subnet
-'''
+"""
-RETURN = r'''
+RETURN = r"""
cluster_subnet_group:
description: A dictionary containing information about the Redshift subnet group.
returned: success
@@ -92,7 +89,7 @@ cluster_subnet_group:
sample:
- subnet-aaaaaaaa
- subnet-bbbbbbbb
-'''
+"""
try:
import botocore
@@ -101,10 +98,11 @@ except ImportError:
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def get_subnet_group(name):
@@ -112,10 +110,13 @@ def get_subnet_group(name):
groups = client.describe_cluster_subnet_groups(
aws_retry=True,
ClusterSubnetGroupName=name,
- )['ClusterSubnetGroups']
- except is_boto3_error_code('ClusterSubnetGroupNotFoundFault'):
+ )["ClusterSubnetGroups"]
+ except is_boto3_error_code("ClusterSubnetGroupNotFoundFault"):
return None
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
module.fail_json_aws(e, msg="Failed to describe subnet group")
if not groups:
@@ -129,23 +130,22 @@ def get_subnet_group(name):
# No support for managing tags yet, but make sure that we don't need to
# change the return value structure after it's been available in a release.
- tags = boto3_tag_list_to_ansible_dict(groups[0]['Tags'])
+ tags = boto3_tag_list_to_ansible_dict(groups[0]["Tags"])
subnet_group = camel_dict_to_snake_dict(groups[0])
- subnet_group['tags'] = tags
- subnet_group['name'] = subnet_group['cluster_subnet_group_name']
+ subnet_group["tags"] = tags
+ subnet_group["name"] = subnet_group["cluster_subnet_group_name"]
- subnet_ids = list(s['subnet_identifier'] for s in subnet_group['subnets'])
- subnet_group['subnet_ids'] = subnet_ids
+ subnet_ids = list(s["subnet_identifier"] for s in subnet_group["subnets"])
+ subnet_group["subnet_ids"] = subnet_ids
return subnet_group
def create_subnet_group(name, description, subnets):
-
if not subnets:
- module.fail_json(msg='At least one subnet must be provided when creating a subnet group')
+ module.fail_json(msg="At least one subnet must be provided when creating a subnet group")
if module.check_mode:
return True
@@ -166,13 +166,13 @@ def create_subnet_group(name, description, subnets):
def update_subnet_group(subnet_group, name, description, subnets):
update_params = dict()
- if description and subnet_group['description'] != description:
- update_params['Description'] = description
+ if description and subnet_group["description"] != description:
+ update_params["Description"] = description
if subnets:
- old_subnets = set(subnet_group['subnet_ids'])
+ old_subnets = set(subnet_group["subnet_ids"])
new_subnets = set(subnets)
if old_subnets != new_subnets:
- update_params['SubnetIds'] = list(subnets)
+ update_params["SubnetIds"] = list(subnets)
if not update_params:
return False
@@ -181,8 +181,8 @@ def update_subnet_group(subnet_group, name, description, subnets):
return True
# Description is optional, SubnetIds is not
- if 'SubnetIds' not in update_params:
- update_params['SubnetIds'] = subnet_group['subnet_ids']
+ if "SubnetIds" not in update_params:
+ update_params["SubnetIds"] = subnet_group["subnet_ids"]
try:
client.modify_cluster_subnet_group(
@@ -197,7 +197,6 @@ def update_subnet_group(subnet_group, name, description, subnets):
def delete_subnet_group(name):
-
if module.check_mode:
return True
@@ -207,20 +206,23 @@ def delete_subnet_group(name):
ClusterSubnetGroupName=name,
)
return True
- except is_boto3_error_code('ClusterSubnetGroupNotFoundFault'):
+ except is_boto3_error_code("ClusterSubnetGroupNotFoundFault"):
# AWS is "eventually consistent", cope with the race conditions where
# deletion hadn't completed when we ran describe
return False
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
module.fail_json_aws(e, msg="Failed to delete subnet group")
def main():
argument_spec = dict(
- state=dict(default='present', choices=['present', 'absent']),
- name=dict(required=True, aliases=['group_name']),
- description=dict(required=False, aliases=['group_description']),
- subnets=dict(required=False, aliases=['group_subnets'], type='list', elements='str'),
+ state=dict(default="present", choices=["present", "absent"]),
+ name=dict(required=True, aliases=["group_name"]),
+ description=dict(required=False, aliases=["group_description"]),
+ subnets=dict(required=False, aliases=["group_subnets"], type="list", elements="str"),
)
global module
@@ -231,17 +233,17 @@ def main():
supports_check_mode=True,
)
- state = module.params.get('state')
- name = module.params.get('name')
- description = module.params.get('description')
- subnets = module.params.get('subnets')
+ state = module.params.get("state")
+ name = module.params.get("name")
+ description = module.params.get("description")
+ subnets = module.params.get("subnets")
- client = module.client('redshift', retry_decorator=AWSRetry.jittered_backoff())
+ client = module.client("redshift", retry_decorator=AWSRetry.jittered_backoff())
subnet_group = get_subnet_group(name)
changed = False
- if state == 'present':
+ if state == "present":
if not subnet_group:
result = create_subnet_group(name, description, subnets)
changed |= result
@@ -257,9 +259,9 @@ def main():
compat_results = dict()
if subnet_group:
- compat_results['group'] = dict(
- name=subnet_group['name'],
- vpc_id=subnet_group['vpc_id'],
+ compat_results["group"] = dict(
+ name=subnet_group["name"],
+ vpc_id=subnet_group["vpc_id"],
)
module.exit_json(
@@ -269,5 +271,5 @@ def main():
)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/route53_wait.py b/ansible_collections/community/aws/plugins/modules/route53_wait.py
new file mode 100644
index 000000000..6b72681d4
--- /dev/null
+++ b/ansible_collections/community/aws/plugins/modules/route53_wait.py
@@ -0,0 +1,185 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r"""
+---
+module: route53_wait
+version_added: 6.3.0
+short_description: wait for changes in Amazons Route 53 DNS service to propagate
+description:
+ - When using M(amazon.aws.route53) with I(wait=false), this module allows to wait for the
+ module's propagation to finish at a later point of time.
+options:
+ result:
+ aliases:
+ - results
+ description:
+ - The registered result of one or multiple M(amazon.aws.route53) invocations.
+ required: true
+ type: dict
+ wait_timeout:
+ description:
+ - How long to wait for the changes to be replicated, in seconds.
+ - This timeout will be used for every changed result in I(result).
+ default: 300
+ type: int
+ region:
+ description:
+ - This setting is ignored by the module. It is only present to make it possible to
+ have I(region) present in the module default group.
+ type: str
+author:
+ - Felix Fontein (@felixfontein)
+extends_documentation_fragment:
+ - amazon.aws.common.modules
+ - amazon.aws.boto3
+"""
+
+RETURN = r"""
+#
+"""
+
+EXAMPLES = r"""
+# Example when using a single route53 invocation:
+
+- name: Add new.foo.com as an A record with 3 IPs
+ amazon.aws.route53:
+ state: present
+ zone: foo.com
+ record: new.foo.com
+ type: A
+ ttl: 7200
+ value:
+ - 1.1.1.1
+ - 2.2.2.2
+ - 3.3.3.3
+ register: module_result
+
+# do something else
+
+- name: Wait for the changes of the above route53 invocation to propagate
+ community.aws.route53_wait:
+ result: "{{ module_result }}"
+
+#########################################################################
+# Example when using a loop over amazon.aws.route53:
+
+- name: Add various A records
+ amazon.aws.route53:
+ state: present
+ zone: foo.com
+ record: "{{ item.record }}"
+ type: A
+ ttl: 300
+ value: "{{ item.value }}"
+ loop:
+ - record: new.foo.com
+ value: 1.1.1.1
+ - record: foo.foo.com
+ value: 2.2.2.2
+ - record: bar.foo.com
+ value:
+ - 3.3.3.3
+ - 4.4.4.4
+ register: module_results
+
+# do something else
+
+- name: Wait for the changes of the above three route53 invocations to propagate
+ community.aws.route53_wait:
+ results: "{{ module_results }}"
+"""
+
+try:
+ import botocore
+except ImportError:
+ pass # Handled by AnsibleAWSModule
+
+from ansible.module_utils._text import to_native
+
+from ansible_collections.amazon.aws.plugins.module_utils.waiters import get_waiter
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
+
+WAIT_RETRY = 5 # how many seconds to wait between propagation status polls
+
+
+def detect_task_results(results):
+ if "results" in results:
+ # This must be the registered result of a loop of route53 tasks
+ for key in ("changed", "msg", "skipped"):
+ if key not in results:
+ raise ValueError(f"missing {key} key")
+ if not isinstance(results["results"], list):
+ raise ValueError("results is present, but not a list")
+ for index, result in enumerate(results["results"]):
+ if not isinstance(result, dict):
+ raise ValueError(f"result {index + 1} is not a dictionary")
+ for key in ("changed", "failed", "ansible_loop_var", "invocation"):
+ if key not in result:
+ raise ValueError(f"missing {key} key for result {index + 1}")
+ yield f" for result #{index + 1}", result
+ return
+ # This must be a single route53 task
+ for key in ("changed", "failed"):
+ if key not in results:
+ raise ValueError(f"missing {key} key")
+ yield "", results
+
+
+def main():
+ argument_spec = dict(
+ result=dict(type="dict", required=True, aliases=["results"]),
+ wait_timeout=dict(type="int", default=300),
+ region=dict(type="str"), # ignored
+ )
+
+ module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
+
+ result_in = module.params["result"]
+ wait_timeout_in = module.params.get("wait_timeout")
+
+ changed_results = []
+ try:
+ for id, result in detect_task_results(result_in):
+ if result.get("wait_id"):
+ changed_results.append((id, result["wait_id"]))
+ except ValueError as exc:
+ module.fail_json(
+ msg=f"The value passed as result does not seem to be a registered route53 result: {to_native(exc)}"
+ )
+
+ # connect to the route53 endpoint
+ try:
+ route53 = module.client("route53")
+ except botocore.exceptions.HTTPClientError as e:
+ module.fail_json_aws(e, msg="Failed to connect to AWS")
+
+ for what, wait_id in changed_results:
+ try:
+ waiter = get_waiter(route53, "resource_record_sets_changed")
+ waiter.wait(
+ Id=wait_id,
+ WaiterConfig=dict(
+ Delay=WAIT_RETRY,
+ MaxAttempts=wait_timeout_in // WAIT_RETRY,
+ ),
+ )
+ except botocore.exceptions.WaiterError as e:
+ module.fail_json_aws(e, msg=f"Timeout waiting for resource records changes{what} to be applied")
+ except (
+ botocore.exceptions.BotoCoreError,
+ botocore.exceptions.ClientError,
+ ) as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(e, msg="Failed to update records")
+ except Exception as e:
+ module.fail_json(msg=f"Unhandled exception. ({to_native(e)})")
+
+ module.exit_json(changed=False)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/aws/plugins/modules/s3_bucket_info.py b/ansible_collections/community/aws/plugins/modules/s3_bucket_info.py
deleted file mode 100644
index 541a02b0f..000000000
--- a/ansible_collections/community/aws/plugins/modules/s3_bucket_info.py
+++ /dev/null
@@ -1,620 +0,0 @@
-#!/usr/bin/python
-"""
-Copyright (c) 2017 Ansible Project
-GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
----
-module: s3_bucket_info
-version_added: 1.0.0
-author:
- - "Gerben Geijteman (@hyperized)"
-short_description: Lists S3 buckets in AWS
-description:
- - Lists S3 buckets and details about those buckets.
- - Prior to release 5.0.0 this module was called C(community.aws.aws_s3_bucket_info).
- The usage did not change.
-options:
- name:
- description:
- - Name of bucket to query.
- type: str
- default: ""
- version_added: 1.4.0
- name_filter:
- description:
- - Limits buckets to only buckets who's name contain the string in I(name_filter).
- type: str
- default: ""
- version_added: 1.4.0
- bucket_facts:
- description:
- - Retrieve requested S3 bucket detailed information.
- - Each bucket_X option executes one API call, hence many options being set to C(true) will cause slower module execution.
- - You can limit buckets by using the I(name) or I(name_filter) option.
- suboptions:
- bucket_accelerate_configuration:
- description: Retrive S3 accelerate configuration.
- type: bool
- default: False
- bucket_location:
- description: Retrive S3 bucket location.
- type: bool
- default: False
- bucket_replication:
- description: Retrive S3 bucket replication.
- type: bool
- default: False
- bucket_acl:
- description: Retrive S3 bucket ACLs.
- type: bool
- default: False
- bucket_logging:
- description: Retrive S3 bucket logging.
- type: bool
- default: False
- bucket_request_payment:
- description: Retrive S3 bucket request payment.
- type: bool
- default: False
- bucket_tagging:
- description: Retrive S3 bucket tagging.
- type: bool
- default: False
- bucket_cors:
- description: Retrive S3 bucket CORS configuration.
- type: bool
- default: False
- bucket_notification_configuration:
- description: Retrive S3 bucket notification configuration.
- type: bool
- default: False
- bucket_encryption:
- description: Retrive S3 bucket encryption.
- type: bool
- default: False
- bucket_ownership_controls:
- description:
- - Retrive S3 ownership controls.
- type: bool
- default: False
- bucket_website:
- description: Retrive S3 bucket website.
- type: bool
- default: False
- bucket_policy:
- description: Retrive S3 bucket policy.
- type: bool
- default: False
- bucket_policy_status:
- description: Retrive S3 bucket policy status.
- type: bool
- default: False
- bucket_lifecycle_configuration:
- description: Retrive S3 bucket lifecycle configuration.
- type: bool
- default: False
- public_access_block:
- description: Retrive S3 bucket public access block.
- type: bool
- default: False
- type: dict
- version_added: 1.4.0
- transform_location:
- description:
- - S3 bucket location for default us-east-1 is normally reported as C(null).
- - Setting this option to C(true) will return C(us-east-1) instead.
- - Affects only queries with I(bucket_facts=true) and I(bucket_location=true).
- type: bool
- default: False
- version_added: 1.4.0
-extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
- - amazon.aws.boto3
-'''
-
-EXAMPLES = '''
-# Note: These examples do not set authentication details, see the AWS Guide for details.
-
-# Note: Only AWS S3 is currently supported
-
-# Lists all S3 buckets
-- community.aws.s3_bucket_info:
- register: result
-
-# Retrieve detailed bucket information
-- community.aws.s3_bucket_info:
- # Show only buckets with name matching
- name_filter: your.testing
- # Choose facts to retrieve
- bucket_facts:
- # bucket_accelerate_configuration: true
- bucket_acl: true
- bucket_cors: true
- bucket_encryption: true
- # bucket_lifecycle_configuration: true
- bucket_location: true
- # bucket_logging: true
- # bucket_notification_configuration: true
- # bucket_ownership_controls: true
- # bucket_policy: true
- # bucket_policy_status: true
- # bucket_replication: true
- # bucket_request_payment: true
- # bucket_tagging: true
- # bucket_website: true
- # public_access_block: true
- transform_location: true
- register: result
-
-# Print out result
-- name: List buckets
- ansible.builtin.debug:
- msg: "{{ result['buckets'] }}"
-'''
-
-RETURN = '''
-bucket_list:
- description: "List of buckets"
- returned: always
- type: complex
- contains:
- name:
- description: Bucket name.
- returned: always
- type: str
- sample: a-testing-bucket-name
- creation_date:
- description: Bucket creation date timestamp.
- returned: always
- type: str
- sample: "2021-01-21T12:44:10+00:00"
- public_access_block:
- description: Bucket public access block configuration.
- returned: when I(bucket_facts=true) and I(public_access_block=true)
- type: complex
- contains:
- PublicAccessBlockConfiguration:
- description: PublicAccessBlockConfiguration data.
- returned: when PublicAccessBlockConfiguration is defined for the bucket
- type: complex
- contains:
- BlockPublicAcls:
- description: BlockPublicAcls setting value.
- type: bool
- sample: true
- BlockPublicPolicy:
- description: BlockPublicPolicy setting value.
- type: bool
- sample: true
- IgnorePublicAcls:
- description: IgnorePublicAcls setting value.
- type: bool
- sample: true
- RestrictPublicBuckets:
- description: RestrictPublicBuckets setting value.
- type: bool
- sample: true
- bucket_name_filter:
- description: String used to limit buckets. See I(name_filter).
- returned: when I(name_filter) is defined
- type: str
- sample: filter-by-this-string
- bucket_acl:
- description: Bucket ACL configuration.
- returned: when I(bucket_facts=true) and I(bucket_acl=true)
- type: complex
- contains:
- Grants:
- description: List of ACL grants.
- type: list
- sample: []
- Owner:
- description: Bucket owner information.
- type: complex
- contains:
- DisplayName:
- description: Bucket owner user display name.
- returned: always
- type: str
- sample: username
- ID:
- description: Bucket owner user ID.
- returned: always
- type: str
- sample: 123894e509349etc
- bucket_cors:
- description: Bucket CORS configuration.
- returned: when I(bucket_facts=true) and I(bucket_cors=true)
- type: complex
- contains:
- CORSRules:
- description: Bucket CORS configuration.
- returned: when CORS rules are defined for the bucket
- type: list
- sample: []
- bucket_encryption:
- description: Bucket encryption configuration.
- returned: when I(bucket_facts=true) and I(bucket_encryption=true)
- type: complex
- contains:
- ServerSideEncryptionConfiguration:
- description: ServerSideEncryptionConfiguration configuration.
- returned: when encryption is enabled on the bucket
- type: complex
- contains:
- Rules:
- description: List of applied encryptio rules.
- returned: when encryption is enabled on the bucket
- type: list
- sample: { "ApplyServerSideEncryptionByDefault": { "SSEAlgorithm": "AES256" }, "BucketKeyEnabled": False }
- bucket_lifecycle_configuration:
- description: Bucket lifecycle configuration settings.
- returned: when I(bucket_facts=true) and I(bucket_lifecycle_configuration=true)
- type: complex
- contains:
- Rules:
- description: List of lifecycle management rules.
- returned: when lifecycle configuration is present
- type: list
- sample: [{ "Status": "Enabled", "ID": "example-rule" }]
- bucket_location:
- description: Bucket location.
- returned: when I(bucket_facts=true) and I(bucket_location=true)
- type: complex
- contains:
- LocationConstraint:
- description: AWS region.
- returned: always
- type: str
- sample: us-east-2
- bucket_logging:
- description: Server access logging configuration.
- returned: when I(bucket_facts=true) and I(bucket_logging=true)
- type: complex
- contains:
- LoggingEnabled:
- description: Server access logging configuration.
- returned: when server access logging is defined for the bucket
- type: complex
- contains:
- TargetBucket:
- description: Target bucket name.
- returned: always
- type: str
- sample: logging-bucket-name
- TargetPrefix:
- description: Prefix in target bucket.
- returned: always
- type: str
- sample: ""
- bucket_notification_configuration:
- description: Bucket notification settings.
- returned: when I(bucket_facts=true) and I(bucket_notification_configuration=true)
- type: complex
- contains:
- TopicConfigurations:
- description: List of notification events configurations.
- returned: when at least one notification is configured
- type: list
- sample: []
- bucket_ownership_controls:
- description: Preffered object ownership settings.
- returned: when I(bucket_facts=true) and I(bucket_ownership_controls=true)
- type: complex
- contains:
- OwnershipControls:
- description: Object ownership settings.
- returned: when ownership controls are defined for the bucket
- type: complex
- contains:
- Rules:
- description: List of ownership rules.
- returned: when ownership rule is defined
- type: list
- sample: [{ "ObjectOwnership:": "ObjectWriter" }]
- bucket_policy:
- description: Bucket policy contents.
- returned: when I(bucket_facts=true) and I(bucket_policy=true)
- type: str
- sample: '{"Version":"2012-10-17","Statement":[{"Sid":"AddCannedAcl","Effect":"Allow",..}}]}'
- bucket_policy_status:
- description: Status of bucket policy.
- returned: when I(bucket_facts=true) and I(bucket_policy_status=true)
- type: complex
- contains:
- PolicyStatus:
- description: Status of bucket policy.
- returned: when bucket policy is present
- type: complex
- contains:
- IsPublic:
- description: Report bucket policy public status.
- returned: when bucket policy is present
- type: bool
- sample: True
- bucket_replication:
- description: Replication configuration settings.
- returned: when I(bucket_facts=true) and I(bucket_replication=true)
- type: complex
- contains:
- Role:
- description: IAM role used for replication.
- returned: when replication rule is defined
- type: str
- sample: "arn:aws:iam::123:role/example-role"
- Rules:
- description: List of replication rules.
- returned: when replication rule is defined
- type: list
- sample: [{ "ID": "rule-1", "Filter": "{}" }]
- bucket_request_payment:
- description: Requester pays setting.
- returned: when I(bucket_facts=true) and I(bucket_request_payment=true)
- type: complex
- contains:
- Payer:
- description: Current payer.
- returned: always
- type: str
- sample: BucketOwner
- bucket_tagging:
- description: Bucket tags.
- returned: when I(bucket_facts=true) and I(bucket_tagging=true)
- type: dict
- sample: { "Tag1": "Value1", "Tag2": "Value2" }
- bucket_website:
- description: Static website hosting.
- returned: when I(bucket_facts=true) and I(bucket_website=true)
- type: complex
- contains:
- ErrorDocument:
- description: Object serving as HTTP error page.
- returned: when static website hosting is enabled
- type: dict
- sample: { "Key": "error.html" }
- IndexDocument:
- description: Object serving as HTTP index page.
- returned: when static website hosting is enabled
- type: dict
- sample: { "Suffix": "error.html" }
- RedirectAllRequestsTo:
- description: Website redict settings.
- returned: when redirect requests is configured
- type: complex
- contains:
- HostName:
- description: Hostname to redirect.
- returned: always
- type: str
- sample: www.example.com
- Protocol:
- description: Protocol used for redirect.
- returned: always
- type: str
- sample: https
-'''
-
-try:
- import botocore
-except ImportError:
- pass # Handled by AnsibleAWSModule
-
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict
-
-
-def get_bucket_list(module, connection, name="", name_filter=""):
- """
- Return result of list_buckets json encoded
- Filter only buckets matching 'name' or name_filter if defined
- :param module:
- :param connection:
- :return:
- """
- buckets = []
- filtered_buckets = []
- final_buckets = []
-
- # Get all buckets
- try:
- buckets = camel_dict_to_snake_dict(connection.list_buckets())['buckets']
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as err_code:
- module.fail_json_aws(err_code, msg="Failed to list buckets")
-
- # Filter buckets if requested
- if name_filter:
- for bucket in buckets:
- if name_filter in bucket['name']:
- filtered_buckets.append(bucket)
- elif name:
- for bucket in buckets:
- if name == bucket['name']:
- filtered_buckets.append(bucket)
-
- # Return proper list (filtered or all)
- if name or name_filter:
- final_buckets = filtered_buckets
- else:
- final_buckets = buckets
- return final_buckets
-
-
-def get_buckets_facts(connection, buckets, requested_facts, transform_location):
- """
- Retrive additional information about S3 buckets
- """
- full_bucket_list = []
- # Iterate over all buckets and append retrived facts to bucket
- for bucket in buckets:
- bucket.update(get_bucket_details(connection, bucket['name'], requested_facts, transform_location))
- full_bucket_list.append(bucket)
-
- return full_bucket_list
-
-
-def get_bucket_details(connection, name, requested_facts, transform_location):
- """
- Execute all enabled S3API get calls for selected bucket
- """
- all_facts = {}
-
- for key in requested_facts:
- if requested_facts[key]:
- if key == 'bucket_location':
- all_facts[key] = {}
- try:
- all_facts[key] = get_bucket_location(name, connection, transform_location)
- # we just pass on error - error means that resources is undefined
- except botocore.exceptions.ClientError:
- pass
- elif key == 'bucket_tagging':
- all_facts[key] = {}
- try:
- all_facts[key] = get_bucket_tagging(name, connection)
- # we just pass on error - error means that resources is undefined
- except botocore.exceptions.ClientError:
- pass
- else:
- all_facts[key] = {}
- try:
- all_facts[key] = get_bucket_property(name, connection, key)
- # we just pass on error - error means that resources is undefined
- except botocore.exceptions.ClientError:
- pass
-
- return all_facts
-
-
-@AWSRetry.jittered_backoff(max_delay=120, catch_extra_error_codes=['NoSuchBucket', 'OperationAborted'])
-def get_bucket_location(name, connection, transform_location=False):
- """
- Get bucket location and optionally transform 'null' to 'us-east-1'
- """
- data = connection.get_bucket_location(Bucket=name)
-
- # Replace 'null' with 'us-east-1'?
- if transform_location:
- try:
- if not data['LocationConstraint']:
- data['LocationConstraint'] = 'us-east-1'
- except KeyError:
- pass
- # Strip response metadata (not needed)
- data.pop('ResponseMetadata', None)
- return data
-
-
-@AWSRetry.jittered_backoff(max_delay=120, catch_extra_error_codes=['NoSuchBucket', 'OperationAborted'])
-def get_bucket_tagging(name, connection):
- """
- Get bucket tags and transform them using `boto3_tag_list_to_ansible_dict` function
- """
- data = connection.get_bucket_tagging(Bucket=name)
-
- try:
- bucket_tags = boto3_tag_list_to_ansible_dict(data['TagSet'])
- return bucket_tags
- except KeyError:
- # Strip response metadata (not needed)
- data.pop('ResponseMetadata', None)
- return data
-
-
-@AWSRetry.jittered_backoff(max_delay=120, catch_extra_error_codes=['NoSuchBucket', 'OperationAborted'])
-def get_bucket_property(name, connection, get_api_name):
- """
- Get bucket property
- """
- api_call = "get_" + get_api_name
- api_function = getattr(connection, api_call)
- data = api_function(Bucket=name)
-
- # Strip response metadata (not needed)
- data.pop('ResponseMetadata', None)
- return data
-
-
-def main():
- """
- Get list of S3 buckets
- :return:
- """
- argument_spec = dict(
- name=dict(type='str', default=""),
- name_filter=dict(type='str', default=""),
- bucket_facts=dict(type='dict', options=dict(
- bucket_accelerate_configuration=dict(type='bool', default=False),
- bucket_acl=dict(type='bool', default=False),
- bucket_cors=dict(type='bool', default=False),
- bucket_encryption=dict(type='bool', default=False),
- bucket_lifecycle_configuration=dict(type='bool', default=False),
- bucket_location=dict(type='bool', default=False),
- bucket_logging=dict(type='bool', default=False),
- bucket_notification_configuration=dict(type='bool', default=False),
- bucket_ownership_controls=dict(type='bool', default=False),
- bucket_policy=dict(type='bool', default=False),
- bucket_policy_status=dict(type='bool', default=False),
- bucket_replication=dict(type='bool', default=False),
- bucket_request_payment=dict(type='bool', default=False),
- bucket_tagging=dict(type='bool', default=False),
- bucket_website=dict(type='bool', default=False),
- public_access_block=dict(type='bool', default=False),
- )),
- transform_location=dict(type='bool', default=False)
- )
-
- # Ensure we have an empty dict
- result = {}
-
- # Define mutually exclusive options
- mutually_exclusive = [
- ['name', 'name_filter']
- ]
-
- # Including ec2 argument spec
- module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True, mutually_exclusive=mutually_exclusive)
-
- # Get parameters
- name = module.params.get("name")
- name_filter = module.params.get("name_filter")
- requested_facts = module.params.get("bucket_facts")
- transform_location = module.params.get("bucket_facts")
-
- # Set up connection
- connection = {}
- try:
- connection = module.client('s3')
- except (connection.exceptions.ClientError, botocore.exceptions.BotoCoreError) as err_code:
- module.fail_json_aws(err_code, msg='Failed to connect to AWS')
-
- # Get basic bucket list (name + creation date)
- bucket_list = get_bucket_list(module, connection, name, name_filter)
-
- # Add information about name/name_filter to result
- if name:
- result['bucket_name'] = name
- elif name_filter:
- result['bucket_name_filter'] = name_filter
-
- # Gather detailed information about buckets if requested
- bucket_facts = module.params.get("bucket_facts")
- if bucket_facts:
- result['buckets'] = get_buckets_facts(connection, bucket_list, requested_facts, transform_location)
- else:
- result['buckets'] = bucket_list
-
- module.exit_json(msg="Retrieved s3 info.", **result)
-
-
-# MAIN
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/aws/plugins/modules/s3_bucket_notification.py b/ansible_collections/community/aws/plugins/modules/s3_bucket_notification.py
index 645ca6989..1045164dc 100644
--- a/ansible_collections/community/aws/plugins/modules/s3_bucket_notification.py
+++ b/ansible_collections/community/aws/plugins/modules/s3_bucket_notification.py
@@ -1,15 +1,11 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
# Copyright: (c) 2021, Ansible Project
# (c) 2019, XLAB d.o.o <www.xlab.si>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: s3_bucket_notification
version_added: 1.0.0
@@ -104,12 +100,12 @@ options:
type: str
default: ''
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
---
# Examples adding notification target configs to a S3 bucket
- name: Setup bucket event notification to a Lambda function
@@ -138,9 +134,9 @@ EXAMPLES = r'''
state: absent
event_name: on_file_add_or_remove
bucket_name: test-bucket
-'''
+"""
-RETURN = r'''
+RETURN = r"""
notification_configuration:
description: dictionary of currently applied notifications
returned: success
@@ -158,51 +154,50 @@ notification_configuration:
description:
- List of current SNS notification configurations applied to the bucket.
type: list
-'''
-
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict
+"""
try:
- from botocore.exceptions import ClientError, BotoCoreError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
except ImportError:
pass # will be protected by AnsibleAWSModule
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
+
class AmazonBucket:
def __init__(self, module, client):
self.module = module
self.client = client
- self.bucket_name = module.params['bucket_name']
+ self.bucket_name = module.params["bucket_name"]
self.check_mode = module.check_mode
self._full_config_cache = None
def full_config(self):
if self._full_config_cache is None:
self._full_config_cache = dict(
- QueueConfigurations=[],
- TopicConfigurations=[],
- LambdaFunctionConfigurations=[]
+ QueueConfigurations=[], TopicConfigurations=[], LambdaFunctionConfigurations=[]
)
try:
- config_lookup = self.client.get_bucket_notification_configuration(
- Bucket=self.bucket_name)
+ config_lookup = self.client.get_bucket_notification_configuration(Bucket=self.bucket_name)
except (ClientError, BotoCoreError) as e:
- self.module.fail_json(msg='{0}'.format(e))
+ self.module.fail_json(msg=f"{e}")
# Handle different event targets
- if config_lookup.get('QueueConfigurations'):
- for queue_config in config_lookup.get('QueueConfigurations'):
- self._full_config_cache['QueueConfigurations'].append(Config.from_api(queue_config))
+ if config_lookup.get("QueueConfigurations"):
+ for queue_config in config_lookup.get("QueueConfigurations"):
+ self._full_config_cache["QueueConfigurations"].append(Config.from_api(queue_config))
- if config_lookup.get('TopicConfigurations'):
- for topic_config in config_lookup.get('TopicConfigurations'):
- self._full_config_cache['TopicConfigurations'].append(Config.from_api(topic_config))
+ if config_lookup.get("TopicConfigurations"):
+ for topic_config in config_lookup.get("TopicConfigurations"):
+ self._full_config_cache["TopicConfigurations"].append(Config.from_api(topic_config))
- if config_lookup.get('LambdaFunctionConfigurations'):
- for function_config in config_lookup.get('LambdaFunctionConfigurations'):
- self._full_config_cache['LambdaFunctionConfigurations'].append(Config.from_api(function_config))
+ if config_lookup.get("LambdaFunctionConfigurations"):
+ for function_config in config_lookup.get("LambdaFunctionConfigurations"):
+ self._full_config_cache["LambdaFunctionConfigurations"].append(Config.from_api(function_config))
return self._full_config_cache
@@ -210,70 +205,59 @@ class AmazonBucket:
# Iterate through configs and get current event config
for target_configs in self.full_config():
for config in self.full_config()[target_configs]:
- if config.raw['Id'] == config_name:
+ if config.raw["Id"] == config_name:
return config
def apply_config(self, desired):
- configs = dict(
- QueueConfigurations=[],
- TopicConfigurations=[],
- LambdaFunctionConfigurations=[]
- )
+ configs = dict(QueueConfigurations=[], TopicConfigurations=[], LambdaFunctionConfigurations=[])
# Iterate through existing configs then add the desired config
for target_configs in self.full_config():
for config in self.full_config()[target_configs]:
- if config.name != desired.raw['Id']:
+ if config.name != desired.raw["Id"]:
configs[target_configs].append(config.raw)
- if self.module.params.get('queue_arn'):
- configs['QueueConfigurations'].append(desired.raw)
- if self.module.params.get('topic_arn'):
- configs['TopicConfigurations'].append(desired.raw)
- if self.module.params.get('lambda_function_arn'):
- configs['LambdaFunctionConfigurations'].append(desired.raw)
+ if self.module.params.get("queue_arn"):
+ configs["QueueConfigurations"].append(desired.raw)
+ if self.module.params.get("topic_arn"):
+ configs["TopicConfigurations"].append(desired.raw)
+ if self.module.params.get("lambda_function_arn"):
+ configs["LambdaFunctionConfigurations"].append(desired.raw)
self._upload_bucket_config(configs)
return configs
def delete_config(self, desired):
- configs = dict(
- QueueConfigurations=[],
- TopicConfigurations=[],
- LambdaFunctionConfigurations=[]
- )
+ configs = dict(QueueConfigurations=[], TopicConfigurations=[], LambdaFunctionConfigurations=[])
# Iterate through existing configs omitting specified config
for target_configs in self.full_config():
for config in self.full_config()[target_configs]:
- if config.name != desired.raw['Id']:
+ if config.name != desired.raw["Id"]:
configs[target_configs].append(config.raw)
self._upload_bucket_config(configs)
return configs
def _upload_bucket_config(self, configs):
- api_params = dict(
- Bucket=self.bucket_name,
- NotificationConfiguration=dict()
- )
+ api_params = dict(Bucket=self.bucket_name, NotificationConfiguration=dict())
# Iterate through available configs
for target_configs in configs:
if len(configs[target_configs]) > 0:
- api_params['NotificationConfiguration'][target_configs] = configs[target_configs]
+ api_params["NotificationConfiguration"][target_configs] = configs[target_configs]
if not self.check_mode:
try:
self.client.put_bucket_notification_configuration(**api_params)
except (ClientError, BotoCoreError) as e:
- self.module.fail_json(msg='{0}'.format(e))
+ self.module.fail_json(msg=f"{e}")
class Config:
def __init__(self, content):
self._content = content
- self.name = content.get('Id')
+ self.name = content.get("Id")
@property
def raw(self):
@@ -289,41 +273,35 @@ class Config:
"""Generate bucket notification params for target"""
bucket_event_params = dict(
- Id=params['event_name'],
- Events=sorted(params['events']),
+ Id=params["event_name"],
+ Events=sorted(params["events"]),
Filter=dict(
Key=dict(
FilterRules=[
- dict(
- Name='Prefix',
- Value=params['prefix']
- ),
- dict(
- Name='Suffix',
- Value=params['suffix']
- )
+ dict(Name="Prefix", Value=params["prefix"]),
+ dict(Name="Suffix", Value=params["suffix"]),
]
)
- )
+ ),
)
# Handle different event targets
- if params.get('queue_arn'):
- bucket_event_params['QueueArn'] = params['queue_arn']
- if params.get('topic_arn'):
- bucket_event_params['TopicArn'] = params['topic_arn']
- if params.get('lambda_function_arn'):
- function_arn = params['lambda_function_arn']
+ if params.get("queue_arn"):
+ bucket_event_params["QueueArn"] = params["queue_arn"]
+ if params.get("topic_arn"):
+ bucket_event_params["TopicArn"] = params["topic_arn"]
+ if params.get("lambda_function_arn"):
+ function_arn = params["lambda_function_arn"]
qualifier = None
- if params['lambda_version'] > 0:
- qualifier = str(params['lambda_version'])
- elif params['lambda_alias']:
- qualifier = str(params['lambda_alias'])
+ if params["lambda_version"] > 0:
+ qualifier = str(params["lambda_version"])
+ elif params["lambda_alias"]:
+ qualifier = str(params["lambda_alias"])
if qualifier:
- params['lambda_function_arn'] = '{0}:{1}'.format(function_arn, qualifier)
+ params["lambda_function_arn"] = f"{function_arn}:{qualifier}"
- bucket_event_params['LambdaFunctionArn'] = params['lambda_function_arn']
+ bucket_event_params["LambdaFunctionArn"] = params["lambda_function_arn"]
return cls(bucket_event_params)
@@ -333,66 +311,70 @@ class Config:
def setup_module_object():
- event_types = ['s3:ObjectCreated:*', 's3:ObjectCreated:Put', 's3:ObjectCreated:Post',
- 's3:ObjectCreated:Copy', 's3:ObjectCreated:CompleteMultipartUpload',
- 's3:ObjectRemoved:*', 's3:ObjectRemoved:Delete',
- 's3:ObjectRemoved:DeleteMarkerCreated', 's3:ObjectRestore:Post',
- 's3:ObjectRestore:Completed', 's3:ReducedRedundancyLostObject']
+ event_types = [
+ "s3:ObjectCreated:*",
+ "s3:ObjectCreated:Put",
+ "s3:ObjectCreated:Post",
+ "s3:ObjectCreated:Copy",
+ "s3:ObjectCreated:CompleteMultipartUpload",
+ "s3:ObjectRemoved:*",
+ "s3:ObjectRemoved:Delete",
+ "s3:ObjectRemoved:DeleteMarkerCreated",
+ "s3:ObjectRestore:Post",
+ "s3:ObjectRestore:Completed",
+ "s3:ReducedRedundancyLostObject",
+ ]
argument_spec = dict(
- state=dict(default='present', choices=['present', 'absent']),
+ state=dict(default="present", choices=["present", "absent"]),
event_name=dict(required=True),
- lambda_function_arn=dict(aliases=['function_arn']),
- queue_arn=dict(type='str'),
- topic_arn=dict(type='str'),
+ lambda_function_arn=dict(aliases=["function_arn"]),
+ queue_arn=dict(type="str"),
+ topic_arn=dict(type="str"),
bucket_name=dict(required=True),
- events=dict(type='list', default=[], choices=event_types, elements='str'),
- prefix=dict(default=''),
- suffix=dict(default=''),
+ events=dict(type="list", default=[], choices=event_types, elements="str"),
+ prefix=dict(default=""),
+ suffix=dict(default=""),
lambda_alias=dict(),
- lambda_version=dict(type='int', default=0),
+ lambda_version=dict(type="int", default=0),
)
mutually_exclusive = [
- ['queue_arn', 'topic_arn', 'lambda_function_arn'],
- ['lambda_alias', 'lambda_version']
+ ["queue_arn", "topic_arn", "lambda_function_arn"],
+ ["lambda_alias", "lambda_version"],
]
return AnsibleAWSModule(
argument_spec=argument_spec,
supports_check_mode=True,
mutually_exclusive=mutually_exclusive,
- required_if=[['state', 'present', ['events']]]
+ required_if=[["state", "present", ["events"]]],
)
def main():
module = setup_module_object()
- client = module.client('s3')
+ client = module.client("s3")
bucket = AmazonBucket(module, client)
- current = bucket.current_config(module.params['event_name'])
+ current = bucket.current_config(module.params["event_name"])
desired = Config.from_params(**module.params)
- notification_configs = dict(
- QueueConfigurations=[],
- TopicConfigurations=[],
- LambdaFunctionConfigurations=[]
- )
+ notification_configs = dict(QueueConfigurations=[], TopicConfigurations=[], LambdaFunctionConfigurations=[])
for target_configs in bucket.full_config():
for cfg in bucket.full_config()[target_configs]:
notification_configs[target_configs].append(camel_dict_to_snake_dict(cfg.raw))
- state = module.params['state']
+ state = module.params["state"]
updated_configuration = dict()
changed = False
- if state == 'present':
+ if state == "present":
if current != desired:
updated_configuration = bucket.apply_config(desired)
changed = True
- elif state == 'absent':
+ elif state == "absent":
if current:
updated_configuration = bucket.delete_config(desired)
changed = True
@@ -402,9 +384,8 @@ def main():
for cfg in updated_configuration.get(target_configs, list()):
notification_configs[target_configs].append(camel_dict_to_snake_dict(cfg))
- module.exit_json(changed=changed, notification_configuration=camel_dict_to_snake_dict(
- notification_configs))
+ module.exit_json(changed=changed, notification_configuration=camel_dict_to_snake_dict(notification_configs))
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/s3_cors.py b/ansible_collections/community/aws/plugins/modules/s3_cors.py
index 753e395f9..d153c7df8 100644
--- a/ansible_collections/community/aws/plugins/modules/s3_cors.py
+++ b/ansible_collections/community/aws/plugins/modules/s3_cors.py
@@ -1,13 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-#
-
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: s3_cors
version_added: 1.0.0
@@ -36,12 +33,12 @@ options:
choices: [ 'present', 'absent' ]
type: str
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide for details.
# Create a simple cors for s3 bucket
@@ -65,9 +62,9 @@ EXAMPLES = r'''
- community.aws.s3_cors:
name: mys3bucket
state: absent
-'''
+"""
-RETURN = r'''
+RETURN = r"""
changed:
description: check to see if a change was made to the rules
returned: always
@@ -96,25 +93,28 @@ rules:
"max_age_seconds": 30000
}
]
-'''
+"""
try:
- from botocore.exceptions import ClientError, BotoCoreError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
except ImportError:
pass # Handled by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import snake_dict_to_camel_dict, compare_policies
+from ansible.module_utils.common.dict_transformations import snake_dict_to_camel_dict
+from ansible_collections.amazon.aws.plugins.module_utils.policy import compare_policies
-def create_or_update_bucket_cors(connection, module):
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
+
+def create_or_update_bucket_cors(connection, module):
name = module.params.get("name")
rules = module.params.get("rules", [])
changed = False
try:
- current_camel_rules = connection.get_bucket_cors(Bucket=name)['CORSRules']
+ current_camel_rules = connection.get_bucket_cors(Bucket=name)["CORSRules"]
except ClientError:
current_camel_rules = []
@@ -125,15 +125,14 @@ def create_or_update_bucket_cors(connection, module):
if changed:
try:
- cors = connection.put_bucket_cors(Bucket=name, CORSConfiguration={'CORSRules': new_camel_rules})
+ cors = connection.put_bucket_cors(Bucket=name, CORSConfiguration={"CORSRules": new_camel_rules})
except (BotoCoreError, ClientError) as e:
- module.fail_json_aws(e, msg="Unable to update CORS for bucket {0}".format(name))
+ module.fail_json_aws(e, msg=f"Unable to update CORS for bucket {name}")
module.exit_json(changed=changed, name=name, rules=rules)
def destroy_bucket_cors(connection, module):
-
name = module.params.get("name")
changed = False
@@ -141,30 +140,29 @@ def destroy_bucket_cors(connection, module):
cors = connection.delete_bucket_cors(Bucket=name)
changed = True
except (BotoCoreError, ClientError) as e:
- module.fail_json_aws(e, msg="Unable to delete CORS for bucket {0}".format(name))
+ module.fail_json_aws(e, msg=f"Unable to delete CORS for bucket {name}")
module.exit_json(changed=changed)
def main():
-
argument_spec = dict(
- name=dict(required=True, type='str'),
- rules=dict(type='list', elements='dict'),
- state=dict(type='str', choices=['present', 'absent'], required=True)
+ name=dict(required=True, type="str"),
+ rules=dict(type="list", elements="dict"),
+ state=dict(type="str", choices=["present", "absent"], required=True),
)
module = AnsibleAWSModule(argument_spec=argument_spec)
- client = module.client('s3')
+ client = module.client("s3")
state = module.params.get("state")
- if state == 'present':
+ if state == "present":
create_or_update_bucket_cors(client, module)
- elif state == 'absent':
+ elif state == "absent":
destroy_bucket_cors(client, module)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/s3_lifecycle.py b/ansible_collections/community/aws/plugins/modules/s3_lifecycle.py
index 660bca869..2f48e06d4 100644
--- a/ansible_collections/community/aws/plugins/modules/s3_lifecycle.py
+++ b/ansible_collections/community/aws/plugins/modules/s3_lifecycle.py
@@ -1,19 +1,18 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: s3_lifecycle
version_added: 1.0.0
short_description: Manage S3 bucket lifecycle rules in AWS
description:
- - Manage S3 bucket lifecycle rules in AWS.
-author: "Rob White (@wimnat)"
+ - Manage S3 bucket lifecycle rules in AWS.
+author:
+ - "Rob White (@wimnat)"
notes:
- If specifying expiration time as days then transition time must also be specified in days.
- If specifying expiration time as a date then transition time must also be specified as a date.
@@ -69,7 +68,6 @@ options:
noncurrent_version_keep_newer:
description:
- The minimum number of non-current versions to retain.
- - Requires C(botocore >= 1.23.12)
- Requres I(noncurrent_version_expiration_days).
required: false
type: int
@@ -149,13 +147,14 @@ options:
type: bool
default: false
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-'''
+RETURN = r""" # """
-EXAMPLES = r'''
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide for details.
- name: Configure a lifecycle rule on a bucket to expire (delete) items with a prefix of /logs/ after 30 days
@@ -219,14 +218,15 @@ EXAMPLES = r'''
storage_class: standard_ia
- transition_days: 90
storage_class: glacier
-'''
+"""
-from copy import deepcopy
import datetime
import time
+from copy import deepcopy
try:
from dateutil import parser as date_parser
+
HAS_DATEUTIL = True
except ImportError:
HAS_DATEUTIL = False
@@ -236,11 +236,12 @@ try:
except ImportError:
pass # handled by AnsibleAwsModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_message
-from ansible_collections.amazon.aws.plugins.module_utils.core import normalize_boto3_result
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_message
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import normalize_boto3_result
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def parse_date(date):
@@ -260,10 +261,13 @@ def fetch_rules(client, module, name):
# Get the bucket's current lifecycle rules
try:
current_lifecycle = client.get_bucket_lifecycle_configuration(aws_retry=True, Bucket=name)
- current_lifecycle_rules = normalize_boto3_result(current_lifecycle['Rules'])
- except is_boto3_error_code('NoSuchLifecycleConfiguration'):
+ current_lifecycle_rules = normalize_boto3_result(current_lifecycle["Rules"])
+ except is_boto3_error_code("NoSuchLifecycleConfiguration"):
current_lifecycle_rules = []
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
module.fail_json_aws(e)
return current_lifecycle_rules
@@ -290,35 +294,37 @@ def build_rule(client, module):
rule = dict(Filter=dict(Prefix=prefix), Status=status.title())
if rule_id is not None:
- rule['ID'] = rule_id
+ rule["ID"] = rule_id
if abort_incomplete_multipart_upload_days:
- rule['AbortIncompleteMultipartUpload'] = {
- 'DaysAfterInitiation': abort_incomplete_multipart_upload_days
- }
+ rule["AbortIncompleteMultipartUpload"] = {"DaysAfterInitiation": abort_incomplete_multipart_upload_days}
# Create expiration
if expiration_days is not None:
- rule['Expiration'] = dict(Days=expiration_days)
+ rule["Expiration"] = dict(Days=expiration_days)
elif expiration_date is not None:
- rule['Expiration'] = dict(Date=expiration_date.isoformat())
+ rule["Expiration"] = dict(Date=expiration_date.isoformat())
elif expire_object_delete_marker is not None:
- rule['Expiration'] = dict(ExpiredObjectDeleteMarker=expire_object_delete_marker)
+ rule["Expiration"] = dict(ExpiredObjectDeleteMarker=expire_object_delete_marker)
if noncurrent_version_expiration_days or noncurrent_version_keep_newer:
- rule['NoncurrentVersionExpiration'] = dict()
+ rule["NoncurrentVersionExpiration"] = dict()
if noncurrent_version_expiration_days is not None:
- rule['NoncurrentVersionExpiration']['NoncurrentDays'] = noncurrent_version_expiration_days
+ rule["NoncurrentVersionExpiration"]["NoncurrentDays"] = noncurrent_version_expiration_days
if noncurrent_version_keep_newer is not None:
- rule['NoncurrentVersionExpiration']['NewerNoncurrentVersions'] = noncurrent_version_keep_newer
+ rule["NoncurrentVersionExpiration"]["NewerNoncurrentVersions"] = noncurrent_version_keep_newer
if transition_days is not None:
- rule['Transitions'] = [dict(Days=transition_days, StorageClass=storage_class.upper()), ]
+ rule["Transitions"] = [
+ dict(Days=transition_days, StorageClass=storage_class.upper()),
+ ]
elif transition_date is not None:
- rule['Transitions'] = [dict(Date=transition_date.isoformat(), StorageClass=storage_class.upper()), ]
+ rule["Transitions"] = [
+ dict(Date=transition_date.isoformat(), StorageClass=storage_class.upper()),
+ ]
if transitions is not None:
- if not rule.get('Transitions'):
- rule['Transitions'] = []
+ if not rule.get("Transitions"):
+ rule["Transitions"] = []
for transition in transitions:
t_out = dict()
if transition.get("transition_date"):
@@ -330,18 +336,21 @@ def build_rule(client, module):
rule["Transitions"].append(t_out)
if noncurrent_version_transition_days is not None:
- rule['NoncurrentVersionTransitions'] = [dict(NoncurrentDays=noncurrent_version_transition_days,
- StorageClass=noncurrent_version_storage_class.upper()), ]
+ rule["NoncurrentVersionTransitions"] = [
+ dict(
+ NoncurrentDays=noncurrent_version_transition_days, StorageClass=noncurrent_version_storage_class.upper()
+ ),
+ ]
if noncurrent_version_transitions is not None:
- if not rule.get('NoncurrentVersionTransitions'):
- rule['NoncurrentVersionTransitions'] = []
+ if not rule.get("NoncurrentVersionTransitions"):
+ rule["NoncurrentVersionTransitions"] = []
for noncurrent_version_transition in noncurrent_version_transitions:
t_out = dict()
- t_out['NoncurrentDays'] = noncurrent_version_transition['transition_days']
- if noncurrent_version_transition.get('storage_class'):
- t_out['StorageClass'] = noncurrent_version_transition['storage_class'].upper()
- rule['NoncurrentVersionTransitions'].append(t_out)
+ t_out["NoncurrentDays"] = noncurrent_version_transition["transition_days"]
+ if noncurrent_version_transition.get("storage_class"):
+ t_out["StorageClass"] = noncurrent_version_transition["storage_class"].upper()
+ rule["NoncurrentVersionTransitions"].append(t_out)
return rule
@@ -358,23 +367,29 @@ def compare_and_update_configuration(client, module, current_lifecycle_rules, ru
if current_lifecycle_rules:
# If rule ID exists, use that for comparison otherwise compare based on prefix
for existing_rule in current_lifecycle_rules:
- if rule.get('ID') == existing_rule.get('ID') and rule['Filter'].get('Prefix', '') != existing_rule.get('Filter', {}).get('Prefix', ''):
- existing_rule.pop('ID')
- elif rule_id is None and rule['Filter'].get('Prefix', '') == existing_rule.get('Filter', {}).get('Prefix', ''):
- existing_rule.pop('ID')
- if rule.get('ID') == existing_rule.get('ID'):
- changed_, appended_ = update_or_append_rule(rule, existing_rule, purge_transitions, lifecycle_configuration)
+ if rule.get("ID") == existing_rule.get("ID") and rule["Filter"].get("Prefix", "") != existing_rule.get(
+ "Filter", {}
+ ).get("Prefix", ""):
+ existing_rule.pop("ID")
+ elif rule_id is None and rule["Filter"].get("Prefix", "") == existing_rule.get("Filter", {}).get(
+ "Prefix", ""
+ ):
+ existing_rule.pop("ID")
+ if rule.get("ID") == existing_rule.get("ID"):
+ changed_, appended_ = update_or_append_rule(
+ rule, existing_rule, purge_transitions, lifecycle_configuration
+ )
changed = changed_ or changed
appended = appended_ or appended
else:
- lifecycle_configuration['Rules'].append(existing_rule)
+ lifecycle_configuration["Rules"].append(existing_rule)
# If nothing appended then append now as the rule must not exist
if not appended:
- lifecycle_configuration['Rules'].append(rule)
+ lifecycle_configuration["Rules"].append(rule)
changed = True
else:
- lifecycle_configuration['Rules'].append(rule)
+ lifecycle_configuration["Rules"].append(rule)
changed = True
return changed, lifecycle_configuration
@@ -382,24 +397,24 @@ def compare_and_update_configuration(client, module, current_lifecycle_rules, ru
def update_or_append_rule(new_rule, existing_rule, purge_transitions, lifecycle_obj):
changed = False
- if existing_rule['Status'] != new_rule['Status']:
- if not new_rule.get('Transitions') and existing_rule.get('Transitions'):
- new_rule['Transitions'] = existing_rule['Transitions']
- if not new_rule.get('Expiration') and existing_rule.get('Expiration'):
- new_rule['Expiration'] = existing_rule['Expiration']
- if not new_rule.get('NoncurrentVersionExpiration') and existing_rule.get('NoncurrentVersionExpiration'):
- new_rule['NoncurrentVersionExpiration'] = existing_rule['NoncurrentVersionExpiration']
- lifecycle_obj['Rules'].append(new_rule)
+ if existing_rule["Status"] != new_rule["Status"]:
+ if not new_rule.get("Transitions") and existing_rule.get("Transitions"):
+ new_rule["Transitions"] = existing_rule["Transitions"]
+ if not new_rule.get("Expiration") and existing_rule.get("Expiration"):
+ new_rule["Expiration"] = existing_rule["Expiration"]
+ if not new_rule.get("NoncurrentVersionExpiration") and existing_rule.get("NoncurrentVersionExpiration"):
+ new_rule["NoncurrentVersionExpiration"] = existing_rule["NoncurrentVersionExpiration"]
+ lifecycle_obj["Rules"].append(new_rule)
changed = True
appended = True
else:
if not purge_transitions:
merge_transitions(new_rule, existing_rule)
if compare_rule(new_rule, existing_rule, purge_transitions):
- lifecycle_obj['Rules'].append(new_rule)
+ lifecycle_obj["Rules"].append(new_rule)
appended = True
else:
- lifecycle_obj['Rules'].append(new_rule)
+ lifecycle_obj["Rules"].append(new_rule)
changed = True
appended = True
return changed, appended
@@ -413,24 +428,23 @@ def compare_and_remove_rule(current_lifecycle_rules, rule_id=None, prefix=None):
# If an ID exists, use that otherwise compare based on prefix
if rule_id is not None:
for existing_rule in current_lifecycle_rules:
- if rule_id == existing_rule['ID']:
+ if rule_id == existing_rule["ID"]:
# We're not keeping the rule (i.e. deleting) so mark as changed
changed = True
else:
- lifecycle_configuration['Rules'].append(existing_rule)
+ lifecycle_configuration["Rules"].append(existing_rule)
else:
for existing_rule in current_lifecycle_rules:
- if prefix == existing_rule['Filter'].get('Prefix', ''):
+ if prefix == existing_rule["Filter"].get("Prefix", ""):
# We're not keeping the rule (i.e. deleting) so mark as changed
changed = True
else:
- lifecycle_configuration['Rules'].append(existing_rule)
+ lifecycle_configuration["Rules"].append(existing_rule)
return changed, lifecycle_configuration
def compare_rule(new_rule, old_rule, purge_transitions):
-
# Copy objects
rule1 = deepcopy(new_rule)
rule2 = deepcopy(old_rule)
@@ -438,10 +452,10 @@ def compare_rule(new_rule, old_rule, purge_transitions):
if purge_transitions:
return rule1 == rule2
else:
- transitions1 = rule1.pop('Transitions', [])
- transitions2 = rule2.pop('Transitions', [])
- noncurrent_transtions1 = rule1.pop('NoncurrentVersionTransitions', [])
- noncurrent_transtions2 = rule2.pop('NoncurrentVersionTransitions', [])
+ transitions1 = rule1.pop("Transitions", [])
+ transitions2 = rule2.pop("Transitions", [])
+ noncurrent_transtions1 = rule1.pop("NoncurrentVersionTransitions", [])
+ noncurrent_transtions2 = rule2.pop("NoncurrentVersionTransitions", [])
if rule1 != rule2:
return False
for transition in transitions1:
@@ -459,39 +473,39 @@ def merge_transitions(updated_rule, updating_rule):
# in updating_rule to updated_rule
updated_transitions = {}
updating_transitions = {}
- for transition in updated_rule.get('Transitions', []):
- updated_transitions[transition['StorageClass']] = transition
- for transition in updating_rule.get('Transitions', []):
- updating_transitions[transition['StorageClass']] = transition
+ for transition in updated_rule.get("Transitions", []):
+ updated_transitions[transition["StorageClass"]] = transition
+ for transition in updating_rule.get("Transitions", []):
+ updating_transitions[transition["StorageClass"]] = transition
for storage_class, transition in updating_transitions.items():
if updated_transitions.get(storage_class) is None:
- updated_rule['Transitions'].append(transition)
+ updated_rule["Transitions"].append(transition)
def create_lifecycle_rule(client, module):
-
name = module.params.get("name")
wait = module.params.get("wait")
changed = False
old_lifecycle_rules = fetch_rules(client, module, name)
new_rule = build_rule(client, module)
- (changed, lifecycle_configuration) = compare_and_update_configuration(client, module,
- old_lifecycle_rules,
- new_rule)
+ (changed, lifecycle_configuration) = compare_and_update_configuration(client, module, old_lifecycle_rules, new_rule)
if changed:
# Write lifecycle to bucket
try:
client.put_bucket_lifecycle_configuration(
- aws_retry=True,
- Bucket=name,
- LifecycleConfiguration=lifecycle_configuration,
+ aws_retry=True, Bucket=name, LifecycleConfiguration=lifecycle_configuration
)
except is_boto3_error_message("At least one action needs to be specified in a rule"):
# Amazon interpreted this as not changing anything
changed = False
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, lifecycle_configuration=lifecycle_configuration, name=name, old_lifecycle_rules=old_lifecycle_rules)
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(
+ e, lifecycle_configuration=lifecycle_configuration, name=name, old_lifecycle_rules=old_lifecycle_rules
+ )
_changed = changed
_retries = 10
@@ -504,9 +518,7 @@ def create_lifecycle_rule(client, module):
time.sleep(5)
_retries -= 1
new_rules = fetch_rules(client, module, name)
- (_changed, lifecycle_configuration) = compare_and_update_configuration(client, module,
- new_rules,
- new_rule)
+ (_changed, lifecycle_configuration) = compare_and_update_configuration(client, module, new_rules, new_rule)
if not _changed:
_not_changed_cnt -= 1
_changed = True
@@ -517,13 +529,17 @@ def create_lifecycle_rule(client, module):
new_rules = fetch_rules(client, module, name)
- module.exit_json(changed=changed, new_rule=new_rule, rules=new_rules,
- old_rules=old_lifecycle_rules, _retries=_retries,
- _config=lifecycle_configuration)
+ module.exit_json(
+ changed=changed,
+ new_rule=new_rule,
+ rules=new_rules,
+ old_rules=old_lifecycle_rules,
+ _retries=_retries,
+ _config=lifecycle_configuration,
+ )
def destroy_lifecycle_rule(client, module):
-
name = module.params.get("name")
prefix = module.params.get("prefix")
rule_id = module.params.get("rule_id")
@@ -539,11 +555,10 @@ def destroy_lifecycle_rule(client, module):
if changed:
# Write lifecycle to bucket or, if there no rules left, delete lifecycle configuration
try:
- if lifecycle_obj['Rules']:
+ if lifecycle_obj["Rules"]:
client.put_bucket_lifecycle_configuration(
- aws_retry=True,
- Bucket=name,
- LifecycleConfiguration=lifecycle_obj)
+ aws_retry=True, Bucket=name, LifecycleConfiguration=lifecycle_obj
+ )
elif current_lifecycle_rules:
changed = True
client.delete_bucket_lifecycle(aws_retry=True, Bucket=name)
@@ -572,33 +587,32 @@ def destroy_lifecycle_rule(client, module):
new_rules = fetch_rules(client, module, name)
- module.exit_json(changed=changed, rules=new_rules, old_rules=current_lifecycle_rules,
- _retries=_retries)
+ module.exit_json(changed=changed, rules=new_rules, old_rules=current_lifecycle_rules, _retries=_retries)
def main():
- s3_storage_class = ['glacier', 'onezone_ia', 'standard_ia', 'intelligent_tiering', 'deep_archive']
+ s3_storage_class = ["glacier", "onezone_ia", "standard_ia", "intelligent_tiering", "deep_archive"]
argument_spec = dict(
- name=dict(required=True, type='str'),
- abort_incomplete_multipart_upload_days=dict(type='int'),
- expiration_days=dict(type='int'),
+ name=dict(required=True, type="str"),
+ abort_incomplete_multipart_upload_days=dict(type="int"),
+ expiration_days=dict(type="int"),
expiration_date=dict(),
- expire_object_delete_marker=dict(type='bool'),
- noncurrent_version_expiration_days=dict(type='int'),
- noncurrent_version_keep_newer=dict(type='int'),
- noncurrent_version_storage_class=dict(default='glacier', type='str', choices=s3_storage_class),
- noncurrent_version_transition_days=dict(type='int'),
- noncurrent_version_transitions=dict(type='list', elements='dict'),
+ expire_object_delete_marker=dict(type="bool"),
+ noncurrent_version_expiration_days=dict(type="int"),
+ noncurrent_version_keep_newer=dict(type="int"),
+ noncurrent_version_storage_class=dict(default="glacier", type="str", choices=s3_storage_class),
+ noncurrent_version_transition_days=dict(type="int"),
+ noncurrent_version_transitions=dict(type="list", elements="dict"),
prefix=dict(),
rule_id=dict(),
- state=dict(default='present', choices=['present', 'absent']),
- status=dict(default='enabled', choices=['enabled', 'disabled']),
- storage_class=dict(default='glacier', type='str', choices=s3_storage_class),
- transition_days=dict(type='int'),
+ state=dict(default="present", choices=["present", "absent"]),
+ status=dict(default="enabled", choices=["enabled", "disabled"]),
+ storage_class=dict(default="glacier", type="str", choices=s3_storage_class),
+ transition_days=dict(type="int"),
transition_date=dict(),
- transitions=dict(type='list', elements='dict'),
- purge_transitions=dict(default=True, type='bool'),
- wait=dict(type='bool', default=False)
+ transitions=dict(type="list", elements="dict"),
+ purge_transitions=dict(default=True, type="bool"),
+ wait=dict(type="bool", default=False),
)
module = AnsibleAWSModule(
@@ -617,51 +631,54 @@ def main():
},
)
- client = module.client('s3', retry_decorator=AWSRetry.jittered_backoff())
+ client = module.client("s3", retry_decorator=AWSRetry.jittered_backoff())
expiration_date = module.params.get("expiration_date")
transition_date = module.params.get("transition_date")
state = module.params.get("state")
- if module.params.get("noncurrent_version_keep_newer"):
- module.require_botocore_at_least(
- "1.23.12",
- reason="to set number of versions to keep with noncurrent_version_keep_newer"
+ if state == "present" and module.params["status"] == "enabled": # allow deleting/disabling a rule by id/prefix
+ required_when_present = (
+ "abort_incomplete_multipart_upload_days",
+ "expiration_date",
+ "expiration_days",
+ "expire_object_delete_marker",
+ "transition_date",
+ "transition_days",
+ "transitions",
+ "noncurrent_version_expiration_days",
+ "noncurrent_version_keep_newer",
+ "noncurrent_version_transition_days",
+ "noncurrent_version_transitions",
)
-
- if state == 'present' and module.params["status"] == "enabled": # allow deleting/disabling a rule by id/prefix
-
- required_when_present = ('abort_incomplete_multipart_upload_days',
- 'expiration_date', 'expiration_days', 'expire_object_delete_marker',
- 'transition_date', 'transition_days', 'transitions',
- 'noncurrent_version_expiration_days',
- 'noncurrent_version_keep_newer',
- 'noncurrent_version_transition_days',
- 'noncurrent_version_transitions')
for param in required_when_present:
if module.params.get(param) is None:
break
else:
- msg = "one of the following is required when 'state' is 'present': %s" % ', '.join(required_when_present)
+ msg = f"one of the following is required when 'state' is 'present': {', '.join(required_when_present)}"
module.fail_json(msg=msg)
# If dates have been set, make sure they're in a valid format
if expiration_date:
expiration_date = parse_date(expiration_date)
if expiration_date is None:
- module.fail_json(msg="expiration_date is not a valid ISO-8601 format."
- " The time must be midnight and a timezone of GMT must be included")
+ module.fail_json(
+ msg="expiration_date is not a valid ISO-8601 format."
+ " The time must be midnight and a timezone of GMT must be included"
+ )
if transition_date:
transition_date = parse_date(transition_date)
if transition_date is None:
- module.fail_json(msg="transition_date is not a valid ISO-8601 format."
- " The time must be midnight and a timezone of GMT must be included")
+ module.fail_json(
+ msg="transition_date is not a valid ISO-8601 format."
+ " The time must be midnight and a timezone of GMT must be included"
+ )
- if state == 'present':
+ if state == "present":
create_lifecycle_rule(client, module)
- elif state == 'absent':
+ elif state == "absent":
destroy_lifecycle_rule(client, module)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/s3_logging.py b/ansible_collections/community/aws/plugins/modules/s3_logging.py
index 011baa951..3a7874994 100644
--- a/ansible_collections/community/aws/plugins/modules/s3_logging.py
+++ b/ansible_collections/community/aws/plugins/modules/s3_logging.py
@@ -1,19 +1,18 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: s3_logging
version_added: 1.0.0
short_description: Manage logging facility of an s3 bucket in AWS
description:
- - Manage logging facility of an s3 bucket in AWS
-author: Rob White (@wimnat)
+ - Manage logging facility of an s3 bucket in AWS
+author:
+ - Rob White (@wimnat)
options:
name:
description:
@@ -36,13 +35,14 @@ options:
default: ""
type: str
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-'''
+RETURN = r""" # """
-EXAMPLES = '''
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide for details.
- name: Enable logging of s3 bucket mywebsite.com to s3 bucket mylogs
@@ -56,32 +56,31 @@ EXAMPLES = '''
community.aws.s3_logging:
name: mywebsite.com
state: absent
-
-'''
+"""
try:
import botocore
except ImportError:
pass # Handled by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
-def compare_bucket_logging(bucket_logging, target_bucket, target_prefix):
- if not bucket_logging.get('LoggingEnabled', False):
+def compare_bucket_logging(bucket_logging, target_bucket, target_prefix):
+ if not bucket_logging.get("LoggingEnabled", False):
if target_bucket:
return True
return False
- logging = bucket_logging['LoggingEnabled']
- if logging['TargetBucket'] != target_bucket:
+ logging = bucket_logging["LoggingEnabled"]
+ if logging["TargetBucket"] != target_bucket:
return True
- if logging['TargetPrefix'] != target_prefix:
+ if logging["TargetPrefix"] != target_prefix:
return True
return False
@@ -89,18 +88,18 @@ def compare_bucket_logging(bucket_logging, target_bucket, target_prefix):
def verify_acls(connection, module, target_bucket):
try:
current_acl = connection.get_bucket_acl(aws_retry=True, Bucket=target_bucket)
- current_grants = current_acl['Grants']
- except is_boto3_error_code('NoSuchBucket'):
- module.fail_json(msg="Target Bucket '{0}' not found".format(target_bucket))
- except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e: # pylint: disable=duplicate-except
+ current_grants = current_acl["Grants"]
+ except is_boto3_error_code("NoSuchBucket"):
+ module.fail_json(msg=f"Target Bucket '{target_bucket}' not found")
+ except (
+ botocore.exceptions.BotoCoreError,
+ botocore.exceptions.ClientError,
+ ) as e: # pylint: disable=duplicate-except
module.fail_json_aws(e, msg="Failed to fetch target bucket ACL")
required_grant = {
- 'Grantee': {
- 'URI': "http://acs.amazonaws.com/groups/s3/LogDelivery",
- 'Type': 'Group'
- },
- 'Permission': 'FULL_CONTROL'
+ "Grantee": {"URI": "http://acs.amazonaws.com/groups/s3/LogDelivery", "Type": "Group"},
+ "Permission": "FULL_CONTROL",
}
for grant in current_grants:
@@ -113,8 +112,8 @@ def verify_acls(connection, module, target_bucket):
updated_acl = dict(current_acl)
updated_grants = list(current_grants)
updated_grants.append(required_grant)
- updated_acl['Grants'] = updated_grants
- del updated_acl['ResponseMetadata']
+ updated_acl["Grants"] = updated_grants
+ del updated_acl["ResponseMetadata"]
try:
connection.put_bucket_acl(aws_retry=True, Bucket=target_bucket, AccessControlPolicy=updated_acl)
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
@@ -124,7 +123,6 @@ def verify_acls(connection, module, target_bucket):
def enable_bucket_logging(connection, module):
-
bucket_name = module.params.get("name")
target_bucket = module.params.get("target_bucket")
target_prefix = module.params.get("target_prefix")
@@ -132,9 +130,12 @@ def enable_bucket_logging(connection, module):
try:
bucket_logging = connection.get_bucket_logging(aws_retry=True, Bucket=bucket_name)
- except is_boto3_error_code('NoSuchBucket'):
- module.fail_json(msg="Bucket '{0}' not found".format(bucket_name))
- except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e: # pylint: disable=duplicate-except
+ except is_boto3_error_code("NoSuchBucket"):
+ module.fail_json(msg=f"Bucket '{bucket_name}' not found")
+ except (
+ botocore.exceptions.BotoCoreError,
+ botocore.exceptions.ClientError,
+ ) as e: # pylint: disable=duplicate-except
module.fail_json_aws(e, msg="Failed to fetch current logging status")
try:
@@ -151,11 +152,12 @@ def enable_bucket_logging(connection, module):
aws_retry=True,
Bucket=bucket_name,
BucketLoggingStatus={
- 'LoggingEnabled': {
- 'TargetBucket': target_bucket,
- 'TargetPrefix': target_prefix,
+ "LoggingEnabled": {
+ "TargetBucket": target_bucket,
+ "TargetPrefix": target_prefix,
}
- })
+ },
+ )
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
module.fail_json_aws(e, msg="Failed to enable bucket logging")
@@ -165,7 +167,6 @@ def enable_bucket_logging(connection, module):
def disable_bucket_logging(connection, module):
-
bucket_name = module.params.get("name")
changed = False
@@ -181,11 +182,9 @@ def disable_bucket_logging(connection, module):
module.exit_json(changed=True)
try:
- response = AWSRetry.jittered_backoff(
- catch_extra_error_codes=['InvalidTargetBucketForLogging']
- )(connection.put_bucket_logging)(
- Bucket=bucket_name, BucketLoggingStatus={}
- )
+ response = AWSRetry.jittered_backoff(catch_extra_error_codes=["InvalidTargetBucketForLogging"])(
+ connection.put_bucket_logging
+ )(Bucket=bucket_name, BucketLoggingStatus={})
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
module.fail_json_aws(e, msg="Failed to disable bucket logging")
@@ -193,24 +192,23 @@ def disable_bucket_logging(connection, module):
def main():
-
argument_spec = dict(
name=dict(required=True),
target_bucket=dict(required=False, default=None),
target_prefix=dict(required=False, default=""),
- state=dict(required=False, default='present', choices=['present', 'absent']),
+ state=dict(required=False, default="present", choices=["present", "absent"]),
)
module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
- connection = module.client('s3', retry_decorator=AWSRetry.jittered_backoff())
+ connection = module.client("s3", retry_decorator=AWSRetry.jittered_backoff())
state = module.params.get("state")
- if state == 'present':
+ if state == "present":
enable_bucket_logging(connection, module)
- elif state == 'absent':
+ elif state == "absent":
disable_bucket_logging(connection, module)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/s3_metrics_configuration.py b/ansible_collections/community/aws/plugins/modules/s3_metrics_configuration.py
index dff566821..4e62b7bf8 100644
--- a/ansible_collections/community/aws/plugins/modules/s3_metrics_configuration.py
+++ b/ansible_collections/community/aws/plugins/modules/s3_metrics_configuration.py
@@ -1,23 +1,22 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: s3_metrics_configuration
version_added: 1.3.0
short_description: Manage s3 bucket metrics configuration in AWS
description:
- - Manage s3 bucket metrics configuration in AWS which allows to get the CloudWatch request metrics for the objects in a bucket
-author: Dmytro Vorotyntsev (@vorotech)
+ - Manage s3 bucket metrics configuration in AWS which allows to get the CloudWatch request metrics for the objects in a bucket
+author:
+ - Dmytro Vorotyntsev (@vorotech)
notes:
- - This modules manages single metrics configuration, the s3 bucket might have up to 1,000 metrics configurations
- - To request metrics for the entire bucket, create a metrics configuration without a filter
- - Metrics configurations are necessary only to enable request metric, bucket-level daily storage metrics are always turned on
+ - This modules manages single metrics configuration, the s3 bucket might have up to 1,000 metrics configurations
+ - To request metrics for the entire bucket, create a metrics configuration without a filter
+ - Metrics configurations are necessary only to enable request metric, bucket-level daily storage metrics are always turned on
options:
bucket_name:
description:
@@ -48,13 +47,14 @@ options:
choices: ['present', 'absent']
type: str
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-'''
+RETURN = r""" # """
-EXAMPLES = r'''
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide for details.
- name: Create a metrics configuration that enables metrics for an entire bucket
@@ -93,56 +93,47 @@ EXAMPLES = r'''
bucket_name: my-bucket
id: EntireBucket
state: absent
-
-'''
+"""
try:
- from botocore.exceptions import ClientError, BotoCoreError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
except ImportError:
pass # Handled by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_tag_list
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import ansible_dict_to_boto3_tag_list
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def _create_metrics_configuration(mc_id, filter_prefix, filter_tags):
- payload = {
- 'Id': mc_id
- }
+ payload = {"Id": mc_id}
# Just a filter_prefix or just a single tag filter is a special case
if filter_prefix and not filter_tags:
- payload['Filter'] = {
- 'Prefix': filter_prefix
- }
+ payload["Filter"] = {"Prefix": filter_prefix}
elif not filter_prefix and len(filter_tags) == 1:
- payload['Filter'] = {
- 'Tag': ansible_dict_to_boto3_tag_list(filter_tags)[0]
- }
+ payload["Filter"] = {"Tag": ansible_dict_to_boto3_tag_list(filter_tags)[0]}
# Otherwise we need to use 'And'
elif filter_tags:
- payload['Filter'] = {
- 'And': {
- 'Tags': ansible_dict_to_boto3_tag_list(filter_tags)
- }
- }
+ payload["Filter"] = {"And": {"Tags": ansible_dict_to_boto3_tag_list(filter_tags)}}
if filter_prefix:
- payload['Filter']['And']['Prefix'] = filter_prefix
+ payload["Filter"]["And"]["Prefix"] = filter_prefix
return payload
def create_or_update_metrics_configuration(client, module):
- bucket_name = module.params.get('bucket_name')
- mc_id = module.params.get('id')
- filter_prefix = module.params.get('filter_prefix')
- filter_tags = module.params.get('filter_tags')
+ bucket_name = module.params.get("bucket_name")
+ mc_id = module.params.get("id")
+ filter_prefix = module.params.get("filter_prefix")
+ filter_tags = module.params.get("filter_tags")
try:
response = client.get_bucket_metrics_configuration(aws_retry=True, Bucket=bucket_name, Id=mc_id)
- metrics_configuration = response['MetricsConfiguration']
- except is_boto3_error_code('NoSuchConfiguration'):
+ metrics_configuration = response["MetricsConfiguration"]
+ except is_boto3_error_code("NoSuchConfiguration"):
metrics_configuration = None
except (BotoCoreError, ClientError) as e: # pylint: disable=duplicate-except
module.fail_json_aws(e, msg="Failed to get bucket metrics configuration")
@@ -158,24 +149,21 @@ def create_or_update_metrics_configuration(client, module):
try:
client.put_bucket_metrics_configuration(
- aws_retry=True,
- Bucket=bucket_name,
- Id=mc_id,
- MetricsConfiguration=new_configuration
+ aws_retry=True, Bucket=bucket_name, Id=mc_id, MetricsConfiguration=new_configuration
)
except (BotoCoreError, ClientError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, msg="Failed to put bucket metrics configuration '%s'" % mc_id)
+ module.fail_json_aws(e, msg=f"Failed to put bucket metrics configuration '{mc_id}'")
module.exit_json(changed=True)
def delete_metrics_configuration(client, module):
- bucket_name = module.params.get('bucket_name')
- mc_id = module.params.get('id')
+ bucket_name = module.params.get("bucket_name")
+ mc_id = module.params.get("id")
try:
client.get_bucket_metrics_configuration(aws_retry=True, Bucket=bucket_name, Id=mc_id)
- except is_boto3_error_code('NoSuchConfiguration'):
+ except is_boto3_error_code("NoSuchConfiguration"):
module.exit_json(changed=False)
except (BotoCoreError, ClientError) as e: # pylint: disable=duplicate-except
module.fail_json_aws(e, msg="Failed to get bucket metrics configuration")
@@ -185,39 +173,36 @@ def delete_metrics_configuration(client, module):
try:
client.delete_bucket_metrics_configuration(aws_retry=True, Bucket=bucket_name, Id=mc_id)
- except is_boto3_error_code('NoSuchConfiguration'):
+ except is_boto3_error_code("NoSuchConfiguration"):
module.exit_json(changed=False)
except (BotoCoreError, ClientError) as e: # pylint: disable=duplicate-except
- module.fail_json_aws(e, msg="Failed to delete bucket metrics configuration '%s'" % mc_id)
+ module.fail_json_aws(e, msg=f"Failed to delete bucket metrics configuration '{mc_id}'")
module.exit_json(changed=True)
def main():
argument_spec = dict(
- bucket_name=dict(type='str', required=True),
- id=dict(type='str', required=True),
- filter_prefix=dict(type='str', required=False),
- filter_tags=dict(default={}, type='dict', required=False, aliases=['filter_tag']),
- state=dict(default='present', type='str', choices=['present', 'absent']),
- )
- module = AnsibleAWSModule(
- argument_spec=argument_spec,
- supports_check_mode=True
+ bucket_name=dict(type="str", required=True),
+ id=dict(type="str", required=True),
+ filter_prefix=dict(type="str", required=False),
+ filter_tags=dict(default={}, type="dict", required=False, aliases=["filter_tag"]),
+ state=dict(default="present", type="str", choices=["present", "absent"]),
)
+ module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
- state = module.params.get('state')
+ state = module.params.get("state")
try:
- client = module.client('s3', retry_decorator=AWSRetry.exponential_backoff(retries=10, delay=3))
+ client = module.client("s3", retry_decorator=AWSRetry.exponential_backoff(retries=10, delay=3))
except (BotoCoreError, ClientError) as e:
- module.fail_json_aws(e, msg='Failed to connect to AWS')
+ module.fail_json_aws(e, msg="Failed to connect to AWS")
- if state == 'present':
+ if state == "present":
create_or_update_metrics_configuration(client, module)
- elif state == 'absent':
+ elif state == "absent":
delete_metrics_configuration(client, module)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/s3_sync.py b/ansible_collections/community/aws/plugins/modules/s3_sync.py
index 80e3db0bd..36809ed2f 100644
--- a/ansible_collections/community/aws/plugins/modules/s3_sync.py
+++ b/ansible_collections/community/aws/plugins/modules/s3_sync.py
@@ -1,31 +1,17 @@
#!/usr/bin/python
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+# -*- coding: utf-8 -*-
+
+# Copyright: Contributors to the Ansible project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = r"""
---
module: s3_sync
version_added: 1.0.0
short_description: Efficiently upload multiple files to S3
description:
- - The S3 module is great, but it is very slow for a large volume of files- even a dozen will be noticeable. In addition to speed, it handles globbing,
- inclusions/exclusions, mime types, expiration mapping, recursion, cache control and smart directory mapping.
+- The S3 module is great, but it is very slow for a large volume of files- even a dozen will be noticeable. In addition to speed, it handles globbing,
+ inclusions/exclusions, mime types, expiration mapping, recursion, cache control and smart directory mapping.
options:
mode:
description:
@@ -127,15 +113,15 @@ options:
default: false
type: bool
-author: Ted Timmons (@tedder)
+author:
+- Ted Timmons (@tedder)
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
+- amazon.aws.common.modules
+- amazon.aws.region.modules
- amazon.aws.boto3
+"""
-'''
-
-EXAMPLES = '''
+EXAMPLES = r"""
- name: basic upload
community.aws.s3_sync:
bucket: tedder
@@ -166,9 +152,9 @@ EXAMPLES = '''
storage_class: "GLACIER"
include: "*"
exclude: "*.txt,.*"
-'''
+"""
-RETURN = '''
+RETURN = r"""
filelist_initial:
description: file listing (dicts) from initial globbing
returned: always
@@ -241,7 +227,7 @@ uploads:
"whytime": "1477931637 / 1477931489"
}]
-'''
+"""
import datetime
import fnmatch
@@ -251,6 +237,7 @@ import stat as osstat # os.stat constants
try:
from dateutil import tz
+
HAS_DATEUTIL = True
except ImportError:
HAS_DATEUTIL = False
@@ -262,11 +249,10 @@ except ImportError:
from ansible.module_utils._text import to_text
-# import module snippets
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
from ansible_collections.community.aws.plugins.module_utils.etag import calculate_multipart_etag
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def gather_files(fileroot, include=None, exclude=None):
@@ -275,25 +261,27 @@ def gather_files(fileroot, include=None, exclude=None):
if os.path.isfile(fileroot):
fullpath = fileroot
fstat = os.stat(fullpath)
- path_array = fileroot.split('/')
+ path_array = fileroot.split("/")
chopped_path = path_array[-1]
f_size = fstat[osstat.ST_SIZE]
f_modified_epoch = fstat[osstat.ST_MTIME]
- ret.append({
- 'fullpath': fullpath,
- 'chopped_path': chopped_path,
- 'modified_epoch': f_modified_epoch,
- 'bytes': f_size,
- })
+ ret.append(
+ {
+ "fullpath": fullpath,
+ "chopped_path": chopped_path,
+ "modified_epoch": f_modified_epoch,
+ "bytes": f_size,
+ }
+ )
else:
- for (dirpath, dirnames, filenames) in os.walk(fileroot):
+ for dirpath, dirnames, filenames in os.walk(fileroot):
for fn in filenames:
fullpath = os.path.join(dirpath, fn)
# include/exclude
if include:
found = False
- for x in include.split(','):
+ for x in include.split(","):
if fnmatch.fnmatch(fn, x):
found = True
if not found:
@@ -302,7 +290,7 @@ def gather_files(fileroot, include=None, exclude=None):
if exclude:
found = False
- for x in exclude.split(','):
+ for x in exclude.split(","):
if fnmatch.fnmatch(fn, x):
found = True
if found:
@@ -313,36 +301,38 @@ def gather_files(fileroot, include=None, exclude=None):
fstat = os.stat(fullpath)
f_size = fstat[osstat.ST_SIZE]
f_modified_epoch = fstat[osstat.ST_MTIME]
- ret.append({
- 'fullpath': fullpath,
- 'chopped_path': chopped_path,
- 'modified_epoch': f_modified_epoch,
- 'bytes': f_size,
- })
+ ret.append(
+ {
+ "fullpath": fullpath,
+ "chopped_path": chopped_path,
+ "modified_epoch": f_modified_epoch,
+ "bytes": f_size,
+ }
+ )
# dirpath = path *to* the directory
# dirnames = subdirs *in* our directory
# filenames
return ret
-def calculate_s3_path(filelist, key_prefix=''):
+def calculate_s3_path(filelist, key_prefix=""):
ret = []
for fileentry in filelist:
# don't modify the input dict
retentry = fileentry.copy()
- retentry['s3_path'] = os.path.join(key_prefix, fileentry['chopped_path'])
+ retentry["s3_path"] = os.path.join(key_prefix, fileentry["chopped_path"])
ret.append(retentry)
return ret
-def calculate_local_etag(filelist, key_prefix=''):
- '''Really, "calculate md5", but since AWS uses their own format, we'll just call
- it a "local etag". TODO optimization: only calculate if remote key exists.'''
+def calculate_local_etag(filelist, key_prefix=""):
+ """Really, "calculate md5", but since AWS uses their own format, we'll just call
+ it a "local etag". TODO optimization: only calculate if remote key exists."""
ret = []
for fileentry in filelist:
# don't modify the input dict
retentry = fileentry.copy()
- retentry['local_etag'] = calculate_multipart_etag(fileentry['fullpath'])
+ retentry["local_etag"] = calculate_multipart_etag(fileentry["fullpath"])
ret.append(retentry)
return ret
@@ -351,20 +341,20 @@ def determine_mimetypes(filelist, override_map):
ret = []
for fileentry in filelist:
retentry = fileentry.copy()
- localfile = fileentry['fullpath']
+ localfile = fileentry["fullpath"]
# reminder: file extension is '.txt', not 'txt'.
file_extension = os.path.splitext(localfile)[1]
if override_map and override_map.get(file_extension):
# override? use it.
- retentry['mime_type'] = override_map[file_extension]
+ retentry["mime_type"] = override_map[file_extension]
else:
# else sniff it
- retentry['mime_type'], retentry['encoding'] = mimetypes.guess_type(localfile, strict=False)
+ retentry["mime_type"], retentry["encoding"] = mimetypes.guess_type(localfile, strict=False)
# might be None or '' from one of the above. Not a great type but better than nothing.
- if not retentry['mime_type']:
- retentry['mime_type'] = 'application/octet-stream'
+ if not retentry["mime_type"]:
+ retentry["mime_type"] = "application/octet-stream"
ret.append(retentry)
@@ -376,10 +366,10 @@ def head_s3(s3, bucket, s3keys):
for entry in s3keys:
retentry = entry.copy()
try:
- retentry['s3_head'] = s3.head_object(Bucket=bucket, Key=entry['s3_path'])
+ retentry["s3_head"] = s3.head_object(Bucket=bucket, Key=entry["s3_path"])
# 404 (Missing) - File doesn't exist, we'll need to upload
# 403 (Denied) - Sometimes we can write but not read, assume we'll need to upload
- except is_boto3_error_code(['404', '403']):
+ except is_boto3_error_code(["404", "403"]):
pass
retkeys.append(retentry)
return retkeys
@@ -389,106 +379,127 @@ def filter_list(s3, bucket, s3filelist, strategy):
keeplist = list(s3filelist)
for e in keeplist:
- e['_strategy'] = strategy
+ e["_strategy"] = strategy
# init/fetch info from S3 if we're going to use it for comparisons
- if not strategy == 'force':
+ if not strategy == "force":
keeplist = head_s3(s3, bucket, s3filelist)
# now actually run the strategies
- if strategy == 'checksum':
+ if strategy == "checksum":
for entry in keeplist:
- if entry.get('s3_head'):
+ if entry.get("s3_head"):
# since we have a remote s3 object, compare the values.
- if entry['s3_head']['ETag'] == entry['local_etag']:
+ if entry["s3_head"]["ETag"] == entry["local_etag"]:
# files match, so remove the entry
- entry['skip_flag'] = True
+ entry["skip_flag"] = True
else:
# file etags don't match, keep the entry.
pass
else: # we don't have an etag, so we'll keep it.
pass
- elif strategy == 'date_size':
+ elif strategy == "date_size":
for entry in keeplist:
- if entry.get('s3_head'):
+ if entry.get("s3_head"):
# fstat = entry['stat']
- local_modified_epoch = entry['modified_epoch']
- local_size = entry['bytes']
+ local_modified_epoch = entry["modified_epoch"]
+ local_size = entry["bytes"]
# py2's datetime doesn't have a timestamp() field, so we have to revert to something more awkward.
# remote_modified_epoch = entry['s3_head']['LastModified'].timestamp()
- remote_modified_datetime = entry['s3_head']['LastModified']
- delta = (remote_modified_datetime - datetime.datetime(1970, 1, 1, tzinfo=tz.tzutc()))
+ remote_modified_datetime = entry["s3_head"]["LastModified"]
+ delta = remote_modified_datetime - datetime.datetime(1970, 1, 1, tzinfo=tz.tzutc())
remote_modified_epoch = delta.seconds + (delta.days * 86400)
- remote_size = entry['s3_head']['ContentLength']
+ remote_size = entry["s3_head"]["ContentLength"]
- entry['whytime'] = '{0} / {1}'.format(local_modified_epoch, remote_modified_epoch)
- entry['whysize'] = '{0} / {1}'.format(local_size, remote_size)
+ entry["whytime"] = f"{local_modified_epoch} / {remote_modified_epoch}"
+ entry["whysize"] = f"{local_size} / {remote_size}"
if local_modified_epoch <= remote_modified_epoch and local_size == remote_size:
- entry['skip_flag'] = True
+ entry["skip_flag"] = True
else:
- entry['why'] = "no s3_head"
+ entry["why"] = "no s3_head"
# else: probably 'force'. Basically we don't skip with any with other strategies.
else:
pass
# prune 'please skip' entries, if any.
- return [x for x in keeplist if not x.get('skip_flag')]
+ return [x for x in keeplist if not x.get("skip_flag")]
def upload_files(s3, bucket, filelist, params):
ret = []
for entry in filelist:
- args = {
- 'ContentType': entry['mime_type']
- }
- if params.get('permission'):
- args['ACL'] = params['permission']
- if params.get('cache_control'):
- args['CacheControl'] = params['cache_control']
- if params.get('storage_class'):
- args['StorageClass'] = params['storage_class']
+ args = {"ContentType": entry["mime_type"]}
+ if params.get("permission"):
+ args["ACL"] = params["permission"]
+ if params.get("cache_control"):
+ args["CacheControl"] = params["cache_control"]
+ if params.get("storage_class"):
+ args["StorageClass"] = params["storage_class"]
# if this fails exception is caught in main()
- s3.upload_file(entry['fullpath'], bucket, entry['s3_path'], ExtraArgs=args, Callback=None, Config=None)
+ s3.upload_file(entry["fullpath"], bucket, entry["s3_path"], ExtraArgs=args, Callback=None, Config=None)
ret.append(entry)
return ret
def remove_files(s3, sourcelist, params):
- bucket = params.get('bucket')
- key_prefix = params.get('key_prefix')
- paginator = s3.get_paginator('list_objects_v2')
- current_keys = set(x['Key'] for x in paginator.paginate(Bucket=bucket, Prefix=key_prefix).build_full_result().get('Contents', []))
- keep_keys = set(to_text(source_file['s3_path']) for source_file in sourcelist)
+ bucket = params.get("bucket")
+ key_prefix = params.get("key_prefix")
+ paginator = s3.get_paginator("list_objects_v2")
+ current_keys = set(
+ x["Key"] for x in paginator.paginate(Bucket=bucket, Prefix=key_prefix).build_full_result().get("Contents", [])
+ )
+ keep_keys = set(to_text(source_file["s3_path"]) for source_file in sourcelist)
delete_keys = list(current_keys - keep_keys)
# can delete 1000 objects at a time
- groups_of_keys = [delete_keys[i:i + 1000] for i in range(0, len(delete_keys), 1000)]
+ groups_of_keys = [delete_keys[i:i + 1000] for i in range(0, len(delete_keys), 1000)] # fmt:skip
for keys in groups_of_keys:
- s3.delete_objects(Bucket=bucket, Delete={'Objects': [{'Key': key} for key in keys]})
+ s3.delete_objects(Bucket=bucket, Delete={"Objects": [{"Key": key} for key in keys]})
return delete_keys
def main():
argument_spec = dict(
- mode=dict(choices=['push'], default='push'),
- file_change_strategy=dict(choices=['force', 'date_size', 'checksum'], default='date_size'),
+ mode=dict(choices=["push"], default="push"),
+ file_change_strategy=dict(choices=["force", "date_size", "checksum"], default="date_size"),
bucket=dict(required=True),
- key_prefix=dict(required=False, default='', no_log=False),
- file_root=dict(required=True, type='path'),
- permission=dict(required=False, choices=['private', 'public-read', 'public-read-write', 'authenticated-read',
- 'aws-exec-read', 'bucket-owner-read', 'bucket-owner-full-control']),
- mime_map=dict(required=False, type='dict'),
+ key_prefix=dict(required=False, default="", no_log=False),
+ file_root=dict(required=True, type="path"),
+ permission=dict(
+ required=False,
+ choices=[
+ "private",
+ "public-read",
+ "public-read-write",
+ "authenticated-read",
+ "aws-exec-read",
+ "bucket-owner-read",
+ "bucket-owner-full-control",
+ ],
+ ),
+ mime_map=dict(required=False, type="dict"),
exclude=dict(required=False, default=".*"),
include=dict(required=False, default="*"),
- cache_control=dict(required=False, default=''),
- delete=dict(required=False, type='bool', default=False),
- storage_class=dict(required=False, default='STANDARD',
- choices=['STANDARD', 'REDUCED_REDUNDANCY', 'STANDARD_IA', 'ONEZONE_IA',
- 'INTELLIGENT_TIERING', 'GLACIER', 'DEEP_ARCHIVE', 'OUTPOSTS']),
+ cache_control=dict(required=False, default=""),
+ delete=dict(required=False, type="bool", default=False),
+ storage_class=dict(
+ required=False,
+ default="STANDARD",
+ choices=[
+ "STANDARD",
+ "REDUCED_REDUNDANCY",
+ "STANDARD_IA",
+ "ONEZONE_IA",
+ "INTELLIGENT_TIERING",
+ "GLACIER",
+ "DEEP_ARCHIVE",
+ "OUTPOSTS",
+ ],
+ ),
# future options: encoding, metadata, retries
)
@@ -497,36 +508,43 @@ def main():
)
if not HAS_DATEUTIL:
- module.fail_json(msg='dateutil required for this module')
+ module.fail_json(msg="dateutil required for this module")
result = {}
- mode = module.params['mode']
+ mode = module.params["mode"]
try:
- s3 = module.client('s3')
+ s3 = module.client("s3")
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to connect to AWS')
+ module.fail_json_aws(e, msg="Failed to connect to AWS")
- if mode == 'push':
+ if mode == "push":
try:
- result['filelist_initial'] = gather_files(module.params['file_root'], exclude=module.params['exclude'], include=module.params['include'])
- result['filelist_typed'] = determine_mimetypes(result['filelist_initial'], module.params.get('mime_map'))
- result['filelist_s3'] = calculate_s3_path(result['filelist_typed'], module.params['key_prefix'])
+ result["filelist_initial"] = gather_files(
+ module.params["file_root"], exclude=module.params["exclude"], include=module.params["include"]
+ )
+ result["filelist_typed"] = determine_mimetypes(result["filelist_initial"], module.params.get("mime_map"))
+ result["filelist_s3"] = calculate_s3_path(result["filelist_typed"], module.params["key_prefix"])
try:
- result['filelist_local_etag'] = calculate_local_etag(result['filelist_s3'])
+ result["filelist_local_etag"] = calculate_local_etag(result["filelist_s3"])
except ValueError as e:
- if module.params['file_change_strategy'] == 'checksum':
- module.fail_json_aws(e, 'Unable to calculate checksum. If running in FIPS mode, you may need to use another file_change_strategy')
- result['filelist_local_etag'] = result['filelist_s3'].copy()
- result['filelist_actionable'] = filter_list(s3, module.params['bucket'], result['filelist_local_etag'], module.params['file_change_strategy'])
- result['uploads'] = upload_files(s3, module.params['bucket'], result['filelist_actionable'], module.params)
-
- if module.params['delete']:
- result['removed'] = remove_files(s3, result['filelist_local_etag'], module.params)
+ if module.params["file_change_strategy"] == "checksum":
+ module.fail_json_aws(
+ e,
+ "Unable to calculate checksum. If running in FIPS mode, you may need to use another file_change_strategy",
+ )
+ result["filelist_local_etag"] = result["filelist_s3"].copy()
+ result["filelist_actionable"] = filter_list(
+ s3, module.params["bucket"], result["filelist_local_etag"], module.params["file_change_strategy"]
+ )
+ result["uploads"] = upload_files(s3, module.params["bucket"], result["filelist_actionable"], module.params)
+
+ if module.params["delete"]:
+ result["removed"] = remove_files(s3, result["filelist_local_etag"], module.params)
# mark changed if we actually upload something.
- if result.get('uploads') or result.get('removed'):
- result['changed'] = True
+ if result.get("uploads") or result.get("removed"):
+ result["changed"] = True
# result.update(filelist=actionable_filelist)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Failed to push file")
@@ -534,5 +552,5 @@ def main():
module.exit_json(**result)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/s3_website.py b/ansible_collections/community/aws/plugins/modules/s3_website.py
index 81d3169cd..1c212d117 100644
--- a/ansible_collections/community/aws/plugins/modules/s3_website.py
+++ b/ansible_collections/community/aws/plugins/modules/s3_website.py
@@ -1,19 +1,18 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: s3_website
version_added: 1.0.0
short_description: Configure an s3 bucket as a website
description:
- - Configure an s3 bucket as a website
-author: Rob White (@wimnat)
+ - Configure an s3 bucket as a website
+author:
+ - Rob White (@wimnat)
options:
name:
description:
@@ -44,13 +43,12 @@ options:
type: str
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-'''
-
-EXAMPLES = '''
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide for details.
- name: Configure an s3 bucket to redirect all requests to example.com
@@ -70,10 +68,9 @@ EXAMPLES = '''
suffix: home.htm
error_key: errors/404.htm
state: present
+"""
-'''
-
-RETURN = '''
+RETURN = r"""
index_document:
description: index document
type: complex
@@ -157,7 +154,7 @@ routing_rules:
returned: when routing rule present
type: str
sample: documents/
-'''
+"""
import time
@@ -168,45 +165,43 @@ except ImportError:
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
-def _create_redirect_dict(url):
+def _create_redirect_dict(url):
redirect_dict = {}
- url_split = url.split(':')
+ url_split = url.split(":")
# Did we split anything?
if len(url_split) == 2:
- redirect_dict[u'Protocol'] = url_split[0]
- redirect_dict[u'HostName'] = url_split[1].replace('//', '')
+ redirect_dict["Protocol"] = url_split[0]
+ redirect_dict["HostName"] = url_split[1].replace("//", "")
elif len(url_split) == 1:
- redirect_dict[u'HostName'] = url_split[0]
+ redirect_dict["HostName"] = url_split[0]
else:
- raise ValueError('Redirect URL appears invalid')
+ raise ValueError("Redirect URL appears invalid")
return redirect_dict
def _create_website_configuration(suffix, error_key, redirect_all_requests):
-
website_configuration = {}
if error_key is not None:
- website_configuration['ErrorDocument'] = {'Key': error_key}
+ website_configuration["ErrorDocument"] = {"Key": error_key}
if suffix is not None:
- website_configuration['IndexDocument'] = {'Suffix': suffix}
+ website_configuration["IndexDocument"] = {"Suffix": suffix}
if redirect_all_requests is not None:
- website_configuration['RedirectAllRequestsTo'] = _create_redirect_dict(redirect_all_requests)
+ website_configuration["RedirectAllRequestsTo"] = _create_redirect_dict(redirect_all_requests)
return website_configuration
def enable_or_update_bucket_as_website(client_connection, resource_connection, module):
-
bucket_name = module.params.get("name")
redirect_all_requests = module.params.get("redirect_all_requests")
# If redirect_all_requests is set then don't use the default suffix that has been set
@@ -224,14 +219,19 @@ def enable_or_update_bucket_as_website(client_connection, resource_connection, m
try:
website_config = client_connection.get_bucket_website(Bucket=bucket_name)
- except is_boto3_error_code('NoSuchWebsiteConfiguration'):
+ except is_boto3_error_code("NoSuchWebsiteConfiguration"):
website_config = None
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
module.fail_json_aws(e, msg="Failed to get website configuration")
if website_config is None:
try:
- bucket_website.put(WebsiteConfiguration=_create_website_configuration(suffix, error_key, redirect_all_requests))
+ bucket_website.put(
+ WebsiteConfiguration=_create_website_configuration(suffix, error_key, redirect_all_requests)
+ )
changed = True
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Failed to set bucket website configuration")
@@ -239,18 +239,26 @@ def enable_or_update_bucket_as_website(client_connection, resource_connection, m
module.fail_json(msg=str(e))
else:
try:
- if (suffix is not None and website_config['IndexDocument']['Suffix'] != suffix) or \
- (error_key is not None and website_config['ErrorDocument']['Key'] != error_key) or \
- (redirect_all_requests is not None and website_config['RedirectAllRequestsTo'] != _create_redirect_dict(redirect_all_requests)):
-
+ if (
+ (suffix is not None and website_config["IndexDocument"]["Suffix"] != suffix)
+ or (error_key is not None and website_config["ErrorDocument"]["Key"] != error_key)
+ or (
+ redirect_all_requests is not None
+ and website_config["RedirectAllRequestsTo"] != _create_redirect_dict(redirect_all_requests)
+ )
+ ):
try:
- bucket_website.put(WebsiteConfiguration=_create_website_configuration(suffix, error_key, redirect_all_requests))
+ bucket_website.put(
+ WebsiteConfiguration=_create_website_configuration(suffix, error_key, redirect_all_requests)
+ )
changed = True
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Failed to update bucket website configuration")
except KeyError as e:
try:
- bucket_website.put(WebsiteConfiguration=_create_website_configuration(suffix, error_key, redirect_all_requests))
+ bucket_website.put(
+ WebsiteConfiguration=_create_website_configuration(suffix, error_key, redirect_all_requests)
+ )
changed = True
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Failed to update bucket website configuration")
@@ -265,15 +273,17 @@ def enable_or_update_bucket_as_website(client_connection, resource_connection, m
def disable_bucket_as_website(client_connection, module):
-
changed = False
bucket_name = module.params.get("name")
try:
client_connection.get_bucket_website(Bucket=bucket_name)
- except is_boto3_error_code('NoSuchWebsiteConfiguration'):
+ except is_boto3_error_code("NoSuchWebsiteConfiguration"):
module.exit_json(changed=changed)
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
module.fail_json_aws(e, msg="Failed to get bucket website")
try:
@@ -286,36 +296,35 @@ def disable_bucket_as_website(client_connection, module):
def main():
-
argument_spec = dict(
- name=dict(type='str', required=True),
- state=dict(type='str', required=True, choices=['present', 'absent']),
- suffix=dict(type='str', required=False, default='index.html'),
- error_key=dict(type='str', required=False, no_log=False),
- redirect_all_requests=dict(type='str', required=False),
+ name=dict(type="str", required=True),
+ state=dict(type="str", required=True, choices=["present", "absent"]),
+ suffix=dict(type="str", required=False, default="index.html"),
+ error_key=dict(type="str", required=False, no_log=False),
+ redirect_all_requests=dict(type="str", required=False),
)
module = AnsibleAWSModule(
argument_spec=argument_spec,
mutually_exclusive=[
- ['redirect_all_requests', 'suffix'],
- ['redirect_all_requests', 'error_key']
+ ["redirect_all_requests", "suffix"],
+ ["redirect_all_requests", "error_key"],
],
)
try:
- client_connection = module.client('s3')
- resource_connection = module.resource('s3')
+ client_connection = module.client("s3")
+ resource_connection = module.resource("s3")
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to connect to AWS')
+ module.fail_json_aws(e, msg="Failed to connect to AWS")
state = module.params.get("state")
- if state == 'present':
+ if state == "present":
enable_or_update_bucket_as_website(client_connection, resource_connection, module)
- elif state == 'absent':
+ elif state == "absent":
disable_bucket_as_website(client_connection, module)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/secretsmanager_secret.py b/ansible_collections/community/aws/plugins/modules/secretsmanager_secret.py
index 851746189..fb2ff8ebe 100644
--- a/ansible_collections/community/aws/plugins/modules/secretsmanager_secret.py
+++ b/ansible_collections/community/aws/plugins/modules/secretsmanager_secret.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
# Copyright: (c) 2018, REY Remi
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: secretsmanager_secret
version_added: 1.0.0
@@ -107,16 +105,16 @@ options:
- Specifies the number of days between automatic scheduled rotations of the secret.
default: 30
type: int
-extends_documentation_fragment:
- - amazon.aws.ec2
- - amazon.aws.aws
- - amazon.aws.boto3
- - amazon.aws.tags
notes:
- Support for I(purge_tags) was added in release 4.0.0.
-'''
+extends_documentation_fragment:
+ - amazon.aws.region.modules
+ - amazon.aws.common.modules
+ - amazon.aws.tags
+ - amazon.aws.boto3
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
- name: Add string to AWS Secrets Manager
community.aws.secretsmanager_secret:
name: 'test_secret_string'
@@ -146,9 +144,9 @@ EXAMPLES = r'''
secret_type: 'string'
secret: "{{ lookup('community.general.random_string', length=16, special=false) }}"
overwrite: false
-'''
+"""
-RETURN = r'''
+RETURN = r"""
secret:
description: The secret information
returned: always
@@ -212,27 +210,44 @@ secret:
returned: when the secret has tags
example: {'MyTagName': 'Some Value'}
version_added: 4.0.0
-'''
+"""
-from ansible.module_utils._text import to_bytes
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import snake_dict_to_camel_dict, camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict, compare_aws_tags, ansible_dict_to_boto3_tag_list
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import compare_policies
-from traceback import format_exc
import json
+from traceback import format_exc
try:
- from botocore.exceptions import BotoCoreError, ClientError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
except ImportError:
pass # handled by AnsibleAWSModule
+from ansible.module_utils._text import to_bytes
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+from ansible.module_utils.common.dict_transformations import snake_dict_to_camel_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.policy import compare_policies
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import ansible_dict_to_boto3_tag_list
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import compare_aws_tags
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
+
class Secret(object):
"""An object representation of the Secret described by the self.module args"""
+
def __init__(
- self, name, secret_type, secret, resource_policy=None, description="", kms_key_id=None,
- tags=None, lambda_arn=None, rotation_interval=None, replica_regions=None,
+ self,
+ name,
+ secret_type,
+ secret,
+ resource_policy=None,
+ description="",
+ kms_key_id=None,
+ tags=None,
+ lambda_arn=None,
+ rotation_interval=None,
+ replica_regions=None,
):
self.name = name
self.description = description
@@ -253,9 +268,7 @@ class Secret(object):
@property
def create_args(self):
- args = {
- "Name": self.name
- }
+ args = {"Name": self.name}
if self.description:
args["Description"] = self.description
if self.kms_key_id:
@@ -264,10 +277,9 @@ class Secret(object):
add_replica_regions = []
for replica in self.replica_regions:
if replica["kms_key_id"]:
- add_replica_regions.append({'Region': replica["region"],
- 'KmsKeyId': replica["kms_key_id"]})
+ add_replica_regions.append({"Region": replica["region"], "KmsKeyId": replica["kms_key_id"]})
else:
- add_replica_regions.append({'Region': replica["region"]})
+ add_replica_regions.append({"Region": replica["region"]})
args["AddReplicaRegions"] = add_replica_regions
if self.tags:
args["Tags"] = ansible_dict_to_boto3_tag_list(self.tags)
@@ -276,9 +288,7 @@ class Secret(object):
@property
def update_args(self):
- args = {
- "SecretId": self.name
- }
+ args = {"SecretId": self.name}
if self.description:
args["Description"] = self.description
if self.kms_key_id:
@@ -288,9 +298,7 @@ class Secret(object):
@property
def secret_resource_policy_args(self):
- args = {
- "SecretId": self.name
- }
+ args = {"SecretId": self.name}
if self.resource_policy:
args["ResourcePolicy"] = self.resource_policy
return args
@@ -310,7 +318,7 @@ class SecretsManagerInterface(object):
def __init__(self, module):
self.module = module
- self.client = self.module.client('secretsmanager')
+ self.client = self.module.client("secretsmanager")
def get_secret(self, name):
try:
@@ -358,7 +366,7 @@ class SecretsManagerInterface(object):
try:
json.loads(secret.secret_resource_policy_args.get("ResourcePolicy"))
except (TypeError, ValueError) as e:
- self.module.fail_json(msg="Failed to parse resource policy as JSON: %s" % (str(e)), exception=format_exc())
+ self.module.fail_json(msg=f"Failed to parse resource policy as JSON: {str(e)}", exception=format_exc())
try:
response = self.client.put_resource_policy(**secret.secret_resource_policy_args)
@@ -371,9 +379,7 @@ class SecretsManagerInterface(object):
self.module.exit_json(changed=True)
try:
replica_regions = []
- response = self.client.remove_regions_from_replication(
- SecretId=name,
- RemoveReplicaRegions=regions)
+ response = self.client.remove_regions_from_replication(SecretId=name, RemoveReplicaRegions=regions)
except (BotoCoreError, ClientError) as e:
self.module.fail_json_aws(e, msg="Failed to replicate secret")
return response
@@ -385,12 +391,10 @@ class SecretsManagerInterface(object):
replica_regions = []
for replica in regions:
if replica["kms_key_id"]:
- replica_regions.append({'Region': replica["region"], 'KmsKeyId': replica["kms_key_id"]})
+ replica_regions.append({"Region": replica["region"], "KmsKeyId": replica["kms_key_id"]})
else:
- replica_regions.append({'Region': replica["region"]})
- response = self.client.replicate_secret_to_regions(
- SecretId=name,
- AddReplicaRegions=replica_regions)
+ replica_regions.append({"Region": replica["region"]})
+ response = self.client.replicate_secret_to_regions(SecretId=name, AddReplicaRegions=replica_regions)
except (BotoCoreError, ClientError) as e:
self.module.fail_json_aws(e, msg="Failed to replicate secret")
return response
@@ -431,7 +435,8 @@ class SecretsManagerInterface(object):
response = self.client.rotate_secret(
SecretId=secret.name,
RotationLambdaARN=secret.rotation_lambda_arn,
- RotationRules=secret.rotation_rules)
+ RotationRules=secret.rotation_rules,
+ )
except (BotoCoreError, ClientError) as e:
self.module.fail_json_aws(e, msg="Failed to rotate secret secret")
else:
@@ -471,7 +476,7 @@ class SecretsManagerInterface(object):
if desired_secret.kms_key_id != current_secret.get("KmsKeyId"):
return False
current_secret_value = self.client.get_secret_value(SecretId=current_secret.get("Name"))
- if desired_secret.secret_type == 'SecretBinary':
+ if desired_secret.secret_type == "SecretBinary":
desired_value = to_bytes(desired_secret.secret)
else:
desired_value = desired_secret.secret
@@ -532,65 +537,69 @@ def compare_regions(desired_secret, current_secret):
def main():
replica_args = dict(
- region=dict(type='str', required=True),
- kms_key_id=dict(type='str', required=False),
+ region=dict(type="str", required=True),
+ kms_key_id=dict(type="str", required=False),
)
module = AnsibleAWSModule(
argument_spec={
- 'name': dict(required=True),
- 'state': dict(choices=['present', 'absent'], default='present'),
- 'overwrite': dict(type='bool', default=True),
- 'description': dict(default=""),
- 'replica': dict(type='list', elements='dict', options=replica_args),
- 'kms_key_id': dict(),
- 'secret_type': dict(choices=['binary', 'string'], default="string"),
- 'secret': dict(default="", no_log=True),
- 'json_secret': dict(type='json', no_log=True),
- 'resource_policy': dict(type='json', default=None),
- 'tags': dict(type='dict', default=None, aliases=['resource_tags']),
- 'purge_tags': dict(type='bool', default=True),
- 'rotation_lambda': dict(),
- 'rotation_interval': dict(type='int', default=30),
- 'recovery_window': dict(type='int', default=30),
+ "name": dict(required=True),
+ "state": dict(choices=["present", "absent"], default="present"),
+ "overwrite": dict(type="bool", default=True),
+ "description": dict(default=""),
+ "replica": dict(type="list", elements="dict", options=replica_args),
+ "kms_key_id": dict(),
+ "secret_type": dict(choices=["binary", "string"], default="string"),
+ "secret": dict(default="", no_log=True),
+ "json_secret": dict(type="json", no_log=True),
+ "resource_policy": dict(type="json", default=None),
+ "tags": dict(type="dict", default=None, aliases=["resource_tags"]),
+ "purge_tags": dict(type="bool", default=True),
+ "rotation_lambda": dict(),
+ "rotation_interval": dict(type="int", default=30),
+ "recovery_window": dict(type="int", default=30),
},
- mutually_exclusive=[['secret', 'json_secret']],
+ mutually_exclusive=[["secret", "json_secret"]],
supports_check_mode=True,
)
changed = False
- state = module.params.get('state')
+ state = module.params.get("state")
secrets_mgr = SecretsManagerInterface(module)
- recovery_window = module.params.get('recovery_window')
+ recovery_window = module.params.get("recovery_window")
secret = Secret(
- module.params.get('name'),
- module.params.get('secret_type'),
- module.params.get('secret') or module.params.get('json_secret'),
- description=module.params.get('description'),
- replica_regions=module.params.get('replica'),
- kms_key_id=module.params.get('kms_key_id'),
- resource_policy=module.params.get('resource_policy'),
- tags=module.params.get('tags'),
- lambda_arn=module.params.get('rotation_lambda'),
- rotation_interval=module.params.get('rotation_interval')
+ module.params.get("name"),
+ module.params.get("secret_type"),
+ module.params.get("secret") or module.params.get("json_secret"),
+ description=module.params.get("description"),
+ replica_regions=module.params.get("replica"),
+ kms_key_id=module.params.get("kms_key_id"),
+ resource_policy=module.params.get("resource_policy"),
+ tags=module.params.get("tags"),
+ lambda_arn=module.params.get("rotation_lambda"),
+ rotation_interval=module.params.get("rotation_interval"),
)
- purge_tags = module.params.get('purge_tags')
+ purge_tags = module.params.get("purge_tags")
current_secret = secrets_mgr.get_secret(secret.name)
- if state == 'absent':
+ if state == "absent":
if current_secret:
if not current_secret.get("DeletedDate"):
- result = camel_dict_to_snake_dict(secrets_mgr.delete_secret(secret.name, recovery_window=recovery_window))
+ result = camel_dict_to_snake_dict(
+ secrets_mgr.delete_secret(secret.name, recovery_window=recovery_window)
+ )
changed = True
elif current_secret.get("DeletedDate") and recovery_window == 0:
- result = camel_dict_to_snake_dict(secrets_mgr.delete_secret(secret.name, recovery_window=recovery_window))
+ result = camel_dict_to_snake_dict(
+ secrets_mgr.delete_secret(secret.name, recovery_window=recovery_window)
+ )
changed = True
else:
result = "secret already scheduled for deletion"
else:
result = "secret does not exist"
- if state == 'present':
+ if state == "present":
if current_secret is None:
result = secrets_mgr.create_secret(secret)
if secret.resource_policy and result.get("ARN"):
@@ -602,7 +611,7 @@ def main():
secrets_mgr.restore_secret(secret.name)
changed = True
if not secrets_mgr.secrets_match(secret, current_secret):
- overwrite = module.params.get('overwrite')
+ overwrite = module.params.get("overwrite")
if overwrite:
result = secrets_mgr.update_secret(secret)
changed = True
@@ -619,8 +628,8 @@ def main():
result = secrets_mgr.put_resource_policy(secret)
changed = True
- if module.params.get('tags') is not None:
- current_tags = boto3_tag_list_to_ansible_dict(current_secret.get('Tags', []))
+ if module.params.get("tags") is not None:
+ current_tags = boto3_tag_list_to_ansible_dict(current_secret.get("Tags", []))
tags_to_add, tags_to_remove = compare_aws_tags(current_tags, secret.tags, purge_tags)
if tags_to_add:
secrets_mgr.tag_secret(secret.name, ansible_dict_to_boto3_tag_list(tags_to_add))
@@ -638,12 +647,12 @@ def main():
changed = True
result = camel_dict_to_snake_dict(secrets_mgr.get_secret(secret.name))
- if result.get('tags', None) is not None:
- result['tags_dict'] = boto3_tag_list_to_ansible_dict(result.get('tags', []))
+ if result.get("tags", None) is not None:
+ result["tags_dict"] = boto3_tag_list_to_ansible_dict(result.get("tags", []))
result.pop("response_metadata")
module.exit_json(changed=changed, secret=result)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/ses_identity.py b/ansible_collections/community/aws/plugins/modules/ses_identity.py
index 997692df6..785519bd3 100644
--- a/ansible_collections/community/aws/plugins/modules/ses_identity.py
+++ b/ansible_collections/community/aws/plugins/modules/ses_identity.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: ses_identity
version_added: 1.0.0
@@ -86,14 +84,14 @@ options:
- Whether or not to enable feedback forwarding.
- This can only be false if both I(bounce_notifications) and I(complaint_notifications) specify SNS topics.
type: 'bool'
- default: True
+ default: true
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide for details.
- name: Ensure example@example.com email identity exists
@@ -117,7 +115,7 @@ EXAMPLES = '''
community.aws.sns_topic:
name: "complaints-topic"
state: present
- purge_subscriptions: False
+ purge_subscriptions: false
register: topic_info
- name: Deliver feedback to topic instead of owner email
@@ -126,11 +124,11 @@ EXAMPLES = '''
state: present
complaint_notifications:
topic: "{{ topic_info.sns_arn }}"
- include_headers: True
+ include_headers: true
bounce_notifications:
topic: "{{ topic_info.sns_arn }}"
- include_headers: False
- feedback_forwarding: False
+ include_headers: false
+ feedback_forwarding: false
# Create an SNS topic for delivery notifications and leave complaints
# Being forwarded to the identity owner email
@@ -138,7 +136,7 @@ EXAMPLES = '''
community.aws.sns_topic:
name: "delivery-notifications-topic"
state: present
- purge_subscriptions: False
+ purge_subscriptions: false
register: topic_info
- name: Delivery notifications to topic
@@ -147,9 +145,9 @@ EXAMPLES = '''
state: present
delivery_notifications:
topic: "{{ topic_info.sns_arn }}"
-'''
+"""
-RETURN = '''
+RETURN = r"""
identity:
description: The identity being modified.
returned: success
@@ -217,19 +215,22 @@ notification_attributes:
headers_in_delivery_notifications_enabled:
description: Whether or not headers are included in messages delivered to the delivery topic.
type: bool
-'''
-
-from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
+"""
import time
try:
- from botocore.exceptions import BotoCoreError, ClientError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
except ImportError:
pass # caught by AnsibleAWSModule
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
+
def get_verification_attributes(connection, module, identity, retries=0, retryDelay=10):
# Unpredictably get_identity_verification_attributes doesn't include the identity even when we've
@@ -241,8 +242,8 @@ def get_verification_attributes(connection, module, identity, retries=0, retryDe
try:
response = connection.get_identity_verification_attributes(Identities=[identity], aws_retry=True)
except (BotoCoreError, ClientError) as e:
- module.fail_json_aws(e, msg='Failed to retrieve identity verification attributes for {identity}'.format(identity=identity))
- identity_verification = response['VerificationAttributes']
+ module.fail_json_aws(e, msg=f"Failed to retrieve identity verification attributes for {identity}")
+ identity_verification = response["VerificationAttributes"]
if identity in identity_verification:
break
time.sleep(retryDelay)
@@ -262,8 +263,8 @@ def get_identity_notifications(connection, module, identity, retries=0, retryDel
try:
response = connection.get_identity_notification_attributes(Identities=[identity], aws_retry=True)
except (BotoCoreError, ClientError) as e:
- module.fail_json_aws(e, msg='Failed to retrieve identity notification attributes for {identity}'.format(identity=identity))
- notification_attributes = response['NotificationAttributes']
+ module.fail_json_aws(e, msg=f"Failed to retrieve identity notification attributes for {identity}")
+ notification_attributes = response["NotificationAttributes"]
# No clear AWS docs on when this happens, but it appears sometimes identities are not included in
# in the notification attributes when the identity is first registered. Suspect that this is caused by
@@ -279,7 +280,7 @@ def get_identity_notifications(connection, module, identity, retries=0, retryDel
# something has gone very wrong.
if len(notification_attributes) != 0:
module.fail_json(
- msg='Unexpected identity found in notification attributes, expected {0} but got {1!r}.'.format(
+ msg="Unexpected identity found in notification attributes, expected {0} but got {1!r}.".format(
identity,
notification_attributes.keys(),
)
@@ -291,46 +292,60 @@ def get_identity_notifications(connection, module, identity, retries=0, retryDel
def desired_topic(module, notification_type):
- arg_dict = module.params.get(notification_type.lower() + '_notifications')
+ arg_dict = module.params.get(notification_type.lower() + "_notifications")
if arg_dict:
- return arg_dict.get('topic', None)
+ return arg_dict.get("topic", None)
else:
return None
def update_notification_topic(connection, module, identity, identity_notifications, notification_type):
- topic_key = notification_type + 'Topic'
+ # Not passing the parameter should not cause any changes.
+ if module.params.get(f"{notification_type.lower()}_notifications") is None:
+ return False
+
+ topic_key = notification_type + "Topic"
if identity_notifications is None:
# If there is no configuration for notifications cannot be being sent to topics
# hence assume None as the current state.
- current = None
+ current_topic = None
elif topic_key in identity_notifications:
- current = identity_notifications[topic_key]
+ current_topic = identity_notifications[topic_key]
else:
# If there is information on the notifications setup but no information on the
# particular notification topic it's pretty safe to assume there's no topic for
# this notification. AWS API docs suggest this information will always be
# included but best to be defensive
- current = None
+ current_topic = None
- required = desired_topic(module, notification_type)
+ required_topic = desired_topic(module, notification_type)
- if current != required:
+ if current_topic != required_topic:
try:
if not module.check_mode:
- connection.set_identity_notification_topic(Identity=identity, NotificationType=notification_type, SnsTopic=required, aws_retry=True)
+ request_kwargs = {
+ "Identity": identity,
+ "NotificationType": notification_type,
+ "aws_retry": True,
+ }
+
+ # The topic has to be omitted from the request to disable the notification.
+ if required_topic is not None:
+ request_kwargs["SnsTopic"] = required_topic
+
+ connection.set_identity_notification_topic(**request_kwargs)
except (BotoCoreError, ClientError) as e:
- module.fail_json_aws(e, msg='Failed to set identity notification topic for {identity} {notification_type}'.format(
- identity=identity,
- notification_type=notification_type,
- ))
+ module.fail_json_aws(
+ e,
+ msg=f"Failed to set identity notification topic for {identity} {notification_type}",
+ )
return True
return False
def update_notification_topic_headers(connection, module, identity, identity_notifications, notification_type):
- arg_dict = module.params.get(notification_type.lower() + '_notifications')
- header_key = 'HeadersIn' + notification_type + 'NotificationsEnabled'
+ arg_dict = module.params.get(notification_type.lower() + "_notifications")
+ header_key = "HeadersIn" + notification_type + "NotificationsEnabled"
if identity_notifications is None:
# If there is no configuration for topic notifications, headers cannot be being
# forwarded, hence assume false.
@@ -343,21 +358,21 @@ def update_notification_topic_headers(connection, module, identity, identity_not
# headers are not included since most API consumers would interpret absence as false.
current = False
- if arg_dict is not None and 'include_headers' in arg_dict:
- required = arg_dict['include_headers']
+ if arg_dict is not None and "include_headers" in arg_dict:
+ required = arg_dict["include_headers"]
else:
required = False
if current != required:
try:
if not module.check_mode:
- connection.set_identity_headers_in_notifications_enabled(Identity=identity, NotificationType=notification_type, Enabled=required,
- aws_retry=True)
+ connection.set_identity_headers_in_notifications_enabled(
+ Identity=identity, NotificationType=notification_type, Enabled=required, aws_retry=True
+ )
except (BotoCoreError, ClientError) as e:
- module.fail_json_aws(e, msg='Failed to set identity headers in notification for {identity} {notification_type}'.format(
- identity=identity,
- notification_type=notification_type,
- ))
+ module.fail_json_aws(
+ e, msg=f"Failed to set identity headers in notification for {identity} {notification_type}"
+ )
return True
return False
@@ -368,51 +383,55 @@ def update_feedback_forwarding(connection, module, identity, identity_notificati
# are being handled by SNS topics. So in the absence of identity_notifications
# information existing feedback forwarding must be on.
current = True
- elif 'ForwardingEnabled' in identity_notifications:
- current = identity_notifications['ForwardingEnabled']
+ elif "ForwardingEnabled" in identity_notifications:
+ current = identity_notifications["ForwardingEnabled"]
else:
# If there is information on the notifications setup but no information on the
# forwarding state it's pretty safe to assume forwarding is off. AWS API docs
# suggest this information will always be included but best to be defensive
current = False
- required = module.params.get('feedback_forwarding')
+ required = module.params.get("feedback_forwarding")
if current != required:
try:
if not module.check_mode:
- connection.set_identity_feedback_forwarding_enabled(Identity=identity, ForwardingEnabled=required, aws_retry=True)
+ connection.set_identity_feedback_forwarding_enabled(
+ Identity=identity, ForwardingEnabled=required, aws_retry=True
+ )
except (BotoCoreError, ClientError) as e:
- module.fail_json_aws(e, msg='Failed to set identity feedback forwarding for {identity}'.format(identity=identity))
+ module.fail_json_aws(e, msg=f"Failed to set identity feedback forwarding for {identity}")
return True
return False
def create_mock_notifications_response(module):
resp = {
- "ForwardingEnabled": module.params.get('feedback_forwarding'),
+ "ForwardingEnabled": module.params.get("feedback_forwarding"),
}
- for notification_type in ('Bounce', 'Complaint', 'Delivery'):
- arg_dict = module.params.get(notification_type.lower() + '_notifications')
- if arg_dict is not None and 'topic' in arg_dict:
- resp[notification_type + 'Topic'] = arg_dict['topic']
-
- header_key = 'HeadersIn' + notification_type + 'NotificationsEnabled'
- if arg_dict is not None and 'include_headers' in arg_dict:
- resp[header_key] = arg_dict['include_headers']
+ for notification_type in ("Bounce", "Complaint", "Delivery"):
+ arg_dict = module.params.get(notification_type.lower() + "_notifications")
+ if arg_dict is not None and "topic" in arg_dict:
+ resp[notification_type + "Topic"] = arg_dict["topic"]
+
+ header_key = "HeadersIn" + notification_type + "NotificationsEnabled"
+ if arg_dict is not None and "include_headers" in arg_dict:
+ resp[header_key] = arg_dict["include_headers"]
else:
resp[header_key] = False
return resp
def update_identity_notifications(connection, module):
- identity = module.params.get('identity')
+ identity = module.params.get("identity")
changed = False
identity_notifications = get_identity_notifications(connection, module, identity)
- for notification_type in ('Bounce', 'Complaint', 'Delivery'):
+ for notification_type in ("Bounce", "Complaint", "Delivery"):
changed |= update_notification_topic(connection, module, identity, identity_notifications, notification_type)
- changed |= update_notification_topic_headers(connection, module, identity, identity_notifications, notification_type)
+ changed |= update_notification_topic_headers(
+ connection, module, identity, identity_notifications, notification_type
+ )
changed |= update_feedback_forwarding(connection, module, identity, identity_notifications)
@@ -425,25 +444,29 @@ def update_identity_notifications(connection, module):
def validate_params_for_identity_present(module):
- if module.params.get('feedback_forwarding') is False:
- if not (desired_topic(module, 'Bounce') and desired_topic(module, 'Complaint')):
- module.fail_json(msg="Invalid Parameter Value 'False' for 'feedback_forwarding'. AWS requires "
- "feedback forwarding to be enabled unless bounces and complaints are handled by SNS topics")
+ if module.params.get("feedback_forwarding") is False:
+ if not (desired_topic(module, "Bounce") and desired_topic(module, "Complaint")):
+ module.fail_json(
+ msg=(
+ "Invalid Parameter Value 'False' for 'feedback_forwarding'. AWS requires "
+ "feedback forwarding to be enabled unless bounces and complaints are handled by SNS topics"
+ )
+ )
def create_or_update_identity(connection, module, region, account_id):
- identity = module.params.get('identity')
+ identity = module.params.get("identity")
changed = False
verification_attributes = get_verification_attributes(connection, module, identity)
if verification_attributes is None:
try:
if not module.check_mode:
- if '@' in identity:
+ if "@" in identity:
connection.verify_email_identity(EmailAddress=identity, aws_retry=True)
else:
connection.verify_domain_identity(Domain=identity, aws_retry=True)
except (BotoCoreError, ClientError) as e:
- module.fail_json_aws(e, msg='Failed to verify identity {identity}'.format(identity=identity))
+ module.fail_json_aws(e, msg=f"Failed to verify identity {identity}")
if module.check_mode:
verification_attributes = {
"VerificationStatus": "Pending",
@@ -451,20 +474,22 @@ def create_or_update_identity(connection, module, region, account_id):
else:
verification_attributes = get_verification_attributes(connection, module, identity, retries=4)
changed = True
- elif verification_attributes['VerificationStatus'] not in ('Pending', 'Success'):
- module.fail_json(msg="Identity " + identity + " in bad status " + verification_attributes['VerificationStatus'],
- verification_attributes=camel_dict_to_snake_dict(verification_attributes))
+ elif verification_attributes["VerificationStatus"] not in ("Pending", "Success"):
+ module.fail_json(
+ msg="Identity " + identity + " in bad status " + verification_attributes["VerificationStatus"],
+ verification_attributes=camel_dict_to_snake_dict(verification_attributes),
+ )
if verification_attributes is None:
- module.fail_json(msg='Unable to load identity verification attributes after registering identity.')
+ module.fail_json(msg="Unable to load identity verification attributes after registering identity.")
notifications_changed, notification_attributes = update_identity_notifications(connection, module)
changed |= notifications_changed
if notification_attributes is None:
- module.fail_json(msg='Unable to load identity notification attributes.')
+ module.fail_json(msg="Unable to load identity notification attributes.")
- identity_arn = 'arn:aws:ses:' + region + ':' + account_id + ':identity/' + identity
+ identity_arn = "arn:aws:ses:" + region + ":" + account_id + ":identity/" + identity
module.exit_json(
changed=changed,
@@ -476,7 +501,7 @@ def create_or_update_identity(connection, module, region, account_id):
def destroy_identity(connection, module):
- identity = module.params.get('identity')
+ identity = module.params.get("identity")
changed = False
verification_attributes = get_verification_attributes(connection, module, identity)
if verification_attributes is not None:
@@ -484,7 +509,7 @@ def destroy_identity(connection, module):
if not module.check_mode:
connection.delete_identity(Identity=identity, aws_retry=True)
except (BotoCoreError, ClientError) as e:
- module.fail_json_aws(e, msg='Failed to delete identity {identity}'.format(identity=identity))
+ module.fail_json_aws(e, msg=f"Failed to delete identity {identity}")
changed = True
module.exit_json(
@@ -494,44 +519,50 @@ def destroy_identity(connection, module):
def get_account_id(module):
- sts = module.client('sts')
+ sts = module.client("sts")
try:
caller_identity = sts.get_caller_identity()
except (BotoCoreError, ClientError) as e:
- module.fail_json_aws(e, msg='Failed to retrieve caller identity')
- return caller_identity['Account']
+ module.fail_json_aws(e, msg="Failed to retrieve caller identity")
+ return caller_identity["Account"]
def main():
module = AnsibleAWSModule(
argument_spec={
- "identity": dict(required=True, type='str'),
- "state": dict(default='present', choices=['present', 'absent']),
- "bounce_notifications": dict(type='dict'),
- "complaint_notifications": dict(type='dict'),
- "delivery_notifications": dict(type='dict'),
- "feedback_forwarding": dict(default=True, type='bool'),
+ "identity": dict(required=True, type="str"),
+ "state": dict(default="present", choices=["present", "absent"]),
+ "bounce_notifications": dict(type="dict"),
+ "complaint_notifications": dict(type="dict"),
+ "delivery_notifications": dict(type="dict"),
+ "feedback_forwarding": dict(default=True, type="bool"),
},
supports_check_mode=True,
)
- for notification_type in ('bounce', 'complaint', 'delivery'):
- param_name = notification_type + '_notifications'
+ for notification_type in ("bounce", "complaint", "delivery"):
+ param_name = notification_type + "_notifications"
arg_dict = module.params.get(param_name)
if arg_dict:
- extra_keys = [x for x in arg_dict.keys() if x not in ('topic', 'include_headers')]
+ extra_keys = [x for x in arg_dict.keys() if x not in ("topic", "include_headers")]
if extra_keys:
- module.fail_json(msg='Unexpected keys ' + str(extra_keys) + ' in ' + param_name + ' valid keys are topic or include_headers')
+ module.fail_json(
+ msg="Unexpected keys "
+ + str(extra_keys)
+ + " in "
+ + param_name
+ + " valid keys are topic or include_headers"
+ )
# SES APIs seem to have a much lower throttling threshold than most of the rest of the AWS APIs.
# Docs say 1 call per second. This shouldn't actually be a big problem for normal usage, but
# the ansible build runs multiple instances of the test in parallel that's caused throttling
# failures so apply a jittered backoff to call SES calls.
- connection = module.client('ses', retry_decorator=AWSRetry.jittered_backoff())
+ connection = module.client("ses", retry_decorator=AWSRetry.jittered_backoff())
state = module.params.get("state")
- if state == 'present':
+ if state == "present":
region = module.region
account_id = get_account_id(module)
validate_params_for_identity_present(module)
@@ -540,5 +571,5 @@ def main():
destroy_identity(connection, module)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/ses_identity_policy.py b/ansible_collections/community/aws/plugins/modules/ses_identity_policy.py
index 16d9f1ded..9b7a3d6b6 100644
--- a/ansible_collections/community/aws/plugins/modules/ses_identity_policy.py
+++ b/ansible_collections/community/aws/plugins/modules/ses_identity_policy.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: ses_identity_policy
version_added: 1.0.0
@@ -41,12 +39,12 @@ options:
choices: [ 'present', 'absent' ]
type: str
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide for details.
- name: add sending authorization policy to domain identity
@@ -75,42 +73,45 @@ EXAMPLES = '''
identity: example.com
policy_name: ExamplePolicy
state: absent
-'''
+"""
-RETURN = '''
+RETURN = r"""
policies:
description: A list of all policies present on the identity after the operation.
returned: success
type: list
sample: [ExamplePolicy]
-'''
-
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import compare_policies, AWSRetry
+"""
import json
try:
- from botocore.exceptions import BotoCoreError, ClientError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
except ImportError:
pass # caught by AnsibleAWSModule
+from ansible_collections.amazon.aws.plugins.module_utils.policy import compare_policies
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
+
def get_identity_policy(connection, module, identity, policy_name):
try:
response = connection.get_identity_policies(Identity=identity, PolicyNames=[policy_name], aws_retry=True)
except (BotoCoreError, ClientError) as e:
- module.fail_json_aws(e, msg='Failed to retrieve identity policy {policy}'.format(policy=policy_name))
- policies = response['Policies']
+ module.fail_json_aws(e, msg=f"Failed to retrieve identity policy {policy_name}")
+ policies = response["Policies"]
if policy_name in policies:
return policies[policy_name]
return None
def create_or_update_identity_policy(connection, module):
- identity = module.params.get('identity')
- policy_name = module.params.get('policy_name')
- required_policy = module.params.get('policy')
+ identity = module.params.get("identity")
+ policy_name = module.params.get("policy_name")
+ required_policy = module.params.get("policy")
required_policy_dict = json.loads(required_policy)
changed = False
@@ -120,9 +121,11 @@ def create_or_update_identity_policy(connection, module):
changed = True
try:
if not module.check_mode:
- connection.put_identity_policy(Identity=identity, PolicyName=policy_name, Policy=required_policy, aws_retry=True)
+ connection.put_identity_policy(
+ Identity=identity, PolicyName=policy_name, Policy=required_policy, aws_retry=True
+ )
except (BotoCoreError, ClientError) as e:
- module.fail_json_aws(e, msg='Failed to put identity policy {policy}'.format(policy=policy_name))
+ module.fail_json_aws(e, msg=f"Failed to put identity policy {policy_name}")
# Load the list of applied policies to include in the response.
# In principle we should be able to just return the response, but given
@@ -133,9 +136,9 @@ def create_or_update_identity_policy(connection, module):
#
# As a nice side benefit this also means the return is correct in check mode
try:
- policies_present = connection.list_identity_policies(Identity=identity, aws_retry=True)['PolicyNames']
+ policies_present = connection.list_identity_policies(Identity=identity, aws_retry=True)["PolicyNames"]
except (BotoCoreError, ClientError) as e:
- module.fail_json_aws(e, msg='Failed to list identity policies')
+ module.fail_json_aws(e, msg="Failed to list identity policies")
if policy_name is not None and policy_name not in policies_present:
policies_present = list(policies_present)
policies_present.append(policy_name)
@@ -146,20 +149,20 @@ def create_or_update_identity_policy(connection, module):
def delete_identity_policy(connection, module):
- identity = module.params.get('identity')
- policy_name = module.params.get('policy_name')
+ identity = module.params.get("identity")
+ policy_name = module.params.get("policy_name")
changed = False
try:
- policies_present = connection.list_identity_policies(Identity=identity, aws_retry=True)['PolicyNames']
+ policies_present = connection.list_identity_policies(Identity=identity, aws_retry=True)["PolicyNames"]
except (BotoCoreError, ClientError) as e:
- module.fail_json_aws(e, msg='Failed to list identity policies')
+ module.fail_json_aws(e, msg="Failed to list identity policies")
if policy_name in policies_present:
try:
if not module.check_mode:
connection.delete_identity_policy(Identity=identity, PolicyName=policy_name, aws_retry=True)
except (BotoCoreError, ClientError) as e:
- module.fail_json_aws(e, msg='Failed to delete identity policy {policy}'.format(policy=policy_name))
+ module.fail_json_aws(e, msg=f"Failed to delete identity policy {policy_name}")
changed = True
policies_present = list(policies_present)
policies_present.remove(policy_name)
@@ -173,12 +176,12 @@ def delete_identity_policy(connection, module):
def main():
module = AnsibleAWSModule(
argument_spec={
- 'identity': dict(required=True, type='str'),
- 'state': dict(default='present', choices=['present', 'absent']),
- 'policy_name': dict(required=True, type='str'),
- 'policy': dict(type='json', default=None),
+ "identity": dict(required=True, type="str"),
+ "state": dict(default="present", choices=["present", "absent"]),
+ "policy_name": dict(required=True, type="str"),
+ "policy": dict(type="json", default=None),
},
- required_if=[['state', 'present', ['policy']]],
+ required_if=[["state", "present", ["policy"]]],
supports_check_mode=True,
)
@@ -186,15 +189,15 @@ def main():
# Docs say 1 call per second. This shouldn't actually be a big problem for normal usage, but
# the ansible build runs multiple instances of the test in parallel that's caused throttling
# failures so apply a jittered backoff to call SES calls.
- connection = module.client('ses', retry_decorator=AWSRetry.jittered_backoff())
+ connection = module.client("ses", retry_decorator=AWSRetry.jittered_backoff())
state = module.params.get("state")
- if state == 'present':
+ if state == "present":
create_or_update_identity_policy(connection, module)
else:
delete_identity_policy(connection, module)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/ses_rule_set.py b/ansible_collections/community/aws/plugins/modules/ses_rule_set.py
index b42ac8088..cf478c0f9 100644
--- a/ansible_collections/community/aws/plugins/modules/ses_rule_set.py
+++ b/ansible_collections/community/aws/plugins/modules/ses_rule_set.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright (c) 2017, Ben Tomasik <ben@tomasik.io>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: ses_rule_set
version_added: 1.0.0
@@ -46,15 +44,14 @@ options:
required: False
default: False
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
+
+EXAMPLES = r"""
+# Note: These examples do not set authentication details, see the AWS Guide for details.
-EXAMPLES = """
-# Note: None of these examples set aws_access_key, aws_secret_key, or region.
-# It is assumed that their matching environment variables are set.
----
- name: Create default rule set and activate it if not already
community.aws.ses_rule_set:
name: default-rule-set
@@ -84,7 +81,7 @@ EXAMPLES = """
force: true
"""
-RETURN = """
+RETURN = r"""
active:
description: if the SES rule set is active
returned: success if I(state) is C(present)
@@ -100,25 +97,29 @@ rule_sets:
}]
"""
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict, AWSRetry
-
try:
- from botocore.exceptions import BotoCoreError, ClientError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
except ImportError:
pass # handled by AnsibleAWSModule
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
+
def list_rule_sets(client, module):
try:
response = client.list_receipt_rule_sets(aws_retry=True)
except (BotoCoreError, ClientError) as e:
module.fail_json_aws(e, msg="Couldn't list rule sets.")
- return response['RuleSets']
+ return response["RuleSets"]
def rule_set_in(name, rule_sets):
- return any(s for s in rule_sets if s['Name'] == name)
+ return any(s for s in rule_sets if s["Name"] == name)
def ruleset_active(client, module, name):
@@ -126,8 +127,8 @@ def ruleset_active(client, module, name):
active_rule_set = client.describe_active_receipt_rule_set(aws_retry=True)
except (BotoCoreError, ClientError) as e:
module.fail_json_aws(e, msg="Couldn't get the active rule set.")
- if active_rule_set is not None and 'Metadata' in active_rule_set:
- return name == active_rule_set['Metadata']['Name']
+ if active_rule_set is not None and "Metadata" in active_rule_set:
+ return name == active_rule_set["Metadata"]["Name"]
else:
# Metadata was not set meaning there is no active rule set
return False
@@ -153,7 +154,7 @@ def update_active_rule_set(client, module, name, desired_active):
try:
client.set_active_receipt_rule_set(RuleSetName=name, aws_retry=True)
except (BotoCoreError, ClientError) as e:
- module.fail_json_aws(e, msg="Couldn't set active rule set to {0}.".format(name))
+ module.fail_json_aws(e, msg=f"Couldn't set active rule set to {name}.")
changed = True
active = True
elif not desired_active and active:
@@ -165,7 +166,7 @@ def update_active_rule_set(client, module, name, desired_active):
def create_or_update_rule_set(client, module):
- name = module.params.get('name')
+ name = module.params.get("name")
check_mode = module.check_mode
changed = False
@@ -175,14 +176,16 @@ def create_or_update_rule_set(client, module):
try:
client.create_receipt_rule_set(RuleSetName=name, aws_retry=True)
except (BotoCoreError, ClientError) as e:
- module.fail_json_aws(e, msg="Couldn't create rule set {0}.".format(name))
+ module.fail_json_aws(e, msg=f"Couldn't create rule set {name}.")
changed = True
rule_sets = list(rule_sets)
- rule_sets.append({
- 'Name': name,
- })
+ rule_sets.append(
+ {
+ "Name": name,
+ }
+ )
- (active_changed, active) = update_active_rule_set(client, module, name, module.params.get('active'))
+ (active_changed, active) = update_active_rule_set(client, module, name, module.params.get("active"))
changed |= active_changed
module.exit_json(
@@ -193,30 +196,33 @@ def create_or_update_rule_set(client, module):
def remove_rule_set(client, module):
- name = module.params.get('name')
+ name = module.params.get("name")
check_mode = module.check_mode
changed = False
rule_sets = list_rule_sets(client, module)
if rule_set_in(name, rule_sets):
active = ruleset_active(client, module, name)
- if active and not module.params.get('force'):
+ if active and not module.params.get("force"):
module.fail_json(
- msg="Couldn't delete rule set {0} because it is currently active. Set force=true to delete an active ruleset.".format(name),
+ msg=(
+ f"Couldn't delete rule set {name} because it is currently active. Set force=true to delete an"
+ " active ruleset."
+ ),
error={
"code": "CannotDelete",
- "message": "Cannot delete active rule set: {0}".format(name),
- }
+ "message": f"Cannot delete active rule set: {name}",
+ },
)
if not check_mode:
- if active and module.params.get('force'):
+ if active and module.params.get("force"):
deactivate_rule_set(client, module)
try:
client.delete_receipt_rule_set(RuleSetName=name, aws_retry=True)
except (BotoCoreError, ClientError) as e:
- module.fail_json_aws(e, msg="Couldn't delete rule set {0}.".format(name))
+ module.fail_json_aws(e, msg=f"Couldn't delete rule set {name}.")
changed = True
- rule_sets = [x for x in rule_sets if x['Name'] != name]
+ rule_sets = [x for x in rule_sets if x["Name"] != name]
module.exit_json(
changed=changed,
@@ -226,27 +232,27 @@ def remove_rule_set(client, module):
def main():
argument_spec = dict(
- name=dict(type='str', required=True),
- state=dict(type='str', default='present', choices=['present', 'absent']),
- active=dict(type='bool'),
- force=dict(type='bool', default=False),
+ name=dict(type="str", required=True),
+ state=dict(type="str", default="present", choices=["present", "absent"]),
+ active=dict(type="bool"),
+ force=dict(type="bool", default=False),
)
module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
- state = module.params.get('state')
+ state = module.params.get("state")
# SES APIs seem to have a much lower throttling threshold than most of the rest of the AWS APIs.
# Docs say 1 call per second. This shouldn't actually be a big problem for normal usage, but
# the ansible build runs multiple instances of the test in parallel that's caused throttling
# failures so apply a jittered backoff to call SES calls.
- client = module.client('ses', retry_decorator=AWSRetry.jittered_backoff())
+ client = module.client("ses", retry_decorator=AWSRetry.jittered_backoff())
- if state == 'absent':
+ if state == "absent":
remove_rule_set(client, module)
else:
create_or_update_rule_set(client, module)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/sns.py b/ansible_collections/community/aws/plugins/modules/sns.py
index f72bbfa49..62c440c1f 100644
--- a/ansible_collections/community/aws/plugins/modules/sns.py
+++ b/ansible_collections/community/aws/plugins/modules/sns.py
@@ -4,11 +4,7 @@
# Copyright: (c) 2014, Michael J. Schultz <mjschultz@gmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
module: sns
short_description: Send Amazon Simple Notification Service messages
version_added: 1.0.0
@@ -96,12 +92,12 @@ options:
version_added: 5.4.0
extends_documentation_fragment:
-- amazon.aws.ec2
-- amazon.aws.aws
-- amazon.aws.boto3
-'''
+ - amazon.aws.region.modules
+ - amazon.aws.common.modules
+ - amazon.aws.boto3
+"""
-EXAMPLES = """
+EXAMPLES = r"""
- name: Send default notification message via SNS
community.aws.sns:
msg: '{{ inventory_hostname }} has completed the play.'
@@ -139,7 +135,7 @@ EXAMPLES = """
delegate_to: localhost
"""
-RETURN = """
+RETURN = r"""
msg:
description: Human-readable diagnostic information
returned: always
@@ -159,32 +155,33 @@ sequence_number:
import json
try:
- from botocore.exceptions import BotoCoreError, ClientError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
except ImportError:
- pass # Handled by AnsibleAWSModule
+ pass # Handled by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
from ansible_collections.community.aws.plugins.module_utils.sns import topic_arn_lookup
def main():
protocols = [
- 'http',
- 'https',
- 'email',
- 'email_json',
- 'sms',
- 'sqs',
- 'application',
- 'lambda',
+ "http",
+ "https",
+ "email",
+ "email_json",
+ "sms",
+ "sqs",
+ "application",
+ "lambda",
]
argument_spec = dict(
- msg=dict(required=True, aliases=['default']),
+ msg=dict(required=True, aliases=["default"]),
subject=dict(),
topic=dict(required=True),
- message_attributes=dict(type='dict'),
- message_structure=dict(choices=['json', 'string'], default='json'),
+ message_attributes=dict(type="dict"),
+ message_structure=dict(choices=["json", "string"], default="json"),
message_group_id=dict(),
message_deduplication_id=dict(),
)
@@ -195,50 +192,48 @@ def main():
module = AnsibleAWSModule(argument_spec=argument_spec)
sns_kwargs = dict(
- Message=module.params['msg'],
- Subject=module.params['subject'],
- MessageStructure=module.params['message_structure'],
+ Message=module.params["msg"],
+ Subject=module.params["subject"],
+ MessageStructure=module.params["message_structure"],
)
- if module.params['message_attributes']:
- if module.params['message_structure'] != 'string':
+ if module.params["message_attributes"]:
+ if module.params["message_structure"] != "string":
module.fail_json(msg='message_attributes is only supported when the message_structure is "string".')
- sns_kwargs['MessageAttributes'] = module.params['message_attributes']
+ sns_kwargs["MessageAttributes"] = module.params["message_attributes"]
if module.params["message_group_id"]:
sns_kwargs["MessageGroupId"] = module.params["message_group_id"]
if module.params["message_deduplication_id"]:
sns_kwargs["MessageDeduplicationId"] = module.params["message_deduplication_id"]
- dict_msg = {
- 'default': sns_kwargs['Message']
- }
+ dict_msg = {"default": sns_kwargs["Message"]}
for p in protocols:
if module.params[p]:
- if sns_kwargs['MessageStructure'] != 'json':
+ if sns_kwargs["MessageStructure"] != "json":
module.fail_json(msg='Protocol-specific messages are only supported when message_structure is "json".')
- dict_msg[p.replace('_', '-')] = module.params[p]
+ dict_msg[p.replace("_", "-")] = module.params[p]
- client = module.client('sns')
+ client = module.client("sns")
- topic = module.params['topic']
- if ':' in topic:
+ topic = module.params["topic"]
+ if ":" in topic:
# Short names can't contain ':' so we'll assume this is the full ARN
- sns_kwargs['TopicArn'] = topic
+ sns_kwargs["TopicArn"] = topic
else:
- sns_kwargs['TopicArn'] = topic_arn_lookup(client, module, topic)
+ sns_kwargs["TopicArn"] = topic_arn_lookup(client, module, topic)
- if not sns_kwargs['TopicArn']:
- module.fail_json(msg='Could not find topic: {0}'.format(topic))
+ if not sns_kwargs["TopicArn"]:
+ module.fail_json(msg=f"Could not find topic: {topic}")
- if sns_kwargs['MessageStructure'] == 'json':
- sns_kwargs['Message'] = json.dumps(dict_msg)
+ if sns_kwargs["MessageStructure"] == "json":
+ sns_kwargs["Message"] = json.dumps(dict_msg)
try:
result = client.publish(**sns_kwargs)
except (BotoCoreError, ClientError) as e:
- module.fail_json_aws(e, msg='Failed to publish message')
+ module.fail_json_aws(e, msg="Failed to publish message")
sns_result = dict(msg="OK", message_id=result["MessageId"])
@@ -248,5 +243,5 @@ def main():
module.exit_json(**sns_result)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/sns_topic.py b/ansible_collections/community/aws/plugins/modules/sns_topic.py
index 3c05be004..0fe7fbe33 100644
--- a/ansible_collections/community/aws/plugins/modules/sns_topic.py
+++ b/ansible_collections/community/aws/plugins/modules/sns_topic.py
@@ -1,13 +1,10 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
module: sns_topic
short_description: Manages AWS SNS topics and subscriptions
version_added: 1.0.0
@@ -159,11 +156,11 @@ options:
notes:
- Support for I(tags) and I(purge_tags) was added in release 5.3.0.
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
- - amazon.aws.tags
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.tags.modules
- amazon.aws.boto3
-'''
+"""
EXAMPLES = r"""
@@ -182,7 +179,7 @@ EXAMPLES = r"""
numMinDelayRetries: 2
numNoDelayRetries: 2
backoffFunction: "linear"
- disableSubscriptionOverrides: True
+ disableSubscriptionOverrides: true
defaultThrottlePolicy:
maxReceivesPerSecond: 10
subscriptions:
@@ -216,7 +213,7 @@ EXAMPLES = r"""
state: absent
"""
-RETURN = r'''
+RETURN = r"""
sns_arn:
description: The ARN of the topic you are modifying
type: str
@@ -332,7 +329,7 @@ sns_topic:
returned: always
type: bool
sample: false
-'''
+"""
import json
@@ -341,38 +338,41 @@ try:
except ImportError:
pass # handled by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import scrub_none_parameters
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import compare_policies
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_tag_list
-from ansible_collections.community.aws.plugins.module_utils.sns import list_topics
-from ansible_collections.community.aws.plugins.module_utils.sns import topic_arn_lookup
-from ansible_collections.community.aws.plugins.module_utils.sns import compare_delivery_policies
-from ansible_collections.community.aws.plugins.module_utils.sns import list_topic_subscriptions
+from ansible_collections.amazon.aws.plugins.module_utils.arn import parse_aws_arn
+from ansible_collections.amazon.aws.plugins.module_utils.policy import compare_policies
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import ansible_dict_to_boto3_tag_list
+from ansible_collections.amazon.aws.plugins.module_utils.transformation import scrub_none_parameters
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
from ansible_collections.community.aws.plugins.module_utils.sns import canonicalize_endpoint
+from ansible_collections.community.aws.plugins.module_utils.sns import compare_delivery_policies
from ansible_collections.community.aws.plugins.module_utils.sns import get_info
+from ansible_collections.community.aws.plugins.module_utils.sns import list_topic_subscriptions
+from ansible_collections.community.aws.plugins.module_utils.sns import list_topics
+from ansible_collections.community.aws.plugins.module_utils.sns import topic_arn_lookup
from ansible_collections.community.aws.plugins.module_utils.sns import update_tags
class SnsTopicManager(object):
- """ Handles SNS Topic creation and destruction """
-
- def __init__(self,
- module,
- name,
- topic_type,
- state,
- display_name,
- policy,
- delivery_policy,
- subscriptions,
- purge_subscriptions,
- tags,
- purge_tags,
- content_based_deduplication,
- check_mode):
-
- self.connection = module.client('sns')
+ """Handles SNS Topic creation and destruction"""
+
+ def __init__(
+ self,
+ module,
+ name,
+ topic_type,
+ state,
+ display_name,
+ policy,
+ delivery_policy,
+ subscriptions,
+ purge_subscriptions,
+ tags,
+ purge_tags,
+ content_based_deduplication,
+ check_mode,
+ ):
+ self.connection = module.client("sns")
self.module = module
self.name = name
self.topic_type = topic_type
@@ -402,73 +402,80 @@ class SnsTopicManager(object):
# NOTE: Never set FifoTopic = False. Some regions (including GovCloud)
# don't support the attribute being set, even to False.
- if self.topic_type == 'fifo':
- attributes['FifoTopic'] = 'true'
- if not self.name.endswith('.fifo'):
- self.name = self.name + '.fifo'
+ if self.topic_type == "fifo":
+ attributes["FifoTopic"] = "true"
+ if not self.name.endswith(".fifo"):
+ self.name = self.name + ".fifo"
if self.tags:
tags = ansible_dict_to_boto3_tag_list(self.tags)
if not self.check_mode:
try:
- response = self.connection.create_topic(Name=self.name,
- Attributes=attributes,
- Tags=tags)
+ response = self.connection.create_topic(Name=self.name, Attributes=attributes, Tags=tags)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, msg="Couldn't create topic %s" % self.name)
- self.topic_arn = response['TopicArn']
+ self.module.fail_json_aws(e, msg=f"Couldn't create topic {self.name}")
+ self.topic_arn = response["TopicArn"]
return True
def _set_topic_attrs(self):
changed = False
try:
- topic_attributes = self.connection.get_topic_attributes(TopicArn=self.topic_arn)['Attributes']
+ topic_attributes = self.connection.get_topic_attributes(TopicArn=self.topic_arn)["Attributes"]
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, msg="Couldn't get topic attributes for topic %s" % self.topic_arn)
+ self.module.fail_json_aws(e, msg=f"Couldn't get topic attributes for topic {self.topic_arn}")
- if self.display_name and self.display_name != topic_attributes['DisplayName']:
+ if self.display_name and self.display_name != topic_attributes["DisplayName"]:
changed = True
- self.attributes_set.append('display_name')
+ self.attributes_set.append("display_name")
if not self.check_mode:
try:
- self.connection.set_topic_attributes(TopicArn=self.topic_arn, AttributeName='DisplayName',
- AttributeValue=self.display_name)
+ self.connection.set_topic_attributes(
+ TopicArn=self.topic_arn, AttributeName="DisplayName", AttributeValue=self.display_name
+ )
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
self.module.fail_json_aws(e, msg="Couldn't set display name")
- if self.policy and compare_policies(self.policy, json.loads(topic_attributes['Policy'])):
+ if self.policy and compare_policies(self.policy, json.loads(topic_attributes["Policy"])):
changed = True
- self.attributes_set.append('policy')
+ self.attributes_set.append("policy")
if not self.check_mode:
try:
- self.connection.set_topic_attributes(TopicArn=self.topic_arn, AttributeName='Policy',
- AttributeValue=json.dumps(self.policy))
+ self.connection.set_topic_attributes(
+ TopicArn=self.topic_arn, AttributeName="Policy", AttributeValue=json.dumps(self.policy)
+ )
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
self.module.fail_json_aws(e, msg="Couldn't set topic policy")
# Set content-based deduplication attribute. Ignore if topic_type is not fifo.
- if ("FifoTopic" in topic_attributes and topic_attributes["FifoTopic"] == "true") and \
- self.content_based_deduplication:
- enabled = "true" if self.content_based_deduplication in 'enabled' else "false"
- if enabled != topic_attributes['ContentBasedDeduplication']:
+ if (
+ "FifoTopic" in topic_attributes and topic_attributes["FifoTopic"] == "true"
+ ) and self.content_based_deduplication:
+ enabled = "true" if self.content_based_deduplication in "enabled" else "false"
+ if enabled != topic_attributes["ContentBasedDeduplication"]:
changed = True
- self.attributes_set.append('content_based_deduplication')
+ self.attributes_set.append("content_based_deduplication")
if not self.check_mode:
try:
- self.connection.set_topic_attributes(TopicArn=self.topic_arn, AttributeName='ContentBasedDeduplication',
- AttributeValue=enabled)
+ self.connection.set_topic_attributes(
+ TopicArn=self.topic_arn, AttributeName="ContentBasedDeduplication", AttributeValue=enabled
+ )
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
self.module.fail_json_aws(e, msg="Couldn't set content-based deduplication")
- if self.delivery_policy and ('DeliveryPolicy' not in topic_attributes or
- compare_delivery_policies(self.delivery_policy, json.loads(topic_attributes['DeliveryPolicy']))):
+ if self.delivery_policy and (
+ "DeliveryPolicy" not in topic_attributes
+ or compare_delivery_policies(self.delivery_policy, json.loads(topic_attributes["DeliveryPolicy"]))
+ ):
changed = True
- self.attributes_set.append('delivery_policy')
+ self.attributes_set.append("delivery_policy")
if not self.check_mode:
try:
- self.connection.set_topic_attributes(TopicArn=self.topic_arn, AttributeName='DeliveryPolicy',
- AttributeValue=json.dumps(self.delivery_policy))
+ self.connection.set_topic_attributes(
+ TopicArn=self.topic_arn,
+ AttributeName="DeliveryPolicy",
+ AttributeValue=json.dumps(self.delivery_policy),
+ )
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
self.module.fail_json_aws(e, msg="Couldn't set topic delivery policy")
return changed
@@ -476,20 +483,23 @@ class SnsTopicManager(object):
def _set_topic_subs(self):
changed = False
subscriptions_existing_list = set()
- desired_subscriptions = [(sub['protocol'],
- canonicalize_endpoint(sub['protocol'], sub['endpoint'])) for sub in
- self.subscriptions]
+ desired_subscriptions = [
+ (sub["protocol"], canonicalize_endpoint(sub["protocol"], sub["endpoint"])) for sub in self.subscriptions
+ ]
for sub in list_topic_subscriptions(self.connection, self.module, self.topic_arn):
- sub_key = (sub['Protocol'], sub['Endpoint'])
+ sub_key = (sub["Protocol"], sub["Endpoint"])
subscriptions_existing_list.add(sub_key)
- if (self.purge_subscriptions and sub_key not in desired_subscriptions and
- sub['SubscriptionArn'] not in ('PendingConfirmation', 'Deleted')):
+ if (
+ self.purge_subscriptions
+ and sub_key not in desired_subscriptions
+ and sub["SubscriptionArn"] not in ("PendingConfirmation", "Deleted")
+ ):
changed = True
self.subscriptions_deleted.append(sub_key)
if not self.check_mode:
try:
- self.connection.unsubscribe(SubscriptionArn=sub['SubscriptionArn'])
+ self.connection.unsubscribe(SubscriptionArn=sub["SubscriptionArn"])
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
self.module.fail_json_aws(e, msg="Couldn't unsubscribe from topic")
@@ -500,13 +510,13 @@ class SnsTopicManager(object):
try:
self.connection.subscribe(TopicArn=self.topic_arn, Protocol=protocol, Endpoint=endpoint)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, msg="Couldn't subscribe to topic %s" % self.topic_arn)
+ self.module.fail_json_aws(e, msg=f"Couldn't subscribe to topic {self.topic_arn}")
return changed
def _init_desired_subscription_attributes(self):
for sub in self.subscriptions:
- sub_key = (sub['protocol'], canonicalize_endpoint(sub['protocol'], sub['endpoint']))
- tmp_dict = sub.get('attributes', {})
+ sub_key = (sub["protocol"], canonicalize_endpoint(sub["protocol"], sub["endpoint"]))
+ tmp_dict = sub.get("attributes", {})
# aws sdk expects values to be strings
# https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sns.html#SNS.Client.set_subscription_attributes
for k, v in tmp_dict.items():
@@ -517,26 +527,28 @@ class SnsTopicManager(object):
def _set_topic_subs_attributes(self):
changed = False
for sub in list_topic_subscriptions(self.connection, self.module, self.topic_arn):
- sub_key = (sub['Protocol'], sub['Endpoint'])
- sub_arn = sub['SubscriptionArn']
+ sub_key = (sub["Protocol"], sub["Endpoint"])
+ sub_arn = sub["SubscriptionArn"]
if not self.desired_subscription_attributes.get(sub_key):
# subscription attributes aren't defined in desired, skipping
continue
try:
- sub_current_attributes = self.connection.get_subscription_attributes(SubscriptionArn=sub_arn)['Attributes']
+ sub_current_attributes = self.connection.get_subscription_attributes(SubscriptionArn=sub_arn)[
+ "Attributes"
+ ]
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, "Couldn't get subscription attributes for subscription %s" % sub_arn)
+ self.module.fail_json_aws(e, f"Couldn't get subscription attributes for subscription {sub_arn}")
- raw_message = self.desired_subscription_attributes[sub_key].get('RawMessageDelivery')
- if raw_message is not None and 'RawMessageDelivery' in sub_current_attributes:
- if sub_current_attributes['RawMessageDelivery'].lower() != raw_message.lower():
+ raw_message = self.desired_subscription_attributes[sub_key].get("RawMessageDelivery")
+ if raw_message is not None and "RawMessageDelivery" in sub_current_attributes:
+ if sub_current_attributes["RawMessageDelivery"].lower() != raw_message.lower():
changed = True
if not self.check_mode:
try:
- self.connection.set_subscription_attributes(SubscriptionArn=sub_arn,
- AttributeName='RawMessageDelivery',
- AttributeValue=raw_message)
+ self.connection.set_subscription_attributes(
+ SubscriptionArn=sub_arn, AttributeName="RawMessageDelivery", AttributeValue=raw_message
+ )
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
self.module.fail_json_aws(e, "Couldn't set RawMessageDelivery subscription attribute")
@@ -549,11 +561,11 @@ class SnsTopicManager(object):
if not subscriptions:
return False
for sub in subscriptions:
- if sub['SubscriptionArn'] not in ('PendingConfirmation', 'Deleted'):
- self.subscriptions_deleted.append(sub['SubscriptionArn'])
+ if sub["SubscriptionArn"] not in ("PendingConfirmation", "Deleted"):
+ self.subscriptions_deleted.append(sub["SubscriptionArn"])
if not self.check_mode:
try:
- self.connection.unsubscribe(SubscriptionArn=sub['SubscriptionArn'])
+ self.connection.unsubscribe(SubscriptionArn=sub["SubscriptionArn"])
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
self.module.fail_json_aws(e, msg="Couldn't unsubscribe from topic")
return True
@@ -564,11 +576,11 @@ class SnsTopicManager(object):
try:
self.connection.delete_topic(TopicArn=self.topic_arn)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, msg="Couldn't delete topic %s" % self.topic_arn)
+ self.module.fail_json_aws(e, msg=f"Couldn't delete topic {self.topic_arn}")
return True
def _name_is_arn(self):
- return self.name.startswith('arn:')
+ return bool(parse_aws_arn(self.name))
def ensure_ok(self):
changed = False
@@ -578,7 +590,9 @@ class SnsTopicManager(object):
if self.topic_arn in list_topics(self.connection, self.module):
changed |= self._set_topic_attrs()
elif self.display_name or self.policy or self.delivery_policy:
- self.module.fail_json(msg="Cannot set display name, policy or delivery policy for SNS topics not owned by this account")
+ self.module.fail_json(
+ msg="Cannot set display name, policy or delivery policy for SNS topics not owned by this account"
+ )
changed |= self._set_topic_subs()
self._init_desired_subscription_attributes()
if self.topic_arn in list_topics(self.connection, self.module):
@@ -595,7 +609,9 @@ class SnsTopicManager(object):
self.populate_topic_arn()
if self.topic_arn:
if self.topic_arn not in list_topics(self.connection, self.module):
- self.module.fail_json(msg="Cannot use state=absent with third party ARN. Use subscribers=[] to unsubscribe")
+ self.module.fail_json(
+ msg="Cannot use state=absent with third party ARN. Use subscribers=[] to unsubscribe"
+ )
changed = self._delete_subscriptions()
changed |= self._delete_topic()
return changed
@@ -606,7 +622,7 @@ class SnsTopicManager(object):
return
name = self.name
- if self.topic_type == 'fifo' and not name.endswith('.fifo'):
+ if self.topic_type == "fifo" and not name.endswith(".fifo"):
name += ".fifo"
self.topic_arn = topic_arn_lookup(self.connection, self.module, name)
@@ -615,83 +631,87 @@ def main():
# We're kinda stuck with CamelCase here, it would be nice to switch to
# snake_case, but we'd need to purge out the alias entries
http_retry_args = dict(
- minDelayTarget=dict(type='int', required=True),
- maxDelayTarget=dict(type='int', required=True),
- numRetries=dict(type='int', required=True),
- numMaxDelayRetries=dict(type='int', required=True),
- numMinDelayRetries=dict(type='int', required=True),
- numNoDelayRetries=dict(type='int', required=True),
- backoffFunction=dict(type='str', required=True, choices=['arithmetic', 'exponential', 'geometric', 'linear']),
+ minDelayTarget=dict(type="int", required=True),
+ maxDelayTarget=dict(type="int", required=True),
+ numRetries=dict(type="int", required=True),
+ numMaxDelayRetries=dict(type="int", required=True),
+ numMinDelayRetries=dict(type="int", required=True),
+ numNoDelayRetries=dict(type="int", required=True),
+ backoffFunction=dict(type="str", required=True, choices=["arithmetic", "exponential", "geometric", "linear"]),
)
http_delivery_args = dict(
- defaultHealthyRetryPolicy=dict(type='dict', required=True, options=http_retry_args),
- disableSubscriptionOverrides=dict(type='bool', required=False),
+ defaultHealthyRetryPolicy=dict(type="dict", required=True, options=http_retry_args),
+ disableSubscriptionOverrides=dict(type="bool", required=False),
defaultThrottlePolicy=dict(
- type='dict', required=False,
+ type="dict",
+ required=False,
options=dict(
- maxReceivesPerSecond=dict(type='int', required=True),
+ maxReceivesPerSecond=dict(type="int", required=True),
),
),
)
delivery_args = dict(
- http=dict(type='dict', required=False, options=http_delivery_args),
+ http=dict(type="dict", required=False, options=http_delivery_args),
)
argument_spec = dict(
name=dict(required=True),
- topic_type=dict(type='str', default='standard', choices=['standard', 'fifo']),
- state=dict(default='present', choices=['present', 'absent']),
+ topic_type=dict(type="str", default="standard", choices=["standard", "fifo"]),
+ state=dict(default="present", choices=["present", "absent"]),
display_name=dict(),
- policy=dict(type='dict'),
- delivery_policy=dict(type='dict', options=delivery_args),
- subscriptions=dict(default=[], type='list', elements='dict'),
- purge_subscriptions=dict(type='bool', default=True),
- tags=dict(type='dict', aliases=['resource_tags']),
- purge_tags=dict(type='bool', default=True),
- content_based_deduplication=dict(choices=['enabled', 'disabled'])
+ policy=dict(type="dict"),
+ delivery_policy=dict(type="dict", options=delivery_args),
+ subscriptions=dict(default=[], type="list", elements="dict"),
+ purge_subscriptions=dict(type="bool", default=True),
+ tags=dict(type="dict", aliases=["resource_tags"]),
+ purge_tags=dict(type="bool", default=True),
+ content_based_deduplication=dict(choices=["enabled", "disabled"]),
)
- module = AnsibleAWSModule(argument_spec=argument_spec,
- supports_check_mode=True)
-
- name = module.params.get('name')
- topic_type = module.params.get('topic_type')
- state = module.params.get('state')
- display_name = module.params.get('display_name')
- policy = module.params.get('policy')
- delivery_policy = module.params.get('delivery_policy')
- subscriptions = module.params.get('subscriptions')
- purge_subscriptions = module.params.get('purge_subscriptions')
- content_based_deduplication = module.params.get('content_based_deduplication')
+ module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
+
+ name = module.params.get("name")
+ topic_type = module.params.get("topic_type")
+ state = module.params.get("state")
+ display_name = module.params.get("display_name")
+ policy = module.params.get("policy")
+ delivery_policy = module.params.get("delivery_policy")
+ subscriptions = module.params.get("subscriptions")
+ purge_subscriptions = module.params.get("purge_subscriptions")
+ content_based_deduplication = module.params.get("content_based_deduplication")
check_mode = module.check_mode
- tags = module.params.get('tags')
- purge_tags = module.params.get('purge_tags')
-
- sns_topic = SnsTopicManager(module,
- name,
- topic_type,
- state,
- display_name,
- policy,
- delivery_policy,
- subscriptions,
- purge_subscriptions,
- tags,
- purge_tags,
- content_based_deduplication,
- check_mode)
-
- if state == 'present':
+ tags = module.params.get("tags")
+ purge_tags = module.params.get("purge_tags")
+
+ sns_topic = SnsTopicManager(
+ module,
+ name,
+ topic_type,
+ state,
+ display_name,
+ policy,
+ delivery_policy,
+ subscriptions,
+ purge_subscriptions,
+ tags,
+ purge_tags,
+ content_based_deduplication,
+ check_mode,
+ )
+
+ if state == "present":
changed = sns_topic.ensure_ok()
- elif state == 'absent':
+ elif state == "absent":
changed = sns_topic.ensure_gone()
- sns_facts = dict(changed=changed,
- sns_arn=sns_topic.topic_arn,
- sns_topic=get_info(sns_topic.connection, module, sns_topic.topic_arn))
+ sns_facts = dict(
+ changed=changed,
+ sns_arn=sns_topic.topic_arn,
+ sns_topic=get_info(sns_topic.connection, module, sns_topic.topic_arn),
+ )
module.exit_json(**sns_facts)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/sns_topic_info.py b/ansible_collections/community/aws/plugins/modules/sns_topic_info.py
index ca6dd1aab..8cd712804 100644
--- a/ansible_collections/community/aws/plugins/modules/sns_topic_info.py
+++ b/ansible_collections/community/aws/plugins/modules/sns_topic_info.py
@@ -1,13 +1,10 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
module: sns_topic_info
short_description: sns_topic_info module
version_added: 3.2.0
@@ -21,12 +18,12 @@ options:
required: false
type: str
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
+- amazon.aws.common.modules
+- amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
- name: list all the topics
community.aws.sns_topic_info:
register: sns_topic_list
@@ -35,9 +32,9 @@ EXAMPLES = r'''
community.aws.sns_topic_info:
topic_arn: "{{ sns_arn }}"
register: sns_topic_info
-'''
+"""
-RETURN = r'''
+RETURN = r"""
result:
description:
- The result contaning the details of one or all AWS SNS topics.
@@ -132,7 +129,7 @@ result:
description: The type of topic.
type: str
sample: "standard"
-'''
+"""
try:
@@ -140,26 +137,26 @@ try:
except ImportError:
pass # handled by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible_collections.community.aws.plugins.module_utils.sns import list_topics
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
from ansible_collections.community.aws.plugins.module_utils.sns import get_info
+from ansible_collections.community.aws.plugins.module_utils.sns import list_topics
def main():
argument_spec = dict(
- topic_arn=dict(type='str', required=False),
+ topic_arn=dict(type="str", required=False),
)
- module = AnsibleAWSModule(argument_spec=argument_spec,
- supports_check_mode=True)
+ module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
- topic_arn = module.params.get('topic_arn')
+ topic_arn = module.params.get("topic_arn")
try:
- connection = module.client('sns', retry_decorator=AWSRetry.jittered_backoff())
+ connection = module.client("sns", retry_decorator=AWSRetry.jittered_backoff())
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to connect to AWS.')
+ module.fail_json_aws(e, msg="Failed to connect to AWS.")
if topic_arn:
results = dict(sns_arn=topic_arn, sns_topic=get_info(connection, module, topic_arn))
@@ -169,5 +166,5 @@ def main():
module.exit_json(result=results)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/sqs_queue.py b/ansible_collections/community/aws/plugins/modules/sqs_queue.py
index 211e64b26..ad3ce68a7 100644
--- a/ansible_collections/community/aws/plugins/modules/sqs_queue.py
+++ b/ansible_collections/community/aws/plugins/modules/sqs_queue.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: sqs_queue
version_added: 1.0.0
@@ -104,13 +102,13 @@ options:
- Enables content-based deduplication. Used for FIFOs only.
- Defaults to C(false).
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
- - amazon.aws.boto3
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.tags
-'''
+ - amazon.aws.boto3
+"""
-RETURN = r'''
+RETURN = r"""
content_based_deduplication:
description: Enables content-based deduplication. Used for FIFOs only.
type: bool
@@ -186,9 +184,9 @@ tags:
type: dict
returned: always
sample: '{"Env": "prod"}'
-'''
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
- name: Create SQS queue with redrive policy
community.aws.sqs_queue:
name: my-queue
@@ -258,7 +256,7 @@ EXAMPLES = r'''
name: my-queue
region: ap-southeast-2
state: absent
-'''
+"""
import json
@@ -270,26 +268,27 @@ except ImportError:
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
from ansible.module_utils.common.dict_transformations import snake_dict_to_camel_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import compare_aws_tags
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import compare_policies
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.policy import compare_policies
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import compare_aws_tags
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def get_queue_name(module, is_fifo=False):
- name = module.params.get('name')
- if not is_fifo or name.endswith('.fifo'):
+ name = module.params.get("name")
+ if not is_fifo or name.endswith(".fifo"):
return name
- return name + '.fifo'
+ return name + ".fifo"
# NonExistentQueue is explicitly expected when a queue doesn't exist
@AWSRetry.jittered_backoff()
def get_queue_url(client, name):
try:
- return client.get_queue_url(QueueName=name)['QueueUrl']
- except is_boto3_error_code('AWS.SimpleQueueService.NonExistentQueue'):
+ return client.get_queue_url(QueueName=name)["QueueUrl"]
+ except is_boto3_error_code("AWS.SimpleQueueService.NonExistentQueue"):
return None
@@ -297,13 +296,13 @@ def describe_queue(client, queue_url):
"""
Description a queue in snake format
"""
- attributes = client.get_queue_attributes(QueueUrl=queue_url, AttributeNames=['All'], aws_retry=True)['Attributes']
+ attributes = client.get_queue_attributes(QueueUrl=queue_url, AttributeNames=["All"], aws_retry=True)["Attributes"]
description = dict(attributes)
- description.pop('Policy', None)
- description.pop('RedrivePolicy', None)
+ description.pop("Policy", None)
+ description.pop("RedrivePolicy", None)
description = camel_dict_to_snake_dict(description)
- description['policy'] = attributes.get('Policy', None)
- description['redrive_policy'] = attributes.get('RedrivePolicy', None)
+ description["policy"] = attributes.get("Policy", None)
+ description["redrive_policy"] = attributes.get("RedrivePolicy", None)
# Boto3 returns everything as a string, convert them back to integers/dicts if
# that's what we expected.
@@ -311,12 +310,12 @@ def describe_queue(client, queue_url):
if value is None:
continue
- if key in ['policy', 'redrive_policy']:
+ if key in ["policy", "redrive_policy"]:
policy = json.loads(value)
description[key] = policy
continue
- if key == 'content_based_deduplication':
+ if key == "content_based_deduplication":
try:
description[key] = bool(value)
except (TypeError, ValueError):
@@ -332,49 +331,48 @@ def describe_queue(client, queue_url):
def create_or_update_sqs_queue(client, module):
- is_fifo = (module.params.get('queue_type') == 'fifo')
- kms_master_key_id = module.params.get('kms_master_key_id')
+ is_fifo = module.params.get("queue_type") == "fifo"
+ kms_master_key_id = module.params.get("kms_master_key_id")
queue_name = get_queue_name(module, is_fifo)
result = dict(
name=queue_name,
- region=module.params.get('region'),
+ region=module.params.get("region"),
changed=False,
)
queue_url = get_queue_url(client, queue_name)
- result['queue_url'] = queue_url
+ result["queue_url"] = queue_url
# Create a dict() to hold attributes that will be passed to boto3
create_attributes = {}
if not queue_url:
if is_fifo:
- create_attributes['FifoQueue'] = "True"
+ create_attributes["FifoQueue"] = "True"
if kms_master_key_id:
- create_attributes['KmsMasterKeyId'] = kms_master_key_id
- result['changed'] = True
+ create_attributes["KmsMasterKeyId"] = kms_master_key_id
+ result["changed"] = True
if module.check_mode:
return result
- queue_url = client.create_queue(QueueName=queue_name, Attributes=create_attributes, aws_retry=True)['QueueUrl']
+ queue_url = client.create_queue(QueueName=queue_name, Attributes=create_attributes, aws_retry=True)["QueueUrl"]
changed, arn = update_sqs_queue(module, client, queue_url)
- result['changed'] |= changed
- result['queue_arn'] = arn
+ result["changed"] |= changed
+ result["queue_arn"] = arn
changed, tags = update_tags(client, queue_url, module)
- result['changed'] |= changed
- result['tags'] = tags
+ result["changed"] |= changed
+ result["tags"] = tags
result.update(describe_queue(client, queue_url))
COMPATABILITY_KEYS = dict(
- delay_seconds='delivery_delay',
- receive_message_wait_time_seconds='receive_message_wait_time',
- visibility_timeout='default_visibility_timeout',
- kms_data_key_reuse_period_seconds='kms_data_key_reuse_period',
+ delay_seconds="delivery_delay",
+ receive_message_wait_time_seconds="receive_message_wait_time",
+ visibility_timeout="default_visibility_timeout",
+ kms_data_key_reuse_period_seconds="kms_data_key_reuse_period",
)
for key in list(result.keys()):
-
# The return values changed between boto and boto3, add the old keys too
# for backwards compatibility
return_name = COMPATABILITY_KEYS.get(key)
@@ -387,30 +385,32 @@ def create_or_update_sqs_queue(client, module):
def update_sqs_queue(module, client, queue_url):
check_mode = module.check_mode
changed = False
- existing_attributes = client.get_queue_attributes(QueueUrl=queue_url, AttributeNames=['All'], aws_retry=True)['Attributes']
+ existing_attributes = client.get_queue_attributes(QueueUrl=queue_url, AttributeNames=["All"], aws_retry=True)[
+ "Attributes"
+ ]
new_attributes = snake_dict_to_camel_dict(module.params, capitalize_first=True)
attributes_to_set = dict()
# Boto3 SQS deals with policies as strings, we want to deal with them as
# dicts
- if module.params.get('policy') is not None:
- policy = module.params.get('policy')
- current_value = existing_attributes.get('Policy', '{}')
+ if module.params.get("policy") is not None:
+ policy = module.params.get("policy")
+ current_value = existing_attributes.get("Policy", "{}")
current_policy = json.loads(current_value)
if compare_policies(current_policy, policy):
- attributes_to_set['Policy'] = json.dumps(policy)
+ attributes_to_set["Policy"] = json.dumps(policy)
changed = True
- if module.params.get('redrive_policy') is not None:
- policy = module.params.get('redrive_policy')
- current_value = existing_attributes.get('RedrivePolicy', '{}')
+ if module.params.get("redrive_policy") is not None:
+ policy = module.params.get("redrive_policy")
+ current_value = existing_attributes.get("RedrivePolicy", "{}")
current_policy = json.loads(current_value)
if compare_policies(current_policy, policy):
- attributes_to_set['RedrivePolicy'] = json.dumps(policy)
+ attributes_to_set["RedrivePolicy"] = json.dumps(policy)
changed = True
for attribute, value in existing_attributes.items():
# We handle these as a special case because they're IAM policies
- if attribute in ['Policy', 'RedrivePolicy']:
+ if attribute in ["Policy", "RedrivePolicy"]:
continue
if attribute not in new_attributes.keys():
@@ -435,23 +435,19 @@ def update_sqs_queue(module, client, queue_url):
if changed and not check_mode:
client.set_queue_attributes(QueueUrl=queue_url, Attributes=attributes_to_set, aws_retry=True)
- return changed, existing_attributes.get('queue_arn')
+ return changed, existing_attributes.get("queue_arn")
def delete_sqs_queue(client, module):
- is_fifo = (module.params.get('queue_type') == 'fifo')
+ is_fifo = module.params.get("queue_type") == "fifo"
queue_name = get_queue_name(module, is_fifo)
- result = dict(
- name=queue_name,
- region=module.params.get('region'),
- changed=False
- )
+ result = dict(name=queue_name, region=module.params.get("region"), changed=False)
queue_url = get_queue_url(client, queue_name)
if not queue_url:
return result
- result['changed'] = bool(queue_url)
+ result["changed"] = bool(queue_url)
if not module.check_mode:
AWSRetry.jittered_backoff()(client.delete_queue)(QueueUrl=queue_url)
@@ -459,13 +455,13 @@ def delete_sqs_queue(client, module):
def update_tags(client, queue_url, module):
- new_tags = module.params.get('tags')
- purge_tags = module.params.get('purge_tags')
+ new_tags = module.params.get("tags")
+ purge_tags = module.params.get("purge_tags")
if new_tags is None:
return False, {}
try:
- existing_tags = client.list_queue_tags(QueueUrl=queue_url, aws_retry=True)['Tags']
+ existing_tags = client.list_queue_tags(QueueUrl=queue_url, aws_retry=True)["Tags"]
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError, KeyError) as e:
existing_tags = {}
@@ -476,7 +472,7 @@ def update_tags(client, queue_url, module):
client.untag_queue(QueueUrl=queue_url, TagKeys=tags_to_remove, aws_retry=True)
if tags_to_add:
client.tag_queue(QueueUrl=queue_url, Tags=tags_to_add)
- existing_tags = client.list_queue_tags(QueueUrl=queue_url, aws_retry=True).get('Tags', {})
+ existing_tags = client.list_queue_tags(QueueUrl=queue_url, aws_retry=True).get("Tags", {})
else:
existing_tags = new_tags
@@ -485,41 +481,40 @@ def update_tags(client, queue_url, module):
def main():
-
argument_spec = dict(
- state=dict(type='str', default='present', choices=['present', 'absent']),
- name=dict(type='str', required=True),
- queue_type=dict(type='str', default='standard', choices=['standard', 'fifo']),
- delay_seconds=dict(type='int', aliases=['delivery_delay']),
- maximum_message_size=dict(type='int'),
- message_retention_period=dict(type='int'),
- policy=dict(type='dict'),
- receive_message_wait_time_seconds=dict(type='int', aliases=['receive_message_wait_time']),
- redrive_policy=dict(type='dict'),
- visibility_timeout=dict(type='int', aliases=['default_visibility_timeout']),
- kms_master_key_id=dict(type='str'),
- fifo_throughput_limit=dict(type='str', choices=["perQueue", "perMessageGroupId"]),
- deduplication_scope=dict(type='str', choices=['queue', 'messageGroup']),
- kms_data_key_reuse_period_seconds=dict(type='int', aliases=['kms_data_key_reuse_period'], no_log=False),
- content_based_deduplication=dict(type='bool'),
- tags=dict(type='dict', aliases=['resource_tags']),
- purge_tags=dict(type='bool', default=True),
+ state=dict(type="str", default="present", choices=["present", "absent"]),
+ name=dict(type="str", required=True),
+ queue_type=dict(type="str", default="standard", choices=["standard", "fifo"]),
+ delay_seconds=dict(type="int", aliases=["delivery_delay"]),
+ maximum_message_size=dict(type="int"),
+ message_retention_period=dict(type="int"),
+ policy=dict(type="dict"),
+ receive_message_wait_time_seconds=dict(type="int", aliases=["receive_message_wait_time"]),
+ redrive_policy=dict(type="dict"),
+ visibility_timeout=dict(type="int", aliases=["default_visibility_timeout"]),
+ kms_master_key_id=dict(type="str"),
+ fifo_throughput_limit=dict(type="str", choices=["perQueue", "perMessageGroupId"]),
+ deduplication_scope=dict(type="str", choices=["queue", "messageGroup"]),
+ kms_data_key_reuse_period_seconds=dict(type="int", aliases=["kms_data_key_reuse_period"], no_log=False),
+ content_based_deduplication=dict(type="bool"),
+ tags=dict(type="dict", aliases=["resource_tags"]),
+ purge_tags=dict(type="bool", default=True),
)
module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
- state = module.params.get('state')
- retry_decorator = AWSRetry.jittered_backoff(catch_extra_error_codes=['AWS.SimpleQueueService.NonExistentQueue'])
+ state = module.params.get("state")
+ retry_decorator = AWSRetry.jittered_backoff(catch_extra_error_codes=["AWS.SimpleQueueService.NonExistentQueue"])
try:
- client = module.client('sqs', retry_decorator=retry_decorator)
- if state == 'present':
+ client = module.client("sqs", retry_decorator=retry_decorator)
+ if state == "present":
result = create_or_update_sqs_queue(client, module)
- elif state == 'absent':
+ elif state == "absent":
result = delete_sqs_queue(client, module)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to control sqs queue')
+ module.fail_json_aws(e, msg="Failed to control sqs queue")
else:
module.exit_json(**result)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/ssm_inventory_info.py b/ansible_collections/community/aws/plugins/modules/ssm_inventory_info.py
new file mode 100644
index 000000000..c5b849097
--- /dev/null
+++ b/ansible_collections/community/aws/plugins/modules/ssm_inventory_info.py
@@ -0,0 +1,114 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: Contributors to the Ansible project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = """
+module: ssm_inventory_info
+version_added: 6.0.0
+short_description: Get SSM inventory information for EC2 instance
+
+description:
+ - Gather SSM inventory for EC2 instance configured with SSM.
+
+author: 'Aubin Bikouo (@abikouo)'
+
+options:
+ instance_id:
+ description:
+ - EC2 instance id.
+ required: true
+ type: str
+
+extends_documentation_fragment:
+- amazon.aws.common.modules
+- amazon.aws.region.modules
+- amazon.aws.boto3
+"""
+
+EXAMPLES = """
+- name: Retrieve SSM inventory info for instance id 'i-012345678902'
+ community.aws.ssm_inventory_info:
+ instance_id: 'i-012345678902'
+"""
+
+
+RETURN = """
+ssm_inventory:
+ returned: on success
+ description: >
+ SSM inventory information.
+ type: dict
+ sample: {
+ 'agent_type': 'amazon-ssm-agent',
+ 'agent_version': '3.2.582.0',
+ 'computer_name': 'ip-172-31-44-166.ec2.internal',
+ 'instance_id': 'i-039eb9b1f55934ab6',
+ 'instance_status': 'Active',
+ 'ip_address': '172.31.44.166',
+ 'platform_name': 'Fedora Linux',
+ 'platform_type': 'Linux',
+ 'platform_version': '37',
+ 'resource_type': 'EC2Instance'
+ }
+"""
+
+
+try:
+ import botocore
+except ImportError:
+ pass # Handled by AnsibleAWSModule
+
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
+
+
+class SsmInventoryInfoFailure(Exception):
+ def __init__(self, exc, msg):
+ self.exc = exc
+ self.msg = msg
+ super().__init__(self)
+
+
+def get_ssm_inventory(connection, filters):
+ try:
+ return connection.get_inventory(Filters=filters)
+ except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
+ raise SsmInventoryInfoFailure(exc=e, msg="get_ssm_inventory() failed.")
+
+
+def execute_module(module, connection):
+ instance_id = module.params.get("instance_id")
+ try:
+ filters = [{"Key": "AWS:InstanceInformation.InstanceId", "Values": [instance_id]}]
+
+ response = get_ssm_inventory(connection, filters)
+ entities = response.get("Entities", [])
+ ssm_inventory = {}
+ if entities:
+ content = entities[0].get("Data", {}).get("AWS:InstanceInformation", {}).get("Content", [])
+ if content:
+ ssm_inventory = camel_dict_to_snake_dict(content[0])
+ module.exit_json(changed=False, ssm_inventory=ssm_inventory)
+ except SsmInventoryInfoFailure as e:
+ module.fail_json_aws(exception=e.exc, msg=e.msg)
+
+
+def main():
+ argument_spec = dict(
+ instance_id=dict(required=True, type="str"),
+ )
+
+ module = AnsibleAWSModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
+
+ connection = module.client("ssm")
+ execute_module(module, connection)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/aws/plugins/modules/ssm_parameter.py b/ansible_collections/community/aws/plugins/modules/ssm_parameter.py
index c435305c2..aefafca00 100644
--- a/ansible_collections/community/aws/plugins/modules/ssm_parameter.py
+++ b/ansible_collections/community/aws/plugins/modules/ssm_parameter.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: (c) 2017, Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: ssm_parameter
version_added: 1.0.0
@@ -86,18 +84,17 @@ author:
- "Bill Wang (@ozbillwang) <ozbillwang@gmail.com>"
- "Michael De La Rue (@mikedlr)"
-extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
- - amazon.aws.boto3
- - amazon.aws.tags
-
notes:
- Support for I(tags) and I(purge_tags) was added in release 5.3.0.
-'''
+extends_documentation_fragment:
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.tags
+ - amazon.aws.boto3
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
- name: Create or update key/value pair in AWS SSM parameter store
community.aws.ssm_parameter:
name: "Hello"
@@ -165,9 +162,9 @@ EXAMPLES = '''
community.aws.ssm_parameter:
name: "Hello"
tags: {}
-'''
+"""
-RETURN = '''
+RETURN = r"""
parameter_metadata:
type: dict
description:
@@ -242,30 +239,32 @@ parameter_metadata:
returned: when the parameter has tags
example: {'MyTagName': 'Some Value'}
version_added: 5.3.0
-'''
+"""
import time
try:
import botocore
- from botocore.exceptions import BotoCoreError, ClientError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
except ImportError:
pass # Handled by AnsibleAWSModule
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible_collections.community.aws.plugins.module_utils.base import BaseWaiterFactory
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
from ansible_collections.amazon.aws.plugins.module_utils.tagging import ansible_dict_to_boto3_tag_list
from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
from ansible_collections.amazon.aws.plugins.module_utils.tagging import compare_aws_tags
+from ansible_collections.community.aws.plugins.module_utils.base import BaseWaiterFactory
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
+
class ParameterWaiterFactory(BaseWaiterFactory):
def __init__(self, module):
- client = module.client('ssm')
+ client = module.client("ssm")
super(ParameterWaiterFactory, self).__init__(module, client)
@property
@@ -273,22 +272,24 @@ class ParameterWaiterFactory(BaseWaiterFactory):
data = super(ParameterWaiterFactory, self)._waiter_model_data
ssm_data = dict(
parameter_exists=dict(
- operation='DescribeParameters',
- delay=1, maxAttempts=20,
+ operation="DescribeParameters",
+ delay=1,
+ maxAttempts=20,
acceptors=[
- dict(state='retry', matcher='error', expected='ParameterNotFound'),
- dict(state='retry', matcher='path', expected=True, argument='length(Parameters[].Name) == `0`'),
- dict(state='success', matcher='path', expected=True, argument='length(Parameters[].Name) > `0`'),
- ]
+ dict(state="retry", matcher="error", expected="ParameterNotFound"),
+ dict(state="retry", matcher="path", expected=True, argument="length(Parameters[].Name) == `0`"),
+ dict(state="success", matcher="path", expected=True, argument="length(Parameters[].Name) > `0`"),
+ ],
),
parameter_deleted=dict(
- operation='DescribeParameters',
- delay=1, maxAttempts=20,
+ operation="DescribeParameters",
+ delay=1,
+ maxAttempts=20,
acceptors=[
- dict(state='retry', matcher='path', expected=True, argument='length(Parameters[].Name) > `0`'),
- dict(state='success', matcher='path', expected=True, argument='length(Parameters[]) == `0`'),
- dict(state='success', matcher='error', expected='ParameterNotFound'),
- ]
+ dict(state="retry", matcher="path", expected=True, argument="length(Parameters[].Name) > `0`"),
+ dict(state="success", matcher="path", expected=True, argument="length(Parameters[]) == `0`"),
+ dict(state="success", matcher="error", expected="ParameterNotFound"),
+ ],
),
)
data.update(ssm_data)
@@ -299,10 +300,10 @@ def _wait_exists(client, module, name):
if module.check_mode:
return
wf = ParameterWaiterFactory(module)
- waiter = wf.get_waiter('parameter_exists')
+ waiter = wf.get_waiter("parameter_exists")
try:
waiter.wait(
- ParameterFilters=[{'Key': 'Name', "Values": [name]}],
+ ParameterFilters=[{"Key": "Name", "Values": [name]}],
)
except botocore.exceptions.WaiterError:
module.warn("Timeout waiting for parameter to exist")
@@ -317,7 +318,7 @@ def _wait_updated(client, module, name, version):
for x in range(1, 10):
try:
parameter = describe_parameter(client, module, ParameterFilters=[{"Key": "Name", "Values": [name]}])
- if parameter.get('Version', 0) > version:
+ if parameter.get("Version", 0) > version:
return
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Failed to describe parameter while waiting for update")
@@ -328,10 +329,10 @@ def _wait_deleted(client, module, name):
if module.check_mode:
return
wf = ParameterWaiterFactory(module)
- waiter = wf.get_waiter('parameter_deleted')
+ waiter = wf.get_waiter("parameter_deleted")
try:
waiter.wait(
- ParameterFilters=[{'Key': 'Name', "Values": [name]}],
+ ParameterFilters=[{"Key": "Name", "Values": [name]}],
)
except botocore.exceptions.WaiterError:
module.warn("Timeout waiting for parameter to exist")
@@ -341,24 +342,27 @@ def _wait_deleted(client, module, name):
def tag_parameter(client, module, parameter_name, tags):
try:
- return client.add_tags_to_resource(aws_retry=True, ResourceType='Parameter',
- ResourceId=parameter_name, Tags=tags)
+ return client.add_tags_to_resource(
+ aws_retry=True, ResourceType="Parameter", ResourceId=parameter_name, Tags=tags
+ )
except (BotoCoreError, ClientError) as e:
module.fail_json_aws(e, msg="Failed to add tag(s) to parameter")
def untag_parameter(client, module, parameter_name, tag_keys):
try:
- return client.remove_tags_from_resource(aws_retry=True, ResourceType='Parameter',
- ResourceId=parameter_name, TagKeys=tag_keys)
+ return client.remove_tags_from_resource(
+ aws_retry=True, ResourceType="Parameter", ResourceId=parameter_name, TagKeys=tag_keys
+ )
except (BotoCoreError, ClientError) as e:
module.fail_json_aws(e, msg="Failed to remove tag(s) from parameter")
def get_parameter_tags(client, module, parameter_name):
try:
- tags = client.list_tags_for_resource(aws_retry=True, ResourceType='Parameter',
- ResourceId=parameter_name)['TagList']
+ tags = client.list_tags_for_resource(aws_retry=True, ResourceType="Parameter", ResourceId=parameter_name)[
+ "TagList"
+ ]
tags_dict = boto3_tag_list_to_ansible_dict(tags)
return tags_dict
except (BotoCoreError, ClientError) as e:
@@ -373,14 +377,12 @@ def update_parameter_tags(client, module, parameter_name, supplied_tags):
return False, response
current_tags = get_parameter_tags(client, module, parameter_name)
- tags_to_add, tags_to_remove = compare_aws_tags(current_tags, supplied_tags,
- module.params.get('purge_tags'))
+ tags_to_add, tags_to_remove = compare_aws_tags(current_tags, supplied_tags, module.params.get("purge_tags"))
if tags_to_add:
if module.check_mode:
return True, response
- response = tag_parameter(client, module, parameter_name,
- ansible_dict_to_boto3_tag_list(tags_to_add))
+ response = tag_parameter(client, module, parameter_name, ansible_dict_to_boto3_tag_list(tags_to_add))
changed = True
if tags_to_remove:
if module.check_mode:
@@ -408,16 +410,16 @@ def update_parameter(client, module, **args):
@AWSRetry.jittered_backoff()
def describe_parameter(client, module, **args):
- paginator = client.get_paginator('describe_parameters')
+ paginator = client.get_paginator("describe_parameters")
existing_parameter = paginator.paginate(**args).build_full_result()
- if not existing_parameter['Parameters']:
+ if not existing_parameter["Parameters"]:
return None
- tags_dict = get_parameter_tags(client, module, module.params.get('name'))
- existing_parameter['Parameters'][0]['tags'] = tags_dict
+ tags_dict = get_parameter_tags(client, module, module.params.get("name"))
+ existing_parameter["Parameters"][0]["tags"] = tags_dict
- return existing_parameter['Parameters'][0]
+ return existing_parameter["Parameters"][0]
def create_update_parameter(client, module):
@@ -425,82 +427,78 @@ def create_update_parameter(client, module):
existing_parameter = None
response = {}
- args = dict(
- Name=module.params.get('name'),
- Type=module.params.get('string_type'),
- Tier=module.params.get('tier')
- )
+ args = dict(Name=module.params.get("name"), Type=module.params.get("string_type"), Tier=module.params.get("tier"))
- if (module.params.get('overwrite_value') in ("always", "changed")):
+ if module.params.get("overwrite_value") in ("always", "changed"):
args.update(Overwrite=True)
else:
args.update(Overwrite=False)
- if module.params.get('value') is not None:
- args.update(Value=module.params.get('value'))
+ if module.params.get("value") is not None:
+ args.update(Value=module.params.get("value"))
- if module.params.get('description'):
- args.update(Description=module.params.get('description'))
+ if module.params.get("description"):
+ args.update(Description=module.params.get("description"))
- if module.params.get('string_type') == 'SecureString':
- args.update(KeyId=module.params.get('key_id'))
+ if module.params.get("string_type") == "SecureString":
+ args.update(KeyId=module.params.get("key_id"))
try:
- existing_parameter = client.get_parameter(aws_retry=True, Name=args['Name'], WithDecryption=True)
+ existing_parameter = client.get_parameter(aws_retry=True, Name=args["Name"], WithDecryption=True)
except botocore.exceptions.ClientError:
pass
except botocore.exceptions.BotoCoreError as e:
module.fail_json_aws(e, msg="fetching parameter")
if existing_parameter:
- original_version = existing_parameter['Parameter']['Version']
- if 'Value' not in args:
- args['Value'] = existing_parameter['Parameter']['Value']
+ original_version = existing_parameter["Parameter"]["Version"]
+ if "Value" not in args:
+ args["Value"] = existing_parameter["Parameter"]["Value"]
- if (module.params.get('overwrite_value') == 'always'):
+ if module.params.get("overwrite_value") == "always":
(changed, response) = update_parameter(client, module, **args)
- elif (module.params.get('overwrite_value') == 'changed'):
- if existing_parameter['Parameter']['Type'] != args['Type']:
+ elif module.params.get("overwrite_value") == "changed":
+ if existing_parameter["Parameter"]["Type"] != args["Type"]:
(changed, response) = update_parameter(client, module, **args)
- elif existing_parameter['Parameter']['Value'] != args['Value']:
+ elif existing_parameter["Parameter"]["Value"] != args["Value"]:
(changed, response) = update_parameter(client, module, **args)
- elif args.get('Description'):
+ elif args.get("Description"):
# Description field not available from get_parameter function so get it from describe_parameters
try:
describe_existing_parameter = describe_parameter(
- client, module,
- ParameterFilters=[{"Key": "Name", "Values": [args['Name']]}])
+ client, module, ParameterFilters=[{"Key": "Name", "Values": [args["Name"]]}]
+ )
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="getting description value")
- if describe_existing_parameter.get('Description') != args['Description']:
+ if describe_existing_parameter.get("Description") != args["Description"]:
(changed, response) = update_parameter(client, module, **args)
if changed:
- _wait_updated(client, module, module.params.get('name'), original_version)
+ _wait_updated(client, module, module.params.get("name"), original_version)
# Handle tag updates for existing parameters
- if module.params.get('overwrite_value') != 'never':
+ if module.params.get("overwrite_value") != "never":
tags_changed, tags_response = update_parameter_tags(
- client, module, existing_parameter['Parameter']['Name'],
- module.params.get('tags'))
+ client, module, existing_parameter["Parameter"]["Name"], module.params.get("tags")
+ )
changed = changed or tags_changed
if tags_response:
- response['tag_updates'] = tags_response
+ response["tag_updates"] = tags_response
else:
# Add tags in initial creation request
- if module.params.get('tags'):
- args.update(Tags=ansible_dict_to_boto3_tag_list(module.params.get('tags')))
+ if module.params.get("tags"):
+ args.update(Tags=ansible_dict_to_boto3_tag_list(module.params.get("tags")))
# Overwrite=True conflicts with tags and is not needed for new param
args.update(Overwrite=False)
(changed, response) = update_parameter(client, module, **args)
- _wait_exists(client, module, module.params.get('name'))
+ _wait_exists(client, module, module.params.get("name"))
return changed, response
@@ -509,8 +507,8 @@ def delete_parameter(client, module):
response = {}
try:
- existing_parameter = client.get_parameter(aws_retry=True, Name=module.params.get('name'), WithDecryption=True)
- except is_boto3_error_code('ParameterNotFound'):
+ existing_parameter = client.get_parameter(aws_retry=True, Name=module.params.get("name"), WithDecryption=True)
+ except is_boto3_error_code("ParameterNotFound"):
return False, {}
except botocore.exceptions.ClientError:
# If we can't describe the parameter we may still be able to delete it
@@ -524,23 +522,23 @@ def delete_parameter(client, module):
return True, {}
try:
- response = client.delete_parameter(
- aws_retry=True,
- Name=module.params.get('name')
- )
- except is_boto3_error_code('ParameterNotFound'):
+ response = client.delete_parameter(aws_retry=True, Name=module.params.get("name"))
+ except is_boto3_error_code("ParameterNotFound"):
return False, {}
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
module.fail_json_aws(e, msg="deleting parameter")
- _wait_deleted(client, module, module.params.get('name'))
+ _wait_deleted(client, module, module.params.get("name"))
return True, response
def setup_client(module):
retry_decorator = AWSRetry.jittered_backoff()
- connection = module.client('ssm', retry_decorator=retry_decorator)
+ connection = module.client("ssm", retry_decorator=retry_decorator)
return connection
@@ -549,14 +547,14 @@ def setup_module_object():
name=dict(required=True),
description=dict(),
value=dict(required=False, no_log=True),
- state=dict(default='present', choices=['present', 'absent']),
- string_type=dict(default='String', choices=['String', 'StringList', 'SecureString'], aliases=['type']),
- decryption=dict(default=True, type='bool'),
+ state=dict(default="present", choices=["present", "absent"]),
+ string_type=dict(default="String", choices=["String", "StringList", "SecureString"], aliases=["type"]),
+ decryption=dict(default=True, type="bool"),
key_id=dict(default="alias/aws/ssm"),
- overwrite_value=dict(default='changed', choices=['never', 'changed', 'always']),
- tier=dict(default='Standard', choices=['Standard', 'Advanced', 'Intelligent-Tiering']),
- tags=dict(type='dict', aliases=['resource_tags']),
- purge_tags=dict(type='bool', default=True),
+ overwrite_value=dict(default="changed", choices=["never", "changed", "always"]),
+ tier=dict(default="Standard", choices=["Standard", "Advanced", "Intelligent-Tiering"]),
+ tags=dict(type="dict", aliases=["resource_tags"]),
+ purge_tags=dict(type="bool", default=True),
)
return AnsibleAWSModule(
@@ -567,7 +565,7 @@ def setup_module_object():
def main():
module = setup_module_object()
- state = module.params.get('state')
+ state = module.params.get("state")
client = setup_client(module)
invocations = {
@@ -580,18 +578,17 @@ def main():
try:
parameter_metadata = describe_parameter(
- client, module,
- ParameterFilters=[{"Key": "Name", "Values": [module.params.get('name')]}])
- except is_boto3_error_code('ParameterNotFound'):
+ client, module, ParameterFilters=[{"Key": "Name", "Values": [module.params.get("name")]}]
+ )
+ except is_boto3_error_code("ParameterNotFound"):
return False, {}
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="to describe parameter")
if parameter_metadata:
- result['parameter_metadata'] = camel_dict_to_snake_dict(parameter_metadata,
- ignore_list=['tags'])
+ result["parameter_metadata"] = camel_dict_to_snake_dict(parameter_metadata, ignore_list=["tags"])
module.exit_json(changed=changed, **result)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/stepfunctions_state_machine.py b/ansible_collections/community/aws/plugins/modules/stepfunctions_state_machine.py
index c141610bb..a2558c808 100644
--- a/ansible_collections/community/aws/plugins/modules/stepfunctions_state_machine.py
+++ b/ansible_collections/community/aws/plugins/modules/stepfunctions_state_machine.py
@@ -1,13 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright (c) 2019, Tom De Keyser (@tdekeyser)
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: stepfunctions_state_machine
version_added: 1.0.0
@@ -44,16 +41,17 @@ options:
choices: [ present, absent ]
type: str
-extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
- - amazon.aws.boto3
- - amazon.aws.tags
author:
- Tom De Keyser (@tdekeyser)
-'''
-EXAMPLES = '''
+extends_documentation_fragment:
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.tags
+ - amazon.aws.boto3
+"""
+
+EXAMPLES = r"""
# Create a new AWS Step Functions state machine
- name: Setup HelloWorld state machine
community.aws.stepfunctions_state_machine:
@@ -77,61 +75,62 @@ EXAMPLES = '''
community.aws.stepfunctions_state_machine:
name: HelloWorldStateMachine
state: absent
-'''
+"""
-RETURN = '''
+RETURN = r"""
state_machine_arn:
description: ARN of the AWS Step Functions state machine
type: str
returned: always
-'''
-
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import (ansible_dict_to_boto3_tag_list,
- AWSRetry,
- compare_aws_tags,
- boto3_tag_list_to_ansible_dict,
- )
+"""
try:
- from botocore.exceptions import ClientError, BotoCoreError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
except ImportError:
pass # caught by AnsibleAWSModule
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import ansible_dict_to_boto3_tag_list
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import compare_aws_tags
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
+
def manage_state_machine(state, sfn_client, module):
state_machine_arn = get_state_machine_arn(sfn_client, module)
- if state == 'present':
+ if state == "present":
if state_machine_arn is None:
create(sfn_client, module)
else:
update(state_machine_arn, sfn_client, module)
- elif state == 'absent':
+ elif state == "absent":
if state_machine_arn is not None:
remove(state_machine_arn, sfn_client, module)
- check_mode(module, msg='State is up-to-date.')
+ check_mode(module, msg="State is up-to-date.")
module.exit_json(changed=False, state_machine_arn=state_machine_arn)
def create(sfn_client, module):
- check_mode(module, msg='State machine would be created.', changed=True)
+ check_mode(module, msg="State machine would be created.", changed=True)
- tags = module.params.get('tags')
- sfn_tags = ansible_dict_to_boto3_tag_list(tags, tag_name_key_name='key', tag_value_key_name='value') if tags else []
+ tags = module.params.get("tags")
+ sfn_tags = ansible_dict_to_boto3_tag_list(tags, tag_name_key_name="key", tag_value_key_name="value") if tags else []
state_machine = sfn_client.create_state_machine(
- name=module.params.get('name'),
- definition=module.params.get('definition'),
- roleArn=module.params.get('role_arn'),
- tags=sfn_tags
+ name=module.params.get("name"),
+ definition=module.params.get("definition"),
+ roleArn=module.params.get("role_arn"),
+ tags=sfn_tags,
)
- module.exit_json(changed=True, state_machine_arn=state_machine.get('stateMachineArn'))
+ module.exit_json(changed=True, state_machine_arn=state_machine.get("stateMachineArn"))
def remove(state_machine_arn, sfn_client, module):
- check_mode(module, msg='State machine would be deleted: {0}'.format(state_machine_arn), changed=True)
+ check_mode(module, msg=f"State machine would be deleted: {state_machine_arn}", changed=True)
sfn_client.delete_state_machine(stateMachineArn=state_machine_arn)
module.exit_json(changed=True, state_machine_arn=state_machine_arn)
@@ -141,29 +140,28 @@ def update(state_machine_arn, sfn_client, module):
tags_to_add, tags_to_remove = compare_tags(state_machine_arn, sfn_client, module)
if params_changed(state_machine_arn, sfn_client, module) or tags_to_add or tags_to_remove:
- check_mode(module, msg='State machine would be updated: {0}'.format(state_machine_arn), changed=True)
+ check_mode(module, msg=f"State machine would be updated: {state_machine_arn}", changed=True)
sfn_client.update_state_machine(
stateMachineArn=state_machine_arn,
- definition=module.params.get('definition'),
- roleArn=module.params.get('role_arn')
- )
- sfn_client.untag_resource(
- resourceArn=state_machine_arn,
- tagKeys=tags_to_remove
+ definition=module.params.get("definition"),
+ roleArn=module.params.get("role_arn"),
)
+ sfn_client.untag_resource(resourceArn=state_machine_arn, tagKeys=tags_to_remove)
sfn_client.tag_resource(
resourceArn=state_machine_arn,
- tags=ansible_dict_to_boto3_tag_list(tags_to_add, tag_name_key_name='key', tag_value_key_name='value')
+ tags=ansible_dict_to_boto3_tag_list(tags_to_add, tag_name_key_name="key", tag_value_key_name="value"),
)
module.exit_json(changed=True, state_machine_arn=state_machine_arn)
def compare_tags(state_machine_arn, sfn_client, module):
- new_tags = module.params.get('tags')
- current_tags = sfn_client.list_tags_for_resource(resourceArn=state_machine_arn).get('tags')
- return compare_aws_tags(boto3_tag_list_to_ansible_dict(current_tags), new_tags if new_tags else {}, module.params.get('purge_tags'))
+ new_tags = module.params.get("tags")
+ current_tags = sfn_client.list_tags_for_resource(resourceArn=state_machine_arn).get("tags")
+ return compare_aws_tags(
+ boto3_tag_list_to_ansible_dict(current_tags), new_tags if new_tags else {}, module.params.get("purge_tags")
+ )
def params_changed(state_machine_arn, sfn_client, module):
@@ -172,7 +170,9 @@ def params_changed(state_machine_arn, sfn_client, module):
from the existing state machine parameters.
"""
current = sfn_client.describe_state_machine(stateMachineArn=state_machine_arn)
- return current.get('definition') != module.params.get('definition') or current.get('roleArn') != module.params.get('role_arn')
+ return current.get("definition") != module.params.get("definition") or current.get("roleArn") != module.params.get(
+ "role_arn"
+ )
def get_state_machine_arn(sfn_client, module):
@@ -180,42 +180,42 @@ def get_state_machine_arn(sfn_client, module):
Finds the state machine ARN based on the name parameter. Returns None if
there is no state machine with this name.
"""
- target_name = module.params.get('name')
- all_state_machines = sfn_client.list_state_machines(aws_retry=True).get('stateMachines')
+ target_name = module.params.get("name")
+ all_state_machines = sfn_client.list_state_machines(aws_retry=True).get("stateMachines")
for state_machine in all_state_machines:
- if state_machine.get('name') == target_name:
- return state_machine.get('stateMachineArn')
+ if state_machine.get("name") == target_name:
+ return state_machine.get("stateMachineArn")
-def check_mode(module, msg='', changed=False):
+def check_mode(module, msg="", changed=False):
if module.check_mode:
module.exit_json(changed=changed, output=msg)
def main():
module_args = dict(
- name=dict(type='str', required=True),
- definition=dict(type='json'),
- role_arn=dict(type='str'),
- state=dict(choices=['present', 'absent'], default='present'),
- tags=dict(default=None, type='dict', aliases=['resource_tags']),
- purge_tags=dict(default=True, type='bool'),
+ name=dict(type="str", required=True),
+ definition=dict(type="json"),
+ role_arn=dict(type="str"),
+ state=dict(choices=["present", "absent"], default="present"),
+ tags=dict(default=None, type="dict", aliases=["resource_tags"]),
+ purge_tags=dict(default=True, type="bool"),
)
module = AnsibleAWSModule(
argument_spec=module_args,
- required_if=[('state', 'present', ['role_arn']), ('state', 'present', ['definition'])],
- supports_check_mode=True
+ required_if=[("state", "present", ["role_arn"]), ("state", "present", ["definition"])],
+ supports_check_mode=True,
)
- sfn_client = module.client('stepfunctions', retry_decorator=AWSRetry.jittered_backoff(retries=5))
- state = module.params.get('state')
+ sfn_client = module.client("stepfunctions", retry_decorator=AWSRetry.jittered_backoff(retries=5))
+ state = module.params.get("state")
try:
manage_state_machine(state, sfn_client, module)
except (BotoCoreError, ClientError) as e:
- module.fail_json_aws(e, msg='Failed to manage state machine')
+ module.fail_json_aws(e, msg="Failed to manage state machine")
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/stepfunctions_state_machine_execution.py b/ansible_collections/community/aws/plugins/modules/stepfunctions_state_machine_execution.py
index aacfa987f..b7a9f7efb 100644
--- a/ansible_collections/community/aws/plugins/modules/stepfunctions_state_machine_execution.py
+++ b/ansible_collections/community/aws/plugins/modules/stepfunctions_state_machine_execution.py
@@ -1,13 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright (c) 2019, Prasad Katti (@prasadkatti)
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: stepfunctions_state_machine_execution
version_added: 1.0.0
@@ -47,16 +44,16 @@ options:
type: str
default: ''
-extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
- - amazon.aws.boto3
-
author:
- Prasad Katti (@prasadkatti)
-'''
-EXAMPLES = '''
+extends_documentation_fragment:
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
+
+EXAMPLES = r"""
- name: Start an execution of a state machine
community.aws.stepfunctions_state_machine_execution:
name: an_execution_name
@@ -69,9 +66,9 @@ EXAMPLES = '''
execution_arn: "arn:aws:states:us-west-2:123456789012:execution:HelloWorldStateMachineCopy:a1e8e2b5-5dfe-d40e-d9e3-6201061047c8"
cause: "cause of task failure"
error: "error code of the failure"
-'''
+"""
-RETURN = '''
+RETURN = r"""
execution_arn:
description: ARN of the AWS Step Functions state machine execution.
type: str
@@ -87,7 +84,7 @@ stop_date:
type: str
returned: if action == stop
sample: "2019-11-02T22:39:49.071000-07:00"
-'''
+"""
try:
@@ -97,100 +94,96 @@ except ImportError:
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def start_execution(module, sfn_client):
- '''
+ """
start_execution uses execution name to determine if a previous execution already exists.
If an execution by the provided name exists, call client.start_execution will not be called.
- '''
+ """
- state_machine_arn = module.params.get('state_machine_arn')
- name = module.params.get('name')
- execution_input = module.params.get('execution_input')
+ state_machine_arn = module.params.get("state_machine_arn")
+ name = module.params.get("name")
+ execution_input = module.params.get("execution_input")
try:
# list_executions is eventually consistent
- page_iterators = sfn_client.get_paginator('list_executions').paginate(stateMachineArn=state_machine_arn)
+ page_iterators = sfn_client.get_paginator("list_executions").paginate(stateMachineArn=state_machine_arn)
- for execution in page_iterators.build_full_result()['executions']:
- if name == execution['name']:
- check_mode(module, msg='State machine execution already exists.', changed=False)
+ for execution in page_iterators.build_full_result()["executions"]:
+ if name == execution["name"]:
+ check_mode(module, msg="State machine execution already exists.", changed=False)
module.exit_json(changed=False)
- check_mode(module, msg='State machine execution would be started.', changed=True)
- res_execution = sfn_client.start_execution(
- stateMachineArn=state_machine_arn,
- name=name,
- input=execution_input
- )
- except is_boto3_error_code('ExecutionAlreadyExists'):
+ check_mode(module, msg="State machine execution would be started.", changed=True)
+ res_execution = sfn_client.start_execution(stateMachineArn=state_machine_arn, name=name, input=execution_input)
+ except is_boto3_error_code("ExecutionAlreadyExists"):
# this will never be executed anymore
module.exit_json(changed=False)
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
module.fail_json_aws(e, msg="Failed to start execution.")
module.exit_json(changed=True, **camel_dict_to_snake_dict(res_execution))
def stop_execution(module, sfn_client):
-
- cause = module.params.get('cause')
- error = module.params.get('error')
- execution_arn = module.params.get('execution_arn')
+ cause = module.params.get("cause")
+ error = module.params.get("error")
+ execution_arn = module.params.get("execution_arn")
try:
# describe_execution is eventually consistent
- execution_status = sfn_client.describe_execution(executionArn=execution_arn)['status']
- if execution_status != 'RUNNING':
- check_mode(module, msg='State machine execution is not running.', changed=False)
+ execution_status = sfn_client.describe_execution(executionArn=execution_arn)["status"]
+ if execution_status != "RUNNING":
+ check_mode(module, msg="State machine execution is not running.", changed=False)
module.exit_json(changed=False)
- check_mode(module, msg='State machine execution would be stopped.', changed=True)
- res = sfn_client.stop_execution(
- executionArn=execution_arn,
- cause=cause,
- error=error
- )
+ check_mode(module, msg="State machine execution would be stopped.", changed=True)
+ res = sfn_client.stop_execution(executionArn=execution_arn, cause=cause, error=error)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Failed to stop execution.")
module.exit_json(changed=True, **camel_dict_to_snake_dict(res))
-def check_mode(module, msg='', changed=False):
+def check_mode(module, msg="", changed=False):
if module.check_mode:
module.exit_json(changed=changed, output=msg)
def main():
module_args = dict(
- action=dict(choices=['start', 'stop'], default='start'),
- name=dict(type='str'),
- execution_input=dict(type='json', default={}),
- state_machine_arn=dict(type='str'),
- cause=dict(type='str', default=''),
- error=dict(type='str', default=''),
- execution_arn=dict(type='str')
+ action=dict(choices=["start", "stop"], default="start"),
+ name=dict(type="str"),
+ execution_input=dict(type="json", default={}),
+ state_machine_arn=dict(type="str"),
+ cause=dict(type="str", default=""),
+ error=dict(type="str", default=""),
+ execution_arn=dict(type="str"),
)
module = AnsibleAWSModule(
argument_spec=module_args,
- required_if=[('action', 'start', ['name', 'state_machine_arn']),
- ('action', 'stop', ['execution_arn']),
- ],
- supports_check_mode=True
+ required_if=[
+ ("action", "start", ["name", "state_machine_arn"]),
+ ("action", "stop", ["execution_arn"]),
+ ],
+ supports_check_mode=True,
)
- sfn_client = module.client('stepfunctions')
+ sfn_client = module.client("stepfunctions")
- action = module.params.get('action')
+ action = module.params.get("action")
if action == "start":
start_execution(module, sfn_client)
else:
stop_execution(module, sfn_client)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/storagegateway_info.py b/ansible_collections/community/aws/plugins/modules/storagegateway_info.py
index 3f3c3ae2f..55b7c4685 100644
--- a/ansible_collections/community/aws/plugins/modules/storagegateway_info.py
+++ b/ansible_collections/community/aws/plugins/modules/storagegateway_info.py
@@ -1,14 +1,12 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: (c) 2018, Loic BLOT (@nerzhul) <loic.blot@unix-experience.fr>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
# This module is sponsored by E.T.A.I. (www.etai.fr)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: storagegateway_info
version_added: 1.0.0
@@ -45,12 +43,12 @@ options:
required: false
default: true
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-RETURN = '''
+RETURN = r"""
gateways:
description: list of gateway objects
returned: always
@@ -161,47 +159,49 @@ gateways:
returned: always
type: str
sample: "present"
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide for details.
- name: "Get AWS storage gateway information"
- community.aws.aws_sgw_info:
+ community.aws.storagegateway_info:
- name: "Get AWS storage gateway information for region eu-west-3"
- community.aws.aws_sgw_info:
+ community.aws.storagegateway_info:
region: eu-west-3
-'''
-
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict
+"""
try:
- from botocore.exceptions import BotoCoreError, ClientError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
except ImportError:
pass # caught by AnsibleAWSModule
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
+
class SGWInformationManager(object):
def __init__(self, client, module):
self.client = client
self.module = module
- self.name = self.module.params.get('name')
+ self.name = self.module.params.get("name")
def fetch(self):
gateways = self.list_gateways()
for gateway in gateways:
- if self.module.params.get('gather_local_disks'):
+ if self.module.params.get("gather_local_disks"):
self.list_local_disks(gateway)
# File share gateway
- if gateway["gateway_type"] == "FILE_S3" and self.module.params.get('gather_file_shares'):
+ if gateway["gateway_type"] == "FILE_S3" and self.module.params.get("gather_file_shares"):
self.list_gateway_file_shares(gateway)
# Volume tape gateway
- elif gateway["gateway_type"] == "VTL" and self.module.params.get('gather_tapes'):
+ elif gateway["gateway_type"] == "VTL" and self.module.params.get("gather_tapes"):
self.list_gateway_vtl(gateway)
# iSCSI gateway
- elif gateway["gateway_type"] in ["CACHED", "STORED"] and self.module.params.get('gather_volumes'):
+ elif gateway["gateway_type"] in ["CACHED", "STORED"] and self.module.params.get("gather_volumes"):
self.list_gateway_volumes(gateway)
self.module.exit_json(gateways=gateways)
@@ -209,12 +209,13 @@ class SGWInformationManager(object):
"""
List all storage gateways for the AWS endpoint.
"""
+
def list_gateways(self):
try:
- paginator = self.client.get_paginator('list_gateways')
+ paginator = self.client.get_paginator("list_gateways")
response = paginator.paginate(
PaginationConfig={
- 'PageSize': 100,
+ "PageSize": 100,
}
).build_full_result()
@@ -231,6 +232,7 @@ class SGWInformationManager(object):
Read file share objects from AWS API response.
Drop the gateway_arn attribute from response, as it will be duplicate with parent object.
"""
+
@staticmethod
def _read_gateway_fileshare_response(fileshares, aws_reponse):
for share in aws_reponse["FileShareInfoList"]:
@@ -244,22 +246,16 @@ class SGWInformationManager(object):
"""
List file shares attached to AWS storage gateway when in S3 mode.
"""
+
def list_gateway_file_shares(self, gateway):
try:
- response = self.client.list_file_shares(
- GatewayARN=gateway["gateway_arn"],
- Limit=100
- )
+ response = self.client.list_file_shares(GatewayARN=gateway["gateway_arn"], Limit=100)
gateway["file_shares"] = []
marker = self._read_gateway_fileshare_response(gateway["file_shares"], response)
while marker is not None:
- response = self.client.list_file_shares(
- GatewayARN=gateway["gateway_arn"],
- Marker=marker,
- Limit=100
- )
+ response = self.client.list_file_shares(GatewayARN=gateway["gateway_arn"], Marker=marker, Limit=100)
marker = self._read_gateway_fileshare_response(gateway["file_shares"], response)
except (BotoCoreError, ClientError) as e:
@@ -268,10 +264,13 @@ class SGWInformationManager(object):
"""
List storage gateway local disks
"""
+
def list_local_disks(self, gateway):
try:
- gateway['local_disks'] = [camel_dict_to_snake_dict(disk) for disk in
- self.client.list_local_disks(GatewayARN=gateway["gateway_arn"])['Disks']]
+ gateway["local_disks"] = [
+ camel_dict_to_snake_dict(disk)
+ for disk in self.client.list_local_disks(GatewayARN=gateway["gateway_arn"])["Disks"]
+ ]
except (BotoCoreError, ClientError) as e:
self.module.fail_json_aws(e, msg="Couldn't list storage gateway local disks")
@@ -279,6 +278,7 @@ class SGWInformationManager(object):
Read tape objects from AWS API response.
Drop the gateway_arn attribute from response, as it will be duplicate with parent object.
"""
+
@staticmethod
def _read_gateway_tape_response(tapes, aws_response):
for tape in aws_response["TapeInfos"]:
@@ -292,20 +292,16 @@ class SGWInformationManager(object):
"""
List VTL & VTS attached to AWS storage gateway in VTL mode
"""
+
def list_gateway_vtl(self, gateway):
try:
- response = self.client.list_tapes(
- Limit=100
- )
+ response = self.client.list_tapes(Limit=100)
gateway["tapes"] = []
marker = self._read_gateway_tape_response(gateway["tapes"], response)
while marker is not None:
- response = self.client.list_tapes(
- Marker=marker,
- Limit=100
- )
+ response = self.client.list_tapes(Marker=marker, Limit=100)
marker = self._read_gateway_tape_response(gateway["tapes"], response)
except (BotoCoreError, ClientError) as e:
@@ -314,14 +310,15 @@ class SGWInformationManager(object):
"""
List volumes attached to AWS storage gateway in CACHED or STORAGE mode
"""
+
def list_gateway_volumes(self, gateway):
try:
- paginator = self.client.get_paginator('list_volumes')
+ paginator = self.client.get_paginator("list_volumes")
response = paginator.paginate(
GatewayARN=gateway["gateway_arn"],
PaginationConfig={
- 'PageSize': 100,
- }
+ "PageSize": 100,
+ },
).build_full_result()
gateway["volumes"] = []
@@ -339,10 +336,10 @@ class SGWInformationManager(object):
def main():
argument_spec = dict(
- gather_local_disks=dict(type='bool', default=True),
- gather_tapes=dict(type='bool', default=True),
- gather_file_shares=dict(type='bool', default=True),
- gather_volumes=dict(type='bool', default=True)
+ gather_local_disks=dict(type="bool", default=True),
+ gather_tapes=dict(type="bool", default=True),
+ gather_file_shares=dict(type="bool", default=True),
+ gather_volumes=dict(type="bool", default=True),
)
module = AnsibleAWSModule(
@@ -350,13 +347,13 @@ def main():
supports_check_mode=True,
)
- client = module.client('storagegateway')
+ client = module.client("storagegateway")
if client is None: # this should never happen
- module.fail_json(msg='Unknown error, failed to create storagegateway client, no information available.')
+ module.fail_json(msg="Unknown error, failed to create storagegateway client, no information available.")
SGWInformationManager(client, module).fetch()
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/sts_assume_role.py b/ansible_collections/community/aws/plugins/modules/sts_assume_role.py
deleted file mode 100644
index 8e5a3b4fe..000000000
--- a/ansible_collections/community/aws/plugins/modules/sts_assume_role.py
+++ /dev/null
@@ -1,172 +0,0 @@
-#!/usr/bin/python
-# Copyright: Ansible Project
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
----
-module: sts_assume_role
-version_added: 1.0.0
-short_description: Assume a role using AWS Security Token Service and obtain temporary credentials
-description:
- - Assume a role using AWS Security Token Service and obtain temporary credentials.
-author:
- - Boris Ekelchik (@bekelchik)
- - Marek Piatek (@piontas)
-options:
- role_arn:
- description:
- - The Amazon Resource Name (ARN) of the role that the caller is
- assuming U(https://docs.aws.amazon.com/IAM/latest/UserGuide/Using_Identifiers.html#Identifiers_ARNs).
- required: true
- type: str
- role_session_name:
- description:
- - Name of the role's session - will be used by CloudTrail.
- required: true
- type: str
- policy:
- description:
- - Supplemental policy to use in addition to assumed role's policies.
- type: str
- duration_seconds:
- description:
- - The duration, in seconds, of the role session. The value can range from 900 seconds (15 minutes) to 43200 seconds (12 hours).
- - The max depends on the IAM role's sessions duration setting.
- - By default, the value is set to 3600 seconds.
- type: int
- external_id:
- description:
- - A unique identifier that is used by third parties to assume a role in their customers' accounts.
- type: str
- mfa_serial_number:
- description:
- - The identification number of the MFA device that is associated with the user who is making the AssumeRole call.
- type: str
- mfa_token:
- description:
- - The value provided by the MFA device, if the trust policy of the role being assumed requires MFA.
- type: str
-notes:
- - In order to use the assumed role in a following playbook task you must pass the access_key, access_secret and access_token.
-extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
-'''
-
-RETURN = '''
-sts_creds:
- description: The temporary security credentials, which include an access key ID, a secret access key, and a security (or session) token
- returned: always
- type: dict
- sample:
- access_key: XXXXXXXXXXXXXXXXXXXX
- expiration: '2017-11-11T11:11:11+00:00'
- secret_key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
- session_token: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-sts_user:
- description: The Amazon Resource Name (ARN) and the assumed role ID
- returned: always
- type: dict
- sample:
- assumed_role_id: arn:aws:sts::123456789012:assumed-role/demo/Bob
- arn: ARO123EXAMPLE123:Bob
-changed:
- description: True if obtaining the credentials succeeds
- type: bool
- returned: always
-'''
-
-EXAMPLES = '''
-# Note: These examples do not set authentication details, see the AWS Guide for details.
-
-# Assume an existing role (more details: https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html)
-- community.aws.sts_assume_role:
- role_arn: "arn:aws:iam::123456789012:role/someRole"
- role_session_name: "someRoleSession"
- register: assumed_role
-
-# Use the assumed role above to tag an instance in account 123456789012
-- amazon.aws.ec2_tag:
- aws_access_key: "{{ assumed_role.sts_creds.access_key }}"
- aws_secret_key: "{{ assumed_role.sts_creds.secret_key }}"
- security_token: "{{ assumed_role.sts_creds.session_token }}"
- resource: i-xyzxyz01
- state: present
- tags:
- MyNewTag: value
-
-'''
-
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict
-
-try:
- from botocore.exceptions import ClientError, ParamValidationError
-except ImportError:
- pass # caught by AnsibleAWSModule
-
-
-def _parse_response(response):
- credentials = response.get('Credentials', {})
- user = response.get('AssumedRoleUser', {})
-
- sts_cred = {
- 'access_key': credentials.get('AccessKeyId'),
- 'secret_key': credentials.get('SecretAccessKey'),
- 'session_token': credentials.get('SessionToken'),
- 'expiration': credentials.get('Expiration')
-
- }
- sts_user = camel_dict_to_snake_dict(user)
- return sts_cred, sts_user
-
-
-def assume_role_policy(connection, module):
- params = {
- 'RoleArn': module.params.get('role_arn'),
- 'RoleSessionName': module.params.get('role_session_name'),
- 'Policy': module.params.get('policy'),
- 'DurationSeconds': module.params.get('duration_seconds'),
- 'ExternalId': module.params.get('external_id'),
- 'SerialNumber': module.params.get('mfa_serial_number'),
- 'TokenCode': module.params.get('mfa_token')
- }
- changed = False
-
- kwargs = dict((k, v) for k, v in params.items() if v is not None)
-
- try:
- response = connection.assume_role(**kwargs)
- changed = True
- except (ClientError, ParamValidationError) as e:
- module.fail_json_aws(e)
-
- sts_cred, sts_user = _parse_response(response)
- module.exit_json(changed=changed, sts_creds=sts_cred, sts_user=sts_user)
-
-
-def main():
- argument_spec = dict(
- role_arn=dict(required=True),
- role_session_name=dict(required=True),
- duration_seconds=dict(required=False, default=None, type='int'),
- external_id=dict(required=False, default=None),
- policy=dict(required=False, default=None),
- mfa_serial_number=dict(required=False, default=None),
- mfa_token=dict(required=False, default=None, no_log=True)
- )
-
- module = AnsibleAWSModule(argument_spec=argument_spec)
-
- connection = module.client('sts')
-
- assume_role_policy(connection, module)
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/aws/plugins/modules/sts_session_token.py b/ansible_collections/community/aws/plugins/modules/sts_session_token.py
index 03df560e9..cb9f99fd3 100644
--- a/ansible_collections/community/aws/plugins/modules/sts_session_token.py
+++ b/ansible_collections/community/aws/plugins/modules/sts_session_token.py
@@ -1,19 +1,18 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: sts_session_token
version_added: 1.0.0
-short_description: Obtain a session token from the AWS Security Token Service
+short_description: obtain a session token from the AWS Security Token Service
description:
- - Obtain a session token from the AWS Security Token Service.
-author: Victor Costan (@pwnall)
+ - Obtain a session token from the AWS Security Token Service.
+author:
+ - Victor Costan (@pwnall)
options:
duration_seconds:
description:
@@ -30,20 +29,21 @@ options:
- The value provided by the MFA device, if the trust policy of the user requires MFA.
type: str
notes:
- - In order to use the session token in a following playbook task you must pass the I(access_key), I(access_secret) and I(access_token).
+ - In order to use the session token in a following playbook task you must pass the I(access_key),
+ I(secret_key) and I(session_token) parameters to modules that should use the session credentials.
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
-'''
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-RETURN = """
+RETURN = r"""
sts_creds:
description: The Credentials object returned by the AWS Security Token Service
returned: always
type: list
sample:
- access_key: ASXXXXXXXXXXXXXXXXXX
+ access_key: ASIAXXXXXXXXXXXXXXXX
expiration: "2016-04-08T11:59:47+00:00"
secret_key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
session_token: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
@@ -54,26 +54,27 @@ changed:
"""
-EXAMPLES = '''
+EXAMPLES = r"""
# Note: These examples do not set authentication details, see the AWS Guide for details.
# (more details: https://docs.aws.amazon.com/STS/latest/APIReference/API_GetSessionToken.html)
- name: Get a session token
community.aws.sts_session_token:
+ access_key: AKIA1EXAMPLE1EXAMPLE
+ secret_key: 123456789abcdefghijklmnopqrstuvwxyzABCDE
duration_seconds: 3600
register: session_credentials
- name: Use the session token obtained above to tag an instance in account 123456789012
amazon.aws.ec2_tag:
- aws_access_key: "{{ session_credentials.sts_creds.access_key }}"
- aws_secret_key: "{{ session_credentials.sts_creds.secret_key }}"
- security_token: "{{ session_credentials.sts_creds.session_token }}"
+ access_key: "{{ session_credentials.sts_creds.access_key }}"
+ secret_key: "{{ session_credentials.sts_creds.secret_key }}"
+ session_token: "{{ session_credentials.sts_creds.session_token }}"
resource: i-xyzxyz01
state: present
tags:
- MyNewTag: value
-
-'''
+ MyNewTag: value
+"""
try:
import botocore
@@ -81,35 +82,35 @@ try:
except ImportError:
pass # Handled by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def normalize_credentials(credentials):
- access_key = credentials.get('AccessKeyId', None)
- secret_key = credentials.get('SecretAccessKey', None)
- session_token = credentials.get('SessionToken', None)
- expiration = credentials.get('Expiration', None)
+ access_key = credentials.get("AccessKeyId", None)
+ secret_key = credentials.get("SecretAccessKey", None)
+ session_token = credentials.get("SessionToken", None)
+ expiration = credentials.get("Expiration", None)
return {
- 'access_key': access_key,
- 'secret_key': secret_key,
- 'session_token': session_token,
- 'expiration': expiration
+ "access_key": access_key,
+ "secret_key": secret_key,
+ "session_token": session_token,
+ "expiration": expiration,
}
def get_session_token(connection, module):
- duration_seconds = module.params.get('duration_seconds')
- mfa_serial_number = module.params.get('mfa_serial_number')
- mfa_token = module.params.get('mfa_token')
+ duration_seconds = module.params.get("duration_seconds")
+ mfa_serial_number = module.params.get("mfa_serial_number")
+ mfa_token = module.params.get("mfa_token")
changed = False
args = {}
if duration_seconds is not None:
- args['DurationSeconds'] = duration_seconds
+ args["DurationSeconds"] = duration_seconds
if mfa_serial_number is not None:
- args['SerialNumber'] = mfa_serial_number
+ args["SerialNumber"] = mfa_serial_number
if mfa_token is not None:
- args['TokenCode'] = mfa_token
+ args["TokenCode"] = mfa_token
try:
response = connection.get_session_token(**args)
@@ -117,13 +118,13 @@ def get_session_token(connection, module):
except ClientError as e:
module.fail_json(msg=e)
- credentials = normalize_credentials(response.get('Credentials', {}))
+ credentials = normalize_credentials(response.get("Credentials", {}))
module.exit_json(changed=changed, sts_creds=credentials)
def main():
argument_spec = dict(
- duration_seconds=dict(required=False, default=None, type='int'),
+ duration_seconds=dict(required=False, default=None, type="int"),
mfa_serial_number=dict(required=False, default=None),
mfa_token=dict(required=False, default=None, no_log=True),
)
@@ -131,12 +132,12 @@ def main():
module = AnsibleAWSModule(argument_spec=argument_spec)
try:
- connection = module.client('sts')
+ connection = module.client("sts")
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Failed to connect to AWS')
+ module.fail_json_aws(e, msg="Failed to connect to AWS")
get_session_token(connection, module)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/waf_condition.py b/ansible_collections/community/aws/plugins/modules/waf_condition.py
index 63585d50c..5b08cb6de 100644
--- a/ansible_collections/community/aws/plugins/modules/waf_condition.py
+++ b/ansible_collections/community/aws/plugins/modules/waf_condition.py
@@ -1,13 +1,11 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright (c) 2017 Will Thames
# Copyright (c) 2015 Mike Mochan
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
module: waf_condition
short_description: Create and delete WAF Conditions
version_added: 1.0.0
@@ -20,10 +18,6 @@ description:
author:
- Will Thames (@willthames)
- Mike Mochan (@mmochan)
-extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
- - amazon.aws.boto3
options:
name:
@@ -137,77 +131,81 @@ options:
- absent
default: present
type: str
-'''
-EXAMPLES = r'''
- - name: create WAF byte condition
- community.aws.waf_condition:
- name: my_byte_condition
- filters:
+extends_documentation_fragment:
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
+
+EXAMPLES = r"""
+- name: create WAF byte condition
+ community.aws.waf_condition:
+ name: my_byte_condition
+ filters:
- field_to_match: header
position: STARTS_WITH
target_string: Hello
header: Content-type
- type: byte
-
- - name: create WAF geo condition
- community.aws.waf_condition:
- name: my_geo_condition
- filters:
- - country: US
- - country: AU
- - country: AT
- type: geo
-
- - name: create IP address condition
- community.aws.waf_condition:
- name: "{{ resource_prefix }}_ip_condition"
- filters:
- - ip_address: "10.0.0.0/8"
- - ip_address: "192.168.0.0/24"
- type: ip
-
- - name: create WAF regex condition
- community.aws.waf_condition:
- name: my_regex_condition
- filters:
- - field_to_match: query_string
- regex_pattern:
- name: greetings
- regex_strings:
- - '[hH]ello'
- - '^Hi there'
- - '.*Good Day to You'
- type: regex
-
- - name: create WAF size condition
- community.aws.waf_condition:
- name: my_size_condition
- filters:
- - field_to_match: query_string
- size: 300
- comparison: GT
- type: size
-
- - name: create WAF sql injection condition
- community.aws.waf_condition:
- name: my_sql_condition
- filters:
- - field_to_match: query_string
- transformation: url_decode
- type: sql
-
- - name: create WAF xss condition
- community.aws.waf_condition:
- name: my_xss_condition
- filters:
- - field_to_match: query_string
- transformation: url_decode
- type: xss
-
-'''
-
-RETURN = r'''
+ type: byte
+
+- name: create WAF geo condition
+ community.aws.waf_condition:
+ name: my_geo_condition
+ filters:
+ - country: US
+ - country: AU
+ - country: AT
+ type: geo
+
+- name: create IP address condition
+ community.aws.waf_condition:
+ name: "{{ resource_prefix }}_ip_condition"
+ filters:
+ - ip_address: "10.0.0.0/8"
+ - ip_address: "192.168.0.0/24"
+ type: ip
+
+- name: create WAF regex condition
+ community.aws.waf_condition:
+ name: my_regex_condition
+ filters:
+ - field_to_match: query_string
+ regex_pattern:
+ name: greetings
+ regex_strings:
+ - '[hH]ello'
+ - '^Hi there'
+ - '.*Good Day to You'
+ type: regex
+
+- name: create WAF size condition
+ community.aws.waf_condition:
+ name: my_size_condition
+ filters:
+ - field_to_match: query_string
+ size: 300
+ comparison: GT
+ type: size
+
+- name: create WAF sql injection condition
+ community.aws.waf_condition:
+ name: my_sql_condition
+ filters:
+ - field_to_match: query_string
+ transformation: url_decode
+ type: sql
+
+- name: create WAF xss condition
+ community.aws.waf_condition:
+ name: my_xss_condition
+ filters:
+ - field_to_match: query_string
+ transformation: url_decode
+ type: xss
+"""
+
+RETURN = r"""
condition:
description: Condition returned by operation.
returned: always
@@ -397,7 +395,7 @@ condition:
description: transformation applied to the text before matching.
type: str
sample: URL_DECODE
-'''
+"""
try:
import botocore
@@ -406,85 +404,92 @@ except ImportError:
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import compare_policies
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
+from ansible_collections.amazon.aws.plugins.module_utils.policy import compare_policies
+from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
from ansible_collections.amazon.aws.plugins.module_utils.waf import MATCH_LOOKUP
-from ansible_collections.amazon.aws.plugins.module_utils.waf import run_func_with_change_token_backoff
from ansible_collections.amazon.aws.plugins.module_utils.waf import get_rule_with_backoff
from ansible_collections.amazon.aws.plugins.module_utils.waf import list_regional_rules_with_backoff
from ansible_collections.amazon.aws.plugins.module_utils.waf import list_rules_with_backoff
+from ansible_collections.amazon.aws.plugins.module_utils.waf import run_func_with_change_token_backoff
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
-class Condition(object):
+class Condition(object):
def __init__(self, client, module):
self.client = client
self.module = module
- self.type = module.params['type']
- self.method_suffix = MATCH_LOOKUP[self.type]['method']
- self.conditionset = MATCH_LOOKUP[self.type]['conditionset']
- self.conditionsets = MATCH_LOOKUP[self.type]['conditionset'] + 's'
- self.conditionsetid = MATCH_LOOKUP[self.type]['conditionset'] + 'Id'
- self.conditiontuple = MATCH_LOOKUP[self.type]['conditiontuple']
- self.conditiontuples = MATCH_LOOKUP[self.type]['conditiontuple'] + 's'
- self.conditiontype = MATCH_LOOKUP[self.type]['type']
+ self.type = module.params["type"]
+ self.method_suffix = MATCH_LOOKUP[self.type]["method"]
+ self.conditionset = MATCH_LOOKUP[self.type]["conditionset"]
+ self.conditionsets = MATCH_LOOKUP[self.type]["conditionset"] + "s"
+ self.conditionsetid = MATCH_LOOKUP[self.type]["conditionset"] + "Id"
+ self.conditiontuple = MATCH_LOOKUP[self.type]["conditiontuple"]
+ self.conditiontuples = MATCH_LOOKUP[self.type]["conditiontuple"] + "s"
+ self.conditiontype = MATCH_LOOKUP[self.type]["type"]
def format_for_update(self, condition_set_id):
# Prep kwargs
kwargs = dict()
- kwargs['Updates'] = list()
+ kwargs["Updates"] = list()
- for filtr in self.module.params.get('filters'):
+ for filtr in self.module.params.get("filters"):
# Only for ip_set
- if self.type == 'ip':
+ if self.type == "ip":
# there might be a better way of detecting an IPv6 address
- if ':' in filtr.get('ip_address'):
- ip_type = 'IPV6'
+ if ":" in filtr.get("ip_address"):
+ ip_type = "IPV6"
else:
- ip_type = 'IPV4'
- condition_insert = {'Type': ip_type, 'Value': filtr.get('ip_address')}
+ ip_type = "IPV4"
+ condition_insert = {"Type": ip_type, "Value": filtr.get("ip_address")}
# Specific for geo_match_set
- if self.type == 'geo':
- condition_insert = dict(Type='Country', Value=filtr.get('country'))
+ if self.type == "geo":
+ condition_insert = dict(Type="Country", Value=filtr.get("country"))
# Common For everything but ip_set and geo_match_set
- if self.type not in ('ip', 'geo'):
-
- condition_insert = dict(FieldToMatch=dict(Type=filtr.get('field_to_match').upper()),
- TextTransformation=filtr.get('transformation', 'none').upper())
-
- if filtr.get('field_to_match').upper() == "HEADER":
- if filtr.get('header'):
- condition_insert['FieldToMatch']['Data'] = filtr.get('header').lower()
+ if self.type not in ("ip", "geo"):
+ condition_insert = dict(
+ FieldToMatch=dict(Type=filtr.get("field_to_match").upper()),
+ TextTransformation=filtr.get("transformation", "none").upper(),
+ )
+
+ if filtr.get("field_to_match").upper() == "HEADER":
+ if filtr.get("header"):
+ condition_insert["FieldToMatch"]["Data"] = filtr.get("header").lower()
else:
self.module.fail_json(msg=str("DATA required when HEADER requested"))
# Specific for byte_match_set
- if self.type == 'byte':
- condition_insert['TargetString'] = filtr.get('target_string')
- condition_insert['PositionalConstraint'] = filtr.get('position')
+ if self.type == "byte":
+ condition_insert["TargetString"] = filtr.get("target_string")
+ condition_insert["PositionalConstraint"] = filtr.get("position")
# Specific for size_constraint_set
- if self.type == 'size':
- condition_insert['ComparisonOperator'] = filtr.get('comparison')
- condition_insert['Size'] = filtr.get('size')
+ if self.type == "size":
+ condition_insert["ComparisonOperator"] = filtr.get("comparison")
+ condition_insert["Size"] = filtr.get("size")
# Specific for regex_match_set
- if self.type == 'regex':
- condition_insert['RegexPatternSetId'] = self.ensure_regex_pattern_present(filtr.get('regex_pattern'))['RegexPatternSetId']
+ if self.type == "regex":
+ condition_insert["RegexPatternSetId"] = self.ensure_regex_pattern_present(filtr.get("regex_pattern"))[
+ "RegexPatternSetId"
+ ]
- kwargs['Updates'].append({'Action': 'INSERT', self.conditiontuple: condition_insert})
+ kwargs["Updates"].append({"Action": "INSERT", self.conditiontuple: condition_insert})
kwargs[self.conditionsetid] = condition_set_id
return kwargs
def format_for_deletion(self, condition):
- return {'Updates': [{'Action': 'DELETE', self.conditiontuple: current_condition_tuple}
- for current_condition_tuple in condition[self.conditiontuples]],
- self.conditionsetid: condition[self.conditionsetid]}
+ return {
+ "Updates": [
+ {"Action": "DELETE", self.conditiontuple: current_condition_tuple}
+ for current_condition_tuple in condition[self.conditiontuples]
+ ],
+ self.conditionsetid: condition[self.conditionsetid],
+ }
@AWSRetry.exponential_backoff()
def list_regex_patterns_with_backoff(self, **params):
@@ -502,60 +507,77 @@ class Condition(object):
try:
response = self.list_regex_patterns_with_backoff(**params)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, msg='Could not list regex patterns')
- regex_patterns.extend(response['RegexPatternSets'])
- if 'NextMarker' in response:
- params['NextMarker'] = response['NextMarker']
+ self.module.fail_json_aws(e, msg="Could not list regex patterns")
+ regex_patterns.extend(response["RegexPatternSets"])
+ if "NextMarker" in response:
+ params["NextMarker"] = response["NextMarker"]
else:
break
return regex_patterns
def get_regex_pattern_by_name(self, name):
existing_regex_patterns = self.list_regex_patterns()
- regex_lookup = dict((item['Name'], item['RegexPatternSetId']) for item in existing_regex_patterns)
+ regex_lookup = dict((item["Name"], item["RegexPatternSetId"]) for item in existing_regex_patterns)
if name in regex_lookup:
- return self.get_regex_pattern_set_with_backoff(regex_lookup[name])['RegexPatternSet']
+ return self.get_regex_pattern_set_with_backoff(regex_lookup[name])["RegexPatternSet"]
else:
return None
def ensure_regex_pattern_present(self, regex_pattern):
- name = regex_pattern['name']
+ name = regex_pattern["name"]
pattern_set = self.get_regex_pattern_by_name(name)
if not pattern_set:
- pattern_set = run_func_with_change_token_backoff(self.client, self.module, {'Name': name},
- self.client.create_regex_pattern_set)['RegexPatternSet']
- missing = set(regex_pattern['regex_strings']) - set(pattern_set['RegexPatternStrings'])
- extra = set(pattern_set['RegexPatternStrings']) - set(regex_pattern['regex_strings'])
+ pattern_set = run_func_with_change_token_backoff(
+ self.client, self.module, {"Name": name}, self.client.create_regex_pattern_set
+ )["RegexPatternSet"]
+ missing = set(regex_pattern["regex_strings"]) - set(pattern_set["RegexPatternStrings"])
+ extra = set(pattern_set["RegexPatternStrings"]) - set(regex_pattern["regex_strings"])
if not missing and not extra:
return pattern_set
- updates = [{'Action': 'INSERT', 'RegexPatternString': pattern} for pattern in missing]
- updates.extend([{'Action': 'DELETE', 'RegexPatternString': pattern} for pattern in extra])
- run_func_with_change_token_backoff(self.client, self.module,
- {'RegexPatternSetId': pattern_set['RegexPatternSetId'], 'Updates': updates},
- self.client.update_regex_pattern_set, wait=True)
- return self.get_regex_pattern_set_with_backoff(pattern_set['RegexPatternSetId'])['RegexPatternSet']
+ updates = [{"Action": "INSERT", "RegexPatternString": pattern} for pattern in missing]
+ updates.extend([{"Action": "DELETE", "RegexPatternString": pattern} for pattern in extra])
+ run_func_with_change_token_backoff(
+ self.client,
+ self.module,
+ {"RegexPatternSetId": pattern_set["RegexPatternSetId"], "Updates": updates},
+ self.client.update_regex_pattern_set,
+ wait=True,
+ )
+ return self.get_regex_pattern_set_with_backoff(pattern_set["RegexPatternSetId"])["RegexPatternSet"]
def delete_unused_regex_pattern(self, regex_pattern_set_id):
try:
- regex_pattern_set = self.client.get_regex_pattern_set(RegexPatternSetId=regex_pattern_set_id)['RegexPatternSet']
+ regex_pattern_set = self.client.get_regex_pattern_set(RegexPatternSetId=regex_pattern_set_id)[
+ "RegexPatternSet"
+ ]
updates = list()
- for regex_pattern_string in regex_pattern_set['RegexPatternStrings']:
- updates.append({'Action': 'DELETE', 'RegexPatternString': regex_pattern_string})
- run_func_with_change_token_backoff(self.client, self.module,
- {'RegexPatternSetId': regex_pattern_set_id, 'Updates': updates},
- self.client.update_regex_pattern_set)
-
- run_func_with_change_token_backoff(self.client, self.module,
- {'RegexPatternSetId': regex_pattern_set_id},
- self.client.delete_regex_pattern_set, wait=True)
- except is_boto3_error_code('WAFNonexistentItemException'):
+ for regex_pattern_string in regex_pattern_set["RegexPatternStrings"]:
+ updates.append({"Action": "DELETE", "RegexPatternString": regex_pattern_string})
+ run_func_with_change_token_backoff(
+ self.client,
+ self.module,
+ {"RegexPatternSetId": regex_pattern_set_id, "Updates": updates},
+ self.client.update_regex_pattern_set,
+ )
+
+ run_func_with_change_token_backoff(
+ self.client,
+ self.module,
+ {"RegexPatternSetId": regex_pattern_set_id},
+ self.client.delete_regex_pattern_set,
+ wait=True,
+ )
+ except is_boto3_error_code("WAFNonexistentItemException"):
return
- except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
- self.module.fail_json_aws(e, msg='Could not delete regex pattern')
+ except (
+ botocore.exceptions.ClientError,
+ botocore.exceptions.BotoCoreError,
+ ) as e: # pylint: disable=duplicate-except
+ self.module.fail_json_aws(e, msg="Could not delete regex pattern")
def get_condition_by_name(self, name):
- all_conditions = [d for d in self.list_conditions() if d['Name'] == name]
+ all_conditions = [d for d in self.list_conditions() if d["Name"] == name]
if all_conditions:
return all_conditions[0][self.conditionsetid]
@@ -563,17 +585,17 @@ class Condition(object):
def get_condition_by_id_with_backoff(self, condition_set_id):
params = dict()
params[self.conditionsetid] = condition_set_id
- func = getattr(self.client, 'get_' + self.method_suffix)
+ func = getattr(self.client, "get_" + self.method_suffix)
return func(**params)[self.conditionset]
def get_condition_by_id(self, condition_set_id):
try:
return self.get_condition_by_id_with_backoff(condition_set_id)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, msg='Could not get condition')
+ self.module.fail_json_aws(e, msg="Could not get condition")
def list_conditions(self):
- method = 'list_' + self.method_suffix + 's'
+ method = "list_" + self.method_suffix + "s"
try:
paginator = self.client.get_paginator(method)
func = paginator.paginate().build_full_result
@@ -583,66 +605,68 @@ class Condition(object):
try:
return func()[self.conditionsets]
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, msg='Could not list %s conditions' % self.type)
+ self.module.fail_json_aws(e, msg=f"Could not list {self.type} conditions")
def tidy_up_regex_patterns(self, regex_match_set):
all_regex_match_sets = self.list_conditions()
all_match_set_patterns = list()
for rms in all_regex_match_sets:
- all_match_set_patterns.extend(conditiontuple['RegexPatternSetId']
- for conditiontuple in self.get_condition_by_id(rms[self.conditionsetid])[self.conditiontuples])
+ all_match_set_patterns.extend(
+ conditiontuple["RegexPatternSetId"]
+ for conditiontuple in self.get_condition_by_id(rms[self.conditionsetid])[self.conditiontuples]
+ )
for filtr in regex_match_set[self.conditiontuples]:
- if filtr['RegexPatternSetId'] not in all_match_set_patterns:
- self.delete_unused_regex_pattern(filtr['RegexPatternSetId'])
+ if filtr["RegexPatternSetId"] not in all_match_set_patterns:
+ self.delete_unused_regex_pattern(filtr["RegexPatternSetId"])
def find_condition_in_rules(self, condition_set_id):
rules_in_use = []
try:
- if self.client.__class__.__name__ == 'WAF':
+ if self.client.__class__.__name__ == "WAF":
all_rules = list_rules_with_backoff(self.client)
- elif self.client.__class__.__name__ == 'WAFRegional':
+ elif self.client.__class__.__name__ == "WAFRegional":
all_rules = list_regional_rules_with_backoff(self.client)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, msg='Could not list rules')
+ self.module.fail_json_aws(e, msg="Could not list rules")
for rule in all_rules:
try:
- rule_details = get_rule_with_backoff(self.client, rule['RuleId'])
+ rule_details = get_rule_with_backoff(self.client, rule["RuleId"])
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, msg='Could not get rule details')
- if condition_set_id in [predicate['DataId'] for predicate in rule_details['Predicates']]:
- rules_in_use.append(rule_details['Name'])
+ self.module.fail_json_aws(e, msg="Could not get rule details")
+ if condition_set_id in [predicate["DataId"] for predicate in rule_details["Predicates"]]:
+ rules_in_use.append(rule_details["Name"])
return rules_in_use
def find_and_delete_condition(self, condition_set_id):
current_condition = self.get_condition_by_id(condition_set_id)
in_use_rules = self.find_condition_in_rules(condition_set_id)
if in_use_rules:
- rulenames = ', '.join(in_use_rules)
- self.module.fail_json(msg="Condition %s is in use by %s" % (current_condition['Name'], rulenames))
+ rulenames = ", ".join(in_use_rules)
+ self.module.fail_json(msg=f"Condition {current_condition['Name']} is in use by {rulenames}")
if current_condition[self.conditiontuples]:
# Filters are deleted using update with the DELETE action
- func = getattr(self.client, 'update_' + self.method_suffix)
+ func = getattr(self.client, "update_" + self.method_suffix)
params = self.format_for_deletion(current_condition)
try:
# We do not need to wait for the conditiontuple delete because we wait later for the delete_* call
run_func_with_change_token_backoff(self.client, self.module, params, func)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, msg='Could not delete filters from condition')
- func = getattr(self.client, 'delete_' + self.method_suffix)
+ self.module.fail_json_aws(e, msg="Could not delete filters from condition")
+ func = getattr(self.client, "delete_" + self.method_suffix)
params = dict()
params[self.conditionsetid] = condition_set_id
try:
run_func_with_change_token_backoff(self.client, self.module, params, func, wait=True)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, msg='Could not delete condition')
+ self.module.fail_json_aws(e, msg="Could not delete condition")
# tidy up regex patterns
- if self.type == 'regex':
+ if self.type == "regex":
self.tidy_up_regex_patterns(current_condition)
return True, {}
def find_missing(self, update, current_condition):
missing = []
- for desired in update['Updates']:
+ for desired in update["Updates"]:
found = False
desired_condition = desired[self.conditiontuple]
current_conditions = current_condition[self.conditiontuples]
@@ -657,39 +681,41 @@ class Condition(object):
current_condition = self.get_condition_by_id(condition_set_id)
update = self.format_for_update(condition_set_id)
missing = self.find_missing(update, current_condition)
- if self.module.params.get('purge_filters'):
- extra = [{'Action': 'DELETE', self.conditiontuple: current_tuple}
- for current_tuple in current_condition[self.conditiontuples]
- if current_tuple not in [desired[self.conditiontuple] for desired in update['Updates']]]
+ if self.module.params.get("purge_filters"):
+ extra = [
+ {"Action": "DELETE", self.conditiontuple: current_tuple}
+ for current_tuple in current_condition[self.conditiontuples]
+ if current_tuple not in [desired[self.conditiontuple] for desired in update["Updates"]]
+ ]
else:
extra = []
changed = bool(missing or extra)
if changed:
- update['Updates'] = missing + extra
- func = getattr(self.client, 'update_' + self.method_suffix)
+ update["Updates"] = missing + extra
+ func = getattr(self.client, "update_" + self.method_suffix)
try:
result = run_func_with_change_token_backoff(self.client, self.module, update, func, wait=True)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, msg='Could not update condition')
+ self.module.fail_json_aws(e, msg="Could not update condition")
return changed, self.get_condition_by_id(condition_set_id)
def ensure_condition_present(self):
- name = self.module.params['name']
+ name = self.module.params["name"]
condition_set_id = self.get_condition_by_name(name)
if condition_set_id:
return self.find_and_update_condition(condition_set_id)
else:
params = dict()
- params['Name'] = name
- func = getattr(self.client, 'create_' + self.method_suffix)
+ params["Name"] = name
+ func = getattr(self.client, "create_" + self.method_suffix)
try:
condition = run_func_with_change_token_backoff(self.client, self.module, params, func)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- self.module.fail_json_aws(e, msg='Could not create condition')
+ self.module.fail_json_aws(e, msg="Could not create condition")
return self.find_and_update_condition(condition[self.conditionset][self.conditionsetid])
def ensure_condition_absent(self):
- condition_set_id = self.get_condition_by_name(self.module.params['name'])
+ condition_set_id = self.get_condition_by_name(self.module.params["name"])
if condition_set_id:
return self.find_and_delete_condition(condition_set_id)
return False, {}
@@ -698,45 +724,46 @@ class Condition(object):
def main():
filters_subspec = dict(
country=dict(),
- field_to_match=dict(choices=['uri', 'query_string', 'header', 'method', 'body']),
+ field_to_match=dict(choices=["uri", "query_string", "header", "method", "body"]),
header=dict(),
- transformation=dict(choices=['none', 'compress_white_space',
- 'html_entity_decode', 'lowercase',
- 'cmd_line', 'url_decode']),
- position=dict(choices=['exactly', 'starts_with', 'ends_with',
- 'contains', 'contains_word']),
- comparison=dict(choices=['EQ', 'NE', 'LE', 'LT', 'GE', 'GT']),
+ transformation=dict(
+ choices=["none", "compress_white_space", "html_entity_decode", "lowercase", "cmd_line", "url_decode"]
+ ),
+ position=dict(choices=["exactly", "starts_with", "ends_with", "contains", "contains_word"]),
+ comparison=dict(choices=["EQ", "NE", "LE", "LT", "GE", "GT"]),
target_string=dict(), # Bytes
- size=dict(type='int'),
+ size=dict(type="int"),
ip_address=dict(),
regex_pattern=dict(),
)
argument_spec = dict(
name=dict(required=True),
- type=dict(required=True, choices=['byte', 'geo', 'ip', 'regex', 'size', 'sql', 'xss']),
- filters=dict(type='list', elements='dict'),
- purge_filters=dict(type='bool', default=False),
- waf_regional=dict(type='bool', default=False),
- state=dict(default='present', choices=['present', 'absent']),
+ type=dict(required=True, choices=["byte", "geo", "ip", "regex", "size", "sql", "xss"]),
+ filters=dict(type="list", elements="dict"),
+ purge_filters=dict(type="bool", default=False),
+ waf_regional=dict(type="bool", default=False),
+ state=dict(default="present", choices=["present", "absent"]),
+ )
+ module = AnsibleAWSModule(
+ argument_spec=argument_spec,
+ required_if=[["state", "present", ["filters"]]],
)
- module = AnsibleAWSModule(argument_spec=argument_spec,
- required_if=[['state', 'present', ['filters']]])
- state = module.params.get('state')
+ state = module.params.get("state")
- resource = 'waf' if not module.params['waf_regional'] else 'waf-regional'
+ resource = "waf" if not module.params["waf_regional"] else "waf-regional"
client = module.client(resource)
condition = Condition(client, module)
- if state == 'present':
+ if state == "present":
(changed, results) = condition.ensure_condition_present()
# return a condition agnostic ID for use by waf_rule
- results['ConditionId'] = results[condition.conditionsetid]
+ results["ConditionId"] = results[condition.conditionsetid]
else:
(changed, results) = condition.ensure_condition_absent()
module.exit_json(changed=changed, condition=camel_dict_to_snake_dict(results))
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/waf_info.py b/ansible_collections/community/aws/plugins/modules/waf_info.py
index 6a49a886e..711d1d8de 100644
--- a/ansible_collections/community/aws/plugins/modules/waf_info.py
+++ b/ansible_collections/community/aws/plugins/modules/waf_info.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
module: waf_info
short_description: Retrieve information for WAF ACLs, Rules, Conditions and Filters
version_added: 1.0.0
@@ -29,12 +27,12 @@ author:
- Mike Mochan (@mmochan)
- Will Thames (@willthames)
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
- name: obtain all WAF information
community.aws.waf_info:
@@ -46,9 +44,9 @@ EXAMPLES = '''
community.aws.waf_info:
name: test_waf
waf_regional: true
-'''
+"""
-RETURN = '''
+RETURN = r"""
wafs:
description: The WAFs that match the passed arguments.
returned: success
@@ -114,31 +112,31 @@ wafs:
"type": "ByteMatch"
}
]
-'''
+"""
+
+from ansible_collections.amazon.aws.plugins.module_utils.waf import get_web_acl
+from ansible_collections.amazon.aws.plugins.module_utils.waf import list_web_acls
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.waf import list_web_acls, get_web_acl
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def main():
argument_spec = dict(
name=dict(required=False),
- waf_regional=dict(type='bool', default=False)
+ waf_regional=dict(type="bool", default=False),
)
module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
- resource = 'waf' if not module.params['waf_regional'] else 'waf-regional'
+ resource = "waf" if not module.params["waf_regional"] else "waf-regional"
client = module.client(resource)
web_acls = list_web_acls(client, module)
- name = module.params['name']
+ name = module.params["name"]
if name:
- web_acls = [web_acl for web_acl in web_acls if
- web_acl['Name'] == name]
+ web_acls = [web_acl for web_acl in web_acls if web_acl["Name"] == name]
if not web_acls:
- module.fail_json(msg="WAF named %s not found" % name)
- module.exit_json(wafs=[get_web_acl(client, module, web_acl['WebACLId'])
- for web_acl in web_acls])
+ module.fail_json(msg=f"WAF named {name} not found")
+ module.exit_json(wafs=[get_web_acl(client, module, web_acl["WebACLId"]) for web_acl in web_acls])
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/waf_rule.py b/ansible_collections/community/aws/plugins/modules/waf_rule.py
index a994b1831..87a02bbbd 100644
--- a/ansible_collections/community/aws/plugins/modules/waf_rule.py
+++ b/ansible_collections/community/aws/plugins/modules/waf_rule.py
@@ -1,13 +1,11 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright (c) 2017 Will Thames
# Copyright (c) 2015 Mike Mochan
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
module: waf_rule
short_description: Create and delete WAF Rules
version_added: 1.0.0
@@ -20,10 +18,6 @@ description:
author:
- Mike Mochan (@mmochan)
- Will Thames (@willthames)
-extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
- - amazon.aws.boto3
options:
name:
@@ -71,30 +65,35 @@ options:
default: false
required: false
type: bool
-'''
-
-EXAMPLES = r'''
- - name: create WAF rule
- community.aws.waf_rule:
- name: my_waf_rule
- conditions:
- - name: my_regex_condition
- type: regex
- negated: false
- - name: my_geo_condition
- type: geo
- negated: false
- - name: my_byte_condition
- type: byte
- negated: true
-
- - name: remove WAF rule
- community.aws.waf_rule:
- name: "my_waf_rule"
- state: absent
-'''
-
-RETURN = r'''
+
+extends_documentation_fragment:
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
+
+EXAMPLES = r"""
+- name: create WAF rule
+ community.aws.waf_rule:
+ name: my_waf_rule
+ conditions:
+ - name: my_regex_condition
+ type: regex
+ negated: false
+ - name: my_geo_condition
+ type: geo
+ negated: false
+ - name: my_byte_condition
+ type: byte
+ negated: true
+
+- name: remove WAF rule
+ community.aws.waf_rule:
+ name: "my_waf_rule"
+ state: absent
+"""
+
+RETURN = r"""
rule:
description: WAF rule contents
returned: always
@@ -135,7 +134,7 @@ rule:
returned: always
type: str
sample: 15de0cbc-9204-4e1f-90e6-69b2f415c261
-'''
+"""
import re
@@ -144,62 +143,62 @@ try:
except ImportError:
pass # handled by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.waf import (
- MATCH_LOOKUP,
- list_regional_rules_with_backoff,
- list_rules_with_backoff,
- run_func_with_change_token_backoff,
- get_web_acl_with_backoff,
- list_web_acls_with_backoff,
- list_regional_web_acls_with_backoff,
-)
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.waf import MATCH_LOOKUP
+from ansible_collections.amazon.aws.plugins.module_utils.waf import get_web_acl_with_backoff
+from ansible_collections.amazon.aws.plugins.module_utils.waf import list_regional_rules_with_backoff
+from ansible_collections.amazon.aws.plugins.module_utils.waf import list_regional_web_acls_with_backoff
+from ansible_collections.amazon.aws.plugins.module_utils.waf import list_rules_with_backoff
+from ansible_collections.amazon.aws.plugins.module_utils.waf import list_web_acls_with_backoff
+from ansible_collections.amazon.aws.plugins.module_utils.waf import run_func_with_change_token_backoff
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def get_rule_by_name(client, module, name):
- rules = [d['RuleId'] for d in list_rules(client, module) if d['Name'] == name]
+ rules = [d["RuleId"] for d in list_rules(client, module) if d["Name"] == name]
if rules:
return rules[0]
def get_rule(client, module, rule_id):
try:
- return client.get_rule(RuleId=rule_id)['Rule']
+ return client.get_rule(RuleId=rule_id)["Rule"]
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Could not get WAF rule')
+ module.fail_json_aws(e, msg="Could not get WAF rule")
def list_rules(client, module):
- if client.__class__.__name__ == 'WAF':
+ if client.__class__.__name__ == "WAF":
try:
return list_rules_with_backoff(client)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Could not list WAF rules')
- elif client.__class__.__name__ == 'WAFRegional':
+ module.fail_json_aws(e, msg="Could not list WAF rules")
+ elif client.__class__.__name__ == "WAFRegional":
try:
return list_regional_rules_with_backoff(client)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Could not list WAF Regional rules')
+ module.fail_json_aws(e, msg="Could not list WAF Regional rules")
def list_regional_rules(client, module):
try:
return list_regional_rules_with_backoff(client)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Could not list WAF rules')
+ module.fail_json_aws(e, msg="Could not list WAF rules")
def find_and_update_rule(client, module, rule_id):
rule = get_rule(client, module, rule_id)
- rule_id = rule['RuleId']
+ rule_id = rule["RuleId"]
existing_conditions = dict((condition_type, dict()) for condition_type in MATCH_LOOKUP)
desired_conditions = dict((condition_type, dict()) for condition_type in MATCH_LOOKUP)
all_conditions = dict()
for condition_type in MATCH_LOOKUP:
- method = 'list_' + MATCH_LOOKUP[condition_type]['method'] + 's'
+ method = "list_" + MATCH_LOOKUP[condition_type]["method"] + "s"
all_conditions[condition_type] = dict()
try:
paginator = client.get_paginator(method)
@@ -209,125 +208,133 @@ def find_and_update_rule(client, module, rule_id):
# and throw different exceptions
func = getattr(client, method)
try:
- pred_results = func()[MATCH_LOOKUP[condition_type]['conditionset'] + 's']
+ pred_results = func()[MATCH_LOOKUP[condition_type]["conditionset"] + "s"]
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Could not list %s conditions' % condition_type)
+ module.fail_json_aws(e, msg=f"Could not list {condition_type} conditions")
for pred in pred_results:
- pred['DataId'] = pred[MATCH_LOOKUP[condition_type]['conditionset'] + 'Id']
- all_conditions[condition_type][pred['Name']] = camel_dict_to_snake_dict(pred)
- all_conditions[condition_type][pred['DataId']] = camel_dict_to_snake_dict(pred)
+ pred["DataId"] = pred[MATCH_LOOKUP[condition_type]["conditionset"] + "Id"]
+ all_conditions[condition_type][pred["Name"]] = camel_dict_to_snake_dict(pred)
+ all_conditions[condition_type][pred["DataId"]] = camel_dict_to_snake_dict(pred)
- for condition in module.params['conditions']:
- desired_conditions[condition['type']][condition['name']] = condition
+ for condition in module.params["conditions"]:
+ desired_conditions[condition["type"]][condition["name"]] = condition
- reverse_condition_types = dict((v['type'], k) for (k, v) in MATCH_LOOKUP.items())
- for condition in rule['Predicates']:
- existing_conditions[reverse_condition_types[condition['Type']]][condition['DataId']] = camel_dict_to_snake_dict(condition)
+ reverse_condition_types = dict((v["type"], k) for (k, v) in MATCH_LOOKUP.items())
+ for condition in rule["Predicates"]:
+ existing_conditions[reverse_condition_types[condition["Type"]]][condition["DataId"]] = camel_dict_to_snake_dict(
+ condition
+ )
insertions = list()
deletions = list()
for condition_type in desired_conditions:
- for (condition_name, condition) in desired_conditions[condition_type].items():
+ for condition_name, condition in desired_conditions[condition_type].items():
if condition_name not in all_conditions[condition_type]:
- module.fail_json(msg="Condition %s of type %s does not exist" % (condition_name, condition_type))
- condition['data_id'] = all_conditions[condition_type][condition_name]['data_id']
- if condition['data_id'] not in existing_conditions[condition_type]:
+ module.fail_json(msg=f"Condition {condition_name} of type {condition_type} does not exist")
+ condition["data_id"] = all_conditions[condition_type][condition_name]["data_id"]
+ if condition["data_id"] not in existing_conditions[condition_type]:
insertions.append(format_for_insertion(condition))
- if module.params['purge_conditions']:
+ if module.params["purge_conditions"]:
for condition_type in existing_conditions:
- deletions.extend([format_for_deletion(condition) for condition in existing_conditions[condition_type].values()
- if not all_conditions[condition_type][condition['data_id']]['name'] in desired_conditions[condition_type]])
+ deletions.extend(
+ [
+ format_for_deletion(condition)
+ for condition in existing_conditions[condition_type].values()
+ if not all_conditions[condition_type][condition["data_id"]]["name"]
+ in desired_conditions[condition_type]
+ ]
+ )
changed = bool(insertions or deletions)
- update = {
- 'RuleId': rule_id,
- 'Updates': insertions + deletions
- }
+ update = {"RuleId": rule_id, "Updates": insertions + deletions}
if changed:
try:
run_func_with_change_token_backoff(client, module, update, client.update_rule, wait=True)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Could not update rule conditions')
+ module.fail_json_aws(e, msg="Could not update rule conditions")
return changed, get_rule(client, module, rule_id)
def format_for_insertion(condition):
- return dict(Action='INSERT',
- Predicate=dict(Negated=condition['negated'],
- Type=MATCH_LOOKUP[condition['type']]['type'],
- DataId=condition['data_id']))
+ return dict(
+ Action="INSERT",
+ Predicate=dict(
+ Negated=condition["negated"], Type=MATCH_LOOKUP[condition["type"]]["type"], DataId=condition["data_id"]
+ ),
+ )
def format_for_deletion(condition):
- return dict(Action='DELETE',
- Predicate=dict(Negated=condition['negated'],
- Type=condition['type'],
- DataId=condition['data_id']))
+ return dict(
+ Action="DELETE",
+ Predicate=dict(Negated=condition["negated"], Type=condition["type"], DataId=condition["data_id"]),
+ )
def remove_rule_conditions(client, module, rule_id):
- conditions = get_rule(client, module, rule_id)['Predicates']
+ conditions = get_rule(client, module, rule_id)["Predicates"]
updates = [format_for_deletion(camel_dict_to_snake_dict(condition)) for condition in conditions]
try:
- run_func_with_change_token_backoff(client, module, {'RuleId': rule_id, 'Updates': updates}, client.update_rule)
+ run_func_with_change_token_backoff(client, module, {"RuleId": rule_id, "Updates": updates}, client.update_rule)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Could not remove rule conditions')
+ module.fail_json_aws(e, msg="Could not remove rule conditions")
def ensure_rule_present(client, module):
- name = module.params['name']
+ name = module.params["name"]
rule_id = get_rule_by_name(client, module, name)
params = dict()
if rule_id:
return find_and_update_rule(client, module, rule_id)
else:
- params['Name'] = module.params['name']
- metric_name = module.params['metric_name']
+ params["Name"] = module.params["name"]
+ metric_name = module.params["metric_name"]
if not metric_name:
- metric_name = re.sub(r'[^a-zA-Z0-9]', '', module.params['name'])
- params['MetricName'] = metric_name
+ metric_name = re.sub(r"[^a-zA-Z0-9]", "", module.params["name"])
+ params["MetricName"] = metric_name
try:
- new_rule = run_func_with_change_token_backoff(client, module, params, client.create_rule)['Rule']
+ new_rule = run_func_with_change_token_backoff(client, module, params, client.create_rule)["Rule"]
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Could not create rule')
- return find_and_update_rule(client, module, new_rule['RuleId'])
+ module.fail_json_aws(e, msg="Could not create rule")
+ return find_and_update_rule(client, module, new_rule["RuleId"])
def find_rule_in_web_acls(client, module, rule_id):
web_acls_in_use = []
try:
- if client.__class__.__name__ == 'WAF':
+ if client.__class__.__name__ == "WAF":
all_web_acls = list_web_acls_with_backoff(client)
- elif client.__class__.__name__ == 'WAFRegional':
+ elif client.__class__.__name__ == "WAFRegional":
all_web_acls = list_regional_web_acls_with_backoff(client)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Could not list Web ACLs')
+ module.fail_json_aws(e, msg="Could not list Web ACLs")
for web_acl in all_web_acls:
try:
- web_acl_details = get_web_acl_with_backoff(client, web_acl['WebACLId'])
+ web_acl_details = get_web_acl_with_backoff(client, web_acl["WebACLId"])
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Could not get Web ACL details')
- if rule_id in [rule['RuleId'] for rule in web_acl_details['Rules']]:
- web_acls_in_use.append(web_acl_details['Name'])
+ module.fail_json_aws(e, msg="Could not get Web ACL details")
+ if rule_id in [rule["RuleId"] for rule in web_acl_details["Rules"]]:
+ web_acls_in_use.append(web_acl_details["Name"])
return web_acls_in_use
def ensure_rule_absent(client, module):
- rule_id = get_rule_by_name(client, module, module.params['name'])
+ rule_id = get_rule_by_name(client, module, module.params["name"])
in_use_web_acls = find_rule_in_web_acls(client, module, rule_id)
if in_use_web_acls:
- web_acl_names = ', '.join(in_use_web_acls)
- module.fail_json(msg="Rule %s is in use by Web ACL(s) %s" %
- (module.params['name'], web_acl_names))
+ web_acl_names = ", ".join(in_use_web_acls)
+ module.fail_json(msg=f"Rule {module.params['name']} is in use by Web ACL(s) {web_acl_names}")
if rule_id:
remove_rule_conditions(client, module, rule_id)
try:
- return True, run_func_with_change_token_backoff(client, module, {'RuleId': rule_id}, client.delete_rule, wait=True)
+ return True, run_func_with_change_token_backoff(
+ client, module, {"RuleId": rule_id}, client.delete_rule, wait=True
+ )
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Could not delete rule')
+ module.fail_json_aws(e, msg="Could not delete rule")
return False, {}
@@ -335,17 +342,17 @@ def main():
argument_spec = dict(
name=dict(required=True),
metric_name=dict(),
- state=dict(default='present', choices=['present', 'absent']),
- conditions=dict(type='list', elements='dict'),
- purge_conditions=dict(type='bool', default=False),
- waf_regional=dict(type='bool', default=False),
+ state=dict(default="present", choices=["present", "absent"]),
+ conditions=dict(type="list", elements="dict"),
+ purge_conditions=dict(type="bool", default=False),
+ waf_regional=dict(type="bool", default=False),
)
module = AnsibleAWSModule(argument_spec=argument_spec)
- state = module.params.get('state')
+ state = module.params.get("state")
- resource = 'waf' if not module.params['waf_regional'] else 'waf-regional'
+ resource = "waf" if not module.params["waf_regional"] else "waf-regional"
client = module.client(resource)
- if state == 'present':
+ if state == "present":
(changed, results) = ensure_rule_present(client, module)
else:
(changed, results) = ensure_rule_absent(client, module)
@@ -353,5 +360,5 @@ def main():
module.exit_json(changed=changed, rule=camel_dict_to_snake_dict(results))
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/waf_web_acl.py b/ansible_collections/community/aws/plugins/modules/waf_web_acl.py
index 9d5ad59e4..021ca568d 100644
--- a/ansible_collections/community/aws/plugins/modules/waf_web_acl.py
+++ b/ansible_collections/community/aws/plugins/modules/waf_web_acl.py
@@ -1,12 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
module: waf_web_acl
short_description: Create and delete WAF Web ACLs
version_added: 1.0.0
@@ -19,10 +17,6 @@ description:
author:
- Mike Mochan (@mmochan)
- Will Thames (@willthames)
-extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
- - amazon.aws.boto3
options:
name:
@@ -85,27 +79,32 @@ options:
default: false
required: false
type: bool
-'''
-
-EXAMPLES = r'''
- - name: create web ACL
- community.aws.waf_web_acl:
- name: my_web_acl
- rules:
- - name: my_rule
- priority: 1
- action: block
- default_action: block
- purge_rules: true
- state: present
-
- - name: delete the web acl
- community.aws.waf_web_acl:
- name: my_web_acl
- state: absent
-'''
-
-RETURN = r'''
+
+extends_documentation_fragment:
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
+
+EXAMPLES = r"""
+- name: create web ACL
+ community.aws.waf_web_acl:
+ name: my_web_acl
+ rules:
+ - name: my_rule
+ priority: 1
+ action: block
+ default_action: block
+ purge_rules: true
+ state: present
+
+- name: delete the web acl
+ community.aws.waf_web_acl:
+ name: my_web_acl
+ state: absent
+"""
+
+RETURN = r"""
web_acl:
description: contents of the Web ACL.
returned: always
@@ -158,29 +157,29 @@ web_acl:
returned: always
type: str
sample: 10fff965-4b6b-46e2-9d78-24f6d2e2d21c
-'''
+"""
+
+import re
try:
import botocore
except ImportError:
pass # handled by AnsibleAWSModule
-import re
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
+from ansible_collections.amazon.aws.plugins.module_utils.waf import list_regional_rules_with_backoff
+from ansible_collections.amazon.aws.plugins.module_utils.waf import list_regional_web_acls_with_backoff
+from ansible_collections.amazon.aws.plugins.module_utils.waf import list_rules_with_backoff
+from ansible_collections.amazon.aws.plugins.module_utils.waf import list_web_acls_with_backoff
+from ansible_collections.amazon.aws.plugins.module_utils.waf import run_func_with_change_token_backoff
from ansible_collections.amazon.aws.plugins.module_utils.waiters import get_waiter
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.waf import (
- list_regional_rules_with_backoff,
- list_regional_web_acls_with_backoff,
- list_rules_with_backoff,
- list_web_acls_with_backoff,
- run_func_with_change_token_backoff,
-)
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
def get_web_acl_by_name(client, module, name):
- acls = [d['WebACLId'] for d in list_web_acls(client, module) if d['Name'] == name]
+ acls = [d["WebACLId"] for d in list_web_acls(client, module) if d["Name"] == name]
if acls:
return acls[0]
else:
@@ -188,91 +187,93 @@ def get_web_acl_by_name(client, module, name):
def create_rule_lookup(client, module):
- if client.__class__.__name__ == 'WAF':
+ if client.__class__.__name__ == "WAF":
try:
rules = list_rules_with_backoff(client)
- return dict((rule['Name'], rule) for rule in rules)
+ return dict((rule["Name"], rule) for rule in rules)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Could not list rules')
- elif client.__class__.__name__ == 'WAFRegional':
+ module.fail_json_aws(e, msg="Could not list rules")
+ elif client.__class__.__name__ == "WAFRegional":
try:
rules = list_regional_rules_with_backoff(client)
- return dict((rule['Name'], rule) for rule in rules)
+ return dict((rule["Name"], rule) for rule in rules)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Could not list regional rules')
+ module.fail_json_aws(e, msg="Could not list regional rules")
def get_web_acl(client, module, web_acl_id):
try:
- return client.get_web_acl(WebACLId=web_acl_id)['WebACL']
+ return client.get_web_acl(WebACLId=web_acl_id)["WebACL"]
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Could not get Web ACL with id %s' % web_acl_id)
+ module.fail_json_aws(e, msg=f"Could not get Web ACL with id {web_acl_id}")
-def list_web_acls(client, module,):
- if client.__class__.__name__ == 'WAF':
+def list_web_acls(
+ client,
+ module,
+):
+ if client.__class__.__name__ == "WAF":
try:
return list_web_acls_with_backoff(client)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Could not get Web ACLs')
- elif client.__class__.__name__ == 'WAFRegional':
+ module.fail_json_aws(e, msg="Could not get Web ACLs")
+ elif client.__class__.__name__ == "WAFRegional":
try:
return list_regional_web_acls_with_backoff(client)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Could not get Web ACLs')
+ module.fail_json_aws(e, msg="Could not get Web ACLs")
def find_and_update_web_acl(client, module, web_acl_id):
acl = get_web_acl(client, module, web_acl_id)
rule_lookup = create_rule_lookup(client, module)
- existing_rules = acl['Rules']
- desired_rules = [{'RuleId': rule_lookup[rule['name']]['RuleId'],
- 'Priority': rule['priority'],
- 'Action': {'Type': rule['action'].upper()},
- 'Type': rule.get('type', 'regular').upper()}
- for rule in module.params['rules']]
+ existing_rules = acl["Rules"]
+ desired_rules = [
+ {
+ "RuleId": rule_lookup[rule["name"]]["RuleId"],
+ "Priority": rule["priority"],
+ "Action": {"Type": rule["action"].upper()},
+ "Type": rule.get("type", "regular").upper(),
+ }
+ for rule in module.params["rules"]
+ ]
missing = [rule for rule in desired_rules if rule not in existing_rules]
extras = []
- if module.params['purge_rules']:
+ if module.params["purge_rules"]:
extras = [rule for rule in existing_rules if rule not in desired_rules]
- insertions = [format_for_update(rule, 'INSERT') for rule in missing]
- deletions = [format_for_update(rule, 'DELETE') for rule in extras]
+ insertions = [format_for_update(rule, "INSERT") for rule in missing]
+ deletions = [format_for_update(rule, "DELETE") for rule in extras]
changed = bool(insertions + deletions)
# Purge rules before adding new ones in case a deletion shares the same
# priority as an insertion.
- params = {
- 'WebACLId': acl['WebACLId'],
- 'DefaultAction': acl['DefaultAction']
- }
+ params = {"WebACLId": acl["WebACLId"], "DefaultAction": acl["DefaultAction"]}
change_tokens = []
if deletions:
try:
- params['Updates'] = deletions
+ params["Updates"] = deletions
result = run_func_with_change_token_backoff(client, module, params, client.update_web_acl)
- change_tokens.append(result['ChangeToken'])
+ change_tokens.append(result["ChangeToken"])
get_waiter(
- client, 'change_token_in_sync',
- ).wait(
- ChangeToken=result['ChangeToken']
- )
+ client,
+ "change_token_in_sync",
+ ).wait(ChangeToken=result["ChangeToken"])
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Could not update Web ACL')
+ module.fail_json_aws(e, msg="Could not update Web ACL")
if insertions:
try:
- params['Updates'] = insertions
+ params["Updates"] = insertions
result = run_func_with_change_token_backoff(client, module, params, client.update_web_acl)
- change_tokens.append(result['ChangeToken'])
+ change_tokens.append(result["ChangeToken"])
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Could not update Web ACL')
+ module.fail_json_aws(e, msg="Could not update Web ACL")
if change_tokens:
for token in change_tokens:
get_waiter(
- client, 'change_token_in_sync',
- ).wait(
- ChangeToken=token
- )
+ client,
+ "change_token_in_sync",
+ ).wait(ChangeToken=token)
if changed:
acl = get_web_acl(client, module, web_acl_id)
return changed, acl
@@ -282,77 +283,79 @@ def format_for_update(rule, action):
return dict(
Action=action,
ActivatedRule=dict(
- Priority=rule['Priority'],
- RuleId=rule['RuleId'],
- Action=dict(
- Type=rule['Action']['Type']
- )
- )
+ Priority=rule["Priority"],
+ RuleId=rule["RuleId"],
+ Action=dict(Type=rule["Action"]["Type"]),
+ ),
)
def remove_rules_from_web_acl(client, module, web_acl_id):
acl = get_web_acl(client, module, web_acl_id)
- deletions = [format_for_update(rule, 'DELETE') for rule in acl['Rules']]
+ deletions = [format_for_update(rule, "DELETE") for rule in acl["Rules"]]
try:
- params = {'WebACLId': acl['WebACLId'], 'DefaultAction': acl['DefaultAction'], 'Updates': deletions}
+ params = {"WebACLId": acl["WebACLId"], "DefaultAction": acl["DefaultAction"], "Updates": deletions}
run_func_with_change_token_backoff(client, module, params, client.update_web_acl)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Could not remove rule')
+ module.fail_json_aws(e, msg="Could not remove rule")
def ensure_web_acl_present(client, module):
changed = False
result = None
- name = module.params['name']
+ name = module.params["name"]
web_acl_id = get_web_acl_by_name(client, module, name)
if web_acl_id:
(changed, result) = find_and_update_web_acl(client, module, web_acl_id)
else:
- metric_name = module.params['metric_name']
+ metric_name = module.params["metric_name"]
if not metric_name:
- metric_name = re.sub(r'[^A-Za-z0-9]', '', module.params['name'])
- default_action = module.params['default_action'].upper()
+ metric_name = re.sub(r"[^A-Za-z0-9]", "", module.params["name"])
+ default_action = module.params["default_action"].upper()
try:
- params = {'Name': name, 'MetricName': metric_name, 'DefaultAction': {'Type': default_action}}
+ params = {"Name": name, "MetricName": metric_name, "DefaultAction": {"Type": default_action}}
new_web_acl = run_func_with_change_token_backoff(client, module, params, client.create_web_acl)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Could not create Web ACL')
- (changed, result) = find_and_update_web_acl(client, module, new_web_acl['WebACL']['WebACLId'])
+ module.fail_json_aws(e, msg="Could not create Web ACL")
+ (changed, result) = find_and_update_web_acl(client, module, new_web_acl["WebACL"]["WebACLId"])
return changed, result
def ensure_web_acl_absent(client, module):
- web_acl_id = get_web_acl_by_name(client, module, module.params['name'])
+ web_acl_id = get_web_acl_by_name(client, module, module.params["name"])
if web_acl_id:
web_acl = get_web_acl(client, module, web_acl_id)
- if web_acl['Rules']:
+ if web_acl["Rules"]:
remove_rules_from_web_acl(client, module, web_acl_id)
try:
- run_func_with_change_token_backoff(client, module, {'WebACLId': web_acl_id}, client.delete_web_acl, wait=True)
+ run_func_with_change_token_backoff(
+ client, module, {"WebACLId": web_acl_id}, client.delete_web_acl, wait=True
+ )
return True, {}
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
- module.fail_json_aws(e, msg='Could not delete Web ACL')
+ module.fail_json_aws(e, msg="Could not delete Web ACL")
return False, {}
def main():
argument_spec = dict(
name=dict(required=True),
- default_action=dict(choices=['block', 'allow', 'count']),
+ default_action=dict(choices=["block", "allow", "count"]),
metric_name=dict(),
- state=dict(default='present', choices=['present', 'absent']),
- rules=dict(type='list', elements='dict'),
- purge_rules=dict(type='bool', default=False),
- waf_regional=dict(type='bool', default=False)
+ state=dict(default="present", choices=["present", "absent"]),
+ rules=dict(type="list", elements="dict"),
+ purge_rules=dict(type="bool", default=False),
+ waf_regional=dict(type="bool", default=False),
+ )
+ module = AnsibleAWSModule(
+ argument_spec=argument_spec,
+ required_if=[["state", "present", ["default_action", "rules"]]],
)
- module = AnsibleAWSModule(argument_spec=argument_spec,
- required_if=[['state', 'present', ['default_action', 'rules']]])
- state = module.params.get('state')
+ state = module.params.get("state")
- resource = 'waf' if not module.params['waf_regional'] else 'waf-regional'
+ resource = "waf" if not module.params["waf_regional"] else "waf-regional"
client = module.client(resource)
- if state == 'present':
+ if state == "present":
(changed, results) = ensure_web_acl_present(client, module)
else:
(changed, results) = ensure_web_acl_absent(client, module)
@@ -360,5 +363,5 @@ def main():
module.exit_json(changed=changed, web_acl=camel_dict_to_snake_dict(results))
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/wafv2_ip_set.py b/ansible_collections/community/aws/plugins/modules/wafv2_ip_set.py
index 7a9011e9b..b96ba0cb1 100644
--- a/ansible_collections/community/aws/plugins/modules/wafv2_ip_set.py
+++ b/ansible_collections/community/aws/plugins/modules/wafv2_ip_set.py
@@ -1,11 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: wafv2_ip_set
version_added: 1.5.0
@@ -63,14 +62,13 @@ notes:
- Support for I(purge_tags) was added in release 4.0.0.
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
- - amazon.aws.boto3
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.tags
+ - amazon.aws.boto3
+"""
-'''
-
-EXAMPLES = '''
+EXAMPLES = r"""
- name: test ip set
wafv2_ip_set:
name: test02
@@ -84,9 +82,9 @@ EXAMPLES = '''
tags:
A: B
C: D
-'''
+"""
-RETURN = """
+RETURN = r"""
addresses:
description: Current addresses of the ip set
sample:
@@ -117,13 +115,16 @@ name:
"""
try:
- from botocore.exceptions import ClientError, BotoCoreError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
except ImportError:
pass # caught by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_tag_list
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import ansible_dict_to_boto3_tag_list
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
from ansible_collections.community.aws.plugins.module_utils.wafv2 import describe_wafv2_tags
from ansible_collections.community.aws.plugins.module_utils.wafv2 import ensure_wafv2_tags
@@ -137,41 +138,36 @@ class IpSet:
self.existing_set, self.id, self.locktoken, self.arn = self.get_set()
def description(self):
- return self.existing_set.get('Description')
+ return self.existing_set.get("Description")
def _format_set(self, ip_set):
if ip_set is None:
return None
- return camel_dict_to_snake_dict(self.existing_set, ignore_list=['tags'])
+ return camel_dict_to_snake_dict(self.existing_set, ignore_list=["tags"])
def get(self):
return self._format_set(self.existing_set)
def remove(self):
try:
- response = self.wafv2.delete_ip_set(
- Name=self.name,
- Scope=self.scope,
- Id=self.id,
- LockToken=self.locktoken
- )
+ response = self.wafv2.delete_ip_set(Name=self.name, Scope=self.scope, Id=self.id, LockToken=self.locktoken)
except (BotoCoreError, ClientError) as e:
self.fail_json_aws(e, msg="Failed to remove wafv2 ip set.")
return {}
def create(self, description, ip_address_version, addresses, tags):
req_obj = {
- 'Name': self.name,
- 'Scope': self.scope,
- 'IPAddressVersion': ip_address_version,
- 'Addresses': addresses,
+ "Name": self.name,
+ "Scope": self.scope,
+ "IPAddressVersion": ip_address_version,
+ "Addresses": addresses,
}
if description:
- req_obj['Description'] = description
+ req_obj["Description"] = description
if tags:
- req_obj['Tags'] = ansible_dict_to_boto3_tag_list(tags)
+ req_obj["Tags"] = ansible_dict_to_boto3_tag_list(tags)
try:
response = self.wafv2.create_ip_set(**req_obj)
@@ -183,15 +179,15 @@ class IpSet:
def update(self, description, addresses):
req_obj = {
- 'Name': self.name,
- 'Scope': self.scope,
- 'Id': self.id,
- 'Addresses': addresses,
- 'LockToken': self.locktoken
+ "Name": self.name,
+ "Scope": self.scope,
+ "Id": self.id,
+ "Addresses": addresses,
+ "LockToken": self.locktoken,
}
if description:
- req_obj['Description'] = description
+ req_obj["Description"] = description
try:
response = self.wafv2.update_ip_set(**req_obj)
@@ -207,38 +203,31 @@ class IpSet:
id = None
arn = None
locktoken = None
- for item in response.get('IPSets'):
- if item.get('Name') == self.name:
- id = item.get('Id')
- locktoken = item.get('LockToken')
- arn = item.get('ARN')
+ for item in response.get("IPSets"):
+ if item.get("Name") == self.name:
+ id = item.get("Id")
+ locktoken = item.get("LockToken")
+ arn = item.get("ARN")
if id:
try:
- existing_set = self.wafv2.get_ip_set(
- Name=self.name,
- Scope=self.scope,
- Id=id
- ).get('IPSet')
+ existing_set = self.wafv2.get_ip_set(Name=self.name, Scope=self.scope, Id=id).get("IPSet")
except (BotoCoreError, ClientError) as e:
self.fail_json_aws(e, msg="Failed to get wafv2 ip set.")
tags = describe_wafv2_tags(self.wafv2, arn, self.fail_json_aws)
- existing_set['tags'] = tags
+ existing_set["tags"] = tags
return existing_set, id, locktoken, arn
def list(self, Nextmarker=None):
# there is currently no paginator for wafv2
- req_obj = {
- 'Scope': self.scope,
- 'Limit': 100
- }
+ req_obj = {"Scope": self.scope, "Limit": 100}
if Nextmarker:
- req_obj['NextMarker'] = Nextmarker
+ req_obj["NextMarker"] = Nextmarker
try:
response = self.wafv2.list_ip_sets(**req_obj)
- if response.get('NextMarker'):
- response['IPSets'] += self.list(Nextmarker=response.get('NextMarker')).get('IPSets')
+ if response.get("NextMarker"):
+ response["IPSets"] += self.list(Nextmarker=response.get("NextMarker")).get("IPSets")
except (BotoCoreError, ClientError) as e:
self.fail_json_aws(e, msg="Failed to list wafv2 ip set.")
@@ -248,11 +237,11 @@ class IpSet:
def compare(existing_set, addresses, purge_addresses, state):
diff = False
new_rules = []
- existing_rules = existing_set.get('addresses')
- if state == 'present':
+ existing_rules = existing_set.get("addresses")
+ if state == "present":
if purge_addresses:
new_rules = addresses
- if sorted(addresses) != sorted(existing_set.get('addresses')):
+ if sorted(addresses) != sorted(existing_set.get("addresses")):
diff = True
else:
@@ -274,23 +263,22 @@ def compare(existing_set, addresses, purge_addresses, state):
def main():
-
arg_spec = dict(
- state=dict(type='str', required=True, choices=['present', 'absent']),
- name=dict(type='str', required=True),
- scope=dict(type='str', required=True, choices=['CLOUDFRONT', 'REGIONAL']),
- description=dict(type='str'),
- ip_address_version=dict(type='str', choices=['IPV4', 'IPV6']),
- addresses=dict(type='list', elements='str'),
- tags=dict(type='dict', aliases=['resource_tags']),
- purge_tags=dict(type='bool', default=True),
- purge_addresses=dict(type='bool', default=True),
+ state=dict(type="str", required=True, choices=["present", "absent"]),
+ name=dict(type="str", required=True),
+ scope=dict(type="str", required=True, choices=["CLOUDFRONT", "REGIONAL"]),
+ description=dict(type="str"),
+ ip_address_version=dict(type="str", choices=["IPV4", "IPV6"]),
+ addresses=dict(type="list", elements="str"),
+ tags=dict(type="dict", aliases=["resource_tags"]),
+ purge_tags=dict(type="bool", default=True),
+ purge_addresses=dict(type="bool", default=True),
)
module = AnsibleAWSModule(
argument_spec=arg_spec,
supports_check_mode=True,
- required_if=[['state', 'present', ['ip_address_version', 'addresses']]]
+ required_if=[["state", "present", ["ip_address_version", "addresses"]]],
)
state = module.params.get("state")
@@ -304,17 +292,18 @@ def main():
purge_addresses = module.params.get("purge_addresses")
check_mode = module.check_mode
- wafv2 = module.client('wafv2')
+ wafv2 = module.client("wafv2")
change = False
retval = {}
ip_set = IpSet(wafv2, name, scope, module.fail_json_aws)
- if state == 'present':
-
+ if state == "present":
if ip_set.get():
- tags_updated = ensure_wafv2_tags(wafv2, ip_set.arn, tags, purge_tags, module.fail_json_aws, module.check_mode)
+ tags_updated = ensure_wafv2_tags(
+ wafv2, ip_set.arn, tags, purge_tags, module.fail_json_aws, module.check_mode
+ )
ips_updated, addresses = compare(ip_set.get(), addresses, purge_addresses, state)
description_updated = bool(description) and ip_set.description() != description
change = ips_updated or description_updated or tags_updated
@@ -322,32 +311,23 @@ def main():
if module.check_mode:
pass
elif ips_updated or description_updated:
- retval = ip_set.update(
- description=description,
- addresses=addresses
- )
+ retval = ip_set.update(description=description, addresses=addresses)
elif tags_updated:
retval, id, locktoken, arn = ip_set.get_set()
else:
if not check_mode:
retval = ip_set.create(
- description=description,
- ip_address_version=ip_address_version,
- addresses=addresses,
- tags=tags
+ description=description, ip_address_version=ip_address_version, addresses=addresses, tags=tags
)
change = True
- if state == 'absent':
+ if state == "absent":
if ip_set.get():
if addresses:
if len(addresses) > 0:
change, addresses = compare(ip_set.get(), addresses, purge_addresses, state)
if change and not check_mode:
- retval = ip_set.update(
- description=description,
- addresses=addresses
- )
+ retval = ip_set.update(description=description, addresses=addresses)
else:
if not check_mode:
retval = ip_set.remove()
@@ -356,5 +336,5 @@ def main():
module.exit_json(changed=change, **retval)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/wafv2_ip_set_info.py b/ansible_collections/community/aws/plugins/modules/wafv2_ip_set_info.py
index b92c9a816..caca5cd70 100644
--- a/ansible_collections/community/aws/plugins/modules/wafv2_ip_set_info.py
+++ b/ansible_collections/community/aws/plugins/modules/wafv2_ip_set_info.py
@@ -1,11 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: wafv2_ip_set_info
version_added: 1.5.0
@@ -28,20 +27,19 @@ options:
type: str
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
-
-'''
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
- name: test ip set
wafv2_ip_set_info:
name: test02
scope: REGIONAL
-'''
+"""
-RETURN = """
+RETURN = r"""
addresses:
description: Current addresses of the ip set
sample:
@@ -72,28 +70,29 @@ name:
"""
try:
- from botocore.exceptions import ClientError, BotoCoreError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
except ImportError:
pass # caught by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
from ansible_collections.community.aws.plugins.module_utils.wafv2 import describe_wafv2_tags
def list_ip_sets(wafv2, scope, fail_json_aws, Nextmarker=None):
# there is currently no paginator for wafv2
- req_obj = {
- 'Scope': scope,
- 'Limit': 100
- }
+ req_obj = {"Scope": scope, "Limit": 100}
if Nextmarker:
- req_obj['NextMarker'] = Nextmarker
+ req_obj["NextMarker"] = Nextmarker
try:
response = wafv2.list_ip_sets(**req_obj)
- if response.get('NextMarker'):
- response['IPSets'] += list_ip_sets(wafv2, scope, fail_json_aws, Nextmarker=response.get('NextMarker')).get('IPSets')
+ if response.get("NextMarker"):
+ response["IPSets"] += list_ip_sets(wafv2, scope, fail_json_aws, Nextmarker=response.get("NextMarker")).get(
+ "IPSets"
+ )
except (BotoCoreError, ClientError) as e:
fail_json_aws(e, msg="Failed to list wafv2 ip set")
return response
@@ -101,21 +100,15 @@ def list_ip_sets(wafv2, scope, fail_json_aws, Nextmarker=None):
def get_ip_set(wafv2, name, scope, id, fail_json_aws):
try:
- response = wafv2.get_ip_set(
- Name=name,
- Scope=scope,
- Id=id
- )
+ response = wafv2.get_ip_set(Name=name, Scope=scope, Id=id)
except (BotoCoreError, ClientError) as e:
fail_json_aws(e, msg="Failed to get wafv2 ip set")
return response
def main():
-
arg_spec = dict(
- name=dict(type='str', required=True),
- scope=dict(type='str', required=True, choices=['CLOUDFRONT', 'REGIONAL'])
+ name=dict(type="str", required=True), scope=dict(type="str", required=True, choices=["CLOUDFRONT", "REGIONAL"])
)
module = AnsibleAWSModule(
@@ -126,26 +119,26 @@ def main():
name = module.params.get("name")
scope = module.params.get("scope")
- wafv2 = module.client('wafv2')
+ wafv2 = module.client("wafv2")
# check if ip set exist
response = list_ip_sets(wafv2, scope, module.fail_json_aws)
id = None
- for item in response.get('IPSets'):
- if item.get('Name') == name:
- id = item.get('Id')
- arn = item.get('ARN')
+ for item in response.get("IPSets"):
+ if item.get("Name") == name:
+ id = item.get("Id")
+ arn = item.get("ARN")
retval = {}
existing_set = None
if id:
existing_set = get_ip_set(wafv2, name, scope, id, module.fail_json_aws)
- retval = camel_dict_to_snake_dict(existing_set.get('IPSet'))
- retval['tags'] = describe_wafv2_tags(wafv2, arn, module.fail_json_aws) or {}
+ retval = camel_dict_to_snake_dict(existing_set.get("IPSet"))
+ retval["tags"] = describe_wafv2_tags(wafv2, arn, module.fail_json_aws) or {}
module.exit_json(**retval)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/wafv2_resources.py b/ansible_collections/community/aws/plugins/modules/wafv2_resources.py
index 527ee1087..b36f51712 100644
--- a/ansible_collections/community/aws/plugins/modules/wafv2_resources.py
+++ b/ansible_collections/community/aws/plugins/modules/wafv2_resources.py
@@ -1,11 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: wafv2_resources
version_added: 1.5.0
@@ -37,22 +36,21 @@ options:
required: true
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
-
-'''
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
- name: add test alb to waf string03
community.aws.wafv2_resources:
name: string03
scope: REGIONAL
state: present
arn: "arn:aws:elasticloadbalancing:eu-central-1:111111111:loadbalancer/app/test03/dd83ea041ba6f933"
-'''
+"""
-RETURN = """
+RETURN = r"""
resource_arns:
description: Current resources where the wafv2 is applied on
sample:
@@ -62,22 +60,20 @@ resource_arns:
"""
try:
- from botocore.exceptions import ClientError, BotoCoreError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
except ImportError:
pass # caught by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
from ansible_collections.community.aws.plugins.module_utils.wafv2 import wafv2_list_web_acls
def get_web_acl(wafv2, name, scope, id, fail_json_aws):
try:
- response = wafv2.get_web_acl(
- Name=name,
- Scope=scope,
- Id=id
- )
+ response = wafv2.get_web_acl(Name=name, Scope=scope, Id=id)
except (BotoCoreError, ClientError) as e:
fail_json_aws(e, msg="Failed to get wafv2 web acl.")
return response
@@ -85,9 +81,7 @@ def get_web_acl(wafv2, name, scope, id, fail_json_aws):
def list_wafv2_resources(wafv2, arn, fail_json_aws):
try:
- response = wafv2.list_resources_for_web_acl(
- WebACLArn=arn
- )
+ response = wafv2.list_resources_for_web_acl(WebACLArn=arn)
except (BotoCoreError, ClientError) as e:
fail_json_aws(e, msg="Failed to list wafv2 web acl.")
return response
@@ -95,10 +89,7 @@ def list_wafv2_resources(wafv2, arn, fail_json_aws):
def add_wafv2_resources(wafv2, waf_arn, arn, fail_json_aws):
try:
- response = wafv2.associate_web_acl(
- WebACLArn=waf_arn,
- ResourceArn=arn
- )
+ response = wafv2.associate_web_acl(WebACLArn=waf_arn, ResourceArn=arn)
except (BotoCoreError, ClientError) as e:
fail_json_aws(e, msg="Failed to add wafv2 web acl.")
return response
@@ -106,27 +97,24 @@ def add_wafv2_resources(wafv2, waf_arn, arn, fail_json_aws):
def remove_resources(wafv2, arn, fail_json_aws):
try:
- response = wafv2.disassociate_web_acl(
- ResourceArn=arn
- )
+ response = wafv2.disassociate_web_acl(ResourceArn=arn)
except (BotoCoreError, ClientError) as e:
fail_json_aws(e, msg="Failed to remove wafv2 web acl.")
return response
def main():
-
arg_spec = dict(
- state=dict(type='str', required=True, choices=['present', 'absent']),
- name=dict(type='str'),
- scope=dict(type='str', choices=['CLOUDFRONT', 'REGIONAL']),
- arn=dict(type='str', required=True)
+ state=dict(type="str", required=True, choices=["present", "absent"]),
+ name=dict(type="str"),
+ scope=dict(type="str", choices=["CLOUDFRONT", "REGIONAL"]),
+ arn=dict(type="str", required=True),
)
module = AnsibleAWSModule(
argument_spec=arg_spec,
supports_check_mode=True,
- required_if=[['state', 'present', ['name', 'scope']]]
+ required_if=[["state", "present", ["name", "scope"]]],
)
state = module.params.get("state")
@@ -135,7 +123,7 @@ def main():
arn = module.params.get("arn")
check_mode = module.check_mode
- wafv2 = module.client('wafv2')
+ wafv2 = module.client("wafv2")
# check if web acl exists
@@ -145,26 +133,26 @@ def main():
retval = {}
change = False
- for item in response.get('WebACLs'):
- if item.get('Name') == name:
- id = item.get('Id')
+ for item in response.get("WebACLs"):
+ if item.get("Name") == name:
+ id = item.get("Id")
if id:
existing_acl = get_web_acl(wafv2, name, scope, id, module.fail_json_aws)
- waf_arn = existing_acl.get('WebACL').get('ARN')
+ waf_arn = existing_acl.get("WebACL").get("ARN")
retval = list_wafv2_resources(wafv2, waf_arn, module.fail_json_aws)
- if state == 'present':
+ if state == "present":
if retval:
- if arn not in retval.get('ResourceArns'):
+ if arn not in retval.get("ResourceArns"):
change = True
if not check_mode:
retval = add_wafv2_resources(wafv2, waf_arn, arn, module.fail_json_aws)
- elif state == 'absent':
+ elif state == "absent":
if retval:
- if arn in retval.get('ResourceArns'):
+ if arn in retval.get("ResourceArns"):
change = True
if not check_mode:
retval = remove_resources(wafv2, arn, module.fail_json_aws)
@@ -172,5 +160,5 @@ def main():
module.exit_json(changed=change, **camel_dict_to_snake_dict(retval))
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/wafv2_resources_info.py b/ansible_collections/community/aws/plugins/modules/wafv2_resources_info.py
index 3a2a7b5dd..5cafee1f6 100644
--- a/ansible_collections/community/aws/plugins/modules/wafv2_resources_info.py
+++ b/ansible_collections/community/aws/plugins/modules/wafv2_resources_info.py
@@ -1,11 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: wafv2_resources_info
version_added: 1.5.0
@@ -28,20 +27,19 @@ options:
type: str
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.boto3
-
-'''
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.boto3
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
- name: get web acl
community.aws.wafv2_resources_info:
name: string03
scope: REGIONAL
-'''
+"""
-RETURN = """
+RETURN = r"""
resource_arns:
description: Current resources where the wafv2 is applied on
sample:
@@ -51,22 +49,20 @@ resource_arns:
"""
try:
- from botocore.exceptions import ClientError, BotoCoreError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
except ImportError:
pass # caught by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
from ansible_collections.community.aws.plugins.module_utils.wafv2 import wafv2_list_web_acls
def get_web_acl(wafv2, name, scope, id, fail_json_aws):
try:
- response = wafv2.get_web_acl(
- Name=name,
- Scope=scope,
- Id=id
- )
+ response = wafv2.get_web_acl(Name=name, Scope=scope, Id=id)
except (BotoCoreError, ClientError) as e:
fail_json_aws(e, msg="Failed to get wafv2 web acl.")
return response
@@ -78,19 +74,16 @@ def list_web_acls(wafv2, scope, fail_json_aws):
def list_wafv2_resources(wafv2, arn, fail_json_aws):
try:
- response = wafv2.list_resources_for_web_acl(
- WebACLArn=arn
- )
+ response = wafv2.list_resources_for_web_acl(WebACLArn=arn)
except (BotoCoreError, ClientError) as e:
fail_json_aws(e, msg="Failed to list wafv2 resources.")
return response
def main():
-
arg_spec = dict(
- name=dict(type='str', required=True),
- scope=dict(type='str', required=True, choices=['CLOUDFRONT', 'REGIONAL'])
+ name=dict(type="str", required=True),
+ scope=dict(type="str", required=True, choices=["CLOUDFRONT", "REGIONAL"]),
)
module = AnsibleAWSModule(
@@ -101,25 +94,25 @@ def main():
name = module.params.get("name")
scope = module.params.get("scope")
- wafv2 = module.client('wafv2')
+ wafv2 = module.client("wafv2")
# check if web acl exists
response = list_web_acls(wafv2, scope, module.fail_json_aws)
id = None
retval = {}
- for item in response.get('WebACLs'):
- if item.get('Name') == name:
- id = item.get('Id')
+ for item in response.get("WebACLs"):
+ if item.get("Name") == name:
+ id = item.get("Id")
if id:
existing_acl = get_web_acl(wafv2, name, scope, id, module.fail_json_aws)
- arn = existing_acl.get('WebACL').get('ARN')
+ arn = existing_acl.get("WebACL").get("ARN")
retval = camel_dict_to_snake_dict(list_wafv2_resources(wafv2, arn, module.fail_json_aws))
module.exit_json(**retval)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/wafv2_rule_group.py b/ansible_collections/community/aws/plugins/modules/wafv2_rule_group.py
index 8e46853c8..e2a7fd1d4 100644
--- a/ansible_collections/community/aws/plugins/modules/wafv2_rule_group.py
+++ b/ansible_collections/community/aws/plugins/modules/wafv2_rule_group.py
@@ -1,11 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: wafv2_rule_group
version_added: 1.5.0
@@ -67,14 +66,13 @@ options:
type: bool
extends_documentation_fragment:
-- amazon.aws.aws
-- amazon.aws.ec2
-- amazon.aws.tags
-- amazon.aws.boto3
-
-'''
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
+ - amazon.aws.tags
+ - amazon.aws.boto3
+"""
-EXAMPLES = '''
+EXAMPLES = r"""
- name: change description
community.aws.wafv2_rule_group:
name: test02
@@ -150,9 +148,9 @@ EXAMPLES = '''
A: B
C: D
register: out
-'''
+"""
-RETURN = """
+RETURN = r"""
arn:
description: Rule group arn
sample: arn:aws:wafv2:eu-central-1:11111111:regional/rulegroup/test02/6e90c01a-e4eb-43e5-b6aa-b1604cedf7d7
@@ -200,19 +198,22 @@ visibility_config:
"""
try:
- from botocore.exceptions import ClientError, BotoCoreError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
except ImportError:
pass # caught by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_tag_list
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import snake_dict_to_camel_dict
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+from ansible.module_utils.common.dict_transformations import snake_dict_to_camel_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import ansible_dict_to_boto3_tag_list
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
from ansible_collections.community.aws.plugins.module_utils.wafv2 import compare_priority_rules
-from ansible_collections.community.aws.plugins.module_utils.wafv2 import wafv2_list_rule_groups
-from ansible_collections.community.aws.plugins.module_utils.wafv2 import wafv2_snake_dict_to_camel_dict
from ansible_collections.community.aws.plugins.module_utils.wafv2 import describe_wafv2_tags
from ansible_collections.community.aws.plugins.module_utils.wafv2 import ensure_wafv2_tags
+from ansible_collections.community.aws.plugins.module_utils.wafv2 import wafv2_list_rule_groups
+from ansible_collections.community.aws.plugins.module_utils.wafv2 import wafv2_snake_dict_to_camel_dict
class RuleGroup:
@@ -226,20 +227,20 @@ class RuleGroup:
def update(self, description, rules, sampled_requests, cloudwatch_metrics, metric_name):
req_obj = {
- 'Name': self.name,
- 'Scope': self.scope,
- 'Id': self.id,
- 'Rules': rules,
- 'LockToken': self.locktoken,
- 'VisibilityConfig': {
- 'SampledRequestsEnabled': sampled_requests,
- 'CloudWatchMetricsEnabled': cloudwatch_metrics,
- 'MetricName': metric_name
- }
+ "Name": self.name,
+ "Scope": self.scope,
+ "Id": self.id,
+ "Rules": rules,
+ "LockToken": self.locktoken,
+ "VisibilityConfig": {
+ "SampledRequestsEnabled": sampled_requests,
+ "CloudWatchMetricsEnabled": cloudwatch_metrics,
+ "MetricName": metric_name,
+ },
}
if description:
- req_obj['Description'] = description
+ req_obj["Description"] = description
try:
response = self.wafv2.update_rule_group(**req_obj)
@@ -251,11 +252,11 @@ class RuleGroup:
if self.id is None:
response = self.list()
- for item in response.get('RuleGroups'):
- if item.get('Name') == self.name:
- self.id = item.get('Id')
- self.locktoken = item.get('LockToken')
- self.arn = item.get('ARN')
+ for item in response.get("RuleGroups"):
+ if item.get("Name") == self.name:
+ self.id = item.get("Id")
+ self.locktoken = item.get("LockToken")
+ self.arn = item.get("ARN")
return self.refresh_group()
@@ -263,18 +264,14 @@ class RuleGroup:
existing_group = None
if self.id:
try:
- response = self.wafv2.get_rule_group(
- Name=self.name,
- Scope=self.scope,
- Id=self.id
- )
- existing_group = response.get('RuleGroup')
- self.locktoken = response.get('LockToken')
+ response = self.wafv2.get_rule_group(Name=self.name, Scope=self.scope, Id=self.id)
+ existing_group = response.get("RuleGroup")
+ self.locktoken = response.get("LockToken")
except (BotoCoreError, ClientError) as e:
self.fail_json_aws(e, msg="Failed to get wafv2 rule group.")
tags = describe_wafv2_tags(self.wafv2, self.arn, self.fail_json_aws)
- existing_group['tags'] = tags or {}
+ existing_group["tags"] = tags or {}
return existing_group
@@ -289,10 +286,7 @@ class RuleGroup:
def remove(self):
try:
response = self.wafv2.delete_rule_group(
- Name=self.name,
- Scope=self.scope,
- Id=self.id,
- LockToken=self.locktoken
+ Name=self.name, Scope=self.scope, Id=self.id, LockToken=self.locktoken
)
except (BotoCoreError, ClientError) as e:
self.fail_json_aws(e, msg="Failed to delete wafv2 rule group.")
@@ -300,22 +294,22 @@ class RuleGroup:
def create(self, capacity, description, rules, sampled_requests, cloudwatch_metrics, metric_name, tags):
req_obj = {
- 'Name': self.name,
- 'Scope': self.scope,
- 'Capacity': capacity,
- 'Rules': rules,
- 'VisibilityConfig': {
- 'SampledRequestsEnabled': sampled_requests,
- 'CloudWatchMetricsEnabled': cloudwatch_metrics,
- 'MetricName': metric_name
- }
+ "Name": self.name,
+ "Scope": self.scope,
+ "Capacity": capacity,
+ "Rules": rules,
+ "VisibilityConfig": {
+ "SampledRequestsEnabled": sampled_requests,
+ "CloudWatchMetricsEnabled": cloudwatch_metrics,
+ "MetricName": metric_name,
+ },
}
if description:
- req_obj['Description'] = description
+ req_obj["Description"] = description
if tags:
- req_obj['Tags'] = ansible_dict_to_boto3_tag_list(tags)
+ req_obj["Tags"] = ansible_dict_to_boto3_tag_list(tags)
try:
response = self.wafv2.create_rule_group(**req_obj)
@@ -328,26 +322,25 @@ class RuleGroup:
def main():
-
arg_spec = dict(
- state=dict(type='str', required=True, choices=['present', 'absent']),
- name=dict(type='str', required=True),
- scope=dict(type='str', required=True, choices=['CLOUDFRONT', 'REGIONAL']),
- capacity=dict(type='int'),
- description=dict(type='str'),
- rules=dict(type='list', elements='dict'),
- sampled_requests=dict(type='bool', default=False),
- cloudwatch_metrics=dict(type='bool', default=True),
- metric_name=dict(type='str'),
- tags=dict(type='dict', aliases=['resource_tags']),
- purge_tags=dict(default=True, type='bool'),
- purge_rules=dict(default=True, type='bool'),
+ state=dict(type="str", required=True, choices=["present", "absent"]),
+ name=dict(type="str", required=True),
+ scope=dict(type="str", required=True, choices=["CLOUDFRONT", "REGIONAL"]),
+ capacity=dict(type="int"),
+ description=dict(type="str"),
+ rules=dict(type="list", elements="dict"),
+ sampled_requests=dict(type="bool", default=False),
+ cloudwatch_metrics=dict(type="bool", default=True),
+ metric_name=dict(type="str"),
+ tags=dict(type="dict", aliases=["resource_tags"]),
+ purge_tags=dict(default=True, type="bool"),
+ purge_rules=dict(default=True, type="bool"),
)
module = AnsibleAWSModule(
argument_spec=arg_spec,
supports_check_mode=True,
- required_if=[['state', 'present', ['capacity', 'rules']]]
+ required_if=[["state", "present", ["capacity", "rules"]]],
)
state = module.params.get("state")
@@ -372,31 +365,26 @@ def main():
if not metric_name:
metric_name = name
- wafv2 = module.client('wafv2')
+ wafv2 = module.client("wafv2")
rule_group = RuleGroup(wafv2, name, scope, module.fail_json_aws)
change = False
retval = {}
- if state == 'present':
+ if state == "present":
if rule_group.get():
- tagging_change = ensure_wafv2_tags(wafv2, rule_group.arn, tags, purge_tags,
- module.fail_json_aws, module.check_mode)
- rules_change, rules = compare_priority_rules(rule_group.get().get('Rules'), rules, purge_rules, state)
- description_change = bool(description) and (rule_group.get().get('Description') != description)
+ tagging_change = ensure_wafv2_tags(
+ wafv2, rule_group.arn, tags, purge_tags, module.fail_json_aws, module.check_mode
+ )
+ rules_change, rules = compare_priority_rules(rule_group.get().get("Rules"), rules, purge_rules, state)
+ description_change = bool(description) and (rule_group.get().get("Description") != description)
change = tagging_change or rules_change or description_change
retval = rule_group.get()
if module.check_mode:
# In check mode nothing changes...
pass
elif rules_change or description_change:
- retval = rule_group.update(
- description,
- rules,
- sampled_requests,
- cloudwatch_metrics,
- metric_name
- )
+ retval = rule_group.update(description, rules, sampled_requests, cloudwatch_metrics, metric_name)
elif tagging_change:
retval = rule_group.refresh_group()
@@ -404,35 +392,25 @@ def main():
change = True
if not check_mode:
retval = rule_group.create(
- capacity,
- description,
- rules,
- sampled_requests,
- cloudwatch_metrics,
- metric_name,
- tags
+ capacity, description, rules, sampled_requests, cloudwatch_metrics, metric_name, tags
)
- elif state == 'absent':
+ elif state == "absent":
if rule_group.get():
if rules:
if len(rules) > 0:
- change, rules = compare_priority_rules(rule_group.get().get('Rules'), rules, purge_rules, state)
+ change, rules = compare_priority_rules(rule_group.get().get("Rules"), rules, purge_rules, state)
if change and not check_mode:
retval = rule_group.update(
- description,
- rules,
- sampled_requests,
- cloudwatch_metrics,
- metric_name
+ description, rules, sampled_requests, cloudwatch_metrics, metric_name
)
else:
change = True
if not check_mode:
retval = rule_group.remove()
- module.exit_json(changed=change, **camel_dict_to_snake_dict(retval, ignore_list=['tags']))
+ module.exit_json(changed=change, **camel_dict_to_snake_dict(retval, ignore_list=["tags"]))
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/wafv2_rule_group_info.py b/ansible_collections/community/aws/plugins/modules/wafv2_rule_group_info.py
index a42bea0c2..58862a9a5 100644
--- a/ansible_collections/community/aws/plugins/modules/wafv2_rule_group_info.py
+++ b/ansible_collections/community/aws/plugins/modules/wafv2_rule_group_info.py
@@ -1,11 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: wafv2_rule_group_info
version_added: 1.5.0
@@ -15,11 +14,6 @@ short_description: wafv2_web_acl_info
description:
- Get informations about existing wafv2 rule groups.
options:
- state:
- description:
- - This option does nothing, has been deprecated, and will be removed in a release after 2022-12-01.
- required: false
- type: str
name:
description:
- The name of the rule group.
@@ -33,21 +27,19 @@ options:
type: str
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
+"""
-'''
-
-EXAMPLES = '''
+EXAMPLES = r"""
- name: rule group info
community.aws.wafv2_rule_group_info:
name: test02
- state: present
scope: REGIONAL
-'''
+"""
-RETURN = """
+RETURN = r"""
arn:
description: Rule group arn
sample: arn:aws:wafv2:eu-central-1:11111111:regional/rulegroup/test02/6e90c01a-e4eb-43e5-b6aa-b1604cedf7d7
@@ -95,23 +87,21 @@ visibility_config:
"""
try:
- from botocore.exceptions import ClientError, BotoCoreError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
except ImportError:
pass # caught by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict
-from ansible_collections.community.aws.plugins.module_utils.wafv2 import wafv2_list_rule_groups
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
from ansible_collections.community.aws.plugins.module_utils.wafv2 import describe_wafv2_tags
+from ansible_collections.community.aws.plugins.module_utils.wafv2 import wafv2_list_rule_groups
def get_rule_group(wafv2, name, scope, id, fail_json_aws):
try:
- response = wafv2.get_rule_group(
- Name=name,
- Scope=scope,
- Id=id
- )
+ response = wafv2.get_rule_group(Name=name, Scope=scope, Id=id)
except (BotoCoreError, ClientError) as e:
fail_json_aws(e, msg="Failed to get wafv2 rule group.")
return response
@@ -119,46 +109,39 @@ def get_rule_group(wafv2, name, scope, id, fail_json_aws):
def main():
arg_spec = dict(
- state=dict(type='str', required=False),
- name=dict(type='str', required=True),
- scope=dict(type='str', required=True, choices=['CLOUDFRONT', 'REGIONAL'])
+ name=dict(type="str", required=True),
+ scope=dict(type="str", required=True, choices=["CLOUDFRONT", "REGIONAL"]),
)
module = AnsibleAWSModule(
argument_spec=arg_spec,
- supports_check_mode=True
+ supports_check_mode=True,
)
- state = module.params.get("state")
name = module.params.get("name")
scope = module.params.get("scope")
- wafv2 = module.client('wafv2')
-
- if state:
- module.deprecate(
- 'The state parameter does nothing, has been deprecated, and will be removed in a future release.',
- version='6.0.0', collection_name='community.aws')
+ wafv2 = module.client("wafv2")
# check if rule group exists
response = wafv2_list_rule_groups(wafv2, scope, module.fail_json_aws)
id = None
retval = {}
- for item in response.get('RuleGroups'):
- if item.get('Name') == name:
- id = item.get('Id')
- arn = item.get('ARN')
+ for item in response.get("RuleGroups"):
+ if item.get("Name") == name:
+ id = item.get("Id")
+ arn = item.get("ARN")
existing_group = None
if id:
existing_group = get_rule_group(wafv2, name, scope, id, module.fail_json_aws)
- retval = camel_dict_to_snake_dict(existing_group.get('RuleGroup'))
+ retval = camel_dict_to_snake_dict(existing_group.get("RuleGroup"))
tags = describe_wafv2_tags(wafv2, arn, module.fail_json_aws)
- retval['tags'] = tags or {}
+ retval["tags"] = tags or {}
module.exit_json(**retval)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/wafv2_web_acl.py b/ansible_collections/community/aws/plugins/modules/wafv2_web_acl.py
index f91fe64e6..054c093c5 100644
--- a/ansible_collections/community/aws/plugins/modules/wafv2_web_acl.py
+++ b/ansible_collections/community/aws/plugins/modules/wafv2_web_acl.py
@@ -1,11 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: wafv2_web_acl
version_added: 1.5.0
@@ -89,7 +88,6 @@ options:
- A map of custom response keys and content bodies. Define response bodies here and reference them in the rules by providing
- the key of the body dictionary element.
- Each element must have a unique dict key and in the dict two keys for I(content_type) and I(content).
- - Requires botocore >= 1.20.40
type: dict
version_added: 3.1.0
purge_rules:
@@ -102,14 +100,13 @@ notes:
- Support for the I(purge_tags) parameter was added in release 4.0.0.
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.tags
- amazon.aws.boto3
+"""
-'''
-
-EXAMPLES = '''
+EXAMPLES = r"""
- name: Create test web acl
community.aws.wafv2_web_acl:
name: test05
@@ -249,10 +246,9 @@ EXAMPLES = '''
content: '{ message: "Your request has been blocked due to too many HTTP requests coming from your IP" }'
region: us-east-1
state: present
+"""
-'''
-
-RETURN = """
+RETURN = r"""
arn:
description: web acl arn
sample: arn:aws:wafv2:eu-central-1:123456789012:regional/webacl/test05/318c1ab9-fa74-4b3b-a974-f92e25106f61
@@ -315,14 +311,17 @@ visibility_config:
"""
try:
- from botocore.exceptions import ClientError, BotoCoreError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
except ImportError:
pass # caught by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_tag_list
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import snake_dict_to_camel_dict
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+from ansible.module_utils.common.dict_transformations import snake_dict_to_camel_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.tagging import ansible_dict_to_boto3_tag_list
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
from ansible_collections.community.aws.plugins.module_utils.wafv2 import compare_priority_rules
from ansible_collections.community.aws.plugins.module_utils.wafv2 import describe_wafv2_tags
from ansible_collections.community.aws.plugins.module_utils.wafv2 import ensure_wafv2_tags
@@ -338,26 +337,35 @@ class WebACL:
self.fail_json_aws = fail_json_aws
self.existing_acl, self.id, self.locktoken = self.get_web_acl()
- def update(self, default_action, description, rules, sampled_requests, cloudwatch_metrics, metric_name, custom_response_bodies):
+ def update(
+ self,
+ default_action,
+ description,
+ rules,
+ sampled_requests,
+ cloudwatch_metrics,
+ metric_name,
+ custom_response_bodies,
+ ):
req_obj = {
- 'Name': self.name,
- 'Scope': self.scope,
- 'Id': self.id,
- 'DefaultAction': default_action,
- 'Rules': rules,
- 'VisibilityConfig': {
- 'SampledRequestsEnabled': sampled_requests,
- 'CloudWatchMetricsEnabled': cloudwatch_metrics,
- 'MetricName': metric_name
+ "Name": self.name,
+ "Scope": self.scope,
+ "Id": self.id,
+ "DefaultAction": default_action,
+ "Rules": rules,
+ "VisibilityConfig": {
+ "SampledRequestsEnabled": sampled_requests,
+ "CloudWatchMetricsEnabled": cloudwatch_metrics,
+ "MetricName": metric_name,
},
- 'LockToken': self.locktoken
+ "LockToken": self.locktoken,
}
if description:
- req_obj['Description'] = description
+ req_obj["Description"] = description
if custom_response_bodies:
- req_obj['CustomResponseBodies'] = custom_response_bodies
+ req_obj["CustomResponseBodies"] = custom_response_bodies
try:
response = self.wafv2.update_web_acl(**req_obj)
@@ -369,12 +377,7 @@ class WebACL:
def remove(self):
try:
- response = self.wafv2.delete_web_acl(
- Name=self.name,
- Scope=self.scope,
- Id=self.id,
- LockToken=self.locktoken
- )
+ response = self.wafv2.delete_web_acl(Name=self.name, Scope=self.scope, Id=self.id, LockToken=self.locktoken)
except (BotoCoreError, ClientError) as e:
self.fail_json_aws(e, msg="Failed to remove wafv2 web acl.")
return response
@@ -391,47 +394,53 @@ class WebACL:
existing_acl = None
response = self.list()
- for item in response.get('WebACLs'):
- if item.get('Name') == self.name:
- id = item.get('Id')
- locktoken = item.get('LockToken')
- arn = item.get('ARN')
+ for item in response.get("WebACLs"):
+ if item.get("Name") == self.name:
+ id = item.get("Id")
+ locktoken = item.get("LockToken")
+ arn = item.get("ARN")
if id:
try:
- existing_acl = self.wafv2.get_web_acl(
- Name=self.name,
- Scope=self.scope,
- Id=id
- )
+ existing_acl = self.wafv2.get_web_acl(Name=self.name, Scope=self.scope, Id=id)
except (BotoCoreError, ClientError) as e:
self.fail_json_aws(e, msg="Failed to get wafv2 web acl.")
tags = describe_wafv2_tags(self.wafv2, arn, self.fail_json_aws)
- existing_acl['tags'] = tags
+ existing_acl["tags"] = tags
return existing_acl, id, locktoken
def list(self):
return wafv2_list_web_acls(self.wafv2, self.scope, self.fail_json_aws)
- def create(self, default_action, rules, sampled_requests, cloudwatch_metrics, metric_name, tags, description, custom_response_bodies):
+ def create(
+ self,
+ default_action,
+ rules,
+ sampled_requests,
+ cloudwatch_metrics,
+ metric_name,
+ tags,
+ description,
+ custom_response_bodies,
+ ):
req_obj = {
- 'Name': self.name,
- 'Scope': self.scope,
- 'DefaultAction': default_action,
- 'Rules': rules,
- 'VisibilityConfig': {
- 'SampledRequestsEnabled': sampled_requests,
- 'CloudWatchMetricsEnabled': cloudwatch_metrics,
- 'MetricName': metric_name
- }
+ "Name": self.name,
+ "Scope": self.scope,
+ "DefaultAction": default_action,
+ "Rules": rules,
+ "VisibilityConfig": {
+ "SampledRequestsEnabled": sampled_requests,
+ "CloudWatchMetricsEnabled": cloudwatch_metrics,
+ "MetricName": metric_name,
+ },
}
if custom_response_bodies:
- req_obj['CustomResponseBodies'] = custom_response_bodies
+ req_obj["CustomResponseBodies"] = custom_response_bodies
if description:
- req_obj['Description'] = description
+ req_obj["Description"] = description
if tags:
- req_obj['Tags'] = ansible_dict_to_boto3_tag_list(tags)
+ req_obj["Tags"] = ansible_dict_to_boto3_tag_list(tags)
try:
response = self.wafv2.create_web_acl(**req_obj)
@@ -443,7 +452,6 @@ class WebACL:
def format_result(result):
-
# We were returning details of the Web ACL inside a "web_acl" parameter on
# creation, keep returning it to avoid breaking existing playbooks, but also
# return what the docs said we return (and returned when no change happened)
@@ -451,31 +459,30 @@ def format_result(result):
if "WebACL" in retval:
retval.update(retval["WebACL"])
- return camel_dict_to_snake_dict(retval, ignore_list=['tags'])
+ return camel_dict_to_snake_dict(retval, ignore_list=["tags"])
def main():
-
arg_spec = dict(
- state=dict(type='str', required=True, choices=['present', 'absent']),
- name=dict(type='str', required=True),
- scope=dict(type='str', required=True, choices=['CLOUDFRONT', 'REGIONAL']),
- description=dict(type='str'),
- default_action=dict(type='str', choices=['Block', 'Allow']),
- rules=dict(type='list', elements='dict'),
- sampled_requests=dict(type='bool', default=False),
- cloudwatch_metrics=dict(type='bool', default=True),
- metric_name=dict(type='str'),
- tags=dict(type='dict', aliases=['resource_tags']),
- purge_tags=dict(default=True, type='bool'),
- custom_response_bodies=dict(type='dict'),
- purge_rules=dict(default=True, type='bool'),
+ state=dict(type="str", required=True, choices=["present", "absent"]),
+ name=dict(type="str", required=True),
+ scope=dict(type="str", required=True, choices=["CLOUDFRONT", "REGIONAL"]),
+ description=dict(type="str"),
+ default_action=dict(type="str", choices=["Block", "Allow"]),
+ rules=dict(type="list", elements="dict"),
+ sampled_requests=dict(type="bool", default=False),
+ cloudwatch_metrics=dict(type="bool", default=True),
+ metric_name=dict(type="str"),
+ tags=dict(type="dict", aliases=["resource_tags"]),
+ purge_tags=dict(default=True, type="bool"),
+ custom_response_bodies=dict(type="dict"),
+ purge_rules=dict(default=True, type="bool"),
)
module = AnsibleAWSModule(
argument_spec=arg_spec,
supports_check_mode=True,
- required_if=[['state', 'present', ['default_action', 'rules']]]
+ required_if=[["state", "present", ["default_action", "rules"]]],
)
state = module.params.get("state")
@@ -494,16 +501,15 @@ def main():
custom_response_bodies = module.params.get("custom_response_bodies")
if custom_response_bodies:
- module.require_botocore_at_least('1.20.40', reason='to set custom response bodies')
custom_response_bodies = {}
for custom_name, body in module.params.get("custom_response_bodies").items():
custom_response_bodies[custom_name] = snake_dict_to_camel_dict(body, capitalize_first=True)
- if default_action == 'Block':
- default_action = {'Block': {}}
- elif default_action == 'Allow':
- default_action = {'Allow': {}}
+ if default_action == "Block":
+ default_action = {"Block": {}}
+ elif default_action == "Allow":
+ default_action = {"Allow": {}}
if rules:
rules = []
@@ -513,17 +519,19 @@ def main():
if not metric_name:
metric_name = name
- wafv2 = module.client('wafv2')
+ wafv2 = module.client("wafv2")
web_acl = WebACL(wafv2, name, scope, module.fail_json_aws)
change = False
retval = {}
- if state == 'present':
+ if state == "present":
if web_acl.get():
- tags_changed = ensure_wafv2_tags(wafv2, web_acl.get().get('WebACL').get('ARN'), tags, purge_tags, module.fail_json_aws, module.check_mode)
- change, rules = compare_priority_rules(web_acl.get().get('WebACL').get('Rules'), rules, purge_rules, state)
- change = change or (description and web_acl.get().get('WebACL').get('Description') != description)
- change = change or (default_action and web_acl.get().get('WebACL').get('DefaultAction') != default_action)
+ tags_changed = ensure_wafv2_tags(
+ wafv2, web_acl.get().get("WebACL").get("ARN"), tags, purge_tags, module.fail_json_aws, module.check_mode
+ )
+ change, rules = compare_priority_rules(web_acl.get().get("WebACL").get("Rules"), rules, purge_rules, state)
+ change = change or (description and web_acl.get().get("WebACL").get("Description") != description)
+ change = change or (default_action and web_acl.get().get("WebACL").get("DefaultAction") != default_action)
if change and not check_mode:
retval = web_acl.update(
@@ -533,7 +541,7 @@ def main():
sampled_requests,
cloudwatch_metrics,
metric_name,
- custom_response_bodies
+ custom_response_bodies,
)
elif tags_changed:
retval, id, locktoken = web_acl.get_web_acl()
@@ -553,14 +561,16 @@ def main():
metric_name,
tags,
description,
- custom_response_bodies
+ custom_response_bodies,
)
- elif state == 'absent':
+ elif state == "absent":
if web_acl.get():
if rules:
if len(rules) > 0:
- change, rules = compare_priority_rules(web_acl.get().get('WebACL').get('Rules'), rules, purge_rules, state)
+ change, rules = compare_priority_rules(
+ web_acl.get().get("WebACL").get("Rules"), rules, purge_rules, state
+ )
if change and not check_mode:
retval = web_acl.update(
default_action,
@@ -569,7 +579,7 @@ def main():
sampled_requests,
cloudwatch_metrics,
metric_name,
- custom_response_bodies
+ custom_response_bodies,
)
else:
change = True
@@ -579,5 +589,5 @@ def main():
module.exit_json(changed=change, **format_result(retval))
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/plugins/modules/wafv2_web_acl_info.py b/ansible_collections/community/aws/plugins/modules/wafv2_web_acl_info.py
index 13be05db5..e3cdc46e3 100644
--- a/ansible_collections/community/aws/plugins/modules/wafv2_web_acl_info.py
+++ b/ansible_collections/community/aws/plugins/modules/wafv2_web_acl_info.py
@@ -1,11 +1,10 @@
#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-DOCUMENTATION = '''
+DOCUMENTATION = r"""
---
module: wafv2_web_acl_info
version_added: 1.5.0
@@ -28,21 +27,20 @@ options:
type: str
extends_documentation_fragment:
- - amazon.aws.aws
- - amazon.aws.ec2
+ - amazon.aws.common.modules
+ - amazon.aws.region.modules
- amazon.aws.boto3
+"""
-'''
-
-EXAMPLES = '''
+EXAMPLES = r"""
- name: get web acl
community.aws.wafv2_web_acl_info:
name: test05
scope: REGIONAL
register: out
-'''
+"""
-RETURN = """
+RETURN = r"""
arn:
description: web acl arn
sample: arn:aws:wafv2:eu-central-1:11111111:regional/webacl/test05/318c1ab9-fa74-4b3b-a974-f92e25106f61
@@ -91,33 +89,30 @@ visibility_config:
"""
try:
- from botocore.exceptions import ClientError, BotoCoreError
+ from botocore.exceptions import BotoCoreError
+ from botocore.exceptions import ClientError
except ImportError:
pass # caught by AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule
from ansible_collections.community.aws.plugins.module_utils.wafv2 import describe_wafv2_tags
from ansible_collections.community.aws.plugins.module_utils.wafv2 import wafv2_list_web_acls
def get_web_acl(wafv2, name, scope, id, fail_json_aws):
try:
- response = wafv2.get_web_acl(
- Name=name,
- Scope=scope,
- Id=id
- )
+ response = wafv2.get_web_acl(Name=name, Scope=scope, Id=id)
except (BotoCoreError, ClientError) as e:
fail_json_aws(e, msg="Failed to get wafv2 web acl.")
return response
def main():
-
arg_spec = dict(
- name=dict(type='str', required=True),
- scope=dict(type='str', required=True, choices=['CLOUDFRONT', 'REGIONAL'])
+ name=dict(type="str", required=True),
+ scope=dict(type="str", required=True, choices=["CLOUDFRONT", "REGIONAL"]),
)
module = AnsibleAWSModule(
@@ -129,7 +124,7 @@ def main():
name = module.params.get("name")
scope = module.params.get("scope")
- wafv2 = module.client('wafv2')
+ wafv2 = module.client("wafv2")
# check if web acl exists
response = wafv2_list_web_acls(wafv2, scope, module.fail_json_aws)
@@ -137,19 +132,19 @@ def main():
arn = None
retval = {}
- for item in response.get('WebACLs'):
- if item.get('Name') == name:
- id = item.get('Id')
- arn = item.get('ARN')
+ for item in response.get("WebACLs"):
+ if item.get("Name") == name:
+ id = item.get("Id")
+ arn = item.get("ARN")
if id:
existing_acl = get_web_acl(wafv2, name, scope, id, module.fail_json_aws)
- retval = camel_dict_to_snake_dict(existing_acl.get('WebACL'))
+ retval = camel_dict_to_snake_dict(existing_acl.get("WebACL"))
tags = describe_wafv2_tags(wafv2, arn, module.fail_json_aws)
- retval['tags'] = tags
+ retval["tags"] = tags
module.exit_json(**retval)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/aws/pyproject.toml b/ansible_collections/community/aws/pyproject.toml
new file mode 100644
index 000000000..a3810fdc1
--- /dev/null
+++ b/ansible_collections/community/aws/pyproject.toml
@@ -0,0 +1,43 @@
+[tool.black]
+skip-string-normalization = false
+line-length = 120
+target-version = ['py37', 'py38']
+extend-exclude = '''
+/(
+ | plugins/module_utils/_version.py
+)/
+'''
+
+[tool.darker]
+revision = "origin/main.."
+
+src = [
+ "plugins",
+ "tests/unit",
+ "tests/integration",
+]
+
+[tool.isort]
+profile = "black"
+force_single_line = true
+line_length = 120
+
+src_paths = [
+ "plugins",
+ "tests/unit",
+ "tests/integration",
+]
+
+# Unstable
+skip = [
+ "aws_ssm.py"
+]
+
+sections = ["FUTURE", "STDLIB", "THIRDPARTY", "FIRSTPARTY", "ANSIBLE_CORE", "ANSIBLE_AMAZON_AWS", "ANSIBLE_COMMUNITY_AWS", "LOCALFOLDER"]
+known_third_party = ["botocore", "boto3"]
+known_ansible_core = ["ansible"]
+known_ansible_amazon_aws = ["ansible_collections.amazon.aws"]
+known_ansible_community_aws = ["ansible_collections.community.aws"]
+
+[tool.flynt]
+transform-joins = true
diff --git a/ansible_collections/community/aws/requirements.txt b/ansible_collections/community/aws/requirements.txt
index 0a1981f46..cd474e3b6 100644
--- a/ansible_collections/community/aws/requirements.txt
+++ b/ansible_collections/community/aws/requirements.txt
@@ -2,5 +2,5 @@
# - tests/unit/constraints.txt
# - tests/integration/constraints.txt
# - tests/integration/targets/setup_botocore_pip
-botocore>=1.21.0
-boto3>=1.18.0
+botocore>=1.29.0
+boto3>=1.26.0
diff --git a/ansible_collections/community/aws/test-requirements.txt b/ansible_collections/community/aws/test-requirements.txt
index 82ab3b8c6..03e59f596 100644
--- a/ansible_collections/community/aws/test-requirements.txt
+++ b/ansible_collections/community/aws/test-requirements.txt
@@ -10,12 +10,12 @@ pytest
pytest-forked
pytest-mock
pytest-xdist
+pytest-ansible ; python_version >= '3.7'
+git+https://github.com/ansible-community/pytest-ansible-units.git ; python_version < '3.7'
# Needed for ansible.utils.ipaddr in tests
netaddr
# Sometimes needed where we don't have features we need in modules
awscli
-# Used for comparing SSH Public keys to the Amazon fingerprints
-pycrypto
-# Used by ec2_win_password
+# Used for comparing SSH Public keys to the Amazon fingerprints and ec2_win_password
cryptography
diff --git a/ansible_collections/community/aws/tests/config.yml b/ansible_collections/community/aws/tests/config.yml
index 5112f7268..8d053169d 100644
--- a/ansible_collections/community/aws/tests/config.yml
+++ b/ansible_collections/community/aws/tests/config.yml
@@ -1,2 +1,2 @@
modules:
- python_requires: '>=3.6'
+ python_requires: '>=3.7'
diff --git a/ansible_collections/community/aws/tests/integration/constraints.txt b/ansible_collections/community/aws/tests/integration/constraints.txt
index cd546e7c2..f388e1f90 100644
--- a/ansible_collections/community/aws/tests/integration/constraints.txt
+++ b/ansible_collections/community/aws/tests/integration/constraints.txt
@@ -1,7 +1,11 @@
# Specifically run tests against the oldest versions that we support
-boto3==1.18.0
-botocore==1.21.0
+botocore==1.29.0
+boto3==1.26.0
# AWS CLI has `botocore==` dependencies, provide the one that matches botocore
# to avoid needing to download over a years worth of awscli wheels.
-awscli==1.20.0
+awscli==1.27.0
+
+# AWS CLI depends on PyYAML <5.5,>=3.10; the latest PyYAML release in that range, 5.4.1, fails to install.
+# Use a version in that range that is known to work (https://github.com/yaml/pyyaml/issues/736)
+PyYAML==5.3.1
diff --git a/ansible_collections/community/aws/tests/integration/requirements.txt b/ansible_collections/community/aws/tests/integration/requirements.txt
index 352e8b7ff..aa71c9681 100644
--- a/ansible_collections/community/aws/tests/integration/requirements.txt
+++ b/ansible_collections/community/aws/tests/integration/requirements.txt
@@ -8,6 +8,6 @@ virtualenv
# Sometimes needed where we don't have features we need in modules
awscli
# Used for comparing SSH Public keys to the Amazon fingerprints
-pycrypto
+cryptography
# Used by ec2_asg_scheduled_action
python-dateutil
diff --git a/ansible_collections/community/aws/tests/integration/requirements.yml b/ansible_collections/community/aws/tests/integration/requirements.yml
new file mode 100644
index 000000000..d3e5b3032
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/requirements.yml
@@ -0,0 +1,8 @@
+---
+collections:
+ - name: https://github.com/ansible-collections/amazon.aws.git
+ type: git
+ version: main
+ - ansible.windows
+ - community.crypto
+ - community.general
diff --git a/ansible_collections/community/aws/tests/integration/targets/accessanalyzer_validate_policy_info/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/accessanalyzer_validate_policy_info/tasks/main.yml
index 857a7c1b4..811ef9fb5 100644
--- a/ansible_collections/community/aws/tests/integration/targets/accessanalyzer_validate_policy_info/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/accessanalyzer_validate_policy_info/tasks/main.yml
@@ -1,10 +1,10 @@
---
- module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key | default(omit) }}'
- aws_secret_key: '{{ aws_secret_key | default(omit) }}'
- security_token: '{{ security_token | default(omit) }}'
- region: '{{ aws_region | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
+ region: '{{ aws_region }}'
block:
- name: get ARN of calling user
diff --git a/ansible_collections/community/aws/tests/integration/targets/acm_certificate/tasks/full_acm_test.yml b/ansible_collections/community/aws/tests/integration/targets/acm_certificate/tasks/full_acm_test.yml
index 5cbd156dd..4c45db05e 100644
--- a/ansible_collections/community/aws/tests/integration/targets/acm_certificate/tasks/full_acm_test.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/acm_certificate/tasks/full_acm_test.yml
@@ -2,15 +2,15 @@
module_defaults:
group/aws:
aws_region: '{{ aws_region }}'
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
block:
- name: list certs
- aws_acm_info: null
+ acm_certificate_info: null
register: list_all
- name: list certs with check mode
- aws_acm_info: null
+ acm_certificate_info: null
register: list_all_check
check_mode: yes # read-only task, should work the same as with no
- name: check certificate listing worked
@@ -20,12 +20,12 @@
- list_all_check.certificates is defined
- list_all.certificates == list_all_check.certificates
- name: ensure absent cert which doesn't exist - first time
- aws_acm:
+ acm_certificate:
name_tag: '{{ item.name }}'
state: absent
with_items: '{{ local_certs }}'
- name: ensure absent cert which doesn't exist - second time
- aws_acm:
+ acm_certificate:
name_tag: '{{ item[0].name }}'
state: absent
check_mode: '{{ item[1] }}'
@@ -39,7 +39,7 @@
- not item.changed
with_items: "{{ absent_start_two.results }}"
- name: list cert which shouldn't exist
- aws_acm_info:
+ acm_certificate_info:
tags:
Name: '{{ item.name }}'
register: list_tag
@@ -75,7 +75,7 @@
privatekey_path: '{{ item.priv_key }}'
selfsigned_digest: sha256
- name: upload certificate with check mode
- aws_acm:
+ acm_certificate:
name_tag: '{{ item.name }}'
certificate: '{{ lookup(''file'', item.cert ) }}'
private_key: '{{ lookup(''file'', item.priv_key ) }}'
@@ -84,7 +84,7 @@
register: upload_check
with_items: '{{ local_certs }}'
- name: check whether cert was uploaded in check mode
- aws_acm_info:
+ acm_certificate_info:
tags:
Name: '{{ item.name }}'
register: list_after_check_mode_upload
@@ -96,7 +96,7 @@
- upload_check.changed
- (item.certificates | length) == 0
- name: upload certificates first time
- aws_acm:
+ acm_certificate:
name_tag: '{{ item.name }}'
certificate: '{{ lookup(''file'', item.cert ) }}'
private_key: '{{ lookup(''file'', item.priv_key ) }}'
@@ -119,7 +119,7 @@
original_cert: '{{ item.item }}'
prev_task: '{{ item }}'
- name: fetch data about cert just uploaded, by ARN
- aws_acm_info:
+ acm_certificate_info:
certificate_arn: '{{ item.certificate.arn }}'
register: fetch_after_up
with_items: '{{ upload.results }}'
@@ -138,7 +138,7 @@
upload_result: '{{ item.item }}'
original_cert: '{{ item.item.item }}'
- name: fetch data about cert just uploaded, by name
- aws_acm_info:
+ acm_certificate_info:
tags:
Name: '{{ original_cert.name }}'
register: fetch_after_up_name
@@ -161,7 +161,7 @@
upload_result: '{{ item.item }}'
original_cert: '{{ item.item.item }}'
- name: fetch data about cert just uploaded, by domain name
- aws_acm_info:
+ acm_certificate_info:
domain_name: '{{ original_cert.domain }}'
register: fetch_after_up_domain
with_items: '{{ upload.results }}'
@@ -182,7 +182,7 @@
upload_result: '{{ item.item }}'
original_cert: '{{ item.item.item }}'
- name: upload certificates again, check not changed
- aws_acm:
+ acm_certificate:
name_tag: '{{ item.name }}'
certificate: '{{ lookup(''file'', item.cert ) }}'
private_key: '{{ lookup(''file'', item.priv_key ) }}'
@@ -191,7 +191,7 @@
with_items: '{{ local_certs }}'
failed_when: upload2.changed
- name: update first cert with body of the second, first time, check mode
- aws_acm:
+ acm_certificate:
state: present
name_tag: '{{ local_certs[0].name }}'
certificate: '{{ lookup(''file'', local_certs[1].cert ) }}'
@@ -203,7 +203,7 @@
that:
- overwrite_check.changed
- name: check previous tasks did not change real cert
- aws_acm_info:
+ acm_certificate_info:
tags:
Name: '{{ local_certs[0].name }}'
register: fetch_after_overwrite_check
@@ -217,7 +217,7 @@
- '''Name'' in fetch_after_overwrite_check.certificates[0].tags'
- fetch_after_overwrite_check.certificates[0].tags['Name'] == local_certs[0].name
- name: update first cert with body of the second, first real time
- aws_acm:
+ acm_certificate:
state: present
name_tag: '{{ local_certs[0].name }}'
certificate: '{{ lookup(''file'', local_certs[1].cert ) }}'
@@ -232,7 +232,7 @@
- overwrite.certificate.domain_name == local_certs[1].domain
- overwrite.changed
- name: check update was sucessfull
- aws_acm_info:
+ acm_certificate_info:
tags:
Name: '{{ local_certs[0].name }}'
register: fetch_after_overwrite
@@ -246,7 +246,7 @@
- '''Name'' in fetch_after_overwrite.certificates[0].tags'
- fetch_after_overwrite.certificates[0].tags['Name'] == local_certs[0].name
- name: fetch other cert
- aws_acm_info:
+ acm_certificate_info:
tags:
Name: '{{ local_certs[1].name }}'
register: check_after_overwrite
@@ -260,7 +260,7 @@
- '''Name'' in check_after_overwrite.certificates[0].tags'
- check_after_overwrite.certificates[0].tags['Name'] == local_certs[1].name
- name: update first cert with body of the second again
- aws_acm:
+ acm_certificate:
state: present
name_tag: '{{ local_certs[0].name }}'
certificate: '{{ lookup(''file'', local_certs[1].cert ) }}'
@@ -275,7 +275,7 @@
- overwrite2.certificate.domain_name == local_certs[1].domain
- not overwrite2.changed
- name: delete certs 1 and 2 in check mode
- aws_acm:
+ acm_certificate:
state: absent
domain_name: '{{ local_certs[1].domain }}'
check_mode: yes
@@ -285,7 +285,7 @@
that:
- delete_both_check.changed
- name: fetch info for certs 1 and 2
- aws_acm_info:
+ acm_certificate_info:
tags:
Name: '{{ local_certs[item].name }}'
register: check_del_one_check
@@ -298,7 +298,7 @@
that:
- (item.certificates | length) == 1
- name: delete certs 1 and 2 real
- aws_acm:
+ acm_certificate:
state: absent
domain_name: '{{ local_certs[1].domain }}'
register: delete_both
@@ -310,7 +310,7 @@
- upload.results[0].certificate.arn in delete_both.arns
- delete_both.changed
- name: fetch info for certs 1 and 2
- aws_acm_info:
+ acm_certificate_info:
tags:
Name: '{{ local_certs[item].name }}'
register: check_del_one
@@ -327,7 +327,7 @@
assert:
that: (item.certificates | length) == 0
- name: check cert 3
- aws_acm_info:
+ acm_certificate_info:
tags:
Name: '{{ local_certs[2].name }}'
register: check_del_one_remain
@@ -336,7 +336,7 @@
that:
- (check_del_one_remain.certificates | length) == 1
- name: delete cert 3
- aws_acm:
+ acm_certificate:
state: absent
domain_name: '{{ local_certs[2].domain }}'
register: delete_third
@@ -348,13 +348,13 @@
- delete_third.arns[0] == upload.results[2].certificate.arn
- delete_third.changed
- name: check cert 3 was deleted
- aws_acm_info:
+ acm_certificate_info:
tags:
Name: '{{ local_certs[2].name }}'
register: check_del_three
failed_when: check_del_three.certificates | length != 0
- name: delete cert 3 again
- aws_acm:
+ acm_certificate:
state: absent
domain_name: '{{ local_certs[2].domain }}'
register: delete_third
@@ -365,7 +365,7 @@
- delete_third.arns | length == 0
- not delete_third.changed
- name: delete cert 3 again, check mode
- aws_acm:
+ acm_certificate:
state: absent
domain_name: '{{ local_certs[2].domain }}'
check_mode: yes
@@ -415,7 +415,7 @@
root_certificates:
- '{{ local_certs[item.ca].cert }}'
- name: upload chained cert, first chain, first time
- aws_acm:
+ acm_certificate:
name_tag: '{{ chained_cert.name }}'
certificate: '{{ lookup(''file'', chained_cert.chains[0].cert ) }}'
certificate_chain: '{{ chains.results[0].complete_chain | join(''
@@ -426,7 +426,7 @@
register: upload_chain
failed_when: not upload_chain.changed
- name: fetch chain of cert we just uploaded
- aws_acm_info:
+ acm_certificate_info:
tags:
Name: '{{ chained_cert.name }}'
register: check_chain
@@ -440,7 +440,7 @@
- (check_chain.certificates[0].certificate_chain | replace( ' ', '' ) | replace( '\n', '')) == ( chains.results[0].complete_chain | join( '\n' ) | replace( ' ', '' ) | replace( '\n', '') )
- (check_chain.certificates[0].certificate | replace( ' ', '' ) | replace( '\n', '')) == ( lookup('file', chained_cert.chains[0].cert ) | replace( ' ', '' ) | replace( '\n', '') )
- name: upload chained cert again, check not changed
- aws_acm:
+ acm_certificate:
name_tag: '{{ chained_cert.name }}'
certificate: '{{ lookup(''file'', chained_cert.chains[0].cert ) }}'
certificate_chain: '{{ chains.results[0].complete_chain | join(''
@@ -455,7 +455,7 @@
- upload_chain_2.certificate.arn == upload_chain.certificate.arn
- not upload_chain_2.changed
- name: upload chained cert, different chain
- aws_acm:
+ acm_certificate:
name_tag: '{{ chained_cert.name }}'
certificate: '{{ lookup(''file'', chained_cert.chains[1].cert ) }}'
certificate_chain: '{{ chains.results[1].complete_chain | join(''
@@ -470,7 +470,7 @@
- upload_chain_3.changed
- upload_chain_3.certificate.arn == upload_chain.certificate.arn
- name: fetch info about chain of cert we just updated
- aws_acm_info:
+ acm_certificate_info:
tags:
Name: '{{ chained_cert.name }}'
register: check_chain_2
@@ -480,7 +480,7 @@
- (check_chain_2.certificates[0].certificate_chain | replace( ' ', '' ) | replace( '\n', '')) == ( chains.results[1].complete_chain | join( '\n' ) | replace( ' ', '' ) | replace( '\n', '') )
- (check_chain_2.certificates[0].certificate | replace( ' ', '' ) | replace( '\n', '')) == ( lookup('file', chained_cert.chains[1].cert ) | replace( ' ', '' ) | replace( '\n', '') )
- name: delete chained cert
- aws_acm:
+ acm_certificate:
name_tag: '{{ chained_cert.name }}'
state: absent
register: delete_chain_3
@@ -491,13 +491,13 @@
- upload_chain.certificate.arn in delete_chain_3.arns
always:
- name: delete first bunch of certificates
- aws_acm:
+ acm_certificate:
name_tag: '{{ item.name }}'
state: absent
with_items: '{{ local_certs }}'
ignore_errors: true
- name: delete chained cert
- aws_acm:
+ acm_certificate:
state: absent
name_tag: '{{ chained_cert.name }}'
ignore_errors: true
diff --git a/ansible_collections/community/aws/tests/integration/targets/acm_certificate/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/acm_certificate/tasks/main.yml
index bf70587e6..5cc6d31a0 100644
--- a/ansible_collections/community/aws/tests/integration/targets/acm_certificate/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/acm_certificate/tasks/main.yml
@@ -2,9 +2,9 @@
module_defaults:
group/aws:
aws_region: '{{ aws_region }}'
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
block:
# The CI runs many of these tests in parallel
# Use this random ID to differentiate which resources
@@ -12,7 +12,7 @@
- set_fact:
aws_acm_test_uuid: "{{ (10**9) | random }}"
- name: attempt to delete cert without specifying required parameter
- aws_acm:
+ acm_certificate:
state: absent
register: result
ignore_errors: true
@@ -22,23 +22,23 @@
- 'result.failed'
- '"If ''state'' is specified as ''absent'' then exactly one of ''name_tag''" in result.msg'
- name: list certs
- aws_acm_info: null
+ acm_certificate_info: null
register: list_all
failed_when: list_all.certificates is not defined
- name: ensure absent cert which doesn't exist - first time
- aws_acm:
+ acm_certificate:
name_tag: '{{ item.name }}'
state: absent
with_items: '{{ local_certs }}'
- name: ensure absent cert which doesn't exist - second time
- aws_acm:
+ acm_certificate:
name_tag: '{{ item.name }}'
state: absent
with_items: '{{ local_certs }}'
register: absent_start_two
failed_when: absent_start_two.changed
- name: list cert which shouldn't exist
- aws_acm_info:
+ acm_certificate_info:
tags:
Name: '{{ item.name }}'
register: list_tag
@@ -71,7 +71,7 @@
- name: try to upload certificate, but name_tag conflicts with tags.Name
vars:
local_cert: '{{ local_certs[0] }}'
- aws_acm:
+ acm_certificate:
name_tag: '{{ local_cert.name }}'
certificate: '{{ lookup(''file'', local_cert.cert ) }}'
private_key: '{{ lookup(''file'', local_cert.priv_key ) }}'
@@ -88,7 +88,7 @@
- 'result.failed'
- '"conflicts with value of" in result.msg'
- name: upload certificates first time
- aws_acm:
+ acm_certificate:
name_tag: '{{ item.name }}'
certificate: '{{ lookup(''file'', item.cert ) }}'
private_key: '{{ lookup(''file'', item.priv_key ) }}'
@@ -115,7 +115,7 @@
original_cert: '{{ item.item }}'
prev_task: '{{ item }}'
- name: fetch data about cert just uploaded, by ARN
- aws_acm_info:
+ acm_certificate_info:
certificate_arn: '{{ item.certificate.arn }}'
register: fetch_after_up
with_items: '{{ upload.results }}'
@@ -138,7 +138,7 @@
upload_result: '{{ item.item }}'
original_cert: '{{ item.item.item }}'
- name: fetch data about cert just uploaded, by name
- aws_acm_info:
+ acm_certificate_info:
tags:
Name: '{{ original_cert.name }}'
register: fetch_after_up_name
@@ -161,7 +161,7 @@
upload_result: '{{ item.item }}'
original_cert: '{{ item.item.item }}'
- name: fetch data about cert just uploaded, by domain name
- aws_acm_info:
+ acm_certificate_info:
domain_name: '{{ original_cert.domain }}'
register: fetch_after_up_domain
with_items: '{{ upload.results }}'
@@ -182,7 +182,7 @@
upload_result: '{{ item.item }}'
original_cert: '{{ item.item.item }}'
- name: upload certificates again, check not changed
- aws_acm:
+ acm_certificate:
name_tag: '{{ item.name }}'
certificate: '{{ lookup(''file'', item.cert ) }}'
private_key: '{{ lookup(''file'', item.priv_key ) }}'
@@ -191,7 +191,7 @@
with_items: '{{ local_certs }}'
failed_when: upload2.changed
- name: change tags of existing certificate, check mode
- aws_acm:
+ acm_certificate:
certificate_arn: '{{ certificate_arn }}'
tags:
Name: '{{ name_tag }}'
@@ -208,7 +208,7 @@
that:
- certificate_with_tags.changed
- name: change tags of existing certificate, changes expected
- aws_acm:
+ acm_certificate:
# When applying tags to an existing certificate, it is sufficient to specify the 'certificate_arn'.
# Previously, the 'aws_acm' module was requiring the 'certificate', 'name_tag' and 'domain_name'
# attributes.
@@ -239,7 +239,7 @@
vars:
name_tag: '{{ upload2.results[0].item.name }}'
- name: change tags of existing certificate, check mode again
- aws_acm:
+ acm_certificate:
certificate_arn: '{{ certificate_arn }}'
tags:
Name: '{{ name_tag }}'
@@ -255,7 +255,7 @@
that:
- not certificate_with_tags.changed
- name: change tags of existing certificate, no change expected
- aws_acm:
+ acm_certificate:
certificate_arn: '{{ certificate_arn }}'
tags:
Name: '{{ name_tag }}'
@@ -299,7 +299,7 @@
- certificate_with_tags.certificate.tags['Environment'] == 'staging'
- certificate_with_tags.certificate.tags['Owner'] == 'Bob'
- name: change tags of existing certificate, purge tags
- aws_acm:
+ acm_certificate:
certificate_arn: '{{ certificate_arn }}'
tags:
Name: '{{ name_tag }}'
@@ -328,7 +328,7 @@
- certificate_with_tags.certificate.tags['Application'] == 'search'
- certificate_with_tags.certificate.tags['Environment'] == 'staging'
- name: update first cert with body of the second, first time
- aws_acm:
+ acm_certificate:
state: present
name_tag: '{{ local_certs[0].name }}'
certificate: '{{ lookup(''file'', local_certs[1].cert ) }}'
@@ -343,7 +343,7 @@
- overwrite.certificate.domain_name == local_certs[1].domain
- overwrite.changed
- name: check update was sucessfull
- aws_acm_info:
+ acm_certificate_info:
tags:
Name: '{{ local_certs[0].name }}'
register: fetch_after_overwrite
@@ -357,7 +357,7 @@
- '''Name'' in fetch_after_overwrite.certificates[0].tags'
- fetch_after_overwrite.certificates[0].tags['Name'] == local_certs[0].name
- name: fetch other cert
- aws_acm_info:
+ acm_certificate_info:
tags:
Name: '{{ local_certs[1].name }}'
register: check_after_overwrite
@@ -371,7 +371,7 @@
- '''Name'' in check_after_overwrite.certificates[0].tags'
- check_after_overwrite.certificates[0].tags['Name'] == local_certs[1].name
- name: update first cert with body of the second again
- aws_acm:
+ acm_certificate:
state: present
name_tag: '{{ local_certs[0].name }}'
certificate: '{{ lookup(''file'', local_certs[1].cert ) }}'
@@ -386,7 +386,7 @@
- overwrite2.certificate.domain_name == local_certs[1].domain
- not overwrite2.changed
- name: delete certs 1 and 2
- aws_acm:
+ acm_certificate:
state: absent
domain_name: '{{ local_certs[1].domain }}'
register: delete_both
@@ -398,7 +398,7 @@
- upload.results[0].certificate.arn in delete_both.arns
- delete_both.changed
- name: fetch info for certs 1 and 2
- aws_acm_info:
+ acm_certificate_info:
tags:
Name: '{{ local_certs[item].name }}'
register: check_del_one
@@ -415,13 +415,13 @@
assert:
that: item.certificates | length == 0
- name: check cert 3 not deleted
- aws_acm_info:
+ acm_certificate_info:
tags:
Name: '{{ local_certs[2].name }}'
register: check_del_one_remain
failed_when: check_del_one_remain.certificates | length != 1
- name: delete cert 3
- aws_acm:
+ acm_certificate:
state: absent
domain_name: '{{ local_certs[2].domain }}'
register: delete_third
@@ -433,13 +433,13 @@
- delete_third.arns[0] == upload.results[2].certificate.arn
- delete_third.changed
- name: check cert 3 was deleted
- aws_acm_info:
+ acm_certificate_info:
tags:
Name: '{{ local_certs[2].name }}'
register: check_del_three
failed_when: check_del_three.certificates | length != 0
- name: delete cert 3 again
- aws_acm:
+ acm_certificate:
state: absent
domain_name: '{{ local_certs[2].domain }}'
register: delete_third
@@ -490,7 +490,7 @@
root_certificates:
- '{{ local_certs[item.ca].cert }}'
- name: upload chained cert, first chain, first time
- aws_acm:
+ acm_certificate:
name_tag: '{{ chained_cert.name }}'
certificate: '{{ lookup(''file'', chained_cert.chains[0].cert ) }}'
certificate_chain: '{{ chains.results[0].complete_chain | join(''
@@ -501,7 +501,7 @@
register: upload_chain
failed_when: not upload_chain.changed
- name: fetch chain of cert we just uploaded
- aws_acm_info:
+ acm_certificate_info:
tags:
Name: '{{ chained_cert.name }}'
register: check_chain
@@ -513,7 +513,7 @@
- (check_chain.certificates[0].certificate_chain | replace( ' ', '' ) | replace( '\n', '')) == ( chains.results[0].complete_chain | join( '\n' ) | replace( ' ', '' ) | replace( '\n', '') )
- (check_chain.certificates[0].certificate | replace( ' ', '' ) | replace( '\n', '')) == ( lookup('file', chained_cert.chains[0].cert ) | replace( ' ', '' ) | replace( '\n', '') )
- name: upload chained cert again, check not changed
- aws_acm:
+ acm_certificate:
name_tag: '{{ chained_cert.name }}'
certificate: '{{ lookup(''file'', chained_cert.chains[0].cert ) }}'
certificate_chain: '{{ chains.results[0].complete_chain | join(''
@@ -528,7 +528,7 @@
- upload_chain_2.certificate.arn == upload_chain.certificate.arn
- not upload_chain_2.changed
- name: upload chained cert, different chain
- aws_acm:
+ acm_certificate:
name_tag: '{{ chained_cert.name }}'
certificate: '{{ lookup(''file'', chained_cert.chains[1].cert ) }}'
certificate_chain: '{{ chains.results[1].complete_chain | join(''
@@ -543,7 +543,7 @@
- upload_chain_3.changed
- upload_chain_3.certificate.arn == upload_chain.certificate.arn
- name: fetch info about chain of cert we just updated
- aws_acm_info:
+ acm_certificate_info:
tags:
Name: '{{ chained_cert.name }}'
register: check_chain_2
@@ -555,7 +555,7 @@
- (check_chain_2.certificates[0].certificate_chain | replace( ' ', '' ) | replace( '\n', '')) == ( chains.results[1].complete_chain | join( '\n' ) | replace( ' ', '' ) | replace( '\n', '') )
- (check_chain_2.certificates[0].certificate | replace( ' ', '' ) | replace( '\n', '')) == ( lookup('file', chained_cert.chains[1].cert ) | replace( ' ', '' ) | replace( '\n', '') )
- name: delete chained cert
- aws_acm:
+ acm_certificate:
name_tag: '{{ chained_cert.name }}'
state: absent
register: delete_chain_3
@@ -566,13 +566,13 @@
- upload_chain.certificate.arn in delete_chain_3.arns
always:
- name: delete first bunch of certificates
- aws_acm:
+ acm_certificate:
name_tag: '{{ item.name }}'
state: absent
with_items: '{{ local_certs }}'
ignore_errors: true
- name: delete chained cert
- aws_acm:
+ acm_certificate:
state: absent
name_tag: '{{ chained_cert.name }}'
ignore_errors: true
diff --git a/ansible_collections/community/aws/tests/integration/targets/api_gateway/defaults/main.yml b/ansible_collections/community/aws/tests/integration/targets/api_gateway/defaults/main.yml
new file mode 100644
index 000000000..aca496660
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/api_gateway/defaults/main.yml
@@ -0,0 +1,9 @@
+---
+api_names:
+ - "ansible-api-{{ resource_prefix }}-1"
+ - "ansible-api-{{ resource_prefix }}-2"
+resource_tags:
+ - gateway_name: "ansible-api-{{ resource_prefix }}"
+ ansible_test: "{{ resource_prefix }}-1"
+ - gateway_name: "ansible-api-{{ resource_prefix }}"
+ ansible_test: "{{ resource_prefix }}-2"
diff --git a/ansible_collections/community/aws/tests/integration/targets/api_gateway/tasks/lookup.yml b/ansible_collections/community/aws/tests/integration/targets/api_gateway/tasks/lookup.yml
new file mode 100644
index 000000000..8e0965439
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/api_gateway/tasks/lookup.yml
@@ -0,0 +1,211 @@
+---
+- name: Test API gateway creation using lookup=tag
+ vars:
+ api_name: "{{ api_names[0] }}"
+ block:
+ - name: Define API gateway configuration
+ set_fact:
+ apigateway_swagger_text: "{{ lookup('template', 'minimal-swagger-api.yml.j2') }}"
+
+ # Test: create API gateway using check_mode = true
+ - name: Create API gateway (check_mode=true)
+ community.aws.api_gateway:
+ name: "{{ api_name }}"
+ swagger_text: "{{ apigateway_swagger_text }}"
+ check_mode: true
+ register: __create_check_mode
+
+ - name: List existing API gateway
+ community.aws.api_gateway_info:
+ register: gateways
+
+ - name: Ensure using check_mode=true, no API gateway was created
+ assert:
+ that:
+ - __create_check_mode is changed
+ - gateways.rest_apis | selectattr('name', 'equalto', api_name) | list | length == 0
+
+ # Test: create new API gateway using name and tags
+ - name: Create new API gateway
+ community.aws.api_gateway:
+ name: "{{ api_name }}"
+ swagger_text: "{{ apigateway_swagger_text }}"
+ lookup: tag
+ tags: "{{ resource_tags[0] }}"
+ register: __create
+
+ - name: List existing API gateway
+ community.aws.api_gateway_info:
+ register: gateways
+
+ - name: Ensure new API was created
+ assert:
+ that:
+ - __create is changed
+ - gateways.rest_apis | selectattr('name', 'equalto', api_name) | list | length == 1
+
+ # Test: create API gateway idempotency (task reported changed but no new API created)
+ - name: Create same API gateway once again
+ community.aws.api_gateway:
+ name: "{{ api_name }}"
+ swagger_text: "{{ apigateway_swagger_text }}"
+ lookup: tag
+ tags: "{{ resource_tags[0] }}"
+
+ - name: List existing API gateway
+ community.aws.api_gateway_info:
+ register: gateways
+
+ - name: Ensure no new API was created
+ assert:
+ that:
+ - gateways.rest_apis | selectattr('name', 'equalto', api_name) | list | length == 1
+
+ # Test: create new API using existing name but different tags (new API gateway should be created)
+ - name: Create another API gateway with the same name but different tags
+ community.aws.api_gateway:
+ name: "{{ api_name }}"
+ swagger_text: "{{ apigateway_swagger_text }}"
+ lookup: tag
+ tags: "{{ resource_tags[1] }}"
+
+ - name: List existing API gateway
+ community.aws.api_gateway_info:
+ register: gateways
+
+ - name: Ensure new API was created
+ assert:
+ that:
+ - gateways.rest_apis | selectattr('name', 'equalto', api_name) | list | length == 2
+
+ rescue:
+ - name: List existing API gateway
+ community.aws.api_gateway_info:
+ register: gateways
+
+ - name: Delete remaining API gateway
+ community.aws.api_gateway:
+ api_id: '{{ item }}'
+ state: absent
+ ignore_errors: true
+ with_items: "{{ gateways.rest_apis | selectattr('name', 'equalto', api_name) | map(attribute='id') | list }}"
+
+- name: Test API gateway deletion
+ block:
+ - name: "Create new API gateway name={{ api_name }}"
+ community.aws.api_gateway:
+ name: "{{ api_name }}"
+ swagger_text: "{{ lookup('template', 'minimal-swagger-api.yml.j2') }}"
+ lookup: tag
+ tags: "{{ resource_tags[0] }}"
+ vars:
+ api_name: "{{ api_names[1] }}"
+
+ - name: List existing API gateway
+ community.aws.api_gateway_info:
+ register: gateways
+
+ - name: Ensure new API was created
+ assert:
+ that:
+ - gateways.rest_apis | selectattr('name', 'equalto', api_names[1]) | list | length == 1
+ - gateways.rest_apis | selectattr('name', 'equalto', api_names[0]) | list | length == 2
+
+ # Test: Delete with lookup=tag (conflict), should failed
+ - name: Delete API gateway
+ community.aws.api_gateway:
+ lookup: tag
+ tags: "{{ resource_tags[0] }}"
+ state: absent
+ register: __delete_conflict
+ ignore_errors: true
+
+ - name: Ensure task failed
+ assert:
+ that:
+ - __delete_conflict is failed
+ - '__delete_conflict.msg == "Tags provided do not identify a unique API gateway"'
+
+ # Test: Delete with name only (no api_id)
+ - name: Create same API gateway once again
+ community.aws.api_gateway:
+ name: "{{ api_names[1] }}"
+ state: absent
+ register: __delete_missing_params
+ ignore_errors: true
+
+ - name: Ensure task failed
+ assert:
+ that:
+ - __delete_missing_params is failed
+ - '__delete_missing_params.msg == "API gateway id must be supplied to delete API gateway or provided tag with lookup=tag to identify API gateway id."'
+
+ # Test: Delete (check_mode)
+ - name: Delete API gateway - check mode
+ community.aws.api_gateway:
+ name: "{{ api_names[1] }}"
+ lookup: tag
+ tags: "{{ resource_tags[0] }}"
+ state: absent
+ register: __delete_check_mode
+ check_mode: true
+
+ - name: List existing API gateway
+ community.aws.api_gateway_info:
+ register: gateways
+
+ - name: Ensure running in check mode, API was not deleted.
+ assert:
+ that:
+ - __delete_check_mode is changed
+ - gateways.rest_apis | selectattr('name', 'equalto', api_names[1]) | list | length == 1
+ - gateways.rest_apis | selectattr('name', 'equalto', api_names[0]) | list | length == 2
+
+ # Test: Delete using name and API gateway
+ - name: Delete API gateway using name and lookup=tag
+ community.aws.api_gateway:
+ name: "{{ api_names[1] }}"
+ lookup: tag
+ tags: "{{ resource_tags[0] }}"
+ state: absent
+ register: __delete
+
+ - name: List existing API gateway
+ community.aws.api_gateway_info:
+ register: gateways
+
+ - name: Ensure matching API gateway was deleted
+ assert:
+ that:
+ - __delete is changed
+ - gateways.rest_apis | selectattr('name', 'equalto', api_names[1]) | list | length == 0
+ - gateways.rest_apis | selectattr('name', 'equalto', api_names[0]) | list | length == 2
+
+ # Test: Delete using api_id
+ - name: Delete API gateway using api_id
+ community.aws.api_gateway:
+ api_id: "{{ gateways.rest_apis | selectattr('name', 'equalto', api_names[0]) | map(attribute='id') | first }}"
+ state: absent
+ register: __delete
+
+ - name: List existing API gateway
+ community.aws.api_gateway_info:
+ register: gateways
+
+ - name: Ensure matching API gateway was deleted
+ assert:
+ that:
+ - __delete is changed
+ - gateways.rest_apis | selectattr('name', 'equalto', api_names[0]) | list | length == 1
+
+ always:
+ - name: List existing API gateway
+ community.aws.api_gateway_info:
+ register: gateways
+
+ - name: Delete remaining API gateway
+ community.aws.api_gateway:
+ api_id: '{{ item }}'
+ state: absent
+ ignore_errors: true
+ with_items: "{{ gateways.rest_apis | selectattr('name', 'in', api_names) | map(attribute='id') | list }}"
diff --git a/ansible_collections/community/aws/tests/integration/targets/api_gateway/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/api_gateway/tasks/main.yml
index 51db07f0d..2e00128cd 100644
--- a/ansible_collections/community/aws/tests/integration/targets/api_gateway/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/api_gateway/tasks/main.yml
@@ -1,9 +1,9 @@
- name: Wrap API Gateway tests with credentials by default
module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region }}'
block:
@@ -11,7 +11,7 @@
# ====================== testing failure cases: ==================================
- name: test with no parameters
- aws_api_gateway:
+ api_gateway:
register: result
ignore_errors: true
@@ -22,7 +22,7 @@
- '"no swagger info provided" in result.msg'
- name: test for disallowing multiple swagger sources
- aws_api_gateway:
+ api_gateway:
api_id: 'fake-api-doesnt-exist'
swagger_file: foo.yml
swagger_text: "this is not really an API"
@@ -42,9 +42,11 @@
template:
src: minimal-swagger-api.yml.j2
dest: "{{output_dir}}/minimal-swagger-api.yml"
+ vars:
+ api_name: "{{ resource_prefix }}-minimal"
- name: deploy new API
- aws_api_gateway:
+ api_gateway:
api_file: "{{output_dir}}/minimal-swagger-api.yml"
stage: "minimal"
endpoint_type: 'REGIONAL'
@@ -58,11 +60,14 @@
- 'create_result.failed == False'
- 'create_result.deploy_response.description == "Automatic deployment by Ansible."'
- 'create_result.configure_response.id == create_result.api_id'
- - '"apigateway:CreateRestApi" in create_result.resource_actions'
- 'create_result.configure_response.endpoint_configuration.types.0 == "REGIONAL"'
- name: check if API endpoint works
- uri: url="https://{{create_result.api_id}}.execute-api.{{aws_region}}.amazonaws.com/minimal"
+ uri:
+ url: "https://{{create_result.api_id}}.execute-api.{{aws_region}}.amazonaws.com/minimal"
+ retries: 10
+ delay: 5
+ until: uri_result is successful
register: uri_result
- name: assert API works success
@@ -71,7 +76,8 @@
- 'uri_result.status == 200'
- name: check if nonexistent endpoint causes error
- uri: url="https://{{create_result.api_id}}.execute-api.{{aws_region}}.amazonaws.com/nominal"
+ uri:
+ url: "https://{{create_result.api_id}}.execute-api.{{aws_region}}.amazonaws.com/nominal"
register: bad_uri_result
ignore_errors: true
@@ -81,7 +87,7 @@
- bad_uri_result is failed
- name: Update API to test params effect
- aws_api_gateway:
+ api_gateway:
api_id: '{{create_result.api_id}}'
api_file: "{{output_dir}}/minimal-swagger-api.yml"
cache_enabled: true
@@ -93,14 +99,12 @@
- name: assert update result
assert:
that:
- - 'update_result.changed == True'
- - 'update_result.failed == False'
- - '"apigateway:PutRestApi" in update_result.resource_actions'
+ - update_result is changed
# ==== additional create/delete tests ====
- name: deploy first API
- aws_api_gateway:
+ api_gateway:
api_file: "{{output_dir}}/minimal-swagger-api.yml"
stage: "minimal"
cache_enabled: false
@@ -108,7 +112,7 @@
register: create_result_1
- name: deploy second API rapidly after first
- aws_api_gateway:
+ api_gateway:
api_file: "{{output_dir}}/minimal-swagger-api.yml"
stage: "minimal"
state: present
@@ -124,13 +128,13 @@
- 'create_result_1.configure_response.endpoint_configuration.types.0 == "EDGE"'
- name: destroy first API
- aws_api_gateway:
+ api_gateway:
state: absent
api_id: '{{create_result_1.api_id}}'
register: destroy_result_1
- name: destroy second API rapidly after first
- aws_api_gateway:
+ api_gateway:
state: absent
api_id: '{{create_result_2.api_id}}'
register: destroy_result_2
@@ -138,29 +142,33 @@
- name: assert both APIs deployed successfully
assert:
that:
- - 'destroy_result_1.changed == True'
- - 'destroy_result_2.changed == True'
- - '"apigateway:DeleteRestApi" in destroy_result_1.resource_actions'
- - '"apigateway:DeleteRestApi" in destroy_result_2.resource_actions'
+ - destroy_result_1 is changed
+ - destroy_result_2 is changed
+
+ # ==== test create/delete using lookup=tag ====
+ - include_tasks: lookup.yml
+
+ # ==== Tagging ====
+ - include_tasks: tagging.yml
# ================= end testing ====================================
always:
- name: Ensure cleanup of API deploy
- aws_api_gateway:
+ api_gateway:
state: absent
api_id: '{{create_result.api_id}}'
ignore_errors: true
- name: Ensure cleanup of API deploy 1
- aws_api_gateway:
+ api_gateway:
state: absent
api_id: '{{create_result_1.api_id}}'
ignore_errors: true
- name: Ensure cleanup of API deploy 2
- aws_api_gateway:
+ api_gateway:
state: absent
api_id: '{{create_result_2.api_id}}'
ignore_errors: true
diff --git a/ansible_collections/community/aws/tests/integration/targets/api_gateway/tasks/tagging.yml b/ansible_collections/community/aws/tests/integration/targets/api_gateway/tasks/tagging.yml
new file mode 100644
index 000000000..b72035083
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/api_gateway/tasks/tagging.yml
@@ -0,0 +1,91 @@
+---
+- name: Test API gateway tagging
+ vars:
+ api_name: "api-{{ resource_prefix }}-tagging"
+ apigateway_tags:
+ resource_prefix: "{{ resource_prefix }}"
+ collection: community.aws
+ new_tag:
+ resource_type: REST
+ block:
+ - name: Define API gateway configuration
+ set_fact:
+ apigateway_swagger_text: "{{ lookup('template', 'minimal-swagger-api.yml.j2') }}"
+
+ - name: Create API gateway
+ community.aws.api_gateway:
+ swagger_text: "{{ apigateway_swagger_text }}"
+ tags: "{{ apigateway_tags }}"
+ register: __api_gateway_create
+
+ - name: Assert resource was created with expected tags
+ assert:
+ that:
+ - __api_gateway_create.configure_response.tags == apigateway_tags
+
+ - name: Define API gateway id
+ ansible.builtin.set_fact:
+ apigateway_id: "{{ __api_gateway_create.api_id }}"
+
+ # Update tags purge_tags=false and check_mode
+ - name: Update tags using check_mode
+ community.aws.api_gateway:
+ api_id: "{{ apigateway_id }}"
+ tags: "{{ apigateway_tags | combine(new_tag) }}"
+ purge_tags: false
+ check_mode: true
+
+ - name: Get API Gateway
+ community.aws.api_gateway_info:
+ ids:
+ - "{{ apigateway_id }}"
+ register: __api_gateway_info
+
+ - name: Ensure tags were not changed
+ assert:
+ that:
+ - __api_gateway_info.rest_apis.0.tags == apigateway_tags
+
+ # Update tags purge_tags=false
+ - name: Update tags
+ community.aws.api_gateway:
+ api_id: "{{ apigateway_id }}"
+ tags: "{{ apigateway_tags | combine(new_tag) }}"
+ purge_tags: false
+
+ - name: Get API Gateway
+ community.aws.api_gateway_info:
+ ids:
+ - "{{ apigateway_id }}"
+ register: __api_gateway_info
+
+ - name: Ensure tags were not changed
+ assert:
+ that:
+ - __api_gateway_info.rest_apis.0.tags == apigateway_tags | combine(new_tag)
+
+ # Update tags purge_tags=true
+ - name: Update tags
+ community.aws.api_gateway:
+ api_id: "{{ apigateway_id }}"
+ tags: "{{ new_tag }}"
+ register: __update_api_gateway
+
+ - name: Get api gateway
+ community.aws.api_gateway_info:
+ ids:
+ - "{{ apigateway_id }}"
+ register: __api_gateway_info
+
+ - name: Ensure tags were not changed
+ assert:
+ that:
+ - __update_api_gateway is changed
+ - __api_gateway_info.rest_apis.0.tags == new_tag
+
+ always:
+ - name: Delete API Gateway
+ community.aws.api_gateway:
+ api_id: "{{ apigateway_id }}"
+ state: absent
+ ignore_errors: true
diff --git a/ansible_collections/community/aws/tests/integration/targets/api_gateway/templates/minimal-swagger-api.yml.j2 b/ansible_collections/community/aws/tests/integration/targets/api_gateway/templates/minimal-swagger-api.yml.j2
index 8c5c05810..d1d4c7ff6 100644
--- a/ansible_collections/community/aws/tests/integration/targets/api_gateway/templates/minimal-swagger-api.yml.j2
+++ b/ansible_collections/community/aws/tests/integration/targets/api_gateway/templates/minimal-swagger-api.yml.j2
@@ -2,7 +2,7 @@
swagger: "2.0"
info:
version: "2017-05-11T12:14:59Z"
- title: "{{resource_prefix}}Empty_API"
+ title: "{{ api_name }}"
host: "fakeexample.execute-api.us-east-1.amazonaws.com"
basePath: "/minimal"
schemes:
diff --git a/ansible_collections/community/aws/tests/integration/targets/api_gateway_domain/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/api_gateway_domain/tasks/main.yml
index 76de2657e..f3c740793 100644
--- a/ansible_collections/community/aws/tests/integration/targets/api_gateway_domain/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/api_gateway_domain/tasks/main.yml
@@ -4,9 +4,9 @@
- name: Run aws_api_gateway_domain module integration tests
module_defaults:
group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"
# NOTE: To make tests work set TLS ARN in defaults/main.yml to an existing and
@@ -17,7 +17,7 @@
# ==================== preparations ========================================
- name: Preperations - Create REST API Gateway on AWS API Gateway service to reference from domain tests
- aws_api_gateway:
+ api_gateway:
swagger_file: files/api_gw_swagger.yml
stage: test
state: present
@@ -26,7 +26,7 @@
# ================== integration tests ==========================================
- name: Create Test - API gateway custom domain setup
- aws_api_gateway_domain:
+ api_gateway_domain:
domain_name: "{{ api_gateway_domain_name }}"
certificate_arn: "{{ api_gateway_domain_tls_arn }}"
security_policy: 'TLS_1_0'
@@ -39,13 +39,13 @@
- assert:
that:
- create_result.changed == True
- - create_result.response.domain.domain_name == "{{ api_gateway_domain_name }}"
+ - create_result.response.domain.domain_name == api_gateway_domain_name
- create_result.response.domain.distribution_domain_name is defined
- create_result.response.domain.distribution_hosted_zone_id is defined
- create_result.response.path_mappings is defined
- name: Idempotence Test - API gateway custom domain setup
- aws_api_gateway_domain:
+ api_gateway_domain:
domain_name: "{{ api_gateway_domain_name }}"
certificate_arn: "{{ api_gateway_domain_tls_arn }}"
security_policy: 'TLS_1_0'
@@ -59,10 +59,10 @@
that:
- repeat_result.changed == False
- repeat_result.failed == False
- - repeat_result.response.domain_name == "{{ api_gateway_domain_name }}"
+ - repeat_result.response.domain_name == api_gateway_domain_name
- name: Update Test - API gateway custom domain setup, change settings
- aws_api_gateway_domain:
+ api_gateway_domain:
domain_name: "{{ api_gateway_domain_name }}"
certificate_arn: "{{ api_gateway_domain_tls_arn }}"
security_policy: 'TLS_1_2'
@@ -75,13 +75,13 @@
- assert:
that:
- update_result.changed == True
- - update_result.response.domain.domain_name == "{{ api_gateway_domain_name }}"
+ - update_result.response.domain.domain_name == api_gateway_domain_name
- update_result.response.domain.security_policy == 'TLS_1_2'
- update_result.response.domain.endpoint_configuration.types.0 == 'REGIONAL'
- update_result.response.path_mappings.0.base_path = '/v1'
- name: Delete - API gateway custom domain setup deletion
- aws_api_gateway_domain:
+ api_gateway_domain:
domain_name: "{{ api_gateway_domain_name }}"
certificate_arn: "{{ api_gateway_domain_tls_arn }}"
security_policy: 'TLS_1_2'
@@ -101,7 +101,7 @@
always:
- name: Cleanup - delete test domain setup
- aws_api_gateway_domain:
+ api_gateway_domain:
domain_name: "{{ api_gateway_domain_name }}"
certificate_arn: "{{ api_gateway_domain_tls_arn }}"
domain_mappings: []
@@ -109,7 +109,7 @@
ignore_errors: true
- name: Cleanup - remove REST API Gateway on AWS API Gateway service
- aws_api_gateway:
+ api_gateway:
api_id: "{{ api_gateway_result.api_id }}"
swagger_file: files/api_gw_swagger.yml
state: absent
diff --git a/ansible_collections/community/aws/tests/integration/targets/autoscaling_complete_lifecycle_action/tasks/env_cleanup.yml b/ansible_collections/community/aws/tests/integration/targets/autoscaling_complete_lifecycle_action/tasks/env_cleanup.yml
index 75d1ecfad..ef894ff54 100644
--- a/ansible_collections/community/aws/tests/integration/targets/autoscaling_complete_lifecycle_action/tasks/env_cleanup.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/autoscaling_complete_lifecycle_action/tasks/env_cleanup.yml
@@ -1,5 +1,5 @@
- name: kill asg
- ec2_asg:
+ autoscaling_group:
name: "{{ asg_name }}"
state: absent
register: removed
@@ -8,7 +8,7 @@
retries: 10
- name: remove launch configs
- ec2_lc:
+ autoscaling_launch_config:
name: "{{ lc_name }}"
state: absent
register: removed
@@ -17,7 +17,7 @@
retries: 10
- name: remove the security group
- ec2_group:
+ ec2_security_group:
name: "{{ sg_name }}"
description: a security group for ansible tests
vpc_id: "{{ testing_vpc.vpc.id }}"
diff --git a/ansible_collections/community/aws/tests/integration/targets/autoscaling_complete_lifecycle_action/tasks/env_setup.yml b/ansible_collections/community/aws/tests/integration/targets/autoscaling_complete_lifecycle_action/tasks/env_setup.yml
index ae958cd89..b4609ea97 100644
--- a/ansible_collections/community/aws/tests/integration/targets/autoscaling_complete_lifecycle_action/tasks/env_setup.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/autoscaling_complete_lifecycle_action/tasks/env_setup.yml
@@ -37,7 +37,7 @@
- "{{ testing_subnet.subnet.id }}"
- name: create a security group with the vpc created in the ec2_setup
- ec2_group:
+ ec2_security_group:
name: "{{ sg_name }}"
description: a security group for ansible tests
vpc_id: "{{ testing_vpc.vpc.id }}"
@@ -53,7 +53,7 @@
register: sg
- name: create a launch configuration
- ec2_lc:
+ autoscaling_launch_config:
name: "{{ lc_name }}"
image_id: "{{ ec2_ami_id }}"
instance_type: t2.micro
@@ -67,7 +67,7 @@
- create_lc.failed is false
- name: create a AutoScalingGroup
- ec2_asg:
+ autoscaling_group:
name: "{{ asg_name }}"
launch_config_name: "{{ lc_name }}"
health_check_period: 60
diff --git a/ansible_collections/community/aws/tests/integration/targets/autoscaling_complete_lifecycle_action/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/autoscaling_complete_lifecycle_action/tasks/main.yml
index d8380d913..d4b2a7c7a 100644
--- a/ansible_collections/community/aws/tests/integration/targets/autoscaling_complete_lifecycle_action/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/autoscaling_complete_lifecycle_action/tasks/main.yml
@@ -2,11 +2,12 @@
- name: "Wrap up all tests and setup AWS credentials"
module_defaults:
group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"
collections:
+ - amazon.aws
- community.aws
block:
- include_tasks: 'env_setup.yml'
diff --git a/ansible_collections/community/aws/tests/integration/targets/autoscaling_complete_lifecycle_action/tasks/tests.yml b/ansible_collections/community/aws/tests/integration/targets/autoscaling_complete_lifecycle_action/tasks/tests.yml
index 7d326c6ff..804f802bb 100644
--- a/ansible_collections/community/aws/tests/integration/targets/autoscaling_complete_lifecycle_action/tasks/tests.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/autoscaling_complete_lifecycle_action/tasks/tests.yml
@@ -3,7 +3,7 @@
block:
#----------------------------------------------------------------------
- name: Create lifecycle hook
- ec2_asg_lifecycle_hook:
+ autoscaling_lifecycle_hook:
autoscaling_group_name: "{{ asg_name }}"
lifecycle_hook_name: "{{ resource_prefix }}-lifecycle-hook"
transition: autoscaling:EC2_INSTANCE_LAUNCHING
@@ -18,7 +18,7 @@
- output is not failed
- name: Create lifecycle hook
- ec2_asg_lifecycle_hook:
+ autoscaling_lifecycle_hook:
autoscaling_group_name: "{{ asg_name }}"
lifecycle_hook_name: "{{ resource_prefix }}-lifecycle-hook-terminate"
transition: autoscaling:EC2_INSTANCE_TERMINATING
@@ -33,7 +33,7 @@
- output is not failed
- name: Trigger scale-up
- ec2_asg:
+ autoscaling_group:
name: "{{ asg_name }}"
replace_all_instances: yes
min_size: 0
@@ -47,7 +47,7 @@
- scale_asg is changed
- name: Describe ASG
- ec2_asg_info:
+ autoscaling_group_info:
name: "{{ asg_name }}"
register: scaled_asg
retries: 24
@@ -62,7 +62,7 @@
instance_ids: '{{ scaled_asg.results[0].instances | map(attribute="instance_id") | list }}'
- name: Describe ASG
- ec2_asg_info:
+ autoscaling_group_info:
name: "{{ asg_name }}"
- name: Complete Lifecycle Hook
@@ -80,7 +80,7 @@
instance_id: '{{ instance_ids[1] }}'
- name: Describe ASG
- ec2_asg_info:
+ autoscaling_group_info:
name: "{{ asg_name }}"
register: hooks_pending
retries: 24
@@ -104,7 +104,7 @@
always:
- name: Delete lifecycle hook
- community.aws.ec2_asg_lifecycle_hook:
+ community.aws.autoscaling_lifecycle_hook:
autoscaling_group_name: "{{ asg_name }}"
lifecycle_hook_name: "{{ resource_prefix }}-lifecycle-hook"
state: absent
@@ -112,7 +112,7 @@
ignore_errors: True
- name: Delete lifecycle hook
- community.aws.ec2_asg_lifecycle_hook:
+ community.aws.autoscaling_lifecycle_hook:
autoscaling_group_name: "{{ asg_name }}"
lifecycle_hook_name: "{{ resource_prefix }}-lifecycle-hook-terminate"
state: absent
diff --git a/ansible_collections/community/aws/tests/integration/targets/autoscaling_instance_refresh/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/autoscaling_instance_refresh/tasks/main.yml
index 32cfd5378..5b754d47d 100644
--- a/ansible_collections/community/aws/tests/integration/targets/autoscaling_instance_refresh/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/autoscaling_instance_refresh/tasks/main.yml
@@ -2,9 +2,9 @@
- name: setup credentials and region
module_defaults:
group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"
collections:
@@ -47,7 +47,7 @@
- "{{ testing_subnet.subnet.id }}"
- name: create a security group with the vpc created in the ec2_setup
- ec2_group:
+ ec2_security_group:
name: "{{ sg_name }}"
description: a security group for ansible tests
vpc_id: "{{ testing_vpc.vpc.id }}"
@@ -63,7 +63,7 @@
register: sg
- name: ensure launch configs exist
- ec2_lc:
+ autoscaling_launch_config:
name: "{{ item }}"
assign_public_ip: true
image_id: "{{ ec2_ami_id }}"
@@ -81,7 +81,7 @@
- "{{ lc_name_2 }}"
- name: launch asg and do not wait for instances to be deemed healthy (no ELB)
- ec2_asg:
+ autoscaling_group:
name: "{{ asg_name }}"
launch_config_name: "{{ lc_name_1 }}"
desired_capacity: 1
@@ -99,7 +99,7 @@
# ============================================================
- name: test invalid cancelation - V1 - (pre-refresh)
- ec2_asg_instance_refresh:
+ autoscaling_instance_refresh:
name: "{{ asg_name }}"
state: "cancelled"
ignore_errors: yes
@@ -107,10 +107,10 @@
- assert:
that:
- - "'An error occurred (ActiveInstanceRefreshNotFound) when calling the CancelInstanceRefresh operation: No in progress or pending Instance Refresh found for Auto Scaling group {{ resource_prefix }}-asg' in result.msg"
+ - "'An error occurred (ActiveInstanceRefreshNotFound) when calling the CancelInstanceRefresh operation: No in progress or pending Instance Refresh found for Auto Scaling group ' ~ resource_prefix ~ '-asg' in result.msg"
- name: test starting a refresh with a valid ASG name - check_mode
- ec2_asg_instance_refresh:
+ autoscaling_instance_refresh:
name: "{{ asg_name }}"
state: "started"
check_mode: true
@@ -123,7 +123,7 @@
- '"autoscaling:StartInstanceRefresh" not in output.resource_actions'
- name: test starting a refresh with a valid ASG name
- ec2_asg_instance_refresh:
+ autoscaling_instance_refresh:
name: "{{ asg_name }}"
state: "started"
register: output
@@ -133,7 +133,7 @@
- "'instance_refresh_id' in output.instance_refreshes"
- name: test starting a refresh with a valid ASG name - Idempotent
- ec2_asg_instance_refresh:
+ autoscaling_instance_refresh:
name: "{{ asg_name }}"
state: "started"
ignore_errors: true
@@ -145,7 +145,7 @@
- '"Failed to start InstanceRefresh: An error occurred (InstanceRefreshInProgress) when calling the StartInstanceRefresh operation: An Instance Refresh is already in progress and blocks the execution of this Instance Refresh." in output.msg'
- name: test starting a refresh with a valid ASG name - Idempotent (check_mode)
- ec2_asg_instance_refresh:
+ autoscaling_instance_refresh:
name: "{{ asg_name }}"
state: "started"
ignore_errors: true
@@ -159,7 +159,7 @@
- '"In check_mode - Instance Refresh is already in progress, can not start new instance refresh." in output.msg'
- name: test starting a refresh with a nonexistent ASG name
- ec2_asg_instance_refresh:
+ autoscaling_instance_refresh:
name: "nonexistentname-asg"
state: "started"
ignore_errors: yes
@@ -170,7 +170,7 @@
- "'Failed to start InstanceRefresh: An error occurred (ValidationError) when calling the StartInstanceRefresh operation: AutoScalingGroup name not found' in result.msg"
- name: test canceling a refresh with an ASG name - check_mode
- ec2_asg_instance_refresh:
+ autoscaling_instance_refresh:
name: "{{ asg_name }}"
state: "cancelled"
check_mode: true
@@ -183,7 +183,7 @@
- '"autoscaling:CancelInstanceRefresh" not in output.resource_actions'
- name: test canceling a refresh with an ASG name
- ec2_asg_instance_refresh:
+ autoscaling_instance_refresh:
name: "{{ asg_name }}"
state: "cancelled"
register: output
@@ -193,7 +193,7 @@
- "'instance_refresh_id' in output.instance_refreshes"
- name: test canceling a refresh with a ASG name - Idempotent
- ec2_asg_instance_refresh:
+ autoscaling_instance_refresh:
name: "{{ asg_name }}"
state: "cancelled"
ignore_errors: yes
@@ -204,7 +204,7 @@
- output is not changed
- name: test cancelling a refresh with a valid ASG name - Idempotent (check_mode)
- ec2_asg_instance_refresh:
+ autoscaling_instance_refresh:
name: "{{ asg_name }}"
state: "cancelled"
ignore_errors: true
@@ -217,7 +217,7 @@
- output is not failed
- name: test starting a refresh with an ASG name and preferences dict
- ec2_asg_instance_refresh:
+ autoscaling_instance_refresh:
name: "{{ asg_name }}"
state: "started"
preferences:
@@ -232,7 +232,7 @@
- "'instance_refresh_id' in output.instance_refreshes"
- name: re-test canceling a refresh with an ASG name
- ec2_asg_instance_refresh:
+ autoscaling_instance_refresh:
name: "{{ asg_name }}"
state: "cancelled"
register: output
@@ -242,7 +242,7 @@
- "'instance_refresh_id' in output.instance_refreshes"
- name: test valid start - V1 - (with preferences missing instance_warmup)
- ec2_asg_instance_refresh:
+ autoscaling_instance_refresh:
name: "{{ asg_name }}"
state: "started"
preferences:
@@ -257,7 +257,7 @@
- "'instance_refresh_id' in output.instance_refreshes"
- name: re-test canceling a refresh with an ASG name
- ec2_asg_instance_refresh:
+ autoscaling_instance_refresh:
name: "{{ asg_name }}"
state: "cancelled"
register: output
@@ -267,7 +267,7 @@
- "'instance_refresh_id' in output.instance_refreshes"
- name: test valid start - V2 - (with preferences missing min_healthy_percentage)
- ec2_asg_instance_refresh:
+ autoscaling_instance_refresh:
name: "{{ asg_name }}"
state: "started"
preferences:
@@ -282,7 +282,7 @@
- "'instance_refresh_id' in output.instance_refreshes"
- name: test invalid cancelation - V2 - (with preferences)
- ec2_asg_instance_refresh:
+ autoscaling_instance_refresh:
name: "{{ asg_name }}"
state: "cancelled"
preferences:
@@ -302,7 +302,7 @@
loop: "{{ query('sequence', 'start=1 end=3') }}"
- name: test getting info for an ASG name
- ec2_asg_instance_refresh_info:
+ autoscaling_instance_refresh_info:
name: "{{ asg_name }}"
region: "{{ aws_region }}"
ignore_errors: yes
@@ -315,7 +315,7 @@
inst_refresh_id_json_query: instance_refreshes[].instance_refresh_id
- name: test using fake refresh ID
- ec2_asg_instance_refresh_info:
+ autoscaling_instance_refresh_info:
name: "{{ asg_name }}"
ids: ['0e367f58-blabla-bla-bla-ca870dc5dbfe']
ignore_errors: yes
@@ -323,10 +323,10 @@
- assert:
that:
- - "{{ output.instance_refreshes|length }} == 0"
+ - output.instance_refreshes | length == 0
- name: test using a real refresh ID
- ec2_asg_instance_refresh_info:
+ autoscaling_instance_refresh_info:
name: "{{ asg_name }}"
ids: [ '{{ refreshout.instance_refreshes.instance_refresh_id }}' ]
ignore_errors: yes
@@ -334,10 +334,10 @@
- assert:
that:
- - "{{ output.instance_refreshes |length }} == 1"
+ - output.instance_refreshes | length == 1
- name: test getting info for an ASG name which doesn't exist
- ec2_asg_instance_refresh_info:
+ autoscaling_instance_refresh_info:
name: n0n3x1stentname27b
ignore_errors: yes
register: output
@@ -347,17 +347,17 @@
- "'Failed to describe InstanceRefreshes: An error occurred (ValidationError) when calling the DescribeInstanceRefreshes operation: AutoScalingGroup name not found - AutoScalingGroup n0n3x1stentname27b not found' == output.msg"
- name: assert that the correct number of records are returned
- ec2_asg_instance_refresh_info:
+ autoscaling_instance_refresh_info:
name: "{{ asg_name }}"
ignore_errors: yes
register: output
- assert:
that:
- - "{{ output.instance_refreshes|length }} == 7"
+ - output.instance_refreshes | length == 7
- name: assert that valid message with fake-token is returned
- ec2_asg_instance_refresh_info:
+ autoscaling_instance_refresh_info:
name: "{{ asg_name }}"
next_token: "fake-token-123"
ignore_errors: yes
@@ -368,7 +368,7 @@
- '"Failed to describe InstanceRefreshes: An error occurred (InvalidNextToken) when calling the DescribeInstanceRefreshes operation: The token ''********'' is invalid." == output.msg'
- name: assert that max records=1 returns no more than one record
- ec2_asg_instance_refresh_info:
+ autoscaling_instance_refresh_info:
name: "{{ asg_name }}"
max_records: 1
ignore_errors: yes
@@ -376,10 +376,10 @@
- assert:
that:
- - "{{ output.instance_refreshes|length }} < 2"
+ - output.instance_refreshes | length < 2
- name: assert that valid message with real-token is returned
- ec2_asg_instance_refresh_info:
+ autoscaling_instance_refresh_info:
name: "{{ asg_name }}"
next_token: "{{ output.next_token }}"
ignore_errors: yes
@@ -387,10 +387,10 @@
- assert:
that:
- - "{{ output.instance_refreshes|length }} == 7"
+ - output.instance_refreshes | length == 7
- name: test using both real nextToken and max_records=1
- ec2_asg_instance_refresh_info:
+ autoscaling_instance_refresh_info:
name: "{{ asg_name }}"
max_records: 1
next_token: "{{ output.next_token }}"
@@ -399,12 +399,12 @@
- assert:
that:
- - "{{ output.instance_refreshes|length }} == 1"
+ - output.instance_refreshes | length == 1
always:
- name: kill asg
- ec2_asg:
+ autoscaling_group:
name: "{{ asg_name }}"
state: absent
register: removed
@@ -414,7 +414,7 @@
# Remove the testing dependencies
- name: remove the load balancer
- ec2_elb_lb:
+ elb_classic_lb:
name: "{{ load_balancer_name }}"
state: absent
security_group_ids:
@@ -440,7 +440,7 @@
retries: 10
- name: remove launch configs
- ec2_lc:
+ autoscaling_launch_config:
name: "{{ item }}"
state: absent
register: removed
@@ -461,7 +461,7 @@
ignore_errors: true
- name: remove the security group
- ec2_group:
+ ec2_security_group:
name: "{{ sg_name }}"
description: a security group for ansible tests
vpc_id: "{{ testing_vpc.vpc.id }}"
diff --git a/ansible_collections/community/aws/tests/integration/targets/autoscaling_instance_refresh/tasks/refresh_and_cancel_three_times.yml b/ansible_collections/community/aws/tests/integration/targets/autoscaling_instance_refresh/tasks/refresh_and_cancel_three_times.yml
index 15fa2100c..9b051a054 100644
--- a/ansible_collections/community/aws/tests/integration/targets/autoscaling_instance_refresh/tasks/refresh_and_cancel_three_times.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/autoscaling_instance_refresh/tasks/refresh_and_cancel_three_times.yml
@@ -1,17 +1,17 @@
---
- name: try to cancel pre-loop
- ec2_asg_instance_refresh:
+ autoscaling_instance_refresh:
name: "{{ asg_name }}"
state: "cancelled"
ignore_errors: yes
- name: test starting a refresh with an ASG name
- ec2_asg_instance_refresh:
+ autoscaling_instance_refresh:
name: "{{ asg_name }}"
state: "started"
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
region: "{{ aws_region }}"
ignore_errors: no
retries: 10
@@ -20,10 +20,10 @@
until: refreshout is not failed
- name: test cancelling a refresh with an ASG name
- ec2_asg_instance_refresh:
+ autoscaling_instance_refresh:
name: "{{ asg_name }}"
state: "cancelled"
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
region: "{{ aws_region }}"
ignore_errors: yes
diff --git a/ansible_collections/community/aws/tests/integration/targets/autoscaling_launch_config/tasks/env_cleanup.yml b/ansible_collections/community/aws/tests/integration/targets/autoscaling_launch_config/tasks/env_cleanup.yml
index 9e5ae6a93..ce626b69c 100644
--- a/ansible_collections/community/aws/tests/integration/targets/autoscaling_launch_config/tasks/env_cleanup.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/autoscaling_launch_config/tasks/env_cleanup.yml
@@ -24,7 +24,7 @@
retries: 10
- name: remove the security group
- ec2_group:
+ ec2_security_group:
name: "{{ resource_prefix }}-sg"
description: a security group for ansible tests
vpc_id: "{{ testing_vpc.vpc.id }}"
diff --git a/ansible_collections/community/aws/tests/integration/targets/autoscaling_launch_config/tasks/env_setup.yml b/ansible_collections/community/aws/tests/integration/targets/autoscaling_launch_config/tasks/env_setup.yml
index 88f5bb6fe..d48bae66c 100644
--- a/ansible_collections/community/aws/tests/integration/targets/autoscaling_launch_config/tasks/env_setup.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/autoscaling_launch_config/tasks/env_setup.yml
@@ -48,7 +48,7 @@
- "{{ testing_subnet_b.subnet.id }}"
- name: create a security group with the vpc
- ec2_group:
+ ec2_security_group:
name: "{{ resource_prefix }}-sg"
description: a security group for ansible tests
vpc_id: "{{ testing_vpc.vpc.id }}"
diff --git a/ansible_collections/community/aws/tests/integration/targets/autoscaling_launch_config/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/autoscaling_launch_config/tasks/main.yml
index 6606484b1..da1f2fb1f 100644
--- a/ansible_collections/community/aws/tests/integration/targets/autoscaling_launch_config/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/autoscaling_launch_config/tasks/main.yml
@@ -1,9 +1,9 @@
- name: run ec2_lc tests
module_defaults:
group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"
collections:
- amazon.aws
@@ -14,7 +14,7 @@
include_tasks: env_setup.yml
- name: Create launch configuration 1
- community.aws.ec2_lc:
+ community.aws.autoscaling_launch_config:
name: '{{ resource_prefix }}-lc1'
image_id: '{{ ec2_ami_id }}'
assign_public_ip: yes
@@ -28,7 +28,7 @@
register: lc_1_create
- name: Gather information about launch configuration 1
- community.aws.ec2_lc_info:
+ community.aws.autoscaling_launch_config_info:
name: '{{ resource_prefix }}-lc1'
register: lc_1_info_result
@@ -42,7 +42,7 @@
- lc_1_info_result.launch_configurations[0].instance_type == 't2.micro'
- name: Create launch configuration 1 - Idempotency
- community.aws.ec2_lc:
+ community.aws.autoscaling_launch_config:
name: '{{ resource_prefix }}-lc1'
image_id: '{{ ec2_ami_id }}'
assign_public_ip: yes
@@ -61,7 +61,7 @@
- '"autoscaling:CreateLaunchConfiguration" not in lc_1_create_idem.resource_actions'
- name: Create launch configuration 2
- community.aws.ec2_lc:
+ community.aws.autoscaling_launch_config:
name: '{{ resource_prefix }}-lc2'
image_id: '{{ ec2_ami_id }}'
assign_public_ip: yes
@@ -75,7 +75,7 @@
register: lc_2_create
- name: Gather information about launch configuration 2
- community.aws.ec2_lc_info:
+ community.aws.autoscaling_launch_config_info:
name: '{{ resource_prefix }}-lc2'
register: lc_2_info_result
@@ -90,7 +90,7 @@
- '"autoscaling:CreateLaunchConfiguration" in lc_2_create.resource_actions'
- name: Create launch configuration 2 - Idempotency
- community.aws.ec2_lc:
+ community.aws.autoscaling_launch_config:
name: '{{ resource_prefix }}-lc2'
image_id: '{{ ec2_ami_id }}'
assign_public_ip: yes
@@ -109,7 +109,7 @@
- '"autoscaling:CreateLaunchConfiguration" not in lc_2_create_idem.resource_actions'
- name: Create launch configuration 3 - test throughput parameter
- community.aws.ec2_lc:
+ community.aws.autoscaling_launch_config:
name: '{{ resource_prefix }}-lc3'
image_id: '{{ ec2_ami_id }}'
instance_type: '{{ ec2_instance_type }}'
@@ -122,7 +122,7 @@
register: lc_3_create
- name: Gather information about launch configuration 3
- community.aws.ec2_lc_info:
+ community.aws.autoscaling_launch_config_info:
name: '{{ resource_prefix }}-lc3'
register: lc_3_info_result
@@ -137,7 +137,7 @@
- '"autoscaling:CreateLaunchConfiguration" in lc_3_create.resource_actions'
- name: Create launch configuration 3 - Idempotency
- community.aws.ec2_lc:
+ community.aws.autoscaling_launch_config:
name: '{{ resource_prefix }}-lc3'
image_id: '{{ ec2_ami_id }}'
instance_type: '{{ ec2_instance_type }}'
@@ -155,7 +155,7 @@
- '"autoscaling:CreateLaunchConfiguration" not in lc_3_create_idem.resource_actions'
- name: Search for the Launch Configurations that start with test resource_prefix
- community.aws.ec2_lc_find:
+ community.aws.autoscaling_launch_config_find:
name_regex: '{{ resource_prefix }}*'
sort_order: descending
register: lc_find_result
@@ -166,7 +166,7 @@
- '"autoscaling:DescribeLaunchConfigurations" in lc_find_result.resource_actions'
- name: Delete launch configuration 1
- community.aws.ec2_lc:
+ community.aws.autoscaling_launch_config:
name: '{{ resource_prefix }}-lc1'
state: absent
register: lc_1_delete
@@ -177,7 +177,7 @@
- '"autoscaling:DeleteLaunchConfiguration" in lc_1_delete.resource_actions'
- name: Delete launch configuration 1 - Idempotency
- community.aws.ec2_lc:
+ community.aws.autoscaling_launch_config:
name: '{{ resource_prefix }}-lc1'
state: absent
register: lc_1_delete_idem
@@ -188,7 +188,7 @@
- '"autoscaling:DeleteLaunchConfiguration" not in lc_1_delete_idem.resource_actions'
- name: Gather information about launch configuration 1
- community.aws.ec2_lc_info:
+ community.aws.autoscaling_launch_config_info:
name: '{{ resource_prefix }}-lc1'
register: lc_1_info_result
@@ -198,7 +198,7 @@
- lc_1_info_result.launch_configurations | length == 0
- name: Delete launch configuration 2
- community.aws.ec2_lc:
+ community.aws.autoscaling_launch_config:
name: '{{ resource_prefix }}-lc2'
state: absent
register: lc_2_delete
@@ -209,7 +209,7 @@
- '"autoscaling:DeleteLaunchConfiguration" in lc_2_delete.resource_actions'
- name: Delete launch configuration 2 - Idempotency
- community.aws.ec2_lc:
+ community.aws.autoscaling_launch_config:
name: '{{ resource_prefix }}-lc2'
state: absent
register: lc_2_delete_idem
@@ -220,7 +220,7 @@
- '"autoscaling:DeleteLaunchConfiguration" not in lc_2_delete_idem.resource_actions'
- name: Gather information about launch configuration 2
- community.aws.ec2_lc_info:
+ community.aws.autoscaling_launch_config_info:
name: '{{ resource_prefix }}-lc2'
register: lc_2_info_result
@@ -230,7 +230,7 @@
- lc_2_info_result.launch_configurations | length == 0
- name: Delete launch configuration 3
- community.aws.ec2_lc:
+ community.aws.autoscaling_launch_config:
name: '{{ resource_prefix }}-lc3'
state: absent
register: lc_3_delete
@@ -241,7 +241,7 @@
- '"autoscaling:DeleteLaunchConfiguration" in lc_3_delete.resource_actions'
- name: Delete launch configuration 3 - Idempotency
- community.aws.ec2_lc:
+ community.aws.autoscaling_launch_config:
name: '{{ resource_prefix }}-lc3'
state: absent
register: lc_3_delete_idem
@@ -252,7 +252,7 @@
- '"autoscaling:DeleteLaunchConfiguration" not in lc_3_delete_idem.resource_actions'
- name: Gather information about launch configuration 3
- community.aws.ec2_lc_info:
+ community.aws.autoscaling_launch_config_info:
name: '{{ resource_prefix }}-lc2'
register: lc_3_info_result
diff --git a/ansible_collections/community/aws/tests/integration/targets/autoscaling_lifecycle_hook/main.yml b/ansible_collections/community/aws/tests/integration/targets/autoscaling_lifecycle_hook/main.yml
index a22182146..e8fdfd37b 100644
--- a/ansible_collections/community/aws/tests/integration/targets/autoscaling_lifecycle_hook/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/autoscaling_lifecycle_hook/main.yml
@@ -2,40 +2,38 @@
# Beware: most of our tests here are run in parallel.
# To add new tests you'll need to add a new host to the inventory and a matching
# '{{ inventory_hostname }}'.yml file in roles/ec2_asg_lifecycle_hook/tasks/
-
-
# Prepare the VPC and figure out which AMI to use
- hosts: all
- gather_facts: no
+ gather_facts: false
tasks:
- - module_defaults:
- group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
- region: "{{ aws_region }}"
- vars:
+ - module_defaults:
+ group/aws:
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
+ region: "{{ aws_region }}"
+ vars:
# We can't just use "run_once" because the facts don't propagate when
# running an 'include' that was run_once
- setup_run_once: yes
- block:
- - include_role:
- name: 'setup_ec2_facts'
- - include_role:
- name: 'ec2_asg_lifecycle_hook'
- tasks_from: env_setup.yml
- rescue:
- - include_role:
- name: 'ec2_asg_lifecycle_hook'
- tasks_from: env_cleanup.yml
- run_once: yes
- - fail:
- msg: 'Environment preparation failed'
- run_once: yes
+ setup_run_once: true
+ block:
+ - ansible.builtin.include_role:
+ name: setup_ec2_facts
+ - ansible.builtin.include_role:
+ name: ec2_asg_lifecycle_hook
+ tasks_from: env_setup.yml
+ rescue:
+ - ansible.builtin.include_role:
+ name: ec2_asg_lifecycle_hook
+ tasks_from: env_cleanup.yml
+ run_once: true
+ - ansible.builtin.fail:
+ msg: Environment preparation failed
+ run_once: true
# VPC should get cleaned up once all hosts have run
- hosts: all
- gather_facts: no
+ gather_facts: false
strategy: free
serial: 6
roles:
diff --git a/ansible_collections/community/aws/tests/integration/targets/autoscaling_lifecycle_hook/meta/main.yml b/ansible_collections/community/aws/tests/integration/targets/autoscaling_lifecycle_hook/meta/main.yml
index 1471b11f6..fcadd50dc 100644
--- a/ansible_collections/community/aws/tests/integration/targets/autoscaling_lifecycle_hook/meta/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/autoscaling_lifecycle_hook/meta/main.yml
@@ -1,2 +1,3 @@
+---
dependencies:
- setup_ec2_facts
diff --git a/ansible_collections/community/aws/tests/integration/targets/autoscaling_lifecycle_hook/roles/ec2_asg_lifecycle_hook/tasks/create_update_delete.yml b/ansible_collections/community/aws/tests/integration/targets/autoscaling_lifecycle_hook/roles/ec2_asg_lifecycle_hook/tasks/create_update_delete.yml
index 800ee6358..f6b92213e 100644
--- a/ansible_collections/community/aws/tests/integration/targets/autoscaling_lifecycle_hook/roles/ec2_asg_lifecycle_hook/tasks/create_update_delete.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/autoscaling_lifecycle_hook/roles/ec2_asg_lifecycle_hook/tasks/create_update_delete.yml
@@ -2,47 +2,46 @@
- name: Test create/update/delete AutoScalingGroups Lifecycle Hooks with ec2_asg_lifecycle_hook
block:
- #----------------------------------------------------------------------
- - name: create a launch configuration
- ec2_lc:
+ # ----------------------------------------------------------------------
+ - name: Create a launch configuration
+ community.aws.autoscaling_launch_config:
name: "{{ resource_prefix }}-lc"
image_id: "{{ ec2_ami_id }}"
region: "{{ aws_region }}"
instance_type: t2.micro
- assign_public_ip: yes
+ assign_public_ip: true
register: create_lc
- - name: ensure that lc is created
- assert:
+ - name: Ensure that lc is created
+ ansible.builtin.assert:
that:
- create_lc is changed
- create_lc.failed is false
- #----------------------------------------------------------------------
- - name: create a AutoScalingGroup
- ec2_asg:
+ # ----------------------------------------------------------------------
+ - name: Create a AutoScalingGroup
+ amazon.aws.autoscaling_group:
name: "{{ resource_prefix }}-asg"
launch_config_name: "{{ resource_prefix }}-lc"
health_check_period: 60
health_check_type: ELB
- replace_all_instances: yes
+ replace_all_instances: true
min_size: 1
max_size: 1
desired_capacity: 1
region: "{{ aws_region }}"
register: create_asg
- - name: ensure that AutoScalingGroup is created
- assert:
+ - name: Ensure that AutoScalingGroup is created
+ ansible.builtin.assert:
that:
- create_asg is changed
- create_asg.failed is false
- '"autoscaling:CreateAutoScalingGroup" in create_asg.resource_actions'
- #----------------------------------------------------------------------
-
+ # ----------------------------------------------------------------------
- name: Create lifecycle hook - check_mode
- community.aws.ec2_asg_lifecycle_hook:
+ community.aws.autoscaling_lifecycle_hook:
region: "{{ aws_region }}"
autoscaling_group_name: "{{ resource_prefix }}-asg"
lifecycle_hook_name: "{{ resource_prefix }}-test-hook"
@@ -53,7 +52,7 @@
check_mode: true
register: output
- - assert:
+ - ansible.builtin.assert:
that:
- output is changed
- output is not failed
@@ -61,7 +60,7 @@
- '"Would have created AutoScalingGroup Lifecycle Hook if not in check_mode" in output.msg'
- name: Create lifecycle hook
- community.aws.ec2_asg_lifecycle_hook:
+ community.aws.autoscaling_lifecycle_hook:
region: "{{ aws_region }}"
autoscaling_group_name: "{{ resource_prefix }}-asg"
lifecycle_hook_name: "{{ resource_prefix }}-test-hook"
@@ -71,7 +70,7 @@
state: present
register: output
- - assert:
+ - ansible.builtin.assert:
that:
- output is changed
- output is not failed
@@ -79,7 +78,7 @@
- output.lifecycle_hook_info[0].heartbeat_timeout == 7000
- name: Create lifecycle hook - Idempotency
- community.aws.ec2_asg_lifecycle_hook:
+ community.aws.autoscaling_lifecycle_hook:
region: "{{ aws_region }}"
autoscaling_group_name: "{{ resource_prefix }}-asg"
lifecycle_hook_name: "{{ resource_prefix }}-test-hook"
@@ -89,14 +88,14 @@
state: present
register: output
- - assert:
+ - ansible.builtin.assert:
that:
- output is not changed
- output is not failed
- '"lifecycle_hook_info" not in output'
- name: Create lifecycle hook - check_mode (Idempotency)
- community.aws.ec2_asg_lifecycle_hook:
+ community.aws.autoscaling_lifecycle_hook:
region: "{{ aws_region }}"
autoscaling_group_name: "{{ resource_prefix }}-asg"
lifecycle_hook_name: "{{ resource_prefix }}-test-hook"
@@ -107,14 +106,14 @@
check_mode: true
register: output
- - assert:
+ - ansible.builtin.assert:
that:
- output is not changed
- output is not failed
- '"lifecycle_hook_info" not in output'
- name: Update lifecycle hook - check_mode
- community.aws.ec2_asg_lifecycle_hook:
+ community.aws.autoscaling_lifecycle_hook:
region: "{{ aws_region }}"
autoscaling_group_name: "{{ resource_prefix }}-asg"
lifecycle_hook_name: "{{ resource_prefix }}-test-hook"
@@ -125,7 +124,7 @@
check_mode: true
register: output
- - assert:
+ - ansible.builtin.assert:
that:
- output is changed
- output is not failed
@@ -133,7 +132,7 @@
- '"Would have modified AutoScalingGroup Lifecycle Hook if not in check_mode." in output.msg'
- name: Update lifecycle hook
- community.aws.ec2_asg_lifecycle_hook:
+ community.aws.autoscaling_lifecycle_hook:
region: "{{ aws_region }}"
autoscaling_group_name: "{{ resource_prefix }}-asg"
lifecycle_hook_name: "{{ resource_prefix }}-test-hook"
@@ -143,7 +142,7 @@
state: present
register: output
- - assert:
+ - ansible.builtin.assert:
that:
- output is changed
- output is not failed
@@ -151,7 +150,7 @@
- output.lifecycle_hook_info[0].heartbeat_timeout == 6000
- name: Update lifecycle hook - Idempotency
- community.aws.ec2_asg_lifecycle_hook:
+ community.aws.autoscaling_lifecycle_hook:
region: "{{ aws_region }}"
autoscaling_group_name: "{{ resource_prefix }}-asg"
lifecycle_hook_name: "{{ resource_prefix }}-test-hook"
@@ -161,14 +160,14 @@
state: present
register: output
- - assert:
+ - ansible.builtin.assert:
that:
- output is not changed
- output is not failed
- '"lifecycle_hook_info" not in output'
- name: Update lifecycle hook - check_mode (Idempotency)
- community.aws.ec2_asg_lifecycle_hook:
+ community.aws.autoscaling_lifecycle_hook:
region: "{{ aws_region }}"
autoscaling_group_name: "{{ resource_prefix }}-asg"
lifecycle_hook_name: "{{ resource_prefix }}-test-hook"
@@ -179,14 +178,14 @@
check_mode: true
register: output
- - assert:
+ - ansible.builtin.assert:
that:
- output is not changed
- output is not failed
- '"lifecycle_hook_info" not in output'
- name: Delete lifecycle hook - check_mode
- community.aws.ec2_asg_lifecycle_hook:
+ community.aws.autoscaling_lifecycle_hook:
region: "{{ aws_region }}"
autoscaling_group_name: "{{ resource_prefix }}-asg"
lifecycle_hook_name: "{{ resource_prefix }}-test-hook"
@@ -194,7 +193,7 @@
check_mode: true
register: output
- - assert:
+ - ansible.builtin.assert:
that:
- output is changed
- output is not failed
@@ -202,35 +201,35 @@
- '"Would have deleted AutoScalingGroup Lifecycle Hook if not in check_mode." in output.msg'
- name: Delete lifecycle hook
- community.aws.ec2_asg_lifecycle_hook:
+ community.aws.autoscaling_lifecycle_hook:
region: "{{ aws_region }}"
autoscaling_group_name: "{{ resource_prefix }}-asg"
lifecycle_hook_name: "{{ resource_prefix }}-test-hook"
state: absent
register: output
- - assert:
+ - ansible.builtin.assert:
that:
- output is changed
- output is not failed
- '"lifecycle_hook_removed" in output'
- name: Delete lifecycle hook - Idempotency
- community.aws.ec2_asg_lifecycle_hook:
+ community.aws.autoscaling_lifecycle_hook:
region: "{{ aws_region }}"
autoscaling_group_name: "{{ resource_prefix }}-asg"
lifecycle_hook_name: "{{ resource_prefix }}-test-hook"
state: absent
register: output
- - assert:
+ - ansible.builtin.assert:
that:
- output is not changed
- output is not failed
- '"lifecycle_hook_removed" not in output'
- name: Delete lifecycle hook - check_mode (Idempotency)
- community.aws.ec2_asg_lifecycle_hook:
+ community.aws.autoscaling_lifecycle_hook:
region: "{{ aws_region }}"
autoscaling_group_name: "{{ resource_prefix }}-asg"
lifecycle_hook_name: "{{ resource_prefix }}-test-hook"
@@ -238,7 +237,7 @@
check_mode: true
register: output
- - assert:
+ - ansible.builtin.assert:
that:
- output is not changed
- output is not failed
diff --git a/ansible_collections/community/aws/tests/integration/targets/autoscaling_lifecycle_hook/roles/ec2_asg_lifecycle_hook/tasks/env_cleanup.yml b/ansible_collections/community/aws/tests/integration/targets/autoscaling_lifecycle_hook/roles/ec2_asg_lifecycle_hook/tasks/env_cleanup.yml
index 3b4ee869b..1befe278a 100644
--- a/ansible_collections/community/aws/tests/integration/targets/autoscaling_lifecycle_hook/roles/ec2_asg_lifecycle_hook/tasks/env_cleanup.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/autoscaling_lifecycle_hook/roles/ec2_asg_lifecycle_hook/tasks/env_cleanup.yml
@@ -1,5 +1,6 @@
-- name: kill asg
- ec2_asg:
+---
+- name: Kill asg
+ amazon.aws.autoscaling_group:
name: "{{ resource_prefix }}-asg"
state: absent
register: removed
@@ -8,8 +9,8 @@
retries: 10
# Remove the testing dependencies
-- name: remove target group
- elb_target_group:
+- name: Remove target group
+ community.aws.elb_target_group:
name: "{{ item }}"
state: absent
register: removed
@@ -20,8 +21,8 @@
- "{{ tg1_name }}"
- "{{ tg2_name }}"
-- name: remove the load balancer
- ec2_elb_lb:
+- name: Remove the load balancer
+ amazon.aws.elb_classic_lb:
name: "{{ load_balancer_name }}"
state: absent
security_group_ids:
@@ -34,20 +35,20 @@
load_balancer_port: 80
instance_port: 80
health_check:
- ping_protocol: tcp
- ping_port: 80
- ping_path: "/"
- response_timeout: 5
- interval: 10
- unhealthy_threshold: 4
- healthy_threshold: 2
+ ping_protocol: tcp
+ ping_port: 80
+ ping_path: /
+ response_timeout: 5
+ interval: 10
+ unhealthy_threshold: 4
+ healthy_threshold: 2
register: removed
until: removed is not failed
ignore_errors: true
retries: 10
-- name: remove launch configs
- ec2_lc:
+- name: Remove launch configs
+ community.aws.autoscaling_launch_config:
name: "{{ item }}"
state: absent
register: removed
@@ -57,8 +58,8 @@
loop:
- "{{ resource_prefix }}-lc"
-- name: delete launch template
- ec2_launch_template:
+- name: Delete launch template
+ community.aws.ec2_launch_template:
name: "{{ resource_prefix }}-lt"
state: absent
register: del_lt
@@ -66,8 +67,8 @@
until: del_lt is not failed
ignore_errors: true
-- name: remove the security group
- ec2_group:
+- name: Remove the security group
+ amazon.aws.ec2_security_group:
name: "{{ resource_prefix }}-sg"
description: a security group for ansible tests
vpc_id: "{{ testing_vpc.vpc.id }}"
@@ -77,14 +78,14 @@
ignore_errors: true
retries: 10
-- name: remove routing rules
- ec2_vpc_route_table:
+- name: Remove routing rules
+ amazon.aws.ec2_vpc_route_table:
state: absent
vpc_id: "{{ testing_vpc.vpc.id }}"
tags:
created: "{{ resource_prefix }}-route"
routes:
- - dest: 0.0.0.0/0
+ - dest: "0.0.0.0/0"
gateway_id: "{{ igw.gateway_id }}"
subnets:
- "{{ testing_subnet.subnet.id }}"
@@ -93,8 +94,8 @@
ignore_errors: true
retries: 10
-- name: remove internet gateway
- ec2_vpc_igw:
+- name: Remove internet gateway
+ amazon.aws.ec2_vpc_igw:
vpc_id: "{{ testing_vpc.vpc.id }}"
state: absent
register: removed
@@ -102,8 +103,8 @@
ignore_errors: true
retries: 10
-- name: remove the subnet
- ec2_vpc_subnet:
+- name: Remove the subnet
+ amazon.aws.ec2_vpc_subnet:
state: absent
vpc_id: "{{ testing_vpc.vpc.id }}"
cidr: 10.55.77.0/24
@@ -112,8 +113,8 @@
ignore_errors: true
retries: 10
-- name: remove the VPC
- ec2_vpc_net:
+- name: Remove the VPC
+ amazon.aws.ec2_vpc_net:
name: "{{ resource_prefix }}-vpc"
cidr_block: 10.55.77.0/24
state: absent
diff --git a/ansible_collections/community/aws/tests/integration/targets/autoscaling_lifecycle_hook/roles/ec2_asg_lifecycle_hook/tasks/env_setup.yml b/ansible_collections/community/aws/tests/integration/targets/autoscaling_lifecycle_hook/roles/ec2_asg_lifecycle_hook/tasks/env_setup.yml
index 8e9be1d55..d51654310 100644
--- a/ansible_collections/community/aws/tests/integration/targets/autoscaling_lifecycle_hook/roles/ec2_asg_lifecycle_hook/tasks/env_setup.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/autoscaling_lifecycle_hook/roles/ec2_asg_lifecycle_hook/tasks/env_setup.yml
@@ -1,25 +1,25 @@
+---
- name: Run ec2_asg_lifecycle_hook integration tests.
block:
-
# ============================================================
# Set up the testing dependencies: VPC, subnet, security group, and two launch configurations
- name: Create VPC for use in testing
- ec2_vpc_net:
+ amazon.aws.ec2_vpc_net:
name: "{{ resource_prefix }}-vpc"
cidr_block: 10.55.77.0/24
tenancy: default
register: testing_vpc
- name: Create internet gateway for use in testing
- ec2_vpc_igw:
+ amazon.aws.ec2_vpc_igw:
vpc_id: "{{ testing_vpc.vpc.id }}"
state: present
register: igw
- name: Create subnet for use in testing
- ec2_vpc_subnet:
+ amazon.aws.ec2_vpc_subnet:
state: present
vpc_id: "{{ testing_vpc.vpc.id }}"
cidr: 10.55.77.0/24
@@ -28,19 +28,19 @@
Name: "{{ resource_prefix }}-subnet"
register: testing_subnet
- - name: create routing rules
- ec2_vpc_route_table:
+ - name: Create routing rules
+ amazon.aws.ec2_vpc_route_table:
vpc_id: "{{ testing_vpc.vpc.id }}"
tags:
created: "{{ resource_prefix }}-route"
routes:
- - dest: 0.0.0.0/0
+ - dest: "0.0.0.0/0"
gateway_id: "{{ igw.gateway_id }}"
subnets:
- "{{ testing_subnet.subnet.id }}"
- - name: create a security group with the vpc created in the ec2_setup
- ec2_group:
+ - name: Create a security group with the vpc created in the ec2_setup
+ amazon.aws.ec2_security_group:
name: "{{ resource_prefix }}-sg"
description: a security group for ansible tests
vpc_id: "{{ testing_vpc.vpc.id }}"
@@ -48,9 +48,9 @@
- proto: tcp
from_port: 22
to_port: 22
- cidr_ip: 0.0.0.0/0
+ cidr_ip: "0.0.0.0/0"
- proto: tcp
from_port: 80
to_port: 80
- cidr_ip: 0.0.0.0/0
+ cidr_ip: "0.0.0.0/0"
register: sg
diff --git a/ansible_collections/community/aws/tests/integration/targets/autoscaling_lifecycle_hook/roles/ec2_asg_lifecycle_hook/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/autoscaling_lifecycle_hook/roles/ec2_asg_lifecycle_hook/tasks/main.yml
index 16442c7fa..e38324bda 100644
--- a/ansible_collections/community/aws/tests/integration/targets/autoscaling_lifecycle_hook/roles/ec2_asg_lifecycle_hook/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/autoscaling_lifecycle_hook/roles/ec2_asg_lifecycle_hook/tasks/main.yml
@@ -3,38 +3,36 @@
# To add new tests you'll need to add a new host to the inventory and a matching
# '{{ inventory_hostname }}'.yml file in roles/ec2_asg_lifecycle_hook/tasks/
-- name: "Wrap up all tests and setup AWS credentials"
+- name: Wrap up all tests and setup AWS credentials
module_defaults:
group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"
aws_config:
retries:
# Unfortunately AWSRetry doesn't support paginators and boto3's paginators
# don't support any configuration of the delay between retries.
max_attempts: 20
- collections:
- - community.aws
block:
- - debug:
- msg: "{{ inventory_hostname }} start: {{ lookup('pipe','date') }}"
- - include_tasks: '{{ inventory_hostname }}.yml'
- - debug:
- msg: "{{ inventory_hostname }} finish: {{ lookup('pipe','date') }}"
+ - ansible.builtin.debug:
+ msg: "{{ inventory_hostname }} start: {{ lookup('pipe', 'date') }}"
+ - ansible.builtin.include_tasks: "{{ inventory_hostname }}.yml"
+ - ansible.builtin.debug:
+ msg: "{{ inventory_hostname }} finish: {{ lookup('pipe', 'date') }}"
always:
- - set_fact:
- _role_complete: True
+ - ansible.builtin.set_fact:
+ _role_complete: true
- vars:
completed_hosts: '{{ ansible_play_hosts_all | map("extract", hostvars, "_role_complete") | list | select("defined") | list | length }}'
- hosts_in_play: '{{ ansible_play_hosts_all | length }}'
- debug:
+ hosts_in_play: "{{ ansible_play_hosts_all | length }}"
+ ansible.builtin.debug:
msg: "{{ completed_hosts }} of {{ hosts_in_play }} complete"
- - include_tasks: env_cleanup.yml
+ - ansible.builtin.include_tasks: env_cleanup.yml
vars:
completed_hosts: '{{ ansible_play_hosts_all | map("extract", hostvars, "_role_complete") | list | select("defined") | list | length }}'
- hosts_in_play: '{{ ansible_play_hosts_all | length }}'
+ hosts_in_play: "{{ ansible_play_hosts_all | length }}"
when:
- - completed_hosts == hosts_in_play
+ - completed_hosts == hosts_in_play
diff --git a/ansible_collections/community/aws/tests/integration/targets/autoscaling_policy/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/autoscaling_policy/tasks/main.yml
index 24b3eea62..684522d64 100644
--- a/ansible_collections/community/aws/tests/integration/targets/autoscaling_policy/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/autoscaling_policy/tasks/main.yml
@@ -12,22 +12,22 @@
- module_defaults:
group/aws:
region: "{{ aws_region }}"
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
collections:
- amazon.aws
block:
- name: create trivial launch_configuration
- ec2_lc:
+ autoscaling_launch_config:
name: "{{ scaling_policy_lc_name }}"
state: present
instance_type: t3.nano
image_id: "{{ ec2_ami_id }}"
- name: create trivial ASG
- ec2_asg:
+ autoscaling_group:
name: "{{ scaling_policy_asg_name }}"
state: present
launch_config_name: "{{ scaling_policy_lc_name }}"
@@ -36,7 +36,7 @@
desired_capacity: 0
- name: Create Simple Scaling policy using implicit defaults
- ec2_scaling_policy:
+ autoscaling_policy:
name: "{{ resource_prefix }}_simplescaling_policy"
asg_name: "{{ scaling_policy_asg_name }}"
state: present
@@ -46,11 +46,11 @@
- assert:
that:
- - result.policy_name == "{{ resource_prefix }}_simplescaling_policy"
+ - result.policy_name == resource_prefix ~ '_simplescaling_policy'
- result.changed
- name: Update Simple Scaling policy using explicit defaults
- ec2_scaling_policy:
+ autoscaling_policy:
name: "{{ resource_prefix }}_simplescaling_policy"
asg_name: "{{ scaling_policy_asg_name }}"
state: present
@@ -61,11 +61,11 @@
- assert:
that:
- - result.policy_name == "{{ resource_prefix }}_simplescaling_policy"
+ - result.policy_name == resource_prefix ~ '_simplescaling_policy'
- not result.changed
- name: min_adjustment_step is ignored with ChangeInCapacity
- ec2_scaling_policy:
+ autoscaling_policy:
name: "{{ resource_prefix }}_simplescaling_policy"
asg_name: "{{ scaling_policy_asg_name }}"
state: present
@@ -77,12 +77,12 @@
- assert:
that:
- - result.policy_name == "{{ resource_prefix }}_simplescaling_policy"
+ - result.policy_name == resource_prefix ~ '_simplescaling_policy'
- not result.changed
- result.adjustment_type == "ChangeInCapacity"
- name: Change Simple Scaling policy adjustment_type to PercentChangeInCapacity
- ec2_scaling_policy:
+ autoscaling_policy:
name: "{{ resource_prefix }}_simplescaling_policy"
asg_name: "{{ scaling_policy_asg_name }}"
state: present
@@ -94,12 +94,12 @@
- assert:
that:
- - result.policy_name == "{{ resource_prefix }}_simplescaling_policy"
+ - result.policy_name == resource_prefix ~ '_simplescaling_policy'
- result.changed
- result.adjustment_type == "PercentChangeInCapacity"
- name: Remove Simple Scaling policy
- ec2_scaling_policy:
+ autoscaling_policy:
name: "{{ resource_prefix }}_simplescaling_policy"
asg_name: "{{ scaling_policy_asg_name }}"
state: absent
@@ -110,7 +110,7 @@
- result.changed
- name: Create Step Scaling policy
- ec2_scaling_policy:
+ autoscaling_policy:
name: "{{ resource_prefix }}_stepscaling_policy"
asg_name: "{{ scaling_policy_asg_name }}"
state: present
@@ -126,11 +126,11 @@
- assert:
that:
- - result.policy_name == "{{ resource_prefix }}_stepscaling_policy"
+ - result.policy_name == resource_prefix ~ '_stepscaling_policy'
- result.changed
- name: Add another step
- ec2_scaling_policy:
+ autoscaling_policy:
name: "{{ resource_prefix }}_stepscaling_policy"
asg_name: "{{ scaling_policy_asg_name }}"
state: present
@@ -149,12 +149,12 @@
- assert:
that:
- - result.policy_name == "{{ resource_prefix }}_stepscaling_policy"
+ - result.policy_name == resource_prefix ~ '_stepscaling_policy'
- result.changed
- result.adjustment_type == "PercentChangeInCapacity"
- name: Remove Step Scaling policy
- ec2_scaling_policy:
+ autoscaling_policy:
name: "{{ resource_prefix }}_stepscaling_policy"
asg_name: "{{ scaling_policy_asg_name }}"
state: absent
@@ -165,7 +165,7 @@
- result.changed
- name: Remove Step Scaling policy (idemopotency)
- ec2_scaling_policy:
+ autoscaling_policy:
name: "{{ resource_prefix }}_stepscaling_policy"
asg_name: "{{ scaling_policy_asg_name }}"
state: absent
@@ -177,7 +177,7 @@
- result is successful
- name: create TargetTracking predefined policy
- ec2_scaling_policy:
+ autoscaling_policy:
name: "{{ resource_prefix }}_targettracking_predefined_policy"
policy_type: TargetTrackingScaling
target_tracking_config:
@@ -189,12 +189,12 @@
- assert:
that:
- - result.policy_name == "{{ resource_prefix }}_targettracking_predefined_policy"
+ - result.policy_name == resource_prefix ~ '_targettracking_predefined_policy'
- result.changed
- result is successful
- name: create TargetTrackingScaling predefined policy (idempotency)
- ec2_scaling_policy:
+ autoscaling_policy:
name: "{{ resource_prefix }}_targettracking_predefined_policy"
policy_type: TargetTrackingScaling
target_tracking_config:
@@ -206,12 +206,12 @@
- assert:
that:
- - result.policy_name == "{{ resource_prefix }}_targettracking_predefined_policy"
+ - result.policy_name == resource_prefix ~ '_targettracking_predefined_policy'
- result is not changed
# # It would be good to also test this but we would need an Target group and an ALB
# - name: create TargetTracking predefined policy with resource_label
-# ec2_scaling_policy:
+# autoscaling_policy:
# name: "{{ resource_prefix }}_targettracking_predefined_rl_policy"
# policy_type: TargetTrackingScaling
# target_tracking_config:
@@ -229,7 +229,7 @@
# - result is successful
#
# - name: create TargetTracking predefined policy with resource_label (idempotency)
-# ec2_scaling_policy:
+# autoscaling_policy:
# name: "{{ resource_prefix }}_targettracking_predefined_rl_policy"
# policy_type: TargetTrackingScaling
# target_tracking_config:
@@ -246,7 +246,7 @@
# - result is not changed
- name: create TargetTrackingScaling custom policy
- ec2_scaling_policy:
+ autoscaling_policy:
name: "{{ resource_prefix }}_targettracking_custom_policy"
policy_type: TargetTrackingScaling
target_tracking_config:
@@ -263,12 +263,12 @@
- assert:
that:
- - result.policy_name == "{{ resource_prefix }}_targettracking_custom_policy"
+ - result.policy_name == resource_prefix ~ '_targettracking_custom_policy'
- result.changed
- result is successful
- name: create TargetTrackingScaling custom policy (idempotency)
- ec2_scaling_policy:
+ autoscaling_policy:
name: "{{ resource_prefix }}_targettracking_custom_policy"
policy_type: TargetTrackingScaling
target_tracking_config:
@@ -285,14 +285,14 @@
- assert:
that:
- - result.policy_name == "{{ resource_prefix }}_targettracking_custom_policy"
+ - result.policy_name == resource_prefix ~ '_targettracking_custom_policy'
- result is not changed
always:
# ============================================================
- name: Remove the scaling policies
- ec2_scaling_policy:
+ autoscaling_policy:
name: "{{ item }}"
state: absent
register: result
@@ -305,13 +305,13 @@
ignore_errors: yes
- name: remove the ASG
- ec2_asg:
+ autoscaling_group:
name: "{{ scaling_policy_asg_name }}"
state: absent
ignore_errors: yes
- name: remove the Launch Configuration
- ec2_lc:
+ autoscaling_launch_config:
name: "{{ scaling_policy_lc_name }}"
state: absent
ignore_errors: yes
diff --git a/ansible_collections/community/aws/tests/integration/targets/autoscaling_scheduled_action/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/autoscaling_scheduled_action/tasks/main.yml
index c78c7efae..4c0e97220 100644
--- a/ansible_collections/community/aws/tests/integration/targets/autoscaling_scheduled_action/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/autoscaling_scheduled_action/tasks/main.yml
@@ -5,9 +5,9 @@
- community.aws
module_defaults:
group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"
block:
## Set up the testing dependencies: VPC, subnet, security group, and launch configuration
@@ -29,7 +29,7 @@
register: testing_subnet
- name: create a security group with the vpc created in the ec2_setup
- ec2_group:
+ ec2_security_group:
name: "{{ resource_prefix }}-sg"
description: a security group for ansible tests
vpc_id: "{{ testing_vpc.vpc.id }}"
@@ -45,7 +45,7 @@
register: sg
- name: ensure launch configs exist
- ec2_lc:
+ autoscaling_launch_config:
name: "{{ resource_prefix }}-lc"
assign_public_ip: true
image_id: "{{ ec2_ami_id }}"
@@ -53,7 +53,7 @@
instance_type: t3.micro
- name: Create ASG ready
- ec2_asg:
+ autoscaling_group:
name: "{{ resource_prefix }}-asg"
launch_config_name: "{{ resource_prefix }}-lc"
desired_capacity: 1
@@ -70,10 +70,10 @@
## Create minimal basic scheduled action
- name: Create basic scheduled_action - check_mode
- ec2_asg_scheduled_action:
+ autoscaling_scheduled_action:
autoscaling_group_name: "{{ resource_prefix }}-asg"
scheduled_action_name: "{{ resource_prefix }}-test"
- start_time: 2022 October 25 08:00 UTC
+ start_time: 2027 November 9 08:00 UTC
recurrence: 40 22 * * 1-5
desired_capacity: 2
state: present
@@ -87,10 +87,10 @@
- scheduled_action is changed
- name: Create basic scheduled_action
- ec2_asg_scheduled_action:
+ autoscaling_scheduled_action:
autoscaling_group_name: "{{ resource_prefix }}-asg"
scheduled_action_name: "{{ resource_prefix }}-test"
- start_time: 2022 October 25 08:00 UTC
+ start_time: 2027 November 9 08:00 UTC
recurrence: 40 22 * * 1-5
desired_capacity: 2
state: present
@@ -101,14 +101,14 @@
that:
- scheduled_action is successful
- scheduled_action is changed
- - scheduled_action.scheduled_action_name == "{{ resource_prefix }}-test"
+ - scheduled_action.scheduled_action_name == resource_prefix ~ '-test'
- scheduled_action.desired_capacity == 2
- name: Create basic scheduled_action - idempotent
- ec2_asg_scheduled_action:
+ autoscaling_scheduled_action:
autoscaling_group_name: "{{ resource_prefix }}-asg"
scheduled_action_name: "{{ resource_prefix }}-test"
- start_time: 2022 October 25 08:00 UTC
+ start_time: 2027 November 9 08:00 UTC
recurrence: 40 22 * * 1-5
desired_capacity: 2
state: present
@@ -122,10 +122,10 @@
## Update minimal basic scheduled action
- name: Update basic scheduled_action - check_mode
- ec2_asg_scheduled_action:
+ autoscaling_scheduled_action:
autoscaling_group_name: "{{ resource_prefix }}-asg"
scheduled_action_name: "{{ resource_prefix }}-test"
- start_time: 2022 October 25 08:00 UTC
+ start_time: 2027 November 9 08:00 UTC
recurrence: 40 22 * * 1-5
desired_capacity: 3
min_size: 3
@@ -140,10 +140,10 @@
- scheduled_action is changed
- name: Update basic scheduled_action
- ec2_asg_scheduled_action:
+ autoscaling_scheduled_action:
autoscaling_group_name: "{{ resource_prefix }}-asg"
scheduled_action_name: "{{ resource_prefix }}-test"
- start_time: 2022 October 25 08:00 UTC
+ start_time: 2027 November 9 08:00 UTC
recurrence: 40 22 * * 1-5
desired_capacity: 3
min_size: 3
@@ -155,15 +155,15 @@
that:
- scheduled_action is successful
- scheduled_action is changed
- - scheduled_action.scheduled_action_name == "{{ resource_prefix }}-test"
+ - scheduled_action.scheduled_action_name == resource_prefix ~ '-test'
- scheduled_action.desired_capacity == 3
- scheduled_action.min_size == 3
- name: Update basic scheduled_action - idempotent
- ec2_asg_scheduled_action:
+ autoscaling_scheduled_action:
autoscaling_group_name: "{{ resource_prefix }}-asg"
scheduled_action_name: "{{ resource_prefix }}-test"
- start_time: 2022 October 25 08:00 UTC
+ start_time: 2027 November 9 08:00 UTC
recurrence: 40 22 * * 1-5
desired_capacity: 3
min_size: 3
@@ -178,11 +178,11 @@
## Create advanced scheduled action
- name: Create advanced scheduled_action - check_mode
- ec2_asg_scheduled_action:
+ autoscaling_scheduled_action:
autoscaling_group_name: "{{ resource_prefix }}-asg"
scheduled_action_name: "{{ resource_prefix }}-test"
- start_time: 2022 October 25 09:00 UTC
- end_time: 2022 October 25 10:00 UTC
+ start_time: 2027 November 9 09:00 UTC
+ end_time: 2027 November 9 10:00 UTC
time_zone: Europe/London
recurrence: 40 22 * * 1-5
min_size: 2
@@ -199,11 +199,11 @@
- advanced_scheduled_action is changed
- name: Create advanced scheduled_action
- ec2_asg_scheduled_action:
+ autoscaling_scheduled_action:
autoscaling_group_name: "{{ resource_prefix }}-asg"
scheduled_action_name: "{{ resource_prefix }}-test1"
- start_time: 2022 October 25 09:00 UTC
- end_time: 2022 October 25 10:00 UTC
+ start_time: 2027 November 9 09:00 UTC
+ end_time: 2027 November 9 10:00 UTC
time_zone: Europe/London
recurrence: 40 22 * * 1-5
min_size: 2
@@ -217,18 +217,18 @@
that:
- advanced_scheduled_action is successful
- advanced_scheduled_action is changed
- - advanced_scheduled_action.scheduled_action_name == "{{ resource_prefix }}-test1"
+ - advanced_scheduled_action.scheduled_action_name == resource_prefix ~ '-test1'
- advanced_scheduled_action.desired_capacity == 2
- advanced_scheduled_action.min_size == 2
- advanced_scheduled_action.max_size == 5
- advanced_scheduled_action.time_zone == "Europe/London"
- name: Create advanced scheduled_action - idempotent
- ec2_asg_scheduled_action:
+ autoscaling_scheduled_action:
autoscaling_group_name: "{{ resource_prefix }}-asg"
scheduled_action_name: "{{ resource_prefix }}-test1"
- start_time: 2022 October 25 09:00 UTC
- end_time: 2022 October 25 10:00 UTC
+ start_time: 2027 November 9 09:00 UTC
+ end_time: 2027 November 9 10:00 UTC
time_zone: Europe/London
recurrence: 40 22 * * 1-5
min_size: 2
@@ -245,7 +245,7 @@
## Delete scheduled action
- name: Delete scheduled_action - check_mode
- ec2_asg_scheduled_action:
+ autoscaling_scheduled_action:
autoscaling_group_name: "{{ resource_prefix }}-asg"
scheduled_action_name: "{{ resource_prefix }}-test1"
state: absent
@@ -259,7 +259,7 @@
- scheduled_action_deletion is changed
- name: Delete scheduled_action
- ec2_asg_scheduled_action:
+ autoscaling_scheduled_action:
autoscaling_group_name: "{{ resource_prefix }}-asg"
scheduled_action_name: "{{ resource_prefix }}-test1"
state: absent
@@ -272,7 +272,7 @@
- scheduled_action_deletion is changed
- name: Delete scheduled_action - idempotent
- ec2_asg_scheduled_action:
+ autoscaling_scheduled_action:
autoscaling_group_name: "{{ resource_prefix }}-asg"
scheduled_action_name: "{{ resource_prefix }}-test1"
state: absent
@@ -285,7 +285,7 @@
- scheduled_action_deletion is not changed
always:
- name: Remove ASG
- ec2_asg:
+ autoscaling_group:
name: "{{ resource_prefix }}-asg"
state: absent
register: removed
@@ -295,7 +295,7 @@
# Remove the testing dependencies
- name: Remove launch configs
- ec2_lc:
+ autoscaling_launch_config:
name: "{{ resource_prefix }}-lc"
state: absent
register: removed
@@ -304,7 +304,7 @@
retries: 10
- name: Remove the security group
- ec2_group:
+ ec2_security_group:
name: "{{ resource_prefix }}-sg"
description: a security group for ansible tests
vpc_id: "{{ testing_vpc.vpc.id }}"
diff --git a/ansible_collections/community/aws/tests/integration/targets/aws_region_info/main.yml b/ansible_collections/community/aws/tests/integration/targets/aws_region_info/main.yml
deleted file mode 100644
index abffda916..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/aws_region_info/main.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-- hosts: localhost
- connection: local
- environment: "{{ ansible_test.environment }}"
- tasks:
- - include_tasks: 'tasks/tests.yml'
diff --git a/ansible_collections/community/aws/tests/integration/targets/aws_region_info/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/aws_region_info/tasks/main.yml
deleted file mode 100644
index 3edbbaded..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/aws_region_info/tasks/main.yml
+++ /dev/null
@@ -1,107 +0,0 @@
----
-- module_defaults:
- group/aws:
- aws_access_key: '{{ aws_access_key | default(omit) }}'
- aws_secret_key: '{{ aws_secret_key | default(omit) }}'
- security_token: '{{ security_token | default(omit) }}'
- region: '{{ aws_region | default(omit) }}'
-
- block:
- - name: 'List available Regions'
- aws_region_info:
- register: regions
-
- - name: check task return attributes
- vars:
- first_region: '{{ regions.regions[0] }}'
- assert:
- that:
- - regions is successful
- - regions is not changed
- - '"regions" in regions'
- - '"endpoint" in first_region'
- - '"opt_in_status" in first_region'
- - '"region_name" in first_region'
-
- - name: 'List available Regions - check_mode'
- aws_region_info:
- register: check_regions
-
- - name: check task return attributes - check_mode
- vars:
- first_region: '{{ check_regions.regions[0] }}'
- assert:
- that:
- - check_regions is successful
- - check_regions is not changed
- - '"regions" in check_regions'
- - '"endpoint" in first_region'
- - '"opt_in_status" in first_region'
- - '"region_name" in first_region'
-
- - name: 'Filter available Regions using - ("region-name")'
- aws_region_info:
- filters:
- region-name: 'us-west-1'
- register: us_west_1
-
- - name: check task return attributes - filtering using -
- vars:
- first_region: '{{ us_west_1.regions[0] }}'
- assert:
- that:
- - us_west_1 is successful
- - us_west_1 is not changed
- - '"regions" in us_west_1'
- - us_west_1.regions | length == 1
- - '"endpoint" in first_region'
- - first_region.endpoint == 'ec2.us-west-1.amazonaws.com'
- - '"opt_in_status" in first_region'
- - first_region.opt_in_status == 'opt-in-not-required'
- - '"region_name" in first_region'
- - first_region.region_name == 'us-west-1'
-
- - name: 'Filter available Regions using _ ("region_name")'
- aws_region_info:
- filters:
- region_name: 'us-west-2'
- register: us_west_2
-
- - name: check task return attributes - filtering using _
- vars:
- first_region: '{{ us_west_2.regions[0] }}'
- assert:
- that:
- - us_west_2 is successful
- - us_west_2 is not changed
- - '"regions" in us_west_2'
- - us_west_2.regions | length == 1
- - '"endpoint" in first_region'
- - first_region.endpoint == 'ec2.us-west-2.amazonaws.com'
- - '"opt_in_status" in first_region'
- - first_region.opt_in_status == 'opt-in-not-required'
- - '"region_name" in first_region'
- - first_region.region_name == 'us-west-2'
-
- - name: 'Filter available Regions using _ and - to check precedence'
- aws_region_info:
- filters:
- region-name: 'eu-west-1'
- region_name: 'eu-central-1'
- register: regions_prededence
-
- - name: check task return attributes - precedence
- vars:
- first_region: '{{ regions_prededence.regions[0] }}'
- assert:
- that:
- - regions_prededence is successful
- - regions_prededence is not changed
- - '"regions" in regions_prededence'
- - regions_prededence.regions | length == 1
- - '"endpoint" in first_region'
- - first_region.endpoint == 'ec2.eu-central-1.amazonaws.com'
- - '"opt_in_status" in first_region'
- - first_region.opt_in_status == 'opt-in-not-required'
- - '"region_name" in first_region'
- - first_region.region_name == 'eu-central-1'
diff --git a/ansible_collections/community/aws/tests/integration/targets/cloudformation_exports_info/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/cloudformation_exports_info/tasks/main.yml
index eb703d49e..f1b99df1b 100644
--- a/ansible_collections/community/aws/tests/integration/targets/cloudformation_exports_info/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/cloudformation_exports_info/tasks/main.yml
@@ -1,9 +1,9 @@
- name: set connection information for aws modules and run tasks
module_defaults:
group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"
collections:
- amazon.aws
diff --git a/ansible_collections/community/aws/tests/integration/targets/cloudformation_stack_set/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/cloudformation_stack_set/tasks/main.yml
index afd614a55..39f13a71f 100644
--- a/ansible_collections/community/aws/tests/integration/targets/cloudformation_stack_set/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/cloudformation_stack_set/tasks/main.yml
@@ -5,14 +5,14 @@
- name: set up aws connection info
set_fact:
aws_connection_info: &aws_connection_info
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"
aws_secondary_connection_info: &aws_secondary_connection_info
- aws_access_key: "{{ secondary_aws_access_key }}"
- aws_secret_key: "{{ secondary_aws_secret_key }}"
- security_token: "{{ secondary_security_token }}"
+ access_key: "{{ secondary_aws_access_key }}"
+ secret_key: "{{ secondary_aws_secret_key }}"
+ session_token: "{{ secondary_security_token | default(omit) }}"
region: "{{ aws_region }}"
no_log: true
diff --git a/ansible_collections/community/aws/tests/integration/targets/cloudfront_distribution/aliases b/ansible_collections/community/aws/tests/integration/targets/cloudfront_distribution/aliases
index e04e1b287..4ef4b2067 100644
--- a/ansible_collections/community/aws/tests/integration/targets/cloudfront_distribution/aliases
+++ b/ansible_collections/community/aws/tests/integration/targets/cloudfront_distribution/aliases
@@ -1,4 +1 @@
-# reason: broken
-disabled
-
cloud/aws
diff --git a/ansible_collections/community/aws/tests/integration/targets/cloudfront_distribution/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/cloudfront_distribution/tasks/main.yml
index a6ac0571a..281097db1 100644
--- a/ansible_collections/community/aws/tests/integration/targets/cloudfront_distribution/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/cloudfront_distribution/tasks/main.yml
@@ -1,8 +1,8 @@
- module_defaults:
group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
cloudfront_distribution:
alias: "{{ cloudfront_alias | default(omit) }}"
viewer_certificate: "{{ cloudfront_viewer_cert | default(omit) }}"
@@ -19,12 +19,18 @@
default_cache_behavior:
target_origin_id: "{{ cloudfront_hostname }}-origin.example.com"
state: present
- purge_origins: yes
+ purge_origins: true
register: cf_distribution
- set_fact:
distribution_id: '{{ cf_distribution.id }}'
+ - name: ensure that default value of 'enabled' is 'true'
+ assert:
+ that:
+ - cf_distribution.changed
+ - cf_distribution.enabled
+
- name: ensure that default value of 'ipv6_enabled' is 'false'
assert:
that:
@@ -49,7 +55,7 @@
cloudfront_distribution:
state: present
distribution_id: "{{ distribution_id }}"
- ipv6_enabled: True
+ ipv6_enabled: true
register: cf_update_ipv6
- name: ensure the 'ipv6_enabled' value has changed (new value is true)
@@ -76,7 +82,7 @@
cloudfront_distribution:
state: present
distribution_id: "{{ distribution_id }}"
- ipv6_enabled: True
+ ipv6_enabled: true
register: cf_update_ipv6
- name: ensure the 'ipv6_enabled' value has changed (new value is true)
@@ -86,45 +92,122 @@
# - not cf_update_ipv6.changed
- cf_update_ipv6.is_ipv6_enabled
- - name: re-run cloudfront distribution with same defaults
+ - name: Ensure that default value of 'http_version' is 'http2'
+ assert:
+ that:
+ - cf_update_ipv6.http_version == 'http2'
+
+ - name: Update the distribution http_version to http2and3
+ cloudfront_distribution:
+ state: present
+ distribution_id: "{{ distribution_id }}"
+ http_version: http2and3
+ register: cf_update_http_version
+
+ - name: Ensure that default value of 'http_version' is 'http2and3'
+ assert:
+ that:
+ - cf_update_http_version.changed
+ - cf_update_http_version.http_version == 'http2and3'
+
+ # - name: re-run cloudfront distribution with same defaults
+ # cloudfront_distribution:
+ # distribution_id: "{{ distribution_id }}"
+ # origins:
+ # - domain_name: "{{ cloudfront_hostname }}-origin.example.com"
+ # state: present
+ # register: cf_dist_no_update
+
+ # - name: ensure distribution was not updated
+ # assert:
+ # that:
+ # - not cf_dist_no_update.changed
+
+ # - name: re-run cloudfront distribution using distribution id
+ # cloudfront_distribution:
+ # distribution_id: "{{ distribution_id }}"
+ # purge_origins: no
+ # state: present
+ # register: cf_dist_with_id
+
+ # - name: ensure distribution was not updated
+ # assert:
+ # that:
+ # - not cf_dist_with_id.changed
+
+ - name: update origin http port
cloudfront_distribution:
distribution_id: "{{ distribution_id }}"
origins:
- domain_name: "{{ cloudfront_hostname }}-origin.example.com"
+ custom_origin_config:
+ http_port: 8080
state: present
- register: cf_dist_no_update
+ register: update_origin_http_port
- - name: ensure distribution was not updated
+ - name: ensure http port was updated
assert:
that:
- - not cf_dist_no_update.changed
+ - update_origin_http_port.changed
- - name: re-run cloudfront distribution using distribution id
+ - name: enable origin Origin Shield
cloudfront_distribution:
distribution_id: "{{ distribution_id }}"
- purge_origins: no
+ origins:
+ - domain_name: "{{ cloudfront_hostname }}-origin.example.com"
+ custom_origin_config:
+ http_port: 8080
+ origin_shield:
+ enabled: true
+ origin_shield_region: '{{ aws_region }}'
state: present
- register: cf_dist_with_id
+ register: update_origin_origin_shield
- - name: ensure distribution was not updated
+ - name: ensure origin Origin Shield was enabled
assert:
that:
- - not cf_dist_with_id.changed
-
- - name: update origin http port
+ - update_origin_origin_shield.changed
+ - update_origin_origin_shield.origins['items'][0].origin_shield.enabled
+ - update_origin_origin_shield.origins['items'][0].origin_shield.origin_shield_region == aws_region
+
+ # TODO: fix module idempotency issue
+ # - name: enable origin Origin Shield again to test idempotency
+ # cloudfront_distribution:
+ # distribution_id: "{{ distribution_id }}"
+ # origins:
+ # - domain_name: "{{ cloudfront_hostname }}-origin.example.com"
+ # custom_origin_config:
+ # http_port: 8080
+ # origin_shield:
+ # enabled: true
+ # origin_shield_region: '{{ aws_region }}'
+ # state: present
+ # register: update_origin_origin_shield_idempotency
+
+ # - name: test idempotency for Origin Shield
+ # assert:
+ # that:
+ # - not update_origin_origin_shield_idempotency.changed
+ # - update_origin_origin_shield_idempotency.origins['items'][0].origin_shield.enabled
+ # - update_origin_origin_shield_idempotency.origins['items'][0].origin_shield.origin_shield_region == '{{ aws_region }}'
+
+ - name: disable origin Origin Shield
cloudfront_distribution:
distribution_id: "{{ distribution_id }}"
origins:
- domain_name: "{{ cloudfront_hostname }}-origin.example.com"
custom_origin_config:
http_port: 8080
+ origin_shield:
+ enabled: false
state: present
- register: update_origin_http_port
+ register: update_origin_origin_shield_disable
- - name: ensure http port was updated
+ - name: ensure origin Origin Shield was disabled
assert:
that:
- - update_origin_http_port.changed
+ - update_origin_origin_shield_disable.changed
+ - not update_origin_origin_shield_disable.origins['items'][0].origin_shield.enabled
- name: update restrictions
cloudfront_distribution:
@@ -167,7 +250,7 @@
id: "{{ resource_prefix }}2.example.com"
default_root_object: index.html
state: present
- wait: yes
+ wait: true
register: cf_add_origin
- name: ensure origin was added
@@ -186,7 +269,7 @@
http_port: 8080
- domain_name: "{{ resource_prefix }}2.example.com"
default_root_object: index.html
- wait: yes
+ wait: true
state: present
register: cf_rerun_second_origin
@@ -194,7 +277,7 @@
assert:
that:
- cf_rerun_second_origin.origins.quantity == 2
- - not cf_rerun_second_origin.changed
+ # - not cf_rerun_second_origin.changed
- name: run with origins in reverse order
cloudfront_distribution:
@@ -211,7 +294,7 @@
assert:
that:
- cf_rerun_second_origin_reversed.origins.quantity == 2
- - not cf_rerun_second_origin_reversed.changed
+ # - not cf_rerun_second_origin_reversed.changed
- name: purge first origin
@@ -221,7 +304,7 @@
- domain_name: "{{ resource_prefix }}2.example.com"
default_cache_behavior:
target_origin_id: "{{ resource_prefix }}2.example.com"
- purge_origins: yes
+ purge_origins: true
state: present
register: cf_purge_origin
@@ -278,12 +361,13 @@
- name: delete distribution
cloudfront_distribution:
distribution_id: "{{ distribution_id }}"
- enabled: no
- wait: yes
+ enabled: false
+ wait: true
state: absent
- - name: create distribution with tags
+ - name: create cloudfront distribution with tags and as disabled
cloudfront_distribution:
+ enabled: false
origins:
- domain_name: "{{ resource_prefix }}2.example.com"
id: "{{ resource_prefix }}2.example.com"
@@ -296,6 +380,12 @@
- set_fact:
distribution_id: '{{ cf_second_distribution.id }}'
+ - name: ensure that the value of 'enabled' is 'false'
+ assert:
+ that:
+ - cf_second_distribution.changed
+ - not cf_second_distribution.enabled
+
- name: ensure tags were set on creation
assert:
that:
@@ -313,14 +403,14 @@
tags:
ATag: tag1
Another: tag
- purge_tags: yes
+ purge_tags: true
state: present
register: rerun_with_purge_tags
- name: ensure that re-running didn't change
assert:
that:
- - not rerun_with_purge_tags.changed
+ # - not rerun_with_purge_tags.changed
- rerun_with_purge_tags.tags|length == 2
- name: add new tag to distribution
@@ -330,7 +420,7 @@
- domain_name: "{{ resource_prefix }}2.example.com"
tags:
Third: thing
- purge_tags: no
+ purge_tags: false
state: present
register: update_with_new_tag
@@ -364,7 +454,7 @@
- name: check that reversing cache behaviors changes nothing when purge_cache_behaviors unset
assert:
that:
- - not reverse_cache_behaviors.changed
+ # - not reverse_cache_behaviors.changed
- reverse_cache_behaviors.cache_behaviors|length == 2
- name: reverse some cache behaviors properly
@@ -373,7 +463,7 @@
origins:
- domain_name: "{{ resource_prefix }}2.example.com"
cache_behaviors: "{{ cloudfront_test_cache_behaviors|reverse|list }}"
- purge_cache_behaviors: yes
+ purge_cache_behaviors: true
state: present
register: reverse_cache_behaviors_with_purge
@@ -389,10 +479,10 @@
origins:
- domain_name: "{{ resource_prefix }}3.example.com"
id: "{{ resource_prefix }}3.example.com"
- purge_origins: yes
+ purge_origins: true
state: present
register: remove_origin_in_use
- ignore_errors: yes
+ ignore_errors: true
- name: check that removing in use origin fails
assert:
@@ -412,18 +502,14 @@
# - path_pattern: /another/path
# target_origin_id: "{{ resource_prefix }}3.example.com"
# state: present
- # aws_access_key: "{{ aws_access_key|default(omit) }}"
- # aws_secret_key: "{{ aws_secret_key|default(omit) }}"
- # security_token: "{{ security_token|default(omit) }}"
- # profile: "{{ profile|default(omit) }}"
# register: update_cache_behaviors in use
- name: create an s3 bucket for next test
# note that although public-read allows reads that we want to stop with origin_access_identity,
# we also need to test without origin_access_identity and it's hard to change bucket perms later
- aws_s3:
- bucket: "{{ resource_prefix }}-bucket"
- mode: create
+ s3_bucket:
+ name: "{{ resource_prefix }}-bucket"
+ state: present
- name: update origin to point to the s3 bucket
cloudfront_distribution:
@@ -431,7 +517,7 @@
origins:
- domain_name: "{{ resource_prefix }}-bucket.s3.amazonaws.com"
id: "{{ resource_prefix }}3.example.com"
- s3_origin_access_identity_enabled: yes
+ s3_origin_access_identity_enabled: true
state: present
register: update_origin_to_s3
@@ -448,7 +534,7 @@
origins:
- domain_name: "{{ resource_prefix }}-bucket.s3.amazonaws.com"
id: "{{ resource_prefix }}3.example.com"
- s3_origin_access_identity_enabled: no
+ s3_origin_access_identity_enabled: false
state: present
register: update_origin_to_s3_without_origin_access
@@ -460,9 +546,9 @@
loop: "{{ update_origin_to_s3_without_origin_access.origins['items'] }}"
- name: delete the s3 bucket
- aws_s3:
- bucket: "{{ resource_prefix }}-bucket"
- mode: delete
+ s3_bucket:
+ name: "{{ resource_prefix }}-bucket"
+ state: absent
- name: check that custom_origin_config can't be used with origin_access_identity enabled
cloudfront_distribution:
@@ -470,18 +556,64 @@
origins:
- domain_name: "{{ resource_prefix }}-bucket.s3.amazonaws.com"
id: "{{ resource_prefix }}3.example.com"
- s3_origin_access_identity_enabled: yes
+ s3_origin_access_identity_enabled: true
custom_origin_config:
origin_protocol_policy: 'http-only'
state: present
register: update_origin_to_s3_with_origin_access_and_with_custom_origin_config
- ignore_errors: True
+ ignore_errors: true
- name: check that custom origin with origin access identity fails
+ # "s3 origin domains and custom_origin_config are mutually exclusive"
+ assert:
+ that:
+ - update_origin_to_s3_with_origin_access_and_with_custom_origin_config.failed
+
+ - name: check that custom_origin_config can't be used with an region-agnostic S3 domain
+ cloudfront_distribution:
+ distribution_id: "{{ distribution_id }}"
+ origins:
+ - domain_name: "{{ resource_prefix }}-bucket.s3.{{ aws_region }}.amazonaws.com"
+ id: "{{ resource_prefix }}3.example.com"
+ custom_origin_config:
+ http_port: 8080
+ state: present
+ register: update_origin_to_s3_with_origin_access_and_with_custom_origin_config
+ ignore_errors: true
+
+ - name: check that custom origin with region-agnostic S3 domain fails
+ # "s3 origin domains and custom_origin_config are mutually exclusive"
+ assert:
+ that:
+ - update_origin_to_s3_with_origin_access_and_with_custom_origin_config.failed
+
+ - name: check that custom_origin_config can't be used with an region-aware S3 domain
+ cloudfront_distribution:
+ distribution_id: "{{ distribution_id }}"
+ origins:
+ - domain_name: "{{ resource_prefix }}-bucket.s3.amazonaws.com"
+ id: "{{ resource_prefix }}3.example.com"
+ custom_origin_config:
+ http_port: 8080
+ state: present
+ register: update_origin_to_s3_with_origin_access_and_with_custom_origin_config
+ ignore_errors: true
+
+ - name: check that custom origin with region-aware S3 domain fails
+ # "s3 origin domains and custom_origin_config are mutually exclusive"
assert:
that:
- update_origin_to_s3_with_origin_access_and_with_custom_origin_config.failed
+ - name: create cloudfront distribution origin access identity
+ cloudfront_origin_access_identity:
+ state: present
+ comment: "this is a sample origin access identity"
+ register: _origin_access_id
+
+ - set_fact:
+ origin_access_identity: 'origin-access-identity/cloudfront/{{ _origin_access_id.cloud_front_origin_access_identity.id }}'
+
- name: Update distribution to use specific access identity
cloudfront_distribution:
distribution_id: "{{ distribution_id }}"
@@ -490,25 +622,61 @@
domain_name: "{{ resource_prefix }}.s3.amazonaws.com"
s3_origin_access_identity_enabled: true
s3_origin_config:
- origin_access_identity: origin-access-identity/cloudfront/ANYTHING
- register: update_distribution_with_specific_access_identity
+ origin_access_identity: '{{ origin_access_identity }}'
+ register: result
- name: check that custom origin uses the provided origin_access_identity
assert:
that:
- - update_distribution_with_specific_access_identity.changed
- - update_distribution_with_specific_access_identity.origins.items[0].s3_origin_config.origin_access_identity == 'origin-access-identity/cloudfront/ANYTHING'
+ - result.changed
+ - result.origins['quantity'] > 0
+ - result.origins['items'] | selectattr('s3_origin_config', 'defined') | map(attribute='s3_origin_config') | selectattr('origin_access_identity', 'eq', origin_access_identity) | list | length == 1
+
+ - name: update distribution to use cache_policy_id and origin_request_policy_id
+ cloudfront_distribution:
+ distribution_id: "{{ distribution_id }}"
+ default_cache_behavior:
+ cache_policy_id: "658327ea-f89d-4fab-a63d-7e88639e58f6"
+ origin_request_policy_id: "88a5eaf4-2fd4-4709-b370-b4c650ea3fcf"
+ state: present
+ register: update_distribution_with_cache_policies
+
+ - name: ensure that the cache_policy_id and origin_request_policy_id was set
+ assert:
+ that:
+ - update_distribution_with_cache_policies.changed
+ - update_distribution_with_cache_policies.default_cache_behavior.cache_policy_id == '658327ea-f89d-4fab-a63d-7e88639e58f6'
+ - update_distribution_with_cache_policies.default_cache_behavior.origin_request_policy_id == '88a5eaf4-2fd4-4709-b370-b4c650ea3fcf'
always:
# TEARDOWN STARTS HERE
- name: delete the s3 bucket
- aws_s3:
- bucket: "{{ resource_prefix }}-bucket"
- mode: delete
+ s3_bucket:
+ name: "{{ resource_prefix }}-bucket"
+ state: absent
+ force: true
+ ignore_errors: true
- name: clean up cloudfront distribution
cloudfront_distribution:
- distribution_id: "{{ distribution_id }}"
- enabled: no
- wait: yes
+ distribution_id: "{{ item }}"
+ enabled: false
+ wait: true
state: absent
+ register: delete_distribution
+ ignore_errors: true
+ async: 1000
+ poll: 0
+ with_items:
+ - '{{ cf_second_distribution.id }}'
+ - '{{ cf_distribution.id }}'
+
+ - name: Wait for cloudfront to be deleted
+ async_status:
+ jid: "{{ item.ansible_job_id }}"
+ register: _delete
+ until: _delete.finished
+ retries: 100
+ delay: 5
+ loop: "{{ delete_distribution.results }}"
+ ignore_errors: true
diff --git a/ansible_collections/community/aws/tests/integration/targets/cloudfront_invalidation/aliases b/ansible_collections/community/aws/tests/integration/targets/cloudfront_invalidation/aliases
new file mode 100644
index 000000000..c282df0b0
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/cloudfront_invalidation/aliases
@@ -0,0 +1,3 @@
+cloudfront_distribution_info
+
+cloud/aws \ No newline at end of file
diff --git a/ansible_collections/community/aws/tests/integration/targets/cloudfront_invalidation/defaults/main.yml b/ansible_collections/community/aws/tests/integration/targets/cloudfront_invalidation/defaults/main.yml
new file mode 100644
index 000000000..9e7265251
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/cloudfront_invalidation/defaults/main.yml
@@ -0,0 +1,2 @@
+---
+cloudfront_hostname: "{{ resource_prefix }}01"
diff --git a/ansible_collections/community/aws/tests/integration/targets/cloudfront_invalidation/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/cloudfront_invalidation/tasks/main.yml
new file mode 100644
index 000000000..b42c8915c
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/cloudfront_invalidation/tasks/main.yml
@@ -0,0 +1,85 @@
+- module_defaults:
+ group/aws:
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
+
+ collections:
+ - amazon.aws
+
+ block:
+ - name: create cloudfront distribution using defaults
+ cloudfront_distribution:
+ origins:
+ - domain_name: "{{ cloudfront_hostname }}-origin.example.com"
+ id: "{{ cloudfront_hostname }}-origin.example.com"
+ default_cache_behavior:
+ target_origin_id: "{{ cloudfront_hostname }}-origin.example.com"
+ state: present
+ register: _distribution
+
+ - set_fact:
+ distribution_id: '{{ _distribution.id }}'
+ caller_reference: '{{ _distribution.caller_reference }}'
+
+ - name: create cloudfront invalidation
+ cloudfront_invalidation:
+ distribution_id: '{{ distribution_id }}'
+ target_paths:
+ - '/path/invalidation'
+
+ - name: get cloudfront invalidation
+ cloudfront_distribution_info:
+ distribution_id: '{{ distribution_id }}'
+ list_invalidations: true
+ register: distribution_info
+
+ - name: Ensure cloudfront distribution has 1 invalidation
+ assert:
+ that:
+ - distribution_info.cloudfront.invalidations | length == 1
+
+ - name: create cloudfront invalidation with caller reference
+ cloudfront_invalidation:
+ distribution_id: '{{ distribution_id }}'
+ target_paths:
+ - '/invalidation/*'
+ caller_reference: '{{ caller_reference }}'
+ register: _invalidation
+
+ - name: Ensure invalidation was created with expected caller reference
+ assert:
+ that:
+ - _invalidation.invalidation.invalidation_batch.caller_reference == caller_reference
+
+ - name: get cloudfront invalidation
+ cloudfront_distribution_info:
+ distribution_id: '{{ distribution_id }}'
+ list_invalidations: true
+ register: distribution_info
+
+ - name: Ensure cloudfront distribution has 2 invalidations
+ assert:
+ that:
+ - distribution_info.cloudfront.invalidations | length == 2
+
+ - name: get cloudfront invalidation
+ cloudfront_distribution_info:
+ distribution_id: '{{ distribution_id }}'
+ invalidation_id: '{{ _invalidation.invalidation.id }}'
+ invalidation: true
+ register: invalidation_info
+
+ - name: Ensure invalidation info was retrieved
+ assert:
+ that:
+ - _invalidation.invalidation.id in invalidation_info.cloudfront
+
+ always:
+ - name: clean up cloudfront distribution
+ cloudfront_distribution:
+ distribution_id: "{{ _distribution.id }}"
+ enabled: false
+ wait: false
+ state: absent
+ ignore_errors: true
diff --git a/ansible_collections/community/aws/tests/integration/targets/cloudfront_origin_access_identity/aliases b/ansible_collections/community/aws/tests/integration/targets/cloudfront_origin_access_identity/aliases
new file mode 100644
index 000000000..c282df0b0
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/cloudfront_origin_access_identity/aliases
@@ -0,0 +1,3 @@
+cloudfront_distribution_info
+
+cloud/aws \ No newline at end of file
diff --git a/ansible_collections/community/aws/tests/integration/targets/cloudfront_origin_access_identity/defaults/main.yml b/ansible_collections/community/aws/tests/integration/targets/cloudfront_origin_access_identity/defaults/main.yml
new file mode 100644
index 000000000..9e7265251
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/cloudfront_origin_access_identity/defaults/main.yml
@@ -0,0 +1,2 @@
+---
+cloudfront_hostname: "{{ resource_prefix }}01"
diff --git a/ansible_collections/community/aws/tests/integration/targets/cloudfront_origin_access_identity/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/cloudfront_origin_access_identity/tasks/main.yml
new file mode 100644
index 000000000..9259108bc
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/cloudfront_origin_access_identity/tasks/main.yml
@@ -0,0 +1,153 @@
+- module_defaults:
+ group/aws:
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
+
+ collections:
+ - amazon.aws
+
+ block:
+ - name: create cloudfront distribution using defaults
+ cloudfront_distribution:
+ origins:
+ - domain_name: "{{ cloudfront_hostname }}-origin.example.com"
+ id: "{{ cloudfront_hostname }}-origin.example.com"
+ default_cache_behavior:
+ target_origin_id: "{{ cloudfront_hostname }}-origin.example.com"
+ state: present
+ register: _distribution
+
+ - set_fact:
+ distribution_id: '{{ _distribution.id }}'
+ caller_reference: '{{ _distribution.caller_reference }}'
+
+ - name: create cloudfront distribution origin access identity
+ cloudfront_origin_access_identity:
+ state: present
+ comment: "this is a sample origin access identity"
+ register: _origin_access_id
+
+ - name: get cloudfront distribution origin access
+ cloudfront_distribution_info:
+ distribution_id: '{{ distribution_id }}'
+ list_origin_access_identities: true
+ register: distribution_info
+
+ - name: Ensure cloudfront distribution origin access identity exists
+ assert:
+ that:
+ - oid in origin_access_ids
+ vars:
+ origin_access_ids: '{{ distribution_info.cloudfront.origin_access_identities | map(attribute="Id") | list }}'
+ oid: '{{ _origin_access_id.cloud_front_origin_access_identity.id }}'
+
+ - name: Update cloudfront origin access identity
+ cloudfront_origin_access_identity:
+ state: present
+ comment: "this origin access identity comment has been updated"
+ origin_access_identity_id: '{{ _origin_access_id.cloud_front_origin_access_identity.id }}'
+ register: _updated_origin_access_id
+
+ - name: Ensure cloudfront origin access was updated
+ assert:
+ that:
+ - _updated_origin_access_id is changed
+ - orig_access_config.comment == "this origin access identity comment has been updated"
+ vars:
+ orig_access_config: '{{ _updated_origin_access_id.cloud_front_origin_access_identity.cloud_front_origin_access_identity_config }}'
+
+ - name: Update cloudfront origin access identity once again
+ cloudfront_origin_access_identity:
+ state: present
+ comment: "this origin access identity comment has been updated"
+ origin_access_identity_id: '{{ _origin_access_id.cloud_front_origin_access_identity.id }}'
+ register: _update_idempotency
+
+ - name: Ensure idempotency did not report change
+ assert:
+ that:
+ - _update_idempotency is not changed
+
+ - name: create another cloudfront distribution origin access identity with caller reference
+ cloudfront_origin_access_identity:
+ state: present
+ comment: "this is another origin access identity"
+ caller_reference: '{{ caller_reference }}'
+ register: _another_origin_access_id
+
+ - name: Ensure invalidation was created with expected caller reference
+ assert:
+ that:
+ - _another_origin_access_id.cloud_front_origin_access_identity.cloud_front_origin_access_identity_config.caller_reference == caller_reference
+
+ - name: get cloudfront origin access identities
+ cloudfront_distribution_info:
+ distribution_id: '{{ distribution_id }}'
+ list_origin_access_identities: true
+ register: distribution_info
+
+ - name: Ensure cloudfront distribution origin access identity exists
+ assert:
+ that:
+ - first_oid in origin_access_ids
+ - another_oid in origin_access_ids
+ vars:
+ origin_access_ids: '{{ distribution_info.cloudfront.origin_access_identities | map(attribute="Id") | list }}'
+ first_oid: '{{ _origin_access_id.cloud_front_origin_access_identity.id }}'
+ another_oid: '{{ _another_origin_access_id.cloud_front_origin_access_identity.id }}'
+
+ - name: get cloudfront origin access
+ cloudfront_distribution_info:
+ distribution_id: '{{ distribution_id }}'
+ origin_access_identity_id: '{{ _another_origin_access_id.cloud_front_origin_access_identity.id }}'
+ origin_access_identity: true
+ register: invalidation_info
+
+ - name: Ensure invalidation info was retrieved
+ assert:
+ that:
+ - _another_origin_access_id.cloud_front_origin_access_identity.id in invalidation_info.cloudfront
+
+ - name: Delete cloudfront origin access
+ cloudfront_origin_access_identity:
+ state: absent
+ origin_access_identity_id: '{{ _another_origin_access_id.cloud_front_origin_access_identity.id }}'
+ register: _delete_origin_access
+
+ - name: Ensure origin access identity was deleted
+ assert:
+ that:
+ - _delete_origin_access is changed
+
+ - name: list cloudfront origin access identities
+ cloudfront_distribution_info:
+ list_origin_access_identities: true
+ register: origin_access_identities
+
+ - name: Ensure deleted origin access identity is not part of the list
+ assert:
+ that:
+ - _another_origin_access_id.cloud_front_origin_access_identity.id not in origin_access_ids
+ vars:
+ origin_access_ids: '{{ origin_access_identities.cloudfront.origin_access_identities | map(attribute="Id") | list}}'
+
+ - name: Delete cloudfront origin access once again
+ cloudfront_origin_access_identity:
+ state: absent
+ origin_access_identity_id: '{{ _another_origin_access_id.cloud_front_origin_access_identity.id }}'
+ register: _delete_origin_access
+
+ - name: Ensure origin access identity was deleted
+ assert:
+ that:
+ - _delete_origin_access is not changed
+
+ always:
+ - name: clean up cloudfront distribution
+ cloudfront_distribution:
+ distribution_id: "{{ _distribution.id }}"
+ enabled: false
+ wait: false
+ state: absent
+ ignore_errors: true
diff --git a/ansible_collections/community/aws/tests/integration/targets/cloudfront_reponse_headers_policy/task/main.yml b/ansible_collections/community/aws/tests/integration/targets/cloudfront_reponse_headers_policy/task/main.yml
index ee30f5ab5..5bab44f9f 100644
--- a/ansible_collections/community/aws/tests/integration/targets/cloudfront_reponse_headers_policy/task/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/cloudfront_reponse_headers_policy/task/main.yml
@@ -3,9 +3,9 @@
- name: Integration testing for the cloudfront_response_headers_policy module
module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region }}'
block:
@@ -24,7 +24,7 @@
that:
- create_result is changed
- create_result is not failed
- - create_result.response_headers_policy.response_headers_policy_config.name == "{{ resource_prefix }}-my-header-policy"
+ - create_result.response_headers_policy.response_headers_policy_config.name == resource_prefix ~ '-my-header-policy'
- name: Rerun same task to ensure idempotence
cloudfront_response_headers_policy:
diff --git a/ansible_collections/community/aws/tests/integration/targets/codebuild_project/tasks/description.yml b/ansible_collections/community/aws/tests/integration/targets/codebuild_project/tasks/description.yml
index 13c12b5b6..e52c4326f 100644
--- a/ansible_collections/community/aws/tests/integration/targets/codebuild_project/tasks/description.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/codebuild_project/tasks/description.yml
@@ -4,14 +4,14 @@
description_two: 'Another_Description - {{ resource_prefix }}'
# Mandatory settings
module_defaults:
- community.aws.aws_codebuild:
+ community.aws.codebuild_project:
name: '{{ project_name }}'
# community.aws.aws_codebuild_info:
# name: '{{ project_name }}'
block:
# - name: test setting description aws_codebuild (check mode)
-# aws_codebuild:
+# codebuild_project:
# description: '{{ description_one }}'
# register: update_result
# check_mode: yes
@@ -21,7 +21,7 @@
# - update_result is changed
- name: test setting description aws_codebuild
- aws_codebuild:
+ codebuild_project:
description: '{{ description_one }}'
register: update_result
- name: assert that update succeeded
@@ -31,7 +31,7 @@
- update_result.project.description == description_one
# - name: test setting description aws_codebuild - idempotency (check mode)
-# aws_codebuild:
+# codebuild_project:
# description: '{{ description_one }}'
# register: update_result
# check_mode: yes
@@ -41,7 +41,7 @@
# - update_result is not changed
- name: test setting description aws_codebuild - idempotency
- aws_codebuild:
+ codebuild_project:
description: '{{ description_one }}'
register: update_result
- name: assert that update succeeded
@@ -53,7 +53,7 @@
###
# - name: test updating description on aws_codebuild (check mode)
-# aws_codebuild:
+# codebuild_project:
# description: '{{ description_two }}'
# register: update_result
# check_mode: yes
@@ -63,7 +63,7 @@
# - update_result is changed
- name: test updating description on aws_codebuild
- aws_codebuild:
+ codebuild_project:
description: '{{ description_two }}'
register: update_result
- name: assert that update succeeded
@@ -73,7 +73,7 @@
- update_result.project.description == description_two
# - name: test updating description on aws_codebuild - idempotency (check mode)
-# aws_codebuild:
+# codebuild_project:
# description: '{{ description_two }}'
# register: update_result
# check_mode: yes
@@ -83,7 +83,7 @@
# - update_result is not changed
- name: test updating description on aws_codebuild - idempotency
- aws_codebuild:
+ codebuild_project:
description: '{{ description_two }}'
register: update_result
- name: assert that update succeeded
@@ -105,7 +105,7 @@
# ###
# - name: test no description param aws_codebuild (check mode)
-# aws_codebuild: {}
+# codebuild_project: {}
# register: update_result
# check_mode: yes
# - name: assert no change
@@ -116,7 +116,7 @@
- name: test no description param aws_codebuild
- aws_codebuild: {}
+ codebuild_project: {}
register: update_result
- name: assert no change
assert:
diff --git a/ansible_collections/community/aws/tests/integration/targets/codebuild_project/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/codebuild_project/tasks/main.yml
index f674aba24..3f8a22fd7 100644
--- a/ansible_collections/community/aws/tests/integration/targets/codebuild_project/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/codebuild_project/tasks/main.yml
@@ -4,9 +4,9 @@
- amazon.aws
module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region }}'
block:
@@ -27,7 +27,7 @@
# ================== integration test ==========================================
- name: create CodeBuild project
- aws_codebuild:
+ codebuild_project:
name: "{{ project_name }}"
description: Build project for testing the Ansible aws_codebuild module
service_role: "{{ codebuild_iam_role.iam_role.arn }}"
@@ -48,7 +48,7 @@
environment_variables:
- { name: 'FOO_ENV', value: 'other' }
tags:
- - { key: 'purpose', value: 'ansible-test' }
+ purpose: 'ansible-test'
state: present
register: output
retries: 10
@@ -61,7 +61,7 @@
- output.project.resource_tags.purpose == "ansible-test"
- name: idempotence check rerunning same Codebuild task
- aws_codebuild:
+ codebuild_project:
name: "{{ project_name }}"
description: Build project for testing the Ansible aws_codebuild module
service_role: "{{ codebuild_iam_role.iam_role.arn }}"
@@ -83,7 +83,7 @@
environment_variables:
- { name: 'FOO_ENV', value: 'other' }
tags:
- - { key: 'purpose', value: 'ansible-test' }
+ purpose: 'ansible-test'
state: present
register: rerun_test_output
@@ -96,7 +96,7 @@
- include_tasks: 'description.yml'
- name: delete CodeBuild project
- aws_codebuild:
+ codebuild_project:
name: "{{ output.project.name }}"
source:
type: CODEPIPELINE
diff --git a/ansible_collections/community/aws/tests/integration/targets/codebuild_project/tasks/tagging.yml b/ansible_collections/community/aws/tests/integration/targets/codebuild_project/tasks/tagging.yml
index a26f2a337..2e31df2d8 100644
--- a/ansible_collections/community/aws/tests/integration/targets/codebuild_project/tasks/tagging.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/codebuild_project/tasks/tagging.yml
@@ -27,7 +27,7 @@
new_snake_case_key: snake_case_value
# Mandatory settings
module_defaults:
- community.aws.aws_codebuild:
+ community.aws.codebuild_project:
name: '{{ project_name }}'
# community.aws.aws_codebuild_info:
# name: '{{ project_name }}'
@@ -36,7 +36,7 @@
###
# - name: test adding tags to aws_codebuild (check mode)
-# aws_codebuild:
+# codebuild_project:
# resource_tags: '{{ first_tags }}'
# purge_tags: True
# register: update_result
@@ -47,7 +47,7 @@
# - update_result is changed
- name: test adding tags to aws_codebuild
- aws_codebuild:
+ codebuild_project:
resource_tags: '{{ first_tags }}'
purge_tags: True
register: update_result
@@ -58,7 +58,7 @@
- update_result.project.resource_tags == first_tags
# - name: test adding tags to aws_codebuild - idempotency (check mode)
-# aws_codebuild:
+# codebuild_project:
# resource_tags: '{{ first_tags }}'
# purge_tags: True
# register: update_result
@@ -69,7 +69,7 @@
# - update_result is not changed
- name: test adding tags to aws_codebuild - idempotency
- aws_codebuild:
+ codebuild_project:
resource_tags: '{{ first_tags }}'
purge_tags: True
register: update_result
@@ -82,7 +82,7 @@
###
# - name: test updating tags with purge on aws_codebuild (check mode)
-# aws_codebuild:
+# codebuild_project:
# resource_tags: '{{ second_tags }}'
# purge_tags: True
# register: update_result
@@ -93,7 +93,7 @@
# - update_result is changed
- name: test updating tags with purge on aws_codebuild
- aws_codebuild:
+ codebuild_project:
resource_tags: '{{ second_tags }}'
purge_tags: True
register: update_result
@@ -104,7 +104,7 @@
- update_result.project.resource_tags == second_tags
# - name: test updating tags with purge on aws_codebuild - idempotency (check mode)
-# aws_codebuild:
+# codebuild_project:
# resource_tags: '{{ second_tags }}'
# purge_tags: True
# register: update_result
@@ -115,7 +115,7 @@
# - update_result is not changed
- name: test updating tags with purge on aws_codebuild - idempotency
- aws_codebuild:
+ codebuild_project:
resource_tags: '{{ second_tags }}'
purge_tags: True
register: update_result
@@ -128,7 +128,7 @@
###
# - name: test updating tags without purge on aws_codebuild (check mode)
-# aws_codebuild:
+# codebuild_project:
# resource_tags: '{{ third_tags }}'
# purge_tags: False
# register: update_result
@@ -139,7 +139,7 @@
# - update_result is changed
- name: test updating tags without purge on aws_codebuild
- aws_codebuild:
+ codebuild_project:
resource_tags: '{{ third_tags }}'
purge_tags: False
register: update_result
@@ -150,7 +150,7 @@
- update_result.project.resource_tags == final_tags
# - name: test updating tags without purge on aws_codebuild - idempotency (check mode)
-# aws_codebuild:
+# codebuild_project:
# resource_tags: '{{ third_tags }}'
# purge_tags: False
# register: update_result
@@ -161,7 +161,7 @@
# - update_result is not changed
- name: test updating tags without purge on aws_codebuild - idempotency
- aws_codebuild:
+ codebuild_project:
resource_tags: '{{ third_tags }}'
purge_tags: False
register: update_result
@@ -184,7 +184,7 @@
# ###
# - name: test no tags param aws_codebuild (check mode)
-# aws_codebuild: {}
+# codebuild_project: {}
# register: update_result
# check_mode: yes
# - name: assert no change
@@ -195,7 +195,7 @@
#
- name: test no tags param aws_codebuild
- aws_codebuild: {}
+ codebuild_project: {}
register: update_result
- name: assert no change
assert:
@@ -206,7 +206,7 @@
###
# - name: test removing tags from aws_codebuild (check mode)
-# aws_codebuild:
+# codebuild_project:
# resource_tags: {}
# purge_tags: True
# register: update_result
@@ -217,7 +217,7 @@
# - update_result is changed
- name: test removing tags from aws_codebuild
- aws_codebuild:
+ codebuild_project:
resource_tags: {}
purge_tags: True
register: update_result
@@ -228,7 +228,7 @@
- update_result.project.resource_tags == {}
# - name: test removing tags from aws_codebuild - idempotency (check mode)
-# aws_codebuild:
+# codebuild_project:
# resource_tags: {}
# purge_tags: True
# register: update_result
@@ -239,7 +239,7 @@
# - update_result is not changed
- name: test removing tags from aws_codebuild - idempotency
- aws_codebuild:
+ codebuild_project:
resource_tags: {}
purge_tags: True
register: update_result
diff --git a/ansible_collections/community/aws/tests/integration/targets/codecommit_repository/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/codecommit_repository/tasks/main.yml
index acf194e1e..62dd1653b 100644
--- a/ansible_collections/community/aws/tests/integration/targets/codecommit_repository/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/codecommit_repository/tasks/main.yml
@@ -1,14 +1,14 @@
---
- module_defaults:
group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"
block:
# ============================================================
- name: Create a repository (CHECK MODE)
- aws_codecommit:
+ codecommit_repository:
name: "{{ resource_prefix }}_repo"
description: original comment
state: present
@@ -19,7 +19,7 @@
- output is changed
- name: Create a repository
- aws_codecommit:
+ codecommit_repository:
name: "{{ resource_prefix }}_repo"
description: original comment
state: present
@@ -27,11 +27,11 @@
- assert:
that:
- output is changed
- - output.repository_metadata.repository_name == '{{ resource_prefix }}_repo'
+ - output.repository_metadata.repository_name == resource_prefix ~ '_repo'
- output.repository_metadata.repository_description == 'original comment'
- name: No-op update to repository
- aws_codecommit:
+ codecommit_repository:
name: "{{ resource_prefix }}_repo"
description: original comment
state: present
@@ -39,11 +39,11 @@
- assert:
that:
- output is not changed
- - output.repository_metadata.repository_name == '{{ resource_prefix }}_repo'
+ - output.repository_metadata.repository_name == resource_prefix ~ '_repo'
- output.repository_metadata.repository_description == 'original comment'
- name: Update repository description (CHECK MODE)
- aws_codecommit:
+ codecommit_repository:
name: "{{ resource_prefix }}_repo"
description: new comment
state: present
@@ -52,11 +52,11 @@
- assert:
that:
- output is changed
- - output.repository_metadata.repository_name == '{{ resource_prefix }}_repo'
+ - output.repository_metadata.repository_name == resource_prefix ~ '_repo'
- output.repository_metadata.repository_description == 'original comment'
- name: Update repository description
- aws_codecommit:
+ codecommit_repository:
name: "{{ resource_prefix }}_repo"
description: new comment
state: present
@@ -64,12 +64,12 @@
- assert:
that:
- output is changed
- - output.repository_metadata.repository_name == '{{ resource_prefix }}_repo'
+ - output.repository_metadata.repository_name == resource_prefix ~ '_repo'
- output.repository_metadata.repository_description == 'new comment'
# ============================================================
- name: Delete a repository (CHECK MODE)
- aws_codecommit:
+ codecommit_repository:
name: "{{ resource_prefix }}_repo"
state: absent
register: output
@@ -79,7 +79,7 @@
- output is changed
- name: Delete a repository
- aws_codecommit:
+ codecommit_repository:
name: "{{ resource_prefix }}_repo"
state: absent
register: output
@@ -88,7 +88,7 @@
- output is changed
- name: Delete a non-existent repository
- aws_codecommit:
+ codecommit_repository:
name: "{{ resource_prefix }}_repo"
state: absent
register: output
@@ -97,27 +97,27 @@
- output is not changed
- name: Create a repository without description
- aws_codecommit:
+ codecommit_repository:
name: "{{ resource_prefix }}_repo"
state: present
register: output
- assert:
that:
- output is changed
- - output.repository_metadata.repository_name == '{{ resource_prefix }}_repo'
+ - output.repository_metadata.repository_name == resource_prefix ~ '_repo'
- name: No-op update to repository without description
- aws_codecommit:
+ codecommit_repository:
name: "{{ resource_prefix }}_repo"
state: present
register: output
- assert:
that:
- output is not changed
- - output.repository_metadata.repository_name == '{{ resource_prefix }}_repo'
+ - output.repository_metadata.repository_name == resource_prefix ~ '_repo'
- name: Delete a repository without description
- aws_codecommit:
+ codecommit_repository:
name: "{{ resource_prefix }}_repo"
state: absent
register: output
@@ -128,7 +128,7 @@
always:
###### TEARDOWN STARTS HERE ######
- name: Delete a repository
- aws_codecommit:
+ codecommit_repository:
name: "{{ resource_prefix }}_repo"
state: absent
ignore_errors: yes
diff --git a/ansible_collections/community/aws/tests/integration/targets/codepipeline/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/codepipeline/tasks/main.yml
index 2e8e7d8f3..57353ed8a 100644
--- a/ansible_collections/community/aws/tests/integration/targets/codepipeline/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/codepipeline/tasks/main.yml
@@ -4,9 +4,9 @@
- amazon.aws
module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region }}'
block:
@@ -23,7 +23,7 @@
# ================== integration test ==========================================
- name: create CodePipeline
- aws_codepipeline:
+ codepipeline:
name: "{{ codepipeline_name }}"
role_arn: "{{ codepipeline_iam_role.iam_role.arn }}"
artifact_store:
@@ -66,11 +66,11 @@
- assert:
that:
- output.changed == True
- - output.pipeline.name == "{{ codepipeline_name }}"
+ - output.pipeline.name == codepipeline_name
- output.pipeline.stages|length > 1
- name: idempotence check rerunning same CodePipeline task
- aws_codepipeline:
+ codepipeline:
name: "{{ codepipeline_name }}"
role_arn: "{{ codepipeline_iam_role.iam_role.arn }}"
artifact_store:
@@ -113,7 +113,7 @@
- rerun_test_output.pipeline == output.pipeline
- name: Test deletion of CodePipeline
- aws_codepipeline:
+ codepipeline:
name: "{{ codepipeline_name }}"
role_arn: ''
artifact_store: {}
@@ -131,7 +131,7 @@
always:
- name: Cleanup - delete test CodePipeline
- aws_codepipeline:
+ codepipeline:
name: "{{ codepipeline_name }}"
role_arn: ''
artifact_store: {}
diff --git a/ansible_collections/community/aws/tests/integration/targets/config/defaults/main.yaml b/ansible_collections/community/aws/tests/integration/targets/config/defaults/main.yaml
index 26b39c583..3beeca841 100644
--- a/ansible_collections/community/aws/tests/integration/targets/config/defaults/main.yaml
+++ b/ansible_collections/community/aws/tests/integration/targets/config/defaults/main.yaml
@@ -1,4 +1,5 @@
---
config_s3_bucket: '{{ resource_prefix }}-config-records'
+config_kms_key: '{{ resource_prefix }}-kms'
config_sns_name: '{{ resource_prefix }}-delivery-channel-test-topic'
config_role_name: 'ansible-test-{{ resource_prefix }}'
diff --git a/ansible_collections/community/aws/tests/integration/targets/config/tasks/main.yaml b/ansible_collections/community/aws/tests/integration/targets/config/tasks/main.yaml
index 313f9f677..244c4b29b 100644
--- a/ansible_collections/community/aws/tests/integration/targets/config/tasks/main.yaml
+++ b/ansible_collections/community/aws/tests/integration/targets/config/tasks/main.yaml
@@ -4,15 +4,22 @@
- amazon.aws
module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region }}'
block:
# ============================================================
# Prerequisites
# ============================================================
+ - name: get ARN of calling user
+ aws_caller_info:
+ register: aws_caller_info
+
+ - name: Store Account ID for later use
+ set_fact:
+ aws_account_id: "{{ aws_caller_info.account }}"
- name: ensure IAM role exists
iam_role:
@@ -21,7 +28,7 @@
state: present
create_instance_profile: no
managed_policy:
- - 'arn:aws:iam::aws:policy/service-role/AWSConfigRole'
+ - arn:aws:iam::aws:policy/service-role/AWS_ConfigRole
register: config_iam_role
- name: ensure SNS topic exists
@@ -37,6 +44,12 @@
s3_bucket:
name: "{{ config_s3_bucket }}"
+ - name: ensure KMS key exists
+ kms_key:
+ alias: "{{ config_kms_key }}"
+ policy: "{{ lookup('template', 'config-kms-policy.json.j2') }}"
+ register: kms_key
+
- name: ensure S3 access for IAM role
iam_policy:
iam_type: role
@@ -49,7 +62,7 @@
# Module requirement testing
# ============================================================
- name: test rule with no source parameter
- aws_config_rule:
+ config_rule:
name: random_name
state: present
register: output
@@ -62,7 +75,7 @@
- 'output.msg.startswith("missing required arguments:")'
- name: test resource_type delivery_channel with no s3_bucket parameter
- aws_config_delivery_channel:
+ config_delivery_channel:
name: random_name
state: present
register: output
@@ -75,7 +88,7 @@
- 'output.msg.startswith("missing required arguments:")'
- name: test resource_type configuration_recorder with no role_arn parameter
- aws_config_recorder:
+ config_recorder:
name: random_name
state: present
register: output
@@ -88,7 +101,7 @@
- 'output.msg.startswith("state is present but all of the following are missing")'
- name: test resource_type configuration_recorder with no recording_group parameter
- aws_config_recorder:
+ config_recorder:
name: random_name
state: present
role_arn: 'arn:aws:iam::123456789012:role/AwsConfigRecorder'
@@ -102,7 +115,7 @@
- 'output.msg.startswith("state is present but all of the following are missing")'
- name: test resource_type aggregation_authorization with no authorized_account_id parameter
- aws_config_aggregation_authorization:
+ config_aggregation_authorization:
state: present
register: output
ignore_errors: true
@@ -114,7 +127,7 @@
- 'output.msg.startswith("missing required arguments:")'
- name: test resource_type aggregation_authorization with no authorized_aws_region parameter
- aws_config_aggregation_authorization:
+ config_aggregation_authorization:
state: present
authorized_account_id: '123456789012'
register: output
@@ -127,7 +140,7 @@
- 'output.msg.startswith("missing required arguments:")'
- name: test resource_type configuration_aggregator with no account_sources parameter
- aws_config_aggregator:
+ config_aggregator:
name: random_name
state: present
register: output
@@ -140,7 +153,7 @@
- 'output.msg.startswith("missing required arguments: account_sources")'
- name: test resource_type configuration_aggregator with no organization_source parameter
- aws_config_aggregator:
+ config_aggregator:
name: random_name
state: present
account_sources: []
@@ -157,7 +170,7 @@
# Creation testing
# ============================================================
- name: Create Configuration Recorder for AWS Config
- aws_config_recorder:
+ config_recorder:
name: '{{ resource_prefix }}-recorder'
state: present
role_arn: "{{ config_iam_role.arn }}"
@@ -171,11 +184,26 @@
- output.changed
- name: Create Delivery Channel for AWS Config
- aws_config_delivery_channel:
+ config_delivery_channel:
+ name: '{{ resource_prefix }}-channel'
+ state: present
+ s3_bucket: "{{ config_s3_bucket }}"
+ s3_prefix: "foo/bar"
+ sns_topic_arn: "{{ config_sns_topic.sns_arn }}"
+ delivery_frequency: 'Twelve_Hours'
+ register: output
+
+ - assert:
+ that:
+ - output.changed
+
+ - name: Create Delivery Channel for AWS Config with a KMS key
+ config_delivery_channel:
name: '{{ resource_prefix }}-channel'
state: present
s3_bucket: "{{ config_s3_bucket }}"
s3_prefix: "foo/bar"
+ kms_key_arn: "{{ kms_key.key_arn }}"
sns_topic_arn: "{{ config_sns_topic.sns_arn }}"
delivery_frequency: 'Twelve_Hours'
register: output
@@ -185,7 +213,7 @@
- output.changed
- name: Create Config Rule for AWS Config
- aws_config_rule:
+ config_rule:
name: '{{ resource_prefix }}-rule'
state: present
description: 'This AWS Config rule checks for public write access on S3 buckets'
@@ -202,7 +230,7 @@
- output.changed
- name: Create aws_config_aggregator
- aws_config_aggregator:
+ config_aggregator:
name: random_name
state: present
account_sources: []
@@ -217,7 +245,7 @@
- output is changed
- name: Create aws_config_aggregator - idempotency
- aws_config_aggregator:
+ config_aggregator:
name: random_name
state: present
account_sources: []
@@ -235,7 +263,7 @@
# Update testing
# ============================================================
- name: Update Configuration Recorder
- aws_config_recorder:
+ config_recorder:
name: '{{ resource_prefix }}-recorder'
state: present
role_arn: "{{ config_iam_role.arn }}"
@@ -251,7 +279,7 @@
- output.changed
- name: Update Delivery Channel
- aws_config_delivery_channel:
+ config_delivery_channel:
name: '{{ resource_prefix }}-channel'
state: present
s3_bucket: "{{ config_s3_bucket }}"
@@ -263,8 +291,22 @@
that:
- output.changed
+ - name: Update Delivery Channel with KMS key
+ config_delivery_channel:
+ name: '{{ resource_prefix }}-channel'
+ state: present
+ s3_bucket: "{{ config_s3_bucket }}"
+ sns_topic_arn: "{{ config_sns_topic.sns_arn }}"
+ kms_key_arn: "{{ kms_key.key_arn }}"
+ delivery_frequency: 'TwentyFour_Hours'
+ register: output
+
+ - assert:
+ that:
+ - output.changed
+
- name: Update Config Rule
- aws_config_rule:
+ config_rule:
name: '{{ resource_prefix }}-rule'
state: present
description: 'This AWS Config rule checks for public write access on S3 buckets'
@@ -281,7 +323,7 @@
- output.changed
- name: Update Config Rule - idempotency
- aws_config_rule:
+ config_rule:
name: '{{ resource_prefix }}-rule'
state: present
description: 'This AWS Config rule checks for public write access on S3 buckets'
@@ -298,7 +340,7 @@
- output is not changed
- name: Update aws_config_aggregator
- aws_config_aggregator:
+ config_aggregator:
name: random_name
state: present
account_sources: []
@@ -315,7 +357,7 @@
- output is changed
- name: Update aws_config_aggregator - idempotency
- aws_config_aggregator:
+ config_aggregator:
name: random_name
state: present
account_sources: []
@@ -335,7 +377,7 @@
# Read testing
# ============================================================
- name: Don't update Configuration Recorder
- aws_config_recorder:
+ config_recorder:
name: '{{ resource_prefix }}-recorder'
state: present
role_arn: "{{ config_iam_role.arn }}"
@@ -351,7 +393,7 @@
- not output.changed
- name: Don't update Delivery Channel
- aws_config_delivery_channel:
+ config_delivery_channel:
name: '{{ resource_prefix }}-channel'
state: present
s3_bucket: "{{ config_s3_bucket }}"
@@ -364,7 +406,7 @@
- not output.changed
- name: Don't update Config Rule
- aws_config_rule:
+ config_rule:
name: '{{ resource_prefix }}-rule'
state: present
description: 'This AWS Config rule checks for public write access on S3 buckets'
@@ -383,7 +425,7 @@
always:
- name: delete aws_config_aggregator
- aws_config_aggregator:
+ config_aggregator:
name: random_name
state: absent
register: output
@@ -393,32 +435,32 @@
# Destroy testing
# ============================================================
- name: Destroy Configuration Recorder
- aws_config_recorder:
+ config_recorder:
name: '{{ resource_prefix }}-recorder'
state: absent
register: output
- ignore_errors: yes
+ ignore_errors: true
# - assert:
# that:
# - output.changed
- name: Destroy Delivery Channel
- aws_config_delivery_channel:
+ config_delivery_channel:
name: '{{ resource_prefix }}-channel'
state: absent
s3_bucket: "{{ config_s3_bucket }}"
sns_topic_arn: "{{ config_sns_topic.sns_arn }}"
delivery_frequency: 'TwentyFour_Hours'
register: output
- ignore_errors: yes
+ ignore_errors: true
# - assert:
# that:
# - output.changed
- name: Destroy Config Rule
- aws_config_rule:
+ config_rule:
name: '{{ resource_prefix }}-rule'
state: absent
description: 'This AWS Config rule checks for public write access on S3 buckets'
@@ -429,7 +471,7 @@
owner: AWS
identifier: 'S3_BUCKET_PUBLIC_READ_PROHIBITED'
register: output
- ignore_errors: yes
+ ignore_errors: true
# - assert:
# that:
@@ -445,23 +487,29 @@
policy_name: AwsConfigRecorderTestRoleS3Policy
state: absent
policy_json: "{{ lookup( 'template', 'config-s3-policy.json.j2') }}"
- ignore_errors: yes
+ ignore_errors: true
- name: remove IAM role
iam_role:
name: '{{ config_role_name }}'
state: absent
- ignore_errors: yes
+ ignore_errors: true
- name: remove SNS topic
sns_topic:
name: '{{ config_sns_name }}'
state: absent
- ignore_errors: yes
+ ignore_errors: true
- name: remove S3 bucket
s3_bucket:
name: "{{ config_s3_bucket }}"
state: absent
- force: yes
- ignore_errors: yes
+ force: true
+ ignore_errors: true
+
+ - name: remove KMS key
+ kms_key:
+ alias: "{{ config_kms_key }}"
+ state: absent
+ ignore_errors: true
diff --git a/ansible_collections/community/aws/tests/integration/targets/config/templates/config-kms-policy.json.j2 b/ansible_collections/community/aws/tests/integration/targets/config/templates/config-kms-policy.json.j2
new file mode 100644
index 000000000..260adc839
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/config/templates/config-kms-policy.json.j2
@@ -0,0 +1,51 @@
+{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Sid": "Enable IAM User Permissions",
+ "Effect": "Allow",
+ "Principal": {
+ "AWS": "arn:aws:iam::{{ aws_account_id }}:root"
+ },
+ "Action": "kms:*",
+ "Resource": "*"
+ },
+ {
+ "Sid": "Allow use of the key",
+ "Effect": "Allow",
+ "Principal": {
+ "AWS": [
+ "arn:aws:iam::{{ aws_account_id }}:role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig",
+ ]
+ },
+ "Action": [
+ "kms:Encrypt",
+ "kms:Decrypt",
+ "kms:ReEncrypt*",
+ "kms:GenerateDataKey*",
+ "kms:DescribeKey"
+ ],
+ "Resource": "*"
+ },
+ {
+ "Sid": "Allow attachment of persistent resources",
+ "Effect": "Allow",
+ "Principal": {
+ "AWS": [
+ "arn:aws:iam::{{ aws_account_id }}:role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig",
+ ]
+ },
+ "Action": [
+ "kms:CreateGrant",
+ "kms:ListGrants",
+ "kms:RevokeGrant"
+ ],
+ "Resource": "*",
+ "Condition": {
+ "Bool": {
+ "kms:GrantIsForAWSResource": "true"
+ }
+ }
+ }
+ ]
+} \ No newline at end of file
diff --git a/ansible_collections/community/aws/tests/integration/targets/connection/test_assume.yml b/ansible_collections/community/aws/tests/integration/targets/connection/test_assume.yml
new file mode 100644
index 000000000..f979ef2d4
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/connection/test_assume.yml
@@ -0,0 +1,16 @@
+- name: 'Ensure remote user exists'
+ ansible.builtin.user:
+ name: '{{ user_name }}'
+ shell: /bin/bash
+ become_user: 'root'
+ become: True
+
+- name: 'Attempt to run a shell command as the user ({{ user_name }})'
+ become_user: '{{ user_name }}'
+ become: True
+ command: 'id -u -n'
+ register: id_cmd
+
+- assert:
+ that:
+ - id_cmd.stdout == user_name
diff --git a/ansible_collections/community/aws/tests/integration/targets/connection/test_connection.yml b/ansible_collections/community/aws/tests/integration/targets/connection/test_connection.yml
index 829ac93b3..b8bdc43f4 100644
--- a/ansible_collections/community/aws/tests/integration/targets/connection/test_connection.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/connection/test_connection.yml
@@ -10,9 +10,12 @@
tasks:
### test wait_for_connection plugin
+
- wait_for_connection:
timeout: '{{ wait_for_timeout | default(100) }}'
+ ### Try to gather the default facts from the host
+
- name: Gather facts
ansible.builtin.setup:
@@ -52,6 +55,30 @@
- name: remove remote temp file
action: "{{ action_prefix }}file path={{ remote_file }} state=absent"
+ ### Test that we're the user we expect to be and can change where appropriate
+ # Regression - https://github.com/ansible-collections/community.aws/issues/853
+
+ - name: Test user manipulaton
+ when:
+ - '"aws_ssm_linux" in group_names'
+ block:
+ - name: 'Find ID when become=False'
+ become: False
+ command: 'id -u -n'
+ register: id_cmd
+
+ - assert:
+ that:
+ - id_cmd.stdout == 'ssm-user'
+
+ - include_tasks: 'test_assume.yml'
+ loop:
+ - ssm-agent
+ - zuul
+ - root
+ loop_control:
+ loop_var: user_name
+
### copy an empty file
- name: copy an empty file
action: "{{ action_prefix }}copy content= dest={{ remote_empty_file }}"
@@ -62,4 +89,4 @@
assert:
that:
- stat_empty_file_cmd.stat.isreg # it is a regular file
- - stat_empty_file_cmd.stat.size == 0
+ - stat_empty_file_cmd.stat.size == 0 \ No newline at end of file
diff --git a/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_addressing/aws_ssm_integration_test_setup.yml b/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_addressing/aws_ssm_integration_test_setup.yml
index db519fb63..9e2f3fd01 100644
--- a/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_addressing/aws_ssm_integration_test_setup.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_addressing/aws_ssm_integration_test_setup.yml
@@ -2,7 +2,7 @@
roles:
- role: ../setup_connection_aws_ssm
vars:
- target_os: fedora
+ target_os: centos
encrypted_bucket: False
s3_bucket_region: 'eu-central-1'
s3_addressing_style: virtual
diff --git a/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_fedora/aliases b/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_centos/aliases
index eb8e0b891..eb8e0b891 100644
--- a/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_fedora/aliases
+++ b/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_centos/aliases
diff --git a/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_fedora/aws_ssm_integration_test_setup.yml b/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_centos/aws_ssm_integration_test_setup.yml
index 353757e33..d64cdabb6 100644
--- a/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_fedora/aws_ssm_integration_test_setup.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_centos/aws_ssm_integration_test_setup.yml
@@ -2,4 +2,4 @@
roles:
- role: ../setup_connection_aws_ssm
vars:
- target_os: fedora
+ target_os: centos
diff --git a/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_fedora/aws_ssm_integration_test_teardown.yml b/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_centos/aws_ssm_integration_test_teardown.yml
index 3ab6f74cf..3ab6f74cf 100644
--- a/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_fedora/aws_ssm_integration_test_teardown.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_centos/aws_ssm_integration_test_teardown.yml
diff --git a/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_fedora/meta/main.yml b/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_centos/meta/main.yml
index d055eb86e..d055eb86e 100644
--- a/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_fedora/meta/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_centos/meta/main.yml
diff --git a/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_fedora/runme.sh b/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_centos/runme.sh
index c99b3b066..c99b3b066 100755
--- a/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_fedora/runme.sh
+++ b/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_centos/runme.sh
diff --git a/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_cross_region/aws_ssm_integration_test_setup.yml b/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_cross_region/aws_ssm_integration_test_setup.yml
index 1f223757c..eff5f5386 100644
--- a/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_cross_region/aws_ssm_integration_test_setup.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_cross_region/aws_ssm_integration_test_setup.yml
@@ -2,7 +2,7 @@
roles:
- role: ../setup_connection_aws_ssm
vars:
- target_os: fedora
+ target_os: centos
s3_bucket_region: 'eu-central-1'
# Post 2019 regions behave differently from other regions
# they're worth testing but it's not possible in CI today.
diff --git a/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_encrypted_s3/aws_ssm_integration_test_setup.yml b/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_encrypted_s3/aws_ssm_integration_test_setup.yml
index bfea0d0dc..d6e650cd3 100644
--- a/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_encrypted_s3/aws_ssm_integration_test_setup.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_encrypted_s3/aws_ssm_integration_test_setup.yml
@@ -2,6 +2,6 @@
roles:
- role: ../setup_connection_aws_ssm
vars:
- target_os: fedora
+ target_os: centos
encrypted_bucket: True
test_suffix: encrypteds3
diff --git a/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_endpoint/aws_ssm_integration_test_setup.yml b/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_endpoint/aws_ssm_integration_test_setup.yml
index 71c850e9d..e0296c7d6 100644
--- a/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_endpoint/aws_ssm_integration_test_setup.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_endpoint/aws_ssm_integration_test_setup.yml
@@ -2,6 +2,6 @@
roles:
- role: ../setup_connection_aws_ssm
vars:
- target_os: fedora
+ target_os: centos
test_suffix: endpoint
endpoint_url: 'https://s3.dualstack.{{ aws_region }}.amazonaws.com'
diff --git a/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_profile/aws_ssm_integration_test_setup.yml b/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_profile/aws_ssm_integration_test_setup.yml
index 3f4c2e47d..b8169d2c6 100644
--- a/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_profile/aws_ssm_integration_test_setup.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_profile/aws_ssm_integration_test_setup.yml
@@ -2,5 +2,5 @@
roles:
- role: ../setup_connection_aws_ssm
vars:
- target_os: fedora
+ target_os: centos
profile_name: test_profile
diff --git a/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_ssm_document/aws_ssm_integration_test_setup.yml b/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_ssm_document/aws_ssm_integration_test_setup.yml
index 992426976..6ef4dfd47 100644
--- a/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_ssm_document/aws_ssm_integration_test_setup.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_ssm_document/aws_ssm_integration_test_setup.yml
@@ -2,6 +2,6 @@
roles:
- role: ../setup_connection_aws_ssm
vars:
- target_os: fedora
+ target_os: centos
use_ssm_document: True
test_suffix: document
diff --git a/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_vars/aws_ssm_integration_test_setup.yml b/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_vars/aws_ssm_integration_test_setup.yml
index ff67bc2c3..2b3755b88 100644
--- a/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_vars/aws_ssm_integration_test_setup.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_vars/aws_ssm_integration_test_setup.yml
@@ -2,5 +2,5 @@
roles:
- role: ../setup_connection_aws_ssm
vars:
- target_os: fedora
+ target_os: centos
credential_vars: True
diff --git a/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_windows/aliases b/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_windows/aliases
index eb8e0b891..b321dedb6 100644
--- a/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_windows/aliases
+++ b/ansible_collections/community/aws/tests/integration/targets/connection_aws_ssm_windows/aliases
@@ -2,3 +2,5 @@ time=10m
cloud/aws
connection_aws_ssm
+
+unstable
diff --git a/ansible_collections/community/aws/tests/integration/targets/dms_endpoint/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/dms_endpoint/tasks/main.yml
index 328ea17a5..8d12933a4 100644
--- a/ansible_collections/community/aws/tests/integration/targets/dms_endpoint/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/dms_endpoint/tasks/main.yml
@@ -4,9 +4,9 @@
- amazon.aws
module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region }}'
block:
diff --git a/ansible_collections/community/aws/tests/integration/targets/dms_replication_subnet_group/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/dms_replication_subnet_group/tasks/main.yml
index 0952602f1..712bc82be 100644
--- a/ansible_collections/community/aws/tests/integration/targets/dms_replication_subnet_group/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/dms_replication_subnet_group/tasks/main.yml
@@ -4,9 +4,9 @@
- amazon.aws
module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region }}'
block:
diff --git a/ansible_collections/community/aws/tests/integration/targets/dynamodb_table/aliases b/ansible_collections/community/aws/tests/integration/targets/dynamodb_table/aliases
index dc5eacd6f..17466b153 100644
--- a/ansible_collections/community/aws/tests/integration/targets/dynamodb_table/aliases
+++ b/ansible_collections/community/aws/tests/integration/targets/dynamodb_table/aliases
@@ -1,2 +1,4 @@
cloud/aws
time=50m
+
+unstable
diff --git a/ansible_collections/community/aws/tests/integration/targets/dynamodb_table/defaults/main.yml b/ansible_collections/community/aws/tests/integration/targets/dynamodb_table/defaults/main.yml
index 8b92884a4..de11cefba 100644
--- a/ansible_collections/community/aws/tests/integration/targets/dynamodb_table/defaults/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/dynamodb_table/defaults/main.yml
@@ -1,5 +1,7 @@
---
table_name: "{{ resource_prefix }}"
+table_name_composite_pk: "{{ resource_prefix }}-composite-pk"
+table_name_composite_pk_local_indexes: "{{ resource_prefix }}-composite-pk-local-indexes"
table_name_on_demand: "{{ resource_prefix }}-pay-per-request"
table_name_on_demand_complex: "{{ resource_prefix }}-pay-per-request-complex"
@@ -31,6 +33,32 @@ indexes:
read_capacity: 2
write_capacity: 2
+local_indexes:
+ - name: NamedIndex
+ type: include
+ hash_key_name: "id" ## == table_index
+ hash_key_type: "NUMBER" ## == table_index_type
+ range_key_name: create_time
+ includes:
+ - other_field
+ - other_field2
+ read_capacity: 10
+ write_capacity: 10
+ - name: AnotherIndex
+ type: all
+ hash_key_name: id ## == table_index
+ hash_key_type: "NUMBER" ## == table_index_type
+ range_key_name: bar
+ read_capacity: 5
+ write_capacity: 5
+ - name: KeysOnlyIndex
+ type: keys_only
+ hash_key_name: id ## == table_index
+ hash_key_type: "NUMBER" ## == table_index_type
+ range_key_name: baz
+ read_capacity: 2
+ write_capacity: 2
+
indexes_pay_per_request:
- name: NamedIndex
type: global_include
diff --git a/ansible_collections/community/aws/tests/integration/targets/dynamodb_table/meta/main.yml b/ansible_collections/community/aws/tests/integration/targets/dynamodb_table/meta/main.yml
index 504e72117..32cf5dda7 100644
--- a/ansible_collections/community/aws/tests/integration/targets/dynamodb_table/meta/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/dynamodb_table/meta/main.yml
@@ -1,4 +1 @@
-dependencies:
- - role: setup_botocore_pip
- vars:
- botocore_version: "1.23.18"
+dependencies: []
diff --git a/ansible_collections/community/aws/tests/integration/targets/dynamodb_table/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/dynamodb_table/tasks/main.yml
index b208f4ca5..268e61bae 100644
--- a/ansible_collections/community/aws/tests/integration/targets/dynamodb_table/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/dynamodb_table/tasks/main.yml
@@ -7,12 +7,12 @@
#
- module_defaults:
group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"
block:
- - include: "test_pay_per_request.yml"
+ - include_tasks: "test_pay_per_request.yml"
# ==============================================
@@ -115,6 +115,262 @@
- create_table.write_capacity == 1
# ==============================================
+ # Attempting to create a table without PK range key but with local indexes will result in an expected failure.
+ # "One or more parameter values were invalid: Table KeySchema does not have a range key, which is required when specifying a LocalSecondaryIndex"
+
+ - name: Create table with simple PK with local indexes - test failure
+ dynamodb_table:
+ state: present
+ name: "{{ table_name_composite_pk }}"
+ hash_key_name: "{{ table_index }}"
+ hash_key_type: "{{ table_index_type }}"
+ indexes: "{{ local_indexes }}"
+ ignore_errors: yes
+ register: create_table
+
+ - name: Check results - Create table with simple PK with local indexes
+ assert:
+ that:
+ - create_table is failed
+
+ # ==============================================
+ # Attempting to create a table with composite PK but with local indexes using different hash key will result in an expected failure.
+ # "One or more parameter values were invalid: Index KeySchema does not have the same leading hash key as table KeySchema for index: NamedIndex. index hash key: id, table hash key: NOT_id"
+
+ - name: Create table with composite PK with mismatching local indexes - test failure
+ dynamodb_table:
+ state: present
+ name: "{{ table_name_composite_pk }}"
+ hash_key_name: "NOT_{{ table_index }}"
+ hash_key_type: "{{ table_index_type }}"
+ range_key_name: "{{ range_index }}"
+ range_key_type: "{{ range_index_type }}"
+ indexes: "{{ local_indexes }}"
+ ignore_errors: yes
+ register: create_table
+
+ - name: Check results - Create table with composite PK with mismatching local indexes
+ assert:
+ that:
+ - create_table is failed
+
+ # ==============================================
+
+ - name: Create table with composite PK - check_mode
+ dynamodb_table:
+ state: present
+ name: "{{ table_name_composite_pk }}"
+ hash_key_name: "{{ table_index }}"
+ hash_key_type: "{{ table_index_type }}"
+ range_key_name: "{{ range_index }}"
+ range_key_type: "{{ range_index_type }}"
+ register: create_table
+ check_mode: True
+
+ - name: Check results - Create table with composite PK - check_mode
+ assert:
+ that:
+ - create_table is successful
+ - create_table is changed
+
+ - name: Create table with composite PK
+ dynamodb_table:
+ state: present
+ name: "{{ table_name_composite_pk }}"
+ hash_key_name: "{{ table_index }}"
+ hash_key_type: "{{ table_index_type }}"
+ range_key_name: "{{ range_index }}"
+ range_key_type: "{{ range_index_type }}"
+ register: create_table
+
+ - name: Check results - Create table with composite PK
+ assert:
+ that:
+ - create_table is successful
+ - create_table is changed
+ - '"hash_key_name" in create_table'
+ - '"hash_key_type" in create_table'
+ - '"indexes" in create_table'
+ - '"range_key_name" in create_table'
+ - '"range_key_type" in create_table'
+ - '"read_capacity" in create_table'
+ - '"region" in create_table'
+ - '"table_name" in create_table'
+ - '"table_status" in create_table'
+ - '"tags" in create_table'
+ - '"write_capacity" in create_table'
+ - create_table.hash_key_name == table_index
+ - create_table.hash_key_type == table_index_type
+ - create_table.range_key_name == range_index
+ - create_table.range_key_type == range_index_type
+ - create_table.indexes | length == 0
+ - create_table.read_capacity == 1
+ - create_table.table_name == table_name_composite_pk
+ - create_table.write_capacity == 1
+
+ - name: Create table with composite PK - idempotent - check_mode
+ dynamodb_table:
+ state: present
+ name: "{{ table_name_composite_pk }}"
+ hash_key_name: "{{ table_index }}"
+ hash_key_type: "{{ table_index_type }}"
+ range_key_name: "{{ range_index }}"
+ range_key_type: "{{ range_index_type }}"
+ register: create_table
+ check_mode: True
+
+ - name: Check results - Create table with composite PK - idempotent - check_mode
+ assert:
+ that:
+ - create_table is successful
+ - create_table is not changed
+
+ - name: Create table with composite PK - idempotent
+ dynamodb_table:
+ state: present
+ name: "{{ table_name_composite_pk }}"
+ hash_key_name: "{{ table_index }}"
+ hash_key_type: "{{ table_index_type }}"
+ range_key_name: "{{ range_index }}"
+ range_key_type: "{{ range_index_type }}"
+ register: create_table
+
+ - name: Check results - Create table with composite PK - idempotent
+ assert:
+ that:
+ - create_table is successful
+ - create_table is not changed
+ - '"hash_key_name" in create_table'
+ - '"hash_key_type" in create_table'
+ - '"indexes" in create_table'
+ - '"range_key_name" in create_table'
+ - '"range_key_type" in create_table'
+ - '"read_capacity" in create_table'
+ - '"region" in create_table'
+ - '"table_name" in create_table'
+ - '"table_status" in create_table'
+ - '"tags" in create_table'
+ - '"write_capacity" in create_table'
+ - create_table.hash_key_name == table_index
+ - create_table.hash_key_type == table_index_type
+ - create_table.range_key_name == range_index
+ - create_table.range_key_type == range_index_type
+ - create_table.indexes | length == 0
+ - create_table.read_capacity == 1
+ - create_table.table_name == table_name_composite_pk
+ - create_table.write_capacity == 1
+
+ # ==============================================
+
+ - name: Create table with composite PK and local indexes - check_mode
+ dynamodb_table:
+ state: present
+ name: "{{ table_name_composite_pk_local_indexes }}"
+ hash_key_name: "{{ table_index }}"
+ hash_key_type: "{{ table_index_type }}"
+ range_key_name: "{{ range_index }}"
+ range_key_type: "{{ range_index_type }}"
+ indexes: "{{ local_indexes }}"
+ register: create_table
+ check_mode: True
+
+ - name: Check results - Create table with composite PK and local indexes - check_mode
+ assert:
+ that:
+ - create_table is successful
+ - create_table is changed
+
+ - name: Create table with composite PK and local indexes
+ dynamodb_table:
+ state: present
+ name: "{{ table_name_composite_pk_local_indexes }}"
+ hash_key_name: "{{ table_index }}"
+ hash_key_type: "{{ table_index_type }}"
+ range_key_name: "{{ range_index }}"
+ range_key_type: "{{ range_index_type }}"
+ indexes: "{{ local_indexes }}"
+ register: create_table
+
+ - name: Check results - Create table with composite PK and local indexes
+ assert:
+ that:
+ - create_table is successful
+ - create_table is changed
+ - '"hash_key_name" in create_table'
+ - '"hash_key_type" in create_table'
+ - '"indexes" in create_table'
+ - '"range_key_name" in create_table'
+ - '"range_key_type" in create_table'
+ - '"read_capacity" in create_table'
+ - '"region" in create_table'
+ - '"table_name" in create_table'
+ - '"table_status" in create_table'
+ - '"tags" in create_table'
+ - '"write_capacity" in create_table'
+ - create_table.hash_key_name == table_index
+ - create_table.hash_key_type == table_index_type
+ - create_table.range_key_name == range_index
+ - create_table.range_key_type == range_index_type
+ - create_table.indexes | length == 3
+ - create_table.read_capacity == 1
+ - create_table.table_name == table_name_composite_pk_local_indexes
+ - create_table.write_capacity == 1
+
+ - name: Create table with composite PK and local indexes - idempotent - check_mode
+ dynamodb_table:
+ state: present
+ name: "{{ table_name_composite_pk_local_indexes }}"
+ hash_key_name: "{{ table_index }}"
+ hash_key_type: "{{ table_index_type }}"
+ range_key_name: "{{ range_index }}"
+ range_key_type: "{{ range_index_type }}"
+ indexes: "{{ local_indexes }}"
+ register: create_table
+ check_mode: True
+
+ - name: Check results - Create table with composite PK and local indexes - idempotent - check_mode
+ assert:
+ that:
+ - create_table is successful
+ - create_table is not changed
+
+ - name: Create table with composite PK and local indexes - idempotent
+ dynamodb_table:
+ state: present
+ name: "{{ table_name_composite_pk_local_indexes }}"
+ hash_key_name: "{{ table_index }}"
+ hash_key_type: "{{ table_index_type }}"
+ range_key_name: "{{ range_index }}"
+ range_key_type: "{{ range_index_type }}"
+ indexes: "{{ local_indexes }}"
+ register: create_table
+
+ - name: Check results - Create table with composite PK and local indexes - idempotent
+ assert:
+ that:
+ - create_table is successful
+ - create_table is not changed
+ - '"hash_key_name" in create_table'
+ - '"hash_key_type" in create_table'
+ - '"indexes" in create_table'
+ - '"range_key_name" in create_table'
+ - '"range_key_type" in create_table'
+ - '"read_capacity" in create_table'
+ - '"region" in create_table'
+ - '"table_name" in create_table'
+ - '"table_status" in create_table'
+ - '"tags" in create_table'
+ - '"write_capacity" in create_table'
+ - create_table.hash_key_name == table_index
+ - create_table.hash_key_type == table_index_type
+ - create_table.range_key_name == range_index
+ - create_table.range_key_type == range_index_type
+ - create_table.indexes | length == 3
+ - create_table.read_capacity == 1
+ - create_table.table_name == table_name_composite_pk_local_indexes
+ - create_table.write_capacity == 1
+
+ # ==============================================
- name: Tag table - check_mode
dynamodb_table:
@@ -488,14 +744,14 @@
- update_indexes is successful
- update_indexes is not changed
- - name: Update table add indexes - idempotent
+ - name: Update table add global indexes - idempotent
dynamodb_table:
state: present
name: "{{ table_name }}"
indexes: "{{ indexes }}"
register: update_indexes
- - name: Check results - Update table add indexes - idempotent
+ - name: Check results - Update table add global indexes - idempotent
assert:
that:
- update_indexes is successful
@@ -588,8 +844,6 @@
tags: "{{ tags_default }}"
indexes: "{{ indexes }}"
register: create_complex_table
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
check_mode: True
- name: Check results - Create complex table - check_mode
@@ -612,8 +866,6 @@
tags: "{{ tags_default }}"
indexes: "{{ indexes }}"
register: create_complex_table
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
- name: Check results - Create complex table
assert:
@@ -656,8 +908,6 @@
tags: "{{ tags_default }}"
indexes: "{{ indexes }}"
register: create_complex_table
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
check_mode: True
- name: Check results - Create complex table - idempotent - check_mode
@@ -680,8 +930,6 @@
tags: "{{ tags_default }}"
indexes: "{{ indexes }}"
register: create_complex_table
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
- name: Check results - Create complex table - idempotent
assert:
@@ -719,8 +967,6 @@
name: "{{ table_name }}"
table_class: "STANDARD"
register: update_class
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
check_mode: True
- name: Check results - Update table class - check_mode
@@ -734,8 +980,6 @@
state: present
name: "{{ table_name }}"
table_class: "STANDARD"
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
register: update_class
- name: Check results - Update table class
@@ -873,6 +1117,20 @@
wait: false
register: delete_table
+ - name: Delete provisoned table with composite key
+ dynamodb_table:
+ state: absent
+ name: "{{ table_name_composite_pk }}"
+ wait: false
+ register: delete_table
+
+ - name: Delete provisoned table with composite key and local indexes
+ dynamodb_table:
+ state: absent
+ name: "{{ table_name_composite_pk_local_indexes }}"
+ wait: false
+ register: delete_table
+
- name: Delete on-demand table
dynamodb_table:
state: absent
diff --git a/ansible_collections/community/aws/tests/integration/targets/dynamodb_table/tasks/test_pay_per_request.yml b/ansible_collections/community/aws/tests/integration/targets/dynamodb_table/tasks/test_pay_per_request.yml
index a05021154..b469a1b51 100644
--- a/ansible_collections/community/aws/tests/integration/targets/dynamodb_table/tasks/test_pay_per_request.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/dynamodb_table/tasks/test_pay_per_request.yml
@@ -22,6 +22,7 @@
hash_key_name: "{{ table_index }}"
hash_key_type: "{{ table_index_type }}"
billing_mode: PAY_PER_REQUEST
+ wait_timeout: 450
register: create_table
- name: Check results - Create table
diff --git a/ansible_collections/community/aws/tests/integration/targets/ec2_carrier_gateway/aliases b/ansible_collections/community/aws/tests/integration/targets/ec2_carrier_gateway/aliases
new file mode 100644
index 000000000..913237649
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/ec2_carrier_gateway/aliases
@@ -0,0 +1,9 @@
+# reason: missing-policy
+# To test Carrier Gateway in the VPC, the Wavelength subnet
+# group should be enabled on the AWS Account.
+unsupported
+
+cloud/aws
+
+ec2_carrier_gateway
+ec2_carrier_gateway_info
diff --git a/ansible_collections/community/aws/tests/integration/targets/ec2_carrier_gateway/defaults/main.yml b/ansible_collections/community/aws/tests/integration/targets/ec2_carrier_gateway/defaults/main.yml
new file mode 100644
index 000000000..2e8c38f88
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/ec2_carrier_gateway/defaults/main.yml
@@ -0,0 +1,3 @@
+---
+vpc_name: '{{ resource_prefix }}-ec2-vpc-cagw'
+cagw_name: '{{ resource_prefix }}-ec2-vpc-cagw'
diff --git a/ansible_collections/community/aws/tests/integration/targets/aws_region_info/meta/main.yml b/ansible_collections/community/aws/tests/integration/targets/ec2_carrier_gateway/meta/main.yml
index 32cf5dda7..32cf5dda7 100644
--- a/ansible_collections/community/aws/tests/integration/targets/aws_region_info/meta/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/ec2_carrier_gateway/meta/main.yml
diff --git a/ansible_collections/community/aws/tests/integration/targets/ec2_carrier_gateway/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/ec2_carrier_gateway/tasks/main.yml
new file mode 100644
index 000000000..4d005b90a
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/ec2_carrier_gateway/tasks/main.yml
@@ -0,0 +1,167 @@
+---
+- name: 'ec2_carrier_gateway integration tests'
+ collections:
+ - community.aws
+ module_defaults:
+ group/aws:
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
+ region: '{{ aws_region }}'
+ block:
+
+ # ============================================================
+ - debug: msg="Setting up test dependencies"
+
+ - name: create a VPC
+ ec2_vpc_net:
+ name: "{{ vpc_name }}-{{ item }}"
+ state: present
+ cidr_block: "{{ vpc_cidr }}"
+ tags:
+ Description: "Created by ansible-test for CAGW tests"
+ register: vpc_result
+ loop: [1]
+
+ - name: use set fact for vpc ids
+ set_fact:
+ vpc_id_1: '{{ vpc_result.results.0.vpc.id }}'
+
+ # ============================================================
+ - debug: msg="Running tests"
+
+ - name: create carrier gateway and attach it to vpc
+ ec2_carrier_gateway:
+ state: present
+ vpc_id: '{{ vpc_id_1 }}'
+ name: "{{ cagw_name }}"
+ register: cagw
+ check_mode: true
+
+ - name: use set fact for cagw ids
+ set_fact:
+ cagw_id: '{{ cagw.carrier_gateway_id }}'
+
+ - assert:
+ that:
+ - cagw.changed
+ - cagw.vpc_id == vpc_id_1
+ - cagw.tags.Name == cagw_name
+
+ - name: test idempotence
+ ec2_carrier_gateway:
+ state: present
+ vpc_id: '{{ vpc_id_1 }}'
+ name: "{{ cagw_name }}"
+ register: cagw
+ check_mode: true
+
+ - assert:
+ that:
+ - not cagw.changed
+ - cagw.carrier_gateway_id == cagw_id
+
+ # ============================================================
+
+ - name: get VPC CAGW facts by ID (CHECK)
+ ec2_carrier_gateway_info:
+ carrier_gateway_id: ['{{ cagw_id }}']
+ register: cagw_info
+ check_mode: True
+
+ - name: verify expected facts
+ vars:
+ cagw_details: '{{ cagw_info.carrier_gateways[0] }}'
+ assert:
+ that:
+ - cagw_info.carrier_gateways | length == 1
+ - '"carrier_gateway_id" in cagw_details'
+ - '"tags" in cagw_details'
+ - '"vpc_id" in cagw_details'
+ - cagw_details.carrier_gateway_id == cagw_id
+ - '"Name" in cagw_details.tags'
+ - cagw_details.tags.Name == cagw_name
+
+ - name: get VPC CAGW facts by Tag
+ ec2_carrier_gateway_info:
+ filters:
+ "tag:Name": "{{ cagw_name }}"
+ register: cagw_info
+
+ - name: verify expected facts
+ vars:
+ cagw_details: '{{ cagw_info.virtual_gateways[0] }}'
+ assert:
+ that:
+ - cagw_info.virtual_gateways | length == 1
+ - '"carrier_gateway_id" in cagw_details'
+ - '"state" in cagw_details'
+ - '"tags" in cagw_details'
+ - cagw_details.carrier_gateway_id == cagw_id
+ - '"Name" in cagw_details.tags'
+ - cagw_details.tags.Name == cagw_name
+
+
+ # ============================================================
+
+ - name: get all CAGWs
+ ec2_carrier_gateway_info:
+ register: cagw_info
+
+ - name: verify test CAGW is in the results
+ vars:
+ cagw_id_list: '{{ cagw_info.carrier_gateways | map(attribute="carrier_gateway_id") | list }}'
+ assert:
+ that:
+ - cagw_id in cagw_id_list
+
+ # ============================================================
+
+ - include_tasks: 'tags.yml'
+
+ # ============================================================
+
+ - name: delete carrier gateway
+ ec2_carrier_gateway:
+ state: absent
+ name: "{{ cagw_name }}"
+ register: cagw
+ check_mode: true
+
+ - assert:
+ that:
+ - cagw.changed
+
+ - name: test idempotence
+ ec2_carrier_gateway:
+ state: absent
+ name: "{{ cagw_name }}"
+ register: cagw
+ check_mode: true
+
+ - assert:
+ that:
+ - not cagw.changed
+
+ always:
+
+ - debug: msg="Removing test dependencies"
+
+ - name: delete carrier gateway
+ ec2_carrier_gateway:
+ state: absent
+ carrier_gateway_id: '{{ cagw.carrier_gateway_id }}'
+ ignore_errors: true
+ check_mode: true
+
+ - name: delete vpc
+ ec2_vpc_net:
+ name: "{{ vpc_name }}-{{ item }}"
+ state: absent
+ cidr_block: "{{ vpc_cidr }}"
+ loop: [1, 2]
+ register: result
+ retries: 10
+ delay: 5
+ until: result is not failed
+ ignore_errors: true
diff --git a/ansible_collections/community/aws/tests/integration/targets/ec2_carrier_gateway/tasks/tags.yml b/ansible_collections/community/aws/tests/integration/targets/ec2_carrier_gateway/tasks/tags.yml
new file mode 100644
index 000000000..07104daa7
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/ec2_carrier_gateway/tasks/tags.yml
@@ -0,0 +1,224 @@
+- vars:
+ first_tags:
+ 'Key with Spaces': Value with spaces
+ CamelCaseKey: CamelCaseValue
+ pascalCaseKey: pascalCaseValue
+ snake_case_key: snake_case_value
+ second_tags:
+ 'New Key with Spaces': Value with spaces
+ NewCamelCaseKey: CamelCaseValue
+ newPascalCaseKey: pascalCaseValue
+ new_snake_case_key: snake_case_value
+ third_tags:
+ 'Key with Spaces': Value with spaces
+ CamelCaseKey: CamelCaseValue
+ pascalCaseKey: pascalCaseValue
+ snake_case_key: snake_case_value
+ 'New Key with Spaces': Updated Value with spaces
+ final_tags:
+ 'Key with Spaces': Value with spaces
+ CamelCaseKey: CamelCaseValue
+ pascalCaseKey: pascalCaseValue
+ snake_case_key: snake_case_value
+ 'New Key with Spaces': Updated Value with spaces
+ NewCamelCaseKey: CamelCaseValue
+ newPascalCaseKey: pascalCaseValue
+ new_snake_case_key: snake_case_value
+ name_tags:
+ Name: '{{ cagw_name }}'
+ module_defaults:
+ ec2_carrier_gateway:
+ name: '{{ cagw_name }}'
+ ec2_carrier_gateway_info:
+ vpn_gateway_ids: ['{{ cagw_id }}']
+ block:
+
+ # ============================================================
+
+ - name: add tags
+ ec2_carrier_gateway:
+ tags: '{{ first_tags }}'
+ state: 'present'
+ register: tag_cagw
+ check_mode: true
+
+ - name: get VPC CAGW facts
+ ec2_carrier_gateway_info: {}
+ register: tag_cagw_info
+
+ - name: verify the tags were added
+ assert:
+ that:
+ - tag_cagw is changed
+ - tag_cagw.carrier_gateway_id == cagw_id
+ - tag_cagw_info.carrier_gateways[0].carrier_gateway_id == cagw_id
+ - tag_cagw_info.carrier_gateways[0].tags == ( first_tags | combine(name_tags) )
+
+ - name: add tags - IDEMPOTENCY
+ ec2_carrier_gateway:
+ tags: '{{ first_tags }}'
+ state: 'present'
+ register: tag_cagw
+ check_mode: true
+ - name: get VPC CAGW facts
+ ec2_carrier_gateway_info: {}
+ register: tag_carrier_gateway_info
+
+ - name: verify no change
+ assert:
+ that:
+ - tag_cagw is not changed
+ - tag_cagw.carrier_gateway_id == cagw_id
+ - tag_cagw_info.carrier_gateways[0].carrier_gateway_id == cagw_id
+ - tag_cagw_info.carrier_gateways[0].tags == ( first_tags | combine(name_tags) )
+
+ # ============================================================
+
+ - name: get VPC CAGW facts by filter
+ ec2_carrier_gateway_info:
+ filters:
+ 'tag:Name': '{{ cagw_name }}'
+ vpn_gateway_ids: '{{ omit }}'
+ register: tag_cagw_info
+
+ - name: assert the facts are the same as before
+ assert:
+ that:
+ - tag_cagw_info.carrier_gateways | length == 1
+ - tag_cagw.carrier_gateway_id == cagw_id
+ - tag_cagw_info.carrier_gateways[0].carrier_gateway_id == cagw_id
+
+ # ============================================================
+
+ - name: modify tags with purge
+ ec2_carrier_gateway:
+ tags: '{{ second_tags }}'
+ state: 'present'
+ register: tag_cagw
+ check_mode: true
+ - name: get VPC CAGW facts
+ ec2_carrier_gateway_info:
+ register: tag_cagw_info
+
+ - name: verify the tags were added
+ assert:
+ that:
+ - tag_cagw is changed
+ - tag_cagw.carrier_gateway_id == cagw_id
+ - tag_cagw_info.carrier_gateways[0].carrier_gateway_id == cagw_id
+ - tag_cagw_info.carrier_gateways[0].tags == ( second_tags | combine(name_tags) )
+
+ - name: modify tags with purge - IDEMPOTENCY
+ ec2_carrier_gateway:
+ tags: '{{ second_tags }}'
+ state: 'present'
+ register: tag_cagw
+ check_mode: true
+ - name: get VPC CAGW facts
+ ec2_carrier_gateway_info:
+ register: tag_cagw_info
+
+ - name: verify no change
+ assert:
+ that:
+ - tag_cagw is not changed
+ - tag_cagw.carrier_gateway_id == cagw_id
+ - tag_cagw_info.carrier_gateways[0].carrier_gateway_id == cagw_id
+ - tag_cagw_info.carrier_gateways[0].tags == ( second_tags | combine(name_tags) )
+
+ # ============================================================
+
+ - name: modify tags without purge
+ ec2_carrier_gateway:
+ tags: '{{ third_tags }}'
+ state: 'present'
+ purge_tags: False
+ register: tag_cagw
+ check_mode: true
+ - name: get VPC CAGW facts
+ ec2_carrier_gateway_info:
+ register: tag_cagw_info
+
+ - name: verify the tags were added
+ assert:
+ that:
+ - tag_cagw is changed
+ - tag_cagw.carrier_gateway_id == cagw_id
+ - tag_cagw_info.carrier_gateways[0].carrier_gateway_id == cagw_id
+ - tag_cagw_info.carrier_gateways[0].tags == ( final_tags | combine(name_tags) )
+
+ - name: modify tags without purge - IDEMPOTENCY
+ ec2_carrier_gateway:
+ tags: '{{ third_tags }}'
+ state: 'present'
+ purge_tags: False
+ register: tag_cagw
+ check_mode: true
+ - name: get VPC CAGW facts
+ ec2_carrier_gateway_info:
+ register: tag_cagw_info
+
+ - name: verify no change
+ assert:
+ that:
+ - tag_cagw is not changed
+ - tag_cagw.carrier_gateway_id == cagw_id
+ - tag_cagw_info.carrier_gateways[0].carrier_gateway_id == cagw_id
+ - tag_cagw_info.carrier_gateways[0].tags == ( final_tags | combine(name_tags) )
+
+ # ============================================================
+
+ - name: No change to tags without setting tags
+ ec2_carrier_gateway:
+ state: 'present'
+ register: tag_cagw
+ check_mode: true
+ - name: get VPC CAGW facts
+ ec2_carrier_gateway_info:
+ register: tag_cagw_info
+
+ - name: verify the tags were added
+ assert:
+ that:
+ - tag_cagw is not changed
+ - tag_cagw.carrier_gateway_id == cagw_id
+ - tag_cagw_info.carrier_gateways[0].carrier_gateway_id == cagw_id
+ - tag_cagw_info.carrier_gateways[0].tags == ( final_tags | combine(name_tags) )
+
+ # ============================================================
+
+ - name: remove non name tags
+ ec2_carrier_gateway:
+ tags: {}
+ state: 'present'
+ register: tag_cagw
+ check_mode: true
+ - name: get VPC CAGW facts
+ ec2_carrier_gateway_info:
+ register: tag_cagw_info
+
+ - name: verify the tags were added
+ assert:
+ that:
+ - tag_cagw is changed
+ - tag_cagw.carrier_gateway_id == cagw_id
+ - tag_cagw_info.carrier_gateways[0].carrier_gateway_id == cagw_id
+ - tag_cagw_info.carrier_gateways[0].tags == name_tags
+
+ - name: remove non name tags - IDEMPOTENCY
+ ec2_carrier_gateway:
+ tags: {}
+ state: 'present'
+ register: tag_cagw
+ check_mode: true
+ - name: get VPC CAGW facts
+ ec2_carrier_gateway_info:
+ register: tag_cagw_info
+
+ - name: verify no change
+ assert:
+ that:
+ - tag_cagw is not changed
+ - tag_cagw.carrier_gateway_id == cagw_id
+ - tag_cagw_info.carrier_gateways[0].carrier_gateway_id == cagw_id
+ - tag_cagw_info.carrier_gateways[0].tags == name_tags
diff --git a/ansible_collections/community/aws/tests/integration/targets/ec2_launch_template/meta/main.yml b/ansible_collections/community/aws/tests/integration/targets/ec2_launch_template/meta/main.yml
index ca18dd30f..1471b11f6 100644
--- a/ansible_collections/community/aws/tests/integration/targets/ec2_launch_template/meta/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/ec2_launch_template/meta/main.yml
@@ -1,5 +1,2 @@
dependencies:
- setup_ec2_facts
- - role: setup_botocore_pip
- vars:
- botocore_version: "1.23.30"
diff --git a/ansible_collections/community/aws/tests/integration/targets/ec2_launch_template/tasks/instance-metadata.yml b/ansible_collections/community/aws/tests/integration/targets/ec2_launch_template/tasks/instance-metadata.yml
index afe907f4f..7648f00ef 100644
--- a/ansible_collections/community/aws/tests/integration/targets/ec2_launch_template/tasks/instance-metadata.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/ec2_launch_template/tasks/instance-metadata.yml
@@ -1,53 +1,5 @@
---
-- name: test with older boto3 version that does not support instance_metadata_tags
- block:
- - name: fail metadata_options
- ec2_launch_template:
- name: "{{ resource_prefix }}-test-metadata"
- metadata_options:
- http_put_response_hop_limit: 1
- http_tokens: required
- http_protocol_ipv6: enabled
- instance_metadata_tags: enabled
- state: present
- register: metadata_options_launch_template
- ignore_errors: yes
- - name: verify fail with usefull error message
- assert:
- that:
- - metadata_options_launch_template.failed
- - metadata_options_launch_template is not changed
- - "'This is required to set instance_metadata_tags' in metadata_options_launch_template.msg"
-
- - name: success metadata_options
- ec2_launch_template:
- name: "{{ resource_prefix }}-test-metadata"
- metadata_options:
- http_put_response_hop_limit: 1
- http_tokens: required
- state: present
- register: metadata_options_launch_template
- - name: instance with metadata_options created with the right options
- assert:
- that:
- - metadata_options_launch_template is changed
- - "metadata_options_launch_template.latest_template.launch_template_data.metadata_options.http_put_response_hop_limit == 1"
- - "metadata_options_launch_template.latest_template.launch_template_data.metadata_options.http_tokens == 'required'"
- - "metadata_options_launch_template.latest_template.launch_template_data.metadata_options.http_protocol_ipv6 is not defined"
- - "metadata_options_launch_template.latest_template.launch_template_data.metadata_options.instance_metadata_tags is not defined"
- always:
- - name: delete the template
- ec2_launch_template:
- name: "{{ resource_prefix }}-test-metadata"
- state: absent
- register: del_lt
- retries: 10
- until: del_lt is not failed
- ignore_errors: true
-
-- name: test with boto3 version that supports instance_metadata_tags
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
+- name: instance_metadata_tags
block:
- name: metadata_options
ec2_launch_template:
diff --git a/ansible_collections/community/aws/tests/integration/targets/ec2_launch_template/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/ec2_launch_template/tasks/main.yml
index aa87871ce..e89dfceb5 100644
--- a/ansible_collections/community/aws/tests/integration/targets/ec2_launch_template/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/ec2_launch_template/tasks/main.yml
@@ -1,9 +1,9 @@
---
- module_defaults:
group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"
block:
- include_tasks: cpu_options.yml
diff --git a/ansible_collections/community/aws/tests/integration/targets/ec2_launch_template/tasks/tags_and_vpc_settings.yml b/ansible_collections/community/aws/tests/integration/targets/ec2_launch_template/tasks/tags_and_vpc_settings.yml
index 026c59907..41ff9082b 100644
--- a/ansible_collections/community/aws/tests/integration/targets/ec2_launch_template/tasks/tags_and_vpc_settings.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/ec2_launch_template/tasks/tags_and_vpc_settings.yml
@@ -31,7 +31,7 @@
register: testing_subnet_b
- name: create a security group with the vpc
- ec2_group:
+ ec2_security_group:
name: "{{ resource_prefix }}-sg"
description: a security group for ansible tests
vpc_id: "{{ testing_vpc.vpc.id }}"
@@ -164,7 +164,7 @@
always:
- name: remove the security group
- ec2_group:
+ ec2_security_group:
name: "{{ resource_prefix }}-sg"
description: a security group for ansible tests
vpc_id: "{{ testing_vpc.vpc.id }}"
diff --git a/ansible_collections/community/aws/tests/integration/targets/ec2_placement_group/tasks/env_cleanup.yml b/ansible_collections/community/aws/tests/integration/targets/ec2_placement_group/tasks/env_cleanup.yml
index 9e5ae6a93..ce626b69c 100644
--- a/ansible_collections/community/aws/tests/integration/targets/ec2_placement_group/tasks/env_cleanup.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/ec2_placement_group/tasks/env_cleanup.yml
@@ -24,7 +24,7 @@
retries: 10
- name: remove the security group
- ec2_group:
+ ec2_security_group:
name: "{{ resource_prefix }}-sg"
description: a security group for ansible tests
vpc_id: "{{ testing_vpc.vpc.id }}"
diff --git a/ansible_collections/community/aws/tests/integration/targets/ec2_placement_group/tasks/env_setup.yml b/ansible_collections/community/aws/tests/integration/targets/ec2_placement_group/tasks/env_setup.yml
index 88f5bb6fe..d48bae66c 100644
--- a/ansible_collections/community/aws/tests/integration/targets/ec2_placement_group/tasks/env_setup.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/ec2_placement_group/tasks/env_setup.yml
@@ -48,7 +48,7 @@
- "{{ testing_subnet_b.subnet.id }}"
- name: create a security group with the vpc
- ec2_group:
+ ec2_security_group:
name: "{{ resource_prefix }}-sg"
description: a security group for ansible tests
vpc_id: "{{ testing_vpc.vpc.id }}"
diff --git a/ansible_collections/community/aws/tests/integration/targets/ec2_placement_group/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/ec2_placement_group/tasks/main.yml
index 91fd9497c..10695571e 100644
--- a/ansible_collections/community/aws/tests/integration/targets/ec2_placement_group/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/ec2_placement_group/tasks/main.yml
@@ -1,9 +1,9 @@
- name: run ec2_placement_group tests
module_defaults:
group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"
collections:
- amazon.aws
@@ -25,7 +25,7 @@
- assert:
that:
- pg_1_create_check_mode is changed
- - pg_1_create_check_mode.placement_group.name == '{{ resource_prefix }}-pg1'
+ - pg_1_create_check_mode.placement_group.name == resource_prefix ~ '-pg1'
- pg_1_create_check_mode.placement_group.state == "DryRun"
- '"ec2:CreatePlacementGroup" in pg_1_create_check_mode.resource_actions'
@@ -41,7 +41,7 @@
- assert:
that:
- pg_1_create is changed
- - pg_1_create.placement_group.name == '{{ resource_prefix }}-pg1'
+ - pg_1_create.placement_group.name == resource_prefix ~ '-pg1'
- pg_1_create.placement_group.state == "available"
- '"ec2:CreatePlacementGroup" in pg_1_create.resource_actions'
@@ -54,7 +54,7 @@
- assert:
that:
- pg_1_info_result is not changed
- - pg_1_info_result.placement_groups[0].name == '{{ resource_prefix }}-pg1'
+ - pg_1_info_result.placement_groups[0].name == resource_prefix ~ '-pg1'
- pg_1_info_result.placement_groups[0].state == "available"
- pg_1_info_result.placement_groups[0].strategy == "cluster"
- '"ec2:DescribePlacementGroups" in pg_1_info_result.resource_actions'
@@ -68,7 +68,7 @@
- assert:
that:
- pg_1_create is not changed
- - pg_1_create.placement_group.name == '{{ resource_prefix }}-pg1'
+ - pg_1_create.placement_group.name == resource_prefix ~ '-pg1'
- pg_1_create.placement_group.state == "available"
- '"ec2:CreatePlacementGroup" not in pg_1_create.resource_actions'
@@ -82,7 +82,7 @@
- assert:
that:
- pg_1_create_check_mode_idem is not changed
- - pg_1_create_check_mode_idem.placement_group.name == '{{ resource_prefix }}-pg1'
+ - pg_1_create_check_mode_idem.placement_group.name == resource_prefix ~ '-pg1'
- pg_1_create_check_mode_idem.placement_group.state == "available"
- '"ec2:CreatePlacementGroup" not in pg_1_create_check_mode_idem.resource_actions'
@@ -97,7 +97,7 @@
- assert:
that:
- pg_2_create_check_mode is changed
- - pg_2_create_check_mode.placement_group.name == '{{ resource_prefix }}-pg2'
+ - pg_2_create_check_mode.placement_group.name == resource_prefix ~ '-pg2'
- pg_2_create_check_mode.placement_group.state == "DryRun"
- '"ec2:CreatePlacementGroup" in pg_2_create_check_mode.resource_actions'
@@ -111,7 +111,7 @@
- assert:
that:
- pg_2_create is changed
- - pg_2_create.placement_group.name == '{{ resource_prefix }}-pg2'
+ - pg_2_create.placement_group.name == resource_prefix ~ '-pg2'
- pg_2_create.placement_group.state == "available"
- '"ec2:CreatePlacementGroup" in pg_2_create.resource_actions'
@@ -127,7 +127,7 @@
- assert:
that:
- pg_2_info_result is not changed
- - pg_2_info_result.placement_groups[0].name == '{{ resource_prefix }}-pg2'
+ - pg_2_info_result.placement_groups[0].name == resource_prefix ~ '-pg2'
- pg_2_info_result.placement_groups[0].state == "available"
- pg_2_info_result.placement_groups[0].strategy == "spread"
- '"ec2:DescribePlacementGroups" in pg_2_info_result.resource_actions'
@@ -142,7 +142,7 @@
- assert:
that:
- pg_2_create is not changed
- - pg_2_create.placement_group.name == '{{ resource_prefix }}-pg2'
+ - pg_2_create.placement_group.name == resource_prefix ~ '-pg2'
- pg_2_create.placement_group.state == "available"
- '"ec2:CreatePlacementGroup" not in pg_2_create.resource_actions'
@@ -157,7 +157,7 @@
- assert:
that:
- pg_2_create_check_mode_idem is not changed
- - pg_2_create_check_mode_idem.placement_group.name == '{{ resource_prefix }}-pg2'
+ - pg_2_create_check_mode_idem.placement_group.name == resource_prefix ~ '-pg2'
- pg_2_create_check_mode_idem.placement_group.state == "available"
- '"ec2:CreatePlacementGroup" not in pg_2_create_check_mode_idem.resource_actions'
@@ -173,7 +173,7 @@
- assert:
that:
- pg_3_create_check_mode is changed
- - pg_3_create_check_mode.placement_group.name == '{{ resource_prefix }}-pg3'
+ - pg_3_create_check_mode.placement_group.name == resource_prefix ~ '-pg3'
- pg_3_create_check_mode.placement_group.state == "DryRun"
- '"ec2:CreatePlacementGroup" in pg_3_create_check_mode.resource_actions'
@@ -188,7 +188,7 @@
- assert:
that:
- pg_3_create is changed
- - pg_3_create.placement_group.name == '{{ resource_prefix }}-pg3'
+ - pg_3_create.placement_group.name == resource_prefix ~ '-pg3'
- pg_3_create.placement_group.state == "available"
- '"ec2:CreatePlacementGroup" in pg_3_create.resource_actions'
@@ -205,7 +205,7 @@
- assert:
that:
- pg_3_info_result is not changed
- - pg_3_info_result.placement_groups[0].name == '{{ resource_prefix }}-pg3'
+ - pg_3_info_result.placement_groups[0].name == resource_prefix ~ '-pg3'
- pg_3_info_result.placement_groups[0].state == "available"
- pg_3_info_result.placement_groups[0].strategy == "partition"
- '"ec2:DescribePlacementGroups" in pg_3_info_result.resource_actions'
@@ -221,7 +221,7 @@
- assert:
that:
- pg_3_create is not changed
- - pg_3_create.placement_group.name == '{{ resource_prefix }}-pg3'
+ - pg_3_create.placement_group.name == resource_prefix ~ '-pg3'
- pg_3_create.placement_group.state == "available"
- '"ec2:CreatePlacementGroup" not in pg_3_create.resource_actions'
@@ -237,7 +237,7 @@
- assert:
that:
- pg_3_create_check_mode_idem is not changed
- - pg_3_create_check_mode_idem.placement_group.name == '{{ resource_prefix }}-pg3'
+ - pg_3_create_check_mode_idem.placement_group.name == resource_prefix ~ '-pg3'
- pg_3_create_check_mode_idem.placement_group.state == "available"
- '"ec2:CreatePlacementGroup" not in pg_3_create_check_mode_idem.resource_actions'
diff --git a/ansible_collections/community/aws/tests/integration/targets/ec2_transit_gateway/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/ec2_transit_gateway/tasks/main.yml
index 6cb279f77..c7353cfc0 100644
--- a/ansible_collections/community/aws/tests/integration/targets/ec2_transit_gateway/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/ec2_transit_gateway/tasks/main.yml
@@ -4,9 +4,9 @@
- amazon.aws
module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region }}'
block:
diff --git a/ansible_collections/community/aws/tests/integration/targets/ec2_transit_gateway_vpc_attachment/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/ec2_transit_gateway_vpc_attachment/tasks/main.yml
index 8694b829e..ce9659473 100644
--- a/ansible_collections/community/aws/tests/integration/targets/ec2_transit_gateway_vpc_attachment/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/ec2_transit_gateway_vpc_attachment/tasks/main.yml
@@ -4,9 +4,9 @@
- amazon.aws
module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region }}'
block:
diff --git a/ansible_collections/community/aws/tests/integration/targets/ec2_vpc_egress_igw/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/ec2_vpc_egress_igw/tasks/main.yml
index 41540b8d4..75fff0e4e 100644
--- a/ansible_collections/community/aws/tests/integration/targets/ec2_vpc_egress_igw/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/ec2_vpc_egress_igw/tasks/main.yml
@@ -4,9 +4,9 @@
- amazon.aws
module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region }}'
block:
diff --git a/ansible_collections/community/aws/tests/integration/targets/ec2_vpc_nacl/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/ec2_vpc_nacl/tasks/main.yml
index e1538049a..36c7ab2d8 100644
--- a/ansible_collections/community/aws/tests/integration/targets/ec2_vpc_nacl/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/ec2_vpc_nacl/tasks/main.yml
@@ -1,9 +1,9 @@
---
- module_defaults:
group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"
collections:
- amazon.aws
diff --git a/ansible_collections/community/aws/tests/integration/targets/ec2_vpc_peer/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/ec2_vpc_peer/tasks/main.yml
index cdb7c6680..b39b69b74 100644
--- a/ansible_collections/community/aws/tests/integration/targets/ec2_vpc_peer/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/ec2_vpc_peer/tasks/main.yml
@@ -4,9 +4,9 @@
- amazon.aws
module_defaults:
group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"
block:
- name: get ARN of calling user
diff --git a/ansible_collections/community/aws/tests/integration/targets/ec2_vpc_vgw/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/ec2_vpc_vgw/tasks/main.yml
index 37bbf5e37..f5a850a71 100644
--- a/ansible_collections/community/aws/tests/integration/targets/ec2_vpc_vgw/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/ec2_vpc_vgw/tasks/main.yml
@@ -4,9 +4,9 @@
- amazon.aws
module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region }}'
block:
diff --git a/ansible_collections/community/aws/tests/integration/targets/ec2_vpc_vpn/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/ec2_vpc_vpn/tasks/main.yml
index a4c740887..9514d7cf3 100644
--- a/ansible_collections/community/aws/tests/integration/targets/ec2_vpc_vpn/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/ec2_vpc_vpn/tasks/main.yml
@@ -4,9 +4,9 @@
- amazon.aws
module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region }}'
block:
@@ -35,7 +35,63 @@
name: testcgw
register: cgw
- - name: create vpn connection, with customer gateway
+ - name: create transit gateway
+ ec2_transit_gateway:
+ description: "Transit Gateway for vpn attachment"
+ register: tgw
+
+ - name: create vpn connection, with customer gateway, vpn_gateway_id and transit_gateway
+ ec2_vpc_vpn:
+ customer_gateway_id: '{{ cgw.gateway.customer_gateway.customer_gateway_id }}'
+ vpn_gateway_id: '{{ vgw.vgw.id }}'
+ transit_gateway_id: '{{ tgw.transit_gateway.transit_gateway_id }}'
+ state: present
+ register: result
+ ignore_errors: true
+
+ - name: assert creation of vpn failed
+ assert:
+ that:
+ - result is failed
+ - result.msg == "parameters are mutually exclusive: vpn_gateway_id|transit_gateway_id"
+
+
+ - name: create vpn connection, with customer gateway and transit_gateway
+ ec2_vpc_vpn:
+ customer_gateway_id: '{{ cgw.gateway.customer_gateway.customer_gateway_id }}'
+ transit_gateway_id: '{{ tgw.transit_gateway.transit_gateway_id }}'
+ state: present
+ register: tgw_vpn
+
+ - name: Store ID of VPN
+ set_fact:
+ vpn_id: '{{ tgw_vpn.vpn_connection_id }}'
+
+ # ============================================================
+ - name: test success with no parameters
+ ec2_vpc_vpn_info:
+ register: result
+
+ - name: assert success with no parameters
+ assert:
+ that:
+ - 'result.changed == false'
+ - 'result.vpn_connections != []'
+ # ============================================================
+
+ - name: Delete vpn created with transit gateway
+ ec2_vpc_vpn:
+ state: absent
+ vpn_connection_id: '{{ vpn_id }}'
+ register: result
+ retries: 10
+ delay: 3
+ until: result is not failed
+ ignore_errors: true
+
+ # ============================================================
+
+ - name: create vpn connection, with customer gateway and vpn gateway
ec2_vpc_vpn:
customer_gateway_id: '{{ cgw.gateway.customer_gateway.customer_gateway_id }}'
vpn_gateway_id: '{{ vgw.vgw.id }}'
@@ -47,6 +103,7 @@
vpn_id: '{{ vpn.vpn_connection_id }}'
# ============================================================
+
- name: test success with no parameters
ec2_vpc_vpn_info:
register: result
@@ -163,3 +220,9 @@
delay: 3
until: result is not failed
ignore_errors: true
+
+ - name: delete transit gateway
+ ec2_transit_gateway:
+ transit_gateway_id: '{{ tgw.transit_gateway.transit_gateway_id }}'
+ state: absent
+ ignore_errors: true
diff --git a/ansible_collections/community/aws/tests/integration/targets/ecs_cluster/meta/main.yml b/ansible_collections/community/aws/tests/integration/targets/ecs_cluster/meta/main.yml
index 7f42526eb..32cf5dda7 100644
--- a/ansible_collections/community/aws/tests/integration/targets/ecs_cluster/meta/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/ecs_cluster/meta/main.yml
@@ -1,4 +1 @@
-dependencies:
- - role: setup_botocore_pip
- vars:
- botocore_version: "1.24.14"
+dependencies: []
diff --git a/ansible_collections/community/aws/tests/integration/targets/ecs_cluster/tasks/01_create_requirements.yml b/ansible_collections/community/aws/tests/integration/targets/ecs_cluster/tasks/01_create_requirements.yml
index 31ca3cf27..14c1b6337 100644
--- a/ansible_collections/community/aws/tests/integration/targets/ecs_cluster/tasks/01_create_requirements.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/ecs_cluster/tasks/01_create_requirements.yml
@@ -72,7 +72,7 @@
register: igw
- name: create a security group to use for creating an ec2 instance
- ec2_group:
+ ec2_security_group:
name: '{{ resource_prefix }}_ecs_cluster-sg'
description: 'created by Ansible integration tests'
state: present
@@ -86,9 +86,9 @@
# As a lookup plugin we don't have access to module_defaults
connection_args:
region: "{{ aws_region }}"
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- aws_security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
no_log: True
- name: set image id fact
diff --git a/ansible_collections/community/aws/tests/integration/targets/ecs_cluster/tasks/20_ecs_service.yml b/ansible_collections/community/aws/tests/integration/targets/ecs_cluster/tasks/20_ecs_service.yml
index 4e0620555..3c4bbcb28 100644
--- a/ansible_collections/community/aws/tests/integration/targets/ecs_cluster/tasks/20_ecs_service.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/ecs_cluster/tasks/20_ecs_service.yml
@@ -86,8 +86,6 @@
- not ecs_service_again.changed
- name: create same ECS service definition via force_new_deployment
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
ecs_service:
state: present
force_new_deployment: true
@@ -113,8 +111,6 @@
- ecs_service_again.changed
- name: force_new_deployment should work without providing a task_definition
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
ecs_service:
state: present
force_new_deployment: yes
@@ -139,8 +135,6 @@
- ecs_service_notaskdef.changed
- name: attempt to use ECS network configuration on task definition without awsvpc network_mode (expected to fail)
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
ecs_service:
state: present
name: "{{ ecs_service_name }}3"
@@ -166,8 +160,6 @@
- ecs_service_network_without_awsvpc_task is failed
- name: scale down ECS service
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
ecs_service:
state: present
name: "{{ ecs_service_name }}"
@@ -191,8 +183,6 @@
- ecs_service_scale_down.service.desiredCount == 0
- name: scale down ECS service again
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
ecs_service:
state: present
name: "{{ ecs_service_name }}"
@@ -228,8 +218,6 @@
- ecs_task_update.changed
- name: Enable ExecuteCommand
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
ecs_service:
state: present
name: "{{ ecs_service_name }}"
@@ -315,8 +303,6 @@
- "ecs_taskdefinition_info.network_mode == 'awsvpc'"
- name: create ECS service definition with network configuration
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
ecs_service:
state: present
name: "{{ ecs_service_name }}2"
@@ -344,8 +330,6 @@
- "create_ecs_service_with_vpc.service.networkConfiguration.awsvpcConfiguration.securityGroups|length == 1"
- name: create ecs_service using health_check_grace_period_seconds
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
ecs_service:
name: "{{ ecs_service_name }}-mft"
cluster: "{{ ecs_cluster_name }}"
@@ -364,11 +348,9 @@
assert:
that:
- ecs_service_creation_hcgp.changed
- - "{{ecs_service_creation_hcgp.service.healthCheckGracePeriodSeconds}} == 30"
+ - ecs_service_creation_hcgp.service.healthCheckGracePeriodSeconds == 30
- name: update ecs_service using health_check_grace_period_seconds
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
ecs_service:
name: "{{ ecs_service_name }}-mft"
cluster: "{{ ecs_cluster_name }}"
@@ -386,11 +368,9 @@
assert:
that:
- ecs_service_creation_hcgp2.changed
- - "{{ecs_service_creation_hcgp2.service.healthCheckGracePeriodSeconds}} == 10"
+ - ecs_service_creation_hcgp2.service.healthCheckGracePeriodSeconds == 10
- name: update ecs_service using REPLICA scheduling_strategy
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
ecs_service:
name: "{{ ecs_service_name }}-replica"
cluster: "{{ ecs_cluster_name }}"
@@ -473,8 +453,8 @@
assert:
that:
- ecs_task_definition_constraints is changed
- - ecs_task_definition_constraints.taskdefinition.placementConstraints[0].type == "{{ ecs_taskdefinition_placement_constraints[0].type }}"
- - ecs_task_definition_constraints.taskdefinition.placementConstraints[0].expression == "{{ ecs_taskdefinition_placement_constraints[0].expression }}"
+ - ecs_task_definition_constraints.taskdefinition.placementConstraints[0].type == ecs_taskdefinition_placement_constraints[0].type
+ - ecs_task_definition_constraints.taskdefinition.placementConstraints[0].expression == ecs_taskdefinition_placement_constraints[0].expression
- name: Remove ecs task definition with placement constraints
ecs_taskdefinition:
@@ -517,8 +497,6 @@
- "ecs_service_create_no_load_balancer.service.loadBalancers | length == 0"
- name: Update ecs_service load balancer
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
ecs_service:
name: "{{ ecs_service_name }}-lb"
cluster: "{{ ecs_cluster_name }}"
@@ -541,8 +519,6 @@
- "ecs_service_update_load_balancer.service.loadBalancers[0].targetGroupArn == elb_target_group_instance.target_group_arn"
- name: Create ecs service with placement constraints
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
ecs_service:
name: "{{ ecs_service_name }}-constraint"
cluster: "{{ ecs_cluster_name }}"
@@ -593,8 +569,6 @@
until: "ECS.services[0].deployments[0].rolloutState == 'COMPLETED'"
- name: Update ecs service's placement constraints
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
ecs_service:
name: "{{ ecs_service_name }}-constraint"
cluster: "{{ ecs_cluster_name }}"
@@ -621,8 +595,6 @@
- "ecs_service_update_constraints.service.placementConstraints[0].expression == 'attribute:ecs.instance-type == t3.micro'"
- name: Remove ecs service's placement constraints
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
ecs_service:
name: "{{ ecs_service_name }}-constraint"
cluster: "{{ ecs_cluster_name }}"
@@ -645,8 +617,6 @@
- "ecs_service_remove_constraints.service.placementConstraints | length == 0"
- name: Create ecs service with placement strategy
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
ecs_service:
name: "{{ ecs_service_name }}-strategy"
cluster: "{{ ecs_cluster_name }}"
@@ -672,8 +642,6 @@
- "ecs_service_creation_strategy.service.placementStrategy[0].field == 'MEMORY'"
- name: Update ecs service's placement strategy
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
ecs_service:
name: "{{ ecs_service_name }}-strategy"
cluster: "{{ ecs_cluster_name }}"
@@ -700,8 +668,6 @@
- "ecs_service_update_strategy.service.placementStrategy[0].field == 'instanceId'"
- name: Remove ecs service's placement strategy
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
ecs_service:
name: "{{ ecs_service_name }}-strategy"
cluster: "{{ ecs_cluster_name }}"
@@ -942,6 +908,65 @@
started_by: ansible_user
register: fargate_run_task_output_with_assign_ip
+- name: create task definition for ARM
+ ecs_taskdefinition:
+ containers: "{{ ecs_fargate_task_containers }}"
+ family: "{{ ecs_task_name }}-arm"
+ network_mode: awsvpc
+ launch_type: FARGATE
+ cpu: 512
+ memory: 1024
+ execution_role_arn: "{{ iam_execution_role.arn }}"
+ state: present
+ runtime_platform:
+ cpuArchitecture: "ARM64"
+ operatingSystemFamily: "LINUX"
+ vars:
+ ecs_task_host_port: 8080
+ register: fargate_arm_task_definition
+
+- name: check that initial task definition for ARM changes
+ assert:
+ that:
+ - fargate_arm_task_definition.changed
+
+- name: recreate task definition for ARM
+ ecs_taskdefinition:
+ containers: "{{ ecs_fargate_task_containers }}"
+ family: "{{ ecs_task_name }}-arm"
+ network_mode: awsvpc
+ launch_type: FARGATE
+ cpu: 512
+ memory: 1024
+ execution_role_arn: "{{ iam_execution_role.arn }}"
+ state: present
+ runtime_platform:
+ cpuArchitecture: "ARM64"
+ operatingSystemFamily: "LINUX"
+ vars:
+ ecs_task_host_port: 8080
+ register: fargate_arm_task_definition_again
+
+- name: check that task definition for ARM does not change
+ assert:
+ that:
+ - not fargate_arm_task_definition_again.changed
+
+- name: delete task definition for ARM
+ ecs_taskdefinition:
+ containers: "{{ ecs_fargate_task_containers }}"
+ family: "{{ ecs_task_name }}-arm"
+ network_mode: awsvpc
+ launch_type: FARGATE
+ cpu: 512
+ memory: 1024
+ execution_role_arn: "{{ iam_execution_role.arn }}"
+ state: present
+ runtime_platform:
+ cpuArchitecture: "ARM64"
+ operatingSystemFamily: "LINUX"
+ vars:
+ ecs_task_host_port: 8080
# ============================================================
# End tests for Fargate
diff --git a/ansible_collections/community/aws/tests/integration/targets/ecs_cluster/tasks/99_terminate_everything.yml b/ansible_collections/community/aws/tests/integration/targets/ecs_cluster/tasks/99_terminate_everything.yml
index 7016f9e70..5d7ba5c72 100644
--- a/ansible_collections/community/aws/tests/integration/targets/ecs_cluster/tasks/99_terminate_everything.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/ecs_cluster/tasks/99_terminate_everything.yml
@@ -18,8 +18,6 @@
ignore_errors: true
- name: scale down ECS service
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
ecs_service:
state: present
name: "{{ ecs_service_name }}"
@@ -44,8 +42,6 @@
register: ecs_service_info
- name: scale down second ECS service
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
ecs_service:
state: present
name: "{{ ecs_service_name }}2"
@@ -62,8 +58,6 @@
register: ecs_service_scale_down
- name: scale down multifunction-test service
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
ecs_service:
name: "{{ ecs_service_name }}-mft"
cluster: "{{ ecs_cluster_name }}"
@@ -78,8 +72,6 @@
register: ecs_service_scale_down
- name: scale down scheduling_strategy service
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
ecs_service:
name: "{{ ecs_service_name }}-replica"
cluster: "{{ ecs_cluster_name }}"
@@ -94,8 +86,6 @@
register: ecs_service_scale_down
- name: scale down Fargate ECS service
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
ecs_service:
state: present
name: "{{ ecs_service_name }}4"
@@ -271,7 +261,7 @@
register: this_deletion
- name: remove security groups
- ec2_group:
+ ec2_security_group:
name: '{{ item }}'
description: 'created by Ansible integration tests'
state: absent
diff --git a/ansible_collections/community/aws/tests/integration/targets/ecs_cluster/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/ecs_cluster/tasks/main.yml
index 1d27cdc73..12d3cb52b 100644
--- a/ansible_collections/community/aws/tests/integration/targets/ecs_cluster/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/ecs_cluster/tasks/main.yml
@@ -4,15 +4,15 @@
- amazon.aws
module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region }}'
block:
- - include: 01_create_requirements.yml
- - include: 10_ecs_cluster.yml
- - include: 20_ecs_service.yml
+ - include_tasks: 01_create_requirements.yml
+ - include_tasks: 10_ecs_cluster.yml
+ - include_tasks: 20_ecs_service.yml
always:
- - include: 99_terminate_everything.yml
+ - include_tasks: 99_terminate_everything.yml
diff --git a/ansible_collections/community/aws/tests/integration/targets/ecs_ecr/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/ecs_ecr/tasks/main.yml
index e0ce4f3f6..68750e06e 100644
--- a/ansible_collections/community/aws/tests/integration/targets/ecs_ecr/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/ecs_ecr/tasks/main.yml
@@ -2,9 +2,9 @@
- module_defaults:
group/aws:
region: "{{ aws_region }}"
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
block:
- set_fact:
@@ -15,7 +15,7 @@
register: aws_caller_info
- name: create KMS key for testing
- aws_kms:
+ kms_key:
alias: "{{ resource_prefix }}-ecr"
description: a key used for testing ECR
state: present
@@ -597,7 +597,7 @@
- name: it should use the provided KMS key
assert:
that:
- - result.repository.encryptionConfiguration.kmsKey == '{{ kms_test_key.key_arn }}'
+ - result.repository.encryptionConfiguration.kmsKey == kms_test_key.key_arn
always:
@@ -607,6 +607,6 @@
state: absent
- name: Delete KMS key
- aws_kms:
+ kms_key:
key_id: '{{ kms_test_key.key_arn }}'
state: absent
diff --git a/ansible_collections/community/aws/tests/integration/targets/ecs_tag/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/ecs_tag/tasks/main.yml
index fff9ee27d..2c5614eb8 100644
--- a/ansible_collections/community/aws/tests/integration/targets/ecs_tag/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/ecs_tag/tasks/main.yml
@@ -1,9 +1,9 @@
- module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key | default(omit) }}'
- aws_secret_key: '{{ aws_secret_key | default(omit) }}'
- security_token: '{{ security_token | default(omit) }}'
- region: '{{ aws_region | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
+ region: '{{ aws_region }}'
collections:
- amazon.aws
block:
@@ -73,7 +73,7 @@
assert:
that:
- taglist.changed == true
- - taglist.added_tags.Name == "{{ resource_prefix }}"
+ - taglist.added_tags.Name == resource_prefix
- taglist.added_tags.another == "foobar"
- name: cluster tags - Add tags to cluster again
@@ -162,8 +162,8 @@
assert:
that:
- taglist.changed == true
- - taglist.added_tags.Name == "service-{{ resource_prefix }}"
- - taglist.tags.Name == "service-{{ resource_prefix }}"
+ - "taglist.added_tags.Name == 'service-' ~ resource_prefix"
+ - "taglist.tags.Name == 'service-' ~ resource_prefix"
- name: services tags - Add name tag again - see no change
ecs_tag:
@@ -179,7 +179,7 @@
assert:
that:
- taglist.changed == false
- - taglist.tags.Name == "service-{{ resource_prefix }}"
+ - "taglist.tags.Name == 'service-' ~ resource_prefix"
- name: service tags - remove service tags
ecs_tag:
@@ -215,8 +215,8 @@
assert:
that:
- taglist.changed == true
- - taglist.added_tags.Name == "task_definition-{{ resource_prefix }}"
- - taglist.tags.Name == "task_definition-{{ resource_prefix }}"
+ - "taglist.added_tags.Name == 'task_definition-' ~ resource_prefix"
+ - "taglist.tags.Name == 'task_definition-' ~ resource_prefix"
- name: task_definition tags - Add name tag again - see no change
ecs_tag:
@@ -232,7 +232,7 @@
assert:
that:
- taglist.changed == false
- - taglist.tags.Name == "task_definition-{{ resource_prefix }}"
+ - "taglist.tags.Name == 'task_definition-' ~ resource_prefix"
- name: task_definition tags - remove task_definition tags
ecs_tag:
diff --git a/ansible_collections/community/aws/tests/integration/targets/efs/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/efs/tasks/main.yml
index d2e9d4bee..bc23f3a11 100644
--- a/ansible_collections/community/aws/tests/integration/targets/efs/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/efs/tasks/main.yml
@@ -4,9 +4,9 @@
- amazon.aws
module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region }}'
block:
@@ -41,7 +41,7 @@
register: testing_subnet_b
- name: Get default security group id for vpc
- ec2_group_info:
+ ec2_security_group_info:
filters:
vpc-id: "{{ testing_vpc.vpc.id }}"
register: sg_facts
@@ -98,7 +98,7 @@
- efs_result.efs[0].mount_targets[1].security_groups[0] == vpc_default_sg_id
- assert:
- that: "{{efs_result_assertions}}"
+ that: efs_result_assertions
# ============================================================
- name: Get EFS by id
@@ -107,7 +107,7 @@
register: efs_result
- assert:
- that: "{{efs_result_assertions}}"
+ that: efs_result_assertions
# ============================================================
- name: Get EFS by tag
@@ -117,7 +117,7 @@
register: efs_result
- assert:
- that: "{{efs_result_assertions}}"
+ that: efs_result_assertions
# ============================================================
- name: Get EFS by target (subnet_id)
@@ -127,7 +127,7 @@
register: efs_result
- assert:
- that: "{{efs_result_assertions}}"
+ that: efs_result_assertions
# ============================================================
- name: Get EFS by target (security_group_id)
@@ -137,7 +137,7 @@
register: efs_result
- assert:
- that: "{{efs_result_assertions}}"
+ that: efs_result_assertions
# ============================================================
- name: Get EFS by tag and target
@@ -149,7 +149,7 @@
register: efs_result
- assert:
- that: "{{efs_result_assertions}}"
+ that: efs_result_assertions
# ============================================================
# Not checking efs_result.efs["throughput_mode"] here as
@@ -231,7 +231,7 @@
- efs_result.efs[0].file_system_id == created_efs.efs.file_system_id
- assert:
- that: "{{efs_result_assertions}}"
+ that: efs_result_assertions
# ============================================================
- name: Efs configure IA transition
@@ -332,9 +332,9 @@
efs_tag:
state: present
resource: "{{ created_efs.efs.file_system_id }}"
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: "{{ aws_region }}"
tags:
check_mode_tag: 'this tag should not be applied'
@@ -349,9 +349,9 @@
efs_tag:
state: present
resource: "{{ created_efs.efs.file_system_id }}"
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: "{{ aws_region }}"
tags:
"Title Case": 'Hello Cruel World'
@@ -366,7 +366,7 @@
- efs_tag_result.tags.Env is defined
- efs_tag_result.tags.Env is search("IntegrationTests")
- efs_tag_result.tags.Name is defined
- - efs_tag_result.tags.Name is search("{{ efs_name }}-test-tag")
+ - efs_tag_result.tags.Name is search(efs_name ~ '-test-tag')
- efs_tag_result.tags["CamelCase"] == 'SimpleCamelCase'
- efs_tag_result.tags["Title Case"] == 'Hello Cruel World'
- efs_tag_result.tags["lowercase spaced"] == 'hello cruel world'
@@ -377,9 +377,9 @@
efs_tag:
state: present
resource: "{{ created_efs.efs.file_system_id }}"
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: "{{ aws_region }}"
tags:
Env: IntegrationTests
@@ -394,9 +394,9 @@
efs_tag:
state: absent
resource: "{{ created_efs.efs.file_system_id }}"
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: "{{ aws_region }}"
tags:
snake_case: 'simple_snake_case'
@@ -412,9 +412,9 @@
efs_tag:
state: present
resource: "{{ created_efs.efs.file_system_id }}"
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: "{{ aws_region }}"
tags:
Env: OtherIntegrationTests
@@ -430,9 +430,9 @@
efs_tag:
state: present
resource: "{{ created_efs.efs.file_system_id }}"
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: "{{ aws_region }}"
tags:
Env: OtherIntegrationTests
@@ -448,9 +448,9 @@
efs_tag:
state: absent
resource: "{{ created_efs.efs.file_system_id }}"
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: "{{ aws_region }}"
tags:
"Title Case": 'Hello Cruel World'
@@ -464,7 +464,7 @@
- efs_tag_result.tags.Env is defined
- efs_tag_result.tags.Env is search("IntegrationTests")
- efs_tag_result.tags.Name is defined
- - efs_tag_result.tags.Name is search("{{ efs_name }}-test-tag")
+ - efs_tag_result.tags.Name is search(efs_name ~ '-test-tag')
- not efs_tag_result.tags["CamelCase"] is defined
- not efs_tag_result.tags["Title Case"] is defined
- not efs_tag_result.tags["lowercase spaced"] is defined
@@ -474,9 +474,9 @@
efs_tag:
state: absent
resource: "{{ created_efs.efs.file_system_id }}"
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: "{{ aws_region }}"
tags:
snake_case: 'simple_snake_case'
@@ -491,9 +491,9 @@
state: absent
resource: "{{ created_efs.efs.file_system_id }}"
region: "{{ aws_region }}"
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
tags: {}
purge_tags: true
register: efs_tag_result
diff --git a/ansible_collections/community/aws/tests/integration/targets/eks_cluster/tasks/full_test.yml b/ansible_collections/community/aws/tests/integration/targets/eks_cluster/tasks/full_test.yml
index e3aca2863..71cc1fc87 100644
--- a/ansible_collections/community/aws/tests/integration/targets/eks_cluster/tasks/full_test.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/eks_cluster/tasks/full_test.yml
@@ -4,12 +4,12 @@
# If us-west-1 does become supported, change this test to use an unsupported region
# or if all regions are supported, delete this test
- name: attempt to use eks in unsupported region
- aws_eks_cluster:
+ eks_cluster:
name: "{{ eks_cluster_name }}"
state: absent
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
region: us-west-1
register: aws_eks_unsupported_region
ignore_errors: yes
@@ -21,7 +21,7 @@
- '"msg" in aws_eks_unsupported_region'
- name: delete an as yet non-existent EKS cluster
- aws_eks_cluster:
+ eks_cluster:
name: "{{ eks_cluster_name }}"
state: absent
register: aws_eks_delete_non_existent
@@ -64,7 +64,7 @@
- "{{ eks_subnets }}"
- name: create security groups to use for EKS
- ec2_group:
+ ec2_security_group:
name: "{{ item.name }}"
description: "{{ item.description }}"
state: present
@@ -75,7 +75,7 @@
register: setup_security_groups
- name: create EKS cluster
- aws_eks_cluster:
+ eks_cluster:
name: "{{ eks_cluster_name }}"
security_groups: "{{ eks_security_groups | map(attribute='name') }}"
subnets: "{{ setup_subnets.results | map(attribute='subnet.id') }}"
@@ -93,7 +93,7 @@
- eks_create.tags.another == "foobar"
- name: create EKS cluster with same details but wait for it to become active
- aws_eks_cluster:
+ eks_cluster:
name: "{{ eks_cluster_name }}"
security_groups: "{{ eks_security_groups | map(attribute='name') }}"
subnets: "{{ setup_subnets.results | map(attribute='subnet.id') }}"
@@ -113,7 +113,7 @@
- eks_create.endpoint != ""
- name: create EKS cluster with same details but using SG ids
- aws_eks_cluster:
+ eks_cluster:
name: "{{ eks_cluster_name }}"
security_groups: "{{ setup_security_groups.results | map(attribute='group_id') }}"
subnets: "{{ setup_subnets.results | map(attribute='subnet.id') }}"
@@ -127,7 +127,7 @@
- eks_create.name == eks_cluster_name
- name: remove EKS cluster, waiting until complete
- aws_eks_cluster:
+ eks_cluster:
name: "{{ eks_cluster_name }}"
state: absent
wait: yes
@@ -139,7 +139,7 @@
- eks_delete is changed
- name: create EKS cluster with same details but wait for it to become active
- aws_eks_cluster:
+ eks_cluster:
name: "{{ eks_cluster_name }}"
security_groups: "{{ eks_security_groups | map(attribute='name') }}"
subnets: "{{ setup_subnets.results | map(attribute='subnet.id') }}"
@@ -154,7 +154,7 @@
- eks_create.name == eks_cluster_name
- name: remove EKS cluster, without waiting this time
- aws_eks_cluster:
+ eks_cluster:
name: "{{ eks_cluster_name }}"
state: absent
register: eks_delete
@@ -165,7 +165,7 @@
- eks_delete is changed
- name: create EKS cluster with short name
- aws_eks_cluster:
+ eks_cluster:
name: "{{ eks_cluster_short_name }}"
security_groups: "{{ eks_security_groups | map(attribute='name') }}"
subnets: "{{ setup_subnets.results | map(attribute='subnet.id') }}"
@@ -180,7 +180,7 @@
- eks_create is not failed
- name: remove EKS cluster with short name
- aws_eks_cluster:
+ eks_cluster:
name: "{{ eks_cluster_short_name }}"
state: absent
wait: yes
@@ -192,7 +192,7 @@
msg: "***** TESTING COMPLETE. COMMENCE TEARDOWN *****"
- name: remove EKS cluster
- aws_eks_cluster:
+ eks_cluster:
name: "{{ eks_cluster_name }}"
state: absent
wait: yes
@@ -200,7 +200,7 @@
ignore_errors: yes
- name: remove EKS cluster
- aws_eks_cluster:
+ eks_cluster:
name: "{{ eks_cluster_short_name }}"
state: absent
wait: yes
@@ -216,7 +216,7 @@
- name: "{{ eks_cluster_name }}-workers-sg"
- name: set all security group rule lists to empty to remove circular dependency
- ec2_group:
+ ec2_security_group:
name: "{{ item.name }}"
description: "{{ item.description }}"
state: present
@@ -229,7 +229,7 @@
ignore_errors: yes
- name: remove security groups
- ec2_group:
+ ec2_security_group:
name: '{{ item.name }}'
state: absent
vpc_id: '{{ setup_vpc.vpc.id }}'
diff --git a/ansible_collections/community/aws/tests/integration/targets/eks_cluster/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/eks_cluster/tasks/main.yml
index 61aa32cd1..0f414f56f 100644
--- a/ansible_collections/community/aws/tests/integration/targets/eks_cluster/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/eks_cluster/tasks/main.yml
@@ -4,9 +4,9 @@
- amazon.aws
module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region }}'
block:
- include_tasks: full_test.yml
diff --git a/ansible_collections/community/aws/tests/integration/targets/eks_fargate_profile/tasks/cleanup_eks_cluster.yml b/ansible_collections/community/aws/tests/integration/targets/eks_fargate_profile/tasks/cleanup_eks_cluster.yml
index d30761fa3..21adb30a8 100644
--- a/ansible_collections/community/aws/tests/integration/targets/eks_fargate_profile/tasks/cleanup_eks_cluster.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/eks_fargate_profile/tasks/cleanup_eks_cluster.yml
@@ -5,7 +5,7 @@
ignore_errors: true
- name: remove EKS cluster
- aws_eks_cluster:
+ eks_cluster:
name: '{{ eks_cluster_name }}'
state: absent
wait: 'yes'
@@ -17,7 +17,7 @@
- name: '{{ eks_cluster_name }}-workers-sg'
- name: set all security group rule lists to empty to remove circular dependency
- ec2_group:
+ ec2_security_group:
name: '{{ item.name }}'
description: '{{ item.description }}'
state: present
@@ -30,7 +30,7 @@
ignore_errors: 'yes'
- name: remove security groups
- ec2_group:
+ ec2_security_group:
name: '{{ item.name }}'
state: absent
vpc_id: '{{ setup_vpc.vpc.id }}'
diff --git a/ansible_collections/community/aws/tests/integration/targets/eks_fargate_profile/tasks/create_eks_cluster.yml b/ansible_collections/community/aws/tests/integration/targets/eks_fargate_profile/tasks/create_eks_cluster.yml
index d5affa5b5..48fbbef80 100644
--- a/ansible_collections/community/aws/tests/integration/targets/eks_fargate_profile/tasks/create_eks_cluster.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/eks_fargate_profile/tasks/create_eks_cluster.yml
@@ -72,7 +72,7 @@
register: nat_route_table
- name: create security groups to use for EKS
- ec2_group:
+ ec2_security_group:
name: '{{ item.name }}'
description: '{{ item.description }}'
state: present
@@ -83,7 +83,7 @@
register: setup_security_groups
- name: create EKS cluster
- aws_eks_cluster:
+ eks_cluster:
name: '{{ eks_cluster_name }}'
security_groups: '{{ eks_security_groups | map(attribute=''name'') }}'
subnets: '{{ setup_subnets.results | map(attribute=''subnet.id'') }}'
@@ -94,4 +94,4 @@
- name: check that EKS cluster was created
assert:
that:
- - eks_create.name == eks_cluster_name \ No newline at end of file
+ - eks_create.name == eks_cluster_name
diff --git a/ansible_collections/community/aws/tests/integration/targets/eks_fargate_profile/tasks/main.yaml b/ansible_collections/community/aws/tests/integration/targets/eks_fargate_profile/tasks/main.yaml
index 77298dc81..d6606e3db 100644
--- a/ansible_collections/community/aws/tests/integration/targets/eks_fargate_profile/tasks/main.yaml
+++ b/ansible_collections/community/aws/tests/integration/targets/eks_fargate_profile/tasks/main.yaml
@@ -4,9 +4,9 @@
- amazon.aws
module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region }}'
block:
- include_tasks: create_eks_cluster.yml
diff --git a/ansible_collections/community/aws/tests/integration/targets/eks_nodegroup/aliases b/ansible_collections/community/aws/tests/integration/targets/eks_nodegroup/aliases
index 0b84301d7..1809e989b 100644
--- a/ansible_collections/community/aws/tests/integration/targets/eks_nodegroup/aliases
+++ b/ansible_collections/community/aws/tests/integration/targets/eks_nodegroup/aliases
@@ -1 +1,2 @@
-cloud/aws \ No newline at end of file
+cloud/aws
+time=30m
diff --git a/ansible_collections/community/aws/tests/integration/targets/eks_nodegroup/tasks/cleanup.yml b/ansible_collections/community/aws/tests/integration/targets/eks_nodegroup/tasks/cleanup.yml
index ff841f0f5..8bdb5bad4 100644
--- a/ansible_collections/community/aws/tests/integration/targets/eks_nodegroup/tasks/cleanup.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/eks_nodegroup/tasks/cleanup.yml
@@ -5,7 +5,7 @@
ignore_errors: yes
- name: remove EKS cluster
- aws_eks_cluster:
+ eks_cluster:
name: '{{ eks_cluster_name }}'
state: absent
wait: 'yes'
@@ -17,7 +17,7 @@
- name: '{{ eks_cluster_name }}-workers-sg'
- name: set all security group rule lists to empty to remove circular dependency
- ec2_group:
+ ec2_security_group:
name: '{{ item.name }}'
description: '{{ item.description }}'
state: present
@@ -30,7 +30,7 @@
ignore_errors: 'yes'
- name: remove security groups
- ec2_group:
+ ec2_security_group:
name: '{{ item.name }}'
state: absent
vpc_id: '{{ setup_vpc.vpc.id }}'
@@ -74,10 +74,10 @@
state: absent
vpc_id: '{{ setup_vpc.vpc.id}}'
ignore_errors: 'yes'
-
+
- name: remove setup VPC
ec2_vpc_net:
cidr_block: 10.0.0.0/16
state: absent
name: '{{ resource_prefix }}_aws_eks'
- ignore_errors: 'yes' \ No newline at end of file
+ ignore_errors: 'yes'
diff --git a/ansible_collections/community/aws/tests/integration/targets/eks_nodegroup/tasks/dependecies.yml b/ansible_collections/community/aws/tests/integration/targets/eks_nodegroup/tasks/dependecies.yml
index dd6efd27a..882d45dd7 100644
--- a/ansible_collections/community/aws/tests/integration/targets/eks_nodegroup/tasks/dependecies.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/eks_nodegroup/tasks/dependecies.yml
@@ -2,7 +2,7 @@
# This space was a copy by aws_eks_cluster integration test
- name: ensure IAM instance role exists
iam_role:
- name: ansible-test-eks_cluster_role
+ name: ansible-test-{{ tiny_prefix }}-eks_nodegroup-cluster
assume_role_policy_document: '{{ lookup(''file'',''eks-trust-policy.json'') }}'
state: present
create_instance_profile: 'no'
@@ -44,7 +44,7 @@
community.aws.ec2_vpc_route_table:
vpc_id: '{{ setup_vpc.vpc.id }}'
tags:
- Name: EKS
+ Name: "EKS-ng-{{ tiny_prefix }}"
subnets: '{{ setup_subnets.results | map(attribute=''subnet.id'') }}'
routes:
- dest: 0.0.0.0/0
@@ -52,7 +52,7 @@
register: public_route_table
- name: create security groups to use for EKS
- ec2_group:
+ ec2_security_group:
name: '{{ item.name }}'
description: '{{ item.description }}'
state: present
@@ -63,7 +63,7 @@
register: setup_security_groups
- name: create EKS cluster
- aws_eks_cluster:
+ eks_cluster:
name: '{{ eks_cluster_name }}'
security_groups: '{{ eks_security_groups | map(attribute=''name'') }}'
subnets: '{{ setup_subnets.results | map(attribute=''subnet.id'') }}'
@@ -77,9 +77,9 @@
- eks_create.name == eks_cluster_name
# Dependecies to eks nodegroup
-- name: create IAM instance role
+- name: create IAM instance role
iam_role:
- name: 'ansible-test-eks_nodegroup'
+ name: 'ansible-test-{{ tiny_prefix }}-eks_nodegroup-ng'
assume_role_policy_document: '{{ lookup(''file'',''eks-nodegroup-trust-policy.json'') }}'
state: present
create_instance_profile: no
diff --git a/ansible_collections/community/aws/tests/integration/targets/eks_nodegroup/tasks/full_test.yml b/ansible_collections/community/aws/tests/integration/targets/eks_nodegroup/tasks/full_test.yml
index dcb35d2d1..9accc8e8f 100644
--- a/ansible_collections/community/aws/tests/integration/targets/eks_nodegroup/tasks/full_test.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/eks_nodegroup/tasks/full_test.yml
@@ -445,7 +445,6 @@
state: absent
cluster_name: '{{ eks_cluster_name }}'
register: eks_nodegroup_result
- check_mode: True
- name: check that eks_nodegroup is not changed (idempotency)
assert:
@@ -578,9 +577,21 @@
cluster_name: '{{ eks_cluster_name }}'
wait: True
register: eks_nodegroup_result
- check_mode: True
- name: check that eks_nodegroup is not changed (idempotency)
assert:
that:
- - eks_nodegroup_result is not changed \ No newline at end of file
+ - eks_nodegroup_result is not changed
+
+- name: wait for deletion of name_a nodegroup (idempotency)
+ eks_nodegroup:
+ name: '{{ eks_nodegroup_name_a }}'
+ state: absent
+ cluster_name: '{{ eks_cluster_name }}'
+ wait: True
+ register: eks_nodegroup_result
+
+- name: check that eks_nodegroup is not changed (idempotency)
+ assert:
+ that:
+ - eks_nodegroup_result is not changed
diff --git a/ansible_collections/community/aws/tests/integration/targets/eks_nodegroup/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/eks_nodegroup/tasks/main.yml
index 9f896bec6..5c1a76f57 100644
--- a/ansible_collections/community/aws/tests/integration/targets/eks_nodegroup/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/eks_nodegroup/tasks/main.yml
@@ -5,9 +5,9 @@
- amozon.community
module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region }}'
block:
- include_tasks: dependecies.yml
diff --git a/ansible_collections/community/aws/tests/integration/targets/elasticache/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/elasticache/tasks/main.yml
index 31ae3d9cf..9664a70f1 100644
--- a/ansible_collections/community/aws/tests/integration/targets/elasticache/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/elasticache/tasks/main.yml
@@ -3,9 +3,9 @@
- name: Integration testing for the elasticache module
module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region }}'
collections:
- amazon.aws
@@ -60,11 +60,11 @@
that:
- elasticache_redis is changed
- elasticache_redis.elasticache.data is defined
- - elasticache_redis.elasticache.name == "{{ elasticache_redis_test_name }}"
- - elasticache_redis.elasticache.data.CacheSubnetGroupName == "{{ elasticache_subnet_group_name }}"
+ - elasticache_redis.elasticache.name == elasticache_redis_test_name
+ - elasticache_redis.elasticache.data.CacheSubnetGroupName == elasticache_subnet_group_name
- name: Add security group for Redis access in Elasticache
- ec2_group:
+ ec2_security_group:
name: "{{ elasticache_redis_sg_name }}"
description: Allow access to Elasticache Redis for testing EC module
vpc_id: "{{ elasticache_vpc.vpc.id }}"
@@ -186,7 +186,7 @@
state: absent
- name: Make sure Redis Security Group is deleted again
- ec2_group:
+ ec2_security_group:
name: "{{ elasticache_redis_sg_name }}"
state: absent
diff --git a/ansible_collections/community/aws/tests/integration/targets/elasticache_subnet_group/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/elasticache_subnet_group/tasks/main.yml
index 5814f9dc9..921a37eb0 100644
--- a/ansible_collections/community/aws/tests/integration/targets/elasticache_subnet_group/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/elasticache_subnet_group/tasks/main.yml
@@ -8,9 +8,9 @@
#
- module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region }}'
block:
diff --git a/ansible_collections/community/aws/tests/integration/targets/elasticbeanstalk_app/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/elasticbeanstalk_app/tasks/main.yml
index d90a7ce8d..e1deb9df9 100644
--- a/ansible_collections/community/aws/tests/integration/targets/elasticbeanstalk_app/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/elasticbeanstalk_app/tasks/main.yml
@@ -4,15 +4,15 @@
- amazon.aws
module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region }}'
block:
# ============================================================
- name: test with no parameters
- aws_elasticbeanstalk_app:
+ elasticbeanstalk_app:
register: result
ignore_errors: true
@@ -23,7 +23,7 @@
# ============================================================
- name: test create app
- aws_elasticbeanstalk_app:
+ elasticbeanstalk_app:
app_name: "{{ app_name }}"
description: "{{ description }}"
state: present
@@ -36,7 +36,7 @@
# ============================================================
- name: test create when app already exists
- aws_elasticbeanstalk_app:
+ elasticbeanstalk_app:
app_name: "{{ app_name }}"
description: "{{ description }}"
state: present
@@ -49,7 +49,7 @@
# ============================================================
- name: make an update to an existing app
- aws_elasticbeanstalk_app:
+ elasticbeanstalk_app:
app_name: "{{ app_name }}"
description: "{{ alternate_description }}"
state: present
@@ -62,7 +62,7 @@
# # ============================================================
# - name: fail deleting an app that has environments that exist
-# aws_elasticbeanstalk_app:
+# elasticbeanstalk_app:
# app_name: "non_app"
# state: absent
# register: result
@@ -75,7 +75,7 @@
# # ============================================================
# - name: deleting an app that has environments that exist with terminate_by_force True
-# aws_elasticbeanstalk_app:
+# elasticbeanstalk_app:
# app_name: "non_app"
# state: absent
# terminate_by_force: True
@@ -98,7 +98,7 @@
# # ============================================================
# - name: deleting an app that has environments that exist with terminate_by_force True
-# aws_elasticbeanstalk_app:
+# elasticbeanstalk_app:
# app_name: "non_app"
# state: absent
# terminate_by_force: True
@@ -111,7 +111,7 @@
#
# ============================================================
- name: delete non existent app
- aws_elasticbeanstalk_app:
+ elasticbeanstalk_app:
app_name: "non_app"
state: absent
register: result
@@ -125,7 +125,7 @@
# ============================================================
- name: delete existing app
- aws_elasticbeanstalk_app:
+ elasticbeanstalk_app:
app_name: "{{ app_name }}"
state: absent
register: result
@@ -140,6 +140,6 @@
always:
- name: delete existing app
- aws_elasticbeanstalk_app:
+ elasticbeanstalk_app:
app_name: "{{ app_name }}"
state: absent
diff --git a/ansible_collections/community/aws/tests/integration/targets/elb_classic_lb_info/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/elb_classic_lb_info/tasks/main.yml
index e4cd8144b..b09e88072 100644
--- a/ansible_collections/community/aws/tests/integration/targets/elb_classic_lb_info/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/elb_classic_lb_info/tasks/main.yml
@@ -18,10 +18,10 @@
- module_defaults:
group/aws:
- region: "{{ ec2_region }}"
- ec2_access_key: "{{ ec2_access_key }}"
- ec2_secret_key: "{{ ec2_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
+ region: "{{ aws_region }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
block:
# ============================================================
@@ -32,8 +32,8 @@
name: "{{ elb_name }}"
state: present
zones:
- - "{{ ec2_region }}a"
- - "{{ ec2_region }}b"
+ - "{{ aws_region }}a"
+ - "{{ aws_region }}b"
listeners:
- protocol: http
load_balancer_port: 80
@@ -55,8 +55,8 @@
that:
- create is changed
# We rely on these for the info test, make sure they're what we expect
- - '"{{ ec2_region }}a" in create.elb.zones'
- - '"{{ ec2_region }}b" in create.elb.zones'
+ - aws_region ~ 'a' in create.elb.zones
+ - aws_region ~ 'b' in create.elb.zones
- create.elb.health_check.healthy_threshold == 10
- create.elb.health_check.interval == 30
- create.elb.health_check.target == "HTTP:80/index.html"
@@ -74,8 +74,8 @@
that:
- info.elbs|length == 1
- elb.availability_zones|length == 2
- - '"{{ ec2_region }}a" in elb.availability_zones'
- - '"{{ ec2_region }}b" in elb.availability_zones'
+ - aws_region ~ 'a' in elb.availability_zones
+ - aws_region ~ 'b' in elb.availability_zones
- elb.health_check.healthy_threshold == 10
- elb.health_check.interval == 30
- elb.health_check.target == "HTTP:80/index.html"
@@ -115,7 +115,7 @@
name: "{{ elb_name }}"
state: present
zones:
- - "{{ ec2_region }}c"
+ - "{{ aws_region }}c"
listeners:
- protocol: http
load_balancer_port: 80
@@ -134,7 +134,7 @@
- assert:
that:
- update_az is changed
- - update_az.elb.zones[0] == "{{ ec2_region }}c"
+ - update_az.elb.zones[0] == aws_region ~ 'c'
- name: Get ELB info after changing AZ's
elb_classic_lb_info:
@@ -144,7 +144,7 @@
- assert:
that:
- elb.availability_zones|length == 1
- - '"{{ ec2_region }}c" in elb.availability_zones[0]'
+ - aws_region ~ 'c' in elb.availability_zones[0]
vars:
elb: "{{ info.elbs[0] }}"
@@ -157,9 +157,9 @@
name: "{{ elb_name }}"
state: present
zones:
- - "{{ ec2_region }}a"
- - "{{ ec2_region }}b"
- - "{{ ec2_region }}c"
+ - "{{ aws_region }}a"
+ - "{{ aws_region }}b"
+ - "{{ aws_region }}c"
listeners:
- protocol: http
load_balancer_port: 80
@@ -170,9 +170,9 @@
- assert:
that:
- update_az is changed
- - '"{{ ec2_region }}a" in update_az.elb.zones'
- - '"{{ ec2_region }}b" in update_az.elb.zones'
- - '"{{ ec2_region }}c" in update_az.elb.zones'
+ - aws_region ~ 'a' in update_az.elb.zones
+ - aws_region ~ 'b' in update_az.elb.zones
+ - aws_region ~ 'c' in update_az.elb.zones
- name: Get ELB info after updating AZ's
elb_classic_lb_info:
@@ -182,9 +182,9 @@
- assert:
that:
- elb.availability_zones|length == 3
- - '"{{ ec2_region }}a" in elb.availability_zones'
- - '"{{ ec2_region }}b" in elb.availability_zones'
- - '"{{ ec2_region }}c" in elb.availability_zones'
+ - aws_region ~ 'a' in elb.availability_zones
+ - aws_region ~ 'b' in elb.availability_zones
+ - aws_region ~ 'c' in elb.availability_zones
vars:
elb: "{{ info.elbs[0] }}"
@@ -197,9 +197,9 @@
name: "{{ elb_name }}"
state: present
zones:
- - "{{ ec2_region }}a"
- - "{{ ec2_region }}b"
- - "{{ ec2_region }}c"
+ - "{{ aws_region }}a"
+ - "{{ aws_region }}b"
+ - "{{ aws_region }}c"
listeners:
- protocol: http
load_balancer_port: 80
@@ -235,9 +235,9 @@
name: "{{ elb_name }}"
state: present
zones:
- - "{{ ec2_region }}a"
- - "{{ ec2_region }}b"
- - "{{ ec2_region }}c"
+ - "{{ aws_region }}a"
+ - "{{ aws_region }}b"
+ - "{{ aws_region }}c"
listeners:
- protocol: http
load_balancer_port: 8081
diff --git a/ansible_collections/community/aws/tests/integration/targets/elb_instance/tasks/cleanup_instances.yml b/ansible_collections/community/aws/tests/integration/targets/elb_instance/tasks/cleanup_instances.yml
index 7ae91ac00..262bc99b2 100644
--- a/ansible_collections/community/aws/tests/integration/targets/elb_instance/tasks/cleanup_instances.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/elb_instance/tasks/cleanup_instances.yml
@@ -9,14 +9,14 @@
ignore_errors: true
- name: Delete ASG
- ec2_asg:
+ autoscaling_group:
name: '{{ asg_name }}'
state: absent
ignore_errors: true
register: ec2_asg_a
- name: Delete Launch Template
- ec2_lc:
+ autoscaling_launch_config:
name: '{{ lc_name }}'
state: absent
ignore_errors: true
diff --git a/ansible_collections/community/aws/tests/integration/targets/elb_instance/tasks/cleanup_vpc.yml b/ansible_collections/community/aws/tests/integration/targets/elb_instance/tasks/cleanup_vpc.yml
index 9abeb74a2..754b685f6 100644
--- a/ansible_collections/community/aws/tests/integration/targets/elb_instance/tasks/cleanup_vpc.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/elb_instance/tasks/cleanup_vpc.yml
@@ -1,6 +1,6 @@
---
- name: delete security groups
- ec2_group:
+ ec2_security_group:
name: '{{ item }}'
state: absent
ignore_errors: true
diff --git a/ansible_collections/community/aws/tests/integration/targets/elb_instance/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/elb_instance/tasks/main.yml
index 247b6f6b6..3ab9be64d 100644
--- a/ansible_collections/community/aws/tests/integration/targets/elb_instance/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/elb_instance/tasks/main.yml
@@ -2,9 +2,9 @@
- module_defaults:
group/aws:
region: "{{ aws_region }}"
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
collections:
- community.aws
- amazon.aws
diff --git a/ansible_collections/community/aws/tests/integration/targets/elb_instance/tasks/manage_asgs.yml b/ansible_collections/community/aws/tests/integration/targets/elb_instance/tasks/manage_asgs.yml
index f0e9db601..ea726b8fe 100644
--- a/ansible_collections/community/aws/tests/integration/targets/elb_instance/tasks/manage_asgs.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/elb_instance/tasks/manage_asgs.yml
@@ -1,6 +1,6 @@
---
- name: Get ASG info
- ec2_asg_info:
+ autoscaling_group_info:
name: "{{ asg_name }}$"
register: asg_info
diff --git a/ansible_collections/community/aws/tests/integration/targets/elb_instance/tasks/setup_instances.yml b/ansible_collections/community/aws/tests/integration/targets/elb_instance/tasks/setup_instances.yml
index b89b38d20..455a9886b 100644
--- a/ansible_collections/community/aws/tests/integration/targets/elb_instance/tasks/setup_instances.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/elb_instance/tasks/setup_instances.yml
@@ -25,7 +25,7 @@
instance_b: "{{ ec2_instance_b.instance_ids[0] }}"
- name: Create a Launch Template
- ec2_lc:
+ autoscaling_launch_config:
name: "{{ lc_name }}"
image_id: "{{ ec2_ami_id }}"
security_groups: "{{ sg_a }}"
@@ -34,7 +34,7 @@
register: ec2_lc_a
- name: Create an ASG
- ec2_asg:
+ autoscaling_group:
name: "{{ asg_name }}"
load_balancers:
- "{{ elb_name_1 }}"
diff --git a/ansible_collections/community/aws/tests/integration/targets/elb_instance/tasks/setup_vpc.yml b/ansible_collections/community/aws/tests/integration/targets/elb_instance/tasks/setup_vpc.yml
index 26fafa41c..60c85b8eb 100644
--- a/ansible_collections/community/aws/tests/integration/targets/elb_instance/tasks/setup_vpc.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/elb_instance/tasks/setup_vpc.yml
@@ -32,7 +32,7 @@
register: setup_subnet_2
- name: create a security group
- ec2_group:
+ ec2_security_group:
name: '{{ sg_name_1 }}'
description: 'created by Ansible integration tests'
state: present
@@ -45,7 +45,7 @@
register: setup_sg_1
- name: create a security group
- ec2_group:
+ ec2_security_group:
name: '{{ sg_name_2 }}'
description: 'created by Ansible integration tests'
state: present
diff --git a/ansible_collections/community/aws/tests/integration/targets/elb_network_lb/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/elb_network_lb/tasks/main.yml
index cf0a13ec4..e277fffd7 100644
--- a/ansible_collections/community/aws/tests/integration/targets/elb_network_lb/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/elb_network_lb/tasks/main.yml
@@ -4,9 +4,9 @@
- amazon.aws
module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region }}'
block:
@@ -89,7 +89,7 @@
gateway_id: "{{ igw.gateway_id }}"
register: route_table
- - ec2_group:
+ - ec2_security_group:
name: "{{ resource_prefix }}"
description: "security group for Ansible NLB integration tests"
state: present
@@ -173,7 +173,7 @@
ignore_errors: yes
- name: destroy sec group
- ec2_group:
+ ec2_security_group:
name: "{{ sec_group.group_name }}"
description: "security group for Ansible NLB integration tests"
state: absent
diff --git a/ansible_collections/community/aws/tests/integration/targets/elb_network_lb/tasks/test_nlb_tags.yml b/ansible_collections/community/aws/tests/integration/targets/elb_network_lb/tasks/test_nlb_tags.yml
index b55a0777f..f1e920de8 100644
--- a/ansible_collections/community/aws/tests/integration/targets/elb_network_lb/tasks/test_nlb_tags.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/elb_network_lb/tasks/test_nlb_tags.yml
@@ -34,7 +34,7 @@
- assert:
that:
- nlb.changed
- - 'nlb.tags.created_by == "NLB test {{ resource_prefix }}"'
+ - nlb.tags.created_by == 'NLB test ' ~ resource_prefix
- name: test tags are not removed if unspecified
elb_network_lb:
@@ -46,7 +46,7 @@
- assert:
that:
- not nlb.changed
- - 'nlb.tags.created_by == "NLB test {{ resource_prefix }}"'
+ - nlb.tags.created_by == 'NLB test ' ~ resource_prefix
- name: remove tags from NLB
elb_network_lb:
diff --git a/ansible_collections/community/aws/tests/integration/targets/elb_network_lb/tasks/test_nlb_with_asg.yml b/ansible_collections/community/aws/tests/integration/targets/elb_network_lb/tasks/test_nlb_with_asg.yml
index 06fab22b5..295e5e469 100644
--- a/ansible_collections/community/aws/tests/integration/targets/elb_network_lb/tasks/test_nlb_with_asg.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/elb_network_lb/tasks/test_nlb_with_asg.yml
@@ -1,17 +1,17 @@
- block:
# create instances
- - ec2_asg:
+ - autoscaling_group:
state: absent
name: "{{ resource_prefix }}-webservers"
wait_timeout: 900
- - ec2_lc:
+ - autoscaling_launch_config:
name: "{{ resource_prefix }}-web-lcfg"
state: absent
- name: Create launch config for testing
- ec2_lc:
+ autoscaling_launch_config:
name: "{{ resource_prefix }}-web-lcfg"
assign_public_ip: true
image_id: "{{ ec2_ami_id }}"
@@ -31,7 +31,7 @@
delete_on_termination: true
- name: Create autoscaling group for app server fleet
- ec2_asg:
+ autoscaling_group:
name: "{{ resource_prefix }}-webservers"
vpc_zone_identifier: "{{ nlb_subnets }}"
launch_config_name: "{{ resource_prefix }}-web-lcfg"
@@ -50,13 +50,13 @@
always:
- - ec2_asg:
+ - autoscaling_group:
state: absent
name: "{{ resource_prefix }}-webservers"
wait_timeout: 900
ignore_errors: yes
- - ec2_lc:
+ - autoscaling_launch_config:
name: "{{ resource_prefix }}-web-lcfg"
state: absent
ignore_errors: yes
diff --git a/ansible_collections/community/aws/tests/integration/targets/elb_target/files/ansible_lambda_target.py b/ansible_collections/community/aws/tests/integration/targets/elb_target/files/ansible_lambda_target.py
index 3ea22472e..d652d6097 100644
--- a/ansible_collections/community/aws/tests/integration/targets/elb_target/files/ansible_lambda_target.py
+++ b/ansible_collections/community/aws/tests/integration/targets/elb_target/files/ansible_lambda_target.py
@@ -1,10 +1,10 @@
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
__metaclass__ = type
import json
def lambda_handler(event, context):
- return {
- 'statusCode': 200,
- 'body': json.dumps('Hello from Lambda!')
- }
+ return {"statusCode": 200, "body": json.dumps("Hello from Lambda!")}
diff --git a/ansible_collections/community/aws/tests/integration/targets/elb_target/tasks/alb_target.yml b/ansible_collections/community/aws/tests/integration/targets/elb_target/tasks/alb_target.yml
index d3638a63c..446b59031 100644
--- a/ansible_collections/community/aws/tests/integration/targets/elb_target/tasks/alb_target.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/elb_target/tasks/alb_target.yml
@@ -51,7 +51,7 @@
register: route_table
- name: create testing security group
- ec2_group:
+ ec2_security_group:
name: "{{ resource_prefix }}-sg"
description: a security group for ansible tests
vpc_id: "{{ vpc.vpc.id }}"
@@ -177,7 +177,7 @@
ignore_errors: true
- name: remove testing security group
- ec2_group:
+ ec2_security_group:
state: absent
name: "{{ resource_prefix }}-sg"
register: removed
diff --git a/ansible_collections/community/aws/tests/integration/targets/elb_target/tasks/ec2_target.yml b/ansible_collections/community/aws/tests/integration/targets/elb_target/tasks/ec2_target.yml
index 611aca26f..20931f1d7 100644
--- a/ansible_collections/community/aws/tests/integration/targets/elb_target/tasks/ec2_target.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/elb_target/tasks/ec2_target.yml
@@ -58,7 +58,7 @@
register: route_table
- name: create testing security group
- ec2_group:
+ ec2_security_group:
name: "{{ resource_prefix }}-sg"
description: a security group for ansible tests
vpc_id: "{{ vpc.vpc.id }}"
@@ -147,7 +147,7 @@
- result.health_check_protocol == 'TCP'
- '"tags" in result'
- '"target_group_arn" in result'
- - result.target_group_name == "{{ tg_name }}-nlb"
+ - result.target_group_name == tg_name ~ '-nlb'
- result.target_type == 'instance'
- result.deregistration_delay_timeout_seconds == '60'
- result.deregistration_delay_connection_termination_enabled
@@ -214,7 +214,7 @@
- '"load_balancer_arn" in result'
- '"tags" in result'
- result.type == 'network'
- - result.vpc_id == '{{ vpc.vpc.id }}'
+ - result.vpc_id == vpc.vpc.id
- name: modify up testing target group for NLB (preserve_client_ip_enabled=false)
elb_target_group:
@@ -603,7 +603,7 @@
ignore_errors: true
- name: remove testing security group
- ec2_group:
+ ec2_security_group:
state: absent
name: "{{ resource_prefix }}-sg"
register: removed
diff --git a/ansible_collections/community/aws/tests/integration/targets/elb_target/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/elb_target/tasks/main.yml
index e99118c64..8f03edfa8 100644
--- a/ansible_collections/community/aws/tests/integration/targets/elb_target/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/elb_target/tasks/main.yml
@@ -2,9 +2,9 @@
- name: set up elb_target test prerequisites
module_defaults:
group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"
collections:
- community.general
diff --git a/ansible_collections/community/aws/tests/integration/targets/elb_target_info/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/elb_target_info/tasks/main.yml
index fc11cdbcd..fadce2135 100644
--- a/ansible_collections/community/aws/tests/integration/targets/elb_target_info/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/elb_target_info/tasks/main.yml
@@ -2,9 +2,9 @@
- name: set up elb_target_info test prerequisites
module_defaults:
group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"
collections:
- amazon.aws
@@ -66,7 +66,7 @@
register: route_table
- name: create testing security group
- ec2_group:
+ ec2_security_group:
name: "{{ resource_prefix }}-sg"
description: a security group for ansible tests
vpc_id: "{{ vpc.vpc.id }}"
@@ -207,9 +207,9 @@
- assert:
that:
- - "{{ alb_target_group.target_group_arn in (target_facts.instance_target_groups | map(attribute='target_group_arn')) }}"
- - "{{ nlb_target_group.target_group_arn in (target_facts.instance_target_groups | map(attribute='target_group_arn')) }}"
- - "{{ idle_target_group.target_group_arn not in (target_facts.instance_target_groups | map(attribute='target_group_arn')) }}"
+ - "alb_target_group.target_group_arn in (target_facts.instance_target_groups | map(attribute='target_group_arn'))"
+ - "nlb_target_group.target_group_arn in (target_facts.instance_target_groups | map(attribute='target_group_arn'))"
+ - "idle_target_group.target_group_arn not in (target_facts.instance_target_groups | map(attribute='target_group_arn'))"
- (target_facts.instance_target_groups | length) == 2
msg: "target facts showed the target in the right target groups"
@@ -228,9 +228,9 @@
- assert:
that:
- - "{{ alb_target_group.target_group_arn in (target_facts.instance_target_groups | map(attribute='target_group_arn')) }}"
- - "{{ nlb_target_group.target_group_arn in (target_facts.instance_target_groups | map(attribute='target_group_arn')) }}"
- - "{{ idle_target_group.target_group_arn in (target_facts.instance_target_groups | map(attribute='target_group_arn')) }}"
+ - "alb_target_group.target_group_arn in (target_facts.instance_target_groups | map(attribute='target_group_arn'))"
+ - "nlb_target_group.target_group_arn in (target_facts.instance_target_groups | map(attribute='target_group_arn'))"
+ - "idle_target_group.target_group_arn in (target_facts.instance_target_groups | map(attribute='target_group_arn'))"
- (target_facts.instance_target_groups | length) == 3
msg: "target facts reflected the addition of the target to the idle group"
@@ -242,9 +242,9 @@
- assert:
that:
- - "{{ alb_target_group.target_group_arn in (target_facts.instance_target_groups | map(attribute='target_group_arn')) }}"
- - "{{ nlb_target_group.target_group_arn in (target_facts.instance_target_groups | map(attribute='target_group_arn')) }}"
- - "{{ idle_target_group.target_group_arn not in (target_facts.instance_target_groups | map(attribute='target_group_arn')) }}"
+ - "alb_target_group.target_group_arn in (target_facts.instance_target_groups | map(attribute='target_group_arn'))"
+ - "nlb_target_group.target_group_arn in (target_facts.instance_target_groups | map(attribute='target_group_arn'))"
+ - "idle_target_group.target_group_arn not in (target_facts.instance_target_groups | map(attribute='target_group_arn'))"
- (target_facts.instance_target_groups | length) == 2
msg: "target_facts.instance_target_groups did not gather unused target groups when variable was set"
@@ -407,7 +407,7 @@
ignore_errors: true
- name: remove testing security group
- ec2_group:
+ ec2_security_group:
state: absent
name: "{{ resource_prefix }}-sg"
description: a security group for ansible tests
diff --git a/ansible_collections/community/aws/tests/integration/targets/glue_connection/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/glue_connection/tasks/main.yml
index 837f9bd17..c11b297af 100644
--- a/ansible_collections/community/aws/tests/integration/targets/glue_connection/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/glue_connection/tasks/main.yml
@@ -4,9 +4,9 @@
- amazon.aws
module_defaults:
group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"
block:
- include_tasks: test_connection_network.yml
diff --git a/ansible_collections/community/aws/tests/integration/targets/glue_connection/tasks/test_connection_jdbc.yml b/ansible_collections/community/aws/tests/integration/targets/glue_connection/tasks/test_connection_jdbc.yml
index 966d8156f..a3b052ba9 100644
--- a/ansible_collections/community/aws/tests/integration/targets/glue_connection/tasks/test_connection_jdbc.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/glue_connection/tasks/test_connection_jdbc.yml
@@ -5,7 +5,7 @@
# TODO: description, match_criteria, security_groups, and subnet_id are unused module options
- name: create glue connection
- aws_glue_connection:
+ glue_connection:
name: "{{ resource_prefix }}"
connection_properties:
JDBC_CONNECTION_URL: "jdbc:mysql://mydb:3306/{{ resource_prefix }}"
@@ -19,7 +19,7 @@
- result.changed
- name: test idempotence creating glue connection
- aws_glue_connection:
+ glue_connection:
name: "{{ resource_prefix }}"
connection_properties:
JDBC_CONNECTION_URL: "jdbc:mysql://mydb:3306/{{ resource_prefix }}"
@@ -33,7 +33,7 @@
- not result.changed
- name: test updating JDBC connection url
- aws_glue_connection:
+ glue_connection:
name: "{{ resource_prefix }}"
connection_properties:
JDBC_CONNECTION_URL: "jdbc:mysql://mydb:3306/{{ resource_prefix }}-updated"
@@ -47,7 +47,7 @@
- result.changed
- name: delete glue connection
- aws_glue_connection:
+ glue_connection:
name: "{{ resource_prefix }}"
state: absent
register: result
@@ -57,7 +57,7 @@
- result.changed
- name: test idempotence removing glue connection
- aws_glue_connection:
+ glue_connection:
name: "{{ resource_prefix }}"
state: absent
register: result
@@ -69,6 +69,6 @@
always:
- name: delete glue connection
- aws_glue_connection:
+ glue_connection:
name: "{{ resource_prefix }}"
state: absent
diff --git a/ansible_collections/community/aws/tests/integration/targets/glue_connection/tasks/test_connection_network.yml b/ansible_collections/community/aws/tests/integration/targets/glue_connection/tasks/test_connection_network.yml
index 230015585..bc7d5cb4c 100644
--- a/ansible_collections/community/aws/tests/integration/targets/glue_connection/tasks/test_connection_network.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/glue_connection/tasks/test_connection_network.yml
@@ -26,7 +26,7 @@
register: glue_subnet_a
- name: Create security group 1
- ec2_group:
+ ec2_security_group:
name: "{{ resource_prefix }}-sg-glue-1"
description: A security group for Ansible tests
vpc_id: "{{ glue_vpc.vpc.id }}"
@@ -37,7 +37,7 @@
rule_desc: Connections from Glue
- name: Create security group 2
- ec2_group:
+ ec2_security_group:
name: "{{ resource_prefix }}-sg-glue-2"
description: A security group for Ansible tests
vpc_id: "{{ glue_vpc.vpc.id }}"
@@ -48,7 +48,7 @@
rule_desc: Connections from Glue
- name: Create Glue connection (check mode)
- aws_glue_connection:
+ glue_connection:
name: "{{ resource_prefix }}"
availability_zone: "{{ aws_region }}a"
connection_properties:
@@ -69,7 +69,7 @@
- glue_connection_check.description is not defined
- name: Create Glue connection
- aws_glue_connection:
+ glue_connection:
name: "{{ resource_prefix }}"
availability_zone: "{{ aws_region }}a"
connection_properties:
@@ -109,7 +109,7 @@
- glue_connection.raw_connection_properties == connection_info["Connection"]["ConnectionProperties"]
- name: Create Glue connection (idempotent) (check mode)
- aws_glue_connection:
+ glue_connection:
name: "{{ resource_prefix }}"
availability_zone: "{{ aws_region }}a"
connection_properties:
@@ -149,7 +149,7 @@
- connection_info_idempotent_check["Connection"]["PhysicalConnectionRequirements"]["AvailabilityZone"] == connection_info["Connection"]["PhysicalConnectionRequirements"]["AvailabilityZone"]
- name: Create Glue connection (idempotent)
- aws_glue_connection:
+ glue_connection:
name: "{{ resource_prefix }}"
availability_zone: "{{ aws_region }}a"
connection_properties:
@@ -188,7 +188,7 @@
- connection_info_idempotent["Connection"]["PhysicalConnectionRequirements"]["AvailabilityZone"] == connection_info["Connection"]["PhysicalConnectionRequirements"]["AvailabilityZone"]
- name: Update Glue connection (check mode)
- aws_glue_connection:
+ glue_connection:
name: "{{ resource_prefix }}"
availability_zone: "{{ aws_region }}a"
connection_properties:
@@ -229,7 +229,7 @@
- glue_connection_update_check.raw_connection_properties == connection_info_update_check["Connection"]["ConnectionProperties"]
- name: Update Glue connection
- aws_glue_connection:
+ glue_connection:
name: "{{ resource_prefix }}"
availability_zone: "{{ aws_region }}a"
connection_properties:
@@ -269,7 +269,7 @@
- glue_connection_update.raw_connection_properties == connection_info_update["Connection"]["ConnectionProperties"]
- name: Delete Glue connection (check mode)
- aws_glue_connection:
+ glue_connection:
name: "{{ resource_prefix }}"
state: absent
check_mode: true
@@ -295,7 +295,7 @@
- connection_info["Connection"]["Name"] == connection_info_delete_check["Connection"]["Name"]
- name: Delete Glue connection
- aws_glue_connection:
+ glue_connection:
name: "{{ resource_prefix }}"
state: absent
register: glue_connection_delete
@@ -307,17 +307,17 @@
always:
- name: Delete Glue connection
- aws_glue_connection:
+ glue_connection:
name: "{{ resource_prefix }}"
state: absent
ignore_errors: true
- name: Delete security group 1
- ec2_group:
+ ec2_security_group:
name: "{{ resource_prefix }}-sg-glue-1"
state: absent
ignore_errors: true
- name: Delete security group 2
- ec2_group:
+ ec2_security_group:
name: "{{ resource_prefix }}-sg-glue-2"
state: absent
ignore_errors: true
diff --git a/ansible_collections/community/aws/tests/integration/targets/glue_crawler/aliases b/ansible_collections/community/aws/tests/integration/targets/glue_crawler/aliases
index 4ef4b2067..21fa9fd98 100644
--- a/ansible_collections/community/aws/tests/integration/targets/glue_crawler/aliases
+++ b/ansible_collections/community/aws/tests/integration/targets/glue_crawler/aliases
@@ -1 +1,4 @@
cloud/aws
+
+disabled
+# https://github.com/ansible-collections/community.aws/issues/1796
diff --git a/ansible_collections/community/aws/tests/integration/targets/glue_crawler/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/glue_crawler/tasks/main.yml
index b96968195..82ff4addf 100644
--- a/ansible_collections/community/aws/tests/integration/targets/glue_crawler/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/glue_crawler/tasks/main.yml
@@ -4,9 +4,9 @@
- amazon.aws
module_defaults:
group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"
block:
@@ -29,7 +29,7 @@
seconds: 10
- name: Create Glue crawler (check mode)
- aws_glue_crawler:
+ glue_crawler:
name: "{{ glue_crawler_name }}"
database_name: my_database
description: "{{ glue_crawler_description }}"
@@ -56,7 +56,7 @@
- glue_crawler_check.description is not defined
- name: Create Glue crawler
- aws_glue_crawler:
+ glue_crawler:
name: "{{ glue_crawler_name }}"
database_name: my_database
description: "{{ glue_crawler_description }}"
@@ -102,7 +102,7 @@
- glue_crawler.targets.S3Targets == crawler_info["Crawler"]["Targets"]["S3Targets"]
- name: Create Glue crawler (idempotent) (check mode)
- aws_glue_crawler:
+ glue_crawler:
name: "{{ glue_crawler_name }}"
database_name: my_database
description: "{{ glue_crawler_description }}"
@@ -149,7 +149,7 @@
- crawler_info["Crawler"]["Targets"]["S3Targets"] == crawler_info_idempotent_check["Crawler"]["Targets"]["S3Targets"]
- name: Create Glue crawler (idempotent)
- aws_glue_crawler:
+ glue_crawler:
name: "{{ glue_crawler_name }}"
database_name: my_database
description: "{{ glue_crawler_description }}"
@@ -195,7 +195,7 @@
- crawler_info["Crawler"]["Targets"]["S3Targets"] == crawler_info_idempotent["Crawler"]["Targets"]["S3Targets"]
- name: Update Glue crawler (check mode)
- aws_glue_crawler:
+ glue_crawler:
name: "{{ glue_crawler_name }}"
database_name: my_database_2
description: "{{ glue_crawler_description }}"
@@ -242,7 +242,7 @@
- glue_crawler_update_check.targets.S3Targets == crawler_info_update_check["Crawler"]["Targets"]["S3Targets"]
- name: Update Glue crawler
- aws_glue_crawler:
+ glue_crawler:
name: "{{ glue_crawler_name }}"
database_name: my_database_2
description: "{{ glue_crawler_description }}"
@@ -288,7 +288,7 @@
- glue_crawler_update.targets.S3Targets == crawler_info_update["Crawler"]["Targets"]["S3Targets"]
- name: Delete Glue crawler (check mode)
- aws_glue_crawler:
+ glue_crawler:
name: "{{ glue_crawler_name }}"
state: absent
check_mode: true
@@ -315,7 +315,7 @@
- crawler_info["Crawler"]["Name"] == crawler_info_delete_check["Crawler"]["Name"]
- name: Delete Glue crawler
- aws_glue_crawler:
+ glue_crawler:
name: "{{ glue_crawler_name }}"
state: absent
register: glue_crawler_delete
@@ -327,7 +327,7 @@
always:
- name: Delete Glue crawler
- aws_glue_crawler:
+ glue_crawler:
name: "{{ glue_crawler_name }}"
state: absent
ignore_errors: true
diff --git a/ansible_collections/community/aws/tests/integration/targets/glue_job/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/glue_job/tasks/main.yml
index 307a9befb..85080fd02 100644
--- a/ansible_collections/community/aws/tests/integration/targets/glue_job/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/glue_job/tasks/main.yml
@@ -4,9 +4,9 @@
- amazon.aws
module_defaults:
group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"
block:
# AWS CLI is needed until there's a module to get info about Glue jobs
@@ -30,7 +30,7 @@
- "arn:aws:iam::aws:policy/AWSXrayWriteOnlyAccess"
- name: Create Glue job (check mode)
- aws_glue_job:
+ glue_job:
name: "{{ glue_job_name }}"
command_python_version: 3
command_script_location: "{{ glue_job_command_script_location }}"
@@ -53,7 +53,7 @@
- glue_job_check.description is not defined
- name: Create Glue job
- aws_glue_job:
+ glue_job:
name: "{{ glue_job_name }}"
command_python_version: 3
command_script_location: "{{ glue_job_command_script_location }}"
@@ -93,7 +93,7 @@
- glue_job.role == job_info["Job"]["Role"]
- name: Create Glue job (idempotent) (check mode)
- aws_glue_job:
+ glue_job:
name: "{{ glue_job_name }}"
command_python_version: 3
command_script_location: "{{ glue_job_command_script_location }}"
@@ -135,7 +135,7 @@
- job_info["Job"]["Role"] == job_info_idempotent_check["Job"]["Role"]
- name: Create Glue job (idempotent)
- aws_glue_job:
+ glue_job:
name: "{{ glue_job_name }}"
command_python_version: 3
command_script_location: "{{ glue_job_command_script_location }}"
@@ -176,7 +176,7 @@
- job_info["Job"]["Role"] == job_info_idempotent["Job"]["Role"]
- name: Update Glue job (check mode)
- aws_glue_job:
+ glue_job:
name: "{{ glue_job_name }}"
command_python_version: 2
command_script_location: "{{ glue_job_command_script_location }}"
@@ -216,7 +216,7 @@
- glue_job_update_check.role == job_info_update_check["Job"]["Role"]
- name: Update Glue job
- aws_glue_job:
+ glue_job:
name: "{{ glue_job_name }}"
command_python_version: 2
command_script_location: "{{ glue_job_command_script_location }}"
@@ -255,7 +255,7 @@
- glue_job_update.role == job_info_update["Job"]["Role"]
- name: Delete Glue job (check mode)
- aws_glue_job:
+ glue_job:
name: "{{ glue_job_name }}"
state: absent
check_mode: true
@@ -281,7 +281,7 @@
- job_info["Job"]["Name"] == job_info_delete_check["Job"]["Name"]
- name: Delete Glue job
- aws_glue_job:
+ glue_job:
name: "{{ glue_job_name }}"
state: absent
register: glue_job_delete
@@ -293,7 +293,7 @@
always:
- name: Delete Glue job
- aws_glue_job:
+ glue_job:
name: "{{ glue_job_name }}"
state: absent
ignore_errors: true
diff --git a/ansible_collections/community/aws/tests/integration/targets/iam_access_key/aliases b/ansible_collections/community/aws/tests/integration/targets/iam_access_key/aliases
deleted file mode 100644
index ffceccfcc..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/iam_access_key/aliases
+++ /dev/null
@@ -1,9 +0,0 @@
-# reason: missing-policy
-# It should be possible to test iam_user by limiting which policies can be
-# attached to the users.
-# Careful review is needed prior to adding this to the main CI.
-unsupported
-
-cloud/aws
-
-iam_access_key_info
diff --git a/ansible_collections/community/aws/tests/integration/targets/iam_access_key/defaults/main.yml b/ansible_collections/community/aws/tests/integration/targets/iam_access_key/defaults/main.yml
deleted file mode 100644
index eaaa3523e..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/iam_access_key/defaults/main.yml
+++ /dev/null
@@ -1,2 +0,0 @@
----
-test_user: '{{ resource_prefix }}'
diff --git a/ansible_collections/community/aws/tests/integration/targets/iam_access_key/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/iam_access_key/tasks/main.yml
deleted file mode 100644
index a7fcc633c..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/iam_access_key/tasks/main.yml
+++ /dev/null
@@ -1,808 +0,0 @@
----
-- name: AWS AuthN details
- module_defaults:
- group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
- region: "{{ aws_region }}"
- collections:
- - amazon.aws
- - community.aws
- block:
- # ==================================================================================
- # Preparation
- # ==================================================================================
- # We create an IAM user with no attached permissions. The *only* thing the
- # user will be able to do is call sts.get_caller_identity
- # https://docs.aws.amazon.com/STS/latest/APIReference/API_GetCallerIdentity.html
- - name: Create test user
- iam_user:
- name: '{{ test_user }}'
- state: present
- register: iam_user
-
- - assert:
- that:
- - iam_user is successful
- - iam_user is changed
-
- # ==================================================================================
-
- - name: Fetch IAM key info (no keys)
- iam_access_key_info:
- user_name: '{{ test_user }}'
- register: access_key_info
-
- - assert:
- that:
- - access_key_info is successful
- - '"access_keys" in access_key_info'
- - access_key_info.access_keys | length == 0
-
- # ==================================================================================
-
- - name: Create a key (check_mode)
- iam_access_key:
- user_name: '{{ test_user }}'
- state: present
- register: create_key_1
- check_mode: true
-
- - assert:
- that:
- - create_key_1 is successful
- - create_key_1 is changed
-
- - name: Create a key
- iam_access_key:
- user_name: '{{ test_user }}'
- state: present
- register: create_key_1
-
- - assert:
- that:
- - create_key_1 is successful
- - create_key_1 is changed
- - '"access_key" in create_key_1'
- - '"secret_access_key" in create_key_1'
- - '"deleted_access_key_id" not in create_key_1'
- - '"access_key_id" in create_key_1.access_key'
- - '"create_date" in create_key_1.access_key'
- - '"user_name" in create_key_1.access_key'
- - '"status" in create_key_1.access_key'
- - create_key_1.access_key.user_name == test_user
- - create_key_1.access_key.status == 'Active'
-
- - name: Fetch IAM key info (1 key)
- iam_access_key_info:
- user_name: '{{ test_user }}'
- register: access_key_info
-
- - assert:
- that:
- - access_key_info is successful
- - '"access_keys" in access_key_info'
- - access_key_info.access_keys | length == 1
- - '"access_key_id" in access_key_1'
- - '"create_date" in access_key_1'
- - '"user_name" in access_key_1'
- - '"status" in access_key_1'
- - access_key_1.user_name == test_user
- - access_key_1.access_key_id == create_key_1.access_key.access_key_id
- - access_key_1.create_date == create_key_1.access_key.create_date
- - access_key_1.status == 'Active'
- vars:
- access_key_1: '{{ access_key_info.access_keys[0] }}'
-
- # ==================================================================================
-
- - name: Create a second key (check_mode)
- iam_access_key:
- user_name: '{{ test_user }}'
- state: present
- register: create_key_2
- check_mode: true
-
- - assert:
- that:
- - create_key_2 is successful
- - create_key_2 is changed
-
- - name: Create a second key
- iam_access_key:
- user_name: '{{ test_user }}'
- state: present
- register: create_key_2
-
- - assert:
- that:
- - create_key_2 is successful
- - create_key_2 is changed
- - '"access_key" in create_key_2'
- - '"secret_access_key" in create_key_2'
- - '"deleted_access_key_id" not in create_key_2'
- - '"access_key_id" in create_key_2.access_key'
- - '"create_date" in create_key_2.access_key'
- - '"user_name" in create_key_2.access_key'
- - '"status" in create_key_2.access_key'
- - create_key_2.access_key.user_name == test_user
- - create_key_2.access_key.status == 'Active'
-
- - name: Fetch IAM key info (2 keys)
- iam_access_key_info:
- user_name: '{{ test_user }}'
- register: access_key_info
-
- - assert:
- that:
- - access_key_info is successful
- - '"access_keys" in access_key_info'
- - access_key_info.access_keys | length == 2
- - '"access_key_id" in access_key_1'
- - '"create_date" in access_key_1'
- - '"user_name" in access_key_1'
- - '"status" in access_key_1'
- - access_key_1.user_name == test_user
- - access_key_1.access_key_id == create_key_1.access_key.access_key_id
- - access_key_1.create_date == create_key_1.access_key.create_date
- - access_key_1.status == 'Active'
- - '"access_key_id" in access_key_2'
- - '"create_date" in access_key_2'
- - '"user_name" in access_key_2'
- - '"status" in access_key_2'
- - access_key_2.user_name == test_user
- - access_key_2.access_key_id == create_key_2.access_key.access_key_id
- - access_key_2.create_date == create_key_2.access_key.create_date
- - access_key_2.status == 'Active'
- vars:
- access_key_1: '{{ access_key_info.access_keys[0] }}'
- access_key_2: '{{ access_key_info.access_keys[1] }}'
-
- # ==================================================================================
-
- # We don't block the attempt to create a third access key - should AWS change
- # the limits this will "JustWork".
-
- # - name: Create a third key (check_mode)
- # iam_access_key:
- # user_name: '{{ test_user }}'
- # state: present
- # register: create_key_3
- # ignore_errors: True
- # check_mode: true
-
- # - assert:
- # that:
- # - create_key_3 is successful
- # - create_key_3 is changed
-
- - name: Create a third key without rotation
- iam_access_key:
- user_name: '{{ test_user }}'
- state: present
- register: create_key_3
- ignore_errors: True
-
- - assert:
- that:
- # If Amazon update the limits we may need to change the expectation here.
- - create_key_3 is failed
-
- - name: Fetch IAM key info (2 keys - not changed)
- iam_access_key_info:
- user_name: '{{ test_user }}'
- register: access_key_info
-
- - assert:
- that:
- - access_key_info is successful
- - '"access_keys" in access_key_info'
- - access_key_info.access_keys | length == 2
- - '"access_key_id" in access_key_1'
- - '"create_date" in access_key_1'
- - '"user_name" in access_key_1'
- - '"status" in access_key_1'
- - access_key_1.user_name == test_user
- - access_key_1.access_key_id == create_key_1.access_key.access_key_id
- - access_key_1.create_date == create_key_1.access_key.create_date
- - access_key_1.status == 'Active'
- - '"access_key_id" in access_key_2'
- - '"create_date" in access_key_2'
- - '"user_name" in access_key_2'
- - '"status" in access_key_2'
- - access_key_2.user_name == test_user
- - access_key_2.access_key_id == create_key_2.access_key.access_key_id
- - access_key_2.create_date == create_key_2.access_key.create_date
- - access_key_2.status == 'Active'
- vars:
- access_key_1: '{{ access_key_info.access_keys[0] }}'
- access_key_2: '{{ access_key_info.access_keys[1] }}'
-
- # ==================================================================================
-
- - name: Create a third key - rotation enabled (check_mode)
- iam_access_key:
- user_name: '{{ test_user }}'
- state: present
- rotate_keys: true
- register: create_key_3
- check_mode: true
-
- - assert:
- that:
- - create_key_3 is successful
- - create_key_3 is changed
- - '"deleted_access_key_id" in create_key_3'
- - create_key_3.deleted_access_key_id == create_key_1.access_key.access_key_id
-
- - name: Create a second key
- iam_access_key:
- user_name: '{{ test_user }}'
- state: present
- rotate_keys: true
- register: create_key_3
-
- - assert:
- that:
- - create_key_3 is successful
- - create_key_3 is changed
- - '"access_key" in create_key_3'
- - '"secret_access_key" in create_key_3'
- - '"deleted_access_key_id" in create_key_3'
- - create_key_3.deleted_access_key_id == create_key_1.access_key.access_key_id
- - '"access_key_id" in create_key_3.access_key'
- - '"create_date" in create_key_3.access_key'
- - '"user_name" in create_key_3.access_key'
- - '"status" in create_key_3.access_key'
- - create_key_3.access_key.user_name == test_user
- - create_key_3.access_key.status == 'Active'
-
- - name: Fetch IAM key info (2 keys - oldest rotated)
- iam_access_key_info:
- user_name: '{{ test_user }}'
- register: access_key_info
-
- - assert:
- that:
- - access_key_info is successful
- - '"access_keys" in access_key_info'
- - access_key_info.access_keys | length == 2
- - '"access_key_id" in access_key_1'
- - '"create_date" in access_key_1'
- - '"user_name" in access_key_1'
- - '"status" in access_key_1'
- - access_key_1.user_name == test_user
- - access_key_1.access_key_id == create_key_2.access_key.access_key_id
- - access_key_1.create_date == create_key_2.access_key.create_date
- - access_key_1.status == 'Active'
- - '"access_key_id" in access_key_2'
- - '"create_date" in access_key_2'
- - '"user_name" in access_key_2'
- - '"status" in access_key_2'
- - access_key_2.user_name == test_user
- - access_key_2.access_key_id == create_key_3.access_key.access_key_id
- - access_key_2.create_date == create_key_3.access_key.create_date
- - access_key_2.status == 'Active'
- vars:
- access_key_1: '{{ access_key_info.access_keys[0] }}'
- access_key_2: '{{ access_key_info.access_keys[1] }}'
-
- # ==================================================================================
-
- - name: Disable third key (check_mode)
- iam_access_key:
- user_name: '{{ test_user }}'
- id: '{{ create_key_3.access_key.access_key_id }}'
- enabled: False
- register: disable_key
- check_mode: true
-
- - assert:
- that:
- - disable_key is successful
- - disable_key is changed
-
- - name: Disable third key
- iam_access_key:
- user_name: '{{ test_user }}'
- id: '{{ create_key_3.access_key.access_key_id }}'
- enabled: False
- register: disable_key
-
- - assert:
- that:
- - disable_key is successful
- - disable_key is changed
- - '"access_key" in disable_key'
- - '"secret_access_key" not in disable_key'
- - '"deleted_access_key_id" not in disable_key'
- - '"access_key_id" in disable_key.access_key'
- - '"create_date" in disable_key.access_key'
- - '"user_name" in disable_key.access_key'
- - '"status" in disable_key.access_key'
- - disable_key.access_key.user_name == test_user
- - disable_key.access_key.status == 'Inactive'
-
- - name: Disable third key - idempotency (check_mode)
- iam_access_key:
- user_name: '{{ test_user }}'
- id: '{{ create_key_3.access_key.access_key_id }}'
- enabled: False
- register: disable_key
- check_mode: true
-
- - assert:
- that:
- - disable_key is successful
- - disable_key is not changed
-
- - name: Disable third key - idempotency
- iam_access_key:
- user_name: '{{ test_user }}'
- id: '{{ create_key_3.access_key.access_key_id }}'
- enabled: False
- register: disable_key
-
- - assert:
- that:
- - disable_key is successful
- - disable_key is not changed
- - '"access_key" in disable_key'
- - '"secret_access_key" not in disable_key'
- - '"deleted_access_key_id" not in disable_key'
- - '"access_key_id" in disable_key.access_key'
- - '"create_date" in disable_key.access_key'
- - '"user_name" in disable_key.access_key'
- - '"status" in disable_key.access_key'
- - disable_key.access_key.user_name == test_user
- - disable_key.access_key.status == 'Inactive'
-
- - name: Fetch IAM key info (2 keys - 1 disabled)
- iam_access_key_info:
- user_name: '{{ test_user }}'
- register: access_key_info
-
- - assert:
- that:
- - access_key_info is successful
- - '"access_keys" in access_key_info'
- - access_key_info.access_keys | length == 2
- - '"access_key_id" in access_key_1'
- - '"create_date" in access_key_1'
- - '"user_name" in access_key_1'
- - '"status" in access_key_1'
- - access_key_1.user_name == test_user
- - access_key_1.access_key_id == create_key_2.access_key.access_key_id
- - access_key_1.create_date == create_key_2.access_key.create_date
- - access_key_1.status == 'Active'
- - '"access_key_id" in access_key_2'
- - '"create_date" in access_key_2'
- - '"user_name" in access_key_2'
- - '"status" in access_key_2'
- - access_key_2.user_name == test_user
- - access_key_2.access_key_id == create_key_3.access_key.access_key_id
- - access_key_2.create_date == create_key_3.access_key.create_date
- - access_key_2.status == 'Inactive'
- vars:
- access_key_1: '{{ access_key_info.access_keys[0] }}'
- access_key_2: '{{ access_key_info.access_keys[1] }}'
-
- # ==================================================================================
-
- - name: Touch third key - no change (check_mode)
- iam_access_key:
- user_name: '{{ test_user }}'
- id: '{{ create_key_3.access_key.access_key_id }}'
- register: touch_key
- check_mode: true
-
- - assert:
- that:
- - touch_key is successful
- - touch_key is not changed
-
- - name: Touch third key - no change
- iam_access_key:
- user_name: '{{ test_user }}'
- id: '{{ create_key_3.access_key.access_key_id }}'
- register: touch_key
-
- - assert:
- that:
- - touch_key is successful
- - touch_key is not changed
- - '"access_key" in touch_key'
- - '"secret_access_key" not in touch_key'
- - '"deleted_access_key_id" not in touch_key'
- - '"access_key_id" in touch_key.access_key'
- - '"create_date" in touch_key.access_key'
- - '"user_name" in touch_key.access_key'
- - '"status" in touch_key.access_key'
- - touch_key.access_key.user_name == test_user
- - touch_key.access_key.status == 'Inactive'
-
- # ==================================================================================
-
- - name: Enable third key (check_mode)
- iam_access_key:
- user_name: '{{ test_user }}'
- id: '{{ create_key_3.access_key.access_key_id }}'
- enabled: True
- register: enable_key
- check_mode: true
-
- - assert:
- that:
- - enable_key is successful
- - enable_key is changed
-
- - name: Enable third key
- iam_access_key:
- user_name: '{{ test_user }}'
- id: '{{ create_key_3.access_key.access_key_id }}'
- enabled: True
- register: enable_key
-
- - assert:
- that:
- - enable_key is successful
- - enable_key is changed
- - '"access_key" in enable_key'
- - '"secret_access_key" not in enable_key'
- - '"deleted_access_key_id" not in enable_key'
- - '"access_key_id" in enable_key.access_key'
- - '"create_date" in enable_key.access_key'
- - '"user_name" in enable_key.access_key'
- - '"status" in enable_key.access_key'
- - enable_key.access_key.user_name == test_user
- - enable_key.access_key.status == 'Active'
-
- - name: Enable third key - idempotency (check_mode)
- iam_access_key:
- user_name: '{{ test_user }}'
- id: '{{ create_key_3.access_key.access_key_id }}'
- enabled: True
- register: enable_key
- check_mode: true
-
- - assert:
- that:
- - enable_key is successful
- - enable_key is not changed
-
- - name: Enable third key - idempotency
- iam_access_key:
- user_name: '{{ test_user }}'
- id: '{{ create_key_3.access_key.access_key_id }}'
- enabled: True
- register: enable_key
-
- - assert:
- that:
- - enable_key is successful
- - enable_key is not changed
- - '"access_key" in enable_key'
- - '"secret_access_key" not in enable_key'
- - '"deleted_access_key_id" not in enable_key'
- - '"access_key_id" in enable_key.access_key'
- - '"create_date" in enable_key.access_key'
- - '"user_name" in enable_key.access_key'
- - '"status" in enable_key.access_key'
- - enable_key.access_key.user_name == test_user
- - enable_key.access_key.status == 'Active'
-
- # ==================================================================================
-
- - name: Touch third key again - no change (check_mode)
- iam_access_key:
- user_name: '{{ test_user }}'
- id: '{{ create_key_3.access_key.access_key_id }}'
- register: touch_key
- check_mode: true
-
- - assert:
- that:
- - touch_key is successful
- - touch_key is not changed
-
- - name: Touch third key again - no change
- iam_access_key:
- user_name: '{{ test_user }}'
- id: '{{ create_key_3.access_key.access_key_id }}'
- register: touch_key
-
- - assert:
- that:
- - touch_key is successful
- - touch_key is not changed
- - '"access_key" in touch_key'
- - '"secret_access_key" not in touch_key'
- - '"deleted_access_key_id" not in touch_key'
- - '"access_key_id" in touch_key.access_key'
- - '"create_date" in touch_key.access_key'
- - '"user_name" in touch_key.access_key'
- - '"status" in touch_key.access_key'
- - touch_key.access_key.user_name == test_user
- - touch_key.access_key.status == 'Active'
-
- # ==================================================================================
-
- - name: Re-Disable third key
- iam_access_key:
- user_name: '{{ test_user }}'
- id: '{{ create_key_3.access_key.access_key_id }}'
- enabled: False
- register: redisable_key
-
- - assert:
- that:
- - redisable_key is successful
- - redisable_key is changed
- - redisable_key.access_key.status == 'Inactive'
-
- - pause:
- seconds: 10
-
- # ==================================================================================
-
- - name: Test GetCallerIdentity - Key 2
- aws_caller_info:
- aws_access_key: "{{ create_key_2.access_key.access_key_id }}"
- aws_secret_key: "{{ create_key_2.secret_access_key }}"
- security_token: "{{ omit }}"
- register: caller_identity_2
-
- - assert:
- that:
- - caller_identity_2 is successful
- - caller_identity_2.arn == iam_user.iam_user.user.arn
-
- - name: Test GetCallerIdentity - Key 1 (gone)
- aws_caller_info:
- aws_access_key: "{{ create_key_1.access_key.access_key_id }}"
- aws_secret_key: "{{ create_key_1.secret_access_key }}"
- security_token: "{{ omit }}"
- register: caller_identity_1
- ignore_errors: true
-
- - assert:
- that:
- - caller_identity_1 is failed
- - caller_identity_1.error.code == 'InvalidClientTokenId'
-
- - name: Test GetCallerIdentity - Key 3 (disabled)
- aws_caller_info:
- aws_access_key: "{{ create_key_3.access_key.access_key_id }}"
- aws_secret_key: "{{ create_key_3.secret_access_key }}"
- security_token: "{{ omit }}"
- register: caller_identity_3
- ignore_errors: true
-
- - assert:
- that:
- - caller_identity_3 is failed
- - caller_identity_3.error.code == 'InvalidClientTokenId'
-
- # ==================================================================================
-
- - name: Delete active key (check_mode)
- iam_access_key:
- user_name: '{{ test_user }}'
- id: '{{ create_key_2.access_key.access_key_id }}'
- state: absent
- register: delete_active_key
- check_mode: true
-
- - assert:
- that:
- - delete_active_key is successful
- - delete_active_key is changed
-
- - name: Delete active key
- iam_access_key:
- user_name: '{{ test_user }}'
- id: '{{ create_key_2.access_key.access_key_id }}'
- state: absent
- register: delete_active_key
-
- - assert:
- that:
- - delete_active_key is successful
- - delete_active_key is changed
-
- - name: Delete active key - idempotency (check_mode)
- iam_access_key:
- user_name: '{{ test_user }}'
- id: '{{ create_key_2.access_key.access_key_id }}'
- state: absent
- register: delete_active_key
- check_mode: true
-
- - assert:
- that:
- - delete_active_key is successful
- - delete_active_key is not changed
-
- - name: Delete active key - idempotency
- iam_access_key:
- user_name: '{{ test_user }}'
- id: '{{ create_key_2.access_key.access_key_id }}'
- state: absent
- register: delete_active_key
-
- - assert:
- that:
- - delete_active_key is successful
- - delete_active_key is not changed
-
- # ==================================================================================
-
- - name: Delete inactive key (check_mode)
- iam_access_key:
- user_name: '{{ test_user }}'
- id: '{{ create_key_3.access_key.access_key_id }}'
- state: absent
- register: delete_inactive_key
- check_mode: true
-
- - assert:
- that:
- - delete_inactive_key is successful
- - delete_inactive_key is changed
-
- - name: Delete inactive key
- iam_access_key:
- user_name: '{{ test_user }}'
- id: '{{ create_key_3.access_key.access_key_id }}'
- state: absent
- register: delete_inactive_key
-
- - assert:
- that:
- - delete_inactive_key is successful
- - delete_inactive_key is changed
-
- - name: Delete inactive key - idempotency (check_mode)
- iam_access_key:
- user_name: '{{ test_user }}'
- id: '{{ create_key_3.access_key.access_key_id }}'
- state: absent
- register: delete_inactive_key
- check_mode: true
-
- - assert:
- that:
- - delete_inactive_key is successful
- - delete_inactive_key is not changed
-
- - name: Delete inactive key - idempotency
- iam_access_key:
- user_name: '{{ test_user }}'
- id: '{{ create_key_3.access_key.access_key_id }}'
- state: absent
- register: delete_inactive_key
-
- - assert:
- that:
- - delete_inactive_key is successful
- - delete_inactive_key is not changed
-
- # ==================================================================================
-
- - name: Fetch IAM key info (no keys)
- iam_access_key_info:
- user_name: '{{ test_user }}'
- register: access_key_info
-
- - assert:
- that:
- - access_key_info is successful
- - '"access_keys" in access_key_info'
- - access_key_info.access_keys | length == 0
-
- # ==================================================================================
-
- - name: Create an inactive key (check_mode)
- iam_access_key:
- user_name: '{{ test_user }}'
- state: present
- enabled: false
- register: create_key_4
- check_mode: true
-
- - assert:
- that:
- - create_key_4 is successful
- - create_key_4 is changed
-
- - name: Create a key
- iam_access_key:
- user_name: '{{ test_user }}'
- state: present
- enabled: false
- register: create_key_4
-
- - assert:
- that:
- - create_key_4 is successful
- - create_key_4 is changed
- - '"access_key" in create_key_4'
- - '"secret_access_key" in create_key_4'
- - '"deleted_access_key_id" not in create_key_4'
- - '"access_key_id" in create_key_4.access_key'
- - '"create_date" in create_key_4.access_key'
- - '"user_name" in create_key_4.access_key'
- - '"status" in create_key_4.access_key'
- - create_key_4.access_key.user_name == test_user
- - create_key_4.access_key.status == 'Inactive'
-
- - name: Fetch IAM key info (1 inactive key)
- iam_access_key_info:
- user_name: '{{ test_user }}'
- register: access_key_info
-
- - assert:
- that:
- - access_key_info is successful
- - '"access_keys" in access_key_info'
- - access_key_info.access_keys | length == 1
- - '"access_key_id" in access_key_1'
- - '"create_date" in access_key_1'
- - '"user_name" in access_key_1'
- - '"status" in access_key_1'
- - access_key_1.user_name == test_user
- - access_key_1.access_key_id == create_key_4.access_key.access_key_id
- - access_key_1.create_date == create_key_4.access_key.create_date
- - access_key_1.status == 'Inactive'
- vars:
- access_key_1: '{{ access_key_info.access_keys[0] }}'
-
- # We already tested the idempotency of disabling keys, use this to verify that
- # the key is disabled
- - name: Disable new key
- iam_access_key:
- user_name: '{{ test_user }}'
- id: '{{ create_key_4.access_key.access_key_id }}'
- enabled: False
- register: disable_new_key
-
- - assert:
- that:
- - disable_new_key is successful
- - disable_new_key is not changed
- - '"access_key" in disable_new_key'
-
- # ==================================================================================
- # Cleanup
-
- - name: Delete new key
- iam_access_key:
- user_name: '{{ test_user }}'
- id: '{{ create_key_4.access_key.access_key_id }}'
- state: absent
- register: delete_new_key
-
- - assert:
- that:
- - delete_new_key is successful
- - delete_new_key is changed
-
- - name: Remove test user
- iam_user:
- name: '{{ test_user }}'
- state: absent
- register: delete_user
-
- - assert:
- that:
- - delete_user is successful
- - delete_user is changed
-
- always:
-
- - name: Remove test user
- iam_user:
- name: '{{ test_user }}'
- state: absent
- ignore_errors: yes
diff --git a/ansible_collections/community/aws/tests/integration/targets/iam_group/aliases b/ansible_collections/community/aws/tests/integration/targets/iam_group/aliases
deleted file mode 100644
index 2da398045..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/iam_group/aliases
+++ /dev/null
@@ -1,7 +0,0 @@
-# reason: missing-policy
-# It should be possible to test iam_groups by limiting which policies can be
-# attached to the groups as well as which users can be added to the groups.
-# Careful review is needed prior to adding this to the main CI.
-unsupported
-
-cloud/aws
diff --git a/ansible_collections/community/aws/tests/integration/targets/iam_group/defaults/main.yml b/ansible_collections/community/aws/tests/integration/targets/iam_group/defaults/main.yml
deleted file mode 100644
index f5112b1a4..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/iam_group/defaults/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-test_user: '{{ resource_prefix }}-user'
-test_group: '{{ resource_prefix }}-group'
diff --git a/ansible_collections/community/aws/tests/integration/targets/iam_group/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/iam_group/tasks/main.yml
deleted file mode 100644
index 65b441827..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/iam_group/tasks/main.yml
+++ /dev/null
@@ -1,127 +0,0 @@
----
-- name: set up aws connection info
- module_defaults:
- group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
- region: "{{ aws_region }}"
- collections:
- - amazon.aws
- block:
- - name: ensure ansible user exists
- iam_user:
- name: '{{ test_user }}'
- state: present
-
- - name: ensure group exists
- iam_group:
- name: '{{ test_group }}'
- users:
- - '{{ test_user }}'
- state: present
- register: iam_group
-
- - assert:
- that:
- - iam_group.iam_group.users
- - iam_group is changed
-
- - name: add non existent user to group
- iam_group:
- name: '{{ test_group }}'
- users:
- - '{{ test_user }}'
- - NonExistentUser
- state: present
- ignore_errors: yes
- register: iam_group
-
- - name: assert that adding non existent user to group fails with helpful message
- assert:
- that:
- - iam_group is failed
- - iam_group.msg.startswith("Couldn't add user NonExistentUser to group {{ test_group }}")
-
- - name: remove a user
- iam_group:
- name: '{{ test_group }}'
- purge_users: True
- users: []
- state: present
- register: iam_group
-
- - assert:
- that:
- - iam_group is changed
- - not iam_group.iam_group.users
-
- - name: re-remove a user (no change)
- iam_group:
- name: '{{ test_group }}'
- purge_users: True
- users: []
- state: present
- register: iam_group
-
- - assert:
- that:
- - iam_group is not changed
- - not iam_group.iam_group.users
-
- - name: Add the user again
- iam_group:
- name: '{{ test_group }}'
- users:
- - '{{ test_user }}'
- state: present
- register: iam_group
-
- - assert:
- that:
- - iam_group is changed
- - iam_group.iam_group.users
-
- - name: Re-add the user
- iam_group:
- name: '{{ test_group }}'
- users:
- - '{{ test_user }}'
- state: present
- register: iam_group
-
- - assert:
- that:
- - iam_group is not changed
- - iam_group.iam_group.users
-
- - name: remove group
- iam_group:
- name: '{{ test_group }}'
- state: absent
- register: iam_group
-
- - assert:
- that:
- - iam_group is changed
-
- - name: re-remove group
- iam_group:
- name: '{{ test_group }}'
- state: absent
- register: iam_group
-
- - assert:
- that:
- - iam_group is not changed
-
- always:
- - name: remove group
- iam_group:
- name: '{{ test_group }}'
- state: absent
-
- - name: remove ansible user
- iam_user:
- name: '{{ test_user }}'
- state: absent
diff --git a/ansible_collections/community/aws/tests/integration/targets/iam_managed_policy/aliases b/ansible_collections/community/aws/tests/integration/targets/iam_managed_policy/aliases
deleted file mode 100644
index 839bd014b..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/iam_managed_policy/aliases
+++ /dev/null
@@ -1,6 +0,0 @@
-# reason: missing-policy
-# It's not possible to control what permissions are granted to a policy.
-# This makes securely testing iam_policy very difficult
-unsupported
-
-cloud/aws
diff --git a/ansible_collections/community/aws/tests/integration/targets/iam_managed_policy/defaults/main.yml b/ansible_collections/community/aws/tests/integration/targets/iam_managed_policy/defaults/main.yml
deleted file mode 100644
index a6edcacef..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/iam_managed_policy/defaults/main.yml
+++ /dev/null
@@ -1,2 +0,0 @@
----
-policy_name: "{{ resource_prefix }}-policy"
diff --git a/ansible_collections/community/aws/tests/integration/targets/iam_managed_policy/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/iam_managed_policy/tasks/main.yml
deleted file mode 100644
index f17b7cad0..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/iam_managed_policy/tasks/main.yml
+++ /dev/null
@@ -1,160 +0,0 @@
----
-- name: "Run integration tests for IAM managed policy"
- module_defaults:
- group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
- region: "{{ aws_region }}"
- collections:
- - amazon.aws
- block:
- ## Test policy creation
- - name: Create IAM managed policy - check mode
- iam_managed_policy:
- policy_name: "{{ policy_name }}"
- policy:
- Version: "2012-10-17"
- Statement:
- - Effect: "Deny"
- Action: "logs:CreateLogGroup"
- Resource: "*"
- state: present
- register: result
- check_mode: yes
-
- - name: Create IAM managed policy - check mode
- assert:
- that:
- - result.changed
-
- - name: Create IAM managed policy
- iam_managed_policy:
- policy_name: "{{ policy_name }}"
- policy:
- Version: "2012-10-17"
- Statement:
- - Effect: "Deny"
- Action: "logs:CreateLogGroup"
- Resource: "*"
- state: present
- register: result
-
- - name: Create IAM managed policy
- assert:
- that:
- - result.changed
- - result.policy.policy_name == policy_name
-
- - name: Create IAM managed policy - idempotency check
- iam_managed_policy:
- policy_name: "{{ policy_name }}"
- policy:
- Version: "2012-10-17"
- Statement:
- - Effect: "Deny"
- Action: "logs:CreateLogGroup"
- Resource: "*"
- state: present
- register: result
-
- - name: Create IAM managed policy - idempotency check
- assert:
- that:
- - not result.changed
-
- ## Test policy update
- - name: Update IAM managed policy - check mode
- iam_managed_policy:
- policy_name: "{{ policy_name }}"
- policy:
- Version: "2012-10-17"
- Statement:
- - Effect: "Deny"
- Action: "logs:Describe*"
- Resource: "*"
- state: present
- register: result
- check_mode: yes
-
- - name: Update IAM managed policy - check mode
- assert:
- that:
- - result.changed
-
- - name: Update IAM managed policy
- iam_managed_policy:
- policy_name: "{{ policy_name }}"
- policy:
- Version: "2012-10-17"
- Statement:
- - Effect: "Deny"
- Action: "logs:Describe*"
- Resource: "*"
- state: present
- register: result
-
- - name: Update IAM managed policy
- assert:
- that:
- - result.changed
- - result.policy.policy_name == policy_name
-
- - name: Update IAM managed policy - idempotency check
- iam_managed_policy:
- policy_name: "{{ policy_name }}"
- policy:
- Version: "2012-10-17"
- Statement:
- - Effect: "Deny"
- Action: "logs:Describe*"
- Resource: "*"
- state: present
- register: result
-
- - name: Update IAM managed policy - idempotency check
- assert:
- that:
- - not result.changed
-
- ## Test policy deletion
- - name: Delete IAM managed policy - check mode
- iam_managed_policy:
- policy_name: "{{ policy_name }}"
- state: absent
- register: result
- check_mode: yes
-
- - name: Delete IAM managed policy - check mode
- assert:
- that:
- - result.changed
-
- - name: Delete IAM managed policy
- iam_managed_policy:
- policy_name: "{{ policy_name }}"
- state: absent
- register: result
-
- - name: Delete IAM managed policy
- assert:
- that:
- - result.changed
-
- - name: Delete IAM managed policy - idempotency check
- iam_managed_policy:
- policy_name: "{{ policy_name }}"
- state: absent
- register: result
-
- - name: Delete IAM managed policy - idempotency check
- assert:
- that:
- - not result.changed
-
- always:
- - name: Delete IAM managed policy
- iam_managed_policy:
- policy_name: "{{ policy_name }}"
- state: absent
- ignore_errors: yes
diff --git a/ansible_collections/community/aws/tests/integration/targets/iam_password_policy/aliases b/ansible_collections/community/aws/tests/integration/targets/iam_password_policy/aliases
deleted file mode 100644
index 140a2f2dc..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/iam_password_policy/aliases
+++ /dev/null
@@ -1,8 +0,0 @@
-# reason: missing-policy
-# IAM Password Policies configure account-wide settings, this makes then
-# difficult to safely test
-# reason: serial
-# Only one password policy can be configured per account
-unsupported
-
-cloud/aws
diff --git a/ansible_collections/community/aws/tests/integration/targets/iam_password_policy/meta/main.yml b/ansible_collections/community/aws/tests/integration/targets/iam_password_policy/meta/main.yml
deleted file mode 100644
index 32cf5dda7..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/iam_password_policy/meta/main.yml
+++ /dev/null
@@ -1 +0,0 @@
-dependencies: []
diff --git a/ansible_collections/community/aws/tests/integration/targets/iam_password_policy/tasks/main.yaml b/ansible_collections/community/aws/tests/integration/targets/iam_password_policy/tasks/main.yaml
deleted file mode 100644
index 7b773eac8..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/iam_password_policy/tasks/main.yaml
+++ /dev/null
@@ -1,107 +0,0 @@
-- module_defaults:
- group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
- region: "{{ aws_region }}"
- collections:
- - amazon.aws
- block:
- - name: set iam password policy
- iam_password_policy:
- state: present
- min_pw_length: 8
- require_symbols: false
- require_numbers: true
- require_uppercase: true
- require_lowercase: true
- allow_pw_change: true
- pw_max_age: 60
- pw_reuse_prevent: 5
- pw_expire: false
- register: result
-
- - name: assert that changes were made
- assert:
- that:
- - result.changed
-
- - name: verify iam password policy has been created
- iam_password_policy:
- state: present
- min_pw_length: 8
- require_symbols: false
- require_numbers: true
- require_uppercase: true
- require_lowercase: true
- allow_pw_change: true
- pw_max_age: 60
- pw_reuse_prevent: 5
- pw_expire: false
- register: result
-
- - name: assert that no changes were made
- assert:
- that:
- - not result.changed
-
- - name: update iam password policy with different settings
- iam_password_policy:
- state: present
- min_pw_length: 15
- require_symbols: true
- require_numbers: true
- require_uppercase: true
- require_lowercase: true
- allow_pw_change: true
- pw_max_age: 30
- pw_reuse_prevent: 10
- pw_expire: true
- register: result
-
- - name: assert that updates were made
- assert:
- that:
- - result.changed
-
- # Test for regression of #59102
- - name: update iam password policy without expiry
- iam_password_policy:
- state: present
- min_pw_length: 15
- require_symbols: true
- require_numbers: true
- require_uppercase: true
- require_lowercase: true
- allow_pw_change: true
- register: result
-
- - name: assert that changes were made
- assert:
- that:
- - result.changed
-
- - name: remove iam password policy
- iam_password_policy:
- state: absent
- register: result
-
- - name: assert password policy has been removed
- assert:
- that:
- - result.changed
-
- - name: verify password policy has been removed
- iam_password_policy:
- state: absent
- register: result
-
- - name: assert no changes were made
- assert:
- that:
- - not result.changed
- always:
- - name: remove iam password policy
- iam_password_policy:
- state: absent
- register: result
diff --git a/ansible_collections/community/aws/tests/integration/targets/iam_role/aliases b/ansible_collections/community/aws/tests/integration/targets/iam_role/aliases
deleted file mode 100644
index 483c86115..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/iam_role/aliases
+++ /dev/null
@@ -1,9 +0,0 @@
-# reason: missing-policy
-# It should be possible to test iam_role by limiting which policies can be
-# attached to the roles.
-# Careful review is needed prior to adding this to the main CI.
-unsupported
-
-cloud/aws
-
-iam_role_info
diff --git a/ansible_collections/community/aws/tests/integration/targets/iam_role/defaults/main.yml b/ansible_collections/community/aws/tests/integration/targets/iam_role/defaults/main.yml
deleted file mode 100644
index d496c4216..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/iam_role/defaults/main.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
-test_role: '{{ resource_prefix }}-role'
-test_path: '/{{ resource_prefix }}/'
-safe_managed_policy: 'AWSDenyAll'
-custom_policy_name: '{{ resource_prefix }}-denyall'
-boundary_policy: 'arn:aws:iam::aws:policy/AWSDenyAll'
diff --git a/ansible_collections/community/aws/tests/integration/targets/iam_role/files/deny-all-a.json b/ansible_collections/community/aws/tests/integration/targets/iam_role/files/deny-all-a.json
deleted file mode 100644
index ae62fd197..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/iam_role/files/deny-all-a.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "Version": "2012-10-17",
- "Statement": [
- {
- "Action": [
- "*"
- ],
- "Effect": "Deny",
- "Resource": "*",
- "Sid": "DenyA"
- }
- ]
-}
diff --git a/ansible_collections/community/aws/tests/integration/targets/iam_role/files/deny-all-b.json b/ansible_collections/community/aws/tests/integration/targets/iam_role/files/deny-all-b.json
deleted file mode 100644
index 3a4704a46..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/iam_role/files/deny-all-b.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "Version": "2012-10-17",
- "Statement": [
- {
- "Action": [
- "*"
- ],
- "Effect": "Deny",
- "Resource": "*",
- "Sid": "DenyB"
- }
- ]
-}
diff --git a/ansible_collections/community/aws/tests/integration/targets/iam_role/files/deny-all.json b/ansible_collections/community/aws/tests/integration/targets/iam_role/files/deny-all.json
deleted file mode 100644
index 3d324b9b9..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/iam_role/files/deny-all.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "Version": "2012-10-17",
- "Statement": [
- {
- "Action": [
- "*"
- ],
- "Effect": "Deny",
- "Resource": "*"
- }
- ]
-}
diff --git a/ansible_collections/community/aws/tests/integration/targets/iam_role/files/deny-assume.json b/ansible_collections/community/aws/tests/integration/targets/iam_role/files/deny-assume.json
deleted file mode 100644
index 73e877158..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/iam_role/files/deny-assume.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "Version": "2012-10-17",
- "Statement": [
- {
- "Action": "sts:AssumeRole",
- "Principal": { "Service": "ec2.amazonaws.com" },
- "Effect": "Deny"
- }
- ]
-}
diff --git a/ansible_collections/community/aws/tests/integration/targets/iam_role/meta/main.yml b/ansible_collections/community/aws/tests/integration/targets/iam_role/meta/main.yml
deleted file mode 100644
index 32cf5dda7..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/iam_role/meta/main.yml
+++ /dev/null
@@ -1 +0,0 @@
-dependencies: []
diff --git a/ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/boundary_policy.yml b/ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/boundary_policy.yml
deleted file mode 100644
index 89a983f15..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/boundary_policy.yml
+++ /dev/null
@@ -1,94 +0,0 @@
----
-- name: "Create minimal role with no boundary policy"
- iam_role:
- name: "{{ test_role }}"
- create_instance_profile: no
- register: iam_role
-
-- assert:
- that:
- - iam_role is changed
- - iam_role.iam_role.role_name == test_role
-
-- name: "Configure Boundary Policy (CHECK MODE)"
- iam_role:
- name: "{{ test_role }}"
- create_instance_profile: no
- boundary: "{{ boundary_policy }}"
- check_mode: yes
- register: iam_role
-
-- assert:
- that:
- - iam_role is changed
-
-- name: "Configure Boundary Policy"
- iam_role:
- name: "{{ test_role }}"
- create_instance_profile: no
- boundary: "{{ boundary_policy }}"
- register: iam_role
-
-- assert:
- that:
- - iam_role is changed
- - iam_role.iam_role.role_name == test_role
-
-- name: "Configure Boundary Policy (no change) - check mode"
- iam_role:
- name: "{{ test_role }}"
- create_instance_profile: no
- boundary: "{{ boundary_policy }}"
- register: iam_role
- check_mode: yes
-
-- assert:
- that:
- - iam_role is not changed
-
-- name: "Configure Boundary Policy (no change)"
- iam_role:
- name: "{{ test_role }}"
- create_instance_profile: no
- boundary: "{{ boundary_policy }}"
- register: iam_role
-
-- assert:
- that:
- - iam_role is not changed
- - iam_role.iam_role.role_name == test_role
-
-- name: "iam_role_info after adding boundary policy"
- iam_role_info:
- name: "{{ test_role }}"
- register: role_info
-
-- assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 1
- - 'role_info.iam_roles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
- - '"assume_role_policy_document" in role_info.iam_roles[0]'
- - '"create_date" in role_info.iam_roles[0]'
- - '"description" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].inline_policies | length == 0
- - role_info.iam_roles[0].instance_profiles | length == 0
- - role_info.iam_roles[0].managed_policies | length == 0
- - role_info.iam_roles[0].max_session_duration == 3600
- - role_info.iam_roles[0].path == '/'
- - role_info.iam_roles[0].permissions_boundary.permissions_boundary_arn == boundary_policy
- - role_info.iam_roles[0].permissions_boundary.permissions_boundary_type == 'Policy'
- - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
- - role_info.iam_roles[0].role_name == test_role
-
-- name: "Remove IAM Role"
- iam_role:
- state: absent
- name: "{{ test_role }}"
- delete_instance_profile: yes
- register: iam_role
-
-- assert:
- that:
- - iam_role is changed \ No newline at end of file
diff --git a/ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/complex_role_creation.yml b/ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/complex_role_creation.yml
deleted file mode 100644
index c23234ebf..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/complex_role_creation.yml
+++ /dev/null
@@ -1,131 +0,0 @@
----
-- name: "Complex IAM Role (CHECK MODE)"
- iam_role:
- name: "{{ test_role }}"
- assume_role_policy_document: '{{ lookup("file", "deny-assume.json") }}'
- boundary: "{{ boundary_policy }}"
- create_instance_profile: no
- description: "Ansible Test Role {{ resource_prefix }}"
- managed_policy:
- - "{{ safe_managed_policy }}"
- - "{{ custom_policy_name }}"
- max_session_duration: 43200
- path: "{{ test_path }}"
- tags:
- TagA: "ValueA"
- check_mode: yes
- register: iam_role
-
-- assert:
- that:
- - iam_role is changed
-
-- name: "iam_role_info after Complex Role creation in check_mode"
- iam_role_info:
- name: "{{ test_role }}"
- register: role_info
-- assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 0
-
-- name: "Complex IAM Role"
- iam_role:
- name: "{{ test_role }}"
- assume_role_policy_document: '{{ lookup("file", "deny-assume.json") }}'
- boundary: "{{ boundary_policy }}"
- create_instance_profile: no
- description: "Ansible Test Role {{ resource_prefix }}"
- managed_policy:
- - "{{ safe_managed_policy }}"
- - "{{ custom_policy_name }}"
- max_session_duration: 43200
- path: "{{ test_path }}"
- tags:
- TagA: "ValueA"
- register: iam_role
-
-- assert:
- that:
- - iam_role is changed
- - iam_role.iam_role.role_name == test_role
- - 'iam_role.iam_role.arn.startswith("arn")'
- - 'iam_role.iam_role.arn.endswith("role" + test_path + test_role )'
- # Would be nice to test the contents...
- - '"assume_role_policy_document" in iam_role.iam_role'
- - iam_role.iam_role.attached_policies | length == 2
- - iam_role.iam_role.max_session_duration == 43200
- - iam_role.iam_role.path == test_path
- - iam_role.iam_role.role_name == test_role
- - '"create_date" in iam_role.iam_role'
- - '"role_id" in iam_role.iam_role'
-
-- name: "Complex IAM role (no change) - check mode"
- iam_role:
- name: "{{ test_role }}"
- assume_role_policy_document: '{{ lookup("file", "deny-assume.json") }}'
- boundary: "{{ boundary_policy }}"
- create_instance_profile: no
- description: "Ansible Test Role {{ resource_prefix }}"
- managed_policy:
- - "{{ safe_managed_policy }}"
- - "{{ custom_policy_name }}"
- max_session_duration: 43200
- path: "{{ test_path }}"
- tags:
- TagA: "ValueA"
- register: iam_role
- check_mode: yes
-
-- assert:
- that:
- - iam_role is not changed
-
-- name: "Complex IAM role (no change)"
- iam_role:
- name: "{{ test_role }}"
- assume_role_policy_document: '{{ lookup("file", "deny-assume.json") }}'
- boundary: "{{ boundary_policy }}"
- create_instance_profile: no
- description: "Ansible Test Role {{ resource_prefix }}"
- managed_policy:
- - "{{ safe_managed_policy }}"
- - "{{ custom_policy_name }}"
- max_session_duration: 43200
- path: "{{ test_path }}"
- tags:
- TagA: "ValueA"
- register: iam_role
-
-- assert:
- that:
- - iam_role is not changed
- - iam_role.iam_role.role_name == test_role
-
-- name: "iam_role_info after Role creation"
- iam_role_info:
- name: "{{ test_role }}"
- register: role_info
-
-- assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 1
- - 'role_info.iam_roles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].arn.endswith("role" + test_path + test_role )'
- - '"assume_role_policy_document" in role_info.iam_roles[0]'
- - '"create_date" in role_info.iam_roles[0]'
- - 'role_info.iam_roles[0].description == "Ansible Test Role {{ resource_prefix }}"'
- - role_info.iam_roles[0].inline_policies | length == 0
- - role_info.iam_roles[0].instance_profiles | length == 0
- - role_info.iam_roles[0].managed_policies | length == 2
- - safe_managed_policy in ( role_info | community.general.json_query("iam_roles[*].managed_policies[*].policy_name") | list | flatten )
- - custom_policy_name in ( role_info | community.general.json_query("iam_roles[*].managed_policies[*].policy_name") | list | flatten )
- - role_info.iam_roles[0].max_session_duration == 43200
- - role_info.iam_roles[0].path == test_path
- - role_info.iam_roles[0].permissions_boundary.permissions_boundary_arn == boundary_policy
- - role_info.iam_roles[0].permissions_boundary.permissions_boundary_type == 'Policy'
- - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
- - role_info.iam_roles[0].role_name == test_role
- - '"TagA" in role_info.iam_roles[0].tags'
- - role_info.iam_roles[0].tags.TagA == "ValueA"
diff --git a/ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/creation_deletion.yml b/ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/creation_deletion.yml
deleted file mode 100644
index 0579a6d34..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/creation_deletion.yml
+++ /dev/null
@@ -1,404 +0,0 @@
----
-- name: Try running some rapid fire create/delete tests
- block:
- - name: "Minimal IAM Role without instance profile (rapid)"
- iam_role:
- name: "{{ test_role }}"
- create_instance_profile: no
- register: iam_role
-
- - name: "Minimal IAM Role without instance profile (rapid)"
- iam_role:
- name: "{{ test_role }}"
- create_instance_profile: no
- register: iam_role_again
-
- - assert:
- that:
- - iam_role is changed
- - iam_role_again is not changed
-
- - name: "Remove IAM Role (rapid)"
- iam_role:
- state: absent
- name: "{{ test_role }}"
- register: iam_role
-
- - name: "Remove IAM Role (rapid)"
- iam_role:
- state: absent
- name: "{{ test_role }}"
- register: iam_role_again
-
- - assert:
- that:
- - iam_role is changed
- - iam_role_again is not changed
-
- - name: "Minimal IAM Role without instance profile (rapid)"
- iam_role:
- name: "{{ test_role }}"
- create_instance_profile: no
- register: iam_role
-
- - name: "Remove IAM Role (rapid)"
- iam_role:
- state: absent
- name: "{{ test_role }}"
-
- register: iam_role_again
- - assert:
- that:
- - iam_role is changed
- - iam_role_again is changed
-
-# ===================================================================
-# Role Creation
-# (without Instance profile)
-- name: "iam_role_info before Role creation (no args)"
- iam_role_info:
- register: role_info
-
-- assert:
- that:
- - role_info is succeeded
-
-- name: "iam_role_info before Role creation (search for test role)"
- iam_role_info:
- name: "{{ test_role }}"
- register: role_info
-
-- assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 0
-
-- name: "Minimal IAM Role (CHECK MODE)"
- iam_role:
- name: "{{ test_role }}"
- create_instance_profile: no
- register: iam_role
- check_mode: yes
-
-- assert:
- that:
- - iam_role is changed
-
-- name: "iam_role_info after Role creation in check_mode"
- iam_role_info:
- name: "{{ test_role }}"
- register: role_info
-- assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 0
-
-- name: "Minimal IAM Role without instance profile"
- iam_role:
- name: "{{ test_role }}"
- create_instance_profile: no
- register: iam_role
-
-- assert:
- that:
- - iam_role is changed
- - iam_role.iam_role.role_name == test_role
- - 'iam_role.iam_role.arn.startswith("arn")'
- - 'iam_role.iam_role.arn.endswith("role/" + test_role )'
- - '"assume_role_policy_document" in iam_role.iam_role'
- - '"assume_role_policy_document_raw" in iam_role.iam_role'
- - iam_role.iam_role.assume_role_policy_document_raw == assume_deny_policy
- - iam_role.iam_role.attached_policies | length == 0
- - iam_role.iam_role.max_session_duration == 3600
- - iam_role.iam_role.path == '/'
- - iam_role.iam_role.role_name == test_role
- - '"create_date" in iam_role.iam_role'
- - '"role_id" in iam_role.iam_role'
-
-- name: "Minimal IAM Role without instance profile (no change) - check mode"
- iam_role:
- name: "{{ test_role }}"
- create_instance_profile: no
- register: iam_role
- check_mode: yes
-
-- assert:
- that:
- - iam_role is not changed
-
-- name: "Minimal IAM Role without instance profile (no change)"
- iam_role:
- name: "{{ test_role }}"
- create_instance_profile: no
- register: iam_role
-
-- assert:
- that:
- - iam_role is not changed
- - iam_role.iam_role.role_name == test_role
-
-- name: "iam_role_info after Role creation"
- iam_role_info:
- name: "{{ test_role }}"
- register: role_info
-
-- assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 1
- - 'role_info.iam_roles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
- - '"assume_role_policy_document" in role_info.iam_roles[0]'
- - '"assume_role_policy_document_raw" in role_info.iam_roles[0]'
- - '"create_date" in role_info.iam_roles[0]'
- - '"description" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].assume_role_policy_document_raw == assume_deny_policy
- - role_info.iam_roles[0].inline_policies | length == 0
- - role_info.iam_roles[0].instance_profiles | length == 0
- - role_info.iam_roles[0].managed_policies | length == 0
- - role_info.iam_roles[0].max_session_duration == 3600
- - role_info.iam_roles[0].path == '/'
- - '"permissions_boundary" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
- - role_info.iam_roles[0].role_name == test_role
- - role_info.iam_roles[0].tags | length == 0
-
-- name: "Remove IAM Role"
- iam_role:
- state: absent
- name: "{{ test_role }}"
- delete_instance_profile: yes
- register: iam_role
-
-- assert:
- that:
- - iam_role is changed
-
-- name: "iam_role_info after Role deletion"
- iam_role_info:
- name: "{{ test_role }}"
- register: role_info
-
-- assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 0
-
-# ------------------------------------------------------------------------------------------
-
-# (with path)
-- name: "Minimal IAM Role with path (CHECK MODE)"
- iam_role:
- name: "{{ test_role }}"
- path: "{{ test_path }}"
- register: iam_role
- check_mode: yes
-
-- assert:
- that:
- - iam_role is changed
-
-- name: "Minimal IAM Role with path"
- iam_role:
- name: "{{ test_role }}"
- path: "{{ test_path }}"
- register: iam_role
-
-- assert:
- that:
- - iam_role is changed
- - iam_role.iam_role.role_name == test_role
- - 'iam_role.iam_role.arn.startswith("arn")'
- - 'iam_role.iam_role.arn.endswith("role" + test_path + test_role )'
- # Would be nice to test the contents...
- - '"assume_role_policy_document" in iam_role.iam_role'
- - iam_role.iam_role.attached_policies | length == 0
- - iam_role.iam_role.max_session_duration == 3600
- - iam_role.iam_role.path == '{{ test_path }}'
- - iam_role.iam_role.role_name == test_role
- - '"create_date" in iam_role.iam_role'
- - '"role_id" in iam_role.iam_role'
-
-- name: "Minimal IAM Role with path (no change) - check mode"
- iam_role:
- name: "{{ test_role }}"
- path: "{{ test_path }}"
- register: iam_role
- check_mode: yes
-
-- assert:
- that:
- - iam_role is not changed
-
-- name: "Minimal IAM Role with path (no change)"
- iam_role:
- name: "{{ test_role }}"
- path: "{{ test_path }}"
- register: iam_role
-
-- assert:
- that:
- - iam_role is not changed
- - iam_role.iam_role.role_name == test_role
-
-- name: "iam_role_info after Role creation"
- iam_role_info:
- name: "{{ test_role }}"
- register: role_info
-
-- assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 1
- - 'role_info.iam_roles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].arn.endswith("role" + test_path + test_role )'
- - '"assume_role_policy_document" in role_info.iam_roles[0]'
- - '"create_date" in role_info.iam_roles[0]'
- - '"description" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].inline_policies | length == 0
- - role_info.iam_roles[0].instance_profiles | length == 1
- - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
- - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile" + test_path + test_role)'
- - role_info.iam_roles[0].managed_policies | length == 0
- - role_info.iam_roles[0].max_session_duration == 3600
- - role_info.iam_roles[0].path == '{{ test_path }}'
- - '"permissions_boundary" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
- - role_info.iam_roles[0].role_name == test_role
- - role_info.iam_roles[0].tags | length == 0
-
-- name: "iam_role_info after Role creation (searching a path)"
- iam_role_info:
- path_prefix: "{{ test_path }}"
- register: role_info
-
-- assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 1
- - 'role_info.iam_roles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].arn.endswith("role" + test_path + test_role )'
- - '"assume_role_policy_document" in role_info.iam_roles[0]'
- - '"create_date" in role_info.iam_roles[0]'
- - '"description" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].inline_policies | length == 0
- - role_info.iam_roles[0].instance_profiles | length == 1
- - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
- - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile" + test_path + test_role)'
- - role_info.iam_roles[0].managed_policies | length == 0
- - role_info.iam_roles[0].max_session_duration == 3600
- - '"permissions_boundary" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].path == '{{ test_path }}'
- - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
- - role_info.iam_roles[0].role_name == test_role
- - role_info.iam_roles[0].tags | length == 0
-
-- name: "Remove IAM Role"
- iam_role:
- state: absent
- name: "{{ test_role }}"
- path: "{{ test_path }}"
- # If we don't delete the existing profile it'll be reused (with the path)
- # by the test below.
- delete_instance_profile: yes
- register: iam_role
-
-- assert:
- that:
- - iam_role is changed
-
-- name: "iam_role_info after Role deletion"
- iam_role_info:
- name: "{{ test_role }}"
- register: role_info
-
-- assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 0
-
-# ------------------------------------------------------------------------------------------
-
-# (with Instance profile)
-- name: "Minimal IAM Role with instance profile - check mode"
- iam_role:
- name: "{{ test_role }}"
- create_instance_profile: yes
- register: iam_role
- check_mode: yes
-
-- assert:
- that:
- - iam_role is changed
-
-- name: "Minimal IAM Role with instance profile"
- iam_role:
- name: "{{ test_role }}"
- create_instance_profile: yes
- register: iam_role
-
-- assert:
- that:
- - iam_role is changed
- - iam_role.iam_role.role_name == test_role
- - 'iam_role.iam_role.arn.startswith("arn")'
- - 'iam_role.iam_role.arn.endswith("role/" + test_role )'
- # Would be nice to test the contents...
- - '"assume_role_policy_document" in iam_role.iam_role'
- - iam_role.iam_role.attached_policies | length == 0
- - iam_role.iam_role.max_session_duration == 3600
- - iam_role.iam_role.path == '/'
- - iam_role.iam_role.role_name == test_role
- - '"create_date" in iam_role.iam_role'
- - '"role_id" in iam_role.iam_role'
-
-- name: "Minimal IAM Role wth instance profile (no change) - check mode"
- iam_role:
- name: "{{ test_role }}"
- create_instance_profile: yes
- register: iam_role
- check_mode: yes
-
-- assert:
- that:
- - iam_role is not changed
-
-- name: "Minimal IAM Role wth instance profile (no change)"
- iam_role:
- name: "{{ test_role }}"
- create_instance_profile: yes
- register: iam_role
-
-- assert:
- that:
- - iam_role is not changed
- - iam_role.iam_role.role_name == test_role
-
-- name: "iam_role_info after Role creation"
- iam_role_info:
- name: "{{ test_role }}"
- register: role_info
-
-- assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 1
- - 'role_info.iam_roles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
- - '"assume_role_policy_document" in role_info.iam_roles[0]'
- - '"create_date" in role_info.iam_roles[0]'
- - '"description" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].inline_policies | length == 0
- - role_info.iam_roles[0].instance_profiles | length == 1
- - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
- - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
- - role_info.iam_roles[0].managed_policies | length == 0
- - role_info.iam_roles[0].max_session_duration == 3600
- - role_info.iam_roles[0].path == '/'
- - '"permissions_boundary" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
- - role_info.iam_roles[0].role_name == test_role
- - role_info.iam_roles[0].tags | length == 0
diff --git a/ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/description_update.yml b/ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/description_update.yml
deleted file mode 100644
index 85f5e1f56..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/description_update.yml
+++ /dev/null
@@ -1,148 +0,0 @@
----
-- name: "Add Description (CHECK MODE)"
- iam_role:
- name: "{{ test_role }}"
- description: "Ansible Test Role {{ resource_prefix }}"
- check_mode: yes
- register: iam_role
-
-- assert:
- that:
- - iam_role is changed
-
-- name: "Add Description"
- iam_role:
- name: "{{ test_role }}"
- description: "Ansible Test Role {{ resource_prefix }}"
- register: iam_role
-
-- assert:
- that:
- - iam_role is changed
- - iam_role.iam_role.role_name == test_role
- - iam_role.iam_role.description == 'Ansible Test Role {{ resource_prefix }}'
-
-- name: "Add Description (no change) - check mode"
- iam_role:
- name: "{{ test_role }}"
- description: "Ansible Test Role {{ resource_prefix }}"
- register: iam_role
- check_mode: yes
-
-- assert:
- that:
- - iam_role is not changed
-
-- name: "Add Description (no change)"
- iam_role:
- name: "{{ test_role }}"
- description: "Ansible Test Role {{ resource_prefix }}"
- register: iam_role
-
-- assert:
- that:
- - iam_role is not changed
- - iam_role.iam_role.role_name == test_role
- - iam_role.iam_role.description == 'Ansible Test Role {{ resource_prefix }}'
-
-- name: "iam_role_info after adding Description"
- iam_role_info:
- name: "{{ test_role }}"
- register: role_info
-
-- assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 1
- - 'role_info.iam_roles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
- - '"assume_role_policy_document" in role_info.iam_roles[0]'
- - '"create_date" in role_info.iam_roles[0]'
- - 'role_info.iam_roles[0].description == "Ansible Test Role {{ resource_prefix }}"'
- - role_info.iam_roles[0].inline_policies | length == 0
- - role_info.iam_roles[0].instance_profiles | length == 1
- - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
- - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
- - role_info.iam_roles[0].managed_policies | length == 0
- - role_info.iam_roles[0].max_session_duration == 43200
- - role_info.iam_roles[0].path == '/'
- - '"permissions_boundary" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
- - role_info.iam_roles[0].role_name == test_role
- - role_info.iam_roles[0].tags | length == 0
-
-# ------------------------------------------------------------------------------------------
-
-- name: "Update Description (CHECK MODE)"
- iam_role:
- name: "{{ test_role }}"
- description: "Ansible Test Role (updated) {{ resource_prefix }}"
- check_mode: yes
- register: iam_role
-
-- assert:
- that:
- - iam_role is changed
-
-- name: "Update Description"
- iam_role:
- name: "{{ test_role }}"
- description: "Ansible Test Role (updated) {{ resource_prefix }}"
- register: iam_role
-
-- assert:
- that:
- - iam_role is changed
- - iam_role.iam_role.role_name == test_role
- - iam_role.iam_role.description == 'Ansible Test Role (updated) {{ resource_prefix }}'
-
-- name: "Update Description (no change) - check mode"
- iam_role:
- name: "{{ test_role }}"
- description: "Ansible Test Role (updated) {{ resource_prefix }}"
- register: iam_role
- check_mode: yes
-
-- assert:
- that:
- - iam_role is not changed
-
-- name: "Update Description (no change)"
- iam_role:
- name: "{{ test_role }}"
- description: "Ansible Test Role (updated) {{ resource_prefix }}"
- register: iam_role
-
-- assert:
- that:
- - iam_role is not changed
- - iam_role.iam_role.role_name == test_role
- - iam_role.iam_role.description == 'Ansible Test Role (updated) {{ resource_prefix }}'
-
-- name: "iam_role_info after updating Description"
- iam_role_info:
- name: "{{ test_role }}"
- register: role_info
-
-- assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 1
- - 'role_info.iam_roles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
- - '"assume_role_policy_document" in role_info.iam_roles[0]'
- - '"create_date" in role_info.iam_roles[0]'
- - 'role_info.iam_roles[0].description == "Ansible Test Role (updated) {{ resource_prefix }}"'
- - role_info.iam_roles[0].inline_policies | length == 0
- - role_info.iam_roles[0].instance_profiles | length == 1
- - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
- - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
- - role_info.iam_roles[0].managed_policies | length == 0
- - role_info.iam_roles[0].max_session_duration == 43200
- - role_info.iam_roles[0].path == '/'
- - '"permissions_boundary" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
- - role_info.iam_roles[0].role_name == test_role
- - role_info.iam_roles[0].tags | length == 0
diff --git a/ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/inline_policy_update.yml b/ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/inline_policy_update.yml
deleted file mode 100644
index d364d87d7..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/inline_policy_update.yml
+++ /dev/null
@@ -1,48 +0,0 @@
----
-- name: "Attach inline policy a"
- iam_policy:
- state: present
- iam_type: "role"
- iam_name: "{{ test_role }}"
- policy_name: "inline-policy-a"
- policy_json: '{{ lookup("file", "deny-all-a.json") }}'
-
-- name: "Attach inline policy b"
- iam_policy:
- state: present
- iam_type: "role"
- iam_name: "{{ test_role }}"
- policy_name: "inline-policy-b"
- policy_json: '{{ lookup("file", "deny-all-b.json") }}'
-
-- name: "iam_role_info after attaching inline policies (using iam_policy)"
- iam_role_info:
- name: "{{ test_role }}"
- register: role_info
-- assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 1
- - 'role_info.iam_roles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
- - '"assume_role_policy_document" in role_info.iam_roles[0]'
- - '"create_date" in role_info.iam_roles[0]'
- - 'role_info.iam_roles[0].description == "Ansible Test Role (updated) {{ resource_prefix }}"'
- - role_info.iam_roles[0].inline_policies | length == 2
- - '"inline-policy-a" in role_info.iam_roles[0].inline_policies'
- - '"inline-policy-b" in role_info.iam_roles[0].inline_policies'
- - role_info.iam_roles[0].instance_profiles | length == 1
- - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
- - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
- - role_info.iam_roles[0].managed_policies | length == 1
- - safe_managed_policy not in ( role_info | community.general.json_query("iam_roles[*].managed_policies[*].policy_name") | list | flatten )
- - custom_policy_name in ( role_info | community.general.json_query("iam_roles[*].managed_policies[*].policy_name") | list | flatten )
- - role_info.iam_roles[0].max_session_duration == 43200
- - role_info.iam_roles[0].path == '/'
- - '"permissions_boundary" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
- - role_info.iam_roles[0].role_name == test_role
- - role_info.iam_roles[0].tags | length == 1
- - '"TagB" in role_info.iam_roles[0].tags'
- - role_info.iam_roles[0].tags.TagB == "ValueB"
diff --git a/ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/main.yml
deleted file mode 100644
index ae47ada1a..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/main.yml
+++ /dev/null
@@ -1,119 +0,0 @@
----
-# Tests for iam_role and iam_role_info
-#
-# Tests:
-# - Minimal Role creation
-# - Role deletion
-# - Fetching a specific role
-# - Creating roles w/ and w/o instance profiles
-# - Creating roles w/ a path
-# - Updating Max Session Duration
-# - Updating Description
-# - Managing list of managed policies
-# - Managing list of inline policies (for testing _info)
-# - Managing boundary policy
-#
-# Notes:
-# - Only tests *documented* return values ( RESULT.iam_role )
-# - There are some known timing issues with boto3 returning before actions
-# complete in the case of problems with "changed" status it's worth enabling
-# the standard_pauses and paranoid_pauses options as a first step in debugging
-
-
-- name: "Setup AWS connection info"
- module_defaults:
- group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
- region: "{{ aws_region }}"
- iam_role:
- assume_role_policy_document: '{{ lookup("file", "deny-assume.json") }}'
- collections:
- - amazon.aws
- - community.general
- block:
- - set_fact:
- assume_deny_policy: '{{ lookup("file", "deny-assume.json") | from_json }}'
- # ===================================================================
- # Parameter Checks
- - include_tasks: parameter_checks.yml
-
- # ===================================================================
- # Supplemental resource pre-creation
- - name: "Create Safe IAM Managed Policy"
- iam_managed_policy:
- state: present
- policy_name: "{{ custom_policy_name }}"
- policy_description: "A safe (deny-all) managed policy"
- policy: "{{ lookup('file', 'deny-all.json') }}"
- register: create_managed_policy
-
- - assert:
- that:
- - create_managed_policy is succeeded
-
- # ===================================================================
- # Rapid Role Creation and deletion
- - include_tasks: creation_deletion.yml
-
- # ===================================================================
- # Max Session Duration Manipulation
- - include_tasks: max_session_update.yml
-
- # ===================================================================
- # Description Manipulation
- - include_tasks: description_update.yml
-
- # ===================================================================
- # Tag Manipulation
- - include_tasks: tags_update.yml
-
- # ===================================================================
- # Policy Manipulation
- - include_tasks: policy_update.yml
-
- # ===================================================================
- # Inline Policy (test _info behavior)
- - include_tasks: inline_policy_update.yml
-
- # ===================================================================
- # Role Removal
- - include_tasks: role_removal.yml
-
- # ===================================================================
- # Boundary Policy (requires create_instance_profile: no)
- - include_tasks: boundary_policy.yml
-
- # ===================================================================
- # Complex role Creation
- - include_tasks: complex_role_creation.yml
-
- always:
- # ===================================================================
- # Cleanup
-
- - name: "Remove IAM Role"
- iam_role:
- state: absent
- name: "{{ test_role }}"
- delete_instance_profile: yes
- ignore_errors: true
-
- - name: "Remove IAM Role (with path)"
- iam_role:
- state: absent
- name: "{{ test_role }}"
- path: "{{ test_path }}"
- delete_instance_profile: yes
- ignore_errors: true
-
- - name: "iam_role_info after Role deletion"
- iam_role_info:
- name: "{{ test_role }}"
- ignore_errors: true
-
- - name: "Remove test managed policy"
- iam_managed_policy:
- state: absent
- policy_name: "{{ custom_policy_name }}"
diff --git a/ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/max_session_update.yml b/ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/max_session_update.yml
deleted file mode 100644
index 8ad3641be..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/max_session_update.yml
+++ /dev/null
@@ -1,71 +0,0 @@
----
-- name: "Update Max Session Duration (CHECK MODE)"
- iam_role:
- name: "{{ test_role }}"
- max_session_duration: 43200
- check_mode: yes
- register: iam_role
-
-- assert:
- that:
- - iam_role is changed
-
-- name: "Update Max Session Duration"
- iam_role:
- name: "{{ test_role }}"
- max_session_duration: 43200
- register: iam_role
-
-- assert:
- that:
- - iam_role is changed
- - iam_role.iam_role.role_name == test_role
- - iam_role.iam_role.max_session_duration == 43200
-
-- name: "Update Max Session Duration (no change)"
- iam_role:
- name: "{{ test_role }}"
- max_session_duration: 43200
- register: iam_role
-
-- assert:
- that:
- - iam_role is not changed
-
-- name: "Update Max Session Duration (no change) - check mode"
- iam_role:
- name: "{{ test_role }}"
- max_session_duration: 43200
- register: iam_role
- check_mode: yes
-
-- assert:
- that:
- - iam_role is not changed
-
-- name: "iam_role_info after updating Max Session Duration"
- iam_role_info:
- name: "{{ test_role }}"
- register: role_info
-
-- assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 1
- - 'role_info.iam_roles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
- - '"assume_role_policy_document" in role_info.iam_roles[0]'
- - '"create_date" in role_info.iam_roles[0]'
- - '"description" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].inline_policies | length == 0
- - role_info.iam_roles[0].instance_profiles | length == 1
- - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
- - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
- - role_info.iam_roles[0].managed_policies | length == 0
- - role_info.iam_roles[0].max_session_duration == 43200
- - role_info.iam_roles[0].path == '/'
- - '"permissions_boundary" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
- - role_info.iam_roles[0].role_name == test_role
- - role_info.iam_roles[0].tags | length == 0
diff --git a/ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/parameter_checks.yml b/ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/parameter_checks.yml
deleted file mode 100644
index 57df5436a..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/parameter_checks.yml
+++ /dev/null
@@ -1,90 +0,0 @@
----
-# Parameter Checks
-- name: "Friendly message when creating an instance profile and adding a boundary profile"
- iam_role:
- name: "{{ test_role }}"
- boundary: "{{ boundary_policy }}"
- register: iam_role
- ignore_errors: yes
-
-- assert:
- that:
- - iam_role is failed
- - '"boundary policy" in iam_role.msg'
- - '"create_instance_profile" in iam_role.msg'
- - '"false" in iam_role.msg'
-
-- name: "Friendly message when boundary profile is not an ARN"
- iam_role:
- name: "{{ test_role }}"
- boundary: "AWSDenyAll"
- create_instance_profile: no
- register: iam_role
- ignore_errors: yes
-
-- assert:
- that:
- - iam_role is failed
- - '"Boundary policy" in iam_role.msg'
- - '"ARN" in iam_role.msg'
-
-- name: 'Friendly message when "present" without assume_role_policy_document'
- module_defaults: { iam_role: {} }
- iam_role:
- name: "{{ test_role }}"
- register: iam_role
- ignore_errors: yes
-
-- assert:
- that:
- - iam_role is failed
- - 'iam_role.msg.startswith("state is present but all of the following are missing")'
- - '"assume_role_policy_document" in iam_role.msg'
-
-- name: "Maximum Session Duration needs to be between 1 and 12 hours"
- iam_role:
- name: "{{ test_role }}"
- max_session_duration: 3599
- register: iam_role
- ignore_errors: yes
-
-- assert:
- that:
- - iam_role is failed
- - '"max_session_duration must be between" in iam_role.msg'
-
-- name: "Maximum Session Duration needs to be between 1 and 12 hours"
- iam_role:
- name: "{{ test_role }}"
- max_session_duration: 43201
- register: iam_role
- ignore_errors: yes
-
-- assert:
- that:
- - iam_role is failed
- - '"max_session_duration must be between" in iam_role.msg'
-
-- name: "Role Paths must start with /"
- iam_role:
- name: "{{ test_role }}"
- path: "test/"
- register: iam_role
- ignore_errors: yes
-
-- assert:
- that:
- - iam_role is failed
- - '"path must begin and end with /" in iam_role.msg'
-
-- name: "Role Paths must end with /"
- iam_role:
- name: "{{ test_role }}"
- path: "/test"
- register: iam_role
- ignore_errors: yes
-
-- assert:
- that:
- - iam_role is failed
- - '"path must begin and end with /" in iam_role.msg'
diff --git a/ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/policy_update.yml b/ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/policy_update.yml
deleted file mode 100644
index a822edf74..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/policy_update.yml
+++ /dev/null
@@ -1,250 +0,0 @@
----
-- name: "Add Managed Policy (CHECK MODE)"
- iam_role:
- name: "{{ test_role }}"
- purge_policies: no
- managed_policy:
- - "{{ safe_managed_policy }}"
- check_mode: yes
- register: iam_role
-
-- assert:
- that:
- - iam_role is changed
-
-- name: "Add Managed Policy"
- iam_role:
- name: "{{ test_role }}"
- purge_policies: no
- managed_policy:
- - "{{ safe_managed_policy }}"
- register: iam_role
-
-- assert:
- that:
- - iam_role is changed
- - iam_role.iam_role.role_name == test_role
-
-- name: "Add Managed Policy (no change) - check mode"
- iam_role:
- name: "{{ test_role }}"
- purge_policies: no
- managed_policy:
- - "{{ safe_managed_policy }}"
- register: iam_role
- check_mode: yes
-
-- assert:
- that:
- - iam_role is not changed
-
-- name: "Add Managed Policy (no change)"
- iam_role:
- name: "{{ test_role }}"
- purge_policies: no
- managed_policy:
- - "{{ safe_managed_policy }}"
- register: iam_role
-
-- assert:
- that:
- - iam_role is not changed
- - iam_role.iam_role.role_name == test_role
-
-- name: "iam_role_info after adding Managed Policy"
- iam_role_info:
- name: "{{ test_role }}"
- register: role_info
-
-- assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 1
- - 'role_info.iam_roles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
- - '"assume_role_policy_document" in role_info.iam_roles[0]'
- - '"create_date" in role_info.iam_roles[0]'
- - 'role_info.iam_roles[0].description == "Ansible Test Role (updated) {{ resource_prefix }}"'
- - role_info.iam_roles[0].inline_policies | length == 0
- - role_info.iam_roles[0].instance_profiles | length == 1
- - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
- - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
- - role_info.iam_roles[0].managed_policies | length == 1
- - safe_managed_policy in ( role_info | community.general.json_query("iam_roles[*].managed_policies[*].policy_name") | list | flatten )
- - custom_policy_name not in ( role_info | community.general.json_query("iam_roles[*].managed_policies[*].policy_name") | list | flatten )
- - role_info.iam_roles[0].max_session_duration == 43200
- - role_info.iam_roles[0].path == '/'
- - '"permissions_boundary" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
- - role_info.iam_roles[0].role_name == test_role
- - role_info.iam_roles[0].tags | length == 1
- - '"TagB" in role_info.iam_roles[0].tags'
- - role_info.iam_roles[0].tags.TagB == "ValueB"
-
-# ------------------------------------------------------------------------------------------
-
-- name: "Update Managed Policy without purge (CHECK MODE)"
- iam_role:
- name: "{{ test_role }}"
- purge_policies: no
- managed_policy:
- - "{{ custom_policy_name }}"
- check_mode: yes
- register: iam_role
-
-- assert:
- that:
- - iam_role is changed
-
-- name: "Update Managed Policy without purge"
- iam_role:
- name: "{{ test_role }}"
- purge_policies: no
- managed_policy:
- - "{{ custom_policy_name }}"
- register: iam_role
-
-- assert:
- that:
- - iam_role is changed
- - iam_role.iam_role.role_name == test_role
-
-- name: "Update Managed Policy without purge (no change) - check mode"
- iam_role:
- name: "{{ test_role }}"
- purge_policies: no
- managed_policy:
- - "{{ custom_policy_name }}"
- register: iam_role
- check_mode: yes
-
-- assert:
- that:
- - iam_role is not changed
-
-- name: "Update Managed Policy without purge (no change)"
- iam_role:
- name: "{{ test_role }}"
- purge_policies: no
- managed_policy:
- - "{{ custom_policy_name }}"
- register: iam_role
-
-- assert:
- that:
- - iam_role is not changed
- - iam_role.iam_role.role_name == test_role
-
-- name: "iam_role_info after updating Managed Policy without purge"
- iam_role_info:
- name: "{{ test_role }}"
- register: role_info
-
-- assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 1
- - 'role_info.iam_roles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
- - '"assume_role_policy_document" in role_info.iam_roles[0]'
- - '"create_date" in role_info.iam_roles[0]'
- - 'role_info.iam_roles[0].description == "Ansible Test Role (updated) {{ resource_prefix }}"'
- - role_info.iam_roles[0].inline_policies | length == 0
- - role_info.iam_roles[0].instance_profiles | length == 1
- - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
- - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
- - role_info.iam_roles[0].managed_policies | length == 2
- - safe_managed_policy in ( role_info | community.general.json_query("iam_roles[*].managed_policies[*].policy_name") | list | flatten )
- - custom_policy_name in ( role_info | community.general.json_query("iam_roles[*].managed_policies[*].policy_name") | list | flatten )
- - role_info.iam_roles[0].max_session_duration == 43200
- - role_info.iam_roles[0].path == '/'
- - '"permissions_boundary" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
- - role_info.iam_roles[0].role_name == test_role
- - role_info.iam_roles[0].tags | length == 1
- - '"TagB" in role_info.iam_roles[0].tags'
- - role_info.iam_roles[0].tags.TagB == "ValueB"
-
-# ------------------------------------------------------------------------------------------
-
-# Managed Policies are purged by default
-- name: "Update Managed Policy with purge (CHECK MODE)"
- iam_role:
- name: "{{ test_role }}"
- managed_policy:
- - "{{ custom_policy_name }}"
- check_mode: yes
- register: iam_role
-
-- assert:
- that:
- - iam_role is changed
-
-- name: "Update Managed Policy with purge"
- iam_role:
- name: "{{ test_role }}"
- managed_policy:
- - "{{ custom_policy_name }}"
- register: iam_role
-
-- assert:
- that:
- - iam_role is changed
- - iam_role.iam_role.role_name == test_role
-
-- name: "Update Managed Policy with purge (no change) - check mode"
- iam_role:
- name: "{{ test_role }}"
- managed_policy:
- - "{{ custom_policy_name }}"
- register: iam_role
- check_mode: yes
-
-- assert:
- that:
- - iam_role is not changed
-
-- name: "Update Managed Policy with purge (no change)"
- iam_role:
- name: "{{ test_role }}"
- managed_policy:
- - "{{ custom_policy_name }}"
- register: iam_role
-
-- assert:
- that:
- - iam_role is not changed
- - iam_role.iam_role.role_name == test_role
-
-- name: "iam_role_info after updating Managed Policy with purge"
- iam_role_info:
- name: "{{ test_role }}"
- register: role_info
-
-- assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 1
- - 'role_info.iam_roles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
- - '"assume_role_policy_document" in role_info.iam_roles[0]'
- - '"create_date" in role_info.iam_roles[0]'
- - 'role_info.iam_roles[0].description == "Ansible Test Role (updated) {{ resource_prefix }}"'
- - role_info.iam_roles[0].inline_policies | length == 0
- - role_info.iam_roles[0].instance_profiles | length == 1
- - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
- - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
- - role_info.iam_roles[0].managed_policies | length == 1
- - safe_managed_policy not in ( role_info | community.general.json_query("iam_roles[*].managed_policies[*].policy_name") | list | flatten )
- - custom_policy_name in ( role_info | community.general.json_query("iam_roles[*].managed_policies[*].policy_name") | list | flatten )
- - role_info.iam_roles[0].max_session_duration == 43200
- - role_info.iam_roles[0].path == '/'
- - '"permissions_boundary" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
- - role_info.iam_roles[0].role_name == test_role
- - role_info.iam_roles[0].tags | length == 1
- - '"TagB" in role_info.iam_roles[0].tags'
- - role_info.iam_roles[0].tags.TagB == "ValueB"
diff --git a/ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/role_removal.yml b/ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/role_removal.yml
deleted file mode 100644
index ebcfd5453..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/role_removal.yml
+++ /dev/null
@@ -1,65 +0,0 @@
----
-- name: "Remove IAM Role (CHECK MODE)"
- iam_role:
- state: absent
- name: "{{ test_role }}"
- delete_instance_profile: yes
- check_mode: yes
- register: iam_role
-
-- assert:
- that:
- - iam_role is changed
-
-- name: "iam_role_info after deleting role in check mode"
- iam_role_info:
- name: "{{ test_role }}"
- register: role_info
-
-- assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 1
-
-- name: "Remove IAM Role"
- iam_role:
- state: absent
- name: "{{ test_role }}"
- delete_instance_profile: yes
- register: iam_role
-
-- assert:
- that:
- - iam_role is changed
-
-- name: "iam_role_info after deleting role"
- iam_role_info:
- name: "{{ test_role }}"
- register: role_info
-- assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 0
-
-- name: "Remove IAM Role (should be gone already) - check mode"
- iam_role:
- state: absent
- name: "{{ test_role }}"
- delete_instance_profile: yes
- register: iam_role
- check_mode: yes
-
-- assert:
- that:
- - iam_role is not changed
-
-- name: "Remove IAM Role (should be gone already)"
- iam_role:
- state: absent
- name: "{{ test_role }}"
- delete_instance_profile: yes
- register: iam_role
-
-- assert:
- that:
- - iam_role is not changed
diff --git a/ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/tags_update.yml b/ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/tags_update.yml
deleted file mode 100644
index 5eadd9fdf..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/iam_role/tasks/tags_update.yml
+++ /dev/null
@@ -1,341 +0,0 @@
----
-- name: "Add Tag (CHECK MODE)"
- iam_role:
- name: "{{ test_role }}"
- tags:
- TagA: ValueA
- check_mode: yes
- register: iam_role
-
-- assert:
- that:
- - iam_role is changed
-
-- name: "Add Tag"
- iam_role:
- name: "{{ test_role }}"
- tags:
- TagA: ValueA
- register: iam_role
-
-- assert:
- that:
- - iam_role is changed
- - iam_role.iam_role.role_name == test_role
- - iam_role.iam_role.tags | length == 1
- - '"TagA" in iam_role.iam_role.tags'
- - iam_role.iam_role.tags.TagA == "ValueA"
-
-- name: "Add Tag (no change) - check mode"
- iam_role:
- name: "{{ test_role }}"
- tags:
- TagA: ValueA
- register: iam_role
- check_mode: yes
-
-- assert:
- that:
- - iam_role is not changed
-
-- name: "Add Tag (no change)"
- iam_role:
- name: "{{ test_role }}"
- tags:
- TagA: ValueA
- register: iam_role
-
-- assert:
- that:
- - iam_role is not changed
- - iam_role.iam_role.role_name == test_role
- - '"TagA" in iam_role.iam_role.tags'
- - iam_role.iam_role.tags.TagA == "ValueA"
-
-- name: "iam_role_info after adding Tags"
- iam_role_info:
- name: "{{ test_role }}"
- register: role_info
-
-- assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 1
- - 'role_info.iam_roles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
- - '"assume_role_policy_document" in role_info.iam_roles[0]'
- - '"create_date" in role_info.iam_roles[0]'
- - 'role_info.iam_roles[0].description == "Ansible Test Role (updated) {{ resource_prefix }}"'
- - role_info.iam_roles[0].inline_policies | length == 0
- - role_info.iam_roles[0].instance_profiles | length == 1
- - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
- - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
- - role_info.iam_roles[0].managed_policies | length == 0
- - role_info.iam_roles[0].max_session_duration == 43200
- - role_info.iam_roles[0].path == '/'
- - '"permissions_boundary" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
- - role_info.iam_roles[0].role_name == test_role
- - role_info.iam_roles[0].tags | length == 1
- - '"TagA" in role_info.iam_roles[0].tags'
- - role_info.iam_roles[0].tags.TagA == "ValueA"
-
-# ------------------------------------------------------------------------------------------
-
-- name: "Update Tag (CHECK MODE)"
- iam_role:
- name: "{{ test_role }}"
- tags:
- TagA: AValue
- check_mode: yes
- register: iam_role
-
-- assert:
- that:
- - iam_role is changed
-
-- name: "Update Tag"
- iam_role:
- name: "{{ test_role }}"
- tags:
- TagA: AValue
- register: iam_role
-
-- assert:
- that:
- - iam_role is changed
- - iam_role.iam_role.role_name == test_role
- - '"TagA" in iam_role.iam_role.tags'
- - iam_role.iam_role.tags.TagA == "AValue"
-
-- name: "Update Tag (no change) - check mode"
- iam_role:
- name: "{{ test_role }}"
- tags:
- TagA: AValue
- register: iam_role
- check_mode: yes
-
-- assert:
- that:
- - iam_role is not changed
-
-- name: "Update Tag (no change)"
- iam_role:
- name: "{{ test_role }}"
- tags:
- TagA: AValue
- register: iam_role
-
-- assert:
- that:
- - iam_role is not changed
- - iam_role.iam_role.role_name == test_role
- - '"TagA" in iam_role.iam_role.tags'
- - iam_role.iam_role.tags.TagA == "AValue"
-
-- name: "iam_role_info after updating Tag"
- iam_role_info:
- name: "{{ test_role }}"
- register: role_info
-
-- assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 1
- - 'role_info.iam_roles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
- - '"assume_role_policy_document" in role_info.iam_roles[0]'
- - '"create_date" in role_info.iam_roles[0]'
- - 'role_info.iam_roles[0].description == "Ansible Test Role (updated) {{ resource_prefix }}"'
- - role_info.iam_roles[0].inline_policies | length == 0
- - role_info.iam_roles[0].instance_profiles | length == 1
- - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
- - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
- - role_info.iam_roles[0].managed_policies | length == 0
- - role_info.iam_roles[0].max_session_duration == 43200
- - role_info.iam_roles[0].path == '/'
- - '"permissions_boundary" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
- - role_info.iam_roles[0].role_name == test_role
- - role_info.iam_roles[0].tags | length == 1
- - '"TagA" in role_info.iam_roles[0].tags'
- - role_info.iam_roles[0].tags.TagA == "AValue"
-
-# ------------------------------------------------------------------------------------------
-
-- name: "Add second Tag without purge (CHECK MODE)"
- iam_role:
- name: "{{ test_role }}"
- purge_tags: no
- tags:
- TagB: ValueB
- check_mode: yes
- register: iam_role
-
-- assert:
- that:
- - iam_role is changed
-
-- name: "Add second Tag without purge"
- iam_role:
- name: "{{ test_role }}"
- purge_tags: no
- tags:
- TagB: ValueB
- register: iam_role
-
-- assert:
- that:
- - iam_role is changed
- - iam_role.iam_role.role_name == test_role
- - '"TagB" in iam_role.iam_role.tags'
- - iam_role.iam_role.tags.TagB == "ValueB"
-
-- name: "Add second Tag without purge (no change) - check mode"
- iam_role:
- name: "{{ test_role }}"
- purge_tags: no
- tags:
- TagB: ValueB
- register: iam_role
- check_mode: yes
-
-- assert:
- that:
- - iam_role is not changed
-
-- name: "Add second Tag without purge (no change)"
- iam_role:
- name: "{{ test_role }}"
- purge_tags: no
- tags:
- TagB: ValueB
- register: iam_role
-
-- assert:
- that:
- - iam_role is not changed
- - iam_role.iam_role.role_name == test_role
- - '"TagB" in iam_role.iam_role.tags'
- - iam_role.iam_role.tags.TagB == "ValueB"
-
-- name: "iam_role_info after adding second Tag without purge"
- iam_role_info:
- name: "{{ test_role }}"
- register: role_info
-
-- assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 1
- - 'role_info.iam_roles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
- - '"assume_role_policy_document" in role_info.iam_roles[0]'
- - '"create_date" in role_info.iam_roles[0]'
- - 'role_info.iam_roles[0].description == "Ansible Test Role (updated) {{ resource_prefix }}"'
- - role_info.iam_roles[0].inline_policies | length == 0
- - role_info.iam_roles[0].instance_profiles | length == 1
- - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
- - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
- - role_info.iam_roles[0].managed_policies | length == 0
- - role_info.iam_roles[0].max_session_duration == 43200
- - role_info.iam_roles[0].path == '/'
- - '"permissions_boundary" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
- - role_info.iam_roles[0].role_name == test_role
- - role_info.iam_roles[0].tags | length == 2
- - '"TagA" in role_info.iam_roles[0].tags'
- - role_info.iam_roles[0].tags.TagA == "AValue"
- - '"TagB" in role_info.iam_roles[0].tags'
- - role_info.iam_roles[0].tags.TagB == "ValueB"
-
-# ------------------------------------------------------------------------------------------
-
-- name: "Purge first tag (CHECK MODE)"
- iam_role:
- name: "{{ test_role }}"
- purge_tags: yes
- tags:
- TagB: ValueB
- check_mode: yes
- register: iam_role
-
-- assert:
- that:
- - iam_role is changed
-
-- name: "Purge first tag"
- iam_role:
- name: "{{ test_role }}"
- purge_tags: yes
- tags:
- TagB: ValueB
- register: iam_role
-
-- assert:
- that:
- - iam_role is changed
- - iam_role.iam_role.role_name == test_role
- - '"TagB" in iam_role.iam_role.tags'
- - iam_role.iam_role.tags.TagB == "ValueB"
-
-- name: "Purge first tag (no change) - check mode"
- iam_role:
- name: "{{ test_role }}"
- purge_tags: yes
- tags:
- TagB: ValueB
- register: iam_role
-
-- assert:
- that:
- - iam_role is not changed
-
-- name: "Purge first tag (no change)"
- iam_role:
- name: "{{ test_role }}"
- purge_tags: yes
- tags:
- TagB: ValueB
- register: iam_role
-
-- assert:
- that:
- - iam_role is not changed
- - iam_role.iam_role.role_name == test_role
- - '"TagB" in iam_role.iam_role.tags'
- - iam_role.iam_role.tags.TagB == "ValueB"
-
-- name: "iam_role_info after purging first Tag"
- iam_role_info:
- name: "{{ test_role }}"
- register: role_info
-
-- assert:
- that:
- - role_info is succeeded
- - role_info.iam_roles | length == 1
- - 'role_info.iam_roles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].arn.endswith("role/" + test_role )'
- - '"assume_role_policy_document" in role_info.iam_roles[0]'
- - '"create_date" in role_info.iam_roles[0]'
- - 'role_info.iam_roles[0].description == "Ansible Test Role (updated) {{ resource_prefix }}"'
- - role_info.iam_roles[0].inline_policies | length == 0
- - role_info.iam_roles[0].instance_profiles | length == 1
- - role_info.iam_roles[0].instance_profiles[0].instance_profile_name == test_role
- - 'role_info.iam_roles[0].instance_profiles[0].arn.startswith("arn")'
- - 'role_info.iam_roles[0].instance_profiles[0].arn.endswith("instance-profile/" + test_role)'
- - role_info.iam_roles[0].managed_policies | length == 0
- - role_info.iam_roles[0].max_session_duration == 43200
- - role_info.iam_roles[0].path == '/'
- - '"permissions_boundary" not in role_info.iam_roles[0]'
- - role_info.iam_roles[0].role_id == iam_role.iam_role.role_id
- - role_info.iam_roles[0].role_name == test_role
- - role_info.iam_roles[0].tags | length == 1
- - '"TagA" not in role_info.iam_roles[0].tags'
- - '"TagB" in role_info.iam_roles[0].tags'
- - role_info.iam_roles[0].tags.TagB == "ValueB"
diff --git a/ansible_collections/community/aws/tests/integration/targets/iam_saml_federation/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/iam_saml_federation/tasks/main.yml
index b061fc601..3098d4811 100644
--- a/ansible_collections/community/aws/tests/integration/targets/iam_saml_federation/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/iam_saml_federation/tasks/main.yml
@@ -1,9 +1,9 @@
- module_defaults:
group/aws:
region: "{{ aws_region }}"
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
collections:
- amazon.aws
block:
diff --git a/ansible_collections/community/aws/tests/integration/targets/iam_server_certificate/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/iam_server_certificate/tasks/main.yml
index 0cfab38c8..d50ebfe52 100644
--- a/ansible_collections/community/aws/tests/integration/targets/iam_server_certificate/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/iam_server_certificate/tasks/main.yml
@@ -11,9 +11,9 @@
#
- module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region }}'
block:
################################################
diff --git a/ansible_collections/community/aws/tests/integration/targets/inspector_target/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/inspector_target/tasks/main.yml
index 907e1ffdd..a32e3bd68 100644
--- a/ansible_collections/community/aws/tests/integration/targets/inspector_target/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/inspector_target/tasks/main.yml
@@ -4,14 +4,14 @@
- amazon.aws
module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region }}'
block:
- name: Create AWS Inspector Target Group
- aws_inspector_target:
+ inspector_target:
name: "{{ aws_inspector_scan_name }}"
state: present
tags:
@@ -20,7 +20,7 @@
register: target_group_create
- name: Create AWS Inspector Target Group (Verify)
- aws_inspector_target:
+ inspector_target:
name: "{{ aws_inspector_scan_name }}"
state: present
tags:
@@ -41,7 +41,7 @@
- target_group_create_verify.tags.changed == "no"
- name: Change AWS Inspector Target Group Tags
- aws_inspector_target:
+ inspector_target:
name: "{{ aws_inspector_scan_name }}"
state: present
tags:
@@ -50,7 +50,7 @@
register: target_group_tag_change
- name: Change AWS Inspector Target Group Tags (Verify)
- aws_inspector_target:
+ inspector_target:
name: "{{ aws_inspector_scan_name }}"
state: present
tags:
@@ -72,13 +72,13 @@
always:
- name: Delete AWS Inspector Target Group
- aws_inspector_target:
+ inspector_target:
name: "{{ aws_inspector_scan_name }}"
state: absent
register: target_group_delete
- name: Delete AWS Inspector Target Group (Verify)
- aws_inspector_target:
+ inspector_target:
name: "{{ aws_inspector_scan_name }}"
state: absent
register: target_group_delete_verify
diff --git a/ansible_collections/community/aws/tests/integration/targets/sts_assume_role/aliases b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/aliases
index 4ef4b2067..d528335bb 100644
--- a/ansible_collections/community/aws/tests/integration/targets/sts_assume_role/aliases
+++ b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/aliases
@@ -1 +1,2 @@
+time=20m
cloud/aws
diff --git a/ansible_collections/community/aws/tests/integration/targets/iam_access_key/meta/main.yml b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/meta/main.yml
index 32cf5dda7..32cf5dda7 100644
--- a/ansible_collections/community/aws/tests/integration/targets/iam_access_key/meta/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/meta/main.yml
diff --git a/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/create_inventory_config.yml b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/create_inventory_config.yml
new file mode 100644
index 000000000..f91a9fba3
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/create_inventory_config.yml
@@ -0,0 +1,16 @@
+---
+- hosts: 127.0.0.1
+ connection: local
+ gather_facts: no
+
+ vars:
+ template_name: "../templates/{{ template | default('inventory.j2') }}"
+
+ vars_files:
+ - vars/main.yml
+
+ tasks:
+ - name: write inventory config file
+ copy:
+ dest: ../test.aws_mq.yml
+ content: "{{ lookup('template', template_name) }}"
diff --git a/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/empty_inventory_config.yml b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/empty_inventory_config.yml
new file mode 100644
index 000000000..6bc277e2a
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/empty_inventory_config.yml
@@ -0,0 +1,9 @@
+---
+- hosts: 127.0.0.1
+ connection: local
+ gather_facts: no
+ tasks:
+ - name: write inventory config file
+ copy:
+ dest: ../test.aws_mq.yml
+ content: ""
diff --git a/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/populate_cache.yml b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/populate_cache.yml
new file mode 100644
index 000000000..dff6ede2f
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/populate_cache.yml
@@ -0,0 +1,32 @@
+---
+- hosts: 127.0.0.1
+ connection: local
+ gather_facts: no
+
+ environment: "{{ ansible_test.environment }}"
+
+ module_defaults:
+ group/aws:
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
+ region: '{{ aws_region }}'
+
+ collections:
+ - community.aws
+
+ vars_files:
+ - vars/main.yml
+
+ tasks:
+ - name: refresh inventory to populate cache
+ meta: refresh_inventory
+
+ - name: assert group was populated with inventory but is empty
+ assert:
+ that:
+ - "'aws_mq' in groups"
+ - "groups.aws_mq | length == 1"
+
+ - name: Delete MQ instance
+ include_tasks: tasks/mq_instance_delete.yml \ No newline at end of file
diff --git a/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/setup_instance.yml b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/setup_instance.yml
new file mode 100644
index 000000000..fcea9cd8c
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/setup_instance.yml
@@ -0,0 +1,29 @@
+---
+- hosts: 127.0.0.1
+ connection: local
+ gather_facts: no
+
+ vars:
+ env_vars:
+ AWS_ACCESS_KEY_ID: '{{ aws_access_key }}'
+ AWS_SECRET_ACCESS_KEY: '{{ aws_secret_key }}'
+ AWS_DEFAULT_REGION: '{{ aws_region }}'
+ AWS_SECURITY_TOKEN: '{{ security_token }}'
+
+ environment: "{{ ansible_test.environment | combine(env_vars) }}"
+
+ module_defaults:
+ group/aws:
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
+ region: '{{ aws_region }}'
+
+ collections:
+ - community.aws
+
+ vars_files:
+ - vars/main.yml
+
+ tasks:
+ - include_tasks: 'tasks/mq_instance_{{ operation }}.yml'
diff --git a/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/tasks/find_broker.yml b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/tasks/find_broker.yml
new file mode 100644
index 000000000..e5f76d0a5
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/tasks/find_broker.yml
@@ -0,0 +1,10 @@
+---
+- name: Find broker by name
+ community.aws.mq_broker_info:
+ broker_name: "{{ broker_name }}"
+ register: broker_info
+ failed_when: false
+
+- name: Find broker by name, if exists
+ set_fact:
+ broker_exists: "{{ not (('Invalid type for parameter BrokerId, value: None' in broker_info.msg) | bool) }}"
diff --git a/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/tasks/mq_instance_create.yml b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/tasks/mq_instance_create.yml
new file mode 100644
index 000000000..88f60c093
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/tasks/mq_instance_create.yml
@@ -0,0 +1,27 @@
+---
+# using command module until #1832 is resolved
+- include_tasks: find_broker.yml
+- block:
+ - name: Get engine versions
+ command: >
+ aws mq describe-broker-engine-types --engine {{ engine }}
+ register: describe_engine_result
+
+ - name: Select latest engine version
+ set_fact:
+ engine_version: "{{ ( describe_engine_result.stdout | from_json ).BrokerEngineTypes[0].EngineVersions | map(attribute='Name') | sort | max }}"
+
+ - name: Create minimal MQ instance in default VPC and default subnet group
+ command: >
+ aws mq create-broker
+ --broker-name {{ broker_name }}
+ --deployment-mode SINGLE_INSTANCE
+ --engine-type {{ engine }}
+ --engine-version {{ engine_version }}
+ {% if resource_tags is defined %}--tags '{{ resource_tags | to_json }}'{% endif %}
+ --host-instance-type mq.t3.micro
+ --users=ConsoleAccess=True,Groups=admin,Password=aODvFQAt4tt1W,Username=master
+ --auto-minor-version-upgrade
+ --no-publicly-accessible
+ when:
+ - not broker_exists \ No newline at end of file
diff --git a/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/tasks/mq_instance_delete.yml b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/tasks/mq_instance_delete.yml
new file mode 100644
index 000000000..b533ee86b
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/tasks/mq_instance_delete.yml
@@ -0,0 +1,13 @@
+---
+- name: remove broker instance
+ community.aws.mq_broker:
+ state: absent
+ engine_type: "{{ engine }}"
+ broker_name: '{{ broker_name }}'
+ register: delete_result
+ failed_when:
+ - delete_result.get('failed',false)
+ - (delete_result.get('message','')).find('be deleted while in state [CREATION_IN_PROGRESS]') == -1
+ until: (delete_result.get('message','')).find('be deleted while in state [CREATION_IN_PROGRESS]') == -1
+ retries: 150
+ delay: 60
diff --git a/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/test_invalid_aws_mq_inventory_config.yml b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/test_invalid_aws_mq_inventory_config.yml
new file mode 100644
index 000000000..c982d0d9e
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/test_invalid_aws_mq_inventory_config.yml
@@ -0,0 +1,9 @@
+---
+- hosts: 127.0.0.1
+ connection: local
+ gather_facts: no
+ tasks:
+ - name: assert inventory was not populated by aws_mq inventory plugin
+ assert:
+ that:
+ - "'aws_mq' not in groups"
diff --git a/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/test_inventory_cache.yml b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/test_inventory_cache.yml
new file mode 100644
index 000000000..8926cefa2
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/test_inventory_cache.yml
@@ -0,0 +1,18 @@
+---
+- hosts: 127.0.0.1
+ connection: local
+ gather_facts: no
+ tasks:
+ - name: assert cache was used to populate inventory
+ assert:
+ that:
+ - "'aws_mq' in groups"
+ - "groups.aws_mq | length == 1"
+
+ - meta: refresh_inventory
+
+ - name: assert refresh_inventory updated the cache
+ assert:
+ that:
+ - "'aws_mq' in groups"
+ - "not groups.aws_mq"
diff --git a/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/test_inventory_no_hosts.yml b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/test_inventory_no_hosts.yml
new file mode 100644
index 000000000..4873adc92
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/test_inventory_no_hosts.yml
@@ -0,0 +1,16 @@
+---
+- hosts: 127.0.0.1
+ connection: local
+ gather_facts: no
+
+ environment: "{{ ansible_test.environment }}"
+
+ collections:
+ - community.aws
+ tasks:
+ - debug: var=groups
+ - name: assert group was populated with inventory but is empty
+ assert:
+ that:
+ - "'aws_mq' in groups"
+ - groups.aws_mq | length == 0
diff --git a/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/test_inventory_with_hostvars_prefix_suffix.yml b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/test_inventory_with_hostvars_prefix_suffix.yml
new file mode 100644
index 000000000..2db7f76ab
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/test_inventory_with_hostvars_prefix_suffix.yml
@@ -0,0 +1,30 @@
+---
+- hosts: 127.0.0.1
+ connection: local
+ gather_facts: no
+
+ environment: "{{ ansible_test.environment }}"
+
+ collections:
+ - community.aws
+
+ vars_files:
+ - vars/main.yml
+
+ tasks:
+
+ - name: assert the hostvars are defined with prefix and/or suffix
+ assert:
+ that:
+ - "hostvars[broker_name][vars_prefix ~ 'host_instance_type' ~ vars_suffix] == 'mq.t3.micro'"
+ - "hostvars[broker_name][vars_prefix ~ 'engine_type' ~ vars_suffix] == engine"
+ - "hostvars[broker_name][vars_prefix ~ 'broker_state' ~ vars_suffix] in ('CREATION_IN_PROGRESS', 'RUNNING')"
+ - "'host_instance_type' not in hostvars[broker_name]"
+ - "'engine_type' not in hostvars[broker_name]"
+ - "'broker_state' not in hostvars[broker_name]"
+ - "'ansible_diff_mode' in hostvars[broker_name]"
+ - "'ansible_forks' in hostvars[broker_name]"
+ - "'ansible_version' in hostvars[broker_name]"
+ vars:
+ vars_prefix: "{{ inventory_prefix | default('') }}"
+ vars_suffix: "{{ inventory_suffix | default('') }}"
diff --git a/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/test_populating_inventory.yml b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/test_populating_inventory.yml
new file mode 100644
index 000000000..a71043c70
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/test_populating_inventory.yml
@@ -0,0 +1,17 @@
+---
+- hosts: 127.0.0.1
+ connection: local
+ gather_facts: no
+
+ environment: "{{ ansible_test.environment }}"
+
+ vars_files:
+ - vars/main.yml
+
+ tasks:
+ - name: assert aws_mq inventory group contains MQ instance created by previous playbook
+ assert:
+ that:
+ - "'aws_mq' in groups"
+ - "groups.aws_mq | length == 1"
+ - groups.aws_mq.0 == broker_name
diff --git a/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/test_populating_inventory_with_constructed.yml b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/test_populating_inventory_with_constructed.yml
new file mode 100644
index 000000000..8d840158f
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/test_populating_inventory_with_constructed.yml
@@ -0,0 +1,27 @@
+---
+- hosts: 127.0.0.1
+ connection: local
+ gather_facts: no
+
+ environment: "{{ ansible_test.environment }}"
+ collections:
+ - community.aws
+
+ vars_files:
+ - vars/main.yml
+
+ tasks:
+
+ - debug:
+ var: groups
+
+ - name: assert the keyed groups from constructed config were added to inventory
+ assert:
+ that:
+ # There are 5 groups: all, ungrouped, aws_mq, tag and engine_type keyed group
+ - "groups | length == 5"
+ - '"all" in groups'
+ - '"ungrouped" in groups'
+ - '"aws_mq" in groups'
+ - '"tag_workload_type_other" in groups'
+ - '"mq_ACTIVEMQ" in groups'
diff --git a/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/vars/main.yml b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/vars/main.yml
new file mode 100644
index 000000000..2f599201c
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/playbooks/vars/main.yml
@@ -0,0 +1,6 @@
+---
+broker_name: "{{ resource_prefix }}-activemq"
+engine: "ACTIVEMQ"
+resource_tags:
+ workload_type: other
+aws_inventory_cache_dir: ""
diff --git a/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/runme.sh b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/runme.sh
new file mode 100755
index 000000000..68a3eda4b
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/runme.sh
@@ -0,0 +1,72 @@
+#!/usr/bin/env bash
+
+set -eux
+
+function cleanup() {
+ ansible-playbook playbooks/setup_instance.yml -e "operation=delete" "$@"
+ exit 1
+}
+
+trap 'cleanup "${@}"' ERR
+
+# ensure test config is empty
+ansible-playbook playbooks/empty_inventory_config.yml "$@"
+
+export ANSIBLE_INVENTORY_ENABLED="community.aws.aws_mq"
+
+# test with default inventory file
+ansible-playbook playbooks/test_invalid_aws_mq_inventory_config.yml "$@"
+
+export ANSIBLE_INVENTORY=test.aws_mq.yml
+
+# test empty inventory config
+ansible-playbook playbooks/test_invalid_aws_mq_inventory_config.yml "$@"
+
+# delete existing resources
+ansible-playbook playbooks/setup_instance.yml -e "operation=delete" "$@"
+
+# generate inventory config and test using it
+ansible-playbook playbooks/create_inventory_config.yml "$@"
+
+# test inventory with no hosts
+ansible-playbook playbooks/test_inventory_no_hosts.yml "$@"
+
+# create MQ resources
+ansible-playbook playbooks/setup_instance.yml -e "operation=create" "$@"
+
+# test inventory populated with MQ instance
+ansible-playbook playbooks/test_populating_inventory.yml "$@"
+
+# generate inventory config with constructed features and test using it
+ansible-playbook playbooks/create_inventory_config.yml -e "template='inventory_with_constructed.j2'" "$@"
+ansible-playbook playbooks/test_populating_inventory_with_constructed.yml "$@"
+
+# generate inventory config with hostvars_prefix features and test using it
+ansible-playbook playbooks/create_inventory_config.yml -e "template='inventory_with_hostvars_prefix_suffix.j2'" -e "inventory_prefix='aws_mq_'" "$@"
+ansible-playbook playbooks/test_inventory_with_hostvars_prefix_suffix.yml -e "inventory_prefix='aws_mq_'" "$@"
+
+# generate inventory config with hostvars_suffix features and test using it
+ansible-playbook playbooks/create_inventory_config.yml -e "template='inventory_with_hostvars_prefix_suffix.j2'" -e "inventory_suffix='_aws_mq'" "$@"
+ansible-playbook playbooks/test_inventory_with_hostvars_prefix_suffix.yml -e "inventory_suffix='_aws_mq'" "$@"
+
+# generate inventory config with hostvars_prefix and hostvars_suffix features and test using it
+ansible-playbook playbooks/create_inventory_config.yml -e "template='inventory_with_hostvars_prefix_suffix.j2'" -e "inventory_prefix='aws_'" -e "inventory_suffix='_mq'" "$@"
+ansible-playbook playbooks/test_inventory_with_hostvars_prefix_suffix.yml -e "inventory_prefix='aws_'" -e "inventory_suffix='_mq'" "$@"
+
+# generate inventory config with statuses and test using it
+ansible-playbook playbooks/create_inventory_config.yml -e '{"inventory_statuses": true}' "$@"
+ansible-playbook playbooks/test_inventory_no_hosts.yml "$@"
+
+# generate inventory config with caching and test using it
+AWS_MQ_CACHE_DIR="aws_mq_cache_dir"
+rm -rf "${AWS_MQ_CACHE_DIR}"
+ansible-playbook playbooks/create_inventory_config.yml -e "template='inventory_with_cache.j2'" -e "aws_inventory_cache_dir=$AWS_MQ_CACHE_DIR" "$@"
+ansible-playbook playbooks/populate_cache.yml "$@"
+ansible-playbook playbooks/test_inventory_cache.yml "$@"
+rm -rf "${AWS_MQ_CACHE_DIR}"
+
+# cleanup inventory config
+ansible-playbook playbooks/empty_inventory_config.yml "$@"
+
+ansible-playbook playbooks/setup_instance.yml -e "operation=delete" "$@"
+
diff --git a/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/templates/inventory.j2 b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/templates/inventory.j2
new file mode 100644
index 000000000..25fa80918
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/templates/inventory.j2
@@ -0,0 +1,12 @@
+plugin: community.aws.aws_mq
+access_key: '{{ aws_access_key }}'
+secret_key: '{{ aws_secret_key }}'
+{% if security_token | default(false) %}
+session_token: '{{ security_token }}'
+{% endif %}
+regions:
+ - '{{ aws_region }}'
+{% if inventory_statuses | default(false) %}
+statuses:
+ - CREATION_FAILED
+{% endif %}
diff --git a/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/templates/inventory_with_cache.j2 b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/templates/inventory_with_cache.j2
new file mode 100644
index 000000000..10941a8d5
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/templates/inventory_with_cache.j2
@@ -0,0 +1,11 @@
+plugin: community.aws.aws_mq
+cache: True
+cache_plugin: jsonfile
+cache_connection: '{{ aws_inventory_cache_dir }}'
+access_key: '{{ aws_access_key }}'
+secret_key: '{{ aws_secret_key }}'
+{% if security_token | default(false) %}
+session_token: '{{ security_token }}'
+{% endif %}
+regions:
+ - '{{ aws_region }}'
diff --git a/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/templates/inventory_with_constructed.j2 b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/templates/inventory_with_constructed.j2
new file mode 100644
index 000000000..7b421ace4
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/templates/inventory_with_constructed.j2
@@ -0,0 +1,13 @@
+plugin: community.aws.aws_mq
+access_key: '{{ aws_access_key }}'
+secret_key: '{{ aws_secret_key }}'
+{% if security_token | default(false) %}
+session_token: '{{ security_token }}'
+{% endif %}
+regions:
+ - '{{ aws_region }}'
+keyed_groups:
+ - key: tags
+ prefix: tag
+ - key: engine_type
+ prefix: mq
diff --git a/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/templates/inventory_with_hostvars_prefix_suffix.j2 b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/templates/inventory_with_hostvars_prefix_suffix.j2
new file mode 100644
index 000000000..13bc6ffa8
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/inventory_aws_mq/templates/inventory_with_hostvars_prefix_suffix.j2
@@ -0,0 +1,14 @@
+plugin: community.aws.aws_mq
+access_key: '{{ aws_access_key }}'
+secret_key: '{{ aws_secret_key }}'
+{% if security_token | default(false) %}
+session_token: '{{ security_token }}'
+{% endif %}
+regions:
+ - '{{ aws_region }}'
+{% if inventory_prefix | default(false) %}
+hostvars_prefix: '{{ inventory_prefix }}'
+{% endif %}
+{% if inventory_suffix | default(false) %}
+hostvars_suffix: '{{ inventory_suffix }}'
+{% endif %}
diff --git a/ansible_collections/community/aws/tests/integration/targets/kinesis_stream/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/kinesis_stream/tasks/main.yml
index b6791fb06..f219f0ae6 100644
--- a/ansible_collections/community/aws/tests/integration/targets/kinesis_stream/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/kinesis_stream/tasks/main.yml
@@ -3,9 +3,9 @@
- name: 'Setup AWS Module Defaults'
module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region }}'
kinesis_stream:
# Number of shards is mandatory when state=present
@@ -23,13 +23,13 @@
# Note: Because we're not a producer / consumer we don't actually need
# access to the keys
- name: 'Create KMS key 1'
- aws_kms:
+ kms_key:
alias: '{{ kms_cmk_alias_1 }}'
state: present
enabled: yes
register: create_kms_1
- name: 'Create KMS key 2'
- aws_kms:
+ kms_key:
alias: '{{ kms_cmk_alias_2 }}'
state: present
enabled: yes
@@ -680,7 +680,7 @@
block:
- name: 'Delete the KMS keys'
ignore_errors: yes
- aws_kms:
+ kms_key:
state: absent
alias: '{{ item }}'
loop:
diff --git a/ansible_collections/community/aws/tests/integration/targets/legacy_missing_tests/aliases b/ansible_collections/community/aws/tests/integration/targets/legacy_missing_tests/aliases
index 27c4351c4..edfaa127e 100644
--- a/ansible_collections/community/aws/tests/integration/targets/legacy_missing_tests/aliases
+++ b/ansible_collections/community/aws/tests/integration/targets/legacy_missing_tests/aliases
@@ -5,9 +5,6 @@ application_scaling_policy
batch_compute_environment
batch_job_definition
batch_job_queue
-cloudfront_distribution_info
-cloudfront_invalidation
-cloudfront_origin_access_identity
data_pipeline
directconnect_confirm_connection
directconnect_connection
diff --git a/ansible_collections/community/aws/tests/integration/targets/lightsail/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/lightsail/tasks/main.yml
index 91f13a8ba..18e76756d 100644
--- a/ansible_collections/community/aws/tests/integration/targets/lightsail/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/lightsail/tasks/main.yml
@@ -2,10 +2,10 @@
- module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key | default(omit) }}'
- aws_secret_key: '{{ aws_secret_key | default(omit) }}'
- security_token: '{{ security_token | default(omit) }}'
- region: '{{ aws_region | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
+ region: '{{ aws_region }}'
block:
@@ -15,8 +15,14 @@
lightsail:
name: "{{ instance_name }}"
zone: "{{ zone }}"
- blueprint_id: amazon_linux
+ blueprint_id: amazon_linux_2
bundle_id: nano_2_0
+ public_ports:
+ - from_port: 50
+ to_port: 50
+ protocol: "tcp"
+ cidrs: ["0.0.0.0/0"]
+ ipv6_cidrs: ["::/0"]
wait: yes
register: result
@@ -25,8 +31,10 @@
- result.changed == True
- "'instance' in result and result.instance.name == instance_name"
- "result.instance.state.name == 'running'"
+ - "result.instance.networking.ports[0].from_port == 50"
+ - result.instance.networking.ports|length == 1
- - name: Make sure create is idempotent
+ - name: Check if it does not delete public ports config when no value is provided
lightsail:
name: "{{ instance_name }}"
zone: "{{ zone }}"
@@ -38,6 +46,24 @@
that:
- result.changed == False
+ - name: Make sure create is idempotent
+ lightsail:
+ name: "{{ instance_name }}"
+ zone: "{{ zone }}"
+ blueprint_id: amazon_linux_2
+ bundle_id: nano_2_0
+ public_ports:
+ - from_port: 50
+ to_port: 50
+ protocol: "tcp"
+ cidrs: ["0.0.0.0/0"]
+ ipv6_cidrs: ["::/0"]
+ register: result
+
+ - assert:
+ that:
+ - result.changed == False
+
- name: Start the running instance
lightsail:
name: "{{ instance_name }}"
diff --git a/ansible_collections/community/aws/tests/integration/targets/aws_region_info/aliases b/ansible_collections/community/aws/tests/integration/targets/lightsail_snapshot/aliases
index 4ef4b2067..4ef4b2067 100644
--- a/ansible_collections/community/aws/tests/integration/targets/aws_region_info/aliases
+++ b/ansible_collections/community/aws/tests/integration/targets/lightsail_snapshot/aliases
diff --git a/ansible_collections/community/aws/tests/integration/targets/lightsail_snapshot/defaults/main.yml b/ansible_collections/community/aws/tests/integration/targets/lightsail_snapshot/defaults/main.yml
new file mode 100644
index 000000000..5866de4ec
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/lightsail_snapshot/defaults/main.yml
@@ -0,0 +1,3 @@
+instance_name: "{{ resource_prefix }}_instance"
+snapshot_name: "{{ resource_prefix }}_instance_snapshot"
+zone: "{{ aws_region }}a"
diff --git a/ansible_collections/community/aws/tests/integration/targets/iam_group/meta/main.yml b/ansible_collections/community/aws/tests/integration/targets/lightsail_snapshot/meta/main.yml
index 32cf5dda7..32cf5dda7 100644
--- a/ansible_collections/community/aws/tests/integration/targets/iam_group/meta/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/lightsail_snapshot/meta/main.yml
diff --git a/ansible_collections/community/aws/tests/integration/targets/lightsail_snapshot/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/lightsail_snapshot/tasks/main.yml
new file mode 100644
index 000000000..98553d278
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/lightsail_snapshot/tasks/main.yml
@@ -0,0 +1,85 @@
+---
+
+- module_defaults:
+ group/aws:
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
+ region: '{{ aws_region }}'
+
+ block:
+
+ # ==== Tests ===================================================
+
+ - name: Create a new instance
+ lightsail:
+ name: "{{ instance_name }}"
+ zone: "{{ zone }}"
+ blueprint_id: amazon_linux_2
+ bundle_id: nano_2_0
+ wait: yes
+
+ - name: Create a new snapshot
+ lightsail_snapshot:
+ snapshot_name: "{{ snapshot_name }}"
+ instance_name: "{{ instance_name }}"
+ region: "{{ aws_region }}"
+ wait: yes
+ register: result
+
+ - assert:
+ that:
+ - result.changed == True
+ - "'instance_snapshot' in result and result.instance_snapshot.name == snapshot_name"
+ - "result.instance_snapshot.state == 'available'"
+
+ - name: Make sure instance snapshot creation is idempotent
+ lightsail_snapshot:
+ snapshot_name: "{{ snapshot_name }}"
+ instance_name: "{{ instance_name }}"
+ region: "{{ aws_region }}"
+ wait: yes
+ register: result
+
+ - assert:
+ that:
+ - result.changed == False
+
+ - name: Delete the instance snapshot
+ lightsail_snapshot:
+ snapshot_name: "{{ snapshot_name }}"
+ region: "{{ aws_region }}"
+ state: absent
+ register: result
+
+ - assert:
+ that:
+ - result.changed == True
+
+ - name: Make sure instance snapshot deletion is idempotent
+ lightsail_snapshot:
+ snapshot_name: "{{ snapshot_name }}"
+ region: "{{ aws_region }}"
+ state: absent
+ register: result
+
+ - assert:
+ that:
+ - result.changed == False
+
+ # ==== Cleanup ====================================================
+
+ always:
+
+ - name: Cleanup - delete instance snapshot
+ lightsail_snapshot:
+ snapshot_name: "{{ snapshot_name }}"
+ region: "{{ aws_region }}"
+ state: absent
+ ignore_errors: yes
+
+ - name: Cleanup - delete instance
+ lightsail:
+ name: "{{ instance_name }}"
+ state: absent
+ ignore_errors: yes
diff --git a/ansible_collections/community/aws/tests/integration/targets/lightsail_static_ip/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/lightsail_static_ip/tasks/main.yml
index f8f327344..e0b452f3e 100644
--- a/ansible_collections/community/aws/tests/integration/targets/lightsail_static_ip/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/lightsail_static_ip/tasks/main.yml
@@ -2,10 +2,10 @@
- module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key | default(omit) }}'
- aws_secret_key: '{{ aws_secret_key | default(omit) }}'
- security_token: '{{ security_token | default(omit) }}'
- region: '{{ aws_region | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
+ region: '{{ aws_region }}'
block:
diff --git a/ansible_collections/community/aws/tests/integration/targets/mq/aliases b/ansible_collections/community/aws/tests/integration/targets/mq/aliases
new file mode 100644
index 000000000..fef8ae9bd
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/mq/aliases
@@ -0,0 +1,13 @@
+# reason: missing-policy
+# We don't have CI or 'unsupported' policy for Amazon MQ, yet
+# reason: slow
+# tests run about 30 minutes
+unsupported
+
+cloud/aws
+
+mq_broker_info
+mq_broker
+mq_broker_config
+mq_user_info
+mq_user
diff --git a/ansible_collections/community/aws/tests/integration/targets/mq/defaults/main.yml b/ansible_collections/community/aws/tests/integration/targets/mq/defaults/main.yml
new file mode 100644
index 000000000..2199c2f63
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/mq/defaults/main.yml
@@ -0,0 +1,9 @@
+---
+# default files for mq_*
+broker_name: '{{resource_prefix}}-mq'
+vpc_name: "{{ resource_prefix }}-vpc"
+vpc_cidr: "10.0.0.0/16"
+subnet_cidr: "10.0.1.0/24"
+sg_name: "{{resource_prefix}}-sg"
+tags:
+ workload_type: other \ No newline at end of file
diff --git a/ansible_collections/community/aws/tests/integration/targets/mq/files/broker_cfg.1.xml b/ansible_collections/community/aws/tests/integration/targets/mq/files/broker_cfg.1.xml
new file mode 100644
index 000000000..0fdc98e46
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/mq/files/broker_cfg.1.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<broker schedulePeriodForDestinationPurge="10000" xmlns="http://activemq.apache.org/schema/core">
+ <!-- update 1 -->
+ <destinationPolicy>
+ <policyMap>
+ <policyEntries>
+ <policyEntry gcInactiveDestinations="true" inactiveTimoutBeforeGC="600000" topic="&gt;">
+ <pendingMessageLimitStrategy>
+ <constantPendingMessageLimitStrategy limit="1000"/>
+ </pendingMessageLimitStrategy>
+ </policyEntry>
+ <policyEntry gcInactiveDestinations="true" inactiveTimoutBeforeGC="600000" queue="&gt;"/>
+ </policyEntries>
+ </policyMap>
+ </destinationPolicy>
+ <plugins/>
+</broker>
diff --git a/ansible_collections/community/aws/tests/integration/targets/mq/files/broker_cfg.1a.xml b/ansible_collections/community/aws/tests/integration/targets/mq/files/broker_cfg.1a.xml
new file mode 100644
index 000000000..b374d1357
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/mq/files/broker_cfg.1a.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<broker schedulePeriodForDestinationPurge="10000" xmlns="http://activemq.apache.org/schema/core">
+ <!-- update 1 -->
+
+ <destinationPolicy>
+ <policyMap>
+ <policyEntries>
+ <policyEntry gcInactiveDestinations="true" inactiveTimoutBeforeGC="600000" topic="&gt;">
+ <pendingMessageLimitStrategy>
+ <constantPendingMessageLimitStrategy limit="1000"/>
+ </pendingMessageLimitStrategy>
+ </policyEntry>
+ <policyEntry gcInactiveDestinations="true" inactiveTimoutBeforeGC="600000" queue="&gt;"/>
+ </policyEntries>
+ </policyMap>
+ </destinationPolicy>
+ <plugins/>
+
+</broker>
+
+
diff --git a/ansible_collections/community/aws/tests/integration/targets/mq/files/broker_cfg.2.xml b/ansible_collections/community/aws/tests/integration/targets/mq/files/broker_cfg.2.xml
new file mode 100644
index 000000000..0d10ebdc6
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/mq/files/broker_cfg.2.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<broker schedulePeriodForDestinationPurge="10000" xmlns="http://activemq.apache.org/schema/core">
+ <!-- update 2 -->
+ <destinationPolicy>
+ <policyMap>
+ <policyEntries>
+ <policyEntry gcInactiveDestinations="true" inactiveTimoutBeforeGC="600000" topic="&gt;">
+ <pendingMessageLimitStrategy>
+ <constantPendingMessageLimitStrategy limit="1000"/>
+ </pendingMessageLimitStrategy>
+ </policyEntry>
+ <policyEntry gcInactiveDestinations="true" inactiveTimoutBeforeGC="600000" queue="&gt;"/>
+ </policyEntries>
+ </policyMap>
+ </destinationPolicy>
+ <plugins/>
+</broker>
diff --git a/ansible_collections/community/aws/tests/integration/targets/iam_managed_policy/meta/main.yml b/ansible_collections/community/aws/tests/integration/targets/mq/meta/main.yml
index 32cf5dda7..32cf5dda7 100644
--- a/ansible_collections/community/aws/tests/integration/targets/iam_managed_policy/meta/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/mq/meta/main.yml
diff --git a/ansible_collections/community/aws/tests/integration/targets/mq/tasks/broker_cleanup.yml b/ansible_collections/community/aws/tests/integration/targets/mq/tasks/broker_cleanup.yml
new file mode 100644
index 000000000..9507f99fa
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/mq/tasks/broker_cleanup.yml
@@ -0,0 +1,17 @@
+- name: cleanup broker
+ mq_broker:
+ broker_name: "{{ broker_name }}"
+ state: "absent"
+ ignore_errors: true
+ when: not ansible_check_mode
+# we need to wait - otherwise env_cleanup.yml will fail
+- name: wait until broker deletion is finished
+ mq_broker_info:
+ broker_id: "{{ broker_id }}"
+ register: result
+ # the condition will never be met - instead it wail fail in the end
+ until: result.broker['broker_state'] != 'DELETION_IN_PROGRESS'
+ retries: 15
+ delay: 60
+ ignore_errors: true
+ when: not ansible_check_mode
diff --git a/ansible_collections/community/aws/tests/integration/targets/mq/tasks/broker_config_tests.yml b/ansible_collections/community/aws/tests/integration/targets/mq/tasks/broker_config_tests.yml
new file mode 100644
index 000000000..31c67438b
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/mq/tasks/broker_config_tests.yml
@@ -0,0 +1,82 @@
+- name: get broker details
+ mq_broker_info:
+ broker_id: "{{ broker_id }}"
+ register: result
+- name: verify test broker is running
+ assert:
+ fail_msg: "broker with id {{ broker_id }} is not in RUNNING state"
+ that:
+ - result.broker['broker_state'] == 'RUNNING'
+ when: not ansible_check_mode
+- name: test 1 - send update to broker config
+ mq_broker_config:
+ broker_id: "{{ broker_id }}"
+ config_xml: "{{ lookup('file', '../files/broker_cfg.1.xml')}}"
+ register: result
+- name: verify test1
+ assert:
+ fail_msg: test1 failed
+ that:
+ - result.changed | bool
+ - result.broker['broker_id'] == broker_id
+ - result.configuration['id'] == result.broker['configurations']['pending']['id']
+ - result.configuration['revision'] == result.broker['configurations']['pending']['revision']
+ when: not ansible_check_mode
+- name: test 1a - send same config again
+ mq_broker_config:
+ broker_id: "{{ broker_id }}"
+ config_xml: "{{ lookup('file', '../files/broker_cfg.1.xml')}}"
+ register: result
+- name: verify test1a
+ assert:
+ fail_msg: test1a failed
+ that:
+ - not (result.changed | bool )
+ when: not ansible_check_mode
+- name: test 2 - send (almost) same config again - differs by whitespace
+ mq_broker_config:
+ broker_id: "{{ broker_id }}"
+ config_xml: "{{ lookup('file', '../files/broker_cfg.1a.xml')}}"
+ register: result
+- name: verify test2
+ assert:
+ fail_msg: test2 failed
+ that:
+ - not (result.changed | bool )
+ when: not ansible_check_mode
+- name: test 3 - send new config with custom description and request reboot
+ mq_broker_config:
+ broker_id: "{{ broker_id }}"
+ config_xml: "{{ lookup('file', '../files/broker_cfg.2.xml')}}"
+ config_description: "test 3 used custom description"
+ reboot: true
+ register: result
+- name: verify test3
+ assert:
+ fail_msg: test3 failed
+ that:
+ - result.changed | bool
+ - result.broker['broker_state'] == 'REBOOT_IN_PROGRESS'
+ when: not ansible_check_mode
+- name: wait for reboot
+ mq_broker_info:
+ broker_id: "{{ broker_id }}"
+ register: result
+ until: result.broker['broker_state'] == 'RUNNING'
+ retries: 15
+ delay: 60
+ when: not ansible_check_mode
+- name: test 3a - send new config again
+ mq_broker_config:
+ broker_id: "{{ broker_id }}"
+ config_xml: "{{ lookup('file', '../files/broker_cfg.2.xml')}}"
+ config_description: "test 3 used custom description"
+ reboot: true
+ register: result
+- name: verify test3a
+ assert:
+ fail_msg: test3a failed
+ that:
+ - not (result.changed | bool )
+ when: not ansible_check_mode
+# Note: currently there's no way to delete a broker configuration (version)
diff --git a/ansible_collections/community/aws/tests/integration/targets/mq/tasks/broker_delete_tests.yml b/ansible_collections/community/aws/tests/integration/targets/mq/tasks/broker_delete_tests.yml
new file mode 100644
index 000000000..bde36cd13
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/mq/tasks/broker_delete_tests.yml
@@ -0,0 +1,43 @@
+- name: delete broker
+ mq_broker:
+ broker_name: "{{ broker_name }}"
+ state: "absent"
+ register: result
+- name: verify broker delete
+ assert:
+ fail_msg: broker delete failed
+ that:
+ - ( result.changed | bool)
+ when: not ansible_check_mode
+- name: get details after delete
+ mq_broker_info:
+ broker_name: "{{ broker_name }}"
+ register: result_d1
+- name: verify broker deletion on progress
+ assert:
+ fail_msg: broker delete too fast?
+ that:
+ - result_d1.broker['broker_state'] == 'DELETION_IN_PROGRESS'
+ when: not ansible_check_mode
+- name: repeat broker deletion
+ mq_broker:
+ broker_name: "{{ broker_name }}"
+ state: "absent"
+ register: result
+- name: verify broker repeated delete
+ assert:
+ fail_msg: didn't detect DELETION_IN_PROGRESS in progress
+ that:
+ - not ( result.changed | bool)
+ when: not ansible_check_mode
+- name: deletion unknown broker - simulates re-deletion of completely deleted broker
+ mq_broker:
+ broker_name: "{{ broker_name }}__unknown_broker__"
+ state: "absent"
+ register: result
+- name: verify delete unknown broker
+ assert:
+ fail_msg: deletion of unknown broker return unexpected result
+ that:
+ - not ( result.changed | bool)
+ when: not ansible_check_mode
diff --git a/ansible_collections/community/aws/tests/integration/targets/mq/tasks/broker_tests.yml b/ansible_collections/community/aws/tests/integration/targets/mq/tasks/broker_tests.yml
new file mode 100644
index 000000000..515306abf
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/mq/tasks/broker_tests.yml
@@ -0,0 +1,120 @@
+- name: create broker with minimal parameters
+ mq_broker:
+ broker_name: "{{ broker_name }}"
+ security_groups: "{{ broker_sg_ids.split(',') }}"
+ subnet_ids: "{{ broker_subnet_ids.split(',') }}"
+ tags: "{{ tags }}"
+ wait: true
+ register: result
+- set_fact:
+ broker_id: "{{ result.broker['broker_id'] }}"
+- name: get broker details by id
+ mq_broker_info:
+ broker_id: "{{ broker_id }}"
+ register: result_c1
+- name: verify creation result
+ assert:
+ fail_msg: broker creation failed
+ that:
+ # change state is from previous operation:
+ - ( result.changed | bool )
+ - result_c1.broker['broker_id'] == broker_id
+ - result_c1.broker['broker_name'] == broker_name
+ - result_c1.broker['broker_state'] == 'RUNNING'
+ - ( result_c1.broker['storage_type'] | upper ) == 'EFS'
+ - result_c1.broker['tags'] == tags
+ when: not ansible_check_mode
+- name: repeat creation
+ mq_broker:
+ broker_name: "{{ broker_name }}"
+ security_groups: "{{ broker_sg_ids.split(',') }}"
+ subnet_ids: "{{ broker_subnet_ids.split(',') }}"
+ register: result
+- set_fact:
+ broker_id: "{{ result.broker['broker_id'] }}"
+- name: get broker details - this time by name
+ mq_broker_info:
+ broker_name: "{{ broker_name }}"
+ register: result_c2
+- name: verify broker re-creation
+ assert:
+ fail_msg: broker re-creation failed
+ that:
+ # change state is from previous operation:
+ - not ( result.changed | bool)
+ - result_c2.broker['broker_id'] == broker_id
+ - result_c2.broker['broker_name'] == broker_name
+ - ( result_c2.broker['storage_type'] | upper ) == 'EFS'
+ when: not ansible_check_mode
+- name: update broker
+ mq_broker:
+ broker_name: "{{ broker_name }}"
+ auto_minor_version_upgrade: false
+ storage_type: EBS
+ register: result
+- name: verify broker update
+ assert:
+ fail_msg: broker update failed
+ that:
+ - ( result.changed | bool)
+ - result.broker['broker_id'] == broker_id
+ when: not ansible_check_mode
+- name: reboot broker to make pending changes active
+ mq_broker:
+ broker_name: "{{ broker_name }}"
+ state: "restarted"
+ register: result
+- name: get broker details by id
+ mq_broker_info:
+ broker_id: "{{ broker_id }}"
+ register: result_r1
+- name: check for pending reboot
+ assert:
+ fail_msg: trigger reboot failed
+ that:
+ - result.changed | bool
+ - result_r1.broker['broker_state'] == 'REBOOT_IN_PROGRESS'
+ when: not ansible_check_mode
+- debug:
+ msg: "Wait until reboot of broker {{ broker_name }} ({{ broker_id }}) is finished. This may take several minutes"
+- name: wait for reboot
+ mq_broker_info:
+ broker_id: "{{ broker_id }}"
+ register: result
+ until: result.broker['broker_state'] == 'RUNNING'
+ retries: 15
+ delay: 60
+ when: not ansible_check_mode
+- name: get details after update
+ mq_broker_info:
+ broker_name: "{{ broker_name }}"
+ register: result_u1
+- name: verify broker update
+ assert:
+ fail_msg: broker update failed
+ that:
+ - result_u1.broker['broker_id'] == broker_id
+ - result_u1.broker['broker_name'] == broker_name
+ - not ( result_u1.broker['auto_minor_version_upgrade'] | bool )
+ # the next one checks that changes to create-only parameters are silently ignore
+ - result_u1.broker['storage_type'] == result_c1.broker['storage_type']
+ when: not ansible_check_mode
+- name: repeat update broker
+ mq_broker:
+ broker_name: "{{ broker_name }}"
+ auto_minor_version_upgrade: false
+ storage_type: EBS
+ register: result
+- name: get details after re-update
+ mq_broker_info:
+ broker_name: "{{ broker_name }}"
+ register: result_u2
+- name: verify broker re-update
+ assert:
+ fail_msg: broker update failed
+ that:
+ - not ( result.changed | bool)
+ - result_u2.broker['broker_id'] == result_u1.broker['broker_id']
+ - result_u2.broker['storage_type'] == result_u1.broker['storage_type']
+ - result_u2.broker['engine_version'] == result_u1.broker['engine_version']
+ when: not ansible_check_mode
diff --git a/ansible_collections/community/aws/tests/integration/targets/mq/tasks/broker_user_info_tests.yml b/ansible_collections/community/aws/tests/integration/targets/mq/tasks/broker_user_info_tests.yml
new file mode 100644
index 000000000..427e272b6
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/mq/tasks/broker_user_info_tests.yml
@@ -0,0 +1,65 @@
+- name: set test data
+ set_fact:
+ create_users:
+ - "info_user1"
+ - "info_user2"
+ - "info_user3"
+ - "info_user4"
+ - "info_user5"
+ delete_users:
+ - "info_user2"
+ - "info_user5"
+- name: prepare tests - create users
+ mq_user:
+ state: present
+ broker_id: "{{ broker_id }}"
+ username: "{{ item }}"
+ loop: "{{ create_users | flatten(levels=1) }}"
+- name: prepare tests - delete users
+ mq_user:
+ state: absent
+ broker_id: "{{ broker_id }}"
+ username: "{{ item }}"
+ loop: "{{ delete_users | flatten(levels=1) }}"
+- name: test2 - list all users
+ mq_user_info:
+ broker_id: "{{ broker_id }}"
+ register: result
+- name: test2 - verify
+ assert:
+ fail_msg: test2 failed
+ that:
+ - result.users['info_user1']
+ - result.users['info_user2']
+ - result.users['info_user3']
+ when: not ansible_check_mode
+- name: test3 - list only user currently being active until next broker reboot
+ mq_user_info:
+ broker_id: "{{ broker_id }}"
+ skip_pending_create: true
+ register: result
+- name: test3 - verify
+ assert:
+ fail_msg: test3 failed
+ that:
+ - not ('info_user1' in result.users)
+ - result.users['info_user2']
+ - not ('info_user3' in result.users)
+ - not ('info_user4' in result.users)
+ - result.users['info_user5']
+ when: not ansible_check_mode
+- name: test4 - list only user that will be active after next broker reboot
+ mq_user_info:
+ broker_id: "{{ broker_id }}"
+ skip_pending_delete: true
+ register: result
+- name: test4 - verify
+ assert:
+ fail_msg: test4 failed
+ that:
+ - result.users['info_user1']
+ - not ('info_user2' in result.users)
+ - result.users['info_user3']
+ - result.users['info_user4']
+ - not ('info_user5' in result.users)
+ when: not ansible_check_mode
diff --git a/ansible_collections/community/aws/tests/integration/targets/mq/tasks/broker_user_tests.yml b/ansible_collections/community/aws/tests/integration/targets/mq/tasks/broker_user_tests.yml
new file mode 100644
index 000000000..6a30c694b
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/mq/tasks/broker_user_tests.yml
@@ -0,0 +1,173 @@
+- name: set test data
+ set_fact:
+ usernames:
+ - "test_user1"
+ - "test_user2"
+ - "test_user3"
+
+- name: test1 - create user with default settings
+ mq_user:
+ broker_id: "{{ broker_id }}"
+ username: "{{ usernames[0] }}"
+ register: result
+- name: test1 - verify
+ assert:
+ fail_msg: test1 failed
+ that:
+ - result.changed | bool
+ - result.user['username'] == usernames[0]
+ - not (result.user['pending']['console_access'] | bool)
+ - result.user['pending']['groups'] | length == 0
+ when: not ansible_check_mode
+- name: test2 - create user with console access and group list
+ mq_user:
+ state: present
+ broker_id: "{{ broker_id }}"
+ username: "{{ usernames[1] }}"
+ console_access: true
+ groups: [ "g1", "g2" ]
+ register: result
+- name: test2 - verify
+ assert:
+ fail_msg: test2 failed
+ that:
+ - result.changed | bool
+ - result.user['username'] == usernames[1]
+ - result.user['pending']['console_access'] | bool
+ - result.user['pending']['groups'] | length == 2
+ when: not ansible_check_mode
+- name: test3 - create user with defined password
+ mq_user:
+ broker_id: "{{ broker_id }}"
+ username: "{{ usernames[2] }}"
+ password: "09234092jzxkjvjk23kn23qn5lk34"
+ register: result
+- name: test3 - verify
+ assert:
+ fail_msg: test3 failed
+ that:
+ - result.changed | bool
+ - result.user['username'] == usernames[2]
+ - not (result.user['pending']['console_access'] | bool)
+ - result.user['pending']['groups'] | length == 0
+ when: not ansible_check_mode
+- name: test4 - update user password - ignore mode
+ mq_user:
+ broker_id: "{{ broker_id }}"
+ username: "{{ usernames[2] }}"
+ password: "new_password_ignored"
+ register: result
+- name: test4 - verify
+ assert:
+ fail_msg: test4 failed
+ that:
+ - not (result.changed | bool)
+ when: not ansible_check_mode
+- name: test5 - update user password - force mode
+ mq_user:
+ broker_id: "{{ broker_id }}"
+ username: "{{ usernames[2] }}"
+ password: "new_Password_Accepted0815%"
+ allow_pw_update: true
+ register: result
+- name: test5 - verify
+ assert:
+ fail_msg: test5 failed
+ that:
+ - result.changed | bool
+ when: not ansible_check_mode
+- name: test6 - update console access - same value
+ mq_user:
+ broker_id: "{{ broker_id }}"
+ username: "{{ usernames[2] }}"
+ console_access: false
+ register: result
+- name: test6 - verify
+ assert:
+ fail_msg: test6 failed
+ that:
+ - not (result.changed | bool)
+ when: not ansible_check_mode
+- name: test7 - update console access - new value
+ mq_user:
+ broker_id: "{{ broker_id }}"
+ username: "{{ usernames[1] }}"
+ console_access: false
+ register: result
+- name: test7 - verify
+ assert:
+ fail_msg: test7 failed
+ that:
+ - result.changed | bool
+ - not( result.user['pending']['console_access'] | bool )
+ - result.user['pending']['groups'] | length == 2
+ when: not ansible_check_mode
+- name: test8 - update group list - same list but different order
+ mq_user:
+ broker_id: "{{ broker_id }}"
+ username: "{{ usernames[1] }}"
+ groups: [ "g2", "g1" ]
+ register: result
+- name: test8 - verify
+ assert:
+ fail_msg: test8 failed
+ that:
+ - not (result.changed | bool)
+ when: not ansible_check_mode
+- name: test9 - update group list - add element
+ mq_user:
+ broker_id: "{{ broker_id }}"
+ username: "{{ usernames[1] }}"
+ groups: [ "g2", "g1", "g3" ]
+ register: result
+- name: test9 - verify
+ assert:
+ fail_msg: test9 failed
+ that:
+ - result.changed | bool
+ - result.user['pending']['groups'] | length == 3
+ when: not ansible_check_mode
+- name: test10 - update group list - remove element
+ mq_user:
+ broker_id: "{{ broker_id }}"
+ username: "{{ usernames[1] }}"
+ groups: [ "g2", "g3" ]
+ register: result
+- name: test10 - verify
+ assert:
+ fail_msg: test10 failed
+ that:
+ - result.changed | bool
+ - result.user['pending']['groups'] | length == 2
+ when: not ansible_check_mode
+- name: test11 - update group list - set to empty list
+ mq_user:
+ broker_id: "{{ broker_id }}"
+ username: "{{ usernames[1] }}"
+ groups: []
+ register: result
+- name: test11 - verify
+ assert:
+ fail_msg: test11 failed
+ that:
+ - result.changed | bool
+ - result.user['pending']['groups'] | length == 0
+ when: not ansible_check_mode
+- name: delete all users
+ mq_user:
+ state: absent
+ broker_id: "{{ broker_id }}"
+ username: "{{ item }}"
+ loop: "{{ usernames | flatten(levels=1) }}"
+- name: test13 - delete deleted user
+ mq_user:
+ state: absent
+ broker_id: "{{ broker_id }}"
+ username: "{{ usernames[1] }}"
+ register: result
+- name: test13 - verify
+ assert:
+ fail_msg: test13 failed
+ that:
+ - not(result.changed | bool)
+ when: not ansible_check_mode
diff --git a/ansible_collections/community/aws/tests/integration/targets/mq/tasks/env_cleanup.yml b/ansible_collections/community/aws/tests/integration/targets/mq/tasks/env_cleanup.yml
new file mode 100644
index 000000000..0ccb37907
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/mq/tasks/env_cleanup.yml
@@ -0,0 +1,33 @@
+- name: remove the security group
+ ec2_security_group:
+ name: "{{ sg_name }}"
+ description: a security group for ansible tests
+ vpc_id: "{{ testing_vpc.vpc.id }}"
+ state: absent
+ register: removed
+ until: removed is not failed
+ ignore_errors: yes
+ retries: 10
+
+- name: remove subnet A
+ ec2_vpc_subnet:
+ state: absent
+ vpc_id: "{{ testing_vpc.vpc.id }}"
+ cidr: "{{ subnet_cidr }}"
+ register: removed
+ until: removed is not failed
+ ignore_errors: yes
+ retries: 10
+
+- name: remove the VPC
+ ec2_vpc_net:
+ name: "{{ vpc_name }}"
+ cidr_block: "{{ vpc_cidr }}"
+ state: absent
+ tags:
+ Name: Ansible Testing VPC
+ tenancy: default
+ register: removed
+ until: removed is not failed
+ ignore_errors: yes
+ retries: 10
diff --git a/ansible_collections/community/aws/tests/integration/targets/mq/tasks/env_setup.yml b/ansible_collections/community/aws/tests/integration/targets/mq/tasks/env_setup.yml
new file mode 100644
index 000000000..e27b66f27
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/mq/tasks/env_setup.yml
@@ -0,0 +1,25 @@
+- name: Create VPC for use in testing
+ ec2_vpc_net:
+ name: "{{ vpc_name }}"
+ cidr_block: "{{ vpc_cidr }}"
+ tags:
+ Name: Ansible ec2_instance Testing VPC
+ tenancy: default
+ register: testing_vpc
+
+- name: Create subnet in zone A
+ ec2_vpc_subnet:
+ state: present
+ vpc_id: "{{ testing_vpc.vpc.id }}"
+ cidr: "{{ subnet_cidr }}"
+ az: "{{ aws_region }}a"
+ resource_tags:
+ Name: "{{ resource_prefix }}-subnet-a"
+ register: testing_subnet_a
+
+- name: create a security group with the vpc
+ ec2_security_group:
+ name: "{{ sg_name }}"
+ description: a security group for ansible tests
+ vpc_id: "{{ testing_vpc.vpc.id }}"
+ register: testing_sg
diff --git a/ansible_collections/community/aws/tests/integration/targets/mq/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/mq/tasks/main.yml
new file mode 100644
index 000000000..e84367a76
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/mq/tasks/main.yml
@@ -0,0 +1,35 @@
+---
+- name: run amazon MQ tests
+ module_defaults:
+ group/aws:
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
+ aws_region: "{{ aws_region }}"
+ collections:
+ - amazon.aws
+
+ block:
+ - name: set up environment for testing.
+ include_tasks: env_setup.yml
+ - name: set subnet and security group
+ set_fact:
+ broker_subnet_ids: "{{ testing_subnet_a.subnet.id }}"
+ broker_sg_ids: "{{ testing_sg.group_id }}"
+ - name: run broker tests
+ include_tasks: broker_tests.yml
+ # re-user broker_id for other tests
+ - name: run broker config tests
+ include_tasks: broker_config_tests.yml
+ - name: run broker user tests
+ include_tasks: broker_user_tests.yml
+ - name: run broker user info tests
+ include_tasks: broker_user_info_tests.yml
+ - name: run broker delete tests
+ include_tasks: broker_delete_tests.yml
+
+ always:
+ - name: cleanup broker
+ include_tasks: broker_cleanup.yml
+
+ - include_tasks: env_cleanup.yml
diff --git a/ansible_collections/community/aws/tests/integration/targets/mq/vars/main.yml b/ansible_collections/community/aws/tests/integration/targets/mq/vars/main.yml
new file mode 100644
index 000000000..ed97d539c
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/mq/vars/main.yml
@@ -0,0 +1 @@
+---
diff --git a/ansible_collections/community/aws/tests/integration/targets/msk_cluster-auth/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/msk_cluster-auth/tasks/main.yml
index 5a6487607..9ed2e92d5 100644
--- a/ansible_collections/community/aws/tests/integration/targets/msk_cluster-auth/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/msk_cluster-auth/tasks/main.yml
@@ -2,9 +2,9 @@
- name: aws_msk_cluster integration tests
module_defaults:
group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"
collections:
- amazon.aws
@@ -42,7 +42,7 @@
# ============================================================
- name: create msk configuration
- aws_msk_config:
+ msk_config:
name: "{{ msk_config_name }}"
state: "present"
kafka_versions:
@@ -55,14 +55,14 @@
always:
- name: delete msk cluster
- aws_msk_cluster:
+ msk_cluster:
name: "{{ msk_cluster_name }}"
state: absent
wait: true
ignore_errors: yes
- name: remove msk configuration
- aws_msk_config:
+ msk_config:
name: "{{ msk_config_name }}"
state: absent
ignore_errors: yes
diff --git a/ansible_collections/community/aws/tests/integration/targets/msk_cluster-auth/tasks/test_create_auth.yml b/ansible_collections/community/aws/tests/integration/targets/msk_cluster-auth/tasks/test_create_auth.yml
index d7cdd3a71..9535c235f 100644
--- a/ansible_collections/community/aws/tests/integration/targets/msk_cluster-auth/tasks/test_create_auth.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/msk_cluster-auth/tasks/test_create_auth.yml
@@ -1,6 +1,6 @@
---
- name: create a msk cluster with authentication flipped from default (check mode)
- aws_msk_cluster:
+ msk_cluster:
name: "{{ msk_cluster_name }}"
state: "present"
version: "{{ msk_version }}"
@@ -24,7 +24,7 @@
- msk_cluster is changed
- name: create a msk cluster with authentication flipped from default
- aws_msk_cluster:
+ msk_cluster:
name: "{{ msk_cluster_name }}"
state: "present"
version: "{{ msk_version }}"
@@ -62,10 +62,10 @@
# Not always returned by API
# - "msk_cluster.cluster_info.client_authentication.unauthenticated.enabled == false"
- "msk_cluster.cluster_info.open_monitoring.prometheus.jmx_exporter.enabled_in_broker == false"
- - "msk_cluster.cluster_info.cluster_arn.startswith('arn:aws:kafka:{{ aws_region }}:')"
+ - "msk_cluster.cluster_info.cluster_arn.startswith('arn:aws:kafka:' ~ aws_region ~ ':')"
- name: create a msk cluster with authentication flipped from default (idempotency)
- aws_msk_cluster:
+ msk_cluster:
name: "{{ msk_cluster_name }}"
state: "present"
version: "{{ msk_version }}"
@@ -89,7 +89,7 @@
### Keep delete simple as we're not checking delete here
- name: delete msk cluster
- aws_msk_cluster:
+ msk_cluster:
name: "{{ msk_cluster_name }}"
state: "absent"
wait: true
diff --git a/ansible_collections/community/aws/tests/integration/targets/msk_cluster/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/msk_cluster/tasks/main.yml
index a3049dad0..6425d7ec7 100644
--- a/ansible_collections/community/aws/tests/integration/targets/msk_cluster/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/msk_cluster/tasks/main.yml
@@ -2,9 +2,9 @@
- name: aws_msk_cluster integration tests
module_defaults:
group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"
collections:
- amazon.aws
@@ -42,7 +42,7 @@
# ============================================================
- name: create msk configuration
- aws_msk_config:
+ msk_config:
name: "{{ msk_config_name }}"
state: "present"
kafka_versions:
@@ -61,14 +61,14 @@
always:
- name: delete msk cluster
- aws_msk_cluster:
+ msk_cluster:
name: "{{ msk_cluster_name }}"
state: absent
wait: true
ignore_errors: yes
- name: remove msk configuration
- aws_msk_config:
+ msk_config:
name: "{{ msk_config_name }}"
state: absent
ignore_errors: yes
diff --git a/ansible_collections/community/aws/tests/integration/targets/msk_cluster/tasks/test_create.yml b/ansible_collections/community/aws/tests/integration/targets/msk_cluster/tasks/test_create.yml
index 4fd7073cc..f6845059f 100644
--- a/ansible_collections/community/aws/tests/integration/targets/msk_cluster/tasks/test_create.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/msk_cluster/tasks/test_create.yml
@@ -1,6 +1,6 @@
---
- name: create msk cluster (check mode)
- aws_msk_cluster:
+ msk_cluster:
name: "{{ msk_cluster_name }}"
state: "present"
version: "{{ msk_version }}"
@@ -20,7 +20,7 @@
- msk_cluster is changed
- name: create msk cluster
- aws_msk_cluster:
+ msk_cluster:
name: "{{ msk_cluster_name }}"
state: "present"
version: "{{ msk_version }}"
@@ -50,10 +50,10 @@
- "msk_cluster.cluster_info.broker_node_group_info.instance_type == 'kafka.t3.small'"
- "msk_cluster.cluster_info.broker_node_group_info.storage_info.ebs_storage_info.volume_size == 10"
- "msk_cluster.cluster_info.open_monitoring.prometheus.jmx_exporter.enabled_in_broker == false"
- - "msk_cluster.cluster_info.cluster_arn.startswith('arn:aws:kafka:{{ aws_region }}:')"
+ - "msk_cluster.cluster_info.cluster_arn.startswith('arn:aws:kafka:' ~ aws_region ~ ':')"
- name: create msk cluster (idempotency)
- aws_msk_cluster:
+ msk_cluster:
name: "{{ msk_cluster_name }}"
state: "present"
version: "{{ msk_version }}"
diff --git a/ansible_collections/community/aws/tests/integration/targets/msk_cluster/tasks/test_delete.yml b/ansible_collections/community/aws/tests/integration/targets/msk_cluster/tasks/test_delete.yml
index efd90fa14..53a0d7c8f 100644
--- a/ansible_collections/community/aws/tests/integration/targets/msk_cluster/tasks/test_delete.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/msk_cluster/tasks/test_delete.yml
@@ -1,6 +1,6 @@
---
- name: delete msk cluster (check mode)
- aws_msk_cluster:
+ msk_cluster:
name: "{{ msk_cluster_name }}"
state: "absent"
wait: true
@@ -13,7 +13,7 @@
- msk_cluster is changed
- name: delete msk cluster
- aws_msk_cluster:
+ msk_cluster:
name: "{{ msk_cluster_name }}"
state: "absent"
wait: true
@@ -25,7 +25,7 @@
- msk_cluster is changed
- name: delete msk cluster (idempotency)
- aws_msk_cluster:
+ msk_cluster:
name: "{{ msk_cluster_name }}"
state: "absent"
wait: true
diff --git a/ansible_collections/community/aws/tests/integration/targets/msk_cluster/tasks/test_update.yml b/ansible_collections/community/aws/tests/integration/targets/msk_cluster/tasks/test_update.yml
index 50ac91718..600d8eb59 100644
--- a/ansible_collections/community/aws/tests/integration/targets/msk_cluster/tasks/test_update.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/msk_cluster/tasks/test_update.yml
@@ -1,6 +1,6 @@
---
- name: update msk cluster (check mode)
- aws_msk_cluster:
+ msk_cluster:
name: "{{ msk_cluster_name }}"
state: "present"
version: "{{ msk_version }}"
@@ -22,7 +22,7 @@
- msk_cluster is changed
- name: update msk cluster
- aws_msk_cluster:
+ msk_cluster:
name: "{{ msk_cluster_name }}"
state: "present"
version: "{{ msk_version }}"
@@ -51,7 +51,7 @@
- "msk_cluster.cluster_info.tags.key3 == 'value3'"
- name: update msk cluster (idempotency)
- aws_msk_cluster:
+ msk_cluster:
name: "{{ msk_cluster_name }}"
state: "present"
version: "{{ msk_version }}"
diff --git a/ansible_collections/community/aws/tests/integration/targets/msk_config/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/msk_config/tasks/main.yml
index cef9e1dfc..5f7f6c782 100644
--- a/ansible_collections/community/aws/tests/integration/targets/msk_config/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/msk_config/tasks/main.yml
@@ -2,15 +2,15 @@
- name: tests for community.aws.aws_msk_config
module_defaults:
group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"
collections:
- amazon.aws
block:
- name: create msk configuration (check mode)
- aws_msk_config:
+ msk_config:
name: "{{ msk_config_name }}"
state: "present"
kafka_versions: "{{ msk_kafka_versions }}"
@@ -24,7 +24,7 @@
- msk_config is changed
- name: create msk configuration
- aws_msk_config:
+ msk_config:
name: "{{ msk_config_name }}"
state: "present"
kafka_versions: "{{ msk_kafka_versions }}"
@@ -37,7 +37,7 @@
- msk_config is changed
- name: create msk configuration (idempotency)
- aws_msk_config:
+ msk_config:
name: "{{ msk_config_name }}"
state: "present"
kafka_versions: "{{ msk_kafka_versions }}"
@@ -53,12 +53,12 @@
assert:
that:
- msk_config.revision == 1
- - "msk_config.arn.startswith('arn:aws:kafka:{{ aws_region }}:')"
+ - "msk_config.arn.startswith('arn:aws:kafka:' ~ aws_region ~ ':')"
- "'auto.create.topics.enable=True' in msk_config.server_properties"
- "'zookeeper.session.timeout.ms=18000' in msk_config.server_properties"
- name: update msk configuration (check mode)
- aws_msk_config:
+ msk_config:
name: "{{ msk_config_name }}"
state: "present"
kafka_versions: "{{ msk_kafka_versions }}"
@@ -72,7 +72,7 @@
- msk_config is changed
- name: update msk configuration
- aws_msk_config:
+ msk_config:
name: "{{ msk_config_name }}"
state: "present"
kafka_versions: "{{ msk_kafka_versions }}"
@@ -93,7 +93,7 @@
- "'zookeeper.session.timeout.ms=36000' in msk_config.server_properties"
- name: update msk configuration (idempotency)
- aws_msk_config:
+ msk_config:
name: "{{ msk_config_name }}"
state: "present"
kafka_versions: "{{ msk_kafka_versions }}"
@@ -106,7 +106,7 @@
- msk_config is not changed
- name: delete msk configuration (check mode)
- aws_msk_config:
+ msk_config:
name: "{{ msk_config_name }}"
state: "absent"
check_mode: yes
@@ -118,7 +118,7 @@
- msk_config is changed
- name: delete msk configuration
- aws_msk_config:
+ msk_config:
name: "{{ msk_config_name }}"
state: "absent"
register: msk_config
@@ -129,7 +129,7 @@
- msk_config is changed
- name: delete msk configuration (idempotency)
- aws_msk_config:
+ msk_config:
name: "{{ msk_config_name }}"
state: "absent"
register: msk_config
@@ -142,7 +142,7 @@
always:
- name: remove msk configuration
- aws_msk_config:
+ msk_config:
name: "{{ msk_config_name }}"
state: absent
ignore_errors: yes
diff --git a/ansible_collections/community/aws/tests/integration/targets/networkfirewall/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/networkfirewall/tasks/main.yml
index 6a77d4f93..5a60654d8 100644
--- a/ansible_collections/community/aws/tests/integration/targets/networkfirewall/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/networkfirewall/tasks/main.yml
@@ -5,9 +5,9 @@
- community.aws
module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region }}'
block:
diff --git a/ansible_collections/community/aws/tests/integration/targets/networkfirewall_policy/meta/main.yml b/ansible_collections/community/aws/tests/integration/targets/networkfirewall_policy/meta/main.yml
index f09ab4af1..32cf5dda7 100644
--- a/ansible_collections/community/aws/tests/integration/targets/networkfirewall_policy/meta/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/networkfirewall_policy/meta/main.yml
@@ -1,4 +1 @@
-dependencies:
- - role: setup_botocore_pip
- vars:
- botocore_version: "1.23.23"
+dependencies: []
diff --git a/ansible_collections/community/aws/tests/integration/targets/networkfirewall_policy/tasks/default_order.yml b/ansible_collections/community/aws/tests/integration/targets/networkfirewall_policy/tasks/default_order.yml
index 50df7e7ab..4c7d2ba25 100644
--- a/ansible_collections/community/aws/tests/integration/targets/networkfirewall_policy/tasks/default_order.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/networkfirewall_policy/tasks/default_order.yml
@@ -223,8 +223,6 @@
stateful_rule_order: strict
register: default_policy
ignore_errors: True
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
- assert:
that:
@@ -237,8 +235,6 @@
stateful_rule_order: strict
register: default_policy
ignore_errors: True
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
- assert:
that:
@@ -1143,8 +1139,6 @@
- 'aws:drop_strict'
register: default_policy
ignore_errors: True
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
- assert:
that:
@@ -1158,8 +1152,6 @@
- 'aws:drop_strict'
register: default_policy
ignore_errors: True
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
- assert:
that:
diff --git a/ansible_collections/community/aws/tests/integration/targets/networkfirewall_policy/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/networkfirewall_policy/tasks/main.yml
index d3890c680..14c3d1182 100644
--- a/ansible_collections/community/aws/tests/integration/targets/networkfirewall_policy/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/networkfirewall_policy/tasks/main.yml
@@ -1,10 +1,10 @@
---
- module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key | default(omit) }}'
- aws_secret_key: '{{ aws_secret_key | default(omit) }}'
- security_token: '{{ security_token | default(omit) }}'
- region: '{{ aws_region | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
+ region: '{{ aws_region }}'
collections:
- amazon.aws
- community.aws
@@ -27,8 +27,6 @@
# Tests specifically related to policies using 'strict' rule order
- include_tasks: 'strict_order.yml'
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
- include_tasks: 'actions.yml'
diff --git a/ansible_collections/community/aws/tests/integration/targets/networkfirewall_policy/tasks/setup.yml b/ansible_collections/community/aws/tests/integration/targets/networkfirewall_policy/tasks/setup.yml
index 27f0ebb48..e77e4d9a9 100644
--- a/ansible_collections/community/aws/tests/integration/targets/networkfirewall_policy/tasks/setup.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/networkfirewall_policy/tasks/setup.yml
@@ -23,9 +23,6 @@
rule_order: strict
register: strict_groups
loop: '{{ range(1,4,1) | list }}'
- # Setting rule order requires botocore>=1.23.23
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
- debug:
var: default_groups
diff --git a/ansible_collections/community/aws/tests/integration/targets/networkfirewall_policy/tasks/strict_order.yml b/ansible_collections/community/aws/tests/integration/targets/networkfirewall_policy/tasks/strict_order.yml
index b842eebae..745009bf5 100644
--- a/ansible_collections/community/aws/tests/integration/targets/networkfirewall_policy/tasks/strict_order.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/networkfirewall_policy/tasks/strict_order.yml
@@ -260,8 +260,6 @@
stateful_rule_order: default
register: strict_policy
ignore_errors: True
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
- assert:
that:
@@ -274,8 +272,6 @@
stateful_rule_order: default
register: strict_policy
ignore_errors: True
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
- assert:
that:
diff --git a/ansible_collections/community/aws/tests/integration/targets/networkfirewall_rule_group/aliases b/ansible_collections/community/aws/tests/integration/targets/networkfirewall_rule_group/aliases
index 3a0301661..ef3989f4b 100644
--- a/ansible_collections/community/aws/tests/integration/targets/networkfirewall_rule_group/aliases
+++ b/ansible_collections/community/aws/tests/integration/targets/networkfirewall_rule_group/aliases
@@ -1,4 +1,6 @@
time=18m
cloud/aws
+# Idempotency issues - https://github.com/ansible-collections/community.aws/issues/1634
+disabled
networkfirewall_rule_group_info
diff --git a/ansible_collections/community/aws/tests/integration/targets/networkfirewall_rule_group/meta/main.yml b/ansible_collections/community/aws/tests/integration/targets/networkfirewall_rule_group/meta/main.yml
index f09ab4af1..32cf5dda7 100644
--- a/ansible_collections/community/aws/tests/integration/targets/networkfirewall_rule_group/meta/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/networkfirewall_rule_group/meta/main.yml
@@ -1,4 +1 @@
-dependencies:
- - role: setup_botocore_pip
- vars:
- botocore_version: "1.23.23"
+dependencies: []
diff --git a/ansible_collections/community/aws/tests/integration/targets/networkfirewall_rule_group/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/networkfirewall_rule_group/tasks/main.yml
index a6e84426e..46823c3c8 100644
--- a/ansible_collections/community/aws/tests/integration/targets/networkfirewall_rule_group/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/networkfirewall_rule_group/tasks/main.yml
@@ -1,10 +1,10 @@
---
- module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key | default(omit) }}'
- aws_secret_key: '{{ aws_secret_key | default(omit) }}'
- security_token: '{{ security_token | default(omit) }}'
- region: '{{ aws_region | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
+ region: '{{ aws_region }}'
collections:
- amazon.aws
- community.aws
@@ -22,8 +22,6 @@
# List the Managed Rule Groups (there's no access to the rules themselves)
- include_tasks: 'managed.yml'
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
# Minimal tests and manipulation of common metadata
- include_tasks: 'minimal.yml'
diff --git a/ansible_collections/community/aws/tests/integration/targets/networkfirewall_rule_group/tasks/stateful.yml b/ansible_collections/community/aws/tests/integration/targets/networkfirewall_rule_group/tasks/stateful.yml
index 3b92a4cee..b6f51eff5 100644
--- a/ansible_collections/community/aws/tests/integration/targets/networkfirewall_rule_group/tasks/stateful.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/networkfirewall_rule_group/tasks/stateful.yml
@@ -1078,8 +1078,6 @@
rule_order: 'strict'
register: stateful_group
ignore_errors: True
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
- assert:
that:
@@ -1092,8 +1090,6 @@
rule_order: 'strict'
register: stateful_group
ignore_errors: True
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
- assert:
that:
@@ -1142,8 +1138,6 @@
rule_order: strict
register: strict_group
check_mode: true
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
- assert:
that:
@@ -1170,8 +1164,6 @@
- 'pass tcp any any -> any any (sid:1000001;)'
rule_order: strict
register: strict_group
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
- assert:
that:
@@ -1208,8 +1200,6 @@
rule_order: strict
register: strict_group
check_mode: true
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
- assert:
that:
@@ -1238,8 +1228,6 @@
- 'pass tcp any any -> any any (sid:1000001;)'
rule_order: strict
register: strict_group
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
- assert:
that:
@@ -1269,8 +1257,6 @@
rule_order: 'default'
register: strict_group
ignore_errors: True
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
- assert:
that:
@@ -1283,8 +1269,6 @@
rule_order: 'default'
register: strict_group
ignore_errors: True
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
- assert:
that:
@@ -1299,8 +1283,6 @@
rule_order: 'strict'
register: strict_group
ignore_errors: True
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
- assert:
that:
@@ -1313,8 +1295,6 @@
rule_order: 'strict'
register: strict_group
ignore_errors: True
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
- assert:
that:
diff --git a/ansible_collections/community/aws/tests/integration/targets/opensearch/meta/main.yml b/ansible_collections/community/aws/tests/integration/targets/opensearch/meta/main.yml
index 13d6ecd91..32cf5dda7 100644
--- a/ansible_collections/community/aws/tests/integration/targets/opensearch/meta/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/opensearch/meta/main.yml
@@ -1,4 +1 @@
-dependencies:
- - role: setup_botocore_pip
- vars:
- botocore_version: "1.21.38"
+dependencies: []
diff --git a/ansible_collections/community/aws/tests/integration/targets/opensearch/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/opensearch/tasks/main.yml
index 6d3b47cad..e3c33d238 100644
--- a/ansible_collections/community/aws/tests/integration/targets/opensearch/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/opensearch/tasks/main.yml
@@ -4,17 +4,15 @@
module_defaults:
group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"
route53:
# Route53 is explicitly a global service
region: null
collections:
- amazon.aws
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
block:
# Get some information about who we are before starting our tests
diff --git a/ansible_collections/community/aws/tests/integration/targets/opensearch/tasks/test_create_cert.yml b/ansible_collections/community/aws/tests/integration/targets/opensearch/tasks/test_create_cert.yml
index 533e75e96..5492bb922 100644
--- a/ansible_collections/community/aws/tests/integration/targets/opensearch/tasks/test_create_cert.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/opensearch/tasks/test_create_cert.yml
@@ -1,10 +1,3 @@
-- pip:
- name:
- # The 'cryptography' module is required by community.crypto.openssl_privatekey
- - 'cryptography'
- virtualenv: "{{ botocore_virtualenv }}"
- virtualenv_command: "{{ botocore_virtualenv_command }}"
- virtualenv_site_packages: no
- name: Create temporary directory
ansible.builtin.tempfile:
state: directory
@@ -28,7 +21,7 @@
privatekey_path: '{{ tempdir_1.path }}/rsa-private-key.pem'
selfsigned_digest: sha256
- name: import certificate to ACM
- aws_acm:
+ acm_certificate:
name_tag: 'opensearch.ansible-integ-test.com'
domain_name: 'opensearch.ansible-integ-test.com'
certificate: "{{ lookup('file', tempdir_1.path + '/rsa-certificate.pem') }}"
@@ -50,4 +43,4 @@
- name: Delete temporary directory
ansible.builtin.file:
state: absent
- path: "{{ tempdir_1.path }}" \ No newline at end of file
+ path: "{{ tempdir_1.path }}"
diff --git a/ansible_collections/community/aws/tests/integration/targets/opensearch/tasks/test_delete_resources.yml b/ansible_collections/community/aws/tests/integration/targets/opensearch/tasks/test_delete_resources.yml
index d9ddfc913..470706f15 100644
--- a/ansible_collections/community/aws/tests/integration/targets/opensearch/tasks/test_delete_resources.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/opensearch/tasks/test_delete_resources.yml
@@ -43,12 +43,12 @@
vpc_name: "{{ item.tags['Name'] }}"
- name: collect info about KMS keys used for test purpose
- aws_kms_info:
+ kms_key_info:
filters:
"tag:AnsibleTest": "AnsibleTestVpc"
register: kms_info
- name: Delete KMS keys that were created for test purpose
- aws_kms:
+ kms_key:
key_id: "{{ kms_arn }}"
state: absent
with_items: "{{ kms_info.kms_keys }}"
@@ -56,6 +56,6 @@
kms_arn: "{{ item.key_arn }}"
- name: delete certificate from ACM
- aws_acm:
+ acm_certificate:
name_tag: 'opensearch.ansible-integ-test.com'
state: absent
diff --git a/ansible_collections/community/aws/tests/integration/targets/opensearch/tasks/test_delete_vpc_resources.yml b/ansible_collections/community/aws/tests/integration/targets/opensearch/tasks/test_delete_vpc_resources.yml
index 5fb803c90..b0cfa6434 100644
--- a/ansible_collections/community/aws/tests/integration/targets/opensearch/tasks/test_delete_vpc_resources.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/opensearch/tasks/test_delete_vpc_resources.yml
@@ -30,13 +30,13 @@
when: route53_zone_ids | length > 0
- name: Get security groups that have been created for test purpose in the VPC
- ec2_group_info:
+ ec2_security_group_info:
filters:
vpc-id: "{{ vpc_id }}"
register: sg_info
- name: Delete security groups
- ec2_group:
+ ec2_security_group:
group_id: "{{ sg_id }}"
state: absent
loop_control:
diff --git a/ansible_collections/community/aws/tests/integration/targets/opensearch/tasks/test_vpc_setup.yml b/ansible_collections/community/aws/tests/integration/targets/opensearch/tasks/test_vpc_setup.yml
index 90aeb50bb..6e1fec1ab 100644
--- a/ansible_collections/community/aws/tests/integration/targets/opensearch/tasks/test_vpc_setup.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/opensearch/tasks/test_vpc_setup.yml
@@ -83,7 +83,7 @@
AnsibleTest: AnsibleTestVpc
- name: Create security group for use in testing
- ec2_group:
+ ec2_security_group:
name: "{{ tiny_prefix }}-sg"
description: a security group for ansible tests
vpc_id: "{{ testing_vpc.vpc.id }}"
@@ -120,7 +120,7 @@
- name: Create KMS key for test purpose
# The key is needed for OpenSearch encryption at rest.
- aws_kms:
+ kms_key:
alias: "{{ tiny_prefix }}-kms"
description: a key used for encryption at rest in test OpenSearch cluster
state: present
diff --git a/ansible_collections/community/aws/tests/integration/targets/redshift/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/redshift/tasks/main.yml
index f79991d4e..a50c0372e 100644
--- a/ansible_collections/community/aws/tests/integration/targets/redshift/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/redshift/tasks/main.yml
@@ -8,9 +8,9 @@
- module_defaults:
group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"
block:
@@ -120,7 +120,7 @@
assert:
that:
- 'result.changed'
- - 'result.cluster.identifier == "{{ redshift_cluster_name }}"'
+ - result.cluster.identifier == redshift_cluster_name
- 'result.cluster.tags.foo == "bar"'
- 'result.cluster.tags.Tizio == "Caio"'
@@ -143,7 +143,7 @@
assert:
that:
- 'not result.changed'
- - 'result.cluster.identifier == "{{ redshift_cluster_name }}"'
+ - result.cluster.identifier == redshift_cluster_name
- 'result.cluster.tags.foo == "bar"'
- 'result.cluster.tags.Tizio == "Caio"'
- 'result.cluster.tags | count() == 2'
@@ -166,7 +166,7 @@
assert:
that:
- 'result.changed'
- - 'result.cluster.identifier == "{{ redshift_cluster_name }}-modified"'
+ - result.cluster.identifier == redshift_cluster_name ~ '-modified'
- 'result.cluster.enhanced_vpc_routing == True'
- 'result.cluster.tags | count() == 1'
- 'result.cluster.tags.foo == "bar"'
@@ -234,7 +234,7 @@
assert:
that:
- 'result.changed'
- - 'result.cluster.identifier == "{{ redshift_cluster_name }}"'
+ - result.cluster.identifier == redshift_cluster_name
- 'result.cluster.db_name == "integration_test"'
# ============================================================
@@ -260,7 +260,7 @@
assert:
that:
- 'result.changed'
- - 'result.cluster.identifier == "{{ redshift_cluster_name }}"'
+ - result.cluster.identifier == redshift_cluster_name
- 'result.cluster.db_name == "integration_test"'
- 'result.cluster.tags.foo == "bar"'
@@ -289,7 +289,7 @@
assert:
that:
- 'result.changed'
- - 'result.cluster.identifier == "{{ redshift_cluster_name }}"'
+ - result.cluster.identifier == redshift_cluster_name
- 'result.cluster.db_name == "integration_test"'
- 'result.cluster.tags.test1 == "value1"'
- 'result.cluster.tags.foo == "bar"'
@@ -318,7 +318,7 @@
assert:
that:
- 'not result.changed'
- - 'result.cluster.identifier == "{{ redshift_cluster_name }}"'
+ - result.cluster.identifier == redshift_cluster_name
- 'result.cluster.db_name == "integration_test"'
- 'result.cluster.tags | count() == 2'
diff --git a/ansible_collections/community/aws/tests/integration/targets/redshift_subnet_group/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/redshift_subnet_group/tasks/main.yml
index e15ee9b93..0df7d98d0 100644
--- a/ansible_collections/community/aws/tests/integration/targets/redshift_subnet_group/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/redshift_subnet_group/tasks/main.yml
@@ -9,9 +9,9 @@
#
- module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region }}'
block:
diff --git a/ansible_collections/community/aws/tests/integration/targets/s3_bucket_info/aliases b/ansible_collections/community/aws/tests/integration/targets/route53_wait/aliases
index 4ef4b2067..4ef4b2067 100644
--- a/ansible_collections/community/aws/tests/integration/targets/s3_bucket_info/aliases
+++ b/ansible_collections/community/aws/tests/integration/targets/route53_wait/aliases
diff --git a/ansible_collections/community/aws/tests/integration/targets/route53_wait/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/route53_wait/tasks/main.yml
new file mode 100644
index 000000000..f9df05f5c
--- /dev/null
+++ b/ansible_collections/community/aws/tests/integration/targets/route53_wait/tasks/main.yml
@@ -0,0 +1,245 @@
+---
+# tasks file for route53_wait integration tests
+
+- set_fact:
+ zone_one: '{{ resource_prefix | replace("-", "") }}.one.ansible.test.'
+- debug:
+ msg: Set zone {{ zone_one }}
+
+- name: Test basics (new zone, A and AAAA records)
+ module_defaults:
+ group/aws:
+ aws_access_key: '{{ aws_access_key }}'
+ aws_secret_key: '{{ aws_secret_key }}'
+ security_token: '{{ security_token | default(omit) }}'
+ region: '{{ aws_region }}'
+ amazon.aws.route53:
+ # Route53 is explicitly a global service
+ region:
+ block:
+ - name: create VPC
+ ec2_vpc_net:
+ cidr_block: 192.0.2.0/24
+ name: '{{ resource_prefix }}_vpc'
+ state: present
+ register: vpc
+
+ - name: Create a zone
+ route53_zone:
+ zone: '{{ zone_one }}'
+ comment: Created in Ansible test {{ resource_prefix }}
+ tags:
+ TestTag: '{{ resource_prefix }}.z1'
+ register: z1
+
+ - name: Create A record (check mode)
+ route53:
+ state: present
+ hosted_zone_id: '{{ z1.zone_id }}'
+ record: test.{{ zone_one }}
+ overwrite: true
+ type: A
+ value: 192.0.2.1
+ wait: false
+ register: result
+ check_mode: true
+ - assert:
+ that:
+ - result is not failed
+ - result is changed
+ - "'wait_id' in result"
+ - result.wait_id is none
+
+ - name: Wait for A record to propagate (should do nothing)
+ route53_wait:
+ result: '{{ result }}'
+
+ - name: Create A record
+ route53:
+ state: present
+ hosted_zone_id: '{{ z1.zone_id }}'
+ record: test.{{ zone_one }}
+ overwrite: true
+ type: A
+ value: 192.0.2.1
+ wait: false
+ register: result
+ - assert:
+ that:
+ - result is not failed
+ - result is changed
+ - "'wait_id' in result"
+ - result.wait_id is string
+
+ - name: Wait for A record to propagate
+ route53_wait:
+ result: '{{ result }}'
+
+ - name: Create A record (idempotent)
+ route53:
+ state: present
+ hosted_zone_id: '{{ z1.zone_id }}'
+ record: test.{{ zone_one }}
+ overwrite: true
+ type: A
+ value: 192.0.2.1
+ wait: false
+ register: result
+ - assert:
+ that:
+ - result is not failed
+ - result is not changed
+ - "'wait_id' not in result"
+
+ - name: Wait for A record to propagate (should do nothing)
+ route53_wait:
+ result: '{{ result }}'
+
+ - name: Create A records
+ route53:
+ state: present
+ hosted_zone_id: '{{ z1.zone_id }}'
+ record: '{{ item.record }}'
+ overwrite: true
+ type: A
+ value: '{{ item.value }}'
+ wait: false
+ loop:
+ - record: test-1.{{ zone_one }}
+ value: 192.0.2.1
+ - record: test-2.{{ zone_one }}
+ value: 192.0.2.2
+ - record: test-3.{{ zone_one }}
+ value: 192.0.2.3
+ register: results
+ - assert:
+ that:
+ - results is not failed
+ - results is changed
+ - results.results | length == 3
+ - results.results[0] is changed
+ - results.results[1] is changed
+ - results.results[2] is changed
+
+ - name: Wait for A records to propagate
+ route53_wait:
+ results: '{{ results }}'
+
+ - name: Create A records (idempotent)
+ route53:
+ state: present
+ hosted_zone_id: '{{ z1.zone_id }}'
+ record: '{{ item.record }}'
+ overwrite: true
+ type: A
+ value: '{{ item.value }}'
+ wait: false
+ loop:
+ - record: test-1.{{ zone_one }}
+ value: 192.0.2.1
+ - record: test-2.{{ zone_one }}
+ value: 192.0.2.2
+ - record: test-3.{{ zone_one }}
+ value: 192.0.2.3
+ register: results
+ - assert:
+ that:
+ - results is not failed
+ - results is not changed
+ - results.results | length == 3
+ - results.results[0] is not changed
+ - results.results[1] is not changed
+ - results.results[2] is not changed
+
+ - name: Wait for A records to propagate (should do nothing)
+ route53_wait:
+ results: '{{ results }}'
+
+ - name: Update some A records
+ route53:
+ state: present
+ hosted_zone_id: '{{ z1.zone_id }}'
+ record: '{{ item.record }}'
+ overwrite: true
+ type: A
+ value: '{{ item.value }}'
+ wait: false
+ loop:
+ - record: test-1.{{ zone_one }}
+ value: 192.0.2.1
+ - record: test-2.{{ zone_one }}
+ value: 192.0.2.4
+ - record: test-3.{{ zone_one }}
+ value: 192.0.2.3
+ register: results
+ - assert:
+ that:
+ - results is not failed
+ - results is changed
+ - results.results | length == 3
+ - results.results[0] is not changed
+ - results.results[1] is changed
+ - results.results[2] is not changed
+
+ - name: Wait for A records to propagate
+ route53_wait:
+ results: '{{ results }}'
+
+#Cleanup------------------------------------------------------
+
+ always:
+
+ - route53_info:
+ query: record_sets
+ hosted_zone_id: '{{ z1.zone_id }}'
+ register: z1_records
+
+ - name: Loop over A/AAAA/CNAME records and delete them
+ route53:
+ state: absent
+ zone: '{{ zone_one }}'
+ record: '{{ item.Name }}'
+ type: '{{ item.Type }}'
+ value: '{{ item.ResourceRecords | map(attribute="Value") | join(",") }}'
+ weight: '{{ item.Weight | default(omit) }}'
+ identifier: '{{ item.SetIdentifier }}'
+ region: '{{ omit }}'
+ ignore_errors: true
+ loop: '{{ z1_records.ResourceRecordSets | selectattr("Type", "in", ["A", "AAAA",
+ "CNAME", "CAA"]) | list }}'
+ when:
+ - '"ResourceRecords" in item'
+ - '"SetIdentifier" in item'
+
+ - name: Loop over A/AAAA/CNAME records and delete them
+ route53:
+ state: absent
+ zone: '{{ zone_one }}'
+ record: '{{ item.Name }}'
+ type: '{{ item.Type }}'
+ value: '{{ item.ResourceRecords | map(attribute="Value") | join(",") }}'
+ ignore_errors: true
+ loop: '{{ z1_records.ResourceRecordSets | selectattr("Type", "in", ["A", "AAAA",
+ "CNAME", "CAA"]) | list }}'
+ when:
+ - '"ResourceRecords" in item'
+
+ - name: Delete test zone one {{ zone_one }}
+ route53_zone:
+ state: absent
+ zone: '{{ zone_one }}'
+ register: delete_one
+ ignore_errors: true
+ retries: 10
+ until: delete_one is not failed
+
+ - name: destroy VPC
+ ec2_vpc_net:
+ cidr_block: 192.0.2.0/24
+ name: '{{ resource_prefix }}_vpc'
+ state: absent
+ register: remove_vpc
+ retries: 10
+ delay: 5
+ until: remove_vpc is success
+ ignore_errors: true
diff --git a/ansible_collections/community/aws/tests/integration/targets/s3_bucket_info/defaults/main.yml b/ansible_collections/community/aws/tests/integration/targets/s3_bucket_info/defaults/main.yml
deleted file mode 100644
index 464c0a299..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/s3_bucket_info/defaults/main.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-name_pattern: "testbucket-ansible-integration"
-testing_buckets:
- - "{{ tiny_prefix }}-{{ name_pattern }}-1"
- - "{{ tiny_prefix }}-{{ name_pattern }}-2"
diff --git a/ansible_collections/community/aws/tests/integration/targets/s3_bucket_info/meta/main.yml b/ansible_collections/community/aws/tests/integration/targets/s3_bucket_info/meta/main.yml
deleted file mode 100644
index 32cf5dda7..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/s3_bucket_info/meta/main.yml
+++ /dev/null
@@ -1 +0,0 @@
-dependencies: []
diff --git a/ansible_collections/community/aws/tests/integration/targets/s3_bucket_info/tasks/basic.yml b/ansible_collections/community/aws/tests/integration/targets/s3_bucket_info/tasks/basic.yml
deleted file mode 100644
index bf09665af..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/s3_bucket_info/tasks/basic.yml
+++ /dev/null
@@ -1,72 +0,0 @@
----
-- name: Get simple S3 bucket list
- aws_s3_bucket_info:
- register: bucket_list
-
-- name: Assert result.changed == False and bucket list was retrieved
- assert:
- that:
- - bucket_list.changed == False
- - bucket_list.buckets
-
-- name: Get complex S3 bucket list
- aws_s3_bucket_info:
- name_filter: "{{ name_pattern }}"
- bucket_facts:
- bucket_accelerate_configuration: true
- bucket_acl: true
- bucket_cors: true
- bucket_encryption: true
- bucket_lifecycle_configuration: true
- bucket_location: true
- bucket_logging: true
- bucket_notification_configuration: true
- bucket_policy: true
- bucket_policy_status: true
- bucket_replication: true
- bucket_request_payment: true
- bucket_tagging: true
- bucket_website: true
- public_access_block: true
- transform_location: true
- register: bucket_list
-
-- name: Assert that buckets list contains requested bucket facts
- assert:
- that:
- - item.name is search(name_pattern)
- - item.bucket_accelerate_configuration is defined
- - item.bucket_acl is defined
- - item.bucket_cors is defined
- - item.bucket_encryption is defined
- - item.bucket_lifecycle_configuration is defined
- - item.bucket_location is defined
- - item.bucket_logging is defined
- - item.bucket_notification_configuration is defined
- - item.bucket_policy is defined
- - item.bucket_policy_status is defined
- - item.bucket_replication is defined
- - item.bucket_request_payment is defined
- - item.bucket_tagging is defined
- - item.bucket_website is defined
- - item.public_access_block is defined
- loop: "{{ bucket_list.buckets }}"
- loop_control:
- label: "{{ item.name }}"
-
-- name: Assert that retrieved bucket facts contains valid data
- assert:
- that:
- - item.bucket_acl.Owner is defined
- - item.bucket_tagging.snake_case is defined
- - item.bucket_tagging.CamelCase is defined
- - item.bucket_tagging["lowercase spaced"] is defined
- - item.bucket_tagging["Title Case"] is defined
- - item.bucket_tagging.snake_case == 'simple_snake_case'
- - item.bucket_tagging.CamelCase == 'SimpleCamelCase'
- - item.bucket_tagging["lowercase spaced"] == 'hello cruel world'
- - item.bucket_tagging["Title Case"] == 'Hello Cruel World'
- - item.bucket_location.LocationConstraint == aws_region
- loop: "{{ bucket_list.buckets }}"
- loop_control:
- label: "{{ item.name }}"
diff --git a/ansible_collections/community/aws/tests/integration/targets/s3_bucket_info/tasks/bucket_ownership_controls.yml b/ansible_collections/community/aws/tests/integration/targets/s3_bucket_info/tasks/bucket_ownership_controls.yml
deleted file mode 100644
index 3acd99cf6..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/s3_bucket_info/tasks/bucket_ownership_controls.yml
+++ /dev/null
@@ -1,81 +0,0 @@
----
-- name: Get S3 bucket ownership controls
- aws_s3_bucket_info:
- name_filter: "{{ name_pattern }}"
- bucket_facts:
- bucket_ownership_controls: true
- transform_location: true
- register: bucket_list
-
-- name: Assert that buckets list contains requested bucket facts
- assert:
- that:
- - item.name is search(name_pattern)
- - item.bucket_ownership_controls is defined
- loop: "{{ bucket_list.buckets }}"
- loop_control:
- label: "{{ item.name }}"
-
-- name: Get complex S3 bucket list (including ownership controls)
- aws_s3_bucket_info:
- name_filter: "{{ name_pattern }}"
- bucket_facts:
- bucket_accelerate_configuration: true
- bucket_acl: true
- bucket_cors: true
- bucket_encryption: true
- bucket_lifecycle_configuration: true
- bucket_location: true
- bucket_logging: true
- bucket_notification_configuration: true
- bucket_ownership_controls: true
- bucket_policy: true
- bucket_policy_status: true
- bucket_replication: true
- bucket_request_payment: true
- bucket_tagging: true
- bucket_website: true
- public_access_block: true
- transform_location: true
- register: bucket_list
-
-- name: Assert that buckets list contains requested bucket facts
- assert:
- that:
- - item.name is search(name_pattern)
- - item.bucket_accelerate_configuration is defined
- - item.bucket_acl is defined
- - item.bucket_cors is defined
- - item.bucket_encryption is defined
- - item.bucket_lifecycle_configuration is defined
- - item.bucket_location is defined
- - item.bucket_logging is defined
- - item.bucket_notification_configuration is defined
- - item.bucket_ownership_controls is defined
- - item.bucket_policy is defined
- - item.bucket_policy_status is defined
- - item.bucket_replication is defined
- - item.bucket_request_payment is defined
- - item.bucket_tagging is defined
- - item.bucket_website is defined
- - item.public_access_block is defined
- loop: "{{ bucket_list.buckets }}"
- loop_control:
- label: "{{ item.name }}"
-
-- name: Assert that retrieved bucket facts contains valid data
- assert:
- that:
- - item.bucket_acl.Owner is defined
- - item.bucket_tagging.snake_case is defined
- - item.bucket_tagging.CamelCase is defined
- - item.bucket_tagging["lowercase spaced"] is defined
- - item.bucket_tagging["Title Case"] is defined
- - item.bucket_tagging.snake_case == 'simple_snake_case'
- - item.bucket_tagging.CamelCase == 'SimpleCamelCase'
- - item.bucket_tagging["lowercase spaced"] == 'hello cruel world'
- - item.bucket_tagging["Title Case"] == 'Hello Cruel World'
- - item.bucket_location.LocationConstraint == aws_region
- loop: "{{ bucket_list.buckets }}"
- loop_control:
- label: "{{ item.name }}"
diff --git a/ansible_collections/community/aws/tests/integration/targets/s3_bucket_info/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/s3_bucket_info/tasks/main.yml
deleted file mode 100644
index 47d24cd0e..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/s3_bucket_info/tasks/main.yml
+++ /dev/null
@@ -1,30 +0,0 @@
----
-- name: Test community.aws.aws_s3_bucket_info
- module_defaults:
- group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
- region: "{{ aws_region }}"
- block:
- - name: Create a simple s3_bucket
- s3_bucket:
- name: "{{ item }}"
- state: present
- tags:
- "lowercase spaced": "hello cruel world"
- "Title Case": "Hello Cruel World"
- CamelCase: "SimpleCamelCase"
- snake_case: "simple_snake_case"
- register: output
- loop: "{{ testing_buckets }}"
-
- - include_tasks: basic.yml
- - include_tasks: bucket_ownership_controls.yml
-
- always:
- - name: Delete simple s3_buckets
- s3_bucket:
- name: "{{ item }}"
- state: absent
- loop: "{{ testing_buckets }}"
diff --git a/ansible_collections/community/aws/tests/integration/targets/s3_bucket_notification/files/mini_lambda.py b/ansible_collections/community/aws/tests/integration/targets/s3_bucket_notification/files/mini_lambda.py
index d0d08dae9..c2b19be1d 100644
--- a/ansible_collections/community/aws/tests/integration/targets/s3_bucket_notification/files/mini_lambda.py
+++ b/ansible_collections/community/aws/tests/integration/targets/s3_bucket_notification/files/mini_lambda.py
@@ -1,13 +1,13 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
__metaclass__ = type
import json
def lambda_handler(event, context):
- return {
- 'statusCode': 200,
- 'body': json.dumps('Hello from Lambda!')
- }
+ return {"statusCode": 200, "body": json.dumps("Hello from Lambda!")}
diff --git a/ansible_collections/community/aws/tests/integration/targets/s3_bucket_notification/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/s3_bucket_notification/tasks/main.yml
index ea7201065..ce81efc8c 100644
--- a/ansible_collections/community/aws/tests/integration/targets/s3_bucket_notification/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/s3_bucket_notification/tasks/main.yml
@@ -4,9 +4,9 @@
- community.general
module_defaults:
group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"
block:
- include_tasks: test_sns_sqs_notifications.yml
diff --git a/ansible_collections/community/aws/tests/integration/targets/s3_lifecycle/aliases b/ansible_collections/community/aws/tests/integration/targets/s3_lifecycle/aliases
index 4ef4b2067..1ba8d84ef 100644
--- a/ansible_collections/community/aws/tests/integration/targets/s3_lifecycle/aliases
+++ b/ansible_collections/community/aws/tests/integration/targets/s3_lifecycle/aliases
@@ -1 +1,2 @@
+time=17m
cloud/aws
diff --git a/ansible_collections/community/aws/tests/integration/targets/s3_lifecycle/meta/main.yml b/ansible_collections/community/aws/tests/integration/targets/s3_lifecycle/meta/main.yml
index c01990664..32cf5dda7 100644
--- a/ansible_collections/community/aws/tests/integration/targets/s3_lifecycle/meta/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/s3_lifecycle/meta/main.yml
@@ -1,4 +1 @@
-dependencies:
- - role: setup_botocore_pip
- vars:
- botocore_version: "1.23.12"
+dependencies: []
diff --git a/ansible_collections/community/aws/tests/integration/targets/s3_lifecycle/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/s3_lifecycle/tasks/main.yml
index 7a15e4b66..d9f169561 100644
--- a/ansible_collections/community/aws/tests/integration/targets/s3_lifecycle/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/s3_lifecycle/tasks/main.yml
@@ -4,9 +4,9 @@
- amazon.aws
module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region }}'
s3_lifecycle:
wait: true
@@ -465,8 +465,6 @@
noncurrent_version_keep_newer: 6
prefix: /something
register: output
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
- assert:
that:
@@ -479,8 +477,6 @@
noncurrent_version_keep_newer: 6
prefix: /something
register: output
- vars:
- ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
- assert:
that:
diff --git a/ansible_collections/community/aws/tests/integration/targets/s3_logging/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/s3_logging/tasks/main.yml
index f6c9a1710..e9a7b220b 100644
--- a/ansible_collections/community/aws/tests/integration/targets/s3_logging/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/s3_logging/tasks/main.yml
@@ -11,9 +11,9 @@
#
- module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region }}'
collections:
- amazon.aws
diff --git a/ansible_collections/community/aws/tests/integration/targets/s3_metrics_configuration/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/s3_metrics_configuration/tasks/main.yml
index ba5cce9e6..9e9f1133a 100644
--- a/ansible_collections/community/aws/tests/integration/targets/s3_metrics_configuration/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/s3_metrics_configuration/tasks/main.yml
@@ -6,10 +6,10 @@
#
- module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key | default(omit) }}'
- aws_secret_key: '{{ aws_secret_key | default(omit) }}'
- security_token: '{{ security_token | default(omit) }}'
- region: '{{ aws_region | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
+ region: '{{ aws_region }}'
collections:
- amazon.aws
block:
diff --git a/ansible_collections/community/aws/tests/integration/targets/s3_metrics_configuration/tasks/s3_metrics_info.yml b/ansible_collections/community/aws/tests/integration/targets/s3_metrics_configuration/tasks/s3_metrics_info.yml
index cca7cad05..fdbc8cbfc 100644
--- a/ansible_collections/community/aws/tests/integration/targets/s3_metrics_configuration/tasks/s3_metrics_info.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/s3_metrics_configuration/tasks/s3_metrics_info.yml
@@ -6,10 +6,10 @@
aws s3api list-bucket-metrics-configurations
--bucket {{ test_bucket }}
environment:
- AWS_ACCESS_KEY_ID: "{{ aws_access_key | default(omit) }}"
- AWS_SECRET_ACCESS_KEY: "{{ aws_secret_key | default(omit) }}"
+ AWS_ACCESS_KEY_ID: "{{ aws_access_key }}"
+ AWS_SECRET_ACCESS_KEY: "{{ aws_secret_key }}"
AWS_SESSION_TOKEN: "{{ security_token | default(omit) }}"
- AWS_DEFAULT_REGION: "{{ aws_region | default(omit) }}"
+ AWS_DEFAULT_REGION: "{{ aws_region }}"
register: list_comand_result
- set_fact:
diff --git a/ansible_collections/community/aws/tests/integration/targets/s3_sync/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/s3_sync/tasks/main.yml
index 08496cd74..600490706 100644
--- a/ansible_collections/community/aws/tests/integration/targets/s3_sync/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/s3_sync/tasks/main.yml
@@ -5,9 +5,9 @@
- community.general
module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region }}'
block:
# ============================================================
@@ -23,7 +23,7 @@
- assert:
that:
- output.changed
- - output.name == "{{ test_bucket }}"
+ - output.name == test_bucket
- not output.requester_pays
# ============================================================
- name: Prepare fixtures folder
@@ -67,7 +67,7 @@
- assert:
that:
- output.changed
- - output.name == "{{ test_bucket_2 }}"
+ - output.name == test_bucket_2
- not output.requester_pays
- name: Sync files with remote bucket using glacier storage class
@@ -113,7 +113,7 @@
- assert:
that:
- output.changed
- - output.name == "{{ test_bucket_3 }}"
+ - output.name == test_bucket_3
- not output.requester_pays
- name: Sync individual file with remote bucket
@@ -158,14 +158,14 @@
- name: Empty all buckets before deleting
block:
- name: list test_bucket objects
- aws_s3:
+ s3_object:
bucket: "{{ test_bucket }}"
mode: list
register: objects
ignore_errors: true
- name: remove objects from test_bucket
- aws_s3:
+ s3_object:
bucket: "{{ test_bucket }}"
mode: delobj
object: "{{ obj }}"
@@ -175,14 +175,14 @@
ignore_errors: true
- name: list test_bucket_2 objects
- aws_s3:
+ s3_object:
bucket: "{{ test_bucket_2 }}"
mode: list
register: objects
ignore_errors: true
- name: remove objects from test_bucket_2
- aws_s3:
+ s3_object:
bucket: "{{ test_bucket_2 }}"
mode: delobj
object: "{{ obj }}"
@@ -192,14 +192,14 @@
ignore_errors: true
- name: list test_bucket_3 objects
- aws_s3:
+ s3_object:
bucket: "{{ test_bucket_3 }}"
mode: list
register: objects
ignore_errors: true
- name: remove objects from test_bucket_3
- aws_s3:
+ s3_object:
bucket: "{{ test_bucket_3 }}"
mode: delobj
object: "{{ obj }}"
diff --git a/ansible_collections/community/aws/tests/integration/targets/secretsmanager_secret/aliases b/ansible_collections/community/aws/tests/integration/targets/secretsmanager_secret/aliases
index 4ef4b2067..e5729917b 100644
--- a/ansible_collections/community/aws/tests/integration/targets/secretsmanager_secret/aliases
+++ b/ansible_collections/community/aws/tests/integration/targets/secretsmanager_secret/aliases
@@ -1 +1,2 @@
+time=37m
cloud/aws
diff --git a/ansible_collections/community/aws/tests/integration/targets/secretsmanager_secret/tasks/basic.yml b/ansible_collections/community/aws/tests/integration/targets/secretsmanager_secret/tasks/basic.yml
index 5d1fb071e..ea285ee05 100644
--- a/ansible_collections/community/aws/tests/integration/targets/secretsmanager_secret/tasks/basic.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/secretsmanager_secret/tasks/basic.yml
@@ -23,9 +23,9 @@
# As a lookup plugin we won't have access to module_defaults
connection_args:
region: "{{ aws_region }}"
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- aws_security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
no_log: True
- vars:
@@ -73,7 +73,7 @@
# Creation testing
# ============================================================
- name: add secret to AWS Secrets Manager
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}"
state: present
secret_type: 'string'
@@ -100,7 +100,7 @@
secret_arn: '{{ result.secret.arn }}'
- name: no changes to secret
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}"
state: present
secret_type: 'string'
@@ -122,7 +122,7 @@
- result.secret.version_ids_to_stages | length == 1
- name: Set secret description
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}"
description: 'this is a change to this secret'
state: present
@@ -151,7 +151,7 @@
###############################################################
- name: Set tags (CHECK_MODE)
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}"
description: 'this is a change to this secret'
state: present
@@ -167,7 +167,7 @@
- result is changed
- name: Set tags
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}"
description: 'this is a change to this secret'
state: present
@@ -197,7 +197,7 @@
- result.secret.version_ids_to_stages | length == 2
- name: Set tags - idempotency (CHECK_MODE)
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}"
description: 'this is a change to this secret'
state: present
@@ -213,7 +213,7 @@
- result is not changed
- name: Set tags - idempotency
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}"
description: 'this is a change to this secret'
state: present
@@ -245,7 +245,7 @@
###
- name: Update tags with purge (CHECK_MODE)
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}"
description: 'this is a change to this secret'
state: present
@@ -261,7 +261,7 @@
- result is changed
- name: Update tags with purge
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}"
description: 'this is a change to this secret'
state: present
@@ -291,7 +291,7 @@
- result.secret.version_ids_to_stages | length == 2
- name: Update tags with purge - idempotency (CHECK_MODE)
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}"
description: 'this is a change to this secret'
state: present
@@ -307,7 +307,7 @@
- result is not changed
- name: Update tags with purge - idempotency
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}"
description: 'this is a change to this secret'
state: present
@@ -339,7 +339,7 @@
###
- name: Update tags without purge (CHECK_MODE)
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}"
description: 'this is a change to this secret'
state: present
@@ -356,7 +356,7 @@
- result is changed
- name: Update tags without purge
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}"
description: 'this is a change to this secret'
state: present
@@ -387,7 +387,7 @@
- result.secret.version_ids_to_stages | length == 2
- name: Update tags without purge - idempotency (CHECK_MODE)
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}"
description: 'this is a change to this secret'
state: present
@@ -404,7 +404,7 @@
- result is not changed
- name: Update tags without purge - idempotency
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}"
description: 'this is a change to this secret'
state: present
@@ -437,7 +437,7 @@
###
- name: Tags not set - idempotency (CHECK_MODE)
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}"
description: 'this is a change to this secret'
state: present
@@ -452,7 +452,7 @@
- result is not changed
- name: Tags not set - idempotency
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}"
description: 'this is a change to this secret'
state: present
@@ -483,7 +483,7 @@
###
- name: remove all tags from secret (CHECK_MODE)
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}"
description: 'this is a change to this secret'
state: present
@@ -499,7 +499,7 @@
- result is changed
- name: remove all tags from secret
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}"
description: 'this is a change to this secret'
state: present
@@ -529,7 +529,7 @@
- result.secret.version_ids_to_stages | length == 2
- name: remove all tags from secret - idempotency (CHECK_MODE)
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}"
description: 'this is a change to this secret'
state: present
@@ -545,7 +545,7 @@
- result is not changed
- name: remove all tags from secret
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}"
description: 'this is a change to this secret'
state: present
@@ -579,7 +579,7 @@
###############################################################
- name: add resource policy to secret
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}"
description: 'this is a change to this secret'
state: present
@@ -594,7 +594,7 @@
- result.changed
- name: remove existing resource policy from secret
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}"
description: 'this is a change to this secret'
state: present
@@ -608,7 +608,7 @@
- result.changed
- name: remove resource policy from secret (idempotency)
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}"
description: 'this is a change to this secret'
state: present
@@ -626,7 +626,7 @@
# ============================================================
- name: Update secret with JSON (CHECK_MODE)
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}"
description: 'this is a change to this secret'
state: present
@@ -642,7 +642,7 @@
- result.changed
- name: Update secret with JSON
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}"
state: present
description: 'this is a change to this secret'
@@ -657,7 +657,7 @@
- result.changed
- name: Update secret with JSON - idempotency (CHECK_MODE)
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}"
description: 'this is a change to this secret'
state: present
@@ -673,7 +673,7 @@
- result is not changed
- name: Update secret with JSON - idempotency
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}"
description: 'this is a change to this secret'
state: present
@@ -693,7 +693,7 @@
# ============================================================
- name: Create secret with overwrite = False (Check mode)
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}-2"
state: present
secret_type: 'string'
@@ -708,7 +708,7 @@
- result is changed
- name: Create secret with overwrite = False
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}-2"
state: present
secret_type: 'string'
@@ -722,7 +722,7 @@
- result is changed
- name: Update secret with overwrite = False (Check mode)
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}-2"
state: present
secret_type: 'string'
@@ -737,7 +737,7 @@
- result is not changed
- name: Create secret with overwrite = False
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}-2"
state: present
secret_type: 'string'
@@ -755,7 +755,7 @@
# ============================================================
- name: remove secret
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}"
state: absent
recovery_window: 7
@@ -767,7 +767,7 @@
- result.changed
- name: remove secret (idempotency)
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}"
state: absent
recovery_window: 7
@@ -779,7 +779,7 @@
- not result.changed
- name: immediate secret removal
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}"
state: absent
recovery_window: 0
@@ -793,7 +793,7 @@
# AWS Doesn't expose when the secret will be removed, all we can do is
# check that we didn't throw an error
- name: immediate secret removal
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}"
state: absent
recovery_window: 0
@@ -806,14 +806,14 @@
always:
- name: remove secret
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}"
state: absent
recovery_window: 0
ignore_errors: yes
- name: remove secret 2
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}-2"
state: absent
recovery_window: 0
diff --git a/ansible_collections/community/aws/tests/integration/targets/secretsmanager_secret/tasks/main.yaml b/ansible_collections/community/aws/tests/integration/targets/secretsmanager_secret/tasks/main.yaml
index 41fbedd9d..9011071f8 100644
--- a/ansible_collections/community/aws/tests/integration/targets/secretsmanager_secret/tasks/main.yaml
+++ b/ansible_collections/community/aws/tests/integration/targets/secretsmanager_secret/tasks/main.yaml
@@ -1,9 +1,9 @@
---
- module_defaults:
group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"
collections:
- amazon.aws
diff --git a/ansible_collections/community/aws/tests/integration/targets/secretsmanager_secret/tasks/replication.yml b/ansible_collections/community/aws/tests/integration/targets/secretsmanager_secret/tasks/replication.yml
index 30d3a9484..30f178c06 100644
--- a/ansible_collections/community/aws/tests/integration/targets/secretsmanager_secret/tasks/replication.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/secretsmanager_secret/tasks/replication.yml
@@ -4,7 +4,7 @@
# Creation/Deletion testing
# ============================================================
- name: add secret to AWS Secrets Manager
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}"
state: present
secret_type: 'string'
@@ -28,7 +28,7 @@
- result.version_ids_to_stages is not none
- name: no changes to secret
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}"
state: present
secret: "{{ super_secret_string }}"
@@ -45,7 +45,7 @@
- result.arn is not none
- name: remove region replica
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}"
description: 'this is a change to remove replication'
secret: "{{ super_secret_string }}"
@@ -60,7 +60,7 @@
- '"replication_status" not in result.secret'
- name: add region replica to an existing secret
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}"
description: 'this is a change add replication'
secret: "{{ super_secret_string }}"
@@ -80,7 +80,7 @@
- result.secret.replication_status[1]["kms_key_id"] == 'alias/aws/secretsmanager'
- name: change replica regions
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}"
state: present
secret: "{{ super_secret_string }}"
@@ -100,7 +100,7 @@
always:
- name: remove region replica
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}"
description: 'this is a change to remove replication'
state: present
@@ -109,7 +109,7 @@
ignore_errors: yes
- name: remove secret
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}"
state: absent
recovery_window: 0
diff --git a/ansible_collections/community/aws/tests/integration/targets/secretsmanager_secret/tasks/rotation.yml b/ansible_collections/community/aws/tests/integration/targets/secretsmanager_secret/tasks/rotation.yml
index 5a1d146e5..697c5ecc2 100644
--- a/ansible_collections/community/aws/tests/integration/targets/secretsmanager_secret/tasks/rotation.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/secretsmanager_secret/tasks/rotation.yml
@@ -1,9 +1,9 @@
---
- module_defaults:
group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"
collections:
- amazon.aws
@@ -70,7 +70,7 @@
# Creation/Deletion testing
# ============================================================
- name: add secret to AWS Secrets Manager
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}-rotate"
state: present
secret_type: 'string'
@@ -95,7 +95,7 @@
principal: "secretsmanager.amazonaws.com"
- name: add rotation lambda to secret
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}-rotate"
description: 'this is a change to this secret'
state: present
@@ -113,7 +113,7 @@
- result.changed
- name: remove rotation lambda from secret
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}-rotate"
description: 'this is a change to this secret'
state: present
@@ -127,7 +127,7 @@
- result.changed
- name: remove rotation lambda from secret
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}-rotate"
description: 'this is a change to this secret'
state: present
@@ -141,7 +141,7 @@
- not result.changed
- name: remove secret
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}-rotate"
state: absent
recovery_window: 0
@@ -149,7 +149,7 @@
always:
- name: remove secret
- aws_secret:
+ secretsmanager_secret:
name: "{{ secret_name }}-rotate"
state: absent
recovery_window: 0
diff --git a/ansible_collections/community/aws/tests/integration/targets/ses_identity/tasks/assert_defaults.yaml b/ansible_collections/community/aws/tests/integration/targets/ses_identity/tasks/assert_defaults.yaml
index 0f74d2f05..266822633 100644
--- a/ansible_collections/community/aws/tests/integration/targets/ses_identity/tasks/assert_defaults.yaml
+++ b/ansible_collections/community/aws/tests/integration/targets/ses_identity/tasks/assert_defaults.yaml
@@ -5,8 +5,8 @@
- name: assert returned identity_arn
assert:
that:
- - "result.identity_arn|regex_search('^arn:aws:ses:' + ec2_region + ':[0-9]*:identity/' + identity + '$')"
- msg: "'{{ result.identity_arn}}' doesn't match regex '^arn:aws:ses:{{ ec2_region }}:[0-9]*:identity/{{ identity }}'"
+ - "result.identity_arn|regex_search('^arn:aws:ses:' + aws_region + ':[0-9]*:identity/' + identity + '$')"
+ msg: "'{{ result.identity_arn}}' doesn't match regex '^arn:aws:ses:{{ aws_region }}:[0-9]*:identity/{{ identity }}'"
- name: assert verification_attributes.verification_status == 'Pending'
assert:
that:
diff --git a/ansible_collections/community/aws/tests/integration/targets/ses_identity/tasks/main.yaml b/ansible_collections/community/aws/tests/integration/targets/ses_identity/tasks/main.yaml
index 81ab3c4a7..3ecb68c38 100644
--- a/ansible_collections/community/aws/tests/integration/targets/ses_identity/tasks/main.yaml
+++ b/ansible_collections/community/aws/tests/integration/targets/ses_identity/tasks/main.yaml
@@ -4,9 +4,9 @@
- amazon.aws
module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region }}'
block:
@@ -14,7 +14,7 @@
- name: test register email identity
block:
- name: register email identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ email_identity }}"
state: present
register: result
@@ -27,14 +27,14 @@
identity: "{{ email_identity }}"
always:
- name: cleanup email identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ email_identity }}"
state: absent
# ============================================================
- name: test register domain identity
block:
- name: register domain identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ domain_identity }}"
state: present
register: result
@@ -51,18 +51,18 @@
- result.verification_attributes.verification_token
always:
- name: cleanup domain identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ domain_identity }}"
state: absent
# ============================================================
- name: test email_identity unchanged when already existing
block:
- name: register identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ email_identity }}"
state: present
- name: duplicate register identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ email_identity }}"
state: present
register: result
@@ -75,18 +75,18 @@
identity: "{{ email_identity }}"
always:
- name: cleanup identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ email_identity }}"
state: absent
# ============================================================
- name: test domain_identity unchanged when already existing
block:
- name: register identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ domain_identity }}"
state: present
- name: duplicate register identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ domain_identity }}"
state: present
register: result
@@ -99,7 +99,7 @@
identity: "{{ domain_identity }}"
always:
- name: cleanup identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ domain_identity }}"
state: absent
# ============================================================
@@ -110,7 +110,7 @@
- name: test register identity without explicit region
block:
- name: register email identity without explicit region
- aws_ses_identity:
+ ses_identity:
identity: "{{ email_identity }}"
state: present
region: "{{ omit }}"
@@ -126,35 +126,35 @@
identity: "{{ email_identity }}"
always:
- name: cleanup email identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ email_identity }}"
state: absent
# ============================================================
- name: test register email identity check mode
block:
- name: register email identity check mode
- aws_ses_identity:
+ ses_identity:
identity: "{{ email_identity }}"
state: present
register: result
check_mode: True
-
+
- name: assert changed is True
assert:
that:
- result.changed == True
-
+
- import_tasks: assert_defaults.yaml
vars:
identity: "{{ email_identity }}"
-
+
always:
- name: cleanup email identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ email_identity }}"
state: absent
register: result
-
+
- name: assert nothing to clean up since check mode
assert:
that:
@@ -163,35 +163,35 @@
- name: test register domain identity check mode
block:
- name: register domain identity check mode
- aws_ses_identity:
+ ses_identity:
identity: "{{ domain_identity }}"
state: present
register: result
check_mode: True
-
+
- name: assert changed is True
assert:
that:
- result.changed == True
-
+
- import_tasks: assert_defaults.yaml
vars:
identity: "{{ domain_identity }}"
-
+
always:
- name: cleanup domain identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ domain_identity }}"
state: absent
register: result
-
+
- name: assert nothing to clean up since check mode
assert:
that:
- result.changed == False
# ============================================================
- name: remove non-existent email identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ email_identity }}"
state: absent
register: result
@@ -201,7 +201,7 @@
- result.changed == False
# ============================================================
- name: remove non-existent domain identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ domain_identity }}"
state: absent
register: result
@@ -213,29 +213,29 @@
- name: test remove email identity check mode
block:
- name: register email identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ email_identity }}"
state: present
register: result
-
+
- name: remove email identity check mode
- aws_ses_identity:
+ ses_identity:
identity: "{{ email_identity }}"
state: absent
register: result
check_mode: True
-
+
- name: assert changed is True
assert:
that:
- result.changed == True
always:
- name: cleanup email identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ email_identity }}"
state: absent
register: result
-
+
- name: assert something to clean up since remove was check mode
assert:
that:
@@ -244,29 +244,29 @@
- name: test remove domain identity check mode
block:
- name: register domain identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ domain_identity }}"
state: present
register: result
-
+
- name: remove domain identity check mode
- aws_ses_identity:
+ ses_identity:
identity: "{{ domain_identity }}"
state: absent
register: result
check_mode: True
-
+
- name: assert changed is True
assert:
that:
- result.changed == True
always:
- name: cleanup domain identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ domain_identity }}"
state: absent
register: result
-
+
- name: assert something to clean up since remove was check mode
assert:
that:
@@ -284,7 +284,7 @@
- complaint
- delivery
- name: register email identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ email_identity }}"
state: present
bounce_notifications:
@@ -316,7 +316,7 @@
- complaint
- delivery
- name: cleanup email identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ email_identity }}"
state: absent
# ============================================================
@@ -332,11 +332,11 @@
- complaint
- delivery
- name: register email identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ email_identity }}"
state: present
- name: set notification topics
- aws_ses_identity:
+ ses_identity:
identity: "{{ email_identity }}"
state: present
bounce_notifications:
@@ -366,7 +366,67 @@
- complaint
- delivery
- name: cleanup email identity
- aws_ses_identity:
+ ses_identity:
+ identity: "{{ email_identity }}"
+ state: absent
+ # ============================================================
+ - name: test clear notification configuration
+ block:
+ - name: test topic
+ sns_topic:
+ name: "{{ notification_queue_name }}-{{ item }}"
+ state: present
+ register: topic_info
+ with_items:
+ - bounce
+ - complaint
+ - delivery
+ - name: register email identity
+ ses_identity:
+ identity: "{{ email_identity }}"
+ state: present
+ bounce_notifications:
+ topic: "{{ topic_info.results[0].sns_arn }}"
+ complaint_notifications:
+ topic: "{{ topic_info.results[1].sns_arn }}"
+ delivery_notifications:
+ topic: "{{ topic_info.results[2].sns_arn }}"
+ - name: Make no change to identity
+ ses_identity:
+ identity: "{{ email_identity }}"
+ state: present
+ register: result
+ - name: assert no change
+ assert:
+ that:
+ - result.changed == False
+
+ - name: clear notification settings
+ ses_identity:
+ identity: "{{ email_identity }}"
+ state: present
+ bounce_notifications: {}
+ complaint_notifications: {}
+ delivery_notifications: {}
+ register: result
+ - name: assert notification settings
+ assert:
+ that:
+ - result.changed == True
+ - "'bounce_topic' not in result.notification_attributes"
+ - "'delivery_topic' not in result.notification_attributes"
+ - "'complaint_topic' not in result.notification_attributes"
+ always:
+ - name: cleanup topics
+ sns_topic:
+ name: "{{ notification_queue_name }}-{{ item }}"
+ state: absent
+ with_items:
+ - bounce
+ - complaint
+ - delivery
+ - name: cleanup email identity
+ ses_identity:
identity: "{{ email_identity }}"
state: absent
# ============================================================
@@ -381,14 +441,14 @@
- bounce
- complaint
- delivery
-
+
- name: register email identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ email_identity }}"
state: present
-
+
- name: set notification settings check mode
- aws_ses_identity:
+ ses_identity:
identity: "{{ email_identity }}"
state: present
bounce_notifications:
@@ -403,12 +463,12 @@
feedback_forwarding: No
register: result
check_mode: True
-
+
- name: assert changed is True
assert:
that:
- result.changed == True
-
+
- name: assert notification settings
assert:
that:
@@ -419,13 +479,13 @@
- result.notification_attributes.complaint_topic == topic_info.results[1].sns_arn
- result.notification_attributes.headers_in_complaint_notifications_enabled == True
- result.notification_attributes.forwarding_enabled == False
-
+
- name: re-register base email identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ email_identity }}"
state: present
register: result
-
+
- name: assert no change since notifications were check mode
assert:
that:
@@ -437,7 +497,6 @@
- "'complaint_topic' not in result.notification_attributes"
- result.notification_attributes.headers_in_complaint_notifications_enabled == False
- result.notification_attributes.forwarding_enabled == True
-
always:
- name: cleanup topics
sns_topic:
@@ -447,16 +506,16 @@
- bounce
- complaint
- delivery
-
+
- name: cleanup email identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ email_identity }}"
state: absent
# ============================================================
- name: test include headers on notification queues
block:
- name: register email identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ email_identity }}"
state: present
bounce_notifications:
@@ -474,7 +533,7 @@
- result.notification_attributes.headers_in_delivery_notifications_enabled == True
always:
- name: cleanup email identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ email_identity }}"
state: absent
# ============================================================
@@ -489,7 +548,7 @@
- bounce
- complaint
- name: register email identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ email_identity }}"
state: present
bounce_notifications:
@@ -511,14 +570,14 @@
- bounce
- complaint
- name: cleanup email identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ email_identity }}"
state: absent
# ============================================================
- name: test disable feedback forwarding fails if no topics
block:
- name: register identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ domain_identity }}"
state: present
feedback_forwarding: No
@@ -530,7 +589,7 @@
- '"Invalid Parameter Value" in result.msg'
always:
- name: cleanup identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ domain_identity }}"
state: absent
# ============================================================
@@ -542,7 +601,7 @@
state: present
register: topic_info
- name: register email identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ email_identity }}"
state: present
bounce_notifications:
@@ -560,7 +619,7 @@
name: "{{ notification_queue_name }}-bounce"
state: absent
- name: cleanup identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ email_identity }}"
state: absent
# ============================================================
@@ -572,7 +631,7 @@
state: present
register: topic_info
- name: register email identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ email_identity }}"
state: present
complaint_notifications:
@@ -590,6 +649,6 @@
name: "{{ notification_queue_name }}-complaint"
state: absent
- name: cleanup identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ email_identity }}"
state: absent
diff --git a/ansible_collections/community/aws/tests/integration/targets/ses_identity_policy/tasks/main.yaml b/ansible_collections/community/aws/tests/integration/targets/ses_identity_policy/tasks/main.yaml
index 5aa3d867b..8fe290b56 100644
--- a/ansible_collections/community/aws/tests/integration/targets/ses_identity_policy/tasks/main.yaml
+++ b/ansible_collections/community/aws/tests/integration/targets/ses_identity_policy/tasks/main.yaml
@@ -4,9 +4,9 @@
- amazon.aws
module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region }}'
block:
@@ -14,13 +14,13 @@
- name: test add identity policy
block:
- name: register identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ domain_identity }}"
state: present
register: identity_info
- name: register identity policy
- aws_ses_identity_policy:
+ ses_identity_policy:
identity: "{{ domain_identity }}"
policy_name: "{{ policy_name }}"
policy: "{{ lookup('template', 'policy.json.j2') }}"
@@ -40,27 +40,27 @@
always:
- name: clean-up identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ domain_identity }}"
state: absent
# ============================================================
- name: test add duplicate identity policy
block:
- name: register identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ domain_identity }}"
state: present
register: identity_info
- name: register identity policy
- aws_ses_identity_policy:
+ ses_identity_policy:
identity: "{{ domain_identity }}"
policy_name: "{{ policy_name }}"
policy: "{{ lookup('template', 'policy.json.j2') }}"
state: present
- name: register duplicate identity policy
- aws_ses_identity_policy:
+ ses_identity_policy:
identity: "{{ domain_identity }}"
policy_name: "{{ policy_name }}"
policy: "{{ lookup('template', 'policy.json.j2') }}"
@@ -80,20 +80,20 @@
always:
- name: clean-up identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ domain_identity }}"
state: absent
# ============================================================
- name: test add identity policy by identity arn
block:
- name: register identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ domain_identity }}"
state: present
register: identity_info
- name: register identity policy
- aws_ses_identity_policy:
+ ses_identity_policy:
identity: "{{ identity_info.identity_arn }}"
policy_name: "{{ policy_name }}"
policy: "{{ lookup('template', 'policy.json.j2') }}"
@@ -113,20 +113,20 @@
always:
- name: clean-up identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ domain_identity }}"
state: absent
# ============================================================
- name: test add multiple identity policies
block:
- name: register identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ domain_identity }}"
state: present
register: identity_info
- name: register identity policy
- aws_ses_identity_policy:
+ ses_identity_policy:
identity: "{{ domain_identity }}"
policy_name: "{{ policy_name }}-{{ item }}"
policy: "{{ lookup('template', 'policy.json.j2') }}"
@@ -145,20 +145,20 @@
always:
- name: clean-up identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ domain_identity }}"
state: absent
# ============================================================
- name: test add inline identity policy
block:
- name: register identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ domain_identity }}"
state: present
register: identity_info
- name: register identity policy
- aws_ses_identity_policy:
+ ses_identity_policy:
identity: "{{ domain_identity }}"
policy_name: "{{ policy_name }}"
policy:
@@ -185,7 +185,7 @@
- result.policies|select('equalto', policy_name)|list|length == 1
- name: register duplicate identity policy
- aws_ses_identity_policy:
+ ses_identity_policy:
identity: "{{ domain_identity }}"
policy_name: "{{ policy_name }}"
policy:
@@ -207,27 +207,27 @@
always:
- name: clean-up identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ domain_identity }}"
state: absent
# ============================================================
- name: test remove identity policy
block:
- name: register identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ domain_identity }}"
state: present
register: identity_info
- name: register identity policy
- aws_ses_identity_policy:
+ ses_identity_policy:
identity: "{{ domain_identity }}"
policy_name: "{{ policy_name }}"
policy: "{{ lookup('template', 'policy.json.j2') }}"
state: present
- name: delete identity policy
- aws_ses_identity_policy:
+ ses_identity_policy:
identity: "{{ domain_identity }}"
policy_name: "{{ policy_name }}"
state: absent
@@ -245,20 +245,20 @@
always:
- name: clean-up identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ domain_identity }}"
state: absent
# ============================================================
- name: test remove missing identity policy
block:
- name: register identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ domain_identity }}"
state: present
register: identity_info
- name: delete identity policy
- aws_ses_identity_policy:
+ ses_identity_policy:
identity: "{{ domain_identity }}"
policy_name: "{{ policy_name }}"
state: absent
@@ -276,20 +276,20 @@
always:
- name: clean-up identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ domain_identity }}"
state: absent
# ============================================================
- name: test add identity policy with invalid policy
block:
- name: register identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ domain_identity }}"
state: present
register: identity_info
- name: register identity policy
- aws_ses_identity_policy:
+ ses_identity_policy:
identity: "{{ domain_identity }}"
policy_name: "{{ policy_name }}"
policy: '{"noSuchAttribute": 2}'
@@ -304,6 +304,6 @@
always:
- name: clean-up identity
- aws_ses_identity:
+ ses_identity:
identity: "{{ domain_identity }}"
state: absent
diff --git a/ansible_collections/community/aws/tests/integration/targets/ses_rule_set/tasks/active-rule-set-tests.yaml b/ansible_collections/community/aws/tests/integration/targets/ses_rule_set/tasks/active-rule-set-tests.yaml
index ea79dbbcc..d83cd2f85 100644
--- a/ansible_collections/community/aws/tests/integration/targets/ses_rule_set/tasks/active-rule-set-tests.yaml
+++ b/ansible_collections/community/aws/tests/integration/targets/ses_rule_set/tasks/active-rule-set-tests.yaml
@@ -10,10 +10,10 @@
- name: mark rule set active
block:
- name: create rule set
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
- name: mark rule set active
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
active: True
register: result
@@ -23,7 +23,7 @@
- result.changed == True
- result.active == True
- name: remark rule set active
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
active: True
register: result
@@ -33,7 +33,7 @@
- result.changed == False
always:
- name: cleanup rule set
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
state: absent
force: True
@@ -42,7 +42,7 @@
- name: create rule set active
block:
- name: create rule set
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
active: True
register: result
@@ -53,7 +53,7 @@
- result.active == True
- "default_rule_set in result.rule_sets|map(attribute='name')"
- name: remark rule set active
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
active: True
register: result
@@ -63,7 +63,7 @@
- result.changed == False
always:
- name: cleanup rule set
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
state: absent
force: True
@@ -72,11 +72,11 @@
- name: mark rule set inactive
block:
- name: create active rule set
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
active: True
- name: mark rule set inactive
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
active: False
register: result
@@ -86,7 +86,7 @@
- result.changed == True
- result.active == False
- name: remark rule set inactive
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
active: False
register: result
@@ -96,7 +96,7 @@
- result.changed == False
always:
- name: cleanup rule set
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
state: absent
force: True
@@ -105,11 +105,11 @@
- name: Absent active flag does not change active status
block:
- name: create active rule set
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
active: True
- name: recreate rule set
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
register: result
- name: assert not changed and still active
@@ -119,7 +119,7 @@
- result.active == True
always:
- name: cleanup rule set
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
state: absent
force: True
@@ -128,11 +128,11 @@
- name: Cannot Remove Active Rule Set
block:
- name: create active rule set
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
active: True
- name: remove rule set
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
state: absent
register: result
@@ -143,7 +143,7 @@
- "result.error.code == 'CannotDelete'"
always:
- name: cleanup rule set
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
state: absent
force: True
@@ -152,11 +152,11 @@
- name: Remove Active Rule Set with Force
block:
- name: create active rule set
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
active: True
- name: force remove rule set
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
state: absent
force: True
@@ -168,7 +168,7 @@
- "default_rule_set not in result.rule_sets|map(attribute='name')"
always:
- name: cleanup rule set
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
state: absent
force: True
@@ -177,15 +177,15 @@
- name: Force Remove of Inactive Rule Set does Not Affect Active Rule Set
block:
- name: create active rule set
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
active: True
- name: create inactive rule set
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ second_rule_set }}"
active: False
- name: force remove inactiave rule set
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ second_rule_set }}"
state: absent
force: True
@@ -196,7 +196,7 @@
- result.changed == True
- "second_rule_set not in result.rule_sets|map(attribute='name')"
- name: remark active rule set active
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
active: True
register: result
@@ -206,7 +206,7 @@
- result.changed == False
always:
- name: cleanup rule set
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ item }}"
state: absent
force: True
@@ -218,11 +218,11 @@
- name: mark rule set inactive in check mode
block:
- name: create rule set
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
active: True
- name: mark rule set inactive in check mode
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
active: False
register: result
@@ -233,7 +233,7 @@
- result.changed == True
- result.active == False
- name: remark rule set inactive
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
active: False
register: result
@@ -243,7 +243,7 @@
- result.changed == True
always:
- name: cleanup rule set
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
state: absent
force: True
@@ -252,11 +252,11 @@
- name: Cannot Remove Active Rule Set in check mode
block:
- name: create active rule set
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
active: True
- name: remove rule set
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
state: absent
register: result
@@ -268,7 +268,7 @@
- "result.error.code == 'CannotDelete'"
always:
- name: cleanup rule set
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
state: absent
force: True
@@ -277,11 +277,11 @@
- name: Remove Active Rule Set with Force in check mode
block:
- name: create active rule set
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
active: True
- name: force remove rule set
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
state: absent
force: True
@@ -294,7 +294,7 @@
- "default_rule_set not in result.rule_sets|map(attribute='name')"
always:
- name: cleanup rule set
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
state: absent
force: True
diff --git a/ansible_collections/community/aws/tests/integration/targets/ses_rule_set/tasks/cleanup-lock.yaml b/ansible_collections/community/aws/tests/integration/targets/ses_rule_set/tasks/cleanup-lock.yaml
index 155bf472e..941e0148a 100644
--- a/ansible_collections/community/aws/tests/integration/targets/ses_rule_set/tasks/cleanup-lock.yaml
+++ b/ansible_collections/community/aws/tests/integration/targets/ses_rule_set/tasks/cleanup-lock.yaml
@@ -9,7 +9,7 @@
- cloudwatchlogs_log_group:
log_group_name: "{{ lock_attempt_log_group_name }}"
state: absent
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"
diff --git a/ansible_collections/community/aws/tests/integration/targets/ses_rule_set/tasks/inactive-rule-set-tests.yaml b/ansible_collections/community/aws/tests/integration/targets/ses_rule_set/tasks/inactive-rule-set-tests.yaml
index 845168c23..92321b3eb 100644
--- a/ansible_collections/community/aws/tests/integration/targets/ses_rule_set/tasks/inactive-rule-set-tests.yaml
+++ b/ansible_collections/community/aws/tests/integration/targets/ses_rule_set/tasks/inactive-rule-set-tests.yaml
@@ -14,7 +14,7 @@
- name: test create rule sets
block:
- name: create rule set
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
register: result
- name: assert changed to exists inactive
@@ -24,7 +24,7 @@
- result.active == False
- "default_rule_set in result.rule_sets|map(attribute='name')"
- name: recreate rule set
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
register: result
- name: assert changed is False
@@ -33,7 +33,7 @@
- result.changed == False
always:
- name: cleanup rule set
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
state: absent
force: True
@@ -41,7 +41,7 @@
- name: Remove No Such Rules Set
block:
- name: remove ruleset
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
state: absent
register: result
@@ -54,10 +54,10 @@
- name: Remove Inactive Rule Set
block:
- name: create rule set
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
- name: remove rule set
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
state: absent
register: result
@@ -68,7 +68,7 @@
- "default_rule_set not in result.rule_sets|map(attribute='name')"
always:
- name: cleanup rule set
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
state: absent
force: True
@@ -76,7 +76,7 @@
- name: test create in check mode
block:
- name: create rule set in check mode
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
register: result
check_mode: True
@@ -88,7 +88,7 @@
- "default_rule_set in result.rule_sets|map(attribute='name')"
always:
- name: cleanup rule set
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
state: absent
force: True
@@ -101,10 +101,10 @@
- name: mark rule set active in check mode
block:
- name: create rule set
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
- name: mark rule set active in check mode
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
active: True
register: result
@@ -118,7 +118,7 @@
# it active again as that way this test can be run in
# parallel
- name: Ensure rule set is inactive
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
active: False
register: result
@@ -128,7 +128,7 @@
- result.changed == False
always:
- name: cleanup rule set
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
state: absent
force: True
@@ -136,10 +136,10 @@
- name: Remove Inactive Rule Set in check mode
block:
- name: create rule set
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
- name: remove rule set
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
state: absent
register: result
@@ -151,7 +151,7 @@
- "default_rule_set not in result.rule_sets|map(attribute='name')"
always:
- name: cleanup rule set
- aws_ses_rule_set:
+ ses_rule_set:
name: "{{ default_rule_set }}"
state: absent
force: True
diff --git a/ansible_collections/community/aws/tests/integration/targets/ses_rule_set/tasks/main.yaml b/ansible_collections/community/aws/tests/integration/targets/ses_rule_set/tasks/main.yaml
index 4902b5c60..99938b774 100644
--- a/ansible_collections/community/aws/tests/integration/targets/ses_rule_set/tasks/main.yaml
+++ b/ansible_collections/community/aws/tests/integration/targets/ses_rule_set/tasks/main.yaml
@@ -4,9 +4,9 @@
- amazon.aws
module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region }}'
block:
diff --git a/ansible_collections/community/aws/tests/integration/targets/setup_botocore_pip/defaults/main.yml b/ansible_collections/community/aws/tests/integration/targets/setup_botocore_pip/defaults/main.yml
index 16ad00270..9745064c9 100644
--- a/ansible_collections/community/aws/tests/integration/targets/setup_botocore_pip/defaults/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/setup_botocore_pip/defaults/main.yml
@@ -1,2 +1,2 @@
-default_botocore_version: '1.21.0'
-default_boto3_version: '1.18.0'
+default_botocore_version: "{{ lookup('amazon.aws.aws_collection_constants', 'MINIMUM_BOTOCORE_VERSION') }}"
+default_boto3_version: "{{ lookup('amazon.aws.aws_collection_constants', 'MINIMUM_BOTO3_VERSION') }}"
diff --git a/ansible_collections/community/aws/tests/integration/targets/setup_connection_aws_ssm/defaults/main.yml b/ansible_collections/community/aws/tests/integration/targets/setup_connection_aws_ssm/defaults/main.yml
index ec7cf0ec6..f7ac20eee 100644
--- a/ansible_collections/community/aws/tests/integration/targets/setup_connection_aws_ssm/defaults/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/setup_connection_aws_ssm/defaults/main.yml
@@ -4,7 +4,15 @@ instance_type: t3.micro
ami_details:
fedora:
owner: 125523088429
- name: Fedora-Cloud-Base-34-1.2.x86_64*
+ name: 'Fedora-Cloud-Base-41-1.2.x86_64*'
+ user_data: |
+ #!/bin/sh
+ sudo dnf install -y https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm
+ sudo systemctl start amazon-ssm-agent
+ os_type: linux
+ centos:
+ owner: 125523088429
+ name: 'CentOS Stream 9 x86_64*'
user_data: |
#!/bin/sh
sudo dnf install -y https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm
@@ -25,6 +33,8 @@ ami_details:
# name: ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server*
user_data: |
#!/bin/sh
+ apt-get update
+ apt-get --yes install acl
# Pre-Installed just needs started
sudo systemctl start amazon-ssm-agent
os_type: linux
diff --git a/ansible_collections/community/aws/tests/integration/targets/setup_connection_aws_ssm/tasks/cleanup.yml b/ansible_collections/community/aws/tests/integration/targets/setup_connection_aws_ssm/tasks/cleanup.yml
index 6171e5eb6..fce828a3c 100644
--- a/ansible_collections/community/aws/tests/integration/targets/setup_connection_aws_ssm/tasks/cleanup.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/setup_connection_aws_ssm/tasks/cleanup.yml
@@ -4,9 +4,9 @@
- amazon.aws
module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region }}'
block:
@@ -68,11 +68,12 @@
iam_role:
name: "{{ iam_role_name }}"
state: absent
+ delete_instance_profile: True
ignore_errors: yes
when: iam_role_vars_file.stat.exists == true
- name: Delete the KMS key
- aws_kms:
+ kms_key:
state: absent
alias: '{{ kms_key_name }}'
diff --git a/ansible_collections/community/aws/tests/integration/targets/setup_connection_aws_ssm/tasks/connection_args.yml b/ansible_collections/community/aws/tests/integration/targets/setup_connection_aws_ssm/tasks/connection_args.yml
index 727220e49..8d5c4b714 100644
--- a/ansible_collections/community/aws/tests/integration/targets/setup_connection_aws_ssm/tasks/connection_args.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/setup_connection_aws_ssm/tasks/connection_args.yml
@@ -3,9 +3,9 @@
# As a lookup plugin we don't have access to module_defaults
connection_args:
region: "{{ aws_region }}"
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- aws_security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
connection_env:
AWS_DEFAULT_REGION: "{{ aws_region }}"
AWS_ACCESS_KEY_ID: "{{ aws_access_key }}"
diff --git a/ansible_collections/community/aws/tests/integration/targets/setup_connection_aws_ssm/tasks/encryption.yml b/ansible_collections/community/aws/tests/integration/targets/setup_connection_aws_ssm/tasks/encryption.yml
index 949892d18..1379b0428 100644
--- a/ansible_collections/community/aws/tests/integration/targets/setup_connection_aws_ssm/tasks/encryption.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/setup_connection_aws_ssm/tasks/encryption.yml
@@ -1,7 +1,7 @@
---
## Task file for setup/teardown AWS resources for aws_ssm integration testing
- name: create a KMS key
- aws_kms:
+ kms_key:
alias: '{{ kms_key_name }}'
grants:
- name: SSM-Agent-Access
diff --git a/ansible_collections/community/aws/tests/integration/targets/setup_connection_aws_ssm/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/setup_connection_aws_ssm/tasks/main.yml
index 830bd5fcc..6c29c4154 100644
--- a/ansible_collections/community/aws/tests/integration/targets/setup_connection_aws_ssm/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/setup_connection_aws_ssm/tasks/main.yml
@@ -5,9 +5,9 @@
- amazon.aws
module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region }}'
block:
diff --git a/ansible_collections/community/aws/tests/integration/targets/setup_ec2_facts/defaults/main.yml b/ansible_collections/community/aws/tests/integration/targets/setup_ec2_facts/defaults/main.yml
index 6fbe55e83..11a1e561e 100644
--- a/ansible_collections/community/aws/tests/integration/targets/setup_ec2_facts/defaults/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/setup_ec2_facts/defaults/main.yml
@@ -1,6 +1,7 @@
+---
# CentOS Community Platform Engineering (CPE)
-ec2_ami_owner_id: '125523088429'
-#ec2_ami_name: 'Fedora-Cloud-Base-*.x86_64*'
-ec2_ami_name: 'CentOS Stream 9 x86_64*'
-#ec2_ami_ssh_user: 'fedora'
-ec2_ami_ssh_user: 'centos'
+ec2_ami_owner_id: "125523088429"
+# ec2_ami_name: 'Fedora-Cloud-Base-*.x86_64*'
+ec2_ami_name: CentOS Stream 9 x86_64*
+# ec2_ami_ssh_user: 'fedora'
+ec2_ami_ssh_user: centos
diff --git a/ansible_collections/community/aws/tests/integration/targets/setup_ec2_facts/meta/main.yml b/ansible_collections/community/aws/tests/integration/targets/setup_ec2_facts/meta/main.yml
index 32cf5dda7..23d65c7ef 100644
--- a/ansible_collections/community/aws/tests/integration/targets/setup_ec2_facts/meta/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/setup_ec2_facts/meta/main.yml
@@ -1 +1,2 @@
+---
dependencies: []
diff --git a/ansible_collections/community/aws/tests/integration/targets/setup_ec2_facts/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/setup_ec2_facts/tasks/main.yml
index f41791073..bd059c866 100644
--- a/ansible_collections/community/aws/tests/integration/targets/setup_ec2_facts/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/setup_ec2_facts/tasks/main.yml
@@ -8,46 +8,47 @@
# rather than hardcoding the IDs so we're not limited to specific Regions
# - ec2_ami_id
#
-- module_defaults:
+- name: Setup common EC2 related facts.
+ module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
- region: '{{ aws_region }}'
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
+ region: "{{ aws_region }}"
- run_once: True
+ run_once: true
block:
# ============================================================
- - name: Get available AZs
- aws_az_info:
- filters:
- region-name: '{{ aws_region }}'
- register: _az_info
+ - name: Get available AZs
+ amazon.aws.aws_az_info:
+ filters:
+ region-name: "{{ aws_region }}"
+ register: _az_info
- - name: Pick an AZ
- set_fact:
- ec2_availability_zone_names: '{{ _az_info.availability_zones | selectattr("zone_name", "defined") | map(attribute="zone_name") | list }}'
+ - name: Pick an AZ
+ ansible.builtin.set_fact:
+ ec2_availability_zone_names: '{{ _az_info.availability_zones | selectattr("zone_name", "defined") | map(attribute="zone_name") | list }}'
- # ============================================================
+ # ============================================================
- - name: Get a list of images
- ec2_ami_info:
- filters:
- name: '{{ ec2_ami_name }}'
- owner-id: '{{ ec2_ami_owner_id }}'
- architecture: x86_64
- virtualization-type: hvm
- root-device-type: ebs
- register: _images_info
- # Very spammy
- no_log: True
+ - name: Get a list of images
+ amazon.aws.ec2_ami_info:
+ filters:
+ name: "{{ ec2_ami_name }}"
+ owner-id: "{{ ec2_ami_owner_id }}"
+ architecture: x86_64
+ virtualization-type: hvm
+ root-device-type: ebs
+ register: _images_info
+ # Very spammy
+ no_log: true
- - name: Set Fact for latest AMI
- vars:
- latest_image: '{{ _images_info.images | sort(attribute="creation_date") | reverse | first }}'
- set_fact:
- ec2_ami_id: '{{ latest_image.image_id }}'
- ec2_ami_details: '{{ latest_image }}'
- ec2_ami_root_disk: '{{ latest_image.block_device_mappings[0].device_name }}'
- ec2_ami_ssh_user: '{{ ec2_ami_ssh_user }}'
+ - name: Set Fact for latest AMI
+ vars:
+ latest_image: '{{ _images_info.images | sort(attribute="creation_date") | reverse | first }}'
+ ansible.builtin.set_fact:
+ ec2_ami_id: "{{ latest_image.image_id }}"
+ ec2_ami_details: "{{ latest_image }}"
+ ec2_ami_root_disk: "{{ latest_image.block_device_mappings[0].device_name }}"
+ ec2_ami_ssh_user: "{{ ec2_ami_ssh_user }}"
diff --git a/ansible_collections/community/aws/tests/integration/targets/setup_sshkey/files/ec2-fingerprint.py b/ansible_collections/community/aws/tests/integration/targets/setup_sshkey/files/ec2-fingerprint.py
index ea2f51b0f..04d2eb1ea 100644
--- a/ansible_collections/community/aws/tests/integration/targets/setup_sshkey/files/ec2-fingerprint.py
+++ b/ansible_collections/community/aws/tests/integration/targets/setup_sshkey/files/ec2-fingerprint.py
@@ -8,24 +8,26 @@ ssh-keygen -f id_rsa.pub -e -m PKCS8 | openssl pkey -pubin -outform DER | openss
(but without needing the OpenSSL CLI)
"""
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
import hashlib
import sys
-from Crypto.PublicKey import RSA
+
+from cryptography.hazmat.primitives import serialization
if len(sys.argv) == 0:
ssh_public_key = "id_rsa.pub"
else:
ssh_public_key = sys.argv[1]
-with open(ssh_public_key, 'r') as key_fh:
- data = key_fh.read()
-
-# Convert from SSH format to DER format
-public_key = RSA.importKey(data).exportKey('DER')
-md5digest = hashlib.md5(public_key).hexdigest()
+with open(ssh_public_key, "rb") as key_file:
+ public_key = serialization.load_ssh_public_key(
+ key_file.read(),
+ )
+pub_der = public_key.public_bytes(
+ encoding=serialization.Encoding.DER,
+ format=serialization.PublicFormat.SubjectPublicKeyInfo,
+)
+md5digest = hashlib.md5(pub_der).hexdigest()
# Format the md5sum into the normal format
pairs = zip(md5digest[::2], md5digest[1::2])
md5string = ":".join(["".join(pair) for pair in pairs])
diff --git a/ansible_collections/community/aws/tests/integration/targets/sns/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/sns/tasks/main.yml
index 42ef9b190..99be6b218 100644
--- a/ansible_collections/community/aws/tests/integration/targets/sns/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/sns/tasks/main.yml
@@ -1,9 +1,9 @@
- name: set up AWS connection info
module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region }}'
collections:
- amazon.aws
diff --git a/ansible_collections/community/aws/tests/integration/targets/sns_topic/files/sns_topic_lambda/sns_topic_lambda.py b/ansible_collections/community/aws/tests/integration/targets/sns_topic/files/sns_topic_lambda/sns_topic_lambda.py
index 98f657836..99c6a8105 100644
--- a/ansible_collections/community/aws/tests/integration/targets/sns_topic/files/sns_topic_lambda/sns_topic_lambda.py
+++ b/ansible_collections/community/aws/tests/integration/targets/sns_topic/files/sns_topic_lambda/sns_topic_lambda.py
@@ -1,6 +1,9 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
__metaclass__ = type
diff --git a/ansible_collections/community/aws/tests/integration/targets/sns_topic/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/sns_topic/tasks/main.yml
index d5b389e4d..00f3f71d9 100644
--- a/ansible_collections/community/aws/tests/integration/targets/sns_topic/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/sns_topic/tasks/main.yml
@@ -1,8 +1,8 @@
- module_defaults:
group/aws:
- aws_secret_key: '{{ aws_secret_key }}'
- aws_access_key: '{{ aws_access_key }}'
- security_token: '{{ security_token|default(omit) }}'
+ secret_key: '{{ aws_secret_key }}'
+ access_key: '{{ aws_access_key }}'
+ session_token: '{{ security_token|default(omit) }}'
region: '{{ aws_region }}'
block:
@@ -62,7 +62,7 @@
that:
- sns_topic_info is successful
- "'result' in sns_topic_info"
- - sns_topic_info.result["sns_arn"] == "{{ sns_arn }}"
+ - sns_topic_info.result["sns_arn"] == sns_arn
- "'sns_topic' in sns_topic_info.result"
- "'display_name' in sns_topic_info.result['sns_topic']"
- sns_topic_info.result["sns_topic"]["display_name"] == "My topic name"
@@ -79,7 +79,7 @@
that:
- sns_topic_info is successful
- "'result' in sns_topic_info"
- - sns_topic_info.result["sns_arn"] == "{{ sns_arn }}"
+ - sns_topic_info.result["sns_arn"] == sns_arn
- "'sns_topic' in sns_topic_info.result"
- "'display_name' in sns_topic_info.result['sns_topic']"
- sns_topic_info.result["sns_topic"]["display_name"] == "My topic name"
@@ -110,7 +110,7 @@
that:
- sns_fifo_topic.changed
- sns_fifo_topic.sns_topic.topic_type == 'fifo'
- - sns_fifo_topic.sns_topic.name == '{{ sns_topic_topic_name }}-fifo'
+ - sns_fifo_topic.sns_topic.name == sns_topic_topic_name ~ '-fifo'
- name: Run create a FIFO topic again for idempotence test (with .fifo)
sns_topic:
diff --git a/ansible_collections/community/aws/tests/integration/targets/sqs_queue/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/sqs_queue/tasks/main.yml
index bcba06c8f..4c16be313 100644
--- a/ansible_collections/community/aws/tests/integration/targets/sqs_queue/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/sqs_queue/tasks/main.yml
@@ -3,9 +3,9 @@
module_defaults:
group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"
block:
@@ -19,7 +19,7 @@
assert:
that:
- create_result.changed
- - create_result.region == "{{ aws_region }}"
+ - create_result.region == aws_region
always:
- name: Test deleting SQS queue
diff --git a/ansible_collections/community/aws/tests/integration/targets/ssm_parameter/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/ssm_parameter/tasks/main.yml
index ac461392a..7c0e27fee 100644
--- a/ansible_collections/community/aws/tests/integration/targets/ssm_parameter/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/ssm_parameter/tasks/main.yml
@@ -3,9 +3,9 @@
# As a lookup plugin we don't have access to module_defaults
connection_args:
region: "{{ aws_region }}"
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- aws_security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
no_log: True
- name: 'aws_ssm lookup plugin integration tests'
@@ -13,9 +13,9 @@
- amazon.aws
module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region }}'
vars:
simple_name: '/{{ ssm_key_prefix }}/Simple'
@@ -87,7 +87,7 @@
# Create
- name: Create key/value pair in aws parameter store (CHECK)
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_name }}'
description: '{{ simple_description }}'
value: '{{ simple_value }}'
@@ -98,7 +98,7 @@
- result is changed
- name: Create key/value pair in aws parameter store
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_name }}'
description: '{{ simple_description }}'
value: '{{ simple_value }}'
@@ -129,7 +129,7 @@
- result.parameter_metadata.type == 'String'
- name: Create key/value pair in aws parameter store - idempotency (CHECK)
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_name }}'
description: '{{ simple_description }}'
value: '{{ simple_value }}'
@@ -140,7 +140,7 @@
- result is not changed
- name: Create key/value pair in aws parameter store - idempotency
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_name }}'
description: '{{ simple_description }}'
value: '{{ simple_value }}'
@@ -174,7 +174,7 @@
# Update description
- name: Update description (CHECK)
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_name }}'
description: '{{ updated_description }}'
register: result
@@ -184,7 +184,7 @@
- result is changed
- name: Update description
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_name }}'
description: '{{ updated_description }}'
register: result
@@ -214,7 +214,7 @@
- result.parameter_metadata.type == 'String'
- name: Update description - idempotency (CHECK)
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_name }}'
description: '{{ updated_description }}'
register: result
@@ -224,7 +224,7 @@
- result is not changed
- name: Update description - idempotency
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_name }}'
description: '{{ updated_description }}'
register: result
@@ -258,7 +258,7 @@
# Update value
- name: Update key/value pair in aws parameter store (CHECK)
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_name }}'
value: '{{ updated_value }}'
register: result
@@ -268,7 +268,7 @@
- result is changed
- name: Update key/value pair in aws parameter store
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_name }}'
value: '{{ updated_value }}'
register: result
@@ -298,7 +298,7 @@
- result.parameter_metadata.type == 'String'
- name: Update key/value pair in aws parameter store - idempotency (CHECK)
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_name }}'
value: '{{ updated_value }}'
register: result
@@ -308,7 +308,7 @@
- result is not changed
- name: Update key/value pair in aws parameter store - idempotency
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_name }}'
value: '{{ updated_value }}'
register: result
@@ -341,7 +341,7 @@
# Complex update
- name: Complex update to key/value pair in aws parameter store (CHECK)
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_name }}'
value: '{{ simple_value }}'
description: '{{ simple_description }}'
@@ -352,7 +352,7 @@
- result is changed
- name: Complex update to key/value pair in aws parameter store
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_name }}'
value: '{{ simple_value }}'
description: '{{ simple_description }}'
@@ -383,7 +383,7 @@
- result.parameter_metadata.type == 'String'
- name: Complex update to key/value pair in aws parameter store - idempotency (CHECK)
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_name }}'
value: '{{ simple_value }}'
description: '{{ simple_description }}'
@@ -394,7 +394,7 @@
- result is not changed
- name: Complex update to key/value pair in aws parameter store - idempotency
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_name }}'
value: '{{ simple_value }}'
description: '{{ simple_description }}'
@@ -428,7 +428,7 @@
# Delete
- name: Delete key/value pair in aws parameter store (CHECK)
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_name }}'
state: absent
register: result
@@ -438,7 +438,7 @@
- result is changed
- name: Delete key/value pair in aws parameter store
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_name }}'
state: absent
register: result
@@ -454,7 +454,7 @@
- info_result is failed
- name: Delete key/value pair in aws parameter store - idempotency (CHECK)
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_name }}'
state: absent
register: result
@@ -464,7 +464,7 @@
- result is not changed
- name: Delete key/value pair in aws parameter store - idempotency
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_name }}'
state: absent
register: result
@@ -474,7 +474,7 @@
- result is not changed
- name: Create key/value pair in aws parameter store with no description
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_name }}'
value: '{{ simple_value }}'
register: result
@@ -485,7 +485,7 @@
- '"description" not in result.parameter_metadata'
- name: Add a description
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_name }}'
value: '{{ simple_value }}'
description: '{{ simple_description }}'
@@ -501,7 +501,7 @@
# Test tags - Create parameter with tags case
- name: Create parameter with tags case - Create parameter (CHECK)
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
description: '{{ simple_tag_param_description }}'
value: '{{ simple_tag_param_value }}'
@@ -513,7 +513,7 @@
- result is changed
- name: Create parameter with tags case - Create parameter
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
description: '{{ simple_tag_param_description }}'
value: '{{ simple_tag_param_value }}'
@@ -523,7 +523,7 @@
- name: Create parameter with tags case - Ensure tags is correct
assert:
that:
- - result.parameter_metadata.tags['{{ item.key }}'] == simple_tags_orig['{{ item.key }}']
+ - result.parameter_metadata.tags[item.key] == simple_tags_orig[item.key]
loop: "{{ simple_tags_orig | dict2items }}"
- name: Create parameter with tags case - Ensure no missing or additional tags
@@ -560,7 +560,7 @@
# Test tags - Update description only case
- name: Update description only case - Update parameter (CHECK)
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
description: '{{ simple_tag_param_updated_description }}'
register: result
@@ -570,7 +570,7 @@
- result is changed
- name: Update description only case - Update parameter
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
description: '{{ simple_tag_param_updated_description }}'
register: result
@@ -578,7 +578,7 @@
- name: Update description only case - Ensure expected tags is correct
assert:
that:
- - result.parameter_metadata.tags['{{ item.key }}'] == simple_tags_orig['{{ item.key }}']
+ - result.parameter_metadata.tags[item.key] == simple_tags_orig[item.key]
loop: "{{ simple_tags_orig | dict2items }}"
- name: Update description only case - Ensure no missing or additional tags
@@ -615,7 +615,7 @@
# Test tags - Add tag to existing parameter case
- name: Add tag to existing parameter case - Update parameter (CHECK)
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
tags: '{{ simple_tags_add_owner }}'
register: result
@@ -625,7 +625,7 @@
- result is changed
- name: Add tag to existing parameter case - Update parameter
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
tags: '{{ simple_tags_add_owner }}'
register: result
@@ -633,7 +633,7 @@
- name: Add tag to existing parameter case - Ensure tags correct
assert:
that:
- - result.parameter_metadata.tags['{{ item.key }}'] == simple_tags_add_owner['{{ item.key }}']
+ - result.parameter_metadata.tags[item.key] == simple_tags_add_owner[item.key]
loop: "{{ simple_tags_add_owner | dict2items }}"
- name: Add tag to existing parameter case - Ensure no missing or additional tags
@@ -667,7 +667,7 @@
- result.parameter_metadata.type == 'String'
- name: Add tag to existing parameter case - Delete parameter
- aws_ssm_parameter_store:
+ ssm_parameter:
name: "{{item}}"
state: absent
ignore_errors: True
@@ -678,7 +678,7 @@
# Test tags - update tags only - change tag
- name: Change single tag case - Create parameter
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
description: '{{ simple_tag_param_description }}'
value: '{{ simple_tag_param_value }}'
@@ -686,7 +686,7 @@
register: result
- name: Change single tag case - Update tag (CHECK)
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
tags: '{{ simple_tags_change_environment }}'
register: result
@@ -696,7 +696,7 @@
- result is changed
- name: Change single tag case - Update tag
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
tags: '{{ simple_tags_change_environment }}'
register: result
@@ -704,7 +704,7 @@
- name: Change single tag case - Ensure expected tags is correct
assert:
that:
- - result.parameter_metadata.tags['{{ item.key }}'] == simple_tags_change_environment['{{ item.key }}']
+ - result.parameter_metadata.tags[item.key] == simple_tags_change_environment[item.key]
loop: "{{ simple_tags_change_environment | dict2items }}"
- name: Change single tag case - Ensure no missing or additional tags
@@ -738,7 +738,7 @@
- result.parameter_metadata.type == 'String'
- name: Change single tag case - Delete parameter
- aws_ssm_parameter_store:
+ ssm_parameter:
name: "{{item}}"
state: absent
ignore_errors: True
@@ -749,7 +749,7 @@
# Test tags - delete tag case
- name: Delete single tag case - Create parameter
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
description: '{{ simple_tag_param_description }}'
value: '{{ simple_tag_param_value }}'
@@ -757,7 +757,7 @@
register: result
- name: Delete single tag case - Update tag (CHECK)
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
tags: '{{ simple_tags_delete_version }}'
register: result
@@ -767,7 +767,7 @@
- result is changed
- name: Delete single tag case - Update tag
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
tags: '{{ simple_tags_delete_version }}'
register: result
@@ -775,7 +775,7 @@
- name: Delete single tag case - Ensure expected tags is correct
assert:
that:
- - result.parameter_metadata.tags['{{ item.key }}'] == simple_tags_delete_version['{{ item.key }}']
+ - result.parameter_metadata.tags[item.key] == simple_tags_delete_version[item.key]
loop: "{{ simple_tags_delete_version | dict2items }}"
- name: Delete single tag case - Ensure no missing or additional tags
@@ -809,7 +809,7 @@
- result.parameter_metadata.type == 'String'
- name: Delete single tag case - Delete parameter
- aws_ssm_parameter_store:
+ ssm_parameter:
name: "{{item}}"
state: absent
ignore_errors: True
@@ -820,7 +820,7 @@
# Test tags - delete tag w/ spaces case
- name: Delete single tag w/ spaces case - Create parameter
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
description: '{{ simple_tag_param_description }}'
value: '{{ simple_tag_param_value }}'
@@ -828,7 +828,7 @@
register: result
- name: Delete single tag w/ spaces case - Update tag (CHECK)
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
tags: '{{ simple_tags_delete_tag_with_space }}'
register: result
@@ -838,7 +838,7 @@
- result is changed
- name: Delete single tag w/ spaces case - Update tag
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
tags: '{{ simple_tags_delete_tag_with_space }}'
register: result
@@ -846,7 +846,7 @@
- name: Delete single tag w/ spaces case - Ensure expected tags is correct
assert:
that:
- - result.parameter_metadata.tags['{{ item.key }}'] == simple_tags_delete_tag_with_space['{{ item.key }}']
+ - result.parameter_metadata.tags[item.key] == simple_tags_delete_tag_with_space[item.key]
loop: "{{ simple_tags_delete_tag_with_space | dict2items }}"
- name: Delete single tag w/ spaces case - Ensure no missing or additional tags
@@ -880,7 +880,7 @@
- result.parameter_metadata.type == 'String'
- name: Delete single tag w/ spaces case - Delete parameter
- aws_ssm_parameter_store:
+ ssm_parameter:
name: "{{item}}"
state: absent
ignore_errors: True
@@ -891,7 +891,7 @@
# Test tags - Add/delete/change tags case
- name: Add/delete/change tags case - Create parameter
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
description: '{{ simple_tag_param_description }}'
value: '{{ simple_tag_param_value }}'
@@ -899,7 +899,7 @@
register: result
- name: Add/delete/change tags case - Update tag (CHECK)
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
tags: '{{ simple_tags_add_delete_change }}'
register: result
@@ -909,7 +909,7 @@
- result is changed
- name: Add/delete/change tags case - Update tag
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
tags: '{{ simple_tags_add_delete_change }}'
register: result
@@ -917,7 +917,7 @@
- name: Add/delete/change tags case - Ensure expected tags is correct
assert:
that:
- - result.parameter_metadata.tags['{{ item.key }}'] == simple_tags_add_delete_change['{{ item.key }}']
+ - result.parameter_metadata.tags[item.key] == simple_tags_add_delete_change[item.key]
loop: "{{ simple_tags_add_delete_change | dict2items }}"
- name: Add/delete/change tags case - Ensure no missing or additional tags
@@ -951,7 +951,7 @@
- result.parameter_metadata.type == 'String'
- name: Add/delete/change tags case - Delete parameter
- aws_ssm_parameter_store:
+ ssm_parameter:
name: "{{item}}"
state: absent
ignore_errors: True
@@ -962,7 +962,7 @@
# Test tags - Delete all tags case
- name: Delete all tags case - Create parameter
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
description: '{{ simple_tag_param_description }}'
value: '{{ simple_tag_param_value }}'
@@ -970,7 +970,7 @@
register: result
- name: Delete all tags case - Update tag (CHECK)
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
tags: '{{ simple_tags_delete_all_tags }}'
register: result
@@ -980,7 +980,7 @@
- result is changed
- name: Delete all tags case - Update tag
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
tags: '{{ simple_tags_delete_all_tags }}'
register: result
@@ -988,7 +988,7 @@
- name: Delete all tags case - Ensure expected tags is correct
assert:
that:
- - result.parameter_metadata.tags['{{ item.key }}'] == simple_tags_delete_all_tags['{{ item.key }}']
+ - result.parameter_metadata.tags[item.key] == simple_tags_delete_all_tags[item.key]
loop: "{{ simple_tags_delete_all_tags | dict2items }}"
- name: Delete all tags case - Ensure no missing or additional tags
@@ -1022,7 +1022,7 @@
- result.parameter_metadata.type == 'String'
- name: Delete all tags case - Delete parameter
- aws_ssm_parameter_store:
+ ssm_parameter:
name: "{{item}}"
state: absent
ignore_errors: True
@@ -1033,7 +1033,7 @@
# Test tags - Add tag case (purge_tags=false)
- name: Add tag case (purge_tags=false) - Create parameter
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
description: '{{ simple_tag_param_description }}'
value: '{{ simple_tag_param_value }}'
@@ -1041,7 +1041,7 @@
register: result
- name: Add tag case (purge_tags=false) - Add tag (CHECK)
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
tags: '{{ simple_tags_purge_false_add_owner }}'
purge_tags: False
@@ -1052,7 +1052,7 @@
- result is changed
- name: Add tag case (purge_tags=false) - Add tag
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
tags: '{{ simple_tags_purge_false_add_owner }}'
purge_tags: False
@@ -1062,8 +1062,8 @@
assert:
that:
- >
- result.parameter_metadata.tags['{{ item.key }}'] ==
- (simple_tags_orig | combine(simple_tags_purge_false_add_owner))['{{ item.key }}']
+ result.parameter_metadata.tags[item.key] ==
+ (simple_tags_orig | combine(simple_tags_purge_false_add_owner))[item.key]
loop: >
{{ simple_tags_orig | combine(simple_tags_purge_false_add_owner) | dict2items }}
@@ -1071,8 +1071,8 @@
assert:
that:
- >
- result.parameter_metadata.tags | length == {{ simple_tags_orig |
- combine(simple_tags_purge_false_add_owner) | dict2items }} | length
+ result.parameter_metadata.tags | length == simple_tags_orig |
+ combine(simple_tags_purge_false_add_owner) | dict2items | length
- name: Add tag case (purge_tags=false) - Lookup a tagged parameter
set_fact:
@@ -1100,7 +1100,7 @@
- result.parameter_metadata.type == 'String'
- name: Add tag case (purge_tags=false) - Delete parameter
- aws_ssm_parameter_store:
+ ssm_parameter:
name: "{{item}}"
state: absent
ignore_errors: True
@@ -1111,7 +1111,7 @@
# Test tags - Add multiple tags case (purge_tags=false)
- name: Add multiple tags case (purge_tags=false) - Create parameter
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
description: '{{ simple_tag_param_description }}'
value: '{{ simple_tag_param_value }}'
@@ -1119,7 +1119,7 @@
register: result
- name: Add multiple tags case (purge_tags=false) - Add tag (CHECK)
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
tags: '{{ simple_tags_purge_false_add_multiple }}'
purge_tags: False
@@ -1130,7 +1130,7 @@
- result is changed
- name: Add multiple tags case (purge_tags=false) - Add tag
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
tags: '{{ simple_tags_purge_false_add_multiple }}'
purge_tags: False
@@ -1140,8 +1140,8 @@
assert:
that:
- >
- result.parameter_metadata.tags['{{ item.key }}'] ==
- (simple_tags_orig | combine(simple_tags_purge_false_add_multiple))['{{ item.key }}']
+ result.parameter_metadata.tags[item.key] ==
+ (simple_tags_orig | combine(simple_tags_purge_false_add_multiple))[item.key]
loop: >
{{ simple_tags_orig | combine(simple_tags_purge_false_add_multiple) | dict2items }}
@@ -1149,8 +1149,8 @@
assert:
that:
- >
- result.parameter_metadata.tags | length == {{ simple_tags_orig |
- combine(simple_tags_purge_false_add_multiple) | dict2items }} | length
+ result.parameter_metadata.tags | length == simple_tags_orig |
+ combine(simple_tags_purge_false_add_multiple) | dict2items | length
- name: Add multiple tags case (purge_tags=false) - Lookup a tagged parameter
set_fact:
@@ -1178,7 +1178,7 @@
- result.parameter_metadata.type == 'String'
- name: Add multiple tags case (purge_tags=false) - Delete parameter
- aws_ssm_parameter_store:
+ ssm_parameter:
name: "{{item}}"
state: absent
ignore_errors: True
@@ -1189,7 +1189,7 @@
# Test tags - Change tag case (purge_tags=false)
- name: Change tag case (purge_tags=false) - Create parameter
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
description: '{{ simple_tag_param_description }}'
value: '{{ simple_tag_param_value }}'
@@ -1197,7 +1197,7 @@
register: result
- name: Change tag case (purge_tags=false) - Change tag (CHECK)
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
tags: '{{ simple_tags_purge_false_change_environment}}'
purge_tags: False
@@ -1208,7 +1208,7 @@
- result is changed
- name: Change tag case (purge_tags=false) - Change tag
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
tags: '{{ simple_tags_purge_false_change_environment }}'
purge_tags: False
@@ -1218,8 +1218,8 @@
assert:
that:
- >
- result.parameter_metadata.tags['{{ item.key }}'] ==
- (simple_tags_orig | combine(simple_tags_purge_false_change_environment))['{{ item.key }}']
+ result.parameter_metadata.tags[item.key] ==
+ (simple_tags_orig | combine(simple_tags_purge_false_change_environment))[item.key]
loop: >
{{ simple_tags_orig | combine(simple_tags_purge_false_change_environment) | dict2items }}
loop_control:
@@ -1230,8 +1230,8 @@
assert:
that:
- >
- result.parameter_metadata.tags | length == {{ simple_tags_orig |
- combine(simple_tags_purge_false_change_environment) | dict2items }} | length
+ result.parameter_metadata.tags | length == simple_tags_orig |
+ combine(simple_tags_purge_false_change_environment) | dict2items | length
- name: Change tag case (purge_tags=false) - Lookup a tagged parameter
set_fact:
@@ -1259,7 +1259,7 @@
- result.parameter_metadata.type == 'String'
- name: Change tag case (purge_tags=false) - Delete parameter
- aws_ssm_parameter_store:
+ ssm_parameter:
name: "{{item}}"
state: absent
ignore_errors: True
@@ -1270,7 +1270,7 @@
# Test tags - Change multiple tags case (purge_tags=false)
- name: Change multiple tags (purge_tags=false) - Create parameter
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
description: '{{ simple_tag_param_description }}'
value: '{{ simple_tag_param_value }}'
@@ -1278,7 +1278,7 @@
register: result
- name: Change multiple tags (purge_tags=false) - Change tag (CHECK)
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
tags: '{{ simple_tags_purge_false_change_multiple}}'
purge_tags: False
@@ -1289,7 +1289,7 @@
- result is changed
- name: Change multiple tags (purge_tags=false) - Change tag
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
tags: '{{ simple_tags_purge_false_change_multiple }}'
purge_tags: False
@@ -1299,8 +1299,8 @@
assert:
that:
- >
- result.parameter_metadata.tags['{{ item.key }}'] ==
- (simple_tags_orig | combine(simple_tags_purge_false_change_multiple))['{{ item.key }}']
+ result.parameter_metadata.tags[item.key] ==
+ (simple_tags_orig | combine(simple_tags_purge_false_change_multiple))[item.key]
loop: >
{{ simple_tags_orig | combine(simple_tags_purge_false_change_multiple) | dict2items }}
loop_control:
@@ -1311,8 +1311,8 @@
assert:
that:
- >
- result.parameter_metadata.tags | length == {{ simple_tags_orig |
- combine(simple_tags_purge_false_change_multiple) | dict2items }} | length
+ result.parameter_metadata.tags | length == simple_tags_orig |
+ combine(simple_tags_purge_false_change_multiple) | dict2items | length
- name: Change multiple tags (purge_tags=false) - Lookup a tagged parameter
set_fact:
@@ -1340,7 +1340,7 @@
- result.parameter_metadata.type == 'String'
- name: Change multiple tags (purge_tags=false) - Delete parameter
- aws_ssm_parameter_store:
+ ssm_parameter:
name: "{{item}}"
state: absent
ignore_errors: True
@@ -1351,7 +1351,7 @@
# Test tags - Add/Change multiple tags case (purge_tags=false)
- name: Add/Change multiple tags (purge_tags=false) - Create parameter
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
description: '{{ simple_tag_param_description }}'
value: '{{ simple_tag_param_value }}'
@@ -1359,7 +1359,7 @@
register: result
- name: Add/Change multiple tags (purge_tags=false) - Change tag (CHECK)
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
tags: '{{ simple_tags_purge_false_add_and_change}}'
purge_tags: False
@@ -1370,7 +1370,7 @@
- result is changed
- name: Add/Change multiple tags (purge_tags=false) - Change tag
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
tags: '{{ simple_tags_purge_false_add_and_change }}'
purge_tags: False
@@ -1380,8 +1380,8 @@
assert:
that:
- >
- result.parameter_metadata.tags['{{ item.key }}'] ==
- (simple_tags_orig | combine(simple_tags_purge_false_add_and_change))['{{ item.key }}']
+ result.parameter_metadata.tags[item.key] ==
+ (simple_tags_orig | combine(simple_tags_purge_false_add_and_change))[item.key]
loop: >
{{ simple_tags_orig | combine(simple_tags_purge_false_add_and_change) | dict2items }}
loop_control:
@@ -1392,8 +1392,8 @@
assert:
that:
- >
- result.parameter_metadata.tags | length == {{ simple_tags_orig |
- combine(simple_tags_purge_false_add_and_change) | dict2items }} | length
+ result.parameter_metadata.tags | length == simple_tags_orig |
+ combine(simple_tags_purge_false_add_and_change) | dict2items | length
- name: Add/Change multiple tags (purge_tags=false) - Lookup a tagged parameter
set_fact:
@@ -1421,7 +1421,7 @@
- result.parameter_metadata.type == 'String'
- name: Add/Change multiple tags (purge_tags=false) - Delete parameter
- aws_ssm_parameter_store:
+ ssm_parameter:
name: "{{item}}"
state: absent
ignore_errors: True
@@ -1432,7 +1432,7 @@
# Test tags - Empty tags dict case (purge_tags=false) # should be no change
- name: Empty tags dict (purge_tags=false) - Create parameter
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
description: '{{ simple_tag_param_description }}'
value: '{{ simple_tag_param_value }}'
@@ -1440,7 +1440,7 @@
register: result
- name: Empty tags dict (purge_tags=false) - Change tag (CHECK)
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
tags: {}
purge_tags: False
@@ -1451,7 +1451,7 @@
- result != 'changed'
- name: Empty tags dict (purge_tags=false) - Change tag
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
tags: {}
purge_tags: False
@@ -1461,7 +1461,7 @@
assert:
that:
- >
- result.parameter_metadata.tags['{{ item.key }}'] == simple_tags_orig['{{ item.key }}']
+ result.parameter_metadata.tags[item.key] == simple_tags_orig[item.key]
loop: >
{{ simple_tags_orig | dict2items }}
loop_control:
@@ -1472,7 +1472,7 @@
that:
- >
result.parameter_metadata.tags | length
- == {{ simple_tags_orig | dict2items }} | length
+ == simple_tags_orig | dict2items | length
- name: Empty tags dict (purge_tags=false) - Lookup a tagged parameter
set_fact:
@@ -1500,7 +1500,7 @@
- result.parameter_metadata.type == 'String'
- name: Empty tags dict (purge_tags=false) - Delete parameter
- aws_ssm_parameter_store:
+ ssm_parameter:
name: "{{item}}"
state: absent
ignore_errors: True
@@ -1511,7 +1511,7 @@
# Test tags - No tags parameter (purge_tags=true) case # should be no change
- name: No tags parameter (purge_tags=true) - Create parameter
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
description: '{{ simple_tag_param_description }}'
value: '{{ simple_tag_param_value }}'
@@ -1519,7 +1519,7 @@
register: result
- name: No tags parameter (purge_tags=true) - Change tag (CHECK)
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
description: '{{ simple_tag_param_updated_description }}'
register: result
@@ -1529,7 +1529,7 @@
- result is changed
- name: No tags parameter (purge_tags=true) - Change tag
- aws_ssm_parameter_store:
+ ssm_parameter:
name: '{{ simple_tag_param_name }}'
description: '{{ simple_tag_param_updated_description }}'
register: result
@@ -1538,8 +1538,8 @@
assert:
that:
- >
- result.parameter_metadata.tags['{{ item.key }}']
- == simple_tags_orig['{{ item.key }}']
+ result.parameter_metadata.tags[item.key]
+ == simple_tags_orig[item.key]
loop: >
{{ simple_tags_orig | dict2items }}
loop_control:
@@ -1550,7 +1550,7 @@
that:
- >
result.parameter_metadata.tags | length
- == {{ simple_tags_orig | dict2items }} | length
+ == simple_tags_orig | dict2items | length
- name: No tags parameter (purge_tags=true) - Lookup a tagged parameter
set_fact:
@@ -1578,7 +1578,7 @@
- result.parameter_metadata.type == 'String'
- name: No tags parameter (purge_tags=true) - Delete parameter
- aws_ssm_parameter_store:
+ ssm_parameter:
name: "{{item}}"
state: absent
ignore_errors: true
@@ -1588,7 +1588,7 @@
always:
# ============================================================
- name: Delete remaining key/value pairs in aws parameter store
- aws_ssm_parameter_store:
+ ssm_parameter:
name: "{{item}}"
state: absent
ignore_errors: True
diff --git a/ansible_collections/community/aws/tests/integration/targets/stepfunctions_state_machine/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/stepfunctions_state_machine/tasks/main.yml
index 8c4bbec71..061acb2c3 100644
--- a/ansible_collections/community/aws/tests/integration/targets/stepfunctions_state_machine/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/stepfunctions_state_machine/tasks/main.yml
@@ -3,9 +3,9 @@
- name: Integration test for AWS Step Function state machine module
module_defaults:
group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"
collections:
- amazon.aws
@@ -33,7 +33,7 @@
# ==== Tests ===================================================
- name: Create a new state machine -- check_mode
- aws_step_functions_state_machine:
+ stepfunctions_state_machine:
name: "{{ state_machine_name }}"
definition: "{{ lookup('file','state_machine.json') }}"
role_arn: "{{ step_functions_role.iam_role.arn }}"
@@ -49,7 +49,7 @@
- creation_check.output == 'State machine would be created.'
- name: Create a new state machine
- aws_step_functions_state_machine:
+ stepfunctions_state_machine:
name: "{{ state_machine_name }}"
definition: "{{ lookup('file','state_machine.json') }}"
role_arn: "{{ step_functions_role.iam_role.arn }}"
@@ -68,7 +68,7 @@
seconds: 5
- name: Idempotent rerun of same state function -- check_mode
- aws_step_functions_state_machine:
+ stepfunctions_state_machine:
name: "{{ state_machine_name }}"
definition: "{{ lookup('file','state_machine.json') }}"
role_arn: "{{ step_functions_role.iam_role.arn }}"
@@ -84,7 +84,7 @@
- result.output == 'State is up-to-date.'
- name: Idempotent rerun of same state function
- aws_step_functions_state_machine:
+ stepfunctions_state_machine:
name: "{{ state_machine_name }}"
definition: "{{ lookup('file','state_machine.json') }}"
role_arn: "{{ step_functions_role.iam_role.arn }}"
@@ -99,7 +99,7 @@
- result.state_machine_arn == creation_output.state_machine_arn
- name: Update an existing state machine -- check_mode
- aws_step_functions_state_machine:
+ stepfunctions_state_machine:
name: "{{ state_machine_name }}"
definition: "{{ lookup('file','alternative_state_machine.json') }}"
role_arn: "{{ step_functions_role.iam_role.arn }}"
@@ -112,10 +112,10 @@
- assert:
that:
- update_check.changed == True
- - "update_check.output == 'State machine would be updated: {{ creation_output.state_machine_arn }}'"
+ - "update_check.output == 'State machine would be updated: ' ~ creation_output.state_machine_arn"
- name: Update an existing state machine
- aws_step_functions_state_machine:
+ stepfunctions_state_machine:
name: "{{ state_machine_name }}"
definition: "{{ lookup('file','alternative_state_machine.json') }}"
role_arn: "{{ step_functions_role.iam_role.arn }}"
@@ -130,7 +130,7 @@
- update_output.state_machine_arn == creation_output.state_machine_arn
- name: Start execution of state machine -- check_mode
- aws_step_functions_state_machine_execution:
+ stepfunctions_state_machine_execution:
name: "{{ execution_name }}"
execution_input: "{}"
state_machine_arn: "{{ creation_output.state_machine_arn }}"
@@ -143,7 +143,7 @@
- "start_execution_output.output == 'State machine execution would be started.'"
- name: Start execution of state machine
- aws_step_functions_state_machine_execution:
+ stepfunctions_state_machine_execution:
name: "{{ execution_name }}"
execution_input: "{}"
state_machine_arn: "{{ creation_output.state_machine_arn }}"
@@ -156,7 +156,7 @@
- "'start_date' in start_execution_output"
- name: Start execution of state machine (check for idempotency) (check mode)
- aws_step_functions_state_machine_execution:
+ stepfunctions_state_machine_execution:
name: "{{ execution_name }}"
execution_input: "{}"
state_machine_arn: "{{ creation_output.state_machine_arn }}"
@@ -169,7 +169,7 @@
- "start_execution_output_idem_check.output == 'State machine execution already exists.'"
- name: Start execution of state machine (check for idempotency)
- aws_step_functions_state_machine_execution:
+ stepfunctions_state_machine_execution:
name: "{{ execution_name }}"
execution_input: "{}"
state_machine_arn: "{{ creation_output.state_machine_arn }}"
@@ -180,7 +180,7 @@
- not start_execution_output_idem.changed
- name: Stop execution of state machine -- check_mode
- aws_step_functions_state_machine_execution:
+ stepfunctions_state_machine_execution:
action: stop
execution_arn: "{{ start_execution_output.execution_arn }}"
cause: "cause of the failure"
@@ -194,7 +194,7 @@
- "stop_execution_output.output == 'State machine execution would be stopped.'"
- name: Stop execution of state machine
- aws_step_functions_state_machine_execution:
+ stepfunctions_state_machine_execution:
action: stop
execution_arn: "{{ start_execution_output.execution_arn }}"
cause: "cause of the failure"
@@ -207,7 +207,7 @@
- "'stop_date' in stop_execution_output"
- name: Stop execution of state machine (check for idempotency)
- aws_step_functions_state_machine_execution:
+ stepfunctions_state_machine_execution:
action: stop
execution_arn: "{{ start_execution_output.execution_arn }}"
cause: "cause of the failure"
@@ -219,7 +219,7 @@
- not stop_execution_output.changed
- name: Try stopping a non-running execution -- check_mode
- aws_step_functions_state_machine_execution:
+ stepfunctions_state_machine_execution:
action: stop
execution_arn: "{{ start_execution_output.execution_arn }}"
cause: "cause of the failure"
@@ -233,7 +233,7 @@
- "stop_execution_output.output == 'State machine execution is not running.'"
- name: Try stopping a non-running execution
- aws_step_functions_state_machine_execution:
+ stepfunctions_state_machine_execution:
action: stop
execution_arn: "{{ start_execution_output.execution_arn }}"
cause: "cause of the failure"
@@ -246,7 +246,7 @@
- not stop_execution_output.changed
- name: Start execution of state machine with the same execution name
- aws_step_functions_state_machine_execution:
+ stepfunctions_state_machine_execution:
name: "{{ execution_name }}"
state_machine_arn: "{{ creation_output.state_machine_arn }}"
register: start_execution_output_again
@@ -256,7 +256,7 @@
- not start_execution_output_again.changed
- name: Remove state machine -- check_mode
- aws_step_functions_state_machine:
+ stepfunctions_state_machine:
name: "{{ state_machine_name }}"
state: absent
register: deletion_check
@@ -265,10 +265,10 @@
- assert:
that:
- deletion_check.changed == True
- - "deletion_check.output == 'State machine would be deleted: {{ creation_output.state_machine_arn }}'"
+ - "deletion_check.output == 'State machine would be deleted: ' ~ creation_output.state_machine_arn"
- name: Remove state machine
- aws_step_functions_state_machine:
+ stepfunctions_state_machine:
name: "{{ state_machine_name }}"
state: absent
register: deletion_output
@@ -279,7 +279,7 @@
- deletion_output.state_machine_arn == creation_output.state_machine_arn
- name: Non-existent state machine is absent
- aws_step_functions_state_machine:
+ stepfunctions_state_machine:
name: "non_existing_state_machine"
state: absent
register: result
@@ -293,7 +293,7 @@
always:
- name: Cleanup - delete state machine
- aws_step_functions_state_machine:
+ stepfunctions_state_machine:
name: "{{ state_machine_name }}"
state: absent
ignore_errors: true
diff --git a/ansible_collections/community/aws/tests/integration/targets/sts_assume_role/defaults/main.yml b/ansible_collections/community/aws/tests/integration/targets/sts_assume_role/defaults/main.yml
deleted file mode 100644
index 17072d6a4..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/sts_assume_role/defaults/main.yml
+++ /dev/null
@@ -1 +0,0 @@
-iam_role_name: "ansible-test-{{ tiny_prefix }}"
diff --git a/ansible_collections/community/aws/tests/integration/targets/sts_assume_role/meta/main.yml b/ansible_collections/community/aws/tests/integration/targets/sts_assume_role/meta/main.yml
deleted file mode 100644
index 32cf5dda7..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/sts_assume_role/meta/main.yml
+++ /dev/null
@@ -1 +0,0 @@
-dependencies: []
diff --git a/ansible_collections/community/aws/tests/integration/targets/sts_assume_role/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/sts_assume_role/tasks/main.yml
deleted file mode 100644
index be684dcea..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/sts_assume_role/tasks/main.yml
+++ /dev/null
@@ -1,332 +0,0 @@
----
-# tasks file for sts_assume_role
-
-- module_defaults:
- group/aws:
- region: "{{ aws_region }}"
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
- collections:
- - amazon.aws
- block:
- # Get some information about who we are before starting our tests
- # we'll need this as soon as we start working on the policies
- - name: get ARN of calling user
- aws_caller_info:
- register: aws_caller_info
-
- - name: register account id
- set_fact:
- aws_account: "{{ aws_caller_info.account }}"
-
- # ============================================================
- - name: create test iam role
- iam_role:
- name: "{{ iam_role_name }}"
- assume_role_policy_document: "{{ lookup('template','policy.json.j2') }}"
- create_instance_profile: False
- managed_policy:
- - arn:aws:iam::aws:policy/IAMReadOnlyAccess
- state: present
- register: test_role
-
- # ============================================================
- - name: pause to ensure role exists before using
- pause:
- seconds: 30
-
- # ============================================================
- - name: test with no parameters
- sts_assume_role:
- aws_access_key: '{{ omit }}'
- aws_secret_key: '{{ omit }}'
- security_token: '{{ omit }}'
- register: result
- ignore_errors: true
-
- - name: assert with no parameters
- assert:
- that:
- - 'result.failed'
- - "'missing required arguments:' in result.msg"
-
- # ============================================================
- - name: test with empty parameters
- sts_assume_role:
- role_arn:
- role_session_name:
- policy:
- duration_seconds:
- external_id:
- mfa_token:
- mfa_serial_number:
- register: result
- ignore_errors: true
-
- - name: assert with empty parameters
- assert:
- that:
- - 'result.failed'
- - "'Missing required parameter in input:' in result.msg"
- when: result.module_stderr is not defined
-
- - name: assert with empty parameters
- assert:
- that:
- - 'result.failed'
- - "'Member must have length greater than or equal to 20' in result.module_stderr"
- when: result.module_stderr is defined
-
- # ============================================================
- - name: test with only 'role_arn' parameter
- sts_assume_role:
- role_arn: "{{ test_role.iam_role.arn }}"
- register: result
- ignore_errors: true
-
- - name: assert with only 'role_arn' parameter
- assert:
- that:
- - 'result.failed'
- - "'missing required arguments: role_session_name' in result.msg"
-
- # ============================================================
- - name: test with only 'role_session_name' parameter
- sts_assume_role:
- role_session_name: "AnsibleTest"
- register: result
- ignore_errors: true
-
- - name: assert with only 'role_session_name' parameter
- assert:
- that:
- - 'result.failed'
- - "'missing required arguments: role_arn' in result.msg"
-
- # ============================================================
- - name: test assume role with invalid policy
- sts_assume_role:
- role_arn: "{{ test_role.iam_role.arn }}"
- role_session_name: "AnsibleTest"
- policy: "invalid policy"
- register: result
- ignore_errors: true
-
- - name: assert assume role with invalid policy
- assert:
- that:
- - 'result.failed'
- - "'The policy is not in the valid JSON format.' in result.msg"
- when: result.module_stderr is not defined
-
- - name: assert assume role with invalid policy
- assert:
- that:
- - 'result.failed'
- - "'The policy is not in the valid JSON format.' in result.module_stderr"
- when: result.module_stderr is defined
-
- # ============================================================
- - name: test assume role with invalid duration seconds
- sts_assume_role:
- role_arn: "{{ test_role.iam_role.arn }}"
- role_session_name: AnsibleTest
- duration_seconds: invalid duration
- register: result
- ignore_errors: true
-
- - name: assert assume role with invalid duration seconds
- assert:
- that:
- - result is failed
- - "'duration_seconds' in result.msg"
- - "'cannot be converted to an int' in result.msg"
-
- # ============================================================
- - name: test assume role with invalid external id
- sts_assume_role:
- role_arn: "{{ test_role.iam_role.arn }}"
- role_session_name: AnsibleTest
- external_id: invalid external id
- register: result
- ignore_errors: true
-
- - name: assert assume role with invalid external id
- assert:
- that:
- - 'result.failed'
- - "'Member must satisfy regular expression pattern:' in result.msg"
- when: result.module_stderr is not defined
-
- - name: assert assume role with invalid external id
- assert:
- that:
- - 'result.failed'
- - "'Member must satisfy regular expression pattern:' in result.module_stderr"
- when: result.module_stderr is defined
-
- # ============================================================
- - name: test assume role with invalid mfa serial number
- sts_assume_role:
- role_arn: "{{ test_role.iam_role.arn }}"
- role_session_name: AnsibleTest
- mfa_serial_number: invalid serial number
- register: result
- ignore_errors: true
-
- - name: assert assume role with invalid mfa serial number
- assert:
- that:
- - 'result.failed'
- - "'Member must satisfy regular expression pattern:' in result.msg"
- when: result.module_stderr is not defined
-
- - name: assert assume role with invalid mfa serial number
- assert:
- that:
- - 'result.failed'
- - "'Member must satisfy regular expression pattern:' in result.module_stderr"
- when: result.module_stderr is defined
-
- # ============================================================
- - name: test assume role with invalid mfa token code
- sts_assume_role:
- role_arn: "{{ test_role.iam_role.arn }}"
- role_session_name: AnsibleTest
- mfa_token: invalid token code
- register: result
- ignore_errors: true
-
- - name: assert assume role with invalid mfa token code
- assert:
- that:
- - 'result.failed'
- - "'Member must satisfy regular expression pattern:' in result.msg"
- when: result.module_stderr is not defined
-
- - name: assert assume role with invalid mfa token code
- assert:
- that:
- - 'result.failed'
- - "'Member must satisfy regular expression pattern:' in result.module_stderr"
- when: result.module_stderr is defined
-
- # ============================================================
- - name: test assume role with invalid role_arn
- sts_assume_role:
- role_arn: invalid role arn
- role_session_name: AnsibleTest
- register: result
- ignore_errors: true
-
- - name: assert assume role with invalid role_arn
- assert:
- that:
- - result.failed
- - "'Invalid length for parameter RoleArn' in result.msg"
- when: result.module_stderr is not defined
-
- - name: assert assume role with invalid role_arn
- assert:
- that:
- - 'result.failed'
- - "'Member must have length greater than or equal to 20' in result.module_stderr"
- when: result.module_stderr is defined
-
- # ============================================================
- - name: test assume not existing sts role
- sts_assume_role:
- role_arn: "arn:aws:iam::123456789:role/non-existing-role"
- role_session_name: "AnsibleTest"
- register: result
- ignore_errors: true
-
- - name: assert assume not existing sts role
- assert:
- that:
- - 'result.failed'
- - "'is not authorized to perform: sts:AssumeRole' in result.msg"
- when: result.module_stderr is not defined
-
- - name: assert assume not existing sts role
- assert:
- that:
- - 'result.failed'
- - "'is not authorized to perform: sts:AssumeRole' in result.msg"
- when: result.module_stderr is defined
-
- # ============================================================
- - name: test assume role
- sts_assume_role:
- role_arn: "{{ test_role.iam_role.arn }}"
- role_session_name: AnsibleTest
- register: assumed_role
-
- - name: assert assume role
- assert:
- that:
- - 'not assumed_role.failed'
- - "'sts_creds' in assumed_role"
- - "'access_key' in assumed_role.sts_creds"
- - "'secret_key' in assumed_role.sts_creds"
- - "'session_token' in assumed_role.sts_creds"
-
- # ============================================================
- - name: test that assumed credentials have IAM read-only access
- iam_role:
- aws_access_key: "{{ assumed_role.sts_creds.access_key }}"
- aws_secret_key: "{{ assumed_role.sts_creds.secret_key }}"
- security_token: "{{ assumed_role.sts_creds.session_token }}"
- name: "{{ iam_role_name }}"
- assume_role_policy_document: "{{ lookup('template','policy.json.j2') }}"
- create_instance_profile: False
- state: present
- register: result
-
- - name: assert assumed role with privileged action (expect changed=false)
- assert:
- that:
- - 'not result.failed'
- - 'not result.changed'
- - "'iam_role' in result"
-
- # ============================================================
- - name: test assumed role with unprivileged action
- iam_role:
- aws_access_key: "{{ assumed_role.sts_creds.access_key }}"
- aws_secret_key: "{{ assumed_role.sts_creds.secret_key }}"
- security_token: "{{ assumed_role.sts_creds.session_token }}"
- name: "{{ iam_role_name }}-new"
- assume_role_policy_document: "{{ lookup('template','policy.json.j2') }}"
- state: present
- register: result
- ignore_errors: true
-
- - name: assert assumed role with unprivileged action (expect changed=false)
- assert:
- that:
- - 'result.failed'
- - "'is not authorized to perform: iam:CreateRole' in result.msg"
- # runs on Python2
- when: result.module_stderr is not defined
-
- - name: assert assumed role with unprivileged action (expect changed=false)
- assert:
- that:
- - 'result.failed'
- - "'is not authorized to perform: iam:CreateRole' in result.module_stderr"
- # runs on Python3
- when: result.module_stderr is defined
-
- # ============================================================
- always:
-
- - name: delete test iam role
- iam_role:
- name: "{{ iam_role_name }}"
- assume_role_policy_document: "{{ lookup('template','policy.json.j2') }}"
- delete_instance_profile: True
- managed_policy:
- - arn:aws:iam::aws:policy/IAMReadOnlyAccess
- state: absent
diff --git a/ansible_collections/community/aws/tests/integration/targets/sts_assume_role/templates/policy.json.j2 b/ansible_collections/community/aws/tests/integration/targets/sts_assume_role/templates/policy.json.j2
deleted file mode 100644
index 559562fd9..000000000
--- a/ansible_collections/community/aws/tests/integration/targets/sts_assume_role/templates/policy.json.j2
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "Version": "2012-10-17",
- "Statement": [
- {
- "Effect": "Allow",
- "Principal": {
- "AWS": "arn:aws:iam::{{ aws_account }}:root"
- },
- "Action": "sts:AssumeRole"
- }
- ]
-} \ No newline at end of file
diff --git a/ansible_collections/community/aws/tests/integration/targets/sts_session_token/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/sts_session_token/tasks/main.yml
index 6231119ec..c814cfd5f 100644
--- a/ansible_collections/community/aws/tests/integration/targets/sts_session_token/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/sts_session_token/tasks/main.yml
@@ -3,9 +3,9 @@
- module_defaults:
group/aws:
region: "{{ aws_region }}"
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
collections:
- amazon.aws
block:
@@ -54,9 +54,9 @@
- name: Get ARN of user when running with generated token
aws_caller_info:
- aws_access_key: "{{ token_details.sts_creds.access_key }}"
- aws_secret_key: "{{ token_details.sts_creds.secret_key }}"
- security_token: "{{ token_details.sts_creds.session_token }}"
+ access_key: "{{ token_details.sts_creds.access_key }}"
+ secret_key: "{{ token_details.sts_creds.secret_key }}"
+ session_token: "{{ token_details.sts_creds.session_token }}"
register: token_aws_caller_info
- assert:
diff --git a/ansible_collections/community/aws/tests/integration/targets/waf_web_acl/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/waf_web_acl/tasks/main.yml
index c176e7def..acbf1f29c 100644
--- a/ansible_collections/community/aws/tests/integration/targets/waf_web_acl/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/waf_web_acl/tasks/main.yml
@@ -4,9 +4,9 @@
- amazon.aws
module_defaults:
group/aws:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token | default(omit) }}'
+ access_key: '{{ aws_access_key }}'
+ secret_key: '{{ aws_secret_key }}'
+ session_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region }}'
block:
@@ -15,7 +15,7 @@
##################################################
- name: create WAF IP condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_ip_condition"
filters:
- ip_address: "10.0.0.0/8"
@@ -23,7 +23,7 @@
register: create_waf_ip_condition
- name: add an IP address to WAF condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_ip_condition"
filters:
- ip_address: "10.0.0.0/8"
@@ -37,7 +37,7 @@
- add_ip_address_to_waf_condition.condition.ip_set_descriptors|length == 2
- name: add an IP address to WAF condition (rely on purge_filters defaulting to false)
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_ip_condition"
filters:
- ip_address: "192.168.10.0/24"
@@ -51,7 +51,7 @@
- add_ip_address_to_waf_condition_no_purge.changed
- name: add an IP address to WAF condition (set purge_filters)
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_ip_condition"
filters:
- ip_address: "192.168.20.0/24"
@@ -66,7 +66,7 @@
- add_ip_address_to_waf_condition_purge.changed
- name: create WAF byte condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_byte_condition"
filters:
- field_to_match: header
@@ -77,7 +77,7 @@
register: create_waf_byte_condition
- name: recreate WAF byte condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_byte_condition"
filters:
- field_to_match: header
@@ -93,7 +93,7 @@
- not recreate_waf_byte_condition.changed
- name: create WAF geo condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_geo_condition"
filters:
- country: US
@@ -103,7 +103,7 @@
register: create_waf_geo_condition
- name: create WAF size condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_size_condition"
filters:
- field_to_match: query_string
@@ -113,7 +113,7 @@
register: create_waf_size_condition
- name: create WAF sql condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_sql_condition"
filters:
- field_to_match: query_string
@@ -122,7 +122,7 @@
register: create_waf_sql_condition
- name: create WAF xss condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_xss_condition"
filters:
- field_to_match: query_string
@@ -131,7 +131,7 @@
register: create_waf_xss_condition
- name: create WAF regex condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_regex_condition"
filters:
- field_to_match: query_string
@@ -145,7 +145,7 @@
register: create_waf_regex_condition
- name: create a second WAF regex condition with the same regex
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_regex_condition_part_2"
filters:
- field_to_match: header
@@ -169,7 +169,7 @@
- name: delete first WAF regex condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_regex_condition"
filters:
- field_to_match: query_string
@@ -184,7 +184,7 @@
register: delete_waf_regex_condition
- name: delete second WAF regex condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_regex_condition_part_2"
filters:
- field_to_match: header
@@ -200,7 +200,7 @@
register: delete_second_waf_regex_condition
- name: create WAF regex condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_regex_condition"
filters:
- field_to_match: query_string
@@ -221,7 +221,7 @@
create_waf_regex_condition.condition.regex_match_tuples[0].regex_pattern_set_id
- name: create WAF Regional IP condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_ip_condition"
filters:
- ip_address: "10.0.0.0/8"
@@ -231,7 +231,7 @@
register: create_waf_regional_ip_condition
- name: add an IP address to WAF Regional condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_ip_condition"
filters:
- ip_address: "10.0.0.0/8"
@@ -247,7 +247,7 @@
- add_ip_address_to_waf_regional_condition.condition.ip_set_descriptors|length == 2
- name: add an IP address to WAF Regional condition (rely on purge_filters defaulting to false)
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_ip_condition"
filters:
- ip_address: "192.168.10.0/24"
@@ -263,7 +263,7 @@
- add_ip_address_to_waf_regional_condition_no_purge.changed
- name: add an IP address to WAF Regional condition (set purge_filters)
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_ip_condition"
filters:
- ip_address: "192.168.20.0/24"
@@ -280,7 +280,7 @@
- add_ip_address_to_waf_regional_condition_purge.changed
- name: create WAF Regional byte condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_byte_condition"
filters:
- field_to_match: header
@@ -293,7 +293,7 @@
register: create_waf_regional_byte_condition
- name: recreate WAF Regional byte condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_byte_condition"
filters:
- field_to_match: header
@@ -311,7 +311,7 @@
- not recreate_waf_regional_byte_condition.changed
- name: create WAF Regional geo condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_geo_condition"
filters:
- country: US
@@ -323,7 +323,7 @@
register: create_waf_regional_geo_condition
- name: create WAF Regional size condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_size_condition"
filters:
- field_to_match: query_string
@@ -335,7 +335,7 @@
register: create_waf_regional_size_condition
- name: create WAF Regional sql condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_sql_condition"
filters:
- field_to_match: query_string
@@ -346,7 +346,7 @@
register: create_waf_regional_sql_condition
- name: create WAF Regional xss condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_xss_condition"
filters:
- field_to_match: query_string
@@ -357,7 +357,7 @@
register: create_waf_regional_xss_condition
- name: create WAF Regional regex condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_regex_condition"
filters:
- field_to_match: query_string
@@ -373,7 +373,7 @@
register: create_waf_regional_regex_condition
- name: create a second WAF Regional regex condition with the same regex
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_regex_condition_part_2"
filters:
- field_to_match: header
@@ -399,7 +399,7 @@
- name: delete first WAF Regional regex condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_regex_condition"
filters:
- field_to_match: query_string
@@ -416,7 +416,7 @@
register: delete_waf_regional_regex_condition
- name: delete second WAF Regional regex condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_regex_condition_part_2"
filters:
- field_to_match: header
@@ -434,7 +434,7 @@
register: delete_second_waf_regional_regex_condition
- name: create WAF Regional regex condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_regex_condition"
filters:
- field_to_match: query_string
@@ -461,7 +461,7 @@
##################################################
- name: create WAF rule
- aws_waf_rule:
+ waf_rule:
name: "{{ resource_prefix }}_rule"
conditions:
- name: "{{ resource_prefix }}_regex_condition"
@@ -483,7 +483,7 @@
- create_aws_waf_rule.rule.predicates|length == 3
- name: recreate WAF rule
- aws_waf_rule:
+ waf_rule:
name: "{{ resource_prefix }}_rule"
conditions:
- name: "{{ resource_prefix }}_regex_condition"
@@ -504,7 +504,7 @@
- create_aws_waf_rule.rule.predicates|length == 3
- name: add further WAF rules relying on purge_conditions defaulting to false
- aws_waf_rule:
+ waf_rule:
name: "{{ resource_prefix }}_rule"
conditions:
- name: "{{ resource_prefix }}_ip_condition"
@@ -525,7 +525,7 @@
- add_conditions_to_aws_waf_rule.rule.predicates|length == 6
- name: remove some rules through purging conditions
- aws_waf_rule:
+ waf_rule:
name: "{{ resource_prefix }}_rule"
conditions:
- name: "{{ resource_prefix }}_ip_condition"
@@ -550,7 +550,7 @@
- add_and_remove_waf_rule_conditions.rule.predicates|length == 4
- name: attempt to remove an in use condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_size_condition"
type: size
state: absent
@@ -561,10 +561,10 @@
assert:
that:
- remove_in_use_condition.failed
- - "'Condition {{ resource_prefix }}_size_condition is in use' in remove_in_use_condition.msg"
+ - "'Condition ' ~ resource_prefix ~ '_size_condition is in use' in remove_in_use_condition.msg"
- name: create WAF Regional rule
- aws_waf_rule:
+ waf_rule:
name: "{{ resource_prefix }}_rule"
conditions:
- name: "{{ resource_prefix }}_regex_condition"
@@ -588,7 +588,7 @@
- create_aws_waf_regional_rule.rule.predicates|length == 3
- name: recreate WAF Regional rule
- aws_waf_rule:
+ waf_rule:
name: "{{ resource_prefix }}_rule"
conditions:
- name: "{{ resource_prefix }}_regex_condition"
@@ -611,7 +611,7 @@
- create_aws_waf_regional_rule.rule.predicates|length == 3
- name: add further WAF Regional rules relying on purge_conditions defaulting to false
- aws_waf_rule:
+ waf_rule:
name: "{{ resource_prefix }}_rule"
conditions:
- name: "{{ resource_prefix }}_ip_condition"
@@ -634,7 +634,7 @@
- add_conditions_to_aws_waf_regional_rule.rule.predicates|length == 6
- name: remove some rules through purging conditions
- aws_waf_rule:
+ waf_rule:
name: "{{ resource_prefix }}_rule"
conditions:
- name: "{{ resource_prefix }}_ip_condition"
@@ -661,7 +661,7 @@
- add_and_remove_waf_regional_rule_conditions.rule.predicates|length == 4
- name: attempt to remove an WAF Regional in use condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_size_condition"
type: size
state: absent
@@ -674,14 +674,14 @@
assert:
that:
- remove_in_use_condition.failed
- - "'Condition {{ resource_prefix }}_size_condition is in use' in remove_in_use_condition.msg"
+ - "'Condition ' ~ resource_prefix ~ '_size_condition is in use' in remove_in_use_condition.msg"
##################################################
# aws_waf_web_acl tests
##################################################
- name: create web ACL
- aws_waf_web_acl:
+ waf_web_acl:
name: "{{ resource_prefix }}_web_acl"
rules:
- name: "{{ resource_prefix }}_rule"
@@ -693,7 +693,7 @@
register: create_web_acl
- name: recreate web acl
- aws_waf_web_acl:
+ waf_web_acl:
name: "{{ resource_prefix }}_web_acl"
rules:
- name: "{{ resource_prefix }}_rule"
@@ -710,7 +710,7 @@
- recreate_web_acl.web_acl.rules|length == 1
- name: create a second WAF rule
- aws_waf_rule:
+ waf_rule:
name: "{{ resource_prefix }}_rule_2"
conditions:
- name: "{{ resource_prefix }}_ip_condition"
@@ -724,7 +724,7 @@
negated: no
- name: add a new rule to the web acl
- aws_waf_web_acl:
+ waf_web_acl:
name: "{{ resource_prefix }}_web_acl"
rules:
- name: "{{ resource_prefix }}_rule_2"
@@ -741,7 +741,7 @@
- web_acl_add_rule.web_acl.rules|length == 2
- name: use purge rules to remove the first rule
- aws_waf_web_acl:
+ waf_web_acl:
name: "{{ resource_prefix }}_web_acl"
rules:
- name: "{{ resource_prefix }}_rule_2"
@@ -759,7 +759,7 @@
- web_acl_add_rule.web_acl.rules|length == 1
- name: swap two rules of same priority
- aws_waf_web_acl:
+ waf_web_acl:
name: "{{ resource_prefix }}_web_acl"
rules:
- name: "{{ resource_prefix }}_rule"
@@ -771,7 +771,7 @@
register: web_acl_swap_rule
- name: attempt to delete the inuse first rule
- aws_waf_rule:
+ waf_rule:
name: "{{ resource_prefix }}_rule"
state: absent
ignore_errors: yes
@@ -783,7 +783,7 @@
- remove_inuse_rule.failed
- name: delete the web acl
- aws_waf_web_acl:
+ waf_web_acl:
name: "{{ resource_prefix }}_web_acl"
state: absent
register: delete_web_acl
@@ -795,12 +795,12 @@
- not delete_web_acl.web_acl
- name: delete the no longer in use first rule
- aws_waf_rule:
+ waf_rule:
name: "{{ resource_prefix }}_rule"
state: absent
- name: create WAF Regional web ACL
- aws_waf_web_acl:
+ waf_web_acl:
name: "{{ resource_prefix }}_web_acl"
rules:
- name: "{{ resource_prefix }}_rule"
@@ -814,7 +814,7 @@
register: create_waf_regional_web_acl
- name: recreate WAF Regional web acl
- aws_waf_web_acl:
+ waf_web_acl:
name: "{{ resource_prefix }}_web_acl"
rules:
- name: "{{ resource_prefix }}_rule"
@@ -833,7 +833,7 @@
- recreate_waf_regional_web_acl.web_acl.rules|length == 1
- name: create a second WAF Regional rule
- aws_waf_rule:
+ waf_rule:
name: "{{ resource_prefix }}_rule_2"
conditions:
- name: "{{ resource_prefix }}_ip_condition"
@@ -849,7 +849,7 @@
waf_regional: true
- name: add a new rule to the WAF Regional web acl
- aws_waf_web_acl:
+ waf_web_acl:
name: "{{ resource_prefix }}_web_acl"
rules:
- name: "{{ resource_prefix }}_rule_2"
@@ -868,7 +868,7 @@
- waf_regional_web_acl_add_rule.web_acl.rules|length == 2
- name: use purge rules to remove the WAF Regional first rule
- aws_waf_web_acl:
+ waf_web_acl:
name: "{{ resource_prefix }}_web_acl"
rules:
- name: "{{ resource_prefix }}_rule_2"
@@ -888,7 +888,7 @@
- waf_regional_web_acl_add_rule.web_acl.rules|length == 1
- name: swap two WAF Regional rules of same priority
- aws_waf_web_acl:
+ waf_web_acl:
name: "{{ resource_prefix }}_web_acl"
rules:
- name: "{{ resource_prefix }}_rule"
@@ -902,7 +902,7 @@
register: waf_regional_web_acl_swap_rule
- name: attempt to delete the WAF Regional inuse first rule
- aws_waf_rule:
+ waf_rule:
name: "{{ resource_prefix }}_rule"
state: absent
region: "{{ aws_region }}"
@@ -916,7 +916,7 @@
- remove_waf_regional_inuse_rule.failed
- name: delete the WAF Regional web acl
- aws_waf_web_acl:
+ waf_web_acl:
name: "{{ resource_prefix }}_web_acl"
state: absent
region: "{{ aws_region }}"
@@ -930,7 +930,7 @@
- not delete_waf_regional_web_acl.web_acl
- name: delete the no longer in use WAF Regional first rule
- aws_waf_rule:
+ waf_rule:
name: "{{ resource_prefix }}_rule"
state: absent
region: "{{ aws_region }}"
@@ -945,84 +945,84 @@
msg: "****** TEARDOWN STARTS HERE ******"
- name: delete the web acl
- aws_waf_web_acl:
+ waf_web_acl:
name: "{{ resource_prefix }}_web_acl"
state: absent
purge_rules: yes
ignore_errors: yes
- name: remove second WAF rule
- aws_waf_rule:
+ waf_rule:
name: "{{ resource_prefix }}_rule_2"
state: absent
purge_conditions: yes
ignore_errors: yes
- name: remove WAF rule
- aws_waf_rule:
+ waf_rule:
name: "{{ resource_prefix }}_rule"
state: absent
purge_conditions: yes
ignore_errors: yes
- name: remove XSS condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_xss_condition"
type: xss
state: absent
ignore_errors: yes
- name: remove SQL condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_sql_condition"
type: sql
state: absent
ignore_errors: yes
- name: remove size condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_size_condition"
type: size
state: absent
ignore_errors: yes
- name: remove geo condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_geo_condition"
type: geo
state: absent
ignore_errors: yes
- name: remove byte condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_byte_condition"
type: byte
state: absent
ignore_errors: yes
- name: remove ip address condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_ip_condition"
type: ip
state: absent
ignore_errors: yes
- name: remove regex part 2 condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_regex_condition_part_2"
type: regex
state: absent
ignore_errors: yes
- name: remove first regex condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_regex_condition"
type: regex
state: absent
ignore_errors: yes
- name: delete the WAF Regional web acl
- aws_waf_web_acl:
+ waf_web_acl:
name: "{{ resource_prefix }}_web_acl"
state: absent
purge_rules: yes
@@ -1031,7 +1031,7 @@
ignore_errors: yes
- name: remove second WAF Regional rule
- aws_waf_rule:
+ waf_rule:
name: "{{ resource_prefix }}_rule_2"
state: absent
purge_conditions: yes
@@ -1040,7 +1040,7 @@
ignore_errors: yes
- name: remove WAF Regional rule
- aws_waf_rule:
+ waf_rule:
name: "{{ resource_prefix }}_rule"
state: absent
purge_conditions: yes
@@ -1049,7 +1049,7 @@
ignore_errors: yes
- name: remove WAF Regional XSS condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_xss_condition"
type: xss
state: absent
@@ -1058,7 +1058,7 @@
ignore_errors: yes
- name: remove WAF Regional SQL condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_sql_condition"
type: sql
state: absent
@@ -1067,7 +1067,7 @@
ignore_errors: yes
- name: remove WAF Regional size condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_size_condition"
type: size
state: absent
@@ -1076,7 +1076,7 @@
ignore_errors: yes
- name: remove WAF Regional geo condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_geo_condition"
type: geo
state: absent
@@ -1085,7 +1085,7 @@
ignore_errors: yes
- name: remove WAF Regional byte condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_byte_condition"
type: byte
state: absent
@@ -1094,7 +1094,7 @@
ignore_errors: yes
- name: remove WAF Regional ip address condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_ip_condition"
type: ip
state: absent
@@ -1103,7 +1103,7 @@
ignore_errors: yes
- name: remove WAF Regional regex part 2 condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_regex_condition_part_2"
type: regex
state: absent
@@ -1112,7 +1112,7 @@
ignore_errors: yes
- name: remove first WAF Regional regex condition
- aws_waf_condition:
+ waf_condition:
name: "{{ resource_prefix }}_regex_condition"
type: regex
state: absent
diff --git a/ansible_collections/community/aws/tests/integration/targets/wafv2/tasks/alb.yml b/ansible_collections/community/aws/tests/integration/targets/wafv2/tasks/alb.yml
index 32aeb376a..c56ad6d46 100644
--- a/ansible_collections/community/aws/tests/integration/targets/wafv2/tasks/alb.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/wafv2/tasks/alb.yml
@@ -63,7 +63,7 @@
gateway_id: '{{ igw.gateway_id }}'
register: route_table
-- ec2_group:
+- ec2_security_group:
name: '{{ resource_prefix }}'
description: security group for Ansible ALB integration tests
state: present
diff --git a/ansible_collections/community/aws/tests/integration/targets/wafv2/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/wafv2/tasks/main.yml
index 547c4c151..a536cf405 100644
--- a/ansible_collections/community/aws/tests/integration/targets/wafv2/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/wafv2/tasks/main.yml
@@ -1,9 +1,9 @@
---
- module_defaults:
group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"
block:
@@ -103,10 +103,6 @@
#########################
- name: destroy ALB
elb_application_lb:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token }}'
- region: '{{ aws_region }}'
name: '{{ alb_name }}'
state: absent
wait: true
@@ -115,10 +111,6 @@
- name: destroy target group if it was created
elb_target_group:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token }}'
- region: '{{ aws_region }}'
name: '{{ tg_name }}'
protocol: http
port: 80
@@ -134,11 +126,7 @@
ignore_errors: true
- name: destroy sec group
- ec2_group:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token }}'
- region: '{{ aws_region }}'
+ ec2_security_group:
name: '{{ sec_group.group_name }}'
description: security group for Ansible ALB integration tests
state: absent
@@ -151,10 +139,6 @@
- name: remove route table
ec2_vpc_route_table:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token }}'
- region: '{{ aws_region }}'
vpc_id: '{{ vpc.vpc.id }}'
route_table_id: '{{ route_table.route_table.route_table_id }}'
lookup: id
@@ -167,10 +151,6 @@
- name: destroy subnets
ec2_vpc_subnet:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token }}'
- region: '{{ aws_region }}'
cidr: '{{ item.cidr }}'
vpc_id: '{{ vpc.vpc.id }}'
state: absent
@@ -187,10 +167,6 @@
- name: destroy internet gateway
ec2_vpc_igw:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token }}'
- region: '{{ aws_region }}'
vpc_id: '{{ vpc.vpc.id }}'
tags:
Name: '{{ resource_prefix }}'
@@ -203,10 +179,6 @@
- name: destroy VPC
ec2_vpc_net:
- aws_access_key: '{{ aws_access_key }}'
- aws_secret_key: '{{ aws_secret_key }}'
- security_token: '{{ security_token }}'
- region: '{{ aws_region }}'
cidr_block: 10.228.228.0/22
name: '{{ resource_prefix }}_vpc'
state: absent
diff --git a/ansible_collections/community/aws/tests/integration/targets/wafv2/tasks/rule_group.yml b/ansible_collections/community/aws/tests/integration/targets/wafv2/tasks/rule_group.yml
index 6ec46f5dd..7648504be 100644
--- a/ansible_collections/community/aws/tests/integration/targets/wafv2/tasks/rule_group.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/wafv2/tasks/rule_group.yml
@@ -79,7 +79,6 @@
- name: rule group info
wafv2_rule_group_info:
name: "{{ rule_group_name }}"
- state: present
scope: REGIONAL
register: out
@@ -554,7 +553,6 @@
- name: rule group info
wafv2_rule_group_info:
name: "{{ rule_group_name }}"
- state: present
scope: REGIONAL
register: out
@@ -671,7 +669,6 @@
- name: rule group info
wafv2_rule_group_info:
name: "{{ rule_group_name }}"
- state: present
scope: REGIONAL
register: out
diff --git a/ansible_collections/community/aws/tests/integration/targets/wafv2_ip_set/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/wafv2_ip_set/tasks/main.yml
index f7afc5b93..6fcf4438c 100644
--- a/ansible_collections/community/aws/tests/integration/targets/wafv2_ip_set/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/wafv2_ip_set/tasks/main.yml
@@ -1,9 +1,9 @@
---
- module_defaults:
group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"
block:
- name: check_mode create ip set
diff --git a/ansible_collections/community/aws/tests/integration/targets/wafv2_rule_group/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/wafv2_rule_group/tasks/main.yml
index 630d5de29..b2a2fcd8c 100644
--- a/ansible_collections/community/aws/tests/integration/targets/wafv2_rule_group/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/wafv2_rule_group/tasks/main.yml
@@ -1,9 +1,9 @@
---
- module_defaults:
group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"
block:
####################################
@@ -87,7 +87,6 @@
- name: rule group info
wafv2_rule_group_info:
name: "{{ rule_group_name }}"
- state: present
scope: REGIONAL
register: out
@@ -562,7 +561,6 @@
- name: rule group info
wafv2_rule_group_info:
name: "{{ rule_group_name }}"
- state: present
scope: REGIONAL
register: out
@@ -679,7 +677,6 @@
- name: rule group info
wafv2_rule_group_info:
name: "{{ rule_group_name }}"
- state: present
scope: REGIONAL
register: out
diff --git a/ansible_collections/community/aws/tests/integration/targets/wafv2_web_acl/tasks/main.yml b/ansible_collections/community/aws/tests/integration/targets/wafv2_web_acl/tasks/main.yml
index 9d44e2b77..64544fd50 100644
--- a/ansible_collections/community/aws/tests/integration/targets/wafv2_web_acl/tasks/main.yml
+++ b/ansible_collections/community/aws/tests/integration/targets/wafv2_web_acl/tasks/main.yml
@@ -1,9 +1,9 @@
---
- module_defaults:
group/aws:
- aws_access_key: "{{ aws_access_key }}"
- aws_secret_key: "{{ aws_secret_key }}"
- security_token: "{{ security_token | default(omit) }}"
+ access_key: "{{ aws_access_key }}"
+ secret_key: "{{ aws_secret_key }}"
+ session_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"
block:
diff --git a/ansible_collections/community/aws/tests/requirements.yml b/ansible_collections/community/aws/tests/requirements.yml
deleted file mode 100644
index 98b77a444..000000000
--- a/ansible_collections/community/aws/tests/requirements.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-integration_tests_dependencies:
-- amazon.aws >= 3.0.0
-- ansible.windows
-- community.crypto
-- community.general
-unit_tests_dependencies:
-- amazon.aws >= 3.0.0
diff --git a/ansible_collections/community/aws/tests/sanity/ignore-2.11.txt b/ansible_collections/community/aws/tests/sanity/ignore-2.11.txt
index 1c8bcbbeb..e69de29bb 100644
--- a/ansible_collections/community/aws/tests/sanity/ignore-2.11.txt
+++ b/ansible_collections/community/aws/tests/sanity/ignore-2.11.txt
@@ -1 +0,0 @@
-plugins/modules/cloudfront_distribution_info.py pylint:unnecessary-comprehension # (new test) Should be an easy fix, but testing is a challenge - test are broken and aliases require a wildcard cert in ACM
diff --git a/ansible_collections/community/aws/tests/sanity/ignore-2.12.txt b/ansible_collections/community/aws/tests/sanity/ignore-2.12.txt
index 1c8bcbbeb..e69de29bb 100644
--- a/ansible_collections/community/aws/tests/sanity/ignore-2.12.txt
+++ b/ansible_collections/community/aws/tests/sanity/ignore-2.12.txt
@@ -1 +0,0 @@
-plugins/modules/cloudfront_distribution_info.py pylint:unnecessary-comprehension # (new test) Should be an easy fix, but testing is a challenge - test are broken and aliases require a wildcard cert in ACM
diff --git a/ansible_collections/community/aws/tests/sanity/ignore-2.13.txt b/ansible_collections/community/aws/tests/sanity/ignore-2.13.txt
index 1c8bcbbeb..e69de29bb 100644
--- a/ansible_collections/community/aws/tests/sanity/ignore-2.13.txt
+++ b/ansible_collections/community/aws/tests/sanity/ignore-2.13.txt
@@ -1 +0,0 @@
-plugins/modules/cloudfront_distribution_info.py pylint:unnecessary-comprehension # (new test) Should be an easy fix, but testing is a challenge - test are broken and aliases require a wildcard cert in ACM
diff --git a/ansible_collections/community/aws/tests/sanity/ignore-2.14.txt b/ansible_collections/community/aws/tests/sanity/ignore-2.14.txt
index 1c8bcbbeb..67d3693df 100644
--- a/ansible_collections/community/aws/tests/sanity/ignore-2.14.txt
+++ b/ansible_collections/community/aws/tests/sanity/ignore-2.14.txt
@@ -1 +1,2 @@
-plugins/modules/cloudfront_distribution_info.py pylint:unnecessary-comprehension # (new test) Should be an easy fix, but testing is a challenge - test are broken and aliases require a wildcard cert in ACM
+plugins/connection/aws_ssm.py yamllint:unparsable-with-libyaml # bug in ansible-test - https://github.com/ansible/ansible/issues/82353
+plugins/inventory/aws_mq.py yamllint:unparsable-with-libyaml # bug in ansible-test - https://github.com/ansible/ansible/issues/82353
diff --git a/ansible_collections/community/aws/tests/sanity/ignore-2.15.txt b/ansible_collections/community/aws/tests/sanity/ignore-2.15.txt
index 1c8bcbbeb..67d3693df 100644
--- a/ansible_collections/community/aws/tests/sanity/ignore-2.15.txt
+++ b/ansible_collections/community/aws/tests/sanity/ignore-2.15.txt
@@ -1 +1,2 @@
-plugins/modules/cloudfront_distribution_info.py pylint:unnecessary-comprehension # (new test) Should be an easy fix, but testing is a challenge - test are broken and aliases require a wildcard cert in ACM
+plugins/connection/aws_ssm.py yamllint:unparsable-with-libyaml # bug in ansible-test - https://github.com/ansible/ansible/issues/82353
+plugins/inventory/aws_mq.py yamllint:unparsable-with-libyaml # bug in ansible-test - https://github.com/ansible/ansible/issues/82353
diff --git a/ansible_collections/community/aws/tests/sanity/ignore-2.16.txt b/ansible_collections/community/aws/tests/sanity/ignore-2.16.txt
new file mode 100644
index 000000000..67d3693df
--- /dev/null
+++ b/ansible_collections/community/aws/tests/sanity/ignore-2.16.txt
@@ -0,0 +1,2 @@
+plugins/connection/aws_ssm.py yamllint:unparsable-with-libyaml # bug in ansible-test - https://github.com/ansible/ansible/issues/82353
+plugins/inventory/aws_mq.py yamllint:unparsable-with-libyaml # bug in ansible-test - https://github.com/ansible/ansible/issues/82353
diff --git a/ansible_collections/community/aws/tests/sanity/ignore-2.17.txt b/ansible_collections/community/aws/tests/sanity/ignore-2.17.txt
new file mode 100644
index 000000000..67d3693df
--- /dev/null
+++ b/ansible_collections/community/aws/tests/sanity/ignore-2.17.txt
@@ -0,0 +1,2 @@
+plugins/connection/aws_ssm.py yamllint:unparsable-with-libyaml # bug in ansible-test - https://github.com/ansible/ansible/issues/82353
+plugins/inventory/aws_mq.py yamllint:unparsable-with-libyaml # bug in ansible-test - https://github.com/ansible/ansible/issues/82353
diff --git a/ansible_collections/community/aws/tests/sanity/ignore-2.9.txt b/ansible_collections/community/aws/tests/sanity/ignore-2.9.txt
index 5ae2cc9cc..e69de29bb 100644
--- a/ansible_collections/community/aws/tests/sanity/ignore-2.9.txt
+++ b/ansible_collections/community/aws/tests/sanity/ignore-2.9.txt
@@ -1 +0,0 @@
-plugins/modules/iam_role.py pylint:ansible-deprecated-no-version
diff --git a/ansible_collections/community/aws/tests/sanity/requirements.yml b/ansible_collections/community/aws/tests/sanity/requirements.yml
new file mode 100644
index 000000000..99ce82a1b
--- /dev/null
+++ b/ansible_collections/community/aws/tests/sanity/requirements.yml
@@ -0,0 +1,5 @@
+---
+collections:
+ - name: https://github.com/ansible-collections/amazon.aws.git
+ type: git
+ version: main
diff --git a/ansible_collections/community/aws/tests/unit/compat/builtins.py b/ansible_collections/community/aws/tests/unit/compat/builtins.py
index 349d310e8..3df85be4f 100644
--- a/ansible_collections/community/aws/tests/unit/compat/builtins.py
+++ b/ansible_collections/community/aws/tests/unit/compat/builtins.py
@@ -16,7 +16,10 @@
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
__metaclass__ = type
#
@@ -28,6 +31,6 @@ __metaclass__ = type
try:
import __builtin__ # pylint: disable=unused-import
except ImportError:
- BUILTINS = 'builtins'
+ BUILTINS = "builtins"
else:
- BUILTINS = '__builtin__'
+ BUILTINS = "__builtin__"
diff --git a/ansible_collections/community/aws/tests/unit/compat/mock.py b/ansible_collections/community/aws/tests/unit/compat/mock.py
deleted file mode 100644
index 0972cd2e8..000000000
--- a/ansible_collections/community/aws/tests/unit/compat/mock.py
+++ /dev/null
@@ -1,122 +0,0 @@
-# (c) 2014, Toshio Kuratomi <tkuratomi@ansible.com>
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-'''
-Compat module for Python3.x's unittest.mock module
-'''
-import sys
-
-# Python 2.7
-
-# Note: Could use the pypi mock library on python3.x as well as python2.x. It
-# is the same as the python3 stdlib mock library
-
-try:
- # Allow wildcard import because we really do want to import all of mock's
- # symbols into this compat shim
- # pylint: disable=wildcard-import,unused-wildcard-import
- from unittest.mock import *
-except ImportError:
- # Python 2
- # pylint: disable=wildcard-import,unused-wildcard-import
- try:
- from mock import *
- except ImportError:
- print('You need the mock library installed on python2.x to run tests')
-
-
-# Prior to 3.4.4, mock_open cannot handle binary read_data
-if sys.version_info >= (3,) and sys.version_info < (3, 4, 4):
- file_spec = None
-
- def _iterate_read_data(read_data):
- # Helper for mock_open:
- # Retrieve lines from read_data via a generator so that separate calls to
- # readline, read, and readlines are properly interleaved
- sep = b'\n' if isinstance(read_data, bytes) else '\n'
- data_as_list = [l + sep for l in read_data.split(sep)]
-
- if data_as_list[-1] == sep:
- # If the last line ended in a newline, the list comprehension will have an
- # extra entry that's just a newline. Remove this.
- data_as_list = data_as_list[:-1]
- else:
- # If there wasn't an extra newline by itself, then the file being
- # emulated doesn't have a newline to end the last line remove the
- # newline that our naive format() added
- data_as_list[-1] = data_as_list[-1][:-1]
-
- for line in data_as_list:
- yield line
-
- def mock_open(mock=None, read_data=''):
- """
- A helper function to create a mock to replace the use of `open`. It works
- for `open` called directly or used as a context manager.
-
- The `mock` argument is the mock object to configure. If `None` (the
- default) then a `MagicMock` will be created for you, with the API limited
- to methods or attributes available on standard file handles.
-
- `read_data` is a string for the `read` methoddline`, and `readlines` of the
- file handle to return. This is an empty string by default.
- """
- def _readlines_side_effect(*args, **kwargs):
- if handle.readlines.return_value is not None:
- return handle.readlines.return_value
- return list(_data)
-
- def _read_side_effect(*args, **kwargs):
- if handle.read.return_value is not None:
- return handle.read.return_value
- return type(read_data)().join(_data)
-
- def _readline_side_effect():
- if handle.readline.return_value is not None:
- while True:
- yield handle.readline.return_value
- for line in _data:
- yield line
-
- global file_spec
- if file_spec is None:
- import _io
- file_spec = list(set(dir(_io.TextIOWrapper)).union(set(dir(_io.BytesIO))))
-
- if mock is None:
- mock = MagicMock(name='open', spec=open)
-
- handle = MagicMock(spec=file_spec)
- handle.__enter__.return_value = handle
-
- _data = _iterate_read_data(read_data)
-
- handle.write.return_value = None
- handle.read.return_value = None
- handle.readline.return_value = None
- handle.readlines.return_value = None
-
- handle.read.side_effect = _read_side_effect
- handle.readline.side_effect = _readline_side_effect()
- handle.readlines.side_effect = _readlines_side_effect
-
- mock.return_value = handle
- return mock
diff --git a/ansible_collections/community/aws/tests/unit/compat/unittest.py b/ansible_collections/community/aws/tests/unit/compat/unittest.py
deleted file mode 100644
index 98f08ad6a..000000000
--- a/ansible_collections/community/aws/tests/unit/compat/unittest.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# (c) 2014, Toshio Kuratomi <tkuratomi@ansible.com>
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-'''
-Compat module for Python2.7's unittest module
-'''
-
-import sys
-
-# Allow wildcard import because we really do want to import all of
-# unittests's symbols into this compat shim
-# pylint: disable=wildcard-import,unused-wildcard-import
-if sys.version_info < (2, 7):
- try:
- # Need unittest2 on python2.6
- from unittest2 import *
- except ImportError:
- print('You need unittest2 installed on python2.6.x to run tests')
-else:
- from unittest import *
diff --git a/ansible_collections/community/aws/tests/unit/constraints.txt b/ansible_collections/community/aws/tests/unit/constraints.txt
index cd546e7c2..5708323f1 100644
--- a/ansible_collections/community/aws/tests/unit/constraints.txt
+++ b/ansible_collections/community/aws/tests/unit/constraints.txt
@@ -1,7 +1,7 @@
# Specifically run tests against the oldest versions that we support
-boto3==1.18.0
-botocore==1.21.0
+botocore==1.29.0
+boto3==1.26.0
# AWS CLI has `botocore==` dependencies, provide the one that matches botocore
# to avoid needing to download over a years worth of awscli wheels.
-awscli==1.20.0
+awscli==1.27.0
diff --git a/ansible_collections/community/aws/tests/unit/mock/loader.py b/ansible_collections/community/aws/tests/unit/mock/loader.py
index 00a584127..339a1918c 100644
--- a/ansible_collections/community/aws/tests/unit/mock/loader.py
+++ b/ansible_collections/community/aws/tests/unit/mock/loader.py
@@ -16,21 +16,24 @@
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
__metaclass__ = type
import os
from ansible.errors import AnsibleParserError
+from ansible.module_utils._text import to_bytes
+from ansible.module_utils._text import to_text
from ansible.parsing.dataloader import DataLoader
-from ansible.module_utils._text import to_bytes, to_text
class DictDataLoader(DataLoader):
-
def __init__(self, file_mapping=None):
file_mapping = {} if file_mapping is None else file_mapping
- assert type(file_mapping) == dict
+ assert isinstance(file_mapping, dict)
super(DictDataLoader, self).__init__()
@@ -51,7 +54,7 @@ class DictDataLoader(DataLoader):
if file_name in self._file_mapping:
return (to_bytes(self._file_mapping[file_name]), False)
else:
- raise AnsibleParserError("file not found: %s" % file_name)
+ raise AnsibleParserError(f"file not found: {file_name}")
def path_exists(self, path):
path = to_text(path)
@@ -68,7 +71,7 @@ class DictDataLoader(DataLoader):
def list_directory(self, path):
ret = []
path = to_text(path)
- for x in (list(self._file_mapping.keys()) + self._known_directories):
+ for x in list(self._file_mapping.keys()) + self._known_directories:
if x.startswith(path):
if os.path.dirname(x) == path:
ret.append(os.path.basename(x))
@@ -86,7 +89,7 @@ class DictDataLoader(DataLoader):
self._known_directories = []
for path in self._file_mapping:
dirname = os.path.dirname(path)
- while dirname not in ('/', ''):
+ while dirname not in ("/", ""):
self._add_known_directory(dirname)
dirname = os.path.dirname(dirname)
diff --git a/ansible_collections/community/aws/tests/unit/mock/path.py b/ansible_collections/community/aws/tests/unit/mock/path.py
index 676b35ab8..8057e5a58 100644
--- a/ansible_collections/community/aws/tests/unit/mock/path.py
+++ b/ansible_collections/community/aws/tests/unit/mock/path.py
@@ -1,10 +1,7 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
+from unittest.mock import MagicMock
-from ansible_collections.community.aws.tests.unit.compat.mock import MagicMock
from ansible.utils.path import unfrackpath
-
mock_unfrackpath_noop = MagicMock(spec_set=unfrackpath, side_effect=lambda x, *args, **kwargs: x)
diff --git a/ansible_collections/community/aws/tests/unit/mock/procenv.py b/ansible_collections/community/aws/tests/unit/mock/procenv.py
index e516a9458..0d8547f50 100644
--- a/ansible_collections/community/aws/tests/unit/mock/procenv.py
+++ b/ansible_collections/community/aws/tests/unit/mock/procenv.py
@@ -16,22 +16,19 @@
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import sys
import json
-
+import sys
+import unittest
from contextlib import contextmanager
-from io import BytesIO, StringIO
-from ansible_collections.community.aws.tests.unit.compat import unittest
-from ansible.module_utils.six import PY3
+from io import BytesIO
+from io import StringIO
+
from ansible.module_utils._text import to_bytes
+from ansible.module_utils.six import PY3
@contextmanager
-def swap_stdin_and_argv(stdin_data='', argv_data=tuple()):
+def swap_stdin_and_argv(stdin_data="", argv_data=tuple()):
"""
context manager that temporarily masks the test runner's values for stdin and argv
"""
@@ -77,7 +74,7 @@ def swap_stdout():
class ModuleTestCase(unittest.TestCase):
def setUp(self, module_args=None):
if module_args is None:
- module_args = {'_ansible_remote_tmp': '/tmp', '_ansible_keep_remote_files': False}
+ module_args = {"_ansible_remote_tmp": "/tmp", "_ansible_keep_remote_files": False}
args = json.dumps(dict(ANSIBLE_MODULE_ARGS=module_args))
diff --git a/ansible_collections/community/aws/tests/unit/mock/vault_helper.py b/ansible_collections/community/aws/tests/unit/mock/vault_helper.py
index b54629da4..c55228c88 100644
--- a/ansible_collections/community/aws/tests/unit/mock/vault_helper.py
+++ b/ansible_collections/community/aws/tests/unit/mock/vault_helper.py
@@ -1,27 +1,29 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
__metaclass__ = type
from ansible.module_utils._text import to_bytes
-
from ansible.parsing.vault import VaultSecret
class TextVaultSecret(VaultSecret):
- '''A secret piece of text. ie, a password. Tracks text encoding.
+ """A secret piece of text. ie, a password. Tracks text encoding.
The text encoding of the text may not be the default text encoding so
- we keep track of the encoding so we encode it to the same bytes.'''
+ we keep track of the encoding so we encode it to the same bytes."""
def __init__(self, text, encoding=None, errors=None, _bytes=None):
super(TextVaultSecret, self).__init__()
self.text = text
- self.encoding = encoding or 'utf-8'
+ self.encoding = encoding or "utf-8"
self._bytes = _bytes
- self.errors = errors or 'strict'
+ self.errors = errors or "strict"
@property
def bytes(self):
- '''The text encoded with encoding, unless we specifically set _bytes.'''
+ """The text encoded with encoding, unless we specifically set _bytes."""
return self._bytes or to_bytes(self.text, encoding=self.encoding, errors=self.errors)
diff --git a/ansible_collections/community/aws/tests/unit/mock/yaml_helper.py b/ansible_collections/community/aws/tests/unit/mock/yaml_helper.py
index a646c0241..8c99ef40f 100644
--- a/ansible_collections/community/aws/tests/unit/mock/yaml_helper.py
+++ b/ansible_collections/community/aws/tests/unit/mock/yaml_helper.py
@@ -1,18 +1,23 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
__metaclass__ = type
import io
+
import yaml
from ansible.module_utils.six import PY3
-from ansible.parsing.yaml.loader import AnsibleLoader
from ansible.parsing.yaml.dumper import AnsibleDumper
+from ansible.parsing.yaml.loader import AnsibleLoader
class YamlTestUtils(object):
"""Mixin class to combine with a unittest.TestCase subclass."""
+
def _loader(self, stream):
"""Vault related tests will want to override this.
@@ -45,8 +50,7 @@ class YamlTestUtils(object):
obj_2 = loader.get_data()
# dump the gen 2 objects directory to strings
- string_from_object_dump_2 = self._dump_string(obj_2,
- dumper=AnsibleDumper)
+ string_from_object_dump_2 = self._dump_string(obj_2, dumper=AnsibleDumper)
# The gen 1 and gen 2 yaml strings
self.assertEqual(string_from_object_dump, string_from_object_dump_2)
@@ -66,7 +70,7 @@ class YamlTestUtils(object):
self.assertEqual(string_from_object_dump, string_from_object_dump_3)
def _old_dump_load_cycle(self, obj):
- '''Dump the passed in object to yaml, load it back up, dump again, compare.'''
+ """Dump the passed in object to yaml, load it back up, dump again, compare."""
stream = io.StringIO()
yaml_string = self._dump_string(obj, dumper=AnsibleDumper)
@@ -111,16 +115,23 @@ class YamlTestUtils(object):
assert yaml_string == yaml_string_obj_from_stream
assert yaml_string == yaml_string_obj_from_stream == yaml_string_obj_from_string
- assert (yaml_string == yaml_string_obj_from_stream == yaml_string_obj_from_string == yaml_string_stream_obj_from_stream ==
- yaml_string_stream_obj_from_string)
+ assert (
+ yaml_string
+ == yaml_string_obj_from_stream
+ == yaml_string_obj_from_string
+ == yaml_string_stream_obj_from_stream
+ == yaml_string_stream_obj_from_string
+ )
assert obj == obj_from_stream
assert obj == obj_from_string
assert obj == yaml_string_obj_from_stream
assert obj == yaml_string_obj_from_string
assert obj == obj_from_stream == obj_from_string == yaml_string_obj_from_stream == yaml_string_obj_from_string
- return {'obj': obj,
- 'yaml_string': yaml_string,
- 'yaml_string_from_stream': yaml_string_from_stream,
- 'obj_from_stream': obj_from_stream,
- 'obj_from_string': obj_from_string,
- 'yaml_string_obj_from_string': yaml_string_obj_from_string}
+ return {
+ "obj": obj,
+ "yaml_string": yaml_string,
+ "yaml_string_from_stream": yaml_string_from_stream,
+ "obj_from_stream": obj_from_stream,
+ "obj_from_string": obj_from_string,
+ "yaml_string_obj_from_string": yaml_string_obj_from_string,
+ }
diff --git a/ansible_collections/community/aws/tests/unit/plugins/connection/test_aws_ssm.py b/ansible_collections/community/aws/tests/unit/plugins/connection/test_aws_ssm.py
index 579cafc16..d5fcb4b1e 100644
--- a/ansible_collections/community/aws/tests/unit/plugins/connection/test_aws_ssm.py
+++ b/ansible_collections/community/aws/tests/unit/plugins/connection/test_aws_ssm.py
@@ -1,11 +1,11 @@
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from io import StringIO
+from unittest.mock import MagicMock
+from unittest.mock import patch
+
import pytest
-from ansible_collections.community.aws.tests.unit.compat.mock import patch, MagicMock
from ansible.playbook.play_context import PlayContext
from ansible.plugins.loader import connection_loader
@@ -15,46 +15,45 @@ if not HAS_BOTO3:
pytestmark = pytest.mark.skip("test_data_pipeline.py requires the python modules 'boto3' and 'botocore'")
-class TestConnectionBaseClass():
-
- @patch('os.path.exists')
- @patch('subprocess.Popen')
- @patch('select.poll')
- @patch('boto3.client')
+class TestConnectionBaseClass:
+ @patch("os.path.exists")
+ @patch("subprocess.Popen")
+ @patch("select.poll")
+ @patch("boto3.client")
def test_plugins_connection_aws_ssm_start_session(self, boto_client, s_poll, s_popen, mock_ospe):
pc = PlayContext()
new_stdin = StringIO()
- conn = connection_loader.get('community.aws.aws_ssm', pc, new_stdin)
+ conn = connection_loader.get("community.aws.aws_ssm", pc, new_stdin)
conn.get_option = MagicMock()
- conn.get_option.side_effect = ['i1234', 'executable', 'abcd', 'i1234']
- conn.host = 'abc'
+ conn.get_option.side_effect = ["i1234", "executable", "abcd", "i1234"]
+ conn.host = "abc"
mock_ospe.return_value = True
boto3 = MagicMock()
- boto3.client('ssm').return_value = MagicMock()
+ boto3.client("ssm").return_value = MagicMock()
conn.start_session = MagicMock()
conn._session_id = MagicMock()
- conn._session_id.return_value = 's1'
+ conn._session_id.return_value = "s1"
s_popen.return_value.stdin.write = MagicMock()
s_poll.return_value = MagicMock()
s_poll.return_value.register = MagicMock()
s_popen.return_value.poll = MagicMock()
s_popen.return_value.poll.return_value = None
conn._stdin_readline = MagicMock()
- conn._stdin_readline.return_value = 'abc123'
- conn.SESSION_START = 'abc'
+ conn._stdin_readline.return_value = "abc123"
+ conn.SESSION_START = "abc"
conn.start_session()
- @patch('random.choice')
+ @patch("random.choice")
def test_plugins_connection_aws_ssm_exec_command(self, r_choice):
pc = PlayContext()
new_stdin = StringIO()
- conn = connection_loader.get('community.aws.aws_ssm', pc, new_stdin)
- r_choice.side_effect = ['a', 'a', 'a', 'a', 'a', 'b', 'b', 'b', 'b', 'b']
+ conn = connection_loader.get("community.aws.aws_ssm", pc, new_stdin)
+ r_choice.side_effect = ["a", "a", "a", "a", "a", "b", "b", "b", "b", "b"]
conn.MARK_LENGTH = 5
conn._session = MagicMock()
conn._session.stdin.write = MagicMock()
conn._wrap_command = MagicMock()
- conn._wrap_command.return_value = 'cmd1'
+ conn._wrap_command.return_value = "cmd1"
conn._flush_stderr = MagicMock()
conn._windows = MagicMock()
conn._windows.return_value = True
@@ -67,44 +66,44 @@ class TestConnectionBaseClass():
conn._session.stdout = MagicMock()
conn._session.stdout.readline = MagicMock()
conn._post_process = MagicMock()
- conn._post_process.return_value = 'test'
- conn._session.stdout.readline.side_effect = iter(['aaaaa\n', 'Hi\n', '0\n', 'bbbbb\n'])
+ conn._post_process.return_value = "test"
+ conn._session.stdout.readline.side_effect = iter(["aaaaa\n", "Hi\n", "0\n", "bbbbb\n"])
conn.get_option = MagicMock()
conn.get_option.return_value = 1
- returncode = 'a'
- stdout = 'b'
+ returncode = "a"
+ stdout = "b"
return (returncode, stdout, conn._flush_stderr)
def test_plugins_connection_aws_ssm_prepare_terminal(self):
pc = PlayContext()
new_stdin = StringIO()
- conn = connection_loader.get('community.aws.aws_ssm', pc, new_stdin)
+ conn = connection_loader.get("community.aws.aws_ssm", pc, new_stdin)
conn.is_windows = MagicMock()
conn.is_windows.return_value = True
def test_plugins_connection_aws_ssm_wrap_command(self):
pc = PlayContext()
new_stdin = StringIO()
- conn = connection_loader.get('community.aws.aws_ssm', pc, new_stdin)
+ conn = connection_loader.get("community.aws.aws_ssm", pc, new_stdin)
conn.is_windows = MagicMock()
conn.is_windows.return_value = True
- return 'windows1'
+ return "windows1"
def test_plugins_connection_aws_ssm_post_process(self):
pc = PlayContext()
new_stdin = StringIO()
- conn = connection_loader.get('community.aws.aws_ssm', pc, new_stdin)
+ conn = connection_loader.get("community.aws.aws_ssm", pc, new_stdin)
conn.is_windows = MagicMock()
conn.is_windows.return_value = True
conn.stdout = MagicMock()
returncode = 0
return returncode, conn.stdout
- @patch('subprocess.Popen')
+ @patch("subprocess.Popen")
def test_plugins_connection_aws_ssm_flush_stderr(self, s_popen):
pc = PlayContext()
new_stdin = StringIO()
- conn = connection_loader.get('community.aws.aws_ssm', pc, new_stdin)
+ conn = connection_loader.get("community.aws.aws_ssm", pc, new_stdin)
conn.poll_stderr = MagicMock()
conn.poll_stderr.register = MagicMock()
conn.stderr = None
@@ -121,37 +120,37 @@ class TestConnectionBaseClass():
# boto3.generate_presigned_url.return_value = MagicMock()
# return (boto3.generate_presigned_url.return_value)
- @patch('os.path.exists')
+ @patch("os.path.exists")
def test_plugins_connection_aws_ssm_put_file(self, mock_ospe):
pc = PlayContext()
new_stdin = StringIO()
- conn = connection_loader.get('community.aws.aws_ssm', pc, new_stdin)
+ conn = connection_loader.get("community.aws.aws_ssm", pc, new_stdin)
conn._connect = MagicMock()
conn._file_transport_command = MagicMock()
- conn._file_transport_command.return_value = (0, 'stdout', 'stderr')
- conn.put_file('/in/file', '/out/file')
+ conn._file_transport_command.return_value = (0, "stdout", "stderr")
+ conn.put_file("/in/file", "/out/file")
def test_plugins_connection_aws_ssm_fetch_file(self):
pc = PlayContext()
new_stdin = StringIO()
- conn = connection_loader.get('community.aws.aws_ssm', pc, new_stdin)
+ conn = connection_loader.get("community.aws.aws_ssm", pc, new_stdin)
conn._connect = MagicMock()
conn._file_transport_command = MagicMock()
- conn._file_transport_command.return_value = (0, 'stdout', 'stderr')
- conn.fetch_file('/in/file', '/out/file')
+ conn._file_transport_command.return_value = (0, "stdout", "stderr")
+ conn.fetch_file("/in/file", "/out/file")
- @patch('subprocess.check_output')
- @patch('boto3.client')
+ @patch("subprocess.check_output")
+ @patch("boto3.client")
def test_plugins_connection_file_transport_command(self, boto_client, s_check_output):
pc = PlayContext()
new_stdin = StringIO()
- conn = connection_loader.get('community.aws.aws_ssm', pc, new_stdin)
+ conn = connection_loader.get("community.aws.aws_ssm", pc, new_stdin)
conn.get_option = MagicMock()
- conn.get_option.side_effect = ['1', '2', '3', '4', '5']
+ conn.get_option.side_effect = ["1", "2", "3", "4", "5"]
conn._get_url = MagicMock()
- conn._get_url.side_effect = ['url1', 'url2']
+ conn._get_url.side_effect = ["url1", "url2"]
boto3 = MagicMock()
- boto3.client('s3').return_value = MagicMock()
+ boto3.client("s3").return_value = MagicMock()
conn.get_option.return_value = 1
get_command = MagicMock()
put_command = MagicMock()
@@ -161,11 +160,11 @@ class TestConnectionBaseClass():
conn.exec_command(put_command, in_data=None, sudoable=False)
conn.exec_command(get_command, in_data=None, sudoable=False)
- @patch('subprocess.check_output')
+ @patch("subprocess.check_output")
def test_plugins_connection_aws_ssm_close(self, s_check_output):
pc = PlayContext()
new_stdin = StringIO()
- conn = connection_loader.get('community.aws.aws_ssm', pc, new_stdin)
+ conn = connection_loader.get("community.aws.aws_ssm", pc, new_stdin)
conn.instance_id = "i-12345"
conn._session_id = True
conn.get_option = MagicMock()
@@ -174,8 +173,8 @@ class TestConnectionBaseClass():
conn._session.terminate = MagicMock()
conn._session.communicate = MagicMock()
conn._terminate_session = MagicMock()
- conn._terminate_session.return_value = ''
+ conn._terminate_session.return_value = ""
conn._session_id = MagicMock()
- conn._session_id.return_value = 'a'
+ conn._session_id.return_value = "a"
conn._client = MagicMock()
conn.close()
diff --git a/ansible_collections/community/fortios/tests/unit/compat/__init__.py b/ansible_collections/community/aws/tests/unit/plugins/inventory/__init__.py
index e69de29bb..e69de29bb 100644
--- a/ansible_collections/community/fortios/tests/unit/compat/__init__.py
+++ b/ansible_collections/community/aws/tests/unit/plugins/inventory/__init__.py
diff --git a/ansible_collections/community/aws/tests/unit/plugins/inventory/test_aws_mq.py b/ansible_collections/community/aws/tests/unit/plugins/inventory/test_aws_mq.py
new file mode 100644
index 000000000..8969b4a03
--- /dev/null
+++ b/ansible_collections/community/aws/tests/unit/plugins/inventory/test_aws_mq.py
@@ -0,0 +1,638 @@
+# -*- coding: utf-8 -*-
+
+# Copyright 2023 Ali AlKhalidi <@doteast>
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+import copy
+import random
+import string
+from unittest.mock import MagicMock
+from unittest.mock import call
+from unittest.mock import patch
+
+import pytest
+
+try:
+ import botocore
+except ImportError:
+ # Handled by HAS_BOTO3
+ pass
+
+from ansible.errors import AnsibleError
+
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import HAS_BOTO3
+
+from ansible_collections.community.aws.plugins.inventory.aws_mq import InventoryModule
+from ansible_collections.community.aws.plugins.inventory.aws_mq import _add_details_to_hosts
+from ansible_collections.community.aws.plugins.inventory.aws_mq import _find_hosts_matching_statuses
+from ansible_collections.community.aws.plugins.inventory.aws_mq import _get_broker_host_tags
+
+if not HAS_BOTO3:
+ pytestmark = pytest.mark.skip("test_aws_mq.py requires the python modules 'boto3' and 'botocore'")
+
+
+def make_clienterror_exception(code="AccessDenied"):
+ return botocore.exceptions.ClientError(
+ {
+ "Error": {"Code": code, "Message": "User is not authorized to perform: xxx on resource: user yyyy"},
+ "ResponseMetadata": {"RequestId": "01234567-89ab-cdef-0123-456789abcdef"},
+ },
+ "getXXX",
+ )
+
+
+@pytest.fixture()
+def inventory():
+ inventory = InventoryModule()
+ inventory.inventory = MagicMock()
+ inventory.inventory.set_variable = MagicMock()
+
+ inventory.all_clients = MagicMock()
+ inventory.get_option = MagicMock()
+
+ inventory._populate_host_vars = MagicMock()
+ inventory._set_composite_vars = MagicMock()
+ inventory._add_host_to_composed_groups = MagicMock()
+ inventory._add_host_to_keyed_groups = MagicMock()
+
+ inventory.get_cache_key = MagicMock()
+
+ inventory._cache = {}
+
+ return inventory
+
+
+@pytest.fixture()
+def connection():
+ conn = MagicMock()
+ return conn
+
+
+@pytest.mark.parametrize(
+ "suffix,result",
+ [
+ ("aws_mq.yml", True),
+ ("aws_mq.yaml", True),
+ ("aws_MQ.yml", False),
+ ("AWS_mq.yaml", False),
+ ],
+)
+def test_inventory_verify_file_suffix(inventory, suffix, result, tmp_path):
+ test_dir = tmp_path / "test_aws_mq"
+ test_dir.mkdir()
+ inventory_file = "inventory" + suffix
+ inventory_file = test_dir / inventory_file
+ inventory_file.write_text("my inventory")
+ assert result == inventory.verify_file(str(inventory_file))
+
+
+def test_inventory_verify_file_with_missing_file(inventory):
+ inventory_file = "this_file_does_not_exist_aws_mq.yml"
+ assert not inventory.verify_file(inventory_file)
+
+
+def generate_random_string(with_digits=True, with_punctuation=True, length=16):
+ data = string.ascii_letters
+ if with_digits:
+ data += string.digits
+ if with_punctuation:
+ data += string.punctuation
+ return "".join([random.choice(data) for i in range(length)])
+
+
+@pytest.mark.parametrize(
+ "hosts,statuses,expected",
+ [
+ (
+ [
+ {"host": "host1", "BrokerState": "DELETION_IN_PROGRESS"},
+ {"host": "host2", "BrokerState": "RUNNING"},
+ {"host": "host3", "BrokerState": "REBOOT_IN_PROGRESS"},
+ {"host": "host4", "BrokerState": "CRITICAL_ACTION_REQUIRED"},
+ {"host": "host5", "BrokerState": "CREATION_FAILED"},
+ {"host": "host6", "BrokerState": "CREATION_IN_PROGRESS"},
+ ],
+ ["RUNNING"],
+ [{"host": "host2", "BrokerState": "RUNNING"}],
+ ),
+ (
+ [
+ {"host": "host1", "BrokerState": "DELETION_IN_PROGRESS"},
+ {"host": "host2", "BrokerState": "RUNNING"},
+ {"host": "host3", "BrokerState": "REBOOT_IN_PROGRESS"},
+ {"host": "host4", "BrokerState": "CRITICAL_ACTION_REQUIRED"},
+ {"host": "host5", "BrokerState": "CREATION_FAILED"},
+ {"host": "host6", "BrokerState": "CREATION_IN_PROGRESS"},
+ ],
+ ["all"],
+ [
+ {"host": "host1", "BrokerState": "DELETION_IN_PROGRESS"},
+ {"host": "host2", "BrokerState": "RUNNING"},
+ {"host": "host3", "BrokerState": "REBOOT_IN_PROGRESS"},
+ {"host": "host4", "BrokerState": "CRITICAL_ACTION_REQUIRED"},
+ {"host": "host5", "BrokerState": "CREATION_FAILED"},
+ {"host": "host6", "BrokerState": "CREATION_IN_PROGRESS"},
+ ],
+ ),
+ (
+ [
+ {"host": "host1", "BrokerState": "DELETION_IN_PROGRESS"},
+ {"host": "host2", "BrokerState": "RUNNING"},
+ {"host": "host3", "BrokerState": "CREATION_FAILED"},
+ {"host": "host4", "BrokerState": "CRITICAL_ACTION_REQUIRED"},
+ {"host": "host5", "BrokerState": "RUNNING"},
+ {"host": "host6", "BrokerState": "CREATION_IN_PROGRESS"},
+ ],
+ ["RUNNING"],
+ [
+ {"host": "host2", "BrokerState": "RUNNING"},
+ {"host": "host5", "BrokerState": "RUNNING"},
+ ],
+ ),
+ ],
+)
+def test_find_hosts_matching_statuses(hosts, statuses, expected):
+ assert expected == _find_hosts_matching_statuses(hosts, statuses)
+
+
+@pytest.mark.parametrize("hosts", ["", "host1", "host2,host3", "host2,host3,host1"])
+@patch("ansible_collections.community.aws.plugins.inventory.aws_mq._get_mq_hostname")
+def test_inventory_format_inventory(m_get_mq_hostname, inventory, hosts):
+ hosts_vars = {
+ "host1": {"var10": "value10"},
+ "host2": {"var20": "value20", "var21": "value21"},
+ "host3": {"var30": "value30", "var31": "value31", "var32": "value32"},
+ }
+
+ m_get_mq_hostname.side_effect = lambda h: h["name"]
+
+ class _inventory_host(object):
+ def __init__(self, name, host_vars):
+ self.name = name
+ self.vars = host_vars
+
+ inventory.inventory = MagicMock()
+ inventory.inventory.get_host.side_effect = lambda x: _inventory_host(name=x, host_vars=hosts_vars.get(x))
+
+ hosts = [{"name": x} for x in hosts.split(",") if x]
+ expected = {
+ "_meta": {"hostvars": {x["name"]: hosts_vars.get(x["name"]) for x in hosts}},
+ "aws_mq": {"hosts": [x["name"] for x in hosts]},
+ }
+
+ assert expected == inventory._format_inventory(hosts)
+ if hosts == []:
+ m_get_mq_hostname.assert_not_called()
+
+
+@pytest.mark.parametrize("length", range(0, 10, 2))
+def test_inventory_populate(inventory, length):
+ group = "aws_mq"
+ hosts = [f"host_{int(i)}" for i in range(length)]
+
+ inventory._add_hosts = MagicMock()
+ inventory._populate(hosts=hosts)
+
+ inventory.inventory.add_group.assert_called_with("aws_mq")
+
+ if len(hosts) == 0:
+ inventory.inventory._add_hosts.assert_not_called()
+ inventory.inventory.add_child.assert_not_called()
+ else:
+ inventory._add_hosts.assert_called_with(hosts=hosts, group=group)
+ inventory.inventory.add_child.assert_called_with("all", group)
+
+
+def test_inventory_populate_from_cache(inventory):
+ cache_data = {
+ "_meta": {
+ "hostvars": {
+ "broker_A": {"var10": "value10"},
+ "broker_B": {"var2": "value2"},
+ "broker_C": {"var3": ["value30", "value31", "value32"]},
+ }
+ },
+ "all": {"hosts": ["broker_A", "broker_D", "broker_B", "broker_C"]},
+ "aws_broker_group_A": {"hosts": ["broker_A", "broker_D"]},
+ "aws_broker_group_B": {"hosts": ["broker_B"]},
+ "aws_broker_group_C": {"hosts": ["broker_C"]},
+ }
+
+ inventory._populate_from_cache(cache_data)
+ inventory.inventory.add_group.assert_has_calls(
+ [
+ call("aws_broker_group_A"),
+ call("aws_broker_group_B"),
+ call("aws_broker_group_C"),
+ ],
+ any_order=True,
+ )
+ inventory.inventory.add_child.assert_has_calls(
+ [
+ call("all", "aws_broker_group_A"),
+ call("all", "aws_broker_group_B"),
+ call("all", "aws_broker_group_C"),
+ ],
+ any_order=True,
+ )
+
+ inventory._populate_host_vars.assert_has_calls(
+ [
+ call(["broker_A"], {"var10": "value10"}, "aws_broker_group_A"),
+ call(["broker_D"], {}, "aws_broker_group_A"),
+ call(["broker_B"], {"var2": "value2"}, "aws_broker_group_B"),
+ call(["broker_C"], {"var3": ["value30", "value31", "value32"]}, "aws_broker_group_C"),
+ ],
+ any_order=True,
+ )
+
+
+@pytest.mark.parametrize("detail", [{}, {"Tags": {"tag1": "value1", "tag2": "value2", "Tag3": "Value2"}}])
+def test_get_broker_host_tags(detail):
+ expected_tags = [
+ {"Key": "tag1", "Value": "value1"},
+ {"Key": "tag2", "Value": "value2"},
+ {"Key": "Tag3", "Value": "Value2"},
+ ]
+
+ tags = _get_broker_host_tags(detail)
+
+ if not detail:
+ assert tags == []
+ else:
+ assert tags == expected_tags
+
+
+@pytest.mark.parametrize("strict", [True, False])
+def test_add_details_to_hosts_with_no_hosts(connection, strict):
+ hosts = []
+
+ _add_details_to_hosts(connection, hosts, strict)
+ connection.describe_broker.assert_not_called()
+
+
+def test_add_details_to_hosts_with_failure_not_strict(connection):
+ hosts = [{"BrokerId": "1"}]
+
+ connection.describe_broker.side_effect = make_clienterror_exception()
+
+ _add_details_to_hosts(connection, hosts, strict=False)
+
+ assert hosts == [{"BrokerId": "1"}]
+
+
+def test_add_details_to_hosts_with_failure_strict(connection):
+ hosts = [{"BrokerId": "1"}]
+
+ connection.describe_broker.side_effect = make_clienterror_exception()
+
+ with pytest.raises(AnsibleError):
+ _add_details_to_hosts(connection, hosts, strict=True)
+
+
+def test_add_details_to_hosts_with_hosts(connection):
+ hosts = [{"BrokerId": "1"}, {"BrokerId": "2"}]
+ broker_hosts_tags = {
+ "1": {"Tags": {"tag10": "value10", "tag11": "value11"}},
+ "2": {"Tags": {"tag20": "value20", "tag21": "value21", "tag22": "value22"}},
+ }
+ connection.describe_broker.side_effect = lambda **kwargs: broker_hosts_tags.get(kwargs.get("BrokerId"))
+
+ _add_details_to_hosts(connection, hosts, strict=False)
+
+ assert hosts == [
+ {
+ "BrokerId": "1",
+ "Tags": [
+ {"Key": "tag10", "Value": "value10"},
+ {"Key": "tag11", "Value": "value11"},
+ ],
+ },
+ {
+ "BrokerId": "2",
+ "Tags": [
+ {"Key": "tag20", "Value": "value20"},
+ {"Key": "tag21", "Value": "value21"},
+ {"Key": "tag22", "Value": "value22"},
+ ],
+ },
+ ]
+
+
+ADD_DETAILS_TO_HOSTS = "ansible_collections.community.aws.plugins.inventory.aws_mq._add_details_to_hosts"
+
+
+@patch(ADD_DETAILS_TO_HOSTS)
+def test_get_broker_hosts(m_add_details_to_hosts, inventory, connection):
+ broker = {
+ "BrokerArn": "arn:xxx:xxxx",
+ "BrokerId": "resource_id",
+ "BrokerName": "brk1",
+ "BrokerState": "RUNNING",
+ "EngineType": "RABBITMQ",
+ "DeploymentMode": "CLUSTER_MULTI_AZ",
+ }
+
+ conn_paginator = MagicMock()
+ paginate = MagicMock()
+
+ connection.get_paginator.return_value = conn_paginator
+ conn_paginator.paginate.return_value = paginate
+
+ paginate.build_full_result.side_effect = lambda **kwargs: {"BrokerSummaries": [broker]}
+
+ connection.describe_broker.return_value = {}
+ connection.list_brokers.return_value = {"BrokerSummaries": [broker]}
+
+ strict = False
+
+ result = inventory._get_broker_hosts(connection=connection, strict=strict)(paginate.build_full_result)
+
+ assert result == [broker]
+
+ m_add_details_to_hosts.assert_called_with(connection, result, strict)
+
+
+@pytest.mark.parametrize("strict", [True, False])
+@patch(ADD_DETAILS_TO_HOSTS)
+def test_get_broker_hosts_with_access_denied(m_add_details_to_hosts, inventory, connection, strict):
+ conn_paginator = MagicMock()
+ paginate = MagicMock()
+
+ connection.get_paginator.return_value = conn_paginator
+ conn_paginator.paginate.return_value = paginate
+
+ paginate.build_full_result.side_effect = make_clienterror_exception()
+
+ if strict:
+ with pytest.raises(AnsibleError):
+ inventory._get_broker_hosts(connection=connection, strict=strict)(paginate.build_full_result)
+ else:
+ assert inventory._get_broker_hosts(connection=connection, strict=strict)(paginate.build_full_result) == []
+
+ m_add_details_to_hosts.assert_not_called()
+
+
+@patch(ADD_DETAILS_TO_HOSTS)
+def test_get_broker_hosts_with_client_error(m_add_details_to_hosts, inventory, connection):
+ conn_paginator = MagicMock()
+ paginate = MagicMock()
+
+ connection.get_paginator.return_value = conn_paginator
+ conn_paginator.paginate.return_value = paginate
+
+ paginate.build_full_result.side_effect = make_clienterror_exception(code="Unknown")
+
+ with pytest.raises(AnsibleError):
+ inventory._get_broker_hosts(connection=connection, strict=False)(paginate.build_full_result)
+
+ m_add_details_to_hosts.assert_not_called()
+
+
+FIND_HOSTS_MATCHING_STATUSES = (
+ "ansible_collections.community.aws.plugins.inventory.aws_mq._find_hosts_matching_statuses"
+)
+
+
+@pytest.mark.parametrize("regions", range(1, 5))
+@patch(FIND_HOSTS_MATCHING_STATUSES)
+def test_inventory_get_all_hosts(m_find_hosts, inventory, regions):
+ params = {
+ "regions": [f"us-east-{int(i)}" for i in range(regions)],
+ "strict": random.choice((True, False)),
+ "statuses": [
+ random.choice(
+ [
+ "RUNNING",
+ "CREATION_IN_PROGRESS",
+ "REBOOT_IN_PROGRESS",
+ "DELETION_IN_PROGRESS",
+ "CRITICAL_ACTION_REQUIRED",
+ ]
+ )
+ for i in range(3)
+ ],
+ }
+
+ connections = [MagicMock() for i in range(regions)]
+
+ inventory.all_clients.return_value = [(connections[i], f"us-east-{int(i)}") for i in range(regions)]
+
+ ids = list(reversed(range(regions)))
+ broker_hosts = [{"BrokerName": f"broker_00{int(i)}"} for i in ids]
+
+ inventory._get_broker_hosts = MagicMock()
+ inventory._get_broker_hosts._boto3_paginate_wrapper = MagicMock()
+ inventory._get_broker_hosts._boto3_paginate_wrapper.side_effect = [[i] for i in broker_hosts]
+ inventory._get_broker_hosts.return_value = inventory._get_broker_hosts._boto3_paginate_wrapper
+
+ result = list(sorted(broker_hosts, key=lambda x: x["BrokerName"]))
+
+ m_find_hosts.return_value = result
+
+ assert result == inventory._get_all_hosts(**params)
+ inventory.all_clients.assert_called_with("mq")
+ inventory._get_broker_hosts.assert_has_calls(
+ [call(connections[i], params["strict"]) for i in range(regions)], any_order=True
+ )
+
+ m_find_hosts.assert_called_with(result, params["statuses"])
+
+
+@pytest.mark.parametrize("hostvars_prefix", [True])
+@pytest.mark.parametrize("hostvars_suffix", [True])
+@patch("ansible_collections.community.aws.plugins.inventory.aws_mq._get_mq_hostname")
+def test_inventory_add_hosts(m_get_mq_hostname, inventory, hostvars_prefix, hostvars_suffix):
+ _options = {
+ "strict": random.choice((False, True)),
+ "compose": random.choice((False, True)),
+ "keyed_groups": "keyed_group_test_inventory_add_hosts",
+ "groups": ["all", "test_inventory_add_hosts"],
+ }
+
+ if hostvars_prefix:
+ _options["hostvars_prefix"] = f"prefix_{generate_random_string(length=8, with_punctuation=False)}"
+ if hostvars_suffix:
+ _options["hostvars_suffix"] = f"suffix_{generate_random_string(length=8, with_punctuation=False)}"
+
+ def _get_option_side_effect(x):
+ return _options.get(x)
+
+ inventory.get_option.side_effect = _get_option_side_effect
+
+ m_get_mq_hostname.side_effect = lambda h: h["BrokerName"]
+
+ hosts = [
+ {
+ "BrokerName": "broker_i_001",
+ "Tags": [{"Key": "Name", "Value": "broker_001"}, {"Key": "RunningEngine", "Value": "ActiveMQ"}],
+ "availability_zone": "us-east-1a",
+ },
+ {
+ "BrokerName": "broker_i_002",
+ "Tags": [{"Key": "ClusterName", "Value": "test_cluster"}, {"Key": "RunningOS", "Value": "CoreOS"}],
+ },
+ {
+ "BrokerName": "test_cluster",
+ "Tags": [{"Key": "CluserVersionOrigin", "Value": "2.0"}, {"Key": "Provider", "Value": "RedHat"}],
+ },
+ {
+ "BrokerName": "another_cluster",
+ "Tags": [{"Key": "TestingPurpose", "Value": "Ansible"}],
+ "availability_zones": ["us-west-1a", "us-east-1b"],
+ },
+ ]
+
+ group = f"test_add_hosts_group_{generate_random_string(length=10, with_punctuation=False)}"
+ inventory._add_hosts(hosts, group)
+
+ m_get_mq_hostname.assert_has_calls([call(h) for h in hosts], any_order=True)
+
+ hosts_names = ["broker_i_001", "broker_i_002", "test_cluster", "another_cluster"]
+ inventory.inventory.add_host.assert_has_calls([call(name, group=group) for name in hosts_names], any_order=True)
+
+ camel_hosts = [
+ {
+ "broker_name": "broker_i_001",
+ "tags": {"Name": "broker_001", "RunningEngine": "ActiveMQ"},
+ "availability_zone": "us-east-1a",
+ },
+ {"broker_name": "broker_i_002", "tags": {"ClusterName": "test_cluster", "RunningOS": "CoreOS"}},
+ {"broker_name": "test_cluster", "tags": {"CluserVersionOrigin": "2.0", "Provider": "RedHat"}},
+ {
+ "broker_name": "another_cluster",
+ "tags": {"TestingPurpose": "Ansible"},
+ "availability_zones": ["us-west-1a", "us-east-1b"],
+ },
+ ]
+
+ set_variable_calls = []
+ for i in range(len(camel_hosts)):
+ for var, value in camel_hosts[i].items():
+ if hostvars_prefix:
+ var = _options["hostvars_prefix"] + var
+ if hostvars_suffix:
+ var += _options["hostvars_suffix"]
+ set_variable_calls.append(call(hosts_names[i], var, value))
+
+ inventory.get_option.assert_has_calls([call("hostvars_prefix"), call("hostvars_suffix")])
+ inventory.inventory.set_variable.assert_has_calls(set_variable_calls)
+
+ if hostvars_prefix or hostvars_suffix:
+ tmp = []
+ for host in camel_hosts:
+ new_host = copy.deepcopy(host)
+ for key in host:
+ new_key = key
+ if hostvars_prefix:
+ new_key = _options["hostvars_prefix"] + new_key
+ if hostvars_suffix:
+ new_key += _options["hostvars_suffix"]
+ new_host[new_key] = host[key]
+ tmp.append(new_host)
+ camel_hosts = tmp
+
+ inventory._set_composite_vars.assert_has_calls(
+ [
+ call(_options["compose"], camel_hosts[i], hosts_names[i], strict=_options["strict"])
+ for i in range(len(camel_hosts))
+ ],
+ any_order=True,
+ )
+ inventory._add_host_to_composed_groups.assert_has_calls(
+ [
+ call(_options["groups"], camel_hosts[i], hosts_names[i], strict=_options["strict"])
+ for i in range(len(camel_hosts))
+ ],
+ any_order=True,
+ )
+ inventory._add_host_to_keyed_groups.assert_has_calls(
+ [
+ call(_options["keyed_groups"], camel_hosts[i], hosts_names[i], strict=_options["strict"])
+ for i in range(len(camel_hosts))
+ ],
+ any_order=True,
+ )
+
+
+BASE_INVENTORY_PARSE = "ansible_collections.community.aws.plugins.inventory.aws_mq.AWSInventoryBase.parse"
+
+
+@pytest.mark.parametrize("user_cache_directive", [True, False])
+@pytest.mark.parametrize("cache", [True, False])
+@pytest.mark.parametrize("cache_hit", [True, False])
+@patch(BASE_INVENTORY_PARSE)
+def test_inventory_parse(m_parse, inventory, user_cache_directive, cache, cache_hit):
+ inventory_data = MagicMock()
+ loader = MagicMock()
+ path = generate_random_string(with_punctuation=False, with_digits=False)
+
+ options = {}
+ options["regions"] = [f"us-east-{d}" for d in range(random.randint(1, 5))]
+ options["strict_permissions"] = random.choice((True, False))
+ options["statuses"] = generate_random_string(with_punctuation=False)
+
+ options["cache"] = user_cache_directive
+
+ def get_option_side_effect(v):
+ return options.get(v)
+
+ inventory.get_option.side_effect = get_option_side_effect
+
+ cache_key = path + generate_random_string()
+ inventory.get_cache_key.return_value = cache_key
+
+ cache_key_value = generate_random_string()
+ if cache_hit:
+ inventory._cache[cache_key] = cache_key_value
+
+ inventory._populate = MagicMock()
+ inventory._populate_from_cache = MagicMock()
+ inventory._get_all_hosts = MagicMock()
+ all_hosts = [
+ {"host": f"host_{int(random.randint(1, 1000))}"},
+ {"host": f"host_{int(random.randint(1, 1000))}"},
+ {"host": f"host_{int(random.randint(1, 1000))}"},
+ {"host": f"host_{int(random.randint(1, 1000))}"},
+ ]
+ inventory._get_all_hosts.return_value = all_hosts
+
+ format_cache_key_value = f"format_inventory_{all_hosts}"
+ inventory._format_inventory = MagicMock()
+ inventory._format_inventory.return_value = format_cache_key_value
+
+ inventory.parse(inventory_data, loader, path, cache)
+
+ m_parse.assert_called_with(inventory_data, loader, path, cache=cache)
+
+ if not cache or not user_cache_directive or (cache and user_cache_directive and not cache_hit):
+ inventory._get_all_hosts.assert_called_with(
+ options["regions"],
+ options["strict_permissions"],
+ options["statuses"],
+ )
+ inventory._populate.assert_called_with(all_hosts)
+ inventory._format_inventory.assert_called_with(all_hosts)
+ else:
+ inventory._get_all_hosts.assert_not_called()
+
+ if cache and user_cache_directive and cache_hit:
+ inventory._populate_from_cache.assert_called_with(cache_key_value)
+
+ if cache and user_cache_directive and not cache_hit or (not cache and user_cache_directive):
+ # validate that cache was populated
+ assert inventory._cache[cache_key] == format_cache_key_value
diff --git a/ansible_collections/community/aws/tests/unit/plugins/modules/conftest.py b/ansible_collections/community/aws/tests/unit/plugins/modules/conftest.py
index a7d1e0475..ba4a1adc3 100644
--- a/ansible_collections/community/aws/tests/unit/plugins/modules/conftest.py
+++ b/ansible_collections/community/aws/tests/unit/plugins/modules/conftest.py
@@ -1,16 +1,14 @@
# Copyright (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
import json
import pytest
-from ansible.module_utils.six import string_types
from ansible.module_utils._text import to_bytes
from ansible.module_utils.common._collections_compat import MutableMapping
+from ansible.module_utils.six import string_types
@pytest.fixture
@@ -18,14 +16,14 @@ def patch_ansible_module(request, mocker):
if isinstance(request.param, string_types):
args = request.param
elif isinstance(request.param, MutableMapping):
- if 'ANSIBLE_MODULE_ARGS' not in request.param:
- request.param = {'ANSIBLE_MODULE_ARGS': request.param}
- if '_ansible_remote_tmp' not in request.param['ANSIBLE_MODULE_ARGS']:
- request.param['ANSIBLE_MODULE_ARGS']['_ansible_remote_tmp'] = '/tmp'
- if '_ansible_keep_remote_files' not in request.param['ANSIBLE_MODULE_ARGS']:
- request.param['ANSIBLE_MODULE_ARGS']['_ansible_keep_remote_files'] = False
+ if "ANSIBLE_MODULE_ARGS" not in request.param:
+ request.param = {"ANSIBLE_MODULE_ARGS": request.param}
+ if "_ansible_remote_tmp" not in request.param["ANSIBLE_MODULE_ARGS"]:
+ request.param["ANSIBLE_MODULE_ARGS"]["_ansible_remote_tmp"] = "/tmp"
+ if "_ansible_keep_remote_files" not in request.param["ANSIBLE_MODULE_ARGS"]:
+ request.param["ANSIBLE_MODULE_ARGS"]["_ansible_keep_remote_files"] = False
args = json.dumps(request.param)
else:
- raise Exception('Malformed data to the patch_ansible_module pytest fixture')
+ raise Exception("Malformed data to the patch_ansible_module pytest fixture")
- mocker.patch('ansible.module_utils.basic._ANSIBLE_ARGS', to_bytes(args))
+ mocker.patch("ansible.module_utils.basic._ANSIBLE_ARGS", to_bytes(args))
diff --git a/ansible_collections/community/aws/tests/unit/plugins/modules/test_acm_certificate.py b/ansible_collections/community/aws/tests/unit/plugins/modules/test_acm_certificate.py
index 726601fe8..608246217 100644
--- a/ansible_collections/community/aws/tests/unit/plugins/modules/test_acm_certificate.py
+++ b/ansible_collections/community/aws/tests/unit/plugins/modules/test_acm_certificate.py
@@ -15,18 +15,21 @@
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
__metaclass__ = type
from pprint import pprint
+from ansible.module_utils._text import to_text
+
from ansible_collections.community.aws.plugins.modules.acm_certificate import chain_compare
from ansible_collections.community.aws.plugins.modules.acm_certificate import pem_chain_split
-from ansible.module_utils._text import to_text
def test_chain_compare():
-
# The functions we're testing take module as an argument
# Just so they can call module.fail_json
# Let's just use None for the unit tests,
@@ -34,14 +37,14 @@ def test_chain_compare():
# And if they do, fail_json is not applicable
module = None
- fixture_suffix = 'tests/unit/plugins/modules/fixtures/certs'
+ fixture_suffix = "tests/unit/plugins/modules/fixtures/certs"
# Test chain split function on super simple (invalid) certs
- expected = ['aaa', 'bbb', 'ccc']
+ expected = ["aaa", "bbb", "ccc"]
- for fname in ['simple-chain-a.cert', 'simple-chain-b.cert']:
- path = fixture_suffix + '/' + fname
- with open(path, 'r') as f:
+ for fname in ["simple-chain-a.cert", "simple-chain-b.cert"]:
+ path = fixture_suffix + "/" + fname
+ with open(path, "r") as f:
pem = to_text(f.read())
actual = pem_chain_split(module, pem)
actual = [a.strip() for a in actual]
@@ -50,76 +53,60 @@ def test_chain_compare():
pprint(expected)
print("Actual:")
pprint(actual)
- raise AssertionError("Failed to properly split %s" % fname)
+ raise AssertionError(f"Failed to properly split {fname}")
# Now test real chains
# chains with same same_as should be considered equal
test_chains = [
- { # Original Cert chain
- 'path': fixture_suffix + '/chain-1.0.cert',
- 'same_as': 1,
- 'length': 3
- },
- { # Same as 1.0, but longer PEM lines
- 'path': fixture_suffix + '/chain-1.1.cert',
- 'same_as': 1,
- 'length': 3
- },
+ {"path": fixture_suffix + "/chain-1.0.cert", "same_as": 1, "length": 3}, # Original Cert chain
+ {"path": fixture_suffix + "/chain-1.1.cert", "same_as": 1, "length": 3}, # Same as 1.0, but longer PEM lines
{ # Same as 1.0, but without the stuff before each --------
- 'path': fixture_suffix + '/chain-1.2.cert',
- 'same_as': 1,
- 'length': 3
+ "path": fixture_suffix + "/chain-1.2.cert",
+ "same_as": 1,
+ "length": 3,
},
{ # Same as 1.0, but in a different order, so should be considered different
- 'path': fixture_suffix + '/chain-1.3.cert',
- 'same_as': 2,
- 'length': 3
+ "path": fixture_suffix + "/chain-1.3.cert",
+ "same_as": 2,
+ "length": 3,
},
{ # Same as 1.0, but with last link missing
- 'path': fixture_suffix + '/chain-1.4.cert',
- 'same_as': 3,
- 'length': 2
+ "path": fixture_suffix + "/chain-1.4.cert",
+ "same_as": 3,
+ "length": 2,
},
{ # Completely different cert chain to all the others
- 'path': fixture_suffix + '/chain-4.cert',
- 'same_as': 4,
- 'length': 3
- },
- { # Single cert
- 'path': fixture_suffix + '/a.pem',
- 'same_as': 5,
- 'length': 1
+ "path": fixture_suffix + "/chain-4.cert",
+ "same_as": 4,
+ "length": 3,
},
- { # a different, single cert
- 'path': fixture_suffix + '/b.pem',
- 'same_as': 6,
- 'length': 1
- }
+ {"path": fixture_suffix + "/a.pem", "same_as": 5, "length": 1}, # Single cert
+ {"path": fixture_suffix + "/b.pem", "same_as": 6, "length": 1}, # a different, single cert
]
for chain in test_chains:
- with open(chain['path'], 'r') as f:
- chain['pem_text'] = to_text(f.read())
+ with open(chain["path"], "r") as f:
+ chain["pem_text"] = to_text(f.read())
# Test to make sure our regex isn't too greedy
- chain['split'] = pem_chain_split(module, chain['pem_text'])
- if len(chain['split']) != chain['length']:
+ chain["split"] = pem_chain_split(module, chain["pem_text"])
+ if len(chain["split"]) != chain["length"]:
print("Cert before split")
- print(chain['pem_text'])
+ print(chain["pem_text"])
print("Cert after split")
- pprint(chain['split'])
- print("path: %s" % chain['path'])
- print("Expected chain length: %d" % chain['length'])
- print("Actual chain length: %d" % len(chain['split']))
- raise AssertionError("Chain %s was not split properly" % chain['path'])
+ pprint(chain["split"])
+ print(f"path: {chain['path']}")
+ print(f"Expected chain length: {int(chain['length'])}")
+ print(f"Actual chain length: {len(chain['split'])}")
+ raise AssertionError(f"Chain {chain['path']} was not split properly")
for chain_a in test_chains:
for chain_b in test_chains:
- expected = (chain_a['same_as'] == chain_b['same_as'])
+ expected = chain_a["same_as"] == chain_b["same_as"]
# Now test the comparison function
- actual = chain_compare(module, chain_a['pem_text'], chain_b['pem_text'])
+ actual = chain_compare(module, chain_a["pem_text"], chain_b["pem_text"])
if expected != actual:
- print("Error, unexpected comparison result between \n%s\nand\n%s" % (chain_a['path'], chain_b['path']))
- print("Expected %s got %s" % (str(expected), str(actual)))
+ print(f"Error, unexpected comparison result between \n{chain_a['path']}\nand\n{chain_b['path']}")
+ print(f"Expected {str(expected)} got {str(actual)}")
assert expected == actual
diff --git a/ansible_collections/community/aws/tests/unit/plugins/modules/test_api_gateway.py b/ansible_collections/community/aws/tests/unit/plugins/modules/test_api_gateway.py
index a6f2c3e91..f0d9de8fa 100644
--- a/ansible_collections/community/aws/tests/unit/plugins/modules/test_api_gateway.py
+++ b/ansible_collections/community/aws/tests/unit/plugins/modules/test_api_gateway.py
@@ -5,17 +5,21 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
__metaclass__ = type
import sys
+
import pytest
from ansible_collections.amazon.aws.plugins.module_utils import modules as aws_modules
from ansible_collections.amazon.aws.plugins.module_utils.botocore import HAS_BOTO3
-from ansible_collections.community.aws.tests.unit.plugins.modules.utils import set_module_args
import ansible_collections.community.aws.plugins.modules.api_gateway as agw
+from ansible_collections.community.aws.tests.unit.plugins.modules.utils import set_module_args
if not HAS_BOTO3:
pytestmark = pytest.mark.skip("test_api_gateway.py requires the `boto3` and `botocore` modules")
@@ -25,7 +29,7 @@ exit_return_dict = {}
def fake_exit_json(self, **kwargs):
- """ store the kwargs given to exit_json rather than putting them out to stdout"""
+ """store the kwargs given to exit_json rather than putting them out to stdout"""
global exit_return_dict
exit_return_dict = kwargs
sys.exit(0)
@@ -33,7 +37,6 @@ def fake_exit_json(self, **kwargs):
def test_upload_api(monkeypatch):
class FakeConnection:
-
def put_rest_api(self, *args, **kwargs):
assert kwargs["body"] == "the-swagger-text-is-fake"
return {"msg": "success!"}
@@ -46,25 +49,29 @@ def test_upload_api(monkeypatch):
monkeypatch.setattr(aws_modules, "boto3_conn", return_fake_connection)
monkeypatch.setattr(aws_modules.AnsibleAWSModule, "exit_json", fake_exit_json)
- set_module_args({
- "api_id": "fred",
- "state": "present",
- "swagger_text": "the-swagger-text-is-fake",
- "region": 'mars-north-1',
- "_ansible_tmpdir": "/tmp/ansibl-abcdef",
- })
+ set_module_args(
+ {
+ "api_id": "fred",
+ "state": "present",
+ "swagger_text": "the-swagger-text-is-fake",
+ "region": "mars-north-1",
+ "_ansible_tmpdir": "/tmp/ansibl-abcdef",
+ }
+ )
with pytest.raises(SystemExit):
agw.main()
assert exit_return_dict["changed"]
def test_warn_if_region_not_specified():
-
- set_module_args({
- "name": "api_gateway",
- "state": "present",
- "runtime": 'python2.7',
- "role": 'arn:aws:iam::123456789012:role/lambda_basic_execution',
- "handler": 'lambda_python.my_handler'})
+ set_module_args(
+ {
+ "name": "api_gateway",
+ "state": "present",
+ "runtime": "python2.7",
+ "role": "arn:aws:iam::123456789012:role/lambda_basic_execution",
+ "handler": "lambda_python.my_handler",
+ }
+ )
with pytest.raises(SystemExit):
print(agw.main())
diff --git a/ansible_collections/community/aws/tests/unit/plugins/modules/test_data_pipeline.py b/ansible_collections/community/aws/tests/unit/plugins/modules/test_data_pipeline.py
index 1a188e8ed..a2bd06ad8 100644
--- a/ansible_collections/community/aws/tests/unit/plugins/modules/test_data_pipeline.py
+++ b/ansible_collections/community/aws/tests/unit/plugins/modules/test_data_pipeline.py
@@ -4,12 +4,16 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
__metaclass__ = type
import collections
-import os
import json
+import os
+
import pytest
from ansible.module_utils._text import to_text
@@ -19,11 +23,18 @@ try:
except ImportError:
pass
+from ansible_collections.amazon.aws.plugins.module_utils.botocore import HAS_BOTO3
+
# Magic... Incorrectly identified by pylint as unused
-from ansible_collections.amazon.aws.tests.unit.utils.amazon_placebo_fixtures import maybe_sleep # pylint: disable=unused-import
-from ansible_collections.amazon.aws.tests.unit.utils.amazon_placebo_fixtures import placeboify # pylint: disable=unused-import
+# isort: off
+# pylint: disable=unused-import
+
+from ansible_collections.amazon.aws.tests.unit.utils.amazon_placebo_fixtures import maybe_sleep
+from ansible_collections.amazon.aws.tests.unit.utils.amazon_placebo_fixtures import placeboify
+
+# pylint: enable=unused-import
+# isort: on
-from ansible_collections.amazon.aws.plugins.module_utils.botocore import HAS_BOTO3
from ansible_collections.community.aws.plugins.modules import data_pipeline
if not HAS_BOTO3:
@@ -34,7 +45,7 @@ class FailException(Exception):
pass
-@pytest.fixture(scope='module')
+@pytest.fixture(scope="module")
def dp_setup():
"""
Yield a FakeModule object, data pipeline id of a vanilla data pipeline, and data pipeline objects
@@ -44,41 +55,41 @@ def dp_setup():
Dependencies = collections.namedtuple("Dependencies", ["module", "data_pipeline_id", "objects"])
# get objects to use to test populating and activating the data pipeline
- if not os.getenv('PLACEBO_RECORD'):
- objects = [{"name": "Every 1 day",
- "id": "DefaultSchedule",
- "fields": []},
- {"name": "Default",
- "id": "Default",
- "fields": []}]
+ if not os.getenv("PLACEBO_RECORD"):
+ objects = [
+ {"name": "Every 1 day", "id": "DefaultSchedule", "fields": []},
+ {"name": "Default", "id": "Default", "fields": []},
+ ]
else:
- s3 = boto3.client('s3')
+ s3 = boto3.client("s3")
data = s3.get_object(Bucket="ansible-test-datapipeline", Key="pipeline-object/new.json")
- objects = json.loads(to_text(data['Body'].read()))
+ objects = json.loads(to_text(data["Body"].read()))
# create a module with vanilla data pipeline parameters
- params = {'name': 'ansible-test-create-pipeline',
- 'description': 'ansible-datapipeline-unit-test',
- 'state': 'present',
- 'timeout': 300,
- 'objects': [],
- 'tags': {},
- 'parameters': [],
- 'values': []}
+ params = {
+ "name": "ansible-test-create-pipeline",
+ "description": "ansible-datapipeline-unit-test",
+ "state": "present",
+ "timeout": 300,
+ "objects": [],
+ "tags": {},
+ "parameters": [],
+ "values": [],
+ }
module = FakeModule(**params)
# yield a module, the data pipeline id, and the data pipeline objects (that are not yet defining the vanilla data pipeline)
- if not os.getenv('PLACEBO_RECORD'):
- yield Dependencies(module=module, data_pipeline_id='df-0590406117G8DPQZY2HA', objects=objects)
+ if not os.getenv("PLACEBO_RECORD"):
+ yield Dependencies(module=module, data_pipeline_id="df-0590406117G8DPQZY2HA", objects=objects)
else:
- connection = boto3.client('datapipeline')
+ connection = boto3.client("datapipeline")
_changed, result = data_pipeline.create_pipeline(connection, module)
- data_pipeline_id = result['data_pipeline']['pipeline_id']
+ data_pipeline_id = result["data_pipeline"]["pipeline_id"]
yield Dependencies(module=module, data_pipeline_id=data_pipeline_id, objects=objects)
# remove data pipeline
- if os.getenv('PLACEBO_RECORD'):
- module.params.update(state='absent')
+ if os.getenv("PLACEBO_RECORD"):
+ module.params.update(state="absent")
data_pipeline.delete_pipeline(connection, module)
@@ -89,7 +100,7 @@ class FakeModule(object):
def fail_json(self, *args, **kwargs):
self.exit_args = args
self.exit_kwargs = kwargs
- raise FailException('FAIL')
+ raise FailException("FAIL")
def exit_json(self, *args, **kwargs):
self.exit_args = args
@@ -97,91 +108,101 @@ class FakeModule(object):
def test_create_pipeline_already_exists(placeboify, maybe_sleep, dp_setup):
- connection = placeboify.client('datapipeline')
+ connection = placeboify.client("datapipeline")
changed, result = data_pipeline.create_pipeline(connection, dp_setup.module)
assert changed is False
- assert "Data Pipeline ansible-test-create-pipeline is present" in result['msg']
+ assert "Data Pipeline ansible-test-create-pipeline is present" in result["msg"]
def test_pipeline_field(placeboify, maybe_sleep, dp_setup):
- connection = placeboify.client('datapipeline')
+ connection = placeboify.client("datapipeline")
pipeline_field_info = data_pipeline.pipeline_field(connection, dp_setup.data_pipeline_id, "@pipelineState")
assert pipeline_field_info == "PENDING"
def test_define_pipeline(placeboify, maybe_sleep, dp_setup):
- connection = placeboify.client('datapipeline')
- changed, result = data_pipeline.define_pipeline(connection, dp_setup.module, dp_setup.objects, dp_setup.data_pipeline_id)
+ connection = placeboify.client("datapipeline")
+ changed, result = data_pipeline.define_pipeline(
+ connection, dp_setup.module, dp_setup.objects, dp_setup.data_pipeline_id
+ )
assert changed is True
- assert 'has been updated' in result
+ assert "has been updated" in result
def test_deactivate_pipeline(placeboify, maybe_sleep, dp_setup):
- connection = placeboify.client('datapipeline')
+ connection = placeboify.client("datapipeline")
_changed, result = data_pipeline.deactivate_pipeline(connection, dp_setup.module)
# XXX possible bug
# assert changed is True
- assert "Data Pipeline ansible-test-create-pipeline deactivated" in result['msg']
+ assert "Data Pipeline ansible-test-create-pipeline deactivated" in result["msg"]
def test_activate_without_population(placeboify, maybe_sleep, dp_setup):
- connection = placeboify.client('datapipeline')
+ connection = placeboify.client("datapipeline")
with pytest.raises(FailException):
_changed, _result = data_pipeline.activate_pipeline(connection, dp_setup.module)
- assert dp_setup.module.exit_kwargs.get('msg') == "You need to populate your pipeline before activation."
+ assert dp_setup.module.exit_kwargs.get("msg") == "You need to populate your pipeline before activation."
def test_create_pipeline(placeboify, maybe_sleep):
- connection = placeboify.client('datapipeline')
- params = {'name': 'ansible-unittest-create-pipeline',
- 'description': 'ansible-datapipeline-unit-test',
- 'state': 'present',
- 'timeout': 300,
- 'tags': {}}
+ connection = placeboify.client("datapipeline")
+ params = {
+ "name": "ansible-unittest-create-pipeline",
+ "description": "ansible-datapipeline-unit-test",
+ "state": "present",
+ "timeout": 300,
+ "tags": {},
+ }
m = FakeModule(**params)
changed, result = data_pipeline.create_pipeline(connection, m)
assert changed is True
- assert result['msg'] == "Data Pipeline ansible-unittest-create-pipeline created."
+ assert result["msg"] == "Data Pipeline ansible-unittest-create-pipeline created."
data_pipeline.delete_pipeline(connection, m)
def test_create_pipeline_with_tags(placeboify, maybe_sleep):
- connection = placeboify.client('datapipeline')
- params = {'name': 'ansible-unittest-create-pipeline_tags',
- 'description': 'ansible-datapipeline-unit-test',
- 'state': 'present',
- 'tags': {'ansible': 'test'},
- 'timeout': 300}
+ connection = placeboify.client("datapipeline")
+ params = {
+ "name": "ansible-unittest-create-pipeline_tags",
+ "description": "ansible-datapipeline-unit-test",
+ "state": "present",
+ "tags": {"ansible": "test"},
+ "timeout": 300,
+ }
m = FakeModule(**params)
changed, result = data_pipeline.create_pipeline(connection, m)
assert changed is True
- assert result['msg'] == "Data Pipeline ansible-unittest-create-pipeline_tags created."
+ assert result["msg"] == "Data Pipeline ansible-unittest-create-pipeline_tags created."
data_pipeline.delete_pipeline(connection, m)
def test_delete_nonexistent_pipeline(placeboify, maybe_sleep):
- connection = placeboify.client('datapipeline')
- params = {'name': 'ansible-test-nonexistent',
- 'description': 'ansible-test-nonexistent',
- 'state': 'absent',
- 'objects': [],
- 'tags': {'ansible': 'test'},
- 'timeout': 300}
+ connection = placeboify.client("datapipeline")
+ params = {
+ "name": "ansible-test-nonexistent",
+ "description": "ansible-test-nonexistent",
+ "state": "absent",
+ "objects": [],
+ "tags": {"ansible": "test"},
+ "timeout": 300,
+ }
m = FakeModule(**params)
changed, _result = data_pipeline.delete_pipeline(connection, m)
assert changed is False
def test_delete_pipeline(placeboify, maybe_sleep):
- connection = placeboify.client('datapipeline')
- params = {'name': 'ansible-test-nonexistent',
- 'description': 'ansible-test-nonexistent',
- 'state': 'absent',
- 'objects': [],
- 'tags': {'ansible': 'test'},
- 'timeout': 300}
+ connection = placeboify.client("datapipeline")
+ params = {
+ "name": "ansible-test-nonexistent",
+ "description": "ansible-test-nonexistent",
+ "state": "absent",
+ "objects": [],
+ "tags": {"ansible": "test"},
+ "timeout": 300,
+ }
m = FakeModule(**params)
data_pipeline.create_pipeline(connection, m)
changed, _result = data_pipeline.delete_pipeline(connection, m)
@@ -189,29 +210,29 @@ def test_delete_pipeline(placeboify, maybe_sleep):
def test_build_unique_id_different():
- m = FakeModule(**{'name': 'ansible-unittest-1', 'description': 'test-unique-id'})
- m2 = FakeModule(**{'name': 'ansible-unittest-1', 'description': 'test-unique-id-different'})
+ m = FakeModule(**{"name": "ansible-unittest-1", "description": "test-unique-id"})
+ m2 = FakeModule(**{"name": "ansible-unittest-1", "description": "test-unique-id-different"})
assert data_pipeline.build_unique_id(m) != data_pipeline.build_unique_id(m2)
def test_build_unique_id_same():
- m = FakeModule(**{'name': 'ansible-unittest-1', 'description': 'test-unique-id', 'tags': {'ansible': 'test'}})
- m2 = FakeModule(**{'name': 'ansible-unittest-1', 'description': 'test-unique-id', 'tags': {'ansible': 'test'}})
+ m = FakeModule(**{"name": "ansible-unittest-1", "description": "test-unique-id", "tags": {"ansible": "test"}})
+ m2 = FakeModule(**{"name": "ansible-unittest-1", "description": "test-unique-id", "tags": {"ansible": "test"}})
assert data_pipeline.build_unique_id(m) == data_pipeline.build_unique_id(m2)
def test_build_unique_id_obj():
# check that the object can be different and the unique id should be the same; should be able to modify objects
- m = FakeModule(**{'name': 'ansible-unittest-1', 'objects': [{'first': 'object'}]})
- m2 = FakeModule(**{'name': 'ansible-unittest-1', 'objects': [{'second': 'object'}]})
+ m = FakeModule(**{"name": "ansible-unittest-1", "objects": [{"first": "object"}]})
+ m2 = FakeModule(**{"name": "ansible-unittest-1", "objects": [{"second": "object"}]})
assert data_pipeline.build_unique_id(m) == data_pipeline.build_unique_id(m2)
def test_format_tags():
- unformatted_tags = {'key1': 'val1', 'key2': 'val2', 'key3': 'val3'}
+ unformatted_tags = {"key1": "val1", "key2": "val2", "key3": "val3"}
formatted_tags = data_pipeline.format_tags(unformatted_tags)
for tag_set in formatted_tags:
- assert unformatted_tags[tag_set['key']] == tag_set['value']
+ assert unformatted_tags[tag_set["key"]] == tag_set["value"]
def test_format_empty_tags():
@@ -221,45 +242,44 @@ def test_format_empty_tags():
def test_pipeline_description(placeboify, maybe_sleep, dp_setup):
- connection = placeboify.client('datapipeline')
+ connection = placeboify.client("datapipeline")
dp_id = dp_setup.data_pipeline_id
pipelines = data_pipeline.pipeline_description(connection, dp_id)
- assert dp_id == pipelines['pipelineDescriptionList'][0]['pipelineId']
+ assert dp_id == pipelines["pipelineDescriptionList"][0]["pipelineId"]
def test_pipeline_description_nonexistent(placeboify, maybe_sleep):
hypothetical_pipeline_id = "df-015440025PF7YGLDK47C"
- connection = placeboify.client('datapipeline')
+ connection = placeboify.client("datapipeline")
with pytest.raises(data_pipeline.DataPipelineNotFound):
data_pipeline.pipeline_description(connection, hypothetical_pipeline_id)
def test_check_dp_exists_true(placeboify, maybe_sleep, dp_setup):
- connection = placeboify.client('datapipeline')
+ connection = placeboify.client("datapipeline")
exists = data_pipeline.check_dp_exists(connection, dp_setup.data_pipeline_id)
assert exists is True
def test_check_dp_exists_false(placeboify, maybe_sleep):
hypothetical_pipeline_id = "df-015440025PF7YGLDK47C"
- connection = placeboify.client('datapipeline')
+ connection = placeboify.client("datapipeline")
exists = data_pipeline.check_dp_exists(connection, hypothetical_pipeline_id)
assert exists is False
def test_check_dp_status(placeboify, maybe_sleep, dp_setup):
- inactive_states = ['INACTIVE', 'PENDING', 'FINISHED', 'DELETING']
- connection = placeboify.client('datapipeline')
+ inactive_states = ["INACTIVE", "PENDING", "FINISHED", "DELETING"]
+ connection = placeboify.client("datapipeline")
state = data_pipeline.check_dp_status(connection, dp_setup.data_pipeline_id, inactive_states)
assert state is True
def test_activate_pipeline(placeboify, maybe_sleep, dp_setup):
# use objects to define pipeline before activating
- connection = placeboify.client('datapipeline')
- data_pipeline.define_pipeline(connection,
- module=dp_setup.module,
- objects=dp_setup.objects,
- dp_id=dp_setup.data_pipeline_id)
+ connection = placeboify.client("datapipeline")
+ data_pipeline.define_pipeline(
+ connection, module=dp_setup.module, objects=dp_setup.objects, dp_id=dp_setup.data_pipeline_id
+ )
changed, _result = data_pipeline.activate_pipeline(connection, dp_setup.module)
assert changed is True
diff --git a/ansible_collections/community/aws/tests/unit/plugins/modules/test_directconnect_confirm_connection.py b/ansible_collections/community/aws/tests/unit/plugins/modules/test_directconnect_confirm_connection.py
index 63804415d..f65648dad 100644
--- a/ansible_collections/community/aws/tests/unit/plugins/modules/test_directconnect_confirm_connection.py
+++ b/ansible_collections/community/aws/tests/unit/plugins/modules/test_directconnect_confirm_connection.py
@@ -1,28 +1,30 @@
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from unittest.mock import call
+from unittest.mock import patch
import pytest
+
try:
from botocore.exceptions import ClientError
except ImportError:
pass
from ansible_collections.amazon.aws.plugins.module_utils.botocore import HAS_BOTO3
-from ansible_collections.community.aws.tests.unit.compat.mock import call
-from ansible_collections.community.aws.tests.unit.compat.mock import patch
+
+from ansible_collections.community.aws.plugins.modules import directconnect_confirm_connection
from ansible_collections.community.aws.tests.unit.plugins.modules.utils import AnsibleExitJson
from ansible_collections.community.aws.tests.unit.plugins.modules.utils import AnsibleFailJson
from ansible_collections.community.aws.tests.unit.plugins.modules.utils import ModuleTestCase
from ansible_collections.community.aws.tests.unit.plugins.modules.utils import set_module_args
-from ansible_collections.community.aws.plugins.modules import directconnect_confirm_connection
-
if not HAS_BOTO3:
- pytestmark = pytest.mark.skip("test_directconnect_confirm_connection.py requires the `boto3` and `botocore` modules")
+ pytestmark = pytest.mark.skip(
+ "test_directconnect_confirm_connection.py requires the `boto3` and `botocore` modules"
+ )
-@patch('ansible_collections.amazon.aws.plugins.module_utils.core.HAS_BOTO3', new=True)
+@patch("ansible_collections.amazon.aws.plugins.module_utils.core.HAS_BOTO3", new=True)
@patch.object(directconnect_confirm_connection.AnsibleAWSModule, "client")
class TestAWSDirectConnectConfirmConnection(ModuleTestCase):
def test_missing_required_parameters(self, *args):
@@ -45,22 +47,18 @@ class TestAWSDirectConnectConfirmConnection(ModuleTestCase):
"connectionName": "ansible-test-connection",
"bandwidth": "1Gbps",
"ownerAccount": "123456789012",
- "region": "us-west-2"
+ "region": "us-west-2",
}
]
}
- set_module_args({
- "connection_id": "dxcon-fgq9rgot"
- })
+ set_module_args({"connection_id": "dxcon-fgq9rgot"})
with self.assertRaises(AnsibleExitJson) as exec_info:
directconnect_confirm_connection.main()
result = exec_info.exception.args[0]
assert result["changed"] is False
assert result["connection_state"] == "requested"
- mock_client.return_value.describe_connections.assert_has_calls([
- call(connectionId="dxcon-fgq9rgot")
- ])
+ mock_client.return_value.describe_connections.assert_has_calls([call(connectionId="dxcon-fgq9rgot")])
mock_client.return_value.confirm_connection.assert_not_called()
def test_get_by_name(self, mock_client):
@@ -73,39 +71,31 @@ class TestAWSDirectConnectConfirmConnection(ModuleTestCase):
"connectionName": "ansible-test-connection",
"bandwidth": "1Gbps",
"ownerAccount": "123456789012",
- "region": "us-west-2"
+ "region": "us-west-2",
}
]
}
- set_module_args({
- "name": "ansible-test-connection"
- })
+ set_module_args({"name": "ansible-test-connection"})
with self.assertRaises(AnsibleExitJson) as exec_info:
directconnect_confirm_connection.main()
result = exec_info.exception.args[0]
assert result["changed"] is False
assert result["connection_state"] == "requested"
- mock_client.return_value.describe_connections.assert_has_calls([
- call(),
- call(connectionId="dxcon-fgq9rgot")
- ])
+ mock_client.return_value.describe_connections.assert_has_calls([call(), call(connectionId="dxcon-fgq9rgot")])
mock_client.return_value.confirm_connection.assert_not_called()
def test_missing_connection_id(self, mock_client):
mock_client.return_value.describe_connections.side_effect = ClientError(
- {'Error': {'Code': 'ResourceNotFoundException'}}, 'DescribeConnection')
- set_module_args({
- "connection_id": "dxcon-aaaabbbb"
- })
+ {"Error": {"Code": "ResourceNotFoundException"}}, "DescribeConnection"
+ )
+ set_module_args({"connection_id": "dxcon-aaaabbbb"})
with self.assertRaises(AnsibleFailJson) as exec_info:
directconnect_confirm_connection.main()
result = exec_info.exception.args[0]
assert result["failed"] is True
- mock_client.return_value.describe_connections.assert_has_calls([
- call(connectionId="dxcon-aaaabbbb")
- ])
+ mock_client.return_value.describe_connections.assert_has_calls([call(connectionId="dxcon-aaaabbbb")])
def test_missing_name(self, mock_client):
mock_client.return_value.describe_connections.return_value = {
@@ -117,21 +107,17 @@ class TestAWSDirectConnectConfirmConnection(ModuleTestCase):
"connectionName": "ansible-test-connection",
"bandwidth": "1Gbps",
"ownerAccount": "123456789012",
- "region": "us-west-2"
+ "region": "us-west-2",
}
]
}
- set_module_args({
- "name": "foobar"
- })
+ set_module_args({"name": "foobar"})
with self.assertRaises(AnsibleFailJson) as exec_info:
directconnect_confirm_connection.main()
result = exec_info.exception.args[0]
assert result["failed"] is True
- mock_client.return_value.describe_connections.assert_has_calls([
- call()
- ])
+ mock_client.return_value.describe_connections.assert_has_calls([call()])
def test_confirm(self, mock_client):
mock_client.return_value.describe_connections.return_value = {
@@ -143,22 +129,22 @@ class TestAWSDirectConnectConfirmConnection(ModuleTestCase):
"connectionName": "ansible-test-connection",
"bandwidth": "1Gbps",
"ownerAccount": "123456789012",
- "region": "us-west-2"
+ "region": "us-west-2",
}
]
}
mock_client.return_value.confirm_connection.return_value = [{}]
- set_module_args({
- "connection_id": "dxcon-fgq9rgot"
- })
+ set_module_args({"connection_id": "dxcon-fgq9rgot"})
with self.assertRaises(AnsibleExitJson) as exec_info:
directconnect_confirm_connection.main()
result = exec_info.exception.args[0]
assert result["changed"] is True
- mock_client.return_value.describe_connections.assert_has_calls([
- call(connectionId="dxcon-fgq9rgot"),
- call(connectionId="dxcon-fgq9rgot"),
- call(connectionId="dxcon-fgq9rgot")
- ])
+ mock_client.return_value.describe_connections.assert_has_calls(
+ [
+ call(connectionId="dxcon-fgq9rgot"),
+ call(connectionId="dxcon-fgq9rgot"),
+ call(connectionId="dxcon-fgq9rgot"),
+ ]
+ )
mock_client.return_value.confirm_connection.assert_called_once_with(connectionId="dxcon-fgq9rgot")
diff --git a/ansible_collections/community/aws/tests/unit/plugins/modules/test_directconnect_connection.py b/ansible_collections/community/aws/tests/unit/plugins/modules/test_directconnect_connection.py
index 65ba0a3f0..f9a620843 100644
--- a/ansible_collections/community/aws/tests/unit/plugins/modules/test_directconnect_connection.py
+++ b/ansible_collections/community/aws/tests/unit/plugins/modules/test_directconnect_connection.py
@@ -4,81 +4,90 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
__metaclass__ = type
import pytest
from ansible_collections.amazon.aws.plugins.module_utils.botocore import HAS_BOTO3
+
# Magic... Incorrectly identified by pylint as unused
-from ansible_collections.amazon.aws.tests.unit.utils.amazon_placebo_fixtures import maybe_sleep # pylint: disable=unused-import
-from ansible_collections.amazon.aws.tests.unit.utils.amazon_placebo_fixtures import placeboify # pylint: disable=unused-import
+# isort: off
+# pylint: disable=unused-import
+from ansible_collections.amazon.aws.tests.unit.utils.amazon_placebo_fixtures import maybe_sleep
+from ansible_collections.amazon.aws.tests.unit.utils.amazon_placebo_fixtures import placeboify
+
+# pylint: enable=unused-import
+# isort: on
from ansible_collections.community.aws.plugins.modules import directconnect_connection
if not HAS_BOTO3:
- pytestmark = pytest.mark.skip("test_directconnect_confirm_connection.py requires the `boto3` and `botocore` modules")
+ pytestmark = pytest.mark.skip(
+ "test_directconnect_confirm_connection.py requires the `boto3` and `botocore` modules"
+ )
# When rerecording these tests, create a stand alone connection with default values in us-west-2
# with the name ansible-test-connection and set connection_id to the appropriate value
connection_id = "dxcon-fgq9rgot"
-connection_name = 'ansible-test-connection'
+connection_name = "ansible-test-connection"
def test_connection_status(placeboify, maybe_sleep):
- client = placeboify.client('directconnect')
- status = directconnect_connection.connection_status(client, connection_id)['connection']
- assert status['connectionName'] == connection_name
- assert status['connectionId'] == connection_id
+ client = placeboify.client("directconnect")
+ status = directconnect_connection.connection_status(client, connection_id)["connection"]
+ assert status["connectionName"] == connection_name
+ assert status["connectionId"] == connection_id
def test_connection_exists_by_id(placeboify, maybe_sleep):
- client = placeboify.client('directconnect')
+ client = placeboify.client("directconnect")
exists = directconnect_connection.connection_exists(client, connection_id)
assert exists == connection_id
def test_connection_exists_by_name(placeboify, maybe_sleep):
- client = placeboify.client('directconnect')
+ client = placeboify.client("directconnect")
exists = directconnect_connection.connection_exists(client, None, connection_name)
assert exists == connection_id
def test_connection_does_not_exist(placeboify, maybe_sleep):
- client = placeboify.client('directconnect')
- exists = directconnect_connection.connection_exists(client, 'dxcon-notthere')
+ client = placeboify.client("directconnect")
+ exists = directconnect_connection.connection_exists(client, "dxcon-notthere")
assert exists is False
def test_changed_properties(placeboify, maybe_sleep):
- client = placeboify.client('directconnect')
- status = directconnect_connection.connection_status(client, connection_id)['connection']
+ client = placeboify.client("directconnect")
+ status = directconnect_connection.connection_status(client, connection_id)["connection"]
location = "differentlocation"
- bandwidth = status['bandwidth']
+ bandwidth = status["bandwidth"]
assert directconnect_connection.changed_properties(status, location, bandwidth) is True
def test_associations_are_not_updated(placeboify, maybe_sleep):
- client = placeboify.client('directconnect')
- status = directconnect_connection.connection_status(client, connection_id)['connection']
- lag_id = status.get('lagId')
+ client = placeboify.client("directconnect")
+ status = directconnect_connection.connection_status(client, connection_id)["connection"]
+ lag_id = status.get("lagId")
assert directconnect_connection.update_associations(client, status, connection_id, lag_id) is False
def test_create_and_delete(placeboify, maybe_sleep):
- client = placeboify.client('directconnect')
+ client = placeboify.client("directconnect")
created_conn = verify_create_works(placeboify, maybe_sleep, client)
verify_delete_works(placeboify, maybe_sleep, client, created_conn)
def verify_create_works(placeboify, maybe_sleep, client):
- created = directconnect_connection.create_connection(client=client,
- location="EqSE2",
- bandwidth="1Gbps",
- name="ansible-test-2",
- lag_id=None)
- assert created.startswith('dxcon')
+ created = directconnect_connection.create_connection(
+ client=client, location="EqSE2", bandwidth="1Gbps", name="ansible-test-2", lag_id=None
+ )
+ assert created.startswith("dxcon")
return created
diff --git a/ansible_collections/community/aws/tests/unit/plugins/modules/test_directconnect_link_aggregation_group.py b/ansible_collections/community/aws/tests/unit/plugins/modules/test_directconnect_link_aggregation_group.py
index 90c8d9604..134be7167 100644
--- a/ansible_collections/community/aws/tests/unit/plugins/modules/test_directconnect_link_aggregation_group.py
+++ b/ansible_collections/community/aws/tests/unit/plugins/modules/test_directconnect_link_aggregation_group.py
@@ -4,40 +4,52 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
__metaclass__ = type
-import pytest
-import os
import collections
+import os
-# Magic... Incorrectly identified by pylint as unused
-from ansible_collections.amazon.aws.tests.unit.utils.amazon_placebo_fixtures import maybe_sleep # pylint: disable=unused-import
-from ansible_collections.amazon.aws.tests.unit.utils.amazon_placebo_fixtures import placeboify # pylint: disable=unused-import
+import pytest
from ansible_collections.amazon.aws.plugins.module_utils.botocore import HAS_BOTO3
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_conn
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import get_aws_connection_info
+# Magic... Incorrectly identified by pylint as unused
+# isort: off
+# pylint: disable=unused-import
+from ansible_collections.amazon.aws.tests.unit.utils.amazon_placebo_fixtures import maybe_sleep
+from ansible_collections.amazon.aws.tests.unit.utils.amazon_placebo_fixtures import placeboify
+
+# pylint: enable=unused-import
+# isort: on
+
from ansible_collections.community.aws.plugins.modules import directconnect_link_aggregation_group as lag_module
if not HAS_BOTO3:
- pytestmark = pytest.mark.skip("test_directconnect_confirm_connection.py requires the `boto3` and `botocore` modules")
+ pytestmark = pytest.mark.skip(
+ "test_directconnect_confirm_connection.py requires the `boto3` and `botocore` modules"
+ )
@pytest.fixture(scope="module")
def dependencies():
-
# each LAG dict will contain the keys: module, connections, virtual_interfaces
Dependencies = collections.namedtuple("Dependencies", ["lag_1", "lag_2"])
lag_1 = dict()
lag_2 = dict()
- vanilla_params = {"name": "ansible_lag_1",
- "location": "EqSe2",
- "num_connections": 1,
- "min_links": 0,
- "bandwidth": "1Gbps"}
+ vanilla_params = {
+ "name": "ansible_lag_1",
+ "location": "EqSe2",
+ "num_connections": 1,
+ "min_links": 0,
+ "bandwidth": "1Gbps",
+ }
for lag in ("ansible_lag_1", "ansible_lag_2"):
params = dict(vanilla_params)
@@ -49,10 +61,19 @@ def dependencies():
if os.getenv("PLACEBO_RECORD"):
region, ec2_url, aws_connect_kwargs = get_aws_connection_info(lag_1["module"], boto3=True)
- client = boto3_conn(lag_1["module"], conn_type="client", resource="directconnect", region=region, endpoint=ec2_url, **aws_connect_kwargs)
+ client = boto3_conn(
+ lag_1["module"],
+ conn_type="client",
+ resource="directconnect",
+ region=region,
+ endpoint=ec2_url,
+ **aws_connect_kwargs,
+ )
# See if link aggregation groups exist
for name in ("ansible_lag_1", "ansible_lag_2"):
- lag_id = lag_module.create_lag(client, num_connections=1, location="EqSe2", bandwidth="1Gbps", name=name, connection_id=None)
+ lag_id = lag_module.create_lag(
+ client, num_connections=1, location="EqSe2", bandwidth="1Gbps", name=name, connection_id=None
+ )
if name == "ansible_lag_1":
lag_1["lag_id"] = lag_id
lag_1["name"] = name
@@ -87,10 +108,7 @@ class FakeModule(object):
def test_nonexistent_lag_status(placeboify, maybe_sleep):
client = placeboify.client("directconnect")
- exists = lag_module.lag_exists(client=client,
- lag_id="doesntexist",
- lag_name="doesntexist",
- verify=True)
+ exists = lag_module.lag_exists(client=client, lag_id="doesntexist", lag_name="doesntexist", verify=True)
assert not exists
@@ -103,28 +121,19 @@ def test_lag_status(placeboify, maybe_sleep, dependencies):
def test_lag_exists(placeboify, maybe_sleep, dependencies):
client = placeboify.client("directconnect")
- exists = lag_module.lag_exists(client=client,
- lag_id=dependencies.lag_1.get("lag_id"),
- lag_name=None,
- verify=True)
+ exists = lag_module.lag_exists(client=client, lag_id=dependencies.lag_1.get("lag_id"), lag_name=None, verify=True)
assert exists
def test_lag_exists_using_name(placeboify, maybe_sleep, dependencies):
client = placeboify.client("directconnect")
- exists = lag_module.lag_exists(client=client,
- lag_id=None,
- lag_name=dependencies.lag_1.get("name"),
- verify=True)
+ exists = lag_module.lag_exists(client=client, lag_id=None, lag_name=dependencies.lag_1.get("name"), verify=True)
assert exists
def test_nonexistent_lag_does_not_exist(placeboify, maybe_sleep):
client = placeboify.client("directconnect")
- exists = lag_module.lag_exists(client=client,
- lag_id="dxlag-XXXXXXXX",
- lag_name="doesntexist",
- verify=True)
+ exists = lag_module.lag_exists(client=client, lag_id="dxlag-XXXXXXXX", lag_name="doesntexist", verify=True)
assert not exists
@@ -143,19 +152,21 @@ def test_lag_changed_true_no(placeboify, maybe_sleep, dependencies):
def test_update_lag(placeboify, maybe_sleep, dependencies):
client = placeboify.client("directconnect")
status_before = lag_module.lag_status(client=client, lag_id=dependencies.lag_2.get("lag_id"))
- lag_module.update_lag(client,
- lag_id=dependencies.lag_2.get("lag_id"),
- lag_name="ansible_lag_2_update",
- min_links=0,
- wait=False,
- wait_timeout=0,
- num_connections=1)
+ lag_module.update_lag(
+ client,
+ lag_id=dependencies.lag_2.get("lag_id"),
+ lag_name="ansible_lag_2_update",
+ min_links=0,
+ wait=False,
+ wait_timeout=0,
+ num_connections=1,
+ )
status_after = lag_module.lag_status(client=client, lag_id=dependencies.lag_2.get("lag_id"))
assert status_before != status_after
# remove the lag name from the statuses and verify it was the only thing changed
- del status_before['lagName']
- del status_after['lagName']
+ del status_before["lagName"]
+ del status_after["lagName"]
assert status_before == status_after
diff --git a/ansible_collections/community/aws/tests/unit/plugins/modules/test_directconnect_virtual_interface.py b/ansible_collections/community/aws/tests/unit/plugins/modules/test_directconnect_virtual_interface.py
index 4f0086421..62b511bde 100644
--- a/ansible_collections/community/aws/tests/unit/plugins/modules/test_directconnect_virtual_interface.py
+++ b/ansible_collections/community/aws/tests/unit/plugins/modules/test_directconnect_virtual_interface.py
@@ -4,20 +4,31 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
__metaclass__ = type
import pytest
from ansible_collections.amazon.aws.plugins.module_utils.botocore import HAS_BOTO3
+
# Magic... Incorrectly identified by pylint as unused
-from ansible_collections.amazon.aws.tests.unit.utils.amazon_placebo_fixtures import maybe_sleep # pylint: disable=unused-import
-from ansible_collections.amazon.aws.tests.unit.utils.amazon_placebo_fixtures import placeboify # pylint: disable=unused-import
+# isort: off
+# pylint: disable=unused-import
+from ansible_collections.amazon.aws.tests.unit.utils.amazon_placebo_fixtures import maybe_sleep
+from ansible_collections.amazon.aws.tests.unit.utils.amazon_placebo_fixtures import placeboify
+
+# pylint: enable=unused-import
+# isort: on
from ansible_collections.community.aws.plugins.modules import directconnect_virtual_interface
if not HAS_BOTO3:
- pytestmark = pytest.mark.skip("test_directconnect_confirm_connection.py requires the `boto3` and `botocore` modules")
+ pytestmark = pytest.mark.skip(
+ "test_directconnect_confirm_connection.py requires the `boto3` and `botocore` modules"
+ )
class FailException(Exception):
@@ -46,10 +57,7 @@ def test_find_unique_vi_by_connection_id(placeboify, maybe_sleep):
def test_find_unique_vi_by_vi_id(placeboify, maybe_sleep):
client = placeboify.client("directconnect")
- vi_id = directconnect_virtual_interface.find_unique_vi(client,
- None,
- "dxvif-aaaaaaaaa",
- None)
+ vi_id = directconnect_virtual_interface.find_unique_vi(client, None, "dxvif-aaaaaaaaa", None)
assert vi_id == "dxvif-aaaaaaaa"
@@ -61,47 +69,38 @@ def test_find_unique_vi_by_name(placeboify, maybe_sleep):
def test_find_unique_vi_returns_multiple(placeboify, maybe_sleep):
client = placeboify.client("directconnect")
- module = FakeModule(state="present",
- id_to_associate="dxcon-aaaaaaaa",
- public=False,
- name=None)
+ module = FakeModule(state="present", id_to_associate="dxcon-aaaaaaaa", public=False, name=None)
with pytest.raises(FailException):
- directconnect_virtual_interface.ensure_state(
- client,
- module
- )
+ directconnect_virtual_interface.ensure_state(client, module)
assert "Multiple virtual interfaces were found" in module.exit_kwargs["msg"]
def test_find_unique_vi_returns_missing_for_vi_id(placeboify, maybe_sleep):
client = placeboify.client("directconnect")
- module = FakeModule(state="present",
- id_to_associate=None,
- public=False,
- name=None,
- virtual_interface_id="dxvif-aaaaaaaa")
+ module = FakeModule(
+ state="present", id_to_associate=None, public=False, name=None, virtual_interface_id="dxvif-aaaaaaaa"
+ )
with pytest.raises(FailException):
- directconnect_virtual_interface.ensure_state(
- client,
- module
- )
+ directconnect_virtual_interface.ensure_state(client, module)
assert "The virtual interface dxvif-aaaaaaaa does not exist" in module.exit_kwargs["msg"]
def test_construct_public_vi():
- module = FakeModule(state="present",
- id_to_associate=None,
- public=True,
- name="aaaaaaaa",
- vlan=1,
- bgp_asn=123,
- authentication_key="aaaa",
- customer_address="169.254.0.1/30",
- amazon_address="169.254.0.2/30",
- address_type="ipv4",
- cidr=["10.88.0.0/30"],
- virtual_gateway_id="xxxx",
- direct_connect_gateway_id="yyyy")
+ module = FakeModule(
+ state="present",
+ id_to_associate=None,
+ public=True,
+ name="aaaaaaaa",
+ vlan=1,
+ bgp_asn=123,
+ authentication_key="aaaa",
+ customer_address="169.254.0.1/30",
+ amazon_address="169.254.0.2/30",
+ address_type="ipv4",
+ cidr=["10.88.0.0/30"],
+ virtual_gateway_id="xxxx",
+ direct_connect_gateway_id="yyyy",
+ )
vi = directconnect_virtual_interface.assemble_params_for_creating_vi(module.params)
assert vi == {
"virtualInterfaceName": "aaaaaaaa",
@@ -111,24 +110,26 @@ def test_construct_public_vi():
"amazonAddress": "169.254.0.2/30",
"customerAddress": "169.254.0.1/30",
"addressFamily": "ipv4",
- "routeFilterPrefixes": [{"cidr": "10.88.0.0/30"}]
+ "routeFilterPrefixes": [{"cidr": "10.88.0.0/30"}],
}
def test_construct_private_vi_with_virtual_gateway_id():
- module = FakeModule(state="present",
- id_to_associate=None,
- public=False,
- name="aaaaaaaa",
- vlan=1,
- bgp_asn=123,
- authentication_key="aaaa",
- customer_address="169.254.0.1/30",
- amazon_address="169.254.0.2/30",
- address_type="ipv4",
- cidr=["10.88.0.0/30"],
- virtual_gateway_id="xxxx",
- direct_connect_gateway_id="yyyy")
+ module = FakeModule(
+ state="present",
+ id_to_associate=None,
+ public=False,
+ name="aaaaaaaa",
+ vlan=1,
+ bgp_asn=123,
+ authentication_key="aaaa",
+ customer_address="169.254.0.1/30",
+ amazon_address="169.254.0.2/30",
+ address_type="ipv4",
+ cidr=["10.88.0.0/30"],
+ virtual_gateway_id="xxxx",
+ direct_connect_gateway_id="yyyy",
+ )
vi = directconnect_virtual_interface.assemble_params_for_creating_vi(module.params)
assert vi == {
"virtualInterfaceName": "aaaaaaaa",
@@ -138,24 +139,26 @@ def test_construct_private_vi_with_virtual_gateway_id():
"amazonAddress": "169.254.0.2/30",
"customerAddress": "169.254.0.1/30",
"addressFamily": "ipv4",
- "virtualGatewayId": "xxxx"
+ "virtualGatewayId": "xxxx",
}
def test_construct_private_vi_with_direct_connect_gateway_id():
- module = FakeModule(state="present",
- id_to_associate=None,
- public=False,
- name="aaaaaaaa",
- vlan=1,
- bgp_asn=123,
- authentication_key="aaaa",
- customer_address="169.254.0.1/30",
- amazon_address="169.254.0.2/30",
- address_type="ipv4",
- cidr=["10.88.0.0/30"],
- virtual_gateway_id=None,
- direct_connect_gateway_id="yyyy")
+ module = FakeModule(
+ state="present",
+ id_to_associate=None,
+ public=False,
+ name="aaaaaaaa",
+ vlan=1,
+ bgp_asn=123,
+ authentication_key="aaaa",
+ customer_address="169.254.0.1/30",
+ amazon_address="169.254.0.2/30",
+ address_type="ipv4",
+ cidr=["10.88.0.0/30"],
+ virtual_gateway_id=None,
+ direct_connect_gateway_id="yyyy",
+ )
vi = directconnect_virtual_interface.assemble_params_for_creating_vi(module.params)
print(vi)
assert vi == {
@@ -166,26 +169,28 @@ def test_construct_private_vi_with_direct_connect_gateway_id():
"amazonAddress": "169.254.0.2/30",
"customerAddress": "169.254.0.1/30",
"addressFamily": "ipv4",
- "directConnectGatewayId": "yyyy"
+ "directConnectGatewayId": "yyyy",
}
def test_create_public_vi(placeboify, maybe_sleep):
client = placeboify.client("directconnect")
- module = FakeModule(state="present",
- id_to_associate='dxcon-aaaaaaaa',
- virtual_interface_id=None,
- public=True,
- name="aaaaaaaa",
- vlan=1,
- bgp_asn=123,
- authentication_key="aaaa",
- customer_address="169.254.0.1/30",
- amazon_address="169.254.0.2/30",
- address_type="ipv4",
- cidr=["10.88.0.0/30"],
- virtual_gateway_id="xxxx",
- direct_connect_gateway_id="yyyy")
+ module = FakeModule(
+ state="present",
+ id_to_associate="dxcon-aaaaaaaa",
+ virtual_interface_id=None,
+ public=True,
+ name="aaaaaaaa",
+ vlan=1,
+ bgp_asn=123,
+ authentication_key="aaaa",
+ customer_address="169.254.0.1/30",
+ amazon_address="169.254.0.2/30",
+ address_type="ipv4",
+ cidr=["10.88.0.0/30"],
+ virtual_gateway_id="xxxx",
+ direct_connect_gateway_id="yyyy",
+ )
changed, latest_state = directconnect_virtual_interface.ensure_state(client, module)
assert changed is True
assert latest_state is not None
@@ -193,20 +198,22 @@ def test_create_public_vi(placeboify, maybe_sleep):
def test_create_private_vi(placeboify, maybe_sleep):
client = placeboify.client("directconnect")
- module = FakeModule(state="present",
- id_to_associate='dxcon-aaaaaaaa',
- virtual_interface_id=None,
- public=False,
- name="aaaaaaaa",
- vlan=1,
- bgp_asn=123,
- authentication_key="aaaa",
- customer_address="169.254.0.1/30",
- amazon_address="169.254.0.2/30",
- address_type="ipv4",
- cidr=["10.88.0.0/30"],
- virtual_gateway_id="xxxx",
- direct_connect_gateway_id="yyyy")
+ module = FakeModule(
+ state="present",
+ id_to_associate="dxcon-aaaaaaaa",
+ virtual_interface_id=None,
+ public=False,
+ name="aaaaaaaa",
+ vlan=1,
+ bgp_asn=123,
+ authentication_key="aaaa",
+ customer_address="169.254.0.1/30",
+ amazon_address="169.254.0.2/30",
+ address_type="ipv4",
+ cidr=["10.88.0.0/30"],
+ virtual_gateway_id="xxxx",
+ direct_connect_gateway_id="yyyy",
+ )
changed, latest_state = directconnect_virtual_interface.ensure_state(client, module)
assert changed is True
assert latest_state is not None
@@ -214,20 +221,22 @@ def test_create_private_vi(placeboify, maybe_sleep):
def test_delete_vi(placeboify, maybe_sleep):
client = placeboify.client("directconnect")
- module = FakeModule(state="absent",
- id_to_associate='dxcon-aaaaaaaa',
- virtual_interface_id='dxvif-aaaaaaaa',
- public=False,
- name="aaaaaaaa",
- vlan=1,
- bgp_asn=123,
- authentication_key="aaaa",
- customer_address="169.254.0.1/30",
- amazon_address="169.254.0.2/30",
- address_type="ipv4",
- cidr=["10.88.0.0/30"],
- virtual_gateway_id=None,
- direct_connect_gateway_id="yyyy")
+ module = FakeModule(
+ state="absent",
+ id_to_associate="dxcon-aaaaaaaa",
+ virtual_interface_id="dxvif-aaaaaaaa",
+ public=False,
+ name="aaaaaaaa",
+ vlan=1,
+ bgp_asn=123,
+ authentication_key="aaaa",
+ customer_address="169.254.0.1/30",
+ amazon_address="169.254.0.2/30",
+ address_type="ipv4",
+ cidr=["10.88.0.0/30"],
+ virtual_gateway_id=None,
+ direct_connect_gateway_id="yyyy",
+ )
changed, latest_state = directconnect_virtual_interface.ensure_state(client, module)
assert changed is True
assert latest_state == {}
diff --git a/ansible_collections/community/aws/tests/unit/plugins/modules/test_ec2_vpc_vpn.py b/ansible_collections/community/aws/tests/unit/plugins/modules/test_ec2_vpc_vpn.py
index 88a1aea83..2b5db4226 100644
--- a/ansible_collections/community/aws/tests/unit/plugins/modules/test_ec2_vpc_vpn.py
+++ b/ansible_collections/community/aws/tests/unit/plugins/modules/test_ec2_vpc_vpn.py
@@ -1,21 +1,29 @@
# (c) 2017 Red Hat Inc.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
__metaclass__ = type
import os
-import pytest
-# Magic... Incorrectly identified by pylint as unused
-from ansible_collections.amazon.aws.tests.unit.utils.amazon_placebo_fixtures import placeboify # pylint: disable=unused-import
-from ansible_collections.amazon.aws.tests.unit.utils.amazon_placebo_fixtures import maybe_sleep # pylint: disable=unused-import
+import pytest
-import ansible_collections.amazon.aws.plugins.module_utils.modules as aws_modules
import ansible_collections.amazon.aws.plugins.module_utils.retries as aws_retries
-from ansible_collections.amazon.aws.plugins.module_utils.ec2 import get_aws_connection_info
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_conn
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict
+from ansible_collections.amazon.aws.plugins.module_utils.ec2 import get_aws_connection_info
+
+# Magic... Incorrectly identified by pylint as unused
+# isort: off
+# pylint: disable=unused-import
+from ansible_collections.amazon.aws.tests.unit.utils.amazon_placebo_fixtures import maybe_sleep
+from ansible_collections.amazon.aws.tests.unit.utils.amazon_placebo_fixtures import placeboify
+
+# pylint: enable=unused-import
+# isort: on
from ansible_collections.community.aws.plugins.modules import ec2_vpc_vpn
@@ -31,12 +39,12 @@ class FakeModule(object):
def fail_json_aws(self, *args, **kwargs):
self.exit_args = args
self.exit_kwargs = kwargs
- raise FailException('FAIL')
+ raise FailException("FAIL")
def fail_json(self, *args, **kwargs):
self.exit_args = args
self.exit_kwargs = kwargs
- raise FailException('FAIL')
+ raise FailException("FAIL")
def exit_json(self, *args, **kwargs):
self.exit_args = args
@@ -45,36 +53,44 @@ class FakeModule(object):
def get_vgw(connection):
# see if two vgw exist and return them if so
- vgw = connection.describe_vpn_gateways(Filters=[{'Name': 'tag:Ansible_VPN', 'Values': ['Test']}])
- if len(vgw['VpnGateways']) >= 2:
- return [vgw['VpnGateways'][0]['VpnGatewayId'], vgw['VpnGateways'][1]['VpnGatewayId']]
+ vgw = connection.describe_vpn_gateways(Filters=[{"Name": "tag:Ansible_VPN", "Values": ["Test"]}])
+ if len(vgw["VpnGateways"]) >= 2:
+ return [vgw["VpnGateways"][0]["VpnGatewayId"], vgw["VpnGateways"][1]["VpnGatewayId"]]
# otherwise create two and return them
- vgw_1 = connection.create_vpn_gateway(Type='ipsec.1')
- vgw_2 = connection.create_vpn_gateway(Type='ipsec.1')
+ vgw_1 = connection.create_vpn_gateway(Type="ipsec.1")
+ vgw_2 = connection.create_vpn_gateway(Type="ipsec.1")
for resource in (vgw_1, vgw_2):
- connection.create_tags(Resources=[resource['VpnGateway']['VpnGatewayId']], Tags=[{'Key': 'Ansible_VPN', 'Value': 'Test'}])
- return [vgw_1['VpnGateway']['VpnGatewayId'], vgw_2['VpnGateway']['VpnGatewayId']]
+ connection.create_tags(
+ Resources=[resource["VpnGateway"]["VpnGatewayId"]], Tags=[{"Key": "Ansible_VPN", "Value": "Test"}]
+ )
+ return [vgw_1["VpnGateway"]["VpnGatewayId"], vgw_2["VpnGateway"]["VpnGatewayId"]]
def get_cgw(connection):
# see if two cgw exist and return them if so
- cgw = connection.describe_customer_gateways(DryRun=False, Filters=[{'Name': 'state', 'Values': ['available']},
- {'Name': 'tag:Name', 'Values': ['Ansible-CGW']}])
- if len(cgw['CustomerGateways']) >= 2:
- return [cgw['CustomerGateways'][0]['CustomerGatewayId'], cgw['CustomerGateways'][1]['CustomerGatewayId']]
+ cgw = connection.describe_customer_gateways(
+ DryRun=False,
+ Filters=[{"Name": "state", "Values": ["available"]}, {"Name": "tag:Name", "Values": ["Ansible-CGW"]}],
+ )
+ if len(cgw["CustomerGateways"]) >= 2:
+ return [cgw["CustomerGateways"][0]["CustomerGatewayId"], cgw["CustomerGateways"][1]["CustomerGatewayId"]]
# otherwise create and return them
- cgw_1 = connection.create_customer_gateway(DryRun=False, Type='ipsec.1', PublicIp='9.8.7.6', BgpAsn=65000)
- cgw_2 = connection.create_customer_gateway(DryRun=False, Type='ipsec.1', PublicIp='5.4.3.2', BgpAsn=65000)
+ cgw_1 = connection.create_customer_gateway(DryRun=False, Type="ipsec.1", PublicIp="9.8.7.6", BgpAsn=65000)
+ cgw_2 = connection.create_customer_gateway(DryRun=False, Type="ipsec.1", PublicIp="5.4.3.2", BgpAsn=65000)
for resource in (cgw_1, cgw_2):
- connection.create_tags(Resources=[resource['CustomerGateway']['CustomerGatewayId']], Tags=[{'Key': 'Ansible-CGW', 'Value': 'Test'}])
- return [cgw_1['CustomerGateway']['CustomerGatewayId'], cgw_2['CustomerGateway']['CustomerGatewayId']]
+ connection.create_tags(
+ Resources=[resource["CustomerGateway"]["CustomerGatewayId"]], Tags=[{"Key": "Ansible-CGW", "Value": "Test"}]
+ )
+ return [cgw_1["CustomerGateway"]["CustomerGatewayId"], cgw_2["CustomerGateway"]["CustomerGatewayId"]]
def get_dependencies():
- if os.getenv('PLACEBO_RECORD'):
+ if os.getenv("PLACEBO_RECORD"):
module = FakeModule(**{})
region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module, boto3=True)
- connection = boto3_conn(module, conn_type='client', resource='ec2', region=region, endpoint=ec2_url, **aws_connect_kwargs)
+ connection = boto3_conn(
+ module, conn_type="client", resource="ec2", region=region, endpoint=ec2_url, **aws_connect_kwargs
+ )
vgw = get_vgw(connection)
cgw = get_cgw(connection)
else:
@@ -85,9 +101,9 @@ def get_dependencies():
def setup_mod_conn(placeboify, params):
- conn = placeboify.client('ec2')
+ conn = placeboify.client("ec2")
retry_decorator = aws_retries.AWSRetry.jittered_backoff()
- wrapped_conn = aws_modules._RetryingBotoClientWrapper(conn, retry_decorator)
+ wrapped_conn = aws_retries.RetryingBotoClientWrapper(conn, retry_decorator)
m = FakeModule(**params)
return m, wrapped_conn
@@ -97,23 +113,25 @@ def make_params(cgw, vgw, tags=None, filters=None, routes=None):
filters = {} if filters is None else filters
routes = [] if routes is None else routes
- return {'customer_gateway_id': cgw,
- 'static_only': True,
- 'vpn_gateway_id': vgw,
- 'connection_type': 'ipsec.1',
- 'purge_tags': True,
- 'tags': tags,
- 'filters': filters,
- 'routes': routes,
- 'delay': 15,
- 'wait_timeout': 600}
+ return {
+ "customer_gateway_id": cgw,
+ "static_only": True,
+ "vpn_gateway_id": vgw,
+ "connection_type": "ipsec.1",
+ "purge_tags": True,
+ "tags": tags,
+ "filters": filters,
+ "routes": routes,
+ "delay": 15,
+ "wait_timeout": 600,
+ }
def make_conn(placeboify, module, connection):
- customer_gateway_id = module.params['customer_gateway_id']
- static_only = module.params['static_only']
- vpn_gateway_id = module.params['vpn_gateway_id']
- connection_type = module.params['connection_type']
+ customer_gateway_id = module.params["customer_gateway_id"]
+ static_only = module.params["static_only"]
+ vpn_gateway_id = module.params["vpn_gateway_id"]
+ connection_type = module.params["connection_type"]
changed = True
vpn = ec2_vpc_vpn.create_connection(connection, customer_gateway_id, static_only, vpn_gateway_id, connection_type)
return changed, vpn
@@ -124,7 +142,7 @@ def tear_down_conn(placeboify, connection, vpn_connection_id):
def setup_req(placeboify, number_of_results=1):
- ''' returns dependencies for VPN connections '''
+ """returns dependencies for VPN connections"""
assert number_of_results in (1, 2)
results = []
cgw, vgw = get_dependencies()
@@ -133,7 +151,7 @@ def setup_req(placeboify, number_of_results=1):
m, conn = setup_mod_conn(placeboify, params)
vpn = ec2_vpc_vpn.ensure_present(conn, params)[1]
- results.append({'module': m, 'connection': conn, 'vpn': vpn, 'params': params})
+ results.append({"module": m, "connection": conn, "vpn": vpn, "params": params})
if number_of_results == 1:
return results[0]
else:
@@ -144,41 +162,44 @@ def test_find_connection_vpc_conn_id(placeboify, maybe_sleep):
# setup dependencies for 2 vpn connections
dependencies = setup_req(placeboify, 2)
dep1, dep2 = dependencies[0], dependencies[1]
- params1, vpn1, _m1, conn1 = dep1['params'], dep1['vpn'], dep1['module'], dep1['connection']
- _params2, vpn2, _m2, conn2 = dep2['params'], dep2['vpn'], dep2['module'], dep2['connection']
+ params1, vpn1, _m1, conn1 = dep1["params"], dep1["vpn"], dep1["module"], dep1["connection"]
+ _params2, vpn2, _m2, conn2 = dep2["params"], dep2["vpn"], dep2["module"], dep2["connection"]
# find the connection with a vpn_connection_id and assert it is the expected one
- assert vpn1['VpnConnectionId'] == ec2_vpc_vpn.find_connection(conn1, params1, vpn1['VpnConnectionId'])['VpnConnectionId']
+ assert (
+ vpn1["VpnConnectionId"]
+ == ec2_vpc_vpn.find_connection(conn1, params1, vpn1["VpnConnectionId"])["VpnConnectionId"]
+ )
- tear_down_conn(placeboify, conn1, vpn1['VpnConnectionId'])
- tear_down_conn(placeboify, conn2, vpn2['VpnConnectionId'])
+ tear_down_conn(placeboify, conn1, vpn1["VpnConnectionId"])
+ tear_down_conn(placeboify, conn2, vpn2["VpnConnectionId"])
def test_find_connection_filters(placeboify, maybe_sleep):
# setup dependencies for 2 vpn connections
dependencies = setup_req(placeboify, 2)
dep1, dep2 = dependencies[0], dependencies[1]
- params1, vpn1, _m1, conn1 = dep1['params'], dep1['vpn'], dep1['module'], dep1['connection']
- params2, vpn2, _m2, conn2 = dep2['params'], dep2['vpn'], dep2['module'], dep2['connection']
+ params1, vpn1, _m1, conn1 = dep1["params"], dep1["vpn"], dep1["module"], dep1["connection"]
+ params2, vpn2, _m2, conn2 = dep2["params"], dep2["vpn"], dep2["module"], dep2["connection"]
# update to different tags
- params1.update(tags={'Wrong': 'Tag'})
- params2.update(tags={'Correct': 'Tag'})
+ params1.update(tags={"Wrong": "Tag"})
+ params2.update(tags={"Correct": "Tag"})
ec2_vpc_vpn.ensure_present(conn1, params1)
ec2_vpc_vpn.ensure_present(conn2, params2)
# create some new parameters for a filter
- params = {'filters': {'tags': {'Correct': 'Tag'}}}
+ params = {"filters": {"tags": {"Correct": "Tag"}}}
# find the connection that has the parameters above
found = ec2_vpc_vpn.find_connection(conn1, params)
# assert the correct connection was found
- assert found['VpnConnectionId'] == vpn2['VpnConnectionId']
+ assert found["VpnConnectionId"] == vpn2["VpnConnectionId"]
# delete the connections
- tear_down_conn(placeboify, conn1, vpn1['VpnConnectionId'])
- tear_down_conn(placeboify, conn2, vpn2['VpnConnectionId'])
+ tear_down_conn(placeboify, conn1, vpn1["VpnConnectionId"])
+ tear_down_conn(placeboify, conn2, vpn2["VpnConnectionId"])
def test_find_connection_insufficient_filters(placeboify, maybe_sleep):
@@ -186,15 +207,15 @@ def test_find_connection_insufficient_filters(placeboify, maybe_sleep):
cgw, vgw = get_dependencies()
# create two connections with the same tags
- params = make_params(cgw[0], vgw[0], tags={'Correct': 'Tag'})
- params2 = make_params(cgw[1], vgw[1], tags={'Correct': 'Tag'})
+ params = make_params(cgw[0], vgw[0], tags={"Correct": "Tag"})
+ params2 = make_params(cgw[1], vgw[1], tags={"Correct": "Tag"})
m, conn = setup_mod_conn(placeboify, params)
m2, conn2 = setup_mod_conn(placeboify, params2)
vpn1 = ec2_vpc_vpn.ensure_present(conn, m.params)[1]
vpn2 = ec2_vpc_vpn.ensure_present(conn2, m2.params)[1]
# reset the parameters so only filtering by tags will occur
- m.params = {'filters': {'tags': {'Correct': 'Tag'}}}
+ m.params = {"filters": {"tags": {"Correct": "Tag"}}}
expected_message = "More than one matching VPN connection was found"
# assert that multiple matching connections have been found
@@ -202,13 +223,13 @@ def test_find_connection_insufficient_filters(placeboify, maybe_sleep):
ec2_vpc_vpn.find_connection(conn, m.params)
# delete the connections
- tear_down_conn(placeboify, conn, vpn1['VpnConnectionId'])
- tear_down_conn(placeboify, conn, vpn2['VpnConnectionId'])
+ tear_down_conn(placeboify, conn, vpn1["VpnConnectionId"])
+ tear_down_conn(placeboify, conn, vpn2["VpnConnectionId"])
def test_find_connection_nonexistent(placeboify, maybe_sleep):
# create parameters but don't create a connection with them
- params = {'filters': {'tags': {'Correct': 'Tag'}}}
+ params = {"filters": {"tags": {"Correct": "Tag"}}}
m, conn = setup_mod_conn(placeboify, params)
# try to find a connection with matching parameters and assert None are found
@@ -226,38 +247,48 @@ def test_create_connection(placeboify, maybe_sleep):
# assert that changed is true and that there is a connection id
assert changed is True
- assert 'VpnConnectionId' in vpn
+ assert "VpnConnectionId" in vpn
# delete connection
- tear_down_conn(placeboify, conn, vpn['VpnConnectionId'])
+ tear_down_conn(placeboify, conn, vpn["VpnConnectionId"])
def test_create_connection_that_exists(placeboify, maybe_sleep):
# setup dependencies for 1 vpn connection
dependencies = setup_req(placeboify, 1)
- params, vpn, _m, conn = dependencies['params'], dependencies['vpn'], dependencies['module'], dependencies['connection']
+ params, vpn, _m, conn = (
+ dependencies["params"],
+ dependencies["vpn"],
+ dependencies["module"],
+ dependencies["connection"],
+ )
# try to recreate the same connection
changed, vpn2 = ec2_vpc_vpn.ensure_present(conn, params)
# nothing should have changed
assert changed is False
- assert vpn['VpnConnectionId'] == vpn2['VpnConnectionId']
+ assert vpn["VpnConnectionId"] == vpn2["VpnConnectionId"]
# delete connection
- tear_down_conn(placeboify, conn, vpn['VpnConnectionId'])
+ tear_down_conn(placeboify, conn, vpn["VpnConnectionId"])
def test_modify_deleted_connection(placeboify, maybe_sleep):
# setup dependencies for 1 vpn connection
dependencies = setup_req(placeboify, 1)
- _params, vpn, m, conn = dependencies['params'], dependencies['vpn'], dependencies['module'], dependencies['connection']
+ _params, vpn, m, conn = (
+ dependencies["params"],
+ dependencies["vpn"],
+ dependencies["module"],
+ dependencies["connection"],
+ )
# delete it
- tear_down_conn(placeboify, conn, vpn['VpnConnectionId'])
+ tear_down_conn(placeboify, conn, vpn["VpnConnectionId"])
# try to update the deleted connection
- m.params.update(vpn_connection_id=vpn['VpnConnectionId'])
+ m.params.update(vpn_connection_id=vpn["VpnConnectionId"])
expected_message = "no VPN connection available or pending with that id"
with pytest.raises(ec2_vpc_vpn.VPNConnectionException, match=expected_message):
ec2_vpc_vpn.ensure_present(conn, m.params)
@@ -266,7 +297,12 @@ def test_modify_deleted_connection(placeboify, maybe_sleep):
def test_delete_connection(placeboify, maybe_sleep):
# setup dependencies for 1 vpn connection
dependencies = setup_req(placeboify, 1)
- _params, vpn, m, conn = dependencies['params'], dependencies['vpn'], dependencies['module'], dependencies['connection']
+ _params, vpn, m, conn = (
+ dependencies["params"],
+ dependencies["vpn"],
+ dependencies["module"],
+ dependencies["connection"],
+ )
# delete it
changed, vpn = ec2_vpc_vpn.ensure_absent(conn, m.params)
@@ -277,7 +313,7 @@ def test_delete_connection(placeboify, maybe_sleep):
def test_delete_nonexistent_connection(placeboify, maybe_sleep):
# create parameters and ensure any connection matching (None) is deleted
- params = {'filters': {'tags': {'ThisConnection': 'DoesntExist'}}, 'delay': 15, 'wait_timeout': 600}
+ params = {"filters": {"tags": {"ThisConnection": "DoesntExist"}}, "delay": 15, "wait_timeout": 600}
m, conn = setup_mod_conn(placeboify, params)
changed, vpn = ec2_vpc_vpn.ensure_absent(conn, m.params)
@@ -288,83 +324,112 @@ def test_delete_nonexistent_connection(placeboify, maybe_sleep):
def test_check_for_update_tags(placeboify, maybe_sleep):
# setup dependencies for 1 vpn connection
dependencies = setup_req(placeboify, 1)
- _params, vpn, m, conn = dependencies['params'], dependencies['vpn'], dependencies['module'], dependencies['connection']
+ _params, vpn, m, conn = (
+ dependencies["params"],
+ dependencies["vpn"],
+ dependencies["module"],
+ dependencies["connection"],
+ )
# add and remove a number of tags
- m.params['tags'] = {'One': 'one', 'Two': 'two'}
+ m.params["tags"] = {"One": "one", "Two": "two"}
ec2_vpc_vpn.ensure_present(conn, m.params)
- m.params['tags'] = {'Two': 'two', 'Three': 'three', 'Four': 'four'}
- changes = ec2_vpc_vpn.check_for_update(conn, m.params, vpn['VpnConnectionId'])
+ m.params["tags"] = {"Two": "two", "Three": "three", "Four": "four"}
+ changes = ec2_vpc_vpn.check_for_update(conn, m.params, vpn["VpnConnectionId"])
- flat_dict_changes = boto3_tag_list_to_ansible_dict(changes['tags_to_add'])
- correct_changes = boto3_tag_list_to_ansible_dict([{'Key': 'Three', 'Value': 'three'}, {'Key': 'Four', 'Value': 'four'}])
+ flat_dict_changes = boto3_tag_list_to_ansible_dict(changes["tags_to_add"])
+ correct_changes = boto3_tag_list_to_ansible_dict(
+ [{"Key": "Three", "Value": "three"}, {"Key": "Four", "Value": "four"}]
+ )
assert flat_dict_changes == correct_changes
- assert changes['tags_to_remove'] == ['One']
+ assert changes["tags_to_remove"] == ["One"]
# delete connection
- tear_down_conn(placeboify, conn, vpn['VpnConnectionId'])
+ tear_down_conn(placeboify, conn, vpn["VpnConnectionId"])
def test_check_for_update_nonmodifiable_attr(placeboify, maybe_sleep):
# setup dependencies for 1 vpn connection
dependencies = setup_req(placeboify, 1)
- params, vpn, m, conn = dependencies['params'], dependencies['vpn'], dependencies['module'], dependencies['connection']
- current_vgw = params['vpn_gateway_id']
+ params, vpn, m, conn = (
+ dependencies["params"],
+ dependencies["vpn"],
+ dependencies["module"],
+ dependencies["connection"],
+ )
+ current_vgw = params["vpn_gateway_id"]
# update a parameter that isn't modifiable
m.params.update(vpn_gateway_id="invalidchange")
- expected_message = 'You cannot modify vpn_gateway_id, the current value of which is {0}. Modifiable VPN connection attributes are'.format(current_vgw)
+ expected_message = f"You cannot modify vpn_gateway_id, the current value of which is {current_vgw}. Modifiable VPN connection attributes are"
with pytest.raises(ec2_vpc_vpn.VPNConnectionException, match=expected_message):
- ec2_vpc_vpn.check_for_update(conn, m.params, vpn['VpnConnectionId'])
+ ec2_vpc_vpn.check_for_update(conn, m.params, vpn["VpnConnectionId"])
# delete connection
- tear_down_conn(placeboify, conn, vpn['VpnConnectionId'])
+ tear_down_conn(placeboify, conn, vpn["VpnConnectionId"])
def test_add_tags(placeboify, maybe_sleep):
# setup dependencies for 1 vpn connection
dependencies = setup_req(placeboify, 1)
- params, vpn, _m, conn = dependencies['params'], dependencies['vpn'], dependencies['module'], dependencies['connection']
+ params, vpn, _m, conn = (
+ dependencies["params"],
+ dependencies["vpn"],
+ dependencies["module"],
+ dependencies["connection"],
+ )
# add a tag to the connection
- ec2_vpc_vpn.add_tags(conn, vpn['VpnConnectionId'], add=[{'Key': 'Ansible-Test', 'Value': 'VPN'}])
+ ec2_vpc_vpn.add_tags(conn, vpn["VpnConnectionId"], add=[{"Key": "Ansible-Test", "Value": "VPN"}])
# assert tag is there
current_vpn = ec2_vpc_vpn.find_connection(conn, params)
- assert current_vpn['Tags'] == [{'Key': 'Ansible-Test', 'Value': 'VPN'}]
+ assert current_vpn["Tags"] == [{"Key": "Ansible-Test", "Value": "VPN"}]
# delete connection
- tear_down_conn(placeboify, conn, vpn['VpnConnectionId'])
+ tear_down_conn(placeboify, conn, vpn["VpnConnectionId"])
def test_remove_tags(placeboify, maybe_sleep):
# setup dependencies for 1 vpn connection
dependencies = setup_req(placeboify, 1)
- params, vpn, _m, conn = dependencies['params'], dependencies['vpn'], dependencies['module'], dependencies['connection']
+ params, vpn, _m, conn = (
+ dependencies["params"],
+ dependencies["vpn"],
+ dependencies["module"],
+ dependencies["connection"],
+ )
# remove a tag from the connection
- ec2_vpc_vpn.remove_tags(conn, vpn['VpnConnectionId'], remove=['Ansible-Test'])
+ ec2_vpc_vpn.remove_tags(conn, vpn["VpnConnectionId"], remove=["Ansible-Test"])
# assert the tag is gone
current_vpn = ec2_vpc_vpn.find_connection(conn, params)
- assert 'Tags' not in current_vpn
+ assert "Tags" not in current_vpn
# delete connection
- tear_down_conn(placeboify, conn, vpn['VpnConnectionId'])
+ tear_down_conn(placeboify, conn, vpn["VpnConnectionId"])
def test_add_routes(placeboify, maybe_sleep):
# setup dependencies for 1 vpn connection
dependencies = setup_req(placeboify, 1)
- params, vpn, _m, conn = dependencies['params'], dependencies['vpn'], dependencies['module'], dependencies['connection']
+ params, vpn, _m, conn = (
+ dependencies["params"],
+ dependencies["vpn"],
+ dependencies["module"],
+ dependencies["connection"],
+ )
# create connection with a route
- ec2_vpc_vpn.add_routes(conn, vpn['VpnConnectionId'], ['195.168.2.0/24', '196.168.2.0/24'])
+ ec2_vpc_vpn.add_routes(conn, vpn["VpnConnectionId"], ["195.168.2.0/24", "196.168.2.0/24"])
# assert both routes are there
current_vpn = ec2_vpc_vpn.find_connection(conn, params)
- assert set(each['DestinationCidrBlock'] for each in current_vpn['Routes']) == set(['195.168.2.0/24', '196.168.2.0/24'])
+ assert set(each["DestinationCidrBlock"] for each in current_vpn["Routes"]) == set(
+ ["195.168.2.0/24", "196.168.2.0/24"]
+ )
# delete connection
- tear_down_conn(placeboify, conn, vpn['VpnConnectionId'])
+ tear_down_conn(placeboify, conn, vpn["VpnConnectionId"])
diff --git a/ansible_collections/community/aws/tests/unit/plugins/modules/test_ec2_win_password.py b/ansible_collections/community/aws/tests/unit/plugins/modules/test_ec2_win_password.py
index 939620120..7f832aa71 100644
--- a/ansible_collections/community/aws/tests/unit/plugins/modules/test_ec2_win_password.py
+++ b/ansible_collections/community/aws/tests/unit/plugins/modules/test_ec2_win_password.py
@@ -1,8 +1,4 @@
-from __future__ import (absolute_import, division, print_function)
-
-__metaclass__ = type
-
-'''
+"""
Commands to encrypt a message that can be decrypted:
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.serialization import load_pem_private_key
@@ -15,9 +11,11 @@ with open(path, 'r') as f:
load_pem_public_key(rsa_public_key_pem = , default_backend())
base64_cipher = public_key.encrypt('Ansible_AWS_EC2_Win_Password', PKCS1v15())
string_cipher = base64.b64encode(base64_cipher)
-'''
+"""
import datetime
+from unittest.mock import patch
+
import pytest
from ansible.module_utils._text import to_bytes
@@ -25,52 +23,53 @@ from ansible.module_utils._text import to_text
from ansible_collections.amazon.aws.plugins.module_utils.botocore import HAS_BOTO3
-from ansible_collections.community.aws.tests.unit.compat.mock import patch
+from ansible_collections.community.aws.plugins.modules.ec2_win_password import ec2_win_password
+from ansible_collections.community.aws.plugins.modules.ec2_win_password import setup_module_object
from ansible_collections.community.aws.tests.unit.plugins.modules.utils import AnsibleExitJson
from ansible_collections.community.aws.tests.unit.plugins.modules.utils import ModuleTestCase
from ansible_collections.community.aws.tests.unit.plugins.modules.utils import set_module_args
-from ansible_collections.community.aws.plugins.modules.ec2_win_password import setup_module_object
-from ansible_collections.community.aws.plugins.modules.ec2_win_password import ec2_win_password
-
-fixture_prefix = 'tests/unit/plugins/modules/fixtures/certs'
+fixture_prefix = "tests/unit/plugins/modules/fixtures/certs"
if not HAS_BOTO3:
pytestmark = pytest.mark.skip("test_api_gateway.py requires the `boto3` and `botocore` modules")
class TestEc2WinPasswordModule(ModuleTestCase):
-
# Future: It would be good to generate this data on the fly and use a
# temporary certificate and password.
- PEM_PATH = fixture_prefix + '/ec2_win_password.pem'
- UNENCRYPTED_DATA = 'Ansible_AWS_EC2_Win_Password'
- ENCRYPTED_DATA = 'L2k1iFiu/TRrjGr6Rwco/T3C7xkWxUw4+YPYpGGOmP3KDdy3hT1' \
- '8RvdDJ2i0e+y7wUcH43DwbRYSlkSyALY/nzjSV9R5NChUyVs3W5' \
- '5oiVuyTKsk0lor8dFJ9z9unq14tScZHvyQ3Nx1ggOtS18S9Pk55q' \
- 'IaCXfx26ucH76VRho='
- INSTANCE_ID = 'i-12345'
-
- @patch('ansible_collections.community.aws.plugins.modules.s3_bucket_notification.AnsibleAWSModule.client')
+ PEM_PATH = fixture_prefix + "/ec2_win_password.pem"
+ UNENCRYPTED_DATA = "Ansible_AWS_EC2_Win_Password"
+ ENCRYPTED_DATA = (
+ "L2k1iFiu/TRrjGr6Rwco/T3C7xkWxUw4+YPYpGGOmP3KDdy3hT1"
+ "8RvdDJ2i0e+y7wUcH43DwbRYSlkSyALY/nzjSV9R5NChUyVs3W5"
+ "5oiVuyTKsk0lor8dFJ9z9unq14tScZHvyQ3Nx1ggOtS18S9Pk55q"
+ "IaCXfx26ucH76VRho="
+ )
+ INSTANCE_ID = "i-12345"
+
+ @patch("ansible_collections.community.aws.plugins.modules.s3_bucket_notification.AnsibleAWSModule.client")
def test_decryption(self, mock_client):
-
path = self.PEM_PATH
- with open(path, 'r') as f:
+ with open(path, "r") as f:
pem = to_text(f.read())
with self.assertRaises(AnsibleExitJson) as exec_info:
- set_module_args({'instance_id': self.INSTANCE_ID,
- 'key_data': pem,
- })
+ set_module_args(
+ {
+ "instance_id": self.INSTANCE_ID,
+ "key_data": pem,
+ }
+ )
module = setup_module_object()
mock_client().get_password_data.return_value = {
- 'InstanceId': self.INSTANCE_ID,
- 'PasswordData': self.ENCRYPTED_DATA,
- 'Timestamp': datetime.datetime.now(),
+ "InstanceId": self.INSTANCE_ID,
+ "PasswordData": self.ENCRYPTED_DATA,
+ "Timestamp": datetime.datetime.now(),
}
ec2_win_password(module)
self.assertEqual(
- exec_info.exception.args[0]['win_password'],
+ exec_info.exception.args[0]["win_password"],
to_bytes(self.UNENCRYPTED_DATA),
)
diff --git a/ansible_collections/community/aws/tests/unit/plugins/modules/test_iam_password_policy.py b/ansible_collections/community/aws/tests/unit/plugins/modules/test_iam_password_policy.py
deleted file mode 100644
index 11de7f477..000000000
--- a/ansible_collections/community/aws/tests/unit/plugins/modules/test_iam_password_policy.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import json
-import pytest
-
-from ansible_collections.community.aws.tests.unit.plugins.modules.utils import set_module_args
-
-from ansible_collections.community.aws.plugins.modules import iam_password_policy
-
-
-def test_warn_if_state_not_specified(capsys):
- set_module_args({
- "min_pw_length": "8",
- "require_symbols": "false",
- "require_numbers": "true",
- "require_uppercase": "true",
- "require_lowercase": "true",
- "allow_pw_change": "true",
- "pw_max_age": "60",
- "pw_reuse_prevent": "5",
- "pw_expire": "false"
- })
- with pytest.raises(SystemExit):
- iam_password_policy.main()
- captured = capsys.readouterr()
-
- output = json.loads(captured.out)
- assert 'missing required arguments' in output.get('msg', '')
diff --git a/ansible_collections/community/aws/tests/unit/plugins/modules/test_opensearch.py b/ansible_collections/community/aws/tests/unit/plugins/modules/test_opensearch.py
index 836e2cf07..7dcd785c9 100644
--- a/ansible_collections/community/aws/tests/unit/plugins/modules/test_opensearch.py
+++ b/ansible_collections/community/aws/tests/unit/plugins/modules/test_opensearch.py
@@ -1,86 +1,85 @@
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
__metaclass__ = type
import functools
-from ansible_collections.community.aws.plugins.module_utils.opensearch import (
- compare_domain_versions,
- parse_version,
-)
+
+from ansible_collections.community.aws.plugins.module_utils.opensearch import compare_domain_versions
+from ansible_collections.community.aws.plugins.module_utils.opensearch import parse_version
def test_parse_version():
test_versions = [
- ['Elasticsearch_5.5', {'engine_type': 'Elasticsearch', 'major': 5, 'minor': 5}],
- ['Elasticsearch_7.1', {'engine_type': 'Elasticsearch', 'major': 7, 'minor': 1}],
- ['Elasticsearch_7.10', {'engine_type': 'Elasticsearch', 'major': 7, 'minor': 10}],
- ['OpenSearch_1.0', {'engine_type': 'OpenSearch', 'major': 1, 'minor': 0}],
- ['OpenSearch_1.1', {'engine_type': 'OpenSearch', 'major': 1, 'minor': 1}],
- ['OpenSearch_a.b', None],
- ['OpenSearch_1.b', None],
- ['OpenSearch_1-1', None],
- ['OpenSearch_1.1.2', None],
- ['OpenSearch_foo_1.1', None],
- ['OpenSearch_1', None],
- ['OpenSearch-1.0', None],
- ['Foo_1.0', None],
+ ["Elasticsearch_5.5", {"engine_type": "Elasticsearch", "major": 5, "minor": 5}],
+ ["Elasticsearch_7.1", {"engine_type": "Elasticsearch", "major": 7, "minor": 1}],
+ ["Elasticsearch_7.10", {"engine_type": "Elasticsearch", "major": 7, "minor": 10}],
+ ["OpenSearch_1.0", {"engine_type": "OpenSearch", "major": 1, "minor": 0}],
+ ["OpenSearch_1.1", {"engine_type": "OpenSearch", "major": 1, "minor": 1}],
+ ["OpenSearch_a.b", None],
+ ["OpenSearch_1.b", None],
+ ["OpenSearch_1-1", None],
+ ["OpenSearch_1.1.2", None],
+ ["OpenSearch_foo_1.1", None],
+ ["OpenSearch_1", None],
+ ["OpenSearch-1.0", None],
+ ["Foo_1.0", None],
]
for expected in test_versions:
ret = parse_version(expected[0])
if ret != expected[1]:
- raise AssertionError(
- f"parse_version({expected[0]} returned {ret}, expected {expected[1]}")
+ raise AssertionError(f"parse_version({expected[0]} returned {ret}, expected {expected[1]}")
def test_version_compare():
test_versions = [
- ['Elasticsearch_5.5', 'Elasticsearch_5.5', 0],
- ['Elasticsearch_5.5', 'Elasticsearch_7.1', -1],
- ['Elasticsearch_7.1', 'Elasticsearch_7.1', 0],
- ['Elasticsearch_7.1', 'Elasticsearch_7.2', -1],
- ['Elasticsearch_7.1', 'Elasticsearch_7.10', -1],
- ['Elasticsearch_7.2', 'Elasticsearch_7.10', -1],
- ['Elasticsearch_7.10', 'Elasticsearch_7.2', 1],
- ['Elasticsearch_7.2', 'Elasticsearch_5.5', 1],
- ['Elasticsearch_7.2', 'OpenSearch_1.0', -1],
- ['Elasticsearch_7.2', 'OpenSearch_1.1', -1],
- ['OpenSearch_1.1', 'OpenSearch_1.1', 0],
- ['OpenSearch_1.0', 'OpenSearch_1.1', -1],
- ['OpenSearch_1.1', 'OpenSearch_1.0', 1],
- ['foo_1.1', 'OpenSearch_1.0', -1],
- ['Elasticsearch_5.5', 'foo_1.0', 1],
+ ["Elasticsearch_5.5", "Elasticsearch_5.5", 0],
+ ["Elasticsearch_5.5", "Elasticsearch_7.1", -1],
+ ["Elasticsearch_7.1", "Elasticsearch_7.1", 0],
+ ["Elasticsearch_7.1", "Elasticsearch_7.2", -1],
+ ["Elasticsearch_7.1", "Elasticsearch_7.10", -1],
+ ["Elasticsearch_7.2", "Elasticsearch_7.10", -1],
+ ["Elasticsearch_7.10", "Elasticsearch_7.2", 1],
+ ["Elasticsearch_7.2", "Elasticsearch_5.5", 1],
+ ["Elasticsearch_7.2", "OpenSearch_1.0", -1],
+ ["Elasticsearch_7.2", "OpenSearch_1.1", -1],
+ ["OpenSearch_1.1", "OpenSearch_1.1", 0],
+ ["OpenSearch_1.0", "OpenSearch_1.1", -1],
+ ["OpenSearch_1.1", "OpenSearch_1.0", 1],
+ ["foo_1.1", "OpenSearch_1.0", -1],
+ ["Elasticsearch_5.5", "foo_1.0", 1],
]
for v in test_versions:
ret = compare_domain_versions(v[0], v[1])
if ret != v[2]:
- raise AssertionError(
- f"compare({v[0]}, {v[1]} returned {ret}, expected {v[2]}")
+ raise AssertionError(f"compare({v[0]}, {v[1]} returned {ret}, expected {v[2]}")
def test_sort_versions():
input_versions = [
- 'Elasticsearch_5.6',
- 'Elasticsearch_5.5',
- 'Elasticsearch_7.10',
- 'Elasticsearch_7.2',
- 'foo_10.5',
- 'OpenSearch_1.1',
- 'OpenSearch_1.0',
- 'Elasticsearch_7.3',
+ "Elasticsearch_5.6",
+ "Elasticsearch_5.5",
+ "Elasticsearch_7.10",
+ "Elasticsearch_7.2",
+ "foo_10.5",
+ "OpenSearch_1.1",
+ "OpenSearch_1.0",
+ "Elasticsearch_7.3",
]
expected_versions = [
- 'foo_10.5',
- 'Elasticsearch_5.5',
- 'Elasticsearch_5.6',
- 'Elasticsearch_7.2',
- 'Elasticsearch_7.3',
- 'Elasticsearch_7.10',
- 'OpenSearch_1.0',
- 'OpenSearch_1.1',
+ "foo_10.5",
+ "Elasticsearch_5.5",
+ "Elasticsearch_5.6",
+ "Elasticsearch_7.2",
+ "Elasticsearch_7.3",
+ "Elasticsearch_7.10",
+ "OpenSearch_1.0",
+ "OpenSearch_1.1",
]
input_versions = sorted(input_versions, key=functools.cmp_to_key(compare_domain_versions))
if input_versions != expected_versions:
- raise AssertionError(
- f"Expected {expected_versions}, got {input_versions}")
+ raise AssertionError(f"Expected {expected_versions}, got {input_versions}")
diff --git a/ansible_collections/community/aws/tests/unit/plugins/modules/test_redshift_cross_region_snapshots.py b/ansible_collections/community/aws/tests/unit/plugins/modules/test_redshift_cross_region_snapshots.py
index 7b22d5b00..1342a8d58 100644
--- a/ansible_collections/community/aws/tests/unit/plugins/modules/test_redshift_cross_region_snapshots.py
+++ b/ansible_collections/community/aws/tests/unit/plugins/modules/test_redshift_cross_region_snapshots.py
@@ -1,40 +1,41 @@
# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
__metaclass__ = type
from ansible_collections.community.aws.plugins.modules import redshift_cross_region_snapshots as rcrs
mock_status_enabled = {
- 'SnapshotCopyGrantName': 'snapshot-us-east-1-to-us-west-2',
- 'DestinationRegion': 'us-west-2',
- 'RetentionPeriod': 1,
+ "SnapshotCopyGrantName": "snapshot-us-east-1-to-us-west-2",
+ "DestinationRegion": "us-west-2",
+ "RetentionPeriod": 1,
}
mock_status_disabled = {}
mock_request_illegal = {
- 'snapshot_copy_grant': 'changed',
- 'destination_region': 'us-west-2',
- 'snapshot_retention_period': 1
+ "snapshot_copy_grant": "changed",
+ "destination_region": "us-west-2",
+ "snapshot_retention_period": 1,
}
mock_request_update = {
- 'snapshot_copy_grant': 'snapshot-us-east-1-to-us-west-2',
- 'destination_region': 'us-west-2',
- 'snapshot_retention_period': 3
+ "snapshot_copy_grant": "snapshot-us-east-1-to-us-west-2",
+ "destination_region": "us-west-2",
+ "snapshot_retention_period": 3,
}
mock_request_no_update = {
- 'snapshot_copy_grant': 'snapshot-us-east-1-to-us-west-2',
- 'destination_region': 'us-west-2',
- 'snapshot_retention_period': 1
+ "snapshot_copy_grant": "snapshot-us-east-1-to-us-west-2",
+ "destination_region": "us-west-2",
+ "snapshot_retention_period": 1,
}
def test_fail_at_unsupported_operations():
- response = rcrs.requesting_unsupported_modifications(
- mock_status_enabled, mock_request_illegal
- )
+ response = rcrs.requesting_unsupported_modifications(mock_status_enabled, mock_request_illegal)
assert response is True
@@ -44,9 +45,7 @@ def test_needs_update_true():
def test_no_change():
- response = rcrs.requesting_unsupported_modifications(
- mock_status_enabled, mock_request_no_update
- )
+ response = rcrs.requesting_unsupported_modifications(mock_status_enabled, mock_request_no_update)
needs_update_response = rcrs.needs_update(mock_status_enabled, mock_request_no_update)
assert response is False
assert needs_update_response is False
diff --git a/ansible_collections/community/aws/tests/unit/plugins/modules/test_route53_wait.py b/ansible_collections/community/aws/tests/unit/plugins/modules/test_route53_wait.py
new file mode 100644
index 000000000..57ed705c5
--- /dev/null
+++ b/ansible_collections/community/aws/tests/unit/plugins/modules/test_route53_wait.py
@@ -0,0 +1,240 @@
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+import pytest
+
+from ansible_collections.community.aws.plugins.modules.route53_wait import detect_task_results
+
+_SINGLE_RESULT_SUCCESS = {
+ "changed": True,
+ "diff": {},
+ "failed": False,
+ "wait_id": None,
+}
+
+_SINGLE_RESULT_FAILED = {
+ "changed": False,
+ "failed": True,
+ "msg": "value of type must be one of: A, AAAA, CAA, CNAME, MX, NS, PTR, SOA, SPF, SRV, TXT, got: bar",
+}
+
+_MULTI_RESULT_SUCCESS = {
+ "ansible_loop_var": "item",
+ "changed": True,
+ "diff": {},
+ "failed": False,
+ "invocation": {
+ "module_args": {
+ "access_key": "asdf",
+ "alias": None,
+ "alias_evaluate_target_health": False,
+ "alias_hosted_zone_id": None,
+ "aws_access_key": "asdf",
+ "aws_ca_bundle": None,
+ "aws_config": None,
+ "aws_secret_key": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
+ "debug_botocore_endpoint_logs": False,
+ "endpoint_url": None,
+ "failover": None,
+ "geo_location": None,
+ "health_check": None,
+ "hosted_zone_id": None,
+ "identifier": None,
+ "overwrite": True,
+ "private_zone": False,
+ "profile": None,
+ "record": "foo.example.org",
+ "region": None,
+ "retry_interval": 500,
+ "secret_key": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
+ "session_token": None,
+ "state": "present",
+ "ttl": 300,
+ "type": "TXT",
+ "validate_certs": True,
+ "value": ["foo"],
+ "vpc_id": None,
+ "wait": False,
+ "wait_timeout": 300,
+ "weight": None,
+ "zone": "example.org",
+ },
+ },
+ "item": {"record": "foo.example.org", "value": "foo"},
+ "wait_id": None,
+}
+
+_MULTI_RESULT_FAILED = {
+ "ansible_loop_var": "item",
+ "changed": False,
+ "failed": True,
+ "invocation": {
+ "module_args": {
+ "access_key": "asdf",
+ "alias": None,
+ "alias_evaluate_target_health": False,
+ "alias_hosted_zone_id": None,
+ "aws_access_key": "asdf",
+ "aws_ca_bundle": None,
+ "aws_config": None,
+ "aws_secret_key": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
+ "debug_botocore_endpoint_logs": False,
+ "endpoint_url": None,
+ "failover": None,
+ "geo_location": None,
+ "health_check": None,
+ "hosted_zone_id": None,
+ "identifier": None,
+ "overwrite": True,
+ "private_zone": False,
+ "profile": None,
+ "record": "foo.example.org",
+ "region": None,
+ "retry_interval": 500,
+ "secret_key": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
+ "session_token": None,
+ "state": "present",
+ "ttl": 300,
+ "type": "bar",
+ "validate_certs": True,
+ "value": ["foo"],
+ "vpc_id": None,
+ "wait": False,
+ "wait_timeout": 300,
+ "weight": None,
+ "zone": "example.org",
+ },
+ },
+ "item": {"record": "foo.example.org", "value": "foo"},
+ "msg": "value of type must be one of: A, AAAA, CAA, CNAME, MX, NS, PTR, SOA, SPF, SRV, TXT, got: bar",
+}
+
+
+DETECT_TASK_RESULTS_DATA = [
+ [
+ _SINGLE_RESULT_SUCCESS,
+ [
+ (
+ "",
+ _SINGLE_RESULT_SUCCESS,
+ ),
+ ],
+ ],
+ [
+ {
+ "changed": True,
+ "msg": "All items completed",
+ "results": [
+ _MULTI_RESULT_SUCCESS,
+ ],
+ "skipped": False,
+ },
+ [
+ (
+ " for result #1",
+ _MULTI_RESULT_SUCCESS,
+ ),
+ ],
+ ],
+ [
+ _SINGLE_RESULT_FAILED,
+ [
+ (
+ "",
+ _SINGLE_RESULT_FAILED,
+ ),
+ ],
+ ],
+ [
+ {
+ "changed": False,
+ "failed": True,
+ "msg": "One or more items failed",
+ "results": [
+ _MULTI_RESULT_FAILED,
+ ],
+ "skipped": False,
+ },
+ [
+ (
+ " for result #1",
+ _MULTI_RESULT_FAILED,
+ ),
+ ],
+ ],
+]
+
+
+@pytest.mark.parametrize(
+ "input, expected",
+ DETECT_TASK_RESULTS_DATA,
+)
+def test_detect_task_results(input, expected):
+ assert list(detect_task_results(input)) == expected
+
+
+DETECT_TASK_RESULTS_FAIL_DATA = [
+ [
+ {},
+ "missing changed key",
+ [],
+ ],
+ [
+ {"changed": True},
+ "missing failed key",
+ [],
+ ],
+ [
+ {"results": None},
+ "missing changed key",
+ [],
+ ],
+ [
+ {"results": None, "changed": True, "msg": "foo"},
+ "missing skipped key",
+ [],
+ ],
+ [
+ {"results": None, "changed": True, "msg": "foo", "skipped": False},
+ "results is present, but not a list",
+ [],
+ ],
+ [
+ {"results": [None], "changed": True, "msg": "foo", "skipped": False},
+ "result 1 is not a dictionary",
+ [],
+ ],
+ [
+ {"results": [{}], "changed": True, "msg": "foo", "skipped": False},
+ "missing changed key for result 1",
+ [],
+ ],
+ [
+ {
+ "results": [{"changed": True, "failed": False, "ansible_loop_var": "item", "invocation": {}}, {}],
+ "changed": True,
+ "msg": "foo",
+ "skipped": False,
+ },
+ "missing changed key for result 2",
+ [(" for result #1", {"changed": True, "failed": False, "ansible_loop_var": "item", "invocation": {}})],
+ ],
+]
+
+
+@pytest.mark.parametrize(
+ "input, expected_exc, expected_result",
+ DETECT_TASK_RESULTS_FAIL_DATA,
+)
+def test_detect_task_fail_results(input, expected_exc, expected_result):
+ result = []
+ with pytest.raises(ValueError) as exc:
+ for res in detect_task_results(input):
+ result.append(res)
+
+ print(exc.value.args[0])
+ assert expected_exc == exc.value.args[0]
+ print(result)
+ assert expected_result == result
diff --git a/ansible_collections/community/aws/tests/unit/plugins/modules/test_ssm_inventory_info.py b/ansible_collections/community/aws/tests/unit/plugins/modules/test_ssm_inventory_info.py
new file mode 100644
index 000000000..518a11a3b
--- /dev/null
+++ b/ansible_collections/community/aws/tests/unit/plugins/modules/test_ssm_inventory_info.py
@@ -0,0 +1,117 @@
+# -*- coding: utf-8 -*-
+
+# Copyright: Contributors to the Ansible project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from unittest.mock import MagicMock
+from unittest.mock import patch
+
+import pytest
+from botocore.exceptions import BotoCoreError
+
+from ansible_collections.community.aws.plugins.modules.ssm_inventory_info import SsmInventoryInfoFailure
+from ansible_collections.community.aws.plugins.modules.ssm_inventory_info import execute_module
+from ansible_collections.community.aws.plugins.modules.ssm_inventory_info import get_ssm_inventory
+
+
+def test_get_ssm_inventory():
+ connection = MagicMock()
+ inventory_response = MagicMock()
+ connection.get_inventory.return_value = inventory_response
+ filters = MagicMock()
+
+ assert get_ssm_inventory(connection, filters) == inventory_response
+ connection.get_inventory.assert_called_once_with(Filters=filters)
+
+
+def test_get_ssm_inventory_failure():
+ connection = MagicMock()
+ connection.get_inventory.side_effect = BotoCoreError(error="failed", operation="get_ssm_inventory")
+ filters = MagicMock()
+
+ with pytest.raises(SsmInventoryInfoFailure):
+ get_ssm_inventory(connection, filters)
+
+
+@patch("ansible_collections.community.aws.plugins.modules.ssm_inventory_info.get_ssm_inventory")
+def test_execute_module(m_get_ssm_inventory):
+ instance_id = "i-0202020202020202"
+ aws_inventory = {
+ "AgentType": "amazon-ssm-agent",
+ "AgentVersion": "3.2.582.0",
+ "ComputerName": "ip-172-31-44-166.ec2.internal",
+ "InstanceId": "i-039eb9b1f55934ab6",
+ "InstanceStatus": "Active",
+ "IpAddress": "172.31.44.166",
+ "PlatformName": "Fedora Linux",
+ "PlatformType": "Linux",
+ "PlatformVersion": "37",
+ "ResourceType": "EC2Instance",
+ }
+
+ ansible_inventory = {
+ "agent_type": "amazon-ssm-agent",
+ "agent_version": "3.2.582.0",
+ "computer_name": "ip-172-31-44-166.ec2.internal",
+ "instance_id": "i-039eb9b1f55934ab6",
+ "instance_status": "Active",
+ "ip_address": "172.31.44.166",
+ "platform_name": "Fedora Linux",
+ "platform_type": "Linux",
+ "platform_version": "37",
+ "resource_type": "EC2Instance",
+ }
+
+ m_get_ssm_inventory.return_value = {
+ "Entities": [{"Id": instance_id, "Data": {"AWS:InstanceInformation": {"Content": [aws_inventory]}}}],
+ "Status": 200,
+ }
+
+ connection = MagicMock()
+ module = MagicMock()
+ module.params = dict(instance_id=instance_id)
+ module.exit_json.side_effect = SystemExit(1)
+ module.fail_json_aws.side_effect = SystemError(2)
+
+ with pytest.raises(SystemExit):
+ execute_module(module, connection)
+
+ module.exit_json.assert_called_once_with(changed=False, ssm_inventory=ansible_inventory)
+
+
+@patch("ansible_collections.community.aws.plugins.modules.ssm_inventory_info.get_ssm_inventory")
+def test_execute_module_no_data(m_get_ssm_inventory):
+ instance_id = "i-0202020202020202"
+
+ m_get_ssm_inventory.return_value = {
+ "Entities": [{"Id": instance_id, "Data": {}}],
+ }
+
+ connection = MagicMock()
+ module = MagicMock()
+ module.params = dict(instance_id=instance_id)
+ module.exit_json.side_effect = SystemExit(1)
+ module.fail_json_aws.side_effect = SystemError(2)
+
+ with pytest.raises(SystemExit):
+ execute_module(module, connection)
+
+ module.exit_json.assert_called_once_with(changed=False, ssm_inventory={})
+
+
+@patch("ansible_collections.community.aws.plugins.modules.ssm_inventory_info.get_ssm_inventory")
+def test_execute_module_failure(m_get_ssm_inventory):
+ instance_id = "i-0202020202020202"
+
+ m_get_ssm_inventory.side_effect = SsmInventoryInfoFailure(
+ exc=BotoCoreError(error="failed", operation="get_ssm_inventory"), msg="get_ssm_inventory() failed."
+ )
+
+ connection = MagicMock()
+ module = MagicMock()
+ module.params = dict(instance_id=instance_id)
+ module.exit_json.side_effect = SystemExit(1)
+ module.fail_json_aws.side_effect = SystemError(2)
+
+ with pytest.raises(SystemError):
+ execute_module(module, connection)
diff --git a/ansible_collections/community/aws/tests/unit/plugins/modules/utils.py b/ansible_collections/community/aws/tests/unit/plugins/modules/utils.py
index 026bf2549..a3d9e31db 100644
--- a/ansible_collections/community/aws/tests/unit/plugins/modules/utils.py
+++ b/ansible_collections/community/aws/tests/unit/plugins/modules/utils.py
@@ -1,23 +1,20 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
import json
+import unittest
+from unittest.mock import patch
-from ansible_collections.community.aws.tests.unit.compat import unittest
-from ansible_collections.community.aws.tests.unit.compat.mock import patch
from ansible.module_utils import basic
from ansible.module_utils._text import to_bytes
def set_module_args(args):
- if '_ansible_remote_tmp' not in args:
- args['_ansible_remote_tmp'] = '/tmp'
- if '_ansible_keep_remote_files' not in args:
- args['_ansible_keep_remote_files'] = False
+ if "_ansible_remote_tmp" not in args:
+ args["_ansible_remote_tmp"] = "/tmp"
+ if "_ansible_keep_remote_files" not in args:
+ args["_ansible_keep_remote_files"] = False
- args = json.dumps({'ANSIBLE_MODULE_ARGS': args})
+ args = json.dumps({"ANSIBLE_MODULE_ARGS": args})
basic._ANSIBLE_ARGS = to_bytes(args)
@@ -30,22 +27,21 @@ class AnsibleFailJson(Exception):
def exit_json(*args, **kwargs):
- if 'changed' not in kwargs:
- kwargs['changed'] = False
+ if "changed" not in kwargs:
+ kwargs["changed"] = False
raise AnsibleExitJson(kwargs)
def fail_json(*args, **kwargs):
- kwargs['failed'] = True
+ kwargs["failed"] = True
raise AnsibleFailJson(kwargs)
class ModuleTestCase(unittest.TestCase):
-
def setUp(self):
self.mock_module = patch.multiple(basic.AnsibleModule, exit_json=exit_json, fail_json=fail_json)
self.mock_module.start()
- self.mock_sleep = patch('time.sleep')
+ self.mock_sleep = patch("time.sleep")
self.mock_sleep.start()
set_module_args({})
self.addCleanup(self.mock_module.stop)
diff --git a/ansible_collections/community/aws/tests/unit/requirements.yml b/ansible_collections/community/aws/tests/unit/requirements.yml
new file mode 100644
index 000000000..99ce82a1b
--- /dev/null
+++ b/ansible_collections/community/aws/tests/unit/requirements.yml
@@ -0,0 +1,5 @@
+---
+collections:
+ - name: https://github.com/ansible-collections/amazon.aws.git
+ type: git
+ version: main
diff --git a/ansible_collections/community/aws/tox.ini b/ansible_collections/community/aws/tox.ini
new file mode 100644
index 000000000..179ed761c
--- /dev/null
+++ b/ansible_collections/community/aws/tox.ini
@@ -0,0 +1,104 @@
+[tox]
+skipsdist = True
+envlist = clean,ansible{2.12,2.13}-py{38,39,310}-{with_constraints,without_constraints},linters
+# Tox4 supports labels which allow us to group the environments rather than dumping all commands into a single environment
+labels =
+ format = flynt, black, isort
+ lint = complexity-report, ansible-lint, black-lint, isort-lint, flake8-lint, flynt-lint
+ units = ansible{2.12,2.13}-py{38,39,310}-{with_constraints,without_constraints}
+
+[common]
+format_dirs = {toxinidir}/plugins {toxinidir}/tests
+
+[testenv]
+description = Run the test-suite and generate a HTML coverage report
+deps =
+ pytest
+ pytest-cov
+ ansible2.12: ansible-core>2.12,<2.13
+ ansible2.13: ansible-core>2.13,<2.14
+ !ansible2.12-!ansible2.13: ansible-core
+ pytest-ansible
+ -rtest-requirements.txt
+ with_constraints: -rtests/unit/constraints.txt
+commands = pytest --cov-report html --cov plugins/callback --cov plugins/inventory --cov plugins/lookup --cov plugins/module_utils --cov plugins/modules --cov plugins/plugin_utils plugins {posargs:tests/}
+
+[testenv:clean]
+deps = coverage
+skip_install = true
+commands = coverage erase
+
+[testenv:complexity-report]
+description = Generate a HTML complexity report in the complexity directory
+deps =
+ # See: https://github.com/lordmauve/flake8-html/issues/30
+ flake8>=3.3.0,<5.0.0
+ flake8-html
+commands = -flake8 --select C90 --max-complexity 10 --format=html --htmldir={posargs:complexity} plugins
+
+[testenv:ansible-lint]
+deps =
+ ansible-lint
+commands =
+ ansible-lint {toxinidir}/plugins
+
+[testenv:black]
+depends =
+ flynt, isort
+deps =
+ black >=23.0, <24.0
+commands =
+ black {[common]format_dirs}
+
+[testenv:black-lint]
+deps =
+ {[testenv:black]deps}
+commands =
+ black -v --check --diff {[common]format_dirs}
+
+[testenv:isort]
+deps =
+ isort
+commands =
+ isort {[common]format_dirs}
+
+[testenv:isort-lint]
+deps =
+ {[testenv:isort]deps}
+commands =
+ isort --check-only --diff {[common]format_dirs}
+
+[testenv:flake8-lint]
+deps =
+ flake8
+commands =
+ flake8 {posargs} {[common]format_dirs}
+
+[testenv:flynt]
+deps =
+ flynt
+commands =
+ flynt {[common]format_dirs}
+
+[testenv:flynt-lint]
+deps =
+ flynt
+commands =
+ flynt --dry-run {[common]format_dirs}
+
+[testenv:linters]
+deps =
+ {[testenv:black]deps}
+ {[testenv:isort]deps}
+ flake8
+commands =
+ black -v --check {toxinidir}/plugins {toxinidir}/tests
+ isort --check-only --diff {toxinidir}/plugins {toxinidir}/tests
+ flake8 {posargs} {toxinidir}/plugins {toxinidir}/tests
+
+[flake8]
+# E123, E125 skipped as they are invalid PEP-8.
+show-source = True
+ignore = E123,E125,E203,E402,E501,E741,F401,F811,F841,W503
+max-line-length = 160
+builtins = _
diff --git a/ansible_collections/community/ciscosmb/CHANGELOG.rst b/ansible_collections/community/ciscosmb/CHANGELOG.rst
index 757936b88..fb3bc6cc0 100644
--- a/ansible_collections/community/ciscosmb/CHANGELOG.rst
+++ b/ansible_collections/community/ciscosmb/CHANGELOG.rst
@@ -5,6 +5,23 @@ CiscoSMB Ansible module Release Notes
.. contents:: Topics
+v1.0.7
+======
+
+Release Summary
+---------------
+
+Release Date: 2023-10-30
+Fix issue on CSB-350 #69
+Clarify configuration doc #66 #64
+
+
+Bugfixes
+--------
+
+- added Cisco device config guide to address issue
+- added extra "\n" to sending commands to address issue
+
v1.0.6
======
diff --git a/ansible_collections/community/ciscosmb/FILES.json b/ansible_collections/community/ciscosmb/FILES.json
index da8c6bb63..cc62fa878 100644
--- a/ansible_collections/community/ciscosmb/FILES.json
+++ b/ansible_collections/community/ciscosmb/FILES.json
@@ -60,7 +60,7 @@
"name": "changelogs/changelog.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1475b799849c551683334960b06c7281d746541d5d6d22982b3ed044e4182ce0",
+ "chksum_sha256": "a3610efbe7df3df55e25d674d38c6f9681680cc6807e3af36cac886440c6346c",
"format": 1
},
{
@@ -102,7 +102,7 @@
"name": "plugins/cliconf/ciscosmb.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1c63934612718d641d0535b99b8a5e0007f47c1269e4966aaa74dfbc1ed48793",
+ "chksum_sha256": "b5bb0ff1d5658fc7d4e8a4337430c13f1289ffba4d49089fdc8a075a91ccbe95",
"format": 1
},
{
@@ -704,7 +704,7 @@
"name": "CHANGELOG.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8dd9df5c99f767b9fd9aa148f152a8d51c233013f7f50e87db55aaeb569a4d4d",
+ "chksum_sha256": "482e1b4cebbd09bb0d8f7b0876ddffd6477af428618f284e1180a583401a8cbb",
"format": 1
},
{
@@ -732,7 +732,7 @@
"name": "README.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5b3d106a2c6bb28a82fabe1ddd14d2a4b993db064d723466bb7b99b2a248af0f",
+ "chksum_sha256": "40d7260f4d76c77e48a364647b75e113ce91d0e18ad67b13207e14cec08718e1",
"format": 1
},
{
diff --git a/ansible_collections/community/ciscosmb/MANIFEST.json b/ansible_collections/community/ciscosmb/MANIFEST.json
index 05a85dc66..2a98111d7 100644
--- a/ansible_collections/community/ciscosmb/MANIFEST.json
+++ b/ansible_collections/community/ciscosmb/MANIFEST.json
@@ -2,7 +2,7 @@
"collection_info": {
"namespace": "community",
"name": "ciscosmb",
- "version": "1.0.6",
+ "version": "1.0.7",
"authors": [
"Petr Kl\u00edma <qaxi@seznam.cz>"
],
@@ -35,7 +35,7 @@
"name": "FILES.json",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0c683d4e8c5cea322d7432678aab55221fee7735eefac38f987f581a123c68f2",
+ "chksum_sha256": "922f00a582a76f8d668444f41338cfc356b64945bfe4149e7a12ac1e838c03b4",
"format": 1
},
"format": 1
diff --git a/ansible_collections/community/ciscosmb/README.md b/ansible_collections/community/ciscosmb/README.md
index 703afb1c2..0ddae236a 100644
--- a/ansible_collections/community/ciscosmb/README.md
+++ b/ansible_collections/community/ciscosmb/README.md
@@ -18,6 +18,40 @@ Tested on devices:
* CBS350-24P-4G
* SG550X-48 stack
+### Required device configuration
+
+Access setup
+```
+! you should set enable password
+enable password level 15
+
+! on user you have two choices
+! use unpriviledged user (for example priv. 7) and "become mode"
+username user1 privilege 7
+
+! or user with full privileges (priv 15)
+username user2 privelege 15
+```
+
+Cisco's SSH server setup
+```
+! you have to enable SSH server
+ip ssh server
+! enable password and/or key
+ip ssh password-auth
+ip ssh pubkey-auth auto-login
+! generate switch ssh key pair if you did not before
+crypto key generate rsa
+
+! if you use public keys for users login configure that keys
+crypto key pubkey-chain ssh
+user-key user2 rsa
+key-string AAAAB3NzaC1......XYZ==
+exit
+```
+
+### Python versions
+
Tested on Python versions:
* 3.6
* 3.7
@@ -25,6 +59,8 @@ Tested on Python versions:
* 3.9
* 3.10
+### Running examples
+
For your tests or quick startup use files form repository: [cismosmb_inventory_template.yml](./ciscosmb_inventory_template.yml), [cismosmb_gather_facts.yml](./ciscosmb_gather_facts.yml), [cismosmb_commands.yml](./ciscosmb_commands.yml) .
Prepare your inventory file - copy file [cismosmb_inventory_template.yml](./ciscosmb_inventory_template.yml) to `cismosmb_inventory.yml` and make your changes.
diff --git a/ansible_collections/community/ciscosmb/changelogs/changelog.yaml b/ansible_collections/community/ciscosmb/changelogs/changelog.yaml
index 0666ff449..41e81a1b7 100644
--- a/ansible_collections/community/ciscosmb/changelogs/changelog.yaml
+++ b/ansible_collections/community/ciscosmb/changelogs/changelog.yaml
@@ -174,3 +174,20 @@ releases:
- playbook_examples.yml
- release-1.0.6.yml
release_date: '2023-05-23'
+ 1.0.7:
+ changes:
+ bugfixes:
+ - added Cisco device config guide to address issue
+ - added extra "\n" to sending commands to address issue
+ release_summary: 'Release Date: 2023-10-30
+
+ Fix issue on CSB-350 #69
+
+ Clarify configuration doc #66 #64
+
+ '
+ fragments:
+ - issue66.yml
+ - issue69.yml
+ - release-1.0.7.yml
+ release_date: '2023-10-30'
diff --git a/ansible_collections/community/ciscosmb/plugins/cliconf/ciscosmb.py b/ansible_collections/community/ciscosmb/plugins/cliconf/ciscosmb.py
index 922edeb69..b3f4b1afa 100644
--- a/ansible_collections/community/ciscosmb/plugins/cliconf/ciscosmb.py
+++ b/ansible_collections/community/ciscosmb/plugins/cliconf/ciscosmb.py
@@ -70,7 +70,7 @@ class Cliconf(CliconfBase):
return
def get(self, command, prompt=None, answer=None, sendonly=False, newline=True, check_all=False):
- return self.send_command(command=command, prompt=prompt, answer=answer, sendonly=sendonly, newline=newline, check_all=check_all)
+ return self.send_command(command=command + "\n", prompt=prompt, answer=answer, sendonly=sendonly, newline=newline, check_all=check_all)
def get_capabilities(self):
result = super().get_capabilities()
diff --git a/ansible_collections/community/crypto/.azure-pipelines/azure-pipelines.yml b/ansible_collections/community/crypto/.azure-pipelines/azure-pipelines.yml
index d9ae3f866..8697acd43 100644
--- a/ansible_collections/community/crypto/.azure-pipelines/azure-pipelines.yml
+++ b/ansible_collections/community/crypto/.azure-pipelines/azure-pipelines.yml
@@ -46,7 +46,7 @@ variables:
resources:
containers:
- container: default
- image: quay.io/ansible/azure-pipelines-test-container:3.0.0
+ image: quay.io/ansible/azure-pipelines-test-container:4.0.1
pool: Standard
@@ -65,6 +65,17 @@ stages:
test: 'devel/sanity/extra'
- name: Units
test: 'devel/units/1'
+ - stage: Ansible_2_16
+ displayName: Sanity & Units 2.16
+ dependsOn: []
+ jobs:
+ - template: templates/matrix.yml
+ parameters:
+ targets:
+ - name: Sanity
+ test: '2.16/sanity/1'
+ - name: Units
+ test: '2.16/units/1'
- stage: Ansible_2_15
displayName: Sanity & Units 2.15
dependsOn: []
@@ -87,17 +98,6 @@ stages:
test: '2.14/sanity/1'
- name: Units
test: '2.14/units/1'
- - stage: Ansible_2_13
- displayName: Sanity & Units 2.13
- dependsOn: []
- jobs:
- - template: templates/matrix.yml
- parameters:
- targets:
- - name: Sanity
- test: '2.13/sanity/1'
- - name: Units
- test: '2.13/units/1'
### Docker
- stage: Docker_devel
displayName: Docker devel
@@ -107,12 +107,8 @@ stages:
parameters:
testFormat: devel/linux/{0}
targets:
- - name: Fedora 37
- test: fedora37
- - name: openSUSE 15
- test: opensuse15
- - name: Ubuntu 20.04
- test: ubuntu2004
+ - name: Fedora 39
+ test: fedora39
- name: Ubuntu 22.04
test: ubuntu2204
- name: Alpine 3
@@ -120,50 +116,46 @@ stages:
groups:
- 1
- 2
- - stage: Docker_2_15
- displayName: Docker 2.15
+ - stage: Docker_2_16
+ displayName: Docker 2.16
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
- testFormat: 2.15/linux/{0}
+ testFormat: 2.16/linux/{0}
targets:
- - name: CentOS 7
- test: centos7
+ - name: Fedora 38
+ test: fedora38
+ - name: openSUSE 15
+ test: opensuse15
groups:
- 1
- 2
- - stage: Docker_2_14
- displayName: Docker 2.14
+ - stage: Docker_2_15
+ displayName: Docker 2.15
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
- testFormat: 2.14/linux/{0}
+ testFormat: 2.15/linux/{0}
targets:
- - name: Fedora 36
- test: fedora36
+ - name: Fedora 37
+ test: fedora37
+ - name: CentOS 7
+ test: centos7
groups:
- 1
- 2
- - stage: Docker_2_13
- displayName: Docker 2.13
+ - stage: Docker_2_14
+ displayName: Docker 2.14
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
- testFormat: 2.13/linux/{0}
+ testFormat: 2.14/linux/{0}
targets:
- - name: openSUSE 15 py2
- test: opensuse15py2
- - name: Fedora 35
- test: fedora35
- - name: Fedora 34
- test: fedora34
- - name: Ubuntu 18.04
- test: ubuntu1804
- - name: Alpine 3
- test: alpine3
+ - name: Ubuntu 20.04
+ test: ubuntu2004
groups:
- 1
- 2
@@ -179,12 +171,10 @@ stages:
targets:
- name: Debian Bullseye
test: debian-bullseye/3.9
+ - name: Debian Bookworm
+ test: debian-bookworm/3.11
- name: ArchLinux
test: archlinux/3.11
- - name: CentOS Stream 8 with Python 3.9
- test: centos-stream8/3.9
- - name: CentOS Stream 8 with Python 3.6
- test: centos-stream8/3.6
groups:
- 1
- 2
@@ -198,12 +188,10 @@ stages:
parameters:
testFormat: devel/{0}
targets:
- - name: Alpine 3.17
- test: alpine/3.17
- - name: Fedora 37
- test: fedora/37
- - name: Ubuntu 20.04
- test: ubuntu/20.04
+ - name: Alpine 3.18
+ test: alpine/3.18
+ - name: Fedora 39
+ test: fedora/39
- name: Ubuntu 22.04
test: ubuntu/22.04
groups:
@@ -218,15 +206,28 @@ stages:
targets:
- name: macOS 13.2
test: macos/13.2
- - name: RHEL 9.1
- test: rhel/9.1
- - name: FreeBSD 12.4
- test: freebsd/12.4
+ - name: RHEL 9.3
+ test: rhel/9.3
- name: FreeBSD 13.2
test: freebsd/13.2
groups:
- 1
- 2
+ - stage: Remote_2_16
+ displayName: Remote 2.16
+ dependsOn: []
+ jobs:
+ - template: templates/matrix.yml
+ parameters:
+ testFormat: 2.16/{0}
+ targets:
+ - name: RHEL 9.2
+ test: rhel/9.2
+ - name: RHEL 8.8
+ test: rhel/8.8
+ groups:
+ - 1
+ - 2
- stage: Remote_2_15
displayName: Remote 2.15
dependsOn: []
@@ -235,10 +236,16 @@ stages:
parameters:
testFormat: 2.15/{0}
targets:
+ - name: RHEL 9.1
+ test: rhel/9.1
+ - name: RHEL 8.7
+ test: rhel/8.7
- name: RHEL 7.9
test: rhel/7.9
- - name: FreeBSD 13.1
- test: freebsd/13.1
+ # - name: FreeBSD 13.1
+ # test: freebsd/13.1
+ # - name: FreeBSD 12.4
+ # test: freebsd/12.4
groups:
- 1
- 2
@@ -250,27 +257,12 @@ stages:
parameters:
testFormat: 2.14/{0}
targets:
- - name: macOS 12.0
- test: macos/12.0
+ #- name: macOS 12.0
+ # test: macos/12.0
- name: RHEL 9.0
test: rhel/9.0
- - name: FreeBSD 12.3
- test: freebsd/12.3
- groups:
- - 1
- - 2
- - stage: Remote_2_13
- displayName: Remote 2.13
- dependsOn: []
- jobs:
- - template: templates/matrix.yml
- parameters:
- testFormat: 2.13/{0}
- targets:
- - name: RHEL 8.5
- test: rhel/8.5
- - name: FreeBSD 13.0
- test: freebsd/13.0
+ #- name: FreeBSD 12.4
+ # test: freebsd/12.4
groups:
- 1
- 2
@@ -284,53 +276,54 @@ stages:
nameFormat: Python {0}
testFormat: devel/generic/{0}
targets:
- - test: 2.7
- - test: 3.6
- test: 3.7
# - test: 3.8
# - test: 3.9
# - test: "3.10"
- test: "3.11"
+ - test: "3.12"
groups:
- 1
- 2
- - stage: Generic_2_15
- displayName: Generic 2.15
+ - stage: Generic_2_16
+ displayName: Generic 2.16
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
nameFormat: Python {0}
- testFormat: 2.15/generic/{0}
+ testFormat: 2.16/generic/{0}
targets:
- - test: 3.5
- - test: "3.10"
+ - test: "2.7"
+ - test: "3.6"
+ - test: "3.11"
groups:
- 1
- 2
- - stage: Generic_2_14
- displayName: Generic 2.14
+ - stage: Generic_2_15
+ displayName: Generic 2.15
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
nameFormat: Python {0}
- testFormat: 2.14/generic/{0}
+ testFormat: 2.15/generic/{0}
targets:
- - test: 3.9
+ - test: 3.5
+ - test: "3.10"
groups:
- 1
- 2
- - stage: Generic_2_13
- displayName: Generic 2.13
+ - stage: Generic_2_14
+ displayName: Generic 2.14
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
nameFormat: Python {0}
- testFormat: 2.13/generic/{0}
+ testFormat: 2.14/generic/{0}
targets:
- - test: 3.8
+ - test: 3.9
groups:
- 1
- 2
@@ -341,22 +334,22 @@ stages:
condition: succeededOrFailed()
dependsOn:
- Ansible_devel
+ - Ansible_2_16
- Ansible_2_15
- Ansible_2_14
- - Ansible_2_13
- Remote_devel_extra_vms
- Remote_devel
+ - Remote_2_16
- Remote_2_15
- Remote_2_14
- - Remote_2_13
- Docker_devel
+ - Docker_2_16
- Docker_2_15
- Docker_2_14
- - Docker_2_13
- Docker_community_devel
- Generic_devel
+ - Generic_2_16
- Generic_2_15
- Generic_2_14
- - Generic_2_13
jobs:
- template: templates/coverage.yml
diff --git a/ansible_collections/community/crypto/.github/workflows/ansible-test.yml b/ansible_collections/community/crypto/.github/workflows/ansible-test.yml
index 325dc5275..be831028b 100644
--- a/ansible_collections/community/crypto/.github/workflows/ansible-test.yml
+++ b/ansible_collections/community/crypto/.github/workflows/ansible-test.yml
@@ -33,6 +33,7 @@ jobs:
- '2.10'
- '2.11'
- '2.12'
+ - '2.13'
# Ansible-test on various stable branches does not yet work well with cgroups v2.
# Since ubuntu-latest now uses Ubuntu 22.04, we need to fall back to the ubuntu-20.04
# image for these stable branches. The list of branches where this is necessary will
@@ -72,6 +73,7 @@ jobs:
- '2.10'
- '2.11'
- '2.12'
+ - '2.13'
steps:
- name: >-
@@ -202,6 +204,55 @@ jobs:
docker: default
python: '3.9'
target: azp/generic/2/
+ # 2.13
+ - ansible: '2.13'
+ docker: opensuse15py2
+ python: ''
+ target: azp/posix/1/
+ - ansible: '2.13'
+ docker: opensuse15py2
+ python: ''
+ target: azp/posix/2/
+ - ansible: '2.13'
+ docker: fedora35
+ python: ''
+ target: azp/posix/1/
+ - ansible: '2.13'
+ docker: fedora35
+ python: ''
+ target: azp/posix/2/
+ - ansible: '2.13'
+ docker: fedora34
+ python: ''
+ target: azp/posix/1/
+ - ansible: '2.13'
+ docker: fedora34
+ python: ''
+ target: azp/posix/2/
+ - ansible: '2.13'
+ docker: ubuntu1804
+ python: ''
+ target: azp/posix/1/
+ - ansible: '2.13'
+ docker: ubuntu1804
+ python: ''
+ target: azp/posix/2/
+ - ansible: '2.13'
+ docker: alpine3
+ python: ''
+ target: azp/posix/1/
+ - ansible: '2.13'
+ docker: alpine3
+ python: ''
+ target: azp/posix/2/
+ - ansible: '2.13'
+ docker: default
+ python: '3.8'
+ target: azp/generic/1/
+ - ansible: '2.13'
+ docker: default
+ python: '3.8'
+ target: azp/generic/2/
steps:
- name: >-
diff --git a/ansible_collections/community/crypto/.github/workflows/ee.yml b/ansible_collections/community/crypto/.github/workflows/ee.yml
index edd4d047b..74f48476f 100644
--- a/ansible_collections/community/crypto/.github/workflows/ee.yml
+++ b/ansible_collections/community/crypto/.github/workflows/ee.yml
@@ -46,6 +46,10 @@ jobs:
- name: ansible-core devel @ RHEL UBI 9
ansible_core: https://github.com/ansible/ansible/archive/devel.tar.gz
ansible_runner: ansible-runner
+ other_deps: |2
+ python_interpreter:
+ package_system: python3.11 python3.11-pip python3.11-wheel python3.11-cryptography
+ python_path: "/usr/bin/python3.11"
base_image: docker.io/redhat/ubi9:latest
pre_base: '"#"'
# For some reason ansible-builder will not install EPEL dependencies on RHEL
@@ -87,12 +91,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
path: ansible_collections/${{ env.NAMESPACE }}/${{ env.COLLECTION_NAME }}
- name: Set up Python
- uses: actions/setup-python@v4
+ uses: actions/setup-python@v5
with:
python-version: '3.11'
diff --git a/ansible_collections/community/crypto/.github/workflows/import-galaxy.yml b/ansible_collections/community/crypto/.github/workflows/import-galaxy.yml
new file mode 100644
index 000000000..0c0ee402a
--- /dev/null
+++ b/ansible_collections/community/crypto/.github/workflows/import-galaxy.yml
@@ -0,0 +1,20 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+name: import-galaxy
+'on':
+ # Run CI against all pushes (direct commits, also merged PRs) to main, and all Pull Requests
+ push:
+ branches:
+ - main
+ - stable-*
+ pull_request:
+
+jobs:
+ import-galaxy:
+ permissions:
+ contents: read
+ name: Test to import built collection artifact with Galaxy importer
+ uses: ansible-community/github-action-test-galaxy-import/.github/workflows/test-galaxy-import.yml@main
diff --git a/ansible_collections/community/crypto/.github/workflows/reuse.yml b/ansible_collections/community/crypto/.github/workflows/reuse.yml
index 3b01cd8ac..29b1f951a 100644
--- a/ansible_collections/community/crypto/.github/workflows/reuse.yml
+++ b/ansible_collections/community/crypto/.github/workflows/reuse.yml
@@ -21,14 +21,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- - name: Install dependencies
- run: |
- pip install reuse
-
- - name: Check REUSE compliance (except some PEM files)
+ - name: Remove some files before checking REUSE compliance
run: |
rm -f tests/integration/targets/*/files/*.pem
rm -f tests/integration/targets/*/files/roots/*.pem
- reuse lint
+
+ - name: REUSE Compliance Check
+ uses: fsfe/reuse-action@v2
diff --git a/ansible_collections/community/crypto/CHANGELOG.md b/ansible_collections/community/crypto/CHANGELOG.md
new file mode 100644
index 000000000..f54352a87
--- /dev/null
+++ b/ansible_collections/community/crypto/CHANGELOG.md
@@ -0,0 +1,1350 @@
+# Community Crypto Release Notes
+
+**Topics**
+- <a href="#v2-18-0">v2\.18\.0</a>
+ - <a href="#release-summary">Release Summary</a>
+ - <a href="#minor-changes">Minor Changes</a>
+ - <a href="#deprecated-features">Deprecated Features</a>
+ - <a href="#bugfixes">Bugfixes</a>
+ - <a href="#new-plugins">New Plugins</a>
+ - <a href="#filter">Filter</a>
+- <a href="#v2-17-1">v2\.17\.1</a>
+ - <a href="#release-summary-1">Release Summary</a>
+ - <a href="#bugfixes-1">Bugfixes</a>
+- <a href="#v2-17-0">v2\.17\.0</a>
+ - <a href="#release-summary-2">Release Summary</a>
+ - <a href="#minor-changes-1">Minor Changes</a>
+- <a href="#v2-16-2">v2\.16\.2</a>
+ - <a href="#release-summary-3">Release Summary</a>
+ - <a href="#bugfixes-2">Bugfixes</a>
+- <a href="#v2-16-1">v2\.16\.1</a>
+ - <a href="#release-summary-4">Release Summary</a>
+ - <a href="#bugfixes-3">Bugfixes</a>
+- <a href="#v2-16-0">v2\.16\.0</a>
+ - <a href="#release-summary-5">Release Summary</a>
+ - <a href="#minor-changes-2">Minor Changes</a>
+ - <a href="#bugfixes-4">Bugfixes</a>
+- <a href="#v2-15-1">v2\.15\.1</a>
+ - <a href="#release-summary-6">Release Summary</a>
+ - <a href="#bugfixes-5">Bugfixes</a>
+- <a href="#v2-15-0">v2\.15\.0</a>
+ - <a href="#release-summary-7">Release Summary</a>
+ - <a href="#minor-changes-3">Minor Changes</a>
+ - <a href="#deprecated-features-1">Deprecated Features</a>
+ - <a href="#bugfixes-6">Bugfixes</a>
+ - <a href="#new-plugins-1">New Plugins</a>
+ - <a href="#filter-1">Filter</a>
+ - <a href="#lookup">Lookup</a>
+- <a href="#v2-14-1">v2\.14\.1</a>
+ - <a href="#release-summary-8">Release Summary</a>
+ - <a href="#bugfixes-7">Bugfixes</a>
+ - <a href="#known-issues">Known Issues</a>
+- <a href="#v2-14-0">v2\.14\.0</a>
+ - <a href="#release-summary-9">Release Summary</a>
+ - <a href="#minor-changes-4">Minor Changes</a>
+- <a href="#v2-13-1">v2\.13\.1</a>
+ - <a href="#release-summary-10">Release Summary</a>
+ - <a href="#bugfixes-8">Bugfixes</a>
+- <a href="#v2-13-0">v2\.13\.0</a>
+ - <a href="#release-summary-11">Release Summary</a>
+ - <a href="#minor-changes-5">Minor Changes</a>
+ - <a href="#deprecated-features-2">Deprecated Features</a>
+ - <a href="#bugfixes-9">Bugfixes</a>
+- <a href="#v2-12-0">v2\.12\.0</a>
+ - <a href="#release-summary-12">Release Summary</a>
+ - <a href="#minor-changes-6">Minor Changes</a>
+- <a href="#v2-11-1">v2\.11\.1</a>
+ - <a href="#release-summary-13">Release Summary</a>
+- <a href="#v2-11-0">v2\.11\.0</a>
+ - <a href="#release-summary-14">Release Summary</a>
+ - <a href="#minor-changes-7">Minor Changes</a>
+ - <a href="#bugfixes-10">Bugfixes</a>
+- <a href="#v2-10-0">v2\.10\.0</a>
+ - <a href="#release-summary-15">Release Summary</a>
+ - <a href="#bugfixes-11">Bugfixes</a>
+ - <a href="#new-plugins-2">New Plugins</a>
+ - <a href="#filter-2">Filter</a>
+- <a href="#v2-9-0">v2\.9\.0</a>
+ - <a href="#release-summary-16">Release Summary</a>
+ - <a href="#minor-changes-8">Minor Changes</a>
+- <a href="#v2-8-1">v2\.8\.1</a>
+ - <a href="#release-summary-17">Release Summary</a>
+- <a href="#v2-8-0">v2\.8\.0</a>
+ - <a href="#release-summary-18">Release Summary</a>
+ - <a href="#minor-changes-9">Minor Changes</a>
+- <a href="#v2-7-1">v2\.7\.1</a>
+ - <a href="#release-summary-19">Release Summary</a>
+ - <a href="#bugfixes-12">Bugfixes</a>
+- <a href="#v2-7-0">v2\.7\.0</a>
+ - <a href="#release-summary-20">Release Summary</a>
+ - <a href="#minor-changes-10">Minor Changes</a>
+ - <a href="#bugfixes-13">Bugfixes</a>
+- <a href="#v2-6-0">v2\.6\.0</a>
+ - <a href="#release-summary-21">Release Summary</a>
+ - <a href="#minor-changes-11">Minor Changes</a>
+- <a href="#v2-5-0">v2\.5\.0</a>
+ - <a href="#release-summary-22">Release Summary</a>
+ - <a href="#minor-changes-12">Minor Changes</a>
+- <a href="#v2-4-0">v2\.4\.0</a>
+ - <a href="#release-summary-23">Release Summary</a>
+ - <a href="#deprecated-features-3">Deprecated Features</a>
+ - <a href="#bugfixes-14">Bugfixes</a>
+- <a href="#v2-3-4">v2\.3\.4</a>
+ - <a href="#release-summary-24">Release Summary</a>
+- <a href="#v2-3-3">v2\.3\.3</a>
+ - <a href="#release-summary-25">Release Summary</a>
+ - <a href="#bugfixes-15">Bugfixes</a>
+- <a href="#v2-3-2">v2\.3\.2</a>
+ - <a href="#release-summary-26">Release Summary</a>
+ - <a href="#bugfixes-16">Bugfixes</a>
+- <a href="#v2-3-1">v2\.3\.1</a>
+ - <a href="#release-summary-27">Release Summary</a>
+ - <a href="#bugfixes-17">Bugfixes</a>
+- <a href="#v2-3-0">v2\.3\.0</a>
+ - <a href="#release-summary-28">Release Summary</a>
+ - <a href="#minor-changes-13">Minor Changes</a>
+ - <a href="#bugfixes-18">Bugfixes</a>
+- <a href="#v2-2-4">v2\.2\.4</a>
+ - <a href="#release-summary-29">Release Summary</a>
+ - <a href="#bugfixes-19">Bugfixes</a>
+- <a href="#v2-2-3">v2\.2\.3</a>
+ - <a href="#release-summary-30">Release Summary</a>
+ - <a href="#bugfixes-20">Bugfixes</a>
+- <a href="#v2-2-2">v2\.2\.2</a>
+ - <a href="#release-summary-31">Release Summary</a>
+ - <a href="#bugfixes-21">Bugfixes</a>
+- <a href="#v2-2-1">v2\.2\.1</a>
+ - <a href="#release-summary-32">Release Summary</a>
+ - <a href="#bugfixes-22">Bugfixes</a>
+- <a href="#v2-2-0">v2\.2\.0</a>
+ - <a href="#release-summary-33">Release Summary</a>
+ - <a href="#minor-changes-14">Minor Changes</a>
+ - <a href="#bugfixes-23">Bugfixes</a>
+- <a href="#v2-1-0">v2\.1\.0</a>
+ - <a href="#release-summary-34">Release Summary</a>
+ - <a href="#minor-changes-15">Minor Changes</a>
+ - <a href="#bugfixes-24">Bugfixes</a>
+ - <a href="#new-modules">New Modules</a>
+- <a href="#v2-0-2">v2\.0\.2</a>
+ - <a href="#release-summary-35">Release Summary</a>
+- <a href="#v2-0-1">v2\.0\.1</a>
+ - <a href="#release-summary-36">Release Summary</a>
+ - <a href="#minor-changes-16">Minor Changes</a>
+ - <a href="#bugfixes-25">Bugfixes</a>
+- <a href="#v2-0-0">v2\.0\.0</a>
+ - <a href="#release-summary-37">Release Summary</a>
+ - <a href="#minor-changes-17">Minor Changes</a>
+ - <a href="#breaking-changes--porting-guide">Breaking Changes / Porting Guide</a>
+ - <a href="#deprecated-features-4">Deprecated Features</a>
+ - <a href="#removed-features-previously-deprecated">Removed Features \(previously deprecated\)</a>
+ - <a href="#bugfixes-26">Bugfixes</a>
+- <a href="#v1-9-4">v1\.9\.4</a>
+ - <a href="#release-summary-38">Release Summary</a>
+ - <a href="#bugfixes-27">Bugfixes</a>
+- <a href="#v1-9-3">v1\.9\.3</a>
+ - <a href="#release-summary-39">Release Summary</a>
+ - <a href="#bugfixes-28">Bugfixes</a>
+- <a href="#v1-9-2">v1\.9\.2</a>
+ - <a href="#release-summary-40">Release Summary</a>
+- <a href="#v1-9-1">v1\.9\.1</a>
+ - <a href="#release-summary-41">Release Summary</a>
+- <a href="#v1-9-0">v1\.9\.0</a>
+ - <a href="#release-summary-42">Release Summary</a>
+ - <a href="#minor-changes-18">Minor Changes</a>
+ - <a href="#bugfixes-29">Bugfixes</a>
+- <a href="#v1-8-0">v1\.8\.0</a>
+ - <a href="#release-summary-43">Release Summary</a>
+ - <a href="#minor-changes-19">Minor Changes</a>
+ - <a href="#bugfixes-30">Bugfixes</a>
+- <a href="#v1-7-1">v1\.7\.1</a>
+ - <a href="#release-summary-44">Release Summary</a>
+ - <a href="#bugfixes-31">Bugfixes</a>
+- <a href="#v1-7-0">v1\.7\.0</a>
+ - <a href="#release-summary-45">Release Summary</a>
+ - <a href="#minor-changes-20">Minor Changes</a>
+ - <a href="#bugfixes-32">Bugfixes</a>
+ - <a href="#new-modules-1">New Modules</a>
+- <a href="#v1-6-2">v1\.6\.2</a>
+ - <a href="#release-summary-46">Release Summary</a>
+ - <a href="#bugfixes-33">Bugfixes</a>
+- <a href="#v1-6-1">v1\.6\.1</a>
+ - <a href="#release-summary-47">Release Summary</a>
+ - <a href="#bugfixes-34">Bugfixes</a>
+- <a href="#v1-6-0">v1\.6\.0</a>
+ - <a href="#release-summary-48">Release Summary</a>
+ - <a href="#minor-changes-21">Minor Changes</a>
+ - <a href="#deprecated-features-5">Deprecated Features</a>
+ - <a href="#bugfixes-35">Bugfixes</a>
+- <a href="#v1-5-0">v1\.5\.0</a>
+ - <a href="#release-summary-49">Release Summary</a>
+ - <a href="#minor-changes-22">Minor Changes</a>
+ - <a href="#deprecated-features-6">Deprecated Features</a>
+ - <a href="#bugfixes-36">Bugfixes</a>
+- <a href="#v1-4-0">v1\.4\.0</a>
+ - <a href="#release-summary-50">Release Summary</a>
+ - <a href="#minor-changes-23">Minor Changes</a>
+ - <a href="#bugfixes-37">Bugfixes</a>
+- <a href="#v1-3-0">v1\.3\.0</a>
+ - <a href="#release-summary-51">Release Summary</a>
+ - <a href="#minor-changes-24">Minor Changes</a>
+ - <a href="#bugfixes-38">Bugfixes</a>
+ - <a href="#new-modules-2">New Modules</a>
+- <a href="#v1-2-0">v1\.2\.0</a>
+ - <a href="#release-summary-52">Release Summary</a>
+ - <a href="#minor-changes-25">Minor Changes</a>
+ - <a href="#security-fixes">Security Fixes</a>
+ - <a href="#bugfixes-39">Bugfixes</a>
+- <a href="#v1-1-1">v1\.1\.1</a>
+ - <a href="#release-summary-53">Release Summary</a>
+ - <a href="#bugfixes-40">Bugfixes</a>
+- <a href="#v1-1-0">v1\.1\.0</a>
+ - <a href="#release-summary-54">Release Summary</a>
+ - <a href="#minor-changes-26">Minor Changes</a>
+ - <a href="#bugfixes-41">Bugfixes</a>
+ - <a href="#new-modules-3">New Modules</a>
+- <a href="#v1-0-0">v1\.0\.0</a>
+ - <a href="#release-summary-55">Release Summary</a>
+ - <a href="#minor-changes-27">Minor Changes</a>
+ - <a href="#deprecated-features-7">Deprecated Features</a>
+ - <a href="#removed-features-previously-deprecated-1">Removed Features \(previously deprecated\)</a>
+ - <a href="#bugfixes-42">Bugfixes</a>
+ - <a href="#new-modules-4">New Modules</a>
+
+<a id="v2-18-0"></a>
+## v2\.18\.0
+
+<a id="release-summary"></a>
+### Release Summary
+
+Bugfix and feature release\.
+
+<a id="minor-changes"></a>
+### Minor Changes
+
+* x509\_crl \- the new option <code>serial\_numbers</code> allow to configure in which format serial numbers can be provided to <code>revoked\_certificates\[\]\.serial\_number</code>\. The default is as integers \(<code>serial\_numbers\=integer</code>\) for backwards compatibility\; setting <code>serial\_numbers\=hex\-octets</code> allows to specify colon\-separated hex octet strings like <code>00\:11\:22\:FF</code> \([https\://github\.com/ansible\-collections/community\.crypto/issues/687](https\://github\.com/ansible\-collections/community\.crypto/issues/687)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/715](https\://github\.com/ansible\-collections/community\.crypto/pull/715)\)\.
+
+<a id="deprecated-features"></a>
+### Deprecated Features
+
+* openssl\_csr\_pipe\, openssl\_privatekey\_pipe\, x509\_certificate\_pipe \- the current behavior of check mode is deprecated and will change in community\.crypto 3\.0\.0\. The current behavior is similar to the modules without <code>\_pipe</code>\: if the object needs to be \(re\-\)generated\, only the <code>changed</code> status is set\, but the object is not updated\. From community\.crypto 3\.0\.0 on\, the modules will ignore check mode and always act as if check mode is not active\. This behavior can already achieved now by adding <code>check\_mode\: false</code> to the task\. If you think this breaks your use\-case of this module\, please [create an issue in the community\.crypto repository](https\://github\.com/ansible\-collections/community\.crypto/issues/new/choose) \([https\://github\.com/ansible\-collections/community\.crypto/issues/712](https\://github\.com/ansible\-collections/community\.crypto/issues/712)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/714](https\://github\.com/ansible\-collections/community\.crypto/pull/714)\)\.
+
+<a id="bugfixes"></a>
+### Bugfixes
+
+* luks\_device \- fixed module a bug that prevented using <code>remove\_keyslot</code> with the value <code>0</code> \([https\://github\.com/ansible\-collections/community\.crypto/pull/710](https\://github\.com/ansible\-collections/community\.crypto/pull/710)\)\.
+* luks\_device \- fixed module falsely outputting <code>changed\=false</code> when trying to add a new slot with a key that is already present in another slot\. The module now rejects adding keys that are already present in another slot \([https\://github\.com/ansible\-collections/community\.crypto/pull/710](https\://github\.com/ansible\-collections/community\.crypto/pull/710)\)\.
+* luks\_device \- fixed testing of LUKS passphrases in when specifying a keyslot for cryptsetup version 2\.0\.3\. The output of this cryptsetup version slightly differs from later versions \([https\://github\.com/ansible\-collections/community\.crypto/pull/710](https\://github\.com/ansible\-collections/community\.crypto/pull/710)\)\.
+
+<a id="new-plugins"></a>
+### New Plugins
+
+<a id="filter"></a>
+#### Filter
+
+* parse\_serial \- Convert a serial number as a colon\-separated list of hex numbers to an integer
+* to\_serial \- Convert an integer to a colon\-separated list of hex numbers
+
+<a id="v2-17-1"></a>
+## v2\.17\.1
+
+<a id="release-summary-1"></a>
+### Release Summary
+
+Bugfix release for compatibility with cryptography 42\.0\.0\.
+
+<a id="bugfixes-1"></a>
+### Bugfixes
+
+* openssl\_dhparam \- was using an internal function instead of the public API to load DH param files when using the <code>cryptography</code> backend\. The internal function was removed in cryptography 42\.0\.0\. The module now uses the public API\, which has been available since support for DH params was added to cryptography \([https\://github\.com/ansible\-collections/community\.crypto/pull/698](https\://github\.com/ansible\-collections/community\.crypto/pull/698)\)\.
+* openssl\_privatekey\_info \- <code>check\_consistency\=true</code> no longer works for RSA keys with cryptography 42\.0\.0\+ \([https\://github\.com/ansible\-collections/community\.crypto/pull/701](https\://github\.com/ansible\-collections/community\.crypto/pull/701)\)\.
+* openssl\_privatekey\_info \- <code>check\_consistency\=true</code> now reports a warning if it cannot determine consistency \([https\://github\.com/ansible\-collections/community\.crypto/pull/705](https\://github\.com/ansible\-collections/community\.crypto/pull/705)\)\.
+
+<a id="v2-17-0"></a>
+## v2\.17\.0
+
+<a id="release-summary-2"></a>
+### Release Summary
+
+Feature release\.
+
+<a id="minor-changes-1"></a>
+### Minor Changes
+
+* luks\_device \- add allow discards option \([https\://github\.com/ansible\-collections/community\.crypto/pull/693](https\://github\.com/ansible\-collections/community\.crypto/pull/693)\)\.
+
+<a id="v2-16-2"></a>
+## v2\.16\.2
+
+<a id="release-summary-3"></a>
+### Release Summary
+
+Bugfix release\.
+
+<a id="bugfixes-2"></a>
+### Bugfixes
+
+* acme\_\* modules \- directly react on bad return data for account creation/retrieval/updating requests \([https\://github\.com/ansible\-collections/community\.crypto/pull/682](https\://github\.com/ansible\-collections/community\.crypto/pull/682)\)\.
+* acme\_\* modules \- fix improved error reporting in case of socket errors\, bad status lines\, and unknown connection errors \([https\://github\.com/ansible\-collections/community\.crypto/pull/684](https\://github\.com/ansible\-collections/community\.crypto/pull/684)\)\.
+* acme\_\* modules \- increase number of retries from 5 to 10 to increase stability with unstable ACME endpoints \([https\://github\.com/ansible\-collections/community\.crypto/pull/685](https\://github\.com/ansible\-collections/community\.crypto/pull/685)\)\.
+* acme\_\* modules \- make account registration handling more flexible to accept 404 instead of 400 send by DigiCert\'s ACME endpoint when an account does not exist \([https\://github\.com/ansible\-collections/community\.crypto/pull/681](https\://github\.com/ansible\-collections/community\.crypto/pull/681)\)\.
+
+<a id="v2-16-1"></a>
+## v2\.16\.1
+
+<a id="release-summary-4"></a>
+### Release Summary
+
+Bugfix release\.
+
+<a id="bugfixes-3"></a>
+### Bugfixes
+
+* acme\_\* modules \- also retry requests in case of socket errors\, bad status lines\, and unknown connection errors\; improve error messages in these cases \([https\://github\.com/ansible\-collections/community\.crypto/issues/680](https\://github\.com/ansible\-collections/community\.crypto/issues/680)\)\.
+
+<a id="v2-16-0"></a>
+## v2\.16\.0
+
+<a id="release-summary-5"></a>
+### Release Summary
+
+Bugfix release\.
+
+<a id="minor-changes-2"></a>
+### Minor Changes
+
+* luks\_devices \- add new options <code>keyslot</code>\, <code>new\_keyslot</code>\, and <code>remove\_keyslot</code> to allow adding/removing keys to/from specific keyslots \([https\://github\.com/ansible\-collections/community\.crypto/pull/664](https\://github\.com/ansible\-collections/community\.crypto/pull/664)\)\.
+
+<a id="bugfixes-4"></a>
+### Bugfixes
+
+* openssl\_pkcs12 \- modify autodetect to not detect pyOpenSSL \>\= 23\.3\.0\, which removed PKCS\#12 support \([https\://github\.com/ansible\-collections/community\.crypto/pull/666](https\://github\.com/ansible\-collections/community\.crypto/pull/666)\)\.
+
+<a id="v2-15-1"></a>
+## v2\.15\.1
+
+<a id="release-summary-6"></a>
+### Release Summary
+
+Bugfix release\.
+
+<a id="bugfixes-5"></a>
+### Bugfixes
+
+* acme\_\* modules \- correctly handle error documents without <code>type</code> \([https\://github\.com/ansible\-collections/community\.crypto/issues/651](https\://github\.com/ansible\-collections/community\.crypto/issues/651)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/652](https\://github\.com/ansible\-collections/community\.crypto/pull/652)\)\.
+
+<a id="v2-15-0"></a>
+## v2\.15\.0
+
+<a id="release-summary-7"></a>
+### Release Summary
+
+Bugfix and feature release\.
+
+<a id="minor-changes-3"></a>
+### Minor Changes
+
+* openssh\_keypair \- fail when comment cannot be updated \([https\://github\.com/ansible\-collections/community\.crypto/pull/646](https\://github\.com/ansible\-collections/community\.crypto/pull/646)\)\.
+
+<a id="deprecated-features-1"></a>
+### Deprecated Features
+
+* get\_certificate \- the default <code>false</code> of the <code>asn1\_base64</code> option is deprecated and will change to <code>true</code> in community\.crypto 3\.0\.0 \([https\://github\.com/ansible\-collections/community\.crypto/pull/600](https\://github\.com/ansible\-collections/community\.crypto/pull/600)\)\.
+
+<a id="bugfixes-6"></a>
+### Bugfixes
+
+* openssh\_cert\, openssh\_keypair \- the modules ignored return codes of <code>ssh</code> and <code>ssh\-keygen</code> in some cases \([https\://github\.com/ansible\-collections/community\.crypto/issues/645](https\://github\.com/ansible\-collections/community\.crypto/issues/645)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/646](https\://github\.com/ansible\-collections/community\.crypto/pull/646)\)\.
+* openssh\_keypair \- fix comment updating for OpenSSH before 6\.5 \([https\://github\.com/ansible\-collections/community\.crypto/pull/646](https\://github\.com/ansible\-collections/community\.crypto/pull/646)\)\.
+
+<a id="new-plugins-1"></a>
+### New Plugins
+
+<a id="filter-1"></a>
+#### Filter
+
+* gpg\_fingerprint \- Retrieve a GPG fingerprint from a GPG public or private key
+
+<a id="lookup"></a>
+#### Lookup
+
+* gpg\_fingerprint \- Retrieve a GPG fingerprint from a GPG public or private key file
+
+<a id="v2-14-1"></a>
+## v2\.14\.1
+
+<a id="release-summary-8"></a>
+### Release Summary
+
+Bugfix and maintenance release with updated documentation\.
+
+From this version on\, community\.crypto is using the new [Ansible semantic markup](https\://docs\.ansible\.com/ansible/devel/dev\_guide/developing\_modules\_documenting\.html\#semantic\-markup\-within\-module\-documentation)
+in its documentation\. If you look at documentation with the ansible\-doc CLI tool
+from ansible\-core before 2\.15\, please note that it does not render the markup
+correctly\. You should be still able to read it in most cases\, but you need
+ansible\-core 2\.15 or later to see it as it is intended\. Alternatively you can
+look at [the devel docsite](https\://docs\.ansible\.com/ansible/devel/collections/community/crypto/)
+for the rendered HTML version of the documentation of the latest release\.
+
+<a id="bugfixes-7"></a>
+### Bugfixes
+
+* Fix PEM detection/identification to also accept random other lines before the line starting with <code>\-\-\-\-\-BEGIN</code> \([https\://github\.com/ansible\-collections/community\.crypto/issues/627](https\://github\.com/ansible\-collections/community\.crypto/issues/627)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/628](https\://github\.com/ansible\-collections/community\.crypto/pull/628)\)\.
+
+<a id="known-issues"></a>
+### Known Issues
+
+* Ansible markup will show up in raw form on ansible\-doc text output for ansible\-core before 2\.15\. If you have trouble deciphering the documentation markup\, please upgrade to ansible\-core 2\.15 \(or newer\)\, or read the HTML documentation on [https\://docs\.ansible\.com/ansible/devel/collections/community/crypto/](https\://docs\.ansible\.com/ansible/devel/collections/community/crypto/)\.
+
+<a id="v2-14-0"></a>
+## v2\.14\.0
+
+<a id="release-summary-9"></a>
+### Release Summary
+
+Feature release\.
+
+<a id="minor-changes-4"></a>
+### Minor Changes
+
+* acme\_certificate \- allow to use no challenge by providing <code>no challenge</code> for the <code>challenge</code> option\. This is needed for ACME servers where validation is done without challenges \([https\://github\.com/ansible\-collections/community\.crypto/issues/613](https\://github\.com/ansible\-collections/community\.crypto/issues/613)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/615](https\://github\.com/ansible\-collections/community\.crypto/pull/615)\)\.
+* acme\_certificate \- validate and wait for challenges in parallel instead handling them one after another \([https\://github\.com/ansible\-collections/community\.crypto/pull/617](https\://github\.com/ansible\-collections/community\.crypto/pull/617)\)\.
+* x509\_certificate\_info \- added support for certificates in DER format when using <code>path</code> parameter \([https\://github\.com/ansible\-collections/community\.crypto/issues/603](https\://github\.com/ansible\-collections/community\.crypto/issues/603)\)\.
+
+<a id="v2-13-1"></a>
+## v2\.13\.1
+
+<a id="release-summary-10"></a>
+### Release Summary
+
+Bugfix release\.
+
+<a id="bugfixes-8"></a>
+### Bugfixes
+
+* execution environment definition \- fix installation of <code>python3\-pyOpenSSL</code> package on CentOS and RHEL \([https\://github\.com/ansible\-collections/community\.crypto/pull/606](https\://github\.com/ansible\-collections/community\.crypto/pull/606)\)\.
+* execution environment definition \- fix source of <code>python3\-pyOpenSSL</code> package for Rocky Linux 9\+ \([https\://github\.com/ansible\-collections/community\.crypto/pull/606](https\://github\.com/ansible\-collections/community\.crypto/pull/606)\)\.
+
+<a id="v2-13-0"></a>
+## v2\.13\.0
+
+<a id="release-summary-11"></a>
+### Release Summary
+
+Bugfix and maintenance release\.
+
+<a id="minor-changes-5"></a>
+### Minor Changes
+
+* x509\_crl \- the <code>crl\_mode</code> option has been added to replace the existing <code>mode</code> option \([https\://github\.com/ansible\-collections/community\.crypto/issues/596](https\://github\.com/ansible\-collections/community\.crypto/issues/596)\)\.
+
+<a id="deprecated-features-2"></a>
+### Deprecated Features
+
+* x509\_crl \- the <code>mode</code> option is deprecated\; use <code>crl\_mode</code> instead\. The <code>mode</code> option will change its meaning in community\.crypto 3\.0\.0\, and will refer to the CRL file\'s mode instead \([https\://github\.com/ansible\-collections/community\.crypto/issues/596](https\://github\.com/ansible\-collections/community\.crypto/issues/596)\)\.
+
+<a id="bugfixes-9"></a>
+### Bugfixes
+
+* openssh\_keypair \- always generate a new key pair if the private key does not exist\. Previously\, the module would fail when <code>regenerate\=fail</code> without an existing key\, contradicting the documentation \([https\://github\.com/ansible\-collections/community\.crypto/pull/598](https\://github\.com/ansible\-collections/community\.crypto/pull/598)\)\.
+* x509\_crl \- remove problem with ansible\-core 2\.16 due to <code>AnsibleModule</code> is now validating the <code>mode</code> parameter\'s values \([https\://github\.com/ansible\-collections/community\.crypto/issues/596](https\://github\.com/ansible\-collections/community\.crypto/issues/596)\)\.
+
+<a id="v2-12-0"></a>
+## v2\.12\.0
+
+<a id="release-summary-12"></a>
+### Release Summary
+
+Feature release\.
+
+<a id="minor-changes-6"></a>
+### Minor Changes
+
+* get\_certificate \- add <code>asn1\_base64</code> option to control whether the ASN\.1 included in the <code>extensions</code> return value is binary data or Base64 encoded \([https\://github\.com/ansible\-collections/community\.crypto/pull/592](https\://github\.com/ansible\-collections/community\.crypto/pull/592)\)\.
+
+<a id="v2-11-1"></a>
+## v2\.11\.1
+
+<a id="release-summary-13"></a>
+### Release Summary
+
+Maintenance release with improved documentation\.
+
+<a id="v2-11-0"></a>
+## v2\.11\.0
+
+<a id="release-summary-14"></a>
+### Release Summary
+
+Feature and bugfix release\.
+
+<a id="minor-changes-7"></a>
+### Minor Changes
+
+* get\_certificate \- adds <code>ciphers</code> option for custom cipher selection \([https\://github\.com/ansible\-collections/community\.crypto/pull/571](https\://github\.com/ansible\-collections/community\.crypto/pull/571)\)\.
+
+<a id="bugfixes-10"></a>
+### Bugfixes
+
+* action plugin helper \- fix handling of deprecations for ansible\-core 2\.14\.2 \([https\://github\.com/ansible\-collections/community\.crypto/pull/572](https\://github\.com/ansible\-collections/community\.crypto/pull/572)\)\.
+* execution environment binary dependencies \(bindep\.txt\) \- fix <code>python3\-pyOpenSSL</code> dependency resolution on RHEL 9\+ / CentOS Stream 9\+ platforms \([https\://github\.com/ansible\-collections/community\.crypto/pull/575](https\://github\.com/ansible\-collections/community\.crypto/pull/575)\)\.
+* various plugins \- remove unnecessary imports \([https\://github\.com/ansible\-collections/community\.crypto/pull/569](https\://github\.com/ansible\-collections/community\.crypto/pull/569)\)\.
+
+<a id="v2-10-0"></a>
+## v2\.10\.0
+
+<a id="release-summary-15"></a>
+### Release Summary
+
+Bugfix and feature release\.
+
+<a id="bugfixes-11"></a>
+### Bugfixes
+
+* openssl\_csr\, openssl\_csr\_pipe \- prevent invalid values for <code>crl\_distribution\_points</code> that do not have one of <code>full\_name</code>\, <code>relative\_name</code>\, and <code>crl\_issuer</code> \([https\://github\.com/ansible\-collections/community\.crypto/pull/560](https\://github\.com/ansible\-collections/community\.crypto/pull/560)\)\.
+* openssl\_publickey\_info \- do not crash with internal error when public key cannot be parsed \([https\://github\.com/ansible\-collections/community\.crypto/pull/551](https\://github\.com/ansible\-collections/community\.crypto/pull/551)\)\.
+
+<a id="new-plugins-2"></a>
+### New Plugins
+
+<a id="filter-2"></a>
+#### Filter
+
+* openssl\_csr\_info \- Retrieve information from OpenSSL Certificate Signing Requests \(CSR\)
+* openssl\_privatekey\_info \- Retrieve information from OpenSSL private keys
+* openssl\_publickey\_info \- Retrieve information from OpenSSL public keys in PEM format
+* split\_pem \- Split PEM file contents into multiple objects
+* x509\_certificate\_info \- Retrieve information from X\.509 certificates in PEM format
+* x509\_crl\_info \- Retrieve information from X\.509 CRLs in PEM format
+
+<a id="v2-9-0"></a>
+## v2\.9\.0
+
+<a id="release-summary-16"></a>
+### Release Summary
+
+Regular feature release\.
+
+<a id="minor-changes-8"></a>
+### Minor Changes
+
+* x509\_certificate\_info \- adds <code>issuer\_uri</code> field in return value based on Authority Information Access data \([https\://github\.com/ansible\-collections/community\.crypto/pull/530](https\://github\.com/ansible\-collections/community\.crypto/pull/530)\)\.
+
+<a id="v2-8-1"></a>
+## v2\.8\.1
+
+<a id="release-summary-17"></a>
+### Release Summary
+
+Maintenance release with improved documentation\.
+
+<a id="v2-8-0"></a>
+## v2\.8\.0
+
+<a id="release-summary-18"></a>
+### Release Summary
+
+Feature release\.
+
+<a id="minor-changes-9"></a>
+### Minor Changes
+
+* acme\_\* modules \- handle more gracefully if CA\'s new nonce call does not return a nonce \([https\://github\.com/ansible\-collections/community\.crypto/pull/525](https\://github\.com/ansible\-collections/community\.crypto/pull/525)\)\.
+* acme\_\* modules \- include symbolic HTTP status codes in error and log messages when available \([https\://github\.com/ansible\-collections/community\.crypto/pull/524](https\://github\.com/ansible\-collections/community\.crypto/pull/524)\)\.
+* openssl\_pkcs12 \- add option <code>encryption\_level</code> which allows to chose <code>compatibility2022</code> when cryptography \>\= 38\.0\.0 is used to enable a more backwards compatible encryption algorithm\. If cryptography uses OpenSSL 3\.0\.0 or newer\, the default algorithm is not compatible with older software \([https\://github\.com/ansible\-collections/community\.crypto/pull/523](https\://github\.com/ansible\-collections/community\.crypto/pull/523)\)\.
+
+<a id="v2-7-1"></a>
+## v2\.7\.1
+
+<a id="release-summary-19"></a>
+### Release Summary
+
+Maintenance release\.
+
+<a id="bugfixes-12"></a>
+### Bugfixes
+
+* acme\_\* modules \- improve feedback when importing <code>cryptography</code> does not work \([https\://github\.com/ansible\-collections/community\.crypto/issues/518](https\://github\.com/ansible\-collections/community\.crypto/issues/518)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/519](https\://github\.com/ansible\-collections/community\.crypto/pull/519)\)\.
+
+<a id="v2-7-0"></a>
+## v2\.7\.0
+
+<a id="release-summary-20"></a>
+### Release Summary
+
+Feature release\.
+
+<a id="minor-changes-10"></a>
+### Minor Changes
+
+* acme\* modules \- also support the HTTP 503 Service Unavailable and 408 Request Timeout response status for automatic retries \([https\://github\.com/ansible\-collections/community\.crypto/pull/513](https\://github\.com/ansible\-collections/community\.crypto/pull/513)\)\.
+
+<a id="bugfixes-13"></a>
+### Bugfixes
+
+* openssl\_privatekey\_pipe \- ensure compatibility with newer versions of ansible\-core \([https\://github\.com/ansible\-collections/community\.crypto/pull/515](https\://github\.com/ansible\-collections/community\.crypto/pull/515)\)\.
+
+<a id="v2-6-0"></a>
+## v2\.6\.0
+
+<a id="release-summary-21"></a>
+### Release Summary
+
+Feature release\.
+
+<a id="minor-changes-11"></a>
+### Minor Changes
+
+* acme\* modules \- support the HTTP 429 Too Many Requests response status \([https\://github\.com/ansible\-collections/community\.crypto/pull/508](https\://github\.com/ansible\-collections/community\.crypto/pull/508)\)\.
+* openssh\_keypair \- added <code>pkcs1</code>\, <code>pkcs8</code>\, and <code>ssh</code> to the available choices for the <code>private\_key\_format</code> option \([https\://github\.com/ansible\-collections/community\.crypto/pull/511](https\://github\.com/ansible\-collections/community\.crypto/pull/511)\)\.
+
+<a id="v2-5-0"></a>
+## v2\.5\.0
+
+<a id="release-summary-22"></a>
+### Release Summary
+
+Maintenance release with improved licensing declaration and documentation fixes\.
+
+<a id="minor-changes-12"></a>
+### Minor Changes
+
+* All software licenses are now in the <code>LICENSES/</code> directory of the collection root\. Moreover\, <code>SPDX\-License\-Identifier\:</code> is used to declare the applicable license for every file that is not automatically generated \([https\://github\.com/ansible\-collections/community\.crypto/pull/491](https\://github\.com/ansible\-collections/community\.crypto/pull/491)\)\.
+
+<a id="v2-4-0"></a>
+## v2\.4\.0
+
+<a id="release-summary-23"></a>
+### Release Summary
+
+Deprecation and bugfix release\. No new features this time\.
+
+<a id="deprecated-features-3"></a>
+### Deprecated Features
+
+* Support for Ansible 2\.9 and ansible\-base 2\.10 is deprecated\, and will be removed in the next major release \(community\.crypto 3\.0\.0\)\. Some modules might still work with these versions afterwards\, but we will no longer keep compatibility code that was needed to support them \([https\://github\.com/ansible\-collections/community\.crypto/pull/460](https\://github\.com/ansible\-collections/community\.crypto/pull/460)\)\.
+
+<a id="bugfixes-14"></a>
+### Bugfixes
+
+* openssl\_pkcs12 \- when using the pyOpenSSL backend\, do not crash when trying to read non\-existing other certificates \([https\://github\.com/ansible\-collections/community\.crypto/issues/486](https\://github\.com/ansible\-collections/community\.crypto/issues/486)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/487](https\://github\.com/ansible\-collections/community\.crypto/pull/487)\)\.
+
+<a id="v2-3-4"></a>
+## v2\.3\.4
+
+<a id="release-summary-24"></a>
+### Release Summary
+
+Re\-release of what was intended to be 2\.3\.3\.
+
+A mistake during the release process caused the 2\.3\.3 tag to end up on the
+commit for 1\.9\.17\, which caused the release pipeline to re\-publish 1\.9\.17
+as 2\.3\.3\.
+
+This release is identical to what should have been 2\.3\.3\, except that the
+version number has been bumped to 2\.3\.4 and this changelog entry for 2\.3\.4
+has been added\.
+
+<a id="v2-3-3"></a>
+## v2\.3\.3
+
+<a id="release-summary-25"></a>
+### Release Summary
+
+Bugfix release\.
+
+<a id="bugfixes-15"></a>
+### Bugfixes
+
+* Include <code>Apache\-2\.0\.txt</code> file for <code>plugins/module\_utils/crypto/\_obj2txt\.py</code> and <code>plugins/module\_utils/crypto/\_objects\_data\.py</code>\.
+* openssl\_csr \- the module no longer crashes with \'permitted\_subtrees/excluded\_subtrees must be a non\-empty list or None\' if only one of <code>name\_constraints\_permitted</code> and <code>name\_constraints\_excluded</code> is provided \([https\://github\.com/ansible\-collections/community\.crypto/issues/481](https\://github\.com/ansible\-collections/community\.crypto/issues/481)\)\.
+* x509\_crl \- do not crash when signing CRL with Ed25519 or Ed448 keys \([https\://github\.com/ansible\-collections/community\.crypto/issues/473](https\://github\.com/ansible\-collections/community\.crypto/issues/473)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/474](https\://github\.com/ansible\-collections/community\.crypto/pull/474)\)\.
+
+<a id="v2-3-2"></a>
+## v2\.3\.2
+
+<a id="release-summary-26"></a>
+### Release Summary
+
+Maintenance and bugfix release\.
+
+<a id="bugfixes-16"></a>
+### Bugfixes
+
+* Include <code>simplified\_bsd\.txt</code> license file for the ECS module utils\.
+* certificate\_complete\_chain \- do not stop execution if an unsupported signature algorithm is encountered\; warn instead \([https\://github\.com/ansible\-collections/community\.crypto/pull/457](https\://github\.com/ansible\-collections/community\.crypto/pull/457)\)\.
+
+<a id="v2-3-1"></a>
+## v2\.3\.1
+
+<a id="release-summary-27"></a>
+### Release Summary
+
+Maintenance release\.
+
+<a id="bugfixes-17"></a>
+### Bugfixes
+
+* Include <code>PSF\-license\.txt</code> file for <code>plugins/module\_utils/\_version\.py</code>\.
+
+<a id="v2-3-0"></a>
+## v2\.3\.0
+
+<a id="release-summary-28"></a>
+### Release Summary
+
+Feature and bugfix release\.
+
+<a id="minor-changes-13"></a>
+### Minor Changes
+
+* Prepare collection for inclusion in an Execution Environment by declaring its dependencies\. Please note that system packages are used for cryptography and PyOpenSSL\, which can be rather limited\. If you need features from newer cryptography versions\, you will have to manually force a newer version to be installed by pip by specifying something like <code>cryptography \>\= 37\.0\.0</code> in your Execution Environment\'s Python dependencies file \([https\://github\.com/ansible\-collections/community\.crypto/pull/440](https\://github\.com/ansible\-collections/community\.crypto/pull/440)\)\.
+* Support automatic conversion for Internalionalized Domain Names \(IDNs\)\. When passing general names\, for example Subject Alternative Names to <code>community\.crypto\.openssl\_csr</code>\, these will automatically be converted to IDNA\. Conversion will be done per label to IDNA2008 if possible\, and IDNA2003 if IDNA2008 conversion fails for that label\. Note that IDNA conversion requires [the Python idna library](https\://pypi\.org/project/idna/) to be installed\. Please note that depending on which versions of the cryptography library are used\, it could try to process the converted IDNA another time with the Python <code>idna</code> library and reject IDNA2003 encoded values\. Using a new enough <code>cryptography</code> version avoids this \([https\://github\.com/ansible\-collections/community\.crypto/issues/426](https\://github\.com/ansible\-collections/community\.crypto/issues/426)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/436](https\://github\.com/ansible\-collections/community\.crypto/pull/436)\)\.
+* acme\_\* modules \- add parameter <code>request\_timeout</code> to manage HTTP\(S\) request timeout \([https\://github\.com/ansible\-collections/community\.crypto/issues/447](https\://github\.com/ansible\-collections/community\.crypto/issues/447)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/448](https\://github\.com/ansible\-collections/community\.crypto/pull/448)\)\.
+* luks\_devices \- added <code>perf\_same\_cpu\_crypt</code>\, <code>perf\_submit\_from\_crypt\_cpus</code>\, <code>perf\_no\_read\_workqueue</code>\, <code>perf\_no\_write\_workqueue</code> for performance tuning when opening LUKS2 containers \([https\://github\.com/ansible\-collections/community\.crypto/issues/427](https\://github\.com/ansible\-collections/community\.crypto/issues/427)\)\.
+* luks\_devices \- added <code>persistent</code> option when opening LUKS2 containers \([https\://github\.com/ansible\-collections/community\.crypto/pull/434](https\://github\.com/ansible\-collections/community\.crypto/pull/434)\)\.
+* openssl\_csr\_info \- add <code>name\_encoding</code> option to control the encoding \(IDNA\, Unicode\) used to return domain names in general names \([https\://github\.com/ansible\-collections/community\.crypto/pull/436](https\://github\.com/ansible\-collections/community\.crypto/pull/436)\)\.
+* openssl\_pkcs12 \- allow to provide the private key as text instead of having to read it from a file\. This allows to store the private key in an encrypted form\, for example in Ansible Vault \([https\://github\.com/ansible\-collections/community\.crypto/pull/452](https\://github\.com/ansible\-collections/community\.crypto/pull/452)\)\.
+* x509\_certificate\_info \- add <code>name\_encoding</code> option to control the encoding \(IDNA\, Unicode\) used to return domain names in general names \([https\://github\.com/ansible\-collections/community\.crypto/pull/436](https\://github\.com/ansible\-collections/community\.crypto/pull/436)\)\.
+* x509\_crl \- add <code>name\_encoding</code> option to control the encoding \(IDNA\, Unicode\) used to return domain names in general names \([https\://github\.com/ansible\-collections/community\.crypto/pull/436](https\://github\.com/ansible\-collections/community\.crypto/pull/436)\)\.
+* x509\_crl\_info \- add <code>name\_encoding</code> option to control the encoding \(IDNA\, Unicode\) used to return domain names in general names \([https\://github\.com/ansible\-collections/community\.crypto/pull/436](https\://github\.com/ansible\-collections/community\.crypto/pull/436)\)\.
+
+<a id="bugfixes-18"></a>
+### Bugfixes
+
+* Make collection more robust when PyOpenSSL is used with an incompatible cryptography version \([https\://github\.com/ansible\-collections/community\.crypto/pull/445](https\://github\.com/ansible\-collections/community\.crypto/pull/445)\)\.
+* x509\_crl \- fix crash when <code>issuer</code> for a revoked certificate is specified \([https\://github\.com/ansible\-collections/community\.crypto/pull/441](https\://github\.com/ansible\-collections/community\.crypto/pull/441)\)\.
+
+<a id="v2-2-4"></a>
+## v2\.2\.4
+
+<a id="release-summary-29"></a>
+### Release Summary
+
+Regular maintenance release\.
+
+<a id="bugfixes-19"></a>
+### Bugfixes
+
+* openssh\_\* modules \- fix exception handling to report traceback to users for enhanced traceability \([https\://github\.com/ansible\-collections/community\.crypto/pull/417](https\://github\.com/ansible\-collections/community\.crypto/pull/417)\)\.
+
+<a id="v2-2-3"></a>
+## v2\.2\.3
+
+<a id="release-summary-30"></a>
+### Release Summary
+
+Regular bugfix release\.
+
+<a id="bugfixes-20"></a>
+### Bugfixes
+
+* luks\_device \- fix parsing of <code>lsblk</code> output when device name ends with <code>crypt</code> \([https\://github\.com/ansible\-collections/community\.crypto/issues/409](https\://github\.com/ansible\-collections/community\.crypto/issues/409)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/410](https\://github\.com/ansible\-collections/community\.crypto/pull/410)\)\.
+
+<a id="v2-2-2"></a>
+## v2\.2\.2
+
+<a id="release-summary-31"></a>
+### Release Summary
+
+Regular bugfix release\.
+
+In this release\, we extended the test matrix to include Alpine 3\, ArchLinux\, Debian Bullseye\, and CentOS Stream 8\. CentOS 8 was removed from the test matrix\.
+
+<a id="bugfixes-21"></a>
+### Bugfixes
+
+* certificate\_complete\_chain \- allow multiple potential intermediate certificates to have the same subject \([https\://github\.com/ansible\-collections/community\.crypto/issues/399](https\://github\.com/ansible\-collections/community\.crypto/issues/399)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/403](https\://github\.com/ansible\-collections/community\.crypto/pull/403)\)\.
+* x509\_certificate \- for the <code>ownca</code> provider\, check whether the CA private key actually belongs to the CA certificate \([https\://github\.com/ansible\-collections/community\.crypto/pull/407](https\://github\.com/ansible\-collections/community\.crypto/pull/407)\)\.
+* x509\_certificate \- regenerate certificate when the CA\'s public key changes for <code>provider\=ownca</code> \([https\://github\.com/ansible\-collections/community\.crypto/pull/407](https\://github\.com/ansible\-collections/community\.crypto/pull/407)\)\.
+* x509\_certificate \- regenerate certificate when the CA\'s subject changes for <code>provider\=ownca</code> \([https\://github\.com/ansible\-collections/community\.crypto/issues/400](https\://github\.com/ansible\-collections/community\.crypto/issues/400)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/402](https\://github\.com/ansible\-collections/community\.crypto/pull/402)\)\.
+* x509\_certificate \- regenerate certificate when the private key changes for <code>provider\=selfsigned</code> \([https\://github\.com/ansible\-collections/community\.crypto/pull/407](https\://github\.com/ansible\-collections/community\.crypto/pull/407)\)\.
+
+<a id="v2-2-1"></a>
+## v2\.2\.1
+
+<a id="release-summary-32"></a>
+### Release Summary
+
+Bugfix release\.
+
+<a id="bugfixes-22"></a>
+### Bugfixes
+
+* openssh\_cert \- fixed false <code>changed</code> status for <code>host</code> certificates when using <code>full\_idempotence</code> \([https\://github\.com/ansible\-collections/community\.crypto/issues/395](https\://github\.com/ansible\-collections/community\.crypto/issues/395)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/396](https\://github\.com/ansible\-collections/community\.crypto/pull/396)\)\.
+
+<a id="v2-2-0"></a>
+## v2\.2\.0
+
+<a id="release-summary-33"></a>
+### Release Summary
+
+Regular bugfix and feature release\.
+
+<a id="minor-changes-14"></a>
+### Minor Changes
+
+* openssh\_cert \- added <code>ignore\_timestamps</code> parameter so it can be used semi\-idempotent with relative timestamps in <code>valid\_to</code>/<code>valid\_from</code> \([https\://github\.com/ansible\-collections/community\.crypto/issues/379](https\://github\.com/ansible\-collections/community\.crypto/issues/379)\)\.
+
+<a id="bugfixes-23"></a>
+### Bugfixes
+
+* luks\_devices \- set <code>LANG</code> and similar environment variables to avoid translated output\, which can break some of the module\'s functionality like key management \([https\://github\.com/ansible\-collections/community\.crypto/pull/388](https\://github\.com/ansible\-collections/community\.crypto/pull/388)\, [https\://github\.com/ansible\-collections/community\.crypto/issues/385](https\://github\.com/ansible\-collections/community\.crypto/issues/385)\)\.
+
+<a id="v2-1-0"></a>
+## v2\.1\.0
+
+<a id="release-summary-34"></a>
+### Release Summary
+
+Feature and bugfix release\.
+
+<a id="minor-changes-15"></a>
+### Minor Changes
+
+* Adjust error messages that indicate <code>cryptography</code> is not installed from <code>Can\'t</code> to <code>Cannot</code> \([https\://github\.com/ansible\-collections/community\.crypto/pull/374](https\://github\.com/ansible\-collections/community\.crypto/pull/374)\)\.
+
+<a id="bugfixes-24"></a>
+### Bugfixes
+
+* Various modules and plugins \- use vendored version of <code>distutils\.version</code> instead of the deprecated Python standard library <code>distutils</code> \([https\://github\.com/ansible\-collections/community\.crypto/pull/353](https\://github\.com/ansible\-collections/community\.crypto/pull/353)\)\.
+* certificate\_complete\_chain \- do not append root twice if the chain already ends with a root certificate \([https\://github\.com/ansible\-collections/community\.crypto/pull/360](https\://github\.com/ansible\-collections/community\.crypto/pull/360)\)\.
+* certificate\_complete\_chain \- do not hang when infinite loop is found \([https\://github\.com/ansible\-collections/community\.crypto/issues/355](https\://github\.com/ansible\-collections/community\.crypto/issues/355)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/360](https\://github\.com/ansible\-collections/community\.crypto/pull/360)\)\.
+
+<a id="new-modules"></a>
+### New Modules
+
+* crypto\_info \- Retrieve cryptographic capabilities
+* openssl\_privatekey\_convert \- Convert OpenSSL private keys
+
+<a id="v2-0-2"></a>
+## v2\.0\.2
+
+<a id="release-summary-35"></a>
+### Release Summary
+
+Documentation fix release\. No actual code changes\.
+
+<a id="v2-0-1"></a>
+## v2\.0\.1
+
+<a id="release-summary-36"></a>
+### Release Summary
+
+Bugfix release with extra forward compatibility for newer versions of cryptography\.
+
+<a id="minor-changes-16"></a>
+### Minor Changes
+
+* acme\_\* modules \- fix usage of <code>fetch\_url</code> with changes in latest ansible\-core <code>devel</code> branch \([https\://github\.com/ansible\-collections/community\.crypto/pull/339](https\://github\.com/ansible\-collections/community\.crypto/pull/339)\)\.
+
+<a id="bugfixes-25"></a>
+### Bugfixes
+
+* acme\_certificate \- avoid passing multiple certificates to <code>cryptography</code>\'s X\.509 certificate loader when <code>fullchain\_dest</code> is used \([https\://github\.com/ansible\-collections/community\.crypto/pull/324](https\://github\.com/ansible\-collections/community\.crypto/pull/324)\)\.
+* get\_certificate\, openssl\_csr\_info\, x509\_certificate\_info \- add fallback code for extension parsing that works with cryptography 36\.0\.0 and newer\. This code re\-serializes de\-serialized extensions and thus can return slightly different values if the extension in the original CSR resp\. certificate was not canonicalized correctly\. This code is currently used as a fallback if the existing code stops working\, but we will switch it to be the main code in a future release \([https\://github\.com/ansible\-collections/community\.crypto/pull/331](https\://github\.com/ansible\-collections/community\.crypto/pull/331)\)\.
+* luks\_device \- now also runs a built\-in LUKS signature cleaner on <code>state\=absent</code> to make sure that also the secondary LUKS2 header is wiped when older versions of wipefs are used \([https\://github\.com/ansible\-collections/community\.crypto/issues/326](https\://github\.com/ansible\-collections/community\.crypto/issues/326)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/327](https\://github\.com/ansible\-collections/community\.crypto/pull/327)\)\.
+* openssl\_pkcs12 \- use new PKCS\#12 deserialization infrastructure from cryptography 36\.0\.0 if available \([https\://github\.com/ansible\-collections/community\.crypto/pull/302](https\://github\.com/ansible\-collections/community\.crypto/pull/302)\)\.
+
+<a id="v2-0-0"></a>
+## v2\.0\.0
+
+<a id="release-summary-37"></a>
+### Release Summary
+
+A new major release of the <code>community\.crypto</code> collection\. The main changes are removal of the PyOpenSSL backends for almost all modules \(<code>openssl\_pkcs12</code> being the only exception\)\, and removal of the <code>assertonly</code> provider in the <code>x509\_certificate</code> provider\. There are also some other breaking changes which should improve the user interface/experience of this collection long\-term\.
+
+<a id="minor-changes-17"></a>
+### Minor Changes
+
+* acme\_certificate \- the <code>subject</code> and <code>issuer</code> fields in in the <code>select\_chain</code> entries are now more strictly validated \([https\://github\.com/ansible\-collections/community\.crypto/pull/316](https\://github\.com/ansible\-collections/community\.crypto/pull/316)\)\.
+* openssl\_csr\, openssl\_csr\_pipe \- provide a new <code>subject\_ordered</code> option if the order of the components in the subject is of importance \([https\://github\.com/ansible\-collections/community\.crypto/issues/291](https\://github\.com/ansible\-collections/community\.crypto/issues/291)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/316](https\://github\.com/ansible\-collections/community\.crypto/pull/316)\)\.
+* openssl\_csr\, openssl\_csr\_pipe \- there is now stricter validation of the values of the <code>subject</code> option \([https\://github\.com/ansible\-collections/community\.crypto/pull/316](https\://github\.com/ansible\-collections/community\.crypto/pull/316)\)\.
+* openssl\_privatekey\_info \- add <code>check\_consistency</code> option to request private key consistency checks to be done \([https\://github\.com/ansible\-collections/community\.crypto/pull/309](https\://github\.com/ansible\-collections/community\.crypto/pull/309)\)\.
+* x509\_certificate\, x509\_certificate\_pipe \- add <code>ignore\_timestamps</code> option which allows to enable idempotency for \'not before\' and \'not after\' options \([https\://github\.com/ansible\-collections/community\.crypto/issues/295](https\://github\.com/ansible\-collections/community\.crypto/issues/295)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/317](https\://github\.com/ansible\-collections/community\.crypto/pull/317)\)\.
+* x509\_crl \- provide a new <code>issuer\_ordered</code> option if the order of the components in the issuer is of importance \([https\://github\.com/ansible\-collections/community\.crypto/issues/291](https\://github\.com/ansible\-collections/community\.crypto/issues/291)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/316](https\://github\.com/ansible\-collections/community\.crypto/pull/316)\)\.
+* x509\_crl \- there is now stricter validation of the values of the <code>issuer</code> option \([https\://github\.com/ansible\-collections/community\.crypto/pull/316](https\://github\.com/ansible\-collections/community\.crypto/pull/316)\)\.
+
+<a id="breaking-changes--porting-guide"></a>
+### Breaking Changes / Porting Guide
+
+* Adjust <code>dirName</code> text parsing and to text converting code to conform to [Sections 2 and 3 of RFC 4514](https\://datatracker\.ietf\.org/doc/html/rfc4514\.html)\. This is similar to how [cryptography handles this](https\://cryptography\.io/en/latest/x509/reference/\#cryptography\.x509\.Name\.rfc4514\_string) \([https\://github\.com/ansible\-collections/community\.crypto/pull/274](https\://github\.com/ansible\-collections/community\.crypto/pull/274)\)\.
+* acme module utils \- removing compatibility code \([https\://github\.com/ansible\-collections/community\.crypto/pull/290](https\://github\.com/ansible\-collections/community\.crypto/pull/290)\)\.
+* acme\_\* modules \- removed vendored copy of the Python library <code>ipaddress</code>\. If you are using Python 2\.x\, please make sure to install the library \([https\://github\.com/ansible\-collections/community\.crypto/pull/287](https\://github\.com/ansible\-collections/community\.crypto/pull/287)\)\.
+* compatibility module\_utils \- removed vendored copy of the Python library <code>ipaddress</code> \([https\://github\.com/ansible\-collections/community\.crypto/pull/287](https\://github\.com/ansible\-collections/community\.crypto/pull/287)\)\.
+* crypto module utils \- removing compatibility code \([https\://github\.com/ansible\-collections/community\.crypto/pull/290](https\://github\.com/ansible\-collections/community\.crypto/pull/290)\)\.
+* get\_certificate\, openssl\_csr\_info\, x509\_certificate\_info \- depending on the <code>cryptography</code> version used\, the modules might not return the ASN\.1 value for an extension as contained in the certificate respectively CSR\, but a re\-encoded version of it\. This should usually be identical to the value contained in the source file\, unless the value was malformed\. For extensions not handled by C\(cryptography\) the value contained in the source file is always returned unaltered \([https\://github\.com/ansible\-collections/community\.crypto/pull/318](https\://github\.com/ansible\-collections/community\.crypto/pull/318)\)\.
+* module\_utils \- removed various PyOpenSSL support functions and default backend values that are not needed for the openssl\_pkcs12 module \([https\://github\.com/ansible\-collections/community\.crypto/pull/273](https\://github\.com/ansible\-collections/community\.crypto/pull/273)\)\.
+* openssl\_csr\, openssl\_csr\_pipe\, x509\_crl \- the <code>subject</code> respectively <code>issuer</code> fields no longer ignore empty values\, but instead fail when encountering them \([https\://github\.com/ansible\-collections/community\.crypto/pull/316](https\://github\.com/ansible\-collections/community\.crypto/pull/316)\)\.
+* openssl\_privatekey\_info \- by default consistency checks are not run\; they need to be explicitly requested by passing <code>check\_consistency\=true</code> \([https\://github\.com/ansible\-collections/community\.crypto/pull/309](https\://github\.com/ansible\-collections/community\.crypto/pull/309)\)\.
+* x509\_crl \- for idempotency checks\, the <code>issuer</code> order is ignored\. If order is important\, use the new <code>issuer\_ordered</code> option \([https\://github\.com/ansible\-collections/community\.crypto/pull/316](https\://github\.com/ansible\-collections/community\.crypto/pull/316)\)\.
+
+<a id="deprecated-features-4"></a>
+### Deprecated Features
+
+* acme\_\* modules \- ACME version 1 is now deprecated and support for it will be removed in community\.crypto 2\.0\.0 \([https\://github\.com/ansible\-collections/community\.crypto/pull/288](https\://github\.com/ansible\-collections/community\.crypto/pull/288)\)\.
+
+<a id="removed-features-previously-deprecated"></a>
+### Removed Features \(previously deprecated\)
+
+* acme\_\* modules \- the <code>acme\_directory</code> option is now required \([https\://github\.com/ansible\-collections/community\.crypto/pull/290](https\://github\.com/ansible\-collections/community\.crypto/pull/290)\)\.
+* acme\_\* modules \- the <code>acme\_version</code> option is now required \([https\://github\.com/ansible\-collections/community\.crypto/pull/290](https\://github\.com/ansible\-collections/community\.crypto/pull/290)\)\.
+* acme\_account\_facts \- the deprecated redirect has been removed\. Use community\.crypto\.acme\_account\_info instead \([https\://github\.com/ansible\-collections/community\.crypto/pull/290](https\://github\.com/ansible\-collections/community\.crypto/pull/290)\)\.
+* acme\_account\_info \- <code>retrieve\_orders\=url\_list</code> no longer returns the return value <code>orders</code>\. Use the <code>order\_uris</code> return value instead \([https\://github\.com/ansible\-collections/community\.crypto/pull/290](https\://github\.com/ansible\-collections/community\.crypto/pull/290)\)\.
+* crypto\.info module utils \- the deprecated redirect has been removed\. Use <code>crypto\.pem</code> instead \([https\://github\.com/ansible\-collections/community\.crypto/pull/290](https\://github\.com/ansible\-collections/community\.crypto/pull/290)\)\.
+* get\_certificate \- removed the <code>pyopenssl</code> backend \([https\://github\.com/ansible\-collections/community\.crypto/pull/273](https\://github\.com/ansible\-collections/community\.crypto/pull/273)\)\.
+* openssl\_certificate \- the deprecated redirect has been removed\. Use community\.crypto\.x509\_certificate instead \([https\://github\.com/ansible\-collections/community\.crypto/pull/290](https\://github\.com/ansible\-collections/community\.crypto/pull/290)\)\.
+* openssl\_certificate\_info \- the deprecated redirect has been removed\. Use community\.crypto\.x509\_certificate\_info instead \([https\://github\.com/ansible\-collections/community\.crypto/pull/290](https\://github\.com/ansible\-collections/community\.crypto/pull/290)\)\.
+* openssl\_csr \- removed the <code>pyopenssl</code> backend \([https\://github\.com/ansible\-collections/community\.crypto/pull/273](https\://github\.com/ansible\-collections/community\.crypto/pull/273)\)\.
+* openssl\_csr and openssl\_csr\_pipe \- <code>version</code> now only accepts the \(default\) value 1 \([https\://github\.com/ansible\-collections/community\.crypto/pull/290](https\://github\.com/ansible\-collections/community\.crypto/pull/290)\)\.
+* openssl\_csr\_info \- removed the <code>pyopenssl</code> backend \([https\://github\.com/ansible\-collections/community\.crypto/pull/273](https\://github\.com/ansible\-collections/community\.crypto/pull/273)\)\.
+* openssl\_csr\_pipe \- removed the <code>pyopenssl</code> backend \([https\://github\.com/ansible\-collections/community\.crypto/pull/273](https\://github\.com/ansible\-collections/community\.crypto/pull/273)\)\.
+* openssl\_privatekey \- removed the <code>pyopenssl</code> backend \([https\://github\.com/ansible\-collections/community\.crypto/pull/273](https\://github\.com/ansible\-collections/community\.crypto/pull/273)\)\.
+* openssl\_privatekey\_info \- removed the <code>pyopenssl</code> backend \([https\://github\.com/ansible\-collections/community\.crypto/pull/273](https\://github\.com/ansible\-collections/community\.crypto/pull/273)\)\.
+* openssl\_privatekey\_pipe \- removed the <code>pyopenssl</code> backend \([https\://github\.com/ansible\-collections/community\.crypto/pull/273](https\://github\.com/ansible\-collections/community\.crypto/pull/273)\)\.
+* openssl\_publickey \- removed the <code>pyopenssl</code> backend \([https\://github\.com/ansible\-collections/community\.crypto/pull/273](https\://github\.com/ansible\-collections/community\.crypto/pull/273)\)\.
+* openssl\_publickey\_info \- removed the <code>pyopenssl</code> backend \([https\://github\.com/ansible\-collections/community\.crypto/pull/273](https\://github\.com/ansible\-collections/community\.crypto/pull/273)\)\.
+* openssl\_signature \- removed the <code>pyopenssl</code> backend \([https\://github\.com/ansible\-collections/community\.crypto/pull/273](https\://github\.com/ansible\-collections/community\.crypto/pull/273)\)\.
+* openssl\_signature\_info \- removed the <code>pyopenssl</code> backend \([https\://github\.com/ansible\-collections/community\.crypto/pull/273](https\://github\.com/ansible\-collections/community\.crypto/pull/273)\)\.
+* x509\_certificate \- remove <code>assertonly</code> provider \([https\://github\.com/ansible\-collections/community\.crypto/pull/289](https\://github\.com/ansible\-collections/community\.crypto/pull/289)\)\.
+* x509\_certificate \- removed the <code>pyopenssl</code> backend \([https\://github\.com/ansible\-collections/community\.crypto/pull/273](https\://github\.com/ansible\-collections/community\.crypto/pull/273)\)\.
+* x509\_certificate\_info \- removed the <code>pyopenssl</code> backend \([https\://github\.com/ansible\-collections/community\.crypto/pull/273](https\://github\.com/ansible\-collections/community\.crypto/pull/273)\)\.
+* x509\_certificate\_pipe \- removed the <code>pyopenssl</code> backend \([https\://github\.com/ansible\-collections/community\.crypto/pull/273](https\://github\.com/ansible\-collections/community\.crypto/pull/273)\)\.
+
+<a id="bugfixes-26"></a>
+### Bugfixes
+
+* cryptography backend \- improve Unicode handling for Python 2 \([https\://github\.com/ansible\-collections/community\.crypto/pull/313](https\://github\.com/ansible\-collections/community\.crypto/pull/313)\)\.
+* get\_certificate \- fix compatibility with the cryptography 35\.0\.0 release \([https\://github\.com/ansible\-collections/community\.crypto/pull/294](https\://github\.com/ansible\-collections/community\.crypto/pull/294)\)\.
+* openssl\_csr\_info \- fix compatibility with the cryptography 35\.0\.0 release \([https\://github\.com/ansible\-collections/community\.crypto/pull/294](https\://github\.com/ansible\-collections/community\.crypto/pull/294)\)\.
+* openssl\_pkcs12 \- fix compatibility with the cryptography 35\.0\.0 release \([https\://github\.com/ansible\-collections/community\.crypto/pull/296](https\://github\.com/ansible\-collections/community\.crypto/pull/296)\)\.
+* x509\_certificate\_info \- fix compatibility with the cryptography 35\.0\.0 release \([https\://github\.com/ansible\-collections/community\.crypto/pull/294](https\://github\.com/ansible\-collections/community\.crypto/pull/294)\)\.
+
+<a id="v1-9-4"></a>
+## v1\.9\.4
+
+<a id="release-summary-38"></a>
+### Release Summary
+
+Regular bugfix release\.
+
+<a id="bugfixes-27"></a>
+### Bugfixes
+
+* acme\_\* modules \- fix commands composed for OpenSSL backend to retrieve information on CSRs and certificates from stdin to use <code>/dev/stdin</code> instead of <code>\-</code>\. This is needed for OpenSSL 1\.0\.1 and 1\.0\.2\, apparently \([https\://github\.com/ansible\-collections/community\.crypto/pull/279](https\://github\.com/ansible\-collections/community\.crypto/pull/279)\)\.
+* acme\_challenge\_cert\_helper \- only return exception when cryptography is not installed\, not when a too old version of it is installed\. This prevents Ansible\'s callback to crash \([https\://github\.com/ansible\-collections/community\.crypto/pull/281](https\://github\.com/ansible\-collections/community\.crypto/pull/281)\)\.
+
+<a id="v1-9-3"></a>
+## v1\.9\.3
+
+<a id="release-summary-39"></a>
+### Release Summary
+
+Regular bugfix release\.
+
+<a id="bugfixes-28"></a>
+### Bugfixes
+
+* openssl\_csr and openssl\_csr\_pipe \- make sure that Unicode strings are used to compare strings with the cryptography backend\. This fixes idempotency problems with non\-ASCII letters on Python 2 \([https\://github\.com/ansible\-collections/community\.crypto/issues/270](https\://github\.com/ansible\-collections/community\.crypto/issues/270)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/271](https\://github\.com/ansible\-collections/community\.crypto/pull/271)\)\.
+
+<a id="v1-9-2"></a>
+## v1\.9\.2
+
+<a id="release-summary-40"></a>
+### Release Summary
+
+Bugfix release to fix the changelog\. No other change compared to 1\.9\.0\.
+
+<a id="v1-9-1"></a>
+## v1\.9\.1
+
+<a id="release-summary-41"></a>
+### Release Summary
+
+Accidental 1\.9\.1 release\. Identical to 1\.9\.0\.
+
+<a id="v1-9-0"></a>
+## v1\.9\.0
+
+<a id="release-summary-42"></a>
+### Release Summary
+
+Regular feature release\.
+
+<a id="minor-changes-18"></a>
+### Minor Changes
+
+* get\_certificate \- added <code>starttls</code> option to retrieve certificates from servers which require clients to request an encrypted connection \([https\://github\.com/ansible\-collections/community\.crypto/pull/264](https\://github\.com/ansible\-collections/community\.crypto/pull/264)\)\.
+* openssh\_keypair \- added <code>diff</code> support \([https\://github\.com/ansible\-collections/community\.crypto/pull/260](https\://github\.com/ansible\-collections/community\.crypto/pull/260)\)\.
+
+<a id="bugfixes-29"></a>
+### Bugfixes
+
+* keypair\_backend module utils \- simplify code to pass sanity tests \([https\://github\.com/ansible\-collections/community\.crypto/pull/263](https\://github\.com/ansible\-collections/community\.crypto/pull/263)\)\.
+* openssh\_keypair \- fixed <code>cryptography</code> backend to preserve original file permissions when regenerating a keypair requires existing files to be overwritten \([https\://github\.com/ansible\-collections/community\.crypto/pull/260](https\://github\.com/ansible\-collections/community\.crypto/pull/260)\)\.
+* openssh\_keypair \- fixed error handling to restore original keypair if regeneration fails \([https\://github\.com/ansible\-collections/community\.crypto/pull/260](https\://github\.com/ansible\-collections/community\.crypto/pull/260)\)\.
+* x509\_crl \- restore inherited function signature to pass sanity tests \([https\://github\.com/ansible\-collections/community\.crypto/pull/263](https\://github\.com/ansible\-collections/community\.crypto/pull/263)\)\.
+
+<a id="v1-8-0"></a>
+## v1\.8\.0
+
+<a id="release-summary-43"></a>
+### Release Summary
+
+Regular bugfix and feature release\.
+
+<a id="minor-changes-19"></a>
+### Minor Changes
+
+* Avoid internal ansible\-core module\_utils in favor of equivalent public API available since at least Ansible 2\.9 \([https\://github\.com/ansible\-collections/community\.crypto/pull/253](https\://github\.com/ansible\-collections/community\.crypto/pull/253)\)\.
+* openssh certificate module utils \- new module\_utils for parsing OpenSSH certificates \([https\://github\.com/ansible\-collections/community\.crypto/pull/246](https\://github\.com/ansible\-collections/community\.crypto/pull/246)\)\.
+* openssh\_cert \- added <code>regenerate</code> option to validate additional certificate parameters which trigger regeneration of an existing certificate \([https\://github\.com/ansible\-collections/community\.crypto/pull/256](https\://github\.com/ansible\-collections/community\.crypto/pull/256)\)\.
+* openssh\_cert \- adding <code>diff</code> support \([https\://github\.com/ansible\-collections/community\.crypto/pull/255](https\://github\.com/ansible\-collections/community\.crypto/pull/255)\)\.
+
+<a id="bugfixes-30"></a>
+### Bugfixes
+
+* openssh\_cert \- fixed certificate generation to restore original certificate if an error is encountered \([https\://github\.com/ansible\-collections/community\.crypto/pull/255](https\://github\.com/ansible\-collections/community\.crypto/pull/255)\)\.
+* openssh\_keypair \- fixed a bug that prevented custom file attributes being applied to public keys \([https\://github\.com/ansible\-collections/community\.crypto/pull/257](https\://github\.com/ansible\-collections/community\.crypto/pull/257)\)\.
+
+<a id="v1-7-1"></a>
+## v1\.7\.1
+
+<a id="release-summary-44"></a>
+### Release Summary
+
+Bugfix release\.
+
+<a id="bugfixes-31"></a>
+### Bugfixes
+
+* openssl\_pkcs12 \- fix crash when loading passphrase\-protected PKCS\#12 files with <code>cryptography</code> backend \([https\://github\.com/ansible\-collections/community\.crypto/issues/247](https\://github\.com/ansible\-collections/community\.crypto/issues/247)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/248](https\://github\.com/ansible\-collections/community\.crypto/pull/248)\)\.
+
+<a id="v1-7-0"></a>
+## v1\.7\.0
+
+<a id="release-summary-45"></a>
+### Release Summary
+
+Regular feature and bugfix release\.
+
+<a id="minor-changes-20"></a>
+### Minor Changes
+
+* cryptography\_openssh module utils \- new module\_utils for managing asymmetric keypairs and OpenSSH formatted/encoded asymmetric keypairs \([https\://github\.com/ansible\-collections/community\.crypto/pull/213](https\://github\.com/ansible\-collections/community\.crypto/pull/213)\)\.
+* openssh\_keypair \- added <code>backend</code> parameter for selecting between the cryptography library or the OpenSSH binary for the execution of actions performed by <code>openssh\_keypair</code> \([https\://github\.com/ansible\-collections/community\.crypto/pull/236](https\://github\.com/ansible\-collections/community\.crypto/pull/236)\)\.
+* openssh\_keypair \- added <code>passphrase</code> parameter for encrypting/decrypting OpenSSH private keys \([https\://github\.com/ansible\-collections/community\.crypto/pull/225](https\://github\.com/ansible\-collections/community\.crypto/pull/225)\)\.
+* openssl\_csr \- add diff mode \([https\://github\.com/ansible\-collections/community\.crypto/issues/38](https\://github\.com/ansible\-collections/community\.crypto/issues/38)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/150](https\://github\.com/ansible\-collections/community\.crypto/pull/150)\)\.
+* openssl\_csr\_info \- now returns <code>public\_key\_type</code> and <code>public\_key\_data</code> \([https\://github\.com/ansible\-collections/community\.crypto/pull/233](https\://github\.com/ansible\-collections/community\.crypto/pull/233)\)\.
+* openssl\_csr\_info \- refactor module to allow code reuse for diff mode \([https\://github\.com/ansible\-collections/community\.crypto/pull/204](https\://github\.com/ansible\-collections/community\.crypto/pull/204)\)\.
+* openssl\_csr\_pipe \- add diff mode \([https\://github\.com/ansible\-collections/community\.crypto/issues/38](https\://github\.com/ansible\-collections/community\.crypto/issues/38)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/150](https\://github\.com/ansible\-collections/community\.crypto/pull/150)\)\.
+* openssl\_pkcs12 \- added option <code>select\_crypto\_backend</code> and a <code>cryptography</code> backend\. This requires cryptography 3\.0 or newer\, and does not support the <code>iter\_size</code> and <code>maciter\_size</code> options \([https\://github\.com/ansible\-collections/community\.crypto/pull/234](https\://github\.com/ansible\-collections/community\.crypto/pull/234)\)\.
+* openssl\_privatekey \- add diff mode \([https\://github\.com/ansible\-collections/community\.crypto/issues/38](https\://github\.com/ansible\-collections/community\.crypto/issues/38)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/150](https\://github\.com/ansible\-collections/community\.crypto/pull/150)\)\.
+* openssl\_privatekey\_info \- refactor module to allow code reuse for diff mode \([https\://github\.com/ansible\-collections/community\.crypto/pull/205](https\://github\.com/ansible\-collections/community\.crypto/pull/205)\)\.
+* openssl\_privatekey\_pipe \- add diff mode \([https\://github\.com/ansible\-collections/community\.crypto/issues/38](https\://github\.com/ansible\-collections/community\.crypto/issues/38)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/150](https\://github\.com/ansible\-collections/community\.crypto/pull/150)\)\.
+* openssl\_publickey \- add diff mode \([https\://github\.com/ansible\-collections/community\.crypto/issues/38](https\://github\.com/ansible\-collections/community\.crypto/issues/38)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/150](https\://github\.com/ansible\-collections/community\.crypto/pull/150)\)\.
+* x509\_certificate \- add diff mode \([https\://github\.com/ansible\-collections/community\.crypto/issues/38](https\://github\.com/ansible\-collections/community\.crypto/issues/38)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/150](https\://github\.com/ansible\-collections/community\.crypto/pull/150)\)\.
+* x509\_certificate\_info \- now returns <code>public\_key\_type</code> and <code>public\_key\_data</code> \([https\://github\.com/ansible\-collections/community\.crypto/pull/233](https\://github\.com/ansible\-collections/community\.crypto/pull/233)\)\.
+* x509\_certificate\_info \- refactor module to allow code reuse for diff mode \([https\://github\.com/ansible\-collections/community\.crypto/pull/206](https\://github\.com/ansible\-collections/community\.crypto/pull/206)\)\.
+* x509\_certificate\_pipe \- add diff mode \([https\://github\.com/ansible\-collections/community\.crypto/issues/38](https\://github\.com/ansible\-collections/community\.crypto/issues/38)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/150](https\://github\.com/ansible\-collections/community\.crypto/pull/150)\)\.
+* x509\_crl \- add diff mode \([https\://github\.com/ansible\-collections/community\.crypto/issues/38](https\://github\.com/ansible\-collections/community\.crypto/issues/38)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/150](https\://github\.com/ansible\-collections/community\.crypto/pull/150)\)\.
+* x509\_crl\_info \- add <code>list\_revoked\_certificates</code> option to avoid enumerating all revoked certificates \([https\://github\.com/ansible\-collections/community\.crypto/pull/232](https\://github\.com/ansible\-collections/community\.crypto/pull/232)\)\.
+* x509\_crl\_info \- refactor module to allow code reuse for diff mode \([https\://github\.com/ansible\-collections/community\.crypto/pull/203](https\://github\.com/ansible\-collections/community\.crypto/pull/203)\)\.
+
+<a id="bugfixes-32"></a>
+### Bugfixes
+
+* openssh\_keypair \- fix <code>check\_mode</code> to populate return values for existing keypairs \([https\://github\.com/ansible\-collections/community\.crypto/issues/113](https\://github\.com/ansible\-collections/community\.crypto/issues/113)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/230](https\://github\.com/ansible\-collections/community\.crypto/pull/230)\)\.
+* various modules \- prevent crashes when modules try to set attributes on not yet existing files in check mode\. This will be fixed in ansible\-core 2\.12\, but it is not backported to every Ansible version we support \([https\://github\.com/ansible\-collections/community\.crypto/issue/242](https\://github\.com/ansible\-collections/community\.crypto/issue/242)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/243](https\://github\.com/ansible\-collections/community\.crypto/pull/243)\)\.
+* x509\_certificate \- fix crash when <code>assertonly</code> provider is used and some error conditions should be reported \([https\://github\.com/ansible\-collections/community\.crypto/issues/240](https\://github\.com/ansible\-collections/community\.crypto/issues/240)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/241](https\://github\.com/ansible\-collections/community\.crypto/pull/241)\)\.
+
+<a id="new-modules-1"></a>
+### New Modules
+
+* openssl\_publickey\_info \- Provide information for OpenSSL public keys
+
+<a id="v1-6-2"></a>
+## v1\.6\.2
+
+<a id="release-summary-46"></a>
+### Release Summary
+
+Bugfix release\. Fixes compatibility issue of ACME modules with step\-ca\.
+
+<a id="bugfixes-33"></a>
+### Bugfixes
+
+* acme\_\* modules \- avoid crashing for ACME servers where the <code>meta</code> directory key is not present \([https\://github\.com/ansible\-collections/community\.crypto/issues/220](https\://github\.com/ansible\-collections/community\.crypto/issues/220)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/221](https\://github\.com/ansible\-collections/community\.crypto/pull/221)\)\.
+
+<a id="v1-6-1"></a>
+## v1\.6\.1
+
+<a id="release-summary-47"></a>
+### Release Summary
+
+Bugfix release\.
+
+<a id="bugfixes-34"></a>
+### Bugfixes
+
+* acme\_\* modules \- fix wrong usages of <code>ACMEProtocolException</code> \([https\://github\.com/ansible\-collections/community\.crypto/pull/216](https\://github\.com/ansible\-collections/community\.crypto/pull/216)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/217](https\://github\.com/ansible\-collections/community\.crypto/pull/217)\)\.
+
+<a id="v1-6-0"></a>
+## v1\.6\.0
+
+<a id="release-summary-48"></a>
+### Release Summary
+
+Fixes compatibility issues with the latest ansible\-core 2\.11 beta\, and contains a lot of internal refactoring for the ACME modules and support for private key passphrases for them\.
+
+<a id="minor-changes-21"></a>
+### Minor Changes
+
+* acme module\_utils \- the <code>acme</code> module\_utils has been split up into several Python modules \([https\://github\.com/ansible\-collections/community\.crypto/pull/184](https\://github\.com/ansible\-collections/community\.crypto/pull/184)\)\.
+* acme\_\* modules \- codebase refactor which should not be visible to end\-users \([https\://github\.com/ansible\-collections/community\.crypto/pull/184](https\://github\.com/ansible\-collections/community\.crypto/pull/184)\)\.
+* acme\_\* modules \- support account key passphrases for <code>cryptography</code> backend \([https\://github\.com/ansible\-collections/community\.crypto/issues/197](https\://github\.com/ansible\-collections/community\.crypto/issues/197)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/207](https\://github\.com/ansible\-collections/community\.crypto/pull/207)\)\.
+* acme\_certificate\_revoke \- support revoking by private keys that are passphrase protected for <code>cryptography</code> backend \([https\://github\.com/ansible\-collections/community\.crypto/pull/207](https\://github\.com/ansible\-collections/community\.crypto/pull/207)\)\.
+* acme\_challenge\_cert\_helper \- add <code>private\_key\_passphrase</code> parameter \([https\://github\.com/ansible\-collections/community\.crypto/pull/207](https\://github\.com/ansible\-collections/community\.crypto/pull/207)\)\.
+
+<a id="deprecated-features-5"></a>
+### Deprecated Features
+
+* acme module\_utils \- the <code>acme</code> module\_utils \(<code>ansible\_collections\.community\.crypto\.plugins\.module\_utils\.acme</code>\) is deprecated and will be removed in community\.crypto 2\.0\.0\. Use the new Python modules in the <code>acme</code> package instead \(<code>ansible\_collections\.community\.crypto\.plugins\.module\_utils\.acme\.xxx</code>\) \([https\://github\.com/ansible\-collections/community\.crypto/pull/184](https\://github\.com/ansible\-collections/community\.crypto/pull/184)\)\.
+
+<a id="bugfixes-35"></a>
+### Bugfixes
+
+* action\_module plugin helper \- make compatible with latest changes in ansible\-core 2\.11\.0b3 \([https\://github\.com/ansible\-collections/community\.crypto/pull/202](https\://github\.com/ansible\-collections/community\.crypto/pull/202)\)\.
+* openssl\_privatekey\_pipe \- make compatible with latest changes in ansible\-core 2\.11\.0b3 \([https\://github\.com/ansible\-collections/community\.crypto/pull/202](https\://github\.com/ansible\-collections/community\.crypto/pull/202)\)\.
+
+<a id="v1-5-0"></a>
+## v1\.5\.0
+
+<a id="release-summary-49"></a>
+### Release Summary
+
+Regular feature and bugfix release\. Deprecates a return value\.
+
+<a id="minor-changes-22"></a>
+### Minor Changes
+
+* acme\_account\_info \- when <code>retrieve\_orders</code> is not <code>ignore</code> and the ACME server allows to query orders\, the new return value <code>order\_uris</code> is always populated with a list of URIs \([https\://github\.com/ansible\-collections/community\.crypto/pull/178](https\://github\.com/ansible\-collections/community\.crypto/pull/178)\)\.
+* luks\_device \- allow to specify sector size for LUKS2 containers with new <code>sector\_size</code> parameter \([https\://github\.com/ansible\-collections/community\.crypto/pull/193](https\://github\.com/ansible\-collections/community\.crypto/pull/193)\)\.
+
+<a id="deprecated-features-6"></a>
+### Deprecated Features
+
+* acme\_account\_info \- when <code>retrieve\_orders\=url\_list</code>\, <code>orders</code> will no longer be returned in community\.crypto 2\.0\.0\. Use <code>order\_uris</code> instead \([https\://github\.com/ansible\-collections/community\.crypto/pull/178](https\://github\.com/ansible\-collections/community\.crypto/pull/178)\)\.
+
+<a id="bugfixes-36"></a>
+### Bugfixes
+
+* openssl\_csr \- no longer fails when comparing CSR without basic constraint when <code>basic\_constraints</code> is specified \([https\://github\.com/ansible\-collections/community\.crypto/issues/179](https\://github\.com/ansible\-collections/community\.crypto/issues/179)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/180](https\://github\.com/ansible\-collections/community\.crypto/pull/180)\)\.
+
+<a id="v1-4-0"></a>
+## v1\.4\.0
+
+<a id="release-summary-50"></a>
+### Release Summary
+
+Release with several new features and bugfixes\.
+
+<a id="minor-changes-23"></a>
+### Minor Changes
+
+* The ACME module\_utils has been relicensed back from the Simplified BSD License \([https\://opensource\.org/licenses/BSD\-2\-Clause](https\://opensource\.org/licenses/BSD\-2\-Clause)\) to the GPLv3\+ \(same license used by most other code in this collection\)\. This undoes a licensing change when the original GPLv3\+ licensed code was moved to module\_utils in [https\://github\.com/ansible/ansible/pull/40697](https\://github\.com/ansible/ansible/pull/40697) \([https\://github\.com/ansible\-collections/community\.crypto/pull/165](https\://github\.com/ansible\-collections/community\.crypto/pull/165)\)\.
+* The <code>crypto/identify\.py</code> module\_utils has been renamed to <code>crypto/pem\.py</code> \([https\://github\.com/ansible\-collections/community\.crypto/pull/166](https\://github\.com/ansible\-collections/community\.crypto/pull/166)\)\.
+* luks\_device \- <code>new\_keyfile</code>\, <code>new\_passphrase</code>\, <code>remove\_keyfile</code> and <code>remove\_passphrase</code> are now idempotent \([https\://github\.com/ansible\-collections/community\.crypto/issues/19](https\://github\.com/ansible\-collections/community\.crypto/issues/19)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/168](https\://github\.com/ansible\-collections/community\.crypto/pull/168)\)\.
+* luks\_device \- allow to configure PBKDF \([https\://github\.com/ansible\-collections/community\.crypto/pull/163](https\://github\.com/ansible\-collections/community\.crypto/pull/163)\)\.
+* openssl\_csr\, openssl\_csr\_pipe \- allow to specify CRL distribution endpoints with <code>crl\_distribution\_points</code> \([https\://github\.com/ansible\-collections/community\.crypto/issues/147](https\://github\.com/ansible\-collections/community\.crypto/issues/147)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/167](https\://github\.com/ansible\-collections/community\.crypto/pull/167)\)\.
+* openssl\_pkcs12 \- allow to specify certificate bundles in <code>other\_certificates</code> by using new option <code>other\_certificates\_parse\_all</code> \([https\://github\.com/ansible\-collections/community\.crypto/issues/149](https\://github\.com/ansible\-collections/community\.crypto/issues/149)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/166](https\://github\.com/ansible\-collections/community\.crypto/pull/166)\)\.
+
+<a id="bugfixes-37"></a>
+### Bugfixes
+
+* acme\_certificate \- error when requested challenge type is not found for non\-valid challenges\, instead of hanging on step 2 \([https\://github\.com/ansible\-collections/community\.crypto/issues/171](https\://github\.com/ansible\-collections/community\.crypto/issues/171)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/173](https\://github\.com/ansible\-collections/community\.crypto/pull/173)\)\.
+
+<a id="v1-3-0"></a>
+## v1\.3\.0
+
+<a id="release-summary-51"></a>
+### Release Summary
+
+Contains new modules <code>openssl\_privatekey\_pipe</code>\, <code>openssl\_csr\_pipe</code> and <code>x509\_certificate\_pipe</code> which allow to create or update private keys\, CSRs and X\.509 certificates without having to write them to disk\.
+
+<a id="minor-changes-24"></a>
+### Minor Changes
+
+* openssh\_cert \- add module parameter <code>use\_agent</code> to enable using signing keys stored in ssh\-agent \([https\://github\.com/ansible\-collections/community\.crypto/issues/116](https\://github\.com/ansible\-collections/community\.crypto/issues/116)\)\.
+* openssl\_csr \- refactor module to allow code reuse by openssl\_csr\_pipe \([https\://github\.com/ansible\-collections/community\.crypto/pull/123](https\://github\.com/ansible\-collections/community\.crypto/pull/123)\)\.
+* openssl\_privatekey \- refactor module to allow code reuse by openssl\_privatekey\_pipe \([https\://github\.com/ansible\-collections/community\.crypto/pull/119](https\://github\.com/ansible\-collections/community\.crypto/pull/119)\)\.
+* openssl\_privatekey \- the elliptic curve <code>secp192r1</code> now triggers a security warning\. Elliptic curves of at least 224 bits should be used for new keys\; see [here](https\://cryptography\.io/en/latest/hazmat/primitives/asymmetric/ec\.html\#elliptic\-curves) \([https\://github\.com/ansible\-collections/community\.crypto/pull/132](https\://github\.com/ansible\-collections/community\.crypto/pull/132)\)\.
+* x509\_certificate \- for the <code>selfsigned</code> provider\, a CSR is not required anymore\. If no CSR is provided\, the module behaves as if a minimal CSR which only contains the public key has been provided \([https\://github\.com/ansible\-collections/community\.crypto/issues/32](https\://github\.com/ansible\-collections/community\.crypto/issues/32)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/129](https\://github\.com/ansible\-collections/community\.crypto/pull/129)\)\.
+* x509\_certificate \- refactor module to allow code reuse by x509\_certificate\_pipe \([https\://github\.com/ansible\-collections/community\.crypto/pull/135](https\://github\.com/ansible\-collections/community\.crypto/pull/135)\)\.
+
+<a id="bugfixes-38"></a>
+### Bugfixes
+
+* openssl\_pkcs12 \- report the correct state when <code>action</code> is <code>parse</code> \([https\://github\.com/ansible\-collections/community\.crypto/issues/143](https\://github\.com/ansible\-collections/community\.crypto/issues/143)\)\.
+* support code \- improve handling of certificate and certificate signing request \(CSR\) loading with the <code>cryptography</code> backend when errors occur \([https\://github\.com/ansible\-collections/community\.crypto/issues/138](https\://github\.com/ansible\-collections/community\.crypto/issues/138)\, [https\://github\.com/ansible\-collections/community\.crypto/pull/139](https\://github\.com/ansible\-collections/community\.crypto/pull/139)\)\.
+* x509\_certificate \- fix <code>entrust</code> provider\, which was broken since community\.crypto 0\.1\.0 due to a feature added before the collection move \([https\://github\.com/ansible\-collections/community\.crypto/pull/135](https\://github\.com/ansible\-collections/community\.crypto/pull/135)\)\.
+
+<a id="new-modules-2"></a>
+### New Modules
+
+* openssl\_csr\_pipe \- Generate OpenSSL Certificate Signing Request \(CSR\)
+* openssl\_privatekey\_pipe \- Generate OpenSSL private keys without disk access
+* x509\_certificate\_pipe \- Generate and/or check OpenSSL certificates
+
+<a id="v1-2-0"></a>
+## v1\.2\.0
+
+<a id="release-summary-52"></a>
+### Release Summary
+
+Please note that this release fixes a security issue \(CVE\-2020\-25646\)\.
+
+<a id="minor-changes-25"></a>
+### Minor Changes
+
+* acme\_certificate \- allow to pass CSR file as content with new option <code>csr\_content</code> \([https\://github\.com/ansible\-collections/community\.crypto/pull/115](https\://github\.com/ansible\-collections/community\.crypto/pull/115)\)\.
+* x509\_certificate\_info \- add <code>fingerprints</code> return value which returns certificate fingerprints \([https\://github\.com/ansible\-collections/community\.crypto/pull/121](https\://github\.com/ansible\-collections/community\.crypto/pull/121)\)\.
+
+<a id="security-fixes"></a>
+### Security Fixes
+
+* openssl\_csr \- the option <code>privatekey\_content</code> was not marked as <code>no\_log</code>\, resulting in it being dumped into the system log by default\, and returned in the registered results in the <code>invocation</code> field \(CVE\-2020\-25646\, [https\://github\.com/ansible\-collections/community\.crypto/pull/125](https\://github\.com/ansible\-collections/community\.crypto/pull/125)\)\.
+* openssl\_privatekey\_info \- the option <code>content</code> was not marked as <code>no\_log</code>\, resulting in it being dumped into the system log by default\, and returned in the registered results in the <code>invocation</code> field \(CVE\-2020\-25646\, [https\://github\.com/ansible\-collections/community\.crypto/pull/125](https\://github\.com/ansible\-collections/community\.crypto/pull/125)\)\.
+* openssl\_publickey \- the option <code>privatekey\_content</code> was not marked as <code>no\_log</code>\, resulting in it being dumped into the system log by default\, and returned in the registered results in the <code>invocation</code> field \(CVE\-2020\-25646\, [https\://github\.com/ansible\-collections/community\.crypto/pull/125](https\://github\.com/ansible\-collections/community\.crypto/pull/125)\)\.
+* openssl\_signature \- the option <code>privatekey\_content</code> was not marked as <code>no\_log</code>\, resulting in it being dumped into the system log by default\, and returned in the registered results in the <code>invocation</code> field \(CVE\-2020\-25646\, [https\://github\.com/ansible\-collections/community\.crypto/pull/125](https\://github\.com/ansible\-collections/community\.crypto/pull/125)\)\.
+* x509\_certificate \- the options <code>privatekey\_content</code> and <code>ownca\_privatekey\_content</code> were not marked as <code>no\_log</code>\, resulting in it being dumped into the system log by default\, and returned in the registered results in the <code>invocation</code> field \(CVE\-2020\-25646\, [https\://github\.com/ansible\-collections/community\.crypto/pull/125](https\://github\.com/ansible\-collections/community\.crypto/pull/125)\)\.
+* x509\_crl \- the option <code>privatekey\_content</code> was not marked as <code>no\_log</code>\, resulting in it being dumped into the system log by default\, and returned in the registered results in the <code>invocation</code> field \(CVE\-2020\-25646\, [https\://github\.com/ansible\-collections/community\.crypto/pull/125](https\://github\.com/ansible\-collections/community\.crypto/pull/125)\)\.
+
+<a id="bugfixes-39"></a>
+### Bugfixes
+
+* openssl\_pkcs12 \- do not crash when reading PKCS\#12 file which has no private key and/or no main certificate \([https\://github\.com/ansible\-collections/community\.crypto/issues/103](https\://github\.com/ansible\-collections/community\.crypto/issues/103)\)\.
+
+<a id="v1-1-1"></a>
+## v1\.1\.1
+
+<a id="release-summary-53"></a>
+### Release Summary
+
+Bugfixes for Ansible 2\.10\.0\.
+
+<a id="bugfixes-40"></a>
+### Bugfixes
+
+* meta/runtime\.yml \- convert Ansible version numbers for old names of modules to collection version numbers \([https\://github\.com/ansible\-collections/community\.crypto/pull/108](https\://github\.com/ansible\-collections/community\.crypto/pull/108)\)\.
+* openssl\_csr \- improve handling of IDNA errors \([https\://github\.com/ansible\-collections/community\.crypto/issues/105](https\://github\.com/ansible\-collections/community\.crypto/issues/105)\)\.
+
+<a id="v1-1-0"></a>
+## v1\.1\.0
+
+<a id="release-summary-54"></a>
+### Release Summary
+
+Release for Ansible 2\.10\.0\.
+
+<a id="minor-changes-26"></a>
+### Minor Changes
+
+* acme\_account \- add <code>external\_account\_binding</code> option to allow creation of ACME accounts with External Account Binding \([https\://github\.com/ansible\-collections/community\.crypto/issues/89](https\://github\.com/ansible\-collections/community\.crypto/issues/89)\)\.
+* acme\_certificate \- allow new selector <code>test\_certificates\: first</code> for <code>select\_chain</code> parameter \([https\://github\.com/ansible\-collections/community\.crypto/pull/102](https\://github\.com/ansible\-collections/community\.crypto/pull/102)\)\.
+* cryptography backends \- support arbitrary dotted OIDs \([https\://github\.com/ansible\-collections/community\.crypto/issues/39](https\://github\.com/ansible\-collections/community\.crypto/issues/39)\)\.
+* get\_certificate \- add support for SNI \([https\://github\.com/ansible\-collections/community\.crypto/issues/69](https\://github\.com/ansible\-collections/community\.crypto/issues/69)\)\.
+* luks\_device \- add support for encryption options on container creation \([https\://github\.com/ansible\-collections/community\.crypto/pull/97](https\://github\.com/ansible\-collections/community\.crypto/pull/97)\)\.
+* openssh\_cert \- add support for PKCS\#11 tokens \([https\://github\.com/ansible\-collections/community\.crypto/pull/95](https\://github\.com/ansible\-collections/community\.crypto/pull/95)\)\.
+* openssl\_certificate \- the PyOpenSSL backend now uses 160 bits of randomness for serial numbers\, instead of a random number between 1000 and 99999\. Please note that this is not a high quality random number \([https\://github\.com/ansible\-collections/community\.crypto/issues/76](https\://github\.com/ansible\-collections/community\.crypto/issues/76)\)\.
+* openssl\_csr \- add support for name constraints extension \([https\://github\.com/ansible\-collections/community\.crypto/issues/46](https\://github\.com/ansible\-collections/community\.crypto/issues/46)\)\.
+* openssl\_csr\_info \- add support for name constraints extension \([https\://github\.com/ansible\-collections/community\.crypto/issues/46](https\://github\.com/ansible\-collections/community\.crypto/issues/46)\)\.
+
+<a id="bugfixes-41"></a>
+### Bugfixes
+
+* acme\_inspect \- fix problem with Python 3\.5 that JSON was not decoded \([https\://github\.com/ansible\-collections/community\.crypto/issues/86](https\://github\.com/ansible\-collections/community\.crypto/issues/86)\)\.
+* get\_certificate \- fix <code>ca\_cert</code> option handling when <code>proxy\_host</code> is used \([https\://github\.com/ansible\-collections/community\.crypto/pull/84](https\://github\.com/ansible\-collections/community\.crypto/pull/84)\)\.
+* openssl\_\*\, x509\_\* modules \- fix handling of general names which refer to IP networks and not IP addresses \([https\://github\.com/ansible\-collections/community\.crypto/pull/92](https\://github\.com/ansible\-collections/community\.crypto/pull/92)\)\.
+
+<a id="new-modules-3"></a>
+### New Modules
+
+* openssl\_signature \- Sign data with openssl
+* openssl\_signature\_info \- Verify signatures with openssl
+
+<a id="v1-0-0"></a>
+## v1\.0\.0
+
+<a id="release-summary-55"></a>
+### Release Summary
+
+This is the first proper release of the <code>community\.crypto</code> collection\. This changelog contains all changes to the modules in this collection that were added after the release of Ansible 2\.9\.0\.
+
+<a id="minor-changes-27"></a>
+### Minor Changes
+
+* luks\_device \- accept <code>passphrase</code>\, <code>new\_passphrase</code> and <code>remove\_passphrase</code>\.
+* luks\_device \- add <code>keysize</code> parameter to set key size at LUKS container creation
+* luks\_device \- added support to use UUIDs\, and labels with LUKS2 containers
+* luks\_device \- added the <code>type</code> option that allows user explicit define the LUKS container format version
+* openssh\_keypair \- instead of regenerating some broken or password protected keys\, fail the module\. Keys can still be regenerated by calling the module with <code>force\=yes</code>\.
+* openssh\_keypair \- the <code>regenerate</code> option allows to configure the module\'s behavior when it should or needs to regenerate private keys\.
+* openssl\_\* modules \- the cryptography backend now properly supports <code>dirName</code>\, <code>otherName</code> and <code>RID</code> \(Registered ID\) names\.
+* openssl\_certificate \- Add option for changing which ACME directory to use with acme\-tiny\. Set the default ACME directory to Let\'s Encrypt instead of using acme\-tiny\'s default\. \(acme\-tiny also uses Let\'s Encrypt at the time being\, so no action should be necessary\.\)
+* openssl\_certificate \- Change the required version of acme\-tiny to \>\= 4\.0\.0
+* openssl\_certificate \- allow to provide content of some input files via the <code>csr\_content</code>\, <code>privatekey\_content</code>\, <code>ownca\_privatekey\_content</code> and <code>ownca\_content</code> options\.
+* openssl\_certificate \- allow to return the existing/generated certificate directly as <code>certificate</code> by setting <code>return\_content</code> to <code>yes</code>\.
+* openssl\_certificate\_info \- allow to provide certificate content via <code>content</code> option \([https\://github\.com/ansible/ansible/issues/64776](https\://github\.com/ansible/ansible/issues/64776)\)\.
+* openssl\_csr \- Add support for specifying the SAN <code>otherName</code> value in the OpenSSL ASN\.1 UTF8 string format\, <code>otherName\:\<OID\>\;UTF8\:string value</code>\.
+* openssl\_csr \- allow to provide private key content via <code>private\_key\_content</code> option\.
+* openssl\_csr \- allow to return the existing/generated CSR directly as <code>csr</code> by setting <code>return\_content</code> to <code>yes</code>\.
+* openssl\_csr\_info \- allow to provide CSR content via <code>content</code> option\.
+* openssl\_dhparam \- allow to return the existing/generated DH params directly as <code>dhparams</code> by setting <code>return\_content</code> to <code>yes</code>\.
+* openssl\_dhparam \- now supports a <code>cryptography</code>\-based backend\. Auto\-detection can be overwritten with the <code>select\_crypto\_backend</code> option\.
+* openssl\_pkcs12 \- allow to return the existing/generated PKCS\#12 directly as <code>pkcs12</code> by setting <code>return\_content</code> to <code>yes</code>\.
+* openssl\_privatekey \- add <code>format</code> and <code>format\_mismatch</code> options\.
+* openssl\_privatekey \- allow to return the existing/generated private key directly as <code>privatekey</code> by setting <code>return\_content</code> to <code>yes</code>\.
+* openssl\_privatekey \- the <code>regenerate</code> option allows to configure the module\'s behavior when it should or needs to regenerate private keys\.
+* openssl\_privatekey\_info \- allow to provide private key content via <code>content</code> option\.
+* openssl\_publickey \- allow to provide private key content via <code>private\_key\_content</code> option\.
+* openssl\_publickey \- allow to return the existing/generated public key directly as <code>publickey</code> by setting <code>return\_content</code> to <code>yes</code>\.
+
+<a id="deprecated-features-7"></a>
+### Deprecated Features
+
+* openssl\_csr \- all values for the <code>version</code> option except <code>1</code> are deprecated\. The value 1 denotes the current only standardized CSR version\.
+
+<a id="removed-features-previously-deprecated-1"></a>
+### Removed Features \(previously deprecated\)
+
+* The <code>letsencrypt</code> module has been removed\. Use <code>acme\_certificate</code> instead\.
+
+<a id="bugfixes-42"></a>
+### Bugfixes
+
+* ACME modules\: fix bug in ACME v1 account update code
+* ACME modules\: make sure some connection errors are handled properly
+* ACME modules\: support Buypass\' ACME v1 endpoint
+* acme\_certificate \- fix crash when module is used with Python 2\.x\.
+* acme\_certificate \- fix misbehavior when ACME v1 is used with <code>modify\_account</code> set to <code>false</code>\.
+* ecs\_certificate \- Always specify header <code>connection\: keep\-alive</code> for ECS API connections\.
+* ecs\_certificate \- Fix formatting of contents of <code>full\_chain\_path</code>\.
+* get\_certificate \- Fix cryptography backend when pyopenssl is unavailable \([https\://github\.com/ansible/ansible/issues/67900](https\://github\.com/ansible/ansible/issues/67900)\)
+* openssh\_keypair \- add logic to avoid breaking password protected keys\.
+* openssh\_keypair \- fixes idempotence issue with public key \([https\://github\.com/ansible/ansible/issues/64969](https\://github\.com/ansible/ansible/issues/64969)\)\.
+* openssh\_keypair \- public key\'s file attributes \(permissions\, owner\, group\, etc\.\) are now set to the same values as the private key\.
+* openssl\_\* modules \- prevent crash on fingerprint determination in FIPS mode \([https\://github\.com/ansible/ansible/issues/67213](https\://github\.com/ansible/ansible/issues/67213)\)\.
+* openssl\_certificate \- When provider is <code>entrust</code>\, use a <code>connection\: keep\-alive</code> header for ECS API connections\.
+* openssl\_certificate \- <code>provider</code> option was documented as required\, but it was not checked whether it was provided\. It is now only required when <code>state</code> is <code>present</code>\.
+* openssl\_certificate \- fix <code>assertonly</code> provider certificate verification\, causing \'private key mismatch\' and \'subject mismatch\' errors\.
+* openssl\_certificate and openssl\_csr \- fix Ed25519 and Ed448 private key support for <code>cryptography</code> backend\. This probably needs at least cryptography 2\.8\, since older versions have problems with signing certificates or CSRs with such keys\. \([https\://github\.com/ansible/ansible/issues/59039](https\://github\.com/ansible/ansible/issues/59039)\, PR [https\://github\.com/ansible/ansible/pull/63984](https\://github\.com/ansible/ansible/pull/63984)\)
+* openssl\_csr \- a warning is issued if an unsupported value for <code>version</code> is used for the <code>cryptography</code> backend\.
+* openssl\_csr \- the module will now enforce that <code>privatekey\_path</code> is specified when <code>state\=present</code>\.
+* openssl\_publickey \- fix a module crash caused when pyOpenSSL is not installed \([https\://github\.com/ansible/ansible/issues/67035](https\://github\.com/ansible/ansible/issues/67035)\)\.
+
+<a id="new-modules-4"></a>
+### New Modules
+
+* ecs\_domain \- Request validation of a domain with the Entrust Certificate Services \(ECS\) API
+* x509\_crl \- Generate Certificate Revocation Lists \(CRLs\)
+* x509\_crl\_info \- Retrieve information on Certificate Revocation Lists \(CRLs\)
diff --git a/ansible_collections/community/docker/tests/sanity/ignore-2.10.txt.license b/ansible_collections/community/crypto/CHANGELOG.md.license
index edff8c768..edff8c768 100644
--- a/ansible_collections/community/docker/tests/sanity/ignore-2.10.txt.license
+++ b/ansible_collections/community/crypto/CHANGELOG.md.license
diff --git a/ansible_collections/community/crypto/CHANGELOG.rst b/ansible_collections/community/crypto/CHANGELOG.rst
index 940ed0c43..320169717 100644
--- a/ansible_collections/community/crypto/CHANGELOG.rst
+++ b/ansible_collections/community/crypto/CHANGELOG.rst
@@ -4,6 +4,191 @@ Community Crypto Release Notes
.. contents:: Topics
+v2.18.0
+=======
+
+Release Summary
+---------------
+
+Bugfix and feature release.
+
+Minor Changes
+-------------
+
+- x509_crl - the new option ``serial_numbers`` allow to configure in which format serial numbers can be provided to ``revoked_certificates[].serial_number``. The default is as integers (``serial_numbers=integer``) for backwards compatibility; setting ``serial_numbers=hex-octets`` allows to specify colon-separated hex octet strings like ``00:11:22:FF`` (https://github.com/ansible-collections/community.crypto/issues/687, https://github.com/ansible-collections/community.crypto/pull/715).
+
+Deprecated Features
+-------------------
+
+- openssl_csr_pipe, openssl_privatekey_pipe, x509_certificate_pipe - the current behavior of check mode is deprecated and will change in community.crypto 3.0.0. The current behavior is similar to the modules without ``_pipe``: if the object needs to be (re-)generated, only the ``changed`` status is set, but the object is not updated. From community.crypto 3.0.0 on, the modules will ignore check mode and always act as if check mode is not active. This behavior can already achieved now by adding ``check_mode: false`` to the task. If you think this breaks your use-case of this module, please `create an issue in the community.crypto repository <https://github.com/ansible-collections/community.crypto/issues/new/choose>`__ (https://github.com/ansible-collections/community.crypto/issues/712, https://github.com/ansible-collections/community.crypto/pull/714).
+
+Bugfixes
+--------
+
+- luks_device - fixed module a bug that prevented using ``remove_keyslot`` with the value ``0`` (https://github.com/ansible-collections/community.crypto/pull/710).
+- luks_device - fixed module falsely outputting ``changed=false`` when trying to add a new slot with a key that is already present in another slot. The module now rejects adding keys that are already present in another slot (https://github.com/ansible-collections/community.crypto/pull/710).
+- luks_device - fixed testing of LUKS passphrases in when specifying a keyslot for cryptsetup version 2.0.3. The output of this cryptsetup version slightly differs from later versions (https://github.com/ansible-collections/community.crypto/pull/710).
+
+New Plugins
+-----------
+
+Filter
+~~~~~~
+
+- parse_serial - Convert a serial number as a colon-separated list of hex numbers to an integer
+- to_serial - Convert an integer to a colon-separated list of hex numbers
+
+v2.17.1
+=======
+
+Release Summary
+---------------
+
+Bugfix release for compatibility with cryptography 42.0.0.
+
+Bugfixes
+--------
+
+- openssl_dhparam - was using an internal function instead of the public API to load DH param files when using the ``cryptography`` backend. The internal function was removed in cryptography 42.0.0. The module now uses the public API, which has been available since support for DH params was added to cryptography (https://github.com/ansible-collections/community.crypto/pull/698).
+- openssl_privatekey_info - ``check_consistency=true`` no longer works for RSA keys with cryptography 42.0.0+ (https://github.com/ansible-collections/community.crypto/pull/701).
+- openssl_privatekey_info - ``check_consistency=true`` now reports a warning if it cannot determine consistency (https://github.com/ansible-collections/community.crypto/pull/705).
+
+v2.17.0
+=======
+
+Release Summary
+---------------
+
+Feature release.
+
+Minor Changes
+-------------
+
+- luks_device - add allow discards option (https://github.com/ansible-collections/community.crypto/pull/693).
+
+v2.16.2
+=======
+
+Release Summary
+---------------
+
+Bugfix release.
+
+Bugfixes
+--------
+
+- acme_* modules - directly react on bad return data for account creation/retrieval/updating requests (https://github.com/ansible-collections/community.crypto/pull/682).
+- acme_* modules - fix improved error reporting in case of socket errors, bad status lines, and unknown connection errors (https://github.com/ansible-collections/community.crypto/pull/684).
+- acme_* modules - increase number of retries from 5 to 10 to increase stability with unstable ACME endpoints (https://github.com/ansible-collections/community.crypto/pull/685).
+- acme_* modules - make account registration handling more flexible to accept 404 instead of 400 send by DigiCert's ACME endpoint when an account does not exist (https://github.com/ansible-collections/community.crypto/pull/681).
+
+v2.16.1
+=======
+
+Release Summary
+---------------
+
+Bugfix release.
+
+Bugfixes
+--------
+
+- acme_* modules - also retry requests in case of socket errors, bad status lines, and unknown connection errors; improve error messages in these cases (https://github.com/ansible-collections/community.crypto/issues/680).
+
+v2.16.0
+=======
+
+Release Summary
+---------------
+
+Bugfix release.
+
+Minor Changes
+-------------
+
+- luks_devices - add new options ``keyslot``, ``new_keyslot``, and ``remove_keyslot`` to allow adding/removing keys to/from specific keyslots (https://github.com/ansible-collections/community.crypto/pull/664).
+
+Bugfixes
+--------
+
+- openssl_pkcs12 - modify autodetect to not detect pyOpenSSL >= 23.3.0, which removed PKCS#12 support (https://github.com/ansible-collections/community.crypto/pull/666).
+
+v2.15.1
+=======
+
+Release Summary
+---------------
+
+Bugfix release.
+
+Bugfixes
+--------
+
+- acme_* modules - correctly handle error documents without ``type`` (https://github.com/ansible-collections/community.crypto/issues/651, https://github.com/ansible-collections/community.crypto/pull/652).
+
+v2.15.0
+=======
+
+Release Summary
+---------------
+
+Bugfix and feature release.
+
+Minor Changes
+-------------
+
+- openssh_keypair - fail when comment cannot be updated (https://github.com/ansible-collections/community.crypto/pull/646).
+
+Deprecated Features
+-------------------
+
+- get_certificate - the default ``false`` of the ``asn1_base64`` option is deprecated and will change to ``true`` in community.crypto 3.0.0 (https://github.com/ansible-collections/community.crypto/pull/600).
+
+Bugfixes
+--------
+
+- openssh_cert, openssh_keypair - the modules ignored return codes of ``ssh`` and ``ssh-keygen`` in some cases (https://github.com/ansible-collections/community.crypto/issues/645, https://github.com/ansible-collections/community.crypto/pull/646).
+- openssh_keypair - fix comment updating for OpenSSH before 6.5 (https://github.com/ansible-collections/community.crypto/pull/646).
+
+New Plugins
+-----------
+
+Filter
+~~~~~~
+
+- gpg_fingerprint - Retrieve a GPG fingerprint from a GPG public or private key
+
+Lookup
+~~~~~~
+
+- gpg_fingerprint - Retrieve a GPG fingerprint from a GPG public or private key file
+
+v2.14.1
+=======
+
+Release Summary
+---------------
+
+Bugfix and maintenance release with updated documentation.
+
+From this version on, community.crypto is using the new `Ansible semantic markup
+<https://docs.ansible.com/ansible/devel/dev_guide/developing_modules_documenting.html#semantic-markup-within-module-documentation>`__
+in its documentation. If you look at documentation with the ansible-doc CLI tool
+from ansible-core before 2.15, please note that it does not render the markup
+correctly. You should be still able to read it in most cases, but you need
+ansible-core 2.15 or later to see it as it is intended. Alternatively you can
+look at `the devel docsite <https://docs.ansible.com/ansible/devel/collections/community/crypto/>`__
+for the rendered HTML version of the documentation of the latest release.
+
+Bugfixes
+--------
+
+- Fix PEM detection/identification to also accept random other lines before the line starting with ``-----BEGIN`` (https://github.com/ansible-collections/community.crypto/issues/627, https://github.com/ansible-collections/community.crypto/pull/628).
+
+Known Issues
+------------
+
+- Ansible markup will show up in raw form on ansible-doc text output for ansible-core before 2.15. If you have trouble deciphering the documentation markup, please upgrade to ansible-core 2.15 (or newer), or read the HTML documentation on https://docs.ansible.com/ansible/devel/collections/community/crypto/.
v2.14.0
=======
@@ -254,7 +439,6 @@ This release is identical to what should have been 2.3.3, except that the
version number has been bumped to 2.3.4 and this changelog entry for 2.3.4
has been added.
-
v2.3.3
======
@@ -309,7 +493,7 @@ Minor Changes
-------------
- Prepare collection for inclusion in an Execution Environment by declaring its dependencies. Please note that system packages are used for cryptography and PyOpenSSL, which can be rather limited. If you need features from newer cryptography versions, you will have to manually force a newer version to be installed by pip by specifying something like ``cryptography >= 37.0.0`` in your Execution Environment's Python dependencies file (https://github.com/ansible-collections/community.crypto/pull/440).
-- Support automatic conversion for Internalionalized Domain Names (IDNs). When passing general names, for example Subject Altenative Names to ``community.crypto.openssl_csr``, these will automatically be converted to IDNA. Conversion will be done per label to IDNA2008 if possible, and IDNA2003 if IDNA2008 conversion fails for that label. Note that IDNA conversion requires `the Python idna library <https://pypi.org/project/idna/>`_ to be installed. Please note that depending on which versions of the cryptography library are used, it could try to process the converted IDNA another time with the Python ``idna`` library and reject IDNA2003 encoded values. Using a new enough ``cryptography`` version avoids this (https://github.com/ansible-collections/community.crypto/issues/426, https://github.com/ansible-collections/community.crypto/pull/436).
+- Support automatic conversion for Internalionalized Domain Names (IDNs). When passing general names, for example Subject Alternative Names to ``community.crypto.openssl_csr``, these will automatically be converted to IDNA. Conversion will be done per label to IDNA2008 if possible, and IDNA2003 if IDNA2008 conversion fails for that label. Note that IDNA conversion requires `the Python idna library <https://pypi.org/project/idna/>`_ to be installed. Please note that depending on which versions of the cryptography library are used, it could try to process the converted IDNA another time with the Python ``idna`` library and reject IDNA2003 encoded values. Using a new enough ``cryptography`` version avoids this (https://github.com/ansible-collections/community.crypto/issues/426, https://github.com/ansible-collections/community.crypto/pull/436).
- acme_* modules - add parameter ``request_timeout`` to manage HTTP(S) request timeout (https://github.com/ansible-collections/community.crypto/issues/447, https://github.com/ansible-collections/community.crypto/pull/448).
- luks_devices - added ``perf_same_cpu_crypt``, ``perf_submit_from_crypt_cpus``, ``perf_no_read_workqueue``, ``perf_no_write_workqueue`` for performance tuning when opening LUKS2 containers (https://github.com/ansible-collections/community.crypto/issues/427).
- luks_devices - added ``persistent`` option when opening LUKS2 containers (https://github.com/ansible-collections/community.crypto/pull/434).
@@ -361,7 +545,6 @@ Regular bugfix release.
In this release, we extended the test matrix to include Alpine 3, ArchLinux, Debian Bullseye, and CentOS Stream 8. CentOS 8 was removed from the test matrix.
-
Bugfixes
--------
@@ -465,7 +648,6 @@ Release Summary
A new major release of the ``community.crypto`` collection. The main changes are removal of the PyOpenSSL backends for almost all modules (``openssl_pkcs12`` being the only exception), and removal of the ``assertonly`` provider in the ``x509_certificate`` provider. There are also some other breaking changes which should improve the user interface/experience of this collection long-term.
-
Minor Changes
-------------
@@ -648,20 +830,20 @@ Minor Changes
- openssh_keypair - added ``passphrase`` parameter for encrypting/decrypting OpenSSH private keys (https://github.com/ansible-collections/community.crypto/pull/225).
- openssl_csr - add diff mode (https://github.com/ansible-collections/community.crypto/issues/38, https://github.com/ansible-collections/community.crypto/pull/150).
- openssl_csr_info - now returns ``public_key_type`` and ``public_key_data`` (https://github.com/ansible-collections/community.crypto/pull/233).
-- openssl_csr_info - refactor module to allow code re-use for diff mode (https://github.com/ansible-collections/community.crypto/pull/204).
+- openssl_csr_info - refactor module to allow code reuse for diff mode (https://github.com/ansible-collections/community.crypto/pull/204).
- openssl_csr_pipe - add diff mode (https://github.com/ansible-collections/community.crypto/issues/38, https://github.com/ansible-collections/community.crypto/pull/150).
- openssl_pkcs12 - added option ``select_crypto_backend`` and a ``cryptography`` backend. This requires cryptography 3.0 or newer, and does not support the ``iter_size`` and ``maciter_size`` options (https://github.com/ansible-collections/community.crypto/pull/234).
- openssl_privatekey - add diff mode (https://github.com/ansible-collections/community.crypto/issues/38, https://github.com/ansible-collections/community.crypto/pull/150).
-- openssl_privatekey_info - refactor module to allow code re-use for diff mode (https://github.com/ansible-collections/community.crypto/pull/205).
+- openssl_privatekey_info - refactor module to allow code reuse for diff mode (https://github.com/ansible-collections/community.crypto/pull/205).
- openssl_privatekey_pipe - add diff mode (https://github.com/ansible-collections/community.crypto/issues/38, https://github.com/ansible-collections/community.crypto/pull/150).
- openssl_publickey - add diff mode (https://github.com/ansible-collections/community.crypto/issues/38, https://github.com/ansible-collections/community.crypto/pull/150).
- x509_certificate - add diff mode (https://github.com/ansible-collections/community.crypto/issues/38, https://github.com/ansible-collections/community.crypto/pull/150).
- x509_certificate_info - now returns ``public_key_type`` and ``public_key_data`` (https://github.com/ansible-collections/community.crypto/pull/233).
-- x509_certificate_info - refactor module to allow code re-use for diff mode (https://github.com/ansible-collections/community.crypto/pull/206).
+- x509_certificate_info - refactor module to allow code reuse for diff mode (https://github.com/ansible-collections/community.crypto/pull/206).
- x509_certificate_pipe - add diff mode (https://github.com/ansible-collections/community.crypto/issues/38, https://github.com/ansible-collections/community.crypto/pull/150).
- x509_crl - add diff mode (https://github.com/ansible-collections/community.crypto/issues/38, https://github.com/ansible-collections/community.crypto/pull/150).
- x509_crl_info - add ``list_revoked_certificates`` option to avoid enumerating all revoked certificates (https://github.com/ansible-collections/community.crypto/pull/232).
-- x509_crl_info - refactor module to allow code re-use for diff mode (https://github.com/ansible-collections/community.crypto/pull/203).
+- x509_crl_info - refactor module to allow code reuse for diff mode (https://github.com/ansible-collections/community.crypto/pull/203).
Bugfixes
--------
@@ -784,16 +966,15 @@ Release Summary
Contains new modules ``openssl_privatekey_pipe``, ``openssl_csr_pipe`` and ``x509_certificate_pipe`` which allow to create or update private keys, CSRs and X.509 certificates without having to write them to disk.
-
Minor Changes
-------------
- openssh_cert - add module parameter ``use_agent`` to enable using signing keys stored in ssh-agent (https://github.com/ansible-collections/community.crypto/issues/116).
-- openssl_csr - refactor module to allow code re-use by openssl_csr_pipe (https://github.com/ansible-collections/community.crypto/pull/123).
-- openssl_privatekey - refactor module to allow code re-use by openssl_privatekey_pipe (https://github.com/ansible-collections/community.crypto/pull/119).
+- openssl_csr - refactor module to allow code reuse by openssl_csr_pipe (https://github.com/ansible-collections/community.crypto/pull/123).
+- openssl_privatekey - refactor module to allow code reuse by openssl_privatekey_pipe (https://github.com/ansible-collections/community.crypto/pull/119).
- openssl_privatekey - the elliptic curve ``secp192r1`` now triggers a security warning. Elliptic curves of at least 224 bits should be used for new keys; see `here <https://cryptography.io/en/latest/hazmat/primitives/asymmetric/ec.html#elliptic-curves>`_ (https://github.com/ansible-collections/community.crypto/pull/132).
- x509_certificate - for the ``selfsigned`` provider, a CSR is not required anymore. If no CSR is provided, the module behaves as if a minimal CSR which only contains the public key has been provided (https://github.com/ansible-collections/community.crypto/issues/32, https://github.com/ansible-collections/community.crypto/pull/129).
-- x509_certificate - refactor module to allow code re-use by x509_certificate_pipe (https://github.com/ansible-collections/community.crypto/pull/135).
+- x509_certificate - refactor module to allow code reuse by x509_certificate_pipe (https://github.com/ansible-collections/community.crypto/pull/135).
Bugfixes
--------
@@ -860,7 +1041,6 @@ Release Summary
Release for Ansible 2.10.0.
-
Minor Changes
-------------
@@ -895,7 +1075,6 @@ Release Summary
This is the first proper release of the ``community.crypto`` collection. This changelog contains all changes to the modules in this collection that were added after the release of Ansible 2.9.0.
-
Minor Changes
-------------
@@ -906,7 +1085,7 @@ Minor Changes
- openssh_keypair - instead of regenerating some broken or password protected keys, fail the module. Keys can still be regenerated by calling the module with ``force=yes``.
- openssh_keypair - the ``regenerate`` option allows to configure the module's behavior when it should or needs to regenerate private keys.
- openssl_* modules - the cryptography backend now properly supports ``dirName``, ``otherName`` and ``RID`` (Registered ID) names.
-- openssl_certificate - Add option for changing which ACME directory to use with acme-tiny. Set the default ACME directory to Let's Encrypt instead of using acme-tiny's default. (acme-tiny also uses Let's Encrypt at the time being, so no action should be neccessary.)
+- openssl_certificate - Add option for changing which ACME directory to use with acme-tiny. Set the default ACME directory to Let's Encrypt instead of using acme-tiny's default. (acme-tiny also uses Let's Encrypt at the time being, so no action should be necessary.)
- openssl_certificate - Change the required version of acme-tiny to >= 4.0.0
- openssl_certificate - allow to provide content of some input files via the ``csr_content``, ``privatekey_content``, ``ownca_privatekey_content`` and ``ownca_content`` options.
- openssl_certificate - allow to return the existing/generated certificate directly as ``certificate`` by setting ``return_content`` to ``yes``.
diff --git a/ansible_collections/community/crypto/FILES.json b/ansible_collections/community/crypto/FILES.json
index 1b50debec..249caaa96 100644
--- a/ansible_collections/community/crypto/FILES.json
+++ b/ansible_collections/community/crypto/FILES.json
@@ -109,7 +109,7 @@
"name": ".azure-pipelines/azure-pipelines.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "691ac4e41aaa53e9b556a626fac186a38637ccb41093d0d15023fa80b550fc85",
+ "chksum_sha256": "82056264d02238b30cfe7740554b4dcde7ec173c7a5de5e494f2fad309462455",
"format": 1
},
{
@@ -130,7 +130,7 @@
"name": ".github/workflows/ansible-test.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7b70d3a4a411debb31f68a1d6d2e22d94f871e0c48f356728aa679b003c5b04e",
+ "chksum_sha256": "aac90c499964bd9233fc13565169248e29e9eda7cf97a2d4db56f6fdba9558ed",
"format": 1
},
{
@@ -151,14 +151,21 @@
"name": ".github/workflows/ee.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "29b85993d26447dc9aba53b7a8cfbc997125595de343fe943e7a701ecd3b928a",
+ "chksum_sha256": "c482219d3ea4b769a0951e146c43522e5076ea629e3a2263e6cee903e27087fc",
+ "format": 1
+ },
+ {
+ "name": ".github/workflows/import-galaxy.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "739c36223d6e0e6ccc98907c43cba53296e7b1ccd64a2d995c2ff21df4ab25a5",
"format": 1
},
{
"name": ".github/workflows/reuse.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7642b7c0999df1190506e7d73be3ea67f5e7f9bb78e809951a96b2f5418a8798",
+ "chksum_sha256": "907950e209820f04e0122e100c86690cf5ac0f4a15cb950cce4d2af6eaaddb37",
"format": 1
},
{
@@ -256,7 +263,7 @@
"name": "changelogs/changelog.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "75e5ff73018cb4f36565a129cffe94719e80e7a7c0704195416962eac2d6888e",
+ "chksum_sha256": "e03726652f634d6ff4b51599ec42f48c6ff77aaec7d59c186770af2c599b2d3f",
"format": 1
},
{
@@ -270,7 +277,7 @@
"name": "changelogs/config.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "35eb45f26e27a9f2830eb5cd398b976e603c12a7e302e5748b2860782f8ebe76",
+ "chksum_sha256": "57d7548204ea1fd0b699f4cca0181e85a556bff89d5a35e52073d6dd44010b99",
"format": 1
},
{
@@ -298,14 +305,14 @@
"name": "docs/docsite/rst/guide_ownca.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2da13087991e7e9c56edbc1f55a974953d40c85516135a02ec39df147d82ab4b",
+ "chksum_sha256": "ae96f9410adaeaf32b5121d4d7eb3f2a93beff46980ddf9412d1e130ce655f24",
"format": 1
},
{
"name": "docs/docsite/rst/guide_selfsigned.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ba38bd4f0c1e7e96d051be283484f97b5a317f437720f178c13990798ce5510a",
+ "chksum_sha256": "17f1e754f67c08a3c2f873905d3678328bdb9763128ef0f80c63f58f5b3c151e",
"format": 1
},
{
@@ -375,7 +382,7 @@
"name": "plugins/action/openssl_privatekey_pipe.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b5fa69f89faba559bb4530aa3b4ae1e0ac8faa7b0cf242a3b155ca8fce52aeff",
+ "chksum_sha256": "be0b2baa47125aaa82d45481f659956cdc7ab556b2d28c59bfbad0088b7928f2",
"format": 1
},
{
@@ -389,7 +396,7 @@
"name": "plugins/doc_fragments/acme.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "db00eecb26e0877afdaa69303adeee2f8b36ba7566c5729e0bee15458c100d55",
+ "chksum_sha256": "72d44b4b7dc88ed9cedd76eec52a796b60da62283a14e68ad41e6adce69665f4",
"format": 1
},
{
@@ -410,35 +417,35 @@
"name": "plugins/doc_fragments/module_certificate.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8dfa16820dd58a10c3480ff33bb2a80d59d49d7ff69e8bb87f0d489690a5bb05",
+ "chksum_sha256": "01ec54e9528e80cd51a70ee9070a79b71f5dbb0b7cac3ce1dc7dc3d7bc538e9f",
"format": 1
},
{
"name": "plugins/doc_fragments/module_csr.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "088ff6848934ec374afd0947e41e1ba180f1e22c306736550f8abb7348337b19",
+ "chksum_sha256": "ec6b6f13f943d007c7280eae9552e30ffa657e8410d142564e6353160748098b",
"format": 1
},
{
"name": "plugins/doc_fragments/module_privatekey.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0228ad1f1652630271882932537c14c833eca5303f77cfd31024e6026f92b6c0",
+ "chksum_sha256": "f40cdec3ba65257ac99bb9ef2b885101b58d1b234076781c640e8e8cc37eee32",
"format": 1
},
{
"name": "plugins/doc_fragments/module_privatekey_convert.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "29872291df81d1b07f8bd474255cec6af84069dd9ba958205630e9b5e0ee6d71",
+ "chksum_sha256": "61d860313987e850926b343e41c645650365cb6f45b8e03f223ed73185f383bf",
"format": 1
},
{
"name": "plugins/doc_fragments/name_encoding.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "51f5cfce1cce8d055ae05979965dcfa4384056ad01862a1d3a24b71c0841e90b",
+ "chksum_sha256": "2528f3c5d69406f80d1bfa54b57f0ba73ab1d510c5c59cbf86c294f660e84717",
"format": 1
},
{
@@ -449,24 +456,38 @@
"format": 1
},
{
+ "name": "plugins/filter/gpg_fingerprint.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "dadd6641ad736f0f39f045047b7c5dc0b295d65c19a4c0c6516a34865bb472b6",
+ "format": 1
+ },
+ {
"name": "plugins/filter/openssl_csr_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1dd1bf8947cf3de522d52922c863814d88f4f4ffd16e63ad498bc188047180ea",
+ "chksum_sha256": "1390798cb555af429e300d9c43226924fdbcf38ae79af125dc2fa10915c32c47",
"format": 1
},
{
"name": "plugins/filter/openssl_privatekey_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9b3b7098951f0349af2c48c1ab4dd3169949110dce189fa9a12397a66fcca914",
+ "chksum_sha256": "7c9a8599a44073ddebd701b737b68b708a86d7012c5a5f7e9cb00a3ee5239048",
"format": 1
},
{
"name": "plugins/filter/openssl_publickey_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0e5a2bf5b101d83b5e6cce4b945c9cb3aec35a0a0869770de8c329a29575d733",
+ "chksum_sha256": "7d2dc1b5fc9b21394a71364f6edd8c16766dd7af12ff01443e7d802e3944dab1",
+ "format": 1
+ },
+ {
+ "name": "plugins/filter/parse_serial.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "558fd33dcdc4c140e6bc780e70c3b7ce0306d08bede307603fa29d45a32a9e05",
"format": 1
},
{
@@ -477,17 +498,38 @@
"format": 1
},
{
+ "name": "plugins/filter/to_serial.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "451c87115f86b6f66d0fb323f2e4c93635cca0945a7b83203d380b3651b26329",
+ "format": 1
+ },
+ {
"name": "plugins/filter/x509_certificate_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "61cd93f0f99d5f9d8e777ceab8388ef9b5de24cdd3e30bd19b9774ce8ab7ce34",
+ "chksum_sha256": "64b2090e57e13fc194ecb34d2e5a0341c6ffe5842bbfc74c2368a7a93474f0fa",
"format": 1
},
{
"name": "plugins/filter/x509_crl_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "22d3c47a885a4d56993ed29f5b8df9fd861c61290a9b888d807c4f4bbeec4a40",
+ "chksum_sha256": "8a50ae2f326becba634a55a7686bc802d4010a2d280004428e391d6c441ac25e",
+ "format": 1
+ },
+ {
+ "name": "plugins/lookup",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "plugins/lookup/gpg_fingerprint.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "a915770a06a1bd426fdb7fc56bab37ef00e52ee49b7d2035f56c1bdad8ffc62b",
"format": 1
},
{
@@ -508,21 +550,21 @@
"name": "plugins/module_utils/acme/account.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d4b0ab4bb75e8d8b36f1dbe67b3c8a19fb40741fe332d11ccef3ae0d321390fd",
+ "chksum_sha256": "a3a9c254face6672fe022c168a2124f5916f515b7ddd0fb9e0e352f5c65b662f",
"format": 1
},
{
"name": "plugins/module_utils/acme/acme.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "06671258b9f97cc7666e6598baf77d30bfc84fcc911594debae90d9322a1ef94",
+ "chksum_sha256": "5d7f05fdab25dcbef2a8ce8d1edcd4c27fcc53c13c735a5c74e46aabc0098724",
"format": 1
},
{
"name": "plugins/module_utils/acme/backend_cryptography.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "efd7551ac178d54d692a0028da9e1bf7075834f13c42230ff12b1253239c5590",
+ "chksum_sha256": "4b8f578400e6bd0762ba44c0784c6a8e4fc442e436243836ace40317eb936b61",
"format": 1
},
{
@@ -557,7 +599,7 @@
"name": "plugins/module_utils/acme/errors.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "21be07a9794843ca25183a8827414b50f9775f7808eeff24bb5b35686f12f180",
+ "chksum_sha256": "76c3a7b79d02728401d3bebb790511669c32b04778144054f77809b676d2be05",
"format": 1
},
{
@@ -676,14 +718,14 @@
"name": "plugins/module_utils/crypto/module_backends/privatekey_convert.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5f4d6daeed1159cbd3d3b6f3d51094b3b559cf22726364bcb392627bb90f7e1f",
+ "chksum_sha256": "90d164b2b338e8e15533df91394b5c8b9a425ee8d13812dbf5050e7d9b2d0388",
"format": 1
},
{
"name": "plugins/module_utils/crypto/module_backends/privatekey_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7bc30ee7a4aa3bc0a8b52f38b4167382adeacba91c0bb68448cf7428f05d5225",
+ "chksum_sha256": "3816e0d0f43e91fd18962abd629ff1b95082c3c199fd8663d8f36ebe7fe0fd79",
"format": 1
},
{
@@ -739,14 +781,14 @@
"name": "plugins/module_utils/crypto/cryptography_support.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "677a5f62a270179a8adab19ba2c91b894c47d90aba0a93312a13713e9f82fe1c",
+ "chksum_sha256": "429ae5d529c41a60c0cf15e55b745cbd9adfd569ea315adf693527ba72499451",
"format": 1
},
{
"name": "plugins/module_utils/crypto/math.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6d885ed9fd96054252e527d806846b42ebbb81fa0dbbd024eced265f02e5adb6",
+ "chksum_sha256": "d91f76043cd78a1c9dec5d22a7775be984e5796efb78b30792042ac5a4ebbee8",
"format": 1
},
{
@@ -760,7 +802,7 @@
"name": "plugins/module_utils/crypto/pem.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9ea343de8d832afccb480a30b64514d152cbf0c5bd435bc2b56ac88e8f35a2b1",
+ "chksum_sha256": "9045d933bdb216615500049e5773323f005b2355868f2628c9775cf88e524ae3",
"format": 1
},
{
@@ -785,6 +827,20 @@
"format": 1
},
{
+ "name": "plugins/module_utils/gnupg",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "plugins/module_utils/gnupg/cli.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed11290b1bb4013983273e189683847b8234de34d55d36644bb039b15c560c55",
+ "format": 1
+ },
+ {
"name": "plugins/module_utils/openssh",
"ftype": "dir",
"chksum_type": null,
@@ -802,14 +858,14 @@
"name": "plugins/module_utils/openssh/backends/common.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ae444b21b047d77b8638a42041b70d6053b9950161d0fca7eceacff4e16e8130",
+ "chksum_sha256": "c93ed32364751dcc8b383361d524beb8197e07ed0dc821fdce0b3a1aab6acbcc",
"format": 1
},
{
"name": "plugins/module_utils/openssh/backends/keypair_backend.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bf2830ac27e85ee6b0955a9361aa4f344576a809ef6a36f90b6a30f5736a5c8c",
+ "chksum_sha256": "b96ee10604b5e6e74e532fd726b346181f4de5d71c188ea8d3c22edf2bfef325",
"format": 1
},
{
@@ -848,6 +904,13 @@
"format": 1
},
{
+ "name": "plugins/module_utils/serial.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "13a8207fcd2fbaa971097fee4ee999e461038980b70e5eebe63292a8d8991207",
+ "format": 1
+ },
+ {
"name": "plugins/module_utils/version.py",
"ftype": "file",
"chksum_type": "sha256",
@@ -865,224 +928,224 @@
"name": "plugins/modules/acme_account.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2be0d33350136b19a27ddfef23035739747b1427d55cdc6f11c3e94ba49b9535",
+ "chksum_sha256": "a9c3a88169fd7a7a8bfeedad92cace558ad6ec9aed11c641bd1f84a2382c9013",
"format": 1
},
{
"name": "plugins/modules/acme_account_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "246523550f4005e2c89a5fcc192afa2b2531f9cf028ab9ac82733c66dc47bbe0",
+ "chksum_sha256": "7c83dcc40c140a22ec7131f77524aef58b07556c9268f2625741fc6a2c338b6c",
"format": 1
},
{
"name": "plugins/modules/acme_certificate.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b306d1dd602e77d49134a731ba03d0b1ec298255e3937cdbf53c86e4e94c7d3d",
+ "chksum_sha256": "c3f29dfd43f862717692b9ea8a48a186f3bf48f73cbe400ded858aa1286662ac",
"format": 1
},
{
"name": "plugins/modules/acme_certificate_revoke.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4d18dcaa1b2841a58f4a1e8495394d07deb29f2343695382d81fd406af9748b5",
+ "chksum_sha256": "04f1b9f3dba82c5351a0ae1eae0c8360a6af3aad6e8df118d320271e3efb04c9",
"format": 1
},
{
"name": "plugins/modules/acme_challenge_cert_helper.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0526e703b1544c6c9aa1bd8a5b35b7e5476134abc64ffa74635ef6b865abf303",
+ "chksum_sha256": "073bd164227b3dfd709e76288c1d3185474556274257e793e77f7acbd2220904",
"format": 1
},
{
"name": "plugins/modules/acme_inspect.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "46a7b696d23763c8d5337a2c2278453bf32685281c682fbeef6fb5fa38779e90",
+ "chksum_sha256": "490494d06240823440e81a5539c91c52f7359fade12e9e19aa28f8dfc5f725da",
"format": 1
},
{
"name": "plugins/modules/certificate_complete_chain.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c15e21508e5c6bc6bd8e9c8849a80e202cfb82efc8ff32216ccbebc68ec327f3",
+ "chksum_sha256": "73b64150590db8f6495379498d4c6d147e2eacc5aa1172d39da85fdb7613d5db",
"format": 1
},
{
"name": "plugins/modules/crypto_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "733397087187d0f1247e076092f3b049501bf9c57a1d0a3381ab19911d93d3a2",
+ "chksum_sha256": "e16e926d1750537f848d54a23c6077e30c44feecff3f161d27030a369913f8ea",
"format": 1
},
{
"name": "plugins/modules/ecs_certificate.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "691ac56b47be423a44b0443f85024294aeb2ebe9bf5001539429560005efea50",
+ "chksum_sha256": "0a5264350a46f4a5e7bf97a2b4bdf4d35391c4032dc8e3011ea6cdfe1a17e292",
"format": 1
},
{
"name": "plugins/modules/ecs_domain.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "296ec6b955ab523fe48f4a48501344b1eb3dd7446321fa12b28d08001cbf4956",
+ "chksum_sha256": "45e9967c4d6da0c575b1e289633d9855a6177eadc63e9b8b4f713290a2b8e878",
"format": 1
},
{
"name": "plugins/modules/get_certificate.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "07a3bbe0329e3f5ac80fda788852813d3c384c98b47cbb85ef93cec27564dbe0",
+ "chksum_sha256": "316e351393face995abc0334f38736f3eb27bd73a9faece5206c061f37122ab0",
"format": 1
},
{
"name": "plugins/modules/luks_device.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "040c47f4ca02ecbb06e165ca193ee7193ea9d3f406f23b64112bd50d5abe3905",
+ "chksum_sha256": "356c668dcafd8704e0acd6b4eb6049f33b934a68f55cb0142786aa3c7b16f943",
"format": 1
},
{
"name": "plugins/modules/openssh_cert.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ebe08a5b115f9ce7a935d9858977174d959875ec6cc3a01ca35d5689ae7f9c46",
+ "chksum_sha256": "8cc8472b4ecb8b0fb8b12cf015f4819f9e8a10f15d00f67339bb47d12536e86e",
"format": 1
},
{
"name": "plugins/modules/openssh_keypair.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0ff1f3cadd6721dfbd049f2e4ba82fba39cefcd647f9cec7d14919562dcb6485",
+ "chksum_sha256": "d5d4992f1485579e57aa3ba1e3c4b9b60f74a34e7567194e42c0f44a1a2358a8",
"format": 1
},
{
"name": "plugins/modules/openssl_csr.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0f9602fb35216d8cbd881f6f8081cf8a865bf1bdeec0c88099f950cbba332314",
+ "chksum_sha256": "769c7559b22ac9f87bc03f5e97b533fb49714c61108210c0e4622c04f41a78d4",
"format": 1
},
{
"name": "plugins/modules/openssl_csr_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ab9a98810711a5d775bd97ef3afd943820fa8ca0c09c2fd8e4c9d9686891122d",
+ "chksum_sha256": "00fcbfab3aaf46bf792c6c32cfb038b1eddd3801315caeafbd68c75b6d7bc669",
"format": 1
},
{
"name": "plugins/modules/openssl_csr_pipe.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ed304374255a30099db7d7920027ba5fb3ac47fb2358ec0ec729fc7ed36d7638",
+ "chksum_sha256": "721b285be1050f3e192a3c420f5b6967aeb4b1378e05b1f3fa9e9cdc859f37f1",
"format": 1
},
{
"name": "plugins/modules/openssl_dhparam.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2c9a0b0dbce23f05873ecb65e82d57208fe91480200ba19cdfc4ad67344df15b",
+ "chksum_sha256": "453b0f7127d1150a7c71a2e90a1591b72b23745b3ef444b3637f624e203e2b3b",
"format": 1
},
{
"name": "plugins/modules/openssl_pkcs12.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fa4234411070092e3d6244edceb1406d8877a138c4e7e1480541625f107b9123",
+ "chksum_sha256": "47c238db11cc03870bffb1228d077cb7d20a3e6a0924fe03d0bc85ae2216df38",
"format": 1
},
{
"name": "plugins/modules/openssl_privatekey.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a3e09f1db6db28aefd0dbf436af986adb3c2c7eb71157ed9012b06fcda659e2e",
+ "chksum_sha256": "c2e9a6df5a0507033082222b78974fbcf236eae6a0d5273c0a2206b9fff11966",
"format": 1
},
{
"name": "plugins/modules/openssl_privatekey_convert.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c772ee82bbce0a2c4dfc0dfa4ed72ff99763da84ed6391f5ce2abe6a3af63565",
+ "chksum_sha256": "53037b0e67d81bca25685497ad8db0232d3ab862348a5b48202d7636fa0e346c",
"format": 1
},
{
"name": "plugins/modules/openssl_privatekey_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0fe21ba6d3e5966bc4335058549bb67632222c9989b1355808404b38e27bc8e4",
+ "chksum_sha256": "4ae078612cf041b77ca1b0dc485bf5a27ff8971ed621bbba5bfec0fb0bb8b199",
"format": 1
},
{
"name": "plugins/modules/openssl_privatekey_pipe.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "dd514e1366f8cf11702a1124c683575c43a54626542069a8a23e8d004da763b4",
+ "chksum_sha256": "ccdb7c9a06d31dacb643d0adc8fc056294e0d16399dcc20902abf4b90128f9ed",
"format": 1
},
{
"name": "plugins/modules/openssl_publickey.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d656ff71493152010c203a46b0f36c6fca9312e2c3b412ea3b9ec39d4fb95a90",
+ "chksum_sha256": "42d317be6985e6ccc85e240a08b5361aa04b3f281891742e1bc1b6bb76fa142b",
"format": 1
},
{
"name": "plugins/modules/openssl_publickey_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e999f1e2cbb54f099c6733d66f74bbc405731b5bc6dd311be13a53c3cc7f3aeb",
+ "chksum_sha256": "3b4dc7c1afb0e78901127a1153b54c1a51b4e0268b4564d40cb91a8015fabff3",
"format": 1
},
{
"name": "plugins/modules/openssl_signature.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "30f457dcd3be6efbf405d842f244d0627397f71001106b48812d4c6bf0b75d7a",
+ "chksum_sha256": "cd4e3f1ba8f7b9bd94545cba395fe1aac3ac734d158c1065d04aa16cf64766b3",
"format": 1
},
{
"name": "plugins/modules/openssl_signature_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bd092d8e5bebe70c888eee8091ed83d2821debffcf69452d20d4c37d261f3742",
+ "chksum_sha256": "5ab6f1b3a1ab362eb47cd4ef526f23ecf1299d670edc7dd27eb087cacd58c4b4",
"format": 1
},
{
"name": "plugins/modules/x509_certificate.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9201740cdaa97912c7a488b93a8bf25b65a355c0275b0d41a55e99e6208b15b4",
+ "chksum_sha256": "66bb9cda2e07f4bd196b0f309a8ed705668e627ea0d3f9137cf29be408ad73b3",
"format": 1
},
{
"name": "plugins/modules/x509_certificate_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "32efd98d7efbac173a75af7f8bf2b3cf0ab65db22dc1f409e29d969e20429174",
+ "chksum_sha256": "9cdcd6e9d4d11182ff9bf203c1432b0d96d74f31548f8eb34ae5b7beb48d57fc",
"format": 1
},
{
"name": "plugins/modules/x509_certificate_pipe.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c022742c244d4cf25451b6021ae656ed76300d815a160d3148bf644f7c8a7e03",
+ "chksum_sha256": "224f31e4b5fb1596015793c79a5897fceb8788c64875f9f876bb17b2436e52d9",
"format": 1
},
{
"name": "plugins/modules/x509_crl.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0818a26da959f7d29da9334e7d0a413b5c10a26f5468889e7c28b85dabe11847",
+ "chksum_sha256": "bc95c541cd09e5d61f437b7c701e3c3370821618a271f98d4746de8480e9084f",
"format": 1
},
{
"name": "plugins/modules/x509_crl_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "35b6cf60c8e00ab3e5fc8e49f9c060729d340664610237c0d1ede057a7adf722",
+ "chksum_sha256": "137f76b43493e79acf2635de56b2a651ad7c2e96bcd363224f4303ae15db86bd",
"format": 1
},
{
@@ -1107,6 +1170,13 @@
"format": 1
},
{
+ "name": "plugins/plugin_utils/gnupg.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c60a75840c1903795bba88c0864902dde73d300c1640cfc8fb02f44b2ba75612",
+ "format": 1
+ },
+ {
"name": "tests",
"ftype": "dir",
"chksum_type": null,
@@ -1621,7 +1691,7 @@
"name": "tests/integration/targets/acme_challenge_cert_helper/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "544305bba02e4b01eb3952a852af5b775e733ab585b299f0dcf942d5bb9d8891",
+ "chksum_sha256": "6387c7e55c9bc0981a68bcd19c53ecca7aead9b291bafa97e17096932d379253",
"format": 1
},
{
@@ -2073,6 +2143,48 @@
"format": 1
},
{
+ "name": "tests/integration/targets/filter_gpg_fingerprint",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/filter_gpg_fingerprint/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/filter_gpg_fingerprint/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e338f97b9e492736b5369c3462dce7c2242ad0e93d07898ee9e827828797dd54",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/filter_gpg_fingerprint/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/filter_gpg_fingerprint/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "5d7829d7a4f2ec7d073111605075dd2d737b669be5f2f736a4929b5879cb39c1",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/filter_gpg_fingerprint/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e28d467b791779a59439ace7e1092ec06529f0795d4a1b73da989f1687104b21",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/filter_openssl_csr_info",
"ftype": "dir",
"chksum_type": null,
@@ -2220,6 +2332,34 @@
"format": 1
},
{
+ "name": "tests/integration/targets/filter_parse_serial",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/filter_parse_serial/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/filter_parse_serial/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "585cf43b15121d3b3d9f7d189e80addc04fe112548f0e2d9d079a5959de9d0a0",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/filter_parse_serial/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "96646c5ab7118c53b8b722f6abe91a7ed4d3eed9be401faefb399d6a8f427c2e",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/filter_split_pem",
"ftype": "dir",
"chksum_type": null,
@@ -2248,6 +2388,34 @@
"format": 1
},
{
+ "name": "tests/integration/targets/filter_to_serial",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/filter_to_serial/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/filter_to_serial/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "27f3a4af4e8233491f1a0927dd5919390789a4aadfffad46f1b71fea74bda6dd",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/filter_to_serial/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "96646c5ab7118c53b8b722f6abe91a7ed4d3eed9be401faefb399d6a8f427c2e",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/filter_x509_certificate_info",
"ftype": "dir",
"chksum_type": null,
@@ -2405,7 +2573,7 @@
"name": "tests/integration/targets/get_certificate/tests/validate.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "87594c273be2a7444848e55d5f08e149c8d2bc4792c7a66cc0cfdc3ffa064e16",
+ "chksum_sha256": "7065d5cda19e9ad371c572e42b22a0d70582639cad716654bf29e4661f232bdb",
"format": 1
},
{
@@ -2416,6 +2584,48 @@
"format": 1
},
{
+ "name": "tests/integration/targets/lookup_gpg_fingerprint",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/lookup_gpg_fingerprint/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/lookup_gpg_fingerprint/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e338f97b9e492736b5369c3462dce7c2242ad0e93d07898ee9e827828797dd54",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/lookup_gpg_fingerprint/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/lookup_gpg_fingerprint/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "483add1f93729e1e6dbeb7f015ed2c9ce5e186813d9b4686acc84a98b1c32eb8",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/lookup_gpg_fingerprint/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e28d467b791779a59439ace7e1092ec06529f0795d4a1b73da989f1687104b21",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/luks_device",
"ftype": "dir",
"chksum_type": null,
@@ -2507,6 +2717,27 @@
"format": 1
},
{
+ "name": "tests/integration/targets/luks_device/tasks/tests/keyslot-create-destroy.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "59ef20cc568328ed71a73daf8b38c59c9d37f233850674819d7fd0657962824f",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/luks_device/tasks/tests/keyslot-duplicate.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "3435782c79d1ab4b5002ffc5f846abbd6e6a628cff8d9ebd79dedd53321c23c4",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/luks_device/tasks/tests/keyslot-options.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6c4d2d0b33210d75a355492517f3d6f4a9501f1337d8b56143021c73cafc979f",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/luks_device/tasks/tests/options.yml",
"ftype": "file",
"chksum_type": "sha256",
@@ -2524,7 +2755,7 @@
"name": "tests/integration/targets/luks_device/tasks/tests/performance.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b007aca0d0d7846e2f78881837c321820bc8d097da767eb23a49cea4e0d86f4f",
+ "chksum_sha256": "d7ecb974bf2dcaa4516fd6069fdbbd30f00f46e167c8286bbfaf0d8d068efe6e",
"format": 1
},
{
@@ -2552,7 +2783,7 @@
"name": "tests/integration/targets/luks_device/vars/Alpine.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ce279a0328bf225612cf60d52eb0dc0b6efa92cf3e2bd63b0cb528729ad4f997",
+ "chksum_sha256": "aa7f5162096c065c2e05fb0d93f72e04c3dbdc1502b321eae3cc6b3529bb5fbe",
"format": 1
},
{
@@ -2615,7 +2846,7 @@
"name": "tests/integration/targets/openssh_cert/tests/idempotency.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "91b187a19efb2b8b947b5952ae19c0ffc3a1aa92f9e46e5fa89bd01ec457fd76",
+ "chksum_sha256": "83f71ae5911064351ed1f97ed7b715f6717401545ca7ec387f7ed83b8e37617f",
"format": 1
},
{
@@ -2713,7 +2944,7 @@
"name": "tests/integration/targets/openssh_keypair/tests/cryptography_backend.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3a394c9e1e941a9618efdbe5059f2b7899192c1099e8654873f41c3912b063c1",
+ "chksum_sha256": "9bd01b5a28bbeff9fb6badf9006c3e18515d44a9e248a8cc1747377939dd3dbb",
"format": 1
},
{
@@ -2727,14 +2958,14 @@
"name": "tests/integration/targets/openssh_keypair/tests/options.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "032dff93f47779f1c50c7b0570cb7b900eacf9f9b26197fd71c248b7ff8cf769",
+ "chksum_sha256": "d9c5bd87af8a49eae1dde8e5b8370bd47ecce72aecaecdda5c4d664dbe620855",
"format": 1
},
{
"name": "tests/integration/targets/openssh_keypair/tests/regenerate.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6d8981862fb6b79ac8d4001629a59e4e10098b6b8478d4368d1c2cf167eb2d86",
+ "chksum_sha256": "55471f24cda0074ddccaaf1f9db8fe5eacbbd66b5e5887cbb35c2950b4952127",
"format": 1
},
{
@@ -3028,7 +3259,7 @@
"name": "tests/integration/targets/openssl_pkcs12/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6fec81beb0862bed86a0eaabf9438438f201f0049c93b3a216dae9a359aef073",
+ "chksum_sha256": "7ac93b621d179ab77bf68b989018e07729545515e8febbac49d653d400be8b87",
"format": 1
},
{
@@ -3105,7 +3336,7 @@
"name": "tests/integration/targets/openssl_privatekey/tests/validate.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5a7c406b6e524b94b182bd5954cd1b5c259a92491beb740216de7db34d955614",
+ "chksum_sha256": "b315a5e9496428293ed207368010f3fc25be01fa50442401cf85ea029772589d",
"format": 1
},
{
@@ -3329,7 +3560,7 @@
"name": "tests/integration/targets/openssl_publickey/tests/validate.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e0ed98881fe8a218db8e9f24f3c0b32ac85b59a1cff84212a18d96cf8e499c75",
+ "chksum_sha256": "ef4df69c9e95f323b8dbf209e61e968237b75dd1d2934ef14b1a502143ab512a",
"format": 1
},
{
@@ -3522,10 +3753,17 @@
"format": 1
},
{
+ "name": "tests/integration/targets/prepare_jinja2_compat/filter_plugins/ansible_compatibility.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "86994c6072fb9111abea280a48690aba324d60ab2640676f83b1f0c8148076b0",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/prepare_jinja2_compat/filter_plugins/jinja_compatibility.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "30fcb05d83e11b370c30e2e84d8fd9f3661369200ade7dd02df9c002a2309a23",
+ "chksum_sha256": "48994f065f9887094a301feff969996dabf7769d05404d79591a4f18d7394295",
"format": 1
},
{
@@ -3655,6 +3893,83 @@
"format": 1
},
{
+ "name": "tests/integration/targets/setup_gnupg",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_gnupg/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_gnupg/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e11ca6edae518cc531ab425daa9eb93f78f89b9ddd515deabd239e8c7925323d",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_gnupg/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_gnupg/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "daa9649eed21befb6174ab36e613568cc2641d7c48520093263f99ba11002a30",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_gnupg/vars",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_gnupg/vars/Alpine.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "89420396444257a72a6dd183efce163ed601703b327287dbd2208e1140a38d5f",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_gnupg/vars/CentOS-6.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "17c1b35607bab5e2c9bc4a95c9712148b9773e0f9428c65f5faa7e59182d97df",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_gnupg/vars/Darwin.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "503c6a541bd64e1996b427d9344653a611d1c789d7dac063523d6b8bacf77e87",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_gnupg/vars/RedHat.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9cc668ae5828d118b63873ea4dd42f0053006cd31e6e4ef495c55f35fcaa066d",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_gnupg/vars/default.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "bc3f1d38f5f88d2cf8f06e67383e4f884dcedfd2ff2d7265b7ec420e58aa949b",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/setup_openssl",
"ftype": "dir",
"chksum_type": null,
@@ -3917,7 +4232,7 @@
"name": "tests/integration/targets/setup_python_info/vars/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a2ac53510da02da97af29c837c144f05d9a6f3b5863156917fc704d9f6d3434a",
+ "chksum_sha256": "00299748a38e036412bdf638f2d8093cc2c555fb50fffd8ed119dee7cee52397",
"format": 1
},
{
@@ -4246,14 +4561,14 @@
"name": "tests/integration/targets/x509_certificate/tests/validate_ownca.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9c45d8284903fb862aa9cbb242bdddb6173cc4ed7b03ca55e0241793dfd63b54",
+ "chksum_sha256": "af825159e41199c2d1f1db026d1440dd6b84b14e6b684de12b76971812d10ec5",
"format": 1
},
{
"name": "tests/integration/targets/x509_certificate/tests/validate_selfsigned.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "749ff8a1ce325c0c9b406ec5cc58b21e4c1e66cb1d26c950a88b90140aa11c47",
+ "chksum_sha256": "fea7c0daa838f7449053a70b563857991d919c281980ca1d4323123b4ae39862",
"format": 1
},
{
@@ -4407,7 +4722,7 @@
"name": "tests/integration/targets/x509_crl/tasks/impl.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3a4100f786b8a06953a0fc3c8d7344670a9da7ba7aaeda0e7d65903966f2697c",
+ "chksum_sha256": "45382b300e70987a5dab1cd4fe3a9339d86655cb2c8e74b3c5a6623692ecdfab",
"format": 1
},
{
@@ -4477,7 +4792,7 @@
"name": "tests/sanity/extra/extra-docs.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0fbd87476e9c35e4c5feb31be4aa1e8fc6aebf0de13058e5a267879f741ec0bf",
+ "chksum_sha256": "c52e316daf1292bbb063be19429fd1f06e02bce3c9d4622a8dfc61fa3af06688",
"format": 1
},
{
@@ -4533,7 +4848,7 @@
"name": "tests/sanity/ignore-2.10.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e90b8ed0470d877e85848af2108f06b47aef9c8a7e25cae6762ccb8a32ae2214",
+ "chksum_sha256": "9c564907d4db67b2eab6b7387740cbf6146bb2f236db4eac52fc320fa2e0eefb",
"format": 1
},
{
@@ -4547,7 +4862,7 @@
"name": "tests/sanity/ignore-2.11.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e90b8ed0470d877e85848af2108f06b47aef9c8a7e25cae6762ccb8a32ae2214",
+ "chksum_sha256": "1b44914e1e87736a09ebfdabf48dae543323720b6864fb9064052e874d96847d",
"format": 1
},
{
@@ -4561,7 +4876,7 @@
"name": "tests/sanity/ignore-2.12.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9bdf1ce59dadc7d5e17b1d3b114fe08cebb91648ce3ec46d5c2b69c4d965ce69",
+ "chksum_sha256": "a4c87a60391639fdf51e7be2088785d7d1950580d27cbc348d45c2bad0887a4a",
"format": 1
},
{
@@ -4575,7 +4890,7 @@
"name": "tests/sanity/ignore-2.13.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7e2345994ac361630efde6d1dcb5657a36a0376d7489731c6fe9d584289402cc",
+ "chksum_sha256": "38df4b447aa4f0fa4b168df195dff78362f955ed3c4117266c320045be6d00a7",
"format": 1
},
{
@@ -4589,7 +4904,7 @@
"name": "tests/sanity/ignore-2.14.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7e2345994ac361630efde6d1dcb5657a36a0376d7489731c6fe9d584289402cc",
+ "chksum_sha256": "38df4b447aa4f0fa4b168df195dff78362f955ed3c4117266c320045be6d00a7",
"format": 1
},
{
@@ -4617,7 +4932,7 @@
"name": "tests/sanity/ignore-2.16.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7e2345994ac361630efde6d1dcb5657a36a0376d7489731c6fe9d584289402cc",
+ "chksum_sha256": "88f167104e425a472b8fd111b8b2e9d7b2e1135ace2d5130cef81ca38aeba161",
"format": 1
},
{
@@ -4628,10 +4943,24 @@
"format": 1
},
{
+ "name": "tests/sanity/ignore-2.17.txt",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "88f167104e425a472b8fd111b8b2e9d7b2e1135ace2d5130cef81ca38aeba161",
+ "format": 1
+ },
+ {
+ "name": "tests/sanity/ignore-2.17.txt.license",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6eb915239f9f35407fa68fdc41ed6522f1fdcce11badbdcd6057548023179ac1",
+ "format": 1
+ },
+ {
"name": "tests/sanity/ignore-2.9.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "79b8db85358ed8f96c4cb0159e502a560e52635341a8cc9ee906d46503f8b37d",
+ "chksum_sha256": "dad1b754c46149195a1a26af8e56bb1aa449d4acec41532bfaf45a8254b11050",
"format": 1
},
{
@@ -4901,6 +5230,13 @@
"format": 1
},
{
+ "name": "tests/unit/plugins/module_utils/crypto/test_pem.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "1f9c39460cfcf7f8c993d2465f4fec1c8690c58413b456aba9d59e91cc043108",
+ "format": 1
+ },
+ {
"name": "tests/unit/plugins/module_utils/openssh",
"ftype": "dir",
"chksum_type": null,
@@ -4939,7 +5275,7 @@
"name": "tests/unit/plugins/modules/test_luks_device.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "359d84e2d64b7c73b30248eded2104aa5121344533354ff453ae506bc4c609ce",
+ "chksum_sha256": "ab827f30acfcd6a3d7a753889fc8a32a4d007359753c0b5549ccb12d515c4dab",
"format": 1
},
{
@@ -5058,7 +5394,7 @@
"name": "tests/utils/shippable/shippable.sh",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "471b1d343b88039ef089ab494312320d6cdd94fb7b2492b5eee340154ab20027",
+ "chksum_sha256": "999e81cec05b7670654928f1b638667dfd2124fcd33ad97b55d7729782803a0b",
"format": 1
},
{
@@ -5090,10 +5426,24 @@
"format": 1
},
{
+ "name": "CHANGELOG.md",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "5430eaa014f0f010ed69848fea7d36d8dbb9fe9a8d7612887dd52c73389dfef1",
+ "format": 1
+ },
+ {
+ "name": "CHANGELOG.md.license",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6eb915239f9f35407fa68fdc41ed6522f1fdcce11badbdcd6057548023179ac1",
+ "format": 1
+ },
+ {
"name": "CHANGELOG.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ab26b4a0179855ed65910b80d42b79ba234d9b44a3a5ad445100fac7c9454dae",
+ "chksum_sha256": "124c1a02abb35f4b3e98c6449bd07d7a606a80e34f297b60be1ed43673955bba",
"format": 1
},
{
@@ -5114,7 +5464,7 @@
"name": "README.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "31f412268cabb2a6b8f80cbce3b2e30acf973905af3c672155a1b4b6cfef1b0e",
+ "chksum_sha256": "dd847490669a8106ad134aa8c1d21e9620891badee9173763ca0643187e7e735",
"format": 1
}
],
diff --git a/ansible_collections/community/crypto/MANIFEST.json b/ansible_collections/community/crypto/MANIFEST.json
index cd7e04ed8..2e16020a1 100644
--- a/ansible_collections/community/crypto/MANIFEST.json
+++ b/ansible_collections/community/crypto/MANIFEST.json
@@ -2,7 +2,7 @@
"collection_info": {
"namespace": "community",
"name": "crypto",
- "version": "2.14.0",
+ "version": "2.18.0",
"authors": [
"Ansible (github.com/ansible)"
],
@@ -41,7 +41,7 @@
"name": "FILES.json",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b1f04aa94c0ac2a75ae7c56654a6e2bfb418a3660a310d3468f119d988ed04f9",
+ "chksum_sha256": "fc4c33abc854162fe45421f98db891d66b0d614f3c5ddfcb8d14f308db7e9df2",
"format": 1
},
"format": 1
diff --git a/ansible_collections/community/crypto/README.md b/ansible_collections/community/crypto/README.md
index d0ae6489f..64ffd4eae 100644
--- a/ansible_collections/community/crypto/README.md
+++ b/ansible_collections/community/crypto/README.md
@@ -18,7 +18,7 @@ Please note that this collection does **not** support Windows targets.
## Tested with Ansible
-Tested with the current Ansible 2.9, ansible-base 2.10, ansible-core 2.11, ansible-core 2.12, ansible-core 2.13, and ansible-core 2.14 releases and the current development version of ansible-core. Ansible versions before 2.9.10 are not supported.
+Tested with the current Ansible 2.9, ansible-base 2.10, ansible-core 2.11, ansible-core 2.12, ansible-core 2.13, ansible-core 2.14, ansible-core 2.15, and ansible-core-2.16 releases and the current development version of ansible-core. Ansible versions before 2.9.10 are not supported.
## External requirements
@@ -38,39 +38,49 @@ If you use the Ansible package and do not update collections independently, use
## Included content
-- OpenSSL / PKI modules:
- - openssl_csr_info
- - openssl_csr
- - openssl_dhparam
- - openssl_pkcs12
- - openssl_privatekey_info
- - openssl_privatekey
- - openssl_publickey
- - openssl_signature_info
- - openssl_signature
- - x509_certificate_info
- - x509_certificate
- - x509_crl_info
- - x509_crl
- - certificate_complete_chain
-- OpenSSH modules:
- - openssh_cert
- - openssh_keypair
-- ACME modules:
- - acme_account_info
- - acme_account
- - acme_certificate
- - acme_certificate_revoke
- - acme_challenge_cert_helper
- - acme_inspect
-- ECS modules:
- - ecs_certificate
- - ecs_domain
-- Miscellaneous modules:
- - get_certificate
- - luks_device
-
-You can also find a list of all modules with documentation on the [Ansible docs site](https://docs.ansible.com/ansible/latest/collections/community/crypto/).
+- OpenSSL / PKI modules and plugins:
+ - certificate_complete_chain module
+ - openssl_csr_info module and filter
+ - openssl_csr_pipe module
+ - openssl_csr module
+ - openssl_dhparam module
+ - openssl_pkcs12 module
+ - openssl_privatekey_convert module
+ - openssl_privatekey_info module and filter
+ - openssl_privatekey_pipe module
+ - openssl_privatekey module
+ - openssl_publickey_info module and filter
+ - openssl_publickey module
+ - openssl_signature_info module
+ - openssl_signature module
+ - split_pem filter
+ - x509_certificate_info module and filter
+ - x509_certificate_pipe module
+ - x509_certificate module
+ - x509_crl_info module and filter
+ - x509_crl module
+- OpenSSH modules and plugins:
+ - openssh_cert module
+ - openssh_keypair module
+- ACME modules and plugins:
+ - acme_account_info module
+ - acme_account module
+ - acme_certificate module
+ - acme_certificate_revoke module
+ - acme_challenge_cert_helper module
+ - acme_inspect module
+- ECS modules and plugins:
+ - ecs_certificate module
+ - ecs_domain module
+- GnuPG modules and plugins:
+ - gpg_fingerprint lookup and filter
+- Miscellaneous modules and plugins:
+ - crypto_info module
+ - get_certificate module
+ - luks_device module
+ - parse_serial and to_serial filters
+
+You can also find a list of all modules and plugins with documentation on the [Ansible docs site](https://docs.ansible.com/ansible/latest/collections/community/crypto/), or the [latest commit collection documentation](https://ansible-collections.github.io/community.crypto/branch/main/).
## Using this collection
@@ -102,7 +112,7 @@ See [Ansible's dev guide](https://docs.ansible.com/ansible/devel/dev_guide/devel
## Release notes
-See the [changelog](https://github.com/ansible-collections/community.crypto/blob/main/CHANGELOG.rst).
+See the [changelog](https://github.com/ansible-collections/community.crypto/blob/main/CHANGELOG.md).
## Roadmap
@@ -129,6 +139,6 @@ This collection is primarily licensed and distributed as a whole under the GNU G
See [LICENSES/GPL-3.0-or-later.txt](https://github.com/ansible-collections/community.crypto/blob/main/COPYING) for the full text.
-Parts of the collection are licensed under the [Apache 2.0 license](https://github.com/ansible-collections/community.crypto/blob/main/LICENSES/Apache-2.0.txt) (`plugins/module_utils/crypto/_obj2txt.py` and `plugins/module_utils/crypto/_objects_data.py`), the [BSD 2-Clause license](https://github.com/ansible-collections/community.crypto/blob/main/LICENSES/BSD-2-Clause.txt) (`plugins/module_utils/ecs/api.py`), the [BSD 3-Clause license](https://github.com/ansible-collections/community.crypto/blob/main/LICENSES/BSD-3-Clause.txt) (`plugins/module_utils/crypto/_obj2txt.py`), and the [PSF 2.0 license](https://github.com/ansible-collections/community.crypto/blob/main/LICENSES/PSF-2.0.txt) (`plugins/module_utils/_version.py`). This only applies to vendored files in ``plugins/module_utils/`` and to the ECS module utils.
+Parts of the collection are licensed under the [Apache 2.0 license](https://github.com/ansible-collections/community.crypto/blob/main/LICENSES/Apache-2.0.txt) (`plugins/module_utils/crypto/_obj2txt.py` and `plugins/module_utils/crypto/_objects_data.py`), the [BSD 2-Clause license](https://github.com/ansible-collections/community.crypto/blob/main/LICENSES/BSD-2-Clause.txt) (`plugins/module_utils/ecs/api.py`), the [BSD 3-Clause license](https://github.com/ansible-collections/community.crypto/blob/main/LICENSES/BSD-3-Clause.txt) (`plugins/module_utils/crypto/_obj2txt.py`, `tests/integration/targets/prepare_jinja2_compat/filter_plugins/jinja_compatibility.py`), and the [PSF 2.0 license](https://github.com/ansible-collections/community.crypto/blob/main/LICENSES/PSF-2.0.txt) (`plugins/module_utils/_version.py`). This only applies to vendored files in ``plugins/module_utils/`` and to the ECS module utils.
Almost all files have a machine readable `SDPX-License-Identifier:` comment denoting its respective license(s) or an equivalent entry in an accompanying `.license` file. Only changelog fragments (which will not be part of a release) are covered by a blanket statement in `.reuse/dep5`. Right now a few vendored PEM files do not have licensing information as well. This conforms to the [REUSE specification](https://reuse.software/spec/) up to the aforementioned PEM files.
diff --git a/ansible_collections/community/crypto/changelogs/changelog.yaml b/ansible_collections/community/crypto/changelogs/changelog.yaml
index ca735b395..044bd81a8 100644
--- a/ansible_collections/community/crypto/changelogs/changelog.yaml
+++ b/ansible_collections/community/crypto/changelogs/changelog.yaml
@@ -56,7 +56,7 @@ releases:
- openssl_certificate - Add option for changing which ACME directory to use
with acme-tiny. Set the default ACME directory to Let's Encrypt instead of
using acme-tiny's default. (acme-tiny also uses Let's Encrypt at the time
- being, so no action should be neccessary.)
+ being, so no action should be necessary.)
- openssl_certificate - Change the required version of acme-tiny to >= 4.0.0
- openssl_certificate - allow to provide content of some input files via the
``csr_content``, ``privatekey_content``, ``ownca_privatekey_content`` and
@@ -247,8 +247,8 @@ releases:
minor_changes:
- openssh_cert - add module parameter ``use_agent`` to enable using signing
keys stored in ssh-agent (https://github.com/ansible-collections/community.crypto/issues/116).
- - openssl_csr - refactor module to allow code re-use by openssl_csr_pipe (https://github.com/ansible-collections/community.crypto/pull/123).
- - openssl_privatekey - refactor module to allow code re-use by openssl_privatekey_pipe
+ - openssl_csr - refactor module to allow code reuse by openssl_csr_pipe (https://github.com/ansible-collections/community.crypto/pull/123).
+ - openssl_privatekey - refactor module to allow code reuse by openssl_privatekey_pipe
(https://github.com/ansible-collections/community.crypto/pull/119).
- openssl_privatekey - the elliptic curve ``secp192r1`` now triggers a security
warning. Elliptic curves of at least 224 bits should be used for new keys;
@@ -258,7 +258,7 @@ releases:
anymore. If no CSR is provided, the module behaves as if a minimal CSR which
only contains the public key has been provided (https://github.com/ansible-collections/community.crypto/issues/32,
https://github.com/ansible-collections/community.crypto/pull/129).
- - x509_certificate - refactor module to allow code re-use by x509_certificate_pipe
+ - x509_certificate - refactor module to allow code reuse by x509_certificate_pipe
(https://github.com/ansible-collections/community.crypto/pull/135).
release_summary: 'Contains new modules ``openssl_privatekey_pipe``, ``openssl_csr_pipe``
and ``x509_certificate_pipe`` which allow to create or update private keys,
@@ -419,7 +419,7 @@ releases:
https://github.com/ansible-collections/community.crypto/pull/150).
- openssl_csr_info - now returns ``public_key_type`` and ``public_key_data``
(https://github.com/ansible-collections/community.crypto/pull/233).
- - openssl_csr_info - refactor module to allow code re-use for diff mode (https://github.com/ansible-collections/community.crypto/pull/204).
+ - openssl_csr_info - refactor module to allow code reuse for diff mode (https://github.com/ansible-collections/community.crypto/pull/204).
- openssl_csr_pipe - add diff mode (https://github.com/ansible-collections/community.crypto/issues/38,
https://github.com/ansible-collections/community.crypto/pull/150).
- openssl_pkcs12 - added option ``select_crypto_backend`` and a ``cryptography``
@@ -427,7 +427,7 @@ releases:
``iter_size`` and ``maciter_size`` options (https://github.com/ansible-collections/community.crypto/pull/234).
- openssl_privatekey - add diff mode (https://github.com/ansible-collections/community.crypto/issues/38,
https://github.com/ansible-collections/community.crypto/pull/150).
- - openssl_privatekey_info - refactor module to allow code re-use for diff mode
+ - openssl_privatekey_info - refactor module to allow code reuse for diff mode
(https://github.com/ansible-collections/community.crypto/pull/205).
- openssl_privatekey_pipe - add diff mode (https://github.com/ansible-collections/community.crypto/issues/38,
https://github.com/ansible-collections/community.crypto/pull/150).
@@ -437,7 +437,7 @@ releases:
https://github.com/ansible-collections/community.crypto/pull/150).
- x509_certificate_info - now returns ``public_key_type`` and ``public_key_data``
(https://github.com/ansible-collections/community.crypto/pull/233).
- - x509_certificate_info - refactor module to allow code re-use for diff mode
+ - x509_certificate_info - refactor module to allow code reuse for diff mode
(https://github.com/ansible-collections/community.crypto/pull/206).
- x509_certificate_pipe - add diff mode (https://github.com/ansible-collections/community.crypto/issues/38,
https://github.com/ansible-collections/community.crypto/pull/150).
@@ -445,7 +445,7 @@ releases:
https://github.com/ansible-collections/community.crypto/pull/150).
- x509_crl_info - add ``list_revoked_certificates`` option to avoid enumerating
all revoked certificates (https://github.com/ansible-collections/community.crypto/pull/232).
- - x509_crl_info - refactor module to allow code re-use for diff mode (https://github.com/ansible-collections/community.crypto/pull/203).
+ - x509_crl_info - refactor module to allow code reuse for diff mode (https://github.com/ansible-collections/community.crypto/pull/203).
release_summary: Regular feature and bugfix release.
fragments:
- 1.7.0.yml
@@ -858,6 +858,200 @@ releases:
- 617-acme_certificate-parallel.yml
- 622-der-format-support.yml
release_date: '2023-06-15'
+ 2.14.1:
+ changes:
+ bugfixes:
+ - Fix PEM detection/identification to also accept random other lines before
+ the line starting with ``-----BEGIN`` (https://github.com/ansible-collections/community.crypto/issues/627,
+ https://github.com/ansible-collections/community.crypto/pull/628).
+ known_issues:
+ - Ansible markup will show up in raw form on ansible-doc text output for ansible-core
+ before 2.15. If you have trouble deciphering the documentation markup, please
+ upgrade to ansible-core 2.15 (or newer), or read the HTML documentation on
+ https://docs.ansible.com/ansible/devel/collections/community/crypto/.
+ release_summary: 'Bugfix and maintenance release with updated documentation.
+
+
+ From this version on, community.crypto is using the new `Ansible semantic
+ markup
+
+ <https://docs.ansible.com/ansible/devel/dev_guide/developing_modules_documenting.html#semantic-markup-within-module-documentation>`__
+
+ in its documentation. If you look at documentation with the ansible-doc CLI
+ tool
+
+ from ansible-core before 2.15, please note that it does not render the markup
+
+ correctly. You should be still able to read it in most cases, but you need
+
+ ansible-core 2.15 or later to see it as it is intended. Alternatively you
+ can
+
+ look at `the devel docsite <https://docs.ansible.com/ansible/devel/collections/community/crypto/>`__
+
+ for the rendered HTML version of the documentation of the latest release.
+
+ '
+ fragments:
+ - 2.14.1.yml
+ - 628-pem-detection.yml
+ - semantic-markup.yml
+ release_date: '2023-06-27'
+ 2.15.0:
+ changes:
+ bugfixes:
+ - openssh_cert, openssh_keypair - the modules ignored return codes of ``ssh``
+ and ``ssh-keygen`` in some cases (https://github.com/ansible-collections/community.crypto/issues/645,
+ https://github.com/ansible-collections/community.crypto/pull/646).
+ - openssh_keypair - fix comment updating for OpenSSH before 6.5 (https://github.com/ansible-collections/community.crypto/pull/646).
+ deprecated_features:
+ - get_certificate - the default ``false`` of the ``asn1_base64`` option is deprecated
+ and will change to ``true`` in community.crypto 3.0.0 (https://github.com/ansible-collections/community.crypto/pull/600).
+ minor_changes:
+ - openssh_keypair - fail when comment cannot be updated (https://github.com/ansible-collections/community.crypto/pull/646).
+ release_summary: Bugfix and feature release.
+ fragments:
+ - 2.15.0.yml
+ - 600-get_certificate-asn1_base64.yml
+ - 646-openssh-rc.yml
+ plugins:
+ filter:
+ - description: Retrieve a GPG fingerprint from a GPG public or private key
+ name: gpg_fingerprint
+ namespace: null
+ lookup:
+ - description: Retrieve a GPG fingerprint from a GPG public or private key file
+ name: gpg_fingerprint
+ namespace: null
+ release_date: '2023-08-12'
+ 2.15.1:
+ changes:
+ bugfixes:
+ - acme_* modules - correctly handle error documents without ``type`` (https://github.com/ansible-collections/community.crypto/issues/651,
+ https://github.com/ansible-collections/community.crypto/pull/652).
+ release_summary: Bugfix release.
+ fragments:
+ - 2.15.1.yml
+ - 652-problem-type.yml
+ release_date: '2023-08-22'
+ 2.16.0:
+ changes:
+ bugfixes:
+ - openssl_pkcs12 - modify autodetect to not detect pyOpenSSL >= 23.3.0, which
+ removed PKCS#12 support (https://github.com/ansible-collections/community.crypto/pull/666).
+ minor_changes:
+ - luks_devices - add new options ``keyslot``, ``new_keyslot``, and ``remove_keyslot``
+ to allow adding/removing keys to/from specific keyslots (https://github.com/ansible-collections/community.crypto/pull/664).
+ release_summary: Bugfix release.
+ fragments:
+ - 2.16.0.yml
+ - 664-luks_device-keyslot.yml
+ - pkcs12.yml
+ release_date: '2023-10-29'
+ 2.16.1:
+ changes:
+ bugfixes:
+ - acme_* modules - also retry requests in case of socket errors, bad status
+ lines, and unknown connection errors; improve error messages in these cases
+ (https://github.com/ansible-collections/community.crypto/issues/680).
+ release_summary: Bugfix release.
+ fragments:
+ - 2.16.1.yml
+ - 680-acme-retry.yml
+ release_date: '2023-12-04'
+ 2.16.2:
+ changes:
+ bugfixes:
+ - acme_* modules - directly react on bad return data for account creation/retrieval/updating
+ requests (https://github.com/ansible-collections/community.crypto/pull/682).
+ - acme_* modules - fix improved error reporting in case of socket errors, bad
+ status lines, and unknown connection errors (https://github.com/ansible-collections/community.crypto/pull/684).
+ - acme_* modules - increase number of retries from 5 to 10 to increase stability
+ with unstable ACME endpoints (https://github.com/ansible-collections/community.crypto/pull/685).
+ - acme_* modules - make account registration handling more flexible to accept
+ 404 instead of 400 send by DigiCert's ACME endpoint when an account does not
+ exist (https://github.com/ansible-collections/community.crypto/pull/681).
+ release_summary: Bugfix release.
+ fragments:
+ - 2.16.2.yml
+ - 681-acme-account.yml
+ - 682-acme-errors.yml
+ - 684-info-code.yml
+ - 685-acme-retry.yml
+ release_date: '2023-12-08'
+ 2.17.0:
+ changes:
+ minor_changes:
+ - luks_device - add allow discards option (https://github.com/ansible-collections/community.crypto/pull/693).
+ release_summary: Feature release.
+ fragments:
+ - 2.17.0.yml
+ - 693-allow-discards.yaml
+ release_date: '2024-01-21'
+ 2.17.1:
+ changes:
+ bugfixes:
+ - openssl_dhparam - was using an internal function instead of the public API
+ to load DH param files when using the ``cryptography`` backend. The internal
+ function was removed in cryptography 42.0.0. The module now uses the public
+ API, which has been available since support for DH params was added to cryptography
+ (https://github.com/ansible-collections/community.crypto/pull/698).
+ - openssl_privatekey_info - ``check_consistency=true`` no longer works for RSA
+ keys with cryptography 42.0.0+ (https://github.com/ansible-collections/community.crypto/pull/701).
+ - openssl_privatekey_info - ``check_consistency=true`` now reports a warning
+ if it cannot determine consistency (https://github.com/ansible-collections/community.crypto/pull/705).
+ release_summary: Bugfix release for compatibility with cryptography 42.0.0.
+ fragments:
+ - 2.17.1.yml
+ - 698-openssl_dhparam-cryptography.yml
+ - 701-private_key_info-consistency.yml
+ - 705-openssl_privatekey_info-consistency.yml
+ release_date: '2024-01-27'
+ 2.18.0:
+ changes:
+ bugfixes:
+ - luks_device - fixed module a bug that prevented using ``remove_keyslot`` with
+ the value ``0`` (https://github.com/ansible-collections/community.crypto/pull/710).
+ - luks_device - fixed module falsely outputting ``changed=false`` when trying
+ to add a new slot with a key that is already present in another slot. The
+ module now rejects adding keys that are already present in another slot (https://github.com/ansible-collections/community.crypto/pull/710).
+ - luks_device - fixed testing of LUKS passphrases in when specifying a keyslot
+ for cryptsetup version 2.0.3. The output of this cryptsetup version slightly
+ differs from later versions (https://github.com/ansible-collections/community.crypto/pull/710).
+ deprecated_features:
+ - 'openssl_csr_pipe, openssl_privatekey_pipe, x509_certificate_pipe - the current
+ behavior of check mode is deprecated and will change in community.crypto 3.0.0.
+ The current behavior is similar to the modules without ``_pipe``: if the object
+ needs to be (re-)generated, only the ``changed`` status is set, but the object
+ is not updated. From community.crypto 3.0.0 on, the modules will ignore check
+ mode and always act as if check mode is not active. This behavior can already
+ achieved now by adding ``check_mode: false`` to the task. If you think this
+ breaks your use-case of this module, please `create an issue in the community.crypto
+ repository <https://github.com/ansible-collections/community.crypto/issues/new/choose>`__
+ (https://github.com/ansible-collections/community.crypto/issues/712, https://github.com/ansible-collections/community.crypto/pull/714).'
+ minor_changes:
+ - x509_crl - the new option ``serial_numbers`` allow to configure in which format
+ serial numbers can be provided to ``revoked_certificates[].serial_number``.
+ The default is as integers (``serial_numbers=integer``) for backwards compatibility;
+ setting ``serial_numbers=hex-octets`` allows to specify colon-separated hex
+ octet strings like ``00:11:22:FF`` (https://github.com/ansible-collections/community.crypto/issues/687,
+ https://github.com/ansible-collections/community.crypto/pull/715).
+ release_summary: Bugfix and feature release.
+ fragments:
+ - 2.18.0.yml
+ - 710-luks_device-keyslot-fixes.yml
+ - 714-pipe-check-mode-deprecation.yml
+ - 715-x509_crl-serial.yml
+ plugins:
+ filter:
+ - description: Convert a serial number as a colon-separated list of hex numbers
+ to an integer
+ name: parse_serial
+ namespace: null
+ - description: Convert an integer to a colon-separated list of hex numbers
+ name: to_serial
+ namespace: null
+ release_date: '2024-02-25'
2.2.0:
changes:
bugfixes:
@@ -947,7 +1141,7 @@ releases:
be installed by pip by specifying something like ``cryptography >= 37.0.0``
in your Execution Environment's Python dependencies file (https://github.com/ansible-collections/community.crypto/pull/440).
- Support automatic conversion for Internalionalized Domain Names (IDNs). When
- passing general names, for example Subject Altenative Names to ``community.crypto.openssl_csr``,
+ passing general names, for example Subject Alternative Names to ``community.crypto.openssl_csr``,
these will automatically be converted to IDNA. Conversion will be done per
label to IDNA2008 if possible, and IDNA2003 if IDNA2008 conversion fails for
that label. Note that IDNA conversion requires `the Python idna library <https://pypi.org/project/idna/>`_
diff --git a/ansible_collections/community/crypto/changelogs/config.yaml b/ansible_collections/community/crypto/changelogs/config.yaml
index f2767048a..93ceb6472 100644
--- a/ansible_collections/community/crypto/changelogs/config.yaml
+++ b/ansible_collections/community/crypto/changelogs/config.yaml
@@ -11,6 +11,9 @@ keep_fragments: false
mention_ancestor: true
new_plugins_after_name: removed_features
notesdir: fragments
+output_formats:
+ - md
+ - rst
prelude_section_name: release_summary
prelude_section_title: Release Summary
sections:
diff --git a/ansible_collections/community/crypto/docs/docsite/rst/guide_ownca.rst b/ansible_collections/community/crypto/docs/docsite/rst/guide_ownca.rst
index 0e8a46da8..79c224a46 100644
--- a/ansible_collections/community/crypto/docs/docsite/rst/guide_ownca.rst
+++ b/ansible_collections/community/crypto/docs/docsite/rst/guide_ownca.rst
@@ -8,7 +8,7 @@
How to create a small CA
========================
-The `community.crypto collection <https://galaxy.ansible.com/community/crypto>`_ offers multiple modules that create private keys, certificate signing requests, and certificates. This guide shows how to create your own small CA and how to use it to sign certificates.
+The `community.crypto collection <https://galaxy.ansible.com/ui/repo/published/community/crypto/>`_ offers multiple modules that create private keys, certificate signing requests, and certificates. This guide shows how to create your own small CA and how to use it to sign certificates.
In all examples, we assume that the CA's private key is password protected, where the password is provided in the ``secret_ca_passphrase`` variable.
diff --git a/ansible_collections/community/crypto/docs/docsite/rst/guide_selfsigned.rst b/ansible_collections/community/crypto/docs/docsite/rst/guide_selfsigned.rst
index dc208d5c7..fda4911d6 100644
--- a/ansible_collections/community/crypto/docs/docsite/rst/guide_selfsigned.rst
+++ b/ansible_collections/community/crypto/docs/docsite/rst/guide_selfsigned.rst
@@ -8,9 +8,9 @@
How to create self-signed certificates
======================================
-The `community.crypto collection <https://galaxy.ansible.com/community/crypto>`_ offers multiple modules that create private keys, certificate signing requests, and certificates. This guide shows how to create self-signed certificates.
+The `community.crypto collection <https://galaxy.ansible.com/ui/repo/published/community/crypto/>`_ offers multiple modules that create private keys, certificate signing requests, and certificates. This guide shows how to create self-signed certificates.
-For creating any kind of certificate, you always have to start with a private key. You can use the :ref:`community.crypto.openssl_privatekey module <ansible_collections.community.crypto.openssl_privatekey_module>` to create a private key. If you only specify ``path``, the default parameters will be used. This will result in a 4096 bit RSA private key:
+For creating any kind of certificate, you always have to start with a private key. You can use the :ref:`community.crypto.openssl_privatekey module <ansible_collections.community.crypto.openssl_privatekey_module>` to create a private key. If you only specify :ansopt:`community.crypto.openssl_privatekey#module:path`, the default parameters will be used. This will result in a 4096 bit RSA private key:
.. code-block:: yaml+jinja
@@ -18,7 +18,7 @@ For creating any kind of certificate, you always have to start with a private ke
community.crypto.openssl_privatekey:
path: /path/to/certificate.key
-You can specify ``type`` to select another key type, ``size`` to select a different key size (only available for RSA and DSA keys), or ``passphrase`` if you want to store the key password-protected:
+You can specify :ansopt:`community.crypto.openssl_privatekey#module:type` to select another key type, :ansopt:`community.crypto.openssl_privatekey#module:size` to select a different key size (only available for RSA and DSA keys), or :ansopt:`community.crypto.openssl_privatekey#module:passphrase` if you want to store the key password-protected:
.. code-block:: yaml+jinja
@@ -38,9 +38,9 @@ To create a very simple self-signed certificate with no specific information, yo
privatekey_path: /path/to/certificate.key
provider: selfsigned
-(If you used ``passphrase`` for the private key, you have to provide ``privatekey_passphrase``.)
+(If you used :ansopt:`community.crypto.openssl_privatekey#module:passphrase` for the private key, you have to provide :ansopt:`community.crypto.x509_certificate#module:privatekey_passphrase`.)
-You can use ``selfsigned_not_after`` to define when the certificate expires (default: in roughly 10 years), and ``selfsigned_not_before`` to define from when the certificate is valid (default: now).
+You can use :ansopt:`community.crypto.x509_certificate#module:selfsigned_not_after` to define when the certificate expires (default: in roughly 10 years), and :ansopt:`community.crypto.x509_certificate#module:selfsigned_not_before` to define from when the certificate is valid (default: now).
To define further properties of the certificate, like the subject, Subject Alternative Names (SANs), key usages, name constraints, etc., you need to first create a Certificate Signing Request (CSR) and provide it to the :ref:`community.crypto.x509_certificate module <ansible_collections.community.crypto.x509_certificate_module>`. If you do not need the CSR file, you can use the :ref:`community.crypto.openssl_csr_pipe module <ansible_collections.community.crypto.openssl_csr_pipe_module>` as in the example below. (To store it to disk, use the :ref:`community.crypto.openssl_csr module <ansible_collections.community.crypto.openssl_csr_module>` instead.)
diff --git a/ansible_collections/community/crypto/plugins/action/openssl_privatekey_pipe.py b/ansible_collections/community/crypto/plugins/action/openssl_privatekey_pipe.py
index dc1a16979..dc864ab01 100644
--- a/ansible_collections/community/crypto/plugins/action/openssl_privatekey_pipe.py
+++ b/ansible_collections/community/crypto/plugins/action/openssl_privatekey_pipe.py
@@ -51,6 +51,16 @@ class PrivateKeyModule(object):
self.module_backend.generate_private_key()
privatekey_data = self.module_backend.get_private_key_data()
self.privatekey_bytes = privatekey_data
+ else:
+ self.module.deprecate(
+ 'Check mode support for openssl_privatekey_pipe will change in community.crypto 3.0.0'
+ ' to behave the same as without check mode. You can get that behavior right now'
+ ' by adding `check_mode: false` to the openssl_privatekey_pipe task. If you think this'
+ ' breaks your use-case of this module, please create an issue in the'
+ ' community.crypto repository',
+ version='3.0.0',
+ collection_name='community.crypto',
+ )
self.changed = True
elif self.module_backend.needs_conversion():
# Convert
@@ -58,6 +68,16 @@ class PrivateKeyModule(object):
self.module_backend.convert_private_key()
privatekey_data = self.module_backend.get_private_key_data()
self.privatekey_bytes = privatekey_data
+ else:
+ self.module.deprecate(
+ 'Check mode support for openssl_privatekey_pipe will change in community.crypto 3.0.0'
+ ' to behave the same as without check mode. You can get that behavior right now'
+ ' by adding `check_mode: false` to the openssl_privatekey_pipe task. If you think this'
+ ' breaks your use-case of this module, please create an issue in the'
+ ' community.crypto repository',
+ version='3.0.0',
+ collection_name='community.crypto',
+ )
self.changed = True
def dump(self):
diff --git a/ansible_collections/community/crypto/plugins/doc_fragments/acme.py b/ansible_collections/community/crypto/plugins/doc_fragments/acme.py
index a50cedd69..2b5bfc231 100644
--- a/ansible_collections/community/crypto/plugins/doc_fragments/acme.py
+++ b/ansible_collections/community/crypto/plugins/doc_fragments/acme.py
@@ -16,10 +16,10 @@ notes:
- "If a new enough version of the C(cryptography) library
is available (see Requirements for details), it will be used
instead of the C(openssl) binary. This can be explicitly disabled
- or enabled with the C(select_crypto_backend) option. Note that using
+ or enabled with the O(select_crypto_backend) option. Note that using
the C(openssl) binary will be slower and less secure, as private key
contents always have to be stored on disk (see
- C(account_key_content))."
+ O(account_key_content))."
- "Although the defaults are chosen so that the module can be used with
the L(Let's Encrypt,https://letsencrypt.org/) CA, the module can in
principle be used with any CA providing an ACME endpoint, such as
@@ -47,15 +47,15 @@ options:
RSA keys can be created with C(openssl genrsa ...). Elliptic curve keys
can be created with C(openssl ecparam -genkey ...). Any other tool creating
private keys in PEM format can be used as well."
- - "Mutually exclusive with C(account_key_content)."
- - "Required if C(account_key_content) is not used."
+ - "Mutually exclusive with O(account_key_content)."
+ - "Required if O(account_key_content) is not used."
type: path
aliases: [ account_key ]
account_key_content:
description:
- "Content of the ACME account RSA or Elliptic Curve key."
- - "Mutually exclusive with C(account_key_src)."
- - "Required if C(account_key_src) is not used."
+ - "Mutually exclusive with O(account_key_src)."
+ - "Required if O(account_key_src) is not used."
- "B(Warning:) the content will be written into a temporary file, which will
be deleted by Ansible when the module completes. Since this is an
important private key — it can be used to change the account key,
@@ -81,9 +81,9 @@ options:
acme_version:
description:
- "The ACME version of the endpoint."
- - "Must be C(1) for the classic Let's Encrypt and Buypass ACME endpoints,
- or C(2) for standardized ACME v2 endpoints."
- - "The value C(1) is deprecated since community.crypto 2.0.0 and will be
+ - "Must be V(1) for the classic Let's Encrypt and Buypass ACME endpoints,
+ or V(2) for standardized ACME v2 endpoints."
+ - "The value V(1) is deprecated since community.crypto 2.0.0 and will be
removed from community.crypto 3.0.0."
required: true
type: int
@@ -114,17 +114,17 @@ options:
validate_certs:
description:
- Whether calls to the ACME directory will validate TLS certificates.
- - "B(Warning:) Should B(only ever) be set to C(false) for testing purposes,
+ - "B(Warning:) Should B(only ever) be set to V(false) for testing purposes,
for example when testing against a local Pebble server."
type: bool
default: true
select_crypto_backend:
description:
- Determines which crypto backend to use.
- - The default choice is C(auto), which tries to use C(cryptography) if available, and falls back to
+ - The default choice is V(auto), which tries to use C(cryptography) if available, and falls back to
C(openssl).
- - If set to C(openssl), will try to use the C(openssl) binary.
- - If set to C(cryptography), will try to use the
+ - If set to V(openssl), will try to use the C(openssl) binary.
+ - If set to V(cryptography), will try to use the
L(cryptography,https://cryptography.io/) library.
type: str
default: auto
diff --git a/ansible_collections/community/crypto/plugins/doc_fragments/module_certificate.py b/ansible_collections/community/crypto/plugins/doc_fragments/module_certificate.py
index 648d4ce91..5691e7bbf 100644
--- a/ansible_collections/community/crypto/plugins/doc_fragments/module_certificate.py
+++ b/ansible_collections/community/crypto/plugins/doc_fragments/module_certificate.py
@@ -17,7 +17,7 @@ description:
- This module allows one to (re)generate OpenSSL certificates.
- It uses the cryptography python library to interact with OpenSSL.
requirements:
- - cryptography >= 1.6 (if using C(selfsigned) or C(ownca) provider)
+ - cryptography >= 1.6 (if using V(selfsigned) or V(ownca) provider)
options:
force:
description:
@@ -28,35 +28,35 @@ options:
csr_path:
description:
- Path to the Certificate Signing Request (CSR) used to generate this certificate.
- - This is mutually exclusive with I(csr_content).
+ - This is mutually exclusive with O(csr_content).
type: path
csr_content:
description:
- Content of the Certificate Signing Request (CSR) used to generate this certificate.
- - This is mutually exclusive with I(csr_path).
+ - This is mutually exclusive with O(csr_path).
type: str
privatekey_path:
description:
- Path to the private key to use when signing the certificate.
- - This is mutually exclusive with I(privatekey_content).
+ - This is mutually exclusive with O(privatekey_content).
type: path
privatekey_content:
description:
- Content of the private key to use when signing the certificate.
- - This is mutually exclusive with I(privatekey_path).
+ - This is mutually exclusive with O(privatekey_path).
type: str
privatekey_passphrase:
description:
- - The passphrase for the I(privatekey_path) resp. I(privatekey_content).
+ - The passphrase for the O(privatekey_path) resp. O(privatekey_content).
- This is required if the private key is password protected.
type: str
ignore_timestamps:
description:
- Whether the "not before" and "not after" timestamps should be ignored for idempotency checks.
- - It is better to keep the default value C(true) when using relative timestamps (like C(+0s) for now).
+ - It is better to keep the default value V(true) when using relative timestamps (like V(+0s) for now).
type: bool
default: true
version_added: 2.0.0
@@ -64,8 +64,8 @@ options:
select_crypto_backend:
description:
- Determines which crypto backend to use.
- - The default choice is C(auto), which tries to use C(cryptography) if available.
- - If set to C(cryptography), will try to use the L(cryptography,https://cryptography.io/) library.
+ - The default choice is V(auto), which tries to use C(cryptography) if available.
+ - If set to V(cryptography), will try to use the L(cryptography,https://cryptography.io/) library.
type: str
default: auto
choices: [ auto, cryptography ]
@@ -73,7 +73,7 @@ options:
notes:
- All ASN.1 TIME values should be specified following the YYYYMMDDHHMMSSZ pattern.
- Date specified should be UTC. Minutes and seconds are mandatory.
- - For security reason, when you use C(ownca) provider, you should NOT run
+ - For security reason, when you use V(ownca) provider, you should NOT run
M(community.crypto.x509_certificate) on a target machine, but on a dedicated CA machine. It
is recommended not to store the CA private key on the target machine. Once signed, the
certificate can be moved to the target machine.
@@ -91,26 +91,26 @@ seealso:
description:
- This module allows one to (re)generate OpenSSL certificates.
requirements:
- - acme-tiny >= 4.0.0 (if using the C(acme) provider)
+ - acme-tiny >= 4.0.0 (if using the V(acme) provider)
options:
acme_accountkey_path:
description:
- - The path to the accountkey for the C(acme) provider.
- - This is only used by the C(acme) provider.
+ - The path to the accountkey for the V(acme) provider.
+ - This is only used by the V(acme) provider.
type: path
acme_challenge_path:
description:
- The path to the ACME challenge directory that is served on U(http://<HOST>:80/.well-known/acme-challenge/)
- - This is only used by the C(acme) provider.
+ - This is only used by the V(acme) provider.
type: path
acme_chain:
description:
- Include the intermediate certificate to the generated certificate
- - This is only used by the C(acme) provider.
+ - This is only used by the V(acme) provider.
- Note that this is only available for older versions of C(acme-tiny).
- New versions include the chain automatically, and setting I(acme_chain) to C(true) results in an error.
+ New versions include the chain automatically, and setting O(acme_chain) to V(true) results in an error.
type: bool
default: false
@@ -127,7 +127,7 @@ options:
entrust_cert_type:
description:
- Specify the type of certificate requested.
- - This is only used by the C(entrust) provider.
+ - This is only used by the V(entrust) provider.
type: str
default: STANDARD_SSL
choices: [ 'STANDARD_SSL', 'ADVANTAGE_SSL', 'UC_SSL', 'EV_SSL', 'WILDCARD_SSL', 'PRIVATE_SSL', 'PD_SSL', 'CDS_ENT_LITE', 'CDS_ENT_PRO', 'SMIME_ENT' ]
@@ -135,66 +135,66 @@ options:
entrust_requester_email:
description:
- The email of the requester of the certificate (for tracking purposes).
- - This is only used by the C(entrust) provider.
- - This is required if the provider is C(entrust).
+ - This is only used by the V(entrust) provider.
+ - This is required if the provider is V(entrust).
type: str
entrust_requester_name:
description:
- The name of the requester of the certificate (for tracking purposes).
- - This is only used by the C(entrust) provider.
- - This is required if the provider is C(entrust).
+ - This is only used by the V(entrust) provider.
+ - This is required if the provider is V(entrust).
type: str
entrust_requester_phone:
description:
- The phone number of the requester of the certificate (for tracking purposes).
- - This is only used by the C(entrust) provider.
- - This is required if the provider is C(entrust).
+ - This is only used by the V(entrust) provider.
+ - This is required if the provider is V(entrust).
type: str
entrust_api_user:
description:
- The username for authentication to the Entrust Certificate Services (ECS) API.
- - This is only used by the C(entrust) provider.
- - This is required if the provider is C(entrust).
+ - This is only used by the V(entrust) provider.
+ - This is required if the provider is V(entrust).
type: str
entrust_api_key:
description:
- The key (password) for authentication to the Entrust Certificate Services (ECS) API.
- - This is only used by the C(entrust) provider.
- - This is required if the provider is C(entrust).
+ - This is only used by the V(entrust) provider.
+ - This is required if the provider is V(entrust).
type: str
entrust_api_client_cert_path:
description:
- The path to the client certificate used to authenticate to the Entrust Certificate Services (ECS) API.
- - This is only used by the C(entrust) provider.
- - This is required if the provider is C(entrust).
+ - This is only used by the V(entrust) provider.
+ - This is required if the provider is V(entrust).
type: path
entrust_api_client_cert_key_path:
description:
- The path to the private key of the client certificate used to authenticate to the Entrust Certificate Services (ECS) API.
- - This is only used by the C(entrust) provider.
- - This is required if the provider is C(entrust).
+ - This is only used by the V(entrust) provider.
+ - This is required if the provider is V(entrust).
type: path
entrust_not_after:
description:
- The point in time at which the certificate stops being valid.
- Time can be specified either as relative time or as an absolute timestamp.
- - A valid absolute time format is C(ASN.1 TIME) such as C(2019-06-18).
- - A valid relative time format is C([+-]timespec) where timespec can be an integer + C([w | d | h | m | s]), such as C(+365d) or C(+32w1d2h)).
+ - A valid absolute time format is C(ASN.1 TIME) such as V(2019-06-18).
+ - A valid relative time format is V([+-]timespec) where timespec can be an integer + C([w | d | h | m | s]), such as V(+365d) or V(+32w1d2h)).
- Time will always be interpreted as UTC.
- Note that only the date (day, month, year) is supported for specifying the expiry date of the issued certificate.
- The full date-time is adjusted to EST (GMT -5:00) before issuance, which may result in a certificate with an expiration date one day
earlier than expected if a relative time is used.
- The minimum certificate lifetime is 90 days, and maximum is three years.
- If this value is not specified, the certificate will stop being valid 365 days the date of issue.
- - This is only used by the C(entrust) provider.
- - Please note that this value is B(not) covered by the I(ignore_timestamps) option.
+ - This is only used by the V(entrust) provider.
+ - Please note that this value is B(not) covered by the O(ignore_timestamps) option.
type: str
default: +365d
@@ -202,60 +202,60 @@ options:
description:
- The path to the specification file defining the Entrust Certificate Services (ECS) API configuration.
- You can use this to keep a local copy of the specification to avoid downloading it every time the module is used.
- - This is only used by the C(entrust) provider.
+ - This is only used by the V(entrust) provider.
type: path
default: https://cloud.entrust.net/EntrustCloud/documentation/cms-api-2.1.0.yaml
'''
BACKEND_OWNCA_DOCUMENTATION = r'''
description:
- - The C(ownca) provider is intended for generating an OpenSSL certificate signed with your own
+ - The V(ownca) provider is intended for generating an OpenSSL certificate signed with your own
CA (Certificate Authority) certificate (self-signed certificate).
options:
ownca_path:
description:
- Remote absolute path of the CA (Certificate Authority) certificate.
- - This is only used by the C(ownca) provider.
- - This is mutually exclusive with I(ownca_content).
+ - This is only used by the V(ownca) provider.
+ - This is mutually exclusive with O(ownca_content).
type: path
ownca_content:
description:
- Content of the CA (Certificate Authority) certificate.
- - This is only used by the C(ownca) provider.
- - This is mutually exclusive with I(ownca_path).
+ - This is only used by the V(ownca) provider.
+ - This is mutually exclusive with O(ownca_path).
type: str
ownca_privatekey_path:
description:
- Path to the CA (Certificate Authority) private key to use when signing the certificate.
- - This is only used by the C(ownca) provider.
- - This is mutually exclusive with I(ownca_privatekey_content).
+ - This is only used by the V(ownca) provider.
+ - This is mutually exclusive with O(ownca_privatekey_content).
type: path
ownca_privatekey_content:
description:
- Content of the CA (Certificate Authority) private key to use when signing the certificate.
- - This is only used by the C(ownca) provider.
- - This is mutually exclusive with I(ownca_privatekey_path).
+ - This is only used by the V(ownca) provider.
+ - This is mutually exclusive with O(ownca_privatekey_path).
type: str
ownca_privatekey_passphrase:
description:
- - The passphrase for the I(ownca_privatekey_path) resp. I(ownca_privatekey_content).
- - This is only used by the C(ownca) provider.
+ - The passphrase for the O(ownca_privatekey_path) resp. O(ownca_privatekey_content).
+ - This is only used by the V(ownca) provider.
type: str
ownca_digest:
description:
- - The digest algorithm to be used for the C(ownca) certificate.
- - This is only used by the C(ownca) provider.
+ - The digest algorithm to be used for the V(ownca) certificate.
+ - This is only used by the V(ownca) provider.
type: str
default: sha256
ownca_version:
description:
- - The version of the C(ownca) certificate.
- - Nowadays it should almost always be C(3).
- - This is only used by the C(ownca) provider.
+ - The version of the V(ownca) certificate.
+ - Nowadays it should almost always be V(3).
+ - This is only used by the V(ownca) provider.
type: int
default: 3
@@ -265,12 +265,12 @@ options:
- Time can be specified either as relative time or as absolute timestamp.
- Time will always be interpreted as UTC.
- Valid format is C([+-]timespec | ASN.1 TIME) where timespec can be an integer
- + C([w | d | h | m | s]) (for example C(+32w1d2h)).
+ + C([w | d | h | m | s]) (for example V(+32w1d2h)).
- If this value is not specified, the certificate will start being valid from now.
- Note that this value is B(not used to determine whether an existing certificate should be regenerated).
- This can be changed by setting the I(ignore_timestamps) option to C(false). Please note that you should
- avoid relative timestamps when setting I(ignore_timestamps=false).
- - This is only used by the C(ownca) provider.
+ This can be changed by setting the O(ignore_timestamps) option to V(false). Please note that you should
+ avoid relative timestamps when setting O(ignore_timestamps=false).
+ - This is only used by the V(ownca) provider.
type: str
default: +0s
@@ -280,12 +280,12 @@ options:
- Time can be specified either as relative time or as absolute timestamp.
- Time will always be interpreted as UTC.
- Valid format is C([+-]timespec | ASN.1 TIME) where timespec can be an integer
- + C([w | d | h | m | s]) (for example C(+32w1d2h)).
+ + C([w | d | h | m | s]) (for example V(+32w1d2h)).
- If this value is not specified, the certificate will stop being valid 10 years from now.
- Note that this value is B(not used to determine whether an existing certificate should be regenerated).
- This can be changed by setting the I(ignore_timestamps) option to C(false). Please note that you should
- avoid relative timestamps when setting I(ignore_timestamps=false).
- - This is only used by the C(ownca) provider.
+ This can be changed by setting the O(ignore_timestamps) option to V(false). Please note that you should
+ avoid relative timestamps when setting O(ignore_timestamps=false).
+ - This is only used by the V(ownca) provider.
- On macOS 10.15 and onwards, TLS server certificates must have a validity period of 825 days or fewer.
Please see U(https://support.apple.com/en-us/HT210176) for more details.
type: str
@@ -294,12 +294,12 @@ options:
ownca_create_subject_key_identifier:
description:
- Whether to create the Subject Key Identifier (SKI) from the public key.
- - A value of C(create_if_not_provided) (default) only creates a SKI when the CSR does not
+ - A value of V(create_if_not_provided) (default) only creates a SKI when the CSR does not
provide one.
- - A value of C(always_create) always creates a SKI. If the CSR provides one, that one is
+ - A value of V(always_create) always creates a SKI. If the CSR provides one, that one is
ignored.
- - A value of C(never_create) never creates a SKI. If the CSR provides one, that one is used.
- - This is only used by the C(ownca) provider.
+ - A value of V(never_create) never creates a SKI. If the CSR provides one, that one is used.
+ - This is only used by the V(ownca) provider.
- Note that this is only supported if the C(cryptography) backend is used!
type: str
choices: [create_if_not_provided, always_create, never_create]
@@ -311,7 +311,7 @@ options:
a authority key identifier, it is ignored.
- The Authority Key Identifier is generated from the CA certificate's Subject Key Identifier,
if available. If it is not available, the CA certificate's public key will be used.
- - This is only used by the C(ownca) provider.
+ - This is only used by the V(ownca) provider.
- Note that this is only supported if the C(cryptography) backend is used!
type: bool
default: true
@@ -319,7 +319,7 @@ options:
BACKEND_SELFSIGNED_DOCUMENTATION = r'''
notes:
- - For the C(selfsigned) provider, I(csr_path) and I(csr_content) are optional. If not provided, a
+ - For the V(selfsigned) provider, O(csr_path) and O(csr_content) are optional. If not provided, a
certificate without any information (Subject, Subject Alternative Names, Key Usage, etc.) is created.
options:
@@ -329,28 +329,28 @@ options:
# csr_path:
# description:
- # - This is optional for the C(selfsigned) provider. If not provided, a certificate
+ # - This is optional for the V(selfsigned) provider. If not provided, a certificate
# without any information (Subject, Subject Alternative Names, Key Usage, etc.) is
# created.
# csr_content:
# description:
- # - This is optional for the C(selfsigned) provider. If not provided, a certificate
+ # - This is optional for the V(selfsigned) provider. If not provided, a certificate
# without any information (Subject, Subject Alternative Names, Key Usage, etc.) is
# created.
selfsigned_version:
description:
- - Version of the C(selfsigned) certificate.
- - Nowadays it should almost always be C(3).
- - This is only used by the C(selfsigned) provider.
+ - Version of the V(selfsigned) certificate.
+ - Nowadays it should almost always be V(3).
+ - This is only used by the V(selfsigned) provider.
type: int
default: 3
selfsigned_digest:
description:
- Digest algorithm to be used when self-signing the certificate.
- - This is only used by the C(selfsigned) provider.
+ - This is only used by the V(selfsigned) provider.
type: str
default: sha256
@@ -360,12 +360,12 @@ options:
- Time can be specified either as relative time or as absolute timestamp.
- Time will always be interpreted as UTC.
- Valid format is C([+-]timespec | ASN.1 TIME) where timespec can be an integer
- + C([w | d | h | m | s]) (for example C(+32w1d2h)).
+ + C([w | d | h | m | s]) (for example V(+32w1d2h)).
- If this value is not specified, the certificate will start being valid from now.
- Note that this value is B(not used to determine whether an existing certificate should be regenerated).
- This can be changed by setting the I(ignore_timestamps) option to C(false). Please note that you should
- avoid relative timestamps when setting I(ignore_timestamps=false).
- - This is only used by the C(selfsigned) provider.
+ This can be changed by setting the O(ignore_timestamps) option to V(false). Please note that you should
+ avoid relative timestamps when setting O(ignore_timestamps=false).
+ - This is only used by the V(selfsigned) provider.
type: str
default: +0s
aliases: [ selfsigned_notBefore ]
@@ -376,12 +376,12 @@ options:
- Time can be specified either as relative time or as absolute timestamp.
- Time will always be interpreted as UTC.
- Valid format is C([+-]timespec | ASN.1 TIME) where timespec can be an integer
- + C([w | d | h | m | s]) (for example C(+32w1d2h)).
+ + C([w | d | h | m | s]) (for example V(+32w1d2h)).
- If this value is not specified, the certificate will stop being valid 10 years from now.
- Note that this value is B(not used to determine whether an existing certificate should be regenerated).
- This can be changed by setting the I(ignore_timestamps) option to C(false). Please note that you should
- avoid relative timestamps when setting I(ignore_timestamps=false).
- - This is only used by the C(selfsigned) provider.
+ This can be changed by setting the O(ignore_timestamps) option to V(false). Please note that you should
+ avoid relative timestamps when setting O(ignore_timestamps=false).
+ - This is only used by the V(selfsigned) provider.
- On macOS 10.15 and onwards, TLS server certificates must have a validity period of 825 days or fewer.
Please see U(https://support.apple.com/en-us/HT210176) for more details.
type: str
@@ -391,12 +391,12 @@ options:
selfsigned_create_subject_key_identifier:
description:
- Whether to create the Subject Key Identifier (SKI) from the public key.
- - A value of C(create_if_not_provided) (default) only creates a SKI when the CSR does not
+ - A value of V(create_if_not_provided) (default) only creates a SKI when the CSR does not
provide one.
- - A value of C(always_create) always creates a SKI. If the CSR provides one, that one is
+ - A value of V(always_create) always creates a SKI. If the CSR provides one, that one is
ignored.
- - A value of C(never_create) never creates a SKI. If the CSR provides one, that one is used.
- - This is only used by the C(selfsigned) provider.
+ - A value of V(never_create) never creates a SKI. If the CSR provides one, that one is used.
+ - This is only used by the V(selfsigned) provider.
- Note that this is only supported if the C(cryptography) backend is used!
type: str
choices: [create_if_not_provided, always_create, never_create]
diff --git a/ansible_collections/community/crypto/plugins/doc_fragments/module_csr.py b/ansible_collections/community/crypto/plugins/doc_fragments/module_csr.py
index 81c4318a4..e2a0bdd94 100644
--- a/ansible_collections/community/crypto/plugins/doc_fragments/module_csr.py
+++ b/ansible_collections/community/crypto/plugins/doc_fragments/module_csr.py
@@ -27,12 +27,12 @@ options:
privatekey_path:
description:
- The path to the private key to use when signing the certificate signing request.
- - Either I(privatekey_path) or I(privatekey_content) must be specified if I(state) is C(present), but not both.
+ - Either O(privatekey_path) or O(privatekey_content) must be specified if O(state) is V(present), but not both.
type: path
privatekey_content:
description:
- The content of the private key to use when signing the certificate signing request.
- - Either I(privatekey_path) or I(privatekey_content) must be specified if I(state) is C(present), but not both.
+ - Either O(privatekey_path) or O(privatekey_content) must be specified if O(state) is V(present), but not both.
type: str
privatekey_passphrase:
description:
@@ -53,17 +53,17 @@ options:
description:
- Key/value pairs that will be present in the subject name field of the certificate signing request.
- If you need to specify more than one value with the same key, use a list as value.
- - If the order of the components is important, use I(subject_ordered).
- - Mutually exclusive with I(subject_ordered).
+ - If the order of the components is important, use O(subject_ordered).
+ - Mutually exclusive with O(subject_ordered).
type: dict
subject_ordered:
description:
- A list of dictionaries, where every dictionary must contain one key/value pair. This key/value pair
will be present in the subject name field of the certificate signing request.
- If you want to specify more than one value with the same key in a row, you can use a list as value.
- - Mutually exclusive with I(subject), and any other subject field option, such as I(country_name),
- I(state_or_province_name), I(locality_name), I(organization_name), I(organizational_unit_name),
- I(common_name), or I(email_address).
+ - Mutually exclusive with O(subject), and any other subject field option, such as O(country_name),
+ O(state_or_province_name), O(locality_name), O(organization_name), O(organizational_unit_name),
+ O(common_name), or O(email_address).
type: list
elements: dict
version_added: 2.0.0
@@ -108,8 +108,8 @@ options:
- Values must be prefixed by their options. (These are C(email), C(URI), C(DNS), C(RID), C(IP), C(dirName),
C(otherName), and the ones specific to your CA).
- Note that if no SAN is specified, but a common name, the common
- name will be added as a SAN except if C(useCommonNameForSAN) is
- set to I(false).
+ name will be added as a SAN except if O(use_common_name_for_san) is
+ set to V(false).
- More at U(https://tools.ietf.org/html/rfc5280#section-4.2.1.6).
type: list
elements: str
@@ -122,8 +122,8 @@ options:
aliases: [ subjectAltName_critical ]
use_common_name_for_san:
description:
- - If set to C(true), the module will fill the common name in for
- C(subject_alt_name) with C(DNS:) prefix if no SAN is specified.
+ - If set to V(true), the module will fill the common name in for
+ O(subject_alt_name) with C(DNS:) prefix if no SAN is specified.
type: bool
default: true
aliases: [ useCommonNameForSAN ]
@@ -186,16 +186,16 @@ options:
description:
- For CA certificates, this specifies a list of identifiers which describe
subtrees of names that this CA is allowed to issue certificates for.
- - Values must be prefixed by their options. (i.e., C(email), C(URI), C(DNS), C(RID), C(IP), C(dirName),
- C(otherName) and the ones specific to your CA).
+ - Values must be prefixed by their options. (That is, C(email), C(URI), C(DNS), C(RID), C(IP), C(dirName),
+ C(otherName), and the ones specific to your CA).
type: list
elements: str
name_constraints_excluded:
description:
- For CA certificates, this specifies a list of identifiers which describe
subtrees of names that this CA is B(not) allowed to issue certificates for.
- - Values must be prefixed by their options. (i.e., C(email), C(URI), C(DNS), C(RID), C(IP), C(dirName),
- C(otherName) and the ones specific to your CA).
+ - Values must be prefixed by their options. (That is, C(email), C(URI), C(DNS), C(RID), C(IP), C(dirName),
+ C(otherName), and the ones specific to your CA).
type: list
elements: str
name_constraints_critical:
@@ -206,8 +206,8 @@ options:
select_crypto_backend:
description:
- Determines which crypto backend to use.
- - The default choice is C(auto), which tries to use C(cryptography) if available.
- - If set to C(cryptography), will try to use the L(cryptography,https://cryptography.io/) library.
+ - The default choice is V(auto), which tries to use C(cryptography) if available.
+ - If set to V(cryptography), will try to use the L(cryptography,https://cryptography.io/) library.
type: str
default: auto
choices: [ auto, cryptography ]
@@ -223,49 +223,51 @@ options:
subject_key_identifier:
description:
- The subject key identifier as a hex string, where two bytes are separated by colons.
- - "Example: C(00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:00:11:22:33)"
+ - "Example: V(00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:00:11:22:33)"
- "Please note that commercial CAs ignore this value, respectively use a value of their
own choice. Specifying this option is mostly useful for self-signed certificates
or for own CAs."
- - Note that this option can only be used if I(create_subject_key_identifier) is C(false).
+ - Note that this option can only be used if O(create_subject_key_identifier) is V(false).
- Note that this is only supported if the C(cryptography) backend is used!
type: str
authority_key_identifier:
description:
- The authority key identifier as a hex string, where two bytes are separated by colons.
- - "Example: C(00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:00:11:22:33)"
+ - "Example: V(00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:00:11:22:33)"
- "Please note that commercial CAs ignore this value, respectively use a value of their
own choice. Specifying this option is mostly useful for self-signed certificates
or for own CAs."
- Note that this is only supported if the C(cryptography) backend is used!
- - The C(AuthorityKeyIdentifier) extension will only be added if at least one of I(authority_key_identifier),
- I(authority_cert_issuer) and I(authority_cert_serial_number) is specified.
+ - The C(AuthorityKeyIdentifier) extension will only be added if at least one of O(authority_key_identifier),
+ O(authority_cert_issuer) and O(authority_cert_serial_number) is specified.
type: str
authority_cert_issuer:
description:
- Names that will be present in the authority cert issuer field of the certificate signing request.
- - Values must be prefixed by their options. (i.e., C(email), C(URI), C(DNS), C(RID), C(IP), C(dirName),
- C(otherName) and the ones specific to your CA)
- - "Example: C(DNS:ca.example.org)"
- - If specified, I(authority_cert_serial_number) must also be specified.
+ - Values must be prefixed by their options. (That is, C(email), C(URI), C(DNS), C(RID), C(IP), C(dirName),
+ C(otherName), and the ones specific to your CA)
+ - "Example: V(DNS:ca.example.org)"
+ - If specified, O(authority_cert_serial_number) must also be specified.
- "Please note that commercial CAs ignore this value, respectively use a value of their
own choice. Specifying this option is mostly useful for self-signed certificates
or for own CAs."
- Note that this is only supported if the C(cryptography) backend is used!
- - The C(AuthorityKeyIdentifier) extension will only be added if at least one of I(authority_key_identifier),
- I(authority_cert_issuer) and I(authority_cert_serial_number) is specified.
+ - The C(AuthorityKeyIdentifier) extension will only be added if at least one of O(authority_key_identifier),
+ O(authority_cert_issuer) and O(authority_cert_serial_number) is specified.
type: list
elements: str
authority_cert_serial_number:
description:
- The authority cert serial number.
- - If specified, I(authority_cert_issuer) must also be specified.
+ - If specified, O(authority_cert_issuer) must also be specified.
- Note that this is only supported if the C(cryptography) backend is used!
- "Please note that commercial CAs ignore this value, respectively use a value of their
own choice. Specifying this option is mostly useful for self-signed certificates
or for own CAs."
- - The C(AuthorityKeyIdentifier) extension will only be added if at least one of I(authority_key_identifier),
- I(authority_cert_issuer) and I(authority_cert_serial_number) is specified.
+ - The C(AuthorityKeyIdentifier) extension will only be added if at least one of O(authority_key_identifier),
+ O(authority_cert_issuer) and O(authority_cert_serial_number) is specified.
+ - This option accepts an B(integer). If you want to provide serial numbers as colon-separated hex strings,
+ such as C(11:22:33), you need to convert them to an integer with P(community.crypto.parse_serial#filter).
type: int
crl_distribution_points:
description:
@@ -277,15 +279,15 @@ options:
full_name:
description:
- Describes how the CRL can be retrieved.
- - Mutually exclusive with I(relative_name).
- - "Example: C(URI:https://ca.example.com/revocations.crl)."
+ - Mutually exclusive with O(crl_distribution_points[].relative_name).
+ - "Example: V(URI:https://ca.example.com/revocations.crl)."
type: list
elements: str
relative_name:
description:
- Describes how the CRL can be retrieved relative to the CRL issuer.
- - Mutually exclusive with I(full_name).
- - "Example: C(/CN=example.com)."
+ - Mutually exclusive with O(crl_distribution_points[].full_name).
+ - "Example: V(/CN=example.com)."
- Can only be used when cryptography >= 1.6 is installed.
type: list
elements: str
@@ -322,4 +324,6 @@ seealso:
- module: community.crypto.openssl_privatekey_pipe
- module: community.crypto.openssl_publickey
- module: community.crypto.openssl_csr_info
+- plugin: community.crypto.parse_serial
+ plugin_type: filter
'''
diff --git a/ansible_collections/community/crypto/plugins/doc_fragments/module_privatekey.py b/ansible_collections/community/crypto/plugins/doc_fragments/module_privatekey.py
index a27b26c7d..d039cf1c0 100644
--- a/ansible_collections/community/crypto/plugins/doc_fragments/module_privatekey.py
+++ b/ansible_collections/community/crypto/plugins/doc_fragments/module_privatekey.py
@@ -18,11 +18,6 @@ description:
L(ECC,https://en.wikipedia.org/wiki/Elliptic-curve_cryptography) or
L(EdDSA,https://en.wikipedia.org/wiki/EdDSA) private keys.
- Keys are generated in PEM format.
- - "Please note that the module regenerates private keys if they do not match
- the module's options. In particular, if you provide another passphrase
- (or specify none), change the keysize, etc., the private key will be
- regenerated. If you are concerned that this could B(overwrite your private key),
- consider using the I(backup) option."
requirements:
- cryptography >= 1.2.3 (older versions might work as well)
options:
@@ -34,20 +29,20 @@ options:
type:
description:
- The algorithm used to generate the TLS/SSL private key.
- - Note that C(ECC), C(X25519), C(X448), C(Ed25519) and C(Ed448) require the C(cryptography) backend.
- C(X25519) needs cryptography 2.5 or newer, while C(X448), C(Ed25519) and C(Ed448) require
- cryptography 2.6 or newer. For C(ECC), the minimal cryptography version required depends on the
- I(curve) option.
+ - Note that V(ECC), V(X25519), V(X448), V(Ed25519), and V(Ed448) require the C(cryptography) backend.
+ V(X25519) needs cryptography 2.5 or newer, while V(X448), V(Ed25519), and V(Ed448) require
+ cryptography 2.6 or newer. For V(ECC), the minimal cryptography version required depends on the
+ O(curve) option.
type: str
default: RSA
choices: [ DSA, ECC, Ed25519, Ed448, RSA, X25519, X448 ]
curve:
description:
- Note that not all curves are supported by all versions of C(cryptography).
- - For maximal interoperability, C(secp384r1) or C(secp256r1) should be used.
+ - For maximal interoperability, V(secp384r1) or V(secp256r1) should be used.
- We use the curve names as defined in the
L(IANA registry for TLS,https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8).
- - Please note that all curves except C(secp224r1), C(secp256k1), C(secp256r1), C(secp384r1) and C(secp521r1)
+ - Please note that all curves except V(secp224r1), V(secp256k1), V(secp256r1), V(secp384r1), and V(secp521r1)
are discouraged for new private keys.
type: str
choices:
@@ -76,13 +71,13 @@ options:
type: str
cipher:
description:
- - The cipher to encrypt the private key. Must be C(auto).
+ - The cipher to encrypt the private key. Must be V(auto).
type: str
select_crypto_backend:
description:
- Determines which crypto backend to use.
- - The default choice is C(auto), which tries to use C(cryptography) if available.
- - If set to C(cryptography), will try to use the L(cryptography,https://cryptography.io/) library.
+ - The default choice is V(auto), which tries to use C(cryptography) if available.
+ - If set to V(cryptography), will try to use the L(cryptography,https://cryptography.io/) library.
type: str
default: auto
choices: [ auto, cryptography ]
@@ -90,11 +85,11 @@ options:
description:
- Determines which format the private key is written in. By default, PKCS1 (traditional OpenSSL format)
is used for all keys which support it. Please note that not every key can be exported in any format.
- - The value C(auto) selects a format based on the key format. The value C(auto_ignore) does the same,
+ - The value V(auto) selects a format based on the key format. The value V(auto_ignore) does the same,
but for existing private key files, it will not force a regenerate when its format is not the automatically
selected one for generation.
- Note that if the format for an existing private key mismatches, the key is B(regenerated) by default.
- To change this behavior, use the I(format_mismatch) option.
+ To change this behavior, use the O(format_mismatch) option.
type: str
default: auto_ignore
choices: [ pkcs1, pkcs8, raw, auto, auto_ignore ]
@@ -102,8 +97,8 @@ options:
description:
- Determines behavior of the module if the format of a private key does not match the expected format, but all
other parameters are as expected.
- - If set to C(regenerate) (default), generates a new private key.
- - If set to C(convert), the key will be converted to the new format instead.
+ - If set to V(regenerate) (default), generates a new private key.
+ - If set to V(convert), the key will be converted to the new format instead.
- Only supported by the C(cryptography) backend.
type: str
default: regenerate
@@ -114,24 +109,24 @@ options:
The module will always generate a new key if the destination file does not exist.
- By default, the key will be regenerated when it does not match the module's options,
except when the key cannot be read or the passphrase does not match. Please note that
- this B(changed) for Ansible 2.10. For Ansible 2.9, the behavior was as if C(full_idempotence)
+ this B(changed) for Ansible 2.10. For Ansible 2.9, the behavior was as if V(full_idempotence)
is specified.
- - If set to C(never), the module will fail if the key cannot be read or the passphrase
+ - If set to V(never), the module will fail if the key cannot be read or the passphrase
is not matching, and will never regenerate an existing key.
- - If set to C(fail), the module will fail if the key does not correspond to the module's
+ - If set to V(fail), the module will fail if the key does not correspond to the module's
options.
- - If set to C(partial_idempotence), the key will be regenerated if it does not conform to
+ - If set to V(partial_idempotence), the key will be regenerated if it does not conform to
the module's options. The key is B(not) regenerated if it cannot be read (broken file),
the key is protected by an unknown passphrase, or when they key is not protected by a
passphrase, but a passphrase is specified.
- - If set to C(full_idempotence), the key will be regenerated if it does not conform to the
+ - If set to V(full_idempotence), the key will be regenerated if it does not conform to the
module's options. This is also the case if the key cannot be read (broken file), the key
is protected by an unknown passphrase, or when they key is not protected by a passphrase,
but a passphrase is specified. Make sure you have a B(backup) when using this option!
- - If set to C(always), the module will always regenerate the key. This is equivalent to
- setting I(force) to C(true).
- - Note that if I(format_mismatch) is set to C(convert) and everything matches except the
- format, the key will always be converted, except if I(regenerate) is set to C(always).
+ - If set to V(always), the module will always regenerate the key. This is equivalent to
+ setting O(force) to V(true).
+ - Note that if O(format_mismatch) is set to V(convert) and everything matches except the
+ format, the key will always be converted, except if O(regenerate) is set to V(always).
type: str
choices:
- never
diff --git a/ansible_collections/community/crypto/plugins/doc_fragments/module_privatekey_convert.py b/ansible_collections/community/crypto/plugins/doc_fragments/module_privatekey_convert.py
index f1c6f70ec..973d1fe00 100644
--- a/ansible_collections/community/crypto/plugins/doc_fragments/module_privatekey_convert.py
+++ b/ansible_collections/community/crypto/plugins/doc_fragments/module_privatekey_convert.py
@@ -18,12 +18,12 @@ options:
src_path:
description:
- Name of the file containing the OpenSSL private key to convert.
- - Exactly one of I(src_path) or I(src_content) must be specified.
+ - Exactly one of O(src_path) or O(src_content) must be specified.
type: path
src_content:
description:
- The content of the file containing the OpenSSL private key to convert.
- - Exactly one of I(src_path) or I(src_content) must be specified.
+ - Exactly one of O(src_path) or O(src_content) must be specified.
type: str
src_passphrase:
description:
diff --git a/ansible_collections/community/crypto/plugins/doc_fragments/name_encoding.py b/ansible_collections/community/crypto/plugins/doc_fragments/name_encoding.py
index fec94380d..b51408530 100644
--- a/ansible_collections/community/crypto/plugins/doc_fragments/name_encoding.py
+++ b/ansible_collections/community/crypto/plugins/doc_fragments/name_encoding.py
@@ -14,12 +14,12 @@ options:
name_encoding:
description:
- How to encode names (DNS names, URIs, email addresses) in return values.
- - C(ignore) will use the encoding returned by the backend.
- - C(idna) will convert all labels of domain names to IDNA encoding.
+ - V(ignore) will use the encoding returned by the backend.
+ - V(idna) will convert all labels of domain names to IDNA encoding.
IDNA2008 will be preferred, and IDNA2003 will be used if IDNA2008 encoding fails.
- - C(unicode) will convert all labels of domain names to Unicode.
+ - V(unicode) will convert all labels of domain names to Unicode.
IDNA2008 will be preferred, and IDNA2003 will be used if IDNA2008 decoding fails.
- - B(Note) that C(idna) and C(unicode) require the L(idna Python library,https://pypi.org/project/idna/) to be installed.
+ - B(Note) that V(idna) and V(unicode) require the L(idna Python library,https://pypi.org/project/idna/) to be installed.
type: str
default: ignore
choices:
@@ -27,5 +27,5 @@ options:
- idna
- unicode
requirements:
- - If I(name_encoding) is set to another value than C(ignore), the L(idna Python library,https://pypi.org/project/idna/) needs to be installed.
+ - If O(name_encoding) is set to another value than V(ignore), the L(idna Python library,https://pypi.org/project/idna/) needs to be installed.
'''
diff --git a/ansible_collections/community/crypto/plugins/filter/gpg_fingerprint.py b/ansible_collections/community/crypto/plugins/filter/gpg_fingerprint.py
new file mode 100644
index 000000000..bd9d21ecb
--- /dev/null
+++ b/ansible_collections/community/crypto/plugins/filter/gpg_fingerprint.py
@@ -0,0 +1,68 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2023, Felix Fontein <felix@fontein.de>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+DOCUMENTATION = """
+name: gpg_fingerprint
+short_description: Retrieve a GPG fingerprint from a GPG public or private key
+author: Felix Fontein (@felixfontein)
+version_added: 2.15.0
+description:
+ - "Takes the content of a private or public GPG key as input and returns its fingerprint."
+options:
+ _input:
+ description:
+ - The content of a GPG public or private key.
+ type: string
+ required: true
+requirements:
+ - GnuPG (C(gpg) executable)
+seealso:
+ - plugin: community.crypto.gpg_fingerprint
+ plugin_type: lookup
+"""
+
+EXAMPLES = """
+- name: Show fingerprint of GPG public key
+ ansible.builtin.debug:
+ msg: "{{ lookup('file', '/path/to/public_key.gpg') | community.crypto.gpg_fingerprint }}"
+"""
+
+RETURN = """
+ _value:
+ description:
+ - The fingerprint of the provided public or private GPG key.
+ type: string
+"""
+
+from ansible.errors import AnsibleFilterError
+from ansible.module_utils.common.text.converters import to_bytes, to_native
+from ansible.module_utils.six import string_types
+
+from ansible_collections.community.crypto.plugins.module_utils.gnupg.cli import GPGError, get_fingerprint_from_bytes
+from ansible_collections.community.crypto.plugins.plugin_utils.gnupg import PluginGPGRunner
+
+
+def gpg_fingerprint(input):
+ if not isinstance(input, string_types):
+ raise AnsibleFilterError(
+ 'The input for the community.crypto.gpg_fingerprint filter must be a string; got {type} instead'.format(type=type(input))
+ )
+ try:
+ gpg = PluginGPGRunner()
+ return get_fingerprint_from_bytes(gpg, to_bytes(input))
+ except GPGError as exc:
+ raise AnsibleFilterError(to_native(exc))
+
+
+class FilterModule(object):
+ '''Ansible jinja2 filters'''
+
+ def filters(self):
+ return {
+ 'gpg_fingerprint': gpg_fingerprint,
+ }
diff --git a/ansible_collections/community/crypto/plugins/filter/openssl_csr_info.py b/ansible_collections/community/crypto/plugins/filter/openssl_csr_info.py
index 851dfe2a4..c66f44b32 100644
--- a/ansible_collections/community/crypto/plugins/filter/openssl_csr_info.py
+++ b/ansible_collections/community/crypto/plugins/filter/openssl_csr_info.py
@@ -26,6 +26,8 @@ extends_documentation_fragment:
- community.crypto.name_encoding
seealso:
- module: community.crypto.openssl_csr_info
+ - plugin: community.crypto.to_serial
+ plugin_type: filter
'''
EXAMPLES = '''
@@ -49,11 +51,11 @@ _value:
signature_valid:
description:
- Whether the CSR's signature is valid.
- - In case the check returns C(false), the module will fail.
+ - In case the check returns V(false), the module will fail.
returned: success
type: bool
basic_constraints:
- description: Entries in the C(basic_constraints) extension, or C(none) if extension is not present.
+ description: Entries in the C(basic_constraints) extension, or V(none) if extension is not present.
returned: success
type: list
elements: str
@@ -63,7 +65,7 @@ _value:
returned: success
type: bool
extended_key_usage:
- description: Entries in the C(extended_key_usage) extension, or C(none) if extension is not present.
+ description: Entries in the C(extended_key_usage) extension, or V(none) if extension is not present.
returned: success
type: list
elements: str
@@ -94,7 +96,7 @@ _value:
sample: "MAMCAQU="
sample: {"1.3.6.1.5.5.7.1.24": { "critical": false, "value": "MAMCAQU="}}
key_usage:
- description: Entries in the C(key_usage) extension, or C(none) if extension is not present.
+ description: Entries in the C(key_usage) extension, or V(none) if extension is not present.
returned: success
type: str
sample: [Key Agreement, Data Encipherment]
@@ -104,8 +106,8 @@ _value:
type: bool
subject_alt_name:
description:
- - Entries in the C(subject_alt_name) extension, or C(none) if extension is not present.
- - See I(name_encoding) for how IDNs are handled.
+ - Entries in the C(subject_alt_name) extension, or V(none) if extension is not present.
+ - See O(name_encoding) for how IDNs are handled.
returned: success
type: list
elements: str
@@ -115,7 +117,7 @@ _value:
returned: success
type: bool
ocsp_must_staple:
- description: C(true) if the OCSP Must Staple extension is present, C(none) otherwise.
+ description: V(true) if the OCSP Must Staple extension is present, V(none) otherwise.
returned: success
type: bool
ocsp_must_staple_critical:
@@ -131,8 +133,8 @@ _value:
name_constraints_excluded:
description:
- List of excluded subtrees the CA cannot sign certificates for.
- - Is C(none) if extension is not present.
- - See I(name_encoding) for how IDNs are handled.
+ - Is V(none) if extension is not present.
+ - See O(name_encoding) for how IDNs are handled.
returned: success
type: list
elements: str
@@ -140,7 +142,7 @@ _value:
name_constraints_critical:
description:
- Whether the C(name_constraints) extension is critical.
- - Is C(none) if extension is not present.
+ - Is V(none) if extension is not present.
returned: success
type: bool
subject:
@@ -164,7 +166,7 @@ _value:
public_key_type:
description:
- The CSR's public key's type.
- - One of C(RSA), C(DSA), C(ECC), C(Ed25519), C(X25519), C(Ed448), or C(X448).
+ - One of V(RSA), V(DSA), V(ECC), V(Ed25519), V(X25519), V(Ed448), or V(X448).
- Will start with C(unknown) if the key type cannot be determined.
returned: success
type: str
@@ -179,57 +181,58 @@ _value:
description:
- Bit size of modulus (RSA) or prime number (DSA).
type: int
- returned: When C(public_key_type=RSA) or C(public_key_type=DSA)
+ returned: When RV(_value.public_key_type=RSA) or RV(_value.public_key_type=DSA)
modulus:
description:
- The RSA key's modulus.
type: int
- returned: When C(public_key_type=RSA)
+ returned: When RV(_value.public_key_type=RSA)
exponent:
description:
- The RSA key's public exponent.
type: int
- returned: When C(public_key_type=RSA)
+ returned: When RV(_value.public_key_type=RSA)
p:
description:
- The C(p) value for DSA.
- This is the prime modulus upon which arithmetic takes place.
type: int
- returned: When C(public_key_type=DSA)
+ returned: When RV(_value.public_key_type=DSA)
q:
description:
- The C(q) value for DSA.
- This is a prime that divides C(p - 1), and at the same time the order of the subgroup of the
multiplicative group of the prime field used.
type: int
- returned: When C(public_key_type=DSA)
+ returned: When RV(_value.public_key_type=DSA)
g:
description:
- The C(g) value for DSA.
- This is the element spanning the subgroup of the multiplicative group of the prime field used.
type: int
- returned: When C(public_key_type=DSA)
+ returned: When RV(_value.public_key_type=DSA)
curve:
description:
- The curve's name for ECC.
type: str
- returned: When C(public_key_type=ECC)
+ returned: When RV(_value.public_key_type=ECC)
exponent_size:
description:
- The maximum number of bits of a private key. This is basically the bit size of the subgroup used.
type: int
- returned: When C(public_key_type=ECC)
+ returned: When RV(_value.public_key_type=ECC)
x:
description:
- The C(x) coordinate for the public point on the elliptic curve.
type: int
- returned: When C(public_key_type=ECC)
+ returned: When RV(_value.public_key_type=ECC)
y:
description:
- - For C(public_key_type=ECC), this is the C(y) coordinate for the public point on the elliptic curve.
- - For C(public_key_type=DSA), this is the publicly known group element whose discrete logarithm w.r.t. C(g) is the private key.
+ - For RV(_value.public_key_type=ECC), this is the C(y) coordinate for the public point on the elliptic curve.
+ - For RV(_value.public_key_type=DSA), this is the publicly known group element whose discrete logarithm with
+ respect to C(g) is the private key.
type: int
- returned: When C(public_key_type=DSA) or C(public_key_type=ECC)
+ returned: When RV(_value.public_key_type=DSA) or RV(_value.public_key_type=ECC)
public_key_fingerprints:
description:
- Fingerprints of CSR's public key.
@@ -241,24 +244,24 @@ _value:
subject_key_identifier:
description:
- The CSR's subject key identifier.
- - The identifier is returned in hexadecimal, with C(:) used to separate bytes.
- - Is C(none) if the C(SubjectKeyIdentifier) extension is not present.
+ - The identifier is returned in hexadecimal, with V(:) used to separate bytes.
+ - Is V(none) if the C(SubjectKeyIdentifier) extension is not present.
returned: success
type: str
sample: '00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:00:11:22:33'
authority_key_identifier:
description:
- The CSR's authority key identifier.
- - The identifier is returned in hexadecimal, with C(:) used to separate bytes.
- - Is C(none) if the C(AuthorityKeyIdentifier) extension is not present.
+ - The identifier is returned in hexadecimal, with V(:) used to separate bytes.
+ - Is V(none) if the C(AuthorityKeyIdentifier) extension is not present.
returned: success
type: str
sample: '00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:00:11:22:33'
authority_cert_issuer:
description:
- The CSR's authority cert issuer as a list of general names.
- - Is C(none) if the C(AuthorityKeyIdentifier) extension is not present.
- - See I(name_encoding) for how IDNs are handled.
+ - Is V(none) if the C(AuthorityKeyIdentifier) extension is not present.
+ - See O(name_encoding) for how IDNs are handled.
returned: success
type: list
elements: str
@@ -266,7 +269,9 @@ _value:
authority_cert_serial_number:
description:
- The CSR's authority cert serial number.
- - Is C(none) if the C(AuthorityKeyIdentifier) extension is not present.
+ - Is V(none) if the C(AuthorityKeyIdentifier) extension is not present.
+ - This return value is an B(integer). If you need the serial numbers as a colon-separated hex string,
+ such as C(11:22:33), you need to convert it to that form with P(community.crypto.to_serial#filter).
returned: success
type: int
sample: 12345
diff --git a/ansible_collections/community/crypto/plugins/filter/openssl_privatekey_info.py b/ansible_collections/community/crypto/plugins/filter/openssl_privatekey_info.py
index 16dfd8597..5ad928e2b 100644
--- a/ansible_collections/community/crypto/plugins/filter/openssl_privatekey_info.py
+++ b/ansible_collections/community/crypto/plugins/filter/openssl_privatekey_info.py
@@ -29,7 +29,7 @@ options:
return_private_key_data:
description:
- Whether to return private key data.
- - Only set this to C(true) when you want private information about this key to
+ - Only set this to V(true) when you want private information about this key to
be extracted.
- "B(WARNING:) you have to make sure that private key data is not accidentally logged!"
type: bool
@@ -74,8 +74,8 @@ _value:
type:
description:
- The key's type.
- - One of C(RSA), C(DSA), C(ECC), C(Ed25519), C(X25519), C(Ed448), or C(X448).
- - Will start with C(unknown) if the key type cannot be determined.
+ - One of V(RSA), V(DSA), V(ECC), V(Ed25519), V(X25519), V(Ed448), or V(X448).
+ - Will start with V(unknown) if the key type cannot be determined.
returned: success
type: str
sample: RSA
@@ -89,61 +89,62 @@ _value:
description:
- Bit size of modulus (RSA) or prime number (DSA).
type: int
- returned: When C(type=RSA) or C(type=DSA)
+ returned: When RV(_value.type=RSA) or RV(_value.type=DSA)
modulus:
description:
- The RSA key's modulus.
type: int
- returned: When C(type=RSA)
+ returned: When RV(_value.type=RSA)
exponent:
description:
- The RSA key's public exponent.
type: int
- returned: When C(type=RSA)
+ returned: When RV(_value.type=RSA)
p:
description:
- The C(p) value for DSA.
- This is the prime modulus upon which arithmetic takes place.
type: int
- returned: When C(type=DSA)
+ returned: When RV(_value.type=DSA)
q:
description:
- The C(q) value for DSA.
- This is a prime that divides C(p - 1), and at the same time the order of the subgroup of the
multiplicative group of the prime field used.
type: int
- returned: When C(type=DSA)
+ returned: When RV(_value.type=DSA)
g:
description:
- The C(g) value for DSA.
- This is the element spanning the subgroup of the multiplicative group of the prime field used.
type: int
- returned: When C(type=DSA)
+ returned: When RV(_value.type=DSA)
curve:
description:
- The curve's name for ECC.
type: str
- returned: When C(type=ECC)
+ returned: When RV(_value.type=ECC)
exponent_size:
description:
- The maximum number of bits of a private key. This is basically the bit size of the subgroup used.
type: int
- returned: When C(type=ECC)
+ returned: When RV(_value.type=ECC)
x:
description:
- The C(x) coordinate for the public point on the elliptic curve.
type: int
- returned: When C(type=ECC)
+ returned: When RV(_value.type=ECC)
y:
description:
- - For C(type=ECC), this is the C(y) coordinate for the public point on the elliptic curve.
- - For C(type=DSA), this is the publicly known group element whose discrete logarithm w.r.t. C(g) is the private key.
+ - For RV(_value.type=ECC), this is the C(y) coordinate for the public point on the elliptic curve.
+ - For RV(_value.type=DSA), this is the publicly known group element whose discrete logarithm with
+ respect to C(g) is the private key.
type: int
- returned: When C(type=DSA) or C(type=ECC)
+ returned: When RV(_value.type=DSA) or RV(_value.type=ECC)
private_data:
description:
- Private key data. Depends on key type.
- returned: success and when I(return_private_key_data) is set to C(true)
+ returned: success and when O(return_private_key_data) is set to V(true)
type: dict
'''
diff --git a/ansible_collections/community/crypto/plugins/filter/openssl_publickey_info.py b/ansible_collections/community/crypto/plugins/filter/openssl_publickey_info.py
index f41af1c79..c9994e867 100644
--- a/ansible_collections/community/crypto/plugins/filter/openssl_publickey_info.py
+++ b/ansible_collections/community/crypto/plugins/filter/openssl_publickey_info.py
@@ -55,8 +55,8 @@ _value:
type:
description:
- The key's type.
- - One of C(RSA), C(DSA), C(ECC), C(Ed25519), C(X25519), C(Ed448), or C(X448).
- - Will start with C(unknown) if the key type cannot be determined.
+ - One of V(RSA), V(DSA), V(ECC), V(Ed25519), V(X25519), V(Ed448), or V(X448).
+ - Will start with V(unknown) if the key type cannot be determined.
returned: success
type: str
sample: RSA
@@ -70,57 +70,58 @@ _value:
description:
- Bit size of modulus (RSA) or prime number (DSA).
type: int
- returned: When C(type=RSA) or C(type=DSA)
+ returned: When RV(_value.type=RSA) or RV(_value.type=DSA)
modulus:
description:
- The RSA key's modulus.
type: int
- returned: When C(type=RSA)
+ returned: When RV(_value.type=RSA)
exponent:
description:
- The RSA key's public exponent.
type: int
- returned: When C(type=RSA)
+ returned: When RV(_value.type=RSA)
p:
description:
- The C(p) value for DSA.
- This is the prime modulus upon which arithmetic takes place.
type: int
- returned: When C(type=DSA)
+ returned: When RV(_value.type=DSA)
q:
description:
- The C(q) value for DSA.
- This is a prime that divides C(p - 1), and at the same time the order of the subgroup of the
multiplicative group of the prime field used.
type: int
- returned: When C(type=DSA)
+ returned: When RV(_value.type=DSA)
g:
description:
- The C(g) value for DSA.
- This is the element spanning the subgroup of the multiplicative group of the prime field used.
type: int
- returned: When C(type=DSA)
+ returned: When RV(_value.type=DSA)
curve:
description:
- The curve's name for ECC.
type: str
- returned: When C(type=ECC)
+ returned: When RV(_value.type=ECC)
exponent_size:
description:
- The maximum number of bits of a private key. This is basically the bit size of the subgroup used.
type: int
- returned: When C(type=ECC)
+ returned: When RV(_value.type=ECC)
x:
description:
- The C(x) coordinate for the public point on the elliptic curve.
type: int
- returned: When C(type=ECC)
+ returned: When RV(_value.type=ECC)
y:
description:
- - For C(type=ECC), this is the C(y) coordinate for the public point on the elliptic curve.
- - For C(type=DSA), this is the publicly known group element whose discrete logarithm w.r.t. C(g) is the private key.
+ - For RV(_value.type=ECC), this is the C(y) coordinate for the public point on the elliptic curve.
+ - For RV(_value.type=DSA), this is the publicly known group element whose discrete logarithm with
+ respect to C(g) is the private key.
type: int
- returned: When C(type=DSA) or C(type=ECC)
+ returned: When RV(_value.type=DSA) or RV(_value.type=ECC)
'''
from ansible.errors import AnsibleFilterError
diff --git a/ansible_collections/community/crypto/plugins/filter/parse_serial.py b/ansible_collections/community/crypto/plugins/filter/parse_serial.py
new file mode 100644
index 000000000..f78dc45d9
--- /dev/null
+++ b/ansible_collections/community/crypto/plugins/filter/parse_serial.py
@@ -0,0 +1,66 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2024, Felix Fontein <felix@fontein.de>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+DOCUMENTATION = """
+name: parse_serial
+short_description: Convert a serial number as a colon-separated list of hex numbers to an integer
+author: Felix Fontein (@felixfontein)
+version_added: 2.18.0
+description:
+ - "Parses a colon-separated list of hex numbers of the form C(00:11:22:33) and returns the corresponding integer."
+options:
+ _input:
+ description:
+ - A serial number represented as a colon-separated list of hex numbers between 0 and 255.
+ - These numbers are interpreted as the byte presentation of an unsigned integer in network byte order.
+ That is, C(01:00) is interpreted as the integer 256.
+ type: string
+ required: true
+seealso:
+ - plugin: community.crypto.to_serial
+ plugin_type: filter
+"""
+
+EXAMPLES = """
+- name: Parse serial number
+ ansible.builtin.debug:
+ msg: "{{ '11:22:33' | community.crypto.parse_serial }}"
+"""
+
+RETURN = """
+ _value:
+ description:
+ - The serial number as an integer.
+ type: int
+"""
+
+from ansible.errors import AnsibleFilterError
+from ansible.module_utils.common.text.converters import to_native
+from ansible.module_utils.six import string_types
+
+from ansible_collections.community.crypto.plugins.module_utils.serial import parse_serial
+
+
+def parse_serial_filter(input):
+ if not isinstance(input, string_types):
+ raise AnsibleFilterError(
+ 'The input for the community.crypto.parse_serial filter must be a string; got {type} instead'.format(type=type(input))
+ )
+ try:
+ return parse_serial(to_native(input))
+ except ValueError as exc:
+ raise AnsibleFilterError(to_native(exc))
+
+
+class FilterModule(object):
+ '''Ansible jinja2 filters'''
+
+ def filters(self):
+ return {
+ 'parse_serial': parse_serial_filter,
+ }
diff --git a/ansible_collections/community/crypto/plugins/filter/to_serial.py b/ansible_collections/community/crypto/plugins/filter/to_serial.py
new file mode 100644
index 000000000..78f337fdd
--- /dev/null
+++ b/ansible_collections/community/crypto/plugins/filter/to_serial.py
@@ -0,0 +1,68 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2024, Felix Fontein <felix@fontein.de>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+DOCUMENTATION = """
+name: to_serial
+short_description: Convert an integer to a colon-separated list of hex numbers
+author: Felix Fontein (@felixfontein)
+version_added: 2.18.0
+description:
+ - "Converts an integer to a colon-separated list of hex numbers of the form C(00:11:22:33)."
+options:
+ _input:
+ description:
+ - The non-negative integer to convert.
+ type: int
+ required: true
+seealso:
+ - plugin: community.crypto.to_serial
+ plugin_type: filter
+"""
+
+EXAMPLES = """
+- name: Convert integer to serial number
+ ansible.builtin.debug:
+ msg: "{{ 1234567 | community.crypto.to_serial }}"
+"""
+
+RETURN = """
+ _value:
+ description:
+ - A colon-separated list of hexadecimal numbers.
+ - Letters are upper-case, and all numbers have exactly two digits.
+ - The string is never empty. The representation of C(0) is C("00").
+ type: string
+"""
+
+from ansible.errors import AnsibleFilterError
+from ansible.module_utils.common.text.converters import to_native
+from ansible.module_utils.six import integer_types
+
+from ansible_collections.community.crypto.plugins.module_utils.serial import to_serial
+
+
+def to_serial_filter(input):
+ if not isinstance(input, integer_types):
+ raise AnsibleFilterError(
+ 'The input for the community.crypto.to_serial filter must be an integer; got {type} instead'.format(type=type(input))
+ )
+ if input < 0:
+ raise AnsibleFilterError('The input for the community.crypto.to_serial filter must not be negative')
+ try:
+ return to_serial(input)
+ except ValueError as exc:
+ raise AnsibleFilterError(to_native(exc))
+
+
+class FilterModule(object):
+ '''Ansible jinja2 filters'''
+
+ def filters(self):
+ return {
+ 'to_serial': to_serial_filter,
+ }
diff --git a/ansible_collections/community/crypto/plugins/filter/x509_certificate_info.py b/ansible_collections/community/crypto/plugins/filter/x509_certificate_info.py
index 21aee98a9..7a18c2c0b 100644
--- a/ansible_collections/community/crypto/plugins/filter/x509_certificate_info.py
+++ b/ansible_collections/community/crypto/plugins/filter/x509_certificate_info.py
@@ -26,6 +26,8 @@ extends_documentation_fragment:
- community.crypto.name_encoding
seealso:
- module: community.crypto.x509_certificate_info
+ - plugin: community.crypto.to_serial
+ plugin_type: filter
'''
EXAMPLES = '''
@@ -51,7 +53,7 @@ _value:
returned: success
type: bool
basic_constraints:
- description: Entries in the C(basic_constraints) extension, or C(none) if extension is not present.
+ description: Entries in the C(basic_constraints) extension, or V(none) if extension is not present.
returned: success
type: list
elements: str
@@ -61,7 +63,7 @@ _value:
returned: success
type: bool
extended_key_usage:
- description: Entries in the C(extended_key_usage) extension, or C(none) if extension is not present.
+ description: Entries in the C(extended_key_usage) extension, or V(none) if extension is not present.
returned: success
type: list
elements: str
@@ -92,7 +94,7 @@ _value:
sample: "MAMCAQU="
sample: {"1.3.6.1.5.5.7.1.24": { "critical": false, "value": "MAMCAQU="}}
key_usage:
- description: Entries in the C(key_usage) extension, or C(none) if extension is not present.
+ description: Entries in the C(key_usage) extension, or V(none) if extension is not present.
returned: success
type: str
sample: [Key Agreement, Data Encipherment]
@@ -102,8 +104,8 @@ _value:
type: bool
subject_alt_name:
description:
- - Entries in the C(subject_alt_name) extension, or C(none) if extension is not present.
- - See I(name_encoding) for how IDNs are handled.
+ - Entries in the C(subject_alt_name) extension, or V(none) if extension is not present.
+ - See O(name_encoding) for how IDNs are handled.
returned: success
type: list
elements: str
@@ -113,7 +115,7 @@ _value:
returned: success
type: bool
ocsp_must_staple:
- description: C(true) if the OCSP Must Staple extension is present, C(none) otherwise.
+ description: V(true) if the OCSP Must Staple extension is present, V(none) otherwise.
returned: success
type: bool
ocsp_must_staple_critical:
@@ -164,8 +166,8 @@ _value:
public_key_type:
description:
- The certificate's public key's type.
- - One of C(RSA), C(DSA), C(ECC), C(Ed25519), C(X25519), C(Ed448), or C(X448).
- - Will start with C(unknown) if the key type cannot be determined.
+ - One of V(RSA), V(DSA), V(ECC), V(Ed25519), V(X25519), V(Ed448), or V(X448).
+ - Will start with V(unknown) if the key type cannot be determined.
returned: success
type: str
sample: RSA
@@ -179,57 +181,58 @@ _value:
description:
- Bit size of modulus (RSA) or prime number (DSA).
type: int
- returned: When C(public_key_type=RSA) or C(public_key_type=DSA)
+ returned: When RV(_value.public_key_type=RSA) or RV(_value.public_key_type=DSA)
modulus:
description:
- The RSA key's modulus.
type: int
- returned: When C(public_key_type=RSA)
+ returned: When RV(_value.public_key_type=RSA)
exponent:
description:
- The RSA key's public exponent.
type: int
- returned: When C(public_key_type=RSA)
+ returned: When RV(_value.public_key_type=RSA)
p:
description:
- The C(p) value for DSA.
- This is the prime modulus upon which arithmetic takes place.
type: int
- returned: When C(public_key_type=DSA)
+ returned: When RV(_value.public_key_type=DSA)
q:
description:
- The C(q) value for DSA.
- This is a prime that divides C(p - 1), and at the same time the order of the subgroup of the
multiplicative group of the prime field used.
type: int
- returned: When C(public_key_type=DSA)
+ returned: When RV(_value.public_key_type=DSA)
g:
description:
- The C(g) value for DSA.
- This is the element spanning the subgroup of the multiplicative group of the prime field used.
type: int
- returned: When C(public_key_type=DSA)
+ returned: When RV(_value.public_key_type=DSA)
curve:
description:
- The curve's name for ECC.
type: str
- returned: When C(public_key_type=ECC)
+ returned: When RV(_value.public_key_type=ECC)
exponent_size:
description:
- The maximum number of bits of a private key. This is basically the bit size of the subgroup used.
type: int
- returned: When C(public_key_type=ECC)
+ returned: When RV(_value.public_key_type=ECC)
x:
description:
- The C(x) coordinate for the public point on the elliptic curve.
type: int
- returned: When C(public_key_type=ECC)
+ returned: When RV(_value.public_key_type=ECC)
y:
description:
- - For C(public_key_type=ECC), this is the C(y) coordinate for the public point on the elliptic curve.
- - For C(public_key_type=DSA), this is the publicly known group element whose discrete logarithm w.r.t. C(g) is the private key.
+ - For RV(_value.public_key_type=ECC), this is the C(y) coordinate for the public point on the elliptic curve.
+ - For RV(_value.public_key_type=DSA), this is the publicly known group element whose discrete logarithm with
+ respect to C(g) is the private key.
type: int
- returned: When C(public_key_type=DSA) or C(public_key_type=ECC)
+ returned: When RV(_value.public_key_type=DSA) or RV(_value.public_key_type=ECC)
public_key_fingerprints:
description:
- Fingerprints of certificate's public key.
@@ -252,7 +255,10 @@ _value:
type: str
sample: sha256WithRSAEncryption
serial_number:
- description: The certificate's serial number.
+ description:
+ - The certificate's serial number.
+ - This return value is an B(integer). If you need the serial numbers as a colon-separated hex string,
+ such as C(11:22:33), you need to convert it to that form with P(community.crypto.to_serial#filter).
returned: success
type: int
sample: 1234
@@ -264,24 +270,24 @@ _value:
subject_key_identifier:
description:
- The certificate's subject key identifier.
- - The identifier is returned in hexadecimal, with C(:) used to separate bytes.
- - Is C(none) if the C(SubjectKeyIdentifier) extension is not present.
+ - The identifier is returned in hexadecimal, with V(:) used to separate bytes.
+ - Is V(none) if the C(SubjectKeyIdentifier) extension is not present.
returned: success
type: str
sample: '00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:00:11:22:33'
authority_key_identifier:
description:
- The certificate's authority key identifier.
- - The identifier is returned in hexadecimal, with C(:) used to separate bytes.
- - Is C(none) if the C(AuthorityKeyIdentifier) extension is not present.
+ - The identifier is returned in hexadecimal, with V(:) used to separate bytes.
+ - Is V(none) if the C(AuthorityKeyIdentifier) extension is not present.
returned: success
type: str
sample: '00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:00:11:22:33'
authority_cert_issuer:
description:
- The certificate's authority cert issuer as a list of general names.
- - Is C(none) if the C(AuthorityKeyIdentifier) extension is not present.
- - See I(name_encoding) for how IDNs are handled.
+ - Is V(none) if the C(AuthorityKeyIdentifier) extension is not present.
+ - See O(name_encoding) for how IDNs are handled.
returned: success
type: list
elements: str
@@ -289,18 +295,20 @@ _value:
authority_cert_serial_number:
description:
- The certificate's authority cert serial number.
- - Is C(none) if the C(AuthorityKeyIdentifier) extension is not present.
+ - Is V(none) if the C(AuthorityKeyIdentifier) extension is not present.
+ - This return value is an B(integer). If you need the serial numbers as a colon-separated hex string,
+ such as C(11:22:33), you need to convert it to that form with P(community.crypto.to_serial#filter).
returned: success
type: int
sample: 12345
ocsp_uri:
description: The OCSP responder URI, if included in the certificate. Will be
- C(none) if no OCSP responder URI is included.
+ V(none) if no OCSP responder URI is included.
returned: success
type: str
issuer_uri:
description: The Issuer URI, if included in the certificate. Will be
- C(none) if no issuer URI is included.
+ V(none) if no issuer URI is included.
returned: success
type: str
'''
diff --git a/ansible_collections/community/crypto/plugins/filter/x509_crl_info.py b/ansible_collections/community/crypto/plugins/filter/x509_crl_info.py
index 11f61fd8a..db1dc5369 100644
--- a/ansible_collections/community/crypto/plugins/filter/x509_crl_info.py
+++ b/ansible_collections/community/crypto/plugins/filter/x509_crl_info.py
@@ -24,7 +24,7 @@ options:
required: true
list_revoked_certificates:
description:
- - If set to C(false), the list of revoked certificates is not included in the result.
+ - If set to V(false), the list of revoked certificates is not included in the result.
- This is useful when retrieving information on large CRL files. Enumerating all revoked
certificates can take some time, including serializing the result as JSON, sending it to
the Ansible controller, and decoding it again.
@@ -35,6 +35,8 @@ extends_documentation_fragment:
- community.crypto.name_encoding
seealso:
- module: community.crypto.x509_crl_info
+ - plugin: community.crypto.to_serial
+ plugin_type: filter
'''
EXAMPLES = '''
@@ -57,15 +59,18 @@ _value:
contains:
format:
description:
- - Whether the CRL is in PEM format (C(pem)) or in DER format (C(der)).
+ - Whether the CRL is in PEM format (V(pem)) or in DER format (V(der)).
returned: success
type: str
sample: pem
+ choices:
+ - pem
+ - der
issuer:
description:
- The CRL's issuer.
- Note that for repeated values, only the last one will be returned.
- - See I(name_encoding) for how IDNs are handled.
+ - See O(name_encoding) for how IDNs are handled.
returned: success
type: dict
sample: {"organizationName": "Ansible", "commonName": "ca.example.com"}
@@ -92,12 +97,15 @@ _value:
sample: sha256WithRSAEncryption
revoked_certificates:
description: List of certificates to be revoked.
- returned: success if I(list_revoked_certificates=true)
+ returned: success if O(list_revoked_certificates=true)
type: list
elements: dict
contains:
serial_number:
- description: Serial number of the certificate.
+ description:
+ - Serial number of the certificate.
+ - This return value is an B(integer). If you need the serial numbers as a colon-separated hex string,
+ such as C(11:22:33), you need to convert it to that form with P(community.crypto.to_serial#filter).
type: int
sample: 1234
revocation_date:
@@ -107,7 +115,7 @@ _value:
issuer:
description:
- The certificate's issuer.
- - See I(name_encoding) for how IDNs are handled.
+ - See O(name_encoding) for how IDNs are handled.
type: list
elements: str
sample: ["DNS:ca.example.org"]
@@ -118,11 +126,19 @@ _value:
reason:
description:
- The value for the revocation reason extension.
- - One of C(unspecified), C(key_compromise), C(ca_compromise), C(affiliation_changed), C(superseded),
- C(cessation_of_operation), C(certificate_hold), C(privilege_withdrawn), C(aa_compromise), and
- C(remove_from_crl).
type: str
sample: key_compromise
+ choices:
+ - unspecified
+ - key_compromise
+ - ca_compromise
+ - affiliation_changed
+ - superseded
+ - cessation_of_operation
+ - certificate_hold
+ - privilege_withdrawn
+ - aa_compromise
+ - remove_from_crl
reason_critical:
description: Whether the revocation reason extension is critical.
type: bool
diff --git a/ansible_collections/community/crypto/plugins/lookup/gpg_fingerprint.py b/ansible_collections/community/crypto/plugins/lookup/gpg_fingerprint.py
new file mode 100644
index 000000000..c562faed8
--- /dev/null
+++ b/ansible_collections/community/crypto/plugins/lookup/gpg_fingerprint.py
@@ -0,0 +1,64 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2023, Felix Fontein <felix@fontein.de>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+DOCUMENTATION = """
+name: gpg_fingerprint
+short_description: Retrieve a GPG fingerprint from a GPG public or private key file
+author: Felix Fontein (@felixfontein)
+version_added: 2.15.0
+description:
+ - "Takes a list of filenames pointing to GPG public or private key files. Returns the fingerprints for each of these keys."
+options:
+ _terms:
+ description:
+ - A path to a GPG public or private key.
+ type: list
+ elements: path
+ required: true
+requirements:
+ - GnuPG (C(gpg) executable)
+seealso:
+ - plugin: community.crypto.gpg_fingerprint
+ plugin_type: filter
+"""
+
+EXAMPLES = """
+- name: Show fingerprint of GPG public key
+ ansible.builtin.debug:
+ msg: "{{ lookup('community.crypto.gpg_fingerprint', '/path/to/public_key.gpg') }}"
+"""
+
+RETURN = """
+ _value:
+ description:
+ - The fingerprints of the provided public or private GPG keys.
+ - The list has one entry for every path provided.
+ type: list
+ elements: string
+"""
+
+from ansible.plugins.lookup import LookupBase
+from ansible.errors import AnsibleLookupError
+from ansible.module_utils.common.text.converters import to_native
+
+from ansible_collections.community.crypto.plugins.module_utils.gnupg.cli import GPGError, get_fingerprint_from_file
+from ansible_collections.community.crypto.plugins.plugin_utils.gnupg import PluginGPGRunner
+
+
+class LookupModule(LookupBase):
+ def run(self, terms, variables=None, **kwargs):
+ self.set_options(direct=kwargs)
+
+ try:
+ gpg = PluginGPGRunner(cwd=self._loader.get_basedir())
+ result = []
+ for path in terms:
+ result.append(get_fingerprint_from_file(gpg, path))
+ return result
+ except GPGError as exc:
+ raise AnsibleLookupError(to_native(exc))
diff --git a/ansible_collections/community/crypto/plugins/module_utils/acme/account.py b/ansible_collections/community/crypto/plugins/module_utils/acme/account.py
index de5eb171d..0ad58e920 100644
--- a/ansible_collections/community/crypto/plugins/module_utils/acme/account.py
+++ b/ansible_collections/community/crypto/plugins/module_utils/acme/account.py
@@ -9,6 +9,8 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type
+from ansible.module_utils.common._collections_compat import Mapping
+
from ansible_collections.community.crypto.plugins.module_utils.acme.errors import (
ACMEProtocolException,
ModuleFailException,
@@ -96,6 +98,9 @@ class ACMEAccount(object):
)
result, info = self.client.send_signed_request(url, new_reg, fail_on_error=False)
+ if not isinstance(result, Mapping):
+ raise ACMEProtocolException(
+ self.client.module, msg='Invalid account creation reply from ACME server', info=info, content=result)
if info['status'] in ([200, 201] if self.client.version == 1 else [201]):
# Account did not exist
@@ -118,8 +123,10 @@ class ACMEAccount(object):
if 'location' in info:
self.client.set_account_uri(info['location'])
return False, result
- elif info['status'] == 400 and result['type'] == 'urn:ietf:params:acme:error:accountDoesNotExist' and not allow_creation:
+ elif info['status'] in (400, 404) and result['type'] == 'urn:ietf:params:acme:error:accountDoesNotExist' and not allow_creation:
# Account does not exist (and we did not try to create it)
+ # (According to RFC 8555, Section 7.3.1, the HTTP status code MUST be 400.
+ # Unfortunately Digicert does not care and sends 404 instead.)
return False, None
elif info['status'] == 403 and result['type'] == 'urn:ietf:params:acme:error:unauthorized' and 'deactivated' in (result.get('detail') or ''):
# Account has been deactivated; currently works for Pebble; has not been
@@ -154,6 +161,9 @@ class ACMEAccount(object):
# retry as a regular POST (with no changed data) for pre-draft-15 ACME servers
data = {}
result, info = self.client.send_signed_request(self.client.account_uri, data, fail_on_error=False)
+ if not isinstance(result, Mapping):
+ raise ACMEProtocolException(
+ self.client.module, msg='Invalid account data retrieved from ACME server', info=info, content=result)
if info['status'] in (400, 403) and result.get('type') == 'urn:ietf:params:acme:error:unauthorized':
# Returned when account is deactivated
return None
@@ -248,5 +258,9 @@ class ACMEAccount(object):
else:
if self.client.version == 1:
update_request['resource'] = 'reg'
- account_data, dummy = self.client.send_signed_request(self.client.account_uri, update_request)
+ account_data, info = self.client.send_signed_request(self.client.account_uri, update_request)
+ if not isinstance(account_data, Mapping):
+ raise ACMEProtocolException(
+ self.client.module, msg='Invalid account updating reply from ACME server', info=info, content=account_data)
+
return True, account_data
diff --git a/ansible_collections/community/crypto/plugins/module_utils/acme/acme.py b/ansible_collections/community/crypto/plugins/module_utils/acme/acme.py
index c054a52f6..74d0bc1ea 100644
--- a/ansible_collections/community/crypto/plugins/module_utils/acme/acme.py
+++ b/ansible_collections/community/crypto/plugins/module_utils/acme/acme.py
@@ -55,15 +55,19 @@ else:
IPADDRESS_IMPORT_ERROR = None
-RETRY_STATUS_CODES = (408, 429, 503)
+# -1 usually means connection problems
+RETRY_STATUS_CODES = (-1, 408, 429, 503)
+
+RETRY_COUNT = 10
def _decode_retry(module, response, info, retry_count):
if info['status'] not in RETRY_STATUS_CODES:
return False
- if retry_count >= 5:
- raise ACMEProtocolException(module, msg='Giving up after 5 retries', info=info, response=response)
+ if retry_count >= RETRY_COUNT:
+ raise ACMEProtocolException(
+ module, msg='Giving up after {retry} retries'.format(retry=RETRY_COUNT), info=info, response=response)
# 429 and 503 should have a Retry-After header (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After)
try:
diff --git a/ansible_collections/community/crypto/plugins/module_utils/acme/backend_cryptography.py b/ansible_collections/community/crypto/plugins/module_utils/acme/backend_cryptography.py
index 207f743f1..2e388980a 100644
--- a/ansible_collections/community/crypto/plugins/module_utils/acme/backend_cryptography.py
+++ b/ansible_collections/community/crypto/plugins/module_utils/acme/backend_cryptography.py
@@ -13,7 +13,6 @@ import base64
import binascii
import datetime
import os
-import sys
import traceback
from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text
@@ -37,6 +36,11 @@ from ansible_collections.community.crypto.plugins.module_utils.acme.io import re
from ansible_collections.community.crypto.plugins.module_utils.acme.utils import nopad_b64
+from ansible_collections.community.crypto.plugins.module_utils.crypto.math import (
+ convert_int_to_bytes,
+ convert_int_to_hex,
+)
+
from ansible_collections.community.crypto.plugins.module_utils.crypto.support import (
parse_name_field,
)
@@ -78,40 +82,6 @@ else:
CRYPTOGRAPHY_ERROR = traceback.format_exc()
-if sys.version_info[0] >= 3:
- # Python 3 (and newer)
- def _count_bytes(n):
- return (n.bit_length() + 7) // 8 if n > 0 else 0
-
- def _convert_int_to_bytes(count, no):
- return no.to_bytes(count, byteorder='big')
-
- def _pad_hex(n, digits):
- res = hex(n)[2:]
- if len(res) < digits:
- res = '0' * (digits - len(res)) + res
- return res
-else:
- # Python 2
- def _count_bytes(n):
- if n <= 0:
- return 0
- h = '%x' % n
- return (len(h) + 1) // 2
-
- def _convert_int_to_bytes(count, n):
- h = '%x' % n
- if len(h) > 2 * count:
- raise Exception('Number {1} needs more than {0} bytes!'.format(count, n))
- return ('0' * (2 * count - len(h)) + h).decode('hex')
-
- def _pad_hex(n, digits):
- h = '%x' % n
- if len(h) < digits:
- h = '0' * (digits - len(h)) + h
- return h
-
-
class CryptographyChainMatcher(ChainMatcher):
@staticmethod
def _parse_key_identifier(key_identifier, name, criterium_idx, module):
@@ -223,8 +193,8 @@ class CryptographyBackend(CryptoBackend):
'alg': 'RS256',
'jwk': {
"kty": "RSA",
- "e": nopad_b64(_convert_int_to_bytes(_count_bytes(pk.e), pk.e)),
- "n": nopad_b64(_convert_int_to_bytes(_count_bytes(pk.n), pk.n)),
+ "e": nopad_b64(convert_int_to_bytes(pk.e)),
+ "n": nopad_b64(convert_int_to_bytes(pk.n)),
},
'hash': 'sha256',
}
@@ -260,8 +230,8 @@ class CryptographyBackend(CryptoBackend):
'jwk': {
"kty": "EC",
"crv": curve,
- "x": nopad_b64(_convert_int_to_bytes(num_bytes, pk.x)),
- "y": nopad_b64(_convert_int_to_bytes(num_bytes, pk.y)),
+ "x": nopad_b64(convert_int_to_bytes(pk.x, count=num_bytes)),
+ "y": nopad_b64(convert_int_to_bytes(pk.y, count=num_bytes)),
},
'hash': hashalg,
'point_size': point_size,
@@ -288,8 +258,8 @@ class CryptographyBackend(CryptoBackend):
hashalg = cryptography.hazmat.primitives.hashes.SHA512
ecdsa = cryptography.hazmat.primitives.asymmetric.ec.ECDSA(hashalg())
r, s = cryptography.hazmat.primitives.asymmetric.utils.decode_dss_signature(key_data['key_obj'].sign(sign_payload, ecdsa))
- rr = _pad_hex(r, 2 * key_data['point_size'])
- ss = _pad_hex(s, 2 * key_data['point_size'])
+ rr = convert_int_to_hex(r, 2 * key_data['point_size'])
+ ss = convert_int_to_hex(s, 2 * key_data['point_size'])
signature = binascii.unhexlify(rr) + binascii.unhexlify(ss)
return {
diff --git a/ansible_collections/community/crypto/plugins/module_utils/acme/errors.py b/ansible_collections/community/crypto/plugins/module_utils/acme/errors.py
index 208a1ae4f..c29831be2 100644
--- a/ansible_collections/community/crypto/plugins/module_utils/acme/errors.py
+++ b/ansible_collections/community/crypto/plugins/module_utils/acme/errors.py
@@ -21,13 +21,14 @@ def format_http_status(status_code):
def format_error_problem(problem, subproblem_prefix=''):
+ error_type = problem.get('type', 'about:blank') # https://www.rfc-editor.org/rfc/rfc7807#section-3.1
if 'title' in problem:
msg = 'Error "{title}" ({type})'.format(
- type=problem['type'],
+ type=error_type,
title=problem['title'],
)
else:
- msg = 'Error {type}'.format(type=problem['type'])
+ msg = 'Error {type}'.format(type=error_type)
if 'detail' in problem:
msg += ': "{detail}"'.format(detail=problem['detail'])
subproblems = problem.get('subproblems')
@@ -95,10 +96,12 @@ class ACMEProtocolException(ModuleFailException):
extras['http_status'] = code
if code is not None and code >= 400 and content_json is not None and 'type' in content_json:
if 'status' in content_json and content_json['status'] != code:
- code = 'status {problem_code} (HTTP status: {http_code})'.format(
+ code_msg = 'status {problem_code} (HTTP status: {http_code})'.format(
http_code=format_http_status(code), problem_code=content_json['status'])
else:
- code = 'status {problem_code}'.format(problem_code=format_http_status(code))
+ code_msg = 'status {problem_code}'.format(problem_code=format_http_status(code))
+ if code == -1 and info.get('msg'):
+ code_msg = 'error: {msg}'.format(msg=info['msg'])
subproblems = content_json.pop('subproblems', None)
add_msg = ' {problem}.'.format(problem=format_error_problem(content_json))
extras['problem'] = content_json
@@ -112,12 +115,14 @@ class ACMEProtocolException(ModuleFailException):
problem=format_error_problem(problem, subproblem_prefix='{0}.'.format(index)),
)
else:
- code = 'HTTP status {code}'.format(code=format_http_status(code))
+ code_msg = 'HTTP status {code}'.format(code=format_http_status(code))
+ if code == -1 and info.get('msg'):
+ code_msg = 'error: {msg}'.format(msg=info['msg'])
if content_json is not None:
add_msg = ' The JSON error result: {content}'.format(content=content_json)
elif content is not None:
add_msg = ' The raw error result: {content}'.format(content=to_text(content))
- msg = '{msg} for {url} with {code}'.format(msg=msg, url=url, code=format_http_status(code))
+ msg = '{msg} for {url} with {code}'.format(msg=msg, url=url, code=code_msg)
elif content_json is not None:
add_msg = ' The JSON result: {content}'.format(content=content_json)
elif content is not None:
diff --git a/ansible_collections/community/crypto/plugins/module_utils/crypto/cryptography_support.py b/ansible_collections/community/crypto/plugins/module_utils/crypto/cryptography_support.py
index fde691997..b767d3417 100644
--- a/ansible_collections/community/crypto/plugins/module_utils/crypto/cryptography_support.py
+++ b/ansible_collections/community/crypto/plugins/module_utils/crypto/cryptography_support.py
@@ -114,7 +114,7 @@ def cryptography_get_extensions_from_cert(cert):
try:
# Since cryptography will not give us the DER value for an extension
# (that is only stored for unrecognized extensions), we have to re-do
- # the extension parsing outselves.
+ # the extension parsing ourselves.
backend = default_backend()
try:
# For certain old versions of cryptography, backend is a MultiBackend object,
@@ -166,7 +166,7 @@ def cryptography_get_extensions_from_csr(csr):
try:
# Since cryptography will not give us the DER value for an extension
# (that is only stored for unrecognized extensions), we have to re-do
- # the extension parsing outselves.
+ # the extension parsing ourselves.
backend = default_backend()
try:
# For certain old versions of cryptography, backend is a MultiBackend object,
diff --git a/ansible_collections/community/crypto/plugins/module_utils/crypto/math.py b/ansible_collections/community/crypto/plugins/module_utils/crypto/math.py
index 1cfe38b99..f56f22d33 100644
--- a/ansible_collections/community/crypto/plugins/module_utils/crypto/math.py
+++ b/ansible_collections/community/crypto/plugins/module_utils/crypto/math.py
@@ -54,17 +54,93 @@ def quick_is_not_prime(n):
python_version = (sys.version_info[0], sys.version_info[1])
if python_version >= (2, 7) or python_version >= (3, 1):
# Ansible still supports Python 2.6 on remote nodes
+
+ def count_bytes(no):
+ """
+ Given an integer, compute the number of bytes necessary to store its absolute value.
+ """
+ no = abs(no)
+ if no == 0:
+ return 0
+ return (no.bit_length() + 7) // 8
+
def count_bits(no):
+ """
+ Given an integer, compute the number of bits necessary to store its absolute value.
+ """
no = abs(no)
if no == 0:
return 0
return no.bit_length()
else:
# Slow, but works
+ def count_bytes(no):
+ """
+ Given an integer, compute the number of bytes necessary to store its absolute value.
+ """
+ no = abs(no)
+ count = 0
+ while no > 0:
+ no >>= 8
+ count += 1
+ return count
+
def count_bits(no):
+ """
+ Given an integer, compute the number of bits necessary to store its absolute value.
+ """
no = abs(no)
count = 0
while no > 0:
no >>= 1
count += 1
return count
+
+if sys.version_info[0] >= 3:
+ # Python 3 (and newer)
+ def _convert_int_to_bytes(count, no):
+ return no.to_bytes(count, byteorder='big')
+
+ def _to_hex(no):
+ return hex(no)[2:]
+else:
+ # Python 2
+ def _convert_int_to_bytes(count, n):
+ h = '%x' % n
+ if len(h) > 2 * count:
+ raise Exception('Number {1} needs more than {0} bytes!'.format(count, n))
+ return ('0' * (2 * count - len(h)) + h).decode('hex')
+
+ def _to_hex(no):
+ return '%x' % no
+
+
+def convert_int_to_bytes(no, count=None):
+ """
+ Convert the absolute value of an integer to a byte string in network byte order.
+
+ If ``count`` is provided, it must be sufficiently large so that the integer's
+ absolute value can be represented with these number of bytes. The resulting byte
+ string will have length exactly ``count``.
+
+ The value zero will be converted to an empty byte string if ``count`` is provided.
+ """
+ no = abs(no)
+ if count is None:
+ count = count_bytes(no)
+ return _convert_int_to_bytes(count, no)
+
+
+def convert_int_to_hex(no, digits=None):
+ """
+ Convert the absolute value of an integer to a string of hexadecimal digits.
+
+ If ``digits`` is provided, the string will be padded on the left with ``0``s so
+ that the returned value has length ``digits``. If ``digits`` is not sufficient,
+ the string will be longer.
+ """
+ no = abs(no)
+ value = _to_hex(no)
+ if digits is not None and len(value) < digits:
+ value = '0' * (digits - len(value)) + value
+ return value
diff --git a/ansible_collections/community/crypto/plugins/module_utils/crypto/module_backends/privatekey_convert.py b/ansible_collections/community/crypto/plugins/module_utils/crypto/module_backends/privatekey_convert.py
index 905ca70fe..fdcc901e0 100644
--- a/ansible_collections/community/crypto/plugins/module_utils/crypto/module_backends/privatekey_convert.py
+++ b/ansible_collections/community/crypto/plugins/module_utils/crypto/module_backends/privatekey_convert.py
@@ -106,7 +106,7 @@ class PrivateKeyConvertBackend:
@abc.abstractmethod
def _load_private_key(self, data, passphrase, current_hint=None):
- """Check whether data cna be loaded as a private key with the provided passphrase. Return tuple (type, private_key)."""
+ """Check whether data can be loaded as a private key with the provided passphrase. Return tuple (type, private_key)."""
pass
def needs_conversion(self):
diff --git a/ansible_collections/community/crypto/plugins/module_utils/crypto/module_backends/privatekey_info.py b/ansible_collections/community/crypto/plugins/module_utils/crypto/module_backends/privatekey_info.py
index d87b9c2be..f44caaa78 100644
--- a/ansible_collections/community/crypto/plugins/module_utils/crypto/module_backends/privatekey_info.py
+++ b/ansible_collections/community/crypto/plugins/module_utils/crypto/module_backends/privatekey_info.py
@@ -105,9 +105,12 @@ def _check_dsa_consistency(key_public_data, key_private_data):
return True
-def _is_cryptography_key_consistent(key, key_public_data, key_private_data):
+def _is_cryptography_key_consistent(key, key_public_data, key_private_data, warn_func=None):
if isinstance(key, cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey):
- return bool(key._backend._lib.RSA_check_key(key._rsa_cdata))
+ # key._backend was removed in cryptography 42.0.0
+ backend = getattr(key, '_backend', None)
+ if backend is not None:
+ return bool(backend._lib.RSA_check_key(key._rsa_cdata))
if isinstance(key, cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey):
result = _check_dsa_consistency(key_public_data, key_private_data)
if result is not None:
@@ -157,6 +160,8 @@ def _is_cryptography_key_consistent(key, key_public_data, key_private_data):
except cryptography.exceptions.InvalidSignature:
return False
# For X25519 and X448, there's no test yet.
+ if warn_func is not None:
+ warn_func('Cannot determine consistency for key of type %s' % type(key))
return None
@@ -253,7 +258,7 @@ class PrivateKeyInfoRetrievalCryptography(PrivateKeyInfoRetrieval):
return _get_cryptography_private_key_info(self.key, need_private_key_data=need_private_key_data)
def _is_key_consistent(self, key_public_data, key_private_data):
- return _is_cryptography_key_consistent(self.key, key_public_data, key_private_data)
+ return _is_cryptography_key_consistent(self.key, key_public_data, key_private_data, warn_func=self.module.warn)
def get_privatekey_info(module, backend, content, passphrase=None, return_private_key_data=False, prefer_one_fingerprint=False):
diff --git a/ansible_collections/community/crypto/plugins/module_utils/crypto/pem.py b/ansible_collections/community/crypto/plugins/module_utils/crypto/pem.py
index 4dc9745fe..da46548c7 100644
--- a/ansible_collections/community/crypto/plugins/module_utils/crypto/pem.py
+++ b/ansible_collections/community/crypto/plugins/module_utils/crypto/pem.py
@@ -14,10 +14,13 @@ PKCS8_PRIVATEKEY_NAMES = ('PRIVATE KEY', 'ENCRYPTED PRIVATE KEY')
PKCS1_PRIVATEKEY_SUFFIX = ' PRIVATE KEY'
-def identify_pem_format(content):
+def identify_pem_format(content, encoding='utf-8'):
'''Given the contents of a binary file, tests whether this could be a PEM file.'''
try:
- lines = content.decode('utf-8').splitlines(False)
+ first_pem = extract_first_pem(content.decode(encoding))
+ if first_pem is None:
+ return False
+ lines = first_pem.splitlines(False)
if lines[0].startswith(PEM_START) and lines[0].endswith(PEM_END) and len(lines[0]) > len(PEM_START) + len(PEM_END):
return True
except UnicodeDecodeError:
@@ -25,14 +28,17 @@ def identify_pem_format(content):
return False
-def identify_private_key_format(content):
+def identify_private_key_format(content, encoding='utf-8'):
'''Given the contents of a private key file, identifies its format.'''
# See https://github.com/openssl/openssl/blob/master/crypto/pem/pem_pkey.c#L40-L85
# (PEM_read_bio_PrivateKey)
# and https://github.com/openssl/openssl/blob/master/include/openssl/pem.h#L46-L47
# (PEM_STRING_PKCS8, PEM_STRING_PKCS8INF)
try:
- lines = content.decode('utf-8').splitlines(False)
+ first_pem = extract_first_pem(content.decode(encoding))
+ if first_pem is None:
+ return 'raw'
+ lines = first_pem.splitlines(False)
if lines[0].startswith(PEM_START) and lines[0].endswith(PEM_END) and len(lines[0]) > len(PEM_START) + len(PEM_END):
name = lines[0][len(PEM_START):-len(PEM_END)]
if name in PKCS8_PRIVATEKEY_NAMES:
diff --git a/ansible_collections/community/crypto/plugins/module_utils/gnupg/cli.py b/ansible_collections/community/crypto/plugins/module_utils/gnupg/cli.py
new file mode 100644
index 000000000..caf0de25f
--- /dev/null
+++ b/ansible_collections/community/crypto/plugins/module_utils/gnupg/cli.py
@@ -0,0 +1,64 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2023, Felix Fontein <felix@fontein.de>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import abc
+import os
+
+from ansible.module_utils import six
+
+
+class GPGError(Exception):
+ pass
+
+
+@six.add_metaclass(abc.ABCMeta)
+class GPGRunner(object):
+ @abc.abstractmethod
+ def run_command(self, command, check_rc=True, data=None):
+ """
+ Run ``[gpg] + command`` and return ``(rc, stdout, stderr)``.
+
+ If ``data`` is not ``None``, it will be provided as stdin.
+ The code assumes it is a bytes string.
+
+ Returned stdout and stderr are native Python strings.
+ Pass ``check_rc=False`` to allow return codes != 0.
+
+ Raises a ``GPGError`` in case of errors.
+ """
+ pass
+
+
+def get_fingerprint_from_stdout(stdout):
+ lines = stdout.splitlines(False)
+ for line in lines:
+ if line.startswith('fpr:'):
+ parts = line.split(':')
+ if len(parts) <= 9 or not parts[9]:
+ raise GPGError('Result line "{line}" does not have fingerprint as 10th component'.format(line=line))
+ return parts[9]
+ raise GPGError('Cannot extract fingerprint from stdout "{stdout}"'.format(stdout=stdout))
+
+
+def get_fingerprint_from_file(gpg_runner, path):
+ if not os.path.exists(path):
+ raise GPGError('{path} does not exist'.format(path=path))
+ stdout = gpg_runner.run_command(
+ ['--no-keyring', '--with-colons', '--import-options', 'show-only', '--import', path],
+ check_rc=True,
+ )[1]
+ return get_fingerprint_from_stdout(stdout)
+
+
+def get_fingerprint_from_bytes(gpg_runner, content):
+ stdout = gpg_runner.run_command(
+ ['--no-keyring', '--with-colons', '--import-options', 'show-only', '--import', '/dev/stdin'],
+ data=content,
+ check_rc=True,
+ )[1]
+ return get_fingerprint_from_stdout(stdout)
diff --git a/ansible_collections/community/crypto/plugins/module_utils/openssh/backends/common.py b/ansible_collections/community/crypto/plugins/module_utils/openssh/backends/common.py
index 6e274a6de..46ee1c913 100644
--- a/ansible_collections/community/crypto/plugins/module_utils/openssh/backends/common.py
+++ b/ansible_collections/community/crypto/plugins/module_utils/openssh/backends/common.py
@@ -127,7 +127,7 @@ class OpensshModule(object):
ssh_bin = self.module.get_bin_path('ssh')
if not ssh_bin:
return ""
- return parse_openssh_version(self.module.run_command([ssh_bin, '-V', '-q'])[2].strip())
+ return parse_openssh_version(self.module.run_command([ssh_bin, '-V', '-q'], check_rc=True)[2].strip())
@_restore_all_on_failure
def _safe_secure_move(self, sources_and_destinations):
@@ -208,14 +208,18 @@ class KeygenCommand(object):
def get_private_key(self, private_key_path, **kwargs):
return self._run_command([self._bin_path, '-l', '-f', private_key_path], **kwargs)
- def update_comment(self, private_key_path, comment, **kwargs):
+ def update_comment(self, private_key_path, comment, force_new_format=True, **kwargs):
if os.path.exists(private_key_path) and not os.access(private_key_path, os.W_OK):
try:
os.chmod(private_key_path, stat.S_IWUSR + stat.S_IRUSR)
except (IOError, OSError) as e:
raise e("The private key at %s is not writeable preventing a comment update" % private_key_path)
- return self._run_command([self._bin_path, '-q', '-o', '-c', '-C', comment, '-f', private_key_path], **kwargs)
+ command = [self._bin_path, '-q']
+ if force_new_format:
+ command.append('-o')
+ command.extend(['-c', '-C', comment, '-f', private_key_path])
+ return self._run_command(command, **kwargs)
class PrivateKey(object):
diff --git a/ansible_collections/community/crypto/plugins/module_utils/openssh/backends/keypair_backend.py b/ansible_collections/community/crypto/plugins/module_utils/openssh/backends/keypair_backend.py
index e3bc3535b..5f54903ef 100644
--- a/ansible_collections/community/crypto/plugins/module_utils/openssh/backends/keypair_backend.py
+++ b/ansible_collections/community/crypto/plugins/module_utils/openssh/backends/keypair_backend.py
@@ -323,23 +323,27 @@ class KeypairBackendOpensshBin(KeypairBackend):
self.ssh_keygen = KeygenCommand(self.module)
def _generate_keypair(self, private_key_path):
- self.ssh_keygen.generate_keypair(private_key_path, self.size, self.type, self.comment)
+ self.ssh_keygen.generate_keypair(private_key_path, self.size, self.type, self.comment, check_rc=True)
def _get_private_key(self):
- private_key_content = self.ssh_keygen.get_private_key(self.private_key_path)[1]
+ rc, private_key_content, err = self.ssh_keygen.get_private_key(self.private_key_path, check_rc=False)
+ if rc != 0:
+ raise ValueError(err)
return PrivateKey.from_string(private_key_content)
def _get_public_key(self):
- public_key_content = self.ssh_keygen.get_matching_public_key(self.private_key_path)[1]
+ public_key_content = self.ssh_keygen.get_matching_public_key(self.private_key_path, check_rc=True)[1]
return PublicKey.from_string(public_key_content)
def _private_key_readable(self):
- rc, stdout, stderr = self.ssh_keygen.get_matching_public_key(self.private_key_path)
+ rc, stdout, stderr = self.ssh_keygen.get_matching_public_key(self.private_key_path, check_rc=False)
return not (rc == 255 or any_in(stderr, 'is not a public key file', 'incorrect passphrase', 'load failed'))
def _update_comment(self):
try:
- self.ssh_keygen.update_comment(self.private_key_path, self.comment)
+ ssh_version = self._get_ssh_version() or "7.8"
+ force_new_format = LooseVersion('6.5') <= LooseVersion(ssh_version) < LooseVersion('7.8')
+ self.ssh_keygen.update_comment(self.private_key_path, self.comment, force_new_format=force_new_format, check_rc=True)
except (IOError, OSError) as e:
self.module.fail_json(msg=to_native(e))
diff --git a/ansible_collections/community/crypto/plugins/module_utils/serial.py b/ansible_collections/community/crypto/plugins/module_utils/serial.py
new file mode 100644
index 000000000..dac554e32
--- /dev/null
+++ b/ansible_collections/community/crypto/plugins/module_utils/serial.py
@@ -0,0 +1,56 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2024, Felix Fontein <felix@fontein.de>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+from ansible.module_utils.common.text.converters import to_native
+
+from ansible_collections.community.crypto.plugins.module_utils.crypto.math import (
+ convert_int_to_hex,
+)
+
+
+def th(number):
+ abs_number = abs(number)
+ mod_10 = abs_number % 10
+ mod_100 = abs_number % 100
+ if mod_100 not in (11, 12, 13):
+ if mod_10 == 1:
+ return 'st'
+ if mod_10 == 2:
+ return 'nd'
+ if mod_10 == 3:
+ return 'rd'
+ return 'th'
+
+
+def parse_serial(value):
+ """
+ Given a colon-separated string of hexadecimal byte values, converts it to an integer.
+ """
+ value = to_native(value)
+ result = 0
+ for i, part in enumerate(value.split(':')):
+ try:
+ part_value = int(part, 16)
+ if part_value < 0 or part_value > 255:
+ raise ValueError('the value is not in range [0, 255]')
+ except ValueError as exc:
+ raise ValueError("The {idx}{th} part {part!r} is not a hexadecimal number in range [0, 255]: {exc}".format(
+ idx=i + 1, th=th(i + 1), part=part, exc=exc))
+ result = (result << 8) | part_value
+ return result
+
+
+def to_serial(value):
+ """
+ Given an integer, converts its absolute value to a colon-separated string of hexadecimal byte values.
+ """
+ value = convert_int_to_hex(value).upper()
+ if len(value) % 2 != 0:
+ value = '0' + value
+ return ':'.join(value[i:i + 2] for i in range(0, len(value), 2))
diff --git a/ansible_collections/community/crypto/plugins/modules/acme_account.py b/ansible_collections/community/crypto/plugins/modules/acme_account.py
index 13de49ab0..1e8d64a57 100644
--- a/ansible_collections/community/crypto/plugins/modules/acme_account.py
+++ b/ansible_collections/community/crypto/plugins/modules/acme_account.py
@@ -22,7 +22,7 @@ description:
notes:
- "The M(community.crypto.acme_certificate) module also allows to do basic account management.
When using both modules, it is recommended to disable account management
- for M(community.crypto.acme_certificate). For that, use the C(modify_account) option of
+ for M(community.crypto.acme_certificate). For that, use the O(community.crypto.acme_certificate#module:modify_account) option of
M(community.crypto.acme_certificate)."
seealso:
- name: Automatic Certificate Management Environment (ACME)
@@ -49,9 +49,9 @@ options:
state:
description:
- "The state of the account, to be identified by its account key."
- - "If the state is C(absent), the account will either not exist or be
+ - "If the state is V(absent), the account will either not exist or be
deactivated."
- - "If the state is C(changed_key), the account must exist. The account
+ - "If the state is V(changed_key), the account must exist. The account
key will be changed; no other information will be touched."
type: str
required: true
@@ -61,7 +61,7 @@ options:
- changed_key
allow_creation:
description:
- - "Whether account creation is allowed (when state is C(present))."
+ - "Whether account creation is allowed (when state is V(present))."
type: bool
default: true
contact:
@@ -70,30 +70,30 @@ options:
- "Email addresses must be prefixed with C(mailto:)."
- "See U(https://tools.ietf.org/html/rfc8555#section-7.3)
for what is allowed."
- - "Must be specified when state is C(present). Will be ignored
- if state is C(absent) or C(changed_key)."
+ - "Must be specified when state is V(present). Will be ignored
+ if state is V(absent) or V(changed_key)."
type: list
elements: str
default: []
terms_agreed:
description:
- "Boolean indicating whether you agree to the terms of service document."
- - "ACME servers can require this to be true."
+ - "ACME servers can require this to be V(true)."
type: bool
default: false
new_account_key_src:
description:
- "Path to a file containing the ACME account RSA or Elliptic Curve key to change to."
- - "Same restrictions apply as to C(account_key_src)."
- - "Mutually exclusive with C(new_account_key_content)."
- - "Required if C(new_account_key_content) is not used and state is C(changed_key)."
+ - "Same restrictions apply as to O(account_key_src)."
+ - "Mutually exclusive with O(new_account_key_content)."
+ - "Required if O(new_account_key_content) is not used and O(state) is V(changed_key)."
type: path
new_account_key_content:
description:
- "Content of the ACME account RSA or Elliptic Curve key to change to."
- - "Same restrictions apply as to C(account_key_content)."
- - "Mutually exclusive with C(new_account_key_src)."
- - "Required if C(new_account_key_src) is not used and state is C(changed_key)."
+ - "Same restrictions apply as to O(account_key_content)."
+ - "Mutually exclusive with O(new_account_key_src)."
+ - "Required if O(new_account_key_src) is not used and O(state) is V(changed_key)."
type: str
new_account_key_passphrase:
description:
@@ -117,14 +117,14 @@ options:
alg:
description:
- The MAC algorithm provided by the CA.
- - If not specified by the CA, this is probably C(HS256).
+ - If not specified by the CA, this is probably V(HS256).
type: str
required: true
choices: [ HS256, HS384, HS512 ]
key:
description:
- Base64 URL encoded value of the MAC key provided by the CA.
- - Padding (C(=) symbols at the end) can be omitted.
+ - Padding (V(=) symbols at the end) can be omitted.
type: str
required: true
version_added: 1.1.0
diff --git a/ansible_collections/community/crypto/plugins/modules/acme_account_info.py b/ansible_collections/community/crypto/plugins/modules/acme_account_info.py
index 4e1a3c7b7..ac4617c90 100644
--- a/ansible_collections/community/crypto/plugins/modules/acme_account_info.py
+++ b/ansible_collections/community/crypto/plugins/modules/acme_account_info.py
@@ -34,11 +34,11 @@ options:
description:
- "Whether to retrieve the list of order URLs or order objects, if provided
by the ACME server."
- - "A value of C(ignore) will not fetch the list of orders."
- - "If the value is not C(ignore) and the ACME server supports orders, the C(order_uris)
- return value is always populated. The C(orders) return value is only returned
- if this option is set to C(object_list)."
- - "Currently, Let's Encrypt does not return orders, so the C(orders) result
+ - "A value of V(ignore) will not fetch the list of orders."
+ - "If the value is not V(ignore) and the ACME server supports orders, the RV(order_uris)
+ return value is always populated. The RV(orders) return value is only returned
+ if this option is set to V(object_list)."
+ - "Currently, Let's Encrypt does not return orders, so the RV(orders) result
will always be empty."
type: str
choices:
@@ -113,7 +113,7 @@ account:
orders:
description:
- A URL where a list of orders can be retrieved for this account.
- - Use the I(retrieve_orders) option to query this URL and retrieve the
+ - Use the O(retrieve_orders) option to query this URL and retrieve the
complete list of orders.
returned: always
type: str
@@ -129,7 +129,7 @@ orders:
- "The list of orders."
type: list
elements: dict
- returned: if account exists, I(retrieve_orders) is C(object_list), and server supports order listing
+ returned: if account exists, O(retrieve_orders) is V(object_list), and server supports order listing
contains:
status:
description: The order's status.
@@ -144,7 +144,7 @@ orders:
description:
- When the order expires.
- Timestamp should be formatted as described in RFC3339.
- - Only required to be included in result when I(status) is C(pending) or C(valid).
+ - Only required to be included in result when RV(orders[].status) is V(pending) or V(valid).
type: str
returned: when server gives expiry date
identifiers:
@@ -154,14 +154,17 @@ orders:
elements: dict
contains:
type:
- description: Type of identifier. C(dns) or C(ip).
+ description: Type of identifier.
type: str
+ choices:
+ - dns
+ - ip
value:
description: Name of identifier. Hostname or IP address.
type: str
wildcard:
- description: "Whether I(value) is actually a wildcard. The wildcard
- prefix C(*.) is not included in I(value) if this is C(true)."
+ description: "Whether RV(orders[].identifiers[].value) is actually a wildcard. The wildcard
+ prefix C(*.) is not included in RV(orders[].identifiers[].value) if this is V(true)."
type: bool
returned: required to be included if the identifier is wildcarded
notBefore:
@@ -202,11 +205,11 @@ orders:
order_uris:
description:
- "The list of orders."
- - "If I(retrieve_orders) is C(url_list), this will be a list of URLs."
- - "If I(retrieve_orders) is C(object_list), this will be a list of objects."
+ - "If O(retrieve_orders) is V(url_list), this will be a list of URLs."
+ - "If O(retrieve_orders) is V(object_list), this will be a list of objects."
type: list
elements: str
- returned: if account exists, I(retrieve_orders) is not C(ignore), and server supports order listing
+ returned: if account exists, O(retrieve_orders) is not V(ignore), and server supports order listing
version_added: 1.5.0
'''
diff --git a/ansible_collections/community/crypto/plugins/modules/acme_certificate.py b/ansible_collections/community/crypto/plugins/modules/acme_certificate.py
index 6aec44e08..9c0b349c4 100644
--- a/ansible_collections/community/crypto/plugins/modules/acme_certificate.py
+++ b/ansible_collections/community/crypto/plugins/modules/acme_certificate.py
@@ -19,15 +19,15 @@ description:
L(ACME protocol,https://tools.ietf.org/html/rfc8555),
such as L(Let's Encrypt,https://letsencrypt.org/) or
L(Buypass,https://www.buypass.com/). The current implementation
- supports the C(http-01), C(dns-01) and C(tls-alpn-01) challenges."
+ supports the V(http-01), V(dns-01) and V(tls-alpn-01) challenges."
- "To use this module, it has to be executed twice. Either as two
different tasks in the same run or during two runs. Note that the output
of the first run needs to be recorded and passed to the second run as the
- module argument C(data)."
+ module argument O(data)."
- "Between these two tasks you have to fulfill the required steps for the
- chosen challenge by whatever means necessary. For C(http-01) that means
+ chosen challenge by whatever means necessary. For V(http-01) that means
creating the necessary challenge file on the destination webserver. For
- C(dns-01) the necessary dns record has to be created. For C(tls-alpn-01)
+ V(dns-01) the necessary dns record has to be created. For V(tls-alpn-01)
the necessary certificate has to be created and served.
It is I(not) the responsibility of this module to perform these steps."
- "For details on how to fulfill these challenges, you might have to read through
@@ -37,11 +37,11 @@ description:
- "The module includes experimental support for IP identifiers according to
the L(RFC 8738,https://www.rfc-editor.org/rfc/rfc8738.html)."
notes:
- - "At least one of C(dest) and C(fullchain_dest) must be specified."
+ - "At least one of O(dest) and O(fullchain_dest) must be specified."
- "This module includes basic account management functionality.
If you want to have more control over your ACME account, use the
M(community.crypto.acme_account) module and disable account management
- for this module using the C(modify_account) option."
+ for this module using the O(modify_account) option."
- "This module was called C(letsencrypt) before Ansible 2.6. The usage
did not change."
seealso:
@@ -57,10 +57,10 @@ seealso:
description: The specification of the ACME protocol (RFC 8555).
link: https://tools.ietf.org/html/rfc8555
- name: ACME TLS ALPN Challenge Extension
- description: The specification of the C(tls-alpn-01) challenge (RFC 8737).
+ description: The specification of the V(tls-alpn-01) challenge (RFC 8737).
link: https://www.rfc-editor.org/rfc/rfc8737.html-05
- module: community.crypto.acme_challenge_cert_helper
- description: Helps preparing C(tls-alpn-01) challenges.
+ description: Helps preparing V(tls-alpn-01) challenges.
- module: community.crypto.openssl_privatekey
description: Can be used to create private keys (both for certificates and accounts).
- module: community.crypto.openssl_privatekey_pipe
@@ -94,7 +94,7 @@ options:
description:
- "The email address associated with this account."
- "It will be used for certificate expiration warnings."
- - "Note that when C(modify_account) is not set to C(false) and you also
+ - "Note that when O(modify_account) is not set to V(false) and you also
used the M(community.crypto.acme_account) module to specify more than one contact
for your account, this module will update your account and restrict
it to the (at most one) contact email address specified here."
@@ -102,31 +102,31 @@ options:
agreement:
description:
- "URI to a terms of service document you agree to when using the
- ACME v1 service at C(acme_directory)."
- - Default is latest gathered from C(acme_directory) URL.
- - This option will only be used when C(acme_version) is 1.
+ ACME v1 service at O(acme_directory)."
+ - Default is latest gathered from O(acme_directory) URL.
+ - This option will only be used when O(acme_version) is 1.
type: str
terms_agreed:
description:
- "Boolean indicating whether you agree to the terms of service document."
- "ACME servers can require this to be true."
- - This option will only be used when C(acme_version) is not 1.
+ - This option will only be used when O(acme_version) is not 1.
type: bool
default: false
modify_account:
description:
- "Boolean indicating whether the module should create the account if
necessary, and update its contact data."
- - "Set to C(false) if you want to use the M(community.crypto.acme_account) module to manage
+ - "Set to V(false) if you want to use the M(community.crypto.acme_account) module to manage
your account instead, and to avoid accidental creation of a new account
using an old key if you changed the account key with M(community.crypto.acme_account)."
- - "If set to C(false), C(terms_agreed) and C(account_email) are ignored."
+ - "If set to V(false), O(terms_agreed) and O(account_email) are ignored."
type: bool
default: true
challenge:
description:
- The challenge to be performed.
- - If set to C(no challenge), no challenge will be used. This is necessary for some private
+ - If set to V(no challenge), no challenge will be used. This is necessary for some private
CAs which use External Account Binding and other means of validating certificate assurance.
For example, an account could be allowed to issue certificates for C(foo.example.com)
without any further validation for a certain period of time.
@@ -148,7 +148,7 @@ options:
account key. This is a bad idea from a security point of view, and
the CA should not accept the CSR. The ACME server should return an
error in this case."
- - Precisely one of I(csr) or I(csr_content) must be specified.
+ - Precisely one of O(csr) or O(csr_content) must be specified.
type: path
aliases: ['src']
csr_content:
@@ -162,7 +162,7 @@ options:
account key. This is a bad idea from a security point of view, and
the CA should not accept the CSR. The ACME server should return an
error in this case."
- - Precisely one of I(csr) or I(csr_content) must be specified.
+ - Precisely one of O(csr) or O(csr_content) must be specified.
type: str
version_added: 1.2.0
data:
@@ -171,27 +171,27 @@ options:
the second run of the module only."
- "The value that must be used here will be provided by a previous use
of this module. See the examples for more details."
- - "Note that for ACME v2, only the C(order_uri) entry of C(data) will
- be used. For ACME v1, C(data) must be non-empty to indicate the
+ - "Note that for ACME v2, only the C(order_uri) entry of O(data) will
+ be used. For ACME v1, O(data) must be non-empty to indicate the
second stage is active; all needed data will be taken from the
CSR."
- - "I(Note): the C(data) option was marked as C(no_log) up to
+ - "I(Note): the O(data) option was marked as C(no_log) up to
Ansible 2.5. From Ansible 2.6 on, it is no longer marked this way
- as it causes error messages to be come unusable, and C(data) does
+ as it causes error messages to be come unusable, and O(data) does
not contain any information which can be used without having
access to the account key or which are not public anyway."
type: dict
dest:
description:
- "The destination file for the certificate."
- - "Required if C(fullchain_dest) is not specified."
+ - "Required if O(fullchain_dest) is not specified."
type: path
aliases: ['cert']
fullchain_dest:
description:
- "The destination file for the full chain (that is, a certificate followed
by chain of intermediate certificates)."
- - "Required if C(dest) is not specified."
+ - "Required if O(dest) is not specified."
type: path
aliases: ['fullchain']
chain_dest:
@@ -202,11 +202,11 @@ options:
remaining_days:
description:
- "The number of days the certificate must have left being valid.
- If C(cert_days < remaining_days), then it will be renewed.
+ If RV(cert_days) < O(remaining_days), then it will be renewed.
If the certificate is not renewed, module return values will not
- include C(challenge_data)."
+ include RV(challenge_data)."
- "To make sure that the certificate is renewed in any case, you can
- use the C(force) option."
+ use the O(force) option."
type: int
default: 10
deactivate_authzs:
@@ -222,16 +222,16 @@ options:
force:
description:
- Enforces the execution of the challenge and validation, even if an
- existing certificate is still valid for more than C(remaining_days).
+ existing certificate is still valid for more than O(remaining_days).
- This is especially helpful when having an updated CSR, for example with
additional domains for which a new certificate is desired.
type: bool
default: false
retrieve_all_alternates:
description:
- - "When set to C(true), will retrieve all alternate trust chains offered by the ACME CA.
+ - "When set to V(true), will retrieve all alternate trust chains offered by the ACME CA.
These will not be written to disk, but will be returned together with the main
- chain as C(all_chains). See the documentation for the C(all_chains) return
+ chain as RV(all_chains). See the documentation for the RV(all_chains) return
value for details."
type: bool
default: false
@@ -244,8 +244,8 @@ options:
- "If a criterium matches multiple chains, the first one matching will be
returned. The order is determined by the ordering of the C(Link) headers
returned by the ACME server and might not be deterministic."
- - "Every criterium can consist of multiple different conditions, like I(issuer)
- and I(subject). For the criterium to match a chain, all conditions must apply
+ - "Every criterium can consist of multiple different conditions, like O(select_chain[].issuer)
+ and O(select_chain[].subject). For the criterium to match a chain, all conditions must apply
to the same certificate in the chain."
- "This option can only be used with the C(cryptography) backend."
type: list
@@ -255,11 +255,11 @@ options:
test_certificates:
description:
- "Determines which certificates in the chain will be tested."
- - "I(all) tests all certificates in the chain (excluding the leaf, which is
+ - "V(all) tests all certificates in the chain (excluding the leaf, which is
identical in all chains)."
- - "I(first) only tests the first certificate in the chain, that is the one which
+ - "V(first) only tests the first certificate in the chain, that is the one which
signed the leaf."
- - "I(last) only tests the last certificate in the chain, that is the one furthest
+ - "V(last) only tests the last certificate in the chain, that is the one furthest
away from the leaf. Its issuer is the root certificate of this chain."
type: str
default: all
@@ -268,29 +268,29 @@ options:
description:
- "Allows to specify parts of the issuer of a certificate in the chain must
have to be selected."
- - "If I(issuer) is empty, any certificate will match."
- - 'An example value would be C({"commonName": "My Preferred CA Root"}).'
+ - "If O(select_chain[].issuer) is empty, any certificate will match."
+ - 'An example value would be V({"commonName": "My Preferred CA Root"}).'
type: dict
subject:
description:
- "Allows to specify parts of the subject of a certificate in the chain must
have to be selected."
- - "If I(subject) is empty, any certificate will match."
- - 'An example value would be C({"CN": "My Preferred CA Intermediate"})'
+ - "If O(select_chain[].subject) is empty, any certificate will match."
+ - 'An example value would be V({"CN": "My Preferred CA Intermediate"})'
type: dict
subject_key_identifier:
description:
- "Checks for the SubjectKeyIdentifier extension. This is an identifier based
on the private key of the intermediate certificate."
- "The identifier must be of the form
- C(A8:4A:6A:63:04:7D:DD:BA:E6:D1:39:B7:A6:45:65:EF:F3:A8:EC:A1)."
+ V(A8:4A:6A:63:04:7D:DD:BA:E6:D1:39:B7:A6:45:65:EF:F3:A8:EC:A1)."
type: str
authority_key_identifier:
description:
- "Checks for the AuthorityKeyIdentifier extension. This is an identifier based
on the private key of the issuer of the intermediate certificate."
- "The identifier must be of the form
- C(C4:A7:B1:A4:7B:2C:71:FA:DB:E1:4B:90:75:FF:C4:15:60:85:89:10)."
+ V(C4:A7:B1:A4:7B:2C:71:FA:DB:E1:4B:90:75:FF:C4:15:60:85:89:10)."
type: str
'''
@@ -305,9 +305,10 @@ EXAMPLES = r'''
register: sample_com_challenge
# Alternative first step:
-- name: Create a challenge for sample.com using a account key from hashi vault.
+- name: Create a challenge for sample.com using a account key from Hashi Vault.
community.crypto.acme_certificate:
- account_key_content: "{{ lookup('hashi_vault', 'secret=secret/account_private_key:value') }}"
+ account_key_content: >-
+ {{ lookup('community.hashi_vault.hashi_vault', 'secret=secret/account_private_key:value') }}
csr: /etc/pki/cert/csr/sample.com.csr
fullchain_dest: /etc/httpd/ssl/sample.com-fullchain.crt
register: sample_com_challenge
@@ -455,32 +456,32 @@ challenge_data:
sample: .well-known/acme-challenge/evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA
resource_original:
description:
- - The original challenge resource including type identifier for C(tls-alpn-01)
+ - The original challenge resource including type identifier for V(tls-alpn-01)
challenges.
- returned: changed and challenge is C(tls-alpn-01)
+ returned: changed and O(challenge) is V(tls-alpn-01)
type: str
sample: DNS:example.com
resource_value:
description:
- The value the resource has to produce for the validation.
- - For C(http-01) and C(dns-01) challenges, the value can be used as-is.
- - "For C(tls-alpn-01) challenges, note that this return value contains a
+ - For V(http-01) and V(dns-01) challenges, the value can be used as-is.
+ - "For V(tls-alpn-01) challenges, note that this return value contains a
Base64 encoded version of the correct binary blob which has to be put
into the acmeValidation x509 extension; see
U(https://www.rfc-editor.org/rfc/rfc8737.html#section-3)
- for details. To do this, you might need the C(b64decode) Jinja filter
+ for details. To do this, you might need the P(ansible.builtin.b64decode#filter) Jinja filter
to extract the binary blob from this return value."
returned: changed
type: str
sample: IlirfxKKXA...17Dt3juxGJ-PCt92wr-oA
record:
description: The full DNS record's name for the challenge.
- returned: changed and challenge is C(dns-01)
+ returned: changed and challenge is V(dns-01)
type: str
sample: _acme-challenge.example.com
challenge_data_dns:
description:
- - List of TXT values per DNS record, in case challenge is C(dns-01).
+ - List of TXT values per DNS record, in case challenge is V(dns-01).
- Since Ansible 2.8.5, only challenges which are not yet valid are returned.
returned: changed
type: dict
@@ -518,11 +519,11 @@ account_uri:
type: str
all_chains:
description:
- - When I(retrieve_all_alternates) is set to C(true), the module will query the ACME server
+ - When O(retrieve_all_alternates) is set to V(true), the module will query the ACME server
for alternate chains. This return value will contain a list of all chains returned,
the first entry being the main chain returned by the server.
- See L(Section 7.4.2 of RFC8555,https://tools.ietf.org/html/rfc8555#section-7.4.2) for details.
- returned: when certificate was retrieved and I(retrieve_all_alternates) is set to C(true)
+ returned: when certificate was retrieved and O(retrieve_all_alternates) is set to V(true)
type: list
elements: dict
contains:
diff --git a/ansible_collections/community/crypto/plugins/modules/acme_certificate_revoke.py b/ansible_collections/community/crypto/plugins/modules/acme_certificate_revoke.py
index f1922384a..022862e60 100644
--- a/ansible_collections/community/crypto/plugins/modules/acme_certificate_revoke.py
+++ b/ansible_collections/community/crypto/plugins/modules/acme_certificate_revoke.py
@@ -19,8 +19,8 @@ description:
L(ACME protocol,https://tools.ietf.org/html/rfc8555),
such as L(Let's Encrypt,https://letsencrypt.org/)."
notes:
- - "Exactly one of C(account_key_src), C(account_key_content),
- C(private_key_src) or C(private_key_content) must be specified."
+ - "Exactly one of O(account_key_src), O(account_key_content),
+ O(private_key_src), or O(private_key_content) must be specified."
- "Trying to revoke an already revoked certificate
should result in an unchanged status, even if the revocation reason
was different than the one specified here. Also, depending on the
@@ -58,13 +58,13 @@ options:
- "RSA keys can be created with C(openssl rsa ...). Elliptic curve keys can
be created with C(openssl ecparam -genkey ...). Any other tool creating
private keys in PEM format can be used as well."
- - "Mutually exclusive with C(account_key_content)."
- - "Required if C(account_key_content) is not used."
+ - "Mutually exclusive with O(account_key_content)."
+ - "Required if O(account_key_content) is not used."
account_key_content:
description:
- "Content of the ACME account RSA or Elliptic Curve key."
- - "Note that exactly one of C(account_key_src), C(account_key_content),
- C(private_key_src) or C(private_key_content) must be specified."
+ - "Note that exactly one of O(account_key_src), O(account_key_content),
+ O(private_key_src), or O(private_key_content) must be specified."
- "I(Warning): the content will be written into a temporary file, which will
be deleted by Ansible when the module completes. Since this is an
important private key — it can be used to change the account key,
@@ -77,14 +77,14 @@ options:
private_key_src:
description:
- "Path to the certificate's private key."
- - "Note that exactly one of C(account_key_src), C(account_key_content),
- C(private_key_src) or C(private_key_content) must be specified."
+ - "Note that exactly one of O(account_key_src), O(account_key_content),
+ O(private_key_src), or O(private_key_content) must be specified."
type: path
private_key_content:
description:
- "Content of the certificate's private key."
- - "Note that exactly one of C(account_key_src), C(account_key_content),
- C(private_key_src) or C(private_key_content) must be specified."
+ - "Note that exactly one of O(account_key_src), O(account_key_content),
+ O(private_key_src), or O(private_key_content) must be specified."
- "I(Warning): the content will be written into a temporary file, which will
be deleted by Ansible when the module completes. Since this is an
important private key — it can be used to change the account key,
@@ -105,11 +105,11 @@ options:
description:
- "One of the revocation reasonCodes defined in
L(Section 5.3.1 of RFC5280,https://tools.ietf.org/html/rfc5280#section-5.3.1)."
- - "Possible values are C(0) (unspecified), C(1) (keyCompromise),
- C(2) (cACompromise), C(3) (affiliationChanged), C(4) (superseded),
- C(5) (cessationOfOperation), C(6) (certificateHold),
- C(8) (removeFromCRL), C(9) (privilegeWithdrawn),
- C(10) (aACompromise)."
+ - "Possible values are V(0) (unspecified), V(1) (keyCompromise),
+ V(2) (cACompromise), V(3) (affiliationChanged), V(4) (superseded),
+ V(5) (cessationOfOperation), V(6) (certificateHold),
+ V(8) (removeFromCRL), V(9) (privilegeWithdrawn),
+ V(10) (aACompromise)."
type: int
'''
diff --git a/ansible_collections/community/crypto/plugins/modules/acme_challenge_cert_helper.py b/ansible_collections/community/crypto/plugins/modules/acme_challenge_cert_helper.py
index 1b963e8cc..9740cd16d 100644
--- a/ansible_collections/community/crypto/plugins/modules/acme_challenge_cert_helper.py
+++ b/ansible_collections/community/crypto/plugins/modules/acme_challenge_cert_helper.py
@@ -49,7 +49,7 @@ options:
- tls-alpn-01
challenge_data:
description:
- - "The C(challenge_data) entry provided by M(community.crypto.acme_certificate) for the
+ - "The RV(community.crypto.acme_certificate#module:challenge_data) entry provided by M(community.crypto.acme_certificate) for the
challenge."
type: dict
required: true
@@ -57,12 +57,12 @@ options:
description:
- "Path to a file containing the private key file to use for this challenge
certificate."
- - "Mutually exclusive with C(private_key_content)."
+ - "Mutually exclusive with O(private_key_content)."
type: path
private_key_content:
description:
- "Content of the private key to use for this challenge certificate."
- - "Mutually exclusive with C(private_key_src)."
+ - "Mutually exclusive with O(private_key_src)."
type: str
private_key_passphrase:
description:
@@ -122,14 +122,16 @@ domain:
type: str
identifier_type:
description:
- - "The identifier type for the actual resource identifier. Will be C(dns)
- or C(ip)."
+ - "The identifier type for the actual resource identifier."
returned: always
type: str
+ choices:
+ - dns
+ - ip
identifier:
description:
- - "The identifier for the actual resource. Will be a domain name if the
- type is C(dns), or an IP address if the type is C(ip)."
+ - "The identifier for the actual resource. Will be a domain name if
+ RV(identifier_type=dns), or an IP address if RV(identifier_type=ip)."
returned: always
type: str
challenge_certificate:
diff --git a/ansible_collections/community/crypto/plugins/modules/acme_inspect.py b/ansible_collections/community/crypto/plugins/modules/acme_inspect.py
index d5c96b722..a2c76507e 100644
--- a/ansible_collections/community/crypto/plugins/modules/acme_inspect.py
+++ b/ansible_collections/community/crypto/plugins/modules/acme_inspect.py
@@ -24,7 +24,7 @@ description:
- "The module can also be used to directly access features of an ACME servers
which are not yet supported by the Ansible ACME modules."
notes:
- - "The I(account_uri) option must be specified for properly authenticated
+ - "The O(account_uri) option must be specified for properly authenticated
ACME v2 requests (except a C(new-account) request)."
- "Using the C(ansible) tool, M(community.crypto.acme_inspect) can be used to directly execute
ACME requests without the need of writing a playbook. For example, the
@@ -54,16 +54,16 @@ options:
url:
description:
- "The URL to send the request to."
- - "Must be specified if I(method) is not C(directory-only)."
+ - "Must be specified if O(method) is not V(directory-only)."
type: str
method:
description:
- "The method to use to access the given URL on the ACME server."
- - "The value C(post) executes an authenticated POST request. The content
- must be specified in the I(content) option."
- - "The value C(get) executes an authenticated POST-as-GET request for ACME v2,
+ - "The value V(post) executes an authenticated POST request. The content
+ must be specified in the O(content) option."
+ - "The value V(get) executes an authenticated POST-as-GET request for ACME v2,
and a regular GET request for ACME v1."
- - "The value C(directory-only) only retrieves the directory, without doing
+ - "The value V(directory-only) only retrieves the directory, without doing
a request."
type: str
default: get
@@ -73,13 +73,13 @@ options:
- directory-only
content:
description:
- - "An encoded JSON object which will be sent as the content if I(method)
- is C(post)."
- - "Required when I(method) is C(post), and not allowed otherwise."
+ - "An encoded JSON object which will be sent as the content if O(method)
+ is V(post)."
+ - "Required when O(method) is V(post), and not allowed otherwise."
type: str
fail_on_acme_error:
description:
- - "If I(method) is C(post) or C(get), make the module fail in case an ACME
+ - "If O(method) is V(post) or V(get), make the module fail in case an ACME
error is returned."
type: bool
default: true
diff --git a/ansible_collections/community/crypto/plugins/modules/certificate_complete_chain.py b/ansible_collections/community/crypto/plugins/modules/certificate_complete_chain.py
index b1862d2ce..357d2f668 100644
--- a/ansible_collections/community/crypto/plugins/modules/certificate_complete_chain.py
+++ b/ansible_collections/community/crypto/plugins/modules/certificate_complete_chain.py
@@ -78,7 +78,7 @@ EXAMPLES = '''
# certificates, finds the associated root certificate.
- name: Find root certificate
community.crypto.certificate_complete_chain:
- input_chain: "{{ lookup('file', '/etc/ssl/csr/www.ansible.com-fullchain.pem') }}"
+ input_chain: "{{ lookup('ansible.builtin.file', '/etc/ssl/csr/www.ansible.com-fullchain.pem') }}"
root_certificates:
- /etc/ca-certificates/
register: www_ansible_com
@@ -91,7 +91,7 @@ EXAMPLES = '''
# certificates, finds the associated root certificate.
- name: Find root certificate
community.crypto.certificate_complete_chain:
- input_chain: "{{ lookup('file', '/etc/ssl/csr/www.ansible.com.pem') }}"
+ input_chain: "{{ lookup('ansible.builtin.file', '/etc/ssl/csr/www.ansible.com.pem') }}"
intermediate_certificates:
- /etc/ssl/csr/www.ansible.com-chain.pem
root_certificates:
diff --git a/ansible_collections/community/crypto/plugins/modules/crypto_info.py b/ansible_collections/community/crypto/plugins/modules/crypto_info.py
index 1988eb32d..d776ac52c 100644
--- a/ansible_collections/community/crypto/plugins/modules/crypto_info.py
+++ b/ansible_collections/community/crypto/plugins/modules/crypto_info.py
@@ -45,12 +45,12 @@ python_cryptography_installed:
python_cryptography_import_error:
description: Import error when trying to import the L(Python cryptography library, https://cryptography.io/).
- returned: when I(python_cryptography_installed=false)
+ returned: when RV(python_cryptography_installed=false)
type: str
python_cryptography_capabilities:
description: Information on the installed L(Python cryptography library, https://cryptography.io/).
- returned: when I(python_cryptography_installed=true)
+ returned: when RV(python_cryptography_installed=true)
type: dict
contains:
version:
@@ -136,7 +136,7 @@ openssl_present:
openssl:
description: Information on the installed OpenSSL binary.
- returned: when I(openssl_present=true)
+ returned: when RV(openssl_present=true)
type: dict
contains:
path:
diff --git a/ansible_collections/community/crypto/plugins/modules/ecs_certificate.py b/ansible_collections/community/crypto/plugins/modules/ecs_certificate.py
index b19b86f56..2c1238d48 100644
--- a/ansible_collections/community/crypto/plugins/modules/ecs_certificate.py
+++ b/ansible_collections/community/crypto/plugins/modules/ecs_certificate.py
@@ -21,7 +21,7 @@ description:
- In order to request a certificate, the domain and organization used in the certificate signing request must be already
validated in the ECS system. It is I(not) the responsibility of this module to perform those steps.
notes:
- - C(path) must be specified as the output location of the certificate.
+ - O(path) must be specified as the output location of the certificate.
requirements:
- cryptography >= 1.6
extends_documentation_fragment:
@@ -32,7 +32,7 @@ attributes:
check_mode:
support: partial
details:
- - Check mode is only supported if I(request_type=new).
+ - Check mode is only supported if O(request_type=new).
diff_mode:
support: none
safe_file_operations:
@@ -40,14 +40,14 @@ attributes:
options:
backup:
description:
- - Whether a backup should be made for the certificate in I(path).
+ - Whether a backup should be made for the certificate in O(path).
type: bool
default: false
force:
description:
- - If force is used, a certificate is requested regardless of whether I(path) points to an existing valid certificate.
- - If C(request_type=renew), a forced renew will fail if the certificate being renewed has been issued within the past 30 days, regardless of the
- value of I(remaining_days) or the return value of I(cert_days) - the ECS API does not support the "renew" operation for certificates that are not
+ - If force is used, a certificate is requested regardless of whether O(path) points to an existing valid certificate.
+ - If O(request_type=renew), a forced renew will fail if the certificate being renewed has been issued within the past 30 days, regardless of the
+ value of O(remaining_days) or the return value of RV(cert_days) - the ECS API does not support the "renew" operation for certificates that are not
at least 30 days old.
type: bool
default: false
@@ -56,9 +56,9 @@ options:
- The destination path for the generated certificate as a PEM encoded cert.
- If the certificate at this location is not an Entrust issued certificate, a new certificate will always be requested even if the current
certificate is technically valid.
- - If there is already an Entrust certificate at this location, whether it is replaced is depends on the I(remaining_days) calculation.
- - If an existing certificate is being replaced (see I(remaining_days), I(force), and I(tracking_id)), whether a new certificate is requested
- or the existing certificate is renewed or reissued is based on I(request_type).
+ - If there is already an Entrust certificate at this location, whether it is replaced is depends on the O(remaining_days) calculation.
+ - If an existing certificate is being replaced (see O(remaining_days), O(force), and O(tracking_id)), whether a new certificate is requested
+ or the existing certificate is renewed or reissued is based on O(request_type).
type: path
required: true
full_chain_path:
@@ -67,54 +67,54 @@ options:
type: path
csr:
description:
- - Base-64 encoded Certificate Signing Request (CSR). I(csr) is accepted with or without PEM formatting around the Base-64 string.
- - If no I(csr) is provided when C(request_type=reissue) or C(request_type=renew), the certificate will be generated with the same public key as
+ - Base-64 encoded Certificate Signing Request (CSR). O(csr) is accepted with or without PEM formatting around the Base-64 string.
+ - If no O(csr) is provided when O(request_type=reissue) or O(request_type=renew), the certificate will be generated with the same public key as
the certificate being renewed or reissued.
- - If I(subject_alt_name) is specified, it will override the subject alternate names in the CSR.
- - If I(eku) is specified, it will override the extended key usage in the CSR.
- - If I(ou) is specified, it will override the organizational units "ou=" present in the subject distinguished name of the CSR, if any.
- - The organization "O=" field from the CSR will not be used. It will be replaced in the issued certificate by I(org) if present, and if not present,
- the organization tied to I(client_id).
+ - If O(subject_alt_name) is specified, it will override the subject alternate names in the CSR.
+ - If O(eku) is specified, it will override the extended key usage in the CSR.
+ - If O(ou) is specified, it will override the organizational units "ou=" present in the subject distinguished name of the CSR, if any.
+ - The organization "O=" field from the CSR will not be used. It will be replaced in the issued certificate by O(org) if present, and if not present,
+ the organization tied to O(client_id).
type: str
tracking_id:
description:
- The tracking ID of the certificate to reissue or renew.
- - I(tracking_id) is invalid if C(request_type=new) or C(request_type=validate_only).
- - If there is a certificate present in I(path) and it is an ECS certificate, I(tracking_id) will be ignored.
- - If there is no certificate present in I(path) or there is but it is from another provider, the certificate represented by I(tracking_id) will
- be renewed or reissued and saved to I(path).
- - If there is no certificate present in I(path) and the I(force) and I(remaining_days) parameters do not indicate a new certificate is needed,
- the certificate referenced by I(tracking_id) certificate will be saved to I(path).
+ - O(tracking_id) is invalid if O(request_type=new) or O(request_type=validate_only).
+ - If there is a certificate present in O(path) and it is an ECS certificate, O(tracking_id) will be ignored.
+ - If there is no certificate present in O(path) or there is but it is from another provider, the certificate represented by O(tracking_id) will
+ be renewed or reissued and saved to O(path).
+ - If there is no certificate present in O(path) and the O(force) and O(remaining_days) parameters do not indicate a new certificate is needed,
+ the certificate referenced by O(tracking_id) certificate will be saved to O(path).
- This can be used when a known certificate is not currently present on a server, but you want to renew or reissue it to be managed by an ansible
- playbook. For example, if you specify C(request_type=renew), I(tracking_id) of an issued certificate, and I(path) to a file that does not exist,
- the first run of a task will download the certificate specified by I(tracking_id) (assuming it is still valid). Future runs of the task will
- (if applicable - see I(force) and I(remaining_days)) renew the certificate now present in I(path).
+ playbook. For example, if you specify O(request_type=renew), O(tracking_id) of an issued certificate, and O(path) to a file that does not exist,
+ the first run of a task will download the certificate specified by O(tracking_id) (assuming it is still valid). Future runs of the task will
+ (if applicable - see O(force) and O(remaining_days)) renew the certificate now present in O(path).
type: int
remaining_days:
description:
- - The number of days the certificate must have left being valid. If C(cert_days < remaining_days) then a new certificate will be
- obtained using I(request_type).
- - If C(request_type=renew), a renewal will fail if the certificate being renewed has been issued within the past 30 days, so do not set a
- I(remaining_days) value that is within 30 days of the full lifetime of the certificate being acted upon.
- - For exmaple, if you are requesting Certificates with a 90 day lifetime, do not set I(remaining_days) to a value C(60) or higher).
- - The I(force) option may be used to ensure that a new certificate is always obtained.
+ - The number of days the certificate must have left being valid. If RV(cert_days) < O(remaining_days) then a new certificate will be
+ obtained using O(request_type).
+ - If O(request_type=renew), a renewal will fail if the certificate being renewed has been issued within the past 30 days, so do not set a
+ O(remaining_days) value that is within 30 days of the full lifetime of the certificate being acted upon.
+ - For example, if you are requesting Certificates with a 90 day lifetime, do not set O(remaining_days) to a value V(60) or higher).
+ - The O(force) option may be used to ensure that a new certificate is always obtained.
type: int
default: 30
request_type:
description:
- - The operation performed if I(tracking_id) references a valid certificate to reissue, or there is already a certificate present in I(path) but
- either I(force) is specified or C(cert_days < remaining_days).
- - Specifying C(request_type=validate_only) means the request will be validated against the ECS API, but no certificate will be issued.
- - Specifying C(request_type=new) means a certificate request will always be submitted and a new certificate issued.
- - Specifying C(request_type=renew) means that an existing certificate (specified by I(tracking_id) if present, otherwise I(path)) will be renewed.
+ - The operation performed if O(tracking_id) references a valid certificate to reissue, or there is already a certificate present in O(path) but
+ either O(force) is specified or RV(cert_days) < O(remaining_days).
+ - Specifying O(request_type=validate_only) means the request will be validated against the ECS API, but no certificate will be issued.
+ - Specifying O(request_type=new) means a certificate request will always be submitted and a new certificate issued.
+ - Specifying O(request_type=renew) means that an existing certificate (specified by O(tracking_id) if present, otherwise O(path)) will be renewed.
If there is no certificate to renew, a new certificate is requested.
- - Specifying C(request_type=reissue) means that an existing certificate (specified by I(tracking_id) if present, otherwise I(path)) will be
+ - Specifying O(request_type=reissue) means that an existing certificate (specified by O(tracking_id) if present, otherwise O(path)) will be
reissued.
If there is no certificate to reissue, a new certificate is requested.
- - If a certificate was issued within the past 30 days, the C(renew) operation is not a valid operation and will fail.
- - Note that C(reissue) is an operation that will result in the revocation of the certificate that is reissued, be cautious with its use.
- - I(check_mode) is only supported if C(request_type=new)
- - For example, setting C(request_type=renew) and C(remaining_days=30) and pointing to the same certificate on multiple playbook runs means that on
+ - If a certificate was issued within the past 30 days, the V(renew) operation is not a valid operation and will fail.
+ - Note that V(reissue) is an operation that will result in the revocation of the certificate that is reissued, be cautious with its use.
+ - I(check_mode) is only supported if O(request_type=new)
+ - For example, setting O(request_type=renew) and O(remaining_days=30) and pointing to the same certificate on multiple playbook runs means that on
the first run new certificate will be requested. It will then be left along on future runs until it is within 30 days of expiry, then the
ECS "renew" operation will be performed.
type: str
@@ -123,57 +123,57 @@ options:
cert_type:
description:
- Specify the type of certificate requested.
- - If a certificate is being reissued or renewed, this parameter is ignored, and the C(cert_type) of the initial certificate is used.
+ - If a certificate is being reissued or renewed, this parameter is ignored, and the O(cert_type) of the initial certificate is used.
type: str
choices: [ 'STANDARD_SSL', 'ADVANTAGE_SSL', 'UC_SSL', 'EV_SSL', 'WILDCARD_SSL', 'PRIVATE_SSL', 'PD_SSL', 'CODE_SIGNING', 'EV_CODE_SIGNING',
'CDS_INDIVIDUAL', 'CDS_GROUP', 'CDS_ENT_LITE', 'CDS_ENT_PRO', 'SMIME_ENT' ]
subject_alt_name:
description:
- - The subject alternative name identifiers, as an array of values (applies to I(cert_type) with a value of C(STANDARD_SSL), C(ADVANTAGE_SSL),
- C(UC_SSL), C(EV_SSL), C(WILDCARD_SSL), C(PRIVATE_SSL), and C(PD_SSL)).
- - If you are requesting a new SSL certificate, and you pass a I(subject_alt_name) parameter, any SAN names in the CSR are ignored.
+ - The subject alternative name identifiers, as an array of values (applies to O(cert_type) with a value of V(STANDARD_SSL), V(ADVANTAGE_SSL),
+ V(UC_SSL), V(EV_SSL), V(WILDCARD_SSL), V(PRIVATE_SSL), and V(PD_SSL)).
+ - If you are requesting a new SSL certificate, and you pass a O(subject_alt_name) parameter, any SAN names in the CSR are ignored.
If no subjectAltName parameter is passed, the SAN names in the CSR are used.
- - See I(request_type) to understand more about SANs during reissues and renewals.
- - In the case of certificates of type C(STANDARD_SSL) certificates, if the CN of the certificate is <domain>.<tld> only the www.<domain>.<tld> value
+ - See O(request_type) to understand more about SANs during reissues and renewals.
+ - In the case of certificates of type V(STANDARD_SSL) certificates, if the CN of the certificate is <domain>.<tld> only the www.<domain>.<tld> value
is accepted. If the CN of the certificate is www.<domain>.<tld> only the <domain>.<tld> value is accepted.
type: list
elements: str
eku:
description:
- - If specified, overrides the key usage in the I(csr).
+ - If specified, overrides the key usage in the O(csr).
type: str
choices: [ SERVER_AUTH, CLIENT_AUTH, SERVER_AND_CLIENT_AUTH ]
ct_log:
description:
- In compliance with browser requirements, this certificate may be posted to the Certificate Transparency (CT) logs. This is a best practice
technique that helps domain owners monitor certificates issued to their domains. Note that not all certificates are eligible for CT logging.
- - If I(ct_log) is not specified, the certificate uses the account default.
- - If I(ct_log) is specified and the account settings allow it, I(ct_log) overrides the account default.
- - If I(ct_log) is set to C(false), but the account settings are set to "always log", the certificate generation will fail.
+ - If O(ct_log) is not specified, the certificate uses the account default.
+ - If O(ct_log) is specified and the account settings allow it, O(ct_log) overrides the account default.
+ - If O(ct_log) is set to V(false), but the account settings are set to "always log", the certificate generation will fail.
type: bool
client_id:
description:
- The client ID to submit the Certificate Signing Request under.
- If no client ID is specified, the certificate will be submitted under the primary client with ID of 1.
- - When using a client other than the primary client, the I(org) parameter cannot be specified.
+ - When using a client other than the primary client, the O(org) parameter cannot be specified.
- The issued certificate will have an organization value in the subject distinguished name represented by the client.
type: int
default: 1
org:
description:
- Organization "O=" to include in the certificate.
- - If I(org) is not specified, the organization from the client represented by I(client_id) is used.
- - Unless the I(cert_type) is C(PD_SSL), this field may not be specified if the value of I(client_id) is not "1" (the primary client).
+ - If O(org) is not specified, the organization from the client represented by O(client_id) is used.
+ - Unless the O(cert_type) is V(PD_SSL), this field may not be specified if the value of O(client_id) is not "1" (the primary client).
non-primary clients, certificates may only be issued with the organization of that client.
type: str
ou:
description:
- Organizational unit "OU=" to include in the certificate.
- - I(ou) behavior is dependent on whether organizational units are enabled for your account. If organizational unit support is disabled for your
- account, organizational units from the I(csr) and the I(ou) parameter are ignored.
- - If both I(csr) and I(ou) are specified, the value in I(ou) will override the OU fields present in the subject distinguished name in the I(csr)
- - If neither I(csr) nor I(ou) are specified for a renew or reissue operation, the OU fields in the initial certificate are reused.
- - An invalid OU from I(csr) is ignored, but any invalid organizational units in I(ou) will result in an error indicating "Unapproved OU". The I(ou)
+ - O(ou) behavior is dependent on whether organizational units are enabled for your account. If organizational unit support is disabled for your
+ account, organizational units from the O(csr) and the O(ou) parameter are ignored.
+ - If both O(csr) and O(ou) are specified, the value in O(ou) will override the OU fields present in the subject distinguished name in the O(csr)
+ - If neither O(csr) nor O(ou) are specified for a renew or reissue operation, the OU fields in the initial certificate are reused.
+ - An invalid OU from O(csr) is ignored, but any invalid organizational units in O(ou) will result in an error indicating "Unapproved OU". The O(ou)
parameter can be used to force failure if an unapproved organizational unit is provided.
- A maximum of one OU may be specified for current products. Multiple OUs are reserved for future products.
type: list
@@ -181,10 +181,10 @@ options:
end_user_key_storage_agreement:
description:
- The end user of the Code Signing certificate must generate and store the private key for this request on cryptographically secure
- hardware to be compliant with the Entrust CSP and Subscription agreement. If requesting a certificate of type C(CODE_SIGNING) or
- C(EV_CODE_SIGNING), you must set I(end_user_key_storage_agreement) to true if and only if you acknowledge that you will inform the user of this
+ hardware to be compliant with the Entrust CSP and Subscription agreement. If requesting a certificate of type V(CODE_SIGNING) or
+ V(EV_CODE_SIGNING), you must set O(end_user_key_storage_agreement) to true if and only if you acknowledge that you will inform the user of this
requirement.
- - Applicable only to I(cert_type) of values C(CODE_SIGNING) and C(EV_CODE_SIGNING).
+ - Applicable only to O(cert_type) of values V(CODE_SIGNING) and V(EV_CODE_SIGNING).
type: bool
tracking_info:
description: Free form tracking information to attach to the record for the certificate.
@@ -320,29 +320,29 @@ options:
cert_expiry:
description:
- The date the certificate should be set to expire, in RFC3339 compliant date or date-time format. For example,
- C(2020-02-23), C(2020-02-23T15:00:00.05Z).
- - I(cert_expiry) is only supported for requests of C(request_type=new) or C(request_type=renew). If C(request_type=reissue),
- I(cert_expiry) will be used for the first certificate issuance, but subsequent issuances will have the same expiry as the initial
+ V(2020-02-23), V(2020-02-23T15:00:00.05Z).
+ - O(cert_expiry) is only supported for requests of O(request_type=new) or O(request_type=renew). If O(request_type=reissue),
+ O(cert_expiry) will be used for the first certificate issuance, but subsequent issuances will have the same expiry as the initial
certificate.
- A reissued certificate will always have the same expiry as the original certificate.
- Note that only the date (day, month, year) is supported for specifying the expiry date. If you choose to specify an expiry time with the expiry
date, the time will be adjusted to Eastern Standard Time (EST). This could have the unintended effect of moving your expiry date to the previous
day.
- Applies only to accounts with a pooling inventory model.
- - Only one of I(cert_expiry) or I(cert_lifetime) may be specified.
+ - Only one of O(cert_expiry) or O(cert_lifetime) may be specified.
type: str
cert_lifetime:
description:
- The lifetime of the certificate.
- Applies to all certificates for accounts with a non-pooling inventory model.
- - I(cert_lifetime) is only supported for requests of C(request_type=new) or C(request_type=renew). If C(request_type=reissue), I(cert_lifetime) will
+ - O(cert_lifetime) is only supported for requests of O(request_type=new) or O(request_type=renew). If O(request_type=reissue), O(cert_lifetime) will
be used for the first certificate issuance, but subsequent issuances will have the same expiry as the initial certificate.
- - Applies to certificates of I(cert_type)=C(CDS_INDIVIDUAL, CDS_GROUP, CDS_ENT_LITE, CDS_ENT_PRO, SMIME_ENT) for accounts with a pooling inventory
- model.
- - C(P1Y) is a certificate with a 1 year lifetime.
- - C(P2Y) is a certificate with a 2 year lifetime.
- - C(P3Y) is a certificate with a 3 year lifetime.
- - Only one of I(cert_expiry) or I(cert_lifetime) may be specified.
+ - Applies to certificates of O(cert_type=CDS_INDIVIDUAL), V(CDS_GROUP), V(CDS_ENT_LITE), V(CDS_ENT_PRO), or V(SMIME_ENT)
+ for accounts with a pooling inventory model.
+ - V(P1Y) is a certificate with a 1 year lifetime.
+ - V(P2Y) is a certificate with a 2 year lifetime.
+ - V(P3Y) is a certificate with a 3 year lifetime.
+ - Only one of O(cert_expiry) or O(cert_lifetime) may be specified.
type: str
choices: [ P1Y, P2Y, P3Y ]
seealso:
@@ -350,6 +350,8 @@ seealso:
description: Can be used to create private keys (both for certificates and accounts).
- module: community.crypto.openssl_csr
description: Can be used to create a Certificate Signing Request (CSR).
+ - plugin: community.crypto.to_serial
+ plugin_type: filter
'''
EXAMPLES = r'''
@@ -476,12 +478,12 @@ filename:
sample: /etc/ssl/crt/www.ansible.com.crt
backup_file:
description: Name of backup file created for the certificate.
- returned: changed and if I(backup) is C(true)
+ returned: changed and if O(backup) is V(true)
type: str
sample: /path/to/www.ansible.com.crt.2019-03-09@11:22~
backup_full_chain_file:
description: Name of the backup file created for the certificate chain.
- returned: changed and if I(backup) is C(true) and I(full_chain_path) is set.
+ returned: changed and if O(backup) is V(true) and O(full_chain_path) is set.
type: str
sample: /path/to/ca.chain.crt.2019-03-09@11:22~
tracking_id:
@@ -490,7 +492,10 @@ tracking_id:
type: int
sample: 380079
serial_number:
- description: The serial number of the issued certificate.
+ description:
+ - The serial number of the issued certificate.
+ - This return value is an B(integer). If you need the serial numbers as a colon-separated hex string,
+ such as C(11:22:33), you need to convert it to that form with P(community.crypto.to_serial#filter).
returned: success
type: int
sample: 1235262234164342
@@ -502,8 +507,8 @@ cert_days:
cert_status:
description:
- The certificate status in ECS.
- - 'Current possible values (which may be expanded in the future) are: C(ACTIVE), C(APPROVED), C(DEACTIVATED), C(DECLINED), C(EXPIRED), C(NA),
- C(PENDING), C(PENDING_QUORUM), C(READY), C(REISSUED), C(REISSUING), C(RENEWED), C(RENEWING), C(REVOKED), C(SUSPENDED)'
+ - 'Current possible values (which may be expanded in the future) are: V(ACTIVE), V(APPROVED), V(DEACTIVATED), V(DECLINED), V(EXPIRED), V(NA),
+ V(PENDING), V(PENDING_QUORUM), V(READY), V(REISSUED), V(REISSUING), V(RENEWED), V(RENEWING), V(REVOKED), V(SUSPENDED)'
returned: success
type: str
sample: ACTIVE
diff --git a/ansible_collections/community/crypto/plugins/modules/ecs_domain.py b/ansible_collections/community/crypto/plugins/modules/ecs_domain.py
index ec7ad98b0..0ee9380f1 100644
--- a/ansible_collections/community/crypto/plugins/modules/ecs_domain.py
+++ b/ansible_collections/community/crypto/plugins/modules/ecs_domain.py
@@ -20,19 +20,19 @@ description:
- Request validation or re-validation of a domain with the Entrust Certificate Services (ECS) API.
- Requires credentials for the L(Entrust Certificate Services,https://www.entrustdatacard.com/products/categories/ssl-certificates) (ECS) API.
- If the domain is already in the validation process, no new validation will be requested, but the validation data (if applicable) will be returned.
- - If the domain is already in the validation process but the I(verification_method) specified is different than the current I(verification_method),
- the I(verification_method) will be updated and validation data (if applicable) will be returned.
- - If the domain is an active, validated domain, the return value of I(changed) will be false, unless C(domain_status=EXPIRED), in which case a re-validation
- will be performed.
- - If C(verification_method=dns), details about the required DNS entry will be specified in the return parameters I(dns_contents), I(dns_location), and
- I(dns_resource_type).
- - If C(verification_method=web_server), details about the required file details will be specified in the return parameters I(file_contents) and
- I(file_location).
- - If C(verification_method=email), the email address(es) that the validation email(s) were sent to will be in the return parameter I(emails). This is
+ - If the domain is already in the validation process but the O(verification_method) specified is different than the current O(verification_method),
+ the O(verification_method) will be updated and validation data (if applicable) will be returned.
+ - If the domain is an active, validated domain, the return value of C(changed) will be false, unless RV(domain_status=EXPIRED), in which case a
+ re-validation will be performed.
+ - If O(verification_method=dns), details about the required DNS entry will be specified in the return parameters RV(dns_contents), RV(dns_location), and
+ RV(dns_resource_type).
+ - If O(verification_method=web_server), details about the required file details will be specified in the return parameters RV(file_contents) and
+ RV(file_location).
+ - If O(verification_method=email), the email address(es) that the validation email(s) were sent to will be in the return parameter RV(emails). This is
purely informational. For domains requested using this module, this will always be a list of size 1.
notes:
- There is a small delay (typically about 5 seconds, but can be as long as 60 seconds) before obtaining the random values when requesting a validation
- while C(verification_method=dns) or C(verification_method=web_server). Be aware of that if doing many domain validation requests.
+ while O(verification_method=dns) or O(verification_method=web_server). Be aware of that if doing many domain validation requests.
extends_documentation_fragment:
- community.crypto.attributes
- community.crypto.ecs_credential
@@ -56,35 +56,35 @@ options:
verification_method:
description:
- The verification method to be used to prove control of the domain.
- - If C(verification_method=email) and the value I(verification_email) is specified, that value is used for the email validation. If
- I(verification_email) is not provided, the first value present in WHOIS data will be used. An email will be sent to the address in
- I(verification_email) with instructions on how to verify control of the domain.
- - If C(verification_method=dns), the value I(dns_contents) must be stored in location I(dns_location), with a DNS record type of
- I(verification_dns_record_type). To prove domain ownership, update your DNS records so the text string returned by I(dns_contents) is available at
- I(dns_location).
- - If C(verification_method=web_server), the contents of return value I(file_contents) must be made available on a web server accessible at location
- I(file_location).
- - If C(verification_method=manual), the domain will be validated with a manual process. This is not recommended.
+ - If O(verification_method=email) and the value O(verification_email) is specified, that value is used for the email validation. If
+ O(verification_email) is not provided, the first value present in WHOIS data will be used. An email will be sent to the address in
+ O(verification_email) with instructions on how to verify control of the domain.
+ - If O(verification_method=dns), the value RV(dns_contents) must be stored in location RV(dns_location), with a DNS record type of
+ RV(dns_resource_type). To prove domain ownership, update your DNS records so the text string returned by RV(dns_contents) is available at
+ RV(dns_location).
+ - If O(verification_method=web_server), the contents of return value RV(file_contents) must be made available on a web server accessible at location
+ RV(file_location).
+ - If O(verification_method=manual), the domain will be validated with a manual process. This is not recommended.
type: str
choices: [ 'dns', 'email', 'manual', 'web_server']
required: true
verification_email:
description:
- Email address to be used to verify domain ownership.
- - 'Email address must be either an email address present in the WHOIS data for I(domain_name), or one of the following constructed emails:
- admin@I(domain_name), administrator@I(domain_name), webmaster@I(domain_name), hostmaster@I(domain_name), postmaster@I(domain_name).'
- - 'Note that if I(domain_name) includes subdomains, the top level domain should be used. For example, if requesting validation of
+ - 'Email address must be either an email address present in the WHOIS data for O(domain_name), or one of the following constructed emails:
+ admin@O(domain_name), administrator@O(domain_name), webmaster@O(domain_name), hostmaster@O(domain_name), postmaster@O(domain_name).'
+ - 'Note that if O(domain_name) includes subdomains, the top level domain should be used. For example, if requesting validation of
example1.ansible.com, or test.example2.ansible.com, and you want to use the "admin" preconstructed name, the email address should be
admin@ansible.com.'
- If using the email values from the WHOIS data for the domain or its top level namespace, they must be exact matches.
- - If C(verification_method=email) but I(verification_email) is not provided, the first email address found in WHOIS data for the domain will be
+ - If O(verification_method=email) but O(verification_email) is not provided, the first email address found in WHOIS data for the domain will be
used.
- To verify domain ownership, domain owner must follow the instructions in the email they receive.
- - Only allowed if C(verification_method=email)
+ - Only allowed if O(verification_method=email)
type: str
seealso:
- module: community.crypto.x509_certificate
- description: Can be used to request certificates from ECS, with C(provider=entrust).
+ description: Can be used to request certificates from ECS, with O(community.crypto.x509_certificate#module:provider=entrust).
- module: community.crypto.ecs_certificate
description: Can be used to request a Certificate from ECS using a verified domain.
'''
@@ -133,72 +133,72 @@ EXAMPLES = r'''
RETURN = '''
domain_status:
- description: Status of the current domain. Will be one of C(APPROVED), C(DECLINED), C(CANCELLED), C(INITIAL_VERIFICATION), C(DECLINED), C(CANCELLED),
- C(RE_VERIFICATION), C(EXPIRED), C(EXPIRING)
+ description: Status of the current domain. Will be one of V(APPROVED), V(DECLINED), V(CANCELLED), V(INITIAL_VERIFICATION), V(DECLINED), V(CANCELLED),
+ V(RE_VERIFICATION), V(EXPIRED), V(EXPIRING)
returned: changed or success
type: str
sample: APPROVED
verification_method:
- description: Verification method used to request the domain validation. If C(changed) will be the same as I(verification_method) input parameter.
+ description: Verification method used to request the domain validation. If C(changed) will be the same as O(verification_method) input parameter.
returned: changed or success
type: str
sample: dns
file_location:
- description: The location that ECS will be expecting to be able to find the file for domain verification, containing the contents of I(file_contents).
- returned: I(verification_method) is C(web_server)
+ description: The location that ECS will be expecting to be able to find the file for domain verification, containing the contents of RV(file_contents).
+ returned: O(verification_method) is V(web_server)
type: str
sample: http://ansible.com/.well-known/pki-validation/abcd.txt
file_contents:
- description: The contents of the file that ECS will be expecting to find at C(file_location).
- returned: I(verification_method) is C(web_server)
+ description: The contents of the file that ECS will be expecting to find at RV(file_location).
+ returned: O(verification_method) is V(web_server)
type: str
sample: AB23CD41432522FF2526920393982FAB
emails:
description:
- The list of emails used to request validation of this domain.
- Domains requested using this module will only have a list of size 1.
- returned: I(verification_method) is C(email)
+ returned: O(verification_method) is V(email)
type: list
sample: [ admin@ansible.com, administrator@ansible.com ]
dns_location:
- description: The location that ECS will be expecting to be able to find the DNS entry for domain verification, containing the contents of I(dns_contents).
- returned: changed and if I(verification_method) is C(dns)
+ description: The location that ECS will be expecting to be able to find the DNS entry for domain verification, containing the contents of RV(dns_contents).
+ returned: changed and if O(verification_method) is V(dns)
type: str
sample: _pki-validation.ansible.com
dns_contents:
- description: The value that ECS will be expecting to find in the DNS record located at I(dns_location).
- returned: changed and if I(verification_method) is C(dns)
+ description: The value that ECS will be expecting to find in the DNS record located at RV(dns_location).
+ returned: changed and if O(verification_method) is V(dns)
type: str
sample: AB23CD41432522FF2526920393982FAB
dns_resource_type:
- description: The type of resource record that ECS will be expecting for the DNS record located at I(dns_location).
- returned: changed and if I(verification_method) is C(dns)
+ description: The type of resource record that ECS will be expecting for the DNS record located at RV(dns_location).
+ returned: changed and if O(verification_method) is V(dns)
type: str
sample: TXT
client_id:
- description: Client ID that the domain belongs to. If the input value I(client_id) is specified, this will always be the same as I(client_id)
+ description: Client ID that the domain belongs to. If the input value O(client_id) is specified, this will always be the same as O(client_id)
returned: changed or success
type: int
sample: 1
ov_eligible:
- description: Whether the domain is eligible for submission of "OV" certificates. Will never be C(false) if I(ov_eligible) is C(true)
- returned: success and I(domain_status) is C(APPROVED), C(RE_VERIFICATION), C(EXPIRING), or C(EXPIRED).
+ description: Whether the domain is eligible for submission of "OV" certificates. Will never be V(false) if RV(ev_eligible) is V(true)
+ returned: success and RV(domain_status) is V(APPROVED), V(RE_VERIFICATION), V(EXPIRING), or V(EXPIRED).
type: bool
sample: true
ov_days_remaining:
- description: The number of days the domain remains eligible for submission of "OV" certificates. Will never be less than the value of I(ev_days_remaining)
- returned: success and I(ov_eligible) is C(true) and I(domain_status) is C(APPROVED), C(RE_VERIFICATION) or C(EXPIRING).
+ description: The number of days the domain remains eligible for submission of "OV" certificates. Will never be less than the value of RV(ev_days_remaining)
+ returned: success and RV(ov_eligible) is V(true) and RV(domain_status) is V(APPROVED), V(RE_VERIFICATION) or V(EXPIRING).
type: int
sample: 129
ev_eligible:
- description: Whether the domain is eligible for submission of "EV" certificates. Will never be C(true) if I(ov_eligible) is C(false)
- returned: success and I(domain_status) is C(APPROVED), C(RE_VERIFICATION) or C(EXPIRING), or C(EXPIRED).
+ description: Whether the domain is eligible for submission of "EV" certificates. Will never be V(true) if RV(ov_eligible) is V(false)
+ returned: success and RV(domain_status) is V(APPROVED), V(RE_VERIFICATION) or V(EXPIRING), or V(EXPIRED).
type: bool
sample: true
ev_days_remaining:
description: The number of days the domain remains eligible for submission of "EV" certificates. Will never be greater than the value of
- I(ov_days_remaining)
- returned: success and I(ev_eligible) is C(true) and I(domain_status) is C(APPROVED), C(RE_VERIFICATION) or C(EXPIRING).
+ RV(ov_days_remaining)
+ returned: success and RV(ev_eligible) is V(true) and RV(domain_status) is V(APPROVED), V(RE_VERIFICATION) or V(EXPIRING).
type: int
sample: 94
diff --git a/ansible_collections/community/crypto/plugins/modules/get_certificate.py b/ansible_collections/community/crypto/plugins/modules/get_certificate.py
index 4b2eeaed8..0f8abc90a 100644
--- a/ansible_collections/community/crypto/plugins/modules/get_certificate.py
+++ b/ansible_collections/community/crypto/plugins/modules/get_certificate.py
@@ -63,7 +63,7 @@ options:
starttls:
description:
- Requests a secure connection for protocols which require clients to initiate encryption.
- - Only available for C(mysql) currently.
+ - Only available for V(mysql) currently.
type: str
choices:
- mysql
@@ -76,15 +76,15 @@ options:
select_crypto_backend:
description:
- Determines which crypto backend to use.
- - The default choice is C(auto), which tries to use C(cryptography) if available.
- - If set to C(cryptography), will try to use the L(cryptography,https://cryptography.io/) library.
+ - The default choice is V(auto), which tries to use C(cryptography) if available.
+ - If set to V(cryptography), will try to use the L(cryptography,https://cryptography.io/) library.
type: str
default: auto
choices: [ auto, cryptography ]
ciphers:
description:
- SSL/TLS Ciphers to use for the request.
- - 'When a list is provided, all ciphers are joined in order with C(:).'
+ - 'When a list is provided, all ciphers are joined in order with V(:).'
- See the L(OpenSSL Cipher List Format,https://www.openssl.org/docs/manmaster/man1/openssl-ciphers.html#CIPHER-LIST-FORMAT)
for more details.
- The available ciphers is dependent on the Python and OpenSSL/LibreSSL versions.
@@ -93,20 +93,23 @@ options:
version_added: 2.11.0
asn1_base64:
description:
- - Whether to encode the ASN.1 values in the C(extensions) return value with Base64 or not.
+ - Whether to encode the ASN.1 values in the RV(extensions) return value with Base64 or not.
- The documentation claimed for a long time that the values are Base64 encoded, but they
- never were. For compatibility this option is set to C(false), but that value will eventually
- be deprecated and changed to C(true).
+ never were. For compatibility this option is set to V(false).
+ - The default value V(false) is B(deprecated) and will change to V(true) in community.crypto 3.0.0.
type: bool
- default: false
version_added: 2.12.0
notes:
- When using ca_cert on OS X it has been reported that in some conditions the validate will always succeed.
requirements:
- - "python >= 2.7 when using C(proxy_host)"
+ - "python >= 2.7 when using O(proxy_host)"
- "cryptography >= 1.6"
+
+seealso:
+ - plugin: community.crypto.to_serial
+ plugin_type: filter
'''
RETURN = '''
@@ -133,7 +136,7 @@ extensions:
type: str
description:
- The ASN.1 content of the extension.
- - If I(asn1_base64=true) this will be Base64 encoded, otherwise the raw
+ - If O(asn1_base64=true) this will be Base64 encoded, otherwise the raw
binary value will be returned.
- Please note that the raw binary value might not survive JSON serialization
to the Ansible controller, and also might cause failures when displaying it.
@@ -148,31 +151,34 @@ extensions:
type: str
description: The extension's name.
issuer:
- description: Information about the issuer of the cert
+ description: Information about the issuer of the cert.
returned: success
type: dict
not_after:
- description: Expiration date of the cert
+ description: Expiration date of the cert.
returned: success
type: str
not_before:
- description: Issue date of the cert
+ description: Issue date of the cert.
returned: success
type: str
serial_number:
- description: The serial number of the cert
+ description:
+ - The serial number of the cert.
+ - This return value is an B(integer). If you need the serial numbers as a colon-separated hex string,
+ such as C(11:22:33), you need to convert it to that form with P(community.crypto.to_serial#filter).
returned: success
- type: str
+ type: int
signature_algorithm:
- description: The algorithm used to sign the cert
+ description: The algorithm used to sign the cert.
returned: success
type: str
subject:
- description: Information about the subject of the cert (OU, CN, etc)
+ description: Information about the subject of the cert (C(OU), C(CN), etc).
returned: success
type: dict
version:
- description: The version number of the certificate
+ description: The version number of the certificate.
returned: success
type: str
'''
@@ -272,7 +278,7 @@ def main():
select_crypto_backend=dict(type='str', choices=['auto', 'cryptography'], default='auto'),
starttls=dict(type='str', choices=['mysql']),
ciphers=dict(type='list', elements='str'),
- asn1_base64=dict(type='bool', default=False),
+ asn1_base64=dict(type='bool'),
),
)
@@ -286,6 +292,15 @@ def main():
start_tls_server_type = module.params.get('starttls')
ciphers = module.params.get('ciphers')
asn1_base64 = module.params['asn1_base64']
+ if asn1_base64 is None:
+ module.deprecate(
+ 'The default value `false` for asn1_base64 is deprecated and will change to `true` in '
+ 'community.crypto 3.0.0. If you need this value, it is best to set the value explicitly '
+ 'and adjust your roles/playbooks to use `asn1_base64=true` as soon as possible',
+ version='3.0.0',
+ collection_name='community.crypto',
+ )
+ asn1_base64 = False
backend = module.params.get('select_crypto_backend')
if backend == 'auto':
diff --git a/ansible_collections/community/crypto/plugins/modules/luks_device.py b/ansible_collections/community/crypto/plugins/modules/luks_device.py
index d8b70e748..5c41eddd3 100644
--- a/ansible_collections/community/crypto/plugins/modules/luks_device.py
+++ b/ansible_collections/community/crypto/plugins/modules/luks_device.py
@@ -30,55 +30,66 @@ attributes:
options:
device:
description:
- - "Device to work with (for example C(/dev/sda1)). Needed in most cases.
- Can be omitted only when I(state=closed) together with I(name)
+ - "Device to work with (for example V(/dev/sda1)). Needed in most cases.
+ Can be omitted only when O(state=closed) together with O(name)
is provided."
type: str
state:
description:
- "Desired state of the LUKS container. Based on its value creates,
destroys, opens or closes the LUKS container on a given device."
- - "I(present) will create LUKS container unless already present.
- Requires I(device) and either I(keyfile) or I(passphrase) options
+ - "V(present) will create LUKS container unless already present.
+ Requires O(device) and either O(keyfile) or O(passphrase) options
to be provided."
- - "I(absent) will remove existing LUKS container if it exists.
- Requires I(device) or I(name) to be specified."
- - "I(opened) will unlock the LUKS container. If it does not exist
+ - "V(absent) will remove existing LUKS container if it exists.
+ Requires O(device) or O(name) to be specified."
+ - "V(opened) will unlock the LUKS container. If it does not exist
it will be created first.
- Requires I(device) and either I(keyfile) or I(passphrase)
- to be specified. Use the I(name) option to set the name of
+ Requires O(device) and either O(keyfile) or O(passphrase)
+ to be specified. Use the O(name) option to set the name of
the opened container. Otherwise the name will be
generated automatically and returned as a part of the
result."
- - "I(closed) will lock the LUKS container. However if the container
+ - "V(closed) will lock the LUKS container. However if the container
does not exist it will be created.
- Requires I(device) and either I(keyfile) or I(passphrase)
+ Requires O(device) and either O(keyfile) or O(passphrase)
options to be provided. If container does already exist
- I(device) or I(name) will suffice."
+ O(device) or O(name) will suffice."
type: str
default: present
choices: [present, absent, opened, closed]
name:
description:
- - "Sets container name when I(state=opened). Can be used
- instead of I(device) when closing the existing container
- (that is, when I(state=closed))."
+ - "Sets container name when O(state=opened). Can be used
+ instead of O(device) when closing the existing container
+ (that is, when O(state=closed))."
type: str
keyfile:
description:
- - "Used to unlock the container. Either a I(keyfile) or a
- I(passphrase) is needed for most of the operations. Parameter
+ - "Used to unlock the container. Either a O(keyfile) or a
+ O(passphrase) is needed for most of the operations. Parameter
value is the path to the keyfile with the passphrase."
- "BEWARE that working with keyfiles in plaintext is dangerous.
Make sure that they are protected."
type: path
passphrase:
description:
- - "Used to unlock the container. Either a I(passphrase) or a
- I(keyfile) is needed for most of the operations. Parameter
+ - "Used to unlock the container. Either a O(passphrase) or a
+ O(keyfile) is needed for most of the operations. Parameter
value is a string with the passphrase."
type: str
version_added: '1.0.0'
+ keyslot:
+ description:
+ - "Adds the O(keyfile) or O(passphrase) to a specific keyslot when
+ creating a new container on O(device). Parameter value is the
+ number of the keyslot."
+ - "B(Note) that a device of O(type=luks1) supports the keyslot numbers
+ V(0)-V(7) and a device of O(type=luks2) supports the keyslot numbers
+ V(0)-V(31). In order to use the keyslots V(8)-V(31) when creating a new
+ container, setting O(type) to V(luks2) is required."
+ type: int
+ version_added: '2.16.0'
keysize:
description:
- "Sets the key size only if LUKS container does not exist."
@@ -86,8 +97,8 @@ options:
version_added: '1.0.0'
new_keyfile:
description:
- - "Adds additional key to given container on I(device).
- Needs I(keyfile) or I(passphrase) option for authorization.
+ - "Adds additional key to given container on O(device).
+ Needs O(keyfile) or O(passphrase) option for authorization.
LUKS container supports up to 8 keyslots. Parameter value
is the path to the keyfile with the passphrase."
- "NOTE that adding additional keys is idempotent only since
@@ -99,8 +110,8 @@ options:
type: path
new_passphrase:
description:
- - "Adds additional passphrase to given container on I(device).
- Needs I(keyfile) or I(passphrase) option for authorization. LUKS
+ - "Adds additional passphrase to given container on O(device).
+ Needs O(keyfile) or O(passphrase) option for authorization. LUKS
container supports up to 8 keyslots. Parameter value is a string
with the new passphrase."
- "NOTE that adding additional passphrase is idempotent only since
@@ -108,34 +119,55 @@ options:
be used even if another keyslot already exists for this passphrase."
type: str
version_added: '1.0.0'
+ new_keyslot:
+ description:
+ - "Adds the additional O(new_keyfile) or O(new_passphrase) to a
+ specific keyslot on the given O(device). Parameter value is the number
+ of the keyslot."
+ - "B(Note) that a device of O(type=luks1) supports the keyslot numbers
+ V(0)-V(7) and a device of O(type=luks2) supports the keyslot numbers
+ V(0)-V(31)."
+ type: int
+ version_added: '2.16.0'
remove_keyfile:
description:
- - "Removes given key from the container on I(device). Does not
+ - "Removes given key from the container on O(device). Does not
remove the keyfile from filesystem.
Parameter value is the path to the keyfile with the passphrase."
- "NOTE that removing keys is idempotent only since
community.crypto 1.4.0. For older versions, trying to remove
a key which no longer exists results in an error."
- "NOTE that to remove the last key from a LUKS container, the
- I(force_remove_last_key) option must be set to C(true)."
+ O(force_remove_last_key) option must be set to V(true)."
- "BEWARE that working with keyfiles in plaintext is dangerous.
Make sure that they are protected."
type: path
remove_passphrase:
description:
- - "Removes given passphrase from the container on I(device).
+ - "Removes given passphrase from the container on O(device).
Parameter value is a string with the passphrase to remove."
- "NOTE that removing passphrases is idempotent only since
community.crypto 1.4.0. For older versions, trying to remove
a passphrase which no longer exists results in an error."
- "NOTE that to remove the last keyslot from a LUKS
- container, the I(force_remove_last_key) option must be set
- to C(true)."
+ container, the O(force_remove_last_key) option must be set
+ to V(true)."
type: str
version_added: '1.0.0'
+ remove_keyslot:
+ description:
+ - "Removes the key in the given slot on O(device). Needs
+ O(keyfile) or O(passphrase) for authorization."
+ - "B(Note) that a device of O(type=luks1) supports the keyslot numbers
+ V(0)-V(7) and a device of O(type=luks2) supports the keyslot numbers
+ V(0)-V(31)."
+ - "B(Note) that the given O(keyfile) or O(passphrase) must not be
+ in the slot to be removed."
+ type: int
+ version_added: '2.16.0'
force_remove_last_key:
description:
- - "If set to C(true), allows removing the last key from a container."
+ - "If set to V(true), allows removing the last key from a container."
- "BEWARE that when the last key has been removed from a container,
the container can no longer be opened!"
type: bool
@@ -145,21 +177,21 @@ options:
- "This option allow the user to create a LUKS2 format container
with label support, respectively to identify the container by
label on later usages."
- - "Will only be used on container creation, or when I(device) is
+ - "Will only be used on container creation, or when O(device) is
not specified."
- - "This cannot be specified if I(type) is set to C(luks1)."
+ - "This cannot be specified if O(type) is set to V(luks1)."
type: str
version_added: '1.0.0'
uuid:
description:
- "With this option user can identify the LUKS container by UUID."
- - "Will only be used when I(device) and I(label) are not specified."
+ - "Will only be used when O(device) and O(label) are not specified."
type: str
version_added: '1.0.0'
type:
description:
- "This option allow the user explicit define the format of LUKS
- container that wants to work with. Options are C(luks1) or C(luks2)"
+ container that wants to work with. Options are V(luks1) or V(luks2)"
type: str
choices: [luks1, luks2]
version_added: '1.0.0'
@@ -168,8 +200,8 @@ options:
- "This option allows the user to define the cipher specification
string for the LUKS container."
- "Will only be used on container creation."
- - "For pre-2.6.10 kernels, use C(aes-plain) as they do not understand
- the new cipher spec strings. To use ESSIV, use C(aes-cbc-essiv:sha256)."
+ - "For pre-2.6.10 kernels, use V(aes-plain) as they do not understand
+ the new cipher spec strings. To use ESSIV, use V(aes-cbc-essiv:sha256)."
type: str
version_added: '1.1.0'
hash:
@@ -193,12 +225,12 @@ options:
- Specify the iteration time used for the PBKDF.
- Note that this is in B(seconds), not in milliseconds as on the
command line.
- - Mutually exclusive with I(iteration_count).
+ - Mutually exclusive with O(pbkdf.iteration_count).
type: float
iteration_count:
description:
- Specify the iteration count used for the PBKDF.
- - Mutually exclusive with I(iteration_time).
+ - Mutually exclusive with O(pbkdf.iteration_time).
type: int
algorithm:
description:
@@ -261,19 +293,26 @@ options:
persistent:
description:
- "Allows the user to store options into container's metadata persistently and automatically use them next time.
- Only I(perf_same_cpu_crypt), I(perf_submit_from_crypt_cpus), I(perf_no_read_workqueue), and I(perf_no_write_workqueue)
- can be stored persistently."
+ Only O(perf_same_cpu_crypt), O(perf_submit_from_crypt_cpus), O(perf_no_read_workqueue), O(perf_no_write_workqueue),
+ and O(allow_discards) can be stored persistently."
- "Will only work with LUKS2 containers."
- "Will only be used when opening containers."
type: bool
default: false
version_added: '2.3.0'
+ allow_discards:
+ description:
+ - "Allow discards (also known as TRIM) requests for device."
+ - "Will only be used when opening containers."
+ type: bool
+ default: false
+ version_added: '2.17.0'
requirements:
- "cryptsetup"
- - "wipefs (when I(state) is C(absent))"
+ - "wipefs (when O(state) is V(absent))"
- "lsblk"
- - "blkid (when I(label) or I(uuid) options are used)"
+ - "blkid (when O(label) or O(uuid) options are used)"
author: Jan Pokorny (@japokorn)
'''
@@ -377,12 +416,32 @@ EXAMPLES = '''
state: "present"
keyfile: "/vault/keyfile"
type: luks2
+
+- name: Create a container with key in slot 4
+ community.crypto.luks_device:
+ device: "/dev/loop0"
+ state: "present"
+ keyfile: "/vault/keyfile"
+ keyslot: 4
+
+- name: Add a new key in slot 5
+ community.crypto.luks_device:
+ device: "/dev/loop0"
+ keyfile: "/vault/keyfile"
+ new_keyfile: "/vault/keyfile"
+ new_keyslot: 5
+
+- name: Remove the key from slot 4 (given keyfile must not be slot 4)
+ community.crypto.luks_device:
+ device: "/dev/loop0"
+ keyfile: "/vault/keyfile"
+ remove_keyslot: 4
'''
RETURN = '''
name:
description:
- When I(state=opened) returns (generated or given) name
+ When O(state=opened) returns (generated or given) name
of LUKS container. Returns None if no name is supplied.
returned: success
type: str
@@ -523,6 +582,29 @@ class CryptHandler(Handler):
result = self._run_command([self._cryptsetup_bin, 'isLuks', device])
return result[RETURN_CODE] == 0
+ def get_luks_type(self, device):
+ ''' get the luks type of a device
+ '''
+ if self.is_luks(device):
+ with open(device, 'rb') as f:
+ for offset in LUKS2_HEADER_OFFSETS:
+ f.seek(offset)
+ data = f.read(LUKS_HEADER_L)
+ if data == LUKS2_HEADER2:
+ return 'luks2'
+ return 'luks1'
+ return None
+
+ def is_luks_slot_set(self, device, keyslot):
+ ''' check if a keyslot is set
+ '''
+ result = self._run_command([self._cryptsetup_bin, 'luksDump', device])
+ if result[RETURN_CODE] != 0:
+ raise ValueError('Error while dumping LUKS header from %s' % (device, ))
+ result_luks1 = 'Key Slot %d: ENABLED' % (keyslot) in result[STDOUT]
+ result_luks2 = ' %d: luks2' % (keyslot) in result[STDOUT]
+ return result_luks1 or result_luks2
+
def _add_pbkdf_options(self, options, pbkdf):
if pbkdf['iteration_time'] is not None:
options.extend(['--iter-time', str(int(pbkdf['iteration_time'] * 1000))])
@@ -535,7 +617,7 @@ class CryptHandler(Handler):
if pbkdf['parallel'] is not None:
options.extend(['--pbkdf-parallel', str(pbkdf['parallel'])])
- def run_luks_create(self, device, keyfile, passphrase, keysize, cipher, hash_, sector_size, pbkdf):
+ def run_luks_create(self, device, keyfile, passphrase, keyslot, keysize, cipher, hash_, sector_size, pbkdf):
# create a new luks container; use batch mode to auto confirm
luks_type = self._module.params['type']
label = self._module.params['label']
@@ -556,6 +638,8 @@ class CryptHandler(Handler):
self._add_pbkdf_options(options, pbkdf)
if sector_size is not None:
options.extend(['--sector-size', str(sector_size)])
+ if keyslot is not None:
+ options.extend(['--key-slot', str(keyslot)])
args = [self._cryptsetup_bin, 'luksFormat']
args.extend(options)
@@ -569,7 +653,7 @@ class CryptHandler(Handler):
% (device, result[STDERR]))
def run_luks_open(self, device, keyfile, passphrase, perf_same_cpu_crypt, perf_submit_from_crypt_cpus,
- perf_no_read_workqueue, perf_no_write_workqueue, persistent, name):
+ perf_no_read_workqueue, perf_no_write_workqueue, persistent, allow_discards, name):
args = [self._cryptsetup_bin]
if keyfile:
args.extend(['--key-file', keyfile])
@@ -583,6 +667,8 @@ class CryptHandler(Handler):
args.extend(['--perf-no_write_workqueue'])
if persistent:
args.extend(['--persistent'])
+ if allow_discards:
+ args.extend(['--allow-discards'])
args.extend(['open', '--type', 'luks', device, name])
result = self._run_command(args, data=passphrase)
@@ -615,7 +701,7 @@ class CryptHandler(Handler):
raise ValueError('Error while wiping LUKS container signatures for %s: %s' % (device, exc))
def run_luks_add_key(self, device, keyfile, passphrase, new_keyfile,
- new_passphrase, pbkdf):
+ new_passphrase, new_keyslot, pbkdf):
''' Add new key from a keyfile or passphrase to given 'device';
authentication done using 'keyfile' or 'passphrase'.
Raises ValueError when command fails.
@@ -625,6 +711,9 @@ class CryptHandler(Handler):
if pbkdf is not None:
self._add_pbkdf_options(args, pbkdf)
+ if new_keyslot is not None:
+ args.extend(['--key-slot', str(new_keyslot)])
+
if keyfile:
args.extend(['--key-file', keyfile])
else:
@@ -640,7 +729,7 @@ class CryptHandler(Handler):
raise ValueError('Error while adding new LUKS keyslot to %s: %s'
% (device, result[STDERR]))
- def run_luks_remove_key(self, device, keyfile, passphrase,
+ def run_luks_remove_key(self, device, keyfile, passphrase, keyslot,
force_remove_last_key=False):
''' Remove key from given device
Raises ValueError when command fails
@@ -675,7 +764,10 @@ class CryptHandler(Handler):
"To be able to remove a key, please set "
"`force_remove_last_key` to `true`." % device)
- args = [self._cryptsetup_bin, 'luksRemoveKey', device, '-q']
+ if keyslot is None:
+ args = [self._cryptsetup_bin, 'luksRemoveKey', device, '-q']
+ else:
+ args = [self._cryptsetup_bin, 'luksKillSlot', device, '-q', str(keyslot)]
if keyfile:
args.extend(['--key-file', keyfile])
result = self._run_command(args, data=passphrase)
@@ -683,7 +775,7 @@ class CryptHandler(Handler):
raise ValueError('Error while removing LUKS key from %s: %s'
% (device, result[STDERR]))
- def luks_test_key(self, device, keyfile, passphrase):
+ def luks_test_key(self, device, keyfile, passphrase, keyslot=None):
''' Check whether the keyfile or passphrase works.
Raises ValueError when command fails.
'''
@@ -695,12 +787,22 @@ class CryptHandler(Handler):
else:
data = passphrase
+ if keyslot is not None:
+ args.extend(['--key-slot', str(keyslot)])
+
result = self._run_command(args, data=data)
if result[RETURN_CODE] == 0:
return True
for output in (STDOUT, STDERR):
if 'No key available with this passphrase' in result[output]:
return False
+ if 'No usable keyslot is available.' in result[output]:
+ return False
+
+ # This check is necessary due to cryptsetup in version 2.0.3 not printing 'No usable keyslot is available'
+ # when using the --key-slot parameter in combination with --test-passphrase
+ if result[RETURN_CODE] == 1 and keyslot is not None and result[STDOUT] == '' and result[STDERR] == '':
+ return False
raise ValueError('Error while testing whether keyslot exists on %s: %s'
% (device, result[STDERR]))
@@ -812,12 +914,20 @@ class ConditionsHandler(Handler):
self._module.fail_json(msg="Contradiction in setup: Asking to "
"add a key to absent LUKS.")
- return not self._crypthandler.luks_test_key(self.device, self._module.params['new_keyfile'], self._module.params['new_passphrase'])
+ key_present = self._crypthandler.luks_test_key(self.device, self._module.params['new_keyfile'], self._module.params['new_passphrase'])
+ if self._module.params['new_keyslot'] is not None:
+ key_present_slot = self._crypthandler.luks_test_key(self.device, self._module.params['new_keyfile'], self._module.params['new_passphrase'],
+ self._module.params['new_keyslot'])
+ if key_present and not key_present_slot:
+ self._module.fail_json(msg="Trying to add key that is already present in another slot")
+
+ return not key_present
def luks_remove_key(self):
if (self.device is None or
(self._module.params['remove_keyfile'] is None and
- self._module.params['remove_passphrase'] is None)):
+ self._module.params['remove_passphrase'] is None and
+ self._module.params['remove_keyslot'] is None)):
# conditions for removing a key not fulfilled
return False
@@ -825,6 +935,15 @@ class ConditionsHandler(Handler):
self._module.fail_json(msg="Contradiction in setup: Asking to "
"remove a key from absent LUKS.")
+ if self._module.params['remove_keyslot'] is not None:
+ if not self._crypthandler.is_luks_slot_set(self.device, self._module.params['remove_keyslot']):
+ return False
+ result = self._crypthandler.luks_test_key(self.device, self._module.params['keyfile'], self._module.params['passphrase'])
+ if self._crypthandler.luks_test_key(self.device, self._module.params['keyfile'], self._module.params['passphrase'],
+ self._module.params['remove_keyslot']):
+ self._module.fail_json(msg='Cannot remove keyslot with keyfile or passphrase in same slot.')
+ return result
+
return self._crypthandler.luks_test_key(self.device, self._module.params['remove_keyfile'], self._module.params['remove_passphrase'])
def luks_remove(self):
@@ -832,6 +951,19 @@ class ConditionsHandler(Handler):
self._module.params['state'] == 'absent' and
self._crypthandler.is_luks(self.device))
+ def validate_keyslot(self, param, luks_type):
+ if self._module.params[param] is not None:
+ if luks_type is None and param == 'keyslot':
+ if 8 <= self._module.params[param] <= 31:
+ self._module.fail_json(msg="You must specify type=luks2 when creating a new LUKS device to use keyslots 8-31.")
+ elif not (0 <= self._module.params[param] <= 7):
+ self._module.fail_json(msg="When not specifying a type, only the keyslots 0-7 are allowed.")
+
+ if luks_type == 'luks1' and not 0 <= self._module.params[param] <= 7:
+ self._module.fail_json(msg="%s must be between 0 and 7 when using LUKS1." % self._module.params[param])
+ elif luks_type == 'luks2' and not 0 <= self._module.params[param] <= 31:
+ self._module.fail_json(msg="%s must be between 0 and 31 when using LUKS2." % self._module.params[param])
+
def run_module():
# available arguments/parameters that a user can pass
@@ -845,6 +977,9 @@ def run_module():
passphrase=dict(type='str', no_log=True),
new_passphrase=dict(type='str', no_log=True),
remove_passphrase=dict(type='str', no_log=True),
+ keyslot=dict(type='int', no_log=False),
+ new_keyslot=dict(type='int', no_log=False),
+ remove_keyslot=dict(type='int', no_log=False),
force_remove_last_key=dict(type='bool', default=False),
keysize=dict(type='int'),
label=dict(type='str'),
@@ -869,12 +1004,13 @@ def run_module():
perf_no_read_workqueue=dict(type='bool', default=False),
perf_no_write_workqueue=dict(type='bool', default=False),
persistent=dict(type='bool', default=False),
+ allow_discards=dict(type='bool', default=False),
)
mutually_exclusive = [
('keyfile', 'passphrase'),
('new_keyfile', 'new_passphrase'),
- ('remove_keyfile', 'remove_passphrase')
+ ('remove_keyfile', 'remove_passphrase', 'remove_keyslot')
]
# seed the result dict in the object
@@ -904,6 +1040,17 @@ def run_module():
if module.params['label'] is not None and module.params['type'] == 'luks1':
module.fail_json(msg='You cannot combine type luks1 with the label option.')
+ if module.params['keyslot'] is not None or module.params['new_keyslot'] is not None or module.params['remove_keyslot'] is not None:
+ luks_type = crypt.get_luks_type(conditions.get_device_name())
+ if luks_type is None and module.params['type'] is not None:
+ luks_type = module.params['type']
+ for param in ['keyslot', 'new_keyslot', 'remove_keyslot']:
+ conditions.validate_keyslot(param, luks_type)
+
+ for param in ['new_keyslot', 'remove_keyslot']:
+ if module.params[param] is not None and module.params['keyfile'] is None and module.params['passphrase'] is None:
+ module.fail_json(msg="Removing a keyslot requires the passphrase or keyfile of another slot.")
+
# The conditions are in order to allow more operations in one run.
# (e.g. create luks and add a key to it)
@@ -914,6 +1061,7 @@ def run_module():
crypt.run_luks_create(conditions.device,
module.params['keyfile'],
module.params['passphrase'],
+ module.params['keyslot'],
module.params['keysize'],
module.params['cipher'],
module.params['hash'],
@@ -949,6 +1097,7 @@ def run_module():
module.params['perf_no_read_workqueue'],
module.params['perf_no_write_workqueue'],
module.params['persistent'],
+ module.params['allow_discards'],
name)
except ValueError as e:
module.fail_json(msg="luks_device error: %s" % e)
@@ -986,6 +1135,7 @@ def run_module():
module.params['passphrase'],
module.params['new_keyfile'],
module.params['new_passphrase'],
+ module.params['new_keyslot'],
module.params['pbkdf'])
except ValueError as e:
module.fail_json(msg="luks_device error: %s" % e)
@@ -1001,6 +1151,7 @@ def run_module():
crypt.run_luks_remove_key(conditions.device,
module.params['remove_keyfile'],
module.params['remove_passphrase'],
+ module.params['remove_keyslot'],
force_remove_last_key=last_key)
except ValueError as e:
module.fail_json(msg="luks_device error: %s" % e)
diff --git a/ansible_collections/community/crypto/plugins/modules/openssh_cert.py b/ansible_collections/community/crypto/plugins/modules/openssh_cert.py
index 8f428107a..8e864cd7d 100644
--- a/ansible_collections/community/crypto/plugins/modules/openssh_cert.py
+++ b/ansible_collections/community/crypto/plugins/modules/openssh_cert.py
@@ -40,13 +40,13 @@ options:
type:
description:
- Whether the module should generate a host or a user certificate.
- - Required if I(state) is C(present).
+ - Required if O(state) is V(present).
type: str
choices: ['host', 'user']
force:
description:
- Should the certificate be regenerated even if it already exists and is valid.
- - Equivalent to I(regenerate=always).
+ - Equivalent to O(regenerate=always).
type: bool
default: false
path:
@@ -56,16 +56,16 @@ options:
required: true
regenerate:
description:
- - When C(never) the task will fail if a certificate already exists at I(path) and is unreadable
+ - When V(never) the task will fail if a certificate already exists at O(path) and is unreadable
otherwise a new certificate will only be generated if there is no existing certificate.
- - When C(fail) the task will fail if a certificate already exists at I(path) and does not
+ - When V(fail) the task will fail if a certificate already exists at O(path) and does not
match the module's options.
- - When C(partial_idempotence) an existing certificate will be regenerated based on
- I(serial), I(signature_algorithm), I(type), I(valid_from), I(valid_to), I(valid_at), and I(principals).
- I(valid_from) and I(valid_to) can be excluded by I(ignore_timestamps=true).
- - When C(full_idempotence) I(identifier), I(options), I(public_key), and I(signing_key)
+ - When V(partial_idempotence) an existing certificate will be regenerated based on
+ O(serial_number), O(signature_algorithm), O(type), O(valid_from), O(valid_to), O(valid_at), and O(principals).
+ O(valid_from) and O(valid_to) can be excluded by O(ignore_timestamps=true).
+ - When V(full_idempotence) O(identifier), O(options), O(public_key), and O(signing_key)
are also considered when compared against an existing certificate.
- - C(always) is equivalent to I(force=true).
+ - V(always) is equivalent to O(force=true).
type: str
choices:
- never
@@ -78,14 +78,14 @@ options:
signature_algorithm:
description:
- As of OpenSSH 8.2 the SHA-1 signature algorithm for RSA keys has been disabled and C(ssh) will refuse
- host certificates signed with the SHA-1 algorithm. OpenSSH 8.1 made C(rsa-sha2-512) the default algorithm
+ host certificates signed with the SHA-1 algorithm. OpenSSH 8.1 made V(rsa-sha2-512) the default algorithm
when acting as a CA and signing certificates with a RSA key. However, for OpenSSH versions less than 8.1
- the SHA-2 signature algorithms, C(rsa-sha2-256) or C(rsa-sha2-512), must be specified using this option
+ the SHA-2 signature algorithms, V(rsa-sha2-256) or V(rsa-sha2-512), must be specified using this option
if compatibility with newer C(ssh) clients is required. Conversely if hosts using OpenSSH version 8.2
- or greater must remain compatible with C(ssh) clients using OpenSSH less than 7.2, then C(ssh-rsa)
- can be used when generating host certificates (a corresponding change to the sshd_config to add C(ssh-rsa)
+ or greater must remain compatible with C(ssh) clients using OpenSSH less than 7.2, then V(ssh-rsa)
+ can be used when generating host certificates (a corresponding change to the sshd_config to add V(ssh-rsa)
to the C(CASignatureAlgorithms) keyword is also required).
- - Using any value for this option with a non-RSA I(signing_key) will cause this module to fail.
+ - Using any value for this option with a non-RSA O(signing_key) will cause this module to fail.
- "Note: OpenSSH versions prior to 7.2 do not support SHA-2 signature algorithms for RSA keys and OpenSSH
versions prior to 7.3 do not support SHA-2 signature algorithms for certificates."
- See U(https://www.openssh.com/txt/release-8.2) for more information.
@@ -98,14 +98,14 @@ options:
signing_key:
description:
- The path to the private openssh key that is used for signing the public key in order to generate the certificate.
- - If the private key is on a PKCS#11 token (I(pkcs11_provider)), set this to the path to the public key instead.
- - Required if I(state) is C(present).
+ - If the private key is on a PKCS#11 token (O(pkcs11_provider)), set this to the path to the public key instead.
+ - Required if O(state) is V(present).
type: path
pkcs11_provider:
description:
- To use a signing key that resides on a PKCS#11 token, set this to the name (or full path) of the shared library to use with the token.
Usually C(libpkcs11.so).
- - If this is set, I(signing_key) needs to point to a file containing the public key of the CA.
+ - If this is set, O(signing_key) needs to point to a file containing the public key of the CA.
type: str
version_added: 1.1.0
use_agent:
@@ -117,37 +117,37 @@ options:
public_key:
description:
- The path to the public key that will be signed with the signing key in order to generate the certificate.
- - Required if I(state) is C(present).
+ - Required if O(state) is V(present).
type: path
valid_from:
description:
- "The point in time the certificate is valid from. Time can be specified either as relative time or as absolute timestamp.
Time will always be interpreted as UTC. Valid formats are: C([+-]timespec | YYYY-MM-DD | YYYY-MM-DDTHH:MM:SS | YYYY-MM-DD HH:MM:SS | always)
- where timespec can be an integer + C([w | d | h | m | s]) (for example C(+32w1d2h)).
+ where timespec can be an integer + C([w | d | h | m | s]) (for example V(+32w1d2h)).
Note that if using relative time this module is NOT idempotent."
- - "The value C(always) is only supported for OpenSSH 7.7 and greater, however, the value C(1970-01-01T00:00:01)
+ - "The value V(always) is only supported for OpenSSH 7.7 and greater, however, the value V(1970-01-01T00:00:01)
can be used with earlier versions as an equivalent expression."
- - "To ignore this value during comparison with an existing certificate set I(ignore_timestamps=true)."
- - Required if I(state) is C(present).
+ - "To ignore this value during comparison with an existing certificate set O(ignore_timestamps=true)."
+ - Required if O(state) is V(present).
type: str
valid_to:
description:
- "The point in time the certificate is valid to. Time can be specified either as relative time or as absolute timestamp.
Time will always be interpreted as UTC. Valid formats are: C([+-]timespec | YYYY-MM-DD | YYYY-MM-DDTHH:MM:SS | YYYY-MM-DD HH:MM:SS | forever)
- where timespec can be an integer + C([w | d | h | m | s]) (for example C(+32w1d2h)).
+ where timespec can be an integer + C([w | d | h | m | s]) (for example V(+32w1d2h)).
Note that if using relative time this module is NOT idempotent."
- - "To ignore this value during comparison with an existing certificate set I(ignore_timestamps=true)."
- - Required if I(state) is C(present).
+ - "To ignore this value during comparison with an existing certificate set O(ignore_timestamps=true)."
+ - Required if O(state) is V(present).
type: str
valid_at:
description:
- "Check if the certificate is valid at a certain point in time. If it is not the certificate will be regenerated.
- Time will always be interpreted as UTC. Mainly to be used with relative timespec for I(valid_from) and / or I(valid_to).
+ Time will always be interpreted as UTC. Mainly to be used with relative timespec for O(valid_from) and / or O(valid_to).
Note that if using relative time this module is NOT idempotent."
type: str
ignore_timestamps:
description:
- - "Whether the I(valid_from) and I(valid_to) timestamps should be ignored for idempotency checks."
+ - "Whether the O(valid_from) and O(valid_to) timestamps should be ignored for idempotency checks."
- "However, the values will still be applied to a new certificate if it meets any other necessary conditions for generation/regeneration."
type: bool
default: false
@@ -161,20 +161,20 @@ options:
options:
description:
- "Specify certificate options when signing a key. The option that are valid for user certificates are:"
- - "C(clear): Clear all enabled permissions. This is useful for clearing the default set of permissions so permissions may be added individually."
- - "C(force-command=command): Forces the execution of command instead of any shell or
+ - "V(clear): Clear all enabled permissions. This is useful for clearing the default set of permissions so permissions may be added individually."
+ - "V(force-command=command): Forces the execution of command instead of any shell or
command specified by the user when the certificate is used for authentication."
- - "C(no-agent-forwarding): Disable ssh-agent forwarding (permitted by default)."
- - "C(no-port-forwarding): Disable port forwarding (permitted by default)."
- - "C(no-pty): Disable PTY allocation (permitted by default)."
- - "C(no-user-rc): Disable execution of C(~/.ssh/rc) by sshd (permitted by default)."
- - "C(no-x11-forwarding): Disable X11 forwarding (permitted by default)"
- - "C(permit-agent-forwarding): Allows ssh-agent forwarding."
- - "C(permit-port-forwarding): Allows port forwarding."
- - "C(permit-pty): Allows PTY allocation."
- - "C(permit-user-rc): Allows execution of C(~/.ssh/rc) by sshd."
- - "C(permit-x11-forwarding): Allows X11 forwarding."
- - "C(source-address=address_list): Restrict the source addresses from which the certificate is considered valid.
+ - "V(no-agent-forwarding): Disable ssh-agent forwarding (permitted by default)."
+ - "V(no-port-forwarding): Disable port forwarding (permitted by default)."
+ - "V(no-pty): Disable PTY allocation (permitted by default)."
+ - "V(no-user-rc): Disable execution of C(~/.ssh/rc) by sshd (permitted by default)."
+ - "V(no-x11-forwarding): Disable X11 forwarding (permitted by default)"
+ - "V(permit-agent-forwarding): Allows ssh-agent forwarding."
+ - "V(permit-port-forwarding): Allows port forwarding."
+ - "V(permit-pty): Allows PTY allocation."
+ - "V(permit-user-rc): Allows execution of C(~/.ssh/rc) by sshd."
+ - "V(permit-x11-forwarding): Allows X11 forwarding."
+ - "V(source-address=address_list): Restrict the source addresses from which the certificate is considered valid.
The C(address_list) is a comma-separated list of one or more address/netmask pairs in CIDR format."
- "At present, no options are valid for host keys."
type: list
@@ -190,7 +190,13 @@ options:
The certificate serial number may be used in a KeyRevocationList.
The serial number may be omitted for checks, but must be specified again for a new certificate.
Note: The default value set by ssh-keygen is 0."
+ - This option accepts an B(integer). If you want to provide serial numbers as colon-separated hex strings,
+ such as C(11:22:33), you need to convert them to an integer with P(community.crypto.parse_serial#filter).
type: int
+
+seealso:
+ - plugin: community.crypto.parse_serial
+ plugin_type: filter
'''
EXAMPLES = '''
@@ -497,7 +503,10 @@ class Certificate(OpensshModule):
if self.state != 'present':
return {}
- certificate_info = self.ssh_keygen.get_certificate_info(self.path)[1]
+ certificate_info = self.ssh_keygen.get_certificate_info(
+ self.path,
+ check_rc=self.state == 'present' and not self.module.check_mode,
+ )[1]
return {
'type': self.type,
diff --git a/ansible_collections/community/crypto/plugins/modules/openssh_keypair.py b/ansible_collections/community/crypto/plugins/modules/openssh_keypair.py
index 35ee6d631..7bb35b27f 100644
--- a/ansible_collections/community/crypto/plugins/modules/openssh_keypair.py
+++ b/ansible_collections/community/crypto/plugins/modules/openssh_keypair.py
@@ -15,12 +15,12 @@ author: "David Kainz (@lolcube)"
short_description: Generate OpenSSH private and public keys
description:
- "This module allows one to (re)generate OpenSSH private and public keys. It uses
- ssh-keygen to generate keys. One can generate C(rsa), C(dsa), C(rsa1), C(ed25519)
- or C(ecdsa) private keys."
+ ssh-keygen to generate keys. One can generate V(rsa), V(dsa), V(rsa1), V(ed25519)
+ or V(ecdsa) private keys."
requirements:
- - ssh-keygen (if I(backend=openssh))
- - cryptography >= 2.6 (if I(backend=cryptography) and OpenSSH < 7.8 is installed)
- - cryptography >= 3.0 (if I(backend=cryptography) and OpenSSH >= 7.8 is installed)
+ - ssh-keygen (if O(backend=openssh))
+ - cryptography >= 2.6 (if O(backend=cryptography) and OpenSSH < 7.8 is installed)
+ - cryptography >= 3.0 (if O(backend=cryptography) and OpenSSH >= 7.8 is installed)
extends_documentation_fragment:
- ansible.builtin.files
- community.crypto.attributes
@@ -49,8 +49,8 @@ options:
type: int
type:
description:
- - "The algorithm used to generate the SSH private key. C(rsa1) is for protocol version 1.
- C(rsa1) is deprecated and may not be supported by every version of ssh-keygen."
+ - "The algorithm used to generate the SSH private key. V(rsa1) is for protocol version 1.
+ V(rsa1) is deprecated and may not be supported by every version of ssh-keygen."
type: str
default: rsa
choices: ['rsa', 'dsa', 'rsa1', 'ecdsa', 'ed25519']
@@ -71,18 +71,18 @@ options:
passphrase:
description:
- Passphrase used to decrypt an existing private key or encrypt a newly generated private key.
- - Passphrases are not supported for I(type=rsa1).
- - Can only be used when I(backend=cryptography), or when I(backend=auto) and a required C(cryptography) version is installed.
+ - Passphrases are not supported for O(type=rsa1).
+ - Can only be used when O(backend=cryptography), or when O(backend=auto) and a required C(cryptography) version is installed.
type: str
version_added: 1.7.0
private_key_format:
description:
- - Used when I(backend=cryptography) to select a format for the private key at the provided I(path).
- - When set to C(auto) this module will match the key format of the installed OpenSSH version.
+ - Used when O(backend=cryptography) to select a format for the private key at the provided O(path).
+ - When set to V(auto) this module will match the key format of the installed OpenSSH version.
- For OpenSSH < 7.8 private keys will be in PKCS1 format except ed25519 keys which will be in OpenSSH format.
- For OpenSSH >= 7.8 all private key types will be in the OpenSSH format.
- - Using this option when I(regenerate=partial_idempotence) or I(regenerate=full_idempotence) will cause
- a new keypair to be generated if the private key's format does not match the value of I(private_key_format).
+ - Using this option when O(regenerate=partial_idempotence) or O(regenerate=full_idempotence) will cause
+ a new keypair to be generated if the private key's format does not match the value of O(private_key_format).
This module will not however convert existing private keys between formats.
type: str
default: auto
@@ -94,8 +94,8 @@ options:
version_added: 1.7.0
backend:
description:
- - Selects between the C(cryptography) library or the OpenSSH binary C(opensshbin).
- - C(auto) will default to C(opensshbin) unless the OpenSSH binary is not installed or when using I(passphrase).
+ - Selects between the V(cryptography) library or the OpenSSH binary V(opensshbin).
+ - V(auto) will default to V(opensshbin) unless the OpenSSH binary is not installed or when using O(passphrase).
type: str
default: auto
choices:
@@ -109,24 +109,24 @@ options:
The module will always generate a new key if the destination file does not exist.
- By default, the key will be regenerated when it does not match the module's options,
except when the key cannot be read or the passphrase does not match. Please note that
- this B(changed) for Ansible 2.10. For Ansible 2.9, the behavior was as if C(full_idempotence)
+ this B(changed) for Ansible 2.10. For Ansible 2.9, the behavior was as if V(full_idempotence)
is specified.
- - If set to C(never), the module will fail if the key cannot be read or the passphrase
+ - If set to V(never), the module will fail if the key cannot be read or the passphrase
is not matching, and will never regenerate an existing key.
- - If set to C(fail), the module will fail if the key does not correspond to the module's
+ - If set to V(fail), the module will fail if the key does not correspond to the module's
options.
- - If set to C(partial_idempotence), the key will be regenerated if it does not conform to
+ - If set to V(partial_idempotence), the key will be regenerated if it does not conform to
the module's options. The key is B(not) regenerated if it cannot be read (broken file),
the key is protected by an unknown passphrase, or when they key is not protected by a
passphrase, but a passphrase is specified.
- - If set to C(full_idempotence), the key will be regenerated if it does not conform to the
+ - If set to V(full_idempotence), the key will be regenerated if it does not conform to the
module's options. This is also the case if the key cannot be read (broken file), the key
is protected by an unknown passphrase, or when they key is not protected by a passphrase,
but a passphrase is specified. Make sure you have a B(backup) when using this option!
- - If set to C(always), the module will always regenerate the key. This is equivalent to
- setting I(force) to C(true).
+ - If set to V(always), the module will always regenerate the key. This is equivalent to
+ setting O(force) to V(true).
- Note that adjusting the comment and the permissions can be changed without regeneration.
- Therefore, even for C(never), the task can result in changed.
+ Therefore, even for V(never), the task can result in changed.
type: str
choices:
- never
@@ -138,8 +138,8 @@ options:
version_added: '1.0.0'
notes:
- In case the ssh key is broken or password protected, the module will fail.
- Set the I(force) option to C(true) if you want to regenerate the keypair.
- - In the case a custom C(mode), C(group), C(owner), or other file attribute is provided it will be applied to both key files.
+ Set the O(force) option to V(true) if you want to regenerate the keypair.
+ - In the case a custom O(mode), O(group), O(owner), or other file attribute is provided it will be applied to both key files.
'''
EXAMPLES = '''
diff --git a/ansible_collections/community/crypto/plugins/modules/openssl_csr.py b/ansible_collections/community/crypto/plugins/modules/openssl_csr.py
index 69b663b23..01a748e79 100644
--- a/ansible_collections/community/crypto/plugins/modules/openssl_csr.py
+++ b/ansible_collections/community/crypto/plugins/modules/openssl_csr.py
@@ -17,7 +17,7 @@ short_description: Generate OpenSSL Certificate Signing Request (CSR)
description:
- "Please note that the module regenerates an existing CSR if it does not match the module's
options, or if it seems to be corrupt. If you are concerned that this could overwrite
- your existing CSR, consider using the I(backup) option."
+ your existing CSR, consider using the O(backup) option."
author:
- Yanis Guenane (@Spredzy)
- Felix Fontein (@felixfontein)
@@ -58,7 +58,7 @@ options:
default: false
return_content:
description:
- - If set to C(true), will return the (current or generated) CSR's content as I(csr).
+ - If set to V(true), will return the (current or generated) CSR's content as RV(csr).
type: bool
default: false
version_added: "1.0.0"
@@ -173,7 +173,7 @@ RETURN = r'''
privatekey:
description:
- Path to the TLS/SSL private key the CSR was generated for
- - Will be C(none) if the private key has been provided in I(privatekey_content).
+ - Will be V(none) if the private key has been provided in O(privatekey_content).
returned: changed or success
type: str
sample: /etc/ssl/private/ansible.com.pem
@@ -234,12 +234,12 @@ name_constraints_excluded:
version_added: 1.1.0
backup_file:
description: Name of backup file created.
- returned: changed and if I(backup) is C(true)
+ returned: changed and if O(backup) is V(true)
type: str
sample: /path/to/www.ansible.com.csr.2019-03-09@11:22~
csr:
description: The (current or generated) CSR's content.
- returned: if I(state) is C(present) and I(return_content) is C(true)
+ returned: if O(state) is V(present) and O(return_content) is V(true)
type: str
version_added: "1.0.0"
'''
diff --git a/ansible_collections/community/crypto/plugins/modules/openssl_csr_info.py b/ansible_collections/community/crypto/plugins/modules/openssl_csr_info.py
index 1ef07e733..fc7eaf18e 100644
--- a/ansible_collections/community/crypto/plugins/modules/openssl_csr_info.py
+++ b/ansible_collections/community/crypto/plugins/modules/openssl_csr_info.py
@@ -32,19 +32,19 @@ options:
path:
description:
- Remote absolute path where the CSR file is loaded from.
- - Either I(path) or I(content) must be specified, but not both.
+ - Either O(path) or O(content) must be specified, but not both.
type: path
content:
description:
- Content of the CSR file.
- - Either I(path) or I(content) must be specified, but not both.
+ - Either O(path) or O(content) must be specified, but not both.
type: str
version_added: "1.0.0"
select_crypto_backend:
description:
- Determines which crypto backend to use.
- - The default choice is C(auto), which tries to use C(cryptography) if available.
- - If set to C(cryptography), will try to use the L(cryptography,https://cryptography.io/) library.
+ - The default choice is V(auto), which tries to use C(cryptography) if available.
+ - If set to V(cryptography), will try to use the L(cryptography,https://cryptography.io/) library.
type: str
default: auto
choices: [ auto, cryptography ]
@@ -52,10 +52,11 @@ options:
seealso:
- module: community.crypto.openssl_csr
- module: community.crypto.openssl_csr_pipe
- - ref: community.crypto.openssl_csr_info filter <ansible_collections.community.crypto.openssl_csr_info_filter>
- # - plugin: community.crypto.openssl_csr_info
- # plugin_type: filter
+ - plugin: community.crypto.openssl_csr_info
+ plugin_type: filter
description: A filter variant of this module.
+ - plugin: community.crypto.to_serial
+ plugin_type: filter
'''
EXAMPLES = r'''
@@ -79,11 +80,11 @@ RETURN = r'''
signature_valid:
description:
- Whether the CSR's signature is valid.
- - In case the check returns C(false), the module will fail.
+ - In case the check returns V(false), the module will fail.
returned: success
type: bool
basic_constraints:
- description: Entries in the C(basic_constraints) extension, or C(none) if extension is not present.
+ description: Entries in the C(basic_constraints) extension, or V(none) if extension is not present.
returned: success
type: list
elements: str
@@ -93,7 +94,7 @@ basic_constraints_critical:
returned: success
type: bool
extended_key_usage:
- description: Entries in the C(extended_key_usage) extension, or C(none) if extension is not present.
+ description: Entries in the C(extended_key_usage) extension, or V(none) if extension is not present.
returned: success
type: list
elements: str
@@ -124,7 +125,7 @@ extensions_by_oid:
sample: "MAMCAQU="
sample: {"1.3.6.1.5.5.7.1.24": { "critical": false, "value": "MAMCAQU="}}
key_usage:
- description: Entries in the C(key_usage) extension, or C(none) if extension is not present.
+ description: Entries in the C(key_usage) extension, or V(none) if extension is not present.
returned: success
type: str
sample: [Key Agreement, Data Encipherment]
@@ -134,8 +135,8 @@ key_usage_critical:
type: bool
subject_alt_name:
description:
- - Entries in the C(subject_alt_name) extension, or C(none) if extension is not present.
- - See I(name_encoding) for how IDNs are handled.
+ - Entries in the C(subject_alt_name) extension, or V(none) if extension is not present.
+ - See O(name_encoding) for how IDNs are handled.
returned: success
type: list
elements: str
@@ -145,7 +146,7 @@ subject_alt_name_critical:
returned: success
type: bool
ocsp_must_staple:
- description: C(true) if the OCSP Must Staple extension is present, C(none) otherwise.
+ description: V(true) if the OCSP Must Staple extension is present, V(none) otherwise.
returned: success
type: bool
ocsp_must_staple_critical:
@@ -162,8 +163,8 @@ name_constraints_permitted:
name_constraints_excluded:
description:
- List of excluded subtrees the CA cannot sign certificates for.
- - Is C(none) if extension is not present.
- - See I(name_encoding) for how IDNs are handled.
+ - Is V(none) if extension is not present.
+ - See O(name_encoding) for how IDNs are handled.
returned: success
type: list
elements: str
@@ -172,7 +173,7 @@ name_constraints_excluded:
name_constraints_critical:
description:
- Whether the C(name_constraints) extension is critical.
- - Is C(none) if extension is not present.
+ - Is V(none) if extension is not present.
returned: success
type: bool
version_added: 1.1.0
@@ -197,8 +198,8 @@ public_key:
public_key_type:
description:
- The CSR's public key's type.
- - One of C(RSA), C(DSA), C(ECC), C(Ed25519), C(X25519), C(Ed448), or C(X448).
- - Will start with C(unknown) if the key type cannot be determined.
+ - One of V(RSA), V(DSA), V(ECC), V(Ed25519), V(X25519), V(Ed448), or V(X448).
+ - Will start with V(unknown) if the key type cannot be determined.
returned: success
type: str
version_added: 1.7.0
@@ -214,57 +215,57 @@ public_key_data:
description:
- Bit size of modulus (RSA) or prime number (DSA).
type: int
- returned: When C(public_key_type=RSA) or C(public_key_type=DSA)
+ returned: When RV(public_key_type=RSA) or RV(public_key_type=DSA)
modulus:
description:
- The RSA key's modulus.
type: int
- returned: When C(public_key_type=RSA)
+ returned: When RV(public_key_type=RSA)
exponent:
description:
- The RSA key's public exponent.
type: int
- returned: When C(public_key_type=RSA)
+ returned: When RV(public_key_type=RSA)
p:
description:
- The C(p) value for DSA.
- This is the prime modulus upon which arithmetic takes place.
type: int
- returned: When C(public_key_type=DSA)
+ returned: When RV(public_key_type=DSA)
q:
description:
- The C(q) value for DSA.
- This is a prime that divides C(p - 1), and at the same time the order of the subgroup of the
multiplicative group of the prime field used.
type: int
- returned: When C(public_key_type=DSA)
+ returned: When RV(public_key_type=DSA)
g:
description:
- The C(g) value for DSA.
- This is the element spanning the subgroup of the multiplicative group of the prime field used.
type: int
- returned: When C(public_key_type=DSA)
+ returned: When RV(public_key_type=DSA)
curve:
description:
- The curve's name for ECC.
type: str
- returned: When C(public_key_type=ECC)
+ returned: When RV(public_key_type=ECC)
exponent_size:
description:
- The maximum number of bits of a private key. This is basically the bit size of the subgroup used.
type: int
- returned: When C(public_key_type=ECC)
+ returned: When RV(public_key_type=ECC)
x:
description:
- The C(x) coordinate for the public point on the elliptic curve.
type: int
- returned: When C(public_key_type=ECC)
+ returned: When RV(public_key_type=ECC)
y:
description:
- - For C(public_key_type=ECC), this is the C(y) coordinate for the public point on the elliptic curve.
- - For C(public_key_type=DSA), this is the publicly known group element whose discrete logarithm w.r.t. C(g) is the private key.
+ - For RV(public_key_type=ECC), this is the C(y) coordinate for the public point on the elliptic curve.
+ - For RV(public_key_type=DSA), this is the publicly known group element whose discrete logarithm w.r.t. C(g) is the private key.
type: int
- returned: When C(public_key_type=DSA) or C(public_key_type=ECC)
+ returned: When RV(public_key_type=DSA) or RV(public_key_type=ECC)
public_key_fingerprints:
description:
- Fingerprints of CSR's public key.
@@ -276,24 +277,24 @@ public_key_fingerprints:
subject_key_identifier:
description:
- The CSR's subject key identifier.
- - The identifier is returned in hexadecimal, with C(:) used to separate bytes.
- - Is C(none) if the C(SubjectKeyIdentifier) extension is not present.
+ - The identifier is returned in hexadecimal, with V(:) used to separate bytes.
+ - Is V(none) if the C(SubjectKeyIdentifier) extension is not present.
returned: success
type: str
sample: '00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:00:11:22:33'
authority_key_identifier:
description:
- The CSR's authority key identifier.
- - The identifier is returned in hexadecimal, with C(:) used to separate bytes.
- - Is C(none) if the C(AuthorityKeyIdentifier) extension is not present.
+ - The identifier is returned in hexadecimal, with V(:) used to separate bytes.
+ - Is V(none) if the C(AuthorityKeyIdentifier) extension is not present.
returned: success
type: str
sample: '00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:00:11:22:33'
authority_cert_issuer:
description:
- The CSR's authority cert issuer as a list of general names.
- - Is C(none) if the C(AuthorityKeyIdentifier) extension is not present.
- - See I(name_encoding) for how IDNs are handled.
+ - Is V(none) if the C(AuthorityKeyIdentifier) extension is not present.
+ - See O(name_encoding) for how IDNs are handled.
returned: success
type: list
elements: str
@@ -301,7 +302,9 @@ authority_cert_issuer:
authority_cert_serial_number:
description:
- The CSR's authority cert serial number.
- - Is C(none) if the C(AuthorityKeyIdentifier) extension is not present.
+ - Is V(none) if the C(AuthorityKeyIdentifier) extension is not present.
+ - This return value is an B(integer). If you need the serial numbers as a colon-separated hex string,
+ such as C(11:22:33), you need to convert it to that form with P(community.crypto.to_serial#filter).
returned: success
type: int
sample: 12345
diff --git a/ansible_collections/community/crypto/plugins/modules/openssl_csr_pipe.py b/ansible_collections/community/crypto/plugins/modules/openssl_csr_pipe.py
index 66cc67354..0c42d5e78 100644
--- a/ansible_collections/community/crypto/plugins/modules/openssl_csr_pipe.py
+++ b/ansible_collections/community/crypto/plugins/modules/openssl_csr_pipe.py
@@ -27,6 +27,12 @@ extends_documentation_fragment:
attributes:
check_mode:
support: full
+ details:
+ - Currently in check mode, private keys will not be (re-)generated, only the changed status is
+ set. This will change in community.crypto 3.0.0.
+ - From community.crypto 3.0.0 on, the module will ignore check mode and always behave as if
+ check mode is not active. If you think this breaks your use-case of this module, please
+ create an issue in the community.crypto repository.
diff_mode:
support: full
options:
@@ -34,6 +40,14 @@ options:
description:
- The existing CSR.
type: str
+ privatekey_path:
+ description:
+ - The path to the private key to use when signing the certificate signing request.
+ - Either O(privatekey_path) or O(privatekey_content) must be specified, but not both.
+ privatekey_content:
+ description:
+ - The content of the private key to use when signing the certificate signing request.
+ - Either O(privatekey_path) or O(privatekey_content) must be specified, but not both.
seealso:
- module: community.crypto.openssl_csr
'''
@@ -50,7 +64,7 @@ EXAMPLES = r'''
- name: Generate an OpenSSL Certificate Signing Request with an inline CSR
community.crypto.openssl_csr:
- content: "{{ lookup('file', '/etc/ssl/csr/www.ansible.com.csr') }}"
+ content: "{{ lookup('ansible.builtin.file', '/etc/ssl/csr/www.ansible.com.csr') }}"
privatekey_content: "{{ private_key_content }}"
common_name: www.ansible.com
register: result
@@ -65,7 +79,7 @@ RETURN = r'''
privatekey:
description:
- Path to the TLS/SSL private key the CSR was generated for
- - Will be C(none) if the private key has been provided in I(privatekey_content).
+ - Will be V(none) if the private key has been provided in O(privatekey_content).
returned: changed or success
type: str
sample: /etc/ssl/private/ansible.com.pem
@@ -138,6 +152,7 @@ from ansible_collections.community.crypto.plugins.module_utils.crypto.basic impo
class CertificateSigningRequestModule(object):
def __init__(self, module, module_backend):
self.check_mode = module.check_mode
+ self.module = module
self.module_backend = module_backend
self.changed = False
if module.params['content'] is not None:
@@ -148,6 +163,16 @@ class CertificateSigningRequestModule(object):
if self.module_backend.needs_regeneration():
if not self.check_mode:
self.module_backend.generate_csr()
+ else:
+ self.module.deprecate(
+ 'Check mode support for openssl_csr_pipe will change in community.crypto 3.0.0'
+ ' to behave the same as without check mode. You can get that behavior right now'
+ ' by adding `check_mode: false` to the openssl_csr_pipe task. If you think this'
+ ' breaks your use-case of this module, please create an issue in the'
+ ' community.crypto repository',
+ version='3.0.0',
+ collection_name='community.crypto',
+ )
self.changed = True
def dump(self):
diff --git a/ansible_collections/community/crypto/plugins/modules/openssl_dhparam.py b/ansible_collections/community/crypto/plugins/modules/openssl_dhparam.py
index d9e1e982e..2c7d93541 100644
--- a/ansible_collections/community/crypto/plugins/modules/openssl_dhparam.py
+++ b/ansible_collections/community/crypto/plugins/modules/openssl_dhparam.py
@@ -18,10 +18,10 @@ description:
- This module uses file common arguments to specify generated file permissions.
- "Please note that the module regenerates existing DH params if they do not
match the module's options. If you are concerned that this could overwrite
- your existing DH params, consider using the I(backup) option."
+ your existing DH params, consider using the O(backup) option."
- The module can use the cryptography Python library, or the C(openssl) executable.
By default, it tries to detect which one is available. This can be overridden
- with the I(select_crypto_backend) option.
+ with the O(select_crypto_backend) option.
requirements:
- Either cryptography >= 2.0
- Or OpenSSL binary C(openssl)
@@ -70,16 +70,16 @@ options:
select_crypto_backend:
description:
- Determines which crypto backend to use.
- - The default choice is C(auto), which tries to use C(cryptography) if available, and falls back to C(openssl).
- - If set to C(openssl), will try to use the OpenSSL C(openssl) executable.
- - If set to C(cryptography), will try to use the L(cryptography,https://cryptography.io/) library.
+ - The default choice is V(auto), which tries to use C(cryptography) if available, and falls back to C(openssl).
+ - If set to V(openssl), will try to use the OpenSSL C(openssl) executable.
+ - If set to V(cryptography), will try to use the L(cryptography,https://cryptography.io/) library.
type: str
default: auto
choices: [ auto, cryptography, openssl ]
version_added: "1.0.0"
return_content:
description:
- - If set to C(true), will return the (current or generated) DH parameter's content as I(dhparams).
+ - If set to V(true), will return the (current or generated) DH parameter's content as RV(dhparams).
type: bool
default: false
version_added: "1.0.0"
@@ -120,12 +120,12 @@ filename:
sample: /etc/ssl/dhparams.pem
backup_file:
description: Name of backup file created.
- returned: changed and if I(backup) is C(true)
+ returned: changed and if O(backup) is V(true)
type: str
sample: /path/to/dhparams.pem.2019-03-09@11:22~
dhparams:
description: The (current or generated) DH params' content.
- returned: if I(state) is C(present) and I(return_content) is C(true)
+ returned: if O(state) is V(present) and O(return_content) is V(true)
type: str
version_added: "1.0.0"
'''
@@ -193,7 +193,7 @@ class DHParameterBase(object):
"""Generate DH params."""
changed = False
- # ony generate when necessary
+ # only generate when necessary
if self.force or not self._check_params_valid(module):
self._do_generate(module)
changed = True
@@ -341,7 +341,7 @@ class DHParameterCryptography(DHParameterBase):
try:
with open(self.path, 'rb') as f:
data = f.read()
- params = self.crypto_backend.load_pem_parameters(data)
+ params = cryptography.hazmat.primitives.serialization.load_pem_parameters(data, backend=self.crypto_backend)
except Exception as dummy:
return False
# Check parameters
diff --git a/ansible_collections/community/crypto/plugins/modules/openssl_pkcs12.py b/ansible_collections/community/crypto/plugins/modules/openssl_pkcs12.py
index e74553b58..e3b993083 100644
--- a/ansible_collections/community/crypto/plugins/modules/openssl_pkcs12.py
+++ b/ansible_collections/community/crypto/plugins/modules/openssl_pkcs12.py
@@ -19,12 +19,12 @@ description:
- This module allows one to (re-)generate PKCS#12.
- The module can use the cryptography Python library, or the pyOpenSSL Python
library. By default, it tries to detect which one is available, assuming none of the
- I(iter_size) and I(maciter_size) options are used. This can be overridden with the
- I(select_crypto_backend) option.
+ O(iter_size) and O(maciter_size) options are used. This can be overridden with the
+ O(select_crypto_backend) option.
# Please note that the C(pyopenssl) backend has been deprecated in community.crypto x.y.0,
# and will be removed in community.crypto (x+1).0.0.
requirements:
- - PyOpenSSL >= 0.15 or cryptography >= 3.0
+ - PyOpenSSL >= 0.15, < 23.3.0 or cryptography >= 3.0
extends_documentation_fragment:
- ansible.builtin.files
- community.crypto.attributes
@@ -39,21 +39,21 @@ attributes:
options:
action:
description:
- - C(export) or C(parse) a PKCS#12.
+ - V(export) or V(parse) a PKCS#12.
type: str
default: export
choices: [ export, parse ]
other_certificates:
description:
- - List of other certificates to include. Pre Ansible 2.8 this parameter was called I(ca_certificates).
+ - List of other certificates to include. Pre Ansible 2.8 this parameter was called O(ca_certificates).
- Assumes there is one PEM-encoded certificate per file. If a file contains multiple PEM certificates,
- set I(other_certificates_parse_all) to C(true).
+ set O(other_certificates_parse_all) to V(true).
type: list
elements: path
aliases: [ ca_certificates ]
other_certificates_parse_all:
description:
- - If set to C(true), assumes that the files mentioned in I(other_certificates) can contain more than one
+ - If set to V(true), assumes that the files mentioned in O(other_certificates) can contain more than one
certificate per file (or even none per file).
type: bool
default: false
@@ -77,21 +77,21 @@ options:
description:
- Number of times to repeat the encryption step.
- This is B(not considered during idempotency checks).
- - This is only used by the C(pyopenssl) backend, or when I(encryption_level=compatibility2022).
- - When using it, the default is C(2048) for C(pyopenssl) and C(50000) for C(cryptography).
+ - This is only used by the C(pyopenssl) backend, or when O(encryption_level=compatibility2022).
+ - When using it, the default is V(2048) for C(pyopenssl) and V(50000) for C(cryptography).
type: int
maciter_size:
description:
- Number of times to repeat the MAC step.
- This is B(not considered during idempotency checks).
- - This is only used by the C(pyopenssl) backend. When using it, the default is C(1).
+ - This is only used by the C(pyopenssl) backend. When using it, the default is V(1).
type: int
encryption_level:
description:
- Determines the encryption level used.
- - C(auto) uses the default of the selected backend. For C(cryptography), this is what the
+ - V(auto) uses the default of the selected backend. For C(cryptography), this is what the
cryptography library's specific version considers the best available encryption.
- - C(compatibility2022) uses compatibility settings for older software in 2022.
+ - V(compatibility2022) uses compatibility settings for older software in 2022.
This is only supported by the C(cryptography) backend if cryptography >= 38.0.0 is available.
- B(Note) that this option is B(not used for idempotency).
choices:
@@ -119,18 +119,18 @@ options:
privatekey_path:
description:
- File to read private key from.
- - Mutually exclusive with I(privatekey_content).
+ - Mutually exclusive with O(privatekey_content).
type: path
privatekey_content:
description:
- Content of the private key file.
- - Mutually exclusive with I(privatekey_path).
+ - Mutually exclusive with O(privatekey_path).
type: str
version_added: "2.3.0"
state:
description:
- Whether the file should exist or not.
- All parameters except C(path) are ignored when state is C(absent).
+ All parameters except O(path) are ignored when state is V(absent).
choices: [ absent, present ]
default: present
type: str
@@ -146,18 +146,18 @@ options:
default: false
return_content:
description:
- - If set to C(true), will return the (current or generated) PKCS#12's content as I(pkcs12).
+ - If set to V(true), will return the (current or generated) PKCS#12's content as RV(pkcs12).
type: bool
default: false
version_added: "1.0.0"
select_crypto_backend:
description:
- Determines which crypto backend to use.
- - The default choice is C(auto), which tries to use C(cryptography) if available, and falls back to C(pyopenssl).
- If I(iter_size) is used together with I(encryption_level != compatibility2022), or if I(maciter_size) is used,
- C(auto) will always result in C(pyopenssl) to be chosen for backwards compatibility.
- - If set to C(pyopenssl), will try to use the L(pyOpenSSL,https://pypi.org/project/pyOpenSSL/) library.
- - If set to C(cryptography), will try to use the L(cryptography,https://cryptography.io/) library.
+ - The default choice is V(auto), which tries to use C(cryptography) if available, and falls back to C(pyopenssl).
+ If O(iter_size) is used together with O(encryption_level) is not V(compatibility2022), or if O(maciter_size) is used,
+ V(auto) will always result in C(pyopenssl) to be chosen for backwards compatibility.
+ - If set to V(pyopenssl), will try to use the L(pyOpenSSL,https://pypi.org/project/pyOpenSSL/) library.
+ - If set to V(cryptography), will try to use the L(cryptography,https://cryptography.io/) library.
# - Please note that the C(pyopenssl) backend has been deprecated in community.crypto x.y.0, and will be
# removed in community.crypto (x+1).0.0.
# From that point on, only the C(cryptography) backend will be available.
@@ -255,12 +255,12 @@ privatekey:
sample: /etc/ssl/private/ansible.com.pem
backup_file:
description: Name of backup file created.
- returned: changed and if I(backup) is C(true)
+ returned: changed and if O(backup) is V(true)
type: str
sample: /path/to/ansible.com.pem.2019-03-09@11:22~
pkcs12:
description: The (current or generated) PKCS#12's content Base64 encoded.
- returned: if I(state) is C(present) and I(return_content) is C(true)
+ returned: if O(state) is V(present) and O(return_content) is V(true)
type: str
version_added: "1.0.0"
'''
@@ -302,11 +302,13 @@ from ansible_collections.community.crypto.plugins.module_utils.crypto.pem import
MINIMAL_CRYPTOGRAPHY_VERSION = '3.0'
MINIMAL_PYOPENSSL_VERSION = '0.15'
+MAXIMAL_PYOPENSSL_VERSION = '23.3.0'
PYOPENSSL_IMP_ERR = None
try:
import OpenSSL
from OpenSSL import crypto
+ from OpenSSL.crypto import load_pkcs12 as _load_pkcs12 # this got removed in pyOpenSSL 23.3.0
PYOPENSSL_VERSION = LooseVersion(OpenSSL.__version__)
except (ImportError, AttributeError):
PYOPENSSL_IMP_ERR = traceback.format_exc()
@@ -711,7 +713,11 @@ def select_backend(module, backend):
if backend == 'auto':
# Detection what is possible
can_use_cryptography = CRYPTOGRAPHY_FOUND and CRYPTOGRAPHY_VERSION >= LooseVersion(MINIMAL_CRYPTOGRAPHY_VERSION)
- can_use_pyopenssl = PYOPENSSL_FOUND and PYOPENSSL_VERSION >= LooseVersion(MINIMAL_PYOPENSSL_VERSION)
+ can_use_pyopenssl = (
+ PYOPENSSL_FOUND and
+ PYOPENSSL_VERSION >= LooseVersion(MINIMAL_PYOPENSSL_VERSION) and
+ PYOPENSSL_VERSION < LooseVersion(MAXIMAL_PYOPENSSL_VERSION)
+ )
# If no restrictions are provided, first try cryptography, then pyOpenSSL
if (
@@ -728,14 +734,17 @@ def select_backend(module, backend):
# Success?
if backend == 'auto':
module.fail_json(msg=("Cannot detect any of the required Python libraries "
- "cryptography (>= {0}) or PyOpenSSL (>= {1})").format(
+ "cryptography (>= {0}) or PyOpenSSL (>= {1}, < {2})").format(
MINIMAL_CRYPTOGRAPHY_VERSION,
- MINIMAL_PYOPENSSL_VERSION))
+ MINIMAL_PYOPENSSL_VERSION,
+ MAXIMAL_PYOPENSSL_VERSION))
if backend == 'pyopenssl':
if not PYOPENSSL_FOUND:
- module.fail_json(msg=missing_required_lib('pyOpenSSL >= {0}'.format(MINIMAL_PYOPENSSL_VERSION)),
- exception=PYOPENSSL_IMP_ERR)
+ msg = missing_required_lib(
+ 'pyOpenSSL >= {0}, < {1}'.format(MINIMAL_PYOPENSSL_VERSION, MAXIMAL_PYOPENSSL_VERSION)
+ )
+ module.fail_json(msg=msg, exception=PYOPENSSL_IMP_ERR)
# module.deprecate('The module is using the PyOpenSSL backend. This backend has been deprecated',
# version='x.0.0', collection_name='community.crypto')
return backend, PkcsPyOpenSSL(module)
diff --git a/ansible_collections/community/crypto/plugins/modules/openssl_privatekey.py b/ansible_collections/community/crypto/plugins/modules/openssl_privatekey.py
index 7b50caff7..a55395d3f 100644
--- a/ansible_collections/community/crypto/plugins/modules/openssl_privatekey.py
+++ b/ansible_collections/community/crypto/plugins/modules/openssl_privatekey.py
@@ -15,7 +15,12 @@ module: openssl_privatekey
short_description: Generate OpenSSL private keys
description:
- This module allows one to (re)generate OpenSSL private keys.
- - The default mode for the private key file will be C(0600) if I(mode) is not explicitly set.
+ - The default mode for the private key file will be V(0600) if O(mode) is not explicitly set.
+ - "Please note that the module regenerates private keys if they do not match
+ the module's options. In particular, if you provide another passphrase
+ (or specify none), change the keysize, etc., the private key will be
+ regenerated. If you are concerned that this could B(overwrite your private key),
+ consider using the O(backup) option."
author:
- Yanis Guenane (@Spredzy)
- Felix Fontein (@felixfontein)
@@ -45,8 +50,8 @@ options:
default: false
path:
description:
- - Name of the file in which the generated TLS/SSL private key will be written. It will have C(0600) mode
- if I(mode) is not explicitly set.
+ - Name of the file in which the generated TLS/SSL private key will be written. It will have V(0600) mode
+ if O(mode) is not explicitly set.
type: path
required: true
format:
@@ -61,10 +66,10 @@ options:
default: false
return_content:
description:
- - If set to C(true), will return the (current or generated) private key's content as I(privatekey).
+ - If set to V(true), will return the (current or generated) private key's content as RV(privatekey).
- Note that especially if the private key is not encrypted, you have to make sure that the returned
value is treated appropriately and not accidentally written to logs etc.! Use with care!
- - Use Ansible's I(no_log) task option to avoid the output being shown. See also
+ - Use Ansible's C(no_log) task option to avoid the output being shown. See also
U(https://docs.ansible.com/ansible/latest/reference_appendices/faq.html#how-do-i-keep-secret-data-in-my-playbook).
type: bool
default: false
@@ -101,6 +106,12 @@ EXAMPLES = r'''
community.crypto.openssl_privatekey:
path: /etc/ssl/private/ansible.com.pem
type: DSA
+
+- name: Generate an OpenSSL private key with elliptic curve cryptography (ECC)
+ community.crypto.openssl_privatekey:
+ path: /etc/ssl/private/ansible.com.pem
+ type: ECC
+ curve: secp256r1
'''
RETURN = r'''
@@ -116,7 +127,7 @@ type:
sample: RSA
curve:
description: Elliptic curve used to generate the TLS/SSL private key.
- returned: changed or success, and I(type) is C(ECC)
+ returned: changed or success, and O(type) is V(ECC)
type: str
sample: secp256r1
filename:
@@ -138,14 +149,14 @@ fingerprint:
sha512: "fd:ed:5e:39:48:5f:9f:fe:7f:25:06:3f:79:08:cd:ee:a5:e7:b3:3d:13:82:87:1f:84:e1:f5:c7:28:77:53:94:86:56:38:69:f0:d9:35:22:01:1e:a6:60:...:0f:9b"
backup_file:
description: Name of backup file created.
- returned: changed and if I(backup) is C(true)
+ returned: changed and if O(backup) is V(true)
type: str
sample: /path/to/privatekey.pem.2019-03-09@11:22~
privatekey:
description:
- The (current or generated) private key's content.
- Will be Base64-encoded if the key is in raw format.
- returned: if I(state) is C(present) and I(return_content) is C(true)
+ returned: if O(state) is V(present) and O(return_content) is V(true)
type: str
version_added: '1.0.0'
'''
diff --git a/ansible_collections/community/crypto/plugins/modules/openssl_privatekey_convert.py b/ansible_collections/community/crypto/plugins/modules/openssl_privatekey_convert.py
index 5aec5cbe8..a09e3e10d 100644
--- a/ansible_collections/community/crypto/plugins/modules/openssl_privatekey_convert.py
+++ b/ansible_collections/community/crypto/plugins/modules/openssl_privatekey_convert.py
@@ -16,7 +16,7 @@ short_description: Convert OpenSSL private keys
version_added: 2.1.0
description:
- This module allows one to convert OpenSSL private keys.
- - The default mode for the private key file will be C(0600) if I(mode) is not explicitly set.
+ - The default mode for the private key file will be V(0600) if O(mode) is not explicitly set.
author:
- Felix Fontein (@felixfontein)
extends_documentation_fragment:
@@ -34,8 +34,8 @@ attributes:
options:
dest_path:
description:
- - Name of the file in which the generated TLS/SSL private key will be written. It will have C(0600) mode
- if I(mode) is not explicitly set.
+ - Name of the file in which the generated TLS/SSL private key will be written. It will have V(0600) mode
+ if O(mode) is not explicitly set.
type: path
required: true
backup:
@@ -59,7 +59,7 @@ EXAMPLES = r'''
RETURN = r'''
backup_file:
description: Name of backup file created.
- returned: changed and if I(backup) is C(true)
+ returned: changed and if O(backup) is V(true)
type: str
sample: /path/to/privatekey.pem.2019-03-09@11:22~
'''
diff --git a/ansible_collections/community/crypto/plugins/modules/openssl_privatekey_info.py b/ansible_collections/community/crypto/plugins/modules/openssl_privatekey_info.py
index 7eaec2348..220bf988e 100644
--- a/ansible_collections/community/crypto/plugins/modules/openssl_privatekey_info.py
+++ b/ansible_collections/community/crypto/plugins/modules/openssl_privatekey_info.py
@@ -18,8 +18,8 @@ description:
- This module allows one to query information on OpenSSL private keys.
- In case the key consistency checks fail, the module will fail as this indicates a faked
private key. In this case, all return variables are still returned. Note that key consistency
- checks are not available all key types; if none is available, C(none) is returned for
- C(key_is_consistent).
+ checks are not available all key types; if none is available, V(none) is returned for
+ RV(key_is_consistent).
- It uses the cryptography python library to interact with OpenSSL.
requirements:
- cryptography >= 1.2.3
@@ -37,7 +37,7 @@ options:
content:
description:
- Content of the private key file.
- - Either I(path) or I(content) must be specified, but not both.
+ - Either O(path) or O(content) must be specified, but not both.
type: str
version_added: '1.0.0'
passphrase:
@@ -47,7 +47,7 @@ options:
return_private_key_data:
description:
- Whether to return private key data.
- - Only set this to C(true) when you want private information about this key to
+ - Only set this to V(true) when you want private information about this key to
leave the remote machine.
- "B(WARNING:) you have to make sure that private key data is not accidentally logged!"
type: bool
@@ -60,6 +60,9 @@ options:
avoid private key material to be transported around and computed with, and only do
so when requested explicitly. This can potentially prevent
L(side-channel attacks,https://en.wikipedia.org/wiki/Side-channel_attack).
+ - Note that consistency checks only work for certain key types, and might depend on the
+ version of the cryptography library. For example, with cryptography 42.0.0 and newer
+ consistency of RSA keys can no longer be checked.
type: bool
default: false
version_added: 2.0.0
@@ -67,8 +70,8 @@ options:
select_crypto_backend:
description:
- Determines which crypto backend to use.
- - The default choice is C(auto), which tries to use C(cryptography) if available.
- - If set to C(cryptography), will try to use the L(cryptography,https://cryptography.io/) library.
+ - The default choice is V(auto), which tries to use C(cryptography) if available.
+ - If set to V(cryptography), will try to use the L(cryptography,https://cryptography.io/) library.
type: str
default: auto
choices: [ auto, cryptography ]
@@ -76,9 +79,8 @@ options:
seealso:
- module: community.crypto.openssl_privatekey
- module: community.crypto.openssl_privatekey_pipe
- - ref: community.crypto.openssl_privatekey_info filter <ansible_collections.community.crypto.openssl_privatekey_info_filter>
- # - plugin: community.crypto.openssl_privatekey_info
- # plugin_type: filter
+ - plugin: community.crypto.openssl_privatekey_info
+ plugin_type: filter
description: A filter variant of this module.
'''
@@ -108,10 +110,10 @@ can_parse_key:
type: bool
key_is_consistent:
description:
- - Whether the key is consistent. Can also return C(none) next to C(true) and
- C(false), to indicate that consistency could not be checked.
- - In case the check returns C(false), the module will fail.
- returned: when I(check_consistency=true)
+ - Whether the key is consistent. Can also return V(none) next to V(true) and
+ V(false), to indicate that consistency could not be checked.
+ - In case the check returns V(false), the module will fail.
+ returned: when O(check_consistency=true)
type: bool
public_key:
description: Private key's public key in PEM format.
@@ -129,8 +131,8 @@ public_key_fingerprints:
type:
description:
- The key's type.
- - One of C(RSA), C(DSA), C(ECC), C(Ed25519), C(X25519), C(Ed448), or C(X448).
- - Will start with C(unknown) if the key type cannot be determined.
+ - One of V(RSA), V(DSA), V(ECC), V(Ed25519), V(X25519), V(Ed448), or V(X448).
+ - Will start with V(unknown) if the key type cannot be determined.
returned: success
type: str
sample: RSA
@@ -144,61 +146,61 @@ public_data:
description:
- Bit size of modulus (RSA) or prime number (DSA).
type: int
- returned: When C(type=RSA) or C(type=DSA)
+ returned: When RV(type=RSA) or RV(type=DSA)
modulus:
description:
- The RSA key's modulus.
type: int
- returned: When C(type=RSA)
+ returned: When RV(type=RSA)
exponent:
description:
- The RSA key's public exponent.
type: int
- returned: When C(type=RSA)
+ returned: When RV(type=RSA)
p:
description:
- The C(p) value for DSA.
- This is the prime modulus upon which arithmetic takes place.
type: int
- returned: When C(type=DSA)
+ returned: When RV(type=DSA)
q:
description:
- The C(q) value for DSA.
- This is a prime that divides C(p - 1), and at the same time the order of the subgroup of the
multiplicative group of the prime field used.
type: int
- returned: When C(type=DSA)
+ returned: When RV(type=DSA)
g:
description:
- The C(g) value for DSA.
- This is the element spanning the subgroup of the multiplicative group of the prime field used.
type: int
- returned: When C(type=DSA)
+ returned: When RV(type=DSA)
curve:
description:
- The curve's name for ECC.
type: str
- returned: When C(type=ECC)
+ returned: When RV(type=ECC)
exponent_size:
description:
- The maximum number of bits of a private key. This is basically the bit size of the subgroup used.
type: int
- returned: When C(type=ECC)
+ returned: When RV(type=ECC)
x:
description:
- The C(x) coordinate for the public point on the elliptic curve.
type: int
- returned: When C(type=ECC)
+ returned: When RV(type=ECC)
y:
description:
- - For C(type=ECC), this is the C(y) coordinate for the public point on the elliptic curve.
- - For C(type=DSA), this is the publicly known group element whose discrete logarithm w.r.t. C(g) is the private key.
+ - For RV(type=ECC), this is the C(y) coordinate for the public point on the elliptic curve.
+ - For RV(type=DSA), this is the publicly known group element whose discrete logarithm w.r.t. C(g) is the private key.
type: int
- returned: When C(type=DSA) or C(type=ECC)
+ returned: When RV(type=DSA) or RV(type=ECC)
private_data:
description:
- Private key data. Depends on key type.
- returned: success and when I(return_private_key_data) is set to C(true)
+ returned: success and when O(return_private_key_data) is set to V(true)
type: dict
'''
diff --git a/ansible_collections/community/crypto/plugins/modules/openssl_privatekey_pipe.py b/ansible_collections/community/crypto/plugins/modules/openssl_privatekey_pipe.py
index 41432840d..6c921a306 100644
--- a/ansible_collections/community/crypto/plugins/modules/openssl_privatekey_pipe.py
+++ b/ansible_collections/community/crypto/plugins/modules/openssl_privatekey_pipe.py
@@ -17,7 +17,7 @@ version_added: 1.3.0
description:
- This module allows one to (re)generate OpenSSL private keys without disk access.
- This allows to read and write keys to vaults without having to write intermediate versions to disk.
- - Make sure to not write the result of this module into logs or to the console, as it contains private key data! Use the I(no_log) task option to be sure.
+ - Make sure to not write the result of this module into logs or to the console, as it contains private key data! Use the C(no_log) task option to be sure.
- Note that this module is implemented as an L(action plugin,https://docs.ansible.com/ansible/latest/plugins/action.html)
and will always be executed on the controller.
author:
@@ -36,6 +36,12 @@ attributes:
- This action runs completely on the controller.
check_mode:
support: full
+ details:
+ - Currently in check mode, private keys will not be (re-)generated, only the changed status is
+ set. This will change in community.crypto 3.0.0.
+ - From community.crypto 3.0.0 on, the module will ignore check mode and always behave as if
+ check mode is not active. If you think this breaks your use-case of this module, please
+ create an issue in the community.crypto repository.
diff_mode:
support: full
options:
@@ -47,16 +53,39 @@ options:
type: str
content_base64:
description:
- - Set to C(true) if the content is base64 encoded.
+ - Set to V(true) if the content is base64 encoded.
type: bool
default: false
return_current_key:
description:
- - Set to C(true) to return the current private key when the module did not generate a new one.
- - Note that in case of check mode, when this option is not set to C(true), the module always returns the
+ - Set to V(true) to return the current private key when the module did not generate a new one.
+ - Note that in case of check mode, when this option is not set to V(true), the module always returns the
current key (if it was provided) and Ansible will replace it by C(VALUE_SPECIFIED_IN_NO_LOG_PARAMETER).
type: bool
default: false
+ regenerate:
+ description:
+ - Allows to configure in which situations the module is allowed to regenerate private keys.
+ The module will always generate a new key if the destination file does not exist.
+ - By default, the key will be regenerated when it does not match the module's options,
+ except when the key cannot be read or the passphrase does not match. Please note that
+ this B(changed) for Ansible 2.10. For Ansible 2.9, the behavior was as if V(full_idempotence)
+ is specified.
+ - If set to V(never), the module will fail if the key cannot be read or the passphrase
+ is not matching, and will never regenerate an existing key.
+ - If set to V(fail), the module will fail if the key does not correspond to the module's
+ options.
+ - If set to V(partial_idempotence), the key will be regenerated if it does not conform to
+ the module's options. The key is B(not) regenerated if it cannot be read (broken file),
+ the key is protected by an unknown passphrase, or when they key is not protected by a
+ passphrase, but a passphrase is specified.
+ - If set to V(full_idempotence), the key will be regenerated if it does not conform to the
+ module's options. This is also the case if the key cannot be read (broken file), the key
+ is protected by an unknown passphrase, or when they key is not protected by a passphrase,
+ but a passphrase is specified. Make sure you have a B(backup) when using this option!
+ - If set to V(always), the module will always regenerate the key.
+ - Note that if O(format_mismatch) is set to V(convert) and everything matches except the
+ format, the key will always be converted, except if O(regenerate) is set to V(always).
seealso:
- module: community.crypto.openssl_privatekey
- module: community.crypto.openssl_privatekey_info
@@ -106,7 +135,7 @@ type:
sample: RSA
curve:
description: Elliptic curve used to generate the TLS/SSL private key.
- returned: changed or success, and I(type) is C(ECC)
+ returned: changed or success, and O(type) is V(ECC)
type: str
sample: secp256r1
fingerprint:
@@ -125,8 +154,8 @@ privatekey:
description:
- The generated private key's content.
- Please note that if the result is not changed, the current private key will only be returned
- if the I(return_current_key) option is set to C(true).
+ if the O(return_current_key) option is set to V(true).
- Will be Base64-encoded if the key is in raw format.
- returned: changed, or I(return_current_key) is C(true)
+ returned: changed, or O(return_current_key) is V(true)
type: str
'''
diff --git a/ansible_collections/community/crypto/plugins/modules/openssl_publickey.py b/ansible_collections/community/crypto/plugins/modules/openssl_publickey.py
index da01d1fb4..98eca22ac 100644
--- a/ansible_collections/community/crypto/plugins/modules/openssl_publickey.py
+++ b/ansible_collections/community/crypto/plugins/modules/openssl_publickey.py
@@ -16,11 +16,11 @@ short_description: Generate an OpenSSL public key from its private key.
description:
- This module allows one to (re)generate public keys from their private keys.
- Public keys are generated in PEM or OpenSSH format. Private keys must be OpenSSL PEM keys.
- OpenSSH private keys are not supported, use the M(community.crypto.openssh_keypair) module to manage these.
+ B(OpenSSH private keys are not supported), use the M(community.crypto.openssh_keypair) module to manage these.
- The module uses the cryptography Python library.
requirements:
- cryptography >= 1.2.3 (older versions might work as well)
- - Needs cryptography >= 1.4 if I(format) is C(OpenSSH)
+ - Needs cryptography >= 1.4 if O(format) is C(OpenSSH)
author:
- Yanis Guenane (@Spredzy)
- Felix Fontein (@felixfontein)
@@ -61,14 +61,14 @@ options:
privatekey_path:
description:
- Path to the TLS/SSL private key from which to generate the public key.
- - Either I(privatekey_path) or I(privatekey_content) must be specified, but not both.
- If I(state) is C(present), one of them is required.
+ - Either O(privatekey_path) or O(privatekey_content) must be specified, but not both.
+ If O(state) is V(present), one of them is required.
type: path
privatekey_content:
description:
- The content of the TLS/SSL private key from which to generate the public key.
- - Either I(privatekey_path) or I(privatekey_content) must be specified, but not both.
- If I(state) is C(present), one of them is required.
+ - Either O(privatekey_path) or O(privatekey_content) must be specified, but not both.
+ If O(state) is V(present), one of them is required.
type: str
version_added: '1.0.0'
privatekey_passphrase:
@@ -84,14 +84,14 @@ options:
select_crypto_backend:
description:
- Determines which crypto backend to use.
- - The default choice is C(auto), which tries to use C(cryptography) if available.
- - If set to C(cryptography), will try to use the L(cryptography,https://cryptography.io/) library.
+ - The default choice is V(auto), which tries to use C(cryptography) if available.
+ - If set to V(cryptography), will try to use the L(cryptography,https://cryptography.io/) library.
type: str
default: auto
choices: [ auto, cryptography ]
return_content:
description:
- - If set to C(true), will return the (current or generated) public key's content as I(publickey).
+ - If set to V(true), will return the (current or generated) public key's content as RV(publickey).
type: bool
default: false
version_added: '1.0.0'
@@ -145,7 +145,7 @@ RETURN = r'''
privatekey:
description:
- Path to the TLS/SSL private key the public key was generated from.
- - Will be C(none) if the private key has been provided in I(privatekey_content).
+ - Will be V(none) if the private key has been provided in O(privatekey_content).
returned: changed or success
type: str
sample: /etc/ssl/private/ansible.com.pem
@@ -173,12 +173,12 @@ fingerprint:
sha512: "fd:ed:5e:39:48:5f:9f:fe:7f:25:06:3f:79:08:cd:ee:a5:e7:b3:3d:13:82:87:1f:84:e1:f5:c7:28:77:53:94:86:56:38:69:f0:d9:35:22:01:1e:a6:60:...:0f:9b"
backup_file:
description: Name of backup file created.
- returned: changed and if I(backup) is C(true)
+ returned: changed and if O(backup) is V(true)
type: str
sample: /path/to/publickey.pem.2019-03-09@11:22~
publickey:
description: The (current or generated) public key's content.
- returned: if I(state) is C(present) and I(return_content) is C(true)
+ returned: if O(state) is V(present) and O(return_content) is V(true)
type: str
version_added: '1.0.0'
'''
diff --git a/ansible_collections/community/crypto/plugins/modules/openssl_publickey_info.py b/ansible_collections/community/crypto/plugins/modules/openssl_publickey_info.py
index 7b0610065..d6e28fdd0 100644
--- a/ansible_collections/community/crypto/plugins/modules/openssl_publickey_info.py
+++ b/ansible_collections/community/crypto/plugins/modules/openssl_publickey_info.py
@@ -32,14 +32,14 @@ options:
content:
description:
- Content of the public key file.
- - Either I(path) or I(content) must be specified, but not both.
+ - Either O(path) or O(content) must be specified, but not both.
type: str
select_crypto_backend:
description:
- Determines which crypto backend to use.
- - The default choice is C(auto), which tries to use C(cryptography) if available.
- - If set to C(cryptography), will try to use the L(cryptography,https://cryptography.io/) library.
+ - The default choice is V(auto), which tries to use C(cryptography) if available.
+ - If set to V(cryptography), will try to use the L(cryptography,https://cryptography.io/) library.
type: str
default: auto
choices: [ auto, cryptography ]
@@ -47,9 +47,8 @@ options:
seealso:
- module: community.crypto.openssl_publickey
- module: community.crypto.openssl_privatekey_info
- - ref: community.crypto.openssl_publickey_info filter <ansible_collections.community.crypto.openssl_publickey_info_filter>
- # - plugin: community.crypto.openssl_publickey_info
- # plugin_type: filter
+ - plugin: community.crypto.openssl_publickey_info
+ plugin_type: filter
description: A filter variant of this module.
'''
@@ -85,8 +84,8 @@ fingerprints:
type:
description:
- The key's type.
- - One of C(RSA), C(DSA), C(ECC), C(Ed25519), C(X25519), C(Ed448), or C(X448).
- - Will start with C(unknown) if the key type cannot be determined.
+ - One of V(RSA), V(DSA), V(ECC), V(Ed25519), V(X25519), V(Ed448), or V(X448).
+ - Will start with V(unknown) if the key type cannot be determined.
returned: success
type: str
sample: RSA
@@ -100,57 +99,57 @@ public_data:
description:
- Bit size of modulus (RSA) or prime number (DSA).
type: int
- returned: When C(type=RSA) or C(type=DSA)
+ returned: When RV(type=RSA) or RV(type=DSA)
modulus:
description:
- The RSA key's modulus.
type: int
- returned: When C(type=RSA)
+ returned: When RV(type=RSA)
exponent:
description:
- The RSA key's public exponent.
type: int
- returned: When C(type=RSA)
+ returned: When RV(type=RSA)
p:
description:
- The C(p) value for DSA.
- This is the prime modulus upon which arithmetic takes place.
type: int
- returned: When C(type=DSA)
+ returned: When RV(type=DSA)
q:
description:
- The C(q) value for DSA.
- This is a prime that divides C(p - 1), and at the same time the order of the subgroup of the
multiplicative group of the prime field used.
type: int
- returned: When C(type=DSA)
+ returned: When RV(type=DSA)
g:
description:
- The C(g) value for DSA.
- This is the element spanning the subgroup of the multiplicative group of the prime field used.
type: int
- returned: When C(type=DSA)
+ returned: When RV(type=DSA)
curve:
description:
- The curve's name for ECC.
type: str
- returned: When C(type=ECC)
+ returned: When RV(type=ECC)
exponent_size:
description:
- The maximum number of bits of a private key. This is basically the bit size of the subgroup used.
type: int
- returned: When C(type=ECC)
+ returned: When RV(type=ECC)
x:
description:
- The C(x) coordinate for the public point on the elliptic curve.
type: int
- returned: When C(type=ECC)
+ returned: When RV(type=ECC)
y:
description:
- - For C(type=ECC), this is the C(y) coordinate for the public point on the elliptic curve.
- - For C(type=DSA), this is the publicly known group element whose discrete logarithm w.r.t. C(g) is the private key.
+ - For RV(type=ECC), this is the C(y) coordinate for the public point on the elliptic curve.
+ - For RV(type=DSA), this is the publicly known group element whose discrete logarithm w.r.t. C(g) is the private key.
type: int
- returned: When C(type=DSA) or C(type=ECC)
+ returned: When RV(type=DSA) or RV(type=ECC)
'''
diff --git a/ansible_collections/community/crypto/plugins/modules/openssl_signature.py b/ansible_collections/community/crypto/plugins/modules/openssl_signature.py
index 43503bd1d..8236839c2 100644
--- a/ansible_collections/community/crypto/plugins/modules/openssl_signature.py
+++ b/ansible_collections/community/crypto/plugins/modules/openssl_signature.py
@@ -35,12 +35,12 @@ options:
privatekey_path:
description:
- The path to the private key to use when signing.
- - Either I(privatekey_path) or I(privatekey_content) must be specified, but not both.
+ - Either O(privatekey_path) or O(privatekey_content) must be specified, but not both.
type: path
privatekey_content:
description:
- The content of the private key to use when signing the certificate signing request.
- - Either I(privatekey_path) or I(privatekey_content) must be specified, but not both.
+ - Either O(privatekey_path) or O(privatekey_content) must be specified, but not both.
type: str
privatekey_passphrase:
description:
@@ -56,8 +56,8 @@ options:
select_crypto_backend:
description:
- Determines which crypto backend to use.
- - The default choice is C(auto), which tries to use C(cryptography) if available.
- - If set to C(cryptography), will try to use the L(cryptography,https://cryptography.io/) library.
+ - The default choice is V(auto), which tries to use C(cryptography) if available.
+ - If set to V(cryptography), will try to use the L(cryptography,https://cryptography.io/) library.
type: str
default: auto
choices: [ auto, cryptography ]
diff --git a/ansible_collections/community/crypto/plugins/modules/openssl_signature_info.py b/ansible_collections/community/crypto/plugins/modules/openssl_signature_info.py
index b83f3e693..2a5d3b3d9 100644
--- a/ansible_collections/community/crypto/plugins/modules/openssl_signature_info.py
+++ b/ansible_collections/community/crypto/plugins/modules/openssl_signature_info.py
@@ -35,12 +35,12 @@ options:
certificate_path:
description:
- The path to the certificate used to verify the signature.
- - Either I(certificate_path) or I(certificate_content) must be specified, but not both.
+ - Either O(certificate_path) or O(certificate_content) must be specified, but not both.
type: path
certificate_content:
description:
- The content of the certificate used to verify the signature.
- - Either I(certificate_path) or I(certificate_content) must be specified, but not both.
+ - Either O(certificate_path) or O(certificate_content) must be specified, but not both.
type: str
signature:
description: Base64 encoded signature.
@@ -49,8 +49,8 @@ options:
select_crypto_backend:
description:
- Determines which crypto backend to use.
- - The default choice is C(auto), which tries to use C(cryptography) if available.
- - If set to C(cryptography), will try to use the L(cryptography,https://cryptography.io/) library.
+ - The default choice is V(auto), which tries to use C(cryptography) if available.
+ - If set to V(cryptography), will try to use the L(cryptography,https://cryptography.io/) library.
type: str
default: auto
choices: [ auto, cryptography ]
@@ -87,7 +87,7 @@ EXAMPLES = r'''
RETURN = r'''
valid:
- description: C(true) means the signature was valid for the given file, C(false) means it was not.
+ description: V(true) means the signature was valid for the given file, V(false) means it was not.
returned: success
type: bool
'''
diff --git a/ansible_collections/community/crypto/plugins/modules/x509_certificate.py b/ansible_collections/community/crypto/plugins/modules/x509_certificate.py
index 1b4ece5cb..f1c7d6b00 100644
--- a/ansible_collections/community/crypto/plugins/modules/x509_certificate.py
+++ b/ansible_collections/community/crypto/plugins/modules/x509_certificate.py
@@ -15,16 +15,16 @@ DOCUMENTATION = r'''
module: x509_certificate
short_description: Generate and/or check OpenSSL certificates
description:
- - It implements a notion of provider (one of C(selfsigned), C(ownca), C(acme), and C(entrust))
+ - It implements a notion of provider (one of V(selfsigned), V(ownca), V(acme), and V(entrust))
for your certificate.
- "Please note that the module regenerates existing certificate if it does not match the module's
options, or if it seems to be corrupt. If you are concerned that this could overwrite
- your existing certificate, consider using the I(backup) option."
+ your existing certificate, consider using the O(backup) option."
- Note that this module was called C(openssl_certificate) when included directly in Ansible up to version 2.9.
When moved to the collection C(community.crypto), it was renamed to
M(community.crypto.x509_certificate). From Ansible 2.10 on, it can still be used by the
old short name (or by C(ansible.builtin.openssl_certificate)), which redirects to
- C(community.crypto.x509_certificate). When using FQCNs or when using the
+ M(community.crypto.x509_certificate). When using FQCNs or when using the
L(collections,https://docs.ansible.com/ansible/latest/user_guide/collections_using.html#using-collections-in-a-playbook)
keyword, the new name M(community.crypto.x509_certificate) should be used to avoid
a deprecation warning.
@@ -67,15 +67,15 @@ options:
Please see the examples on how to emulate it with
M(community.crypto.x509_certificate_info), M(community.crypto.openssl_csr_info),
M(community.crypto.openssl_privatekey_info) and M(ansible.builtin.assert).
- - "The C(entrust) provider was added for Ansible 2.9 and requires credentials for the
+ - "The V(entrust) provider was added for Ansible 2.9 and requires credentials for the
L(Entrust Certificate Services,https://www.entrustdatacard.com/products/categories/ssl-certificates) (ECS) API."
- - Required if I(state) is C(present).
+ - Required if O(state) is V(present).
type: str
choices: [ acme, entrust, ownca, selfsigned ]
return_content:
description:
- - If set to C(true), will return the (current or generated) certificate's content as I(certificate).
+ - If set to V(true), will return the (current or generated) certificate's content as RV(certificate).
type: bool
default: false
version_added: '1.0.0'
@@ -222,12 +222,12 @@ filename:
sample: /etc/ssl/crt/www.ansible.com.crt
backup_file:
description: Name of backup file created.
- returned: changed and if I(backup) is C(true)
+ returned: changed and if O(backup) is V(true)
type: str
sample: /path/to/www.ansible.com.crt.2019-03-09@11:22~
certificate:
description: The (current or generated) certificate's content.
- returned: if I(state) is C(present) and I(return_content) is C(true)
+ returned: if O(state) is V(present) and O(return_content) is V(true)
type: str
version_added: '1.0.0'
'''
diff --git a/ansible_collections/community/crypto/plugins/modules/x509_certificate_info.py b/ansible_collections/community/crypto/plugins/modules/x509_certificate_info.py
index 145cd2195..d89f610c5 100644
--- a/ansible_collections/community/crypto/plugins/modules/x509_certificate_info.py
+++ b/ansible_collections/community/crypto/plugins/modules/x509_certificate_info.py
@@ -21,7 +21,7 @@ description:
up to version 2.9. When moved to the collection C(community.crypto), it was renamed to
M(community.crypto.x509_certificate_info). From Ansible 2.10 on, it can still be used by the
old short name (or by C(ansible.builtin.openssl_certificate_info)), which redirects to
- C(community.crypto.x509_certificate_info). When using FQCNs or when using the
+ M(community.crypto.x509_certificate_info). When using FQCNs or when using the
L(collections,https://docs.ansible.com/ansible/latest/user_guide/collections_using.html#using-collections-in-a-playbook)
keyword, the new name M(community.crypto.x509_certificate_info) should be used to avoid
a deprecation warning.
@@ -39,31 +39,31 @@ options:
path:
description:
- Remote absolute path where the certificate file is loaded from.
- - Either I(path) or I(content) must be specified, but not both.
+ - Either O(path) or O(content) must be specified, but not both.
- PEM and DER formats are supported.
type: path
content:
description:
- Content of the X.509 certificate in PEM format.
- - Either I(path) or I(content) must be specified, but not both.
+ - Either O(path) or O(content) must be specified, but not both.
type: str
version_added: '1.0.0'
valid_at:
description:
- A dict of names mapping to time specifications. Every time specified here
will be checked whether the certificate is valid at this point. See the
- C(valid_at) return value for informations on the result.
+ RV(valid_at) return value for information on the result.
- Time can be specified either as relative time or as absolute timestamp.
- Time will always be interpreted as UTC.
- Valid format is C([+-]timespec | ASN.1 TIME) where timespec can be an integer
- + C([w | d | h | m | s]) (for example C(+32w1d2h)), and ASN.1 TIME (in other words, pattern C(YYYYMMDDHHMMSSZ)).
+ + C([w | d | h | m | s]) (for example V(+32w1d2h)), and ASN.1 TIME (in other words, pattern C(YYYYMMDDHHMMSSZ)).
Note that all timestamps will be treated as being in UTC.
type: dict
select_crypto_backend:
description:
- Determines which crypto backend to use.
- - The default choice is C(auto), which tries to use C(cryptography) if available.
- - If set to C(cryptography), will try to use the L(cryptography,https://cryptography.io/) library.
+ - The default choice is V(auto), which tries to use C(cryptography) if available.
+ - If set to V(cryptography), will try to use the L(cryptography,https://cryptography.io/) library.
type: str
default: auto
choices: [ auto, cryptography ]
@@ -74,10 +74,11 @@ notes:
seealso:
- module: community.crypto.x509_certificate
- module: community.crypto.x509_certificate_pipe
- - ref: community.crypto.x509_certificate_info filter <ansible_collections.community.crypto.x509_certificate_info_filter>
- # - plugin: community.crypto.x509_certificate_info
- # plugin_type: filter
+ - plugin: community.crypto.x509_certificate_info
+ plugin_type: filter
description: A filter variant of this module.
+ - plugin: community.crypto.to_serial
+ plugin_type: filter
'''
EXAMPLES = r'''
@@ -127,7 +128,7 @@ expired:
returned: success
type: bool
basic_constraints:
- description: Entries in the C(basic_constraints) extension, or C(none) if extension is not present.
+ description: Entries in the C(basic_constraints) extension, or V(none) if extension is not present.
returned: success
type: list
elements: str
@@ -137,7 +138,7 @@ basic_constraints_critical:
returned: success
type: bool
extended_key_usage:
- description: Entries in the C(extended_key_usage) extension, or C(none) if extension is not present.
+ description: Entries in the C(extended_key_usage) extension, or V(none) if extension is not present.
returned: success
type: list
elements: str
@@ -168,7 +169,7 @@ extensions_by_oid:
sample: "MAMCAQU="
sample: {"1.3.6.1.5.5.7.1.24": { "critical": false, "value": "MAMCAQU="}}
key_usage:
- description: Entries in the C(key_usage) extension, or C(none) if extension is not present.
+ description: Entries in the C(key_usage) extension, or V(none) if extension is not present.
returned: success
type: str
sample: [Key Agreement, Data Encipherment]
@@ -178,8 +179,8 @@ key_usage_critical:
type: bool
subject_alt_name:
description:
- - Entries in the C(subject_alt_name) extension, or C(none) if extension is not present.
- - See I(name_encoding) for how IDNs are handled.
+ - Entries in the C(subject_alt_name) extension, or V(none) if extension is not present.
+ - See O(name_encoding) for how IDNs are handled.
returned: success
type: list
elements: str
@@ -189,7 +190,7 @@ subject_alt_name_critical:
returned: success
type: bool
ocsp_must_staple:
- description: C(true) if the OCSP Must Staple extension is present, C(none) otherwise.
+ description: V(true) if the OCSP Must Staple extension is present, V(none) otherwise.
returned: success
type: bool
ocsp_must_staple_critical:
@@ -240,8 +241,8 @@ public_key:
public_key_type:
description:
- The certificate's public key's type.
- - One of C(RSA), C(DSA), C(ECC), C(Ed25519), C(X25519), C(Ed448), or C(X448).
- - Will start with C(unknown) if the key type cannot be determined.
+ - One of V(RSA), V(DSA), V(ECC), V(Ed25519), V(X25519), V(Ed448), or V(X448).
+ - Will start with V(unknown) if the key type cannot be determined.
returned: success
type: str
version_added: 1.7.0
@@ -257,57 +258,57 @@ public_key_data:
description:
- Bit size of modulus (RSA) or prime number (DSA).
type: int
- returned: When C(public_key_type=RSA) or C(public_key_type=DSA)
+ returned: When RV(public_key_type=RSA) or RV(public_key_type=DSA)
modulus:
description:
- The RSA key's modulus.
type: int
- returned: When C(public_key_type=RSA)
+ returned: When RV(public_key_type=RSA)
exponent:
description:
- The RSA key's public exponent.
type: int
- returned: When C(public_key_type=RSA)
+ returned: When RV(public_key_type=RSA)
p:
description:
- The C(p) value for DSA.
- This is the prime modulus upon which arithmetic takes place.
type: int
- returned: When C(public_key_type=DSA)
+ returned: When RV(public_key_type=DSA)
q:
description:
- The C(q) value for DSA.
- This is a prime that divides C(p - 1), and at the same time the order of the subgroup of the
multiplicative group of the prime field used.
type: int
- returned: When C(public_key_type=DSA)
+ returned: When RV(public_key_type=DSA)
g:
description:
- The C(g) value for DSA.
- This is the element spanning the subgroup of the multiplicative group of the prime field used.
type: int
- returned: When C(public_key_type=DSA)
+ returned: When RV(public_key_type=DSA)
curve:
description:
- The curve's name for ECC.
type: str
- returned: When C(public_key_type=ECC)
+ returned: When RV(public_key_type=ECC)
exponent_size:
description:
- The maximum number of bits of a private key. This is basically the bit size of the subgroup used.
type: int
- returned: When C(public_key_type=ECC)
+ returned: When RV(public_key_type=ECC)
x:
description:
- The C(x) coordinate for the public point on the elliptic curve.
type: int
- returned: When C(public_key_type=ECC)
+ returned: When RV(public_key_type=ECC)
y:
description:
- - For C(public_key_type=ECC), this is the C(y) coordinate for the public point on the elliptic curve.
- - For C(public_key_type=DSA), this is the publicly known group element whose discrete logarithm w.r.t. C(g) is the private key.
+ - For RV(public_key_type=ECC), this is the C(y) coordinate for the public point on the elliptic curve.
+ - For RV(public_key_type=DSA), this is the publicly known group element whose discrete logarithm w.r.t. C(g) is the private key.
type: int
- returned: When C(public_key_type=DSA) or C(public_key_type=ECC)
+ returned: When RV(public_key_type=DSA) or RV(public_key_type=ECC)
public_key_fingerprints:
description:
- Fingerprints of certificate's public key.
@@ -331,7 +332,10 @@ signature_algorithm:
type: str
sample: sha256WithRSAEncryption
serial_number:
- description: The certificate's serial number.
+ description:
+ - The certificate's serial number.
+ - This return value is an B(integer). If you need the serial numbers as a colon-separated hex string,
+ such as C(11:22:33), you need to convert it to that form with P(community.crypto.to_serial#filter).
returned: success
type: int
sample: 1234
@@ -341,7 +345,7 @@ version:
type: int
sample: 3
valid_at:
- description: For every time stamp provided in the I(valid_at) option, a
+ description: For every time stamp provided in the O(valid_at) option, a
boolean whether the certificate is valid at that point in time
or not.
returned: success
@@ -349,24 +353,24 @@ valid_at:
subject_key_identifier:
description:
- The certificate's subject key identifier.
- - The identifier is returned in hexadecimal, with C(:) used to separate bytes.
- - Is C(none) if the C(SubjectKeyIdentifier) extension is not present.
+ - The identifier is returned in hexadecimal, with V(:) used to separate bytes.
+ - Is V(none) if the C(SubjectKeyIdentifier) extension is not present.
returned: success
type: str
sample: '00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:00:11:22:33'
authority_key_identifier:
description:
- The certificate's authority key identifier.
- - The identifier is returned in hexadecimal, with C(:) used to separate bytes.
- - Is C(none) if the C(AuthorityKeyIdentifier) extension is not present.
+ - The identifier is returned in hexadecimal, with V(:) used to separate bytes.
+ - Is V(none) if the C(AuthorityKeyIdentifier) extension is not present.
returned: success
type: str
sample: '00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:00:11:22:33'
authority_cert_issuer:
description:
- The certificate's authority cert issuer as a list of general names.
- - Is C(none) if the C(AuthorityKeyIdentifier) extension is not present.
- - See I(name_encoding) for how IDNs are handled.
+ - Is V(none) if the C(AuthorityKeyIdentifier) extension is not present.
+ - See O(name_encoding) for how IDNs are handled.
returned: success
type: list
elements: str
@@ -374,18 +378,20 @@ authority_cert_issuer:
authority_cert_serial_number:
description:
- The certificate's authority cert serial number.
- - Is C(none) if the C(AuthorityKeyIdentifier) extension is not present.
+ - Is V(none) if the C(AuthorityKeyIdentifier) extension is not present.
+ - This return value is an B(integer). If you need the serial numbers as a colon-separated hex string,
+ such as C(11:22:33), you need to convert it to that form with P(community.crypto.to_serial#filter).
returned: success
type: int
sample: 12345
ocsp_uri:
description: The OCSP responder URI, if included in the certificate. Will be
- C(none) if no OCSP responder URI is included.
+ V(none) if no OCSP responder URI is included.
returned: success
type: str
issuer_uri:
description: The Issuer URI, if included in the certificate. Will be
- C(none) if no issuer URI is included.
+ V(none) if no issuer URI is included.
returned: success
type: str
version_added: 2.9.0
diff --git a/ansible_collections/community/crypto/plugins/modules/x509_certificate_pipe.py b/ansible_collections/community/crypto/plugins/modules/x509_certificate_pipe.py
index 440a2cdf1..a968ef4c3 100644
--- a/ansible_collections/community/crypto/plugins/modules/x509_certificate_pipe.py
+++ b/ansible_collections/community/crypto/plugins/modules/x509_certificate_pipe.py
@@ -17,11 +17,8 @@ module: x509_certificate_pipe
short_description: Generate and/or check OpenSSL certificates
version_added: 1.3.0
description:
- - It implements a notion of provider (ie. C(selfsigned), C(ownca), C(entrust))
+ - It implements a notion of provider (one of V(selfsigned), V(ownca), V(entrust))
for your certificate.
- - "Please note that the module regenerates an existing certificate if it does not match the module's
- options, or if it seems to be corrupt. If you are concerned that this could overwrite
- your existing certificate, consider using the I(backup) option."
author:
- Yanis Guenane (@Spredzy)
- Markus Teufelberger (@MarkusTeufelberger)
@@ -35,13 +32,19 @@ extends_documentation_fragment:
attributes:
check_mode:
support: full
+ details:
+ - Currently in check mode, private keys will not be (re-)generated, only the changed status is
+ set. This will change in community.crypto 3.0.0.
+ - From community.crypto 3.0.0 on, the module will ignore check mode and always behave as if
+ check mode is not active. If you think this breaks your use-case of this module, please
+ create an issue in the community.crypto repository.
diff_mode:
support: full
options:
provider:
description:
- Name of the provider to use to generate/retrieve the OpenSSL certificate.
- - "The C(entrust) provider requires credentials for the
+ - "The V(entrust) provider requires credentials for the
L(Entrust Certificate Services,https://www.entrustdatacard.com/products/categories/ssl-certificates) (ECS) API."
type: str
choices: [ entrust, ownca, selfsigned ]
@@ -74,8 +77,8 @@ EXAMPLES = r'''
- name: (1/2) Generate an OpenSSL Certificate with the CSR provided inline
community.crypto.x509_certificate_pipe:
provider: ownca
- content: "{{ lookup('file', '/etc/ssl/csr/www.ansible.com.crt') }}"
- csr_content: "{{ lookup('file', '/etc/ssl/csr/www.ansible.com.csr') }}"
+ content: "{{ lookup('ansible.builtin.file', '/etc/ssl/csr/www.ansible.com.crt') }}"
+ csr_content: "{{ lookup('ansible.builtin.file', '/etc/ssl/csr/www.ansible.com.csr') }}"
ownca_cert: /path/to/ca_cert.crt
ownca_privatekey: /path/to/ca_cert.key
ownca_privatekey_passphrase: hunter2
@@ -157,6 +160,7 @@ class GenericCertificate(object):
"""Retrieve a certificate using the given module backend."""
def __init__(self, module, module_backend):
self.check_mode = module.check_mode
+ self.module = module
self.module_backend = module_backend
self.changed = False
if module.params['content'] is not None:
@@ -166,6 +170,16 @@ class GenericCertificate(object):
if self.module_backend.needs_regeneration():
if not self.check_mode:
self.module_backend.generate_certificate()
+ else:
+ self.module.deprecate(
+ 'Check mode support for x509_certificate_pipe will change in community.crypto 3.0.0'
+ ' to behave the same as without check mode. You can get that behavior right now'
+ ' by adding `check_mode: false` to the x509_certificate_pipe task. If you think this'
+ ' breaks your use-case of this module, please create an issue in the'
+ ' community.crypto repository',
+ version='3.0.0',
+ collection_name='community.crypto',
+ )
self.changed = True
def dump(self, check_mode=False):
diff --git a/ansible_collections/community/crypto/plugins/modules/x509_crl.py b/ansible_collections/community/crypto/plugins/modules/x509_crl.py
index 824ed8310..1ac97005a 100644
--- a/ansible_collections/community/crypto/plugins/modules/x509_crl.py
+++ b/ansible_collections/community/crypto/plugins/modules/x509_crl.py
@@ -45,24 +45,24 @@ options:
crl_mode:
description:
- Defines how to process entries of existing CRLs.
- - If set to C(generate), makes sure that the CRL has the exact set of revoked certificates
- as specified in I(revoked_certificates).
- - If set to C(update), makes sure that the CRL contains the revoked certificates from
- I(revoked_certificates), but can also contain other revoked certificates. If the CRL file
+ - If set to V(generate), makes sure that the CRL has the exact set of revoked certificates
+ as specified in O(revoked_certificates).
+ - If set to V(update), makes sure that the CRL contains the revoked certificates from
+ O(revoked_certificates), but can also contain other revoked certificates. If the CRL file
already exists, all entries from the existing CRL will also be included in the new CRL.
- When using C(update), you might be interested in setting I(ignore_timestamps) to C(true).
- - The default value is C(generate).
- - This parameter was called I(mode) before community.crypto 2.13.0. It has been renamed to avoid
- a collision with the common I(mode) parameter for setting the CRL file's access mode.
+ When using V(update), you might be interested in setting O(ignore_timestamps) to V(true).
+ - The default value is V(generate).
+ - This parameter was called O(mode) before community.crypto 2.13.0. It has been renamed to avoid
+ a collision with the common O(mode) parameter for setting the CRL file's access mode.
type: str
# default: generate
choices: [ generate, update ]
version_added: 2.13.0
mode:
description:
- - This parameter has been renamed to I(crl_mode). The old name I(mode) is now deprecated and will
- be removed in community.crypto 3.0.0. Replace usage of this parameter with I(crl_mode).
- - Note that from community.crypto 3.0.0 on, I(mode) will be used for the CRL file's mode.
+ - This parameter has been renamed to O(crl_mode). The old name O(mode) is now deprecated and will
+ be removed in community.crypto 3.0.0. Replace usage of this parameter with O(crl_mode).
+ - Note that from community.crypto 3.0.0 on, O(mode) will be used for the CRL file's mode.
type: str
# default: generate
choices: [ generate, update ]
@@ -89,7 +89,7 @@ options:
format:
description:
- Whether the CRL file should be in PEM or DER format.
- - If an existing CRL file does match everything but I(format), it will be converted to the correct format
+ - If an existing CRL file does match everything but O(format), it will be converted to the correct format
instead of regenerated.
type: str
choices: [pem, der]
@@ -98,18 +98,18 @@ options:
privatekey_path:
description:
- Path to the CA's private key to use when signing the CRL.
- - Either I(privatekey_path) or I(privatekey_content) must be specified if I(state) is C(present), but not both.
+ - Either O(privatekey_path) or O(privatekey_content) must be specified if O(state) is V(present), but not both.
type: path
privatekey_content:
description:
- The content of the CA's private key to use when signing the CRL.
- - Either I(privatekey_path) or I(privatekey_content) must be specified if I(state) is C(present), but not both.
+ - Either O(privatekey_path) or O(privatekey_content) must be specified if O(state) is V(present), but not both.
type: str
privatekey_passphrase:
description:
- - The passphrase for the I(privatekey_path).
+ - The passphrase for the O(privatekey_path).
- This is required if the private key is password protected.
type: str
@@ -117,9 +117,9 @@ options:
description:
- Key/value pairs that will be present in the issuer name field of the CRL.
- If you need to specify more than one value with the same key, use a list as value.
- - If the order of the components is important, use I(issuer_ordered).
- - One of I(issuer) and I(issuer_ordered) is required if I(state) is C(present).
- - Mutually exclusive with I(issuer_ordered).
+ - If the order of the components is important, use O(issuer_ordered).
+ - One of O(issuer) and O(issuer_ordered) is required if O(state) is V(present).
+ - Mutually exclusive with O(issuer_ordered).
type: dict
issuer_ordered:
description:
@@ -127,8 +127,8 @@ options:
This key/value pair will be present in the issuer name field of the CRL.
- If you want to specify more than one value with the same key in a row, you can
use a list as value.
- - One of I(issuer) and I(issuer_ordered) is required if I(state) is C(present).
- - Mutually exclusive with I(issuer).
+ - One of O(issuer) and O(issuer_ordered) is required if O(state) is V(present).
+ - Mutually exclusive with O(issuer).
type: list
elements: dict
version_added: 2.0.0
@@ -139,23 +139,23 @@ options:
- Time can be specified either as relative time or as absolute timestamp.
- Time will always be interpreted as UTC.
- Valid format is C([+-]timespec | ASN.1 TIME) where timespec can be an integer
- + C([w | d | h | m | s]) (for example C(+32w1d2h)).
+ + C([w | d | h | m | s]) (for example V(+32w1d2h)).
- Note that if using relative time this module is NOT idempotent, except when
- I(ignore_timestamps) is set to C(true).
+ O(ignore_timestamps) is set to V(true).
type: str
default: "+0s"
next_update:
description:
- - "The absolute latest point in time by which this I(issuer) is expected to have issued
- another CRL. Many clients will treat a CRL as expired once I(next_update) occurs."
+ - "The absolute latest point in time by which this O(issuer) is expected to have issued
+ another CRL. Many clients will treat a CRL as expired once O(next_update) occurs."
- Time can be specified either as relative time or as absolute timestamp.
- Time will always be interpreted as UTC.
- Valid format is C([+-]timespec | ASN.1 TIME) where timespec can be an integer
- + C([w | d | h | m | s]) (for example C(+32w1d2h)).
+ + C([w | d | h | m | s]) (for example V(+32w1d2h)).
- Note that if using relative time this module is NOT idempotent, except when
- I(ignore_timestamps) is set to C(true).
- - Required if I(state) is C(present).
+ O(ignore_timestamps) is set to V(true).
+ - Required if O(state) is V(present).
type: str
digest:
@@ -164,10 +164,25 @@ options:
type: str
default: sha256
+ serial_numbers:
+ description:
+ - This option determines which values will be accepted for O(revoked_certificates[].serial_number).
+ - If set to V(integer) (default), serial numbers are assumed to be integers, for example V(66223).
+ (This example value is equivalent to the hex octet string V(01:02:AF).)
+ - If set to V(hex-octets), serial numbers are assumed to be colon-separated hex octet strings,
+ for example V(01:02:AF).
+ (This example value is equivalent to the integer V(66223).)
+ type: str
+ choices:
+ - integer
+ - hex-octets
+ default: integer
+ version_added: 2.18.0
+
revoked_certificates:
description:
- List of certificates to be revoked.
- - Required if I(state) is C(present).
+ - Required if O(state) is V(present).
type: list
elements: dict
suboptions:
@@ -175,37 +190,46 @@ options:
description:
- Path to a certificate in PEM format.
- The serial number and issuer will be extracted from the certificate.
- - Mutually exclusive with I(content) and I(serial_number). One of these three options
+ - Mutually exclusive with O(revoked_certificates[].content) and
+ O(revoked_certificates[].serial_number). One of these three options
must be specified.
type: path
content:
description:
- Content of a certificate in PEM format.
- The serial number and issuer will be extracted from the certificate.
- - Mutually exclusive with I(path) and I(serial_number). One of these three options
+ - Mutually exclusive with O(revoked_certificates[].path) and
+ O(revoked_certificates[].serial_number). One of these three options
must be specified.
type: str
serial_number:
description:
- Serial number of the certificate.
- - Mutually exclusive with I(path) and I(content). One of these three options must
+ - Mutually exclusive with O(revoked_certificates[].path) and
+ O(revoked_certificates[].content). One of these three options must
be specified.
- type: int
+ - This option accepts integers or hex octet strings, depending on the value
+ of O(serial_numbers).
+ - If O(serial_numbers=integer), integers such as V(66223) must be provided.
+ - If O(serial_numbers=hex-octets), strings such as V(01:02:AF) must be provided.
+ - You can use the filters P(community.crypto.parse_serial#filter) and
+ P(community.crypto.to_serial#filter) to convert these two representations.
+ type: raw
revocation_date:
description:
- The point in time the certificate was revoked.
- Time can be specified either as relative time or as absolute timestamp.
- Time will always be interpreted as UTC.
- Valid format is C([+-]timespec | ASN.1 TIME) where timespec can be an integer
- + C([w | d | h | m | s]) (for example C(+32w1d2h)).
+ + C([w | d | h | m | s]) (for example V(+32w1d2h)).
- Note that if using relative time this module is NOT idempotent, except when
- I(ignore_timestamps) is set to C(true).
+ O(ignore_timestamps) is set to V(true).
type: str
default: "+0s"
issuer:
description:
- The certificate's issuer.
- - "Example: C(DNS:ca.example.org)"
+ - "Example: V(DNS:ca.example.org)"
type: list
elements: str
issuer_critical:
@@ -240,9 +264,9 @@ options:
- Time can be specified either as relative time or as absolute timestamp.
- Time will always be interpreted as UTC.
- Valid format is C([+-]timespec | ASN.1 TIME) where timespec can be an integer
- + C([w | d | h | m | s]) (for example C(+32w1d2h)).
+ + C([w | d | h | m | s]) (for example V(+32w1d2h)).
- Note that if using relative time this module is NOT idempotent. This will NOT
- change when I(ignore_timestamps) is set to C(true).
+ change when O(ignore_timestamps) is set to V(true).
type: str
invalidity_date_critical:
description:
@@ -252,22 +276,28 @@ options:
ignore_timestamps:
description:
- - Whether the timestamps I(last_update), I(next_update) and I(revocation_date) (in
- I(revoked_certificates)) should be ignored for idempotency checks. The timestamp
- I(invalidity_date) in I(revoked_certificates) will never be ignored.
+ - Whether the timestamps O(last_update), O(next_update) and
+ O(revoked_certificates[].revocation_date) should be ignored for idempotency checks.
+ The timestamp O(revoked_certificates[].invalidity_date) will never be ignored.
- Use this in combination with relative timestamps for these values to get idempotency.
type: bool
default: false
return_content:
description:
- - If set to C(true), will return the (current or generated) CRL's content as I(crl).
+ - If set to V(true), will return the (current or generated) CRL's content as RV(crl).
type: bool
default: false
notes:
- All ASN.1 TIME values should be specified following the YYYYMMDDHHMMSSZ pattern.
- Date specified should be UTC. Minutes and seconds are mandatory.
+
+seealso:
+ - plugin: community.crypto.parse_serial
+ plugin_type: filter
+ - plugin: community.crypto.to_serial
+ plugin_type: filter
'''
EXAMPLES = r'''
@@ -300,7 +330,7 @@ filename:
sample: /path/to/my-ca.crl
backup_file:
description: Name of backup file created.
- returned: changed and if I(backup) is C(true)
+ returned: changed and if O(backup) is V(true)
type: str
sample: /path/to/my-ca.crl.2019-03-09@11:22~
privatekey:
@@ -310,15 +340,18 @@ privatekey:
sample: /path/to/my-ca.pem
format:
description:
- - Whether the CRL is in PEM format (C(pem)) or in DER format (C(der)).
+ - Whether the CRL is in PEM format (V(pem)) or in DER format (V(der)).
returned: success
type: str
sample: pem
+ choices:
+ - pem
+ - der
issuer:
description:
- The CRL's issuer.
- Note that for repeated values, only the last one will be returned.
- - See I(name_encoding) for how IDNs are handled.
+ - See O(name_encoding) for how IDNs are handled.
returned: success
type: dict
sample: {"organizationName": "Ansible", "commonName": "ca.example.com"}
@@ -350,7 +383,10 @@ revoked_certificates:
elements: dict
contains:
serial_number:
- description: Serial number of the certificate.
+ description:
+ - Serial number of the certificate.
+ - This return value is an B(integer). If you need the serial numbers as a colon-separated hex string,
+ such as C(11:22:33), you need to convert it to that form with P(community.crypto.to_serial#filter).
type: int
sample: 1234
revocation_date:
@@ -360,7 +396,7 @@ revoked_certificates:
issuer:
description:
- The certificate's issuer.
- - See I(name_encoding) for how IDNs are handled.
+ - See O(name_encoding) for how IDNs are handled.
type: list
elements: str
sample: ["DNS:ca.example.org"]
@@ -371,11 +407,19 @@ revoked_certificates:
reason:
description:
- The value for the revocation reason extension.
- - One of C(unspecified), C(key_compromise), C(ca_compromise), C(affiliation_changed), C(superseded),
- C(cessation_of_operation), C(certificate_hold), C(privilege_withdrawn), C(aa_compromise), and
- C(remove_from_crl).
type: str
sample: key_compromise
+ choices:
+ - unspecified
+ - key_compromise
+ - ca_compromise
+ - affiliation_changed
+ - superseded
+ - cessation_of_operation
+ - certificate_hold
+ - privilege_withdrawn
+ - aa_compromise
+ - remove_from_crl
reason_critical:
description: Whether the revocation reason extension is critical.
type: bool
@@ -393,9 +437,9 @@ revoked_certificates:
crl:
description:
- The (current or generated) CRL's content.
- - Will be the CRL itself if I(format) is C(pem), and Base64 of the
- CRL if I(format) is C(der).
- returned: if I(state) is C(present) and I(return_content) is C(true)
+ - Will be the CRL itself if O(format) is V(pem), and Base64 of the
+ CRL if O(format) is V(der).
+ returned: if O(state) is V(present) and O(return_content) is V(true)
type: str
'''
@@ -406,7 +450,9 @@ import traceback
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible.module_utils.common.text.converters import to_native, to_text
+from ansible.module_utils.common.validation import check_type_int, check_type_str
+from ansible_collections.community.crypto.plugins.module_utils.serial import parse_serial
from ansible_collections.community.crypto.plugins.module_utils.version import LooseVersion
from ansible_collections.community.crypto.plugins.module_utils.io import (
@@ -495,6 +541,7 @@ class CRL(OpenSSLObject):
self.ignore_timestamps = module.params['ignore_timestamps']
self.return_content = module.params['return_content']
self.name_encoding = module.params['name_encoding']
+ self.serial_numbers_format = module.params['serial_numbers']
self.crl_content = None
self.privatekey_path = module.params['privatekey_path']
@@ -520,6 +567,8 @@ class CRL(OpenSSLObject):
if self.digest is None:
raise CRLError('The digest "{0}" is not supported'.format(module.params['digest']))
+ self.module = module
+
self.revoked_certificates = []
for i, rc in enumerate(module.params['revoked_certificates']):
result = {
@@ -551,7 +600,7 @@ class CRL(OpenSSLObject):
)
else:
# Specify serial_number (and potentially issuer) directly
- result['serial_number'] = rc['serial_number']
+ result['serial_number'] = self._parse_serial_number(rc['serial_number'], i)
# All other options
if rc['issuer']:
result['issuer'] = [cryptography_get_name(issuer, 'issuer') for issuer in rc['issuer']]
@@ -571,8 +620,6 @@ class CRL(OpenSSLObject):
result['invalidity_date_critical'] = rc['invalidity_date_critical']
self.revoked_certificates.append(result)
- self.module = module
-
self.backup = module.params['backup']
self.backup_file = None
@@ -606,6 +653,25 @@ class CRL(OpenSSLObject):
self.diff_after = self.diff_before = self._get_info(data)
+ def _parse_serial_number(self, value, index):
+ if self.serial_numbers_format == 'integer':
+ try:
+ return check_type_int(value)
+ except TypeError as exc:
+ self.module.fail_json(msg='Error while parsing revoked_certificates[{idx}].serial_number as an integer: {exc}'.format(
+ idx=index + 1,
+ exc=to_native(exc),
+ ))
+ if self.serial_numbers_format == 'hex-octets':
+ try:
+ return parse_serial(check_type_str(value))
+ except (TypeError, ValueError) as exc:
+ self.module.fail_json(msg='Error while parsing revoked_certificates[{idx}].serial_number as an colon-separated hex octet string: {exc}'.format(
+ idx=index + 1,
+ exc=to_native(exc),
+ ))
+ raise RuntimeError('Unexpected value %s of serial_numbers' % (self.serial_numbers_format, ))
+
def _get_info(self, data):
if data is None:
return dict()
@@ -871,7 +937,7 @@ def main():
options=dict(
path=dict(type='path'),
content=dict(type='str'),
- serial_number=dict(type='int'),
+ serial_number=dict(type='raw'),
revocation_date=dict(type='str', default='+0s'),
issuer=dict(type='list', elements='str'),
issuer_critical=dict(type='bool', default=False),
@@ -891,6 +957,7 @@ def main():
mutually_exclusive=[['path', 'content', 'serial_number']],
),
name_encoding=dict(type='str', default='ignore', choices=['ignore', 'idna', 'unicode']),
+ serial_numbers=dict(type='str', default='integer', choices=['integer', 'hex-octets']),
),
required_if=[
('state', 'present', ['privatekey_path', 'privatekey_content'], True),
diff --git a/ansible_collections/community/crypto/plugins/modules/x509_crl_info.py b/ansible_collections/community/crypto/plugins/modules/x509_crl_info.py
index 7b0ebcac9..2cf25f530 100644
--- a/ansible_collections/community/crypto/plugins/modules/x509_crl_info.py
+++ b/ansible_collections/community/crypto/plugins/modules/x509_crl_info.py
@@ -28,16 +28,16 @@ options:
path:
description:
- Remote absolute path where the generated CRL file should be created or is already located.
- - Either I(path) or I(content) must be specified, but not both.
+ - Either O(path) or O(content) must be specified, but not both.
type: path
content:
description:
- Content of the X.509 CRL in PEM format, or Base64-encoded X.509 CRL.
- - Either I(path) or I(content) must be specified, but not both.
+ - Either O(path) or O(content) must be specified, but not both.
type: str
list_revoked_certificates:
description:
- - If set to C(false), the list of revoked certificates is not included in the result.
+ - If set to V(false), the list of revoked certificates is not included in the result.
- This is useful when retrieving information on large CRL files. Enumerating all revoked
certificates can take some time, including serializing the result as JSON, sending it to
the Ansible controller, and decoding it again.
@@ -50,10 +50,11 @@ notes:
They are all in UTC.
seealso:
- module: community.crypto.x509_crl
- - ref: community.crypto.x509_crl_info filter <ansible_collections.community.crypto.x509_crl_info_filter>
- # - plugin: community.crypto.x509_crl_info
- # plugin_type: filter
+ - plugin: community.crypto.x509_crl_info
+ plugin_type: filter
description: A filter variant of this module.
+ - plugin: community.crypto.to_serial
+ plugin_type: filter
'''
EXAMPLES = r'''
@@ -76,15 +77,18 @@ EXAMPLES = r'''
RETURN = r'''
format:
description:
- - Whether the CRL is in PEM format (C(pem)) or in DER format (C(der)).
+ - Whether the CRL is in PEM format (V(pem)) or in DER format (V(der)).
returned: success
type: str
sample: pem
+ choices:
+ - pem
+ - der
issuer:
description:
- The CRL's issuer.
- Note that for repeated values, only the last one will be returned.
- - See I(name_encoding) for how IDNs are handled.
+ - See O(name_encoding) for how IDNs are handled.
returned: success
type: dict
sample: {"organizationName": "Ansible", "commonName": "ca.example.com"}
@@ -111,12 +115,15 @@ digest:
sample: sha256WithRSAEncryption
revoked_certificates:
description: List of certificates to be revoked.
- returned: success if I(list_revoked_certificates=true)
+ returned: success if O(list_revoked_certificates=true)
type: list
elements: dict
contains:
serial_number:
- description: Serial number of the certificate.
+ description:
+ - Serial number of the certificate.
+ - This return value is an B(integer). If you need the serial numbers as a colon-separated hex string,
+ such as C(11:22:33), you need to convert it to that form with P(community.crypto.to_serial#filter).
type: int
sample: 1234
revocation_date:
@@ -126,7 +133,7 @@ revoked_certificates:
issuer:
description:
- The certificate's issuer.
- - See I(name_encoding) for how IDNs are handled.
+ - See O(name_encoding) for how IDNs are handled.
type: list
elements: str
sample: ["DNS:ca.example.org"]
@@ -137,11 +144,19 @@ revoked_certificates:
reason:
description:
- The value for the revocation reason extension.
- - One of C(unspecified), C(key_compromise), C(ca_compromise), C(affiliation_changed), C(superseded),
- C(cessation_of_operation), C(certificate_hold), C(privilege_withdrawn), C(aa_compromise), and
- C(remove_from_crl).
type: str
sample: key_compromise
+ choices:
+ - unspecified
+ - key_compromise
+ - ca_compromise
+ - affiliation_changed
+ - superseded
+ - cessation_of_operation
+ - certificate_hold
+ - privilege_withdrawn
+ - aa_compromise
+ - remove_from_crl
reason_critical:
description: Whether the revocation reason extension is critical.
type: bool
diff --git a/ansible_collections/community/crypto/plugins/plugin_utils/gnupg.py b/ansible_collections/community/crypto/plugins/plugin_utils/gnupg.py
new file mode 100644
index 000000000..0cd715bf0
--- /dev/null
+++ b/ansible_collections/community/crypto/plugins/plugin_utils/gnupg.py
@@ -0,0 +1,51 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2023, Felix Fontein <felix@fontein.de>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+from subprocess import Popen, PIPE
+
+from ansible.module_utils.common.process import get_bin_path
+from ansible.module_utils.common.text.converters import to_native
+
+from ansible_collections.community.crypto.plugins.module_utils.gnupg.cli import GPGError, GPGRunner
+
+
+class PluginGPGRunner(GPGRunner):
+ def __init__(self, executable=None, cwd=None):
+ if executable is None:
+ try:
+ executable = get_bin_path('gpg')
+ except ValueError as e:
+ raise GPGError('Cannot find the `gpg` executable on the controller')
+ self.executable = executable
+ self.cwd = cwd
+
+ def run_command(self, command, check_rc=True, data=None):
+ """
+ Run ``[gpg] + command`` and return ``(rc, stdout, stderr)``.
+
+ If ``data`` is not ``None``, it will be provided as stdin.
+ The code assumes it is a bytes string.
+
+ Returned stdout and stderr are native Python strings.
+ Pass ``check_rc=False`` to allow return codes != 0.
+
+ Raises a ``GPGError`` in case of errors.
+ """
+ command = [self.executable] + command
+ p = Popen(command, shell=False, cwd=self.cwd, stdin=PIPE, stdout=PIPE, stderr=PIPE)
+ stdout, stderr = p.communicate(input=data)
+ stdout = to_native(stdout, errors='surrogate_or_replace')
+ stderr = to_native(stderr, errors='surrogate_or_replace')
+ if check_rc and p.returncode != 0:
+ raise GPGError('Running {cmd} yielded return code {rc} with stdout: "{stdout}" and stderr: "{stderr}")'.format(
+ cmd=' '.join(command),
+ rc=p.returncode,
+ stdout=to_native(stdout, errors='surrogate_or_replace'),
+ stderr=to_native(stderr, errors='surrogate_or_replace'),
+ ))
+ return p.returncode, stdout, stderr
diff --git a/ansible_collections/community/crypto/tests/integration/targets/acme_challenge_cert_helper/tasks/main.yml b/ansible_collections/community/crypto/tests/integration/targets/acme_challenge_cert_helper/tasks/main.yml
index ef40ec601..c4b138572 100644
--- a/ansible_collections/community/crypto/tests/integration/targets/acme_challenge_cert_helper/tasks/main.yml
+++ b/ansible_collections/community/crypto/tests/integration/targets/acme_challenge_cert_helper/tasks/main.yml
@@ -9,7 +9,7 @@
####################################################################
- block:
- - name: Generate ECC256 accoun keys
+ - name: Generate ECC256 account keys
openssl_privatekey:
path: "{{ remote_tmp_dir }}/account-ec256.pem"
type: ECC
diff --git a/ansible_collections/community/crypto/tests/integration/targets/filter_gpg_fingerprint/aliases b/ansible_collections/community/crypto/tests/integration/targets/filter_gpg_fingerprint/aliases
new file mode 100644
index 000000000..326a499c3
--- /dev/null
+++ b/ansible_collections/community/crypto/tests/integration/targets/filter_gpg_fingerprint/aliases
@@ -0,0 +1,6 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+azp/posix/2
+destructive
diff --git a/ansible_collections/community/crypto/tests/integration/targets/filter_gpg_fingerprint/meta/main.yml b/ansible_collections/community/crypto/tests/integration/targets/filter_gpg_fingerprint/meta/main.yml
new file mode 100644
index 000000000..398d0cf6c
--- /dev/null
+++ b/ansible_collections/community/crypto/tests/integration/targets/filter_gpg_fingerprint/meta/main.yml
@@ -0,0 +1,9 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+dependencies:
+ - prepare_jinja2_compat
+ - setup_remote_tmp_dir
+ - setup_gnupg
diff --git a/ansible_collections/community/crypto/tests/integration/targets/filter_gpg_fingerprint/tasks/main.yml b/ansible_collections/community/crypto/tests/integration/targets/filter_gpg_fingerprint/tasks/main.yml
new file mode 100644
index 000000000..071b490fd
--- /dev/null
+++ b/ansible_collections/community/crypto/tests/integration/targets/filter_gpg_fingerprint/tasks/main.yml
@@ -0,0 +1,80 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Run tests if GPG is available
+ when: has_gnupg
+ block:
+ - name: Create GPG key
+ ansible.builtin.command:
+ cmd: gpg --homedir "{{ remote_tmp_dir }}" --batch --generate-key
+ stdin: |
+ %echo Generating a basic OpenPGP key
+ %no-ask-passphrase
+ %no-protection
+ Key-Type: RSA
+ Key-Length: 4096
+ Name-Real: Foo Bar
+ Name-Email: foo@bar.com
+ Expire-Date: 0
+ %commit
+ %echo done
+ register: result
+
+ - name: Extract fingerprint
+ ansible.builtin.shell: gpg --homedir "{{ remote_tmp_dir }}" --with-colons --fingerprint foo@bar.com | grep '^fpr:'
+ register: fingerprints
+
+ - name: Show fingerprints
+ ansible.builtin.debug:
+ msg: "{{ fingerprints.stdout_lines | map('split', ':') | list }}"
+
+ - name: Export public key
+ ansible.builtin.command: gpg --homedir "{{ remote_tmp_dir }}" --export --armor foo@bar.com
+ register: public_key
+
+ - name: Export private key
+ ansible.builtin.command: gpg --homedir "{{ remote_tmp_dir }}" --export-secret-key --armor foo@bar.com
+ register: private_key
+
+ - name: Gather fingerprints
+ ansible.builtin.set_fact:
+ public_key_fingerprint: "{{ public_key.stdout | community.crypto.gpg_fingerprint }}"
+ private_key_fingerprint: "{{ private_key.stdout | community.crypto.gpg_fingerprint }}"
+
+ - name: Check whether fingerprints match
+ ansible.builtin.assert:
+ that:
+ - public_key_fingerprint == (fingerprints.stdout_lines[0] | split(':'))[9]
+ - private_key_fingerprint == (fingerprints.stdout_lines[0] | split(':'))[9]
+
+ - name: Error scenario - wrong input type
+ ansible.builtin.set_fact:
+ failing_result: "{{ 42 | community.crypto.gpg_fingerprint }}"
+ register: result
+ ignore_errors: true
+
+ - name: Check result
+ ansible.builtin.assert:
+ that:
+ - result is failed
+ - >-
+ 'The input for the community.crypto.gpg_fingerprint filter must be a string; got ' in result.msg
+ - >-
+ 'int' in result.msg
+
+ - name: Error scenario - garbage input
+ ansible.builtin.set_fact:
+ failing_result: "{{ 'garbage' | community.crypto.gpg_fingerprint }}"
+ register: result
+ ignore_errors: true
+
+ - name: Check result
+ ansible.builtin.assert:
+ that:
+ - result is failed
+ - >-
+ 'Running ' in result.msg
+ - >-
+ ('/gpg --no-keyring --with-colons --import-options show-only --import /dev/stdin yielded return code ') in result.msg
diff --git a/ansible_collections/community/crypto/tests/integration/targets/filter_parse_serial/aliases b/ansible_collections/community/crypto/tests/integration/targets/filter_parse_serial/aliases
new file mode 100644
index 000000000..12d1d6617
--- /dev/null
+++ b/ansible_collections/community/crypto/tests/integration/targets/filter_parse_serial/aliases
@@ -0,0 +1,5 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+azp/posix/2
diff --git a/ansible_collections/community/crypto/tests/integration/targets/filter_parse_serial/tasks/main.yml b/ansible_collections/community/crypto/tests/integration/targets/filter_parse_serial/tasks/main.yml
new file mode 100644
index 000000000..67175ac07
--- /dev/null
+++ b/ansible_collections/community/crypto/tests/integration/targets/filter_parse_serial/tasks/main.yml
@@ -0,0 +1,62 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Test parse_serial filter
+ assert:
+ that:
+ - >-
+ '0' | community.crypto.parse_serial == 0
+ - >-
+ '00' | community.crypto.parse_serial == 0
+ - >-
+ '000' | community.crypto.parse_serial == 0
+ - >-
+ 'ff' | community.crypto.parse_serial == 255
+ - >-
+ '0ff' | community.crypto.parse_serial == 255
+ - >-
+ '1:0' | community.crypto.parse_serial == 256
+ - >-
+ '1:2:3' | community.crypto.parse_serial == 66051
+
+- name: "Test error 1: empty string"
+ debug:
+ msg: >-
+ {{ '' | community.crypto.parse_serial }}
+ ignore_errors: true
+ register: error_1
+
+- name: "Test error 2: invalid type"
+ debug:
+ msg: >-
+ {{ [] | community.crypto.parse_serial }}
+ ignore_errors: true
+ register: error_2
+
+- name: "Test error 3: invalid values (range)"
+ debug:
+ msg: >-
+ {{ '100' | community.crypto.parse_serial }}
+ ignore_errors: true
+ register: error_3
+
+- name: "Test error 4: invalid values (digits)"
+ debug:
+ msg: >-
+ {{ 'abcdefg' | community.crypto.parse_serial }}
+ ignore_errors: true
+ register: error_4
+
+- name: Validate errors
+ assert:
+ that:
+ - >-
+ error_1 is failed and "The 1st part '' is not a hexadecimal number in range [0, 255]: invalid literal" in error_1.msg
+ - >-
+ error_2 is failed and "The input for the community.crypto.parse_serial filter must be a string; got " in error_2.msg
+ - >-
+ error_3 is failed and "The 1st part '100' is not a hexadecimal number in range [0, 255]: the value is not in range [0, 255]" in error_3.msg
+ - >-
+ error_4 is failed and "The 1st part 'abcdefg' is not a hexadecimal number in range [0, 255]: invalid literal" in error_4.msg
diff --git a/ansible_collections/community/crypto/tests/integration/targets/filter_to_serial/aliases b/ansible_collections/community/crypto/tests/integration/targets/filter_to_serial/aliases
new file mode 100644
index 000000000..12d1d6617
--- /dev/null
+++ b/ansible_collections/community/crypto/tests/integration/targets/filter_to_serial/aliases
@@ -0,0 +1,5 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+azp/posix/2
diff --git a/ansible_collections/community/crypto/tests/integration/targets/filter_to_serial/tasks/main.yml b/ansible_collections/community/crypto/tests/integration/targets/filter_to_serial/tasks/main.yml
new file mode 100644
index 000000000..1b1f4385f
--- /dev/null
+++ b/ansible_collections/community/crypto/tests/integration/targets/filter_to_serial/tasks/main.yml
@@ -0,0 +1,35 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Test to_serial filter
+ assert:
+ that:
+ - 0 | community.crypto.to_serial == '00'
+ - 1 | community.crypto.to_serial == '01'
+ - 255 | community.crypto.to_serial == 'FF'
+ - 256 | community.crypto.to_serial == '01:00'
+ - 65536 | community.crypto.to_serial == '01:00:00'
+
+- name: "Test error 1: negative number"
+ debug:
+ msg: >-
+ {{ (-1) | community.crypto.to_serial }}
+ ignore_errors: true
+ register: error_1
+
+- name: "Test error 2: invalid type"
+ debug:
+ msg: >-
+ {{ [] | community.crypto.to_serial }}
+ ignore_errors: true
+ register: error_2
+
+- name: Validate error
+ assert:
+ that:
+ - >-
+ error_1 is failed and "The input for the community.crypto.to_serial filter must not be negative" in error_1.msg
+ - >-
+ error_2 is failed and "The input for the community.crypto.to_serial filter must be an integer; got " in error_2.msg
diff --git a/ansible_collections/community/crypto/tests/integration/targets/get_certificate/tests/validate.yml b/ansible_collections/community/crypto/tests/integration/targets/get_certificate/tests/validate.yml
index 810a66f85..29ca26873 100644
--- a/ansible_collections/community/crypto/tests/integration/targets/get_certificate/tests/validate.yml
+++ b/ansible_collections/community/crypto/tests/integration/targets/get_certificate/tests/validate.yml
@@ -71,7 +71,11 @@
- result is not changed
- result is failed
# We got the expected error message
- - "'The handshake operation timed out' in result.msg or 'unknown protocol' in result.msg or 'wrong version number' in result.msg"
+ - >-
+ 'The handshake operation timed out' in result.msg
+ or 'unknown protocol' in result.msg
+ or 'wrong version number' in result.msg
+ or 'record layer failure' in result.msg
- name: Test timeout option
get_certificate:
diff --git a/ansible_collections/community/crypto/tests/integration/targets/lookup_gpg_fingerprint/aliases b/ansible_collections/community/crypto/tests/integration/targets/lookup_gpg_fingerprint/aliases
new file mode 100644
index 000000000..326a499c3
--- /dev/null
+++ b/ansible_collections/community/crypto/tests/integration/targets/lookup_gpg_fingerprint/aliases
@@ -0,0 +1,6 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+azp/posix/2
+destructive
diff --git a/ansible_collections/community/crypto/tests/integration/targets/lookup_gpg_fingerprint/meta/main.yml b/ansible_collections/community/crypto/tests/integration/targets/lookup_gpg_fingerprint/meta/main.yml
new file mode 100644
index 000000000..398d0cf6c
--- /dev/null
+++ b/ansible_collections/community/crypto/tests/integration/targets/lookup_gpg_fingerprint/meta/main.yml
@@ -0,0 +1,9 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+dependencies:
+ - prepare_jinja2_compat
+ - setup_remote_tmp_dir
+ - setup_gnupg
diff --git a/ansible_collections/community/crypto/tests/integration/targets/lookup_gpg_fingerprint/tasks/main.yml b/ansible_collections/community/crypto/tests/integration/targets/lookup_gpg_fingerprint/tasks/main.yml
new file mode 100644
index 000000000..860cbce97
--- /dev/null
+++ b/ansible_collections/community/crypto/tests/integration/targets/lookup_gpg_fingerprint/tasks/main.yml
@@ -0,0 +1,93 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Run tests if GPG is available
+ when: has_gnupg
+ block:
+ - name: Create GPG key
+ ansible.builtin.command:
+ cmd: gpg --homedir "{{ remote_tmp_dir }}" --batch --generate-key
+ stdin: |
+ %echo Generating a basic OpenPGP key
+ %no-ask-passphrase
+ %no-protection
+ Key-Type: RSA
+ Key-Length: 4096
+ Name-Real: Foo Bar
+ Name-Email: foo@bar.com
+ Expire-Date: 0
+ %commit
+ %echo done
+ register: result
+
+ - name: Extract fingerprint
+ ansible.builtin.shell: gpg --homedir "{{ remote_tmp_dir }}" --with-colons --fingerprint foo@bar.com | grep '^fpr:'
+ register: fingerprints
+
+ - name: Show fingerprints
+ ansible.builtin.debug:
+ msg: "{{ fingerprints.stdout_lines | map('split', ':') | list }}"
+
+ - name: Export public key
+ ansible.builtin.command: gpg --homedir "{{ remote_tmp_dir }}" --export --armor foo@bar.com
+ register: public_key
+
+ - name: Export private key
+ ansible.builtin.command: gpg --homedir "{{ remote_tmp_dir }}" --export-secret-key --armor foo@bar.com
+ register: private_key
+
+ - name: Write public key to disk
+ ansible.builtin.copy:
+ dest: "{{ remote_tmp_dir }}/public-key"
+ content: "{{ public_key.stdout }}"
+
+ - name: Write private key to disk
+ ansible.builtin.copy:
+ dest: "{{ remote_tmp_dir }}/private-key"
+ content: "{{ private_key.stdout }}"
+
+ - name: Gather fingerprints
+ ansible.builtin.set_fact:
+ public_key_fingerprint: "{{ lookup('community.crypto.gpg_fingerprint', remote_tmp_dir ~ '/public-key') }}"
+ private_key_fingerprint: "{{ lookup('community.crypto.gpg_fingerprint', remote_tmp_dir ~ '/private-key') }}"
+
+ - name: Check whether fingerprints match
+ ansible.builtin.assert:
+ that:
+ - public_key_fingerprint == (fingerprints.stdout_lines[0] | split(':'))[9]
+ - private_key_fingerprint == (fingerprints.stdout_lines[0] | split(':'))[9]
+
+ - name: Error scenario - file does not exist
+ ansible.builtin.set_fact:
+ failing_result: "{{ lookup('community.crypto.gpg_fingerprint', remote_tmp_dir ~ '/does-not-exist') }}"
+ register: result
+ ignore_errors: true
+
+ - name: Check result
+ ansible.builtin.assert:
+ that:
+ - result is failed
+ - >-
+ (remote_tmp_dir ~ '/does-not-exist does not exist') in result.msg
+
+ - name: Write garbage to disk
+ ansible.builtin.copy:
+ dest: "{{ remote_tmp_dir }}/garbage"
+ content: gargabe
+
+ - name: Error scenario - file contains garbage
+ ansible.builtin.set_fact:
+ failing_result: "{{ lookup('community.crypto.gpg_fingerprint', remote_tmp_dir ~ '/garbage') }}"
+ register: result
+ ignore_errors: true
+
+ - name: Check result
+ ansible.builtin.assert:
+ that:
+ - result is failed
+ - >-
+ 'Running ' in result.msg
+ - >-
+ ('/gpg --no-keyring --with-colons --import-options show-only --import ' ~ remote_tmp_dir ~ '/garbage yielded return code ') in result.msg
diff --git a/ansible_collections/community/crypto/tests/integration/targets/luks_device/tasks/tests/keyslot-create-destroy.yml b/ansible_collections/community/crypto/tests/integration/targets/luks_device/tasks/tests/keyslot-create-destroy.yml
new file mode 100644
index 000000000..51a3db362
--- /dev/null
+++ b/ansible_collections/community/crypto/tests/integration/targets/luks_device/tasks/tests/keyslot-create-destroy.yml
@@ -0,0 +1,206 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Create luks with keyslot 4 (check)
+ luks_device:
+ device: "{{ cryptfile_device }}"
+ state: present
+ keyfile: "{{ remote_tmp_dir }}/keyfile1"
+ keyslot: 4
+ pbkdf:
+ iteration_time: 0.1
+ check_mode: true
+ become: true
+ register: create_luks_slot4_check
+- name: Create luks with keyslot 4
+ luks_device:
+ device: "{{ cryptfile_device }}"
+ state: present
+ keyfile: "{{ remote_tmp_dir }}/keyfile1"
+ keyslot: 4
+ pbkdf:
+ iteration_time: 0.1
+ become: true
+ register: create_luks_slot4
+- name: Create luks with keyslot 4 (idempotent)
+ luks_device:
+ device: "{{ cryptfile_device }}"
+ state: present
+ keyfile: "{{ remote_tmp_dir }}/keyfile1"
+ keyslot: 4
+ pbkdf:
+ iteration_time: 0.1
+ become: true
+ register: create_luks_slot4_idem
+- name: Create luks with keyslot 4 (idempotent, check)
+ luks_device:
+ device: "{{ cryptfile_device }}"
+ state: present
+ keyfile: "{{ remote_tmp_dir }}/keyfile1"
+ keyslot: 4
+ pbkdf:
+ iteration_time: 0.1
+ check_mode: true
+ become: true
+ register: create_luks_slot4_idem_check
+- name: Dump luks header
+ command: "cryptsetup luksDump {{ cryptfile_device }}"
+ become: true
+ register: luks_header_slot4
+- assert:
+ that:
+ - create_luks_slot4_check is changed
+ - create_luks_slot4 is changed
+ - create_luks_slot4_idem is not changed
+ - create_luks_slot4_idem_check is not changed
+ - "'Key Slot 4: ENABLED' in luks_header_slot4.stdout or '4: luks2' in luks_header_slot4.stdout"
+
+- name: Add key in slot 2 (check)
+ luks_device:
+ device: "{{ cryptfile_device }}"
+ state: present
+ keyfile: "{{ remote_tmp_dir }}/keyfile1"
+ new_keyfile: "{{ remote_tmp_dir }}/keyfile2"
+ new_keyslot: 2
+ pbkdf:
+ iteration_time: 0.1
+ check_mode: true
+ become: true
+ register: add_luks_slot2_check
+- name: Add key in slot 2
+ luks_device:
+ device: "{{ cryptfile_device }}"
+ state: present
+ keyfile: "{{ remote_tmp_dir }}/keyfile1"
+ new_keyfile: "{{ remote_tmp_dir }}/keyfile2"
+ new_keyslot: 2
+ pbkdf:
+ iteration_time: 0.1
+ become: true
+ register: add_luks_slot2
+- name: Add key in slot 2 (idempotent)
+ luks_device:
+ device: "{{ cryptfile_device }}"
+ state: present
+ keyfile: "{{ remote_tmp_dir }}/keyfile1"
+ new_keyfile: "{{ remote_tmp_dir }}/keyfile2"
+ new_keyslot: 2
+ pbkdf:
+ iteration_time: 0.1
+ become: true
+ register: add_luks_slot2_idem
+- name: Add key in slot 2 (idempotent, check)
+ luks_device:
+ device: "{{ cryptfile_device }}"
+ state: present
+ keyfile: "{{ remote_tmp_dir }}/keyfile1"
+ new_keyfile: "{{ remote_tmp_dir }}/keyfile2"
+ new_keyslot: 2
+ pbkdf:
+ iteration_time: 0.1
+ check_mode: true
+ become: true
+ register: add_luks_slot2_idem_check
+- name: Dump luks header
+ command: "cryptsetup luksDump {{ cryptfile_device }}"
+ become: true
+ register: luks_header_slot2
+- assert:
+ that:
+ - add_luks_slot2_check is changed
+ - add_luks_slot2 is changed
+ - add_luks_slot2_idem is not changed
+ - add_luks_slot2_idem_check is not changed
+ - "'Key Slot 2: ENABLED' in luks_header_slot2.stdout or '2: luks2' in luks_header_slot2.stdout"
+
+- name: Check remove slot 4 without key
+ luks_device:
+ device: "{{ cryptfile_device }}"
+ remove_keyslot: 4
+ ignore_errors: true
+ become: true
+ register: kill_slot4_nokey
+- name: Check remove slot 4 with slot 4 key
+ luks_device:
+ device: "{{ cryptfile_device }}"
+ remove_keyslot: 4
+ keyfile: "{{ remote_tmp_dir }}/keyfile1"
+ ignore_errors: true
+ become: true
+ register: kill_slot4_key_slot4
+- assert:
+ that:
+ - kill_slot4_nokey is failed
+ - kill_slot4_key_slot4 is failed
+
+- name: Remove key in slot 4 (check)
+ luks_device:
+ device: "{{ cryptfile_device }}"
+ keyfile: "{{ remote_tmp_dir }}/keyfile2"
+ remove_keyslot: 4
+ check_mode: true
+ become: true
+ register: kill_luks_slot4_check
+- name: Remove key in slot 4
+ luks_device:
+ device: "{{ cryptfile_device }}"
+ keyfile: "{{ remote_tmp_dir }}/keyfile2"
+ remove_keyslot: 4
+ become: true
+ register: kill_luks_slot4
+- name: Remove key in slot 4 (idempotent)
+ luks_device:
+ device: "{{ cryptfile_device }}"
+ keyfile: "{{ remote_tmp_dir }}/keyfile2"
+ remove_keyslot: 4
+ become: true
+ register: kill_luks_slot4_idem
+- name: Remove key in slot 4 (idempotent)
+ luks_device:
+ device: "{{ cryptfile_device }}"
+ keyfile: "{{ remote_tmp_dir }}/keyfile2"
+ remove_keyslot: 4
+ check_mode: true
+ become: true
+ register: kill_luks_slot4_idem_check
+- name: Dump luks header
+ command: "cryptsetup luksDump {{ cryptfile_device }}"
+ become: true
+ register: luks_header_slot4_removed
+- assert:
+ that:
+ - kill_luks_slot4_check is changed
+ - kill_luks_slot4 is changed
+ - kill_luks_slot4_idem is not changed
+ - kill_luks_slot4_idem_check is not changed
+ - "'Key Slot 4: DISABLED' in luks_header_slot4_removed.stdout or not '4: luks' in luks_header_slot4_removed.stdout"
+
+- name: Add key in slot 0
+ luks_device:
+ device: "{{ cryptfile_device }}"
+ state: present
+ keyfile: "{{ remote_tmp_dir }}/keyfile2"
+ new_keyfile: "{{ remote_tmp_dir }}/keyfile1"
+ new_keyslot: 0
+ pbkdf:
+ iteration_time: 0.1
+ become: true
+ register: add_luks_slot0
+- name: Remove key in slot 0
+ luks_device:
+ device: "{{ cryptfile_device }}"
+ keyfile: "{{ remote_tmp_dir }}/keyfile2"
+ remove_keyslot: 0
+ become: true
+ register: kill_luks_slot0
+- name: Dump luks header
+ command: "cryptsetup luksDump {{ cryptfile_device }}"
+ become: true
+ register: luks_header_slot0_removed
+- assert:
+ that:
+ - add_luks_slot0 is changed
+ - kill_luks_slot0 is changed
+ - "'Key Slot 0: DISABLED' in luks_header_slot0_removed.stdout or not '0: luks' in luks_header_slot0_removed.stdout"
diff --git a/ansible_collections/community/crypto/tests/integration/targets/luks_device/tasks/tests/keyslot-duplicate.yml b/ansible_collections/community/crypto/tests/integration/targets/luks_device/tasks/tests/keyslot-duplicate.yml
new file mode 100644
index 000000000..cb9e559a1
--- /dev/null
+++ b/ansible_collections/community/crypto/tests/integration/targets/luks_device/tasks/tests/keyslot-duplicate.yml
@@ -0,0 +1,40 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Create new luks
+ luks_device:
+ device: "{{ cryptfile_device }}"
+ state: present
+ keyfile: "{{ remote_tmp_dir }}/keyfile1"
+ pbkdf:
+ iteration_time: 0.1
+ become: true
+- name: Add new keyslot with same keyfile (check)
+ luks_device:
+ device: "{{ cryptfile_device }}"
+ state: present
+ new_keyslot: 1
+ keyfile: "{{ remote_tmp_dir }}/keyfile1"
+ new_keyfile: "{{ remote_tmp_dir }}/keyfile1"
+ become: true
+ ignore_errors: true
+ check_mode: true
+ register: keyslot_duplicate_check
+- name: Add new keyslot with same keyfile
+ luks_device:
+ device: "{{ cryptfile_device }}"
+ state: present
+ new_keyslot: 1
+ keyfile: "{{ remote_tmp_dir }}/keyfile1"
+ new_keyfile: "{{ remote_tmp_dir }}/keyfile1"
+ become: true
+ ignore_errors: true
+ register: keyslot_duplicate
+- assert:
+ that:
+ - keyslot_duplicate_check is failed
+ - "'Trying to add key that is already present in another slot' in keyslot_duplicate_check.msg"
+ - keyslot_duplicate is failed
+ - "'Trying to add key that is already present in another slot' in keyslot_duplicate.msg"
diff --git a/ansible_collections/community/crypto/tests/integration/targets/luks_device/tasks/tests/keyslot-options.yml b/ansible_collections/community/crypto/tests/integration/targets/luks_device/tasks/tests/keyslot-options.yml
new file mode 100644
index 000000000..8a1ca14b3
--- /dev/null
+++ b/ansible_collections/community/crypto/tests/integration/targets/luks_device/tasks/tests/keyslot-options.yml
@@ -0,0 +1,79 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Check invalid slot (luks1, 8)
+ luks_device:
+ device: "{{ cryptfile_device }}"
+ state: present
+ type: luks1
+ keyfile: "{{ remote_tmp_dir }}/keyfile1"
+ keyslot: 8
+ pbkdf:
+ iteration_time: 0.1
+ ignore_errors: true
+ become: true
+ register: create_luks1_slot8
+- name: Check invalid slot (luks2, 32)
+ luks_device:
+ device: "{{ cryptfile_device }}"
+ state: present
+ type: luks2
+ keyfile: "{{ remote_tmp_dir }}/keyfile1"
+ keyslot: 32
+ pbkdf:
+ iteration_time: 0.1
+ ignore_errors: true
+ become: true
+ register: create_luks2_slot32
+- name: Check invalid slot (no luks type, 8)
+ luks_device:
+ device: "{{ cryptfile_device }}"
+ state: present
+ keyfile: "{{ remote_tmp_dir }}/keyfile1"
+ keyslot: 8
+ pbkdf:
+ iteration_time: 0.1
+ ignore_errors: true
+ become: true
+ register: create_luks_slot8
+- assert:
+ that:
+ - create_luks1_slot8 is failed
+ - create_luks2_slot32 is failed
+ - create_luks_slot8 is failed
+
+- name: Check valid slot (luks2, 8)
+ luks_device:
+ device: "{{ cryptfile_device }}"
+ state: present
+ type: luks2
+ keyfile: "{{ remote_tmp_dir }}/keyfile1"
+ keyslot: 8
+ pbkdf:
+ iteration_time: 0.1
+ become: true
+ ignore_errors: true
+ register: create_luks2_slot8
+- name: Make sure that the previous task only fails if LUKS2 is not supported
+ assert:
+ that:
+ - "'Unknown option --type' in create_luks2_slot8.msg"
+ when: create_luks2_slot8 is failed
+- name: Check add valid slot (no luks type, 10)
+ luks_device:
+ device: "{{ cryptfile_device }}"
+ state: present
+ keyfile: "{{ remote_tmp_dir }}/keyfile1"
+ new_keyfile: "{{ remote_tmp_dir }}/keyfile2"
+ new_keyslot: 10
+ pbkdf:
+ iteration_time: 0.1
+ become: true
+ register: create_luks_slot10
+ when: create_luks2_slot8 is changed
+- assert:
+ that:
+ - create_luks_slot10 is changed
+ when: create_luks2_slot8 is changed \ No newline at end of file
diff --git a/ansible_collections/community/crypto/tests/integration/targets/luks_device/tasks/tests/performance.yml b/ansible_collections/community/crypto/tests/integration/targets/luks_device/tasks/tests/performance.yml
index 572625517..85f28ae4f 100644
--- a/ansible_collections/community/crypto/tests/integration/targets/luks_device/tasks/tests/performance.yml
+++ b/ansible_collections/community/crypto/tests/integration/targets/luks_device/tasks/tests/performance.yml
@@ -15,6 +15,7 @@
perf_no_read_workqueue: true
perf_no_write_workqueue: true
persistent: true
+ allow_discards: true
pbkdf:
iteration_time: 0.1
check_mode: true
@@ -32,6 +33,7 @@
perf_no_read_workqueue: true
perf_no_write_workqueue: true
persistent: true
+ allow_discards: true
become: true
register: create_open
- name: Create and open (idempotent)
@@ -46,6 +48,7 @@
perf_no_read_workqueue: true
perf_no_write_workqueue: true
persistent: true
+ allow_discards: true
become: true
register: create_open_idem
- name: Create and open (idempotent, check)
@@ -60,6 +63,7 @@
perf_no_read_workqueue: true
perf_no_write_workqueue: true
persistent: true
+ allow_discards: true
check_mode: true
become: true
register: create_open_idem_check
@@ -80,6 +84,7 @@
- "'no-write-workqueue' in luks_header.stdout"
- "'same-cpu-crypt' in luks_header.stdout"
- "'submit-from-crypt-cpus' in luks_header.stdout"
+ - "'allow-discards' in luks_header.stdout"
- name: Dump device mapper table
command: "dmsetup table {{ create_open.name }}"
@@ -91,6 +96,7 @@
- "'no_write_workqueue' in dm_table.stdout"
- "'same_cpu_crypt' in dm_table.stdout"
- "'submit_from_crypt_cpus' in dm_table.stdout"
+ - "'allow_discards' in dm_table.stdout"
- name: Closed and Removed
luks_device:
diff --git a/ansible_collections/community/crypto/tests/integration/targets/luks_device/vars/Alpine.yml b/ansible_collections/community/crypto/tests/integration/targets/luks_device/vars/Alpine.yml
index c0d230abf..e7e1f184a 100644
--- a/ansible_collections/community/crypto/tests/integration/targets/luks_device/vars/Alpine.yml
+++ b/ansible_collections/community/crypto/tests/integration/targets/luks_device/vars/Alpine.yml
@@ -7,4 +7,5 @@ cryptsetup_package: cryptsetup
luks_extra_packages:
- device-mapper
+ - lsblk
- wipefs
diff --git a/ansible_collections/community/crypto/tests/integration/targets/openssh_cert/tests/idempotency.yml b/ansible_collections/community/crypto/tests/integration/targets/openssh_cert/tests/idempotency.yml
index c83596997..b1dd4a650 100644
--- a/ansible_collections/community/crypto/tests/integration/targets/openssh_cert/tests/idempotency.yml
+++ b/ansible_collections/community/crypto/tests/integration/targets/openssh_cert/tests/idempotency.yml
@@ -31,7 +31,7 @@
valid_to: forever
check_mode: true
changed: true
- - test_name: Generate cert - force option (idemopotent, check mode)
+ - test_name: Generate cert - force option (idempotent, check mode)
force: true
type: user
valid_from: always
diff --git a/ansible_collections/community/crypto/tests/integration/targets/openssh_keypair/tests/cryptography_backend.yml b/ansible_collections/community/crypto/tests/integration/targets/openssh_keypair/tests/cryptography_backend.yml
index b72c0be68..cf09dc20f 100644
--- a/ansible_collections/community/crypto/tests/integration/targets/openssh_keypair/tests/cryptography_backend.yml
+++ b/ansible_collections/community/crypto/tests/integration/targets/openssh_keypair/tests/cryptography_backend.yml
@@ -75,7 +75,7 @@
state: absent
- name: Generate PEM encoded key with passphrase
- command: 'ssh-keygen -b 1280 -f {{ remote_tmp_dir }}/pem_encoded -N {{ passphrase }} -m PEM'
+ command: 'ssh-keygen -t rsa -b 1280 -f {{ remote_tmp_dir }}/pem_encoded -N {{ passphrase }} -m PEM'
- name: Try to verify a PEM encoded key
openssh_keypair:
diff --git a/ansible_collections/community/crypto/tests/integration/targets/openssh_keypair/tests/options.yml b/ansible_collections/community/crypto/tests/integration/targets/openssh_keypair/tests/options.yml
index fdabd7614..0d324939c 100644
--- a/ansible_collections/community/crypto/tests/integration/targets/openssh_keypair/tests/options.yml
+++ b/ansible_collections/community/crypto/tests/integration/targets/openssh_keypair/tests/options.yml
@@ -100,8 +100,10 @@
comment: "test_modified@comment"
backend: "{{ backend }}"
register: modified_comment_output
+ ignore_errors: true
- name: "({{ backend }}) Assert comment preserved public key - comment"
+ when: modified_comment_output is succeeded
assert:
that:
- comment_output.public_key == modified_comment_output.public_key
@@ -111,9 +113,17 @@
assert:
that:
- modified_comment_output.comment == 'test_modified@comment'
+ - modified_comment_output is succeeded
# Support for updating comments for key types other than rsa1 was added in OpenSSH 7.2
when: not (backend == 'opensshbin' and openssh_version is version('7.2', '<'))
+- name: "({{ backend }}) Assert comment not changed - comment"
+ assert:
+ that:
+ - modified_comment_output is failed
+ # Support for updating comments for key types other than rsa1 was added in OpenSSH 7.2
+ when: backend == 'opensshbin' and openssh_version is version('7.2', '<')
+
- name: "({{ backend }}) Remove key - comment"
openssh_keypair:
path: "{{ remote_tmp_dir }}/comment"
diff --git a/ansible_collections/community/crypto/tests/integration/targets/openssh_keypair/tests/regenerate.yml b/ansible_collections/community/crypto/tests/integration/targets/openssh_keypair/tests/regenerate.yml
index d10096044..f9e2f43b3 100644
--- a/ansible_collections/community/crypto/tests/integration/targets/openssh_keypair/tests/regenerate.yml
+++ b/ansible_collections/community/crypto/tests/integration/targets/openssh_keypair/tests/regenerate.yml
@@ -329,22 +329,25 @@
that:
- result is changed
-- name: "({{ backend }}) Regenerate - adjust comment"
- openssh_keypair:
- path: '{{ remote_tmp_dir }}/regenerate-a-{{ item }}'
- type: dsa
- size: 1024
- comment: test comment
- regenerate: '{{ item }}'
- backend: "{{ backend }}"
- loop: "{{ regenerate_values }}"
- register: result
-- assert:
- that:
- - result is changed
- # for all values but 'always', the key should not be regenerated.
- # verify this by comparing fingerprints:
- - result.results[0].fingerprint == result.results[1].fingerprint
- - result.results[0].fingerprint == result.results[2].fingerprint
- - result.results[0].fingerprint == result.results[3].fingerprint
- - result.results[0].fingerprint != result.results[4].fingerprint
+# Support for updating comments for key types other than rsa1 was added in OpenSSH 7.2
+- when: not (backend == 'opensshbin' and openssh_version is version('7.2', '<'))
+ block:
+ - name: "({{ backend }}) Regenerate - adjust comment"
+ openssh_keypair:
+ path: '{{ remote_tmp_dir }}/regenerate-a-{{ item }}'
+ type: dsa
+ size: 1024
+ comment: test comment
+ regenerate: '{{ item }}'
+ backend: "{{ backend }}"
+ loop: "{{ regenerate_values }}"
+ register: result
+ - assert:
+ that:
+ - result is changed
+ # for all values but 'always', the key should not be regenerated.
+ # verify this by comparing fingerprints:
+ - result.results[0].fingerprint == result.results[1].fingerprint
+ - result.results[0].fingerprint == result.results[2].fingerprint
+ - result.results[0].fingerprint == result.results[3].fingerprint
+ - result.results[0].fingerprint != result.results[4].fingerprint
diff --git a/ansible_collections/community/crypto/tests/integration/targets/openssl_pkcs12/tasks/main.yml b/ansible_collections/community/crypto/tests/integration/targets/openssl_pkcs12/tasks/main.yml
index 7116c8674..cad051c6c 100644
--- a/ansible_collections/community/crypto/tests/integration/targets/openssl_pkcs12/tasks/main.yml
+++ b/ansible_collections/community/crypto/tests/integration/targets/openssl_pkcs12/tasks/main.yml
@@ -69,7 +69,10 @@
vars:
select_crypto_backend: pyopenssl
- when: (pyopenssl_version.stdout | default('0.0')) is version('0.15', '>=')
+ when: >-
+ (pyopenssl_version.stdout | default('0.0')) is version('0.15', '>=')
+ and
+ (pyopenssl_version.stdout | default('0.0')) is version('23.3.0', '<')
- block:
- name: Running tests with cryptography backend
@@ -79,4 +82,11 @@
when: cryptography_version.stdout is version('3.0', '>=')
- when: (pyopenssl_version.stdout | default('0.0')) is version('0.15', '>=') or cryptography_version.stdout is version('3.0', '>=')
+ when: >-
+ (
+ (pyopenssl_version.stdout | default('0.0')) is version('0.15', '>=')
+ and
+ (pyopenssl_version.stdout | default('0.0')) is version('23.3.0', '<')
+ )
+ or
+ cryptography_version.stdout is version('3.0', '>=')
diff --git a/ansible_collections/community/crypto/tests/integration/targets/openssl_privatekey/tests/validate.yml b/ansible_collections/community/crypto/tests/integration/targets/openssl_privatekey/tests/validate.yml
index 8f134dddf..4d92c2546 100644
--- a/ansible_collections/community/crypto/tests/integration/targets/openssl_privatekey/tests/validate.yml
+++ b/ansible_collections/community/crypto/tests/integration/targets/openssl_privatekey/tests/validate.yml
@@ -74,7 +74,7 @@
shell: "{{ openssl_binary }} rsa -noout -text -in {{ remote_tmp_dir }}/privatekey5.pem -passin pass:ansible | grep Private | sed 's/\\(RSA *\\)*Private-Key: (\\(.*\\) bit.*)/\\2/'"
register: privatekey5
# Current version of OS/X that runs in the CI (10.11) does not have an up to date version of the OpenSSL library
- # leading to this test to fail when run in the CI. However, this test has been run for 10.12 and has returned succesfully.
+ # leading to this test to fail when run in the CI. However, this test has been run for 10.12 and has returned successfully.
when: openssl_version.stdout is version('0.9.8zh', '>=')
- name: "({{ select_crypto_backend }}) Validate privatekey5 (assert - Passphrase protected key + idempotence)"
diff --git a/ansible_collections/community/crypto/tests/integration/targets/openssl_publickey/tests/validate.yml b/ansible_collections/community/crypto/tests/integration/targets/openssl_publickey/tests/validate.yml
index 8a1ab86e3..8c8a7292c 100644
--- a/ansible_collections/community/crypto/tests/integration/targets/openssl_publickey/tests/validate.yml
+++ b/ansible_collections/community/crypto/tests/integration/targets/openssl_publickey/tests/validate.yml
@@ -43,7 +43,7 @@
- name: "({{ select_crypto_backend }}) Validate public key - OpenSSH format (assert)"
assert:
that:
- - privatekey_publickey.stdout == '{{ publickey.content|b64decode }}'
+ - privatekey_publickey.stdout == publickey.content | b64decode
when: select_crypto_backend == 'cryptography' and cryptography_version.stdout is version('1.4.0', '>=')
- name: "({{ select_crypto_backend }}) Validate public key - OpenSSH format - test idempotence (issue 33256)"
diff --git a/ansible_collections/community/crypto/tests/integration/targets/prepare_jinja2_compat/filter_plugins/ansible_compatibility.py b/ansible_collections/community/crypto/tests/integration/targets/prepare_jinja2_compat/filter_plugins/ansible_compatibility.py
new file mode 100644
index 000000000..c14af4ccb
--- /dev/null
+++ b/ansible_collections/community/crypto/tests/integration/targets/prepare_jinja2_compat/filter_plugins/ansible_compatibility.py
@@ -0,0 +1,20 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+
+# Added in ansible-core 2.11
+def compatibility_split_filter(text, by_what):
+ return text.split(by_what)
+
+
+class FilterModule:
+ ''' Jinja2 compat filters '''
+
+ def filters(self):
+ return {
+ 'split': compatibility_split_filter,
+ }
diff --git a/ansible_collections/community/crypto/tests/integration/targets/prepare_jinja2_compat/filter_plugins/jinja_compatibility.py b/ansible_collections/community/crypto/tests/integration/targets/prepare_jinja2_compat/filter_plugins/jinja_compatibility.py
index 87ce01dce..98180a177 100644
--- a/ansible_collections/community/crypto/tests/integration/targets/prepare_jinja2_compat/filter_plugins/jinja_compatibility.py
+++ b/ansible_collections/community/crypto/tests/integration/targets/prepare_jinja2_compat/filter_plugins/jinja_compatibility.py
@@ -1,6 +1,11 @@
-# Copyright (c) Ansible Project
-# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
-# SPDX-License-Identifier: GPL-3.0-or-later
+# This code is part of Ansible, but is an independent component.
+# This particular file snippet, and this file snippet only, is licensed under the
+# BSD-3-Clause License. Modules you write using this snippet, which is embedded
+# dynamically by Ansible, still belong to the author of the module, and may assign
+# their own license to the complete work.
+
+# The BSD License license has been included as LICENSES/BSD-3-Clause.txt in this collection.
+# SPDX-License-Identifier: BSD-3-Clause
# Copyright 2007 Pallets
#
diff --git a/ansible_collections/community/crypto/tests/integration/targets/setup_gnupg/meta/main.yml b/ansible_collections/community/crypto/tests/integration/targets/setup_gnupg/meta/main.yml
new file mode 100644
index 000000000..2fcd152f9
--- /dev/null
+++ b/ansible_collections/community/crypto/tests/integration/targets/setup_gnupg/meta/main.yml
@@ -0,0 +1,7 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+dependencies:
+ - setup_pkg_mgr
diff --git a/ansible_collections/community/crypto/tests/integration/targets/setup_gnupg/tasks/main.yml b/ansible_collections/community/crypto/tests/integration/targets/setup_gnupg/tasks/main.yml
new file mode 100644
index 000000000..9e02356fc
--- /dev/null
+++ b/ansible_collections/community/crypto/tests/integration/targets/setup_gnupg/tasks/main.yml
@@ -0,0 +1,30 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Print distribution specific data
+ ansible.builtin.debug:
+ msg: |
+ Distribution: {{ ansible_facts.distribution }}
+ Distribution version: {{ ansible_facts.distribution_version }}
+ Distribution major version: {{ ansible_facts.distribution_major_version }}
+ OS family: {{ ansible_facts.os_family }}
+
+- name: Include distribution specific variables
+ ansible.builtin.include_vars: '{{ lookup("ansible.builtin.first_found", params) }}'
+ vars:
+ params:
+ files:
+ - '{{ ansible_facts.distribution }}-{{ ansible_facts.distribution_version }}.yml'
+ - '{{ ansible_facts.distribution }}-{{ ansible_facts.distribution_major_version }}.yml'
+ - '{{ ansible_facts.distribution }}.yml'
+ - '{{ ansible_facts.os_family }}.yml'
+ - default.yml
+ paths:
+ - '{{ role_path }}/vars'
+
+- name: Install GnuPG
+ ansible.builtin.package:
+ name: '{{ gnupg_package_name }}'
+ when: has_gnupg
diff --git a/ansible_collections/community/crypto/tests/integration/targets/setup_gnupg/vars/Alpine.yml b/ansible_collections/community/crypto/tests/integration/targets/setup_gnupg/vars/Alpine.yml
new file mode 100644
index 000000000..99bd64412
--- /dev/null
+++ b/ansible_collections/community/crypto/tests/integration/targets/setup_gnupg/vars/Alpine.yml
@@ -0,0 +1,8 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# Alpine 3.12 should have GnuPG, but for some reason installing it fails...
+has_gnupg: "{{ ansible_facts.distribution_version is version('3.13', '>=') }}"
+gnupg_package_name: gpg
diff --git a/ansible_collections/community/crypto/tests/integration/targets/setup_gnupg/vars/CentOS-6.yml b/ansible_collections/community/crypto/tests/integration/targets/setup_gnupg/vars/CentOS-6.yml
new file mode 100644
index 000000000..fd09e9142
--- /dev/null
+++ b/ansible_collections/community/crypto/tests/integration/targets/setup_gnupg/vars/CentOS-6.yml
@@ -0,0 +1,7 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+has_gnupg: false
+# The GnuPG version included with CentOS 6 is too old, it doesn't understand --generate-key
diff --git a/ansible_collections/community/crypto/tests/integration/targets/setup_gnupg/vars/Darwin.yml b/ansible_collections/community/crypto/tests/integration/targets/setup_gnupg/vars/Darwin.yml
new file mode 100644
index 000000000..a7d999db8
--- /dev/null
+++ b/ansible_collections/community/crypto/tests/integration/targets/setup_gnupg/vars/Darwin.yml
@@ -0,0 +1,7 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# TODO Homebrew currently isn't happy when running as root, so assume we don't have GnuPG
+has_gnupg: false
diff --git a/ansible_collections/community/crypto/tests/integration/targets/setup_gnupg/vars/RedHat.yml b/ansible_collections/community/crypto/tests/integration/targets/setup_gnupg/vars/RedHat.yml
new file mode 100644
index 000000000..3e82c4f98
--- /dev/null
+++ b/ansible_collections/community/crypto/tests/integration/targets/setup_gnupg/vars/RedHat.yml
@@ -0,0 +1,7 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+has_gnupg: true
+gnupg_package_name: gnupg2
diff --git a/ansible_collections/community/crypto/tests/integration/targets/setup_gnupg/vars/default.yml b/ansible_collections/community/crypto/tests/integration/targets/setup_gnupg/vars/default.yml
new file mode 100644
index 000000000..6059ed80e
--- /dev/null
+++ b/ansible_collections/community/crypto/tests/integration/targets/setup_gnupg/vars/default.yml
@@ -0,0 +1,7 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+has_gnupg: true
+gnupg_package_name: gnupg
diff --git a/ansible_collections/community/crypto/tests/integration/targets/setup_python_info/vars/main.yml b/ansible_collections/community/crypto/tests/integration/targets/setup_python_info/vars/main.yml
index ec2170aed..8bbf9f670 100644
--- a/ansible_collections/community/crypto/tests/integration/targets/setup_python_info/vars/main.yml
+++ b/ansible_collections/community/crypto/tests/integration/targets/setup_python_info/vars/main.yml
@@ -72,6 +72,8 @@ system_python_version_data:
Debian:
'11':
- '3.9'
+ '12':
+ - '3.11'
Alpine:
'3.16':
- '3.10'
diff --git a/ansible_collections/community/crypto/tests/integration/targets/x509_certificate/tests/validate_ownca.yml b/ansible_collections/community/crypto/tests/integration/targets/x509_certificate/tests/validate_ownca.yml
index b1569a94c..ac25b6295 100644
--- a/ansible_collections/community/crypto/tests/integration/targets/x509_certificate/tests/validate_ownca.yml
+++ b/ansible_collections/community/crypto/tests/integration/targets/x509_certificate/tests/validate_ownca.yml
@@ -15,7 +15,7 @@
shell: '{{ openssl_binary }} x509 -noout -in {{ remote_tmp_dir}}/ownca_cert.pem -text | grep "Issuer" | sed "s/.*: \(.*\)/\1/g"'
register: ownca_cert_issuer
-- name: (OwnCA validation, {{select_crypto_backend}}) Validate ownca certificate (test - ownca certficate version == default == 3)
+- name: (OwnCA validation, {{select_crypto_backend}}) Validate ownca certificate (test - ownca certificate version == default == 3)
shell: '{{ openssl_binary }} x509 -noout -in {{ remote_tmp_dir}}/ownca_cert.pem -text | grep "Version" | sed "s/.*: \(.*\) .*/\1/g"'
register: ownca_cert_version
diff --git a/ansible_collections/community/crypto/tests/integration/targets/x509_certificate/tests/validate_selfsigned.yml b/ansible_collections/community/crypto/tests/integration/targets/x509_certificate/tests/validate_selfsigned.yml
index dfb1d8713..c76310437 100644
--- a/ansible_collections/community/crypto/tests/integration/targets/x509_certificate/tests/validate_selfsigned.yml
+++ b/ansible_collections/community/crypto/tests/integration/targets/x509_certificate/tests/validate_selfsigned.yml
@@ -18,7 +18,7 @@
shell: '{{ openssl_binary }} x509 -noout -modulus -in {{ remote_tmp_dir }}/cert_no_csr.pem'
register: cert_modulus
-- name: (Selfsigned validation, {{select_crypto_backend}}) Validate certificate with no CSR (test - certficate version == default == 3)
+- name: (Selfsigned validation, {{select_crypto_backend}}) Validate certificate with no CSR (test - certificate version == default == 3)
shell: '{{ openssl_binary }} x509 -noout -in {{ remote_tmp_dir}}/cert_no_csr.pem -text | grep "Version" | sed "s/.*: \(.*\) .*/\1/g"'
register: cert_version
@@ -55,7 +55,7 @@
register: cert_issuer
-- name: (Selfsigned validation, {{select_crypto_backend}}) Validate certificate (test - certficate version == default == 3)
+- name: (Selfsigned validation, {{select_crypto_backend}}) Validate certificate (test - certificate version == default == 3)
shell: '{{ openssl_binary }} x509 -noout -in {{ remote_tmp_dir}}/cert.pem -text | grep "Version" | sed "s/.*: \(.*\) .*/\1/g"'
register: cert_version
diff --git a/ansible_collections/community/crypto/tests/integration/targets/x509_crl/tasks/impl.yml b/ansible_collections/community/crypto/tests/integration/targets/x509_crl/tasks/impl.yml
index 11fa7dcca..29f2c473d 100644
--- a/ansible_collections/community/crypto/tests/integration/targets/x509_crl/tasks/impl.yml
+++ b/ansible_collections/community/crypto/tests/integration/targets/x509_crl/tasks/impl.yml
@@ -119,7 +119,7 @@
- cert-2.pem
register: slurp
-- name: Create CRL 1 (idempotent with content, check mode)
+- name: Create CRL 1 (idempotent with content and octet string serial, check mode)
x509_crl:
path: '{{ remote_tmp_dir }}/ca-crl1.crl'
privatekey_content: "{{ slurp.results[0].content | b64decode }}"
@@ -127,6 +127,7 @@
CN: Ansible
last_update: 20191013000000Z
next_update: 20191113000000Z
+ serial_numbers: hex-octets
revoked_certificates:
- content: "{{ slurp.results[1].content | b64decode }}"
revocation_date: 20191013000000Z
@@ -135,12 +136,12 @@
reason: key_compromise
reason_critical: true
invalidity_date: 20191012000000Z
- - serial_number: 1234
+ - serial_number: 04:D2
revocation_date: 20191001000000Z
check_mode: true
register: crl_1_idem_content_check
-- name: Create CRL 1 (idempotent with content)
+- name: Create CRL 1 (idempotent with content and octet string serial)
x509_crl:
path: '{{ remote_tmp_dir }}/ca-crl1.crl'
privatekey_content: "{{ slurp.results[0].content | b64decode }}"
@@ -148,6 +149,7 @@
CN: Ansible
last_update: 20191013000000Z
next_update: 20191113000000Z
+ serial_numbers: hex-octets
revoked_certificates:
- content: "{{ slurp.results[1].content | b64decode }}"
revocation_date: 20191013000000Z
@@ -156,7 +158,7 @@
reason: key_compromise
reason_critical: true
invalidity_date: 20191012000000Z
- - serial_number: 1234
+ - serial_number: 04:D2
revocation_date: 20191001000000Z
register: crl_1_idem_content
@@ -220,7 +222,7 @@
reason: key_compromise
reason_critical: true
invalidity_date: 20191012000000Z
- - serial_number: 1234
+ - serial_number: "1234"
revocation_date: 20191001000000Z
check_mode: true
register: crl_1_format_idem_check
@@ -242,7 +244,7 @@
reason: key_compromise
reason_critical: true
invalidity_date: 20191012000000Z
- - serial_number: 1234
+ - serial_number: "1234"
revocation_date: 20191001000000Z
return_content: true
register: crl_1_format_idem
diff --git a/ansible_collections/community/crypto/tests/sanity/extra/extra-docs.py b/ansible_collections/community/crypto/tests/sanity/extra/extra-docs.py
index c636beb08..251e6d70f 100755
--- a/ansible_collections/community/crypto/tests/sanity/extra/extra-docs.py
+++ b/ansible_collections/community/crypto/tests/sanity/extra/extra-docs.py
@@ -17,7 +17,7 @@ def main():
suffix = ':{env}'.format(env=env["ANSIBLE_COLLECTIONS_PATH"]) if 'ANSIBLE_COLLECTIONS_PATH' in env else ''
env['ANSIBLE_COLLECTIONS_PATH'] = '{root}{suffix}'.format(root=os.path.dirname(os.path.dirname(os.path.dirname(os.getcwd()))), suffix=suffix)
p = subprocess.run(
- ['antsibull-docs', 'lint-collection-docs', '--plugin-docs', '--disallow-semantic-markup', '--skip-rstcheck', '.'],
+ ['antsibull-docs', 'lint-collection-docs', '--plugin-docs', '--skip-rstcheck', '.'],
env=env,
check=False,
)
diff --git a/ansible_collections/community/crypto/tests/sanity/ignore-2.10.txt b/ansible_collections/community/crypto/tests/sanity/ignore-2.10.txt
index 56340b5b3..81d34f186 100644
--- a/ansible_collections/community/crypto/tests/sanity/ignore-2.10.txt
+++ b/ansible_collections/community/crypto/tests/sanity/ignore-2.10.txt
@@ -4,6 +4,21 @@
.azure-pipelines/scripts/publish-codecov.py compile-3.5!skip # Uses Python 3.6+ syntax
.azure-pipelines/scripts/publish-codecov.py future-import-boilerplate
.azure-pipelines/scripts/publish-codecov.py metaclass-boilerplate
+docs/docsite/rst/guide_selfsigned.rst rstcheck
plugins/modules/acme_account_info.py validate-modules:return-syntax-error
+plugins/modules/acme_challenge_cert_helper.py validate-modules:return-syntax-error
+plugins/modules/ecs_certificate.py validate-modules:invalid-documentation
+plugins/modules/get_certificate.py validate-modules:invalid-documentation
+plugins/modules/openssh_cert.py validate-modules:invalid-documentation
+plugins/modules/openssl_csr.py validate-modules:invalid-documentation
+plugins/modules/openssl_csr_info.py validate-modules:invalid-documentation
+plugins/modules/openssl_csr_pipe.py validate-modules:invalid-documentation
+plugins/modules/openssl_privatekey_info.py validate-modules:invalid-documentation
+plugins/modules/openssl_publickey_info.py validate-modules:invalid-documentation
+plugins/modules/x509_certificate_info.py validate-modules:invalid-documentation
+plugins/modules/x509_crl.py validate-modules:invalid-documentation
+plugins/modules/x509_crl.py validate-modules:return-syntax-error
+plugins/modules/x509_crl_info.py validate-modules:invalid-documentation
+plugins/modules/x509_crl_info.py validate-modules:return-syntax-error
tests/ee/roles/smoke/library/smoke_ipaddress.py shebang
tests/ee/roles/smoke/library/smoke_pyyaml.py shebang
diff --git a/ansible_collections/community/crypto/tests/sanity/ignore-2.11.txt b/ansible_collections/community/crypto/tests/sanity/ignore-2.11.txt
index 56340b5b3..2677551db 100644
--- a/ansible_collections/community/crypto/tests/sanity/ignore-2.11.txt
+++ b/ansible_collections/community/crypto/tests/sanity/ignore-2.11.txt
@@ -5,5 +5,19 @@
.azure-pipelines/scripts/publish-codecov.py future-import-boilerplate
.azure-pipelines/scripts/publish-codecov.py metaclass-boilerplate
plugins/modules/acme_account_info.py validate-modules:return-syntax-error
+plugins/modules/acme_challenge_cert_helper.py validate-modules:return-syntax-error
+plugins/modules/ecs_certificate.py validate-modules:invalid-documentation
+plugins/modules/get_certificate.py validate-modules:invalid-documentation
+plugins/modules/openssh_cert.py validate-modules:invalid-documentation
+plugins/modules/openssl_csr.py validate-modules:invalid-documentation
+plugins/modules/openssl_csr_info.py validate-modules:invalid-documentation
+plugins/modules/openssl_csr_pipe.py validate-modules:invalid-documentation
+plugins/modules/openssl_privatekey_info.py validate-modules:invalid-documentation
+plugins/modules/openssl_publickey_info.py validate-modules:invalid-documentation
+plugins/modules/x509_certificate_info.py validate-modules:invalid-documentation
+plugins/modules/x509_crl.py validate-modules:invalid-documentation
+plugins/modules/x509_crl.py validate-modules:return-syntax-error
+plugins/modules/x509_crl_info.py validate-modules:invalid-documentation
+plugins/modules/x509_crl_info.py validate-modules:return-syntax-error
tests/ee/roles/smoke/library/smoke_ipaddress.py shebang
tests/ee/roles/smoke/library/smoke_pyyaml.py shebang
diff --git a/ansible_collections/community/crypto/tests/sanity/ignore-2.12.txt b/ansible_collections/community/crypto/tests/sanity/ignore-2.12.txt
index c9b09ca4e..26e5b6864 100644
--- a/ansible_collections/community/crypto/tests/sanity/ignore-2.12.txt
+++ b/ansible_collections/community/crypto/tests/sanity/ignore-2.12.txt
@@ -1,4 +1,18 @@
.azure-pipelines/scripts/publish-codecov.py replace-urlopen
plugins/modules/acme_account_info.py validate-modules:return-syntax-error
+plugins/modules/acme_challenge_cert_helper.py validate-modules:return-syntax-error
+plugins/modules/ecs_certificate.py validate-modules:invalid-documentation
+plugins/modules/get_certificate.py validate-modules:invalid-documentation
+plugins/modules/openssh_cert.py validate-modules:invalid-documentation
+plugins/modules/openssl_csr.py validate-modules:invalid-documentation
+plugins/modules/openssl_csr_info.py validate-modules:invalid-documentation
+plugins/modules/openssl_csr_pipe.py validate-modules:invalid-documentation
+plugins/modules/openssl_privatekey_info.py validate-modules:invalid-documentation
+plugins/modules/openssl_publickey_info.py validate-modules:invalid-documentation
+plugins/modules/x509_certificate_info.py validate-modules:invalid-documentation
+plugins/modules/x509_crl.py validate-modules:invalid-documentation
+plugins/modules/x509_crl.py validate-modules:return-syntax-error
+plugins/modules/x509_crl_info.py validate-modules:invalid-documentation
+plugins/modules/x509_crl_info.py validate-modules:return-syntax-error
tests/ee/roles/smoke/library/smoke_ipaddress.py shebang
tests/ee/roles/smoke/library/smoke_pyyaml.py shebang
diff --git a/ansible_collections/community/crypto/tests/sanity/ignore-2.13.txt b/ansible_collections/community/crypto/tests/sanity/ignore-2.13.txt
index ca127b4fd..74ca94712 100644
--- a/ansible_collections/community/crypto/tests/sanity/ignore-2.13.txt
+++ b/ansible_collections/community/crypto/tests/sanity/ignore-2.13.txt
@@ -1,3 +1,15 @@
.azure-pipelines/scripts/publish-codecov.py replace-urlopen
+plugins/lookup/gpg_fingerprint.py validate-modules:invalid-documentation
+plugins/modules/ecs_certificate.py validate-modules:invalid-documentation
+plugins/modules/get_certificate.py validate-modules:invalid-documentation
+plugins/modules/openssh_cert.py validate-modules:invalid-documentation
+plugins/modules/openssl_csr.py validate-modules:invalid-documentation
+plugins/modules/openssl_csr_info.py validate-modules:invalid-documentation
+plugins/modules/openssl_csr_pipe.py validate-modules:invalid-documentation
+plugins/modules/openssl_privatekey_info.py validate-modules:invalid-documentation
+plugins/modules/openssl_publickey_info.py validate-modules:invalid-documentation
+plugins/modules/x509_certificate_info.py validate-modules:invalid-documentation
+plugins/modules/x509_crl.py validate-modules:invalid-documentation
+plugins/modules/x509_crl_info.py validate-modules:invalid-documentation
tests/ee/roles/smoke/library/smoke_ipaddress.py shebang
tests/ee/roles/smoke/library/smoke_pyyaml.py shebang
diff --git a/ansible_collections/community/crypto/tests/sanity/ignore-2.14.txt b/ansible_collections/community/crypto/tests/sanity/ignore-2.14.txt
index ca127b4fd..74ca94712 100644
--- a/ansible_collections/community/crypto/tests/sanity/ignore-2.14.txt
+++ b/ansible_collections/community/crypto/tests/sanity/ignore-2.14.txt
@@ -1,3 +1,15 @@
.azure-pipelines/scripts/publish-codecov.py replace-urlopen
+plugins/lookup/gpg_fingerprint.py validate-modules:invalid-documentation
+plugins/modules/ecs_certificate.py validate-modules:invalid-documentation
+plugins/modules/get_certificate.py validate-modules:invalid-documentation
+plugins/modules/openssh_cert.py validate-modules:invalid-documentation
+plugins/modules/openssl_csr.py validate-modules:invalid-documentation
+plugins/modules/openssl_csr_info.py validate-modules:invalid-documentation
+plugins/modules/openssl_csr_pipe.py validate-modules:invalid-documentation
+plugins/modules/openssl_privatekey_info.py validate-modules:invalid-documentation
+plugins/modules/openssl_publickey_info.py validate-modules:invalid-documentation
+plugins/modules/x509_certificate_info.py validate-modules:invalid-documentation
+plugins/modules/x509_crl.py validate-modules:invalid-documentation
+plugins/modules/x509_crl_info.py validate-modules:invalid-documentation
tests/ee/roles/smoke/library/smoke_ipaddress.py shebang
tests/ee/roles/smoke/library/smoke_pyyaml.py shebang
diff --git a/ansible_collections/community/crypto/tests/sanity/ignore-2.16.txt b/ansible_collections/community/crypto/tests/sanity/ignore-2.16.txt
index ca127b4fd..9ffe1e998 100644
--- a/ansible_collections/community/crypto/tests/sanity/ignore-2.16.txt
+++ b/ansible_collections/community/crypto/tests/sanity/ignore-2.16.txt
@@ -1,3 +1,2 @@
-.azure-pipelines/scripts/publish-codecov.py replace-urlopen
tests/ee/roles/smoke/library/smoke_ipaddress.py shebang
tests/ee/roles/smoke/library/smoke_pyyaml.py shebang
diff --git a/ansible_collections/community/crypto/tests/sanity/ignore-2.17.txt b/ansible_collections/community/crypto/tests/sanity/ignore-2.17.txt
new file mode 100644
index 000000000..9ffe1e998
--- /dev/null
+++ b/ansible_collections/community/crypto/tests/sanity/ignore-2.17.txt
@@ -0,0 +1,2 @@
+tests/ee/roles/smoke/library/smoke_ipaddress.py shebang
+tests/ee/roles/smoke/library/smoke_pyyaml.py shebang
diff --git a/ansible_collections/community/docker/tests/sanity/ignore-2.9.txt.license b/ansible_collections/community/crypto/tests/sanity/ignore-2.17.txt.license
index edff8c768..edff8c768 100644
--- a/ansible_collections/community/docker/tests/sanity/ignore-2.9.txt.license
+++ b/ansible_collections/community/crypto/tests/sanity/ignore-2.17.txt.license
diff --git a/ansible_collections/community/crypto/tests/sanity/ignore-2.9.txt b/ansible_collections/community/crypto/tests/sanity/ignore-2.9.txt
index ce2f4b667..e20c4e5f3 100644
--- a/ansible_collections/community/crypto/tests/sanity/ignore-2.9.txt
+++ b/ansible_collections/community/crypto/tests/sanity/ignore-2.9.txt
@@ -4,5 +4,20 @@
.azure-pipelines/scripts/publish-codecov.py compile-3.5!skip # Uses Python 3.6+ syntax
.azure-pipelines/scripts/publish-codecov.py future-import-boilerplate
.azure-pipelines/scripts/publish-codecov.py metaclass-boilerplate
+docs/docsite/rst/guide_selfsigned.rst rstcheck
+plugins/modules/acme_challenge_cert_helper.py validate-modules:return-syntax-error
+plugins/modules/ecs_certificate.py validate-modules:invalid-documentation
+plugins/modules/get_certificate.py validate-modules:invalid-documentation
+plugins/modules/openssh_cert.py validate-modules:invalid-documentation
+plugins/modules/openssl_csr.py validate-modules:invalid-documentation
+plugins/modules/openssl_csr_info.py validate-modules:invalid-documentation
+plugins/modules/openssl_csr_pipe.py validate-modules:invalid-documentation
+plugins/modules/openssl_privatekey_info.py validate-modules:invalid-documentation
+plugins/modules/openssl_publickey_info.py validate-modules:invalid-documentation
+plugins/modules/x509_certificate_info.py validate-modules:invalid-documentation
+plugins/modules/x509_crl.py validate-modules:invalid-documentation
+plugins/modules/x509_crl.py validate-modules:return-syntax-error
+plugins/modules/x509_crl_info.py validate-modules:invalid-documentation
+plugins/modules/x509_crl_info.py validate-modules:return-syntax-error
tests/ee/roles/smoke/library/smoke_ipaddress.py shebang
tests/ee/roles/smoke/library/smoke_pyyaml.py shebang
diff --git a/ansible_collections/community/crypto/tests/unit/plugins/module_utils/crypto/test_pem.py b/ansible_collections/community/crypto/tests/unit/plugins/module_utils/crypto/test_pem.py
new file mode 100644
index 000000000..183d81b92
--- /dev/null
+++ b/ansible_collections/community/crypto/tests/unit/plugins/module_utils/crypto/test_pem.py
@@ -0,0 +1,67 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2023, Felix Fontein <felix@fontein.de>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+import pytest
+
+from ansible_collections.community.crypto.plugins.module_utils.crypto.pem import (
+ identify_pem_format,
+ identify_private_key_format,
+ split_pem_list,
+ extract_first_pem,
+)
+
+
+PEM_TEST_CASES = [
+ (b'', [], False, 'raw'),
+ (b'random stuff\nblabla', [], False, 'raw'),
+ (b'-----BEGIN PRIVATE KEY-----', [], False, 'raw'),
+ (
+ b'-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----',
+ ['-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----'],
+ True,
+ 'pkcs8',
+ ),
+ (
+ b'foo=bar\n# random stuff\n-----BEGIN RSA PRIVATE KEY-----\nblabla\n-----END RSA PRIVATE KEY-----\nmore stuff\n',
+ ['-----BEGIN RSA PRIVATE KEY-----\nblabla\n-----END RSA PRIVATE KEY-----\n'],
+ True,
+ 'pkcs1',
+ ),
+ (
+ b'foo=bar\n# random stuff\n-----BEGIN CERTIFICATE-----\nblabla\n-----END CERTIFICATE-----\nmore stuff\n'
+ b'\n-----BEGIN CERTIFICATE-----\nfoobar\n-----END CERTIFICATE-----',
+ [
+ '-----BEGIN CERTIFICATE-----\nblabla\n-----END CERTIFICATE-----\n',
+ '-----BEGIN CERTIFICATE-----\nfoobar\n-----END CERTIFICATE-----',
+ ],
+ True,
+ 'unknown-pem',
+ ),
+ (
+ b'-----BEGINCERTIFICATE-----\n-----BEGIN CERTIFICATE-----\n-----BEGINCERTIFICATE-----\n-----END CERTIFICATE-----\n-----BEGINCERTIFICATE-----\n',
+ [
+ '-----BEGIN CERTIFICATE-----\n-----BEGINCERTIFICATE-----\n-----END CERTIFICATE-----\n',
+ ],
+ True,
+ 'unknown-pem',
+ ),
+]
+
+
+@pytest.mark.parametrize('data, pems, is_pem, private_key_type', PEM_TEST_CASES)
+def test_pem_handling(data, pems, is_pem, private_key_type):
+ assert identify_pem_format(data) == is_pem
+ assert identify_private_key_format(data) == private_key_type
+ try:
+ text = data.decode('utf-8')
+ assert split_pem_list(text) == pems
+ first_pem = pems[0] if pems else None
+ assert extract_first_pem(text) == first_pem
+ except UnicodeDecodeError:
+ pass
diff --git a/ansible_collections/community/crypto/tests/unit/plugins/modules/test_luks_device.py b/ansible_collections/community/crypto/tests/unit/plugins/modules/test_luks_device.py
index c773640c6..371001827 100644
--- a/ansible_collections/community/crypto/tests/unit/plugins/modules/test_luks_device.py
+++ b/ansible_collections/community/crypto/tests/unit/plugins/modules/test_luks_device.py
@@ -148,16 +148,16 @@ LUKS_ADD_KEY_DATA = (
# device, remove_key, remove_passphrase, state, label, expected
LUKS_REMOVE_KEY_DATA = (
- ("dummy", "key", None, "present", None, True),
- (None, "key", None, "present", None, False),
- (None, "key", None, "present", "labelName", True),
- ("dummy", None, None, "present", None, False),
- ("dummy", "key", None, "absent", None, "exception"),
- ("dummy", None, "foo", "present", None, True),
- (None, None, "foo", "present", None, False),
- (None, None, "foo", "present", "labelName", True),
- ("dummy", None, None, "present", None, False),
- ("dummy", None, "foo", "absent", None, "exception"))
+ ("dummy", "key", None, None, "present", None, True),
+ (None, "key", None, None, "present", None, False),
+ (None, "key", None, None, "present", "labelName", True),
+ ("dummy", None, None, None, "present", None, False),
+ ("dummy", "key", None, None, "absent", None, "exception"),
+ ("dummy", None, "foo", None, "present", None, True),
+ (None, None, "foo", None, "present", None, False),
+ (None, None, "foo", None, "present", "labelName", True),
+ ("dummy", None, None, None, "present", None, False),
+ ("dummy", None, "foo", None, "absent", None, "exception"))
@pytest.mark.parametrize("device, keyfile, passphrase, state, is_luks, " +
@@ -275,6 +275,7 @@ def test_luks_add_key(device, keyfile, passphrase, new_keyfile, new_passphrase,
module.params["passphrase"] = passphrase
module.params["new_keyfile"] = new_keyfile
module.params["new_passphrase"] = new_passphrase
+ module.params["new_keyslot"] = None
module.params["state"] = state
module.params["label"] = label
@@ -291,17 +292,18 @@ def test_luks_add_key(device, keyfile, passphrase, new_keyfile, new_passphrase,
assert expected == "exception"
-@pytest.mark.parametrize("device, remove_keyfile, remove_passphrase, state, " +
- "label, expected",
- ((d[0], d[1], d[2], d[3], d[4], d[5])
+@pytest.mark.parametrize("device, remove_keyfile, remove_passphrase, remove_keyslot, " +
+ "state, label, expected",
+ ((d[0], d[1], d[2], d[3], d[4], d[5], d[6])
for d in LUKS_REMOVE_KEY_DATA))
-def test_luks_remove_key(device, remove_keyfile, remove_passphrase, state,
+def test_luks_remove_key(device, remove_keyfile, remove_passphrase, remove_keyslot, state,
label, expected, monkeypatch):
module = DummyModule()
module.params["device"] = device
module.params["remove_keyfile"] = remove_keyfile
module.params["remove_passphrase"] = remove_passphrase
+ module.params["remove_keyslot"] = remove_keyslot
module.params["state"] = state
module.params["label"] = label
diff --git a/ansible_collections/community/crypto/tests/utils/shippable/shippable.sh b/ansible_collections/community/crypto/tests/utils/shippable/shippable.sh
index 526137698..2ef1d2f3b 100755
--- a/ansible_collections/community/crypto/tests/utils/shippable/shippable.sh
+++ b/ansible_collections/community/crypto/tests/utils/shippable/shippable.sh
@@ -75,17 +75,8 @@ fi
# END: HACK
-if [ "${SHIPPABLE_BUILD_ID:-}" ]; then
- export ANSIBLE_COLLECTIONS_PATHS="${HOME}/.ansible"
- SHIPPABLE_RESULT_DIR="$(pwd)/shippable"
- TEST_DIR="${ANSIBLE_COLLECTIONS_PATHS}/ansible_collections/community/crypto"
- mkdir -p "${TEST_DIR}"
- cp -aT "${SHIPPABLE_BUILD_DIR}" "${TEST_DIR}"
- cd "${TEST_DIR}"
-else
- # AZP
- export ANSIBLE_COLLECTIONS_PATHS="$PWD/../../../"
-fi
+# AZP
+export ANSIBLE_COLLECTIONS_PATHS="$PWD/../../../"
if [ "${test}" == "sanity/extra" ]; then
retry pip install junit-xml --disable-pip-version-check
diff --git a/ansible_collections/community/digitalocean/.github/workflows/ansible-test-integration.yml b/ansible_collections/community/digitalocean/.github/workflows/ansible-test-integration.yml
index d2962f216..f0729fd64 100644
--- a/ansible_collections/community/digitalocean/.github/workflows/ansible-test-integration.yml
+++ b/ansible_collections/community/digitalocean/.github/workflows/ansible-test-integration.yml
@@ -1,24 +1,32 @@
-name: integration
+name: Integration tests
on:
push:
- branches:
- - main
- schedule:
- - cron: "10 6 * * *"
+ branches: [main]
workflow_dispatch:
concurrency:
- group: cloud-integration-tests
+ group: ${{ github.workflow }}
cancel-in-progress: false
+env:
+ # NOTE: Yes, the origination is not from a PR :smile: but we do have
+ # integration tests on PR and we want the cloud resources uniquely named
+ PR_NUMBER: 0
+
jobs:
integration:
- runs-on: ubuntu-latest
- timeout-minutes: 40
+ runs-on: ubuntu-22.04
+ environment: main
+ timeout-minutes: 60
+ name: Integration (Ⓐ${{ matrix.versions.ansible }} on ${{ matrix.versions.python }} / ${{ matrix.module }})
strategy:
fail-fast: false
max-parallel: 1
matrix:
+ # https://docs.ansible.com/ansible/latest/reference_appendices/release_and_maintenance.html
+ versions:
+ - ansible: stable-2.14
+ python: "3.9"
module:
- digital_ocean_account_info
- digital_ocean_balance_info
@@ -31,7 +39,7 @@ jobs:
- digital_ocean_database_info
- digital_ocean_domain
- digital_ocean_domain_info
- - digital_ocean_domain_record
+ # - digital_ocean_domain_record # No test
- digital_ocean_domain_record_info
- digital_ocean_droplet
- digital_ocean_droplet_info
@@ -45,9 +53,10 @@ jobs:
- digital_ocean_load_balancer
- digital_ocean_load_balancer_info
- digital_ocean_monitoring_alerts
- - digital_ocean_monitoring_alerts_info
+ # - digital_ocean_monitoring_alerts_info # No test
- digital_ocean_project
- digital_ocean_project_info
+ - digital_ocean_project_resource_info
- digital_ocean_region_info
- digital_ocean_size_info
- digital_ocean_snapshot
@@ -61,7 +70,6 @@ jobs:
- digital_ocean_volume_info
- digital_ocean_vpc
- digital_ocean_vpc_info
-
steps:
- name: Perform testing
uses: ansible-community/ansible-test-gh-action@release/v1
@@ -73,8 +81,8 @@ jobs:
./tests/utils/render.sh
tests/integration/integration_config.yml.template
> tests/integration/integration_config.yml
- origin-python-version: 3.9
+ ansible-core-version: ${{ matrix.versions.ansible }}
+ origin-python-version: ${{ matrix.versions.python }}
target: ${{ matrix.module }}
- target-python-version: 3.9
+ target-python-version: ${{ matrix.versions.python }}
testing-type: integration
- test-deps: community.general
diff --git a/ansible_collections/community/digitalocean/.github/workflows/ansible-test-sanity.yml b/ansible_collections/community/digitalocean/.github/workflows/ansible-test-sanity.yml
index 95cde9006..25df12475 100644
--- a/ansible_collections/community/digitalocean/.github/workflows/ansible-test-sanity.yml
+++ b/ansible_collections/community/digitalocean/.github/workflows/ansible-test-sanity.yml
@@ -1,52 +1,29 @@
name: sanity
+
on:
- pull_request:
- types: [ opened, synchronize, reopened ]
push:
- branches: [ main ]
- schedule:
- - cron: '0 6 * * *'
+ branches: [main]
+ pull_request:
+ types: [opened, synchronize, reopened]
+ workflow_dispatch:
jobs:
-
- sanity_29:
- timeout-minutes: 30
- name: Sanity (Ⓐ$${{ matrix.ansible }})
- strategy:
- matrix:
- ansible:
- - stable-2.9
- runs-on: ubuntu-latest
- steps:
- - name: Perform testing
- uses: ansible-community/ansible-test-gh-action@release/v1
- with:
- ansible-core-version: ${{ matrix.ansible }}
- # pre-test-cmd:
- python-version: 3.8
- target-python-version: 3.8
- testing-type: sanity
- # test-deps:
-
sanity:
timeout-minutes: 30
name: Sanity (Ⓐ$${{ matrix.ansible }})
strategy:
+ fail-fast: false
matrix:
ansible:
- - stable-2.10
- - stable-2.11
- - stable-2.12
- - stable-2.13
- - devel
- runs-on: ubuntu-latest
+ - stable-2.12
+ - stable-2.13
+ - stable-2.14
+ runs-on: ubuntu-22.04
steps:
- name: Perform testing
uses: ansible-community/ansible-test-gh-action@release/v1
with:
ansible-core-version: ${{ matrix.ansible }}
- # pre-test-cmd:
- python-version: 3.9
+ origin-python-version: 3.9
target-python-version: 3.9
testing-type: sanity
- # test-deps:
diff --git a/ansible_collections/community/digitalocean/.github/workflows/ansible-test-unit.yml b/ansible_collections/community/digitalocean/.github/workflows/ansible-test-unit.yml
index 4b3615c1d..7639c7f0f 100644
--- a/ansible_collections/community/digitalocean/.github/workflows/ansible-test-unit.yml
+++ b/ansible_collections/community/digitalocean/.github/workflows/ansible-test-unit.yml
@@ -1,57 +1,29 @@
name: unit
on:
- pull_request:
- types: [ opened, synchronize, reopened ]
push:
- branches: [ main ]
- schedule:
- - cron: '10 6 * * *'
+ branches: [main]
+ pull_request:
+ types: [opened, synchronize, reopened]
+ workflow_dispatch:
jobs:
-
- units_29:
- runs-on: ubuntu-latest
- timeout-minutes: 30
- name: Units (Ⓐ${{ matrix.ansible }})
- strategy:
- fail-fast: true
- matrix:
- ansible:
- - stable-2.9
- steps:
- - name: Perform testing
- uses: ansible-community/ansible-test-gh-action@release/v1
- with:
- ansible-core-version: ${{ matrix.ansible }}
- # pre-test-cmd:
- python-version: 3.8
- target-python-version: 3.8
- testing-type: units
- test-deps: >-
- ansible.netcommon
- ansible.utils
- community.general
-
units:
- runs-on: ubuntu-latest
+ runs-on: ubuntu-22.04
timeout-minutes: 30
name: Units (Ⓐ${{ matrix.ansible }})
strategy:
- fail-fast: true
+ fail-fast: false
matrix:
ansible:
- - stable-2.10
- - stable-2.11
- stable-2.12
- stable-2.13
- - devel
+ - stable-2.14
steps:
- name: Perform testing
uses: ansible-community/ansible-test-gh-action@release/v1
with:
ansible-core-version: ${{ matrix.ansible }}
- # pre-test-cmd:
- python-version: 3.9
+ origin-python-version: 3.9
target-python-version: 3.9
testing-type: units
test-deps: >-
diff --git a/ansible_collections/community/digitalocean/.github/workflows/black.yml b/ansible_collections/community/digitalocean/.github/workflows/black.yml
index ce6685b0a..a38fe9c1a 100644
--- a/ansible_collections/community/digitalocean/.github/workflows/black.yml
+++ b/ansible_collections/community/digitalocean/.github/workflows/black.yml
@@ -2,15 +2,16 @@
name: black
on:
- pull_request:
- types: [ opened, synchronize, reopened ]
push:
- branches: [ main ]
+ branches: [main]
+ pull_request:
+ types: [opened, synchronize, reopened]
+ workflow_dispatch:
jobs:
lint:
- runs-on: ubuntu-latest
+ runs-on: ubuntu-22.04
timeout-minutes: 15
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- uses: psf/black@stable
diff --git a/ansible_collections/community/digitalocean/.github/workflows/pull-request-integration.yml b/ansible_collections/community/digitalocean/.github/workflows/pull-request-integration.yml
index b70f30e3c..9558d67b4 100644
--- a/ansible_collections/community/digitalocean/.github/workflows/pull-request-integration.yml
+++ b/ansible_collections/community/digitalocean/.github/workflows/pull-request-integration.yml
@@ -1,114 +1,97 @@
-name: pull-request-integration
+name: Pull request integration tests
on:
pull_request_target:
- branches: [main]
- types: [opened, synchronize, reopened]
+ branches:
+ - main
paths:
- - plugins/module_utils/**
- - plugins/modules/**
+ - poetry.lock
+ - pyproject.toml
+ - 'plugins/module_utils/**'
+ - 'plugins/modules/**'
+ - 'tests/integration/**'
concurrency:
- group: cloud-integration-tests
- cancel-in-progress: false
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
+ cancel-in-progress: true
env:
- DEFAULT_BRANCH: remotes/origin/main
+ PR_NUMBER: ${{ github.event.pull_request.number }}
jobs:
- changes:
- # Require reviewers for this environment
- # https://securitylab.github.com/research/github-actions-preventing-pwn-requests/
+ human-review-and-approval:
+ runs-on: ubuntu-22.04
+ # MUST keep this environment set if using pull_request_target
environment: integration
- runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
- with:
- fetch-depth: 0
- ref: ${{ github.head_ref }}
-
- - name: show changes files
- run: |
- git diff --name-only $DEFAULT_BRANCH
-
- - name: get changed module_utils
- id: changed-module-utils
- run: |
- basenames=()
- for file in $(git diff --name-only $DEFAULT_BRANCH | grep 'plugins/module_utils/'); do
- basenames+=($(basename $file .py))
- done
- printf '::set-output name=matrix::%s\n' $(printf '%s\n' "${basenames[@]}" | jq -R . | jq -sc .)
+ - name: Wait for approval
+ run: sleep 10
- - name: get changed modules
- id: changed-modules
- run: |
- basenames=()
- for file in $(git diff --name-only $DEFAULT_BRANCH | grep 'plugins/modules/'); do
- basenames+=($(basename $file .py))
- done
- printf '::set-output name=matrix::%s\n' $(printf '%s\n' "${basenames[@]}" | jq -R . | jq -sc .)
-
- outputs:
- module-utils-matrix: ${{ steps.changed-module-utils.outputs.matrix }}
- module-matrix: ${{ steps.changed-modules.outputs.matrix }}
-
- test-module-utils:
- environment: integration
- runs-on: ubuntu-latest
- timeout-minutes: 120
- needs: [changes]
- if: ${{ needs.changes.outputs.module-utils-matrix != '[""]' }}
+ test-integration:
+ needs: human-review-and-approval
+ runs-on: ubuntu-22.04
+ # NOTE using the 'needs' as a gate ... the 'integration' environment has
+ # required reviewers (which is a good idea since we're using pull_request_target)
+ timeout-minutes: 90
strategy:
fail-fast: false
+ # NOTE we're hitting 429s (too many requests)
max-parallel: 1
matrix:
+ versions:
+ - ansible: stable-2.14
+ python: "3.9"
module:
- - digital_ocean_account_info
- - digital_ocean_balance_info
- - digital_ocean_block_storage
- - digital_ocean_cdn_endpoints
- - digital_ocean_cdn_endpoints_info
- - digital_ocean_certificate
- - digital_ocean_certificate_info
- - digital_ocean_database
- - digital_ocean_database_info
- - digital_ocean_domain
- - digital_ocean_domain_info
- - digital_ocean_domain_record
- - digital_ocean_domain_record_info
- - digital_ocean_droplet
- - digital_ocean_droplet_info
- - digital_ocean_firewall
- - digital_ocean_firewall_info
- - digital_ocean_floating_ip
- - digital_ocean_floating_ip_info
- - digital_ocean_image_info
- - digital_ocean_kubernetes
- - digital_ocean_kubernetes_info
- - digital_ocean_load_balancer
- - digital_ocean_load_balancer_info
- - digital_ocean_monitoring_alerts
- - digital_ocean_monitoring_alerts_info
- - digital_ocean_project
- - digital_ocean_project_info
- - digital_ocean_region_info
- - digital_ocean_size_info
- - digital_ocean_snapshot
- - digital_ocean_snapshot_info
- - digital_ocean_spaces
- - digital_ocean_spaces_info
- - digital_ocean_sshkey
- - digital_ocean_sshkey_info
- - digital_ocean_tag
- - digital_ocean_tag_info
- - digital_ocean_volume_info
- - digital_ocean_vpc
- - digital_ocean_vpc_info
+ - digital_ocean_account_info
+ - digital_ocean_balance_info
+ - digital_ocean_block_storage
+ - digital_ocean_cdn_endpoints
+ - digital_ocean_cdn_endpoints_info
+ - digital_ocean_certificate
+ - digital_ocean_certificate_info
+ - digital_ocean_database
+ - digital_ocean_database_info
+ - digital_ocean_domain
+ - digital_ocean_domain_info
+ # - digital_ocean_domain_record # No test
+ - digital_ocean_domain_record_info
+ - digital_ocean_droplet
+ - digital_ocean_droplet_info
+ - digital_ocean_firewall
+ - digital_ocean_firewall_info
+ - digital_ocean_floating_ip
+ - digital_ocean_floating_ip_info
+ - digital_ocean_image_info
+ - digital_ocean_kubernetes
+ - digital_ocean_kubernetes_info
+ - digital_ocean_load_balancer
+ - digital_ocean_load_balancer_info
+ - digital_ocean_monitoring_alerts
+ # - digital_ocean_monitoring_alerts_info # No test
+ - digital_ocean_project
+ - digital_ocean_project_info
+ - digital_ocean_project_resource_info
+ - digital_ocean_region_info
+ - digital_ocean_size_info
+ - digital_ocean_snapshot
+ - digital_ocean_snapshot_info
+ - digital_ocean_spaces
+ - digital_ocean_spaces_info
+ - digital_ocean_sshkey
+ - digital_ocean_sshkey_info
+ - digital_ocean_tag
+ - digital_ocean_tag_info
+ - digital_ocean_volume_info
+ - digital_ocean_vpc
+ - digital_ocean_vpc_info
steps:
- - name: Perform testing (all modules)
+ - name: Perform integration testing
uses: ansible-community/ansible-test-gh-action@release/v1
with:
+ # MUST set 'git-checkout-ref' if using pull_request_target
+ # MUST use an Environment if using pull_request_target
+ # 'github.event.pull_request.head.sha' checks out the
+ # PR source repo's code, which should be considered untrusted
git-checkout-ref: ${{ github.event.pull_request.head.sha }}
pre-test-cmd: >-
DO_API_KEY=${{ secrets.DO_API_KEY }}
@@ -117,36 +100,8 @@ jobs:
./tests/utils/render.sh
tests/integration/integration_config.yml.template
> tests/integration/integration_config.yml
- origin-python-version: 3.9
- target-python-version: 3.9
- testing-type: integration
- test-deps: community.general
+ ansible-core-version: ${{ matrix.versions.ansible }}
+ origin-python-version: ${{ matrix.versions.python }}
target: ${{ matrix.module }}
-
- test-modules:
- environment: integration
- runs-on: ubuntu-latest
- timeout-minutes: 40
- needs: [changes]
- if: ${{ needs.changes.outputs.module-utils-matrix == '[""]' && needs.changes.outputs.module-matrix != '[""]' }}
- strategy:
- fail-fast: false
- matrix:
- module: ${{ fromJSON(needs.changes.outputs.module-matrix) }}
- steps:
- - name: Perform testing (changed module)
- uses: ansible-community/ansible-test-gh-action@release/v1
- with:
- git-checkout-ref: ${{ github.event.pull_request.head.sha }}
- pre-test-cmd: >-
- DO_API_KEY=${{ secrets.DO_API_KEY }}
- AWS_ACCESS_KEY_ID=${{ secrets.AWS_ACCESS_KEY_ID }}
- AWS_SECRET_ACCESS_KEY=${{ secrets.AWS_SECRET_ACCESS_KEY }}
- ./tests/utils/render.sh
- tests/integration/integration_config.yml.template
- > tests/integration/integration_config.yml
- origin-python-version: 3.9
- target-python-version: 3.9
+ target-python-version: ${{ matrix.versions.python }}
testing-type: integration
- test-deps: community.general
- target: ${{ matrix.module }}
diff --git a/ansible_collections/community/digitalocean/.gitignore b/ansible_collections/community/digitalocean/.gitignore
index 76f823201..3d1696616 100644
--- a/ansible_collections/community/digitalocean/.gitignore
+++ b/ansible_collections/community/digitalocean/.gitignore
@@ -120,6 +120,9 @@ venv.bak/
# Rope project settings
.ropeproject
+# Intellij idea project settings
+.idea
+
# mkdocs documentation
/site
diff --git a/ansible_collections/community/digitalocean/.tool-versions b/ansible_collections/community/digitalocean/.tool-versions
new file mode 100644
index 000000000..f061d0ebd
--- /dev/null
+++ b/ansible_collections/community/digitalocean/.tool-versions
@@ -0,0 +1 @@
+python 3.9.16
diff --git a/ansible_collections/community/digitalocean/CHANGELOG.rst b/ansible_collections/community/digitalocean/CHANGELOG.rst
index 3f7009fc6..e3e543e73 100644
--- a/ansible_collections/community/digitalocean/CHANGELOG.rst
+++ b/ansible_collections/community/digitalocean/CHANGELOG.rst
@@ -5,6 +5,57 @@ Community DigitalOcean Release Notes
.. contents:: Topics
+v1.26.0
+=======
+
+Minor Changes
+-------------
+
+- digital_ocean_kubernetes - add project_name parameter (https://github.com/ansible-collections/community.digitalocean/issues/264).
+
+Bugfixes
+--------
+
+- The C(project_name) parameter for many modules was used by alias C(project) internally in the codebase, but to work properly C(project_name) must be used in the code. Replace self.module.params.get("project") with self.module.params.get("project_name") (https://github.com/ansible-collections/community.digitalocean/issues/326).
+- digital_ocean_kubernetes - module didn't return kubeconfig properly, return documentation was invalid. Fixed version returns data with the same structure all the time, also it is aligned with M(community.digitalocean.digital_ocean_kubernetes_info) documentation return data now. (https://github.com/ansible-collections/community.digitalocean/issues/322).
+
+v1.25.0
+=======
+
+Minor Changes
+-------------
+
+- fix sanity tests (https://github.com/ansible-collections/community.digitalocean/issues/323).
+
+Bugfixes
+--------
+
+- inventory plugin - restore reading auth token from env variables (https://github.com/ansible-collections/community.digitalocean/pull/315).
+
+New Modules
+-----------
+
+- digital_ocean_project_resource_info - Gather information about DigitalOcean Project Resources
+
+v1.24.0
+=======
+
+Minor Changes
+-------------
+
+- documentation - use C(true) and C(false) for boolean values in documentation and examples (https://github.com/ansible-collections/community.digitalocean/issues/303).
+- inventory plugin - drop C(api_token) in favor of C(oauth_token) for consistency (https://github.com/ansible-collections/community.digitalocean/issues/300).
+- tests - add C(sanity), C(units), and C(psf/black) back on merge into C(main) (https://github.com/ansible-collections/community.digitalocean/pull/311).
+- tests - drop Ansible 2.9 and Ansible Core 2.10 and 2.11 (https://github.com/ansible-collections/community.digitalocean/pull/310).
+- tests - remove the daily runs (https://github.com/ansible-collections/community.digitalocean/pull/310).
+- tests - run C(psf/black) across all files (https://github.com/ansible-collections/community.digitalocean/pull/310).
+- tests - test against Ansible Core 2.12, 2.13, and 2.14 (https://github.com/ansible-collections/community.digitalocean/pull/310).
+
+Bugfixes
+--------
+
+- digital_ocean_domain - fix ``all_domains`` by using ``get_paginated_data`` to retrieve all of the domains in the account from the paginated domains api endpoint (https://github.com/ansible-collections/community.digitalocean/pull/307).
+
v1.23.0
=======
@@ -19,8 +70,8 @@ Minor Changes
Bugfixes
--------
-- inventory plugin - bugfix for baseurl parameter (https://github.com/ansible-collections/community.digitalocean/pull/297).
- integration tests - add missing `environment` directive on pull request integration testing (https://github.com/ansible-collections/community.digitalocean/issues/293).
+- inventory plugin - bugfix for baseurl parameter (https://github.com/ansible-collections/community.digitalocean/pull/297).
v1.22.0
=======
diff --git a/ansible_collections/community/digitalocean/CODEOWNERS b/ansible_collections/community/digitalocean/CODEOWNERS
new file mode 100644
index 000000000..e51dbfcaf
--- /dev/null
+++ b/ansible_collections/community/digitalocean/CODEOWNERS
@@ -0,0 +1 @@
+* @Akasurde @bmildren @danxg87 @geerlingguy @mamercad @mpontillo @tparker00
diff --git a/ansible_collections/community/digitalocean/FILES.json b/ansible_collections/community/digitalocean/FILES.json
index 00d671b00..ffcdb1215 100644
--- a/ansible_collections/community/digitalocean/FILES.json
+++ b/ansible_collections/community/digitalocean/FILES.json
@@ -25,35 +25,35 @@
"name": ".github/workflows/ansible-test-integration.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a67c8b8bd855984828a5dff70eeede2fb375ce727c4b762eb058f5afa74cbb78",
+ "chksum_sha256": "6df224ceacdef5f62b798ea5ac4e65df22118d26925d4fb520761f3a25f1c8f1",
"format": 1
},
{
"name": ".github/workflows/ansible-test-sanity.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d389347280fa81421b17f97ad4b1d9bad54e223e54b81ab875bbbb52590add35",
+ "chksum_sha256": "5b634c89a66776e092fb10c17ba0c3fdb7c85c2298e04b1bf72aa5d7684ce739",
"format": 1
},
{
"name": ".github/workflows/ansible-test-unit.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0284cac0a096014cd45aca0a6cd9a8a48d378017e88b56b3f818b2320d419a70",
+ "chksum_sha256": "16ce2290f2c953d36411c0659edd1a6085f4416b9e14b0baee4f7f52754df5f3",
"format": 1
},
{
"name": ".github/workflows/black.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "561aecfa4d554c62e1a4a054807e70b8a5fdff72cfb36dfe9327379959068545",
+ "chksum_sha256": "4275a97b69cfbb7221e3938265cd4a403ead0a27f2319a5dde495066694e7bff",
"format": 1
},
{
"name": ".github/workflows/pull-request-integration.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "798a09115f8346b3bb044a5952f856b7f7e604fc6876ef2d62fba809f6aa0def",
+ "chksum_sha256": "d1b502ba3005e66e63ebc42048e5e5ea62b1bbefce6100145435242d39fbcff6",
"format": 1
},
{
@@ -88,7 +88,7 @@
"name": "changelogs/changelog.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bbdbadc2141b0d3aef5586c1e954d5ad3275c55477c78718c7bd8991379c4f69",
+ "chksum_sha256": "f9f589dfd4755389b1e134011d970c0cca0b9ca2be5368c364f89216d665e124",
"format": 1
},
{
@@ -130,7 +130,7 @@
"name": "plugins/doc_fragments/digital_ocean.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d46c48309bd83fb6d9517fe348b0f79abed2c9936a745c8b93500bbb50ad1ab5",
+ "chksum_sha256": "07b61276aa8a4a4bc658c41e5f2550b7a68763918a68cdff3f498b679660c0fa",
"format": 1
},
{
@@ -144,7 +144,7 @@
"name": "plugins/inventory/digitalocean.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b52a388bd444cb45d380369faf380aa9c5f9459d8db6aac3e2f1642539363a27",
+ "chksum_sha256": "846df865ad051426cc92892218a834075cac0f394ec9b479ed28596e2ecd8f2a",
"format": 1
},
{
@@ -158,7 +158,7 @@
"name": "plugins/module_utils/digital_ocean.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f1185211388225f955a5790fa43b7f6d58e81309a279f64bfa70ce78c68fed4d",
+ "chksum_sha256": "54fb1888c238f4ef4d3a5ea075bf4ca1d7260c69d7750920d0d6cfe60e3f8ff2",
"format": 1
},
{
@@ -263,7 +263,7 @@
"name": "plugins/modules/digital_ocean.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4321ebab46ec5f699aabe4b29e713d79b923bb8a4fcd7c9397408f9f81b4dbdc",
+ "chksum_sha256": "0aa97beb97a7aa6fcee96c7219075e5ffb8476c16af071402ab0b980ef5ee73f",
"format": 1
},
{
@@ -284,21 +284,21 @@
"name": "plugins/modules/digital_ocean_block_storage.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "47750f27efd168f758b5fd454471aa0d0e0dac284f23982c6f0626b4f40f81a2",
+ "chksum_sha256": "25b001d563ba7ee867ca7748a7e34ad2f2a728cefcc95895807585596004c4b7",
"format": 1
},
{
"name": "plugins/modules/digital_ocean_cdn_endpoints.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6dba98b5eca51961dbb7ed850f89735b46f17d06e56059134bde982fc43c3d84",
+ "chksum_sha256": "8d4fc0d25252047059cd6f95d980916a3da6e2bbb0e1ecc7c9e92a5750e993a9",
"format": 1
},
{
"name": "plugins/modules/digital_ocean_cdn_endpoints_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "598f08b64245ad33eb6879e93d61e7b33536742dc86efc21f6487125381fcd4d",
+ "chksum_sha256": "1f88e72ae7cf9fc19f1ae3beb2e17df38afe891ce6f034131452d2ad3edf37fe",
"format": 1
},
{
@@ -319,21 +319,21 @@
"name": "plugins/modules/digital_ocean_database.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "72c503eb70525affe7662637419f2e0594546e2a9c3041cdf99421e59ceaa3e8",
+ "chksum_sha256": "2684b006bb5163c586a0753d9a0cef41db024885adc0d62cd9cedd8403a949c1",
"format": 1
},
{
"name": "plugins/modules/digital_ocean_database_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c6a9f1fb48b0f93d84a5bf0868a23ea88fd34d423a8a4825e2ade8621e96a6d7",
+ "chksum_sha256": "b3f56effe233932512a7fff1fc3b208d2cfcf283ee28ec73fd8c7409c099e2a5",
"format": 1
},
{
"name": "plugins/modules/digital_ocean_domain.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e54c54dabab4d90b9e3dfe2fd9320944b8965b19f619270e4deb3c05a9a130cd",
+ "chksum_sha256": "12d91b47eb876546cfa5c6b071a8376f56c7bb9acbd961b2926a37cf9d93522d",
"format": 1
},
{
@@ -347,35 +347,35 @@
"name": "plugins/modules/digital_ocean_domain_record.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "296147c5b23385199f2e9955f884f2ffd7568f600737a2f575536e9824e6bf9b",
+ "chksum_sha256": "33787ba6696ca405328028159abd92ed5004752fd5b0517e8304406bf39b5e28",
"format": 1
},
{
"name": "plugins/modules/digital_ocean_domain_record_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fab0194b7a74c527438e89c8fa7801dbb9532a32f5d815d529eb9be2fb965162",
+ "chksum_sha256": "fb99fe473b0daf171f34ee610209129ec3efc30f1f9a20a7544932cf89d77c11",
"format": 1
},
{
"name": "plugins/modules/digital_ocean_droplet.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a12ddb9dd84857a50562ec74633dd698cdc834d5b134db1edbf9efaebb55b830",
+ "chksum_sha256": "6a4989a5f8dad33b56d23168b56328d356047085ed0f07a38cc6786d2f0e4b05",
"format": 1
},
{
"name": "plugins/modules/digital_ocean_droplet_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "428938d5080a9fda0e69737a94c6aeaf132aa5c67d380252e4cbfba7a50243b6",
+ "chksum_sha256": "ed1fdb9153f04852c74883c80af0285993f4957a7ef59840262c86fb413aefdc",
"format": 1
},
{
"name": "plugins/modules/digital_ocean_firewall.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3019358bce84b27244f75e6d0fc70186c8f3bec143a06f996320edf7155fb3b1",
+ "chksum_sha256": "f43851b89486652c089f3350cfc05eb546c4497276bbddddd39b1efd93a23800",
"format": 1
},
{
@@ -389,7 +389,7 @@
"name": "plugins/modules/digital_ocean_floating_ip.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b3fbbad1f805bbe44ea062c2f7751efa0e27696ebaf66d31c04f437ffb0e12d9",
+ "chksum_sha256": "17d21871c49d2f852994d1d52c9b3d5c12c328cacd1cbfd068be81989797e919",
"format": 1
},
{
@@ -410,21 +410,21 @@
"name": "plugins/modules/digital_ocean_kubernetes.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8288f64dcbc7fbdf3da017fe32cafb9c8068f8dca53538fca7882377695a3a78",
+ "chksum_sha256": "2c2c43ed3a093562d39383058d5ed96f753bd5a2d78c930ef31c9460bc0e223d",
"format": 1
},
{
"name": "plugins/modules/digital_ocean_kubernetes_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "967ae0016638341fccc56dd1145cbf868dc41a37e02ce214b16d3fede5be56a4",
+ "chksum_sha256": "2630e3ada64a58b00b274d0512b8f058d655e03e6bfa7823a9388a5452778c72",
"format": 1
},
{
"name": "plugins/modules/digital_ocean_load_balancer.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "75abb34818ff0265136d898f205a7b02195e529d93232ac898d9a8fc49824ea1",
+ "chksum_sha256": "9d472b8af28bfdbe0fc811d4f089a0b675c8ec4caa8c0eb0bb17d5cf5dcdc4bf",
"format": 1
},
{
@@ -438,28 +438,35 @@
"name": "plugins/modules/digital_ocean_monitoring_alerts.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "66a2d2ade7c6c6d58f5add506d5deb16b41d4e718315a16c0d48d67032e28af8",
+ "chksum_sha256": "9a468d41c867b84abf83101efe837514f38eb6faac138d1c1cc7b45dd6622abe",
"format": 1
},
{
"name": "plugins/modules/digital_ocean_monitoring_alerts_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e291415d6d626258458ea42a32b533e51c5f4dd1f56c18ec20c4e77cebd20689",
+ "chksum_sha256": "b6aff7f563284f833062e946e702032eba20a99a6c9192fca1da08bc14df3aa0",
"format": 1
},
{
"name": "plugins/modules/digital_ocean_project.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fa446935175c0b6d7ac4e97a9ed865302d73f89561432a6eca92859e0595cd15",
+ "chksum_sha256": "ba4be53fda91e2489f5f7552f6415b2acfb920cd45bfed7e5fadf84dee0601f9",
"format": 1
},
{
"name": "plugins/modules/digital_ocean_project_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "80d2c5131ea4250e4700a0e991f270e08cc314f3e9d5ce1d3d6abbc5b035c7b3",
+ "chksum_sha256": "b79e58a4b69e7bb07de6f5da32c63d85f365963bd34697d84c23e94527a454bd",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/digital_ocean_project_resource_info.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "a330ffe1a1866e1a7a7b33f023f92c2997ee7d1eeab1f21f1e5bd01d5d6c0368",
"format": 1
},
{
@@ -480,7 +487,7 @@
"name": "plugins/modules/digital_ocean_snapshot.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c0d3daa6dbd393e3cf1b5fad59ee5c212de50a572c98af9ccd7a7305a609f0be",
+ "chksum_sha256": "7b9ee5b4f5e767d54fa48422709b30214e773358998205c7daceed9a7242241e",
"format": 1
},
{
@@ -494,21 +501,21 @@
"name": "plugins/modules/digital_ocean_spaces.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8d2460847d8b52a31298f356b156f8498fa438e6e2046168486966b4d82e4cd6",
+ "chksum_sha256": "41114bdd31331deee1c3b45b01af97f5fc981403f642e403403f70643f64d4e3",
"format": 1
},
{
"name": "plugins/modules/digital_ocean_spaces_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e7b72a7b0aff56fdde7852f985b9357d1ca0bf1b96c3fa377f18016d9f286c00",
+ "chksum_sha256": "1f46e24af3f09613f9472da4ea3f076cb561e40704107440202be4a202c29df5",
"format": 1
},
{
"name": "plugins/modules/digital_ocean_sshkey.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9e2c3485ffac260810929615b2f31ff9aff1a694963dda371ffd90a2a150ac47",
+ "chksum_sha256": "ef5260099b650e0d5dfaa0ecbdfcc3de22856058a2f091f6771555131ff569ed",
"format": 1
},
{
@@ -543,14 +550,14 @@
"name": "plugins/modules/digital_ocean_vpc.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3770b51fa942f01f83ec76515fb970e0c18e3f6e470f02bdfc3eb710bf0f198e",
+ "chksum_sha256": "b56a078ccd489364fa8d3aa4dc9acac0a204493ee7952fe93a0b52ca4afc8d23",
"format": 1
},
{
"name": "plugins/modules/digital_ocean_vpc_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f413316213e0f87be397786e3dd9ec0c3e10a918ae728606eaba0cc2d6027a6e",
+ "chksum_sha256": "606b5fbe590ffdfb940998b58cc4b79716882021649bd55c09782f3314f157b4",
"format": 1
},
{
@@ -578,7 +585,7 @@
"name": "scripts/inventory/digital_ocean.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c2e479be0c22ec57b873b2503b930a2b0d2198e34a6b812689f1bcf59dc5e7b5",
+ "chksum_sha256": "81c41feb6fe4929433389bd9d77e34e0cb809a4b1f0ab923f7e0aba48a15087b",
"format": 1
},
{
@@ -690,7 +697,7 @@
"name": "tests/integration/targets/digital_ocean_block_storage/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e49ef1125342347a96e74f0657a6209c696aa26b06348ab7b3394b3d85098a0e",
+ "chksum_sha256": "702f01998502c02c98902c420b2a555781f912db2ebec0af23a39e04b0583d9f",
"format": 1
},
{
@@ -753,7 +760,7 @@
"name": "tests/integration/targets/digital_ocean_cdn_endpoints/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ "chksum_sha256": "b5ea375becd3088862c16fc97fe379532c583079829fcf1fdcb549e6808262fb",
"format": 1
},
{
@@ -1089,7 +1096,7 @@
"name": "tests/integration/targets/digital_ocean_domain_record_info/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ "chksum_sha256": "b5ea375becd3088862c16fc97fe379532c583079829fcf1fdcb549e6808262fb",
"format": 1
},
{
@@ -1110,7 +1117,7 @@
"name": "tests/integration/targets/digital_ocean_droplet/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b03756c08514bcfd0372763442625c178e630147a4a6a2e43d2c0aae4db499cf",
+ "chksum_sha256": "2012eb4f18d7836aa087c9238c5d8a9824c8e07aae281bdfa78585e6d3936167",
"format": 1
},
{
@@ -1124,7 +1131,7 @@
"name": "tests/integration/targets/digital_ocean_droplet/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e77539ee7523840b7eba12bdd43ae17be38f57b3adf57a17f8208b2108c8fd5a",
+ "chksum_sha256": "90d9c868abb55b8c48bbf865893ff5ab92204cc6a3d9bc9b7c2ece5d726bda30",
"format": 1
},
{
@@ -1278,7 +1285,7 @@
"name": "tests/integration/targets/digital_ocean_floating_ip/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c1dd07d9bf81cb7c5c370f4e62a241084ec1040ce01044ec72118e557953a266",
+ "chksum_sha256": "81aa1c31e180c53bed726e7b4cc8646a398fecc60a764450e9ece64ff9747e56",
"format": 1
},
{
@@ -1404,7 +1411,7 @@
"name": "tests/integration/targets/digital_ocean_kubernetes/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cf1d0849c5cdf4052d15c85b8788a6e22bef9a9518669819dd4cba0667aa6816",
+ "chksum_sha256": "19f82309887192afd04a9da9bd665b1c42fed475b6ef98fadf34ee708924e1f0",
"format": 1
},
{
@@ -1418,7 +1425,7 @@
"name": "tests/integration/targets/digital_ocean_kubernetes/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f90019f9e34bee677ec10cae36f7be0e2a70f75fdff49224ad704f2aac3cbafe",
+ "chksum_sha256": "48416ba988a569a63d43b3334efb5e18f0a7b66449796894c642aa7d20fa5115",
"format": 1
},
{
@@ -1446,7 +1453,7 @@
"name": "tests/integration/targets/digital_ocean_kubernetes_info/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5e92416aeca8878d799bc64c4d0b4f78d244ef9b6f0a0ed31a16d154490f47f7",
+ "chksum_sha256": "e0d3de73b5a3e32f84e2012d54445f90b981c7a8eddd1a8e301f67de2809c898",
"format": 1
},
{
@@ -1460,7 +1467,7 @@
"name": "tests/integration/targets/digital_ocean_kubernetes_info/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "18d5cfc3d9ecd699870b2748f5f3f9184ba3555a4e3fe4233d4899e1db47a254",
+ "chksum_sha256": "a5fdabd6c1e26c7e8fc147239ba4462c4348c2a3b7a2d20bddd54817dfbc25ab",
"format": 1
},
{
@@ -1488,7 +1495,7 @@
"name": "tests/integration/targets/digital_ocean_load_balancer/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "48c408854bad4e9d44ac5241ab75d42719d718f188530bd6b1f5c3a88e99b4fb",
+ "chksum_sha256": "d8f590cc68e3142294e29a740092d1b36530c3a1403562f027d82e739a7b3147",
"format": 1
},
{
@@ -1572,7 +1579,7 @@
"name": "tests/integration/targets/digital_ocean_monitoring_alerts/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4ccf1c2e066d3c59914cc39c49c1db694da5713db419b24e5dbc4f82bd5c9fd8",
+ "chksum_sha256": "370136ea61485bbd254c444c7e6576dc573eaf7470ef19e3c821e542e0ae91e4",
"format": 1
},
{
@@ -1593,7 +1600,7 @@
"name": "tests/integration/targets/digital_ocean_monitoring_alerts/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ "chksum_sha256": "b5ea375becd3088862c16fc97fe379532c583079829fcf1fdcb549e6808262fb",
"format": 1
},
{
@@ -1681,6 +1688,48 @@
"format": 1
},
{
+ "name": "tests/integration/targets/digital_ocean_project_resource_info",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/digital_ocean_project_resource_info/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/digital_ocean_project_resource_info/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f77a27423291484a3a130c7c349f032a8ca855cbdd6b4245f866d3b85ee77cd3",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/digital_ocean_project_resource_info/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/digital_ocean_project_resource_info/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "11b779159d8435099681c44ca3638c85f5a4eedc059129baa3a4baf68dbb1912",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/digital_ocean_project_resource_info/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "b5ea375becd3088862c16fc97fe379532c583079829fcf1fdcb549e6808262fb",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/digital_ocean_region_info",
"ftype": "dir",
"chksum_type": null,
@@ -1782,7 +1831,7 @@
"name": "tests/integration/targets/digital_ocean_snapshot/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "44603460d09ae29c96ecbfac932b961f8183ce677dec478b2ff89843acbd29ff",
+ "chksum_sha256": "ea867891ffd7db1b9315521b5d6123a0174fdddb1f5d748b92b082b23e203232",
"format": 1
},
{
@@ -2230,7 +2279,7 @@
"name": "tests/integration/integration_config.yml.template",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "88f1bcc8df7d52e95b740e8ebf99105c027d6172df212cf2cf999906863f9d61",
+ "chksum_sha256": "a25aa1f1972b2bbd5295248fcd14a3009d71b9621c77199f30e4cd416f7ce3c8",
"format": 1
},
{
@@ -2293,7 +2342,7 @@
"name": "tests/unit/plugins/inventory/test_digitalocean.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "eabb2b93dc2a351d1c811c27c9c1909065f2a1087ab3e485f50fcde81fe2ee1e",
+ "chksum_sha256": "7a4cefa39de8b8979203b91efbcac56882b3814d126fe2b0bc2d4480720459b9",
"format": 1
},
{
@@ -2307,7 +2356,7 @@
"name": "tests/unit/plugins/modules/test_digital_ocean_kubernetes.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ca626d4d4b019b0b1c746c9cbcd374b705abdd6ab48ded438603e557d08ee573",
+ "chksum_sha256": "f343444826c0ede9ffb75a4ce8b49cd6c44e802f2c49d4f654ba650dde234785",
"format": 1
},
{
@@ -2335,14 +2384,28 @@
"name": ".gitignore",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f59a2bf97befc68fb5a72a0aae195a9a95e1633d28fb595fec3a559ec04761ca",
+ "chksum_sha256": "9810801ddd3fc111f18af0ac2d7541cad5cd8ca277e8621108141b159af1d283",
+ "format": 1
+ },
+ {
+ "name": ".tool-versions",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c439ea32753e78ca7df224e7add99fd60695f440982c69e7fc6bc67769716575",
"format": 1
},
{
"name": "CHANGELOG.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "790f9e88958fdd42bc276769f78e6cd0c147800734dcf156c8132ea57e758338",
+ "chksum_sha256": "1e0ecb46bede4c3eab979545e94099c62b1a8571a8e608078e7b710cb9ddf3a0",
+ "format": 1
+ },
+ {
+ "name": "CODEOWNERS",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "11a344ed9e833025d7441fd9caf1c1aad17a5a6097a2c06140611030e4af9664",
"format": 1
},
{
@@ -2356,7 +2419,7 @@
"name": "README.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cf4814eaf041b96803d02aae15adc445979c51e802a3e658f1be5132fae2e38f",
+ "chksum_sha256": "f3ea88f47acc4e45c52db2d918e0cf2ca56ca0033bb1c8ab69c1475afad14b9e",
"format": 1
},
{
@@ -2365,6 +2428,20 @@
"chksum_type": "sha256",
"chksum_sha256": "08263e731c1a39f4d143b80830250fa028ec6eeca4bdb9763bb3d3aed70cf076",
"format": 1
+ },
+ {
+ "name": "poetry.lock",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "b91f46e08cc5088f0ef9fd4be0fb8343788b29b8d4cff60f8e679345fa2d7a15",
+ "format": 1
+ },
+ {
+ "name": "pyproject.toml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f1e0cf854931be56a6e0d7118d9de7694b85246a11da98069c64afd1e9968aee",
+ "format": 1
}
],
"format": 1
diff --git a/ansible_collections/community/digitalocean/MANIFEST.json b/ansible_collections/community/digitalocean/MANIFEST.json
index 1f207864c..6d57f21a2 100644
--- a/ansible_collections/community/digitalocean/MANIFEST.json
+++ b/ansible_collections/community/digitalocean/MANIFEST.json
@@ -2,7 +2,7 @@
"collection_info": {
"namespace": "community",
"name": "digitalocean",
- "version": "1.23.0",
+ "version": "1.26.0",
"authors": [
"Ansible (https://github.com/ansible)",
"BondAnthony (https://github.com/BondAnthony)",
@@ -33,7 +33,8 @@
"Vitaly Khabarov (https://github.com/vitkhab)",
"Onur G\u00fczel (https://github.com/onurguzel)",
"Shuaib Munshi (https://github.com/shuaibmunshi)",
- "Corey Wright (https://github.com/coreywright)"
+ "Corey Wright (https://github.com/coreywright)",
+ "Raman Babich (https://github.com/raman-babich)"
],
"readme": "README.md",
"tags": [
@@ -54,7 +55,7 @@
"name": "FILES.json",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "73859de3a30b2cdcb242f4b496ef31c47fc8d36f64646d3149622c7738d1929f",
+ "chksum_sha256": "2a9251a310fb2deb335b529e665101028bda07b3c65589a4f02d388ec531399a",
"format": 1
},
"format": 1
diff --git a/ansible_collections/community/digitalocean/README.md b/ansible_collections/community/digitalocean/README.md
index a53f9cd1f..dd41f07d1 100644
--- a/ansible_collections/community/digitalocean/README.md
+++ b/ansible_collections/community/digitalocean/README.md
@@ -73,8 +73,8 @@ This collection contains modules and plugins to assist in automating [DigitalOce
The collection is tested and supported with:
-- ansible >= 2.9.10 or ansible-core >= 2.11 (as well as the [devel branch](https://github.com/ansible/ansible))
-- python >= 3.6
+- ansible-core >= 2.12 (not including `devel`)
+- python >= 3.9
### Installing the Collection from Ansible Galaxy
diff --git a/ansible_collections/community/digitalocean/changelogs/changelog.yaml b/ansible_collections/community/digitalocean/changelogs/changelog.yaml
index 8eed4ea07..d624d4ab8 100644
--- a/ansible_collections/community/digitalocean/changelogs/changelog.yaml
+++ b/ansible_collections/community/digitalocean/changelogs/changelog.yaml
@@ -339,9 +339,9 @@ releases:
1.23.0:
changes:
bugfixes:
- - inventory plugin - bugfix for baseurl parameter (https://github.com/ansible-collections/community.digitalocean/pull/297).
- integration tests - add missing `environment` directive on pull request integration
testing (https://github.com/ansible-collections/community.digitalocean/issues/293).
+ - inventory plugin - bugfix for baseurl parameter (https://github.com/ansible-collections/community.digitalocean/pull/297).
minor_changes:
- digital_ocean_load_balancer - add support for C(size_unit) over deprecated
C(size); deprecate C(algorithm) completely (https://github.com/ansible-collections/community.digitalocean/issues/270).
@@ -358,6 +358,69 @@ releases:
- 291-pr-integration-tests-branch.yaml
- 293-integration-test-pr-environment.yaml
release_date: '2022-12-29'
+ 1.24.0:
+ changes:
+ bugfixes:
+ - digital_ocean_domain - fix ``all_domains`` by using ``get_paginated_data``
+ to retrieve all of the domains in the account from the paginated domains api
+ endpoint (https://github.com/ansible-collections/community.digitalocean/pull/307).
+ minor_changes:
+ - documentation - use C(true) and C(false) for boolean values in documentation
+ and examples (https://github.com/ansible-collections/community.digitalocean/issues/303).
+ - inventory plugin - drop C(api_token) in favor of C(oauth_token) for consistency
+ (https://github.com/ansible-collections/community.digitalocean/issues/300).
+ - tests - add C(sanity), C(units), and C(psf/black) back on merge into C(main)
+ (https://github.com/ansible-collections/community.digitalocean/pull/311).
+ - tests - drop Ansible 2.9 and Ansible Core 2.10 and 2.11 (https://github.com/ansible-collections/community.digitalocean/pull/310).
+ - tests - remove the daily runs (https://github.com/ansible-collections/community.digitalocean/pull/310).
+ - tests - run C(psf/black) across all files (https://github.com/ansible-collections/community.digitalocean/pull/310).
+ - tests - test against Ansible Core 2.12, 2.13, and 2.14 (https://github.com/ansible-collections/community.digitalocean/pull/310).
+ fragments:
+ - 300-inventory-plugin-oauth-token.yaml
+ - 303-documentation-bool-true-false.yaml
+ - 307-get-all-domains-pagination-fix.yaml
+ - 310-update-tests.yaml
+ - 311-update-tests.yaml
+ - 312-double-integration-test-timeout.yaml
+ release_date: '2023-08-12'
+ 1.25.0:
+ changes:
+ bugfixes:
+ - inventory plugin - restore reading auth token from env variables (https://github.com/ansible-collections/community.digitalocean/pull/315).
+ minor_changes:
+ - fix sanity tests (https://github.com/ansible-collections/community.digitalocean/issues/323).
+ fragments:
+ - 314-add-cname-example-to-domain_record-module.yaml
+ - 316-inventory-plugin-restore-reading-auth-token-from-env-variables.yaml
+ - 323-project-resource-info-module.yaml
+ modules:
+ - description: Gather information about DigitalOcean Project Resources
+ name: digital_ocean_project_resource_info
+ namespace: ''
+ release_date: '2023-12-11'
+ 1.26.0:
+ changes:
+ bugfixes:
+ - The C(project_name) parameter for many modules was used by alias C(project)
+ internally in the codebase, but to work properly C(project_name) must be used
+ in the code. Replace self.module.params.get("project") with self.module.params.get("project_name")
+ (https://github.com/ansible-collections/community.digitalocean/issues/326).
+ - digital_ocean_kubernetes - module didn't return kubeconfig properly, return
+ documentation was invalid. Fixed version returns data with the same structure
+ all the time, also it is aligned with M(community.digitalocean.digital_ocean_kubernetes_info)
+ documentation return data now. (https://github.com/ansible-collections/community.digitalocean/issues/322).
+ minor_changes:
+ - digital_ocean_kubernetes - add project_name parameter (https://github.com/ansible-collections/community.digitalocean/issues/264).
+ fragments:
+ - 264-kubernetes-project.yaml
+ - 322-k8s-module-kubeconfig.yaml
+ - 326-project-name-param.yaml
+ - 334-droplet-ci-images.yml
+ - 337-refactor-integration-tests.yml
+ - 338-refactor-integration-tests.yml
+ - 339-refactor-integration-tests.yml
+ - 340-fix-refactor-integration-tests.yml
+ release_date: '2024-01-01'
1.3.0:
modules:
- description: Create and delete a DigitalOcean database
diff --git a/ansible_collections/community/digitalocean/plugins/doc_fragments/digital_ocean.py b/ansible_collections/community/digitalocean/plugins/doc_fragments/digital_ocean.py
index bc65ad386..7f9e067ad 100644
--- a/ansible_collections/community/digitalocean/plugins/doc_fragments/digital_ocean.py
+++ b/ansible_collections/community/digitalocean/plugins/doc_fragments/digital_ocean.py
@@ -22,7 +22,7 @@ options:
description:
- DigitalOcean OAuth token.
- "There are several other environment variables which can be used to provide this value."
- - "i.e., - 'DO_API_TOKEN', 'DO_API_KEY', 'DO_OAUTH_TOKEN' and 'OAUTH_TOKEN'"
+ - "i.e., - C(DO_API_TOKEN), C(DO_API_KEY), C(DO_OAUTH_TOKEN) and C(OAUTH_TOKEN)."
type: str
aliases: [ api_token ]
timeout:
@@ -35,5 +35,5 @@ options:
- If set to C(no), the SSL certificates will not be validated.
- This should only set to C(no) used on personally controlled sites using self-signed certificates.
type: bool
- default: yes
+ default: true
"""
diff --git a/ansible_collections/community/digitalocean/plugins/inventory/digitalocean.py b/ansible_collections/community/digitalocean/plugins/inventory/digitalocean.py
index 6aafb5f45..b886fc114 100644
--- a/ansible_collections/community/digitalocean/plugins/inventory/digitalocean.py
+++ b/ansible_collections/community/digitalocean/plugins/inventory/digitalocean.py
@@ -30,15 +30,6 @@ options:
this should always be C(community.digitalocean.digitalocean).
required: true
choices: ['community.digitalocean.digitalocean']
- api_token:
- description:
- - DigitalOcean OAuth token.
- - Template expressions can be used in this field.
- required: true
- type: str
- aliases: [ oauth_token ]
- env:
- - name: DO_API_TOKEN
attributes:
description: >-
Droplet attributes to add as host vars to each inventory host.
@@ -78,7 +69,7 @@ options:
EXAMPLES = r"""
# Using keyed groups and compose for hostvars
plugin: community.digitalocean.digitalocean
-api_token: '{{ lookup("pipe", "./get-do-token.sh" }}'
+oauth_token: '{{ lookup("pipe", "./get-do-token.sh" }}'
attributes:
- id
- name
@@ -108,7 +99,6 @@ filters:
- 'do_region.slug == "fra1"'
"""
-import re
import json
from ansible.errors import AnsibleError, AnsibleParserError
from ansible.inventory.group import to_safe_group_name
@@ -119,7 +109,6 @@ from ansible.plugins.inventory import BaseInventoryPlugin, Constructable, Cachea
class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
-
NAME = "community.digitalocean.digitalocean"
# Constructable methods use the following function to construct group names. By
@@ -160,7 +149,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
def _get_payload(self):
# request parameters
- api_token = self._template_option("api_token")
+ api_token = self._template_option("oauth_token")
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer {0}".format(api_token),
@@ -195,7 +184,6 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
strict = self.get_option("strict")
host_filters = self.get_option("filters")
for record in records:
-
host_name = record.get("name")
if not host_name:
continue
diff --git a/ansible_collections/community/digitalocean/plugins/module_utils/digital_ocean.py b/ansible_collections/community/digitalocean/plugins/module_utils/digital_ocean.py
index 44ca3ccd1..f7bb42042 100644
--- a/ansible_collections/community/digitalocean/plugins/module_utils/digital_ocean.py
+++ b/ansible_collections/community/digitalocean/plugins/module_utils/digital_ocean.py
@@ -12,10 +12,9 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type
import json
-import os
-from ansible.module_utils.urls import fetch_url
from ansible.module_utils._text import to_text
from ansible.module_utils.basic import env_fallback
+from ansible.module_utils.urls import fetch_url
class Response(object):
@@ -224,6 +223,42 @@ class DigitalOceanProjects:
return "Unexpected error; more than one project with the same name", {}
return "", project[0]
+ def get_resources_by_id(self, id):
+ """Fetches the project resources with the given id.
+
+ Returns:
+ error_message -- project fetch error message (or "" if no error)
+ resources -- resources dictionary representation (or {} if error)
+ """
+ resources = self.rest.get_paginated_data(
+ base_url="projects/{0}/resources?".format(id), data_key_name="resources"
+ )
+ return "", dict(resources=resources)
+
+ def get_resources_by_name(self, name):
+ """Fetches the project resources with the given name.
+
+ Returns:
+ error_message -- project fetch error message (or "" if no error)
+ resources -- resources dictionary representation (or {} if error)
+ """
+ err_msg, project = self.get_by_name(name)
+ if err_msg:
+ return err_msg, {}
+ return self.get_resources_by_id(project.get("id"))
+
+ def get_resources_of_default(self):
+ """Fetches default project resources.
+
+ Returns:
+ error_message -- project fetch error message (or "" if no error)
+ resources -- resources dictionary representation (or {} if error)
+ """
+ err_msg, project = self.get_default()
+ if err_msg:
+ return err_msg, {}
+ return self.get_resources_by_id(project.get("id"))
+
def assign_to_project(self, project_name, urn):
"""Assign resource (urn) to project (name).
@@ -248,6 +283,7 @@ class DigitalOceanProjects:
Domain | do:domain:example.com
Droplet | do:droplet:4126873
Floating IP | do:floatingip:192.168.99.100
+ Kubernetes | do:kubernetes:bd5f5959-5e1e-4205-a714-a914373942af
Load Balancer | do:loadbalancer:39052d89-8dd4-4d49-8d5a-3c3b6b365b5b
Space | do:space:my-website-assets
Volume | do:volume:6fc4c277-ea5c-448a-93cd-dd496cfef71f
diff --git a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean.py b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean.py
index 1c33f2c79..4f3d7b146 100644
--- a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean.py
+++ b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean.py
@@ -185,7 +185,6 @@ EXAMPLES = r"""
image_id: fedora-19-x64
"""
-import os
import time
import traceback
@@ -198,7 +197,7 @@ except ImportError:
try:
# Imported as a dependency for dopy
- import ansible.module_utils.six
+ import ansible.module_utils.six # pylint: disable=unused-import
HAS_SIX = True
except ImportError:
@@ -398,7 +397,6 @@ def core(module):
if command == "droplet":
Droplet.setup(api_token)
if state in ("active", "present"):
-
# First, try to find a droplet by id.
droplet = Droplet.find(id=module.params["id"])
diff --git a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_block_storage.py b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_block_storage.py
index 8597eb1ee..58bc546f9 100644
--- a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_block_storage.py
+++ b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_block_storage.py
@@ -182,7 +182,7 @@ class DOBlockStorage(object):
def __init__(self, module):
self.module = module
self.rest = DigitalOceanHelper(module)
- if self.module.params.get("project"):
+ if self.module.params.get("project_name"):
# only load for non-default project assignments
self.projects = DigitalOceanProjects(module, self.rest)
@@ -295,7 +295,7 @@ class DOBlockStorage(object):
status = response.status_code
json = response.json
if status == 201:
- project_name = self.module.params.get("project")
+ project_name = self.module.params.get("project_name")
if (
project_name
): # empty string is the default project, skip project assignment
diff --git a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_cdn_endpoints.py b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_cdn_endpoints.py
index d36177586..c01735b68 100644
--- a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_cdn_endpoints.py
+++ b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_cdn_endpoints.py
@@ -43,11 +43,13 @@ options:
description:
- The ID of a DigitalOcean managed TLS certificate used for SSL when a custom subdomain is provided.
type: str
+ default: ""
required: false
custom_domain:
description:
- The fully qualified domain name (FQDN) of the custom subdomain used with the CDN endpoint.
type: str
+ default: ""
required: false
extends_documentation_fragment:
- community.digitalocean.digital_ocean.documentation
@@ -92,7 +94,7 @@ data:
"""
-from ansible.module_utils.basic import AnsibleModule, env_fallback
+from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.digitalocean.plugins.module_utils.digital_ocean import (
DigitalOceanHelper,
)
diff --git a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_cdn_endpoints_info.py b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_cdn_endpoints_info.py
index 7c8de494f..46e75affc 100644
--- a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_cdn_endpoints_info.py
+++ b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_cdn_endpoints_info.py
@@ -54,7 +54,7 @@ data:
"""
-from ansible.module_utils.basic import AnsibleModule, env_fallback
+from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.digitalocean.plugins.module_utils.digital_ocean import (
DigitalOceanHelper,
)
diff --git a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_database.py b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_database.py
index ffae82dbb..9fc035279 100644
--- a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_database.py
+++ b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_database.py
@@ -196,9 +196,8 @@ resources:
"""
-import json
import time
-from ansible.module_utils.basic import AnsibleModule, env_fallback
+from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.digitalocean.plugins.module_utils.digital_ocean import (
DigitalOceanHelper,
DigitalOceanProjects,
@@ -209,7 +208,7 @@ class DODatabase(object):
def __init__(self, module):
self.module = module
self.rest = DigitalOceanHelper(module)
- if self.module.params.get("project"):
+ if self.module.params.get("project_name"):
# only load for non-default project assignments
self.projects = DigitalOceanProjects(module, self.rest)
# pop wait and wait_timeout so we don't include it in the POST data
@@ -336,7 +335,7 @@ class DODatabase(object):
if self.wait:
json_data = self.ensure_online(database_id)
- project_name = self.module.params.get("project")
+ project_name = self.module.params.get("project_name")
if project_name: # empty string is the default project, skip project assignment
urn = "do:dbaas:{0}".format(database_id)
assign_status, error_message, resources = self.projects.assign_to_project(
diff --git a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_database_info.py b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_database_info.py
index cc5996613..c2c987eb0 100644
--- a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_database_info.py
+++ b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_database_info.py
@@ -93,7 +93,7 @@ data:
"""
-from ansible.module_utils.basic import AnsibleModule, env_fallback
+from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.digitalocean.plugins.module_utils.digital_ocean import (
DigitalOceanHelper,
)
diff --git a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_domain.py b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_domain.py
index 234c6cf21..502420df5 100644
--- a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_domain.py
+++ b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_domain.py
@@ -119,7 +119,7 @@ class DoManager(DigitalOceanHelper, object):
return response.status_code, response.json
def all_domains(self):
- resp = self.get("domains/")
+ resp = self.get_paginated_data(base_url="domains?", data_key_name="domains")
return resp
def find(self):
@@ -127,8 +127,7 @@ class DoManager(DigitalOceanHelper, object):
return None
domains = self.all_domains()
- status, json = self.jsonify(domains)
- for domain in json["domains"]:
+ for domain in domains:
if domain["name"] == self.domain_name:
return domain
return None
@@ -193,7 +192,7 @@ def run(module):
do_manager = DoManager(module)
state = module.params.get("state")
- if module.params.get("project"):
+ if module.params.get("project_name"):
# only load for non-default project assignments
projects = DigitalOceanProjects(module, do_manager)
@@ -215,7 +214,7 @@ def run(module):
# few times before giving up and returning null.
domain_name = module.params.get("name")
- project_name = module.params.get("project")
+ project_name = module.params.get("project_name")
urn = "do:domain:{0}".format(domain_name)
for i in range(ZONE_FILE_ATTEMPTS):
diff --git a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_domain_record.py b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_domain_record.py
index 05bc4a457..9fa5bd572 100644
--- a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_domain_record.py
+++ b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_domain_record.py
@@ -45,7 +45,6 @@ options:
data:
description:
- This is the value of the record, depending on the record type.
- default: ""
type: str
name:
description:
@@ -116,7 +115,7 @@ EXAMPLES = """
type: A
name: www
data: 127.0.0.2
- force_update: yes
+ force_update: true
- name: Update A record for www based on record_id
community.digitalocean.digital_ocean_domain_record:
@@ -127,7 +126,7 @@ EXAMPLES = """
type: A
name: www
data: 127.0.0.2
- force_update: yes
+ force_update: true
- name: Remove www record based on name/type/data
community.digitalocean.digital_ocean_domain_record:
@@ -145,6 +144,19 @@ EXAMPLES = """
domain: example.com
record_id: 1234567
+- name: Create CNAME records for www, git and status subdomains
+ community.digitalocean.digital_ocean_domain_record:
+ state: present
+ oauth_token: "{{ lookup('ansible.builtin.env', 'DO_API_TOKEN') }}"
+ domain: example.com
+ type: CNAME
+ name: "{{ item }}"
+ data: example.com
+ with_items:
+ - www
+ - git
+ - status
+
- name: Create MX record with priority 10 for example.com
community.digitalocean.digital_ocean_domain_record:
state: present
@@ -218,7 +230,6 @@ class DigitalOceanDomainRecordManager(DigitalOceanHelper, object):
)
def __get_all_records(self):
-
records = []
page = 1
while True:
@@ -315,7 +326,6 @@ class DigitalOceanDomainRecordManager(DigitalOceanHelper, object):
)
def create_or_update_record(self):
-
# if record_id is given we need to update the record no matter what
if self.record_id:
changed, result = self.__update_record(self.record_id)
@@ -394,7 +404,6 @@ class DigitalOceanDomainRecordManager(DigitalOceanHelper, object):
)
def __build_payload(self):
-
payload = dict(
data=self.module.params.get("data"),
flags=self.module.params.get("flags"),
@@ -418,7 +427,6 @@ class DigitalOceanDomainRecordManager(DigitalOceanHelper, object):
return payload
def delete_record(self):
-
# if record_id is given, try to find the record based on the id
if self.record_id:
record = self.__find_record_by_id(self.record_id)
diff --git a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_domain_record_info.py b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_domain_record_info.py
index b42a7aaaf..d28af6fdd 100644
--- a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_domain_record_info.py
+++ b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_domain_record_info.py
@@ -89,7 +89,6 @@ data:
"""
-from ansible.module_utils.basic import env_fallback
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.digitalocean.plugins.module_utils.digital_ocean import (
DigitalOceanHelper,
@@ -116,7 +115,6 @@ class DigitalOceanDomainRecordManager(DigitalOceanHelper, object):
)
def __get_all_records(self):
-
records = []
page = 1
while True:
@@ -176,7 +174,6 @@ class DigitalOceanDomainRecordManager(DigitalOceanHelper, object):
return None
def __build_payload(self):
-
payload = dict(
name=self.module.params.get("name"),
type=self.module.params.get("type"),
diff --git a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_droplet.py b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_droplet.py
index 791f2891b..495aca7b1 100644
--- a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_droplet.py
+++ b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_droplet.py
@@ -287,7 +287,7 @@ resources:
"""
import time
-from ansible.module_utils.basic import AnsibleModule, env_fallback
+from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.digitalocean.plugins.module_utils.digital_ocean import (
DigitalOceanHelper,
DigitalOceanProjects,
@@ -295,7 +295,6 @@ from ansible_collections.community.digitalocean.plugins.module_utils.digital_oce
class DODroplet(object):
-
failure_message = {
"empty_response": "Empty response from the DigitalOcean API; please try again or open a bug if it never "
"succeeds.",
@@ -320,7 +319,7 @@ class DODroplet(object):
self.name = None
self.size = None
self.status = None
- if self.module.params.get("project"):
+ if self.module.params.get("project_name"):
# only load for non-default project assignments
self.projects = DigitalOceanProjects(module, self.rest)
self.firewalls = self.get_firewalls()
@@ -780,7 +779,7 @@ class DODroplet(object):
if json_data:
droplet = json_data.get("droplet", droplet)
- project_name = self.module.params.get("project")
+ project_name = self.module.params.get("project_name")
if project_name: # empty string is the default project, skip project assignment
urn = "do:droplet:{0}".format(droplet_id)
assign_status, error_message, resources = self.projects.assign_to_project(
diff --git a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_droplet_info.py b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_droplet_info.py
index 474b9af27..65032301a 100644
--- a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_droplet_info.py
+++ b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_droplet_info.py
@@ -210,7 +210,6 @@ data:
type: list
"""
-from traceback import format_exc
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.digitalocean.plugins.module_utils.digital_ocean import (
DigitalOceanHelper,
diff --git a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_firewall.py b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_firewall.py
index 24b7c4203..61ccea01c 100644
--- a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_firewall.py
+++ b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_firewall.py
@@ -544,7 +544,7 @@ def main():
outbound_rules=dict(
type="list", elements="dict", options=outbound_spec, required=False
),
- ),
+ )
module = AnsibleModule(
argument_spec=argument_spec,
required_if=[("state", "present", ["inbound_rules", "outbound_rules"])],
diff --git a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_floating_ip.py b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_floating_ip.py
index d4d6ff263..ed84d2841 100644
--- a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_floating_ip.py
+++ b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_floating_ip.py
@@ -435,11 +435,11 @@ def create_floating_ips(module, rest):
json_data = response.json
if status_code == 202:
if module.params.get(
- "project"
+ "project_name"
): # only load for non-default project assignments
rest = DigitalOceanHelper(module)
projects = DigitalOceanProjects(module, rest)
- project_name = module.params.get("project")
+ project_name = module.params.get("project_name")
if (
project_name
): # empty string is the default project, skip project assignment
diff --git a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_kubernetes.py b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_kubernetes.py
index eda9c4241..b286930f7 100644
--- a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_kubernetes.py
+++ b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_kubernetes.py
@@ -155,6 +155,14 @@ options:
- Highly available control planes incur less downtime.
type: bool
default: false
+ project_name:
+ aliases: ["project"]
+ description:
+ - Project to assign the resource to (project name, not UUID).
+ - Defaults to the default project of the account (empty string).
+ type: str
+ required: false
+ default: ""
"""
@@ -169,9 +177,9 @@ EXAMPLES = r"""
- name: hacktoberfest-workers
size: s-1vcpu-2gb
count: 3
- return_kubeconfig: yes
+ return_kubeconfig: true
wait_timeout: 600
- register: my_cluster
+ register: my_cluster
- name: Show the kubeconfig for the cluster we just created
debug:
@@ -182,6 +190,21 @@ EXAMPLES = r"""
state: absent
oauth_token: "{{ lookup('env', 'DO_API_TOKEN') }}"
name: hacktoberfest
+
+- name: Create a new DigitalOcean Kubernetes cluster assigned to Project "test"
+ community.digitalocean.digital_ocean_kubernetes:
+ state: present
+ oauth_token: "{{ lookup('env', 'DO_API_TOKEN') }}"
+ name: hacktoberfest
+ region: nyc1
+ node_pools:
+ - name: hacktoberfest-workers
+ size: s-1vcpu-2gb
+ count: 3
+ return_kubeconfig: true
+ project: test
+ wait_timeout: 600
+ register: my_cluster
"""
@@ -212,62 +235,58 @@ data:
- name: do-nyc1-hacktoberfest-admin
user:
token: REDACTED
- kubernetes_cluster:
- auto_upgrade: false
- cluster_subnet: 10.244.0.0/16
- created_at: '2020-09-27T00:55:37Z'
- endpoint: https://REDACTED.k8s.ondigitalocean.com
+ auto_upgrade: false
+ cluster_subnet: 10.244.0.0/16
+ created_at: '2020-09-27T00:55:37Z'
+ endpoint: https://REDACTED.k8s.ondigitalocean.com
+ id: REDACTED
+ ipv4: REDACTED
+ maintenance_policy:
+ day: any
+ duration: 4h0m0s
+ start_time: '15:00'
+ name: hacktoberfest
+ node_pools:
+ - auto_scale: false
+ count: 1
id: REDACTED
- ipv4: REDACTED
- maintenance_policy:
- day: any
- duration: 4h0m0s
- start_time: '15:00'
- name: hacktoberfest
- node_pools:
- - auto_scale: false
- count: 1
+ labels: null
+ max_nodes: 0
+ min_nodes: 0
+ name: hacktoberfest-workers
+ nodes:
+ - created_at: '2020-09-27T00:55:37Z'
+ droplet_id: '209555245'
id: REDACTED
- labels: null
- max_nodes: 0
- min_nodes: 0
- name: hacktoberfest-workers
- nodes:
- - created_at: '2020-09-27T00:55:37Z'
- droplet_id: '209555245'
- id: REDACTED
- name: hacktoberfest-workers-3tdq1
- status:
- state: running
- updated_at: '2020-09-27T00:58:36Z'
- size: s-1vcpu-2gb
- tags:
- - k8s
- - k8s:REDACTED
- - k8s:worker
- taints: []
- region: nyc1
- service_subnet: 10.245.0.0/16
- status:
- state: running
- surge_upgrade: false
+ name: hacktoberfest-workers-3tdq1
+ status:
+ state: running
+ updated_at: '2020-09-27T00:58:36Z'
+ size: s-1vcpu-2gb
tags:
- k8s
- k8s:REDACTED
- updated_at: '2020-09-27T01:00:37Z'
- version: 1.18.8-do.1
- vpc_uuid: REDACTED
+ - k8s:worker
+ taints: []
+ region: nyc1
+ service_subnet: 10.245.0.0/16
+ status:
+ state: running
+ surge_upgrade: false
+ tags:
+ - k8s
+ - k8s:REDACTED
+ updated_at: '2020-09-27T01:00:37Z'
+ version: 1.18.8-do.1
+ vpc_uuid: REDACTED
"""
-import traceback
import time
-import json
-from traceback import format_exc
-from ansible.module_utils._text import to_native
from ansible.module_utils.basic import AnsibleModule, env_fallback
from ansible_collections.community.digitalocean.plugins.module_utils.digital_ocean import (
DigitalOceanHelper,
+ DigitalOceanProjects,
)
@@ -281,6 +300,8 @@ class DOKubernetes(object):
self.wait_timeout = self.module.params.pop("wait_timeout", 600)
self.module.params.pop("oauth_token")
self.cluster_id = None
+ if self.module.params.get("project_name"):
+ self.projects = DigitalOceanProjects(module, self.rest)
def get_by_id(self):
"""Returns an existing DigitalOcean Kubernetes cluster matching on id"""
@@ -379,16 +400,32 @@ class DOKubernetes(object):
node_pool["size"], ", ".join(valid_sizes)
)
)
-
+ if self.module.check_mode:
+ self.module.exit_json(changed=True)
# Create the Kubernetes cluster
json_data = self.get_kubernetes()
if json_data:
# Add the kubeconfig to the return
if self.return_kubeconfig:
json_data["kubeconfig"] = self.get_kubernetes_kubeconfig()
+ # Assign kubernetes to project
+ project_name = self.module.params.get("project_name")
+ # empty string is the default project, skip project assignment
+ if project_name:
+ urn = "do:kubernetes:{0}".format(self.cluster_id)
+ (
+ assign_status,
+ error_message,
+ resources,
+ ) = self.projects.assign_to_project(project_name, urn)
+ if assign_status not in {"ok", "assigned", "already_assigned"}:
+ self.module.fail_json(
+ changed=False,
+ msg=error_message,
+ assign_status=assign_status,
+ resources=resources,
+ )
self.module.exit_json(changed=False, data=json_data)
- if self.module.check_mode:
- self.module.exit_json(changed=True)
request_params = dict(self.module.params)
response = self.rest.post("kubernetes/clusters", data=request_params)
json_data = response.json
@@ -401,6 +438,24 @@ class DOKubernetes(object):
# Add the kubeconfig to the return
if self.return_kubeconfig:
json_data["kubeconfig"] = self.get_kubernetes_kubeconfig()
+ # Assign kubernetes to project
+ project_name = self.module.params.get("project_name")
+ # empty string is the default project, skip project assignment
+ if project_name:
+ urn = "do:kubernetes:{0}".format(self.cluster_id)
+ assign_status, error_message, resources = self.projects.assign_to_project(
+ project_name, urn
+ )
+ if assign_status not in {"ok", "assigned", "already_assigned"}:
+ self.module.fail_json(
+ changed=True,
+ msg=error_message,
+ assign_status=assign_status,
+ resources=resources,
+ )
+ json_data["kubernetes_cluster"][
+ "kubeconfig"
+ ] = self.get_kubernetes_kubeconfig()
self.module.exit_json(changed=True, data=json_data["kubernetes_cluster"])
def delete(self):
@@ -477,6 +532,9 @@ def main():
wait=dict(type="bool", default=True),
wait_timeout=dict(type="int", default=600),
ha=dict(type="bool", default=False),
+ project_name=dict(
+ type="str", aliases=["project"], required=False, default=""
+ ),
),
required_if=(
[
diff --git a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_kubernetes_info.py b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_kubernetes_info.py
index d60e9b4ad..2780d5a2b 100644
--- a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_kubernetes_info.py
+++ b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_kubernetes_info.py
@@ -42,7 +42,7 @@ EXAMPLES = r"""
community.digitalocean.digital_ocean_kubernetes_info:
oauth_token: "{{ lookup('ansible.builtin.env', 'DO_API_TOKEN') }}"
name: hacktoberfest
- return_kubeconfig: yes
+ return_kubeconfig: true
register: my_cluster
- ansible.builtin.debug:
@@ -127,11 +127,6 @@ data:
"""
-import traceback
-import time
-import json
-from traceback import format_exc
-from ansible.module_utils._text import to_native
from ansible.module_utils.basic import AnsibleModule, env_fallback
from ansible_collections.community.digitalocean.plugins.module_utils.digital_ocean import (
DigitalOceanHelper,
diff --git a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_load_balancer.py b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_load_balancer.py
index ecc9efa43..d0da6f7dc 100644
--- a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_load_balancer.py
+++ b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_load_balancer.py
@@ -407,8 +407,7 @@ resources:
import time
-from ansible.module_utils._text import to_native
-from ansible.module_utils.basic import AnsibleModule, env_fallback
+from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.digitalocean.plugins.module_utils.digital_ocean import (
DigitalOceanHelper,
DigitalOceanProjects,
@@ -416,7 +415,6 @@ from ansible_collections.community.digitalocean.plugins.module_utils.digital_oce
class DOLoadBalancer(object):
-
# Regions which use 'size' versus 'size_unit'
size_regions = {"ams2", "nyc2", "sfo1"}
all_sizes = {"lb-small", "lb-medium", "lb-large"}
@@ -469,7 +467,7 @@ class DOLoadBalancer(object):
self.module.params.pop("oauth_token")
self.wait = self.module.params.pop("wait", True)
self.wait_timeout = self.module.params.pop("wait_timeout", 600)
- if self.module.params.get("project"):
+ if self.module.params.get("project_name"):
# only load for non-default project assignments
self.projects = DigitalOceanProjects(module, self.rest)
@@ -718,7 +716,7 @@ class DOLoadBalancer(object):
if self.wait:
self.ensure_active()
- project_name = self.module.params.get("project")
+ project_name = self.module.params.get("project_name")
if project_name: # empty string is the default project, skip project assignment
urn = "do:loadbalancer:{0}".format(self.id)
(
diff --git a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_monitoring_alerts.py b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_monitoring_alerts.py
index 67825ccc5..039940b97 100644
--- a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_monitoring_alerts.py
+++ b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_monitoring_alerts.py
@@ -144,7 +144,6 @@ data:
"""
-from ansible.module_utils._text import to_native
from ansible.module_utils.basic import AnsibleModule, env_fallback
from ansible_collections.community.digitalocean.plugins.module_utils.digital_ocean import (
DigitalOceanHelper,
@@ -247,7 +246,6 @@ class DOMonitoringAlerts(object):
def delete(self):
uuid = self.module.params.get("uuid", None)
if uuid is not None:
-
# Check mode
if self.module.check_mode:
self.module.exit_json(changed=True)
diff --git a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_monitoring_alerts_info.py b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_monitoring_alerts_info.py
index a5d87ad60..54c4402c2 100644
--- a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_monitoring_alerts_info.py
+++ b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_monitoring_alerts_info.py
@@ -77,7 +77,6 @@ data:
"""
-from ansible.module_utils._text import to_native
from ansible.module_utils.basic import AnsibleModule, env_fallback
from ansible_collections.community.digitalocean.plugins.module_utils.digital_ocean import (
DigitalOceanHelper,
diff --git a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_project.py b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_project.py
index e0333883e..7799ec019 100644
--- a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_project.py
+++ b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_project.py
@@ -135,8 +135,6 @@ data:
}
"""
-import time
-import json
from ansible.module_utils.basic import AnsibleModule, env_fallback
from ansible_collections.community.digitalocean.plugins.module_utils.digital_ocean import (
DigitalOceanHelper,
diff --git a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_project_info.py b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_project_info.py
index 0c6ac670c..a3bfb4eeb 100644
--- a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_project_info.py
+++ b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_project_info.py
@@ -66,7 +66,6 @@ data:
updated_at: "2021-03-11T00:00:00Z"
"""
-from traceback import format_exc
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.digitalocean.plugins.module_utils.digital_ocean import (
DigitalOceanHelper,
diff --git a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_project_resource_info.py b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_project_resource_info.py
new file mode 100644
index 000000000..13c1404b7
--- /dev/null
+++ b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_project_resource_info.py
@@ -0,0 +1,104 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright: (c) 2023, Raman Babich <ramanbabich@gmail.com>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+DOCUMENTATION = r"""
+---
+module: digital_ocean_project_resource_info
+short_description: Gather information about DigitalOcean Project Resources
+description:
+ - This module can be used to gather information about Project Resources.
+author: "Raman Babich (@raman-babich)"
+version_added: 1.25.0
+
+options:
+ id:
+ description:
+ - Project ID that can be used to identify and reference a project.
+ - If C(id) and C(name) are not specified default project will be used.
+ type: str
+ name:
+ description:
+ - Project name that can be used to identify and reference a project.
+ - If C(id) and C(name) are not specified default project will be used.
+ type: str
+
+extends_documentation_fragment:
+- community.digitalocean.digital_ocean
+"""
+
+EXAMPLES = r"""
+- name: Get project resources by id
+ community.digitalocean.digital_ocean_project_resource_info:
+ id: cb1ef55e-3cd8-4c7c-aa5d-07c32bf41627
+
+- name: Get project resources by name
+ community.digitalocean.digital_ocean_project_resource_info:
+ name: my-project-name
+
+- name: Get default project resources
+ community.digitalocean.digital_ocean_project_resource_info:
+"""
+
+RETURN = r"""
+data:
+ description: "DigitalOcean project resources information"
+ elements: dict
+ returned: success
+ type: list
+ sample:
+ - urn: "do:droplet:13457723"
+ assigned_at: "2018-09-28T19:26:37Z"
+ links:
+ self: "https://api.digitalocean.com/v2/droplets/13457723"
+ status: "ok"
+ - urn: "do:domain:example.com"
+ assigned_at: "2019-03-31T16:24:14Z"
+ links:
+ self: "https://api.digitalocean.com/v2/domains/example.com"
+ status: "ok"
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.community.digitalocean.plugins.module_utils.digital_ocean import (
+ DigitalOceanHelper,
+ DigitalOceanProjects,
+)
+
+
+def run(module):
+ rest = DigitalOceanHelper(module)
+ projects = DigitalOceanProjects(module, rest)
+ if module.params["id"]:
+ err_msg, resources = projects.get_resources_by_id(module.params["id"])
+ elif module.params["name"]:
+ err_msg, resources = projects.get_resources_by_name(module.params["name"])
+ else:
+ err_msg, resources = projects.get_resources_of_default()
+
+ if err_msg:
+ module.fail_json(msg=err_msg)
+ module.exit_json(data=resources["resources"])
+
+
+def main():
+ argument_spec = DigitalOceanHelper.digital_ocean_argument_spec()
+ argument_spec.update(
+ name=dict(type="str"),
+ id=dict(type="str"),
+ )
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ mutually_exclusive=[("id", "name")],
+ supports_check_mode=True,
+ )
+ run(module)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_snapshot.py b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_snapshot.py
index 67dc01000..241d6621e 100644
--- a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_snapshot.py
+++ b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_snapshot.py
@@ -46,6 +46,7 @@ options:
- Only applies to volume snapshots (not Droplets).
type: list
elements: str
+ default: []
droplet_id:
description:
- Droplet ID to snapshot.
diff --git a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_spaces.py b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_spaces.py
index 0d101b501..1a2ac272b 100644
--- a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_spaces.py
+++ b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_spaces.py
@@ -208,7 +208,6 @@ def run(module):
def main():
-
argument_spec = DigitalOceanHelper.digital_ocean_argument_spec()
argument_spec.update(
state=dict(type="str", choices=["present", "absent"], default="present"),
diff --git a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_spaces_info.py b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_spaces_info.py
index 50f050020..aeab3ce9b 100644
--- a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_spaces_info.py
+++ b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_spaces_info.py
@@ -128,7 +128,6 @@ def run(module):
def main():
-
argument_spec = DigitalOceanHelper.digital_ocean_argument_spec()
argument_spec.update(
state=dict(type="str", choices=["present"], default="present"),
diff --git a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_sshkey.py b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_sshkey.py
index 3a7e662ba..8d09c1dd3 100644
--- a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_sshkey.py
+++ b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_sshkey.py
@@ -82,7 +82,6 @@ import json
import hashlib
import base64
-from ansible.module_utils.basic import env_fallback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.urls import fetch_url
diff --git a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_vpc.py b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_vpc.py
index 598ec2bf3..473b0bc9f 100644
--- a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_vpc.py
+++ b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_vpc.py
@@ -117,7 +117,6 @@ data:
"""
-import time
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.digitalocean.plugins.module_utils.digital_ocean import (
DigitalOceanHelper,
diff --git a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_vpc_info.py b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_vpc_info.py
index c2b11078d..5d8915969 100644
--- a/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_vpc_info.py
+++ b/ansible_collections/community/digitalocean/plugins/modules/digital_ocean_vpc_info.py
@@ -66,7 +66,6 @@ data:
"""
-import time
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.digitalocean.plugins.module_utils.digital_ocean import (
DigitalOceanHelper,
diff --git a/ansible_collections/community/digitalocean/poetry.lock b/ansible_collections/community/digitalocean/poetry.lock
new file mode 100644
index 000000000..48d82074e
--- /dev/null
+++ b/ansible_collections/community/digitalocean/poetry.lock
@@ -0,0 +1,2491 @@
+# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand.
+
+[[package]]
+name = "aiofiles"
+version = "23.2.1"
+description = "File support for asyncio."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "aiofiles-23.2.1-py3-none-any.whl", hash = "sha256:19297512c647d4b27a2cf7c34caa7e405c0d60b5560618a29a9fe027b18b0107"},
+ {file = "aiofiles-23.2.1.tar.gz", hash = "sha256:84ec2218d8419404abcb9f0c02df3f34c6e0a68ed41072acfb1cef5cbc29051a"},
+]
+
+[[package]]
+name = "aiohttp"
+version = "3.9.0"
+description = "Async http client/server framework (asyncio)"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "aiohttp-3.9.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6896b8416be9ada4d22cd359d7cb98955576ce863eadad5596b7cdfbf3e17c6c"},
+ {file = "aiohttp-3.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1736d87dad8ef46a8ec9cddd349fa9f7bd3a064c47dd6469c0d6763d3d49a4fc"},
+ {file = "aiohttp-3.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8c9e5f4d7208cda1a2bb600e29069eecf857e6980d0ccc922ccf9d1372c16f4b"},
+ {file = "aiohttp-3.9.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8488519aa05e636c5997719fe543c8daf19f538f4fa044f3ce94bee608817cff"},
+ {file = "aiohttp-3.9.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ab16c254e2312efeb799bc3c06897f65a133b38b69682bf75d1f1ee1a9c43a9"},
+ {file = "aiohttp-3.9.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7a94bde005a8f926d0fa38b88092a03dea4b4875a61fbcd9ac6f4351df1b57cd"},
+ {file = "aiohttp-3.9.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b777c9286b6c6a94f50ddb3a6e730deec327e9e2256cb08b5530db0f7d40fd8"},
+ {file = "aiohttp-3.9.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:571760ad7736b34d05597a1fd38cbc7d47f7b65deb722cb8e86fd827404d1f6b"},
+ {file = "aiohttp-3.9.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:deac0a32aec29608eb25d730f4bc5a261a65b6c48ded1ed861d2a1852577c932"},
+ {file = "aiohttp-3.9.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:4ee1b4152bc3190cc40ddd6a14715e3004944263ea208229ab4c297712aa3075"},
+ {file = "aiohttp-3.9.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:3607375053df58ed6f23903aa10cf3112b1240e8c799d243bbad0f7be0666986"},
+ {file = "aiohttp-3.9.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:65b0a70a25456d329a5e1426702dde67be0fb7a4ead718005ba2ca582d023a94"},
+ {file = "aiohttp-3.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5a2eb5311a37fe105aa35f62f75a078537e1a9e4e1d78c86ec9893a3c97d7a30"},
+ {file = "aiohttp-3.9.0-cp310-cp310-win32.whl", hash = "sha256:2cbc14a13fb6b42d344e4f27746a4b03a2cb0c1c3c5b932b0d6ad8881aa390e3"},
+ {file = "aiohttp-3.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:ac9669990e2016d644ba8ae4758688534aabde8dbbc81f9af129c3f5f01ca9cd"},
+ {file = "aiohttp-3.9.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f8e05f5163528962ce1d1806fce763ab893b1c5b7ace0a3538cd81a90622f844"},
+ {file = "aiohttp-3.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4afa8f71dba3a5a2e1e1282a51cba7341ae76585345c43d8f0e624882b622218"},
+ {file = "aiohttp-3.9.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f929f4c9b9a00f3e6cc0587abb95ab9c05681f8b14e0fe1daecfa83ea90f8318"},
+ {file = "aiohttp-3.9.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28185e36a78d247c55e9fbea2332d16aefa14c5276a582ce7a896231c6b1c208"},
+ {file = "aiohttp-3.9.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a486ddf57ab98b6d19ad36458b9f09e6022de0381674fe00228ca7b741aacb2f"},
+ {file = "aiohttp-3.9.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:70e851f596c00f40a2f00a46126c95c2e04e146015af05a9da3e4867cfc55911"},
+ {file = "aiohttp-3.9.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c5b7bf8fe4d39886adc34311a233a2e01bc10eb4e842220235ed1de57541a896"},
+ {file = "aiohttp-3.9.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c67a51ea415192c2e53e4e048c78bab82d21955b4281d297f517707dc836bf3d"},
+ {file = "aiohttp-3.9.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:694df243f394629bcae2d8ed94c589a181e8ba8604159e6e45e7b22e58291113"},
+ {file = "aiohttp-3.9.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3dd8119752dd30dd7bca7d4bc2a92a59be6a003e4e5c2cf7e248b89751b8f4b7"},
+ {file = "aiohttp-3.9.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:eb6dfd52063186ac97b4caa25764cdbcdb4b10d97f5c5f66b0fa95052e744eb7"},
+ {file = "aiohttp-3.9.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:d97c3e286d0ac9af6223bc132dc4bad6540b37c8d6c0a15fe1e70fb34f9ec411"},
+ {file = "aiohttp-3.9.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:816f4db40555026e4cdda604a1088577c1fb957d02f3f1292e0221353403f192"},
+ {file = "aiohttp-3.9.0-cp311-cp311-win32.whl", hash = "sha256:3abf0551874fecf95f93b58f25ef4fc9a250669a2257753f38f8f592db85ddea"},
+ {file = "aiohttp-3.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:e18d92c3e9e22553a73e33784fcb0ed484c9874e9a3e96c16a8d6a1e74a0217b"},
+ {file = "aiohttp-3.9.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:99ae01fb13a618b9942376df77a1f50c20a281390dad3c56a6ec2942e266220d"},
+ {file = "aiohttp-3.9.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:05857848da443c8c12110d99285d499b4e84d59918a21132e45c3f0804876994"},
+ {file = "aiohttp-3.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:317719d7f824eba55857fe0729363af58e27c066c731bc62cd97bc9c3d9c7ea4"},
+ {file = "aiohttp-3.9.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1e3b3c107ccb0e537f309f719994a55621acd2c8fdf6d5ce5152aed788fb940"},
+ {file = "aiohttp-3.9.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:45820ddbb276113ead8d4907a7802adb77548087ff5465d5c554f9aa3928ae7d"},
+ {file = "aiohttp-3.9.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:05a183f1978802588711aed0dea31e697d760ce9055292db9dc1604daa9a8ded"},
+ {file = "aiohttp-3.9.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51a4cd44788ea0b5e6bb8fa704597af3a30be75503a7ed1098bc5b8ffdf6c982"},
+ {file = "aiohttp-3.9.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:673343fbc0c1ac44d0d2640addc56e97a052504beacd7ade0dc5e76d3a4c16e8"},
+ {file = "aiohttp-3.9.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7e8a3b79b6d186a9c99761fd4a5e8dd575a48d96021f220ac5b5fa856e5dd029"},
+ {file = "aiohttp-3.9.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:6777a390e41e78e7c45dab43a4a0196c55c3b8c30eebe017b152939372a83253"},
+ {file = "aiohttp-3.9.0-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:7ae5f99a32c53731c93ac3075abd3e1e5cfbe72fc3eaac4c27c9dd64ba3b19fe"},
+ {file = "aiohttp-3.9.0-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:f1e4f254e9c35d8965d377e065c4a8a55d396fe87c8e7e8429bcfdeeb229bfb3"},
+ {file = "aiohttp-3.9.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:11ca808f9a6b63485059f5f6e164ef7ec826483c1212a44f268b3653c91237d8"},
+ {file = "aiohttp-3.9.0-cp312-cp312-win32.whl", hash = "sha256:de3cc86f4ea8b4c34a6e43a7306c40c1275e52bfa9748d869c6b7d54aa6dad80"},
+ {file = "aiohttp-3.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:ca4fddf84ac7d8a7d0866664936f93318ff01ee33e32381a115b19fb5a4d1202"},
+ {file = "aiohttp-3.9.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:f09960b5bb1017d16c0f9e9f7fc42160a5a49fa1e87a175fd4a2b1a1833ea0af"},
+ {file = "aiohttp-3.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8303531e2c17b1a494ffaeba48f2da655fe932c4e9a2626c8718403c83e5dd2b"},
+ {file = "aiohttp-3.9.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4790e44f46a4aa07b64504089def5744d3b6780468c4ec3a1a36eb7f2cae9814"},
+ {file = "aiohttp-3.9.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1d7edf74a36de0e5ca50787e83a77cf352f5504eb0ffa3f07000a911ba353fb"},
+ {file = "aiohttp-3.9.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:94697c7293199c2a2551e3e3e18438b4cba293e79c6bc2319f5fd652fccb7456"},
+ {file = "aiohttp-3.9.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a1b66dbb8a7d5f50e9e2ea3804b01e766308331d0cac76eb30c563ac89c95985"},
+ {file = "aiohttp-3.9.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9623cfd9e85b76b83ef88519d98326d4731f8d71869867e47a0b979ffec61c73"},
+ {file = "aiohttp-3.9.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f32c86dc967ab8c719fd229ce71917caad13cc1e8356ee997bf02c5b368799bf"},
+ {file = "aiohttp-3.9.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f50b4663c3e0262c3a361faf440761fbef60ccdde5fe8545689a4b3a3c149fb4"},
+ {file = "aiohttp-3.9.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:dcf71c55ec853826cd70eadb2b6ac62ec577416442ca1e0a97ad875a1b3a0305"},
+ {file = "aiohttp-3.9.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:42fe4fd9f0dfcc7be4248c162d8056f1d51a04c60e53366b0098d1267c4c9da8"},
+ {file = "aiohttp-3.9.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:76a86a9989ebf82ee61e06e2bab408aec4ea367dc6da35145c3352b60a112d11"},
+ {file = "aiohttp-3.9.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f9e09a1c83521d770d170b3801eea19b89f41ccaa61d53026ed111cb6f088887"},
+ {file = "aiohttp-3.9.0-cp38-cp38-win32.whl", hash = "sha256:a00ce44c21612d185c5275c5cba4bab8d7c1590f248638b667ed8a782fa8cd6f"},
+ {file = "aiohttp-3.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:d5b9345ab92ebe6003ae11d8092ce822a0242146e6fa270889b9ba965457ca40"},
+ {file = "aiohttp-3.9.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:98d21092bf2637c5fa724a428a69e8f5955f2182bff61f8036827cf6ce1157bf"},
+ {file = "aiohttp-3.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:35a68cd63ca6aaef5707888f17a70c36efe62b099a4e853d33dc2e9872125be8"},
+ {file = "aiohttp-3.9.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3d7f6235c7475658acfc1769d968e07ab585c79f6ca438ddfecaa9a08006aee2"},
+ {file = "aiohttp-3.9.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db04d1de548f7a62d1dd7e7cdf7c22893ee168e22701895067a28a8ed51b3735"},
+ {file = "aiohttp-3.9.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:536b01513d67d10baf6f71c72decdf492fb7433c5f2f133e9a9087379d4b6f31"},
+ {file = "aiohttp-3.9.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c8b0a6487e8109427ccf638580865b54e2e3db4a6e0e11c02639231b41fc0f"},
+ {file = "aiohttp-3.9.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7276fe0017664414fdc3618fca411630405f1aaf0cc3be69def650eb50441787"},
+ {file = "aiohttp-3.9.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:23170247ef89ffa842a02bbfdc425028574d9e010611659abeb24d890bc53bb8"},
+ {file = "aiohttp-3.9.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b1a2ea8252cacc7fd51df5a56d7a2bb1986ed39be9397b51a08015727dfb69bd"},
+ {file = "aiohttp-3.9.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:2d71abc15ff7047412ef26bf812dfc8d0d1020d664617f4913df2df469f26b76"},
+ {file = "aiohttp-3.9.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:2d820162c8c2bdbe97d328cd4f417c955ca370027dce593345e437b2e9ffdc4d"},
+ {file = "aiohttp-3.9.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:2779f5e7c70f7b421915fd47db332c81de365678180a9f3ab404088f87ba5ff9"},
+ {file = "aiohttp-3.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:366bc870d7ac61726f32a489fbe3d1d8876e87506870be66b01aeb84389e967e"},
+ {file = "aiohttp-3.9.0-cp39-cp39-win32.whl", hash = "sha256:1df43596b826022b14998f0460926ce261544fedefe0d2f653e1b20f49e96454"},
+ {file = "aiohttp-3.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:9c196b30f1b1aa3363a69dd69079ae9bec96c2965c4707eaa6914ba099fb7d4f"},
+ {file = "aiohttp-3.9.0.tar.gz", hash = "sha256:09f23292d29135025e19e8ff4f0a68df078fe4ee013bca0105b2e803989de92d"},
+]
+
+[package.dependencies]
+aiosignal = ">=1.1.2"
+async-timeout = {version = ">=4.0,<5.0", markers = "python_version < \"3.11\""}
+attrs = ">=17.3.0"
+frozenlist = ">=1.1.1"
+multidict = ">=4.5,<7.0"
+yarl = ">=1.0,<2.0"
+
+[package.extras]
+speedups = ["Brotli", "aiodns", "brotlicffi"]
+
+[[package]]
+name = "aiosignal"
+version = "1.3.1"
+description = "aiosignal: a list of registered asynchronous callbacks"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17"},
+ {file = "aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc"},
+]
+
+[package.dependencies]
+frozenlist = ">=1.1.0"
+
+[[package]]
+name = "alabaster"
+version = "0.7.13"
+description = "A configurable sidebar-enabled Sphinx theme"
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "alabaster-0.7.13-py3-none-any.whl", hash = "sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3"},
+ {file = "alabaster-0.7.13.tar.gz", hash = "sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2"},
+]
+
+[[package]]
+name = "ansible-compat"
+version = "4.1.5"
+description = "Ansible compatibility goodies"
+optional = false
+python-versions = ">=3.9"
+files = [
+ {file = "ansible-compat-4.1.5.tar.gz", hash = "sha256:597c836a184c1131feeb6b0e23cda236c41fecdee64427375278fb6920fd2e74"},
+ {file = "ansible_compat-4.1.5-py3-none-any.whl", hash = "sha256:bfd301071da2fee8a2b80bbb62fcd5d727c028c37c95187b9c2200b8c20ae18c"},
+]
+
+[package.dependencies]
+ansible-core = ">=2.12"
+jsonschema = ">=4.6.0"
+packaging = "*"
+PyYAML = "*"
+subprocess-tee = ">=0.4.1"
+typing-extensions = {version = ">=4.5.0", markers = "python_version < \"3.10\""}
+
+[package.extras]
+docs = ["argparse-manpage", "black", "mkdocs-ansible[lock] (>=0.1.2)"]
+test = ["coverage", "pip-tools", "pytest (>=7.2.0)", "pytest-mock", "pytest-plus"]
+
+[[package]]
+name = "ansible-core"
+version = "2.15.8"
+description = "Radically simple IT automation"
+optional = false
+python-versions = ">=3.9"
+files = [
+ {file = "ansible-core-2.15.8.tar.gz", hash = "sha256:8aa49cb1ddbf33d88c2bb4bf09ecd4b0dd8b788e174adca8b88dda6e6bdbf59b"},
+ {file = "ansible_core-2.15.8-py3-none-any.whl", hash = "sha256:55e6f4350fb98ac5441620ba981b1d9f7b90aa5f320885965af996e149bd3caa"},
+]
+
+[package.dependencies]
+cryptography = "*"
+importlib-resources = {version = ">=5.0,<5.1", markers = "python_version < \"3.10\""}
+jinja2 = ">=3.0.0"
+packaging = "*"
+PyYAML = ">=5.1"
+resolvelib = ">=0.5.3,<1.1.0"
+
+[[package]]
+name = "ansible-lint"
+version = "6.17.2"
+description = "Checks playbooks for practices and behavior that could potentially be improved"
+optional = false
+python-versions = ">=3.9"
+files = [
+ {file = "ansible-lint-6.17.2.tar.gz", hash = "sha256:9df62535f4228c67947548d6498884d5fa7b22ee3e947372e64ed0e5fcaba038"},
+ {file = "ansible_lint-6.17.2-py3-none-any.whl", hash = "sha256:4037647a0c55cf9ffb7a3bcd5ddb1d764b4f238b259866212893cecb2e3daadf"},
+]
+
+[package.dependencies]
+ansible-compat = ">=4.0.5"
+ansible-core = ">=2.12.0"
+black = ">=22.8.0"
+filelock = ">=3.3.0"
+jsonschema = ">=4.10.0"
+packaging = ">=21.3"
+pathspec = ">=0.10.3"
+pyyaml = ">=5.4.1"
+requests = ">=2.31.0"
+rich = ">=12.0.0"
+"ruamel.yaml" = ">=0.17.0,<0.17.29 || >0.17.29,<0.17.30 || >0.17.30,<0.18"
+subprocess-tee = ">=0.4.1"
+wcmatch = ">=8.1.2"
+yamllint = ">=1.30.0"
+
+[package.extras]
+docs = ["mkdocs-ansible[lock] (>=0.1.6)", "pipdeptree (>=2.4.0)"]
+lock = ["ansible-compat (==4.1.2)", "ansible-core (==2.15.1)", "attrs (==23.1.0)", "black (==23.3.0)", "bracex (==2.3.post1)", "certifi (==2023.5.7)", "cffi (==1.15.1)", "charset-normalizer (==3.1.0)", "click (==8.1.3)", "cryptography (==41.0.1)", "filelock (==3.12.2)", "idna (==3.4)", "importlib-resources (==5.0.7)", "jinja2 (==3.1.2)", "jsonschema (==4.17.3)", "markdown-it-py (==3.0.0)", "markupsafe (==2.1.3)", "mdurl (==0.1.2)", "mypy-extensions (==1.0.0)", "packaging (==23.1)", "pathspec (==0.11.1)", "platformdirs (==3.7.0)", "pycparser (==2.21)", "pygments (==2.15.1)", "pyrsistent (==0.19.3)", "pyyaml (==6.0)", "requests (==2.31.0)", "rich (==13.4.2)", "ruamel-yaml (==0.17.32)", "subprocess-tee (==0.4.1)", "tomli (==2.0.1)", "typing-extensions (==4.6.3)", "urllib3 (==2.0.3)", "wcmatch (==8.4.1)", "yamllint (==1.32.0)"]
+test = ["black", "coverage-enable-subprocess", "coverage[toml] (>=6.4.4)", "jmespath", "mypy", "netaddr", "psutil", "pylint", "pytest (>=7.2.2)", "pytest-mock", "pytest-plus (>=0.2)", "pytest-xdist (>=2.1.0)", "ruamel-yaml-clib", "ruamel.yaml (>=0.17.31,<0.18)", "spdx-tools (>=0.7.1)", "types-jsonschema", "types-pyyaml"]
+
+[[package]]
+name = "ansible-pygments"
+version = "0.1.1"
+description = "Tools for building the Ansible Distribution"
+optional = false
+python-versions = ">=3.6.0,<4.0.0"
+files = [
+ {file = "ansible-pygments-0.1.1.tar.gz", hash = "sha256:0d0a23cc562f94f4b464f931059ad1688635aac9642962bc68ae3acdb6efbcd0"},
+ {file = "ansible_pygments-0.1.1-py3-none-any.whl", hash = "sha256:85aa7412a46c83efcfe460c8016da289600c171d2edfa0f474e0dc30a398b002"},
+]
+
+[package.dependencies]
+pygments = ">=2.4.0"
+
+[[package]]
+name = "antsibull-changelog"
+version = "0.22.0"
+description = "Changelog tool for Ansible-base and Ansible collections"
+optional = false
+python-versions = ">=3.9.0"
+files = [
+ {file = "antsibull_changelog-0.22.0-py3-none-any.whl", hash = "sha256:dfc6d6c9ca651b55af0e435e95c57faa33be4ff538d9f4446c6ff1a866d86f9e"},
+ {file = "antsibull_changelog-0.22.0.tar.gz", hash = "sha256:2e6356ab32bfef7efe3c047b3c25e4166532a094f545448be1b708ab3a5c6be3"},
+]
+
+[package.dependencies]
+docutils = "*"
+packaging = "*"
+pyyaml = "*"
+rstcheck = ">=3.0.0,<7.0.0"
+semantic-version = "*"
+
+[package.extras]
+codeqa = ["flake8 (>=3.8.0)", "pylint", "reuse"]
+coverage = ["coverage[toml]"]
+dev = ["antsibull-changelog[codeqa]", "antsibull-changelog[coverage]", "antsibull-changelog[formatters]", "antsibull-changelog[test]", "antsibull-changelog[typing]", "nox"]
+formatters = ["black", "isort"]
+test = ["pytest", "pytest-cov", "pytest-error-for-skips"]
+toml = ["tomli"]
+typing = ["mypy", "pyre-check (>=0.9.17)", "types-docutils", "types-pyyaml", "types-toml"]
+
+[[package]]
+name = "antsibull-core"
+version = "2.0.0"
+description = "Tools for building the Ansible Distribution"
+optional = false
+python-versions = ">=3.9"
+files = [
+ {file = "antsibull_core-2.0.0-py3-none-any.whl", hash = "sha256:ed4931ade19bb314079659c72d1ff97b7a26fd452141b4fccc722edc943f2b00"},
+ {file = "antsibull_core-2.0.0.tar.gz", hash = "sha256:a9421d01748ac8b0186eb94535425ae614f8dfc2f48a52d8e8da97cde7cbb010"},
+]
+
+[package.dependencies]
+aiofiles = "*"
+aiohttp = ">=3.0.0"
+build = "*"
+packaging = ">=20.0"
+perky = "*"
+pydantic = ">=1.0.0,<2.0.0"
+pyyaml = "*"
+semantic-version = "*"
+sh = ">=1.0.0,<2.0.0"
+twiggy = ">=0.5.0"
+
+[package.extras]
+codeqa = ["antsibull-changelog", "flake8 (>=6.0.0)", "pylint (>=2.15.7)", "reuse"]
+coverage = ["coverage[toml]"]
+dev = ["antsibull-core[codeqa]", "antsibull-core[coverage]", "antsibull-core[formatters]", "antsibull-core[test]", "antsibull-core[typing]", "nox"]
+formatters = ["black", "isort"]
+test = ["asynctest", "cryptography", "pytest", "pytest-asyncio (>=0.20)", "pytest-cov", "pytest-error-for-skips"]
+typing = ["mypy", "pyre-check (>=0.9.17)", "types-aiofiles", "types-pyyaml"]
+
+[[package]]
+name = "antsibull-docs"
+version = "2.3.1"
+description = "Tools for building Ansible documentation"
+optional = false
+python-versions = ">=3.9"
+files = [
+ {file = "antsibull_docs-2.3.1-py3-none-any.whl", hash = "sha256:d37b102a2bf4d8fa821f85c6502c0c22024f65d61b66004d323c2b359534d58a"},
+ {file = "antsibull_docs-2.3.1.tar.gz", hash = "sha256:02bf622bcb4bb95611d5b78ffecc0a30da5aa1e1d2b7c3737f3497e288f20326"},
+]
+
+[package.dependencies]
+aiohttp = ">=3.0.0"
+ansible-pygments = "*"
+antsibull-core = ">=2.0.0,<3.0.0"
+antsibull-docs-parser = ">=1.0.0,<2.0.0"
+asyncio-pool = "*"
+docutils = "*"
+jinja2 = ">=3.0"
+packaging = "*"
+pydantic = ">=1.0.0,<2.0.0"
+pyyaml = "*"
+rstcheck = ">=3.0.0,<7.0.0"
+semantic-version = "*"
+sphinx = "*"
+twiggy = "*"
+
+[package.extras]
+codeqa = ["antsibull-changelog", "flake8 (>=3.8.0)", "pylint (>=2.17.2)", "reuse"]
+coverage = ["coverage[toml]"]
+dev = ["antsibull-docs[codeqa]", "antsibull-docs[formatters]", "antsibull-docs[test]", "antsibull-docs[typing]", "nox"]
+formatters = ["black", "isort"]
+test = ["ansible-core (>=2.14.0)", "asynctest", "cryptography", "pytest", "pytest-asyncio (>=0.12)", "pytest-cov", "pytest-error-for-skips"]
+typing = ["mypy", "pyre-check (>=0.9.17)", "types-aiofiles", "types-docutils", "types-pyyaml"]
+
+[[package]]
+name = "antsibull-docs-parser"
+version = "1.0.0"
+description = "Python library for processing Ansible documentation markup"
+optional = false
+python-versions = ">=3.6.1"
+files = [
+ {file = "antsibull_docs_parser-1.0.0-py3-none-any.whl", hash = "sha256:397978554bfd58709f2aaa81946d1e31c71d674c411a8a9513d7181843eb1f63"},
+ {file = "antsibull_docs_parser-1.0.0.tar.gz", hash = "sha256:7711dd2b30cac3e95c80a83810b99a0aad3297d12004c6fa9c57be9cff1c883a"},
+]
+
+[package.extras]
+codeqa = ["antsibull-changelog", "flake8", "pylint", "reuse"]
+coverage = ["coverage[toml]"]
+dev = ["antsibull-docs-parser[codeqa]", "antsibull-docs-parser[coverage]", "antsibull-docs-parser[formatters]", "antsibull-docs-parser[test]", "antsibull-docs-parser[typing]", "nox"]
+formatters = ["black", "isort"]
+test = ["pytest", "pytest-cov", "pytest-error-for-skips", "pyyaml"]
+typing = ["mypy", "pyre-check (>=0.9.17)"]
+
+[[package]]
+name = "astroid"
+version = "2.15.6"
+description = "An abstract syntax tree for Python with inference support."
+optional = false
+python-versions = ">=3.7.2"
+files = [
+ {file = "astroid-2.15.6-py3-none-any.whl", hash = "sha256:389656ca57b6108f939cf5d2f9a2a825a3be50ba9d589670f393236e0a03b91c"},
+ {file = "astroid-2.15.6.tar.gz", hash = "sha256:903f024859b7c7687d7a7f3a3f73b17301f8e42dfd9cc9df9d4418172d3e2dbd"},
+]
+
+[package.dependencies]
+lazy-object-proxy = ">=1.4.0"
+typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""}
+wrapt = {version = ">=1.11,<2", markers = "python_version < \"3.11\""}
+
+[[package]]
+name = "async-timeout"
+version = "4.0.3"
+description = "Timeout context manager for asyncio programs"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"},
+ {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"},
+]
+
+[[package]]
+name = "asyncio-pool"
+version = "0.6.0"
+description = "Pool of asyncio coroutines with familiar interface"
+optional = false
+python-versions = ">=3.5"
+files = [
+ {file = "asyncio_pool-0.6.0-py3-none-any.whl", hash = "sha256:bf4417be93c2776262d93decabbbd633579f7610947fb73d80857823689e1455"},
+ {file = "asyncio_pool-0.6.0.tar.gz", hash = "sha256:d7ba5e299ba58d4fb0cebbc722989d1f880df4c4b19e37055075b3dabc062c5b"},
+]
+
+[[package]]
+name = "attrs"
+version = "23.1.0"
+description = "Classes Without Boilerplate"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"},
+ {file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"},
+]
+
+[package.extras]
+cov = ["attrs[tests]", "coverage[toml] (>=5.3)"]
+dev = ["attrs[docs,tests]", "pre-commit"]
+docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"]
+tests = ["attrs[tests-no-zope]", "zope-interface"]
+tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
+
+[[package]]
+name = "babel"
+version = "2.12.1"
+description = "Internationalization utilities"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "Babel-2.12.1-py3-none-any.whl", hash = "sha256:b4246fb7677d3b98f501a39d43396d3cafdc8eadb045f4a31be01863f655c610"},
+ {file = "Babel-2.12.1.tar.gz", hash = "sha256:cc2d99999cd01d44420ae725a21c9e3711b3aadc7976d6147f622d8581963455"},
+]
+
+[[package]]
+name = "black"
+version = "23.7.0"
+description = "The uncompromising code formatter."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "black-23.7.0-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:5c4bc552ab52f6c1c506ccae05681fab58c3f72d59ae6e6639e8885e94fe2587"},
+ {file = "black-23.7.0-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:552513d5cd5694590d7ef6f46e1767a4df9af168d449ff767b13b084c020e63f"},
+ {file = "black-23.7.0-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:86cee259349b4448adb4ef9b204bb4467aae74a386bce85d56ba4f5dc0da27be"},
+ {file = "black-23.7.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:501387a9edcb75d7ae8a4412bb8749900386eaef258f1aefab18adddea1936bc"},
+ {file = "black-23.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:fb074d8b213749fa1d077d630db0d5f8cc3b2ae63587ad4116e8a436e9bbe995"},
+ {file = "black-23.7.0-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:b5b0ee6d96b345a8b420100b7d71ebfdd19fab5e8301aff48ec270042cd40ac2"},
+ {file = "black-23.7.0-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:893695a76b140881531062d48476ebe4a48f5d1e9388177e175d76234ca247cd"},
+ {file = "black-23.7.0-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:c333286dc3ddca6fdff74670b911cccedacb4ef0a60b34e491b8a67c833b343a"},
+ {file = "black-23.7.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:831d8f54c3a8c8cf55f64d0422ee875eecac26f5f649fb6c1df65316b67c8926"},
+ {file = "black-23.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:7f3bf2dec7d541b4619b8ce526bda74a6b0bffc480a163fed32eb8b3c9aed8ad"},
+ {file = "black-23.7.0-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:f9062af71c59c004cd519e2fb8f5d25d39e46d3af011b41ab43b9c74e27e236f"},
+ {file = "black-23.7.0-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:01ede61aac8c154b55f35301fac3e730baf0c9cf8120f65a9cd61a81cfb4a0c3"},
+ {file = "black-23.7.0-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:327a8c2550ddc573b51e2c352adb88143464bb9d92c10416feb86b0f5aee5ff6"},
+ {file = "black-23.7.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d1c6022b86f83b632d06f2b02774134def5d4d4f1dac8bef16d90cda18ba28a"},
+ {file = "black-23.7.0-cp38-cp38-win_amd64.whl", hash = "sha256:27eb7a0c71604d5de083757fbdb245b1a4fae60e9596514c6ec497eb63f95320"},
+ {file = "black-23.7.0-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:8417dbd2f57b5701492cd46edcecc4f9208dc75529bcf76c514864e48da867d9"},
+ {file = "black-23.7.0-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:47e56d83aad53ca140da0af87678fb38e44fd6bc0af71eebab2d1f59b1acf1d3"},
+ {file = "black-23.7.0-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:25cc308838fe71f7065df53aedd20327969d05671bac95b38fdf37ebe70ac087"},
+ {file = "black-23.7.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:642496b675095d423f9b8448243336f8ec71c9d4d57ec17bf795b67f08132a91"},
+ {file = "black-23.7.0-cp39-cp39-win_amd64.whl", hash = "sha256:ad0014efc7acf0bd745792bd0d8857413652979200ab924fbf239062adc12491"},
+ {file = "black-23.7.0-py3-none-any.whl", hash = "sha256:9fd59d418c60c0348505f2ddf9609c1e1de8e7493eab96198fc89d9f865e7a96"},
+ {file = "black-23.7.0.tar.gz", hash = "sha256:022a582720b0d9480ed82576c920a8c1dde97cc38ff11d8d8859b3bd6ca9eedb"},
+]
+
+[package.dependencies]
+click = ">=8.0.0"
+mypy-extensions = ">=0.4.3"
+packaging = ">=22.0"
+pathspec = ">=0.9.0"
+platformdirs = ">=2"
+tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
+typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""}
+
+[package.extras]
+colorama = ["colorama (>=0.4.3)"]
+d = ["aiohttp (>=3.7.4)"]
+jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
+uvloop = ["uvloop (>=0.15.2)"]
+
+[[package]]
+name = "boto3"
+version = "1.28.24"
+description = "The AWS SDK for Python"
+optional = false
+python-versions = ">= 3.7"
+files = [
+ {file = "boto3-1.28.24-py3-none-any.whl", hash = "sha256:0300ca6ec8bc136eb316b32cc1e30c66b85bc497f5a5fe42e095ae4280569708"},
+ {file = "boto3-1.28.24.tar.gz", hash = "sha256:9d1b4713c888e53a218648ad71522bee9bec9d83f2999fff2494675af810b632"},
+]
+
+[package.dependencies]
+botocore = ">=1.31.24,<1.32.0"
+jmespath = ">=0.7.1,<2.0.0"
+s3transfer = ">=0.6.0,<0.7.0"
+
+[package.extras]
+crt = ["botocore[crt] (>=1.21.0,<2.0a0)"]
+
+[[package]]
+name = "botocore"
+version = "1.31.24"
+description = "Low-level, data-driven core of boto 3."
+optional = false
+python-versions = ">= 3.7"
+files = [
+ {file = "botocore-1.31.24-py3-none-any.whl", hash = "sha256:8c7ba9b09e9104e2d473214e1ffcf84b77e04cf6f5f2344942c1eed9e299f947"},
+ {file = "botocore-1.31.24.tar.gz", hash = "sha256:2d8f412c67f9285219f52d5dbbb6ef0dfa9f606da29cbdd41b6d6474bcc4bbd4"},
+]
+
+[package.dependencies]
+jmespath = ">=0.7.1,<2.0.0"
+python-dateutil = ">=2.1,<3.0.0"
+urllib3 = ">=1.25.4,<1.27"
+
+[package.extras]
+crt = ["awscrt (==0.16.26)"]
+
+[[package]]
+name = "bracex"
+version = "2.3.post1"
+description = "Bash style brace expander."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "bracex-2.3.post1-py3-none-any.whl", hash = "sha256:351b7f20d56fb9ea91f9b9e9e7664db466eb234188c175fd943f8f755c807e73"},
+ {file = "bracex-2.3.post1.tar.gz", hash = "sha256:e7b23fc8b2cd06d3dec0692baabecb249dda94e06a617901ff03a6c56fd71693"},
+]
+
+[[package]]
+name = "build"
+version = "0.10.0"
+description = "A simple, correct Python build frontend"
+optional = false
+python-versions = ">= 3.7"
+files = [
+ {file = "build-0.10.0-py3-none-any.whl", hash = "sha256:af266720050a66c893a6096a2f410989eeac74ff9a68ba194b3f6473e8e26171"},
+ {file = "build-0.10.0.tar.gz", hash = "sha256:d5b71264afdb5951d6704482aac78de887c80691c52b88a9ad195983ca2c9269"},
+]
+
+[package.dependencies]
+colorama = {version = "*", markers = "os_name == \"nt\""}
+packaging = ">=19.0"
+pyproject_hooks = "*"
+tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
+
+[package.extras]
+docs = ["furo (>=2021.08.31)", "sphinx (>=4.0,<5.0)", "sphinx-argparse-cli (>=1.5)", "sphinx-autodoc-typehints (>=1.10)"]
+test = ["filelock (>=3)", "pytest (>=6.2.4)", "pytest-cov (>=2.12)", "pytest-mock (>=2)", "pytest-rerunfailures (>=9.1)", "pytest-xdist (>=1.34)", "setuptools (>=42.0.0)", "setuptools (>=56.0.0)", "toml (>=0.10.0)", "wheel (>=0.36.0)"]
+typing = ["importlib-metadata (>=5.1)", "mypy (==0.991)", "tomli", "typing-extensions (>=3.7.4.3)"]
+virtualenv = ["virtualenv (>=20.0.35)"]
+
+[[package]]
+name = "certifi"
+version = "2023.7.22"
+description = "Python package for providing Mozilla's CA Bundle."
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "certifi-2023.7.22-py3-none-any.whl", hash = "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"},
+ {file = "certifi-2023.7.22.tar.gz", hash = "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082"},
+]
+
+[[package]]
+name = "cffi"
+version = "1.15.1"
+description = "Foreign Function Interface for Python calling C code."
+optional = false
+python-versions = "*"
+files = [
+ {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"},
+ {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"},
+ {file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"},
+ {file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"},
+ {file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"},
+ {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"},
+ {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"},
+ {file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"},
+ {file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"},
+ {file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"},
+ {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"},
+ {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"},
+ {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"},
+ {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"},
+ {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"},
+ {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"},
+ {file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"},
+ {file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"},
+ {file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"},
+ {file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"},
+ {file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"},
+ {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"},
+ {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"},
+ {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"},
+ {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"},
+ {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"},
+ {file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"},
+ {file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"},
+ {file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"},
+ {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"},
+ {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"},
+ {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"},
+ {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"},
+ {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"},
+ {file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"},
+ {file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"},
+ {file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"},
+ {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"},
+ {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"},
+ {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"},
+ {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"},
+ {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"},
+ {file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"},
+ {file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"},
+ {file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"},
+ {file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"},
+ {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"},
+ {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"},
+ {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"},
+ {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"},
+ {file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"},
+ {file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"},
+ {file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"},
+ {file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"},
+ {file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"},
+ {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"},
+ {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"},
+ {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"},
+ {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"},
+ {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"},
+ {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"},
+ {file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"},
+ {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"},
+ {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"},
+]
+
+[package.dependencies]
+pycparser = "*"
+
+[[package]]
+name = "cfgv"
+version = "3.3.1"
+description = "Validate configuration and produce human readable error messages."
+optional = false
+python-versions = ">=3.6.1"
+files = [
+ {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"},
+ {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"},
+]
+
+[[package]]
+name = "charset-normalizer"
+version = "3.2.0"
+description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
+optional = false
+python-versions = ">=3.7.0"
+files = [
+ {file = "charset-normalizer-3.2.0.tar.gz", hash = "sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-win32.whl", hash = "sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96"},
+ {file = "charset_normalizer-3.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-win32.whl", hash = "sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1"},
+ {file = "charset_normalizer-3.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489"},
+ {file = "charset_normalizer-3.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346"},
+ {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982"},
+ {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c"},
+ {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4"},
+ {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449"},
+ {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3"},
+ {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a"},
+ {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7"},
+ {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd"},
+ {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3"},
+ {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592"},
+ {file = "charset_normalizer-3.2.0-cp37-cp37m-win32.whl", hash = "sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1"},
+ {file = "charset_normalizer-3.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-win32.whl", hash = "sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706"},
+ {file = "charset_normalizer-3.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-win32.whl", hash = "sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9"},
+ {file = "charset_normalizer-3.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80"},
+ {file = "charset_normalizer-3.2.0-py3-none-any.whl", hash = "sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6"},
+]
+
+[[package]]
+name = "click"
+version = "8.1.6"
+description = "Composable command line interface toolkit"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "click-8.1.6-py3-none-any.whl", hash = "sha256:fa244bb30b3b5ee2cae3da8f55c9e5e0c0e86093306301fb418eb9dc40fbded5"},
+ {file = "click-8.1.6.tar.gz", hash = "sha256:48ee849951919527a045bfe3bf7baa8a959c423134e1a5b98c05c20ba75a1cbd"},
+]
+
+[package.dependencies]
+colorama = {version = "*", markers = "platform_system == \"Windows\""}
+
+[[package]]
+name = "colorama"
+version = "0.4.6"
+description = "Cross-platform colored terminal text."
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
+files = [
+ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
+ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
+]
+
+[[package]]
+name = "commonmark"
+version = "0.9.1"
+description = "Python parser for the CommonMark Markdown spec"
+optional = false
+python-versions = "*"
+files = [
+ {file = "commonmark-0.9.1-py2.py3-none-any.whl", hash = "sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9"},
+ {file = "commonmark-0.9.1.tar.gz", hash = "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60"},
+]
+
+[package.extras]
+test = ["flake8 (==3.7.8)", "hypothesis (==3.55.3)"]
+
+[[package]]
+name = "cryptography"
+version = "41.0.6"
+description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "cryptography-41.0.6-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:0f27acb55a4e77b9be8d550d762b0513ef3fc658cd3eb15110ebbcbd626db12c"},
+ {file = "cryptography-41.0.6-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:ae236bb8760c1e55b7a39b6d4d32d2279bc6c7c8500b7d5a13b6fb9fc97be35b"},
+ {file = "cryptography-41.0.6-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afda76d84b053923c27ede5edc1ed7d53e3c9f475ebaf63c68e69f1403c405a8"},
+ {file = "cryptography-41.0.6-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da46e2b5df770070412c46f87bac0849b8d685c5f2679771de277a422c7d0b86"},
+ {file = "cryptography-41.0.6-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ff369dd19e8fe0528b02e8df9f2aeb2479f89b1270d90f96a63500afe9af5cae"},
+ {file = "cryptography-41.0.6-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:b648fe2a45e426aaee684ddca2632f62ec4613ef362f4d681a9a6283d10e079d"},
+ {file = "cryptography-41.0.6-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:5daeb18e7886a358064a68dbcaf441c036cbdb7da52ae744e7b9207b04d3908c"},
+ {file = "cryptography-41.0.6-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:068bc551698c234742c40049e46840843f3d98ad7ce265fd2bd4ec0d11306596"},
+ {file = "cryptography-41.0.6-cp37-abi3-win32.whl", hash = "sha256:2132d5865eea673fe6712c2ed5fb4fa49dba10768bb4cc798345748380ee3660"},
+ {file = "cryptography-41.0.6-cp37-abi3-win_amd64.whl", hash = "sha256:48783b7e2bef51224020efb61b42704207dde583d7e371ef8fc2a5fb6c0aabc7"},
+ {file = "cryptography-41.0.6-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:8efb2af8d4ba9dbc9c9dd8f04d19a7abb5b49eab1f3694e7b5a16a5fc2856f5c"},
+ {file = "cryptography-41.0.6-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c5a550dc7a3b50b116323e3d376241829fd326ac47bc195e04eb33a8170902a9"},
+ {file = "cryptography-41.0.6-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:85abd057699b98fce40b41737afb234fef05c67e116f6f3650782c10862c43da"},
+ {file = "cryptography-41.0.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f39812f70fc5c71a15aa3c97b2bbe213c3f2a460b79bd21c40d033bb34a9bf36"},
+ {file = "cryptography-41.0.6-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:742ae5e9a2310e9dade7932f9576606836ed174da3c7d26bc3d3ab4bd49b9f65"},
+ {file = "cryptography-41.0.6-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:35f3f288e83c3f6f10752467c48919a7a94b7d88cc00b0668372a0d2ad4f8ead"},
+ {file = "cryptography-41.0.6-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4d03186af98b1c01a4eda396b137f29e4e3fb0173e30f885e27acec8823c1b09"},
+ {file = "cryptography-41.0.6-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:b27a7fd4229abef715e064269d98a7e2909ebf92eb6912a9603c7e14c181928c"},
+ {file = "cryptography-41.0.6-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:398ae1fc711b5eb78e977daa3cbf47cec20f2c08c5da129b7a296055fbb22aed"},
+ {file = "cryptography-41.0.6-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:7e00fb556bda398b99b0da289ce7053639d33b572847181d6483ad89835115f6"},
+ {file = "cryptography-41.0.6-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:60e746b11b937911dc70d164060d28d273e31853bb359e2b2033c9e93e6f3c43"},
+ {file = "cryptography-41.0.6-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3288acccef021e3c3c10d58933f44e8602cf04dba96d9796d70d537bb2f4bbc4"},
+ {file = "cryptography-41.0.6.tar.gz", hash = "sha256:422e3e31d63743855e43e5a6fcc8b4acab860f560f9321b0ee6269cc7ed70cc3"},
+]
+
+[package.dependencies]
+cffi = ">=1.12"
+
+[package.extras]
+docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"]
+docstest = ["pyenchant (>=1.6.11)", "sphinxcontrib-spelling (>=4.0.1)", "twine (>=1.12.0)"]
+nox = ["nox"]
+pep8test = ["black", "check-sdist", "mypy", "ruff"]
+sdist = ["build"]
+ssh = ["bcrypt (>=3.1.5)"]
+test = ["pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"]
+test-randomorder = ["pytest-randomly"]
+
+[[package]]
+name = "dill"
+version = "0.3.7"
+description = "serialize all of Python"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "dill-0.3.7-py3-none-any.whl", hash = "sha256:76b122c08ef4ce2eedcd4d1abd8e641114bfc6c2867f49f3c41facf65bf19f5e"},
+ {file = "dill-0.3.7.tar.gz", hash = "sha256:cc1c8b182eb3013e24bd475ff2e9295af86c1a38eb1aff128dac8962a9ce3c03"},
+]
+
+[package.extras]
+graph = ["objgraph (>=1.7.2)"]
+
+[[package]]
+name = "distlib"
+version = "0.3.7"
+description = "Distribution utilities"
+optional = false
+python-versions = "*"
+files = [
+ {file = "distlib-0.3.7-py2.py3-none-any.whl", hash = "sha256:2e24928bc811348f0feb63014e97aaae3037f2cf48712d51ae61df7fd6075057"},
+ {file = "distlib-0.3.7.tar.gz", hash = "sha256:9dafe54b34a028eafd95039d5e5d4851a13734540f1331060d31c9916e7147a8"},
+]
+
+[[package]]
+name = "docutils"
+version = "0.19"
+description = "Docutils -- Python Documentation Utilities"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "docutils-0.19-py3-none-any.whl", hash = "sha256:5e1de4d849fee02c63b040a4a3fd567f4ab104defd8a5511fbbc24a8a017efbc"},
+ {file = "docutils-0.19.tar.gz", hash = "sha256:33995a6753c30b7f577febfc2c50411fec6aac7f7ffeb7c4cfe5991072dcf9e6"},
+]
+
+[[package]]
+name = "exceptiongroup"
+version = "1.1.2"
+description = "Backport of PEP 654 (exception groups)"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "exceptiongroup-1.1.2-py3-none-any.whl", hash = "sha256:e346e69d186172ca7cf029c8c1d16235aa0e04035e5750b4b95039e65204328f"},
+ {file = "exceptiongroup-1.1.2.tar.gz", hash = "sha256:12c3e887d6485d16943a309616de20ae5582633e0a2eda17f4e10fd61c1e8af5"},
+]
+
+[package.extras]
+test = ["pytest (>=6)"]
+
+[[package]]
+name = "filelock"
+version = "3.12.2"
+description = "A platform independent file lock."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "filelock-3.12.2-py3-none-any.whl", hash = "sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec"},
+ {file = "filelock-3.12.2.tar.gz", hash = "sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81"},
+]
+
+[package.extras]
+docs = ["furo (>=2023.5.20)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"]
+testing = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"]
+
+[[package]]
+name = "frozenlist"
+version = "1.4.0"
+description = "A list-like structure which implements collections.abc.MutableSequence"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "frozenlist-1.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:764226ceef3125e53ea2cb275000e309c0aa5464d43bd72abd661e27fffc26ab"},
+ {file = "frozenlist-1.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d6484756b12f40003c6128bfcc3fa9f0d49a687e171186c2d85ec82e3758c559"},
+ {file = "frozenlist-1.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9ac08e601308e41eb533f232dbf6b7e4cea762f9f84f6357136eed926c15d12c"},
+ {file = "frozenlist-1.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d081f13b095d74b67d550de04df1c756831f3b83dc9881c38985834387487f1b"},
+ {file = "frozenlist-1.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:71932b597f9895f011f47f17d6428252fc728ba2ae6024e13c3398a087c2cdea"},
+ {file = "frozenlist-1.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:981b9ab5a0a3178ff413bca62526bb784249421c24ad7381e39d67981be2c326"},
+ {file = "frozenlist-1.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e41f3de4df3e80de75845d3e743b3f1c4c8613c3997a912dbf0229fc61a8b963"},
+ {file = "frozenlist-1.4.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6918d49b1f90821e93069682c06ffde41829c346c66b721e65a5c62b4bab0300"},
+ {file = "frozenlist-1.4.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0e5c8764c7829343d919cc2dfc587a8db01c4f70a4ebbc49abde5d4b158b007b"},
+ {file = "frozenlist-1.4.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8d0edd6b1c7fb94922bf569c9b092ee187a83f03fb1a63076e7774b60f9481a8"},
+ {file = "frozenlist-1.4.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:e29cda763f752553fa14c68fb2195150bfab22b352572cb36c43c47bedba70eb"},
+ {file = "frozenlist-1.4.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:0c7c1b47859ee2cac3846fde1c1dc0f15da6cec5a0e5c72d101e0f83dcb67ff9"},
+ {file = "frozenlist-1.4.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:901289d524fdd571be1c7be054f48b1f88ce8dddcbdf1ec698b27d4b8b9e5d62"},
+ {file = "frozenlist-1.4.0-cp310-cp310-win32.whl", hash = "sha256:1a0848b52815006ea6596c395f87449f693dc419061cc21e970f139d466dc0a0"},
+ {file = "frozenlist-1.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:b206646d176a007466358aa21d85cd8600a415c67c9bd15403336c331a10d956"},
+ {file = "frozenlist-1.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:de343e75f40e972bae1ef6090267f8260c1446a1695e77096db6cfa25e759a95"},
+ {file = "frozenlist-1.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ad2a9eb6d9839ae241701d0918f54c51365a51407fd80f6b8289e2dfca977cc3"},
+ {file = "frozenlist-1.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bd7bd3b3830247580de99c99ea2a01416dfc3c34471ca1298bccabf86d0ff4dc"},
+ {file = "frozenlist-1.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bdf1847068c362f16b353163391210269e4f0569a3c166bc6a9f74ccbfc7e839"},
+ {file = "frozenlist-1.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38461d02d66de17455072c9ba981d35f1d2a73024bee7790ac2f9e361ef1cd0c"},
+ {file = "frozenlist-1.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5a32087d720c608f42caed0ef36d2b3ea61a9d09ee59a5142d6070da9041b8f"},
+ {file = "frozenlist-1.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dd65632acaf0d47608190a71bfe46b209719bf2beb59507db08ccdbe712f969b"},
+ {file = "frozenlist-1.4.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:261b9f5d17cac914531331ff1b1d452125bf5daa05faf73b71d935485b0c510b"},
+ {file = "frozenlist-1.4.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b89ac9768b82205936771f8d2eb3ce88503b1556324c9f903e7156669f521472"},
+ {file = "frozenlist-1.4.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:008eb8b31b3ea6896da16c38c1b136cb9fec9e249e77f6211d479db79a4eaf01"},
+ {file = "frozenlist-1.4.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e74b0506fa5aa5598ac6a975a12aa8928cbb58e1f5ac8360792ef15de1aa848f"},
+ {file = "frozenlist-1.4.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:490132667476f6781b4c9458298b0c1cddf237488abd228b0b3650e5ecba7467"},
+ {file = "frozenlist-1.4.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:76d4711f6f6d08551a7e9ef28c722f4a50dd0fc204c56b4bcd95c6cc05ce6fbb"},
+ {file = "frozenlist-1.4.0-cp311-cp311-win32.whl", hash = "sha256:a02eb8ab2b8f200179b5f62b59757685ae9987996ae549ccf30f983f40602431"},
+ {file = "frozenlist-1.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:515e1abc578dd3b275d6a5114030b1330ba044ffba03f94091842852f806f1c1"},
+ {file = "frozenlist-1.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:f0ed05f5079c708fe74bf9027e95125334b6978bf07fd5ab923e9e55e5fbb9d3"},
+ {file = "frozenlist-1.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ca265542ca427bf97aed183c1676e2a9c66942e822b14dc6e5f42e038f92a503"},
+ {file = "frozenlist-1.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:491e014f5c43656da08958808588cc6c016847b4360e327a62cb308c791bd2d9"},
+ {file = "frozenlist-1.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:17ae5cd0f333f94f2e03aaf140bb762c64783935cc764ff9c82dff626089bebf"},
+ {file = "frozenlist-1.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e78fb68cf9c1a6aa4a9a12e960a5c9dfbdb89b3695197aa7064705662515de2"},
+ {file = "frozenlist-1.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5655a942f5f5d2c9ed93d72148226d75369b4f6952680211972a33e59b1dfdc"},
+ {file = "frozenlist-1.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c11b0746f5d946fecf750428a95f3e9ebe792c1ee3b1e96eeba145dc631a9672"},
+ {file = "frozenlist-1.4.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e66d2a64d44d50d2543405fb183a21f76b3b5fd16f130f5c99187c3fb4e64919"},
+ {file = "frozenlist-1.4.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:88f7bc0fcca81f985f78dd0fa68d2c75abf8272b1f5c323ea4a01a4d7a614efc"},
+ {file = "frozenlist-1.4.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5833593c25ac59ede40ed4de6d67eb42928cca97f26feea219f21d0ed0959b79"},
+ {file = "frozenlist-1.4.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:fec520865f42e5c7f050c2a79038897b1c7d1595e907a9e08e3353293ffc948e"},
+ {file = "frozenlist-1.4.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:b826d97e4276750beca7c8f0f1a4938892697a6bcd8ec8217b3312dad6982781"},
+ {file = "frozenlist-1.4.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ceb6ec0a10c65540421e20ebd29083c50e6d1143278746a4ef6bcf6153171eb8"},
+ {file = "frozenlist-1.4.0-cp38-cp38-win32.whl", hash = "sha256:2b8bcf994563466db019fab287ff390fffbfdb4f905fc77bc1c1d604b1c689cc"},
+ {file = "frozenlist-1.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:a6c8097e01886188e5be3e6b14e94ab365f384736aa1fca6a0b9e35bd4a30bc7"},
+ {file = "frozenlist-1.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6c38721585f285203e4b4132a352eb3daa19121a035f3182e08e437cface44bf"},
+ {file = "frozenlist-1.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a0c6da9aee33ff0b1a451e867da0c1f47408112b3391dd43133838339e410963"},
+ {file = "frozenlist-1.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:93ea75c050c5bb3d98016b4ba2497851eadf0ac154d88a67d7a6816206f6fa7f"},
+ {file = "frozenlist-1.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f61e2dc5ad442c52b4887f1fdc112f97caeff4d9e6ebe78879364ac59f1663e1"},
+ {file = "frozenlist-1.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa384489fefeb62321b238e64c07ef48398fe80f9e1e6afeff22e140e0850eef"},
+ {file = "frozenlist-1.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:10ff5faaa22786315ef57097a279b833ecab1a0bfb07d604c9cbb1c4cdc2ed87"},
+ {file = "frozenlist-1.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:007df07a6e3eb3e33e9a1fe6a9db7af152bbd8a185f9aaa6ece10a3529e3e1c6"},
+ {file = "frozenlist-1.4.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f4f399d28478d1f604c2ff9119907af9726aed73680e5ed1ca634d377abb087"},
+ {file = "frozenlist-1.4.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c5374b80521d3d3f2ec5572e05adc94601985cc526fb276d0c8574a6d749f1b3"},
+ {file = "frozenlist-1.4.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:ce31ae3e19f3c902de379cf1323d90c649425b86de7bbdf82871b8a2a0615f3d"},
+ {file = "frozenlist-1.4.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7211ef110a9194b6042449431e08c4d80c0481e5891e58d429df5899690511c2"},
+ {file = "frozenlist-1.4.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:556de4430ce324c836789fa4560ca62d1591d2538b8ceb0b4f68fb7b2384a27a"},
+ {file = "frozenlist-1.4.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7645a8e814a3ee34a89c4a372011dcd817964ce8cb273c8ed6119d706e9613e3"},
+ {file = "frozenlist-1.4.0-cp39-cp39-win32.whl", hash = "sha256:19488c57c12d4e8095a922f328df3f179c820c212940a498623ed39160bc3c2f"},
+ {file = "frozenlist-1.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:6221d84d463fb110bdd7619b69cb43878a11d51cbb9394ae3105d082d5199167"},
+ {file = "frozenlist-1.4.0.tar.gz", hash = "sha256:09163bdf0b2907454042edb19f887c6d33806adc71fbd54afc14908bfdc22251"},
+]
+
+[[package]]
+name = "identify"
+version = "2.5.26"
+description = "File identification library for Python"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "identify-2.5.26-py2.py3-none-any.whl", hash = "sha256:c22a8ead0d4ca11f1edd6c9418c3220669b3b7533ada0a0ffa6cc0ef85cf9b54"},
+ {file = "identify-2.5.26.tar.gz", hash = "sha256:7243800bce2f58404ed41b7c002e53d4d22bcf3ae1b7900c2d7aefd95394bf7f"},
+]
+
+[package.extras]
+license = ["ukkonen"]
+
+[[package]]
+name = "idna"
+version = "3.4"
+description = "Internationalized Domain Names in Applications (IDNA)"
+optional = false
+python-versions = ">=3.5"
+files = [
+ {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"},
+ {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"},
+]
+
+[[package]]
+name = "imagesize"
+version = "1.4.1"
+description = "Getting image size from png/jpeg/jpeg2000/gif file"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+files = [
+ {file = "imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b"},
+ {file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"},
+]
+
+[[package]]
+name = "importlib-metadata"
+version = "6.8.0"
+description = "Read metadata from Python packages"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "importlib_metadata-6.8.0-py3-none-any.whl", hash = "sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb"},
+ {file = "importlib_metadata-6.8.0.tar.gz", hash = "sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743"},
+]
+
+[package.dependencies]
+zipp = ">=0.5"
+
+[package.extras]
+docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
+perf = ["ipython"]
+testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"]
+
+[[package]]
+name = "importlib-resources"
+version = "5.0.7"
+description = "Read resources from Python packages"
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "importlib_resources-5.0.7-py3-none-any.whl", hash = "sha256:2238159eb743bd85304a16e0536048b3e991c531d1cd51c4a834d1ccf2829057"},
+ {file = "importlib_resources-5.0.7.tar.gz", hash = "sha256:4df460394562b4581bb4e4087ad9447bd433148fba44241754ec3152499f1d1b"},
+]
+
+[package.extras]
+docs = ["jaraco.packaging (>=8.2)", "rst.linker (>=1.9)", "sphinx"]
+testing = ["pytest (>=3.5,!=3.7.3)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=1.2.3)", "pytest-cov", "pytest-enabler", "pytest-flake8", "pytest-mypy"]
+
+[[package]]
+name = "iniconfig"
+version = "2.0.0"
+description = "brain-dead simple config-ini parsing"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"},
+ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
+]
+
+[[package]]
+name = "isort"
+version = "5.12.0"
+description = "A Python utility / library to sort Python imports."
+optional = false
+python-versions = ">=3.8.0"
+files = [
+ {file = "isort-5.12.0-py3-none-any.whl", hash = "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6"},
+ {file = "isort-5.12.0.tar.gz", hash = "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504"},
+]
+
+[package.extras]
+colors = ["colorama (>=0.4.3)"]
+pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"]
+plugins = ["setuptools"]
+requirements-deprecated-finder = ["pip-api", "pipreqs"]
+
+[[package]]
+name = "jinja2"
+version = "3.1.2"
+description = "A very fast and expressive template engine."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"},
+ {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"},
+]
+
+[package.dependencies]
+MarkupSafe = ">=2.0"
+
+[package.extras]
+i18n = ["Babel (>=2.7)"]
+
+[[package]]
+name = "jmespath"
+version = "1.0.1"
+description = "JSON Matching Expressions"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980"},
+ {file = "jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe"},
+]
+
+[[package]]
+name = "jsonschema"
+version = "4.19.0"
+description = "An implementation of JSON Schema validation for Python"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "jsonschema-4.19.0-py3-none-any.whl", hash = "sha256:043dc26a3845ff09d20e4420d6012a9c91c9aa8999fa184e7efcfeccb41e32cb"},
+ {file = "jsonschema-4.19.0.tar.gz", hash = "sha256:6e1e7569ac13be8139b2dd2c21a55d350066ee3f80df06c608b398cdc6f30e8f"},
+]
+
+[package.dependencies]
+attrs = ">=22.2.0"
+jsonschema-specifications = ">=2023.03.6"
+referencing = ">=0.28.4"
+rpds-py = ">=0.7.1"
+
+[package.extras]
+format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"]
+format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=1.11)"]
+
+[[package]]
+name = "jsonschema-specifications"
+version = "2023.7.1"
+description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "jsonschema_specifications-2023.7.1-py3-none-any.whl", hash = "sha256:05adf340b659828a004220a9613be00fa3f223f2b82002e273dee62fd50524b1"},
+ {file = "jsonschema_specifications-2023.7.1.tar.gz", hash = "sha256:c91a50404e88a1f6ba40636778e2ee08f6e24c5613fe4c53ac24578a5a7f72bb"},
+]
+
+[package.dependencies]
+referencing = ">=0.28.0"
+
+[[package]]
+name = "lazy-object-proxy"
+version = "1.9.0"
+description = "A fast and thorough lazy object proxy."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "lazy-object-proxy-1.9.0.tar.gz", hash = "sha256:659fb5809fa4629b8a1ac5106f669cfc7bef26fbb389dda53b3e010d1ac4ebae"},
+ {file = "lazy_object_proxy-1.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b40387277b0ed2d0602b8293b94d7257e17d1479e257b4de114ea11a8cb7f2d7"},
+ {file = "lazy_object_proxy-1.9.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8c6cfb338b133fbdbc5cfaa10fe3c6aeea827db80c978dbd13bc9dd8526b7d4"},
+ {file = "lazy_object_proxy-1.9.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:721532711daa7db0d8b779b0bb0318fa87af1c10d7fe5e52ef30f8eff254d0cd"},
+ {file = "lazy_object_proxy-1.9.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:66a3de4a3ec06cd8af3f61b8e1ec67614fbb7c995d02fa224813cb7afefee701"},
+ {file = "lazy_object_proxy-1.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1aa3de4088c89a1b69f8ec0dcc169aa725b0ff017899ac568fe44ddc1396df46"},
+ {file = "lazy_object_proxy-1.9.0-cp310-cp310-win32.whl", hash = "sha256:f0705c376533ed2a9e5e97aacdbfe04cecd71e0aa84c7c0595d02ef93b6e4455"},
+ {file = "lazy_object_proxy-1.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:ea806fd4c37bf7e7ad82537b0757999264d5f70c45468447bb2b91afdbe73a6e"},
+ {file = "lazy_object_proxy-1.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:946d27deaff6cf8452ed0dba83ba38839a87f4f7a9732e8f9fd4107b21e6ff07"},
+ {file = "lazy_object_proxy-1.9.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79a31b086e7e68b24b99b23d57723ef7e2c6d81ed21007b6281ebcd1688acb0a"},
+ {file = "lazy_object_proxy-1.9.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f699ac1c768270c9e384e4cbd268d6e67aebcfae6cd623b4d7c3bfde5a35db59"},
+ {file = "lazy_object_proxy-1.9.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bfb38f9ffb53b942f2b5954e0f610f1e721ccebe9cce9025a38c8ccf4a5183a4"},
+ {file = "lazy_object_proxy-1.9.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:189bbd5d41ae7a498397287c408617fe5c48633e7755287b21d741f7db2706a9"},
+ {file = "lazy_object_proxy-1.9.0-cp311-cp311-win32.whl", hash = "sha256:81fc4d08b062b535d95c9ea70dbe8a335c45c04029878e62d744bdced5141586"},
+ {file = "lazy_object_proxy-1.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:f2457189d8257dd41ae9b434ba33298aec198e30adf2dcdaaa3a28b9994f6adb"},
+ {file = "lazy_object_proxy-1.9.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d9e25ef10a39e8afe59a5c348a4dbf29b4868ab76269f81ce1674494e2565a6e"},
+ {file = "lazy_object_proxy-1.9.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cbf9b082426036e19c6924a9ce90c740a9861e2bdc27a4834fd0a910742ac1e8"},
+ {file = "lazy_object_proxy-1.9.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f5fa4a61ce2438267163891961cfd5e32ec97a2c444e5b842d574251ade27d2"},
+ {file = "lazy_object_proxy-1.9.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:8fa02eaab317b1e9e03f69aab1f91e120e7899b392c4fc19807a8278a07a97e8"},
+ {file = "lazy_object_proxy-1.9.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e7c21c95cae3c05c14aafffe2865bbd5e377cfc1348c4f7751d9dc9a48ca4bda"},
+ {file = "lazy_object_proxy-1.9.0-cp37-cp37m-win32.whl", hash = "sha256:f12ad7126ae0c98d601a7ee504c1122bcef553d1d5e0c3bfa77b16b3968d2734"},
+ {file = "lazy_object_proxy-1.9.0-cp37-cp37m-win_amd64.whl", hash = "sha256:edd20c5a55acb67c7ed471fa2b5fb66cb17f61430b7a6b9c3b4a1e40293b1671"},
+ {file = "lazy_object_proxy-1.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2d0daa332786cf3bb49e10dc6a17a52f6a8f9601b4cf5c295a4f85854d61de63"},
+ {file = "lazy_object_proxy-1.9.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cd077f3d04a58e83d04b20e334f678c2b0ff9879b9375ed107d5d07ff160171"},
+ {file = "lazy_object_proxy-1.9.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:660c94ea760b3ce47d1855a30984c78327500493d396eac4dfd8bd82041b22be"},
+ {file = "lazy_object_proxy-1.9.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:212774e4dfa851e74d393a2370871e174d7ff0ebc980907723bb67d25c8a7c30"},
+ {file = "lazy_object_proxy-1.9.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f0117049dd1d5635bbff65444496c90e0baa48ea405125c088e93d9cf4525b11"},
+ {file = "lazy_object_proxy-1.9.0-cp38-cp38-win32.whl", hash = "sha256:0a891e4e41b54fd5b8313b96399f8b0e173bbbfc03c7631f01efbe29bb0bcf82"},
+ {file = "lazy_object_proxy-1.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:9990d8e71b9f6488e91ad25f322898c136b008d87bf852ff65391b004da5e17b"},
+ {file = "lazy_object_proxy-1.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9e7551208b2aded9c1447453ee366f1c4070602b3d932ace044715d89666899b"},
+ {file = "lazy_object_proxy-1.9.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f83ac4d83ef0ab017683d715ed356e30dd48a93746309c8f3517e1287523ef4"},
+ {file = "lazy_object_proxy-1.9.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7322c3d6f1766d4ef1e51a465f47955f1e8123caee67dd641e67d539a534d006"},
+ {file = "lazy_object_proxy-1.9.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:18b78ec83edbbeb69efdc0e9c1cb41a3b1b1ed11ddd8ded602464c3fc6020494"},
+ {file = "lazy_object_proxy-1.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:09763491ce220c0299688940f8dc2c5d05fd1f45af1e42e636b2e8b2303e4382"},
+ {file = "lazy_object_proxy-1.9.0-cp39-cp39-win32.whl", hash = "sha256:9090d8e53235aa280fc9239a86ae3ea8ac58eff66a705fa6aa2ec4968b95c821"},
+ {file = "lazy_object_proxy-1.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:db1c1722726f47e10e0b5fdbf15ac3b8adb58c091d12b3ab713965795036985f"},
+]
+
+[[package]]
+name = "markupsafe"
+version = "2.1.3"
+description = "Safely add untrusted strings to HTML/XML markup."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa"},
+ {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57"},
+ {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f"},
+ {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52"},
+ {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00"},
+ {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6"},
+ {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779"},
+ {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7"},
+ {file = "MarkupSafe-2.1.3-cp310-cp310-win32.whl", hash = "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431"},
+ {file = "MarkupSafe-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559"},
+ {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c"},
+ {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575"},
+ {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee"},
+ {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2"},
+ {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9"},
+ {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc"},
+ {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9"},
+ {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"},
+ {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"},
+ {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"},
+ {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc"},
+ {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823"},
+ {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11"},
+ {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd"},
+ {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939"},
+ {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c"},
+ {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c"},
+ {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1"},
+ {file = "MarkupSafe-2.1.3-cp312-cp312-win32.whl", hash = "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007"},
+ {file = "MarkupSafe-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb"},
+ {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"},
+ {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"},
+ {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"},
+ {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e"},
+ {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc"},
+ {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48"},
+ {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155"},
+ {file = "MarkupSafe-2.1.3-cp37-cp37m-win32.whl", hash = "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0"},
+ {file = "MarkupSafe-2.1.3-cp37-cp37m-win_amd64.whl", hash = "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24"},
+ {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4"},
+ {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0"},
+ {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee"},
+ {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be"},
+ {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e"},
+ {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8"},
+ {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3"},
+ {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d"},
+ {file = "MarkupSafe-2.1.3-cp38-cp38-win32.whl", hash = "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5"},
+ {file = "MarkupSafe-2.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc"},
+ {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198"},
+ {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b"},
+ {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58"},
+ {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e"},
+ {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c"},
+ {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636"},
+ {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea"},
+ {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e"},
+ {file = "MarkupSafe-2.1.3-cp39-cp39-win32.whl", hash = "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2"},
+ {file = "MarkupSafe-2.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba"},
+ {file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"},
+]
+
+[[package]]
+name = "mccabe"
+version = "0.7.0"
+description = "McCabe checker, plugin for flake8"
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"},
+ {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"},
+]
+
+[[package]]
+name = "multidict"
+version = "6.0.4"
+description = "multidict implementation"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "multidict-6.0.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b1a97283e0c85772d613878028fec909f003993e1007eafa715b24b377cb9b8"},
+ {file = "multidict-6.0.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eeb6dcc05e911516ae3d1f207d4b0520d07f54484c49dfc294d6e7d63b734171"},
+ {file = "multidict-6.0.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d6d635d5209b82a3492508cf5b365f3446afb65ae7ebd755e70e18f287b0adf7"},
+ {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c048099e4c9e9d615545e2001d3d8a4380bd403e1a0578734e0d31703d1b0c0b"},
+ {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ea20853c6dbbb53ed34cb4d080382169b6f4554d394015f1bef35e881bf83547"},
+ {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16d232d4e5396c2efbbf4f6d4df89bfa905eb0d4dc5b3549d872ab898451f569"},
+ {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36c63aaa167f6c6b04ef2c85704e93af16c11d20de1d133e39de6a0e84582a93"},
+ {file = "multidict-6.0.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:64bdf1086b6043bf519869678f5f2757f473dee970d7abf6da91ec00acb9cb98"},
+ {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:43644e38f42e3af682690876cff722d301ac585c5b9e1eacc013b7a3f7b696a0"},
+ {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7582a1d1030e15422262de9f58711774e02fa80df0d1578995c76214f6954988"},
+ {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:ddff9c4e225a63a5afab9dd15590432c22e8057e1a9a13d28ed128ecf047bbdc"},
+ {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ee2a1ece51b9b9e7752e742cfb661d2a29e7bcdba2d27e66e28a99f1890e4fa0"},
+ {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a2e4369eb3d47d2034032a26c7a80fcb21a2cb22e1173d761a162f11e562caa5"},
+ {file = "multidict-6.0.4-cp310-cp310-win32.whl", hash = "sha256:574b7eae1ab267e5f8285f0fe881f17efe4b98c39a40858247720935b893bba8"},
+ {file = "multidict-6.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:4dcbb0906e38440fa3e325df2359ac6cb043df8e58c965bb45f4e406ecb162cc"},
+ {file = "multidict-6.0.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0dfad7a5a1e39c53ed00d2dd0c2e36aed4650936dc18fd9a1826a5ae1cad6f03"},
+ {file = "multidict-6.0.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:64da238a09d6039e3bd39bb3aee9c21a5e34f28bfa5aa22518581f910ff94af3"},
+ {file = "multidict-6.0.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ff959bee35038c4624250473988b24f846cbeb2c6639de3602c073f10410ceba"},
+ {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:01a3a55bd90018c9c080fbb0b9f4891db37d148a0a18722b42f94694f8b6d4c9"},
+ {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c5cb09abb18c1ea940fb99360ea0396f34d46566f157122c92dfa069d3e0e982"},
+ {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:666daae833559deb2d609afa4490b85830ab0dfca811a98b70a205621a6109fe"},
+ {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11bdf3f5e1518b24530b8241529d2050014c884cf18b6fc69c0c2b30ca248710"},
+ {file = "multidict-6.0.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d18748f2d30f94f498e852c67d61261c643b349b9d2a581131725595c45ec6c"},
+ {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:458f37be2d9e4c95e2d8866a851663cbc76e865b78395090786f6cd9b3bbf4f4"},
+ {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b1a2eeedcead3a41694130495593a559a668f382eee0727352b9a41e1c45759a"},
+ {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7d6ae9d593ef8641544d6263c7fa6408cc90370c8cb2bbb65f8d43e5b0351d9c"},
+ {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:5979b5632c3e3534e42ca6ff856bb24b2e3071b37861c2c727ce220d80eee9ed"},
+ {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dcfe792765fab89c365123c81046ad4103fcabbc4f56d1c1997e6715e8015461"},
+ {file = "multidict-6.0.4-cp311-cp311-win32.whl", hash = "sha256:3601a3cece3819534b11d4efc1eb76047488fddd0c85a3948099d5da4d504636"},
+ {file = "multidict-6.0.4-cp311-cp311-win_amd64.whl", hash = "sha256:81a4f0b34bd92df3da93315c6a59034df95866014ac08535fc819f043bfd51f0"},
+ {file = "multidict-6.0.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:67040058f37a2a51ed8ea8f6b0e6ee5bd78ca67f169ce6122f3e2ec80dfe9b78"},
+ {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:853888594621e6604c978ce2a0444a1e6e70c8d253ab65ba11657659dcc9100f"},
+ {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:39ff62e7d0f26c248b15e364517a72932a611a9b75f35b45be078d81bdb86603"},
+ {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af048912e045a2dc732847d33821a9d84ba553f5c5f028adbd364dd4765092ac"},
+ {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1e8b901e607795ec06c9e42530788c45ac21ef3aaa11dbd0c69de543bfb79a9"},
+ {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62501642008a8b9871ddfccbf83e4222cf8ac0d5aeedf73da36153ef2ec222d2"},
+ {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:99b76c052e9f1bc0721f7541e5e8c05db3941eb9ebe7b8553c625ef88d6eefde"},
+ {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:509eac6cf09c794aa27bcacfd4d62c885cce62bef7b2c3e8b2e49d365b5003fe"},
+ {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:21a12c4eb6ddc9952c415f24eef97e3e55ba3af61f67c7bc388dcdec1404a067"},
+ {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:5cad9430ab3e2e4fa4a2ef4450f548768400a2ac635841bc2a56a2052cdbeb87"},
+ {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ab55edc2e84460694295f401215f4a58597f8f7c9466faec545093045476327d"},
+ {file = "multidict-6.0.4-cp37-cp37m-win32.whl", hash = "sha256:5a4dcf02b908c3b8b17a45fb0f15b695bf117a67b76b7ad18b73cf8e92608775"},
+ {file = "multidict-6.0.4-cp37-cp37m-win_amd64.whl", hash = "sha256:6ed5f161328b7df384d71b07317f4d8656434e34591f20552c7bcef27b0ab88e"},
+ {file = "multidict-6.0.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5fc1b16f586f049820c5c5b17bb4ee7583092fa0d1c4e28b5239181ff9532e0c"},
+ {file = "multidict-6.0.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1502e24330eb681bdaa3eb70d6358e818e8e8f908a22a1851dfd4e15bc2f8161"},
+ {file = "multidict-6.0.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b692f419760c0e65d060959df05f2a531945af31fda0c8a3b3195d4efd06de11"},
+ {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45e1ecb0379bfaab5eef059f50115b54571acfbe422a14f668fc8c27ba410e7e"},
+ {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ddd3915998d93fbcd2566ddf9cf62cdb35c9e093075f862935573d265cf8f65d"},
+ {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:59d43b61c59d82f2effb39a93c48b845efe23a3852d201ed2d24ba830d0b4cf2"},
+ {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc8e1d0c705233c5dd0c5e6460fbad7827d5d36f310a0fadfd45cc3029762258"},
+ {file = "multidict-6.0.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6aa0418fcc838522256761b3415822626f866758ee0bc6632c9486b179d0b52"},
+ {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6748717bb10339c4760c1e63da040f5f29f5ed6e59d76daee30305894069a660"},
+ {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4d1a3d7ef5e96b1c9e92f973e43aa5e5b96c659c9bc3124acbbd81b0b9c8a951"},
+ {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4372381634485bec7e46718edc71528024fcdc6f835baefe517b34a33c731d60"},
+ {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:fc35cb4676846ef752816d5be2193a1e8367b4c1397b74a565a9d0389c433a1d"},
+ {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4b9d9e4e2b37daddb5c23ea33a3417901fa7c7b3dee2d855f63ee67a0b21e5b1"},
+ {file = "multidict-6.0.4-cp38-cp38-win32.whl", hash = "sha256:e41b7e2b59679edfa309e8db64fdf22399eec4b0b24694e1b2104fb789207779"},
+ {file = "multidict-6.0.4-cp38-cp38-win_amd64.whl", hash = "sha256:d6c254ba6e45d8e72739281ebc46ea5eb5f101234f3ce171f0e9f5cc86991480"},
+ {file = "multidict-6.0.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:16ab77bbeb596e14212e7bab8429f24c1579234a3a462105cda4a66904998664"},
+ {file = "multidict-6.0.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bc779e9e6f7fda81b3f9aa58e3a6091d49ad528b11ed19f6621408806204ad35"},
+ {file = "multidict-6.0.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ceef517eca3e03c1cceb22030a3e39cb399ac86bff4e426d4fc6ae49052cc60"},
+ {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:281af09f488903fde97923c7744bb001a9b23b039a909460d0f14edc7bf59706"},
+ {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:52f2dffc8acaba9a2f27174c41c9e57f60b907bb9f096b36b1a1f3be71c6284d"},
+ {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b41156839806aecb3641f3208c0dafd3ac7775b9c4c422d82ee2a45c34ba81ca"},
+ {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5e3fc56f88cc98ef8139255cf8cd63eb2c586531e43310ff859d6bb3a6b51f1"},
+ {file = "multidict-6.0.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8316a77808c501004802f9beebde51c9f857054a0c871bd6da8280e718444449"},
+ {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f70b98cd94886b49d91170ef23ec5c0e8ebb6f242d734ed7ed677b24d50c82cf"},
+ {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bf6774e60d67a9efe02b3616fee22441d86fab4c6d335f9d2051d19d90a40063"},
+ {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:e69924bfcdda39b722ef4d9aa762b2dd38e4632b3641b1d9a57ca9cd18f2f83a"},
+ {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:6b181d8c23da913d4ff585afd1155a0e1194c0b50c54fcfe286f70cdaf2b7176"},
+ {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:52509b5be062d9eafc8170e53026fbc54cf3b32759a23d07fd935fb04fc22d95"},
+ {file = "multidict-6.0.4-cp39-cp39-win32.whl", hash = "sha256:27c523fbfbdfd19c6867af7346332b62b586eed663887392cff78d614f9ec313"},
+ {file = "multidict-6.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:33029f5734336aa0d4c0384525da0387ef89148dc7191aae00ca5fb23d7aafc2"},
+ {file = "multidict-6.0.4.tar.gz", hash = "sha256:3666906492efb76453c0e7b97f2cf459b0682e7402c0489a95484965dbc1da49"},
+]
+
+[[package]]
+name = "mypy-extensions"
+version = "1.0.0"
+description = "Type system extensions for programs checked with the mypy type checker."
+optional = false
+python-versions = ">=3.5"
+files = [
+ {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"},
+ {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
+]
+
+[[package]]
+name = "nodeenv"
+version = "1.8.0"
+description = "Node.js virtual environment builder"
+optional = false
+python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*"
+files = [
+ {file = "nodeenv-1.8.0-py2.py3-none-any.whl", hash = "sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec"},
+ {file = "nodeenv-1.8.0.tar.gz", hash = "sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2"},
+]
+
+[package.dependencies]
+setuptools = "*"
+
+[[package]]
+name = "packaging"
+version = "23.1"
+description = "Core utilities for Python packages"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"},
+ {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"},
+]
+
+[[package]]
+name = "pathspec"
+version = "0.11.2"
+description = "Utility library for gitignore style pattern matching of file paths."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"},
+ {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"},
+]
+
+[[package]]
+name = "perky"
+version = "0.9.2"
+description = "A simple, Pythonic file format. Same interface as the"
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "perky-0.9.2-py3-none-any.whl", hash = "sha256:bd1a3e2ebeedc611dcba6e01d6bf3fab872782e606bee4acbdceae7b19877192"},
+ {file = "perky-0.9.2.tar.gz", hash = "sha256:02e5ebe84c5beaff6c8254497c75793b7dbaca903941c82035958ddb1bb66178"},
+]
+
+[[package]]
+name = "platformdirs"
+version = "3.10.0"
+description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "platformdirs-3.10.0-py3-none-any.whl", hash = "sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d"},
+ {file = "platformdirs-3.10.0.tar.gz", hash = "sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d"},
+]
+
+[package.extras]
+docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"]
+test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"]
+
+[[package]]
+name = "pluggy"
+version = "1.2.0"
+description = "plugin and hook calling mechanisms for python"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "pluggy-1.2.0-py3-none-any.whl", hash = "sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849"},
+ {file = "pluggy-1.2.0.tar.gz", hash = "sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3"},
+]
+
+[package.extras]
+dev = ["pre-commit", "tox"]
+testing = ["pytest", "pytest-benchmark"]
+
+[[package]]
+name = "pre-commit"
+version = "3.3.3"
+description = "A framework for managing and maintaining multi-language pre-commit hooks."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "pre_commit-3.3.3-py2.py3-none-any.whl", hash = "sha256:10badb65d6a38caff29703362271d7dca483d01da88f9d7e05d0b97171c136cb"},
+ {file = "pre_commit-3.3.3.tar.gz", hash = "sha256:a2256f489cd913d575c145132ae196fe335da32d91a8294b7afe6622335dd023"},
+]
+
+[package.dependencies]
+cfgv = ">=2.0.0"
+identify = ">=1.0.0"
+nodeenv = ">=0.11.1"
+pyyaml = ">=5.1"
+virtualenv = ">=20.10.0"
+
+[[package]]
+name = "pycparser"
+version = "2.21"
+description = "C parser in Python"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+files = [
+ {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"},
+ {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"},
+]
+
+[[package]]
+name = "pydantic"
+version = "1.10.12"
+description = "Data validation and settings management using python type hints"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "pydantic-1.10.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a1fcb59f2f355ec350073af41d927bf83a63b50e640f4dbaa01053a28b7a7718"},
+ {file = "pydantic-1.10.12-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b7ccf02d7eb340b216ec33e53a3a629856afe1c6e0ef91d84a4e6f2fb2ca70fe"},
+ {file = "pydantic-1.10.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8fb2aa3ab3728d950bcc885a2e9eff6c8fc40bc0b7bb434e555c215491bcf48b"},
+ {file = "pydantic-1.10.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:771735dc43cf8383959dc9b90aa281f0b6092321ca98677c5fb6125a6f56d58d"},
+ {file = "pydantic-1.10.12-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ca48477862372ac3770969b9d75f1bf66131d386dba79506c46d75e6b48c1e09"},
+ {file = "pydantic-1.10.12-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a5e7add47a5b5a40c49b3036d464e3c7802f8ae0d1e66035ea16aa5b7a3923ed"},
+ {file = "pydantic-1.10.12-cp310-cp310-win_amd64.whl", hash = "sha256:e4129b528c6baa99a429f97ce733fff478ec955513630e61b49804b6cf9b224a"},
+ {file = "pydantic-1.10.12-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b0d191db0f92dfcb1dec210ca244fdae5cbe918c6050b342d619c09d31eea0cc"},
+ {file = "pydantic-1.10.12-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:795e34e6cc065f8f498c89b894a3c6da294a936ee71e644e4bd44de048af1405"},
+ {file = "pydantic-1.10.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:69328e15cfda2c392da4e713443c7dbffa1505bc9d566e71e55abe14c97ddc62"},
+ {file = "pydantic-1.10.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2031de0967c279df0d8a1c72b4ffc411ecd06bac607a212892757db7462fc494"},
+ {file = "pydantic-1.10.12-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:ba5b2e6fe6ca2b7e013398bc7d7b170e21cce322d266ffcd57cca313e54fb246"},
+ {file = "pydantic-1.10.12-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2a7bac939fa326db1ab741c9d7f44c565a1d1e80908b3797f7f81a4f86bc8d33"},
+ {file = "pydantic-1.10.12-cp311-cp311-win_amd64.whl", hash = "sha256:87afda5539d5140cb8ba9e8b8c8865cb5b1463924d38490d73d3ccfd80896b3f"},
+ {file = "pydantic-1.10.12-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:549a8e3d81df0a85226963611950b12d2d334f214436a19537b2efed61b7639a"},
+ {file = "pydantic-1.10.12-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:598da88dfa127b666852bef6d0d796573a8cf5009ffd62104094a4fe39599565"},
+ {file = "pydantic-1.10.12-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ba5c4a8552bff16c61882db58544116d021d0b31ee7c66958d14cf386a5b5350"},
+ {file = "pydantic-1.10.12-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c79e6a11a07da7374f46970410b41d5e266f7f38f6a17a9c4823db80dadf4303"},
+ {file = "pydantic-1.10.12-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ab26038b8375581dc832a63c948f261ae0aa21f1d34c1293469f135fa92972a5"},
+ {file = "pydantic-1.10.12-cp37-cp37m-win_amd64.whl", hash = "sha256:e0a16d274b588767602b7646fa05af2782576a6cf1022f4ba74cbb4db66f6ca8"},
+ {file = "pydantic-1.10.12-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6a9dfa722316f4acf4460afdf5d41d5246a80e249c7ff475c43a3a1e9d75cf62"},
+ {file = "pydantic-1.10.12-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a73f489aebd0c2121ed974054cb2759af8a9f747de120acd2c3394cf84176ccb"},
+ {file = "pydantic-1.10.12-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b30bcb8cbfccfcf02acb8f1a261143fab622831d9c0989707e0e659f77a18e0"},
+ {file = "pydantic-1.10.12-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2fcfb5296d7877af406ba1547dfde9943b1256d8928732267e2653c26938cd9c"},
+ {file = "pydantic-1.10.12-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:2f9a6fab5f82ada41d56b0602606a5506aab165ca54e52bc4545028382ef1c5d"},
+ {file = "pydantic-1.10.12-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:dea7adcc33d5d105896401a1f37d56b47d443a2b2605ff8a969a0ed5543f7e33"},
+ {file = "pydantic-1.10.12-cp38-cp38-win_amd64.whl", hash = "sha256:1eb2085c13bce1612da8537b2d90f549c8cbb05c67e8f22854e201bde5d98a47"},
+ {file = "pydantic-1.10.12-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ef6c96b2baa2100ec91a4b428f80d8f28a3c9e53568219b6c298c1125572ebc6"},
+ {file = "pydantic-1.10.12-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6c076be61cd0177a8433c0adcb03475baf4ee91edf5a4e550161ad57fc90f523"},
+ {file = "pydantic-1.10.12-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d5a58feb9a39f481eda4d5ca220aa8b9d4f21a41274760b9bc66bfd72595b86"},
+ {file = "pydantic-1.10.12-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5f805d2d5d0a41633651a73fa4ecdd0b3d7a49de4ec3fadf062fe16501ddbf1"},
+ {file = "pydantic-1.10.12-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:1289c180abd4bd4555bb927c42ee42abc3aee02b0fb2d1223fb7c6e5bef87dbe"},
+ {file = "pydantic-1.10.12-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5d1197e462e0364906cbc19681605cb7c036f2475c899b6f296104ad42b9f5fb"},
+ {file = "pydantic-1.10.12-cp39-cp39-win_amd64.whl", hash = "sha256:fdbdd1d630195689f325c9ef1a12900524dceb503b00a987663ff4f58669b93d"},
+ {file = "pydantic-1.10.12-py3-none-any.whl", hash = "sha256:b749a43aa51e32839c9d71dc67eb1e4221bb04af1033a32e3923d46f9effa942"},
+ {file = "pydantic-1.10.12.tar.gz", hash = "sha256:0fe8a415cea8f340e7a9af9c54fc71a649b43e8ca3cc732986116b3cb135d303"},
+]
+
+[package.dependencies]
+typing-extensions = ">=4.2.0"
+
+[package.extras]
+dotenv = ["python-dotenv (>=0.10.4)"]
+email = ["email-validator (>=1.0.3)"]
+
+[[package]]
+name = "pygments"
+version = "2.16.1"
+description = "Pygments is a syntax highlighting package written in Python."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "Pygments-2.16.1-py3-none-any.whl", hash = "sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692"},
+ {file = "Pygments-2.16.1.tar.gz", hash = "sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29"},
+]
+
+[package.extras]
+plugins = ["importlib-metadata"]
+
+[[package]]
+name = "pylint"
+version = "2.17.5"
+description = "python code static checker"
+optional = false
+python-versions = ">=3.7.2"
+files = [
+ {file = "pylint-2.17.5-py3-none-any.whl", hash = "sha256:73995fb8216d3bed149c8d51bba25b2c52a8251a2c8ac846ec668ce38fab5413"},
+ {file = "pylint-2.17.5.tar.gz", hash = "sha256:f7b601cbc06fef7e62a754e2b41294c2aa31f1cb659624b9a85bcba29eaf8252"},
+]
+
+[package.dependencies]
+astroid = ">=2.15.6,<=2.17.0-dev0"
+colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""}
+dill = {version = ">=0.2", markers = "python_version < \"3.11\""}
+isort = ">=4.2.5,<6"
+mccabe = ">=0.6,<0.8"
+platformdirs = ">=2.2.0"
+tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
+tomlkit = ">=0.10.1"
+typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""}
+
+[package.extras]
+spelling = ["pyenchant (>=3.2,<4.0)"]
+testutils = ["gitpython (>3)"]
+
+[[package]]
+name = "pyproject-hooks"
+version = "1.0.0"
+description = "Wrappers to call pyproject.toml-based build backend hooks."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "pyproject_hooks-1.0.0-py3-none-any.whl", hash = "sha256:283c11acd6b928d2f6a7c73fa0d01cb2bdc5f07c57a2eeb6e83d5e56b97976f8"},
+ {file = "pyproject_hooks-1.0.0.tar.gz", hash = "sha256:f271b298b97f5955d53fb12b72c1fb1948c22c1a6b70b315c54cedaca0264ef5"},
+]
+
+[package.dependencies]
+tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
+
+[[package]]
+name = "pytest"
+version = "7.4.0"
+description = "pytest: simple powerful testing with Python"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "pytest-7.4.0-py3-none-any.whl", hash = "sha256:78bf16451a2eb8c7a2ea98e32dc119fd2aa758f1d5d66dbf0a59d69a3969df32"},
+ {file = "pytest-7.4.0.tar.gz", hash = "sha256:b4bf8c45bd59934ed84001ad51e11b4ee40d40a1229d2c79f9c592b0a3f6bd8a"},
+]
+
+[package.dependencies]
+colorama = {version = "*", markers = "sys_platform == \"win32\""}
+exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""}
+iniconfig = "*"
+packaging = "*"
+pluggy = ">=0.12,<2.0"
+tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""}
+
+[package.extras]
+testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"]
+
+[[package]]
+name = "pytest-mock"
+version = "3.11.1"
+description = "Thin-wrapper around the mock package for easier use with pytest"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "pytest-mock-3.11.1.tar.gz", hash = "sha256:7f6b125602ac6d743e523ae0bfa71e1a697a2f5534064528c6ff84c2f7c2fc7f"},
+ {file = "pytest_mock-3.11.1-py3-none-any.whl", hash = "sha256:21c279fff83d70763b05f8874cc9cfb3fcacd6d354247a976f9529d19f9acf39"},
+]
+
+[package.dependencies]
+pytest = ">=5.0"
+
+[package.extras]
+dev = ["pre-commit", "pytest-asyncio", "tox"]
+
+[[package]]
+name = "python-dateutil"
+version = "2.8.2"
+description = "Extensions to the standard Python datetime module"
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
+files = [
+ {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"},
+ {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"},
+]
+
+[package.dependencies]
+six = ">=1.5"
+
+[[package]]
+name = "pyyaml"
+version = "6.0.1"
+description = "YAML parser and emitter for Python"
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"},
+ {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"},
+ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"},
+ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"},
+ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"},
+ {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"},
+ {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"},
+ {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"},
+ {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"},
+ {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"},
+ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"},
+ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"},
+ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"},
+ {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"},
+ {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"},
+ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"},
+ {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"},
+ {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"},
+ {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"},
+ {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"},
+ {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"},
+ {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"},
+ {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"},
+ {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"},
+ {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"},
+ {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"},
+ {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"},
+ {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"},
+ {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"},
+ {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"},
+ {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"},
+ {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"},
+ {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"},
+ {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"},
+ {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"},
+ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"},
+ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"},
+ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"},
+ {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"},
+ {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"},
+ {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"},
+ {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"},
+ {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"},
+ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"},
+ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"},
+ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"},
+ {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"},
+ {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"},
+ {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"},
+ {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"},
+]
+
+[[package]]
+name = "referencing"
+version = "0.30.2"
+description = "JSON Referencing + Python"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "referencing-0.30.2-py3-none-any.whl", hash = "sha256:449b6669b6121a9e96a7f9e410b245d471e8d48964c67113ce9afe50c8dd7bdf"},
+ {file = "referencing-0.30.2.tar.gz", hash = "sha256:794ad8003c65938edcdbc027f1933215e0d0ccc0291e3ce20a4d87432b59efc0"},
+]
+
+[package.dependencies]
+attrs = ">=22.2.0"
+rpds-py = ">=0.7.0"
+
+[[package]]
+name = "requests"
+version = "2.31.0"
+description = "Python HTTP for Humans."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"},
+ {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"},
+]
+
+[package.dependencies]
+certifi = ">=2017.4.17"
+charset-normalizer = ">=2,<4"
+idna = ">=2.5,<4"
+urllib3 = ">=1.21.1,<3"
+
+[package.extras]
+socks = ["PySocks (>=1.5.6,!=1.5.7)"]
+use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
+
+[[package]]
+name = "resolvelib"
+version = "1.0.1"
+description = "Resolve abstract dependencies into concrete ones"
+optional = false
+python-versions = "*"
+files = [
+ {file = "resolvelib-1.0.1-py2.py3-none-any.whl", hash = "sha256:d2da45d1a8dfee81bdd591647783e340ef3bcb104b54c383f70d422ef5cc7dbf"},
+ {file = "resolvelib-1.0.1.tar.gz", hash = "sha256:04ce76cbd63fded2078ce224785da6ecd42b9564b1390793f64ddecbe997b309"},
+]
+
+[package.extras]
+examples = ["html5lib", "packaging", "pygraphviz", "requests"]
+lint = ["black", "flake8", "isort", "mypy", "types-requests"]
+release = ["build", "towncrier", "twine"]
+test = ["commentjson", "packaging", "pytest"]
+
+[[package]]
+name = "rich"
+version = "12.6.0"
+description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
+optional = false
+python-versions = ">=3.6.3,<4.0.0"
+files = [
+ {file = "rich-12.6.0-py3-none-any.whl", hash = "sha256:a4eb26484f2c82589bd9a17c73d32a010b1e29d89f1604cd9bf3a2097b81bb5e"},
+ {file = "rich-12.6.0.tar.gz", hash = "sha256:ba3a3775974105c221d31141f2c116f4fd65c5ceb0698657a11e9f295ec93fd0"},
+]
+
+[package.dependencies]
+commonmark = ">=0.9.0,<0.10.0"
+pygments = ">=2.6.0,<3.0.0"
+
+[package.extras]
+jupyter = ["ipywidgets (>=7.5.1,<8.0.0)"]
+
+[[package]]
+name = "rpds-py"
+version = "0.9.2"
+description = "Python bindings to Rust's persistent data structures (rpds)"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "rpds_py-0.9.2-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:ab6919a09c055c9b092798ce18c6c4adf49d24d4d9e43a92b257e3f2548231e7"},
+ {file = "rpds_py-0.9.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d55777a80f78dd09410bd84ff8c95ee05519f41113b2df90a69622f5540c4f8b"},
+ {file = "rpds_py-0.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a216b26e5af0a8e265d4efd65d3bcec5fba6b26909014effe20cd302fd1138fa"},
+ {file = "rpds_py-0.9.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:29cd8bfb2d716366a035913ced99188a79b623a3512292963d84d3e06e63b496"},
+ {file = "rpds_py-0.9.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:44659b1f326214950a8204a248ca6199535e73a694be8d3e0e869f820767f12f"},
+ {file = "rpds_py-0.9.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:745f5a43fdd7d6d25a53ab1a99979e7f8ea419dfefebcab0a5a1e9095490ee5e"},
+ {file = "rpds_py-0.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a987578ac5214f18b99d1f2a3851cba5b09f4a689818a106c23dbad0dfeb760f"},
+ {file = "rpds_py-0.9.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bf4151acb541b6e895354f6ff9ac06995ad9e4175cbc6d30aaed08856558201f"},
+ {file = "rpds_py-0.9.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:03421628f0dc10a4119d714a17f646e2837126a25ac7a256bdf7c3943400f67f"},
+ {file = "rpds_py-0.9.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:13b602dc3e8dff3063734f02dcf05111e887f301fdda74151a93dbbc249930fe"},
+ {file = "rpds_py-0.9.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:fae5cb554b604b3f9e2c608241b5d8d303e410d7dfb6d397c335f983495ce7f6"},
+ {file = "rpds_py-0.9.2-cp310-none-win32.whl", hash = "sha256:47c5f58a8e0c2c920cc7783113df2fc4ff12bf3a411d985012f145e9242a2764"},
+ {file = "rpds_py-0.9.2-cp310-none-win_amd64.whl", hash = "sha256:4ea6b73c22d8182dff91155af018b11aac9ff7eca085750455c5990cb1cfae6e"},
+ {file = "rpds_py-0.9.2-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:e564d2238512c5ef5e9d79338ab77f1cbbda6c2d541ad41b2af445fb200385e3"},
+ {file = "rpds_py-0.9.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f411330a6376fb50e5b7a3e66894e4a39e60ca2e17dce258d53768fea06a37bd"},
+ {file = "rpds_py-0.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e7521f5af0233e89939ad626b15278c71b69dc1dfccaa7b97bd4cdf96536bb7"},
+ {file = "rpds_py-0.9.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8d3335c03100a073883857e91db9f2e0ef8a1cf42dc0369cbb9151c149dbbc1b"},
+ {file = "rpds_py-0.9.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d25b1c1096ef0447355f7293fbe9ad740f7c47ae032c2884113f8e87660d8f6e"},
+ {file = "rpds_py-0.9.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6a5d3fbd02efd9cf6a8ffc2f17b53a33542f6b154e88dd7b42ef4a4c0700fdad"},
+ {file = "rpds_py-0.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c5934e2833afeaf36bd1eadb57256239785f5af0220ed8d21c2896ec4d3a765f"},
+ {file = "rpds_py-0.9.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:095b460e117685867d45548fbd8598a8d9999227e9061ee7f012d9d264e6048d"},
+ {file = "rpds_py-0.9.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:91378d9f4151adc223d584489591dbb79f78814c0734a7c3bfa9c9e09978121c"},
+ {file = "rpds_py-0.9.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:24a81c177379300220e907e9b864107614b144f6c2a15ed5c3450e19cf536fae"},
+ {file = "rpds_py-0.9.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:de0b6eceb46141984671802d412568d22c6bacc9b230174f9e55fc72ef4f57de"},
+ {file = "rpds_py-0.9.2-cp311-none-win32.whl", hash = "sha256:700375326ed641f3d9d32060a91513ad668bcb7e2cffb18415c399acb25de2ab"},
+ {file = "rpds_py-0.9.2-cp311-none-win_amd64.whl", hash = "sha256:0766babfcf941db8607bdaf82569ec38107dbb03c7f0b72604a0b346b6eb3298"},
+ {file = "rpds_py-0.9.2-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:b1440c291db3f98a914e1afd9d6541e8fc60b4c3aab1a9008d03da4651e67386"},
+ {file = "rpds_py-0.9.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0f2996fbac8e0b77fd67102becb9229986396e051f33dbceada3debaacc7033f"},
+ {file = "rpds_py-0.9.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f30d205755566a25f2ae0382944fcae2f350500ae4df4e795efa9e850821d82"},
+ {file = "rpds_py-0.9.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:159fba751a1e6b1c69244e23ba6c28f879a8758a3e992ed056d86d74a194a0f3"},
+ {file = "rpds_py-0.9.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a1f044792e1adcea82468a72310c66a7f08728d72a244730d14880cd1dabe36b"},
+ {file = "rpds_py-0.9.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9251eb8aa82e6cf88510530b29eef4fac825a2b709baf5b94a6094894f252387"},
+ {file = "rpds_py-0.9.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01899794b654e616c8625b194ddd1e5b51ef5b60ed61baa7a2d9c2ad7b2a4238"},
+ {file = "rpds_py-0.9.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b0c43f8ae8f6be1d605b0465671124aa8d6a0e40f1fb81dcea28b7e3d87ca1e1"},
+ {file = "rpds_py-0.9.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:207f57c402d1f8712618f737356e4b6f35253b6d20a324d9a47cb9f38ee43a6b"},
+ {file = "rpds_py-0.9.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b52e7c5ae35b00566d244ffefba0f46bb6bec749a50412acf42b1c3f402e2c90"},
+ {file = "rpds_py-0.9.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:978fa96dbb005d599ec4fd9ed301b1cc45f1a8f7982d4793faf20b404b56677d"},
+ {file = "rpds_py-0.9.2-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:6aa8326a4a608e1c28da191edd7c924dff445251b94653988efb059b16577a4d"},
+ {file = "rpds_py-0.9.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:aad51239bee6bff6823bbbdc8ad85136c6125542bbc609e035ab98ca1e32a192"},
+ {file = "rpds_py-0.9.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4bd4dc3602370679c2dfb818d9c97b1137d4dd412230cfecd3c66a1bf388a196"},
+ {file = "rpds_py-0.9.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dd9da77c6ec1f258387957b754f0df60766ac23ed698b61941ba9acccd3284d1"},
+ {file = "rpds_py-0.9.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:190ca6f55042ea4649ed19c9093a9be9d63cd8a97880106747d7147f88a49d18"},
+ {file = "rpds_py-0.9.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:876bf9ed62323bc7dcfc261dbc5572c996ef26fe6406b0ff985cbcf460fc8a4c"},
+ {file = "rpds_py-0.9.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa2818759aba55df50592ecbc95ebcdc99917fa7b55cc6796235b04193eb3c55"},
+ {file = "rpds_py-0.9.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9ea4d00850ef1e917815e59b078ecb338f6a8efda23369677c54a5825dbebb55"},
+ {file = "rpds_py-0.9.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:5855c85eb8b8a968a74dc7fb014c9166a05e7e7a8377fb91d78512900aadd13d"},
+ {file = "rpds_py-0.9.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:14c408e9d1a80dcb45c05a5149e5961aadb912fff42ca1dd9b68c0044904eb32"},
+ {file = "rpds_py-0.9.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:65a0583c43d9f22cb2130c7b110e695fff834fd5e832a776a107197e59a1898e"},
+ {file = "rpds_py-0.9.2-cp38-none-win32.whl", hash = "sha256:71f2f7715935a61fa3e4ae91d91b67e571aeb5cb5d10331ab681256bda2ad920"},
+ {file = "rpds_py-0.9.2-cp38-none-win_amd64.whl", hash = "sha256:674c704605092e3ebbbd13687b09c9f78c362a4bc710343efe37a91457123044"},
+ {file = "rpds_py-0.9.2-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:07e2c54bef6838fa44c48dfbc8234e8e2466d851124b551fc4e07a1cfeb37260"},
+ {file = "rpds_py-0.9.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f7fdf55283ad38c33e35e2855565361f4bf0abd02470b8ab28d499c663bc5d7c"},
+ {file = "rpds_py-0.9.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:890ba852c16ace6ed9f90e8670f2c1c178d96510a21b06d2fa12d8783a905193"},
+ {file = "rpds_py-0.9.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:50025635ba8b629a86d9d5474e650da304cb46bbb4d18690532dd79341467846"},
+ {file = "rpds_py-0.9.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:517cbf6e67ae3623c5127206489d69eb2bdb27239a3c3cc559350ef52a3bbf0b"},
+ {file = "rpds_py-0.9.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0836d71ca19071090d524739420a61580f3f894618d10b666cf3d9a1688355b1"},
+ {file = "rpds_py-0.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c439fd54b2b9053717cca3de9583be6584b384d88d045f97d409f0ca867d80f"},
+ {file = "rpds_py-0.9.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f68996a3b3dc9335037f82754f9cdbe3a95db42bde571d8c3be26cc6245f2324"},
+ {file = "rpds_py-0.9.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7d68dc8acded354c972116f59b5eb2e5864432948e098c19fe6994926d8e15c3"},
+ {file = "rpds_py-0.9.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:f963c6b1218b96db85fc37a9f0851eaf8b9040aa46dec112611697a7023da535"},
+ {file = "rpds_py-0.9.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5a46859d7f947061b4010e554ccd1791467d1b1759f2dc2ec9055fa239f1bc26"},
+ {file = "rpds_py-0.9.2-cp39-none-win32.whl", hash = "sha256:e07e5dbf8a83c66783a9fe2d4566968ea8c161199680e8ad38d53e075df5f0d0"},
+ {file = "rpds_py-0.9.2-cp39-none-win_amd64.whl", hash = "sha256:682726178138ea45a0766907957b60f3a1bf3acdf212436be9733f28b6c5af3c"},
+ {file = "rpds_py-0.9.2-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:196cb208825a8b9c8fc360dc0f87993b8b260038615230242bf18ec84447c08d"},
+ {file = "rpds_py-0.9.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:c7671d45530fcb6d5e22fd40c97e1e1e01965fc298cbda523bb640f3d923b387"},
+ {file = "rpds_py-0.9.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83b32f0940adec65099f3b1c215ef7f1d025d13ff947975a055989cb7fd019a4"},
+ {file = "rpds_py-0.9.2-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7f67da97f5b9eac838b6980fc6da268622e91f8960e083a34533ca710bec8611"},
+ {file = "rpds_py-0.9.2-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:03975db5f103997904c37e804e5f340c8fdabbb5883f26ee50a255d664eed58c"},
+ {file = "rpds_py-0.9.2-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:987b06d1cdb28f88a42e4fb8a87f094e43f3c435ed8e486533aea0bf2e53d931"},
+ {file = "rpds_py-0.9.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c861a7e4aef15ff91233751619ce3a3d2b9e5877e0fcd76f9ea4f6847183aa16"},
+ {file = "rpds_py-0.9.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:02938432352359805b6da099c9c95c8a0547fe4b274ce8f1a91677401bb9a45f"},
+ {file = "rpds_py-0.9.2-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:ef1f08f2a924837e112cba2953e15aacfccbbfcd773b4b9b4723f8f2ddded08e"},
+ {file = "rpds_py-0.9.2-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:35da5cc5cb37c04c4ee03128ad59b8c3941a1e5cd398d78c37f716f32a9b7f67"},
+ {file = "rpds_py-0.9.2-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:141acb9d4ccc04e704e5992d35472f78c35af047fa0cfae2923835d153f091be"},
+ {file = "rpds_py-0.9.2-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:79f594919d2c1a0cc17d1988a6adaf9a2f000d2e1048f71f298b056b1018e872"},
+ {file = "rpds_py-0.9.2-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:a06418fe1155e72e16dddc68bb3780ae44cebb2912fbd8bb6ff9161de56e1798"},
+ {file = "rpds_py-0.9.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b2eb034c94b0b96d5eddb290b7b5198460e2d5d0c421751713953a9c4e47d10"},
+ {file = "rpds_py-0.9.2-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8b08605d248b974eb02f40bdcd1a35d3924c83a2a5e8f5d0fa5af852c4d960af"},
+ {file = "rpds_py-0.9.2-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a0805911caedfe2736935250be5008b261f10a729a303f676d3d5fea6900c96a"},
+ {file = "rpds_py-0.9.2-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ab2299e3f92aa5417d5e16bb45bb4586171c1327568f638e8453c9f8d9e0f020"},
+ {file = "rpds_py-0.9.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c8d7594e38cf98d8a7df25b440f684b510cf4627fe038c297a87496d10a174f"},
+ {file = "rpds_py-0.9.2-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8b9ec12ad5f0a4625db34db7e0005be2632c1013b253a4a60e8302ad4d462afd"},
+ {file = "rpds_py-0.9.2-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:1fcdee18fea97238ed17ab6478c66b2095e4ae7177e35fb71fbe561a27adf620"},
+ {file = "rpds_py-0.9.2-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:933a7d5cd4b84f959aedeb84f2030f0a01d63ae6cf256629af3081cf3e3426e8"},
+ {file = "rpds_py-0.9.2-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:686ba516e02db6d6f8c279d1641f7067ebb5dc58b1d0536c4aaebb7bf01cdc5d"},
+ {file = "rpds_py-0.9.2-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:0173c0444bec0a3d7d848eaeca2d8bd32a1b43f3d3fde6617aac3731fa4be05f"},
+ {file = "rpds_py-0.9.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:d576c3ef8c7b2d560e301eb33891d1944d965a4d7a2eacb6332eee8a71827db6"},
+ {file = "rpds_py-0.9.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed89861ee8c8c47d6beb742a602f912b1bb64f598b1e2f3d758948721d44d468"},
+ {file = "rpds_py-0.9.2-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1054a08e818f8e18910f1bee731583fe8f899b0a0a5044c6e680ceea34f93876"},
+ {file = "rpds_py-0.9.2-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99e7c4bb27ff1aab90dcc3e9d37ee5af0231ed98d99cb6f5250de28889a3d502"},
+ {file = "rpds_py-0.9.2-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c545d9d14d47be716495076b659db179206e3fd997769bc01e2d550eeb685596"},
+ {file = "rpds_py-0.9.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9039a11bca3c41be5a58282ed81ae422fa680409022b996032a43badef2a3752"},
+ {file = "rpds_py-0.9.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fb39aca7a64ad0c9490adfa719dbeeb87d13be137ca189d2564e596f8ba32c07"},
+ {file = "rpds_py-0.9.2-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:2d8b3b3a2ce0eaa00c5bbbb60b6713e94e7e0becab7b3db6c5c77f979e8ed1f1"},
+ {file = "rpds_py-0.9.2-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:99b1c16f732b3a9971406fbfe18468592c5a3529585a45a35adbc1389a529a03"},
+ {file = "rpds_py-0.9.2-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:c27ee01a6c3223025f4badd533bea5e87c988cb0ba2811b690395dfe16088cfe"},
+ {file = "rpds_py-0.9.2.tar.gz", hash = "sha256:8d70e8f14900f2657c249ea4def963bed86a29b81f81f5b76b5a9215680de945"},
+]
+
+[[package]]
+name = "rstcheck"
+version = "6.1.2"
+description = "Checks syntax of reStructuredText and code blocks nested within it"
+optional = false
+python-versions = ">=3.7,<4.0"
+files = [
+ {file = "rstcheck-6.1.2-py3-none-any.whl", hash = "sha256:4aaa46e0debc179f849807c453fa384fd2b75167faf5b1274115730805fab529"},
+ {file = "rstcheck-6.1.2.tar.gz", hash = "sha256:f9cb07a72ef9a81d1e32187eae29b00a89421ccba1bde0b1652a08ed0923f61b"},
+]
+
+[package.dependencies]
+rstcheck-core = ">=1.0.2,<2.0.0"
+typer = {version = ">=0.4.1,<0.8", extras = ["all"]}
+
+[package.extras]
+docs = ["m2r2 (>=0.3.2)", "sphinx", "sphinx-autobuild (==2021.3.14)", "sphinx-click (>=4.0.3,<5.0.0)", "sphinx-rtd-dark-mode (>=1.2.4,<2.0.0)", "sphinx-rtd-theme (<1)", "sphinxcontrib-spelling (>=7.3)"]
+sphinx = ["sphinx"]
+testing = ["coverage-conditional-plugin (>=0.5)", "coverage[toml] (>=6.0)", "pytest (>=7.2)", "pytest-cov (>=3.0)", "pytest-randomly (>=3.0)", "pytest-sugar (>=0.9.5)"]
+toml = ["tomli"]
+
+[[package]]
+name = "rstcheck-core"
+version = "1.0.3"
+description = "Checks syntax of reStructuredText and code blocks nested within it"
+optional = false
+python-versions = ">=3.7,<4.0"
+files = [
+ {file = "rstcheck_core-1.0.3-py3-none-any.whl", hash = "sha256:d75d7df8f15b58e8aafe322d6fb6ef1ac8d12bb563089b0696948a00ee7f601a"},
+ {file = "rstcheck_core-1.0.3.tar.gz", hash = "sha256:add19c9a1b97d9087f4b463b49c12cd8a9c03689a255e99089c70a2692f16369"},
+]
+
+[package.dependencies]
+docutils = ">=0.7,<0.20"
+pydantic = ">=1.2,<2.0"
+types-docutils = ">=0.18,<0.20"
+
+[package.extras]
+docs = ["m2r2 (>=0.3.2)", "sphinx (>=4.0,<6.0)", "sphinx-autobuild (==2021.3.14)", "sphinx-autodoc-typehints (>=1.15)", "sphinx-rtd-dark-mode (>=1.2.4,<2.0.0)", "sphinx-rtd-theme (<1)", "sphinxcontrib-apidoc (>=0.3)", "sphinxcontrib-spelling (>=7.3)"]
+sphinx = ["sphinx (>=4.0,<6.0)"]
+testing = ["coverage-conditional-plugin (>=0.5)", "coverage[toml] (>=6.0)", "pytest (>=6.0)", "pytest-cov (>=3.0)", "pytest-mock (>=3.7)", "pytest-randomly (>=3.0)", "pytest-sugar (>=0.9.5)"]
+toml = ["tomli (>=2.0,<3.0)"]
+
+[[package]]
+name = "ruamel-yaml"
+version = "0.17.32"
+description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order"
+optional = false
+python-versions = ">=3"
+files = [
+ {file = "ruamel.yaml-0.17.32-py3-none-any.whl", hash = "sha256:23cd2ed620231677564646b0c6a89d138b6822a0d78656df7abda5879ec4f447"},
+ {file = "ruamel.yaml-0.17.32.tar.gz", hash = "sha256:ec939063761914e14542972a5cba6d33c23b0859ab6342f61cf070cfc600efc2"},
+]
+
+[package.dependencies]
+"ruamel.yaml.clib" = {version = ">=0.2.7", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.12\""}
+
+[package.extras]
+docs = ["ryd"]
+jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"]
+
+[[package]]
+name = "ruamel-yaml-clib"
+version = "0.2.7"
+description = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml"
+optional = false
+python-versions = ">=3.5"
+files = [
+ {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d5859983f26d8cd7bb5c287ef452e8aacc86501487634573d260968f753e1d71"},
+ {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:debc87a9516b237d0466a711b18b6ebeb17ba9f391eb7f91c649c5c4ec5006c7"},
+ {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:df5828871e6648db72d1c19b4bd24819b80a755c4541d3409f0f7acd0f335c80"},
+ {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:efa08d63ef03d079dcae1dfe334f6c8847ba8b645d08df286358b1f5293d24ab"},
+ {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-win32.whl", hash = "sha256:763d65baa3b952479c4e972669f679fe490eee058d5aa85da483ebae2009d231"},
+ {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-win_amd64.whl", hash = "sha256:d000f258cf42fec2b1bbf2863c61d7b8918d31ffee905da62dede869254d3b8a"},
+ {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:045e0626baf1c52e5527bd5db361bc83180faaba2ff586e763d3d5982a876a9e"},
+ {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:1a6391a7cabb7641c32517539ca42cf84b87b667bad38b78d4d42dd23e957c81"},
+ {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:9c7617df90c1365638916b98cdd9be833d31d337dbcd722485597b43c4a215bf"},
+ {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:41d0f1fa4c6830176eef5b276af04c89320ea616655d01327d5ce65e50575c94"},
+ {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-win32.whl", hash = "sha256:f6d3d39611ac2e4f62c3128a9eed45f19a6608670c5a2f4f07f24e8de3441d38"},
+ {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-win_amd64.whl", hash = "sha256:da538167284de58a52109a9b89b8f6a53ff8437dd6dc26d33b57bf6699153122"},
+ {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:4b3a93bb9bc662fc1f99c5c3ea8e623d8b23ad22f861eb6fce9377ac07ad6072"},
+ {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-macosx_12_0_arm64.whl", hash = "sha256:a234a20ae07e8469da311e182e70ef6b199d0fbeb6c6cc2901204dd87fb867e8"},
+ {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:15910ef4f3e537eea7fe45f8a5d19997479940d9196f357152a09031c5be59f3"},
+ {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:370445fd795706fd291ab00c9df38a0caed0f17a6fb46b0f607668ecb16ce763"},
+ {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-win32.whl", hash = "sha256:ecdf1a604009bd35c674b9225a8fa609e0282d9b896c03dd441a91e5f53b534e"},
+ {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-win_amd64.whl", hash = "sha256:f34019dced51047d6f70cb9383b2ae2853b7fc4dce65129a5acd49f4f9256646"},
+ {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2aa261c29a5545adfef9296b7e33941f46aa5bbd21164228e833412af4c9c75f"},
+ {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-macosx_12_0_arm64.whl", hash = "sha256:f01da5790e95815eb5a8a138508c01c758e5f5bc0ce4286c4f7028b8dd7ac3d0"},
+ {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:40d030e2329ce5286d6b231b8726959ebbe0404c92f0a578c0e2482182e38282"},
+ {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:c3ca1fbba4ae962521e5eb66d72998b51f0f4d0f608d3c0347a48e1af262efa7"},
+ {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-win32.whl", hash = "sha256:7bdb4c06b063f6fd55e472e201317a3bb6cdeeee5d5a38512ea5c01e1acbdd93"},
+ {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-win_amd64.whl", hash = "sha256:be2a7ad8fd8f7442b24323d24ba0b56c51219513cfa45b9ada3b87b76c374d4b"},
+ {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:91a789b4aa0097b78c93e3dc4b40040ba55bef518f84a40d4442f713b4094acb"},
+ {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:99e77daab5d13a48a4054803d052ff40780278240a902b880dd37a51ba01a307"},
+ {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:3243f48ecd450eddadc2d11b5feb08aca941b5cd98c9b1db14b2fd128be8c697"},
+ {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:8831a2cedcd0f0927f788c5bdf6567d9dc9cc235646a434986a852af1cb54b4b"},
+ {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-win32.whl", hash = "sha256:3110a99e0f94a4a3470ff67fc20d3f96c25b13d24c6980ff841e82bafe827cac"},
+ {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-win_amd64.whl", hash = "sha256:92460ce908546ab69770b2e576e4f99fbb4ce6ab4b245345a3869a0a0410488f"},
+ {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5bc0667c1eb8f83a3752b71b9c4ba55ef7c7058ae57022dd9b29065186a113d9"},
+ {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:4a4d8d417868d68b979076a9be6a38c676eca060785abaa6709c7b31593c35d1"},
+ {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:bf9a6bc4a0221538b1a7de3ed7bca4c93c02346853f44e1cd764be0023cd3640"},
+ {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:a7b301ff08055d73223058b5c46c55638917f04d21577c95e00e0c4d79201a6b"},
+ {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-win32.whl", hash = "sha256:d5e51e2901ec2366b79f16c2299a03e74ba4531ddcfacc1416639c557aef0ad8"},
+ {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-win_amd64.whl", hash = "sha256:184faeaec61dbaa3cace407cffc5819f7b977e75360e8d5ca19461cd851a5fc5"},
+ {file = "ruamel.yaml.clib-0.2.7.tar.gz", hash = "sha256:1f08fd5a2bea9c4180db71678e850b995d2a5f4537be0e94557668cf0f5f9497"},
+]
+
+[[package]]
+name = "s3transfer"
+version = "0.6.1"
+description = "An Amazon S3 Transfer Manager"
+optional = false
+python-versions = ">= 3.7"
+files = [
+ {file = "s3transfer-0.6.1-py3-none-any.whl", hash = "sha256:3c0da2d074bf35d6870ef157158641178a4204a6e689e82546083e31e0311346"},
+ {file = "s3transfer-0.6.1.tar.gz", hash = "sha256:640bb492711f4c0c0905e1f62b6aaeb771881935ad27884852411f8e9cacbca9"},
+]
+
+[package.dependencies]
+botocore = ">=1.12.36,<2.0a.0"
+
+[package.extras]
+crt = ["botocore[crt] (>=1.20.29,<2.0a.0)"]
+
+[[package]]
+name = "semantic-version"
+version = "2.10.0"
+description = "A library implementing the 'SemVer' scheme."
+optional = false
+python-versions = ">=2.7"
+files = [
+ {file = "semantic_version-2.10.0-py2.py3-none-any.whl", hash = "sha256:de78a3b8e0feda74cabc54aab2da702113e33ac9d9eb9d2389bcf1f58b7d9177"},
+ {file = "semantic_version-2.10.0.tar.gz", hash = "sha256:bdabb6d336998cbb378d4b9db3a4b56a1e3235701dc05ea2690d9a997ed5041c"},
+]
+
+[package.extras]
+dev = ["Django (>=1.11)", "check-manifest", "colorama (<=0.4.1)", "coverage", "flake8", "nose2", "readme-renderer (<25.0)", "tox", "wheel", "zest.releaser[recommended]"]
+doc = ["Sphinx", "sphinx-rtd-theme"]
+
+[[package]]
+name = "setuptools"
+version = "68.0.0"
+description = "Easily download, build, install, upgrade, and uninstall Python packages"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "setuptools-68.0.0-py3-none-any.whl", hash = "sha256:11e52c67415a381d10d6b462ced9cfb97066179f0e871399e006c4ab101fc85f"},
+ {file = "setuptools-68.0.0.tar.gz", hash = "sha256:baf1fdb41c6da4cd2eae722e135500da913332ab3f2f5c7d33af9b492acb5235"},
+]
+
+[package.extras]
+docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
+testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
+testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"]
+
+[[package]]
+name = "sh"
+version = "1.14.3"
+description = "Python subprocess replacement"
+optional = false
+python-versions = "*"
+files = [
+ {file = "sh-1.14.3.tar.gz", hash = "sha256:e4045b6c732d9ce75d571c79f5ac2234edd9ae4f5fa9d59b09705082bdca18c7"},
+]
+
+[[package]]
+name = "shellingham"
+version = "1.5.0.post1"
+description = "Tool to Detect Surrounding Shell"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "shellingham-1.5.0.post1-py2.py3-none-any.whl", hash = "sha256:368bf8c00754fd4f55afb7bbb86e272df77e4dc76ac29dbcbb81a59e9fc15744"},
+ {file = "shellingham-1.5.0.post1.tar.gz", hash = "sha256:823bc5fb5c34d60f285b624e7264f4dda254bc803a3774a147bf99c0e3004a28"},
+]
+
+[[package]]
+name = "six"
+version = "1.16.0"
+description = "Python 2 and 3 compatibility utilities"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
+files = [
+ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
+ {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
+]
+
+[[package]]
+name = "snowballstemmer"
+version = "2.2.0"
+description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms."
+optional = false
+python-versions = "*"
+files = [
+ {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"},
+ {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"},
+]
+
+[[package]]
+name = "sphinx"
+version = "7.1.2"
+description = "Python documentation generator"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "sphinx-7.1.2-py3-none-any.whl", hash = "sha256:d170a81825b2fcacb6dfd5a0d7f578a053e45d3f2b153fecc948c37344eb4cbe"},
+ {file = "sphinx-7.1.2.tar.gz", hash = "sha256:780f4d32f1d7d1126576e0e5ecc19dc32ab76cd24e950228dcf7b1f6d3d9e22f"},
+]
+
+[package.dependencies]
+alabaster = ">=0.7,<0.8"
+babel = ">=2.9"
+colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""}
+docutils = ">=0.18.1,<0.21"
+imagesize = ">=1.3"
+importlib-metadata = {version = ">=4.8", markers = "python_version < \"3.10\""}
+Jinja2 = ">=3.0"
+packaging = ">=21.0"
+Pygments = ">=2.13"
+requests = ">=2.25.0"
+snowballstemmer = ">=2.0"
+sphinxcontrib-applehelp = "*"
+sphinxcontrib-devhelp = "*"
+sphinxcontrib-htmlhelp = ">=2.0.0"
+sphinxcontrib-jsmath = "*"
+sphinxcontrib-qthelp = "*"
+sphinxcontrib-serializinghtml = ">=1.1.5"
+
+[package.extras]
+docs = ["sphinxcontrib-websupport"]
+lint = ["docutils-stubs", "flake8 (>=3.5.0)", "flake8-simplify", "isort", "mypy (>=0.990)", "ruff", "sphinx-lint", "types-requests"]
+test = ["cython", "filelock", "html5lib", "pytest (>=4.6)"]
+
+[[package]]
+name = "sphinxcontrib-applehelp"
+version = "1.0.6"
+description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books"
+optional = false
+python-versions = ">=3.9"
+files = [
+ {file = "sphinxcontrib_applehelp-1.0.6-py3-none-any.whl", hash = "sha256:c0578efa23cab5a2f3aaa8af5691b952433f4fdfaac255befd3452448e7ea4a4"},
+ {file = "sphinxcontrib_applehelp-1.0.6.tar.gz", hash = "sha256:a59274de7a952a99af36b8a5092352d9249279c0e3280b7dceaae8e15873c942"},
+]
+
+[package.dependencies]
+Sphinx = ">=5"
+
+[package.extras]
+lint = ["docutils-stubs", "flake8", "mypy"]
+test = ["pytest"]
+
+[[package]]
+name = "sphinxcontrib-devhelp"
+version = "1.0.4"
+description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp documents"
+optional = false
+python-versions = ">=3.9"
+files = [
+ {file = "sphinxcontrib_devhelp-1.0.4-py3-none-any.whl", hash = "sha256:d4e20a17f78865d4096733989b5efa0d5e7743900e98e1f6ecd6f489380febc8"},
+ {file = "sphinxcontrib_devhelp-1.0.4.tar.gz", hash = "sha256:4fd751c63dc40895ac8740948f26bf1a3c87e4e441cc008672abd1cb2bc8a3d1"},
+]
+
+[package.dependencies]
+Sphinx = ">=5"
+
+[package.extras]
+lint = ["docutils-stubs", "flake8", "mypy"]
+test = ["pytest"]
+
+[[package]]
+name = "sphinxcontrib-htmlhelp"
+version = "2.0.3"
+description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files"
+optional = false
+python-versions = ">=3.9"
+files = [
+ {file = "sphinxcontrib_htmlhelp-2.0.3-py3-none-any.whl", hash = "sha256:abee4e6c5471203ad2fc40dc6a16ed99884a5d6b15a6f79c9269a7e82cf04149"},
+ {file = "sphinxcontrib_htmlhelp-2.0.3.tar.gz", hash = "sha256:14358d0f88ccf58447f2b54343cdcc0012f32de2f8d27cf934fdbc0b362f9597"},
+]
+
+[package.dependencies]
+Sphinx = ">=5"
+
+[package.extras]
+lint = ["docutils-stubs", "flake8", "mypy"]
+test = ["html5lib", "pytest"]
+
+[[package]]
+name = "sphinxcontrib-jsmath"
+version = "1.0.1"
+description = "A sphinx extension which renders display math in HTML via JavaScript"
+optional = false
+python-versions = ">=3.5"
+files = [
+ {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"},
+ {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"},
+]
+
+[package.extras]
+test = ["flake8", "mypy", "pytest"]
+
+[[package]]
+name = "sphinxcontrib-qthelp"
+version = "1.0.5"
+description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp documents"
+optional = false
+python-versions = ">=3.9"
+files = [
+ {file = "sphinxcontrib_qthelp-1.0.5-py3-none-any.whl", hash = "sha256:962730a6ad15d21fd6760b14c9e95c00a097413595aa6ee871dd9dfa4b002a16"},
+ {file = "sphinxcontrib_qthelp-1.0.5.tar.gz", hash = "sha256:d31d1a1beaf3894866bb318fb712f1edc82687f1c06235a01e5b2c50c36d5c40"},
+]
+
+[package.dependencies]
+Sphinx = ">=5"
+
+[package.extras]
+lint = ["docutils-stubs", "flake8", "mypy"]
+test = ["pytest"]
+
+[[package]]
+name = "sphinxcontrib-serializinghtml"
+version = "1.1.7"
+description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)"
+optional = false
+python-versions = ">=3.9"
+files = [
+ {file = "sphinxcontrib_serializinghtml-1.1.7-py3-none-any.whl", hash = "sha256:424164fc3a8b4355a29d5ea8b7f18199022d160c8f7b96e68bb6c50217729b87"},
+ {file = "sphinxcontrib_serializinghtml-1.1.7.tar.gz", hash = "sha256:ca31afee32e1508cff4034e258060ce2c81a3b1c49e77da60fdb61f0e7a73c22"},
+]
+
+[package.dependencies]
+Sphinx = ">=5"
+
+[package.extras]
+lint = ["docutils-stubs", "flake8", "mypy"]
+test = ["pytest"]
+
+[[package]]
+name = "subprocess-tee"
+version = "0.4.1"
+description = "subprocess-tee"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "subprocess-tee-0.4.1.tar.gz", hash = "sha256:b3c124993f8b88d1eb1c2fde0bc2069787eac720ba88771cba17e8c93324825d"},
+ {file = "subprocess_tee-0.4.1-py3-none-any.whl", hash = "sha256:eca56973a1c1237093c2055b2731bcaab784683b83f22c76f26e4c5763402e28"},
+]
+
+[package.extras]
+test = ["enrich (>=1.2.6)", "molecule (>=3.4.0)", "pytest (>=6.2.5)", "pytest-cov (>=2.12.1)", "pytest-plus (>=0.2)", "pytest-xdist (>=2.3.0)"]
+
+[[package]]
+name = "tomli"
+version = "2.0.1"
+description = "A lil' TOML parser"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
+ {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
+]
+
+[[package]]
+name = "tomlkit"
+version = "0.12.1"
+description = "Style preserving TOML library"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "tomlkit-0.12.1-py3-none-any.whl", hash = "sha256:712cbd236609acc6a3e2e97253dfc52d4c2082982a88f61b640ecf0817eab899"},
+ {file = "tomlkit-0.12.1.tar.gz", hash = "sha256:38e1ff8edb991273ec9f6181244a6a391ac30e9f5098e7535640ea6be97a7c86"},
+]
+
+[[package]]
+name = "twiggy"
+version = "0.5.1"
+description = "a Pythonic logger"
+optional = false
+python-versions = "*"
+files = [
+ {file = "Twiggy-0.5.1-py3-none-any.whl", hash = "sha256:014671fdff7538b7f2396ff01724937ef57e1ac0e08f688747afbbcdeec9f081"},
+ {file = "Twiggy-0.5.1.tar.gz", hash = "sha256:7938840275972f6ce89994a5bdfb0b84f0386301a043a960af6364952e78ffe4"},
+]
+
+[package.dependencies]
+six = "*"
+
+[[package]]
+name = "typer"
+version = "0.7.0"
+description = "Typer, build great CLIs. Easy to code. Based on Python type hints."
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "typer-0.7.0-py3-none-any.whl", hash = "sha256:b5e704f4e48ec263de1c0b3a2387cd405a13767d2f907f44c1a08cbad96f606d"},
+ {file = "typer-0.7.0.tar.gz", hash = "sha256:ff797846578a9f2a201b53442aedeb543319466870fbe1c701eab66dd7681165"},
+]
+
+[package.dependencies]
+click = ">=7.1.1,<9.0.0"
+colorama = {version = ">=0.4.3,<0.5.0", optional = true, markers = "extra == \"all\""}
+rich = {version = ">=10.11.0,<13.0.0", optional = true, markers = "extra == \"all\""}
+shellingham = {version = ">=1.3.0,<2.0.0", optional = true, markers = "extra == \"all\""}
+
+[package.extras]
+all = ["colorama (>=0.4.3,<0.5.0)", "rich (>=10.11.0,<13.0.0)", "shellingham (>=1.3.0,<2.0.0)"]
+dev = ["autoflake (>=1.3.1,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)", "pre-commit (>=2.17.0,<3.0.0)"]
+doc = ["cairosvg (>=2.5.2,<3.0.0)", "mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pillow (>=9.3.0,<10.0.0)"]
+test = ["black (>=22.3.0,<23.0.0)", "coverage (>=6.2,<7.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.910)", "pytest (>=4.4.0,<8.0.0)", "pytest-cov (>=2.10.0,<5.0.0)", "pytest-sugar (>=0.9.4,<0.10.0)", "pytest-xdist (>=1.32.0,<4.0.0)", "rich (>=10.11.0,<13.0.0)", "shellingham (>=1.3.0,<2.0.0)"]
+
+[[package]]
+name = "types-docutils"
+version = "0.19.1.9"
+description = "Typing stubs for docutils"
+optional = false
+python-versions = "*"
+files = [
+ {file = "types-docutils-0.19.1.9.tar.gz", hash = "sha256:1d029567e67c52992fd42aa968778bc10a5e445c8450fc751d672d6f50330a4a"},
+ {file = "types_docutils-0.19.1.9-py3-none-any.whl", hash = "sha256:556fb7ee19248aa482caa142a830c940b776b0f8c7577a98abe0977574546a1d"},
+]
+
+[[package]]
+name = "typing-extensions"
+version = "4.7.1"
+description = "Backported and Experimental Type Hints for Python 3.7+"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"},
+ {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"},
+]
+
+[[package]]
+name = "urllib3"
+version = "1.26.18"
+description = "HTTP library with thread-safe connection pooling, file post, and more."
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
+files = [
+ {file = "urllib3-1.26.18-py2.py3-none-any.whl", hash = "sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07"},
+ {file = "urllib3-1.26.18.tar.gz", hash = "sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0"},
+]
+
+[package.extras]
+brotli = ["brotli (==1.0.9)", "brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"]
+secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"]
+socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
+
+[[package]]
+name = "virtualenv"
+version = "20.24.2"
+description = "Virtual Python Environment builder"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "virtualenv-20.24.2-py3-none-any.whl", hash = "sha256:43a3052be36080548bdee0b42919c88072037d50d56c28bd3f853cbe92b953ff"},
+ {file = "virtualenv-20.24.2.tar.gz", hash = "sha256:fd8a78f46f6b99a67b7ec5cf73f92357891a7b3a40fd97637c27f854aae3b9e0"},
+]
+
+[package.dependencies]
+distlib = ">=0.3.7,<1"
+filelock = ">=3.12.2,<4"
+platformdirs = ">=3.9.1,<4"
+
+[package.extras]
+docs = ["furo (>=2023.5.20)", "proselint (>=0.13)", "sphinx (>=7.0.1)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"]
+test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"]
+
+[[package]]
+name = "wcmatch"
+version = "8.4.1"
+description = "Wildcard/glob file name matcher."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "wcmatch-8.4.1-py3-none-any.whl", hash = "sha256:3476cd107aba7b25ba1d59406938a47dc7eec6cfd0ad09ff77193f21a964dee7"},
+ {file = "wcmatch-8.4.1.tar.gz", hash = "sha256:b1f042a899ea4c458b7321da1b5e3331e3e0ec781583434de1301946ceadb943"},
+]
+
+[package.dependencies]
+bracex = ">=2.1.1"
+
+[[package]]
+name = "wrapt"
+version = "1.15.0"
+description = "Module for decorators, wrappers and monkey patching."
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
+files = [
+ {file = "wrapt-1.15.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ca1cccf838cd28d5a0883b342474c630ac48cac5df0ee6eacc9c7290f76b11c1"},
+ {file = "wrapt-1.15.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e826aadda3cae59295b95343db8f3d965fb31059da7de01ee8d1c40a60398b29"},
+ {file = "wrapt-1.15.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5fc8e02f5984a55d2c653f5fea93531e9836abbd84342c1d1e17abc4a15084c2"},
+ {file = "wrapt-1.15.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:96e25c8603a155559231c19c0349245eeb4ac0096fe3c1d0be5c47e075bd4f46"},
+ {file = "wrapt-1.15.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:40737a081d7497efea35ab9304b829b857f21558acfc7b3272f908d33b0d9d4c"},
+ {file = "wrapt-1.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:f87ec75864c37c4c6cb908d282e1969e79763e0d9becdfe9fe5473b7bb1e5f09"},
+ {file = "wrapt-1.15.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:1286eb30261894e4c70d124d44b7fd07825340869945c79d05bda53a40caa079"},
+ {file = "wrapt-1.15.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:493d389a2b63c88ad56cdc35d0fa5752daac56ca755805b1b0c530f785767d5e"},
+ {file = "wrapt-1.15.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:58d7a75d731e8c63614222bcb21dd992b4ab01a399f1f09dd82af17bbfc2368a"},
+ {file = "wrapt-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:21f6d9a0d5b3a207cdf7acf8e58d7d13d463e639f0c7e01d82cdb671e6cb7923"},
+ {file = "wrapt-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ce42618f67741d4697684e501ef02f29e758a123aa2d669e2d964ff734ee00ee"},
+ {file = "wrapt-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41d07d029dd4157ae27beab04d22b8e261eddfc6ecd64ff7000b10dc8b3a5727"},
+ {file = "wrapt-1.15.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54accd4b8bc202966bafafd16e69da9d5640ff92389d33d28555c5fd4f25ccb7"},
+ {file = "wrapt-1.15.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fbfbca668dd15b744418265a9607baa970c347eefd0db6a518aaf0cfbd153c0"},
+ {file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:76e9c727a874b4856d11a32fb0b389afc61ce8aaf281ada613713ddeadd1cfec"},
+ {file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e20076a211cd6f9b44a6be58f7eeafa7ab5720eb796975d0c03f05b47d89eb90"},
+ {file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a74d56552ddbde46c246b5b89199cb3fd182f9c346c784e1a93e4dc3f5ec9975"},
+ {file = "wrapt-1.15.0-cp310-cp310-win32.whl", hash = "sha256:26458da5653aa5b3d8dc8b24192f574a58984c749401f98fff994d41d3f08da1"},
+ {file = "wrapt-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:75760a47c06b5974aa5e01949bf7e66d2af4d08cb8c1d6516af5e39595397f5e"},
+ {file = "wrapt-1.15.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ba1711cda2d30634a7e452fc79eabcadaffedf241ff206db2ee93dd2c89a60e7"},
+ {file = "wrapt-1.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:56374914b132c702aa9aa9959c550004b8847148f95e1b824772d453ac204a72"},
+ {file = "wrapt-1.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a89ce3fd220ff144bd9d54da333ec0de0399b52c9ac3d2ce34b569cf1a5748fb"},
+ {file = "wrapt-1.15.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3bbe623731d03b186b3d6b0d6f51865bf598587c38d6f7b0be2e27414f7f214e"},
+ {file = "wrapt-1.15.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3abbe948c3cbde2689370a262a8d04e32ec2dd4f27103669a45c6929bcdbfe7c"},
+ {file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b67b819628e3b748fd3c2192c15fb951f549d0f47c0449af0764d7647302fda3"},
+ {file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7eebcdbe3677e58dd4c0e03b4f2cfa346ed4049687d839adad68cc38bb559c92"},
+ {file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:74934ebd71950e3db69960a7da29204f89624dde411afbfb3b4858c1409b1e98"},
+ {file = "wrapt-1.15.0-cp311-cp311-win32.whl", hash = "sha256:bd84395aab8e4d36263cd1b9308cd504f6cf713b7d6d3ce25ea55670baec5416"},
+ {file = "wrapt-1.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:a487f72a25904e2b4bbc0817ce7a8de94363bd7e79890510174da9d901c38705"},
+ {file = "wrapt-1.15.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:4ff0d20f2e670800d3ed2b220d40984162089a6e2c9646fdb09b85e6f9a8fc29"},
+ {file = "wrapt-1.15.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9ed6aa0726b9b60911f4aed8ec5b8dd7bf3491476015819f56473ffaef8959bd"},
+ {file = "wrapt-1.15.0-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:896689fddba4f23ef7c718279e42f8834041a21342d95e56922e1c10c0cc7afb"},
+ {file = "wrapt-1.15.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:75669d77bb2c071333417617a235324a1618dba66f82a750362eccbe5b61d248"},
+ {file = "wrapt-1.15.0-cp35-cp35m-win32.whl", hash = "sha256:fbec11614dba0424ca72f4e8ba3c420dba07b4a7c206c8c8e4e73f2e98f4c559"},
+ {file = "wrapt-1.15.0-cp35-cp35m-win_amd64.whl", hash = "sha256:fd69666217b62fa5d7c6aa88e507493a34dec4fa20c5bd925e4bc12fce586639"},
+ {file = "wrapt-1.15.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b0724f05c396b0a4c36a3226c31648385deb6a65d8992644c12a4963c70326ba"},
+ {file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbeccb1aa40ab88cd29e6c7d8585582c99548f55f9b2581dfc5ba68c59a85752"},
+ {file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38adf7198f8f154502883242f9fe7333ab05a5b02de7d83aa2d88ea621f13364"},
+ {file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:578383d740457fa790fdf85e6d346fda1416a40549fe8db08e5e9bd281c6a475"},
+ {file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:a4cbb9ff5795cd66f0066bdf5947f170f5d63a9274f99bdbca02fd973adcf2a8"},
+ {file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:af5bd9ccb188f6a5fdda9f1f09d9f4c86cc8a539bd48a0bfdc97723970348418"},
+ {file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b56d5519e470d3f2fe4aa7585f0632b060d532d0696c5bdfb5e8319e1d0f69a2"},
+ {file = "wrapt-1.15.0-cp36-cp36m-win32.whl", hash = "sha256:77d4c1b881076c3ba173484dfa53d3582c1c8ff1f914c6461ab70c8428b796c1"},
+ {file = "wrapt-1.15.0-cp36-cp36m-win_amd64.whl", hash = "sha256:077ff0d1f9d9e4ce6476c1a924a3332452c1406e59d90a2cf24aeb29eeac9420"},
+ {file = "wrapt-1.15.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5c5aa28df055697d7c37d2099a7bc09f559d5053c3349b1ad0c39000e611d317"},
+ {file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a8564f283394634a7a7054b7983e47dbf39c07712d7b177b37e03f2467a024e"},
+ {file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780c82a41dc493b62fc5884fb1d3a3b81106642c5c5c78d6a0d4cbe96d62ba7e"},
+ {file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e169e957c33576f47e21864cf3fc9ff47c223a4ebca8960079b8bd36cb014fd0"},
+ {file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b02f21c1e2074943312d03d243ac4388319f2456576b2c6023041c4d57cd7019"},
+ {file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f2e69b3ed24544b0d3dbe2c5c0ba5153ce50dcebb576fdc4696d52aa22db6034"},
+ {file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d787272ed958a05b2c86311d3a4135d3c2aeea4fc655705f074130aa57d71653"},
+ {file = "wrapt-1.15.0-cp37-cp37m-win32.whl", hash = "sha256:02fce1852f755f44f95af51f69d22e45080102e9d00258053b79367d07af39c0"},
+ {file = "wrapt-1.15.0-cp37-cp37m-win_amd64.whl", hash = "sha256:abd52a09d03adf9c763d706df707c343293d5d106aea53483e0ec8d9e310ad5e"},
+ {file = "wrapt-1.15.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cdb4f085756c96a3af04e6eca7f08b1345e94b53af8921b25c72f096e704e145"},
+ {file = "wrapt-1.15.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:230ae493696a371f1dbffaad3dafbb742a4d27a0afd2b1aecebe52b740167e7f"},
+ {file = "wrapt-1.15.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63424c681923b9f3bfbc5e3205aafe790904053d42ddcc08542181a30a7a51bd"},
+ {file = "wrapt-1.15.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6bcbfc99f55655c3d93feb7ef3800bd5bbe963a755687cbf1f490a71fb7794b"},
+ {file = "wrapt-1.15.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c99f4309f5145b93eca6e35ac1a988f0dc0a7ccf9ccdcd78d3c0adf57224e62f"},
+ {file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b130fe77361d6771ecf5a219d8e0817d61b236b7d8b37cc045172e574ed219e6"},
+ {file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:96177eb5645b1c6985f5c11d03fc2dbda9ad24ec0f3a46dcce91445747e15094"},
+ {file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5fe3e099cf07d0fb5a1e23d399e5d4d1ca3e6dfcbe5c8570ccff3e9208274f7"},
+ {file = "wrapt-1.15.0-cp38-cp38-win32.whl", hash = "sha256:abd8f36c99512755b8456047b7be10372fca271bf1467a1caa88db991e7c421b"},
+ {file = "wrapt-1.15.0-cp38-cp38-win_amd64.whl", hash = "sha256:b06fa97478a5f478fb05e1980980a7cdf2712015493b44d0c87606c1513ed5b1"},
+ {file = "wrapt-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2e51de54d4fb8fb50d6ee8327f9828306a959ae394d3e01a1ba8b2f937747d86"},
+ {file = "wrapt-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0970ddb69bba00670e58955f8019bec4a42d1785db3faa043c33d81de2bf843c"},
+ {file = "wrapt-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76407ab327158c510f44ded207e2f76b657303e17cb7a572ffe2f5a8a48aa04d"},
+ {file = "wrapt-1.15.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cd525e0e52a5ff16653a3fc9e3dd827981917d34996600bbc34c05d048ca35cc"},
+ {file = "wrapt-1.15.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d37ac69edc5614b90516807de32d08cb8e7b12260a285ee330955604ed9dd29"},
+ {file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:078e2a1a86544e644a68422f881c48b84fef6d18f8c7a957ffd3f2e0a74a0d4a"},
+ {file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:2cf56d0e237280baed46f0b5316661da892565ff58309d4d2ed7dba763d984b8"},
+ {file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7dc0713bf81287a00516ef43137273b23ee414fe41a3c14be10dd95ed98a2df9"},
+ {file = "wrapt-1.15.0-cp39-cp39-win32.whl", hash = "sha256:46ed616d5fb42f98630ed70c3529541408166c22cdfd4540b88d5f21006b0eff"},
+ {file = "wrapt-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:eef4d64c650f33347c1f9266fa5ae001440b232ad9b98f1f43dfe7a79435c0a6"},
+ {file = "wrapt-1.15.0-py3-none-any.whl", hash = "sha256:64b1df0f83706b4ef4cfb4fb0e4c2669100fd7ecacfb59e091fad300d4e04640"},
+ {file = "wrapt-1.15.0.tar.gz", hash = "sha256:d06730c6aed78cee4126234cf2d071e01b44b915e725a6cb439a879ec9754a3a"},
+]
+
+[[package]]
+name = "yamllint"
+version = "1.32.0"
+description = "A linter for YAML files."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "yamllint-1.32.0-py3-none-any.whl", hash = "sha256:d97a66e48da820829d96077d76b8dfbe6c6140f106e558dae87e81ac4e6b30b7"},
+ {file = "yamllint-1.32.0.tar.gz", hash = "sha256:d01dde008c65de5b235188ab3110bebc59d18e5c65fc8a58267cd211cd9df34a"},
+]
+
+[package.dependencies]
+pathspec = ">=0.5.3"
+pyyaml = "*"
+
+[package.extras]
+dev = ["doc8", "flake8", "flake8-import-order", "rstcheck[sphinx]", "sphinx"]
+
+[[package]]
+name = "yarl"
+version = "1.9.2"
+description = "Yet another URL library"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "yarl-1.9.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8c2ad583743d16ddbdf6bb14b5cd76bf43b0d0006e918809d5d4ddf7bde8dd82"},
+ {file = "yarl-1.9.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:82aa6264b36c50acfb2424ad5ca537a2060ab6de158a5bd2a72a032cc75b9eb8"},
+ {file = "yarl-1.9.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c0c77533b5ed4bcc38e943178ccae29b9bcf48ffd1063f5821192f23a1bd27b9"},
+ {file = "yarl-1.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee4afac41415d52d53a9833ebae7e32b344be72835bbb589018c9e938045a560"},
+ {file = "yarl-1.9.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9bf345c3a4f5ba7f766430f97f9cc1320786f19584acc7086491f45524a551ac"},
+ {file = "yarl-1.9.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2a96c19c52ff442a808c105901d0bdfd2e28575b3d5f82e2f5fd67e20dc5f4ea"},
+ {file = "yarl-1.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:891c0e3ec5ec881541f6c5113d8df0315ce5440e244a716b95f2525b7b9f3608"},
+ {file = "yarl-1.9.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c3a53ba34a636a256d767c086ceb111358876e1fb6b50dfc4d3f4951d40133d5"},
+ {file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:566185e8ebc0898b11f8026447eacd02e46226716229cea8db37496c8cdd26e0"},
+ {file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:2b0738fb871812722a0ac2154be1f049c6223b9f6f22eec352996b69775b36d4"},
+ {file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:32f1d071b3f362c80f1a7d322bfd7b2d11e33d2adf395cc1dd4df36c9c243095"},
+ {file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:e9fdc7ac0d42bc3ea78818557fab03af6181e076a2944f43c38684b4b6bed8e3"},
+ {file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:56ff08ab5df8429901ebdc5d15941b59f6253393cb5da07b4170beefcf1b2528"},
+ {file = "yarl-1.9.2-cp310-cp310-win32.whl", hash = "sha256:8ea48e0a2f931064469bdabca50c2f578b565fc446f302a79ba6cc0ee7f384d3"},
+ {file = "yarl-1.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:50f33040f3836e912ed16d212f6cc1efb3231a8a60526a407aeb66c1c1956dde"},
+ {file = "yarl-1.9.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:646d663eb2232d7909e6601f1a9107e66f9791f290a1b3dc7057818fe44fc2b6"},
+ {file = "yarl-1.9.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:aff634b15beff8902d1f918012fc2a42e0dbae6f469fce134c8a0dc51ca423bb"},
+ {file = "yarl-1.9.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a83503934c6273806aed765035716216cc9ab4e0364f7f066227e1aaea90b8d0"},
+ {file = "yarl-1.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b25322201585c69abc7b0e89e72790469f7dad90d26754717f3310bfe30331c2"},
+ {file = "yarl-1.9.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:22a94666751778629f1ec4280b08eb11815783c63f52092a5953faf73be24191"},
+ {file = "yarl-1.9.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ec53a0ea2a80c5cd1ab397925f94bff59222aa3cf9c6da938ce05c9ec20428d"},
+ {file = "yarl-1.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:159d81f22d7a43e6eabc36d7194cb53f2f15f498dbbfa8edc8a3239350f59fe7"},
+ {file = "yarl-1.9.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:832b7e711027c114d79dffb92576acd1bd2decc467dec60e1cac96912602d0e6"},
+ {file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:95d2ecefbcf4e744ea952d073c6922e72ee650ffc79028eb1e320e732898d7e8"},
+ {file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:d4e2c6d555e77b37288eaf45b8f60f0737c9efa3452c6c44626a5455aeb250b9"},
+ {file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:783185c75c12a017cc345015ea359cc801c3b29a2966c2655cd12b233bf5a2be"},
+ {file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:b8cc1863402472f16c600e3e93d542b7e7542a540f95c30afd472e8e549fc3f7"},
+ {file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:822b30a0f22e588b32d3120f6d41e4ed021806418b4c9f0bc3048b8c8cb3f92a"},
+ {file = "yarl-1.9.2-cp311-cp311-win32.whl", hash = "sha256:a60347f234c2212a9f0361955007fcf4033a75bf600a33c88a0a8e91af77c0e8"},
+ {file = "yarl-1.9.2-cp311-cp311-win_amd64.whl", hash = "sha256:be6b3fdec5c62f2a67cb3f8c6dbf56bbf3f61c0f046f84645cd1ca73532ea051"},
+ {file = "yarl-1.9.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:38a3928ae37558bc1b559f67410df446d1fbfa87318b124bf5032c31e3447b74"},
+ {file = "yarl-1.9.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac9bb4c5ce3975aeac288cfcb5061ce60e0d14d92209e780c93954076c7c4367"},
+ {file = "yarl-1.9.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3da8a678ca8b96c8606bbb8bfacd99a12ad5dd288bc6f7979baddd62f71c63ef"},
+ {file = "yarl-1.9.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:13414591ff516e04fcdee8dc051c13fd3db13b673c7a4cb1350e6b2ad9639ad3"},
+ {file = "yarl-1.9.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf74d08542c3a9ea97bb8f343d4fcbd4d8f91bba5ec9d5d7f792dbe727f88938"},
+ {file = "yarl-1.9.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e7221580dc1db478464cfeef9b03b95c5852cc22894e418562997df0d074ccc"},
+ {file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:494053246b119b041960ddcd20fd76224149cfea8ed8777b687358727911dd33"},
+ {file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:52a25809fcbecfc63ac9ba0c0fb586f90837f5425edfd1ec9f3372b119585e45"},
+ {file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:e65610c5792870d45d7b68c677681376fcf9cc1c289f23e8e8b39c1485384185"},
+ {file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:1b1bba902cba32cdec51fca038fd53f8beee88b77efc373968d1ed021024cc04"},
+ {file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:662e6016409828ee910f5d9602a2729a8a57d74b163c89a837de3fea050c7582"},
+ {file = "yarl-1.9.2-cp37-cp37m-win32.whl", hash = "sha256:f364d3480bffd3aa566e886587eaca7c8c04d74f6e8933f3f2c996b7f09bee1b"},
+ {file = "yarl-1.9.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6a5883464143ab3ae9ba68daae8e7c5c95b969462bbe42e2464d60e7e2698368"},
+ {file = "yarl-1.9.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5610f80cf43b6202e2c33ba3ec2ee0a2884f8f423c8f4f62906731d876ef4fac"},
+ {file = "yarl-1.9.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b9a4e67ad7b646cd6f0938c7ebfd60e481b7410f574c560e455e938d2da8e0f4"},
+ {file = "yarl-1.9.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:83fcc480d7549ccebe9415d96d9263e2d4226798c37ebd18c930fce43dfb9574"},
+ {file = "yarl-1.9.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5fcd436ea16fee7d4207c045b1e340020e58a2597301cfbcfdbe5abd2356c2fb"},
+ {file = "yarl-1.9.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84e0b1599334b1e1478db01b756e55937d4614f8654311eb26012091be109d59"},
+ {file = "yarl-1.9.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3458a24e4ea3fd8930e934c129b676c27452e4ebda80fbe47b56d8c6c7a63a9e"},
+ {file = "yarl-1.9.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:838162460b3a08987546e881a2bfa573960bb559dfa739e7800ceeec92e64417"},
+ {file = "yarl-1.9.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f4e2d08f07a3d7d3e12549052eb5ad3eab1c349c53ac51c209a0e5991bbada78"},
+ {file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:de119f56f3c5f0e2fb4dee508531a32b069a5f2c6e827b272d1e0ff5ac040333"},
+ {file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:149ddea5abf329752ea5051b61bd6c1d979e13fbf122d3a1f9f0c8be6cb6f63c"},
+ {file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:674ca19cbee4a82c9f54e0d1eee28116e63bc6fd1e96c43031d11cbab8b2afd5"},
+ {file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:9b3152f2f5677b997ae6c804b73da05a39daa6a9e85a512e0e6823d81cdad7cc"},
+ {file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5415d5a4b080dc9612b1b63cba008db84e908b95848369aa1da3686ae27b6d2b"},
+ {file = "yarl-1.9.2-cp38-cp38-win32.whl", hash = "sha256:f7a3d8146575e08c29ed1cd287068e6d02f1c7bdff8970db96683b9591b86ee7"},
+ {file = "yarl-1.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:63c48f6cef34e6319a74c727376e95626f84ea091f92c0250a98e53e62c77c72"},
+ {file = "yarl-1.9.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:75df5ef94c3fdc393c6b19d80e6ef1ecc9ae2f4263c09cacb178d871c02a5ba9"},
+ {file = "yarl-1.9.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c027a6e96ef77d401d8d5a5c8d6bc478e8042f1e448272e8d9752cb0aff8b5c8"},
+ {file = "yarl-1.9.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f3b078dbe227f79be488ffcfc7a9edb3409d018e0952cf13f15fd6512847f3f7"},
+ {file = "yarl-1.9.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59723a029760079b7d991a401386390c4be5bfec1e7dd83e25a6a0881859e716"},
+ {file = "yarl-1.9.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b03917871bf859a81ccb180c9a2e6c1e04d2f6a51d953e6a5cdd70c93d4e5a2a"},
+ {file = "yarl-1.9.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c1012fa63eb6c032f3ce5d2171c267992ae0c00b9e164efe4d73db818465fac3"},
+ {file = "yarl-1.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a74dcbfe780e62f4b5a062714576f16c2f3493a0394e555ab141bf0d746bb955"},
+ {file = "yarl-1.9.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8c56986609b057b4839968ba901944af91b8e92f1725d1a2d77cbac6972b9ed1"},
+ {file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2c315df3293cd521033533d242d15eab26583360b58f7ee5d9565f15fee1bef4"},
+ {file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:b7232f8dfbd225d57340e441d8caf8652a6acd06b389ea2d3222b8bc89cbfca6"},
+ {file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:53338749febd28935d55b41bf0bcc79d634881195a39f6b2f767870b72514caf"},
+ {file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:066c163aec9d3d073dc9ffe5dd3ad05069bcb03fcaab8d221290ba99f9f69ee3"},
+ {file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8288d7cd28f8119b07dd49b7230d6b4562f9b61ee9a4ab02221060d21136be80"},
+ {file = "yarl-1.9.2-cp39-cp39-win32.whl", hash = "sha256:b124e2a6d223b65ba8768d5706d103280914d61f5cae3afbc50fc3dfcc016623"},
+ {file = "yarl-1.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:61016e7d582bc46a5378ffdd02cd0314fb8ba52f40f9cf4d9a5e7dbef88dee18"},
+ {file = "yarl-1.9.2.tar.gz", hash = "sha256:04ab9d4b9f587c06d801c2abfe9317b77cdf996c65a90d5e84ecc45010823571"},
+]
+
+[package.dependencies]
+idna = ">=2.0"
+multidict = ">=4.0"
+
+[[package]]
+name = "zipp"
+version = "3.16.2"
+description = "Backport of pathlib-compatible object wrapper for zip files"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "zipp-3.16.2-py3-none-any.whl", hash = "sha256:679e51dd4403591b2d6838a48de3d283f3d188412a9782faadf845f298736ba0"},
+ {file = "zipp-3.16.2.tar.gz", hash = "sha256:ebc15946aa78bd63458992fc81ec3b6f7b1e92d51c35e6de1c3804e73b799147"},
+]
+
+[package.extras]
+docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
+testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"]
+
+[metadata]
+lock-version = "2.0"
+python-versions = "~3.9"
+content-hash = "634c4528f212eaad456177a3a24492e43de58adf152f08f855cf71ae7f2889f3"
diff --git a/ansible_collections/community/digitalocean/pyproject.toml b/ansible_collections/community/digitalocean/pyproject.toml
new file mode 100644
index 000000000..aae8e9005
--- /dev/null
+++ b/ansible_collections/community/digitalocean/pyproject.toml
@@ -0,0 +1,27 @@
+[tool.poetry]
+name = "digitalocean"
+version = "0.0.1"
+description = "Ansible Community DigitalOcean Collection"
+authors = ["Mark Mercado <mmercado@digitalocean.com>"]
+license = "GPL-3.0"
+readme = "README.md"
+
+[tool.poetry.dependencies]
+python = "~3.9"
+ansible-core = "^2.15.8"
+boto3 = "^1.28.16"
+jmespath = "^1.0.1"
+
+[tool.poetry.group.dev.dependencies]
+ansible-lint = { version = "^6.16.2", markers = "platform_system != 'Windows'" }
+black = "^23.3.0"
+pre-commit = "^3.3.2"
+pylint = "^2.17.4"
+pytest = "^7.3.1"
+antsibull-changelog = "^0.22.0"
+antsibull-docs = "^2.3.1"
+pytest-mock = "^3.11.1"
+
+[build-system]
+requires = ["poetry-core"]
+build-backend = "poetry.core.masonry.api"
diff --git a/ansible_collections/community/digitalocean/scripts/inventory/digital_ocean.py b/ansible_collections/community/digitalocean/scripts/inventory/digital_ocean.py
index 1d5685c24..a896a0444 100755
--- a/ansible_collections/community/digitalocean/scripts/inventory/digital_ocean.py
+++ b/ansible_collections/community/digitalocean/scripts/inventory/digital_ocean.py
@@ -229,7 +229,6 @@ class DoManager:
class DigitalOceanInventory(object):
-
###########################################################################
# Main execution path
###########################################################################
diff --git a/ansible_collections/community/digitalocean/tests/integration/integration_config.yml.template b/ansible_collections/community/digitalocean/tests/integration/integration_config.yml.template
index d742bfd2a..9803b403c 100644
--- a/ansible_collections/community/digitalocean/tests/integration/integration_config.yml.template
+++ b/ansible_collections/community/digitalocean/tests/integration/integration_config.yml.template
@@ -2,3 +2,4 @@
do_api_key: ${DO_API_KEY}
aws_access_key_id: ${AWS_ACCESS_KEY_ID}
aws_secret_access_key: ${AWS_SECRET_ACCESS_KEY}
+pr_number: ${PR_NUMBER}
diff --git a/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_block_storage/defaults/main.yml b/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_block_storage/defaults/main.yml
index 0e52c2cb0..b9c97fa83 100644
--- a/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_block_storage/defaults/main.yml
+++ b/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_block_storage/defaults/main.yml
@@ -1,5 +1,5 @@
do_region: nyc1
-volume_name: gh-ci-volume
+volume_name: gh-ci-volume-0-{{ pr_number }}
volume_size: 15
volume_down_size: 10
volume_up_size: 20
diff --git a/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_cdn_endpoints/aliases b/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_cdn_endpoints/aliases
index e69de29bb..7a68b11da 100644
--- a/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_cdn_endpoints/aliases
+++ b/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_cdn_endpoints/aliases
@@ -0,0 +1 @@
+disabled
diff --git a/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_domain_record_info/aliases b/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_domain_record_info/aliases
index e69de29bb..7a68b11da 100644
--- a/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_domain_record_info/aliases
+++ b/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_domain_record_info/aliases
@@ -0,0 +1 @@
+disabled
diff --git a/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_droplet/defaults/main.yml b/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_droplet/defaults/main.yml
index 312f53e85..9ab0fe9ec 100644
--- a/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_droplet/defaults/main.yml
+++ b/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_droplet/defaults/main.yml
@@ -1,6 +1,6 @@
do_region: nyc1
-droplet_name: gh-ci-droplet
-droplet_image: ubuntu-18-04-x64
+droplet_name: gh-ci-droplet-0-{{ pr_number }}
+droplet_image: ubuntu-22-04-x64
droplet_size: s-1vcpu-1gb
droplet_new_size: s-1vcpu-2gb
project_name: gh-ci-project
diff --git a/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_droplet/tasks/main.yml b/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_droplet/tasks/main.yml
index 79177be26..69e0c7807 100644
--- a/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_droplet/tasks/main.yml
+++ b/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_droplet/tasks/main.yml
@@ -439,8 +439,8 @@
ansible.builtin.assert:
that:
- firewall_settings is defined
- - "{{ (firewall_settings.data | map(attribute='droplet_ids'))[0] | length > 0 }}"
- - "{{ firewall_droplet.data.droplet.id }} in {{ (firewall_settings.data | map(attribute='droplet_ids'))[0] }}"
+ - (firewall_settings.data | map(attribute='droplet_ids'))[0] | length > 0
+ - firewall_droplet.data.droplet.id in (firewall_settings.data | map(attribute='droplet_ids'))[0]
- name: Rerun on above droplet without removing firewall
community.digitalocean.digital_ocean_droplet:
@@ -490,8 +490,8 @@
ansible.builtin.assert:
that:
- firewall_settings_removal is defined
- - "{{ (firewall_settings_removal.data | map(attribute='droplet_ids'))[0] | length == 0 }}"
- - "{{ firewall_droplet.data.droplet.id }} not in {{ firewall_settings_removal.data | map(attribute='droplet_ids') }}"
+ - (firewall_settings_removal.data | map(attribute='droplet_ids'))[0] | length == 0
+ - firewall_droplet.data.droplet.id not in (firewall_settings_removal.data | map(attribute='droplet_ids'))
always:
diff --git a/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_floating_ip/defaults/main.yml b/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_floating_ip/defaults/main.yml
index 30cbae2de..f80c4eed9 100644
--- a/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_floating_ip/defaults/main.yml
+++ b/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_floating_ip/defaults/main.yml
@@ -1,5 +1,5 @@
do_region: nyc1
-droplet_name: gh-ci-droplet
-droplet_image: ubuntu-18-04-x64
+droplet_name: gh-ci-droplet-1-{{ pr_number }}
+droplet_image: ubuntu-22-04-x64
droplet_size: s-1vcpu-1gb
project_name: gh-ci-project
diff --git a/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_kubernetes/defaults/main.yml b/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_kubernetes/defaults/main.yml
index 6dd5f7421..8b69c43c8 100644
--- a/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_kubernetes/defaults/main.yml
+++ b/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_kubernetes/defaults/main.yml
@@ -1,15 +1,16 @@
do_region: nyc1
+test_project_name: test-kubernetes
-cluster_name: gh-ci-k8s
+cluster_name: gh-ci-k8s-0-{{ pr_number }}
cluster_version: latest
cluster_node_pools:
- - name: gh-ci-k8s-workers
+ - name: gh-ci-k8s-workers-0-{{ pr_number }}
size: s-1vcpu-2gb
count: 1
-cluster_ha_name: gh-ci-ha-k8s
+cluster_ha_name: gh-ci-ha-k8s-1-{{ pr_number }}
cluster_ha_version: latest
cluster_ha_node_pools:
- - name: gh-ci-k8s-ha-workers
+ - name: gh-ci-k8s-ha-workers-1-{{ pr_number }}
size: s-1vcpu-2gb
count: 3
diff --git a/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_kubernetes/tasks/main.yml b/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_kubernetes/tasks/main.yml
index 4d605fa79..3635a824b 100644
--- a/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_kubernetes/tasks/main.yml
+++ b/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_kubernetes/tasks/main.yml
@@ -57,6 +57,28 @@
- result.failed
- result.msg == "Kubernetes cluster not found"
+ - name: Ensure the test project is absent
+ community.digitalocean.digital_ocean_project:
+ oauth_token: "{{ do_api_key }}"
+ state: absent
+ name: "{{ test_project_name }}"
+ register: project
+
+ - name: Verify test project is absent
+ ansible.builtin.assert:
+ that:
+ - not project.changed
+
+ - name: Create test project
+ community.digitalocean.digital_ocean_project:
+ oauth_token: "{{ do_api_key }}"
+ state: present
+ name: "{{ test_project_name }}"
+ purpose: Just trying out DigitalOcean
+ description: This is a test project
+ environment: Development
+ register: project
+
- name: Create the Kubernetes cluster
community.digitalocean.digital_ocean_kubernetes:
oauth_token: "{{ do_api_key }}"
@@ -65,6 +87,7 @@
version: "{{ cluster_version }}"
region: "{{ do_region }}"
node_pools: "{{ cluster_node_pools }}"
+ project_name: "{{ test_project_name }}"
return_kubeconfig: false
wait_timeout: 600
register: result
@@ -74,6 +97,8 @@
that:
- result.changed
- result.data.name == cluster_name
+ - result.data.kubeconfig is defined
+ - result.data.kubeconfig | length > 0
- name: Gather information about the Kubernetes cluster
community.digitalocean.digital_ocean_kubernetes_info:
@@ -103,6 +128,19 @@
- result.data.kubeconfig is defined
- result.data.kubeconfig | length > 0
+ - name: Get test project resources
+ community.digitalocean.digital_ocean_project_resource_info:
+ oauth_token: "{{ do_api_key }}"
+ name: "{{ test_project_name }}"
+ register: resources
+
+ - name: Verify kubernetes cluster is present
+ ansible.builtin.assert:
+ that:
+ - resources.data is defined
+ - resources.data | length == 1
+ - resources.data[0].urn == 'do:kubernetes:' + result.data.id
+
- name: Give the cloud a minute to settle
ansible.builtin.pause:
minutes: 1
@@ -227,3 +265,10 @@
return_kubeconfig: false
wait_timeout: 600
ignore_errors: true # Should this fail, we'll clean it up next run
+
+ - name: Delete test project
+ community.digitalocean.digital_ocean_project:
+ oauth_token: "{{ do_api_key }}"
+ state: absent
+ name: "{{ test_project_name }}"
+ ignore_errors: true # Should this fail, we'll clean it up next run
diff --git a/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_kubernetes_info/defaults/main.yml b/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_kubernetes_info/defaults/main.yml
index c1f5ba32b..905687a30 100644
--- a/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_kubernetes_info/defaults/main.yml
+++ b/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_kubernetes_info/defaults/main.yml
@@ -1,8 +1,8 @@
do_region: nyc1
-cluster_name: gh-ci-k8s
+cluster_name: gh-ci-k8s-2-{{ pr_number }}
cluster_version: latest
cluster_node_pools:
- - name: gh-ci-k8s-workers
+ - name: gh-ci-k8s-workers-2-{{ pr_number }}
size: s-1vcpu-2gb
count: 1
diff --git a/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_kubernetes_info/tasks/main.yml b/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_kubernetes_info/tasks/main.yml
index a0787f33a..4648e40be 100644
--- a/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_kubernetes_info/tasks/main.yml
+++ b/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_kubernetes_info/tasks/main.yml
@@ -16,8 +16,7 @@
register: result
ignore_errors: true # expected to fail
- - name: Verify Kubernetes cluster information is not found
+ - name: Verify Kubernetes cluster information is not changed
ansible.builtin.assert:
that:
- not result.changed
- - not result.data.name is defined
diff --git a/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_load_balancer/defaults/main.yml b/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_load_balancer/defaults/main.yml
index a2386cb7f..d1649b1dd 100644
--- a/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_load_balancer/defaults/main.yml
+++ b/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_load_balancer/defaults/main.yml
@@ -1,6 +1,6 @@
do_region: nyc1
-droplet_name: gh-ci-droplet
-droplet_image: ubuntu-18-04-x64
+droplet_name: gh-ci-droplet-2-{{ pr_number }}
+droplet_image: ubuntu-22-04-x64
droplet_size: s-1vcpu-1gb
lb_name: gh-ci-loadbalancer
lb_size: lb-small
diff --git a/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_monitoring_alerts/aliases b/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_monitoring_alerts/aliases
index e69de29bb..7a68b11da 100644
--- a/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_monitoring_alerts/aliases
+++ b/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_monitoring_alerts/aliases
@@ -0,0 +1 @@
+disabled
diff --git a/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_monitoring_alerts/defaults/main.yml b/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_monitoring_alerts/defaults/main.yml
index c25f2f804..f3267faac 100644
--- a/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_monitoring_alerts/defaults/main.yml
+++ b/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_monitoring_alerts/defaults/main.yml
@@ -1,5 +1,5 @@
do_region: nyc1
-droplet_name: gh-ci-droplet
-droplet_image: ubuntu-18-04-x64
+droplet_name: gh-ci-droplet-3-{{ pr_number }}
+droplet_image: ubuntu-22-04-x64
droplet_size: s-1vcpu-1gb
alert_email: mamercad@gmail.com
diff --git a/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_project_resource_info/aliases b/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_project_resource_info/aliases
new file mode 100644
index 000000000..7a68b11da
--- /dev/null
+++ b/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_project_resource_info/aliases
@@ -0,0 +1 @@
+disabled
diff --git a/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_project_resource_info/defaults/main.yml b/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_project_resource_info/defaults/main.yml
new file mode 100644
index 000000000..8b54ada0a
--- /dev/null
+++ b/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_project_resource_info/defaults/main.yml
@@ -0,0 +1,2 @@
+---
+test_project_name: test-project-resources
diff --git a/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_project_resource_info/tasks/main.yml b/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_project_resource_info/tasks/main.yml
new file mode 100644
index 000000000..3b311898e
--- /dev/null
+++ b/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_project_resource_info/tasks/main.yml
@@ -0,0 +1,156 @@
+---
+- block:
+
+ - name: Ensure API key is provided
+ ansible.builtin.fail:
+ msg: do_api_key should be defined in tests/integration/integration_config.yml
+ when:
+ - do_api_key is not defined
+ - do_api_key | length == 0
+
+ - name: Ensure the project is absent
+ community.digitalocean.digital_ocean_project:
+ oauth_token: "{{ do_api_key }}"
+ state: absent
+ name: "{{ test_project_name }}"
+ register: project
+
+ - name: Verify project is absent
+ ansible.builtin.assert:
+ that:
+ - not project.changed
+
+ - name: Create test project
+ community.digitalocean.digital_ocean_project:
+ oauth_token: "{{ do_api_key }}"
+ state: present
+ name: "{{ test_project_name }}"
+ purpose: Just trying out DigitalOcean
+ description: This is a test project
+ environment: Development
+ register: project
+
+ - name: Create some resource (block storage)
+ community.digitalocean.digital_ocean_block_storage:
+ state: present
+ oauth_token: "{{ do_api_key }}"
+ command: create
+ region: fra1
+ block_size: 1
+ volume_name: fra1-test-project-resources
+ project: "{{ test_project_name }}"
+ register: resource
+
+ - name: Get project resources by name
+ community.digitalocean.digital_ocean_project_resource_info:
+ oauth_token: "{{ do_api_key }}"
+ name: "{{ test_project_name }}"
+ register: resources
+
+ - name: Verify resource is present
+ ansible.builtin.assert:
+ that:
+ - resources.data is defined
+ - resources.data | length == 1
+ - resources.data[0].urn == resource.resources.urn
+
+ - name: Get project resources by id
+ community.digitalocean.digital_ocean_project_resource_info:
+ oauth_token: "{{ do_api_key }}"
+ id: "{{ project.data.project.id }}"
+ register: resources
+
+ - name: Verify resource is present
+ ansible.builtin.assert:
+ that:
+ - resources.data is defined
+ - resources.data | length == 1
+ - resources.data[0].urn == resource.resources.urn
+
+ - name: Get all projects
+ community.digitalocean.digital_ocean_project_info:
+ oauth_token: "{{ do_api_key }}"
+ register: projects
+
+ - name: Extract currently default project
+ ansible.builtin.set_fact:
+ default_project: "{{ projects.data | selectattr('is_default') | first }}"
+
+ - name: Make test project default one
+ community.digitalocean.digital_ocean_project:
+ oauth_token: "{{ do_api_key }}"
+ state: present
+ name: "{{ project.data.project.name }}"
+ purpose: "{{ project.data.project.purpose }}"
+ description: "{{ project.data.project.description }}"
+ environment: "{{ project.data.project.environment }}"
+ is_default: true
+ register: project
+
+ - name: Get project resources of default
+ community.digitalocean.digital_ocean_project_resource_info:
+ oauth_token: "{{ do_api_key }}"
+ register: resources
+
+ - name: Verify resource is present
+ ansible.builtin.assert:
+ that:
+ - resources.data is defined
+ - resources.data | length == 1
+ - resources.data[0].urn == resource.resources.urn
+
+ - name: Get project resources by name
+ community.digitalocean.digital_ocean_project_resource_info:
+ oauth_token: "{{ do_api_key }}"
+ name: "{{ test_project_name }}"
+ register: resources
+
+ - name: Verify resource is present
+ ansible.builtin.assert:
+ that:
+ - resources.data is defined
+ - resources.data | length == 1
+ - resources.data[0].urn == resource.resources.urn
+
+ - name: Get project resources by id
+ community.digitalocean.digital_ocean_project_resource_info:
+ oauth_token: "{{ do_api_key }}"
+ id: "{{ project.data.project.id }}"
+ register: resources
+
+ - name: Verify resource is present
+ ansible.builtin.assert:
+ that:
+ - resources.data is defined
+ - resources.data | length == 1
+ - resources.data[0].urn == resource.resources.urn
+
+ - name: Change back default project
+ community.digitalocean.digital_ocean_project:
+ oauth_token: "{{ do_api_key }}"
+ state: present
+ name: "{{ default_project.name }}"
+ purpose: "{{ default_project.purpose }}"
+ description: "{{ default_project.description }}"
+ environment: "{{ default_project.environment }}"
+ is_default: true
+ register: default_project
+
+ always:
+
+ - name: Delete the resource (block storage)
+ community.digitalocean.digital_ocean_block_storage:
+ state: absent
+ oauth_token: "{{ do_api_key }}"
+ command: create
+ region: fra1
+ volume_name: fra1-test-project-resources
+ project: "{{ test_project_name }}"
+ ignore_errors: true # Should this fail, we'll clean it up next run
+
+ - name: Delete test project
+ community.digitalocean.digital_ocean_project:
+ oauth_token: "{{ do_api_key }}"
+ state: absent
+ name: "{{ test_project_name }}"
+ ignore_errors: true # Should this fail, we'll clean it up next run
diff --git a/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_snapshot/defaults/main.yml b/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_snapshot/defaults/main.yml
index d1396ae47..ad696e889 100644
--- a/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_snapshot/defaults/main.yml
+++ b/ansible_collections/community/digitalocean/tests/integration/targets/digital_ocean_snapshot/defaults/main.yml
@@ -1,9 +1,9 @@
do_region: nyc1
-droplet_name: gh-ci-droplet
-droplet_image: ubuntu-18-04-x64
+droplet_name: gh-ci-droplet-4-{{ pr_number }}
+droplet_image: ubuntu-22-04-x64
droplet_size: s-1vcpu-1gb
snapshot_name: gh-ci-snapshot
-volume_name: gh-ci-volume
+volume_name: gh-ci-volume-4-{{ pr_number }}
volume_size: 15
volume_down_size: 10
volume_up_size: 20
diff --git a/ansible_collections/community/digitalocean/tests/unit/plugins/inventory/test_digitalocean.py b/ansible_collections/community/digitalocean/tests/unit/plugins/inventory/test_digitalocean.py
index 340f36109..2f9062699 100644
--- a/ansible_collections/community/digitalocean/tests/unit/plugins/inventory/test_digitalocean.py
+++ b/ansible_collections/community/digitalocean/tests/unit/plugins/inventory/test_digitalocean.py
@@ -8,7 +8,7 @@ __metaclass__ = type
import pytest
-from ansible.errors import AnsibleError, AnsibleParserError
+from ansible.errors import AnsibleError
from ansible.inventory.data import InventoryData
from ansible.template import Templar
from ansible.parsing.dataloader import DataLoader
@@ -208,7 +208,7 @@ def test_populate_groups_sanitization(inventory, mocker, transform):
def get_option_with_templated_api_token(option):
options = {
# "random_choice" with just a single input always returns the same result.
- "api_token": '{{ lookup("random_choice", "my-do-token") }}',
+ "oauth_token": '{{ lookup("random_choice", "my-do-token") }}',
"pagination": 100,
}
return options.get(option)
diff --git a/ansible_collections/community/digitalocean/tests/unit/plugins/modules/test_digital_ocean_kubernetes.py b/ansible_collections/community/digitalocean/tests/unit/plugins/modules/test_digital_ocean_kubernetes.py
index cfb0f59b6..e919aa450 100644
--- a/ansible_collections/community/digitalocean/tests/unit/plugins/modules/test_digital_ocean_kubernetes.py
+++ b/ansible_collections/community/digitalocean/tests/unit/plugins/modules/test_digital_ocean_kubernetes.py
@@ -4,6 +4,7 @@ __metaclass__ = type
from ansible_collections.community.general.tests.unit.compat import unittest
from ansible_collections.community.general.tests.unit.compat.mock import MagicMock
+from ansible_collections.community.general.tests.unit.compat.mock import DEFAULT
from ansible_collections.community.digitalocean.plugins.modules.digital_ocean_kubernetes import (
DOKubernetes,
)
@@ -12,6 +13,7 @@ from ansible_collections.community.digitalocean.plugins.modules.digital_ocean_ku
class TestDOKubernetes(unittest.TestCase):
def test_get_by_id_when_ok(self):
module = MagicMock()
+ module.params.get.return_value = False
k = DOKubernetes(module)
k.rest = MagicMock()
k.rest.get = MagicMock()
@@ -21,6 +23,7 @@ class TestDOKubernetes(unittest.TestCase):
def test_get_by_id_when_not_ok(self):
module = MagicMock()
+ module.params.get.return_value = False
k = DOKubernetes(module)
k.rest = MagicMock()
k.rest.get = MagicMock()
@@ -30,6 +33,7 @@ class TestDOKubernetes(unittest.TestCase):
def test_get_all_clusters_when_ok(self):
module = MagicMock()
+ module.params.get.return_value = False
k = DOKubernetes(module)
k.rest = MagicMock()
k.rest.get = MagicMock()
@@ -39,6 +43,7 @@ class TestDOKubernetes(unittest.TestCase):
def test_get_all_clusters_when_not_ok(self):
module = MagicMock()
+ module.params.get.return_value = False
k = DOKubernetes(module)
k.rest = MagicMock()
k.rest.get = MagicMock()
@@ -48,11 +53,13 @@ class TestDOKubernetes(unittest.TestCase):
def test_get_by_name_none(self):
module = MagicMock()
+ module.params.get.return_value = False
k = DOKubernetes(module)
self.assertIsNone(k.get_by_name(None))
def test_get_by_name_found(self):
module = MagicMock()
+ module.params.get.return_value = False
k = DOKubernetes(module)
k.get_all_clusters = MagicMock()
k.get_all_clusters.return_value = {"kubernetes_clusters": [{"name": "foo"}]}
@@ -60,6 +67,7 @@ class TestDOKubernetes(unittest.TestCase):
def test_get_by_name_not_found(self):
module = MagicMock()
+ module.params.get.return_value = False
k = DOKubernetes(module)
k.get_all_clusters = MagicMock()
k.get_all_clusters.return_value = {"kubernetes_clusters": [{"name": "foo"}]}
@@ -67,6 +75,7 @@ class TestDOKubernetes(unittest.TestCase):
def test_get_kubernetes_kubeconfig_when_ok(self):
module = MagicMock()
+ module.params.get.return_value = False
k = DOKubernetes(module)
k.rest = MagicMock()
k.rest.get = MagicMock()
@@ -76,6 +85,7 @@ class TestDOKubernetes(unittest.TestCase):
def test_get_kubernetes_kubeconfig_when_not_ok(self):
module = MagicMock()
+ module.params.get.return_value = False
k = DOKubernetes(module)
k.rest = MagicMock()
k.rest.get = MagicMock()
@@ -85,6 +95,7 @@ class TestDOKubernetes(unittest.TestCase):
def test_get_kubernetes_when_found(self):
module = MagicMock()
+ module.params.get.return_value = False
k = DOKubernetes(module)
k.get_by_name = MagicMock()
k.get_by_name.return_value = {"id": 42}
@@ -92,6 +103,7 @@ class TestDOKubernetes(unittest.TestCase):
def test_get_kubernetes_when_not_found(self):
module = MagicMock()
+ module.params.get.return_value = False
k = DOKubernetes(module)
k.get_by_name = MagicMock()
k.get_by_name.return_value = None
@@ -99,6 +111,7 @@ class TestDOKubernetes(unittest.TestCase):
def test_get_kubernetes_options_when_ok(self):
module = MagicMock()
+ module.params.get.return_value = False
k = DOKubernetes(module)
k.rest = MagicMock()
k.rest.get = MagicMock()
@@ -108,6 +121,7 @@ class TestDOKubernetes(unittest.TestCase):
def test_get_kubernetes_options_when_not_ok(self):
module = MagicMock()
+ module.params.get.return_value = False
k = DOKubernetes(module)
k.rest = MagicMock()
k.rest.get = MagicMock()
@@ -117,6 +131,7 @@ class TestDOKubernetes(unittest.TestCase):
def test_ensure_running_when_running(self):
module = MagicMock()
+ module.params.get.return_value = False
module.fail_json = MagicMock()
k = DOKubernetes(module)
@@ -137,6 +152,7 @@ class TestDOKubernetes(unittest.TestCase):
def test_ensure_running_when_not_running(self):
module = MagicMock()
+ module.params.get.return_value = False
module.fail_json = MagicMock()
k = DOKubernetes(module)
@@ -158,14 +174,19 @@ class TestDOKubernetes(unittest.TestCase):
def test_create_ok(self):
module = MagicMock()
+
+ def side_effect(*args, **kwargs):
+ if "project_name" == args[0]:
+ return False
+ if "regions" == args[0]:
+ return "nyc1"
+ return DEFAULT
+
+ module.params.get.side_effect = side_effect
module.exit_json = MagicMock()
module.fail_json = MagicMock()
k = DOKubernetes(module)
- k.module = MagicMock()
- k.module.params = MagicMock()
-
- k.module.params.return_value = {"region": "nyc1"}
k.get_kubernetes_options = MagicMock()
@@ -190,21 +211,25 @@ class TestDOKubernetes(unittest.TestCase):
k.rest.post.return_value.status_code = 200
k.ensure_running = MagicMock()
k.cluster_id = MagicMock()
- k.module = MagicMock()
k.create()
k.module.exit_json.assert_called()
def test_create_not_ok(self):
module = MagicMock()
+
+ def side_effect(*args, **kwargs):
+ if "project_name" == args[0]:
+ return False
+ if "regions" == args[0]:
+ return "nyc1"
+ return DEFAULT
+
+ module.params.get.side_effect = side_effect
module.exit_json = MagicMock()
module.fail_json = MagicMock()
k = DOKubernetes(module)
- k.module = MagicMock()
- k.module.params = MagicMock()
-
- k.module.params.return_value = {"region": "nyc1"}
k.get_kubernetes_options = MagicMock()
@@ -229,13 +254,13 @@ class TestDOKubernetes(unittest.TestCase):
k.rest.post.return_value.status_code = 400
k.ensure_running = MagicMock()
k.cluster_id = MagicMock()
- k.module = MagicMock()
k.create()
k.module.exit_json.assert_called()
def test_delete_ok(self):
module = MagicMock()
+ module.params.get.return_value = False
module.exit_json = MagicMock()
k = DOKubernetes(module)
@@ -252,6 +277,7 @@ class TestDOKubernetes(unittest.TestCase):
def test_delete_not_ok(self):
module = MagicMock()
+ module.params.get.return_value = False
module.exit_json = MagicMock()
k = DOKubernetes(module)
diff --git a/ansible_collections/community/dns/.github/workflows/ansible-test.yml b/ansible_collections/community/dns/.github/workflows/ansible-test.yml
index 6de639005..7ed813e13 100644
--- a/ansible_collections/community/dns/.github/workflows/ansible-test.yml
+++ b/ansible_collections/community/dns/.github/workflows/ansible-test.yml
@@ -36,6 +36,7 @@ jobs:
- stable-2.13
- stable-2.14
- stable-2.15
+ - stable-2.16
- devel
# Ansible-test on various stable branches does not yet work well with cgroups v2.
# Since ubuntu-latest now uses Ubuntu 22.04, we need to fall back to the ubuntu-20.04
@@ -76,6 +77,7 @@ jobs:
- stable-2.13
- stable-2.14
- stable-2.15
+ - stable-2.16
- devel
steps:
@@ -89,6 +91,8 @@ jobs:
# NOTE: we're installing with git to work around Galaxy being a huge PITA (https://github.com/ansible/galaxy/issues/2429)
pre-test-cmd: >-
git clone --depth=1 --single-branch https://github.com/ansible-collections/community.internal_test_tools.git ../../community/internal_test_tools
+ ;
+ tests/unit/replace-requirements.sh requirements-${{ matrix.ansible }}.txt
integration:
# Ansible-test on various stable branches does not yet work well with cgroups v2.
@@ -107,13 +111,12 @@ jobs:
ansible:
- devel
python:
- - 2.7
- - 3.6
- 3.7
- 3.8
- 3.9
- "3.10"
- "3.11"
+ - "3.12"
include:
# 2.9
- ansible: stable-2.9
@@ -139,10 +142,13 @@ jobs:
python: "3.9"
# 2.15
- ansible: stable-2.15
+ python: "3.7"
+ # 2.16
+ - ansible: stable-2.16
python: "2.7"
- - ansible: stable-2.15
- python: "3.5"
- - ansible: stable-2.15
+ - ansible: stable-2.16
+ python: "3.6"
+ - ansible: stable-2.16
python: "3.11"
steps:
@@ -158,6 +164,6 @@ jobs:
integration-retry-on-error: 'true'
# NOTE: we're installing with git to work around Galaxy being a huge PITA (https://github.com/ansible/galaxy/issues/2429)
pre-test-cmd: >-
- git clone --depth=1 --single-branch https://github.com/ansible-collections/community.general.git ../../community/general
+ tests/integration/replace-requirements.sh requirements-${{ matrix.ansible }}.txt
target-python-version: ${{ matrix.python }}
testing-type: integration
diff --git a/ansible_collections/community/dns/.github/workflows/check-psl.yml b/ansible_collections/community/dns/.github/workflows/check-psl.yml
index 145d47041..b4b6051fb 100644
--- a/ansible_collections/community/dns/.github/workflows/check-psl.yml
+++ b/ansible_collections/community/dns/.github/workflows/check-psl.yml
@@ -21,7 +21,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Update PSL (returns exit code 1 if something changed)
run: ./update-psl.sh
diff --git a/ansible_collections/community/dns/.github/workflows/ee.yml b/ansible_collections/community/dns/.github/workflows/ee.yml
index 90dcab306..9a2f1164b 100644
--- a/ansible_collections/community/dns/.github/workflows/ee.yml
+++ b/ansible_collections/community/dns/.github/workflows/ee.yml
@@ -46,6 +46,10 @@ jobs:
- name: ansible-core devel @ RHEL UBI 9
ansible_core: https://github.com/ansible/ansible/archive/devel.tar.gz
ansible_runner: ansible-runner
+ other_deps: |2
+ python_interpreter:
+ package_system: python3.11 python3.11-pip python3.11-wheel python3.11-cryptography
+ python_path: "/usr/bin/python3.11"
base_image: docker.io/redhat/ubi9:latest
pre_base: '"#"'
- name: ansible-core 2.15 @ Rocky Linux 9
@@ -77,12 +81,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
path: ansible_collections/${{ env.NAMESPACE }}/${{ env.COLLECTION_NAME }}
- name: Set up Python
- uses: actions/setup-python@v4
+ uses: actions/setup-python@v5
with:
python-version: '3.11'
diff --git a/ansible_collections/community/dns/.github/workflows/extra-tests.yml b/ansible_collections/community/dns/.github/workflows/extra-tests.yml
index 3f1625615..975404fa5 100644
--- a/ansible_collections/community/dns/.github/workflows/extra-tests.yml
+++ b/ansible_collections/community/dns/.github/workflows/extra-tests.yml
@@ -26,14 +26,14 @@ jobs:
steps:
- name: Check out code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
path: ansible_collections/${{env.NAMESPACE}}/${{env.COLLECTION_NAME}}
- name: Set up Python
- uses: actions/setup-python@v4
+ uses: actions/setup-python@v5
with:
- python-version: '3.10'
+ python-version: '3.11'
- name: Install ansible-core
run: pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check
diff --git a/ansible_collections/community/dns/.github/workflows/import-galaxy.yml b/ansible_collections/community/dns/.github/workflows/import-galaxy.yml
index 61b08e0f3..0c0ee402a 100644
--- a/ansible_collections/community/dns/.github/workflows/import-galaxy.yml
+++ b/ansible_collections/community/dns/.github/workflows/import-galaxy.yml
@@ -4,7 +4,7 @@
# SPDX-License-Identifier: GPL-3.0-or-later
name: import-galaxy
-on:
+'on':
# Run CI against all pushes (direct commits, also merged PRs) to main, and all Pull Requests
push:
branches:
@@ -12,77 +12,9 @@ on:
- stable-*
pull_request:
-env:
- # Adjust this to your collection
- NAMESPACE: community
- COLLECTION_NAME: dns
-
jobs:
- build-collection:
- name: Build collection artifact
- runs-on: ubuntu-latest
- steps:
- - name: Check out code
- uses: actions/checkout@v3
- with:
- path: ./checkout
-
- - name: Set up Python
- uses: actions/setup-python@v4
- with:
- python-version: '3.10'
-
- - name: Install ansible-core
- run: pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check
-
- - name: Make sure galaxy.yml has version entry
- run: >-
- python -c
- 'import yaml ;
- f = open("galaxy.yml", "rb") ;
- data = yaml.safe_load(f) ;
- f.close() ;
- data["version"] = data.get("version") or "0.0.1" ;
- f = open("galaxy.yml", "wb") ;
- f.write(yaml.dump(data).encode("utf-8")) ;
- f.close() ;
- '
- working-directory: ./checkout
-
- - name: Build collection
- run: ansible-galaxy collection build
- working-directory: ./checkout
-
- - name: Copy artifact into subdirectory
- run: mkdir ./artifact && mv ./checkout/${{ env.NAMESPACE }}-${{ env.COLLECTION_NAME }}-*.tar.gz ./artifact
-
- - name: Upload artifact
- uses: actions/upload-artifact@v3
- with:
- name: ${{ env.NAMESPACE }}-${{ env.COLLECTION_NAME }}-${{ github.sha }}
- path: ./artifact/
-
import-galaxy:
- name: Import artifact with Galaxy importer
- runs-on: ubuntu-latest
- needs:
- - build-collection
- steps:
- - name: Set up Python
- uses: actions/setup-python@v4
- with:
- python-version: '3.10'
-
- - name: Install ansible-core
- run: pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check
-
- - name: Install galaxy-importer
- run: pip install galaxy-importer --disable-pip-version-check
-
- - name: Download artifact
- uses: actions/download-artifact@v3
- with:
- name: ${{ env.NAMESPACE }}-${{ env.COLLECTION_NAME }}-${{ github.sha }}
-
- - name: Run Galaxy importer
- run: python -m galaxy_importer.main ${{ env.NAMESPACE }}-${{ env.COLLECTION_NAME }}-*.tar.gz
+ permissions:
+ contents: read
+ name: Test to import built collection artifact with Galaxy importer
+ uses: ansible-community/github-action-test-galaxy-import/.github/workflows/test-galaxy-import.yml@main
diff --git a/ansible_collections/community/dns/.github/workflows/reuse.yml b/ansible_collections/community/dns/.github/workflows/reuse.yml
index 8d9ebde8d..8064af149 100644
--- a/ansible_collections/community/dns/.github/workflows/reuse.yml
+++ b/ansible_collections/community/dns/.github/workflows/reuse.yml
@@ -21,12 +21,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- - name: Install dependencies
- run: |
- pip install reuse
-
- - name: Check REUSE compliance
- run: |
- reuse lint
+ - name: REUSE Compliance Check
+ uses: fsfe/reuse-action@v3
diff --git a/ansible_collections/community/dns/CHANGELOG.md b/ansible_collections/community/dns/CHANGELOG.md
new file mode 100644
index 000000000..fbce77c60
--- /dev/null
+++ b/ansible_collections/community/dns/CHANGELOG.md
@@ -0,0 +1,1013 @@
+# Community DNS Collection Release Notes
+
+**Topics**
+
+- <a href="#v2-8-3">v2\.8\.3</a>
+ - <a href="#release-summary">Release Summary</a>
+ - <a href="#bugfixes">Bugfixes</a>
+- <a href="#v2-8-2">v2\.8\.2</a>
+ - <a href="#release-summary-1">Release Summary</a>
+ - <a href="#security-fixes">Security Fixes</a>
+ - <a href="#bugfixes-1">Bugfixes</a>
+- <a href="#v2-8-1">v2\.8\.1</a>
+ - <a href="#release-summary-2">Release Summary</a>
+ - <a href="#bugfixes-2">Bugfixes</a>
+- <a href="#v2-8-0">v2\.8\.0</a>
+ - <a href="#release-summary-3">Release Summary</a>
+ - <a href="#minor-changes">Minor Changes</a>
+ - <a href="#deprecated-features">Deprecated Features</a>
+ - <a href="#bugfixes-3">Bugfixes</a>
+- <a href="#v2-7-0">v2\.7\.0</a>
+ - <a href="#release-summary-4">Release Summary</a>
+ - <a href="#minor-changes-1">Minor Changes</a>
+ - <a href="#bugfixes-4">Bugfixes</a>
+- <a href="#v2-6-4">v2\.6\.4</a>
+ - <a href="#release-summary-5">Release Summary</a>
+ - <a href="#bugfixes-5">Bugfixes</a>
+- <a href="#v2-6-3">v2\.6\.3</a>
+ - <a href="#release-summary-6">Release Summary</a>
+ - <a href="#bugfixes-6">Bugfixes</a>
+- <a href="#v2-6-2">v2\.6\.2</a>
+ - <a href="#release-summary-7">Release Summary</a>
+ - <a href="#bugfixes-7">Bugfixes</a>
+- <a href="#v2-6-1">v2\.6\.1</a>
+ - <a href="#release-summary-8">Release Summary</a>
+ - <a href="#bugfixes-8">Bugfixes</a>
+- <a href="#v2-6-0">v2\.6\.0</a>
+ - <a href="#release-summary-9">Release Summary</a>
+ - <a href="#minor-changes-2">Minor Changes</a>
+ - <a href="#bugfixes-9">Bugfixes</a>
+ - <a href="#new-plugins">New Plugins</a>
+ - <a href="#lookup">Lookup</a>
+ - <a href="#new-modules">New Modules</a>
+- <a href="#v2-5-7">v2\.5\.7</a>
+ - <a href="#release-summary-10">Release Summary</a>
+ - <a href="#bugfixes-10">Bugfixes</a>
+- <a href="#v2-5-6">v2\.5\.6</a>
+ - <a href="#release-summary-11">Release Summary</a>
+ - <a href="#known-issues">Known Issues</a>
+- <a href="#v2-5-5">v2\.5\.5</a>
+ - <a href="#release-summary-12">Release Summary</a>
+ - <a href="#bugfixes-11">Bugfixes</a>
+- <a href="#v2-5-4">v2\.5\.4</a>
+ - <a href="#release-summary-13">Release Summary</a>
+ - <a href="#bugfixes-12">Bugfixes</a>
+- <a href="#v2-5-3">v2\.5\.3</a>
+ - <a href="#release-summary-14">Release Summary</a>
+ - <a href="#bugfixes-13">Bugfixes</a>
+- <a href="#v2-5-2">v2\.5\.2</a>
+ - <a href="#release-summary-15">Release Summary</a>
+ - <a href="#bugfixes-14">Bugfixes</a>
+- <a href="#v2-5-1">v2\.5\.1</a>
+ - <a href="#release-summary-16">Release Summary</a>
+ - <a href="#bugfixes-15">Bugfixes</a>
+- <a href="#v2-5-0">v2\.5\.0</a>
+ - <a href="#release-summary-17">Release Summary</a>
+ - <a href="#minor-changes-3">Minor Changes</a>
+ - <a href="#deprecated-features-1">Deprecated Features</a>
+ - <a href="#bugfixes-16">Bugfixes</a>
+- <a href="#v2-4-2">v2\.4\.2</a>
+ - <a href="#release-summary-18">Release Summary</a>
+ - <a href="#bugfixes-17">Bugfixes</a>
+- <a href="#v2-4-1">v2\.4\.1</a>
+ - <a href="#release-summary-19">Release Summary</a>
+ - <a href="#bugfixes-18">Bugfixes</a>
+- <a href="#v2-4-0">v2\.4\.0</a>
+ - <a href="#release-summary-20">Release Summary</a>
+ - <a href="#minor-changes-4">Minor Changes</a>
+ - <a href="#bugfixes-19">Bugfixes</a>
+- <a href="#v2-3-4">v2\.3\.4</a>
+ - <a href="#release-summary-21">Release Summary</a>
+ - <a href="#bugfixes-20">Bugfixes</a>
+- <a href="#v2-3-3">v2\.3\.3</a>
+ - <a href="#release-summary-22">Release Summary</a>
+ - <a href="#bugfixes-21">Bugfixes</a>
+- <a href="#v2-3-2">v2\.3\.2</a>
+ - <a href="#release-summary-23">Release Summary</a>
+ - <a href="#bugfixes-22">Bugfixes</a>
+- <a href="#v2-3-1">v2\.3\.1</a>
+ - <a href="#release-summary-24">Release Summary</a>
+ - <a href="#minor-changes-5">Minor Changes</a>
+ - <a href="#bugfixes-23">Bugfixes</a>
+- <a href="#v2-3-0">v2\.3\.0</a>
+ - <a href="#release-summary-25">Release Summary</a>
+ - <a href="#minor-changes-6">Minor Changes</a>
+ - <a href="#bugfixes-24">Bugfixes</a>
+- <a href="#v2-2-1">v2\.2\.1</a>
+ - <a href="#release-summary-26">Release Summary</a>
+ - <a href="#bugfixes-25">Bugfixes</a>
+- <a href="#v2-2-0">v2\.2\.0</a>
+ - <a href="#release-summary-27">Release Summary</a>
+ - <a href="#minor-changes-7">Minor Changes</a>
+ - <a href="#bugfixes-26">Bugfixes</a>
+- <a href="#v2-1-1">v2\.1\.1</a>
+ - <a href="#release-summary-28">Release Summary</a>
+ - <a href="#bugfixes-27">Bugfixes</a>
+- <a href="#v2-1-0">v2\.1\.0</a>
+ - <a href="#release-summary-29">Release Summary</a>
+ - <a href="#minor-changes-8">Minor Changes</a>
+ - <a href="#bugfixes-28">Bugfixes</a>
+- <a href="#v2-0-9">v2\.0\.9</a>
+ - <a href="#release-summary-30">Release Summary</a>
+ - <a href="#bugfixes-29">Bugfixes</a>
+- <a href="#v2-0-8">v2\.0\.8</a>
+ - <a href="#release-summary-31">Release Summary</a>
+ - <a href="#bugfixes-30">Bugfixes</a>
+- <a href="#v2-0-7">v2\.0\.7</a>
+ - <a href="#release-summary-32">Release Summary</a>
+ - <a href="#bugfixes-31">Bugfixes</a>
+- <a href="#v2-0-6">v2\.0\.6</a>
+ - <a href="#release-summary-33">Release Summary</a>
+ - <a href="#bugfixes-32">Bugfixes</a>
+- <a href="#v2-0-5">v2\.0\.5</a>
+ - <a href="#release-summary-34">Release Summary</a>
+ - <a href="#bugfixes-33">Bugfixes</a>
+- <a href="#v2-0-4">v2\.0\.4</a>
+ - <a href="#release-summary-35">Release Summary</a>
+ - <a href="#bugfixes-34">Bugfixes</a>
+- <a href="#v2-0-3">v2\.0\.3</a>
+ - <a href="#release-summary-36">Release Summary</a>
+ - <a href="#minor-changes-9">Minor Changes</a>
+- <a href="#v2-0-2">v2\.0\.2</a>
+ - <a href="#release-summary-37">Release Summary</a>
+ - <a href="#bugfixes-35">Bugfixes</a>
+- <a href="#v2-0-1">v2\.0\.1</a>
+ - <a href="#release-summary-38">Release Summary</a>
+ - <a href="#bugfixes-36">Bugfixes</a>
+- <a href="#v2-0-0">v2\.0\.0</a>
+ - <a href="#release-summary-39">Release Summary</a>
+ - <a href="#minor-changes-10">Minor Changes</a>
+ - <a href="#breaking-changes--porting-guide">Breaking Changes / Porting Guide</a>
+ - <a href="#deprecated-features-2">Deprecated Features</a>
+ - <a href="#bugfixes-37">Bugfixes</a>
+ - <a href="#new-plugins-1">New Plugins</a>
+ - <a href="#inventory">Inventory</a>
+ - <a href="#new-modules-1">New Modules</a>
+- <a href="#v1-2-0">v1\.2\.0</a>
+ - <a href="#release-summary-40">Release Summary</a>
+ - <a href="#minor-changes-11">Minor Changes</a>
+ - <a href="#bugfixes-38">Bugfixes</a>
+- <a href="#v1-1-0">v1\.1\.0</a>
+ - <a href="#release-summary-41">Release Summary</a>
+ - <a href="#minor-changes-12">Minor Changes</a>
+ - <a href="#bugfixes-39">Bugfixes</a>
+- <a href="#v1-0-1">v1\.0\.1</a>
+ - <a href="#release-summary-42">Release Summary</a>
+ - <a href="#bugfixes-40">Bugfixes</a>
+- <a href="#v1-0-0">v1\.0\.0</a>
+ - <a href="#release-summary-43">Release Summary</a>
+ - <a href="#bugfixes-41">Bugfixes</a>
+- <a href="#v0-3-0">v0\.3\.0</a>
+ - <a href="#release-summary-44">Release Summary</a>
+ - <a href="#minor-changes-13">Minor Changes</a>
+ - <a href="#bugfixes-42">Bugfixes</a>
+ - <a href="#new-modules-2">New Modules</a>
+- <a href="#v0-2-0">v0\.2\.0</a>
+ - <a href="#release-summary-45">Release Summary</a>
+ - <a href="#major-changes">Major Changes</a>
+ - <a href="#minor-changes-14">Minor Changes</a>
+ - <a href="#breaking-changes--porting-guide-1">Breaking Changes / Porting Guide</a>
+ - <a href="#bugfixes-43">Bugfixes</a>
+ - <a href="#new-modules-3">New Modules</a>
+- <a href="#v0-1-0">v0\.1\.0</a>
+ - <a href="#release-summary-46">Release Summary</a>
+ - <a href="#new-plugins-2">New Plugins</a>
+ - <a href="#filter">Filter</a>
+ - <a href="#new-modules-4">New Modules</a>
+
+<a id="v2-8-3"></a>
+## v2\.8\.3
+
+<a id="release-summary"></a>
+### Release Summary
+
+Bugfix release\.
+
+<a id="bugfixes"></a>
+### Bugfixes
+
+* DNS record modules\, inventory plugins \- fix the TXT entry encoder to avoid splitting up escape sequences for quotes and backslashes over multiple TXT strings \([https\://github\.com/ansible\-collections/community\.dns/issues/190](https\://github\.com/ansible\-collections/community\.dns/issues/190)\, [https\://github\.com/ansible\-collections/community\.dns/pull/191](https\://github\.com/ansible\-collections/community\.dns/pull/191)\)\.
+* Update Public Suffix List\.
+
+<a id="v2-8-2"></a>
+## v2\.8\.2
+
+<a id="release-summary-1"></a>
+### Release Summary
+
+Bugfix release\.
+
+<a id="security-fixes"></a>
+### Security Fixes
+
+* hosttech\_dns\_records and hetzner\_dns\_records inventory plugins \- make sure all data received from the remote servers is marked as unsafe\, so remote code execution by obtaining texts that can be evaluated as templates is not possible \([https\://www\.die\-welt\.net/2024/03/remote\-code\-execution\-in\-ansible\-dynamic\-inventory\-plugins/](https\://www\.die\-welt\.net/2024/03/remote\-code\-execution\-in\-ansible\-dynamic\-inventory\-plugins/)\, [https\://github\.com/ansible\-collections/community\.dns/pull/189](https\://github\.com/ansible\-collections/community\.dns/pull/189)\)\.
+
+<a id="bugfixes-1"></a>
+### Bugfixes
+
+* Update Public Suffix List\.
+
+<a id="v2-8-1"></a>
+## v2\.8\.1
+
+<a id="release-summary-2"></a>
+### Release Summary
+
+Maintenance release with updated PSL\.
+
+<a id="bugfixes-2"></a>
+### Bugfixes
+
+* Update Public Suffix List\.
+
+<a id="v2-8-0"></a>
+## v2\.8\.0
+
+<a id="release-summary-3"></a>
+### Release Summary
+
+Feature and maintenance release with updated PSL\.
+
+<a id="minor-changes"></a>
+### Minor Changes
+
+* hetzner\_dns\_records and hosttech\_dns\_records inventory plugins \- the <code>filters</code> option has been renamed to <code>simple\_filters</code>\. The old name still works until community\.hrobot 2\.0\.0\. Then it will change to allow more complex filtering with the <code>community\.library\_inventory\_filtering\_v1</code> collection\'s functionality \([https\://github\.com/ansible\-collections/community\.dns/pull/181](https\://github\.com/ansible\-collections/community\.dns/pull/181)\)\.
+
+<a id="deprecated-features"></a>
+### Deprecated Features
+
+* hetzner\_dns\_records and hosttech\_dns\_records inventory plugins \- the <code>filters</code> option has been renamed to <code>simple\_filters</code>\. The old name will stop working in community\.hrobot 2\.0\.0 \([https\://github\.com/ansible\-collections/community\.dns/pull/181](https\://github\.com/ansible\-collections/community\.dns/pull/181)\)\.
+
+<a id="bugfixes-3"></a>
+### Bugfixes
+
+* Update Public Suffix List\.
+
+<a id="v2-7-0"></a>
+## v2\.7\.0
+
+<a id="release-summary-4"></a>
+### Release Summary
+
+Bugfix and feature release with updated PSL\.
+
+<a id="minor-changes-1"></a>
+### Minor Changes
+
+* nameserver\_info and nameserver\_record\_info \- add <code>server</code> parameter to specify custom DNS servers \([https\://github\.com/ansible\-collections/community\.dns/pull/168](https\://github\.com/ansible\-collections/community\.dns/pull/168)\, [https\://github\.com/ansible\-collections/community\.dns/pull/178](https\://github\.com/ansible\-collections/community\.dns/pull/178)\)\.
+* wait\_for\_txt \- add <code>server</code> parameter to specify custom DNS servers \([https\://github\.com/ansible\-collections/community\.dns/pull/178](https\://github\.com/ansible\-collections/community\.dns/pull/178)\)\.
+
+<a id="bugfixes-4"></a>
+### Bugfixes
+
+* Update Public Suffix List\.
+* wait\_for\_txt\, nameserver\_info\, nameserver\_record\_info \- when looking up nameservers for a domain\, do not treat <code>NXDOMAIN</code> as a fatal error \([https\://github\.com/ansible\-collections/community\.dns/pull/177](https\://github\.com/ansible\-collections/community\.dns/pull/177)\)\.
+
+<a id="v2-6-4"></a>
+## v2\.6\.4
+
+<a id="release-summary-5"></a>
+### Release Summary
+
+Bugfix and maintenance version\.
+
+<a id="bugfixes-5"></a>
+### Bugfixes
+
+* Update Public Suffix List\.
+* nameserver\_record\_info \- fix crash when more than one record is retrieved \([https\://github\.com/ansible\-collections/community\.dns/pull/172](https\://github\.com/ansible\-collections/community\.dns/pull/172)\)\.
+
+<a id="v2-6-3"></a>
+## v2\.6\.3
+
+<a id="release-summary-6"></a>
+### Release Summary
+
+Maintenance release with updated PSL\.
+
+<a id="bugfixes-6"></a>
+### Bugfixes
+
+* HTTP module utils \- make compatible with ansible\-core 2\.17 \([https\://github\.com/ansible\-collections/community\.dns/pull/165](https\://github\.com/ansible\-collections/community\.dns/pull/165)\)\.
+* Update Public Suffix List\.
+
+<a id="v2-6-2"></a>
+## v2\.6\.2
+
+<a id="release-summary-7"></a>
+### Release Summary
+
+Maintenance release with updated PSL\.
+
+<a id="bugfixes-7"></a>
+### Bugfixes
+
+* Update Public Suffix List\.
+
+<a id="v2-6-1"></a>
+## v2\.6\.1
+
+<a id="release-summary-8"></a>
+### Release Summary
+
+Maintenance release with updated PSL\.
+
+<a id="bugfixes-8"></a>
+### Bugfixes
+
+* Update Public Suffix List\.
+
+<a id="v2-6-0"></a>
+## v2\.6\.0
+
+<a id="release-summary-9"></a>
+### Release Summary
+
+Feature release with an updated Public Suffix List\.
+
+<a id="minor-changes-2"></a>
+### Minor Changes
+
+* wait\_for\_txt \- add <code>servfail\_retries</code> parameter that allows retrying after SERVFAIL errors \([https\://github\.com/ansible\-collections/community\.dns/pull/159](https\://github\.com/ansible\-collections/community\.dns/pull/159)\)\.
+* wait\_for\_txt\, resolver module utils \- use [EDNS](https\://en\.wikipedia\.org/wiki/Extension\_Mechanisms\_for\_DNS) \([https\://github\.com/ansible\-collections/community\.dns/pull/158](https\://github\.com/ansible\-collections/community\.dns/pull/158)\)\.
+
+<a id="bugfixes-9"></a>
+### Bugfixes
+
+* Update Public Suffix List\.
+* wait\_for\_txt\, resolver module utils \- improve error handling \([https\://github\.com/ansible\-collections/community\.dns/pull/158](https\://github\.com/ansible\-collections/community\.dns/pull/158)\)\.
+
+<a id="new-plugins"></a>
+### New Plugins
+
+<a id="lookup"></a>
+#### Lookup
+
+* community\.dns\.lookup \- Look up DNS records
+* community\.dns\.lookup\_as\_dict \- Look up DNS records as dictionaries
+
+<a id="new-modules"></a>
+### New Modules
+
+* community\.dns\.nameserver\_info \- Look up nameservers for a DNS name
+* community\.dns\.nameserver\_record\_info \- Look up all records of a type from all nameservers for a DNS name
+
+<a id="v2-5-7"></a>
+## v2\.5\.7
+
+<a id="release-summary-10"></a>
+### Release Summary
+
+Regular maintenance release with updated Public Suffix List\.
+
+<a id="bugfixes-10"></a>
+### Bugfixes
+
+* Update Public Suffix List\.
+
+<a id="v2-5-6"></a>
+## v2\.5\.6
+
+<a id="release-summary-11"></a>
+### Release Summary
+
+Maintenance release\.
+
+From this version on\, community\.dns is using the new [Ansible semantic markup](https\://docs\.ansible\.com/ansible/devel/dev\_guide/developing\_modules\_documenting\.html\#semantic\-markup\-within\-module\-documentation)
+in its documentation\. If you look at documentation with the ansible\-doc CLI tool
+from ansible\-core before 2\.15\, please note that it does not render the markup
+correctly\. You should be still able to read it in most cases\, but you need
+ansible\-core 2\.15 or later to see it as it is intended\. Alternatively you can
+look at [the devel docsite](https\://docs\.ansible\.com/ansible/devel/collections/community/dns/)
+for the rendered HTML version of the documentation of the latest release\.
+
+<a id="known-issues"></a>
+### Known Issues
+
+* Ansible markup will show up in raw form on ansible\-doc text output for ansible\-core before 2\.15\. If you have trouble deciphering the documentation markup\, please upgrade to ansible\-core 2\.15 \(or newer\)\, or read the HTML documentation on [https\://docs\.ansible\.com/ansible/devel/collections/community/dns/](https\://docs\.ansible\.com/ansible/devel/collections/community/dns/)\.
+
+<a id="v2-5-5"></a>
+## v2\.5\.5
+
+<a id="release-summary-12"></a>
+### Release Summary
+
+Maintenance release with updated PSL\.
+
+<a id="bugfixes-11"></a>
+### Bugfixes
+
+* Update Public Suffix List\.
+
+<a id="v2-5-4"></a>
+## v2\.5\.4
+
+<a id="release-summary-13"></a>
+### Release Summary
+
+Maintenance release with updated PSL\.
+
+<a id="bugfixes-12"></a>
+### Bugfixes
+
+* Update Public Suffix List\.
+
+<a id="v2-5-3"></a>
+## v2\.5\.3
+
+<a id="release-summary-14"></a>
+### Release Summary
+
+Maintenance release with updated PSL\.
+
+<a id="bugfixes-13"></a>
+### Bugfixes
+
+* Update Public Suffix List\.
+
+<a id="v2-5-2"></a>
+## v2\.5\.2
+
+<a id="release-summary-15"></a>
+### Release Summary
+
+Maintenance release with improved documentation and updated PSL\.
+
+<a id="bugfixes-14"></a>
+### Bugfixes
+
+* Update Public Suffix List\.
+
+<a id="v2-5-1"></a>
+## v2\.5\.1
+
+<a id="release-summary-16"></a>
+### Release Summary
+
+Maintenance release \(updated PSL\)\.
+
+<a id="bugfixes-15"></a>
+### Bugfixes
+
+* Update Public Suffix List\.
+
+<a id="v2-5-0"></a>
+## v2\.5\.0
+
+<a id="release-summary-17"></a>
+### Release Summary
+
+Feature and bugfix release with updated PSL\.
+
+<a id="minor-changes-3"></a>
+### Minor Changes
+
+* hosttech inventory plugin \- allow to configure token\, username\, and password with <code>ANSIBLE\_HOSTTECH\_DNS\_TOKEN</code>\, <code>ANSIBLE\_HOSTTECH\_API\_USERNAME</code>\, and <code>ANSIBLE\_HOSTTECH\_API\_PASSWORD</code> environment variables\, respectively \([https\://github\.com/ansible\-collections/community\.dns/pull/131](https\://github\.com/ansible\-collections/community\.dns/pull/131)\)\.
+* various modules and inventory plugins \- add new option <code>txt\_character\_encoding</code> which controls whether numeric escape sequences are interpreted as octals or decimals when <code>txt\_transformation\=quoted</code> \([https\://github\.com/ansible\-collections/community\.dns/pull/134](https\://github\.com/ansible\-collections/community\.dns/pull/134)\)\.
+
+<a id="deprecated-features-1"></a>
+### Deprecated Features
+
+* The default of the newly added option <code>txt\_character\_encoding</code> will change from <code>octal</code> to <code>decimal</code> in community\.dns 3\.0\.0\. The new default will be compatible with [RFC 1035](https\://www\.ietf\.org/rfc/rfc1035\.txt) \([https\://github\.com/ansible\-collections/community\.dns/pull/134](https\://github\.com/ansible\-collections/community\.dns/pull/134)\)\.
+
+<a id="bugfixes-16"></a>
+### Bugfixes
+
+* Update Public Suffix List\.
+* inventory plugins \- document <code>plugin</code> option used by the <code>ansible\.builtin\.auto</code> inventory plugin and mention required file ending in the documentation \([https\://github\.com/ansible\-collections/community\.dns/issues/130](https\://github\.com/ansible\-collections/community\.dns/issues/130)\, [https\://github\.com/ansible\-collections/community\.dns/pull/131](https\://github\.com/ansible\-collections/community\.dns/pull/131)\)\.
+
+<a id="v2-4-2"></a>
+## v2\.4\.2
+
+<a id="release-summary-18"></a>
+### Release Summary
+
+Maintenance release with updated Public Suffix List\.
+
+<a id="bugfixes-17"></a>
+### Bugfixes
+
+* Update Public Suffix List\.
+
+<a id="v2-4-1"></a>
+## v2\.4\.1
+
+<a id="release-summary-19"></a>
+### Release Summary
+
+Regular maintenance release\.
+
+<a id="bugfixes-18"></a>
+### Bugfixes
+
+* Update Public Suffix List\.
+* wait\_for\_txt \- also retrieve IPv6 addresses of nameservers\. Prevents failures with IPv6 only nameservers \([https\://github\.com/ansible\-collections/community\.dns/issues/120](https\://github\.com/ansible\-collections/community\.dns/issues/120)\, [https\://github\.com/ansible\-collections/community\.dns/pull/121](https\://github\.com/ansible\-collections/community\.dns/pull/121)\)\.
+
+<a id="v2-4-0"></a>
+## v2\.4\.0
+
+<a id="release-summary-20"></a>
+### Release Summary
+
+Feature and maintenance release\.
+
+<a id="minor-changes-4"></a>
+### Minor Changes
+
+* Added a <code>community\.dns\.hetzner</code> module defaults group / action group\. Use with <code>group/community\.dns\.hetzner</code> to provide options for all Hetzner DNS modules \([https\://github\.com/ansible\-collections/community\.dns/pull/119](https\://github\.com/ansible\-collections/community\.dns/pull/119)\)\.
+* Added a <code>community\.dns\.hosttech</code> module defaults group / action group\. Use with <code>group/community\.dns\.hosttech</code> to provide options for all Hosttech DNS modules \([https\://github\.com/ansible\-collections/community\.dns/pull/119](https\://github\.com/ansible\-collections/community\.dns/pull/119)\)\.
+* wait\_for\_txt \- the module now supports check mode\. The only practical change in behavior is that in check mode\, the module is now executed instead of skipped\. Since the module does not change anything\, it should have been marked as supporting check mode since it was originally added \([https\://github\.com/ansible\-collections/community\.dns/pull/119](https\://github\.com/ansible\-collections/community\.dns/pull/119)\)\.
+
+<a id="bugfixes-19"></a>
+### Bugfixes
+
+* Update Public Suffix List\.
+
+<a id="v2-3-4"></a>
+## v2\.3\.4
+
+<a id="release-summary-21"></a>
+### Release Summary
+
+Maintenance release with updated Public Suffix List\.
+
+<a id="bugfixes-20"></a>
+### Bugfixes
+
+* Update Public Suffix List\.
+
+<a id="v2-3-3"></a>
+## v2\.3\.3
+
+<a id="release-summary-22"></a>
+### Release Summary
+
+Maintenance release including an updated Public Suffix List\.
+
+<a id="bugfixes-21"></a>
+### Bugfixes
+
+* Update Public Suffix List\.
+
+<a id="v2-3-2"></a>
+## v2\.3\.2
+
+<a id="release-summary-23"></a>
+### Release Summary
+
+Maintenance release with updated Public Suffix List\.
+
+<a id="bugfixes-22"></a>
+### Bugfixes
+
+* Update Public Suffix List\.
+
+<a id="v2-3-1"></a>
+## v2\.3\.1
+
+<a id="release-summary-24"></a>
+### Release Summary
+
+Maintenance release including an updated Public Suffix List\.
+
+<a id="minor-changes-5"></a>
+### Minor Changes
+
+* The collection repository conforms to the [REUSE specification](https\://reuse\.software/spec/) except for the changelog fragments \([https\://github\.com/ansible\-collections/community\.dns/pull/112](https\://github\.com/ansible\-collections/community\.dns/pull/112)\)\.
+
+<a id="bugfixes-23"></a>
+### Bugfixes
+
+* Update Public Suffix List\.
+
+<a id="v2-3-0"></a>
+## v2\.3\.0
+
+<a id="release-summary-25"></a>
+### Release Summary
+
+Maintenance release including an updated Public Suffix List\.
+
+<a id="minor-changes-6"></a>
+### Minor Changes
+
+* All software licenses are now in the <code>LICENSES/</code> directory of the collection root\. Moreover\, <code>SPDX\-License\-Identifier\:</code> is used to declare the applicable license for every file that is not automatically generated \([https\://github\.com/ansible\-collections/community\.dns/pull/109](https\://github\.com/ansible\-collections/community\.dns/pull/109)\)\.
+
+<a id="bugfixes-24"></a>
+### Bugfixes
+
+* Update Public Suffix List\.
+
+<a id="v2-2-1"></a>
+## v2\.2\.1
+
+<a id="release-summary-26"></a>
+### Release Summary
+
+Maintenance release with updated Public Suffix List\.
+
+<a id="bugfixes-25"></a>
+### Bugfixes
+
+* Update Public Suffix List\.
+
+<a id="v2-2-0"></a>
+## v2\.2\.0
+
+<a id="release-summary-27"></a>
+### Release Summary
+
+Feature release\.
+
+<a id="minor-changes-7"></a>
+### Minor Changes
+
+* hetzner\_dns\_records and hosttech\_dns\_records inventory plugins \- allow to template provider\-specific credentials and the <code>zone\_name</code>\, <code>zone\_id</code> options \([https\://github\.com/ansible\-collections/community\.dns/pull/106](https\://github\.com/ansible\-collections/community\.dns/pull/106)\)\.
+* wait\_for\_txt \- improve error messages so that in case of SERVFAILs or other DNS errors it is clear which record was queried from which DNS server \([https\://github\.com/ansible\-collections/community\.dns/pull/105](https\://github\.com/ansible\-collections/community\.dns/pull/105)\)\.
+
+<a id="bugfixes-26"></a>
+### Bugfixes
+
+* Update Public Suffix List\.
+
+<a id="v2-1-1"></a>
+## v2\.1\.1
+
+<a id="release-summary-28"></a>
+### Release Summary
+
+Maintenance release with updated Public Suffix List\.
+
+<a id="bugfixes-27"></a>
+### Bugfixes
+
+* Update Public Suffix List\.
+
+<a id="v2-1-0"></a>
+## v2\.1\.0
+
+<a id="release-summary-29"></a>
+### Release Summary
+
+Feature and maintenance release with updated PSL\.
+
+<a id="minor-changes-8"></a>
+### Minor Changes
+
+* Prepare collection for inclusion in an Execution Environment by declaring its dependencies \([https\://github\.com/ansible\-collections/community\.dns/pull/93](https\://github\.com/ansible\-collections/community\.dns/pull/93)\)\.
+
+<a id="bugfixes-28"></a>
+### Bugfixes
+
+* Update Public Suffix List\.
+
+<a id="v2-0-9"></a>
+## v2\.0\.9
+
+<a id="release-summary-30"></a>
+### Release Summary
+
+Maintenance release with updated Public Suffix List and added collection links file\.
+
+<a id="bugfixes-29"></a>
+### Bugfixes
+
+* Update Public Suffix List\.
+
+<a id="v2-0-8"></a>
+## v2\.0\.8
+
+<a id="release-summary-31"></a>
+### Release Summary
+
+Maintenance release with updated Public Suffix List\.
+
+<a id="bugfixes-30"></a>
+### Bugfixes
+
+* Update Public Suffix List\.
+
+<a id="v2-0-7"></a>
+## v2\.0\.7
+
+<a id="release-summary-32"></a>
+### Release Summary
+
+Maintenance release with updated Public Suffix List\.
+
+<a id="bugfixes-31"></a>
+### Bugfixes
+
+* Update Public Suffix List\.
+
+<a id="v2-0-6"></a>
+## v2\.0\.6
+
+<a id="release-summary-33"></a>
+### Release Summary
+
+Bugfix release\.
+
+<a id="bugfixes-32"></a>
+### Bugfixes
+
+* Update Public Suffix List\.
+* wait\_for\_txt \- do not fail if <code>NXDOMAIN</code> result is returned\. Also do not succeed if no nameserver can be found \([https\://github\.com/ansible\-collections/community\.dns/issues/81](https\://github\.com/ansible\-collections/community\.dns/issues/81)\, [https\://github\.com/ansible\-collections/community\.dns/pull/82](https\://github\.com/ansible\-collections/community\.dns/pull/82)\)\.
+
+<a id="v2-0-5"></a>
+## v2\.0\.5
+
+<a id="release-summary-34"></a>
+### Release Summary
+
+Maintenance release with updated Public Suffix List\.
+
+<a id="bugfixes-33"></a>
+### Bugfixes
+
+* Update Public Suffix List\.
+
+<a id="v2-0-4"></a>
+## v2\.0\.4
+
+<a id="release-summary-35"></a>
+### Release Summary
+
+Maintenance release with updated Public Suffix List\.
+
+<a id="bugfixes-34"></a>
+### Bugfixes
+
+* Update Public Suffix List\.
+
+<a id="v2-0-3"></a>
+## v2\.0\.3
+
+<a id="release-summary-36"></a>
+### Release Summary
+
+Bugfix release\.
+
+<a id="minor-changes-9"></a>
+### Minor Changes
+
+* HTTP API module utils \- fix usage of <code>fetch\_url</code> with changes in latest ansible\-core <code>devel</code> branch \([https\://github\.com/ansible\-collections/community\.dns/pull/73](https\://github\.com/ansible\-collections/community\.dns/pull/73)\)\.
+
+<a id="v2-0-2"></a>
+## v2\.0\.2
+
+<a id="release-summary-37"></a>
+### Release Summary
+
+Regular maintenance release\.
+
+<a id="bugfixes-35"></a>
+### Bugfixes
+
+* Update Public Suffix List\.
+
+<a id="v2-0-1"></a>
+## v2\.0\.1
+
+<a id="release-summary-38"></a>
+### Release Summary
+
+Maintenance release with Public Suffix List updates\.
+
+<a id="bugfixes-36"></a>
+### Bugfixes
+
+* Update Public Suffix List\.
+
+<a id="v2-0-0"></a>
+## v2\.0\.0
+
+<a id="release-summary-39"></a>
+### Release Summary
+
+This release contains many new features\, modules and plugins\, but also has several breaking changes to the 1\.x\.y versions\. Please read the changelog carefully to determine what to change if you used an earlier version of this collection\.
+
+<a id="minor-changes-10"></a>
+### Minor Changes
+
+* Add support for Hetzner DNS \([https\://github\.com/ansible\-collections/community\.dns/pull/27](https\://github\.com/ansible\-collections/community\.dns/pull/27)\)\.
+* Added a <code>txt\_transformation</code> option to all modules and plugins working with DNS records \([https\://github\.com/ansible\-collections/community\.dns/issues/48](https\://github\.com/ansible\-collections/community\.dns/issues/48)\, [https\://github\.com/ansible\-collections/community\.dns/pull/57](https\://github\.com/ansible\-collections/community\.dns/pull/57)\, [https\://github\.com/ansible\-collections/community\.dns/pull/60](https\://github\.com/ansible\-collections/community\.dns/pull/60)\)\.
+* The hosttech\_dns\_records module has been renamed to hosttech\_dns\_record\_sets \([https\://github\.com/ansible\-collections/community\.dns/pull/31](https\://github\.com/ansible\-collections/community\.dns/pull/31)\)\.
+* The internal API now supports bulk DNS record changes\, if supported by the API \([https\://github\.com/ansible\-collections/community\.dns/pull/39](https\://github\.com/ansible\-collections/community\.dns/pull/39)\)\.
+* The internal record API allows to manage extra data \([https\://github\.com/ansible\-collections/community\.dns/pull/63](https\://github\.com/ansible\-collections/community\.dns/pull/63)\)\.
+* Use HTTP helper class to make API implementations work for both plugins and modules\. Make WSDL API use <code>fetch\_url</code> instead of <code>open\_url</code> for modules \([https\://github\.com/ansible\-collections/community\.dns/pull/36](https\://github\.com/ansible\-collections/community\.dns/pull/36)\)\.
+* hetzner\_dns\_record and hosttech\_dns\_record \- when not using check mode\, use actual return data for diff\, instead of input data\, so that extra data can be shown \([https\://github\.com/ansible\-collections/community\.dns/pull/63](https\://github\.com/ansible\-collections/community\.dns/pull/63)\)\.
+* hetzner\_dns\_zone\_info \- the <code>legacy\_ns</code> return value is now sorted\, since its order is unstable \([https\://github\.com/ansible\-collections/community\.dns/pull/46](https\://github\.com/ansible\-collections/community\.dns/pull/46)\)\.
+* hosttech\_dns\_\* modules \- rename <code>zone</code> parameter to <code>zone\_name</code>\. The old name <code>zone</code> can still be used as an alias \([https\://github\.com/ansible\-collections/community\.dns/pull/32](https\://github\.com/ansible\-collections/community\.dns/pull/32)\)\.
+* hosttech\_dns\_record\_set \- <code>value</code> is no longer required when <code>state\=absent</code> and <code>overwrite\=true</code> \([https\://github\.com/ansible\-collections/community\.dns/pull/31](https\://github\.com/ansible\-collections/community\.dns/pull/31)\)\.
+* hosttech\_dns\_record\_sets \- <code>records</code> has been renamed to <code>record\_sets</code>\. The old name <code>records</code> can still be used as an alias \([https\://github\.com/ansible\-collections/community\.dns/pull/31](https\://github\.com/ansible\-collections/community\.dns/pull/31)\)\.
+* hosttech\_dns\_zone\_info \- return extra information as <code>zone\_info</code> \([https\://github\.com/ansible\-collections/community\.dns/pull/38](https\://github\.com/ansible\-collections/community\.dns/pull/38)\)\.
+
+<a id="breaking-changes--porting-guide"></a>
+### Breaking Changes / Porting Guide
+
+* All Hetzner modules and plugins which handle DNS records now work with unquoted TXT values by default\. The old behavior can be obtained by setting <code>txt\_transformation\=api</code> \([https\://github\.com/ansible\-collections/community\.dns/issues/48](https\://github\.com/ansible\-collections/community\.dns/issues/48)\, [https\://github\.com/ansible\-collections/community\.dns/pull/57](https\://github\.com/ansible\-collections/community\.dns/pull/57)\, [https\://github\.com/ansible\-collections/community\.dns/pull/60](https\://github\.com/ansible\-collections/community\.dns/pull/60)\)\.
+* Hosttech API creation \- now requires a <code>ModuleOptionProvider</code> object instead of an <code>AnsibleModule</code> object\. Alternatively an Ansible plugin instance can be passed \([https\://github\.com/ansible\-collections/community\.dns/pull/37](https\://github\.com/ansible\-collections/community\.dns/pull/37)\)\.
+* The hetzner\_dns\_record\_info and hosttech\_dns\_record\_info modules have been renamed to hetzner\_dns\_record\_set\_info and hosttech\_dns\_record\_set\_info\, respectively \([https\://github\.com/ansible\-collections/community\.dns/pull/54](https\://github\.com/ansible\-collections/community\.dns/pull/54)\)\.
+* The hosttech\_dns\_record module has been renamed to hosttech\_dns\_record\_set \([https\://github\.com/ansible\-collections/community\.dns/pull/31](https\://github\.com/ansible\-collections/community\.dns/pull/31)\)\.
+* The internal bulk record updating helper \(<code>bulk\_apply\_changes</code>\) now also returns the records that were deleted\, created or updated \([https\://github\.com/ansible\-collections/community\.dns/pull/63](https\://github\.com/ansible\-collections/community\.dns/pull/63)\)\.
+* The internal record API no longer allows to manage comments explicitly \([https\://github\.com/ansible\-collections/community\.dns/pull/63](https\://github\.com/ansible\-collections/community\.dns/pull/63)\)\.
+* When using the internal modules API\, now a zone ID type and a provider information object must be passed \([https\://github\.com/ansible\-collections/community\.dns/pull/27](https\://github\.com/ansible\-collections/community\.dns/pull/27)\)\.
+* hetzner\_dns\_record\* modules \- implement correct handling of default TTL\. The value <code>none</code> is now accepted and returned in this case \([https\://github\.com/ansible\-collections/community\.dns/pull/52](https\://github\.com/ansible\-collections/community\.dns/pull/52)\, [https\://github\.com/ansible\-collections/community\.dns/issues/50](https\://github\.com/ansible\-collections/community\.dns/issues/50)\)\.
+* hetzner\_dns\_record\, hetzner\_dns\_record\_set\, hetzner\_dns\_record\_sets \- the default TTL is now 300 and no longer 3600\, which equals the default in the web console \([https\://github\.com/ansible\-collections/community\.dns/pull/43](https\://github\.com/ansible\-collections/community\.dns/pull/43)\)\.
+* hosttech\_dns\_record\_set \- the option <code>overwrite</code> was replaced by a new option <code>on\_existing</code>\. Specifying <code>overwrite\=true</code> is equivalent to <code>on\_existing\=replace</code> \(the new default\)\. Specifying <code>overwrite\=false</code> with <code>state\=present</code> is equivalent to <code>on\_existing\=keep\_and\_fail</code>\, and specifying <code>overwrite\=false</code> with <code>state\=absent</code> is equivalent to <code>on\_existing\=keep</code> \([https\://github\.com/ansible\-collections/community\.dns/pull/31](https\://github\.com/ansible\-collections/community\.dns/pull/31)\)\.
+
+<a id="deprecated-features-2"></a>
+### Deprecated Features
+
+* The hosttech\_dns\_records module has been renamed to hosttech\_dns\_record\_sets\. The old name will stop working in community\.dns 3\.0\.0 \([https\://github\.com/ansible\-collections/community\.dns/pull/31](https\://github\.com/ansible\-collections/community\.dns/pull/31)\)\.
+
+<a id="bugfixes-37"></a>
+### Bugfixes
+
+* Hetzner API \- interpret missing TTL as 300\, which is what the web console also does \([https\://github\.com/ansible\-collections/community\.dns/pull/42](https\://github\.com/ansible\-collections/community\.dns/pull/42)\)\.
+* Update Public Suffix List\.
+* Update Public Suffix List\.
+* Update Public Suffix List\.
+* hetzner API code \- make sure to also handle errors returned by the API if the HTTP status code indicates success\. This sometimes happens for 500 Internal Server Error \([https\://github\.com/ansible\-collections/community\.dns/pull/58](https\://github\.com/ansible\-collections/community\.dns/pull/58)\)\.
+* hosttech\_dns\_zone\_info \- make sure that full information is returned both when requesting a zone by ID or by name \([https\://github\.com/ansible\-collections/community\.dns/pull/56](https\://github\.com/ansible\-collections/community\.dns/pull/56)\)\.
+* wait\_for\_txt \- fix handling of too long TXT values \([https\://github\.com/ansible\-collections/community\.dns/pull/65](https\://github\.com/ansible\-collections/community\.dns/pull/65)\)\.
+* wait\_for\_txt \- resolving nameservers sometimes resulted in an empty list\, yielding wrong results \([https\://github\.com/ansible\-collections/community\.dns/pull/64](https\://github\.com/ansible\-collections/community\.dns/pull/64)\)\.
+
+<a id="new-plugins-1"></a>
+### New Plugins
+
+<a id="inventory"></a>
+#### Inventory
+
+* community\.dns\.hetzner\_dns\_records \- Create inventory from Hetzner DNS records
+* community\.dns\.hosttech\_dns\_records \- Create inventory from Hosttech DNS records
+
+<a id="new-modules-1"></a>
+### New Modules
+
+* community\.dns\.hetzner\_dns\_record \- Add or delete a single record in Hetzner DNS service
+* community\.dns\.hetzner\_dns\_record\_info \- Retrieve records in Hetzner DNS service
+* community\.dns\.hetzner\_dns\_record\_set \- Add or delete record sets in Hetzner DNS service
+* community\.dns\.hetzner\_dns\_record\_set\_info \- Retrieve record sets in Hetzner DNS service
+* community\.dns\.hetzner\_dns\_record\_sets \- Bulk synchronize DNS record sets in Hetzner DNS service
+* community\.dns\.hetzner\_dns\_zone\_info \- Retrieve zone information in Hetzner DNS service
+* community\.dns\.hosttech\_dns\_record \- Add or delete a single record in Hosttech DNS service
+* community\.dns\.hosttech\_dns\_record\_info \- Retrieve records in Hosttech DNS service
+* community\.dns\.hosttech\_dns\_record\_set \- Add or delete record sets in Hosttech DNS service
+* community\.dns\.hosttech\_dns\_record\_sets \- Bulk synchronize DNS record sets in Hosttech DNS service
+
+<a id="v1-2-0"></a>
+## v1\.2\.0
+
+<a id="release-summary-40"></a>
+### Release Summary
+
+Last minor 1\.x\.0 version\. The 2\.0\.0 version will have some backwards incompatible changes to the <code>hosttech\_dns\_record</code> and <code>hosttech\_dns\_records</code> modules which will require user intervention\. These changes should result in a better UX\.
+
+<a id="minor-changes-11"></a>
+### Minor Changes
+
+* hosttech modules \- add <code>api\_token</code> alias for <code>hosttech\_token</code> \([https\://github\.com/ansible\-collections/community\.dns/pull/26](https\://github\.com/ansible\-collections/community\.dns/pull/26)\)\.
+* hosttech\_dns\_record \- in <code>diff</code> mode\, also return <code>diff</code> data structure when <code>changed</code> is <code>false</code> \([https\://github\.com/ansible\-collections/community\.dns/pull/28](https\://github\.com/ansible\-collections/community\.dns/pull/28)\)\.
+* module utils \- add default implementation for some zone/record API functions\, and move common JSON API code to helper class \([https\://github\.com/ansible\-collections/community\.dns/pull/26](https\://github\.com/ansible\-collections/community\.dns/pull/26)\)\.
+
+<a id="bugfixes-38"></a>
+### Bugfixes
+
+* Update Public Suffix List\.
+* hosttech\_dns\_record \- correctly handle quoting in CAA records for JSON API \([https\://github\.com/ansible\-collections/community\.dns/pull/30](https\://github\.com/ansible\-collections/community\.dns/pull/30)\)\.
+
+<a id="v1-1-0"></a>
+## v1\.1\.0
+
+<a id="release-summary-41"></a>
+### Release Summary
+
+Regular maintenance release\.
+
+<a id="minor-changes-12"></a>
+### Minor Changes
+
+* Avoid internal ansible\-core module\_utils in favor of equivalent public API available since at least Ansible 2\.9 \([https\://github\.com/ansible\-collections/community\.dns/pull/24](https\://github\.com/ansible\-collections/community\.dns/pull/24)\)\.
+
+<a id="bugfixes-39"></a>
+### Bugfixes
+
+* Update Public Suffix List\.
+
+<a id="v1-0-1"></a>
+## v1\.0\.1
+
+<a id="release-summary-42"></a>
+### Release Summary
+
+Regular maintenance release\.
+
+<a id="bugfixes-40"></a>
+### Bugfixes
+
+* Update Public Suffix List\.
+
+<a id="v1-0-0"></a>
+## v1\.0\.0
+
+<a id="release-summary-43"></a>
+### Release Summary
+
+First stable release\.
+
+<a id="bugfixes-41"></a>
+### Bugfixes
+
+* Update Public Suffix List\.
+
+<a id="v0-3-0"></a>
+## v0\.3\.0
+
+<a id="release-summary-44"></a>
+### Release Summary
+
+Fixes bugs\, adds rate limiting for Hosttech JSON API\, and adds a new bulk synchronization module\.
+
+<a id="minor-changes-13"></a>
+### Minor Changes
+
+* hosttech\_dns\_\* \- handle <code>419 Too Many Requests</code> with proper rate limiting for JSON API \([https\://github\.com/ansible\-collections/community\.dns/pull/14](https\://github\.com/ansible\-collections/community\.dns/pull/14)\)\.
+
+<a id="bugfixes-42"></a>
+### Bugfixes
+
+* Avoid converting ASCII labels which contain underscores or other printable ASCII characters outside <code>\[a\-zA\-Z0\-9\-\]</code> to alabels during normalization \([https\://github\.com/ansible\-collections/community\.dns/pull/13](https\://github\.com/ansible\-collections/community\.dns/pull/13)\)\.
+* Updated Public Suffix List\.
+
+<a id="new-modules-2"></a>
+### New Modules
+
+* community\.dns\.hosttech\_dns\_records \- Bulk synchronize DNS records in Hosttech DNS service
+
+<a id="v0-2-0"></a>
+## v0\.2\.0
+
+<a id="release-summary-45"></a>
+### Release Summary
+
+Major refactoring release\, which adds a zone information module and supports HostTech\'s new REST API\.
+
+<a id="major-changes"></a>
+### Major Changes
+
+* hosttech\_\* modules \- support the new JSON API at [https\://api\.ns1\.hosttech\.eu/api/documentation/](https\://api\.ns1\.hosttech\.eu/api/documentation/) \([https\://github\.com/ansible\-collections/community\.dns/pull/4](https\://github\.com/ansible\-collections/community\.dns/pull/4)\)\.
+
+<a id="minor-changes-14"></a>
+### Minor Changes
+
+* hosttech\_dns\_record\* modules \- allow to specify <code>prefix</code> instead of <code>record</code> \([https\://github\.com/ansible\-collections/community\.dns/pull/8](https\://github\.com/ansible\-collections/community\.dns/pull/8)\)\.
+* hosttech\_dns\_record\* modules \- allow to specify zone by ID with the <code>zone\_id</code> parameter\, alternatively to the <code>zone</code> parameter \([https\://github\.com/ansible\-collections/community\.dns/pull/7](https\://github\.com/ansible\-collections/community\.dns/pull/7)\)\.
+* hosttech\_dns\_record\* modules \- return <code>zone\_id</code> on success \([https\://github\.com/ansible\-collections/community\.dns/pull/7](https\://github\.com/ansible\-collections/community\.dns/pull/7)\)\.
+* hosttech\_dns\_record\* modules \- support IDN domain names and prefixes \([https\://github\.com/ansible\-collections/community\.dns/pull/9](https\://github\.com/ansible\-collections/community\.dns/pull/9)\)\.
+* hosttech\_dns\_record\_info \- also return <code>prefix</code> for a record set \([https\://github\.com/ansible\-collections/community\.dns/pull/8](https\://github\.com/ansible\-collections/community\.dns/pull/8)\)\.
+* hosttech\_record \- allow to delete records without querying their content first by specifying <code>overwrite\=true</code> \([https\://github\.com/ansible\-collections/community\.dns/pull/4](https\://github\.com/ansible\-collections/community\.dns/pull/4)\)\.
+
+<a id="breaking-changes--porting-guide-1"></a>
+### Breaking Changes / Porting Guide
+
+* hosttech\_\* module\_utils \- completely rewrite and refactor to support new JSON API and allow to reuse provider\-independent module logic \([https\://github\.com/ansible\-collections/community\.dns/pull/4](https\://github\.com/ansible\-collections/community\.dns/pull/4)\)\.
+
+<a id="bugfixes-43"></a>
+### Bugfixes
+
+* Update Public Suffix List\.
+* hosttech\_record \- fix diff mode for <code>state\=absent</code> \([https\://github\.com/ansible\-collections/community\.dns/pull/4](https\://github\.com/ansible\-collections/community\.dns/pull/4)\)\.
+* hosttech\_record\_info \- fix authentication error handling \([https\://github\.com/ansible\-collections/community\.dns/pull/4](https\://github\.com/ansible\-collections/community\.dns/pull/4)\)\.
+
+<a id="new-modules-3"></a>
+### New Modules
+
+* community\.dns\.hosttech\_dns\_zone\_info \- Retrieve zone information in Hosttech DNS service
+
+<a id="v0-1-0"></a>
+## v0\.1\.0
+
+<a id="release-summary-46"></a>
+### Release Summary
+
+Initial public release\.
+
+<a id="new-plugins-2"></a>
+### New Plugins
+
+<a id="filter"></a>
+#### Filter
+
+* community\.dns\.get\_public\_suffix \- Returns the public suffix of a DNS name
+* community\.dns\.get\_registrable\_domain \- Returns the registrable domain name of a DNS name
+* community\.dns\.remove\_public\_suffix \- Removes the public suffix from a DNS name
+* community\.dns\.remove\_registrable\_domain \- Removes the registrable domain name from a DNS name
+
+<a id="new-modules-4"></a>
+### New Modules
+
+* community\.dns\.hosttech\_dns\_record \- Add or delete entries in Hosttech DNS service
+* community\.dns\.hosttech\_dns\_record\_info \- Retrieve entries in Hosttech DNS service
+* community\.dns\.wait\_for\_txt \- Wait for TXT entries to be available on all authoritative nameservers
diff --git a/ansible_collections/community/general/tests/sanity/ignore-2.11.txt.license b/ansible_collections/community/dns/CHANGELOG.md.license
index edff8c768..edff8c768 100644
--- a/ansible_collections/community/general/tests/sanity/ignore-2.11.txt.license
+++ b/ansible_collections/community/dns/CHANGELOG.md.license
diff --git a/ansible_collections/community/dns/CHANGELOG.rst b/ansible_collections/community/dns/CHANGELOG.rst
index bc3b3ffd9..37b4a2500 100644
--- a/ansible_collections/community/dns/CHANGELOG.rst
+++ b/ansible_collections/community/dns/CHANGELOG.rst
@@ -4,6 +4,217 @@ Community DNS Collection Release Notes
.. contents:: Topics
+v2.8.3
+======
+
+Release Summary
+---------------
+
+Bugfix release.
+
+Bugfixes
+--------
+
+- DNS record modules, inventory plugins - fix the TXT entry encoder to avoid splitting up escape sequences for quotes and backslashes over multiple TXT strings (https://github.com/ansible-collections/community.dns/issues/190, https://github.com/ansible-collections/community.dns/pull/191).
+- Update Public Suffix List.
+
+v2.8.2
+======
+
+Release Summary
+---------------
+
+Bugfix release.
+
+Security Fixes
+--------------
+
+- hosttech_dns_records and hetzner_dns_records inventory plugins - make sure all data received from the remote servers is marked as unsafe, so remote code execution by obtaining texts that can be evaluated as templates is not possible (https://www.die-welt.net/2024/03/remote-code-execution-in-ansible-dynamic-inventory-plugins/, https://github.com/ansible-collections/community.dns/pull/189).
+
+Bugfixes
+--------
+
+- Update Public Suffix List.
+
+v2.8.1
+======
+
+Release Summary
+---------------
+
+Maintenance release with updated PSL.
+
+Bugfixes
+--------
+
+- Update Public Suffix List.
+
+v2.8.0
+======
+
+Release Summary
+---------------
+
+Feature and maintenance release with updated PSL.
+
+Minor Changes
+-------------
+
+- hetzner_dns_records and hosttech_dns_records inventory plugins - the ``filters`` option has been renamed to ``simple_filters``. The old name still works until community.hrobot 2.0.0. Then it will change to allow more complex filtering with the ``community.library_inventory_filtering_v1`` collection's functionality (https://github.com/ansible-collections/community.dns/pull/181).
+
+Deprecated Features
+-------------------
+
+- hetzner_dns_records and hosttech_dns_records inventory plugins - the ``filters`` option has been renamed to ``simple_filters``. The old name will stop working in community.hrobot 2.0.0 (https://github.com/ansible-collections/community.dns/pull/181).
+
+Bugfixes
+--------
+
+- Update Public Suffix List.
+
+v2.7.0
+======
+
+Release Summary
+---------------
+
+Bugfix and feature release with updated PSL.
+
+Minor Changes
+-------------
+
+- nameserver_info and nameserver_record_info - add ``server`` parameter to specify custom DNS servers (https://github.com/ansible-collections/community.dns/pull/168, https://github.com/ansible-collections/community.dns/pull/178).
+- wait_for_txt - add ``server`` parameter to specify custom DNS servers (https://github.com/ansible-collections/community.dns/pull/178).
+
+Bugfixes
+--------
+
+- Update Public Suffix List.
+- wait_for_txt, nameserver_info, nameserver_record_info - when looking up nameservers for a domain, do not treat ``NXDOMAIN`` as a fatal error (https://github.com/ansible-collections/community.dns/pull/177).
+
+v2.6.4
+======
+
+Release Summary
+---------------
+
+Bugfix and maintenance version.
+
+Bugfixes
+--------
+
+- Update Public Suffix List.
+- nameserver_record_info - fix crash when more than one record is retrieved (https://github.com/ansible-collections/community.dns/pull/172).
+
+v2.6.3
+======
+
+Release Summary
+---------------
+
+Maintenance release with updated PSL.
+
+Bugfixes
+--------
+
+- HTTP module utils - make compatible with ansible-core 2.17 (https://github.com/ansible-collections/community.dns/pull/165).
+- Update Public Suffix List.
+
+v2.6.2
+======
+
+Release Summary
+---------------
+
+Maintenance release with updated PSL.
+
+Bugfixes
+--------
+
+- Update Public Suffix List.
+
+v2.6.1
+======
+
+Release Summary
+---------------
+
+Maintenance release with updated PSL.
+
+Bugfixes
+--------
+
+- Update Public Suffix List.
+
+v2.6.0
+======
+
+Release Summary
+---------------
+
+Feature release with an updated Public Suffix List.
+
+Minor Changes
+-------------
+
+- wait_for_txt - add ``servfail_retries`` parameter that allows retrying after SERVFAIL errors (https://github.com/ansible-collections/community.dns/pull/159).
+- wait_for_txt, resolver module utils - use `EDNS <https://en.wikipedia.org/wiki/Extension_Mechanisms_for_DNS>`__ (https://github.com/ansible-collections/community.dns/pull/158).
+
+Bugfixes
+--------
+
+- Update Public Suffix List.
+- wait_for_txt, resolver module utils - improve error handling (https://github.com/ansible-collections/community.dns/pull/158).
+
+New Plugins
+-----------
+
+Lookup
+~~~~~~
+
+- community.dns.lookup - Look up DNS records
+- community.dns.lookup_as_dict - Look up DNS records as dictionaries
+
+New Modules
+-----------
+
+- community.dns.nameserver_info - Look up nameservers for a DNS name
+- community.dns.nameserver_record_info - Look up all records of a type from all nameservers for a DNS name
+
+v2.5.7
+======
+
+Release Summary
+---------------
+
+Regular maintenance release with updated Public Suffix List.
+
+Bugfixes
+--------
+
+- Update Public Suffix List.
+
+v2.5.6
+======
+
+Release Summary
+---------------
+
+Maintenance release.
+
+From this version on, community.dns is using the new `Ansible semantic markup
+<https://docs.ansible.com/ansible/devel/dev_guide/developing_modules_documenting.html#semantic-markup-within-module-documentation>`__
+in its documentation. If you look at documentation with the ansible-doc CLI tool
+from ansible-core before 2.15, please note that it does not render the markup
+correctly. You should be still able to read it in most cases, but you need
+ansible-core 2.15 or later to see it as it is intended. Alternatively you can
+look at `the devel docsite <https://docs.ansible.com/ansible/devel/collections/community/dns/>`__
+for the rendered HTML version of the documentation of the latest release.
+
+Known Issues
+------------
+
+- Ansible markup will show up in raw form on ansible-doc text output for ansible-core before 2.15. If you have trouble deciphering the documentation markup, please upgrade to ansible-core 2.15 (or newer), or read the HTML documentation on https://docs.ansible.com/ansible/devel/collections/community/dns/.
v2.5.5
======
@@ -484,7 +695,6 @@ Release Summary
Last minor 1.x.0 version. The 2.0.0 version will have some backwards incompatible changes to the ``hosttech_dns_record`` and ``hosttech_dns_records`` modules which will require user intervention. These changes should result in a better UX.
-
Minor Changes
-------------
@@ -592,7 +802,7 @@ Minor Changes
Breaking Changes / Porting Guide
--------------------------------
-- hosttech_* module_utils - completely rewrite and refactor to support new JSON API and allow to re-use provider-independent module logic (https://github.com/ansible-collections/community.dns/pull/4).
+- hosttech_* module_utils - completely rewrite and refactor to support new JSON API and allow to reuse provider-independent module logic (https://github.com/ansible-collections/community.dns/pull/4).
Bugfixes
--------
diff --git a/ansible_collections/community/dns/FILES.json b/ansible_collections/community/dns/FILES.json
index 28b4fc42f..8bda06632 100644
--- a/ansible_collections/community/dns/FILES.json
+++ b/ansible_collections/community/dns/FILES.json
@@ -25,14 +25,14 @@
"name": ".github/workflows/ansible-test.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "57f43a933f9c97400b40a433e63641f054cd983d9dbe80634f46a03cca350224",
+ "chksum_sha256": "cb9ff13908693ca232d8a96c732b37b686549b5a18c58241a40c14cafe97dec0",
"format": 1
},
{
"name": ".github/workflows/check-psl.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "328ab30e4396fbcd5256cbd489493fe4fbd60d5e91285c843066102762cc8d13",
+ "chksum_sha256": "118df96cf8dd220a3796a3626cdf1110d7c516f3442bd7d2ca8d5d8e7d6a06a5",
"format": 1
},
{
@@ -53,28 +53,28 @@
"name": ".github/workflows/ee.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fc968cc46f8bfe4e3a61e9bd923514e7c3a740f7561e5f954b88c0ff278852cd",
+ "chksum_sha256": "bcef35a96fa3202cfec5d7adcb76b93124fa08e1a8c6dd914bf8cbb8aed28f11",
"format": 1
},
{
"name": ".github/workflows/extra-tests.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c563072f09b977b1e3f5de4bef418a4985efc2be2e9b8c3ce5f3ded827e0f829",
+ "chksum_sha256": "c7ed351192ec963495e9a1752c3ecd914698582affd90dec5065c7f2180fe1dc",
"format": 1
},
{
"name": ".github/workflows/import-galaxy.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3adc031272832a2901eeca54ab1e98f08f65682fd3046ec6d8f79885c6d21e97",
+ "chksum_sha256": "739c36223d6e0e6ccc98907c43cba53296e7b1ccd64a2d995c2ff21df4ab25a5",
"format": 1
},
{
"name": ".github/workflows/reuse.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e8a5666a792db2dbbb984d861032728af7523bd05eb64f72d5fe24d7888c4a85",
+ "chksum_sha256": "91fb4be801aaf7897a138f4774f1fa172291af4fcd9e1c7a3a5e3830236305fe",
"format": 1
},
{
@@ -151,7 +151,7 @@
"name": "changelogs/changelog.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "87340f9738ad8fd68d3b353331f75224c62db5146a60dc8ec73aee23e127de8c",
+ "chksum_sha256": "86ce7da485fe12025925410c18b8b391fccc9b84dffff900037604813663277f",
"format": 1
},
{
@@ -165,7 +165,7 @@
"name": "changelogs/config.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "eaf381e2fe7a048e89338e704fb11ed2be9366b56f9b0c1aecb5c69200d245ae",
+ "chksum_sha256": "e43f412de1a581ff888e1c037718691d86545bf11e07aaf66719f51233fc3d9b",
"format": 1
},
{
@@ -193,21 +193,21 @@
"name": "docs/docsite/rst/filter_guide.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4951821c42291a5155c07ab8890b797891a797a48d56177f5c43fa1f68e40ed3",
+ "chksum_sha256": "b407b72d65102202fc82d449bef8dd026f4d2debb9f7140fa6ac664a4cd4f5fc",
"format": 1
},
{
"name": "docs/docsite/rst/hetzner_guide.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9f1add331b70dab5095c92502c08e1315ed425ab313aa0d140dd34a53215dc80",
+ "chksum_sha256": "b7f406b5c5d7921909eb2196feae0ec9a28e18ee5a2ce08e0a8db50c3e2506f6",
"format": 1
},
{
"name": "docs/docsite/rst/hosttech_guide.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a5a52988e830180e5ce155bfbcdb1a7f6b4f32d49ac36a9754af2c2ab41b0dbe",
+ "chksum_sha256": "aa681fcb4d15501cb903fa73e3f12f587a094ccf38b4293cbc2f7c3c68fbb1d1",
"format": 1
},
{
@@ -277,77 +277,77 @@
"name": "plugins/doc_fragments/filters.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b96398417b1b6574669976db5fb6db1d797ca98c4966973ea28c7d90a8e89d45",
+ "chksum_sha256": "1cb405a996cfcbd3e2f3b93bebbb46bb58d1a3d4a096e2cd4f4224300622e22c",
"format": 1
},
{
"name": "plugins/doc_fragments/hetzner.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d533aa9b538b4b516f61b1bc279cc41f5182b61768982a589b60b5fb93d7e826",
+ "chksum_sha256": "404be926c5e8d5ebd8c3ca9d2298ee20271a94002718af887dbf9fb2a2c2f5d5",
"format": 1
},
{
"name": "plugins/doc_fragments/hosttech.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c688311bad0e2ef03270326ec7c5395c6a337dc9c6858085723c543f330634dd",
+ "chksum_sha256": "8d5111e6a8451815e488972647ddd93c97ee7c0643ed1d93486b08ce64e94aea",
"format": 1
},
{
"name": "plugins/doc_fragments/inventory_records.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9901b4cc5e7285e71f460b2284c135f4dce22089ef4cf0594d1425cc1f49f4a1",
+ "chksum_sha256": "ca51ab2e9350f36f68827a2fa86145ad0865838ac43313e07e09f853fd6e1f3c",
"format": 1
},
{
"name": "plugins/doc_fragments/module_record.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3b2487963454cf78d4603577d87fa09f021682fa63b91c87a5bf7d37a18f6188",
+ "chksum_sha256": "d47652ca9323493adf9e018cc4854f647963b0343cf50baf5120a4dd6f6de632",
"format": 1
},
{
"name": "plugins/doc_fragments/module_record_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a6de9b0cc1556bcfb4ec0db4ae29d8bd16e0b618ecb58754d5c1a9bdda7ee541",
+ "chksum_sha256": "9b2ca73771adedb40bd5563517538018e7e94e972be9d4c11c7477f262425bee",
"format": 1
},
{
"name": "plugins/doc_fragments/module_record_set.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6239eb43284dd8561616e048e1fd96aeaadaf5c0e9a43db9a8d203622f4a6d4b",
+ "chksum_sha256": "93f0a0b7e58c77fb0b0458fec03fefdfe2e29d74b54ab058b120263da2416b7a",
"format": 1
},
{
"name": "plugins/doc_fragments/module_record_set_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b10b9465de88c3b79b2f76e181745559ca662166e0a4036c29b1311af9ac44a7",
+ "chksum_sha256": "76cefb614786062fba1bb6f1e2cbf704f51c4a4089992fd0dc125f8f9d89ecd6",
"format": 1
},
{
"name": "plugins/doc_fragments/module_record_sets.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1898824cddb3853becd5c2207e42f6d2ccc18cdae5539ebf3911e8b3ca7b2f89",
+ "chksum_sha256": "08ae979b4324fe3b21e61e46226a494fa0bd5ce9b24c3f5daec40eec11dda18c",
"format": 1
},
{
"name": "plugins/doc_fragments/module_zone_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "91f80f14cdef9da9c08c1f969ed9ffb07f097070efac7447c5f30c11394d8031",
+ "chksum_sha256": "8618f26a1465c96304e63f4f8af7ee310a983343be77d2a5aa3541fc0664145e",
"format": 1
},
{
"name": "plugins/doc_fragments/options.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "10ac33fbbbeb9be9afaa107f62ade852ef9ee471e829588e4ee4e108ba873b05",
+ "chksum_sha256": "d6187dcb10a41b78a6bf385d22a3fafe2c1a8e69b296aeb8292d109edfab3b22",
"format": 1
},
{
@@ -403,14 +403,35 @@
"name": "plugins/inventory/hetzner_dns_records.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b4ef8ec66c251b7703b461ae5d782b0f3208c96bff19df643bb29b618d172724",
+ "chksum_sha256": "b6531b5ee8da29ac4909eeb4db27b9d5c232c8acfd8741dc99cc6d5877ccf213",
"format": 1
},
{
"name": "plugins/inventory/hosttech_dns_records.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7dcc6657d43c6d2004c4a0c45d5a0f704481e1536673d154d8e3bba0e85494e9",
+ "chksum_sha256": "ed0fef2e327ea3103a8e3c08a0af587f1cc48c6239ad14e3164f706e86d7f160",
+ "format": 1
+ },
+ {
+ "name": "plugins/lookup",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "plugins/lookup/lookup.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6571e35773f4c9116eaf7c21e5c25ab95d803e54d3c929e6b94b82eaa503d8ee",
+ "format": 1
+ },
+ {
+ "name": "plugins/lookup/lookup_as_dict.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "2eb51bdf708dc19c84dd15e16c8804570922cdf0b5cfad337c7a85c93b326750",
"format": 1
},
{
@@ -445,7 +466,7 @@
"name": "plugins/module_utils/conversion/txt.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f4ef8ea4cc71f015b68f1d5e964790321c963c9a4e4e29e24c424539c0e874f2",
+ "chksum_sha256": "2b67dedea39b7e459c5013b1fea65b14ff051564cf2fc266fd14b95c29be656f",
"format": 1
},
{
@@ -554,10 +575,24 @@
"format": 1
},
{
+ "name": "plugins/module_utils/dnspython_records.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9ac13fa2d67854365a63648e79af5d1a3dec899add8c6feb377c513fdbeb1ab1",
+ "format": 1
+ },
+ {
"name": "plugins/module_utils/http.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f6e60896ab9557f54b702025c41b7906b483eecf5191807cd69d3d9396e0192a",
+ "chksum_sha256": "5ea2697586e3d869be7ccb0c65d52869f385acae200f828d79ec3fd7aa8029ec",
+ "format": 1
+ },
+ {
+ "name": "plugins/module_utils/ips.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "971a40f6bbc1a97df51c6c4f79dab21be0efb95c0ce79627f65841752aabbdcd",
"format": 1
},
{
@@ -599,7 +634,7 @@
"name": "plugins/module_utils/resolver.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d2780e267283aee2fa56258926a9a7d89b63ee56838e7ea8c108f4067347a346",
+ "chksum_sha256": "2d0ceedf04f529e982d7865daa9c7d56b4ba49361e665a5e246fb4f3f4de569a",
"format": 1
},
{
@@ -627,7 +662,7 @@
"name": "plugins/module_utils/zone_record_helpers.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9b2b9aab72062fe177da968c554fe7a8155803848b40f98c3a0c4d1b40e3bc7a",
+ "chksum_sha256": "23ffb0889b6edb65129f732eda29f2c37ed2ffeeda7d28c0b7aa116076d20361",
"format": 1
},
{
@@ -641,98 +676,112 @@
"name": "plugins/modules/hosttech_dns_records.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "542133e245b31b09c514d862ae33a41df558c3d36e3fff047fbb8a5b41465074",
+ "chksum_sha256": "fe2c760eaf5bccaed8abbefe6dd6952b428fd05c0cc48919dc579acc7ad57141",
"format": 1
},
{
"name": "plugins/modules/hetzner_dns_record.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1af221c28f0c4686cb2695434bb792f2f153c1d2454a9f8d427b1d5d8953c7f8",
+ "chksum_sha256": "235b7a73ce5f2a9e74098f8c4100fbe2ca828a13ec021872392e5f0442cc6e56",
"format": 1
},
{
"name": "plugins/modules/hetzner_dns_record_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "05ddf1bfd4c7afe5760b05f1bdc5693839fc302af7f76adb0e1be1e271561608",
+ "chksum_sha256": "4c18b6d859e1f97180dd4636faa1fba61b54b72e9b93d38888ac54b910988ba1",
"format": 1
},
{
"name": "plugins/modules/hetzner_dns_record_set.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c4c0a209ff43962f5030cb44ddd1e7deabfea3f82d848bd460d7307059027972",
+ "chksum_sha256": "35f71b7b8f680261f51b78d7c34cf4d89f490ba5937674614055cd6593e578d3",
"format": 1
},
{
"name": "plugins/modules/hetzner_dns_record_set_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1e24dd296cbbc1210759b5e60a9f754b8e78fb5b017333aba4b343ecf5c57cd1",
+ "chksum_sha256": "d16b0111d6afd73ebe845a3a500a63bd39996442e0a4f45ed1d6c6bd7de9d201",
"format": 1
},
{
"name": "plugins/modules/hetzner_dns_record_sets.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0801be20ea6bdc1b9af8ce0d04e57ae8b32b8f0bfe20656021b850a2a3a83907",
+ "chksum_sha256": "ed1dc6db050606eb7a36e857055aabe827b88f28e5dcca03c5faa45d1cde5ce4",
"format": 1
},
{
"name": "plugins/modules/hetzner_dns_zone_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "336ed14aae54e4a0e6604914b40ff8867a49eb84c33308b78c58aa4a1b0f53cd",
+ "chksum_sha256": "209b496fff14e93f73349d1dc20d18e99e725bde2b050ebed3207360ec4a1f3d",
"format": 1
},
{
"name": "plugins/modules/hosttech_dns_record.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1edf1a6d7e0ea5939606ae153a2b563834dc2de960a23a98a018dfcddbaef409",
+ "chksum_sha256": "a3d8f2e8e85e018a3487bdac1300204d798d05a3d3ed7f2d09a9a34328f0ede6",
"format": 1
},
{
"name": "plugins/modules/hosttech_dns_record_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "24a8c3b3a5197c1530f1c7f8f2f0dea1117bf5ca05f3027f36b1ef6b8b6b14f0",
+ "chksum_sha256": "9edad91069d7d4016822c269ccafcb4da3241345a2992c6066459a99c7099851",
"format": 1
},
{
"name": "plugins/modules/hosttech_dns_record_set.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "18230d597c1cd3d7d150f7cb07d417b2b68a12276813c88cf3456c80a63e6eaa",
+ "chksum_sha256": "20c17392e17dc9a9a4e79dc59a38d48e811eb6078729036e538cdf96e03f1183",
"format": 1
},
{
"name": "plugins/modules/hosttech_dns_record_set_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6751d18dfa5c640f35da77a20d2465338ece071ba8ac8b5303e9eda396737a04",
+ "chksum_sha256": "cabdcbcaa21e3ab61dc0342905d3cd3a255a807e30199b45600c27eef9b572e6",
"format": 1
},
{
"name": "plugins/modules/hosttech_dns_record_sets.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "542133e245b31b09c514d862ae33a41df558c3d36e3fff047fbb8a5b41465074",
+ "chksum_sha256": "fe2c760eaf5bccaed8abbefe6dd6952b428fd05c0cc48919dc579acc7ad57141",
"format": 1
},
{
"name": "plugins/modules/hosttech_dns_zone_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8f9c3a5fd7836a5fc5cdfd571db72a7998fcc62e05acddf8e607a046da022e0d",
+ "chksum_sha256": "cdeb61c41acdc861c80778c828bdf9d8cf8731671f7c82162aa67e5e1ceb85c1",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/nameserver_info.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ff4478b83dc13d0a0ce0fc21612cb1cfa1a387e1555912825ef0cb1cefa9efc8",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/nameserver_record_info.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "7852ebc817c22900ff6d713e8d088a304d81f405645ed6c81cecb9004089bf4f",
"format": 1
},
{
"name": "plugins/modules/wait_for_txt.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "eca0b0120be5426a13aafb56265d82666b12068b75d21732e45625a1005dc8a8",
+ "chksum_sha256": "bec1dbe1203bb7c3297f09d0384bd13cdac68d68b2a12acc11598c3553f1b0cb",
"format": 1
},
{
@@ -753,7 +802,14 @@
"name": "plugins/plugin_utils/inventory/records.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2de808c5923d8e4b84e41eeb43b91c5ad8e7bf4400b03f359afcd0c49237ff03",
+ "chksum_sha256": "c77b1d234e40d804759699724336db0683f6c9173f8e36c69b8b0e3d3a33a50c",
+ "format": 1
+ },
+ {
+ "name": "plugins/plugin_utils/ips.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "22851f00f437e72a6ed6eaa759088c5e56fa06a442fb7cd4feac13cf87566def",
"format": 1
},
{
@@ -764,6 +820,13 @@
"format": 1
},
{
+ "name": "plugins/plugin_utils/resolver.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "831ba70576c5668bb20489f28e0a1506c5d8914abb57d56a5c6dc07969bfde0d",
+ "format": 1
+ },
+ {
"name": "plugins/plugin_utils/templated_options.py",
"ftype": "file",
"chksum_type": "sha256",
@@ -774,7 +837,7 @@
"name": "plugins/public_suffix_list.dat",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c21461ca3f4ac0267bf3dc8d64c5c0b3dcdc27a43cae7e1cf2677ed951d26ecc",
+ "chksum_sha256": "9bf809262c4506519ef0c2d89681b77c8a87d2bcf5d17d7b0496840c1451cfd9",
"format": 1
},
{
@@ -844,7 +907,7 @@
"name": "tests/ee/roles/wait_for_txt/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "93362d607677767f4a6b1c9ed53b1d8888f7a2fb84e24647768f2ebf2008c76d",
+ "chksum_sha256": "78632512c81d43f6c1a65fadb752180ec7e432b39d0baafe51c31bc52eeb6f00",
"format": 1
},
{
@@ -981,6 +1044,104 @@
"format": 1
},
{
+ "name": "tests/integration/targets/lookup_lookup",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/lookup_lookup/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/lookup_lookup/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "34db5ec41377c4c79e1cf83b7f4ac88e29fd0b3c467ddf26104ee21eec89024e",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/lookup_lookup/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "cbe5933470cb27da2d1df8a8d3e8dc0b860df5b8e474c3413389f1ae841002ec",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/lookup_lookup_as_dict",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/lookup_lookup_as_dict/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/lookup_lookup_as_dict/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "d4d40eff9ec56b5236626dafd6db61fb0ef2c54f15af48dcd0aedf584cabea0c",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/lookup_lookup_as_dict/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "cbe5933470cb27da2d1df8a8d3e8dc0b860df5b8e474c3413389f1ae841002ec",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/nameserver_info",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/nameserver_info/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/nameserver_info/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "cac88735a717b40fcc635462966e50790db466e2dae4456bef2e012a96b50eb9",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/nameserver_record_info",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/nameserver_record_info/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/nameserver_record_info/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "bc4a4c41bf13fee592e97d01d01d235928fb2cc89dda219ae39c71fe3b3bffc5",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/required_module_params",
"ftype": "dir",
"chksum_type": null,
@@ -1026,42 +1187,56 @@
"name": "tests/integration/targets/wait_for_txt/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a08332f1fc96503af7257974f9b0cb006a259961b4a5ef3137f6766a4d310704",
+ "chksum_sha256": "e91a52fae8adc8b0aa8b108f09765135ea432639d8e97416ad26eddf8e5cde86",
"format": 1
},
{
"name": "tests/integration/targets/wait_for_txt/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "22aabe027192db7fa8fcbb72d5ae66aa903097169aba7e68a6a3fc5e7fc577d5",
+ "chksum_sha256": "cbe5933470cb27da2d1df8a8d3e8dc0b860df5b8e474c3413389f1ae841002ec",
"format": 1
},
{
- "name": "tests/integration/targets/wait_for_txt/runme.sh",
+ "name": "tests/integration/integration_config.yml.hetzner-template",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "af4e97f0430418d1e5ca825f0f42e739c645b62ffd32de00f6b6c033f2f50aa2",
+ "chksum_sha256": "16daaa2db3d94f40abd5d91871dee781b04c139f3692ed7057ea768ea0458fe2",
"format": 1
},
{
- "name": "tests/integration/targets/wait_for_txt/runme.yml",
+ "name": "tests/integration/integration_config.yml.hosttech-template",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f1153fc402d8c568c711113c99130006d3fedc0f8b81cb6f80eb25eb1578c239",
+ "chksum_sha256": "62bb2d772cba011fc9151a14393d616fcd55554b400bb8dc0ef56f9cdc7c19ea",
"format": 1
},
{
- "name": "tests/integration/integration_config.yml.hetzner-template",
+ "name": "tests/integration/replace-requirements.sh",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "16daaa2db3d94f40abd5d91871dee781b04c139f3692ed7057ea768ea0458fe2",
+ "chksum_sha256": "9ef269363fb4921693e63d5bca4f113028c7a98d954b3d25e752d7f96cea2bdb",
"format": 1
},
{
- "name": "tests/integration/integration_config.yml.hosttech-template",
+ "name": "tests/integration/requirements-stable-2.10.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "62bb2d772cba011fc9151a14393d616fcd55554b400bb8dc0ef56f9cdc7c19ea",
+ "chksum_sha256": "2c089ca496e1059909afc4d13958f4744bfb953ee039ea1e39a98c3f8309c5fa",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/requirements-stable-2.9.txt",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "2c089ca496e1059909afc4d13958f4744bfb953ee039ea1e39a98c3f8309c5fa",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/requirements.txt",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "3a63580de11a7ce96ccf62858dba53e99cb433bcf1238ca526dac32e089202dc",
"format": 1
},
{
@@ -1103,7 +1278,7 @@
"name": "tests/sanity/extra/extra-docs.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0fbd87476e9c35e4c5feb31be4aa1e8fc6aebf0de13058e5a267879f741ec0bf",
+ "chksum_sha256": "c52e316daf1292bbb063be19429fd1f06e02bce3c9d4622a8dfc61fa3af06688",
"format": 1
},
{
@@ -1180,7 +1355,7 @@
"name": "tests/sanity/ignore-2.10.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e6ba33006d3aa232443f145cbbc66c1eb5a4c06e75b6a9c63e89972c990d2786",
+ "chksum_sha256": "b2d0fb7a1b0d0126f05818085d52eb73d78a9f6e4f3805971496df81150e80ca",
"format": 1
},
{
@@ -1194,7 +1369,7 @@
"name": "tests/sanity/ignore-2.11.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e6ba33006d3aa232443f145cbbc66c1eb5a4c06e75b6a9c63e89972c990d2786",
+ "chksum_sha256": "a4d81352bb04ea35d84a43ea0150df5a717fd8f9591bab74ab5d25e360a7e456",
"format": 1
},
{
@@ -1208,7 +1383,7 @@
"name": "tests/sanity/ignore-2.12.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e6ba33006d3aa232443f145cbbc66c1eb5a4c06e75b6a9c63e89972c990d2786",
+ "chksum_sha256": "a4d81352bb04ea35d84a43ea0150df5a717fd8f9591bab74ab5d25e360a7e456",
"format": 1
},
{
@@ -1222,7 +1397,7 @@
"name": "tests/sanity/ignore-2.13.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e6ba33006d3aa232443f145cbbc66c1eb5a4c06e75b6a9c63e89972c990d2786",
+ "chksum_sha256": "a4d81352bb04ea35d84a43ea0150df5a717fd8f9591bab74ab5d25e360a7e456",
"format": 1
},
{
@@ -1236,7 +1411,7 @@
"name": "tests/sanity/ignore-2.14.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e6ba33006d3aa232443f145cbbc66c1eb5a4c06e75b6a9c63e89972c990d2786",
+ "chksum_sha256": "a4d81352bb04ea35d84a43ea0150df5a717fd8f9591bab74ab5d25e360a7e456",
"format": 1
},
{
@@ -1275,13 +1450,27 @@
"format": 1
},
{
- "name": "tests/sanity/ignore-2.9.txt",
+ "name": "tests/sanity/ignore-2.17.txt",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "e6ba33006d3aa232443f145cbbc66c1eb5a4c06e75b6a9c63e89972c990d2786",
"format": 1
},
{
+ "name": "tests/sanity/ignore-2.17.txt.license",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6eb915239f9f35407fa68fdc41ed6522f1fdcce11badbdcd6057548023179ac1",
+ "format": 1
+ },
+ {
+ "name": "tests/sanity/ignore-2.9.txt",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "b2d0fb7a1b0d0126f05818085d52eb73d78a9f6e4f3805971496df81150e80ca",
+ "format": 1
+ },
+ {
"name": "tests/sanity/ignore-2.9.txt.license",
"ftype": "file",
"chksum_type": "sha256",
@@ -1313,14 +1502,35 @@
"name": "tests/unit/plugins/inventory/test_hetzner_dns_records.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "75a38f930f1989126cfd8c06d1389e4fd5c648486dc4359147b8bf9d9d553e1f",
+ "chksum_sha256": "b0a2245e3bc7a899c5ba90f7ea85471fa5f3c26aa612ac859e3cf0ede691ea44",
"format": 1
},
{
"name": "tests/unit/plugins/inventory/test_hosttech_dns_records.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "eb49251839b33f89c0d18f218c1862ad42a33c1b8665f6dd741ffeb5d05fbdda",
+ "chksum_sha256": "c8c44d2037060fbfbaab8d05fc3af1d78513af2a5d91d872199aa75768a82b93",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/lookup",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/lookup/test_lookup.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "a888fcf181730c2aae23357e0a073cbf1996a2172b13ea8c96e0ab17623937af",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/lookup/test_lookup_as_dict.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "283ff7237b352e16cc23b413fd05b39bcb474c047f1662507f7c078a56d0814e",
"format": 1
},
{
@@ -1348,7 +1558,7 @@
"name": "tests/unit/plugins/module_utils/conversion/test_txt.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d0334105e803f8b137097c4cbaef351f12484f7a578f35f0d186a6f63e98c23d",
+ "chksum_sha256": "a3623f51a80dd57864dc7f318d50ef231bd864e11aa1b2a03a3b5efa848df739",
"format": 1
},
{
@@ -1411,7 +1621,7 @@
"name": "tests/unit/plugins/module_utils/resolver_helper.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e9527f31a6eda7f9b1e2fca62e9325a9c9b964343a5704c1f94e304cec4c2b3b",
+ "chksum_sha256": "1732b34b946b6911c9cc9690330f589691a71eccc1344d1973f31d3814327bf8",
"format": 1
},
{
@@ -1422,6 +1632,20 @@
"format": 1
},
{
+ "name": "tests/unit/plugins/module_utils/test_dnspython_records.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "4fac8d9cfac7288257f5dc344e546cc51fba21ac83ad4e3cd658491dced79b3d",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/module_utils/test_ips.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "3ff7a4c1b5002faf507cebb5757e92dce739dfab607955716d3d717703972d4e",
+ "format": 1
+ },
+ {
"name": "tests/unit/plugins/module_utils/test_json_api_helper.py",
"ftype": "file",
"chksum_type": "sha256",
@@ -1453,7 +1677,7 @@
"name": "tests/unit/plugins/module_utils/test_resolver.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "dd95bd83c9cab2adc7698ed7a6968298ff3334cdbbae8db56b85777801753ada",
+ "chksum_sha256": "f79b5af9da07abe1ce92836406dfbbc31359c8580e2b6fab1557675e8ef45d4b",
"format": 1
},
{
@@ -1576,10 +1800,24 @@
"format": 1
},
{
+ "name": "tests/unit/plugins/modules/test_nameserver_info.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "630ee0b0abefcb61b8e1f2399d2db0e988ff24e4339a5aaae953a14cccd44e12",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/modules/test_nameserver_record_info.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "448d339b5969e83a9897f6192f6ac4b898403419c70b2055dfac97f2b422c050",
+ "format": 1
+ },
+ {
"name": "tests/unit/plugins/modules/test_wait_for_txt.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "822afe1474b99d4865a523118ae616d36e9793eb6693add50034986d05b8aeaa",
+ "chksum_sha256": "8def3b82a62a61d0d28ee33bc589364336da840bb024ada98b070e5024f7ee21",
"format": 1
},
{
@@ -1590,6 +1828,13 @@
"format": 1
},
{
+ "name": "tests/unit/plugins/plugin_utils/test_ips.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f92989d10aa1264b11862d9b7c88eff833d5306f35edac9acac2f2d9f8d2388d",
+ "format": 1
+ },
+ {
"name": "tests/unit/plugins/plugin_utils/test_public_suffix.py",
"ftype": "file",
"chksum_type": "sha256",
@@ -1597,10 +1842,38 @@
"format": 1
},
{
+ "name": "tests/unit/plugins/plugin_utils/test_resolver.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "3fd725a172beea7cb73ed85bafc6c6745d7e8aaf08d74b1e9e7c534a05c7ddab",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/replace-requirements.sh",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9ef269363fb4921693e63d5bca4f113028c7a98d954b3d25e752d7f96cea2bdb",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/requirements-stable-2.10.txt",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "1404c050017797dba43f1a8963794f33afaf0e5667abc792c062adf8ac84c254",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/requirements-stable-2.9.txt",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "1404c050017797dba43f1a8963794f33afaf0e5667abc792c062adf8ac84c254",
+ "format": 1
+ },
+ {
"name": "tests/unit/requirements.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3d0ac34bebc9bdedbd7bd3bcd3342985b276839ae82cc75442c297609b01cf25",
+ "chksum_sha256": "b4f4056523e6ab794378043243f6ca8a5681a46c73e1a4cbcb197ae7056333ee",
"format": 1
},
{
@@ -1618,10 +1891,24 @@
"format": 1
},
{
+ "name": "CHANGELOG.md",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ab12a2e489b31f469f321b053a4cb432216fe20e8374cd0ffb4ecf68bc8c7348",
+ "format": 1
+ },
+ {
+ "name": "CHANGELOG.md.license",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6eb915239f9f35407fa68fdc41ed6522f1fdcce11badbdcd6057548023179ac1",
+ "format": 1
+ },
+ {
"name": "CHANGELOG.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c3789f0c3f34ccaee424dff34293d3172ac44dcfd15393861c9c8e805e2d33a4",
+ "chksum_sha256": "a2deefeaf4feaee535b1f34f517495188be0c31c22c1e5a33e470f86245dc92f",
"format": 1
},
{
@@ -1649,7 +1936,7 @@
"name": "README.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6986b272ce1b0a3e2842a19405c8f44b0df445ec1c563e076260d7bc5622080d",
+ "chksum_sha256": "9083e4932c4b72abbc6c7382b3c964df7826b1a12a49f4d2e34cc36155380fd7",
"format": 1
},
{
@@ -1670,7 +1957,7 @@
"name": "update-docs-fragments.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e92bad2be3a0fd524207e52e587cebed402ec87dd723ca7e33f48725121ea18f",
+ "chksum_sha256": "ee7f8429976728a0bc777fab9b822b57d1138ccf142aebac3367cffed485f86a",
"format": 1
},
{
diff --git a/ansible_collections/community/dns/MANIFEST.json b/ansible_collections/community/dns/MANIFEST.json
index 133510541..fcbfda5d6 100644
--- a/ansible_collections/community/dns/MANIFEST.json
+++ b/ansible_collections/community/dns/MANIFEST.json
@@ -2,7 +2,7 @@
"collection_info": {
"namespace": "community",
"name": "dns",
- "version": "2.5.5",
+ "version": "2.8.3",
"authors": [
"Felix Fontein (github.com/felixfontein)",
"Markus Bergholz (github.com/markuman)"
@@ -30,7 +30,7 @@
"name": "FILES.json",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fa3df6e39a948ef0e253b1076133edf0f43b1119e56063a3e2a35ed2f8c5344e",
+ "chksum_sha256": "8234c71782176e94860f305e6a9e4365b2167e2bd47e59e9c580a1011fc96b39",
"format": 1
},
"format": 1
diff --git a/ansible_collections/community/dns/README.md b/ansible_collections/community/dns/README.md
index 5796339b4..8a404fa3a 100644
--- a/ansible_collections/community/dns/README.md
+++ b/ansible_collections/community/dns/README.md
@@ -16,7 +16,7 @@ Please note that this collection does **not** support Windows targets.
## Tested with Ansible
-Tested with the current Ansible 2.9, ansible-base 2.10, ansible-core 2.11, ansible-core 2.12, ansible-core 2.13, and ansible-core 2.14 releases and the current development version of ansible-core. Ansible versions before 2.9.10 are not supported.
+Tested with the current Ansible 2.9, ansible-base 2.10, ansible-core 2.11, ansible-core 2.12, ansible-core 2.13, ansible-core 2.14, ansible-core 2.15, and ansible-core 2.16 releases and the current development version of ansible-core. Ansible versions before 2.9.10 are not supported.
## External requirements
@@ -47,10 +47,15 @@ If you use the Ansible package and do not update collections independently, use
- `hosttech_dns_record_set`: create/update/delete DNS record sets with HostTech DNS.
- `hosttech_dns_record_set`: bulk synchronize DNS record sets in Hosttech DNS service.
- `hosttech_dns_zone_info`: retrieve zone information from HostTech DNS.
+ - `nameserver_info`: Look up nameservers for a DNS name.
+ - `nameserver_record_info`: Look up all records of a type from all nameservers for a DNS name.
- `wait_for_txt`: wait for TXT records to propagate to all name servers.
+- Lookup plugins:
+ - `lookup`: look up DNS records and return them as a list of strings.
+ - `lookup_as_dict`: look up DNS records and return them as a list of dictionaries.
- Inventory plugins:
- - `hetzner_dns_records`: create inventory from Hetzner DNS records
- - `hosttech_dns_records`: create inventory from HostTech DNS records
+ - `hetzner_dns_records`: create inventory from Hetzner DNS records.
+ - `hosttech_dns_records`: create inventory from HostTech DNS records.
- Filters:
- `get_public_suffix`: given a domain name, returns the public suffix. For example, `"www.ansible.com" | community.dns.get_public_suffix == ".com"` and `"some.random.prefixes.ansible.co.uk" | community.dns.get_public_suffix == ".co.uk"`.
- `get_registrable_domain`: given a domain name, returns the *registrable domain name* (also called *registered domain name*). For example, `"www.ansible.com" | community.dns.get_registrable_domain == "ansible.com"` and `"some.random.prefixes.ansible.co.uk" | community.dns.get_registrable_domain == "ansible.co.uk"`.
@@ -82,7 +87,7 @@ You can find more information in the [developer guide for collections](https://d
## Release notes
-See the [changelog](https://github.com/ansible-collections/community.dns/tree/main/CHANGELOG.rst).
+See the [changelog](https://github.com/ansible-collections/community.dns/tree/main/CHANGELOG.md).
## Releasing, Versioning and Deprecation
diff --git a/ansible_collections/community/dns/changelogs/changelog.yaml b/ansible_collections/community/dns/changelogs/changelog.yaml
index b287c50db..626ad4abf 100644
--- a/ansible_collections/community/dns/changelogs/changelog.yaml
+++ b/ansible_collections/community/dns/changelogs/changelog.yaml
@@ -35,7 +35,7 @@ releases:
changes:
breaking_changes:
- hosttech_* module_utils - completely rewrite and refactor to support new JSON
- API and allow to re-use provider-independent module logic (https://github.com/ansible-collections/community.dns/pull/4).
+ API and allow to reuse provider-independent module logic (https://github.com/ansible-collections/community.dns/pull/4).
bugfixes:
- Update Public Suffix List.
- hosttech_record - fix diff mode for ``state=absent`` (https://github.com/ansible-collections/community.dns/pull/4).
@@ -617,3 +617,195 @@ releases:
- 2.5.5.yml
- update-psl.yml
release_date: '2023-06-19'
+ 2.5.6:
+ changes:
+ known_issues:
+ - Ansible markup will show up in raw form on ansible-doc text output for ansible-core
+ before 2.15. If you have trouble deciphering the documentation markup, please
+ upgrade to ansible-core 2.15 (or newer), or read the HTML documentation on
+ https://docs.ansible.com/ansible/devel/collections/community/dns/.
+ release_summary: 'Maintenance release.
+
+
+ From this version on, community.dns is using the new `Ansible semantic markup
+
+ <https://docs.ansible.com/ansible/devel/dev_guide/developing_modules_documenting.html#semantic-markup-within-module-documentation>`__
+
+ in its documentation. If you look at documentation with the ansible-doc CLI
+ tool
+
+ from ansible-core before 2.15, please note that it does not render the markup
+
+ correctly. You should be still able to read it in most cases, but you need
+
+ ansible-core 2.15 or later to see it as it is intended. Alternatively you
+ can
+
+ look at `the devel docsite <https://docs.ansible.com/ansible/devel/collections/community/dns/>`__
+
+ for the rendered HTML version of the documentation of the latest release.
+
+ '
+ fragments:
+ - 2.5.6.yml
+ release_date: '2023-06-22'
+ 2.5.7:
+ changes:
+ bugfixes:
+ - Update Public Suffix List.
+ release_summary: Regular maintenance release with updated Public Suffix List.
+ fragments:
+ - 2.5.7.yml
+ - update-psl.yml
+ release_date: '2023-07-17'
+ 2.6.0:
+ changes:
+ bugfixes:
+ - Update Public Suffix List.
+ - wait_for_txt, resolver module utils - improve error handling (https://github.com/ansible-collections/community.dns/pull/158).
+ minor_changes:
+ - wait_for_txt - add ``servfail_retries`` parameter that allows retrying after
+ SERVFAIL errors (https://github.com/ansible-collections/community.dns/pull/159).
+ - wait_for_txt, resolver module utils - use `EDNS <https://en.wikipedia.org/wiki/Extension_Mechanisms_for_DNS>`__
+ (https://github.com/ansible-collections/community.dns/pull/158).
+ release_summary: Feature release with an updated Public Suffix List.
+ fragments:
+ - 158-resolver.yml
+ - 159-servfail.yml
+ - 2.6.0.yml
+ - update-psl.yml
+ modules:
+ - description: Look up nameservers for a DNS name
+ name: nameserver_info
+ namespace: ''
+ - description: Look up all records of a type from all nameservers for a DNS name
+ name: nameserver_record_info
+ namespace: ''
+ plugins:
+ lookup:
+ - description: Look up DNS records
+ name: lookup
+ namespace: null
+ - description: Look up DNS records as dictionaries
+ name: lookup_as_dict
+ namespace: null
+ release_date: '2023-08-15'
+ 2.6.1:
+ changes:
+ bugfixes:
+ - Update Public Suffix List.
+ release_summary: Maintenance release with updated PSL.
+ fragments:
+ - 2.6.1.yml
+ - update-psl.yml
+ release_date: '2023-09-12'
+ 2.6.2:
+ changes:
+ bugfixes:
+ - Update Public Suffix List.
+ release_summary: Maintenance release with updated PSL.
+ fragments:
+ - 2.6.2.yml
+ - update-psl.yml
+ release_date: '2023-10-08'
+ 2.6.3:
+ changes:
+ bugfixes:
+ - HTTP module utils - make compatible with ansible-core 2.17 (https://github.com/ansible-collections/community.dns/pull/165).
+ - Update Public Suffix List.
+ release_summary: Maintenance release with updated PSL.
+ fragments:
+ - 165-url.yml
+ - 2.6.3.yml
+ - update-psl.yml
+ release_date: '2023-11-06'
+ 2.6.4:
+ changes:
+ bugfixes:
+ - Update Public Suffix List.
+ - nameserver_record_info - fix crash when more than one record is retrieved
+ (https://github.com/ansible-collections/community.dns/pull/172).
+ release_summary: Bugfix and maintenance version.
+ fragments:
+ - 172-nameserver_record_info.yml
+ - 2.6.4.yml
+ - update-psl.yml
+ release_date: '2023-12-03'
+ 2.7.0:
+ changes:
+ bugfixes:
+ - Update Public Suffix List.
+ - wait_for_txt, nameserver_info, nameserver_record_info - when looking up nameservers
+ for a domain, do not treat ``NXDOMAIN`` as a fatal error (https://github.com/ansible-collections/community.dns/pull/177).
+ minor_changes:
+ - nameserver_info and nameserver_record_info - add ``server`` parameter to specify
+ custom DNS servers (https://github.com/ansible-collections/community.dns/pull/168,
+ https://github.com/ansible-collections/community.dns/pull/178).
+ - wait_for_txt - add ``server`` parameter to specify custom DNS servers (https://github.com/ansible-collections/community.dns/pull/178).
+ release_summary: Bugfix and feature release with updated PSL.
+ fragments:
+ - 168-custom-dns-server.yml
+ - 177-ns-lookup-nxdomain.yml
+ - 178-wait_for_txt-server.yml
+ - 2.7.0.yml
+ - update-psl.yml
+ release_date: '2024-01-01'
+ 2.8.0:
+ changes:
+ bugfixes:
+ - Update Public Suffix List.
+ deprecated_features:
+ - hetzner_dns_records and hosttech_dns_records inventory plugins - the ``filters``
+ option has been renamed to ``simple_filters``. The old name will stop working
+ in community.hrobot 2.0.0 (https://github.com/ansible-collections/community.dns/pull/181).
+ minor_changes:
+ - hetzner_dns_records and hosttech_dns_records inventory plugins - the ``filters``
+ option has been renamed to ``simple_filters``. The old name still works until
+ community.hrobot 2.0.0. Then it will change to allow more complex filtering
+ with the ``community.library_inventory_filtering_v1`` collection's functionality
+ (https://github.com/ansible-collections/community.dns/pull/181).
+ release_summary: Feature and maintenance release with updated PSL.
+ fragments:
+ - 181-inventory-filters.yml
+ - 2.8.0.yml
+ - update-psl.yml
+ release_date: '2024-01-29'
+ 2.8.1:
+ changes:
+ bugfixes:
+ - Update Public Suffix List.
+ release_summary: Maintenance release with updated PSL.
+ fragments:
+ - 2.8.1.yml
+ - update-psl.yml
+ release_date: '2024-02-25'
+ 2.8.2:
+ changes:
+ bugfixes:
+ - Update Public Suffix List.
+ release_summary: Bugfix release.
+ security_fixes:
+ - hosttech_dns_records and hetzner_dns_records inventory plugins - make sure
+ all data received from the remote servers is marked as unsafe, so remote code
+ execution by obtaining texts that can be evaluated as templates is not possible
+ (https://www.die-welt.net/2024/03/remote-code-execution-in-ansible-dynamic-inventory-plugins/,
+ https://github.com/ansible-collections/community.dns/pull/189).
+ fragments:
+ - 2.8.2.yml
+ - inventory-rce.yml
+ - update-psl.yml
+ release_date: '2024-03-16'
+ 2.8.3:
+ changes:
+ bugfixes:
+ - DNS record modules, inventory plugins - fix the TXT entry encoder to avoid
+ splitting up escape sequences for quotes and backslashes over multiple TXT
+ strings (https://github.com/ansible-collections/community.dns/issues/190,
+ https://github.com/ansible-collections/community.dns/pull/191).
+ - Update Public Suffix List.
+ release_summary: Bugfix release.
+ fragments:
+ - 191-txt-quoting.yml
+ - 2.8.3.yml
+ - update-psl.yml
+ release_date: '2024-03-24'
diff --git a/ansible_collections/community/dns/changelogs/config.yaml b/ansible_collections/community/dns/changelogs/config.yaml
index 5f5075391..06dc33cc8 100644
--- a/ansible_collections/community/dns/changelogs/config.yaml
+++ b/ansible_collections/community/dns/changelogs/config.yaml
@@ -11,6 +11,9 @@ keep_fragments: false
mention_ancestor: true
new_plugins_after_name: removed_features
notesdir: fragments
+output_formats:
+- rst
+- md
prelude_section_name: release_summary
prelude_section_title: Release Summary
sections:
diff --git a/ansible_collections/community/dns/docs/docsite/rst/filter_guide.rst b/ansible_collections/community/dns/docs/docsite/rst/filter_guide.rst
index a2169369c..aee397f8a 100644
--- a/ansible_collections/community/dns/docs/docsite/rst/filter_guide.rst
+++ b/ansible_collections/community/dns/docs/docsite/rst/filter_guide.rst
@@ -14,10 +14,10 @@ Community.Dns Filter Guide
The :ref:`community.dns collection <plugins_in_community.dns>` offers several filters for working with DNS names:
-- :ref:`community.dns.get_public_suffix <ansible_collections.community.dns.get_public_suffix_filter>`: given a domain name, returns the public suffix;
-- :ref:`community.dns.get_registrable_domain <ansible_collections.community.dns.get_registrable_domain_filter>`: given a domain name, returns the registrable domain name;
-- :ref:`community.dns.remove_public_suffix <ansible_collections.community.dns.remove_public_suffix_filter>`: given a domain name, returns the part before the public suffix;
-- :ref:`community.dns.remove_registrable_domain <ansible_collections.community.dns.remove_registrable_domain_filter>`: given a domain name, returns the part before the registrable domain name.
+- :ansplugin:`community.dns.get_public_suffix#filter`: given a domain name, returns the public suffix;
+- :ansplugin:`community.dns.get_registrable_domain#filter`: given a domain name, returns the registrable domain name;
+- :ansplugin:`community.dns.remove_public_suffix#filter`: given a domain name, returns the part before the public suffix;
+- :ansplugin:`community.dns.remove_registrable_domain#filter`: given a domain name, returns the part before the registrable domain name.
These filters allow to work with `public suffixes <https://en.wikipedia.org/wiki/Public_Suffix_List>`_; a *public suffix* is a DNS suffix under which users can (or could) directly register names. They use the `Public Suffix List <https://publicsuffix.org/>`_, a Mozilla initiative maintained as a community resource which tries to list all such public suffixes. Common examples for public suffixes are ``.com``, ``.net``, but also longer suffixes such as ``.co.uk`` or ``.github.io``.
@@ -26,7 +26,7 @@ The label directly before the public suffix together with the suffix is called t
Working with public suffixes
----------------------------
-The :ref:`community.dns.get_public_suffix <ansible_collections.community.dns.get_public_suffix_filter>` and :ref:`community.dns.remove_public_suffix <ansible_collections.community.dns.remove_public_suffix_filter>` filters allow to extract and remove public suffixes from DNS names:
+The :ansplugin:`community.dns.get_public_suffix#filter` and :ansplugin:`community.dns.remove_public_suffix#filter` filters allow to extract and remove public suffixes from DNS names:
.. code-block:: yaml+jinja
@@ -45,28 +45,28 @@ The filters also allow additional options (keyword arguments):
:keep_unknown_suffix:
- A boolean with default value ``true``. This treats unknown TLDs as valid public suffixes. So for example the public suffix of ``example.tlddoesnotexist`` is ``.tlddoesnotexist`` if this is ``true``. If set to ``false``, it will return an empty string in this case. This option corresponds to whether the global wildcard rule ``*`` in the Public Suffix List is used or not.
+ A boolean with default value :ansval:`true`. This treats unknown TLDs as valid public suffixes. So for example the public suffix of :ansval:`example.tlddoesnotexist` is ``.tlddoesnotexist`` if this is :ansval:`true`. If set to :ansval:`false`, it will return an empty string in this case. This option corresponds to whether the global wildcard rule ``*`` in the Public Suffix List is used or not.
:icann_only:
- A boolean with default value ``false``. This controls whether only entries from the ICANN section of the Public Suffix List are used, or also entries from the Private section. For example, ``.co.uk`` is in the ICANN section, but ``github.io`` is in the Private section.
+ A boolean with default value :ansval:`false`. This controls whether only entries from the ICANN section of the Public Suffix List are used, or also entries from the Private section. For example, ``.co.uk`` is in the ICANN section, but ``github.io`` is in the Private section.
:normalize_result:
- (Only for :ref:`community.dns.get_public_suffix <ansible_collections.community.dns.get_public_suffix_filter>`) A boolean with default value ``false``. This controls whether the result is reconstructed from the normalized name used during lookup. During normalization, ulabels are converted to alabels, and every label is converted to lowercase. For example, the ulabel ``ëçãmplê`` is converted to ``xn--mpl-llatwb`` (puny-code), and ``Example.COM`` is converted to ``example.com``.
+ (Only for :ansplugin:`community.dns.get_public_suffix#filter`) A boolean with default value :ansval:`false`. This controls whether the result is reconstructed from the normalized name used during lookup. During normalization, ulabels are converted to alabels, and every label is converted to lowercase. For example, the ulabel :ansval:`ëçãmplê` is converted to ``xn--mpl-llatwb`` (puny-code), and :ansval:`Example.COM` is converted to ``example.com``.
:keep_leading_period:
- (Only for :ref:`community.dns.get_public_suffix <ansible_collections.community.dns.get_public_suffix_filter>`) A boolean with default value ``true``. This controls whether the leading period of a public suffix is preserved or not.
+ (Only for :ansplugin:`community.dns.get_public_suffix#filter`) A boolean with default value :ansval:`true`. This controls whether the leading period of a public suffix is preserved or not.
:keep_trailing_period:
- (Only for :ref:`community.dns.remove_public_suffix <ansible_collections.community.dns.remove_public_suffix_filter>`) A boolean with default value ``false``. This controls whether the trailing period of the prefix (that is, the part before the public suffix) is preserved or not.
+ (Only for :ansplugin:`community.dns.remove_public_suffix#filter`) A boolean with default value :ansval:`false`. This controls whether the trailing period of the prefix (that is, the part before the public suffix) is preserved or not.
Working with registrable domain names
-------------------------------------
-The :ref:`community.dns.get_registrable_domain <ansible_collections.community.dns.get_registrable_domain_filter>` and :ref:`community.dns.remove_registrable_domain <ansible_collections.community.dns.remove_registrable_domain_filter>` filters allow to extract and remove registrable domain names from DNS names:
+The :ansplugin:`community.dns.get_registrable_domain#filter` and :ansplugin:`community.dns.remove_registrable_domain#filter` filters allow to extract and remove registrable domain names from DNS names:
.. code-block:: yaml+jinja
@@ -85,20 +85,20 @@ The filters also allow additional options (keyword arguments):
:keep_unknown_suffix:
- A boolean with default value ``true``. This treats unknown TLDs as valid public suffixes. So for example the public suffix of ``example.tlddoesnotexist`` is ``.tlddoesnotexist`` if this is ``true``, and hence the registrable domain of ``www.example.tlddoesnotexist`` is ``example.tlddoesnotexist``. If set to ``false``, the registrable domain of ``www.example.tlddoesnotexist`` is ``tlddoesnotexist``. This option corresponds to whether the global wildcard rule ``*`` in the Public Suffix List is used or not.
+ A boolean with default value :ansval:`true`. This treats unknown TLDs as valid public suffixes. So for example the public suffix of :ansval:`example.tlddoesnotexist` is ``.tlddoesnotexist`` if this is :ansval:`true`, and hence the registrable domain of :ansval:`www.example.tlddoesnotexist` is ``example.tlddoesnotexist``. If set to :ansval:`false`, the registrable domain of :ansval:`www.example.tlddoesnotexist` is ``tlddoesnotexist``. This option corresponds to whether the global wildcard rule ``*`` in the Public Suffix List is used or not.
:icann_only:
- A boolean with default value ``false``. This controls whether only entries from the ICANN section of the Public Suffix List are used, or also entries from the Private section. For example, ``.co.uk`` is in the ICANN section, but ``github.io`` is in the Private section.
+ A boolean with default value :ansval:`false`. This controls whether only entries from the ICANN section of the Public Suffix List are used, or also entries from the Private section. For example, ``.co.uk`` is in the ICANN section, but ``github.io`` is in the Private section.
:only_if_registerable:
- A boolean with default value ``true``. This controls the behavior in case there is no label in front of the public suffix. This is the case if the DNS name itself is a public suffix. If set to ``false``, in this case the public suffix is treated as a registrable domain. If set to ``true`` (default), the registrable domain of a public suffix is interpreted as an empty string.
+ A boolean with default value :ansval:`true`. This controls the behavior in case there is no label in front of the public suffix. This is the case if the DNS name itself is a public suffix. If set to :ansval:`false`, in this case the public suffix is treated as a registrable domain. If set to :ansval:`true` (default), the registrable domain of a public suffix is interpreted as an empty string.
:normalize_result:
- (Only for :ref:`community.dns.get_registrable_domain <ansible_collections.community.dns.get_registrable_domain_filter>`) A boolean with default value ``false``. This controls whether the result is reconstructed from the normalized name used during lookup. During normalization, ulabels are converted to alabels, and every label is converted to lowercase. For example, the ulabel ``ëçãmplê`` is converted to ``xn--mpl-llatwb`` (puny-code), and ``Example.COM`` is converted to ``example.com``.
+ (Only for :ansplugin:`community.dns.get_registrable_domain#filter`) A boolean with default value :ansval:`false`. This controls whether the result is reconstructed from the normalized name used during lookup. During normalization, ulabels are converted to alabels, and every label is converted to lowercase. For example, the ulabel :ansval:`ëçãmplê` is converted to ``xn--mpl-llatwb`` (puny-code), and :ansval:`Example.COM` is converted to ``example.com``.
:keep_trailing_period:
- (Only for :ref:`community.dns.remove_registrable_domain <ansible_collections.community.dns.remove_registrable_domain_filter>`) A boolean with default value ``false``. This controls whether the trailing period of the prefix (that is, the part before the registrable domain) is preserved or not.
+ (Only for :ansplugin:`community.dns.remove_registrable_domain#filter`) A boolean with default value :ansval:`false`. This controls whether the trailing period of the prefix (that is, the part before the registrable domain) is preserved or not.
diff --git a/ansible_collections/community/dns/docs/docsite/rst/hetzner_guide.rst b/ansible_collections/community/dns/docs/docsite/rst/hetzner_guide.rst
index cbb029dcf..8c0e34e26 100644
--- a/ansible_collections/community/dns/docs/docsite/rst/hetzner_guide.rst
+++ b/ansible_collections/community/dns/docs/docsite/rst/hetzner_guide.rst
@@ -17,23 +17,23 @@ The modules use the `JSON REST based API <https://dns.hetzner.com/api-docs/>`_.
The collection provides six modules for working with Hetzner DNS:
-- :ref:`community.dns.hetzner_dns_record <ansible_collections.community.dns.hetzner_dns_record_module>`: create/update/delete single DNS records
-- :ref:`community.dns.hetzner_dns_record_info <ansible_collections.community.dns.hetzner_dns_record_info_module>`: retrieve information on DNS records
-- :ref:`community.dns.hetzner_dns_record_set <ansible_collections.community.dns.hetzner_dns_record_set_module>`: create/update/delete DNS record sets
-- :ref:`community.dns.hetzner_dns_record_set_info <ansible_collections.community.dns.hetzner_dns_record_set_info_module>`: retrieve information on DNS record sets
-- :ref:`community.dns.hetzner_dns_record_sets <ansible_collections.community.dns.hetzner_dns_record_sets_module>`: bulk synchronize DNS record sets
-- :ref:`community.dns.hetzner_dns_zone_info <ansible_collections.community.dns.hetzner_dns_zone_info_module>`: retrieve zone information
+- :ansplugin:`community.dns.hetzner_dns_record#module`: create/update/delete single DNS records
+- :ansplugin:`community.dns.hetzner_dns_record_info#module`: retrieve information on DNS records
+- :ansplugin:`community.dns.hetzner_dns_record_set#module`: create/update/delete DNS record sets
+- :ansplugin:`community.dns.hetzner_dns_record_set_info#module`: retrieve information on DNS record sets
+- :ansplugin:`community.dns.hetzner_dns_record_sets#module`: bulk synchronize DNS record sets
+- :ansplugin:`community.dns.hetzner_dns_zone_info#module`: retrieve zone information
-If you are interested in migrating from the `markuman.hetzner_dns collection <https://galaxy.ansible.com/markuman/hetzner_dns>`_, please see :ref:`ansible_collections.community.dns.docsite.hetzner_guide.migration_markuman_hetzner_dns`.
+If you are interested in migrating from the `markuman.hetzner_dns collection <https://galaxy.ansible.com/ui/repo/published/markuman/hetzner_dns/>`_, please see :ref:`ansible_collections.community.dns.docsite.hetzner_guide.migration_markuman_hetzner_dns`.
It also provides an inventory plugin:
-- :ref:`community.dns.hetzner_dns_records <ansible_collections.community.dns.hetzner_dns_records_inventory>`: create inventory from DNS records
+- :ansplugin:`community.dns.hetzner_dns_records#inventory`: create inventory from DNS records
Authentication
--------------
-To use Hetzner's API, you need to create an API token. You can manage API tokens in the "API tokens" menu entry in your user menu in the `DNS Console <https://dns.hetzner.com/>`_. You must provide the token to the ``hetzner_token`` option of the modules, its alias ``api_token``, or pass it on in the ``HETZNER_DNS_TOKEN`` environment variable:
+To use Hetzner's API, you need to create an API token. You can manage API tokens in the "API tokens" menu entry in your user menu in the `DNS Console <https://dns.hetzner.com/>`_. You must provide the token to the :ansopt:`hetzner_token` option of the modules, its alias :ansopt:`api_token`, or pass it on in the :envvar:`HETZNER_DNS_TOKEN` environment variable:
.. code-block:: yaml+jinja
@@ -77,7 +77,7 @@ Here all two tasks will use the options set for the module defaults group.
Working with DNS zones
----------------------
-The :ref:`community.dns.hetzner_dns_zone_info module <ansible_collections.community.dns.hetzner_dns_zone_info_module>` allows to query information on a zone. The zone can be identified both by its name and by its ID (which is an integer):
+The :ansplugin:`community.dns.hetzner_dns_zone_info module <community.dns.hetzner_dns_zone_info#module>` allows to query information on a zone. The zone can be identified both by its name and by its ID (which is an integer):
.. code-block:: yaml+jinja
@@ -105,12 +105,12 @@ Working with DNS records
.. note::
- By default, TXT record values returned and accepted by the modules and plugins in this collection are unquoted. This means that you do not have to add double quotes (``"``), and escape double quotes (as ``\"``) and backslashes (as ``\\``). All modules and plugins which work with DNS records support the ``txt_transformation`` option which allows to configure this behavior.
+ By default, TXT record values returned and accepted by the modules and plugins in this collection are unquoted. This means that you do not have to add double quotes (``"``), and escape double quotes (as ``\"``) and backslashes (as ``\\``). All modules and plugins which work with DNS records support the :ansopt:`community.dns.hetzner_dns_record_set#module:txt_transformation` option which allows to configure this behavior.
Querying DNS records and record sets
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-The :ref:`community.dns.hetzner_dns_record_set_info module <ansible_collections.community.dns.hetzner_dns_record_set_info_module>` allows to query DNS record sets from the API. It can be used to query a single record set:
+The :ansplugin:`community.dns.hetzner_dns_record_set_info module <community.dns.hetzner_dns_record_set_info#module>` allows to query DNS record sets from the API. It can be used to query a single record set:
.. code-block:: yaml+jinja
@@ -137,7 +137,7 @@ The :ref:`community.dns.hetzner_dns_record_set_info module <ansible_collections.
msg: There is no A record for www.example.com
when: not result.set
-In all examples in this section, you can replace ``zone_name=example.com`` by ``zone_id=aBcDeFgHiJlMnOpQrStUvW`` with the zone's ID string.
+In all examples in this section, you can replace :ansopt:`community.dns.hetzner_dns_record_set_info#module:zone_name=example.com` by :ansopt:`community.dns.hetzner_dns_record_set_info#module:zone_id=aBcDeFgHiJlMnOpQrStUvW` with the zone's ID string.
You can also query a list of all record sets for a record name or prefix:
@@ -177,14 +177,14 @@ Finally you can query all record sets for a zone:
TTL {{ item.ttl }} has values {{ item.value | join(', ') }}
loop: result.sets
-If you are interested in individual DNS records, and not record sets, you should use the :ref:`community.dns.hetzner_dns_record_info module <ansible_collections.community.dns.hetzner_dns_record_info_module>`. It supports the same limiting options as the ``community.dns.hetzner_dns_record_set_info`` module.
+If you are interested in individual DNS records, and not record sets, you should use the :ansplugin:`community.dns.hetzner_dns_record_info module <community.dns.hetzner_dns_record_info#module>`. It supports the same limiting options as the :ansplugin:`community.dns.hetzner_dns_record_set_info module <community.dns.hetzner_dns_record_set_info#module>`.
Creating and updating DNS single records
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you do not want to add/remove values, but replace values, you will be interested in modifying a **record set** and not a single record. This is in particular important when working with ``CNAME`` and ``SOA`` records.
-The :ref:`community.dns.hetzner_dns_record module <ansible_collections.community.dns.hetzner_dns_record_module>` allows to set, update and remove single DNS records. Setting and updating can be done as follows. Records will be matched by record name and type, and the TTL value will be updated if necessary:
+The :ansplugin:`community.dns.hetzner_dns_record module <community.dns.hetzner_dns_record#module>` allows to set, update and remove single DNS records. Setting and updating can be done as follows. Records will be matched by record name and type, and the TTL value will be updated if necessary:
.. code-block:: yaml+jinja
@@ -200,7 +200,7 @@ The :ref:`community.dns.hetzner_dns_record module <ansible_collections.community
value: 1.1.1.1
ttl: 300
-To delete records, simply use ``state=absent``. Records will be matched by record name and type, and the TTL will be ignored:
+To delete records, simply use :ansopt:`community.dns.hetzner_dns_record#module:state=absent`. Records will be matched by record name and type, and the TTL will be ignored:
.. code-block:: yaml+jinja
@@ -217,7 +217,7 @@ Records of the same type for the same record name with other values are ignored.
Creating and updating DNS record sets
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-The :ref:`community.dns.hetzner_dns_record_set module <ansible_collections.community.dns.hetzner_dns_record_set_module>` allows to set, update and remove DNS record sets. Setting and updating can be done as follows:
+The :ansplugin:`community.dns.hetzner_dns_record_set module <community.dns.hetzner_dns_record_set#module>` allows to set, update and remove DNS record sets. Setting and updating can be done as follows:
.. code-block:: yaml+jinja
@@ -234,9 +234,9 @@ The :ref:`community.dns.hetzner_dns_record_set module <ansible_collections.commu
- 1.1.1.1
- 8.8.8.8
-If you want to assert that a record has a certain value, set ``on_existing=keep``. Using ``keep_and_warn`` instead will emit a warning if this happens, and ``keep_and_fail`` will make the module fail.
+If you want to assert that a record has a certain value, set :ansopt:`community.dns.hetzner_dns_record_set#module:on_existing=keep`. Using :ansval:`keep_and_warn` instead will emit a warning if this happens, and :ansval:`keep_and_fail` will make the module fail.
-To delete values, you can either overwrite the values with value ``[]``, or use ``state=absent``:
+To delete values, you can either overwrite the values with value :ansval:`[]`, or use :ansopt:`community.dns.hetzner_dns_record_set#module:state=absent`:
.. code-block:: yaml+jinja
@@ -266,12 +266,12 @@ To delete values, you can either overwrite the values with value ``[]``, or use
value:
- '::1'
-In the third example, ``on_existing=keep_and_fail`` is present and an explicit value and TTL are given. This makes the module remove the current value only if there's a AAAA record for ``www.example.com`` whose current value is ``::1`` and whose TTL is 300. If another value is set, the module will not make any change, but fail. This can be useful to not accidentally remove values you do not want to change. To issue a warning instead of failing, use ``on_existing=keep_and_warn``, and to simply not do a change without any indication of this situation, use ``on_existing=keep``.
+In the third example, :ansopt:`community.dns.hetzner_dns_record_set#module:on_existing=keep_and_fail` is present and an explicit value and TTL are given. This makes the module remove the current value only if there's a AAAA record for ``www.example.com`` whose current value is ``::1`` and whose TTL is 300. If another value is set, the module will not make any change, but fail. This can be useful to not accidentally remove values you do not want to change. To issue a warning instead of failing, use :ansopt:`community.dns.hetzner_dns_record_set#module:on_existing=keep_and_warn`, and to simply not do a change without any indication of this situation, use :ansopt:`community.dns.hetzner_dns_record_set#module:on_existing=keep`.
Bulk synchronization of DNS record sets
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-If you want to set/update multiple records at once, or even make sure that the precise set of records you are providing are present and nothing else, you can use the :ref:`community.dns.hetzner_dns_record_sets module <ansible_collections.community.dns.hetzner_dns_record_sets_module>`.
+If you want to set/update multiple records at once, or even make sure that the precise set of records you are providing are present and nothing else, you can use the :ansplugin:`community.dns.hetzner_dns_record_sets module <community.dns.hetzner_dns_record_sets#module>`.
The following example shows up to set/update multiple records at once:
@@ -280,7 +280,7 @@ The following example shows up to set/update multiple records at once:
- name: Make sure that multiple records are present
community.dns.hetzner_dns_record_sets:
zone_name: example.com
- records:
+ record_sets:
- prefix: www
type: A
value:
@@ -291,7 +291,7 @@ The following example shows up to set/update multiple records at once:
value:
- '::1'
-The next example shows how to make sure that only the given records are available and all other records are deleted. Note that for the ``type=NS`` record we used ``ignore=true``, which allows us to skip the value. It tells the module that it should not touch the ``NS`` record for ``example.com``.
+The next example shows how to make sure that only the given records are available and all other records are deleted. Note that for the :ansopt:`community.dns.hetzner_dns_record_sets#module:record_sets[].type=NS` record we used :ansopt:`community.dns.hetzner_dns_record_sets#module:record_sets[].ignore=true`, which allows us to skip the value. It tells the module that it should not touch the ``NS`` record for ``example.com``.
.. code-block:: yaml+jinja
@@ -299,7 +299,7 @@ The next example shows how to make sure that only the given records are availabl
community.dns.hetzner_dns_record_sets:
zone_name: example.com
prune: true
- records:
+ record_sets:
- prefix: www
type: A
value:
@@ -318,7 +318,7 @@ The next example shows how to make sure that only the given records are availabl
Migrating from ``markuman.hetzner_dns``
---------------------------------------
-This section describes how to migrate playbooks and roles from using the `markuman.hetzner_dns collection <https://galaxy.ansible.com/markuman/hetzner_dns>`_ to the Hetzner modules and plugins in the ``community.dns`` collection.
+This section describes how to migrate playbooks and roles from using the `markuman.hetzner_dns collection <https://galaxy.ansible.com/ui/repo/published/markuman/hetzner_dns/>`_ to the Hetzner modules and plugins in the ``community.dns`` collection.
There are three steps for migrating. Two of these steps must be done on migration, the third step can also be done later:
@@ -326,18 +326,18 @@ There are three steps for migrating. Two of these steps must be done on migratio
2. Adjust module and plugin options if necessary.
3. Avoid deprecated aliases which ease the transition.
-The `markuman.hetzner_dns collection <https://galaxy.ansible.com/markuman/hetzner_dns>`_ collection provides three modules and one inventory plugin.
+The `markuman.hetzner_dns collection <https://galaxy.ansible.com/ui/repo/published/markuman/hetzner_dns/>`_ collection provides three modules and one inventory plugin.
.. note::
- When working with TXT records, please look at the ``txt_transformation`` option. By default, the modules and plugins in this collection use **unquoted** values (you do not have to add double quotes and escape double quotes and backslashes), while the modules and plugins in ``markuman.hetzner_dns`` use partially quoted values. You can switch behavior of the ``community.dns`` modules by passing ``txt_transformation=api`` or ``txt_transformation=quoted``.
+ When working with TXT records, please look at the :ansopt:`community.dns.hetzner_dns_record_set#module:txt_transformation` option. By default, the modules and plugins in this collection use **unquoted** values (you do not have to add double quotes and escape double quotes and backslashes), while the modules and plugins in ``markuman.hetzner_dns`` use partially quoted values. You can switch behavior of the ``community.dns`` modules by passing :ansopt:`community.dns.hetzner_dns_record_set#module:txt_transformation=api` or :ansopt:`community.dns.hetzner_dns_record_set#module:txt_transformation=quoted`.
The markuman.hetzner_dns.record module
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-The ``markuman.hetzner_dns.zone_info`` module can be replaced by the :ref:`community.dns.hetzner_dns_record module <ansible_collections.community.dns.hetzner_dns_record_module>` and the :ref:`community.dns.hetzner_dns_record_set module <ansible_collections.community.dns.hetzner_dns_record_set_module>`, depending on what it is used for.
+The ``markuman.hetzner_dns.zone_info`` module can be replaced by the :ansplugin:`community.dns.hetzner_dns_record module <community.dns.hetzner_dns_record#module>` and the :ansplugin:`community.dns.hetzner_dns_record_set module <community.dns.hetzner_dns_record_set#module>`, depending on what it is used for.
-When creating, updating or removing single records, the :ref:`community.dns.hetzner_dns_record module <ansible_collections.community.dns.hetzner_dns_record_module>` should be used. This is the case when ``purge=false`` is specified (the default value). Note that ``replace``, ``overwrite`` and ``solo`` are aliases of ``purge``.
+When creating, updating or removing single records, the :ansplugin:`community.dns.hetzner_dns_record module <community.dns.hetzner_dns_record#module>` should be used. This is the case when :ansopt:`purge=false` is specified (the default value). Note that :ansopt:`replace`, :ansopt:`overwrite` and :ansopt:`solo` are aliases of :ansopt:`purge`.
.. code-block:: yaml+jinja
@@ -370,7 +370,7 @@ When creating, updating or removing single records, the :ref:`community.dns.hetz
# or keep the following option:
txt_transformation: api
-When the ``markuman.hetzner_dns.record`` module is in replace mode, it should be replaced by the :ref:`community.dns.hetzner_dns_record_set module <ansible_collections.community.dns.hetzner_dns_record_set_module>`, since then it operates on the *record set* and not just on a single record:
+When the ``markuman.hetzner_dns.record`` module is in replace mode, it should be replaced by the :ansplugin:`community.dns.hetzner_dns_record_set module <community.dns.hetzner_dns_record_set#module>`, since then it operates on the *record set* and not just on a single record:
.. code-block:: yaml+jinja
@@ -410,7 +410,7 @@ When the ``markuman.hetzner_dns.record`` module is in replace mode, it should be
# or keep the following option:
txt_transformation: api
-When deleting a record, it depends on whether ``value`` is specified or not. If ``value`` is specified, the module is deleting a single DNS record, and the :ref:`community.dns.hetzner_dns_record module <ansible_collections.community.dns.hetzner_dns_record_module>` should be used:
+When deleting a record, it depends on whether :ansopt:`value` is specified or not. If :ansopt:`value` is specified, the module is deleting a single DNS record, and the :ansplugin:`community.dns.hetzner_dns_record module <community.dns.hetzner_dns_record#module>` should be used:
.. code-block:: yaml+jinja
@@ -440,7 +440,7 @@ When deleting a record, it depends on whether ``value`` is specified or not. If
# or keep the following option:
txt_transformation: api
-When ``value`` is not specified, the ``markuman.hetzner_dns.record`` module will delete all records for this prefix and type. In that case, it operates on a record set and the :ref:`community.dns.hetzner_dns_record_set module <ansible_collections.community.dns.hetzner_dns_record_set_module>` should be used:
+When :ansopt:`value` is not specified, the ``markuman.hetzner_dns.record`` module will delete all records for this prefix and type. In that case, it operates on a record set and the :ansplugin:`community.dns.hetzner_dns_record_set module <community.dns.hetzner_dns_record_set#module>` should be used:
.. code-block:: yaml+jinja
@@ -463,22 +463,22 @@ When ``value`` is not specified, the ``markuman.hetzner_dns.record`` module will
# 'type' does not change:
type: A
-A last step is replacing the deprecated alias ``name`` of ``prefix`` by ``prefix``. This can be done later though, if you do not mind the deprecation warnings.
+A last step is replacing the deprecated alias :ansopt:`community.dns.hetzner_dns_record_set#module:name` of :ansopt:`community.dns.hetzner_dns_record_set#module:prefix` by :ansopt:`community.dns.hetzner_dns_record_set#module:prefix`. This can be done later though, if you do not mind the deprecation warnings.
The markuman.hetzner_dns.record_info module
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-The ``markuman.hetzner_dns.record_info`` module can be replaced by the :ref:`community.dns.hetzner_dns_record_info module <ansible_collections.community.dns.hetzner_dns_record_info_module>`. The main difference is that instead of by the ``filters`` option, the output is controlled by the ``what`` option (choices ``single_record``, ``all_types_for_record``, and ``all_records``), the ``type`` option (needed when ``what=single_record``), and the ``record`` and ``prefix`` options (needed when ``what`` is not ``all_records``).
+The ``markuman.hetzner_dns.record_info`` module can be replaced by the :ansplugin:`community.dns.hetzner_dns_record_info module <community.dns.hetzner_dns_record_info#module>`. The main difference is that instead of by the :ansopt:`filters` option, the output is controlled by the :ansopt:`community.dns.hetzner_dns_record_info#module:what` option (choices :ansval:`single_record`, :ansval:`all_types_for_record`, and :ansval:`all_records`), the :ansopt:`community.dns.hetzner_dns_record_info#module:type` option (needed when :ansopt:`community.dns.hetzner_dns_record_info#module:what=single_record`), and the :ansopt:`community.dns.hetzner_dns_record_info#module:record` and :ansopt:`community.dns.hetzner_dns_record_info#module:prefix` options (needed when :ansopt:`community.dns.hetzner_dns_record_info#module:what` is not :ansval:`all_records`).
The markuman.hetzner_dns.zone_info module
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-The ``markuman.hetzner_dns.zone_info`` module can be replaced by the :ref:`community.dns.hetzner_dns_zone_info module <ansible_collections.community.dns.hetzner_dns_zone_info_module>`. The main differences are:
+The ``markuman.hetzner_dns.zone_info`` module can be replaced by the :ansplugin:`community.dns.hetzner_dns_zone_info module <community.dns.hetzner_dns_zone_info#module>`. The main differences are:
-1. The parameter ``name`` must be changed to ``zone_name`` or ``zone``.
-2. The return value ``zone_info`` no longer has the ``name`` and ``id`` entries. Use the return values ``zone_name`` and ``zone_id`` instead.
+1. The parameter :ansopt:`name` must be changed to :ansopt:`community.dns.hetzner_dns_zone_info#module:zone_name` or :ansopt:`community.dns.hetzner_dns_zone_info#module:zone`.
+2. The return value :ansretval:`community.dns.hetzner_dns_zone_info#module:zone_info` no longer has the ``name`` and ``id`` entries. Use the return values :ansretval:`community.dns.hetzner_dns_zone_info#module:zone_name` and :ansretval:`community.dns.hetzner_dns_zone_info#module:zone_id` instead.
The markuman.hetzner_dns.inventory inventory plugin
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-The ``markuman.hetzner_dns.inventory`` inventory plugin can be replaced by the :ref:`community.dns.hetzner_dns_records inventory plugin <ansible_collections.community.dns.hetzner_dns_records_inventory>`. Besides the plugin name, no change should be necessary.
+The ``markuman.hetzner_dns.inventory`` inventory plugin can be replaced by the :ansplugin:`community.dns.hetzner_dns_records inventory plugin <community.dns.hetzner_dns_records#inventory>`. Besides the plugin name, no change should be necessary.
diff --git a/ansible_collections/community/dns/docs/docsite/rst/hosttech_guide.rst b/ansible_collections/community/dns/docs/docsite/rst/hosttech_guide.rst
index 8efb8058f..ed44685d5 100644
--- a/ansible_collections/community/dns/docs/docsite/rst/hosttech_guide.rst
+++ b/ansible_collections/community/dns/docs/docsite/rst/hosttech_guide.rst
@@ -17,26 +17,26 @@ The modules support both the old `WSDL-based API <https://ns1.hosttech.eu/public
The collection provides six modules for working with HostTech DNS:
-- :ref:`community.dns.hosttech_dns_record <ansible_collections.community.dns.hosttech_dns_record_module>`: create/update/delete single DNS records
-- :ref:`community.dns.hosttech_dns_record_info <ansible_collections.community.dns.hosttech_dns_record_info_module>`: retrieve information on DNS records
-- :ref:`community.dns.hosttech_dns_record_set <ansible_collections.community.dns.hosttech_dns_record_set_module>`: create/update/delete DNS record sets
-- :ref:`community.dns.hosttech_dns_record_set_info <ansible_collections.community.dns.hosttech_dns_record_set_info_module>`: retrieve information on DNS record sets
-- :ref:`community.dns.hosttech_dns_record_sets <ansible_collections.community.dns.hosttech_dns_record_sets_module>`: bulk synchronize DNS record sets
-- :ref:`community.dns.hosttech_dns_zone_info <ansible_collections.community.dns.hosttech_dns_zone_info_module>`: retrieve zone information
+- :ansplugin:`community.dns.hosttech_dns_record#module`: create/update/delete single DNS records
+- :ansplugin:`community.dns.hosttech_dns_record_info#module`: retrieve information on DNS records
+- :ansplugin:`community.dns.hosttech_dns_record_set#module`: create/update/delete DNS record sets
+- :ansplugin:`community.dns.hosttech_dns_record_set_info#module`: retrieve information on DNS record sets
+- :ansplugin:`community.dns.hosttech_dns_record_sets#module`: bulk synchronize DNS record sets
+- :ansplugin:`community.dns.hosttech_dns_zone_info#module`: retrieve zone information
It also provides an inventory plugin:
-- :ref:`community.dns.hosttech_dns_records <ansible_collections.community.dns.hosttech_dns_records_inventory>`: create inventory from DNS records
+- :ansplugin:`community.dns.hosttech_dns_records#inventory`: create inventory from DNS records
Authentication, Requirements and APIs
-------------------------------------
-HostTech currently has two APIs for working with DNS records: the old WSDL-based API, and the new JSON-based REST API. We recommend using the new REST API if possible.
+HostTech currently has two APIs for working with DNS records: the old WSDL-based API, and the new JSON-based REST API. We recommend using the new JSON REST API if possible.
JSON REST API
~~~~~~~~~~~~~
-To use the JSON REST API, you need to create a API token. You can manage API tokens in the "DNS Editor" in the "API" section. You must provide the token to the ``hosttech_token`` option of the modules:
+To use the JSON REST API, you need to create a API token. You can manage API tokens in the "DNS Editor" in the "API" section. You must provide the token to the :ansopt:`hosttech_token` option of the modules:
.. code-block:: yaml+jinja
@@ -49,7 +49,7 @@ In the examples in this guide, we will leave the authentication options away. Pl
WSDL API
~~~~~~~~
-To use the WSDL API, you need to set API credentials. These can be found and changed in the "Servercenter" and there in the "Solutions" section under settings for the "DNS Tool". The username is fixed, but the password can be changed. The credentials must be provided to the ``hosttech_username`` and ``hosttech_password`` options of the modules.
+To use the WSDL API, you need to set API credentials. These can be found and changed in the "Servercenter" and there in the "Solutions" section under settings for the "DNS Tool". The username is fixed, but the password can be changed. The credentials must be provided to the :ansopt:`hosttech_username` and :ansopt:`hosttech_password` options of the modules.
You also need to install the `lxml Python module <https://pypi.org/project/lxml/>`_ to work with the WSDL API. This can be done before using the modules:
@@ -101,7 +101,7 @@ Here all two tasks will use the options set for the module defaults group.
Working with DNS zones
----------------------
-The :ref:`community.dns.hosttech_dns_zone_info module <ansible_collections.community.dns.hosttech_dns_zone_info_module>` allows to query information on a zone. The zone can be identified both by its name and by its ID (which is an integer):
+The :ansplugin:`community.dns.hosttech_dns_zone_info module <community.dns.hosttech_dns_zone_info#module>` allows to query information on a zone. The zone can be identified both by its name and by its ID (which is an integer):
.. code-block:: yaml+jinja
@@ -129,12 +129,12 @@ Working with DNS records
.. note::
- By default, TXT record values returned and accepted by the modules and plugins in this collection are unquoted. This means that you do not have to add double quotes (``"``), and escape double quotes (as ``\"``) and backslashes (as ``\\``). All modules and plugins which work with DNS records support the ``txt_transformation`` option which allows to configure this behavior.
+ By default, TXT record values returned and accepted by the modules and plugins in this collection are unquoted. This means that you do not have to add double quotes (``"``), and escape double quotes (as ``\"``) and backslashes (as ``\\``). All modules and plugins which work with DNS records support the :ansopt:`community.dns.hosttech_dns_record_set#module:txt_transformation` option which allows to configure this behavior.
Querying DNS records and record sets
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-The :ref:`community.dns.hosttech_dns_record_set_info module <ansible_collections.community.dns.hosttech_dns_record_set_info_module>` allows to query DNS record sets from the API. It can be used to query a single record set:
+The :ansplugin:`community.dns.hosttech_dns_record_set_info module <community.dns.hosttech_dns_record_set_info#module>` allows to query DNS record sets from the API. It can be used to query a single record set:
.. code-block:: yaml+jinja
@@ -161,7 +161,7 @@ The :ref:`community.dns.hosttech_dns_record_set_info module <ansible_collections
msg: There is no A record for www.example.com
when: not result.set
-In all examples in this section, you can replace ``zone_name: example.com`` by ``zone_id: 42`` with the zone's integer ID.
+In all examples in this section, you can replace :ansopt:`community.dns.hosttech_dns_record_set_info#module:zone_name=example.com` by :ansopt:`community.dns.hosttech_dns_record_set_info#module:zone_id=42` with the zone's integer ID.
You can also query a list of all record sets for a record name or prefix:
@@ -201,14 +201,14 @@ Finally you can query all record sets for a zone:
TTL {{ item.ttl }} has values {{ item.value | join(', ') }}
loop: result.sets
-If you are interested in individual DNS records, and not record sets, you should use the :ref:`community.dns.hosttech_dns_record_info module <ansible_collections.community.dns.hosttech_dns_record_info_module>`. It supports the same limiting options as the ``community.dns.hosttech_dns_record_set_info`` module.
+If you are interested in individual DNS records, and not record sets, you should use the :ansplugin:`community.dns.hosttech_dns_record_info module <community.dns.hosttech_dns_record_info#module>`. It supports the same limiting options as the :ansplugin:`community.dns.hosttech_dns_record_set_info module <community.dns.hosttech_dns_record_set_info#module>`.
Creating and updating DNS single records
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you do not want to add/remove values, but replace values, you will be interested in modifying a **record set** and not a single record. This is in particular important when working with ``CNAME`` and ``SOA`` records.
-The :ref:`community.dns.hosttech_dns_record module <ansible_collections.community.dns.hosttech_dns_record_module>` allows to set, update and remove single DNS records. Setting and updating can be done as follows. Records will be matched by record name and type, and the TTL value will be updated if necessary:
+The :ansplugin:`community.dns.hosttech_dns_record module <community.dns.hosttech_dns_record#module>` allows to set, update and remove single DNS records. Setting and updating can be done as follows. Records will be matched by record name and type, and the TTL value will be updated if necessary:
.. code-block:: yaml+jinja
@@ -224,7 +224,7 @@ The :ref:`community.dns.hosttech_dns_record module <ansible_collections.communit
value: 1.1.1.1
ttl: 300
-To delete records, simply use ``state: absent``. Records will be matched by record name and type, and the TTL will be ignored:
+To delete records, simply use :ansopt:`community.dns.hosttech_dns_record#module:state=absent`. Records will be matched by record name and type, and the TTL will be ignored:
.. code-block:: yaml+jinja
@@ -241,7 +241,7 @@ Records of the same type for the same record name with other values are ignored.
Creating and updating DNS record sets
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-The :ref:`community.dns.hosttech_dns_record_set module <ansible_collections.community.dns.hosttech_dns_record_set_module>` allows to set, update and remove DNS record sets. Setting and updating can be done as follows:
+The :ansplugin:`community.dns.hosttech_dns_record_set module <community.dns.hosttech_dns_record_set#module>` allows to set, update and remove DNS record sets. Setting and updating can be done as follows:
.. code-block:: yaml+jinja
@@ -258,9 +258,9 @@ The :ref:`community.dns.hosttech_dns_record_set module <ansible_collections.comm
- 1.1.1.1
- 8.8.8.8
-If you want to assert that a record has a certain value, set ``on_existing: keep``. Using ``keep_and_warn`` instead will emit a warning if this happens, and ``keep_and_fail`` will make the module fail.
+If you want to assert that a record has a certain value, set :ansopt:`community.dns.hosttech_dns_record_set#module:on_existing=keep`. Using :ansval:`keep_and_warn` instead will emit a warning if this happens, and :ansval:`keep_and_fail` will make the module fail.
-To delete values, you can either overwrite the values with value ``[]``, or use ``state: absent``:
+To delete values, you can either overwrite the values with value :ansval:`[]`, or use :ansopt:`community.dns.hosttech_dns_record_set#module:state=absent`:
.. code-block:: yaml+jinja
@@ -290,12 +290,12 @@ To delete values, you can either overwrite the values with value ``[]``, or use
value:
- '::1'
-In the third example, ``on_existing: keep_and_fail`` is present and an explicit value and TTL are given. This makes the module remove the current value only if there's a AAAA record for ``www.example.com`` whose current value is ``::1`` and whose TTL is 300. If another value is set, the module will not make any change, but fail. This can be useful to not accidentally remove values you do not want to change. To issue a warning instead of failing, use ``on_existing: keep_and_warn``, and to simply not do a change without any indication of this situation, use ``on_existing: keep``.
+In the third example, :ansopt:`community.dns.hosttech_dns_record_set#module:on_existing=keep_and_fail` is present and an explicit value and TTL are given. This makes the module remove the current value only if there's a AAAA record for ``www.example.com`` whose current value is ``::1`` and whose TTL is 300. If another value is set, the module will not make any change, but fail. This can be useful to not accidentally remove values you do not want to change. To issue a warning instead of failing, use :ansopt:`community.dns.hosttech_dns_record_set#module:on_existing=keep_and_warn`, and to simply not do a change without any indication of this situation, use :ansopt:`community.dns.hosttech_dns_record_set#module:on_existing=keep`.
Bulk synchronization of DNS record sets
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-If you want to set/update multiple records at once, or even make sure that the precise set of records you are providing are present and nothing else, you can use the :ref:`community.dns.hosttech_dns_record_sets module <ansible_collections.community.dns.hosttech_dns_record_sets_module>`.
+If you want to set/update multiple records at once, or even make sure that the precise set of records you are providing are present and nothing else, you can use the :ansplugin:`community.dns.hosttech_dns_record_sets module <community.dns.hosttech_dns_record_sets#module>`.
The following example shows up to set/update multiple records at once:
@@ -304,7 +304,7 @@ The following example shows up to set/update multiple records at once:
- name: Make sure that multiple records are present
community.dns.hosttech_dns_record_sets:
zone_name: example.com
- records:
+ record_sets:
- prefix: www
type: A
value:
@@ -315,7 +315,7 @@ The following example shows up to set/update multiple records at once:
value:
- '::1'
-The next example shows how to make sure that only the given records are available and all other records are deleted. Note that for the ``type: NS`` record we used ``ignore: true``, which allows us to skip the value. It tells the module that it should not touch the ``NS`` record for ``example.com``.
+The next example shows how to make sure that only the given records are available and all other records are deleted. Note that for the :ansopt:`community.dns.hosttech_dns_record_sets#module:record_sets[].type=NS` record we used :ansopt:`community.dns.hosttech_dns_record_sets#module:record_sets[].ignore=true`, which allows us to skip the value. It tells the module that it should not touch the ``NS`` record for ``example.com``.
.. code-block:: yaml+jinja
@@ -323,7 +323,7 @@ The next example shows how to make sure that only the given records are availabl
community.dns.hosttech_dns_record_sets:
zone_name: example.com
prune: true
- records:
+ record_sets:
- prefix: www
type: A
value:
diff --git a/ansible_collections/community/dns/plugins/doc_fragments/filters.py b/ansible_collections/community/dns/plugins/doc_fragments/filters.py
index e153d4bf9..3227c0f21 100644
--- a/ansible_collections/community/dns/plugins/doc_fragments/filters.py
+++ b/ansible_collections/community/dns/plugins/doc_fragments/filters.py
@@ -26,8 +26,8 @@ options:
keep_unknown_suffix:
description:
- This treats unknown TLDs as valid public suffixes. So for example the public suffix
- of C(example.tlddoesnotexist) is C(.tlddoesnotexist) if this is C(true). If set to
- C(false), it will return an empty string in this case.
+ of C(example.tlddoesnotexist) is C(.tlddoesnotexist) if this is V(true). If set to
+ V(false), it will return an empty string in this case.
- This option corresponds to whether the global wildcard rule C(*) in the Public
Suffix List is used or not.
type: boolean
@@ -40,17 +40,17 @@ options:
description:
- This controls the behavior in case there is no label in front of the public suffix.
This is the case if the DNS name itself is a public suffix.
- - If set to C(false), in this case the public suffix is treated as a registrable domain.
- - If set to C(true) (default), the registrable domain of a public suffix is interpreted as an
+ - If set to V(false), in this case the public suffix is treated as a registrable domain.
+ - If set to V(true) (default), the registrable domain of a public suffix is interpreted as an
empty string.
type: boolean
default: true
keep_unknown_suffix:
description:
- This treats unknown TLDs as valid public suffixes. So for example the public suffix of
- C(example.tlddoesnotexist) is C(.tlddoesnotexist) if this is C(true), and hence the
+ C(example.tlddoesnotexist) is C(.tlddoesnotexist) if this is V(true), and hence the
registrable domain of C(www.example.tlddoesnotexist) is C(example.tlddoesnotexist).
- If set to C(false), the registrable domain of C(www.example.tlddoesnotexist) is
+ If set to V(false), the registrable domain of C(www.example.tlddoesnotexist) is
C(tlddoesnotexist).
- This option corresponds to whether the global wildcard rule C(*) in the Public Suffix List
is used or not.
diff --git a/ansible_collections/community/dns/plugins/doc_fragments/hetzner.py b/ansible_collections/community/dns/plugins/doc_fragments/hetzner.py
index 3b79e5da0..3e8199b85 100644
--- a/ansible_collections/community/dns/plugins/doc_fragments/hetzner.py
+++ b/ansible_collections/community/dns/plugins/doc_fragments/hetzner.py
@@ -16,7 +16,7 @@ options:
hetzner_token:
description:
- The token for the Hetzner API.
- - If not provided, will be read from the environment variable C(HETZNER_DNS_TOKEN).
+ - If not provided, will be read from the environment variable E(HETZNER_DNS_TOKEN).
aliases:
- api_token
type: str
@@ -33,6 +33,15 @@ options:
- name: HETZNER_DNS_TOKEN
'''
+ # NOTE: This document fragment adds additional information on records.
+ RECORD_NOTES = r'''
+options: {}
+notes:
+ - For C(CNAME) records, use absolute DNS names for values. Absolute DNS names end with
+ a trailing period C(.), for example C(foo.example.com.). If you use a relative DNS name, with no
+ trailing period, the value will be relative to the zone of the C(CNAME) record.
+'''
+
# WARNING: This section is automatically generated by update-docs-fragments.py.
# It is used to augment the docs fragments module_record, module_record_set.
# DO NOT EDIT MANUALLY!
@@ -76,17 +85,19 @@ options:
record:
description:
- The full DNS record to create or delete.
- - Exactly one of I(record) and I(prefix) must be specified.
+ - Exactly one of O(record_sets[].record) and O(record_sets[].prefix)
+ must be specified.
type: str
prefix:
description:
- The prefix of the DNS record.
- - This is the part of I(record) before I(zone_name). For example,
- if the record to be modified is C(www.example.com) for the zone
- C(example.com), the prefix is C(www). If the record in this
- example would be C(example.com), the prefix would be C('') (empty
- string).
- - Exactly one of I(record) and I(prefix) must be specified.
+ - This is the part of O(record_sets[].record) before O(zone_name).
+ For example, if the record to be modified is C(www.example.com)
+ for the zone C(example.com), the prefix is V(www). If the record
+ in this example would be C(example.com), the prefix would be
+ V('') (empty string).
+ - Exactly one of O(record_sets[].record) and O(record_sets[].prefix)
+ must be specified.
type: str
ttl:
description:
@@ -119,13 +130,13 @@ options:
- YAML lists or multiple comma-spaced values are allowed.
- When deleting a record all values for the record must be specified
or it will not be deleted.
- - Must be specified if I(ignore=false).
+ - Must be specified if O(record_sets[].ignore=false).
type: list
elements: str
ignore:
description:
- - If set to C(true), I(value) will be ignored.
- - This is useful when I(prune=true), but you do not want certain
+ - If set to V(true), O(record_sets[].value) will be ignored.
+ - This is useful when O(prune=true), but you do not want certain
entries to be removed without having to know their current value.
type: bool
default: false
@@ -136,7 +147,7 @@ options:
# DO NOT EDIT MANUALLY!
RECORD_TYPE_CHOICES_RECORDS_INVENTORY = r'''
options:
- filters:
+ simple_filters:
suboptions:
type:
description:
diff --git a/ansible_collections/community/dns/plugins/doc_fragments/hosttech.py b/ansible_collections/community/dns/plugins/doc_fragments/hosttech.py
index 937983f50..571b0e595 100644
--- a/ansible_collections/community/dns/plugins/doc_fragments/hosttech.py
+++ b/ansible_collections/community/dns/plugins/doc_fragments/hosttech.py
@@ -19,20 +19,20 @@ options:
hosttech_username:
description:
- The username for the Hosttech API user.
- - If provided, I(hosttech_password) must also be provided.
- - Mutually exclusive with I(hosttech_token).
+ - If provided, O(hosttech_password) must also be provided.
+ - Mutually exclusive with O(hosttech_token).
type: str
hosttech_password:
description:
- The password for the Hosttech API user.
- - If provided, I(hosttech_username) must also be provided.
- - Mutually exclusive with I(hosttech_token).
+ - If provided, O(hosttech_username) must also be provided.
+ - Mutually exclusive with O(hosttech_token).
type: str
hosttech_token:
description:
- The password for the Hosttech API user.
- - Mutually exclusive with I(hosttech_username) and I(hosttech_password).
- - Since community.dns 1.2.0, the alias I(api_token) can be used.
+ - Mutually exclusive with O(hosttech_username) and O(hosttech_password).
+ - Since community.dns 1.2.0, the alias O(ignore:api_token) can be used.
aliases:
- api_token
type: str
@@ -58,6 +58,11 @@ options:
version_added: 2.5.0
'''
+ # NOTE: This document fragment adds additional information on records.
+ RECORD_NOTES = r'''
+options: {}
+'''
+
# WARNING: This section is automatically generated by update-docs-fragments.py.
# It is used to augment the docs fragments module_record, module_record_set.
# DO NOT EDIT MANUALLY!
@@ -97,17 +102,19 @@ options:
record:
description:
- The full DNS record to create or delete.
- - Exactly one of I(record) and I(prefix) must be specified.
+ - Exactly one of O(record_sets[].record) and O(record_sets[].prefix)
+ must be specified.
type: str
prefix:
description:
- The prefix of the DNS record.
- - This is the part of I(record) before I(zone_name). For example,
- if the record to be modified is C(www.example.com) for the zone
- C(example.com), the prefix is C(www). If the record in this
- example would be C(example.com), the prefix would be C('') (empty
- string).
- - Exactly one of I(record) and I(prefix) must be specified.
+ - This is the part of O(record_sets[].record) before O(zone_name).
+ For example, if the record to be modified is C(www.example.com)
+ for the zone C(example.com), the prefix is V(www). If the record
+ in this example would be C(example.com), the prefix would be
+ V('') (empty string).
+ - Exactly one of O(record_sets[].record) and O(record_sets[].prefix)
+ must be specified.
type: str
ttl:
description:
@@ -136,13 +143,13 @@ options:
- YAML lists or multiple comma-spaced values are allowed.
- When deleting a record all values for the record must be specified
or it will not be deleted.
- - Must be specified if I(ignore=false).
+ - Must be specified if O(record_sets[].ignore=false).
type: list
elements: str
ignore:
description:
- - If set to C(true), I(value) will be ignored.
- - This is useful when I(prune=true), but you do not want certain
+ - If set to V(true), O(record_sets[].value) will be ignored.
+ - This is useful when O(prune=true), but you do not want certain
entries to be removed without having to know their current value.
type: bool
default: false
@@ -153,7 +160,7 @@ options:
# DO NOT EDIT MANUALLY!
RECORD_TYPE_CHOICES_RECORDS_INVENTORY = r'''
options:
- filters:
+ simple_filters:
suboptions:
type:
description:
diff --git a/ansible_collections/community/dns/plugins/doc_fragments/inventory_records.py b/ansible_collections/community/dns/plugins/doc_fragments/inventory_records.py
index fcdc55acb..e7a90a7b7 100644
--- a/ansible_collections/community/dns/plugins/doc_fragments/inventory_records.py
+++ b/ansible_collections/community/dns/plugins/doc_fragments/inventory_records.py
@@ -17,24 +17,28 @@ description:
- Records are matched by prefix / record name and value.
notes:
- - The I(zone_name) and I(zone_id) options can be templated.
+ - The O(zone_name) and O(zone_id) options can be templated.
options:
zone_name:
description:
- The DNS zone to modify.
- - Exactly one of I(zone_name) and I(zone_id) must be specified.
+ - Exactly one of O(zone_name) and O(zone_id) must be specified.
type: str
aliases:
- zone
zone_id:
description:
- The ID of the DNS zone to modify.
- - Exactly one of I(zone_name) and I(zone_id) must be specified.
- filters:
+ - Exactly one of O(zone_name) and O(zone_id) must be specified.
+ simple_filters:
description:
- A dictionary of filter value pairs.
+ - This option has been renamed from O(filters) to O(simple_filters) in community.dns 2.8.0.
+ The old name can still be used until community.dns 3.0.0.
type: dict
+ aliases:
+ - filters
default: {}
suboptions:
# (The following must be kept in sync with the equivalent lines in <provider_name>.py!)
diff --git a/ansible_collections/community/dns/plugins/doc_fragments/module_record.py b/ansible_collections/community/dns/plugins/doc_fragments/module_record.py
index 4eaa956aa..d79313555 100644
--- a/ansible_collections/community/dns/plugins/doc_fragments/module_record.py
+++ b/ansible_collections/community/dns/plugins/doc_fragments/module_record.py
@@ -28,26 +28,26 @@ options:
zone_name:
description:
- The DNS zone to modify.
- - Exactly one of I(zone_name) and I(zone_id) must be specified.
+ - Exactly one of O(zone_name) and O(zone_id) must be specified.
type: str
aliases:
- zone
zone_id:
description:
- The ID of the DNS zone to modify.
- - Exactly one of I(zone_name) and I(zone_id) must be specified.
+ - Exactly one of O(zone_name) and O(zone_id) must be specified.
record:
description:
- The full DNS record to create or delete.
- - Exactly one of I(record) and I(prefix) must be specified.
+ - Exactly one of O(record) and O(prefix) must be specified.
type: str
prefix:
description:
- The prefix of the DNS record.
- - This is the part of I(record) before I(zone_name). For example, if the record to be modified is C(www.example.com)
- for the zone C(example.com), the prefix is C(www). If the record in this example would be C(example.com), the
- prefix would be C('') (empty string).
- - Exactly one of I(record) and I(prefix) must be specified.
+ - This is the part of O(record) before O(zone_name). For example, if the record to be modified is C(www.example.com)
+ for the zone C(example.com), the prefix is V(www). If the record in this example would be C(example.com), the
+ prefix would be V('') (empty string).
+ - Exactly one of O(record) and O(prefix) must be specified.
type: str
ttl:
description:
diff --git a/ansible_collections/community/dns/plugins/doc_fragments/module_record_info.py b/ansible_collections/community/dns/plugins/doc_fragments/module_record_info.py
index e039ec6aa..43b0549c2 100644
--- a/ansible_collections/community/dns/plugins/doc_fragments/module_record_info.py
+++ b/ansible_collections/community/dns/plugins/doc_fragments/module_record_info.py
@@ -27,30 +27,30 @@ options:
zone_name:
description:
- The DNS zone to modify.
- - Exactly one of I(zone) and I(zone_id) must be specified.
+ - Exactly one of O(zone_name) and O(zone_id) must be specified.
type: str
aliases:
- zone
zone_id:
description:
- The ID of the DNS zone to modify.
- - Exactly one of I(zone_name) and I(zone_id) must be specified.
+ - Exactly one of O(zone_name) and O(zone_id) must be specified.
record:
description:
- The full DNS record to retrieve.
- - If I(what) is C(single_record) or C(all_types_for_record), exactly one of I(record) and I(prefix) is required.
+ - If O(what) is V(single_record) or V(all_types_for_record), exactly one of O(record) and O(prefix) is required.
type: str
prefix:
description:
- The prefix of the DNS record.
- - This is the part of I(record) before I(zone_name). For example, if the record to be modified is C(www.example.com)
- for the zone C(example.com), the prefix is C(www). If the record in this example would be C(example.com), the
- prefix would be C('') (empty string).
- - If I(what) is C(single_record) or C(all_types_for_record), exactly one of I(record) and I(prefix) is required.
+ - This is the part of O(record) before O(zone_name). For example, if the record to be modified is C(www.example.com)
+ for the zone C(example.com), the prefix is V(www). If the record in this example would be C(example.com), the
+ prefix would be V('') (empty string).
+ - If O(what) is V(single_record) or V(all_types_for_record), exactly one of O(record) and O(prefix) is required.
type: str
type:
description:
- The type of DNS record to retrieve.
- - Required if I(what) is C(single_record).
+ - Required if O(what) is V(single_record).
type: str
'''
diff --git a/ansible_collections/community/dns/plugins/doc_fragments/module_record_set.py b/ansible_collections/community/dns/plugins/doc_fragments/module_record_set.py
index 2b4004422..2fb83186c 100644
--- a/ansible_collections/community/dns/plugins/doc_fragments/module_record_set.py
+++ b/ansible_collections/community/dns/plugins/doc_fragments/module_record_set.py
@@ -25,33 +25,32 @@ options:
zone_name:
description:
- The DNS zone to modify.
- - Exactly one of I(zone_name) and I(zone_id) must be specified.
+ - Exactly one of O(zone_name) and O(zone_id) must be specified.
type: str
aliases:
- zone
zone_id:
description:
- The ID of the DNS zone to modify.
- - Exactly one of I(zone_name) and I(zone_id) must be specified.
+ - Exactly one of O(zone_name) and O(zone_id) must be specified.
version_added: 0.2.0
record:
description:
- The full DNS record to create or delete.
- - Exactly one of I(record) and I(prefix) must be specified.
+ - Exactly one of O(record) and O(prefix) must be specified.
type: str
prefix:
description:
- The prefix of the DNS record.
- - This is the part of I(record) before I(zone_name). For example, if the record to be modified is C(www.example.com)
- for the zone C(example.com), the prefix is C(www). If the record in this example would be C(example.com), the
- prefix would be C('') (empty string).
- - Exactly one of I(record) and I(prefix) must be specified.
+ - This is the part of O(record) before O(zone_name). For example, if the record to be modified is C(www.example.com)
+ for the zone C(example.com), the prefix is V(www). If the record in this example would be C(example.com), the
+ prefix would be V('') (empty string).
+ - Exactly one of O(record) and O(prefix) must be specified.
type: str
version_added: 0.2.0
ttl:
description:
- The TTL to give the new record, in seconds.
- - Will be ignored if I(state=absent) and I(on_existing=replace).
type: int
type:
description:
@@ -64,22 +63,22 @@ options:
- YAML lists or multiple comma-spaced values are allowed.
- When deleting a record all values for the record must be specified or it will
not be deleted.
- - Must be specified if I(state=present) or when I(on_existing) is not C(replace).
- - Will be ignored if I(state=absent) and I(on_existing=replace).
+ - Must be specified if O(state=present) or when O(on_existing) is not V(replace).
+ - Will be ignored if O(state=absent) and O(on_existing=replace).
type: list
elements: str
on_existing:
description:
- This option defines the behavior if the record set already exists, but differs from the specified record set.
- For this comparison, I(value) and I(ttl) are used for all records of type I(type) matching the I(prefix) resp. I(record).
- - If set to C(replace), the record will be updated (I(state=present)) or removed (I(state=absent)).
- This is the old I(overwrite=true) behavior.
- - If set to C(keep_and_fail), the module will fail and not modify the records.
- This is the old I(overwrite=false) behavior if I(state=present).
- - If set to C(keep_and_warn), the module will warn and not modify the records.
- - If set to C(keep), the module will not modify the records.
- This is the old I(overwrite=false) behavior if I(state=absent).
- - If I(state=absent) and the value is not C(replace), I(value) must be specified.
+ For this comparison, O(value) and O(ttl) are used for all records of type O(type) matching the O(prefix) resp. O(record).
+ - If set to V(replace), the record will be updated (O(state=present)) or removed (O(state=absent)).
+ This is the old O(ignore:overwrite=true) behavior.
+ - If set to V(keep_and_fail), the module will fail and not modify the records.
+ This is the old O(ignore:overwrite=false) behavior if O(state=present).
+ - If set to V(keep_and_warn), the module will warn and not modify the records.
+ - If set to V(keep), the module will not modify the records.
+ This is the old O(ignore:overwrite=false) behavior if O(state=absent).
+ - If O(state=absent) and the value is not V(replace), O(value) must be specified.
default: replace
type: str
choices:
diff --git a/ansible_collections/community/dns/plugins/doc_fragments/module_record_set_info.py b/ansible_collections/community/dns/plugins/doc_fragments/module_record_set_info.py
index 857e9036e..2fa5321dd 100644
--- a/ansible_collections/community/dns/plugins/doc_fragments/module_record_set_info.py
+++ b/ansible_collections/community/dns/plugins/doc_fragments/module_record_set_info.py
@@ -27,32 +27,32 @@ options:
zone_name:
description:
- The DNS zone to modify.
- - Exactly one of I(zone) and I(zone_id) must be specified.
+ - Exactly one of O(zone_name) and O(zone_id) must be specified.
type: str
aliases:
- zone
zone_id:
description:
- The ID of the DNS zone to modify.
- - Exactly one of I(zone_name) and I(zone_id) must be specified.
+ - Exactly one of O(zone_name) and O(zone_id) must be specified.
version_added: 0.2.0
record:
description:
- The full DNS record to retrieve.
- - If I(what) is C(single_record) or C(all_types_for_record), exactly one of I(record) and I(prefix) is required.
+ - If O(what) is V(single_record) or V(all_types_for_record), exactly one of O(record) and O(prefix) is required.
type: str
prefix:
description:
- The prefix of the DNS record.
- - This is the part of I(record) before I(zone_name). For example, if the record to be modified is C(www.example.com)
- for the zone C(example.com), the prefix is C(www). If the record in this example would be C(example.com), the
- prefix would be C('') (empty string).
- - If I(what) is C(single_record) or C(all_types_for_record), exactly one of I(record) and I(prefix) is required.
+ - This is the part of O(record) before O(zone_name). For example, if the record to be modified is C(www.example.com)
+ for the zone C(example.com), the prefix is V(www). If the record in this example would be C(example.com), the
+ prefix would be V('') (empty string).
+ - If O(what) is V(single_record) or V(all_types_for_record), exactly one of O(record) and O(prefix) is required.
type: str
version_added: 0.2.0
type:
description:
- The type of DNS record to retrieve.
- - Required if I(what) is C(single_record).
+ - Required if O(what) is V(single_record).
type: str
'''
diff --git a/ansible_collections/community/dns/plugins/doc_fragments/module_record_sets.py b/ansible_collections/community/dns/plugins/doc_fragments/module_record_sets.py
index 1b393b444..cf3fcbe9f 100644
--- a/ansible_collections/community/dns/plugins/doc_fragments/module_record_sets.py
+++ b/ansible_collections/community/dns/plugins/doc_fragments/module_record_sets.py
@@ -14,27 +14,27 @@ class ModuleDocFragment(object):
DOCUMENTATION = r'''
description:
- The module allows to set, modify and delete multiple DNS record sets at once.
- - With the I(purge) option, it is also possible to delete existing record sets
+ - With the O(prune) option, it is also possible to delete existing record sets
that are not mentioned in the module parameters. With this, it is possible
to synchronize the expected state of a DNS zone with the expected state.
- - "It is possible to ignore certain record sets by specifying I(ignore: true) for
+ - "It is possible to ignore certain record sets by specifying O(record_sets[].ignore=true) for
that record set."
options:
zone_name:
description:
- The DNS zone to modify.
- - Exactly one of I(zone_name) and I(zone_id) must be specified.
+ - Exactly one of O(zone_name) and O(zone_id) must be specified.
type: str
aliases:
- zone
zone_id:
description:
- The ID of the DNS zone to modify.
- - Exactly one of I(zone_name) and I(zone_id) must be specified.
+ - Exactly one of O(zone_name) and O(zone_id) must be specified.
prune:
description:
- - If set to C(true), will remove all existing records in the zone that are not listed in I(records).
+ - If set to V(true), will remove all existing records in the zone that are not listed in O(record_sets).
type: bool
default: false
record_sets:
@@ -50,15 +50,15 @@ options:
record:
description:
- The full DNS record to create or delete.
- - Exactly one of I(record) and I(prefix) must be specified.
+ - Exactly one of O(record_sets[].record) and O(record_sets[].prefix) must be specified.
type: str
prefix:
description:
- The prefix of the DNS record.
- - This is the part of I(record) before I(zone_name). For example, if the record to be modified is C(www.example.com)
- for the zone C(example.com), the prefix is C(www). If the record in this example would be C(example.com), the
- prefix would be C('') (empty string).
- - Exactly one of I(record) and I(prefix) must be specified.
+ - This is the part of O(record_sets[].record) before O(zone_name). For example, if the record to be modified is C(www.example.com)
+ for the zone C(example.com), the prefix is V(www). If the record in this example would be C(example.com), the
+ prefix would be V('') (empty string).
+ - Exactly one of O(record_sets[].record) and O(record_sets[].prefix) must be specified.
type: str
ttl:
description:
@@ -75,13 +75,13 @@ options:
- YAML lists or multiple comma-spaced values are allowed.
- When deleting a record all values for the record must be specified or it will
not be deleted.
- - Must be specified if I(ignore=false).
+ - Must be specified if O(record_sets[].ignore=false).
type: list
elements: str
ignore:
description:
- - If set to C(true), I(value) will be ignored.
- - This is useful when I(prune=true), but you do not want certain entries to be removed
+ - If set to V(true), O(record_sets[].value) will be ignored.
+ - This is useful when O(prune=true), but you do not want certain entries to be removed
without having to know their current value.
type: bool
default: false
diff --git a/ansible_collections/community/dns/plugins/doc_fragments/module_zone_info.py b/ansible_collections/community/dns/plugins/doc_fragments/module_zone_info.py
index b218051e5..bcccfea73 100644
--- a/ansible_collections/community/dns/plugins/doc_fragments/module_zone_info.py
+++ b/ansible_collections/community/dns/plugins/doc_fragments/module_zone_info.py
@@ -16,13 +16,13 @@ options:
zone_name:
description:
- The DNS zone to query.
- - Exactly one of I(zone_name) and I(zone_id) must be specified.
+ - Exactly one of O(zone_name) and O(zone_id) must be specified.
type: str
aliases:
- zone
zone_id:
description:
- The ID of the DNS zone to query.
- - Exactly one of I(zone_name) and I(zone_id) must be specified.
+ - Exactly one of O(zone_name) and O(zone_id) must be specified.
version_added: 0.2.0
'''
diff --git a/ansible_collections/community/dns/plugins/doc_fragments/options.py b/ansible_collections/community/dns/plugins/doc_fragments/options.py
index a9e92e8b5..55c83f1b2 100644
--- a/ansible_collections/community/dns/plugins/doc_fragments/options.py
+++ b/ansible_collections/community/dns/plugins/doc_fragments/options.py
@@ -28,23 +28,23 @@ options:
description:
- Determines how TXT entry values are converted between the API and this module's
input and output.
- - The value C(api) means that values are returned from this module as they are returned
+ - The value V(api) means that values are returned from this module as they are returned
from the API, and pushed to the API as they have been passed to this module. For
idempotency checks, the input string will be compared to the strings returned by the
API. The API might automatically transform some values, like splitting long values or
adding quotes, which can cause problems with idempotency.
- - The value C(unquoted) automatically transforms values so that you can pass in unquoted
+ - The value V(unquoted) automatically transforms values so that you can pass in unquoted
values, and the module will return unquoted values. If you pass in quoted values, they
will be double-quoted.
- - The value C(quoted) automatically transforms values so that you must use quoting for values
+ - The value V(quoted) automatically transforms values so that you must use quoting for values
that contain spaces, characters such as quotation marks and backslashes, and that are
longer than 255 bytes. It also makes sure to return values from the API in a normalized
encoding.
- - The default value, C(unquoted), ensures that you can work with values without having
- to care about how to correctly quote for DNS. Most users should use one of C(unquoted)
- or C(quoted), but not C(api).
+ - The default value, V(unquoted), ensures that you can work with values without having
+ to care about how to correctly quote for DNS. Most users should use one of V(unquoted)
+ or V(quoted), but not V(api).
- B(Note:) the conversion code assumes UTF-8 encoding for values. If you need another
- encoding use I(txt_transformation=api) and handle the encoding yourself.
+ encoding use O(txt_transformation=api) and handle the encoding yourself.
type: str
choices:
- api
@@ -53,10 +53,10 @@ options:
default: unquoted
txt_character_encoding:
description:
- - Whether to treat numeric escape sequences (C(\xyz)) as octal or decimal numbers.
- This is only used when I(txt_transformation=quoted).
- - The current default is C(octal) which is deprecated. It will change to C(decimal) in
- community.dns 3.0.0. The value C(decimal) is compatible to L(RFC 1035, https://www.ietf.org/rfc/rfc1035.txt).
+ - Whether to treat numeric escape sequences (V(\\xyz)) as octal or decimal numbers.
+ This is only used when O(txt_transformation=quoted).
+ - The current default is V(octal) which is deprecated. It will change to V(decimal) in
+ community.dns 3.0.0. The value V(decimal) is compatible to L(RFC 1035, https://www.ietf.org/rfc/rfc1035.txt).
type: str
choices:
- decimal
diff --git a/ansible_collections/community/dns/plugins/inventory/hetzner_dns_records.py b/ansible_collections/community/dns/plugins/inventory/hetzner_dns_records.py
index 970cd8631..7982c23f0 100644
--- a/ansible_collections/community/dns/plugins/inventory/hetzner_dns_records.py
+++ b/ansible_collections/community/dns/plugins/inventory/hetzner_dns_records.py
@@ -23,7 +23,7 @@ description:
options:
plugin:
- description: The name of this plugin. Should always be set to C(community.dns.hetzner_dns_records) for this plugin to recognize it as its own.
+ description: The name of this plugin. Should always be set to V(community.dns.hetzner_dns_records) for this plugin to recognize it as its own.
# TODO: add `required: true` in 3.0.0
# required: true
choices:
@@ -39,7 +39,7 @@ extends_documentation_fragment:
- community.dns.options.record_transformation
notes:
- - The provider-specific I(hetzner_token) option can be templated.
+ - The provider-specific O(hetzner_token) option can be templated.
author:
- Markus Bergholz (@markuman) <markuman+spambelongstogoogle@gmail.com>
@@ -55,7 +55,7 @@ EXAMPLES = '''
plugin: community.dns.hetzner_dns_records
zone_name: domain.de
-filters:
+simple_filters:
type:
- TXT
txt_transformation: unquoted
diff --git a/ansible_collections/community/dns/plugins/inventory/hosttech_dns_records.py b/ansible_collections/community/dns/plugins/inventory/hosttech_dns_records.py
index aa840510d..d14cf73ed 100644
--- a/ansible_collections/community/dns/plugins/inventory/hosttech_dns_records.py
+++ b/ansible_collections/community/dns/plugins/inventory/hosttech_dns_records.py
@@ -23,7 +23,7 @@ description:
options:
plugin:
- description: The name of this plugin. Should always be set to C(community.dns.hosttech_dns_records) for this plugin to recognize it as its own.
+ description: The name of this plugin. Should always be set to V(community.dns.hosttech_dns_records) for this plugin to recognize it as its own.
# TODO: add `required: true` in 3.0.0
# required: true
choices:
@@ -47,7 +47,7 @@ extends_documentation_fragment:
- community.dns.options.record_transformation
notes:
- - The provider-specific I(hosttech_username), I(hosttech_password), and I(hosttech_token) options can be templated.
+ - The provider-specific O(hosttech_username), O(hosttech_password), and O(hosttech_token) options can be templated.
author:
- Markus Bergholz (@markuman) <markuman+spambelongstogoogle@gmail.com>
@@ -63,7 +63,7 @@ EXAMPLES = '''
plugin: community.dns.hosttech_dns_records
zone_name: domain.ch
-filters:
+simple_filters:
type:
- AAAA
diff --git a/ansible_collections/community/dns/plugins/lookup/lookup.py b/ansible_collections/community/dns/plugins/lookup/lookup.py
new file mode 100644
index 000000000..9f18164b1
--- /dev/null
+++ b/ansible_collections/community/dns/plugins/lookup/lookup.py
@@ -0,0 +1,210 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2023, Felix Fontein <felix@fontein.de>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+DOCUMENTATION = r'''
+name: lookup
+author: Felix Fontein (@felixfontein)
+short_description: Look up DNS records
+version_added: 2.6.0
+requirements:
+ - dnspython >= 1.15.0 (maybe older versions also work)
+ - ipaddress (on Python 2.7 when using O(server))
+description:
+ - Look up DNS records.
+options:
+ _terms:
+ description:
+ - Domain name(s) to query.
+ type: list
+ elements: str
+ required: true
+ type:
+ description:
+ - The record type to retrieve.
+ type: str
+ default: A
+ choices:
+ - A
+ - ALL
+ - AAAA
+ - CAA
+ - CNAME
+ - DNAME
+ - DNSKEY
+ - DS
+ - HINFO
+ - LOC
+ - MX
+ - NAPTR
+ - NS
+ - NSEC
+ - NSEC3
+ - NSEC3PARAM
+ - PTR
+ - RP
+ - RRSIG
+ - SOA
+ - SPF
+ - SRV
+ - SSHFP
+ - TLSA
+ - TXT
+ query_retry:
+ description:
+ - Number of retries for DNS query timeouts.
+ type: int
+ default: 3
+ query_timeout:
+ description:
+ - Timeout per DNS query in seconds.
+ type: float
+ default: 10
+ server:
+ description:
+ - The DNS server(s) to use to look up the result. Must be a list of one or more IP addresses.
+ - By default, the system's standard resolver is used.
+ type: list
+ elements: str
+ servfail_retries:
+ description:
+ - How often to retry on SERVFAIL errors.
+ type: int
+ default: 0
+ nxdomain_handling:
+ description:
+ - How to handle NXDOMAIN errors. These appear if an unknown domain name is queried.
+ - V(empty) (default) returns an empty result for that domain name.
+ This means that for the corresponding domain name, nothing is added to RV(_result).
+ - V(fail) makes the lookup fail.
+ - V(message) adds the string V(NXDOMAIN) to RV(_result).
+ type: str
+ choices:
+ - empty
+ - fail
+ - message
+ default: empty
+notes:
+ - Note that when using this lookup plugin with V(lookup(\)), and the result is a one-element list,
+ Ansible simply returns the one element not as a list. Since this behavior is surprising and
+ can cause problems, it is better to use V(query(\)) instead of V(lookup(\)). See the examples
+ and also R(Forcing lookups to return lists, query) in the Ansible documentation.
+'''
+
+EXAMPLES = """
+- name: Look up A (IPv4) records for example.org
+ ansible.builtin.debug:
+ msg: "{{ query('community.dns.lookup', 'example.org.') }}"
+
+- name: Look up AAAA (IPv6) records for example.org
+ ansible.builtin.debug:
+ msg: "{{ query('community.dns.lookup', 'example.org.', type='AAAA' ) }}"
+"""
+
+RETURN = """
+_result:
+ description:
+ - The records of type O(type) for all queried DNS names.
+ - If multiple DNS names are queried in O(_terms), the resulting lists have been concatenated.
+ type: list
+ elements: str
+ sample:
+ - 127.0.0.1
+"""
+
+from ansible.errors import AnsibleLookupError
+from ansible.plugins.lookup import LookupBase
+from ansible.module_utils.common.text.converters import to_text
+
+from ansible_collections.community.dns.plugins.module_utils.ips import (
+ is_ip_address,
+)
+
+from ansible_collections.community.dns.plugins.module_utils.dnspython_records import (
+ NAME_TO_RDTYPE,
+)
+
+from ansible_collections.community.dns.plugins.module_utils.resolver import (
+ SimpleResolver,
+)
+
+from ansible_collections.community.dns.plugins.plugin_utils.ips import (
+ assert_requirements_present as assert_requirements_present_ipaddress,
+)
+
+from ansible_collections.community.dns.plugins.plugin_utils.resolver import (
+ assert_requirements_present as assert_requirements_present_dnspython,
+ guarded_run,
+)
+
+try:
+ import dns.resolver
+except ImportError:
+ # handled by assert_requirements_present_dnspython
+ pass
+
+
+class LookupModule(LookupBase):
+ @staticmethod
+ def _resolve(resolver, name, rdtype, server_addresses, nxdomain_handling):
+ def callback():
+ try:
+ rrset = resolver.resolve(
+ name,
+ rdtype=rdtype,
+ server_addresses=server_addresses,
+ nxdomain_is_empty=nxdomain_handling == 'empty',
+ )
+ if not rrset:
+ return []
+ return [to_text(data) for data in rrset]
+ except dns.resolver.NXDOMAIN:
+ if nxdomain_handling == 'message':
+ return ['NXDOMAIN']
+ raise AnsibleLookupError('Got NXDOMAIN when querying {name}'.format(name=name))
+
+ return guarded_run(
+ callback,
+ error_class=AnsibleLookupError,
+ server=name,
+ )
+
+ def run(self, terms, variables=None, **kwargs):
+ assert_requirements_present_dnspython('community.dns.lookup', 'lookup')
+
+ self.set_options(var_options=variables, direct=kwargs)
+
+ resolver = SimpleResolver(
+ timeout=self.get_option('query_timeout'),
+ timeout_retries=self.get_option('query_retry'),
+ servfail_retries=self.get_option('servfail_retries'),
+ )
+
+ rdtype = NAME_TO_RDTYPE[self.get_option('type')]
+
+ nxdomain_handling = self.get_option('nxdomain_handling')
+
+ server_addresses = None
+ if self.get_option('server'):
+ server_addresses = []
+ assert_requirements_present_ipaddress('community.dns.lookup', 'lookup')
+ for server in self.get_option('server'):
+ if is_ip_address(server):
+ server_addresses.append(server)
+ continue
+ else:
+ server_addresses.extend(guarded_run(
+ lambda: resolver.resolve_addresses(server),
+ error_class=AnsibleLookupError,
+ server=server,
+ ))
+
+ result = []
+ for name in terms:
+ result.extend(self._resolve(resolver, name, rdtype, server_addresses, nxdomain_handling))
+ return result
diff --git a/ansible_collections/community/dns/plugins/lookup/lookup_as_dict.py b/ansible_collections/community/dns/plugins/lookup/lookup_as_dict.py
new file mode 100644
index 000000000..8783d86c1
--- /dev/null
+++ b/ansible_collections/community/dns/plugins/lookup/lookup_as_dict.py
@@ -0,0 +1,497 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2023, Felix Fontein <felix@fontein.de>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+DOCUMENTATION = r'''
+name: lookup_as_dict
+author: Felix Fontein (@felixfontein)
+short_description: Look up DNS records as dictionaries
+version_added: 2.6.0
+requirements:
+ - dnspython >= 1.15.0 (maybe older versions also work)
+ - ipaddress (on Python 2.7 when using O(server))
+description:
+ - Look up DNS records and return them as interpreted dictionaries.
+options:
+ _terms:
+ description:
+ - Domain name(s) to query.
+ type: list
+ elements: str
+ required: true
+ type:
+ description:
+ - The record type to retrieve.
+ type: str
+ default: A
+ choices:
+ - A
+ - ALL
+ - AAAA
+ - CAA
+ - CNAME
+ - DNAME
+ - DNSKEY
+ - DS
+ - HINFO
+ - LOC
+ - MX
+ - NAPTR
+ - NS
+ - NSEC
+ - NSEC3
+ - NSEC3PARAM
+ - PTR
+ - RP
+ - RRSIG
+ - SOA
+ - SPF
+ - SRV
+ - SSHFP
+ - TLSA
+ - TXT
+ query_retry:
+ description:
+ - Number of retries for DNS query timeouts.
+ type: int
+ default: 3
+ query_timeout:
+ description:
+ - Timeout per DNS query in seconds.
+ type: float
+ default: 10
+ server:
+ description:
+ - The DNS server(s) to use to look up the result. Must be a list of one or more IP addresses.
+ - By default, the system's standard resolver is used.
+ type: list
+ elements: str
+ servfail_retries:
+ description:
+ - How often to retry on SERVFAIL errors.
+ type: int
+ default: 0
+ nxdomain_handling:
+ description:
+ - How to handle NXDOMAIN errors. These appear if an unknown domain name is queried.
+ - V(empty) (default) returns an empty result for that domain name.
+ This means that for the corresponding domain name, nothing is added to RV(_result).
+ - V(fail) makes the lookup fail.
+ type: str
+ choices:
+ - empty
+ - fail
+ default: empty
+notes:
+ - Note that when using this lookup plugin with V(lookup(\)), and the result is a one-element list,
+ Ansible simply returns the one element not as a list. Since this behavior is surprising and
+ can cause problems, it is better to use V(query(\)) instead of V(lookup(\)). See the examples
+ and also R(Forcing lookups to return lists, query) in the Ansible documentation.
+'''
+
+EXAMPLES = """
+- name: Look up A (IPv4) records for example.org as a list of dictionaries
+ ansible.builtin.debug:
+ msg: "{{ query('community.dns.lookup_as_dict', 'example.org.') }}"
+
+- name: Look up AAAA (IPv6) records for example.org as a list of IPv6 addresses
+ ansible.builtin.debug:
+ msg: "{{ query('community.dns.lookup_as_dict', 'example.org.', type='AAAA' ) | map(attribute='address') }}"
+
+- name: Look up TXT records for ansible.com as a list of strings
+ ansible.builtin.debug:
+ msg: "{{ query('community.dns.lookup_as_dict', 'ansible.com.', type='TXT' ) | map(attribute='value') }}"
+"""
+
+RETURN = """
+_result:
+ description:
+ - The records of type O(type) for all queried DNS names.
+ - If multiple DNS names are queried in O(_terms), the resulting lists have been concatenated.
+ - Depending on O(type), different fields are returned.
+ - For O(type=TXT) and O(type=SPF), also the concatenated value is returned as RV(_result[].value).
+ type: list
+ elements: dict
+ sample:
+ - address: 127.0.0.1
+ contains:
+ address:
+ description:
+ - A IPv4 respectively IPv6 address.
+ type: str
+ returned: if O(type=A) or O(type=AAAA)
+ algorithm:
+ description:
+ - The algorithm ID.
+ type: int
+ returned: if O(type=DNSKEY) or O(type=DS) or O(type=NSEC3) or O(type=NSEC3PARAM) or O(type=RRSIG) or O(type=SSHFP)
+ altitude:
+ description:
+ - The altitude.
+ type: float
+ returned: if O(type=LOC)
+ cert:
+ description:
+ - The certificate.
+ type: str
+ returned: if O(type=TLSA)
+ cpu:
+ description:
+ - The CPU.
+ type: str
+ returned: if O(type=HINFO)
+ digest:
+ description:
+ - The digest.
+ type: str
+ returned: if O(type=DS)
+ digest_type:
+ description:
+ - The digest's type.
+ type: int
+ returned: if O(type=DS)
+ exchange:
+ description:
+ - The exchange server.
+ type: str
+ returned: if O(type=MX)
+ expiration:
+ description:
+ - The expiration Unix timestamp.
+ type: int
+ returned: if O(type=RRSIG)
+ expire:
+ description:
+ - Number of seconds after which secondary name servers should stop answering request
+ for this zone if the main name server does not respond.
+ type: int
+ returned: if O(type=SOA)
+ fingerprint:
+ description:
+ - The fingerprint.
+ type: str
+ returned: if O(type=SSHFP)
+ flags:
+ description:
+ - Flags.
+ - This is actually of type C(string) for O(type=NAPTR).
+ type: int
+ returned: if O(type=CAA) or O(type=DNSKEY) or O(type=NAPTR) or O(type=NSEC3) or O(type=NSEC3PARAM)
+ fp_type:
+ description:
+ - The fingerprint's type.
+ type: int
+ returned: if O(type=SSHFP)
+ horizontal_precision:
+ description:
+ - The horizontal precision of the location.
+ type: float
+ returned: if O(type=LOC)
+ inception:
+ description:
+ - The inception Unix timestamp.
+ type: int
+ returned: if O(type=RRSIG)
+ iterations:
+ description:
+ - The number of iterations.
+ type: int
+ returned: if O(type=NSEC3) or O(type=NSEC3PARAM)
+ key:
+ description:
+ - The key.
+ type: str
+ returned: if O(type=DNSKEY)
+ key_tag:
+ description:
+ - The key's tag.
+ type: int
+ returned: if O(type=DS) or O(type=RRSIG)
+ labels:
+ description:
+ - The labels.
+ type: int
+ returned: if O(type=RRSIG)
+ latitude:
+ description:
+ - The location's latitude.
+ type: list
+ elements: int
+ returned: if O(type=LOC)
+ longitude:
+ description:
+ - The location's longitude.
+ type: list
+ elements: int
+ returned: if O(type=LOC)
+ mbox:
+ description:
+ - The mbox.
+ type: str
+ returned: if O(type=RP)
+ minimum:
+ description:
+ - Used to calculate the TTL for purposes of negative caching.
+ type: int
+ returned: if O(type=SOA)
+ mname:
+ description:
+ - Primary main name server for this zone.
+ type: str
+ returned: if O(type=SOA)
+ mtype:
+ description:
+ - The mtype.
+ type: int
+ returned: if O(type=TLSA)
+ next:
+ description:
+ - The next value.
+ type: str
+ returned: if O(type=NSEC) or O(type=NSEC3)
+ order:
+ description:
+ - The order value.
+ type: int
+ returned: if O(type=NAPTR)
+ original_ttl:
+ description:
+ - The original TTL.
+ type: int
+ returned: if O(type=RRSIG)
+ os:
+ description:
+ - The operating system.
+ type: str
+ returned: if O(type=HINFO)
+ port:
+ description:
+ - The port.
+ type: int
+ returned: if O(type=SRV)
+ preference:
+ description:
+ - The preference value for this record.
+ type: int
+ returned: if O(type=MX) or O(type=NAPTR)
+ priority:
+ description:
+ - The priority value for this record.
+ type: int
+ returned: if O(type=SRV)
+ protocol:
+ description:
+ - The protocol.
+ type: int
+ returned: if O(type=DNSKEY)
+ refresh:
+ description:
+ - Number of seconds after which secondary name servers should query the main
+ name server for the SOA record to detect zone changes.
+ type: int
+ returned: if O(type=SOA)
+ regexp:
+ description:
+ - A regular expression.
+ type: str
+ returned: if O(type=NAPTR)
+ replacement:
+ description:
+ - The replacement.
+ type: str
+ returned: if O(type=NAPTR)
+ retry:
+ description:
+ - Number of seconds after which secondary name servers should retry to request
+ the serial number from the main name server if the main name server does not respond.
+ type: int
+ returned: if O(type=SOA)
+ rname:
+ description:
+ - E-mail address of the administrator responsible for this zone.
+ type: str
+ returned: if O(type=SOA)
+ salt:
+ description:
+ - The salt.
+ type: str
+ returned: if O(type=NSEC3) or O(type=NSEC3PARAM)
+ selector:
+ description:
+ - The selector.
+ type: int
+ returned: if O(type=TLSA)
+ serial:
+ description:
+ - Serial number for this zone.
+ type: int
+ returned: if O(type=SOA)
+ service:
+ description:
+ - The service.
+ type: str
+ returned: if O(type=NAPTR)
+ signature:
+ description:
+ - The signature.
+ type: str
+ returned: if O(type=RRSIG)
+ signer:
+ description:
+ - The signer.
+ type: str
+ returned: if O(type=RRSIG)
+ size:
+ description:
+ - The size of the location.
+ type: float
+ returned: if O(type=LOC)
+ strings:
+ description:
+ - List of strings for this record.
+ - See RV(_result[].value) for the concatenated result.
+ type: list
+ elements: str
+ returned: if O(type=SPF) or O(type=TXT)
+ tag:
+ description:
+ - The tag.
+ type: str
+ returned: if O(type=CAA)
+ target:
+ description:
+ - The target.
+ type: str
+ returned: if O(type=CNAME) or O(type=DNAME) or O(type=NS) or O(type=PTR) or O(type=SRV)
+ txt:
+ description:
+ - The TXT value.
+ type: str
+ returned: if O(type=RP)
+ type_covered:
+ description:
+ - The type covered.
+ type: str
+ returned: if O(type=RRSIG)
+ usage:
+ description:
+ - The usage flag.
+ type: int
+ returned: if O(type=TLSA)
+ value:
+ description:
+ - The value.
+ - For O(type=SPF) or O(type=TXT), this is the concatenation of RV(_result[].strings).
+ type: str
+ returned: if O(type=CAA) or O(type=SPF) or O(type=TXT)
+ vertical_precision:
+ description:
+ - The vertical precision of the location.
+ type: float
+ returned: if O(type=LOC)
+ weight:
+ description:
+ - The service's weight.
+ type: int
+ returned: if O(type=SRV)
+ windows:
+ description:
+ - The windows.
+ type: str
+ returned: if O(type=NSEC) or O(type=NSEC3)
+"""
+
+from ansible.errors import AnsibleLookupError
+from ansible.plugins.lookup import LookupBase
+
+from ansible_collections.community.dns.plugins.module_utils.ips import (
+ is_ip_address,
+)
+
+from ansible_collections.community.dns.plugins.module_utils.dnspython_records import (
+ NAME_TO_RDTYPE,
+ convert_rdata_to_dict,
+)
+
+from ansible_collections.community.dns.plugins.module_utils.resolver import (
+ SimpleResolver,
+)
+
+from ansible_collections.community.dns.plugins.plugin_utils.ips import (
+ assert_requirements_present as assert_requirements_present_ipaddress,
+)
+
+from ansible_collections.community.dns.plugins.plugin_utils.resolver import (
+ assert_requirements_present as assert_requirements_present_dnspython,
+ guarded_run,
+)
+
+try:
+ import dns.resolver
+except ImportError:
+ # handled by assert_requirements_present_dnspython
+ pass
+
+
+class LookupModule(LookupBase):
+ @staticmethod
+ def _resolve(resolver, name, rdtype, server_addresses, nxdomain_handling):
+ def callback():
+ try:
+ rrset = resolver.resolve(
+ name,
+ rdtype=rdtype,
+ server_addresses=server_addresses,
+ nxdomain_is_empty=nxdomain_handling == 'empty',
+ )
+ if not rrset:
+ return []
+ return [convert_rdata_to_dict(data) for data in rrset]
+ except dns.resolver.NXDOMAIN:
+ raise AnsibleLookupError('Got NXDOMAIN when querying {name}'.format(name=name))
+
+ return guarded_run(
+ callback,
+ error_class=AnsibleLookupError,
+ server=name,
+ )
+
+ def run(self, terms, variables=None, **kwargs):
+ assert_requirements_present_dnspython('community.dns.lookup', 'lookup_as_dict')
+
+ self.set_options(var_options=variables, direct=kwargs)
+
+ resolver = SimpleResolver(
+ timeout=self.get_option('query_timeout'),
+ timeout_retries=self.get_option('query_retry'),
+ servfail_retries=self.get_option('servfail_retries'),
+ )
+
+ rdtype = NAME_TO_RDTYPE[self.get_option('type')]
+
+ nxdomain_handling = self.get_option('nxdomain_handling')
+
+ server_addresses = None
+ if self.get_option('server'):
+ server_addresses = []
+ assert_requirements_present_ipaddress('community.dns.lookup', 'lookup_as_dict')
+ for server in self.get_option('server'):
+ if is_ip_address(server):
+ server_addresses.append(server)
+ continue
+ else:
+ server_addresses.extend(guarded_run(
+ lambda: resolver.resolve_addresses(server),
+ error_class=AnsibleLookupError,
+ server=server,
+ ))
+
+ result = []
+ for name in terms:
+ result.extend(self._resolve(resolver, name, rdtype, server_addresses, nxdomain_handling))
+ return result
diff --git a/ansible_collections/community/dns/plugins/module_utils/conversion/txt.py b/ansible_collections/community/dns/plugins/module_utils/conversion/txt.py
index a4521c7fa..7258ef58d 100644
--- a/ansible_collections/community/dns/plugins/module_utils/conversion/txt.py
+++ b/ansible_collections/community/dns/plugins/module_utils/conversion/txt.py
@@ -183,6 +183,10 @@ def encode_txt_value(value, always_quote=False, use_character_encoding=_SENTINEL
# Add letter
if letter in (b'"', b'\\'):
+ # Make sure that we don't split up an escape sequence over multiple TXT strings
+ if len(buffer) + 2 > 255:
+ append(buffer[:255])
+ buffer = buffer[255:]
buffer.append(b'\\')
buffer.append(letter)
elif use_character_encoding and not (0x20 <= ord(letter) < 0x7F):
diff --git a/ansible_collections/community/dns/plugins/module_utils/dnspython_records.py b/ansible_collections/community/dns/plugins/module_utils/dnspython_records.py
new file mode 100644
index 000000000..c5bb0b5e4
--- /dev/null
+++ b/ansible_collections/community/dns/plugins/module_utils/dnspython_records.py
@@ -0,0 +1,135 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2015, Jan-Piet Mens <jpmens(at)gmail.com>
+# Copyright (c) 2017 Ansible Project
+# Copyright (c) 2022, Felix Fontein <felix@fontein.de>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+
+import base64
+
+from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text
+from ansible.module_utils.six import binary_type
+
+NAME_TO_RDTYPE = {}
+RDTYPE_TO_NAME = {}
+RDTYPE_TO_FIELDS = {}
+
+try:
+ import dns.name
+ import dns.rdata
+ import dns.rdatatype
+
+ # The following data has been borrowed from community.general's dig lookup plugin.
+ #
+ # Note: adding support for RRSIG is hard work. :)
+ for name, rdtype, fields in [
+ ('A', dns.rdatatype.A, ['address']),
+ ('AAAA', dns.rdatatype.AAAA, ['address']),
+ ('CAA', dns.rdatatype.CAA, ['flags', 'tag', 'value']),
+ ('CNAME', dns.rdatatype.CNAME, ['target']),
+ ('DNAME', dns.rdatatype.DNAME, ['target']),
+ ('DNSKEY', dns.rdatatype.DNSKEY, ['flags', 'algorithm', 'protocol', 'key']),
+ ('DS', dns.rdatatype.DS, ['algorithm', 'digest_type', 'key_tag', 'digest']),
+ ('HINFO', dns.rdatatype.HINFO, ['cpu', 'os']),
+ ('LOC', dns.rdatatype.LOC, ['latitude', 'longitude', 'altitude', 'size', 'horizontal_precision', 'vertical_precision']),
+ ('MX', dns.rdatatype.MX, ['preference', 'exchange']),
+ ('NAPTR', dns.rdatatype.NAPTR, ['order', 'preference', 'flags', 'service', 'regexp', 'replacement']),
+ ('NS', dns.rdatatype.NS, ['target']),
+ ('NSEC', dns.rdatatype.NSEC, ['next', 'windows']),
+ ('NSEC3', dns.rdatatype.NSEC3, ['algorithm', 'flags', 'iterations', 'salt', 'next', 'windows']),
+ ('NSEC3PARAM', dns.rdatatype.NSEC3PARAM, ['algorithm', 'flags', 'iterations', 'salt']),
+ ('PTR', dns.rdatatype.PTR, ['target']),
+ ('RP', dns.rdatatype.RP, ['mbox', 'txt']),
+ ('RRSIG', dns.rdatatype.RRSIG, ['type_covered', 'algorithm', 'labels', 'original_ttl', 'expiration', 'inception', 'key_tag', 'signer', 'signature']),
+ ('SOA', dns.rdatatype.SOA, ['mname', 'rname', 'serial', 'refresh', 'retry', 'expire', 'minimum']),
+ ('SPF', dns.rdatatype.SPF, ['strings']),
+ ('SRV', dns.rdatatype.SRV, ['priority', 'weight', 'port', 'target']),
+ ('SSHFP', dns.rdatatype.SSHFP, ['algorithm', 'fp_type', 'fingerprint']),
+ ('TLSA', dns.rdatatype.TLSA, ['usage', 'selector', 'mtype', 'cert']),
+ ('TXT', dns.rdatatype.TXT, ['strings']),
+ ]:
+ NAME_TO_RDTYPE[name] = rdtype
+ RDTYPE_TO_NAME[rdtype] = name
+ RDTYPE_TO_FIELDS[rdtype] = fields
+
+except ImportError:
+ pass # has to be handled on application level
+
+
+def convert_rdata_to_dict(rdata, to_unicode=True, add_synthetic=True):
+ '''
+ Convert a DNSPython record data object to a Python dictionary.
+
+ Code borrowed from community.general's dig looup plugin.
+
+ If ``to_unicode=True``, all strings will be converted to Unicode/UTF-8 strings.
+
+ If ``add_synthetic=True``, for some record types additional fields are added.
+ For TXT and SPF records, ``value`` contains the concatenated strings, for example.
+ '''
+ result = {}
+
+ fields = RDTYPE_TO_FIELDS.get(rdata.rdtype)
+ if fields is None:
+ raise ValueError('Unsupported record type {rdtype}'.format(rdtype=rdata.rdtype))
+ for f in fields:
+ val = rdata.__getattribute__(f)
+
+ if isinstance(val, dns.name.Name):
+ val = dns.name.Name.to_text(val)
+
+ if rdata.rdtype == dns.rdatatype.DS and f == 'digest':
+ val = dns.rdata._hexify(rdata.digest).replace(' ', '')
+ if rdata.rdtype == dns.rdatatype.DNSKEY and f == 'algorithm':
+ val = int(val)
+ if rdata.rdtype == dns.rdatatype.DNSKEY and f == 'key':
+ val = dns.rdata._base64ify(rdata.key).replace(' ', '')
+ if rdata.rdtype == dns.rdatatype.NSEC3 and f == 'next':
+ val = to_native(base64.b32encode(rdata.next).translate(dns.rdtypes.ANY.NSEC3.b32_normal_to_hex).lower())
+ if rdata.rdtype in (dns.rdatatype.NSEC, dns.rdatatype.NSEC3) and f == 'windows':
+ try:
+ val = dns.rdtypes.util.Bitmap(rdata.windows).to_text().lstrip(' ')
+ except AttributeError:
+ # dnspython < 2.0.0
+ val = []
+ for window, bitmap in rdata.windows:
+ for i, byte in enumerate(bitmap):
+ for j in range(8):
+ if (byte >> (7 - j)) & 1 != 0:
+ val.append(dns.rdatatype.to_text(window * 256 + i * 8 + j))
+ val = ' '.join(val).lstrip(' ')
+ if rdata.rdtype in (dns.rdatatype.NSEC3, dns.rdatatype.NSEC3PARAM) and f == 'salt':
+ val = dns.rdata._hexify(rdata.salt).replace(' ', '')
+ if rdata.rdtype == dns.rdatatype.RRSIG and f == 'type_covered':
+ val = RDTYPE_TO_NAME.get(rdata.type_covered) or str(val)
+ if rdata.rdtype == dns.rdatatype.RRSIG and f == 'algorithm':
+ val = int(val)
+ if rdata.rdtype == dns.rdatatype.RRSIG and f == 'signature':
+ val = dns.rdata._base64ify(rdata.signature).replace(' ', '')
+ if rdata.rdtype == dns.rdatatype.SSHFP and f == 'fingerprint':
+ val = dns.rdata._hexify(rdata.fingerprint).replace(' ', '')
+ if rdata.rdtype == dns.rdatatype.TLSA and f == 'cert':
+ val = dns.rdata._hexify(rdata.cert).replace(' ', '')
+
+ if isinstance(val, (list, tuple)):
+ if to_unicode:
+ val = [to_text(v) if isinstance(v, binary_type) else v for v in val]
+ else:
+ val = list(val)
+ elif to_unicode and isinstance(val, binary_type):
+ val = to_text(val)
+
+ result[f] = val
+
+ if add_synthetic:
+ if rdata.rdtype in (dns.rdatatype.TXT, dns.rdatatype.SPF):
+ if to_unicode:
+ result['value'] = u''.join([to_text(str) for str in rdata.strings])
+ else:
+ result['value'] = b''.join([to_bytes(str) for str in rdata.strings])
+ return result
diff --git a/ansible_collections/community/dns/plugins/module_utils/http.py b/ansible_collections/community/dns/plugins/module_utils/http.py
index fc4e1a590..d904100fc 100644
--- a/ansible_collections/community/dns/plugins/module_utils/http.py
+++ b/ansible_collections/community/dns/plugins/module_utils/http.py
@@ -13,7 +13,8 @@ import abc
from ansible.module_utils import six
from ansible.module_utils.common.text.converters import to_native
from ansible.module_utils.six import PY3
-from ansible.module_utils.urls import fetch_url, open_url, urllib_error, NoSSLError, ConnectionError
+from ansible.module_utils.urls import fetch_url, open_url, NoSSLError, ConnectionError
+import ansible.module_utils.six.moves.urllib.error as urllib_error
class NetworkError(Exception):
diff --git a/ansible_collections/community/dns/plugins/module_utils/ips.py b/ansible_collections/community/dns/plugins/module_utils/ips.py
new file mode 100644
index 000000000..adad9d228
--- /dev/null
+++ b/ansible_collections/community/dns/plugins/module_utils/ips.py
@@ -0,0 +1,37 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2023, Felix Fontein <felix@fontein.de>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+
+import traceback
+
+from ansible.module_utils.basic import missing_required_lib
+from ansible.module_utils.common.text.converters import to_text
+
+try:
+ import ipaddress
+except ImportError:
+ IPADDRESS_IMPORT_EXC = traceback.format_exc()
+else:
+ IPADDRESS_IMPORT_EXC = None
+
+
+def is_ip_address(server):
+ try:
+ ipaddress.ip_address(to_text(server))
+ return True
+ except ValueError:
+ return False
+
+
+def assert_requirements_present(module):
+ if IPADDRESS_IMPORT_EXC is not None:
+ module.fail_json(
+ msg=missing_required_lib('ipaddress'),
+ exception=IPADDRESS_IMPORT_EXC,
+ )
diff --git a/ansible_collections/community/dns/plugins/module_utils/resolver.py b/ansible_collections/community/dns/plugins/module_utils/resolver.py
index 98f1034e0..280b697d4 100644
--- a/ansible_collections/community/dns/plugins/module_utils/resolver.py
+++ b/ansible_collections/community/dns/plugins/module_utils/resolver.py
@@ -10,7 +10,7 @@ __metaclass__ = type
import traceback
from ansible.module_utils.basic import missing_required_lib
-from ansible.module_utils.common.text.converters import to_text
+from ansible.module_utils.common.text.converters import to_native, to_text
try:
import dns
@@ -27,23 +27,26 @@ else:
DNSPYTHON_IMPORTERROR = None
+_EDNS_SIZE = 1232 # equals dns.message.DEFAULT_EDNS_PAYLOAD; larger values cause problems with Route53 nameservers for me
+
+
class ResolverError(Exception):
pass
-class ResolveDirectlyFromNameServers(object):
- def __init__(self, timeout=10, timeout_retries=3, always_ask_default_resolver=True):
- self.cache = {}
+class _Resolve(object):
+ def __init__(self, timeout=10, timeout_retries=3, servfail_retries=0):
self.timeout = timeout
self.timeout_retries = timeout_retries
+ self.servfail_retries = servfail_retries
self.default_resolver = dns.resolver.get_default_resolver()
- self.default_nameservers = self.default_resolver.nameservers
- self.always_ask_default_resolver = always_ask_default_resolver
- def _handle_reponse_errors(self, target, response, nameserver=None, query=None):
+ def _handle_reponse_errors(self, target, response, nameserver=None, query=None, accept_errors=None):
rcode = response.rcode()
if rcode == dns.rcode.NOERROR:
return True
+ if accept_errors and rcode in accept_errors:
+ return True
if rcode == dns.rcode.NXDOMAIN:
raise dns.resolver.NXDOMAIN(qnames=[target], responses={target: response})
msg = 'Error %s' % dns.rcode.to_text(rcode)
@@ -63,6 +66,96 @@ class ResolveDirectlyFromNameServers(object):
raise exc
retry += 1
+ def _resolve(self, resolver, dnsname, handle_response_errors=False, **kwargs):
+ retry = 0
+ while True:
+ try:
+ response = self._handle_timeout(resolver.resolve, dnsname, lifetime=self.timeout, **kwargs)
+ except AttributeError:
+ # For dnspython < 2.0.0
+ resolver.search = False
+ try:
+ response = self._handle_timeout(resolver.query, dnsname, lifetime=self.timeout, **kwargs)
+ except TypeError:
+ # For dnspython < 1.6.0
+ resolver.lifetime = self.timeout
+ response = self._handle_timeout(resolver.query, dnsname, **kwargs)
+ if response.response.rcode() == dns.rcode.SERVFAIL and retry < self.servfail_retries:
+ retry += 1
+ continue
+ if handle_response_errors:
+ self._handle_reponse_errors(dnsname, response.response, nameserver=resolver.nameservers)
+ return response.rrset
+
+
+class SimpleResolver(_Resolve):
+ def __init__(
+ self,
+ timeout=10,
+ timeout_retries=3,
+ servfail_retries=0,
+ ):
+ super(SimpleResolver, self).__init__(
+ timeout=timeout,
+ timeout_retries=timeout_retries,
+ servfail_retries=servfail_retries,
+ )
+
+ def resolve(self, target, nxdomain_is_empty=True, server_addresses=None, **kwargs):
+ dnsname = dns.name.from_unicode(to_text(target))
+
+ resolver = self.default_resolver
+ if server_addresses:
+ resolver = dns.resolver.Resolver(configure=False)
+ resolver.timeout = self.timeout
+ resolver.nameservers = server_addresses
+
+ resolver.use_edns(0, ednsflags=dns.flags.DO, payload=_EDNS_SIZE)
+
+ try:
+ return self._resolve(resolver, dnsname, handle_response_errors=True, **kwargs)
+ except dns.resolver.NXDOMAIN:
+ if nxdomain_is_empty:
+ return None
+ raise
+ except dns.resolver.NoAnswer:
+ return None
+
+ def resolve_addresses(self, target, **kwargs):
+ dnsname = dns.name.from_unicode(to_text(target))
+ resolver = self.default_resolver
+ result = []
+ try:
+ for data in self._resolve(resolver, dnsname, handle_response_errors=True, rdtype=dns.rdatatype.A, **kwargs):
+ result.append(str(data))
+ except dns.resolver.NoAnswer:
+ pass
+ try:
+ for data in self._resolve(resolver, dnsname, handle_response_errors=True, rdtype=dns.rdatatype.AAAA, **kwargs):
+ result.append(str(data))
+ except dns.resolver.NoAnswer:
+ pass
+ return result
+
+
+class ResolveDirectlyFromNameServers(_Resolve):
+ def __init__(
+ self,
+ timeout=10,
+ timeout_retries=3,
+ servfail_retries=0,
+ always_ask_default_resolver=True,
+ server_addresses=None,
+ ):
+ super(ResolveDirectlyFromNameServers, self).__init__(
+ timeout=timeout,
+ timeout_retries=timeout_retries,
+ servfail_retries=servfail_retries,
+ )
+ self.cache = {}
+ self.default_nameservers = self.default_resolver.nameservers if server_addresses is None else server_addresses
+ self.always_ask_default_resolver = always_ask_default_resolver
+
def _lookup_ns_names(self, target, nameservers=None, nameserver_ips=None):
if self.always_ask_default_resolver:
nameservers = None
@@ -75,8 +168,16 @@ class ResolveDirectlyFromNameServers(object):
raise ResolverError('Have neither nameservers nor nameserver IPs')
query = dns.message.make_query(target, dns.rdatatype.NS)
- response = self._handle_timeout(dns.query.udp, query, nameserver_ips[0], timeout=self.timeout)
- self._handle_reponse_errors(target, response, nameserver=nameserver_ips[0], query='get NS for "%s"' % target)
+ retry = 0
+ while True:
+ response = self._handle_timeout(dns.query.udp, query, nameserver_ips[0], timeout=self.timeout)
+ if response.rcode() == dns.rcode.SERVFAIL and retry < self.servfail_retries:
+ retry += 1
+ continue
+ break
+ self._handle_reponse_errors(
+ target, response, nameserver=nameserver_ips[0], query='get NS for "%s"' % target, accept_errors=[dns.rcode.NXDOMAIN],
+ )
cname = None
for rrset in response.answer:
@@ -96,18 +197,8 @@ class ResolveDirectlyFromNameServers(object):
def _lookup_address_impl(self, target, rdtype):
try:
- try:
- answer = self._handle_timeout(self.default_resolver.resolve, target, rdtype=rdtype, lifetime=self.timeout)
- except AttributeError:
- # For dnspython < 2.0.0
- self.default_resolver.search = False
- try:
- answer = self._handle_timeout(self.default_resolver.query, target, rdtype=rdtype, lifetime=self.timeout)
- except TypeError:
- # For dnspython < 1.6.0
- self.default_resolver.lifetime = self.timeout
- answer = self._handle_timeout(self.default_resolver.query, target, rdtype=rdtype)
- return [str(res) for res in answer.rrset]
+ answer = self._resolve(self.default_resolver, target, handle_response_errors=True, rdtype=rdtype)
+ return [str(res) for res in answer]
except dns.resolver.NoAnswer:
return []
@@ -150,6 +241,7 @@ class ResolveDirectlyFromNameServers(object):
resolver = self.cache.get(cache_index)
if resolver is None:
resolver = dns.resolver.Resolver(configure=False)
+ resolver.use_edns(0, ednsflags=dns.flags.DO, payload=_EDNS_SIZE)
resolver.timeout = self.timeout
nameserver_ips = set()
for nameserver in nameservers:
@@ -162,10 +254,10 @@ class ResolveDirectlyFromNameServers(object):
nameservers = self._lookup_ns(dns.name.from_unicode(to_text(target)))
if resolve_addresses:
nameserver_ips = set()
- for nameserver in nameservers:
+ for nameserver in nameservers or []:
nameserver_ips.update(self._lookup_address(nameserver))
nameservers = list(nameserver_ips)
- return sorted(nameservers)
+ return sorted(nameservers or [])
def resolve(self, target, nxdomain_is_empty=True, **kwargs):
dnsname = dns.name.from_unicode(to_text(target))
@@ -186,28 +278,47 @@ class ResolveDirectlyFromNameServers(object):
loop_catcher.add(dnsname)
results = {}
- for nameserver in nameservers:
+ for nameserver in nameservers or []:
results[nameserver] = None
resolver = self._get_resolver(dnsname, [nameserver])
try:
- try:
- response = self._handle_timeout(resolver.resolve, dnsname, lifetime=self.timeout, **kwargs)
- except AttributeError:
- # For dnspython < 2.0.0
- resolver.search = False
- try:
- response = self._handle_timeout(resolver.query, dnsname, lifetime=self.timeout, **kwargs)
- except TypeError:
- # For dnspython < 1.6.0
- resolver.lifetime = self.timeout
- response = self._handle_timeout(resolver.query, dnsname, **kwargs)
- if response.rrset:
- results[nameserver] = response.rrset
+ results[nameserver] = self._resolve(resolver, dnsname, handle_response_errors=True, **kwargs)
except dns.resolver.NoAnswer:
pass
+ except dns.resolver.NXDOMAIN:
+ if nxdomain_is_empty:
+ results[nameserver] = []
+ else:
+ raise
return results
+def guarded_run(runner, module, server=None, generate_additional_results=None):
+ suffix = ' for {0}'.format(server) if server is not None else ''
+ kwargs = {}
+ try:
+ return runner()
+ except ResolverError as e:
+ if generate_additional_results is not None:
+ kwargs = generate_additional_results()
+ module.fail_json(
+ msg='Unexpected resolving error{0}: {1}'.format(suffix, to_native(e)),
+ exception=traceback.format_exc(),
+ **kwargs
+ )
+ except dns.exception.DNSException as e:
+ if generate_additional_results is not None:
+ kwargs = generate_additional_results()
+ module.fail_json(
+ msg='Unexpected DNS error{0}: {1}'.format(suffix, to_native(e)),
+ exception=traceback.format_exc(),
+ **kwargs
+ )
+
+
def assert_requirements_present(module):
if DNSPYTHON_IMPORTERROR is not None:
- module.fail_json(msg=missing_required_lib('dnspython'), exception=DNSPYTHON_IMPORTERROR)
+ module.fail_json(
+ msg=missing_required_lib('dnspython'),
+ exception=DNSPYTHON_IMPORTERROR,
+ )
diff --git a/ansible_collections/community/dns/plugins/module_utils/zone_record_helpers.py b/ansible_collections/community/dns/plugins/module_utils/zone_record_helpers.py
index 57277e29b..27b62c04d 100644
--- a/ansible_collections/community/dns/plugins/module_utils/zone_record_helpers.py
+++ b/ansible_collections/community/dns/plugins/module_utils/zone_record_helpers.py
@@ -37,7 +37,7 @@ def bulk_apply_changes(api,
@param stop_early_on_errors: If set to ``True``, try to stop changes after the first error happens.
This might only work on some APIs.
@return A tuple (changed, errors, success) where ``changed`` is a boolean which indicates whether a
- change was made, ``errors`` is a list of ``DNSAPIError`` instances for the errors occured,
+ change was made, ``errors`` is a list of ``DNSAPIError`` instances for the errors occurred,
and ``success`` is a dictionary with three lists ``success['deleted']``,
``success['changed']`` and ``success['created']``, which list all records that were deleted,
changed and created, respectively.
diff --git a/ansible_collections/community/dns/plugins/modules/hetzner_dns_record.py b/ansible_collections/community/dns/plugins/modules/hetzner_dns_record.py
index b17e0842c..23c873322 100644
--- a/ansible_collections/community/dns/plugins/modules/hetzner_dns_record.py
+++ b/ansible_collections/community/dns/plugins/modules/hetzner_dns_record.py
@@ -27,6 +27,7 @@ description:
extends_documentation_fragment:
- community.dns.hetzner
- community.dns.hetzner.record_default_ttl
+ - community.dns.hetzner.record_notes
- community.dns.hetzner.record_type_choices
- community.dns.hetzner.zone_id_type
- community.dns.module_record
diff --git a/ansible_collections/community/dns/plugins/modules/hetzner_dns_record_info.py b/ansible_collections/community/dns/plugins/modules/hetzner_dns_record_info.py
index 9d77a38d5..edf65aaca 100644
--- a/ansible_collections/community/dns/plugins/modules/hetzner_dns_record_info.py
+++ b/ansible_collections/community/dns/plugins/modules/hetzner_dns_record_info.py
@@ -37,6 +37,11 @@ attributes:
author:
- Markus Bergholz (@markuman) <markuman+spambelongstogoogle@gmail.com>
- Felix Fontein (@felixfontein)
+
+seealso:
+ - module: community.dns.hetzner_dns_record_set_info
+ - plugin: community.dns.hetzner_dns_records
+ plugin_type: inventory
'''
EXAMPLES = '''
@@ -58,7 +63,7 @@ records:
description: The list of fetched records.
type: list
elements: dict
- returned: success and I(what) is not C(single_record)
+ returned: success and O(what) is not V(single_record)
contains:
record:
description: The record name.
@@ -75,7 +80,7 @@ records:
ttl:
description:
- The TTL.
- - Will return C(none) if the zone's default TTL is used.
+ - Will return V(none) if the zone's default TTL is used.
type: int
sample: 3600
value:
diff --git a/ansible_collections/community/dns/plugins/modules/hetzner_dns_record_set.py b/ansible_collections/community/dns/plugins/modules/hetzner_dns_record_set.py
index 0766e6465..ce3ad313a 100644
--- a/ansible_collections/community/dns/plugins/modules/hetzner_dns_record_set.py
+++ b/ansible_collections/community/dns/plugins/modules/hetzner_dns_record_set.py
@@ -23,6 +23,7 @@ description:
extends_documentation_fragment:
- community.dns.hetzner
- community.dns.hetzner.record_default_ttl
+ - community.dns.hetzner.record_notes
- community.dns.hetzner.record_type_choices
- community.dns.hetzner.zone_id_type
- community.dns.module_record_set
@@ -128,10 +129,9 @@ EXAMPLES = '''
zone: foo.com
record: foo.com
type: CAA
- ttl: 3600
value:
- - "128 issue letsencrypt.org"
- - "128 iodef mailto:webmaster@foo.com"
+ - '128 issue "letsencrypt.org"'
+ - '128 iodef "mailto:webmaster@foo.com"'
hetzner_token: access_token
- name: Add an MX record
diff --git a/ansible_collections/community/dns/plugins/modules/hetzner_dns_record_set_info.py b/ansible_collections/community/dns/plugins/modules/hetzner_dns_record_set_info.py
index 5c70d1fb0..2df5d0f77 100644
--- a/ansible_collections/community/dns/plugins/modules/hetzner_dns_record_set_info.py
+++ b/ansible_collections/community/dns/plugins/modules/hetzner_dns_record_set_info.py
@@ -37,6 +37,11 @@ attributes:
author:
- Markus Bergholz (@markuman) <markuman+spambelongstogoogle@gmail.com>
- Felix Fontein (@felixfontein)
+
+seealso:
+ - module: community.dns.hetzner_dns_record_info
+ - plugin: community.dns.hetzner_dns_records
+ plugin_type: inventory
'''
EXAMPLES = '''
@@ -57,7 +62,7 @@ RETURN = '''
set:
description: The fetched record set. Is empty if record set does not exist.
type: dict
- returned: success and I(what) is C(single_record)
+ returned: success and O(what) is V(single_record)
contains:
record:
description: The record name.
@@ -76,7 +81,7 @@ set:
description:
- The TTL.
- If there are records in this set with different TTLs, the minimum of the TTLs will be presented here.
- - Will return C(none) if the zone's default TTL is used.
+ - Will return V(none) if the zone's default TTL is used.
type: int
sample: 3600
ttls:
@@ -109,7 +114,7 @@ sets:
description: The list of fetched record sets.
type: list
elements: dict
- returned: success and I(what) is not C(single_record)
+ returned: success and O(what) is not V(single_record)
contains:
record:
description: The record name.
@@ -128,7 +133,7 @@ sets:
description:
- The TTL.
- If there are records in this set with different TTLs, the minimum of the TTLs will be presented here.
- - Will return C(none) if the zone's default TTL is used.
+ - Will return V(none) if the zone's default TTL is used.
type: int
sample: 3600
ttls:
diff --git a/ansible_collections/community/dns/plugins/modules/hetzner_dns_record_sets.py b/ansible_collections/community/dns/plugins/modules/hetzner_dns_record_sets.py
index 52857186c..e7d515efe 100644
--- a/ansible_collections/community/dns/plugins/modules/hetzner_dns_record_sets.py
+++ b/ansible_collections/community/dns/plugins/modules/hetzner_dns_record_sets.py
@@ -22,6 +22,7 @@ description:
extends_documentation_fragment:
- community.dns.hetzner
+ - community.dns.hetzner.record_notes
- community.dns.hetzner.record_type_choices_record_sets_module
- community.dns.hetzner.zone_id_type
- community.dns.module_record_sets
diff --git a/ansible_collections/community/dns/plugins/modules/hetzner_dns_zone_info.py b/ansible_collections/community/dns/plugins/modules/hetzner_dns_zone_info.py
index 44cc88af5..9f4626e06 100644
--- a/ansible_collections/community/dns/plugins/modules/hetzner_dns_zone_info.py
+++ b/ansible_collections/community/dns/plugins/modules/hetzner_dns_zone_info.py
@@ -121,7 +121,7 @@ zone_info:
status:
description:
- Status of the zone.
- - Can be one of C(verified), C(failed) and C(pending).
+ - Can be one of V(verified), V(failed) and V(pending).
type: str
sample: verified
# choices:
diff --git a/ansible_collections/community/dns/plugins/modules/hosttech_dns_record.py b/ansible_collections/community/dns/plugins/modules/hosttech_dns_record.py
index 0756b6a4c..1473f6624 100644
--- a/ansible_collections/community/dns/plugins/modules/hosttech_dns_record.py
+++ b/ansible_collections/community/dns/plugins/modules/hosttech_dns_record.py
@@ -28,6 +28,7 @@ description:
extends_documentation_fragment:
- community.dns.hosttech
- community.dns.hosttech.record_default_ttl
+ - community.dns.hosttech.record_notes
- community.dns.hosttech.record_type_choices
- community.dns.hosttech.zone_id_type
- community.dns.module_record
diff --git a/ansible_collections/community/dns/plugins/modules/hosttech_dns_record_info.py b/ansible_collections/community/dns/plugins/modules/hosttech_dns_record_info.py
index 84ee8e3b2..71004464e 100644
--- a/ansible_collections/community/dns/plugins/modules/hosttech_dns_record_info.py
+++ b/ansible_collections/community/dns/plugins/modules/hosttech_dns_record_info.py
@@ -36,6 +36,11 @@ attributes:
author:
- Felix Fontein (@felixfontein)
+
+seealso:
+ - module: community.dns.hosttech_dns_record_set_info
+ - plugin: community.dns.hosttech_dns_records
+ plugin_type: inventory
'''
EXAMPLES = '''
@@ -57,7 +62,7 @@ records:
description: The list of fetched records.
type: list
elements: dict
- returned: success and I(what) is not C(single_record)
+ returned: success and O(what) is not V(single_record)
contains:
record:
description: The record name.
diff --git a/ansible_collections/community/dns/plugins/modules/hosttech_dns_record_set.py b/ansible_collections/community/dns/plugins/modules/hosttech_dns_record_set.py
index d16c82ad7..7da02aec4 100644
--- a/ansible_collections/community/dns/plugins/modules/hosttech_dns_record_set.py
+++ b/ansible_collections/community/dns/plugins/modules/hosttech_dns_record_set.py
@@ -24,6 +24,7 @@ description:
extends_documentation_fragment:
- community.dns.hosttech
- community.dns.hosttech.record_default_ttl
+ - community.dns.hosttech.record_notes
- community.dns.hosttech.record_type_choices
- community.dns.hosttech.zone_id_type
- community.dns.module_record_set
@@ -128,8 +129,8 @@ EXAMPLES = '''
type: CAA
ttl: 3600
value:
- - "128 issue letsencrypt.org"
- - "128 iodef mailto:webmaster@foo.com"
+ - '128 issue "letsencrypt.org"'
+ - '128 iodef "mailto:webmaster@foo.com"'
hosttech_token: access_token
- name: Add an MX record
diff --git a/ansible_collections/community/dns/plugins/modules/hosttech_dns_record_set_info.py b/ansible_collections/community/dns/plugins/modules/hosttech_dns_record_set_info.py
index 5b7c576b8..60a54809d 100644
--- a/ansible_collections/community/dns/plugins/modules/hosttech_dns_record_set_info.py
+++ b/ansible_collections/community/dns/plugins/modules/hosttech_dns_record_set_info.py
@@ -19,7 +19,7 @@ version_added: 0.1.0
description:
- "Retrieves DNS record sets in Hosttech DNS service."
- - This module was renamed from C(community.dns.hosttech_dns_record_info) to C(community.dns.hosttech_dns_record_set_info)
+ - This module was renamed from C(community.dns.hosttech_dns_record_info) to M(community.dns.hosttech_dns_record_set_info)
in community.dns 2.0.0.
extends_documentation_fragment:
@@ -38,6 +38,11 @@ attributes:
author:
- Felix Fontein (@felixfontein)
+
+seealso:
+ - module: community.dns.hosttech_dns_record_info
+ - plugin: community.dns.hosttech_dns_records
+ plugin_type: inventory
'''
EXAMPLES = '''
@@ -58,7 +63,7 @@ RETURN = '''
set:
description: The fetched record set. Is empty if record set does not exist.
type: dict
- returned: success and I(what) is C(single_record)
+ returned: success and O(what=single_record)
contains:
record:
description: The record name.
@@ -109,7 +114,7 @@ sets:
description: The list of fetched record sets.
type: list
elements: dict
- returned: success and I(what) is not C(single_record)
+ returned: success and O(what=single_record)
contains:
record:
description: The record name.
diff --git a/ansible_collections/community/dns/plugins/modules/hosttech_dns_record_sets.py b/ansible_collections/community/dns/plugins/modules/hosttech_dns_record_sets.py
index c985779ca..583cfa58e 100644
--- a/ansible_collections/community/dns/plugins/modules/hosttech_dns_record_sets.py
+++ b/ansible_collections/community/dns/plugins/modules/hosttech_dns_record_sets.py
@@ -23,6 +23,7 @@ description:
extends_documentation_fragment:
- community.dns.hosttech
+ - community.dns.hosttech.record_notes
- community.dns.hosttech.record_type_choices_record_sets_module
- community.dns.hosttech.zone_id_type
- community.dns.module_record_sets
diff --git a/ansible_collections/community/dns/plugins/modules/hosttech_dns_records.py b/ansible_collections/community/dns/plugins/modules/hosttech_dns_records.py
index c985779ca..583cfa58e 100644
--- a/ansible_collections/community/dns/plugins/modules/hosttech_dns_records.py
+++ b/ansible_collections/community/dns/plugins/modules/hosttech_dns_records.py
@@ -23,6 +23,7 @@ description:
extends_documentation_fragment:
- community.dns.hosttech
+ - community.dns.hosttech.record_notes
- community.dns.hosttech.record_type_choices_record_sets_module
- community.dns.hosttech.zone_id_type
- community.dns.module_record_sets
diff --git a/ansible_collections/community/dns/plugins/modules/hosttech_dns_zone_info.py b/ansible_collections/community/dns/plugins/modules/hosttech_dns_zone_info.py
index 6621893a7..d364d0694 100644
--- a/ansible_collections/community/dns/plugins/modules/hosttech_dns_zone_info.py
+++ b/ansible_collections/community/dns/plugins/modules/hosttech_dns_zone_info.py
@@ -80,22 +80,22 @@ zone_info:
description:
- Whether DNSSEC is enabled for the zone or not.
type: bool
- returned: When I(hosttech_token) has been specified.
+ returned: When O(hosttech_token) has been specified.
dnssec_email:
description:
- The email address contacted when the DNSSEC key is changed.
- - Is C(none) if DNSSEC is not enabled.
+ - Is V(none) if DNSSEC is not enabled.
type: str
- returned: When I(hosttech_token) has been specified.
+ returned: When O(hosttech_token) has been specified.
ds_records:
description:
- The DS records.
- See L(Section 5 of RFC 4034,https://datatracker.ietf.org/doc/html/rfc4034#section-5) and
L(Section 2.1 of RFC 4034,https://datatracker.ietf.org/doc/html/rfc4034#section-2.1) for details.
- - Is C(none) if DNSSEC is not enabled.
+ - Is V(none) if DNSSEC is not enabled.
type: list
elements: dict
- returned: When I(hosttech_token) has been specified.
+ returned: When O(hosttech_token) has been specified.
contains:
algorithm:
description:
diff --git a/ansible_collections/community/dns/plugins/modules/nameserver_info.py b/ansible_collections/community/dns/plugins/modules/nameserver_info.py
new file mode 100644
index 000000000..62ba30961
--- /dev/null
+++ b/ansible_collections/community/dns/plugins/modules/nameserver_info.py
@@ -0,0 +1,168 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2022, Felix Fontein <felix@fontein.de>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+
+DOCUMENTATION = r'''
+---
+module: nameserver_info
+short_description: Look up nameservers for a DNS name
+version_added: 2.6.0
+description:
+ - Retrieve all nameservers that are responsible for a DNS name.
+extends_documentation_fragment:
+ - community.dns.attributes
+ - community.dns.attributes.info_module
+author:
+ - Felix Fontein (@felixfontein)
+options:
+ name:
+ description:
+ - A list of DNS names whose nameservers to retrieve.
+ required: true
+ type: list
+ elements: str
+ resolve_addresses:
+ description:
+ - Whether to resolve the nameserver names to IP addresses.
+ type: bool
+ default: false
+ query_retry:
+ description:
+ - Number of retries for DNS query timeouts.
+ type: int
+ default: 3
+ query_timeout:
+ description:
+ - Timeout per DNS query in seconds.
+ type: float
+ default: 10
+ always_ask_default_resolver:
+ description:
+ - When set to V(true) (default), will use the default resolver to find the authoritative nameservers
+ of a subzone. See O(server) for how to configure the default resolver.
+ - When set to V(false), will use the authoritative nameservers of the parent zone to find the
+ authoritative nameservers of a subzone. This only makes sense when the nameservers were recently
+ changed and have not yet propagated.
+ type: bool
+ default: true
+ servfail_retries:
+ description:
+ - How often to retry on SERVFAIL errors.
+ type: int
+ default: 0
+ server:
+ description:
+ - The DNS server(s) to use to look up the result. Must be a list of one or more IP addresses.
+ - By default, the system's standard resolver is used.
+ type: list
+ elements: str
+ version_added: 2.7.0
+requirements:
+ - dnspython >= 1.15.0 (maybe older versions also work)
+'''
+
+EXAMPLES = r'''
+- name: Retrieve name servers of two DNS names
+ community.dns.nameserver_info:
+ name:
+ - www.example.com
+ - example.org
+ register: result
+
+- name: Show nameservers for www.example.com
+ ansible.builtin.debug:
+ msg: '{{ result.results[0].nameserver }}'
+'''
+
+RETURN = r'''
+results:
+ description:
+ - Information on the nameservers for every DNS name provided in O(name).
+ returned: always
+ type: list
+ elements: dict
+ contains:
+ name:
+ description:
+ - The DNS name this entry is for.
+ returned: always
+ type: str
+ sample: www.example.com
+ nameservers:
+ description:
+ - A list of nameservers for this DNS name.
+ returned: success
+ type: list
+ elements: str
+ sample:
+ - ns1.example.com
+ - ns2.example.com
+ sample:
+ - name: www.example.com
+ nameservers:
+ - ns1.example.com
+ - ns2.example.com
+ - name: example.org
+ nameservers:
+ - ns1.example.org
+ - ns2.example.org
+ - ns3.example.org
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.community.dns.plugins.module_utils.resolver import (
+ ResolveDirectlyFromNameServers,
+ assert_requirements_present,
+ guarded_run,
+)
+
+
+def main():
+ module = AnsibleModule(
+ argument_spec=dict(
+ name=dict(required=True, type='list', elements='str'),
+ resolve_addresses=dict(type='bool', default=False),
+ query_retry=dict(type='int', default=3),
+ query_timeout=dict(type='float', default=10),
+ always_ask_default_resolver=dict(type='bool', default=True),
+ servfail_retries=dict(type='int', default=0),
+ server=dict(type='list', elements='str'),
+ ),
+ supports_check_mode=True,
+ )
+ assert_requirements_present(module)
+
+ names = module.params['name']
+ resolve_addresses = module.params['resolve_addresses']
+
+ resolver = ResolveDirectlyFromNameServers(
+ timeout=module.params['query_timeout'],
+ timeout_retries=module.params['query_retry'],
+ servfail_retries=module.params['servfail_retries'],
+ always_ask_default_resolver=module.params['always_ask_default_resolver'],
+ server_addresses=module.params['server'],
+ )
+ results = [None] * len(names)
+ for index, name in enumerate(names):
+ results[index] = {
+ 'name': name,
+ }
+
+ def f():
+ for index, name in enumerate(names):
+ results[index]['nameservers'] = sorted(resolver.resolve_nameservers(name, resolve_addresses=resolve_addresses))
+
+ guarded_run(f, module, generate_additional_results=lambda: dict(results=results))
+ module.exit_json(results=results)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/dns/plugins/modules/nameserver_record_info.py b/ansible_collections/community/dns/plugins/modules/nameserver_record_info.py
new file mode 100644
index 000000000..f9374acae
--- /dev/null
+++ b/ansible_collections/community/dns/plugins/modules/nameserver_record_info.py
@@ -0,0 +1,568 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2022, Felix Fontein <felix@fontein.de>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+
+DOCUMENTATION = r'''
+---
+module: nameserver_record_info
+short_description: Look up all records of a type from all nameservers for a DNS name
+version_added: 2.6.0
+description:
+ - Given a DNS name and a record type, will retrieve all nameservers that are responsible for
+ this DNS name, and from them all records for this name of the given type.
+extends_documentation_fragment:
+ - community.dns.attributes
+ - community.dns.attributes.info_module
+author:
+ - Felix Fontein (@felixfontein)
+options:
+ name:
+ description:
+ - A list of DNS names whose nameservers to retrieve.
+ required: true
+ type: list
+ elements: str
+ type:
+ description:
+ - The record type to retrieve.
+ required: true
+ type: str
+ choices:
+ - A
+ - ALL
+ - AAAA
+ - CAA
+ - CNAME
+ - DNAME
+ - DNSKEY
+ - DS
+ - HINFO
+ - LOC
+ - MX
+ - NAPTR
+ - NS
+ - NSEC
+ - NSEC3
+ - NSEC3PARAM
+ - PTR
+ - RP
+ - RRSIG
+ - SOA
+ - SPF
+ - SRV
+ - SSHFP
+ - TLSA
+ - TXT
+ query_retry:
+ description:
+ - Number of retries for DNS query timeouts.
+ type: int
+ default: 3
+ query_timeout:
+ description:
+ - Timeout per DNS query in seconds.
+ type: float
+ default: 10
+ always_ask_default_resolver:
+ description:
+ - When set to V(true) (default), will use the default resolver to find the authoritative nameservers
+ of a subzone. See O(server) for how to configure the default resolver.
+ - When set to V(false), will use the authoritative nameservers of the parent zone to find the
+ authoritative nameservers of a subzone. This only makes sense when the nameservers were recently
+ changed and have not yet propagated.
+ type: bool
+ default: true
+ servfail_retries:
+ description:
+ - How often to retry on SERVFAIL errors.
+ type: int
+ default: 0
+ server:
+ description:
+ - The DNS server(s) to use to look up the result. Must be a list of one or more IP addresses.
+ - By default, the system's standard resolver is used.
+ type: list
+ elements: str
+ version_added: 2.7.0
+requirements:
+ - dnspython >= 1.15.0 (maybe older versions also work)
+notes:
+ - dnspython before 2.0.0 does not correctly support (un-)escaping UTF-8 in TXT-like records. This can
+ result in wrongly decoded TXT records. Please use dnspython 2.0.0 or later to fix this issue; see also
+ U(https://github.com/rthalley/dnspython/issues/321).
+ Unfortunately dnspython 2.0.0 requires Python 3.6 or newer.
+'''
+
+EXAMPLES = r'''
+- name: Retrieve TXT values from all nameservers for two DNS names
+ community.dns.nameserver_record_info:
+ name:
+ - www.example.com
+ - example.org
+ type: TXT
+ register: result
+
+- name: Show TXT values for www.example.com for all nameservers
+ ansible.builtin.debug:
+ msg: '{{ result.results[0].result }}'
+'''
+
+RETURN = r'''
+results:
+ description:
+ - Information on the records for every DNS name provided in O(name).
+ returned: always
+ type: list
+ elements: dict
+ contains:
+ name:
+ description:
+ - The DNS name this entry is for.
+ returned: always
+ type: str
+ sample: www.example.com
+ result:
+ description:
+ - A list of values per nameserver.
+ returned: success
+ type: list
+ elements: dict
+ sample:
+ - nameserver: ns1.example.com
+ values:
+ - X
+ - nameserver: ns2.example.com
+ values:
+ - X
+ contains:
+ nameserver:
+ description:
+ - The nameserver.
+ returned: success
+ type: str
+ sample: ns1.example.com
+ values:
+ description:
+ - The records of type O(type).
+ - Depending on O(type), different fields are returned.
+ - For O(type=TXT) and O(type=SPF), also the concatenated value is returned as RV(results[].result[].values[].value).
+ returned: success
+ type: list
+ elements: dict
+ sample:
+ - address: 127.0.0.1
+ contains:
+ address:
+ description:
+ - A IPv4 respectively IPv6 address.
+ type: str
+ returned: if O(type=A) or O(type=AAAA)
+ algorithm:
+ description:
+ - The algorithm ID.
+ type: int
+ returned: if O(type=DNSKEY) or O(type=DS) or O(type=NSEC3) or O(type=NSEC3PARAM) or O(type=RRSIG) or O(type=SSHFP)
+ altitude:
+ description:
+ - The altitude.
+ type: float
+ returned: if O(type=LOC)
+ cert:
+ description:
+ - The certificate.
+ type: str
+ returned: if O(type=TLSA)
+ cpu:
+ description:
+ - The CPU.
+ type: str
+ returned: if O(type=HINFO)
+ digest:
+ description:
+ - The digest.
+ type: str
+ returned: if O(type=DS)
+ digest_type:
+ description:
+ - The digest's type.
+ type: int
+ returned: if O(type=DS)
+ exchange:
+ description:
+ - The exchange server.
+ type: str
+ returned: if O(type=MX)
+ expiration:
+ description:
+ - The expiration Unix timestamp.
+ type: int
+ returned: if O(type=RRSIG)
+ expire:
+ description:
+ - Number of seconds after which secondary name servers should stop answering request
+ for this zone if the main name server does not respond.
+ type: int
+ returned: if O(type=SOA)
+ fingerprint:
+ description:
+ - The fingerprint.
+ type: str
+ returned: if O(type=SSHFP)
+ flags:
+ description:
+ - Flags.
+ - This is actually of type C(string) for O(type=NAPTR).
+ type: int
+ returned: if O(type=CAA) or O(type=DNSKEY) or O(type=NAPTR) or O(type=NSEC3) or O(type=NSEC3PARAM)
+ fp_type:
+ description:
+ - The fingerprint's type.
+ type: int
+ returned: if O(type=SSHFP)
+ horizontal_precision:
+ description:
+ - The horizontal precision of the location.
+ type: float
+ returned: if O(type=LOC)
+ inception:
+ description:
+ - The inception Unix timestamp.
+ type: int
+ returned: if O(type=RRSIG)
+ iterations:
+ description:
+ - The number of iterations.
+ type: int
+ returned: if O(type=NSEC3) or O(type=NSEC3PARAM)
+ key:
+ description:
+ - The key.
+ type: str
+ returned: if O(type=DNSKEY)
+ key_tag:
+ description:
+ - The key's tag.
+ type: int
+ returned: if O(type=DS) or O(type=RRSIG)
+ labels:
+ description:
+ - The labels.
+ type: int
+ returned: if O(type=RRSIG)
+ latitude:
+ description:
+ - The location's latitude.
+ type: list
+ elements: int
+ returned: if O(type=LOC)
+ longitude:
+ description:
+ - The location's longitude.
+ type: list
+ elements: int
+ returned: if O(type=LOC)
+ mbox:
+ description:
+ - The mbox.
+ type: str
+ returned: if O(type=RP)
+ minimum:
+ description:
+ - Used to calculate the TTL for purposes of negative caching.
+ type: int
+ returned: if O(type=SOA)
+ mname:
+ description:
+ - Primary main name server for this zone.
+ type: str
+ returned: if O(type=SOA)
+ mtype:
+ description:
+ - The mtype.
+ type: int
+ returned: if O(type=TLSA)
+ next:
+ description:
+ - The next value.
+ type: str
+ returned: if O(type=NSEC) or O(type=NSEC3)
+ order:
+ description:
+ - The order value.
+ type: int
+ returned: if O(type=NAPTR)
+ original_ttl:
+ description:
+ - The original TTL.
+ type: int
+ returned: if O(type=RRSIG)
+ os:
+ description:
+ - The operating system.
+ type: str
+ returned: if O(type=HINFO)
+ port:
+ description:
+ - The port.
+ type: int
+ returned: if O(type=SRV)
+ preference:
+ description:
+ - The preference value for this record.
+ type: int
+ returned: if O(type=MX) or O(type=NAPTR)
+ priority:
+ description:
+ - The priority value for this record.
+ type: int
+ returned: if O(type=SRV)
+ protocol:
+ description:
+ - The protocol.
+ type: int
+ returned: if O(type=DNSKEY)
+ refresh:
+ description:
+ - Number of seconds after which secondary name servers should query the main
+ name server for the SOA record to detect zone changes.
+ type: int
+ returned: if O(type=SOA)
+ regexp:
+ description:
+ - A regular expression.
+ type: str
+ returned: if O(type=NAPTR)
+ replacement:
+ description:
+ - The replacement.
+ type: str
+ returned: if O(type=NAPTR)
+ retry:
+ description:
+ - Number of seconds after which secondary name servers should retry to request
+ the serial number from the main name server if the main name server does not respond.
+ type: int
+ returned: if O(type=SOA)
+ rname:
+ description:
+ - E-mail address of the administrator responsible for this zone.
+ type: str
+ returned: if O(type=SOA)
+ salt:
+ description:
+ - The salt.
+ type: str
+ returned: if O(type=NSEC3) or O(type=NSEC3PARAM)
+ selector:
+ description:
+ - The selector.
+ type: int
+ returned: if O(type=TLSA)
+ serial:
+ description:
+ - Serial number for this zone.
+ type: int
+ returned: if O(type=SOA)
+ service:
+ description:
+ - The service.
+ type: str
+ returned: if O(type=NAPTR)
+ signature:
+ description:
+ - The signature.
+ type: str
+ returned: if O(type=RRSIG)
+ signer:
+ description:
+ - The signer.
+ type: str
+ returned: if O(type=RRSIG)
+ size:
+ description:
+ - The size of the location.
+ type: float
+ returned: if O(type=LOC)
+ strings:
+ description:
+ - List of strings for this record.
+ - See RV(results[].result[].values[].value) for the concatenated result.
+ type: list
+ elements: str
+ returned: if O(type=SPF) or O(type=TXT)
+ tag:
+ description:
+ - The tag.
+ type: str
+ returned: if O(type=CAA)
+ target:
+ description:
+ - The target.
+ type: str
+ returned: if O(type=CNAME) or O(type=DNAME) or O(type=NS) or O(type=PTR) or O(type=SRV)
+ txt:
+ description:
+ - The TXT value.
+ type: str
+ returned: if O(type=RP)
+ type_covered:
+ description:
+ - The type covered.
+ type: str
+ returned: if O(type=RRSIG)
+ usage:
+ description:
+ - The usage flag.
+ type: int
+ returned: if O(type=TLSA)
+ value:
+ description:
+ - The value.
+ - For O(type=SPF) or O(type=TXT), this is the concatenation of RV(results[].result[].values[].strings).
+ type: str
+ returned: if O(type=CAA) or O(type=SPF) or O(type=TXT)
+ vertical_precision:
+ description:
+ - The vertical precision of the location.
+ type: float
+ returned: if O(type=LOC)
+ weight:
+ description:
+ - The service's weight.
+ type: int
+ returned: if O(type=SRV)
+ windows:
+ description:
+ - The windows.
+ type: str
+ returned: if O(type=NSEC) or O(type=NSEC3)
+ sample:
+ - name: www.example.com
+ result:
+ - nameserver: ns1.example.com
+ values:
+ - address: 127.0.0.1
+ - nameserver: ns2.example.com
+ values:
+ - address: 127.0.0.1
+ - name: example.org
+ result:
+ - nameserver: ns1.example.org
+ values:
+ - address: 127.0.0.1
+ - address: 127.0.0.2
+ - nameserver: ns2.example.org
+ values:
+ - address: 127.0.0.2
+ - nameserver: ns3.example.org
+ values:
+ - address: 127.0.0.1
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.community.dns.plugins.module_utils.resolver import (
+ ResolveDirectlyFromNameServers,
+ assert_requirements_present,
+ guarded_run,
+)
+
+from ansible_collections.community.dns.plugins.module_utils.dnspython_records import (
+ NAME_TO_RDTYPE,
+ convert_rdata_to_dict,
+)
+
+
+def main():
+ module = AnsibleModule(
+ argument_spec=dict(
+ name=dict(required=True, type='list', elements='str'),
+ type=dict(
+ required=True,
+ type='str',
+ choices=[
+ 'A',
+ 'ALL',
+ 'AAAA',
+ 'CAA',
+ 'CNAME',
+ 'DNAME',
+ 'DNSKEY',
+ 'DS',
+ 'HINFO',
+ 'LOC',
+ 'MX',
+ 'NAPTR',
+ 'NS',
+ 'NSEC',
+ 'NSEC3',
+ 'NSEC3PARAM',
+ 'PTR',
+ 'RP',
+ 'RRSIG',
+ 'SOA',
+ 'SPF',
+ 'SRV',
+ 'SSHFP',
+ 'TLSA',
+ 'TXT',
+ ],
+ ),
+ query_retry=dict(type='int', default=3),
+ query_timeout=dict(type='float', default=10),
+ always_ask_default_resolver=dict(type='bool', default=True),
+ servfail_retries=dict(type='int', default=0),
+ server=dict(type='list', elements='str'),
+ ),
+ supports_check_mode=True,
+ )
+ assert_requirements_present(module)
+
+ names = module.params['name']
+ record_type = module.params['type']
+
+ resolver = ResolveDirectlyFromNameServers(
+ timeout=module.params['query_timeout'],
+ timeout_retries=module.params['query_retry'],
+ servfail_retries=module.params['servfail_retries'],
+ always_ask_default_resolver=module.params['always_ask_default_resolver'],
+ server_addresses=module.params['server'],
+ )
+ results = [None] * len(names)
+ for index, name in enumerate(names):
+ results[index] = {
+ 'name': name,
+ }
+
+ rdtype = NAME_TO_RDTYPE[record_type]
+
+ def f():
+ for index, name in enumerate(names):
+ result = []
+ results[index]['result'] = result
+ records_for_nameservers = resolver.resolve(name, rdtype=rdtype)
+ for nameserver, records in records_for_nameservers.items():
+ ns_result = {
+ 'nameserver': nameserver,
+ }
+ result.append(ns_result)
+ values = []
+ if records is not None:
+ for data in records:
+ values.append(convert_rdata_to_dict(data))
+ ns_result['values'] = values
+ result.sort(key=lambda v: v['nameserver'])
+
+ guarded_run(f, module, generate_additional_results=lambda: dict(results=results))
+ module.exit_json(results=results)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/dns/plugins/modules/wait_for_txt.py b/ansible_collections/community/dns/plugins/modules/wait_for_txt.py
index 1a09c5ed6..7252ae883 100644
--- a/ansible_collections/community/dns/plugins/modules/wait_for_txt.py
+++ b/ansible_collections/community/dns/plugins/modules/wait_for_txt.py
@@ -40,7 +40,7 @@ options:
suboptions:
name:
description:
- - A DNS name, like C(www.example.com).
+ - A DNS name, like V(www.example.com).
type: str
required: true
values:
@@ -51,17 +51,17 @@ options:
required: true
mode:
description:
- - Comparison modes for the values in I(values).
- - If C(subset), I(values) should be a (not necessarily proper) subset of the TXT values set for
+ - Comparison modes for the values in O(records[].values).
+ - If V(subset), O(records[].values) should be a (not necessarily proper) subset of the TXT values set for
the DNS name.
- - If C(superset), I(values) should be a (not necessarily proper) superset of the TXT values set
+ - If V(superset), O(records[].values) should be a (not necessarily proper) superset of the TXT values set
for the DNS name.
This includes the case that no TXT entries are set.
- - If C(superset_not_empty), I(values) should be a (not necessarily proper) superset of the TXT
+ - If V(superset_not_empty), O(records[].values) should be a (not necessarily proper) superset of the TXT
values set for the DNS name, assuming at least one TXT record is present.
- - If C(equals), I(values) should be the same set of strings as the TXT values for the DNS name
+ - If V(equals), O(records[].values) should be the same set of strings as the TXT values for the DNS name
(up to order).
- - If C(equals_ordered), I(values) should be the same ordered list of strings as the TXT values
+ - If V(equals_ordered), O(records[].values) should be the same ordered list of strings as the TXT values
for the DNS name.
type: str
default: subset
@@ -93,13 +93,26 @@ options:
default: 10
always_ask_default_resolver:
description:
- - When set to C(true) (default), will use the default resolver to find the authoritative nameservers
- of a subzone.
- - When set to C(false), will use the authoritative nameservers of the parent zone to find the
+ - When set to V(true) (default), will use the default resolver to find the authoritative nameservers
+ of a subzone. See O(server) for how to configure the default resolver.
+ - When set to V(false), will use the authoritative nameservers of the parent zone to find the
authoritative nameservers of a subzone. This only makes sense when the nameservers were recently
- changed and haven't propagated.
+ changed and have not yet propagated.
type: bool
default: true
+ servfail_retries:
+ description:
+ - How often to retry on SERVFAIL errors.
+ type: int
+ default: 0
+ version_added: 2.6.0
+ server:
+ description:
+ - The DNS server(s) to use to look up the result. Must be a list of one or more IP addresses.
+ - By default, the system's standard resolver is used.
+ type: list
+ elements: str
+ version_added: 2.7.0
requirements:
- dnspython >= 1.15.0 (maybe older versions also work)
'''
@@ -124,7 +137,7 @@ RETURN = r'''
records:
description:
- Results on the TXT records queried.
- - The entries are in a 1:1 correspondence to the entries of the I(records) parameter,
+ - The entries are in a 1:1 correspondence to the entries of the O(records) parameter,
in exactly the same order.
returned: always
type: list
@@ -180,7 +193,6 @@ completed:
'''
import time
-import traceback
try:
from time import monotonic
@@ -188,16 +200,15 @@ except ImportError:
from time import clock as monotonic
from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.common.text.converters import to_native, to_text
+from ansible.module_utils.common.text.converters import to_text
from ansible_collections.community.dns.plugins.module_utils.resolver import (
ResolveDirectlyFromNameServers,
- ResolverError,
assert_requirements_present,
+ guarded_run,
)
try:
- import dns.exception
import dns.rdatatype
except ImportError:
pass # handled in assert_requirements_present()
@@ -238,97 +249,107 @@ def validate_check(record_values, expected_values, comparison_mode):
raise Exception('Internal error!')
-def main():
- module = AnsibleModule(
- argument_spec=dict(
- records=dict(required=True, type='list', elements='dict', options=dict(
- name=dict(required=True, type='str'),
- values=dict(required=True, type='list', elements='str'),
- mode=dict(type='str', default='subset', choices=['subset', 'superset', 'superset_not_empty', 'equals', 'equals_ordered']),
- )),
- query_retry=dict(type='int', default=3),
- query_timeout=dict(type='float', default=10),
- timeout=dict(type='float'),
- max_sleep=dict(type='float', default=10),
- always_ask_default_resolver=dict(type='bool', default=True),
- ),
- supports_check_mode=True,
- )
- assert_requirements_present(module)
+class Waiter(object):
+ def __init__(self, module):
+ self.module = module
+
+ self.resolver = ResolveDirectlyFromNameServers(
+ timeout=self.module.params['query_timeout'],
+ timeout_retries=self.module.params['query_retry'],
+ servfail_retries=self.module.params['servfail_retries'],
+ always_ask_default_resolver=self.module.params['always_ask_default_resolver'],
+ server_addresses=self.module.params['server'],
+ )
+ self.records = self.module.params['records']
+ self.timeout = self.module.params['timeout']
+ self.max_sleep = self.module.params['max_sleep']
+
+ self.results = [None] * len(self.records)
+ for index in range(len(self.records)):
+ self.results[index] = {
+ 'name': self.records[index]['name'],
+ 'done': False,
+ 'check_count': 0,
+ }
+ self.finished_checks = 0
+
+ def _run(self):
+ self.start_time = monotonic()
- resolver = ResolveDirectlyFromNameServers(
- timeout=module.params['query_timeout'],
- timeout_retries=module.params['query_retry'],
- always_ask_default_resolver=module.params['always_ask_default_resolver'],
- )
- records = module.params['records']
- timeout = module.params['timeout']
- max_sleep = module.params['max_sleep']
-
- results = [None] * len(records)
- for index in range(len(records)):
- results[index] = {
- 'name': records[index]['name'],
- 'done': False,
- 'check_count': 0,
- }
- finished_checks = 0
-
- start_time = monotonic()
- try:
step = 0
while True:
has_timeout = False
- if timeout is not None:
- expired = monotonic() - start_time
- has_timeout = expired > timeout
+ if self.timeout is not None:
+ expired = monotonic() - self.start_time
+ has_timeout = expired > self.timeout
done = True
- for index, record in enumerate(records):
- if results[index]['done']:
+ for index, record in enumerate(self.records):
+ if self.results[index]['done']:
continue
- txts = lookup(resolver, record['name'])
- results[index]['values'] = txts
- results[index]['check_count'] += 1
+ txts = lookup(self.resolver, record['name'])
+ self.results[index]['values'] = txts
+ self.results[index]['check_count'] += 1
if txts and all(validate_check(txt, record['values'], record['mode']) for txt in txts.values()):
- results[index]['done'] = True
- finished_checks += 1
+ self.results[index]['done'] = True
+ self.finished_checks += 1
else:
done = False
if done:
- module.exit_json(
+ self.module.exit_json(
msg='All checks passed',
- records=results,
- completed=finished_checks)
+ **self._generate_additional_results()
+ )
if has_timeout:
- module.fail_json(
- msg='Timeout ({0} out of {1} check(s) passed).'.format(finished_checks, len(records)),
- records=results,
- completed=finished_checks)
+ self.module.fail_json(
+ msg='Timeout ({0} out of {1} check(s) passed).'.format(self.finished_checks, len(self.records)),
+ **self._generate_additional_results()
+ )
# Simple quadratic sleep with maximum wait of max_sleep seconds
- wait = min(2 + step * 0.5, max_sleep)
- if timeout is not None:
+ wait = min(2 + step * 0.5, self.max_sleep)
+ if self.timeout is not None:
# Make sure we do not exceed the timeout by much by waiting
- expired = monotonic() - start_time
- wait = max(min(wait, timeout - expired + 0.1), 0.1)
+ expired = monotonic() - self.start_time
+ wait = max(min(wait, self.timeout - expired + 0.1), 0.1)
time.sleep(wait)
step += 1
- except ResolverError as e:
- module.fail_json(
- msg='Unexpected resolving error: {0}'.format(to_native(e)),
- records=results,
- completed=finished_checks,
- exception=traceback.format_exc())
- except dns.exception.DNSException as e:
- module.fail_json(
- msg='Unexpected DNS error: {0}'.format(to_native(e)),
- records=results,
- completed=finished_checks,
- exception=traceback.format_exc())
+
+ def _generate_additional_results(self):
+ return dict(
+ records=self.results,
+ completed=self.finished_checks,
+ )
+
+ def run(self):
+ guarded_run(self._run, self.module, generate_additional_results=self._generate_additional_results)
+
+
+def main():
+ module = AnsibleModule(
+ argument_spec=dict(
+ records=dict(required=True, type='list', elements='dict', options=dict(
+ name=dict(required=True, type='str'),
+ values=dict(required=True, type='list', elements='str'),
+ mode=dict(type='str', default='subset', choices=['subset', 'superset', 'superset_not_empty', 'equals', 'equals_ordered']),
+ )),
+ query_retry=dict(type='int', default=3),
+ query_timeout=dict(type='float', default=10),
+ timeout=dict(type='float'),
+ max_sleep=dict(type='float', default=10),
+ always_ask_default_resolver=dict(type='bool', default=True),
+ servfail_retries=dict(type='int', default=0),
+ server=dict(type='list', elements='str'),
+ ),
+ supports_check_mode=True,
+ )
+ assert_requirements_present(module)
+
+ waiter = Waiter(module)
+ waiter.run()
if __name__ == "__main__":
diff --git a/ansible_collections/community/dns/plugins/plugin_utils/inventory/records.py b/ansible_collections/community/dns/plugins/plugin_utils/inventory/records.py
index 461a92b35..30fa11bdc 100644
--- a/ansible_collections/community/dns/plugins/plugin_utils/inventory/records.py
+++ b/ansible_collections/community/dns/plugins/plugin_utils/inventory/records.py
@@ -15,6 +15,7 @@ from ansible.module_utils import six
from ansible.module_utils.common._collections_compat import Sequence
from ansible.plugins.inventory import BaseInventoryPlugin
from ansible.utils.display import Display
+from ansible.utils.unsafe_proxy import wrap_var as make_unsafe
from ansible.template import Templar
from ansible_collections.community.dns.plugins.module_utils.provider import (
@@ -65,7 +66,15 @@ class RecordsInventoryModule(BaseInventoryPlugin):
def parse(self, inventory, loader, path, cache=False):
super(RecordsInventoryModule, self).parse(inventory, loader, path, cache)
- self._read_config_data(path)
+ orig_config = self._read_config_data(path)
+
+ if 'filters' in orig_config:
+ display.deprecated(
+ 'The `filters` option of the %s inventory plugin has been renamed to `simple_filters`. '
+ 'The old name will stop working in community.dns 3.0.0.' % self.NAME,
+ collection_name='community.dns',
+ version='3.0.0',
+ )
self.templar = Templar(loader=loader)
@@ -109,7 +118,7 @@ class RecordsInventoryModule(BaseInventoryPlugin):
except DNSAPIError as e:
raise AnsibleError('Error: %s' % e)
- filters = self.get_option('filters')
+ filters = self.get_option('simple_filters')
filter_types = filters.get('type') or ['A', 'AAAA', 'CNAME']
if not isinstance(filter_types, Sequence) or isinstance(filter_types, six.string_types):
@@ -121,4 +130,4 @@ class RecordsInventoryModule(BaseInventoryPlugin):
if record.prefix:
name = '%s.%s' % (record.prefix, name)
self.inventory.add_host(name)
- self.inventory.set_variable(name, 'ansible_host', record.target)
+ self.inventory.set_variable(name, 'ansible_host', make_unsafe(record.target))
diff --git a/ansible_collections/community/dns/plugins/plugin_utils/ips.py b/ansible_collections/community/dns/plugins/plugin_utils/ips.py
new file mode 100644
index 000000000..256078794
--- /dev/null
+++ b/ansible_collections/community/dns/plugins/plugin_utils/ips.py
@@ -0,0 +1,27 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2023, Felix Fontein <felix@fontein.de>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+from ansible.errors import AnsibleError
+from ansible.module_utils.basic import missing_required_lib
+from ansible.module_utils.six import raise_from
+
+try:
+ import ipaddress # pylint: disable=unused-import
+except ImportError as exc:
+ IPADDRESS_IMPORT_EXC = exc
+else:
+ IPADDRESS_IMPORT_EXC = None
+
+
+def assert_requirements_present(plugin_name, plugin_type):
+ if IPADDRESS_IMPORT_EXC is not None:
+ msg = 'The {fqcn} {type} plugin is missing requirements: {msg}'.format(
+ msg=missing_required_lib('ipaddress'), fqcn=plugin_name, type=plugin_type
+ )
+ raise_from(AnsibleError(msg), IPADDRESS_IMPORT_EXC)
diff --git a/ansible_collections/community/dns/plugins/plugin_utils/resolver.py b/ansible_collections/community/dns/plugins/plugin_utils/resolver.py
new file mode 100644
index 000000000..99c875643
--- /dev/null
+++ b/ansible_collections/community/dns/plugins/plugin_utils/resolver.py
@@ -0,0 +1,49 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2023, Felix Fontein <felix@fontein.de>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+from ansible.errors import AnsibleError
+from ansible.module_utils.basic import missing_required_lib
+from ansible.module_utils.common.text.converters import to_native
+from ansible.module_utils.six import raise_from
+
+from ansible_collections.community.dns.plugins.module_utils.resolver import (
+ ResolverError,
+)
+
+try:
+ import dns # pylint: disable=unused-import
+ import dns.exception # pylint: disable=unused-import
+ import dns.name # pylint: disable=unused-import
+ import dns.message # pylint: disable=unused-import
+ import dns.query # pylint: disable=unused-import
+ import dns.rcode # pylint: disable=unused-import
+ import dns.rdatatype # pylint: disable=unused-import
+ import dns.resolver # pylint: disable=unused-import
+except ImportError as exc:
+ DNSPYTHON_IMPORTERROR = exc
+else:
+ DNSPYTHON_IMPORTERROR = None
+
+
+def guarded_run(runner, error_class=AnsibleError, server=None):
+ suffix = ' for {0}'.format(server) if server is not None else ''
+ try:
+ return runner()
+ except ResolverError as e:
+ raise_from(error_class('Unexpected resolving error{0}: {1}'.format(suffix, to_native(e))), e)
+ except dns.exception.DNSException as e:
+ raise_from(error_class('Unexpected DNS error{0}: {1}'.format(suffix, to_native(e))), e)
+
+
+def assert_requirements_present(plugin_name, plugin_type):
+ if DNSPYTHON_IMPORTERROR is not None:
+ msg = 'The {fqcn} {type} plugin is missing requirements: {msg}'.format(
+ msg=missing_required_lib('dnspython'), fqcn=plugin_name, type=plugin_type
+ )
+ raise_from(AnsibleError(msg), DNSPYTHON_IMPORTERROR)
diff --git a/ansible_collections/community/dns/plugins/public_suffix_list.dat b/ansible_collections/community/dns/plugins/public_suffix_list.dat
index b63242437..dd8bd923e 100644
--- a/ansible_collections/community/dns/plugins/public_suffix_list.dat
+++ b/ansible_collections/community/dns/plugins/public_suffix_list.dat
@@ -1059,22 +1059,11 @@ gouv.fr
nom.fr
prd.fr
tm.fr
-// Former "domaines sectoriels", still registration suffixes
-aeroport.fr
-avocat.fr
+// Other SLDs now selfmanaged out of AFNIC range. Former "domaines sectoriels", still registration suffixes
avoues.fr
cci.fr
-chambagri.fr
-chirurgiens-dentistes.fr
-experts-comptables.fr
-geometre-expert.fr
greta.fr
huissier-justice.fr
-medecin.fr
-notaires.fr
-pharmacien.fr
-port.fr
-veterinaire.fr
// ga : https://en.wikipedia.org/wiki/.ga
ga
@@ -5892,6 +5881,7 @@ kyiv.ua
lg.ua
lt.ua
lugansk.ua
+luhansk.ua
lutsk.ua
lv.ua
lviv.ua
@@ -5915,11 +5905,13 @@ te.ua
ternopil.ua
uz.ua
uzhgorod.ua
+uzhhorod.ua
vinnica.ua
vinnytsia.ua
vn.ua
volyn.ua
yalta.ua
+zakarpattia.ua
zaporizhzhe.ua
zaporizhzhia.ua
zhitomir.ua
@@ -6031,7 +6023,6 @@ k12.ca.us
k12.co.us
k12.ct.us
k12.dc.us
-k12.de.us
k12.fl.us
k12.ga.us
k12.gu.us
@@ -6719,3420 +6710,4478 @@ org.zw
// newGTLDs
-// List of new gTLDs imported from https://www.icann.org/resources/registries/gtlds/v2/gtlds.json on 2023-06-16T15:12:40Z
+// List of new gTLDs imported from https://www.icann.org/resources/registries/gtlds/v2/gtlds.json on 2024-03-06T15:14:58Z
// This list is auto-generated, don't edit it manually.
-// aaa : 2015-02-26 American Automobile Association, Inc.
+// aaa : American Automobile Association, Inc.
+// https://www.iana.org/domains/root/db/aaa.html
aaa
-// aarp : 2015-05-21 AARP
+// aarp : AARP
+// https://www.iana.org/domains/root/db/aarp.html
aarp
-// abb : 2014-10-24 ABB Ltd
+// abb : ABB Ltd
+// https://www.iana.org/domains/root/db/abb.html
abb
-// abbott : 2014-07-24 Abbott Laboratories, Inc.
+// abbott : Abbott Laboratories, Inc.
+// https://www.iana.org/domains/root/db/abbott.html
abbott
-// abbvie : 2015-07-30 AbbVie Inc.
+// abbvie : AbbVie Inc.
+// https://www.iana.org/domains/root/db/abbvie.html
abbvie
-// abc : 2015-07-30 Disney Enterprises, Inc.
+// abc : Disney Enterprises, Inc.
+// https://www.iana.org/domains/root/db/abc.html
abc
-// able : 2015-06-25 Able Inc.
+// able : Able Inc.
+// https://www.iana.org/domains/root/db/able.html
able
-// abogado : 2014-04-24 Registry Services, LLC
+// abogado : Registry Services, LLC
+// https://www.iana.org/domains/root/db/abogado.html
abogado
-// abudhabi : 2015-07-30 Abu Dhabi Systems and Information Centre
+// abudhabi : Abu Dhabi Systems and Information Centre
+// https://www.iana.org/domains/root/db/abudhabi.html
abudhabi
-// academy : 2013-11-07 Binky Moon, LLC
+// academy : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/academy.html
academy
-// accenture : 2014-08-15 Accenture plc
+// accenture : Accenture plc
+// https://www.iana.org/domains/root/db/accenture.html
accenture
-// accountant : 2014-11-20 dot Accountant Limited
+// accountant : dot Accountant Limited
+// https://www.iana.org/domains/root/db/accountant.html
accountant
-// accountants : 2014-03-20 Binky Moon, LLC
+// accountants : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/accountants.html
accountants
-// aco : 2015-01-08 ACO Severin Ahlmann GmbH & Co. KG
+// aco : ACO Severin Ahlmann GmbH & Co. KG
+// https://www.iana.org/domains/root/db/aco.html
aco
-// actor : 2013-12-12 Dog Beach, LLC
+// actor : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/actor.html
actor
-// ads : 2014-12-04 Charleston Road Registry Inc.
+// ads : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/ads.html
ads
-// adult : 2014-10-16 ICM Registry AD LLC
+// adult : ICM Registry AD LLC
+// https://www.iana.org/domains/root/db/adult.html
adult
-// aeg : 2015-03-19 Aktiebolaget Electrolux
+// aeg : Aktiebolaget Electrolux
+// https://www.iana.org/domains/root/db/aeg.html
aeg
-// aetna : 2015-05-21 Aetna Life Insurance Company
+// aetna : Aetna Life Insurance Company
+// https://www.iana.org/domains/root/db/aetna.html
aetna
-// afl : 2014-10-02 Australian Football League
+// afl : Australian Football League
+// https://www.iana.org/domains/root/db/afl.html
afl
-// africa : 2014-03-24 ZA Central Registry NPC trading as Registry.Africa
+// africa : ZA Central Registry NPC trading as Registry.Africa
+// https://www.iana.org/domains/root/db/africa.html
africa
-// agakhan : 2015-04-23 Fondation Aga Khan (Aga Khan Foundation)
+// agakhan : Fondation Aga Khan (Aga Khan Foundation)
+// https://www.iana.org/domains/root/db/agakhan.html
agakhan
-// agency : 2013-11-14 Binky Moon, LLC
+// agency : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/agency.html
agency
-// aig : 2014-12-18 American International Group, Inc.
+// aig : American International Group, Inc.
+// https://www.iana.org/domains/root/db/aig.html
aig
-// airbus : 2015-07-30 Airbus S.A.S.
+// airbus : Airbus S.A.S.
+// https://www.iana.org/domains/root/db/airbus.html
airbus
-// airforce : 2014-03-06 Dog Beach, LLC
+// airforce : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/airforce.html
airforce
-// airtel : 2014-10-24 Bharti Airtel Limited
+// airtel : Bharti Airtel Limited
+// https://www.iana.org/domains/root/db/airtel.html
airtel
-// akdn : 2015-04-23 Fondation Aga Khan (Aga Khan Foundation)
+// akdn : Fondation Aga Khan (Aga Khan Foundation)
+// https://www.iana.org/domains/root/db/akdn.html
akdn
-// alibaba : 2015-01-15 Alibaba Group Holding Limited
+// alibaba : Alibaba Group Holding Limited
+// https://www.iana.org/domains/root/db/alibaba.html
alibaba
-// alipay : 2015-01-15 Alibaba Group Holding Limited
+// alipay : Alibaba Group Holding Limited
+// https://www.iana.org/domains/root/db/alipay.html
alipay
-// allfinanz : 2014-07-03 Allfinanz Deutsche Vermögensberatung Aktiengesellschaft
+// allfinanz : Allfinanz Deutsche Vermögensberatung Aktiengesellschaft
+// https://www.iana.org/domains/root/db/allfinanz.html
allfinanz
-// allstate : 2015-07-31 Allstate Fire and Casualty Insurance Company
+// allstate : Allstate Fire and Casualty Insurance Company
+// https://www.iana.org/domains/root/db/allstate.html
allstate
-// ally : 2015-06-18 Ally Financial Inc.
+// ally : Ally Financial Inc.
+// https://www.iana.org/domains/root/db/ally.html
ally
-// alsace : 2014-07-02 Region Grand Est
+// alsace : Region Grand Est
+// https://www.iana.org/domains/root/db/alsace.html
alsace
-// alstom : 2015-07-30 ALSTOM
+// alstom : ALSTOM
+// https://www.iana.org/domains/root/db/alstom.html
alstom
-// amazon : 2019-12-19 Amazon Registry Services, Inc.
+// amazon : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/amazon.html
amazon
-// americanexpress : 2015-07-31 American Express Travel Related Services Company, Inc.
+// americanexpress : American Express Travel Related Services Company, Inc.
+// https://www.iana.org/domains/root/db/americanexpress.html
americanexpress
-// americanfamily : 2015-07-23 AmFam, Inc.
+// americanfamily : AmFam, Inc.
+// https://www.iana.org/domains/root/db/americanfamily.html
americanfamily
-// amex : 2015-07-31 American Express Travel Related Services Company, Inc.
+// amex : American Express Travel Related Services Company, Inc.
+// https://www.iana.org/domains/root/db/amex.html
amex
-// amfam : 2015-07-23 AmFam, Inc.
+// amfam : AmFam, Inc.
+// https://www.iana.org/domains/root/db/amfam.html
amfam
-// amica : 2015-05-28 Amica Mutual Insurance Company
+// amica : Amica Mutual Insurance Company
+// https://www.iana.org/domains/root/db/amica.html
amica
-// amsterdam : 2014-07-24 Gemeente Amsterdam
+// amsterdam : Gemeente Amsterdam
+// https://www.iana.org/domains/root/db/amsterdam.html
amsterdam
-// analytics : 2014-12-18 Campus IP LLC
+// analytics : Campus IP LLC
+// https://www.iana.org/domains/root/db/analytics.html
analytics
-// android : 2014-08-07 Charleston Road Registry Inc.
+// android : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/android.html
android
-// anquan : 2015-01-08 Beijing Qihu Keji Co., Ltd.
+// anquan : Beijing Qihu Keji Co., Ltd.
+// https://www.iana.org/domains/root/db/anquan.html
anquan
-// anz : 2015-07-31 Australia and New Zealand Banking Group Limited
+// anz : Australia and New Zealand Banking Group Limited
+// https://www.iana.org/domains/root/db/anz.html
anz
-// aol : 2015-09-17 Oath Inc.
+// aol : Oath Inc.
+// https://www.iana.org/domains/root/db/aol.html
aol
-// apartments : 2014-12-11 Binky Moon, LLC
+// apartments : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/apartments.html
apartments
-// app : 2015-05-14 Charleston Road Registry Inc.
+// app : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/app.html
app
-// apple : 2015-05-14 Apple Inc.
+// apple : Apple Inc.
+// https://www.iana.org/domains/root/db/apple.html
apple
-// aquarelle : 2014-07-24 Aquarelle.com
+// aquarelle : Aquarelle.com
+// https://www.iana.org/domains/root/db/aquarelle.html
aquarelle
-// arab : 2015-11-12 League of Arab States
+// arab : League of Arab States
+// https://www.iana.org/domains/root/db/arab.html
arab
-// aramco : 2014-11-20 Aramco Services Company
+// aramco : Aramco Services Company
+// https://www.iana.org/domains/root/db/aramco.html
aramco
-// archi : 2014-02-06 Identity Digital Limited
+// archi : Identity Digital Limited
+// https://www.iana.org/domains/root/db/archi.html
archi
-// army : 2014-03-06 Dog Beach, LLC
+// army : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/army.html
army
-// art : 2016-03-24 UK Creative Ideas Limited
+// art : UK Creative Ideas Limited
+// https://www.iana.org/domains/root/db/art.html
art
-// arte : 2014-12-11 Association Relative à la Télévision Européenne G.E.I.E.
+// arte : Association Relative à la Télévision Européenne G.E.I.E.
+// https://www.iana.org/domains/root/db/arte.html
arte
-// asda : 2015-07-31 Wal-Mart Stores, Inc.
+// asda : Wal-Mart Stores, Inc.
+// https://www.iana.org/domains/root/db/asda.html
asda
-// associates : 2014-03-06 Binky Moon, LLC
+// associates : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/associates.html
associates
-// athleta : 2015-07-30 The Gap, Inc.
+// athleta : The Gap, Inc.
+// https://www.iana.org/domains/root/db/athleta.html
athleta
-// attorney : 2014-03-20 Dog Beach, LLC
+// attorney : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/attorney.html
attorney
-// auction : 2014-03-20 Dog Beach, LLC
+// auction : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/auction.html
auction
-// audi : 2015-05-21 AUDI Aktiengesellschaft
+// audi : AUDI Aktiengesellschaft
+// https://www.iana.org/domains/root/db/audi.html
audi
-// audible : 2015-06-25 Amazon Registry Services, Inc.
+// audible : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/audible.html
audible
-// audio : 2014-03-20 XYZ.COM LLC
+// audio : XYZ.COM LLC
+// https://www.iana.org/domains/root/db/audio.html
audio
-// auspost : 2015-08-13 Australian Postal Corporation
+// auspost : Australian Postal Corporation
+// https://www.iana.org/domains/root/db/auspost.html
auspost
-// author : 2014-12-18 Amazon Registry Services, Inc.
+// author : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/author.html
author
-// auto : 2014-11-13 XYZ.COM LLC
+// auto : XYZ.COM LLC
+// https://www.iana.org/domains/root/db/auto.html
auto
-// autos : 2014-01-09 XYZ.COM LLC
+// autos : XYZ.COM LLC
+// https://www.iana.org/domains/root/db/autos.html
autos
-// avianca : 2015-01-08 Avianca Inc.
+// avianca : Avianca Inc.
+// https://www.iana.org/domains/root/db/avianca.html
avianca
-// aws : 2015-06-25 AWS Registry LLC
+// aws : AWS Registry LLC
+// https://www.iana.org/domains/root/db/aws.html
aws
-// axa : 2013-12-19 AXA Group Operations SAS
+// axa : AXA Group Operations SAS
+// https://www.iana.org/domains/root/db/axa.html
axa
-// azure : 2014-12-18 Microsoft Corporation
+// azure : Microsoft Corporation
+// https://www.iana.org/domains/root/db/azure.html
azure
-// baby : 2015-04-09 XYZ.COM LLC
+// baby : XYZ.COM LLC
+// https://www.iana.org/domains/root/db/baby.html
baby
-// baidu : 2015-01-08 Baidu, Inc.
+// baidu : Baidu, Inc.
+// https://www.iana.org/domains/root/db/baidu.html
baidu
-// banamex : 2015-07-30 Citigroup Inc.
+// banamex : Citigroup Inc.
+// https://www.iana.org/domains/root/db/banamex.html
banamex
-// bananarepublic : 2015-07-31 The Gap, Inc.
-bananarepublic
-
-// band : 2014-06-12 Dog Beach, LLC
+// band : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/band.html
band
-// bank : 2014-09-25 fTLD Registry Services LLC
+// bank : fTLD Registry Services LLC
+// https://www.iana.org/domains/root/db/bank.html
bank
-// bar : 2013-12-12 Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable
+// bar : Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable
+// https://www.iana.org/domains/root/db/bar.html
bar
-// barcelona : 2014-07-24 Municipi de Barcelona
+// barcelona : Municipi de Barcelona
+// https://www.iana.org/domains/root/db/barcelona.html
barcelona
-// barclaycard : 2014-11-20 Barclays Bank PLC
+// barclaycard : Barclays Bank PLC
+// https://www.iana.org/domains/root/db/barclaycard.html
barclaycard
-// barclays : 2014-11-20 Barclays Bank PLC
+// barclays : Barclays Bank PLC
+// https://www.iana.org/domains/root/db/barclays.html
barclays
-// barefoot : 2015-06-11 Gallo Vineyards, Inc.
+// barefoot : Gallo Vineyards, Inc.
+// https://www.iana.org/domains/root/db/barefoot.html
barefoot
-// bargains : 2013-11-14 Binky Moon, LLC
+// bargains : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/bargains.html
bargains
-// baseball : 2015-10-29 MLB Advanced Media DH, LLC
+// baseball : MLB Advanced Media DH, LLC
+// https://www.iana.org/domains/root/db/baseball.html
baseball
-// basketball : 2015-08-20 Fédération Internationale de Basketball (FIBA)
+// basketball : Fédération Internationale de Basketball (FIBA)
+// https://www.iana.org/domains/root/db/basketball.html
basketball
-// bauhaus : 2014-04-17 Werkhaus GmbH
+// bauhaus : Werkhaus GmbH
+// https://www.iana.org/domains/root/db/bauhaus.html
bauhaus
-// bayern : 2014-01-23 Bayern Connect GmbH
+// bayern : Bayern Connect GmbH
+// https://www.iana.org/domains/root/db/bayern.html
bayern
-// bbc : 2014-12-18 British Broadcasting Corporation
+// bbc : British Broadcasting Corporation
+// https://www.iana.org/domains/root/db/bbc.html
bbc
-// bbt : 2015-07-23 BB&T Corporation
+// bbt : BB&T Corporation
+// https://www.iana.org/domains/root/db/bbt.html
bbt
-// bbva : 2014-10-02 BANCO BILBAO VIZCAYA ARGENTARIA, S.A.
+// bbva : BANCO BILBAO VIZCAYA ARGENTARIA, S.A.
+// https://www.iana.org/domains/root/db/bbva.html
bbva
-// bcg : 2015-04-02 The Boston Consulting Group, Inc.
+// bcg : The Boston Consulting Group, Inc.
+// https://www.iana.org/domains/root/db/bcg.html
bcg
-// bcn : 2014-07-24 Municipi de Barcelona
+// bcn : Municipi de Barcelona
+// https://www.iana.org/domains/root/db/bcn.html
bcn
-// beats : 2015-05-14 Beats Electronics, LLC
+// beats : Beats Electronics, LLC
+// https://www.iana.org/domains/root/db/beats.html
beats
-// beauty : 2015-12-03 XYZ.COM LLC
+// beauty : XYZ.COM LLC
+// https://www.iana.org/domains/root/db/beauty.html
beauty
-// beer : 2014-01-09 Registry Services, LLC
+// beer : Registry Services, LLC
+// https://www.iana.org/domains/root/db/beer.html
beer
-// bentley : 2014-12-18 Bentley Motors Limited
+// bentley : Bentley Motors Limited
+// https://www.iana.org/domains/root/db/bentley.html
bentley
-// berlin : 2013-10-31 dotBERLIN GmbH & Co. KG
+// berlin : dotBERLIN GmbH & Co. KG
+// https://www.iana.org/domains/root/db/berlin.html
berlin
-// best : 2013-12-19 BestTLD Pty Ltd
+// best : BestTLD Pty Ltd
+// https://www.iana.org/domains/root/db/best.html
best
-// bestbuy : 2015-07-31 BBY Solutions, Inc.
+// bestbuy : BBY Solutions, Inc.
+// https://www.iana.org/domains/root/db/bestbuy.html
bestbuy
-// bet : 2015-05-07 Identity Digital Limited
+// bet : Identity Digital Limited
+// https://www.iana.org/domains/root/db/bet.html
bet
-// bharti : 2014-01-09 Bharti Enterprises (Holding) Private Limited
+// bharti : Bharti Enterprises (Holding) Private Limited
+// https://www.iana.org/domains/root/db/bharti.html
bharti
-// bible : 2014-06-19 American Bible Society
+// bible : American Bible Society
+// https://www.iana.org/domains/root/db/bible.html
bible
-// bid : 2013-12-19 dot Bid Limited
+// bid : dot Bid Limited
+// https://www.iana.org/domains/root/db/bid.html
bid
-// bike : 2013-08-27 Binky Moon, LLC
+// bike : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/bike.html
bike
-// bing : 2014-12-18 Microsoft Corporation
+// bing : Microsoft Corporation
+// https://www.iana.org/domains/root/db/bing.html
bing
-// bingo : 2014-12-04 Binky Moon, LLC
+// bingo : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/bingo.html
bingo
-// bio : 2014-03-06 Identity Digital Limited
+// bio : Identity Digital Limited
+// https://www.iana.org/domains/root/db/bio.html
bio
-// black : 2014-01-16 Identity Digital Limited
+// black : Identity Digital Limited
+// https://www.iana.org/domains/root/db/black.html
black
-// blackfriday : 2014-01-16 Registry Services, LLC
+// blackfriday : Registry Services, LLC
+// https://www.iana.org/domains/root/db/blackfriday.html
blackfriday
-// blockbuster : 2015-07-30 Dish DBS Corporation
+// blockbuster : Dish DBS Corporation
+// https://www.iana.org/domains/root/db/blockbuster.html
blockbuster
-// blog : 2015-05-14 Knock Knock WHOIS There, LLC
+// blog : Knock Knock WHOIS There, LLC
+// https://www.iana.org/domains/root/db/blog.html
blog
-// bloomberg : 2014-07-17 Bloomberg IP Holdings LLC
+// bloomberg : Bloomberg IP Holdings LLC
+// https://www.iana.org/domains/root/db/bloomberg.html
bloomberg
-// blue : 2013-11-07 Identity Digital Limited
+// blue : Identity Digital Limited
+// https://www.iana.org/domains/root/db/blue.html
blue
-// bms : 2014-10-30 Bristol-Myers Squibb Company
+// bms : Bristol-Myers Squibb Company
+// https://www.iana.org/domains/root/db/bms.html
bms
-// bmw : 2014-01-09 Bayerische Motoren Werke Aktiengesellschaft
+// bmw : Bayerische Motoren Werke Aktiengesellschaft
+// https://www.iana.org/domains/root/db/bmw.html
bmw
-// bnpparibas : 2014-05-29 BNP Paribas
+// bnpparibas : BNP Paribas
+// https://www.iana.org/domains/root/db/bnpparibas.html
bnpparibas
-// boats : 2014-12-04 XYZ.COM LLC
+// boats : XYZ.COM LLC
+// https://www.iana.org/domains/root/db/boats.html
boats
-// boehringer : 2015-07-09 Boehringer Ingelheim International GmbH
+// boehringer : Boehringer Ingelheim International GmbH
+// https://www.iana.org/domains/root/db/boehringer.html
boehringer
-// bofa : 2015-07-31 Bank of America Corporation
+// bofa : Bank of America Corporation
+// https://www.iana.org/domains/root/db/bofa.html
bofa
-// bom : 2014-10-16 Núcleo de Informação e Coordenação do Ponto BR - NIC.br
+// bom : Núcleo de Informação e Coordenação do Ponto BR - NIC.br
+// https://www.iana.org/domains/root/db/bom.html
bom
-// bond : 2014-06-05 ShortDot SA
+// bond : ShortDot SA
+// https://www.iana.org/domains/root/db/bond.html
bond
-// boo : 2014-01-30 Charleston Road Registry Inc.
+// boo : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/boo.html
boo
-// book : 2015-08-27 Amazon Registry Services, Inc.
+// book : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/book.html
book
-// booking : 2015-07-16 Booking.com B.V.
+// booking : Booking.com B.V.
+// https://www.iana.org/domains/root/db/booking.html
booking
-// bosch : 2015-06-18 Robert Bosch GMBH
+// bosch : Robert Bosch GMBH
+// https://www.iana.org/domains/root/db/bosch.html
bosch
-// bostik : 2015-05-28 Bostik SA
+// bostik : Bostik SA
+// https://www.iana.org/domains/root/db/bostik.html
bostik
-// boston : 2015-12-10 Registry Services, LLC
+// boston : Registry Services, LLC
+// https://www.iana.org/domains/root/db/boston.html
boston
-// bot : 2014-12-18 Amazon Registry Services, Inc.
+// bot : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/bot.html
bot
-// boutique : 2013-11-14 Binky Moon, LLC
+// boutique : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/boutique.html
boutique
-// box : 2015-11-12 Intercap Registry Inc.
+// box : Intercap Registry Inc.
+// https://www.iana.org/domains/root/db/box.html
box
-// bradesco : 2014-12-18 Banco Bradesco S.A.
+// bradesco : Banco Bradesco S.A.
+// https://www.iana.org/domains/root/db/bradesco.html
bradesco
-// bridgestone : 2014-12-18 Bridgestone Corporation
+// bridgestone : Bridgestone Corporation
+// https://www.iana.org/domains/root/db/bridgestone.html
bridgestone
-// broadway : 2014-12-22 Celebrate Broadway, Inc.
+// broadway : Celebrate Broadway, Inc.
+// https://www.iana.org/domains/root/db/broadway.html
broadway
-// broker : 2014-12-11 Dog Beach, LLC
+// broker : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/broker.html
broker
-// brother : 2015-01-29 Brother Industries, Ltd.
+// brother : Brother Industries, Ltd.
+// https://www.iana.org/domains/root/db/brother.html
brother
-// brussels : 2014-02-06 DNS.be vzw
+// brussels : DNS.be vzw
+// https://www.iana.org/domains/root/db/brussels.html
brussels
-// build : 2013-11-07 Plan Bee LLC
+// build : Plan Bee LLC
+// https://www.iana.org/domains/root/db/build.html
build
-// builders : 2013-11-07 Binky Moon, LLC
+// builders : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/builders.html
builders
-// business : 2013-11-07 Binky Moon, LLC
+// business : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/business.html
business
-// buy : 2014-12-18 Amazon Registry Services, Inc.
+// buy : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/buy.html
buy
-// buzz : 2013-10-02 DOTSTRATEGY CO.
+// buzz : DOTSTRATEGY CO.
+// https://www.iana.org/domains/root/db/buzz.html
buzz
-// bzh : 2014-02-27 Association www.bzh
+// bzh : Association www.bzh
+// https://www.iana.org/domains/root/db/bzh.html
bzh
-// cab : 2013-10-24 Binky Moon, LLC
+// cab : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/cab.html
cab
-// cafe : 2015-02-11 Binky Moon, LLC
+// cafe : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/cafe.html
cafe
-// cal : 2014-07-24 Charleston Road Registry Inc.
+// cal : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/cal.html
cal
-// call : 2014-12-18 Amazon Registry Services, Inc.
+// call : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/call.html
call
-// calvinklein : 2015-07-30 PVH gTLD Holdings LLC
+// calvinklein : PVH gTLD Holdings LLC
+// https://www.iana.org/domains/root/db/calvinklein.html
calvinklein
-// cam : 2016-04-21 Cam Connecting SARL
+// cam : Cam Connecting SARL
+// https://www.iana.org/domains/root/db/cam.html
cam
-// camera : 2013-08-27 Binky Moon, LLC
+// camera : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/camera.html
camera
-// camp : 2013-11-07 Binky Moon, LLC
+// camp : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/camp.html
camp
-// canon : 2014-09-12 Canon Inc.
+// canon : Canon Inc.
+// https://www.iana.org/domains/root/db/canon.html
canon
-// capetown : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry
+// capetown : ZA Central Registry NPC trading as ZA Central Registry
+// https://www.iana.org/domains/root/db/capetown.html
capetown
-// capital : 2014-03-06 Binky Moon, LLC
+// capital : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/capital.html
capital
-// capitalone : 2015-08-06 Capital One Financial Corporation
+// capitalone : Capital One Financial Corporation
+// https://www.iana.org/domains/root/db/capitalone.html
capitalone
-// car : 2015-01-22 XYZ.COM LLC
+// car : XYZ.COM LLC
+// https://www.iana.org/domains/root/db/car.html
car
-// caravan : 2013-12-12 Caravan International, Inc.
+// caravan : Caravan International, Inc.
+// https://www.iana.org/domains/root/db/caravan.html
caravan
-// cards : 2013-12-05 Binky Moon, LLC
+// cards : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/cards.html
cards
-// care : 2014-03-06 Binky Moon, LLC
+// care : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/care.html
care
-// career : 2013-10-09 dotCareer LLC
+// career : dotCareer LLC
+// https://www.iana.org/domains/root/db/career.html
career
-// careers : 2013-10-02 Binky Moon, LLC
+// careers : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/careers.html
careers
-// cars : 2014-11-13 XYZ.COM LLC
+// cars : XYZ.COM LLC
+// https://www.iana.org/domains/root/db/cars.html
cars
-// casa : 2013-11-21 Registry Services, LLC
+// casa : Registry Services, LLC
+// https://www.iana.org/domains/root/db/casa.html
casa
-// case : 2015-09-03 Digity, LLC
+// case : Digity, LLC
+// https://www.iana.org/domains/root/db/case.html
case
-// cash : 2014-03-06 Binky Moon, LLC
+// cash : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/cash.html
cash
-// casino : 2014-12-18 Binky Moon, LLC
+// casino : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/casino.html
casino
-// catering : 2013-12-05 Binky Moon, LLC
+// catering : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/catering.html
catering
-// catholic : 2015-10-21 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication)
+// catholic : Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication)
+// https://www.iana.org/domains/root/db/catholic.html
catholic
-// cba : 2014-06-26 COMMONWEALTH BANK OF AUSTRALIA
+// cba : COMMONWEALTH BANK OF AUSTRALIA
+// https://www.iana.org/domains/root/db/cba.html
cba
-// cbn : 2014-08-22 The Christian Broadcasting Network, Inc.
+// cbn : The Christian Broadcasting Network, Inc.
+// https://www.iana.org/domains/root/db/cbn.html
cbn
-// cbre : 2015-07-02 CBRE, Inc.
+// cbre : CBRE, Inc.
+// https://www.iana.org/domains/root/db/cbre.html
cbre
-// cbs : 2015-08-06 CBS Domains Inc.
-cbs
-
-// center : 2013-11-07 Binky Moon, LLC
+// center : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/center.html
center
-// ceo : 2013-11-07 CEOTLD Pty Ltd
+// ceo : XYZ.COM LLC
+// https://www.iana.org/domains/root/db/ceo.html
ceo
-// cern : 2014-06-05 European Organization for Nuclear Research ("CERN")
+// cern : European Organization for Nuclear Research ("CERN")
+// https://www.iana.org/domains/root/db/cern.html
cern
-// cfa : 2014-08-28 CFA Institute
+// cfa : CFA Institute
+// https://www.iana.org/domains/root/db/cfa.html
cfa
-// cfd : 2014-12-11 ShortDot SA
+// cfd : ShortDot SA
+// https://www.iana.org/domains/root/db/cfd.html
cfd
-// chanel : 2015-04-09 Chanel International B.V.
+// chanel : Chanel International B.V.
+// https://www.iana.org/domains/root/db/chanel.html
chanel
-// channel : 2014-05-08 Charleston Road Registry Inc.
+// channel : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/channel.html
channel
-// charity : 2018-04-11 Public Interest Registry
+// charity : Public Interest Registry
+// https://www.iana.org/domains/root/db/charity.html
charity
-// chase : 2015-04-30 JPMorgan Chase Bank, National Association
+// chase : JPMorgan Chase Bank, National Association
+// https://www.iana.org/domains/root/db/chase.html
chase
-// chat : 2014-12-04 Binky Moon, LLC
+// chat : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/chat.html
chat
-// cheap : 2013-11-14 Binky Moon, LLC
+// cheap : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/cheap.html
cheap
-// chintai : 2015-06-11 CHINTAI Corporation
+// chintai : CHINTAI Corporation
+// https://www.iana.org/domains/root/db/chintai.html
chintai
-// christmas : 2013-11-21 XYZ.COM LLC
+// christmas : XYZ.COM LLC
+// https://www.iana.org/domains/root/db/christmas.html
christmas
-// chrome : 2014-07-24 Charleston Road Registry Inc.
+// chrome : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/chrome.html
chrome
-// church : 2014-02-06 Binky Moon, LLC
+// church : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/church.html
church
-// cipriani : 2015-02-19 Hotel Cipriani Srl
+// cipriani : Hotel Cipriani Srl
+// https://www.iana.org/domains/root/db/cipriani.html
cipriani
-// circle : 2014-12-18 Amazon Registry Services, Inc.
+// circle : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/circle.html
circle
-// cisco : 2014-12-22 Cisco Technology, Inc.
+// cisco : Cisco Technology, Inc.
+// https://www.iana.org/domains/root/db/cisco.html
cisco
-// citadel : 2015-07-23 Citadel Domain LLC
+// citadel : Citadel Domain LLC
+// https://www.iana.org/domains/root/db/citadel.html
citadel
-// citi : 2015-07-30 Citigroup Inc.
+// citi : Citigroup Inc.
+// https://www.iana.org/domains/root/db/citi.html
citi
-// citic : 2014-01-09 CITIC Group Corporation
+// citic : CITIC Group Corporation
+// https://www.iana.org/domains/root/db/citic.html
citic
-// city : 2014-05-29 Binky Moon, LLC
+// city : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/city.html
city
-// cityeats : 2014-12-11 Lifestyle Domain Holdings, Inc.
-cityeats
-
-// claims : 2014-03-20 Binky Moon, LLC
+// claims : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/claims.html
claims
-// cleaning : 2013-12-05 Binky Moon, LLC
+// cleaning : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/cleaning.html
cleaning
-// click : 2014-06-05 Internet Naming Company LLC
+// click : Internet Naming Company LLC
+// https://www.iana.org/domains/root/db/click.html
click
-// clinic : 2014-03-20 Binky Moon, LLC
+// clinic : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/clinic.html
clinic
-// clinique : 2015-10-01 The Estée Lauder Companies Inc.
+// clinique : The Estée Lauder Companies Inc.
+// https://www.iana.org/domains/root/db/clinique.html
clinique
-// clothing : 2013-08-27 Binky Moon, LLC
+// clothing : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/clothing.html
clothing
-// cloud : 2015-04-16 Aruba PEC S.p.A.
+// cloud : Aruba PEC S.p.A.
+// https://www.iana.org/domains/root/db/cloud.html
cloud
-// club : 2013-11-08 Registry Services, LLC
+// club : Registry Services, LLC
+// https://www.iana.org/domains/root/db/club.html
club
-// clubmed : 2015-06-25 Club Méditerranée S.A.
+// clubmed : Club Méditerranée S.A.
+// https://www.iana.org/domains/root/db/clubmed.html
clubmed
-// coach : 2014-10-09 Binky Moon, LLC
+// coach : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/coach.html
coach
-// codes : 2013-10-31 Binky Moon, LLC
+// codes : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/codes.html
codes
-// coffee : 2013-10-17 Binky Moon, LLC
+// coffee : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/coffee.html
coffee
-// college : 2014-01-16 XYZ.COM LLC
+// college : XYZ.COM LLC
+// https://www.iana.org/domains/root/db/college.html
college
-// cologne : 2014-02-05 dotKoeln GmbH
+// cologne : dotKoeln GmbH
+// https://www.iana.org/domains/root/db/cologne.html
cologne
-// comcast : 2015-07-23 Comcast IP Holdings I, LLC
-comcast
-
-// commbank : 2014-06-26 COMMONWEALTH BANK OF AUSTRALIA
+// commbank : COMMONWEALTH BANK OF AUSTRALIA
+// https://www.iana.org/domains/root/db/commbank.html
commbank
-// community : 2013-12-05 Binky Moon, LLC
+// community : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/community.html
community
-// company : 2013-11-07 Binky Moon, LLC
+// company : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/company.html
company
-// compare : 2015-10-08 Registry Services, LLC
+// compare : Registry Services, LLC
+// https://www.iana.org/domains/root/db/compare.html
compare
-// computer : 2013-10-24 Binky Moon, LLC
+// computer : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/computer.html
computer
-// comsec : 2015-01-08 VeriSign, Inc.
+// comsec : VeriSign, Inc.
+// https://www.iana.org/domains/root/db/comsec.html
comsec
-// condos : 2013-12-05 Binky Moon, LLC
+// condos : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/condos.html
condos
-// construction : 2013-09-16 Binky Moon, LLC
+// construction : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/construction.html
construction
-// consulting : 2013-12-05 Dog Beach, LLC
+// consulting : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/consulting.html
consulting
-// contact : 2015-01-08 Dog Beach, LLC
+// contact : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/contact.html
contact
-// contractors : 2013-09-10 Binky Moon, LLC
+// contractors : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/contractors.html
contractors
-// cooking : 2013-11-21 Registry Services, LLC
+// cooking : Registry Services, LLC
+// https://www.iana.org/domains/root/db/cooking.html
cooking
-// cool : 2013-11-14 Binky Moon, LLC
+// cool : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/cool.html
cool
-// corsica : 2014-09-25 Collectivité de Corse
+// corsica : Collectivité de Corse
+// https://www.iana.org/domains/root/db/corsica.html
corsica
-// country : 2013-12-19 Internet Naming Company LLC
+// country : Internet Naming Company LLC
+// https://www.iana.org/domains/root/db/country.html
country
-// coupon : 2015-02-26 Amazon Registry Services, Inc.
+// coupon : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/coupon.html
coupon
-// coupons : 2015-03-26 Binky Moon, LLC
+// coupons : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/coupons.html
coupons
-// courses : 2014-12-04 Registry Services, LLC
+// courses : Registry Services, LLC
+// https://www.iana.org/domains/root/db/courses.html
courses
-// cpa : 2019-06-10 American Institute of Certified Public Accountants
+// cpa : American Institute of Certified Public Accountants
+// https://www.iana.org/domains/root/db/cpa.html
cpa
-// credit : 2014-03-20 Binky Moon, LLC
+// credit : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/credit.html
credit
-// creditcard : 2014-03-20 Binky Moon, LLC
+// creditcard : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/creditcard.html
creditcard
-// creditunion : 2015-01-22 DotCooperation LLC
+// creditunion : DotCooperation LLC
+// https://www.iana.org/domains/root/db/creditunion.html
creditunion
-// cricket : 2014-10-09 dot Cricket Limited
+// cricket : dot Cricket Limited
+// https://www.iana.org/domains/root/db/cricket.html
cricket
-// crown : 2014-10-24 Crown Equipment Corporation
+// crown : Crown Equipment Corporation
+// https://www.iana.org/domains/root/db/crown.html
crown
-// crs : 2014-04-03 Federated Co-operatives Limited
+// crs : Federated Co-operatives Limited
+// https://www.iana.org/domains/root/db/crs.html
crs
-// cruise : 2015-12-10 Viking River Cruises (Bermuda) Ltd.
+// cruise : Viking River Cruises (Bermuda) Ltd.
+// https://www.iana.org/domains/root/db/cruise.html
cruise
-// cruises : 2013-12-05 Binky Moon, LLC
+// cruises : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/cruises.html
cruises
-// cuisinella : 2014-04-03 SCHMIDT GROUPE S.A.S.
+// cuisinella : SCHMIDT GROUPE S.A.S.
+// https://www.iana.org/domains/root/db/cuisinella.html
cuisinella
-// cymru : 2014-05-08 Nominet UK
+// cymru : Nominet UK
+// https://www.iana.org/domains/root/db/cymru.html
cymru
-// cyou : 2015-01-22 ShortDot SA
+// cyou : ShortDot SA
+// https://www.iana.org/domains/root/db/cyou.html
cyou
-// dabur : 2014-02-06 Dabur India Limited
+// dabur : Dabur India Limited
+// https://www.iana.org/domains/root/db/dabur.html
dabur
-// dad : 2014-01-23 Charleston Road Registry Inc.
+// dad : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/dad.html
dad
-// dance : 2013-10-24 Dog Beach, LLC
+// dance : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/dance.html
dance
-// data : 2016-06-02 Dish DBS Corporation
+// data : Dish DBS Corporation
+// https://www.iana.org/domains/root/db/data.html
data
-// date : 2014-11-20 dot Date Limited
+// date : dot Date Limited
+// https://www.iana.org/domains/root/db/date.html
date
-// dating : 2013-12-05 Binky Moon, LLC
+// dating : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/dating.html
dating
-// datsun : 2014-03-27 NISSAN MOTOR CO., LTD.
+// datsun : NISSAN MOTOR CO., LTD.
+// https://www.iana.org/domains/root/db/datsun.html
datsun
-// day : 2014-01-30 Charleston Road Registry Inc.
+// day : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/day.html
day
-// dclk : 2014-11-20 Charleston Road Registry Inc.
+// dclk : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/dclk.html
dclk
-// dds : 2015-05-07 Registry Services, LLC
+// dds : Registry Services, LLC
+// https://www.iana.org/domains/root/db/dds.html
dds
-// deal : 2015-06-25 Amazon Registry Services, Inc.
+// deal : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/deal.html
deal
-// dealer : 2014-12-22 Intercap Registry Inc.
+// dealer : Intercap Registry Inc.
+// https://www.iana.org/domains/root/db/dealer.html
dealer
-// deals : 2014-05-22 Binky Moon, LLC
+// deals : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/deals.html
deals
-// degree : 2014-03-06 Dog Beach, LLC
+// degree : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/degree.html
degree
-// delivery : 2014-09-11 Binky Moon, LLC
+// delivery : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/delivery.html
delivery
-// dell : 2014-10-24 Dell Inc.
+// dell : Dell Inc.
+// https://www.iana.org/domains/root/db/dell.html
dell
-// deloitte : 2015-07-31 Deloitte Touche Tohmatsu
+// deloitte : Deloitte Touche Tohmatsu
+// https://www.iana.org/domains/root/db/deloitte.html
deloitte
-// delta : 2015-02-19 Delta Air Lines, Inc.
+// delta : Delta Air Lines, Inc.
+// https://www.iana.org/domains/root/db/delta.html
delta
-// democrat : 2013-10-24 Dog Beach, LLC
+// democrat : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/democrat.html
democrat
-// dental : 2014-03-20 Binky Moon, LLC
+// dental : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/dental.html
dental
-// dentist : 2014-03-20 Dog Beach, LLC
+// dentist : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/dentist.html
dentist
-// desi : 2013-11-14 Desi Networks LLC
+// desi
+// https://www.iana.org/domains/root/db/desi.html
desi
-// design : 2014-11-07 Registry Services, LLC
+// design : Registry Services, LLC
+// https://www.iana.org/domains/root/db/design.html
design
-// dev : 2014-10-16 Charleston Road Registry Inc.
+// dev : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/dev.html
dev
-// dhl : 2015-07-23 Deutsche Post AG
+// dhl : Deutsche Post AG
+// https://www.iana.org/domains/root/db/dhl.html
dhl
-// diamonds : 2013-09-22 Binky Moon, LLC
+// diamonds : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/diamonds.html
diamonds
-// diet : 2014-06-26 XYZ.COM LLC
+// diet : XYZ.COM LLC
+// https://www.iana.org/domains/root/db/diet.html
diet
-// digital : 2014-03-06 Binky Moon, LLC
+// digital : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/digital.html
digital
-// direct : 2014-04-10 Binky Moon, LLC
+// direct : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/direct.html
direct
-// directory : 2013-09-20 Binky Moon, LLC
+// directory : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/directory.html
directory
-// discount : 2014-03-06 Binky Moon, LLC
+// discount : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/discount.html
discount
-// discover : 2015-07-23 Discover Financial Services
+// discover : Discover Financial Services
+// https://www.iana.org/domains/root/db/discover.html
discover
-// dish : 2015-07-30 Dish DBS Corporation
+// dish : Dish DBS Corporation
+// https://www.iana.org/domains/root/db/dish.html
dish
-// diy : 2015-11-05 Lifestyle Domain Holdings, Inc.
+// diy : Internet Naming Company LLC
+// https://www.iana.org/domains/root/db/diy.html
diy
-// dnp : 2013-12-13 Dai Nippon Printing Co., Ltd.
+// dnp : Dai Nippon Printing Co., Ltd.
+// https://www.iana.org/domains/root/db/dnp.html
dnp
-// docs : 2014-10-16 Charleston Road Registry Inc.
+// docs : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/docs.html
docs
-// doctor : 2016-06-02 Binky Moon, LLC
+// doctor : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/doctor.html
doctor
-// dog : 2014-12-04 Binky Moon, LLC
+// dog : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/dog.html
dog
-// domains : 2013-10-17 Binky Moon, LLC
+// domains : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/domains.html
domains
-// dot : 2015-05-21 Dish DBS Corporation
+// dot : Dish DBS Corporation
+// https://www.iana.org/domains/root/db/dot.html
dot
-// download : 2014-11-20 dot Support Limited
+// download : dot Support Limited
+// https://www.iana.org/domains/root/db/download.html
download
-// drive : 2015-03-05 Charleston Road Registry Inc.
+// drive : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/drive.html
drive
-// dtv : 2015-06-04 Dish DBS Corporation
+// dtv : Dish DBS Corporation
+// https://www.iana.org/domains/root/db/dtv.html
dtv
-// dubai : 2015-01-01 Dubai Smart Government Department
+// dubai : Dubai Smart Government Department
+// https://www.iana.org/domains/root/db/dubai.html
dubai
-// dunlop : 2015-07-02 The Goodyear Tire & Rubber Company
+// dunlop : The Goodyear Tire & Rubber Company
+// https://www.iana.org/domains/root/db/dunlop.html
dunlop
-// dupont : 2015-06-25 DuPont Specialty Products USA, LLC
+// dupont : DuPont Specialty Products USA, LLC
+// https://www.iana.org/domains/root/db/dupont.html
dupont
-// durban : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry
+// durban : ZA Central Registry NPC trading as ZA Central Registry
+// https://www.iana.org/domains/root/db/durban.html
durban
-// dvag : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG
+// dvag : Deutsche Vermögensberatung Aktiengesellschaft DVAG
+// https://www.iana.org/domains/root/db/dvag.html
dvag
-// dvr : 2016-05-26 DISH Technologies L.L.C.
+// dvr : DISH Technologies L.L.C.
+// https://www.iana.org/domains/root/db/dvr.html
dvr
-// earth : 2014-12-04 Interlink Systems Innovation Institute K.K.
+// earth : Interlink Systems Innovation Institute K.K.
+// https://www.iana.org/domains/root/db/earth.html
earth
-// eat : 2014-01-23 Charleston Road Registry Inc.
+// eat : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/eat.html
eat
-// eco : 2016-07-08 Big Room Inc.
+// eco : Big Room Inc.
+// https://www.iana.org/domains/root/db/eco.html
eco
-// edeka : 2014-12-18 EDEKA Verband kaufmännischer Genossenschaften e.V.
+// edeka : EDEKA Verband kaufmännischer Genossenschaften e.V.
+// https://www.iana.org/domains/root/db/edeka.html
edeka
-// education : 2013-11-07 Binky Moon, LLC
+// education : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/education.html
education
-// email : 2013-10-31 Binky Moon, LLC
+// email : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/email.html
email
-// emerck : 2014-04-03 Merck KGaA
+// emerck : Merck KGaA
+// https://www.iana.org/domains/root/db/emerck.html
emerck
-// energy : 2014-09-11 Binky Moon, LLC
+// energy : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/energy.html
energy
-// engineer : 2014-03-06 Dog Beach, LLC
+// engineer : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/engineer.html
engineer
-// engineering : 2014-03-06 Binky Moon, LLC
+// engineering : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/engineering.html
engineering
-// enterprises : 2013-09-20 Binky Moon, LLC
+// enterprises : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/enterprises.html
enterprises
-// epson : 2014-12-04 Seiko Epson Corporation
+// epson : Seiko Epson Corporation
+// https://www.iana.org/domains/root/db/epson.html
epson
-// equipment : 2013-08-27 Binky Moon, LLC
+// equipment : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/equipment.html
equipment
-// ericsson : 2015-07-09 Telefonaktiebolaget L M Ericsson
+// ericsson : Telefonaktiebolaget L M Ericsson
+// https://www.iana.org/domains/root/db/ericsson.html
ericsson
-// erni : 2014-04-03 ERNI Group Holding AG
+// erni : ERNI Group Holding AG
+// https://www.iana.org/domains/root/db/erni.html
erni
-// esq : 2014-05-08 Charleston Road Registry Inc.
+// esq : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/esq.html
esq
-// estate : 2013-08-27 Binky Moon, LLC
+// estate : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/estate.html
estate
-// etisalat : 2015-09-03 Emirates Telecommunications Corporation (trading as Etisalat)
-etisalat
-
-// eurovision : 2014-04-24 European Broadcasting Union (EBU)
+// eurovision : European Broadcasting Union (EBU)
+// https://www.iana.org/domains/root/db/eurovision.html
eurovision
-// eus : 2013-12-12 Puntueus Fundazioa
+// eus : Puntueus Fundazioa
+// https://www.iana.org/domains/root/db/eus.html
eus
-// events : 2013-12-05 Binky Moon, LLC
+// events : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/events.html
events
-// exchange : 2014-03-06 Binky Moon, LLC
+// exchange : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/exchange.html
exchange
-// expert : 2013-11-21 Binky Moon, LLC
+// expert : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/expert.html
expert
-// exposed : 2013-12-05 Binky Moon, LLC
+// exposed : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/exposed.html
exposed
-// express : 2015-02-11 Binky Moon, LLC
+// express : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/express.html
express
-// extraspace : 2015-05-14 Extra Space Storage LLC
+// extraspace : Extra Space Storage LLC
+// https://www.iana.org/domains/root/db/extraspace.html
extraspace
-// fage : 2014-12-18 Fage International S.A.
+// fage : Fage International S.A.
+// https://www.iana.org/domains/root/db/fage.html
fage
-// fail : 2014-03-06 Binky Moon, LLC
+// fail : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/fail.html
fail
-// fairwinds : 2014-11-13 FairWinds Partners, LLC
+// fairwinds : FairWinds Partners, LLC
+// https://www.iana.org/domains/root/db/fairwinds.html
fairwinds
-// faith : 2014-11-20 dot Faith Limited
+// faith : dot Faith Limited
+// https://www.iana.org/domains/root/db/faith.html
faith
-// family : 2015-04-02 Dog Beach, LLC
+// family : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/family.html
family
-// fan : 2014-03-06 Dog Beach, LLC
+// fan : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/fan.html
fan
-// fans : 2014-11-07 ZDNS International Limited
+// fans : ZDNS International Limited
+// https://www.iana.org/domains/root/db/fans.html
fans
-// farm : 2013-11-07 Binky Moon, LLC
+// farm : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/farm.html
farm
-// farmers : 2015-07-09 Farmers Insurance Exchange
+// farmers : Farmers Insurance Exchange
+// https://www.iana.org/domains/root/db/farmers.html
farmers
-// fashion : 2014-07-03 Registry Services, LLC
+// fashion : Registry Services, LLC
+// https://www.iana.org/domains/root/db/fashion.html
fashion
-// fast : 2014-12-18 Amazon Registry Services, Inc.
+// fast : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/fast.html
fast
-// fedex : 2015-08-06 Federal Express Corporation
+// fedex : Federal Express Corporation
+// https://www.iana.org/domains/root/db/fedex.html
fedex
-// feedback : 2013-12-19 Top Level Spectrum, Inc.
+// feedback : Top Level Spectrum, Inc.
+// https://www.iana.org/domains/root/db/feedback.html
feedback
-// ferrari : 2015-07-31 Fiat Chrysler Automobiles N.V.
+// ferrari : Fiat Chrysler Automobiles N.V.
+// https://www.iana.org/domains/root/db/ferrari.html
ferrari
-// ferrero : 2014-12-18 Ferrero Trading Lux S.A.
+// ferrero : Ferrero Trading Lux S.A.
+// https://www.iana.org/domains/root/db/ferrero.html
ferrero
-// fidelity : 2015-07-30 Fidelity Brokerage Services LLC
+// fidelity : Fidelity Brokerage Services LLC
+// https://www.iana.org/domains/root/db/fidelity.html
fidelity
-// fido : 2015-08-06 Rogers Communications Canada Inc.
+// fido : Rogers Communications Canada Inc.
+// https://www.iana.org/domains/root/db/fido.html
fido
-// film : 2015-01-08 Motion Picture Domain Registry Pty Ltd
+// film : Motion Picture Domain Registry Pty Ltd
+// https://www.iana.org/domains/root/db/film.html
film
-// final : 2014-10-16 Núcleo de Informação e Coordenação do Ponto BR - NIC.br
+// final : Núcleo de Informação e Coordenação do Ponto BR - NIC.br
+// https://www.iana.org/domains/root/db/final.html
final
-// finance : 2014-03-20 Binky Moon, LLC
+// finance : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/finance.html
finance
-// financial : 2014-03-06 Binky Moon, LLC
+// financial : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/financial.html
financial
-// fire : 2015-06-25 Amazon Registry Services, Inc.
+// fire : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/fire.html
fire
-// firestone : 2014-12-18 Bridgestone Licensing Services, Inc
+// firestone : Bridgestone Licensing Services, Inc
+// https://www.iana.org/domains/root/db/firestone.html
firestone
-// firmdale : 2014-03-27 Firmdale Holdings Limited
+// firmdale : Firmdale Holdings Limited
+// https://www.iana.org/domains/root/db/firmdale.html
firmdale
-// fish : 2013-12-12 Binky Moon, LLC
+// fish : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/fish.html
fish
-// fishing : 2013-11-21 Registry Services, LLC
+// fishing : Registry Services, LLC
+// https://www.iana.org/domains/root/db/fishing.html
fishing
-// fit : 2014-11-07 Registry Services, LLC
+// fit : Registry Services, LLC
+// https://www.iana.org/domains/root/db/fit.html
fit
-// fitness : 2014-03-06 Binky Moon, LLC
+// fitness : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/fitness.html
fitness
-// flickr : 2015-04-02 Flickr, Inc.
+// flickr : Flickr, Inc.
+// https://www.iana.org/domains/root/db/flickr.html
flickr
-// flights : 2013-12-05 Binky Moon, LLC
+// flights : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/flights.html
flights
-// flir : 2015-07-23 FLIR Systems, Inc.
+// flir : FLIR Systems, Inc.
+// https://www.iana.org/domains/root/db/flir.html
flir
-// florist : 2013-11-07 Binky Moon, LLC
+// florist : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/florist.html
florist
-// flowers : 2014-10-09 XYZ.COM LLC
+// flowers : XYZ.COM LLC
+// https://www.iana.org/domains/root/db/flowers.html
flowers
-// fly : 2014-05-08 Charleston Road Registry Inc.
+// fly : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/fly.html
fly
-// foo : 2014-01-23 Charleston Road Registry Inc.
+// foo : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/foo.html
foo
-// food : 2016-04-21 Lifestyle Domain Holdings, Inc.
+// food : Internet Naming Company LLC
+// https://www.iana.org/domains/root/db/food.html
food
-// football : 2014-12-18 Binky Moon, LLC
+// football : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/football.html
football
-// ford : 2014-11-13 Ford Motor Company
+// ford : Ford Motor Company
+// https://www.iana.org/domains/root/db/ford.html
ford
-// forex : 2014-12-11 Dog Beach, LLC
+// forex : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/forex.html
forex
-// forsale : 2014-05-22 Dog Beach, LLC
+// forsale : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/forsale.html
forsale
-// forum : 2015-04-02 Fegistry, LLC
+// forum : Fegistry, LLC
+// https://www.iana.org/domains/root/db/forum.html
forum
-// foundation : 2013-12-05 Public Interest Registry
+// foundation : Public Interest Registry
+// https://www.iana.org/domains/root/db/foundation.html
foundation
-// fox : 2015-09-11 FOX Registry, LLC
+// fox : FOX Registry, LLC
+// https://www.iana.org/domains/root/db/fox.html
fox
-// free : 2015-12-10 Amazon Registry Services, Inc.
+// free : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/free.html
free
-// fresenius : 2015-07-30 Fresenius Immobilien-Verwaltungs-GmbH
+// fresenius : Fresenius Immobilien-Verwaltungs-GmbH
+// https://www.iana.org/domains/root/db/fresenius.html
fresenius
-// frl : 2014-05-15 FRLregistry B.V.
+// frl : FRLregistry B.V.
+// https://www.iana.org/domains/root/db/frl.html
frl
-// frogans : 2013-12-19 OP3FT
+// frogans : OP3FT
+// https://www.iana.org/domains/root/db/frogans.html
frogans
-// frontdoor : 2015-07-02 Lifestyle Domain Holdings, Inc.
-frontdoor
-
-// frontier : 2015-02-05 Frontier Communications Corporation
+// frontier : Frontier Communications Corporation
+// https://www.iana.org/domains/root/db/frontier.html
frontier
-// ftr : 2015-07-16 Frontier Communications Corporation
+// ftr : Frontier Communications Corporation
+// https://www.iana.org/domains/root/db/ftr.html
ftr
-// fujitsu : 2015-07-30 Fujitsu Limited
+// fujitsu : Fujitsu Limited
+// https://www.iana.org/domains/root/db/fujitsu.html
fujitsu
-// fun : 2016-01-14 Radix FZC
+// fun : Radix Technologies Inc.
+// https://www.iana.org/domains/root/db/fun.html
fun
-// fund : 2014-03-20 Binky Moon, LLC
+// fund : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/fund.html
fund
-// furniture : 2014-03-20 Binky Moon, LLC
+// furniture : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/furniture.html
furniture
-// futbol : 2013-09-20 Dog Beach, LLC
+// futbol : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/futbol.html
futbol
-// fyi : 2015-04-02 Binky Moon, LLC
+// fyi : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/fyi.html
fyi
-// gal : 2013-11-07 Asociación puntoGAL
+// gal : Asociación puntoGAL
+// https://www.iana.org/domains/root/db/gal.html
gal
-// gallery : 2013-09-13 Binky Moon, LLC
+// gallery : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/gallery.html
gallery
-// gallo : 2015-06-11 Gallo Vineyards, Inc.
+// gallo : Gallo Vineyards, Inc.
+// https://www.iana.org/domains/root/db/gallo.html
gallo
-// gallup : 2015-02-19 Gallup, Inc.
+// gallup : Gallup, Inc.
+// https://www.iana.org/domains/root/db/gallup.html
gallup
-// game : 2015-05-28 XYZ.COM LLC
+// game : XYZ.COM LLC
+// https://www.iana.org/domains/root/db/game.html
game
-// games : 2015-05-28 Dog Beach, LLC
+// games : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/games.html
games
-// gap : 2015-07-31 The Gap, Inc.
+// gap : The Gap, Inc.
+// https://www.iana.org/domains/root/db/gap.html
gap
-// garden : 2014-06-26 Registry Services, LLC
+// garden : Registry Services, LLC
+// https://www.iana.org/domains/root/db/garden.html
garden
-// gay : 2019-05-23 Registry Services, LLC
+// gay : Registry Services, LLC
+// https://www.iana.org/domains/root/db/gay.html
gay
-// gbiz : 2014-07-17 Charleston Road Registry Inc.
+// gbiz : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/gbiz.html
gbiz
-// gdn : 2014-07-31 Joint Stock Company "Navigation-information systems"
+// gdn : Joint Stock Company "Navigation-information systems"
+// https://www.iana.org/domains/root/db/gdn.html
gdn
-// gea : 2014-12-04 GEA Group Aktiengesellschaft
+// gea : GEA Group Aktiengesellschaft
+// https://www.iana.org/domains/root/db/gea.html
gea
-// gent : 2014-01-23 Easyhost BV
+// gent : Easyhost BV
+// https://www.iana.org/domains/root/db/gent.html
gent
-// genting : 2015-03-12 Resorts World Inc Pte. Ltd.
+// genting : Resorts World Inc Pte. Ltd.
+// https://www.iana.org/domains/root/db/genting.html
genting
-// george : 2015-07-31 Wal-Mart Stores, Inc.
+// george : Wal-Mart Stores, Inc.
+// https://www.iana.org/domains/root/db/george.html
george
-// ggee : 2014-01-09 GMO Internet, Inc.
+// ggee : GMO Internet, Inc.
+// https://www.iana.org/domains/root/db/ggee.html
ggee
-// gift : 2013-10-17 DotGift, LLC
+// gift : DotGift, LLC
+// https://www.iana.org/domains/root/db/gift.html
gift
-// gifts : 2014-07-03 Binky Moon, LLC
+// gifts : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/gifts.html
gifts
-// gives : 2014-03-06 Public Interest Registry
+// gives : Public Interest Registry
+// https://www.iana.org/domains/root/db/gives.html
gives
-// giving : 2014-11-13 Public Interest Registry
+// giving : Public Interest Registry
+// https://www.iana.org/domains/root/db/giving.html
giving
-// glass : 2013-11-07 Binky Moon, LLC
+// glass : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/glass.html
glass
-// gle : 2014-07-24 Charleston Road Registry Inc.
+// gle : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/gle.html
gle
-// global : 2014-04-17 Identity Digital Limited
+// global : Identity Digital Limited
+// https://www.iana.org/domains/root/db/global.html
global
-// globo : 2013-12-19 Globo Comunicação e Participações S.A
+// globo : Globo Comunicação e Participações S.A
+// https://www.iana.org/domains/root/db/globo.html
globo
-// gmail : 2014-05-01 Charleston Road Registry Inc.
+// gmail : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/gmail.html
gmail
-// gmbh : 2016-01-29 Binky Moon, LLC
+// gmbh : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/gmbh.html
gmbh
-// gmo : 2014-01-09 GMO Internet, Inc.
+// gmo : GMO Internet, Inc.
+// https://www.iana.org/domains/root/db/gmo.html
gmo
-// gmx : 2014-04-24 1&1 Mail & Media GmbH
+// gmx : 1&1 Mail & Media GmbH
+// https://www.iana.org/domains/root/db/gmx.html
gmx
-// godaddy : 2015-07-23 Go Daddy East, LLC
+// godaddy : Go Daddy East, LLC
+// https://www.iana.org/domains/root/db/godaddy.html
godaddy
-// gold : 2015-01-22 Binky Moon, LLC
+// gold : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/gold.html
gold
-// goldpoint : 2014-11-20 YODOBASHI CAMERA CO.,LTD.
+// goldpoint : YODOBASHI CAMERA CO.,LTD.
+// https://www.iana.org/domains/root/db/goldpoint.html
goldpoint
-// golf : 2014-12-18 Binky Moon, LLC
+// golf : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/golf.html
golf
-// goo : 2014-12-18 NTT Resonant Inc.
+// goo : NTT DOCOMO, INC.
+// https://www.iana.org/domains/root/db/goo.html
goo
-// goodyear : 2015-07-02 The Goodyear Tire & Rubber Company
+// goodyear : The Goodyear Tire & Rubber Company
+// https://www.iana.org/domains/root/db/goodyear.html
goodyear
-// goog : 2014-11-20 Charleston Road Registry Inc.
+// goog : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/goog.html
goog
-// google : 2014-07-24 Charleston Road Registry Inc.
+// google : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/google.html
google
-// gop : 2014-01-16 Republican State Leadership Committee, Inc.
+// gop : Republican State Leadership Committee, Inc.
+// https://www.iana.org/domains/root/db/gop.html
gop
-// got : 2014-12-18 Amazon Registry Services, Inc.
+// got : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/got.html
got
-// grainger : 2015-05-07 Grainger Registry Services, LLC
+// grainger : Grainger Registry Services, LLC
+// https://www.iana.org/domains/root/db/grainger.html
grainger
-// graphics : 2013-09-13 Binky Moon, LLC
+// graphics : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/graphics.html
graphics
-// gratis : 2014-03-20 Binky Moon, LLC
+// gratis : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/gratis.html
gratis
-// green : 2014-05-08 Identity Digital Limited
+// green : Identity Digital Limited
+// https://www.iana.org/domains/root/db/green.html
green
-// gripe : 2014-03-06 Binky Moon, LLC
+// gripe : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/gripe.html
gripe
-// grocery : 2016-06-16 Wal-Mart Stores, Inc.
+// grocery : Wal-Mart Stores, Inc.
+// https://www.iana.org/domains/root/db/grocery.html
grocery
-// group : 2014-08-15 Binky Moon, LLC
+// group : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/group.html
group
-// guardian : 2015-07-30 The Guardian Life Insurance Company of America
-guardian
-
-// gucci : 2014-11-13 Guccio Gucci S.p.a.
+// gucci : Guccio Gucci S.p.a.
+// https://www.iana.org/domains/root/db/gucci.html
gucci
-// guge : 2014-08-28 Charleston Road Registry Inc.
+// guge : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/guge.html
guge
-// guide : 2013-09-13 Binky Moon, LLC
+// guide : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/guide.html
guide
-// guitars : 2013-11-14 XYZ.COM LLC
+// guitars : XYZ.COM LLC
+// https://www.iana.org/domains/root/db/guitars.html
guitars
-// guru : 2013-08-27 Binky Moon, LLC
+// guru : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/guru.html
guru
-// hair : 2015-12-03 XYZ.COM LLC
+// hair : XYZ.COM LLC
+// https://www.iana.org/domains/root/db/hair.html
hair
-// hamburg : 2014-02-20 Hamburg Top-Level-Domain GmbH
+// hamburg : Hamburg Top-Level-Domain GmbH
+// https://www.iana.org/domains/root/db/hamburg.html
hamburg
-// hangout : 2014-11-13 Charleston Road Registry Inc.
+// hangout : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/hangout.html
hangout
-// haus : 2013-12-05 Dog Beach, LLC
+// haus : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/haus.html
haus
-// hbo : 2015-07-30 HBO Registry Services, Inc.
+// hbo : HBO Registry Services, Inc.
+// https://www.iana.org/domains/root/db/hbo.html
hbo
-// hdfc : 2015-07-30 HOUSING DEVELOPMENT FINANCE CORPORATION LIMITED
+// hdfc : HOUSING DEVELOPMENT FINANCE CORPORATION LIMITED
+// https://www.iana.org/domains/root/db/hdfc.html
hdfc
-// hdfcbank : 2015-02-12 HDFC Bank Limited
+// hdfcbank : HDFC Bank Limited
+// https://www.iana.org/domains/root/db/hdfcbank.html
hdfcbank
-// health : 2015-02-11 Registry Services, LLC
+// health : Registry Services, LLC
+// https://www.iana.org/domains/root/db/health.html
health
-// healthcare : 2014-06-12 Binky Moon, LLC
+// healthcare : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/healthcare.html
healthcare
-// help : 2014-06-26 Innovation service Limited
+// help : Innovation service Limited
+// https://www.iana.org/domains/root/db/help.html
help
-// helsinki : 2015-02-05 City of Helsinki
+// helsinki : City of Helsinki
+// https://www.iana.org/domains/root/db/helsinki.html
helsinki
-// here : 2014-02-06 Charleston Road Registry Inc.
+// here : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/here.html
here
-// hermes : 2014-07-10 HERMES INTERNATIONAL
+// hermes : HERMES INTERNATIONAL
+// https://www.iana.org/domains/root/db/hermes.html
hermes
-// hiphop : 2014-03-06 Dot Hip Hop, LLC
+// hiphop : Dot Hip Hop, LLC
+// https://www.iana.org/domains/root/db/hiphop.html
hiphop
-// hisamitsu : 2015-07-16 Hisamitsu Pharmaceutical Co.,Inc.
+// hisamitsu : Hisamitsu Pharmaceutical Co.,Inc.
+// https://www.iana.org/domains/root/db/hisamitsu.html
hisamitsu
-// hitachi : 2014-10-31 Hitachi, Ltd.
+// hitachi : Hitachi, Ltd.
+// https://www.iana.org/domains/root/db/hitachi.html
hitachi
-// hiv : 2014-03-13 Internet Naming Company LLC
+// hiv : Internet Naming Company LLC
+// https://www.iana.org/domains/root/db/hiv.html
hiv
-// hkt : 2015-05-14 PCCW-HKT DataCom Services Limited
+// hkt : PCCW-HKT DataCom Services Limited
+// https://www.iana.org/domains/root/db/hkt.html
hkt
-// hockey : 2015-03-19 Binky Moon, LLC
+// hockey : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/hockey.html
hockey
-// holdings : 2013-08-27 Binky Moon, LLC
+// holdings : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/holdings.html
holdings
-// holiday : 2013-11-07 Binky Moon, LLC
+// holiday : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/holiday.html
holiday
-// homedepot : 2015-04-02 Home Depot Product Authority, LLC
+// homedepot : Home Depot Product Authority, LLC
+// https://www.iana.org/domains/root/db/homedepot.html
homedepot
-// homegoods : 2015-07-16 The TJX Companies, Inc.
+// homegoods : The TJX Companies, Inc.
+// https://www.iana.org/domains/root/db/homegoods.html
homegoods
-// homes : 2014-01-09 XYZ.COM LLC
+// homes : XYZ.COM LLC
+// https://www.iana.org/domains/root/db/homes.html
homes
-// homesense : 2015-07-16 The TJX Companies, Inc.
+// homesense : The TJX Companies, Inc.
+// https://www.iana.org/domains/root/db/homesense.html
homesense
-// honda : 2014-12-18 Honda Motor Co., Ltd.
+// honda : Honda Motor Co., Ltd.
+// https://www.iana.org/domains/root/db/honda.html
honda
-// horse : 2013-11-21 Registry Services, LLC
+// horse : Registry Services, LLC
+// https://www.iana.org/domains/root/db/horse.html
horse
-// hospital : 2016-10-20 Binky Moon, LLC
+// hospital : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/hospital.html
hospital
-// host : 2014-04-17 Radix FZC
+// host : Radix Technologies Inc.
+// https://www.iana.org/domains/root/db/host.html
host
-// hosting : 2014-05-29 XYZ.COM LLC
+// hosting : XYZ.COM LLC
+// https://www.iana.org/domains/root/db/hosting.html
hosting
-// hot : 2015-08-27 Amazon Registry Services, Inc.
+// hot : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/hot.html
hot
-// hoteles : 2015-03-05 Travel Reservations SRL
-hoteles
-
-// hotels : 2016-04-07 Booking.com B.V.
+// hotels : Booking.com B.V.
+// https://www.iana.org/domains/root/db/hotels.html
hotels
-// hotmail : 2014-12-18 Microsoft Corporation
+// hotmail : Microsoft Corporation
+// https://www.iana.org/domains/root/db/hotmail.html
hotmail
-// house : 2013-11-07 Binky Moon, LLC
+// house : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/house.html
house
-// how : 2014-01-23 Charleston Road Registry Inc.
+// how : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/how.html
how
-// hsbc : 2014-10-24 HSBC Global Services (UK) Limited
+// hsbc : HSBC Global Services (UK) Limited
+// https://www.iana.org/domains/root/db/hsbc.html
hsbc
-// hughes : 2015-07-30 Hughes Satellite Systems Corporation
+// hughes : Hughes Satellite Systems Corporation
+// https://www.iana.org/domains/root/db/hughes.html
hughes
-// hyatt : 2015-07-30 Hyatt GTLD, L.L.C.
+// hyatt : Hyatt GTLD, L.L.C.
+// https://www.iana.org/domains/root/db/hyatt.html
hyatt
-// hyundai : 2015-07-09 Hyundai Motor Company
+// hyundai : Hyundai Motor Company
+// https://www.iana.org/domains/root/db/hyundai.html
hyundai
-// ibm : 2014-07-31 International Business Machines Corporation
+// ibm : International Business Machines Corporation
+// https://www.iana.org/domains/root/db/ibm.html
ibm
-// icbc : 2015-02-19 Industrial and Commercial Bank of China Limited
+// icbc : Industrial and Commercial Bank of China Limited
+// https://www.iana.org/domains/root/db/icbc.html
icbc
-// ice : 2014-10-30 IntercontinentalExchange, Inc.
+// ice : IntercontinentalExchange, Inc.
+// https://www.iana.org/domains/root/db/ice.html
ice
-// icu : 2015-01-08 ShortDot SA
+// icu : ShortDot SA
+// https://www.iana.org/domains/root/db/icu.html
icu
-// ieee : 2015-07-23 IEEE Global LLC
+// ieee : IEEE Global LLC
+// https://www.iana.org/domains/root/db/ieee.html
ieee
-// ifm : 2014-01-30 ifm electronic gmbh
+// ifm : ifm electronic gmbh
+// https://www.iana.org/domains/root/db/ifm.html
ifm
-// ikano : 2015-07-09 Ikano S.A.
+// ikano : Ikano S.A.
+// https://www.iana.org/domains/root/db/ikano.html
ikano
-// imamat : 2015-08-06 Fondation Aga Khan (Aga Khan Foundation)
+// imamat : Fondation Aga Khan (Aga Khan Foundation)
+// https://www.iana.org/domains/root/db/imamat.html
imamat
-// imdb : 2015-06-25 Amazon Registry Services, Inc.
+// imdb : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/imdb.html
imdb
-// immo : 2014-07-10 Binky Moon, LLC
+// immo : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/immo.html
immo
-// immobilien : 2013-11-07 Dog Beach, LLC
+// immobilien : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/immobilien.html
immobilien
-// inc : 2018-03-10 Intercap Registry Inc.
+// inc : Intercap Registry Inc.
+// https://www.iana.org/domains/root/db/inc.html
inc
-// industries : 2013-12-05 Binky Moon, LLC
+// industries : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/industries.html
industries
-// infiniti : 2014-03-27 NISSAN MOTOR CO., LTD.
+// infiniti : NISSAN MOTOR CO., LTD.
+// https://www.iana.org/domains/root/db/infiniti.html
infiniti
-// ing : 2014-01-23 Charleston Road Registry Inc.
+// ing : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/ing.html
ing
-// ink : 2013-12-05 Registry Services, LLC
+// ink : Registry Services, LLC
+// https://www.iana.org/domains/root/db/ink.html
ink
-// institute : 2013-11-07 Binky Moon, LLC
+// institute : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/institute.html
institute
-// insurance : 2015-02-19 fTLD Registry Services LLC
+// insurance : fTLD Registry Services LLC
+// https://www.iana.org/domains/root/db/insurance.html
insurance
-// insure : 2014-03-20 Binky Moon, LLC
+// insure : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/insure.html
insure
-// international : 2013-11-07 Binky Moon, LLC
+// international : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/international.html
international
-// intuit : 2015-07-30 Intuit Administrative Services, Inc.
+// intuit : Intuit Administrative Services, Inc.
+// https://www.iana.org/domains/root/db/intuit.html
intuit
-// investments : 2014-03-20 Binky Moon, LLC
+// investments : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/investments.html
investments
-// ipiranga : 2014-08-28 Ipiranga Produtos de Petroleo S.A.
+// ipiranga : Ipiranga Produtos de Petroleo S.A.
+// https://www.iana.org/domains/root/db/ipiranga.html
ipiranga
-// irish : 2014-08-07 Binky Moon, LLC
+// irish : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/irish.html
irish
-// ismaili : 2015-08-06 Fondation Aga Khan (Aga Khan Foundation)
+// ismaili : Fondation Aga Khan (Aga Khan Foundation)
+// https://www.iana.org/domains/root/db/ismaili.html
ismaili
-// ist : 2014-08-28 Istanbul Metropolitan Municipality
+// ist : Istanbul Metropolitan Municipality
+// https://www.iana.org/domains/root/db/ist.html
ist
-// istanbul : 2014-08-28 Istanbul Metropolitan Municipality
+// istanbul : Istanbul Metropolitan Municipality
+// https://www.iana.org/domains/root/db/istanbul.html
istanbul
-// itau : 2014-10-02 Itau Unibanco Holding S.A.
+// itau : Itau Unibanco Holding S.A.
+// https://www.iana.org/domains/root/db/itau.html
itau
-// itv : 2015-07-09 ITV Services Limited
+// itv : ITV Services Limited
+// https://www.iana.org/domains/root/db/itv.html
itv
-// jaguar : 2014-11-13 Jaguar Land Rover Ltd
+// jaguar : Jaguar Land Rover Ltd
+// https://www.iana.org/domains/root/db/jaguar.html
jaguar
-// java : 2014-06-19 Oracle Corporation
+// java : Oracle Corporation
+// https://www.iana.org/domains/root/db/java.html
java
-// jcb : 2014-11-20 JCB Co., Ltd.
+// jcb : JCB Co., Ltd.
+// https://www.iana.org/domains/root/db/jcb.html
jcb
-// jeep : 2015-07-30 FCA US LLC.
+// jeep : FCA US LLC.
+// https://www.iana.org/domains/root/db/jeep.html
jeep
-// jetzt : 2014-01-09 Binky Moon, LLC
+// jetzt : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/jetzt.html
jetzt
-// jewelry : 2015-03-05 Binky Moon, LLC
+// jewelry : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/jewelry.html
jewelry
-// jio : 2015-04-02 Reliance Industries Limited
+// jio : Reliance Industries Limited
+// https://www.iana.org/domains/root/db/jio.html
jio
-// jll : 2015-04-02 Jones Lang LaSalle Incorporated
+// jll : Jones Lang LaSalle Incorporated
+// https://www.iana.org/domains/root/db/jll.html
jll
-// jmp : 2015-03-26 Matrix IP LLC
+// jmp : Matrix IP LLC
+// https://www.iana.org/domains/root/db/jmp.html
jmp
-// jnj : 2015-06-18 Johnson & Johnson Services, Inc.
+// jnj : Johnson & Johnson Services, Inc.
+// https://www.iana.org/domains/root/db/jnj.html
jnj
-// joburg : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry
+// joburg : ZA Central Registry NPC trading as ZA Central Registry
+// https://www.iana.org/domains/root/db/joburg.html
joburg
-// jot : 2014-12-18 Amazon Registry Services, Inc.
+// jot : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/jot.html
jot
-// joy : 2014-12-18 Amazon Registry Services, Inc.
+// joy : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/joy.html
joy
-// jpmorgan : 2015-04-30 JPMorgan Chase Bank, National Association
+// jpmorgan : JPMorgan Chase Bank, National Association
+// https://www.iana.org/domains/root/db/jpmorgan.html
jpmorgan
-// jprs : 2014-09-18 Japan Registry Services Co., Ltd.
+// jprs : Japan Registry Services Co., Ltd.
+// https://www.iana.org/domains/root/db/jprs.html
jprs
-// juegos : 2014-03-20 Internet Naming Company LLC
+// juegos : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/juegos.html
juegos
-// juniper : 2015-07-30 JUNIPER NETWORKS, INC.
+// juniper : JUNIPER NETWORKS, INC.
+// https://www.iana.org/domains/root/db/juniper.html
juniper
-// kaufen : 2013-11-07 Dog Beach, LLC
+// kaufen : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/kaufen.html
kaufen
-// kddi : 2014-09-12 KDDI CORPORATION
+// kddi : KDDI CORPORATION
+// https://www.iana.org/domains/root/db/kddi.html
kddi
-// kerryhotels : 2015-04-30 Kerry Trading Co. Limited
+// kerryhotels : Kerry Trading Co. Limited
+// https://www.iana.org/domains/root/db/kerryhotels.html
kerryhotels
-// kerrylogistics : 2015-04-09 Kerry Trading Co. Limited
+// kerrylogistics : Kerry Trading Co. Limited
+// https://www.iana.org/domains/root/db/kerrylogistics.html
kerrylogistics
-// kerryproperties : 2015-04-09 Kerry Trading Co. Limited
+// kerryproperties : Kerry Trading Co. Limited
+// https://www.iana.org/domains/root/db/kerryproperties.html
kerryproperties
-// kfh : 2014-12-04 Kuwait Finance House
+// kfh : Kuwait Finance House
+// https://www.iana.org/domains/root/db/kfh.html
kfh
-// kia : 2015-07-09 KIA MOTORS CORPORATION
+// kia : KIA MOTORS CORPORATION
+// https://www.iana.org/domains/root/db/kia.html
kia
-// kids : 2021-08-13 DotKids Foundation Limited
+// kids : DotKids Foundation Limited
+// https://www.iana.org/domains/root/db/kids.html
kids
-// kim : 2013-09-23 Identity Digital Limited
+// kim : Identity Digital Limited
+// https://www.iana.org/domains/root/db/kim.html
kim
-// kinder : 2014-11-07 Ferrero Trading Lux S.A.
-kinder
-
-// kindle : 2015-06-25 Amazon Registry Services, Inc.
+// kindle : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/kindle.html
kindle
-// kitchen : 2013-09-20 Binky Moon, LLC
+// kitchen : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/kitchen.html
kitchen
-// kiwi : 2013-09-20 DOT KIWI LIMITED
+// kiwi : DOT KIWI LIMITED
+// https://www.iana.org/domains/root/db/kiwi.html
kiwi
-// koeln : 2014-01-09 dotKoeln GmbH
+// koeln : dotKoeln GmbH
+// https://www.iana.org/domains/root/db/koeln.html
koeln
-// komatsu : 2015-01-08 Komatsu Ltd.
+// komatsu : Komatsu Ltd.
+// https://www.iana.org/domains/root/db/komatsu.html
komatsu
-// kosher : 2015-08-20 Kosher Marketing Assets LLC
+// kosher : Kosher Marketing Assets LLC
+// https://www.iana.org/domains/root/db/kosher.html
kosher
-// kpmg : 2015-04-23 KPMG International Cooperative (KPMG International Genossenschaft)
+// kpmg : KPMG International Cooperative (KPMG International Genossenschaft)
+// https://www.iana.org/domains/root/db/kpmg.html
kpmg
-// kpn : 2015-01-08 Koninklijke KPN N.V.
+// kpn : Koninklijke KPN N.V.
+// https://www.iana.org/domains/root/db/kpn.html
kpn
-// krd : 2013-12-05 KRG Department of Information Technology
+// krd : KRG Department of Information Technology
+// https://www.iana.org/domains/root/db/krd.html
krd
-// kred : 2013-12-19 KredTLD Pty Ltd
+// kred : KredTLD Pty Ltd
+// https://www.iana.org/domains/root/db/kred.html
kred
-// kuokgroup : 2015-04-09 Kerry Trading Co. Limited
+// kuokgroup : Kerry Trading Co. Limited
+// https://www.iana.org/domains/root/db/kuokgroup.html
kuokgroup
-// kyoto : 2014-11-07 Academic Institution: Kyoto Jyoho Gakuen
+// kyoto : Academic Institution: Kyoto Jyoho Gakuen
+// https://www.iana.org/domains/root/db/kyoto.html
kyoto
-// lacaixa : 2014-01-09 Fundación Bancaria Caixa d’Estalvis i Pensions de Barcelona, “la Caixa”
+// lacaixa : Fundación Bancaria Caixa d’Estalvis i Pensions de Barcelona, “la Caixa”
+// https://www.iana.org/domains/root/db/lacaixa.html
lacaixa
-// lamborghini : 2015-06-04 Automobili Lamborghini S.p.A.
+// lamborghini : Automobili Lamborghini S.p.A.
+// https://www.iana.org/domains/root/db/lamborghini.html
lamborghini
-// lamer : 2015-10-01 The Estée Lauder Companies Inc.
+// lamer : The Estée Lauder Companies Inc.
+// https://www.iana.org/domains/root/db/lamer.html
lamer
-// lancaster : 2015-02-12 LANCASTER
+// lancaster : LANCASTER
+// https://www.iana.org/domains/root/db/lancaster.html
lancaster
-// land : 2013-09-10 Binky Moon, LLC
+// land : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/land.html
land
-// landrover : 2014-11-13 Jaguar Land Rover Ltd
+// landrover : Jaguar Land Rover Ltd
+// https://www.iana.org/domains/root/db/landrover.html
landrover
-// lanxess : 2015-07-30 LANXESS Corporation
+// lanxess : LANXESS Corporation
+// https://www.iana.org/domains/root/db/lanxess.html
lanxess
-// lasalle : 2015-04-02 Jones Lang LaSalle Incorporated
+// lasalle : Jones Lang LaSalle Incorporated
+// https://www.iana.org/domains/root/db/lasalle.html
lasalle
-// lat : 2014-10-16 XYZ.COM LLC
+// lat : XYZ.COM LLC
+// https://www.iana.org/domains/root/db/lat.html
lat
-// latino : 2015-07-30 Dish DBS Corporation
+// latino : Dish DBS Corporation
+// https://www.iana.org/domains/root/db/latino.html
latino
-// latrobe : 2014-06-16 La Trobe University
+// latrobe : La Trobe University
+// https://www.iana.org/domains/root/db/latrobe.html
latrobe
-// law : 2015-01-22 Registry Services, LLC
+// law : Registry Services, LLC
+// https://www.iana.org/domains/root/db/law.html
law
-// lawyer : 2014-03-20 Dog Beach, LLC
+// lawyer : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/lawyer.html
lawyer
-// lds : 2014-03-20 IRI Domain Management, LLC
+// lds : IRI Domain Management, LLC
+// https://www.iana.org/domains/root/db/lds.html
lds
-// lease : 2014-03-06 Binky Moon, LLC
+// lease : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/lease.html
lease
-// leclerc : 2014-08-07 A.C.D. LEC Association des Centres Distributeurs Edouard Leclerc
+// leclerc : A.C.D. LEC Association des Centres Distributeurs Edouard Leclerc
+// https://www.iana.org/domains/root/db/leclerc.html
leclerc
-// lefrak : 2015-07-16 LeFrak Organization, Inc.
+// lefrak : LeFrak Organization, Inc.
+// https://www.iana.org/domains/root/db/lefrak.html
lefrak
-// legal : 2014-10-16 Binky Moon, LLC
+// legal : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/legal.html
legal
-// lego : 2015-07-16 LEGO Juris A/S
+// lego : LEGO Juris A/S
+// https://www.iana.org/domains/root/db/lego.html
lego
-// lexus : 2015-04-23 TOYOTA MOTOR CORPORATION
+// lexus : TOYOTA MOTOR CORPORATION
+// https://www.iana.org/domains/root/db/lexus.html
lexus
-// lgbt : 2014-05-08 Identity Digital Limited
+// lgbt : Identity Digital Limited
+// https://www.iana.org/domains/root/db/lgbt.html
lgbt
-// lidl : 2014-09-18 Schwarz Domains und Services GmbH & Co. KG
+// lidl : Schwarz Domains und Services GmbH & Co. KG
+// https://www.iana.org/domains/root/db/lidl.html
lidl
-// life : 2014-02-06 Binky Moon, LLC
+// life : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/life.html
life
-// lifeinsurance : 2015-01-15 American Council of Life Insurers
+// lifeinsurance : American Council of Life Insurers
+// https://www.iana.org/domains/root/db/lifeinsurance.html
lifeinsurance
-// lifestyle : 2014-12-11 Lifestyle Domain Holdings, Inc.
+// lifestyle : Internet Naming Company LLC
+// https://www.iana.org/domains/root/db/lifestyle.html
lifestyle
-// lighting : 2013-08-27 Binky Moon, LLC
+// lighting : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/lighting.html
lighting
-// like : 2014-12-18 Amazon Registry Services, Inc.
+// like : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/like.html
like
-// lilly : 2015-07-31 Eli Lilly and Company
+// lilly : Eli Lilly and Company
+// https://www.iana.org/domains/root/db/lilly.html
lilly
-// limited : 2014-03-06 Binky Moon, LLC
+// limited : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/limited.html
limited
-// limo : 2013-10-17 Binky Moon, LLC
+// limo : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/limo.html
limo
-// lincoln : 2014-11-13 Ford Motor Company
+// lincoln : Ford Motor Company
+// https://www.iana.org/domains/root/db/lincoln.html
lincoln
-// link : 2013-11-14 Nova Registry Ltd
+// link : Nova Registry Ltd
+// https://www.iana.org/domains/root/db/link.html
link
-// lipsy : 2015-06-25 Lipsy Ltd
+// lipsy : Lipsy Ltd
+// https://www.iana.org/domains/root/db/lipsy.html
lipsy
-// live : 2014-12-04 Dog Beach, LLC
+// live : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/live.html
live
-// living : 2015-07-30 Lifestyle Domain Holdings, Inc.
+// living : Internet Naming Company LLC
+// https://www.iana.org/domains/root/db/living.html
living
-// llc : 2017-12-14 Identity Digital Limited
+// llc : Identity Digital Limited
+// https://www.iana.org/domains/root/db/llc.html
llc
-// llp : 2019-08-26 Intercap Registry Inc.
+// llp : Intercap Registry Inc.
+// https://www.iana.org/domains/root/db/llp.html
llp
-// loan : 2014-11-20 dot Loan Limited
+// loan : dot Loan Limited
+// https://www.iana.org/domains/root/db/loan.html
loan
-// loans : 2014-03-20 Binky Moon, LLC
+// loans : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/loans.html
loans
-// locker : 2015-06-04 Dish DBS Corporation
+// locker : Orange Domains LLC
+// https://www.iana.org/domains/root/db/locker.html
locker
-// locus : 2015-06-25 Locus Analytics LLC
+// locus : Locus Analytics LLC
+// https://www.iana.org/domains/root/db/locus.html
locus
-// lol : 2015-01-30 XYZ.COM LLC
+// lol : XYZ.COM LLC
+// https://www.iana.org/domains/root/db/lol.html
lol
-// london : 2013-11-14 Dot London Domains Limited
+// london : Dot London Domains Limited
+// https://www.iana.org/domains/root/db/london.html
london
-// lotte : 2014-11-07 Lotte Holdings Co., Ltd.
+// lotte : Lotte Holdings Co., Ltd.
+// https://www.iana.org/domains/root/db/lotte.html
lotte
-// lotto : 2014-04-10 Identity Digital Limited
+// lotto : Identity Digital Limited
+// https://www.iana.org/domains/root/db/lotto.html
lotto
-// love : 2014-12-22 Merchant Law Group LLP
+// love : Merchant Law Group LLP
+// https://www.iana.org/domains/root/db/love.html
love
-// lpl : 2015-07-30 LPL Holdings, Inc.
+// lpl : LPL Holdings, Inc.
+// https://www.iana.org/domains/root/db/lpl.html
lpl
-// lplfinancial : 2015-07-30 LPL Holdings, Inc.
+// lplfinancial : LPL Holdings, Inc.
+// https://www.iana.org/domains/root/db/lplfinancial.html
lplfinancial
-// ltd : 2014-09-25 Binky Moon, LLC
+// ltd : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/ltd.html
ltd
-// ltda : 2014-04-17 InterNetX, Corp
+// ltda : InterNetX, Corp
+// https://www.iana.org/domains/root/db/ltda.html
ltda
-// lundbeck : 2015-08-06 H. Lundbeck A/S
+// lundbeck : H. Lundbeck A/S
+// https://www.iana.org/domains/root/db/lundbeck.html
lundbeck
-// luxe : 2014-01-09 Registry Services, LLC
+// luxe : Registry Services, LLC
+// https://www.iana.org/domains/root/db/luxe.html
luxe
-// luxury : 2013-10-17 Luxury Partners, LLC
+// luxury : Luxury Partners, LLC
+// https://www.iana.org/domains/root/db/luxury.html
luxury
-// madrid : 2014-05-01 Comunidad de Madrid
+// madrid : Comunidad de Madrid
+// https://www.iana.org/domains/root/db/madrid.html
madrid
-// maif : 2014-10-02 Mutuelle Assurance Instituteur France (MAIF)
+// maif : Mutuelle Assurance Instituteur France (MAIF)
+// https://www.iana.org/domains/root/db/maif.html
maif
-// maison : 2013-12-05 Binky Moon, LLC
+// maison : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/maison.html
maison
-// makeup : 2015-01-15 XYZ.COM LLC
+// makeup : XYZ.COM LLC
+// https://www.iana.org/domains/root/db/makeup.html
makeup
-// man : 2014-12-04 MAN SE
+// man : MAN SE
+// https://www.iana.org/domains/root/db/man.html
man
-// management : 2013-11-07 Binky Moon, LLC
+// management : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/management.html
management
-// mango : 2013-10-24 PUNTO FA S.L.
+// mango : PUNTO FA S.L.
+// https://www.iana.org/domains/root/db/mango.html
mango
-// map : 2016-06-09 Charleston Road Registry Inc.
+// map : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/map.html
map
-// market : 2014-03-06 Dog Beach, LLC
+// market : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/market.html
market
-// marketing : 2013-11-07 Binky Moon, LLC
+// marketing : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/marketing.html
marketing
-// markets : 2014-12-11 Dog Beach, LLC
+// markets : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/markets.html
markets
-// marriott : 2014-10-09 Marriott Worldwide Corporation
+// marriott : Marriott Worldwide Corporation
+// https://www.iana.org/domains/root/db/marriott.html
marriott
-// marshalls : 2015-07-16 The TJX Companies, Inc.
+// marshalls : The TJX Companies, Inc.
+// https://www.iana.org/domains/root/db/marshalls.html
marshalls
-// mattel : 2015-08-06 Mattel Sites, Inc.
+// mattel : Mattel Sites, Inc.
+// https://www.iana.org/domains/root/db/mattel.html
mattel
-// mba : 2015-04-02 Binky Moon, LLC
+// mba : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/mba.html
mba
-// mckinsey : 2015-07-31 McKinsey Holdings, Inc.
+// mckinsey : McKinsey Holdings, Inc.
+// https://www.iana.org/domains/root/db/mckinsey.html
mckinsey
-// med : 2015-08-06 Medistry LLC
+// med : Medistry LLC
+// https://www.iana.org/domains/root/db/med.html
med
-// media : 2014-03-06 Binky Moon, LLC
+// media : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/media.html
media
-// meet : 2014-01-16 Charleston Road Registry Inc.
+// meet : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/meet.html
meet
-// melbourne : 2014-05-29 The Crown in right of the State of Victoria, represented by its Department of State Development, Business and Innovation
+// melbourne : The Crown in right of the State of Victoria, represented by its Department of State Development, Business and Innovation
+// https://www.iana.org/domains/root/db/melbourne.html
melbourne
-// meme : 2014-01-30 Charleston Road Registry Inc.
+// meme : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/meme.html
meme
-// memorial : 2014-10-16 Dog Beach, LLC
+// memorial : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/memorial.html
memorial
-// men : 2015-02-26 Exclusive Registry Limited
+// men : Exclusive Registry Limited
+// https://www.iana.org/domains/root/db/men.html
men
-// menu : 2013-09-11 Dot Menu Registry, LLC
+// menu : Dot Menu Registry, LLC
+// https://www.iana.org/domains/root/db/menu.html
menu
-// merckmsd : 2016-07-14 MSD Registry Holdings, Inc.
+// merckmsd : MSD Registry Holdings, Inc.
+// https://www.iana.org/domains/root/db/merckmsd.html
merckmsd
-// miami : 2013-12-19 Registry Services, LLC
+// miami : Registry Services, LLC
+// https://www.iana.org/domains/root/db/miami.html
miami
-// microsoft : 2014-12-18 Microsoft Corporation
+// microsoft : Microsoft Corporation
+// https://www.iana.org/domains/root/db/microsoft.html
microsoft
-// mini : 2014-01-09 Bayerische Motoren Werke Aktiengesellschaft
+// mini : Bayerische Motoren Werke Aktiengesellschaft
+// https://www.iana.org/domains/root/db/mini.html
mini
-// mint : 2015-07-30 Intuit Administrative Services, Inc.
+// mint : Intuit Administrative Services, Inc.
+// https://www.iana.org/domains/root/db/mint.html
mint
-// mit : 2015-07-02 Massachusetts Institute of Technology
+// mit : Massachusetts Institute of Technology
+// https://www.iana.org/domains/root/db/mit.html
mit
-// mitsubishi : 2015-07-23 Mitsubishi Corporation
+// mitsubishi : Mitsubishi Corporation
+// https://www.iana.org/domains/root/db/mitsubishi.html
mitsubishi
-// mlb : 2015-05-21 MLB Advanced Media DH, LLC
+// mlb : MLB Advanced Media DH, LLC
+// https://www.iana.org/domains/root/db/mlb.html
mlb
-// mls : 2015-04-23 The Canadian Real Estate Association
+// mls : The Canadian Real Estate Association
+// https://www.iana.org/domains/root/db/mls.html
mls
-// mma : 2014-11-07 MMA IARD
+// mma : MMA IARD
+// https://www.iana.org/domains/root/db/mma.html
mma
-// mobile : 2016-06-02 Dish DBS Corporation
+// mobile : Dish DBS Corporation
+// https://www.iana.org/domains/root/db/mobile.html
mobile
-// moda : 2013-11-07 Dog Beach, LLC
+// moda : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/moda.html
moda
-// moe : 2013-11-13 Interlink Systems Innovation Institute K.K.
+// moe : Interlink Systems Innovation Institute K.K.
+// https://www.iana.org/domains/root/db/moe.html
moe
-// moi : 2014-12-18 Amazon Registry Services, Inc.
+// moi : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/moi.html
moi
-// mom : 2015-04-16 XYZ.COM LLC
+// mom : XYZ.COM LLC
+// https://www.iana.org/domains/root/db/mom.html
mom
-// monash : 2013-09-30 Monash University
+// monash : Monash University
+// https://www.iana.org/domains/root/db/monash.html
monash
-// money : 2014-10-16 Binky Moon, LLC
+// money : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/money.html
money
-// monster : 2015-09-11 XYZ.COM LLC
+// monster : XYZ.COM LLC
+// https://www.iana.org/domains/root/db/monster.html
monster
-// mormon : 2013-12-05 IRI Domain Management, LLC
+// mormon : IRI Domain Management, LLC
+// https://www.iana.org/domains/root/db/mormon.html
mormon
-// mortgage : 2014-03-20 Dog Beach, LLC
+// mortgage : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/mortgage.html
mortgage
-// moscow : 2013-12-19 Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID)
+// moscow : Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID)
+// https://www.iana.org/domains/root/db/moscow.html
moscow
-// moto : 2015-06-04 Motorola Trademark Holdings, LLC
+// moto : Motorola Trademark Holdings, LLC
+// https://www.iana.org/domains/root/db/moto.html
moto
-// motorcycles : 2014-01-09 XYZ.COM LLC
+// motorcycles : XYZ.COM LLC
+// https://www.iana.org/domains/root/db/motorcycles.html
motorcycles
-// mov : 2014-01-30 Charleston Road Registry Inc.
+// mov : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/mov.html
mov
-// movie : 2015-02-05 Binky Moon, LLC
+// movie : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/movie.html
movie
-// msd : 2015-07-23 MSD Registry Holdings, Inc.
+// msd : MSD Registry Holdings, Inc.
+// https://www.iana.org/domains/root/db/msd.html
msd
-// mtn : 2014-12-04 MTN Dubai Limited
+// mtn : MTN Dubai Limited
+// https://www.iana.org/domains/root/db/mtn.html
mtn
-// mtr : 2015-03-12 MTR Corporation Limited
+// mtr : MTR Corporation Limited
+// https://www.iana.org/domains/root/db/mtr.html
mtr
-// music : 2021-05-04 DotMusic Limited
+// music : DotMusic Limited
+// https://www.iana.org/domains/root/db/music.html
music
-// mutual : 2015-04-02 Northwestern Mutual MU TLD Registry, LLC
-mutual
-
-// nab : 2015-08-20 National Australia Bank Limited
+// nab : National Australia Bank Limited
+// https://www.iana.org/domains/root/db/nab.html
nab
-// nagoya : 2013-10-24 GMO Registry, Inc.
+// nagoya : GMO Registry, Inc.
+// https://www.iana.org/domains/root/db/nagoya.html
nagoya
-// natura : 2015-03-12 NATURA COSMÉTICOS S.A.
+// natura : NATURA COSMÉTICOS S.A.
+// https://www.iana.org/domains/root/db/natura.html
natura
-// navy : 2014-03-06 Dog Beach, LLC
+// navy : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/navy.html
navy
-// nba : 2015-07-31 NBA REGISTRY, LLC
+// nba : NBA REGISTRY, LLC
+// https://www.iana.org/domains/root/db/nba.html
nba
-// nec : 2015-01-08 NEC Corporation
+// nec : NEC Corporation
+// https://www.iana.org/domains/root/db/nec.html
nec
-// netbank : 2014-06-26 COMMONWEALTH BANK OF AUSTRALIA
+// netbank : COMMONWEALTH BANK OF AUSTRALIA
+// https://www.iana.org/domains/root/db/netbank.html
netbank
-// netflix : 2015-06-18 Netflix, Inc.
+// netflix : Netflix, Inc.
+// https://www.iana.org/domains/root/db/netflix.html
netflix
-// network : 2013-11-14 Binky Moon, LLC
+// network : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/network.html
network
-// neustar : 2013-12-05 NeuStar, Inc.
+// neustar : NeuStar, Inc.
+// https://www.iana.org/domains/root/db/neustar.html
neustar
-// new : 2014-01-30 Charleston Road Registry Inc.
+// new : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/new.html
new
-// news : 2014-12-18 Dog Beach, LLC
+// news : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/news.html
news
-// next : 2015-06-18 Next plc
+// next : Next plc
+// https://www.iana.org/domains/root/db/next.html
next
-// nextdirect : 2015-06-18 Next plc
+// nextdirect : Next plc
+// https://www.iana.org/domains/root/db/nextdirect.html
nextdirect
-// nexus : 2014-07-24 Charleston Road Registry Inc.
+// nexus : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/nexus.html
nexus
-// nfl : 2015-07-23 NFL Reg Ops LLC
+// nfl : NFL Reg Ops LLC
+// https://www.iana.org/domains/root/db/nfl.html
nfl
-// ngo : 2014-03-06 Public Interest Registry
+// ngo : Public Interest Registry
+// https://www.iana.org/domains/root/db/ngo.html
ngo
-// nhk : 2014-02-13 Japan Broadcasting Corporation (NHK)
+// nhk : Japan Broadcasting Corporation (NHK)
+// https://www.iana.org/domains/root/db/nhk.html
nhk
-// nico : 2014-12-04 DWANGO Co., Ltd.
+// nico : DWANGO Co., Ltd.
+// https://www.iana.org/domains/root/db/nico.html
nico
-// nike : 2015-07-23 NIKE, Inc.
+// nike : NIKE, Inc.
+// https://www.iana.org/domains/root/db/nike.html
nike
-// nikon : 2015-05-21 NIKON CORPORATION
+// nikon : NIKON CORPORATION
+// https://www.iana.org/domains/root/db/nikon.html
nikon
-// ninja : 2013-11-07 Dog Beach, LLC
+// ninja : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/ninja.html
ninja
-// nissan : 2014-03-27 NISSAN MOTOR CO., LTD.
+// nissan : NISSAN MOTOR CO., LTD.
+// https://www.iana.org/domains/root/db/nissan.html
nissan
-// nissay : 2015-10-29 Nippon Life Insurance Company
+// nissay : Nippon Life Insurance Company
+// https://www.iana.org/domains/root/db/nissay.html
nissay
-// nokia : 2015-01-08 Nokia Corporation
+// nokia : Nokia Corporation
+// https://www.iana.org/domains/root/db/nokia.html
nokia
-// northwesternmutual : 2015-06-18 Northwestern Mutual Registry, LLC
-northwesternmutual
-
-// norton : 2014-12-04 NortonLifeLock Inc.
+// norton : NortonLifeLock Inc.
+// https://www.iana.org/domains/root/db/norton.html
norton
-// now : 2015-06-25 Amazon Registry Services, Inc.
+// now : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/now.html
now
-// nowruz : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
+// nowruz : Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
+// https://www.iana.org/domains/root/db/nowruz.html
nowruz
-// nowtv : 2015-05-14 Starbucks (HK) Limited
+// nowtv : Starbucks (HK) Limited
+// https://www.iana.org/domains/root/db/nowtv.html
nowtv
-// nra : 2014-05-22 NRA Holdings Company, INC.
+// nra : NRA Holdings Company, INC.
+// https://www.iana.org/domains/root/db/nra.html
nra
-// nrw : 2013-11-21 Minds + Machines GmbH
+// nrw : Minds + Machines GmbH
+// https://www.iana.org/domains/root/db/nrw.html
nrw
-// ntt : 2014-10-31 NIPPON TELEGRAPH AND TELEPHONE CORPORATION
+// ntt : NIPPON TELEGRAPH AND TELEPHONE CORPORATION
+// https://www.iana.org/domains/root/db/ntt.html
ntt
-// nyc : 2014-01-23 The City of New York by and through the New York City Department of Information Technology & Telecommunications
+// nyc : The City of New York by and through the New York City Department of Information Technology & Telecommunications
+// https://www.iana.org/domains/root/db/nyc.html
nyc
-// obi : 2014-09-25 OBI Group Holding SE & Co. KGaA
+// obi : OBI Group Holding SE & Co. KGaA
+// https://www.iana.org/domains/root/db/obi.html
obi
-// observer : 2015-04-30 Dog Beach, LLC
+// observer : Fegistry, LLC
+// https://www.iana.org/domains/root/db/observer.html
observer
-// office : 2015-03-12 Microsoft Corporation
+// office : Microsoft Corporation
+// https://www.iana.org/domains/root/db/office.html
office
-// okinawa : 2013-12-05 BRregistry, Inc.
+// okinawa : BRregistry, Inc.
+// https://www.iana.org/domains/root/db/okinawa.html
okinawa
-// olayan : 2015-05-14 Competrol (Luxembourg) Sarl
+// olayan : Competrol (Luxembourg) Sarl
+// https://www.iana.org/domains/root/db/olayan.html
olayan
-// olayangroup : 2015-05-14 Competrol (Luxembourg) Sarl
+// olayangroup : Competrol (Luxembourg) Sarl
+// https://www.iana.org/domains/root/db/olayangroup.html
olayangroup
-// oldnavy : 2015-07-31 The Gap, Inc.
-oldnavy
-
-// ollo : 2015-06-04 Dish DBS Corporation
+// ollo : Dish DBS Corporation
+// https://www.iana.org/domains/root/db/ollo.html
ollo
-// omega : 2015-01-08 The Swatch Group Ltd
+// omega : The Swatch Group Ltd
+// https://www.iana.org/domains/root/db/omega.html
omega
-// one : 2014-11-07 One.com A/S
+// one : One.com A/S
+// https://www.iana.org/domains/root/db/one.html
one
-// ong : 2014-03-06 Public Interest Registry
+// ong : Public Interest Registry
+// https://www.iana.org/domains/root/db/ong.html
ong
-// onl : 2013-09-16 iRegistry GmbH
+// onl : iRegistry GmbH
+// https://www.iana.org/domains/root/db/onl.html
onl
-// online : 2015-01-15 Radix FZC
+// online : Radix Technologies Inc.
+// https://www.iana.org/domains/root/db/online.html
online
-// ooo : 2014-01-09 INFIBEAM AVENUES LIMITED
+// ooo : INFIBEAM AVENUES LIMITED
+// https://www.iana.org/domains/root/db/ooo.html
ooo
-// open : 2015-07-31 American Express Travel Related Services Company, Inc.
+// open : American Express Travel Related Services Company, Inc.
+// https://www.iana.org/domains/root/db/open.html
open
-// oracle : 2014-06-19 Oracle Corporation
+// oracle : Oracle Corporation
+// https://www.iana.org/domains/root/db/oracle.html
oracle
-// orange : 2015-03-12 Orange Brand Services Limited
+// orange : Orange Brand Services Limited
+// https://www.iana.org/domains/root/db/orange.html
orange
-// organic : 2014-03-27 Identity Digital Limited
+// organic : Identity Digital Limited
+// https://www.iana.org/domains/root/db/organic.html
organic
-// origins : 2015-10-01 The Estée Lauder Companies Inc.
+// origins : The Estée Lauder Companies Inc.
+// https://www.iana.org/domains/root/db/origins.html
origins
-// osaka : 2014-09-04 Osaka Registry Co., Ltd.
+// osaka : Osaka Registry Co., Ltd.
+// https://www.iana.org/domains/root/db/osaka.html
osaka
-// otsuka : 2013-10-11 Otsuka Holdings Co., Ltd.
+// otsuka : Otsuka Holdings Co., Ltd.
+// https://www.iana.org/domains/root/db/otsuka.html
otsuka
-// ott : 2015-06-04 Dish DBS Corporation
+// ott : Dish DBS Corporation
+// https://www.iana.org/domains/root/db/ott.html
ott
-// ovh : 2014-01-16 MédiaBC
+// ovh : MédiaBC
+// https://www.iana.org/domains/root/db/ovh.html
ovh
-// page : 2014-12-04 Charleston Road Registry Inc.
+// page : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/page.html
page
-// panasonic : 2015-07-30 Panasonic Holdings Corporation
+// panasonic : Panasonic Holdings Corporation
+// https://www.iana.org/domains/root/db/panasonic.html
panasonic
-// paris : 2014-01-30 City of Paris
+// paris : City of Paris
+// https://www.iana.org/domains/root/db/paris.html
paris
-// pars : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
+// pars : Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
+// https://www.iana.org/domains/root/db/pars.html
pars
-// partners : 2013-12-05 Binky Moon, LLC
+// partners : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/partners.html
partners
-// parts : 2013-12-05 Binky Moon, LLC
+// parts : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/parts.html
parts
-// party : 2014-09-11 Blue Sky Registry Limited
+// party : Blue Sky Registry Limited
+// https://www.iana.org/domains/root/db/party.html
party
-// passagens : 2015-03-05 Travel Reservations SRL
-passagens
-
-// pay : 2015-08-27 Amazon Registry Services, Inc.
+// pay : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/pay.html
pay
-// pccw : 2015-05-14 PCCW Enterprises Limited
+// pccw : PCCW Enterprises Limited
+// https://www.iana.org/domains/root/db/pccw.html
pccw
-// pet : 2015-05-07 Identity Digital Limited
+// pet : Identity Digital Limited
+// https://www.iana.org/domains/root/db/pet.html
pet
-// pfizer : 2015-09-11 Pfizer Inc.
+// pfizer : Pfizer Inc.
+// https://www.iana.org/domains/root/db/pfizer.html
pfizer
-// pharmacy : 2014-06-19 National Association of Boards of Pharmacy
+// pharmacy : National Association of Boards of Pharmacy
+// https://www.iana.org/domains/root/db/pharmacy.html
pharmacy
-// phd : 2016-07-28 Charleston Road Registry Inc.
+// phd : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/phd.html
phd
-// philips : 2014-11-07 Koninklijke Philips N.V.
+// philips : Koninklijke Philips N.V.
+// https://www.iana.org/domains/root/db/philips.html
philips
-// phone : 2016-06-02 Dish DBS Corporation
+// phone : Dish DBS Corporation
+// https://www.iana.org/domains/root/db/phone.html
phone
-// photo : 2013-11-14 Registry Services, LLC
+// photo : Registry Services, LLC
+// https://www.iana.org/domains/root/db/photo.html
photo
-// photography : 2013-09-20 Binky Moon, LLC
+// photography : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/photography.html
photography
-// photos : 2013-10-17 Binky Moon, LLC
+// photos : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/photos.html
photos
-// physio : 2014-05-01 PhysBiz Pty Ltd
+// physio : PhysBiz Pty Ltd
+// https://www.iana.org/domains/root/db/physio.html
physio
-// pics : 2013-11-14 XYZ.COM LLC
+// pics : XYZ.COM LLC
+// https://www.iana.org/domains/root/db/pics.html
pics
-// pictet : 2014-06-26 Pictet Europe S.A.
+// pictet : Pictet Europe S.A.
+// https://www.iana.org/domains/root/db/pictet.html
pictet
-// pictures : 2014-03-06 Binky Moon, LLC
+// pictures : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/pictures.html
pictures
-// pid : 2015-01-08 Top Level Spectrum, Inc.
+// pid : Top Level Spectrum, Inc.
+// https://www.iana.org/domains/root/db/pid.html
pid
-// pin : 2014-12-18 Amazon Registry Services, Inc.
+// pin : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/pin.html
pin
-// ping : 2015-06-11 Ping Registry Provider, Inc.
+// ping : Ping Registry Provider, Inc.
+// https://www.iana.org/domains/root/db/ping.html
ping
-// pink : 2013-10-01 Identity Digital Limited
+// pink : Identity Digital Limited
+// https://www.iana.org/domains/root/db/pink.html
pink
-// pioneer : 2015-07-16 Pioneer Corporation
+// pioneer : Pioneer Corporation
+// https://www.iana.org/domains/root/db/pioneer.html
pioneer
-// pizza : 2014-06-26 Binky Moon, LLC
+// pizza : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/pizza.html
pizza
-// place : 2014-04-24 Binky Moon, LLC
+// place : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/place.html
place
-// play : 2015-03-05 Charleston Road Registry Inc.
+// play : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/play.html
play
-// playstation : 2015-07-02 Sony Interactive Entertainment Inc.
+// playstation : Sony Interactive Entertainment Inc.
+// https://www.iana.org/domains/root/db/playstation.html
playstation
-// plumbing : 2013-09-10 Binky Moon, LLC
+// plumbing : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/plumbing.html
plumbing
-// plus : 2015-02-05 Binky Moon, LLC
+// plus : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/plus.html
plus
-// pnc : 2015-07-02 PNC Domain Co., LLC
+// pnc : PNC Domain Co., LLC
+// https://www.iana.org/domains/root/db/pnc.html
pnc
-// pohl : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG
+// pohl : Deutsche Vermögensberatung Aktiengesellschaft DVAG
+// https://www.iana.org/domains/root/db/pohl.html
pohl
-// poker : 2014-07-03 Identity Digital Limited
+// poker : Identity Digital Limited
+// https://www.iana.org/domains/root/db/poker.html
poker
-// politie : 2015-08-20 Politie Nederland
+// politie : Politie Nederland
+// https://www.iana.org/domains/root/db/politie.html
politie
-// porn : 2014-10-16 ICM Registry PN LLC
+// porn : ICM Registry PN LLC
+// https://www.iana.org/domains/root/db/porn.html
porn
-// pramerica : 2015-07-30 Prudential Financial, Inc.
+// pramerica : Prudential Financial, Inc.
+// https://www.iana.org/domains/root/db/pramerica.html
pramerica
-// praxi : 2013-12-05 Praxi S.p.A.
+// praxi : Praxi S.p.A.
+// https://www.iana.org/domains/root/db/praxi.html
praxi
-// press : 2014-04-03 Radix FZC
+// press : Radix Technologies Inc.
+// https://www.iana.org/domains/root/db/press.html
press
-// prime : 2015-06-25 Amazon Registry Services, Inc.
+// prime : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/prime.html
prime
-// prod : 2014-01-23 Charleston Road Registry Inc.
+// prod : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/prod.html
prod
-// productions : 2013-12-05 Binky Moon, LLC
+// productions : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/productions.html
productions
-// prof : 2014-07-24 Charleston Road Registry Inc.
+// prof : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/prof.html
prof
-// progressive : 2015-07-23 Progressive Casualty Insurance Company
+// progressive : Progressive Casualty Insurance Company
+// https://www.iana.org/domains/root/db/progressive.html
progressive
-// promo : 2014-12-18 Identity Digital Limited
+// promo : Identity Digital Limited
+// https://www.iana.org/domains/root/db/promo.html
promo
-// properties : 2013-12-05 Binky Moon, LLC
+// properties : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/properties.html
properties
-// property : 2014-05-22 Internet Naming Company LLC
+// property : Digital Property Infrastructure Limited
+// https://www.iana.org/domains/root/db/property.html
property
-// protection : 2015-04-23 XYZ.COM LLC
+// protection : XYZ.COM LLC
+// https://www.iana.org/domains/root/db/protection.html
protection
-// pru : 2015-07-30 Prudential Financial, Inc.
+// pru : Prudential Financial, Inc.
+// https://www.iana.org/domains/root/db/pru.html
pru
-// prudential : 2015-07-30 Prudential Financial, Inc.
+// prudential : Prudential Financial, Inc.
+// https://www.iana.org/domains/root/db/prudential.html
prudential
-// pub : 2013-12-12 Dog Beach, LLC
+// pub : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/pub.html
pub
-// pwc : 2015-10-29 PricewaterhouseCoopers LLP
+// pwc : PricewaterhouseCoopers LLP
+// https://www.iana.org/domains/root/db/pwc.html
pwc
-// qpon : 2013-11-14 dotQPON LLC
+// qpon : dotQPON LLC
+// https://www.iana.org/domains/root/db/qpon.html
qpon
-// quebec : 2013-12-19 PointQuébec Inc
+// quebec : PointQuébec Inc
+// https://www.iana.org/domains/root/db/quebec.html
quebec
-// quest : 2015-03-26 XYZ.COM LLC
+// quest : XYZ.COM LLC
+// https://www.iana.org/domains/root/db/quest.html
quest
-// racing : 2014-12-04 Premier Registry Limited
+// racing : Premier Registry Limited
+// https://www.iana.org/domains/root/db/racing.html
racing
-// radio : 2016-07-21 European Broadcasting Union (EBU)
+// radio : European Broadcasting Union (EBU)
+// https://www.iana.org/domains/root/db/radio.html
radio
-// read : 2014-12-18 Amazon Registry Services, Inc.
+// read : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/read.html
read
-// realestate : 2015-09-11 dotRealEstate LLC
+// realestate : dotRealEstate LLC
+// https://www.iana.org/domains/root/db/realestate.html
realestate
-// realtor : 2014-05-29 Real Estate Domains LLC
+// realtor : Real Estate Domains LLC
+// https://www.iana.org/domains/root/db/realtor.html
realtor
-// realty : 2015-03-19 Dog Beach, LLC
+// realty : Internet Naming Company LLC
+// https://www.iana.org/domains/root/db/realty.html
realty
-// recipes : 2013-10-17 Binky Moon, LLC
+// recipes : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/recipes.html
recipes
-// red : 2013-11-07 Identity Digital Limited
+// red : Identity Digital Limited
+// https://www.iana.org/domains/root/db/red.html
red
-// redstone : 2014-10-31 Redstone Haute Couture Co., Ltd.
+// redstone : Redstone Haute Couture Co., Ltd.
+// https://www.iana.org/domains/root/db/redstone.html
redstone
-// redumbrella : 2015-03-26 Travelers TLD, LLC
+// redumbrella : Travelers TLD, LLC
+// https://www.iana.org/domains/root/db/redumbrella.html
redumbrella
-// rehab : 2014-03-06 Dog Beach, LLC
+// rehab : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/rehab.html
rehab
-// reise : 2014-03-13 Binky Moon, LLC
+// reise : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/reise.html
reise
-// reisen : 2014-03-06 Binky Moon, LLC
+// reisen : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/reisen.html
reisen
-// reit : 2014-09-04 National Association of Real Estate Investment Trusts, Inc.
+// reit : National Association of Real Estate Investment Trusts, Inc.
+// https://www.iana.org/domains/root/db/reit.html
reit
-// reliance : 2015-04-02 Reliance Industries Limited
+// reliance : Reliance Industries Limited
+// https://www.iana.org/domains/root/db/reliance.html
reliance
-// ren : 2013-12-12 ZDNS International Limited
+// ren : ZDNS International Limited
+// https://www.iana.org/domains/root/db/ren.html
ren
-// rent : 2014-12-04 XYZ.COM LLC
+// rent : XYZ.COM LLC
+// https://www.iana.org/domains/root/db/rent.html
rent
-// rentals : 2013-12-05 Binky Moon, LLC
+// rentals : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/rentals.html
rentals
-// repair : 2013-11-07 Binky Moon, LLC
+// repair : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/repair.html
repair
-// report : 2013-12-05 Binky Moon, LLC
+// report : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/report.html
report
-// republican : 2014-03-20 Dog Beach, LLC
+// republican : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/republican.html
republican
-// rest : 2013-12-19 Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable
+// rest : Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable
+// https://www.iana.org/domains/root/db/rest.html
rest
-// restaurant : 2014-07-03 Binky Moon, LLC
+// restaurant : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/restaurant.html
restaurant
-// review : 2014-11-20 dot Review Limited
+// review : dot Review Limited
+// https://www.iana.org/domains/root/db/review.html
review
-// reviews : 2013-09-13 Dog Beach, LLC
+// reviews : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/reviews.html
reviews
-// rexroth : 2015-06-18 Robert Bosch GMBH
+// rexroth : Robert Bosch GMBH
+// https://www.iana.org/domains/root/db/rexroth.html
rexroth
-// rich : 2013-11-21 iRegistry GmbH
+// rich : iRegistry GmbH
+// https://www.iana.org/domains/root/db/rich.html
rich
-// richardli : 2015-05-14 Pacific Century Asset Management (HK) Limited
+// richardli : Pacific Century Asset Management (HK) Limited
+// https://www.iana.org/domains/root/db/richardli.html
richardli
-// ricoh : 2014-11-20 Ricoh Company, Ltd.
+// ricoh : Ricoh Company, Ltd.
+// https://www.iana.org/domains/root/db/ricoh.html
ricoh
-// ril : 2015-04-02 Reliance Industries Limited
+// ril : Reliance Industries Limited
+// https://www.iana.org/domains/root/db/ril.html
ril
-// rio : 2014-02-27 Empresa Municipal de Informática SA - IPLANRIO
+// rio : Empresa Municipal de Informática SA - IPLANRIO
+// https://www.iana.org/domains/root/db/rio.html
rio
-// rip : 2014-07-10 Dog Beach, LLC
+// rip : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/rip.html
rip
-// rocher : 2014-12-18 Ferrero Trading Lux S.A.
-rocher
-
-// rocks : 2013-11-14 Dog Beach, LLC
+// rocks : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/rocks.html
rocks
-// rodeo : 2013-12-19 Registry Services, LLC
+// rodeo : Registry Services, LLC
+// https://www.iana.org/domains/root/db/rodeo.html
rodeo
-// rogers : 2015-08-06 Rogers Communications Canada Inc.
+// rogers : Rogers Communications Canada Inc.
+// https://www.iana.org/domains/root/db/rogers.html
rogers
-// room : 2014-12-18 Amazon Registry Services, Inc.
+// room : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/room.html
room
-// rsvp : 2014-05-08 Charleston Road Registry Inc.
+// rsvp : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/rsvp.html
rsvp
-// rugby : 2016-12-15 World Rugby Strategic Developments Limited
+// rugby : World Rugby Strategic Developments Limited
+// https://www.iana.org/domains/root/db/rugby.html
rugby
-// ruhr : 2013-10-02 dotSaarland GmbH
+// ruhr : dotSaarland GmbH
+// https://www.iana.org/domains/root/db/ruhr.html
ruhr
-// run : 2015-03-19 Binky Moon, LLC
+// run : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/run.html
run
-// rwe : 2015-04-02 RWE AG
+// rwe : RWE AG
+// https://www.iana.org/domains/root/db/rwe.html
rwe
-// ryukyu : 2014-01-09 BRregistry, Inc.
+// ryukyu : BRregistry, Inc.
+// https://www.iana.org/domains/root/db/ryukyu.html
ryukyu
-// saarland : 2013-12-12 dotSaarland GmbH
+// saarland : dotSaarland GmbH
+// https://www.iana.org/domains/root/db/saarland.html
saarland
-// safe : 2014-12-18 Amazon Registry Services, Inc.
+// safe : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/safe.html
safe
-// safety : 2015-01-08 Safety Registry Services, LLC.
+// safety : Safety Registry Services, LLC.
+// https://www.iana.org/domains/root/db/safety.html
safety
-// sakura : 2014-12-18 SAKURA Internet Inc.
+// sakura : SAKURA Internet Inc.
+// https://www.iana.org/domains/root/db/sakura.html
sakura
-// sale : 2014-10-16 Dog Beach, LLC
+// sale : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/sale.html
sale
-// salon : 2014-12-11 Binky Moon, LLC
+// salon : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/salon.html
salon
-// samsclub : 2015-07-31 Wal-Mart Stores, Inc.
+// samsclub : Wal-Mart Stores, Inc.
+// https://www.iana.org/domains/root/db/samsclub.html
samsclub
-// samsung : 2014-04-03 SAMSUNG SDS CO., LTD
+// samsung : SAMSUNG SDS CO., LTD
+// https://www.iana.org/domains/root/db/samsung.html
samsung
-// sandvik : 2014-11-13 Sandvik AB
+// sandvik : Sandvik AB
+// https://www.iana.org/domains/root/db/sandvik.html
sandvik
-// sandvikcoromant : 2014-11-07 Sandvik AB
+// sandvikcoromant : Sandvik AB
+// https://www.iana.org/domains/root/db/sandvikcoromant.html
sandvikcoromant
-// sanofi : 2014-10-09 Sanofi
+// sanofi : Sanofi
+// https://www.iana.org/domains/root/db/sanofi.html
sanofi
-// sap : 2014-03-27 SAP AG
+// sap : SAP AG
+// https://www.iana.org/domains/root/db/sap.html
sap
-// sarl : 2014-07-03 Binky Moon, LLC
+// sarl : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/sarl.html
sarl
-// sas : 2015-04-02 Research IP LLC
+// sas : Research IP LLC
+// https://www.iana.org/domains/root/db/sas.html
sas
-// save : 2015-06-25 Amazon Registry Services, Inc.
+// save : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/save.html
save
-// saxo : 2014-10-31 Saxo Bank A/S
+// saxo : Saxo Bank A/S
+// https://www.iana.org/domains/root/db/saxo.html
saxo
-// sbi : 2015-03-12 STATE BANK OF INDIA
+// sbi : STATE BANK OF INDIA
+// https://www.iana.org/domains/root/db/sbi.html
sbi
-// sbs : 2014-11-07 ShortDot SA
+// sbs : ShortDot SA
+// https://www.iana.org/domains/root/db/sbs.html
sbs
-// sca : 2014-03-13 SVENSKA CELLULOSA AKTIEBOLAGET SCA (publ)
-sca
-
-// scb : 2014-02-20 The Siam Commercial Bank Public Company Limited ("SCB")
+// scb : The Siam Commercial Bank Public Company Limited ("SCB")
+// https://www.iana.org/domains/root/db/scb.html
scb
-// schaeffler : 2015-08-06 Schaeffler Technologies AG & Co. KG
+// schaeffler : Schaeffler Technologies AG & Co. KG
+// https://www.iana.org/domains/root/db/schaeffler.html
schaeffler
-// schmidt : 2014-04-03 SCHMIDT GROUPE S.A.S.
+// schmidt : SCHMIDT GROUPE S.A.S.
+// https://www.iana.org/domains/root/db/schmidt.html
schmidt
-// scholarships : 2014-04-24 Scholarships.com, LLC
+// scholarships : Scholarships.com, LLC
+// https://www.iana.org/domains/root/db/scholarships.html
scholarships
-// school : 2014-12-18 Binky Moon, LLC
+// school : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/school.html
school
-// schule : 2014-03-06 Binky Moon, LLC
+// schule : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/schule.html
schule
-// schwarz : 2014-09-18 Schwarz Domains und Services GmbH & Co. KG
+// schwarz : Schwarz Domains und Services GmbH & Co. KG
+// https://www.iana.org/domains/root/db/schwarz.html
schwarz
-// science : 2014-09-11 dot Science Limited
+// science : dot Science Limited
+// https://www.iana.org/domains/root/db/science.html
science
-// scot : 2014-01-23 Dot Scot Registry Limited
+// scot : Dot Scot Registry Limited
+// https://www.iana.org/domains/root/db/scot.html
scot
-// search : 2016-06-09 Charleston Road Registry Inc.
+// search : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/search.html
search
-// seat : 2014-05-22 SEAT, S.A. (Sociedad Unipersonal)
+// seat : SEAT, S.A. (Sociedad Unipersonal)
+// https://www.iana.org/domains/root/db/seat.html
seat
-// secure : 2015-08-27 Amazon Registry Services, Inc.
+// secure : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/secure.html
secure
-// security : 2015-05-14 XYZ.COM LLC
+// security : XYZ.COM LLC
+// https://www.iana.org/domains/root/db/security.html
security
-// seek : 2014-12-04 Seek Limited
+// seek : Seek Limited
+// https://www.iana.org/domains/root/db/seek.html
seek
-// select : 2015-10-08 Registry Services, LLC
+// select : Registry Services, LLC
+// https://www.iana.org/domains/root/db/select.html
select
-// sener : 2014-10-24 Sener Ingeniería y Sistemas, S.A.
+// sener : Sener Ingeniería y Sistemas, S.A.
+// https://www.iana.org/domains/root/db/sener.html
sener
-// services : 2014-02-27 Binky Moon, LLC
+// services : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/services.html
services
-// seven : 2015-08-06 Seven West Media Ltd
+// seven : Seven West Media Ltd
+// https://www.iana.org/domains/root/db/seven.html
seven
-// sew : 2014-07-17 SEW-EURODRIVE GmbH & Co KG
+// sew : SEW-EURODRIVE GmbH & Co KG
+// https://www.iana.org/domains/root/db/sew.html
sew
-// sex : 2014-11-13 ICM Registry SX LLC
+// sex : ICM Registry SX LLC
+// https://www.iana.org/domains/root/db/sex.html
sex
-// sexy : 2013-09-11 Internet Naming Company LLC
+// sexy : Internet Naming Company LLC
+// https://www.iana.org/domains/root/db/sexy.html
sexy
-// sfr : 2015-08-13 Societe Francaise du Radiotelephone - SFR
+// sfr : Societe Francaise du Radiotelephone - SFR
+// https://www.iana.org/domains/root/db/sfr.html
sfr
-// shangrila : 2015-09-03 Shangri‐La International Hotel Management Limited
+// shangrila : Shangri‐La International Hotel Management Limited
+// https://www.iana.org/domains/root/db/shangrila.html
shangrila
-// sharp : 2014-05-01 Sharp Corporation
+// sharp : Sharp Corporation
+// https://www.iana.org/domains/root/db/sharp.html
sharp
-// shaw : 2015-04-23 Shaw Cablesystems G.P.
+// shaw : Shaw Cablesystems G.P.
+// https://www.iana.org/domains/root/db/shaw.html
shaw
-// shell : 2015-07-30 Shell Information Technology International Inc
+// shell : Shell Information Technology International Inc
+// https://www.iana.org/domains/root/db/shell.html
shell
-// shia : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
+// shia : Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
+// https://www.iana.org/domains/root/db/shia.html
shia
-// shiksha : 2013-11-14 Identity Digital Limited
+// shiksha : Identity Digital Limited
+// https://www.iana.org/domains/root/db/shiksha.html
shiksha
-// shoes : 2013-10-02 Binky Moon, LLC
+// shoes : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/shoes.html
shoes
-// shop : 2016-04-08 GMO Registry, Inc.
+// shop : GMO Registry, Inc.
+// https://www.iana.org/domains/root/db/shop.html
shop
-// shopping : 2016-03-31 Binky Moon, LLC
+// shopping : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/shopping.html
shopping
-// shouji : 2015-01-08 Beijing Qihu Keji Co., Ltd.
+// shouji : Beijing Qihu Keji Co., Ltd.
+// https://www.iana.org/domains/root/db/shouji.html
shouji
-// show : 2015-03-05 Binky Moon, LLC
+// show : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/show.html
show
-// showtime : 2015-08-06 CBS Domains Inc.
-showtime
-
-// silk : 2015-06-25 Amazon Registry Services, Inc.
+// silk : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/silk.html
silk
-// sina : 2015-03-12 Sina Corporation
+// sina : Sina Corporation
+// https://www.iana.org/domains/root/db/sina.html
sina
-// singles : 2013-08-27 Binky Moon, LLC
+// singles : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/singles.html
singles
-// site : 2015-01-15 Radix FZC
+// site : Radix Technologies Inc.
+// https://www.iana.org/domains/root/db/site.html
site
-// ski : 2015-04-09 Identity Digital Limited
+// ski : Identity Digital Limited
+// https://www.iana.org/domains/root/db/ski.html
ski
-// skin : 2015-01-15 XYZ.COM LLC
+// skin : XYZ.COM LLC
+// https://www.iana.org/domains/root/db/skin.html
skin
-// sky : 2014-06-19 Sky International AG
+// sky : Sky International AG
+// https://www.iana.org/domains/root/db/sky.html
sky
-// skype : 2014-12-18 Microsoft Corporation
+// skype : Microsoft Corporation
+// https://www.iana.org/domains/root/db/skype.html
skype
-// sling : 2015-07-30 DISH Technologies L.L.C.
+// sling : DISH Technologies L.L.C.
+// https://www.iana.org/domains/root/db/sling.html
sling
-// smart : 2015-07-09 Smart Communications, Inc. (SMART)
+// smart : Smart Communications, Inc. (SMART)
+// https://www.iana.org/domains/root/db/smart.html
smart
-// smile : 2014-12-18 Amazon Registry Services, Inc.
+// smile : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/smile.html
smile
-// sncf : 2015-02-19 Société Nationale SNCF
+// sncf : Société Nationale SNCF
+// https://www.iana.org/domains/root/db/sncf.html
sncf
-// soccer : 2015-03-26 Binky Moon, LLC
+// soccer : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/soccer.html
soccer
-// social : 2013-11-07 Dog Beach, LLC
+// social : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/social.html
social
-// softbank : 2015-07-02 SoftBank Group Corp.
+// softbank : SoftBank Group Corp.
+// https://www.iana.org/domains/root/db/softbank.html
softbank
-// software : 2014-03-20 Dog Beach, LLC
+// software : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/software.html
software
-// sohu : 2013-12-19 Sohu.com Limited
+// sohu : Sohu.com Limited
+// https://www.iana.org/domains/root/db/sohu.html
sohu
-// solar : 2013-11-07 Binky Moon, LLC
+// solar : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/solar.html
solar
-// solutions : 2013-11-07 Binky Moon, LLC
+// solutions : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/solutions.html
solutions
-// song : 2015-02-26 Amazon Registry Services, Inc.
+// song : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/song.html
song
-// sony : 2015-01-08 Sony Corporation
+// sony : Sony Corporation
+// https://www.iana.org/domains/root/db/sony.html
sony
-// soy : 2014-01-23 Charleston Road Registry Inc.
+// soy : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/soy.html
soy
-// spa : 2019-09-19 Asia Spa and Wellness Promotion Council Limited
+// spa : Asia Spa and Wellness Promotion Council Limited
+// https://www.iana.org/domains/root/db/spa.html
spa
-// space : 2014-04-03 Radix FZC
+// space : Radix Technologies Inc.
+// https://www.iana.org/domains/root/db/space.html
space
-// sport : 2017-11-16 Global Association of International Sports Federations (GAISF)
+// sport : SportAccord
+// https://www.iana.org/domains/root/db/sport.html
sport
-// spot : 2015-02-26 Amazon Registry Services, Inc.
+// spot : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/spot.html
spot
-// srl : 2015-05-07 InterNetX, Corp
+// srl : InterNetX, Corp
+// https://www.iana.org/domains/root/db/srl.html
srl
-// stada : 2014-11-13 STADA Arzneimittel AG
+// stada : STADA Arzneimittel AG
+// https://www.iana.org/domains/root/db/stada.html
stada
-// staples : 2015-07-30 Staples, Inc.
+// staples : Staples, Inc.
+// https://www.iana.org/domains/root/db/staples.html
staples
-// star : 2015-01-08 Star India Private Limited
+// star : Star India Private Limited
+// https://www.iana.org/domains/root/db/star.html
star
-// statebank : 2015-03-12 STATE BANK OF INDIA
+// statebank : STATE BANK OF INDIA
+// https://www.iana.org/domains/root/db/statebank.html
statebank
-// statefarm : 2015-07-30 State Farm Mutual Automobile Insurance Company
+// statefarm : State Farm Mutual Automobile Insurance Company
+// https://www.iana.org/domains/root/db/statefarm.html
statefarm
-// stc : 2014-10-09 Saudi Telecom Company
+// stc : Saudi Telecom Company
+// https://www.iana.org/domains/root/db/stc.html
stc
-// stcgroup : 2014-10-09 Saudi Telecom Company
+// stcgroup : Saudi Telecom Company
+// https://www.iana.org/domains/root/db/stcgroup.html
stcgroup
-// stockholm : 2014-12-18 Stockholms kommun
+// stockholm : Stockholms kommun
+// https://www.iana.org/domains/root/db/stockholm.html
stockholm
-// storage : 2014-12-22 XYZ.COM LLC
+// storage : XYZ.COM LLC
+// https://www.iana.org/domains/root/db/storage.html
storage
-// store : 2015-04-09 Radix FZC
+// store : Radix Technologies Inc.
+// https://www.iana.org/domains/root/db/store.html
store
-// stream : 2016-01-08 dot Stream Limited
+// stream : dot Stream Limited
+// https://www.iana.org/domains/root/db/stream.html
stream
-// studio : 2015-02-11 Dog Beach, LLC
+// studio : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/studio.html
studio
-// study : 2014-12-11 Registry Services, LLC
+// study : Registry Services, LLC
+// https://www.iana.org/domains/root/db/study.html
study
-// style : 2014-12-04 Binky Moon, LLC
+// style : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/style.html
style
-// sucks : 2014-12-22 Vox Populi Registry Ltd.
+// sucks : Vox Populi Registry Ltd.
+// https://www.iana.org/domains/root/db/sucks.html
sucks
-// supplies : 2013-12-19 Binky Moon, LLC
+// supplies : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/supplies.html
supplies
-// supply : 2013-12-19 Binky Moon, LLC
+// supply : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/supply.html
supply
-// support : 2013-10-24 Binky Moon, LLC
+// support : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/support.html
support
-// surf : 2014-01-09 Registry Services, LLC
+// surf : Registry Services, LLC
+// https://www.iana.org/domains/root/db/surf.html
surf
-// surgery : 2014-03-20 Binky Moon, LLC
+// surgery : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/surgery.html
surgery
-// suzuki : 2014-02-20 SUZUKI MOTOR CORPORATION
+// suzuki : SUZUKI MOTOR CORPORATION
+// https://www.iana.org/domains/root/db/suzuki.html
suzuki
-// swatch : 2015-01-08 The Swatch Group Ltd
+// swatch : The Swatch Group Ltd
+// https://www.iana.org/domains/root/db/swatch.html
swatch
-// swiss : 2014-10-16 Swiss Confederation
+// swiss : Swiss Confederation
+// https://www.iana.org/domains/root/db/swiss.html
swiss
-// sydney : 2014-09-18 State of New South Wales, Department of Premier and Cabinet
+// sydney : State of New South Wales, Department of Premier and Cabinet
+// https://www.iana.org/domains/root/db/sydney.html
sydney
-// systems : 2013-11-07 Binky Moon, LLC
+// systems : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/systems.html
systems
-// tab : 2014-12-04 Tabcorp Holdings Limited
+// tab : Tabcorp Holdings Limited
+// https://www.iana.org/domains/root/db/tab.html
tab
-// taipei : 2014-07-10 Taipei City Government
+// taipei : Taipei City Government
+// https://www.iana.org/domains/root/db/taipei.html
taipei
-// talk : 2015-04-09 Amazon Registry Services, Inc.
+// talk : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/talk.html
talk
-// taobao : 2015-01-15 Alibaba Group Holding Limited
+// taobao : Alibaba Group Holding Limited
+// https://www.iana.org/domains/root/db/taobao.html
taobao
-// target : 2015-07-31 Target Domain Holdings, LLC
+// target : Target Domain Holdings, LLC
+// https://www.iana.org/domains/root/db/target.html
target
-// tatamotors : 2015-03-12 Tata Motors Ltd
+// tatamotors : Tata Motors Ltd
+// https://www.iana.org/domains/root/db/tatamotors.html
tatamotors
-// tatar : 2014-04-24 Limited Liability Company "Coordination Center of Regional Domain of Tatarstan Republic"
+// tatar : Limited Liability Company "Coordination Center of Regional Domain of Tatarstan Republic"
+// https://www.iana.org/domains/root/db/tatar.html
tatar
-// tattoo : 2013-08-30 Registry Services, LLC
+// tattoo : Registry Services, LLC
+// https://www.iana.org/domains/root/db/tattoo.html
tattoo
-// tax : 2014-03-20 Binky Moon, LLC
+// tax : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/tax.html
tax
-// taxi : 2015-03-19 Binky Moon, LLC
+// taxi : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/taxi.html
taxi
-// tci : 2014-09-12 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
+// tci : Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
+// https://www.iana.org/domains/root/db/tci.html
tci
-// tdk : 2015-06-11 TDK Corporation
+// tdk : TDK Corporation
+// https://www.iana.org/domains/root/db/tdk.html
tdk
-// team : 2015-03-05 Binky Moon, LLC
+// team : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/team.html
team
-// tech : 2015-01-30 Radix FZC
+// tech : Radix Technologies Inc.
+// https://www.iana.org/domains/root/db/tech.html
tech
-// technology : 2013-09-13 Binky Moon, LLC
+// technology : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/technology.html
technology
-// temasek : 2014-08-07 Temasek Holdings (Private) Limited
+// temasek : Temasek Holdings (Private) Limited
+// https://www.iana.org/domains/root/db/temasek.html
temasek
-// tennis : 2014-12-04 Binky Moon, LLC
+// tennis : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/tennis.html
tennis
-// teva : 2015-07-02 Teva Pharmaceutical Industries Limited
+// teva : Teva Pharmaceutical Industries Limited
+// https://www.iana.org/domains/root/db/teva.html
teva
-// thd : 2015-04-02 Home Depot Product Authority, LLC
+// thd : Home Depot Product Authority, LLC
+// https://www.iana.org/domains/root/db/thd.html
thd
-// theater : 2015-03-19 Binky Moon, LLC
+// theater : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/theater.html
theater
-// theatre : 2015-05-07 XYZ.COM LLC
+// theatre : XYZ.COM LLC
+// https://www.iana.org/domains/root/db/theatre.html
theatre
-// tiaa : 2015-07-23 Teachers Insurance and Annuity Association of America
+// tiaa : Teachers Insurance and Annuity Association of America
+// https://www.iana.org/domains/root/db/tiaa.html
tiaa
-// tickets : 2015-02-05 XYZ.COM LLC
+// tickets : XYZ.COM LLC
+// https://www.iana.org/domains/root/db/tickets.html
tickets
-// tienda : 2013-11-14 Binky Moon, LLC
+// tienda : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/tienda.html
tienda
-// tiffany : 2015-01-30 Tiffany and Company
-tiffany
-
-// tips : 2013-09-20 Binky Moon, LLC
+// tips : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/tips.html
tips
-// tires : 2014-11-07 Binky Moon, LLC
+// tires : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/tires.html
tires
-// tirol : 2014-04-24 punkt Tirol GmbH
+// tirol : punkt Tirol GmbH
+// https://www.iana.org/domains/root/db/tirol.html
tirol
-// tjmaxx : 2015-07-16 The TJX Companies, Inc.
+// tjmaxx : The TJX Companies, Inc.
+// https://www.iana.org/domains/root/db/tjmaxx.html
tjmaxx
-// tjx : 2015-07-16 The TJX Companies, Inc.
+// tjx : The TJX Companies, Inc.
+// https://www.iana.org/domains/root/db/tjx.html
tjx
-// tkmaxx : 2015-07-16 The TJX Companies, Inc.
+// tkmaxx : The TJX Companies, Inc.
+// https://www.iana.org/domains/root/db/tkmaxx.html
tkmaxx
-// tmall : 2015-01-15 Alibaba Group Holding Limited
+// tmall : Alibaba Group Holding Limited
+// https://www.iana.org/domains/root/db/tmall.html
tmall
-// today : 2013-09-20 Binky Moon, LLC
+// today : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/today.html
today
-// tokyo : 2013-11-13 GMO Registry, Inc.
+// tokyo : GMO Registry, Inc.
+// https://www.iana.org/domains/root/db/tokyo.html
tokyo
-// tools : 2013-11-21 Binky Moon, LLC
+// tools : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/tools.html
tools
-// top : 2014-03-20 .TOP Registry
+// top : .TOP Registry
+// https://www.iana.org/domains/root/db/top.html
top
-// toray : 2014-12-18 Toray Industries, Inc.
+// toray : Toray Industries, Inc.
+// https://www.iana.org/domains/root/db/toray.html
toray
-// toshiba : 2014-04-10 TOSHIBA Corporation
+// toshiba : TOSHIBA Corporation
+// https://www.iana.org/domains/root/db/toshiba.html
toshiba
-// total : 2015-08-06 TotalEnergies SE
+// total : TotalEnergies SE
+// https://www.iana.org/domains/root/db/total.html
total
-// tours : 2015-01-22 Binky Moon, LLC
+// tours : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/tours.html
tours
-// town : 2014-03-06 Binky Moon, LLC
+// town : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/town.html
town
-// toyota : 2015-04-23 TOYOTA MOTOR CORPORATION
+// toyota : TOYOTA MOTOR CORPORATION
+// https://www.iana.org/domains/root/db/toyota.html
toyota
-// toys : 2014-03-06 Binky Moon, LLC
+// toys : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/toys.html
toys
-// trade : 2014-01-23 Elite Registry Limited
+// trade : Elite Registry Limited
+// https://www.iana.org/domains/root/db/trade.html
trade
-// trading : 2014-12-11 Dog Beach, LLC
+// trading : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/trading.html
trading
-// training : 2013-11-07 Binky Moon, LLC
+// training : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/training.html
training
-// travel : 2015-10-09 Dog Beach, LLC
+// travel : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/travel.html
travel
-// travelers : 2015-03-26 Travelers TLD, LLC
+// travelers : Travelers TLD, LLC
+// https://www.iana.org/domains/root/db/travelers.html
travelers
-// travelersinsurance : 2015-03-26 Travelers TLD, LLC
+// travelersinsurance : Travelers TLD, LLC
+// https://www.iana.org/domains/root/db/travelersinsurance.html
travelersinsurance
-// trust : 2014-10-16 Internet Naming Company LLC
+// trust : Internet Naming Company LLC
+// https://www.iana.org/domains/root/db/trust.html
trust
-// trv : 2015-03-26 Travelers TLD, LLC
+// trv : Travelers TLD, LLC
+// https://www.iana.org/domains/root/db/trv.html
trv
-// tube : 2015-06-11 Latin American Telecom LLC
+// tube : Latin American Telecom LLC
+// https://www.iana.org/domains/root/db/tube.html
tube
-// tui : 2014-07-03 TUI AG
+// tui : TUI AG
+// https://www.iana.org/domains/root/db/tui.html
tui
-// tunes : 2015-02-26 Amazon Registry Services, Inc.
+// tunes : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/tunes.html
tunes
-// tushu : 2014-12-18 Amazon Registry Services, Inc.
+// tushu : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/tushu.html
tushu
-// tvs : 2015-02-19 T V SUNDRAM IYENGAR & SONS LIMITED
+// tvs : T V SUNDRAM IYENGAR & SONS LIMITED
+// https://www.iana.org/domains/root/db/tvs.html
tvs
-// ubank : 2015-08-20 National Australia Bank Limited
+// ubank : National Australia Bank Limited
+// https://www.iana.org/domains/root/db/ubank.html
ubank
-// ubs : 2014-12-11 UBS AG
+// ubs : UBS AG
+// https://www.iana.org/domains/root/db/ubs.html
ubs
-// unicom : 2015-10-15 China United Network Communications Corporation Limited
+// unicom : China United Network Communications Corporation Limited
+// https://www.iana.org/domains/root/db/unicom.html
unicom
-// university : 2014-03-06 Binky Moon, LLC
+// university : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/university.html
university
-// uno : 2013-09-11 Radix FZC
+// uno : Radix Technologies Inc.
+// https://www.iana.org/domains/root/db/uno.html
uno
-// uol : 2014-05-01 UBN INTERNET LTDA.
+// uol : UBN INTERNET LTDA.
+// https://www.iana.org/domains/root/db/uol.html
uol
-// ups : 2015-06-25 UPS Market Driver, Inc.
+// ups : UPS Market Driver, Inc.
+// https://www.iana.org/domains/root/db/ups.html
ups
-// vacations : 2013-12-05 Binky Moon, LLC
+// vacations : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/vacations.html
vacations
-// vana : 2014-12-11 Lifestyle Domain Holdings, Inc.
+// vana : Internet Naming Company LLC
+// https://www.iana.org/domains/root/db/vana.html
vana
-// vanguard : 2015-09-03 The Vanguard Group, Inc.
+// vanguard : The Vanguard Group, Inc.
+// https://www.iana.org/domains/root/db/vanguard.html
vanguard
-// vegas : 2014-01-16 Dot Vegas, Inc.
+// vegas : Dot Vegas, Inc.
+// https://www.iana.org/domains/root/db/vegas.html
vegas
-// ventures : 2013-08-27 Binky Moon, LLC
+// ventures : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/ventures.html
ventures
-// verisign : 2015-08-13 VeriSign, Inc.
+// verisign : VeriSign, Inc.
+// https://www.iana.org/domains/root/db/verisign.html
verisign
-// versicherung : 2014-03-20 tldbox GmbH
+// versicherung : tldbox GmbH
+// https://www.iana.org/domains/root/db/versicherung.html
versicherung
-// vet : 2014-03-06 Dog Beach, LLC
+// vet : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/vet.html
vet
-// viajes : 2013-10-17 Binky Moon, LLC
+// viajes : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/viajes.html
viajes
-// video : 2014-10-16 Dog Beach, LLC
+// video : Dog Beach, LLC
+// https://www.iana.org/domains/root/db/video.html
video
-// vig : 2015-05-14 VIENNA INSURANCE GROUP AG Wiener Versicherung Gruppe
+// vig : VIENNA INSURANCE GROUP AG Wiener Versicherung Gruppe
+// https://www.iana.org/domains/root/db/vig.html
vig
-// viking : 2015-04-02 Viking River Cruises (Bermuda) Ltd.
+// viking : Viking River Cruises (Bermuda) Ltd.
+// https://www.iana.org/domains/root/db/viking.html
viking
-// villas : 2013-12-05 Binky Moon, LLC
+// villas : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/villas.html
villas
-// vin : 2015-06-18 Binky Moon, LLC
+// vin : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/vin.html
vin
-// vip : 2015-01-22 Registry Services, LLC
+// vip : Registry Services, LLC
+// https://www.iana.org/domains/root/db/vip.html
vip
-// virgin : 2014-09-25 Virgin Enterprises Limited
+// virgin : Virgin Enterprises Limited
+// https://www.iana.org/domains/root/db/virgin.html
virgin
-// visa : 2015-07-30 Visa Worldwide Pte. Limited
+// visa : Visa Worldwide Pte. Limited
+// https://www.iana.org/domains/root/db/visa.html
visa
-// vision : 2013-12-05 Binky Moon, LLC
+// vision : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/vision.html
vision
-// viva : 2014-11-07 Saudi Telecom Company
+// viva : Saudi Telecom Company
+// https://www.iana.org/domains/root/db/viva.html
viva
-// vivo : 2015-07-31 Telefonica Brasil S.A.
+// vivo : Telefonica Brasil S.A.
+// https://www.iana.org/domains/root/db/vivo.html
vivo
-// vlaanderen : 2014-02-06 DNS.be vzw
+// vlaanderen : DNS.be vzw
+// https://www.iana.org/domains/root/db/vlaanderen.html
vlaanderen
-// vodka : 2013-12-19 Registry Services, LLC
+// vodka : Registry Services, LLC
+// https://www.iana.org/domains/root/db/vodka.html
vodka
-// volkswagen : 2015-05-14 Volkswagen Group of America Inc.
-volkswagen
-
-// volvo : 2015-11-12 Volvo Holding Sverige Aktiebolag
+// volvo : Volvo Holding Sverige Aktiebolag
+// https://www.iana.org/domains/root/db/volvo.html
volvo
-// vote : 2013-11-21 Monolith Registry LLC
+// vote : Monolith Registry LLC
+// https://www.iana.org/domains/root/db/vote.html
vote
-// voting : 2013-11-13 Valuetainment Corp.
+// voting : Valuetainment Corp.
+// https://www.iana.org/domains/root/db/voting.html
voting
-// voto : 2013-11-21 Monolith Registry LLC
+// voto : Monolith Registry LLC
+// https://www.iana.org/domains/root/db/voto.html
voto
-// voyage : 2013-08-27 Binky Moon, LLC
+// voyage : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/voyage.html
voyage
-// vuelos : 2015-03-05 Travel Reservations SRL
-vuelos
-
-// wales : 2014-05-08 Nominet UK
+// wales : Nominet UK
+// https://www.iana.org/domains/root/db/wales.html
wales
-// walmart : 2015-07-31 Wal-Mart Stores, Inc.
+// walmart : Wal-Mart Stores, Inc.
+// https://www.iana.org/domains/root/db/walmart.html
walmart
-// walter : 2014-11-13 Sandvik AB
+// walter : Sandvik AB
+// https://www.iana.org/domains/root/db/walter.html
walter
-// wang : 2013-10-24 Zodiac Wang Limited
+// wang : Zodiac Wang Limited
+// https://www.iana.org/domains/root/db/wang.html
wang
-// wanggou : 2014-12-18 Amazon Registry Services, Inc.
+// wanggou : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/wanggou.html
wanggou
-// watch : 2013-11-14 Binky Moon, LLC
+// watch : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/watch.html
watch
-// watches : 2014-12-22 Identity Digital Limited
+// watches : Identity Digital Limited
+// https://www.iana.org/domains/root/db/watches.html
watches
-// weather : 2015-01-08 International Business Machines Corporation
+// weather : International Business Machines Corporation
+// https://www.iana.org/domains/root/db/weather.html
weather
-// weatherchannel : 2015-03-12 International Business Machines Corporation
+// weatherchannel : International Business Machines Corporation
+// https://www.iana.org/domains/root/db/weatherchannel.html
weatherchannel
-// webcam : 2014-01-23 dot Webcam Limited
+// webcam : dot Webcam Limited
+// https://www.iana.org/domains/root/db/webcam.html
webcam
-// weber : 2015-06-04 Saint-Gobain Weber SA
+// weber : Saint-Gobain Weber SA
+// https://www.iana.org/domains/root/db/weber.html
weber
-// website : 2014-04-03 Radix FZC
+// website : Radix Technologies Inc.
+// https://www.iana.org/domains/root/db/website.html
website
-// wedding : 2014-04-24 Registry Services, LLC
+// wed
+// https://www.iana.org/domains/root/db/wed.html
+wed
+
+// wedding : Registry Services, LLC
+// https://www.iana.org/domains/root/db/wedding.html
wedding
-// weibo : 2015-03-05 Sina Corporation
+// weibo : Sina Corporation
+// https://www.iana.org/domains/root/db/weibo.html
weibo
-// weir : 2015-01-29 Weir Group IP Limited
+// weir : Weir Group IP Limited
+// https://www.iana.org/domains/root/db/weir.html
weir
-// whoswho : 2014-02-20 Who's Who Registry
+// whoswho : Who's Who Registry
+// https://www.iana.org/domains/root/db/whoswho.html
whoswho
-// wien : 2013-10-28 punkt.wien GmbH
+// wien : punkt.wien GmbH
+// https://www.iana.org/domains/root/db/wien.html
wien
-// wiki : 2013-11-07 Registry Services, LLC
+// wiki : Registry Services, LLC
+// https://www.iana.org/domains/root/db/wiki.html
wiki
-// williamhill : 2014-03-13 William Hill Organization Limited
+// williamhill : William Hill Organization Limited
+// https://www.iana.org/domains/root/db/williamhill.html
williamhill
-// win : 2014-11-20 First Registry Limited
+// win : First Registry Limited
+// https://www.iana.org/domains/root/db/win.html
win
-// windows : 2014-12-18 Microsoft Corporation
+// windows : Microsoft Corporation
+// https://www.iana.org/domains/root/db/windows.html
windows
-// wine : 2015-06-18 Binky Moon, LLC
+// wine : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/wine.html
wine
-// winners : 2015-07-16 The TJX Companies, Inc.
+// winners : The TJX Companies, Inc.
+// https://www.iana.org/domains/root/db/winners.html
winners
-// wme : 2014-02-13 William Morris Endeavor Entertainment, LLC
+// wme : William Morris Endeavor Entertainment, LLC
+// https://www.iana.org/domains/root/db/wme.html
wme
-// wolterskluwer : 2015-08-06 Wolters Kluwer N.V.
+// wolterskluwer : Wolters Kluwer N.V.
+// https://www.iana.org/domains/root/db/wolterskluwer.html
wolterskluwer
-// woodside : 2015-07-09 Woodside Petroleum Limited
+// woodside : Woodside Petroleum Limited
+// https://www.iana.org/domains/root/db/woodside.html
woodside
-// work : 2013-12-19 Registry Services, LLC
+// work : Registry Services, LLC
+// https://www.iana.org/domains/root/db/work.html
work
-// works : 2013-11-14 Binky Moon, LLC
+// works : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/works.html
works
-// world : 2014-06-12 Binky Moon, LLC
+// world : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/world.html
world
-// wow : 2015-10-08 Amazon Registry Services, Inc.
+// wow : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/wow.html
wow
-// wtc : 2013-12-19 World Trade Centers Association, Inc.
+// wtc : World Trade Centers Association, Inc.
+// https://www.iana.org/domains/root/db/wtc.html
wtc
-// wtf : 2014-03-06 Binky Moon, LLC
+// wtf : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/wtf.html
wtf
-// xbox : 2014-12-18 Microsoft Corporation
+// xbox : Microsoft Corporation
+// https://www.iana.org/domains/root/db/xbox.html
xbox
-// xerox : 2014-10-24 Xerox DNHC LLC
+// xerox : Xerox DNHC LLC
+// https://www.iana.org/domains/root/db/xerox.html
xerox
-// xfinity : 2015-07-09 Comcast IP Holdings I, LLC
-xfinity
-
-// xihuan : 2015-01-08 Beijing Qihu Keji Co., Ltd.
+// xihuan : Beijing Qihu Keji Co., Ltd.
+// https://www.iana.org/domains/root/db/xihuan.html
xihuan
-// xin : 2014-12-11 Elegant Leader Limited
+// xin : Elegant Leader Limited
+// https://www.iana.org/domains/root/db/xin.html
xin
-// xn--11b4c3d : 2015-01-15 VeriSign Sarl
+// xn--11b4c3d : VeriSign Sarl
+// https://www.iana.org/domains/root/db/xn--11b4c3d.html
कॉम
-// xn--1ck2e1b : 2015-02-26 Amazon Registry Services, Inc.
+// xn--1ck2e1b : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/xn--1ck2e1b.html
セール
-// xn--1qqw23a : 2014-01-09 Guangzhou YU Wei Information Technology Co., Ltd.
+// xn--1qqw23a : Guangzhou YU Wei Information Technology Co., Ltd.
+// https://www.iana.org/domains/root/db/xn--1qqw23a.html
佛山
-// xn--30rr7y : 2014-06-12 Excellent First Limited
+// xn--30rr7y : Excellent First Limited
+// https://www.iana.org/domains/root/db/xn--30rr7y.html
慈善
-// xn--3bst00m : 2013-09-13 Eagle Horizon Limited
+// xn--3bst00m : Eagle Horizon Limited
+// https://www.iana.org/domains/root/db/xn--3bst00m.html
集团
-// xn--3ds443g : 2013-09-08 TLD REGISTRY LIMITED OY
+// xn--3ds443g : TLD REGISTRY LIMITED OY
+// https://www.iana.org/domains/root/db/xn--3ds443g.html
在线
-// xn--3pxu8k : 2015-01-15 VeriSign Sarl
+// xn--3pxu8k : VeriSign Sarl
+// https://www.iana.org/domains/root/db/xn--3pxu8k.html
点看
-// xn--42c2d9a : 2015-01-15 VeriSign Sarl
+// xn--42c2d9a : VeriSign Sarl
+// https://www.iana.org/domains/root/db/xn--42c2d9a.html
คอม
-// xn--45q11c : 2013-11-21 Zodiac Gemini Ltd
+// xn--45q11c : Zodiac Gemini Ltd
+// https://www.iana.org/domains/root/db/xn--45q11c.html
八卦
-// xn--4gbrim : 2013-10-04 Helium TLDs Ltd
+// xn--4gbrim : Helium TLDs Ltd
+// https://www.iana.org/domains/root/db/xn--4gbrim.html
موقع
-// xn--55qw42g : 2013-11-08 China Organizational Name Administration Center
+// xn--55qw42g : China Organizational Name Administration Center
+// https://www.iana.org/domains/root/db/xn--55qw42g.html
公益
-// xn--55qx5d : 2013-11-14 China Internet Network Information Center (CNNIC)
+// xn--55qx5d : China Internet Network Information Center (CNNIC)
+// https://www.iana.org/domains/root/db/xn--55qx5d.html
公司
-// xn--5su34j936bgsg : 2015-09-03 Shangri‐La International Hotel Management Limited
+// xn--5su34j936bgsg : Shangri‐La International Hotel Management Limited
+// https://www.iana.org/domains/root/db/xn--5su34j936bgsg.html
香格里拉
-// xn--5tzm5g : 2014-12-22 Global Website TLD Asia Limited
+// xn--5tzm5g : Global Website TLD Asia Limited
+// https://www.iana.org/domains/root/db/xn--5tzm5g.html
网站
-// xn--6frz82g : 2013-09-23 Identity Digital Limited
+// xn--6frz82g : Identity Digital Limited
+// https://www.iana.org/domains/root/db/xn--6frz82g.html
移动
-// xn--6qq986b3xl : 2013-09-13 Tycoon Treasure Limited
+// xn--6qq986b3xl : Tycoon Treasure Limited
+// https://www.iana.org/domains/root/db/xn--6qq986b3xl.html
我爱你
-// xn--80adxhks : 2013-12-19 Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID)
+// xn--80adxhks : Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID)
+// https://www.iana.org/domains/root/db/xn--80adxhks.html
москва
-// xn--80aqecdr1a : 2015-10-21 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication)
+// xn--80aqecdr1a : Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication)
+// https://www.iana.org/domains/root/db/xn--80aqecdr1a.html
католик
-// xn--80asehdb : 2013-07-14 CORE Association
+// xn--80asehdb : CORE Association
+// https://www.iana.org/domains/root/db/xn--80asehdb.html
онлайн
-// xn--80aswg : 2013-07-14 CORE Association
+// xn--80aswg : CORE Association
+// https://www.iana.org/domains/root/db/xn--80aswg.html
сайт
-// xn--8y0a063a : 2015-03-26 China United Network Communications Corporation Limited
+// xn--8y0a063a : China United Network Communications Corporation Limited
+// https://www.iana.org/domains/root/db/xn--8y0a063a.html
联通
-// xn--9dbq2a : 2015-01-15 VeriSign Sarl
+// xn--9dbq2a : VeriSign Sarl
+// https://www.iana.org/domains/root/db/xn--9dbq2a.html
קום
-// xn--9et52u : 2014-06-12 RISE VICTORY LIMITED
+// xn--9et52u : RISE VICTORY LIMITED
+// https://www.iana.org/domains/root/db/xn--9et52u.html
时尚
-// xn--9krt00a : 2015-03-12 Sina Corporation
+// xn--9krt00a : Sina Corporation
+// https://www.iana.org/domains/root/db/xn--9krt00a.html
微博
-// xn--b4w605ferd : 2014-08-07 Temasek Holdings (Private) Limited
+// xn--b4w605ferd : Temasek Holdings (Private) Limited
+// https://www.iana.org/domains/root/db/xn--b4w605ferd.html
淡马锡
-// xn--bck1b9a5dre4c : 2015-02-26 Amazon Registry Services, Inc.
+// xn--bck1b9a5dre4c : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/xn--bck1b9a5dre4c.html
ファッション
-// xn--c1avg : 2013-11-14 Public Interest Registry
+// xn--c1avg : Public Interest Registry
+// https://www.iana.org/domains/root/db/xn--c1avg.html
орг
-// xn--c2br7g : 2015-01-15 VeriSign Sarl
+// xn--c2br7g : VeriSign Sarl
+// https://www.iana.org/domains/root/db/xn--c2br7g.html
नेट
-// xn--cck2b3b : 2015-02-26 Amazon Registry Services, Inc.
+// xn--cck2b3b : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/xn--cck2b3b.html
ストア
-// xn--cckwcxetd : 2019-12-19 Amazon Registry Services, Inc.
+// xn--cckwcxetd : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/xn--cckwcxetd.html
アマゾン
-// xn--cg4bki : 2013-09-27 SAMSUNG SDS CO., LTD
+// xn--cg4bki : SAMSUNG SDS CO., LTD
+// https://www.iana.org/domains/root/db/xn--cg4bki.html
삼성
-// xn--czr694b : 2014-01-16 Internet DotTrademark Organisation Limited
+// xn--czr694b : Internet DotTrademark Organisation Limited
+// https://www.iana.org/domains/root/db/xn--czr694b.html
商标
-// xn--czrs0t : 2013-12-19 Binky Moon, LLC
+// xn--czrs0t : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/xn--czrs0t.html
商店
-// xn--czru2d : 2013-11-21 Zodiac Aquarius Limited
+// xn--czru2d : Zodiac Aquarius Limited
+// https://www.iana.org/domains/root/db/xn--czru2d.html
商城
-// xn--d1acj3b : 2013-11-20 The Foundation for Network Initiatives “The Smart Internet”
+// xn--d1acj3b : The Foundation for Network Initiatives “The Smart Internet”
+// https://www.iana.org/domains/root/db/xn--d1acj3b.html
дети
-// xn--eckvdtc9d : 2014-12-18 Amazon Registry Services, Inc.
+// xn--eckvdtc9d : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/xn--eckvdtc9d.html
ポイント
-// xn--efvy88h : 2014-08-22 Guangzhou YU Wei Information Technology Co., Ltd.
+// xn--efvy88h : Guangzhou YU Wei Information Technology Co., Ltd.
+// https://www.iana.org/domains/root/db/xn--efvy88h.html
新闻
-// xn--fct429k : 2015-04-09 Amazon Registry Services, Inc.
+// xn--fct429k : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/xn--fct429k.html
家電
-// xn--fhbei : 2015-01-15 VeriSign Sarl
+// xn--fhbei : VeriSign Sarl
+// https://www.iana.org/domains/root/db/xn--fhbei.html
كوم
-// xn--fiq228c5hs : 2013-09-08 TLD REGISTRY LIMITED OY
+// xn--fiq228c5hs : TLD REGISTRY LIMITED OY
+// https://www.iana.org/domains/root/db/xn--fiq228c5hs.html
中文网
-// xn--fiq64b : 2013-10-14 CITIC Group Corporation
+// xn--fiq64b : CITIC Group Corporation
+// https://www.iana.org/domains/root/db/xn--fiq64b.html
中信
-// xn--fjq720a : 2014-05-22 Binky Moon, LLC
+// xn--fjq720a : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/xn--fjq720a.html
娱乐
-// xn--flw351e : 2014-07-31 Charleston Road Registry Inc.
+// xn--flw351e : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/xn--flw351e.html
谷歌
-// xn--fzys8d69uvgm : 2015-05-14 PCCW Enterprises Limited
+// xn--fzys8d69uvgm : PCCW Enterprises Limited
+// https://www.iana.org/domains/root/db/xn--fzys8d69uvgm.html
電訊盈科
-// xn--g2xx48c : 2015-01-30 Nawang Heli(Xiamen) Network Service Co., LTD.
+// xn--g2xx48c : Nawang Heli(Xiamen) Network Service Co., LTD.
+// https://www.iana.org/domains/root/db/xn--g2xx48c.html
购物
-// xn--gckr3f0f : 2015-02-26 Amazon Registry Services, Inc.
+// xn--gckr3f0f : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/xn--gckr3f0f.html
クラウド
-// xn--gk3at1e : 2015-10-08 Amazon Registry Services, Inc.
+// xn--gk3at1e : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/xn--gk3at1e.html
通販
-// xn--hxt814e : 2014-05-15 Zodiac Taurus Limited
+// xn--hxt814e : Zodiac Taurus Limited
+// https://www.iana.org/domains/root/db/xn--hxt814e.html
网店
-// xn--i1b6b1a6a2e : 2013-11-14 Public Interest Registry
+// xn--i1b6b1a6a2e : Public Interest Registry
+// https://www.iana.org/domains/root/db/xn--i1b6b1a6a2e.html
संगठन
-// xn--imr513n : 2014-12-11 Internet DotTrademark Organisation Limited
+// xn--imr513n : Internet DotTrademark Organisation Limited
+// https://www.iana.org/domains/root/db/xn--imr513n.html
餐厅
-// xn--io0a7i : 2013-11-14 China Internet Network Information Center (CNNIC)
+// xn--io0a7i : China Internet Network Information Center (CNNIC)
+// https://www.iana.org/domains/root/db/xn--io0a7i.html
网络
-// xn--j1aef : 2015-01-15 VeriSign Sarl
+// xn--j1aef : VeriSign Sarl
+// https://www.iana.org/domains/root/db/xn--j1aef.html
ком
-// xn--jlq480n2rg : 2019-12-19 Amazon Registry Services, Inc.
+// xn--jlq480n2rg : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/xn--jlq480n2rg.html
亚马逊
-// xn--jvr189m : 2015-02-26 Amazon Registry Services, Inc.
+// xn--jvr189m : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/xn--jvr189m.html
食品
-// xn--kcrx77d1x4a : 2014-11-07 Koninklijke Philips N.V.
+// xn--kcrx77d1x4a : Koninklijke Philips N.V.
+// https://www.iana.org/domains/root/db/xn--kcrx77d1x4a.html
飞利浦
-// xn--kput3i : 2014-02-13 Beijing RITT-Net Technology Development Co., Ltd
+// xn--kput3i : Beijing RITT-Net Technology Development Co., Ltd
+// https://www.iana.org/domains/root/db/xn--kput3i.html
手机
-// xn--mgba3a3ejt : 2014-11-20 Aramco Services Company
+// xn--mgba3a3ejt : Aramco Services Company
+// https://www.iana.org/domains/root/db/xn--mgba3a3ejt.html
ارامكو
-// xn--mgba7c0bbn0a : 2015-05-14 Competrol (Luxembourg) Sarl
+// xn--mgba7c0bbn0a : Competrol (Luxembourg) Sarl
+// https://www.iana.org/domains/root/db/xn--mgba7c0bbn0a.html
العليان
-// xn--mgbaakc7dvf : 2015-09-03 Emirates Telecommunications Corporation (trading as Etisalat)
-اتصالات
-
-// xn--mgbab2bd : 2013-10-31 CORE Association
+// xn--mgbab2bd : CORE Association
+// https://www.iana.org/domains/root/db/xn--mgbab2bd.html
بازار
-// xn--mgbca7dzdo : 2015-07-30 Abu Dhabi Systems and Information Centre
+// xn--mgbca7dzdo : Abu Dhabi Systems and Information Centre
+// https://www.iana.org/domains/root/db/xn--mgbca7dzdo.html
ابوظبي
-// xn--mgbi4ecexp : 2015-10-21 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication)
+// xn--mgbi4ecexp : Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication)
+// https://www.iana.org/domains/root/db/xn--mgbi4ecexp.html
كاثوليك
-// xn--mgbt3dhd : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
+// xn--mgbt3dhd : Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
+// https://www.iana.org/domains/root/db/xn--mgbt3dhd.html
همراه
-// xn--mk1bu44c : 2015-01-15 VeriSign Sarl
+// xn--mk1bu44c : VeriSign Sarl
+// https://www.iana.org/domains/root/db/xn--mk1bu44c.html
닷컴
-// xn--mxtq1m : 2014-03-06 Net-Chinese Co., Ltd.
+// xn--mxtq1m : Net-Chinese Co., Ltd.
+// https://www.iana.org/domains/root/db/xn--mxtq1m.html
政府
-// xn--ngbc5azd : 2013-07-13 International Domain Registry Pty. Ltd.
+// xn--ngbc5azd : International Domain Registry Pty. Ltd.
+// https://www.iana.org/domains/root/db/xn--ngbc5azd.html
شبكة
-// xn--ngbe9e0a : 2014-12-04 Kuwait Finance House
+// xn--ngbe9e0a : Kuwait Finance House
+// https://www.iana.org/domains/root/db/xn--ngbe9e0a.html
بيتك
-// xn--ngbrx : 2015-11-12 League of Arab States
+// xn--ngbrx : League of Arab States
+// https://www.iana.org/domains/root/db/xn--ngbrx.html
عرب
-// xn--nqv7f : 2013-11-14 Public Interest Registry
+// xn--nqv7f : Public Interest Registry
+// https://www.iana.org/domains/root/db/xn--nqv7f.html
机构
-// xn--nqv7fs00ema : 2013-11-14 Public Interest Registry
+// xn--nqv7fs00ema : Public Interest Registry
+// https://www.iana.org/domains/root/db/xn--nqv7fs00ema.html
组织机构
-// xn--nyqy26a : 2014-11-07 Stable Tone Limited
+// xn--nyqy26a : Stable Tone Limited
+// https://www.iana.org/domains/root/db/xn--nyqy26a.html
健康
-// xn--otu796d : 2017-08-06 Jiang Yu Liang Cai Technology Company Limited
+// xn--otu796d : Jiang Yu Liang Cai Technology Company Limited
+// https://www.iana.org/domains/root/db/xn--otu796d.html
招聘
-// xn--p1acf : 2013-12-12 Rusnames Limited
+// xn--p1acf : Rusnames Limited
+// https://www.iana.org/domains/root/db/xn--p1acf.html
рус
-// xn--pssy2u : 2015-01-15 VeriSign Sarl
+// xn--pssy2u : VeriSign Sarl
+// https://www.iana.org/domains/root/db/xn--pssy2u.html
大拿
-// xn--q9jyb4c : 2013-09-17 Charleston Road Registry Inc.
+// xn--q9jyb4c : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/xn--q9jyb4c.html
みんな
-// xn--qcka1pmc : 2014-07-31 Charleston Road Registry Inc.
+// xn--qcka1pmc : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/xn--qcka1pmc.html
グーグル
-// xn--rhqv96g : 2013-09-11 Stable Tone Limited
+// xn--rhqv96g : Stable Tone Limited
+// https://www.iana.org/domains/root/db/xn--rhqv96g.html
世界
-// xn--rovu88b : 2015-02-26 Amazon Registry Services, Inc.
+// xn--rovu88b : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/xn--rovu88b.html
書籍
-// xn--ses554g : 2014-01-16 KNET Co., Ltd.
+// xn--ses554g : KNET Co., Ltd.
+// https://www.iana.org/domains/root/db/xn--ses554g.html
网址
-// xn--t60b56a : 2015-01-15 VeriSign Sarl
+// xn--t60b56a : VeriSign Sarl
+// https://www.iana.org/domains/root/db/xn--t60b56a.html
닷넷
-// xn--tckwe : 2015-01-15 VeriSign Sarl
+// xn--tckwe : VeriSign Sarl
+// https://www.iana.org/domains/root/db/xn--tckwe.html
コム
-// xn--tiq49xqyj : 2015-10-21 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication)
+// xn--tiq49xqyj : Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication)
+// https://www.iana.org/domains/root/db/xn--tiq49xqyj.html
天主教
-// xn--unup4y : 2013-07-14 Binky Moon, LLC
+// xn--unup4y : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/xn--unup4y.html
游戏
-// xn--vermgensberater-ctb : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG
+// xn--vermgensberater-ctb : Deutsche Vermögensberatung Aktiengesellschaft DVAG
+// https://www.iana.org/domains/root/db/xn--vermgensberater-ctb.html
vermögensberater
-// xn--vermgensberatung-pwb : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG
+// xn--vermgensberatung-pwb : Deutsche Vermögensberatung Aktiengesellschaft DVAG
+// https://www.iana.org/domains/root/db/xn--vermgensberatung-pwb.html
vermögensberatung
-// xn--vhquv : 2013-08-27 Binky Moon, LLC
+// xn--vhquv : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/xn--vhquv.html
企业
-// xn--vuq861b : 2014-10-16 Beijing Tele-info Technology Co., Ltd.
+// xn--vuq861b : Beijing Tele-info Technology Co., Ltd.
+// https://www.iana.org/domains/root/db/xn--vuq861b.html
信息
-// xn--w4r85el8fhu5dnra : 2015-04-30 Kerry Trading Co. Limited
+// xn--w4r85el8fhu5dnra : Kerry Trading Co. Limited
+// https://www.iana.org/domains/root/db/xn--w4r85el8fhu5dnra.html
嘉里大酒店
-// xn--w4rs40l : 2015-07-30 Kerry Trading Co. Limited
+// xn--w4rs40l : Kerry Trading Co. Limited
+// https://www.iana.org/domains/root/db/xn--w4rs40l.html
嘉里
-// xn--xhq521b : 2013-11-14 Guangzhou YU Wei Information Technology Co., Ltd.
+// xn--xhq521b : Guangzhou YU Wei Information Technology Co., Ltd.
+// https://www.iana.org/domains/root/db/xn--xhq521b.html
广东
-// xn--zfr164b : 2013-11-08 China Organizational Name Administration Center
+// xn--zfr164b : China Organizational Name Administration Center
+// https://www.iana.org/domains/root/db/xn--zfr164b.html
政务
-// xyz : 2013-12-05 XYZ.COM LLC
+// xyz : XYZ.COM LLC
+// https://www.iana.org/domains/root/db/xyz.html
xyz
-// yachts : 2014-01-09 XYZ.COM LLC
+// yachts : XYZ.COM LLC
+// https://www.iana.org/domains/root/db/yachts.html
yachts
-// yahoo : 2015-04-02 Oath Inc.
+// yahoo : Oath Inc.
+// https://www.iana.org/domains/root/db/yahoo.html
yahoo
-// yamaxun : 2014-12-18 Amazon Registry Services, Inc.
+// yamaxun : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/yamaxun.html
yamaxun
-// yandex : 2014-04-10 Yandex Europe B.V.
+// yandex : Yandex Europe B.V.
+// https://www.iana.org/domains/root/db/yandex.html
yandex
-// yodobashi : 2014-11-20 YODOBASHI CAMERA CO.,LTD.
+// yodobashi : YODOBASHI CAMERA CO.,LTD.
+// https://www.iana.org/domains/root/db/yodobashi.html
yodobashi
-// yoga : 2014-05-29 Registry Services, LLC
+// yoga : Registry Services, LLC
+// https://www.iana.org/domains/root/db/yoga.html
yoga
-// yokohama : 2013-12-12 GMO Registry, Inc.
+// yokohama : GMO Registry, Inc.
+// https://www.iana.org/domains/root/db/yokohama.html
yokohama
-// you : 2015-04-09 Amazon Registry Services, Inc.
+// you : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/you.html
you
-// youtube : 2014-05-01 Charleston Road Registry Inc.
+// youtube : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/youtube.html
youtube
-// yun : 2015-01-08 Beijing Qihu Keji Co., Ltd.
+// yun : Beijing Qihu Keji Co., Ltd.
+// https://www.iana.org/domains/root/db/yun.html
yun
-// zappos : 2015-06-25 Amazon Registry Services, Inc.
+// zappos : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/zappos.html
zappos
-// zara : 2014-11-07 Industria de Diseño Textil, S.A. (INDITEX, S.A.)
+// zara : Industria de Diseño Textil, S.A. (INDITEX, S.A.)
+// https://www.iana.org/domains/root/db/zara.html
zara
-// zero : 2014-12-18 Amazon Registry Services, Inc.
+// zero : Amazon Registry Services, Inc.
+// https://www.iana.org/domains/root/db/zero.html
zero
-// zip : 2014-05-08 Charleston Road Registry Inc.
+// zip : Charleston Road Registry Inc.
+// https://www.iana.org/domains/root/db/zip.html
zip
-// zone : 2013-11-14 Binky Moon, LLC
+// zone : Binky Moon, LLC
+// https://www.iana.org/domains/root/db/zone.html
zone
-// zuerich : 2014-11-07 Kanton Zürich (Canton of Zurich)
+// zuerich : Kanton Zürich (Canton of Zurich)
+// https://www.iana.org/domains/root/db/zuerich.html
zuerich
@@ -10140,6 +11189,12 @@ zuerich
// ===BEGIN PRIVATE DOMAINS===
// (Note: these are in alphabetical order by company name)
+// 12CHARS: https://12chars.com
+// Submitted by Kenny Niehage <psl@12chars.com>
+12chars.dev
+12chars.it
+12chars.pro
+
// 1GB LLC : https://www.1gb.ua/
// Submitted by 1GB LLC <noc@1gb.com.ua>
cc.ua
@@ -10149,6 +11204,11 @@ ltd.ua
// 611coin : https://611project.org/
611.to
+// A2 Hosting
+// Submitted by Tyler Hall <sysadmin@a2hosting.com>
+a2hosted.com
+cpserver.com
+
// Aaron Marais' Gitlab pages: https://lab.aaronleem.co.za
// Submitted by Aaron Marais <its_me@aaronleem.co.za>
graphox.us
@@ -10165,12 +11225,18 @@ graphox.us
// Submitted by Ofer Kalaora <postmaster@activetrail.com>
activetrail.biz
+// Adaptable.io : https://adaptable.io
+// Submitted by Mark Terrel <support@adaptable.io>
+adaptable.app
+
// Adobe : https://www.adobe.com/
// Submitted by Ian Boston <boston@adobe.com> and Lars Trieloff <trieloff@adobe.com>
adobeaemcloud.com
*.dev.adobeaemcloud.com
+aem.live
hlx.live
adobeaemcloud.net
+aem.page
hlx.page
hlx3.page
@@ -10240,11 +11306,79 @@ myamaze.net
// Submitted by AWS Security <psl-maintainers@amazon.com>
// Subsections of Amazon/subsidiaries will appear until "concludes" tag
+// Amazon API Gateway
+// Submitted by AWS Security <psl-maintainers@amazon.com>
+// Reference: 9e37648f-a66c-4655-9ab1-5981f8737197
+execute-api.cn-north-1.amazonaws.com.cn
+execute-api.cn-northwest-1.amazonaws.com.cn
+execute-api.af-south-1.amazonaws.com
+execute-api.ap-east-1.amazonaws.com
+execute-api.ap-northeast-1.amazonaws.com
+execute-api.ap-northeast-2.amazonaws.com
+execute-api.ap-northeast-3.amazonaws.com
+execute-api.ap-south-1.amazonaws.com
+execute-api.ap-south-2.amazonaws.com
+execute-api.ap-southeast-1.amazonaws.com
+execute-api.ap-southeast-2.amazonaws.com
+execute-api.ap-southeast-3.amazonaws.com
+execute-api.ap-southeast-4.amazonaws.com
+execute-api.ca-central-1.amazonaws.com
+execute-api.ca-west-1.amazonaws.com
+execute-api.eu-central-1.amazonaws.com
+execute-api.eu-central-2.amazonaws.com
+execute-api.eu-north-1.amazonaws.com
+execute-api.eu-south-1.amazonaws.com
+execute-api.eu-south-2.amazonaws.com
+execute-api.eu-west-1.amazonaws.com
+execute-api.eu-west-2.amazonaws.com
+execute-api.eu-west-3.amazonaws.com
+execute-api.il-central-1.amazonaws.com
+execute-api.me-central-1.amazonaws.com
+execute-api.me-south-1.amazonaws.com
+execute-api.sa-east-1.amazonaws.com
+execute-api.us-east-1.amazonaws.com
+execute-api.us-east-2.amazonaws.com
+execute-api.us-gov-east-1.amazonaws.com
+execute-api.us-gov-west-1.amazonaws.com
+execute-api.us-west-1.amazonaws.com
+execute-api.us-west-2.amazonaws.com
+
// Amazon CloudFront
// Submitted by Donavan Miller <donavanm@amazon.com>
// Reference: 54144616-fd49-4435-8535-19c6a601bdb3
cloudfront.net
+// Amazon Cognito
+// Submitted by AWS Security <psl-maintainers@amazon.com>
+// Reference: 7bee1013-f456-47df-bfe8-03c78d946d61
+auth.af-south-1.amazoncognito.com
+auth.ap-northeast-1.amazoncognito.com
+auth.ap-northeast-2.amazoncognito.com
+auth.ap-northeast-3.amazoncognito.com
+auth.ap-south-1.amazoncognito.com
+auth.ap-southeast-1.amazoncognito.com
+auth.ap-southeast-2.amazoncognito.com
+auth.ap-southeast-3.amazoncognito.com
+auth.ca-central-1.amazoncognito.com
+auth.eu-central-1.amazoncognito.com
+auth.eu-north-1.amazoncognito.com
+auth.eu-south-1.amazoncognito.com
+auth.eu-west-1.amazoncognito.com
+auth.eu-west-2.amazoncognito.com
+auth.eu-west-3.amazoncognito.com
+auth.il-central-1.amazoncognito.com
+auth.me-south-1.amazoncognito.com
+auth.sa-east-1.amazoncognito.com
+auth.us-east-1.amazoncognito.com
+auth-fips.us-east-1.amazoncognito.com
+auth.us-east-2.amazoncognito.com
+auth-fips.us-east-2.amazoncognito.com
+auth-fips.us-gov-west-1.amazoncognito.com
+auth.us-west-1.amazoncognito.com
+auth-fips.us-west-1.amazoncognito.com
+auth.us-west-2.amazoncognito.com
+auth-fips.us-west-2.amazoncognito.com
+
// Amazon EC2
// Submitted by Luke Wells <psl-maintainers@amazon.com>
// Reference: 4c38fa71-58ac-4768-99e5-689c1767e537
@@ -10253,47 +11387,317 @@ cloudfront.net
*.compute.amazonaws.com.cn
us-east-1.amazonaws.com
+// Amazon EMR
+// Submitted by AWS Security <psl-maintainers@amazon.com>
+// Reference: 597f3f8e-9283-4e48-8e32-7ee25a1ff6ab
+emrappui-prod.cn-north-1.amazonaws.com.cn
+emrnotebooks-prod.cn-north-1.amazonaws.com.cn
+emrstudio-prod.cn-north-1.amazonaws.com.cn
+emrappui-prod.cn-northwest-1.amazonaws.com.cn
+emrnotebooks-prod.cn-northwest-1.amazonaws.com.cn
+emrstudio-prod.cn-northwest-1.amazonaws.com.cn
+emrappui-prod.af-south-1.amazonaws.com
+emrnotebooks-prod.af-south-1.amazonaws.com
+emrstudio-prod.af-south-1.amazonaws.com
+emrappui-prod.ap-east-1.amazonaws.com
+emrnotebooks-prod.ap-east-1.amazonaws.com
+emrstudio-prod.ap-east-1.amazonaws.com
+emrappui-prod.ap-northeast-1.amazonaws.com
+emrnotebooks-prod.ap-northeast-1.amazonaws.com
+emrstudio-prod.ap-northeast-1.amazonaws.com
+emrappui-prod.ap-northeast-2.amazonaws.com
+emrnotebooks-prod.ap-northeast-2.amazonaws.com
+emrstudio-prod.ap-northeast-2.amazonaws.com
+emrappui-prod.ap-northeast-3.amazonaws.com
+emrnotebooks-prod.ap-northeast-3.amazonaws.com
+emrstudio-prod.ap-northeast-3.amazonaws.com
+emrappui-prod.ap-south-1.amazonaws.com
+emrnotebooks-prod.ap-south-1.amazonaws.com
+emrstudio-prod.ap-south-1.amazonaws.com
+emrappui-prod.ap-southeast-1.amazonaws.com
+emrnotebooks-prod.ap-southeast-1.amazonaws.com
+emrstudio-prod.ap-southeast-1.amazonaws.com
+emrappui-prod.ap-southeast-2.amazonaws.com
+emrnotebooks-prod.ap-southeast-2.amazonaws.com
+emrstudio-prod.ap-southeast-2.amazonaws.com
+emrappui-prod.ap-southeast-3.amazonaws.com
+emrnotebooks-prod.ap-southeast-3.amazonaws.com
+emrstudio-prod.ap-southeast-3.amazonaws.com
+emrappui-prod.ca-central-1.amazonaws.com
+emrnotebooks-prod.ca-central-1.amazonaws.com
+emrstudio-prod.ca-central-1.amazonaws.com
+emrappui-prod.eu-central-1.amazonaws.com
+emrnotebooks-prod.eu-central-1.amazonaws.com
+emrstudio-prod.eu-central-1.amazonaws.com
+emrappui-prod.eu-north-1.amazonaws.com
+emrnotebooks-prod.eu-north-1.amazonaws.com
+emrstudio-prod.eu-north-1.amazonaws.com
+emrappui-prod.eu-south-1.amazonaws.com
+emrnotebooks-prod.eu-south-1.amazonaws.com
+emrstudio-prod.eu-south-1.amazonaws.com
+emrappui-prod.eu-west-1.amazonaws.com
+emrnotebooks-prod.eu-west-1.amazonaws.com
+emrstudio-prod.eu-west-1.amazonaws.com
+emrappui-prod.eu-west-2.amazonaws.com
+emrnotebooks-prod.eu-west-2.amazonaws.com
+emrstudio-prod.eu-west-2.amazonaws.com
+emrappui-prod.eu-west-3.amazonaws.com
+emrnotebooks-prod.eu-west-3.amazonaws.com
+emrstudio-prod.eu-west-3.amazonaws.com
+emrappui-prod.me-central-1.amazonaws.com
+emrnotebooks-prod.me-central-1.amazonaws.com
+emrstudio-prod.me-central-1.amazonaws.com
+emrappui-prod.me-south-1.amazonaws.com
+emrnotebooks-prod.me-south-1.amazonaws.com
+emrstudio-prod.me-south-1.amazonaws.com
+emrappui-prod.sa-east-1.amazonaws.com
+emrnotebooks-prod.sa-east-1.amazonaws.com
+emrstudio-prod.sa-east-1.amazonaws.com
+emrappui-prod.us-east-1.amazonaws.com
+emrnotebooks-prod.us-east-1.amazonaws.com
+emrstudio-prod.us-east-1.amazonaws.com
+emrappui-prod.us-east-2.amazonaws.com
+emrnotebooks-prod.us-east-2.amazonaws.com
+emrstudio-prod.us-east-2.amazonaws.com
+emrappui-prod.us-gov-east-1.amazonaws.com
+emrnotebooks-prod.us-gov-east-1.amazonaws.com
+emrstudio-prod.us-gov-east-1.amazonaws.com
+emrappui-prod.us-gov-west-1.amazonaws.com
+emrnotebooks-prod.us-gov-west-1.amazonaws.com
+emrstudio-prod.us-gov-west-1.amazonaws.com
+emrappui-prod.us-west-1.amazonaws.com
+emrnotebooks-prod.us-west-1.amazonaws.com
+emrstudio-prod.us-west-1.amazonaws.com
+emrappui-prod.us-west-2.amazonaws.com
+emrnotebooks-prod.us-west-2.amazonaws.com
+emrstudio-prod.us-west-2.amazonaws.com
+
+// Amazon Managed Workflows for Apache Airflow
+// Submitted by AWS Security <psl-maintainers@amazon.com>
+// Reference: 4ab55e6f-90c0-4a8d-b6a0-52ca5dbb1c2e
+*.cn-north-1.airflow.amazonaws.com.cn
+*.cn-northwest-1.airflow.amazonaws.com.cn
+*.ap-northeast-1.airflow.amazonaws.com
+*.ap-northeast-2.airflow.amazonaws.com
+*.ap-south-1.airflow.amazonaws.com
+*.ap-southeast-1.airflow.amazonaws.com
+*.ap-southeast-2.airflow.amazonaws.com
+*.ca-central-1.airflow.amazonaws.com
+*.eu-central-1.airflow.amazonaws.com
+*.eu-north-1.airflow.amazonaws.com
+*.eu-west-1.airflow.amazonaws.com
+*.eu-west-2.airflow.amazonaws.com
+*.eu-west-3.airflow.amazonaws.com
+*.sa-east-1.airflow.amazonaws.com
+*.us-east-1.airflow.amazonaws.com
+*.us-east-2.airflow.amazonaws.com
+*.us-west-2.airflow.amazonaws.com
+
// Amazon S3
-// Submitted by Luke Wells <psl-maintainers@amazon.com>
-// Reference: d068bd97-f0a9-4838-a6d8-954b622ef4ae
+// Submitted by AWS Security <psl-maintainers@amazon.com>
+// Reference: cd5c8b3a-67b7-4b40-9236-c87ce81a3d10
+s3.dualstack.cn-north-1.amazonaws.com.cn
+s3-accesspoint.dualstack.cn-north-1.amazonaws.com.cn
+s3-website.dualstack.cn-north-1.amazonaws.com.cn
s3.cn-north-1.amazonaws.com.cn
+s3-accesspoint.cn-north-1.amazonaws.com.cn
+s3-deprecated.cn-north-1.amazonaws.com.cn
+s3-object-lambda.cn-north-1.amazonaws.com.cn
+s3-website.cn-north-1.amazonaws.com.cn
+s3.dualstack.cn-northwest-1.amazonaws.com.cn
+s3-accesspoint.dualstack.cn-northwest-1.amazonaws.com.cn
+s3.cn-northwest-1.amazonaws.com.cn
+s3-accesspoint.cn-northwest-1.amazonaws.com.cn
+s3-object-lambda.cn-northwest-1.amazonaws.com.cn
+s3-website.cn-northwest-1.amazonaws.com.cn
+s3.dualstack.af-south-1.amazonaws.com
+s3-accesspoint.dualstack.af-south-1.amazonaws.com
+s3-website.dualstack.af-south-1.amazonaws.com
+s3.af-south-1.amazonaws.com
+s3-accesspoint.af-south-1.amazonaws.com
+s3-object-lambda.af-south-1.amazonaws.com
+s3-website.af-south-1.amazonaws.com
+s3.dualstack.ap-east-1.amazonaws.com
+s3-accesspoint.dualstack.ap-east-1.amazonaws.com
+s3.ap-east-1.amazonaws.com
+s3-accesspoint.ap-east-1.amazonaws.com
+s3-object-lambda.ap-east-1.amazonaws.com
+s3-website.ap-east-1.amazonaws.com
s3.dualstack.ap-northeast-1.amazonaws.com
+s3-accesspoint.dualstack.ap-northeast-1.amazonaws.com
+s3-website.dualstack.ap-northeast-1.amazonaws.com
+s3.ap-northeast-1.amazonaws.com
+s3-accesspoint.ap-northeast-1.amazonaws.com
+s3-object-lambda.ap-northeast-1.amazonaws.com
+s3-website.ap-northeast-1.amazonaws.com
s3.dualstack.ap-northeast-2.amazonaws.com
+s3-accesspoint.dualstack.ap-northeast-2.amazonaws.com
+s3-website.dualstack.ap-northeast-2.amazonaws.com
s3.ap-northeast-2.amazonaws.com
+s3-accesspoint.ap-northeast-2.amazonaws.com
+s3-object-lambda.ap-northeast-2.amazonaws.com
s3-website.ap-northeast-2.amazonaws.com
+s3.dualstack.ap-northeast-3.amazonaws.com
+s3-accesspoint.dualstack.ap-northeast-3.amazonaws.com
+s3-website.dualstack.ap-northeast-3.amazonaws.com
+s3.ap-northeast-3.amazonaws.com
+s3-accesspoint.ap-northeast-3.amazonaws.com
+s3-object-lambda.ap-northeast-3.amazonaws.com
+s3-website.ap-northeast-3.amazonaws.com
s3.dualstack.ap-south-1.amazonaws.com
+s3-accesspoint.dualstack.ap-south-1.amazonaws.com
+s3-website.dualstack.ap-south-1.amazonaws.com
s3.ap-south-1.amazonaws.com
+s3-accesspoint.ap-south-1.amazonaws.com
+s3-object-lambda.ap-south-1.amazonaws.com
s3-website.ap-south-1.amazonaws.com
+s3.dualstack.ap-south-2.amazonaws.com
+s3-accesspoint.dualstack.ap-south-2.amazonaws.com
+s3.ap-south-2.amazonaws.com
+s3-accesspoint.ap-south-2.amazonaws.com
+s3-object-lambda.ap-south-2.amazonaws.com
+s3-website.ap-south-2.amazonaws.com
s3.dualstack.ap-southeast-1.amazonaws.com
+s3-accesspoint.dualstack.ap-southeast-1.amazonaws.com
+s3-website.dualstack.ap-southeast-1.amazonaws.com
+s3.ap-southeast-1.amazonaws.com
+s3-accesspoint.ap-southeast-1.amazonaws.com
+s3-object-lambda.ap-southeast-1.amazonaws.com
+s3-website.ap-southeast-1.amazonaws.com
s3.dualstack.ap-southeast-2.amazonaws.com
+s3-accesspoint.dualstack.ap-southeast-2.amazonaws.com
+s3-website.dualstack.ap-southeast-2.amazonaws.com
+s3.ap-southeast-2.amazonaws.com
+s3-accesspoint.ap-southeast-2.amazonaws.com
+s3-object-lambda.ap-southeast-2.amazonaws.com
+s3-website.ap-southeast-2.amazonaws.com
+s3.dualstack.ap-southeast-3.amazonaws.com
+s3-accesspoint.dualstack.ap-southeast-3.amazonaws.com
+s3.ap-southeast-3.amazonaws.com
+s3-accesspoint.ap-southeast-3.amazonaws.com
+s3-object-lambda.ap-southeast-3.amazonaws.com
+s3-website.ap-southeast-3.amazonaws.com
+s3.dualstack.ap-southeast-4.amazonaws.com
+s3-accesspoint.dualstack.ap-southeast-4.amazonaws.com
+s3.ap-southeast-4.amazonaws.com
+s3-accesspoint.ap-southeast-4.amazonaws.com
+s3-object-lambda.ap-southeast-4.amazonaws.com
+s3-website.ap-southeast-4.amazonaws.com
s3.dualstack.ca-central-1.amazonaws.com
+s3-accesspoint.dualstack.ca-central-1.amazonaws.com
+s3-accesspoint-fips.dualstack.ca-central-1.amazonaws.com
+s3-fips.dualstack.ca-central-1.amazonaws.com
+s3-website.dualstack.ca-central-1.amazonaws.com
s3.ca-central-1.amazonaws.com
+s3-accesspoint.ca-central-1.amazonaws.com
+s3-accesspoint-fips.ca-central-1.amazonaws.com
+s3-fips.ca-central-1.amazonaws.com
+s3-object-lambda.ca-central-1.amazonaws.com
s3-website.ca-central-1.amazonaws.com
+s3.dualstack.ca-west-1.amazonaws.com
+s3-accesspoint.dualstack.ca-west-1.amazonaws.com
+s3-accesspoint-fips.dualstack.ca-west-1.amazonaws.com
+s3-fips.dualstack.ca-west-1.amazonaws.com
+s3-website.dualstack.ca-west-1.amazonaws.com
+s3.ca-west-1.amazonaws.com
+s3-accesspoint.ca-west-1.amazonaws.com
+s3-accesspoint-fips.ca-west-1.amazonaws.com
+s3-fips.ca-west-1.amazonaws.com
+s3-website.ca-west-1.amazonaws.com
s3.dualstack.eu-central-1.amazonaws.com
+s3-accesspoint.dualstack.eu-central-1.amazonaws.com
+s3-website.dualstack.eu-central-1.amazonaws.com
s3.eu-central-1.amazonaws.com
+s3-accesspoint.eu-central-1.amazonaws.com
+s3-object-lambda.eu-central-1.amazonaws.com
s3-website.eu-central-1.amazonaws.com
+s3.dualstack.eu-central-2.amazonaws.com
+s3-accesspoint.dualstack.eu-central-2.amazonaws.com
+s3.eu-central-2.amazonaws.com
+s3-accesspoint.eu-central-2.amazonaws.com
+s3-object-lambda.eu-central-2.amazonaws.com
+s3-website.eu-central-2.amazonaws.com
+s3.dualstack.eu-north-1.amazonaws.com
+s3-accesspoint.dualstack.eu-north-1.amazonaws.com
+s3.eu-north-1.amazonaws.com
+s3-accesspoint.eu-north-1.amazonaws.com
+s3-object-lambda.eu-north-1.amazonaws.com
+s3-website.eu-north-1.amazonaws.com
+s3.dualstack.eu-south-1.amazonaws.com
+s3-accesspoint.dualstack.eu-south-1.amazonaws.com
+s3-website.dualstack.eu-south-1.amazonaws.com
+s3.eu-south-1.amazonaws.com
+s3-accesspoint.eu-south-1.amazonaws.com
+s3-object-lambda.eu-south-1.amazonaws.com
+s3-website.eu-south-1.amazonaws.com
+s3.dualstack.eu-south-2.amazonaws.com
+s3-accesspoint.dualstack.eu-south-2.amazonaws.com
+s3.eu-south-2.amazonaws.com
+s3-accesspoint.eu-south-2.amazonaws.com
+s3-object-lambda.eu-south-2.amazonaws.com
+s3-website.eu-south-2.amazonaws.com
s3.dualstack.eu-west-1.amazonaws.com
+s3-accesspoint.dualstack.eu-west-1.amazonaws.com
+s3-website.dualstack.eu-west-1.amazonaws.com
+s3.eu-west-1.amazonaws.com
+s3-accesspoint.eu-west-1.amazonaws.com
+s3-deprecated.eu-west-1.amazonaws.com
+s3-object-lambda.eu-west-1.amazonaws.com
+s3-website.eu-west-1.amazonaws.com
s3.dualstack.eu-west-2.amazonaws.com
+s3-accesspoint.dualstack.eu-west-2.amazonaws.com
s3.eu-west-2.amazonaws.com
+s3-accesspoint.eu-west-2.amazonaws.com
+s3-object-lambda.eu-west-2.amazonaws.com
s3-website.eu-west-2.amazonaws.com
s3.dualstack.eu-west-3.amazonaws.com
+s3-accesspoint.dualstack.eu-west-3.amazonaws.com
+s3-website.dualstack.eu-west-3.amazonaws.com
s3.eu-west-3.amazonaws.com
+s3-accesspoint.eu-west-3.amazonaws.com
+s3-object-lambda.eu-west-3.amazonaws.com
s3-website.eu-west-3.amazonaws.com
+s3.dualstack.il-central-1.amazonaws.com
+s3-accesspoint.dualstack.il-central-1.amazonaws.com
+s3.il-central-1.amazonaws.com
+s3-accesspoint.il-central-1.amazonaws.com
+s3-object-lambda.il-central-1.amazonaws.com
+s3-website.il-central-1.amazonaws.com
+s3.dualstack.me-central-1.amazonaws.com
+s3-accesspoint.dualstack.me-central-1.amazonaws.com
+s3.me-central-1.amazonaws.com
+s3-accesspoint.me-central-1.amazonaws.com
+s3-object-lambda.me-central-1.amazonaws.com
+s3-website.me-central-1.amazonaws.com
+s3.dualstack.me-south-1.amazonaws.com
+s3-accesspoint.dualstack.me-south-1.amazonaws.com
+s3.me-south-1.amazonaws.com
+s3-accesspoint.me-south-1.amazonaws.com
+s3-object-lambda.me-south-1.amazonaws.com
+s3-website.me-south-1.amazonaws.com
s3.amazonaws.com
+s3-1.amazonaws.com
+s3-ap-east-1.amazonaws.com
s3-ap-northeast-1.amazonaws.com
s3-ap-northeast-2.amazonaws.com
+s3-ap-northeast-3.amazonaws.com
s3-ap-south-1.amazonaws.com
s3-ap-southeast-1.amazonaws.com
s3-ap-southeast-2.amazonaws.com
s3-ca-central-1.amazonaws.com
s3-eu-central-1.amazonaws.com
+s3-eu-north-1.amazonaws.com
s3-eu-west-1.amazonaws.com
s3-eu-west-2.amazonaws.com
s3-eu-west-3.amazonaws.com
s3-external-1.amazonaws.com
+s3-fips-us-gov-east-1.amazonaws.com
s3-fips-us-gov-west-1.amazonaws.com
+mrap.accesspoint.s3-global.amazonaws.com
+s3-me-south-1.amazonaws.com
s3-sa-east-1.amazonaws.com
s3-us-east-2.amazonaws.com
+s3-us-gov-east-1.amazonaws.com
s3-us-gov-west-1.amazonaws.com
s3-us-west-1.amazonaws.com
s3-us-west-2.amazonaws.com
@@ -10303,80 +11707,282 @@ s3-website-ap-southeast-2.amazonaws.com
s3-website-eu-west-1.amazonaws.com
s3-website-sa-east-1.amazonaws.com
s3-website-us-east-1.amazonaws.com
+s3-website-us-gov-west-1.amazonaws.com
s3-website-us-west-1.amazonaws.com
s3-website-us-west-2.amazonaws.com
s3.dualstack.sa-east-1.amazonaws.com
+s3-accesspoint.dualstack.sa-east-1.amazonaws.com
+s3-website.dualstack.sa-east-1.amazonaws.com
+s3.sa-east-1.amazonaws.com
+s3-accesspoint.sa-east-1.amazonaws.com
+s3-object-lambda.sa-east-1.amazonaws.com
+s3-website.sa-east-1.amazonaws.com
s3.dualstack.us-east-1.amazonaws.com
+s3-accesspoint.dualstack.us-east-1.amazonaws.com
+s3-accesspoint-fips.dualstack.us-east-1.amazonaws.com
+s3-fips.dualstack.us-east-1.amazonaws.com
+s3-website.dualstack.us-east-1.amazonaws.com
+s3.us-east-1.amazonaws.com
+s3-accesspoint.us-east-1.amazonaws.com
+s3-accesspoint-fips.us-east-1.amazonaws.com
+s3-deprecated.us-east-1.amazonaws.com
+s3-fips.us-east-1.amazonaws.com
+s3-object-lambda.us-east-1.amazonaws.com
+s3-website.us-east-1.amazonaws.com
s3.dualstack.us-east-2.amazonaws.com
+s3-accesspoint.dualstack.us-east-2.amazonaws.com
+s3-accesspoint-fips.dualstack.us-east-2.amazonaws.com
+s3-fips.dualstack.us-east-2.amazonaws.com
s3.us-east-2.amazonaws.com
+s3-accesspoint.us-east-2.amazonaws.com
+s3-accesspoint-fips.us-east-2.amazonaws.com
+s3-deprecated.us-east-2.amazonaws.com
+s3-fips.us-east-2.amazonaws.com
+s3-object-lambda.us-east-2.amazonaws.com
s3-website.us-east-2.amazonaws.com
+s3.dualstack.us-gov-east-1.amazonaws.com
+s3-accesspoint.dualstack.us-gov-east-1.amazonaws.com
+s3-accesspoint-fips.dualstack.us-gov-east-1.amazonaws.com
+s3-fips.dualstack.us-gov-east-1.amazonaws.com
+s3.us-gov-east-1.amazonaws.com
+s3-accesspoint.us-gov-east-1.amazonaws.com
+s3-accesspoint-fips.us-gov-east-1.amazonaws.com
+s3-fips.us-gov-east-1.amazonaws.com
+s3-object-lambda.us-gov-east-1.amazonaws.com
+s3-website.us-gov-east-1.amazonaws.com
+s3.dualstack.us-gov-west-1.amazonaws.com
+s3-accesspoint.dualstack.us-gov-west-1.amazonaws.com
+s3-accesspoint-fips.dualstack.us-gov-west-1.amazonaws.com
+s3-fips.dualstack.us-gov-west-1.amazonaws.com
+s3.us-gov-west-1.amazonaws.com
+s3-accesspoint.us-gov-west-1.amazonaws.com
+s3-accesspoint-fips.us-gov-west-1.amazonaws.com
+s3-fips.us-gov-west-1.amazonaws.com
+s3-object-lambda.us-gov-west-1.amazonaws.com
+s3-website.us-gov-west-1.amazonaws.com
+s3.dualstack.us-west-1.amazonaws.com
+s3-accesspoint.dualstack.us-west-1.amazonaws.com
+s3-accesspoint-fips.dualstack.us-west-1.amazonaws.com
+s3-fips.dualstack.us-west-1.amazonaws.com
+s3-website.dualstack.us-west-1.amazonaws.com
+s3.us-west-1.amazonaws.com
+s3-accesspoint.us-west-1.amazonaws.com
+s3-accesspoint-fips.us-west-1.amazonaws.com
+s3-fips.us-west-1.amazonaws.com
+s3-object-lambda.us-west-1.amazonaws.com
+s3-website.us-west-1.amazonaws.com
+s3.dualstack.us-west-2.amazonaws.com
+s3-accesspoint.dualstack.us-west-2.amazonaws.com
+s3-accesspoint-fips.dualstack.us-west-2.amazonaws.com
+s3-fips.dualstack.us-west-2.amazonaws.com
+s3-website.dualstack.us-west-2.amazonaws.com
+s3.us-west-2.amazonaws.com
+s3-accesspoint.us-west-2.amazonaws.com
+s3-accesspoint-fips.us-west-2.amazonaws.com
+s3-deprecated.us-west-2.amazonaws.com
+s3-fips.us-west-2.amazonaws.com
+s3-object-lambda.us-west-2.amazonaws.com
+s3-website.us-west-2.amazonaws.com
+
+// Amazon SageMaker Notebook Instances
+// Submitted by AWS Security <psl-maintainers@amazon.com>
+// Reference: ce8ae0b1-0070-496d-be88-37c31837af9d
+notebook.af-south-1.sagemaker.aws
+notebook.ap-east-1.sagemaker.aws
+notebook.ap-northeast-1.sagemaker.aws
+notebook.ap-northeast-2.sagemaker.aws
+notebook.ap-northeast-3.sagemaker.aws
+notebook.ap-south-1.sagemaker.aws
+notebook.ap-south-2.sagemaker.aws
+notebook.ap-southeast-1.sagemaker.aws
+notebook.ap-southeast-2.sagemaker.aws
+notebook.ap-southeast-3.sagemaker.aws
+notebook.ap-southeast-4.sagemaker.aws
+notebook.ca-central-1.sagemaker.aws
+notebook-fips.ca-central-1.sagemaker.aws
+notebook.ca-west-1.sagemaker.aws
+notebook-fips.ca-west-1.sagemaker.aws
+notebook.eu-central-1.sagemaker.aws
+notebook.eu-central-2.sagemaker.aws
+notebook.eu-north-1.sagemaker.aws
+notebook.eu-south-1.sagemaker.aws
+notebook.eu-south-2.sagemaker.aws
+notebook.eu-west-1.sagemaker.aws
+notebook.eu-west-2.sagemaker.aws
+notebook.eu-west-3.sagemaker.aws
+notebook.il-central-1.sagemaker.aws
+notebook.me-central-1.sagemaker.aws
+notebook.me-south-1.sagemaker.aws
+notebook.sa-east-1.sagemaker.aws
+notebook.us-east-1.sagemaker.aws
+notebook-fips.us-east-1.sagemaker.aws
+notebook.us-east-2.sagemaker.aws
+notebook-fips.us-east-2.sagemaker.aws
+notebook.us-gov-east-1.sagemaker.aws
+notebook-fips.us-gov-east-1.sagemaker.aws
+notebook.us-gov-west-1.sagemaker.aws
+notebook-fips.us-gov-west-1.sagemaker.aws
+notebook.us-west-1.sagemaker.aws
+notebook.us-west-2.sagemaker.aws
+notebook-fips.us-west-2.sagemaker.aws
+notebook.cn-north-1.sagemaker.com.cn
+notebook.cn-northwest-1.sagemaker.com.cn
+
+// Amazon SageMaker Studio
+// Submitted by AWS Security <psl-maintainers@amazon.com>
+// Reference: 057ee397-6bf8-4f20-b807-d7bc145ac980
+studio.af-south-1.sagemaker.aws
+studio.ap-east-1.sagemaker.aws
+studio.ap-northeast-1.sagemaker.aws
+studio.ap-northeast-2.sagemaker.aws
+studio.ap-northeast-3.sagemaker.aws
+studio.ap-south-1.sagemaker.aws
+studio.ap-southeast-1.sagemaker.aws
+studio.ap-southeast-2.sagemaker.aws
+studio.ap-southeast-3.sagemaker.aws
+studio.ca-central-1.sagemaker.aws
+studio.eu-central-1.sagemaker.aws
+studio.eu-north-1.sagemaker.aws
+studio.eu-south-1.sagemaker.aws
+studio.eu-west-1.sagemaker.aws
+studio.eu-west-2.sagemaker.aws
+studio.eu-west-3.sagemaker.aws
+studio.il-central-1.sagemaker.aws
+studio.me-central-1.sagemaker.aws
+studio.me-south-1.sagemaker.aws
+studio.sa-east-1.sagemaker.aws
+studio.us-east-1.sagemaker.aws
+studio.us-east-2.sagemaker.aws
+studio.us-gov-east-1.sagemaker.aws
+studio-fips.us-gov-east-1.sagemaker.aws
+studio.us-gov-west-1.sagemaker.aws
+studio-fips.us-gov-west-1.sagemaker.aws
+studio.us-west-1.sagemaker.aws
+studio.us-west-2.sagemaker.aws
+studio.cn-north-1.sagemaker.com.cn
+studio.cn-northwest-1.sagemaker.com.cn
+
+// Analytics on AWS
+// Submitted by AWS Security <psl-maintainers@amazon.com>
+// Reference: 955f9f40-a495-4e73-ae85-67b77ac9cadd
+analytics-gateway.ap-northeast-1.amazonaws.com
+analytics-gateway.ap-northeast-2.amazonaws.com
+analytics-gateway.ap-south-1.amazonaws.com
+analytics-gateway.ap-southeast-1.amazonaws.com
+analytics-gateway.ap-southeast-2.amazonaws.com
+analytics-gateway.eu-central-1.amazonaws.com
+analytics-gateway.eu-west-1.amazonaws.com
+analytics-gateway.us-east-1.amazonaws.com
+analytics-gateway.us-east-2.amazonaws.com
+analytics-gateway.us-west-2.amazonaws.com
+
+// AWS Amplify
+// Submitted by AWS Security <psl-maintainers@amazon.com>
+// Reference: 5ecce854-c033-4fc4-a755-1a9916d9a9bb
+*.amplifyapp.com
+
+// AWS App Runner
+// Submitted by AWS Security <psl-maintainers@amazon.com>
+// Reference: 6828c008-ba5d-442f-ade5-48da4e7c2316
+*.awsapprunner.com
// AWS Cloud9
// Submitted by: AWS Security <psl-maintainers@amazon.com>
-// Reference: 2b6dfa9a-3a7f-4367-b2e7-0321e77c0d59
+// Reference: 30717f72-4007-4f0f-8ed4-864c6f2efec9
+webview-assets.aws-cloud9.af-south-1.amazonaws.com
vfs.cloud9.af-south-1.amazonaws.com
webview-assets.cloud9.af-south-1.amazonaws.com
+webview-assets.aws-cloud9.ap-east-1.amazonaws.com
vfs.cloud9.ap-east-1.amazonaws.com
webview-assets.cloud9.ap-east-1.amazonaws.com
+webview-assets.aws-cloud9.ap-northeast-1.amazonaws.com
vfs.cloud9.ap-northeast-1.amazonaws.com
webview-assets.cloud9.ap-northeast-1.amazonaws.com
+webview-assets.aws-cloud9.ap-northeast-2.amazonaws.com
vfs.cloud9.ap-northeast-2.amazonaws.com
webview-assets.cloud9.ap-northeast-2.amazonaws.com
+webview-assets.aws-cloud9.ap-northeast-3.amazonaws.com
vfs.cloud9.ap-northeast-3.amazonaws.com
webview-assets.cloud9.ap-northeast-3.amazonaws.com
+webview-assets.aws-cloud9.ap-south-1.amazonaws.com
vfs.cloud9.ap-south-1.amazonaws.com
webview-assets.cloud9.ap-south-1.amazonaws.com
+webview-assets.aws-cloud9.ap-southeast-1.amazonaws.com
vfs.cloud9.ap-southeast-1.amazonaws.com
webview-assets.cloud9.ap-southeast-1.amazonaws.com
+webview-assets.aws-cloud9.ap-southeast-2.amazonaws.com
vfs.cloud9.ap-southeast-2.amazonaws.com
webview-assets.cloud9.ap-southeast-2.amazonaws.com
+webview-assets.aws-cloud9.ca-central-1.amazonaws.com
vfs.cloud9.ca-central-1.amazonaws.com
webview-assets.cloud9.ca-central-1.amazonaws.com
+webview-assets.aws-cloud9.eu-central-1.amazonaws.com
vfs.cloud9.eu-central-1.amazonaws.com
webview-assets.cloud9.eu-central-1.amazonaws.com
+webview-assets.aws-cloud9.eu-north-1.amazonaws.com
vfs.cloud9.eu-north-1.amazonaws.com
webview-assets.cloud9.eu-north-1.amazonaws.com
+webview-assets.aws-cloud9.eu-south-1.amazonaws.com
vfs.cloud9.eu-south-1.amazonaws.com
webview-assets.cloud9.eu-south-1.amazonaws.com
+webview-assets.aws-cloud9.eu-west-1.amazonaws.com
vfs.cloud9.eu-west-1.amazonaws.com
webview-assets.cloud9.eu-west-1.amazonaws.com
+webview-assets.aws-cloud9.eu-west-2.amazonaws.com
vfs.cloud9.eu-west-2.amazonaws.com
webview-assets.cloud9.eu-west-2.amazonaws.com
+webview-assets.aws-cloud9.eu-west-3.amazonaws.com
vfs.cloud9.eu-west-3.amazonaws.com
webview-assets.cloud9.eu-west-3.amazonaws.com
+webview-assets.aws-cloud9.il-central-1.amazonaws.com
+vfs.cloud9.il-central-1.amazonaws.com
+webview-assets.aws-cloud9.me-south-1.amazonaws.com
vfs.cloud9.me-south-1.amazonaws.com
webview-assets.cloud9.me-south-1.amazonaws.com
+webview-assets.aws-cloud9.sa-east-1.amazonaws.com
vfs.cloud9.sa-east-1.amazonaws.com
webview-assets.cloud9.sa-east-1.amazonaws.com
+webview-assets.aws-cloud9.us-east-1.amazonaws.com
vfs.cloud9.us-east-1.amazonaws.com
webview-assets.cloud9.us-east-1.amazonaws.com
+webview-assets.aws-cloud9.us-east-2.amazonaws.com
vfs.cloud9.us-east-2.amazonaws.com
webview-assets.cloud9.us-east-2.amazonaws.com
+webview-assets.aws-cloud9.us-west-1.amazonaws.com
vfs.cloud9.us-west-1.amazonaws.com
webview-assets.cloud9.us-west-1.amazonaws.com
+webview-assets.aws-cloud9.us-west-2.amazonaws.com
vfs.cloud9.us-west-2.amazonaws.com
webview-assets.cloud9.us-west-2.amazonaws.com
// AWS Elastic Beanstalk
-// Submitted by Luke Wells <psl-maintainers@amazon.com>
-// Reference: aa202394-43a0-4857-b245-8db04549137e
+// Submitted by AWS Security <psl-maintainers@amazon.com>
+// Reference: bb5a965c-dec3-4967-aa22-e306ad064797
cn-north-1.eb.amazonaws.com.cn
cn-northwest-1.eb.amazonaws.com.cn
elasticbeanstalk.com
+af-south-1.elasticbeanstalk.com
+ap-east-1.elasticbeanstalk.com
ap-northeast-1.elasticbeanstalk.com
ap-northeast-2.elasticbeanstalk.com
ap-northeast-3.elasticbeanstalk.com
ap-south-1.elasticbeanstalk.com
ap-southeast-1.elasticbeanstalk.com
ap-southeast-2.elasticbeanstalk.com
+ap-southeast-3.elasticbeanstalk.com
ca-central-1.elasticbeanstalk.com
eu-central-1.elasticbeanstalk.com
+eu-north-1.elasticbeanstalk.com
+eu-south-1.elasticbeanstalk.com
eu-west-1.elasticbeanstalk.com
eu-west-2.elasticbeanstalk.com
eu-west-3.elasticbeanstalk.com
+il-central-1.elasticbeanstalk.com
+me-south-1.elasticbeanstalk.com
sa-east-1.elasticbeanstalk.com
us-east-1.elasticbeanstalk.com
us-east-2.elasticbeanstalk.com
+us-gov-east-1.elasticbeanstalk.com
us-gov-west-1.elasticbeanstalk.com
us-west-1.elasticbeanstalk.com
us-west-2.elasticbeanstalk.com
@@ -10392,6 +11998,11 @@ us-west-2.elasticbeanstalk.com
// Reference: d916759d-a08b-4241-b536-4db887383a6a
awsglobalaccelerator.com
+// AWS re:Post Private
+// Submitted by AWS Security <psl-maintainers@amazon.com>
+// Reference: 83385945-225f-416e-9aa0-ad0632bfdcee
+*.private.repost.aws
+
// eero
// Submitted by Yue Kang <eero-dynamic-dns@amazon.com>
// Reference: 264afe70-f62c-4c02-8ab9-b5281ed24461
@@ -10409,6 +12020,10 @@ tele.amune.org
// Submitted by Apigee Security Team <security@apigee.com>
apigee.io
+// Apis Networks: https://apisnetworks.com
+// Submitted by Matt Saladna <matt@apisnetworks.com>
+panel.dev
+
// Apphud : https://apphud.com
// Submitted by Alexander Selivanov <alex@apphud.com>
siiites.com
@@ -10426,6 +12041,10 @@ appudo.net
// Submitted by Thomas Orozco <thomas@aptible.com>
on-aptible.com
+// Aquapal : https://aquapal.net/
+// Submitted by Aki Ueno <admin@aquapal.net>
+f5.si
+
// ASEINet : https://www.aseinet.com/
// Submitted by Asei SEKIGUCHI <mail@aseinet.com>
user.aseinet.ne.jp
@@ -10520,6 +12139,10 @@ beagleboard.io
// Submitted by Lev Nekrasov <lnekrasov@beget.com>
*.beget.app
+// Besties : https://besties.house
+// Submitted by Hazel Cora <hazy@besties.house>
+pages.gay
+
// BetaInABox
// Submitted by Adrian <adrian@betainabox.com>
betainabox.com
@@ -10565,6 +12188,10 @@ square7.de
bplaced.net
square7.net
+// Brave : https://brave.com
+// Submitted by Andrea Brancaleoni <abrancaleoni@brave.com>
+*.s.brave.io
+
// Brendly : https://brendly.rs
// Submitted by Dusan Radovanovic <dusan.radovanovic@brendly.rs>
shop.brendly.rs
@@ -10590,7 +12217,9 @@ mycd.eu
// Canva Pty Ltd : https://canva.com/
// Submitted by Joel Aquilina <publicsuffixlist@canva.com>
canva-apps.cn
+*.my.canvasite.cn
canva-apps.com
+*.my.canva.site
// Carrd : https://carrd.co
// Submitted by AJ <aj@carrd.co>
@@ -10782,6 +12411,10 @@ co.no
webhosting.be
hosting-cluster.nl
+// Convex : https://convex.dev/
+// Submitted by James Cowling <security@convex.dev>
+convex.site
+
// Coordination Center for TLD RU and XN--P1AI : https://cctld.ru/en/domains/domens_ru/reserved/
// Submitted by George Georgievsky <gug@cctld.ru>
ac.ru
@@ -10803,10 +12436,18 @@ feste-ip.net
knx-server.net
static-access.net
+// cPanel L.L.C. : https://www.cpanel.net/
+// Submitted by Dustin Scherer <public.suffix@cpanel.net>
+*.cprapid.com
+
// Craynic, s.r.o. : http://www.craynic.com/
// Submitted by Ales Krajnik <ales.krajnik@craynic.com>
realm.cz
+// Crisp IM SAS : https://crisp.chat/
+// Submitted by Baptiste Jamin <hostmaster@crisp.chat>
+on.crisp.email
+
// Cryptonomic : https://cryptonomic.net/
// Submitted by Andrew Cady <public-suffix-list@cryptonomic.net>
*.cryptonomic.net
@@ -10827,6 +12468,13 @@ curv.dev
*.ocp.customer-oci.com
*.ocs.customer-oci.com
+// Cyclic Software : https://www.cyclic.sh
+// Submitted by Kam Lasater <dns-admin@cyclic.sh>
+cyclic.app
+cyclic.cloud
+cyclic-app.com
+cyclic.co.in
+
// cyon GmbH : https://www.cyon.ch/
// Submitted by Dominic Luechinger <dol@cyon.ch>
cyon.link
@@ -11307,6 +12955,10 @@ e4.cz
easypanel.app
easypanel.host
+// EasyWP : https://www.easywp.com
+// Submitted by <infracloudteam@namecheap.com>
+*.ewp.live
+
// Elementor : Elementor Ltd.
// Submitted by Anton Barkan <antonb@elementor.com>
elementor.cloud
@@ -11421,10 +13073,6 @@ url.tw
// Submitted by Eric Jiang <eric@fabrica.dev>
onfabrica.com
-// Facebook, Inc.
-// Submitted by Peter Ruibal <public-suffix@fb.com>
-apps.fbsbx.com
-
// FAITID : https://faitid.org/
// Submitted by Maxim Alzoba <tech.contact@faitid.org>
// https://www.flexireg.net/stat_info
@@ -11582,6 +13230,10 @@ flap.id
onflashdrive.app
fldrv.com
+// FlutterFlow : https://flutterflow.io
+// Submitted by Anton Emelyanov <anton@flutterflow.io>
+flutterflow.app
+
// fly.io: https://fly.io
// Submitted by Kurt Mackey <kurt@fly.io>
fly.dev
@@ -11592,7 +13244,7 @@ shw.io
// Submitted by Jonathan Rudenberg <jonathan@flynn.io>
flynnhosting.net
-// Forgerock : https://www.forgerock.com
+// Forgerock : https://www.forgerock.com
// Submitted by Roderick Parr <roderick.parr@forgerock.com>
forgeblocks.com
id.forgerock.io
@@ -11639,7 +13291,7 @@ freemyip.com
// Submitted by Daniel A. Maierhofer <vorstand@funkfeuer.at>
wien.funkfeuer.at
-// Futureweb OG : http://www.futureweb.at
+// Futureweb GmbH : https://www.futureweb.at
// Submitted by Andreas Schnederle-Wagner <schnederle@futureweb.at>
*.futurecms.at
*.ex.futurecms.at
@@ -11650,6 +13302,10 @@ futuremailing.at
*.kunden.ortsinfo.at
*.statics.cloud
+// GCom Internet : https://www.gcom.net.au
+// Submitted by Leo Julius <support@gcom.net.au>
+aliases121.com
+
// GDS : https://www.gov.uk/service-manual/technology/managing-domain-names
// Submitted by Stephen Ford <hostmaster@digital.cabinet-office.gov.uk>
independent-commission.uk
@@ -11833,10 +13489,6 @@ london.cloudapps.digital
// Submitted by Richard Baker <richard.baker@digital.cabinet-office.gov.uk>
pymnt.uk
-// UKHomeOffice : https://www.gov.uk/government/organisations/home-office
-// Submitted by Jon Shanks <jon.shanks@digital.homeoffice.gov.uk>
-homeoffice.gov.uk
-
// GlobeHosting, Inc.
// Submitted by Zoltan Egresi <egresi@globehosting.com>
ro.im
@@ -11847,8 +13499,7 @@ goip.de
// Google, Inc.
// Submitted by Eduardo Vela <evn@google.com>
-run.app
-a.run.app
+*.run.app
web.app
*.0emm.com
appspot.com
@@ -12003,6 +13654,12 @@ ravendb.run
// Submitted by Krzysztof Wolski <krzysztof.wolski@home.eu>
homesklep.pl
+// Homebase : https://homebase.id/
+// Submitted by Jason Babo <info@homebase.id>
+*.kin.one
+*.id.pub
+*.kin.pub
+
// Hong Kong Productivity Council: https://www.hkpc.org/
// Submitted by SECaaS Team <summchan@hkpc.org>
secaas.hk
@@ -12146,7 +13803,6 @@ iobb.net
// Submitted by Ihor Kolodyuk <ik@jelastic.com>
mel.cloudlets.com.au
cloud.interhostsolutions.be
-users.scale.virtualcloud.com.br
mycloud.by
alp1.ae.flow.ch
appengine.flow.ch
@@ -12170,9 +13826,7 @@ ch.trendhosting.cloud
de.trendhosting.cloud
jele.club
amscompute.com
-clicketcloud.com
dopaas.com
-hidora.com
paas.hosted-by-previder.com
rag-cloud.hosteur.com
rag-cloud-ch.hosteur.com
@@ -12459,6 +14113,11 @@ memset.net
// Submitted by Ruben Schmidmeister <psl-maintainers@messerli.ch>
messerli.app
+// Meta Platforms, Inc. : https://meta.com/
+// Submitted by Jacob Cordero <public-suffix@meta.com>
+atmeta.com
+apps.fbsbx.com
+
// MetaCentrum, CESNET z.s.p.o. : https://www.metacentrum.cz/en/
// Submitted by Zdeněk Šustr <zdenek.sustr@cesnet.cz>
*.cloud.metacentrum.cz
@@ -12479,19 +14138,32 @@ co.pl
// Microsoft Corporation : http://microsoft.com
// Submitted by Public Suffix List Admin <msftpsladmin@microsoft.com>
+// Managed by Corporate Domains
+// Microsoft Azure : https://home.azure
*.azurecontainer.io
+cloudapp.azure.com
+azure-api.net
+azureedge.net
+azurefd.net
azurewebsites.net
azure-mobile.net
-cloudapp.net
azurestaticapps.net
1.azurestaticapps.net
2.azurestaticapps.net
3.azurestaticapps.net
+4.azurestaticapps.net
+5.azurestaticapps.net
+6.azurestaticapps.net
+7.azurestaticapps.net
centralus.azurestaticapps.net
eastasia.azurestaticapps.net
eastus2.azurestaticapps.net
westeurope.azurestaticapps.net
westus2.azurestaticapps.net
+cloudapp.net
+trafficmanager.net
+blob.core.windows.net
+servicebus.windows.net
// minion.systems : http://minion.systems
// Submitted by Robert Böttinger <r@minion.systems>
@@ -12505,6 +14177,10 @@ mintere.site
// Submitted by Grayson Martin <grayson.martin@mobileeducation.us>
forte.id
+// MODX Systems LLC : https://modx.com
+// Submitted by Elizabeth Southwell <elizabeth@modx.com>
+modx.dev
+
// Mozilla Corporation : https://mozilla.com
// Submitted by Ben Francis <bfrancis@mozilla.com>
mozilla-iot.org
@@ -12566,6 +14242,10 @@ jp.ngrok.io
sa.ngrok.io
us.ngrok.io
ngrok.pizza
+ngrok.pro
+
+// Nicolaus Copernicus University in Torun - MSK TORMAN (https://www.man.torun.pl)
+torun.pl
// Nimbus Hosting Ltd. : https://www.nimbushosting.co.uk/
// Submitted by Nicholas Ford <nick@nimbushosting.co.uk>
@@ -12878,7 +14558,8 @@ on-web.fr
// Platform.sh : https://platform.sh
// Submitted by Nikola Kotur <nikola@platform.sh>
-bc.platform.sh
+*.upsun.app
+upsunapp.com
ent.platform.sh
eu.platform.sh
us.platform.sh
@@ -12897,6 +14578,10 @@ pdns.page
plesk.page
pleskns.com
+// Pley AB : https://www.pley.com/
+// Submitted by Henning Pohl <infra@pley.com>
+pley.games
+
// Port53 : https://port53.io/
// Submitted by Maximilian Schieder <maxi@zeug.co>
dyn53.io
@@ -12973,6 +14658,8 @@ qbuser.com
// Rad Web Hosting: https://radwebhosting.com
// Submitted by Scott Claeys <s.claeys@radwebhosting.com>
cloudsite.builders
+myradweb.net
+servername.us
// Redgate Software: https://red-gate.com
// Submitted by Andrew Farries <andrew.farries@red-gate.com>
@@ -13039,11 +14726,40 @@ app.render.com
onrender.com
// Repl.it : https://repl.it
-// Submitted by Lincoln Bergeson <lincoln@replit.com>
+// Submitted by Lincoln Bergeson <psl@repl.it>
+replit.app
+id.replit.app
firewalledreplit.co
id.firewalledreplit.co
repl.co
id.repl.co
+replit.dev
+archer.replit.dev
+bones.replit.dev
+canary.replit.dev
+global.replit.dev
+hacker.replit.dev
+id.replit.dev
+janeway.replit.dev
+kim.replit.dev
+kira.replit.dev
+kirk.replit.dev
+odo.replit.dev
+paris.replit.dev
+picard.replit.dev
+pike.replit.dev
+prerelease.replit.dev
+reed.replit.dev
+riker.replit.dev
+sisko.replit.dev
+spock.replit.dev
+staging.replit.dev
+sulu.replit.dev
+tarpit.replit.dev
+teams.replit.dev
+tucker.replit.dev
+wesley.replit.dev
+worf.replit.dev
repl.run
// Resin.io : https://resin.io
@@ -13140,10 +14856,11 @@ from.tv
sakura.tv
// Salesforce.com, Inc. https://salesforce.com/
-// Submitted by Michael Biven <mbiven@salesforce.com>
+// Submitted by Michael Biven <mbiven@salesforce.com> and Aaron Romeo <aaron.romeo@salesforce.com>
*.builder.code.com
*.dev-builder.code.com
*.stg-builder.code.com
+*.001.test.code-builder-stg.platform.salesforce.com
// Sandstorm Development Group, Inc. : https://sandcats.io/
// Submitted by Asheesh Laroia <asheesh@sandstorm.io>
@@ -13159,6 +14876,7 @@ logoip.com
fr-par-1.baremetal.scw.cloud
fr-par-2.baremetal.scw.cloud
nl-ams-1.baremetal.scw.cloud
+cockpit.fr-par.scw.cloud
fnc.fr-par.scw.cloud
functions.fnc.fr-par.scw.cloud
k8s.fr-par.scw.cloud
@@ -13169,11 +14887,13 @@ whm.fr-par.scw.cloud
priv.instances.scw.cloud
pub.instances.scw.cloud
k8s.scw.cloud
+cockpit.nl-ams.scw.cloud
k8s.nl-ams.scw.cloud
nodes.k8s.nl-ams.scw.cloud
s3.nl-ams.scw.cloud
s3-website.nl-ams.scw.cloud
whm.nl-ams.scw.cloud
+cockpit.pl-waw.scw.cloud
k8s.pl-waw.scw.cloud
nodes.k8s.pl-waw.scw.cloud
s3.pl-waw.scw.cloud
@@ -13281,6 +15001,20 @@ bounty-full.com
alpha.bounty-full.com
beta.bounty-full.com
+// Smallregistry by Promopixel SARL: https://www.smallregistry.net
+// Former AFNIC's SLDs
+// Submitted by Jérôme Lipowicz <support@promopixel.com>
+aeroport.fr
+avocat.fr
+chambagri.fr
+chirurgiens-dentistes.fr
+experts-comptables.fr
+medecin.fr
+notaires.fr
+pharmacien.fr
+port.fr
+veterinaire.fr
+
// Small Technology Foundation : https://small-tech.org
// Submitted by Aral Balkan <aral@small-tech.org>
small-web.org
@@ -13308,6 +15042,14 @@ srht.site
// Submitted by Adrien Gillon <adrien+public-suffix-list@stackhero.io>
stackhero-network.com
+// STACKIT : https://www.stackit.de/en/
+// Submitted by STACKIT-DNS Team (Simon Stier) <stackit-dns@mail.schwarz>
+runs.onstackit.cloud
+stackit.gg
+stackit.rocks
+stackit.run
+stackit.zone
+
// Staclar : https://staclar.com
// Submitted by Q Misell <q@staclar.com>
musician.io
@@ -13374,10 +15116,33 @@ myspreadshop.co.uk
// Submitted by Jacob Lee <jacob@stdlib.com>
api.stdlib.com
+// stereosense GmbH : https://www.involve.me
+// Submitted by Florian Burmann <publicsuffix@involve.me>
+feedback.ac
+forms.ac
+assessments.cx
+calculators.cx
+funnels.cx
+paynow.cx
+quizzes.cx
+researched.cx
+tests.cx
+surveys.so
+
+// Storipress : https://storipress.com
+// Submitted by Benno Liu <benno@storipress.com>
+storipress.app
+
// Storj Labs Inc. : https://storj.io/
// Submitted by Philip Hutchins <hostmaster@storj.io>
storj.farm
+// Streak : https://streak.com
+// Submitted by Blake Kadatz <eng@streak.com>
+streak-link.com
+streaklinks.com
+streakusercontent.com
+
// Studenten Net Twente : http://www.snt.utwente.nl/
// Submitted by Silke Hofstra <syscom@snt.utwente.nl>
utwente.io
@@ -13440,6 +15205,7 @@ taifun-dns.de
// Submitted by David Anderson <danderson@tailscale.com>
beta.tailscale.net
ts.net
+*.c.ts.net
// TASK geographical domains (www.task.gda.pl/uslugi/dns)
gda.pl
@@ -13642,7 +15408,6 @@ de.gt
to.gt
be.gy
cc.hn
-blog.kg
io.kg
jp.kg
tv.kg
@@ -13676,6 +15441,11 @@ v.ua
// Submitted by Masayuki Note <masa@blade.wafflecell.com>
wafflecell.com
+// Webflow, Inc. : https://www.webflow.com
+// Submitted by Webflow Security Team <security@webflow.com>
+webflow.io
+webflowtest.io
+
// WebHare bv: https://www.webhare.com/
// Submitted by Arnold Hendriks <info@webhare.com>
*.webhare.dev
@@ -13741,6 +15511,8 @@ js.wpenginepowered.com
// Submitted by Shahar Talmi <shahar@wix.com>
wixsite.com
editorx.io
+wixstudio.io
+wix.run
// XenonCloud GbR: https://xenoncloud.net
// Submitted by Julian Uphoff <publicsuffixlist@xenoncloud.net>
@@ -13793,6 +15565,10 @@ noho.st
za.net
za.org
+// ZAP-Hosting GmbH & Co. KG : https://zap-hosting.com
+// Submitted by Julian Alker <security@zap-hosting.com>
+zap.cloud
+
// Zine EOOD : https://zine.bg/
// Submitted by Martin Angelov <martin@zine.bg>
bss.design
diff --git a/ansible_collections/community/dns/tests/ee/roles/wait_for_txt/tasks/main.yml b/ansible_collections/community/dns/tests/ee/roles/wait_for_txt/tasks/main.yml
index 43941d042..7c7de6b70 100644
--- a/ansible_collections/community/dns/tests/ee/roles/wait_for_txt/tasks/main.yml
+++ b/ansible_collections/community/dns/tests/ee/roles/wait_for_txt/tasks/main.yml
@@ -3,16 +3,12 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
-- name: Get TXT records for github.com
- shell: |
- dig -t TXT github.com +short | sed -e 's/" "//g' -e 's/"//g'
- register: dig
-
- name: Wait for existing TXT entry
community.dns.wait_for_txt:
records:
- name: github.com
- values: "{{ dig.stdout_lines }}"
+ values: |
+ {{ query('community.dns.lookup_as_dict', 'github.com', type='TXT') | map(attribute='value') | list }}
- name: github.io
values: []
query_timeout: 20
diff --git a/ansible_collections/community/dns/tests/integration/replace-requirements.sh b/ansible_collections/community/dns/tests/integration/replace-requirements.sh
new file mode 100755
index 000000000..c3a52f5d1
--- /dev/null
+++ b/ansible_collections/community/dns/tests/integration/replace-requirements.sh
@@ -0,0 +1,10 @@
+#!/usr/bin/env bash
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+DIRECTORY="$(dirname "$0")"
+
+if [ -e "${DIRECTORY}/$1" ]; then
+ cp "${DIRECTORY}/$1" "${DIRECTORY}/requirements.txt"
+fi
diff --git a/ansible_collections/community/dns/tests/integration/requirements-stable-2.10.txt b/ansible_collections/community/dns/tests/integration/requirements-stable-2.10.txt
new file mode 100644
index 000000000..af90be668
--- /dev/null
+++ b/ansible_collections/community/dns/tests/integration/requirements-stable-2.10.txt
@@ -0,0 +1,7 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+ipaddress ; python_version < '3.3'
+
+dnspython < 2.4.0
diff --git a/ansible_collections/community/dns/tests/integration/requirements-stable-2.9.txt b/ansible_collections/community/dns/tests/integration/requirements-stable-2.9.txt
new file mode 100644
index 000000000..af90be668
--- /dev/null
+++ b/ansible_collections/community/dns/tests/integration/requirements-stable-2.9.txt
@@ -0,0 +1,7 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+ipaddress ; python_version < '3.3'
+
+dnspython < 2.4.0
diff --git a/ansible_collections/community/dns/tests/integration/requirements.txt b/ansible_collections/community/dns/tests/integration/requirements.txt
new file mode 100644
index 000000000..5e4bca63f
--- /dev/null
+++ b/ansible_collections/community/dns/tests/integration/requirements.txt
@@ -0,0 +1,7 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+ipaddress ; python_version < '3.3'
+
+dnspython
diff --git a/ansible_collections/community/dns/tests/integration/targets/lookup_lookup/aliases b/ansible_collections/community/dns/tests/integration/targets/lookup_lookup/aliases
new file mode 100644
index 000000000..abc0d5476
--- /dev/null
+++ b/ansible_collections/community/dns/tests/integration/targets/lookup_lookup/aliases
@@ -0,0 +1,5 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+shippable/posix/group1
diff --git a/ansible_collections/community/dns/tests/integration/targets/lookup_lookup/tasks/main.yml b/ansible_collections/community/dns/tests/integration/targets/lookup_lookup/tasks/main.yml
new file mode 100644
index 000000000..52ba9a46c
--- /dev/null
+++ b/ansible_collections/community/dns/tests/integration/targets/lookup_lookup/tasks/main.yml
@@ -0,0 +1,26 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Look up some records
+ ansible.builtin.set_fact:
+ ansible_a: >-
+ {{ query('community.dns.lookup', 'ansible.com', type='A') }}
+ ansible_aaaa: >-
+ {{ query('community.dns.lookup', 'ansible.com', type='AAAA', server='9.9.9.9') }}
+ ansible_txt: >-
+ {{ query('community.dns.lookup', 'ansible.com', type='TXT', server=['1.1.1.1', '8.8.8.8', 'dns9.quad9.net.']) }}
+ ansible_empty: >-
+ {{ query('community.dns.lookup', 'does-not-exist.ansible.com') }}
+
+- name: Check results
+ assert:
+ that:
+ - ansible_a | length > 0
+ - ansible_a[0] is regex("^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$")
+ - ansible_aaaa | length > 0
+ - ansible_aaaa[0] is regex("^[0-9a-fA-F:]+$")
+ - ansible_txt | length > 0
+ - ansible_txt[0] is string
+ - ansible_empty | length == 0
diff --git a/ansible_collections/community/dns/tests/integration/targets/lookup_lookup_as_dict/aliases b/ansible_collections/community/dns/tests/integration/targets/lookup_lookup_as_dict/aliases
new file mode 100644
index 000000000..abc0d5476
--- /dev/null
+++ b/ansible_collections/community/dns/tests/integration/targets/lookup_lookup_as_dict/aliases
@@ -0,0 +1,5 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+shippable/posix/group1
diff --git a/ansible_collections/community/dns/tests/integration/targets/lookup_lookup_as_dict/tasks/main.yml b/ansible_collections/community/dns/tests/integration/targets/lookup_lookup_as_dict/tasks/main.yml
new file mode 100644
index 000000000..3ba6f52f0
--- /dev/null
+++ b/ansible_collections/community/dns/tests/integration/targets/lookup_lookup_as_dict/tasks/main.yml
@@ -0,0 +1,31 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Look up some records
+ ansible.builtin.set_fact:
+ ansible_a: >-
+ {{ query('community.dns.lookup_as_dict', 'ansible.com', type='A') }}
+ ansible_aaaa: >-
+ {{ query('community.dns.lookup_as_dict', 'ansible.com', type='AAAA', server='9.9.9.9') }}
+ ansible_txt: >-
+ {{ query('community.dns.lookup_as_dict', 'ansible.com', type='TXT', server=['1.1.1.1', '8.8.8.8', 'dns9.quad9.net.']) }}
+ ansible_empty: >-
+ {{ query('community.dns.lookup_as_dict', 'does-not-exist.ansible.com') }}
+
+- name: Check results
+ assert:
+ that:
+ - ansible_a | length > 0
+ - ansible_a[0].address is string
+ - ansible_a[0].address is regex("^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$")
+ - ansible_aaaa | length > 0
+ - ansible_aaaa[0].address is string
+ - ansible_aaaa[0].address is regex("^[0-9a-fA-F:]+$")
+ - ansible_txt | length > 0
+ - ansible_txt[0].strings is sequence
+ - ansible_txt[0].strings[0] is string
+ - ansible_txt[0].value is string
+ - ansible_txt | map(attribute='strings') | map('join') | list == ansible_txt | map(attribute='value') | list
+ - ansible_empty | length == 0
diff --git a/ansible_collections/community/dns/tests/integration/targets/nameserver_info/tasks/main.yml b/ansible_collections/community/dns/tests/integration/targets/nameserver_info/tasks/main.yml
new file mode 100644
index 000000000..0b074df5a
--- /dev/null
+++ b/ansible_collections/community/dns/tests/integration/targets/nameserver_info/tasks/main.yml
@@ -0,0 +1,78 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Retrieve name servers of two DNS names
+ community.dns.nameserver_info:
+ name:
+ - www.example.com
+ - example.org
+ register: result
+
+- name: Show TXT values for www.example.com for all nameservers
+ ansible.builtin.debug:
+ msg: '{{ result }}'
+
+- name: Show nameservers for www.example.com
+ ansible.builtin.debug:
+ msg: '{{ result.results[0].nameservers }}'
+
+- name: Show TXT values for www.example.com for all nameservers
+ ansible.builtin.debug:
+ msg: '{{ result.results[0].nameservers[0] }}'
+
+- name: Validate results
+ assert:
+ that:
+ - result.results[0].nameservers[0] == 'a.iana-servers.net.'
+ - result.results[0].nameservers[1] == 'b.iana-servers.net.'
+ - result.results[0].nameservers[0] != 'b.iana-servers.net.'
+
+- name: Retrieve name servers of two DNS names using custom DNS servers
+ community.dns.nameserver_info:
+ name:
+ - www.example.com
+ - example.org
+ server:
+ # Quad9 servers (https://en.wikipedia.org/wiki/Quad9#Service)
+ - 9.9.9.9
+ - 149.112.112.112
+ - 2620:fe::9
+ - 2620:fe::fe
+ register: result
+
+- name: Show TXT values for www.example.com for all nameservers
+ ansible.builtin.debug:
+ msg: '{{ result }}'
+
+- name: Show nameservers for www.example.com
+ ansible.builtin.debug:
+ msg: '{{ result.results[0].nameservers }}'
+
+- name: Show TXT values for www.example.com for first nameserver
+ ansible.builtin.debug:
+ msg: '{{ result.results[0].nameservers[0] }}'
+
+- name: Validate results
+ assert:
+ that:
+ - result.results[0].nameservers[0] == 'a.iana-servers.net.'
+ - result.results[0].nameservers[1] == 'b.iana-servers.net.'
+ - result.results[0].nameservers[0] != 'b.iana-servers.net.'
+
+- name: Retrieve name servers of a DNS name that do not exist
+ community.dns.nameserver_info:
+ name:
+ - foo.bar.example.com
+ register: result
+
+- name: Show TXT values for www.example.com for all nameservers
+ ansible.builtin.debug:
+ msg: '{{ result }}'
+
+- name: Validate results
+ assert:
+ that:
+ - result.results[0].nameservers[0] == 'a.iana-servers.net.'
+ - result.results[0].nameservers[1] == 'b.iana-servers.net.'
diff --git a/ansible_collections/community/dns/tests/integration/targets/nameserver_record_info/tasks/main.yml b/ansible_collections/community/dns/tests/integration/targets/nameserver_record_info/tasks/main.yml
new file mode 100644
index 000000000..b03b641fe
--- /dev/null
+++ b/ansible_collections/community/dns/tests/integration/targets/nameserver_record_info/tasks/main.yml
@@ -0,0 +1,56 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Retrieve TXT values from all nameservers for two DNS names
+ community.dns.nameserver_record_info:
+ name:
+ - www.example.com
+ - example.org
+ type: TXT
+ register: result
+
+- name: Show TXT values for www.example.com for all nameservers
+ ansible.builtin.debug:
+ msg: '{{ result }}'
+
+- name: Show TXT values for www.example.com for first nameserver
+ ansible.builtin.debug:
+ msg: '{{ result.results[0].result[0].nameserver }}'
+
+- name: Validate results
+ assert:
+ that:
+ - result.results[0].result[0].nameserver == 'a.iana-servers.net.'
+ - result.results[0].result[1].nameserver == 'b.iana-servers.net.'
+ - result.results[0].result[0].nameserver != 'b.iana-servers.net.'
+
+- name: Retrieve TXT values from all nameservers for two DNS names using custom DNS servers
+ community.dns.nameserver_record_info:
+ name:
+ - www.example.com
+ - example.org
+ type: TXT
+ server:
+ # Quad9 servers (https://en.wikipedia.org/wiki/Quad9#Service)
+ - 9.9.9.9
+ - 149.112.112.112
+ - 2620:fe::9
+ - 2620:fe::fe
+ register: result
+
+- name: Show TXT values for www.example.com for all nameservers
+ ansible.builtin.debug:
+ msg: '{{ result }}'
+
+- name: Show TXT values for www.example.com for all nameservers
+ ansible.builtin.debug:
+ msg: '{{ result.results[0].result[0].nameserver }}'
+
+- name: Validate results
+ assert:
+ that:
+ - result.results[0].result[0].nameserver == 'a.iana-servers.net.'
+ - result.results[0].result[1].nameserver == 'b.iana-servers.net.'
+ - result.results[0].result[0].nameserver != 'b.iana-servers.net.'
diff --git a/ansible_collections/community/dns/tests/integration/targets/wait_for_txt/aliases b/ansible_collections/community/dns/tests/integration/targets/wait_for_txt/aliases
index 34334fd82..abc0d5476 100644
--- a/ansible_collections/community/dns/tests/integration/targets/wait_for_txt/aliases
+++ b/ansible_collections/community/dns/tests/integration/targets/wait_for_txt/aliases
@@ -3,4 +3,3 @@
# SPDX-License-Identifier: GPL-3.0-or-later
shippable/posix/group1
-destructive
diff --git a/ansible_collections/community/dns/tests/integration/targets/wait_for_txt/tasks/main.yml b/ansible_collections/community/dns/tests/integration/targets/wait_for_txt/tasks/main.yml
index fce443423..b706cfcae 100644
--- a/ansible_collections/community/dns/tests/integration/targets/wait_for_txt/tasks/main.yml
+++ b/ansible_collections/community/dns/tests/integration/targets/wait_for_txt/tasks/main.yml
@@ -8,7 +8,7 @@
records:
- name: github.com
values: |
- {{ query('community.general.dig', 'github.com', 'qtype=TXT') | map('regex_replace', '" "', '') | list }}
+ {{ query('community.dns.lookup_as_dict', 'github.com', type='TXT') | map(attribute='value') | list }}
- name: github.io
values: []
query_timeout: 20
diff --git a/ansible_collections/community/dns/tests/sanity/extra/extra-docs.py b/ansible_collections/community/dns/tests/sanity/extra/extra-docs.py
index c636beb08..251e6d70f 100755
--- a/ansible_collections/community/dns/tests/sanity/extra/extra-docs.py
+++ b/ansible_collections/community/dns/tests/sanity/extra/extra-docs.py
@@ -17,7 +17,7 @@ def main():
suffix = ':{env}'.format(env=env["ANSIBLE_COLLECTIONS_PATH"]) if 'ANSIBLE_COLLECTIONS_PATH' in env else ''
env['ANSIBLE_COLLECTIONS_PATH'] = '{root}{suffix}'.format(root=os.path.dirname(os.path.dirname(os.path.dirname(os.getcwd()))), suffix=suffix)
p = subprocess.run(
- ['antsibull-docs', 'lint-collection-docs', '--plugin-docs', '--disallow-semantic-markup', '--skip-rstcheck', '.'],
+ ['antsibull-docs', 'lint-collection-docs', '--plugin-docs', '--skip-rstcheck', '.'],
env=env,
check=False,
)
diff --git a/ansible_collections/community/dns/tests/sanity/ignore-2.10.txt b/ansible_collections/community/dns/tests/sanity/ignore-2.10.txt
index dc9da1161..14ec3bedc 100644
--- a/ansible_collections/community/dns/tests/sanity/ignore-2.10.txt
+++ b/ansible_collections/community/dns/tests/sanity/ignore-2.10.txt
@@ -1 +1,8 @@
+docs/docsite/rst/filter_guide.rst rstcheck
+docs/docsite/rst/hosttech_guide.rst rstcheck
+docs/docsite/rst/hetzner_guide.rst rstcheck
+plugins/modules/hetzner_dns_record_info.py validate-modules:invalid-documentation
+plugins/modules/hetzner_dns_record_set_info.py validate-modules:invalid-documentation
+plugins/modules/hosttech_dns_record_info.py validate-modules:invalid-documentation
+plugins/modules/hosttech_dns_record_set_info.py validate-modules:invalid-documentation
plugins/public_suffix_list.dat no-smart-quotes
diff --git a/ansible_collections/community/dns/tests/sanity/ignore-2.11.txt b/ansible_collections/community/dns/tests/sanity/ignore-2.11.txt
index dc9da1161..593a5082f 100644
--- a/ansible_collections/community/dns/tests/sanity/ignore-2.11.txt
+++ b/ansible_collections/community/dns/tests/sanity/ignore-2.11.txt
@@ -1 +1,5 @@
+plugins/modules/hetzner_dns_record_info.py validate-modules:invalid-documentation
+plugins/modules/hetzner_dns_record_set_info.py validate-modules:invalid-documentation
+plugins/modules/hosttech_dns_record_info.py validate-modules:invalid-documentation
+plugins/modules/hosttech_dns_record_set_info.py validate-modules:invalid-documentation
plugins/public_suffix_list.dat no-smart-quotes
diff --git a/ansible_collections/community/dns/tests/sanity/ignore-2.12.txt b/ansible_collections/community/dns/tests/sanity/ignore-2.12.txt
index dc9da1161..593a5082f 100644
--- a/ansible_collections/community/dns/tests/sanity/ignore-2.12.txt
+++ b/ansible_collections/community/dns/tests/sanity/ignore-2.12.txt
@@ -1 +1,5 @@
+plugins/modules/hetzner_dns_record_info.py validate-modules:invalid-documentation
+plugins/modules/hetzner_dns_record_set_info.py validate-modules:invalid-documentation
+plugins/modules/hosttech_dns_record_info.py validate-modules:invalid-documentation
+plugins/modules/hosttech_dns_record_set_info.py validate-modules:invalid-documentation
plugins/public_suffix_list.dat no-smart-quotes
diff --git a/ansible_collections/community/dns/tests/sanity/ignore-2.13.txt b/ansible_collections/community/dns/tests/sanity/ignore-2.13.txt
index dc9da1161..593a5082f 100644
--- a/ansible_collections/community/dns/tests/sanity/ignore-2.13.txt
+++ b/ansible_collections/community/dns/tests/sanity/ignore-2.13.txt
@@ -1 +1,5 @@
+plugins/modules/hetzner_dns_record_info.py validate-modules:invalid-documentation
+plugins/modules/hetzner_dns_record_set_info.py validate-modules:invalid-documentation
+plugins/modules/hosttech_dns_record_info.py validate-modules:invalid-documentation
+plugins/modules/hosttech_dns_record_set_info.py validate-modules:invalid-documentation
plugins/public_suffix_list.dat no-smart-quotes
diff --git a/ansible_collections/community/dns/tests/sanity/ignore-2.14.txt b/ansible_collections/community/dns/tests/sanity/ignore-2.14.txt
index dc9da1161..593a5082f 100644
--- a/ansible_collections/community/dns/tests/sanity/ignore-2.14.txt
+++ b/ansible_collections/community/dns/tests/sanity/ignore-2.14.txt
@@ -1 +1,5 @@
+plugins/modules/hetzner_dns_record_info.py validate-modules:invalid-documentation
+plugins/modules/hetzner_dns_record_set_info.py validate-modules:invalid-documentation
+plugins/modules/hosttech_dns_record_info.py validate-modules:invalid-documentation
+plugins/modules/hosttech_dns_record_set_info.py validate-modules:invalid-documentation
plugins/public_suffix_list.dat no-smart-quotes
diff --git a/ansible_collections/community/dns/tests/sanity/ignore-2.17.txt b/ansible_collections/community/dns/tests/sanity/ignore-2.17.txt
new file mode 100644
index 000000000..dc9da1161
--- /dev/null
+++ b/ansible_collections/community/dns/tests/sanity/ignore-2.17.txt
@@ -0,0 +1 @@
+plugins/public_suffix_list.dat no-smart-quotes
diff --git a/ansible_collections/community/general/tests/sanity/ignore-2.12.txt.license b/ansible_collections/community/dns/tests/sanity/ignore-2.17.txt.license
index edff8c768..edff8c768 100644
--- a/ansible_collections/community/general/tests/sanity/ignore-2.12.txt.license
+++ b/ansible_collections/community/dns/tests/sanity/ignore-2.17.txt.license
diff --git a/ansible_collections/community/dns/tests/sanity/ignore-2.9.txt b/ansible_collections/community/dns/tests/sanity/ignore-2.9.txt
index dc9da1161..14ec3bedc 100644
--- a/ansible_collections/community/dns/tests/sanity/ignore-2.9.txt
+++ b/ansible_collections/community/dns/tests/sanity/ignore-2.9.txt
@@ -1 +1,8 @@
+docs/docsite/rst/filter_guide.rst rstcheck
+docs/docsite/rst/hosttech_guide.rst rstcheck
+docs/docsite/rst/hetzner_guide.rst rstcheck
+plugins/modules/hetzner_dns_record_info.py validate-modules:invalid-documentation
+plugins/modules/hetzner_dns_record_set_info.py validate-modules:invalid-documentation
+plugins/modules/hosttech_dns_record_info.py validate-modules:invalid-documentation
+plugins/modules/hosttech_dns_record_set_info.py validate-modules:invalid-documentation
plugins/public_suffix_list.dat no-smart-quotes
diff --git a/ansible_collections/community/dns/tests/unit/plugins/inventory/test_hetzner_dns_records.py b/ansible_collections/community/dns/tests/unit/plugins/inventory/test_hetzner_dns_records.py
index 3b01de586..bfaa4886d 100644
--- a/ansible_collections/community/dns/tests/unit/plugins/inventory/test_hetzner_dns_records.py
+++ b/ansible_collections/community/dns/tests/unit/plugins/inventory/test_hetzner_dns_records.py
@@ -12,6 +12,7 @@ import textwrap
from ansible import constants as C
from ansible.inventory.manager import InventoryManager
from ansible.module_utils.common.text.converters import to_native
+from ansible.utils.unsafe_proxy import AnsibleUnsafe
from ansible_collections.community.internal_test_tools.tests.unit.mock.path import mock_unfrackpath_noop
from ansible_collections.community.internal_test_tools.tests.unit.mock.loader import DictDataLoader
@@ -208,6 +209,8 @@ def test_inventory_file_simple(mocker):
assert im._inventory.get_host('*.example.com') in im._inventory.groups['ungrouped'].hosts
assert im._inventory.get_host('example.com').get_vars()['ansible_host'] == '1.2.3.4'
assert im._inventory.get_host('*.example.com').get_vars()['ansible_host'] == '1.2.3.5'
+ assert isinstance(im._inventory.get_host('example.com').get_vars()['ansible_host'], AnsibleUnsafe)
+ assert isinstance(im._inventory.get_host('*.example.com').get_vars()['ansible_host'], AnsibleUnsafe)
assert len(im._inventory.groups['ungrouped'].hosts) == 2
assert len(im._inventory.groups['all'].hosts) == 0
diff --git a/ansible_collections/community/dns/tests/unit/plugins/inventory/test_hosttech_dns_records.py b/ansible_collections/community/dns/tests/unit/plugins/inventory/test_hosttech_dns_records.py
index a7adb2c09..cefd02a06 100644
--- a/ansible_collections/community/dns/tests/unit/plugins/inventory/test_hosttech_dns_records.py
+++ b/ansible_collections/community/dns/tests/unit/plugins/inventory/test_hosttech_dns_records.py
@@ -12,6 +12,7 @@ import textwrap
from ansible import constants as C
from ansible.inventory.manager import InventoryManager
from ansible.module_utils.common.text.converters import to_native
+from ansible.utils.unsafe_proxy import AnsibleUnsafe
from ansible_collections.community.internal_test_tools.tests.unit.mock.path import mock_unfrackpath_noop
from ansible_collections.community.internal_test_tools.tests.unit.mock.loader import DictDataLoader
@@ -185,6 +186,8 @@ def test_inventory_file_simple(mocker):
assert im._inventory.get_host('*.example.com') in im._inventory.groups['ungrouped'].hosts
assert im._inventory.get_host('example.com').get_vars()['ansible_host'] == '1.2.3.4'
assert im._inventory.get_host('*.example.com').get_vars()['ansible_host'] == '1.2.3.5'
+ assert isinstance(im._inventory.get_host('example.com').get_vars()['ansible_host'], AnsibleUnsafe)
+ assert isinstance(im._inventory.get_host('*.example.com').get_vars()['ansible_host'], AnsibleUnsafe)
assert len(im._inventory.groups['ungrouped'].hosts) == 2
assert len(im._inventory.groups['all'].hosts) == 0
diff --git a/ansible_collections/community/dns/tests/unit/plugins/lookup/test_lookup.py b/ansible_collections/community/dns/tests/unit/plugins/lookup/test_lookup.py
new file mode 100644
index 000000000..0982d8704
--- /dev/null
+++ b/ansible_collections/community/dns/tests/unit/plugins/lookup/test_lookup.py
@@ -0,0 +1,498 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2023, Felix Fontein <felix@fontein.de>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# Make coding more python3-ish
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+import pytest
+
+from ansible.errors import AnsibleLookupError
+from ansible.plugins.loader import lookup_loader
+
+from ansible_collections.community.internal_test_tools.tests.unit.compat.unittest import TestCase
+from ansible_collections.community.internal_test_tools.tests.unit.compat.mock import patch, MagicMock
+
+from ..module_utils.resolver_helper import (
+ mock_resolver,
+ mock_query_udp,
+ create_mock_answer,
+)
+
+# We need dnspython
+dns = pytest.importorskip('dns')
+
+
+class TestLookup(TestCase):
+ def setUp(self):
+ self.lookup = lookup_loader.get("community.dns.lookup")
+
+ def test_simple(self):
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('1.1.1.1', ): [
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(dns.rrset.from_rdata(
+ 'www.example.com',
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, '127.0.0.1'),
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, '127.0.0.2'),
+ )),
+ },
+ ],
+ })
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp([])):
+ result = self.lookup.run(['www.example.com'])
+
+ print(result)
+ assert len(result) == 2
+ assert result[0] == '127.0.0.1'
+ assert result[1] == '127.0.0.2'
+
+ def test_retry_success(self):
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('1.1.1.1', ): [
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'raise': dns.exception.Timeout(timeout=10),
+ },
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'raise': dns.exception.Timeout(timeout=10),
+ },
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'raise': dns.exception.Timeout(timeout=10),
+ },
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(dns.rrset.from_rdata(
+ 'www.example.com',
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, '127.0.0.1'),
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, '127.0.0.2'),
+ )),
+ },
+ ],
+ })
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp([])):
+ result = self.lookup.run(['www.example.com'])
+
+ print(result)
+ assert len(result) == 2
+ assert result[0] == '127.0.0.1'
+ assert result[1] == '127.0.0.2'
+
+ def test_retry_fail(self):
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('1.1.1.1', ): [
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'raise': dns.exception.Timeout(timeout=10),
+ },
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'raise': dns.exception.Timeout(timeout=10),
+ },
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'raise': dns.exception.Timeout(timeout=10),
+ },
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'raise': dns.exception.Timeout(timeout=10),
+ },
+ ],
+ })
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp([])):
+ with pytest.raises(AnsibleLookupError) as exc:
+ self.lookup.run(['www.example.com'])
+
+ print(exc.value.args[0])
+ assert exc.value.args[0].startswith('Unexpected DNS error for www.example.com: The DNS operation timed out after 10')
+
+ def test_simple_nxdomain(self):
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('1.1.1.1', ): [
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.NXDOMAIN),
+ },
+ ],
+ })
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp([])):
+ result = self.lookup.run(['www.example.com'])
+
+ print(result)
+ assert len(result) == 0
+
+ def test_simple_nxdomain(self):
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('1.1.1.1', ): [
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.NXDOMAIN),
+ },
+ ],
+ })
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp([])):
+ result = self.lookup.run(['www.example.com'])
+
+ print(result)
+ assert len(result) == 0
+
+ def test_simple_nxdomain_empty(self):
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('1.1.1.1', ): [
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.NXDOMAIN),
+ },
+ ],
+ })
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp([])):
+ result = self.lookup.run(['www.example.com'], nxdomain_handling='empty')
+
+ print(result)
+ assert len(result) == 0
+
+ def test_simple_nxdomain_message(self):
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('1.1.1.1', ): [
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.NXDOMAIN),
+ },
+ ],
+ })
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp([])):
+ result = self.lookup.run(['www.example.com'], nxdomain_handling='message')
+
+ print(result)
+ assert len(result) == 1
+ assert result[0] == 'NXDOMAIN'
+
+ def test_simple_nxdomain_fail(self):
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('1.1.1.1', ): [
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.NXDOMAIN),
+ },
+ ],
+ })
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp([])):
+ with pytest.raises(AnsibleLookupError) as exc:
+ self.lookup.run(['www.example.com'], nxdomain_handling='fail')
+
+ print(exc.value.args[0])
+ assert exc.value.args[0] == 'Got NXDOMAIN when querying www.example.com'
+
+ def test_simple_servfail(self):
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('1.1.1.1', ): [
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.SERVFAIL),
+ },
+ ],
+ })
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp([])):
+ with pytest.raises(AnsibleLookupError) as exc:
+ self.lookup.run(['www.example.com'])
+
+ print(exc.value.args[0])
+ assert exc.value.args[0] == "Unexpected resolving error for www.example.com: Error SERVFAIL while querying ['1.1.1.1']"
+
+ def test_retry_servfail_success(self):
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('1.1.1.1', ): [
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.SERVFAIL),
+ },
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.SERVFAIL),
+ },
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.NXDOMAIN),
+ },
+ ],
+ })
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp([])):
+ result = self.lookup.run(['www.example.com'], servfail_retries=2)
+
+ print(result)
+ assert len(result) == 0
+
+ def test_retry_servfail_fail(self):
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('1.1.1.1', ): [
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.SERVFAIL),
+ },
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.SERVFAIL),
+ },
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.SERVFAIL),
+ },
+ ],
+ })
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp([])):
+ with pytest.raises(AnsibleLookupError) as exc:
+ self.lookup.run(['www.example.com'], servfail_retries=2)
+
+ print(exc.value.args[0])
+ assert exc.value.args[0] == "Unexpected resolving error for www.example.com: Error SERVFAIL while querying ['1.1.1.1']"
+
+ def test_type(self):
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('1.1.1.1', ): [
+ {
+ 'target': dns.name.from_unicode(u'example.com'),
+ 'rdtype': dns.rdatatype.TXT,
+ 'lifetime': 10,
+ 'result': create_mock_answer(dns.rrset.from_rdata(
+ 'example.com',
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.TXT, '"foo bar"'),
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.TXT, 'baz bam'),
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.TXT, 'bar'),
+ )),
+ },
+ ],
+ })
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp([])):
+ result = self.lookup.run(['example.com'], type='TXT')
+
+ print(result)
+ assert len(result) == 3
+ assert result[0] == '"foo bar"'
+ assert result[1] == '"baz" "bam"'
+ assert result[2] == '"bar"'
+
+ def test_server(self):
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('2.2.2.2', '3.3.3.3'): [
+ {
+ 'target': dns.name.from_unicode(u'example.org'),
+ 'rdtype': dns.rdatatype.AAAA,
+ 'lifetime': 10,
+ 'result': create_mock_answer(dns.rrset.from_rdata(
+ 'example.org',
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.AAAA, '::1'),
+ )),
+ },
+ ],
+ })
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp([])):
+ result = self.lookup.run(['example.org'], type='AAAA', server=['2.2.2.2', '3.3.3.3'])
+
+ print(result)
+ assert len(result) == 1
+ assert result[0] == '::1'
+
+ def test_server_resolve(self):
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('1.1.1.1', ): [
+ {
+ 'target': dns.name.from_unicode(u'ns.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(dns.rrset.from_rdata(
+ 'ns.example.com',
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, '1.2.3.4'),
+ )),
+ },
+ {
+ 'target': dns.name.from_unicode(u'ns.example.com'),
+ 'rdtype': dns.rdatatype.AAAA,
+ 'lifetime': 10,
+ 'result': create_mock_answer(dns.rrset.from_rdata(
+ 'ns.example.com',
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.AAAA, '1::2'),
+ )),
+ },
+ ],
+ ('1.2.3.4', '1::2', '2.2.2.2', '3.3.3.3'): [
+ {
+ 'target': dns.name.from_unicode(u'example.org'),
+ 'rdtype': dns.rdatatype.AAAA,
+ 'lifetime': 10,
+ 'result': create_mock_answer(dns.rrset.from_rdata(
+ 'example.org',
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.AAAA, '::1'),
+ )),
+ },
+ ],
+ })
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp([])):
+ result = self.lookup.run(['example.org'], type='AAAA', server=['2.2.2.2', 'ns.example.com', '3.3.3.3'])
+
+ print(result)
+ assert len(result) == 1
+ assert result[0] == '::1'
+
+ def test_server_resolve_nxdomain(self):
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('1.1.1.1', ): [
+ {
+ 'target': dns.name.from_unicode(u'ns.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.NXDOMAIN),
+ },
+ ],
+ })
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp([])):
+ with pytest.raises(AnsibleLookupError) as exc:
+ self.lookup.run(['www.example.com'], server=['2.2.2.2', 'ns.example.com'])
+
+ print(exc.value.args[0])
+ assert exc.value.args[0] == 'Unexpected DNS error for ns.example.com: The DNS query name does not exist: ns.example.com.'
+
+ def test_server_resolve_servfail(self):
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('1.1.1.1', ): [
+ {
+ 'target': dns.name.from_unicode(u'ns.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.SERVFAIL),
+ },
+ ],
+ })
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp([])):
+ with pytest.raises(AnsibleLookupError) as exc:
+ self.lookup.run(['www.example.com'], server=['2.2.2.2', 'ns.example.com'])
+
+ print(exc.value.args[0])
+ assert exc.value.args[0] == "Unexpected resolving error for ns.example.com: Error SERVFAIL while querying ['1.1.1.1']"
+
+ def test_server_resolve_empty_lifetime(self):
+ fake_query = MagicMock()
+ fake_query.question = 'Doctor Who?'
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('1.1.1.1', ): [
+ {
+ 'target': dns.name.from_unicode(u'ns.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 5,
+ 'raise': dns.resolver.NoAnswer(response=fake_query),
+ },
+ {
+ 'target': dns.name.from_unicode(u'ns.example.com'),
+ 'rdtype': dns.rdatatype.AAAA,
+ 'lifetime': 5,
+ 'raise': dns.resolver.NoAnswer(response=fake_query),
+ },
+ ],
+ ('3.3.3.3', ): [
+ {
+ 'target': dns.name.from_unicode(u'example.org'),
+ 'rdtype': dns.rdatatype.AAAA,
+ 'lifetime': 5,
+ 'raise': dns.resolver.NoAnswer(response=fake_query),
+ },
+ ],
+ })
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp([])):
+ result = self.lookup.run(
+ ['example.org'],
+ type='AAAA',
+ server=['ns.example.com', '3.3.3.3'],
+ query_timeout=5,
+ )
+
+ print(result)
+ assert len(result) == 0
diff --git a/ansible_collections/community/dns/tests/unit/plugins/lookup/test_lookup_as_dict.py b/ansible_collections/community/dns/tests/unit/plugins/lookup/test_lookup_as_dict.py
new file mode 100644
index 000000000..f29d73143
--- /dev/null
+++ b/ansible_collections/community/dns/tests/unit/plugins/lookup/test_lookup_as_dict.py
@@ -0,0 +1,461 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2023, Felix Fontein <felix@fontein.de>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# Make coding more python3-ish
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+import pytest
+
+from ansible.errors import AnsibleLookupError
+from ansible.plugins.loader import lookup_loader
+
+from ansible_collections.community.internal_test_tools.tests.unit.compat.unittest import TestCase
+from ansible_collections.community.internal_test_tools.tests.unit.compat.mock import patch, MagicMock
+
+from ..module_utils.resolver_helper import (
+ mock_resolver,
+ mock_query_udp,
+ create_mock_answer,
+)
+
+# We need dnspython
+dns = pytest.importorskip('dns')
+
+
+class TestLookupAsDict(TestCase):
+ def setUp(self):
+ self.lookup = lookup_loader.get("community.dns.lookup_as_dict")
+
+ def test_simple(self):
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('1.1.1.1', ): [
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(dns.rrset.from_rdata(
+ 'www.example.com',
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, '127.0.0.1'),
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, '127.0.0.2'),
+ )),
+ },
+ ],
+ })
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp([])):
+ result = self.lookup.run(['www.example.com'])
+
+ print(result)
+ assert len(result) == 2
+ assert result[0] == {
+ 'address': '127.0.0.1',
+ }
+ assert result[1] == {
+ 'address': '127.0.0.2',
+ }
+
+ def test_retry_success(self):
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('1.1.1.1', ): [
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'raise': dns.exception.Timeout(timeout=10),
+ },
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'raise': dns.exception.Timeout(timeout=10),
+ },
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'raise': dns.exception.Timeout(timeout=10),
+ },
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(dns.rrset.from_rdata(
+ 'www.example.com',
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, '127.0.0.1'),
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, '127.0.0.2'),
+ )),
+ },
+ ],
+ })
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp([])):
+ result = self.lookup.run(['www.example.com'])
+
+ print(result)
+ assert len(result) == 2
+ assert result[0] == {
+ 'address': '127.0.0.1',
+ }
+ assert result[1] == {
+ 'address': '127.0.0.2',
+ }
+
+ def test_retry_fail(self):
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('1.1.1.1', ): [
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'raise': dns.exception.Timeout(timeout=10),
+ },
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'raise': dns.exception.Timeout(timeout=10),
+ },
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'raise': dns.exception.Timeout(timeout=10),
+ },
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'raise': dns.exception.Timeout(timeout=10),
+ },
+ ],
+ })
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp([])):
+ with pytest.raises(AnsibleLookupError) as exc:
+ self.lookup.run(['www.example.com'])
+
+ print(exc.value.args[0])
+ assert exc.value.args[0].startswith('Unexpected DNS error for www.example.com: The DNS operation timed out after 10')
+
+ def test_simple_nxdomain_empty(self):
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('1.1.1.1', ): [
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.NXDOMAIN),
+ },
+ ],
+ })
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp([])):
+ result = self.lookup.run(['www.example.com'], nxdomain_handling='empty')
+
+ print(result)
+ assert len(result) == 0
+
+ def test_simple_nxdomain_fail(self):
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('1.1.1.1', ): [
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.NXDOMAIN),
+ },
+ ],
+ })
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp([])):
+ with pytest.raises(AnsibleLookupError) as exc:
+ self.lookup.run(['www.example.com'], nxdomain_handling='fail')
+
+ print(exc.value.args[0])
+ assert exc.value.args[0] == 'Got NXDOMAIN when querying www.example.com'
+
+ def test_simple_servfail(self):
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('1.1.1.1', ): [
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.SERVFAIL),
+ },
+ ],
+ })
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp([])):
+ with pytest.raises(AnsibleLookupError) as exc:
+ self.lookup.run(['www.example.com'])
+
+ print(exc.value.args[0])
+ assert exc.value.args[0] == "Unexpected resolving error for www.example.com: Error SERVFAIL while querying ['1.1.1.1']"
+
+ def test_retry_servfail_success(self):
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('1.1.1.1', ): [
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.SERVFAIL),
+ },
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.SERVFAIL),
+ },
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.NXDOMAIN),
+ },
+ ],
+ })
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp([])):
+ result = self.lookup.run(['www.example.com'], servfail_retries=2)
+
+ print(result)
+ assert len(result) == 0
+
+ def test_retry_servfail_fail(self):
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('1.1.1.1', ): [
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.SERVFAIL),
+ },
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.SERVFAIL),
+ },
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.SERVFAIL),
+ },
+ ],
+ })
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp([])):
+ with pytest.raises(AnsibleLookupError) as exc:
+ self.lookup.run(['www.example.com'], servfail_retries=2)
+
+ print(exc.value.args[0])
+ assert exc.value.args[0] == "Unexpected resolving error for www.example.com: Error SERVFAIL while querying ['1.1.1.1']"
+
+ def test_type(self):
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('1.1.1.1', ): [
+ {
+ 'target': dns.name.from_unicode(u'example.com'),
+ 'rdtype': dns.rdatatype.TXT,
+ 'lifetime': 10,
+ 'result': create_mock_answer(dns.rrset.from_rdata(
+ 'example.com',
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.TXT, '"foo bar"'),
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.TXT, 'baz bam'),
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.TXT, 'bar'),
+ )),
+ },
+ ],
+ })
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp([])):
+ result = self.lookup.run(['example.com'], type='TXT')
+
+ print(result)
+ assert len(result) == 3
+ assert result[0] == {
+ 'strings': ['foo bar'],
+ 'value': 'foo bar',
+ }
+ assert result[1] == {
+ 'strings': ['baz', 'bam'],
+ 'value': 'bazbam',
+ }
+ assert result[2] == {
+ 'strings': ['bar'],
+ 'value': 'bar',
+ }
+
+ def test_server(self):
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('2.2.2.2', '3.3.3.3'): [
+ {
+ 'target': dns.name.from_unicode(u'example.org'),
+ 'rdtype': dns.rdatatype.AAAA,
+ 'lifetime': 10,
+ 'result': create_mock_answer(dns.rrset.from_rdata(
+ 'example.org',
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.AAAA, '::1'),
+ )),
+ },
+ ],
+ })
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp([])):
+ result = self.lookup.run(['example.org'], type='AAAA', server=['2.2.2.2', '3.3.3.3'])
+
+ print(result)
+ assert len(result) == 1
+ assert result[0] == {
+ 'address': '::1',
+ }
+
+ def test_server_resolve(self):
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('1.1.1.1', ): [
+ {
+ 'target': dns.name.from_unicode(u'ns.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(dns.rrset.from_rdata(
+ 'ns.example.com',
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, '1.2.3.4'),
+ )),
+ },
+ {
+ 'target': dns.name.from_unicode(u'ns.example.com'),
+ 'rdtype': dns.rdatatype.AAAA,
+ 'lifetime': 10,
+ 'result': create_mock_answer(dns.rrset.from_rdata(
+ 'ns.example.com',
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.AAAA, '1::2'),
+ )),
+ },
+ ],
+ ('1.2.3.4', '1::2', '2.2.2.2', '3.3.3.3'): [
+ {
+ 'target': dns.name.from_unicode(u'example.org'),
+ 'rdtype': dns.rdatatype.AAAA,
+ 'lifetime': 10,
+ 'result': create_mock_answer(dns.rrset.from_rdata(
+ 'example.org',
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.AAAA, '::1'),
+ )),
+ },
+ ],
+ })
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp([])):
+ result = self.lookup.run(['example.org'], type='AAAA', server=['2.2.2.2', 'ns.example.com', '3.3.3.3'])
+
+ print(result)
+ assert len(result) == 1
+ assert result[0] == {
+ 'address': '::1',
+ }
+
+ def test_server_resolve_nxdomain(self):
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('1.1.1.1', ): [
+ {
+ 'target': dns.name.from_unicode(u'ns.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.NXDOMAIN),
+ },
+ ],
+ })
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp([])):
+ with pytest.raises(AnsibleLookupError) as exc:
+ self.lookup.run(['www.example.com'], server=['2.2.2.2', 'ns.example.com'])
+
+ print(exc.value.args[0])
+ assert exc.value.args[0] == 'Unexpected DNS error for ns.example.com: The DNS query name does not exist: ns.example.com.'
+
+ def test_server_resolve_servfail(self):
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('1.1.1.1', ): [
+ {
+ 'target': dns.name.from_unicode(u'ns.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.SERVFAIL),
+ },
+ ],
+ })
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp([])):
+ with pytest.raises(AnsibleLookupError) as exc:
+ self.lookup.run(['www.example.com'], server=['2.2.2.2', 'ns.example.com'])
+
+ print(exc.value.args[0])
+ assert exc.value.args[0] == "Unexpected resolving error for ns.example.com: Error SERVFAIL while querying ['1.1.1.1']"
+
+ def test_server_resolve_empty_lifetime(self):
+ fake_query = MagicMock()
+ fake_query.question = 'Doctor Who?'
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('1.1.1.1', ): [
+ {
+ 'target': dns.name.from_unicode(u'ns.example.com'),
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 5,
+ 'raise': dns.resolver.NoAnswer(response=fake_query),
+ },
+ {
+ 'target': dns.name.from_unicode(u'ns.example.com'),
+ 'rdtype': dns.rdatatype.AAAA,
+ 'lifetime': 5,
+ 'raise': dns.resolver.NoAnswer(response=fake_query),
+ },
+ ],
+ ('3.3.3.3', ): [
+ {
+ 'target': dns.name.from_unicode(u'example.org'),
+ 'rdtype': dns.rdatatype.AAAA,
+ 'lifetime': 5,
+ 'raise': dns.resolver.NoAnswer(response=fake_query),
+ },
+ ],
+ })
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp([])):
+ result = self.lookup.run(
+ ['example.org'],
+ type='AAAA',
+ server=['ns.example.com', '3.3.3.3'],
+ query_timeout=5,
+ )
+
+ print(result)
+ assert len(result) == 0
diff --git a/ansible_collections/community/dns/tests/unit/plugins/module_utils/conversion/test_txt.py b/ansible_collections/community/dns/tests/unit/plugins/module_utils/conversion/test_txt.py
index e5984444b..664b6db6d 100644
--- a/ansible_collections/community/dns/tests/unit/plugins/module_utils/conversion/test_txt.py
+++ b/ansible_collections/community/dns/tests/unit/plugins/module_utils/conversion/test_txt.py
@@ -138,6 +138,16 @@ TEST_ENCODE_DECODE = [
True, True, 'decimal'
),
(
+ # Avoid splitting up an escape into multiple TXT strings
+ u'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzAB'
+ u'CDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123'
+ u'456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdef"\\',
+ u'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzAB'
+ u'CDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123'
+ u'456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdef \\"\\\\',
+ False, True, 'decimal'
+ ),
+ (
# Avoid splitting up an decimal sequence into multiple TXT strings
u'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzAB'
u'CDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123'
diff --git a/ansible_collections/community/dns/tests/unit/plugins/module_utils/resolver_helper.py b/ansible_collections/community/dns/tests/unit/plugins/module_utils/resolver_helper.py
index e410d2076..7fa213c9f 100644
--- a/ansible_collections/community/dns/tests/unit/plugins/module_utils/resolver_helper.py
+++ b/ansible_collections/community/dns/tests/unit/plugins/module_utils/resolver_helper.py
@@ -11,6 +11,11 @@ __metaclass__ = type
from ansible_collections.community.internal_test_tools.tests.unit.compat.mock import MagicMock
+try:
+ import dns.rcode
+except ImportError:
+ pass
+
def mock_resolver(default_nameservers, nameserver_resolve_sequence):
def create_resolver(configure=True):
@@ -59,15 +64,16 @@ def mock_query_udp(call_sequence):
return udp
-def create_mock_answer(rrset=None):
- answer = MagicMock()
- answer.rrset = rrset
- return answer
-
-
def create_mock_response(rcode, authority=None, answer=None):
response = MagicMock()
response.rcode = MagicMock(return_value=rcode)
response.authority = authority or []
response.answer = answer or []
return response
+
+
+def create_mock_answer(rrset=None, rcode=None):
+ answer = MagicMock()
+ answer.response = create_mock_response(dns.rcode.NOERROR if rcode is None else rcode, answer=[rrset] if rrset else None)
+ answer.rrset = rrset
+ return answer
diff --git a/ansible_collections/community/dns/tests/unit/plugins/module_utils/test_dnspython_records.py b/ansible_collections/community/dns/tests/unit/plugins/module_utils/test_dnspython_records.py
new file mode 100644
index 000000000..9594b8097
--- /dev/null
+++ b/ansible_collections/community/dns/tests/unit/plugins/module_utils/test_dnspython_records.py
@@ -0,0 +1,376 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2022, Felix Fontein <felix@fontein.de>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# Make coding more python3-ish
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+import pytest
+
+from ansible_collections.community.dns.plugins.module_utils.dnspython_records import (
+ RDTYPE_TO_FIELDS,
+ convert_rdata_to_dict,
+)
+
+# We need dnspython
+dns = pytest.importorskip('dns')
+
+import dns.version
+
+
+TEST_CONVERT_RDATA_TO_DICT = [
+ (
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, '3.3.3.3'),
+ {'to_unicode': True, 'add_synthetic': False},
+ {
+ 'address': '3.3.3.3',
+ },
+ ),
+ (
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.AAAA, '1:2::3'),
+ {'to_unicode': True, 'add_synthetic': False},
+ {
+ 'address': '1:2::3',
+ },
+ ),
+ (
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.AAAA, '::'),
+ {'to_unicode': False, 'add_synthetic': True},
+ {
+ 'address': '::',
+ },
+ ),
+ (
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.CAA, '10 issue letsencrypt.org'),
+ {'to_unicode': True, 'add_synthetic': False},
+ {
+ 'flags': 10,
+ 'tag': 'issue',
+ 'value': 'letsencrypt.org',
+ },
+ ),
+ (
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.CNAME, 'foo.example.com.'),
+ {'to_unicode': True, 'add_synthetic': False},
+ {
+ 'target': 'foo.example.com.',
+ },
+ ),
+ (
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.DNAME, 'foo.example.com.'),
+ {'to_unicode': True, 'add_synthetic': False},
+ {
+ 'target': 'foo.example.com.',
+ },
+ ),
+ (
+ dns.rdata.from_text(
+ dns.rdataclass.IN,
+ dns.rdatatype.DNSKEY,
+ '512 255 1 AQMFD5raczCJHViKtLYhWGz8hMY9UGRuniJDBzC7w0aR yzWZriO6i2odGWWQVucZqKVsENW91IOW4vqudngPZsY3'
+ ' GvQ/xVA8/7pyFj6b7Esga60zyGW6LFe9r8n6paHrlG5o jqf0BaqHT+8=',
+ ),
+ {'to_unicode': False, 'add_synthetic': False},
+ {
+ 'flags': 512,
+ 'algorithm': 1,
+ 'protocol': 255,
+ 'key': (
+ 'AQMFD5raczCJHViKtLYhWGz8hMY9UGRuniJDBzC7w0aRyzWZriO6i2odGWWQVucZqKVsENW9'
+ '1IOW4vqudngPZsY3GvQ/xVA8/7pyFj6b7Esga60zyGW6LFe9r8n6paHrlG5ojqf0BaqHT+8='
+ ),
+ },
+ ),
+ (
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.DS, '12345 3 1 123456789abcdef67890123456789abcdef67890'),
+ {'to_unicode': False, 'add_synthetic': False},
+ {
+ 'algorithm': 3,
+ 'digest_type': 1,
+ 'key_tag': 12345,
+ 'digest': '123456789abcdef67890123456789abcdef67890',
+ },
+ ),
+ (
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.HINFO, '"Generic PC clone" "NetBSD-1.4"'),
+ {'to_unicode': False, 'add_synthetic': False},
+ {
+ 'cpu': b'Generic PC clone',
+ 'os': b'NetBSD-1.4',
+ },
+ ),
+ (
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.LOC, '60 9 0.000 N 24 39 0.000 E 10.00m 20.00m 2000.00m 20.00m'),
+ {'to_unicode': False, 'add_synthetic': False},
+ {
+ 'latitude': [60, 9, 0, 0, 1],
+ 'longitude': [24, 39, 0, 0, 1],
+ 'altitude': 1000.0,
+ 'size': 2000.0,
+ 'horizontal_precision': 200000.0,
+ 'vertical_precision': 2000.0,
+ },
+ ),
+ (
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.MX, '10 mail.example.com'),
+ {'to_unicode': True, 'add_synthetic': False},
+ {
+ 'preference': 10,
+ 'exchange': 'mail.example.com',
+ },
+ ),
+ (
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NAPTR, '65535 65535 "text 1" "text 2" "text 3" example.com.'),
+ {'to_unicode': False, 'add_synthetic': False},
+ {
+ 'order': 65535,
+ 'preference': 65535,
+ 'flags': b'text 1',
+ 'service': b'text 2',
+ 'regexp': b'text 3',
+ 'replacement': 'example.com.',
+ },
+ ),
+ (
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'ns.example.org.'),
+ {'to_unicode': True, 'add_synthetic': False},
+ {
+ 'target': 'ns.example.org.',
+ },
+ ),
+ (
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NSEC, 'a.secure A MX RRSIG NSEC TYPE1234'),
+ {'to_unicode': False, 'add_synthetic': False},
+ {
+ 'next': 'a.secure',
+ 'windows': 'A MX RRSIG NSEC TYPE1234',
+ },
+ ),
+ (
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NSEC3, '1 1 123 f00baa23 2t7b4g4vsa5smi47k61mv5bv1a22bojr NS SOA MX RRSIG DNSKEY NSEC3PARAM'),
+ {'to_unicode': False, 'add_synthetic': False},
+ {
+ 'algorithm': 1,
+ 'flags': 1,
+ 'iterations': 123,
+ 'salt': 'f00baa23',
+ 'next': '2t7b4g4vsa5smi47k61mv5bv1a22bojr',
+ 'windows': 'NS SOA MX RRSIG DNSKEY NSEC3PARAM',
+ },
+ ),
+ (
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NSEC3PARAM, '1 1 123 f00baa23'),
+ {'to_unicode': False, 'add_synthetic': False},
+ {
+ 'algorithm': 1,
+ 'flags': 1,
+ 'iterations': 123,
+ 'salt': 'f00baa23',
+ },
+ ),
+ (
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.PTR, 'example.com.'),
+ {'to_unicode': False, 'add_synthetic': False},
+ {
+ 'target': 'example.com.',
+ },
+ ),
+ (
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.RP, 'mbox-dname txt-dname'),
+ {'to_unicode': False, 'add_synthetic': False},
+ {
+ 'mbox': 'mbox-dname',
+ 'txt': 'txt-dname',
+ },
+ ),
+ (
+ dns.rdata.from_text(
+ dns.rdataclass.IN,
+ dns.rdatatype.RRSIG,
+ 'SOA 5 2 3600 20101127004331 20101119213831 61695 dnspython.org. sDUlltRlFTQw5ITFxOXW3TgmrHeMeNpdqcZ4EXxM9FHhIlte6V9YCnDw'
+ ' t6dvM9jAXdIEi03l9H/RAd9xNNW6gvGMHsBGzpvvqFQxIBR2PoiZA1mX /SWHZFdbt4xjYTtXqpyYvrMK0Dt7bUYPadyhPFCJ1B+I8Zi7B5WJEOd0 8vs=',
+ ),
+ {'to_unicode': False, 'add_synthetic': False},
+ {
+ 'type_covered': 'SOA',
+ 'algorithm': 5,
+ 'labels': 2,
+ 'original_ttl': 3600,
+ 'expiration': 1290818611,
+ 'inception': 1290202711,
+ 'key_tag': 61695,
+ 'signer': 'dnspython.org.',
+ 'signature': (
+ 'sDUlltRlFTQw5ITFxOXW3TgmrHeMeNpdqcZ4EXxM9FHhIlte6V9YCnDwt6dvM9jAXdIEi03l9H/RAd9xNNW6gv'
+ 'GMHsBGzpvvqFQxIBR2PoiZA1mX/SWHZFdbt4xjYTtXqpyYvrMK0Dt7bUYPadyhPFCJ1B+I8Zi7B5WJEOd08vs='
+ ),
+ },
+ ),
+ (
+ dns.rdata.from_text(
+ dns.rdataclass.IN,
+ dns.rdatatype.RRSIG,
+ 'NSEC 1 3 3600 20200101000000 20030101000000 2143 foo. MxFcby9k/yvedMfQgKzhH5er0Mu/vILz'
+ ' 45IkskceFGgiWCn/GxHhai6VAuHAoNUz 4YoU1tVfSCSqQYn6//11U6Nld80jEeC8 aTrO+KKmCaY=',
+ ),
+ {'to_unicode': False, 'add_synthetic': False},
+ {
+ 'type_covered': 'NSEC',
+ 'algorithm': 1,
+ 'labels': 3,
+ 'original_ttl': 3600,
+ 'expiration': 1577836800,
+ 'inception': 1041379200,
+ 'key_tag': 2143,
+ 'signer': 'foo.',
+ 'signature': 'MxFcby9k/yvedMfQgKzhH5er0Mu/vILz45IkskceFGgiWCn/GxHhai6VAuHAoNUz4YoU1tVfSCSqQYn6//11U6Nld80jEeC8aTrO+KKmCaY=',
+ },
+ ),
+ (
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.example.com. ns.example.org. 1 7200 900 1209600 86400'),
+ {'to_unicode': False, 'add_synthetic': False},
+ {
+ 'mname': 'ns.example.com.',
+ 'rname': 'ns.example.org.',
+ 'serial': 1,
+ 'refresh': 7200,
+ 'retry': 900,
+ 'expire': 1209600,
+ 'minimum': 86400,
+ },
+ ),
+ (
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SPF, '"v=spf1 a mx" " -all"'),
+ {'to_unicode': False, 'add_synthetic': False},
+ {
+ 'strings': [b'v=spf1 a mx', b' -all'],
+ },
+ ),
+ (
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SPF, '"v=spf1 a mx" " -all"'),
+ {'to_unicode': False, 'add_synthetic': True},
+ {
+ 'strings': [b'v=spf1 a mx', b' -all'],
+ 'value': b'v=spf1 a mx -all',
+ },
+ ),
+ (
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SRV, r'0 1 443 exchange.example.com'),
+ {'to_unicode': False, 'add_synthetic': False},
+ {
+ 'priority': 0,
+ 'weight': 1,
+ 'port': 443,
+ 'target': 'exchange.example.com',
+ },
+ ),
+ (
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SSHFP, r'1 1 aa549bfe898489c02d1715d97d79c57ba2fa76ab'),
+ {'to_unicode': False, 'add_synthetic': False},
+ {
+ 'algorithm': 1,
+ 'fp_type': 1,
+ 'fingerprint': 'aa549bfe898489c02d1715d97d79c57ba2fa76ab',
+ },
+ ),
+ (
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.TLSA, r'3 1 1 a9cdf989b504fe5dca90c0d2167b6550570734f7c763e09fdf88904e06157065'),
+ {'to_unicode': False, 'add_synthetic': False},
+ {
+ 'usage': 3,
+ 'selector': 1,
+ 'mtype': 1,
+ 'cert': 'a9cdf989b504fe5dca90c0d2167b6550570734f7c763e09fdf88904e06157065',
+ },
+ ),
+ (
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.TXT, r'asdf "foo bar"'),
+ {'to_unicode': False, 'add_synthetic': False},
+ {
+ 'strings': [b'asdf', b'foo bar'],
+ },
+ ),
+ (
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.TXT, r'asdf "foo bar"'),
+ {'to_unicode': False, 'add_synthetic': True},
+ {
+ 'strings': [b'asdf', b'foo bar'],
+ 'value': b'asdffoo bar',
+ },
+ ),
+ (
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.TXT, r'asdf "foo bar"'),
+ {'to_unicode': True, 'add_synthetic': False},
+ {
+ 'strings': [u'asdf', u'foo bar'],
+ },
+ ),
+ (
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.TXT, r'asdf "foo bar"'),
+ {'to_unicode': True, 'add_synthetic': True},
+ {
+ 'strings': [u'asdf', u'foo bar'],
+ 'value': u'asdffoo bar',
+ },
+ ),
+]
+
+
+if dns.version.MAJOR >= 2:
+ # https://github.com/rthalley/dnspython/issues/321 makes this not working on dnspython < 2.0.0,
+ # which affects Python 3.5 and 2.x since these are only supported by dnspython < 2.0.0.
+ TEST_CONVERT_RDATA_TO_DICT.extend([
+ (
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.TXT, r'asdf "foo \195\164"'),
+ {'to_unicode': False, 'add_synthetic': False},
+ {
+ 'strings': [b'asdf', b'foo \xC3\xA4'],
+ },
+ ),
+ (
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.TXT, r'asdf "foo \195\164"'),
+ {'to_unicode': False, 'add_synthetic': True},
+ {
+ 'strings': [b'asdf', b'foo \xC3\xA4'],
+ 'value': b'asdffoo \xC3\xA4',
+ },
+ ),
+ (
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.TXT, r'asdf "foo \195\164"'),
+ {'to_unicode': True, 'add_synthetic': False},
+ {
+ 'strings': [u'asdf', u'foo ä'],
+ },
+ ),
+ (
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.TXT, r'asdf "foo \195\164"'),
+ {'to_unicode': True, 'add_synthetic': True},
+ {
+ 'strings': [u'asdf', u'foo ä'],
+ 'value': u'asdffoo ä',
+ },
+ ),
+ ])
+
+
+@pytest.mark.parametrize("rdata, kwarg, expected_result", TEST_CONVERT_RDATA_TO_DICT)
+def test_convert_rdata_to_dict(rdata, kwarg, expected_result):
+ result = convert_rdata_to_dict(rdata, **kwarg)
+ print(expected_result)
+ print(result)
+ assert expected_result == result
+
+
+def test_error():
+ v = RDTYPE_TO_FIELDS.pop(dns.rdatatype.A)
+ try:
+ with pytest.raises(ValueError) as exc:
+ convert_rdata_to_dict(dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, '3.3.3.3'))
+ finally:
+ RDTYPE_TO_FIELDS[dns.rdatatype.A] = v
+ print(exc.value.args)
+ assert exc.value.args == ('Unsupported record type 1', )
diff --git a/ansible_collections/community/dns/tests/unit/plugins/module_utils/test_ips.py b/ansible_collections/community/dns/tests/unit/plugins/module_utils/test_ips.py
new file mode 100644
index 000000000..660f9adc1
--- /dev/null
+++ b/ansible_collections/community/dns/tests/unit/plugins/module_utils/test_ips.py
@@ -0,0 +1,62 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2023, Felix Fontein <felix@fontein.de>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# Make coding more python3-ish
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+import pytest
+
+from ansible_collections.community.dns.plugins.module_utils import ips
+
+from ansible_collections.community.dns.plugins.module_utils.ips import (
+ assert_requirements_present,
+ is_ip_address,
+)
+
+# We need ipaddress
+ipaddress = pytest.importorskip('ipaddress')
+
+
+def test_assert_requirements_present():
+ class ModuleFailException(Exception):
+ pass
+
+ class FakeModule(object):
+ def fail_json(self, **kwargs):
+ raise ModuleFailException(kwargs)
+
+ module = FakeModule()
+
+ orig_importerror = ips.IPADDRESS_IMPORT_EXC
+ try:
+ ips.IPADDRESS_IMPORT_EXC = None
+ assert_requirements_present(module)
+
+ ips.IPADDRESS_IMPORT_EXC = 'asdf'
+ with pytest.raises(ModuleFailException) as exc:
+ assert_requirements_present(module)
+
+ assert 'ipaddress' in exc.value.args[0]['msg']
+ assert 'asdf' == exc.value.args[0]['exception']
+
+ finally:
+ ips.IPADDRESS_IMPORT_EXC = orig_importerror
+
+
+IS_IP_ADDRESS_DATA = [
+ ('foo.bar', False),
+ ('foo', False),
+ ('123', False),
+ ('1.2.3.4', True),
+ ('::', True),
+]
+
+
+@pytest.mark.parametrize("input, output", IS_IP_ADDRESS_DATA)
+def test_is_ip_address(input, output):
+ assert is_ip_address(input) == output
diff --git a/ansible_collections/community/dns/tests/unit/plugins/module_utils/test_resolver.py b/ansible_collections/community/dns/tests/unit/plugins/module_utils/test_resolver.py
index 1f51601e0..cea7fb1d6 100644
--- a/ansible_collections/community/dns/tests/unit/plugins/module_utils/test_resolver.py
+++ b/ansible_collections/community/dns/tests/unit/plugins/module_utils/test_resolver.py
@@ -36,24 +36,26 @@ def test_assert_requirements_present():
class ModuleFailException(Exception):
pass
- def fail_json(**kwargs):
- raise ModuleFailException(kwargs)
+ class FakeModule(object):
+ def fail_json(self, **kwargs):
+ raise ModuleFailException(kwargs)
- module = MagicMock()
- module.fail_json = MagicMock(side_effect=fail_json)
+ module = FakeModule()
orig_importerror = resolver.DNSPYTHON_IMPORTERROR
- resolver.DNSPYTHON_IMPORTERROR = None
- assert_requirements_present(module)
-
- resolver.DNSPYTHON_IMPORTERROR = 'asdf'
- with pytest.raises(ModuleFailException) as exc:
+ try:
+ resolver.DNSPYTHON_IMPORTERROR = None
assert_requirements_present(module)
- assert 'dnspython' in exc.value.args[0]['msg']
- assert 'asdf' == exc.value.args[0]['exception']
+ resolver.DNSPYTHON_IMPORTERROR = 'asdf'
+ with pytest.raises(ModuleFailException) as exc:
+ assert_requirements_present(module)
+
+ assert 'dnspython' in exc.value.args[0]['msg']
+ assert 'asdf' == exc.value.args[0]['exception']
- resolver.DNSPYTHON_IMPORTERROR = orig_importerror
+ finally:
+ resolver.DNSPYTHON_IMPORTERROR = orig_importerror
def test_lookup_ns_names():
@@ -449,7 +451,69 @@ def test_timeout_failure():
assert exc.value.kwargs['timeout'] == 4
-def test_error_nxdomain():
+def test_error_nameserver_nxdomain_none():
+ resolver = mock_resolver(['1.1.1.1'], {})
+ udp_sequence = [
+ {
+ 'query_target': dns.name.from_unicode(u'com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.NXDOMAIN),
+ },
+ {
+ 'query_target': dns.name.from_unicode(u'example.com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.NXDOMAIN),
+ },
+ ]
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp(udp_sequence)):
+ resolver = ResolveDirectlyFromNameServers()
+ assert resolver.resolve_nameservers('example.com') == []
+
+
+def test_error_nameserver_nxdomain_partial_first():
+ resolver = mock_resolver(['1.1.1.1'], {})
+ udp_sequence = [
+ {
+ 'query_target': dns.name.from_unicode(u'com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.NOERROR, answer=[dns.rrset.from_rdata(
+ 'com',
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'ns.com'),
+ )]),
+ },
+ {
+ 'query_target': dns.name.from_unicode(u'example.com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.NXDOMAIN),
+ },
+ ]
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp(udp_sequence)):
+ resolver = ResolveDirectlyFromNameServers()
+ assert resolver.resolve_nameservers('example.com') == ['ns.com']
+
+
+def test_error_nameserver_nxdomain_partial_second():
resolver = mock_resolver(['1.1.1.1'], {})
udp_sequence = [
{
@@ -461,14 +525,159 @@ def test_error_nxdomain():
},
'result': create_mock_response(dns.rcode.NXDOMAIN),
},
+ {
+ 'query_target': dns.name.from_unicode(u'example.com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.NOERROR, answer=[dns.rrset.from_rdata(
+ 'com',
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'ns.com'),
+ )]),
+ },
]
with patch('dns.resolver.get_default_resolver', resolver):
with patch('dns.resolver.Resolver', resolver):
with patch('dns.query.udp', mock_query_udp(udp_sequence)):
+ resolver = ResolveDirectlyFromNameServers()
+ assert resolver.resolve_nameservers('example.com') == ['ns.com']
+
+
+def test_error_nxdomain_ok():
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('1.1.1.1', ): [
+ {
+ 'target': 'ns.com',
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(dns.rrset.from_rdata(
+ 'ns.com',
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, '3.3.3.3'),
+ )),
+ },
+ {
+ 'target': 'ns.com',
+ 'rdtype': dns.rdatatype.AAAA,
+ 'lifetime': 10,
+ 'result': create_mock_answer(dns.rrset.from_rdata(
+ 'ns.com',
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.AAAA, '1:2::3'),
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.AAAA, '2:3::4'),
+ )),
+ },
+ ],
+ ('1:2::3', '2:3::4', '3.3.3.3'): [
+ {
+ 'target': dns.name.from_unicode(u'example.com'),
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.NXDOMAIN),
+ },
+ ],
+ })
+ udp_sequence = [
+ {
+ 'query_target': dns.name.from_unicode(u'com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.NOERROR, answer=[dns.rrset.from_rdata(
+ 'com',
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'ns.com'),
+ )]),
+ },
+ {
+ 'query_target': dns.name.from_unicode(u'example.com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.NXDOMAIN),
+ },
+ ]
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp(udp_sequence)):
+ resolver = ResolveDirectlyFromNameServers()
+ rrset_dict = resolver.resolve('example.com', nxdomain_is_empty=True)
+ print(rrset_dict)
+ assert sorted(rrset_dict.keys()) == ['ns.com']
+ assert rrset_dict['ns.com'] == []
+
+
+def test_error_nxdomain_fail():
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('1.1.1.1', ): [
+ {
+ 'target': 'ns.com',
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(dns.rrset.from_rdata(
+ 'ns.com',
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, '3.3.3.3'),
+ )),
+ },
+ {
+ 'target': 'ns.com',
+ 'rdtype': dns.rdatatype.AAAA,
+ 'lifetime': 10,
+ 'result': create_mock_answer(dns.rrset.from_rdata(
+ 'ns.com',
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.AAAA, '1:2::3'),
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.AAAA, '2:3::4'),
+ )),
+ },
+ ],
+ ('1:2::3', '2:3::4', '3.3.3.3'): [
+ {
+ 'target': dns.name.from_unicode(u'example.com'),
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.NXDOMAIN),
+ },
+ ],
+ })
+ udp_sequence = [
+ {
+ 'query_target': dns.name.from_unicode(u'com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.NOERROR, answer=[dns.rrset.from_rdata(
+ 'com',
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'ns.com'),
+ )]),
+ },
+ {
+ 'query_target': dns.name.from_unicode(u'example.com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.NXDOMAIN),
+ },
+ ]
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp(udp_sequence)):
+ resolver = ResolveDirectlyFromNameServers()
with pytest.raises(dns.resolver.NXDOMAIN) as exc:
- resolver = ResolveDirectlyFromNameServers()
- resolver.resolve_nameservers('example.com')
- assert exc.value.kwargs['qnames'] == [dns.name.from_unicode(u'com')]
+ resolver.resolve('example.com', nxdomain_is_empty=False)
+ print(exc.value.args[0])
+ assert exc.value.args[0] == 'The DNS query name does not exist: example.com.'
def test_error_servfail():
@@ -493,6 +702,306 @@ def test_error_servfail():
assert exc.value.args[0] == 'Error SERVFAIL while querying 1.1.1.1 with query get NS for "com."'
+def test_error_servfail_retry_success():
+ resolver = mock_resolver(['1.1.1.1'], {})
+ udp_sequence = [
+ {
+ 'query_target': dns.name.from_unicode(u'com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.SERVFAIL),
+ },
+ {
+ 'query_target': dns.name.from_unicode(u'com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.SERVFAIL),
+ },
+ {
+ 'query_target': dns.name.from_unicode(u'com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.NOERROR, authority=[dns.rrset.from_rdata(
+ 'com',
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'ns.com'),
+ )]),
+ },
+ ]
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp(udp_sequence)):
+ resolver = ResolveDirectlyFromNameServers(servfail_retries=2)
+ assert resolver.resolve_nameservers('com') == ['ns.com']
+
+
+def test_error_servfail_retry_fail():
+ resolver = mock_resolver(['1.1.1.1'], {})
+ udp_sequence = [
+ {
+ 'query_target': dns.name.from_unicode(u'com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.SERVFAIL),
+ },
+ {
+ 'query_target': dns.name.from_unicode(u'com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.SERVFAIL),
+ },
+ {
+ 'query_target': dns.name.from_unicode(u'com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.SERVFAIL),
+ },
+ ]
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp(udp_sequence)):
+ with pytest.raises(ResolverError) as exc:
+ resolver = ResolveDirectlyFromNameServers(servfail_retries=2)
+ resolver.resolve_nameservers('example.com')
+ assert exc.value.args[0] == 'Error SERVFAIL while querying 1.1.1.1 with query get NS for "com."'
+
+
+def test_servfail_handling():
+ fake_query = MagicMock()
+ fake_query.question = 'Doctor Who?'
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('1.1.1.1', ): [
+ {
+ 'target': 'ns.example.com',
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.SERVFAIL),
+ },
+ {
+ 'target': 'ns.example.com',
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(dns.rrset.from_rdata(
+ 'ns.example.com',
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, '3.3.3.3'),
+ )),
+ },
+ {
+ 'target': 'ns.example.com',
+ 'rdtype': dns.rdatatype.AAAA,
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.SERVFAIL),
+ },
+ {
+ 'target': 'ns.example.com',
+ 'rdtype': dns.rdatatype.AAAA,
+ 'lifetime': 10,
+ 'raise': dns.resolver.NoAnswer(response=fake_query),
+ },
+ {
+ 'target': 'ns.com',
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.SERVFAIL),
+ },
+ {
+ 'target': 'ns.com',
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.SERVFAIL),
+ },
+ {
+ 'target': 'ns.com',
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(dns.rrset.from_rdata(
+ 'ns.com',
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, '2.2.2.2'),
+ )),
+ },
+ {
+ 'target': 'ns.com',
+ 'rdtype': dns.rdatatype.AAAA,
+ 'lifetime': 10,
+ 'raise': dns.resolver.NoAnswer(response=fake_query),
+ },
+ ],
+ })
+ udp_sequence = [
+ {
+ 'query_target': dns.name.from_unicode(u'com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.NOERROR, answer=[dns.rrset.from_rdata(
+ 'com',
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'ns.com'),
+ )]),
+ },
+ {
+ 'query_target': dns.name.from_unicode(u'example.com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.NOERROR, authority=[dns.rrset.from_rdata(
+ 'example.com',
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'ns.example.com'),
+ )]),
+ },
+ ]
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp(udp_sequence)):
+ resolver = ResolveDirectlyFromNameServers(servfail_retries=2)
+ assert resolver.resolve_nameservers('example.com', resolve_addresses=True) == ['3.3.3.3']
+ # The following results should be cached:
+ assert resolver.resolve_nameservers('com') == ['ns.com']
+ assert resolver.resolve_nameservers('com', resolve_addresses=True) == ['2.2.2.2']
+ assert resolver.resolve_nameservers('example.com') == ['ns.example.com']
+ assert resolver.resolve_nameservers('example.com', resolve_addresses=True) == ['3.3.3.3']
+
+
+def test_servfail_failing():
+ fake_query = MagicMock()
+ fake_query.question = 'Doctor Who?'
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('1.1.1.1', ): [
+ {
+ 'target': 'ns.example.com',
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.SERVFAIL),
+ },
+ {
+ 'target': 'ns.example.com',
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(dns.rrset.from_rdata(
+ 'ns.example.com',
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, '3.3.3.3'),
+ )),
+ },
+ {
+ 'target': 'ns.example.com',
+ 'rdtype': dns.rdatatype.AAAA,
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.SERVFAIL),
+ },
+ {
+ 'target': 'ns.example.com',
+ 'rdtype': dns.rdatatype.AAAA,
+ 'lifetime': 10,
+ 'raise': dns.resolver.NoAnswer(response=fake_query),
+ },
+ {
+ 'target': 'ns.com',
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.SERVFAIL),
+ },
+ {
+ 'target': 'ns.com',
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.SERVFAIL),
+ },
+ {
+ 'target': 'ns.com',
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(dns.rrset.from_rdata(
+ 'ns.com',
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, '2.2.2.2'),
+ )),
+ },
+ {
+ 'target': 'ns.com',
+ 'rdtype': dns.rdatatype.AAAA,
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.SERVFAIL),
+ },
+ {
+ 'target': 'ns.com',
+ 'rdtype': dns.rdatatype.AAAA,
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.SERVFAIL),
+ },
+ {
+ 'target': 'ns.com',
+ 'rdtype': dns.rdatatype.AAAA,
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.SERVFAIL),
+ },
+ ],
+ })
+ udp_sequence = [
+ {
+ 'query_target': dns.name.from_unicode(u'com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.NOERROR, answer=[dns.rrset.from_rdata(
+ 'com',
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'ns.com'),
+ )]),
+ },
+ {
+ 'query_target': dns.name.from_unicode(u'example.com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.NOERROR, authority=[dns.rrset.from_rdata(
+ 'example.com',
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'ns.example.com'),
+ )]),
+ },
+ ]
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp(udp_sequence)):
+ resolver = ResolveDirectlyFromNameServers(servfail_retries=2)
+ assert resolver.resolve_nameservers('example.com', resolve_addresses=True) == ['3.3.3.3']
+ # The following results should be cached:
+ assert resolver.resolve_nameservers('com') == ['ns.com']
+ with pytest.raises(ResolverError) as exc:
+ resolver.resolve_nameservers('com', resolve_addresses=True)
+ assert exc.value.args[0] == "Error SERVFAIL while querying ['1.1.1.1']"
+
+
def test_no_response():
fake_query = MagicMock()
fake_query.question = 'Doctor Who?'
diff --git a/ansible_collections/community/dns/tests/unit/plugins/modules/test_nameserver_info.py b/ansible_collections/community/dns/tests/unit/plugins/modules/test_nameserver_info.py
new file mode 100644
index 000000000..e8fd4a6ed
--- /dev/null
+++ b/ansible_collections/community/dns/tests/unit/plugins/modules/test_nameserver_info.py
@@ -0,0 +1,395 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2022, Felix Fontein <felix@fontein.de>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# Make coding more python3-ish
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+import pytest
+
+from ansible_collections.community.internal_test_tools.tests.unit.compat.mock import MagicMock, patch
+
+from ansible_collections.community.internal_test_tools.tests.unit.plugins.modules.utils import (
+ set_module_args,
+ ModuleTestCase,
+ AnsibleExitJson,
+ AnsibleFailJson,
+)
+
+from ansible_collections.community.dns.plugins.modules import nameserver_info
+
+from ..module_utils.resolver_helper import (
+ mock_resolver,
+ mock_query_udp,
+ create_mock_answer,
+ create_mock_response,
+)
+
+# We need dnspython
+dns = pytest.importorskip('dns')
+
+
+class TestNameserverInfo(ModuleTestCase):
+ def test_single(self):
+ fake_query = MagicMock()
+ fake_query.question = 'Doctor Who?'
+ resolver = mock_resolver(['1.1.1.1'], {})
+ udp_sequence = [
+ {
+ 'query_target': dns.name.from_unicode(u'com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.NOERROR, answer=[dns.rrset.from_rdata(
+ 'com',
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'ns.com'),
+ )]),
+ },
+ {
+ 'query_target': dns.name.from_unicode(u'example.com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.NOERROR, answer=[dns.rrset.from_rdata(
+ 'example.com',
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'ns.example.com'),
+ )]),
+ },
+ {
+ 'query_target': dns.name.from_unicode(u'www.example.com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.NOERROR, answer=[dns.rrset.from_rdata(
+ 'www.example.com',
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.example.com. ns.example.com. 12345 7200 120 2419200 10800'),
+ ), dns.rrset.from_rdata(
+ 'www.example.com',
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.CNAME, 'example.org')
+ )]),
+ },
+ ]
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp(udp_sequence)):
+ with pytest.raises(AnsibleExitJson) as exc:
+ set_module_args({
+ 'name': ['www.example.com'],
+ })
+ nameserver_info.main()
+
+ print(exc.value.args[0])
+ assert exc.value.args[0]['changed'] is False
+ assert len(exc.value.args[0]['results']) == 1
+ assert exc.value.args[0]['results'][0]['name'] == 'www.example.com'
+ assert exc.value.args[0]['results'][0]['nameservers'] == [
+ 'ns.example.com',
+ ]
+
+ def test_single_ips(self):
+ fake_query = MagicMock()
+ fake_query.question = 'Doctor Who?'
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('1.1.1.1', ): [
+ {
+ 'target': 'ns.example.com',
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(dns.rrset.from_rdata(
+ 'ns.example.com',
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, '3.3.3.3'),
+ )),
+ },
+ {
+ 'target': 'ns.example.com',
+ 'rdtype': dns.rdatatype.AAAA,
+ 'lifetime': 10,
+ 'result': create_mock_answer(dns.rrset.from_rdata(
+ 'ns.example.com',
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.AAAA, '1:2::3'),
+ )),
+ },
+ ],
+ })
+ udp_sequence = [
+ {
+ 'query_target': dns.name.from_unicode(u'com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.NOERROR, answer=[dns.rrset.from_rdata(
+ 'com',
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'ns.com'),
+ )]),
+ },
+ {
+ 'query_target': dns.name.from_unicode(u'example.com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.NOERROR, answer=[dns.rrset.from_rdata(
+ 'example.com',
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'ns.example.com'),
+ )]),
+ },
+ {
+ 'query_target': dns.name.from_unicode(u'www.example.com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.NOERROR, answer=[dns.rrset.from_rdata(
+ 'www.example.com',
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.example.com. ns.example.com. 12345 7200 120 2419200 10800'),
+ ), dns.rrset.from_rdata(
+ 'www.example.com',
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.CNAME, 'example.org')
+ )]),
+ },
+ ]
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp(udp_sequence)):
+ with pytest.raises(AnsibleExitJson) as exc:
+ set_module_args({
+ 'name': ['www.example.com'],
+ 'resolve_addresses': True,
+ })
+ nameserver_info.main()
+
+ print(exc.value.args[0])
+ assert exc.value.args[0]['changed'] is False
+ assert len(exc.value.args[0]['results']) == 1
+ assert exc.value.args[0]['results'][0]['name'] == 'www.example.com'
+ assert exc.value.args[0]['results'][0]['nameservers'] == [
+ '1:2::3',
+ '3.3.3.3',
+ ]
+
+ def test_timeout(self):
+ fake_query = MagicMock()
+ fake_query.question = 'Doctor Who?'
+ resolver = mock_resolver(['1.1.1.1'], {})
+ udp_sequence = [
+ {
+ 'query_target': dns.name.from_unicode(u'com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 9,
+ },
+ 'result': create_mock_response(dns.rcode.NOERROR, answer=[dns.rrset.from_rdata(
+ 'com',
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'ns.com'),
+ )]),
+ },
+ {
+ 'query_target': dns.name.from_unicode(u'example.com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 9,
+ },
+ 'result': create_mock_response(dns.rcode.NOERROR, answer=[dns.rrset.from_rdata(
+ 'example.com',
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'ns.example.com'),
+ )]),
+ },
+ {
+ 'query_target': dns.name.from_unicode(u'www.example.com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 9,
+ },
+ 'raise': dns.exception.Timeout(timeout=9),
+ },
+ {
+ 'query_target': dns.name.from_unicode(u'www.example.com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 9,
+ },
+ 'result': create_mock_response(dns.rcode.NOERROR, authority=[dns.rrset.from_rdata(
+ 'www.example.com',
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.example.com. ns.example.com. 12345 7200 120 2419200 10800'),
+ )]),
+ },
+ {
+ 'query_target': dns.name.from_unicode(u'mail.example.com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 9,
+ },
+ 'raise': dns.exception.Timeout(timeout=9),
+ },
+ {
+ 'query_target': dns.name.from_unicode(u'mail.example.com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 9,
+ },
+ 'raise': dns.exception.Timeout(timeout=9),
+ },
+ ]
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp(udp_sequence)):
+ with pytest.raises(AnsibleFailJson) as exc:
+ set_module_args({
+ 'name': ['www.example.com', 'mail.example.com'],
+ 'query_timeout': 9,
+ 'query_retry': 1,
+ })
+ nameserver_info.main()
+
+ print(exc.value.args[0])
+ assert exc.value.args[0]['msg'] in (
+ 'Unexpected DNS error: The DNS operation timed out after 9 seconds',
+ 'Unexpected DNS error: The DNS operation timed out after 9.000 seconds',
+ )
+ assert len(exc.value.args[0]['results']) == 2
+ assert exc.value.args[0]['results'][0]['name'] == 'www.example.com'
+ assert exc.value.args[0]['results'][0]['nameservers'] == ['ns.example.com']
+ assert exc.value.args[0]['results'][1]['name'] == 'mail.example.com'
+ assert 'nameservers' not in exc.value.args[0]['results'][1]
+
+ def test_nxdomain(self):
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('1.1.1.1', ): [
+ {
+ 'target': 'ns.example.com',
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(dns.rrset.from_rdata(
+ 'ns.example.com',
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, '3.3.3.3'),
+ )),
+ },
+ {
+ 'target': 'ns.example.com',
+ 'rdtype': dns.rdatatype.AAAA,
+ 'lifetime': 10,
+ 'result': create_mock_answer(dns.rrset.from_rdata(
+ 'ns.example.com',
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.AAAA, '1:2::3'),
+ )),
+ },
+ ],
+ ('1:2::3', '3.3.3.3'): [
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.TXT,
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.NXDOMAIN),
+ },
+ ],
+ })
+ udp_sequence = [
+ {
+ 'query_target': dns.name.from_unicode(u'com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.NXDOMAIN),
+ },
+ {
+ 'query_target': dns.name.from_unicode(u'example.com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.NOERROR, answer=[dns.rrset.from_rdata(
+ 'example.com',
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'ns.example.com'),
+ )]),
+ },
+ {
+ 'query_target': dns.name.from_unicode(u'www.example.com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.NXDOMAIN),
+ },
+ ]
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp(udp_sequence)):
+ with pytest.raises(AnsibleExitJson) as exc:
+ set_module_args({
+ 'name': ['www.example.com'],
+ })
+ nameserver_info.main()
+
+ print(exc.value.args[0])
+ assert exc.value.args[0]['changed'] is False
+ assert len(exc.value.args[0]['results']) == 1
+ assert exc.value.args[0]['results'][0]['name'] == 'www.example.com'
+ assert exc.value.args[0]['results'][0]['nameservers'] == ['ns.example.com']
+
+ def test_servfail(self):
+ resolver = mock_resolver(['1.1.1.1'], {})
+ udp_sequence = [
+ {
+ 'query_target': dns.name.from_unicode(u'com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.SERVFAIL),
+ },
+ ]
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp(udp_sequence)):
+ with pytest.raises(AnsibleFailJson) as exc:
+ set_module_args({
+ 'name': ['www.example.com'],
+ })
+ nameserver_info.main()
+
+ print(exc.value.args[0])
+ assert exc.value.args[0]['msg'] == 'Unexpected resolving error: Error SERVFAIL while querying 1.1.1.1 with query get NS for "com."'
+ assert len(exc.value.args[0]['results']) == 1
+ assert exc.value.args[0]['results'][0]['name'] == 'www.example.com'
+ assert 'nameservers' not in exc.value.args[0]['results'][0]
diff --git a/ansible_collections/community/dns/tests/unit/plugins/modules/test_nameserver_record_info.py b/ansible_collections/community/dns/tests/unit/plugins/modules/test_nameserver_record_info.py
new file mode 100644
index 000000000..ee68586ff
--- /dev/null
+++ b/ansible_collections/community/dns/tests/unit/plugins/modules/test_nameserver_record_info.py
@@ -0,0 +1,592 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2022, Felix Fontein <felix@fontein.de>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# Make coding more python3-ish
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+import pytest
+
+from ansible_collections.community.internal_test_tools.tests.unit.compat.mock import MagicMock, patch
+
+from ansible_collections.community.internal_test_tools.tests.unit.plugins.modules.utils import (
+ set_module_args,
+ ModuleTestCase,
+ AnsibleExitJson,
+ AnsibleFailJson,
+)
+
+from ansible_collections.community.dns.plugins.modules import nameserver_record_info
+
+from ..module_utils.resolver_helper import (
+ mock_resolver,
+ mock_query_udp,
+ create_mock_answer,
+ create_mock_response,
+)
+
+# We need dnspython
+dns = pytest.importorskip('dns')
+
+
+class TestNameserverRecordInfo(ModuleTestCase):
+ def test_single(self):
+ fake_query = MagicMock()
+ fake_query.question = 'Doctor Who?'
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('1.1.1.1', ): [
+ {
+ 'target': 'ns.example.com',
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(dns.rrset.from_rdata(
+ 'ns.example.com',
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, '3.3.3.3'),
+ )),
+ },
+ {
+ 'target': 'ns.example.com',
+ 'rdtype': dns.rdatatype.AAAA,
+ 'lifetime': 10,
+ 'result': create_mock_answer(dns.rrset.from_rdata(
+ 'ns.example.com',
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.AAAA, '1:2::3'),
+ )),
+ },
+ {
+ 'target': 'ns.example.org',
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(dns.rrset.from_rdata(
+ 'ns.example.org',
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, '4.4.4.4'),
+ )),
+ },
+ {
+ 'target': 'ns.example.org',
+ 'rdtype': dns.rdatatype.AAAA,
+ 'lifetime': 10,
+ 'raise': dns.resolver.NoAnswer(response=fake_query),
+ },
+ ],
+ ('1:2::3', '3.3.3.3'): [
+ {
+ 'target': dns.name.from_unicode(u'example.org'),
+ 'rdtype': dns.rdatatype.TXT,
+ 'lifetime': 10,
+ 'result': create_mock_answer(dns.rrset.from_rdata(
+ 'example.org',
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.TXT, 'asdf'),
+ )),
+ },
+ ],
+ ('4.4.4.4', ): [
+ {
+ 'target': dns.name.from_unicode(u'example.org'),
+ 'rdtype': dns.rdatatype.TXT,
+ 'lifetime': 10,
+ 'result': create_mock_answer(dns.rrset.from_rdata(
+ 'example.org',
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.TXT, 'asdf'),
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.TXT, 'fdsa'),
+ )),
+ },
+ ],
+ })
+ udp_sequence = [
+ {
+ 'query_target': dns.name.from_unicode(u'com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.NOERROR, answer=[dns.rrset.from_rdata(
+ 'com',
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'ns.com'),
+ )]),
+ },
+ {
+ 'query_target': dns.name.from_unicode(u'example.com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.NOERROR, answer=[dns.rrset.from_rdata(
+ 'example.com',
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'ns.example.com'),
+ )]),
+ },
+ {
+ 'query_target': dns.name.from_unicode(u'www.example.com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.NOERROR, answer=[dns.rrset.from_rdata(
+ 'www.example.com',
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.example.com. ns.example.com. 12345 7200 120 2419200 10800'),
+ ), dns.rrset.from_rdata(
+ 'www.example.com',
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.CNAME, 'example.org')
+ )]),
+ },
+ {
+ 'query_target': dns.name.from_unicode(u'org'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.NOERROR, answer=[dns.rrset.from_rdata(
+ 'org',
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'ns.org'),
+ )]),
+ },
+ {
+ 'query_target': dns.name.from_unicode(u'example.org'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.NOERROR, answer=[dns.rrset.from_rdata(
+ 'example.org',
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'ns.example.org'),
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'ns.example.com'),
+ )]),
+ },
+ ]
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp(udp_sequence)):
+ with pytest.raises(AnsibleExitJson) as exc:
+ set_module_args({
+ 'name': ['www.example.com'],
+ 'type': 'TXT',
+ })
+ nameserver_record_info.main()
+
+ print(exc.value.args[0])
+ assert exc.value.args[0]['changed'] is False
+ assert len(exc.value.args[0]['results']) == 1
+ assert exc.value.args[0]['results'][0]['name'] == 'www.example.com'
+ assert len(exc.value.args[0]['results'][0]['result']) == 2
+ assert exc.value.args[0]['results'][0]['result'][0]['nameserver'] == 'ns.example.com'
+ assert exc.value.args[0]['results'][0]['result'][0]['values'] == [
+ {
+ 'strings': ['asdf'],
+ 'value': 'asdf',
+ }
+ ]
+ assert exc.value.args[0]['results'][0]['result'][1]['nameserver'] == 'ns.example.org'
+ assert exc.value.args[0]['results'][0]['result'][1]['values'] == [
+ {
+ 'strings': ['asdf'],
+ 'value': 'asdf',
+ },
+ {
+ 'strings': ['fdsa'],
+ 'value': 'fdsa',
+ },
+ ]
+
+ def test_timeout(self):
+ fake_query = MagicMock()
+ fake_query.question = 'Doctor Who?'
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('1.1.1.1', ): [
+ {
+ 'target': 'ns.example.com',
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 9,
+ 'result': create_mock_answer(dns.rrset.from_rdata(
+ 'ns.example.com',
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, '3.3.3.3'),
+ )),
+ },
+ {
+ 'target': 'ns.example.com',
+ 'rdtype': dns.rdatatype.AAAA,
+ 'lifetime': 9,
+ 'raise': dns.resolver.NoAnswer(response=fake_query),
+ },
+ ],
+ ('3.3.3.3', ): [
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.TXT,
+ 'lifetime': 9,
+ 'raise': dns.exception.Timeout(timeout=9),
+ },
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.TXT,
+ 'lifetime': 9,
+ 'result': create_mock_answer(dns.rrset.from_rdata(
+ 'www.example.com',
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.TXT, 'fdsa asdf'),
+ )),
+ },
+ {
+ 'target': dns.name.from_unicode(u'mail.example.com'),
+ 'rdtype': dns.rdatatype.TXT,
+ 'lifetime': 9,
+ 'raise': dns.exception.Timeout(timeout=9),
+ },
+ {
+ 'target': dns.name.from_unicode(u'mail.example.com'),
+ 'rdtype': dns.rdatatype.TXT,
+ 'lifetime': 9,
+ 'raise': dns.exception.Timeout(timeout=9),
+ },
+ ],
+ })
+ udp_sequence = [
+ {
+ 'query_target': dns.name.from_unicode(u'com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 9,
+ },
+ 'result': create_mock_response(dns.rcode.NOERROR, answer=[dns.rrset.from_rdata(
+ 'com',
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'ns.com'),
+ )]),
+ },
+ {
+ 'query_target': dns.name.from_unicode(u'example.com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 9,
+ },
+ 'result': create_mock_response(dns.rcode.NOERROR, answer=[dns.rrset.from_rdata(
+ 'example.com',
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'ns.example.com'),
+ )]),
+ },
+ {
+ 'query_target': dns.name.from_unicode(u'www.example.com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 9,
+ },
+ 'result': create_mock_response(dns.rcode.NOERROR, authority=[dns.rrset.from_rdata(
+ 'www.example.com',
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.example.com. ns.example.com. 12345 7200 120 2419200 10800'),
+ )]),
+ },
+ {
+ 'query_target': dns.name.from_unicode(u'mail.example.com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 9,
+ },
+ 'result': create_mock_response(dns.rcode.NOERROR, authority=[dns.rrset.from_rdata(
+ 'mail.example.com',
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.example.com. ns.example.com. 12345 7200 120 2419200 10800'),
+ )]),
+ },
+ ]
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp(udp_sequence)):
+ with pytest.raises(AnsibleFailJson) as exc:
+ set_module_args({
+ 'name': ['www.example.com', 'mail.example.com'],
+ 'type': 'TXT',
+ 'query_timeout': 9,
+ 'query_retry': 1,
+ })
+ nameserver_record_info.main()
+
+ print(exc.value.args[0])
+ assert exc.value.args[0]['msg'] in (
+ 'Unexpected DNS error: The DNS operation timed out after 9 seconds',
+ 'Unexpected DNS error: The DNS operation timed out after 9.000 seconds',
+ )
+ assert len(exc.value.args[0]['results']) == 2
+ assert exc.value.args[0]['results'][0]['name'] == 'www.example.com'
+ assert exc.value.args[0]['results'][0]['result'] == [
+ {
+ 'nameserver': 'ns.example.com',
+ 'values': [
+ {
+ 'strings': ['fdsa', 'asdf'],
+ 'value': 'fdsaasdf',
+ }
+ ],
+ }
+ ]
+ assert exc.value.args[0]['results'][1]['name'] == 'mail.example.com'
+ assert exc.value.args[0]['results'][1]['result'] == []
+
+ def test_nxdomain(self):
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('1.1.1.1', ): [
+ {
+ 'target': 'ns.example.com',
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(dns.rrset.from_rdata(
+ 'ns.example.com',
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, '3.3.3.3'),
+ )),
+ },
+ {
+ 'target': 'ns.example.com',
+ 'rdtype': dns.rdatatype.AAAA,
+ 'lifetime': 10,
+ 'result': create_mock_answer(dns.rrset.from_rdata(
+ 'ns.example.com',
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.AAAA, '1:2::3'),
+ )),
+ },
+ ],
+ ('1:2::3', '3.3.3.3'): [
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.TXT,
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.NXDOMAIN),
+ },
+ ],
+ })
+ udp_sequence = [
+ {
+ 'query_target': dns.name.from_unicode(u'com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.NXDOMAIN),
+ },
+ {
+ 'query_target': dns.name.from_unicode(u'example.com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.NOERROR, answer=[dns.rrset.from_rdata(
+ 'example.com',
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'ns.example.com'),
+ )]),
+ },
+ {
+ 'query_target': dns.name.from_unicode(u'www.example.com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.NXDOMAIN),
+ },
+ ]
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp(udp_sequence)):
+ with pytest.raises(AnsibleExitJson) as exc:
+ set_module_args({
+ 'name': ['www.example.com'],
+ 'type': 'TXT',
+ })
+ nameserver_record_info.main()
+
+ print(exc.value.args[0])
+ assert exc.value.args[0]['changed'] is False
+ assert len(exc.value.args[0]['results']) == 1
+ assert exc.value.args[0]['results'][0]['name'] == 'www.example.com'
+ assert len(exc.value.args[0]['results'][0]['result']) == 1
+ assert exc.value.args[0]['results'][0]['result'][0]['nameserver'] == 'ns.example.com'
+ assert exc.value.args[0]['results'][0]['result'][0]['values'] == []
+
+ def test_servfail(self):
+ resolver = mock_resolver(['1.1.1.1'], {})
+ udp_sequence = [
+ {
+ 'query_target': dns.name.from_unicode(u'com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.SERVFAIL),
+ },
+ ]
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp(udp_sequence)):
+ with pytest.raises(AnsibleFailJson) as exc:
+ set_module_args({
+ 'name': ['www.example.com'],
+ 'type': 'TXT',
+ })
+ nameserver_record_info.main()
+
+ print(exc.value.args[0])
+ assert exc.value.args[0]['msg'] == 'Unexpected resolving error: Error SERVFAIL while querying 1.1.1.1 with query get NS for "com."'
+ assert len(exc.value.args[0]['results']) == 1
+ assert exc.value.args[0]['results'][0]['name'] == 'www.example.com'
+ assert exc.value.args[0]['results'][0]['result'] == []
+
+ def test_cname_loop(self):
+ fake_query = MagicMock()
+ fake_query.question = 'Doctor Who?'
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('1.1.1.1', ): [
+ {
+ 'target': 'ns.example.com',
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(dns.rrset.from_rdata(
+ 'ns.example.com',
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, '3.3.3.3'),
+ )),
+ },
+ {
+ 'target': 'ns.example.com',
+ 'rdtype': dns.rdatatype.AAAA,
+ 'lifetime': 10,
+ 'raise': dns.resolver.NoAnswer(response=fake_query),
+ },
+ {
+ 'target': 'ns.example.org',
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(dns.rrset.from_rdata(
+ 'ns.example.org',
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, '4.4.4.4'),
+ )),
+ },
+ {
+ 'target': 'ns.example.org',
+ 'rdtype': dns.rdatatype.AAAA,
+ 'lifetime': 10,
+ 'raise': dns.resolver.NoAnswer(response=fake_query),
+ },
+ ],
+ })
+ udp_sequence = [
+ {
+ 'query_target': dns.name.from_unicode(u'com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.NOERROR, answer=[dns.rrset.from_rdata(
+ 'com',
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'ns.com'),
+ )]),
+ },
+ {
+ 'query_target': dns.name.from_unicode(u'example.com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.NOERROR, answer=[dns.rrset.from_rdata(
+ 'example.com',
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'ns.example.com'),
+ )]),
+ },
+ {
+ 'query_target': dns.name.from_unicode(u'www.example.com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.NOERROR, answer=[dns.rrset.from_rdata(
+ 'www.example.com',
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.SOA, 'ns.example.com. ns.example.com. 12345 7200 120 2419200 10800'),
+ ), dns.rrset.from_rdata(
+ 'www.example.com',
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.CNAME, 'example.org')
+ )]),
+ },
+ {
+ 'query_target': dns.name.from_unicode(u'org'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.NOERROR, answer=[dns.rrset.from_rdata(
+ 'org',
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'ns.org'),
+ )]),
+ },
+ {
+ 'query_target': dns.name.from_unicode(u'example.org'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.NOERROR, answer=[dns.rrset.from_rdata(
+ 'example.org',
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'ns.example.org'),
+ ), dns.rrset.from_rdata(
+ 'example.org',
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.CNAME, 'www.example.com')
+ )]),
+ },
+ ]
+ with patch('dns.resolver.get_default_resolver', resolver):
+ with patch('dns.resolver.Resolver', resolver):
+ with patch('dns.query.udp', mock_query_udp(udp_sequence)):
+ with pytest.raises(AnsibleFailJson) as exc:
+ set_module_args({
+ 'name': ['www.example.com'],
+ 'type': 'TXT',
+ })
+ nameserver_record_info.main()
+
+ print(exc.value.args[0])
+ assert exc.value.args[0]['msg'] == 'Unexpected resolving error: Found CNAME loop starting at www.example.com'
+ assert len(exc.value.args[0]['results']) == 1
+ assert exc.value.args[0]['results'][0]['name'] == 'www.example.com'
+ assert exc.value.args[0]['results'][0]['result'] == []
diff --git a/ansible_collections/community/dns/tests/unit/plugins/modules/test_wait_for_txt.py b/ansible_collections/community/dns/tests/unit/plugins/modules/test_wait_for_txt.py
index 829d6465e..9ee935ba0 100644
--- a/ansible_collections/community/dns/tests/unit/plugins/modules/test_wait_for_txt.py
+++ b/ansible_collections/community/dns/tests/unit/plugins/modules/test_wait_for_txt.py
@@ -1195,7 +1195,44 @@ class TestWaitForTXT(ModuleTestCase):
assert exc.value.args[0]['records'][1]['check_count'] == 1
def test_nxdomain(self):
- resolver = mock_resolver(['1.1.1.1'], {})
+ resolver = mock_resolver(['1.1.1.1'], {
+ ('1.1.1.1', ): [
+ {
+ 'target': 'ns.example.com',
+ 'rdtype': dns.rdatatype.A,
+ 'lifetime': 10,
+ 'result': create_mock_answer(dns.rrset.from_rdata(
+ 'ns.example.com',
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.A, '3.3.3.3'),
+ )),
+ },
+ {
+ 'target': 'ns.example.com',
+ 'rdtype': dns.rdatatype.AAAA,
+ 'lifetime': 10,
+ 'result': create_mock_answer(dns.rrset.from_rdata(
+ 'ns.example.com',
+ 300,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.AAAA, '1:2::3'),
+ )),
+ },
+ ],
+ ('1:2::3', '3.3.3.3'): [
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.TXT,
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.NXDOMAIN),
+ },
+ {
+ 'target': dns.name.from_unicode(u'www.example.com'),
+ 'rdtype': dns.rdatatype.TXT,
+ 'lifetime': 10,
+ 'result': create_mock_answer(rcode=dns.rcode.NXDOMAIN),
+ },
+ ],
+ })
udp_sequence = [
{
'query_target': dns.name.from_unicode(u'com'),
@@ -1207,7 +1244,20 @@ class TestWaitForTXT(ModuleTestCase):
'result': create_mock_response(dns.rcode.NXDOMAIN),
},
{
- 'query_target': dns.name.from_unicode(u'com'),
+ 'query_target': dns.name.from_unicode(u'example.com'),
+ 'query_type': dns.rdatatype.NS,
+ 'nameserver': '1.1.1.1',
+ 'kwargs': {
+ 'timeout': 10,
+ },
+ 'result': create_mock_response(dns.rcode.NOERROR, answer=[dns.rrset.from_rdata(
+ 'example.com',
+ 3600,
+ dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS, 'ns.example.com'),
+ )]),
+ },
+ {
+ 'query_target': dns.name.from_unicode(u'www.example.com'),
'query_type': dns.rdatatype.NS,
'nameserver': '1.1.1.1',
'kwargs': {
@@ -1237,12 +1287,14 @@ class TestWaitForTXT(ModuleTestCase):
wait_for_txt.main()
print(exc.value.args[0])
+ assert exc.value.args[0]['failed'] is True
assert exc.value.args[0]['msg'] == 'Timeout (0 out of 1 check(s) passed).'
assert exc.value.args[0]['completed'] == 0
assert len(exc.value.args[0]['records']) == 1
assert exc.value.args[0]['records'][0]['name'] == 'www.example.com'
assert exc.value.args[0]['records'][0]['done'] is False
- assert exc.value.args[0]['records'][0]['values'] == {}
+ assert len(exc.value.args[0]['records'][0]['values']) == 1
+ assert exc.value.args[0]['records'][0]['values']['ns.example.com'] == []
assert exc.value.args[0]['records'][0]['check_count'] == 2
def test_servfail(self):
diff --git a/ansible_collections/community/dns/tests/unit/plugins/plugin_utils/test_ips.py b/ansible_collections/community/dns/tests/unit/plugins/plugin_utils/test_ips.py
new file mode 100644
index 000000000..211bad1bf
--- /dev/null
+++ b/ansible_collections/community/dns/tests/unit/plugins/plugin_utils/test_ips.py
@@ -0,0 +1,39 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2023, Felix Fontein <felix@fontein.de>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# Make coding more python3-ish
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+import pytest
+
+from ansible.errors import AnsibleError
+
+from ansible_collections.community.dns.plugins.plugin_utils import ips
+
+from ansible_collections.community.dns.plugins.plugin_utils.ips import (
+ assert_requirements_present,
+)
+
+# We need ipaddress
+ipaddress = pytest.importorskip('ipaddress')
+
+
+def test_assert_requirements_present():
+ orig_importerror = ips.IPADDRESS_IMPORT_EXC
+ try:
+ ips.IPADDRESS_IMPORT_EXC = None
+ assert_requirements_present('community.dns.foo', 'lookup')
+
+ ips.IPADDRESS_IMPORT_EXC = Exception('asdf')
+ with pytest.raises(AnsibleError) as exc:
+ assert_requirements_present('community.dns.foo', 'lookup')
+
+ assert 'ipaddress' in exc.value.args[0]
+
+ finally:
+ ips.IPADDRESS_IMPORT_EXC = orig_importerror
diff --git a/ansible_collections/community/dns/tests/unit/plugins/plugin_utils/test_resolver.py b/ansible_collections/community/dns/tests/unit/plugins/plugin_utils/test_resolver.py
new file mode 100644
index 000000000..578155a68
--- /dev/null
+++ b/ansible_collections/community/dns/tests/unit/plugins/plugin_utils/test_resolver.py
@@ -0,0 +1,36 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2023, Felix Fontein <felix@fontein.de>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# Make coding more python3-ish
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+import pytest
+
+from ansible.errors import AnsibleError
+
+from ansible_collections.community.dns.plugins.plugin_utils import resolver
+
+from ansible_collections.community.dns.plugins.plugin_utils.resolver import (
+ assert_requirements_present,
+)
+
+
+def test_assert_requirements_present():
+ orig_importerror = resolver.DNSPYTHON_IMPORTERROR
+ try:
+ resolver.DNSPYTHON_IMPORTERROR = None
+ assert_requirements_present('community.dns.foo', 'lookup')
+
+ resolver.DNSPYTHON_IMPORTERROR = Exception('asdf')
+ with pytest.raises(AnsibleError) as exc:
+ assert_requirements_present('community.dns.foo', 'lookup')
+
+ assert 'dnspython' in exc.value.args[0]
+
+ finally:
+ resolver.DNSPYTHON_IMPORTERROR = orig_importerror
diff --git a/ansible_collections/community/dns/tests/unit/replace-requirements.sh b/ansible_collections/community/dns/tests/unit/replace-requirements.sh
new file mode 100755
index 000000000..c3a52f5d1
--- /dev/null
+++ b/ansible_collections/community/dns/tests/unit/replace-requirements.sh
@@ -0,0 +1,10 @@
+#!/usr/bin/env bash
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+DIRECTORY="$(dirname "$0")"
+
+if [ -e "${DIRECTORY}/$1" ]; then
+ cp "${DIRECTORY}/$1" "${DIRECTORY}/requirements.txt"
+fi
diff --git a/ansible_collections/community/dns/tests/unit/requirements-stable-2.10.txt b/ansible_collections/community/dns/tests/unit/requirements-stable-2.10.txt
new file mode 100644
index 000000000..126caabdc
--- /dev/null
+++ b/ansible_collections/community/dns/tests/unit/requirements-stable-2.10.txt
@@ -0,0 +1,13 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+unittest2 ; python_version < '2.7'
+importlib ; python_version < '2.7'
+
+ipaddress ; python_version < '3.3'
+
+dnspython < 2.4.0
+
+lxml < 4.3.0 ; python_version < '2.7' # lxml 4.3.0 and later require python 2.7 or later
+lxml ; python_version >= '2.7'
diff --git a/ansible_collections/community/dns/tests/unit/requirements-stable-2.9.txt b/ansible_collections/community/dns/tests/unit/requirements-stable-2.9.txt
new file mode 100644
index 000000000..126caabdc
--- /dev/null
+++ b/ansible_collections/community/dns/tests/unit/requirements-stable-2.9.txt
@@ -0,0 +1,13 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+unittest2 ; python_version < '2.7'
+importlib ; python_version < '2.7'
+
+ipaddress ; python_version < '3.3'
+
+dnspython < 2.4.0
+
+lxml < 4.3.0 ; python_version < '2.7' # lxml 4.3.0 and later require python 2.7 or later
+lxml ; python_version >= '2.7'
diff --git a/ansible_collections/community/dns/tests/unit/requirements.txt b/ansible_collections/community/dns/tests/unit/requirements.txt
index 8b7c7cd61..dff61418a 100644
--- a/ansible_collections/community/dns/tests/unit/requirements.txt
+++ b/ansible_collections/community/dns/tests/unit/requirements.txt
@@ -5,6 +5,8 @@
unittest2 ; python_version < '2.7'
importlib ; python_version < '2.7'
+ipaddress ; python_version < '3.3'
+
dnspython
lxml < 4.3.0 ; python_version < '2.7' # lxml 4.3.0 and later require python 2.7 or later
diff --git a/ansible_collections/community/dns/update-docs-fragments.py b/ansible_collections/community/dns/update-docs-fragments.py
index 9ceba70f1..eac0aaae3 100755
--- a/ansible_collections/community/dns/update-docs-fragments.py
+++ b/ansible_collections/community/dns/update-docs-fragments.py
@@ -42,7 +42,7 @@ DEPENDENT_FRAGMENTS = [
]),
]),
('RECORD_TYPE_CHOICES_RECORDS_INVENTORY', [
- ('record_type', 'options.filters.suboptions.type', [
+ ('record_type', 'options.simple_filters.suboptions.type', [
'inventory_records',
]),
]),
diff --git a/ansible_collections/community/docker/.azure-pipelines/azure-pipelines.yml b/ansible_collections/community/docker/.azure-pipelines/azure-pipelines.yml
index ac5c8623d..b54ccc148 100644
--- a/ansible_collections/community/docker/.azure-pipelines/azure-pipelines.yml
+++ b/ansible_collections/community/docker/.azure-pipelines/azure-pipelines.yml
@@ -46,7 +46,7 @@ variables:
resources:
containers:
- container: default
- image: quay.io/ansible/azure-pipelines-test-container:3.0.0
+ image: quay.io/ansible/azure-pipelines-test-container:4.0.1
pool: Standard
@@ -66,6 +66,17 @@ stages:
test: 'devel/sanity/extra'
- name: Units
test: 'devel/units/1'
+ - stage: Ansible_2_16
+ displayName: Sanity & Units 2.16
+ dependsOn: []
+ jobs:
+ - template: templates/matrix.yml
+ parameters:
+ targets:
+ - name: Sanity
+ test: '2.16/sanity/1'
+ - name: Units
+ test: '2.16/units/1'
- stage: Ansible_2_15
displayName: Sanity & Units 2.15
dependsOn: []
@@ -88,17 +99,6 @@ stages:
test: '2.14/sanity/1'
- name: Units
test: '2.14/units/1'
- - stage: Ansible_2_13
- displayName: Sanity & Units 2.13
- dependsOn: []
- jobs:
- - template: templates/matrix.yml
- parameters:
- targets:
- - name: Sanity
- test: '2.13/sanity/1'
- - name: Units
- test: '2.13/units/1'
### Docker
- stage: Docker_devel
@@ -109,12 +109,8 @@ stages:
parameters:
testFormat: devel/linux/{0}
targets:
- - name: CentOS 7
- test: centos7
- - name: Fedora 37
- test: fedora37
- - name: openSUSE 15
- test: opensuse15
+ - name: Fedora 39
+ test: fedora39
- name: Ubuntu 20.04
test: ubuntu2004
- name: Ubuntu 22.04
@@ -124,49 +120,55 @@ stages:
groups:
- 4
- 5
- - stage: Docker_2_15
- displayName: Docker 2.15
+ - 6
+ - stage: Docker_2_16
+ displayName: Docker 2.16
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
- testFormat: 2.15/linux/{0}
+ testFormat: 2.16/linux/{0}
targets:
+ - name: Fedora 38
+ test: fedora38
- name: CentOS 7
test: centos7
+ - name: openSUSE 15
+ test: opensuse15
groups:
- 4
- 5
- - stage: Docker_2_14
- displayName: Docker 2.14
+ - 6
+ - stage: Docker_2_15
+ displayName: Docker 2.15
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
- testFormat: 2.14/linux/{0}
+ testFormat: 2.15/linux/{0}
targets:
- - name: Fedora 36
- test: fedora36
+ - name: Fedora 37
+ test: fedora37
+ - name: CentOS 7
+ test: centos7
groups:
- 4
- 5
- - stage: Docker_2_13
- displayName: Docker 2.13
+ - 6
+ - stage: Docker_2_14
+ displayName: Docker 2.14
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
- testFormat: 2.13/linux/{0}
+ testFormat: 2.14/linux/{0}
targets:
- - name: Fedora 35
- test: fedora35
- - name: openSUSE 15 py2
- test: opensuse15py2
- name: Alpine 3
test: alpine3
groups:
- 4
- 5
+ - 6
### Community Docker
- stage: Docker_community_devel
@@ -179,15 +181,14 @@ stages:
targets:
- name: Debian Bullseye
test: debian-bullseye/3.9
+ - name: Debian Bookworm
+ test: debian-bookworm/3.11
- name: ArchLinux
test: archlinux/3.11
- - name: CentOS Stream 8 with Python 3.6
- test: centos-stream8/3.6
- - name: CentOS Stream 8 with Python 3.9
- test: centos-stream8/3.9
groups:
- 4
- 5
+ - 6
### Remote
- stage: Remote_devel
@@ -198,56 +199,64 @@ stages:
parameters:
testFormat: devel/{0}
targets:
- - name: RHEL 9.1 with latest Docker SDK from PyPi
- test: rhel/9.1-pypi-latest
+ - name: RHEL 9.3 with latest Docker SDK from PyPi
+ test: rhel/9.3-pypi-latest
+ # Currently always hangs in group 2
+ # - name: RHEL 8.8
+ # test: rhel/8.8
groups:
- 1
- 2
- 3
- 4
- 5
- - stage: Remote_2_15
- displayName: Remote 2.15
+ - 6
+ - stage: Remote_2_16
+ displayName: Remote 2.16
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
- testFormat: 2.15/{0}
+ testFormat: 2.16/{0}
targets:
- - name: RHEL 7.9
- test: rhel/7.9
+ - name: RHEL 9.2
+ test: rhel/9.2
groups:
- 1
- 2
- 3
- 4
- 5
- - stage: Remote_2_14
- displayName: Remote 2.14
+ - stage: Remote_2_15
+ displayName: Remote 2.15
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
- testFormat: 2.14/{0}
+ testFormat: 2.15/{0}
targets:
- - name: RHEL 9.0
- test: rhel/9.0
+ - name: RHEL 9.1
+ test: rhel/9.1
+ - name: RHEL 8.7
+ test: rhel/8.7
+ - name: RHEL 7.9
+ test: rhel/7.9
groups:
- 1
- 2
- 3
- 4
- 5
- - stage: Remote_2_13
- displayName: Remote 2.13
+ - stage: Remote_2_14
+ displayName: Remote 2.14
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
- testFormat: 2.13/{0}
+ testFormat: 2.14/{0}
targets:
- - name: RHEL 8.5
- test: rhel/8.5
+ - name: RHEL 9.0
+ test: rhel/9.0
groups:
- 1
- 2
@@ -261,17 +270,17 @@ stages:
condition: succeededOrFailed()
dependsOn:
- Ansible_devel
+ - Ansible_2_16
- Ansible_2_15
- Ansible_2_14
- - Ansible_2_13
- Remote_devel
+ - Remote_2_16
- Remote_2_15
- Remote_2_14
- - Remote_2_13
- Docker_devel
+ - Docker_2_16
- Docker_2_15
- Docker_2_14
- - Docker_2_13
- Docker_community_devel
jobs:
- template: templates/coverage.yml
diff --git a/ansible_collections/community/docker/.github/workflows/ansible-test.yml b/ansible_collections/community/docker/.github/workflows/ansible-test.yml
index 6aa69f015..d8910d9f6 100644
--- a/ansible_collections/community/docker/.github/workflows/ansible-test.yml
+++ b/ansible_collections/community/docker/.github/workflows/ansible-test.yml
@@ -31,6 +31,7 @@ jobs:
ansible:
- '2.11'
- '2.12'
+ - '2.13'
# Ansible-test on various stable branches does not yet work well with cgroups v2.
# Since ubuntu-latest now uses Ubuntu 22.04, we need to fall back to the ubuntu-20.04
# image for these stable branches. The list of branches where this is necessary will
@@ -49,6 +50,8 @@ jobs:
coverage: ${{ github.event_name == 'schedule' && 'always' || 'never' }}
pull-request-change-detection: 'true'
testing-type: sanity
+ pre-test-cmd: >-
+ git clone --depth=1 --single-branch --branch stable-1 https://github.com/ansible-collections/community.library_inventory_filtering.git ../../community/library_inventory_filtering_v1
units:
# Ansible-test on various stable branches does not yet work well with cgroups v2.
@@ -68,11 +71,10 @@ jobs:
ansible:
- '2.11'
- '2.12'
+ - '2.13'
steps:
- - name: >-
- Perform unit testing against
- Ansible version ${{ matrix.ansible }}
+ - name: Perform unit testing against Ansible version ${{ matrix.ansible }}
uses: felixfontein/ansible-test-gh-action@main
with:
ansible-core-github-repository-slug: ${{ contains(fromJson('["2.10", "2.11"]'), matrix.ansible) && 'felixfontein/ansible' || 'ansible/ansible' }}
@@ -80,6 +82,8 @@ jobs:
coverage: ${{ github.event_name == 'schedule' && 'always' || 'never' }}
pull-request-change-detection: 'true'
testing-type: units
+ pre-test-cmd: >-
+ git clone --depth=1 --single-branch --branch stable-1 https://github.com/ansible-collections/community.library_inventory_filtering.git ../../community/library_inventory_filtering_v1
integration:
# Ansible-test on various stable branches does not yet work well with cgroups v2.
@@ -120,6 +124,10 @@ jobs:
python: ''
target: azp/5/
- ansible: '2.11'
+ docker: fedora32
+ python: ''
+ target: azp/6/
+ - ansible: '2.11'
docker: alpine3
python: ''
target: azp/4/
@@ -128,6 +136,10 @@ jobs:
docker: alpine3
python: ''
target: azp/5/
+ - ansible: '2.11'
+ docker: alpine3
+ python: ''
+ target: azp/6/
# 2.12
- ansible: '2.12'
docker: fedora33
@@ -138,6 +150,10 @@ jobs:
python: ''
target: azp/5/
- ansible: '2.12'
+ docker: fedora33
+ python: ''
+ target: azp/6/
+ - ansible: '2.12'
docker: fedora34
python: ''
target: azp/4/
@@ -146,6 +162,10 @@ jobs:
python: ''
target: azp/5/
- ansible: '2.12'
+ docker: fedora34
+ python: ''
+ target: azp/6/
+ - ansible: '2.12'
docker: ubuntu1804
python: ''
target: azp/4/
@@ -153,12 +173,50 @@ jobs:
docker: ubuntu1804
python: ''
target: azp/5/
+ - ansible: '2.12'
+ docker: ubuntu1804
+ python: ''
+ target: azp/6/
+ # 2.13
+ - ansible: '2.13'
+ docker: fedora35
+ python: ''
+ target: azp/4/
+ - ansible: '2.13'
+ docker: fedora35
+ python: ''
+ target: azp/5/
+ - ansible: '2.13'
+ docker: fedora35
+ python: ''
+ target: azp/6/
+ - ansible: '2.13'
+ docker: opensuse15py2
+ python: ''
+ target: azp/4/
+ - ansible: '2.13'
+ docker: opensuse15py2
+ python: ''
+ target: azp/5/
+ - ansible: '2.13'
+ docker: opensuse15py2
+ python: ''
+ target: azp/6/
+ - ansible: '2.13'
+ docker: alpine3
+ python: ''
+ target: azp/4/
+ - ansible: '2.13'
+ docker: alpine3
+ python: ''
+ target: azp/5/
+ - ansible: '2.13'
+ docker: alpine3
+ python: ''
+ target: azp/6/
steps:
- - name: >-
- Perform integration testing against
- Ansible version ${{ matrix.ansible }}
- under Python ${{ matrix.python }}
+ - name: Perform integration testing against Ansible version ${{ matrix.ansible }} under Python ${{ matrix.python }}
uses: felixfontein/ansible-test-gh-action@main
with:
ansible-core-github-repository-slug: ${{ contains(fromJson('["2.10", "2.11"]'), matrix.ansible) && 'felixfontein/ansible' || 'ansible/ansible' }}
@@ -176,6 +234,8 @@ jobs:
git clone --depth=1 --single-branch https://github.com/ansible-collections/community.crypto.git ../../community/crypto
;
git clone --depth=1 --single-branch https://github.com/ansible-collections/community.general.git ../../community/general
+ ;
+ git clone --depth=1 --single-branch --branch stable-1 https://github.com/ansible-collections/community.library_inventory_filtering.git ../../community/library_inventory_filtering_v1
${{ matrix.extra-constraints && format('; echo ''{0}'' >> tests/utils/constraints.txt', matrix.extra-constraints) || '' }}
;
cat tests/utils/constraints.txt
diff --git a/ansible_collections/community/docker/.github/workflows/docs-pr.yml b/ansible_collections/community/docker/.github/workflows/docs-pr.yml
index c63bdbfc6..74aad8825 100644
--- a/ansible_collections/community/docker/.github/workflows/docs-pr.yml
+++ b/ansible_collections/community/docker/.github/workflows/docs-pr.yml
@@ -32,6 +32,7 @@ jobs:
init-extra-html-theme-options: |
documentation_home_url=https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/branch/main/
render-file-line: '> * `$<status>` [$<path_tail>](https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/pr/${{ github.event.number }}/$<path_tail>)'
+ extra-collections: community.library_inventory_filtering_v1
publish-docs-gh-pages:
# for now we won't run this on forks
diff --git a/ansible_collections/community/docker/.github/workflows/docs-push.yml b/ansible_collections/community/docker/.github/workflows/docs-push.yml
index ccc320850..8ed0d874b 100644
--- a/ansible_collections/community/docker/.github/workflows/docs-push.yml
+++ b/ansible_collections/community/docker/.github/workflows/docs-push.yml
@@ -37,6 +37,7 @@ jobs:
init-html-short-title: Community.Docker Collection Docs
init-extra-html-theme-options: |
documentation_home_url=https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/branch/main/
+ extra-collections: community.library_inventory_filtering_v1
publish-docs-gh-pages:
# for now we won't run this on forks
diff --git a/ansible_collections/community/docker/.github/workflows/ee.yml b/ansible_collections/community/docker/.github/workflows/ee.yml
index 2b2675b0c..d884f56ef 100644
--- a/ansible_collections/community/docker/.github/workflows/ee.yml
+++ b/ansible_collections/community/docker/.github/workflows/ee.yml
@@ -46,6 +46,10 @@ jobs:
- name: ansible-core devel @ RHEL UBI 9
ansible_core: https://github.com/ansible/ansible/archive/devel.tar.gz
ansible_runner: ansible-runner
+ other_deps: |2
+ python_interpreter:
+ package_system: python3.11 python3.11-pip python3.11-wheel python3.11-cryptography
+ python_path: "/usr/bin/python3.11"
base_image: docker.io/redhat/ubi9:latest
pre_base: '"#"'
- name: ansible-core 2.15 @ Rocky Linux 9
@@ -77,12 +81,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
path: ansible_collections/${{ env.NAMESPACE }}/${{ env.COLLECTION_NAME }}
- name: Set up Python
- uses: actions/setup-python@v4
+ uses: actions/setup-python@v5
with:
python-version: '3.11'
diff --git a/ansible_collections/community/docker/.github/workflows/import-galaxy.yml b/ansible_collections/community/docker/.github/workflows/import-galaxy.yml
new file mode 100644
index 000000000..0c0ee402a
--- /dev/null
+++ b/ansible_collections/community/docker/.github/workflows/import-galaxy.yml
@@ -0,0 +1,20 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+name: import-galaxy
+'on':
+ # Run CI against all pushes (direct commits, also merged PRs) to main, and all Pull Requests
+ push:
+ branches:
+ - main
+ - stable-*
+ pull_request:
+
+jobs:
+ import-galaxy:
+ permissions:
+ contents: read
+ name: Test to import built collection artifact with Galaxy importer
+ uses: ansible-community/github-action-test-galaxy-import/.github/workflows/test-galaxy-import.yml@main
diff --git a/ansible_collections/community/docker/.github/workflows/reuse.yml b/ansible_collections/community/docker/.github/workflows/reuse.yml
index 8d9ebde8d..8064af149 100644
--- a/ansible_collections/community/docker/.github/workflows/reuse.yml
+++ b/ansible_collections/community/docker/.github/workflows/reuse.yml
@@ -21,12 +21,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- - name: Install dependencies
- run: |
- pip install reuse
-
- - name: Check REUSE compliance
- run: |
- reuse lint
+ - name: REUSE Compliance Check
+ uses: fsfe/reuse-action@v3
diff --git a/ansible_collections/community/docker/CHANGELOG.md b/ansible_collections/community/docker/CHANGELOG.md
new file mode 100644
index 000000000..2e232e769
--- /dev/null
+++ b/ansible_collections/community/docker/CHANGELOG.md
@@ -0,0 +1,1390 @@
+# Docker Community Collection Release Notes
+
+**Topics**
+
+- <a href="#v3-8-1">v3\.8\.1</a>
+ - <a href="#release-summary">Release Summary</a>
+ - <a href="#security-fixes">Security Fixes</a>
+ - <a href="#bugfixes">Bugfixes</a>
+- <a href="#v3-8-0">v3\.8\.0</a>
+ - <a href="#release-summary-1">Release Summary</a>
+ - <a href="#minor-changes">Minor Changes</a>
+ - <a href="#bugfixes-1">Bugfixes</a>
+- <a href="#v3-7-0">v3\.7\.0</a>
+ - <a href="#release-summary-2">Release Summary</a>
+ - <a href="#minor-changes-1">Minor Changes</a>
+ - <a href="#bugfixes-2">Bugfixes</a>
+ - <a href="#new-modules">New Modules</a>
+- <a href="#v3-6-0">v3\.6\.0</a>
+ - <a href="#release-summary-3">Release Summary</a>
+ - <a href="#major-changes">Major Changes</a>
+ - <a href="#minor-changes-2">Minor Changes</a>
+ - <a href="#bugfixes-3">Bugfixes</a>
+ - <a href="#new-modules-1">New Modules</a>
+- <a href="#v3-5-0">v3\.5\.0</a>
+ - <a href="#release-summary-4">Release Summary</a>
+ - <a href="#minor-changes-3">Minor Changes</a>
+ - <a href="#deprecated-features">Deprecated Features</a>
+ - <a href="#bugfixes-4">Bugfixes</a>
+- <a href="#v3-4-11">v3\.4\.11</a>
+ - <a href="#release-summary-5">Release Summary</a>
+ - <a href="#bugfixes-5">Bugfixes</a>
+- <a href="#v3-4-10">v3\.4\.10</a>
+ - <a href="#release-summary-6">Release Summary</a>
+ - <a href="#bugfixes-6">Bugfixes</a>
+- <a href="#v3-4-9">v3\.4\.9</a>
+ - <a href="#release-summary-7">Release Summary</a>
+ - <a href="#bugfixes-7">Bugfixes</a>
+- <a href="#v3-4-8">v3\.4\.8</a>
+ - <a href="#release-summary-8">Release Summary</a>
+ - <a href="#known-issues">Known Issues</a>
+- <a href="#v3-4-7">v3\.4\.7</a>
+ - <a href="#release-summary-9">Release Summary</a>
+ - <a href="#bugfixes-8">Bugfixes</a>
+- <a href="#v3-4-6">v3\.4\.6</a>
+ - <a href="#release-summary-10">Release Summary</a>
+ - <a href="#bugfixes-9">Bugfixes</a>
+ - <a href="#known-issues-1">Known Issues</a>
+- <a href="#v3-4-5">v3\.4\.5</a>
+ - <a href="#release-summary-11">Release Summary</a>
+ - <a href="#bugfixes-10">Bugfixes</a>
+- <a href="#v3-4-4">v3\.4\.4</a>
+ - <a href="#release-summary-12">Release Summary</a>
+ - <a href="#minor-changes-4">Minor Changes</a>
+ - <a href="#known-issues-2">Known Issues</a>
+- <a href="#v3-4-3">v3\.4\.3</a>
+ - <a href="#release-summary-13">Release Summary</a>
+- <a href="#v3-4-2">v3\.4\.2</a>
+ - <a href="#release-summary-14">Release Summary</a>
+ - <a href="#bugfixes-11">Bugfixes</a>
+- <a href="#v3-4-1">v3\.4\.1</a>
+ - <a href="#release-summary-15">Release Summary</a>
+ - <a href="#bugfixes-12">Bugfixes</a>
+- <a href="#v3-4-0">v3\.4\.0</a>
+ - <a href="#release-summary-16">Release Summary</a>
+ - <a href="#minor-changes-5">Minor Changes</a>
+ - <a href="#bugfixes-13">Bugfixes</a>
+ - <a href="#new-modules-2">New Modules</a>
+- <a href="#v3-3-2">v3\.3\.2</a>
+ - <a href="#release-summary-17">Release Summary</a>
+ - <a href="#bugfixes-14">Bugfixes</a>
+- <a href="#v3-3-1">v3\.3\.1</a>
+ - <a href="#release-summary-18">Release Summary</a>
+ - <a href="#bugfixes-15">Bugfixes</a>
+- <a href="#v3-3-0">v3\.3\.0</a>
+ - <a href="#release-summary-19">Release Summary</a>
+ - <a href="#minor-changes-6">Minor Changes</a>
+ - <a href="#bugfixes-16">Bugfixes</a>
+- <a href="#v3-2-2">v3\.2\.2</a>
+ - <a href="#release-summary-20">Release Summary</a>
+ - <a href="#bugfixes-17">Bugfixes</a>
+- <a href="#v3-2-1">v3\.2\.1</a>
+ - <a href="#release-summary-21">Release Summary</a>
+- <a href="#v3-2-0">v3\.2\.0</a>
+ - <a href="#release-summary-22">Release Summary</a>
+ - <a href="#minor-changes-7">Minor Changes</a>
+ - <a href="#deprecated-features-1">Deprecated Features</a>
+- <a href="#v3-1-0">v3\.1\.0</a>
+ - <a href="#release-summary-23">Release Summary</a>
+ - <a href="#minor-changes-8">Minor Changes</a>
+- <a href="#v3-0-2">v3\.0\.2</a>
+ - <a href="#release-summary-24">Release Summary</a>
+ - <a href="#bugfixes-18">Bugfixes</a>
+- <a href="#v3-0-1">v3\.0\.1</a>
+ - <a href="#release-summary-25">Release Summary</a>
+ - <a href="#bugfixes-19">Bugfixes</a>
+- <a href="#v3-0-0">v3\.0\.0</a>
+ - <a href="#release-summary-26">Release Summary</a>
+ - <a href="#major-changes-1">Major Changes</a>
+ - <a href="#minor-changes-9">Minor Changes</a>
+ - <a href="#breaking-changes--porting-guide">Breaking Changes / Porting Guide</a>
+ - <a href="#removed-features-previously-deprecated">Removed Features \(previously deprecated\)</a>
+ - <a href="#security-fixes-1">Security Fixes</a>
+ - <a href="#bugfixes-20">Bugfixes</a>
+- <a href="#v2-7-0">v2\.7\.0</a>
+ - <a href="#release-summary-27">Release Summary</a>
+ - <a href="#minor-changes-10">Minor Changes</a>
+ - <a href="#deprecated-features-2">Deprecated Features</a>
+ - <a href="#bugfixes-21">Bugfixes</a>
+- <a href="#v2-6-0">v2\.6\.0</a>
+ - <a href="#release-summary-28">Release Summary</a>
+ - <a href="#minor-changes-11">Minor Changes</a>
+ - <a href="#deprecated-features-3">Deprecated Features</a>
+ - <a href="#bugfixes-22">Bugfixes</a>
+- <a href="#v2-5-1">v2\.5\.1</a>
+ - <a href="#release-summary-29">Release Summary</a>
+ - <a href="#bugfixes-23">Bugfixes</a>
+- <a href="#v2-5-0">v2\.5\.0</a>
+ - <a href="#release-summary-30">Release Summary</a>
+ - <a href="#minor-changes-12">Minor Changes</a>
+- <a href="#v2-4-0">v2\.4\.0</a>
+ - <a href="#release-summary-31">Release Summary</a>
+ - <a href="#minor-changes-13">Minor Changes</a>
+ - <a href="#bugfixes-24">Bugfixes</a>
+- <a href="#v2-3-0">v2\.3\.0</a>
+ - <a href="#release-summary-32">Release Summary</a>
+ - <a href="#minor-changes-14">Minor Changes</a>
+ - <a href="#bugfixes-25">Bugfixes</a>
+- <a href="#v2-2-1">v2\.2\.1</a>
+ - <a href="#release-summary-33">Release Summary</a>
+ - <a href="#bugfixes-26">Bugfixes</a>
+- <a href="#v2-2-0">v2\.2\.0</a>
+ - <a href="#release-summary-34">Release Summary</a>
+ - <a href="#minor-changes-15">Minor Changes</a>
+ - <a href="#bugfixes-27">Bugfixes</a>
+- <a href="#v2-1-1">v2\.1\.1</a>
+ - <a href="#release-summary-35">Release Summary</a>
+ - <a href="#bugfixes-28">Bugfixes</a>
+- <a href="#v2-1-0">v2\.1\.0</a>
+ - <a href="#release-summary-36">Release Summary</a>
+ - <a href="#minor-changes-16">Minor Changes</a>
+ - <a href="#bugfixes-29">Bugfixes</a>
+- <a href="#v2-0-2">v2\.0\.2</a>
+ - <a href="#release-summary-37">Release Summary</a>
+ - <a href="#bugfixes-30">Bugfixes</a>
+- <a href="#v2-0-1">v2\.0\.1</a>
+ - <a href="#release-summary-38">Release Summary</a>
+- <a href="#v2-0-0">v2\.0\.0</a>
+ - <a href="#release-summary-39">Release Summary</a>
+ - <a href="#breaking-changes--porting-guide-1">Breaking Changes / Porting Guide</a>
+ - <a href="#deprecated-features-4">Deprecated Features</a>
+ - <a href="#removed-features-previously-deprecated-1">Removed Features \(previously deprecated\)</a>
+- <a href="#v1-10-0">v1\.10\.0</a>
+ - <a href="#release-summary-40">Release Summary</a>
+ - <a href="#minor-changes-17">Minor Changes</a>
+- <a href="#v1-9-1">v1\.9\.1</a>
+ - <a href="#release-summary-41">Release Summary</a>
+ - <a href="#bugfixes-31">Bugfixes</a>
+- <a href="#v1-9-0">v1\.9\.0</a>
+ - <a href="#release-summary-42">Release Summary</a>
+ - <a href="#minor-changes-18">Minor Changes</a>
+ - <a href="#deprecated-features-5">Deprecated Features</a>
+ - <a href="#bugfixes-32">Bugfixes</a>
+ - <a href="#new-plugins">New Plugins</a>
+ - <a href="#connection">Connection</a>
+- <a href="#v1-8-0">v1\.8\.0</a>
+ - <a href="#release-summary-43">Release Summary</a>
+ - <a href="#minor-changes-19">Minor Changes</a>
+ - <a href="#bugfixes-33">Bugfixes</a>
+- <a href="#v1-7-0">v1\.7\.0</a>
+ - <a href="#release-summary-44">Release Summary</a>
+ - <a href="#minor-changes-20">Minor Changes</a>
+- <a href="#v1-6-1">v1\.6\.1</a>
+ - <a href="#release-summary-45">Release Summary</a>
+ - <a href="#bugfixes-34">Bugfixes</a>
+- <a href="#v1-6-0">v1\.6\.0</a>
+ - <a href="#release-summary-46">Release Summary</a>
+ - <a href="#minor-changes-21">Minor Changes</a>
+ - <a href="#deprecated-features-6">Deprecated Features</a>
+ - <a href="#bugfixes-35">Bugfixes</a>
+- <a href="#v1-5-0">v1\.5\.0</a>
+ - <a href="#release-summary-47">Release Summary</a>
+ - <a href="#minor-changes-22">Minor Changes</a>
+ - <a href="#bugfixes-36">Bugfixes</a>
+ - <a href="#new-modules-3">New Modules</a>
+- <a href="#v1-4-0">v1\.4\.0</a>
+ - <a href="#release-summary-48">Release Summary</a>
+ - <a href="#minor-changes-23">Minor Changes</a>
+ - <a href="#breaking-changes--porting-guide-2">Breaking Changes / Porting Guide</a>
+ - <a href="#security-fixes-2">Security Fixes</a>
+ - <a href="#bugfixes-37">Bugfixes</a>
+- <a href="#v1-3-0">v1\.3\.0</a>
+ - <a href="#release-summary-49">Release Summary</a>
+ - <a href="#minor-changes-24">Minor Changes</a>
+ - <a href="#bugfixes-38">Bugfixes</a>
+ - <a href="#new-modules-4">New Modules</a>
+- <a href="#v1-2-2">v1\.2\.2</a>
+ - <a href="#release-summary-50">Release Summary</a>
+ - <a href="#security-fixes-3">Security Fixes</a>
+- <a href="#v1-2-1">v1\.2\.1</a>
+ - <a href="#release-summary-51">Release Summary</a>
+ - <a href="#bugfixes-39">Bugfixes</a>
+- <a href="#v1-2-0">v1\.2\.0</a>
+ - <a href="#release-summary-52">Release Summary</a>
+ - <a href="#minor-changes-25">Minor Changes</a>
+ - <a href="#bugfixes-40">Bugfixes</a>
+- <a href="#v1-1-0">v1\.1\.0</a>
+ - <a href="#release-summary-53">Release Summary</a>
+ - <a href="#minor-changes-26">Minor Changes</a>
+ - <a href="#deprecated-features-7">Deprecated Features</a>
+ - <a href="#bugfixes-41">Bugfixes</a>
+ - <a href="#new-plugins-1">New Plugins</a>
+ - <a href="#connection-1">Connection</a>
+ - <a href="#inventory">Inventory</a>
+ - <a href="#new-modules-5">New Modules</a>
+- <a href="#v1-0-1">v1\.0\.1</a>
+ - <a href="#release-summary-54">Release Summary</a>
+ - <a href="#bugfixes-42">Bugfixes</a>
+- <a href="#v1-0-0">v1\.0\.0</a>
+ - <a href="#release-summary-55">Release Summary</a>
+ - <a href="#minor-changes-27">Minor Changes</a>
+- <a href="#v0-1-0">v0\.1\.0</a>
+ - <a href="#release-summary-56">Release Summary</a>
+ - <a href="#minor-changes-28">Minor Changes</a>
+ - <a href="#removed-features-previously-deprecated-2">Removed Features \(previously deprecated\)</a>
+ - <a href="#bugfixes-43">Bugfixes</a>
+
+<a id="v3-8-1"></a>
+## v3\.8\.1
+
+<a id="release-summary"></a>
+### Release Summary
+
+Bugfix release
+
+<a id="security-fixes"></a>
+### Security Fixes
+
+* docker\_containers\, docker\_machine\, and docker\_swarm inventory plugins \- make sure all data received from the Docker daemon / Docker machine is marked as unsafe\, so remote code execution by obtaining texts that can be evaluated as templates is not possible \([https\://www\.die\-welt\.net/2024/03/remote\-code\-execution\-in\-ansible\-dynamic\-inventory\-plugins/](https\://www\.die\-welt\.net/2024/03/remote\-code\-execution\-in\-ansible\-dynamic\-inventory\-plugins/)\, [https\://github\.com/ansible\-collections/community\.docker/pull/815](https\://github\.com/ansible\-collections/community\.docker/pull/815)\)\.
+
+<a id="bugfixes"></a>
+### Bugfixes
+
+* docker\_compose\_v2 \- do not fail when non\-fatal errors occur\. This can happen when pulling an image fails\, but then the image can be built for another service\. Docker Compose emits an error in that case\, but <code>docker compose up</code> still completes successfully \([https\://github\.com/ansible\-collections/community\.docker/issues/807](https\://github\.com/ansible\-collections/community\.docker/issues/807)\, [https\://github\.com/ansible\-collections/community\.docker/pull/810](https\://github\.com/ansible\-collections/community\.docker/pull/810)\, [https\://github\.com/ansible\-collections/community\.docker/pull/811](https\://github\.com/ansible\-collections/community\.docker/pull/811)\)\.
+* docker\_compose\_v2\* modules \- correctly parse <code>Warning</code> events emitted by Docker Compose \([https\://github\.com/ansible\-collections/community\.docker/issues/807](https\://github\.com/ansible\-collections/community\.docker/issues/807)\, [https\://github\.com/ansible\-collections/community\.docker/pull/811](https\://github\.com/ansible\-collections/community\.docker/pull/811)\)\.
+* docker\_compose\_v2\* modules \- parse <code>logfmt</code> warnings emitted by Docker Compose \([https\://github\.com/ansible\-collections/community\.docker/issues/787](https\://github\.com/ansible\-collections/community\.docker/issues/787)\, [https\://github\.com/ansible\-collections/community\.docker/pull/811](https\://github\.com/ansible\-collections/community\.docker/pull/811)\)\.
+* docker\_compose\_v2\_pull \- fixing idempotence by checking actual pull progress events instead of service\-level pull request when <code>policy\=always</code>\. This stops the module from reporting <code>changed\=true</code> if no actual change happened when pulling\. In check mode\, it has to assume that a change happens though \([https\://github\.com/ansible\-collections/community\.docker/issues/813](https\://github\.com/ansible\-collections/community\.docker/issues/813)\, [https\://github\.com/ansible\-collections/community\.docker/pull/814](https\://github\.com/ansible\-collections/community\.docker/pull/814)\)\.
+
+<a id="v3-8-0"></a>
+## v3\.8\.0
+
+<a id="release-summary-1"></a>
+### Release Summary
+
+Bugfix and feature release\.
+
+<a id="minor-changes"></a>
+### Minor Changes
+
+* docker\_compose\_v2 \- allow to wait until containers are running/health when running <code>docker compose up</code> with the new <code>wait</code> option \([https\://github\.com/ansible\-collections/community\.docker/issues/794](https\://github\.com/ansible\-collections/community\.docker/issues/794)\, [https\://github\.com/ansible\-collections/community\.docker/pull/796](https\://github\.com/ansible\-collections/community\.docker/pull/796)\)\.
+* docker\_container \- the <code>pull\_check\_mode\_behavior</code> option now allows to control the module\'s behavior in check mode when <code>pull\=always</code> \([https\://github\.com/ansible\-collections/community\.docker/issues/792](https\://github\.com/ansible\-collections/community\.docker/issues/792)\, [https\://github\.com/ansible\-collections/community\.docker/pull/797](https\://github\.com/ansible\-collections/community\.docker/pull/797)\)\.
+* docker\_container \- the <code>pull</code> option now accepts the three values <code>never</code>\, <code>missing\_image</code> \(default\)\, and <code>never</code>\, next to the previously valid values <code>true</code> \(equivalent to <code>always</code>\) and <code>false</code> \(equivalent to <code>missing\_image</code>\)\. This allows the equivalent to <code>\-\-pull\=never</code> from the Docker command line \([https\://github\.com/ansible\-collections/community\.docker/issues/783](https\://github\.com/ansible\-collections/community\.docker/issues/783)\, [https\://github\.com/ansible\-collections/community\.docker/pull/797](https\://github\.com/ansible\-collections/community\.docker/pull/797)\)\.
+
+<a id="bugfixes-1"></a>
+### Bugfixes
+
+* docker\_compose\_v2 \- do not consider a <code>Waiting</code> event as an action/change \([https\://github\.com/ansible\-collections/community\.docker/pull/804](https\://github\.com/ansible\-collections/community\.docker/pull/804)\)\.
+* docker\_compose\_v2 \- do not treat service\-level pull events as changes to avoid incorrect <code>changed\=true</code> return value of <code>pull\=always</code> \([https\://github\.com/ansible\-collections/community\.docker/issues/802](https\://github\.com/ansible\-collections/community\.docker/issues/802)\, [https\://github\.com/ansible\-collections/community\.docker/pull/803](https\://github\.com/ansible\-collections/community\.docker/pull/803)\)\.
+* docker\_compose\_v2\, docker\_compose\_v2\_pull \- fix parsing of pull messages for Docker Compose 2\.20\.0 \([https\://github\.com/ansible\-collections/community\.docker/issues/785](https\://github\.com/ansible\-collections/community\.docker/issues/785)\, [https\://github\.com/ansible\-collections/community\.docker/pull/786](https\://github\.com/ansible\-collections/community\.docker/pull/786)\)\.
+
+<a id="v3-7-0"></a>
+## v3\.7\.0
+
+<a id="release-summary-2"></a>
+### Release Summary
+
+Bugfix and feature release\.
+
+<a id="minor-changes-1"></a>
+### Minor Changes
+
+* docker\_compose\_v2 \- add <code>scale</code> option to allow to explicitly scale services \([https\://github\.com/ansible\-collections/community\.docker/pull/776](https\://github\.com/ansible\-collections/community\.docker/pull/776)\)\.
+* docker\_compose\_v2\, docker\_compose\_v2\_pull \- support <code>files</code> parameter to specify multiple Compose files \([https\://github\.com/ansible\-collections/community\.docker/issues/772](https\://github\.com/ansible\-collections/community\.docker/issues/772)\, [https\://github\.com/ansible\-collections/community\.docker/pull/775](https\://github\.com/ansible\-collections/community\.docker/pull/775)\)\.
+
+<a id="bugfixes-2"></a>
+### Bugfixes
+
+* docker\_compose\_v2 \- properly parse dry\-run build events from <code>stderr</code> \([https\://github\.com/ansible\-collections/community\.docker/issues/778](https\://github\.com/ansible\-collections/community\.docker/issues/778)\, [https\://github\.com/ansible\-collections/community\.docker/pull/779](https\://github\.com/ansible\-collections/community\.docker/pull/779)\)\.
+* docker\_compose\_v2\_pull \- the module was documented as part of the <code>community\.docker\.docker</code> action group\, but was not actually part of it\. That has now been fixed \([https\://github\.com/ansible\-collections/community\.docker/pull/773](https\://github\.com/ansible\-collections/community\.docker/pull/773)\)\.
+
+<a id="new-modules"></a>
+### New Modules
+
+* docker\_image\_export \- Export \(archive\) Docker images
+
+<a id="v3-6-0"></a>
+## v3\.6\.0
+
+<a id="release-summary-3"></a>
+### Release Summary
+
+Bugfix and feature release\.
+
+The collection now includes a bunch of new <code>docker\_image\_\*</code> modules that move features out of the
+rather complex <code>docker\_image</code> module\. These new modules are easier to use and can better declare whether
+they support check mode\, diff mode\, or none of them\.
+
+This version also features modules that support the Docker CLI plugins <code>buildx</code> and <code>compose</code>\.
+The <code>docker\_image\_build</code> module uses the <code>docker buildx</code> command under the hood\, and the <code>docker\_compose\_v2</code>
+and <code>docker\_compose\_v2\_pull</code> modules uses the <code>docker compose</code> command\. All these modules use the Docker CLI
+instead of directly talking to the API\. The modules support mostly the same interface as the API based modules\,
+so the main difference is that instead of some Python requirements\, they depend on the Docker CLI tool <code>docker</code>\.
+
+<a id="major-changes"></a>
+### Major Changes
+
+* The <code>community\.docker</code> collection now depends on the <code>community\.library\_inventory\_filtering\_v1</code> collection\. This utility collection provides host filtering functionality for inventory plugins\. If you use the Ansible community package\, both collections are included and you do not have to do anything special\. If you install the collection with <code>ansible\-galaxy collection install</code>\, it will be installed automatically\. If you install the collection by copying the files of the collection to a place where ansible\-core can find it\, for example by cloning the git repository\, you need to make sure that you also have to install the dependency if you are using the inventory plugins \([https\://github\.com/ansible\-collections/community\.docker/pull/698](https\://github\.com/ansible\-collections/community\.docker/pull/698)\)\.
+
+<a id="minor-changes-2"></a>
+### Minor Changes
+
+* The <code>ca\_cert</code> option available to almost all modules and plugins has been renamed to <code>ca\_path</code>\. The name <code>ca\_path</code> is also used for similar options in ansible\-core and other collections\. The old name has been added as an alias and can still be used \([https\://github\.com/ansible\-collections/community\.docker/pull/744](https\://github\.com/ansible\-collections/community\.docker/pull/744)\)\.
+* The <code>docker\_stack\*</code> modules now use the common CLI\-based module code added for the <code>docker\_image\_build</code> and <code>docker\_compose\_v2</code> modules\. This means that the modules now have various more configuration options with respect to talking to the Docker Daemon\, and now also are part of the <code>community\.docker\.docker</code> and <code>docker</code> module default groups \([https\://github\.com/ansible\-collections/community\.docker/pull/745](https\://github\.com/ansible\-collections/community\.docker/pull/745)\)\.
+* docker\_container \- add <code>networks\[\]\.mac\_address</code> option for Docker API 1\.44\+\. Note that Docker API 1\.44 no longer uses the global <code>mac\_address</code> option\, this new option is the only way to set the MAC address for a container \([https\://github\.com/ansible\-collections/community\.docker/pull/763](https\://github\.com/ansible\-collections/community\.docker/pull/763)\)\.
+* docker\_image \- allow to specify labels and <code>/dev/shm</code> size when building images \([https\://github\.com/ansible\-collections/community\.docker/issues/726](https\://github\.com/ansible\-collections/community\.docker/issues/726)\, [https\://github\.com/ansible\-collections/community\.docker/pull/727](https\://github\.com/ansible\-collections/community\.docker/pull/727)\)\.
+* docker\_image \- allow to specify memory size and swap memory size in other units than bytes \([https\://github\.com/ansible\-collections/community\.docker/pull/727](https\://github\.com/ansible\-collections/community\.docker/pull/727)\)\.
+* inventory plugins \- add <code>filter</code> option which allows to include and exclude hosts based on Jinja2 conditions \([https\://github\.com/ansible\-collections/community\.docker/pull/698](https\://github\.com/ansible\-collections/community\.docker/pull/698)\, [https\://github\.com/ansible\-collections/community\.docker/issues/610](https\://github\.com/ansible\-collections/community\.docker/issues/610)\)\.
+
+<a id="bugfixes-3"></a>
+### Bugfixes
+
+* Use <code>unix\:///var/run/docker\.sock</code> instead of the legacy <code>unix\://var/run/docker\.sock</code> as default for <code>docker\_host</code> \([https\://github\.com/ansible\-collections/community\.docker/pull/736](https\://github\.com/ansible\-collections/community\.docker/pull/736)\)\.
+* docker\_image \- fix archiving idempotency with Docker API 1\.44 or later \([https\://github\.com/ansible\-collections/community\.docker/pull/765](https\://github\.com/ansible\-collections/community\.docker/pull/765)\)\.
+
+<a id="new-modules-1"></a>
+### New Modules
+
+* docker\_compose\_v2 \- Manage multi\-container Docker applications with Docker Compose CLI plugin
+* docker\_compose\_v2\_pull \- Pull a Docker compose project
+* docker\_image\_build \- Build Docker images using Docker buildx
+* docker\_image\_pull \- Pull Docker images from registries
+* docker\_image\_push \- Push Docker images to registries
+* docker\_image\_remove \- Remove Docker images
+* docker\_image\_tag \- Tag Docker images with new names and/or tags
+
+<a id="v3-5-0"></a>
+## v3\.5\.0
+
+<a id="release-summary-4"></a>
+### Release Summary
+
+Bugfix and feature release\.
+
+<a id="minor-changes-3"></a>
+### Minor Changes
+
+* docker\_container \- implement better <code>platform</code> string comparisons to improve idempotency \([https\://github\.com/ansible\-collections/community\.docker/issues/654](https\://github\.com/ansible\-collections/community\.docker/issues/654)\, [https\://github\.com/ansible\-collections/community\.docker/pull/705](https\://github\.com/ansible\-collections/community\.docker/pull/705)\)\.
+* docker\_container \- internal refactorings which allow comparisons to use more information like details of the current image or the Docker host config \([https\://github\.com/ansible\-collections/community\.docker/pull/713](https\://github\.com/ansible\-collections/community\.docker/pull/713)\)\.
+
+<a id="deprecated-features"></a>
+### Deprecated Features
+
+* docker\_container \- the default <code>ignore</code> for the <code>image\_name\_mismatch</code> parameter has been deprecated and will switch to <code>recreate</code> in community\.docker 4\.0\.0\. A deprecation warning will be printed in situations where the default value is used and where a behavior would change once the default changes \([https\://github\.com/ansible\-collections/community\.docker/pull/703](https\://github\.com/ansible\-collections/community\.docker/pull/703)\)\.
+
+<a id="bugfixes-4"></a>
+### Bugfixes
+
+* modules and plugins using the Docker SDK for Python \- remove <code>ssl\_version</code> from the parameters passed to Docker SDK for Python 7\.0\.0\+\. Explicitly fail with a nicer error message if it was explicitly set in this case \([https\://github\.com/ansible\-collections/community\.docker/pull/715](https\://github\.com/ansible\-collections/community\.docker/pull/715)\)\.
+* modules and plugins using the Docker SDK for Python \- remove <code>tls\_hostname</code> from the parameters passed to Docker SDK for Python 7\.0\.0\+\. Explicitly fail with a nicer error message if it was explicitly set in this case \([https\://github\.com/ansible\-collections/community\.docker/pull/721](https\://github\.com/ansible\-collections/community\.docker/pull/721)\)\.
+* vendored Docker SDK for Python \- avoid passing on <code>ssl\_version</code> and <code>tls\_hostname</code> if they were not provided by the user\. Remove dead code\. \([https\://github\.com/ansible\-collections/community\.docker/pull/722](https\://github\.com/ansible\-collections/community\.docker/pull/722)\)\.
+
+<a id="v3-4-11"></a>
+## v3\.4\.11
+
+<a id="release-summary-5"></a>
+### Release Summary
+
+Bugfix release\.
+
+<a id="bugfixes-5"></a>
+### Bugfixes
+
+* docker\_volume \- fix crash caused by accessing an empty dictionary\. The <code>has\_different\_config\(\)</code> was raising an <code>AttributeError</code> because the <code>self\.existing\_volume\[\"Labels\"\]</code> dictionary was <code>None</code> \([https\://github\.com/ansible\-collections/community\.docker/pull/702](https\://github\.com/ansible\-collections/community\.docker/pull/702)\)\.
+
+<a id="v3-4-10"></a>
+## v3\.4\.10
+
+<a id="release-summary-6"></a>
+### Release Summary
+
+Bugfix release\.
+
+<a id="bugfixes-6"></a>
+### Bugfixes
+
+* docker\_swarm \- make init and join operations work again with Docker SDK for Python before 4\.0\.0 \([https\://github\.com/ansible\-collections/community\.docker/issues/695](https\://github\.com/ansible\-collections/community\.docker/issues/695)\, [https\://github\.com/ansible\-collections/community\.docker/pull/696](https\://github\.com/ansible\-collections/community\.docker/pull/696)\)\.
+
+<a id="v3-4-9"></a>
+## v3\.4\.9
+
+<a id="release-summary-7"></a>
+### Release Summary
+
+Maintenance release with updated documentation and vendored Docker SDK for Python code\.
+
+<a id="bugfixes-7"></a>
+### Bugfixes
+
+* vendored Docker SDK for Python code \- cherry\-pick changes from the Docker SDK for Python code to align code\. These changes should not affect the parts used by the collection\'s code \([https\://github\.com/ansible\-collections/community\.docker/pull/694](https\://github\.com/ansible\-collections/community\.docker/pull/694)\)\.
+
+<a id="v3-4-8"></a>
+## v3\.4\.8
+
+<a id="release-summary-8"></a>
+### Release Summary
+
+Maintenance release with updated documentation\.
+
+From this version on\, community\.docker is using the new [Ansible semantic markup](https\://docs\.ansible\.com/ansible/devel/dev\_guide/developing\_modules\_documenting\.html\#semantic\-markup\-within\-module\-documentation)
+in its documentation\. If you look at documentation with the ansible\-doc CLI tool
+from ansible\-core before 2\.15\, please note that it does not render the markup
+correctly\. You should be still able to read it in most cases\, but you need
+ansible\-core 2\.15 or later to see it as it is intended\. Alternatively you can
+look at [the devel docsite](https\://docs\.ansible\.com/ansible/devel/collections/community/docker/)
+for the rendered HTML version of the documentation of the latest release\.
+
+<a id="known-issues"></a>
+### Known Issues
+
+* Ansible markup will show up in raw form on ansible\-doc text output for ansible\-core before 2\.15\. If you have trouble deciphering the documentation markup\, please upgrade to ansible\-core 2\.15 \(or newer\)\, or read the HTML documentation on [https\://docs\.ansible\.com/ansible/devel/collections/community/docker/](https\://docs\.ansible\.com/ansible/devel/collections/community/docker/)\.
+
+<a id="v3-4-7"></a>
+## v3\.4\.7
+
+<a id="release-summary-9"></a>
+### Release Summary
+
+Bugfix release\.
+
+<a id="bugfixes-8"></a>
+### Bugfixes
+
+* docker\_swarm\_info \- if <code>service\=true</code> is used\, do not crash when a service without an endpoint spec is encountered \([https\://github\.com/ansible\-collections/community\.docker/issues/636](https\://github\.com/ansible\-collections/community\.docker/issues/636)\, [https\://github\.com/ansible\-collections/community\.docker/pull/637](https\://github\.com/ansible\-collections/community\.docker/pull/637)\)\.
+
+<a id="v3-4-6"></a>
+## v3\.4\.6
+
+<a id="release-summary-10"></a>
+### Release Summary
+
+Bugfix release with documentation warnings about using certain functionality when connecting to the Docker daemon with TCP TLS\.
+
+<a id="bugfixes-9"></a>
+### Bugfixes
+
+* socket\_handler module utils \- make sure this fully works when Docker SDK for Python is not available \([https\://github\.com/ansible\-collections/community\.docker/pull/620](https\://github\.com/ansible\-collections/community\.docker/pull/620)\)\.
+* vendored Docker SDK for Python code \- fix for errors on pipe close in Windows \([https\://github\.com/ansible\-collections/community\.docker/pull/619](https\://github\.com/ansible\-collections/community\.docker/pull/619)\)\.
+* vendored Docker SDK for Python code \- respect timeouts on Windows named pipes \([https\://github\.com/ansible\-collections/community\.docker/pull/619](https\://github\.com/ansible\-collections/community\.docker/pull/619)\)\.
+* vendored Docker SDK for Python code \- use <code>poll\(\)</code> instead of <code>select\(\)</code> except on Windows \([https\://github\.com/ansible\-collections/community\.docker/pull/619](https\://github\.com/ansible\-collections/community\.docker/pull/619)\)\.
+
+<a id="known-issues-1"></a>
+### Known Issues
+
+* docker\_api connection plugin \- does <strong>not work with TCP TLS sockets</strong>\! This is caused by the inability to send an <code>close\_notify</code> TLS alert without closing the connection with Python\'s <code>SSLSocket</code> \([https\://github\.com/ansible\-collections/community\.docker/issues/605](https\://github\.com/ansible\-collections/community\.docker/issues/605)\, [https\://github\.com/ansible\-collections/community\.docker/pull/621](https\://github\.com/ansible\-collections/community\.docker/pull/621)\)\.
+* docker\_container\_exec \- does <strong>not work with TCP TLS sockets</strong> when the <code>stdin</code> option is used\! This is caused by the inability to send an <code>close\_notify</code> TLS alert without closing the connection with Python\'s <code>SSLSocket</code> \([https\://github\.com/ansible\-collections/community\.docker/issues/605](https\://github\.com/ansible\-collections/community\.docker/issues/605)\, [https\://github\.com/ansible\-collections/community\.docker/pull/621](https\://github\.com/ansible\-collections/community\.docker/pull/621)\)\.
+
+<a id="v3-4-5"></a>
+## v3\.4\.5
+
+<a id="release-summary-11"></a>
+### Release Summary
+
+Maintenance release which adds compatibility with requests 2\.29\.0 and 2\.30\.0 and urllib3 2\.0\.
+
+<a id="bugfixes-10"></a>
+### Bugfixes
+
+* Make vendored Docker SDK for Python code compatible with requests 2\.29\.0 and urllib3 2\.0 \([https\://github\.com/ansible\-collections/community\.docker/pull/613](https\://github\.com/ansible\-collections/community\.docker/pull/613)\)\.
+
+<a id="v3-4-4"></a>
+## v3\.4\.4
+
+<a id="release-summary-12"></a>
+### Release Summary
+
+Maintenance release with updated EE requirements and updated documentation\.
+
+<a id="minor-changes-4"></a>
+### Minor Changes
+
+* Restrict requests to versions before 2\.29\.0\, and urllib3 to versions before 2\.0\.0\. This is necessary until the vendored code from Docker SDK for Python has been fully adjusted to work with a feature of urllib3 that is used since requests 2\.29\.0 \([https\://github\.com/ansible\-collections/community\.docker/issues/611](https\://github\.com/ansible\-collections/community\.docker/issues/611)\, [https\://github\.com/ansible\-collections/community\.docker/pull/612](https\://github\.com/ansible\-collections/community\.docker/pull/612)\)\.
+
+<a id="known-issues-2"></a>
+### Known Issues
+
+* The modules and plugins using the vendored code from Docker SDK for Python currently do not work with requests 2\.29\.0 and/or urllib3 2\.0\.0\. The same is currently true for the latest version of Docker SDK for Python itself \([https\://github\.com/ansible\-collections/community\.docker/issues/611](https\://github\.com/ansible\-collections/community\.docker/issues/611)\, [https\://github\.com/ansible\-collections/community\.docker/pull/612](https\://github\.com/ansible\-collections/community\.docker/pull/612)\)\.
+
+<a id="v3-4-3"></a>
+## v3\.4\.3
+
+<a id="release-summary-13"></a>
+### Release Summary
+
+Maintenance release with improved documentation\.
+
+<a id="v3-4-2"></a>
+## v3\.4\.2
+
+<a id="release-summary-14"></a>
+### Release Summary
+
+Bugfix release\.
+
+<a id="bugfixes-11"></a>
+### Bugfixes
+
+* docker\_prune \- return correct value for <code>changed</code>\. So far the module always claimed that nothing changed \([https\://github\.com/ansible\-collections/community\.docker/pull/593](https\://github\.com/ansible\-collections/community\.docker/pull/593)\)\.
+
+<a id="v3-4-1"></a>
+## v3\.4\.1
+
+<a id="release-summary-15"></a>
+### Release Summary
+
+Regular bugfix release\.
+
+<a id="bugfixes-12"></a>
+### Bugfixes
+
+* docker\_api connection plugin\, docker\_container\_exec\, docker\_container\_copy\_into \- properly close socket to Daemon after executing commands in containers \([https\://github\.com/ansible\-collections/community\.docker/pull/582](https\://github\.com/ansible\-collections/community\.docker/pull/582)\)\.
+* docker\_container \- fix <code>tmfs\_size</code> and <code>tmpfs\_mode</code> not being set \([https\://github\.com/ansible\-collections/community\.docker/pull/580](https\://github\.com/ansible\-collections/community\.docker/pull/580)\)\.
+* various plugins and modules \- remove unnecessary imports \([https\://github\.com/ansible\-collections/community\.docker/pull/574](https\://github\.com/ansible\-collections/community\.docker/pull/574)\)\.
+
+<a id="v3-4-0"></a>
+## v3\.4\.0
+
+<a id="release-summary-16"></a>
+### Release Summary
+
+Regular bugfix and feature release\.
+
+<a id="minor-changes-5"></a>
+### Minor Changes
+
+* docker\_api connection plugin \- when copying files to/from a container\, stream the file contents instead of first reading them to memory \([https\://github\.com/ansible\-collections/community\.docker/pull/545](https\://github\.com/ansible\-collections/community\.docker/pull/545)\)\.
+* docker\_host\_info \- allow to list all containers with new option <code>containers\_all</code> \([https\://github\.com/ansible\-collections/community\.docker/issues/535](https\://github\.com/ansible\-collections/community\.docker/issues/535)\, [https\://github\.com/ansible\-collections/community\.docker/pull/538](https\://github\.com/ansible\-collections/community\.docker/pull/538)\)\.
+
+<a id="bugfixes-13"></a>
+### Bugfixes
+
+* docker\_api connection plugin \- fix error handling when 409 Conflict is returned by the Docker daemon in case of a stopped container \([https\://github\.com/ansible\-collections/community\.docker/pull/546](https\://github\.com/ansible\-collections/community\.docker/pull/546)\)\.
+* docker\_container\_exec \- fix error handling when 409 Conflict is returned by the Docker daemon in case of a stopped container \([https\://github\.com/ansible\-collections/community\.docker/pull/546](https\://github\.com/ansible\-collections/community\.docker/pull/546)\)\.
+* docker\_plugin \- do not crash if plugin is installed in check mode \([https\://github\.com/ansible\-collections/community\.docker/issues/552](https\://github\.com/ansible\-collections/community\.docker/issues/552)\, [https\://github\.com/ansible\-collections/community\.docker/pull/553](https\://github\.com/ansible\-collections/community\.docker/pull/553)\)\.
+* most modules \- fix handling of <code>DOCKER\_TIMEOUT</code> environment variable\, and improve handling of other fallback environment variables \([https\://github\.com/ansible\-collections/community\.docker/issues/551](https\://github\.com/ansible\-collections/community\.docker/issues/551)\, [https\://github\.com/ansible\-collections/community\.docker/pull/554](https\://github\.com/ansible\-collections/community\.docker/pull/554)\)\.
+
+<a id="new-modules-2"></a>
+### New Modules
+
+* docker\_container\_copy\_into \- Copy a file into a Docker container
+
+<a id="v3-3-2"></a>
+## v3\.3\.2
+
+<a id="release-summary-17"></a>
+### Release Summary
+
+Bugfix release\.
+
+<a id="bugfixes-14"></a>
+### Bugfixes
+
+* docker\_container \- when <code>detach\=false</code>\, wait indefinitely and not at most one minute\. This was the behavior with Docker SDK for Python\, and was accidentally changed in 3\.0\.0 \([https\://github\.com/ansible\-collections/community\.docker/issues/526](https\://github\.com/ansible\-collections/community\.docker/issues/526)\, [https\://github\.com/ansible\-collections/community\.docker/pull/527](https\://github\.com/ansible\-collections/community\.docker/pull/527)\)\.
+
+<a id="v3-3-1"></a>
+## v3\.3\.1
+
+<a id="release-summary-18"></a>
+### Release Summary
+
+Bugfix release\.
+
+<a id="bugfixes-15"></a>
+### Bugfixes
+
+* current\_container\_facts \- make container detection work better in more cases \([https\://github\.com/ansible\-collections/community\.docker/pull/522](https\://github\.com/ansible\-collections/community\.docker/pull/522)\)\.
+
+<a id="v3-3-0"></a>
+## v3\.3\.0
+
+<a id="release-summary-19"></a>
+### Release Summary
+
+Feature and bugfix release\.
+
+<a id="minor-changes-6"></a>
+### Minor Changes
+
+* current\_container\_facts \- make work with current Docker version\, also support Podman \([https\://github\.com/ansible\-collections/community\.docker/pull/510](https\://github\.com/ansible\-collections/community\.docker/pull/510)\)\.
+* docker\_image \- when using <code>archive\_path</code>\, detect whether changes are necessary based on the image ID \(hash\)\. If the existing tar archive matches the source\, do nothing\. Previously\, each task execution re\-created the archive \([https\://github\.com/ansible\-collections/community\.docker/pull/500](https\://github\.com/ansible\-collections/community\.docker/pull/500)\)\.
+
+<a id="bugfixes-16"></a>
+### Bugfixes
+
+* docker\_container\_exec \- fix <code>chdir</code> option which was ignored since community\.docker 3\.0\.0 \([https\://github\.com/ansible\-collections/community\.docker/issues/517](https\://github\.com/ansible\-collections/community\.docker/issues/517)\, [https\://github\.com/ansible\-collections/community\.docker/pull/518](https\://github\.com/ansible\-collections/community\.docker/pull/518)\)\.
+* vendored latest Docker SDK for Python bugfix \([https\://github\.com/ansible\-collections/community\.docker/pull/513](https\://github\.com/ansible\-collections/community\.docker/pull/513)\, [https\://github\.com/docker/docker\-py/issues/3045](https\://github\.com/docker/docker\-py/issues/3045)\)\.
+
+<a id="v3-2-2"></a>
+## v3\.2\.2
+
+<a id="release-summary-20"></a>
+### Release Summary
+
+Bugfix release\.
+
+<a id="bugfixes-17"></a>
+### Bugfixes
+
+* docker\_container \- the <code>kill\_signal</code> option erroneously did not accept strings anymore since 3\.0\.0 \([https\://github\.com/ansible\-collections/community\.docker/issues/505](https\://github\.com/ansible\-collections/community\.docker/issues/505)\, [https\://github\.com/ansible\-collections/community\.docker/pull/506](https\://github\.com/ansible\-collections/community\.docker/pull/506)\)\.
+
+<a id="v3-2-1"></a>
+## v3\.2\.1
+
+<a id="release-summary-21"></a>
+### Release Summary
+
+Maintenance release with improved documentation\.
+
+<a id="v3-2-0"></a>
+## v3\.2\.0
+
+<a id="release-summary-22"></a>
+### Release Summary
+
+Feature and deprecation release\.
+
+<a id="minor-changes-7"></a>
+### Minor Changes
+
+* docker\_container \- added <code>image\_name\_mismatch</code> option which allows to control the behavior if the container uses the image specified\, but the container\'s configuration uses a different name for the image than the one provided to the module \([https\://github\.com/ansible\-collections/community\.docker/issues/485](https\://github\.com/ansible\-collections/community\.docker/issues/485)\, [https\://github\.com/ansible\-collections/community\.docker/pull/488](https\://github\.com/ansible\-collections/community\.docker/pull/488)\)\.
+
+<a id="deprecated-features-1"></a>
+### Deprecated Features
+
+* docker\_container \- the <code>ignore\_image</code> option is deprecated and will be removed in community\.docker 4\.0\.0\. Use <code>image\: ignore</code> in <code>comparisons</code> instead \([https\://github\.com/ansible\-collections/community\.docker/pull/487](https\://github\.com/ansible\-collections/community\.docker/pull/487)\)\.
+* docker\_container \- the <code>purge\_networks</code> option is deprecated and will be removed in community\.docker 4\.0\.0\. Use <code>networks\: strict</code> in <code>comparisons</code> instead\, and make sure to provide <code>networks</code>\, with value <code>\[\]</code> if all networks should be removed \([https\://github\.com/ansible\-collections/community\.docker/pull/487](https\://github\.com/ansible\-collections/community\.docker/pull/487)\)\.
+
+<a id="v3-1-0"></a>
+## v3\.1\.0
+
+<a id="release-summary-23"></a>
+### Release Summary
+
+Feature release\.
+
+<a id="minor-changes-8"></a>
+### Minor Changes
+
+* The collection repository conforms to the [REUSE specification](https\://reuse\.software/spec/) except for the changelog fragments \([https\://github\.com/ansible\-collections/community\.docker/pull/462](https\://github\.com/ansible\-collections/community\.docker/pull/462)\)\.
+* docker\_swarm \- allows usage of the <code>data\_path\_port</code> parameter when initializing a swarm \([https\://github\.com/ansible\-collections/community\.docker/issues/296](https\://github\.com/ansible\-collections/community\.docker/issues/296)\)\.
+
+<a id="v3-0-2"></a>
+## v3\.0\.2
+
+<a id="release-summary-24"></a>
+### Release Summary
+
+Bugfix release\.
+
+<a id="bugfixes-18"></a>
+### Bugfixes
+
+* docker\_image \- fix build argument handling \([https\://github\.com/ansible\-collections/community\.docker/issues/455](https\://github\.com/ansible\-collections/community\.docker/issues/455)\, [https\://github\.com/ansible\-collections/community\.docker/pull/456](https\://github\.com/ansible\-collections/community\.docker/pull/456)\)\.
+
+<a id="v3-0-1"></a>
+## v3\.0\.1
+
+<a id="release-summary-25"></a>
+### Release Summary
+
+Bugfix release\.
+
+<a id="bugfixes-19"></a>
+### Bugfixes
+
+* docker\_container \- fix handling of <code>env\_file</code> \([https\://github\.com/ansible\-collections/community\.docker/issues/451](https\://github\.com/ansible\-collections/community\.docker/issues/451)\, [https\://github\.com/ansible\-collections/community\.docker/pull/452](https\://github\.com/ansible\-collections/community\.docker/pull/452)\)\.
+
+<a id="v3-0-0"></a>
+## v3\.0\.0
+
+<a id="release-summary-26"></a>
+### Release Summary
+
+The 3\.0\.0 release features a rewrite of the <code>docker\_container</code> module\, and many modules and plugins no longer depend on the Docker SDK for Python\.
+
+<a id="major-changes-1"></a>
+### Major Changes
+
+* The collection now contains vendored code from the Docker SDK for Python to talk to the Docker daemon\. Modules and plugins using this code no longer need the Docker SDK for Python installed on the machine the module or plugin is running on \([https\://github\.com/ansible\-collections/community\.docker/pull/398](https\://github\.com/ansible\-collections/community\.docker/pull/398)\)\.
+* docker\_api connection plugin \- no longer uses the Docker SDK for Python\. It requires <code>requests</code> to be installed\, and depending on the features used has some more requirements\. If the Docker SDK for Python is installed\, these requirements are likely met \([https\://github\.com/ansible\-collections/community\.docker/pull/414](https\://github\.com/ansible\-collections/community\.docker/pull/414)\)\.
+* docker\_container \- no longer uses the Docker SDK for Python\. It requires <code>requests</code> to be installed\, and depending on the features used has some more requirements\. If the Docker SDK for Python is installed\, these requirements are likely met \([https\://github\.com/ansible\-collections/community\.docker/pull/422](https\://github\.com/ansible\-collections/community\.docker/pull/422)\)\.
+* docker\_container \- the module was completely rewritten from scratch \([https\://github\.com/ansible\-collections/community\.docker/pull/422](https\://github\.com/ansible\-collections/community\.docker/pull/422)\)\.
+* docker\_container\_exec \- no longer uses the Docker SDK for Python\. It requires <code>requests</code> to be installed\, and depending on the features used has some more requirements\. If the Docker SDK for Python is installed\, these requirements are likely met \([https\://github\.com/ansible\-collections/community\.docker/pull/401](https\://github\.com/ansible\-collections/community\.docker/pull/401)\)\.
+* docker\_container\_info \- no longer uses the Docker SDK for Python\. It requires <code>requests</code> to be installed\, and depending on the features used has some more requirements\. If the Docker SDK for Python is installed\, these requirements are likely met \([https\://github\.com/ansible\-collections/community\.docker/pull/402](https\://github\.com/ansible\-collections/community\.docker/pull/402)\)\.
+* docker\_containers inventory plugin \- no longer uses the Docker SDK for Python\. It requires <code>requests</code> to be installed\, and depending on the features used has some more requirements\. If the Docker SDK for Python is installed\, these requirements are likely met \([https\://github\.com/ansible\-collections/community\.docker/pull/413](https\://github\.com/ansible\-collections/community\.docker/pull/413)\)\.
+* docker\_host\_info \- no longer uses the Docker SDK for Python\. It requires <code>requests</code> to be installed\, and depending on the features used has some more requirements\. If the Docker SDK for Python is installed\, these requirements are likely met \([https\://github\.com/ansible\-collections/community\.docker/pull/403](https\://github\.com/ansible\-collections/community\.docker/pull/403)\)\.
+* docker\_image \- no longer uses the Docker SDK for Python\. It requires <code>requests</code> to be installed\, and depending on the features used has some more requirements\. If the Docker SDK for Python is installed\, these requirements are likely met \([https\://github\.com/ansible\-collections/community\.docker/pull/404](https\://github\.com/ansible\-collections/community\.docker/pull/404)\)\.
+* docker\_image\_info \- no longer uses the Docker SDK for Python\. It requires <code>requests</code> to be installed\, and depending on the features used has some more requirements\. If the Docker SDK for Python is installed\, these requirements are likely met \([https\://github\.com/ansible\-collections/community\.docker/pull/405](https\://github\.com/ansible\-collections/community\.docker/pull/405)\)\.
+* docker\_image\_load \- no longer uses the Docker SDK for Python\. It requires <code>requests</code> to be installed\, and depending on the features used has some more requirements\. If the Docker SDK for Python is installed\, these requirements are likely met \([https\://github\.com/ansible\-collections/community\.docker/pull/406](https\://github\.com/ansible\-collections/community\.docker/pull/406)\)\.
+* docker\_login \- no longer uses the Docker SDK for Python\. It requires <code>requests</code> to be installed\, and depending on the features used has some more requirements\. If the Docker SDK for Python is installed\, these requirements are likely met \([https\://github\.com/ansible\-collections/community\.docker/pull/407](https\://github\.com/ansible\-collections/community\.docker/pull/407)\)\.
+* docker\_network \- no longer uses the Docker SDK for Python\. It requires <code>requests</code> to be installed\, and depending on the features used has some more requirements\. If the Docker SDK for Python is installed\, these requirements are likely met \([https\://github\.com/ansible\-collections/community\.docker/pull/408](https\://github\.com/ansible\-collections/community\.docker/pull/408)\)\.
+* docker\_network\_info \- no longer uses the Docker SDK for Python\. It requires <code>requests</code> to be installed\, and depending on the features used has some more requirements\. If the Docker SDK for Python is installed\, these requirements are likely met \([https\://github\.com/ansible\-collections/community\.docker/pull/409](https\://github\.com/ansible\-collections/community\.docker/pull/409)\)\.
+* docker\_plugin \- no longer uses the Docker SDK for Python\. It requires <code>requests</code> to be installed\, and depending on the features used has some more requirements\. If the Docker SDK for Python is installed\, these requirements are likely met \([https\://github\.com/ansible\-collections/community\.docker/pull/429](https\://github\.com/ansible\-collections/community\.docker/pull/429)\)\.
+* docker\_prune \- no longer uses the Docker SDK for Python\. It requires <code>requests</code> to be installed\, and depending on the features used has some more requirements\. If the Docker SDK for Python is installed\, these requirements are likely met \([https\://github\.com/ansible\-collections/community\.docker/pull/410](https\://github\.com/ansible\-collections/community\.docker/pull/410)\)\.
+* docker\_volume \- no longer uses the Docker SDK for Python\. It requires <code>requests</code> to be installed\, and depending on the features used has some more requirements\. If the Docker SDK for Python is installed\, these requirements are likely met \([https\://github\.com/ansible\-collections/community\.docker/pull/411](https\://github\.com/ansible\-collections/community\.docker/pull/411)\)\.
+* docker\_volume\_info \- no longer uses the Docker SDK for Python\. It requires <code>requests</code> to be installed\, and depending on the features used has some more requirements\. If the Docker SDK for Python is installed\, these requirements are likely met \([https\://github\.com/ansible\-collections/community\.docker/pull/412](https\://github\.com/ansible\-collections/community\.docker/pull/412)\)\.
+
+<a id="minor-changes-9"></a>
+### Minor Changes
+
+* All software licenses are now in the <code>LICENSES/</code> directory of the collection root\. Moreover\, <code>SPDX\-License\-Identifier\:</code> is used to declare the applicable license for every file that is not automatically generated \([https\://github\.com/ansible\-collections/community\.docker/pull/430](https\://github\.com/ansible\-collections/community\.docker/pull/430)\)\.
+* Remove vendored copy of <code>distutils\.version</code> in favor of vendored copy included with ansible\-core 2\.12\+\. For ansible\-core 2\.11\, uses <code>distutils\.version</code> for Python \< 3\.12\. There is no support for ansible\-core 2\.11 with Python 3\.12\+ \([https\://github\.com/ansible\-collections/community\.docker/pull/271](https\://github\.com/ansible\-collections/community\.docker/pull/271)\)\.
+* docker\_container \- add a new parameter <code>image\_comparison</code> to control the behavior for which image will be used for idempotency checks \([https\://github\.com/ansible\-collections/community\.docker/issues/421](https\://github\.com/ansible\-collections/community\.docker/issues/421)\, [https\://github\.com/ansible\-collections/community\.docker/pull/428](https\://github\.com/ansible\-collections/community\.docker/pull/428)\)\.
+* docker\_container \- add support for <code>cgroupns\_mode</code> \([https\://github\.com/ansible\-collections/community\.docker/issues/338](https\://github\.com/ansible\-collections/community\.docker/issues/338)\, [https\://github\.com/ansible\-collections/community\.docker/pull/427](https\://github\.com/ansible\-collections/community\.docker/pull/427)\)\.
+* docker\_container \- allow to specify <code>platform</code> \([https\://github\.com/ansible\-collections/community\.docker/issues/123](https\://github\.com/ansible\-collections/community\.docker/issues/123)\, [https\://github\.com/ansible\-collections/community\.docker/pull/426](https\://github\.com/ansible\-collections/community\.docker/pull/426)\)\.
+* modules and plugins communicating directly with the Docker daemon \- improve default TLS version selection for Python 3\.6 and newer\. This is only a change relative to older community\.docker 3\.0\.0 pre\-releases or with respect to Docker SDK for Python \< 6\.0\.0\. Docker SDK for Python 6\.0\.0 will also include this change \([https\://github\.com/ansible\-collections/community\.docker/pull/434](https\://github\.com/ansible\-collections/community\.docker/pull/434)\)\.
+* modules and plugins communicating directly with the Docker daemon \- simplify use of helper function that was removed in Docker SDK for Python to find executables \([https\://github\.com/ansible\-collections/community\.docker/pull/438](https\://github\.com/ansible\-collections/community\.docker/pull/438)\)\.
+* socker\_handler and socket\_helper module utils \- improve Python forward compatibility\, create helper functions for file blocking/unblocking \([https\://github\.com/ansible\-collections/community\.docker/pull/415](https\://github\.com/ansible\-collections/community\.docker/pull/415)\)\.
+
+<a id="breaking-changes--porting-guide"></a>
+### Breaking Changes / Porting Guide
+
+* This collection does not work with ansible\-core 2\.11 on Python 3\.12\+\. Please either upgrade to ansible\-core 2\.12\+\, or use Python 3\.11 or earlier \([https\://github\.com/ansible\-collections/community\.docker/pull/271](https\://github\.com/ansible\-collections/community\.docker/pull/271)\)\.
+* docker\_container \- <code>exposed\_ports</code> is no longer ignored in <code>comparisons</code>\. Before\, its value was assumed to be identical with the value of <code>published\_ports</code> \([https\://github\.com/ansible\-collections/community\.docker/pull/422](https\://github\.com/ansible\-collections/community\.docker/pull/422)\)\.
+* docker\_container \- <code>log\_options</code> can no longer be specified when <code>log\_driver</code> is not specified \([https\://github\.com/ansible\-collections/community\.docker/pull/422](https\://github\.com/ansible\-collections/community\.docker/pull/422)\)\.
+* docker\_container \- <code>publish\_all\_ports</code> is no longer ignored in <code>comparisons</code> \([https\://github\.com/ansible\-collections/community\.docker/pull/422](https\://github\.com/ansible\-collections/community\.docker/pull/422)\)\.
+* docker\_container \- <code>restart\_retries</code> can no longer be specified when <code>restart\_policy</code> is not specified \([https\://github\.com/ansible\-collections/community\.docker/pull/422](https\://github\.com/ansible\-collections/community\.docker/pull/422)\)\.
+* docker\_container \- <code>stop\_timeout</code> is no longer ignored for idempotency if told to be not ignored in <code>comparisons</code>\. So far it defaulted to <code>ignore</code> there\, and setting it to <code>strict</code> had no effect \([https\://github\.com/ansible\-collections/community\.docker/pull/422](https\://github\.com/ansible\-collections/community\.docker/pull/422)\)\.
+* modules and plugins communicating directly with the Docker daemon \- when connecting by SSH and not using <code>use\_ssh\_client\=true</code>\, reject unknown host keys instead of accepting them\. This is only a breaking change relative to older community\.docker 3\.0\.0 pre\-releases or with respect to Docker SDK for Python \< 6\.0\.0\. Docker SDK for Python 6\.0\.0 will also include this change \([https\://github\.com/ansible\-collections/community\.docker/pull/434](https\://github\.com/ansible\-collections/community\.docker/pull/434)\)\.
+
+<a id="removed-features-previously-deprecated"></a>
+### Removed Features \(previously deprecated\)
+
+* Execution Environments built with community\.docker no longer include docker\-compose \< 2\.0\.0\. If you need to use it with the <code>docker\_compose</code> module\, please install that requirement manually \([https\://github\.com/ansible\-collections/community\.docker/pull/400](https\://github\.com/ansible\-collections/community\.docker/pull/400)\)\.
+* Support for Ansible 2\.9 and ansible\-base 2\.10 has been removed\. If you need support for Ansible 2\.9 or ansible\-base 2\.10\, please use community\.docker 2\.x\.y \([https\://github\.com/ansible\-collections/community\.docker/pull/400](https\://github\.com/ansible\-collections/community\.docker/pull/400)\)\.
+* Support for Docker API versions 1\.20 to 1\.24 has been removed\. If you need support for these API versions\, please use community\.docker 2\.x\.y \([https\://github\.com/ansible\-collections/community\.docker/pull/400](https\://github\.com/ansible\-collections/community\.docker/pull/400)\)\.
+* Support for Python 2\.6 has been removed\. If you need support for Python 2\.6\, please use community\.docker 2\.x\.y \([https\://github\.com/ansible\-collections/community\.docker/pull/400](https\://github\.com/ansible\-collections/community\.docker/pull/400)\)\.
+* Various modules \- the default of <code>tls\_hostname</code> \(<code>localhost</code>\) has been removed\. If you want to continue using <code>localhost</code>\, you need to specify it explicitly \([https\://github\.com/ansible\-collections/community\.docker/pull/363](https\://github\.com/ansible\-collections/community\.docker/pull/363)\)\.
+* docker\_container \- the <code>all</code> value is no longer allowed in <code>published\_ports</code>\. Use <code>publish\_all\_ports\=true</code> instead \([https\://github\.com/ansible\-collections/community\.docker/pull/399](https\://github\.com/ansible\-collections/community\.docker/pull/399)\)\.
+* docker\_container \- the default of <code>command\_handling</code> was changed from <code>compatibility</code> to <code>correct</code>\. Older versions were warning for every invocation of the module when this would result in a change of behavior \([https\://github\.com/ansible\-collections/community\.docker/pull/399](https\://github\.com/ansible\-collections/community\.docker/pull/399)\)\.
+* docker\_stack \- the return values <code>out</code> and <code>err</code> have been removed\. Use <code>stdout</code> and <code>stderr</code> instead \([https\://github\.com/ansible\-collections/community\.docker/pull/363](https\://github\.com/ansible\-collections/community\.docker/pull/363)\)\.
+
+<a id="security-fixes-1"></a>
+### Security Fixes
+
+* modules and plugins communicating directly with the Docker daemon \- when connecting by SSH and not using <code>use\_ssh\_client\=true</code>\, reject unknown host keys instead of accepting them\. This is only a change relative to older community\.docker 3\.0\.0 pre\-releases or with respect to Docker SDK for Python \< 6\.0\.0\. Docker SDK for Python 6\.0\.0 will also include this change \([https\://github\.com/ansible\-collections/community\.docker/pull/434](https\://github\.com/ansible\-collections/community\.docker/pull/434)\)\.
+
+<a id="bugfixes-20"></a>
+### Bugfixes
+
+* docker\_image \- when composing the build context\, trim trailing whitespace from <code>\.dockerignore</code> entries\. This is only a change relative to older community\.docker 3\.0\.0 pre\-releases or with respect to Docker SDK for Python \< 6\.0\.0\. Docker SDK for Python 6\.0\.0 will also include this change \([https\://github\.com/ansible\-collections/community\.docker/pull/434](https\://github\.com/ansible\-collections/community\.docker/pull/434)\)\.
+* docker\_plugin \- fix crash when handling plugin options \([https\://github\.com/ansible\-collections/community\.docker/issues/446](https\://github\.com/ansible\-collections/community\.docker/issues/446)\, [https\://github\.com/ansible\-collections/community\.docker/pull/447](https\://github\.com/ansible\-collections/community\.docker/pull/447)\)\.
+* docker\_stack \- fix broken string formatting when reporting error in case <code>compose</code> was containing invalid values \([https\://github\.com/ansible\-collections/community\.docker/pull/448](https\://github\.com/ansible\-collections/community\.docker/pull/448)\)\.
+* modules and plugins communicating directly with the Docker daemon \- do not create a subshell for SSH connections when using <code>use\_ssh\_client\=true</code>\. This is only a change relative to older community\.docker 3\.0\.0 pre\-releases or with respect to Docker SDK for Python \< 6\.0\.0\. Docker SDK for Python 6\.0\.0 will also include this change \([https\://github\.com/ansible\-collections/community\.docker/pull/434](https\://github\.com/ansible\-collections/community\.docker/pull/434)\)\.
+* modules and plugins communicating directly with the Docker daemon \- fix <code>ProxyCommand</code> handling for SSH connections when not using <code>use\_ssh\_client\=true</code>\. This is only a change relative to older community\.docker 3\.0\.0 pre\-releases or with respect to Docker SDK for Python \< 6\.0\.0\. Docker SDK for Python 6\.0\.0 will also include this change \([https\://github\.com/ansible\-collections/community\.docker/pull/434](https\://github\.com/ansible\-collections/community\.docker/pull/434)\)\.
+* modules and plugins communicating directly with the Docker daemon \- fix parsing of IPv6 addresses with a port in <code>docker\_host</code>\. This is only a change relative to older community\.docker 3\.0\.0 pre\-releases or with respect to Docker SDK for Python \< 6\.0\.0\. Docker SDK for Python 6\.0\.0 will also include this change \([https\://github\.com/ansible\-collections/community\.docker/pull/434](https\://github\.com/ansible\-collections/community\.docker/pull/434)\)\.
+* modules and plugins communicating directly with the Docker daemon \- prevent crash when TLS is used \([https\://github\.com/ansible\-collections/community\.docker/pull/432](https\://github\.com/ansible\-collections/community\.docker/pull/432)\)\.
+
+<a id="v2-7-0"></a>
+## v2\.7\.0
+
+<a id="release-summary-27"></a>
+### Release Summary
+
+Bugfix and deprecation release\. The next 2\.x\.y releases will only be bugfix releases\, the next expect minor/major release will be 3\.0\.0 with some major changes\.
+
+<a id="minor-changes-10"></a>
+### Minor Changes
+
+* Move common utility functions from the <code>common</code> module\_util to a new module\_util called <code>util</code>\. This should not have any user\-visible effect \([https\://github\.com/ansible\-collections/community\.docker/pull/390](https\://github\.com/ansible\-collections/community\.docker/pull/390)\)\.
+
+<a id="deprecated-features-2"></a>
+### Deprecated Features
+
+* Support for Docker API version 1\.20 to 1\.24 has been deprecated and will be removed in community\.docker 3\.0\.0\. The first Docker version supporting API version 1\.25 was Docker 1\.13\, released in January 2017\. This affects the modules <code>docker\_container</code>\, <code>docker\_container\_exec</code>\, <code>docker\_container\_info</code>\, <code>docker\_compose</code>\, <code>docker\_login</code>\, <code>docker\_image</code>\, <code>docker\_image\_info</code>\, <code>docker\_image\_load</code>\, <code>docker\_host\_info</code>\, <code>docker\_network</code>\, <code>docker\_network\_info</code>\, <code>docker\_node\_info</code>\, <code>docker\_swarm\_info</code>\, <code>docker\_swarm\_service</code>\, <code>docker\_swarm\_service\_info</code>\, <code>docker\_volume\_info</code>\, and <code>docker\_volume</code>\, whose minimally supported API version is between 1\.20 and 1\.24 \([https\://github\.com/ansible\-collections/community\.docker/pull/396](https\://github\.com/ansible\-collections/community\.docker/pull/396)\)\.
+* Support for Python 2\.6 is deprecated and will be removed in the next major release \(community\.docker 3\.0\.0\)\. Some modules might still work with Python 2\.6\, but we will no longer try to ensure compatibility \([https\://github\.com/ansible\-collections/community\.docker/pull/388](https\://github\.com/ansible\-collections/community\.docker/pull/388)\)\.
+
+<a id="bugfixes-21"></a>
+### Bugfixes
+
+* Docker SDK for Python based modules and plugins \- if the API version is specified as an option\, use that one to validate API version requirements of module/plugin options instead of the latest API version supported by the Docker daemon\. This also avoids one unnecessary API call per module/plugin \([https\://github\.com/ansible\-collections/community\.docker/pull/389](https\://github\.com/ansible\-collections/community\.docker/pull/389)\)\.
+
+<a id="v2-6-0"></a>
+## v2\.6\.0
+
+<a id="release-summary-28"></a>
+### Release Summary
+
+Bugfix and feature release\.
+
+<a id="minor-changes-11"></a>
+### Minor Changes
+
+* docker\_container \- added <code>image\_label\_mismatch</code> parameter \([https\://github\.com/ansible\-collections/community\.docker/issues/314](https\://github\.com/ansible\-collections/community\.docker/issues/314)\, [https\://github\.com/ansible\-collections/community\.docker/pull/370](https\://github\.com/ansible\-collections/community\.docker/pull/370)\)\.
+
+<a id="deprecated-features-3"></a>
+### Deprecated Features
+
+* Support for Ansible 2\.9 and ansible\-base 2\.10 is deprecated\, and will be removed in the next major release \(community\.docker 3\.0\.0\)\. Some modules might still work with these versions afterwards\, but we will no longer keep compatibility code that was needed to support them \([https\://github\.com/ansible\-collections/community\.docker/pull/361](https\://github\.com/ansible\-collections/community\.docker/pull/361)\)\.
+* The dependency on docker\-compose for Execution Environments is deprecated and will be removed in community\.docker 3\.0\.0\. The [Python docker\-compose library](https\://pypi\.org/project/docker\-compose/) is unmaintained and can cause dependency issues\. You can manually still install it in an Execution Environment when needed \([https\://github\.com/ansible\-collections/community\.docker/pull/373](https\://github\.com/ansible\-collections/community\.docker/pull/373)\)\.
+* Various modules \- the default of <code>tls\_hostname</code> that was supposed to be removed in community\.docker 2\.0\.0 will now be removed in version 3\.0\.0 \([https\://github\.com/ansible\-collections/community\.docker/pull/362](https\://github\.com/ansible\-collections/community\.docker/pull/362)\)\.
+* docker\_stack \- the return values <code>out</code> and <code>err</code> that were supposed to be removed in community\.docker 2\.0\.0 will now be removed in version 3\.0\.0 \([https\://github\.com/ansible\-collections/community\.docker/pull/362](https\://github\.com/ansible\-collections/community\.docker/pull/362)\)\.
+
+<a id="bugfixes-22"></a>
+### Bugfixes
+
+* docker\_container \- fail with a meaningful message instead of crashing if a port is specified with more than three colon\-separated parts \([https\://github\.com/ansible\-collections/community\.docker/pull/367](https\://github\.com/ansible\-collections/community\.docker/pull/367)\, [https\://github\.com/ansible\-collections/community\.docker/issues/365](https\://github\.com/ansible\-collections/community\.docker/issues/365)\)\.
+* docker\_container \- remove unused code that will cause problems with Python 3\.13 \([https\://github\.com/ansible\-collections/community\.docker/pull/354](https\://github\.com/ansible\-collections/community\.docker/pull/354)\)\.
+
+<a id="v2-5-1"></a>
+## v2\.5\.1
+
+<a id="release-summary-29"></a>
+### Release Summary
+
+Maintenance release\.
+
+<a id="bugfixes-23"></a>
+### Bugfixes
+
+* Include <code>PSF\-license\.txt</code> file for <code>plugins/module\_utils/\_version\.py</code>\.
+
+<a id="v2-5-0"></a>
+## v2\.5\.0
+
+<a id="release-summary-30"></a>
+### Release Summary
+
+Regular feature release\.
+
+<a id="minor-changes-12"></a>
+### Minor Changes
+
+* docker\_config \- add support for <code>template\_driver</code> with one option <code>golang</code> \([https\://github\.com/ansible\-collections/community\.docker/issues/332](https\://github\.com/ansible\-collections/community\.docker/issues/332)\, [https\://github\.com/ansible\-collections/community\.docker/pull/345](https\://github\.com/ansible\-collections/community\.docker/pull/345)\)\.
+* docker\_swarm \- adds <code>data\_path\_addr</code> parameter during swarm initialization or when joining \([https\://github\.com/ansible\-collections/community\.docker/issues/339](https\://github\.com/ansible\-collections/community\.docker/issues/339)\)\.
+
+<a id="v2-4-0"></a>
+## v2\.4\.0
+
+<a id="release-summary-31"></a>
+### Release Summary
+
+Regular feature and bugfix release\.
+
+<a id="minor-changes-13"></a>
+### Minor Changes
+
+* Prepare collection for inclusion in an Execution Environment by declaring its dependencies\. The <code>docker\_stack\*</code> modules are not supported \([https\://github\.com/ansible\-collections/community\.docker/pull/336](https\://github\.com/ansible\-collections/community\.docker/pull/336)\)\.
+* current\_container\_facts \- add detection for GitHub Actions \([https\://github\.com/ansible\-collections/community\.docker/pull/336](https\://github\.com/ansible\-collections/community\.docker/pull/336)\)\.
+* docker\_container \- support returning Docker container log output when using Docker\'s <code>local</code> logging driver\, an optimized local logging driver introduced in Docker 18\.09 \([https\://github\.com/ansible\-collections/community\.docker/pull/337](https\://github\.com/ansible\-collections/community\.docker/pull/337)\)\.
+
+<a id="bugfixes-24"></a>
+### Bugfixes
+
+* docker connection plugin \- make sure that <code>docker\_extra\_args</code> is used for querying the Docker version\. Also ensures that the Docker version is only queried when needed\. This is currently the case if a remote user is specified \([https\://github\.com/ansible\-collections/community\.docker/issues/325](https\://github\.com/ansible\-collections/community\.docker/issues/325)\, [https\://github\.com/ansible\-collections/community\.docker/pull/327](https\://github\.com/ansible\-collections/community\.docker/pull/327)\)\.
+
+<a id="v2-3-0"></a>
+## v2\.3\.0
+
+<a id="release-summary-32"></a>
+### Release Summary
+
+Regular feature and bugfix release\.
+
+<a id="minor-changes-14"></a>
+### Minor Changes
+
+* docker connection plugin \- implement connection reset by clearing internal container user cache \([https\://github\.com/ansible\-collections/community\.docker/pull/312](https\://github\.com/ansible\-collections/community\.docker/pull/312)\)\.
+* docker connection plugin \- simplify <code>actual\_user</code> handling code \([https\://github\.com/ansible\-collections/community\.docker/pull/311](https\://github\.com/ansible\-collections/community\.docker/pull/311)\)\.
+* docker connection plugin \- the plugin supports new ways to define the timeout\. These are the <code>ANSIBLE\_DOCKER\_TIMEOUT</code> environment variable\, the <code>timeout</code> setting in the <code>docker\_connection</code> section of <code>ansible\.cfg</code>\, and the <code>ansible\_docker\_timeout</code> variable \([https\://github\.com/ansible\-collections/community\.docker/pull/297](https\://github\.com/ansible\-collections/community\.docker/pull/297)\)\.
+* docker\_api connection plugin \- implement connection reset by clearing internal container user/group ID cache \([https\://github\.com/ansible\-collections/community\.docker/pull/312](https\://github\.com/ansible\-collections/community\.docker/pull/312)\)\.
+* docker\_api connection plugin \- the plugin supports new ways to define the timeout\. These are the <code>ANSIBLE\_DOCKER\_TIMEOUT</code> environment variable\, the <code>timeout</code> setting in the <code>docker\_connection</code> section of <code>ansible\.cfg</code>\, and the <code>ansible\_docker\_timeout</code> variable \([https\://github\.com/ansible\-collections/community\.docker/pull/308](https\://github\.com/ansible\-collections/community\.docker/pull/308)\)\.
+
+<a id="bugfixes-25"></a>
+### Bugfixes
+
+* docker connection plugin \- fix option handling to be compatible with ansible\-core 2\.13 \([https\://github\.com/ansible\-collections/community\.docker/pull/297](https\://github\.com/ansible\-collections/community\.docker/pull/297)\, [https\://github\.com/ansible\-collections/community\.docker/issues/307](https\://github\.com/ansible\-collections/community\.docker/issues/307)\)\.
+* docker\_api connection plugin \- fix option handling to be compatible with ansible\-core 2\.13 \([https\://github\.com/ansible\-collections/community\.docker/pull/308](https\://github\.com/ansible\-collections/community\.docker/pull/308)\)\.
+
+<a id="v2-2-1"></a>
+## v2\.2\.1
+
+<a id="release-summary-33"></a>
+### Release Summary
+
+Regular bugfix release\.
+
+<a id="bugfixes-26"></a>
+### Bugfixes
+
+* docker\_compose \- fix Python 3 type error when extracting warnings or errors from docker\-compose\'s output \([https\://github\.com/ansible\-collections/community\.docker/pull/305](https\://github\.com/ansible\-collections/community\.docker/pull/305)\)\.
+
+<a id="v2-2-0"></a>
+## v2\.2\.0
+
+<a id="release-summary-34"></a>
+### Release Summary
+
+Regular feature and bugfix release\.
+
+<a id="minor-changes-15"></a>
+### Minor Changes
+
+* docker\_config \- add support for rolling update\, set <code>rolling\_versions</code> to <code>true</code> to enable \([https\://github\.com/ansible\-collections/community\.docker/pull/295](https\://github\.com/ansible\-collections/community\.docker/pull/295)\, [https\://github\.com/ansible\-collections/community\.docker/issues/109](https\://github\.com/ansible\-collections/community\.docker/issues/109)\)\.
+* docker\_secret \- add support for rolling update\, set <code>rolling\_versions</code> to <code>true</code> to enable \([https\://github\.com/ansible\-collections/community\.docker/pull/293](https\://github\.com/ansible\-collections/community\.docker/pull/293)\, [https\://github\.com/ansible\-collections/community\.docker/issues/21](https\://github\.com/ansible\-collections/community\.docker/issues/21)\)\.
+* docker\_swarm\_service \- add support for setting capabilities with the <code>cap\_add</code> and <code>cap\_drop</code> parameters\. Usage is the same as with the <code>capabilities</code> and <code>cap\_drop</code> parameters for <code>docker\_container</code> \([https\://github\.com/ansible\-collections/community\.docker/pull/294](https\://github\.com/ansible\-collections/community\.docker/pull/294)\)\.
+
+<a id="bugfixes-27"></a>
+### Bugfixes
+
+* docker\_container\, docker\_image \- adjust image finding code to peculiarities of <code>podman\-docker</code>\'s API emulation when Docker short names like <code>redis</code> are used \([https\://github\.com/ansible\-collections/community\.docker/issues/292](https\://github\.com/ansible\-collections/community\.docker/issues/292)\)\.
+
+<a id="v2-1-1"></a>
+## v2\.1\.1
+
+<a id="release-summary-35"></a>
+### Release Summary
+
+Emergency release to amend breaking change in previous release\.
+
+<a id="bugfixes-28"></a>
+### Bugfixes
+
+* Fix unintended breaking change caused by [an earlier fix](https\://github\.com/ansible\-collections/community\.docker/pull/258) by vendoring the deprecated Python standard library <code>distutils\.version</code> until this collection stops supporting Ansible 2\.9 and ansible\-base 2\.10 \([https\://github\.com/ansible\-collections/community\.docker/issues/267](https\://github\.com/ansible\-collections/community\.docker/issues/267)\, [https\://github\.com/ansible\-collections/community\.docker/pull/269](https\://github\.com/ansible\-collections/community\.docker/pull/269)\)\.
+
+<a id="v2-1-0"></a>
+## v2\.1\.0
+
+<a id="release-summary-36"></a>
+### Release Summary
+
+Feature and bugfix release\.
+
+<a id="minor-changes-16"></a>
+### Minor Changes
+
+* docker\_container\_exec \- add <code>detach</code> parameter \([https\://github\.com/ansible\-collections/community\.docker/issues/250](https\://github\.com/ansible\-collections/community\.docker/issues/250)\, [https\://github\.com/ansible\-collections/community\.docker/pull/255](https\://github\.com/ansible\-collections/community\.docker/pull/255)\)\.
+* docker\_container\_exec \- add <code>env</code> option \([https\://github\.com/ansible\-collections/community\.docker/issues/248](https\://github\.com/ansible\-collections/community\.docker/issues/248)\, [https\://github\.com/ansible\-collections/community\.docker/pull/254](https\://github\.com/ansible\-collections/community\.docker/pull/254)\)\.
+
+<a id="bugfixes-29"></a>
+### Bugfixes
+
+* Various modules and plugins \- use vendored version of <code>distutils\.version</code> included in ansible\-core 2\.12 if available\. This avoids breakage when <code>distutils</code> is removed from the standard library of Python 3\.12\. Note that ansible\-core 2\.11\, ansible\-base 2\.10 and Ansible 2\.9 are right now not compatible with Python 3\.12\, hence this fix does not target these ansible\-core/\-base/2\.9 versions \([https\://github\.com/ansible\-collections/community\.docker/pull/258](https\://github\.com/ansible\-collections/community\.docker/pull/258)\)\.
+* docker connection plugin \- replace deprecated <code>distutils\.spawn\.find\_executable</code> with Ansible\'s <code>get\_bin\_path</code> to find the <code>docker</code> executable \([https\://github\.com/ansible\-collections/community\.docker/pull/257](https\://github\.com/ansible\-collections/community\.docker/pull/257)\)\.
+* docker\_container\_exec \- disallow using the <code>chdir</code> option for Docker API before 1\.35 \([https\://github\.com/ansible\-collections/community\.docker/pull/253](https\://github\.com/ansible\-collections/community\.docker/pull/253)\)\.
+
+<a id="v2-0-2"></a>
+## v2\.0\.2
+
+<a id="release-summary-37"></a>
+### Release Summary
+
+Bugfix release\.
+
+<a id="bugfixes-30"></a>
+### Bugfixes
+
+* docker\_api connection plugin \- avoid passing an unnecessary argument to a Docker SDK for Python call that is only supported by version 3\.0\.0 or later \([https\://github\.com/ansible\-collections/community\.docker/pull/243](https\://github\.com/ansible\-collections/community\.docker/pull/243)\)\.
+* docker\_container\_exec \- <code>chdir</code> is only supported since Docker SDK for Python 3\.0\.0\. Make sure that this option can only use when 3\.0\.0 or later is installed\, and prevent passing this parameter on when <code>chdir</code> is not provided to this module \([https\://github\.com/ansible\-collections/community\.docker/pull/243](https\://github\.com/ansible\-collections/community\.docker/pull/243)\, [https\://github\.com/ansible\-collections/community\.docker/issues/242](https\://github\.com/ansible\-collections/community\.docker/issues/242)\)\.
+* nsenter connection plugin \- ensure the <code>nsenter\_pid</code> option is retrieved in <code>\_connect</code> instead of <code>\_\_init\_\_</code> to prevent a crash due to bad initialization order \([https\://github\.com/ansible\-collections/community\.docker/pull/249](https\://github\.com/ansible\-collections/community\.docker/pull/249)\)\.
+* nsenter connection plugin \- replace the use of <code>\-\-all\-namespaces</code> with specific namespaces to support compatibility with Busybox nsenter \(used on\, for example\, Alpine containers\) \([https\://github\.com/ansible\-collections/community\.docker/pull/249](https\://github\.com/ansible\-collections/community\.docker/pull/249)\)\.
+
+<a id="v2-0-1"></a>
+## v2\.0\.1
+
+<a id="release-summary-38"></a>
+### Release Summary
+
+Maintenance release with some documentation fixes\.
+
+<a id="v2-0-0"></a>
+## v2\.0\.0
+
+<a id="release-summary-39"></a>
+### Release Summary
+
+New major release with some deprecations removed and a breaking change in the <code>docker\_compose</code> module regarding the <code>timeout</code> parameter\.
+
+<a id="breaking-changes--porting-guide-1"></a>
+### Breaking Changes / Porting Guide
+
+* docker\_compose \- fixed <code>timeout</code> defaulting behavior so that <code>stop\_grace\_period</code>\, if defined in the compose file\, will be used if <em class="title-reference">timeout\`</em> is not specified \([https\://github\.com/ansible\-collections/community\.docker/pull/163](https\://github\.com/ansible\-collections/community\.docker/pull/163)\)\.
+
+<a id="deprecated-features-4"></a>
+### Deprecated Features
+
+* docker\_container \- using the special value <code>all</code> in <code>published\_ports</code> has been deprecated\. Use <code>publish\_all\_ports\=true</code> instead \([https\://github\.com/ansible\-collections/community\.docker/pull/210](https\://github\.com/ansible\-collections/community\.docker/pull/210)\)\.
+
+<a id="removed-features-previously-deprecated-1"></a>
+### Removed Features \(previously deprecated\)
+
+* docker\_container \- the default value of <code>container\_default\_behavior</code> changed to <code>no\_defaults</code> \([https\://github\.com/ansible\-collections/community\.docker/pull/210](https\://github\.com/ansible\-collections/community\.docker/pull/210)\)\.
+* docker\_container \- the default value of <code>network\_mode</code> is now the name of the first network specified in <code>networks</code> if such are specified and <code>networks\_cli\_compatible\=true</code> \([https\://github\.com/ansible\-collections/community\.docker/pull/210](https\://github\.com/ansible\-collections/community\.docker/pull/210)\)\.
+* docker\_container \- the special value <code>all</code> can no longer be used in <code>published\_ports</code> next to other values\. Please use <code>publish\_all\_ports\=true</code> instead \([https\://github\.com/ansible\-collections/community\.docker/pull/210](https\://github\.com/ansible\-collections/community\.docker/pull/210)\)\.
+* docker\_login \- removed the <code>email</code> option \([https\://github\.com/ansible\-collections/community\.docker/pull/210](https\://github\.com/ansible\-collections/community\.docker/pull/210)\)\.
+
+<a id="v1-10-0"></a>
+## v1\.10\.0
+
+<a id="release-summary-40"></a>
+### Release Summary
+
+Regular feature and bugfix release\.
+
+<a id="minor-changes-17"></a>
+### Minor Changes
+
+* Add the modules docker\_container\_exec\, docker\_image\_load and docker\_plugin to the <code>docker</code> module defaults group \([https\://github\.com/ansible\-collections/community\.docker/pull/209](https\://github\.com/ansible\-collections/community\.docker/pull/209)\)\.
+* docker\_config \- add option <code>data\_src</code> to read configuration data from target \([https\://github\.com/ansible\-collections/community\.docker/issues/64](https\://github\.com/ansible\-collections/community\.docker/issues/64)\, [https\://github\.com/ansible\-collections/community\.docker/pull/203](https\://github\.com/ansible\-collections/community\.docker/pull/203)\)\.
+* docker\_secret \- add option <code>data\_src</code> to read secret data from target \([https\://github\.com/ansible\-collections/community\.docker/issues/64](https\://github\.com/ansible\-collections/community\.docker/issues/64)\, [https\://github\.com/ansible\-collections/community\.docker/pull/203](https\://github\.com/ansible\-collections/community\.docker/pull/203)\)\.
+
+<a id="v1-9-1"></a>
+## v1\.9\.1
+
+<a id="release-summary-41"></a>
+### Release Summary
+
+Regular bugfix release\.
+
+<a id="bugfixes-31"></a>
+### Bugfixes
+
+* docker\_compose \- fixed incorrect <code>changed</code> status for services with <code>profiles</code> defined\, but none enabled \([https\://github\.com/ansible\-collections/community\.docker/pull/192](https\://github\.com/ansible\-collections/community\.docker/pull/192)\)\.
+
+<a id="v1-9-0"></a>
+## v1\.9\.0
+
+<a id="release-summary-42"></a>
+### Release Summary
+
+New bugfixes and features release\.
+
+<a id="minor-changes-18"></a>
+### Minor Changes
+
+* docker\_\* modules \- include <code>ImportError</code> traceback when reporting that Docker SDK for Python could not be found \([https\://github\.com/ansible\-collections/community\.docker/pull/188](https\://github\.com/ansible\-collections/community\.docker/pull/188)\)\.
+* docker\_compose \- added <code>env\_file</code> option for specifying custom environment files \([https\://github\.com/ansible\-collections/community\.docker/pull/174](https\://github\.com/ansible\-collections/community\.docker/pull/174)\)\.
+* docker\_container \- added <code>publish\_all\_ports</code> option to publish all exposed ports to random ports except those explicitly bound with <code>published\_ports</code> \(this was already added in community\.docker 1\.8\.0\) \([https\://github\.com/ansible\-collections/community\.docker/pull/162](https\://github\.com/ansible\-collections/community\.docker/pull/162)\)\.
+* docker\_container \- added new <code>command\_handling</code> option with current deprecated default value <code>compatibility</code> which allows to control how the module handles shell quoting when interpreting lists\, and how the module handles empty lists/strings\. The default will switch to <code>correct</code> in community\.docker 3\.0\.0 \([https\://github\.com/ansible\-collections/community\.docker/pull/186](https\://github\.com/ansible\-collections/community\.docker/pull/186)\)\.
+* docker\_container \- lifted restriction preventing the creation of anonymous volumes with the <code>mounts</code> option \([https\://github\.com/ansible\-collections/community\.docker/pull/181](https\://github\.com/ansible\-collections/community\.docker/pull/181)\)\.
+
+<a id="deprecated-features-5"></a>
+### Deprecated Features
+
+* docker\_container \- the new <code>command\_handling</code>\'s default value\, <code>compatibility</code>\, is deprecated and will change to <code>correct</code> in community\.docker 3\.0\.0\. A deprecation warning is emitted by the module in cases where the behavior will change\. Please note that ansible\-core will output a deprecation warning only once\, so if it is shown for an earlier task\, there could be more tasks with this warning where it is not shown \([https\://github\.com/ansible\-collections/community\.docker/pull/186](https\://github\.com/ansible\-collections/community\.docker/pull/186)\)\.
+
+<a id="bugfixes-32"></a>
+### Bugfixes
+
+* docker\_compose \- fixes task failures when bringing up services while using <code>docker\-compose \<1\.17\.0</code> \([https\://github\.com/ansible\-collections/community\.docker/issues/180](https\://github\.com/ansible\-collections/community\.docker/issues/180)\)\.
+* docker\_container \- make sure to also return <code>container</code> on <code>detached\=false</code> when status code is non\-zero \([https\://github\.com/ansible\-collections/community\.docker/pull/178](https\://github\.com/ansible\-collections/community\.docker/pull/178)\)\.
+* docker\_stack\_info \- make sure that module isn\'t skipped in check mode \([https\://github\.com/ansible\-collections/community\.docker/pull/183](https\://github\.com/ansible\-collections/community\.docker/pull/183)\)\.
+* docker\_stack\_task\_info \- make sure that module isn\'t skipped in check mode \([https\://github\.com/ansible\-collections/community\.docker/pull/183](https\://github\.com/ansible\-collections/community\.docker/pull/183)\)\.
+
+<a id="new-plugins"></a>
+### New Plugins
+
+<a id="connection"></a>
+#### Connection
+
+* nsenter \- execute on host running controller container
+
+<a id="v1-8-0"></a>
+## v1\.8\.0
+
+<a id="release-summary-43"></a>
+### Release Summary
+
+Regular bugfix and feature release\.
+
+<a id="minor-changes-19"></a>
+### Minor Changes
+
+* Avoid internal ansible\-core module\_utils in favor of equivalent public API available since at least Ansible 2\.9 \([https\://github\.com/ansible\-collections/community\.docker/pull/164](https\://github\.com/ansible\-collections/community\.docker/pull/164)\)\.
+* docker\_compose \- added <code>profiles</code> option to specify service profiles when starting services \([https\://github\.com/ansible\-collections/community\.docker/pull/167](https\://github\.com/ansible\-collections/community\.docker/pull/167)\)\.
+* docker\_containers inventory plugin \- when <code>connection\_type\=docker\-api</code>\, now pass Docker daemon connection options from inventory plugin to connection plugin\. This can be disabled by setting <code>configure\_docker\_daemon\=false</code> \([https\://github\.com/ansible\-collections/community\.docker/pull/157](https\://github\.com/ansible\-collections/community\.docker/pull/157)\)\.
+* docker\_host\_info \- allow values for keys in <code>containers\_filters</code>\, <code>images\_filters</code>\, <code>networks\_filters</code>\, and <code>volumes\_filters</code> to be passed as YAML lists \([https\://github\.com/ansible\-collections/community\.docker/pull/160](https\://github\.com/ansible\-collections/community\.docker/pull/160)\)\.
+* docker\_plugin \- added <code>alias</code> option to specify local names for docker plugins \([https\://github\.com/ansible\-collections/community\.docker/pull/161](https\://github\.com/ansible\-collections/community\.docker/pull/161)\)\.
+
+<a id="bugfixes-33"></a>
+### Bugfixes
+
+* docker\_compose \- fix idempotence bug when using <code>stopped\: true</code> \([https\://github\.com/ansible\-collections/community\.docker/issues/142](https\://github\.com/ansible\-collections/community\.docker/issues/142)\, [https\://github\.com/ansible\-collections/community\.docker/pull/159](https\://github\.com/ansible\-collections/community\.docker/pull/159)\)\.
+
+<a id="v1-7-0"></a>
+## v1\.7\.0
+
+<a id="release-summary-44"></a>
+### Release Summary
+
+Small feature and bugfix release\.
+
+<a id="minor-changes-20"></a>
+### Minor Changes
+
+* docker\_image \- allow to tag images by ID \([https\://github\.com/ansible\-collections/community\.docker/pull/149](https\://github\.com/ansible\-collections/community\.docker/pull/149)\)\.
+
+<a id="v1-6-1"></a>
+## v1\.6\.1
+
+<a id="release-summary-45"></a>
+### Release Summary
+
+Bugfix release to reduce deprecation warning spam\.
+
+<a id="bugfixes-34"></a>
+### Bugfixes
+
+* docker\_\* modules and plugins\, except <code>docker\_swarm</code> connection plugin and <code>docker\_compose</code> and <code>docker\_stack\*\` modules \- only emit \`\`tls\_hostname</code> deprecation message if TLS is actually used \([https\://github\.com/ansible\-collections/community\.docker/pull/143](https\://github\.com/ansible\-collections/community\.docker/pull/143)\)\.
+
+<a id="v1-6-0"></a>
+## v1\.6\.0
+
+<a id="release-summary-46"></a>
+### Release Summary
+
+Regular bugfix and feature release\.
+
+<a id="minor-changes-21"></a>
+### Minor Changes
+
+* common module utils \- correct error messages for guiding to install proper Docker SDK for Python module \([https\://github\.com/ansible\-collections/community\.docker/pull/125](https\://github\.com/ansible\-collections/community\.docker/pull/125)\)\.
+* docker\_container \- allow <code>memory\_swap\: \-1</code> to set memory swap limit to unlimited\. This is useful when the user cannot set memory swap limits due to cgroup limitations or other reasons\, as by default Docker will try to set swap usage to two times the value of <code>memory</code> \([https\://github\.com/ansible\-collections/community\.docker/pull/138](https\://github\.com/ansible\-collections/community\.docker/pull/138)\)\.
+
+<a id="deprecated-features-6"></a>
+### Deprecated Features
+
+* docker\_\* modules and plugins\, except <code>docker\_swarm</code> connection plugin and <code>docker\_compose</code> and <code>docker\_stack\*\` modules \- the current default \`\`localhost</code> for <code>tls\_hostname</code> is deprecated\. In community\.docker 2\.0\.0 it will be computed from <code>docker\_host</code> instead \([https\://github\.com/ansible\-collections/community\.docker/pull/134](https\://github\.com/ansible\-collections/community\.docker/pull/134)\)\.
+
+<a id="bugfixes-35"></a>
+### Bugfixes
+
+* docker\-compose \- fix not pulling when <code>state\: present</code> and <code>stopped\: true</code> \([https\://github\.com/ansible\-collections/community\.docker/issues/12](https\://github\.com/ansible\-collections/community\.docker/issues/12)\, [https\://github\.com/ansible\-collections/community\.docker/pull/119](https\://github\.com/ansible\-collections/community\.docker/pull/119)\)\.
+* docker\_plugin \- also configure plugin after installing \([https\://github\.com/ansible\-collections/community\.docker/issues/118](https\://github\.com/ansible\-collections/community\.docker/issues/118)\, [https\://github\.com/ansible\-collections/community\.docker/pull/135](https\://github\.com/ansible\-collections/community\.docker/pull/135)\)\.
+* docker\_swarm\_services \- avoid crash during idempotence check if <code>published\_port</code> is not specified \([https\://github\.com/ansible\-collections/community\.docker/issues/107](https\://github\.com/ansible\-collections/community\.docker/issues/107)\, [https\://github\.com/ansible\-collections/community\.docker/pull/136](https\://github\.com/ansible\-collections/community\.docker/pull/136)\)\.
+
+<a id="v1-5-0"></a>
+## v1\.5\.0
+
+<a id="release-summary-47"></a>
+### Release Summary
+
+Regular feature release\.
+
+<a id="minor-changes-22"></a>
+### Minor Changes
+
+* Add the <code>use\_ssh\_client</code> option to most docker modules and plugins \([https\://github\.com/ansible\-collections/community\.docker/issues/108](https\://github\.com/ansible\-collections/community\.docker/issues/108)\, [https\://github\.com/ansible\-collections/community\.docker/pull/114](https\://github\.com/ansible\-collections/community\.docker/pull/114)\)\.
+
+<a id="bugfixes-36"></a>
+### Bugfixes
+
+* all modules \- use <code>to\_native</code> to convert exceptions to strings \([https\://github\.com/ansible\-collections/community\.docker/pull/121](https\://github\.com/ansible\-collections/community\.docker/pull/121)\)\.
+
+<a id="new-modules-3"></a>
+### New Modules
+
+* docker\_container\_exec \- Execute command in a docker container
+
+<a id="v1-4-0"></a>
+## v1\.4\.0
+
+<a id="release-summary-48"></a>
+### Release Summary
+
+Security release to address another potential secret leak\. Also includes regular bugfixes and features\.
+
+<a id="minor-changes-23"></a>
+### Minor Changes
+
+* docker\_swarm\_service \- change <code>publish\.published\_port</code> option from mandatory to optional\. Docker will assign random high port if not specified \([https\://github\.com/ansible\-collections/community\.docker/issues/99](https\://github\.com/ansible\-collections/community\.docker/issues/99)\)\.
+
+<a id="breaking-changes--porting-guide-2"></a>
+### Breaking Changes / Porting Guide
+
+* docker\_swarm \- if <code>join\_token</code> is specified\, a returned join token with the same value will be replaced by <code>VALUE\_SPECIFIED\_IN\_NO\_LOG\_PARAMETER</code>\. Make sure that you do not blindly use the join tokens from the return value of this module when the module is invoked with <code>join\_token</code> specified\! This breaking change appears in a minor release since it is necessary to fix a security issue \([https\://github\.com/ansible\-collections/community\.docker/pull/103](https\://github\.com/ansible\-collections/community\.docker/pull/103)\)\.
+
+<a id="security-fixes-2"></a>
+### Security Fixes
+
+* docker\_swarm \- the <code>join\_token</code> option is now marked as <code>no\_log</code> so it is no longer written into logs \([https\://github\.com/ansible\-collections/community\.docker/pull/103](https\://github\.com/ansible\-collections/community\.docker/pull/103)\)\.
+
+<a id="bugfixes-37"></a>
+### Bugfixes
+
+* <code>docker\_swarm\_service</code> \- fix KeyError on caused by reference to deprecated option <code>update\_failure\_action</code> \([https\://github\.com/ansible\-collections/community\.docker/pull/100](https\://github\.com/ansible\-collections/community\.docker/pull/100)\)\.
+* docker\_swarm\_service \- mark <code>secrets</code> module option with <code>no\_log\=False</code> since it does not leak secrets \([https\://github\.com/ansible\-collections/community\.general/pull/2001](https\://github\.com/ansible\-collections/community\.general/pull/2001)\)\.
+
+<a id="v1-3-0"></a>
+## v1\.3\.0
+
+<a id="release-summary-49"></a>
+### Release Summary
+
+Regular feature and bugfix release\.
+
+<a id="minor-changes-24"></a>
+### Minor Changes
+
+* docker\_container \- add <code>storage\_opts</code> option to specify storage options \([https\://github\.com/ansible\-collections/community\.docker/issues/91](https\://github\.com/ansible\-collections/community\.docker/issues/91)\, [https\://github\.com/ansible\-collections/community\.docker/pull/93](https\://github\.com/ansible\-collections/community\.docker/pull/93)\)\.
+* docker\_image \- allows to specify platform to pull for <code>source\=pull</code> with new option <code>pull\_platform</code> \([https\://github\.com/ansible\-collections/community\.docker/issues/79](https\://github\.com/ansible\-collections/community\.docker/issues/79)\, [https\://github\.com/ansible\-collections/community\.docker/pull/89](https\://github\.com/ansible\-collections/community\.docker/pull/89)\)\.
+* docker\_image \- properly support image IDs \(hashes\) for loading and tagging images \([https\://github\.com/ansible\-collections/community\.docker/issues/86](https\://github\.com/ansible\-collections/community\.docker/issues/86)\, [https\://github\.com/ansible\-collections/community\.docker/pull/87](https\://github\.com/ansible\-collections/community\.docker/pull/87)\)\.
+* docker\_swarm\_service \- adding support for maximum number of tasks per node \(<code>replicas\_max\_per\_node</code>\) when running swarm service in replicated mode\. Introduced in API 1\.40 \([https\://github\.com/ansible\-collections/community\.docker/issues/7](https\://github\.com/ansible\-collections/community\.docker/issues/7)\, [https\://github\.com/ansible\-collections/community\.docker/pull/92](https\://github\.com/ansible\-collections/community\.docker/pull/92)\)\.
+
+<a id="bugfixes-38"></a>
+### Bugfixes
+
+* docker\_container \- fix healthcheck disabling idempotency issue with strict comparison \([https\://github\.com/ansible\-collections/community\.docker/issues/85](https\://github\.com/ansible\-collections/community\.docker/issues/85)\)\.
+* docker\_image \- prevent module failure when removing image that is removed between inspection and removal \([https\://github\.com/ansible\-collections/community\.docker/pull/87](https\://github\.com/ansible\-collections/community\.docker/pull/87)\)\.
+* docker\_image \- prevent module failure when removing non\-existent image by ID \([https\://github\.com/ansible\-collections/community\.docker/pull/87](https\://github\.com/ansible\-collections/community\.docker/pull/87)\)\.
+* docker\_image\_info \- prevent module failure when image vanishes between listing and inspection \([https\://github\.com/ansible\-collections/community\.docker/pull/87](https\://github\.com/ansible\-collections/community\.docker/pull/87)\)\.
+* docker\_image\_info \- prevent module failure when querying non\-existent image by ID \([https\://github\.com/ansible\-collections/community\.docker/pull/87](https\://github\.com/ansible\-collections/community\.docker/pull/87)\)\.
+
+<a id="new-modules-4"></a>
+### New Modules
+
+* docker\_image\_load \- Load docker image\(s\) from archives
+* docker\_plugin \- Manage Docker plugins
+
+<a id="v1-2-2"></a>
+## v1\.2\.2
+
+<a id="release-summary-50"></a>
+### Release Summary
+
+Security bugfix release to address CVE\-2021\-20191\.
+
+<a id="security-fixes-3"></a>
+### Security Fixes
+
+* docker\_swarm \- enabled <code>no\_log</code> for the option <code>signing\_ca\_key</code> to prevent accidental disclosure \(CVE\-2021\-20191\, [https\://github\.com/ansible\-collections/community\.docker/pull/80](https\://github\.com/ansible\-collections/community\.docker/pull/80)\)\.
+
+<a id="v1-2-1"></a>
+## v1\.2\.1
+
+<a id="release-summary-51"></a>
+### Release Summary
+
+Bugfix release\.
+
+<a id="bugfixes-39"></a>
+### Bugfixes
+
+* docker connection plugin \- fix Docker version parsing\, as some docker versions have a leading <code>v</code> in the output of the command <code>docker version \-\-format \"\{\{\.Server\.Version\}\}\"</code> \([https\://github\.com/ansible\-collections/community\.docker/pull/76](https\://github\.com/ansible\-collections/community\.docker/pull/76)\)\.
+
+<a id="v1-2-0"></a>
+## v1\.2\.0
+
+<a id="release-summary-52"></a>
+### Release Summary
+
+Feature release with one new feature and two bugfixes\.
+
+<a id="minor-changes-25"></a>
+### Minor Changes
+
+* docker\_container \- added <code>default\_host\_ip</code> option which allows to explicitly set the default IP string for published ports without explicitly specified IPs\. When using IPv6 binds with Docker 20\.10\.2 or newer\, this needs to be set to an empty string \(<code>\"\"</code>\) \([https\://github\.com/ansible\-collections/community\.docker/issues/70](https\://github\.com/ansible\-collections/community\.docker/issues/70)\, [https\://github\.com/ansible\-collections/community\.docker/pull/71](https\://github\.com/ansible\-collections/community\.docker/pull/71)\)\.
+
+<a id="bugfixes-40"></a>
+### Bugfixes
+
+* docker\_container \- allow IPv6 zones \(RFC 4007\) in bind IPs \([https\://github\.com/ansible\-collections/community\.docker/pull/66](https\://github\.com/ansible\-collections/community\.docker/pull/66)\)\.
+* docker\_image \- fix crash on loading images with versions of Docker SDK for Python before 2\.5\.0 \([https\://github\.com/ansible\-collections/community\.docker/issues/72](https\://github\.com/ansible\-collections/community\.docker/issues/72)\, [https\://github\.com/ansible\-collections/community\.docker/pull/73](https\://github\.com/ansible\-collections/community\.docker/pull/73)\)\.
+
+<a id="v1-1-0"></a>
+## v1\.1\.0
+
+<a id="release-summary-53"></a>
+### Release Summary
+
+Feature release with three new plugins and modules\.
+
+<a id="minor-changes-26"></a>
+### Minor Changes
+
+* docker\_container \- support specifying <code>cgroup\_parent</code> \([https\://github\.com/ansible\-collections/community\.docker/issues/6](https\://github\.com/ansible\-collections/community\.docker/issues/6)\, [https\://github\.com/ansible\-collections/community\.docker/pull/59](https\://github\.com/ansible\-collections/community\.docker/pull/59)\)\.
+* docker\_container \- when a container is started with <code>detached\=false</code>\, <code>status</code> is now also returned when it is 0 \([https\://github\.com/ansible\-collections/community\.docker/issues/26](https\://github\.com/ansible\-collections/community\.docker/issues/26)\, [https\://github\.com/ansible\-collections/community\.docker/pull/58](https\://github\.com/ansible\-collections/community\.docker/pull/58)\)\.
+* docker\_image \- support <code>platform</code> when building images \([https\://github\.com/ansible\-collections/community\.docker/issues/22](https\://github\.com/ansible\-collections/community\.docker/issues/22)\, [https\://github\.com/ansible\-collections/community\.docker/pull/54](https\://github\.com/ansible\-collections/community\.docker/pull/54)\)\.
+
+<a id="deprecated-features-7"></a>
+### Deprecated Features
+
+* docker\_container \- currently <code>published\_ports</code> can contain port mappings next to the special value <code>all</code>\, in which case the port mappings are ignored\. This behavior is deprecated for community\.docker 2\.0\.0\, at which point it will either be forbidden\, or this behavior will be properly implemented similar to how the Docker CLI tool handles this \([https\://github\.com/ansible\-collections/community\.docker/issues/8](https\://github\.com/ansible\-collections/community\.docker/issues/8)\, [https\://github\.com/ansible\-collections/community\.docker/pull/60](https\://github\.com/ansible\-collections/community\.docker/pull/60)\)\.
+
+<a id="bugfixes-41"></a>
+### Bugfixes
+
+* docker\_image \- if <code>push\=true</code> is used with <code>repository</code>\, and the image does not need to be tagged\, still push\. This can happen if <code>repository</code> and <code>name</code> are equal \([https\://github\.com/ansible\-collections/community\.docker/issues/52](https\://github\.com/ansible\-collections/community\.docker/issues/52)\, [https\://github\.com/ansible\-collections/community\.docker/pull/53](https\://github\.com/ansible\-collections/community\.docker/pull/53)\)\.
+* docker\_image \- report error when loading a broken archive that contains no image \([https\://github\.com/ansible\-collections/community\.docker/issues/46](https\://github\.com/ansible\-collections/community\.docker/issues/46)\, [https\://github\.com/ansible\-collections/community\.docker/pull/55](https\://github\.com/ansible\-collections/community\.docker/pull/55)\)\.
+* docker\_image \- report error when the loaded archive does not contain the specified image \([https\://github\.com/ansible\-collections/community\.docker/issues/41](https\://github\.com/ansible\-collections/community\.docker/issues/41)\, [https\://github\.com/ansible\-collections/community\.docker/pull/55](https\://github\.com/ansible\-collections/community\.docker/pull/55)\)\.
+
+<a id="new-plugins-1"></a>
+### New Plugins
+
+<a id="connection-1"></a>
+#### Connection
+
+* docker\_api \- Run tasks in docker containers
+
+<a id="inventory"></a>
+#### Inventory
+
+* docker\_containers \- Ansible dynamic inventory plugin for Docker containers\.
+
+<a id="new-modules-5"></a>
+### New Modules
+
+* current\_container\_facts \- Return facts about whether the module runs in a Docker container
+
+<a id="v1-0-1"></a>
+## v1\.0\.1
+
+<a id="release-summary-54"></a>
+### Release Summary
+
+Maintenance release with a bugfix for <code>docker\_container</code>\.
+
+<a id="bugfixes-42"></a>
+### Bugfixes
+
+* docker\_container \- the validation for <code>capabilities</code> in <code>device\_requests</code> was incorrect \([https\://github\.com/ansible\-collections/community\.docker/issues/42](https\://github\.com/ansible\-collections/community\.docker/issues/42)\, [https\://github\.com/ansible\-collections/community\.docker/pull/43](https\://github\.com/ansible\-collections/community\.docker/pull/43)\)\.
+
+<a id="v1-0-0"></a>
+## v1\.0\.0
+
+<a id="release-summary-55"></a>
+### Release Summary
+
+This is the first production \(non\-prerelease\) release of <code>community\.docker</code>\.
+
+<a id="minor-changes-27"></a>
+### Minor Changes
+
+* Add collection\-side support of the <code>docker</code> action group / module defaults group \([https\://github\.com/ansible\-collections/community\.docker/pull/17](https\://github\.com/ansible\-collections/community\.docker/pull/17)\)\.
+* docker\_image \- return docker build output \([https\://github\.com/ansible\-collections/community\.general/pull/805](https\://github\.com/ansible\-collections/community\.general/pull/805)\)\.
+* docker\_secret \- add a warning when the secret does not have an <code>ansible\_key</code> label but the <code>force</code> parameter is not set \([https\://github\.com/ansible\-collections/community\.docker/issues/30](https\://github\.com/ansible\-collections/community\.docker/issues/30)\, [https\://github\.com/ansible\-collections/community\.docker/pull/31](https\://github\.com/ansible\-collections/community\.docker/pull/31)\)\.
+
+<a id="v0-1-0"></a>
+## v0\.1\.0
+
+<a id="release-summary-56"></a>
+### Release Summary
+
+The <code>community\.docker</code> continues the work on the Ansible docker modules and plugins from their state in <code>community\.general</code> 1\.2\.0\. The changes listed here are thus relative to the modules and plugins <code>community\.general\.docker\*</code>\.
+
+All deprecation removals planned for <code>community\.general</code> 2\.0\.0 have been applied\. All deprecation removals scheduled for <code>community\.general</code> 3\.0\.0 have been re\-scheduled for <code>community\.docker</code> 2\.0\.0\.
+
+<a id="minor-changes-28"></a>
+### Minor Changes
+
+* docker\_container \- now supports the <code>device\_requests</code> option\, which allows to request additional resources such as GPUs \([https\://github\.com/ansible/ansible/issues/65748](https\://github\.com/ansible/ansible/issues/65748)\, [https\://github\.com/ansible\-collections/community\.general/pull/1119](https\://github\.com/ansible\-collections/community\.general/pull/1119)\)\.
+
+<a id="removed-features-previously-deprecated-2"></a>
+### Removed Features \(previously deprecated\)
+
+* docker\_container \- no longer returns <code>ansible\_facts</code> \([https\://github\.com/ansible\-collections/community\.docker/pull/1](https\://github\.com/ansible\-collections/community\.docker/pull/1)\)\.
+* docker\_container \- the default of <code>networks\_cli\_compatible</code> changed to <code>true</code> \([https\://github\.com/ansible\-collections/community\.docker/pull/1](https\://github\.com/ansible\-collections/community\.docker/pull/1)\)\.
+* docker\_container \- the unused option <code>trust\_image\_content</code> has been removed \([https\://github\.com/ansible\-collections/community\.docker/pull/1](https\://github\.com/ansible\-collections/community\.docker/pull/1)\)\.
+* docker\_image \- <code>state\=build</code> has been removed\. Use <code>present</code> instead \([https\://github\.com/ansible\-collections/community\.docker/pull/1](https\://github\.com/ansible\-collections/community\.docker/pull/1)\)\.
+* docker\_image \- the <code>container\_limits</code>\, <code>dockerfile</code>\, <code>http\_timeout</code>\, <code>nocache</code>\, <code>rm</code>\, <code>path</code>\, <code>buildargs</code>\, <code>pull</code> have been removed\. Use the corresponding suboptions of <code>build</code> instead \([https\://github\.com/ansible\-collections/community\.docker/pull/1](https\://github\.com/ansible\-collections/community\.docker/pull/1)\)\.
+* docker\_image \- the <code>force</code> option has been removed\. Use the more specific <code>force\_\*</code> options instead \([https\://github\.com/ansible\-collections/community\.docker/pull/1](https\://github\.com/ansible\-collections/community\.docker/pull/1)\)\.
+* docker\_image \- the <code>source</code> option is now mandatory \([https\://github\.com/ansible\-collections/community\.docker/pull/1](https\://github\.com/ansible\-collections/community\.docker/pull/1)\)\.
+* docker\_image \- the <code>use\_tls</code> option has been removed\. Use <code>tls</code> and <code>validate\_certs</code> instead \([https\://github\.com/ansible\-collections/community\.docker/pull/1](https\://github\.com/ansible\-collections/community\.docker/pull/1)\)\.
+* docker\_image \- the default of the <code>build\.pull</code> option changed to <code>false</code> \([https\://github\.com/ansible\-collections/community\.docker/pull/1](https\://github\.com/ansible\-collections/community\.docker/pull/1)\)\.
+* docker\_image\_facts \- this alias is on longer available\, use <code>docker\_image\_info</code> instead \([https\://github\.com/ansible\-collections/community\.docker/pull/1](https\://github\.com/ansible\-collections/community\.docker/pull/1)\)\.
+* docker\_network \- no longer returns <code>ansible\_facts</code> \([https\://github\.com/ansible\-collections/community\.docker/pull/1](https\://github\.com/ansible\-collections/community\.docker/pull/1)\)\.
+* docker\_network \- the <code>ipam\_options</code> option has been removed\. Use <code>ipam\_config</code> instead \([https\://github\.com/ansible\-collections/community\.docker/pull/1](https\://github\.com/ansible\-collections/community\.docker/pull/1)\)\.
+* docker\_service \- no longer returns <code>ansible\_facts</code> \([https\://github\.com/ansible\-collections/community\.docker/pull/1](https\://github\.com/ansible\-collections/community\.docker/pull/1)\)\.
+* docker\_swarm \- <code>state\=inspect</code> has been removed\. Use <code>docker\_swarm\_info</code> instead \([https\://github\.com/ansible\-collections/community\.docker/pull/1](https\://github\.com/ansible\-collections/community\.docker/pull/1)\)\.
+* docker\_swarm\_service \- the <code>constraints</code> option has been removed\. Use <code>placement\.constraints</code> instead \([https\://github\.com/ansible\-collections/community\.docker/pull/1](https\://github\.com/ansible\-collections/community\.docker/pull/1)\)\.
+* docker\_swarm\_service \- the <code>limit\_cpu</code> and <code>limit\_memory</code> options has been removed\. Use the corresponding suboptions in <code>limits</code> instead \([https\://github\.com/ansible\-collections/community\.docker/pull/1](https\://github\.com/ansible\-collections/community\.docker/pull/1)\)\.
+* docker\_swarm\_service \- the <code>log\_driver</code> and <code>log\_driver\_options</code> options has been removed\. Use the corresponding suboptions in <code>logging</code> instead \([https\://github\.com/ansible\-collections/community\.docker/pull/1](https\://github\.com/ansible\-collections/community\.docker/pull/1)\)\.
+* docker\_swarm\_service \- the <code>reserve\_cpu</code> and <code>reserve\_memory</code> options has been removed\. Use the corresponding suboptions in <code>reservations</code> instead \([https\://github\.com/ansible\-collections/community\.docker/pull/1](https\://github\.com/ansible\-collections/community\.docker/pull/1)\)\.
+* docker\_swarm\_service \- the <code>restart\_policy</code>\, <code>restart\_policy\_attempts</code>\, <code>restart\_policy\_delay</code> and <code>restart\_policy\_window</code> options has been removed\. Use the corresponding suboptions in <code>restart\_config</code> instead \([https\://github\.com/ansible\-collections/community\.docker/pull/1](https\://github\.com/ansible\-collections/community\.docker/pull/1)\)\.
+* docker\_swarm\_service \- the <code>update\_delay</code>\, <code>update\_parallelism</code>\, <code>update\_failure\_action</code>\, <code>update\_monitor</code>\, <code>update\_max\_failure\_ratio</code> and <code>update\_order</code> options has been removed\. Use the corresponding suboptions in <code>update\_config</code> instead \([https\://github\.com/ansible\-collections/community\.docker/pull/1](https\://github\.com/ansible\-collections/community\.docker/pull/1)\)\.
+* docker\_volume \- no longer returns <code>ansible\_facts</code> \([https\://github\.com/ansible\-collections/community\.docker/pull/1](https\://github\.com/ansible\-collections/community\.docker/pull/1)\)\.
+* docker\_volume \- the <code>force</code> option has been removed\. Use <code>recreate</code> instead \([https\://github\.com/ansible\-collections/community\.docker/pull/1](https\://github\.com/ansible\-collections/community\.docker/pull/1)\)\.
+
+<a id="bugfixes-43"></a>
+### Bugfixes
+
+* docker\_login \- fix internal config file storage to handle credentials for more than one registry \([https\://github\.com/ansible\-collections/community\.general/issues/1117](https\://github\.com/ansible\-collections/community\.general/issues/1117)\)\.
diff --git a/ansible_collections/community/docker/CHANGELOG.md.license b/ansible_collections/community/docker/CHANGELOG.md.license
new file mode 100644
index 000000000..edff8c768
--- /dev/null
+++ b/ansible_collections/community/docker/CHANGELOG.md.license
@@ -0,0 +1,3 @@
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
+SPDX-FileCopyrightText: Ansible Project
diff --git a/ansible_collections/community/docker/CHANGELOG.rst b/ansible_collections/community/docker/CHANGELOG.rst
index fb15fe36a..74e43714e 100644
--- a/ansible_collections/community/docker/CHANGELOG.rst
+++ b/ansible_collections/community/docker/CHANGELOG.rst
@@ -4,6 +4,210 @@ Docker Community Collection Release Notes
.. contents:: Topics
+v3.8.1
+======
+
+Release Summary
+---------------
+
+Bugfix release
+
+Security Fixes
+--------------
+
+- docker_containers, docker_machine, and docker_swarm inventory plugins - make sure all data received from the Docker daemon / Docker machine is marked as unsafe, so remote code execution by obtaining texts that can be evaluated as templates is not possible (https://www.die-welt.net/2024/03/remote-code-execution-in-ansible-dynamic-inventory-plugins/, https://github.com/ansible-collections/community.docker/pull/815).
+
+Bugfixes
+--------
+
+- docker_compose_v2 - do not fail when non-fatal errors occur. This can happen when pulling an image fails, but then the image can be built for another service. Docker Compose emits an error in that case, but ``docker compose up`` still completes successfully (https://github.com/ansible-collections/community.docker/issues/807, https://github.com/ansible-collections/community.docker/pull/810, https://github.com/ansible-collections/community.docker/pull/811).
+- docker_compose_v2* modules - correctly parse ``Warning`` events emitted by Docker Compose (https://github.com/ansible-collections/community.docker/issues/807, https://github.com/ansible-collections/community.docker/pull/811).
+- docker_compose_v2* modules - parse ``logfmt`` warnings emitted by Docker Compose (https://github.com/ansible-collections/community.docker/issues/787, https://github.com/ansible-collections/community.docker/pull/811).
+- docker_compose_v2_pull - fixing idempotence by checking actual pull progress events instead of service-level pull request when ``policy=always``. This stops the module from reporting ``changed=true`` if no actual change happened when pulling. In check mode, it has to assume that a change happens though (https://github.com/ansible-collections/community.docker/issues/813, https://github.com/ansible-collections/community.docker/pull/814).
+
+v3.8.0
+======
+
+Release Summary
+---------------
+
+Bugfix and feature release.
+
+Minor Changes
+-------------
+
+- docker_compose_v2 - allow to wait until containers are running/health when running ``docker compose up`` with the new ``wait`` option (https://github.com/ansible-collections/community.docker/issues/794, https://github.com/ansible-collections/community.docker/pull/796).
+- docker_container - the ``pull_check_mode_behavior`` option now allows to control the module's behavior in check mode when ``pull=always`` (https://github.com/ansible-collections/community.docker/issues/792, https://github.com/ansible-collections/community.docker/pull/797).
+- docker_container - the ``pull`` option now accepts the three values ``never``, ``missing_image`` (default), and ``never``, next to the previously valid values ``true`` (equivalent to ``always``) and ``false`` (equivalent to ``missing_image``). This allows the equivalent to ``--pull=never`` from the Docker command line (https://github.com/ansible-collections/community.docker/issues/783, https://github.com/ansible-collections/community.docker/pull/797).
+
+Bugfixes
+--------
+
+- docker_compose_v2 - do not consider a ``Waiting`` event as an action/change (https://github.com/ansible-collections/community.docker/pull/804).
+- docker_compose_v2 - do not treat service-level pull events as changes to avoid incorrect ``changed=true`` return value of ``pull=always`` (https://github.com/ansible-collections/community.docker/issues/802, https://github.com/ansible-collections/community.docker/pull/803).
+- docker_compose_v2, docker_compose_v2_pull - fix parsing of pull messages for Docker Compose 2.20.0 (https://github.com/ansible-collections/community.docker/issues/785, https://github.com/ansible-collections/community.docker/pull/786).
+
+v3.7.0
+======
+
+Release Summary
+---------------
+
+Bugfix and feature release.
+
+Minor Changes
+-------------
+
+- docker_compose_v2 - add ``scale`` option to allow to explicitly scale services (https://github.com/ansible-collections/community.docker/pull/776).
+- docker_compose_v2, docker_compose_v2_pull - support ``files`` parameter to specify multiple Compose files (https://github.com/ansible-collections/community.docker/issues/772, https://github.com/ansible-collections/community.docker/pull/775).
+
+Bugfixes
+--------
+
+- docker_compose_v2 - properly parse dry-run build events from ``stderr`` (https://github.com/ansible-collections/community.docker/issues/778, https://github.com/ansible-collections/community.docker/pull/779).
+- docker_compose_v2_pull - the module was documented as part of the ``community.docker.docker`` action group, but was not actually part of it. That has now been fixed (https://github.com/ansible-collections/community.docker/pull/773).
+
+New Modules
+-----------
+
+- docker_image_export - Export (archive) Docker images
+
+v3.6.0
+======
+
+Release Summary
+---------------
+
+Bugfix and feature release.
+
+The collection now includes a bunch of new ``docker_image_*`` modules that move features out of the
+rather complex ``docker_image`` module. These new modules are easier to use and can better declare whether
+they support check mode, diff mode, or none of them.
+
+This version also features modules that support the Docker CLI plugins ``buildx`` and ``compose``.
+The ``docker_image_build`` module uses the ``docker buildx`` command under the hood, and the ``docker_compose_v2``
+and ``docker_compose_v2_pull`` modules uses the ``docker compose`` command. All these modules use the Docker CLI
+instead of directly talking to the API. The modules support mostly the same interface as the API based modules,
+so the main difference is that instead of some Python requirements, they depend on the Docker CLI tool ``docker``.
+
+Major Changes
+-------------
+
+- The ``community.docker`` collection now depends on the ``community.library_inventory_filtering_v1`` collection. This utility collection provides host filtering functionality for inventory plugins. If you use the Ansible community package, both collections are included and you do not have to do anything special. If you install the collection with ``ansible-galaxy collection install``, it will be installed automatically. If you install the collection by copying the files of the collection to a place where ansible-core can find it, for example by cloning the git repository, you need to make sure that you also have to install the dependency if you are using the inventory plugins (https://github.com/ansible-collections/community.docker/pull/698).
+
+Minor Changes
+-------------
+
+- The ``ca_cert`` option available to almost all modules and plugins has been renamed to ``ca_path``. The name ``ca_path`` is also used for similar options in ansible-core and other collections. The old name has been added as an alias and can still be used (https://github.com/ansible-collections/community.docker/pull/744).
+- The ``docker_stack*`` modules now use the common CLI-based module code added for the ``docker_image_build`` and ``docker_compose_v2`` modules. This means that the modules now have various more configuration options with respect to talking to the Docker Daemon, and now also are part of the ``community.docker.docker`` and ``docker`` module default groups (https://github.com/ansible-collections/community.docker/pull/745).
+- docker_container - add ``networks[].mac_address`` option for Docker API 1.44+. Note that Docker API 1.44 no longer uses the global ``mac_address`` option, this new option is the only way to set the MAC address for a container (https://github.com/ansible-collections/community.docker/pull/763).
+- docker_image - allow to specify labels and ``/dev/shm`` size when building images (https://github.com/ansible-collections/community.docker/issues/726, https://github.com/ansible-collections/community.docker/pull/727).
+- docker_image - allow to specify memory size and swap memory size in other units than bytes (https://github.com/ansible-collections/community.docker/pull/727).
+- inventory plugins - add ``filter`` option which allows to include and exclude hosts based on Jinja2 conditions (https://github.com/ansible-collections/community.docker/pull/698, https://github.com/ansible-collections/community.docker/issues/610).
+
+Bugfixes
+--------
+
+- Use ``unix:///var/run/docker.sock`` instead of the legacy ``unix://var/run/docker.sock`` as default for ``docker_host`` (https://github.com/ansible-collections/community.docker/pull/736).
+- docker_image - fix archiving idempotency with Docker API 1.44 or later (https://github.com/ansible-collections/community.docker/pull/765).
+
+New Modules
+-----------
+
+- docker_compose_v2 - Manage multi-container Docker applications with Docker Compose CLI plugin
+- docker_compose_v2_pull - Pull a Docker compose project
+- docker_image_build - Build Docker images using Docker buildx
+- docker_image_pull - Pull Docker images from registries
+- docker_image_push - Push Docker images to registries
+- docker_image_remove - Remove Docker images
+- docker_image_tag - Tag Docker images with new names and/or tags
+
+v3.5.0
+======
+
+Release Summary
+---------------
+
+Bugfix and feature release.
+
+Minor Changes
+-------------
+
+- docker_container - implement better ``platform`` string comparisons to improve idempotency (https://github.com/ansible-collections/community.docker/issues/654, https://github.com/ansible-collections/community.docker/pull/705).
+- docker_container - internal refactorings which allow comparisons to use more information like details of the current image or the Docker host config (https://github.com/ansible-collections/community.docker/pull/713).
+
+Deprecated Features
+-------------------
+
+- docker_container - the default ``ignore`` for the ``image_name_mismatch`` parameter has been deprecated and will switch to ``recreate`` in community.docker 4.0.0. A deprecation warning will be printed in situations where the default value is used and where a behavior would change once the default changes (https://github.com/ansible-collections/community.docker/pull/703).
+
+Bugfixes
+--------
+
+- modules and plugins using the Docker SDK for Python - remove ``ssl_version`` from the parameters passed to Docker SDK for Python 7.0.0+. Explicitly fail with a nicer error message if it was explicitly set in this case (https://github.com/ansible-collections/community.docker/pull/715).
+- modules and plugins using the Docker SDK for Python - remove ``tls_hostname`` from the parameters passed to Docker SDK for Python 7.0.0+. Explicitly fail with a nicer error message if it was explicitly set in this case (https://github.com/ansible-collections/community.docker/pull/721).
+- vendored Docker SDK for Python - avoid passing on ``ssl_version`` and ``tls_hostname`` if they were not provided by the user. Remove dead code. (https://github.com/ansible-collections/community.docker/pull/722).
+
+v3.4.11
+=======
+
+Release Summary
+---------------
+
+Bugfix release.
+
+Bugfixes
+--------
+
+- docker_volume - fix crash caused by accessing an empty dictionary. The ``has_different_config()`` was raising an ``AttributeError`` because the ``self.existing_volume["Labels"]`` dictionary was ``None`` (https://github.com/ansible-collections/community.docker/pull/702).
+
+v3.4.10
+=======
+
+Release Summary
+---------------
+
+Bugfix release.
+
+Bugfixes
+--------
+
+- docker_swarm - make init and join operations work again with Docker SDK for Python before 4.0.0 (https://github.com/ansible-collections/community.docker/issues/695, https://github.com/ansible-collections/community.docker/pull/696).
+
+v3.4.9
+======
+
+Release Summary
+---------------
+
+Maintenance release with updated documentation and vendored Docker SDK for Python code.
+
+Bugfixes
+--------
+
+- vendored Docker SDK for Python code - cherry-pick changes from the Docker SDK for Python code to align code. These changes should not affect the parts used by the collection's code (https://github.com/ansible-collections/community.docker/pull/694).
+
+v3.4.8
+======
+
+Release Summary
+---------------
+
+Maintenance release with updated documentation.
+
+From this version on, community.docker is using the new `Ansible semantic markup
+<https://docs.ansible.com/ansible/devel/dev_guide/developing_modules_documenting.html#semantic-markup-within-module-documentation>`__
+in its documentation. If you look at documentation with the ansible-doc CLI tool
+from ansible-core before 2.15, please note that it does not render the markup
+correctly. You should be still able to read it in most cases, but you need
+ansible-core 2.15 or later to see it as it is intended. Alternatively you can
+look at `the devel docsite <https://docs.ansible.com/ansible/devel/collections/community/docker/>`__
+for the rendered HTML version of the documentation of the latest release.
+
+Known Issues
+------------
+
+- Ansible markup will show up in raw form on ansible-doc text output for ansible-core before 2.15. If you have trouble deciphering the documentation markup, please upgrade to ansible-core 2.15 (or newer), or read the HTML documentation on https://docs.ansible.com/ansible/devel/collections/community/docker/.
v3.4.7
======
@@ -300,7 +504,7 @@ Minor Changes
- docker_container - allow to specify ``platform`` (https://github.com/ansible-collections/community.docker/issues/123, https://github.com/ansible-collections/community.docker/pull/426).
- modules and plugins communicating directly with the Docker daemon - improve default TLS version selection for Python 3.6 and newer. This is only a change relative to older community.docker 3.0.0 pre-releases or with respect to Docker SDK for Python < 6.0.0. Docker SDK for Python 6.0.0 will also include this change (https://github.com/ansible-collections/community.docker/pull/434).
- modules and plugins communicating directly with the Docker daemon - simplify use of helper function that was removed in Docker SDK for Python to find executables (https://github.com/ansible-collections/community.docker/pull/438).
-- socker_handler and socket_helper module utils - improve Python forward compatibilty, create helper functions for file blocking/unblocking (https://github.com/ansible-collections/community.docker/pull/415).
+- socker_handler and socket_helper module utils - improve Python forward compatibility, create helper functions for file blocking/unblocking (https://github.com/ansible-collections/community.docker/pull/415).
Breaking Changes / Porting Guide
--------------------------------
@@ -493,7 +697,7 @@ Minor Changes
Bugfixes
--------
-- docker_container, docker_image - adjust image finding code to pecularities of ``podman-docker``'s API emulation when Docker short names like ``redis`` are used (https://github.com/ansible-collections/community.docker/issues/292).
+- docker_container, docker_image - adjust image finding code to peculiarities of ``podman-docker``'s API emulation when Docker short names like ``redis`` are used (https://github.com/ansible-collections/community.docker/issues/292).
v2.1.1
======
@@ -542,7 +746,7 @@ Bugfixes
- docker_api connection plugin - avoid passing an unnecessary argument to a Docker SDK for Python call that is only supported by version 3.0.0 or later (https://github.com/ansible-collections/community.docker/pull/243).
- docker_container_exec - ``chdir`` is only supported since Docker SDK for Python 3.0.0. Make sure that this option can only use when 3.0.0 or later is installed, and prevent passing this parameter on when ``chdir`` is not provided to this module (https://github.com/ansible-collections/community.docker/pull/243, https://github.com/ansible-collections/community.docker/issues/242).
-- nsenter connection plugin - ensure the ``nsenter_pid`` option is retrieved in ``_connect`` instead of ``__init__`` to prevent a crasher due to bad initialization order (https://github.com/ansible-collections/community.docker/pull/249).
+- nsenter connection plugin - ensure the ``nsenter_pid`` option is retrieved in ``_connect`` instead of ``__init__`` to prevent a crash due to bad initialization order (https://github.com/ansible-collections/community.docker/pull/249).
- nsenter connection plugin - replace the use of ``--all-namespaces`` with specific namespaces to support compatibility with Busybox nsenter (used on, for example, Alpine containers) (https://github.com/ansible-collections/community.docker/pull/249).
v2.0.1
@@ -792,9 +996,9 @@ Bugfixes
- docker_container - fix healthcheck disabling idempotency issue with strict comparison (https://github.com/ansible-collections/community.docker/issues/85).
- docker_image - prevent module failure when removing image that is removed between inspection and removal (https://github.com/ansible-collections/community.docker/pull/87).
-- docker_image - prevent module failure when removing non-existant image by ID (https://github.com/ansible-collections/community.docker/pull/87).
+- docker_image - prevent module failure when removing non-existent image by ID (https://github.com/ansible-collections/community.docker/pull/87).
- docker_image_info - prevent module failure when image vanishes between listing and inspection (https://github.com/ansible-collections/community.docker/pull/87).
-- docker_image_info - prevent module failure when querying non-existant image by ID (https://github.com/ansible-collections/community.docker/pull/87).
+- docker_image_info - prevent module failure when querying non-existent image by ID (https://github.com/ansible-collections/community.docker/pull/87).
New Modules
-----------
@@ -913,7 +1117,6 @@ Release Summary
This is the first production (non-prerelease) release of ``community.docker``.
-
Minor Changes
-------------
@@ -931,7 +1134,6 @@ The ``community.docker`` continues the work on the Ansible docker modules and pl
All deprecation removals planned for ``community.general`` 2.0.0 have been applied. All deprecation removals scheduled for ``community.general`` 3.0.0 have been re-scheduled for ``community.docker`` 2.0.0.
-
Minor Changes
-------------
@@ -949,7 +1151,7 @@ Removed Features (previously deprecated)
- docker_image - the ``source`` option is now mandatory (https://github.com/ansible-collections/community.docker/pull/1).
- docker_image - the ``use_tls`` option has been removed. Use ``tls`` and ``validate_certs`` instead (https://github.com/ansible-collections/community.docker/pull/1).
- docker_image - the default of the ``build.pull`` option changed to ``false`` (https://github.com/ansible-collections/community.docker/pull/1).
-- docker_image_facts - this alias is on longer availabe, use ``docker_image_info`` instead (https://github.com/ansible-collections/community.docker/pull/1).
+- docker_image_facts - this alias is on longer available, use ``docker_image_info`` instead (https://github.com/ansible-collections/community.docker/pull/1).
- docker_network - no longer returns ``ansible_facts`` (https://github.com/ansible-collections/community.docker/pull/1).
- docker_network - the ``ipam_options`` option has been removed. Use ``ipam_config`` instead (https://github.com/ansible-collections/community.docker/pull/1).
- docker_service - no longer returns ``ansible_facts`` (https://github.com/ansible-collections/community.docker/pull/1).
diff --git a/ansible_collections/community/docker/FILES.json b/ansible_collections/community/docker/FILES.json
index edc83e6f7..9797df497 100644
--- a/ansible_collections/community/docker/FILES.json
+++ b/ansible_collections/community/docker/FILES.json
@@ -109,7 +109,7 @@
"name": ".azure-pipelines/azure-pipelines.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ea4b811e8060d4717b92e76a372e0840fbc617f12958516a4360d773903dc028",
+ "chksum_sha256": "4083b64eda9b5fdcbf472007a0a8edc921d46d7d2132b870ccddfc04b72aede1",
"format": 1
},
{
@@ -130,35 +130,42 @@
"name": ".github/workflows/ansible-test.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4131ea9bc006d31c7c0dec53330c54af588c2c82ec18ebd0aa1db9b7a1256a01",
+ "chksum_sha256": "c1b9c8b20850a848ebb8c91cdb9382cc3e521658fb2bbe1bb62f6357565e044d",
"format": 1
},
{
"name": ".github/workflows/docs-pr.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "754a357ab5c3a5fd1dd782ade11220decb76a24bfb4452a9a15d9a7fec1f863e",
+ "chksum_sha256": "b42710de9bd387cfe9475eb546b21ee2c20af7c062b2601f8ae94b4b3255d313",
"format": 1
},
{
"name": ".github/workflows/docs-push.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8e50964ae57efe54009281fbd8f6f6f3bfa493821a5da63c08635afed76fc8f2",
+ "chksum_sha256": "c6bf8a08ff0faa3aced5e10453305f2d50df702833b6983c333886a651caa2b7",
"format": 1
},
{
"name": ".github/workflows/ee.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "16c3016cc7ac13c3523fd5235253e5894d563f6f002e7724fb1e19a7687f8051",
+ "chksum_sha256": "f7bad2dd69eaeb6413cc12e92a6bf9c962ed705563a8803a09c76669c39ca501",
+ "format": 1
+ },
+ {
+ "name": ".github/workflows/import-galaxy.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "739c36223d6e0e6ccc98907c43cba53296e7b1ccd64a2d995c2ff21df4ab25a5",
"format": 1
},
{
"name": ".github/workflows/reuse.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e8a5666a792db2dbbb984d861032728af7523bd05eb64f72d5fe24d7888c4a85",
+ "chksum_sha256": "91fb4be801aaf7897a138f4774f1fa172291af4fcd9e1c7a3a5e3830236305fe",
"format": 1
},
{
@@ -207,7 +214,7 @@
"name": "LICENSES/Apache-2.0.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f2f0b07fa5e492c11d27aa0d2f3f1a0e64b9d17f32d8aa489ae2af9609af33b2",
+ "chksum_sha256": "a88d15b80c84a53d3d94876d718db924f6e59bf5cbc6a9328415bb3c0269f963",
"format": 1
},
{
@@ -235,7 +242,7 @@
"name": "changelogs/changelog.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "61e7fce8a5851bb2137604e0a9197fd369cf5a6c909632cf177111ec82797d75",
+ "chksum_sha256": "78b978f9536ee113fed773101c478a20057167e348c8d5b6cdb77f44e62d9b6f",
"format": 1
},
{
@@ -249,7 +256,7 @@
"name": "changelogs/config.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e608bfe9368cd9a95e04b99ec78d74bd7c8e125cc715c059a1957bb32079c102",
+ "chksum_sha256": "89ca51ecae2759b4987976d346e16fa930be4a4e05062a1385764626e3aca951",
"format": 1
},
{
@@ -277,7 +284,14 @@
"name": "docs/docsite/rst/scenario_guide.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "11df82606883ecfa82952f141ed9c30ac31e07746dcd50edc53ca8dd3a360a2e",
+ "chksum_sha256": "b7460de972dad8dba6ffbaacd46a84f2b673a74e78f5eb3db617fd3eb574ba6d",
+ "format": 1
+ },
+ {
+ "name": "docs/docsite/config.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "a2d289e9f0e5f0151d1cd40963461f6427b69df33ba7dde69b950dc58912f016",
"format": 1
},
{
@@ -326,7 +340,7 @@
"name": "meta/runtime.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "036384152d6b46d0edefb1a12d1dfef3c85205511e5db3319d49d17fa342f97f",
+ "chksum_sha256": "edcb1bfa37eaf30f16b8a081dcd80ac6406972a894d4f3f5f7fd320e4f309c38",
"format": 1
},
{
@@ -347,7 +361,7 @@
"name": "plugins/action/docker_container_copy_into.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1c50124cc05fb7aece01e325768ce1683916f5c620545c6ff094756a3f58e29e",
+ "chksum_sha256": "e79dbc67466ae588344ddd74a79d508c859252cf76b71a918cf066ac39fb7de1",
"format": 1
},
{
@@ -361,21 +375,21 @@
"name": "plugins/connection/docker.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7b33a9616e9189aed4014f1869666bec5b788dba44385ecf3cbeed4e30f4ffe8",
+ "chksum_sha256": "499dc980904433196409bc04a10faf38801123c8a22871026037f4bad6d13bab",
"format": 1
},
{
"name": "plugins/connection/docker_api.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "989cc3489190aac86f45542c4b21888e5454eca9043f1776790b0824a6ad626e",
+ "chksum_sha256": "eb3275f36134a45b5acc0620f5b0b849c9cde8cf1975c7cd45b683d56e2e4258",
"format": 1
},
{
"name": "plugins/connection/nsenter.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8ca5d2af831451b5d3d38fcf237314b0d86f85bea38d589f91b249e7d5f34031",
+ "chksum_sha256": "2f246a2f8dcb35feb42d2a1d7f28ead845ae4854da097781489233f5a5920e94",
"format": 1
},
{
@@ -393,10 +407,17 @@
"format": 1
},
{
+ "name": "plugins/doc_fragments/compose_v2.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9e42aa81006fe5a72ef9713d008b616da75c6dbb0bc359ff892ced2885545166",
+ "format": 1
+ },
+ {
"name": "plugins/doc_fragments/docker.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f164958068db65e0d813835b35ea9b057c1f45cabaaa5e5e34d7b6b22b2e3ade",
+ "chksum_sha256": "89dae4973d0a843ba52d8ac81197045dcdc136df4ca685210efe815366dbb70f",
"format": 1
},
{
@@ -410,21 +431,21 @@
"name": "plugins/inventory/docker_containers.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2b00c2519a8e5698bc534d3e1b3ef6127e91bc9fa81192b64db2f0bea605c89d",
+ "chksum_sha256": "1d01e5f455339e704233d7df6597aae12be29a5fef4e6aef5fcb787cfb8030d2",
"format": 1
},
{
"name": "plugins/inventory/docker_machine.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "63788182b475bbb689919fa08b9753c3cba026937a6d7be2ee5238727d583e53",
+ "chksum_sha256": "559ab252a16a63dc14a344be1f90ee66f976d8f3927f83dda2b3657fea0c1078",
"format": 1
},
{
"name": "plugins/inventory/docker_swarm.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "94be597d342833b28bd4061b9faf061c0b04e7b1f0fedbbcc48458e90b27a918",
+ "chksum_sha256": "a01b5a62dffc44a43c42dfacff3ee1430d39c43c0d313a4289a12526bca33109",
"format": 1
},
{
@@ -452,7 +473,7 @@
"name": "plugins/module_utils/_api/api/client.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "957bfbb66512485e7b324be0c00e4c96a0db8a99f0d175732ee64ebc6fce29c6",
+ "chksum_sha256": "8554f7ce18d5be8e27c24585da9ca10eb9873fd3d190b1089908e11e64fcfdc1",
"format": 1
},
{
@@ -536,7 +557,7 @@
"name": "plugins/module_utils/_api/transport/ssladapter.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "44b20375c0f42347bd84f6e855d4a4042b5cf6e83f0f49199ea04cb8c6578130",
+ "chksum_sha256": "9280c24e44fb347c2f6075cc2ac6eb36d2ab68fda7aa95e00c987a9495343b9e",
"format": 1
},
{
@@ -620,14 +641,14 @@
"name": "plugins/module_utils/_api/utils/socket.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "87d46479caf0eb9214156b0bc10d9348171a3f96db3a9d2c6406b4e8f109c122",
+ "chksum_sha256": "58f5909c0bdbf63fbb0c09c89aeb3f8a1f9e8b22c071fd2c0c25e6bfce166d18",
"format": 1
},
{
"name": "plugins/module_utils/_api/utils/utils.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f11f1f6efa555721dcad3244256e97daaddf282e81d9a9a16683aa9d11ff1973",
+ "chksum_sha256": "951272b159d81117e35e73c6d67fce3ea9501b1edc6aace9580063a4a61936b4",
"format": 1
},
{
@@ -655,14 +676,14 @@
"name": "plugins/module_utils/_api/errors.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "36dcebce54b43306c9bd14c64786c14c9e91b60cdc60747f2d531861eb43d90a",
+ "chksum_sha256": "0c856e76224c2ff545de31cbba165bb09120bc276208c2f76ce4a62c0b027c36",
"format": 1
},
{
"name": "plugins/module_utils/_api/tls.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "23a55b15907f6d866d17f366af10e6efc0e618b207a53d3dd59ae2698cea384e",
+ "chksum_sha256": "f9f061aba4ca55a4649311b98b42e700e36b449a5f2ec117b470ef723050ad14",
"format": 1
},
{
@@ -676,21 +697,35 @@
"name": "plugins/module_utils/module_container/base.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ee59b15754a61eb80299496b9ff66b8724faa2cc62580a627ce0c3ea2a147a8e",
+ "chksum_sha256": "3ef56885b8746ef1ae068412cd9a608dcb83f5b7aa06670d5ae6216aa845a940",
"format": 1
},
{
"name": "plugins/module_utils/module_container/docker_api.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "158af3f302bad3889571eb688dd61d2c0c14f97806fdf73e6f02c445766c25e1",
+ "chksum_sha256": "2d0e757e6b3439e7445531b1be278c283e2a442747f86f51ef831739ddf158c5",
"format": 1
},
{
"name": "plugins/module_utils/module_container/module.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ec66e374d210e738d7aaea787d1bc42a547f7067acabeb6253f7fb0b8970dd18",
+ "chksum_sha256": "5bce434dccc5301efe29067d15a789513a2e70f3542e56eff0c32bc4dcc1ab36",
+ "format": 1
+ },
+ {
+ "name": "plugins/module_utils/_logfmt.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "83828f29e47da36c168e78a5ea7d17bf72fa20905e6678b6dbe1e445f3aa0f69",
+ "format": 1
+ },
+ {
+ "name": "plugins/module_utils/_platform.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "45b82a5a2cf3d9b279c5fa6e285cb91f783035abe888c0f1147ed4b427a81ac2",
"format": 1
},
{
@@ -704,14 +739,28 @@
"name": "plugins/module_utils/common.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "86b8ea61f7933baa3a681810ffbb49a28f45f4d71d09023b093093d96acde20e",
+ "chksum_sha256": "5de0831ed3a84d5a505424594ac264bd723f247a26a50bc32896b41083096fda",
"format": 1
},
{
"name": "plugins/module_utils/common_api.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3eded77a2c9e9987e6690f1bfb17b8ebaf8eb5aba712ae2d9417cce1a116e301",
+ "chksum_sha256": "1ee4abcab984e082d2336fed858ab787e538b6e2c25a9a446fde0fd4d6c73f81",
+ "format": 1
+ },
+ {
+ "name": "plugins/module_utils/common_cli.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0129c9ca85986f12989d754336d5897eadf0fcd3166f1ab89afca096963fbfd6",
+ "format": 1
+ },
+ {
+ "name": "plugins/module_utils/compose_v2.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "60698c26cc1f0b0394ebd9ed2451d45681844d44c79c32b0e2921193feebc29f",
"format": 1
},
{
@@ -725,7 +774,7 @@
"name": "plugins/module_utils/image_archive.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7c6784aecdfc14661d55b3ddef4e0c19e6a44bb0fecdbc514834c571716e8711",
+ "chksum_sha256": "26073983bafd86ccadb1f197f2a55188f208145db066bbc02ea9bf59aaf30085",
"format": 1
},
{
@@ -753,7 +802,7 @@
"name": "plugins/module_utils/util.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "36b3fed68a9a09ffe13fd31c72531f2428db92417f8b39d3a98b8914485c3a92",
+ "chksum_sha256": "cd9d4863ea58408543821688b7093aed25a1323109de82c13c8489f6cd45651a",
"format": 1
},
{
@@ -774,196 +823,252 @@
"name": "plugins/modules/current_container_facts.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f8859f459d86a9cea8acc478f6cca9d9afbdb8fdb3de67dd7c26b519e8266e5b",
+ "chksum_sha256": "6866839dd328f2c566de59dea1a826ec60cb9fa20c2639c520d16338d3a09839",
"format": 1
},
{
"name": "plugins/modules/docker_compose.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ca2ed4f1ab7e7b8950aeecc53368085068d46c12a19387eb6f830916cf899f69",
+ "chksum_sha256": "ae76fdb37a3517ffcdc50047d900d33a94a9c5e85dcc76ebdd1bbc6dfa9c3b8b",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/docker_compose_v2.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "237adfe9c0e33461e576fe78fb2c5f82b089e9df202fa9e61ca5ab4bc39d4282",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/docker_compose_v2_pull.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "16378b1ddf2c8914b0b9ec7adc4519f6b664787971ba46672b1ec05f593c1ca3",
"format": 1
},
{
"name": "plugins/modules/docker_config.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d332e43cf754184bcc99367c2b256408d60baeaad3b1f45eceef634748cd9eb5",
+ "chksum_sha256": "c0f87f95dcdd562d4dcb8d637377d2923eeb0946f255ff691d45dad1690f6aa1",
"format": 1
},
{
"name": "plugins/modules/docker_container.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e47b110ea04f3db21c4c84ac913d587191bf32c72d70f11819bca7a721135458",
+ "chksum_sha256": "20ff6513c8c1d81c477c58c1cbe943e383005bcf8c110cfb3b58f96240339da7",
"format": 1
},
{
"name": "plugins/modules/docker_container_copy_into.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "dfeac79e2e0e22a99815fce943475665427a528dffce4c9804e401eb5b735053",
+ "chksum_sha256": "249d80799d026e601bf5040b554708c933a2376bda27c43d668cc9258f8b5110",
"format": 1
},
{
"name": "plugins/modules/docker_container_exec.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e89910b315662391984fb98d93621c435c486899b3a2cb260a4459e0e544fe44",
+ "chksum_sha256": "088ebb7b7c11d7d7ee8a9e30a9813dc7acfd0bac32782a8a128ac3fe613ab797",
"format": 1
},
{
"name": "plugins/modules/docker_container_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cf3a704310a9a0ac7d02af0fc9b07cfb9d3ce65cdab9ba597161f25bcb493c33",
+ "chksum_sha256": "35e0e238679d4354f9de4c1d6dc2ac3e0862cf672946d78ef0cc4a7556ab0f62",
"format": 1
},
{
"name": "plugins/modules/docker_host_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fc1571ef765c93fd2f80e20b687ddab8360f482f0630021f5755f8ea8529d116",
+ "chksum_sha256": "7dd379926353d259ccccf5030a0c96549ebe8ec3be98e491610ba6b331f7888e",
"format": 1
},
{
"name": "plugins/modules/docker_image.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6e5fe1c3bdef812f6e58d89084958948d2a77000b2316090e4309035e95635b1",
+ "chksum_sha256": "537490ed518e8224d115fe315b7240a715b0d3e8b6d004b79e8966e1277c817d",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/docker_image_build.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0c56e7842f5681b3ca5081ee263fc33ee2a677ce07d19407c04be97f66352720",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/docker_image_export.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "7067813390e980633abb6e6dac5f5465999cc14edd128098167ca4866bab3af2",
"format": 1
},
{
"name": "plugins/modules/docker_image_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cee8e231c2ddc6330958d95c830a523cfb5663284b2fe7f9a8b9f43948037df5",
+ "chksum_sha256": "559cca032685ee95c35d6035a7cd3f618318c42f26785f1a0ff588c6f7951468",
"format": 1
},
{
"name": "plugins/modules/docker_image_load.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "dc180605dc910fedd7c3e9b75ce91c2de46a3eb6df014f7666345c074f621f8f",
+ "chksum_sha256": "16169307ec8cfa3787eadfe2fd33c818134ba9ef11e964ea4b57f0c73d695196",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/docker_image_pull.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9e9f67a89f12825306cd7c4a5ad7e88d7a37e3c61441f47a3845d254eea40742",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/docker_image_push.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "268edc32e25119bd5325af3d9ed30aa0c9e0086e787243c99930f9987189fb9a",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/docker_image_remove.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0041c6479f43faa0a47c6935202a6b1fbbe3c149753a2e1f5d5d93c0a0588420",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/docker_image_tag.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "44167b07eef7079178b8b386407d11c327107d41a38957301179da71a8825b65",
"format": 1
},
{
"name": "plugins/modules/docker_login.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c1f09ecf54b177ba5830773fdfb7092cf54ab207f33522a603201a4fce94a42b",
+ "chksum_sha256": "2d03eca55c8d126807cff8d560211dd7cd06aedd84d1c8af2342afc96ce23a84",
"format": 1
},
{
"name": "plugins/modules/docker_network.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "03cb04a8a13c033237eddc478b5944e32a571ae67cde6004b923e08083bdf1ca",
+ "chksum_sha256": "d8f6a678e09487346b7ab007dcef3d8c5cb494ede7ccadc43be42c205902de40",
"format": 1
},
{
"name": "plugins/modules/docker_network_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3a67bff7fa7f1a2f0d55b5c34187699b0794e67123bfdb86bc3da50a9296e413",
+ "chksum_sha256": "2df4c46a27a1a7f4faa016db358677a3885ec854592a0416e051a33a83d99d39",
"format": 1
},
{
"name": "plugins/modules/docker_node.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "98e369f1bcf1caded3d21f38724c6187a7705a0bae647a57edade757e2679ec8",
+ "chksum_sha256": "6f05002632112751e1f8f46b26a1c7faf2285fce01bd2ce836077a222f0e01bc",
"format": 1
},
{
"name": "plugins/modules/docker_node_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5875c7b1b2a5f080277de528ffb22f70540ea19d3a25583b25cc6b1046573517",
+ "chksum_sha256": "780820410f8eb564f8b858f61aa33fbc4eaee4919719df1f7c75b4c9629a67e7",
"format": 1
},
{
"name": "plugins/modules/docker_plugin.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "39ba800ce74a9d7740abe244464fe1fac4c66a7e10592930f8f2ce3de40dc566",
+ "chksum_sha256": "0e51993a3f5ba1e1d0d8067e7d4dacaac4a4031c6fc7431a847c4f69a6a7f556",
"format": 1
},
{
"name": "plugins/modules/docker_prune.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9315eb36ddab089ddcceba06cf8c70faf3a4d0d77ecce0d9a133716ee4bc1dc8",
+ "chksum_sha256": "83107f0243ee1c6706686da15f65e8aa2e5fc96e0d346934210557a97ca38292",
"format": 1
},
{
"name": "plugins/modules/docker_secret.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fe578e93cd122a530a0b1880aaaeb6286ea06c9ce7d752345094a3ea0f63d00f",
+ "chksum_sha256": "c68ef5309cbfd19cc754f80301d57f8ed71c2b758073e31e16cf84e7f6110707",
"format": 1
},
{
"name": "plugins/modules/docker_stack.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7b0ee4740452db238cc6799510b3fccd6e06fb933b7053117bf62dccedc28f66",
+ "chksum_sha256": "047d1241a93d534ece032531376bca777d4b768846d0a50e443ffc2a50401e32",
"format": 1
},
{
"name": "plugins/modules/docker_stack_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5c8ad7b526a9903d4c334225e81c1b794f72927e7ca1bd318400f6f4d1a35a23",
+ "chksum_sha256": "cbe62b6ff998c1f3c5e8c88e2aef77002993c0b5e67dad10413d618eb3984635",
"format": 1
},
{
"name": "plugins/modules/docker_stack_task_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "34cdb57ca28f881e6069bb9f84f452c5f3b340f6f19afb09e3b7b8ebb918379a",
+ "chksum_sha256": "83fecae51c22fca463f96318f2e2c07d593adcfd84eccd043a7c1abddb988a64",
"format": 1
},
{
"name": "plugins/modules/docker_swarm.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b6b384c90ee60b63b166485bf25aebf00d2c1111a5857a049e2ce1685aad9d12",
+ "chksum_sha256": "326f01d8464ff007981b53b8b1836c3585390f7495ab0105509b4a78f676c479",
"format": 1
},
{
"name": "plugins/modules/docker_swarm_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cc3b2471a4d4154fc8e0f07f6719b0b3b0b036f53d46dc17b3b0ecacdf975dbb",
+ "chksum_sha256": "05bcd2c3e0b417f7ee328732c6c4afba2dba2400a83e5149a6af989eeda493fe",
"format": 1
},
{
"name": "plugins/modules/docker_swarm_service.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d445e55603e0c3f01d0d7b4a976cda370b0ef1fdcd0afdcc23bd400bcbabd1db",
+ "chksum_sha256": "a123422ef5020a31efc1f19872e62bd1374af3352640a62df3f01dc8a4c0a3df",
"format": 1
},
{
"name": "plugins/modules/docker_swarm_service_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a67a4a18d2482ce4a624d93351c6d013780351e531eeed4a8507e0d03b871a4b",
+ "chksum_sha256": "11ab44415df1311c23916d9e1a84b83b54e06077cbd01f22989acc0d23769fec",
"format": 1
},
{
"name": "plugins/modules/docker_volume.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1d59a481f217bd40f4b9188b540490285a7bdedd0a6e830b5942f661006630dd",
+ "chksum_sha256": "763910fd648b74f32a1a5acfa7d1c5c19ebc2cf473fe57856133b76c93759b87",
"format": 1
},
{
"name": "plugins/modules/docker_volume_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e6727d7a596134f2f4f7116e42081ad78bf41d7c72df2e4fc87ea772f138c769",
+ "chksum_sha256": "b1b8c2614b7d3746f5ac2c4e7f378fcd7912217a8171638c33e697b7889a173d",
"format": 1
},
{
@@ -1208,7 +1313,7 @@
"name": "tests/integration/targets/connection_docker_api/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0b6cbfff0581c89d9114e38c9c9d6a5f688dbaa924e60b29e8d774eb1203c2ed",
+ "chksum_sha256": "6fbc5e2468efd3c9de72d5eb1061a59b4c3ac7274c4857be455efcc35e8610d5",
"format": 1
},
{
@@ -1229,7 +1334,7 @@
"name": "tests/integration/targets/connection_docker_api/setup.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "90fca01e7a2276ac2616ca60026535d3996b4de111479473d7471a9ceaf22be1",
+ "chksum_sha256": "d7287d44d5223a9afb55417cb29ffdd2fb06568dd6a817274b82578082ae3176",
"format": 1
},
{
@@ -1278,7 +1383,7 @@
"name": "tests/integration/targets/connection_nsenter/runme.sh",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7f6a528c5f20c98919cf8cb93d1487f05844c9f5eab75621cc7a294d67177a08",
+ "chksum_sha256": "6c7656f5c6e2ce7d59a76527b1dfe599dbf79325e32f23b1ef7fbd478c418c79",
"format": 1
},
{
@@ -1362,7 +1467,7 @@
"name": "tests/integration/targets/docker_compose/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "47bfd6330a8616b7324f5a956839b953d844ed07b327c78a67ac86d1b65c6102",
+ "chksum_sha256": "87e5d82e8ac83281e179792a74c7a27cb38a271327311e27ce44cd81c9e654af",
"format": 1
},
{
@@ -1397,20 +1502,153 @@
"name": "tests/integration/targets/docker_compose/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1527d71c7fcb97bba10c5abe90cf36795b45583d33280d58a8b170a33dc27d36",
+ "chksum_sha256": "6b8ed3ac1dcbc2e57090222c0122e12eed47715945aa536b910fb924733b57ee",
"format": 1
},
{
"name": "tests/integration/targets/docker_compose/tasks/run-test.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "da6c09c1ac08f548c321efdee418d3bf6a621f65725d3d6de095119600a3e876",
+ "chksum_sha256": "589896d784e4a7b77ed0c607c47d776ee00968bf212f82097e73498a3754b65b",
"format": 1
},
{
"name": "tests/integration/targets/docker_compose/aliases",
"ftype": "file",
"chksum_type": "sha256",
+ "chksum_sha256": "0198949fe4ff2cfe98102ac0580ef659952ecf3c8c45dab7f0c78655e372e828",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_compose_v2",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_compose_v2/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_compose_v2/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "58974ad0879f97f23deb80f10b5f0edca86e1864798c8abc02390de4ea8437d7",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_compose_v2/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_compose_v2/tasks/tests",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_compose_v2/tasks/tests/pull.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "2dca8d67d229abe3fa5a6c0913fab09042576790055a6a7b5b0cb14bf493a317",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_compose_v2/tasks/tests/start-stop.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "22379b999ad56ac7691796e2f2c7e0cd5e359c9cab97ded2074fce676d558eb9",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_compose_v2/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "375f957e7348b7c72fac3e7ce7634b9424daf98122537ff7b803b56aa4b3079d",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_compose_v2/tasks/run-test.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "589896d784e4a7b77ed0c607c47d776ee00968bf212f82097e73498a3754b65b",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_compose_v2/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c22c090ea76cdd2a6ccd1689e016e014e4b1970a498e6db3123d5c95fb7a352b",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_compose_v2_pull",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_compose_v2_pull/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_compose_v2_pull/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "58974ad0879f97f23deb80f10b5f0edca86e1864798c8abc02390de4ea8437d7",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_compose_v2_pull/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_compose_v2_pull/tasks/tests",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_compose_v2_pull/tasks/tests/pull.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "b8eb64730c4423e73f6ed793b393f8ea6be6b66369e8133135717d4271efd135",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_compose_v2_pull/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "375f957e7348b7c72fac3e7ce7634b9424daf98122537ff7b803b56aa4b3079d",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_compose_v2_pull/tasks/run-test.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "589896d784e4a7b77ed0c607c47d776ee00968bf212f82097e73498a3754b65b",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_compose_v2_pull/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
"chksum_sha256": "c22c090ea76cdd2a6ccd1689e016e014e4b1970a498e6db3123d5c95fb7a352b",
"format": 1
},
@@ -1432,7 +1670,7 @@
"name": "tests/integration/targets/docker_config/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0f3d9ae2d6857600b4881f03e3b5cb30b9492a75bce28ba914c621af34f3b7fa",
+ "chksum_sha256": "48e41681961146fc376abdd7ef550952d84678a300f6310fd18910e2b270ac29",
"format": 1
},
{
@@ -1509,7 +1747,7 @@
"name": "tests/integration/targets/docker_container/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0b6cbfff0581c89d9114e38c9c9d6a5f688dbaa924e60b29e8d774eb1203c2ed",
+ "chksum_sha256": "6fbc5e2468efd3c9de72d5eb1061a59b4c3ac7274c4857be455efcc35e8610d5",
"format": 1
},
{
@@ -1530,7 +1768,7 @@
"name": "tests/integration/targets/docker_container/tasks/tests/comparisons.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f622ba77bed23fe0bef21c621696db94325b0e98f067dc64f12abbcb7daa6a36",
+ "chksum_sha256": "9975880766fb10219151c58592084c77a17f340af95fb146503bf8e4ed5b5001",
"format": 1
},
{
@@ -1544,7 +1782,7 @@
"name": "tests/integration/targets/docker_container/tasks/tests/image-ids.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b0440399c26e6c9b3cf2e29da8ef4e3a97a2c93ee675cd5e7a55c4f8e41785e8",
+ "chksum_sha256": "60cfc29a44563833ed84d2240f6de1f146f2a3e05590bf45004108b290e1c5d3",
"format": 1
},
{
@@ -1565,7 +1803,7 @@
"name": "tests/integration/targets/docker_container/tasks/tests/options.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a5c152736a4e2c51367d3553cccc4b44320ac52eab374f4837b3eaaf29e6cc72",
+ "chksum_sha256": "b6479e2ffd06f410f3eaafd8cd478325ef1291e9013fc79d36c5c3da42b7207e",
"format": 1
},
{
@@ -1600,14 +1838,14 @@
"name": "tests/integration/targets/docker_container/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f437ccc68a828f632b778b60368f62f93758c09bd3339df64ae427cd8e9ef9e7",
+ "chksum_sha256": "47bc2c08f9e907360b97511ad5096630439458e0d6020d851f9e80fb778c9ab1",
"format": 1
},
{
"name": "tests/integration/targets/docker_container/tasks/run-test.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "da6c09c1ac08f548c321efdee418d3bf6a621f65725d3d6de095119600a3e876",
+ "chksum_sha256": "589896d784e4a7b77ed0c607c47d776ee00968bf212f82097e73498a3754b65b",
"format": 1
},
{
@@ -1635,7 +1873,7 @@
"name": "tests/integration/targets/docker_container_copy_into/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0f3d9ae2d6857600b4881f03e3b5cb30b9492a75bce28ba914c621af34f3b7fa",
+ "chksum_sha256": "f1c910549dd871495ae0ef7a0ddfa2c2b836d671346c8993ab0d91008b19e86c",
"format": 1
},
{
@@ -1670,14 +1908,14 @@
"name": "tests/integration/targets/docker_container_copy_into/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "524ff9fae84d128947e0b36eaf1ba800f55dcc1e4cec812ae4f4a86463d725e2",
+ "chksum_sha256": "8d9fa990ca08e1a50f0729260994fe275ff72e11e997118e0bdebadcaea4ad22",
"format": 1
},
{
"name": "tests/integration/targets/docker_container_copy_into/tasks/run-test.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "da6c09c1ac08f548c321efdee418d3bf6a621f65725d3d6de095119600a3e876",
+ "chksum_sha256": "589896d784e4a7b77ed0c607c47d776ee00968bf212f82097e73498a3754b65b",
"format": 1
},
{
@@ -1705,7 +1943,7 @@
"name": "tests/integration/targets/docker_container_exec/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0b6cbfff0581c89d9114e38c9c9d6a5f688dbaa924e60b29e8d774eb1203c2ed",
+ "chksum_sha256": "6fbc5e2468efd3c9de72d5eb1061a59b4c3ac7274c4857be455efcc35e8610d5",
"format": 1
},
{
@@ -1747,7 +1985,7 @@
"name": "tests/integration/targets/docker_container_info/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0b6cbfff0581c89d9114e38c9c9d6a5f688dbaa924e60b29e8d774eb1203c2ed",
+ "chksum_sha256": "6fbc5e2468efd3c9de72d5eb1061a59b4c3ac7274c4857be455efcc35e8610d5",
"format": 1
},
{
@@ -1789,7 +2027,7 @@
"name": "tests/integration/targets/docker_host_info/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0b6cbfff0581c89d9114e38c9c9d6a5f688dbaa924e60b29e8d774eb1203c2ed",
+ "chksum_sha256": "6fbc5e2468efd3c9de72d5eb1061a59b4c3ac7274c4857be455efcc35e8610d5",
"format": 1
},
{
@@ -1810,7 +2048,7 @@
"name": "tests/integration/targets/docker_host_info/tasks/test_host_info.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c8876138d9d717c706d3131a7e17b762e25ad4079de0138e6062e2f603bed57f",
+ "chksum_sha256": "71b40536d593bc36f89a74db356d48dfd933c001d934f0728512eec3b1c99045",
"format": 1
},
{
@@ -1838,7 +2076,7 @@
"name": "tests/integration/targets/docker_image/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7dbaea666eae950a1143d33cb471f602233866f4e39e4ece479ce828658a50ab",
+ "chksum_sha256": "1c2c8deaa4439989de0cde4582eec0a685d1c15554272cf4e82d6fc4e119b076",
"format": 1
},
{
@@ -1859,21 +2097,21 @@
"name": "tests/integration/targets/docker_image/tasks/tests/basic.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "142e5c02da389057b35f7439df89e0c3047f8ac3f0bad93513a770e0a04ee5cd",
+ "chksum_sha256": "82c6cc949307b59b70c390d8c43067cb5fea9ae6de3c57e5d133fc9e9caa2d7a",
"format": 1
},
{
"name": "tests/integration/targets/docker_image/tasks/tests/docker_image.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b00a60da257604ace692b6a044f374071d828d1ff005ffc786c23f8fae385f35",
+ "chksum_sha256": "132b8e0517198529ec420ca730dabad59ba9fa99c5f307a8074d12a1e9a2b773",
"format": 1
},
{
"name": "tests/integration/targets/docker_image/tasks/tests/options.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a2f7b377f8b6c3ca7e3565a40ae4d81244f26ac5bbfdcc5dec20ed17fae268fd",
+ "chksum_sha256": "01e5f20d85b5a760235bb1c1b56136c8097ad7dfd32a5211fcffa5416191bb97",
"format": 1
},
{
@@ -1887,14 +2125,14 @@
"name": "tests/integration/targets/docker_image/tasks/run-test.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "da6c09c1ac08f548c321efdee418d3bf6a621f65725d3d6de095119600a3e876",
+ "chksum_sha256": "589896d784e4a7b77ed0c607c47d776ee00968bf212f82097e73498a3754b65b",
"format": 1
},
{
"name": "tests/integration/targets/docker_image/tasks/test.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cdc47967e0d64ebadcb0878d571976a21a5942ac286e88fdf00694e3e733f239",
+ "chksum_sha256": "eaeceab2e31f7a9b28a4f2e68a19b356ea9619e12ef2b7f776ab20967fc8fd0b",
"format": 1
},
{
@@ -1947,6 +2185,188 @@
"format": 1
},
{
+ "name": "tests/integration/targets/docker_image_build",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_build/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_build/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "58f77094d90397f9219c42f973c386ad471d6a9e17c590260458ea0de4aa7ce0",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_build/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_build/tasks/tests",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_build/tasks/tests/options.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "175cbbaf36639ee9c054d814400835d571416b48df606c9ed7ccaf009f98032c",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_build/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c1fe5f030f6ca6066ca6c9d8e41d697cc62bb457a55e76ef4dedff2e7fe896f1",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_build/tasks/run-test.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "589896d784e4a7b77ed0c607c47d776ee00968bf212f82097e73498a3754b65b",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_build/tasks/test.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "d96b8ee07ced0cad104066cce1c1ccbd8569008924dc2669c43f363dcfec9c6f",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_build/templates",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_build/templates/ArgsDockerfile",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c3699620b7b078291c3f1d1c97414c9e961b51ce3705fdccb67545e87fe7e75e",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_build/templates/Dockerfile",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9d300419d4d1e626ddbd093c53831948c6ebb6d48a973ba4a0d9fa34cdf7462e",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_build/templates/EtcHostsDockerfile",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f9d474c11ff7766ee58b74e50ecd80fba99b9ca1bab0b661c8f39c91dee23aed",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_build/templates/MyDockerfile",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "7d9039d8165a7c7170c5f1466438e9c27d6380abb329609d7601d34325709858",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_build/templates/StagedDockerfile",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "d5882640f5183ed9b01fe7f06e144cd375bd402a1f2014392347c5e0bfce2222",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_build/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c22c090ea76cdd2a6ccd1689e016e014e4b1970a498e6db3123d5c95fb7a352b",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_export",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_export/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_export/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f1c910549dd871495ae0ef7a0ddfa2c2b836d671346c8993ab0d91008b19e86c",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_export/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_export/tasks/tests",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_export/tasks/tests/basic.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "5d45f01ccb2bdd3ca9e191085355417aff91eabbd9950714549ae559c43e409e",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_export/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c1fe5f030f6ca6066ca6c9d8e41d697cc62bb457a55e76ef4dedff2e7fe896f1",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_export/tasks/run-test.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "589896d784e4a7b77ed0c607c47d776ee00968bf212f82097e73498a3754b65b",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_export/tasks/test.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "4f86478b3e92d32cd089ed3a4b4b6c9dfa7d2e0629f2180ba5a5159447de3c0e",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_export/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c22c090ea76cdd2a6ccd1689e016e014e4b1970a498e6db3123d5c95fb7a352b",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/docker_image_info",
"ftype": "dir",
"chksum_type": null,
@@ -1964,7 +2384,7 @@
"name": "tests/integration/targets/docker_image_info/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0b6cbfff0581c89d9114e38c9c9d6a5f688dbaa924e60b29e8d774eb1203c2ed",
+ "chksum_sha256": "6fbc5e2468efd3c9de72d5eb1061a59b4c3ac7274c4857be455efcc35e8610d5",
"format": 1
},
{
@@ -1978,7 +2398,7 @@
"name": "tests/integration/targets/docker_image_info/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "426eca8e288e79157781391f44256414ede3708b23c39f29c92dd7db3091cf42",
+ "chksum_sha256": "dc3ce4462ff5b5f575a9e3734427fee06c61d8a0cbd93ead7926f95d0131a8a9",
"format": 1
},
{
@@ -2006,7 +2426,7 @@
"name": "tests/integration/targets/docker_image_load/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0f3d9ae2d6857600b4881f03e3b5cb30b9492a75bce28ba914c621af34f3b7fa",
+ "chksum_sha256": "f1c910549dd871495ae0ef7a0ddfa2c2b836d671346c8993ab0d91008b19e86c",
"format": 1
},
{
@@ -2027,7 +2447,7 @@
"name": "tests/integration/targets/docker_image_load/tasks/tests/basic.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "86da5d9bdf5be5824548d45f489180bf3783a4a3e418f6632343ffa512860e04",
+ "chksum_sha256": "d5de67d5dab3fcd7da5eaf5c3a6c94261bf62d1917bde74d9a950d96a17f1ed9",
"format": 1
},
{
@@ -2041,14 +2461,14 @@
"name": "tests/integration/targets/docker_image_load/tasks/run-test.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "da6c09c1ac08f548c321efdee418d3bf6a621f65725d3d6de095119600a3e876",
+ "chksum_sha256": "589896d784e4a7b77ed0c607c47d776ee00968bf212f82097e73498a3754b65b",
"format": 1
},
{
"name": "tests/integration/targets/docker_image_load/tasks/test.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "095b8c21beee6803c2a06eae5119a074eb019e54ebf2d8f0f348047cdc4e8997",
+ "chksum_sha256": "4f86478b3e92d32cd089ed3a4b4b6c9dfa7d2e0629f2180ba5a5159447de3c0e",
"format": 1
},
{
@@ -2059,6 +2479,251 @@
"format": 1
},
{
+ "name": "tests/integration/targets/docker_image_pull",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_pull/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_pull/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "3fe2a9716c9e0d5f76289712ef7a56c65f1101ad33972a291e80c638560348de",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_pull/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_pull/tasks/tests",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_pull/tasks/tests/basic.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "a74261dfdb75932a93fef7f45fae601eea430ad9a7770b2ea60c5451fe8567c0",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_pull/tasks/tests/image-ids.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6046c00692b59a1087dc1a1be4fb0a51d2ead9b8eb13f5dec6bf9f5c281e3556",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_pull/tasks/tests/registry.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "5640e423fa7377f6513b62f58b068e66143f2f15b74a0a4b00d9adfdcf286352",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_pull/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c1fe5f030f6ca6066ca6c9d8e41d697cc62bb457a55e76ef4dedff2e7fe896f1",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_pull/tasks/run-test.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "589896d784e4a7b77ed0c607c47d776ee00968bf212f82097e73498a3754b65b",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_pull/tasks/test.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "4f86478b3e92d32cd089ed3a4b4b6c9dfa7d2e0629f2180ba5a5159447de3c0e",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_pull/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c22c090ea76cdd2a6ccd1689e016e014e4b1970a498e6db3123d5c95fb7a352b",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_push",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_push/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_push/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "3fe2a9716c9e0d5f76289712ef7a56c65f1101ad33972a291e80c638560348de",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_push/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_push/tasks/tests",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_push/tasks/tests/basic.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0e176bf605f73d6dc857c02c67aa1b8c400d8c51e30e00b2d076eddd7f10f8c1",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_push/tasks/tests/registry.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "033ce4bb02091d123ce90d08d9618cb5b6dd9ab959d8a7c27944aeab3fe3a704",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_push/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c1fe5f030f6ca6066ca6c9d8e41d697cc62bb457a55e76ef4dedff2e7fe896f1",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_push/tasks/run-test.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "589896d784e4a7b77ed0c607c47d776ee00968bf212f82097e73498a3754b65b",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_push/tasks/test.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "4f86478b3e92d32cd089ed3a4b4b6c9dfa7d2e0629f2180ba5a5159447de3c0e",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_push/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c22c090ea76cdd2a6ccd1689e016e014e4b1970a498e6db3123d5c95fb7a352b",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_remove",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_remove/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_remove/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6fbc5e2468efd3c9de72d5eb1061a59b4c3ac7274c4857be455efcc35e8610d5",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_remove/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_remove/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "8909cd9fb5a4f056696fb0e2f6b5c595388c0209f9aacd3143a2cdfa95039acb",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_remove/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c22c090ea76cdd2a6ccd1689e016e014e4b1970a498e6db3123d5c95fb7a352b",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_tag",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_tag/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_tag/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6fbc5e2468efd3c9de72d5eb1061a59b4c3ac7274c4857be455efcc35e8610d5",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_tag/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_tag/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "a0189575a19c755c3ae0594b57deaf9ef24496566dafb73b9ca5edc64732c57a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/docker_image_tag/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c22c090ea76cdd2a6ccd1689e016e014e4b1970a498e6db3123d5c95fb7a352b",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/docker_login",
"ftype": "dir",
"chksum_type": null,
@@ -2076,7 +2741,7 @@
"name": "tests/integration/targets/docker_login/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c0879f5877b4d7a56bfd1fc54868e01542fd2c3a3c935fbaf51a6f8b1d78b98c",
+ "chksum_sha256": "3fe2a9716c9e0d5f76289712ef7a56c65f1101ad33972a291e80c638560348de",
"format": 1
},
{
@@ -2118,14 +2783,14 @@
"name": "tests/integration/targets/docker_login/tasks/run-test.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "da6c09c1ac08f548c321efdee418d3bf6a621f65725d3d6de095119600a3e876",
+ "chksum_sha256": "589896d784e4a7b77ed0c607c47d776ee00968bf212f82097e73498a3754b65b",
"format": 1
},
{
"name": "tests/integration/targets/docker_login/tasks/test.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "17cb11d752619a8dec4d8cb853f761e8b57fdb5e5ce5a5da262f9084609727a2",
+ "chksum_sha256": "461a8c0fd7d6c95ea0cb8da0bd992001aee333d6b1df85ad59287c50816d4fc7",
"format": 1
},
{
@@ -2153,7 +2818,7 @@
"name": "tests/integration/targets/docker_network/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0b6cbfff0581c89d9114e38c9c9d6a5f688dbaa924e60b29e8d774eb1203c2ed",
+ "chksum_sha256": "ae0071cbdc1f10ad0a69b2bcec3ad0c9026329d5a4a885c48defd2286853051c",
"format": 1
},
{
@@ -2209,14 +2874,14 @@
"name": "tests/integration/targets/docker_network/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "783052d7b0b20a53eb53022d1a11291f58a2d6a1d5e1fe4cdaba53ef8f48ae91",
+ "chksum_sha256": "dc33f1ea882658d11b8b05f9d7ecb3b5fa83f93874634d4a64fcf5b0ce4ee135",
"format": 1
},
{
"name": "tests/integration/targets/docker_network/tasks/run-test.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "da6c09c1ac08f548c321efdee418d3bf6a621f65725d3d6de095119600a3e876",
+ "chksum_sha256": "589896d784e4a7b77ed0c607c47d776ee00968bf212f82097e73498a3754b65b",
"format": 1
},
{
@@ -2244,7 +2909,7 @@
"name": "tests/integration/targets/docker_network_info/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0b6cbfff0581c89d9114e38c9c9d6a5f688dbaa924e60b29e8d774eb1203c2ed",
+ "chksum_sha256": "6fbc5e2468efd3c9de72d5eb1061a59b4c3ac7274c4857be455efcc35e8610d5",
"format": 1
},
{
@@ -2286,7 +2951,7 @@
"name": "tests/integration/targets/docker_node/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0b6cbfff0581c89d9114e38c9c9d6a5f688dbaa924e60b29e8d774eb1203c2ed",
+ "chksum_sha256": "cd202950e619805dd026c97d7f544448832e6e453bb905939e6e8f86b40700cf",
"format": 1
},
{
@@ -2307,7 +2972,7 @@
"name": "tests/integration/targets/docker_node/tasks/test_node.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bda1878d83565fb8898708430195d199316191192995faf33f56328291d02458",
+ "chksum_sha256": "6286e7ba1e8bd45d6eab7be864c5732a387f3660d2ac2f294e70aad9b2ada3d8",
"format": 1
},
{
@@ -2335,7 +3000,7 @@
"name": "tests/integration/targets/docker_node_info/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0b6cbfff0581c89d9114e38c9c9d6a5f688dbaa924e60b29e8d774eb1203c2ed",
+ "chksum_sha256": "cd202950e619805dd026c97d7f544448832e6e453bb905939e6e8f86b40700cf",
"format": 1
},
{
@@ -2384,7 +3049,7 @@
"name": "tests/integration/targets/docker_plugin/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0b6cbfff0581c89d9114e38c9c9d6a5f688dbaa924e60b29e8d774eb1203c2ed",
+ "chksum_sha256": "cd202950e619805dd026c97d7f544448832e6e453bb905939e6e8f86b40700cf",
"format": 1
},
{
@@ -2419,14 +3084,14 @@
"name": "tests/integration/targets/docker_plugin/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "52bb0aa03f299c3dc12da10e484e0461c14fdff09b45613a80e537aaea6d344b",
+ "chksum_sha256": "9d9fdb52da705c4dfb2359e5c2d49068f19609f91763fb3d8777fed5627add36",
"format": 1
},
{
"name": "tests/integration/targets/docker_plugin/tasks/run-test.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "da6c09c1ac08f548c321efdee418d3bf6a621f65725d3d6de095119600a3e876",
+ "chksum_sha256": "589896d784e4a7b77ed0c607c47d776ee00968bf212f82097e73498a3754b65b",
"format": 1
},
{
@@ -2454,7 +3119,7 @@
"name": "tests/integration/targets/docker_prune/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0b6cbfff0581c89d9114e38c9c9d6a5f688dbaa924e60b29e8d774eb1203c2ed",
+ "chksum_sha256": "6fbc5e2468efd3c9de72d5eb1061a59b4c3ac7274c4857be455efcc35e8610d5",
"format": 1
},
{
@@ -2496,7 +3161,7 @@
"name": "tests/integration/targets/docker_secret/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0f3d9ae2d6857600b4881f03e3b5cb30b9492a75bce28ba914c621af34f3b7fa",
+ "chksum_sha256": "48e41681961146fc376abdd7ef550952d84678a300f6310fd18910e2b270ac29",
"format": 1
},
{
@@ -2650,7 +3315,7 @@
"name": "tests/integration/targets/docker_stack_info/tasks/test_stack_info.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "47f3a780523d0ade76b5f881890ced60757ab9a24988b4398691b0b849c47acc",
+ "chksum_sha256": "29e78c0d01610a78842ca6301e597e5945169162814e9cf5415bd66406c8246a",
"format": 1
},
{
@@ -2734,7 +3399,7 @@
"name": "tests/integration/targets/docker_stack_task_info/tasks/test_stack_task_info.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "dcfd63fef6c062d68b21cbbf4ecb44656d4be44f167cbb86f758edc4f8842b86",
+ "chksum_sha256": "5095994eb5af632106c94860af28783dfac2551ea3e83ca89ea1cbb8d5743e3c",
"format": 1
},
{
@@ -2797,7 +3462,7 @@
"name": "tests/integration/targets/docker_swarm/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2e40a69bda050967e474e8787b51b7343a60d5c7ac88685d66b556d160b942ea",
+ "chksum_sha256": "afb9965617dda796ed1d87d1a9cb81c0d18c52b89cecc9bd081a60de56421576",
"format": 1
},
{
@@ -2853,14 +3518,14 @@
"name": "tests/integration/targets/docker_swarm/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "243eaa04af0c56a5361d4ae5e09fc7d1ee61ac8df474638a0d00dfa5cbf08db9",
+ "chksum_sha256": "83facb629ba05b88437476933f76de29c5b3d771c73016683130c160f467bdd7",
"format": 1
},
{
"name": "tests/integration/targets/docker_swarm/tasks/run-test.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "63a1b79555c097c3c1d8b0bdb2b84b86b91873c6d3d55b7534067c8fea6d41fb",
+ "chksum_sha256": "589896d784e4a7b77ed0c607c47d776ee00968bf212f82097e73498a3754b65b",
"format": 1
},
{
@@ -2888,7 +3553,7 @@
"name": "tests/integration/targets/docker_swarm_info/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0b6cbfff0581c89d9114e38c9c9d6a5f688dbaa924e60b29e8d774eb1203c2ed",
+ "chksum_sha256": "cd202950e619805dd026c97d7f544448832e6e453bb905939e6e8f86b40700cf",
"format": 1
},
{
@@ -2909,7 +3574,7 @@
"name": "tests/integration/targets/docker_swarm_info/tasks/test_swarm_info.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "90c49732479e7ca86986ab2c60e33e6f76b8498153ac5c53f868853d7d41f501",
+ "chksum_sha256": "a66e2f1d82c3ab32d59c07635c4d20abf69b8d323b96ddf841357b6b0b58cdfa",
"format": 1
},
{
@@ -2958,7 +3623,7 @@
"name": "tests/integration/targets/docker_swarm_service/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0b6cbfff0581c89d9114e38c9c9d6a5f688dbaa924e60b29e8d774eb1203c2ed",
+ "chksum_sha256": "cd202950e619805dd026c97d7f544448832e6e453bb905939e6e8f86b40700cf",
"format": 1
},
{
@@ -3063,14 +3728,14 @@
"name": "tests/integration/targets/docker_swarm_service/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "66e91bb3f282f7b18ca6a769723a257694c0d06721505e1d52a4c7f71c5edc61",
+ "chksum_sha256": "11581ee9556a8936a8ab16d8d1efeb94d7c48255103a35b466eda5043985ea17",
"format": 1
},
{
"name": "tests/integration/targets/docker_swarm_service/tasks/run-test.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "da6c09c1ac08f548c321efdee418d3bf6a621f65725d3d6de095119600a3e876",
+ "chksum_sha256": "589896d784e4a7b77ed0c607c47d776ee00968bf212f82097e73498a3754b65b",
"format": 1
},
{
@@ -3112,7 +3777,7 @@
"name": "tests/integration/targets/docker_swarm_service_info/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0b6cbfff0581c89d9114e38c9c9d6a5f688dbaa924e60b29e8d774eb1203c2ed",
+ "chksum_sha256": "cd202950e619805dd026c97d7f544448832e6e453bb905939e6e8f86b40700cf",
"format": 1
},
{
@@ -3161,7 +3826,7 @@
"name": "tests/integration/targets/docker_volume/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0b6cbfff0581c89d9114e38c9c9d6a5f688dbaa924e60b29e8d774eb1203c2ed",
+ "chksum_sha256": "6fbc5e2468efd3c9de72d5eb1061a59b4c3ac7274c4857be455efcc35e8610d5",
"format": 1
},
{
@@ -3189,14 +3854,14 @@
"name": "tests/integration/targets/docker_volume/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6543ef6a25f219df5e563d0c1f01ef07f5b0a3dab90f402e9829c1bc74877a9a",
+ "chksum_sha256": "fd4eca112abb405d6608e364103379b1d106c0fd8f61b7b7ee464a5756d3e4ed",
"format": 1
},
{
"name": "tests/integration/targets/docker_volume/tasks/run-test.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "da6c09c1ac08f548c321efdee418d3bf6a621f65725d3d6de095119600a3e876",
+ "chksum_sha256": "589896d784e4a7b77ed0c607c47d776ee00968bf212f82097e73498a3754b65b",
"format": 1
},
{
@@ -3224,7 +3889,7 @@
"name": "tests/integration/targets/docker_volume_info/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0b6cbfff0581c89d9114e38c9c9d6a5f688dbaa924e60b29e8d774eb1203c2ed",
+ "chksum_sha256": "6fbc5e2468efd3c9de72d5eb1061a59b4c3ac7274c4857be455efcc35e8610d5",
"format": 1
},
{
@@ -3294,7 +3959,7 @@
"name": "tests/integration/targets/generic_connection_tests/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2e40a69bda050967e474e8787b51b7343a60d5c7ac88685d66b556d160b942ea",
+ "chksum_sha256": "b0d732afa83688b5150e3b820884f8342c9ee4c0d9a56858687e17584d6b4de1",
"format": 1
},
{
@@ -3322,7 +3987,7 @@
"name": "tests/integration/targets/generic_connection_tests/vars/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "14638ce9bffa141ed24360a6b3829bc932cc92d32534849dff7e47c8dbd4d337",
+ "chksum_sha256": "5f127d1b97bf228ef19a0c0c998f7a7611f43087865121d35beec0fb44a07a25",
"format": 1
},
{
@@ -3350,7 +4015,7 @@
"name": "tests/integration/targets/generic_ssh_connection/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3f6945a1293b14cbefecf8301fcc7cabaa845fabc7e6e5d4df97a159a848bb2c",
+ "chksum_sha256": "515ee11c2347dabc82e8f82887d5b978fd93ef1f324c0dc208182baca2b638a0",
"format": 1
},
{
@@ -3364,7 +4029,7 @@
"name": "tests/integration/targets/generic_ssh_connection/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d252f557380bba5c18a7d7a395bedf317d1a3322d6ed0d28c24738edbc7b3c5f",
+ "chksum_sha256": "89d9d7da7291d856cc871282536f110a0b38c459b43ba2925444cc4c0595133c",
"format": 1
},
{
@@ -3392,7 +4057,7 @@
"name": "tests/integration/targets/inventory_docker_containers/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0b6cbfff0581c89d9114e38c9c9d6a5f688dbaa924e60b29e8d774eb1203c2ed",
+ "chksum_sha256": "6fbc5e2468efd3c9de72d5eb1061a59b4c3ac7274c4857be455efcc35e8610d5",
"format": 1
},
{
@@ -3406,28 +4071,28 @@
"name": "tests/integration/targets/inventory_docker_containers/playbooks/docker_cleanup.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "234f2134d2618268ded9e87f250344cb54d1ffac76077dec39231ef435e69888",
+ "chksum_sha256": "05c43d3ee07e3844fc8e887e51e7aac1724e5e02b762847a6bbe4a5141825c16",
"format": 1
},
{
"name": "tests/integration/targets/inventory_docker_containers/playbooks/docker_setup.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "27487a6d48339d9cc60b3f212670c8d1e36c19f340cbf254ce24c183bbc59fe1",
+ "chksum_sha256": "c7baa4866eb0bf2867252beb9a89b1aa709d912818f4364deb2bf35267b59c6f",
"format": 1
},
{
"name": "tests/integration/targets/inventory_docker_containers/playbooks/test_inventory_1.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9f9ec4b04a09105e25040fbc27f2dce25d25826d2c589cb2f50e9d9fe9cdb80c",
+ "chksum_sha256": "5a161e8190369dce67ab9b59f2c4109fbfda3ce2cac66c80412b7aacc558c996",
"format": 1
},
{
"name": "tests/integration/targets/inventory_docker_containers/playbooks/test_inventory_2.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2f8162017e23a5c9faeeadbfb6e5e0700f1e64f1d76bb5f4d21c44deb6593c4f",
+ "chksum_sha256": "e932ce6bae051ae264322180fced5ee38ce01ccd2c1b5c8ca4d4fa855e1bffd8",
"format": 1
},
{
@@ -3455,7 +4120,7 @@
"name": "tests/integration/targets/inventory_docker_containers/runme.sh",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9e9f61933604532e33a6df228c8165615864926686a4f278bccf7574725a471f",
+ "chksum_sha256": "959dd0ebdd942dd1ea2518dcafecf11004ffe7f3ab4f6eb3ddf418a6fd2a947e",
"format": 1
},
{
@@ -3490,7 +4155,7 @@
"name": "tests/integration/targets/inventory_docker_machine/playbooks/pre-setup.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "06da4e8823ec83e13ab7e15e2448347a01ff3e86a26a7d5bae23a9a85630318f",
+ "chksum_sha256": "87061ebde573e07bac6d43d7991eb716942a931ae0f4e4a51e53e6a6a2f81fb2",
"format": 1
},
{
@@ -3553,7 +4218,7 @@
"name": "tests/integration/targets/inventory_docker_machine/runme.sh",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b7766b726c1bd9f7f88d041949de164708050e7cc2391db54e760bfdf0c0a18e",
+ "chksum_sha256": "40d6b2c962e3c75f15ce208eeb6d47cf16b4049560ed69c977e74fb1a2f465c2",
"format": 1
},
{
@@ -3581,7 +4246,7 @@
"name": "tests/integration/targets/inventory_docker_swarm/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0b6cbfff0581c89d9114e38c9c9d6a5f688dbaa924e60b29e8d774eb1203c2ed",
+ "chksum_sha256": "cd202950e619805dd026c97d7f544448832e6e453bb905939e6e8f86b40700cf",
"format": 1
},
{
@@ -3595,14 +4260,14 @@
"name": "tests/integration/targets/inventory_docker_swarm/playbooks/swarm_cleanup.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "260def0e56e182996d606d1cf1844cb867a566dca8a703f2072ac7828b411845",
+ "chksum_sha256": "08ae593373e067d4f51b95903ecf66e764ad9e690f1f287cfe436899e99b0a2f",
"format": 1
},
{
"name": "tests/integration/targets/inventory_docker_swarm/playbooks/swarm_setup.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "68093251935f6f88a5224d35b3a27e3f7025e7e5f8e553163daf6981faf36478",
+ "chksum_sha256": "7264337e3c80dbe3ba6d521850c653da85767df86814af18a03b90a7b64fb2ec",
"format": 1
},
{
@@ -3644,7 +4309,7 @@
"name": "tests/integration/targets/inventory_docker_swarm/runme.sh",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b4b637a7352ac0fd0648dbced168f58e41cbc8b283d3b142575cc02dd7e84820",
+ "chksum_sha256": "9165553f336b498778d029796fb63fce86d53d9a8a3ffc42190c20a9442a4e66",
"format": 1
},
{
@@ -3665,7 +4330,7 @@
"name": "tests/integration/targets/setup_docker/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "dcfce2a57ae37a11f8350da70b4cb56af42d7175b34257b93b91a1073b1e4d4a",
+ "chksum_sha256": "588fe56f36b397ee3f8e5f44732ccda89632bad1b148143d06cd21365c162542",
"format": 1
},
{
@@ -3679,7 +4344,7 @@
"name": "tests/integration/targets/setup_docker/handlers/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b3404a9480a664270525437804a3d4e92476437dcedea0c04500deb7e9447f25",
+ "chksum_sha256": "5fde8f14499aecccaad502ae36b1cdc7d40057275b62fc255cb8c791fefcd7ae",
"format": 1
},
{
@@ -3707,7 +4372,7 @@
"name": "tests/integration/targets/setup_docker/tasks/Alpine.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "43b8d257ab837f98501833d5b91f8eee268be85accf168f3dfb9f478ac0d3af1",
+ "chksum_sha256": "13b468db50d2d5e6f76a989547a8ba2d9b6552a355d86173ea3f1fd7619309b9",
"format": 1
},
{
@@ -3763,7 +4428,7 @@
"name": "tests/integration/targets/setup_docker/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6f121d1ab26132465c260741cc7f45bdc50e20986a8a1b1186c929c98154edcf",
+ "chksum_sha256": "3e5d213ee69aa2b33302bc83ce9d56fde52956a4070fde9c3e2de3c7564ad88c",
"format": 1
},
{
@@ -3791,7 +4456,7 @@
"name": "tests/integration/targets/setup_docker/vars/RedHat-7.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "646aba9f18362f886a8d806cc2129a958ba226d851d54e55b805140a8b14ab7e",
+ "chksum_sha256": "d8fac5856f538ceb01bcfa39157cc49b2fd4b06f90f81b139931dfb51ba1d3fa",
"format": 1
},
{
@@ -3819,7 +4484,7 @@
"name": "tests/integration/targets/setup_docker/vars/Ubuntu-14.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "718e986033765b8744119a049b8d6c6efc048cb3eacd85edcb42c6a69e08cdcc",
+ "chksum_sha256": "63a1b79555c097c3c1d8b0bdb2b84b86b91873c6d3d55b7534067c8fea6d41fb",
"format": 1
},
{
@@ -3847,7 +4512,7 @@
"name": "tests/integration/targets/setup_docker/vars/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "14638ce9bffa141ed24360a6b3829bc932cc92d32534849dff7e47c8dbd4d337",
+ "chksum_sha256": "5f127d1b97bf228ef19a0c0c998f7a7611f43087865121d35beec0fb44a07a25",
"format": 1
},
{
@@ -3858,189 +4523,448 @@
"format": 1
},
{
- "name": "tests/integration/targets/setup_docker_compose",
+ "name": "tests/integration/targets/setup_docker_cli_buildx",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/setup_docker_compose/defaults",
+ "name": "tests/integration/targets/setup_docker_cli_buildx/meta",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/setup_docker_compose/defaults/main.yml",
+ "name": "tests/integration/targets/setup_docker_cli_buildx/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5a0dcbb1be4a30a25685755533954499a8849453b5758f093fbc74c9025d1ae5",
+ "chksum_sha256": "0b6cbfff0581c89d9114e38c9c9d6a5f688dbaa924e60b29e8d774eb1203c2ed",
"format": 1
},
{
- "name": "tests/integration/targets/setup_docker_compose/meta",
+ "name": "tests/integration/targets/setup_docker_cli_buildx/tasks",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/setup_docker_compose/meta/main.yml",
+ "name": "tests/integration/targets/setup_docker_cli_buildx/tasks/Debian.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "8c799c5451b3a64dd1fd3d8b578d17b92a074a78f5cb34104da51f04877109b1",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_cli_buildx/tasks/Fedora.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "8c799c5451b3a64dd1fd3d8b578d17b92a074a78f5cb34104da51f04877109b1",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_cli_buildx/tasks/RedHat-7.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "8c799c5451b3a64dd1fd3d8b578d17b92a074a78f5cb34104da51f04877109b1",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_cli_buildx/tasks/RedHat-9.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "8c799c5451b3a64dd1fd3d8b578d17b92a074a78f5cb34104da51f04877109b1",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_cli_buildx/tasks/Alpine.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "00790dc5d03168159d5780e0cc7b3a3a73b9fed8aa7ab5c84f538b189ed7c2df",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_cli_buildx/tasks/Archlinux.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "1d99d87f0c899b2a5f9e72705de13726d9499905a88ee7d0518d1e0a5ecc5afa",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_cli_buildx/tasks/RedHat-8.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "eb7b20e68f175f1be8cd72e7c62f1943db97b151d0b39c0573efaf92ea74f8c3",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_cli_buildx/tasks/Suse.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "40fbe81fae1589d08d7026a9b648bd1b836c54e24d28c5311d778838926879bb",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_cli_buildx/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "721d802f4ff5041cb0d78ee17e9555375422ec46ead9d8c3eeec197661887b2f",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_cli_buildx/tasks/nothing.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "8c799c5451b3a64dd1fd3d8b578d17b92a074a78f5cb34104da51f04877109b1",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_cli_buildx/vars",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_cli_buildx/vars/default.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "63a1b79555c097c3c1d8b0bdb2b84b86b91873c6d3d55b7534067c8fea6d41fb",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_cli_compose",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_cli_compose/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_cli_compose/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0b6cbfff0581c89d9114e38c9c9d6a5f688dbaa924e60b29e8d774eb1203c2ed",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_cli_compose/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_cli_compose/tasks/Debian.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "8c799c5451b3a64dd1fd3d8b578d17b92a074a78f5cb34104da51f04877109b1",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_cli_compose/tasks/Fedora.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "8c799c5451b3a64dd1fd3d8b578d17b92a074a78f5cb34104da51f04877109b1",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_cli_compose/tasks/RedHat-7.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "8c799c5451b3a64dd1fd3d8b578d17b92a074a78f5cb34104da51f04877109b1",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_cli_compose/tasks/RedHat-9.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "8c799c5451b3a64dd1fd3d8b578d17b92a074a78f5cb34104da51f04877109b1",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_cli_compose/tasks/Alpine.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6cbc07316095dcf5ff8cf95bd2e57095ae2187fab0c9edf224e0d6bf212f553b",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_cli_compose/tasks/Archlinux.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0391df4795e8bbf89618a8ebb1c3ce3458cd06474f1a9e9d9f8cdf1139a8a384",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_cli_compose/tasks/RedHat-8.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "eb33f9ec7af9d4a5355e1aa3685fbbe9ced427ad030d1ce36f1f36c3eaa051c7",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_cli_compose/tasks/Suse.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "d1ea224b6e53e3f587af86e5f8d988e9569011d2e1d3f98a3f5836abaf3085b9",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_cli_compose/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "4c8d8ec38064dacd5357eee4cab893855454ebe75e9f30c638071735a596776e",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_cli_compose/tasks/nothing.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "8c799c5451b3a64dd1fd3d8b578d17b92a074a78f5cb34104da51f04877109b1",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_cli_compose/vars",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_cli_compose/vars/default.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "63a1b79555c097c3c1d8b0bdb2b84b86b91873c6d3d55b7534067c8fea6d41fb",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_compose_v1",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_compose_v1/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_compose_v1/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ce4bb65d99952f682f7153558914669854e3ce0113789d6d0c09b2d58d6423d6",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_compose_v1/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_compose_v1/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "73fc081e424b642eeab13b34ec6594726fa079ea946df22fdf7e0cc75fece2d3",
"format": 1
},
{
- "name": "tests/integration/targets/setup_docker_compose/tasks",
+ "name": "tests/integration/targets/setup_docker_compose_v1/tasks",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/setup_docker_compose/tasks/Alpine.yml",
+ "name": "tests/integration/targets/setup_docker_compose_v1/tasks/Alpine.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "b71b69524c05e82aeea8ba71809e08218c45a108eb50e73bb81ddcfafbc0f48c",
"format": 1
},
{
- "name": "tests/integration/targets/setup_docker_compose/tasks/Archlinux.yml",
+ "name": "tests/integration/targets/setup_docker_compose_v1/tasks/Archlinux.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "b70baef7cc2b4cc553b7a6dde5aba91de029be5c08c2d0373ec57a0bccacb645",
"format": 1
},
{
- "name": "tests/integration/targets/setup_docker_compose/tasks/Debian.yml",
+ "name": "tests/integration/targets/setup_docker_compose_v1/tasks/Debian.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "72be467f15cffa21fa7eefbb26646f78d49787b9d30b97d41bbc045242ecc792",
"format": 1
},
{
- "name": "tests/integration/targets/setup_docker_compose/tasks/Fedora.yml",
+ "name": "tests/integration/targets/setup_docker_compose_v1/tasks/Fedora.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "f75f1446ccac863d07c5a0503bef419b8be29b5556a10b7200bdf7ac2f87d6b0",
"format": 1
},
{
- "name": "tests/integration/targets/setup_docker_compose/tasks/RedHat-7.yml",
+ "name": "tests/integration/targets/setup_docker_compose_v1/tasks/RedHat-7.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "0eb71ce9c438e1425fe68baefcd0e4ef0fdcf189f7610be09a3987f136270efd",
"format": 1
},
{
- "name": "tests/integration/targets/setup_docker_compose/tasks/RedHat-8.yml",
+ "name": "tests/integration/targets/setup_docker_compose_v1/tasks/RedHat-8.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "bf017f59cbd79a3501fa97c8a25f789dd4344a58d5cbe3a53d68390b3930c642",
"format": 1
},
{
- "name": "tests/integration/targets/setup_docker_compose/tasks/RedHat-9.yml",
+ "name": "tests/integration/targets/setup_docker_compose_v1/tasks/RedHat-9.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "bf017f59cbd79a3501fa97c8a25f789dd4344a58d5cbe3a53d68390b3930c642",
"format": 1
},
{
- "name": "tests/integration/targets/setup_docker_compose/tasks/Suse.yml",
+ "name": "tests/integration/targets/setup_docker_compose_v1/tasks/Suse.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "8eb0b2d6ae8ba75408d500d36c1bc26325d79d3277f29a35bf6e7a7dc73cbac8",
"format": 1
},
{
- "name": "tests/integration/targets/setup_docker_compose/tasks/main.yml",
+ "name": "tests/integration/targets/setup_docker_compose_v1/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "14c06a6d94f6eec3b1691433c009b560cccfe8edff15164ce7076ed03f73a603",
"format": 1
},
{
- "name": "tests/integration/targets/setup_docker_compose/tasks/setup.yml",
+ "name": "tests/integration/targets/setup_docker_compose_v1/tasks/setup.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "347de1b4ae8ddb1c9c51606f248b23047ef5bd881d662eee6bf07d4b59ab7fc3",
+ "chksum_sha256": "d0f71068688a01b29984ff13a35fbcb2ddc306d511c8f63ca66a57db807b44b6",
"format": 1
},
{
- "name": "tests/integration/targets/setup_docker_compose/vars",
+ "name": "tests/integration/targets/setup_docker_compose_v1/vars",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/setup_docker_compose/vars/CentOS-8.yml",
+ "name": "tests/integration/targets/setup_docker_compose_v1/vars/Alpine.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f20697da978c8ed625b345961999507bdc44548fc6f322804cce12c8106148a0",
+ "chksum_sha256": "0554ad7767703892ec32552f8d6119dcc9015f694aa90e4aa4dc4d65a069840e",
"format": 1
},
{
- "name": "tests/integration/targets/setup_docker_compose/vars/RedHat-7.yml",
+ "name": "tests/integration/targets/setup_docker_compose_v1/vars/Archlinux.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "10152adf3d38b6a56495180b4585ffea1ca37943561b97ce2fb504dcedcb6339",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_compose_v1/vars/CentOS-8.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "f20697da978c8ed625b345961999507bdc44548fc6f322804cce12c8106148a0",
"format": 1
},
{
- "name": "tests/integration/targets/setup_docker_compose/vars/RedHat-8.yml",
+ "name": "tests/integration/targets/setup_docker_compose_v1/vars/Debian-11.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "57bb4c8bfe93488522b1b6e6fe14783266ebf1692fdcbf8743b76b248ae0484a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_compose_v1/vars/Debian-12.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "57bb4c8bfe93488522b1b6e6fe14783266ebf1692fdcbf8743b76b248ae0484a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_compose_v1/vars/RedHat-7.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fd5145a46e8fb735a465794fb7daf159b2777397fa9e206df45052e2855f2946",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_compose_v1/vars/RedHat-8.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "c892ab9caff1f3abc4d33665d2dbc8d400aa5c19a8da57aa68b9d361e19a7d25",
"format": 1
},
{
- "name": "tests/integration/targets/setup_docker_compose/vars/RedHat-9.yml",
+ "name": "tests/integration/targets/setup_docker_compose_v1/vars/RedHat-9.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "c892ab9caff1f3abc4d33665d2dbc8d400aa5c19a8da57aa68b9d361e19a7d25",
"format": 1
},
{
- "name": "tests/integration/targets/setup_docker_compose/vars/Suse-py2.yml",
+ "name": "tests/integration/targets/setup_docker_compose_v1/vars/Suse-py2.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "f20697da978c8ed625b345961999507bdc44548fc6f322804cce12c8106148a0",
"format": 1
},
{
- "name": "tests/integration/targets/setup_docker_compose/vars/Suse-py3.yml",
+ "name": "tests/integration/targets/setup_docker_compose_v1/vars/Suse-py3.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0061c7189c312bb9d118ae0390ed09046eb9de90e29df5da0db043f571de71b5",
+ "chksum_sha256": "c892ab9caff1f3abc4d33665d2dbc8d400aa5c19a8da57aa68b9d361e19a7d25",
"format": 1
},
{
- "name": "tests/integration/targets/setup_docker_compose/vars/Ubuntu-16.yml",
+ "name": "tests/integration/targets/setup_docker_compose_v1/vars/Ubuntu-14.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "db950d02e92758a200434ecf25d81c90e7f076466be75332673c714b6be638a0",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_compose_v1/vars/Ubuntu-16.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "f20697da978c8ed625b345961999507bdc44548fc6f322804cce12c8106148a0",
"format": 1
},
{
- "name": "tests/integration/targets/setup_docker_compose/vars/Ubuntu-18.yml",
+ "name": "tests/integration/targets/setup_docker_compose_v1/vars/Ubuntu-18.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "f20697da978c8ed625b345961999507bdc44548fc6f322804cce12c8106148a0",
"format": 1
},
{
- "name": "tests/integration/targets/setup_docker_compose/vars/Ubuntu.yml",
+ "name": "tests/integration/targets/setup_docker_compose_v1/vars/Ubuntu.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "0061c7189c312bb9d118ae0390ed09046eb9de90e29df5da0db043f571de71b5",
"format": 1
},
{
- "name": "tests/integration/targets/setup_docker_compose/vars/default.yml",
+ "name": "tests/integration/targets/setup_docker_compose_v1/vars/default.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "63a1b79555c097c3c1d8b0bdb2b84b86b91873c6d3d55b7534067c8fea6d41fb",
@@ -4194,6 +5118,125 @@
"format": 1
},
{
+ "name": "tests/integration/targets/setup_docker_current_container_network_ip",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_current_container_network_ip/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_current_container_network_ip/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "41bf68c553802d515363d753ddcb1dd210353046bbce15372476067f260176c6",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_current_container_network_ip/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_current_container_network_ip/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fdc6377d741426c14f7cae91fe58584664a155b76ff1725cd005f05f98efc577",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_python_deps",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_python_deps/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_python_deps/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "721c28099649141d17cacdcdb886f4de0188ddadac86852f2abb6a334830de34",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_python_deps/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_python_deps/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "cb68a78cb264725dfaa8d3647048f08b136626454fb58e349c909e13b19d4be1",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_python_deps/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_python_deps/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "decb7c8ff488a40f3ff28d848a09158ae3a0b33675b4ee27320bd90cd0879f3c",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_python_deps/vars",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_python_deps/vars/RedHat-7.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "849f8ca19544ea366e1209448768a68238e0ec4a55d09daa9bb9817e4d51df98",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_python_deps/vars/Ubuntu-14.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "5cb84acc4451ea34b384dbd22bf68b593398d4fe490d313dfbd0ea043dbde0fa",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_python_deps/vars/default.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "63a1b79555c097c3c1d8b0bdb2b84b86b91873c6d3d55b7534067c8fea6d41fb",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_python_deps/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "cb09ffab7e455855046b8e8ef753c031bcd11a625c879517fa98335d23b15af8",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/setup_docker_registry",
"ftype": "dir",
"chksum_type": null,
@@ -4232,7 +5275,7 @@
"name": "tests/integration/targets/setup_docker_registry/handlers/cleanup.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "53b156130794d1c5df35d9e01508a3533488abfe0e5ff309a1887cc4e04478b2",
+ "chksum_sha256": "120d0201a317b41b424e1e8fd4f96f6d039a133f07e34dc04b1d785b56009c60",
"format": 1
},
{
@@ -4253,7 +5296,7 @@
"name": "tests/integration/targets/setup_docker_registry/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "df14f8571467afbfe26d30dca0d552af60569eef593778ceed169823636b6df0",
+ "chksum_sha256": "2817df3a1acffc7941cbe75ff9125d401a566c95e787d2deaa091e54c335bff3",
"format": 1
},
{
@@ -4281,7 +5324,7 @@
"name": "tests/integration/targets/setup_docker_registry/tasks/setup.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "35b7f4aab9306e42354462b5a1fb9795fd00321596a26483d971e907ed1718ec",
+ "chksum_sha256": "41e6a5d9cfc661c70c418c31e3ff1d02310fd05f5e5317f8d011857352cceaae",
"format": 1
},
{
@@ -4295,14 +5338,98 @@
"name": "tests/integration/targets/setup_docker_registry/vars/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "14638ce9bffa141ed24360a6b3829bc932cc92d32534849dff7e47c8dbd4d337",
+ "chksum_sha256": "5f127d1b97bf228ef19a0c0c998f7a7611f43087865121d35beec0fb44a07a25",
"format": 1
},
{
"name": "tests/integration/targets/setup_docker_registry/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d1b7da6a77f85a946d3fb9c0413c8ef74fce16c441a9327fa51ffab1098589a3",
+ "chksum_sha256": "9261aed0af24389371a0ac5c0b56cd61997059af5220a337b12a98abe1943cb4",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_sdk_for_python",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_sdk_for_python/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_sdk_for_python/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "73546253591c2bccf84f689e9199ee47090ac74ee12cbf2d15af209064e74910",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_sdk_for_python/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_sdk_for_python/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "cb68a78cb264725dfaa8d3647048f08b136626454fb58e349c909e13b19d4be1",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_sdk_for_python/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_sdk_for_python/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9c624239e18818059907db67e112f49bfd6eb478836ff51c5e94326e80f01805",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_sdk_for_python/vars",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_sdk_for_python/vars/RedHat-7.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "82c26f13d94c77a379869f352eb627928a151649bc4035af2063eee6b177316e",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_sdk_for_python/vars/Ubuntu-14.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "db950d02e92758a200434ecf25d81c90e7f076466be75332673c714b6be638a0",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_sdk_for_python/vars/default.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "63a1b79555c097c3c1d8b0bdb2b84b86b91873c6d3d55b7534067c8fea6d41fb",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_docker_sdk_for_python/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "cb09ffab7e455855046b8e8ef753c031bcd11a625c879517fa98335d23b15af8",
"format": 1
},
{
@@ -4561,7 +5688,7 @@
"name": "tests/integration/requirements.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "39735683a98661e03467f5ff49ebf18fc44d981d0c5d63ab2aaa07cf69bd1ab5",
+ "chksum_sha256": "d17176cccf067bce53bc57f15ed98cc91ce74d1f79f6e122558117fe75565687",
"format": 1
},
{
@@ -4579,6 +5706,27 @@
"format": 1
},
{
+ "name": "tests/sanity/extra/action-group.json",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "8db6b6d605787776bb1fa0be5bc4eb52a89fc896f5d3b5fff13d943035e5905f",
+ "format": 1
+ },
+ {
+ "name": "tests/sanity/extra/action-group.json.license",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6eb915239f9f35407fa68fdc41ed6522f1fdcce11badbdcd6057548023179ac1",
+ "format": 1
+ },
+ {
+ "name": "tests/sanity/extra/action-group.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "43418297dc51c6b51bb746189d9045c1650b6d7de373e926798e3773eb2fd3c1",
+ "format": 1
+ },
+ {
"name": "tests/sanity/extra/extra-docs.json",
"ftype": "file",
"chksum_type": "sha256",
@@ -4596,7 +5744,7 @@
"name": "tests/sanity/extra/extra-docs.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0fbd87476e9c35e4c5feb31be4aa1e8fc6aebf0de13058e5a267879f741ec0bf",
+ "chksum_sha256": "c52e316daf1292bbb063be19429fd1f06e02bce3c9d4622a8dfc61fa3af06688",
"format": 1
},
{
@@ -4649,24 +5797,10 @@
"format": 1
},
{
- "name": "tests/sanity/ignore-2.10.txt",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "f29b7fd15a448c7e4db863939b521ba515ca347a04feec3904926f36d1df667b",
- "format": 1
- },
- {
- "name": "tests/sanity/ignore-2.10.txt.license",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "6eb915239f9f35407fa68fdc41ed6522f1fdcce11badbdcd6057548023179ac1",
- "format": 1
- },
- {
"name": "tests/sanity/ignore-2.11.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f29b7fd15a448c7e4db863939b521ba515ca347a04feec3904926f36d1df667b",
+ "chksum_sha256": "9a24bca3a941c3895d8443f5467ad500972776bf79973430315dc60666ca395d",
"format": 1
},
{
@@ -4680,7 +5814,7 @@
"name": "tests/sanity/ignore-2.12.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b6df9bd553d2e95b00295bd64ea2ad10e6925108616c3ee435091d9936035937",
+ "chksum_sha256": "253e2f40d466107ec1ec5ec4a936056f7a25a47c9eff9c1541faed239e954847",
"format": 1
},
{
@@ -4694,7 +5828,7 @@
"name": "tests/sanity/ignore-2.13.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ccc7d836b365401a29253c3db1fef85f976a8977eb57332de1136187ac45f39a",
+ "chksum_sha256": "7633370c8868422bb5746752325d5799c4054b89347bfe284a5d562f1aa1ca75",
"format": 1
},
{
@@ -4736,7 +5870,7 @@
"name": "tests/sanity/ignore-2.16.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ccc7d836b365401a29253c3db1fef85f976a8977eb57332de1136187ac45f39a",
+ "chksum_sha256": "77e2580c039e9062bb354b79bad043392a7e343f11e1797b35b3d28b6955de79",
"format": 1
},
{
@@ -4747,14 +5881,14 @@
"format": 1
},
{
- "name": "tests/sanity/ignore-2.9.txt",
+ "name": "tests/sanity/ignore-2.17.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d49ed4d275b233af4655cbd623246de96dd7e5aff9356a409f4a8ea7c3cdb215",
+ "chksum_sha256": "77e2580c039e9062bb354b79bad043392a7e343f11e1797b35b3d28b6955de79",
"format": 1
},
{
- "name": "tests/sanity/ignore-2.9.txt.license",
+ "name": "tests/sanity/ignore-2.17.txt.license",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "6eb915239f9f35407fa68fdc41ed6522f1fdcce11badbdcd6057548023179ac1",
@@ -4820,7 +5954,7 @@
"name": "tests/unit/plugins/connection/test_docker.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6935ce21e236c76bbca4f6013b0cda317c825e89d6e2216b995e3ff72b01155f",
+ "chksum_sha256": "fca32d195d2be88e7728ce148fb170721db4ba7745ca162f1ed86e3b2145b93e",
"format": 1
},
{
@@ -4834,7 +5968,7 @@
"name": "tests/unit/plugins/inventory/test_docker_containers.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a267a4fb74b88a5069b0991f2d307234291e5e05735a4a363bde0bbdc73ac438",
+ "chksum_sha256": "87571060e81b9ed77b5332a56e5c6b5fbeba60201a07e20882b57944e5a13aaf",
"format": 1
},
{
@@ -4862,7 +5996,7 @@
"name": "tests/unit/plugins/module_utils/_api/api/test_client.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cca7fe225e44648e6ecc14ee76480d0e9b07850b0df54f5ea797f0d8df0112ed",
+ "chksum_sha256": "5114474e56b443ac90b48d2ce7d140c825da8cf52cc9d12f1285fd868089a2d2",
"format": 1
},
{
@@ -4883,7 +6017,7 @@
"name": "tests/unit/plugins/module_utils/_api/transport/test_ssladapter.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "81cd1cd14e699a58eff8a368477dc036bc68c74f37c6e2840b29dca4bc7c5dc9",
+ "chksum_sha256": "493f208f91caa26637ce2b5d7d4b7bafe0a5702baaa71ce34c2159c3f56e4588",
"format": 1
},
{
@@ -5006,6 +6140,20 @@
"format": 1
},
{
+ "name": "tests/unit/plugins/module_utils/compose_v2_test_cases.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "33aa50ee3a08c4615898083b9ac016ccd15dbcb0f3d6c2789123e480eab32439",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/module_utils/test__logfmt.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "7b9953396f57500b205a31805597a1c990d2aa80404ea2952494d5b129460758",
+ "format": 1
+ },
+ {
"name": "tests/unit/plugins/module_utils/test__scramble.py",
"ftype": "file",
"chksum_type": "sha256",
@@ -5013,6 +6161,13 @@
"format": 1
},
{
+ "name": "tests/unit/plugins/module_utils/test_compose_v2.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e0edcf037a5b0a6925584b4241888f095067fb3dc1d8e9f0b870f50343e6c997",
+ "format": 1
+ },
+ {
"name": "tests/unit/plugins/module_utils/test_copy.py",
"ftype": "file",
"chksum_type": "sha256",
@@ -5093,7 +6248,7 @@
"name": "tests/unit/requirements.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "999b6bb4a4234b1f38abb63cbd57d40af2d93bcff2260ab088e09157a055abaf",
+ "chksum_sha256": "12b0e4bf7113bf7fbdab69a78078c507a37a366cf4539d8f6ceab7ee2c3d46f3",
"format": 1
},
{
@@ -5170,7 +6325,7 @@
"name": "tests/utils/shippable/shippable.sh",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "59171fc13d0e2c92443c4e9d807a0c5b4143f59120c4e2bb1415a35474233cec",
+ "chksum_sha256": "db01bed83cdeff8d87b90c222cb84a5661680c9dd733f4ed5929dc7d44fc8636",
"format": 1
},
{
@@ -5195,10 +6350,31 @@
"format": 1
},
{
+ "name": "tests/galaxy-importer.cfg",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "d4e70c7540d2f405f079373fea81ee9be93021d051333797b20e756212ce3f0f",
+ "format": 1
+ },
+ {
+ "name": "CHANGELOG.md",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "a454d168d730e40228bc1b635787e39f4f1dd9561117c1c0472203fb3850ea45",
+ "format": 1
+ },
+ {
+ "name": "CHANGELOG.md.license",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6eb915239f9f35407fa68fdc41ed6522f1fdcce11badbdcd6057548023179ac1",
+ "format": 1
+ },
+ {
"name": "CHANGELOG.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c5ffd8701fda79eab260f17b11aa04ba6750abfbda47be69a3cf8c468541c281",
+ "chksum_sha256": "c0938e99f68c7ca4fce239f527e9a251a8c32562d4f89065fd2f4b53187f6408",
"format": 1
},
{
@@ -5219,7 +6395,7 @@
"name": "README.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d2110bcce37881a4a9a62c36821e188e5173be767b8b3ea483b82257b05006db",
+ "chksum_sha256": "f2ed87985a5ed9319821b58e4f4e124db2e06f1b6c60a28c9f50a2666d37ca6f",
"format": 1
}
],
diff --git a/ansible_collections/community/docker/LICENSES/Apache-2.0.txt b/ansible_collections/community/docker/LICENSES/Apache-2.0.txt
index 75191a4dc..6276c238f 100644
--- a/ansible_collections/community/docker/LICENSES/Apache-2.0.txt
+++ b/ansible_collections/community/docker/LICENSES/Apache-2.0.txt
@@ -1,7 +1,7 @@
Apache License
Version 2.0, January 2004
- http://www.apache.org/licenses/
+ https://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
@@ -176,13 +176,13 @@
END OF TERMS AND CONDITIONS
- Copyright 2016 Docker, Inc.
+ Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
+ https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/ansible_collections/community/docker/MANIFEST.json b/ansible_collections/community/docker/MANIFEST.json
index 86c6e45ef..ac81cb0ff 100644
--- a/ansible_collections/community/docker/MANIFEST.json
+++ b/ansible_collections/community/docker/MANIFEST.json
@@ -2,7 +2,7 @@
"collection_info": {
"namespace": "community",
"name": "docker",
- "version": "3.4.7",
+ "version": "3.8.1",
"authors": [
"Ansible Docker Working Group"
],
@@ -16,9 +16,11 @@
"Apache-2.0"
],
"license_file": null,
- "dependencies": {},
+ "dependencies": {
+ "community.library_inventory_filtering_v1": ">=1.0.0"
+ },
"repository": "https://github.com/ansible-collections/community.docker",
- "documentation": null,
+ "documentation": "https://docs.ansible.com/ansible/latest/collections/community/docker/",
"homepage": "https://github.com/ansible-collections/community.docker",
"issues": "https://github.com/ansible-collections/community.docker/issues"
},
@@ -26,7 +28,7 @@
"name": "FILES.json",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "304daad33746f1615fd5ad546cd59d0779efa14114acba510189c8c34784b7f1",
+ "chksum_sha256": "b8f523a2e97dadfa557a707eca6cb96b06b64396f46e33fb6c9bfcb200345094",
"format": 1
},
"format": 1
diff --git a/ansible_collections/community/docker/README.md b/ansible_collections/community/docker/README.md
index e82e0a8ed..1bee82833 100644
--- a/ansible_collections/community/docker/README.md
+++ b/ansible_collections/community/docker/README.md
@@ -16,7 +16,7 @@ Please note that this collection does **not** support Windows targets. The conne
## Tested with Ansible
-Tested with the current ansible-core 2.11, ansible-core 2.12, ansible-core 2.13, and ansible-core 2.14 releases, and the current development version of ansible-core. Ansible/ansible-base versions before 2.11.0 are not supported.
+Tested with the current ansible-core 2.11, ansible-core 2.12, ansible-core 2.13, ansible-core 2.14, ansible-core 2.15, and ansible-core 2.16 releases, and the current development version of ansible-core. Ansible/ansible-base versions before 2.11.0 are not supported.
Please note that Ansible 2.9 and ansible-base 2.10 are no longer supported. If you need to use them, use community.docker 2.x.y. Also note that this collection does not work with ansible-core 2.11 (this includes ansible-base and Ansible 2.9) on Python 3.12+.
@@ -62,8 +62,14 @@ If you use the Ansible package and do not update collections independently, use
- community.docker.docker_container_info: retrieve information on Docker containers
- community.docker.docker_host_info: retrieve information on the Docker daemon
- community.docker.docker_image: manage Docker images
+ - community.docker.docker_image_build: build Docker images using Docker buildx
+ - community.docker.docker_image_export: export (archive) Docker images
- community.docker.docker_image_info: retrieve information on Docker images
- community.docker.docker_image_load: load Docker images from archives
+ - community.docker.docker_image_pull: pull Docker images from registries
+ - community.docker.docker_image_push: push Docker images to registries
+ - community.docker.docker_image_remove: remove Docker images
+ - community.docker.docker_image_tag: tag Docker images with new names and/or tags
- community.docker.docker_login: log in and out to/from registries
- community.docker.docker_network: manage Docker networks
- community.docker.docker_network_info: retrieve information on Docker networks
@@ -72,7 +78,9 @@ If you use the Ansible package and do not update collections independently, use
- community.docker.docker_volume: manage Docker volumes
- community.docker.docker_volume_info: retrieve information on Docker volumes
* Docker Compose:
- - community.docker.docker_compose: manage Docker Compose files
+ - community.docker.docker_compose: manage Docker Compose files (legacy Docker Compose v1)
+ - community.docker.docker_compose_v2: manage Docker Compose files (Docker compose CLI plugin)
+ - community.docker.docker_compose_v2_pull: pull a Docker compose project
* Docker Swarm:
- community.docker.docker_config: manage configurations
- community.docker.docker_node: manage Docker Swarm nodes
@@ -112,7 +120,7 @@ You can find more information in the [developer guide for collections](https://d
## Release notes
-See the [changelog](https://github.com/ansible-collections/community.docker/tree/main/CHANGELOG.rst).
+See the [changelog](https://github.com/ansible-collections/community.docker/tree/main/CHANGELOG.md).
## More information
diff --git a/ansible_collections/community/docker/changelogs/changelog.yaml b/ansible_collections/community/docker/changelogs/changelog.yaml
index 9b479daab..db03d2485 100644
--- a/ansible_collections/community/docker/changelogs/changelog.yaml
+++ b/ansible_collections/community/docker/changelogs/changelog.yaml
@@ -36,7 +36,7 @@ releases:
instead (https://github.com/ansible-collections/community.docker/pull/1).
- docker_image - the default of the ``build.pull`` option changed to ``false``
(https://github.com/ansible-collections/community.docker/pull/1).
- - docker_image_facts - this alias is on longer availabe, use ``docker_image_info``
+ - docker_image_facts - this alias is on longer available, use ``docker_image_info``
instead (https://github.com/ansible-collections/community.docker/pull/1).
- docker_network - no longer returns ``ansible_facts`` (https://github.com/ansible-collections/community.docker/pull/1).
- docker_network - the ``ipam_options`` option has been removed. Use ``ipam_config``
@@ -213,11 +213,11 @@ releases:
comparison (https://github.com/ansible-collections/community.docker/issues/85).
- docker_image - prevent module failure when removing image that is removed
between inspection and removal (https://github.com/ansible-collections/community.docker/pull/87).
- - docker_image - prevent module failure when removing non-existant image by
+ - docker_image - prevent module failure when removing non-existent image by
ID (https://github.com/ansible-collections/community.docker/pull/87).
- docker_image_info - prevent module failure when image vanishes between listing
and inspection (https://github.com/ansible-collections/community.docker/pull/87).
- - docker_image_info - prevent module failure when querying non-existant image
+ - docker_image_info - prevent module failure when querying non-existent image
by ID (https://github.com/ansible-collections/community.docker/pull/87).
minor_changes:
- docker_container - add ``storage_opts`` option to specify storage options
@@ -475,7 +475,7 @@ releases:
module (https://github.com/ansible-collections/community.docker/pull/243,
https://github.com/ansible-collections/community.docker/issues/242).
- nsenter connection plugin - ensure the ``nsenter_pid`` option is retrieved
- in ``_connect`` instead of ``__init__`` to prevent a crasher due to bad initialization
+ in ``_connect`` instead of ``__init__`` to prevent a crash due to bad initialization
order (https://github.com/ansible-collections/community.docker/pull/249).
- nsenter connection plugin - replace the use of ``--all-namespaces`` with specific
namespaces to support compatibility with Busybox nsenter (used on, for example,
@@ -528,7 +528,7 @@ releases:
2.2.0:
changes:
bugfixes:
- - docker_container, docker_image - adjust image finding code to pecularities
+ - docker_container, docker_image - adjust image finding code to peculiarities
of ``podman-docker``'s API emulation when Docker short names like ``redis``
are used (https://github.com/ansible-collections/community.docker/issues/292).
minor_changes:
@@ -791,7 +791,7 @@ releases:
with ansible-core 2.12+. For ansible-core 2.11, uses ``distutils.version``
for Python < 3.12. There is no support for ansible-core 2.11 with Python 3.12+
(https://github.com/ansible-collections/community.docker/pull/271).
- - socker_handler and socket_helper module utils - improve Python forward compatibilty,
+ - socker_handler and socket_helper module utils - improve Python forward compatibility,
create helper functions for file blocking/unblocking (https://github.com/ansible-collections/community.docker/pull/415).
release_summary: First alpha prerelease of community.docker 3.0.0. This version
has several breaking changes and features rewrites of several modules to directly
@@ -1129,6 +1129,28 @@ releases:
- fix-tmpfs_size-and-tmpfs_mode.yml
- remove-unneeded-imports.yml
release_date: '2023-02-20'
+ 3.4.10:
+ changes:
+ bugfixes:
+ - docker_swarm - make init and join operations work again with Docker SDK for
+ Python before 4.0.0 (https://github.com/ansible-collections/community.docker/issues/695,
+ https://github.com/ansible-collections/community.docker/pull/696).
+ release_summary: Bugfix release.
+ fragments:
+ - 3.4.10.yml
+ - 696-docker_swarm-data_addr_path.yml
+ release_date: '2023-10-29'
+ 3.4.11:
+ changes:
+ bugfixes:
+ - docker_volume - fix crash caused by accessing an empty dictionary. The ``has_different_config()``
+ was raising an ``AttributeError`` because the ``self.existing_volume["Labels"]``
+ dictionary was ``None`` (https://github.com/ansible-collections/community.docker/pull/702).
+ release_summary: Bugfix release.
+ fragments:
+ - 3.4.11.yml
+ - 702-docker-volume-label-none.yaml
+ release_date: '2023-11-12'
3.4.2:
changes:
bugfixes:
@@ -1214,3 +1236,390 @@ releases:
- 3.4.7.yml
- 637-swarm_info-endpoint_spec.yml
release_date: '2023-06-15'
+ 3.4.8:
+ changes:
+ known_issues:
+ - Ansible markup will show up in raw form on ansible-doc text output for ansible-core
+ before 2.15. If you have trouble deciphering the documentation markup, please
+ upgrade to ansible-core 2.15 (or newer), or read the HTML documentation on
+ https://docs.ansible.com/ansible/devel/collections/community/docker/.
+ release_summary: 'Maintenance release with updated documentation.
+
+
+ From this version on, community.docker is using the new `Ansible semantic
+ markup
+
+ <https://docs.ansible.com/ansible/devel/dev_guide/developing_modules_documenting.html#semantic-markup-within-module-documentation>`__
+
+ in its documentation. If you look at documentation with the ansible-doc CLI
+ tool
+
+ from ansible-core before 2.15, please note that it does not render the markup
+
+ correctly. You should be still able to read it in most cases, but you need
+
+ ansible-core 2.15 or later to see it as it is intended. Alternatively you
+ can
+
+ look at `the devel docsite <https://docs.ansible.com/ansible/devel/collections/community/docker/>`__
+
+ for the rendered HTML version of the documentation of the latest release.
+
+ '
+ fragments:
+ - 3.4.8.yml
+ release_date: '2023-06-22'
+ 3.4.9:
+ changes:
+ bugfixes:
+ - vendored Docker SDK for Python code - cherry-pick changes from the Docker
+ SDK for Python code to align code. These changes should not affect the parts
+ used by the collection's code (https://github.com/ansible-collections/community.docker/pull/694).
+ release_summary: Maintenance release with updated documentation and vendored
+ Docker SDK for Python code.
+ fragments:
+ - 3.4.9.yml
+ - 694-docker-py.yml
+ release_date: '2023-10-08'
+ 3.5.0:
+ changes:
+ bugfixes:
+ - modules and plugins using the Docker SDK for Python - remove ``ssl_version``
+ from the parameters passed to Docker SDK for Python 7.0.0+. Explicitly fail
+ with a nicer error message if it was explicitly set in this case (https://github.com/ansible-collections/community.docker/pull/715).
+ - modules and plugins using the Docker SDK for Python - remove ``tls_hostname``
+ from the parameters passed to Docker SDK for Python 7.0.0+. Explicitly fail
+ with a nicer error message if it was explicitly set in this case (https://github.com/ansible-collections/community.docker/pull/721).
+ - vendored Docker SDK for Python - avoid passing on ``ssl_version`` and ``tls_hostname``
+ if they were not provided by the user. Remove dead code. (https://github.com/ansible-collections/community.docker/pull/722).
+ deprecated_features:
+ - docker_container - the default ``ignore`` for the ``image_name_mismatch``
+ parameter has been deprecated and will switch to ``recreate`` in community.docker
+ 4.0.0. A deprecation warning will be printed in situations where the default
+ value is used and where a behavior would change once the default changes (https://github.com/ansible-collections/community.docker/pull/703).
+ minor_changes:
+ - docker_container - implement better ``platform`` string comparisons to improve
+ idempotency (https://github.com/ansible-collections/community.docker/issues/654,
+ https://github.com/ansible-collections/community.docker/pull/705).
+ - docker_container - internal refactorings which allow comparisons to use more
+ information like details of the current image or the Docker host config (https://github.com/ansible-collections/community.docker/pull/713).
+ release_summary: Bugfix and feature release.
+ fragments:
+ - 3.5.0.yml
+ - 703-docker_container-image_name_mismatch.yml
+ - 705-docker_container-platform.yml
+ - 713-docker_container-refactoring.yml
+ - 715-docker-7.yml
+ - 721-docker-7.yml
+ - 722-tls.yml
+ release_date: '2023-12-10'
+ 3.6.0:
+ changes:
+ bugfixes:
+ - docker_image - fix archiving idempotency with Docker API 1.44 or later (https://github.com/ansible-collections/community.docker/pull/765).
+ minor_changes:
+ - docker_container - add ``networks[].mac_address`` option for Docker API 1.44+.
+ Note that Docker API 1.44 no longer uses the global ``mac_address`` option,
+ this new option is the only way to set the MAC address for a container (https://github.com/ansible-collections/community.docker/pull/763).
+ release_summary: 'Bugfix and feature release.
+
+
+ The collection now includes a bunch of new ``docker_image_*`` modules that
+ move features out of the
+
+ rather complex ``docker_image`` module. These new modules are easier to use
+ and can better declare whether
+
+ they support check mode, diff mode, or none of them.
+
+
+ This version also features modules that support the Docker CLI plugins ``buildx``
+ and ``compose``.
+
+ The ``docker_image_build`` module uses the ``docker buildx`` command under
+ the hood, and the ``docker_compose_v2``
+
+ and ``docker_compose_v2_pull`` modules uses the ``docker compose`` command.
+ All these modules use the Docker CLI
+
+ instead of directly talking to the API. The modules support mostly the same
+ interface as the API based modules,
+
+ so the main difference is that instead of some Python requirements, they depend
+ on the Docker CLI tool ``docker``.
+
+ '
+ fragments:
+ - 3.6.0.yml
+ - 763-docker_container-mac_address.yml
+ - 765-docker_image-archive.yml
+ release_date: '2024-01-21'
+ 3.6.0-b1:
+ changes:
+ bugfixes:
+ - Use ``unix:///var/run/docker.sock`` instead of the legacy ``unix://var/run/docker.sock``
+ as default for ``docker_host`` (https://github.com/ansible-collections/community.docker/pull/736).
+ minor_changes:
+ - docker_image - allow to specify labels and ``/dev/shm`` size when building
+ images (https://github.com/ansible-collections/community.docker/issues/726,
+ https://github.com/ansible-collections/community.docker/pull/727).
+ - docker_image - allow to specify memory size and swap memory size in other
+ units than bytes (https://github.com/ansible-collections/community.docker/pull/727).
+ release_summary: 'Prerelease of the upcoming 3.6.0 bugfix and feature release.
+
+
+ The collection now includes a bunch of new ``docker_image_*`` modules that
+ move features out of the
+
+ rather complex ``docker_image`` module. These new modules are easier to use
+ and can better declare whether
+
+ they support check mode, diff mode, or none of them.
+
+
+ This version also features modules that support the Docker CLI plugins ``buildx``
+ and ``compose``.
+
+ The ``docker_image_build`` module uses the ``docker buildx`` command under
+ the hood, and the ``docker_compose_v2``
+
+ module uses the ``docker compose`` command. Both these modules use the Docker
+ CLI instead of directly talking
+
+ to the API. The modules support mostly the same interface as the API based
+ modules, so the main difference is that
+
+ instead of some Python requirements, they depend on the Docker CLI tool ``docker``.
+
+ '
+ fragments:
+ - 3.6.0-b1.yml
+ - 727-docker_image-build.yml
+ - host.yml
+ modules:
+ - description: Manage multi-container Docker applications with Docker Compose
+ CLI plugin
+ name: docker_compose_v2
+ namespace: ''
+ - description: Build Docker images using Docker buildx
+ name: docker_image_build
+ namespace: ''
+ - description: Pull Docker images from registries
+ name: docker_image_pull
+ namespace: ''
+ - description: Push Docker images to registries
+ name: docker_image_push
+ namespace: ''
+ - description: Remove Docker images
+ name: docker_image_remove
+ namespace: ''
+ - description: Tag Docker images with new names and/or tags
+ name: docker_image_tag
+ namespace: ''
+ release_date: '2024-01-04'
+ 3.6.0-b2:
+ changes:
+ major_changes:
+ - The ``community.docker`` collection now depends on the ``community.library_inventory_filtering_v1``
+ collection. This utility collection provides host filtering functionality
+ for inventory plugins. If you use the Ansible community package, both collections
+ are included and you do not have to do anything special. If you install the
+ collection with ``ansible-galaxy collection install``, it will be installed
+ automatically. If you install the collection by copying the files of the collection
+ to a place where ansible-core can find it, for example by cloning the git
+ repository, you need to make sure that you also have to install the dependency
+ if you are using the inventory plugins (https://github.com/ansible-collections/community.docker/pull/698).
+ minor_changes:
+ - The ``ca_cert`` option available to almost all modules and plugins has been
+ renamed to ``ca_path``. The name ``ca_path`` is also used for similar options
+ in ansible-core and other collections. The old name has been added as an alias
+ and can still be used (https://github.com/ansible-collections/community.docker/pull/744).
+ - The ``docker_stack*`` modules now use the common CLI-based module code added
+ for the ``docker_image_build`` and ``docker_compose_v2`` modules. This means
+ that the modules now have various more configuration options with respect
+ to talking to the Docker Daemon, and now also are part of the ``community.docker.docker``
+ and ``docker`` module default groups (https://github.com/ansible-collections/community.docker/pull/745).
+ - inventory plugins - add ``filter`` option which allows to include and exclude
+ hosts based on Jinja2 conditions (https://github.com/ansible-collections/community.docker/pull/698,
+ https://github.com/ansible-collections/community.docker/issues/610).
+ release_summary: 'Second prerelease of the upcoming 3.6.0 bugfix and feature
+ release.
+
+
+ The collection now includes a bunch of new ``docker_image_*`` modules that
+ move features out of the
+
+ rather complex ``docker_image`` module. These new modules are easier to use
+ and can better declare whether
+
+ they support check mode, diff mode, or none of them.
+
+
+ This version also features modules that support the Docker CLI plugins ``buildx``
+ and ``compose``.
+
+ The ``docker_image_build`` module uses the ``docker buildx`` command under
+ the hood, and the ``docker_compose_v2``
+
+ and ``docker_compose_v2_pull`` modules uses the ``docker compose`` command.
+ All these modules use the Docker CLI
+
+ instead of directly talking to the API. The modules support mostly the same
+ interface as the API based modules,
+
+ so the main difference is that instead of some Python requirements, they depend
+ on the Docker CLI tool ``docker``.
+
+
+ Other changes to the collection since the last prerelease:
+
+
+ * docker_compose_v2 allows to specify the pull policy
+
+ '
+ fragments:
+ - 3.6.0-b2.yml
+ - 698-filter.yml
+ - 744-ca_path.yml
+ - 745-docker_stack.yml
+ modules:
+ - description: Pull a Docker compose project
+ name: docker_compose_v2_pull
+ namespace: ''
+ release_date: '2024-01-14'
+ 3.6.0-rc1:
+ changes:
+ release_summary: 'First release candidate of the latest bugfix and feature release.
+
+ No more features will be added before the final release, which will likely
+ happen on Sunday or Monday.
+
+
+ The collection now includes a bunch of new ``docker_image_*`` modules that
+ move features out of the
+
+ rather complex ``docker_image`` module. These new modules are easier to use
+ and can better declare whether
+
+ they support check mode, diff mode, or none of them.
+
+
+ This version also features modules that support the Docker CLI plugins ``buildx``
+ and ``compose``.
+
+ The ``docker_image_build`` module uses the ``docker buildx`` command under
+ the hood, and the ``docker_compose_v2``
+
+ and ``docker_compose_v2_pull`` modules uses the ``docker compose`` command.
+ All these modules use the Docker CLI
+
+ instead of directly talking to the API. The modules support mostly the same
+ interface as the API based modules,
+
+ so the main difference is that instead of some Python requirements, they depend
+ on the Docker CLI tool ``docker``.
+
+
+ Changes since the last beta:
+
+ * The ``docker_compose_v2*`` modules also checks for ``compose.yaml`` and
+ ``compose.yml``, not only for ``docker-compose.yaml`` and ``docker-compose.yml``.
+
+ * You can now specify ``services`` in the ``docker_compose_v2`` module.
+
+ * You can now specify ``build`` in the ``docker_compose_v2`` module (allows
+ to pass ``--build`` or ``--no-build`` depending on its value).
+
+ '
+ fragments:
+ - 3.6.0-rc1.yml
+ release_date: '2024-01-18'
+ 3.7.0:
+ changes:
+ bugfixes:
+ - docker_compose_v2 - properly parse dry-run build events from ``stderr`` (https://github.com/ansible-collections/community.docker/issues/778,
+ https://github.com/ansible-collections/community.docker/pull/779).
+ - docker_compose_v2_pull - the module was documented as part of the ``community.docker.docker``
+ action group, but was not actually part of it. That has now been fixed (https://github.com/ansible-collections/community.docker/pull/773).
+ minor_changes:
+ - docker_compose_v2 - add ``scale`` option to allow to explicitly scale services
+ (https://github.com/ansible-collections/community.docker/pull/776).
+ - docker_compose_v2, docker_compose_v2_pull - support ``files`` parameter to
+ specify multiple Compose files (https://github.com/ansible-collections/community.docker/issues/772,
+ https://github.com/ansible-collections/community.docker/pull/775).
+ release_summary: Bugfix and feature release.
+ fragments:
+ - 3.7.0.yml
+ - 773-docker_compose_v2_pull-action-group.yml
+ - 775-docker_compose-files.yml
+ - 776-docker_compose-scale.yml
+ - 779-compose-v2-build.yml
+ modules:
+ - description: Export (archive) Docker images
+ name: docker_image_export
+ namespace: ''
+ release_date: '2024-01-27'
+ 3.8.0:
+ changes:
+ bugfixes:
+ - docker_compose_v2 - do not consider a ``Waiting`` event as an action/change
+ (https://github.com/ansible-collections/community.docker/pull/804).
+ - docker_compose_v2 - do not treat service-level pull events as changes to avoid
+ incorrect ``changed=true`` return value of ``pull=always`` (https://github.com/ansible-collections/community.docker/issues/802,
+ https://github.com/ansible-collections/community.docker/pull/803).
+ - docker_compose_v2, docker_compose_v2_pull - fix parsing of pull messages for
+ Docker Compose 2.20.0 (https://github.com/ansible-collections/community.docker/issues/785,
+ https://github.com/ansible-collections/community.docker/pull/786).
+ minor_changes:
+ - docker_compose_v2 - allow to wait until containers are running/health when
+ running ``docker compose up`` with the new ``wait`` option (https://github.com/ansible-collections/community.docker/issues/794,
+ https://github.com/ansible-collections/community.docker/pull/796).
+ - docker_container - the ``pull_check_mode_behavior`` option now allows to control
+ the module's behavior in check mode when ``pull=always`` (https://github.com/ansible-collections/community.docker/issues/792,
+ https://github.com/ansible-collections/community.docker/pull/797).
+ - docker_container - the ``pull`` option now accepts the three values ``never``,
+ ``missing_image`` (default), and ``never``, next to the previously valid values
+ ``true`` (equivalent to ``always``) and ``false`` (equivalent to ``missing_image``).
+ This allows the equivalent to ``--pull=never`` from the Docker command line
+ (https://github.com/ansible-collections/community.docker/issues/783, https://github.com/ansible-collections/community.docker/pull/797).
+ release_summary: Bugfix and feature release.
+ fragments:
+ - 3.8.0.yml
+ - 786-docker_v2.yml
+ - 796-docker_compose_v2-wait.yml
+ - 797-docker_container-pull.yml
+ - 803-compose-v2-pull.yml
+ - 804-compose-v2-waiting.yml
+ release_date: '2024-02-25'
+ 3.8.1:
+ changes:
+ bugfixes:
+ - docker_compose_v2 - do not fail when non-fatal errors occur. This can happen
+ when pulling an image fails, but then the image can be built for another service.
+ Docker Compose emits an error in that case, but ``docker compose up`` still
+ completes successfully (https://github.com/ansible-collections/community.docker/issues/807,
+ https://github.com/ansible-collections/community.docker/pull/810, https://github.com/ansible-collections/community.docker/pull/811).
+ - docker_compose_v2* modules - correctly parse ``Warning`` events emitted by
+ Docker Compose (https://github.com/ansible-collections/community.docker/issues/807,
+ https://github.com/ansible-collections/community.docker/pull/811).
+ - docker_compose_v2* modules - parse ``logfmt`` warnings emitted by Docker Compose
+ (https://github.com/ansible-collections/community.docker/issues/787, https://github.com/ansible-collections/community.docker/pull/811).
+ - docker_compose_v2_pull - fixing idempotence by checking actual pull progress
+ events instead of service-level pull request when ``policy=always``. This
+ stops the module from reporting ``changed=true`` if no actual change happened
+ when pulling. In check mode, it has to assume that a change happens though
+ (https://github.com/ansible-collections/community.docker/issues/813, https://github.com/ansible-collections/community.docker/pull/814).
+ release_summary: Bugfix release
+ security_fixes:
+ - docker_containers, docker_machine, and docker_swarm inventory plugins - make
+ sure all data received from the Docker daemon / Docker machine is marked as
+ unsafe, so remote code execution by obtaining texts that can be evaluated
+ as templates is not possible (https://www.die-welt.net/2024/03/remote-code-execution-in-ansible-dynamic-inventory-plugins/,
+ https://github.com/ansible-collections/community.docker/pull/815).
+ fragments:
+ - 3.8.1.yml
+ - 810-compose-errors.yml
+ - 811-compose-v2-logfmt.yml
+ - 814-docker_compose_v2_pull-idem.yml
+ - inventory-rce.yml
+ release_date: '2024-03-16'
diff --git a/ansible_collections/community/docker/changelogs/config.yaml b/ansible_collections/community/docker/changelogs/config.yaml
index 1c0c2d208..1fd1d794d 100644
--- a/ansible_collections/community/docker/changelogs/config.yaml
+++ b/ansible_collections/community/docker/changelogs/config.yaml
@@ -11,6 +11,9 @@ keep_fragments: false
mention_ancestor: true
new_plugins_after_name: removed_features
notesdir: fragments
+output_formats:
+ - md
+ - rst
prelude_section_name: release_summary
prelude_section_title: Release Summary
sections:
diff --git a/ansible_collections/community/docker/docs/docsite/config.yml b/ansible_collections/community/docker/docs/docsite/config.yml
new file mode 100644
index 000000000..846b95f62
--- /dev/null
+++ b/ansible_collections/community/docker/docs/docsite/config.yml
@@ -0,0 +1,15 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# The following `.. envvar::` directives are defined in the extra docsite docs:
+envvar_directives:
+ - DOCKER_HOST
+ - DOCKER_API_VERSION
+ - DOCKER_TIMEOUT
+ - DOCKER_CERT_PATH
+ - DOCKER_SSL_VERSION
+ - DOCKER_TLS
+ - DOCKER_TLS_HOSTNAME
+ - DOCKER_TLS_VERIFY
diff --git a/ansible_collections/community/docker/docs/docsite/rst/scenario_guide.rst b/ansible_collections/community/docker/docs/docsite/rst/scenario_guide.rst
index e4b84431f..203aa57d2 100644
--- a/ansible_collections/community/docker/docs/docsite/rst/scenario_guide.rst
+++ b/ansible_collections/community/docker/docs/docsite/rst/scenario_guide.rst
@@ -8,7 +8,7 @@
Docker Guide
============
-The `community.docker collection <https://galaxy.ansible.com/community/docker>`_ offers several modules and plugins for orchestrating Docker containers and Docker Swarm.
+The `community.docker collection <https://galaxy.ansible.com/ui/repo/published/community/docker/>`_ offers several modules and plugins for orchestrating Docker containers and Docker Swarm.
.. contents::
:local:
@@ -18,7 +18,7 @@ The `community.docker collection <https://galaxy.ansible.com/community/docker>`_
Requirements
------------
-Most of the modules and plugins in community.docker require the `Docker SDK for Python <https://docker-py.readthedocs.io/en/stable/>`_. The SDK needs to be installed on the machines where the modules and plugins are executed, and for the Python version(s) with which the modules and plugins are executed. You can use the :ref:`community.general.python_requirements_info module <ansible_collections.community.general.python_requirements_info_module>` to make sure that the Docker SDK for Python is installed on the correct machine and for the Python version used by Ansible.
+Most of the modules and plugins in community.docker require the `Docker SDK for Python <https://docker-py.readthedocs.io/en/stable/>`_. The SDK needs to be installed on the machines where the modules and plugins are executed, and for the Python version(s) with which the modules and plugins are executed. You can use the :ansplugin:`community.general.python_requirements_info module <community.general.python_requirements_info#module>` to make sure that the Docker SDK for Python is installed on the correct machine and for the Python version used by Ansible.
Note that plugins (inventory plugins and connection plugins) are always executed in the context of Ansible itself. If you use a plugin that requires the Docker SDK for Python, you need to install it on the machine running ``ansible`` or ``ansible-playbook`` and for the same Python interpreter used by Ansible. To see which Python is used, run ``ansible --version``.
@@ -49,7 +49,7 @@ Parameters
Most plugins and modules can be configured by the following parameters:
docker_host
- The URL or Unix socket path used to connect to the Docker API. Defaults to ``unix://var/run/docker.sock``. To connect to a remote host, provide the TCP connection string (for example: ``tcp://192.0.2.23:2376``). If TLS is used to encrypt the connection to the API, then the module will automatically replace 'tcp' in the connection URL with 'https'.
+ The URL or Unix socket path used to connect to the Docker API. Defaults to ``unix:///var/run/docker.sock``. To connect to a remote host, provide the TCP connection string (for example: ``tcp://192.0.2.23:2376``). If TLS is used to encrypt the connection to the API, then the module will automatically replace ``tcp`` in the connection URL with ``https``.
api_version
The version of the Docker API running on the Docker Host. Defaults to the latest version of the API supported by the Docker SDK for Python installed.
@@ -63,7 +63,7 @@ Most plugins and modules can be configured by the following parameters:
validate_certs
Secure the connection to the API by using TLS and verifying the authenticity of the Docker host server. Default is ``false``.
- cacert_path
+ ca_path
Use a CA certificate when performing server verification by providing the path to a CA certificate file.
cert_path
@@ -78,6 +78,58 @@ Most plugins and modules can be configured by the following parameters:
ssl_version
Provide a valid SSL version number. The default value is determined by the Docker SDK for Python.
+ This option is not available for the CLI based plugins. It is mainly needed for legacy systems and should be avoided.
+
+
+Module default group
+....................
+
+To avoid having to specify common parameters for all the modules in every task, you can use the ``community.docker.docker`` :ref:`module defaults group <module_defaults_groups>`, or its short name ``docker``.
+
+.. note::
+
+ Module default groups only work for modules, not for plugins (connection and inventory plugins).
+
+The following example shows how the module default group can be used in a playbook:
+
+.. code-block:: yaml+jinja
+
+ ---
+ - name: Pull and image and start the container
+ hosts: localhost
+ gather_facts: false
+ module_defaults:
+ group/community.docker.docker:
+ # Select Docker Daemon on other host
+ docker_host: tcp://192.0.2.23:2376
+ # Configure TLS
+ tls: true
+ validate_certs: true
+ tls_hostname: docker.example.com
+ ca_path: /path/to/cacert.pem
+ # Increase timeout
+ timeout: 120
+ tasks:
+ - name: Pull image
+ community.docker.docker_image_pull:
+ name: python
+ tag: 3.12
+
+ - name: Start container
+ community.docker.docker_container:
+ cleanup: true
+ command: python --version
+ detach: false
+ image: python:3.12
+ name: my-python-container
+ output_logs: true
+
+ - name: Show output
+ ansible.builtin.debug:
+ msg: "{{ output.container.Output }}"
+
+Here the two ``community.docker`` tasks will use the options set for the module defaults group.
+
Environment variables
.....................
@@ -86,27 +138,38 @@ You can also control how the plugins and modules connect to the Docker API by se
For plugins, they have to be set for the environment Ansible itself runs in. For modules, they have to be set for the environment the modules are executed in. For modules running on remote machines, the environment variables have to be set on that machine for the user used to execute the modules with.
- DOCKER_HOST
- The URL or Unix socket path used to connect to the Docker API.
+.. envvar:: DOCKER_HOST
+
+ The URL or Unix socket path used to connect to the Docker API.
+
+.. envvar:: DOCKER_API_VERSION
+
+ The version of the Docker API running on the Docker Host. Defaults to the latest version of the API supported
+ by Docker SDK for Python.
+
+.. envvar:: DOCKER_TIMEOUT
+
+ The maximum amount of time in seconds to wait on a response from the API.
- DOCKER_API_VERSION
- The version of the Docker API running on the Docker Host. Defaults to the latest version of the API supported
- by Docker SDK for Python.
+.. envvar:: DOCKER_CERT_PATH
- DOCKER_TIMEOUT
- The maximum amount of time in seconds to wait on a response from the API.
+ Path to the directory containing the client certificate, client key and CA certificate.
- DOCKER_CERT_PATH
- Path to the directory containing the client certificate, client key and CA certificate.
+.. envvar:: DOCKER_SSL_VERSION
- DOCKER_SSL_VERSION
- Provide a valid SSL version number.
+ Provide a valid SSL version number.
- DOCKER_TLS
- Secure the connection to the API by using TLS without verifying the authenticity of the Docker Host.
+.. envvar:: DOCKER_TLS
- DOCKER_TLS_VERIFY
- Secure the connection to the API by using TLS and verify the authenticity of the Docker Host.
+ Secure the connection to the API by using TLS without verifying the authenticity of the Docker Host.
+
+.. envvar:: DOCKER_TLS_HOSTNAME
+
+ When verifying the authenticity of the Docker Host, uses this hostname to compare to the host's certificate.
+
+.. envvar:: DOCKER_TLS_VERIFY
+
+ Secure the connection to the API by using TLS and verify the authenticity of the Docker Host.
Plain Docker daemon: images, networks, volumes, and containers
@@ -115,70 +178,118 @@ Plain Docker daemon: images, networks, volumes, and containers
For working with a plain Docker daemon, that is without Swarm, there are connection plugins, an inventory plugin, and several modules available:
docker connection plugin
- The :ref:`community.docker.docker connection plugin <ansible_collections.community.docker.docker_connection>` uses the Docker CLI utility to connect to Docker containers and execute modules in them. It essentially wraps ``docker exec`` and ``docker cp``. This connection plugin is supported by the :ref:`ansible.posix.synchronize module <ansible_collections.ansible.posix.synchronize_module>`.
+ The :ansplugin:`community.docker.docker connection plugin <community.docker.docker#connection>` uses the Docker CLI utility to connect to Docker containers and execute modules in them. It essentially wraps ``docker exec`` and ``docker cp``. This connection plugin is supported by the :ansplugin:`ansible.posix.synchronize module <ansible.posix.synchronize#module>`.
docker_api connection plugin
- The :ref:`community.docker.docker_api connection plugin <ansible_collections.community.docker.docker_api_connection>` talks directly to the Docker daemon to connect to Docker containers and execute modules in them.
+ The :ansplugin:`community.docker.docker_api connection plugin <community.docker.docker_api#connection>` talks directly to the Docker daemon to connect to Docker containers and execute modules in them.
docker_containers inventory plugin
- The :ref:`community.docker.docker_containers inventory plugin <ansible_collections.community.docker.docker_containers_inventory>` allows you to dynamically add Docker containers from a Docker Daemon to your Ansible inventory. See :ref:`dynamic_inventory` for details on dynamic inventories.
+ The :ansplugin:`community.docker.docker_containers inventory plugin <community.docker.docker_containers#inventory>` allows you to dynamically add Docker containers from a Docker Daemon to your Ansible inventory. See :ref:`dynamic_inventory` for details on dynamic inventories.
The `docker inventory script <https://github.com/ansible-community/contrib-scripts/blob/main/inventory/docker.py>`_ is deprecated. Please use the inventory plugin instead. The inventory plugin has several compatibility options. If you need to collect Docker containers from multiple Docker daemons, you need to add every Docker daemon as an individual inventory source.
docker_host_info module
- The :ref:`community.docker.docker_host_info module <ansible_collections.community.docker.docker_host_info_module>` allows you to retrieve information on a Docker daemon, such as all containers, images, volumes, networks and so on.
+ The :ansplugin:`community.docker.docker_host_info module <community.docker.docker_host_info#module>` allows you to retrieve information on a Docker daemon, such as all containers, images, volumes, networks and so on.
docker_login module
- The :ref:`community.docker.docker_login module <ansible_collections.community.docker.docker_login_module>` allows you to log in and out of a remote registry, such as Docker Hub or a private registry. It provides similar functionality to the ``docker login`` and ``docker logout`` CLI commands.
+ The :ansplugin:`community.docker.docker_login module <community.docker.docker_login#module>` allows you to log in and out of a remote registry, such as Docker Hub or a private registry. It provides similar functionality to the ``docker login`` and ``docker logout`` CLI commands.
docker_prune module
- The :ref:`community.docker.docker_prune module <ansible_collections.community.docker.docker_prune_module>` allows you to prune no longer needed containers, images, volumes and so on. It provides similar functionality to the ``docker prune`` CLI command.
+ The :ansplugin:`community.docker.docker_prune module <community.docker.docker_prune#module>` allows you to prune no longer needed containers, images, volumes and so on. It provides similar functionality to the ``docker prune`` CLI command.
docker_image module
- The :ref:`community.docker.docker_image module <ansible_collections.community.docker.docker_image_module>` provides full control over images, including: build, pull, push, tag and remove.
+ The :ansplugin:`community.docker.docker_image module <community.docker.docker_image#module>` provides full control over images, including: build, pull, push, tag and remove.
+
+ docker_image_build
+ The :ansplugin:`community.docker.docker_image_build module <community.docker.docker_image_build#module>` allows you to build a Docker image using Docker buildx.
+
+ docker_image_export module
+ The :ansplugin:`community.docker.docker_image_export module <community.docker.docker_image_export#module>` allows you to export (archive) images.
docker_image_info module
- The :ref:`community.docker.docker_image_info module <ansible_collections.community.docker.docker_image_info_module>` allows you to list and inspect images.
+ The :ansplugin:`community.docker.docker_image_info module <community.docker.docker_image_info#module>` allows you to list and inspect images.
+
+ docker_image_load
+ The :ansplugin:`community.docker.docker_image_load module <community.docker.docker_image_load#module>` allows you to import one or multiple images from tarballs.
+
+ docker_image_pull
+ The :ansplugin:`community.docker.docker_image_pull module <community.docker.docker_image_pull#module>` allows you to pull a Docker image from a registry.
+
+ docker_image_push
+ The :ansplugin:`community.docker.docker_image_push module <community.docker.docker_image_push#module>` allows you to push a Docker image to a registry.
+
+ docker_image_remove
+ The :ansplugin:`community.docker.docker_image_remove module <community.docker.docker_image_remove#module>` allows you to remove and/or untag a Docker image from the Docker daemon.
+
+ docker_image_tag
+ The :ansplugin:`community.docker.docker_image_tag module <community.docker.docker_image_tag#module>` allows you to tag a Docker image with additional names and/or tags.
docker_network module
- The :ref:`community.docker.docker_network module <ansible_collections.community.docker.docker_network_module>` provides full control over Docker networks.
+ The :ansplugin:`community.docker.docker_network module <community.docker.docker_network#module>` provides full control over Docker networks.
docker_network_info module
- The :ref:`community.docker.docker_network_info module <ansible_collections.community.docker.docker_network_info_module>` allows you to inspect Docker networks.
+ The :ansplugin:`community.docker.docker_network_info module <community.docker.docker_network_info#module>` allows you to inspect Docker networks.
docker_volume_info module
- The :ref:`community.docker.docker_volume_info module <ansible_collections.community.docker.docker_volume_info_module>` provides full control over Docker volumes.
+ The :ansplugin:`community.docker.docker_volume_info module <community.docker.docker_volume_info#module>` provides full control over Docker volumes.
docker_volume module
- The :ref:`community.docker.docker_volume module <ansible_collections.community.docker.docker_volume_module>` allows you to inspect Docker volumes.
+ The :ansplugin:`community.docker.docker_volume module <community.docker.docker_volume#module>` allows you to inspect Docker volumes.
docker_container module
- The :ref:`community.docker.docker_container module <ansible_collections.community.docker.docker_container_module>` manages the container lifecycle by providing the ability to create, update, stop, start and destroy a Docker container.
+ The :ansplugin:`community.docker.docker_container module <community.docker.docker_container#module>` manages the container lifecycle by providing the ability to create, update, stop, start and destroy a Docker container.
+
+ docker_container_copy_into
+ The :ansplugin:`community.docker.docker_container_copy_into module <community.docker.docker_container_copy_into#module>` allows you to copy files from the control node into a container.
+
+ docker_container_exec
+ The :ansplugin:`community.docker.docker_container_exec module <community.docker.docker_container_exec#module>` allows you to execute commands in a running container.
docker_container_info module
- The :ref:`community.docker.docker_container_info module <ansible_collections.community.docker.docker_container_info_module>` allows you to inspect a Docker container.
+ The :ansplugin:`community.docker.docker_container_info module <community.docker.docker_container_info#module>` allows you to inspect a Docker container.
+
+ docker_plugin
+ The :ansplugin:`community.docker.docker_plugin module <community.docker.docker_plugin#module>` allows you to manage Docker plugins.
Docker Compose
--------------
-The :ref:`community.docker.docker_compose module <ansible_collections.community.docker.docker_compose_module>`
+Docker Compose v2
+.................
+
+There are two modules for working with Docker compose projects:
+
+ community.docker.docker_compose_v2
+ The :ansplugin:`community.docker.docker_compose_v2 module <community.docker.docker_compose_v2#module>` allows you to use your existing Docker compose files to orchestrate containers on a single Docker daemon or on Swarm.
+
+ community.docker.docker_compose_v2_pull
+ The :ansplugin:`community.docker.docker_compose_v2_pull module <community.docker.docker_compose_v2_pull#module>` allows you to pull Docker compose projects.
+
+These modules use the Docker CLI "compose" plugin (``docker compose``), and thus needs access to the Docker CLI tool.
+No further requirements next to to the CLI tool and its Docker Compose plugin are needed.
+
+Docker Compose v1
+.................
+
+The :ansplugin:`community.docker.docker_compose module <community.docker.docker_compose#module>`
allows you to use your existing Docker compose files to orchestrate containers on a single Docker daemon or on Swarm.
-Supports compose versions 1 and 2.
+This module uses the out-dated and End of Life version 1.x of Docker Compose. It should mainly be used for legacy systems
+which still have to use that version of Docker Compose.
-Next to Docker SDK for Python, you need to install `docker-compose <https://github.com/docker/compose>`_ on the remote machines to use the module.
+You need to install the `old Python docker-compose <https://pypi.org/project/docker-compose/>`_ on the remote machines to use the module.
Docker Machine
--------------
-The :ref:`community.docker.docker_machine inventory plugin <ansible_collections.community.docker.docker_machine_inventory>` allows you to dynamically add Docker Machine hosts to your Ansible inventory.
+The :ansplugin:`community.docker.docker_machine inventory plugin <community.docker.docker_machine#inventory>` allows you to dynamically add Docker Machine hosts to your Ansible inventory.
-Docker stack
-------------
+Docker Swarm stack
+------------------
-The :ref:`community.docker.docker_stack module <ansible_collections.community.docker.docker_stack_module>` module allows you to control Docker stacks. Information on stacks can be retrieved by the :ref:`community.docker.docker_stack_info module <ansible_collections.community.docker.docker_stack_info_module>`, and information on stack tasks can be retrieved by the :ref:`community.docker.docker_stack_task_info module <ansible_collections.community.docker.docker_stack_task_info_module>`.
+The :ansplugin:`community.docker.docker_stack module <community.docker.docker_stack#module>` module allows you to control Docker Swarm stacks. Information on Swarm stacks can be retrieved by the :ansplugin:`community.docker.docker_stack_info module <community.docker.docker_stack_info#module>`, and information on Swarm stack tasks can be retrieved by the :ansplugin:`community.docker.docker_stack_task_info module <community.docker.docker_stack_task_info#module>`.
Docker Swarm
@@ -192,19 +303,19 @@ Swarm management
One inventory plugin and several modules are provided to manage Docker Swarms:
docker_swarm inventory plugin
- The :ref:`community.docker.docker_swarm inventory plugin <ansible_collections.community.docker.docker_swarm_inventory>` allows you to dynamically add all Docker Swarm nodes to your Ansible inventory.
+ The :ansplugin:`community.docker.docker_swarm inventory plugin <community.docker.docker_swarm#inventory>` allows you to dynamically add all Docker Swarm nodes to your Ansible inventory.
docker_swarm module
- The :ref:`community.docker.docker_swarm module <ansible_collections.community.docker.docker_swarm_module>` allows you to globally configure Docker Swarm manager nodes to join and leave swarms, and to change the Docker Swarm configuration.
+ The :ansplugin:`community.docker.docker_swarm module <community.docker.docker_swarm#module>` allows you to globally configure Docker Swarm manager nodes to join and leave swarms, and to change the Docker Swarm configuration.
docker_swarm_info module
- The :ref:`community.docker.docker_swarm_info module <ansible_collections.community.docker.docker_swarm_info_module>` allows you to retrieve information on Docker Swarm.
+ The :ansplugin:`community.docker.docker_swarm_info module <community.docker.docker_swarm_info#module>` allows you to retrieve information on Docker Swarm.
docker_node module
- The :ref:`community.docker.docker_node module <ansible_collections.community.docker.docker_node_module>` allows you to manage Docker Swarm nodes.
+ The :ansplugin:`community.docker.docker_node module <community.docker.docker_node#module>` allows you to manage Docker Swarm nodes.
docker_node_info module
- The :ref:`community.docker.docker_node_info module <ansible_collections.community.docker.docker_node_info_module>` allows you to retrieve information on Docker Swarm nodes.
+ The :ansplugin:`community.docker.docker_node_info module <community.docker.docker_node_info#module>` allows you to retrieve information on Docker Swarm nodes.
Configuration management
........................
@@ -212,21 +323,12 @@ Configuration management
The community.docker collection offers modules to manage Docker Swarm configurations and secrets:
docker_config module
- The :ref:`community.docker.docker_config module <ansible_collections.community.docker.docker_config_module>` allows you to create and modify Docker Swarm configs.
+ The :ansplugin:`community.docker.docker_config module <community.docker.docker_config#module>` allows you to create and modify Docker Swarm configs.
docker_secret module
- The :ref:`community.docker.docker_secret module <ansible_collections.community.docker.docker_secret_module>` allows you to create and modify Docker Swarm secrets.
-
+ The :ansplugin:`community.docker.docker_secret module <community.docker.docker_secret#module>` allows you to create and modify Docker Swarm secrets.
Swarm services
..............
-Docker Swarm services can be created and updated with the :ref:`community.docker.docker_swarm_service module <ansible_collections.community.docker.docker_swarm_service_module>`, and information on them can be queried by the :ref:`community.docker.docker_swarm_service_info module <ansible_collections.community.docker.docker_swarm_service_info_module>`.
-
-
-Helpful links
--------------
-
-Still using Dockerfile to build images? Check out `ansible-bender <https://github.com/ansible-community/ansible-bender>`_, and start building images from your Ansible playbooks.
-
-Use `Ansible Operator <https://learn.openshift.com/ansibleop/ansible-operator-overview/>`_ to launch your docker-compose file on `OpenShift <https://www.okd.io/>`_. Go from an app on your laptop to a fully scalable app in the cloud with Kubernetes in just a few moments.
+Docker Swarm services can be created and updated with the :ansplugin:`community.docker.docker_swarm_service module <community.docker.docker_swarm_service#module>`, and information on them can be queried by the :ansplugin:`community.docker.docker_swarm_service_info module <community.docker.docker_swarm_service_info#module>`.
diff --git a/ansible_collections/community/docker/meta/runtime.yml b/ansible_collections/community/docker/meta/runtime.yml
index 7616e6fea..0ddd09fa3 100644
--- a/ansible_collections/community/docker/meta/runtime.yml
+++ b/ansible_collections/community/docker/meta/runtime.yml
@@ -7,6 +7,8 @@ requires_ansible: '>=2.11.0'
action_groups:
docker:
- docker_compose
+ - docker_compose_v2
+ - docker_compose_v2_pull
- docker_config
- docker_container
- docker_container_copy_into
@@ -14,8 +16,14 @@ action_groups:
- docker_container_info
- docker_host_info
- docker_image
+ - docker_image_build
+ - docker_image_export
- docker_image_info
- docker_image_load
+ - docker_image_pull
+ - docker_image_push
+ - docker_image_remove
+ - docker_image_tag
- docker_login
- docker_network
- docker_network_info
@@ -24,6 +32,9 @@ action_groups:
- docker_plugin
- docker_prune
- docker_secret
+ - docker_stack
+ - docker_stack_info
+ - docker_stack_task_info
- docker_swarm
- docker_swarm_info
- docker_swarm_service
diff --git a/ansible_collections/community/docker/plugins/action/docker_container_copy_into.py b/ansible_collections/community/docker/plugins/action/docker_container_copy_into.py
index 372cbd0a3..fed0af00b 100644
--- a/ansible_collections/community/docker/plugins/action/docker_container_copy_into.py
+++ b/ansible_collections/community/docker/plugins/action/docker_container_copy_into.py
@@ -15,7 +15,7 @@ from ansible_collections.community.docker.plugins.module_utils._scramble import
class ActionModule(ActionBase):
- # Set to True when transfering files to the remote
+ # Set to True when transferring files to the remote
TRANSFERS_FILES = False
def run(self, tmp=None, task_vars=None):
diff --git a/ansible_collections/community/docker/plugins/connection/docker.py b/ansible_collections/community/docker/plugins/connection/docker.py
index ba2249299..68247dae2 100644
--- a/ansible_collections/community/docker/plugins/connection/docker.py
+++ b/ansible_collections/community/docker/plugins/connection/docker.py
@@ -20,8 +20,7 @@ description:
- Run commands or put/fetch files to an existing docker container.
- Uses the Docker CLI to execute commands in the container. If you prefer
to directly connect to the Docker daemon, use the
- R(community.docker.docker_api,ansible_collections.community.docker.docker_api_connection)
- connection plugin.
+ P(community.docker.docker_api#connection) connection plugin.
options:
remote_addr:
description:
diff --git a/ansible_collections/community/docker/plugins/connection/docker_api.py b/ansible_collections/community/docker/plugins/connection/docker_api.py
index 24c95f55a..3b99281c3 100644
--- a/ansible_collections/community/docker/plugins/connection/docker_api.py
+++ b/ansible_collections/community/docker/plugins/connection/docker_api.py
@@ -15,8 +15,7 @@ description:
- Run commands or put/fetch files to an existing docker container.
- Uses the L(requests library,https://pypi.org/project/requests/) to interact
directly with the Docker daemon instead of using the Docker CLI. Use the
- R(community.docker.docker,ansible_collections.community.docker.docker_connection)
- connection plugin if you want to use the Docker CLI.
+ P(community.docker.docker#connection) connection plugin if you want to use the Docker CLI.
notes:
- Does B(not work with TCP TLS sockets)! This is caused by the inability to send C(close_notify) without closing the connection
with Python's C(SSLSocket)s. See U(https://github.com/ansible-collections/community.docker/issues/605) for more information.
diff --git a/ansible_collections/community/docker/plugins/connection/nsenter.py b/ansible_collections/community/docker/plugins/connection/nsenter.py
index fff36afbb..f429f8cef 100644
--- a/ansible_collections/community/docker/plugins/connection/nsenter.py
+++ b/ansible_collections/community/docker/plugins/connection/nsenter.py
@@ -128,7 +128,7 @@ class Connection(ConnectionBase):
# This plugin does not support pipelining. This diverges from the behavior of
# the core "local" connection plugin that this one derives from.
if sudoable and self.become and self.become.expect_prompt():
- # Create a pty if sudoable for privlege escalation that needs it.
+ # Create a pty if sudoable for privilege escalation that needs it.
# Falls back to using a standard pipe if this fails, which may
# cause the command to fail in certain situations where we are escalating
# privileges or the command otherwise needs a pty.
diff --git a/ansible_collections/community/docker/plugins/doc_fragments/compose_v2.py b/ansible_collections/community/docker/plugins/doc_fragments/compose_v2.py
new file mode 100644
index 000000000..4e21f974c
--- /dev/null
+++ b/ansible_collections/community/docker/plugins/doc_fragments/compose_v2.py
@@ -0,0 +1,63 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2023, Felix Fontein <felix@fontein.de>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+
+class ModuleDocFragment(object):
+
+ # Docker doc fragment
+ DOCUMENTATION = r'''
+options:
+ project_src:
+ description:
+ - Path to a directory containing a Compose file
+ (C(compose.yml), C(compose.yaml), C(docker-compose.yml), or C(docker-compose.yaml)).
+ - If O(files) is provided, will look for these files in this directory instead.
+ type: path
+ required: true
+ project_name:
+ description:
+ - Provide a project name. If not provided, the project name is taken from the basename of O(project_src).
+ type: str
+ files:
+ description:
+ - List of Compose file names relative to O(project_src) to be used instead of the main Compose file
+ (C(compose.yml), C(compose.yaml), C(docker-compose.yml), or C(docker-compose.yaml)).
+ - Files are loaded and merged in the order given.
+ type: list
+ elements: path
+ version_added: 3.7.0
+ env_files:
+ description:
+ - By default environment files are loaded from a C(.env) file located directly under the O(project_src) directory.
+ - O(env_files) can be used to specify the path of one or multiple custom environment files instead.
+ - The path is relative to the O(project_src) directory.
+ type: list
+ elements: path
+ profiles:
+ description:
+ - List of profiles to enable when starting services.
+ - Equivalent to C(docker compose --profile).
+ type: list
+ elements: str
+notes:
+ - |-
+ The Docker compose CLI plugin has no stable output format (see for example U(https://github.com/docker/compose/issues/10872)),
+ and for the main operations also no machine friendly output format. The module tries to accomodate this with various
+ version-dependent behavior adjustments and with testing older and newer versions of the Docker compose CLI plugin.
+
+ Currently the module is tested with multiple plugin versions between 2.18.1 and 2.23.3. The exact list of plugin versions
+ will change over time. New releases of the Docker compose CLI plugin can break this module at any time.
+'''
+
+ # The following needs to be kept in sync with the compose_v2 module utils
+ MINIMUM_VERSION = r'''
+options: {}
+requirements:
+ - "Docker CLI with Docker compose plugin 2.18.0 or later"
+'''
diff --git a/ansible_collections/community/docker/plugins/doc_fragments/docker.py b/ansible_collections/community/docker/plugins/doc_fragments/docker.py
index 4c537850e..92989a97b 100644
--- a/ansible_collections/community/docker/plugins/doc_fragments/docker.py
+++ b/ansible_collections/community/docker/plugins/doc_fragments/docker.py
@@ -16,25 +16,27 @@ options:
docker_host:
description:
- The URL or Unix socket path used to connect to the Docker API. To connect to a remote host, provide the
- TCP connection string. For example, C(tcp://192.0.2.23:2376). If TLS is used to encrypt the connection,
+ TCP connection string. For example, V(tcp://192.0.2.23:2376). If TLS is used to encrypt the connection,
the module will automatically replace C(tcp) in the connection URL with C(https).
- - If the value is not specified in the task, the value of environment variable C(DOCKER_HOST) will be used
+ - If the value is not specified in the task, the value of environment variable E(DOCKER_HOST) will be used
instead. If the environment variable is not set, the default value will be used.
type: str
- default: unix://var/run/docker.sock
+ default: unix:///var/run/docker.sock
aliases: [ docker_url ]
tls_hostname:
description:
- When verifying the authenticity of the Docker Host server, provide the expected name of the server.
- - If the value is not specified in the task, the value of environment variable C(DOCKER_TLS_HOSTNAME) will
+ - If the value is not specified in the task, the value of environment variable E(DOCKER_TLS_HOSTNAME) will
be used instead. If the environment variable is not set, the default value will be used.
- - Note that this option had a default value C(localhost) in older versions. It was removed in community.docker 3.0.0.
+ - Note that this option had a default value V(localhost) in older versions. It was removed in community.docker 3.0.0.
+ - B(Note:) this option is no longer supported for Docker SDK for Python 7.0.0+. Specifying it with Docker SDK for
+ Python 7.0.0 or newer will lead to an error.
type: str
api_version:
description:
- The version of the Docker API running on the Docker Host.
- Defaults to the latest version of the API supported by Docker SDK for Python and the docker daemon.
- - If the value is not specified in the task, the value of environment variable C(DOCKER_API_VERSION) will be
+ - If the value is not specified in the task, the value of environment variable E(DOCKER_API_VERSION) will be
used instead. If the environment variable is not set, the default value will be used.
type: str
default: auto
@@ -42,42 +44,46 @@ options:
timeout:
description:
- The maximum amount of time in seconds to wait on a response from the API.
- - If the value is not specified in the task, the value of environment variable C(DOCKER_TIMEOUT) will be used
+ - If the value is not specified in the task, the value of environment variable E(DOCKER_TIMEOUT) will be used
instead. If the environment variable is not set, the default value will be used.
type: int
default: 60
- ca_cert:
+ ca_path:
description:
- Use a CA certificate when performing server verification by providing the path to a CA certificate file.
- - If the value is not specified in the task and the environment variable C(DOCKER_CERT_PATH) is set,
- the file C(ca.pem) from the directory specified in the environment variable C(DOCKER_CERT_PATH) will be used.
+ - If the value is not specified in the task and the environment variable E(DOCKER_CERT_PATH) is set,
+ the file C(ca.pem) from the directory specified in the environment variable E(DOCKER_CERT_PATH) will be used.
+ - This option was called O(ca_cert) and got renamed to O(ca_path) in community.docker 3.6.0. The old name has
+ been added as an alias and can still be used.
type: path
- aliases: [ tls_ca_cert, cacert_path ]
+ aliases: [ ca_cert, tls_ca_cert, cacert_path ]
client_cert:
description:
- Path to the client's TLS certificate file.
- - If the value is not specified in the task and the environment variable C(DOCKER_CERT_PATH) is set,
- the file C(cert.pem) from the directory specified in the environment variable C(DOCKER_CERT_PATH) will be used.
+ - If the value is not specified in the task and the environment variable E(DOCKER_CERT_PATH) is set,
+ the file C(cert.pem) from the directory specified in the environment variable E(DOCKER_CERT_PATH) will be used.
type: path
aliases: [ tls_client_cert, cert_path ]
client_key:
description:
- Path to the client's TLS key file.
- - If the value is not specified in the task and the environment variable C(DOCKER_CERT_PATH) is set,
- the file C(key.pem) from the directory specified in the environment variable C(DOCKER_CERT_PATH) will be used.
+ - If the value is not specified in the task and the environment variable E(DOCKER_CERT_PATH) is set,
+ the file C(key.pem) from the directory specified in the environment variable E(DOCKER_CERT_PATH) will be used.
type: path
aliases: [ tls_client_key, key_path ]
ssl_version:
description:
- - Provide a valid SSL version number. Default value determined by ssl.py module.
- - If the value is not specified in the task, the value of environment variable C(DOCKER_SSL_VERSION) will be
+ - Provide a valid SSL version number. Default value determined by L(SSL Python module, https://docs.python.org/3/library/ssl.html).
+ - If the value is not specified in the task, the value of environment variable E(DOCKER_SSL_VERSION) will be
used instead.
+ - B(Note:) this option is no longer supported for Docker SDK for Python 7.0.0+. Specifying it with Docker SDK for
+ Python 7.0.0 or newer will lead to an error.
type: str
tls:
description:
- Secure the connection to the API by using TLS without verifying the authenticity of the Docker host
- server. Note that if I(validate_certs) is set to C(true) as well, it will take precedence.
- - If the value is not specified in the task, the value of environment variable C(DOCKER_TLS) will be used
+ server. Note that if O(validate_certs) is set to V(true) as well, it will take precedence.
+ - If the value is not specified in the task, the value of environment variable E(DOCKER_TLS) will be used
instead. If the environment variable is not set, the default value will be used.
type: bool
default: false
@@ -91,7 +97,7 @@ options:
validate_certs:
description:
- Secure the connection to the API by using TLS and verifying the authenticity of the Docker host server.
- - If the value is not specified in the task, the value of environment variable C(DOCKER_TLS_VERIFY) will be
+ - If the value is not specified in the task, the value of environment variable E(DOCKER_TLS_VERIFY) will be
used instead. If the environment variable is not set, the default value will be used.
type: bool
default: false
@@ -104,14 +110,14 @@ options:
notes:
- Connect to the Docker daemon by providing parameters with each task or by defining environment variables.
- You can define C(DOCKER_HOST), C(DOCKER_TLS_HOSTNAME), C(DOCKER_API_VERSION), C(DOCKER_CERT_PATH), C(DOCKER_SSL_VERSION),
- C(DOCKER_TLS), C(DOCKER_TLS_VERIFY) and C(DOCKER_TIMEOUT). If you are using docker machine, run the script shipped
+ You can define E(DOCKER_HOST), E(DOCKER_TLS_HOSTNAME), E(DOCKER_API_VERSION), E(DOCKER_CERT_PATH), E(DOCKER_SSL_VERSION),
+ E(DOCKER_TLS), E(DOCKER_TLS_VERIFY) and E(DOCKER_TIMEOUT). If you are using docker machine, run the script shipped
with the product that sets up the environment. It will set these variables for you. See
U(https://docs.docker.com/machine/reference/env/) for more details.
- When connecting to Docker daemon with TLS, you might need to install additional Python packages.
For the Docker SDK for Python, version 2.4 or newer, this can be done by installing C(docker[tls]) with M(ansible.builtin.pip).
- Note that the Docker SDK for Python only allows to specify the path to the Docker configuration for very few functions.
- In general, it will use C($HOME/.docker/config.json) if the C(DOCKER_CONFIG) environment variable is not specified,
+ In general, it will use C($HOME/.docker/config.json) if the E(DOCKER_CONFIG) environment variable is not specified,
and use C($DOCKER_CONFIG/config.json) otherwise.
'''
@@ -131,9 +137,11 @@ options:
timeout:
vars:
- name: ansible_docker_timeout
- ca_cert:
+ ca_path:
vars:
- name: ansible_docker_ca_cert
+ - name: ansible_docker_ca_path
+ version_added: 3.6.0
client_cert:
vars:
- name: ansible_docker_client_cert
@@ -189,25 +197,25 @@ options:
docker_host:
description:
- The URL or Unix socket path used to connect to the Docker API. To connect to a remote host, provide the
- TCP connection string. For example, C(tcp://192.0.2.23:2376). If TLS is used to encrypt the connection,
+ TCP connection string. For example, V(tcp://192.0.2.23:2376). If TLS is used to encrypt the connection,
the module will automatically replace C(tcp) in the connection URL with C(https).
- - If the value is not specified in the task, the value of environment variable C(DOCKER_HOST) will be used
+ - If the value is not specified in the task, the value of environment variable E(DOCKER_HOST) will be used
instead. If the environment variable is not set, the default value will be used.
type: str
- default: unix://var/run/docker.sock
+ default: unix:///var/run/docker.sock
aliases: [ docker_url ]
tls_hostname:
description:
- When verifying the authenticity of the Docker Host server, provide the expected name of the server.
- - If the value is not specified in the task, the value of environment variable C(DOCKER_TLS_HOSTNAME) will
+ - If the value is not specified in the task, the value of environment variable E(DOCKER_TLS_HOSTNAME) will
be used instead. If the environment variable is not set, the default value will be used.
- - Note that this option had a default value C(localhost) in older versions. It was removed in community.docker 3.0.0.
+ - Note that this option had a default value V(localhost) in older versions. It was removed in community.docker 3.0.0.
type: str
api_version:
description:
- The version of the Docker API running on the Docker Host.
- Defaults to the latest version of the API supported by this collection and the docker daemon.
- - If the value is not specified in the task, the value of environment variable C(DOCKER_API_VERSION) will be
+ - If the value is not specified in the task, the value of environment variable E(DOCKER_API_VERSION) will be
used instead. If the environment variable is not set, the default value will be used.
type: str
default: auto
@@ -215,42 +223,44 @@ options:
timeout:
description:
- The maximum amount of time in seconds to wait on a response from the API.
- - If the value is not specified in the task, the value of environment variable C(DOCKER_TIMEOUT) will be used
+ - If the value is not specified in the task, the value of environment variable E(DOCKER_TIMEOUT) will be used
instead. If the environment variable is not set, the default value will be used.
type: int
default: 60
- ca_cert:
+ ca_path:
description:
- Use a CA certificate when performing server verification by providing the path to a CA certificate file.
- - If the value is not specified in the task and the environment variable C(DOCKER_CERT_PATH) is set,
- the file C(ca.pem) from the directory specified in the environment variable C(DOCKER_CERT_PATH) will be used.
+ - If the value is not specified in the task and the environment variable E(DOCKER_CERT_PATH) is set,
+ the file C(ca.pem) from the directory specified in the environment variable E(DOCKER_CERT_PATH) will be used.
+ - This option was called O(ca_cert) and got renamed to O(ca_path) in community.docker 3.6.0. The old name has
+ been added as an alias and can still be used.
type: path
- aliases: [ tls_ca_cert, cacert_path ]
+ aliases: [ ca_cert, tls_ca_cert, cacert_path ]
client_cert:
description:
- Path to the client's TLS certificate file.
- - If the value is not specified in the task and the environment variable C(DOCKER_CERT_PATH) is set,
- the file C(cert.pem) from the directory specified in the environment variable C(DOCKER_CERT_PATH) will be used.
+ - If the value is not specified in the task and the environment variable E(DOCKER_CERT_PATH) is set,
+ the file C(cert.pem) from the directory specified in the environment variable E(DOCKER_CERT_PATH) will be used.
type: path
aliases: [ tls_client_cert, cert_path ]
client_key:
description:
- Path to the client's TLS key file.
- - If the value is not specified in the task and the environment variable C(DOCKER_CERT_PATH) is set,
- the file C(key.pem) from the directory specified in the environment variable C(DOCKER_CERT_PATH) will be used.
+ - If the value is not specified in the task and the environment variable E(DOCKER_CERT_PATH) is set,
+ the file C(key.pem) from the directory specified in the environment variable E(DOCKER_CERT_PATH) will be used.
type: path
aliases: [ tls_client_key, key_path ]
ssl_version:
description:
- - Provide a valid SSL version number. Default value determined by ssl.py module.
- - If the value is not specified in the task, the value of environment variable C(DOCKER_SSL_VERSION) will be
+ - Provide a valid SSL version number. Default value determined by L(SSL Python module, https://docs.python.org/3/library/ssl.html).
+ - If the value is not specified in the task, the value of environment variable E(DOCKER_SSL_VERSION) will be
used instead.
type: str
tls:
description:
- Secure the connection to the API by using TLS without verifying the authenticity of the Docker host
- server. Note that if I(validate_certs) is set to C(true) as well, it will take precedence.
- - If the value is not specified in the task, the value of environment variable C(DOCKER_TLS) will be used
+ server. Note that if O(validate_certs) is set to V(true) as well, it will take precedence.
+ - If the value is not specified in the task, the value of environment variable E(DOCKER_TLS) will be used
instead. If the environment variable is not set, the default value will be used.
type: bool
default: false
@@ -263,7 +273,7 @@ options:
validate_certs:
description:
- Secure the connection to the API by using TLS and verifying the authenticity of the Docker host server.
- - If the value is not specified in the task, the value of environment variable C(DOCKER_TLS_VERIFY) will be
+ - If the value is not specified in the task, the value of environment variable E(DOCKER_TLS_VERIFY) will be
used instead. If the environment variable is not set, the default value will be used.
type: bool
default: false
@@ -276,14 +286,12 @@ options:
notes:
- Connect to the Docker daemon by providing parameters with each task or by defining environment variables.
- You can define C(DOCKER_HOST), C(DOCKER_TLS_HOSTNAME), C(DOCKER_API_VERSION), C(DOCKER_CERT_PATH), C(DOCKER_SSL_VERSION),
- C(DOCKER_TLS), C(DOCKER_TLS_VERIFY) and C(DOCKER_TIMEOUT). If you are using docker machine, run the script shipped
+ You can define E(DOCKER_HOST), E(DOCKER_TLS_HOSTNAME), E(DOCKER_API_VERSION), E(DOCKER_CERT_PATH), E(DOCKER_SSL_VERSION),
+ E(DOCKER_TLS), E(DOCKER_TLS_VERIFY) and E(DOCKER_TIMEOUT). If you are using docker machine, run the script shipped
with the product that sets up the environment. It will set these variables for you. See
U(https://docs.docker.com/machine/reference/env/) for more details.
-# - When connecting to Docker daemon with TLS, you might need to install additional Python packages.
-# For the Docker SDK for Python, version 2.4 or newer, this can be done by installing C(docker[tls]) with M(ansible.builtin.pip).
# - Note that the Docker SDK for Python only allows to specify the path to the Docker configuration for very few functions.
-# In general, it will use C($HOME/.docker/config.json) if the C(DOCKER_CONFIG) environment variable is not specified,
+# In general, it will use C($HOME/.docker/config.json) if the E(DOCKER_CONFIG) environment variable is not specified,
# and use C($DOCKER_CONFIG/config.json) otherwise.
- This module does B(not) use the L(Docker SDK for Python,https://docker-py.readthedocs.io/en/stable/) to
communicate with the Docker daemon. It uses code derived from the Docker SDK or Python that is included in this
@@ -291,7 +299,96 @@ notes:
requirements:
- requests
- pywin32 (when using named pipes on Windows 32)
- - paramiko (when using SSH with I(use_ssh_client=false))
+ - paramiko (when using SSH with O(use_ssh_client=false))
- pyOpenSSL (when using TLS)
- backports.ssl_match_hostname (when using TLS on Python 2)
'''
+
+ # Docker doc fragment when using the Docker CLI
+ CLI_DOCUMENTATION = r'''
+options:
+ docker_cli:
+ description:
+ - Path to the Docker CLI. If not provided, will search for Docker CLI on the E(PATH).
+ type: path
+ docker_host:
+ description:
+ - The URL or Unix socket path used to connect to the Docker API. To connect to a remote host, provide the
+ TCP connection string. For example, V(tcp://192.0.2.23:2376). If TLS is used to encrypt the connection,
+ the module will automatically replace C(tcp) in the connection URL with C(https).
+ - If the value is not specified in the task, the value of environment variable E(DOCKER_HOST) will be used
+ instead. If the environment variable is not set, the default value will be used.
+ type: str
+ default: unix:///var/run/docker.sock
+ aliases: [ docker_url ]
+ tls_hostname:
+ description:
+ - When verifying the authenticity of the Docker Host server, provide the expected name of the server.
+ - If the value is not specified in the task, the value of environment variable E(DOCKER_TLS_HOSTNAME) will
+ be used instead. If the environment variable is not set, the default value will be used.
+ type: str
+ api_version:
+ description:
+ - The version of the Docker API running on the Docker Host.
+ - Defaults to the latest version of the API supported by this collection and the docker daemon.
+ - If the value is not specified in the task, the value of environment variable E(DOCKER_API_VERSION) will be
+ used instead. If the environment variable is not set, the default value will be used.
+ type: str
+ default: auto
+ aliases: [ docker_api_version ]
+ ca_path:
+ description:
+ - Use a CA certificate when performing server verification by providing the path to a CA certificate file.
+ - If the value is not specified in the task and the environment variable E(DOCKER_CERT_PATH) is set,
+ the file C(ca.pem) from the directory specified in the environment variable E(DOCKER_CERT_PATH) will be used.
+ type: path
+ aliases: [ ca_cert, tls_ca_cert, cacert_path ]
+ client_cert:
+ description:
+ - Path to the client's TLS certificate file.
+ - If the value is not specified in the task and the environment variable E(DOCKER_CERT_PATH) is set,
+ the file C(cert.pem) from the directory specified in the environment variable E(DOCKER_CERT_PATH) will be used.
+ type: path
+ aliases: [ tls_client_cert, cert_path ]
+ client_key:
+ description:
+ - Path to the client's TLS key file.
+ - If the value is not specified in the task and the environment variable E(DOCKER_CERT_PATH) is set,
+ the file C(key.pem) from the directory specified in the environment variable E(DOCKER_CERT_PATH) will be used.
+ type: path
+ aliases: [ tls_client_key, key_path ]
+ tls:
+ description:
+ - Secure the connection to the API by using TLS without verifying the authenticity of the Docker host
+ server. Note that if O(validate_certs) is set to V(true) as well, it will take precedence.
+ - If the value is not specified in the task, the value of environment variable E(DOCKER_TLS) will be used
+ instead. If the environment variable is not set, the default value will be used.
+ type: bool
+ default: false
+ validate_certs:
+ description:
+ - Secure the connection to the API by using TLS and verifying the authenticity of the Docker host server.
+ - If the value is not specified in the task, the value of environment variable E(DOCKER_TLS_VERIFY) will be
+ used instead. If the environment variable is not set, the default value will be used.
+ type: bool
+ default: false
+ aliases: [ tls_verify ]
+ # debug:
+ # description:
+ # - Debug mode
+ # type: bool
+ # default: false
+ cli_context:
+ description:
+ - The Docker CLI context to use.
+ type: str
+
+notes:
+ - Connect to the Docker daemon by providing parameters with each task or by defining environment variables.
+ You can define E(DOCKER_HOST), E(DOCKER_TLS_HOSTNAME), E(DOCKER_API_VERSION), E(DOCKER_CERT_PATH),
+ E(DOCKER_TLS), E(DOCKER_TLS_VERIFY) and E(DOCKER_TIMEOUT). If you are using docker machine, run the script shipped
+ with the product that sets up the environment. It will set these variables for you. See
+ U(https://docs.docker.com/machine/reference/env/) for more details.
+ - This module does B(not) use the L(Docker SDK for Python,https://docker-py.readthedocs.io/en/stable/) to
+ communicate with the Docker daemon. It directly calls the Docker CLI program.
+'''
diff --git a/ansible_collections/community/docker/plugins/inventory/docker_containers.py b/ansible_collections/community/docker/plugins/inventory/docker_containers.py
index a82cda955..75b49ff92 100644
--- a/ansible_collections/community/docker/plugins/inventory/docker_containers.py
+++ b/ansible_collections/community/docker/plugins/inventory/docker_containers.py
@@ -21,13 +21,14 @@ author:
extends_documentation_fragment:
- ansible.builtin.constructed
- community.docker.docker.api_documentation
+ - community.library_inventory_filtering_v1.inventory_filter
description:
- Reads inventories from the Docker API.
- Uses a YAML configuration file that ends with C(docker.[yml|yaml]).
options:
plugin:
description:
- - The name of this plugin, it should always be set to C(community.docker.docker_containers)
+ - The name of this plugin, it should always be set to V(community.docker.docker_containers)
for this plugin to recognize it as it's own.
type: str
required: true
@@ -36,17 +37,14 @@ options:
connection_type:
description:
- Which connection type to use the containers.
- - One way to connect to containers is to use SSH (C(ssh)). For this, the options I(default_ip) and
- I(private_ssh_port) are used. This requires that a SSH daemon is running inside the containers.
- - Alternatively, C(docker-cli) selects the
- R(docker connection plugin,ansible_collections.community.docker.docker_connection),
- and C(docker-api) (default) selects the
- R(docker_api connection plugin,ansible_collections.community.docker.docker_api_connection).
- - When C(docker-api) is used, all Docker daemon configuration values are passed from the inventory plugin
- to the connection plugin. This can be controlled with I(configure_docker_daemon).
- - Note that the R(docker_api connection plugin,ansible_collections.community.docker.docker_api_connection)
- does B(not work with TCP TLS sockets)! See U(https://github.com/ansible-collections/community.docker/issues/605)
- for more information.
+ - One way to connect to containers is to use SSH (V(ssh)). For this, the options O(default_ip) and
+ O(private_ssh_port) are used. This requires that a SSH daemon is running inside the containers.
+ - Alternatively, V(docker-cli) selects the P(community.docker.docker#connection) connection plugin,
+ and V(docker-api) (default) selects the P(community.docker.docker_api#connection) connection plugin.
+ - When V(docker-api) is used, all Docker daemon configuration values are passed from the inventory plugin
+ to the connection plugin. This can be controlled with O(configure_docker_daemon).
+ - Note that the P(community.docker.docker_api#connection) does B(not work with TCP TLS sockets)!
+ See U(https://github.com/ansible-collections/community.docker/issues/605) for more information.
type: str
default: docker-api
choices:
@@ -57,7 +55,7 @@ options:
configure_docker_daemon:
description:
- Whether to pass all Docker daemon configuration from the inventory plugin to the connection plugin.
- - Only used when I(connection_type=docker-api).
+ - Only used when O(connection_type=docker-api).
type: bool
default: true
version_added: 1.8.0
@@ -67,8 +65,8 @@ options:
- Toggle to (not) include all available inspection metadata.
- Note that all top-level keys will be transformed to the format C(docker_xxx).
For example, C(HostConfig) is converted to C(docker_hostconfig).
- - If this is C(false), these values can only be used during I(constructed), I(groups), and I(keyed_groups).
- - The C(docker) inventory script always added these variables, so for compatibility set this to C(true).
+ - If this is V(false), these values can only be used during O(compose), O(groups), and O(keyed_groups).
+ - The C(docker) inventory script always added these variables, so for compatibility set this to V(true).
type: bool
default: false
@@ -76,14 +74,14 @@ options:
description:
- The IP address to assign to ansible_host when the container's SSH port is mapped to interface
'0.0.0.0'.
- - Only used if I(connection_type) is C(ssh).
+ - Only used if O(connection_type) is V(ssh).
type: str
default: 127.0.0.1
private_ssh_port:
description:
- The port containers use for SSH.
- - Only used if I(connection_type) is C(ssh).
+ - Only used if O(connection_type) is V(ssh).
type: int
default: 22
@@ -96,20 +94,23 @@ options:
- "C(image_<image name>): contains the containers that have the image C(<image name>)."
- "C(stack_<stack name>): contains the containers that belong to the stack C(<stack name>)."
- "C(service_<service name>): contains the containers that belong to the service C(<service name>)"
- - "C(<docker_host>): contains the containers which belong to the Docker daemon I(docker_host).
+ - "C(<docker_host>): contains the containers which belong to the Docker daemon O(docker_host).
Useful if you run this plugin against multiple Docker daemons."
- "C(running): contains all containers that are running."
- "C(stopped): contains all containers that are not running."
- - If this is not set to C(true), you should use keyed groups to add the containers to groups.
+ - If this is not set to V(true), you should use keyed groups to add the containers to groups.
See the examples for how to do that.
type: bool
default: false
+
+ filters:
+ version_added: 3.5.0
'''
EXAMPLES = '''
# Minimal example using local Docker daemon
plugin: community.docker.docker_containers
-docker_host: unix://var/run/docker.sock
+docker_host: unix:///var/run/docker.sock
# Minimal example using remote Docker daemon
plugin: community.docker.docker_containers
@@ -124,7 +125,7 @@ tls: true
plugin: community.docker.docker_containers
docker_host: tcp://my-docker-host:2376
validate_certs: true
-ca_cert: /somewhere/ca.pem
+ca_path: /somewhere/ca.pem
client_key: /somewhere/key.pem
client_cert: /somewhere/cert.pem
@@ -147,6 +148,18 @@ connection_type: ssh
compose:
ansible_ssh_host: ansible_ssh_host | default(docker_name[1:], true)
ansible_ssh_port: ansible_ssh_port | default(22, true)
+
+# Only consider containers which have a label 'foo', or whose name starts with 'a'
+plugin: community.docker.docker_containers
+filters:
+ # Accept all containers which have a label called 'foo'
+ - include: >-
+ "foo" in docker_config.Labels
+ # Next accept all containers whose inventory_hostname starts with 'a'
+ - include: >-
+ inventory_hostname.startswith("a")
+ # Exclude all containers that didn't match any of the above filters
+ - exclude: true
'''
import re
@@ -154,6 +167,7 @@ import re
from ansible.errors import AnsibleError
from ansible.module_utils.common.text.converters import to_native
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable
+from ansible.utils.unsafe_proxy import wrap_var as make_unsafe
from ansible_collections.community.docker.plugins.module_utils.common_api import (
RequestException,
@@ -166,6 +180,7 @@ from ansible_collections.community.docker.plugins.plugin_utils.common_api import
)
from ansible_collections.community.docker.plugins.module_utils._api.errors import APIError, DockerException
+from ansible_collections.community.library_inventory_filtering_v1.plugins.plugin_utils.inventory_filter import parse_filters, filter_host
MIN_DOCKER_API = None
@@ -212,6 +227,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
if value is not None:
extra_facts[var_name] = value
+ filters = parse_filters(self.get_option('filters'))
for container in containers:
id = container.get('Id')
short_id = id[:13]
@@ -223,10 +239,9 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
name = short_id
full_name = id
- self.inventory.add_host(name)
facts = dict(
- docker_name=name,
- docker_short_id=short_id
+ docker_name=make_unsafe(name),
+ docker_short_id=make_unsafe(short_id),
)
full_facts = dict()
@@ -241,26 +256,26 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
running = state.get('Running')
+ groups = []
+
# Add container to groups
image_name = config.get('Image')
if image_name and add_legacy_groups:
- self.inventory.add_group('image_{0}'.format(image_name))
- self.inventory.add_host(name, group='image_{0}'.format(image_name))
+ groups.append('image_{0}'.format(image_name))
stack_name = labels.get('com.docker.stack.namespace')
if stack_name:
full_facts['docker_stack'] = stack_name
if add_legacy_groups:
- self.inventory.add_group('stack_{0}'.format(stack_name))
- self.inventory.add_host(name, group='stack_{0}'.format(stack_name))
+ groups.append('stack_{0}'.format(stack_name))
service_name = labels.get('com.docker.swarm.service.name')
if service_name:
full_facts['docker_service'] = service_name
if add_legacy_groups:
- self.inventory.add_group('service_{0}'.format(service_name))
- self.inventory.add_host(name, group='service_{0}'.format(service_name))
+ groups.append('service_{0}'.format(service_name))
+ ansible_connection = None
if connection_type == 'ssh':
# Figure out ssh IP and Port
try:
@@ -283,23 +298,38 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
elif connection_type == 'docker-cli':
facts.update(dict(
ansible_host=full_name,
- ansible_connection='community.docker.docker',
))
+ ansible_connection = 'community.docker.docker'
elif connection_type == 'docker-api':
facts.update(dict(
ansible_host=full_name,
- ansible_connection='community.docker.docker_api',
))
facts.update(extra_facts)
+ ansible_connection = 'community.docker.docker_api'
full_facts.update(facts)
for key, value in inspect.items():
fact_key = self._slugify(key)
full_facts[fact_key] = value
+ full_facts = make_unsafe(full_facts)
+
+ if ansible_connection:
+ for d in (facts, full_facts):
+ if 'ansible_connection' not in d:
+ d['ansible_connection'] = ansible_connection
+
+ if not filter_host(self, name, full_facts, filters):
+ continue
+
if verbose_output:
facts.update(full_facts)
+ self.inventory.add_host(name)
+ for group in groups:
+ self.inventory.add_group(group)
+ self.inventory.add_host(name, group=group)
+
for key, value in facts.items():
self.inventory.set_variable(name, key, value)
diff --git a/ansible_collections/community/docker/plugins/inventory/docker_machine.py b/ansible_collections/community/docker/plugins/inventory/docker_machine.py
index 69d946100..e3330a339 100644
--- a/ansible_collections/community/docker/plugins/inventory/docker_machine.py
+++ b/ansible_collections/community/docker/plugins/inventory/docker_machine.py
@@ -13,12 +13,13 @@ DOCUMENTATION = '''
requirements:
- L(Docker Machine,https://docs.docker.com/machine/)
extends_documentation_fragment:
- - constructed
+ - ansible.builtin.constructed
+ - community.library_inventory_filtering_v1.inventory_filter
description:
- Get inventory hosts from Docker Machine.
- Uses a YAML configuration file that ends with docker_machine.(yml|yaml).
- The plugin sets standard host variables C(ansible_host), C(ansible_port), C(ansible_user) and C(ansible_ssh_private_key).
- - The plugin stores the Docker Machine 'env' output variables in I(dm_) prefixed host variables.
+ - The plugin stores the Docker Machine 'env' output variables in C(dm_) prefixed host variables.
options:
plugin:
@@ -28,12 +29,12 @@ DOCUMENTATION = '''
daemon_env:
description:
- Whether docker daemon connection environment variables should be fetched, and how to behave if they cannot be fetched.
- - With C(require) and C(require-silently), fetch them and skip any host for which they cannot be fetched.
- A warning will be issued for any skipped host if the choice is C(require).
- - With C(optional) and C(optional-silently), fetch them and not skip hosts for which they cannot be fetched.
- A warning will be issued for hosts where they cannot be fetched if the choice is C(optional).
- - With C(skip), do not attempt to fetch the docker daemon connection environment variables.
- - If fetched successfully, the variables will be prefixed with I(dm_) and stored as host variables.
+ - With V(require) and V(require-silently), fetch them and skip any host for which they cannot be fetched.
+ A warning will be issued for any skipped host if the choice is V(require).
+ - With V(optional) and V(optional-silently), fetch them and not skip hosts for which they cannot be fetched.
+ A warning will be issued for hosts where they cannot be fetched if the choice is V(optional).
+ - With V(skip), do not attempt to fetch the docker daemon connection environment variables.
+ - If fetched successfully, the variables will be prefixed with C(dm_) and stored as host variables.
type: str
choices:
- require
@@ -44,15 +45,17 @@ DOCUMENTATION = '''
default: require
running_required:
description:
- - When C(true), hosts which Docker Machine indicates are in a state other than C(running) will be skipped.
+ - When V(true), hosts which Docker Machine indicates are in a state other than C(running) will be skipped.
type: bool
default: true
verbose_output:
description:
- - When C(true), include all available nodes metadata (for exmaple C(Image), C(Region), C(Size)) as a JSON object
+ - When V(true), include all available nodes metadata (for example C(Image), C(Region), C(Size)) as a JSON object
named C(docker_machine_node_attributes).
type: bool
default: true
+ filters:
+ version_added: 3.5.0
'''
EXAMPLES = '''
@@ -93,6 +96,9 @@ from ansible.module_utils.common.text.converters import to_text
from ansible.module_utils.common.process import get_bin_path
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable, Cacheable
from ansible.utils.display import Display
+from ansible.utils.unsafe_proxy import wrap_var as make_unsafe
+
+from ansible_collections.community.library_inventory_filtering_v1.plugins.plugin_utils.inventory_filter import parse_filters, filter_host
import json
import re
@@ -173,7 +179,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
def _inspect_docker_machine_host(self, node):
try:
- inspect_lines = self._run_command(['inspect', self.node])
+ inspect_lines = self._run_command(['inspect', node])
except subprocess.CalledProcessError:
return None
@@ -181,7 +187,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
def _ip_addr_docker_machine_host(self, node):
try:
- ip_addr = self._run_command(['ip', self.node])
+ ip_addr = self._run_command(['ip', node])
except subprocess.CalledProcessError:
return None
@@ -201,13 +207,18 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
def _populate(self):
daemon_env = self.get_option('daemon_env')
+ filters = parse_filters(self.get_option('filters'))
try:
- for self.node in self._get_machine_names():
- self.node_attrs = self._inspect_docker_machine_host(self.node)
- if not self.node_attrs:
+ for node in self._get_machine_names():
+ node_attrs = self._inspect_docker_machine_host(node)
+ if not node_attrs:
continue
- machine_name = self.node_attrs['Driver']['MachineName']
+ unsafe_node_attrs = make_unsafe(node_attrs)
+
+ machine_name = unsafe_node_attrs['Driver']['MachineName']
+ if not filter_host(self, machine_name, unsafe_node_attrs, filters):
+ continue
# query `docker-machine env` to obtain remote Docker daemon connection settings in the form of commands
# that could be used to set environment variables to influence a local Docker client:
@@ -224,40 +235,40 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
# check for valid ip address from inspect output, else explicitly use ip command to find host ip address
# this works around an issue seen with Google Compute Platform where the IP address was not available
# via the 'inspect' subcommand but was via the 'ip' subcomannd.
- if self.node_attrs['Driver']['IPAddress']:
- ip_addr = self.node_attrs['Driver']['IPAddress']
+ if unsafe_node_attrs['Driver']['IPAddress']:
+ ip_addr = unsafe_node_attrs['Driver']['IPAddress']
else:
- ip_addr = self._ip_addr_docker_machine_host(self.node)
+ ip_addr = self._ip_addr_docker_machine_host(node)
# set standard Ansible remote host connection settings to details captured from `docker-machine`
# see: https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html
- self.inventory.set_variable(machine_name, 'ansible_host', ip_addr)
- self.inventory.set_variable(machine_name, 'ansible_port', self.node_attrs['Driver']['SSHPort'])
- self.inventory.set_variable(machine_name, 'ansible_user', self.node_attrs['Driver']['SSHUser'])
- self.inventory.set_variable(machine_name, 'ansible_ssh_private_key_file', self.node_attrs['Driver']['SSHKeyPath'])
+ self.inventory.set_variable(machine_name, 'ansible_host', make_unsafe(ip_addr))
+ self.inventory.set_variable(machine_name, 'ansible_port', unsafe_node_attrs['Driver']['SSHPort'])
+ self.inventory.set_variable(machine_name, 'ansible_user', unsafe_node_attrs['Driver']['SSHUser'])
+ self.inventory.set_variable(machine_name, 'ansible_ssh_private_key_file', unsafe_node_attrs['Driver']['SSHKeyPath'])
# set variables based on Docker Machine tags
- tags = self.node_attrs['Driver'].get('Tags') or ''
- self.inventory.set_variable(machine_name, 'dm_tags', tags)
+ tags = unsafe_node_attrs['Driver'].get('Tags') or ''
+ self.inventory.set_variable(machine_name, 'dm_tags', make_unsafe(tags))
# set variables based on Docker Machine env variables
for kv in env_var_tuples:
- self.inventory.set_variable(machine_name, 'dm_{0}'.format(kv[0]), kv[1])
+ self.inventory.set_variable(machine_name, 'dm_{0}'.format(kv[0]), make_unsafe(kv[1]))
if self.get_option('verbose_output'):
- self.inventory.set_variable(machine_name, 'docker_machine_node_attributes', self.node_attrs)
+ self.inventory.set_variable(machine_name, 'docker_machine_node_attributes', unsafe_node_attrs)
# Use constructed if applicable
strict = self.get_option('strict')
# Composed variables
- self._set_composite_vars(self.get_option('compose'), self.node_attrs, machine_name, strict=strict)
+ self._set_composite_vars(self.get_option('compose'), unsafe_node_attrs, machine_name, strict=strict)
# Complex groups based on jinja2 conditionals, hosts that meet the conditional are added to group
- self._add_host_to_composed_groups(self.get_option('groups'), self.node_attrs, machine_name, strict=strict)
+ self._add_host_to_composed_groups(self.get_option('groups'), unsafe_node_attrs, machine_name, strict=strict)
# Create groups based on variable values and add the corresponding hosts to it
- self._add_host_to_keyed_groups(self.get_option('keyed_groups'), self.node_attrs, machine_name, strict=strict)
+ self._add_host_to_keyed_groups(self.get_option('keyed_groups'), unsafe_node_attrs, machine_name, strict=strict)
except Exception as e:
raise AnsibleError('Unable to fetch hosts from Docker Machine, this was the original exception: %s' %
diff --git a/ansible_collections/community/docker/plugins/inventory/docker_swarm.py b/ansible_collections/community/docker/plugins/inventory/docker_swarm.py
index ebb1da15c..0d60033f9 100644
--- a/ansible_collections/community/docker/plugins/inventory/docker_swarm.py
+++ b/ansible_collections/community/docker/plugins/inventory/docker_swarm.py
@@ -17,16 +17,17 @@ DOCUMENTATION = '''
- python >= 2.7
- L(Docker SDK for Python,https://docker-py.readthedocs.io/en/stable/) >= 1.10.0
extends_documentation_fragment:
- - constructed
+ - ansible.builtin.constructed
+ - community.library_inventory_filtering_v1.inventory_filter
description:
- Reads inventories from the Docker swarm API.
- Uses a YAML configuration file docker_swarm.[yml|yaml].
- - "The plugin returns following groups of swarm nodes: I(all) - all hosts; I(workers) - all worker nodes;
- I(managers) - all manager nodes; I(leader) - the swarm leader node;
- I(nonleaders) - all nodes except the swarm leader."
+ - "The plugin returns following groups of swarm nodes: C(all) - all hosts; C(workers) - all worker nodes;
+ C(managers) - all manager nodes; C(leader) - the swarm leader node;
+ C(nonleaders) - all nodes except the swarm leader."
options:
plugin:
- description: The name of this plugin, it should always be set to C(community.docker.docker_swarm)
+ description: The name of this plugin, it should always be set to V(community.docker.docker_swarm)
for this plugin to recognize it as it's own.
type: str
required: true
@@ -34,13 +35,13 @@ DOCUMENTATION = '''
docker_host:
description:
- Socket of a Docker swarm manager node (C(tcp), C(unix)).
- - "Use C(unix://var/run/docker.sock) to connect via local socket."
+ - "Use V(unix:///var/run/docker.sock) to connect via local socket."
type: str
required: true
aliases: [ docker_url ]
verbose_output:
description: Toggle to (not) include all available nodes metadata (for example C(Platform), C(Architecture), C(OS),
- C(EngineVersion))
+ C(EngineVersion)).
type: bool
default: true
tls:
@@ -57,11 +58,13 @@ DOCUMENTATION = '''
description: Path to the client's TLS key file.
type: path
aliases: [ tls_client_key, key_path ]
- ca_cert:
- description: Use a CA certificate when performing server verification by providing the path to a CA
- certificate file.
+ ca_path:
+ description:
+ - Use a CA certificate when performing server verification by providing the path to a CA certificate file.
+ - This option was called O(ca_cert) and got renamed to O(ca_path) in community.docker 3.6.0. The old name has
+ been added as an alias and can still be used.
type: path
- aliases: [ tls_ca_cert, cacert_path ]
+ aliases: [ ca_cert, tls_ca_cert, cacert_path ]
client_cert:
description: Path to the client's TLS certificate file.
type: path
@@ -71,7 +74,9 @@ DOCUMENTATION = '''
the server.
type: str
ssl_version:
- description: Provide a valid SSL version number. Default value determined by ssl.py module.
+ description:
+ - Provide a valid SSL version number. Default value determined
+ by L(SSL Python module, https://docs.python.org/3/library/ssl.html).
type: str
api_version:
description:
@@ -82,7 +87,7 @@ DOCUMENTATION = '''
timeout:
description:
- The maximum amount of time in seconds to wait on a response from the API.
- - If the value is not specified in the task, the value of environment variable C(DOCKER_TIMEOUT)
+ - If the value is not specified in the task, the value of environment variable E(DOCKER_TIMEOUT).
will be used instead. If the environment variable is not set, the default value will be used.
type: int
default: 60
@@ -96,20 +101,22 @@ DOCUMENTATION = '''
version_added: 1.5.0
include_host_uri:
description: Toggle to return the additional attribute C(ansible_host_uri) which contains the URI of the
- swarm leader in format of C(tcp://172.16.0.1:2376). This value may be used without additional
- modification as value of option I(docker_host) in Docker Swarm modules when connecting via API.
- The port always defaults to C(2376).
+ swarm leader in format of V(tcp://172.16.0.1:2376). This value may be used without additional
+ modification as value of option O(docker_host) in Docker Swarm modules when connecting via API.
+ The port always defaults to V(2376).
type: bool
default: false
include_host_uri_port:
- description: Override the detected port number included in I(ansible_host_uri)
+ description: Override the detected port number included in C(ansible_host_uri).
type: int
+ filters:
+ version_added: 3.5.0
'''
EXAMPLES = '''
# Minimal example using local docker
plugin: community.docker.docker_swarm
-docker_host: unix://var/run/docker.sock
+docker_host: unix:///var/run/docker.sock
# Minimal example using remote docker
plugin: community.docker.docker_swarm
@@ -124,7 +131,7 @@ tls: true
plugin: community.docker.docker_swarm
docker_host: tcp://my-docker-host:2376
validate_certs: true
-ca_cert: /somewhere/ca.pem
+ca_path: /somewhere/ca.pem
client_key: /somewhere/key.pem
client_cert: /somewhere/cert.pem
@@ -152,6 +159,9 @@ from ansible_collections.community.docker.plugins.module_utils.common import get
from ansible_collections.community.docker.plugins.module_utils.util import update_tls_hostname
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable
from ansible.parsing.utils.addresses import parse_address
+from ansible.utils.unsafe_proxy import wrap_var as make_unsafe
+
+from ansible_collections.community.library_inventory_filtering_v1.plugins.plugin_utils.inventory_filter import parse_filters, filter_host
try:
import docker
@@ -174,7 +184,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
tls=self.get_option('tls'),
tls_verify=self.get_option('validate_certs'),
key_path=self.get_option('client_key'),
- cacert_path=self.get_option('ca_cert'),
+ cacert_path=self.get_option('ca_path'),
cert_path=self.get_option('client_cert'),
tls_hostname=self.get_option('tls_hostname'),
api_version=self.get_option('api_version'),
@@ -192,6 +202,8 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
self.inventory.add_group('leader')
self.inventory.add_group('nonleaders')
+ filters = parse_filters(self.get_option('filters'))
+
if self.get_option('include_host_uri'):
if self.get_option('include_host_uri_port'):
host_uri_port = str(self.get_option('include_host_uri_port'))
@@ -202,48 +214,51 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
try:
self.nodes = self.client.nodes.list()
- for self.node in self.nodes:
- self.node_attrs = self.client.nodes.get(self.node.id).attrs
- self.inventory.add_host(self.node_attrs['ID'])
- self.inventory.add_host(self.node_attrs['ID'], group=self.node_attrs['Spec']['Role'])
- self.inventory.set_variable(self.node_attrs['ID'], 'ansible_host',
- self.node_attrs['Status']['Addr'])
+ for node in self.nodes:
+ node_attrs = self.client.nodes.get(node.id).attrs
+ unsafe_node_attrs = make_unsafe(node_attrs)
+ if not filter_host(self, unsafe_node_attrs['ID'], unsafe_node_attrs, filters):
+ continue
+ self.inventory.add_host(unsafe_node_attrs['ID'])
+ self.inventory.add_host(unsafe_node_attrs['ID'], group=unsafe_node_attrs['Spec']['Role'])
+ self.inventory.set_variable(unsafe_node_attrs['ID'], 'ansible_host',
+ unsafe_node_attrs['Status']['Addr'])
if self.get_option('include_host_uri'):
- self.inventory.set_variable(self.node_attrs['ID'], 'ansible_host_uri',
- 'tcp://' + self.node_attrs['Status']['Addr'] + ':' + host_uri_port)
+ self.inventory.set_variable(unsafe_node_attrs['ID'], 'ansible_host_uri',
+ make_unsafe('tcp://' + unsafe_node_attrs['Status']['Addr'] + ':' + host_uri_port))
if self.get_option('verbose_output'):
- self.inventory.set_variable(self.node_attrs['ID'], 'docker_swarm_node_attributes', self.node_attrs)
- if 'ManagerStatus' in self.node_attrs:
- if self.node_attrs['ManagerStatus'].get('Leader'):
+ self.inventory.set_variable(unsafe_node_attrs['ID'], 'docker_swarm_node_attributes', unsafe_node_attrs)
+ if 'ManagerStatus' in unsafe_node_attrs:
+ if unsafe_node_attrs['ManagerStatus'].get('Leader'):
# This is workaround of bug in Docker when in some cases the Leader IP is 0.0.0.0
# Check moby/moby#35437 for details
- swarm_leader_ip = parse_address(self.node_attrs['ManagerStatus']['Addr'])[0] or \
- self.node_attrs['Status']['Addr']
+ swarm_leader_ip = parse_address(node_attrs['ManagerStatus']['Addr'])[0] or \
+ unsafe_node_attrs['Status']['Addr']
if self.get_option('include_host_uri'):
- self.inventory.set_variable(self.node_attrs['ID'], 'ansible_host_uri',
- 'tcp://' + swarm_leader_ip + ':' + host_uri_port)
- self.inventory.set_variable(self.node_attrs['ID'], 'ansible_host', swarm_leader_ip)
- self.inventory.add_host(self.node_attrs['ID'], group='leader')
+ self.inventory.set_variable(unsafe_node_attrs['ID'], 'ansible_host_uri',
+ make_unsafe('tcp://' + swarm_leader_ip + ':' + host_uri_port))
+ self.inventory.set_variable(unsafe_node_attrs['ID'], 'ansible_host', make_unsafe(swarm_leader_ip))
+ self.inventory.add_host(unsafe_node_attrs['ID'], group='leader')
else:
- self.inventory.add_host(self.node_attrs['ID'], group='nonleaders')
+ self.inventory.add_host(unsafe_node_attrs['ID'], group='nonleaders')
else:
- self.inventory.add_host(self.node_attrs['ID'], group='nonleaders')
+ self.inventory.add_host(unsafe_node_attrs['ID'], group='nonleaders')
# Use constructed if applicable
strict = self.get_option('strict')
# Composed variables
self._set_composite_vars(self.get_option('compose'),
- self.node_attrs,
- self.node_attrs['ID'],
+ unsafe_node_attrs,
+ unsafe_node_attrs['ID'],
strict=strict)
# Complex groups based on jinja2 conditionals, hosts that meet the conditional are added to group
self._add_host_to_composed_groups(self.get_option('groups'),
- self.node_attrs,
- self.node_attrs['ID'],
+ unsafe_node_attrs,
+ unsafe_node_attrs['ID'],
strict=strict)
# Create groups based on variable values and add the corresponding hosts to it
self._add_host_to_keyed_groups(self.get_option('keyed_groups'),
- self.node_attrs,
- self.node_attrs['ID'],
+ unsafe_node_attrs,
+ unsafe_node_attrs['ID'],
strict=strict)
except Exception as e:
raise AnsibleError('Unable to fetch hosts from Docker swarm API, this was the original exception: %s' %
diff --git a/ansible_collections/community/docker/plugins/module_utils/_api/api/client.py b/ansible_collections/community/docker/plugins/module_utils/_api/api/client.py
index d9ec5870d..44f17924f 100644
--- a/ansible_collections/community/docker/plugins/module_utils/_api/api/client.py
+++ b/ansible_collections/community/docker/plugins/module_utils/_api/api/client.py
@@ -455,7 +455,7 @@ class APIClient(
return self._get_result_tty(stream, res, self._check_is_tty(container))
def _get_result_tty(self, stream, res, is_tty):
- # We should also use raw streaming (without keep-alives)
+ # We should also use raw streaming (without keep-alive)
# if we're dealing with a tty-enabled container.
if is_tty:
return self._stream_raw_result(res) if stream else \
diff --git a/ansible_collections/community/docker/plugins/module_utils/_api/errors.py b/ansible_collections/community/docker/plugins/module_utils/_api/errors.py
index 90dd5aada..47c284d39 100644
--- a/ansible_collections/community/docker/plugins/module_utils/_api/errors.py
+++ b/ansible_collections/community/docker/plugins/module_utils/_api/errors.py
@@ -12,6 +12,7 @@ __metaclass__ = type
from ._import_helper import HTTPError as _HTTPError
+from ansible.module_utils.common.text.converters import to_native
from ansible.module_utils.six import raise_from
@@ -32,7 +33,7 @@ def create_api_error_from_http_exception(e):
try:
explanation = response.json()['message']
except ValueError:
- explanation = (response.content or '').strip()
+ explanation = to_native((response.content or '').strip())
cls = APIError
if response.status_code == 404:
if explanation and ('No such image' in str(explanation) or
diff --git a/ansible_collections/community/docker/plugins/module_utils/_api/tls.py b/ansible_collections/community/docker/plugins/module_utils/_api/tls.py
index ed5416d82..b1e284a5d 100644
--- a/ansible_collections/community/docker/plugins/module_utils/_api/tls.py
+++ b/ansible_collections/community/docker/plugins/module_utils/_api/tls.py
@@ -39,8 +39,7 @@ class TLSConfig(object):
ssl_version = None
def __init__(self, client_cert=None, ca_cert=None, verify=None,
- ssl_version=None, assert_hostname=None,
- assert_fingerprint=None):
+ ssl_version=None, assert_hostname=None):
# Argument compatibility/mapping with
# https://docs.docker.com/engine/articles/https/
# This diverges from the Docker CLI in that users can specify 'tls'
@@ -48,7 +47,6 @@ class TLSConfig(object):
# leaving verify=False
self.assert_hostname = assert_hostname
- self.assert_fingerprint = assert_fingerprint
# If the user provides an SSL version, we should use their preference
if ssl_version:
@@ -118,5 +116,4 @@ class TLSConfig(object):
client.mount('https://', SSLHTTPAdapter(
ssl_version=self.ssl_version,
assert_hostname=self.assert_hostname,
- assert_fingerprint=self.assert_fingerprint,
))
diff --git a/ansible_collections/community/docker/plugins/module_utils/_api/transport/ssladapter.py b/ansible_collections/community/docker/plugins/module_utils/_api/transport/ssladapter.py
index e1b5ce020..ed9250d6a 100644
--- a/ansible_collections/community/docker/plugins/module_utils/_api/transport/ssladapter.py
+++ b/ansible_collections/community/docker/plugins/module_utils/_api/transport/ssladapter.py
@@ -27,15 +27,11 @@ PoolManager = urllib3.poolmanager.PoolManager
class SSLHTTPAdapter(BaseHTTPAdapter):
'''An HTTPS Transport Adapter that uses an arbitrary SSL version.'''
- __attrs__ = HTTPAdapter.__attrs__ + ['assert_fingerprint',
- 'assert_hostname',
- 'ssl_version']
+ __attrs__ = HTTPAdapter.__attrs__ + ['assert_hostname', 'ssl_version']
- def __init__(self, ssl_version=None, assert_hostname=None,
- assert_fingerprint=None, **kwargs):
+ def __init__(self, ssl_version=None, assert_hostname=None, **kwargs):
self.ssl_version = ssl_version
self.assert_hostname = assert_hostname
- self.assert_fingerprint = assert_fingerprint
super(SSLHTTPAdapter, self).__init__(**kwargs)
def init_poolmanager(self, connections, maxsize, block=False):
@@ -43,9 +39,9 @@ class SSLHTTPAdapter(BaseHTTPAdapter):
'num_pools': connections,
'maxsize': maxsize,
'block': block,
- 'assert_hostname': self.assert_hostname,
- 'assert_fingerprint': self.assert_fingerprint,
}
+ if self.assert_hostname is not None:
+ kwargs['assert_hostname'] = self.assert_hostname
if self.ssl_version and self.can_override_ssl_version():
kwargs['ssl_version'] = self.ssl_version
@@ -60,7 +56,7 @@ class SSLHTTPAdapter(BaseHTTPAdapter):
But we still need to take care of when there is a proxy poolmanager
"""
conn = super(SSLHTTPAdapter, self).get_connection(*args, **kwargs)
- if conn.assert_hostname != self.assert_hostname:
+ if self.assert_hostname is not None and conn.assert_hostname != self.assert_hostname:
conn.assert_hostname = self.assert_hostname
return conn
diff --git a/ansible_collections/community/docker/plugins/module_utils/_api/utils/socket.py b/ansible_collections/community/docker/plugins/module_utils/_api/utils/socket.py
index 9193ce30e..792aa0cb5 100644
--- a/ansible_collections/community/docker/plugins/module_utils/_api/utils/socket.py
+++ b/ansible_collections/community/docker/plugins/module_utils/_api/utils/socket.py
@@ -15,7 +15,6 @@ import os
import select
import socket as pysocket
import struct
-import sys
from ansible.module_utils.six import PY3, binary_type
@@ -43,7 +42,7 @@ def read(socket, n=4096):
recoverable_errors = (errno.EINTR, errno.EDEADLK, errno.EWOULDBLOCK)
if PY3 and not isinstance(socket, NpipeSocket):
- if sys.platform == 'win32':
+ if not hasattr(select, "poll"):
# Limited to 1024
select.select([socket], [], [])
else:
diff --git a/ansible_collections/community/docker/plugins/module_utils/_api/utils/utils.py b/ansible_collections/community/docker/plugins/module_utils/_api/utils/utils.py
index 910b0dc35..db3718d4d 100644
--- a/ansible_collections/community/docker/plugins/module_utils/_api/utils/utils.py
+++ b/ansible_collections/community/docker/plugins/module_utils/_api/utils/utils.py
@@ -160,6 +160,22 @@ def convert_volume_binds(binds):
else:
mode = 'rw'
+ # NOTE: this is only relevant for Linux hosts
+ # (doesn't apply in Docker Desktop)
+ propagation_modes = [
+ 'rshared',
+ 'shared',
+ 'rslave',
+ 'slave',
+ 'rprivate',
+ 'private',
+ ]
+ if 'propagation' in v and v['propagation'] in propagation_modes:
+ if mode:
+ mode = ','.join([mode, v['propagation']])
+ else:
+ mode = v['propagation']
+
result.append(
text_type('{0}:{1}:{2}').format(k, bind, mode)
)
diff --git a/ansible_collections/community/docker/plugins/module_utils/_logfmt.py b/ansible_collections/community/docker/plugins/module_utils/_logfmt.py
new file mode 100644
index 000000000..fa45b5754
--- /dev/null
+++ b/ansible_collections/community/docker/plugins/module_utils/_logfmt.py
@@ -0,0 +1,208 @@
+# Copyright (c) 2024, Felix Fontein <felix@fontein.de>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+"""
+Parse go logfmt messages.
+
+See https://pkg.go.dev/github.com/kr/logfmt?utm_source=godoc for information on the format.
+"""
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+
+# The format is defined in https://pkg.go.dev/github.com/kr/logfmt?utm_source=godoc
+# (look for "EBNFish")
+
+
+class InvalidLogFmt(Exception):
+ pass
+
+
+class _Mode(object):
+ GARBAGE = 0
+ KEY = 1
+ EQUAL = 2
+ IDENT_VALUE = 3
+ QUOTED_VALUE = 4
+
+
+_ESCAPE_DICT = {
+ '"': '"',
+ '\\': '\\',
+ "'": "'",
+ '/': '/',
+ 'b': '\b',
+ 'f': '\f',
+ 'n': '\n',
+ 'r': '\r',
+ 't': '\t',
+}
+
+_HEX_DICT = {
+ '0': 0,
+ '1': 1,
+ '2': 2,
+ '3': 3,
+ '4': 4,
+ '5': 5,
+ '6': 6,
+ '7': 7,
+ '8': 8,
+ '9': 9,
+ 'a': 0xA,
+ 'b': 0xB,
+ 'c': 0xC,
+ 'd': 0xD,
+ 'e': 0xE,
+ 'f': 0xF,
+ 'A': 0xA,
+ 'B': 0xB,
+ 'C': 0xC,
+ 'D': 0xD,
+ 'E': 0xE,
+ 'F': 0xF,
+}
+
+
+def _is_ident(cur):
+ return cur > ' ' and cur not in ('"', '=')
+
+
+class _Parser(object):
+ def __init__(self, line):
+ self.line = line
+ self.index = 0
+ self.length = len(line)
+
+ def done(self):
+ return self.index >= self.length
+
+ def cur(self):
+ return self.line[self.index]
+
+ def next(self):
+ self.index += 1
+
+ def prev(self):
+ self.index -= 1
+
+ def parse_unicode_sequence(self):
+ if self.index + 6 > self.length:
+ raise InvalidLogFmt('Not enough space for unicode escape')
+ if self.line[self.index:self.index + 2] != '\\u':
+ raise InvalidLogFmt('Invalid unicode escape start')
+ v = 0
+ for i in range(self.index + 2, self.index + 6):
+ v <<= 4
+ try:
+ v += _HEX_DICT[self.line[self.index]]
+ except KeyError:
+ raise InvalidLogFmt('Invalid unicode escape digit {digit!r}'.format(digit=self.line[self.index]))
+ self.index += 6
+ return chr(v)
+
+
+def parse_line(line, logrus_mode=False):
+ result = {}
+ parser = _Parser(line)
+ key = []
+ value = []
+ mode = _Mode.GARBAGE
+
+ def handle_kv(has_no_value=False):
+ k = ''.join(key)
+ v = None if has_no_value else ''.join(value)
+ result[k] = v
+ del key[:]
+ del value[:]
+
+ def parse_garbage(cur):
+ if _is_ident(cur):
+ return _Mode.KEY
+ parser.next()
+ return _Mode.GARBAGE
+
+ def parse_key(cur):
+ if _is_ident(cur):
+ key.append(cur)
+ parser.next()
+ return _Mode.KEY
+ elif cur == '=':
+ parser.next()
+ return _Mode.EQUAL
+ else:
+ if logrus_mode:
+ raise InvalidLogFmt('Key must always be followed by "=" in logrus mode')
+ handle_kv(has_no_value=True)
+ parser.next()
+ return _Mode.GARBAGE
+
+ def parse_equal(cur):
+ if _is_ident(cur):
+ value.append(cur)
+ parser.next()
+ return _Mode.IDENT_VALUE
+ elif cur == '"':
+ parser.next()
+ return _Mode.QUOTED_VALUE
+ else:
+ handle_kv()
+ parser.next()
+ return _Mode.GARBAGE
+
+ def parse_ident_value(cur):
+ if _is_ident(cur):
+ value.append(cur)
+ parser.next()
+ return _Mode.IDENT_VALUE
+ else:
+ handle_kv()
+ parser.next()
+ return _Mode.GARBAGE
+
+ def parse_quoted_value(cur):
+ if cur == '\\':
+ parser.next()
+ if parser.done():
+ raise InvalidLogFmt('Unterminated escape sequence in quoted string')
+ cur = parser.cur()
+ if cur in _ESCAPE_DICT:
+ value.append(_ESCAPE_DICT[cur])
+ elif cur != 'u':
+ raise InvalidLogFmt('Unknown escape sequence {seq!r}'.format(seq='\\' + cur))
+ else:
+ parser.prev()
+ value.append(parser.parse_unicode_sequence())
+ parser.next()
+ return _Mode.QUOTED_VALUE
+ elif cur == '"':
+ handle_kv()
+ parser.next()
+ return _Mode.GARBAGE
+ elif cur < ' ':
+ raise InvalidLogFmt('Control characters in quoted string are not allowed')
+ else:
+ value.append(cur)
+ parser.next()
+ return _Mode.QUOTED_VALUE
+
+ parsers = {
+ _Mode.GARBAGE: parse_garbage,
+ _Mode.KEY: parse_key,
+ _Mode.EQUAL: parse_equal,
+ _Mode.IDENT_VALUE: parse_ident_value,
+ _Mode.QUOTED_VALUE: parse_quoted_value,
+ }
+ while not parser.done():
+ mode = parsers[mode](parser.cur())
+ if mode == _Mode.KEY and logrus_mode:
+ raise InvalidLogFmt('Key must always be followed by "=" in logrus mode')
+ if mode == _Mode.KEY or mode == _Mode.EQUAL:
+ handle_kv(has_no_value=True)
+ elif mode == _Mode.IDENT_VALUE:
+ handle_kv()
+ elif mode == _Mode.QUOTED_VALUE:
+ raise InvalidLogFmt('Unterminated quoted string')
+ return result
diff --git a/ansible_collections/community/docker/plugins/module_utils/_platform.py b/ansible_collections/community/docker/plugins/module_utils/_platform.py
new file mode 100644
index 000000000..4b6216f74
--- /dev/null
+++ b/ansible_collections/community/docker/plugins/module_utils/_platform.py
@@ -0,0 +1,179 @@
+# This code is part of the Ansible collection community.docker, but is an independent component.
+# This particular file, and this file only, is based on containerd's platforms Go module
+# (https://github.com/containerd/containerd/tree/main/platforms)
+#
+# Copyright (c) 2023 Felix Fontein <felix@fontein.de>
+# Copyright The containerd Authors
+#
+# It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection)
+# SPDX-License-Identifier: Apache-2.0
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import re
+
+
+_VALID_STR = re.compile('^[A-Za-z0-9_-]+$')
+
+
+def _validate_part(string, part, part_name):
+ if not part:
+ raise ValueError('Invalid platform string "{string}": {part} is empty'.format(string=string, part=part_name))
+ if not _VALID_STR.match(part):
+ raise ValueError('Invalid platform string "{string}": {part} has invalid characters'.format(string=string, part=part_name))
+ return part
+
+
+# See https://github.com/containerd/containerd/blob/main/platforms/database.go#L32-L38
+_KNOWN_OS = (
+ "aix", "android", "darwin", "dragonfly", "freebsd", "hurd", "illumos", "ios", "js",
+ "linux", "nacl", "netbsd", "openbsd", "plan9", "solaris", "windows", "zos",
+)
+
+# See https://github.com/containerd/containerd/blob/main/platforms/database.go#L54-L60
+_KNOWN_ARCH = (
+ "386", "amd64", "amd64p32", "arm", "armbe", "arm64", "arm64be", "ppc64", "ppc64le",
+ "loong64", "mips", "mipsle", "mips64", "mips64le", "mips64p32", "mips64p32le",
+ "ppc", "riscv", "riscv64", "s390", "s390x", "sparc", "sparc64", "wasm",
+)
+
+
+def _normalize_os(os_str):
+ # See normalizeOS() in https://github.com/containerd/containerd/blob/main/platforms/database.go
+ os_str = os_str.lower()
+ if os_str == 'macos':
+ os_str = 'darwin'
+ return os_str
+
+
+_NORMALIZE_ARCH = {
+ ("i386", None): ("386", ""),
+ ("x86_64", "v1"): ("amd64", ""),
+ ("x86-64", "v1"): ("amd64", ""),
+ ("amd64", "v1"): ("amd64", ""),
+ ("x86_64", None): ("amd64", None),
+ ("x86-64", None): ("amd64", None),
+ ("amd64", None): ("amd64", None),
+ ("aarch64", "8"): ("arm64", ""),
+ ("arm64", "8"): ("arm64", ""),
+ ("aarch64", "v8"): ("arm64", ""),
+ ("arm64", "v8"): ("arm64", ""),
+ ("aarch64", None): ("arm64", None),
+ ("arm64", None): ("arm64", None),
+ ("armhf", None): ("arm", "v7"),
+ ("armel", None): ("arm", "v6"),
+ ("arm", ""): ("arm", "v7"),
+ ("arm", "5"): ("arm", "v5"),
+ ("arm", "6"): ("arm", "v6"),
+ ("arm", "7"): ("arm", "v7"),
+ ("arm", "8"): ("arm", "v8"),
+ ("arm", None): ("arm", None),
+}
+
+
+def _normalize_arch(arch_str, variant_str):
+ # See normalizeArch() in https://github.com/containerd/containerd/blob/main/platforms/database.go
+ arch_str = arch_str.lower()
+ variant_str = variant_str.lower()
+ res = _NORMALIZE_ARCH.get((arch_str, variant_str))
+ if res is None:
+ res = _NORMALIZE_ARCH.get((arch_str, None))
+ if res is None:
+ return arch_str, variant_str
+ if res is not None:
+ arch_str = res[0]
+ if res[1] is not None:
+ variant_str = res[1]
+ return arch_str, variant_str
+
+
+class _Platform(object):
+ def __init__(self, os=None, arch=None, variant=None):
+ self.os = os
+ self.arch = arch
+ self.variant = variant
+ if variant is not None:
+ if arch is None:
+ raise ValueError('If variant is given, architecture must be given too')
+ if os is None:
+ raise ValueError('If variant is given, os must be given too')
+
+ @classmethod
+ def parse_platform_string(cls, string, daemon_os=None, daemon_arch=None):
+ # See Parse() in https://github.com/containerd/containerd/blob/main/platforms/platforms.go
+ if string is None:
+ return cls()
+ if not string:
+ raise ValueError('Platform string must be non-empty')
+ parts = string.split('/', 2)
+ arch = None
+ variant = None
+ if len(parts) == 1:
+ _validate_part(string, string, 'OS/architecture')
+ # The part is either OS or architecture
+ os = _normalize_os(string)
+ if os in _KNOWN_OS:
+ if daemon_arch is not None:
+ arch, variant = _normalize_arch(daemon_arch, '')
+ return cls(os=os, arch=arch, variant=variant)
+ arch, variant = _normalize_arch(os, '')
+ if arch in _KNOWN_ARCH:
+ return cls(
+ os=_normalize_os(daemon_os) if daemon_os else None,
+ arch=arch or None,
+ variant=variant or None,
+ )
+ raise ValueError('Invalid platform string "{0}": unknown OS or architecture'.format(string))
+ os = _validate_part(string, parts[0], 'OS')
+ if not os:
+ raise ValueError('Invalid platform string "{0}": OS is empty'.format(string))
+ arch = _validate_part(string, parts[1], 'architecture') if len(parts) > 1 else None
+ if arch is not None and not arch:
+ raise ValueError('Invalid platform string "{0}": architecture is empty'.format(string))
+ variant = _validate_part(string, parts[2], 'variant') if len(parts) > 2 else None
+ if variant is not None and not variant:
+ raise ValueError('Invalid platform string "{0}": variant is empty'.format(string))
+ arch, variant = _normalize_arch(arch, variant or '')
+ if len(parts) == 2 and arch == 'arm' and variant == 'v7':
+ variant = None
+ if len(parts) == 3 and arch == 'arm64' and variant == '':
+ variant = 'v8'
+ return cls(os=_normalize_os(os), arch=arch, variant=variant or None)
+
+ def __str__(self):
+ if self.variant:
+ parts = [self.os, self.arch, self.variant]
+ elif self.os:
+ if self.arch:
+ parts = [self.os, self.arch]
+ else:
+ parts = [self.os]
+ elif self.arch is not None:
+ parts = [self.arch]
+ else:
+ parts = []
+ return '/'.join(parts)
+
+ def __repr__(self):
+ return '_Platform(os={os!r}, arch={arch!r}, variant={variant!r})'.format(os=self.os, arch=self.arch, variant=self.variant)
+
+ def __eq__(self, other):
+ return self.os == other.os and self.arch == other.arch and self.variant == other.variant
+
+
+def normalize_platform_string(string, daemon_os=None, daemon_arch=None):
+ return str(_Platform.parse_platform_string(string, daemon_os=daemon_os, daemon_arch=daemon_arch))
+
+
+def compose_platform_string(os=None, arch=None, variant=None, daemon_os=None, daemon_arch=None):
+ if os is None and daemon_os is not None:
+ os = _normalize_os(daemon_os)
+ if arch is None and daemon_arch is not None:
+ arch, variant = _normalize_arch(daemon_arch, variant or '')
+ variant = variant or None
+ return str(_Platform(os=os, arch=arch, variant=variant or None))
+
+
+def compare_platform_strings(string1, string2):
+ return _Platform.parse_platform_string(string1) == _Platform.parse_platform_string(string2)
diff --git a/ansible_collections/community/docker/plugins/module_utils/common.py b/ansible_collections/community/docker/plugins/module_utils/common.py
index e6a06ed65..d1dcf3e60 100644
--- a/ansible_collections/community/docker/plugins/module_utils/common.py
+++ b/ansible_collections/community/docker/plugins/module_utils/common.py
@@ -122,6 +122,32 @@ if not HAS_DOCKER_PY:
def _get_tls_config(fail_function, **kwargs):
+ if 'ssl_version' in kwargs and LooseVersion(docker_version) >= LooseVersion('7.0.0b1'):
+ ssl_version = kwargs.pop('ssl_version')
+ if ssl_version is not None:
+ fail_function(
+ "ssl_version is not compatible with Docker SDK for Python 7.0.0+. You are using"
+ " Docker SDK for Python {docker_py_version}. The ssl_version option (value: {ssl_version})"
+ " has either been set directly or with the environment variable DOCKER_SSL_VERSION."
+ " Make sure it is not set, or switch to an older version of Docker SDK for Python.".format(
+ docker_py_version=docker_version,
+ ssl_version=ssl_version,
+ )
+ )
+ if 'assert_hostname' in kwargs and LooseVersion(docker_version) >= LooseVersion('7.0.0b1'):
+ assert_hostname = kwargs.pop('assert_hostname')
+ if assert_hostname is not None:
+ fail_function(
+ "tls_hostname is not compatible with Docker SDK for Python 7.0.0+. You are using"
+ " Docker SDK for Python {docker_py_version}. The tls_hostname option (value: {tls_hostname})"
+ " has either been set directly or with the environment variable DOCKER_TLS_HOSTNAME."
+ " Make sure it is not set, or switch to an older version of Docker SDK for Python.".format(
+ docker_py_version=docker_version,
+ tls_hostname=assert_hostname,
+ )
+ )
+ # Filter out all None parameters
+ kwargs = dict((k, v) for k, v in kwargs.items() if v is not None)
try:
tls_config = TLSConfig(**kwargs)
return tls_config
@@ -234,12 +260,8 @@ class AnsibleDockerClientBase(Client):
def log(self, msg, pretty_print=False):
pass
# if self.debug:
- # log_file = open('docker.log', 'a')
- # if pretty_print:
- # log_file.write(json.dumps(msg, sort_keys=True, indent=4, separators=(',', ': ')))
- # log_file.write(u'\n')
- # else:
- # log_file.write(msg + u'\n')
+ # from .util import log_debug
+ # log_debug(msg, pretty_print=pretty_print)
@abc.abstractmethod
def fail(self, msg, **kwargs):
@@ -309,7 +331,7 @@ class AnsibleDockerClientBase(Client):
'DOCKER_TLS_HOSTNAME', None, type='str'),
api_version=self._get_value('api_version', params['api_version'], 'DOCKER_API_VERSION',
'auto', type='str'),
- cacert_path=self._get_value('cacert_path', params['ca_cert'], 'DOCKER_CERT_PATH', None, type='str'),
+ cacert_path=self._get_value('cacert_path', params['ca_path'], 'DOCKER_CERT_PATH', None, type='str'),
cert_path=self._get_value('cert_path', params['client_cert'], 'DOCKER_CERT_PATH', None, type='str'),
key_path=self._get_value('key_path', params['client_key'], 'DOCKER_CERT_PATH', None, type='str'),
ssl_version=self._get_value('ssl_version', params['ssl_version'], 'DOCKER_SSL_VERSION', None, type='str'),
@@ -456,7 +478,7 @@ class AnsibleDockerClientBase(Client):
images = self._image_lookup(lookup, tag)
if len(images) > 1:
- self.fail("Registry returned more than one result for %s:%s" % (name, tag))
+ self.fail("Daemon returned more than one result for %s:%s" % (name, tag))
if len(images) == 1:
try:
diff --git a/ansible_collections/community/docker/plugins/module_utils/common_api.py b/ansible_collections/community/docker/plugins/module_utils/common_api.py
index 7d46a153a..b5ea42fa3 100644
--- a/ansible_collections/community/docker/plugins/module_utils/common_api.py
+++ b/ansible_collections/community/docker/plugins/module_utils/common_api.py
@@ -131,12 +131,8 @@ class AnsibleDockerClientBase(Client):
def log(self, msg, pretty_print=False):
pass
# if self.debug:
- # log_file = open('docker.log', 'a')
- # if pretty_print:
- # log_file.write(json.dumps(msg, sort_keys=True, indent=4, separators=(',', ': ')))
- # log_file.write(u'\n')
- # else:
- # log_file.write(msg + u'\n')
+ # from .util import log_debug
+ # log_debug(msg, pretty_print=pretty_print)
@abc.abstractmethod
def fail(self, msg, **kwargs):
@@ -206,7 +202,7 @@ class AnsibleDockerClientBase(Client):
'DOCKER_TLS_HOSTNAME', None, type='str'),
api_version=self._get_value('api_version', params['api_version'], 'DOCKER_API_VERSION',
'auto', type='str'),
- cacert_path=self._get_value('cacert_path', params['ca_cert'], 'DOCKER_CERT_PATH', None, type='str'),
+ cacert_path=self._get_value('cacert_path', params['ca_path'], 'DOCKER_CERT_PATH', None, type='str'),
cert_path=self._get_value('cert_path', params['client_cert'], 'DOCKER_CERT_PATH', None, type='str'),
key_path=self._get_value('key_path', params['client_key'], 'DOCKER_CERT_PATH', None, type='str'),
ssl_version=self._get_value('ssl_version', params['ssl_version'], 'DOCKER_SSL_VERSION', None, type='str'),
@@ -396,7 +392,7 @@ class AnsibleDockerClientBase(Client):
images = self._image_lookup(lookup, tag)
if len(images) > 1:
- self.fail("Registry returned more than one result for %s:%s" % (name, tag))
+ self.fail("Daemon returned more than one result for %s:%s" % (name, tag))
if len(images) == 1:
try:
diff --git a/ansible_collections/community/docker/plugins/module_utils/common_cli.py b/ansible_collections/community/docker/plugins/module_utils/common_cli.py
new file mode 100644
index 000000000..60d539877
--- /dev/null
+++ b/ansible_collections/community/docker/plugins/module_utils/common_cli.py
@@ -0,0 +1,339 @@
+# Copyright (c) 2023, Felix Fontein <felix@fontein.de>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+
+import abc
+import json
+import shlex
+
+from ansible.module_utils.basic import AnsibleModule, env_fallback
+from ansible.module_utils.common.process import get_bin_path
+from ansible.module_utils.common.text.converters import to_native
+
+from ansible_collections.community.docker.plugins.module_utils.version import LooseVersion
+
+from ansible_collections.community.docker.plugins.module_utils._api.auth import resolve_repository_name
+
+from ansible_collections.community.docker.plugins.module_utils.util import ( # noqa: F401, pylint: disable=unused-import
+ DEFAULT_DOCKER_HOST,
+ DEFAULT_TLS,
+ DEFAULT_TLS_VERIFY,
+ DOCKER_MUTUALLY_EXCLUSIVE,
+ DOCKER_REQUIRED_TOGETHER,
+ sanitize_result,
+)
+
+
+DOCKER_COMMON_ARGS = dict(
+ docker_cli=dict(type='path'),
+ docker_host=dict(type='str', default=DEFAULT_DOCKER_HOST, fallback=(env_fallback, ['DOCKER_HOST']), aliases=['docker_url']),
+ tls_hostname=dict(type='str', fallback=(env_fallback, ['DOCKER_TLS_HOSTNAME'])),
+ api_version=dict(type='str', default='auto', fallback=(env_fallback, ['DOCKER_API_VERSION']), aliases=['docker_api_version']),
+ ca_path=dict(type='path', aliases=['ca_cert', 'tls_ca_cert', 'cacert_path']),
+ client_cert=dict(type='path', aliases=['tls_client_cert', 'cert_path']),
+ client_key=dict(type='path', aliases=['tls_client_key', 'key_path']),
+ tls=dict(type='bool', default=DEFAULT_TLS, fallback=(env_fallback, ['DOCKER_TLS'])),
+ validate_certs=dict(type='bool', default=DEFAULT_TLS_VERIFY, fallback=(env_fallback, ['DOCKER_TLS_VERIFY']), aliases=['tls_verify']),
+ # debug=dict(type='bool', default=False),
+ cli_context=dict(type='str'),
+)
+
+
+class DockerException(Exception):
+ pass
+
+
+class AnsibleDockerClientBase(object):
+ def __init__(self, common_args, min_docker_api_version=None):
+ self._environment = {}
+ if common_args['tls_hostname']:
+ self._environment['DOCKER_TLS_HOSTNAME'] = common_args['tls_hostname']
+ if common_args['api_version'] and common_args['api_version'] != 'auto':
+ self._environment['DOCKER_API_VERSION'] = common_args['api_version']
+ self._cli = common_args.get('docker_cli')
+ if self._cli is None:
+ try:
+ self._cli = get_bin_path('docker')
+ except ValueError:
+ self.fail('Cannot find docker CLI in path. Please provide it explicitly with the docker_cli parameter')
+
+ self._cli_base = [self._cli]
+ self._cli_base.extend(['--host', common_args['docker_host']])
+ if common_args['validate_certs']:
+ self._cli_base.append('--tlsverify')
+ elif common_args['tls']:
+ self._cli_base.append('--tls')
+ if common_args['ca_path']:
+ self._cli_base.extend(['--tlscacert', common_args['ca_path']])
+ if common_args['client_cert']:
+ self._cli_base.extend(['--tlscert', common_args['client_cert']])
+ if common_args['client_key']:
+ self._cli_base.extend(['--tlskey', common_args['client_key']])
+ if common_args['cli_context']:
+ self._cli_base.extend(['--context', common_args['cli_context']])
+
+ # `--format json` was only added as a shorthand for `--format {{ json . }}` in Docker 23.0
+ dummy, self._version, dummy = self.call_cli_json('version', '--format', '{{ json . }}', check_rc=True)
+ self._info = None
+
+ self.docker_api_version_str = self._version['Server']['ApiVersion']
+ self.docker_api_version = LooseVersion(self.docker_api_version_str)
+ min_docker_api_version = min_docker_api_version or '1.25'
+ if self.docker_api_version < LooseVersion(min_docker_api_version):
+ self.fail('Docker API version is %s. Minimum version required is %s.' % (self.docker_api_version_str, min_docker_api_version))
+
+ def log(self, msg, pretty_print=False):
+ pass
+ # if self.debug:
+ # from .util import log_debug
+ # log_debug(msg, pretty_print=pretty_print)
+
+ def get_cli(self):
+ return self._cli
+
+ def get_version_info(self):
+ return self._version
+
+ def _compose_cmd(self, args):
+ return self._cli_base + list(args)
+
+ def _compose_cmd_str(self, args):
+ return ' '.join(shlex.quote(a) for a in self._compose_cmd(args))
+
+ @abc.abstractmethod
+ # def call_cli(self, *args, check_rc=False, data=None, cwd=None, environ_update=None):
+ def call_cli(self, *args, **kwargs):
+ # Python 2.7 doesn't like anything than '**kwargs' after '*args', so we have to do this manually...
+ pass
+
+ # def call_cli_json(self, *args, check_rc=False, data=None, cwd=None, environ_update=None, warn_on_stderr=False):
+ def call_cli_json(self, *args, **kwargs):
+ warn_on_stderr = kwargs.pop('warn_on_stderr', False)
+ rc, stdout, stderr = self.call_cli(*args, **kwargs)
+ if warn_on_stderr and stderr:
+ self.warn(to_native(stderr))
+ try:
+ data = json.loads(stdout)
+ except Exception as exc:
+ self.fail('Error while parsing JSON output of {cmd}: {exc}\nJSON output: {stdout}'.format(
+ cmd=self._compose_cmd_str(args),
+ exc=to_native(exc),
+ stdout=to_native(stdout),
+ ))
+ return rc, data, stderr
+
+ # def call_cli_json_stream(self, *args, check_rc=False, data=None, cwd=None, environ_update=None, warn_on_stderr=False):
+ def call_cli_json_stream(self, *args, **kwargs):
+ warn_on_stderr = kwargs.pop('warn_on_stderr', False)
+ rc, stdout, stderr = self.call_cli(*args, **kwargs)
+ if warn_on_stderr and stderr:
+ self.warn(to_native(stderr))
+ result = []
+ try:
+ for line in stdout.splitlines():
+ line = line.strip()
+ if line.startswith(b'{'):
+ result.append(json.loads(line))
+ except Exception as exc:
+ self.fail('Error while parsing JSON output of {cmd}: {exc}\nJSON output: {stdout}'.format(
+ cmd=self._compose_cmd_str(args),
+ exc=to_native(exc),
+ stdout=to_native(stdout),
+ ))
+ return rc, result, stderr
+
+ @abc.abstractmethod
+ def fail(self, msg, **kwargs):
+ pass
+
+ @abc.abstractmethod
+ def warn(self, msg):
+ pass
+
+ @abc.abstractmethod
+ def deprecate(self, msg, version=None, date=None, collection_name=None):
+ pass
+
+ def get_cli_info(self):
+ if self._info is None:
+ dummy, self._info, dummy = self.call_cli_json('info', '--format', '{{ json . }}', check_rc=True)
+ return self._info
+
+ def get_client_plugin_info(self, component):
+ for plugin in self.get_cli_info()['ClientInfo'].get('Plugins') or []:
+ if plugin.get('Name') == component:
+ return plugin
+ return None
+
+ def _image_lookup(self, name, tag):
+ '''
+ Including a tag in the name parameter sent to the Docker SDK for Python images method
+ does not work consistently. Instead, get the result set for name and manually check
+ if the tag exists.
+ '''
+ dummy, images, dummy = self.call_cli_json_stream(
+ 'image', 'ls', '--format', '{{ json . }}', '--no-trunc', '--filter', 'reference={0}'.format(name),
+ check_rc=True,
+ )
+ if tag:
+ lookup = "%s:%s" % (name, tag)
+ lookup_digest = "%s@%s" % (name, tag)
+ response = images
+ images = []
+ for image in response:
+ if image.get('Tag') == tag or image.get('Digest') == tag:
+ images = [image]
+ break
+ return images
+
+ def find_image(self, name, tag):
+ '''
+ Lookup an image (by name and tag) and return the inspection results.
+ '''
+ if not name:
+ return None
+
+ self.log("Find image %s:%s" % (name, tag))
+ images = self._image_lookup(name, tag)
+ if not images:
+ # In API <= 1.20 seeing 'docker.io/<name>' as the name of images pulled from docker hub
+ registry, repo_name = resolve_repository_name(name)
+ if registry == 'docker.io':
+ # If docker.io is explicitly there in name, the image
+ # isn't found in some cases (#41509)
+ self.log("Check for docker.io image: %s" % repo_name)
+ images = self._image_lookup(repo_name, tag)
+ if not images and repo_name.startswith('library/'):
+ # Sometimes library/xxx images are not found
+ lookup = repo_name[len('library/'):]
+ self.log("Check for docker.io image: %s" % lookup)
+ images = self._image_lookup(lookup, tag)
+ if not images:
+ # Last case for some Docker versions: if docker.io wasn't there,
+ # it can be that the image wasn't found either
+ # (https://github.com/ansible/ansible/pull/15586)
+ lookup = "%s/%s" % (registry, repo_name)
+ self.log("Check for docker.io image: %s" % lookup)
+ images = self._image_lookup(lookup, tag)
+ if not images and '/' not in repo_name:
+ # This seems to be happening with podman-docker
+ # (https://github.com/ansible-collections/community.docker/issues/291)
+ lookup = "%s/library/%s" % (registry, repo_name)
+ self.log("Check for docker.io image: %s" % lookup)
+ images = self._image_lookup(lookup, tag)
+
+ if len(images) > 1:
+ self.fail("Daemon returned more than one result for %s:%s" % (name, tag))
+
+ if len(images) == 1:
+ rc, image, stderr = self.call_cli_json('image', 'inspect', images[0]['ID'])
+ if not image:
+ self.log("Image %s:%s not found." % (name, tag))
+ return None
+ if rc != 0:
+ self.fail("Error inspecting image %s:%s - %s" % (name, tag, to_native(stderr)))
+ return image[0]
+
+ self.log("Image %s:%s not found." % (name, tag))
+ return None
+
+ def find_image_by_id(self, image_id, accept_missing_image=False):
+ '''
+ Lookup an image (by ID) and return the inspection results.
+ '''
+ if not image_id:
+ return None
+
+ self.log("Find image %s (by ID)" % image_id)
+ rc, image, stderr = self.call_cli_json('image', 'inspect', image_id)
+ if not image:
+ if not accept_missing_image:
+ self.fail("Error inspecting image ID %s - %s" % (image_id, to_native(stderr)))
+ self.log("Image %s not found." % image_id)
+ return None
+ if rc != 0:
+ self.fail("Error inspecting image ID %s - %s" % (image_id, to_native(stderr)))
+ return image[0]
+
+
+class AnsibleModuleDockerClient(AnsibleDockerClientBase):
+ def __init__(self, argument_spec=None, supports_check_mode=False, mutually_exclusive=None,
+ required_together=None, required_if=None, required_one_of=None, required_by=None,
+ min_docker_api_version=None, fail_results=None):
+
+ # Modules can put information in here which will always be returned
+ # in case client.fail() is called.
+ self.fail_results = fail_results or {}
+
+ merged_arg_spec = dict()
+ merged_arg_spec.update(DOCKER_COMMON_ARGS)
+ if argument_spec:
+ merged_arg_spec.update(argument_spec)
+ self.arg_spec = merged_arg_spec
+
+ mutually_exclusive_params = []
+ mutually_exclusive_params += DOCKER_MUTUALLY_EXCLUSIVE
+ if mutually_exclusive:
+ mutually_exclusive_params += mutually_exclusive
+
+ required_together_params = []
+ required_together_params += DOCKER_REQUIRED_TOGETHER
+ if required_together:
+ required_together_params += required_together
+
+ self.module = AnsibleModule(
+ argument_spec=merged_arg_spec,
+ supports_check_mode=supports_check_mode,
+ mutually_exclusive=mutually_exclusive_params,
+ required_together=required_together_params,
+ required_if=required_if,
+ required_one_of=required_one_of,
+ required_by=required_by or {},
+ )
+
+ self.debug = False # self.module.params['debug']
+ self.check_mode = self.module.check_mode
+ self.diff = self.module._diff
+
+ common_args = dict((k, self.module.params[k]) for k in DOCKER_COMMON_ARGS)
+ super(AnsibleModuleDockerClient, self).__init__(common_args, min_docker_api_version=min_docker_api_version)
+
+ # def call_cli(self, *args, check_rc=False, data=None, cwd=None, environ_update=None):
+ def call_cli(self, *args, **kwargs):
+ # Python 2.7 doesn't like anything than '**kwargs' after '*args', so we have to do this manually...
+ check_rc = kwargs.pop('check_rc', False)
+ data = kwargs.pop('data', None)
+ cwd = kwargs.pop('cwd', None)
+ environ_update = kwargs.pop('environ_update', None)
+ if kwargs:
+ raise TypeError("call_cli() got an unexpected keyword argument '%s'" % list(kwargs)[0])
+
+ environment = self._environment.copy()
+ if environ_update:
+ environment.update(environ_update)
+ rc, stdout, stderr = self.module.run_command(
+ self._compose_cmd(args),
+ binary_data=True,
+ check_rc=check_rc,
+ cwd=cwd,
+ data=data,
+ encoding=None,
+ environ_update=environment,
+ expand_user_and_vars=False,
+ ignore_invalid_cwd=False,
+ )
+ return rc, stdout, stderr
+
+ def fail(self, msg, **kwargs):
+ self.fail_results.update(kwargs)
+ self.module.fail_json(msg=msg, **sanitize_result(self.fail_results))
+
+ def warn(self, msg):
+ self.module.warn(msg)
+
+ def deprecate(self, msg, version=None, date=None, collection_name=None):
+ self.module.deprecate(msg, version=version, date=date, collection_name=collection_name)
diff --git a/ansible_collections/community/docker/plugins/module_utils/compose_v2.py b/ansible_collections/community/docker/plugins/module_utils/compose_v2.py
new file mode 100644
index 000000000..92f109269
--- /dev/null
+++ b/ansible_collections/community/docker/plugins/module_utils/compose_v2.py
@@ -0,0 +1,618 @@
+# Copyright (c) 2023, Felix Fontein <felix@fontein.de>
+# Copyright (c) 2023, Léo El Amri (@lel-amri)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+
+import os
+import re
+from collections import namedtuple
+
+from ansible.module_utils.common.text.converters import to_native
+from ansible.module_utils.six.moves import shlex_quote
+
+from ansible_collections.community.docker.plugins.module_utils.util import DockerBaseClass
+from ansible_collections.community.docker.plugins.module_utils.version import LooseVersion
+from ansible_collections.community.docker.plugins.module_utils._logfmt import (
+ InvalidLogFmt as _InvalidLogFmt,
+ parse_line as _parse_logfmt_line,
+)
+
+
+DOCKER_COMPOSE_FILES = ('compose.yaml', 'compose.yml', 'docker-compose.yaml', 'docker-compose.yml')
+
+DOCKER_STATUS_DONE = frozenset((
+ 'Started',
+ 'Healthy',
+ 'Exited',
+ 'Restarted',
+ 'Running',
+ 'Created',
+ 'Stopped',
+ 'Killed',
+ 'Removed',
+ # An extra, specific to containers
+ 'Recreated',
+ # Extras for pull events
+ 'Pulled',
+))
+DOCKER_STATUS_WORKING = frozenset((
+ 'Creating',
+ 'Starting',
+ 'Restarting',
+ 'Stopping',
+ 'Killing',
+ 'Removing',
+ # An extra, specific to containers
+ 'Recreate',
+ # Extras for pull events
+ 'Pulling',
+ # Extras for build start events
+ 'Building',
+))
+DOCKER_STATUS_PULL = frozenset((
+ 'Pulled',
+ 'Pulling',
+))
+DOCKER_STATUS_ERROR = frozenset((
+ 'Error',
+))
+DOCKER_STATUS_WARNING = frozenset((
+ 'Warning',
+))
+DOCKER_STATUS_WAITING = frozenset((
+ 'Waiting',
+))
+DOCKER_STATUS = frozenset(DOCKER_STATUS_DONE | DOCKER_STATUS_WORKING | DOCKER_STATUS_PULL | DOCKER_STATUS_ERROR | DOCKER_STATUS_WAITING)
+
+DOCKER_PULL_PROGRESS_DONE = frozenset((
+ 'Already exists',
+ 'Download complete',
+ 'Pull complete',
+))
+DOCKER_PULL_PROGRESS_WORKING = frozenset((
+ 'Pulling fs layer',
+ 'Waiting',
+ 'Downloading',
+ 'Verifying Checksum',
+ 'Extracting',
+))
+
+
+class ResourceType(object):
+ UNKNOWN = "unknown"
+ NETWORK = "network"
+ IMAGE = "image"
+ IMAGE_LAYER = "image-layer"
+ VOLUME = "volume"
+ CONTAINER = "container"
+ SERVICE = "service"
+
+ @classmethod
+ def from_docker_compose_event(cls, resource_type):
+ # type: (Type[ResourceType], Text) -> Any
+ return {
+ "Network": cls.NETWORK,
+ "Image": cls.IMAGE,
+ "Volume": cls.VOLUME,
+ "Container": cls.CONTAINER,
+ }[resource_type]
+
+
+Event = namedtuple(
+ 'Event',
+ ['resource_type', 'resource_id', 'status', 'msg']
+)
+
+
+_DRY_RUN_MARKER = 'DRY-RUN MODE -'
+
+_RE_RESOURCE_EVENT = re.compile(
+ r'^'
+ r'\s*'
+ r'(?P<resource_type>Network|Image|Volume|Container)'
+ r'\s+'
+ r'(?P<resource_id>\S+)'
+ r'\s+'
+ r'(?P<status>\S(?:|.*\S))'
+ r'\s*'
+ r'$'
+)
+
+_RE_PULL_EVENT = re.compile(
+ r'^'
+ r'\s*'
+ r'(?P<service>\S+)'
+ r'\s+'
+ r'(?P<status>%s)'
+ r'\s*'
+ r'$'
+ % '|'.join(re.escape(status) for status in DOCKER_STATUS_PULL)
+)
+
+_RE_PULL_PROGRESS = re.compile(
+ r'^'
+ r'\s*'
+ r'(?P<layer>\S+)'
+ r'\s+'
+ r'(?P<status>%s)'
+ r'\s*'
+ r'(?:|\s\[[^]]+\]\s+\S+\s*|\s+[0-9.kKmMgGbB]+/[0-9.kKmMgGbB]+\s*)'
+ r'$'
+ % '|'.join(re.escape(status) for status in sorted(DOCKER_PULL_PROGRESS_DONE | DOCKER_PULL_PROGRESS_WORKING))
+)
+
+_RE_ERROR_EVENT = re.compile(
+ r'^'
+ r'\s*'
+ r'(?P<resource_id>\S+)'
+ r'\s+'
+ r'(?P<status>%s)'
+ r'\s*'
+ r'(?P<msg>\S.*\S)?'
+ r'$'
+ % '|'.join(re.escape(status) for status in DOCKER_STATUS_ERROR)
+)
+
+_RE_WARNING_EVENT = re.compile(
+ r'^'
+ r'\s*'
+ r'(?P<resource_id>\S+)'
+ r'\s+'
+ r'(?P<status>%s)'
+ r'\s*'
+ r'(?P<msg>\S.*\S)?'
+ r'$'
+ % '|'.join(re.escape(status) for status in DOCKER_STATUS_WARNING)
+)
+
+_RE_CONTINUE_EVENT = re.compile(
+ r'^'
+ r'\s*'
+ r'(?P<resource_id>\S+)'
+ r'\s+'
+ r'-'
+ r'\s*'
+ r'(?P<msg>\S(?:|.*\S))'
+ r'$'
+)
+
+_RE_SKIPPED_EVENT = re.compile(
+ r'^'
+ r'\s*'
+ r'(?P<resource_id>\S+)'
+ r'\s+'
+ r'Skipped -'
+ r'\s*'
+ r'(?P<msg>\S(?:|.*\S))'
+ r'$'
+)
+
+_RE_BUILD_START_EVENT = re.compile(
+ r'^'
+ r'\s*'
+ r'build service'
+ r'\s+'
+ r'(?P<resource_id>\S+)'
+ r'$'
+)
+
+_RE_BUILD_PROGRESS_EVENT = re.compile(
+ r'^'
+ r'\s*'
+ r'==>'
+ r'\s+'
+ r'(?P<msg>.*)'
+ r'$'
+)
+
+# The following needs to be kept in sync with the MINIMUM_VERSION compose_v2 docs fragment
+MINIMUM_COMPOSE_VERSION = '2.18.0'
+
+
+def _extract_event(line, warn_function=None):
+ match = _RE_RESOURCE_EVENT.match(line)
+ if match is not None:
+ status = match.group('status')
+ msg = None
+ if status not in DOCKER_STATUS:
+ status, msg = msg, status
+ return Event(
+ ResourceType.from_docker_compose_event(match.group('resource_type')),
+ match.group('resource_id'),
+ status,
+ msg,
+ ), True
+ match = _RE_PULL_EVENT.match(line)
+ if match:
+ return Event(
+ ResourceType.SERVICE,
+ match.group('service'),
+ match.group('status'),
+ None,
+ ), True
+ match = _RE_ERROR_EVENT.match(line)
+ if match:
+ return Event(
+ ResourceType.UNKNOWN,
+ match.group('resource_id'),
+ match.group('status'),
+ match.group('msg') or None,
+ ), True
+ match = _RE_WARNING_EVENT.match(line)
+ if match:
+ if warn_function:
+ if match.group('msg'):
+ msg = '{rid}: {msg}'
+ else:
+ msg = 'Unspecified warning for {rid}'
+ warn_function(msg.format(rid=match.group('resource_id'), msg=match.group('msg')))
+ return None, True
+ match = _RE_PULL_PROGRESS.match(line)
+ if match:
+ return Event(
+ ResourceType.IMAGE_LAYER,
+ match.group('layer'),
+ match.group('status'),
+ None,
+ ), True
+ match = _RE_SKIPPED_EVENT.match(line)
+ if match:
+ return Event(
+ ResourceType.UNKNOWN,
+ match.group('resource_id'),
+ 'Skipped',
+ match.group('msg'),
+ ), True
+ match = _RE_BUILD_START_EVENT.match(line)
+ if match:
+ return Event(
+ ResourceType.SERVICE,
+ match.group('resource_id'),
+ 'Building',
+ None,
+ ), True
+ return None, False
+
+
+def _extract_logfmt_event(line, warn_function=None):
+ try:
+ result = _parse_logfmt_line(line, logrus_mode=True)
+ except _InvalidLogFmt:
+ return None, False
+ if 'time' not in result or 'level' not in result or 'msg' not in result:
+ return None, False
+ if result['level'] == 'warning':
+ if warn_function:
+ warn_function(result['msg'])
+ return None, True
+ # TODO: no idea what to do with this
+ return None, False
+
+
+def _warn_missing_dry_run_prefix(line, warn_missing_dry_run_prefix, warn_function):
+ if warn_missing_dry_run_prefix and warn_function:
+ # This could be a bug, a change of docker compose's output format, ...
+ # Tell the user to report it to us :-)
+ warn_function(
+ 'Event line is missing dry-run mode marker: {0!r}. Please report this at '
+ 'https://github.com/ansible-collections/community.docker/issues/new?assignees=&labels=&projects=&template=bug_report.md'
+ .format(line)
+ )
+
+
+def _warn_unparsable_line(line, warn_function):
+ # This could be a bug, a change of docker compose's output format, ...
+ # Tell the user to report it to us :-)
+ if warn_function:
+ warn_function(
+ 'Cannot parse event from line: {0!r}. Please report this at '
+ 'https://github.com/ansible-collections/community.docker/issues/new?assignees=&labels=&projects=&template=bug_report.md'
+ .format(line)
+ )
+
+
+def _find_last_event_for(events, resource_id):
+ for index, event in enumerate(reversed(events)):
+ if event.resource_id == resource_id:
+ return len(events) - 1 - index, event
+ return None
+
+
+def _concat_event_msg(event, append_msg):
+ return Event(
+ event.resource_type,
+ event.resource_id,
+ event.status,
+ '\n'.join(msg for msg in [event.msg, append_msg] if msg is not None),
+ )
+
+
+def parse_events(stderr, dry_run=False, warn_function=None):
+ events = []
+ error_event = None
+ stderr_lines = stderr.splitlines()
+ if stderr_lines and stderr_lines[-1] == b'':
+ del stderr_lines[-1]
+ for line in stderr_lines:
+ line = to_native(line.strip())
+ if not line:
+ continue
+ warn_missing_dry_run_prefix = False
+ if dry_run:
+ if line.startswith(_DRY_RUN_MARKER):
+ line = line[len(_DRY_RUN_MARKER):].lstrip()
+ else:
+ warn_missing_dry_run_prefix = True
+ event, parsed = _extract_event(line, warn_function=warn_function)
+ if event is not None:
+ events.append(event)
+ if event.status in DOCKER_STATUS_ERROR:
+ error_event = event
+ else:
+ error_event = None
+ _warn_missing_dry_run_prefix(line, warn_missing_dry_run_prefix, warn_function)
+ continue
+ elif parsed:
+ continue
+ match = _RE_BUILD_PROGRESS_EVENT.match(line)
+ if match:
+ # Ignore this
+ continue
+ match = _RE_CONTINUE_EVENT.match(line)
+ if match:
+ # Continuing an existing event
+ index_event = _find_last_event_for(events, match.group('resource_id'))
+ if index_event is not None:
+ index, event = index_event
+ events[-1] = _concat_event_msg(event, match.group('msg'))
+ event, parsed = _extract_logfmt_event(line, warn_function=warn_function)
+ if event is not None:
+ events.append(event)
+ elif parsed:
+ continue
+ if error_event is not None:
+ # Unparsable line that apparently belongs to the previous error event
+ events[-1] = _concat_event_msg(error_event, line)
+ continue
+ if line.startswith('Error '):
+ # Error message that is independent of an error event
+ error_event = Event(
+ ResourceType.UNKNOWN,
+ '',
+ 'Error',
+ line,
+ )
+ events.append(error_event)
+ continue
+ if len(stderr_lines) == 1:
+ # **Very likely** an error message that is independent of an error event
+ error_event = Event(
+ ResourceType.UNKNOWN,
+ '',
+ 'Error',
+ line,
+ )
+ events.append(error_event)
+ continue
+ _warn_missing_dry_run_prefix(line, warn_missing_dry_run_prefix, warn_function)
+ _warn_unparsable_line(line, warn_function)
+ return events
+
+
+def has_changes(events, ignore_service_pull_events=False):
+ for event in events:
+ if event.status in DOCKER_STATUS_WORKING:
+ if ignore_service_pull_events and event.status in DOCKER_STATUS_PULL:
+ continue
+ return True
+ if event.resource_type == ResourceType.IMAGE_LAYER and event.status in DOCKER_PULL_PROGRESS_WORKING:
+ return True
+ return False
+
+
+def extract_actions(events):
+ actions = []
+ pull_actions = set()
+ for event in events:
+ if event.resource_type == ResourceType.IMAGE_LAYER and event.status in DOCKER_PULL_PROGRESS_WORKING:
+ pull_id = (event.resource_id, event.status)
+ if pull_id not in pull_actions:
+ pull_actions.add(pull_id)
+ actions.append({
+ 'what': event.resource_type,
+ 'id': event.resource_id,
+ 'status': event.status,
+ })
+ if event.resource_type != ResourceType.IMAGE_LAYER and event.status in DOCKER_STATUS_WORKING:
+ actions.append({
+ 'what': event.resource_type,
+ 'id': event.resource_id,
+ 'status': event.status,
+ })
+ return actions
+
+
+def emit_warnings(events, warn_function):
+ for event in events:
+ # If a message is present, assume it is a warning
+ if event.status is None and event.msg is not None:
+ warn_function('Docker compose: {resource_type} {resource_id}: {msg}'.format(
+ resource_type=event.resource_type,
+ resource_id=event.resource_id,
+ msg=event.msg,
+ ))
+
+
+def is_failed(events, rc):
+ if rc:
+ return True
+ return False
+
+
+def update_failed(result, events, args, stdout, stderr, rc, cli):
+ if not rc:
+ return False
+ errors = []
+ for event in events:
+ if event.status in DOCKER_STATUS_ERROR:
+ msg = 'Error when processing {resource_type} {resource_id}: '
+ if event.resource_type == 'unknown':
+ msg = 'Error when processing {resource_id}: '
+ if event.resource_id == '':
+ msg = 'General error: '
+ msg += '{status}' if event.msg is None else '{msg}'
+ errors.append(msg.format(
+ resource_type=event.resource_type,
+ resource_id=event.resource_id,
+ status=event.status,
+ msg=event.msg,
+ ))
+ if not errors:
+ errors.append('Return code {code} is non-zero'.format(code=rc))
+ result['failed'] = True
+ result['msg'] = '\n'.join(errors)
+ result['cmd'] = ' '.join(shlex_quote(arg) for arg in [cli] + args)
+ result['stdout'] = to_native(stdout)
+ result['stderr'] = to_native(stderr)
+ result['rc'] = rc
+ return True
+
+
+def common_compose_argspec():
+ return dict(
+ project_src=dict(type='path', required=True),
+ project_name=dict(type='str'),
+ files=dict(type='list', elements='path'),
+ env_files=dict(type='list', elements='path'),
+ profiles=dict(type='list', elements='str'),
+ )
+
+
+def combine_binary_output(*outputs):
+ return b'\n'.join(out for out in outputs if out)
+
+
+def combine_text_output(*outputs):
+ return '\n'.join(out for out in outputs if out)
+
+
+class BaseComposeManager(DockerBaseClass):
+ def __init__(self, client, min_version=MINIMUM_COMPOSE_VERSION):
+ super(BaseComposeManager, self).__init__()
+ self.client = client
+ self.check_mode = self.client.check_mode
+ parameters = self.client.module.params
+
+ self.project_src = parameters['project_src']
+ self.project_name = parameters['project_name']
+ self.files = parameters['files']
+ self.env_files = parameters['env_files']
+ self.profiles = parameters['profiles']
+
+ compose = self.client.get_client_plugin_info('compose')
+ if compose is None:
+ self.client.fail('Docker CLI {0} does not have the compose plugin installed'.format(self.client.get_cli()))
+ compose_version = compose['Version'].lstrip('v')
+ self.compose_version = LooseVersion(compose_version)
+ if self.compose_version < LooseVersion(min_version):
+ self.client.fail('Docker CLI {cli} has the compose plugin with version {version}; need version {min_version} or later'.format(
+ cli=self.client.get_cli(),
+ version=compose_version,
+ min_version=min_version,
+ ))
+
+ if not os.path.isdir(self.project_src):
+ self.client.fail('"{0}" is not a directory'.format(self.project_src))
+
+ if self.files:
+ for file in self.files:
+ path = os.path.join(self.project_src, file)
+ if not os.path.exists(path):
+ self.client.fail('Cannot find Compose file "{0}" relative to project directory "{1}"'.format(file, self.project_src))
+ elif all(not os.path.exists(os.path.join(self.project_src, f)) for f in DOCKER_COMPOSE_FILES):
+ filenames = ', '.join(DOCKER_COMPOSE_FILES[:-1])
+ self.client.fail('"{0}" does not contain {1}, or {2}'.format(self.project_src, filenames, DOCKER_COMPOSE_FILES[-1]))
+
+ def get_base_args(self):
+ args = ['compose', '--ansi', 'never']
+ if self.compose_version >= LooseVersion('2.19.0'):
+ # https://github.com/docker/compose/pull/10690
+ args.extend(['--progress', 'plain'])
+ args.extend(['--project-directory', self.project_src])
+ if self.project_name:
+ args.extend(['--project-name', self.project_name])
+ for file in self.files or []:
+ args.extend(['--file', file])
+ for env_file in self.env_files or []:
+ args.extend(['--env-file', env_file])
+ for profile in self.profiles or []:
+ args.extend(['--profile', profile])
+ return args
+
+ def list_containers_raw(self):
+ args = self.get_base_args() + ['ps', '--format', 'json', '--all']
+ if self.compose_version >= LooseVersion('2.23.0'):
+ # https://github.com/docker/compose/pull/11038
+ args.append('--no-trunc')
+ kwargs = dict(cwd=self.project_src, check_rc=True)
+ if self.compose_version >= LooseVersion('2.21.0'):
+ # Breaking change in 2.21.0: https://github.com/docker/compose/pull/10918
+ dummy, containers, dummy = self.client.call_cli_json_stream(*args, **kwargs)
+ else:
+ dummy, containers, dummy = self.client.call_cli_json(*args, **kwargs)
+ return containers
+
+ def list_containers(self):
+ result = []
+ for container in self.list_containers_raw():
+ labels = {}
+ if container.get('Labels'):
+ for part in container['Labels'].split(','):
+ label_value = part.split('=', 1)
+ labels[label_value[0]] = label_value[1] if len(label_value) > 1 else ''
+ container['Labels'] = labels
+ container['Names'] = container.get('Names', container['Name']).split(',')
+ container['Networks'] = container.get('Networks', '').split(',')
+ container['Publishers'] = container.get('Publishers') or []
+ result.append(container)
+ return result
+
+ def list_images(self):
+ args = self.get_base_args() + ['images', '--format', 'json']
+ kwargs = dict(cwd=self.project_src, check_rc=True)
+ dummy, images, dummy = self.client.call_cli_json(*args, **kwargs)
+ return images
+
+ def parse_events(self, stderr, dry_run=False):
+ return parse_events(stderr, dry_run=dry_run, warn_function=self.client.warn)
+
+ def emit_warnings(self, events):
+ emit_warnings(events, warn_function=self.client.warn)
+
+ def update_result(self, result, events, stdout, stderr, ignore_service_pull_events=False):
+ result['changed'] = result.get('changed', False) or has_changes(events, ignore_service_pull_events=ignore_service_pull_events)
+ result['actions'] = result.get('actions', []) + extract_actions(events)
+ result['stdout'] = combine_text_output(result.get('stdout'), to_native(stdout))
+ result['stderr'] = combine_text_output(result.get('stderr'), to_native(stderr))
+
+ def update_failed(self, result, events, args, stdout, stderr, rc):
+ return update_failed(
+ result,
+ events,
+ args=args,
+ stdout=stdout,
+ stderr=stderr,
+ rc=rc,
+ cli=self.client.get_cli(),
+ )
+
+ def cleanup_result(self, result):
+ if not result.get('failed'):
+ # Only return stdout and stderr if it's not empty
+ for res in ('stdout', 'stderr'):
+ if result.get(res) == '':
+ result.pop(res)
diff --git a/ansible_collections/community/docker/plugins/module_utils/image_archive.py b/ansible_collections/community/docker/plugins/module_utils/image_archive.py
index e174631e2..46b5abc14 100644
--- a/ansible_collections/community/docker/plugins/module_utils/image_archive.py
+++ b/ansible_collections/community/docker/plugins/module_utils/image_archive.py
@@ -23,7 +23,7 @@ class ImageArchiveManifestSummary(object):
:param image_id: File name portion of Config entry, e.g. abcde12345 from abcde12345.json
:type image_id: str
:param repo_tags Docker image names, e.g. ["hello-world:latest"]
- :type repo_tags: list
+ :type repo_tags: list[str]
'''
self.image_id = image_id
@@ -60,13 +60,13 @@ def api_image_id(archive_image_id):
return 'sha256:%s' % archive_image_id
-def archived_image_manifest(archive_path):
+def load_archived_image_manifest(archive_path):
'''
- Attempts to get Image.Id and image name from metadata stored in the image
+ Attempts to get image IDs and image names from metadata stored in the image
archive tar file.
- The tar should contain a file "manifest.json" with an array with a single entry,
- and the entry should have a Config field with the image ID in its file name, as
+ The tar should contain a file "manifest.json" with an array with one or more entries,
+ and every entry should have a Config field with the image ID in its file name, as
well as a RepoTags list, which typically has only one entry.
:raises:
@@ -75,7 +75,7 @@ def archived_image_manifest(archive_path):
:param archive_path: Tar file to read
:type archive_path: str
- :return: None, if no file at archive_path, or the extracted image ID, which will not have a sha256: prefix.
+ :return: None, if no file at archive_path, or a list of ImageArchiveManifestSummary objects.
:rtype: ImageArchiveManifestSummary
'''
@@ -100,44 +100,51 @@ def archived_image_manifest(archive_path):
# In Python 2.6, this does not have __exit__
ef.close()
- if len(manifest) != 1:
+ if len(manifest) == 0:
raise ImageArchiveInvalidException(
- "Expected to have one entry in manifest.json but found %s" % len(manifest),
+ "Expected to have at least one entry in manifest.json but found none",
None
)
- m0 = manifest[0]
-
- try:
- config_file = m0['Config']
- except KeyError as exc:
- raise ImageArchiveInvalidException(
- "Failed to get Config entry from manifest.json: %s" % to_native(exc),
- exc
- )
-
- # Extracts hash without 'sha256:' prefix
- try:
- # Strip off .json filename extension, leaving just the hash.
- image_id = os.path.splitext(config_file)[0]
- except Exception as exc:
- raise ImageArchiveInvalidException(
- "Failed to extract image id from config file name %s: %s" % (config_file, to_native(exc)),
- exc
- )
-
- try:
- repo_tags = m0['RepoTags']
- except KeyError as exc:
- raise ImageArchiveInvalidException(
- "Failed to get RepoTags entry from manifest.json: %s" % to_native(exc),
- exc
- )
-
- return ImageArchiveManifestSummary(
- image_id=image_id,
- repo_tags=repo_tags
- )
+ result = []
+ for index, meta in enumerate(manifest):
+ try:
+ config_file = meta['Config']
+ except KeyError as exc:
+ raise ImageArchiveInvalidException(
+ "Failed to get Config entry from {0}th manifest in manifest.json: {1}".format(index + 1, to_native(exc)),
+ exc
+ )
+
+ # Extracts hash without 'sha256:' prefix
+ try:
+ # Strip off .json filename extension, leaving just the hash.
+ image_id = os.path.splitext(config_file)[0]
+ except Exception as exc:
+ raise ImageArchiveInvalidException(
+ "Failed to extract image id from config file name %s: %s" % (config_file, to_native(exc)),
+ exc
+ )
+
+ for prefix in (
+ 'blobs/sha256/', # Moby 25.0.0, Docker API 1.44
+ ):
+ if image_id.startswith(prefix):
+ image_id = image_id[len(prefix):]
+
+ try:
+ repo_tags = meta['RepoTags']
+ except KeyError as exc:
+ raise ImageArchiveInvalidException(
+ "Failed to get RepoTags entry from {0}th manifest in manifest.json: {1}".format(index + 1, to_native(exc)),
+ exc
+ )
+
+ result.append(ImageArchiveManifestSummary(
+ image_id=image_id,
+ repo_tags=repo_tags
+ ))
+ return result
except ImageArchiveInvalidException:
raise
@@ -155,3 +162,33 @@ def archived_image_manifest(archive_path):
raise
except Exception as exc:
raise ImageArchiveInvalidException("Failed to open tar file %s: %s" % (archive_path, to_native(exc)), exc)
+
+
+def archived_image_manifest(archive_path):
+ '''
+ Attempts to get Image.Id and image name from metadata stored in the image
+ archive tar file.
+
+ The tar should contain a file "manifest.json" with an array with a single entry,
+ and the entry should have a Config field with the image ID in its file name, as
+ well as a RepoTags list, which typically has only one entry.
+
+ :raises:
+ ImageArchiveInvalidException: A file already exists at archive_path, but could not extract an image ID from it.
+
+ :param archive_path: Tar file to read
+ :type archive_path: str
+
+ :return: None, if no file at archive_path, or the extracted image ID, which will not have a sha256: prefix.
+ :rtype: ImageArchiveManifestSummary
+ '''
+
+ results = load_archived_image_manifest(archive_path)
+ if results is None:
+ return None
+ if len(results) == 1:
+ return results[0]
+ raise ImageArchiveInvalidException(
+ "Expected to have one entry in manifest.json but found %s" % len(results),
+ None
+ )
diff --git a/ansible_collections/community/docker/plugins/module_utils/module_container/base.py b/ansible_collections/community/docker/plugins/module_utils/module_container/base.py
index 21c29226e..0f776aa5c 100644
--- a/ansible_collections/community/docker/plugins/module_utils/module_container/base.py
+++ b/ansible_collections/community/docker/plugins/module_utils/module_container/base.py
@@ -19,10 +19,15 @@ from ansible.module_utils.six import string_types
from ansible_collections.community.docker.plugins.module_utils.util import (
clean_dict_booleans_for_docker_api,
+ compare_generic,
normalize_healthcheck,
omit_none_from_dict,
)
+from ansible_collections.community.docker.plugins.module_utils._platform import (
+ compare_platform_strings,
+)
+
from ansible_collections.community.docker.plugins.module_utils._api.utils.utils import (
parse_env_file,
)
@@ -67,6 +72,7 @@ class Option(object):
not_a_container_option=False,
not_an_ansible_option=False,
copy_comparison_from=None,
+ compare=None,
):
self.name = name
self.type = type
@@ -106,6 +112,11 @@ class Option(object):
self.not_a_container_option = not_a_container_option
self.not_an_ansible_option = not_an_ansible_option
self.copy_comparison_from = copy_comparison_from
+ self.compare = (
+ lambda param_value, container_value: compare(self, param_value, container_value)
+ ) if compare else (
+ lambda param_value, container_value: compare_generic(param_value, container_value, self.comparison, self.comparison_type)
+ )
class OptionGroup(object):
@@ -166,17 +177,21 @@ class OptionGroup(object):
class Engine(object):
min_api_version = None # string or None
min_api_version_obj = None # LooseVersion object or None
+ extra_option_minimal_versions = None # dict[str, dict[str, Any]] or None
@abc.abstractmethod
- def get_value(self, module, container, api_version, options):
+ def get_value(self, module, container, api_version, options, image, host_info):
pass
+ def compare_value(self, option, param_value, container_value):
+ return option.compare(param_value, container_value)
+
@abc.abstractmethod
def set_value(self, module, data, api_version, options, values):
pass
@abc.abstractmethod
- def get_expected_values(self, module, client, api_version, options, image, values):
+ def get_expected_values(self, module, client, api_version, options, image, values, host_info):
pass
@abc.abstractmethod
@@ -199,6 +214,14 @@ class Engine(object):
def can_update_value(self, api_version):
pass
+ @abc.abstractmethod
+ def needs_container_image(self, values):
+ pass
+
+ @abc.abstractmethod
+ def needs_host_info(self, values):
+ pass
+
class EngineDriver(object):
name = None # string
@@ -209,6 +232,10 @@ class EngineDriver(object):
pass
@abc.abstractmethod
+ def get_host_info(self, client):
+ pass
+
+ @abc.abstractmethod
def get_api_version(self, client):
pass
@@ -483,6 +510,8 @@ def _preprocess_networks(module, values):
parsed_link = (link, link)
parsed_links.append(tuple(parsed_link))
network['links'] = parsed_links
+ if network['mac_address']:
+ network['mac_address'] = network['mac_address'].replace('-', ':')
return values
@@ -733,6 +762,15 @@ def _preprocess_ports(module, values):
return values
+def _compare_platform(option, param_value, container_value):
+ if option.comparison == 'ignore':
+ return True
+ try:
+ return compare_platform_strings(param_value, container_value)
+ except ValueError:
+ return param_value == container_value
+
+
OPTION_AUTO_REMOVE = (
OptionGroup()
.add_option('auto_remove', type='bool')
@@ -910,7 +948,7 @@ OPTION_HOSTNAME = (
)
OPTION_IMAGE = (
- OptionGroup(preprocess=_preprocess_networks)
+ OptionGroup()
.add_option('image', type='str')
)
@@ -984,6 +1022,7 @@ OPTION_NETWORK = (
ipv6_address=dict(type='str'),
aliases=dict(type='list', elements='str'),
links=dict(type='list', elements='str'),
+ mac_address=dict(type='str'),
))
)
@@ -1009,7 +1048,7 @@ OPTION_PIDS_LIMIT = (
OPTION_PLATFORM = (
OptionGroup()
- .add_option('platform', type='str')
+ .add_option('platform', type='str', compare=_compare_platform)
)
OPTION_PRIVILEGED = (
diff --git a/ansible_collections/community/docker/plugins/module_utils/module_container/docker_api.py b/ansible_collections/community/docker/plugins/module_utils/module_container/docker_api.py
index cccf72df4..61a5500c9 100644
--- a/ansible_collections/community/docker/plugins/module_utils/module_container/docker_api.py
+++ b/ansible_collections/community/docker/plugins/module_utils/module_container/docker_api.py
@@ -17,6 +17,11 @@ from ansible_collections.community.docker.plugins.module_utils.common_api import
RequestException,
)
+from ansible_collections.community.docker.plugins.module_utils._platform import (
+ compose_platform_string,
+ normalize_platform_string,
+)
+
from ansible_collections.community.docker.plugins.module_utils.module_container.base import (
OPTION_AUTO_REMOVE,
OPTION_BLKIO_WEIGHT,
@@ -165,6 +170,8 @@ class DockerAPIEngineDriver(EngineDriver):
for option in options.options:
if not option.not_an_ansible_option:
option_minimal_versions[option.name] = {'docker_api_version': engine.min_api_version}
+ if engine.extra_option_minimal_versions:
+ option_minimal_versions.update(engine.extra_option_minimal_versions)
active_options.append(options)
@@ -181,6 +188,9 @@ class DockerAPIEngineDriver(EngineDriver):
return client.module, active_options, client
+ def get_host_info(self, client):
+ return client.info()
+
def get_api_version(self, client):
return client.docker_api_version
@@ -216,7 +226,7 @@ class DockerAPIEngineDriver(EngineDriver):
return client.get_container_by_id(container_id)
def inspect_image_by_id(self, client, image_id):
- return client.find_image_by_id(image_id)
+ return client.find_image_by_id(image_id, accept_missing_image=True)
def inspect_image_by_name(self, client, repository, tag):
return client.find_image(repository, tag)
@@ -236,7 +246,13 @@ class DockerAPIEngineDriver(EngineDriver):
def connect_container_to_network(self, client, container_id, network_id, parameters=None):
parameters = (parameters or {}).copy()
params = {}
- for para, dest_para in {'ipv4_address': 'IPv4Address', 'ipv6_address': 'IPv6Address', 'links': 'Links', 'aliases': 'Aliases'}.items():
+ for para, dest_para in {
+ 'ipv4_address': 'IPv4Address',
+ 'ipv6_address': 'IPv6Address',
+ 'links': 'Links',
+ 'aliases': 'Aliases',
+ 'mac_address': 'MacAddress',
+ }.items():
value = parameters.pop(para, None)
if value:
if para == 'links':
@@ -387,18 +403,27 @@ class DockerAPIEngine(Engine):
can_set_value=None,
can_update_value=None,
min_api_version=None,
+ compare_value=None,
+ needs_container_image=None,
+ needs_host_info=None,
+ extra_option_minimal_versions=None,
):
self.min_api_version = min_api_version
self.min_api_version_obj = None if min_api_version is None else LooseVersion(min_api_version)
self.get_value = get_value
self.set_value = set_value
- self.get_expected_values = get_expected_values or (lambda module, client, api_version, options, image, values: values)
+ self.get_expected_values = get_expected_values or (lambda module, client, api_version, options, image, values, host_info: values)
self.ignore_mismatching_result = ignore_mismatching_result or \
(lambda module, client, api_version, option, image, container_value, expected_value: False)
self.preprocess_value = preprocess_value or (lambda module, client, api_version, options, values: values)
self.update_value = update_value
self.can_set_value = can_set_value or (lambda api_version: set_value is not None)
self.can_update_value = can_update_value or (lambda api_version: update_value is not None)
+ self.needs_container_image = needs_container_image or (lambda values: False)
+ self.needs_host_info = needs_host_info or (lambda values: False)
+ if compare_value is not None:
+ self.compare_value = compare_value
+ self.extra_option_minimal_versions = extra_option_minimal_versions
@classmethod
def config_value(
@@ -423,7 +448,7 @@ class DockerAPIEngine(Engine):
values[options[0].name] = value
return values
- def get_value(module, container, api_version, options):
+ def get_value(module, container, api_version, options, image, host_info):
if len(options) != 1:
raise AssertionError('config_value can only be used for a single option')
value = container['Config'].get(config_name, _SENTRY)
@@ -435,7 +460,7 @@ class DockerAPIEngine(Engine):
get_expected_values_ = None
if get_expected_value:
- def get_expected_values_(module, client, api_version, options, image, values):
+ def get_expected_values_(module, client, api_version, options, image, values, host_info):
if len(options) != 1:
raise AssertionError('host_config_value can only be used for a single option')
value = values.get(options[0].name, _SENTRY)
@@ -499,7 +524,7 @@ class DockerAPIEngine(Engine):
values[options[0].name] = value
return values
- def get_value(module, container, api_version, options):
+ def get_value(module, container, api_version, options, get_value, host_info):
if len(options) != 1:
raise AssertionError('host_config_value can only be used for a single option')
value = container['HostConfig'].get(host_config_name, _SENTRY)
@@ -511,7 +536,7 @@ class DockerAPIEngine(Engine):
get_expected_values_ = None
if get_expected_value:
- def get_expected_values_(module, client, api_version, options, image, values):
+ def get_expected_values_(module, client, api_version, options, image, values, host_info):
if len(options) != 1:
raise AssertionError('host_config_value can only be used for a single option')
value = values.get(options[0].name, _SENTRY)
@@ -585,7 +610,7 @@ def _get_default_host_ip(module, client):
return ip
-def _get_value_detach_interactive(module, container, api_version, options):
+def _get_value_detach_interactive(module, container, api_version, options, image, host_info):
attach_stdin = container['Config'].get('OpenStdin')
attach_stderr = container['Config'].get('AttachStderr')
attach_stdout = container['Config'].get('AttachStdout')
@@ -836,7 +861,7 @@ def _get_network_id(module, client, network_name):
client.fail("Error getting network id for %s - %s" % (network_name, to_native(exc)))
-def _get_values_network(module, container, api_version, options):
+def _get_values_network(module, container, api_version, options, image, host_info):
value = container['HostConfig'].get('NetworkMode', _SENTRY)
if value is _SENTRY:
return {}
@@ -852,7 +877,7 @@ def _set_values_network(module, data, api_version, options, values):
data['HostConfig']['NetworkMode'] = value
-def _get_values_mounts(module, container, api_version, options):
+def _get_values_mounts(module, container, api_version, options, image, host_info):
volumes = container['Config'].get('Volumes')
binds = container['HostConfig'].get('Binds')
# According to https://github.com/moby/moby/, support for HostConfig.Mounts
@@ -916,7 +941,7 @@ def _get_image_binds(volumes):
return results
-def _get_expected_values_mounts(module, client, api_version, options, image, values):
+def _get_expected_values_mounts(module, client, api_version, options, image, values, host_info):
expected_values = {}
# binds
@@ -1017,7 +1042,7 @@ def _set_values_mounts(module, data, api_version, options, values):
data['HostConfig']['Binds'] = values['volume_binds']
-def _get_values_log(module, container, api_version, options):
+def _get_values_log(module, container, api_version, options, image, host_info):
log_config = container['HostConfig'].get('LogConfig') or {}
return {
'log_driver': log_config.get('Type'),
@@ -1037,18 +1062,50 @@ def _set_values_log(module, data, api_version, options, values):
data['HostConfig']['LogConfig'] = log_config
-def _get_values_platform(module, container, api_version, options):
+def _get_values_platform(module, container, api_version, options, image, host_info):
+ if image and (image.get('Os') or image.get('Architecture') or image.get('Variant')):
+ return {
+ 'platform': compose_platform_string(
+ os=image.get('Os'),
+ arch=image.get('Architecture'),
+ variant=image.get('Variant'),
+ daemon_os=host_info.get('OSType') if host_info else None,
+ daemon_arch=host_info.get('Architecture') if host_info else None,
+ )
+ }
return {
'platform': container.get('Platform'),
}
+def _get_expected_values_platform(module, client, api_version, options, image, values, host_info):
+ expected_values = {}
+ if 'platform' in values:
+ try:
+ expected_values['platform'] = normalize_platform_string(
+ values['platform'],
+ daemon_os=host_info.get('OSType') if host_info else None,
+ daemon_arch=host_info.get('Architecture') if host_info else None,
+ )
+ except ValueError as exc:
+ module.fail_json(msg='Error while parsing platform parameer: %s' % (to_native(exc), ))
+ return expected_values
+
+
def _set_values_platform(module, data, api_version, options, values):
if 'platform' in values:
data['platform'] = values['platform']
-def _get_values_restart(module, container, api_version, options):
+def _needs_container_image_platform(values):
+ return 'platform' in values
+
+
+def _needs_host_info_platform(values):
+ return 'platform' in values
+
+
+def _get_values_restart(module, container, api_version, options, image, host_info):
restart_policy = container['HostConfig'].get('RestartPolicy') or {}
return {
'restart_policy': restart_policy.get('Name'),
@@ -1077,7 +1134,7 @@ def _update_value_restart(module, data, api_version, options, values):
}
-def _get_values_ports(module, container, api_version, options):
+def _get_values_ports(module, container, api_version, options, image, host_info):
host_config = container['HostConfig']
config = container['Config']
@@ -1094,7 +1151,7 @@ def _get_values_ports(module, container, api_version, options):
}
-def _get_expected_values_ports(module, client, api_version, options, image, values):
+def _get_expected_values_ports(module, client, api_version, options, image, values, host_info):
expected_values = {}
if 'published_ports' in values:
@@ -1283,6 +1340,12 @@ OPTION_NETWORK.add_engine('docker_api', DockerAPIEngine(
get_value=_get_values_network,
set_value=_set_values_network,
ignore_mismatching_result=_ignore_mismatching_network_result,
+ extra_option_minimal_versions={
+ 'networks.mac_address': {
+ 'docker_api_version': '1.44',
+ 'detect_usage': lambda c: any(net_info.get('mac_address') is not None for net_info in (c.module.params['networks'] or [])),
+ },
+ },
))
OPTION_OOM_KILLER.add_engine('docker_api', DockerAPIEngine.host_config_value('OomKillDisable'))
@@ -1296,6 +1359,9 @@ OPTION_PIDS_LIMIT.add_engine('docker_api', DockerAPIEngine.host_config_value('Pi
OPTION_PLATFORM.add_engine('docker_api', DockerAPIEngine(
get_value=_get_values_platform,
set_value=_set_values_platform,
+ get_expected_values=_get_expected_values_platform,
+ needs_container_image=_needs_container_image_platform,
+ needs_host_info=_needs_host_info_platform,
min_api_version='1.41',
))
diff --git a/ansible_collections/community/docker/plugins/module_utils/module_container/module.py b/ansible_collections/community/docker/plugins/module_utils/module_container/module.py
index 230dbfb40..5d819efa4 100644
--- a/ansible_collections/community/docker/plugins/module_utils/module_container/module.py
+++ b/ansible_collections/community/docker/plugins/module_utils/module_container/module.py
@@ -78,6 +78,11 @@ class ContainerManager(DockerBaseClass):
self.param_output_logs = self.module.params['output_logs']
self.param_paused = self.module.params['paused']
self.param_pull = self.module.params['pull']
+ if self.param_pull is True:
+ self.param_pull = 'always'
+ if self.param_pull is False:
+ self.param_pull = 'missing'
+ self.param_pull_check_mode_behavior = self.module.params['pull_check_mode_behavior']
self.param_recreate = self.module.params['recreate']
self.param_removal_wait_timeout = self.module.params['removal_wait_timeout']
self.param_restart = self.module.params['restart']
@@ -132,7 +137,7 @@ class ContainerManager(DockerBaseClass):
self.all_options['image'].comparison = 'ignore'
if self.module.params['purge_networks']:
self.all_options['networks'].comparison = 'strict'
- # Process comparsions specified by user
+ # Process comparisons specified by user
if self.module.params.get('comparisons'):
# If '*' appears in comparisons, process it first
if '*' in self.module.params['comparisons']:
@@ -268,6 +273,20 @@ class ContainerManager(DockerBaseClass):
parameters.append((options, values))
return parameters
+ def _needs_container_image(self):
+ for options, values in self.parameters:
+ engine = options.get_engine(self.engine_driver.name)
+ if engine.needs_container_image(values):
+ return True
+ return False
+
+ def _needs_host_info(self):
+ for options, values in self.parameters:
+ engine = options.get_engine(self.engine_driver.name)
+ if engine.needs_host_info(values):
+ return True
+ return False
+
def present(self, state):
self.parameters = self._collect_params(self.options)
container = self._get_container(self.param_name)
@@ -280,8 +299,10 @@ class ContainerManager(DockerBaseClass):
# the container already runs or not; in the former case, in case the
# container needs to be restarted, we use the existing container's
# image ID.
- image, comparison_image = self._get_image(container)
+ image, container_image, comparison_image = self._get_image(
+ container, needs_container_image=self._needs_container_image())
self.log(image, pretty_print=True)
+ host_info = self.engine_driver.get_host_info(self.client) if self._needs_host_info() else None
if not container.exists or container.removing:
# New container
if container.removing:
@@ -301,13 +322,24 @@ class ContainerManager(DockerBaseClass):
container_created = True
else:
# Existing container
- different, differences = self.has_different_configuration(container, comparison_image)
+ different, differences = self.has_different_configuration(container, container_image, comparison_image, host_info)
image_different = False
if self.all_options['image'].comparison == 'strict':
image_different = self._image_is_different(image, container)
- if self.param_image_name_mismatch == 'recreate' and self.param_image is not None and self.param_image != container.image_name:
- different = True
- self.diff_tracker.add('image_name', parameter=self.param_image, active=container.image_name)
+ if self.param_image_name_mismatch != 'ignore' and self.param_image is not None and self.param_image != container.image_name:
+ if self.param_image_name_mismatch == 'recreate':
+ different = True
+ self.diff_tracker.add('image_name', parameter=self.param_image, active=container.image_name)
+ else:
+ # The default has been deprecated!
+ self.module.deprecate(
+ 'The default value "ignore" for image_name_mismatch has been deprecated and will change to "recreate"'
+ ' in community.docker 4.0.0. In the current situation, this would cause the container to be recreated'
+ ' since the current container\'s image name "{active}" does not match the desired image name "{parameter}".'.format(
+ parameter=self.param_image, active=container.image_name),
+ version='4.0.0',
+ collection_name='community.docker',
+ )
if image_different or different or self.param_recreate:
self.diff_tracker.merge(differences)
self.diff['differences'] = differences.get_legacy_docker_container_diffs()
@@ -333,7 +365,7 @@ class ContainerManager(DockerBaseClass):
comparison_image = image
if container and container.exists:
- container = self.update_limits(container, comparison_image)
+ container = self.update_limits(container, container_image, comparison_image, host_info)
container = self.update_networks(container, container_created)
if state == 'started' and not container.running:
@@ -398,45 +430,58 @@ class ContainerManager(DockerBaseClass):
image = self.engine_driver.inspect_image_by_name(self.client, repository, tag)
return image or fallback
- def _get_image(self, container):
+ def _get_image(self, container, needs_container_image=False):
image_parameter = self.param_image
+ get_container_image = needs_container_image or not image_parameter
+ container_image = self._get_container_image(container) if get_container_image else None
+ if container_image:
+ self.log("current image")
+ self.log(container_image, pretty_print=True)
if not image_parameter:
self.log('No image specified')
- return None, self._get_container_image(container)
+ return None, container_image, container_image
if is_image_name_id(image_parameter):
image = self.engine_driver.inspect_image_by_id(self.client, image_parameter)
+ if image is None:
+ self.client.fail("Cannot find image with ID %s" % (image_parameter, ))
else:
repository, tag = parse_repository_tag(image_parameter)
if not tag:
tag = "latest"
image = self.engine_driver.inspect_image_by_name(self.client, repository, tag)
- if not image or self.param_pull:
+ if not image and self.param_pull == "never":
+ self.client.fail("Cannot find image with name %s:%s, and pull=never" % (repository, tag))
+ if not image or self.param_pull == "always":
if not self.check_mode:
self.log("Pull the image.")
image, alreadyToLatest = self.engine_driver.pull_image(
self.client, repository, tag, platform=self.module.params['platform'])
if alreadyToLatest:
self.results['changed'] = False
+ self.results['actions'].append(dict(pulled_image="%s:%s" % (repository, tag), changed=False))
else:
self.results['changed'] = True
- self.results['actions'].append(dict(pulled_image="%s:%s" % (repository, tag)))
- elif not image:
- # If the image isn't there, claim we'll pull.
- # (Implicitly: if the image is there, claim it already was latest.)
+ self.results['actions'].append(dict(pulled_image="%s:%s" % (repository, tag), changed=True))
+ elif not image or self.param_pull_check_mode_behavior == 'always':
+ # If the image isn't there, or pull_check_mode_behavior == 'always', claim we'll
+ # pull. (Implicitly: if the image is there, claim it already was latest unless
+ # pull_check_mode_behavior == 'always'.)
self.results['changed'] = True
- self.results['actions'].append(dict(pulled_image="%s:%s" % (repository, tag)))
+ action = dict(pulled_image="%s:%s" % (repository, tag))
+ if not image:
+ action['changed'] = True
+ self.results['actions'].append(action)
self.log("image")
self.log(image, pretty_print=True)
comparison_image = image
if self.param_image_comparison == 'current-image':
- comparison_image = self._get_container_image(container, image)
- if comparison_image != image:
- self.log("current image")
- self.log(comparison_image, pretty_print=True)
+ if not get_container_image:
+ container_image = self._get_container_image(container)
+ comparison_image = container_image
- return image, comparison_image
+ return image, container_image, comparison_image
def _image_is_different(self, image, container):
if image and image.get('Id'):
@@ -455,15 +500,16 @@ class ContainerManager(DockerBaseClass):
params['Image'] = image
return params
- def _record_differences(self, differences, options, param_values, engine, container, image):
- container_values = engine.get_value(self.module, container.raw, self.engine_driver.get_api_version(self.client), options.options)
+ def _record_differences(self, differences, options, param_values, engine, container, container_image, image, host_info):
+ container_values = engine.get_value(
+ self.module, container.raw, self.engine_driver.get_api_version(self.client), options.options, container_image, host_info)
expected_values = engine.get_expected_values(
- self.module, self.client, self.engine_driver.get_api_version(self.client), options.options, image, param_values.copy())
+ self.module, self.client, self.engine_driver.get_api_version(self.client), options.options, image, param_values.copy(), host_info)
for option in options.options:
if option.name in expected_values:
param_value = expected_values[option.name]
container_value = container_values.get(option.name)
- match = compare_generic(param_value, container_value, option.comparison, option.comparison_type)
+ match = engine.compare_value(option, param_value, container_value)
if not match:
# No match.
@@ -497,28 +543,28 @@ class ContainerManager(DockerBaseClass):
c = sorted(c, key=sort_key_fn)
differences.add(option.name, parameter=p, active=c)
- def has_different_configuration(self, container, image):
+ def has_different_configuration(self, container, container_image, image, host_info):
differences = DifferenceTracker()
update_differences = DifferenceTracker()
for options, param_values in self.parameters:
engine = options.get_engine(self.engine_driver.name)
if engine.can_update_value(self.engine_driver.get_api_version(self.client)):
- self._record_differences(update_differences, options, param_values, engine, container, image)
+ self._record_differences(update_differences, options, param_values, engine, container, container_image, image, host_info)
else:
- self._record_differences(differences, options, param_values, engine, container, image)
+ self._record_differences(differences, options, param_values, engine, container, container_image, image, host_info)
has_differences = not differences.empty
# Only consider differences of properties that can be updated when there are also other differences
if has_differences:
differences.merge(update_differences)
return has_differences, differences
- def has_different_resource_limits(self, container, image):
+ def has_different_resource_limits(self, container, container_image, image, host_info):
differences = DifferenceTracker()
for options, param_values in self.parameters:
engine = options.get_engine(self.engine_driver.name)
if not engine.can_update_value(self.engine_driver.get_api_version(self.client)):
continue
- self._record_differences(differences, options, param_values, engine, container, image)
+ self._record_differences(differences, options, param_values, engine, container, container_image, image, host_info)
has_differences = not differences.empty
return has_differences, differences
@@ -531,8 +577,8 @@ class ContainerManager(DockerBaseClass):
engine.update_value(self.module, result, self.engine_driver.get_api_version(self.client), options.options, values)
return result
- def update_limits(self, container, image):
- limits_differ, different_limits = self.has_different_resource_limits(container, image)
+ def update_limits(self, container, container_image, image, host_info):
+ limits_differ, different_limits = self.has_different_resource_limits(container, container_image, image, host_info)
if limits_differ:
self.log("limit differences:")
self.log(different_limits.get_legacy_docker_container_diffs(), pretty_print=True)
@@ -580,6 +626,8 @@ class ContainerManager(DockerBaseClass):
expected_links.append("%s:%s" % (link, alias))
if not compare_generic(expected_links, network_info.get('Links'), 'allow_more_present', 'set'):
diff = True
+ if network.get('mac_address') and network['mac_address'] != network_info.get('MacAddress'):
+ diff = True
if diff:
different = True
differences.append(dict(
@@ -589,7 +637,8 @@ class ContainerManager(DockerBaseClass):
ipv4_address=network_info_ipam.get('IPv4Address'),
ipv6_address=network_info_ipam.get('IPv6Address'),
aliases=network_info.get('Aliases'),
- links=network_info.get('Links')
+ links=network_info.get('Links'),
+ mac_address=network_info.get('MacAddress'),
)
))
return different, differences
@@ -816,14 +865,15 @@ def run_module(engine_driver):
image=dict(type='str'),
image_comparison=dict(type='str', choices=['desired-image', 'current-image'], default='desired-image'),
image_label_mismatch=dict(type='str', choices=['ignore', 'fail'], default='ignore'),
- image_name_mismatch=dict(type='str', choices=['ignore', 'recreate'], default='ignore'),
+ image_name_mismatch=dict(type='str', choices=['ignore', 'recreate']),
keep_volumes=dict(type='bool', default=True),
kill_signal=dict(type='str'),
name=dict(type='str', required=True),
networks_cli_compatible=dict(type='bool', default=True),
output_logs=dict(type='bool', default=False),
paused=dict(type='bool'),
- pull=dict(type='bool', default=False),
+ pull=dict(type='raw', choices=['never', 'missing', 'always', True, False], default='missing'),
+ pull_check_mode_behavior=dict(type='str', choices=['image_not_present', 'always'], default='image_not_present'),
purge_networks=dict(type='bool', default=False, removed_in_version='4.0.0', removed_from_collection='community.docker'),
recreate=dict(type='bool', default=False),
removal_wait_timeout=dict(type='float'),
diff --git a/ansible_collections/community/docker/plugins/module_utils/util.py b/ansible_collections/community/docker/plugins/module_utils/util.py
index 9c6b738c6..efd3301f1 100644
--- a/ansible_collections/community/docker/plugins/module_utils/util.py
+++ b/ansible_collections/community/docker/plugins/module_utils/util.py
@@ -6,6 +6,7 @@ from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
+import json
import re
from datetime import timedelta
@@ -14,7 +15,7 @@ from ansible.module_utils.common.collections import is_sequence
from ansible.module_utils.six.moves.urllib.parse import urlparse
-DEFAULT_DOCKER_HOST = 'unix://var/run/docker.sock'
+DEFAULT_DOCKER_HOST = 'unix:///var/run/docker.sock'
DEFAULT_TLS = False
DEFAULT_TLS_VERIFY = False
DEFAULT_TLS_HOSTNAME = 'localhost' # deprecated
@@ -25,7 +26,7 @@ DOCKER_COMMON_ARGS = dict(
tls_hostname=dict(type='str', fallback=(env_fallback, ['DOCKER_TLS_HOSTNAME'])),
api_version=dict(type='str', default='auto', fallback=(env_fallback, ['DOCKER_API_VERSION']), aliases=['docker_api_version']),
timeout=dict(type='int', default=DEFAULT_TIMEOUT_SECONDS, fallback=(env_fallback, ['DOCKER_TIMEOUT'])),
- ca_cert=dict(type='path', aliases=['tls_ca_cert', 'cacert_path']),
+ ca_path=dict(type='path', aliases=['ca_cert', 'tls_ca_cert', 'cacert_path']),
client_cert=dict(type='path', aliases=['tls_client_cert', 'cert_path']),
client_key=dict(type='path', aliases=['tls_client_key', 'key_path']),
ssl_version=dict(type='str', fallback=(env_fallback, ['DOCKER_SSL_VERSION'])),
@@ -85,6 +86,19 @@ def sanitize_result(data):
return data
+def log_debug(msg, pretty_print=False):
+ """Write a log message to docker.log.
+
+ If ``pretty_print=True``, the message will be pretty-printed as JSON.
+ """
+ with open('docker.log', 'a') as log_file:
+ if pretty_print:
+ log_file.write(json.dumps(msg, sort_keys=True, indent=4, separators=(',', ': ')))
+ log_file.write(u'\n')
+ else:
+ log_file.write(msg + u'\n')
+
+
class DockerBaseClass(object):
def __init__(self):
self.debug = False
@@ -92,12 +106,7 @@ class DockerBaseClass(object):
def log(self, msg, pretty_print=False):
pass
# if self.debug:
- # log_file = open('docker.log', 'a')
- # if pretty_print:
- # log_file.write(json.dumps(msg, sort_keys=True, indent=4, separators=(',', ': ')))
- # log_file.write(u'\n')
- # else:
- # log_file.write(msg + u'\n')
+ # log_debug(msg, pretty_print=pretty_print)
def update_tls_hostname(result, old_behavior=False, deprecate_function=None, uses_tls=True):
diff --git a/ansible_collections/community/docker/plugins/modules/current_container_facts.py b/ansible_collections/community/docker/plugins/modules/current_container_facts.py
index f2cde2b59..2daf60bb0 100644
--- a/ansible_collections/community/docker/plugins/modules/current_container_facts.py
+++ b/ansible_collections/community/docker/plugins/modules/current_container_facts.py
@@ -58,10 +58,10 @@ ansible_facts:
description:
- The detected container environment.
- Contains an empty string if no container was detected, or a non-empty string identifying the container environment.
- - C(docker) indicates that the module ran inside a regular Docker container.
- - C(azure_pipelines) indicates that the module ran on Azure Pipelines. This seems to no longer be reported.
- - C(github_actions) indicates that the module ran inside a Docker container on GitHub Actions. It is supported since community.docker 2.4.0.
- - C(podman) indicates that the module ran inside a regular Podman container. It is supported since community.docker 3.3.0.
+ - V(docker) indicates that the module ran inside a regular Docker container.
+ - V(azure_pipelines) indicates that the module ran on Azure Pipelines. This seems to no longer be reported.
+ - V(github_actions) indicates that the module ran inside a Docker container on GitHub Actions. It is supported since community.docker 2.4.0.
+ - V(podman) indicates that the module ran inside a regular Podman container. It is supported since community.docker 3.3.0.
returned: always
type: str
choices:
diff --git a/ansible_collections/community/docker/plugins/modules/docker_compose.py b/ansible_collections/community/docker/plugins/modules/docker_compose.py
index 01db6a22f..f8edbee4b 100644
--- a/ansible_collections/community/docker/plugins/modules/docker_compose.py
+++ b/ansible_collections/community/docker/plugins/modules/docker_compose.py
@@ -12,13 +12,14 @@ DOCUMENTATION = '''
module: docker_compose
-short_description: Manage multi-container Docker applications with Docker Compose.
+short_description: Manage multi-container Docker applications with Docker Compose V1
author: "Chris Houseknecht (@chouseknecht)"
description:
- Uses Docker Compose to start, shutdown and scale services. B(This module requires docker-compose < 2.0.0.)
- - Configuration can be read from a C(docker-compose.yml) or C(docker-compose.yaml) file or inline using the I(definition) option.
+ Use the M(community.docker.docker_compose_v2) module for using the modern Docker compose CLI plugin.
+ - Configuration can be read from a C(docker-compose.yml) or C(docker-compose.yaml) file or inline using the O(definition) option.
- See the examples for more details.
- Supports check mode.
- This module was called C(docker_service) before Ansible 2.8. The usage did not change.
@@ -39,27 +40,27 @@ options:
project_src:
description:
- Path to a directory containing a C(docker-compose.yml) or C(docker-compose.yaml) file.
- - Mutually exclusive with I(definition).
- - Required when no I(definition) is provided.
+ - Mutually exclusive with O(definition).
+ - Required when no O(definition) is provided.
type: path
project_name:
description:
- - Provide a project name. If not provided, the project name is taken from the basename of I(project_src).
- - Required when I(definition) is provided.
+ - Provide a project name. If not provided, the project name is taken from the basename of O(project_src).
+ - Required when O(definition) is provided.
type: str
env_file:
description:
- - By default environment files are loaded from a C(.env) file located directly under the I(project_src) directory.
- - I(env_file) can be used to specify the path of a custom environment file instead.
- - The path is relative to the I(project_src) directory.
+ - By default environment files are loaded from a C(.env) file located directly under the O(project_src) directory.
+ - O(env_file) can be used to specify the path of a custom environment file instead.
+ - The path is relative to the O(project_src) directory.
- Requires C(docker-compose) version 1.25.0 or greater.
- "Note: C(docker-compose) versions C(<=1.28) load the env file from the current working directory of the
- C(docker-compose) command rather than I(project_src)."
+ C(docker-compose) command rather than O(project_src)."
type: path
version_added: 1.9.0
files:
description:
- - List of Compose file names relative to I(project_src). Overrides C(docker-compose.yml) or C(docker-compose.yaml).
+ - List of Compose file names relative to O(project_src). Overrides C(docker-compose.yml) or C(docker-compose.yaml).
- Files are loaded and merged in the order given.
type: list
elements: path
@@ -74,9 +75,9 @@ options:
state:
description:
- Desired state of the project.
- - Specifying C(present) is the same as running C(docker-compose up) resp. C(docker-compose stop) (with I(stopped)) resp. C(docker-compose restart)
- (with I(restarted)).
- - Specifying C(absent) is the same as running C(docker-compose down).
+ - Specifying V(present) is the same as running C(docker-compose up) resp. C(docker-compose stop) (with O(stopped=true)) resp. C(docker-compose restart)
+ (with O(restarted=true)).
+ - Specifying V(absent) is the same as running C(docker-compose down).
type: str
default: present
choices:
@@ -84,25 +85,25 @@ options:
- present
services:
description:
- - When I(state) is C(present) run C(docker-compose up) resp. C(docker-compose stop) (with I(stopped)) resp. C(docker-compose restart) (with I(restarted))
- on a subset of services.
- - If empty, which is the default, the operation will be performed on all services defined in the Compose file (or inline I(definition)).
+ - When O(state) is V(present) run C(docker-compose up) resp. C(docker-compose stop) (with O(stopped=true)) resp.
+ C(docker-compose restart) (with O(restarted=true)) on a subset of services.
+ - If empty, which is the default, the operation will be performed on all services defined in the Compose file (or inline O(definition)).
type: list
elements: str
scale:
description:
- - When I(state) is C(present) scale services. Provide a dictionary of key/value pairs where the key
+ - When O(state) is V(present) scale services. Provide a dictionary of key/value pairs where the key
is the name of the service and the value is an integer count for the number of containers.
type: dict
dependencies:
description:
- - When I(state) is C(present) specify whether or not to include linked services.
+ - When O(state) is V(present) specify whether or not to include linked services.
type: bool
default: true
definition:
description:
- Compose file describing one or more services, networks and volumes.
- - Mutually exclusive with I(project_src) and I(files).
+ - Mutually exclusive with O(project_src) and O(files).
type: dict
hostname_check:
description:
@@ -112,8 +113,8 @@ options:
recreate:
description:
- By default containers will be recreated when their configuration differs from the service definition.
- - Setting to C(never) ignores configuration differences and leaves existing containers unchanged.
- - Setting to C(always) forces recreation of all existing containers.
+ - Setting to V(never) ignores configuration differences and leaves existing containers unchanged.
+ - Setting to V(always) forces recreation of all existing containers.
type: str
default: smart
choices:
@@ -122,49 +123,49 @@ options:
- smart
build:
description:
- - Use with I(state) C(present) to always build images prior to starting the application.
+ - Use with O(state=present) to always build images prior to starting the application.
- Same as running C(docker-compose build) with the pull option.
- Images will only be rebuilt if Docker detects a change in the Dockerfile or build directory contents.
- - Use the I(nocache) option to ignore the image cache when performing the build.
- - If an existing image is replaced, services using the image will be recreated unless I(recreate) is C(never).
+ - Use the O(nocache) option to ignore the image cache when performing the build.
+ - If an existing image is replaced, services using the image will be recreated unless O(recreate=never).
type: bool
default: false
pull:
description:
- - Use with I(state) C(present) to always pull images prior to starting the application.
+ - Use with O(state=present) to always pull images prior to starting the application.
- Same as running C(docker-compose pull).
- - When a new image is pulled, services using the image will be recreated unless I(recreate) is C(never).
+ - When a new image is pulled, services using the image will be recreated unless O(recreate=never).
type: bool
default: false
nocache:
description:
- - Use with the I(build) option to ignore the cache during the image build process.
+ - Use with the O(build) option to ignore the cache during the image build process.
type: bool
default: false
remove_images:
description:
- - Use with I(state) C(absent) to remove all images or only local images.
+ - Use with O(state=absent) to remove all images or only local images.
type: str
choices:
- 'all'
- 'local'
remove_volumes:
description:
- - Use with I(state) C(absent) to remove data volumes.
+ - Use with O(state=absent) to remove data volumes.
type: bool
default: false
stopped:
description:
- - Use with I(state) C(present) to stop all containers defined in the Compose file.
- - If I(services) is defined, only the containers listed there will be stopped.
+ - Use with O(state=present) to stop all containers defined in the Compose file.
+ - If O(services) is defined, only the containers listed there will be stopped.
- Requires C(docker-compose) version 1.17.0 or greater for full support. For older versions, the services will
first be started and then stopped when the service is supposed to be created as stopped.
type: bool
default: false
restarted:
description:
- - Use with I(state) C(present) to restart all containers defined in the Compose file.
- - If I(services) is defined, only the containers listed there will be restarted.
+ - Use with O(state=present) to restart all containers defined in the Compose file.
+ - If O(services) is defined, only the containers listed there will be restarted.
type: bool
default: false
remove_orphans:
@@ -175,8 +176,8 @@ options:
timeout:
description:
- Timeout in seconds for container shutdown when attached or when containers are already running.
- - By default C(compose) will use a C(10s) timeout unless C(default_grace_period) is defined for a
- particular service in the I(project_src).
+ - By default C(docker-compose) will use a V(10) seconds timeout unless C(default_grace_period) is defined for a
+ particular service in the O(project_src).
type: int
default: null
use_ssh_client:
@@ -184,10 +185,13 @@ options:
- Currently ignored for this module, but might suddenly be supported later on.
requirements:
- - "L(Docker SDK for Python,https://docker-py.readthedocs.io/en/stable/) >= 1.8.0"
+ - "L(Docker SDK for Python,https://docker-py.readthedocs.io/en/stable/) >= 1.8.0, < 7. Docker SDK for Python 7+ is incompatible to docker-compose v1."
- "docker-compose >= 1.7.0, < 2.0.0"
- "Docker API >= 1.25"
- "PyYAML >= 3.11"
+
+seealso:
+ - module: community.docker.docker_compose_v2
'''
EXAMPLES = '''
@@ -236,7 +240,7 @@ EXAMPLES = '''
ansible.builtin.debug:
var: output
- - name: Verify that web and db services are running
+ - name: Verify that web and db services are not running
ansible.builtin.assert:
that:
- "not output.services.web.flask_web_1.state.running"
@@ -440,7 +444,7 @@ services:
actions:
description: Provides the actions to be taken on each service as determined by compose.
- returned: when in check mode or I(debug) is C(true)
+ returned: when in check mode or O(debug=true)
type: complex
contains:
service_name:
diff --git a/ansible_collections/community/docker/plugins/modules/docker_compose_v2.py b/ansible_collections/community/docker/plugins/modules/docker_compose_v2.py
new file mode 100644
index 000000000..29bb81ad9
--- /dev/null
+++ b/ansible_collections/community/docker/plugins/modules/docker_compose_v2.py
@@ -0,0 +1,638 @@
+#!/usr/bin/python
+#
+# Copyright (c) 2023, Felix Fontein <felix@fontein.de>
+# Copyright (c) 2023, Léo El Amri (@lel-amri)
+# Copyright 2016 Red Hat | Ansible
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+
+DOCUMENTATION = '''
+
+module: docker_compose_v2
+
+short_description: Manage multi-container Docker applications with Docker Compose CLI plugin
+
+version_added: 3.6.0
+
+description:
+ - Uses Docker Compose to start or shutdown services.
+
+extends_documentation_fragment:
+ - community.docker.compose_v2
+ - community.docker.compose_v2.minimum_version
+ - community.docker.docker.cli_documentation
+ - community.docker.attributes
+ - community.docker.attributes.actiongroup_docker
+
+attributes:
+ check_mode:
+ support: full
+ details:
+ - In check mode, pulling the image does not result in a changed result.
+ diff_mode:
+ support: none
+
+options:
+ state:
+ description:
+ - Desired state of the project.
+ - V(present) is equivalent to running C(docker compose up).
+ - V(stopped) is equivalent to running C(docker compose stop).
+ - V(absent) is equivalent to running C(docker compose down).
+ - V(restarted) is equivalent to running C(docker compose restart).
+ type: str
+ default: present
+ choices:
+ - absent
+ - stopped
+ - restarted
+ - present
+ pull:
+ description:
+ - Whether to pull images before running. This is used when C(docker compose up) is run.
+ - V(always) ensures that the images are always pulled, even when already present on the Docker daemon.
+ - V(missing) only pulls them when they are not present on the Docker daemon.
+ - V(never) never pulls images. If they are not present, the module will fail when trying to create the containers that need them.
+ - V(policy) use the Compose file's C(pull_policy) defined for the service to figure out what to do.
+ type: str
+ choices:
+ - always
+ - missing
+ - never
+ - policy
+ default: policy
+ build:
+ description:
+ - Whether to build images before starting containers. This is used when C(docker compose up) is run.
+ - V(always) always builds before starting containers. This is equivalent to the C(--build) option of C(docker compose up).
+ - V(never) never builds before starting containers. This is equivalent to the C(--no-build) option of C(docker compose up).
+ - V(policy) uses the policy as defined in the Compose file.
+ type: str
+ choices:
+ - always
+ - never
+ - policy
+ default: policy
+ dependencies:
+ description:
+ - When O(state) is V(present) or V(restarted), specify whether or not to include linked services.
+ type: bool
+ default: true
+ recreate:
+ description:
+ - By default containers will be recreated when their configuration differs from the service definition.
+ - Setting to V(never) ignores configuration differences and leaves existing containers unchanged.
+ - Setting to V(always) forces recreation of all existing containers.
+ type: str
+ default: auto
+ choices:
+ - always
+ - never
+ - auto
+ remove_images:
+ description:
+ - Use with O(state=absent) to remove all images or only local images.
+ type: str
+ choices:
+ - all
+ - local
+ remove_volumes:
+ description:
+ - Use with O(state=absent) to remove data volumes.
+ type: bool
+ default: false
+ remove_orphans:
+ description:
+ - Remove containers for services not defined in the Compose file.
+ type: bool
+ default: false
+ timeout:
+ description:
+ - Timeout in seconds for container shutdown when attached or when containers are already running.
+ type: int
+ services:
+ description:
+ - Specifies a subset of services to be targeted.
+ type: list
+ elements: str
+ scale:
+ description:
+ - Define how to scale services when running C(docker compose up).
+ - Provide a dictionary of key/value pairs where the key is the name of the service
+ and the value is an integer count for the number of containers.
+ type: dict
+ version_added: 3.7.0
+ wait:
+ description:
+ - When running C(docker compose up), pass C(--wait) to wait for services to be running/healthy.
+ - A timeout can be set with the O(wait_timeout) option.
+ type: bool
+ default: false
+ version_added: 3.8.0
+ wait_timeout:
+ description:
+ - When O(wait=true), wait at most this amount of seconds.
+ type: int
+ version_added: 3.8.0
+
+author:
+ - Felix Fontein (@felixfontein)
+
+seealso:
+ - module: community.docker.docker_compose
+ - module: community.docker.docker_compose_v2_pull
+'''
+
+EXAMPLES = '''
+# Examples use the django example at https://docs.docker.com/compose/django. Follow it to create the
+# flask directory
+
+- name: Run using a project directory
+ hosts: localhost
+ gather_facts: false
+ tasks:
+ - name: Tear down existing services
+ community.docker.docker_compose_v2:
+ project_src: flask
+ state: absent
+
+ - name: Create and start services
+ community.docker.docker_compose_v2:
+ project_src: flask
+ register: output
+
+ - name: Show results
+ ansible.builtin.debug:
+ var: output
+
+ - name: Run `docker-compose up` again
+ community.docker.docker_compose_v2:
+ project_src: flask
+ register: output
+
+ - name: Show results
+ ansible.builtin.debug:
+ var: output
+
+ - ansible.builtin.assert:
+ that: not output.changed
+
+ - name: Stop all services
+ community.docker.docker_compose_v2:
+ project_src: flask
+ state: stopped
+ register: output
+
+ - name: Show results
+ ansible.builtin.debug:
+ var: output
+
+ - name: Verify that web and db services are not running
+ ansible.builtin.assert:
+ that:
+ - "not output.services.web.flask_web_1.state.running"
+ - "not output.services.db.flask_db_1.state.running"
+
+ - name: Restart services
+ community.docker.docker_compose_v2:
+ project_src: flask
+ state: restarted
+ register: output
+
+ - name: Show results
+ ansible.builtin.debug:
+ var: output
+
+ - name: Verify that web and db services are running
+ ansible.builtin.assert:
+ that:
+ - "output.services.web.flask_web_1.state.running"
+ - "output.services.db.flask_db_1.state.running"
+'''
+
+RETURN = '''
+containers:
+ description:
+ - A list of containers associated to the service.
+ returned: success
+ type: list
+ elements: dict
+ contains:
+ Command:
+ description:
+ - The container's command.
+ type: raw
+ CreatedAt:
+ description:
+ - The timestamp when the container was created.
+ type: str
+ sample: "2024-01-02 12:20:41 +0100 CET"
+ ExitCode:
+ description:
+ - The container's exit code.
+ type: int
+ Health:
+ description:
+ - The container's health check.
+ type: raw
+ ID:
+ description:
+ - The container's ID.
+ type: str
+ sample: "44a7d607219a60b7db0a4817fb3205dce46e91df2cb4b78a6100b6e27b0d3135"
+ Image:
+ description:
+ - The container's image.
+ type: str
+ Labels:
+ description:
+ - Labels for this container.
+ type: dict
+ LocalVolumes:
+ description:
+ - The local volumes count.
+ type: str
+ Mounts:
+ description:
+ - Mounts.
+ type: str
+ Name:
+ description:
+ - The container's primary name.
+ type: str
+ Names:
+ description:
+ - List of names of the container.
+ type: list
+ elements: str
+ Networks:
+ description:
+ - List of networks attached to this container.
+ type: list
+ elements: str
+ Ports:
+ description:
+ - List of port assignments as a string.
+ type: str
+ Publishers:
+ description:
+ - List of port assigments.
+ type: list
+ elements: dict
+ contains:
+ URL:
+ description:
+ - Interface the port is bound to.
+ type: str
+ TargetPort:
+ description:
+ - The container's port the published port maps to.
+ type: int
+ PublishedPort:
+ description:
+ - The port that is published.
+ type: int
+ Protocol:
+ description:
+ - The protocol.
+ type: str
+ choices:
+ - tcp
+ - udp
+ RunningFor:
+ description:
+ - Amount of time the container runs.
+ type: str
+ Service:
+ description:
+ - The name of the service.
+ type: str
+ Size:
+ description:
+ - The container's size.
+ type: str
+ sample: "0B"
+ State:
+ description:
+ - The container's state.
+ type: str
+ sample: running
+ Status:
+ description:
+ - The container's status.
+ type: str
+ sample: Up About a minute
+images:
+ description:
+ - A list of images associated to the service.
+ returned: success
+ type: list
+ elements: dict
+ contains:
+ ID:
+ description:
+ - The image's ID.
+ type: str
+ sample: sha256:c8bccc0af9571ec0d006a43acb5a8d08c4ce42b6cc7194dd6eb167976f501ef1
+ ContainerName:
+ description:
+ - Name of the conainer this image is used by.
+ type: str
+ Repository:
+ description:
+ - The repository where this image belongs to.
+ type: str
+ Tag:
+ description:
+ - The tag of the image.
+ type: str
+ Size:
+ description:
+ - The image's size in bytes.
+ type: int
+actions:
+ description:
+ - A list of actions that have been applied.
+ returned: success
+ type: list
+ elements: dict
+ contains:
+ what:
+ description:
+ - What kind of resource was changed.
+ type: str
+ sample: container
+ choices:
+ - container
+ - image
+ - network
+ - service
+ - unknown
+ - volume
+ id:
+ description:
+ - The ID of the resource that was changed.
+ type: str
+ sample: container
+ status:
+ description:
+ - The status change that happened.
+ type: str
+ sample: Creating
+ choices:
+ - Starting
+ - Exiting
+ - Restarting
+ - Creating
+ - Stopping
+ - Killing
+ - Removing
+ - Recreating
+ - Pulling
+ - Building
+'''
+
+import traceback
+
+from ansible.module_utils.common.validation import check_type_int
+from ansible.module_utils.common.text.converters import to_native
+from ansible.module_utils.six import string_types
+
+from ansible_collections.community.docker.plugins.module_utils.common_cli import (
+ AnsibleModuleDockerClient,
+ DockerException,
+)
+
+from ansible_collections.community.docker.plugins.module_utils.compose_v2 import (
+ BaseComposeManager,
+ common_compose_argspec,
+ is_failed,
+)
+
+
+class ServicesManager(BaseComposeManager):
+ def __init__(self, client):
+ super(ServicesManager, self).__init__(client)
+ parameters = self.client.module.params
+
+ self.state = parameters['state']
+ self.dependencies = parameters['dependencies']
+ self.pull = parameters['pull']
+ self.build = parameters['build']
+ self.recreate = parameters['recreate']
+ self.remove_images = parameters['remove_images']
+ self.remove_volumes = parameters['remove_volumes']
+ self.remove_orphans = parameters['remove_orphans']
+ self.timeout = parameters['timeout']
+ self.services = parameters['services'] or []
+ self.scale = parameters['scale'] or {}
+ self.wait = parameters['wait']
+ self.wait_timeout = parameters['wait_timeout']
+
+ for key, value in self.scale.items():
+ if not isinstance(key, string_types):
+ self.client.fail('The key %s for `scale` is not a string' % repr(key))
+ try:
+ value = check_type_int(value)
+ except TypeError as exc:
+ self.client.fail('The value %s for `scale[%s]` is not an integer' % (repr(value), repr(key)))
+ if value < 0:
+ self.client.fail('The value %s for `scale[%s]` is negative' % (repr(value), repr(key)))
+ self.scale[key] = value
+
+ def run(self):
+ if self.state == 'present':
+ result = self.cmd_up()
+ elif self.state == 'stopped':
+ result = self.cmd_stop()
+ elif self.state == 'restarted':
+ result = self.cmd_restart()
+ elif self.state == 'absent':
+ result = self.cmd_down()
+
+ result['containers'] = self.list_containers()
+ result['images'] = self.list_images()
+ self.cleanup_result(result)
+ return result
+
+ def get_up_cmd(self, dry_run, no_start=False):
+ args = self.get_base_args() + ['up', '--detach', '--no-color', '--quiet-pull']
+ if self.pull != 'policy':
+ args.extend(['--pull', self.pull])
+ if self.remove_orphans:
+ args.append('--remove-orphans')
+ if self.recreate == 'always':
+ args.append('--force-recreate')
+ if self.recreate == 'never':
+ args.append('--no-recreate')
+ if not self.dependencies:
+ args.append('--no-deps')
+ if self.timeout is not None:
+ args.extend(['--timeout', '%d' % self.timeout])
+ if self.build == 'always':
+ args.append('--build')
+ elif self.build == 'never':
+ args.append('--no-build')
+ for key, value in sorted(self.scale.items()):
+ args.extend(['--scale', '%s=%d' % (key, value)])
+ if self.wait:
+ args.append('--wait')
+ if self.wait_timeout is not None:
+ args.extend(['--wait-timeout', str(self.wait_timeout)])
+ if no_start:
+ args.append('--no-start')
+ if dry_run:
+ args.append('--dry-run')
+ for service in self.services:
+ args.append(service)
+ args.append('--')
+ return args
+
+ def cmd_up(self):
+ result = dict()
+ args = self.get_up_cmd(self.check_mode)
+ rc, stdout, stderr = self.client.call_cli(*args, cwd=self.project_src)
+ events = self.parse_events(stderr, dry_run=self.check_mode)
+ self.emit_warnings(events)
+ self.update_result(result, events, stdout, stderr, ignore_service_pull_events=True)
+ self.update_failed(result, events, args, stdout, stderr, rc)
+ return result
+
+ def get_stop_cmd(self, dry_run):
+ args = self.get_base_args() + ['stop']
+ if self.timeout is not None:
+ args.extend(['--timeout', '%d' % self.timeout])
+ if dry_run:
+ args.append('--dry-run')
+ for service in self.services:
+ args.append(service)
+ args.append('--')
+ return args
+
+ def _are_containers_stopped(self):
+ for container in self.list_containers_raw():
+ if container['State'] not in ('created', 'exited', 'stopped', 'killed'):
+ return False
+ return True
+
+ def cmd_stop(self):
+ # Since 'docker compose stop' **always** claims its stopping containers, even if they are already
+ # stopped, we have to do this a bit more complicated.
+
+ result = dict()
+ # Make sure all containers are created
+ args_1 = self.get_up_cmd(self.check_mode, no_start=True)
+ rc_1, stdout_1, stderr_1 = self.client.call_cli(*args_1, cwd=self.project_src)
+ events_1 = self.parse_events(stderr_1, dry_run=self.check_mode)
+ self.emit_warnings(events_1)
+ self.update_result(result, events_1, stdout_1, stderr_1, ignore_service_pull_events=True)
+ is_failed_1 = is_failed(events_1, rc_1)
+ if not is_failed_1 and not self._are_containers_stopped():
+ # Make sure all containers are stopped
+ args_2 = self.get_stop_cmd(self.check_mode)
+ rc_2, stdout_2, stderr_2 = self.client.call_cli(*args_2, cwd=self.project_src)
+ events_2 = self.parse_events(stderr_2, dry_run=self.check_mode)
+ self.emit_warnings(events_2)
+ self.update_result(result, events_2, stdout_2, stderr_2)
+ else:
+ args_2 = []
+ rc_2, stdout_2, stderr_2 = 0, b'', b''
+ events_2 = []
+ # Compose result
+ self.update_failed(
+ result,
+ events_1 + events_2,
+ args_1 if is_failed_1 else args_2,
+ stdout_1 if is_failed_1 else stdout_2,
+ stderr_1 if is_failed_1 else stderr_2,
+ rc_1 if is_failed_1 else rc_2,
+ )
+ return result
+
+ def get_restart_cmd(self, dry_run):
+ args = self.get_base_args() + ['restart']
+ if not self.dependencies:
+ args.append('--no-deps')
+ if self.timeout is not None:
+ args.extend(['--timeout', '%d' % self.timeout])
+ if dry_run:
+ args.append('--dry-run')
+ for service in self.services:
+ args.append(service)
+ args.append('--')
+ return args
+
+ def cmd_restart(self):
+ result = dict()
+ args = self.get_restart_cmd(self.check_mode)
+ rc, stdout, stderr = self.client.call_cli(*args, cwd=self.project_src)
+ events = self.parse_events(stderr, dry_run=self.check_mode)
+ self.emit_warnings(events)
+ self.update_result(result, events, stdout, stderr)
+ self.update_failed(result, events, args, stdout, stderr, rc)
+ return result
+
+ def get_down_cmd(self, dry_run):
+ args = self.get_base_args() + ['down']
+ if self.remove_orphans:
+ args.append('--remove-orphans')
+ if self.remove_images:
+ args.extend(['--rmi', self.remove_images])
+ if self.remove_volumes:
+ args.append('--volumes')
+ if self.timeout is not None:
+ args.extend(['--timeout', '%d' % self.timeout])
+ if dry_run:
+ args.append('--dry-run')
+ for service in self.services:
+ args.append(service)
+ args.append('--')
+ return args
+
+ def cmd_down(self):
+ result = dict()
+ args = self.get_down_cmd(self.check_mode)
+ rc, stdout, stderr = self.client.call_cli(*args, cwd=self.project_src)
+ events = self.parse_events(stderr, dry_run=self.check_mode)
+ self.emit_warnings(events)
+ self.update_result(result, events, stdout, stderr)
+ self.update_failed(result, events, args, stdout, stderr, rc)
+ return result
+
+
+def main():
+ argument_spec = dict(
+ state=dict(type='str', default='present', choices=['absent', 'present', 'stopped', 'restarted']),
+ dependencies=dict(type='bool', default=True),
+ pull=dict(type='str', choices=['always', 'missing', 'never', 'policy'], default='policy'),
+ build=dict(type='str', choices=['always', 'never', 'policy'], default='policy'),
+ recreate=dict(type='str', default='auto', choices=['always', 'never', 'auto']),
+ remove_images=dict(type='str', choices=['all', 'local']),
+ remove_volumes=dict(type='bool', default=False),
+ remove_orphans=dict(type='bool', default=False),
+ timeout=dict(type='int'),
+ services=dict(type='list', elements='str'),
+ scale=dict(type='dict'),
+ wait=dict(type='bool', default=False),
+ wait_timeout=dict(type='int'),
+ )
+ argument_spec.update(common_compose_argspec())
+
+ client = AnsibleModuleDockerClient(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
+
+ try:
+ result = ServicesManager(client).run()
+ client.module.exit_json(**result)
+ except DockerException as e:
+ client.fail('An unexpected docker error occurred: {0}'.format(to_native(e)), exception=traceback.format_exc())
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/docker/plugins/modules/docker_compose_v2_pull.py b/ansible_collections/community/docker/plugins/modules/docker_compose_v2_pull.py
new file mode 100644
index 000000000..2b1980bf6
--- /dev/null
+++ b/ansible_collections/community/docker/plugins/modules/docker_compose_v2_pull.py
@@ -0,0 +1,163 @@
+#!/usr/bin/python
+#
+# Copyright (c) 2023, Felix Fontein <felix@fontein.de>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+
+DOCUMENTATION = '''
+
+module: docker_compose_v2_pull
+
+short_description: Pull a Docker compose project
+
+version_added: 3.6.0
+
+description:
+ - Uses Docker Compose to pull images for a project.
+
+extends_documentation_fragment:
+ - community.docker.compose_v2
+ - community.docker.compose_v2.minimum_version
+ - community.docker.docker.cli_documentation
+ - community.docker.attributes
+ - community.docker.attributes.actiongroup_docker
+
+attributes:
+ check_mode:
+ support: full
+ details:
+ - If O(policy=always), the module will always indicate a change.
+ Docker Compose does not give any information whether pulling would
+ update the image or not.
+ diff_mode:
+ support: none
+
+options:
+ policy:
+ description:
+ - Whether to pull images before running. This is used when C(docker compose up) is ran.
+ - V(always) ensures that the images are always pulled, even when already present on the Docker daemon.
+ - V(missing) only pulls them when they are not present on the Docker daemon. This is only supported since Docker Compose 2.22.0.
+ type: str
+ choices:
+ - always
+ - missing
+ default: always
+
+author:
+ - Felix Fontein (@felixfontein)
+
+seealso:
+ - module: community.docker.docker_compose_v2
+'''
+
+EXAMPLES = '''
+- name: Pull images for flask project
+ community.docker.docker_compose_v2_pull:
+ project_src: /path/to/flask
+'''
+
+RETURN = '''
+actions:
+ description:
+ - A list of actions that have been applied.
+ returned: success
+ type: list
+ elements: dict
+ contains:
+ what:
+ description:
+ - What kind of resource was changed.
+ type: str
+ sample: container
+ choices:
+ - image
+ - unknown
+ id:
+ description:
+ - The ID of the resource that was changed.
+ type: str
+ sample: container
+ status:
+ description:
+ - The status change that happened.
+ type: str
+ sample: Pulling
+ choices:
+ - Pulling
+'''
+
+import traceback
+
+from ansible.module_utils.common.text.converters import to_native
+
+from ansible_collections.community.docker.plugins.module_utils.common_cli import (
+ AnsibleModuleDockerClient,
+ DockerException,
+)
+
+from ansible_collections.community.docker.plugins.module_utils.compose_v2 import (
+ BaseComposeManager,
+ common_compose_argspec,
+)
+
+from ansible_collections.community.docker.plugins.module_utils.version import LooseVersion
+
+
+class PullManager(BaseComposeManager):
+ def __init__(self, client):
+ super(PullManager, self).__init__(client)
+ parameters = self.client.module.params
+
+ self.policy = parameters['policy']
+
+ if self.policy != 'always' and self.compose_version < LooseVersion('2.22.0'):
+ # https://github.com/docker/compose/pull/10981 - 2.22.0
+ self.client.fail('A pull policy other than always is only supported since Docker Compose 2.22.0. {0} has version {1}'.format(
+ self.client.get_cli(), self.compose_version))
+
+ def get_pull_cmd(self, dry_run, no_start=False):
+ args = self.get_base_args() + ['pull']
+ if self.policy != 'always':
+ args.extend(['--policy', self.policy])
+ if dry_run:
+ args.append('--dry-run')
+ args.append('--')
+ return args
+
+ def run(self):
+ result = dict()
+ args = self.get_pull_cmd(self.check_mode)
+ rc, stdout, stderr = self.client.call_cli(*args, cwd=self.project_src)
+ events = self.parse_events(stderr, dry_run=self.check_mode)
+ self.emit_warnings(events)
+ self.update_result(result, events, stdout, stderr, ignore_service_pull_events=self.policy != 'missing' and not self.check_mode)
+ self.update_failed(result, events, args, stdout, stderr, rc)
+ self.cleanup_result(result)
+ return result
+
+
+def main():
+ argument_spec = dict(
+ policy=dict(type='str', choices=['always', 'missing'], default='always'),
+ )
+ argument_spec.update(common_compose_argspec())
+
+ client = AnsibleModuleDockerClient(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
+
+ try:
+ result = PullManager(client).run()
+ client.module.exit_json(**result)
+ except DockerException as e:
+ client.fail('An unexpected docker error occurred: {0}'.format(to_native(e)), exception=traceback.format_exc())
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/docker/plugins/modules/docker_config.py b/ansible_collections/community/docker/plugins/modules/docker_config.py
index 9f55e0f0d..86654e78b 100644
--- a/ansible_collections/community/docker/plugins/modules/docker_config.py
+++ b/ansible_collections/community/docker/plugins/modules/docker_config.py
@@ -18,7 +18,7 @@ description:
- Create and remove Docker configs in a Swarm environment. Similar to C(docker config create) and C(docker config rm).
- Adds to the metadata of new configs 'ansible_key', an encrypted hash representation of the data, which is then used
in future runs to test if a config has changed. If 'ansible_key' is not present, then a config will not be updated
- unless the I(force) option is set.
+ unless the O(force) option is set.
- Updates to configs are performed by removing the config and creating it again.
extends_documentation_fragment:
@@ -37,45 +37,45 @@ options:
data:
description:
- The value of the config.
- - Mutually exclusive with I(data_src). One of I(data) and I(data_src) is required if I(state=present).
+ - Mutually exclusive with O(data_src). One of O(data) and O(data_src) is required if O(state=present).
type: str
data_is_b64:
description:
- - If set to C(true), the data is assumed to be Base64 encoded and will be
+ - If set to V(true), the data is assumed to be Base64 encoded and will be
decoded before being used.
- - To use binary I(data), it is better to keep it Base64 encoded and let it
+ - To use binary O(data), it is better to keep it Base64 encoded and let it
be decoded by this option.
type: bool
default: false
data_src:
description:
- The file on the target from which to read the config.
- - Mutually exclusive with I(data). One of I(data) and I(data_src) is required if I(state=present).
+ - Mutually exclusive with O(data). One of O(data) and O(data_src) is required if O(state=present).
type: path
version_added: 1.10.0
labels:
description:
- - "A map of key:value meta data, where both the I(key) and I(value) are expected to be a string."
+ - "A map of key:value meta data, where both the C(key) and C(value) are expected to be a string."
- If new meta data is provided, or existing meta data is modified, the config will be updated by removing it and creating it again.
type: dict
force:
description:
- - Use with state C(present) to always remove and recreate an existing config.
- - If C(true), an existing config will be replaced, even if it has not been changed.
+ - Use with O(state=present) to always remove and recreate an existing config.
+ - If V(true), an existing config will be replaced, even if it has not been changed.
type: bool
default: false
rolling_versions:
description:
- - If set to C(true), configs are created with an increasing version number appended to their name.
+ - If set to V(true), configs are created with an increasing version number appended to their name.
- Adds a label containing the version number to the managed configs with the name C(ansible_version).
type: bool
default: false
version_added: 2.2.0
versions_to_keep:
description:
- - When using I(rolling_versions), the number of old versions of the config to keep.
+ - When using O(rolling_versions), the number of old versions of the config to keep.
- Extraneous old configs are deleted after the new one is created.
- - Set to C(-1) to keep everything or to C(0) or C(1) to keep only the current one.
+ - Set to V(-1) to keep everything or V(0) or V(1) to keep only the current one.
type: int
default: 5
version_added: 2.2.0
@@ -86,7 +86,7 @@ options:
required: true
state:
description:
- - Set to C(present), if the config should exist, and C(absent), if it should not.
+ - Set to V(present), if the config should exist, and V(absent), if it should not.
type: str
default: present
choices:
@@ -94,7 +94,7 @@ options:
- present
template_driver:
description:
- - Set to C(golang) to use a Go template in I(data) or a Go template file in I(data_src).
+ - Set to V(golang) to use a Go template in O(data) or a Go template file in O(data_src).
type: str
choices:
- golang
@@ -183,13 +183,13 @@ RETURN = '''
config_id:
description:
- The ID assigned by Docker to the config object.
- returned: success and I(state) is C(present)
+ returned: success and O(state=present)
type: str
sample: 'hzehrmyjigmcp2gb6nlhmjqcv'
config_name:
description:
- The name of the created config object.
- returned: success and I(state) is C(present)
+ returned: success and O(state=present)
type: str
sample: 'awesome_config'
version_added: 2.2.0
diff --git a/ansible_collections/community/docker/plugins/modules/docker_container.py b/ansible_collections/community/docker/plugins/modules/docker_container.py
index 9d1ed416e..d7dbc3780 100644
--- a/ansible_collections/community/docker/plugins/modules/docker_container.py
+++ b/ansible_collections/community/docker/plugins/modules/docker_container.py
@@ -20,11 +20,11 @@ description:
notes:
- For most config changes, the container needs to be recreated. This means that the existing container has to be destroyed and
- a new one created. This can cause unexpected data loss and downtime. You can use the I(comparisons) option to
+ a new one created. This can cause unexpected data loss and downtime. You can use the O(comparisons) option to
prevent this.
- If the module needs to recreate the container, it will only use the options provided to the module to create the
- new container (except I(image)). Therefore, always specify B(all) options relevant to the container.
- - When I(restart) is set to C(true), the module will only restart the container if no config changes are detected.
+ new container (except O(image)). Therefore, always specify B(all) options relevant to the container.
+ - When O(restart) is set to V(true), the module will only restart the container if no config changes are detected.
extends_documentation_fragment:
- community.docker.docker.api_documentation
@@ -35,7 +35,8 @@ attributes:
check_mode:
support: partial
details:
- - When trying to pull an image, the module assumes this is always changed in check mode.
+ - When trying to pull an image, the module assumes this is never changed in check mode except when the image is not present on the Docker daemon.
+ - This behavior can be configured with O(pull_check_mode_behavior).
diff_mode:
support: full
@@ -43,7 +44,7 @@ options:
auto_remove:
description:
- Enable auto-removal of the container on daemon side when the container's process exits.
- - If I(container_default_behavior) is set to C(compatibility), this option has a default of C(false).
+ - If O(container_default_behavior=compatibility), this option has a default of V(false).
type: bool
blkio_weight:
description:
@@ -76,14 +77,14 @@ options:
version_added: 1.1.0
cleanup:
description:
- - Use with I(detach=false) to remove the container after successful execution.
+ - Use with O(detach=false) to remove the container after successful execution.
type: bool
default: false
command:
description:
- Command to execute when the container starts. A command may be either a string or a list.
- Prior to version 2.4, strings were split on commas.
- - See I(command_handling) for differences in how strings and lists are handled.
+ - See O(command_handling) for differences in how strings and lists are handled.
type: raw
comparisons:
description:
@@ -91,30 +92,30 @@ options:
module options to decide whether the container should be recreated / updated
or not.
- Only options which correspond to the state of a container as handled by the
- Docker daemon can be specified, as well as I(networks).
- - Must be a dictionary specifying for an option one of the keys C(strict), C(ignore)
- and C(allow_more_present).
- - If C(strict) is specified, values are tested for equality, and changes always
- result in updating or restarting. If C(ignore) is specified, changes are ignored.
- - C(allow_more_present) is allowed only for lists, sets and dicts. If it is
+ Docker daemon can be specified, as well as O(networks).
+ - Must be a dictionary specifying for an option one of the keys V(strict), V(ignore)
+ and V(allow_more_present).
+ - If V(strict) is specified, values are tested for equality, and changes always
+ result in updating or restarting. If V(ignore) is specified, changes are ignored.
+ - V(allow_more_present) is allowed only for lists, sets and dicts. If it is
specified for lists or sets, the container will only be updated or restarted if
the module option contains a value which is not present in the container's
options. If the option is specified for a dict, the container will only be updated
or restarted if the module option contains a key which is not present in the
container's option, or if the value of a key present differs.
- - The wildcard option C(*) can be used to set one of the default values C(strict)
- or C(ignore) to I(all) comparisons which are not explicitly set to other values.
+ - The wildcard option C(*) can be used to set one of the default values V(strict)
+ or V(ignore) to I(all) comparisons which are not explicitly set to other values.
- See the examples for details.
type: dict
container_default_behavior:
description:
- In older versions of this module, various module options used to have default values.
This caused problems with containers which use different values for these options.
- - The default value is now C(no_defaults). To restore the old behavior, set it to
- C(compatibility), which will ensure that the default values are used when the values
+ - The default value is now V(no_defaults). To restore the old behavior, set it to
+ V(compatibility), which will ensure that the default values are used when the values
are not explicitly specified by the user.
- - This affects the I(auto_remove), I(detach), I(init), I(interactive), I(memory),
- I(paused), I(privileged), I(read_only) and I(tty) options.
+ - This affects the O(auto_remove), O(detach), O(init), O(interactive), O(memory),
+ O(paused), O(privileged), O(read_only), and O(tty) options.
type: str
choices:
- compatibility
@@ -122,15 +123,15 @@ options:
default: no_defaults
command_handling:
description:
- - The default behavior for I(command) (when provided as a list) and I(entrypoint) is to
+ - The default behavior for O(command) (when provided as a list) and O(entrypoint) is to
convert them to strings without considering shell quoting rules. (For comparing idempotency,
the resulting string is split considering shell quoting rules.)
- - Also, setting I(command) to an empty list of string, and setting I(entrypoint) to an empty
+ - Also, setting O(command) to an empty list of string, and setting O(entrypoint) to an empty
list will be handled as if these options are not specified. This is different from idempotency
handling for other container-config related options.
- - When this is set to C(compatibility), which was the default until community.docker 3.0.0, the
+ - When this is set to V(compatibility), which was the default until community.docker 3.0.0, the
current behavior will be kept.
- - When this is set to C(correct), these options are kept as lists, and an empty value or empty
+ - When this is set to V(correct), these options are kept as lists, and an empty value or empty
list will be handled correctly for idempotency checks. This has been the default since
community.docker 3.0.0.
type: str
@@ -142,25 +143,26 @@ options:
cpu_period:
description:
- Limit CPU CFS (Completely Fair Scheduler) period.
- - See I(cpus) for an easier to use alternative.
+ - See O(cpus) for an easier to use alternative.
type: int
cpu_quota:
description:
- Limit CPU CFS (Completely Fair Scheduler) quota.
- - See I(cpus) for an easier to use alternative.
+ - See O(cpus) for an easier to use alternative.
type: int
cpus:
description:
- Specify how much of the available CPU resources a container can use.
- - A value of C(1.5) means that at most one and a half CPU (core) will be used.
+ - A value of V(1.5) means that at most one and a half CPU (core) will be used.
type: float
cpuset_cpus:
description:
- - CPUs in which to allow execution C(1,3) or C(1-3).
+ - CPUs in which to allow execution.
+ - For example V(1,3) or V(1-3).
type: str
cpuset_mems:
description:
- - Memory nodes (MEMs) in which to allow execution C(0-3) or C(0,1).
+ - Memory nodes (MEMs) in which to allow execution V(0-3) or V(0,1).
type: str
cpu_shares:
description:
@@ -170,19 +172,19 @@ options:
description:
- Define the default host IP to use.
- Must be an empty string, an IPv4 address, or an IPv6 address.
- - With Docker 20.10.2 or newer, this should be set to an empty string (C("")) to avoid the
+ - With Docker 20.10.2 or newer, this should be set to an empty string (V("")) to avoid the
port bindings without an explicit IP address to only bind to IPv4.
See U(https://github.com/ansible-collections/community.docker/issues/70) for details.
- By default, the module will try to auto-detect this value from the C(bridge) network's
C(com.docker.network.bridge.host_binding_ipv4) option. If it cannot auto-detect it, it
- will fall back to C(0.0.0.0).
+ will fall back to V(0.0.0.0).
type: str
version_added: 1.2.0
detach:
description:
- Enable detached mode to leave the container running in background.
- If disabled, the task will reflect the status of the container run (failed if the command failed).
- - If I(container_default_behavior) is set to C(compatibility), this option has a default of C(true).
+ - If O(container_default_behavior=compatibility), this option has a default of V(true).
type: bool
devices:
description:
@@ -204,8 +206,8 @@ options:
rate:
description:
- "Device read limit in format C(<number>[<unit>])."
- - "Number is a positive integer. Unit can be one of C(B) (byte), C(K) (kibibyte, 1024B), C(M) (mebibyte), C(G) (gibibyte),
- C(T) (tebibyte), or C(P) (pebibyte)."
+ - "Number is a positive integer. Unit can be one of V(B) (byte), V(K) (kibibyte, 1024B), V(M) (mebibyte), V(G) (gibibyte),
+ V(T) (tebibyte), or V(P) (pebibyte)."
- "Omitting the unit defaults to bytes."
type: str
required: true
@@ -223,8 +225,8 @@ options:
rate:
description:
- "Device read limit in format C(<number>[<unit>])."
- - "Number is a positive integer. Unit can be one of C(B) (byte), C(K) (kibibyte, 1024B), C(M) (mebibyte), C(G) (gibibyte),
- C(T) (tebibyte), or C(P) (pebibyte)."
+ - "Number is a positive integer. Unit can be one of V(B) (byte), V(K) (kibibyte, 1024B), V(M) (mebibyte), V(G) (gibibyte),
+ V(T) (tebibyte), or V(P) (pebibyte)."
- "Omitting the unit defaults to bytes."
type: str
required: true
@@ -281,7 +283,7 @@ options:
count:
description:
- Number or devices to request.
- - Set to C(-1) to request all available devices.
+ - Set to V(-1) to request all available devices.
type: int
device_ids:
description:
@@ -319,19 +321,19 @@ options:
env:
description:
- Dictionary of key,value pairs.
- - Values which might be parsed as numbers, booleans or other types by the YAML parser must be quoted (for example C("true")) in order to avoid data loss.
- - Please note that if you are passing values in with Jinja2 templates, like C("{{ value }}"), you need to add C(| string) to prevent Ansible to
- convert strings such as C("true") back to booleans. The correct way is to use C("{{ value | string }}").
+ - Values which might be parsed as numbers, booleans or other types by the YAML parser must be quoted (for example V("true")) in order to avoid data loss.
+ - Please note that if you are passing values in with Jinja2 templates, like V("{{ value }}"), you need to add V(| string) to prevent Ansible to
+ convert strings such as V("true") back to booleans. The correct way is to use V("{{ value | string }}").
type: dict
env_file:
description:
- - Path to a file, present on the target, containing environment variables I(FOO=BAR).
- - If variable also present in I(env), then the I(env) value will override.
+ - Path to a file, present on the target, containing environment variables C(FOO=BAR).
+ - If variable also present in O(env), then the O(env) value will override.
type: path
entrypoint:
description:
- Command that overwrites the default C(ENTRYPOINT) of the image.
- - See I(command_handling) for differences in how strings and lists are handled.
+ - See O(command_handling) for differences in how strings and lists are handled.
type: list
elements: str
etc_hosts:
@@ -367,34 +369,35 @@ options:
- Configure a check that is run to determine whether or not containers for this service are "healthy".
- "See the docs for the L(HEALTHCHECK Dockerfile instruction,https://docs.docker.com/engine/reference/builder/#healthcheck)
for details on how healthchecks work."
- - "I(interval), I(timeout) and I(start_period) are specified as durations. They accept duration as a string in a format
- that look like: C(5h34m56s), C(1m30s) etc. The supported units are C(us), C(ms), C(s), C(m) and C(h)."
+ - "O(healthcheck.interval), O(healthcheck.timeout) and O(healthcheck.start_period) are specified as durations.
+ They accept duration as a string in a format that look like: V(5h34m56s), V(1m30s), and so on.
+ The supported units are V(us), V(ms), V(s), V(m) and V(h)."
type: dict
suboptions:
test:
description:
- Command to run to check health.
- - Must be either a string or a list. If it is a list, the first item must be one of C(NONE), C(CMD) or C(CMD-SHELL).
+ - Must be either a string or a list. If it is a list, the first item must be one of V(NONE), V(CMD) or V(CMD-SHELL).
type: raw
interval:
description:
- Time between running the check.
- - The default used by the Docker daemon is C(30s).
+ - The default used by the Docker daemon is V(30s).
type: str
timeout:
description:
- Maximum time to allow one check to run.
- - The default used by the Docker daemon is C(30s).
+ - The default used by the Docker daemon is V(30s).
type: str
retries:
description:
- Consecutive number of failures needed to report unhealthy.
- - The default used by the Docker daemon is C(3).
+ - The default used by the Docker daemon is V(3).
type: int
start_period:
description:
- Start period for the container to initialize before starting health-retries countdown.
- - The default used by the Docker daemon is C(0s).
+ - The default used by the Docker daemon is V(0s).
type: str
hostname:
description:
@@ -402,30 +405,30 @@ options:
type: str
ignore_image:
description:
- - When I(state) is C(present) or C(started), the module compares the configuration of an existing
+ - When O(state) is V(present) or V(started), the module compares the configuration of an existing
container to requested configuration. The evaluation includes the image version. If the image
version in the registry does not match the container, the container will be recreated. You can
- stop this behavior by setting I(ignore_image) to C(true).
+ stop this behavior by setting O(ignore_image) to V(true).
- "B(Warning:) This option is ignored if C(image: ignore) or C(*: ignore) is specified in the
- I(comparisons) option."
+ O(comparisons) option."
- "This option is deprecated since community.docker 3.2.0 and will be removed in community.docker 4.0.0.
- Use C(image: ignore) in I(comparisons) instead of I(ignore_image=true)."
+ Use C(image: ignore) in O(comparisons) instead of O(ignore_image=true)."
type: bool
default: false
image:
description:
- Repository path and tag used to create the container. If an image is not found or pull is true, the image
- will be pulled from the registry. If no tag is included, C(latest) will be used.
+ will be pulled from the registry. If no tag is included, V(latest) will be used.
- Can also be an image ID. If this is the case, the image is assumed to be available locally.
- The I(pull) option is ignored for this case.
+ The O(pull) option is ignored for this case.
type: str
image_comparison:
description:
- Determines which image to use for idempotency checks that depend on image parameters.
- - The default, C(desired-image), will use the image that is provided to the module via the I(image) parameter.
- - C(current-image) will use the image that the container is currently using, if the container exists. It
+ - The default, V(desired-image), will use the image that is provided to the module via the O(image) parameter.
+ - V(current-image) will use the image that the container is currently using, if the container exists. It
falls back to the image that is provided in case the container does not yet exist.
- - This affects the I(env), I(env_file), I(exposed_ports), I(labels), and I(volumes) options.
+ - This affects the O(env), O(env_file), O(exposed_ports), O(labels), and O(volumes) options.
type: str
choices:
- desired-image
@@ -435,13 +438,13 @@ options:
image_label_mismatch:
description:
- How to handle labels inherited from the image that are not set explicitly.
- - When C(ignore), labels that are present in the image but not specified in I(labels) will be
- ignored. This is useful to avoid having to specify the image labels in I(labels) while keeping
- labels I(comparisons) C(strict).
- - When C(fail), if there are labels present in the image which are not set from I(labels), the
+ - When V(ignore), labels that are present in the image but not specified in O(labels) will be
+ ignored. This is useful to avoid having to specify the image labels in O(labels) while keeping
+ labels O(comparisons) V(strict).
+ - When V(fail), if there are labels present in the image which are not set from O(labels), the
module will fail. This prevents introducing unexpected labels from the base image.
- "B(Warning:) This option is ignored unless C(labels: strict) or C(*: strict) is specified in
- the I(comparisons) option."
+ the O(comparisons) option."
type: str
choices:
- 'ignore'
@@ -452,30 +455,31 @@ options:
description:
- Determines what the module does if the image matches, but the image name in the container's configuration
does not match the image name provided to the module.
- - "This is ignored if C(image: ignore) is set in I(comparisons)."
- - If set to C(recreate) the container will be recreated.
- - If set to C(ignore) the container will not be recreated because of this. It might still get recreated for other reasons.
+ - "This is ignored if C(image: ignore) is set in O(comparisons)."
+ - If set to V(recreate) the container will be recreated.
+ - If set to V(ignore) (currently the default) the container will not be recreated because of this. It might still get recreated for other reasons.
This has been the default behavior of the module for a long time, but might not be what users expect.
+ - Since community.docker 3.5.0, the default V(ignore) has been deprecated. If not specified, a deprecation warning
+ will be emitted if this setting would make a difference. The default will change to V(recreate) in community.docker 4.0.0.
type: str
choices:
- recreate
- ignore
- default: ignore
version_added: 3.2.0
init:
description:
- Run an init inside the container that forwards signals and reaps processes.
- - If I(container_default_behavior) is set to C(compatibility), this option has a default of C(false).
+ - If O(container_default_behavior=compatibility), this option has a default of V(false).
type: bool
interactive:
description:
- Keep stdin open after a container is launched, even if not attached.
- - If I(container_default_behavior) is set to C(compatibility), this option has a default of C(false).
+ - If O(container_default_behavior=compatibility), this option has a default of V(false).
type: bool
ipc_mode:
description:
- Set the IPC mode for the container.
- - Can be one of C(container:<name|id>) to reuse another container's IPC namespace or C(host) to use
+ - Can be one of V(container:<name|id>) to reuse another container's IPC namespace or V(host) to use
the host's IPC namespace within the container.
type: str
keep_volumes:
@@ -490,8 +494,8 @@ options:
kernel_memory:
description:
- "Kernel memory limit in format C(<number>[<unit>]). Number is a positive integer.
- Unit can be C(B) (byte), C(K) (kibibyte, 1024B), C(M) (mebibyte), C(G) (gibibyte),
- C(T) (tebibyte), or C(P) (pebibyte). Minimum is C(4M)."
+ Unit can be V(B) (byte), V(K) (kibibyte, 1024B), V(M) (mebibyte), V(G) (gibibyte),
+ V(T) (tebibyte), or V(P) (pebibyte). Minimum is V(4M)."
- Omitting the unit defaults to bytes.
type: str
labels:
@@ -506,42 +510,45 @@ options:
elements: str
log_driver:
description:
- - Specify the logging driver. Docker uses C(json-file) by default.
- - See L(here,https://docs.docker.com/config/containers/logging/configure/) for possible choices.
+ - Specify the logging driver. Docker uses V(json-file) by default.
+ - See L(the Docker logging configuration documentation,https://docs.docker.com/config/containers/logging/configure/)
+ for possible choices.
type: str
log_options:
description:
- - Dictionary of options specific to the chosen I(log_driver).
+ - Dictionary of options specific to the chosen O(log_driver).
- See U(https://docs.docker.com/engine/admin/logging/overview/) for details.
- - I(log_driver) needs to be specified for I(log_options) to take effect, even if using the default C(json-file) driver.
+ - O(log_driver) needs to be specified for O(log_options) to take effect, even if using the default V(json-file) driver.
type: dict
aliases:
- log_opt
mac_address:
description:
- - Container MAC address (for example, C(92:d0:c6:0a:29:33)).
+ - Container MAC address (for example, V(92:d0:c6:0a:29:33)).
+ - Note that the global container-wide MAC address is deprecated and no longer used since Docker API version 1.44.
+ - Use O(networks[].mac_address) instead.
type: str
memory:
description:
- "Memory limit in format C(<number>[<unit>]). Number is a positive integer.
- Unit can be C(B) (byte), C(K) (kibibyte, 1024B), C(M) (mebibyte), C(G) (gibibyte),
- C(T) (tebibyte), or C(P) (pebibyte)."
+ Unit can be V(B) (byte), V(K) (kibibyte, 1024B), V(M) (mebibyte), V(G) (gibibyte),
+ V(T) (tebibyte), or V(P) (pebibyte)."
- Omitting the unit defaults to bytes.
- - If I(container_default_behavior) is set to C(compatibility), this option has a default of C("0").
+ - If O(container_default_behavior=compatibility), this option has a default of V("0").
type: str
memory_reservation:
description:
- "Memory soft limit in format C(<number>[<unit>]). Number is a positive integer.
- Unit can be C(B) (byte), C(K) (kibibyte, 1024B), C(M) (mebibyte), C(G) (gibibyte),
- C(T) (tebibyte), or C(P) (pebibyte)."
+ Unit can be V(B) (byte), V(K) (kibibyte, 1024B), V(M) (mebibyte), V(G) (gibibyte),
+ V(T) (tebibyte), or V(P) (pebibyte)."
- Omitting the unit defaults to bytes.
type: str
memory_swap:
description:
- "Total memory limit (memory + swap) in format C(<number>[<unit>]), or
- the special values C(unlimited) or C(-1) for unlimited swap usage.
- Number is a positive integer. Unit can be C(B) (byte), C(K) (kibibyte, 1024B),
- C(M) (mebibyte), C(G) (gibibyte), C(T) (tebibyte), or C(P) (pebibyte)."
+ the special values V(unlimited) or V(-1) for unlimited swap usage.
+ Number is a positive integer. Unit can be V(B) (byte), V(K) (kibibyte, 1024B),
+ V(M) (mebibyte), V(G) (gibibyte), V(T) (tebibyte), or V(P) (pebibyte)."
- Omitting the unit defaults to bytes.
type: str
memory_swappiness:
@@ -554,7 +561,7 @@ options:
type: list
elements: dict
description:
- - Specification for mounts to be added to the container. More powerful alternative to I(volumes).
+ - Specification for mounts to be added to the container. More powerful alternative to O(volumes).
suboptions:
target:
description:
@@ -565,12 +572,12 @@ options:
description:
- Mount source.
- For example, this can be a volume name or a host path.
- - If not supplied when I(type=volume) an anonymous volume will be created.
+ - If not supplied when O(mounts[].type=volume) an anonymous volume will be created.
type: str
type:
description:
- The mount type.
- - Note that C(npipe) is only supported by Docker for Windows.
+ - Note that V(npipe) is only supported by Docker for Windows.
type: str
choices:
- bind
@@ -593,7 +600,7 @@ options:
- delegated
propagation:
description:
- - Propagation mode. Only valid for the C(bind) type.
+ - Propagation mode. Only valid for the V(bind) type.
type: str
choices:
- private
@@ -604,16 +611,16 @@ options:
- rslave
no_copy:
description:
- - False if the volume should be populated with the data from the target. Only valid for the C(volume) type.
- - The default value is C(false).
+ - False if the volume should be populated with the data from the target. Only valid for the V(volume) type.
+ - The default value is V(false).
type: bool
labels:
description:
- - User-defined name and labels for the volume. Only valid for the C(volume) type.
+ - User-defined name and labels for the volume. Only valid for the V(volume) type.
type: dict
volume_driver:
description:
- - Specify the volume driver. Only valid for the C(volume) type.
+ - Specify the volume driver. Only valid for the V(volume) type.
- See L(here,https://docs.docker.com/storage/volumes/#use-a-volume-driver) for details.
type: str
volume_options:
@@ -624,8 +631,8 @@ options:
tmpfs_size:
description:
- "The size for the tmpfs mount in bytes in format <number>[<unit>]."
- - "Number is a positive integer. Unit can be one of C(B) (byte), C(K) (kibibyte, 1024B), C(M) (mebibyte), C(G) (gibibyte),
- C(T) (tebibyte), or C(P) (pebibyte)."
+ - "Number is a positive integer. Unit can be one of V(B) (byte), V(K) (kibibyte, 1024B), V(M) (mebibyte), V(G) (gibibyte),
+ V(T) (tebibyte), or V(P) (pebibyte)."
- "Omitting the unit defaults to bytes."
type: str
tmpfs_mode:
@@ -640,24 +647,24 @@ options:
required: true
network_mode:
description:
- - Connect the container to a network. Choices are C(bridge), C(host), C(none), C(container:<name|id>), C(<network_name>) or C(default).
- - "Since community.docker 2.0.0, if I(networks_cli_compatible) is C(true) and I(networks) contains at least one network,
- the default value for I(network_mode) is the name of the first network in the I(networks) list. You can prevent this
- by explicitly specifying a value for I(network_mode), like the default value C(default) which will be used by Docker if
- I(network_mode) is not specified."
+ - Connect the container to a network. Choices are V(bridge), V(host), V(none), C(container:<name|id>), C(<network_name>) or V(default).
+ - "Since community.docker 2.0.0, if O(networks_cli_compatible=true) and O(networks) contains at least one network,
+ the default value for O(network_mode) is the name of the first network in the O(networks) list. You can prevent this
+ by explicitly specifying a value for O(network_mode), like the default value V(default) which will be used by Docker if
+ O(network_mode) is not specified."
type: str
userns_mode:
description:
- - Set the user namespace mode for the container. Currently, the only valid value are C(host) and the empty string.
+ - Set the user namespace mode for the container. Currently, the only valid value are V(host) and the empty string (V("")).
type: str
networks:
description:
- List of networks the container belongs to.
- For examples of the data structure and usage see EXAMPLES below.
- - "To remove a container from one or more networks, use C(networks: strict) in the I(comparisons) option."
- - "If I(networks_cli_compatible) is set to C(false), this will not remove the default network if I(networks) is specified.
- This is different from the behavior of C(docker run ...). You need to explicitly use C(networks: strict) in I(comparisons)
- to enforce the removal of the default network (and all other networks not explicitly mentioned in I(networks)) in that case."
+ - "To remove a container from one or more networks, use C(networks: strict) in the O(comparisons) option."
+ - "If O(networks_cli_compatible=false), this will not remove the default network if O(networks) is specified.
+ This is different from the behavior of C(docker run ...). You need to explicitly use C(networks: strict) in O(comparisons)
+ to enforce the removal of the default network (and all other networks not explicitly mentioned in O(networks)) in that case."
type: list
elements: dict
suboptions:
@@ -685,17 +692,23 @@ options:
can be used in the network to reach this container.
type: list
elements: str
+ mac_address:
+ description:
+ - Endpoint MAC address (for example, V(92:d0:c6:0a:29:33)).
+ - This is only available for Docker API version 1.44 and later.
+ type: str
+ version_added: 3.6.0
networks_cli_compatible:
description:
- - "If I(networks_cli_compatible) is set to C(true) (default), this module will behave as
- C(docker run --network) and will B(not) add the default network if I(networks) is
- specified. If I(networks) is not specified, the default network will be attached."
- - "When I(networks_cli_compatible) is set to C(false) and networks are provided to the module
- via the I(networks) option, the module behaves differently than C(docker run --network):
+ - "If O(networks_cli_compatible=true) (default), this module will behave as
+ C(docker run --network) and will B(not) add the default network if O(networks) is
+ specified. If O(networks) is not specified, the default network will be attached."
+ - "When O(networks_cli_compatible=false) and networks are provided to the module
+ via the O(networks) option, the module behaves differently than C(docker run --network):
C(docker run --network other) will create a container with network C(other) attached,
- but the default network not attached. This module with I(networks: {name: other}) will
+ but the default network not attached. This module with O(networks) set to C({name: other}) will
create a container with both C(default) and C(other) attached. If C(networks: strict)
- or C(*: strict) is set in I(comparisons), the C(default) network will be removed afterwards."
+ or C(*: strict) is set in O(comparisons), the C(default) network will be removed afterwards."
type: bool
default: true
oom_killer:
@@ -710,13 +723,13 @@ options:
output_logs:
description:
- If set to true, output of the container command will be printed.
- - Only effective when I(log_driver) is set to C(json-file), C(journald), or C(local).
+ - Only effective when O(log_driver) is set to V(json-file), V(journald), or V(local).
type: bool
default: false
paused:
description:
- Use with the started state to pause running processes inside the container.
- - If I(container_default_behavior) is set to C(compatibility), this option has a default of C(false).
+ - If O(container_default_behavior=compatibility), this option has a default of V(false).
type: bool
pid_mode:
description:
@@ -725,31 +738,34 @@ options:
pids_limit:
description:
- Set PIDs limit for the container. It accepts an integer value.
- - Set C(-1) for unlimited PIDs.
+ - Set V(-1) for unlimited PIDs.
type: int
platform:
description:
- Platform for the container in the format C(os[/arch[/variant]]).
- - "Please note that inspecting the container does not always return the exact platform string used to
- create the container. This can cause idempotency to break for this module. Use the I(comparisons) option
- with C(platform: ignore) to prevent accidental recreation of the container due to this."
+ - "Note that since community.docker 3.5.0, the module uses both the image's metadata and the Docker
+ daemon's information to normalize platform strings similarly to how Docker itself is doing this.
+ If you notice idempotency problems, L(please create an issue in the community.docker GitHub repository,
+ https://github.com/ansible-collections/community.docker/issues/new?assignees=&labels=&projects=&template=bug_report.md).
+ For older community.docker versions, you can use the O(comparisons) option with C(platform: ignore)
+ to prevent accidental recreation of the container due to this."
type: str
version_added: 3.0.0
privileged:
description:
- Give extended privileges to the container.
- - If I(container_default_behavior) is set to C(compatibility), this option has a default of C(false).
+ - If O(container_default_behavior=compatibility), this option has a default of V(false).
type: bool
publish_all_ports:
description:
- Publish all ports to the host.
- - Any specified port bindings from I(published_ports) will remain intact when C(true).
+ - Any specified port bindings from O(published_ports) will remain intact when V(true).
type: bool
version_added: 1.8.0
published_ports:
description:
- List of ports to publish from the container to the host.
- - "Use docker CLI syntax: C(8000), C(9000:8000), or C(0.0.0.0:9000:8000), where 8000 is a
+ - "Use docker CLI syntax: V(8000), V(9000:8000), or V(0.0.0.0:9000:8000), where 8000 is a
container port, 9000 is a host port, and 0.0.0.0 is a host interface."
- Port ranges can be used for source and destination ports. If two ranges with
different lengths are specified, the shorter range will be used.
@@ -757,41 +773,66 @@ options:
to the first port of the destination range, but to a free port in that range. This is the
same behavior as for C(docker) command line utility.
- "Bind addresses must be either IPv4 or IPv6 addresses. Hostnames are B(not) allowed. This
- is different from the C(docker) command line utility. Use the R(dig lookup,ansible_collections.community.general.dig_lookup)
+ is different from the C(docker) command line utility. Use the P(community.general.dig#lookup) lookup
to resolve hostnames."
- - If I(networks) parameter is provided, will inspect each network to see if there exists
+ - If O(networks) parameter is provided, will inspect each network to see if there exists
a bridge network with optional parameter C(com.docker.network.bridge.host_binding_ipv4).
If such a network is found, then published ports where no host IP address is specified
will be bound to the host IP pointed to by C(com.docker.network.bridge.host_binding_ipv4).
Note that the first bridge network with a C(com.docker.network.bridge.host_binding_ipv4)
- value encountered in the list of I(networks) is the one that will be used.
- - The value C(all) was allowed in earlier versions of this module. Support for it was removed in
- community.docker 3.0.0. Use the I(publish_all_ports) option instead.
+ value encountered in the list of O(networks) is the one that will be used.
+ - The value V(all) was allowed in earlier versions of this module. Support for it was removed in
+ community.docker 3.0.0. Use the O(publish_all_ports) option instead.
type: list
elements: str
aliases:
- ports
pull:
description:
- - If true, always pull the latest version of an image. Otherwise, will only pull an image
- when missing.
+ - If set to V(never), will never try to pull an image. Will fail if the image is not available
+ on the Docker daemon.
+ - If set to V(missing) or V(false), only pull the image if it is not available on the Docker
+ daemon. This is the default behavior.
+ - If set to V(always) or V(true), always try to pull the latest version of the image.
- "B(Note:) images are only pulled when specified by name. If the image is specified
- as a image ID (hash), it cannot be pulled."
- type: bool
- default: false
+ as a image ID (hash), it cannot be pulled, and this option is ignored."
+ - "B(Note:) the values V(never), V(missing), and V(always) are only available since
+ community.docker 3.8.0. Earlier versions only support V(true) and V(false)."
+ type: raw
+ choices:
+ - never
+ - missing
+ - always
+ - true
+ - false
+ default: missing
+ pull_check_mode_behavior:
+ description:
+ - Allows to adjust the behavior when O(pull=always) or O(pull=true) in check mode.
+ - Since the Docker daemon does not expose any functionality to test whether a pull will result
+ in a changed image, the module by default acts like O(pull=always) only results in a change when
+ the image is not present.
+ - If set to V(image_not_present) (default), only report changes in check mode when the image is not present.
+ - If set to V(always), always report changes in check mode.
+ type: str
+ default: image_not_present
+ choices:
+ - image_not_present
+ - always
+ version_added: 3.8.0
purge_networks:
description:
- - Remove the container from ALL networks not included in I(networks) parameter.
- - Any default networks such as C(bridge), if not found in I(networks), will be removed as well.
+ - Remove the container from ALL networks not included in O(networks) parameter.
+ - Any default networks such as C(bridge), if not found in O(networks), will be removed as well.
- "This option is deprecated since community.docker 3.2.0 and will be removed in community.docker 4.0.0.
- Use C(networks: strict) in I(comparisons) instead of I(purge_networks=true) and make sure that
- I(networks) is specified. If you want to remove all networks, specify I(networks: [])."
+ Use C(networks: strict) in O(comparisons) instead of O(purge_networks=true) and make sure that
+ O(networks) is specified. If you want to remove all networks, specify O(networks) as C([])."
type: bool
default: false
read_only:
description:
- Mount the container's root file system as read-only.
- - If I(container_default_behavior) is set to C(compatibility), this option has a default of C(false).
+ - If O(container_default_behavior=compatibility), this option has a default of V(false).
type: bool
recreate:
description:
@@ -816,7 +857,7 @@ options:
restart_policy:
description:
- Container restart policy.
- - Place quotes around C(no) option.
+ - Place quotes around V(no) option.
type: str
choices:
- 'no'
@@ -834,9 +875,9 @@ options:
shm_size:
description:
- "Size of C(/dev/shm) in format C(<number>[<unit>]). Number is positive integer.
- Unit can be C(B) (byte), C(K) (kibibyte, 1024B), C(M) (mebibyte), C(G) (gibibyte),
- C(T) (tebibyte), or C(P) (pebibyte)."
- - Omitting the unit defaults to bytes. If you omit the size entirely, Docker daemon uses C(64M).
+ Unit can be V(B) (byte), V(K) (kibibyte, 1024B), V(M) (mebibyte), V(G) (gibibyte),
+ V(T) (tebibyte), or V(P) (pebibyte)."
+ - Omitting the unit defaults to bytes. If you omit the size entirely, Docker daemon uses V(64M).
type: str
security_opts:
description:
@@ -845,22 +886,22 @@ options:
elements: str
state:
description:
- - 'C(absent) - A container matching the specified name will be stopped and removed. Use I(force_kill) to kill the container
- rather than stopping it. Use I(keep_volumes) to retain anonymous volumes associated with the removed container.'
- - 'C(present) - Asserts the existence of a container matching the name and any provided configuration parameters. If no
+ - 'V(absent) - A container matching the specified name will be stopped and removed. Use O(force_kill) to kill the container
+ rather than stopping it. Use O(keep_volumes) to retain anonymous volumes associated with the removed container.'
+ - 'V(present) - Asserts the existence of a container matching the name and any provided configuration parameters. If no
container matches the name, a container will be created. If a container matches the name but the provided configuration
does not match, the container will be updated, if it can be. If it cannot be updated, it will be removed and re-created
with the requested config.'
- - 'C(started) - Asserts that the container is first C(present), and then if the container is not running moves it to a running
- state. Use I(restart) to force a matching container to be stopped and restarted.'
- - 'C(stopped) - Asserts that the container is first C(present), and then if the container is running moves it to a stopped
+ - 'V(started) - Asserts that the container is first V(present), and then if the container is not running moves it to a running
+ state. Use O(restart) to force a matching container to be stopped and restarted.'
+ - 'V(stopped) - Asserts that the container is first V(present), and then if the container is running moves it to a stopped
state.'
- - "To control what will be taken into account when comparing configuration, see the I(comparisons) option. To avoid that the
- image version will be taken into account, you can also use the C(image: ignore) in the I(comparisons) option."
- - Use the I(recreate) option to always force re-creation of a matching container, even if it is running.
- - If the container should be killed instead of stopped in case it needs to be stopped for recreation, or because I(state) is
- C(stopped), please use the I(force_kill) option. Use I(keep_volumes) to retain anonymous volumes associated with a removed container.
- - Use I(keep_volumes) to retain anonymous volumes associated with a removed container.
+ - "To control what will be taken into account when comparing configuration, see the O(comparisons) option. To avoid that the
+ image version will be taken into account, you can also use the V(image: ignore) in the O(comparisons) option."
+ - Use the O(recreate) option to always force re-creation of a matching container, even if it is running.
+ - If the container should be killed instead of stopped in case it needs to be stopped for recreation, or because O(state) is
+ V(stopped), please use the O(force_kill) option. Use O(keep_volumes) to retain anonymous volumes associated with a removed container.
+ - Use O(keep_volumes) to retain anonymous volumes associated with a removed container.
type: str
default: started
choices:
@@ -896,11 +937,11 @@ options:
tty:
description:
- Allocate a pseudo-TTY.
- - If I(container_default_behavior) is set to C(compatibility), this option has a default of C(false).
+ - If O(container_default_behavior=compatibility), this option has a default of V(false).
type: bool
ulimits:
description:
- - "List of ulimit options. A ulimit is specified as C(nofile:262144:262144)."
+ - "List of ulimit options. A ulimit is specified as V(nofile:262144:262144)."
type: list
elements: str
sysctls:
@@ -920,12 +961,12 @@ options:
description:
- List of volumes to mount within the container.
- "Use docker CLI-style syntax: C(/host:/container[:mode])"
- - "Mount modes can be a comma-separated list of various modes such as C(ro), C(rw), C(consistent),
- C(delegated), C(cached), C(rprivate), C(private), C(rshared), C(shared), C(rslave), C(slave), and
- C(nocopy). Note that the docker daemon might not support all modes and combinations of such modes."
- - SELinux hosts can additionally use C(z) or C(Z) to use a shared or private label for the volume.
- - "Note that Ansible 2.7 and earlier only supported one mode, which had to be one of C(ro), C(rw),
- C(z), and C(Z)."
+ - "Mount modes can be a comma-separated list of various modes such as V(ro), V(rw), V(consistent),
+ V(delegated), V(cached), V(rprivate), V(private), V(rshared), V(shared), V(rslave), V(slave), and
+ V(nocopy). Note that the docker daemon might not support all modes and combinations of such modes."
+ - SELinux hosts can additionally use V(z) or V(Z) to use a shared or private label for the volume.
+ - "Note that Ansible 2.7 and earlier only supported one mode, which had to be one of V(ro), V(rw),
+ V(z), and V(Z)."
type: list
elements: str
volume_driver:
@@ -1225,9 +1266,9 @@ RETURN = '''
container:
description:
- Facts representing the current state of the container. Matches the docker inspection output.
- - Empty if I(state) is C(absent).
- - If I(detach=false), will include C(Output) attribute containing any output from container run.
- returned: success; or when I(state=started) and I(detach=false), and when waiting for the container result did not fail
+ - Empty if O(state=absent).
+ - If O(detach=false), will include C(Output) attribute containing any output from container run.
+ returned: success; or when O(state=started) and O(detach=false), and when waiting for the container result did not fail
type: dict
sample: '{
"AppArmorProfile": "",
@@ -1265,7 +1306,7 @@ status:
description:
- In case a container is started without detaching, this contains the exit code of the process in the container.
- Before community.docker 1.1.0, this was only returned when non-zero.
- returned: when I(state=started) and I(detach=false), and when waiting for the container result did not fail
+ returned: when O(state=started) and O(detach=false), and when waiting for the container result did not fail
type: int
sample: 0
'''
diff --git a/ansible_collections/community/docker/plugins/modules/docker_container_copy_into.py b/ansible_collections/community/docker/plugins/modules/docker_container_copy_into.py
index f140bfe6a..2af99152d 100644
--- a/ansible_collections/community/docker/plugins/modules/docker_container_copy_into.py
+++ b/ansible_collections/community/docker/plugins/modules/docker_container_copy_into.py
@@ -19,7 +19,7 @@ version_added: 3.4.0
description:
- Copy a file into a Docker container.
- Similar to C(docker cp).
- - To copy files in a non-running container, you must provide the I(owner_id) and I(group_id) options.
+ - To copy files in a non-running container, you must provide the O(owner_id) and O(group_id) options.
This is also necessary if the container does not contain a C(/bin/sh) shell with an C(id) tool.
attributes:
@@ -41,19 +41,19 @@ options:
path:
description:
- Path to a file on the managed node.
- - Mutually exclusive with I(content). One of I(content) and I(path) is required.
+ - Mutually exclusive with O(content). One of O(content) and O(path) is required.
type: path
content:
description:
- The file's content.
- - If you plan to provide binary data, provide it pre-encoded to base64, and set I(content_is_b64=true).
- - Mutually exclusive with I(path). One of I(content) and I(path) is required.
+ - If you plan to provide binary data, provide it pre-encoded to base64, and set O(content_is_b64=true).
+ - Mutually exclusive with O(path). One of O(content) and O(path) is required.
type: str
content_is_b64:
description:
- - If set to C(true), the content in I(content) is assumed to be Base64 encoded and
+ - If set to V(true), the content in O(content) is assumed to be Base64 encoded and
will be decoded before being used.
- - To use binary I(content), it is better to keep it Base64 encoded and let it
+ - To use binary O(content), it is better to keep it Base64 encoded and let it
be decoded by this option. Otherwise you risk the data to be interpreted as
UTF-8 and corrupted.
type: bool
@@ -77,7 +77,7 @@ options:
owner_id:
description:
- The owner ID to use when writing the file to disk.
- - If provided, I(group_id) must also be provided.
+ - If provided, O(group_id) must also be provided.
- If not provided, the module will try to determine the user and group ID for the current user in the container.
This will only work if C(/bin/sh) is present in the container and the C(id) binary or shell builtin is available.
Also the container must be running.
@@ -85,7 +85,7 @@ options:
group_id:
description:
- The group ID to use when writing the file to disk.
- - If provided, I(owner_id) must also be provided.
+ - If provided, O(owner_id) must also be provided.
- If not provided, the module will try to determine the user and group ID for the current user in the container.
This will only work if C(/bin/sh) is present in the container and the C(id) binary or shell builtin is available.
Also the container must be running.
@@ -97,8 +97,8 @@ options:
type: int
force:
description:
- - If set to C(true), force writing the file (without performing any idempotency checks).
- - If set to C(false), only write the file if it does not exist on the target. If a filesystem object exists at
+ - If set to V(true), force writing the file (without performing any idempotency checks).
+ - If set to V(false), only write the file if it does not exist on the target. If a filesystem object exists at
the destination, the module will not do any change.
- If this option is not specified, the module will be idempotent. To verify idempotency, it will try to get information
on the filesystem object in the container, and if everything seems to match will download the file from the container
@@ -138,7 +138,7 @@ RETURN = '''
container_path:
description:
- The actual path in the container.
- - Can only be different from I(container_path) when I(follow=true).
+ - Can only be different from O(container_path) when O(follow=true).
type: str
returned: success
'''
diff --git a/ansible_collections/community/docker/plugins/modules/docker_container_exec.py b/ansible_collections/community/docker/plugins/modules/docker_container_exec.py
index 522a70a33..0d92dad96 100644
--- a/ansible_collections/community/docker/plugins/modules/docker_container_exec.py
+++ b/ansible_collections/community/docker/plugins/modules/docker_container_exec.py
@@ -42,21 +42,21 @@ options:
description:
- The command to execute.
- Since this is a list of arguments, no quoting is needed.
- - Exactly one of I(argv) or I(command) must be specified.
+ - Exactly one of O(argv) or O(command) must be specified.
command:
type: str
description:
- The command to execute.
- - Exactly one of I(argv) or I(command) must be specified.
+ - Exactly one of O(argv) or O(command) must be specified.
chdir:
type: str
description:
- The directory to run the command in.
detach:
description:
- - Whether to run the command synchronously (I(detach=false), default) or asynchronously (I(detach=true)).
- - If set to C(true), I(stdin) cannot be provided, and the return values C(stdout), C(stderr) and
- C(rc) are not returned.
+ - Whether to run the command synchronously (O(detach=false), default) or asynchronously (O(detach=true)).
+ - If set to V(true), O(stdin) cannot be provided, and the return values RV(stdout), RV(stderr), and
+ RV(rc) are not returned.
type: bool
default: false
version_added: 2.1.0
@@ -68,12 +68,12 @@ options:
type: str
description:
- Set the stdin of the command directly to the specified value.
- - Can only be used if I(detach=false).
+ - Can only be used if O(detach=false).
stdin_add_newline:
type: bool
default: true
description:
- - If set to C(true), appends a newline to I(stdin).
+ - If set to V(true), appends a newline to O(stdin).
strip_empty_ends:
type: bool
default: true
@@ -87,16 +87,17 @@ options:
env:
description:
- Dictionary of environment variables with their respective values to be passed to the command ran inside the container.
- - Values which might be parsed as numbers, booleans or other types by the YAML parser must be quoted (for example C("true")) in order to avoid data loss.
- - Please note that if you are passing values in with Jinja2 templates, like C("{{ value }}"), you need to add C(| string) to prevent Ansible to
- convert strings such as C("true") back to booleans. The correct way is to use C("{{ value | string }}").
+ - Values which might be parsed as numbers, booleans or other types by the YAML parser must be quoted (for example V("true")) in order to avoid data loss.
+ - Please note that if you are passing values in with Jinja2 templates, like V("{{ value }}"), you need to add V(| string) to prevent Ansible to
+ convert strings such as V("true") back to booleans. The correct way is to use V("{{ value | string }}").
type: dict
version_added: 2.1.0
notes:
- - Does not support C(check_mode).
- - Does B(not work with TCP TLS sockets) when using I(stdin). This is caused by the inability to send C(close_notify) without closing the connection
+ - Does B(not work with TCP TLS sockets) when using O(stdin). This is caused by the inability to send C(close_notify) without closing the connection
with Python's C(SSLSocket)s. See U(https://github.com/ansible-collections/community.docker/issues/605) for more information.
+ - If you need to evaluate environment variables of the container in O(command) or O(argv), you need to pass the command through a shell,
+ like O(command=/bin/sh -c "echo $ENV_VARIABLE").
author:
- "Felix Fontein (@felixfontein)"
@@ -134,23 +135,23 @@ EXAMPLES = '''
RETURN = '''
stdout:
type: str
- returned: success and I(detach=false)
+ returned: success and O(detach=false)
description:
- The standard output of the container command.
stderr:
type: str
- returned: success and I(detach=false)
+ returned: success and O(detach=false)
description:
- The standard error output of the container command.
rc:
type: int
- returned: success and I(detach=false)
+ returned: success and O(detach=false)
sample: 0
description:
- The exit code of the command.
exec_id:
type: str
- returned: success and I(detach=true)
+ returned: success and O(detach=true)
sample: 249d9e3075655baf705ed8f40488c5e9434049cf3431976f1bfdb73741c574c5
description:
- The execution ID of the command.
diff --git a/ansible_collections/community/docker/plugins/modules/docker_container_info.py b/ansible_collections/community/docker/plugins/modules/docker_container_info.py
index bfc28156b..ff24b1bc0 100644
--- a/ansible_collections/community/docker/plugins/modules/docker_container_info.py
+++ b/ansible_collections/community/docker/plugins/modules/docker_container_info.py
@@ -66,7 +66,7 @@ exists:
container:
description:
- Facts representing the current state of the container. Matches the docker inspection output.
- - Will be C(none) if container does not exist.
+ - Will be V(none) if container does not exist.
returned: always
type: dict
sample: '{
diff --git a/ansible_collections/community/docker/plugins/modules/docker_host_info.py b/ansible_collections/community/docker/plugins/modules/docker_host_info.py
index f08845faa..696cdfd0c 100644
--- a/ansible_collections/community/docker/plugins/modules/docker_host_info.py
+++ b/ansible_collections/community/docker/plugins/modules/docker_host_info.py
@@ -108,10 +108,10 @@ options:
default: false
verbose_output:
description:
- - When set to C(true) and I(networks), I(volumes), I(images), I(containers) or I(disk_usage) is set to C(true)
+ - When set to V(true) and O(networks), O(volumes), O(images), O(containers), or O(disk_usage) is set to V(true)
then output will contain verbose information about objects matching the full output of API method.
For details see the documentation of your version of Docker API at U(https://docs.docker.com/engine/api/).
- - The verbose output in this module contains only subset of information returned by I(_info) module
+ - The verbose output in this module contains only subset of information returned by this module
for each type of the objects.
type: bool
default: false
@@ -169,7 +169,7 @@ EXAMPLES = '''
RETURN = '''
can_talk_to_docker:
description:
- - Will be C(true) if the module can talk to the docker daemon.
+ - Will be V(true) if the module can talk to the docker daemon.
returned: both on success and on error
type: bool
@@ -181,40 +181,40 @@ host_info:
volumes:
description:
- List of dict objects containing the basic information about each volume.
- Keys matches the C(docker volume ls) output unless I(verbose_output=true).
- See description for I(verbose_output).
- returned: When I(volumes) is C(true)
+ Keys matches the C(docker volume ls) output unless O(verbose_output=true).
+ See description for O(verbose_output).
+ returned: When O(volumes=true)
type: list
elements: dict
networks:
description:
- List of dict objects containing the basic information about each network.
- Keys matches the C(docker network ls) output unless I(verbose_output=true).
- See description for I(verbose_output).
- returned: When I(networks) is C(true)
+ Keys matches the C(docker network ls) output unless O(verbose_output=true).
+ See description for O(verbose_output).
+ returned: When O(networks=true)
type: list
elements: dict
containers:
description:
- List of dict objects containing the basic information about each container.
- Keys matches the C(docker container ls) output unless I(verbose_output=true).
- See description for I(verbose_output).
- returned: When I(containers) is C(true)
+ Keys matches the C(docker container ls) output unless O(verbose_output=true).
+ See description for O(verbose_output).
+ returned: When O(containers=true)
type: list
elements: dict
images:
description:
- List of dict objects containing the basic information about each image.
- Keys matches the C(docker image ls) output unless I(verbose_output=true).
- See description for I(verbose_output).
- returned: When I(images) is C(true)
+ Keys matches the C(docker image ls) output unless O(verbose_output=true).
+ See description for O(verbose_output).
+ returned: When O(images=true)
type: list
elements: dict
disk_usage:
description:
- Information on summary disk usage by images, containers and volumes on docker host
- unless I(verbose_output=true). See description for I(verbose_output).
- returned: When I(disk_usage) is C(true)
+ unless O(verbose_output=true). See description for O(verbose_output).
+ returned: When O(disk_usage=true)
type: dict
'''
diff --git a/ansible_collections/community/docker/plugins/modules/docker_image.py b/ansible_collections/community/docker/plugins/modules/docker_image.py
index 735de786a..b229ad382 100644
--- a/ansible_collections/community/docker/plugins/modules/docker_image.py
+++ b/ansible_collections/community/docker/plugins/modules/docker_image.py
@@ -20,6 +20,7 @@ description:
notes:
- Building images is done using Docker daemon's API. It is not possible to use BuildKit / buildx this way.
+ Use M(community.docker.docker_image_build) to build images with BuildKit.
extends_documentation_fragment:
- community.docker.docker.api_documentation
@@ -38,12 +39,12 @@ options:
source:
description:
- "Determines where the module will try to retrieve the image from."
- - "Use C(build) to build the image from a C(Dockerfile). I(build.path) must
+ - "Use V(build) to build the image from a C(Dockerfile). O(build.path) must
be specified when this value is used."
- - "Use C(load) to load the image from a C(.tar) file. I(load_path) must
+ - "Use V(load) to load the image from a C(.tar) file. O(load_path) must
be specified when this value is used."
- - "Use C(pull) to pull the image from a registry."
- - "Use C(local) to make sure that the image is already available on the local
+ - "Use V(pull) to pull the image from a registry."
+ - "Use V(local) to make sure that the image is already available on the local
docker daemon. This means that the module does not try to build, pull or load the image."
type: str
choices:
@@ -63,8 +64,8 @@ options:
elements: str
dockerfile:
description:
- - Use with state C(present) and source C(build) to provide an alternate name for the Dockerfile to use when building an image.
- - This can also include a relative path (relative to I(path)).
+ - Use with O(state=present) and O(source=build) to provide an alternate name for the Dockerfile to use when building an image.
+ - This can also include a relative path (relative to O(build.path)).
type: str
http_timeout:
description:
@@ -112,13 +113,21 @@ options:
suboptions:
memory:
description:
- - Set memory limit for build.
- type: int
+ - "Memory limit for build in format C(<number>[<unit>]). Number is a positive integer.
+ Unit can be V(B) (byte), V(K) (kibibyte, 1024B), V(M) (mebibyte), V(G) (gibibyte),
+ V(T) (tebibyte), or V(P) (pebibyte)."
+ - Omitting the unit defaults to bytes.
+ - Before community.docker 3.6.0, no units were allowed.
+ type: str
memswap:
description:
- - Total memory (memory + swap).
- - Use C(-1) to disable swap.
- type: int
+ - "Total memory limit (memory + swap) for build in format C(<number>[<unit>]), or
+ the special values V(unlimited) or V(-1) for unlimited swap usage.
+ Number is a positive integer. Unit can be V(B) (byte), V(K) (kibibyte, 1024B),
+ V(M) (mebibyte), V(G) (gibibyte), V(T) (tebibyte), or V(P) (pebibyte)."
+ - Omitting the unit defaults to bytes.
+ - Before community.docker 3.6.0, no units were allowed, and neither was the special value V(unlimited).
+ type: str
cpushares:
description:
- CPU shares (relative weight).
@@ -126,11 +135,11 @@ options:
cpusetcpus:
description:
- CPUs in which to allow execution.
- - For example, C(0-3) or C(0,1).
+ - For example, V(0-3) or V(0,1).
type: str
use_config_proxy:
description:
- - If set to C(true) and a proxy configuration is specified in the docker client configuration
+ - If set to V(true) and a proxy configuration is specified in the docker client configuration
(by default C($HOME/.docker/config.json)), the corresponding environment variables will
be set in the container being built.
type: bool
@@ -144,37 +153,50 @@ options:
- Platform in the format C(os[/arch[/variant]]).
type: str
version_added: 1.1.0
+ shm_size:
+ description:
+ - "Size of C(/dev/shm) in format C(<number>[<unit>]). Number is positive integer.
+ Unit can be V(B) (byte), V(K) (kibibyte, 1024B), V(M) (mebibyte), V(G) (gibibyte),
+ V(T) (tebibyte), or V(P) (pebibyte)."
+ - Omitting the unit defaults to bytes. If you omit the size entirely, Docker daemon uses V(64M).
+ type: str
+ version_added: 3.6.0
+ labels:
+ description:
+ - Dictionary of key value pairs.
+ type: dict
+ version_added: 3.6.0
archive_path:
description:
- - Use with state C(present) to archive an image to a .tar file.
+ - Use with O(state=present) to archive an image to a C(.tar) file.
type: path
load_path:
description:
- - Use with state C(present) to load an image from a .tar file.
- - Set I(source) to C(load) if you want to load the image.
+ - Use with O(state=present) to load an image from a C(.tar) file.
+ - Set O(source=load) if you want to load the image.
type: path
force_source:
description:
- - Use with state C(present) to build, load or pull an image (depending on the
- value of the I(source) option) when the image already exists.
+ - Use with O(state=present) to build, load or pull an image (depending on the
+ value of the O(source) option) when the image already exists.
type: bool
default: false
force_absent:
description:
- - Use with state I(absent) to un-tag and remove all images matching the specified name.
+ - Use with O(state=absent) to un-tag and remove all images matching the specified name.
type: bool
default: false
force_tag:
description:
- - Use with state C(present) to force tagging an image.
+ - Use with O(state=present) to force tagging an image.
type: bool
default: false
name:
description:
- "Image name. Name format will be one of: C(name), C(repository/name), C(registry_server:port/name).
When pushing or pulling an image the name can optionally include the tag by appending C(:tag_name)."
- - Note that image IDs (hashes) are only supported for I(state=absent), for I(state=present) with I(source=load),
- and for I(state=present) with I(source=local).
+ - Note that image IDs (hashes) are only supported for O(state=absent), for O(state=present) with O(source=load),
+ and for O(state=present) with O(source=local).
type: str
required: true
pull:
@@ -191,23 +213,23 @@ options:
type: str
push:
description:
- - Push the image to the registry. Specify the registry as part of the I(name) or I(repository) parameter.
+ - Push the image to the registry. Specify the registry as part of the O(name) or O(repository) parameter.
type: bool
default: false
repository:
description:
- - Use with state C(present) to tag the image.
- - Expects format C(repository:tag). If no tag is provided, will use the value of the I(tag) parameter or C(latest).
- - If I(push=true), I(repository) must either include a registry, or will be assumed to belong to the default
+ - Use with O(state=present) to tag the image.
+ - Expects format C(repository:tag). If no tag is provided, will use the value of the O(tag) parameter or V(latest).
+ - If O(push=true), O(repository) must either include a registry, or will be assumed to belong to the default
registry (Docker Hub).
type: str
state:
description:
- Make assertions about the state of an image.
- - When C(absent) an image will be removed. Use the force option to un-tag and remove all images
+ - When V(absent) an image will be removed. Use the force option to un-tag and remove all images
matching the provided name.
- - When C(present) check if an image exists using the provided name and tag. If the image is not found or the
- force option is used, the image will either be pulled, built or loaded, depending on the I(source) option.
+ - When V(present) check if an image exists using the provided name and tag. If the image is not found or the
+ force option is used, the image will either be pulled, built or loaded, depending on the O(source) option.
type: str
default: present
choices:
@@ -216,8 +238,8 @@ options:
tag:
description:
- Used to select an image when pulling. Will be added to the image when pushing, tagging or building. Defaults to
- I(latest).
- - If I(name) parameter format is I(name:tag), then tag value from I(name) will take precedence.
+ V(latest).
+ - If O(name) parameter format is C(name:tag), then tag value from O(name) will take precedence.
type: str
default: latest
@@ -229,6 +251,15 @@ author:
- Chris Houseknecht (@chouseknecht)
- Sorin Sbarnea (@ssbarnea)
+seealso:
+ - module: community.docker.docker_image_build
+ - module: community.docker.docker_image_export
+ - module: community.docker.docker_image_info
+ - module: community.docker.docker_image_load
+ - module: community.docker.docker_image_pull
+ - module: community.docker.docker_image_push
+ - module: community.docker.docker_image_remove
+ - module: community.docker.docker_image_tag
'''
EXAMPLES = '''
@@ -338,6 +369,7 @@ import os
import traceback
from ansible.module_utils.common.text.converters import to_native
+from ansible.module_utils.common.text.formatters import human_to_bytes
from ansible_collections.community.docker.plugins.module_utils.common_api import (
AnsibleDockerClient,
@@ -377,6 +409,17 @@ from ansible_collections.community.docker.plugins.module_utils._api.utils.utils
)
+def convert_to_bytes(value, module, name, unlimited_value=None):
+ if value is None:
+ return value
+ try:
+ if unlimited_value is not None and value in ('unlimited', str(unlimited_value)):
+ return unlimited_value
+ return human_to_bytes(value)
+ except ValueError as exc:
+ module.fail_json(msg='Failed to convert %s to bytes: %s' % (name, to_native(exc)))
+
+
class ImageManager(DockerBaseClass):
def __init__(self, client, results):
@@ -402,6 +445,12 @@ class ImageManager(DockerBaseClass):
self.archive_path = parameters['archive_path']
self.cache_from = build.get('cache_from')
self.container_limits = build.get('container_limits')
+ if self.container_limits and 'memory' in self.container_limits:
+ self.container_limits['memory'] = convert_to_bytes(
+ self.container_limits['memory'], self.client.module, 'build.container_limits.memory')
+ if self.container_limits and 'memswap' in self.container_limits:
+ self.container_limits['memswap'] = convert_to_bytes(
+ self.container_limits['memswap'], self.client.module, 'build.container_limits.memswap', unlimited_value=-1)
self.dockerfile = build.get('dockerfile')
self.force_source = parameters['force_source']
self.force_absent = parameters['force_absent']
@@ -424,6 +473,8 @@ class ImageManager(DockerBaseClass):
self.buildargs = build.get('args')
self.build_platform = build.get('platform')
self.use_config_proxy = build.get('use_config_proxy')
+ self.shm_size = convert_to_bytes(build.get('shm_size'), self.client.module, 'build.shm_size')
+ self.labels = clean_dict_booleans_for_docker_api(build.get('labels'))
# If name contains a tag, it takes precedence over tag parameter.
if not is_image_name_id(self.name):
@@ -825,6 +876,12 @@ class ImageManager(DockerBaseClass):
if self.build_platform is not None:
params['platform'] = self.build_platform
+ if self.shm_size is not None:
+ params['shmsize'] = self.shm_size
+
+ if self.labels:
+ params['labels'] = json.dumps(self.labels)
+
if context is not None:
headers['Content-Type'] = 'application/tar'
@@ -945,8 +1002,8 @@ def main():
build=dict(type='dict', options=dict(
cache_from=dict(type='list', elements='str'),
container_limits=dict(type='dict', options=dict(
- memory=dict(type='int'),
- memswap=dict(type='int'),
+ memory=dict(type='str'),
+ memswap=dict(type='str'),
cpushares=dict(type='int'),
cpusetcpus=dict(type='str'),
)),
@@ -962,6 +1019,8 @@ def main():
target=dict(type='str'),
etc_hosts=dict(type='dict'),
platform=dict(type='str'),
+ shm_size=dict(type='str'),
+ labels=dict(type='dict'),
)),
archive_path=dict(type='path'),
force_source=dict(type='bool', default=False),
diff --git a/ansible_collections/community/docker/plugins/modules/docker_image_build.py b/ansible_collections/community/docker/plugins/modules/docker_image_build.py
new file mode 100644
index 000000000..7f9502098
--- /dev/null
+++ b/ansible_collections/community/docker/plugins/modules/docker_image_build.py
@@ -0,0 +1,316 @@
+#!/usr/bin/python
+#
+# Copyright (c) 2023, Felix Fontein <felix@fontein.de>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+
+DOCUMENTATION = '''
+---
+module: docker_image_build
+
+short_description: Build Docker images using Docker buildx
+
+version_added: 3.6.0
+
+description:
+ - This module allows you to build Docker images using Docker's buildx plugin (BuildKit).
+
+extends_documentation_fragment:
+ - community.docker.docker.cli_documentation
+ - community.docker.attributes
+ - community.docker.attributes.actiongroup_docker
+
+attributes:
+ check_mode:
+ support: full
+ diff_mode:
+ support: none
+
+options:
+ name:
+ description:
+ - "Image name. Name format will be one of: C(name), C(repository/name), C(registry_server:port/name).
+ When pushing or pulling an image the name can optionally include the tag by appending C(:tag_name)."
+ - Note that image IDs (hashes) and names with digest cannot be used.
+ type: str
+ required: true
+ tag:
+ description:
+ - Tag for the image name O(name) that is to be tagged.
+ - If O(name)'s format is C(name:tag), then the tag value from O(name) will take precedence.
+ type: str
+ default: latest
+ path:
+ description:
+ - The path for the build environment.
+ type: path
+ required: true
+ dockerfile:
+ description:
+ - Provide an alternate name for the Dockerfile to use when building an image.
+ - This can also include a relative path (relative to O(path)).
+ type: str
+ cache_from:
+ description:
+ - List of image names to consider as cache source.
+ type: list
+ elements: str
+ pull:
+ description:
+ - When building an image downloads any updates to the FROM image in Dockerfile.
+ type: bool
+ default: false
+ network:
+ description:
+ - The network to use for C(RUN) build instructions.
+ type: str
+ nocache:
+ description:
+ - Do not use cache when building an image.
+ type: bool
+ default: false
+ etc_hosts:
+ description:
+ - Extra hosts to add to C(/etc/hosts) in building containers, as a mapping of hostname to IP address.
+ type: dict
+ args:
+ description:
+ - Provide a dictionary of C(key:value) build arguments that map to Dockerfile ARG directive.
+ - Docker expects the value to be a string. For convenience any non-string values will be converted to strings.
+ type: dict
+ target:
+ description:
+ - When building an image specifies an intermediate build stage by
+ name as a final stage for the resulting image.
+ type: str
+ platform:
+ description:
+ - Platform in the format C(os[/arch[/variant]]).
+ type: str
+ shm_size:
+ description:
+ - "Size of C(/dev/shm) in format C(<number>[<unit>]). Number is positive integer.
+ Unit can be V(B) (byte), V(K) (kibibyte, 1024B), V(M) (mebibyte), V(G) (gibibyte),
+ V(T) (tebibyte), or V(P) (pebibyte)."
+ - Omitting the unit defaults to bytes. If you omit the size entirely, Docker daemon uses V(64M).
+ type: str
+ labels:
+ description:
+ - Dictionary of key value pairs.
+ type: dict
+ rebuild:
+ description:
+ - Defines the behavior of the module if the image to build (as specified in O(name) and O(tag)) already exists.
+ type: str
+ choices:
+ - never
+ - always
+ default: never
+
+requirements:
+ - "Docker CLI with Docker buildx plugin"
+
+author:
+ - Felix Fontein (@felixfontein)
+
+seealso:
+ - module: community.docker.docker_image_push
+ - module: community.docker.docker_image_tag
+'''
+
+EXAMPLES = '''
+- name: Build Python 3.12 image
+ community.docker.docker_image_build:
+ name: localhost/python/3.12:latest
+ path: /home/user/images/python
+ dockerfile: Dockerfile-3.12
+'''
+
+RETURN = '''
+image:
+ description: Image inspection results for the affected image.
+ returned: success
+ type: dict
+ sample: {}
+'''
+
+import os
+import traceback
+
+from ansible.module_utils.common.text.converters import to_native
+from ansible.module_utils.common.text.formatters import human_to_bytes
+
+from ansible_collections.community.docker.plugins.module_utils.common_cli import (
+ AnsibleModuleDockerClient,
+ DockerException,
+)
+
+from ansible_collections.community.docker.plugins.module_utils.util import (
+ DockerBaseClass,
+ clean_dict_booleans_for_docker_api,
+ is_image_name_id,
+ is_valid_tag,
+)
+
+from ansible_collections.community.docker.plugins.module_utils._api.utils.utils import (
+ parse_repository_tag,
+)
+
+
+def convert_to_bytes(value, module, name, unlimited_value=None):
+ if value is None:
+ return value
+ try:
+ if unlimited_value is not None and value in ('unlimited', str(unlimited_value)):
+ return unlimited_value
+ return human_to_bytes(value)
+ except ValueError as exc:
+ module.fail_json(msg='Failed to convert %s to bytes: %s' % (name, to_native(exc)))
+
+
+def dict_to_list(dictionary, concat='='):
+ return ['%s%s%s' % (k, concat, v) for k, v in sorted(dictionary.items())]
+
+
+class ImageBuilder(DockerBaseClass):
+ def __init__(self, client):
+ super(ImageBuilder, self).__init__()
+ self.client = client
+ self.check_mode = self.client.check_mode
+ parameters = self.client.module.params
+
+ self.cache_from = parameters['cache_from']
+ self.pull = parameters['pull']
+ self.network = parameters['network']
+ self.nocache = parameters['nocache']
+ self.etc_hosts = clean_dict_booleans_for_docker_api(parameters['etc_hosts'])
+ self.args = clean_dict_booleans_for_docker_api(parameters['args'])
+ self.target = parameters['target']
+ self.platform = parameters['platform']
+ self.shm_size = convert_to_bytes(parameters['shm_size'], self.client.module, 'shm_size')
+ self.labels = clean_dict_booleans_for_docker_api(parameters['labels'])
+ self.rebuild = parameters['rebuild']
+
+ buildx = self.client.get_client_plugin_info('buildx')
+ if buildx is None:
+ self.fail('Docker CLI {0} does not have the buildx plugin installed'.format(self.client.get_cli()))
+
+ self.path = parameters['path']
+ if not os.path.isdir(self.path):
+ self.fail('"{0}" is not an existing directory'.format(self.path))
+ self.dockerfile = parameters['dockerfile']
+ if self.dockerfile and not os.path.isfile(os.path.join(self.path, self.dockerfile)):
+ self.fail('"{0}" is not an existing file'.format(os.path.join(self.path, self.dockerfile)))
+
+ self.name = parameters['name']
+ self.tag = parameters['tag']
+ if not is_valid_tag(self.tag, allow_empty=True):
+ self.fail('"{0}" is not a valid docker tag'.format(self.tag))
+ if is_image_name_id(self.name):
+ self.fail('Image name must not be a digest')
+
+ # If name contains a tag, it takes precedence over tag parameter.
+ repo, repo_tag = parse_repository_tag(self.name)
+ if repo_tag:
+ self.name = repo
+ self.tag = repo_tag
+
+ if is_image_name_id(self.tag):
+ self.fail('Image name must not contain a digest, but have a tag')
+
+ def fail(self, msg, **kwargs):
+ self.client.fail(msg, **kwargs)
+
+ def add_list_arg(self, args, option, values):
+ for value in values:
+ args.extend([option, value])
+
+ def add_args(self, args):
+ args.extend(['--tag', '%s:%s' % (self.name, self.tag)])
+ if self.dockerfile:
+ args.extend(['--file', os.path.join(self.path, self.dockerfile)])
+ if self.cache_from:
+ self.add_list_arg(args, '--cache-from', self.cache_from)
+ if self.pull:
+ args.append('--pull')
+ if self.network:
+ args.extend(['--network', self.network])
+ if self.nocache:
+ args.append('--no-cache')
+ if self.etc_hosts:
+ self.add_list_arg(args, '--add-host', dict_to_list(self.etc_hosts, ':'))
+ if self.args:
+ self.add_list_arg(args, '--build-arg', dict_to_list(self.args))
+ if self.target:
+ args.extend(['--target', self.target])
+ if self.platform:
+ args.extend(['--platform', self.platform])
+ if self.shm_size:
+ args.extend(['--shm-size', str(self.shm_size)])
+ if self.labels:
+ self.add_list_arg(args, '--label', dict_to_list(self.labels))
+
+ def build_image(self):
+ image = self.client.find_image(self.name, self.tag)
+ results = dict(
+ changed=False,
+ actions=[],
+ image=image or {},
+ )
+
+ if image:
+ if self.rebuild == 'never':
+ return results
+
+ results['changed'] = True
+ if not self.check_mode:
+ args = ['buildx', 'build', '--progress', 'plain']
+ self.add_args(args)
+ args.extend(['--', self.path])
+ rc, stdout, stderr = self.client.call_cli(*args)
+ if rc != 0:
+ self.fail('Building %s:%s failed' % (self.name, self.tag), stdout=to_native(stdout), stderr=to_native(stderr))
+ results['stdout'] = to_native(stdout)
+ results['stderr'] = to_native(stderr)
+ results['image'] = self.client.find_image(self.name, self.tag) or {}
+
+ return results
+
+
+def main():
+ argument_spec = dict(
+ name=dict(type='str', required=True),
+ tag=dict(type='str', default='latest'),
+ path=dict(type='path', required=True),
+ dockerfile=dict(type='str'),
+ cache_from=dict(type='list', elements='str'),
+ pull=dict(type='bool', default=False),
+ network=dict(type='str'),
+ nocache=dict(type='bool', default=False),
+ etc_hosts=dict(type='dict'),
+ args=dict(type='dict'),
+ target=dict(type='str'),
+ platform=dict(type='str'),
+ shm_size=dict(type='str'),
+ labels=dict(type='dict'),
+ rebuild=dict(type='str', choices=['never', 'always'], default='never'),
+ )
+
+ client = AnsibleModuleDockerClient(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
+
+ try:
+ results = ImageBuilder(client).build_image()
+ client.module.exit_json(**results)
+ except DockerException as e:
+ client.fail('An unexpected Docker error occurred: {0}'.format(to_native(e)), exception=traceback.format_exc())
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/docker/plugins/modules/docker_image_export.py b/ansible_collections/community/docker/plugins/modules/docker_image_export.py
new file mode 100644
index 000000000..9e03875a2
--- /dev/null
+++ b/ansible_collections/community/docker/plugins/modules/docker_image_export.py
@@ -0,0 +1,283 @@
+#!/usr/bin/python
+#
+# Copyright (c) 2023, Felix Fontein <felix@fontein.de>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+
+DOCUMENTATION = '''
+---
+module: docker_image_export
+
+short_description: Export (archive) Docker images
+
+version_added: 3.7.0
+
+description:
+ - Creates an archive (tarball) from one or more Docker images.
+ - This can be copied to another machine and loaded with M(community.docker.docker_image_load).
+
+extends_documentation_fragment:
+ - community.docker.docker.api_documentation
+ - community.docker.attributes
+ - community.docker.attributes.actiongroup_docker
+
+attributes:
+ check_mode:
+ support: full
+ diff_mode:
+ support: none
+
+options:
+ names:
+ description:
+ - "One or more image names. Name format will be one of: C(name), C(repository/name), C(registry_server:port/name).
+ When pushing or pulling an image the name can optionally include the tag by appending C(:tag_name)."
+ - Note that image IDs (hashes) can also be used.
+ type: list
+ elements: str
+ required: true
+ aliases:
+ - name
+ tag:
+ description:
+ - Tag for the image name O(name) that is to be tagged.
+ - If O(name)'s format is C(name:tag), then the tag value from O(name) will take precedence.
+ type: str
+ default: latest
+ path:
+ description:
+ - The C(.tar) file the image should be exported to.
+ type: path
+ force:
+ description:
+ - Export the image even if the C(.tar) file already exists and seems to contain the right image.
+ type: bool
+ default: false
+
+requirements:
+ - "Docker API >= 1.25"
+
+author:
+ - Felix Fontein (@felixfontein)
+
+seealso:
+ - module: community.docker.docker_image
+ - module: community.docker.docker_image_info
+ - module: community.docker.docker_image_load
+'''
+
+EXAMPLES = '''
+- name: Export an image
+ community.docker.docker_image_export:
+ name: pacur/centos-7
+ path: /tmp/centos-7.tar
+
+- name: Export multiple images
+ community.docker.docker_image_export:
+ names:
+ - hello-world:latest
+ - pacur/centos-7:latest
+ path: /tmp/various.tar
+'''
+
+RETURN = '''
+images:
+ description: Image inspection results for the affected images.
+ returned: success
+ type: list
+ elements: dict
+ sample: []
+'''
+
+import traceback
+
+from ansible.module_utils.common.text.converters import to_native
+
+from ansible_collections.community.docker.plugins.module_utils.common_api import (
+ AnsibleDockerClient,
+ RequestException,
+)
+
+from ansible_collections.community.docker.plugins.module_utils.image_archive import (
+ load_archived_image_manifest,
+ api_image_id,
+ ImageArchiveInvalidException,
+)
+
+from ansible_collections.community.docker.plugins.module_utils.util import (
+ DockerBaseClass,
+ is_image_name_id,
+ is_valid_tag,
+)
+from ansible_collections.community.docker.plugins.module_utils._api.constants import (
+ DEFAULT_DATA_CHUNK_SIZE,
+)
+from ansible_collections.community.docker.plugins.module_utils._api.errors import DockerException
+from ansible_collections.community.docker.plugins.module_utils._api.utils.utils import (
+ parse_repository_tag,
+)
+
+
+class ImageExportManager(DockerBaseClass):
+ def __init__(self, client):
+ super(ImageExportManager, self).__init__()
+
+ self.client = client
+ parameters = self.client.module.params
+ self.check_mode = self.client.check_mode
+
+ self.path = parameters['path']
+ self.force = parameters['force']
+ self.tag = parameters['tag']
+
+ if not is_valid_tag(self.tag, allow_empty=True):
+ self.fail('"{0}" is not a valid docker tag'.format(self.tag))
+
+ # If name contains a tag, it takes precedence over tag parameter.
+ self.names = []
+ for name in parameters['names']:
+ if is_image_name_id(name):
+ self.names.append({'id': name, 'joined': name})
+ else:
+ repo, repo_tag = parse_repository_tag(name)
+ if not repo_tag:
+ repo_tag = self.tag
+ self.names.append({'name': repo, 'tag': repo_tag, 'joined': '%s:%s' % (repo, repo_tag)})
+
+ if not self.names:
+ self.fail('At least one image name must be specified')
+
+ def fail(self, msg):
+ self.client.fail(msg)
+
+ def get_export_reason(self):
+ if self.force:
+ return 'Exporting since force=true'
+
+ try:
+ archived_images = load_archived_image_manifest(self.path)
+ if archived_images is None:
+ return 'Overwriting since no image is present in archive'
+ except ImageArchiveInvalidException as exc:
+ self.log('Unable to extract manifest summary from archive: %s' % to_native(exc))
+ return 'Overwriting an unreadable archive file'
+
+ left_names = list(self.names)
+ for archived_image in archived_images:
+ found = False
+ for i, name in enumerate(left_names):
+ if name['id'] == api_image_id(archived_image.image_id) and [name['joined']] == archived_image.repo_tags:
+ del left_names[i]
+ found = True
+ break
+ if not found:
+ return 'Overwriting archive since it contains unexpected image %s named %s' % (
+ archived_image.image_id, ', '.join(archived_image.repo_tags)
+ )
+ if left_names:
+ return 'Overwriting archive since it is missing image(s) %s' % (', '.join([name['joined'] for name in left_names]))
+
+ return None
+
+ def write_chunks(self, chunks):
+ try:
+ with open(self.path, 'wb') as fd:
+ for chunk in chunks:
+ fd.write(chunk)
+ except Exception as exc:
+ self.fail("Error writing image archive %s - %s" % (self.path, to_native(exc)))
+
+ def export_images(self):
+ image_names = [name['joined'] for name in self.names]
+ image_names_str = ', '.join(image_names)
+ if len(image_names) == 1:
+ self.log("Getting archive of image %s" % image_names[0])
+ try:
+ chunks = self.client._stream_raw_result(
+ self.client._get(self.client._url('/images/{0}/get', image_names[0]), stream=True),
+ DEFAULT_DATA_CHUNK_SIZE,
+ False,
+ )
+ except Exception as exc:
+ self.fail("Error getting image %s - %s" % (image_names[0], to_native(exc)))
+ else:
+ self.log("Getting archive of images %s" % image_names_str)
+ try:
+ chunks = self.client._stream_raw_result(
+ self.client._get(
+ self.client._url('/images/get'),
+ stream=True,
+ params={'names': image_names},
+ ),
+ DEFAULT_DATA_CHUNK_SIZE,
+ False,
+ )
+ except Exception as exc:
+ self.fail("Error getting images %s - %s" % (image_names_str, to_native(exc)))
+
+ self.write_chunks(chunks)
+
+ def run(self):
+ tag = self.tag
+ if not tag:
+ tag = "latest"
+
+ images = []
+ for name in self.names:
+ if 'id' in name:
+ image = self.client.find_image_by_id(name['id'], accept_missing_image=True)
+ else:
+ image = self.client.find_image(name=name['name'], tag=name['tag'])
+ if not image:
+ self.fail("Image %s not found" % name['joined'])
+ images.append(image)
+
+ # Will have a 'sha256:' prefix
+ name['id'] = image['Id']
+
+ results = {
+ 'changed': False,
+ 'images': images,
+ }
+
+ reason = self.get_export_reason()
+ if reason is not None:
+ results['msg'] = reason
+ results['changed'] = True
+
+ if not self.check_mode:
+ self.export_images()
+
+ return results
+
+
+def main():
+ argument_spec = dict(
+ path=dict(type='path'),
+ force=dict(type='bool', default=False),
+ names=dict(type='list', elements='str', required=True, aliases=['name']),
+ tag=dict(type='str', default='latest'),
+ )
+
+ client = AnsibleDockerClient(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
+
+ try:
+ results = ImageExportManager(client).run()
+ client.module.exit_json(**results)
+ except DockerException as e:
+ client.fail('An unexpected Docker error occurred: {0}'.format(to_native(e)), exception=traceback.format_exc())
+ except RequestException as e:
+ client.fail(
+ 'An unexpected requests error occurred when trying to talk to the Docker daemon: {0}'.format(to_native(e)),
+ exception=traceback.format_exc())
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/docker/plugins/modules/docker_image_info.py b/ansible_collections/community/docker/plugins/modules/docker_image_info.py
index e4f480b1c..2f441672f 100644
--- a/ansible_collections/community/docker/plugins/modules/docker_image_info.py
+++ b/ansible_collections/community/docker/plugins/modules/docker_image_info.py
@@ -19,8 +19,8 @@ description:
- If an image does not exist locally, it will not appear in the results. If you want to check whether an image exists
locally, you can call the module with the image name, then check whether the result list is empty (image does not
exist) or has one element (the image exists locally).
- - The module will not attempt to pull images from registries. Use M(community.docker.docker_image) with I(source) set to C(pull)
- to ensure an image is pulled.
+ - The module will not attempt to pull images from registries. Use M(community.docker.docker_image) with
+ O(community.docker.docker_image#module:source=pull) to ensure an image is pulled.
notes:
- This module was called C(docker_image_facts) before Ansible 2.8. The usage did not change.
@@ -35,7 +35,7 @@ options:
name:
description:
- An image name or a list of image names. Name format will be C(name[:tag]) or C(repository/name[:tag]),
- where C(tag) is optional. If a tag is not provided, C(latest) will be used. Instead of image names, also
+ where C(tag) is optional. If a tag is not provided, V(latest) will be used. Instead of image names, also
image IDs can be used.
- If no name is provided, a list of all images will be returned.
type: list
diff --git a/ansible_collections/community/docker/plugins/modules/docker_image_load.py b/ansible_collections/community/docker/plugins/modules/docker_image_load.py
index 880ae4e4c..ec628d1ba 100644
--- a/ansible_collections/community/docker/plugins/modules/docker_image_load.py
+++ b/ansible_collections/community/docker/plugins/modules/docker_image_load.py
@@ -39,14 +39,17 @@ options:
type: path
required: true
-notes:
- - Does not support C(check_mode).
-
requirements:
- "Docker API >= 1.25"
author:
- Felix Fontein (@felixfontein)
+
+seealso:
+ - module: community.docker.docker_image_export
+ - module: community.docker.docker_image_push
+ - module: community.docker.docker_image_remove
+ - module: community.docker.docker_image_tag
'''
EXAMPLES = '''
diff --git a/ansible_collections/community/docker/plugins/modules/docker_image_pull.py b/ansible_collections/community/docker/plugins/modules/docker_image_pull.py
new file mode 100644
index 000000000..a70942b3f
--- /dev/null
+++ b/ansible_collections/community/docker/plugins/modules/docker_image_pull.py
@@ -0,0 +1,223 @@
+#!/usr/bin/python
+#
+# Copyright (c) 2023, Felix Fontein <felix@fontein.de>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+
+DOCUMENTATION = '''
+---
+module: docker_image_pull
+
+short_description: Pull Docker images from registries
+
+version_added: 3.6.0
+
+description:
+ - Pulls a Docker image from a registry.
+
+extends_documentation_fragment:
+ - community.docker.docker.api_documentation
+ - community.docker.attributes
+ - community.docker.attributes.actiongroup_docker
+
+attributes:
+ check_mode:
+ support: partial
+ details:
+ - When trying to pull an image with O(pull=always), the module assumes this is always changed in check mode.
+ - When check mode is combined with diff mode, the pulled image's ID is always shown as V(unknown) in the diff.
+ diff_mode:
+ support: full
+
+options:
+ name:
+ description:
+ - "Image name. Name format must be one of V(name), V(repository/name), or V(registry_server:port/name).
+ - The name can optionally include the tag by appending V(:tag_name), or it can contain a digest by appending V(@hash:digest)."
+ type: str
+ required: true
+ tag:
+ description:
+ - Used to select an image when pulling. Defaults to V(latest).
+ - If O(name) parameter format is C(name:tag) or C(image@hash:digest), then O(tag) will be ignored.
+ type: str
+ default: latest
+ platform:
+ description:
+ - Ask for this specific platform when pulling.
+ type: str
+ pull:
+ description:
+ - Determines when to pull an image.
+ - If V(always), will always pull the image.
+ - If V(not_present), will only pull the image if no image of the name exists on the current Docker daemon,
+ or if O(platform) does not match.
+ type: str
+ choices:
+ - always
+ - not_present
+ default: always
+
+requirements:
+ - "Docker API >= 1.25"
+
+author:
+ - Felix Fontein (@felixfontein)
+
+seealso:
+ - module: community.docker.docker_image_pull
+ - module: community.docker.docker_image_remove
+ - module: community.docker.docker_image_tag
+'''
+
+EXAMPLES = '''
+- name: Pull an image
+ community.docker.docker_image_pull:
+ name: pacur/centos-7
+ # Select platform for pulling. If not specified, will pull whatever docker prefers.
+ platform: amd64
+'''
+
+RETURN = '''
+image:
+ description: Image inspection results for the affected image.
+ returned: success
+ type: dict
+ sample: {}
+'''
+
+import traceback
+
+from ansible.module_utils.common.text.converters import to_native
+
+from ansible_collections.community.docker.plugins.module_utils.common_api import (
+ AnsibleDockerClient,
+ RequestException,
+)
+
+from ansible_collections.community.docker.plugins.module_utils.util import (
+ DockerBaseClass,
+ is_image_name_id,
+ is_valid_tag,
+)
+
+from ansible_collections.community.docker.plugins.module_utils._api.errors import DockerException
+from ansible_collections.community.docker.plugins.module_utils._api.utils.utils import (
+ parse_repository_tag,
+)
+
+from ansible_collections.community.docker.plugins.module_utils._platform import (
+ normalize_platform_string,
+ compare_platform_strings,
+ compose_platform_string,
+)
+
+
+def image_info(image):
+ result = {}
+ if image:
+ result['id'] = image['Id']
+ else:
+ result['exists'] = False
+ return result
+
+
+class ImagePuller(DockerBaseClass):
+ def __init__(self, client):
+ super(ImagePuller, self).__init__()
+
+ self.client = client
+ self.check_mode = self.client.check_mode
+
+ parameters = self.client.module.params
+ self.name = parameters['name']
+ self.tag = parameters['tag']
+ self.platform = parameters['platform']
+ self.pull_mode = parameters['pull']
+
+ if is_image_name_id(self.name):
+ self.client.fail("Cannot pull an image by ID")
+ if not is_valid_tag(self.tag, allow_empty=True):
+ self.client.fail('"{0}" is not a valid docker tag!'.format(self.tag))
+
+ # If name contains a tag, it takes precedence over tag parameter.
+ repo, repo_tag = parse_repository_tag(self.name)
+ if repo_tag:
+ self.name = repo
+ self.tag = repo_tag
+
+ def pull(self):
+ image = self.client.find_image(name=self.name, tag=self.tag)
+ results = dict(
+ changed=False,
+ actions=[],
+ image=image or {},
+ diff=dict(before=image_info(image), after=image_info(image)),
+ )
+
+ if image and self.pull_mode == 'not_present':
+ if self.platform is None:
+ return results
+ host_info = self.client.info()
+ wanted_platform = normalize_platform_string(
+ self.platform,
+ daemon_os=host_info.get('OSType'),
+ daemon_arch=host_info.get('Architecture'),
+ )
+ image_platform = compose_platform_string(
+ os=image.get('Os'),
+ arch=image.get('Architecture'),
+ variant=image.get('Variant'),
+ daemon_os=host_info.get('OSType'),
+ daemon_arch=host_info.get('Architecture'),
+ )
+ if compare_platform_strings(wanted_platform, image_platform):
+ return results
+
+ results['actions'].append('Pulled image %s:%s' % (self.name, self.tag))
+ if self.check_mode:
+ results['changed'] = True
+ results['diff']['after'] = image_info(dict(Id='unknown'))
+ else:
+ results['image'], not_changed = self.client.pull_image(self.name, tag=self.tag, platform=self.platform)
+ results['changed'] = not not_changed
+ results['diff']['after'] = image_info(results['image'])
+
+ return results
+
+
+def main():
+ argument_spec = dict(
+ name=dict(type='str', required=True),
+ tag=dict(type='str', default='latest'),
+ platform=dict(type='str'),
+ pull=dict(type='str', choices=['always', 'not_present'], default='always'),
+ )
+
+ option_minimal_versions = dict(
+ platform=dict(docker_api_version='1.32'),
+ )
+
+ client = AnsibleDockerClient(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ option_minimal_versions=option_minimal_versions,
+ )
+
+ try:
+ results = ImagePuller(client).pull()
+ client.module.exit_json(**results)
+ except DockerException as e:
+ client.fail('An unexpected Docker error occurred: {0}'.format(to_native(e)), exception=traceback.format_exc())
+ except RequestException as e:
+ client.fail(
+ 'An unexpected requests error occurred when trying to talk to the Docker daemon: {0}'.format(to_native(e)),
+ exception=traceback.format_exc())
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/docker/plugins/modules/docker_image_push.py b/ansible_collections/community/docker/plugins/modules/docker_image_push.py
new file mode 100644
index 000000000..f1474d838
--- /dev/null
+++ b/ansible_collections/community/docker/plugins/modules/docker_image_push.py
@@ -0,0 +1,197 @@
+#!/usr/bin/python
+#
+# Copyright (c) 2023, Felix Fontein <felix@fontein.de>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+
+DOCUMENTATION = '''
+---
+module: docker_image_push
+
+short_description: Push Docker images to registries
+
+version_added: 3.6.0
+
+description:
+ - Pushes a Docker image to a registry.
+
+extends_documentation_fragment:
+ - community.docker.docker.api_documentation
+ - community.docker.attributes
+ - community.docker.attributes.actiongroup_docker
+
+attributes:
+ check_mode:
+ support: none
+ diff_mode:
+ support: none
+
+options:
+ name:
+ description:
+ - "Image name. Name format must be one of V(name), V(repository/name), or V(registry_server:port/name).
+ - The name can optionally include the tag by appending V(:tag_name), or it can contain a digest by appending V(@hash:digest)."
+ type: str
+ required: true
+ tag:
+ description:
+ - Select which image to push. Defaults to V(latest).
+ - If O(name) parameter format is C(name:tag) or C(image@hash:digest), then O(tag) will be ignored.
+ type: str
+ default: latest
+
+requirements:
+ - "Docker API >= 1.25"
+
+author:
+ - Felix Fontein (@felixfontein)
+
+seealso:
+ - module: community.docker.docker_image_pull
+ - module: community.docker.docker_image_remove
+ - module: community.docker.docker_image_tag
+'''
+
+EXAMPLES = '''
+- name: Push an image
+ community.docker.docker_image_push:
+ name: registry.example.com:5000/repo/image
+ tag: latest
+'''
+
+RETURN = '''
+image:
+ description: Image inspection results for the affected image.
+ returned: success
+ type: dict
+ sample: {}
+'''
+
+import traceback
+
+from ansible.module_utils.common.text.converters import to_native
+
+from ansible_collections.community.docker.plugins.module_utils.common_api import (
+ AnsibleDockerClient,
+ RequestException,
+)
+
+from ansible_collections.community.docker.plugins.module_utils.util import (
+ DockerBaseClass,
+ is_image_name_id,
+ is_valid_tag,
+)
+
+from ansible_collections.community.docker.plugins.module_utils._api.errors import DockerException
+from ansible_collections.community.docker.plugins.module_utils._api.utils.utils import (
+ parse_repository_tag,
+)
+
+from ansible_collections.community.docker.plugins.module_utils._api.auth import (
+ get_config_header,
+ resolve_repository_name,
+)
+
+
+class ImagePusher(DockerBaseClass):
+ def __init__(self, client):
+ super(ImagePusher, self).__init__()
+
+ self.client = client
+ self.check_mode = self.client.check_mode
+
+ parameters = self.client.module.params
+ self.name = parameters['name']
+ self.tag = parameters['tag']
+
+ if is_image_name_id(self.name):
+ self.client.fail("Cannot push an image by ID")
+ if not is_valid_tag(self.tag, allow_empty=True):
+ self.client.fail('"{0}" is not a valid docker tag!'.format(self.tag))
+
+ # If name contains a tag, it takes precedence over tag parameter.
+ repo, repo_tag = parse_repository_tag(self.name)
+ if repo_tag:
+ self.name = repo
+ self.tag = repo_tag
+
+ if is_image_name_id(self.tag):
+ self.client.fail("Cannot push an image by digest")
+ if not is_valid_tag(self.tag, allow_empty=False):
+ self.client.fail('"{0}" is not a valid docker tag!'.format(self.tag))
+
+ def push(self):
+ image = self.client.find_image(name=self.name, tag=self.tag)
+ if not image:
+ self.client.fail('Cannot find image %s:%s' % (self.name, self.tag))
+
+ results = dict(
+ changed=False,
+ actions=[],
+ image=image,
+ )
+
+ push_registry, push_repo = resolve_repository_name(self.name)
+ try:
+ results['actions'].append('Pushed image %s:%s' % (self.name, self.tag))
+
+ headers = {}
+ header = get_config_header(self.client, push_registry)
+ if header:
+ headers['X-Registry-Auth'] = header
+ response = self.client._post_json(
+ self.client._url("/images/{0}/push", self.name),
+ data=None,
+ headers=headers,
+ stream=True,
+ params={'tag': self.tag},
+ )
+ self.client._raise_for_status(response)
+ for line in self.client._stream_helper(response, decode=True):
+ self.log(line, pretty_print=True)
+ if line.get('errorDetail'):
+ raise Exception(line['errorDetail']['message'])
+ status = line.get('status')
+ if status == 'Pushing':
+ results['changed'] = True
+ except Exception as exc:
+ if 'unauthorized' in str(exc):
+ if 'authentication required' in str(exc):
+ self.client.fail("Error pushing image %s/%s:%s - %s. Try logging into %s first." %
+ (push_registry, push_repo, self.tag, to_native(exc), push_registry))
+ else:
+ self.client.fail("Error pushing image %s/%s:%s - %s. Does the repository exist?" %
+ (push_registry, push_repo, self.tag, str(exc)))
+ self.client.fail("Error pushing image %s:%s: %s" % (self.name, self.tag, to_native(exc)))
+
+ return results
+
+
+def main():
+ argument_spec = dict(
+ name=dict(type='str', required=True),
+ tag=dict(type='str', default='latest'),
+ )
+
+ client = AnsibleDockerClient(
+ argument_spec=argument_spec,
+ supports_check_mode=False,
+ )
+
+ try:
+ results = ImagePusher(client).push()
+ client.module.exit_json(**results)
+ except DockerException as e:
+ client.fail('An unexpected Docker error occurred: {0}'.format(to_native(e)), exception=traceback.format_exc())
+ except RequestException as e:
+ client.fail(
+ 'An unexpected requests error occurred when trying to talk to the Docker daemon: {0}'.format(to_native(e)),
+ exception=traceback.format_exc())
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/docker/plugins/modules/docker_image_remove.py b/ansible_collections/community/docker/plugins/modules/docker_image_remove.py
new file mode 100644
index 000000000..c8ea326b2
--- /dev/null
+++ b/ansible_collections/community/docker/plugins/modules/docker_image_remove.py
@@ -0,0 +1,269 @@
+#!/usr/bin/python
+#
+# Copyright 2016 Red Hat | Ansible
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+
+DOCUMENTATION = '''
+---
+module: docker_image_remove
+
+short_description: Remove Docker images
+
+version_added: 3.6.0
+
+description:
+ - Remove Docker images from the Docker daemon.
+
+extends_documentation_fragment:
+ - community.docker.docker.api_documentation
+ - community.docker.attributes
+ - community.docker.attributes.actiongroup_docker
+
+attributes:
+ check_mode:
+ support: full
+ diff_mode:
+ support: full
+
+options:
+ name:
+ description:
+ - "Image name. Name format will be one of: C(name), C(repository/name), C(registry_server:port/name).
+ When pushing or pulling an image the name can optionally include the tag by appending C(:tag_name)."
+ - Note that image IDs (hashes) can also be used.
+ type: str
+ required: true
+ tag:
+ description:
+ - Tag for the image name O(name) that is to be tagged.
+ - If O(name)'s format is C(name:tag), then the tag value from O(name) will take precedence.
+ type: str
+ default: latest
+ force:
+ description:
+ - Un-tag and remove all images matching the specified name.
+ type: bool
+ default: false
+ prune:
+ description:
+ - Delete untagged parent images.
+ type: bool
+ default: true
+
+requirements:
+ - "Docker API >= 1.25"
+
+author:
+ - Felix Fontein (@felixfontein)
+
+seealso:
+ - module: community.docker.docker_image_load
+ - module: community.docker.docker_image_pull
+ - module: community.docker.docker_image_tag
+'''
+
+EXAMPLES = '''
+
+- name: Remove an image
+ community.docker.docker_image_remove:
+ name: pacur/centos-7
+'''
+
+RETURN = '''
+image:
+ description:
+ - Image inspection results for the affected image before removal.
+ - Empty if the image was not found.
+ returned: success
+ type: dict
+ sample: {}
+deleted:
+ description:
+ - The digests of the images that were deleted.
+ returned: success
+ type: list
+ elements: str
+ sample: []
+untagged:
+ description:
+ - The digests of the images that were untagged.
+ returned: success
+ type: list
+ elements: str
+ sample: []
+'''
+
+import traceback
+
+from ansible.module_utils.common.text.converters import to_native
+
+from ansible_collections.community.docker.plugins.module_utils.common_api import (
+ AnsibleDockerClient,
+ RequestException,
+)
+
+from ansible_collections.community.docker.plugins.module_utils.util import (
+ DockerBaseClass,
+ is_image_name_id,
+ is_valid_tag,
+)
+
+from ansible_collections.community.docker.plugins.module_utils._api.errors import DockerException, NotFound
+from ansible_collections.community.docker.plugins.module_utils._api.utils.utils import (
+ parse_repository_tag,
+)
+
+
+class ImageRemover(DockerBaseClass):
+
+ def __init__(self, client):
+ super(ImageRemover, self).__init__()
+
+ self.client = client
+ self.check_mode = self.client.check_mode
+ self.diff = self.client.module._diff
+
+ parameters = self.client.module.params
+ self.name = parameters['name']
+ self.tag = parameters['tag']
+ self.force = parameters['force']
+ self.prune = parameters['prune']
+
+ if not is_valid_tag(self.tag, allow_empty=True):
+ self.fail('"{0}" is not a valid docker tag'.format(self.tag))
+
+ # If name contains a tag, it takes precedence over tag parameter.
+ if not is_image_name_id(self.name):
+ repo, repo_tag = parse_repository_tag(self.name)
+ if repo_tag:
+ self.name = repo
+ self.tag = repo_tag
+
+ def fail(self, msg):
+ self.client.fail(msg)
+
+ def get_diff_state(self, image):
+ if not image:
+ return dict(exists=False)
+ return dict(
+ exists=True,
+ id=image['Id'],
+ tags=sorted(image.get('RepoTags') or []),
+ digests=sorted(image.get('RepoDigests') or []),
+ )
+
+ def absent(self):
+ results = dict(
+ changed=False,
+ actions=[],
+ image={},
+ deleted=[],
+ untagged=[],
+ )
+
+ name = self.name
+ if is_image_name_id(name):
+ image = self.client.find_image_by_id(name, accept_missing_image=True)
+ else:
+ image = self.client.find_image(name, self.tag)
+ if self.tag:
+ name = "%s:%s" % (self.name, self.tag)
+
+ if self.diff:
+ results['diff'] = dict(before=self.get_diff_state(image))
+
+ if not image:
+ if self.diff:
+ results['diff']['after'] = self.get_diff_state(image)
+ return results
+
+ results['changed'] = True
+ results['actions'].append("Removed image %s" % (name))
+ results['image'] = image
+
+ if not self.check_mode:
+ try:
+ res = self.client.delete_json('/images/{0}', name, params={'force': self.force, 'noprune': not self.prune})
+ except NotFound:
+ # If the image vanished while we were trying to remove it, don't fail
+ res = []
+ except Exception as exc:
+ self.fail("Error removing image %s - %s" % (name, to_native(exc)))
+
+ for entry in res:
+ if entry.get('Untagged'):
+ results['untagged'].append(entry['Untagged'])
+ if entry.get('Deleted'):
+ results['deleted'].append(entry['Deleted'])
+
+ results['untagged'] = sorted(results['untagged'])
+ results['deleted'] = sorted(results['deleted'])
+
+ if self.diff:
+ image_after = self.client.find_image_by_id(image['Id'], accept_missing_image=True)
+ results['diff']['after'] = self.get_diff_state(image_after)
+
+ elif is_image_name_id(name):
+ results['deleted'].append(image['Id'])
+ results['untagged'] = sorted((image.get('RepoTags') or []) + (image.get('RepoDigests') or []))
+ if not self.force and results['untagged']:
+ self.fail('Cannot delete image by ID that is still in use - use force=true')
+ if self.diff:
+ results['diff']['after'] = self.get_diff_state({})
+
+ elif is_image_name_id(self.tag):
+ results['untagged'].append(name)
+ if len(image.get('RepoTags') or []) < 1 and len(image.get('RepoDigests') or []) < 2:
+ results['deleted'].append(image['Id'])
+ if self.diff:
+ results['diff']['after'] = self.get_diff_state(image)
+ try:
+ results['diff']['after']['digests'].remove(name)
+ except ValueError:
+ pass
+
+ else:
+ results['untagged'].append(name)
+ if len(image.get('RepoTags') or []) < 2 and len(image.get('RepoDigests') or []) < 1:
+ results['deleted'].append(image['Id'])
+ if self.diff:
+ results['diff']['after'] = self.get_diff_state(image)
+ try:
+ results['diff']['after']['tags'].remove(name)
+ except ValueError:
+ pass
+
+ return results
+
+
+def main():
+ argument_spec = dict(
+ name=dict(type='str', required=True),
+ tag=dict(type='str', default='latest'),
+ force=dict(type='bool', default=False),
+ prune=dict(type='bool', default=True),
+ )
+
+ client = AnsibleDockerClient(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
+
+ try:
+ results = ImageRemover(client).absent()
+ client.module.exit_json(**results)
+ except DockerException as e:
+ client.fail('An unexpected Docker error occurred: {0}'.format(to_native(e)), exception=traceback.format_exc())
+ except RequestException as e:
+ client.fail(
+ 'An unexpected requests error occurred when trying to talk to the Docker daemon: {0}'.format(to_native(e)),
+ exception=traceback.format_exc())
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/docker/plugins/modules/docker_image_tag.py b/ansible_collections/community/docker/plugins/modules/docker_image_tag.py
new file mode 100644
index 000000000..c395a7fca
--- /dev/null
+++ b/ansible_collections/community/docker/plugins/modules/docker_image_tag.py
@@ -0,0 +1,273 @@
+#!/usr/bin/python
+#
+# Copyright (c) 2023, Felix Fontein <felix@fontein.de>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+
+DOCUMENTATION = '''
+---
+module: docker_image_tag
+
+short_description: Tag Docker images with new names and/or tags
+
+version_added: 3.6.0
+
+description:
+ - This module allows to tag Docker images with new names and/or tags.
+
+extends_documentation_fragment:
+ - community.docker.docker.api_documentation
+ - community.docker.attributes
+ - community.docker.attributes.actiongroup_docker
+
+attributes:
+ check_mode:
+ support: full
+ diff_mode:
+ support: full
+
+options:
+ name:
+ description:
+ - "Image name. Name format will be one of: C(name), C(repository/name), C(registry_server:port/name).
+ When pushing or pulling an image the name can optionally include the tag by appending C(:tag_name)."
+ - Note that image IDs (hashes) can also be used.
+ type: str
+ required: true
+ tag:
+ description:
+ - Tag for the image name O(name) that is to be tagged.
+ - If O(name)'s format is C(name:tag), then the tag value from O(name) will take precedence.
+ type: str
+ default: latest
+ repository:
+ description:
+ - List of new image names to tag the image as.
+ - Expects format C(repository:tag). If no tag is provided, will use the value of the O(tag) parameter if present, or V(latest).
+ type: list
+ elements: str
+ required: true
+ existing_images:
+ description:
+ - Defines the behavior if the image to be tagged already exists and is another image than the one identified by O(name) and O(tag).
+ - If set to V(keep), the tagged image is kept.
+ - If set to V(overwrite), the tagged image is overwritten by the specified one.
+ type: str
+ choices:
+ - keep
+ - overwrite
+ default: overwrite
+
+requirements:
+ - "Docker API >= 1.25"
+
+author:
+ - Felix Fontein (@felixfontein)
+
+seealso:
+ - module: community.docker.docker_image_push
+ - module: community.docker.docker_image_remove
+'''
+
+EXAMPLES = '''
+- name: Tag Python 3.12 image with two new names
+ community.docker.docker_image_tag:
+ name: python:3.12
+ repository:
+ - python-3:3.12
+ - local-registry:5000/python-3/3.12:latest
+'''
+
+RETURN = '''
+image:
+ description: Image inspection results for the affected image.
+ returned: success
+ type: dict
+ sample: {}
+tagged_images:
+ description:
+ - A list of images that got tagged.
+ returned: success
+ type: list
+ elements: str
+ sample:
+ - python-3:3.12
+'''
+
+import traceback
+
+from ansible.module_utils.common.text.converters import to_native
+from ansible.module_utils.common.text.formatters import human_to_bytes
+
+from ansible_collections.community.docker.plugins.module_utils.common_api import (
+ AnsibleDockerClient,
+ RequestException,
+)
+
+from ansible_collections.community.docker.plugins.module_utils.util import (
+ DockerBaseClass,
+ is_image_name_id,
+ is_valid_tag,
+)
+
+from ansible_collections.community.docker.plugins.module_utils._api.errors import DockerException
+from ansible_collections.community.docker.plugins.module_utils._api.utils.utils import (
+ parse_repository_tag,
+)
+
+
+def convert_to_bytes(value, module, name, unlimited_value=None):
+ if value is None:
+ return value
+ try:
+ if unlimited_value is not None and value in ('unlimited', str(unlimited_value)):
+ return unlimited_value
+ return human_to_bytes(value)
+ except ValueError as exc:
+ module.fail_json(msg='Failed to convert %s to bytes: %s' % (name, to_native(exc)))
+
+
+def image_info(name, tag, image):
+ result = dict(name=name, tag=tag)
+ if image:
+ result['id'] = image['Id']
+ else:
+ result['exists'] = False
+ return result
+
+
+class ImageTagger(DockerBaseClass):
+ def __init__(self, client):
+ super(ImageTagger, self).__init__()
+
+ self.client = client
+ parameters = self.client.module.params
+ self.check_mode = self.client.check_mode
+
+ self.name = parameters['name']
+ self.tag = parameters['tag']
+ if not is_valid_tag(self.tag, allow_empty=True):
+ self.fail('"{0}" is not a valid docker tag'.format(self.tag))
+
+ # If name contains a tag, it takes precedence over tag parameter.
+ if not is_image_name_id(self.name):
+ repo, repo_tag = parse_repository_tag(self.name)
+ if repo_tag:
+ self.name = repo
+ self.tag = repo_tag
+
+ self.keep_existing_images = parameters['existing_images'] == 'keep'
+
+ # Make sure names in repository are valid images, and add tag if needed
+ self.repositories = []
+ for i, repository in enumerate(parameters['repository']):
+ if is_image_name_id(repository):
+ self.fail("repository[%d] must not be an image ID; got: %s" % (i + 1, repository))
+ repo, repo_tag = parse_repository_tag(repository)
+ if not repo_tag:
+ repo_tag = parameters['tag']
+ elif not is_valid_tag(repo_tag, allow_empty=False):
+ self.fail("repository[%d] must not have a digest; got: %s" % (i + 1, repository))
+ self.repositories.append((repo, repo_tag))
+
+ def fail(self, msg):
+ self.client.fail(msg)
+
+ def tag_image(self, image, name, tag):
+ tagged_image = self.client.find_image(name=name, tag=tag)
+ if tagged_image:
+ # Idempotency checks
+ if tagged_image['Id'] == image['Id']:
+ return (
+ False,
+ "target image already exists (%s) and is as expected" % tagged_image['Id'],
+ tagged_image,
+ )
+ if self.keep_existing_images:
+ return (
+ False,
+ "target image already exists (%s) and is not as expected, but kept" % tagged_image['Id'],
+ tagged_image,
+ )
+ msg = "target image existed (%s) and was not as expected" % tagged_image['Id']
+ else:
+ msg = "target image did not exist"
+
+ if not self.check_mode:
+ try:
+ params = {
+ 'tag': tag,
+ 'repo': name,
+ 'force': True,
+ }
+ res = self.client._post(self.client._url('/images/{0}/tag', image['Id']), params=params)
+ self.client._raise_for_status(res)
+ if res.status_code != 201:
+ raise Exception("Tag operation failed.")
+ except Exception as exc:
+ self.fail("Error: failed to tag image as %s:%s - %s" % (name, tag, to_native(exc)))
+
+ return True, msg, tagged_image
+
+ def tag_images(self):
+ if is_image_name_id(self.name):
+ image = self.client.find_image_by_id(self.name, accept_missing_image=False)
+ else:
+ image = self.client.find_image(name=self.name, tag=self.tag)
+ if not image:
+ self.fail("Cannot find image %s:%s" % (self.name, self.tag))
+
+ before = []
+ after = []
+ tagged_images = []
+ results = dict(
+ changed=False,
+ actions=[],
+ image=image,
+ tagged_images=tagged_images,
+ diff=dict(before=dict(images=before), after=dict(images=after)),
+ )
+ for repository, tag in self.repositories:
+ tagged, msg, old_image = self.tag_image(image, repository, tag)
+ before.append(image_info(repository, tag, old_image))
+ after.append(image_info(repository, tag, image if tagged else old_image))
+ if tagged:
+ results['changed'] = True
+ results['actions'].append('Tagged image %s as %s:%s: %s' % (image['Id'], repository, tag, msg))
+ tagged_images.append('%s:%s' % (repository, tag))
+ else:
+ results['actions'].append('Not tagged image %s as %s:%s: %s' % (image['Id'], repository, tag, msg))
+
+ return results
+
+
+def main():
+ argument_spec = dict(
+ name=dict(type='str', required=True),
+ tag=dict(type='str', default='latest'),
+ repository=dict(type='list', elements='str', required=True),
+ existing_images=dict(type='str', choices=['keep', 'overwrite'], default='overwrite'),
+ )
+
+ client = AnsibleDockerClient(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
+
+ try:
+ results = ImageTagger(client).tag_images()
+ client.module.exit_json(**results)
+ except DockerException as e:
+ client.fail('An unexpected Docker error occurred: {0}'.format(to_native(e)), exception=traceback.format_exc())
+ except RequestException as e:
+ client.fail(
+ 'An unexpected requests error occurred when trying to talk to the Docker daemon: {0}'.format(to_native(e)),
+ exception=traceback.format_exc())
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/docker/plugins/modules/docker_login.py b/ansible_collections/community/docker/plugins/modules/docker_login.py
index 360dd5785..bb4e00b87 100644
--- a/ansible_collections/community/docker/plugins/modules/docker_login.py
+++ b/ansible_collections/community/docker/plugins/modules/docker_login.py
@@ -46,12 +46,12 @@ options:
username:
description:
- The username for the registry account.
- - Required when I(state) is C(present).
+ - Required when O(state=present).
type: str
password:
description:
- The plaintext password for the registry account.
- - Required when I(state) is C(present).
+ - Required when O(state=present).
type: str
reauthorize:
description:
@@ -69,7 +69,7 @@ options:
- dockercfg_path
state:
description:
- - This controls the current state of the user. C(present) will login in a user, C(absent) will log them out.
+ - This controls the current state of the user. V(present) will login in a user, V(absent) will log them out.
- To logout you only need the registry server, which defaults to DockerHub.
- Before 2.1 you could ONLY log in.
- Docker does not support 'logout' with a custom config file.
@@ -112,7 +112,7 @@ EXAMPLES = '''
RETURN = '''
login_results:
description: Results from the login.
- returned: when I(state=present)
+ returned: when O(state=present)
type: dict
sample: {
"serveraddress": "localhost:5000",
@@ -261,7 +261,7 @@ class LoginManager(DockerBaseClass):
def run(self):
'''
- Do the actuall work of this task here. This allows instantiation for partial
+ Do the actual work of this task here. This allows instantiation for partial
testing.
'''
diff --git a/ansible_collections/community/docker/plugins/modules/docker_network.py b/ansible_collections/community/docker/plugins/modules/docker_network.py
index db9323636..5670ceea0 100644
--- a/ansible_collections/community/docker/plugins/modules/docker_network.py
+++ b/ansible_collections/community/docker/plugins/modules/docker_network.py
@@ -61,8 +61,8 @@ options:
force:
description:
- - With state C(absent) forces disconnecting all containers from the
- network prior to deleting the network. With state C(present) will
+ - With state V(absent) forces disconnecting all containers from the
+ network prior to deleting the network. With state V(present) will
disconnect all containers, delete the network and re-create the
network.
- This option is required if you have changed the IPAM or driver options
@@ -73,7 +73,7 @@ options:
appends:
description:
- By default the connected list is canonical, meaning containers not on the list are removed from the network.
- - Use I(appends) to leave existing containers connected.
+ - Use O(appends) to leave existing containers connected.
type: bool
default: false
aliases:
@@ -98,7 +98,7 @@ options:
description:
- List of IPAM config blocks. Consult
L(Docker docs,https://docs.docker.com/compose/compose-file/compose-file-v2/#ipam) for valid options and values.
- Note that I(iprange) is spelled differently here (we use the notation from the Docker SDK for Python).
+ Note that O(ipam_config[].iprange) is spelled differently here (we use the notation from the Docker SDK for Python).
type: list
elements: dict
suboptions:
@@ -121,14 +121,14 @@ options:
state:
description:
- - C(absent) deletes the network. If a network has connected containers, it
- cannot be deleted. Use the I(force) option to disconnect all containers
+ - V(absent) deletes the network. If a network has connected containers, it
+ cannot be deleted. Use the O(force) option to disconnect all containers
and delete the network.
- - C(present) creates the network, if it does not already exist with the
+ - V(present) creates the network, if it does not already exist with the
specified parameters, and connects the list of containers provided via
the connected parameter. Containers not on the list will be disconnected.
An empty list will leave no containers connected to the network. Use the
- I(appends) option to leave existing containers connected. Use the I(force)
+ O(appends) option to leave existing containers connected. Use the O(force)
options to force re-creation of the network.
type: str
default: present
@@ -163,7 +163,7 @@ options:
notes:
- When network options are changed, the module disconnects all containers from the network, deletes the network, and re-creates the network.
- It does not try to reconnect containers, except the ones listed in (I(connected), and even for these, it does not consider specific
+ It does not try to reconnect containers, except the ones listed in (O(connected), and even for these, it does not consider specific
connection options like fixed IP addresses or MAC addresses. If you need more control over how the containers are connected to the
network, loop the M(community.docker.docker_container) module to loop over your containers to make sure they are connected properly.
- The module does not support Docker Swarm. This means that it will not try to disconnect or reconnect services. If services are connected to the
diff --git a/ansible_collections/community/docker/plugins/modules/docker_network_info.py b/ansible_collections/community/docker/plugins/modules/docker_network_info.py
index 9818baad5..c2c445bd1 100644
--- a/ansible_collections/community/docker/plugins/modules/docker_network_info.py
+++ b/ansible_collections/community/docker/plugins/modules/docker_network_info.py
@@ -66,7 +66,7 @@ exists:
network:
description:
- Facts representing the current state of the network. Matches the docker inspection output.
- - Will be C(none) if network does not exist.
+ - Will be V(none) if network does not exist.
returned: always
type: dict
sample: {
diff --git a/ansible_collections/community/docker/plugins/modules/docker_node.py b/ansible_collections/community/docker/plugins/modules/docker_node.py
index d097b07f7..bfa369e98 100644
--- a/ansible_collections/community/docker/plugins/modules/docker_node.py
+++ b/ansible_collections/community/docker/plugins/modules/docker_node.py
@@ -39,19 +39,19 @@ options:
labels:
description:
- User-defined key/value metadata that will be assigned as node attribute.
- - Label operations in this module apply to the docker swarm node specified by I(hostname).
+ - Label operations in this module apply to the docker swarm node specified by O(hostname).
Use M(community.docker.docker_swarm) module to add/modify/remove swarm cluster labels.
- The actual state of labels assigned to the node when module completes its work depends on
- I(labels_state) and I(labels_to_remove) parameters values. See description below.
+ O(labels_state) and O(labels_to_remove) parameters values. See description below.
type: dict
labels_state:
description:
- - It defines the operation on the labels assigned to node and labels specified in I(labels) option.
- - Set to C(merge) to combine labels provided in I(labels) with those already assigned to the node.
+ - It defines the operation on the labels assigned to node and labels specified in O(labels) option.
+ - Set to V(merge) to combine labels provided in O(labels) with those already assigned to the node.
If no labels are assigned then it will add listed labels. For labels that are already assigned
- to the node, it will update their values. The labels not specified in I(labels) will remain unchanged.
- If I(labels) is empty then no changes will be made.
- - Set to C(replace) to replace all assigned labels with provided ones. If I(labels) is empty then
+ to the node, it will update their values. The labels not specified in O(labels) will remain unchanged.
+ If O(labels) is empty then no changes will be made.
+ - Set to V(replace) to replace all assigned labels with provided ones. If O(labels) is empty then
all labels assigned to the node will be removed.
type: str
default: 'merge'
@@ -63,10 +63,10 @@ options:
- List of labels that will be removed from the node configuration. The list has to contain only label
names, not their values.
- If the label provided on the list is not assigned to the node, the entry is ignored.
- - If the label is both on the I(labels_to_remove) and I(labels), then value provided in I(labels) remains
+ - If the label is both on the O(labels_to_remove) and O(labels), then value provided in O(labels) remains
assigned to the node.
- - If I(labels_state) is C(replace) and I(labels) is not provided or empty then all labels assigned to
- node are removed and I(labels_to_remove) is ignored.
+ - If O(labels_state=replace) and O(labels) is not provided or empty then all labels assigned to
+ node are removed and O(labels_to_remove) is ignored.
type: list
elements: str
availability:
diff --git a/ansible_collections/community/docker/plugins/modules/docker_node_info.py b/ansible_collections/community/docker/plugins/modules/docker_node_info.py
index d943db31b..c64de0f8d 100644
--- a/ansible_collections/community/docker/plugins/modules/docker_node_info.py
+++ b/ansible_collections/community/docker/plugins/modules/docker_node_info.py
@@ -33,14 +33,14 @@ options:
- The list of nodes names to inspect.
- If empty then return information of all nodes in Swarm cluster.
- When identifying the node use either the hostname of the node (as registered in Swarm) or node ID.
- - If I(self) is C(true) then this parameter is ignored.
+ - If O(self=true) then this parameter is ignored.
type: list
elements: str
self:
description:
- - If C(true), queries the node (that is, the docker daemon) the module communicates with.
- - If C(true) then I(name) is ignored.
- - If C(false) then query depends on I(name) presence and value.
+ - If V(true), queries the node (that is, the docker daemon) the module communicates with.
+ - If V(true) then O(name) is ignored.
+ - If V(false) then query depends on O(name) presence and value.
type: bool
default: false
@@ -79,8 +79,8 @@ RETURN = '''
nodes:
description:
- Facts representing the current state of the nodes. Matches the C(docker node inspect) output.
- - Can contain multiple entries if more than one node provided in I(name), or I(name) is not provided.
- - If I(name) contains a list of nodes, the output will provide information on all nodes registered
+ - Can contain multiple entries if more than one node provided in O(name), or O(name) is not provided.
+ - If O(name) contains a list of nodes, the output will provide information on all nodes registered
at the swarm, including nodes that left the swarm but have not been removed from the cluster on swarm
managers and nodes that are unreachable.
returned: always
diff --git a/ansible_collections/community/docker/plugins/modules/docker_plugin.py b/ansible_collections/community/docker/plugins/modules/docker_plugin.py
index 9bb850665..e7242e8eb 100644
--- a/ansible_collections/community/docker/plugins/modules/docker_plugin.py
+++ b/ansible_collections/community/docker/plugins/modules/docker_plugin.py
@@ -17,6 +17,8 @@ version_added: 1.3.0
description:
- This module allows to install, delete, enable and disable Docker plugins.
- Performs largely the same function as the C(docker plugin) CLI subcommand.
+notes:
+ - The C(--grant-all-permissions) CLI flag is true by default in this module.
extends_documentation_fragment:
- community.docker.docker.api_documentation
@@ -38,10 +40,10 @@ options:
state:
description:
- - C(absent) remove the plugin.
- - C(present) install the plugin, if it does not already exist.
- - C(enable) enable the plugin.
- - C(disable) disable the plugin.
+ - V(absent) remove the plugin.
+ - V(present) install the plugin, if it does not already exist.
+ - V(enable) enable the plugin.
+ - V(disable) disable the plugin.
default: present
choices:
- absent
@@ -121,7 +123,7 @@ plugin:
actions:
description:
- List of actions performed during task execution.
- returned: when I(state!=absent)
+ returned: when O(state) is not V(absent)
type: list
'''
diff --git a/ansible_collections/community/docker/plugins/modules/docker_prune.py b/ansible_collections/community/docker/plugins/modules/docker_prune.py
index 1557f85a4..1dfbf290e 100644
--- a/ansible_collections/community/docker/plugins/modules/docker_prune.py
+++ b/ansible_collections/community/docker/plugins/modules/docker_prune.py
@@ -124,14 +124,14 @@ RETURN = '''
containers:
description:
- List of IDs of deleted containers.
- returned: I(containers) is C(true)
+ returned: O(containers=true)
type: list
elements: str
sample: []
containers_space_reclaimed:
description:
- Amount of reclaimed disk space from container pruning in bytes.
- returned: I(containers) is C(true)
+ returned: O(containers=true)
type: int
sample: 0
@@ -139,14 +139,14 @@ containers_space_reclaimed:
images:
description:
- List of IDs of deleted images.
- returned: I(images) is C(true)
+ returned: O(images=true)
type: list
elements: str
sample: []
images_space_reclaimed:
description:
- Amount of reclaimed disk space from image pruning in bytes.
- returned: I(images) is C(true)
+ returned: O(images=true)
type: int
sample: 0
@@ -154,7 +154,7 @@ images_space_reclaimed:
networks:
description:
- List of IDs of deleted networks.
- returned: I(networks) is C(true)
+ returned: O(networks=true)
type: list
elements: str
sample: []
@@ -163,14 +163,14 @@ networks:
volumes:
description:
- List of IDs of deleted volumes.
- returned: I(volumes) is C(true)
+ returned: O(volumes=true)
type: list
elements: str
sample: []
volumes_space_reclaimed:
description:
- Amount of reclaimed disk space from volumes pruning in bytes.
- returned: I(volumes) is C(true)
+ returned: O(volumes=true)
type: int
sample: 0
@@ -178,7 +178,7 @@ volumes_space_reclaimed:
builder_cache_space_reclaimed:
description:
- Amount of reclaimed disk space from builder cache pruning in bytes.
- returned: I(builder_cache) is C(true)
+ returned: O(builder_cache=true)
type: int
sample: 0
'''
diff --git a/ansible_collections/community/docker/plugins/modules/docker_secret.py b/ansible_collections/community/docker/plugins/modules/docker_secret.py
index 546756a49..cf4324541 100644
--- a/ansible_collections/community/docker/plugins/modules/docker_secret.py
+++ b/ansible_collections/community/docker/plugins/modules/docker_secret.py
@@ -18,7 +18,7 @@ description:
- Create and remove Docker secrets in a Swarm environment. Similar to C(docker secret create) and C(docker secret rm).
- Adds to the metadata of new secrets C(ansible_key), an encrypted hash representation of the data, which is then used
in future runs to test if a secret has changed. If C(ansible_key) is not present, then a secret will not be updated
- unless the I(force) option is set.
+ unless the O(force) option is set.
- Updates to secrets are performed by removing the secret and creating it again.
extends_documentation_fragment:
@@ -37,20 +37,20 @@ options:
data:
description:
- The value of the secret.
- - Mutually exclusive with I(data_src). One of I(data) and I(data_src) is required if I(state=present).
+ - Mutually exclusive with O(data_src). One of O(data) and O(data_src) is required if O(state=present).
type: str
data_is_b64:
description:
- - If set to C(true), the data is assumed to be Base64 encoded and will be
+ - If set to V(true), the data is assumed to be Base64 encoded and will be
decoded before being used.
- - To use binary I(data), it is better to keep it Base64 encoded and let it
+ - To use binary O(data), it is better to keep it Base64 encoded and let it
be decoded by this option.
type: bool
default: false
data_src:
description:
- The file on the target from which to read the secret.
- - Mutually exclusive with I(data). One of I(data) and I(data_src) is required if I(state=present).
+ - Mutually exclusive with O(data). One of O(data) and O(data_src) is required if O(state=present).
type: path
version_added: 1.10.0
labels:
@@ -60,22 +60,22 @@ options:
type: dict
force:
description:
- - Use with state C(present) to always remove and recreate an existing secret.
- - If C(true), an existing secret will be replaced, even if it has not changed.
+ - Use with O(state=present) to always remove and recreate an existing secret.
+ - If V(true), an existing secret will be replaced, even if it has not changed.
type: bool
default: false
rolling_versions:
description:
- - If set to C(true), secrets are created with an increasing version number appended to their name.
+ - If set to V(true), secrets are created with an increasing version number appended to their name.
- Adds a label containing the version number to the managed secrets with the name C(ansible_version).
type: bool
default: false
version_added: 2.2.0
versions_to_keep:
description:
- - When using I(rolling_versions), the number of old versions of the secret to keep.
+ - When using O(rolling_versions), the number of old versions of the secret to keep.
- Extraneous old secrets are deleted after the new one is created.
- - Set to C(-1) to keep everything or to C(0) or C(1) to keep only the current one.
+ - Set to V(-1) to keep everything or to V(0) or V(1) to keep only the current one.
type: int
default: 5
version_added: 2.2.0
@@ -86,7 +86,7 @@ options:
required: true
state:
description:
- - Set to C(present), if the secret should exist, and C(absent), if it should not.
+ - Set to V(present), if the secret should exist, and V(absent), if it should not.
type: str
default: present
choices:
@@ -175,13 +175,13 @@ RETURN = '''
secret_id:
description:
- The ID assigned by Docker to the secret object.
- returned: success and I(state) is C(present)
+ returned: success and O(state=present)
type: str
sample: 'hzehrmyjigmcp2gb6nlhmjqcv'
secret_name:
description:
- The name of the created secret object.
- returned: success and I(state) is C(present)
+ returned: success and O(state=present)
type: str
sample: 'awesome_secret'
version_added: 2.2.0
diff --git a/ansible_collections/community/docker/plugins/modules/docker_stack.py b/ansible_collections/community/docker/plugins/modules/docker_stack.py
index 98f4c3ad9..728bc5cfc 100644
--- a/ansible_collections/community/docker/plugins/modules/docker_stack.py
+++ b/ansible_collections/community/docker/plugins/modules/docker_stack.py
@@ -18,12 +18,16 @@ description:
- Manage docker stacks using the C(docker stack) command
on the target node (see examples).
extends_documentation_fragment:
+ - community.docker.docker.cli_documentation
- community.docker.attributes
+ - community.docker.attributes.actiongroup_docker
attributes:
check_mode:
support: none
diff_mode:
support: none
+ action_group:
+ version_added: 3.6.0
options:
name:
description:
@@ -68,8 +72,8 @@ options:
choices: ["always", "changed", "never"]
absent_retries:
description:
- - If C(>0) and I(state) is C(absent) the module will retry up to
- I(absent_retries) times to delete the stack until all the
+ - If larger than V(0) and O(state=absent) the module will retry up to
+ O(absent_retries) times to delete the stack until all the
resources have been effectively deleted.
If the last try still reports the stack as not completely
removed the module will fail.
@@ -77,11 +81,32 @@ options:
default: 0
absent_retries_interval:
description:
- - Interval in seconds between consecutive I(absent_retries).
+ - Interval in seconds between consecutive O(absent_retries).
type: int
default: 1
+ docker_cli:
+ version_added: 3.6.0
+ docker_host:
+ version_added: 3.6.0
+ tls_hostname:
+ version_added: 3.6.0
+ api_version:
+ version_added: 3.6.0
+ ca_path:
+ version_added: 3.6.0
+ client_cert:
+ version_added: 3.6.0
+ client_key:
+ version_added: 3.6.0
+ tls:
+ version_added: 3.6.0
+ validate_certs:
+ version_added: 3.6.0
+ cli_context:
+ version_added: 3.6.0
requirements:
+ - Docker CLI tool C(docker)
- jsondiff
- pyyaml
'''
@@ -128,10 +153,20 @@ EXAMPLES = '''
import json
+import os
import tempfile
+import traceback
+
from ansible.module_utils.six import string_types
from time import sleep
+from ansible.module_utils.common.text.converters import to_native
+
+from ansible_collections.community.docker.plugins.module_utils.common_cli import (
+ AnsibleModuleDockerClient,
+ DockerException,
+)
+
try:
from jsondiff import diff as json_diff
HAS_JSONDIFF = True
@@ -144,28 +179,16 @@ try:
except ImportError:
HAS_YAML = False
-from ansible.module_utils.basic import AnsibleModule, os
-
-def docker_stack_services(module, stack_name):
- docker_bin = module.get_bin_path('docker', required=True)
- rc, out, err = module.run_command([docker_bin,
- "stack",
- "services",
- stack_name,
- "--format",
- "{{.Name}}"])
- if err == "Nothing found in stack: %s\n" % stack_name:
+def docker_stack_services(client, stack_name):
+ rc, out, err = client.call_cli("stack", "services", stack_name, "--format", "{{.Name}}")
+ if to_native(err) == "Nothing found in stack: %s\n" % stack_name:
return []
- return out.strip().split('\n')
+ return to_native(out).strip().split('\n')
-def docker_service_inspect(module, service_name):
- docker_bin = module.get_bin_path('docker', required=True)
- rc, out, err = module.run_command([docker_bin,
- "service",
- "inspect",
- service_name])
+def docker_service_inspect(client, service_name):
+ rc, out, err = client.call_cli("service", "inspect", service_name)
if rc != 0:
return None
else:
@@ -173,45 +196,43 @@ def docker_service_inspect(module, service_name):
return ret
-def docker_stack_deploy(module, stack_name, compose_files):
- docker_bin = module.get_bin_path('docker', required=True)
- command = [docker_bin, "stack", "deploy"]
- if module.params["prune"]:
+def docker_stack_deploy(client, stack_name, compose_files):
+ command = ["stack", "deploy"]
+ if client.module.params["prune"]:
command += ["--prune"]
- if module.params["with_registry_auth"]:
+ if client.module.params["with_registry_auth"]:
command += ["--with-registry-auth"]
- if module.params["resolve_image"]:
+ if client.module.params["resolve_image"]:
command += ["--resolve-image",
- module.params["resolve_image"]]
+ client.module.params["resolve_image"]]
for compose_file in compose_files:
command += ["--compose-file",
compose_file]
command += [stack_name]
- return module.run_command(command)
+ rc, out, err = client.call_cli(*command)
+ return rc, to_native(out), to_native(err)
-def docker_stack_inspect(module, stack_name):
+def docker_stack_inspect(client, stack_name):
ret = {}
- for service_name in docker_stack_services(module, stack_name):
- ret[service_name] = docker_service_inspect(module, service_name)
+ for service_name in docker_stack_services(client, stack_name):
+ ret[service_name] = docker_service_inspect(client, service_name)
return ret
-def docker_stack_rm(module, stack_name, retries, interval):
- docker_bin = module.get_bin_path('docker', required=True)
- command = [docker_bin, "stack", "rm", stack_name]
-
- rc, out, err = module.run_command(command)
+def docker_stack_rm(client, stack_name, retries, interval):
+ command = ["stack", "rm", stack_name]
+ rc, out, err = client.call_cli(*command)
- while err != "Nothing found in stack: %s\n" % stack_name and retries > 0:
+ while to_native(err) != "Nothing found in stack: %s\n" % stack_name and retries > 0:
sleep(interval)
retries = retries - 1
- rc, out, err = module.run_command(command)
- return rc, out, err
+ rc, out, err = client.call_cli(*command)
+ return rc, to_native(out), to_native(err)
def main():
- module = AnsibleModule(
+ client = AnsibleModuleDockerClient(
argument_spec={
'name': dict(type='str', required=True),
'compose': dict(type='list', elements='raw', default=[]),
@@ -222,87 +243,97 @@ def main():
'absent_retries': dict(type='int', default=0),
'absent_retries_interval': dict(type='int', default=1)
},
- supports_check_mode=False
+ supports_check_mode=False,
)
if not HAS_JSONDIFF:
- return module.fail_json(msg="jsondiff is not installed, try 'pip install jsondiff'")
+ return client.fail("jsondiff is not installed, try 'pip install jsondiff'")
if not HAS_YAML:
- return module.fail_json(msg="yaml is not installed, try 'pip install pyyaml'")
-
- state = module.params['state']
- compose = module.params['compose']
- name = module.params['name']
- absent_retries = module.params['absent_retries']
- absent_retries_interval = module.params['absent_retries_interval']
-
- if state == 'present':
- if not compose:
- module.fail_json(msg=("compose parameter must be a list "
- "containing at least one element"))
-
- compose_files = []
- for i, compose_def in enumerate(compose):
- if isinstance(compose_def, dict):
- compose_file_fd, compose_file = tempfile.mkstemp()
- module.add_cleanup_file(compose_file)
- with os.fdopen(compose_file_fd, 'w') as stack_file:
- compose_files.append(compose_file)
- stack_file.write(yaml_dump(compose_def))
- elif isinstance(compose_def, string_types):
- compose_files.append(compose_def)
- else:
- module.fail_json(msg="compose element '%s' must be a string or a dictionary" % compose_def)
-
- before_stack_services = docker_stack_inspect(module, name)
-
- rc, out, err = docker_stack_deploy(module, name, compose_files)
-
- after_stack_services = docker_stack_inspect(module, name)
-
- if rc != 0:
- module.fail_json(msg="docker stack up deploy command failed",
- rc=rc,
- stdout=out, stderr=err)
-
- before_after_differences = json_diff(before_stack_services,
- after_stack_services)
- for k in before_after_differences.keys():
- if isinstance(before_after_differences[k], dict):
- before_after_differences[k].pop('UpdatedAt', None)
- before_after_differences[k].pop('Version', None)
- if not list(before_after_differences[k].keys()):
- before_after_differences.pop(k)
-
- if not before_after_differences:
- module.exit_json(
- changed=False,
- rc=rc,
- stdout=out,
- stderr=err)
- else:
- module.exit_json(
- changed=True,
- rc=rc,
- stdout=out,
- stderr=err,
- stack_spec_diff=json_diff(before_stack_services,
- after_stack_services,
- dump=True))
+ return client.fail("yaml is not installed, try 'pip install pyyaml'")
+
+ try:
+ state = client.module.params['state']
+ compose = client.module.params['compose']
+ name = client.module.params['name']
+ absent_retries = client.module.params['absent_retries']
+ absent_retries_interval = client.module.params['absent_retries_interval']
+
+ if state == 'present':
+ if not compose:
+ client.fail("compose parameter must be a list containing at least one element")
+
+ compose_files = []
+ for i, compose_def in enumerate(compose):
+ if isinstance(compose_def, dict):
+ compose_file_fd, compose_file = tempfile.mkstemp()
+ client.module.add_cleanup_file(compose_file)
+ with os.fdopen(compose_file_fd, 'w') as stack_file:
+ compose_files.append(compose_file)
+ stack_file.write(yaml_dump(compose_def))
+ elif isinstance(compose_def, string_types):
+ compose_files.append(compose_def)
+ else:
+ client.fail("compose element '%s' must be a string or a dictionary" % compose_def)
+
+ before_stack_services = docker_stack_inspect(client, name)
+
+ rc, out, err = docker_stack_deploy(client, name, compose_files)
+
+ after_stack_services = docker_stack_inspect(client, name)
- else:
- if docker_stack_services(module, name):
- rc, out, err = docker_stack_rm(module, name, absent_retries, absent_retries_interval)
if rc != 0:
- module.fail_json(msg="'docker stack down' command failed",
- rc=rc,
- stdout=out, stderr=err)
+ client.fail("docker stack up deploy command failed", rc=rc, stdout=out, stderr=err)
+
+ before_after_differences = json_diff(before_stack_services, after_stack_services)
+ for k in before_after_differences.keys():
+ if isinstance(before_after_differences[k], dict):
+ before_after_differences[k].pop('UpdatedAt', None)
+ before_after_differences[k].pop('Version', None)
+ if not list(before_after_differences[k].keys()):
+ before_after_differences.pop(k)
+
+ if not before_after_differences:
+ client.module.exit_json(
+ changed=False,
+ rc=rc,
+ stdout=out,
+ stderr=err,
+ )
else:
- module.exit_json(changed=True,
- msg=out, rc=rc,
- stdout=out, stderr=err)
- module.exit_json(changed=False)
+ client.module.exit_json(
+ changed=True,
+ rc=rc,
+ stdout=out,
+ stderr=err,
+ stack_spec_diff=json_diff(
+ before_stack_services,
+ after_stack_services,
+ dump=True,
+ ),
+ )
+
+ else:
+ if docker_stack_services(client, name):
+ rc, out, err = docker_stack_rm(client, name, absent_retries, absent_retries_interval)
+ if rc != 0:
+ client.module.fail_json(
+ msg="'docker stack down' command failed",
+ rc=rc,
+ stdout=out,
+ stderr=err,
+ )
+ else:
+ client.module.exit_json(
+ changed=True,
+ msg=out,
+ rc=rc,
+ stdout=out,
+ stderr=err,
+ )
+ client.module.exit_json(changed=False)
+ except DockerException as e:
+ client.fail('An unexpected Docker error occurred: {0}'.format(to_native(e)), exception=traceback.format_exc())
if __name__ == "__main__":
diff --git a/ansible_collections/community/docker/plugins/modules/docker_stack_info.py b/ansible_collections/community/docker/plugins/modules/docker_stack_info.py
index bf3bfbdbe..21ce20dd6 100644
--- a/ansible_collections/community/docker/plugins/modules/docker_stack_info.py
+++ b/ansible_collections/community/docker/plugins/modules/docker_stack_info.py
@@ -13,20 +13,52 @@ DOCUMENTATION = '''
---
module: docker_stack_info
author: "Jose Angel Munoz (@imjoseangel)"
-short_description: Return information on a docker stack
+short_description: Return information on all docker stacks
description:
- Retrieve information on docker stacks using the C(docker stack) command
on the target node (see examples).
+requirements:
+ - Docker CLI tool C(docker)
extends_documentation_fragment:
+ - community.docker.docker.cli_documentation
- community.docker.attributes
+ - community.docker.attributes.actiongroup_docker
- community.docker.attributes.info_module
+attributes:
+ action_group:
+ version_added: 3.6.0
+options:
+ docker_cli:
+ version_added: 3.6.0
+ docker_host:
+ version_added: 3.6.0
+ tls_hostname:
+ version_added: 3.6.0
+ api_version:
+ version_added: 3.6.0
+ ca_path:
+ version_added: 3.6.0
+ client_cert:
+ version_added: 3.6.0
+ client_key:
+ version_added: 3.6.0
+ tls:
+ version_added: 3.6.0
+ validate_certs:
+ version_added: 3.6.0
+ cli_context:
+ version_added: 3.6.0
+seealso:
+ - module: community.docker.docker_stack_task_info
+ description: >-
+ To retrieve detailed information about the services under a specific
+ stack use the M(community.docker.docker_stack_task_info) module.
'''
RETURN = '''
results:
- description: |
- List of dictionaries containing the list of stacks or tasks associated
- to a stack name.
+ description:
+ - List of dictionaries containing the list of stacks on the target node
sample:
- {"name":"grafana","namespace":"default","orchestrator":"Kubernetes","services":"2"}
returned: always
@@ -45,7 +77,14 @@ EXAMPLES = '''
'''
import json
-from ansible.module_utils.basic import AnsibleModule
+import traceback
+
+from ansible.module_utils.common.text.converters import to_native
+
+from ansible_collections.community.docker.plugins.module_utils.common_cli import (
+ AnsibleModuleDockerClient,
+ DockerException,
+)
def docker_stack_list(module):
@@ -57,31 +96,23 @@ def docker_stack_list(module):
def main():
- module = AnsibleModule(
+ client = AnsibleModuleDockerClient(
argument_spec={
},
- supports_check_mode=True
+ supports_check_mode=True,
)
- rc, out, err = docker_stack_list(module)
-
- if rc != 0:
- module.fail_json(msg="Error running docker stack. {0}".format(err),
- rc=rc, stdout=out, stderr=err)
- else:
- if out:
- ret = list(
- json.loads(outitem)
- for outitem in out.splitlines())
-
- else:
- ret = []
-
- module.exit_json(changed=False,
- rc=rc,
- stdout=out,
- stderr=err,
- results=ret)
+ try:
+ rc, ret, stderr = client.call_cli_json_stream('stack', 'ls', '--format={{json .}}', check_rc=True)
+ client.module.exit_json(
+ changed=False,
+ rc=rc,
+ stdout='\n'.join([json.dumps(entry) for entry in ret]),
+ stderr=to_native(stderr).strip(),
+ results=ret,
+ )
+ except DockerException as e:
+ client.fail('An unexpected Docker error occurred: {0}'.format(to_native(e)), exception=traceback.format_exc())
if __name__ == "__main__":
diff --git a/ansible_collections/community/docker/plugins/modules/docker_stack_task_info.py b/ansible_collections/community/docker/plugins/modules/docker_stack_task_info.py
index e3693bc54..72076310a 100644
--- a/ansible_collections/community/docker/plugins/modules/docker_stack_task_info.py
+++ b/ansible_collections/community/docker/plugins/modules/docker_stack_task_info.py
@@ -18,23 +18,50 @@ description:
- Retrieve information on docker stacks tasks using the C(docker stack) command
on the target node (see examples).
extends_documentation_fragment:
+ - community.docker.docker.cli_documentation
- community.docker.attributes
+ - community.docker.attributes.actiongroup_docker
- community.docker.attributes.info_module
+attributes:
+ action_group:
+ version_added: 3.6.0
options:
name:
description:
- Stack name.
type: str
required: true
+ docker_cli:
+ version_added: 3.6.0
+ docker_host:
+ version_added: 3.6.0
+ tls_hostname:
+ version_added: 3.6.0
+ api_version:
+ version_added: 3.6.0
+ ca_path:
+ version_added: 3.6.0
+ client_cert:
+ version_added: 3.6.0
+ client_key:
+ version_added: 3.6.0
+ tls:
+ version_added: 3.6.0
+ validate_certs:
+ version_added: 3.6.0
+ cli_context:
+ version_added: 3.6.0
+requirements:
+ - Docker CLI tool C(docker)
'''
RETURN = '''
results:
- description: |
- List of dictionaries containing the list of tasks associated
- to a stack name.
- sample: >
- [{"CurrentState":"Running","DesiredState":"Running","Error":"","ID":"7wqv6m02ugkw","Image":"busybox","Name":"test_stack.1","Node":"swarm","Ports":""}]
+ description:
+ - List of dictionaries containing the list of tasks associated
+ to a stack name.
+ sample:
+ - {"CurrentState":"Running","DesiredState":"Running","Error":"","ID":"7wqv6m02ugkw","Image":"busybox","Name":"test_stack.1","Node":"swarm","Ports":""}
returned: always
type: list
elements: dict
@@ -52,7 +79,14 @@ EXAMPLES = '''
'''
import json
-from ansible.module_utils.basic import AnsibleModule
+import traceback
+
+from ansible.module_utils.common.text.converters import to_native
+
+from ansible_collections.community.docker.plugins.module_utils.common_cli import (
+ AnsibleModuleDockerClient,
+ DockerException,
+)
def docker_stack_task(module, stack_name):
@@ -64,34 +98,25 @@ def docker_stack_task(module, stack_name):
def main():
- module = AnsibleModule(
+ client = AnsibleModuleDockerClient(
argument_spec={
'name': dict(type='str', required=True)
},
- supports_check_mode=True
+ supports_check_mode=True,
)
- name = module.params['name']
-
- rc, out, err = docker_stack_task(module, name)
-
- if rc != 0:
- module.fail_json(msg="Error running docker stack. {0}".format(err),
- rc=rc, stdout=out, stderr=err)
- else:
- if out:
- ret = list(
- json.loads(outitem)
- for outitem in out.splitlines())
-
- else:
- ret = []
-
- module.exit_json(changed=False,
- rc=rc,
- stdout=out,
- stderr=err,
- results=ret)
+ try:
+ name = client.module.params['name']
+ rc, ret, stderr = client.call_cli_json_stream('stack', 'ps', name, '--format={{json .}}', check_rc=True)
+ client.module.exit_json(
+ changed=False,
+ rc=rc,
+ stdout='\n'.join([json.dumps(entry) for entry in ret]),
+ stderr=to_native(stderr).strip(),
+ results=ret,
+ )
+ except DockerException as e:
+ client.fail('An unexpected Docker error occurred: {0}'.format(to_native(e)), exception=traceback.format_exc())
if __name__ == "__main__":
diff --git a/ansible_collections/community/docker/plugins/modules/docker_swarm.py b/ansible_collections/community/docker/plugins/modules/docker_swarm.py
index 69b88f583..dc04c0a40 100644
--- a/ansible_collections/community/docker/plugins/modules/docker_swarm.py
+++ b/ansible_collections/community/docker/plugins/modules/docker_swarm.py
@@ -32,11 +32,11 @@ options:
description:
- Externally reachable address advertised to other nodes.
- This can either be an address/port combination
- in the form C(192.168.1.1:4567), or an interface followed by a
- port number, like C(eth0:4567).
+ in the form V(192.168.1.1:4567), or an interface followed by a
+ port number, like V(eth0:4567).
- If the port number is omitted,
the port number from the listen address is used.
- - If I(advertise_addr) is not specified, it will be automatically
+ - If O(advertise_addr) is not specified, it will be automatically
detected when possible.
- Only used when swarm is initialised or joined. Because of this it's not
considered for idempotency checking.
@@ -60,8 +60,8 @@ options:
description:
- Listen address used for inter-manager communication.
- This can either be an address/port combination in the form
- C(192.168.1.1:4567), or an interface followed by a port number,
- like C(eth0:4567).
+ V(192.168.1.1:4567), or an interface followed by a port number,
+ like V(eth0:4567).
- If the port number is omitted, the default swarm listening port
is used.
- Only used when swarm is initialised or joined. Because of this it's not
@@ -70,16 +70,16 @@ options:
default: 0.0.0.0:2377
force:
description:
- - Use with state C(present) to force creating a new Swarm, even if already part of one.
- - Use with state C(absent) to Leave the swarm even if this node is a manager.
+ - Use with state V(present) to force creating a new Swarm, even if already part of one.
+ - Use with state V(absent) to Leave the swarm even if this node is a manager.
type: bool
default: false
state:
description:
- - Set to C(present), to create/update a new cluster.
- - Set to C(join), to join an existing cluster.
- - Set to C(absent), to leave an existing cluster.
- - Set to C(remove), to remove an absent node from the cluster.
+ - Set to V(present), to create/update a new cluster.
+ - Set to V(join), to join an existing cluster.
+ - Set to V(absent), to leave an existing cluster.
+ - Set to V(remove), to remove an absent node from the cluster.
Note that removing requires Docker SDK for Python >= 2.4.0.
- M(community.docker.docker_node) can be used to demote a manager before removal.
type: str
@@ -92,35 +92,35 @@ options:
node_id:
description:
- Swarm id of the node to remove.
- - Used with I(state=remove).
+ - Used with O(state=remove).
type: str
join_token:
description:
- Swarm token used to join a swarm cluster.
- - Used with I(state=join).
+ - Used with O(state=join).
- If this value is specified, the corresponding value in the return values will be censored by Ansible.
This is a side-effect of this value not being logged.
type: str
remote_addrs:
description:
- Remote address of one or more manager nodes of an existing Swarm to connect to.
- - Used with I(state=join).
+ - Used with O(state=join).
type: list
elements: str
task_history_retention_limit:
description:
- Maximum number of tasks history stored.
- - Docker default value is C(5).
+ - Docker default value is V(5).
type: int
snapshot_interval:
description:
- Number of logs entries between snapshot.
- - Docker default value is C(10000).
+ - Docker default value is V(10000).
type: int
keep_old_snapshots:
description:
- Number of snapshots to keep beyond the current snapshot.
- - Docker default value is C(0).
+ - Docker default value is V(0).
type: int
log_entries_for_slow_followers:
description:
@@ -129,23 +129,23 @@ options:
heartbeat_tick:
description:
- Amount of ticks (in seconds) between each heartbeat.
- - Docker default value is C(1) seconds.
+ - Docker default value is V(1) seconds.
type: int
election_tick:
description:
- Amount of ticks (in seconds) needed without a leader to trigger a new election.
- - Docker default value is C(10) seconds.
+ - Docker default value is V(10) seconds.
type: int
dispatcher_heartbeat_period:
description:
- The delay (in nanoseconds) for an agent to send a heartbeat to the dispatcher.
- - Docker default value is 5 seconds, which corresponds to a value of C(5000000000).
+ - Docker default value is 5 seconds, which corresponds to a value of V(5000000000).
# DefaultHeartBeatPeriod in https://github.com/moby/moby/blob/master/vendor/github.com/moby/swarmkit/v2/manager/dispatcher/dispatcher.go#L32
type: int
node_cert_expiry:
description:
- Automatic expiry for nodes certificates, given in nanoseconds.
- - Docker default value is 90 days, which corresponds to a value of C(7776000000000000).
+ - Docker default value is 90 days, which corresponds to a value of V(7776000000000000).
# DefaultNodeCertExpiration in https://github.com/moby/moby/blob/master/vendor/github.com/moby/swarmkit/v2/ca/certificates.go#L56
type: int
name:
@@ -175,13 +175,13 @@ options:
description:
- An integer whose purpose is to force swarm to generate a new signing CA certificate and key,
if none have been specified.
- - Docker default value is C(0).
+ - Docker default value is V(0).
- Requires API version >= 1.30.
type: int
autolock_managers:
description:
- If set, generate a key and use it to lock data stored on the managers.
- - Docker default value is C(false).
+ - Docker default value is V(false).
- M(community.docker.docker_swarm_info) can be used to retrieve the unlock key.
type: bool
rotate_worker_token:
@@ -195,18 +195,20 @@ options:
data_path_addr:
description:
- Address or interface to use for data path traffic.
- - This can either be an address in the form C(192.168.1.1), or an interface,
- like C(eth0).
+ - This can either be an address in the form V(192.168.1.1), or an interface,
+ like V(eth0).
- Only used when swarm is initialised or joined. Because of this it is not
considered for idempotency checking.
+ - Requires API version >= 1.30.
type: str
version_added: 2.5.0
data_path_port:
description:
- Port to use for data path traffic.
- - This needs to be a port number like C(9789).
+ - This needs to be a port number like V(9789).
- Only used when swarm is initialised. Because of this it is not
considered for idempotency checking.
+ - Requires API version >= 1.40.
type: int
version_added: 3.1.0
@@ -264,7 +266,7 @@ EXAMPLES = '''
RETURN = '''
swarm_facts:
- description: Informations about swarm.
+ description: Information about swarm.
returned: success
type: dict
contains:
@@ -276,8 +278,8 @@ swarm_facts:
Worker:
description:
- Token to join the cluster as a new *worker* node.
- - "B(Note:) if this value has been specified as I(join_token), the value here will not
- be the token, but C(VALUE_SPECIFIED_IN_NO_LOG_PARAMETER). If you pass I(join_token),
+ - "B(Note:) if this value has been specified as O(join_token), the value here will not
+ be the token, but C(VALUE_SPECIFIED_IN_NO_LOG_PARAMETER). If you pass O(join_token),
make sure your playbook/role does not depend on this return value!"
returned: success
type: str
@@ -285,16 +287,16 @@ swarm_facts:
Manager:
description:
- Token to join the cluster as a new *manager* node.
- - "B(Note:) if this value has been specified as I(join_token), the value here will not
- be the token, but C(VALUE_SPECIFIED_IN_NO_LOG_PARAMETER). If you pass I(join_token),
+ - "B(Note:) if this value has been specified as O(join_token), the value here will not
+ be the token, but C(VALUE_SPECIFIED_IN_NO_LOG_PARAMETER). If you pass O(join_token),
make sure your playbook/role does not depend on this return value!"
returned: success
type: str
example: SWMTKN-1--xxxxx
UnlockKey:
- description: The swarm unlock-key if I(autolock_managers) is C(true).
- returned: on success if I(autolock_managers) is C(true)
- and swarm is initialised, or if I(autolock_managers) has changed.
+ description: The swarm unlock-key if O(autolock_managers=true).
+ returned: on success if O(autolock_managers=true)
+ and swarm is initialised, or if O(autolock_managers) has changed.
type: str
example: SWMKEY-1-xxx
@@ -534,7 +536,6 @@ class SwarmManager(DockerBaseClass):
init_arguments = {
'advertise_addr': self.parameters.advertise_addr,
'listen_addr': self.parameters.listen_addr,
- 'data_path_addr': self.parameters.data_path_addr,
'force_new_cluster': self.force,
'swarm_spec': self.parameters.spec,
}
@@ -542,6 +543,8 @@ class SwarmManager(DockerBaseClass):
init_arguments['default_addr_pool'] = self.parameters.default_addr_pool
if self.parameters.subnet_size is not None:
init_arguments['subnet_size'] = self.parameters.subnet_size
+ if self.parameters.data_path_addr is not None:
+ init_arguments['data_path_addr'] = self.parameters.data_path_addr
if self.parameters.data_path_port is not None:
init_arguments['data_path_port'] = self.parameters.data_path_port
try:
@@ -595,11 +598,16 @@ class SwarmManager(DockerBaseClass):
self.results['actions'].append("This node is already part of a swarm.")
return
if not self.check_mode:
+ join_arguments = {
+ 'remote_addrs': self.parameters.remote_addrs,
+ 'join_token': self.parameters.join_token,
+ 'listen_addr': self.parameters.listen_addr,
+ 'advertise_addr': self.parameters.advertise_addr,
+ }
+ if self.parameters.data_path_addr is not None:
+ join_arguments['data_path_addr'] = self.parameters.data_path_addr
try:
- self.client.join_swarm(
- remote_addrs=self.parameters.remote_addrs, join_token=self.parameters.join_token,
- listen_addr=self.parameters.listen_addr, advertise_addr=self.parameters.advertise_addr,
- data_path_addr=self.parameters.data_path_addr)
+ self.client.join_swarm(**join_arguments)
except APIError as exc:
self.client.fail("Can not join the Swarm Cluster: %s" % to_native(exc))
self.results['actions'].append("New node is added to swarm cluster")
diff --git a/ansible_collections/community/docker/plugins/modules/docker_swarm_info.py b/ansible_collections/community/docker/plugins/modules/docker_swarm_info.py
index df1e5af95..6c6008dcf 100644
--- a/ansible_collections/community/docker/plugins/modules/docker_swarm_info.py
+++ b/ansible_collections/community/docker/plugins/modules/docker_swarm_info.py
@@ -77,10 +77,10 @@ options:
default: false
verbose_output:
description:
- - When set to C(true) and I(nodes), I(services) or I(tasks) is set to C(true), then the module output will
+ - When set to V(true) and O(nodes), O(services), or O(tasks) is set to V(true), then the module output will
contain verbose information about objects matching the full output of API method.
- For details see the documentation of your version of Docker API at U(https://docs.docker.com/engine/api/).
- - The verbose output in this module contains only subset of information returned by I(_info) module
+ - The verbose output in this module contains only subset of information returned by this info module
for each type of the objects.
type: bool
default: false
@@ -139,21 +139,21 @@ EXAMPLES = '''
RETURN = '''
can_talk_to_docker:
description:
- - Will be C(true) if the module can talk to the docker daemon.
+ - Will be V(true) if the module can talk to the docker daemon.
returned: both on success and on error
type: bool
docker_swarm_active:
description:
- - Will be C(true) if the module can talk to the docker daemon,
+ - Will be V(true) if the module can talk to the docker daemon,
and the docker daemon is in Swarm mode.
returned: both on success and on error
type: bool
docker_swarm_manager:
description:
- - Will be C(true) if the module can talk to the docker daemon,
+ - Will be V(true) if the module can talk to the docker daemon,
the docker daemon is in Swarm mode, and the current node is
a manager node.
- - Only if this one is C(true), the module will not fail.
+ - Only if this one is V(true), the module will not fail.
returned: both on success and on error
type: bool
swarm_facts:
@@ -165,30 +165,30 @@ swarm_facts:
swarm_unlock_key:
description:
- Contains the key needed to unlock the swarm.
- returned: When I(unlock_key) is C(true).
+ returned: When O(unlock_key=true).
type: str
nodes:
description:
- List of dict objects containing the basic information about each volume.
- Keys matches the C(docker node ls) output unless I(verbose_output=true).
- See description for I(verbose_output).
- returned: When I(nodes) is C(true)
+ Keys matches the C(docker node ls) output unless O(verbose_output=true).
+ See description for O(verbose_output).
+ returned: When O(nodes=true)
type: list
elements: dict
services:
description:
- List of dict objects containing the basic information about each volume.
- Keys matches the C(docker service ls) output unless I(verbose_output=true).
- See description for I(verbose_output).
- returned: When I(services) is C(true)
+ Keys matches the C(docker service ls) output unless O(verbose_output=true).
+ See description for O(verbose_output).
+ returned: When O(services=true)
type: list
elements: dict
tasks:
description:
- List of dict objects containing the basic information about each volume.
- Keys matches the C(docker service ps) output unless I(verbose_output=true).
- See description for I(verbose_output).
- returned: When I(tasks) is C(true)
+ Keys matches the C(docker service ps) output unless O(verbose_output=true).
+ See description for O(verbose_output).
+ returned: When O(tasks=true)
type: list
elements: dict
diff --git a/ansible_collections/community/docker/plugins/modules/docker_swarm_service.py b/ansible_collections/community/docker/plugins/modules/docker_swarm_service.py
index 564234cb5..95cc10366 100644
--- a/ansible_collections/community/docker/plugins/modules/docker_swarm_service.py
+++ b/ansible_collections/community/docker/plugins/modules/docker_swarm_service.py
@@ -64,7 +64,7 @@ options:
required: true
filename:
description:
- - Name of the file containing the config. Defaults to the I(config_name) if not specified.
+ - Name of the file containing the config. Defaults to the O(configs[].config_name) if not specified.
type: str
uid:
description:
@@ -76,7 +76,7 @@ options:
type: str
mode:
description:
- - File access mode inside the container. Must be an octal number (like C(0644) or C(0444)).
+ - File access mode inside the container. Must be an octal number (like V(0644) or V(0444)).
type: int
container_labels:
description:
@@ -114,7 +114,7 @@ options:
- List or dictionary of the service environment variables.
- If passed a list each items need to be in the format of C(KEY=VALUE).
- If passed a dictionary values which might be parsed as numbers,
- booleans or other types by the YAML parser must be quoted (for example C("true"))
+ booleans or other types by the YAML parser must be quoted (for example V("true"))
in order to avoid data loss.
- Corresponds to the C(--env) option of C(docker service create).
type: raw
@@ -123,7 +123,7 @@ options:
- List of paths to files, present on the target, containing environment variables C(FOO=BAR).
- The order of the list is significant in determining the value assigned to a
variable that shows up more than once.
- - If variable also present in I(env), then I(env) value will override.
+ - If variable also present in O(env), then O(env) value will override.
type: list
elements: path
force_update:
@@ -143,14 +143,15 @@ options:
- Configure a check that is run to determine whether or not containers for this service are "healthy".
See the docs for the L(HEALTHCHECK Dockerfile instruction,https://docs.docker.com/engine/reference/builder/#healthcheck)
for details on how healthchecks work.
- - "I(interval), I(timeout) and I(start_period) are specified as durations. They accept duration as a string in a format
- that look like: C(5h34m56s), C(1m30s) etc. The supported units are C(us), C(ms), C(s), C(m) and C(h)."
+ - "O(healthcheck.interval), O(healthcheck.timeout), and O(healthcheck.start_period) are specified as durations.
+ They accept duration as a string in a format that look like: V(5h34m56s), V(1m30s), and so on.
+ The supported units are V(us), V(ms), V(s), V(m) and V(h)."
type: dict
suboptions:
test:
description:
- Command to run to check health.
- - Must be either a string or a list. If it is a list, the first item must be one of C(NONE), C(CMD) or C(CMD-SHELL).
+ - Must be either a string or a list. If it is a list, the first item must be one of V(NONE), V(CMD) or V(CMD-SHELL).
type: raw
interval:
description:
@@ -201,15 +202,15 @@ options:
suboptions:
cpus:
description:
- - Service CPU limit. C(0) equals no limit.
+ - Service CPU limit. V(0) equals no limit.
- Corresponds to the C(--limit-cpu) option of C(docker service create).
type: float
memory:
description:
- "Service memory limit in format C(<number>[<unit>]). Number is a positive integer.
- Unit can be C(B) (byte), C(K) (kibibyte, 1024B), C(M) (mebibyte), C(G) (gibibyte),
- C(T) (tebibyte), or C(P) (pebibyte)."
- - C(0) equals no limit.
+ Unit can be V(B) (byte), V(K) (kibibyte, 1024B), V(M) (mebibyte), V(G) (gibibyte),
+ V(T) (tebibyte), or V(P) (pebibyte)."
+ - V(0) equals no limit.
- Omitting the unit defaults to bytes.
- Corresponds to the C(--limit-memory) option of C(docker service create).
type: str
@@ -249,7 +250,7 @@ options:
source:
description:
- Mount source (for example a volume name or a host path).
- - Must be specified if I(type) is not C(tmpfs).
+ - Must be specified if O(mounts[].type) is not V(tmpfs).
type: str
target:
description:
@@ -259,7 +260,7 @@ options:
type:
description:
- The mount type.
- - Note that C(npipe) is only supported by Docker for Windows. Also note that C(npipe) was added in Ansible 2.9.
+ - Note that V(npipe) is only supported by Docker for Windows. Also note that V(npipe) was added in Ansible 2.9.
type: str
default: bind
choices:
@@ -278,7 +279,7 @@ options:
propagation:
description:
- The propagation mode to use.
- - Can only be used when I(type) is C(bind).
+ - Can only be used when O(mounts[].type=bind).
type: str
choices:
- shared
@@ -290,12 +291,12 @@ options:
no_copy:
description:
- Disable copying of data from a container when a volume is created.
- - Can only be used when I(type) is C(volume).
+ - Can only be used when O(mounts[].type=volume).
type: bool
driver_config:
description:
- Volume driver configuration.
- - Can only be used when I(type) is C(volume).
+ - Can only be used when O(mounts[].type=volume).
suboptions:
name:
description:
@@ -309,14 +310,14 @@ options:
tmpfs_size:
description:
- "Size of the tmpfs mount in format C(<number>[<unit>]). Number is a positive integer.
- Unit can be C(B) (byte), C(K) (kibibyte, 1024B), C(M) (mebibyte), C(G) (gibibyte),
- C(T) (tebibyte), or C(P) (pebibyte)."
- - Can only be used when I(type) is C(tmpfs).
+ Unit can be V(B) (byte), V(K) (kibibyte, 1024B), V(M) (mebibyte), V(G) (gibibyte),
+ V(T) (tebibyte), or V(P) (pebibyte)."
+ - Can only be used when O(mounts[].type=tmpfs).
type: str
tmpfs_mode:
description:
- File mode of the tmpfs in octal.
- - Can only be used when I(type) is C(tmpfs).
+ - Can only be used when O(mounts[].type=tmpfs).
type: int
name:
description:
@@ -327,8 +328,8 @@ options:
networks:
description:
- List of the service networks names or dictionaries.
- - When passed dictionaries valid sub-options are I(name), which is required, and
- I(aliases) and I(options).
+ - When passed dictionaries valid sub-options are C(name), which is required, and
+ C(aliases) and C(options).
- Prior to API version 1.29, updating and removing networks is not supported.
If changes are made the service will then be removed and recreated.
- Corresponds to the C(--network) option of C(docker service create).
@@ -399,9 +400,9 @@ options:
type: bool
replicas:
description:
- - Number of containers instantiated in the service. Valid only if I(mode) is C(replicated).
- - If set to C(-1), and service is not present, service replicas will be set to C(1).
- - If set to C(-1), and service is present, service replicas will be unchanged.
+ - Number of containers instantiated in the service. Valid only if O(mode=replicated).
+ - If set to V(-1), and service is not present, service replicas will be set to V(1).
+ - If set to V(-1), and service is present, service replicas will be unchanged.
- Corresponds to the C(--replicas) option of C(docker service create).
type: int
default: -1
@@ -411,15 +412,15 @@ options:
suboptions:
cpus:
description:
- - Service CPU reservation. C(0) equals no reservation.
+ - Service CPU reservation. V(0) equals no reservation.
- Corresponds to the C(--reserve-cpu) option of C(docker service create).
type: float
memory:
description:
- "Service memory reservation in format C(<number>[<unit>]). Number is a positive integer.
- Unit can be C(B) (byte), C(K) (kibibyte, 1024B), C(M) (mebibyte), C(G) (gibibyte),
- C(T) (tebibyte), or C(P) (pebibyte)."
- - C(0) equals no reservation.
+ Unit can be V(B) (byte), V(K) (kibibyte, 1024B), V(M) (mebibyte), V(G) (gibibyte),
+ V(T) (tebibyte), or V(P) (pebibyte)."
+ - V(0) equals no reservation.
- Omitting the unit defaults to bytes.
- Corresponds to the C(--reserve-memory) option of C(docker service create).
type: str
@@ -447,7 +448,7 @@ options:
description:
- Delay between restarts.
- "Accepts a a string in a format that look like:
- C(5h34m56s), C(1m30s) etc. The supported units are C(us), C(ms), C(s), C(m) and C(h)."
+ V(5h34m56s), V(1m30s) etc. The supported units are V(us), V(ms), V(s), V(m) and V(h)."
- Corresponds to the C(--restart-delay) option of C(docker service create).
type: str
max_attempts:
@@ -459,7 +460,7 @@ options:
description:
- Restart policy evaluation window.
- "Accepts a string in a format that look like:
- C(5h34m56s), C(1m30s) etc. The supported units are C(us), C(ms), C(s), C(m) and C(h)."
+ V(5h34m56s), V(1m30s) etc. The supported units are V(us), V(ms), V(s), V(m) and V(h)."
- Corresponds to the C(--restart-window) option of C(docker service create).
type: str
type: dict
@@ -477,7 +478,7 @@ options:
description:
- Delay between task rollbacks.
- "Accepts a string in a format that look like:
- C(5h34m56s), C(1m30s) etc. The supported units are C(us), C(ms), C(s), C(m) and C(h)."
+ V(5h34m56s), V(1m30s) etc. The supported units are V(us), V(ms), V(s), V(m) and V(h)."
- Corresponds to the C(--rollback-delay) option of C(docker service create).
- Requires API version >= 1.28.
type: str
@@ -494,7 +495,7 @@ options:
description:
- Duration after each task rollback to monitor for failure.
- "Accepts a string in a format that look like:
- C(5h34m56s), C(1m30s) etc. The supported units are C(us), C(ms), C(s), C(m) and C(h)."
+ V(5h34m56s), V(1m30s) etc. The supported units are V(us), V(ms), V(s), V(m) and V(h)."
- Corresponds to the C(--rollback-monitor) option of C(docker service create).
- Requires API version >= 1.28.
type: str
@@ -529,7 +530,7 @@ options:
required: true
filename:
description:
- - Name of the file containing the secret. Defaults to the I(secret_name) if not specified.
+ - Name of the file containing the secret. Defaults to the O(secrets[].secret_name) if not specified.
- Corresponds to the C(target) key of C(docker service create --secret).
type: str
uid:
@@ -542,12 +543,12 @@ options:
type: str
mode:
description:
- - File access mode inside the container. Must be an octal number (like C(0644) or C(0444)).
+ - File access mode inside the container. Must be an octal number (like V(0644) or V(0444)).
type: int
state:
description:
- - C(absent) - A service matching the specified name will be removed and have its tasks stopped.
- - C(present) - Asserts the existence of a service matching the name and provided configuration parameters.
+ - V(absent) - A service matching the specified name will be removed and have its tasks stopped.
+ - V(present) - Asserts the existence of a service matching the name and provided configuration parameters.
Unspecified configuration parameters will be set to docker defaults.
type: str
default: present
@@ -558,7 +559,7 @@ options:
description:
- Time to wait before force killing a container.
- "Accepts a duration as a string in a format that look like:
- C(5h34m56s), C(1m30s) etc. The supported units are C(us), C(ms), C(s), C(m) and C(h)."
+ V(5h34m56s), V(1m30s) etc. The supported units are V(us), V(ms), V(s), V(m) and V(h)."
- Corresponds to the C(--stop-grace-period) option of C(docker service create).
type: str
stop_signal:
@@ -584,14 +585,14 @@ options:
description:
- Rolling update delay.
- "Accepts a string in a format that look like:
- C(5h34m56s), C(1m30s) etc. The supported units are C(us), C(ms), C(s), C(m) and C(h)."
+ V(5h34m56s), V(1m30s) etc. The supported units are V(us), V(ms), V(s), V(m) and V(h)."
- Corresponds to the C(--update-delay) option of C(docker service create).
type: str
failure_action:
description:
- Action to take in case of container failure.
- Corresponds to the C(--update-failure-action) option of C(docker service create).
- - Usage of I(rollback) requires API version >= 1.29.
+ - Usage of V(rollback) requires API version >= 1.29.
type: str
choices:
- continue
@@ -601,7 +602,7 @@ options:
description:
- Time to monitor updated tasks for failures.
- "Accepts a string in a format that look like:
- C(5h34m56s), C(1m30s) etc. The supported units are C(us), C(ms), C(s), C(m) and C(h)."
+ V(5h34m56s), V(1m30s) etc. The supported units are V(us), V(ms), V(s), V(m) and V(h)."
- Corresponds to the C(--update-monitor) option of C(docker service create).
type: str
max_failure_ratio:
@@ -619,7 +620,7 @@ options:
user:
description:
- Sets the username or UID used for the specified command.
- - Before Ansible 2.8, the default value for this option was C(root).
+ - Before Ansible 2.8, the default value for this option was V(root).
- The default has been removed so that the user defined in the image is used if no user is specified here.
- Corresponds to the C(--user) option of C(docker service create).
type: str
@@ -648,7 +649,7 @@ requirements:
- "Docker API >= 1.25"
notes:
- "Images will only resolve to the latest digest when using Docker API >= 1.30 and Docker SDK for Python >= 3.2.0.
- When using older versions use C(force_update: true) to trigger the swarm to resolve a new image."
+ When using older versions use O(force_update=true) to trigger the swarm to resolve a new image."
'''
RETURN = '''
@@ -661,7 +662,7 @@ swarm_service:
- Note that facts are not part of registered vars but accessible directly.
- Note that before Ansible 2.7.9, the return variable was documented as C(ansible_swarm_service),
while the module actually returned a variable called C(ansible_docker_service). The variable
- was renamed to C(swarm_service) in both code and documentation for Ansible 2.7.9 and Ansible 2.8.0.
+ was renamed to RV(swarm_service) in both code and documentation for Ansible 2.7.9 and Ansible 2.8.0.
In Ansible 2.7.x, the old name C(ansible_docker_service) can still be used.
sample: '{
"args": [
@@ -1148,7 +1149,7 @@ def has_list_changed(new_list, old_list, sort_lists=True, sort_key=None):
else:
zip_data = zip(new_list, old_list)
for new_item, old_item in zip_data:
- is_same_type = type(new_item) == type(old_item)
+ is_same_type = type(new_item) == type(old_item) # noqa: E721, pylint: disable=unidiomatic-typecheck
if not is_same_type:
if isinstance(new_item, string_types) and isinstance(old_item, string_types):
# Even though the types are different between these items,
diff --git a/ansible_collections/community/docker/plugins/modules/docker_swarm_service_info.py b/ansible_collections/community/docker/plugins/modules/docker_swarm_service_info.py
index ebe8a8e10..0a9dd56c8 100644
--- a/ansible_collections/community/docker/plugins/modules/docker_swarm_service_info.py
+++ b/ansible_collections/community/docker/plugins/modules/docker_swarm_service_info.py
@@ -58,7 +58,7 @@ exists:
service:
description:
- A dictionary representing the current state of the service. Matches the C(docker service inspect) output.
- - Will be C(none) if service does not exist.
+ - Will be V(none) if service does not exist.
returned: always
type: dict
'''
diff --git a/ansible_collections/community/docker/plugins/modules/docker_volume.py b/ansible_collections/community/docker/plugins/modules/docker_volume.py
index 09b1d386b..f282cafd0 100644
--- a/ansible_collections/community/docker/plugins/modules/docker_volume.py
+++ b/ansible_collections/community/docker/plugins/modules/docker_volume.py
@@ -38,7 +38,7 @@ options:
driver:
description:
- - Specify the type of volume. Docker provides the C(local) driver, but 3rd party drivers can also be used.
+ - Specify the type of volume. Docker provides the V(local) driver, but 3rd party drivers can also be used.
type: str
default: local
@@ -56,13 +56,13 @@ options:
recreate:
description:
- - Controls when a volume will be recreated when I(state) is C(present). Please
+ - Controls when a volume will be recreated when O(state=present). Please
note that recreating an existing volume will cause B(any data in the existing volume
to be lost!) The volume will be deleted and a new volume with the same name will be
created.
- - The value C(always) forces the volume to be always recreated.
- - The value C(never) makes sure the volume will not be recreated.
- - The value C(options-changed) makes sure the volume will be recreated if the volume
+ - The value V(always) forces the volume to be always recreated.
+ - The value V(never) makes sure the volume will not be recreated.
+ - The value V(options-changed) makes sure the volume will be recreated if the volume
already exist and the driver, driver options or labels differ.
type: str
default: never
@@ -73,8 +73,8 @@ options:
state:
description:
- - C(absent) deletes the volume.
- - C(present) creates the volume, if it does not already exist.
+ - V(absent) deletes the volume.
+ - V(present) creates the volume, if it does not already exist.
type: str
default: present
choices:
@@ -214,7 +214,7 @@ class DockerVolumeManager(object):
parameter=value,
active=self.existing_volume['Options'].get(key))
if self.parameters.labels:
- existing_labels = self.existing_volume.get('Labels', {})
+ existing_labels = self.existing_volume.get('Labels') or {}
for label in self.parameters.labels:
if existing_labels.get(label) != self.parameters.labels.get(label):
differences.add('labels.%s' % label,
diff --git a/ansible_collections/community/docker/plugins/modules/docker_volume_info.py b/ansible_collections/community/docker/plugins/modules/docker_volume_info.py
index 100010ba4..9345d2e6e 100644
--- a/ansible_collections/community/docker/plugins/modules/docker_volume_info.py
+++ b/ansible_collections/community/docker/plugins/modules/docker_volume_info.py
@@ -63,7 +63,7 @@ exists:
volume:
description:
- Volume inspection results for the affected volume.
- - Will be C(none) if volume does not exist.
+ - Will be V(none) if volume does not exist.
returned: success
type: dict
sample: '{
diff --git a/ansible_collections/community/docker/tests/galaxy-importer.cfg b/ansible_collections/community/docker/tests/galaxy-importer.cfg
new file mode 100644
index 000000000..5ab20d06a
--- /dev/null
+++ b/ansible_collections/community/docker/tests/galaxy-importer.cfg
@@ -0,0 +1,8 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+[galaxy-importer]
+# This is only needed to make Zuul's third-party-check happy.
+# It is not needed by anything else.
+run_ansible_doc=false
diff --git a/ansible_collections/community/docker/tests/integration/requirements.yml b/ansible_collections/community/docker/tests/integration/requirements.yml
index 7b3e38d98..b4c045f43 100644
--- a/ansible_collections/community/docker/tests/integration/requirements.yml
+++ b/ansible_collections/community/docker/tests/integration/requirements.yml
@@ -5,6 +5,7 @@
collections:
- ansible.posix
-- community.internal_test_tools
- community.crypto
- community.general
+- community.internal_test_tools
+- community.library_inventory_filtering_v1
diff --git a/ansible_collections/community/docker/tests/integration/targets/connection_docker_api/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/connection_docker_api/meta/main.yml
index 5769ff1cb..471ddd412 100644
--- a/ansible_collections/community/docker/tests/integration/targets/connection_docker_api/meta/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/connection_docker_api/meta/main.yml
@@ -5,3 +5,4 @@
dependencies:
- setup_docker
+ - setup_docker_python_deps
diff --git a/ansible_collections/community/docker/tests/integration/targets/connection_docker_api/setup.yml b/ansible_collections/community/docker/tests/integration/targets/connection_docker_api/setup.yml
index e522a51f0..0b0738843 100644
--- a/ansible_collections/community/docker/tests/integration/targets/connection_docker_api/setup.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/connection_docker_api/setup.yml
@@ -12,3 +12,7 @@
- name: Setup docker
import_role:
name: setup_docker
+
+ - name: Setup docker Python deps
+ import_role:
+ name: setup_docker_python_deps
diff --git a/ansible_collections/community/docker/tests/integration/targets/connection_nsenter/runme.sh b/ansible_collections/community/docker/tests/integration/targets/connection_nsenter/runme.sh
index eebbb6a39..5a2a84c30 100755
--- a/ansible_collections/community/docker/tests/integration/targets/connection_nsenter/runme.sh
+++ b/ansible_collections/community/docker/tests/integration/targets/connection_nsenter/runme.sh
@@ -8,6 +8,7 @@ set -euo pipefail
[[ -n "${DEBUG:-}" || -n "${ANSIBLE_DEBUG:-}" ]] && set -x
readonly IMAGE="quay.io/ansible/ansible-runner:devel"
+# shellcheck disable=SC2155
readonly PYTHON="$(command -v python3 python | head -n1)"
# Determine collection root
@@ -18,6 +19,7 @@ while true; do
fi
COLLECTION_ROOT="${COLLECTION_ROOT}../"
done
+# shellcheck disable=SC2155
readonly COLLECTION_ROOT="$(cd ${COLLECTION_ROOT} ; pwd)"
# Setup phase
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_compose/aliases b/ansible_collections/community/docker/tests/integration/targets/docker_compose/aliases
index 2e1acc0ad..d8f457d53 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_compose/aliases
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_compose/aliases
@@ -2,5 +2,5 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
-azp/4
+azp/6
destructive
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_compose/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_compose/meta/main.yml
index 7f44c871d..6b4232214 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_compose/meta/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_compose/meta/main.yml
@@ -4,5 +4,5 @@
# SPDX-License-Identifier: GPL-3.0-or-later
dependencies:
- - setup_docker_compose
+ - setup_docker_compose_v1
- setup_remote_tmp_dir
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_compose/tasks/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_compose/tasks/main.yml
index d3c7eae51..8ea59f865 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_compose/tasks/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_compose/tasks/main.yml
@@ -20,26 +20,28 @@
# Run the tests
- block:
- - include_tasks: run-test.yml
- with_fileglob:
- - "tests/*.yml"
+ - include_tasks: run-test.yml
+ with_fileglob:
+ - "tests/*.yml"
+ loop_control:
+ loop_var: test_name
always:
- - name: "Make sure all containers are removed"
- docker_container:
- name: "{{ item }}"
- state: absent
- force_kill: true
- with_items: "{{ cnames }}"
- diff: false
- - name: "Make sure all networks are removed"
- docker_network:
- name: "{{ item }}"
- state: absent
- force: true
- with_items: "{{ dnetworks }}"
- when: docker_py_version is version('1.10.0', '>=')
- diff: false
+ - name: "Make sure all containers are removed"
+ docker_container:
+ name: "{{ item }}"
+ state: absent
+ force_kill: true
+ with_items: "{{ cnames }}"
+ diff: false
+ - name: "Make sure all networks are removed"
+ docker_network:
+ name: "{{ item }}"
+ state: absent
+ force: true
+ with_items: "{{ dnetworks }}"
+ when: docker_py_version is version('1.10.0', '>=')
+ diff: false
when: has_docker_compose and docker_py_version is version('1.8.0', '>=') and docker_api_version is version('1.25', '>=')
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_compose/tasks/run-test.yml b/ansible_collections/community/docker/tests/integration/targets/docker_compose/tasks/run-test.yml
index 65853ddd8..72a58962d 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_compose/tasks/run-test.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_compose/tasks/run-test.yml
@@ -3,5 +3,5 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
-- name: "Loading tasks from {{ item }}"
- include_tasks: "{{ item }}"
+- name: "Loading tasks from {{ test_name }}"
+ include_tasks: "{{ test_name }}"
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_compose_v2/aliases b/ansible_collections/community/docker/tests/integration/targets/docker_compose_v2/aliases
new file mode 100644
index 000000000..2e1acc0ad
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_compose_v2/aliases
@@ -0,0 +1,6 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+azp/4
+destructive
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_compose_v2/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_compose_v2/meta/main.yml
new file mode 100644
index 000000000..aefcf50f2
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_compose_v2/meta/main.yml
@@ -0,0 +1,10 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+dependencies:
+ - setup_docker_cli_compose
+ # The Python dependencies are needed for the other modules
+ - setup_docker_python_deps
+ - setup_remote_tmp_dir
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_compose_v2/tasks/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_compose_v2/tasks/main.yml
new file mode 100644
index 000000000..8813f0e71
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_compose_v2/tasks/main.yml
@@ -0,0 +1,48 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+####################################################################
+# WARNING: These are designed specifically for Ansible tests #
+# and should not be used as examples of how to write Ansible roles #
+####################################################################
+
+# Create random name prefix (for services, ...)
+- name: Create random container name prefix
+ set_fact:
+ name_prefix: "{{ 'ansible-docker-test-%0x' % ((2**32) | random) }}"
+ cnames: []
+ dnetworks: []
+
+- debug:
+ msg: "Using name prefix {{ name_prefix }}"
+
+# Run the tests
+- block:
+ - command: docker compose --help
+
+ - include_tasks: run-test.yml
+ with_fileglob:
+ - "tests/*.yml"
+ loop_control:
+ loop_var: test_name
+
+ always:
+ - name: "Make sure all containers are removed"
+ docker_container:
+ name: "{{ item }}"
+ state: absent
+ force_kill: true
+ with_items: "{{ cnames }}"
+ diff: false
+
+ - name: "Make sure all networks are removed"
+ docker_network:
+ name: "{{ item }}"
+ state: absent
+ force: true
+ with_items: "{{ dnetworks }}"
+ diff: false
+
+ when: docker_has_compose and docker_compose_version is version('2.18.0', '>=')
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_compose_v2/tasks/run-test.yml b/ansible_collections/community/docker/tests/integration/targets/docker_compose_v2/tasks/run-test.yml
new file mode 100644
index 000000000..72a58962d
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_compose_v2/tasks/run-test.yml
@@ -0,0 +1,7 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: "Loading tasks from {{ test_name }}"
+ include_tasks: "{{ test_name }}"
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_compose_v2/tasks/tests/pull.yml b/ansible_collections/community/docker/tests/integration/targets/docker_compose_v2/tasks/tests/pull.yml
new file mode 100644
index 000000000..47647a9bc
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_compose_v2/tasks/tests/pull.yml
@@ -0,0 +1,211 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- vars:
+ pname: "{{ name_prefix }}-pull"
+ cname: "{{ name_prefix }}-cont"
+ non_existing_image: does-not-exist:latest
+ project_src: "{{ remote_tmp_dir }}/{{ pname }}"
+ test_service_non_existing: |
+ version: '3'
+ services:
+ {{ cname }}:
+ image: {{ non_existing_image }}
+ test_service_alpine: |
+ version: '3'
+ services:
+ {{ cname }}:
+ image: {{ docker_test_image_alpine }}
+ command: /bin/sh -c 'sleep 10m'
+ stop_grace_period: 1s
+
+ block:
+ - name: Registering container name
+ set_fact:
+ cnames: "{{ cnames + [pname ~ '-' ~ cname ~ '-1'] }}"
+ dnetworks: "{{ dnetworks + [pname ~ '_default'] }}"
+
+ - name: Create project directory
+ file:
+ path: '{{ project_src }}'
+ state: directory
+
+ - name: Make sure images are not around
+ docker_image_remove:
+ name: '{{ item }}'
+ loop:
+ - '{{ non_existing_image }}'
+ - '{{ docker_test_image_alpine }}'
+
+####################################################################
+## Missing image ###################################################
+####################################################################
+
+ - name: Template project file with non-existing image
+ copy:
+ dest: '{{ project_src }}/docker-compose.yml'
+ content: '{{ test_service_non_existing }}'
+
+ - name: Present with pull=never (check)
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: present
+ pull: never
+ check_mode: true
+ register: present_1_check
+ ignore_errors: true
+
+ - name: Present with pull=never
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: present
+ pull: never
+ register: present_1
+ ignore_errors: true
+
+ - name: Present without explicit pull (check)
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: present
+ check_mode: true
+ register: present_2_check
+ ignore_errors: true
+
+ - name: Present without explicit pull
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: present
+ register: present_2
+ ignore_errors: true
+
+ - assert:
+ that:
+ - present_1_check is failed or present_1_check is changed
+ - present_1_check is changed or present_1_check.msg.startswith('General error:')
+ - present_1 is failed
+ - present_1.msg.startswith('General error:')
+ - present_2_check is failed
+ - present_2_check.msg.startswith('Error when processing ' ~ cname ~ ':')
+ - present_2 is failed
+ - present_2.msg.startswith('Error when processing ' ~ cname ~ ':')
+
+####################################################################
+## Regular image ###################################################
+####################################################################
+
+ - name: Template project file with Alpine image
+ copy:
+ dest: '{{ project_src }}/docker-compose.yml'
+ content: '{{ test_service_alpine }}'
+
+ - name: Present with pull=missing (check)
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: present
+ pull: missing
+ check_mode: true
+ register: present_1_check
+
+ - name: Present with pull=missing
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: present
+ pull: missing
+ register: present_1
+
+ - name: Present with pull=missing (idempotent, check)
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: present
+ pull: missing
+ check_mode: true
+ register: present_2_check
+
+ - name: Present with pull=missing (idempotent)
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: present
+ pull: missing
+ register: present_2
+
+ - name: Present with pull=always (check)
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: present
+ pull: always
+ check_mode: true
+ register: present_3_check
+
+ - name: Present with pull=always
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: present
+ pull: always
+ register: present_3
+
+ - name: Stopping service
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: absent
+
+ - name: Present with pull=never (check)
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: present
+ pull: missing
+ check_mode: true
+ register: present_4_check
+
+ - name: Present with pull=never
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: present
+ pull: missing
+ register: present_4
+
+ - name: Present with pull=never (idempotent, check)
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: present
+ pull: missing
+ check_mode: true
+ register: present_5_check
+
+ - name: Present with pull=never (idempotent)
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: present
+ pull: missing
+ register: present_5
+
+ - name: Cleanup
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: absent
+
+ - assert:
+ that:
+ - present_1_check is changed
+ - present_1_check.actions | selectattr('status', 'eq', 'Pulling') | first
+ - present_1_check.actions | selectattr('status', 'eq', 'Creating') | first
+ - present_1 is changed
+ - present_1.actions | selectattr('status', 'eq', 'Pulling') | first
+ - present_1.actions | selectattr('status', 'eq', 'Creating') | first
+ - present_2_check is not changed
+ - present_2 is not changed
+ - present_3_check is changed
+ - present_3_check.actions | selectattr('status', 'eq', 'Pulling') | first
+ - present_3_check.actions | selectattr('status', 'eq', 'Creating') | length == 0
+ - present_3_check.actions | selectattr('status', 'eq', 'Recreating') | length == 0
+ - present_3 is not changed
+ - present_3.actions | selectattr('status', 'eq', 'Pulling') | first
+ - present_3.actions | selectattr('status', 'eq', 'Creating') | length == 0
+ - present_3.actions | selectattr('status', 'eq', 'Recreating') | length == 0
+ - present_4_check is changed
+ - present_4_check.actions | selectattr('status', 'eq', 'Pulling') | length == 0
+ - present_4 is changed
+ - present_4.actions | selectattr('status', 'eq', 'Pulling') | length == 0
+ - present_5_check is not changed
+ - present_5 is not changed
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_compose_v2/tasks/tests/start-stop.yml b/ansible_collections/community/docker/tests/integration/targets/docker_compose_v2/tasks/tests/start-stop.yml
new file mode 100644
index 000000000..22dd5e026
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_compose_v2/tasks/tests/start-stop.yml
@@ -0,0 +1,262 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- vars:
+ pname: "{{ name_prefix }}-start-stop"
+ cname: "{{ name_prefix }}-container"
+ project_src: "{{ remote_tmp_dir }}/{{ pname }}"
+ test_service: |
+ version: '3'
+ services:
+ {{ cname }}:
+ image: "{{ docker_test_image_alpine }}"
+ command: '/bin/sh -c "sleep 10m"'
+ stop_grace_period: 1s
+ test_service_mod: |
+ version: '3'
+ services:
+ {{ cname }}:
+ image: "{{ docker_test_image_alpine }}"
+ command: '/bin/sh -c "sleep 15m"'
+ stop_grace_period: 1s
+
+ block:
+ - name: Registering container name
+ set_fact:
+ cnames: "{{ cnames + [pname ~ '-' ~ cname ~ '-1'] }}"
+ dnetworks: "{{ dnetworks + [pname ~ '_default'] }}"
+
+ - name: Create project directory
+ file:
+ path: '{{ project_src }}'
+ state: directory
+
+####################################################################
+## Present #########################################################
+####################################################################
+
+ - name: Template default project file
+ copy:
+ dest: '{{ project_src }}/docker-compose.yml'
+ content: '{{ test_service }}'
+
+ - name: Present (check)
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: present
+ check_mode: true
+ register: present_1_check
+
+ - name: Present
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: present
+ register: present_1
+
+ - name: Present (idempotent check)
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: present
+ check_mode: true
+ register: present_2_check
+
+ - name: Present (idempotent)
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: present
+ register: present_2
+
+ - name: Template modified project file
+ copy:
+ dest: '{{ project_src }}/docker-compose.yml'
+ content: '{{ test_service_mod }}'
+
+ - name: Present (changed check)
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: present
+ check_mode: true
+ register: present_3_check
+
+ - name: Present (changed)
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: present
+ register: present_3
+
+ - assert:
+ that:
+ - present_1_check is changed
+ - present_1 is changed
+ - present_1.containers | length == 1
+ - present_1.containers[0].Name == pname ~ '-' ~ cname ~ '-1'
+ - present_1.containers[0].Image == docker_test_image_alpine
+ - present_1.images | length == 1
+ - present_1.images[0].ContainerName == pname ~ '-' ~ cname ~ '-1'
+ - present_1.images[0].Repository == (docker_test_image_alpine | split(':') | first)
+ - present_1.images[0].Tag == (docker_test_image_alpine | split(':') | last)
+ - present_2_check is not changed
+ - present_2 is not changed
+ - present_3_check is changed
+ - present_3 is changed
+
+####################################################################
+## Absent ##########################################################
+####################################################################
+
+ - name: Absent (check)
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: absent
+ check_mode: true
+ register: absent_1_check
+
+ - name: Absent
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: absent
+ register: absent_1
+
+ - name: Absent (idempotent check)
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: absent
+ check_mode: true
+ register: absent_2_check
+
+ - name: Absent (idempotent)
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: absent
+ register: absent_2
+
+ - assert:
+ that:
+ - absent_1_check is changed
+ - absent_1 is changed
+ - absent_2_check is not changed
+ - absent_2 is not changed
+
+####################################################################
+## Stopping and starting ###########################################
+####################################################################
+
+ - name: Template default project file
+ copy:
+ dest: '{{ project_src }}/docker-compose.yml'
+ content: '{{ test_service }}'
+
+ - name: Present stopped (check)
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: stopped
+ check_mode: true
+ register: present_1_check
+
+ - name: Present stopped
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: stopped
+ register: present_1
+
+ - name: Present stopped (idempotent check)
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: stopped
+ check_mode: true
+ register: present_2_check
+
+ - name: Present stopped (idempotent)
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: stopped
+ register: present_2
+
+ - name: Started (check)
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: present
+ check_mode: true
+ register: present_3_check
+
+ - name: Started
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: present
+ register: present_3
+
+ - name: Started (idempotent check)
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: present
+ check_mode: true
+ register: present_4_check
+
+ - name: Started (idempotent)
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: present
+ register: present_4
+
+ - name: Restarted (check)
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: restarted
+ check_mode: true
+ register: present_5_check
+
+ - name: Restarted
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: restarted
+ register: present_5
+
+ - name: Stopped (check)
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: stopped
+ check_mode: true
+ register: present_6_check
+
+ - name: Stopped
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: stopped
+ register: present_6
+
+ - name: Restarted (check)
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: restarted
+ check_mode: true
+ register: present_7_check
+
+ - name: Restarted
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: restarted
+ register: present_7
+
+ - name: Cleanup
+ docker_compose_v2:
+ project_src: '{{ project_src }}'
+ state: absent
+
+ - assert:
+ that:
+ - present_1_check is changed
+ - present_1 is changed
+ - present_2_check is not changed
+ - present_2 is not changed
+ - present_3_check is changed
+ - present_3 is changed
+ - present_4_check is not changed
+ - present_4 is not changed
+ - present_5_check is changed
+ - present_5 is changed
+ - present_6_check is changed
+ - present_6 is changed
+ - present_7_check is changed
+ - present_7 is changed
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_compose_v2_pull/aliases b/ansible_collections/community/docker/tests/integration/targets/docker_compose_v2_pull/aliases
new file mode 100644
index 000000000..2e1acc0ad
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_compose_v2_pull/aliases
@@ -0,0 +1,6 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+azp/4
+destructive
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_compose_v2_pull/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_compose_v2_pull/meta/main.yml
new file mode 100644
index 000000000..aefcf50f2
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_compose_v2_pull/meta/main.yml
@@ -0,0 +1,10 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+dependencies:
+ - setup_docker_cli_compose
+ # The Python dependencies are needed for the other modules
+ - setup_docker_python_deps
+ - setup_remote_tmp_dir
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_compose_v2_pull/tasks/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_compose_v2_pull/tasks/main.yml
new file mode 100644
index 000000000..8813f0e71
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_compose_v2_pull/tasks/main.yml
@@ -0,0 +1,48 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+####################################################################
+# WARNING: These are designed specifically for Ansible tests #
+# and should not be used as examples of how to write Ansible roles #
+####################################################################
+
+# Create random name prefix (for services, ...)
+- name: Create random container name prefix
+ set_fact:
+ name_prefix: "{{ 'ansible-docker-test-%0x' % ((2**32) | random) }}"
+ cnames: []
+ dnetworks: []
+
+- debug:
+ msg: "Using name prefix {{ name_prefix }}"
+
+# Run the tests
+- block:
+ - command: docker compose --help
+
+ - include_tasks: run-test.yml
+ with_fileglob:
+ - "tests/*.yml"
+ loop_control:
+ loop_var: test_name
+
+ always:
+ - name: "Make sure all containers are removed"
+ docker_container:
+ name: "{{ item }}"
+ state: absent
+ force_kill: true
+ with_items: "{{ cnames }}"
+ diff: false
+
+ - name: "Make sure all networks are removed"
+ docker_network:
+ name: "{{ item }}"
+ state: absent
+ force: true
+ with_items: "{{ dnetworks }}"
+ diff: false
+
+ when: docker_has_compose and docker_compose_version is version('2.18.0', '>=')
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_compose_v2_pull/tasks/run-test.yml b/ansible_collections/community/docker/tests/integration/targets/docker_compose_v2_pull/tasks/run-test.yml
new file mode 100644
index 000000000..72a58962d
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_compose_v2_pull/tasks/run-test.yml
@@ -0,0 +1,7 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: "Loading tasks from {{ test_name }}"
+ include_tasks: "{{ test_name }}"
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_compose_v2_pull/tasks/tests/pull.yml b/ansible_collections/community/docker/tests/integration/targets/docker_compose_v2_pull/tasks/tests/pull.yml
new file mode 100644
index 000000000..27f2637b7
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_compose_v2_pull/tasks/tests/pull.yml
@@ -0,0 +1,192 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- vars:
+ pname: "{{ name_prefix }}-pull"
+ cname: "{{ name_prefix }}-cont"
+ non_existing_image: does-not-exist:latest
+ project_src: "{{ remote_tmp_dir }}/{{ pname }}"
+ test_service_non_existing: |
+ version: '3'
+ services:
+ {{ cname }}:
+ image: {{ non_existing_image }}
+ test_service_alpine: |
+ version: '3'
+ services:
+ {{ cname }}:
+ image: {{ docker_test_image_alpine }}
+ command: /bin/sh -c 'sleep 10m'
+ stop_grace_period: 1s
+
+ block:
+ - name: Registering container name
+ set_fact:
+ cnames: "{{ cnames + [pname ~ '-' ~ cname ~ '-1'] }}"
+ dnetworks: "{{ dnetworks + [pname ~ '_default'] }}"
+
+ - name: Create project directory
+ file:
+ path: '{{ project_src }}'
+ state: directory
+
+ - name: Make sure images are not around
+ docker_image_remove:
+ name: '{{ item }}'
+ loop:
+ - '{{ non_existing_image }}'
+ - '{{ docker_test_image_alpine }}'
+
+####################################################################
+## Missing image ###################################################
+####################################################################
+
+ - name: Template project file with non-existing image
+ copy:
+ dest: '{{ project_src }}/docker-compose.yml'
+ content: '{{ test_service_non_existing }}'
+
+ - name: Pull (check)
+ docker_compose_v2_pull:
+ project_src: '{{ project_src }}'
+ check_mode: true
+ register: pull_1_check
+ ignore_errors: true
+
+ - name: Pull
+ docker_compose_v2_pull:
+ project_src: '{{ project_src }}'
+ register: pull_1
+ ignore_errors: true
+
+ - assert:
+ that:
+ - pull_1_check is failed or pull_1_check is changed
+ - pull_1_check is changed or pull_1_check.msg.startswith('Error when processing ')
+ - pull_1 is failed
+ - pull_1.msg.startswith('Error when processing ')
+
+####################################################################
+## Regular image ###################################################
+####################################################################
+
+ - name: Template project file with Alpine image
+ copy:
+ dest: '{{ project_src }}/docker-compose.yml'
+ content: '{{ test_service_alpine }}'
+
+ - when: docker_compose_version is version('2.22.0', '>=')
+ block:
+ - name: Pull with policy=missing (check)
+ docker_compose_v2_pull:
+ project_src: '{{ project_src }}'
+ policy: missing
+ check_mode: true
+ register: pull_1_check
+
+ - name: Pull with policy=missing
+ docker_compose_v2_pull:
+ project_src: '{{ project_src }}'
+ policy: missing
+ register: pull_1
+
+ - name: Pull with policy=missing (idempotent, check)
+ docker_compose_v2_pull:
+ project_src: '{{ project_src }}'
+ policy: missing
+ check_mode: true
+ register: pull_2_check
+
+ - name: Pull with policy=missing (idempotent)
+ docker_compose_v2_pull:
+ project_src: '{{ project_src }}'
+ policy: missing
+ register: pull_2
+
+ - name: Make sure image is not around
+ docker_image_remove:
+ name: '{{ docker_test_image_alpine }}'
+
+ - name: Pull with policy=always (check)
+ docker_compose_v2_pull:
+ project_src: '{{ project_src }}'
+ policy: always
+ check_mode: true
+ register: pull_3_check
+
+ - name: Pull with policy=always
+ docker_compose_v2_pull:
+ project_src: '{{ project_src }}'
+ policy: always
+ register: pull_3
+
+ - name: Pull with policy=always (check, idempotent)
+ docker_compose_v2_pull:
+ project_src: '{{ project_src }}'
+ policy: always
+ check_mode: true
+ register: pull_4_check
+
+ - name: Pull with policy=always (idempotent)
+ docker_compose_v2_pull:
+ project_src: '{{ project_src }}'
+ policy: always
+ register: pull_4
+
+ - assert:
+ that:
+ - pull_1_check is changed
+ - pull_1_check.actions | selectattr('status', 'eq', 'Pulling') | first
+ - pull_1 is changed
+ - pull_1.actions | selectattr('status', 'eq', 'Pulling') | first
+ - pull_2_check is not changed
+ - pull_2 is not changed
+ - pull_3_check is changed
+ - pull_3_check.actions | selectattr('status', 'eq', 'Pulling') | first
+ - pull_3 is changed
+ - pull_3.actions | selectattr('status', 'eq', 'Pulling') | first
+ - pull_4_check is changed
+ - pull_4_check.actions | selectattr('status', 'eq', 'Pulling') | first
+ - pull_4 is not changed
+ - pull_4.actions | selectattr('status', 'eq', 'Pulling') | first
+
+ - when: docker_compose_version is version('2.22.0', '<')
+ block:
+ - name: Pull with policy=always (check)
+ docker_compose_v2_pull:
+ project_src: '{{ project_src }}'
+ policy: always
+ check_mode: true
+ register: pull_1_check
+
+ - name: Pull with policy=always
+ docker_compose_v2_pull:
+ project_src: '{{ project_src }}'
+ policy: always
+ register: pull_1
+
+ - name: Pull with policy=always (again, check)
+ docker_compose_v2_pull:
+ project_src: '{{ project_src }}'
+ policy: always
+ check_mode: true
+ register: pull_2_check
+
+ - name: Pull with policy=always (again)
+ docker_compose_v2_pull:
+ project_src: '{{ project_src }}'
+ policy: always
+ register: pull_2
+
+ - assert:
+ that:
+ - pull_1_check is changed
+ - pull_1_check.actions | selectattr('status', 'eq', 'Pulling') | first
+ - pull_1 is changed
+ - pull_1.actions | selectattr('status', 'eq', 'Pulling') | first
+ - pull_2_check is changed
+ - pull_2_check.actions | selectattr('status', 'eq', 'Pulling') | first
+ - pull_2 is not changed
+ - pull_2.actions | selectattr('status', 'eq', 'Pulling') | first
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_config/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_config/meta/main.yml
index 2650229d8..9eeb6626b 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_config/meta/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_config/meta/main.yml
@@ -5,4 +5,5 @@
dependencies:
- setup_docker
+ - setup_docker_sdk_for_python
- setup_remote_tmp_dir
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_container/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_container/meta/main.yml
index 5769ff1cb..471ddd412 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_container/meta/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_container/meta/main.yml
@@ -5,3 +5,4 @@
dependencies:
- setup_docker
+ - setup_docker_python_deps
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_container/tasks/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_container/tasks/main.yml
index 9911452f9..2236bc803 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_container/tasks/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_container/tasks/main.yml
@@ -34,30 +34,31 @@
# Run the tests
- block:
- - include_tasks: run-test.yml
- with_fileglob:
- - "tests/*.yml"
+ - include_tasks: run-test.yml
+ with_fileglob:
+ - "tests/*.yml"
+ loop_control:
+ loop_var: test_name
always:
- - name: "Make sure all containers are removed"
- docker_container:
- name: "{{ item }}"
- state: absent
- force_kill: true
- with_items: "{{ cnames }}"
- diff: false
- - name: "Make sure all images are removed"
- docker_image:
- name: "{{ item }}"
- state: absent
- with_items: "{{ inames }}"
- - name: "Make sure all networks are removed"
- docker_network:
- name: "{{ item }}"
- state: absent
- force: true
- with_items: "{{ dnetworks }}"
- diff: false
+ - name: "Make sure all containers are removed"
+ docker_container:
+ name: "{{ item }}"
+ state: absent
+ force_kill: true
+ with_items: "{{ cnames }}"
+ diff: false
+ - name: "Make sure all images are removed"
+ docker_image_remove:
+ name: "{{ item }}"
+ with_items: "{{ inames }}"
+ - name: "Make sure all networks are removed"
+ docker_network:
+ name: "{{ item }}"
+ state: absent
+ force: true
+ with_items: "{{ dnetworks }}"
+ diff: false
when: docker_api_version is version('1.25', '>=')
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_container/tasks/run-test.yml b/ansible_collections/community/docker/tests/integration/targets/docker_container/tasks/run-test.yml
index 65853ddd8..72a58962d 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_container/tasks/run-test.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_container/tasks/run-test.yml
@@ -3,5 +3,5 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
-- name: "Loading tasks from {{ item }}"
- include_tasks: "{{ item }}"
+- name: "Loading tasks from {{ test_name }}"
+ include_tasks: "{{ test_name }}"
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_container/tasks/tests/comparisons.yml b/ansible_collections/community/docker/tests/integration/targets/docker_container/tasks/tests/comparisons.yml
index 54f0d4a62..c37a0c4df 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_container/tasks/tests/comparisons.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_container/tasks/tests/comparisons.yml
@@ -384,9 +384,8 @@
- name: Pull {{ docker_test_image_hello_world }} image to make sure wildcard_2 test succeeds
# If the image isn't there, it will pull it and return 'changed'.
- docker_image:
+ docker_image_pull:
name: "{{ docker_test_image_hello_world }}"
- source: pull
- name: wildcard
docker_container:
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_container/tasks/tests/image-ids.yml b/ansible_collections/community/docker/tests/integration/targets/docker_container/tasks/tests/image-ids.yml
index 76270c68a..4dfdb02a6 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_container/tasks/tests/image-ids.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_container/tasks/tests/image-ids.yml
@@ -11,9 +11,8 @@
cnames: "{{ cnames + [cname] }}"
- name: Pull images
- docker_image:
+ docker_image_pull:
name: "{{ image }}"
- source: pull
loop:
- "{{ docker_test_image_hello_world }}"
- "{{ docker_test_image_alpine }}"
@@ -69,10 +68,9 @@
- name: Untag image
# Image will not be deleted since the container still uses it
- docker_image:
+ docker_image_remove:
name: "{{ docker_test_image_alpine }}"
- force_absent: true
- state: absent
+ force: true
- name: Create container with {{ docker_test_image_alpine }} image via name (check mode, will pull, same image)
docker_container:
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_container/tasks/tests/options.yml b/ansible_collections/community/docker/tests/integration/targets/docker_container/tasks/tests/options.yml
index 1254fb52d..845c7897a 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_container/tasks/tests/options.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_container/tasks/tests/options.yml
@@ -2235,9 +2235,8 @@
- name: Pull images to make sure ignore_image test succeeds
# If the image isn't there, it will pull it and return 'changed'.
- docker_image:
+ docker_image_pull:
name: "{{ item }}"
- source: pull
loop:
- "{{ docker_test_image_hello_world }}"
- "{{ docker_test_image_registry_nginx }}"
@@ -2456,9 +2455,8 @@
diff: false
- name: cleanup image
- docker_image:
+ docker_image_remove:
name: "{{ iname_labels }}"
- state: absent
diff: false
- assert:
@@ -2486,9 +2484,8 @@
- name: Pull images to make sure ignore_image test succeeds
# If the image isn't there, it will pull it and return 'changed'.
- docker_image:
+ docker_image_pull:
name: "{{ item }}"
- source: pull
loop:
- "{{ docker_test_image_hello_world }}"
- "{{ docker_test_image_registry_nginx }}"
@@ -2577,9 +2574,8 @@
inames: "{{ inames + [iname_name_mismatch] }}"
- name: Tag hello world image (pulled earlier) with new name
- docker_image:
+ docker_image_tag:
name: "{{ docker_test_image_registry_nginx }}"
- source: local
repository: "{{ iname_name_mismatch }}:latest"
- name: image_name_mismatch
@@ -2617,9 +2613,8 @@
diff: false
- name: Cleanup image
- docker_image:
+ docker_image_remove:
name: "{{ iname_name_mismatch }}"
- state: absent
diff: false
- assert:
@@ -3015,46 +3010,48 @@ avoid such warnings, please quote the value.' in (log_options_2.warnings | defau
## mac_address #####################################################
####################################################################
-- name: mac_address
- docker_container:
- image: "{{ docker_test_image_alpine }}"
- command: '/bin/sh -c "sleep 10m"'
- name: "{{ cname }}"
- mac_address: 92:d0:c6:0a:29:33
- state: started
- register: mac_address_1
-
-- name: mac_address (idempotency)
- docker_container:
- image: "{{ docker_test_image_alpine }}"
- command: '/bin/sh -c "sleep 10m"'
- name: "{{ cname }}"
- mac_address: 92:d0:c6:0a:29:33
- state: started
- register: mac_address_2
-
-- name: mac_address (change)
- docker_container:
- image: "{{ docker_test_image_alpine }}"
- command: '/bin/sh -c "sleep 10m"'
- name: "{{ cname }}"
- mac_address: 92:d0:c6:0a:29:44
- state: started
- force_kill: true
- register: mac_address_3
-
-- name: cleanup
- docker_container:
- name: "{{ cname }}"
- state: absent
- force_kill: true
- diff: false
-
-- assert:
- that:
- - mac_address_1 is changed
- - mac_address_2 is not changed
- - mac_address_3 is changed
+- when: docker_api_version is version('1.44', '<')
+ block:
+ - name: mac_address
+ docker_container:
+ image: "{{ docker_test_image_alpine }}"
+ command: '/bin/sh -c "sleep 10m"'
+ name: "{{ cname }}"
+ mac_address: 92:d0:c6:0a:29:33
+ state: started
+ register: mac_address_1
+
+ - name: mac_address (idempotency)
+ docker_container:
+ image: "{{ docker_test_image_alpine }}"
+ command: '/bin/sh -c "sleep 10m"'
+ name: "{{ cname }}"
+ mac_address: 92:d0:c6:0a:29:33
+ state: started
+ register: mac_address_2
+
+ - name: mac_address (change)
+ docker_container:
+ image: "{{ docker_test_image_alpine }}"
+ command: '/bin/sh -c "sleep 10m"'
+ name: "{{ cname }}"
+ mac_address: 92:d0:c6:0a:29:44
+ state: started
+ force_kill: true
+ register: mac_address_3
+
+ - name: cleanup
+ docker_container:
+ name: "{{ cname }}"
+ state: absent
+ force_kill: true
+ diff: false
+
+ - assert:
+ that:
+ - mac_address_1 is changed
+ - mac_address_2 is not changed
+ - mac_address_3 is changed
####################################################################
## memory ##########################################################
@@ -3549,9 +3546,8 @@ avoid such warnings, please quote the value.' in (log_options_2.warnings | defau
####################################################################
- name: Remove hello-world image
- docker_image:
+ docker_image_remove:
name: hello-world:latest
- state: absent
- name: platform
docker_container:
@@ -3564,17 +3560,38 @@ avoid such warnings, please quote the value.' in (log_options_2.warnings | defau
register: platform_1
ignore_errors: true
-- name: platform (idempotency)
+- name: platform (idempotency with full name)
+ # Docker daemon only returns 'linux' as the platform for the container,
+ # so this has to be handled correctly by our additional code
docker_container:
image: hello-world:latest
name: "{{ cname }}"
state: present
- # The container always reports 'linux' as platform instead of 'linux/amd64'...
- platform: linux
+ platform: linux/amd64
debug: true
register: platform_2
ignore_errors: true
+- name: platform (idempotency with shorter name)
+ docker_container:
+ image: hello-world:latest
+ name: "{{ cname }}"
+ state: present
+ platform: linux
+ debug: true
+ register: platform_3
+ ignore_errors: true
+
+- name: platform (idempotency with shorter name)
+ docker_container:
+ image: hello-world:latest
+ name: "{{ cname }}"
+ state: present
+ platform: amd64
+ debug: true
+ register: platform_4
+ ignore_errors: true
+
- name: platform (changed)
docker_container:
image: hello-world:latest
@@ -3587,7 +3604,19 @@ avoid such warnings, please quote the value.' in (log_options_2.warnings | defau
comparisons:
# Do not restart because of the changed image ID
image: ignore
- register: platform_3
+ register: platform_5
+ ignore_errors: true
+
+- name: platform (idempotency)
+ docker_container:
+ image: hello-world:latest
+ name: "{{ cname }}"
+ state: present
+ pull: true
+ platform: 386
+ force_kill: true
+ debug: true
+ register: platform_6
ignore_errors: true
- name: cleanup
@@ -3601,7 +3630,10 @@ avoid such warnings, please quote the value.' in (log_options_2.warnings | defau
that:
- platform_1 is changed
- platform_2 is not changed and platform_2 is not failed
- - platform_3 is changed
+ - platform_3 is not changed and platform_3 is not failed
+ - platform_4 is not changed and platform_4 is not failed
+ - platform_5 is changed
+ - platform_6 is not changed and platform_6 is not failed
when: docker_api_version is version('1.41', '>=')
- assert:
that:
@@ -3611,6 +3643,149 @@ avoid such warnings, please quote the value.' in (log_options_2.warnings | defau
when: docker_api_version is version('1.41', '<')
####################################################################
+## pull / pull_check_mode_behavior #################################
+####################################################################
+
+- name: Remove hello-world image
+ docker_image_remove:
+ name: "{{ docker_test_image_hello_world }}"
+
+- name: pull (pull=never)
+ docker_container:
+ image: "{{ docker_test_image_hello_world }}"
+ name: "{{ cname }}"
+ state: present
+ pull: never
+ debug: true
+ register: pull_1
+ ignore_errors: true
+
+- name: pull (pull=missing, check mode)
+ docker_container:
+ image: "{{ docker_test_image_hello_world }}"
+ name: "{{ cname }}"
+ state: present
+ pull: missing
+ debug: true
+ register: pull_2
+ check_mode: true
+ ignore_errors: true
+
+- name: pull (pull=missing)
+ docker_container:
+ image: "{{ docker_test_image_hello_world }}"
+ name: "{{ cname }}"
+ state: present
+ pull: missing
+ debug: true
+ register: pull_3
+ ignore_errors: true
+
+- name: pull (pull=missing, idempotent, check mode)
+ docker_container:
+ image: "{{ docker_test_image_hello_world }}"
+ name: "{{ cname }}"
+ state: present
+ pull: missing
+ debug: true
+ register: pull_4
+ check_mode: true
+ ignore_errors: true
+
+- name: pull (pull=missing, idempotent)
+ docker_container:
+ image: "{{ docker_test_image_hello_world }}"
+ name: "{{ cname }}"
+ state: present
+ pull: missing
+ debug: true
+ register: pull_5
+ ignore_errors: true
+
+- name: pull (pull=always, check mode, pull_check_mode_behavior=image_not_present)
+ docker_container:
+ image: "{{ docker_test_image_hello_world }}"
+ name: "{{ cname }}"
+ state: present
+ pull: always
+ pull_check_mode_behavior: image_not_present
+ debug: true
+ register: pull_6
+ check_mode: true
+ ignore_errors: true
+
+- name: pull (pull=always, check mode, pull_check_mode_behavior=always)
+ docker_container:
+ image: "{{ docker_test_image_hello_world }}"
+ name: "{{ cname }}"
+ state: present
+ pull: always
+ pull_check_mode_behavior: always
+ debug: true
+ register: pull_7
+ check_mode: true
+ ignore_errors: true
+
+- name: pull (pull=always)
+ docker_container:
+ image: "{{ docker_test_image_hello_world }}"
+ name: "{{ cname }}"
+ state: present
+ pull: always
+ debug: true
+ register: pull_8
+ ignore_errors: true
+
+- name: cleanup
+ docker_container:
+ name: "{{ cname }}"
+ state: absent
+ force_kill: true
+ diff: false
+
+- assert:
+ that:
+ - pull_1 is failed
+ - pull_1.msg == ("Cannot find image with name " ~ docker_test_image_hello_world ~ ", and pull=never")
+ - pull_2 is changed
+ - pulled_image_action not in pull_2.actions
+ - pulled_image_action_changed in pull_2.actions
+ - pulled_image_action_unchanged not in pull_2.actions
+ - pull_3 is changed
+ - pulled_image_action not in pull_3.actions
+ - pulled_image_action_changed in pull_3.actions
+ - pulled_image_action_unchanged not in pull_3.actions
+ - pull_4 is not changed
+ - pulled_image_action not in pull_4.actions
+ - pulled_image_action_changed not in pull_4.actions
+ - pulled_image_action_unchanged not in pull_4.actions
+ - pull_5 is not changed
+ - pulled_image_action not in pull_5.actions
+ - pulled_image_action_changed not in pull_5.actions
+ - pulled_image_action_unchanged not in pull_5.actions
+ - pull_6 is not changed
+ - pulled_image_action not in pull_6.actions
+ - pulled_image_action_changed not in pull_6.actions
+ - pulled_image_action_unchanged not in pull_6.actions
+ - pull_7 is changed
+ - pulled_image_action in pull_7.actions
+ - pulled_image_action_changed not in pull_7.actions
+ - pulled_image_action_unchanged not in pull_7.actions
+ - pull_8 is not changed
+ - pulled_image_action not in pull_8.actions
+ - pulled_image_action_changed not in pull_8.actions
+ - pulled_image_action_unchanged in pull_8.actions
+ vars:
+ pulled_image_action:
+ pulled_image: "{{ docker_test_image_hello_world }}"
+ pulled_image_action_changed:
+ pulled_image: "{{ docker_test_image_hello_world }}"
+ changed: true
+ pulled_image_action_unchanged:
+ pulled_image: "{{ docker_test_image_hello_world }}"
+ changed: false
+
+####################################################################
## privileged ######################################################
####################################################################
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_container_copy_into/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_container_copy_into/meta/main.yml
index 2650229d8..f5b897895 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_container_copy_into/meta/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_container_copy_into/meta/main.yml
@@ -5,4 +5,5 @@
dependencies:
- setup_docker
+ - setup_docker_python_deps
- setup_remote_tmp_dir
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_container_copy_into/tasks/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_container_copy_into/tasks/main.yml
index 20f9a2681..7eb1b86a3 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_container_copy_into/tasks/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_container_copy_into/tasks/main.yml
@@ -26,18 +26,20 @@
# Run the tests
- block:
- - include_tasks: run-test.yml
- with_fileglob:
- - "tests/*.yml"
+ - include_tasks: run-test.yml
+ with_fileglob:
+ - "tests/*.yml"
+ loop_control:
+ loop_var: test_name
always:
- - name: "Make sure all containers are removed"
- docker_container:
- name: "{{ item }}"
- state: absent
- force_kill: true
- with_items: "{{ cnames }}"
- diff: false
+ - name: "Make sure all containers are removed"
+ docker_container:
+ name: "{{ item }}"
+ state: absent
+ force_kill: true
+ with_items: "{{ cnames }}"
+ diff: false
when: docker_api_version is version('1.25', '>=')
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_container_copy_into/tasks/run-test.yml b/ansible_collections/community/docker/tests/integration/targets/docker_container_copy_into/tasks/run-test.yml
index 65853ddd8..72a58962d 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_container_copy_into/tasks/run-test.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_container_copy_into/tasks/run-test.yml
@@ -3,5 +3,5 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
-- name: "Loading tasks from {{ item }}"
- include_tasks: "{{ item }}"
+- name: "Loading tasks from {{ test_name }}"
+ include_tasks: "{{ test_name }}"
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_container_exec/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_container_exec/meta/main.yml
index 5769ff1cb..471ddd412 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_container_exec/meta/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_container_exec/meta/main.yml
@@ -5,3 +5,4 @@
dependencies:
- setup_docker
+ - setup_docker_python_deps
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_container_info/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_container_info/meta/main.yml
index 5769ff1cb..471ddd412 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_container_info/meta/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_container_info/meta/main.yml
@@ -5,3 +5,4 @@
dependencies:
- setup_docker
+ - setup_docker_python_deps
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_host_info/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_host_info/meta/main.yml
index 5769ff1cb..471ddd412 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_host_info/meta/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_host_info/meta/main.yml
@@ -5,3 +5,4 @@
dependencies:
- setup_docker
+ - setup_docker_python_deps
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_host_info/tasks/test_host_info.yml b/ansible_collections/community/docker/tests/integration/targets/docker_host_info/tasks/test_host_info.yml
index 0d090db97..b4871d3e3 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_host_info/tasks/test_host_info.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_host_info/tasks/test_host_info.yml
@@ -91,7 +91,7 @@
- name: assert container is returned when filters are matched (single label)
assert:
- that: "{{ output.containers | length }} == 1"
+ that: "output.containers | length == 1"
- name: Get info on Docker host and list containers matching filters (multiple labels)
docker_host_info:
@@ -104,7 +104,7 @@
- name: assert container is returned when filters are matched (multiple labels)
assert:
- that: "{{ output.containers | length }} == 1"
+ that: "output.containers | length == 1"
- name: Get info on Docker host and do not list containers which do not match filters
docker_host_info:
@@ -118,7 +118,7 @@
- name: assert no container is returned when filters are not matched
assert:
- that: "{{ output.containers | length }} == 0"
+ that: "output.containers | length == 0"
- name: Get info on Docker host and list containers matching filters (single label, not all containers)
docker_host_info:
@@ -139,8 +139,8 @@
- name: assert one resp. two container is returned
assert:
that:
- - "{{ output.containers | length }} == 1"
- - "{{ output_all.containers | length }} == 2"
+ - "output.containers | length == 1"
+ - "output_all.containers | length == 2"
- name: Get info on Docker host and list containers with verbose output
docker_host_info:
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_image/meta/main.yml
index f7ba9ab1b..511f9e419 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_image/meta/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image/meta/main.yml
@@ -5,4 +5,5 @@
dependencies:
- setup_docker_registry
+ - setup_docker_python_deps
- setup_remote_tmp_dir
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image/tasks/run-test.yml b/ansible_collections/community/docker/tests/integration/targets/docker_image/tasks/run-test.yml
index 65853ddd8..72a58962d 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_image/tasks/run-test.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image/tasks/run-test.yml
@@ -3,5 +3,5 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
-- name: "Loading tasks from {{ item }}"
- include_tasks: "{{ item }}"
+- name: "Loading tasks from {{ test_name }}"
+ include_tasks: "{{ test_name }}"
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image/tasks/test.yml b/ansible_collections/community/docker/tests/integration/targets/docker_image/tasks/test.yml
index 50bb84ffc..ea3b47dd3 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_image/tasks/test.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image/tasks/test.yml
@@ -31,22 +31,24 @@
- StagedDockerfile
- block:
- - include_tasks: run-test.yml
- with_fileglob:
- - "tests/*.yml"
+ - include_tasks: run-test.yml
+ with_fileglob:
+ - "tests/*.yml"
+ loop_control:
+ loop_var: test_name
always:
- - name: "Make sure all images are removed"
- docker_image:
- name: "{{ item }}"
- state: absent
- with_items: "{{ inames }}"
- - name: "Make sure all containers are removed"
- docker_container:
- name: "{{ item }}"
- state: absent
- force_kill: true
- with_items: "{{ cnames }}"
+ - name: "Make sure all images are removed"
+ docker_image:
+ name: "{{ item }}"
+ state: absent
+ with_items: "{{ inames }}"
+ - name: "Make sure all containers are removed"
+ docker_container:
+ name: "{{ item }}"
+ state: absent
+ force_kill: true
+ with_items: "{{ cnames }}"
when: docker_api_version is version('1.25', '>=')
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image/tasks/tests/basic.yml b/ansible_collections/community/docker/tests/integration/targets/docker_image/tasks/tests/basic.yml
index 78b4f7738..068e92f4e 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_image/tasks/tests/basic.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image/tasks/tests/basic.yml
@@ -117,7 +117,7 @@
register: fail_3
ignore_errors: true
-- name: buildargs
+- name: Build image ID (must fail)
docker_image:
source: build
name: "{{ present_1.image.Id }}"
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image/tasks/tests/docker_image.yml b/ansible_collections/community/docker/tests/integration/targets/docker_image/tasks/tests/docker_image.yml
index a13eb691f..ffd427fd2 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_image/tasks/tests/docker_image.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image/tasks/tests/docker_image.yml
@@ -9,8 +9,8 @@
- name: Determining pushed image names
set_fact:
- hello_world_image_base: "{{ registry_address }}/test/hello-world"
- test_image_base: "{{ registry_address }}/test/{{ iname }}"
+ hello_world_image_base: "{{ registry_address | default('localhost') }}/test/hello-world"
+ test_image_base: "{{ registry_address | default('localhost') }}/test/{{ iname }}"
- name: Registering image name
set_fact:
@@ -20,179 +20,182 @@
## interact with test registry #####################################
####################################################################
-- name: Make sure image is not there
- docker_image:
- name: "{{ hello_world_image_base }}:latest"
- state: absent
- force_absent: true
-
-- name: Make sure we have {{ docker_test_image_hello_world }}
- docker_image:
- name: "{{ docker_test_image_hello_world }}"
- source: pull
-
-- name: Push image to test registry
- docker_image:
- name: "{{ docker_test_image_hello_world }}"
- repository: "{{ hello_world_image_base }}:latest"
- push: true
- source: local
- register: push_1
-
-- name: Push image to test registry (idempotent)
- docker_image:
- name: "{{ docker_test_image_hello_world }}"
- repository: "{{ hello_world_image_base }}:latest"
- push: true
- source: local
- register: push_2
-
-- name: Push image to test registry (force, still idempotent)
- docker_image:
- name: "{{ docker_test_image_hello_world }}"
- repository: "{{ hello_world_image_base }}:latest"
- push: true
- source: local
- force_tag: true
- register: push_3
-
-- assert:
- that:
- - push_1 is changed
- - push_2 is not changed
- - push_3 is not changed
-
-- name: Get facts of local image
- docker_image_info:
- name: "{{ hello_world_image_base }}:latest"
- register: facts_1
-
-- name: Make sure image is not there
- docker_image:
- name: "{{ hello_world_image_base }}:latest"
- state: absent
- force_absent: true
-
-- name: Get facts of local image (absent)
- docker_image_info:
- name: "{{ hello_world_image_base }}:latest"
- register: facts_2
-
-- name: Pull image from test registry
- docker_image:
- name: "{{ hello_world_image_base }}:latest"
- state: present
- source: pull
- register: pull_1
-
-- name: Pull image from test registry (idempotency)
- docker_image:
- name: "{{ hello_world_image_base }}:latest"
- state: present
- source: pull
- register: pull_2
-
-- name: Get facts of local image (present)
- docker_image_info:
- name: "{{ hello_world_image_base }}:latest"
- register: facts_3
-
-- assert:
- that:
- - pull_1 is changed
- - pull_2 is not changed
- - facts_1.images | length == 1
- - facts_2.images | length == 0
- - facts_3.images | length == 1
-
-- name: Pull image from test registry (with digest)
- docker_image:
- name: "{{ facts_3.images[0].RepoDigests[0] }}"
- state: present
- source: pull
- force_source: true
- register: pull_digest
-
-- name: Make sure that changed is still false
- assert:
- that:
- - pull_digest is not changed
-
-- name: Tag different image with new tag
- docker_image:
- name: "{{ docker_test_image_alpine_different }}"
- repository: "{{ hello_world_image_base }}:newtag"
- push: false
- source: pull
-
-- name: Push different image with new tag
- docker_image:
- name: "{{ hello_world_image_base }}"
- repository: "{{ hello_world_image_base }}"
- tag: newtag
- push: true
- source: local
- register: push_1_different
-
-- name: Push different image with new tag (idempotent)
- docker_image:
- name: "{{ hello_world_image_base }}"
- repository: "{{ hello_world_image_base }}"
- tag: newtag
- push: true
- source: local
- register: push_2_different
-
-- assert:
- that:
- - push_1_different is changed
- - push_2_different is not changed
-
-- name: Tag same image with new tag
- docker_image:
- name: "{{ docker_test_image_alpine_different }}"
- repository: "{{ hello_world_image_base }}:newtag2"
- push: false
- source: pull
-
-- name: Push same image with new tag
- docker_image:
- name: "{{ hello_world_image_base }}"
- repository: "{{ hello_world_image_base }}"
- tag: newtag2
- push: true
- source: local
- register: push_1_same
-
-- name: Push same image with new tag (idempotent)
- docker_image:
- name: "{{ hello_world_image_base }}"
- repository: "{{ hello_world_image_base }}"
- tag: newtag2
- push: true
- source: local
- register: push_2_same
-
-- assert:
- that:
- # NOTE: This should be:
- # - push_1_same is changed
- # Unfortunately docker does *NOT* report whether the tag already existed or not.
- # Here are the logs returned by client.push() for both tasks (which are exactly the same):
- # push_1_same:
- # {"status": "The push refers to repository [localhost:32796/test/hello-world]"},
- # {"id": "3fc64803ca2d", "progressDetail": {}, "status": "Preparing"},
- # {"id": "3fc64803ca2d", "progressDetail": {}, "status": "Layer already exists"},
- # {"status": "newtag2: digest: sha256:92251458088c638061cda8fd8b403b76d661a4dc6b7ee71b6affcf1872557b2b size: 528"},
- # {"aux": {"Digest": "sha256:92251458088c638061cda8fd8b403b76d661a4dc6b7ee71b6affcf1872557b2b", "Size": 528, "Tag": "newtag2"}, "progressDetail": {}}
- # push_2_same:
- # {"status": "The push refers to repository [localhost:32796/test/hello-world]"},
- # {"id": "3fc64803ca2d", "progressDetail": {}, "status": "Preparing"},
- # {"id": "3fc64803ca2d", "progressDetail": {}, "status": "Layer already exists"},
- # {"status": "newtag2: digest: sha256:92251458088c638061cda8fd8b403b76d661a4dc6b7ee71b6affcf1872557b2b size: 528"},
- # {"aux": {"Digest": "sha256:92251458088c638061cda8fd8b403b76d661a4dc6b7ee71b6affcf1872557b2b", "Size": 528, "Tag": "newtag2"}, "progressDetail": {}}
- - push_1_same is not changed
- - push_2_same is not changed
+- name: Run registry tests only when registry is present
+ when: registry_address is defined
+ block:
+ - name: Make sure image is not there
+ docker_image:
+ name: "{{ hello_world_image_base }}:latest"
+ state: absent
+ force_absent: true
+
+ - name: Make sure we have {{ docker_test_image_hello_world }}
+ docker_image:
+ name: "{{ docker_test_image_hello_world }}"
+ source: pull
+
+ - name: Push image to test registry
+ docker_image:
+ name: "{{ docker_test_image_hello_world }}"
+ repository: "{{ hello_world_image_base }}:latest"
+ push: true
+ source: local
+ register: push_1
+
+ - name: Push image to test registry (idempotent)
+ docker_image:
+ name: "{{ docker_test_image_hello_world }}"
+ repository: "{{ hello_world_image_base }}:latest"
+ push: true
+ source: local
+ register: push_2
+
+ - name: Push image to test registry (force, still idempotent)
+ docker_image:
+ name: "{{ docker_test_image_hello_world }}"
+ repository: "{{ hello_world_image_base }}:latest"
+ push: true
+ source: local
+ force_tag: true
+ register: push_3
+
+ - assert:
+ that:
+ - push_1 is changed
+ - push_2 is not changed
+ - push_3 is not changed
+
+ - name: Get facts of local image
+ docker_image_info:
+ name: "{{ hello_world_image_base }}:latest"
+ register: facts_1
+
+ - name: Make sure image is not there
+ docker_image:
+ name: "{{ hello_world_image_base }}:latest"
+ state: absent
+ force_absent: true
+
+ - name: Get facts of local image (absent)
+ docker_image_info:
+ name: "{{ hello_world_image_base }}:latest"
+ register: facts_2
+
+ - name: Pull image from test registry
+ docker_image:
+ name: "{{ hello_world_image_base }}:latest"
+ state: present
+ source: pull
+ register: pull_1
+
+ - name: Pull image from test registry (idempotency)
+ docker_image:
+ name: "{{ hello_world_image_base }}:latest"
+ state: present
+ source: pull
+ register: pull_2
+
+ - name: Get facts of local image (present)
+ docker_image_info:
+ name: "{{ hello_world_image_base }}:latest"
+ register: facts_3
+
+ - assert:
+ that:
+ - pull_1 is changed
+ - pull_2 is not changed
+ - facts_1.images | length == 1
+ - facts_2.images | length == 0
+ - facts_3.images | length == 1
+
+ - name: Pull image from test registry (with digest)
+ docker_image:
+ name: "{{ hello_world_image_base }}@{{ facts_3.images[0].RepoDigests[0] | regex_replace('.*@', '') }}"
+ state: present
+ source: pull
+ force_source: true
+ register: pull_digest
+
+ - name: Make sure that changed is still false
+ assert:
+ that:
+ - pull_digest is not changed
+
+ - name: Tag different image with new tag
+ docker_image:
+ name: "{{ docker_test_image_alpine_different }}"
+ repository: "{{ hello_world_image_base }}:newtag"
+ push: false
+ source: pull
+
+ - name: Push different image with new tag
+ docker_image:
+ name: "{{ hello_world_image_base }}"
+ repository: "{{ hello_world_image_base }}"
+ tag: newtag
+ push: true
+ source: local
+ register: push_1_different
+
+ - name: Push different image with new tag (idempotent)
+ docker_image:
+ name: "{{ hello_world_image_base }}"
+ repository: "{{ hello_world_image_base }}"
+ tag: newtag
+ push: true
+ source: local
+ register: push_2_different
+
+ - assert:
+ that:
+ - push_1_different is changed
+ - push_2_different is not changed
+
+ - name: Tag same image with new tag
+ docker_image:
+ name: "{{ docker_test_image_alpine_different }}"
+ repository: "{{ hello_world_image_base }}:newtag2"
+ push: false
+ source: pull
+
+ - name: Push same image with new tag
+ docker_image:
+ name: "{{ hello_world_image_base }}"
+ repository: "{{ hello_world_image_base }}"
+ tag: newtag2
+ push: true
+ source: local
+ register: push_1_same
+
+ - name: Push same image with new tag (idempotent)
+ docker_image:
+ name: "{{ hello_world_image_base }}"
+ repository: "{{ hello_world_image_base }}"
+ tag: newtag2
+ push: true
+ source: local
+ register: push_2_same
+
+ - assert:
+ that:
+ # NOTE: This should be:
+ # - push_1_same is changed
+ # Unfortunately docker does *NOT* report whether the tag already existed or not.
+ # Here are the logs returned by client.push() for both tasks (which are exactly the same):
+ # push_1_same:
+ # {"status": "The push refers to repository [localhost:32796/test/hello-world]"},
+ # {"id": "3fc64803ca2d", "progressDetail": {}, "status": "Preparing"},
+ # {"id": "3fc64803ca2d", "progressDetail": {}, "status": "Layer already exists"},
+ # {"status": "newtag2: digest: sha256:92251458088c638061cda8fd8b403b76d661a4dc6b7ee71b6affcf1872557b2b size: 528"},
+ # {"aux": {"Digest": "sha256:92251458088c638061cda8fd8b403b76d661a4dc6b7ee71b6affcf1872557b2b", "Size": 528, "Tag": "newtag2"}, "progressDetail": {}}
+ # push_2_same:
+ # {"status": "The push refers to repository [localhost:32796/test/hello-world]"},
+ # {"id": "3fc64803ca2d", "progressDetail": {}, "status": "Preparing"},
+ # {"id": "3fc64803ca2d", "progressDetail": {}, "status": "Layer already exists"},
+ # {"status": "newtag2: digest: sha256:92251458088c638061cda8fd8b403b76d661a4dc6b7ee71b6affcf1872557b2b size: 528"},
+ # {"aux": {"Digest": "sha256:92251458088c638061cda8fd8b403b76d661a4dc6b7ee71b6affcf1872557b2b", "Size": 528, "Tag": "newtag2"}, "progressDetail": {}}
+ - push_1_same is not changed
+ - push_2_same is not changed
####################################################################
## repository ######################################################
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image/tasks/tests/options.yml b/ansible_collections/community/docker/tests/integration/targets/docker_image/tasks/tests/options.yml
index 0670f1332..b8f6c7002 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_image/tasks/tests/options.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image/tasks/tests/options.yml
@@ -76,7 +76,7 @@
build:
path: "{{ remote_tmp_dir }}/files"
container_limits:
- memory: 4000
+ memory: 4KB
pull: false
source: build
ignore_errors: true
@@ -88,8 +88,8 @@
build:
path: "{{ remote_tmp_dir }}/files"
container_limits:
- memory: 7000000
- memswap: 8000000
+ memory: 7MB
+ memswap: 8MB
pull: false
source: build
register: container_limits_2
@@ -444,3 +444,61 @@
- assert:
that:
- path_1 is changed
+
+####################################################################
+## build.shm_size ##################################################
+####################################################################
+
+- name: Build image with custom shm_size
+ docker_image:
+ name: "{{ iname }}"
+ build:
+ path: "{{ remote_tmp_dir }}/files"
+ dockerfile: "MyDockerfile"
+ pull: false
+ shm_size: 128MB
+ source: build
+ register: path_1
+
+- name: cleanup
+ docker_image:
+ name: "{{ iname }}"
+ state: absent
+ force_absent: true
+
+- assert:
+ that:
+ - path_1 is changed
+
+####################################################################
+## build.labels ####################################################
+####################################################################
+
+- name: Build image with labels
+ docker_image:
+ name: "{{ iname }}"
+ build:
+ path: "{{ remote_tmp_dir }}/files"
+ dockerfile: "MyDockerfile"
+ pull: false
+ labels:
+ FOO: BAR
+ this is a label: this is the label's value
+ source: build
+ register: labels_1
+
+- name: cleanup
+ docker_image:
+ name: "{{ iname }}"
+ state: absent
+ force_absent: true
+
+- name: Show image information
+ debug:
+ var: labels_1.image
+
+- assert:
+ that:
+ - labels_1 is changed
+ - labels_1.image.Config.Labels.FOO == 'BAR'
+ - labels_1.image.Config.Labels["this is a label"] == "this is the label's value"
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_build/aliases b/ansible_collections/community/docker/tests/integration/targets/docker_image_build/aliases
new file mode 100644
index 000000000..2e1acc0ad
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_build/aliases
@@ -0,0 +1,6 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+azp/4
+destructive
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_build/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_image_build/meta/main.yml
new file mode 100644
index 000000000..71ac98d4f
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_build/meta/main.yml
@@ -0,0 +1,10 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+dependencies:
+ - setup_docker_cli_buildx
+ # The Python dependencies are needed for the other modules
+ - setup_docker_python_deps
+ - setup_remote_tmp_dir
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_build/tasks/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_image_build/tasks/main.yml
new file mode 100644
index 000000000..88b23cfe7
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_build/tasks/main.yml
@@ -0,0 +1,13 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+####################################################################
+# WARNING: These are designed specifically for Ansible tests #
+# and should not be used as examples of how to write Ansible roles #
+####################################################################
+
+- when: ansible_facts.distribution ~ ansible_facts.distribution_major_version not in ['CentOS6', 'RedHat6']
+ include_tasks:
+ file: test.yml
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_build/tasks/run-test.yml b/ansible_collections/community/docker/tests/integration/targets/docker_image_build/tasks/run-test.yml
new file mode 100644
index 000000000..72a58962d
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_build/tasks/run-test.yml
@@ -0,0 +1,7 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: "Loading tasks from {{ test_name }}"
+ include_tasks: "{{ test_name }}"
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_build/tasks/test.yml b/ansible_collections/community/docker/tests/integration/targets/docker_image_build/tasks/test.yml
new file mode 100644
index 000000000..af6e75b22
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_build/tasks/test.yml
@@ -0,0 +1,59 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Create random name prefix
+ set_fact:
+ name_prefix: "{{ 'ansible-docker-test-%0x' % ((2**32) | random) }}"
+- name: Create image and container list
+ set_fact:
+ inames: []
+ cnames: []
+
+- debug:
+ msg: "Using name prefix {{ name_prefix }}"
+
+- name: Create files directory
+ file:
+ path: '{{ remote_tmp_dir }}/files'
+ state: directory
+
+- name: Template files
+ template:
+ src: '{{ item }}'
+ dest: '{{ remote_tmp_dir }}/files/{{ item }}'
+ loop:
+ - ArgsDockerfile
+ - Dockerfile
+ - EtcHostsDockerfile
+ - MyDockerfile
+ - StagedDockerfile
+
+- debug:
+ msg: "Has buildx plugin: {{ docker_has_buildx }}"
+
+- block:
+ - include_tasks: run-test.yml
+ with_fileglob:
+ - "tests/*.yml"
+ loop_control:
+ loop_var: test_name
+
+ always:
+ - name: "Make sure all images are removed"
+ docker_image:
+ name: "{{ item }}"
+ state: absent
+ with_items: "{{ inames }}"
+ - name: "Make sure all containers are removed"
+ docker_container:
+ name: "{{ item }}"
+ state: absent
+ force_kill: true
+ with_items: "{{ cnames }}"
+
+ when: docker_api_version is version('1.25', '>=') and docker_cli_version is version('19.03', '>=') and docker_has_buildx
+
+- fail: msg="Too old docker / docker-py version to run docker_image tests!"
+ when: not(docker_api_version is version('1.25', '>=') and docker_cli_version is version('19.03', '>=')) and (ansible_distribution != 'CentOS' or ansible_distribution_major_version|int > 6) and docker_has_buildx
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_build/tasks/tests/options.yml b/ansible_collections/community/docker/tests/integration/targets/docker_image_build/tasks/tests/options.yml
new file mode 100644
index 000000000..990035788
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_build/tasks/tests/options.yml
@@ -0,0 +1,204 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Registering image name
+ set_fact:
+ iname: "{{ name_prefix ~ '-options' }}"
+
+- name: Registering image name
+ set_fact:
+ inames: "{{ inames + [iname] }}"
+
+####################################################################
+## args ############################################################
+####################################################################
+
+- name: cleanup
+ docker_image_remove:
+ name: "{{ iname }}"
+
+- name: buildargs
+ docker_image_build:
+ name: "{{ iname }}"
+ path: "{{ remote_tmp_dir }}/files"
+ dockerfile: "ArgsDockerfile"
+ args:
+ IMAGE: "{{ docker_test_image_busybox }}"
+ TEST1: val1
+ TEST2: val2
+ TEST3: "True"
+ pull: false
+ register: buildargs_1
+
+- name: buildargs (idempotency)
+ docker_image_build:
+ name: "{{ iname }}"
+ path: "{{ remote_tmp_dir }}/files"
+ dockerfile: "ArgsDockerfile"
+ args:
+ IMAGE: "{{ docker_test_image_busybox }}"
+ TEST1: val1
+ TEST2: val2
+ TEST3: "True"
+ pull: false
+ register: buildargs_2
+
+- name: cleanup
+ docker_image_remove:
+ name: "{{ iname }}"
+
+- assert:
+ that:
+ - buildargs_1 is changed
+ - buildargs_2 is not changed
+
+####################################################################
+## dockerfile ######################################################
+####################################################################
+
+- name: dockerfile
+ docker_image_build:
+ name: "{{ iname }}"
+ path: "{{ remote_tmp_dir }}/files"
+ dockerfile: "MyDockerfile"
+ pull: false
+ register: dockerfile_1
+
+- name: cleanup
+ docker_image_remove:
+ name: "{{ iname }}"
+
+- assert:
+ that:
+ - dockerfile_1 is changed
+ - "('FROM ' ~ docker_test_image_alpine) in dockerfile_1.stderr"
+ - dockerfile_1['image']['Config']['WorkingDir'] == '/newdata'
+
+####################################################################
+## platform ########################################################
+####################################################################
+
+- name: cleanup
+ docker_image_remove:
+ name: "{{ iname }}"
+
+- name: platform
+ docker_image_build:
+ name: "{{ iname }}"
+ path: "{{ remote_tmp_dir }}/files"
+ platform: linux
+ pull: false
+ register: platform_1
+
+- name: platform (idempotency)
+ docker_image_build:
+ name: "{{ iname }}"
+ path: "{{ remote_tmp_dir }}/files"
+ platform: linux
+ pull: false
+ register: platform_2
+
+- name: cleanup
+ docker_image_remove:
+ name: "{{ iname }}"
+
+- assert:
+ that:
+ - platform_1 is changed
+ - platform_2 is not changed
+
+####################################################################
+## target ##########################################################
+####################################################################
+
+- name: Build multi-stage image
+ docker_image_build:
+ name: "{{ iname }}"
+ path: "{{ remote_tmp_dir }}/files"
+ dockerfile: "StagedDockerfile"
+ target: first
+ pull: false
+ register: dockerfile_2
+
+- name: cleanup
+ docker_image_remove:
+ name: "{{ iname }}"
+
+- assert:
+ that:
+ - dockerfile_2 is changed
+ - dockerfile_2.image.Config.WorkingDir == '/first'
+
+####################################################################
+## etc_hosts #######################################################
+####################################################################
+
+- name: Build image with custom etc_hosts
+ docker_image_build:
+ name: "{{ iname }}"
+ path: "{{ remote_tmp_dir }}/files"
+ dockerfile: "EtcHostsDockerfile"
+ pull: false
+ etc_hosts:
+ some-custom-host: "127.0.0.1"
+ register: path_1
+
+- name: cleanup
+ docker_image_remove:
+ name: "{{ iname }}"
+
+- assert:
+ that:
+ - path_1 is changed
+
+####################################################################
+## shm_size ########################################################
+####################################################################
+
+- name: Build image with custom shm_size
+ docker_image_build:
+ name: "{{ iname }}"
+ path: "{{ remote_tmp_dir }}/files"
+ dockerfile: "MyDockerfile"
+ pull: false
+ shm_size: 128MB
+ register: path_1
+
+- name: cleanup
+ docker_image_remove:
+ name: "{{ iname }}"
+
+- assert:
+ that:
+ - path_1 is changed
+
+####################################################################
+## labels ##########################################################
+####################################################################
+
+- name: Build image with labels
+ docker_image_build:
+ name: "{{ iname }}"
+ path: "{{ remote_tmp_dir }}/files"
+ dockerfile: "MyDockerfile"
+ pull: false
+ labels:
+ FOO: BAR
+ this is a label: this is the label's value
+ register: labels_1
+
+- name: cleanup
+ docker_image_remove:
+ name: "{{ iname }}"
+
+- name: Show image information
+ debug:
+ var: labels_1.image
+
+- assert:
+ that:
+ - labels_1 is changed
+ - labels_1.image.Config.Labels.FOO == 'BAR'
+ - labels_1.image.Config.Labels["this is a label"] == "this is the label's value"
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_build/templates/ArgsDockerfile b/ansible_collections/community/docker/tests/integration/targets/docker_image_build/templates/ArgsDockerfile
new file mode 100644
index 000000000..dedd88a8f
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_build/templates/ArgsDockerfile
@@ -0,0 +1,13 @@
+# Copyright (c) 2022, Felix Fontein
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+ARG IMAGE
+ARG TEST1
+ARG TEST2
+ARG TEST3
+
+FROM ${IMAGE}
+ENV foo /bar
+WORKDIR ${foo}
+RUN echo "${TEST1} - ${TEST2} - ${TEST3}"
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_build/templates/Dockerfile b/ansible_collections/community/docker/tests/integration/targets/docker_image_build/templates/Dockerfile
new file mode 100644
index 000000000..286094b9e
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_build/templates/Dockerfile
@@ -0,0 +1,7 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+FROM {{ docker_test_image_busybox }}
+ENV foo /bar
+WORKDIR ${foo}
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_build/templates/EtcHostsDockerfile b/ansible_collections/community/docker/tests/integration/targets/docker_image_build/templates/EtcHostsDockerfile
new file mode 100644
index 000000000..bc21b966b
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_build/templates/EtcHostsDockerfile
@@ -0,0 +1,7 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+FROM {{ docker_test_image_busybox }}
+# This should fail building if docker cannot resolve some-custom-host
+RUN ping -c1 some-custom-host
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_build/templates/MyDockerfile b/ansible_collections/community/docker/tests/integration/targets/docker_image_build/templates/MyDockerfile
new file mode 100644
index 000000000..24b1c926f
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_build/templates/MyDockerfile
@@ -0,0 +1,9 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+FROM {{ docker_test_image_alpine }}
+ENV INSTALL_PATH /newdata
+RUN mkdir -p $INSTALL_PATH
+
+WORKDIR $INSTALL_PATH
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_build/templates/StagedDockerfile b/ansible_collections/community/docker/tests/integration/targets/docker_image_build/templates/StagedDockerfile
new file mode 100644
index 000000000..da2253425
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_build/templates/StagedDockerfile
@@ -0,0 +1,11 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+FROM {{ docker_test_image_busybox }} AS first
+ENV dir /first
+WORKDIR ${dir}
+
+FROM {{ docker_test_image_busybox }} AS second
+ENV dir /second
+WORKDIR ${dir}
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_export/aliases b/ansible_collections/community/docker/tests/integration/targets/docker_image_export/aliases
new file mode 100644
index 000000000..2e1acc0ad
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_export/aliases
@@ -0,0 +1,6 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+azp/4
+destructive
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_export/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_image_export/meta/main.yml
new file mode 100644
index 000000000..f5b897895
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_export/meta/main.yml
@@ -0,0 +1,9 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+dependencies:
+ - setup_docker
+ - setup_docker_python_deps
+ - setup_remote_tmp_dir
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_export/tasks/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_image_export/tasks/main.yml
new file mode 100644
index 000000000..88b23cfe7
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_export/tasks/main.yml
@@ -0,0 +1,13 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+####################################################################
+# WARNING: These are designed specifically for Ansible tests #
+# and should not be used as examples of how to write Ansible roles #
+####################################################################
+
+- when: ansible_facts.distribution ~ ansible_facts.distribution_major_version not in ['CentOS6', 'RedHat6']
+ include_tasks:
+ file: test.yml
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_export/tasks/run-test.yml b/ansible_collections/community/docker/tests/integration/targets/docker_image_export/tasks/run-test.yml
new file mode 100644
index 000000000..72a58962d
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_export/tasks/run-test.yml
@@ -0,0 +1,7 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: "Loading tasks from {{ test_name }}"
+ include_tasks: "{{ test_name }}"
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_export/tasks/test.yml b/ansible_collections/community/docker/tests/integration/targets/docker_image_export/tasks/test.yml
new file mode 100644
index 000000000..e6ffe722d
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_export/tasks/test.yml
@@ -0,0 +1,39 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Create random name prefix
+ set_fact:
+ name_prefix: "{{ 'ansible-docker-test-%0x' % ((2**32) | random) }}"
+- name: Create image and container list
+ set_fact:
+ inames: []
+ cnames: []
+
+- debug:
+ msg: "Using name prefix {{ name_prefix }}"
+
+- block:
+ - include_tasks: run-test.yml
+ with_fileglob:
+ - "tests/*.yml"
+ loop_control:
+ loop_var: test_name
+
+ always:
+ - name: "Make sure all images are removed"
+ docker_image_remove:
+ name: "{{ item }}"
+ with_items: "{{ inames }}"
+ - name: "Make sure all containers are removed"
+ docker_container:
+ name: "{{ item }}"
+ state: absent
+ force_kill: true
+ with_items: "{{ cnames }}"
+
+ when: docker_api_version is version('1.25', '>=')
+
+- fail: msg="Too old docker / docker-py version to run docker_image tests!"
+ when: not(docker_api_version is version('1.25', '>=')) and (ansible_distribution != 'CentOS' or ansible_distribution_major_version|int > 6)
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_export/tasks/tests/basic.yml b/ansible_collections/community/docker/tests/integration/targets/docker_image_export/tasks/tests/basic.yml
new file mode 100644
index 000000000..b5f7e6534
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_export/tasks/tests/basic.yml
@@ -0,0 +1,69 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- set_fact:
+ image_names:
+ - "{{ docker_test_image_hello_world }}"
+ - "{{ docker_test_image_alpine_different }}"
+ - "{{ docker_test_image_alpine }}"
+
+- name: Make sure images are there
+ docker_image_pull:
+ name: "{{ item }}"
+ register: images
+ loop: "{{ image_names }}"
+
+- vars:
+ image_ids: "{{ images.results | map(attribute='image') | map(attribute='Id') | list }}"
+ all_images: "{{ image_names + (images.results | map(attribute='image') | map(attribute='Id') | list) }}"
+ image_tasks:
+ - file: archive-1.tar
+ images: "{{ image_names }}"
+ - file: archive-2.tar
+ images: "{{ image_ids }}"
+ - file: archive-3.tar
+ images:
+ - "{{ image_names[0] }}"
+ - "{{ image_ids[1] }}"
+ - file: archive-4.tar
+ images:
+ - "{{ image_ids[0] }}"
+ - "{{ image_names[0] }}"
+ - file: archive-5.tar
+ images:
+ - "{{ image_ids[0] }}"
+
+ block:
+ - name: Create archives
+ docker_image_export:
+ names: "{{ item.images }}"
+ path: "{{ remote_tmp_dir }}/{{ item.file }}"
+ loop: "{{ image_tasks }}"
+ loop_control:
+ label: "{{ item.file }}"
+ register: result
+
+ - name: Extract manifest.json files
+ command: tar xvf "{{ remote_tmp_dir }}/{{ item.file }}" manifest.json --to-stdout
+ loop: "{{ image_tasks }}"
+ loop_control:
+ label: "{{ item.file }}"
+ register: manifests
+
+ - name: Do basic tests
+ assert:
+ that:
+ - item.0.images | length == item.1 | length
+ - item.1 | unique | length == item.2 | length
+ - manifest_json_images == export_image_ids
+ loop: "{{ image_tasks | zip(export_images, manifests_json) }}"
+ loop_control:
+ label: "{{ item.0.file }}"
+ vars:
+ filenames: "{{ image_tasks | map(attribute='file') }}"
+ export_images: "{{ result.results | map(attribute='images') | map('map', attribute='Id') }}"
+ manifests_json: "{{ manifests.results | map(attribute='stdout') | map('from_json') }}"
+ manifest_json_images: "{{ item.2 | map(attribute='Config') | map('regex_replace', '.json$', '') | map('regex_replace', '^blobs/sha256/', '') | sort }}"
+ export_image_ids: "{{ item.1 | map('regex_replace', '^sha256:', '') | unique | sort }}"
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_info/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_image_info/meta/main.yml
index 5769ff1cb..471ddd412 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_image_info/meta/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_info/meta/main.yml
@@ -5,3 +5,4 @@
dependencies:
- setup_docker
+ - setup_docker_python_deps
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_info/tasks/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_image_info/tasks/main.yml
index 5bd053ac4..289a9cf1f 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_image_info/tasks/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_info/tasks/main.yml
@@ -10,9 +10,8 @@
- block:
- name: Make sure image is not there
- docker_image:
+ docker_image_remove:
name: "{{ docker_test_image_alpine_different }}"
- state: absent
- name: Inspect a non-available image
docker_image_info:
@@ -24,10 +23,8 @@
- "result.images|length == 0"
- name: Make sure images are there
- docker_image:
+ docker_image_pull:
name: "{{ item }}"
- source: pull
- state: present
loop:
- "{{ docker_test_image_hello_world }}"
- "{{ docker_test_image_alpine }}"
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_load/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_image_load/meta/main.yml
index 2650229d8..f5b897895 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_image_load/meta/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_load/meta/main.yml
@@ -5,4 +5,5 @@
dependencies:
- setup_docker
+ - setup_docker_python_deps
- setup_remote_tmp_dir
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_load/tasks/run-test.yml b/ansible_collections/community/docker/tests/integration/targets/docker_image_load/tasks/run-test.yml
index 65853ddd8..72a58962d 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_image_load/tasks/run-test.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_load/tasks/run-test.yml
@@ -3,5 +3,5 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
-- name: "Loading tasks from {{ item }}"
- include_tasks: "{{ item }}"
+- name: "Loading tasks from {{ test_name }}"
+ include_tasks: "{{ test_name }}"
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_load/tasks/test.yml b/ansible_collections/community/docker/tests/integration/targets/docker_image_load/tasks/test.yml
index a56c95301..e6ffe722d 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_image_load/tasks/test.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_load/tasks/test.yml
@@ -15,22 +15,23 @@
msg: "Using name prefix {{ name_prefix }}"
- block:
- - include_tasks: run-test.yml
- with_fileglob:
- - "tests/*.yml"
+ - include_tasks: run-test.yml
+ with_fileglob:
+ - "tests/*.yml"
+ loop_control:
+ loop_var: test_name
always:
- - name: "Make sure all images are removed"
- docker_image:
- name: "{{ item }}"
- state: absent
- with_items: "{{ inames }}"
- - name: "Make sure all containers are removed"
- docker_container:
- name: "{{ item }}"
- state: absent
- force_kill: true
- with_items: "{{ cnames }}"
+ - name: "Make sure all images are removed"
+ docker_image_remove:
+ name: "{{ item }}"
+ with_items: "{{ inames }}"
+ - name: "Make sure all containers are removed"
+ docker_container:
+ name: "{{ item }}"
+ state: absent
+ force_kill: true
+ with_items: "{{ cnames }}"
when: docker_api_version is version('1.25', '>=')
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_load/tasks/tests/basic.yml b/ansible_collections/community/docker/tests/integration/targets/docker_image_load/tasks/tests/basic.yml
index 8d9de9948..70dc8df01 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_image_load/tasks/tests/basic.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_load/tasks/tests/basic.yml
@@ -10,9 +10,8 @@
- "{{ docker_test_image_alpine }}"
- name: Make sure images are there
- docker_image:
+ docker_image_pull:
name: "{{ item }}"
- source: pull
register: images
loop: "{{ image_names }}"
@@ -22,7 +21,9 @@
all_images: "{{ image_names + (images.results | map(attribute='image') | map(attribute='Id') | list) }}"
- name: Create archives
- command: docker save {{ item.images | join(' ') }} -o {{ remote_tmp_dir }}/{{ item.file }}
+ docker_image_export:
+ names: "{{ item.images }}"
+ path: "{{ remote_tmp_dir }}/{{ item.file }}"
loop:
- file: archive-1.tar
images: "{{ image_names }}"
@@ -43,10 +44,9 @@
# All images by IDs
- name: Remove all images
- docker_image:
+ docker_image_remove:
name: "{{ item }}"
- state: absent
- force_absent: true
+ force: true
loop: "{{ all_images }}"
ignore_errors: true
register: remove_all_images
@@ -67,10 +67,9 @@
when: remove_all_images is failed
- name: Remove all images (after pruning)
- docker_image:
+ docker_image_remove:
name: "{{ item }}"
- state: absent
- force_absent: true
+ force: true
loop: "{{ all_images }}"
when: remove_all_images is failed
@@ -107,9 +106,8 @@
# Mixed images and IDs
- name: Remove all images
- docker_image:
+ docker_image_remove:
name: "{{ item }}"
- state: absent
loop: "{{ all_images }}"
- name: Load all images (mixed images and IDs)
@@ -137,9 +135,8 @@
# Same image twice
- name: Remove all images
- docker_image:
+ docker_image_remove:
name: "{{ item }}"
- state: absent
loop: "{{ all_images }}"
- name: Load all images (same image twice)
@@ -162,9 +159,8 @@
# Single image by ID
- name: Remove all images
- docker_image:
+ docker_image_remove:
name: "{{ item }}"
- state: absent
loop: "{{ all_images }}"
- name: Load all images (single image by ID)
@@ -197,9 +193,8 @@
# All images by names
- name: Remove all images
- docker_image:
+ docker_image_remove:
name: "{{ item }}"
- state: absent
loop: "{{ all_images }}"
- name: Load all images (names)
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_pull/aliases b/ansible_collections/community/docker/tests/integration/targets/docker_image_pull/aliases
new file mode 100644
index 000000000..2e1acc0ad
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_pull/aliases
@@ -0,0 +1,6 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+azp/4
+destructive
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_pull/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_image_pull/meta/main.yml
new file mode 100644
index 000000000..ff316450e
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_pull/meta/main.yml
@@ -0,0 +1,8 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+dependencies:
+ - setup_docker_registry
+ - setup_docker_python_deps
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_pull/tasks/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_image_pull/tasks/main.yml
new file mode 100644
index 000000000..88b23cfe7
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_pull/tasks/main.yml
@@ -0,0 +1,13 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+####################################################################
+# WARNING: These are designed specifically for Ansible tests #
+# and should not be used as examples of how to write Ansible roles #
+####################################################################
+
+- when: ansible_facts.distribution ~ ansible_facts.distribution_major_version not in ['CentOS6', 'RedHat6']
+ include_tasks:
+ file: test.yml
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_pull/tasks/run-test.yml b/ansible_collections/community/docker/tests/integration/targets/docker_image_pull/tasks/run-test.yml
new file mode 100644
index 000000000..72a58962d
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_pull/tasks/run-test.yml
@@ -0,0 +1,7 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: "Loading tasks from {{ test_name }}"
+ include_tasks: "{{ test_name }}"
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_pull/tasks/test.yml b/ansible_collections/community/docker/tests/integration/targets/docker_image_pull/tasks/test.yml
new file mode 100644
index 000000000..e6ffe722d
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_pull/tasks/test.yml
@@ -0,0 +1,39 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Create random name prefix
+ set_fact:
+ name_prefix: "{{ 'ansible-docker-test-%0x' % ((2**32) | random) }}"
+- name: Create image and container list
+ set_fact:
+ inames: []
+ cnames: []
+
+- debug:
+ msg: "Using name prefix {{ name_prefix }}"
+
+- block:
+ - include_tasks: run-test.yml
+ with_fileglob:
+ - "tests/*.yml"
+ loop_control:
+ loop_var: test_name
+
+ always:
+ - name: "Make sure all images are removed"
+ docker_image_remove:
+ name: "{{ item }}"
+ with_items: "{{ inames }}"
+ - name: "Make sure all containers are removed"
+ docker_container:
+ name: "{{ item }}"
+ state: absent
+ force_kill: true
+ with_items: "{{ cnames }}"
+
+ when: docker_api_version is version('1.25', '>=')
+
+- fail: msg="Too old docker / docker-py version to run docker_image tests!"
+ when: not(docker_api_version is version('1.25', '>=')) and (ansible_distribution != 'CentOS' or ansible_distribution_major_version|int > 6)
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_pull/tasks/tests/basic.yml b/ansible_collections/community/docker/tests/integration/targets/docker_image_pull/tasks/tests/basic.yml
new file mode 100644
index 000000000..23e1f0929
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_pull/tasks/tests/basic.yml
@@ -0,0 +1,196 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Basic pull tests
+ vars:
+ image_name: "{{ docker_test_image_hello_world_platform }}"
+ block:
+ - name: Make sure image is not there
+ docker_image_remove:
+ name: "{{ image_name }}"
+ force: true
+
+ - name: Pull image (check mode)
+ docker_image_pull:
+ name: "{{ image_name }}"
+ platform: amd64
+ register: present_1_check
+ check_mode: true
+
+ - debug:
+ var: present_1_check.diff
+
+ - name: Pull image
+ docker_image_pull:
+ name: "{{ image_name }}"
+ platform: amd64
+ register: present_1
+
+ - debug:
+ var: present_1.diff
+
+ - name: Pull image (idempotent 1, check mode)
+ docker_image_pull:
+ name: "{{ image_name }}"
+ platform: amd64
+ pull: always
+ register: present_2_check
+ check_mode: true
+
+ - debug:
+ var: present_2_check.diff
+
+ - name: Pull image (idempotent 1)
+ docker_image_pull:
+ name: "{{ image_name }}"
+ platform: amd64
+ pull: always
+ register: present_2
+
+ - debug:
+ var: present_2.diff
+
+ - name: Pull image (change, check mode)
+ docker_image_pull:
+ name: "{{ image_name }}"
+ platform: arm64
+ pull: always
+ register: present_3_check
+ check_mode: true
+
+ - debug:
+ var: present_3_check.diff
+
+ - name: Pull image (change)
+ docker_image_pull:
+ name: "{{ image_name }}"
+ platform: arm64
+ pull: always
+ register: present_3
+
+ - debug:
+ var: present_3.diff
+
+ - name: Pull image (idempotent 2, check mode)
+ docker_image_pull:
+ name: "{{ image_name }}"
+ platform: arm64
+ pull: not_present
+ register: present_4_check
+ check_mode: true
+
+ - debug:
+ var: present_4_check.diff
+
+ - name: Pull image (idempotent 2)
+ docker_image_pull:
+ name: "{{ image_name }}"
+ platform: arm64
+ pull: not_present
+ register: present_4
+
+ - debug:
+ var: present_4.diff
+
+ - name: Pull image (change, check mode)
+ docker_image_pull:
+ name: "{{ image_name }}"
+ platform: amd64
+ pull: not_present
+ register: present_5_check
+ check_mode: true
+
+ - debug:
+ var: present_5_check.diff
+
+ - name: Pull image (change)
+ docker_image_pull:
+ name: "{{ image_name }}"
+ platform: amd64
+ pull: not_present
+ register: present_5
+
+ - debug:
+ var: present_5.diff
+
+ - assert:
+ that:
+ - present_1_check is changed
+ - present_1_check.actions | length == 1
+ - present_1_check.actions[0] == 'Pulled image ' ~ image_name
+ - present_1_check.diff.before.exists is false
+ - present_1_check.diff.after.id == 'unknown'
+ - present_1 is changed
+ - present_1.actions | length == 1
+ - present_1.actions[0] == 'Pulled image ' ~ image_name
+ - present_1.diff.before.exists is false
+ - present_1.diff.after.id is string
+ - present_2_check is changed
+ - present_2_check.actions | length == 1
+ - present_2_check.actions[0] == 'Pulled image ' ~ image_name
+ - present_2_check.diff.before.id == present_1.diff.after.id
+ - present_2_check.diff.after.id == 'unknown'
+ - present_2 is not changed
+ - present_2.actions | length == 1
+ - present_2.actions[0] == 'Pulled image ' ~ image_name
+ - present_2.diff.before.id == present_1.diff.after.id
+ - present_2.diff.after.id == present_1.diff.after.id
+ - present_3_check is changed
+ - present_3_check.actions | length == 1
+ - present_3_check.actions[0] == 'Pulled image ' ~ image_name
+ - present_3_check.diff.before.id == present_1.diff.after.id
+ - present_3_check.diff.after.id == 'unknown'
+ - present_3 is changed
+ - present_3.actions | length == 1
+ - present_3.actions[0] == 'Pulled image ' ~ image_name
+ - present_3.diff.before.id == present_1.diff.after.id
+ - present_3.diff.after.id != present_1.diff.after.id
+ - present_3.diff.after.id is string
+ - present_4_check is not changed
+ - present_4_check.actions | length == 0
+ - present_4_check.diff.before.id == present_3.diff.after.id
+ - present_4_check.diff.after.id == present_3.diff.after.id
+ - present_4 is not changed
+ - present_4.actions | length == 0
+ - present_4.diff.before.id == present_3.diff.after.id
+ - present_4.diff.after.id == present_3.diff.after.id
+ - present_5_check is changed
+ - present_5_check.actions | length == 1
+ - present_5_check.actions[0] == 'Pulled image ' ~ image_name
+ - present_5_check.diff.before.id == present_3.diff.after.id
+ - present_5_check.diff.after.id == 'unknown'
+ - present_5 is changed
+ - present_5.actions | length == 1
+ - present_5.actions[0] == 'Pulled image ' ~ image_name
+ - present_5.diff.before.id == present_3.diff.after.id
+ - present_5.diff.after.id == present_1.diff.after.id
+
+ always:
+ - name: cleanup
+ docker_image_remove:
+ name: "{{ image_name }}"
+ force: true
+
+- name: Pull image ID (must fail)
+ docker_image_pull:
+ name: "{{ present_1.image.Id }}"
+ register: fail_1
+ ignore_errors: true
+
+- name: Pull invalid tag (must fail)
+ docker_image_pull:
+ name: "{{ docker_test_image_hello_world }}"
+ tag: foo/bar
+ register: fail_2
+ ignore_errors: true
+
+- assert:
+ that:
+ - fail_1 is failed
+ - >-
+ 'Cannot pull an image by ID' == fail_1.msg
+ - fail_2 is failed
+ - >-
+ '"foo/bar" is not a valid docker tag!' == fail_2.msg
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_pull/tasks/tests/image-ids.yml b/ansible_collections/community/docker/tests/integration/targets/docker_image_pull/tasks/tests/image-ids.yml
new file mode 100644
index 000000000..dd092a8b8
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_pull/tasks/tests/image-ids.yml
@@ -0,0 +1,89 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Image ID pull tests
+ block:
+ - name: Make sure images are not there
+ docker_image_remove:
+ name: "{{ item }}"
+ force: true
+ loop:
+ - "sha256:{{ docker_test_image_digest_v1_image_id }}"
+ - "sha256:{{ docker_test_image_digest_v2_image_id }}"
+
+ - name: Pull image 1
+ docker_image_pull:
+ name: "{{ docker_test_image_digest_base }}@sha256:{{ docker_test_image_digest_v1 }}"
+ register: present_1
+ diff: true
+
+ - name: Pull image 1 (idempotent, do pull)
+ docker_image_pull:
+ name: "{{ docker_test_image_digest_base }}@sha256:{{ docker_test_image_digest_v1 }}"
+ pull: always
+ register: present_2
+ diff: true
+
+ - name: Pull image 1 (idempotent, do not pull)
+ docker_image_pull:
+ name: "{{ docker_test_image_digest_base }}@sha256:{{ docker_test_image_digest_v1 }}"
+ pull: not_present
+ register: present_3
+ diff: true
+
+ - assert:
+ that:
+ - present_1 is changed
+ - present_1.actions | length == 1
+ - present_1.actions[0] == 'Pulled image ' ~ docker_test_image_digest_base ~ ':sha256:' ~ docker_test_image_digest_v1
+ - present_1.diff.before.exists is false
+ - present_1.diff.after.id is string
+ - present_2 is not changed
+ - present_2.actions | length == 1
+ - present_2.actions[0] == 'Pulled image ' ~ docker_test_image_digest_base ~ ':sha256:' ~ docker_test_image_digest_v1
+ - present_2.diff.before.id == present_1.diff.after.id
+ - present_2.diff.after.id == present_1.diff.after.id
+ - present_3 is not changed
+ - present_3.actions | length == 0
+ - present_3.diff.before.id == present_1.diff.after.id
+ - present_3.diff.after.id == present_1.diff.after.id
+
+ - name: Pull image 2 (check mode)
+ docker_image_pull:
+ name: "{{ docker_test_image_digest_base }}@sha256:{{ docker_test_image_digest_v2 }}"
+ pull: always
+ register: present_4
+ diff: true
+ check_mode: true
+
+ - name: Pull image 2
+ docker_image_pull:
+ name: "{{ docker_test_image_digest_base }}@sha256:{{ docker_test_image_digest_v2 }}"
+ pull: always
+ register: present_5
+ diff: true
+
+ - assert:
+ that:
+ - present_4 is changed
+ - present_4.actions | length == 1
+ - present_4.actions[0] == 'Pulled image ' ~ docker_test_image_digest_base ~ ':sha256:' ~ docker_test_image_digest_v2
+ - present_4.diff.before.exists is false
+ - present_4.diff.after.id == 'unknown'
+ - present_5 is changed
+ - present_5.actions | length == 1
+ - present_5.actions[0] == 'Pulled image ' ~ docker_test_image_digest_base ~ ':sha256:' ~ docker_test_image_digest_v2
+ - present_5.diff.before.exists is false
+ - present_5.diff.after.id != present_1.diff.after.id
+ - present_5.diff.after.id is string
+
+ always:
+ - name: cleanup
+ docker_image_remove:
+ name: "{{ item }}"
+ force: true
+ loop:
+ - "sha256:{{ docker_test_image_digest_v1_image_id }}"
+ - "sha256:{{ docker_test_image_digest_v2_image_id }}"
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_pull/tasks/tests/registry.yml b/ansible_collections/community/docker/tests/integration/targets/docker_image_pull/tasks/tests/registry.yml
new file mode 100644
index 000000000..2edc3b62d
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_pull/tasks/tests/registry.yml
@@ -0,0 +1,126 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Run registry tests only when registry is present
+ when: registry_address is defined
+ block:
+ - name: Registering image name
+ set_fact:
+ iname: "{{ name_prefix ~ '-options' }}"
+
+ - name: Determining pushed image names
+ set_fact:
+ hello_world_image_base: "{{ registry_address }}/test/hello-world"
+
+ - name: Registering image name
+ set_fact:
+ inames: "{{ inames + [iname, hello_world_image_base ~ ':latest'] }}"
+
+ - name: Make sure image is not there
+ docker_image_remove:
+ name: "{{ hello_world_image_base }}:latest"
+ force: true
+
+ - name: Make sure we have {{ docker_test_image_hello_world }}
+ docker_image_pull:
+ name: "{{ docker_test_image_hello_world }}"
+ diff: true
+
+ - name: Tag image
+ docker_image_tag:
+ name: "{{ docker_test_image_hello_world }}"
+ repository:
+ - "{{ hello_world_image_base }}:latest"
+
+ - name: Push image to test registry
+ docker_image_push:
+ name: "{{ hello_world_image_base }}:latest"
+
+ - name: Get facts of local image
+ docker_image_info:
+ name: "{{ hello_world_image_base }}:latest"
+ register: facts_1
+
+ - name: Make sure image is not there
+ docker_image_remove:
+ name: "{{ hello_world_image_base }}:latest"
+ force: true
+
+ - name: Get facts of local image (not there)
+ docker_image_info:
+ name: "{{ hello_world_image_base }}:latest"
+ register: facts_2
+
+ - name: Pull image from test registry (check mode)
+ docker_image_pull:
+ name: "{{ hello_world_image_base }}:latest"
+ register: pull_1_check
+ diff: true
+ check_mode: true
+
+ - name: Pull image from test registry
+ docker_image_pull:
+ name: "{{ hello_world_image_base }}:latest"
+ register: pull_1
+ diff: true
+
+ - name: Pull image from test registry (idempotency, not pulling, check mode)
+ docker_image_pull:
+ name: "{{ hello_world_image_base }}:latest"
+ pull: not_present
+ register: pull_2_check
+ diff: true
+ check_mode: true
+
+ - name: Pull image from test registry (idempotency, not pulling)
+ docker_image_pull:
+ name: "{{ hello_world_image_base }}:latest"
+ pull: not_present
+ register: pull_2
+ diff: true
+
+ - name: Pull image from test registry (idempotency, pulling, check mode)
+ docker_image_pull:
+ name: "{{ hello_world_image_base }}:latest"
+ pull: always
+ register: pull_3_check
+ diff: true
+ check_mode: true
+
+ - name: Pull image from test registry (idempotency, pulling)
+ docker_image_pull:
+ name: "{{ hello_world_image_base }}:latest"
+ pull: always
+ register: pull_3
+ diff: true
+
+ - name: Get facts of local image (present)
+ docker_image_info:
+ name: "{{ hello_world_image_base }}:latest"
+ register: facts_3
+
+ - assert:
+ that:
+ - pull_1_check is changed
+ - pull_1_check.diff.before.exists is false
+ - pull_1_check.diff.after.id == 'unknown'
+ - pull_1 is changed
+ - pull_1.diff.before.exists is false
+ - pull_1.diff.after.id == facts_1.images[0].Id
+ - pull_2_check is not changed
+ - pull_2_check.diff.before.id == facts_1.images[0].Id
+ - pull_2_check.diff.before == pull_2.diff.after
+ - pull_2 is not changed
+ - pull_2.diff.before.id == facts_1.images[0].Id
+ - pull_2.diff.before == pull_2.diff.after
+ - pull_3_check is changed
+ - pull_3_check.diff.before.id == facts_1.images[0].Id
+ - pull_3_check.diff.after.id == 'unknown'
+ - pull_3 is not changed
+ - pull_3.diff.before.id == facts_1.images[0].Id
+ - pull_3.diff.before == pull_2.diff.after
+ - facts_1.images | length == 1
+ - facts_2.images | length == 0
+ - facts_3.images | length == 1
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_push/aliases b/ansible_collections/community/docker/tests/integration/targets/docker_image_push/aliases
new file mode 100644
index 000000000..2e1acc0ad
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_push/aliases
@@ -0,0 +1,6 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+azp/4
+destructive
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_push/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_image_push/meta/main.yml
new file mode 100644
index 000000000..ff316450e
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_push/meta/main.yml
@@ -0,0 +1,8 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+dependencies:
+ - setup_docker_registry
+ - setup_docker_python_deps
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_push/tasks/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_image_push/tasks/main.yml
new file mode 100644
index 000000000..88b23cfe7
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_push/tasks/main.yml
@@ -0,0 +1,13 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+####################################################################
+# WARNING: These are designed specifically for Ansible tests #
+# and should not be used as examples of how to write Ansible roles #
+####################################################################
+
+- when: ansible_facts.distribution ~ ansible_facts.distribution_major_version not in ['CentOS6', 'RedHat6']
+ include_tasks:
+ file: test.yml
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_push/tasks/run-test.yml b/ansible_collections/community/docker/tests/integration/targets/docker_image_push/tasks/run-test.yml
new file mode 100644
index 000000000..72a58962d
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_push/tasks/run-test.yml
@@ -0,0 +1,7 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: "Loading tasks from {{ test_name }}"
+ include_tasks: "{{ test_name }}"
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_push/tasks/test.yml b/ansible_collections/community/docker/tests/integration/targets/docker_image_push/tasks/test.yml
new file mode 100644
index 000000000..e6ffe722d
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_push/tasks/test.yml
@@ -0,0 +1,39 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Create random name prefix
+ set_fact:
+ name_prefix: "{{ 'ansible-docker-test-%0x' % ((2**32) | random) }}"
+- name: Create image and container list
+ set_fact:
+ inames: []
+ cnames: []
+
+- debug:
+ msg: "Using name prefix {{ name_prefix }}"
+
+- block:
+ - include_tasks: run-test.yml
+ with_fileglob:
+ - "tests/*.yml"
+ loop_control:
+ loop_var: test_name
+
+ always:
+ - name: "Make sure all images are removed"
+ docker_image_remove:
+ name: "{{ item }}"
+ with_items: "{{ inames }}"
+ - name: "Make sure all containers are removed"
+ docker_container:
+ name: "{{ item }}"
+ state: absent
+ force_kill: true
+ with_items: "{{ cnames }}"
+
+ when: docker_api_version is version('1.25', '>=')
+
+- fail: msg="Too old docker / docker-py version to run docker_image tests!"
+ when: not(docker_api_version is version('1.25', '>=')) and (ansible_distribution != 'CentOS' or ansible_distribution_major_version|int > 6)
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_push/tasks/tests/basic.yml b/ansible_collections/community/docker/tests/integration/targets/docker_image_push/tasks/tests/basic.yml
new file mode 100644
index 000000000..15ed8744f
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_push/tasks/tests/basic.yml
@@ -0,0 +1,60 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- vars:
+ image_name: registry.example.com:5000/foo/bar:baz
+ block:
+ - name: Make sure image is not present
+ docker_image_remove:
+ name: "{{ image_name }}"
+
+ - name: Push non-existing image (must fail)
+ docker_image_push:
+ name: "{{ image_name }}"
+ register: fail_1
+ ignore_errors: true
+
+ - name: Push image ID (must fail)
+ docker_image_push:
+ name: "sha256:{{ docker_test_image_digest_v1_image_id }}"
+ register: fail_2
+ ignore_errors: true
+
+ - name: Push image with digest (must fail)
+ docker_image_push:
+ name: "{{ docker_test_image_digest_base }}@sha256:{{ docker_test_image_digest_v1 }}"
+ register: fail_3
+ ignore_errors: true
+
+ - name: Push invalid tag (must fail)
+ docker_image_push:
+ name: "{{ docker_test_image_hello_world }}"
+ tag: foo/bar
+ register: fail_4
+ ignore_errors: true
+
+ - name: Push invalid tag 2 (must fail)
+ docker_image_push:
+ name: "{{ docker_test_image_digest_base }}:foo bar"
+ register: fail_5
+ ignore_errors: true
+
+ - assert:
+ that:
+ - fail_1 is failed
+ - >-
+ 'Cannot find image registry.example.com:5000/foo/bar:baz' == fail_1.msg
+ - fail_2 is failed
+ - >-
+ 'Cannot push an image by ID' == fail_2.msg
+ - fail_3 is failed
+ - >-
+ 'Cannot push an image by digest' == fail_3.msg
+ - fail_4 is failed
+ - >-
+ '"foo/bar" is not a valid docker tag!' == fail_4.msg
+ - fail_5 is failed
+ - >-
+ '"foo bar" is not a valid docker tag!' == fail_5.msg
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_push/tasks/tests/registry.yml b/ansible_collections/community/docker/tests/integration/targets/docker_image_push/tasks/tests/registry.yml
new file mode 100644
index 000000000..ca18d196b
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_push/tasks/tests/registry.yml
@@ -0,0 +1,82 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Run registry tests only when registry is present
+ when: registry_address is defined
+ block:
+ - name: Pull images
+ docker_image_pull:
+ name: "{{ item }}"
+ loop:
+ - "{{ docker_test_image_hello_world }}"
+ - "{{ docker_test_image_alpine }}"
+ register: pulled_images
+
+ - name: Determining pushed image names
+ set_fact:
+ image_name_base: "{{ registry_address }}/test/{{ name_prefix }}"
+ image_name_base2: "{{ registry_frontend2_address }}/test/{{ name_prefix }}"
+ image_tag: latest
+
+ - name: Registering image name
+ set_fact:
+ inames: "{{ inames + [image_name_base ~ ':' ~ image_tag, image_name_base2 ~ ':' ~ image_tag] }}"
+
+ - name: Tag first image
+ docker_image_tag:
+ name: "{{ docker_test_image_hello_world }}"
+ repository:
+ - "{{ image_name_base }}:{{ image_tag }}"
+ - "{{ image_name_base2 }}:{{ image_tag }}"
+
+ - name: Push first image
+ docker_image_push:
+ name: "{{ image_name_base }}:{{ image_tag }}"
+ register: push_1
+
+ - name: Push first image (idempotent)
+ docker_image_push:
+ name: "{{ image_name_base }}:{{ image_tag }}"
+ register: push_2
+
+ - name: Tag second image
+ docker_image_tag:
+ name: "{{ docker_test_image_alpine }}"
+ repository:
+ - "{{ image_name_base }}:{{ image_tag }}"
+
+ - name: Push second image with same name
+ docker_image_push:
+ name: "{{ image_name_base }}:{{ image_tag }}"
+ register: push_3
+
+ - assert:
+ that:
+ - push_1 is changed
+ - push_1.image.Id == pulled_images.results[0].image.Id
+ - push_2 is not changed
+ - push_2.image.Id == pulled_images.results[0].image.Id
+ - push_3 is changed
+ - push_3.image.Id == pulled_images.results[1].image.Id
+
+ - when: registry_frontend2_address != 'n/a'
+ block:
+ - name: Make sure we are logged out from registry
+ docker_login:
+ registry_url: "{{ registry_frontend2_address }}"
+ username: testuser
+ password: hunter2
+ state: absent
+
+ - name: Push image (unauthenticated)
+ docker_image_push:
+ name: "{{ image_name_base2 }}:{{ image_tag }}"
+ register: push_4
+ ignore_errors: true
+
+ - assert:
+ that:
+ - push_4 is failed
+ - push_4.msg == 'Error pushing image ' ~ image_name_base2 ~ ':' ~ image_tag ~ ': no basic auth credentials'
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_remove/aliases b/ansible_collections/community/docker/tests/integration/targets/docker_image_remove/aliases
new file mode 100644
index 000000000..2e1acc0ad
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_remove/aliases
@@ -0,0 +1,6 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+azp/4
+destructive
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_remove/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_image_remove/meta/main.yml
new file mode 100644
index 000000000..471ddd412
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_remove/meta/main.yml
@@ -0,0 +1,8 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+dependencies:
+ - setup_docker
+ - setup_docker_python_deps
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_remove/tasks/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_image_remove/tasks/main.yml
new file mode 100644
index 000000000..afa72da82
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_remove/tasks/main.yml
@@ -0,0 +1,296 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+####################################################################
+# WARNING: These are designed specifically for Ansible tests #
+# and should not be used as examples of how to write Ansible roles #
+####################################################################
+
+- block:
+ - name: Pick image prefix
+ set_fact:
+ iname_prefix: "{{ 'ansible-docker-test-%0x' % ((2**32) | random) }}"
+
+ - name: Define image names
+ set_fact:
+ image: "{{ docker_test_image_hello_world }}"
+ image_id: "{{ docker_test_image_hello_world_image_id }}"
+ image_names:
+ - "{{ iname_prefix }}-tagged-1:latest"
+ - "{{ iname_prefix }}-tagged-1:foo"
+ - "{{ iname_prefix }}-tagged-1:bar"
+
+ - name: Remove image complete
+ docker_image_remove:
+ name: "{{ image_id }}"
+ force: true
+
+ - name: Remove tagged images
+ docker_image_remove:
+ name: "{{ item }}"
+ loop: "{{ image_names }}"
+
+ - name: Make sure image we work with is there
+ docker_image_pull:
+ name: "{{ image }}"
+ register: pulled_image
+ diff: true
+
+ - name: Remove tagged image (not there, check mode)
+ docker_image_remove:
+ name: "{{ iname_prefix }}-tagged-1:latest"
+ register: remove_1_check
+ check_mode: true
+ diff: true
+
+ - name: Remove tagged image (not there)
+ docker_image_remove:
+ name: "{{ iname_prefix }}-tagged-1:latest"
+ register: remove_1
+ diff: true
+
+ - name: Inspect image
+ docker_image_info:
+ name: "{{ iname_prefix }}-tagged-1:latest"
+ register: info_1
+
+ - assert:
+ that:
+ - remove_1_check is not changed
+ - remove_1_check.diff == remove_1.diff
+ - remove_1 is not changed
+ - remove_1.diff.before.exists is false
+ - remove_1.diff.after.exists is false
+ - remove_1.deleted | length == 0
+ - remove_1.untagged | length == 0
+ - remove_1_check.deleted == remove_1.deleted
+ - remove_1_check.untagged == remove_1.untagged
+ - info_1.images | length == 0
+
+ - name: Tag image 1
+ docker_image_tag:
+ name: "{{ image }}"
+ repository:
+ - "{{ iname_prefix }}-tagged-1:latest"
+ - "{{ iname_prefix }}-tagged-1:foo"
+ - "{{ iname_prefix }}-tagged-1:bar"
+
+ - name: Remove tagged image (check mode)
+ docker_image_remove:
+ name: "{{ iname_prefix }}-tagged-1:latest"
+ register: remove_2_check
+ check_mode: true
+ diff: true
+
+ - name: Remove tagged image
+ docker_image_remove:
+ name: "{{ iname_prefix }}-tagged-1:latest"
+ register: remove_2
+ diff: true
+
+ - name: Inspect image
+ docker_image_info:
+ name: "{{ iname_prefix }}-tagged-1:latest"
+ register: info_2
+
+ - assert:
+ that:
+ - remove_2_check is changed
+ - remove_2_check.diff == remove_2.diff
+ - remove_2 is changed
+ - remove_2.diff.before.id == pulled_image.image.Id
+ - remove_2.diff.before.tags | length == 4
+ - remove_2.diff.before.digests | length == 1
+ - remove_2.diff.after.id == pulled_image.image.Id
+ - remove_2.diff.after.tags | length == 3
+ - remove_2.diff.after.digests | length == 1
+ - remove_2.deleted | length == 0
+ - remove_2.untagged | length == 1
+ - remove_2.untagged[0] == iname_prefix ~ '-tagged-1:latest'
+ - remove_2_check.deleted == remove_2.deleted
+ - remove_2_check.untagged == remove_2.untagged
+ - info_2.images | length == 0
+
+ - name: Remove tagged image (idempotent, check mode)
+ docker_image_remove:
+ name: "{{ iname_prefix }}-tagged-1:latest"
+ register: remove_3_check
+ check_mode: true
+ diff: true
+
+ - name: Remove tagged image (idempotent)
+ docker_image_remove:
+ name: "{{ iname_prefix }}-tagged-1:latest"
+ register: remove_3
+ diff: true
+
+ - assert:
+ that:
+ - remove_3_check is not changed
+ - remove_3_check.diff == remove_3.diff
+ - remove_3 is not changed
+ - remove_3.diff.before.exists is false
+ - remove_3.diff.after.exists is false
+ - remove_3.deleted | length == 0
+ - remove_3.untagged | length == 0
+ - remove_3_check.deleted == remove_3.deleted
+ - remove_3_check.untagged == remove_3.untagged
+
+ - name: Inspect image with tag foo and bar
+ docker_image_info:
+ name:
+ - "{{ iname_prefix }}-tagged-1:foo"
+ - "{{ iname_prefix }}-tagged-1:bar"
+ register: info_3
+
+ - name: Remove tagged image (force, check mode)
+ docker_image_remove:
+ name: "{{ iname_prefix }}-tagged-1:foo"
+ force: true
+ register: remove_4_check
+ check_mode: true
+ diff: true
+
+ - name: Remove tagged image (force)
+ docker_image_remove:
+ name: "{{ iname_prefix }}-tagged-1:foo"
+ force: true
+ register: remove_4
+ diff: true
+
+ - name: Inspect image with tag foo and bar
+ docker_image_info:
+ name:
+ - "{{ iname_prefix }}-tagged-1:foo"
+ - "{{ iname_prefix }}-tagged-1:bar"
+ register: info_4
+
+ - assert:
+ that:
+ - remove_4_check is changed
+ - remove_4_check.diff == remove_4.diff
+ - remove_4 is changed
+ - remove_4.diff.before.id == pulled_image.image.Id
+ - remove_4.diff.before.tags | length == 3
+ - remove_4.diff.before.digests | length == 1
+ - remove_4.diff.after.id == pulled_image.image.Id
+ - remove_4.diff.after.tags | length == 2
+ - remove_4.diff.after.digests | length == 1
+ - remove_4.deleted | length == 0
+ - remove_4.untagged | length == 1
+ - remove_4.untagged[0] == iname_prefix ~ '-tagged-1:foo'
+ - remove_4_check.deleted == remove_4.deleted
+ - remove_4_check.untagged == remove_4.untagged
+ - info_3.images | length == 2
+ - info_3.images[0].Id == pulled_image.image.Id
+ - info_3.images[1].Id == pulled_image.image.Id
+ - info_4.images | length == 1
+ - info_4.images[0].Id == pulled_image.image.Id
+
+ - name: Remove image ID (force, idempotent, check mode)
+ docker_image_remove:
+ name: "{{ iname_prefix }}-tagged-1:foo"
+ force: true
+ register: remove_5_check
+ check_mode: true
+ diff: true
+
+ - name: Remove image ID (force, idempotent)
+ docker_image_remove:
+ name: "{{ iname_prefix }}-tagged-1:foo"
+ force: true
+ register: remove_5
+ diff: true
+
+ - assert:
+ that:
+ - remove_5_check is not changed
+ - remove_5_check.diff == remove_5.diff
+ - remove_5 is not changed
+ - remove_5.diff.before.exists is false
+ - remove_5.diff.after.exists is false
+ - remove_5.deleted | length == 0
+ - remove_5.untagged | length == 0
+ - remove_5_check.deleted == remove_5.deleted
+ - remove_5_check.untagged == remove_5.untagged
+
+ - name: Remove image ID (force, check mode)
+ docker_image_remove:
+ name: "{{ pulled_image.image.Id }}"
+ force: true
+ register: remove_6_check
+ check_mode: true
+ diff: true
+
+ - name: Remove image ID (force)
+ docker_image_remove:
+ name: "{{ pulled_image.image.Id }}"
+ force: true
+ register: remove_6
+ diff: true
+
+ - name: Inspect image with tag foo and bar
+ docker_image_info:
+ name:
+ - "{{ iname_prefix }}-tagged-1:foo"
+ - "{{ iname_prefix }}-tagged-1:bar"
+ register: info_5
+
+ - assert:
+ that:
+ - remove_6_check is changed
+ - remove_6_check.diff == remove_6.diff
+ - remove_6 is changed
+ - remove_6.diff.before.id == pulled_image.image.Id
+ - remove_6.diff.before.tags | length == 2
+ - remove_6.diff.before.digests | length == 1
+ - remove_6.diff.after.exists is false
+ - remove_6.deleted | length > 1
+ - pulled_image.image.Id in remove_6.deleted
+ - remove_6.untagged | length == 3
+ - (iname_prefix ~ '-tagged-1:bar') in remove_6.untagged
+ - image in remove_6.untagged
+ - remove_6_check.deleted | length == 1
+ - remove_6_check.deleted[0] == pulled_image.image.Id
+ - remove_6_check.untagged == remove_6.untagged
+ - info_5.images | length == 0
+
+ - name: Remove image ID (force, idempotent, check mode)
+ docker_image_remove:
+ name: "{{ pulled_image.image.Id }}"
+ force: true
+ register: remove_7_check
+ check_mode: true
+ diff: true
+
+ - name: Remove image ID (force, idempotent)
+ docker_image_remove:
+ name: "{{ pulled_image.image.Id }}"
+ force: true
+ register: remove_7
+ diff: true
+
+ - assert:
+ that:
+ - remove_7_check is not changed
+ - remove_7_check.diff == remove_7.diff
+ - remove_7 is not changed
+ - remove_7.diff.before.exists is false
+ - remove_7.diff.after.exists is false
+ - remove_7.deleted | length == 0
+ - remove_7.untagged | length == 0
+ - remove_7_check.deleted == remove_7.deleted
+ - remove_7_check.untagged == remove_7.untagged
+
+ always:
+ - name: Remove tagged images
+ docker_image_remove:
+ name: "{{ item }}"
+ loop: "{{ image_names }}"
+
+ when: docker_api_version is version('1.25', '>=')
+
+- fail: msg="Too old docker / docker-py version to run docker_image_info tests!"
+ when: not(docker_api_version is version('1.25', '>=')) and (ansible_distribution != 'CentOS' or ansible_distribution_major_version|int > 6)
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_tag/aliases b/ansible_collections/community/docker/tests/integration/targets/docker_image_tag/aliases
new file mode 100644
index 000000000..2e1acc0ad
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_tag/aliases
@@ -0,0 +1,6 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+azp/4
+destructive
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_tag/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_image_tag/meta/main.yml
new file mode 100644
index 000000000..471ddd412
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_tag/meta/main.yml
@@ -0,0 +1,8 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+dependencies:
+ - setup_docker
+ - setup_docker_python_deps
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_image_tag/tasks/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_image_tag/tasks/main.yml
new file mode 100644
index 000000000..327917485
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_image_tag/tasks/main.yml
@@ -0,0 +1,402 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+####################################################################
+# WARNING: These are designed specifically for Ansible tests #
+# and should not be used as examples of how to write Ansible roles #
+####################################################################
+
+- block:
+ - name: Pick image prefix
+ set_fact:
+ iname_prefix: "{{ 'ansible-docker-test-%0x' % ((2**32) | random) }}"
+
+ - name: Define image names
+ set_fact:
+ image_1: "{{ docker_test_image_hello_world }}"
+ image_2: "{{ docker_test_image_alpine }}"
+ image_3: "{{ docker_test_image_digest_base }}@sha256:{{ docker_test_image_digest_v1 }}"
+ image_names:
+ - "{{ iname_prefix }}-tagged-1:latest"
+ - "{{ iname_prefix }}-tagged-1:foo"
+ - "{{ iname_prefix }}-tagged-1:bar"
+ - "{{ iname_prefix }}-tagged-2:baz"
+
+ - name: Make sure images we work with are there
+ docker_image_pull:
+ name: "{{ item }}"
+ loop:
+ - "{{ image_1 }}"
+ - "{{ image_2 }}"
+ - "{{ image_3 }}"
+ register: pulled_images
+ diff: true
+
+ - name: Remove tagged images
+ docker_image_remove:
+ name: "{{ item }}"
+ loop: "{{ image_names }}"
+
+ - name: Tag image 1 (check mode)
+ docker_image_tag:
+ name: "{{ image_1 }}"
+ repository:
+ - "{{ iname_prefix }}-tagged-1:latest"
+ - "{{ iname_prefix }}-tagged-1:foo"
+ register: tag_1_check
+ diff: true
+ check_mode: true
+
+ - name: Tag image 1
+ docker_image_tag:
+ name: "{{ image_1 }}"
+ repository:
+ - "{{ iname_prefix }}-tagged-1:latest"
+ - "{{ iname_prefix }}-tagged-1:foo"
+ register: tag_1
+ diff: true
+
+ - name: Fetch image infos
+ docker_image_info:
+ name: "{{ image_names }}"
+ register: info_1
+
+ - assert:
+ that:
+ - tag_1 is changed
+ - tag_1.diff.before.images | length == 2
+ - tag_1.diff.before.images[0] != tag_1.diff.after.images[0]
+ - tag_1.diff.before.images[1] != tag_1.diff.after.images[1]
+ - tag_1.diff.before.images[0].exists is false
+ - tag_1.diff.before.images[1].exists is false
+ - tag_1.diff.after.images[0].id == pulled_images.results[0].image.Id
+ - tag_1.diff.after.images[1].id == pulled_images.results[0].image.Id
+ - info_1.images | length == 2
+ - info_1.images[0].Id == pulled_images.results[0].image.Id
+ - info_1.images[1].Id == pulled_images.results[0].image.Id
+ - tag_1_check == tag_1
+
+ - name: Tag image 1 (idempotent, check mode)
+ docker_image_tag:
+ name: "{{ image_1 }}"
+ repository:
+ - "{{ iname_prefix }}-tagged-1:latest"
+ - "{{ iname_prefix }}-tagged-1:foo"
+ register: tag_2_check
+ diff: true
+ check_mode: true
+
+ - name: Tag image 1 (idempotent)
+ docker_image_tag:
+ name: "{{ image_1 }}"
+ repository:
+ - "{{ iname_prefix }}-tagged-1:latest"
+ - "{{ iname_prefix }}-tagged-1:foo"
+ register: tag_2
+ diff: true
+
+ - assert:
+ that:
+ - tag_2 is not changed
+ - tag_2.diff.before == tag_2.diff.after
+ - tag_2.diff.before.images | length == 2
+ - tag_2_check == tag_2
+
+ - name: Tag image 1 (idempotent, different input format, check mode)
+ docker_image_tag:
+ name: "{{ image_1 }}"
+ tag: foo
+ repository:
+ - "{{ iname_prefix }}-tagged-1:latest"
+ - "{{ iname_prefix }}-tagged-1"
+ register: tag_3_check
+ diff: true
+ check_mode: true
+
+ - name: Tag image 1 (idempotent, different input format)
+ docker_image_tag:
+ name: "{{ image_1 }}"
+ tag: foo
+ repository:
+ - "{{ iname_prefix }}-tagged-1:latest"
+ - "{{ iname_prefix }}-tagged-1"
+ register: tag_3
+ diff: true
+
+ - assert:
+ that:
+ - tag_3 is not changed
+ - tag_3.diff.before == tag_3.diff.after
+ - tag_3.diff.before.images | length == 2
+ - tag_3_check == tag_3
+
+ - name: Tag image 1 (one more, check mode)
+ docker_image_tag:
+ name: "{{ image_1 }}"
+ repository:
+ - "{{ iname_prefix }}-tagged-1:latest"
+ - "{{ iname_prefix }}-tagged-1:foo"
+ - "{{ iname_prefix }}-tagged-2:baz"
+ register: tag_4_check
+ diff: true
+ check_mode: true
+
+ - name: Tag image 1 (one more)
+ docker_image_tag:
+ name: "{{ image_1 }}"
+ repository:
+ - "{{ iname_prefix }}-tagged-1:latest"
+ - "{{ iname_prefix }}-tagged-1:foo"
+ - "{{ iname_prefix }}-tagged-2:baz"
+ register: tag_4
+ diff: true
+
+ - name: Fetch image infos
+ docker_image_info:
+ name: "{{ image_names }}"
+ register: info_4
+
+ - assert:
+ that:
+ - tag_4 is changed
+ - tag_4.diff.before.images | length == 3
+ - tag_4.diff.before.images[0] == tag_4.diff.after.images[0]
+ - tag_4.diff.before.images[1] == tag_4.diff.after.images[1]
+ - tag_4.diff.before.images[2] != tag_4.diff.after.images[2]
+ - tag_4.diff.before.images[2].exists is false
+ - tag_4.diff.after.images[0].id == pulled_images.results[0].image.Id
+ - tag_4.diff.after.images[1].id == pulled_images.results[0].image.Id
+ - tag_4.diff.after.images[2].id == pulled_images.results[0].image.Id
+ - info_4.images | length == 3
+ - info_4.images[0].Id == pulled_images.results[0].image.Id
+ - info_4.images[1].Id == pulled_images.results[0].image.Id
+ - info_4.images[2].Id == pulled_images.results[0].image.Id
+ - tag_4_check == tag_4
+
+ - name: Tag image 2 (only change missing one, check mode)
+ docker_image_tag:
+ name: "{{ image_2 }}"
+ existing_images: keep
+ repository:
+ - "{{ iname_prefix }}-tagged-1:latest"
+ - "{{ iname_prefix }}-tagged-1:foo"
+ - "{{ iname_prefix }}-tagged-1:bar"
+ register: tag_5_check
+ diff: true
+ check_mode: true
+
+ - name: Tag image 2 (only change missing one)
+ docker_image_tag:
+ name: "{{ image_2 }}"
+ existing_images: keep
+ repository:
+ - "{{ iname_prefix }}-tagged-1:latest"
+ - "{{ iname_prefix }}-tagged-1:foo"
+ - "{{ iname_prefix }}-tagged-1:bar"
+ register: tag_5
+ diff: true
+
+ - name: Fetch image infos
+ docker_image_info:
+ name: "{{ image_names }}"
+ register: info_5
+
+ - assert:
+ that:
+ - tag_5 is changed
+ - tag_5.diff.before.images | length == 3
+ - tag_5.diff.before.images[0] == tag_5.diff.after.images[0]
+ - tag_5.diff.before.images[1] == tag_5.diff.after.images[1]
+ - tag_5.diff.before.images[2] != tag_5.diff.after.images[2]
+ - tag_5.diff.before.images[2].exists is false
+ - tag_5.diff.after.images[0].id == pulled_images.results[0].image.Id
+ - tag_5.diff.after.images[1].id == pulled_images.results[0].image.Id
+ - tag_5.diff.after.images[2].id == pulled_images.results[1].image.Id
+ - info_5.images | length == 4
+ - info_5.images[0].Id == pulled_images.results[0].image.Id
+ - info_5.images[1].Id == pulled_images.results[0].image.Id
+ - info_5.images[2].Id == pulled_images.results[1].image.Id
+ - info_5.images[3].Id == pulled_images.results[0].image.Id
+ - tag_5_check == tag_5
+
+ - name: Tag image 2 (idempotent, check mode)
+ docker_image_tag:
+ name: "{{ image_2 }}"
+ existing_images: keep
+ repository:
+ - "{{ iname_prefix }}-tagged-1:latest"
+ - "{{ iname_prefix }}-tagged-1:foo"
+ - "{{ iname_prefix }}-tagged-1:bar"
+ register: tag_6_check
+ diff: true
+ check_mode: true
+
+ - name: Tag image 2 (idempotent)
+ docker_image_tag:
+ name: "{{ image_2 }}"
+ existing_images: keep
+ repository:
+ - "{{ iname_prefix }}-tagged-1:latest"
+ - "{{ iname_prefix }}-tagged-1:foo"
+ - "{{ iname_prefix }}-tagged-1:bar"
+ register: tag_6
+ diff: true
+
+ - assert:
+ that:
+ - tag_6 is not changed
+ - tag_6.diff.before == tag_6.diff.after
+ - tag_6.diff.before.images | length == 3
+ - tag_6_check == tag_6
+
+ - name: Tag image 2 (only change wrong ones, check mode)
+ docker_image_tag:
+ name: "{{ image_2 }}"
+ existing_images: overwrite
+ repository:
+ - "{{ iname_prefix }}-tagged-1:latest"
+ - "{{ iname_prefix }}-tagged-1:foo"
+ - "{{ iname_prefix }}-tagged-1:bar"
+ register: tag_7_check
+ diff: true
+ check_mode: true
+
+ - name: Tag image 2 (only change wrong ones)
+ docker_image_tag:
+ name: "{{ image_2 }}"
+ existing_images: overwrite
+ repository:
+ - "{{ iname_prefix }}-tagged-1:latest"
+ - "{{ iname_prefix }}-tagged-1:foo"
+ - "{{ iname_prefix }}-tagged-1:bar"
+ register: tag_7
+ diff: true
+
+ - name: Fetch image infos
+ docker_image_info:
+ name: "{{ image_names }}"
+ register: info_7
+
+ - assert:
+ that:
+ - tag_7 is changed
+ - tag_7.diff.before.images | length == 3
+ - tag_7.diff.before.images[0] != tag_7.diff.after.images[0]
+ - tag_7.diff.before.images[1] != tag_7.diff.after.images[1]
+ - tag_7.diff.before.images[2] == tag_7.diff.after.images[2]
+ - tag_7.diff.before.images[0].id == pulled_images.results[0].image.Id
+ - tag_7.diff.before.images[1].id == pulled_images.results[0].image.Id
+ - tag_7.diff.after.images[0].id == pulled_images.results[1].image.Id
+ - tag_7.diff.after.images[1].id == pulled_images.results[1].image.Id
+ - tag_7.diff.after.images[2].id == pulled_images.results[1].image.Id
+ - info_7.images | length == 4
+ - info_7.images[0].Id == pulled_images.results[1].image.Id
+ - info_7.images[1].Id == pulled_images.results[1].image.Id
+ - info_7.images[2].Id == pulled_images.results[1].image.Id
+ - info_7.images[3].Id == pulled_images.results[0].image.Id
+ - tag_7_check == tag_7
+
+ - name: Tag image 2 (idempotent, check mode)
+ docker_image_tag:
+ name: "{{ image_2 }}"
+ existing_images: overwrite
+ repository:
+ - "{{ iname_prefix }}-tagged-1:latest"
+ - "{{ iname_prefix }}-tagged-1:foo"
+ - "{{ iname_prefix }}-tagged-1:bar"
+ register: tag_8_check
+ diff: true
+ check_mode: true
+
+ - name: Tag image 2 (idempotent)
+ docker_image_tag:
+ name: "{{ image_2 }}"
+ existing_images: overwrite
+ repository:
+ - "{{ iname_prefix }}-tagged-1:latest"
+ - "{{ iname_prefix }}-tagged-1:foo"
+ - "{{ iname_prefix }}-tagged-1:bar"
+ register: tag_8
+ diff: true
+
+ - assert:
+ that:
+ - tag_8 is not changed
+ - tag_8.diff.before == tag_8.diff.after
+ - tag_8.diff.before.images | length == 3
+ - tag_8_check == tag_8
+
+ - name: Tag image 3 (source image has digest)
+ docker_image_tag:
+ name: "{{ image_3 }}"
+ existing_images: overwrite
+ repository:
+ - "{{ iname_prefix }}-tagged-2:baz"
+ register: tag_9
+ diff: true
+
+ - assert:
+ that:
+ - tag_9 is changed
+ - tag_9.diff.before.images | length == 1
+ - tag_9.diff.before.images[0].id == pulled_images.results[0].image.Id
+ - tag_9.diff.after.images[0].id == pulled_images.results[2].image.Id
+
+ - name: Tag image 3 (source image is ID)
+ docker_image_tag:
+ name: "{{ pulled_images.results[2].image.Id }}"
+ existing_images: overwrite
+ repository:
+ - "{{ iname_prefix }}-tagged-1:foo"
+ register: tag_10
+ diff: true
+
+ - assert:
+ that:
+ - tag_10 is changed
+ - tag_10.diff.before.images | length == 1
+ - tag_10.diff.before.images[0].id == pulled_images.results[1].image.Id
+ - tag_10.diff.after.images[0].id == pulled_images.results[2].image.Id
+
+ - name: Tag image 3 (fail because of digest)
+ docker_image_tag:
+ name: "{{ image_3 }}"
+ existing_images: overwrite
+ repository:
+ - "{{ iname_prefix }}-tagged-2@sha256:{{ docker_test_image_digest_v1 }}"
+ register: tag_11
+ ignore_errors: true
+
+ - assert:
+ that:
+ - tag_11 is failed
+ - >-
+ tag_11.msg == 'repository[1] must not have a digest; got: ' ~ iname_prefix ~ '-tagged-2@sha256:' ~ docker_test_image_digest_v1
+
+ - name: Tag image 3 (fail because of image ID)
+ docker_image_tag:
+ name: "{{ image_3 }}"
+ existing_images: overwrite
+ repository:
+ - "sha256:{{ docker_test_image_digest_v1 }}"
+ register: tag_12
+ ignore_errors: true
+
+ - assert:
+ that:
+ - tag_12 is failed
+ - >-
+ tag_12.msg == 'repository[1] must not be an image ID; got: sha256:' ~ docker_test_image_digest_v1
+
+ always:
+ - name: Remove tagged images
+ docker_image_remove:
+ name: "{{ item }}"
+ loop: "{{ image_names }}"
+
+ when: docker_api_version is version('1.25', '>=')
+
+- fail: msg="Too old docker / docker-py version to run docker_image_info tests!"
+ when: not(docker_api_version is version('1.25', '>=')) and (ansible_distribution != 'CentOS' or ansible_distribution_major_version|int > 6)
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_login/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_login/meta/main.yml
index 3133a0360..ff316450e 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_login/meta/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_login/meta/main.yml
@@ -5,3 +5,4 @@
dependencies:
- setup_docker_registry
+ - setup_docker_python_deps
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_login/tasks/run-test.yml b/ansible_collections/community/docker/tests/integration/targets/docker_login/tasks/run-test.yml
index 65853ddd8..72a58962d 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_login/tasks/run-test.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_login/tasks/run-test.yml
@@ -3,5 +3,5 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
-- name: "Loading tasks from {{ item }}"
- include_tasks: "{{ item }}"
+- name: "Loading tasks from {{ test_name }}"
+ include_tasks: "{{ test_name }}"
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_login/tasks/test.yml b/ansible_collections/community/docker/tests/integration/targets/docker_login/tasks/test.yml
index bd99acc0a..b56fe799f 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_login/tasks/test.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_login/tasks/test.yml
@@ -4,9 +4,11 @@
# SPDX-License-Identifier: GPL-3.0-or-later
- block:
- - include_tasks: run-test.yml
- with_fileglob:
- - "tests/*.yml"
+ - include_tasks: run-test.yml
+ with_fileglob:
+ - "tests/*.yml"
+ loop_control:
+ loop_var: test_name
when: docker_api_version is version('1.25', '>=')
- fail: msg="Too old docker / docker-py version to run docker_image tests!"
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_network/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_network/meta/main.yml
index 5769ff1cb..44bdbe8d5 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_network/meta/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_network/meta/main.yml
@@ -5,3 +5,5 @@
dependencies:
- setup_docker
+ - setup_docker_python_deps
+ - setup_docker_sdk_for_python # for Swarm support
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_network/tasks/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_network/tasks/main.yml
index 4a056151b..d2f7f0258 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_network/tasks/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_network/tasks/main.yml
@@ -28,23 +28,25 @@
msg: "Using name prefix {{ name_prefix }}"
- block:
- - include_tasks: run-test.yml
- with_fileglob:
- - "tests/*.yml"
+ - include_tasks: run-test.yml
+ with_fileglob:
+ - "tests/*.yml"
+ loop_control:
+ loop_var: test_name
always:
- - name: "Make sure all containers are removed"
- docker_container:
- name: "{{ item }}"
- state: absent
- force_kill: true
- loop: "{{ cnames }}"
- - name: "Make sure all networks are removed"
- docker_network:
- name: "{{ item }}"
- state: absent
- force: true
- loop: "{{ dnetworks }}"
+ - name: "Make sure all containers are removed"
+ docker_container:
+ name: "{{ item }}"
+ state: absent
+ force_kill: true
+ loop: "{{ cnames }}"
+ - name: "Make sure all networks are removed"
+ docker_network:
+ name: "{{ item }}"
+ state: absent
+ force: true
+ loop: "{{ dnetworks }}"
when: docker_api_version is version('1.25', '>=') # FIXME: find out API version!
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_network/tasks/run-test.yml b/ansible_collections/community/docker/tests/integration/targets/docker_network/tasks/run-test.yml
index 65853ddd8..72a58962d 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_network/tasks/run-test.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_network/tasks/run-test.yml
@@ -3,5 +3,5 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
-- name: "Loading tasks from {{ item }}"
- include_tasks: "{{ item }}"
+- name: "Loading tasks from {{ test_name }}"
+ include_tasks: "{{ test_name }}"
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_network_info/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_network_info/meta/main.yml
index 5769ff1cb..471ddd412 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_network_info/meta/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_network_info/meta/main.yml
@@ -5,3 +5,4 @@
dependencies:
- setup_docker
+ - setup_docker_python_deps
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_node/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_node/meta/main.yml
index 5769ff1cb..6407d95b0 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_node/meta/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_node/meta/main.yml
@@ -5,3 +5,4 @@
dependencies:
- setup_docker
+ - setup_docker_sdk_for_python
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_node/tasks/test_node.yml b/ansible_collections/community/docker/tests/integration/targets/docker_node/tasks/test_node.yml
index 89c9b3555..c326fc9f3 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_node/tasks/test_node.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_node/tasks/test_node.yml
@@ -697,7 +697,7 @@
- label6
- label7
check_mode: true
- register: output_add_del_overlap_lables_1
+ register: output_add_del_overlap_labels_1
- name: Try to add or update and remove overlapping labels at the same time
docker_node:
@@ -708,7 +708,7 @@
labels_to_remove:
- label6
- label7
- register: output_add_del_overlap_lables_2
+ register: output_add_del_overlap_labels_2
- name: Try to add or update and remove overlapping labels at the same time (idempotent)
docker_node:
@@ -719,7 +719,7 @@
labels_to_remove:
- label6
- label7
- register: output_add_del_overlap_lables_3
+ register: output_add_del_overlap_labels_3
- name: Try to add or update and remove overlapping labels at the same time (idempotent check)
docker_node:
@@ -731,19 +731,19 @@
- label6
- label7
check_mode: true
- register: output_add_del_overlap_lables_4
+ register: output_add_del_overlap_labels_4
- name: assert adding or updating and removing overlapping labels from swarm node
assert:
that:
- - 'output_add_del_overlap_lables_1 is changed'
- - 'output_add_del_overlap_lables_2 is changed'
- - 'output_add_del_overlap_lables_3 is not changed'
- - 'output_add_del_overlap_lables_4 is not changed'
- - 'output_add_del_overlap_lables_2.node.Spec.Labels | length == 3'
- - '"label7" not in output_add_del_overlap_lables_2.node.Spec.Labels'
- - 'output_add_del_overlap_lables_2.node.Spec.Labels.label6 == "value6666"'
- - 'output_add_del_overlap_lables_2.node.Spec.Labels.label22 == "value22"'
+ - 'output_add_del_overlap_labels_1 is changed'
+ - 'output_add_del_overlap_labels_2 is changed'
+ - 'output_add_del_overlap_labels_3 is not changed'
+ - 'output_add_del_overlap_labels_4 is not changed'
+ - 'output_add_del_overlap_labels_2.node.Spec.Labels | length == 3'
+ - '"label7" not in output_add_del_overlap_labels_2.node.Spec.Labels'
+ - 'output_add_del_overlap_labels_2.node.Spec.Labels.label6 == "value6666"'
+ - 'output_add_del_overlap_labels_2.node.Spec.Labels.label22 == "value22"'
####################################################################
## Replace labels #############################################
@@ -828,7 +828,7 @@
check_mode: true
register: output_remove_labels_4
- - name: assert removing all lables from swarm node
+ - name: assert removing all labels from swarm node
assert:
that:
- 'output_remove_labels_1 is changed'
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_node_info/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_node_info/meta/main.yml
index 5769ff1cb..6407d95b0 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_node_info/meta/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_node_info/meta/main.yml
@@ -5,3 +5,4 @@
dependencies:
- setup_docker
+ - setup_docker_sdk_for_python
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_plugin/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_plugin/meta/main.yml
index 5769ff1cb..6407d95b0 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_plugin/meta/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_plugin/meta/main.yml
@@ -5,3 +5,4 @@
dependencies:
- setup_docker
+ - setup_docker_sdk_for_python
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_plugin/tasks/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_plugin/tasks/main.yml
index 142614332..8684ca117 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_plugin/tasks/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_plugin/tasks/main.yml
@@ -17,16 +17,18 @@
register: dev_fuse_stat
- block:
- - include_tasks: run-test.yml
- with_fileglob:
- - "tests/*.yml"
+ - include_tasks: run-test.yml
+ with_fileglob:
+ - "tests/*.yml"
+ loop_control:
+ loop_var: test_name
always:
- - name: "Make sure plugin is removed"
- docker_plugin:
- plugin_name: "{{ item }}"
- state: absent
- with_items: "{{ plugin_names }}"
+ - name: "Make sure plugin is removed"
+ docker_plugin:
+ plugin_name: "{{ item }}"
+ state: absent
+ with_items: "{{ plugin_names }}"
when: docker_api_version is version('1.25', '>=') and dev_fuse_stat.stat.exists
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_plugin/tasks/run-test.yml b/ansible_collections/community/docker/tests/integration/targets/docker_plugin/tasks/run-test.yml
index 65853ddd8..72a58962d 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_plugin/tasks/run-test.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_plugin/tasks/run-test.yml
@@ -3,5 +3,5 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
-- name: "Loading tasks from {{ item }}"
- include_tasks: "{{ item }}"
+- name: "Loading tasks from {{ test_name }}"
+ include_tasks: "{{ test_name }}"
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_prune/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_prune/meta/main.yml
index 5769ff1cb..471ddd412 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_prune/meta/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_prune/meta/main.yml
@@ -5,3 +5,4 @@
dependencies:
- setup_docker
+ - setup_docker_python_deps
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_secret/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_secret/meta/main.yml
index 2650229d8..9eeb6626b 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_secret/meta/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_secret/meta/main.yml
@@ -5,4 +5,5 @@
dependencies:
- setup_docker
+ - setup_docker_sdk_for_python
- setup_remote_tmp_dir
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_stack_info/tasks/test_stack_info.yml b/ansible_collections/community/docker/tests/integration/targets/docker_stack_info/tasks/test_stack_info.yml
index 58d6d5bb9..cca26c802 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_stack_info/tasks/test_stack_info.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_stack_info/tasks/test_stack_info.yml
@@ -18,7 +18,7 @@
assert:
that:
- 'output is failed'
- - '"Error running docker stack" in output.msg'
+ - '"Error response from daemon: This node is not a swarm manager" in output.msg'
- name: Create a swarm cluster
docker_swarm:
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_stack_task_info/tasks/test_stack_task_info.yml b/ansible_collections/community/docker/tests/integration/targets/docker_stack_task_info/tasks/test_stack_task_info.yml
index 30b5ca9e8..cb905d5cf 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_stack_task_info/tasks/test_stack_task_info.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_stack_task_info/tasks/test_stack_task_info.yml
@@ -18,7 +18,7 @@
assert:
that:
- 'output is failed'
- - '"Error running docker stack" in output.msg'
+ - '"Error response from daemon: This node is not a swarm manager" in output.msg'
- name: Create a swarm cluster
docker_swarm:
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_swarm/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_swarm/meta/main.yml
index e7ff3d68b..13f97ae20 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_swarm/meta/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_swarm/meta/main.yml
@@ -5,5 +5,6 @@
dependencies:
- setup_docker
+ - setup_docker_sdk_for_python
- setup_openssl
- setup_remote_tmp_dir
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_swarm/tasks/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_swarm/tasks/main.yml
index 16f681530..f2b90167c 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_swarm/tasks/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_swarm/tasks/main.yml
@@ -14,9 +14,11 @@
- docker_api_version is version('1.25', '>=')
block:
- - include_tasks: "{{ item }}"
+ - include_tasks: run-test.yml
with_fileglob:
- - 'tests/*.yml'
+ - "tests/*.yml"
+ loop_control:
+ loop_var: test_name
always:
- import_tasks: cleanup.yml
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_swarm/tasks/run-test.yml b/ansible_collections/community/docker/tests/integration/targets/docker_swarm/tasks/run-test.yml
index f55df21f8..72a58962d 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_swarm/tasks/run-test.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_swarm/tasks/run-test.yml
@@ -2,3 +2,6 @@
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: "Loading tasks from {{ test_name }}"
+ include_tasks: "{{ test_name }}"
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_swarm_info/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_swarm_info/meta/main.yml
index 5769ff1cb..6407d95b0 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_swarm_info/meta/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_swarm_info/meta/main.yml
@@ -5,3 +5,4 @@
dependencies:
- setup_docker
+ - setup_docker_sdk_for_python
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_swarm_info/tasks/test_swarm_info.yml b/ansible_collections/community/docker/tests/integration/targets/docker_swarm_info/tasks/test_swarm_info.yml
index 288e2a0b0..a2cd5f8f9 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_swarm_info/tasks/test_swarm_info.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_swarm_info/tasks/test_swarm_info.yml
@@ -14,7 +14,7 @@
ignore_errors: true
register: output
- - name: assert failure when called when swarm is not in use or not run on mamager node
+ - name: assert failure when called when swarm is not in use or not run on manager node
assert:
that:
- 'output is failed'
@@ -58,7 +58,7 @@
nodes: true
register: output
- - name: assert reding swarm facts with list of nodes option
+ - name: assert reading swarm facts with list of nodes option
assert:
that:
- 'output.swarm_facts.JoinTokens.Manager'
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_swarm_service/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_swarm_service/meta/main.yml
index 5769ff1cb..6407d95b0 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_swarm_service/meta/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_swarm_service/meta/main.yml
@@ -5,3 +5,4 @@
dependencies:
- setup_docker
+ - setup_docker_sdk_for_python
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_swarm_service/tasks/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_swarm_service/tasks/main.yml
index 5a5795b5f..bbea0a031 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_swarm_service/tasks/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_swarm_service/tasks/main.yml
@@ -24,14 +24,16 @@
# Run the tests
- block:
- - name: Create a Swarm cluster
- docker_swarm:
- state: present
- advertise_addr: "{{ansible_default_ipv4.address | default('127.0.0.1')}}"
+ - name: Create a Swarm cluster
+ docker_swarm:
+ state: present
+ advertise_addr: "{{ansible_default_ipv4.address | default('127.0.0.1')}}"
- - include_tasks: run-test.yml
- with_fileglob:
- - "tests/*.yml"
+ - include_tasks: run-test.yml
+ with_fileglob:
+ - "tests/*.yml"
+ loop_control:
+ loop_var: test_name
always:
- name: Make sure all services are removed
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_swarm_service/tasks/run-test.yml b/ansible_collections/community/docker/tests/integration/targets/docker_swarm_service/tasks/run-test.yml
index 65853ddd8..72a58962d 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_swarm_service/tasks/run-test.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_swarm_service/tasks/run-test.yml
@@ -3,5 +3,5 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
-- name: "Loading tasks from {{ item }}"
- include_tasks: "{{ item }}"
+- name: "Loading tasks from {{ test_name }}"
+ include_tasks: "{{ test_name }}"
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_swarm_service_info/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_swarm_service_info/meta/main.yml
index 5769ff1cb..6407d95b0 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_swarm_service_info/meta/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_swarm_service_info/meta/main.yml
@@ -5,3 +5,4 @@
dependencies:
- setup_docker
+ - setup_docker_sdk_for_python
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_volume/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_volume/meta/main.yml
index 5769ff1cb..471ddd412 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_volume/meta/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_volume/meta/main.yml
@@ -5,3 +5,4 @@
dependencies:
- setup_docker
+ - setup_docker_python_deps
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_volume/tasks/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_volume/tasks/main.yml
index b356e5618..055898402 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_volume/tasks/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_volume/tasks/main.yml
@@ -17,16 +17,18 @@
msg: "Using name prefix {{ name_prefix }}"
- block:
- - include_tasks: run-test.yml
- with_fileglob:
- - "tests/*.yml"
+ - include_tasks: run-test.yml
+ with_fileglob:
+ - "tests/*.yml"
+ loop_control:
+ loop_var: test_name
always:
- - name: "Make sure all volumes are removed"
- docker_volume:
- name: "{{ item }}"
- state: absent
- with_items: "{{ vnames }}"
+ - name: "Make sure all volumes are removed"
+ docker_volume:
+ name: "{{ item }}"
+ state: absent
+ with_items: "{{ vnames }}"
when: docker_api_version is version('1.25', '>=')
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_volume/tasks/run-test.yml b/ansible_collections/community/docker/tests/integration/targets/docker_volume/tasks/run-test.yml
index 65853ddd8..72a58962d 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_volume/tasks/run-test.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_volume/tasks/run-test.yml
@@ -3,5 +3,5 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
-- name: "Loading tasks from {{ item }}"
- include_tasks: "{{ item }}"
+- name: "Loading tasks from {{ test_name }}"
+ include_tasks: "{{ test_name }}"
diff --git a/ansible_collections/community/docker/tests/integration/targets/docker_volume_info/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/docker_volume_info/meta/main.yml
index 5769ff1cb..471ddd412 100644
--- a/ansible_collections/community/docker/tests/integration/targets/docker_volume_info/meta/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/docker_volume_info/meta/main.yml
@@ -5,3 +5,4 @@
dependencies:
- setup_docker
+ - setup_docker_python_deps
diff --git a/ansible_collections/community/docker/tests/integration/targets/generic_connection_tests/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/generic_connection_tests/meta/main.yml
index e7ff3d68b..7440275b2 100644
--- a/ansible_collections/community/docker/tests/integration/targets/generic_connection_tests/meta/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/generic_connection_tests/meta/main.yml
@@ -5,5 +5,7 @@
dependencies:
- setup_docker
+ - setup_docker_python_deps
+ - setup_docker_current_container_network_ip
- setup_openssl
- setup_remote_tmp_dir
diff --git a/ansible_collections/community/docker/tests/integration/targets/generic_connection_tests/vars/main.yml b/ansible_collections/community/docker/tests/integration/targets/generic_connection_tests/vars/main.yml
index e4eafc24e..1859bdfe6 100644
--- a/ansible_collections/community/docker/tests/integration/targets/generic_connection_tests/vars/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/generic_connection_tests/vars/main.yml
@@ -4,10 +4,14 @@
# SPDX-License-Identifier: GPL-3.0-or-later
docker_test_image_digest_v1: e004c2cc521c95383aebb1fb5893719aa7a8eae2e7a71f316a4410784edb00a9
+docker_test_image_digest_v1_image_id: 758ec7f3a1ee85f8f08399b55641bfb13e8c1109287ddc5e22b68c3d653152ee
docker_test_image_digest_v2: ee44b399df993016003bf5466bd3eeb221305e9d0fa831606bc7902d149c775b
+docker_test_image_digest_v2_image_id: dc3bacd8b5ea796cea5d6070c8f145df9076f26a6bc1c8981fd5b176d37de843
docker_test_image_digest_base: quay.io/ansible/docker-test-containers
docker_test_image_hello_world: quay.io/ansible/docker-test-containers:hello-world
+docker_test_image_hello_world_image_id: sha256:bf756fb1ae65adf866bd8c456593cd24beb6a0a061dedf42b26a993176745f6b
docker_test_image_hello_world_base: quay.io/ansible/docker-test-containers
+docker_test_image_hello_world_platform: docker.io/library/hello-world:latest
docker_test_image_busybox: quay.io/ansible/docker-test-containers:busybox
docker_test_image_alpine: quay.io/ansible/docker-test-containers:alpine3.8
docker_test_image_alpine_different: quay.io/ansible/docker-test-containers:alpine3.7
diff --git a/ansible_collections/community/docker/tests/integration/targets/generic_ssh_connection/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/generic_ssh_connection/meta/main.yml
index 6fdc1c8ec..ee4a358cb 100644
--- a/ansible_collections/community/docker/tests/integration/targets/generic_ssh_connection/meta/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/generic_ssh_connection/meta/main.yml
@@ -6,3 +6,4 @@
dependencies:
- setup_docker
- setup_paramiko
+ - setup_docker_python_deps
diff --git a/ansible_collections/community/docker/tests/integration/targets/generic_ssh_connection/tasks/main.yml b/ansible_collections/community/docker/tests/integration/targets/generic_ssh_connection/tasks/main.yml
index 94554f716..8bfa52511 100644
--- a/ansible_collections/community/docker/tests/integration/targets/generic_ssh_connection/tasks/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/generic_ssh_connection/tasks/main.yml
@@ -68,7 +68,6 @@
docker_host: "ssh://root@localhost"
use_ssh_client: true
register: output
- ignore_errors: true
- name: Make sure we got information
assert:
@@ -80,11 +79,3 @@
- 'output.volumes is not defined'
- 'output.images is not defined'
- 'output.disk_usage is not defined'
- when: docker_py_version is version('4.4.0', '>=')
-
-- name: Make sure we got information
- assert:
- that:
- - output is failed
- - "'use_ssh_client=True requires Docker SDK for Python 4.4.0 or newer' in output.msg"
- when: docker_py_version is version('4.4.0', '<')
diff --git a/ansible_collections/community/docker/tests/integration/targets/inventory_docker_containers/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/inventory_docker_containers/meta/main.yml
index 5769ff1cb..471ddd412 100644
--- a/ansible_collections/community/docker/tests/integration/targets/inventory_docker_containers/meta/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/inventory_docker_containers/meta/main.yml
@@ -5,3 +5,4 @@
dependencies:
- setup_docker
+ - setup_docker_python_deps
diff --git a/ansible_collections/community/docker/tests/integration/targets/inventory_docker_containers/playbooks/docker_cleanup.yml b/ansible_collections/community/docker/tests/integration/targets/inventory_docker_containers/playbooks/docker_cleanup.yml
index 6f2a3b6c5..9a01aa289 100644
--- a/ansible_collections/community/docker/tests/integration/targets/inventory_docker_containers/playbooks/docker_cleanup.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/inventory_docker_containers/playbooks/docker_cleanup.yml
@@ -15,12 +15,3 @@
loop:
- ansible-docker-test-docker-inventory-container-1
- ansible-docker-test-docker-inventory-container-2
-
- - name: remove docker pagkages
- action: "{{ ansible_facts.pkg_mgr }}"
- args:
- name:
- - docker
- - docker-ce
- - docker-ce-cli
- state: absent
diff --git a/ansible_collections/community/docker/tests/integration/targets/inventory_docker_containers/playbooks/docker_setup.yml b/ansible_collections/community/docker/tests/integration/targets/inventory_docker_containers/playbooks/docker_setup.yml
index 0c1f33685..72507e414 100644
--- a/ansible_collections/community/docker/tests/integration/targets/inventory_docker_containers/playbooks/docker_setup.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/inventory_docker_containers/playbooks/docker_setup.yml
@@ -13,6 +13,10 @@
import_role:
name: setup_docker
+ - name: Setup Docker Python deps
+ import_role:
+ name: setup_docker_python_deps
+
- name: Start containers
docker_container:
name: "{{ item.name }}"
@@ -21,6 +25,8 @@
command: '/bin/sh -c "sleep 10m"'
published_ports:
- 22/tcp
+ labels:
+ foo: !unsafe 'EVALU{{ "" }}ATED'
loop:
- name: ansible-docker-test-docker-inventory-container-1
- name: ansible-docker-test-docker-inventory-container-2
diff --git a/ansible_collections/community/docker/tests/integration/targets/inventory_docker_containers/playbooks/test_inventory_1.yml b/ansible_collections/community/docker/tests/integration/targets/inventory_docker_containers/playbooks/test_inventory_1.yml
index c0f28f57d..976b25b21 100644
--- a/ansible_collections/community/docker/tests/integration/targets/inventory_docker_containers/playbooks/test_inventory_1.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/inventory_docker_containers/playbooks/test_inventory_1.yml
@@ -25,7 +25,6 @@
# will be other containers.
- inventory_hostname.startswith('ansible-docker-test-docker-inventory-container-')
block:
-
- name: Run raw command
raw: ls /
register: output
diff --git a/ansible_collections/community/docker/tests/integration/targets/inventory_docker_containers/playbooks/test_inventory_2.yml b/ansible_collections/community/docker/tests/integration/targets/inventory_docker_containers/playbooks/test_inventory_2.yml
index 28f8dc008..71346bfa1 100644
--- a/ansible_collections/community/docker/tests/integration/targets/inventory_docker_containers/playbooks/test_inventory_2.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/inventory_docker_containers/playbooks/test_inventory_2.yml
@@ -47,3 +47,13 @@
# When the integration tests are run inside a docker container, there
# will be other containers.
- inventory_hostname.startswith('ansible-docker-test-docker-inventory-container-')
+ - name: Write labels into file
+ copy:
+ dest: "/tmp/{{ inventory_hostname }}-labels.txt"
+ content: |-
+ {{ docker_config.Labels }}
+ delegate_to: localhost
+ when:
+ # When the integration tests are run inside a docker container, there
+ # will be other containers.
+ - inventory_hostname.startswith('ansible-docker-test-docker-inventory-container-')
diff --git a/ansible_collections/community/docker/tests/integration/targets/inventory_docker_containers/runme.sh b/ansible_collections/community/docker/tests/integration/targets/inventory_docker_containers/runme.sh
index acc1d5f45..318275d99 100755
--- a/ansible_collections/community/docker/tests/integration/targets/inventory_docker_containers/runme.sh
+++ b/ansible_collections/community/docker/tests/integration/targets/inventory_docker_containers/runme.sh
@@ -9,17 +9,23 @@ set -euo pipefail
cleanup() {
echo "Cleanup"
- ansible-playbook playbooks/docker_cleanup.yml
+ ansible-playbook playbooks/docker_cleanup.yml "$@"
echo "Done"
}
trap cleanup INT TERM EXIT
echo "Setup"
-ANSIBLE_ROLES_PATH=.. ansible-playbook playbooks/docker_setup.yml
+ANSIBLE_ROLES_PATH=.. ansible-playbook playbooks/docker_setup.yml "$@"
echo "Test docker_containers inventory 1"
-ansible-playbook -i inventory_1.docker.yml playbooks/test_inventory_1.yml
+ansible-playbook -i inventory_1.docker.yml playbooks/test_inventory_1.yml "$@"
echo "Test docker_containers inventory 2"
-ansible-playbook -i inventory_2.docker.yml playbooks/test_inventory_2.yml
+rm -f /tmp/ansible-docker-test-docker-inventory-container-*-labels.txt
+ansible-playbook -i inventory_2.docker.yml playbooks/test_inventory_2.yml "$@"
+
+echo "Validate that 'EVALUATED' does not appear in the labels"
+for FILENAME in /tmp/ansible-docker-test-docker-inventory-container-*-labels.txt; do
+ grep -qv EVALUATED "${FILENAME}" || ( echo "${FILENAME} contains EVALUATED!" && exit 1 )
+done
diff --git a/ansible_collections/community/docker/tests/integration/targets/inventory_docker_machine/playbooks/pre-setup.yml b/ansible_collections/community/docker/tests/integration/targets/inventory_docker_machine/playbooks/pre-setup.yml
index 3c6c1367c..aacaf67bf 100644
--- a/ansible_collections/community/docker/tests/integration/targets/inventory_docker_machine/playbooks/pre-setup.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/inventory_docker_machine/playbooks/pre-setup.yml
@@ -10,6 +10,10 @@
include_role:
name: setup_docker
+ - name: Setup Docker Python deps
+ import_role:
+ name: setup_docker_python_deps
+
# There seems to be no better way to install docker-machine. At least I couldn't find any packages for RHEL7/8.
- name: Download docker-machine binary
vars:
diff --git a/ansible_collections/community/docker/tests/integration/targets/inventory_docker_machine/runme.sh b/ansible_collections/community/docker/tests/integration/targets/inventory_docker_machine/runme.sh
index b39a08c41..5d00aa666 100755
--- a/ansible_collections/community/docker/tests/integration/targets/inventory_docker_machine/runme.sh
+++ b/ansible_collections/community/docker/tests/integration/targets/inventory_docker_machine/runme.sh
@@ -23,14 +23,14 @@ SAVED_PATH="$PATH"
cleanup() {
PATH="${SAVED_PATH}"
echo "Cleanup"
- ansible-playbook -i teardown.docker_machine.yml playbooks/teardown.yml
+ ansible-playbook -i teardown.docker_machine.yml playbooks/teardown.yml "$@"
echo "Done"
}
trap cleanup INT TERM EXIT
echo "Pre-setup (install docker, docker-machine)"
-ANSIBLE_ROLES_PATH=.. ansible-playbook playbooks/pre-setup.yml
+ANSIBLE_ROLES_PATH=.. ansible-playbook playbooks/pre-setup.yml "$@"
echo "Print docker-machine version"
docker-machine --version
@@ -43,10 +43,10 @@ echo "Test that the docker_machine inventory plugin is being loaded"
ANSIBLE_DEBUG=yes ansible-inventory -i inventory_1.docker_machine.yml --list | grep -F "Loading InventoryModule 'docker_machine'"
echo "Setup"
-ansible-playbook playbooks/setup.yml
+ansible-playbook playbooks/setup.yml "$@"
echo "Test docker_machine inventory 1"
-ansible-playbook -i inventory_1.docker_machine.yml playbooks/test_inventory_1.yml
+ansible-playbook -i inventory_1.docker_machine.yml playbooks/test_inventory_1.yml "$@"
echo "Activate Docker Machine mock"
PATH=${SCRIPT_DIR}:$PATH
diff --git a/ansible_collections/community/docker/tests/integration/targets/inventory_docker_swarm/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/inventory_docker_swarm/meta/main.yml
index 5769ff1cb..6407d95b0 100644
--- a/ansible_collections/community/docker/tests/integration/targets/inventory_docker_swarm/meta/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/inventory_docker_swarm/meta/main.yml
@@ -5,3 +5,4 @@
dependencies:
- setup_docker
+ - setup_docker_sdk_for_python
diff --git a/ansible_collections/community/docker/tests/integration/targets/inventory_docker_swarm/playbooks/swarm_cleanup.yml b/ansible_collections/community/docker/tests/integration/targets/inventory_docker_swarm/playbooks/swarm_cleanup.yml
index 4039a6bde..a6bedd41a 100644
--- a/ansible_collections/community/docker/tests/integration/targets/inventory_docker_swarm/playbooks/swarm_cleanup.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/inventory_docker_swarm/playbooks/swarm_cleanup.yml
@@ -11,12 +11,3 @@
docker_swarm:
state: absent
force: true
-
- - name: remove docker pagkages
- action: "{{ ansible_facts.pkg_mgr }}"
- args:
- name:
- - docker
- - docker-ce
- - docker-ce-cli
- state: absent
diff --git a/ansible_collections/community/docker/tests/integration/targets/inventory_docker_swarm/playbooks/swarm_setup.yml b/ansible_collections/community/docker/tests/integration/targets/inventory_docker_swarm/playbooks/swarm_setup.yml
index 1ae4c63fe..9dd43dd2e 100644
--- a/ansible_collections/community/docker/tests/integration/targets/inventory_docker_swarm/playbooks/swarm_setup.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/inventory_docker_swarm/playbooks/swarm_setup.yml
@@ -13,6 +13,10 @@
import_role:
name: setup_docker
+ - name: Setup Docker SDK for Python
+ import_role:
+ name: setup_docker_sdk_for_python
+
- name: Create a Swarm cluster
community.docker.docker_swarm:
state: present
diff --git a/ansible_collections/community/docker/tests/integration/targets/inventory_docker_swarm/runme.sh b/ansible_collections/community/docker/tests/integration/targets/inventory_docker_swarm/runme.sh
index 746b8592f..1759b888b 100755
--- a/ansible_collections/community/docker/tests/integration/targets/inventory_docker_swarm/runme.sh
+++ b/ansible_collections/community/docker/tests/integration/targets/inventory_docker_swarm/runme.sh
@@ -9,17 +9,17 @@ set -euo pipefail
cleanup() {
echo "Cleanup"
- ansible-playbook playbooks/swarm_cleanup.yml
+ ansible-playbook playbooks/swarm_cleanup.yml "$@"
echo "Done"
}
trap cleanup INT TERM EXIT
echo "Setup"
-ANSIBLE_ROLES_PATH=.. ansible-playbook playbooks/swarm_setup.yml
+ANSIBLE_ROLES_PATH=.. ansible-playbook playbooks/swarm_setup.yml "$@"
echo "Test docker_swarm inventory 1"
-ansible-playbook -i inventory_1.docker_swarm.yml playbooks/test_inventory_1.yml
+ansible-playbook -i inventory_1.docker_swarm.yml playbooks/test_inventory_1.yml "$@"
echo "Test docker_swarm inventory 2"
-ansible-playbook -i inventory_2.docker_swarm.yml playbooks/test_inventory_2.yml
+ansible-playbook -i inventory_2.docker_swarm.yml playbooks/test_inventory_2.yml "$@"
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker/defaults/main.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker/defaults/main.yml
index 0509fe0ef..412fc5644 100644
--- a/ansible_collections/community/docker/tests/integration/targets/setup_docker/defaults/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker/defaults/main.yml
@@ -5,7 +5,6 @@
docker_cli_version: '0.0'
docker_api_version: '0.0'
-docker_py_version: '0.0'
docker_skip_cleanup: true
docker_prereq_packages: []
docker_packages:
@@ -13,10 +12,6 @@ docker_packages:
docker_cli_packages:
- docker-ce-cli
-docker_pip_extra_packages: []
-docker_pip_package: docker
-docker_pip_package_limit: ''
-
docker_cleanup_packages:
- docker
- docker-ce
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker/handlers/main.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker/handlers/main.yml
index 96ca226c7..ec68f655c 100644
--- a/ansible_collections/community/docker/tests/integration/targets/setup_docker/handlers/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker/handlers/main.yml
@@ -3,13 +3,6 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
-- name: Remove pip packages
- pip:
- state: present
- name: "{{ [docker_pip_package] | union(docker_pip_extra_packages) }}"
- listen: cleanup docker
- when: not docker_skip_cleanup | bool
-
- name: Remove docker pagkages
action: "{{ ansible_facts.pkg_mgr }}"
args:
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker/tasks/Alpine.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker/tasks/Alpine.yml
index 64f6eb34a..cb07fbf78 100644
--- a/ansible_collections/community/docker/tests/integration/targets/setup_docker/tasks/Alpine.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker/tasks/Alpine.yml
@@ -5,6 +5,7 @@
- name: Install docker
apk:
- name: docker
+ name:
+ - docker
update_cache: true
notify: cleanup docker
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker/tasks/main.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker/tasks/main.yml
index e8f078d3b..e3d7c413f 100644
--- a/ansible_collections/community/docker/tests/integration/targets/setup_docker/tasks/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker/tasks/main.yml
@@ -25,6 +25,14 @@
set_fact:
needs_docker_daemon: '{{ not ansible_module_running_in_container }}'
+ - name:
+ debug:
+ msg: |-
+ OS family: {{ ansible_facts.os_family }}
+ Distribution: {{ ansible_facts.distribution }}
+ Distribution major version: {{ ansible_facts.distribution_major_version }}
+ Distribution full version: {{ ansible_facts.distribution_version }}
+
- name: Include distribution specific variables
include_vars: "{{ lookup('first_found', params) }}"
vars:
@@ -68,36 +76,18 @@
register: docker_api_version_stdout
ignore_errors: true
- - name: Limit docker pypi package version to < 4.3.0
- set_fact:
- docker_pip_package_limit: '<4.3.0'
- when: (docker_api_version_stdout.stdout | default('0.0')) is version('1.39', '<')
-
- - name: Install/upgrade Python requirements
- pip:
- name: "{{ [docker_pip_package ~ docker_pip_package_limit] + docker_pip_extra_packages }}"
- extra_args: "-c {{ remote_constraints }}"
- state: "{{ 'latest' if force_docker_sdk_for_python_pypi | default(false) else 'present' }}"
- notify: cleanup docker
-
# Detect docker CLI and docker-py versions
- name: Check Docker CLI version
command: "docker version -f {% raw %}'{{.Client.Version}}'{% endraw %}"
register: docker_cli_version_stdout
ignore_errors: true
- - name: Check docker-py version
- command: "{{ ansible_python.executable }} -c 'import docker; print(docker.__version__)'"
- register: docker_py_version_stdout
- ignore_errors: true
-
- set_fact:
docker_cli_version: "{{ docker_cli_version_stdout.stdout | default('0.0') }}"
docker_api_version: "{{ docker_api_version_stdout.stdout | default('0.0') }}"
- docker_py_version: "{{ docker_py_version_stdout.stdout | default('0.0') }}"
- debug:
- msg: "Docker CLI version: {{ docker_cli_version }}; Docker API version: {{ docker_api_version }}; docker-py library version: {{ docker_py_version }}"
+ msg: "Docker CLI version: {{ docker_cli_version }}; Docker API version: {{ docker_api_version }}"
- block:
# Cleanup docker daemon
@@ -162,13 +152,3 @@
images: "{{ docker_images.stdout_lines | default([]) }}"
when: docker_cli_version is version('0.0', '>')
-
- - name: Inspect current container
- docker_container_info:
- name: "{{ ansible_module_container_id }}"
- register: current_container_info
- when: ansible_module_running_in_container
-
- - name: Determine network name
- set_fact:
- current_container_network_ip: "{{ (current_container_info.container.NetworkSettings.Networks | dictsort)[0].0 | default('') if ansible_module_running_in_container else '' }}"
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker/vars/RedHat-7.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker/vars/RedHat-7.yml
index b1e28987c..bbf9ed32c 100644
--- a/ansible_collections/community/docker/tests/integration/targets/setup_docker/vars/RedHat-7.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker/vars/RedHat-7.yml
@@ -8,6 +8,3 @@ docker_prereq_packages:
- device-mapper-persistent-data
- lvm2
- libseccomp
-
-docker_pip_extra_packages:
- - requests==2.6.0
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker/vars/Ubuntu-14.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker/vars/Ubuntu-14.yml
index d7c82455b..f55df21f8 100644
--- a/ansible_collections/community/docker/tests/integration/targets/setup_docker/vars/Ubuntu-14.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker/vars/Ubuntu-14.yml
@@ -2,9 +2,3 @@
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
-
-docker_pip_extra_packages:
- # Installing requests >=2.12.0 on Ubuntu 14.04 breaks certificate validation. We restrict to an older version
- # to ensure out get_url tests work out fine. This is only an issue if pyOpenSSL is also installed.
- # Not sure why RHEL7 needs this specific version
- - requests==2.6.0
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker/vars/main.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker/vars/main.yml
index e4eafc24e..1859bdfe6 100644
--- a/ansible_collections/community/docker/tests/integration/targets/setup_docker/vars/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker/vars/main.yml
@@ -4,10 +4,14 @@
# SPDX-License-Identifier: GPL-3.0-or-later
docker_test_image_digest_v1: e004c2cc521c95383aebb1fb5893719aa7a8eae2e7a71f316a4410784edb00a9
+docker_test_image_digest_v1_image_id: 758ec7f3a1ee85f8f08399b55641bfb13e8c1109287ddc5e22b68c3d653152ee
docker_test_image_digest_v2: ee44b399df993016003bf5466bd3eeb221305e9d0fa831606bc7902d149c775b
+docker_test_image_digest_v2_image_id: dc3bacd8b5ea796cea5d6070c8f145df9076f26a6bc1c8981fd5b176d37de843
docker_test_image_digest_base: quay.io/ansible/docker-test-containers
docker_test_image_hello_world: quay.io/ansible/docker-test-containers:hello-world
+docker_test_image_hello_world_image_id: sha256:bf756fb1ae65adf866bd8c456593cd24beb6a0a061dedf42b26a993176745f6b
docker_test_image_hello_world_base: quay.io/ansible/docker-test-containers
+docker_test_image_hello_world_platform: docker.io/library/hello-world:latest
docker_test_image_busybox: quay.io/ansible/docker-test-containers:busybox
docker_test_image_alpine: quay.io/ansible/docker-test-containers:alpine3.8
docker_test_image_alpine_different: quay.io/ansible/docker-test-containers:alpine3.7
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/meta/main.yml
new file mode 100644
index 000000000..5769ff1cb
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/meta/main.yml
@@ -0,0 +1,7 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+dependencies:
+ - setup_docker
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/tasks/Alpine.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/tasks/Alpine.yml
new file mode 100644
index 000000000..48d357a3b
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/tasks/Alpine.yml
@@ -0,0 +1,13 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Buildx is available from Alpine 3.14 on
+ set_fact:
+ docker_has_buildx: "{{ ansible_facts.distribution_version is version('3.14', '>=') }}"
+
+- name: Install Docker buildx CLI plugin
+ apk:
+ name: docker-cli-buildx
+ when: docker_has_buildx
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/tasks/Archlinux.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/tasks/Archlinux.yml
new file mode 100644
index 000000000..5d2709017
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/tasks/Archlinux.yml
@@ -0,0 +1,8 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Install Docker buildx CLI plugin
+ community.general.pacman:
+ name: docker-buildx
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/tasks/Debian.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/tasks/Debian.yml
new file mode 100644
index 000000000..a93d788ac
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/tasks/Debian.yml
@@ -0,0 +1,7 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# nothing to do
+[]
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/tasks/Fedora.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/tasks/Fedora.yml
new file mode 100644
index 000000000..a93d788ac
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/tasks/Fedora.yml
@@ -0,0 +1,7 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# nothing to do
+[]
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/vars/RedHat-7.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/tasks/RedHat-7.yml
index c5d18002b..a93d788ac 100644
--- a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/vars/RedHat-7.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/tasks/RedHat-7.yml
@@ -3,4 +3,5 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
-skip_docker_compose: true
+# nothing to do
+[]
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/tasks/RedHat-8.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/tasks/RedHat-8.yml
new file mode 100644
index 000000000..6bb81a941
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/tasks/RedHat-8.yml
@@ -0,0 +1,8 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: For some reason we don't have the buildx plugin
+ set_fact:
+ docker_has_buildx: false
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/tasks/RedHat-9.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/tasks/RedHat-9.yml
new file mode 100644
index 000000000..a93d788ac
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/tasks/RedHat-9.yml
@@ -0,0 +1,7 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# nothing to do
+[]
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/tasks/Suse.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/tasks/Suse.yml
new file mode 100644
index 000000000..fd667cc24
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/tasks/Suse.yml
@@ -0,0 +1,14 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Buildx is available in OpenSuSE 15.5, not sure which versions before
+ set_fact:
+ docker_has_buildx: "{{ ansible_facts.distribution_version is version('15.5', '>=') }}"
+
+- name: Install Docker buildx CLI plugin
+ community.general.zypper:
+ name: docker-buildx
+ disable_gpg_check: true
+ when: docker_has_buildx
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/tasks/main.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/tasks/main.yml
new file mode 100644
index 000000000..979ad2ba6
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/tasks/main.yml
@@ -0,0 +1,49 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+####################################################################
+# WARNING: These are designed specifically for Ansible tests #
+# and should not be used as examples of how to write Ansible roles #
+####################################################################
+
+- name: Setup Docker
+ when: ansible_facts.distribution ~ ansible_facts.distribution_major_version not in ['CentOS6', 'RedHat6']
+ block:
+ - name:
+ debug:
+ msg: |-
+ OS family: {{ ansible_facts.os_family }}
+ Distribution: {{ ansible_facts.distribution }}
+ Distribution major version: {{ ansible_facts.distribution_major_version }}
+ Distribution full version: {{ ansible_facts.distribution_version }}
+
+ - name: Set facts for Docker features to defaults
+ set_fact:
+ docker_has_buildx: true
+
+ - name: Include distribution specific variables
+ include_vars: "{{ lookup('first_found', params) }}"
+ vars:
+ params:
+ files:
+ - "{{ ansible_facts.distribution }}-{{ ansible_facts.distribution_major_version }}.yml"
+ - "{{ ansible_facts.os_family }}-{{ ansible_facts.distribution_major_version }}.yml"
+ - "{{ ansible_facts.distribution }}.yml"
+ - "{{ ansible_facts.os_family }}.yml"
+ - default.yml
+ paths:
+ - "{{ role_path }}/vars"
+
+ - name: Include distribution specific tasks
+ include_tasks: "{{ lookup('first_found', params) }}"
+ vars:
+ params:
+ files:
+ - "{{ ansible_facts.distribution }}-{{ ansible_facts.distribution_major_version }}.yml"
+ - "{{ ansible_facts.os_family }}-{{ ansible_facts.distribution_major_version }}.yml"
+ - "{{ ansible_facts.distribution }}.yml"
+ - "{{ ansible_facts.os_family }}.yml"
+ paths:
+ - "{{ role_path }}/tasks"
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/tasks/nothing.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/tasks/nothing.yml
new file mode 100644
index 000000000..a93d788ac
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/tasks/nothing.yml
@@ -0,0 +1,7 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# nothing to do
+[]
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/vars/default.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/vars/default.yml
index f55df21f8..f55df21f8 100644
--- a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/vars/default.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_buildx/vars/default.yml
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/meta/main.yml
new file mode 100644
index 000000000..5769ff1cb
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/meta/main.yml
@@ -0,0 +1,7 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+dependencies:
+ - setup_docker
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/tasks/Alpine.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/tasks/Alpine.yml
new file mode 100644
index 000000000..7190dbad5
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/tasks/Alpine.yml
@@ -0,0 +1,13 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Compose is available from Alpine 3.15 on
+ set_fact:
+ docker_has_compose: "{{ ansible_facts.distribution_version is version('3.15', '>=') }}"
+
+- name: Install Docker compose CLI plugin
+ apk:
+ name: docker-cli-compose
+ when: docker_has_compose
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/tasks/Archlinux.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/tasks/Archlinux.yml
new file mode 100644
index 000000000..89dedb0b2
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/tasks/Archlinux.yml
@@ -0,0 +1,8 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Install Docker compose CLI plugin
+ community.general.pacman:
+ name: docker-compose
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/tasks/Debian.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/tasks/Debian.yml
new file mode 100644
index 000000000..a93d788ac
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/tasks/Debian.yml
@@ -0,0 +1,7 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# nothing to do
+[]
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/tasks/Fedora.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/tasks/Fedora.yml
new file mode 100644
index 000000000..a93d788ac
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/tasks/Fedora.yml
@@ -0,0 +1,7 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# nothing to do
+[]
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/tasks/RedHat-7.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/tasks/RedHat-7.yml
new file mode 100644
index 000000000..a93d788ac
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/tasks/RedHat-7.yml
@@ -0,0 +1,7 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# nothing to do
+[]
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/tasks/RedHat-8.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/tasks/RedHat-8.yml
new file mode 100644
index 000000000..b4ece59ae
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/tasks/RedHat-8.yml
@@ -0,0 +1,8 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: For some reason we don't have the buildx plugin
+ set_fact:
+ docker_has_compose: false
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/tasks/RedHat-9.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/tasks/RedHat-9.yml
new file mode 100644
index 000000000..a93d788ac
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/tasks/RedHat-9.yml
@@ -0,0 +1,7 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# nothing to do
+[]
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/tasks/Suse.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/tasks/Suse.yml
new file mode 100644
index 000000000..5b80302bf
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/tasks/Suse.yml
@@ -0,0 +1,14 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Compose is available in OpenSuSE 15.5, not sure which versions before
+ set_fact:
+ docker_has_compose: "{{ ansible_facts.distribution_version is version('15.5', '>=') }}"
+
+- name: Install Docker compose CLI plugin
+ community.general.zypper:
+ name: docker-compose
+ disable_gpg_check: true
+ when: docker_has_compose
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/tasks/main.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/tasks/main.yml
new file mode 100644
index 000000000..7a971c229
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/tasks/main.yml
@@ -0,0 +1,65 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+####################################################################
+# WARNING: These are designed specifically for Ansible tests #
+# and should not be used as examples of how to write Ansible roles #
+####################################################################
+
+- name: Setup Docker
+ when: ansible_facts.distribution ~ ansible_facts.distribution_major_version not in ['CentOS6', 'RedHat6']
+ block:
+ - name:
+ debug:
+ msg: |-
+ OS family: {{ ansible_facts.os_family }}
+ Distribution: {{ ansible_facts.distribution }}
+ Distribution major version: {{ ansible_facts.distribution_major_version }}
+ Distribution full version: {{ ansible_facts.distribution_version }}
+
+ - name: Set facts for Docker features to defaults
+ set_fact:
+ docker_has_compose: true
+ docker_compose_version: "0.0"
+
+ - name: Include distribution specific variables
+ include_vars: "{{ lookup('first_found', params) }}"
+ vars:
+ params:
+ files:
+ - "{{ ansible_facts.distribution }}-{{ ansible_facts.distribution_major_version }}.yml"
+ - "{{ ansible_facts.os_family }}-{{ ansible_facts.distribution_major_version }}.yml"
+ - "{{ ansible_facts.distribution }}.yml"
+ - "{{ ansible_facts.os_family }}.yml"
+ - default.yml
+ paths:
+ - "{{ role_path }}/vars"
+
+ - name: Include distribution specific tasks
+ include_tasks: "{{ lookup('first_found', params) }}"
+ vars:
+ params:
+ files:
+ - "{{ ansible_facts.distribution }}-{{ ansible_facts.distribution_major_version }}.yml"
+ - "{{ ansible_facts.os_family }}-{{ ansible_facts.distribution_major_version }}.yml"
+ - "{{ ansible_facts.distribution }}.yml"
+ - "{{ ansible_facts.os_family }}.yml"
+ paths:
+ - "{{ role_path }}/tasks"
+
+ - name: Obtain Docker Compose version
+ when: docker_has_compose
+ block:
+ - command:
+ cmd: docker info --format '{% raw %}{{ json .ClientInfo.Plugins }}{% endraw %}'
+ register: docker_cli_plugins_stdout
+ - set_fact:
+ docker_has_compose: >-
+ {{ docker_cli_plugins_stdout.stdout | from_json | selectattr('Name', 'eq', 'compose') | map(attribute='Version') | length > 0 }}
+ docker_compose_version: >-
+ {{ docker_cli_plugins_stdout.stdout | from_json | selectattr('Name', 'eq', 'compose') | map(attribute='Version') | first | default('0.0') | regex_replace('^v', '') }}
+
+ - debug:
+ msg: "Has Docker compoes plugin: {{ docker_has_compose }}; Docker compose plugin version: {{ docker_compose_version }}"
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/tasks/nothing.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/tasks/nothing.yml
new file mode 100644
index 000000000..a93d788ac
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/tasks/nothing.yml
@@ -0,0 +1,7 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# nothing to do
+[]
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/vars/default.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/vars/default.yml
new file mode 100644
index 000000000..f55df21f8
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_cli_compose/vars/default.yml
@@ -0,0 +1,4 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/defaults/main.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/defaults/main.yml
new file mode 100644
index 000000000..0ebf5269f
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/defaults/main.yml
@@ -0,0 +1,15 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+skip_docker_compose: false
+
+docker_pip_extra_packages: []
+docker_pip_package: docker
+docker_pip_package_limit: '<7.0.0'
+
+docker_compose_packages:
+ - docker-compose
+docker_compose_pip_packages:
+ - docker-compose
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/meta/main.yml
index b6e985d7f..b6e985d7f 100644
--- a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/meta/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/meta/main.yml
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/tasks/Alpine.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/tasks/Alpine.yml
index 85042fdf0..85042fdf0 100644
--- a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/tasks/Alpine.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/tasks/Alpine.yml
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/tasks/Archlinux.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/tasks/Archlinux.yml
index 2e62ff052..2e62ff052 100644
--- a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/tasks/Archlinux.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/tasks/Archlinux.yml
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/tasks/Debian.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/tasks/Debian.yml
index 1729ccabe..1729ccabe 100644
--- a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/tasks/Debian.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/tasks/Debian.yml
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/tasks/Fedora.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/tasks/Fedora.yml
index a5f3d467b..a5f3d467b 100644
--- a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/tasks/Fedora.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/tasks/Fedora.yml
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/tasks/RedHat-7.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/tasks/RedHat-7.yml
index 62f0e3738..62f0e3738 100644
--- a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/tasks/RedHat-7.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/tasks/RedHat-7.yml
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/tasks/RedHat-8.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/tasks/RedHat-8.yml
index 549868455..549868455 100644
--- a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/tasks/RedHat-8.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/tasks/RedHat-8.yml
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/tasks/RedHat-9.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/tasks/RedHat-9.yml
index 549868455..549868455 100644
--- a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/tasks/RedHat-9.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/tasks/RedHat-9.yml
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/tasks/Suse.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/tasks/Suse.yml
index 46e50fd4d..46e50fd4d 100644
--- a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/tasks/Suse.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/tasks/Suse.yml
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/tasks/main.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/tasks/main.yml
index 630885104..630885104 100644
--- a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/tasks/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/tasks/main.yml
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/tasks/setup.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/tasks/setup.yml
index 08c68a89a..0db7293df 100644
--- a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/tasks/setup.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/tasks/setup.yml
@@ -37,21 +37,41 @@
paths:
- "{{ role_path }}/tasks"
+ - name: Limit docker pypi package version to < 4.3.0
+ set_fact:
+ docker_pip_package_limit: '<4.3.0'
+ when: docker_api_version is version('1.39', '<')
+
+ - name: Install/upgrade Docker SDK for Python
+ pip:
+ name: "{{ [docker_pip_package ~ docker_pip_package_limit] + docker_pip_extra_packages }}"
+ extra_args: "-c {{ remote_constraints }}"
+ state: present
+
- name: Install docker-compose
pip:
state: present
name: "{{ docker_compose_pip_packages }}"
extra_args: "-c {{ remote_constraints }}"
+ - name: Check docker-py version
+ command: "{{ ansible_python.executable }} -c 'import docker; print(docker.__version__)'"
+ register: docker_py_version_stdout
+ ignore_errors: true
+
- name: Register docker-compose version
command: "{{ ansible_python.executable }} -c 'import compose; print(compose.__version__)'"
register: docker_compose_version
ignore_errors: true
- - name: Declare docker-compose version
+ - name: Declare docker-py and docker-compose version
set_fact:
+ docker_py_version: "{{ docker_py_version_stdout.stdout | default('0.0') }}"
docker_compose_version: "{{ docker_compose_version.stdout | default('0.0.0') }}"
+ - debug:
+ msg: "Docker SDK for Python version: {{ docker_py_version }}; Docker Compose version: {{ docker_compose_version }}"
+
- name: Declare docker-compose as existing
set_fact:
has_docker_compose: true
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/defaults/main.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/Alpine.yml
index f701c90e3..fb03ae738 100644
--- a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/defaults/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/Alpine.yml
@@ -3,8 +3,9 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
-skip_docker_compose: false
docker_compose_packages:
- docker-compose
docker_compose_pip_packages:
- docker-compose
+ # Force PyYAML to 5.3.1
+ - PyYAML==5.3.1
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/Archlinux.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/Archlinux.yml
new file mode 100644
index 000000000..f0698a3e4
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/Archlinux.yml
@@ -0,0 +1,9 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+docker_compose_pip_packages:
+ - docker-compose
+ # Force PyYAML to 5.3.1
+ - PyYAML==5.3.1
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/vars/CentOS-8.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/CentOS-8.yml
index c5d18002b..c5d18002b 100644
--- a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/vars/CentOS-8.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/CentOS-8.yml
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/Debian-11.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/Debian-11.yml
new file mode 100644
index 000000000..727d541fd
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/Debian-11.yml
@@ -0,0 +1,8 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+docker_pip_extra_packages:
+ # https://github.com/docker/docker-py/issues/3113
+ - requests<2.29.0
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/Debian-12.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/Debian-12.yml
new file mode 100644
index 000000000..727d541fd
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/Debian-12.yml
@@ -0,0 +1,8 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+docker_pip_extra_packages:
+ # https://github.com/docker/docker-py/issues/3113
+ - requests<2.29.0
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/RedHat-7.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/RedHat-7.yml
new file mode 100644
index 000000000..99b27c1c6
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/RedHat-7.yml
@@ -0,0 +1,10 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+skip_docker_compose: true
+
+docker_pip_extra_packages:
+ # Not sure why RHEL7 needs this specific version
+ - requests==2.6.0
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/vars/RedHat-8.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/RedHat-8.yml
index 7279eac17..7279eac17 100644
--- a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/vars/RedHat-8.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/RedHat-8.yml
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/vars/RedHat-9.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/RedHat-9.yml
index 7279eac17..7279eac17 100644
--- a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/vars/RedHat-9.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/RedHat-9.yml
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/vars/Suse-py2.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/Suse-py2.yml
index c5d18002b..c5d18002b 100644
--- a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/vars/Suse-py2.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/Suse-py2.yml
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/vars/Suse-py3.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/Suse-py3.yml
index 46c58b253..7279eac17 100644
--- a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/vars/Suse-py3.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/Suse-py3.yml
@@ -3,4 +3,4 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
-docker_compose_pip_packages: []
+docker_compose_packages: []
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/Ubuntu-14.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/Ubuntu-14.yml
new file mode 100644
index 000000000..f701e1f77
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/Ubuntu-14.yml
@@ -0,0 +1,9 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+docker_pip_extra_packages:
+ # Installing requests >=2.12.0 on Ubuntu 14.04 breaks certificate validation. We restrict to an older version
+ # to ensure out get_url tests work out fine. This is only an issue if pyOpenSSL is also installed.
+ - requests==2.6.0
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/vars/Ubuntu-16.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/Ubuntu-16.yml
index c5d18002b..c5d18002b 100644
--- a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/vars/Ubuntu-16.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/Ubuntu-16.yml
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/vars/Ubuntu-18.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/Ubuntu-18.yml
index c5d18002b..c5d18002b 100644
--- a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/vars/Ubuntu-18.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/Ubuntu-18.yml
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/vars/Ubuntu.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/Ubuntu.yml
index 46c58b253..46c58b253 100644
--- a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose/vars/Ubuntu.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/Ubuntu.yml
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/default.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/default.yml
new file mode 100644
index 000000000..f55df21f8
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_compose_v1/vars/default.yml
@@ -0,0 +1,4 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_current_container_network_ip/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_current_container_network_ip/meta/main.yml
new file mode 100644
index 000000000..2a770b722
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_current_container_network_ip/meta/main.yml
@@ -0,0 +1,7 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+dependencies:
+ - setup_docker_python_deps
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_current_container_network_ip/tasks/main.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_current_container_network_ip/tasks/main.yml
new file mode 100644
index 000000000..21ed39723
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_current_container_network_ip/tasks/main.yml
@@ -0,0 +1,25 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+####################################################################
+# WARNING: These are designed specifically for Ansible tests #
+# and should not be used as examples of how to write Ansible roles #
+####################################################################
+
+- name: Setup Docker
+ when: ansible_facts.distribution ~ ansible_facts.distribution_major_version not in ['CentOS6', 'RedHat6']
+ block:
+ - name: Detect whether we are running inside a container
+ current_container_facts:
+
+ - name: Inspect current container
+ docker_container_info:
+ name: "{{ ansible_module_container_id }}"
+ register: current_container_info
+ when: ansible_module_running_in_container
+
+ - name: Determine network name
+ set_fact:
+ current_container_network_ip: "{{ (current_container_info.container.NetworkSettings.Networks | dictsort)[0].0 | default('') if ansible_module_running_in_container else '' }}"
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_python_deps/aliases b/ansible_collections/community/docker/tests/integration/targets/setup_docker_python_deps/aliases
new file mode 100644
index 000000000..0a430dff1
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_python_deps/aliases
@@ -0,0 +1,5 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+needs/target/setup_epel
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_python_deps/defaults/main.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_python_deps/defaults/main.yml
new file mode 100644
index 000000000..cd11129ed
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_python_deps/defaults/main.yml
@@ -0,0 +1,12 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+docker_pip_api_packages:
+ - requests
+ # - paramiko
+ # - pyOpenSSL
+
+docker_pip_api_packages_python2:
+ - backports.ssl-match-hostname
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_python_deps/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_python_deps/meta/main.yml
new file mode 100644
index 000000000..d4a5c7d05
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_python_deps/meta/main.yml
@@ -0,0 +1,8 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+dependencies:
+ - setup_remote_constraints
+ - setup_pkg_mgr
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_python_deps/tasks/main.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_python_deps/tasks/main.yml
new file mode 100644
index 000000000..67c2651d2
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_python_deps/tasks/main.yml
@@ -0,0 +1,15 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+####################################################################
+# WARNING: These are designed specifically for Ansible tests #
+# and should not be used as examples of how to write Ansible roles #
+####################################################################
+
+- name: Install/upgrade Python requirements
+ pip:
+ name: "{{ docker_pip_api_packages + (docker_pip_api_packages_python2 if ansible_facts.python.version.major == 2 else []) }}"
+ extra_args: "-c {{ remote_constraints }}"
+ state: present
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_python_deps/vars/RedHat-7.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_python_deps/vars/RedHat-7.yml
new file mode 100644
index 000000000..ff5720177
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_python_deps/vars/RedHat-7.yml
@@ -0,0 +1,10 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+docker_pip_api_packages:
+ # Not sure why RHEL7 needs this specific version of requests
+ - requests==2.6.0
+ # - paramiko
+ # - pyOpenSSL
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_python_deps/vars/Ubuntu-14.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_python_deps/vars/Ubuntu-14.yml
new file mode 100644
index 000000000..41a8bceb5
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_python_deps/vars/Ubuntu-14.yml
@@ -0,0 +1,11 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+docker_pip_api_packages:
+ # Installing requests >=2.12.0 on Ubuntu 14.04 breaks certificate validation. We restrict to an older version
+ # to ensure out get_url tests work out fine. This is only an issue if pyOpenSSL is also installed.
+ - requests==2.6.0
+ # - paramiko
+ # - pyOpenSSL
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_python_deps/vars/default.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_python_deps/vars/default.yml
new file mode 100644
index 000000000..f55df21f8
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_python_deps/vars/default.yml
@@ -0,0 +1,4 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_registry/aliases b/ansible_collections/community/docker/tests/integration/targets/setup_docker_registry/aliases
index 357972ff5..e1026a831 100644
--- a/ansible_collections/community/docker/tests/integration/targets/setup_docker_registry/aliases
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_registry/aliases
@@ -3,4 +3,5 @@
# SPDX-License-Identifier: GPL-3.0-or-later
needs/target/setup_docker
+needs/target/setup_docker_current_container_network_ip
needs/target/setup_openssl
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_registry/handlers/cleanup.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_registry/handlers/cleanup.yml
index 0a1f363cb..6833be48a 100644
--- a/ansible_collections/community/docker/tests/integration/targets/setup_docker_registry/handlers/cleanup.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_registry/handlers/cleanup.yml
@@ -4,9 +4,8 @@
# SPDX-License-Identifier: GPL-3.0-or-later
- name: "Make sure all images are removed"
- docker_image:
+ docker_image_remove:
name: "{{ item }}"
- state: absent
with_items: "{{ docker_registry_setup_inames }}"
- name: "Get registry logs"
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_registry/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_registry/meta/main.yml
index 4ab14ed10..f13fc1adc 100644
--- a/ansible_collections/community/docker/tests/integration/targets/setup_docker_registry/meta/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_registry/meta/main.yml
@@ -5,5 +5,7 @@
dependencies:
#- setup_docker -- done in setup.yml, to work around cleanup problems!
+ #- setup_docker_current_container_network_ip
+ - setup_docker_python_deps
- setup_openssl
- setup_remote_tmp_dir
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_registry/tasks/setup.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_registry/tasks/setup.yml
index b3a8662ee..454c6604a 100644
--- a/ansible_collections/community/docker/tests/integration/targets/setup_docker_registry/tasks/setup.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_registry/tasks/setup.yml
@@ -16,6 +16,10 @@
include_role:
name: setup_docker
+- name: Figure out current container's network IP
+ include_role:
+ name: setup_docker_current_container_network_ip
+
- name: Create random name prefix and test registry name
set_fact:
docker_registry_container_name_registry: '{{ ''ansible-docker-test-registry-%0x'' % ((2**32) | random) }}'
@@ -36,10 +40,10 @@
- debug:
msg: Using test registry name {{ docker_registry_container_name_registry }} and nginx frontend names {{ docker_registry_container_name_nginx }} and {{ docker_registry_container_name_nginx2 }}
-- fail: msg="Too old docker / docker-py version to set up docker registry!"
- when: not(docker_py_version is version('1.8.0', '>=') and docker_api_version is version('1.25', '>=')) and (ansible_distribution != 'CentOS' or ansible_distribution_major_version|int > 6)
+- fail: msg="Too old docker version to set up docker registry!"
+ when: not(docker_api_version is version('1.25', '>=')) and (ansible_distribution != 'CentOS' or ansible_distribution_major_version|int > 6)
-- when: docker_py_version is version('1.8.0', '>=') and docker_api_version is version('1.25', '>=')
+- when: docker_api_version is version('1.25', '>=')
block:
# Set up registry container
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_registry/vars/main.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_registry/vars/main.yml
index e4eafc24e..1859bdfe6 100644
--- a/ansible_collections/community/docker/tests/integration/targets/setup_docker_registry/vars/main.yml
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_registry/vars/main.yml
@@ -4,10 +4,14 @@
# SPDX-License-Identifier: GPL-3.0-or-later
docker_test_image_digest_v1: e004c2cc521c95383aebb1fb5893719aa7a8eae2e7a71f316a4410784edb00a9
+docker_test_image_digest_v1_image_id: 758ec7f3a1ee85f8f08399b55641bfb13e8c1109287ddc5e22b68c3d653152ee
docker_test_image_digest_v2: ee44b399df993016003bf5466bd3eeb221305e9d0fa831606bc7902d149c775b
+docker_test_image_digest_v2_image_id: dc3bacd8b5ea796cea5d6070c8f145df9076f26a6bc1c8981fd5b176d37de843
docker_test_image_digest_base: quay.io/ansible/docker-test-containers
docker_test_image_hello_world: quay.io/ansible/docker-test-containers:hello-world
+docker_test_image_hello_world_image_id: sha256:bf756fb1ae65adf866bd8c456593cd24beb6a0a061dedf42b26a993176745f6b
docker_test_image_hello_world_base: quay.io/ansible/docker-test-containers
+docker_test_image_hello_world_platform: docker.io/library/hello-world:latest
docker_test_image_busybox: quay.io/ansible/docker-test-containers:busybox
docker_test_image_alpine: quay.io/ansible/docker-test-containers:alpine3.8
docker_test_image_alpine_different: quay.io/ansible/docker-test-containers:alpine3.7
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_sdk_for_python/aliases b/ansible_collections/community/docker/tests/integration/targets/setup_docker_sdk_for_python/aliases
new file mode 100644
index 000000000..0a430dff1
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_sdk_for_python/aliases
@@ -0,0 +1,5 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+needs/target/setup_epel
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_sdk_for_python/defaults/main.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_sdk_for_python/defaults/main.yml
new file mode 100644
index 000000000..29a257f81
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_sdk_for_python/defaults/main.yml
@@ -0,0 +1,10 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+docker_py_version: '0.0'
+
+docker_pip_extra_packages: []
+docker_pip_package: docker
+docker_pip_package_limit: ''
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_sdk_for_python/meta/main.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_sdk_for_python/meta/main.yml
new file mode 100644
index 000000000..d4a5c7d05
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_sdk_for_python/meta/main.yml
@@ -0,0 +1,8 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+dependencies:
+ - setup_remote_constraints
+ - setup_pkg_mgr
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_sdk_for_python/tasks/main.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_sdk_for_python/tasks/main.yml
new file mode 100644
index 000000000..91cd5fcba
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_sdk_for_python/tasks/main.yml
@@ -0,0 +1,47 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+####################################################################
+# WARNING: These are designed specifically for Ansible tests #
+# and should not be used as examples of how to write Ansible roles #
+####################################################################
+
+- name: Setup Docker SDK for Python
+ when: ansible_facts.distribution ~ ansible_facts.distribution_major_version not in ['CentOS6', 'RedHat6']
+ block:
+ - name: Include distribution specific variables
+ include_vars: "{{ lookup('first_found', params) }}"
+ vars:
+ params:
+ files:
+ - "{{ ansible_facts.distribution }}-{{ ansible_facts.distribution_major_version }}.yml"
+ - "{{ ansible_facts.os_family }}-{{ ansible_facts.distribution_major_version }}.yml"
+ - "{{ ansible_facts.distribution }}.yml"
+ - "{{ ansible_facts.os_family }}.yml"
+ - default.yml
+ paths:
+ - "{{ role_path }}/vars"
+
+ - name: Limit docker pypi package version to < 4.3.0
+ set_fact:
+ docker_pip_package_limit: '<4.3.0'
+ when: docker_api_version is version('1.39', '<')
+
+ - name: Install/upgrade Python requirements
+ pip:
+ name: "{{ [docker_pip_package ~ docker_pip_package_limit] + docker_pip_extra_packages }}"
+ extra_args: "-c {{ remote_constraints }}"
+ state: "{{ 'latest' if force_docker_sdk_for_python_pypi | default(false) else 'present' }}"
+
+ - name: Check docker-py version
+ command: "{{ ansible_python.executable }} -c 'import docker; print(docker.__version__)'"
+ register: docker_py_version_stdout
+ ignore_errors: true
+
+ - set_fact:
+ docker_py_version: "{{ docker_py_version_stdout.stdout | default('0.0') }}"
+
+ - debug:
+ msg: "Docker SDK for Python version: {{ docker_py_version }}"
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_sdk_for_python/vars/RedHat-7.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_sdk_for_python/vars/RedHat-7.yml
new file mode 100644
index 000000000..9fa5efa5c
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_sdk_for_python/vars/RedHat-7.yml
@@ -0,0 +1,8 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+docker_pip_extra_packages:
+ # Not sure why RHEL7 needs this specific version
+ - requests==2.6.0
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_sdk_for_python/vars/Ubuntu-14.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_sdk_for_python/vars/Ubuntu-14.yml
new file mode 100644
index 000000000..f701e1f77
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_sdk_for_python/vars/Ubuntu-14.yml
@@ -0,0 +1,9 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+docker_pip_extra_packages:
+ # Installing requests >=2.12.0 on Ubuntu 14.04 breaks certificate validation. We restrict to an older version
+ # to ensure out get_url tests work out fine. This is only an issue if pyOpenSSL is also installed.
+ - requests==2.6.0
diff --git a/ansible_collections/community/docker/tests/integration/targets/setup_docker_sdk_for_python/vars/default.yml b/ansible_collections/community/docker/tests/integration/targets/setup_docker_sdk_for_python/vars/default.yml
new file mode 100644
index 000000000..f55df21f8
--- /dev/null
+++ b/ansible_collections/community/docker/tests/integration/targets/setup_docker_sdk_for_python/vars/default.yml
@@ -0,0 +1,4 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
diff --git a/ansible_collections/community/docker/tests/sanity/extra/action-group.json b/ansible_collections/community/docker/tests/sanity/extra/action-group.json
new file mode 100644
index 000000000..477ca3f8b
--- /dev/null
+++ b/ansible_collections/community/docker/tests/sanity/extra/action-group.json
@@ -0,0 +1,11 @@
+{
+ "include_symlinks": true,
+ "prefixes": [
+ "meta/runtime.yml",
+ "plugins/modules/"
+ ],
+ "output": "path-message",
+ "requirements": [
+ "pyyaml"
+ ]
+}
diff --git a/ansible_collections/community/docker/tests/sanity/extra/action-group.json.license b/ansible_collections/community/docker/tests/sanity/extra/action-group.json.license
new file mode 100644
index 000000000..edff8c768
--- /dev/null
+++ b/ansible_collections/community/docker/tests/sanity/extra/action-group.json.license
@@ -0,0 +1,3 @@
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
+SPDX-FileCopyrightText: Ansible Project
diff --git a/ansible_collections/community/docker/tests/sanity/extra/action-group.py b/ansible_collections/community/docker/tests/sanity/extra/action-group.py
new file mode 100755
index 000000000..efe31ab91
--- /dev/null
+++ b/ansible_collections/community/docker/tests/sanity/extra/action-group.py
@@ -0,0 +1,82 @@
+#!/usr/bin/env python
+# Copyright (c) 2024, Felix Fontein <felix@fontein.de>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+"""Make sure all modules that should show up in the action group."""
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import os
+import yaml
+
+
+def main():
+ """Main entry point."""
+
+ # Load redirects
+ meta_runtime = 'meta/runtime.yml'
+ try:
+ with open(meta_runtime, 'rb') as f:
+ data = yaml.safe_load(f)
+ action_group = data['action_groups']['docker']
+ except Exception as exc:
+ print('%s: cannot load action group: %s' % (meta_runtime, exc))
+ return
+
+ exclusions = ['current_container_facts']
+ modules_directory = 'plugins/modules/'
+ modules_suffix = '.py'
+
+ for file in os.listdir(modules_directory):
+ if not file.endswith(modules_suffix):
+ continue
+ module_name = file[:-len(modules_suffix)]
+
+ should_be_in_action_group = module_name not in exclusions
+
+ if should_be_in_action_group:
+ if module_name not in action_group:
+ print('%s: module %s is not part of docker action group' % (meta_runtime, module_name))
+ else:
+ action_group.remove(module_name)
+
+ path = os.path.join(modules_directory, file)
+ documentation = []
+ in_docs = False
+ with open(path, 'r', encoding='utf-8') as f:
+ for line in f:
+ if line.startswith('DOCUMENTATION ='):
+ in_docs = True
+ elif line.startswith(("'''", '"""')) and in_docs:
+ in_docs = False
+ elif in_docs:
+ documentation.append(line)
+ if in_docs:
+ print('%s: cannot find DOCUMENTATION end' % (path))
+ if not documentation:
+ print('%s: cannot find DOCUMENTATION' % (path))
+ continue
+
+ try:
+ docs = yaml.safe_load('\n'.join(documentation))
+ if not isinstance(docs, dict):
+ raise Exception('is not a top-level dictionary')
+ except Exception as exc:
+ print('%s: cannot load DOCUMENTATION as YAML: %s' % (path, exc))
+ continue
+
+ docs_fragments = docs.get('extends_documentation_fragment') or []
+ is_in_action_group = 'community.docker.attributes.actiongroup_docker' in docs_fragments
+
+ if should_be_in_action_group != is_in_action_group:
+ if should_be_in_action_group:
+ print('%s: module does not document itself as part of action group, but it should' % (path))
+ else:
+ print('%s: module documents itself as part of action group, but it should not be' % (path))
+
+ for module_name in action_group:
+ print('%s: module %s mentioned in docker action group does not exist' % (meta_runtime, module_name))
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/docker/tests/sanity/extra/extra-docs.py b/ansible_collections/community/docker/tests/sanity/extra/extra-docs.py
index c636beb08..251e6d70f 100755
--- a/ansible_collections/community/docker/tests/sanity/extra/extra-docs.py
+++ b/ansible_collections/community/docker/tests/sanity/extra/extra-docs.py
@@ -17,7 +17,7 @@ def main():
suffix = ':{env}'.format(env=env["ANSIBLE_COLLECTIONS_PATH"]) if 'ANSIBLE_COLLECTIONS_PATH' in env else ''
env['ANSIBLE_COLLECTIONS_PATH'] = '{root}{suffix}'.format(root=os.path.dirname(os.path.dirname(os.path.dirname(os.getcwd()))), suffix=suffix)
p = subprocess.run(
- ['antsibull-docs', 'lint-collection-docs', '--plugin-docs', '--disallow-semantic-markup', '--skip-rstcheck', '.'],
+ ['antsibull-docs', 'lint-collection-docs', '--plugin-docs', '--skip-rstcheck', '.'],
env=env,
check=False,
)
diff --git a/ansible_collections/community/docker/tests/sanity/ignore-2.10.txt b/ansible_collections/community/docker/tests/sanity/ignore-2.10.txt
deleted file mode 100644
index 1a9f48884..000000000
--- a/ansible_collections/community/docker/tests/sanity/ignore-2.10.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-.azure-pipelines/scripts/publish-codecov.py replace-urlopen
-.azure-pipelines/scripts/publish-codecov.py compile-2.6!skip # Uses Python 3.6+ syntax
-.azure-pipelines/scripts/publish-codecov.py compile-2.7!skip # Uses Python 3.6+ syntax
-.azure-pipelines/scripts/publish-codecov.py compile-3.5!skip # Uses Python 3.6+ syntax
-.azure-pipelines/scripts/publish-codecov.py future-import-boilerplate
-.azure-pipelines/scripts/publish-codecov.py metaclass-boilerplate
-plugins/modules/current_container_facts.py validate-modules:return-syntax-error
-plugins/module_utils/module_container/module.py compile-2.6!skip # Uses Python 2.7+ syntax
-plugins/module_utils/module_container/module.py import-2.6!skip # Uses Python 2.7+ syntax
-plugins/modules/docker_container.py import-2.6!skip # Import uses Python 2.7+ syntax
-plugins/modules/docker_container_copy_into.py validate-modules:undocumented-parameter # _max_file_size_for_diff is used by the action plugin
diff --git a/ansible_collections/community/docker/tests/sanity/ignore-2.11.txt b/ansible_collections/community/docker/tests/sanity/ignore-2.11.txt
index 1a9f48884..2bc38ac22 100644
--- a/ansible_collections/community/docker/tests/sanity/ignore-2.11.txt
+++ b/ansible_collections/community/docker/tests/sanity/ignore-2.11.txt
@@ -7,5 +7,7 @@
plugins/modules/current_container_facts.py validate-modules:return-syntax-error
plugins/module_utils/module_container/module.py compile-2.6!skip # Uses Python 2.7+ syntax
plugins/module_utils/module_container/module.py import-2.6!skip # Uses Python 2.7+ syntax
+plugins/modules/docker_compose_v2.py validate-modules:return-syntax-error
+plugins/modules/docker_compose_v2_pull.py validate-modules:return-syntax-error
plugins/modules/docker_container.py import-2.6!skip # Import uses Python 2.7+ syntax
plugins/modules/docker_container_copy_into.py validate-modules:undocumented-parameter # _max_file_size_for_diff is used by the action plugin
diff --git a/ansible_collections/community/docker/tests/sanity/ignore-2.12.txt b/ansible_collections/community/docker/tests/sanity/ignore-2.12.txt
index 3d71834db..f3c4575fb 100644
--- a/ansible_collections/community/docker/tests/sanity/ignore-2.12.txt
+++ b/ansible_collections/community/docker/tests/sanity/ignore-2.12.txt
@@ -1,3 +1,5 @@
.azure-pipelines/scripts/publish-codecov.py replace-urlopen
plugins/modules/current_container_facts.py validate-modules:return-syntax-error
+plugins/modules/docker_compose_v2.py validate-modules:return-syntax-error
+plugins/modules/docker_compose_v2_pull.py validate-modules:return-syntax-error
plugins/modules/docker_container_copy_into.py validate-modules:undocumented-parameter # _max_file_size_for_diff is used by the action plugin
diff --git a/ansible_collections/community/docker/tests/sanity/ignore-2.13.txt b/ansible_collections/community/docker/tests/sanity/ignore-2.13.txt
index 2a06013da..c0d5c549c 100644
--- a/ansible_collections/community/docker/tests/sanity/ignore-2.13.txt
+++ b/ansible_collections/community/docker/tests/sanity/ignore-2.13.txt
@@ -1,2 +1,3 @@
.azure-pipelines/scripts/publish-codecov.py replace-urlopen
+plugins/modules/docker_compose_v2.py validate-modules:return-syntax-error
plugins/modules/docker_container_copy_into.py validate-modules:undocumented-parameter # _max_file_size_for_diff is used by the action plugin
diff --git a/ansible_collections/community/docker/tests/sanity/ignore-2.16.txt b/ansible_collections/community/docker/tests/sanity/ignore-2.16.txt
index 2a06013da..12e0b26f9 100644
--- a/ansible_collections/community/docker/tests/sanity/ignore-2.16.txt
+++ b/ansible_collections/community/docker/tests/sanity/ignore-2.16.txt
@@ -1,2 +1 @@
-.azure-pipelines/scripts/publish-codecov.py replace-urlopen
plugins/modules/docker_container_copy_into.py validate-modules:undocumented-parameter # _max_file_size_for_diff is used by the action plugin
diff --git a/ansible_collections/community/docker/tests/sanity/ignore-2.17.txt b/ansible_collections/community/docker/tests/sanity/ignore-2.17.txt
new file mode 100644
index 000000000..12e0b26f9
--- /dev/null
+++ b/ansible_collections/community/docker/tests/sanity/ignore-2.17.txt
@@ -0,0 +1 @@
+plugins/modules/docker_container_copy_into.py validate-modules:undocumented-parameter # _max_file_size_for_diff is used by the action plugin
diff --git a/ansible_collections/community/docker/tests/sanity/ignore-2.17.txt.license b/ansible_collections/community/docker/tests/sanity/ignore-2.17.txt.license
new file mode 100644
index 000000000..edff8c768
--- /dev/null
+++ b/ansible_collections/community/docker/tests/sanity/ignore-2.17.txt.license
@@ -0,0 +1,3 @@
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
+SPDX-FileCopyrightText: Ansible Project
diff --git a/ansible_collections/community/docker/tests/sanity/ignore-2.9.txt b/ansible_collections/community/docker/tests/sanity/ignore-2.9.txt
deleted file mode 100644
index 81b68cbd8..000000000
--- a/ansible_collections/community/docker/tests/sanity/ignore-2.9.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-.azure-pipelines/scripts/publish-codecov.py replace-urlopen
-.azure-pipelines/scripts/publish-codecov.py compile-2.6!skip # Uses Python 3.6+ syntax
-.azure-pipelines/scripts/publish-codecov.py compile-2.7!skip # Uses Python 3.6+ syntax
-.azure-pipelines/scripts/publish-codecov.py compile-3.5!skip # Uses Python 3.6+ syntax
-.azure-pipelines/scripts/publish-codecov.py future-import-boilerplate
-.azure-pipelines/scripts/publish-codecov.py metaclass-boilerplate
-plugins/module_utils/module_container/module.py compile-2.6!skip # Uses Python 2.7+ syntax
-plugins/module_utils/module_container/module.py import-2.6!skip # Uses Python 2.7+ syntax
-plugins/modules/docker_container.py import-2.6!skip # Import uses Python 2.7+ syntax
-plugins/modules/docker_container_copy_into.py validate-modules:undocumented-parameter # _max_file_size_for_diff is used by the action plugin
diff --git a/ansible_collections/community/docker/tests/unit/plugins/connection/test_docker.py b/ansible_collections/community/docker/tests/unit/plugins/connection/test_docker.py
index 5ae6a8e12..279b469c0 100644
--- a/ansible_collections/community/docker/tests/unit/plugins/connection/test_docker.py
+++ b/ansible_collections/community/docker/tests/unit/plugins/connection/test_docker.py
@@ -13,6 +13,7 @@ from ansible_collections.community.docker.tests.unit.compat import unittest
from ansible.errors import AnsibleError
from ansible.playbook.play_context import PlayContext
from ansible.plugins.loader import connection_loader
+from ansible.module_utils.six import PY2
class TestDockerConnectionClass(unittest.TestCase):
@@ -36,7 +37,8 @@ class TestDockerConnectionClass(unittest.TestCase):
def test_docker_connection_module_too_old(self, mock_new_docker_verison, mock_old_docker_version):
self.dc._version = None
self.dc.remote_user = 'foo'
- self.assertRaisesRegexp(AnsibleError, '^docker connection type requires docker 1.3 or higher$', self.dc._get_actual_user)
+ (self.assertRaisesRegexp if PY2 else self.assertRaisesRegex)(
+ AnsibleError, '^docker connection type requires docker 1.3 or higher$', self.dc._get_actual_user)
@mock.patch('ansible_collections.community.docker.plugins.connection.docker.Connection._old_docker_version',
return_value=('false', 'garbage', '', 1))
@@ -54,4 +56,5 @@ class TestDockerConnectionClass(unittest.TestCase):
def test_docker_connection_module_wrong_cmd(self, mock_new_docker_version, mock_old_docker_version):
self.dc._version = None
self.dc.remote_user = 'foo'
- self.assertRaisesRegexp(AnsibleError, '^Docker version check (.*?) failed: ', self.dc._get_actual_user)
+ (self.assertRaisesRegexp if PY2 else self.assertRaisesRegex)(
+ AnsibleError, '^Docker version check (.*?) failed: ', self.dc._get_actual_user)
diff --git a/ansible_collections/community/docker/tests/unit/plugins/inventory/test_docker_containers.py b/ansible_collections/community/docker/tests/unit/plugins/inventory/test_docker_containers.py
index ea16c0d9f..e5761247d 100644
--- a/ansible_collections/community/docker/tests/unit/plugins/inventory/test_docker_containers.py
+++ b/ansible_collections/community/docker/tests/unit/plugins/inventory/test_docker_containers.py
@@ -9,14 +9,24 @@ __metaclass__ = type
import pytest
from ansible.inventory.data import InventoryData
+from ansible.parsing.dataloader import DataLoader
+from ansible.template import Templar
from ansible_collections.community.docker.plugins.inventory.docker_containers import InventoryModule
+from ansible_collections.community.docker.tests.unit.compat.mock import create_autospec
@pytest.fixture(scope="module")
-def inventory():
+def templar():
+ dataloader = create_autospec(DataLoader, instance=True)
+ return Templar(loader=dataloader)
+
+
+@pytest.fixture(scope="module")
+def inventory(templar):
r = InventoryModule()
r.inventory = InventoryData()
+ r.templar = templar
return r
@@ -114,6 +124,7 @@ def test_populate(inventory, mocker):
'compose': {},
'groups': {},
'keyed_groups': {},
+ 'filters': None,
}))
inventory._populate(client)
@@ -145,6 +156,7 @@ def test_populate_service(inventory, mocker):
'groups': {},
'keyed_groups': {},
'docker_host': 'unix://var/run/docker.sock',
+ 'filters': None,
}))
inventory._populate(client)
@@ -186,6 +198,7 @@ def test_populate_stack(inventory, mocker):
'docker_host': 'unix://var/run/docker.sock',
'default_ip': '127.0.0.1',
'private_ssh_port': 22,
+ 'filters': None,
}))
inventory._populate(client)
@@ -212,3 +225,46 @@ def test_populate_stack(inventory, mocker):
assert len(inventory.inventory.groups['unix://var/run/docker.sock'].hosts) == 1
assert len(inventory.inventory.groups) == 10
assert len(inventory.inventory.hosts) == 1
+
+
+def test_populate_filter_none(inventory, mocker):
+ client = FakeClient(LOVING_THARP)
+
+ inventory.get_option = mocker.MagicMock(side_effect=create_get_option({
+ 'verbose_output': True,
+ 'connection_type': 'docker-api',
+ 'add_legacy_groups': False,
+ 'compose': {},
+ 'groups': {},
+ 'keyed_groups': {},
+ 'filters': [
+ {'exclude': True},
+ ],
+ }))
+ inventory._populate(client)
+
+ assert len(inventory.inventory.hosts) == 0
+
+
+def test_populate_filter(inventory, mocker):
+ client = FakeClient(LOVING_THARP)
+
+ inventory.get_option = mocker.MagicMock(side_effect=create_get_option({
+ 'verbose_output': True,
+ 'connection_type': 'docker-api',
+ 'add_legacy_groups': False,
+ 'compose': {},
+ 'groups': {},
+ 'keyed_groups': {},
+ 'filters': [
+ {'include': 'docker_state.Running is true'},
+ {'exclude': True},
+ ],
+ }))
+ inventory._populate(client)
+
+ host_1 = inventory.inventory.get_host('loving_tharp')
+ host_1_vars = host_1.get_vars()
+
+ assert host_1_vars['ansible_host'] == 'loving_tharp'
+ assert len(inventory.inventory.hosts) == 1
diff --git a/ansible_collections/community/docker/tests/unit/plugins/module_utils/_api/api/test_client.py b/ansible_collections/community/docker/tests/unit/plugins/module_utils/_api/api/test_client.py
index ea0035655..57040b631 100644
--- a/ansible_collections/community/docker/tests/unit/plugins/module_utils/_api/api/test_client.py
+++ b/ansible_collections/community/docker/tests/unit/plugins/module_utils/_api/api/test_client.py
@@ -619,7 +619,7 @@ class TCPSocketStreamTest(unittest.TestCase):
def test_read_from_socket_no_stream_no_tty(self):
res = self.request(stream=False, tty=False, demux=False)
- res == self.stdout_data + self.stderr_data
+ assert res == self.stdout_data + self.stderr_data
def test_read_from_socket_no_stream_no_tty_demux(self):
res = self.request(stream=False, tty=False, demux=True)
diff --git a/ansible_collections/community/docker/tests/unit/plugins/module_utils/_api/transport/test_ssladapter.py b/ansible_collections/community/docker/tests/unit/plugins/module_utils/_api/transport/test_ssladapter.py
index 428163e61..77e5017ec 100644
--- a/ansible_collections/community/docker/tests/unit/plugins/module_utils/_api/transport/test_ssladapter.py
+++ b/ansible_collections/community/docker/tests/unit/plugins/module_utils/_api/transport/test_ssladapter.py
@@ -20,14 +20,18 @@ if sys.version_info < (2, 7):
from ansible_collections.community.docker.plugins.module_utils._api.transport import ssladapter
+HAS_MATCH_HOSTNAME = True
try:
from backports.ssl_match_hostname import (
match_hostname, CertificateError
)
except ImportError:
- from ssl import (
- match_hostname, CertificateError
- )
+ try:
+ from ssl import (
+ match_hostname, CertificateError
+ )
+ except ImportError:
+ HAS_MATCH_HOSTNAME = False
try:
from ssl import OP_NO_SSLv3, OP_NO_SSLv2, OP_NO_TLSv1
@@ -47,6 +51,7 @@ class SSLAdapterTest(unittest.TestCase):
assert not ssl_context.options & OP_NO_TLSv1
+@pytest.mark.skipif(not HAS_MATCH_HOSTNAME, reason='match_hostname is not available')
class MatchHostnameTest(unittest.TestCase):
cert = {
'issuer': (
diff --git a/ansible_collections/community/docker/tests/unit/plugins/module_utils/compose_v2_test_cases.py b/ansible_collections/community/docker/tests/unit/plugins/module_utils/compose_v2_test_cases.py
new file mode 100644
index 000000000..d7258396c
--- /dev/null
+++ b/ansible_collections/community/docker/tests/unit/plugins/module_utils/compose_v2_test_cases.py
@@ -0,0 +1,10588 @@
+# Copyright 2022 Red Hat | Ansible
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+from ansible_collections.community.docker.plugins.module_utils.compose_v2 import (
+ Event,
+)
+
+
+EVENT_TEST_CASES = [
+ # #######################################################################################################################
+ # ## Docker Compose 2.18.1 ##############################################################################################
+ # #######################################################################################################################
+ # docker_compose_v2: "Absent" on 2024-01-07 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Absent" on 2024-01-13 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-07 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-13 in 2.12-ubuntu1804
+ (
+ '2.18.1-2.12-ubuntu1804-2024-01-07-docker_compose_v2-absent',
+ '2.18.1',
+ False,
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Stopping\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Stopped\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Removing\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Removed\n'
+ ' Network ansible-docker-test-01234567-start-stop_default Removing\n'
+ ' Network ansible-docker-test-01234567-start-stop_default Removed\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Stopping',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Stopped',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Removing',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Removed',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Removing',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Removed',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Absent (check)" on 2024-01-07 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Absent (check)" on 2024-01-13 in 2.12-ubuntu1804
+ (
+ '2.18.1-2.12-ubuntu1804-2024-01-07-docker_compose_v2-absent-(check)',
+ '2.18.1',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Stopping\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Stopped\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Removing\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Removed\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Removing\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Resource is still in use\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Stopping',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Stopped',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Removing',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Removed',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Removing',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ None,
+ 'Resource is still in use',
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Cleanup" on 2024-01-07 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-13 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Stopping service" on 2024-01-07 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Stopping service" on 2024-01-13 in 2.12-ubuntu1804
+ (
+ '2.18.1-2.12-ubuntu1804-2024-01-07-docker_compose_v2-cleanup',
+ '2.18.1',
+ False,
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Stopping\n'
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Stopped\n'
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Removing\n'
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Removed\n'
+ ' Network ansible-docker-test-01234567-pull_default Removing\n'
+ ' Network ansible-docker-test-01234567-pull_default Removed\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Stopping',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Stopped',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Removing',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Removed',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Removing',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Removed',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present" on 2024-01-07 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Present" on 2024-01-13 in 2.12-ubuntu1804
+ (
+ '2.18.1-2.12-ubuntu1804-2024-01-07-docker_compose_v2-present',
+ '2.18.1',
+ False,
+ ' ansible-docker-test-01234567-container Pulling \n'
+ ' ansible-docker-test-01234567-container Pulled \n'
+ ' Network ansible-docker-test-01234567-start-stop_default Creating\n'
+ ' Network ansible-docker-test-01234567-start-stop_default Created\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Creating\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Created\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-container',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-container',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (changed check)" on 2024-01-13 in 2.12-ubuntu1804
+ (
+ '2.18.1-2.12-ubuntu1804-2024-01-13-docker_compose_v2-present-(changed-check)',
+ '2.18.1',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreated\n'
+ ' DRY-RUN MODE - Container 80c52c26780_ansible-docker-test-7c5458ac-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container 80c52c26780_ansible-docker-test-7c5458ac-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ '80c52c26780_ansible-docker-test-7c5458ac-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ '80c52c26780_ansible-docker-test-7c5458ac-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (changed check)" on 2024-01-07 in 2.12-ubuntu1804
+ (
+ '2.18.1-2.12-ubuntu1804-2024-01-07-docker_compose_v2-present-(changed-check)',
+ '2.18.1',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreated\n'
+ ' DRY-RUN MODE - Container 9121995872d_ansible-docker-test-dba91fb6-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container 9121995872d_ansible-docker-test-dba91fb6-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ '9121995872d_ansible-docker-test-dba91fb6-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ '9121995872d_ansible-docker-test-dba91fb6-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (changed)" on 2024-01-07 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Present (changed)" on 2024-01-13 in 2.12-ubuntu1804
+ (
+ '2.18.1-2.12-ubuntu1804-2024-01-07-docker_compose_v2-present-(changed)',
+ '2.18.1',
+ False,
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreate\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreated\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (check)" on 2024-01-13 in 2.12-ubuntu1804
+ (
+ '2.18.1-2.12-ubuntu1804-2024-01-13-docker_compose_v2-present-(check)',
+ '2.18.1',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-container Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-container Pulled \n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-7c5458ac-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-7c5458ac-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-container',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-container',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-7c5458ac-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-7c5458ac-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (check)" on 2024-01-07 in 2.12-ubuntu1804
+ (
+ '2.18.1-2.12-ubuntu1804-2024-01-07-docker_compose_v2-present-(check)',
+ '2.18.1',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-container Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-container Pulled \n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-dba91fb6-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-dba91fb6-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-container',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-container',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-dba91fb6-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-dba91fb6-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (idempotent check)" on 2024-01-07 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Present (idempotent check)" on 2024-01-13 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Started (idempotent check)" on 2024-01-07 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Started (idempotent check)" on 2024-01-13 in 2.12-ubuntu1804
+ (
+ '2.18.1-2.12-ubuntu1804-2024-01-07-docker_compose_v2-present-(idempotent-check)',
+ '2.18.1',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Running\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Running',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (idempotent)" on 2024-01-07 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Present (idempotent)" on 2024-01-13 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Started (idempotent)" on 2024-01-07 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Started (idempotent)" on 2024-01-13 in 2.12-ubuntu1804
+ (
+ '2.18.1-2.12-ubuntu1804-2024-01-07-docker_compose_v2-present-(idempotent)',
+ '2.18.1',
+ False,
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Running\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Running',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present stopped" on 2024-01-07 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Present stopped" on 2024-01-13 in 2.12-ubuntu1804
+ (
+ '2.18.1-2.12-ubuntu1804-2024-01-07-docker_compose_v2-present-stopped',
+ '2.18.1',
+ False,
+ ' Network ansible-docker-test-01234567-start-stop_default Creating\n'
+ ' Network ansible-docker-test-01234567-start-stop_default Created\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Creating\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Created\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Created',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present stopped (check)" on 2024-01-07 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Present stopped (check)" on 2024-01-13 in 2.12-ubuntu1804
+ (
+ '2.18.1-2.12-ubuntu1804-2024-01-07-docker_compose_v2-present-stopped-(check)',
+ '2.18.1',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Created\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Created',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=always" on 2024-01-07 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Present with pull=always" on 2024-01-13 in 2.12-ubuntu1804
+ (
+ '2.18.1-2.12-ubuntu1804-2024-01-07-docker_compose_v2-present-with-pull=always',
+ '2.18.1',
+ False,
+ ' ansible-docker-test-01234567-cont Pulling \n'
+ ' ansible-docker-test-01234567-cont Pulled \n'
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Running\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Running',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=always (check)" on 2024-01-07 in 2.12-ubuntu1804
+ (
+ '2.18.1-2.12-ubuntu1804-2024-01-07-docker_compose_v2-present-with-pull=always-(check)',
+ '2.18.1',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreated\n'
+ ' DRY-RUN MODE - Container 002a15404ac_ansible-docker-test-dba91fb6-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container 002a15404ac_ansible-docker-test-dba91fb6-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ '002a15404ac_ansible-docker-test-dba91fb6-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ '002a15404ac_ansible-docker-test-dba91fb6-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=always (check)" on 2024-01-13 in 2.12-ubuntu1804
+ (
+ '2.18.1-2.12-ubuntu1804-2024-01-13-docker_compose_v2-present-with-pull=always-(check)',
+ '2.18.1',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreated\n'
+ ' DRY-RUN MODE - Container ec060c7b341_ansible-docker-test-7c5458ac-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container ec060c7b341_ansible-docker-test-7c5458ac-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ec060c7b341_ansible-docker-test-7c5458ac-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ec060c7b341_ansible-docker-test-7c5458ac-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=missing" on 2024-01-07 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Present with pull=missing" on 2024-01-13 in 2.12-ubuntu1804
+ (
+ '2.18.1-2.12-ubuntu1804-2024-01-07-docker_compose_v2-present-with-pull=missing',
+ '2.18.1',
+ False,
+ ' ansible-docker-test-01234567-cont Pulling \n'
+ ' ansible-docker-test-01234567-cont Pulled \n'
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=missing (check)" on 2024-01-13 in 2.12-ubuntu1804
+ (
+ '2.18.1-2.12-ubuntu1804-2024-01-13-docker_compose_v2-present-with-pull=missing-(check)',
+ '2.18.1',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-7c5458ac-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-7c5458ac-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-7c5458ac-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-7c5458ac-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=missing (check)" on 2024-01-07 in 2.12-ubuntu1804
+ (
+ '2.18.1-2.12-ubuntu1804-2024-01-07-docker_compose_v2-present-with-pull=missing-(check)',
+ '2.18.1',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-dba91fb6-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-dba91fb6-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-dba91fb6-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-dba91fb6-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=missing (idempotent)" on 2024-01-07 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent)" on 2024-01-13 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent)" on 2024-01-07 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent)" on 2024-01-13 in 2.12-ubuntu1804
+ (
+ '2.18.1-2.12-ubuntu1804-2024-01-07-docker_compose_v2-present-with-pull=missing-(idempotent)',
+ '2.18.1',
+ False,
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Running\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Running',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=missing (idempotent, check)" on 2024-01-07 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent, check)" on 2024-01-13 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent, check)" on 2024-01-07 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent, check)" on 2024-01-13 in 2.12-ubuntu1804
+ (
+ '2.18.1-2.12-ubuntu1804-2024-01-07-docker_compose_v2-present-with-pull=missing-(idempotent,-check)',
+ '2.18.1',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Running\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Running',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=never" on 2024-01-07 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-13 in 2.12-ubuntu1804
+ (
+ '2.18.1-2.12-ubuntu1804-2024-01-07-docker_compose_v2-present-with-pull=never',
+ '2.18.1',
+ False,
+ ' Network ansible-docker-test-01234567-pull_default Creating\n'
+ ' Network ansible-docker-test-01234567-pull_default Created\n'
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=never" on 2024-01-07 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-13 in 2.12-ubuntu1804
+ (
+ '2.18.1-2.12-ubuntu1804-2024-01-07-docker_compose_v2-present-with-pull=never',
+ '2.18.1',
+ False,
+ ' Network ansible-docker-test-01234567-pull_default Creating\n'
+ ' Network ansible-docker-test-01234567-pull_default Created\n'
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ 'Error response from daemon: No such image: does-not-exist:latest\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'unknown',
+ '',
+ 'Error',
+ 'Error response from daemon: No such image: does-not-exist:latest',
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=never (check)" on 2024-01-13 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Present with pull=never (check)" on 2024-01-13 in 2.12-ubuntu1804
+ (
+ '2.18.1-2.12-ubuntu1804-2024-01-13-docker_compose_v2-present-with-pull=never-(check)',
+ '2.18.1',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-7c5458ac-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-7c5458ac-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-7c5458ac-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-7c5458ac-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=never (check)" on 2024-01-07 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Present with pull=never (check)" on 2024-01-07 in 2.12-ubuntu1804
+ (
+ '2.18.1-2.12-ubuntu1804-2024-01-07-docker_compose_v2-present-with-pull=never-(check)',
+ '2.18.1',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-dba91fb6-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-dba91fb6-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-dba91fb6-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-dba91fb6-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present without explicit pull" on 2024-01-07 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Present without explicit pull" on 2024-01-13 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2_pull: "Pull" on 2024-01-13 in 2.12-ubuntu1804
+ (
+ '2.18.1-2.12-ubuntu1804-2024-01-07-docker_compose_v2-present-without-explicit-pull',
+ '2.18.1',
+ False,
+ ' ansible-docker-test-01234567-cont Pulling \n'
+ ' ansible-docker-test-01234567-cont Error \n'
+ "Error response from daemon: pull access denied for does-not-exist, repository does not exist or may require 'docker login': denied: requested access to the resource is denied\n", # noqa: E501
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'unknown',
+ 'ansible-docker-test-01234567-cont',
+ 'Error',
+ "Error response from daemon: pull access denied for does-not-exist, repository does not exist or may require 'docker login': denied: requested access to the resource is denied", # noqa: E501
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present without explicit pull (check)" on 2024-01-07 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Present without explicit pull (check)" on 2024-01-13 in 2.12-ubuntu1804
+ (
+ '2.18.1-2.12-ubuntu1804-2024-01-07-docker_compose_v2-present-without-explicit-pull-(check)',
+ '2.18.1',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Error \n'
+ 'pull access denied, repository does not exist or may require authorization: server message: insufficient_scope: authorization failed\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'unknown',
+ 'ansible-docker-test-01234567-cont',
+ 'Error',
+ 'pull access denied, repository does not exist or may require authorization: server message: insufficient_scope: authorization failed',
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Restarted" on 2024-01-07 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-07 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-13 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-13 in 2.12-ubuntu1804
+ (
+ '2.18.1-2.12-ubuntu1804-2024-01-07-docker_compose_v2-restarted',
+ '2.18.1',
+ False,
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Restarting\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Restarting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Restarted (check)" on 2024-01-07 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-07 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-13 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-13 in 2.12-ubuntu1804
+ (
+ '2.18.1-2.12-ubuntu1804-2024-01-07-docker_compose_v2-restarted-(check)',
+ '2.18.1',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Restarting\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Restarting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Started" on 2024-01-07 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Started" on 2024-01-13 in 2.12-ubuntu1804
+ (
+ '2.18.1-2.12-ubuntu1804-2024-01-07-docker_compose_v2-started',
+ '2.18.1',
+ False,
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Started (check)" on 2024-01-07 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Started (check)" on 2024-01-13 in 2.12-ubuntu1804
+ (
+ '2.18.1-2.12-ubuntu1804-2024-01-07-docker_compose_v2-started-(check)',
+ '2.18.1',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Stopped" on 2024-01-07 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Stopped" on 2024-01-13 in 2.12-ubuntu1804
+ (
+ '2.18.1-2.12-ubuntu1804-2024-01-07-docker_compose_v2-stopped',
+ '2.18.1',
+ False,
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Running\n'
+ '\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Stopping\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Stopped\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Running',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Stopping',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Stopped',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Stopped (check)" on 2024-01-07 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2: "Stopped (check)" on 2024-01-13 in 2.12-ubuntu1804
+ (
+ '2.18.1-2.12-ubuntu1804-2024-01-07-docker_compose_v2-stopped-(check)',
+ '2.18.1',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Running\n'
+ '\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Stopping\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Stopped\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Running',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Stopping',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Stopped',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2_pull: "Pull (check)" on 2024-01-13 in 2.12-ubuntu1804
+ (
+ '2.18.1-2.12-ubuntu1804-2024-01-13-docker_compose_v2_pull-pull-(check)',
+ '2.18.1',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Error \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont - Pull error for image: does-not-exist:latest \n'
+ 'pull access denied, repository does not exist or may require authorization: server message: insufficient_scope: authorization failed\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'unknown',
+ 'ansible-docker-test-01234567-cont',
+ 'Error',
+ 'pull access denied, repository does not exist or may require authorization: server message: insufficient_scope: authorization failed',
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2_pull: "Pull with policy=always" on 2024-01-13 in 2.12-ubuntu1804
+ (
+ '2.18.1-2.12-ubuntu1804-2024-01-13-docker_compose_v2_pull-pull-with-policy=always',
+ '2.18.1',
+ False,
+ ' ansible-docker-test-01234567-cont Pulling \n'
+ ' 486039affc0a Pulling fs layer \n'
+ ' 486039affc0a Downloading [> ] 32.16kB/2.207MB\n'
+ ' 486039affc0a Verifying Checksum \n'
+ ' 486039affc0a Download complete \n'
+ ' 486039affc0a Extracting [> ] 32.77kB/2.207MB\n'
+ ' 486039affc0a Extracting [==================================================>] 2.207MB/2.207MB\n'
+ ' 486039affc0a Pull complete \n'
+ ' ansible-docker-test-01234567-cont Pulled \n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Pulling fs layer',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Downloading',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Verifying Checksum',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Download complete',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Extracting',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Extracting',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Pull complete',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2_pull: "Pull with policy=always (again)" on 2024-01-13 in 2.12-ubuntu1804
+ (
+ '2.18.1-2.12-ubuntu1804-2024-01-13-docker_compose_v2_pull-pull-with-policy=always-(again)',
+ '2.18.1',
+ False,
+ ' ansible-docker-test-01234567-cont Pulling \n'
+ ' ansible-docker-test-01234567-cont Pulled \n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2_pull: "Pull with policy=always (again, check)" on 2024-01-13 in 2.12-ubuntu1804
+ # Duplicated in: docker_compose_v2_pull: "Pull with policy=always (check)" on 2024-01-13 in 2.12-ubuntu1804
+ (
+ '2.18.1-2.12-ubuntu1804-2024-01-13-docker_compose_v2_pull-pull-with-policy=always-(again,-check)',
+ '2.18.1',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # #######################################################################################################################
+ # ## Docker Compose 2.21.0 ##############################################################################################
+ # #######################################################################################################################
+ # docker_compose_v2: "Absent" on 2024-01-07 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Absent" on 2024-01-13 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Absent" on 2024-01-07 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Absent" on 2024-01-13 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Absent" on 2024-01-07 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Absent" on 2024-01-13 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Absent" on 2024-01-07 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Absent" on 2024-01-13 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Absent" on 2024-01-07 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Absent" on 2024-01-13 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Absent" on 2024-01-07 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Absent" on 2024-01-13 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Absent" on 2024-01-07 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Absent" on 2024-01-13 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Absent" on 2024-01-07 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Absent" on 2024-01-13 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Absent" on 2024-01-07 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Absent" on 2024-01-13 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Absent" on 2024-01-07 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Absent" on 2024-01-13 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Absent" on 2024-01-07 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Absent" on 2024-01-13 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-07 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-13 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-07 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-13 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-07 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-13 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-07 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-13 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-07 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-13 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-07 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-13 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-07 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-13 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-07 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-13 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-07 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-13 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-07 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-13 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-07 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-13 in devel-ubuntu2204
+ (
+ '2.21.0-2.14-rhel9.0-2024-01-07-docker_compose_v2-absent',
+ '2.21.0',
+ False,
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Stopping\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Stopped\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Removing\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Removed\n'
+ ' Network ansible-docker-test-01234567-start-stop_default Removing\n'
+ ' Network ansible-docker-test-01234567-start-stop_default Removed\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Stopping',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Stopped',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Removing',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Removed',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Removing',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Removed',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Absent (check)" on 2024-01-07 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Absent (check)" on 2024-01-13 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Absent (check)" on 2024-01-07 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Absent (check)" on 2024-01-13 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Absent (check)" on 2024-01-07 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Absent (check)" on 2024-01-13 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Absent (check)" on 2024-01-07 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Absent (check)" on 2024-01-13 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Absent (check)" on 2024-01-07 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Absent (check)" on 2024-01-13 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Absent (check)" on 2024-01-07 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Absent (check)" on 2024-01-13 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Absent (check)" on 2024-01-07 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Absent (check)" on 2024-01-13 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Absent (check)" on 2024-01-07 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Absent (check)" on 2024-01-13 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Absent (check)" on 2024-01-07 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Absent (check)" on 2024-01-13 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Absent (check)" on 2024-01-07 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Absent (check)" on 2024-01-13 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Absent (check)" on 2024-01-07 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Absent (check)" on 2024-01-13 in devel-ubuntu2204
+ (
+ '2.21.0-2.14-rhel9.0-2024-01-07-docker_compose_v2-absent-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Stopping\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Stopped\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Removing\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Removed\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Removing\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Resource is still in use\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Stopping',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Stopped',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Removing',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Removed',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Removing',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ None,
+ 'Resource is still in use',
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Cleanup" on 2024-01-07 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-13 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-07 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-13 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-07 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-13 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-07 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-13 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-07 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-13 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-07 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-13 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-07 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-13 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-07 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-13 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-07 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-13 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-07 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-13 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-07 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-13 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Stopping service" on 2024-01-07 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Stopping service" on 2024-01-13 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Stopping service" on 2024-01-07 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Stopping service" on 2024-01-13 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Stopping service" on 2024-01-07 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Stopping service" on 2024-01-13 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Stopping service" on 2024-01-07 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Stopping service" on 2024-01-13 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Stopping service" on 2024-01-07 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Stopping service" on 2024-01-13 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Stopping service" on 2024-01-07 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Stopping service" on 2024-01-13 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Stopping service" on 2024-01-07 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Stopping service" on 2024-01-13 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Stopping service" on 2024-01-07 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Stopping service" on 2024-01-13 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Stopping service" on 2024-01-07 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Stopping service" on 2024-01-13 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Stopping service" on 2024-01-07 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Stopping service" on 2024-01-13 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Stopping service" on 2024-01-07 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Stopping service" on 2024-01-13 in devel-ubuntu2204
+ (
+ '2.21.0-2.14-rhel9.0-2024-01-07-docker_compose_v2-cleanup',
+ '2.21.0',
+ False,
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Stopping\n'
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Stopped\n'
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Removing\n'
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Removed\n'
+ ' Network ansible-docker-test-01234567-pull_default Removing\n'
+ ' Network ansible-docker-test-01234567-pull_default Removed\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Stopping',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Stopped',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Removing',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Removed',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Removing',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Removed',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present" on 2024-01-07 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Present" on 2024-01-13 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Present" on 2024-01-07 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Present" on 2024-01-13 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Present" on 2024-01-07 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Present" on 2024-01-13 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Present" on 2024-01-07 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Present" on 2024-01-13 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Present" on 2024-01-07 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Present" on 2024-01-13 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Present" on 2024-01-07 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Present" on 2024-01-13 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Present" on 2024-01-07 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Present" on 2024-01-13 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Present" on 2024-01-07 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Present" on 2024-01-13 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Present" on 2024-01-07 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Present" on 2024-01-13 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Present" on 2024-01-07 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Present" on 2024-01-13 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Present" on 2024-01-07 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Present" on 2024-01-13 in devel-ubuntu2204
+ (
+ '2.21.0-2.14-rhel9.0-2024-01-07-docker_compose_v2-present',
+ '2.21.0',
+ False,
+ ' Network ansible-docker-test-01234567-start-stop_default Creating\n'
+ ' Network ansible-docker-test-01234567-start-stop_default Created\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Creating\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Created\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (changed check)" on 2024-01-13 in 2.16-rhel9.2
+ (
+ '2.21.0-2.16-rhel9.2-2024-01-13-docker_compose_v2-present-(changed-check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreated\n'
+ ' DRY-RUN MODE - Container 054e03eb5ea_ansible-docker-test-b2745d99-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container 054e03eb5ea_ansible-docker-test-b2745d99-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ '054e03eb5ea_ansible-docker-test-b2745d99-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ '054e03eb5ea_ansible-docker-test-b2745d99-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (changed check)" on 2024-01-07 in 2.16-rhel9.2
+ (
+ '2.21.0-2.16-rhel9.2-2024-01-07-docker_compose_v2-present-(changed-check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreated\n'
+ ' DRY-RUN MODE - Container 0a77f424a61_ansible-docker-test-d1d30700-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container 0a77f424a61_ansible-docker-test-d1d30700-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ '0a77f424a61_ansible-docker-test-d1d30700-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ '0a77f424a61_ansible-docker-test-d1d30700-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (changed check)" on 2024-01-13 in devel-ubuntu2004
+ (
+ '2.21.0-devel-ubuntu2004-2024-01-13-docker_compose_v2-present-(changed-check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreated\n'
+ ' DRY-RUN MODE - Container 0e165a36533_ansible-docker-test-e700ac20-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container 0e165a36533_ansible-docker-test-e700ac20-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ '0e165a36533_ansible-docker-test-e700ac20-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ '0e165a36533_ansible-docker-test-e700ac20-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (changed check)" on 2024-01-07 in devel-ubuntu2204
+ (
+ '2.21.0-devel-ubuntu2204-2024-01-07-docker_compose_v2-present-(changed-check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreated\n'
+ ' DRY-RUN MODE - Container 26bf8ff1675_ansible-docker-test-1f1d0d58-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container 26bf8ff1675_ansible-docker-test-1f1d0d58-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ '26bf8ff1675_ansible-docker-test-1f1d0d58-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ '26bf8ff1675_ansible-docker-test-1f1d0d58-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (changed check)" on 2024-01-13 in 2.15-rhel9.1
+ (
+ '2.21.0-2.15-rhel9.1-2024-01-13-docker_compose_v2-present-(changed-check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreated\n'
+ ' DRY-RUN MODE - Container 27c209a84a5_ansible-docker-test-d616c3a5-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container 27c209a84a5_ansible-docker-test-d616c3a5-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ '27c209a84a5_ansible-docker-test-d616c3a5-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ '27c209a84a5_ansible-docker-test-d616c3a5-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (changed check)" on 2024-01-07 in devel-rhel9.3
+ (
+ '2.21.0-devel-rhel9.3-2024-01-07-docker_compose_v2-present-(changed-check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreated\n'
+ ' DRY-RUN MODE - Container 4b568108657_ansible-docker-test-64d917f4-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container 4b568108657_ansible-docker-test-64d917f4-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ '4b568108657_ansible-docker-test-64d917f4-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ '4b568108657_ansible-docker-test-64d917f4-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (changed check)" on 2024-01-07 in devel-ubuntu2004
+ (
+ '2.21.0-devel-ubuntu2004-2024-01-07-docker_compose_v2-present-(changed-check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreated\n'
+ ' DRY-RUN MODE - Container 6dc8d091c94_ansible-docker-test-2460e737-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container 6dc8d091c94_ansible-docker-test-2460e737-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ '6dc8d091c94_ansible-docker-test-2460e737-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ '6dc8d091c94_ansible-docker-test-2460e737-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (changed check)" on 2024-01-07 in 2.14-rhel9.0
+ (
+ '2.21.0-2.14-rhel9.0-2024-01-07-docker_compose_v2-present-(changed-check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreated\n'
+ ' DRY-RUN MODE - Container 71b893893dc_ansible-docker-test-4baa7139-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container 71b893893dc_ansible-docker-test-4baa7139-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ '71b893893dc_ansible-docker-test-4baa7139-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ '71b893893dc_ansible-docker-test-4baa7139-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (changed check)" on 2024-01-07 in devel-debian-bullseye
+ (
+ '2.21.0-devel-debian-bullseye-2024-01-07-docker_compose_v2-present-(changed-check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreated\n'
+ ' DRY-RUN MODE - Container 71e7a319c23_ansible-docker-test-19ffba88-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container 71e7a319c23_ansible-docker-test-19ffba88-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ '71e7a319c23_ansible-docker-test-19ffba88-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ '71e7a319c23_ansible-docker-test-19ffba88-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (changed check)" on 2024-01-07 in 2.16-centos7
+ (
+ '2.21.0-2.16-centos7-2024-01-07-docker_compose_v2-present-(changed-check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreated\n'
+ ' DRY-RUN MODE - Container 78e827e6673_ansible-docker-test-6aaaa304-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container 78e827e6673_ansible-docker-test-6aaaa304-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ '78e827e6673_ansible-docker-test-6aaaa304-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ '78e827e6673_ansible-docker-test-6aaaa304-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (changed check)" on 2024-01-13 in devel-debian-bookworm
+ (
+ '2.21.0-devel-debian-bookworm-2024-01-13-docker_compose_v2-present-(changed-check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreated\n'
+ ' DRY-RUN MODE - Container 7971b0c189d_ansible-docker-test-51914faa-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container 7971b0c189d_ansible-docker-test-51914faa-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ '7971b0c189d_ansible-docker-test-51914faa-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ '7971b0c189d_ansible-docker-test-51914faa-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (changed check)" on 2024-01-13 in devel-rhel9.3
+ (
+ '2.21.0-devel-rhel9.3-2024-01-13-docker_compose_v2-present-(changed-check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreated\n'
+ ' DRY-RUN MODE - Container 7b8d91093c9_ansible-docker-test-d2caf0c9-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container 7b8d91093c9_ansible-docker-test-d2caf0c9-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ '7b8d91093c9_ansible-docker-test-d2caf0c9-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ '7b8d91093c9_ansible-docker-test-d2caf0c9-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (changed check)" on 2024-01-13 in 2.16-centos7
+ (
+ '2.21.0-2.16-centos7-2024-01-13-docker_compose_v2-present-(changed-check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreated\n'
+ ' DRY-RUN MODE - Container 7bedd9b4513_ansible-docker-test-1ba2643a-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container 7bedd9b4513_ansible-docker-test-1ba2643a-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ '7bedd9b4513_ansible-docker-test-1ba2643a-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ '7bedd9b4513_ansible-docker-test-1ba2643a-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (changed check)" on 2024-01-13 in 2.15-rhel7.9
+ (
+ '2.21.0-2.15-rhel7.9-2024-01-13-docker_compose_v2-present-(changed-check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreated\n'
+ ' DRY-RUN MODE - Container 87873e68934_ansible-docker-test-ad622acd-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container 87873e68934_ansible-docker-test-ad622acd-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ '87873e68934_ansible-docker-test-ad622acd-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ '87873e68934_ansible-docker-test-ad622acd-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (changed check)" on 2024-01-13 in 2.14-rhel9.0
+ (
+ '2.21.0-2.14-rhel9.0-2024-01-13-docker_compose_v2-present-(changed-check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreated\n'
+ ' DRY-RUN MODE - Container a81dce9774b_ansible-docker-test-4fcbaf1e-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container a81dce9774b_ansible-docker-test-4fcbaf1e-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ 'a81dce9774b_ansible-docker-test-4fcbaf1e-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'a81dce9774b_ansible-docker-test-4fcbaf1e-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (changed check)" on 2024-01-13 in 2.15-centos7
+ (
+ '2.21.0-2.15-centos7-2024-01-13-docker_compose_v2-present-(changed-check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreated\n'
+ ' DRY-RUN MODE - Container d28b7978587_ansible-docker-test-971ad57c-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container d28b7978587_ansible-docker-test-971ad57c-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ 'd28b7978587_ansible-docker-test-971ad57c-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'd28b7978587_ansible-docker-test-971ad57c-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (changed check)" on 2024-01-07 in 2.15-rhel9.1
+ (
+ '2.21.0-2.15-rhel9.1-2024-01-07-docker_compose_v2-present-(changed-check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreated\n'
+ ' DRY-RUN MODE - Container dea4aafe907_ansible-docker-test-d6ae094c-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container dea4aafe907_ansible-docker-test-d6ae094c-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ 'dea4aafe907_ansible-docker-test-d6ae094c-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'dea4aafe907_ansible-docker-test-d6ae094c-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (changed check)" on 2024-01-07 in 2.15-centos7
+ (
+ '2.21.0-2.15-centos7-2024-01-07-docker_compose_v2-present-(changed-check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreated\n'
+ ' DRY-RUN MODE - Container e508faa8323_ansible-docker-test-ce1fa4d7-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container e508faa8323_ansible-docker-test-ce1fa4d7-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ 'e508faa8323_ansible-docker-test-ce1fa4d7-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'e508faa8323_ansible-docker-test-ce1fa4d7-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (changed check)" on 2024-01-13 in devel-ubuntu2204
+ (
+ '2.21.0-devel-ubuntu2204-2024-01-13-docker_compose_v2-present-(changed-check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreated\n'
+ ' DRY-RUN MODE - Container ef57cb7913f_ansible-docker-test-ede01681-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container ef57cb7913f_ansible-docker-test-ede01681-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ef57cb7913f_ansible-docker-test-ede01681-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ef57cb7913f_ansible-docker-test-ede01681-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (changed check)" on 2024-01-07 in 2.15-rhel7.9
+ (
+ '2.21.0-2.15-rhel7.9-2024-01-07-docker_compose_v2-present-(changed-check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreated\n'
+ ' DRY-RUN MODE - Container efe8857a191_ansible-docker-test-601188b1-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container efe8857a191_ansible-docker-test-601188b1-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ 'efe8857a191_ansible-docker-test-601188b1-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'efe8857a191_ansible-docker-test-601188b1-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (changed check)" on 2024-01-13 in devel-debian-bullseye
+ (
+ '2.21.0-devel-debian-bullseye-2024-01-13-docker_compose_v2-present-(changed-check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreated\n'
+ ' DRY-RUN MODE - Container f0de40ba686_ansible-docker-test-834c1a9b-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container f0de40ba686_ansible-docker-test-834c1a9b-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ 'f0de40ba686_ansible-docker-test-834c1a9b-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'f0de40ba686_ansible-docker-test-834c1a9b-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (changed check)" on 2024-01-07 in devel-debian-bookworm
+ (
+ '2.21.0-devel-debian-bookworm-2024-01-07-docker_compose_v2-present-(changed-check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreated\n'
+ ' DRY-RUN MODE - Container f6416652e13_ansible-docker-test-5f3d2e16-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container f6416652e13_ansible-docker-test-5f3d2e16-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ 'f6416652e13_ansible-docker-test-5f3d2e16-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'f6416652e13_ansible-docker-test-5f3d2e16-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (changed)" on 2024-01-07 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Present (changed)" on 2024-01-13 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Present (changed)" on 2024-01-07 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Present (changed)" on 2024-01-13 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Present (changed)" on 2024-01-07 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Present (changed)" on 2024-01-13 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Present (changed)" on 2024-01-07 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Present (changed)" on 2024-01-13 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Present (changed)" on 2024-01-07 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Present (changed)" on 2024-01-13 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Present (changed)" on 2024-01-07 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Present (changed)" on 2024-01-13 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Present (changed)" on 2024-01-07 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Present (changed)" on 2024-01-13 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Present (changed)" on 2024-01-07 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Present (changed)" on 2024-01-13 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Present (changed)" on 2024-01-07 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Present (changed)" on 2024-01-13 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Present (changed)" on 2024-01-07 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Present (changed)" on 2024-01-13 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Present (changed)" on 2024-01-07 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Present (changed)" on 2024-01-13 in devel-ubuntu2204
+ (
+ '2.21.0-2.14-rhel9.0-2024-01-07-docker_compose_v2-present-(changed)',
+ '2.21.0',
+ False,
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreate\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreated\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (check)" on 2024-01-07 in devel-debian-bullseye
+ (
+ '2.21.0-devel-debian-bullseye-2024-01-07-docker_compose_v2-present-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-19ffba88-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-19ffba88-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-19ffba88-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-19ffba88-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (check)" on 2024-01-13 in 2.16-centos7
+ (
+ '2.21.0-2.16-centos7-2024-01-13-docker_compose_v2-present-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-1ba2643a-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-1ba2643a-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-1ba2643a-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-1ba2643a-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (check)" on 2024-01-07 in devel-ubuntu2204
+ (
+ '2.21.0-devel-ubuntu2204-2024-01-07-docker_compose_v2-present-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-1f1d0d58-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-1f1d0d58-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-1f1d0d58-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-1f1d0d58-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (check)" on 2024-01-07 in devel-ubuntu2004
+ (
+ '2.21.0-devel-ubuntu2004-2024-01-07-docker_compose_v2-present-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-2460e737-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-2460e737-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-2460e737-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-2460e737-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (check)" on 2024-01-07 in 2.14-rhel9.0
+ (
+ '2.21.0-2.14-rhel9.0-2024-01-07-docker_compose_v2-present-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-4baa7139-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-4baa7139-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-4baa7139-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-4baa7139-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (check)" on 2024-01-13 in 2.14-rhel9.0
+ (
+ '2.21.0-2.14-rhel9.0-2024-01-13-docker_compose_v2-present-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-4fcbaf1e-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-4fcbaf1e-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-4fcbaf1e-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-4fcbaf1e-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (check)" on 2024-01-13 in devel-debian-bookworm
+ (
+ '2.21.0-devel-debian-bookworm-2024-01-13-docker_compose_v2-present-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-51914faa-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-51914faa-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-51914faa-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-51914faa-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (check)" on 2024-01-07 in devel-debian-bookworm
+ (
+ '2.21.0-devel-debian-bookworm-2024-01-07-docker_compose_v2-present-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-5f3d2e16-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-5f3d2e16-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-5f3d2e16-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-5f3d2e16-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (check)" on 2024-01-07 in 2.15-rhel7.9
+ (
+ '2.21.0-2.15-rhel7.9-2024-01-07-docker_compose_v2-present-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-601188b1-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-601188b1-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-601188b1-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-601188b1-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (check)" on 2024-01-07 in devel-rhel9.3
+ (
+ '2.21.0-devel-rhel9.3-2024-01-07-docker_compose_v2-present-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-64d917f4-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-64d917f4-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-64d917f4-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-64d917f4-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (check)" on 2024-01-07 in 2.16-centos7
+ (
+ '2.21.0-2.16-centos7-2024-01-07-docker_compose_v2-present-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-6aaaa304-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-6aaaa304-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-6aaaa304-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-6aaaa304-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (check)" on 2024-01-13 in devel-debian-bullseye
+ (
+ '2.21.0-devel-debian-bullseye-2024-01-13-docker_compose_v2-present-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-834c1a9b-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-834c1a9b-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-834c1a9b-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-834c1a9b-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (check)" on 2024-01-13 in 2.15-centos7
+ (
+ '2.21.0-2.15-centos7-2024-01-13-docker_compose_v2-present-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-971ad57c-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-971ad57c-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-971ad57c-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-971ad57c-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (check)" on 2024-01-13 in 2.15-rhel7.9
+ (
+ '2.21.0-2.15-rhel7.9-2024-01-13-docker_compose_v2-present-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-ad622acd-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-ad622acd-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-ad622acd-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-ad622acd-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (check)" on 2024-01-13 in 2.16-rhel9.2
+ (
+ '2.21.0-2.16-rhel9.2-2024-01-13-docker_compose_v2-present-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-b2745d99-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-b2745d99-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-b2745d99-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-b2745d99-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (check)" on 2024-01-07 in 2.15-centos7
+ (
+ '2.21.0-2.15-centos7-2024-01-07-docker_compose_v2-present-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-ce1fa4d7-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-ce1fa4d7-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-ce1fa4d7-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-ce1fa4d7-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (check)" on 2024-01-07 in 2.16-rhel9.2
+ (
+ '2.21.0-2.16-rhel9.2-2024-01-07-docker_compose_v2-present-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-d1d30700-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-d1d30700-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-d1d30700-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-d1d30700-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (check)" on 2024-01-13 in devel-rhel9.3
+ (
+ '2.21.0-devel-rhel9.3-2024-01-13-docker_compose_v2-present-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-d2caf0c9-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-d2caf0c9-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-d2caf0c9-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-d2caf0c9-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (check)" on 2024-01-13 in 2.15-rhel9.1
+ (
+ '2.21.0-2.15-rhel9.1-2024-01-13-docker_compose_v2-present-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-d616c3a5-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-d616c3a5-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-d616c3a5-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-d616c3a5-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (check)" on 2024-01-07 in 2.15-rhel9.1
+ (
+ '2.21.0-2.15-rhel9.1-2024-01-07-docker_compose_v2-present-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-d6ae094c-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-d6ae094c-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-d6ae094c-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-d6ae094c-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (check)" on 2024-01-13 in devel-ubuntu2004
+ (
+ '2.21.0-devel-ubuntu2004-2024-01-13-docker_compose_v2-present-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-e700ac20-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-e700ac20-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-e700ac20-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-e700ac20-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (check)" on 2024-01-13 in devel-ubuntu2204
+ (
+ '2.21.0-devel-ubuntu2204-2024-01-13-docker_compose_v2-present-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-ede01681-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-ede01681-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-ede01681-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-ede01681-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (idempotent check)" on 2024-01-07 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Present (idempotent check)" on 2024-01-13 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Present (idempotent check)" on 2024-01-07 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Present (idempotent check)" on 2024-01-13 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Present (idempotent check)" on 2024-01-07 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Present (idempotent check)" on 2024-01-13 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Present (idempotent check)" on 2024-01-07 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Present (idempotent check)" on 2024-01-13 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Present (idempotent check)" on 2024-01-07 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Present (idempotent check)" on 2024-01-13 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Present (idempotent check)" on 2024-01-07 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Present (idempotent check)" on 2024-01-13 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Present (idempotent check)" on 2024-01-07 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Present (idempotent check)" on 2024-01-13 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Present (idempotent check)" on 2024-01-07 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Present (idempotent check)" on 2024-01-13 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Present (idempotent check)" on 2024-01-07 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Present (idempotent check)" on 2024-01-13 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Present (idempotent check)" on 2024-01-07 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Present (idempotent check)" on 2024-01-13 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Present (idempotent check)" on 2024-01-07 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Present (idempotent check)" on 2024-01-13 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Started (idempotent check)" on 2024-01-07 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Started (idempotent check)" on 2024-01-13 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Started (idempotent check)" on 2024-01-07 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Started (idempotent check)" on 2024-01-13 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Started (idempotent check)" on 2024-01-07 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Started (idempotent check)" on 2024-01-13 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Started (idempotent check)" on 2024-01-07 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Started (idempotent check)" on 2024-01-13 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Started (idempotent check)" on 2024-01-07 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Started (idempotent check)" on 2024-01-13 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Started (idempotent check)" on 2024-01-07 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Started (idempotent check)" on 2024-01-13 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Started (idempotent check)" on 2024-01-07 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Started (idempotent check)" on 2024-01-13 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Started (idempotent check)" on 2024-01-07 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Started (idempotent check)" on 2024-01-13 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Started (idempotent check)" on 2024-01-07 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Started (idempotent check)" on 2024-01-13 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Started (idempotent check)" on 2024-01-07 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Started (idempotent check)" on 2024-01-13 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Started (idempotent check)" on 2024-01-07 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Started (idempotent check)" on 2024-01-13 in devel-ubuntu2204
+ (
+ '2.21.0-2.14-rhel9.0-2024-01-07-docker_compose_v2-present-(idempotent-check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Running\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Running',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (idempotent)" on 2024-01-07 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Present (idempotent)" on 2024-01-13 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Present (idempotent)" on 2024-01-07 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Present (idempotent)" on 2024-01-13 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Present (idempotent)" on 2024-01-07 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Present (idempotent)" on 2024-01-13 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Present (idempotent)" on 2024-01-07 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Present (idempotent)" on 2024-01-13 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Present (idempotent)" on 2024-01-07 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Present (idempotent)" on 2024-01-13 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Present (idempotent)" on 2024-01-07 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Present (idempotent)" on 2024-01-13 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Present (idempotent)" on 2024-01-07 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Present (idempotent)" on 2024-01-13 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Present (idempotent)" on 2024-01-07 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Present (idempotent)" on 2024-01-13 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Present (idempotent)" on 2024-01-07 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Present (idempotent)" on 2024-01-13 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Present (idempotent)" on 2024-01-07 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Present (idempotent)" on 2024-01-13 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Present (idempotent)" on 2024-01-07 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Present (idempotent)" on 2024-01-13 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Started (idempotent)" on 2024-01-07 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Started (idempotent)" on 2024-01-13 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Started (idempotent)" on 2024-01-07 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Started (idempotent)" on 2024-01-13 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Started (idempotent)" on 2024-01-07 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Started (idempotent)" on 2024-01-13 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Started (idempotent)" on 2024-01-07 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Started (idempotent)" on 2024-01-13 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Started (idempotent)" on 2024-01-07 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Started (idempotent)" on 2024-01-13 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Started (idempotent)" on 2024-01-07 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Started (idempotent)" on 2024-01-13 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Started (idempotent)" on 2024-01-07 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Started (idempotent)" on 2024-01-13 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Started (idempotent)" on 2024-01-07 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Started (idempotent)" on 2024-01-13 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Started (idempotent)" on 2024-01-07 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Started (idempotent)" on 2024-01-13 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Started (idempotent)" on 2024-01-07 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Started (idempotent)" on 2024-01-13 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Started (idempotent)" on 2024-01-07 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Started (idempotent)" on 2024-01-13 in devel-ubuntu2204
+ (
+ '2.21.0-2.14-rhel9.0-2024-01-07-docker_compose_v2-present-(idempotent)',
+ '2.21.0',
+ False,
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Running\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Running',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present stopped" on 2024-01-07 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Present stopped" on 2024-01-13 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Present stopped" on 2024-01-07 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Present stopped" on 2024-01-13 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Present stopped" on 2024-01-07 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Present stopped" on 2024-01-13 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Present stopped" on 2024-01-07 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Present stopped" on 2024-01-13 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Present stopped" on 2024-01-07 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Present stopped" on 2024-01-13 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Present stopped" on 2024-01-07 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Present stopped" on 2024-01-13 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Present stopped" on 2024-01-07 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Present stopped" on 2024-01-13 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Present stopped" on 2024-01-07 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Present stopped" on 2024-01-13 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Present stopped" on 2024-01-07 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Present stopped" on 2024-01-13 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Present stopped" on 2024-01-07 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Present stopped" on 2024-01-13 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Present stopped" on 2024-01-07 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Present stopped" on 2024-01-13 in devel-ubuntu2204
+ (
+ '2.21.0-2.14-rhel9.0-2024-01-07-docker_compose_v2-present-stopped',
+ '2.21.0',
+ False,
+ ' Network ansible-docker-test-01234567-start-stop_default Creating\n'
+ ' Network ansible-docker-test-01234567-start-stop_default Created\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Creating\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Created\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Created',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present stopped (check)" on 2024-01-07 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Present stopped (check)" on 2024-01-13 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Present stopped (check)" on 2024-01-07 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Present stopped (check)" on 2024-01-13 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Present stopped (check)" on 2024-01-07 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Present stopped (check)" on 2024-01-13 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Present stopped (check)" on 2024-01-07 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Present stopped (check)" on 2024-01-13 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Present stopped (check)" on 2024-01-07 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Present stopped (check)" on 2024-01-13 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Present stopped (check)" on 2024-01-07 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Present stopped (check)" on 2024-01-13 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Present stopped (check)" on 2024-01-07 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Present stopped (check)" on 2024-01-13 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Present stopped (check)" on 2024-01-07 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Present stopped (check)" on 2024-01-13 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Present stopped (check)" on 2024-01-07 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Present stopped (check)" on 2024-01-13 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Present stopped (check)" on 2024-01-07 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Present stopped (check)" on 2024-01-13 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Present stopped (check)" on 2024-01-07 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Present stopped (check)" on 2024-01-13 in devel-ubuntu2204
+ (
+ '2.21.0-2.14-rhel9.0-2024-01-07-docker_compose_v2-present-stopped-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Created\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Created',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=always" on 2024-01-07 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Present with pull=always" on 2024-01-13 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Present with pull=always" on 2024-01-07 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Present with pull=always" on 2024-01-13 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Present with pull=always" on 2024-01-07 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Present with pull=always" on 2024-01-13 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Present with pull=always" on 2024-01-07 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Present with pull=always" on 2024-01-13 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Present with pull=always" on 2024-01-07 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Present with pull=always" on 2024-01-13 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Present with pull=always" on 2024-01-07 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Present with pull=always" on 2024-01-13 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Present with pull=always" on 2024-01-07 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Present with pull=always" on 2024-01-13 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Present with pull=always" on 2024-01-07 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Present with pull=always" on 2024-01-13 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Present with pull=always" on 2024-01-07 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Present with pull=always" on 2024-01-13 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Present with pull=always" on 2024-01-07 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Present with pull=always" on 2024-01-13 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Present with pull=always" on 2024-01-07 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Present with pull=always" on 2024-01-13 in devel-ubuntu2204
+ (
+ '2.21.0-2.14-rhel9.0-2024-01-07-docker_compose_v2-present-with-pull=always',
+ '2.21.0',
+ False,
+ ' ansible-docker-test-01234567-cont Pulling \n'
+ ' ansible-docker-test-01234567-cont Pulled \n'
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Running\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Running',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=always (check)" on 2024-01-13 in devel-debian-bookworm
+ (
+ '2.21.0-devel-debian-bookworm-2024-01-13-docker_compose_v2-present-with-pull=always-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreated\n'
+ ' DRY-RUN MODE - Container 0b4286904e0_ansible-docker-test-51914faa-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container 0b4286904e0_ansible-docker-test-51914faa-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ '0b4286904e0_ansible-docker-test-51914faa-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ '0b4286904e0_ansible-docker-test-51914faa-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=always (check)" on 2024-01-07 in devel-ubuntu2204
+ (
+ '2.21.0-devel-ubuntu2204-2024-01-07-docker_compose_v2-present-with-pull=always-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreated\n'
+ ' DRY-RUN MODE - Container 0d5362bac93_ansible-docker-test-1f1d0d58-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container 0d5362bac93_ansible-docker-test-1f1d0d58-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ '0d5362bac93_ansible-docker-test-1f1d0d58-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ '0d5362bac93_ansible-docker-test-1f1d0d58-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=always (check)" on 2024-01-07 in 2.16-rhel9.2
+ (
+ '2.21.0-2.16-rhel9.2-2024-01-07-docker_compose_v2-present-with-pull=always-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreated\n'
+ ' DRY-RUN MODE - Container 3d7b7be6dbe_ansible-docker-test-d1d30700-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container 3d7b7be6dbe_ansible-docker-test-d1d30700-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ '3d7b7be6dbe_ansible-docker-test-d1d30700-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ '3d7b7be6dbe_ansible-docker-test-d1d30700-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=always (check)" on 2024-01-13 in 2.16-centos7
+ (
+ '2.21.0-2.16-centos7-2024-01-13-docker_compose_v2-present-with-pull=always-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreated\n'
+ ' DRY-RUN MODE - Container 49ff7fef052_ansible-docker-test-1ba2643a-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container 49ff7fef052_ansible-docker-test-1ba2643a-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ '49ff7fef052_ansible-docker-test-1ba2643a-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ '49ff7fef052_ansible-docker-test-1ba2643a-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=always (check)" on 2024-01-07 in 2.16-centos7
+ (
+ '2.21.0-2.16-centos7-2024-01-07-docker_compose_v2-present-with-pull=always-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreated\n'
+ ' DRY-RUN MODE - Container 5d30320650e_ansible-docker-test-6aaaa304-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container 5d30320650e_ansible-docker-test-6aaaa304-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ '5d30320650e_ansible-docker-test-6aaaa304-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ '5d30320650e_ansible-docker-test-6aaaa304-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=always (check)" on 2024-01-07 in 2.15-rhel7.9
+ (
+ '2.21.0-2.15-rhel7.9-2024-01-07-docker_compose_v2-present-with-pull=always-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreated\n'
+ ' DRY-RUN MODE - Container 611a044106b_ansible-docker-test-601188b1-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container 611a044106b_ansible-docker-test-601188b1-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ '611a044106b_ansible-docker-test-601188b1-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ '611a044106b_ansible-docker-test-601188b1-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=always (check)" on 2024-01-13 in devel-ubuntu2004
+ (
+ '2.21.0-devel-ubuntu2004-2024-01-13-docker_compose_v2-present-with-pull=always-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreated\n'
+ ' DRY-RUN MODE - Container 61802a08aa6_ansible-docker-test-e700ac20-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container 61802a08aa6_ansible-docker-test-e700ac20-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ '61802a08aa6_ansible-docker-test-e700ac20-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ '61802a08aa6_ansible-docker-test-e700ac20-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=always (check)" on 2024-01-07 in 2.15-centos7
+ (
+ '2.21.0-2.15-centos7-2024-01-07-docker_compose_v2-present-with-pull=always-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreated\n'
+ ' DRY-RUN MODE - Container 61bd1b13d9c_ansible-docker-test-ce1fa4d7-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container 61bd1b13d9c_ansible-docker-test-ce1fa4d7-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ '61bd1b13d9c_ansible-docker-test-ce1fa4d7-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ '61bd1b13d9c_ansible-docker-test-ce1fa4d7-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=always (check)" on 2024-01-13 in devel-rhel9.3
+ (
+ '2.21.0-devel-rhel9.3-2024-01-13-docker_compose_v2-present-with-pull=always-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreated\n'
+ ' DRY-RUN MODE - Container 769aec9cd4d_ansible-docker-test-d2caf0c9-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container 769aec9cd4d_ansible-docker-test-d2caf0c9-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ '769aec9cd4d_ansible-docker-test-d2caf0c9-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ '769aec9cd4d_ansible-docker-test-d2caf0c9-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=always (check)" on 2024-01-13 in devel-ubuntu2204
+ (
+ '2.21.0-devel-ubuntu2204-2024-01-13-docker_compose_v2-present-with-pull=always-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreated\n'
+ ' DRY-RUN MODE - Container 813ca227a6f_ansible-docker-test-ede01681-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container 813ca227a6f_ansible-docker-test-ede01681-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ '813ca227a6f_ansible-docker-test-ede01681-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ '813ca227a6f_ansible-docker-test-ede01681-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=always (check)" on 2024-01-13 in devel-debian-bullseye
+ (
+ '2.21.0-devel-debian-bullseye-2024-01-13-docker_compose_v2-present-with-pull=always-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreated\n'
+ ' DRY-RUN MODE - Container 8a586ed91d6_ansible-docker-test-834c1a9b-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container 8a586ed91d6_ansible-docker-test-834c1a9b-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ '8a586ed91d6_ansible-docker-test-834c1a9b-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ '8a586ed91d6_ansible-docker-test-834c1a9b-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=always (check)" on 2024-01-07 in devel-rhel9.3
+ (
+ '2.21.0-devel-rhel9.3-2024-01-07-docker_compose_v2-present-with-pull=always-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreated\n'
+ ' DRY-RUN MODE - Container 8bec416e98d_ansible-docker-test-64d917f4-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container 8bec416e98d_ansible-docker-test-64d917f4-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ '8bec416e98d_ansible-docker-test-64d917f4-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ '8bec416e98d_ansible-docker-test-64d917f4-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=always (check)" on 2024-01-13 in 2.16-rhel9.2
+ (
+ '2.21.0-2.16-rhel9.2-2024-01-13-docker_compose_v2-present-with-pull=always-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreated\n'
+ ' DRY-RUN MODE - Container 906450ba6e7_ansible-docker-test-b2745d99-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container 906450ba6e7_ansible-docker-test-b2745d99-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ '906450ba6e7_ansible-docker-test-b2745d99-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ '906450ba6e7_ansible-docker-test-b2745d99-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=always (check)" on 2024-01-13 in 2.15-rhel9.1
+ (
+ '2.21.0-2.15-rhel9.1-2024-01-13-docker_compose_v2-present-with-pull=always-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreated\n'
+ ' DRY-RUN MODE - Container a99ed30c7d6_ansible-docker-test-d616c3a5-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container a99ed30c7d6_ansible-docker-test-d616c3a5-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ 'a99ed30c7d6_ansible-docker-test-d616c3a5-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'a99ed30c7d6_ansible-docker-test-d616c3a5-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=always (check)" on 2024-01-07 in 2.15-rhel9.1
+ (
+ '2.21.0-2.15-rhel9.1-2024-01-07-docker_compose_v2-present-with-pull=always-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreated\n'
+ ' DRY-RUN MODE - Container b78faf8a742_ansible-docker-test-d6ae094c-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container b78faf8a742_ansible-docker-test-d6ae094c-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ 'b78faf8a742_ansible-docker-test-d6ae094c-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'b78faf8a742_ansible-docker-test-d6ae094c-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=always (check)" on 2024-01-13 in 2.15-centos7
+ (
+ '2.21.0-2.15-centos7-2024-01-13-docker_compose_v2-present-with-pull=always-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreated\n'
+ ' DRY-RUN MODE - Container be1b2a9ca28_ansible-docker-test-971ad57c-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container be1b2a9ca28_ansible-docker-test-971ad57c-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ 'be1b2a9ca28_ansible-docker-test-971ad57c-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'be1b2a9ca28_ansible-docker-test-971ad57c-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=always (check)" on 2024-01-07 in devel-debian-bookworm
+ (
+ '2.21.0-devel-debian-bookworm-2024-01-07-docker_compose_v2-present-with-pull=always-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreated\n'
+ ' DRY-RUN MODE - Container c9d730c2613_ansible-docker-test-5f3d2e16-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container c9d730c2613_ansible-docker-test-5f3d2e16-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ 'c9d730c2613_ansible-docker-test-5f3d2e16-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'c9d730c2613_ansible-docker-test-5f3d2e16-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=always (check)" on 2024-01-13 in 2.15-rhel7.9
+ (
+ '2.21.0-2.15-rhel7.9-2024-01-13-docker_compose_v2-present-with-pull=always-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreated\n'
+ ' DRY-RUN MODE - Container da16aa68f6f_ansible-docker-test-ad622acd-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container da16aa68f6f_ansible-docker-test-ad622acd-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ 'da16aa68f6f_ansible-docker-test-ad622acd-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'da16aa68f6f_ansible-docker-test-ad622acd-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=always (check)" on 2024-01-13 in 2.14-rhel9.0
+ (
+ '2.21.0-2.14-rhel9.0-2024-01-13-docker_compose_v2-present-with-pull=always-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreated\n'
+ ' DRY-RUN MODE - Container dff4b309c58_ansible-docker-test-4fcbaf1e-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container dff4b309c58_ansible-docker-test-4fcbaf1e-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ 'dff4b309c58_ansible-docker-test-4fcbaf1e-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'dff4b309c58_ansible-docker-test-4fcbaf1e-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=always (check)" on 2024-01-07 in 2.14-rhel9.0
+ (
+ '2.21.0-2.14-rhel9.0-2024-01-07-docker_compose_v2-present-with-pull=always-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreated\n'
+ ' DRY-RUN MODE - Container ecd243ea972_ansible-docker-test-4baa7139-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container ecd243ea972_ansible-docker-test-4baa7139-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ecd243ea972_ansible-docker-test-4baa7139-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ecd243ea972_ansible-docker-test-4baa7139-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=always (check)" on 2024-01-07 in devel-ubuntu2004
+ (
+ '2.21.0-devel-ubuntu2004-2024-01-07-docker_compose_v2-present-with-pull=always-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreated\n'
+ ' DRY-RUN MODE - Container f48d54a75fb_ansible-docker-test-2460e737-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container f48d54a75fb_ansible-docker-test-2460e737-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ 'f48d54a75fb_ansible-docker-test-2460e737-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'f48d54a75fb_ansible-docker-test-2460e737-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=always (check)" on 2024-01-07 in devel-debian-bullseye
+ (
+ '2.21.0-devel-debian-bullseye-2024-01-07-docker_compose_v2-present-with-pull=always-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreated\n'
+ ' DRY-RUN MODE - Container fa8f62dfced_ansible-docker-test-19ffba88-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container fa8f62dfced_ansible-docker-test-19ffba88-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ 'fa8f62dfced_ansible-docker-test-19ffba88-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'fa8f62dfced_ansible-docker-test-19ffba88-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=missing" on 2024-01-07 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Present with pull=missing" on 2024-01-13 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Present with pull=missing" on 2024-01-07 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Present with pull=missing" on 2024-01-13 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Present with pull=missing" on 2024-01-07 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Present with pull=missing" on 2024-01-13 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Present with pull=missing" on 2024-01-07 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Present with pull=missing" on 2024-01-13 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Present with pull=missing" on 2024-01-07 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Present with pull=missing" on 2024-01-13 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Present with pull=missing" on 2024-01-07 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Present with pull=missing" on 2024-01-13 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Present with pull=missing" on 2024-01-07 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Present with pull=missing" on 2024-01-13 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Present with pull=missing" on 2024-01-07 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Present with pull=missing" on 2024-01-13 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Present with pull=missing" on 2024-01-07 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Present with pull=missing" on 2024-01-13 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Present with pull=missing" on 2024-01-07 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Present with pull=missing" on 2024-01-13 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Present with pull=missing" on 2024-01-07 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Present with pull=missing" on 2024-01-13 in devel-ubuntu2204
+ (
+ '2.21.0-2.14-rhel9.0-2024-01-07-docker_compose_v2-present-with-pull=missing',
+ '2.21.0',
+ False,
+ ' ansible-docker-test-01234567-cont Pulling \n'
+ ' ansible-docker-test-01234567-cont Pulled \n'
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=missing (check)" on 2024-01-07 in devel-debian-bullseye
+ (
+ '2.21.0-devel-debian-bullseye-2024-01-07-docker_compose_v2-present-with-pull=missing-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-19ffba88-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-19ffba88-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-19ffba88-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-19ffba88-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=missing (check)" on 2024-01-13 in 2.16-centos7
+ (
+ '2.21.0-2.16-centos7-2024-01-13-docker_compose_v2-present-with-pull=missing-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-1ba2643a-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-1ba2643a-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-1ba2643a-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-1ba2643a-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=missing (check)" on 2024-01-07 in devel-ubuntu2204
+ (
+ '2.21.0-devel-ubuntu2204-2024-01-07-docker_compose_v2-present-with-pull=missing-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-1f1d0d58-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-1f1d0d58-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-1f1d0d58-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-1f1d0d58-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=missing (check)" on 2024-01-07 in devel-ubuntu2004
+ (
+ '2.21.0-devel-ubuntu2004-2024-01-07-docker_compose_v2-present-with-pull=missing-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-2460e737-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-2460e737-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-2460e737-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-2460e737-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=missing (check)" on 2024-01-07 in 2.14-rhel9.0
+ (
+ '2.21.0-2.14-rhel9.0-2024-01-07-docker_compose_v2-present-with-pull=missing-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-4baa7139-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-4baa7139-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-4baa7139-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-4baa7139-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=missing (check)" on 2024-01-13 in 2.14-rhel9.0
+ (
+ '2.21.0-2.14-rhel9.0-2024-01-13-docker_compose_v2-present-with-pull=missing-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-4fcbaf1e-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-4fcbaf1e-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-4fcbaf1e-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-4fcbaf1e-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=missing (check)" on 2024-01-13 in devel-debian-bookworm
+ (
+ '2.21.0-devel-debian-bookworm-2024-01-13-docker_compose_v2-present-with-pull=missing-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-51914faa-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-51914faa-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-51914faa-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-51914faa-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=missing (check)" on 2024-01-07 in devel-debian-bookworm
+ (
+ '2.21.0-devel-debian-bookworm-2024-01-07-docker_compose_v2-present-with-pull=missing-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-5f3d2e16-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-5f3d2e16-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-5f3d2e16-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-5f3d2e16-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=missing (check)" on 2024-01-07 in 2.15-rhel7.9
+ (
+ '2.21.0-2.15-rhel7.9-2024-01-07-docker_compose_v2-present-with-pull=missing-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-601188b1-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-601188b1-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-601188b1-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-601188b1-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=missing (check)" on 2024-01-07 in devel-rhel9.3
+ (
+ '2.21.0-devel-rhel9.3-2024-01-07-docker_compose_v2-present-with-pull=missing-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-64d917f4-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-64d917f4-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-64d917f4-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-64d917f4-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=missing (check)" on 2024-01-07 in 2.16-centos7
+ (
+ '2.21.0-2.16-centos7-2024-01-07-docker_compose_v2-present-with-pull=missing-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-6aaaa304-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-6aaaa304-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-6aaaa304-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-6aaaa304-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=missing (check)" on 2024-01-13 in devel-debian-bullseye
+ (
+ '2.21.0-devel-debian-bullseye-2024-01-13-docker_compose_v2-present-with-pull=missing-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-834c1a9b-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-834c1a9b-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-834c1a9b-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-834c1a9b-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=missing (check)" on 2024-01-13 in 2.15-centos7
+ (
+ '2.21.0-2.15-centos7-2024-01-13-docker_compose_v2-present-with-pull=missing-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-971ad57c-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-971ad57c-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-971ad57c-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-971ad57c-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=missing (check)" on 2024-01-13 in 2.15-rhel7.9
+ (
+ '2.21.0-2.15-rhel7.9-2024-01-13-docker_compose_v2-present-with-pull=missing-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-ad622acd-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-ad622acd-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-ad622acd-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-ad622acd-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=missing (check)" on 2024-01-13 in 2.16-rhel9.2
+ (
+ '2.21.0-2.16-rhel9.2-2024-01-13-docker_compose_v2-present-with-pull=missing-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-b2745d99-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-b2745d99-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-b2745d99-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-b2745d99-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=missing (check)" on 2024-01-07 in 2.15-centos7
+ (
+ '2.21.0-2.15-centos7-2024-01-07-docker_compose_v2-present-with-pull=missing-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-ce1fa4d7-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-ce1fa4d7-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-ce1fa4d7-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-ce1fa4d7-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=missing (check)" on 2024-01-07 in 2.16-rhel9.2
+ (
+ '2.21.0-2.16-rhel9.2-2024-01-07-docker_compose_v2-present-with-pull=missing-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-d1d30700-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-d1d30700-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-d1d30700-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-d1d30700-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=missing (check)" on 2024-01-13 in devel-rhel9.3
+ (
+ '2.21.0-devel-rhel9.3-2024-01-13-docker_compose_v2-present-with-pull=missing-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-d2caf0c9-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-d2caf0c9-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-d2caf0c9-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-d2caf0c9-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=missing (check)" on 2024-01-13 in 2.15-rhel9.1
+ (
+ '2.21.0-2.15-rhel9.1-2024-01-13-docker_compose_v2-present-with-pull=missing-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-d616c3a5-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-d616c3a5-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-d616c3a5-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-d616c3a5-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=missing (check)" on 2024-01-07 in 2.15-rhel9.1
+ (
+ '2.21.0-2.15-rhel9.1-2024-01-07-docker_compose_v2-present-with-pull=missing-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-d6ae094c-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-d6ae094c-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-d6ae094c-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-d6ae094c-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=missing (check)" on 2024-01-13 in devel-ubuntu2004
+ (
+ '2.21.0-devel-ubuntu2004-2024-01-13-docker_compose_v2-present-with-pull=missing-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-e700ac20-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-e700ac20-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-e700ac20-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-e700ac20-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=missing (check)" on 2024-01-13 in devel-ubuntu2204
+ (
+ '2.21.0-devel-ubuntu2204-2024-01-13-docker_compose_v2-present-with-pull=missing-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-ede01681-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-ede01681-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-ede01681-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-ede01681-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=missing (idempotent)" on 2024-01-07 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent)" on 2024-01-13 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent)" on 2024-01-07 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent)" on 2024-01-13 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent)" on 2024-01-07 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent)" on 2024-01-13 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent)" on 2024-01-07 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent)" on 2024-01-13 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent)" on 2024-01-07 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent)" on 2024-01-13 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent)" on 2024-01-07 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent)" on 2024-01-13 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent)" on 2024-01-07 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent)" on 2024-01-13 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent)" on 2024-01-07 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent)" on 2024-01-13 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent)" on 2024-01-07 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent)" on 2024-01-13 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent)" on 2024-01-07 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent)" on 2024-01-13 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent)" on 2024-01-07 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent)" on 2024-01-13 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent)" on 2024-01-07 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent)" on 2024-01-13 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent)" on 2024-01-07 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent)" on 2024-01-13 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent)" on 2024-01-07 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent)" on 2024-01-13 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent)" on 2024-01-07 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent)" on 2024-01-13 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent)" on 2024-01-07 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent)" on 2024-01-13 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent)" on 2024-01-07 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent)" on 2024-01-13 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent)" on 2024-01-07 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent)" on 2024-01-13 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent)" on 2024-01-07 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent)" on 2024-01-13 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent)" on 2024-01-07 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent)" on 2024-01-13 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent)" on 2024-01-07 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent)" on 2024-01-13 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent)" on 2024-01-07 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent)" on 2024-01-13 in devel-ubuntu2204
+ (
+ '2.21.0-2.14-rhel9.0-2024-01-07-docker_compose_v2-present-with-pull=missing-(idempotent)',
+ '2.21.0',
+ False,
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Running\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Running',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=missing (idempotent, check)" on 2024-01-07 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent, check)" on 2024-01-13 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent, check)" on 2024-01-07 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent, check)" on 2024-01-13 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent, check)" on 2024-01-07 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent, check)" on 2024-01-13 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent, check)" on 2024-01-07 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent, check)" on 2024-01-13 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent, check)" on 2024-01-07 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent, check)" on 2024-01-13 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent, check)" on 2024-01-07 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent, check)" on 2024-01-13 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent, check)" on 2024-01-07 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent, check)" on 2024-01-13 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent, check)" on 2024-01-07 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent, check)" on 2024-01-13 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent, check)" on 2024-01-07 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent, check)" on 2024-01-13 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent, check)" on 2024-01-07 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent, check)" on 2024-01-13 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent, check)" on 2024-01-07 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent, check)" on 2024-01-13 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent, check)" on 2024-01-07 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent, check)" on 2024-01-13 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent, check)" on 2024-01-07 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent, check)" on 2024-01-13 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent, check)" on 2024-01-07 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent, check)" on 2024-01-13 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent, check)" on 2024-01-07 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent, check)" on 2024-01-13 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent, check)" on 2024-01-07 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent, check)" on 2024-01-13 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent, check)" on 2024-01-07 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent, check)" on 2024-01-13 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent, check)" on 2024-01-07 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent, check)" on 2024-01-13 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent, check)" on 2024-01-07 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent, check)" on 2024-01-13 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent, check)" on 2024-01-07 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent, check)" on 2024-01-13 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent, check)" on 2024-01-07 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent, check)" on 2024-01-13 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent, check)" on 2024-01-07 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent, check)" on 2024-01-13 in devel-ubuntu2204
+ (
+ '2.21.0-2.14-rhel9.0-2024-01-07-docker_compose_v2-present-with-pull=missing-(idempotent,-check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Running\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Running',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=never" on 2024-01-07 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-13 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-07 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-13 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-07 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-13 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-07 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-13 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-07 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-13 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-07 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-13 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-07 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-13 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-07 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-13 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-07 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-13 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-07 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-13 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-07 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-13 in devel-ubuntu2204
+ (
+ '2.21.0-2.14-rhel9.0-2024-01-07-docker_compose_v2-present-with-pull=never',
+ '2.21.0',
+ False,
+ ' Network ansible-docker-test-01234567-pull_default Creating\n'
+ ' Network ansible-docker-test-01234567-pull_default Created\n'
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=never" on 2024-01-07 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-13 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-07 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-13 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-07 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-13 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-07 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-13 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-07 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-13 in devel-rhel9.3
+ (
+ '2.21.0-2.14-rhel9.0-2024-01-07-docker_compose_v2-present-with-pull=never',
+ '2.21.0',
+ False,
+ ' Network ansible-docker-test-01234567-pull_default Creating\n'
+ ' Network ansible-docker-test-01234567-pull_default Created\n'
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ 'Error response from daemon: No such image: does-not-exist:latest\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'unknown',
+ '',
+ 'Error',
+ 'Error response from daemon: No such image: does-not-exist:latest',
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=never" on 2024-01-07 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-13 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-07 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-13 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-07 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-13 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-07 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-13 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-07 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-13 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-07 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-13 in devel-ubuntu2204
+ (
+ '2.21.0-2.15-centos7-2024-01-07-docker_compose_v2-present-with-pull=never',
+ '2.21.0',
+ False,
+ ' Network ansible-docker-test-01234567-pull_default Creating\n'
+ ' Network ansible-docker-test-01234567-pull_default Created\n'
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ 'Error response from daemon: no such image: does-not-exist:latest: No such image: does-not-exist:latest\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'unknown',
+ '',
+ 'Error',
+ 'Error response from daemon: no such image: does-not-exist:latest: No such image: does-not-exist:latest',
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=never (check)" on 2024-01-07 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Present with pull=never (check)" on 2024-01-07 in devel-debian-bullseye
+ (
+ '2.21.0-devel-debian-bullseye-2024-01-07-docker_compose_v2-present-with-pull=never-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-19ffba88-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-19ffba88-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-19ffba88-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-19ffba88-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=never (check)" on 2024-01-13 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Present with pull=never (check)" on 2024-01-13 in 2.16-centos7
+ (
+ '2.21.0-2.16-centos7-2024-01-13-docker_compose_v2-present-with-pull=never-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-1ba2643a-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-1ba2643a-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-1ba2643a-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-1ba2643a-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=never (check)" on 2024-01-07 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Present with pull=never (check)" on 2024-01-07 in devel-ubuntu2204
+ (
+ '2.21.0-devel-ubuntu2204-2024-01-07-docker_compose_v2-present-with-pull=never-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-1f1d0d58-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-1f1d0d58-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-1f1d0d58-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-1f1d0d58-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=never (check)" on 2024-01-07 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Present with pull=never (check)" on 2024-01-07 in devel-ubuntu2004
+ (
+ '2.21.0-devel-ubuntu2004-2024-01-07-docker_compose_v2-present-with-pull=never-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-2460e737-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-2460e737-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-2460e737-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-2460e737-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=never (check)" on 2024-01-07 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Present with pull=never (check)" on 2024-01-07 in 2.14-rhel9.0
+ (
+ '2.21.0-2.14-rhel9.0-2024-01-07-docker_compose_v2-present-with-pull=never-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-4baa7139-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-4baa7139-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-4baa7139-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-4baa7139-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=never (check)" on 2024-01-13 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Present with pull=never (check)" on 2024-01-13 in 2.14-rhel9.0
+ (
+ '2.21.0-2.14-rhel9.0-2024-01-13-docker_compose_v2-present-with-pull=never-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-4fcbaf1e-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-4fcbaf1e-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-4fcbaf1e-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-4fcbaf1e-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=never (check)" on 2024-01-13 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Present with pull=never (check)" on 2024-01-13 in devel-debian-bookworm
+ (
+ '2.21.0-devel-debian-bookworm-2024-01-13-docker_compose_v2-present-with-pull=never-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-51914faa-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-51914faa-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-51914faa-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-51914faa-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=never (check)" on 2024-01-07 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Present with pull=never (check)" on 2024-01-07 in devel-debian-bookworm
+ (
+ '2.21.0-devel-debian-bookworm-2024-01-07-docker_compose_v2-present-with-pull=never-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-5f3d2e16-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-5f3d2e16-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-5f3d2e16-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-5f3d2e16-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=never (check)" on 2024-01-07 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Present with pull=never (check)" on 2024-01-07 in 2.15-rhel7.9
+ (
+ '2.21.0-2.15-rhel7.9-2024-01-07-docker_compose_v2-present-with-pull=never-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-601188b1-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-601188b1-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-601188b1-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-601188b1-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=never (check)" on 2024-01-07 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Present with pull=never (check)" on 2024-01-07 in devel-rhel9.3
+ (
+ '2.21.0-devel-rhel9.3-2024-01-07-docker_compose_v2-present-with-pull=never-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-64d917f4-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-64d917f4-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-64d917f4-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-64d917f4-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=never (check)" on 2024-01-07 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Present with pull=never (check)" on 2024-01-07 in 2.16-centos7
+ (
+ '2.21.0-2.16-centos7-2024-01-07-docker_compose_v2-present-with-pull=never-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-6aaaa304-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-6aaaa304-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-6aaaa304-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-6aaaa304-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=never (check)" on 2024-01-13 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Present with pull=never (check)" on 2024-01-13 in devel-debian-bullseye
+ (
+ '2.21.0-devel-debian-bullseye-2024-01-13-docker_compose_v2-present-with-pull=never-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-834c1a9b-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-834c1a9b-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-834c1a9b-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-834c1a9b-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=never (check)" on 2024-01-13 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Present with pull=never (check)" on 2024-01-13 in 2.15-centos7
+ (
+ '2.21.0-2.15-centos7-2024-01-13-docker_compose_v2-present-with-pull=never-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-971ad57c-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-971ad57c-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-971ad57c-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-971ad57c-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=never (check)" on 2024-01-13 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Present with pull=never (check)" on 2024-01-13 in 2.15-rhel7.9
+ (
+ '2.21.0-2.15-rhel7.9-2024-01-13-docker_compose_v2-present-with-pull=never-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-ad622acd-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-ad622acd-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-ad622acd-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-ad622acd-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=never (check)" on 2024-01-13 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Present with pull=never (check)" on 2024-01-13 in 2.16-rhel9.2
+ (
+ '2.21.0-2.16-rhel9.2-2024-01-13-docker_compose_v2-present-with-pull=never-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-b2745d99-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-b2745d99-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-b2745d99-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-b2745d99-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=never (check)" on 2024-01-07 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Present with pull=never (check)" on 2024-01-07 in 2.15-centos7
+ (
+ '2.21.0-2.15-centos7-2024-01-07-docker_compose_v2-present-with-pull=never-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-ce1fa4d7-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-ce1fa4d7-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-ce1fa4d7-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-ce1fa4d7-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=never (check)" on 2024-01-07 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Present with pull=never (check)" on 2024-01-07 in 2.16-rhel9.2
+ (
+ '2.21.0-2.16-rhel9.2-2024-01-07-docker_compose_v2-present-with-pull=never-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-d1d30700-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-d1d30700-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-d1d30700-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-d1d30700-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=never (check)" on 2024-01-13 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Present with pull=never (check)" on 2024-01-13 in devel-rhel9.3
+ (
+ '2.21.0-devel-rhel9.3-2024-01-13-docker_compose_v2-present-with-pull=never-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-d2caf0c9-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-d2caf0c9-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-d2caf0c9-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-d2caf0c9-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=never (check)" on 2024-01-13 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Present with pull=never (check)" on 2024-01-13 in 2.15-rhel9.1
+ (
+ '2.21.0-2.15-rhel9.1-2024-01-13-docker_compose_v2-present-with-pull=never-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-d616c3a5-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-d616c3a5-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-d616c3a5-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-d616c3a5-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=never (check)" on 2024-01-07 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Present with pull=never (check)" on 2024-01-07 in 2.15-rhel9.1
+ (
+ '2.21.0-2.15-rhel9.1-2024-01-07-docker_compose_v2-present-with-pull=never-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-d6ae094c-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-d6ae094c-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-d6ae094c-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-d6ae094c-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=never (check)" on 2024-01-13 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Present with pull=never (check)" on 2024-01-13 in devel-ubuntu2004
+ (
+ '2.21.0-devel-ubuntu2004-2024-01-13-docker_compose_v2-present-with-pull=never-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-e700ac20-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-e700ac20-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-e700ac20-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-e700ac20-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=never (check)" on 2024-01-13 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Present with pull=never (check)" on 2024-01-13 in devel-ubuntu2204
+ (
+ '2.21.0-devel-ubuntu2204-2024-01-13-docker_compose_v2-present-with-pull=never-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-ede01681-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-ede01681-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-ede01681-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-ede01681-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present without explicit pull" on 2024-01-07 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Present without explicit pull" on 2024-01-13 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Present without explicit pull" on 2024-01-07 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Present without explicit pull" on 2024-01-13 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Present without explicit pull" on 2024-01-07 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Present without explicit pull" on 2024-01-13 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Present without explicit pull" on 2024-01-07 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Present without explicit pull" on 2024-01-13 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Present without explicit pull" on 2024-01-07 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Present without explicit pull" on 2024-01-13 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Present without explicit pull" on 2024-01-07 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Present without explicit pull" on 2024-01-13 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Present without explicit pull" on 2024-01-07 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Present without explicit pull" on 2024-01-13 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Present without explicit pull" on 2024-01-07 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Present without explicit pull" on 2024-01-13 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Present without explicit pull" on 2024-01-07 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Present without explicit pull" on 2024-01-13 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Present without explicit pull" on 2024-01-07 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Present without explicit pull" on 2024-01-13 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Present without explicit pull" on 2024-01-07 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Present without explicit pull" on 2024-01-13 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2_pull: "Pull" on 2024-01-13 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2_pull: "Pull" on 2024-01-13 in 2.15-centos7
+ # Duplicated in: docker_compose_v2_pull: "Pull" on 2024-01-13 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2_pull: "Pull" on 2024-01-13 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2_pull: "Pull" on 2024-01-13 in 2.16-centos7
+ # Duplicated in: docker_compose_v2_pull: "Pull" on 2024-01-13 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2_pull: "Pull" on 2024-01-13 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2_pull: "Pull" on 2024-01-13 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2_pull: "Pull" on 2024-01-13 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2_pull: "Pull" on 2024-01-13 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2_pull: "Pull" on 2024-01-13 in devel-ubuntu2204
+ (
+ '2.21.0-2.14-rhel9.0-2024-01-07-docker_compose_v2-present-without-explicit-pull',
+ '2.21.0',
+ False,
+ ' ansible-docker-test-01234567-cont Pulling \n'
+ ' ansible-docker-test-01234567-cont Error \n'
+ "Error response from daemon: pull access denied for does-not-exist, repository does not exist or may require 'docker login': denied: requested access to the resource is denied\n", # noqa: E501
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'unknown',
+ 'ansible-docker-test-01234567-cont',
+ 'Error',
+ "Error response from daemon: pull access denied for does-not-exist, repository does not exist or may require 'docker login': denied: requested access to the resource is denied", # noqa: E501
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present without explicit pull (check)" on 2024-01-07 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Present without explicit pull (check)" on 2024-01-13 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Present without explicit pull (check)" on 2024-01-07 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Present without explicit pull (check)" on 2024-01-13 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Present without explicit pull (check)" on 2024-01-07 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Present without explicit pull (check)" on 2024-01-13 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Present without explicit pull (check)" on 2024-01-07 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Present without explicit pull (check)" on 2024-01-13 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Present without explicit pull (check)" on 2024-01-07 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Present without explicit pull (check)" on 2024-01-13 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Present without explicit pull (check)" on 2024-01-07 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Present without explicit pull (check)" on 2024-01-13 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Present without explicit pull (check)" on 2024-01-07 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Present without explicit pull (check)" on 2024-01-13 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Present without explicit pull (check)" on 2024-01-07 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Present without explicit pull (check)" on 2024-01-13 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Present without explicit pull (check)" on 2024-01-07 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Present without explicit pull (check)" on 2024-01-13 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Present without explicit pull (check)" on 2024-01-07 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Present without explicit pull (check)" on 2024-01-13 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Present without explicit pull (check)" on 2024-01-07 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Present without explicit pull (check)" on 2024-01-13 in devel-ubuntu2204
+ (
+ '2.21.0-2.14-rhel9.0-2024-01-07-docker_compose_v2-present-without-explicit-pull-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Error \n'
+ 'pull access denied, repository does not exist or may require authorization: server message: insufficient_scope: authorization failed\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'unknown',
+ 'ansible-docker-test-01234567-cont',
+ 'Error',
+ 'pull access denied, repository does not exist or may require authorization: server message: insufficient_scope: authorization failed',
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Restarted" on 2024-01-07 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-07 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-13 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-13 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-07 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-07 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-13 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-13 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-07 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-07 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-13 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-13 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-07 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-07 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-13 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-13 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-07 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-07 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-13 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-13 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-07 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-07 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-13 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-13 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-07 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-07 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-13 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-13 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-07 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-07 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-13 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-13 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-07 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-07 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-13 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-13 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-07 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-07 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-13 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-13 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-07 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-07 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-13 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-13 in devel-ubuntu2204
+ (
+ '2.21.0-2.14-rhel9.0-2024-01-07-docker_compose_v2-restarted',
+ '2.21.0',
+ False,
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Restarting\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Restarting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Restarted (check)" on 2024-01-07 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-07 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-13 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-13 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-07 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-07 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-13 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-13 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-07 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-07 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-13 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-13 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-07 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-07 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-13 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-13 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-07 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-07 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-13 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-13 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-07 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-07 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-13 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-13 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-07 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-07 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-13 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-13 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-07 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-07 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-13 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-13 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-07 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-07 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-13 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-13 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-07 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-07 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-13 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-13 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-07 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-07 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-13 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-13 in devel-ubuntu2204
+ (
+ '2.21.0-2.14-rhel9.0-2024-01-07-docker_compose_v2-restarted-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Restarting\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Restarting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Started" on 2024-01-07 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Started" on 2024-01-13 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Started" on 2024-01-07 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Started" on 2024-01-13 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Started" on 2024-01-07 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Started" on 2024-01-13 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Started" on 2024-01-07 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Started" on 2024-01-13 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Started" on 2024-01-07 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Started" on 2024-01-13 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Started" on 2024-01-07 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Started" on 2024-01-13 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Started" on 2024-01-07 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Started" on 2024-01-13 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Started" on 2024-01-07 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Started" on 2024-01-13 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Started" on 2024-01-07 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Started" on 2024-01-13 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Started" on 2024-01-07 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Started" on 2024-01-13 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Started" on 2024-01-07 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Started" on 2024-01-13 in devel-ubuntu2204
+ (
+ '2.21.0-2.14-rhel9.0-2024-01-07-docker_compose_v2-started',
+ '2.21.0',
+ False,
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Started (check)" on 2024-01-07 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Started (check)" on 2024-01-13 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Started (check)" on 2024-01-07 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Started (check)" on 2024-01-13 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Started (check)" on 2024-01-07 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Started (check)" on 2024-01-13 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Started (check)" on 2024-01-07 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Started (check)" on 2024-01-13 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Started (check)" on 2024-01-07 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Started (check)" on 2024-01-13 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Started (check)" on 2024-01-07 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Started (check)" on 2024-01-13 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Started (check)" on 2024-01-07 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Started (check)" on 2024-01-13 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Started (check)" on 2024-01-07 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Started (check)" on 2024-01-13 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Started (check)" on 2024-01-07 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Started (check)" on 2024-01-13 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Started (check)" on 2024-01-07 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Started (check)" on 2024-01-13 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Started (check)" on 2024-01-07 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Started (check)" on 2024-01-13 in devel-ubuntu2204
+ (
+ '2.21.0-2.14-rhel9.0-2024-01-07-docker_compose_v2-started-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Stopped" on 2024-01-07 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Stopped" on 2024-01-13 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Stopped" on 2024-01-07 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Stopped" on 2024-01-13 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Stopped" on 2024-01-07 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Stopped" on 2024-01-13 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Stopped" on 2024-01-07 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Stopped" on 2024-01-13 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Stopped" on 2024-01-07 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Stopped" on 2024-01-13 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Stopped" on 2024-01-07 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Stopped" on 2024-01-13 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Stopped" on 2024-01-07 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Stopped" on 2024-01-13 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Stopped" on 2024-01-07 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Stopped" on 2024-01-13 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Stopped" on 2024-01-07 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Stopped" on 2024-01-13 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Stopped" on 2024-01-07 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Stopped" on 2024-01-13 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Stopped" on 2024-01-07 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Stopped" on 2024-01-13 in devel-ubuntu2204
+ (
+ '2.21.0-2.14-rhel9.0-2024-01-07-docker_compose_v2-stopped',
+ '2.21.0',
+ False,
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Running\n'
+ '\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Stopping\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Stopped\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Running',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Stopping',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Stopped',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Stopped (check)" on 2024-01-07 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Stopped (check)" on 2024-01-13 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2: "Stopped (check)" on 2024-01-07 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Stopped (check)" on 2024-01-13 in 2.15-centos7
+ # Duplicated in: docker_compose_v2: "Stopped (check)" on 2024-01-07 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Stopped (check)" on 2024-01-13 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2: "Stopped (check)" on 2024-01-07 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Stopped (check)" on 2024-01-13 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2: "Stopped (check)" on 2024-01-07 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Stopped (check)" on 2024-01-13 in 2.16-centos7
+ # Duplicated in: docker_compose_v2: "Stopped (check)" on 2024-01-07 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Stopped (check)" on 2024-01-13 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2: "Stopped (check)" on 2024-01-07 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Stopped (check)" on 2024-01-13 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2: "Stopped (check)" on 2024-01-07 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Stopped (check)" on 2024-01-13 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2: "Stopped (check)" on 2024-01-07 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Stopped (check)" on 2024-01-13 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2: "Stopped (check)" on 2024-01-07 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Stopped (check)" on 2024-01-13 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2: "Stopped (check)" on 2024-01-07 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2: "Stopped (check)" on 2024-01-13 in devel-ubuntu2204
+ (
+ '2.21.0-2.14-rhel9.0-2024-01-07-docker_compose_v2-stopped-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Running\n'
+ '\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Stopping\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Stopped\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Running',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Stopping',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Stopped',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2_pull: "Pull (check)" on 2024-01-13 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2_pull: "Pull (check)" on 2024-01-13 in 2.15-centos7
+ # Duplicated in: docker_compose_v2_pull: "Pull (check)" on 2024-01-13 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2_pull: "Pull (check)" on 2024-01-13 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2_pull: "Pull (check)" on 2024-01-13 in 2.16-centos7
+ # Duplicated in: docker_compose_v2_pull: "Pull (check)" on 2024-01-13 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2_pull: "Pull (check)" on 2024-01-13 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2_pull: "Pull (check)" on 2024-01-13 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2_pull: "Pull (check)" on 2024-01-13 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2_pull: "Pull (check)" on 2024-01-13 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2_pull: "Pull (check)" on 2024-01-13 in devel-ubuntu2204
+ (
+ '2.21.0-2.14-rhel9.0-2024-01-13-docker_compose_v2_pull-pull-(check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Error \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont - Pull error for image: does-not-exist:latest \n'
+ 'pull access denied, repository does not exist or may require authorization: server message: insufficient_scope: authorization failed\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'unknown',
+ 'ansible-docker-test-01234567-cont',
+ 'Error',
+ 'pull access denied, repository does not exist or may require authorization: server message: insufficient_scope: authorization failed',
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2_pull: "Pull with policy=always" on 2024-01-13 in 2.15-rhel7.9
+ (
+ '2.21.0-2.15-rhel7.9-2024-01-13-docker_compose_v2_pull-pull-with-policy=always',
+ '2.21.0',
+ False,
+ ' ansible-docker-test-01234567-cont Pulling \n'
+ ' 486039affc0a Pulling fs layer \n'
+ ' 486039affc0a Downloading [> ] 34.2kB/2.207MB\n'
+ ' 486039affc0a Verifying Checksum \n'
+ ' 486039affc0a Download complete \n'
+ ' 486039affc0a Extracting [> ] 32.77kB/2.207MB\n'
+ ' 486039affc0a Extracting [==================================================>] 2.207MB/2.207MB\n'
+ ' 486039affc0a Pull complete \n'
+ ' ansible-docker-test-01234567-cont Pulled \n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Pulling fs layer',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Downloading',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Verifying Checksum',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Download complete',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Extracting',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Extracting',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Pull complete',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2_pull: "Pull with policy=always" on 2024-01-13 in 2.15-rhel9.1
+ (
+ '2.21.0-2.15-rhel9.1-2024-01-13-docker_compose_v2_pull-pull-with-policy=always',
+ '2.21.0',
+ False,
+ ' ansible-docker-test-01234567-cont Pulling \n'
+ ' 486039affc0a Pulling fs layer \n'
+ ' 486039affc0a Downloading [> ] 32.12kB/2.207MB\n'
+ ' 486039affc0a Download complete \n'
+ ' 486039affc0a Extracting [> ] 32.77kB/2.207MB\n'
+ ' 486039affc0a Extracting [==================================================>] 2.207MB/2.207MB\n'
+ ' 486039affc0a Pull complete \n'
+ ' ansible-docker-test-01234567-cont Pulled \n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Pulling fs layer',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Downloading',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Download complete',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Extracting',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Extracting',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Pull complete',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2_pull: "Pull with policy=always" on 2024-01-13 in 2.16-rhel9.2
+ (
+ '2.21.0-2.16-rhel9.2-2024-01-13-docker_compose_v2_pull-pull-with-policy=always',
+ '2.21.0',
+ False,
+ ' ansible-docker-test-01234567-cont Pulling \n'
+ ' 486039affc0a Pulling fs layer \n'
+ ' 486039affc0a Downloading [> ] 32.12kB/2.207MB\n'
+ ' 486039affc0a Downloading [==================================================>] 2.207MB/2.207MB\n'
+ ' 486039affc0a Download complete \n'
+ ' 486039affc0a Extracting [> ] 32.77kB/2.207MB\n'
+ ' 486039affc0a Extracting [==================================================>] 2.207MB/2.207MB\n'
+ ' 486039affc0a Pull complete \n'
+ ' ansible-docker-test-01234567-cont Pulled \n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Pulling fs layer',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Downloading',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Downloading',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Download complete',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Extracting',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Extracting',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Pull complete',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2_pull: "Pull with policy=always" on 2024-01-13 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2_pull: "Pull with policy=always" on 2024-01-13 in devel-rhel9.3
+ (
+ '2.21.0-2.14-rhel9.0-2024-01-13-docker_compose_v2_pull-pull-with-policy=always',
+ '2.21.0',
+ False,
+ ' ansible-docker-test-01234567-cont Pulling \n'
+ ' 486039affc0a Pulling fs layer \n'
+ ' 486039affc0a Downloading [> ] 32.16kB/2.207MB\n'
+ ' 486039affc0a Verifying Checksum \n'
+ ' 486039affc0a Download complete \n'
+ ' 486039affc0a Extracting [> ] 32.77kB/2.207MB\n'
+ ' 486039affc0a Extracting [==================================================>] 2.207MB/2.207MB\n'
+ ' 486039affc0a Pull complete \n'
+ ' ansible-docker-test-01234567-cont Pulled \n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Pulling fs layer',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Downloading',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Verifying Checksum',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Download complete',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Extracting',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Extracting',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Pull complete',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2_pull: "Pull with policy=always" on 2024-01-13 in 2.16-centos7
+ (
+ '2.21.0-2.16-centos7-2024-01-13-docker_compose_v2_pull-pull-with-policy=always',
+ '2.21.0',
+ False,
+ ' ansible-docker-test-01234567-cont Pulling \n'
+ ' 486039affc0a Pulling fs layer \n'
+ ' 486039affc0a Downloading [> ] 32.16kB/2.207MB\n'
+ ' 486039affc0a Verifying Checksum \n'
+ ' 486039affc0a Download complete \n'
+ ' 486039affc0a Extracting [> ] 32.77kB/2.207MB\n'
+ ' 486039affc0a Extracting [================================================> ] 2.13MB/2.207MB\n'
+ ' 486039affc0a Extracting [==================================================>] 2.207MB/2.207MB\n'
+ ' 486039affc0a Pull complete \n'
+ ' ansible-docker-test-01234567-cont Pulled \n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Pulling fs layer',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Downloading',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Verifying Checksum',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Download complete',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Extracting',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Extracting',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Extracting',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Pull complete',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2_pull: "Pull with policy=always" on 2024-01-13 in devel-ubuntu2204
+ (
+ '2.21.0-devel-ubuntu2204-2024-01-13-docker_compose_v2_pull-pull-with-policy=always',
+ '2.21.0',
+ False,
+ ' ansible-docker-test-01234567-cont Pulling \n'
+ ' 486039affc0a Pulling fs layer \n'
+ ' 486039affc0a Downloading [> ] 32.16kB/2.207MB\n'
+ ' 486039affc0a Verifying Checksum \n'
+ ' 486039affc0a Download complete \n'
+ ' 486039affc0a Extracting [> ] 32.77kB/2.207MB\n'
+ ' 486039affc0a Extracting [===============================================> ] 2.097MB/2.207MB\n'
+ ' 486039affc0a Extracting [==================================================>] 2.207MB/2.207MB\n'
+ ' 486039affc0a Pull complete \n'
+ ' ansible-docker-test-01234567-cont Pulled \n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Pulling fs layer',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Downloading',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Verifying Checksum',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Download complete',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Extracting',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Extracting',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Extracting',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Pull complete',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2_pull: "Pull with policy=always" on 2024-01-13 in devel-debian-bookworm
+ (
+ '2.21.0-devel-debian-bookworm-2024-01-13-docker_compose_v2_pull-pull-with-policy=always',
+ '2.21.0',
+ False,
+ ' ansible-docker-test-01234567-cont Pulling \n'
+ ' 486039affc0a Pulling fs layer \n'
+ ' 486039affc0a Downloading [> ] 32.16kB/2.207MB\n'
+ ' 486039affc0a Verifying Checksum \n'
+ ' 486039affc0a Download complete \n'
+ ' 486039affc0a Extracting [> ] 32.77kB/2.207MB\n'
+ ' 486039affc0a Extracting [==============================================> ] 2.032MB/2.207MB\n'
+ ' 486039affc0a Extracting [==================================================>] 2.207MB/2.207MB\n'
+ ' 486039affc0a Pull complete \n'
+ ' ansible-docker-test-01234567-cont Pulled \n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Pulling fs layer',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Downloading',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Verifying Checksum',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Download complete',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Extracting',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Extracting',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Extracting',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Pull complete',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2_pull: "Pull with policy=always" on 2024-01-13 in devel-ubuntu2004
+ (
+ '2.21.0-devel-ubuntu2004-2024-01-13-docker_compose_v2_pull-pull-with-policy=always',
+ '2.21.0',
+ False,
+ ' ansible-docker-test-01234567-cont Pulling \n'
+ ' 486039affc0a Pulling fs layer \n'
+ ' 486039affc0a Downloading [> ] 32.16kB/2.207MB\n'
+ ' 486039affc0a Verifying Checksum \n'
+ ' 486039affc0a Download complete \n'
+ ' 486039affc0a Extracting [> ] 32.77kB/2.207MB\n'
+ ' 486039affc0a Extracting [============================================> ] 1.966MB/2.207MB\n'
+ ' 486039affc0a Extracting [==================================================>] 2.207MB/2.207MB\n'
+ ' 486039affc0a Pull complete \n'
+ ' ansible-docker-test-01234567-cont Pulled \n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Pulling fs layer',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Downloading',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Verifying Checksum',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Download complete',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Extracting',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Extracting',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Extracting',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Pull complete',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2_pull: "Pull with policy=always" on 2024-01-13 in 2.15-centos7
+ (
+ '2.21.0-2.15-centos7-2024-01-13-docker_compose_v2_pull-pull-with-policy=always',
+ '2.21.0',
+ False,
+ ' ansible-docker-test-01234567-cont Pulling \n'
+ ' 486039affc0a Pulling fs layer \n'
+ ' 486039affc0a Downloading [> ] 32.16kB/2.207MB\n'
+ ' 486039affc0a Verifying Checksum \n'
+ ' 486039affc0a Download complete \n'
+ ' 486039affc0a Extracting [> ] 32.77kB/2.207MB\n'
+ ' 486039affc0a Extracting [=======================================> ] 1.737MB/2.207MB\n'
+ ' 486039affc0a Extracting [==================================================>] 2.207MB/2.207MB\n'
+ ' 486039affc0a Pull complete \n'
+ ' ansible-docker-test-01234567-cont Pulled \n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Pulling fs layer',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Downloading',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Verifying Checksum',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Download complete',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Extracting',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Extracting',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Extracting',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Pull complete',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2_pull: "Pull with policy=always" on 2024-01-13 in devel-debian-bullseye
+ (
+ '2.21.0-devel-debian-bullseye-2024-01-13-docker_compose_v2_pull-pull-with-policy=always',
+ '2.21.0',
+ False,
+ ' ansible-docker-test-01234567-cont Pulling \n'
+ ' 486039affc0a Pulling fs layer \n'
+ ' 486039affc0a Downloading [> ] 32.16kB/2.207MB\n'
+ ' 486039affc0a Verifying Checksum \n'
+ ' 486039affc0a Download complete \n'
+ ' 486039affc0a Extracting [> ] 32.77kB/2.207MB\n'
+ ' 486039affc0a Extracting [=====================================> ] 1.638MB/2.207MB\n'
+ ' 486039affc0a Extracting [==================================================>] 2.207MB/2.207MB\n'
+ ' 486039affc0a Pull complete \n'
+ ' ansible-docker-test-01234567-cont Pulled \n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Pulling fs layer',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Downloading',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Verifying Checksum',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Download complete',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Extracting',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Extracting',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Extracting',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Pull complete',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2_pull: "Pull with policy=always (again)" on 2024-01-13 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2_pull: "Pull with policy=always (again)" on 2024-01-13 in 2.15-centos7
+ # Duplicated in: docker_compose_v2_pull: "Pull with policy=always (again)" on 2024-01-13 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2_pull: "Pull with policy=always (again)" on 2024-01-13 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2_pull: "Pull with policy=always (again)" on 2024-01-13 in 2.16-centos7
+ # Duplicated in: docker_compose_v2_pull: "Pull with policy=always (again)" on 2024-01-13 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2_pull: "Pull with policy=always (again)" on 2024-01-13 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2_pull: "Pull with policy=always (again)" on 2024-01-13 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2_pull: "Pull with policy=always (again)" on 2024-01-13 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2_pull: "Pull with policy=always (again)" on 2024-01-13 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2_pull: "Pull with policy=always (again)" on 2024-01-13 in devel-ubuntu2204
+ (
+ '2.21.0-2.14-rhel9.0-2024-01-13-docker_compose_v2_pull-pull-with-policy=always-(again)',
+ '2.21.0',
+ False,
+ ' ansible-docker-test-01234567-cont Pulling \n'
+ ' ansible-docker-test-01234567-cont Pulled \n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2_pull: "Pull with policy=always (again, check)" on 2024-01-13 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2_pull: "Pull with policy=always (again, check)" on 2024-01-13 in 2.15-centos7
+ # Duplicated in: docker_compose_v2_pull: "Pull with policy=always (again, check)" on 2024-01-13 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2_pull: "Pull with policy=always (again, check)" on 2024-01-13 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2_pull: "Pull with policy=always (again, check)" on 2024-01-13 in 2.16-centos7
+ # Duplicated in: docker_compose_v2_pull: "Pull with policy=always (again, check)" on 2024-01-13 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2_pull: "Pull with policy=always (again, check)" on 2024-01-13 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2_pull: "Pull with policy=always (again, check)" on 2024-01-13 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2_pull: "Pull with policy=always (again, check)" on 2024-01-13 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2_pull: "Pull with policy=always (again, check)" on 2024-01-13 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2_pull: "Pull with policy=always (again, check)" on 2024-01-13 in devel-ubuntu2204
+ # Duplicated in: docker_compose_v2_pull: "Pull with policy=always (check)" on 2024-01-13 in 2.14-rhel9.0
+ # Duplicated in: docker_compose_v2_pull: "Pull with policy=always (check)" on 2024-01-13 in 2.15-centos7
+ # Duplicated in: docker_compose_v2_pull: "Pull with policy=always (check)" on 2024-01-13 in 2.15-rhel7.9
+ # Duplicated in: docker_compose_v2_pull: "Pull with policy=always (check)" on 2024-01-13 in 2.15-rhel9.1
+ # Duplicated in: docker_compose_v2_pull: "Pull with policy=always (check)" on 2024-01-13 in 2.16-centos7
+ # Duplicated in: docker_compose_v2_pull: "Pull with policy=always (check)" on 2024-01-13 in 2.16-rhel9.2
+ # Duplicated in: docker_compose_v2_pull: "Pull with policy=always (check)" on 2024-01-13 in devel-debian-bookworm
+ # Duplicated in: docker_compose_v2_pull: "Pull with policy=always (check)" on 2024-01-13 in devel-debian-bullseye
+ # Duplicated in: docker_compose_v2_pull: "Pull with policy=always (check)" on 2024-01-13 in devel-rhel9.3
+ # Duplicated in: docker_compose_v2_pull: "Pull with policy=always (check)" on 2024-01-13 in devel-ubuntu2004
+ # Duplicated in: docker_compose_v2_pull: "Pull with policy=always (check)" on 2024-01-13 in devel-ubuntu2204
+ (
+ '2.21.0-2.14-rhel9.0-2024-01-13-docker_compose_v2_pull-pull-with-policy=always-(again,-check)',
+ '2.21.0',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # #######################################################################################################################
+ # ## Docker Compose 2.23.3 ##############################################################################################
+ # #######################################################################################################################
+ # docker_compose_v2: "Absent" on 2024-01-07 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Absent" on 2024-01-13 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-07 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-13 in devel-archlinux
+ (
+ '2.23.3-devel-archlinux-2024-01-07-docker_compose_v2-absent',
+ '2.23.3',
+ False,
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Stopping\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Stopped\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Removing\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Removed\n'
+ ' Network ansible-docker-test-01234567-start-stop_default Removing\n'
+ ' Network ansible-docker-test-01234567-start-stop_default Removed\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Stopping',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Stopped',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Removing',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Removed',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Removing',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Removed',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Absent (check)" on 2024-01-07 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Absent (check)" on 2024-01-13 in devel-archlinux
+ (
+ '2.23.3-devel-archlinux-2024-01-07-docker_compose_v2-absent-(check)',
+ '2.23.3',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Stopping\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Stopped\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Removing\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Removed\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Removing\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Resource is still in use\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Stopping',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Stopped',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Removing',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Removed',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Removing',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ None,
+ 'Resource is still in use',
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Cleanup" on 2024-01-07 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Cleanup" on 2024-01-13 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Stopping service" on 2024-01-07 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Stopping service" on 2024-01-13 in devel-archlinux
+ (
+ '2.23.3-devel-archlinux-2024-01-07-docker_compose_v2-cleanup',
+ '2.23.3',
+ False,
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Stopping\n'
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Stopped\n'
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Removing\n'
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Removed\n'
+ ' Network ansible-docker-test-01234567-pull_default Removing\n'
+ ' Network ansible-docker-test-01234567-pull_default Removed\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Stopping',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Stopped',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Removing',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Removed',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Removing',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Removed',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present" on 2024-01-07 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Present" on 2024-01-13 in devel-archlinux
+ (
+ '2.23.3-devel-archlinux-2024-01-07-docker_compose_v2-present',
+ '2.23.3',
+ False,
+ ' Network ansible-docker-test-01234567-start-stop_default Creating\n'
+ ' Network ansible-docker-test-01234567-start-stop_default Created\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Creating\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Created\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (changed check)" on 2024-01-07 in devel-archlinux
+ (
+ '2.23.3-devel-archlinux-2024-01-07-docker_compose_v2-present-(changed-check)',
+ '2.23.3',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreated\n'
+ ' DRY-RUN MODE - Container df477f7889c_ansible-docker-test-bc362ba-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container df477f7889c_ansible-docker-test-bc362ba-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ 'df477f7889c_ansible-docker-test-bc362ba-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'df477f7889c_ansible-docker-test-bc362ba-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (changed check)" on 2024-01-13 in devel-archlinux
+ (
+ '2.23.3-devel-archlinux-2024-01-13-docker_compose_v2-present-(changed-check)',
+ '2.23.3',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreated\n'
+ ' DRY-RUN MODE - Container e3161c3ca1e_ansible-docker-test-26fefc5c-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container e3161c3ca1e_ansible-docker-test-26fefc5c-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ 'e3161c3ca1e_ansible-docker-test-26fefc5c-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'e3161c3ca1e_ansible-docker-test-26fefc5c-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (changed)" on 2024-01-07 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Present (changed)" on 2024-01-13 in devel-archlinux
+ (
+ '2.23.3-devel-archlinux-2024-01-07-docker_compose_v2-present-(changed)',
+ '2.23.3',
+ False,
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreate\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Recreated\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (check)" on 2024-01-13 in devel-archlinux
+ (
+ '2.23.3-devel-archlinux-2024-01-13-docker_compose_v2-present-(check)',
+ '2.23.3',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-26fefc5c-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-26fefc5c-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-26fefc5c-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-26fefc5c-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (check)" on 2024-01-07 in devel-archlinux
+ (
+ '2.23.3-devel-archlinux-2024-01-07-docker_compose_v2-present-(check)',
+ '2.23.3',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-bc362ba-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-bc362ba-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-bc362ba-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-bc362ba-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (idempotent check)" on 2024-01-07 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Present (idempotent check)" on 2024-01-13 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Started (idempotent check)" on 2024-01-07 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Started (idempotent check)" on 2024-01-13 in devel-archlinux
+ (
+ '2.23.3-devel-archlinux-2024-01-07-docker_compose_v2-present-(idempotent-check)',
+ '2.23.3',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Running\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Running',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present (idempotent)" on 2024-01-07 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Present (idempotent)" on 2024-01-13 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Started (idempotent)" on 2024-01-07 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Started (idempotent)" on 2024-01-13 in devel-archlinux
+ (
+ '2.23.3-devel-archlinux-2024-01-07-docker_compose_v2-present-(idempotent)',
+ '2.23.3',
+ False,
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Running\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Running',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present stopped" on 2024-01-07 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Present stopped" on 2024-01-13 in devel-archlinux
+ (
+ '2.23.3-devel-archlinux-2024-01-07-docker_compose_v2-present-stopped',
+ '2.23.3',
+ False,
+ ' Network ansible-docker-test-01234567-start-stop_default Creating\n'
+ ' Network ansible-docker-test-01234567-start-stop_default Created\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Creating\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Created\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Created',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present stopped (check)" on 2024-01-07 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Present stopped (check)" on 2024-01-13 in devel-archlinux
+ (
+ '2.23.3-devel-archlinux-2024-01-07-docker_compose_v2-present-stopped-(check)',
+ '2.23.3',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-start-stop_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Created\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-start-stop_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Created',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=always" on 2024-01-07 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Present with pull=always" on 2024-01-13 in devel-archlinux
+ (
+ '2.23.3-devel-archlinux-2024-01-07-docker_compose_v2-present-with-pull=always',
+ '2.23.3',
+ False,
+ ' ansible-docker-test-01234567-cont Pulling \n'
+ ' ansible-docker-test-01234567-cont Pulled \n'
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Running\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Running',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=always (check)" on 2024-01-07 in devel-archlinux
+ (
+ '2.23.3-devel-archlinux-2024-01-07-docker_compose_v2-present-with-pull=always-(check)',
+ '2.23.3',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreated\n'
+ ' DRY-RUN MODE - Container 9f33f2ddb62_ansible-docker-test-bc362ba-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container 9f33f2ddb62_ansible-docker-test-bc362ba-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ '9f33f2ddb62_ansible-docker-test-bc362ba-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ '9f33f2ddb62_ansible-docker-test-bc362ba-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=always (check)" on 2024-01-13 in devel-archlinux
+ (
+ '2.23.3-devel-archlinux-2024-01-13-docker_compose_v2-present-with-pull=always-(check)',
+ '2.23.3',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreate\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Recreated\n'
+ ' DRY-RUN MODE - Container e6dd7e14964_ansible-docker-test-26fefc5c-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container e6dd7e14964_ansible-docker-test-26fefc5c-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreate',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Recreated',
+ None,
+ ),
+ Event(
+ 'container',
+ 'e6dd7e14964_ansible-docker-test-26fefc5c-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'e6dd7e14964_ansible-docker-test-26fefc5c-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=missing" on 2024-01-07 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Present with pull=missing" on 2024-01-13 in devel-archlinux
+ (
+ '2.23.3-devel-archlinux-2024-01-07-docker_compose_v2-present-with-pull=missing',
+ '2.23.3',
+ False,
+ ' ansible-docker-test-01234567-cont Pulling \n'
+ ' ansible-docker-test-01234567-cont Pulled \n'
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=missing (check)" on 2024-01-13 in devel-archlinux
+ (
+ '2.23.3-devel-archlinux-2024-01-13-docker_compose_v2-present-with-pull=missing-(check)',
+ '2.23.3',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-26fefc5c-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-26fefc5c-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-26fefc5c-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-26fefc5c-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=missing (check)" on 2024-01-07 in devel-archlinux
+ (
+ '2.23.3-devel-archlinux-2024-01-07-docker_compose_v2-present-with-pull=missing-(check)',
+ '2.23.3',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-bc362ba-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-bc362ba-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-bc362ba-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-bc362ba-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=missing (idempotent)" on 2024-01-07 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent)" on 2024-01-13 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent)" on 2024-01-07 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent)" on 2024-01-13 in devel-archlinux
+ (
+ '2.23.3-devel-archlinux-2024-01-07-docker_compose_v2-present-with-pull=missing-(idempotent)',
+ '2.23.3',
+ False,
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Running\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Running',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=missing (idempotent, check)" on 2024-01-07 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Present with pull=missing (idempotent, check)" on 2024-01-13 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent, check)" on 2024-01-07 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Present with pull=never (idempotent, check)" on 2024-01-13 in devel-archlinux
+ (
+ '2.23.3-devel-archlinux-2024-01-07-docker_compose_v2-present-with-pull=missing-(idempotent,-check)',
+ '2.23.3',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Running\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Running',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=never" on 2024-01-07 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-13 in devel-archlinux
+ (
+ '2.23.3-devel-archlinux-2024-01-07-docker_compose_v2-present-with-pull=never',
+ '2.23.3',
+ False,
+ ' Network ansible-docker-test-01234567-pull_default Creating\n'
+ ' Network ansible-docker-test-01234567-pull_default Created\n'
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=never" on 2024-01-07 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Present with pull=never" on 2024-01-13 in devel-archlinux
+ (
+ '2.23.3-devel-archlinux-2024-01-07-docker_compose_v2-present-with-pull=never',
+ '2.23.3',
+ False,
+ ' Network ansible-docker-test-01234567-pull_default Creating\n'
+ ' Network ansible-docker-test-01234567-pull_default Created\n'
+ ' Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ 'Error response from daemon: no such image: does-not-exist:latest: No such image: does-not-exist:latest\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'unknown',
+ '',
+ 'Error',
+ 'Error response from daemon: no such image: does-not-exist:latest: No such image: does-not-exist:latest',
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=never (check)" on 2024-01-13 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Present with pull=never (check)" on 2024-01-13 in devel-archlinux
+ (
+ '2.23.3-devel-archlinux-2024-01-13-docker_compose_v2-present-with-pull=never-(check)',
+ '2.23.3',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-26fefc5c-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-26fefc5c-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-26fefc5c-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-26fefc5c-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present with pull=never (check)" on 2024-01-07 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Present with pull=never (check)" on 2024-01-07 in devel-archlinux
+ (
+ '2.23.3-devel-archlinux-2024-01-07-docker_compose_v2-present-with-pull=never-(check)',
+ '2.23.3',
+ True,
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Creating\n'
+ ' DRY-RUN MODE - Network ansible-docker-test-01234567-pull_default Created\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Creating\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1 Created\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-bc362ba-pull-ansible-docker-test-01234567-cont-1 Starting\n'
+ ' DRY-RUN MODE - Container nsible-docker-test-bc362ba-pull-ansible-docker-test-01234567-cont-1 Started\n',
+ [
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'ansible-docker-test-01234567-pull_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-pull-ansible-docker-test-01234567-cont-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-bc362ba-pull-ansible-docker-test-01234567-cont-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'nsible-docker-test-bc362ba-pull-ansible-docker-test-01234567-cont-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present without explicit pull" on 2024-01-07 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Present without explicit pull" on 2024-01-13 in devel-archlinux
+ # Duplicated in: docker_compose_v2_pull: "Pull" on 2024-01-13 in devel-archlinux
+ (
+ '2.23.3-devel-archlinux-2024-01-07-docker_compose_v2-present-without-explicit-pull',
+ '2.23.3',
+ False,
+ ' ansible-docker-test-01234567-cont Pulling \n'
+ ' ansible-docker-test-01234567-cont Error \n'
+ "Error response from daemon: pull access denied for does-not-exist, repository does not exist or may require 'docker login': denied: requested access to the resource is denied\n", # noqa: E501
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'unknown',
+ 'ansible-docker-test-01234567-cont',
+ 'Error',
+ "Error response from daemon: pull access denied for does-not-exist, repository does not exist or may require 'docker login': denied: requested access to the resource is denied", # noqa: E501
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Present without explicit pull (check)" on 2024-01-07 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Present without explicit pull (check)" on 2024-01-13 in devel-archlinux
+ (
+ '2.23.3-devel-archlinux-2024-01-07-docker_compose_v2-present-without-explicit-pull-(check)',
+ '2.23.3',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Error \n'
+ 'pull access denied, repository does not exist or may require authorization: server message: insufficient_scope: authorization failed\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'unknown',
+ 'ansible-docker-test-01234567-cont',
+ 'Error',
+ 'pull access denied, repository does not exist or may require authorization: server message: insufficient_scope: authorization failed',
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Restarted" on 2024-01-07 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-07 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-13 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Restarted" on 2024-01-13 in devel-archlinux
+ (
+ '2.23.3-devel-archlinux-2024-01-07-docker_compose_v2-restarted',
+ '2.23.3',
+ False,
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Restarting\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Restarting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Restarted (check)" on 2024-01-07 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-07 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-13 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Restarted (check)" on 2024-01-13 in devel-archlinux
+ (
+ '2.23.3-devel-archlinux-2024-01-07-docker_compose_v2-restarted-(check)',
+ '2.23.3',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Restarting\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Restarting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Started" on 2024-01-07 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Started" on 2024-01-13 in devel-archlinux
+ (
+ '2.23.3-devel-archlinux-2024-01-07-docker_compose_v2-started',
+ '2.23.3',
+ False,
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Started (check)" on 2024-01-07 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Started (check)" on 2024-01-13 in devel-archlinux
+ (
+ '2.23.3-devel-archlinux-2024-01-07-docker_compose_v2-started-(check)',
+ '2.23.3',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Starting\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Started\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Stopped" on 2024-01-07 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Stopped" on 2024-01-13 in devel-archlinux
+ (
+ '2.23.3-devel-archlinux-2024-01-07-docker_compose_v2-stopped',
+ '2.23.3',
+ False,
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Running\n'
+ '\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Stopping\n'
+ ' Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Stopped\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Running',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Stopping',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Stopped',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2: "Stopped (check)" on 2024-01-07 in devel-archlinux
+ # Duplicated in: docker_compose_v2: "Stopped (check)" on 2024-01-13 in devel-archlinux
+ (
+ '2.23.3-devel-archlinux-2024-01-07-docker_compose_v2-stopped-(check)',
+ '2.23.3',
+ True,
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Running\n'
+ '\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Stopping\n'
+ ' DRY-RUN MODE - Container ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1 Stopped\n',
+ [
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Running',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Stopping',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ansible-docker-test-01234567-start-stop-ansible-docker-test-01234567-container-1',
+ 'Stopped',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2_pull: "Pull (check)" on 2024-01-13 in devel-archlinux
+ (
+ '2.23.3-devel-archlinux-2024-01-13-docker_compose_v2_pull-pull-(check)',
+ '2.23.3',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Error \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont - Pull error for image: does-not-exist:latest \n'
+ 'pull access denied, repository does not exist or may require authorization: server message: insufficient_scope: authorization failed\n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'unknown',
+ 'ansible-docker-test-01234567-cont',
+ 'Error',
+ 'pull access denied, repository does not exist or may require authorization: server message: insufficient_scope: authorization failed',
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2_pull: "Pull with policy=always" on 2024-01-13 in devel-archlinux
+ (
+ '2.23.3-devel-archlinux-2024-01-13-docker_compose_v2_pull-pull-with-policy=always',
+ '2.23.3',
+ False,
+ ' ansible-docker-test-01234567-cont Pulling \n'
+ ' ansible-docker-test-01234567-cont Pulled \n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2_pull: "Pull with policy=always (check)" on 2024-01-13 in devel-archlinux
+ # Duplicated in: docker_compose_v2_pull: "Pull with policy=missing (check)" on 2024-01-13 in devel-archlinux
+ (
+ '2.23.3-devel-archlinux-2024-01-13-docker_compose_v2_pull-pull-with-policy=always-(check)',
+ '2.23.3',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulling \n'
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Pulled \n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2_pull: "Pull with policy=missing" on 2024-01-13 in devel-archlinux
+ (
+ '2.23.3-devel-archlinux-2024-01-13-docker_compose_v2_pull-pull-with-policy=missing',
+ '2.23.3',
+ False,
+ ' ansible-docker-test-01234567-cont Pulling \n'
+ ' 486039affc0a Pulling fs layer \n'
+ ' 486039affc0a Downloading [> ] 32.16kB/2.207MB\n'
+ ' 486039affc0a Verifying Checksum \n'
+ ' 486039affc0a Download complete \n'
+ ' 486039affc0a Extracting [> ] 32.77kB/2.207MB\n'
+ ' 486039affc0a Extracting [==========================================> ] 1.868MB/2.207MB\n'
+ ' 486039affc0a Extracting [==================================================>] 2.207MB/2.207MB\n'
+ ' 486039affc0a Pull complete \n'
+ ' ansible-docker-test-01234567-cont Pulled \n',
+ [
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulling',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Pulling fs layer',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Downloading',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Verifying Checksum',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Download complete',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Extracting',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Extracting',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Extracting',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '486039affc0a',
+ 'Pull complete',
+ None,
+ ),
+ Event(
+ 'service',
+ 'ansible-docker-test-01234567-cont',
+ 'Pulled',
+ None,
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2_pull: "Pull with policy=missing (idempotent)" on 2024-01-13 in devel-archlinux
+ (
+ '2.23.3-devel-archlinux-2024-01-13-docker_compose_v2_pull-pull-with-policy=missing-(idempotent)',
+ '2.23.3',
+ False,
+ ' ansible-docker-test-01234567-cont Skipped - Image is already present locally \n',
+ [
+ Event(
+ 'unknown',
+ 'ansible-docker-test-01234567-cont',
+ 'Skipped',
+ 'Image is already present locally',
+ ),
+ ],
+ [],
+ ),
+ # docker_compose_v2_pull: "Pull with policy=missing (idempotent, check)" on 2024-01-13 in devel-archlinux
+ (
+ '2.23.3-devel-archlinux-2024-01-13-docker_compose_v2_pull-pull-with-policy=missing-(idempotent,-check)',
+ '2.23.3',
+ True,
+ ' DRY-RUN MODE - ansible-docker-test-01234567-cont Skipped - Image is already present locally \n',
+ [
+ Event(
+ 'unknown',
+ 'ansible-docker-test-01234567-cont',
+ 'Skipped',
+ 'Image is already present locally',
+ ),
+ ],
+ [],
+ ),
+]
diff --git a/ansible_collections/community/docker/tests/unit/plugins/module_utils/test__logfmt.py b/ansible_collections/community/docker/tests/unit/plugins/module_utils/test__logfmt.py
new file mode 100644
index 000000000..efcc15ff6
--- /dev/null
+++ b/ansible_collections/community/docker/tests/unit/plugins/module_utils/test__logfmt.py
@@ -0,0 +1,100 @@
+# Copyright (c) 2024, Felix Fontein <felix@fontein.de>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import pytest
+
+from ansible_collections.community.docker.plugins.module_utils._logfmt import (
+ InvalidLogFmt,
+ parse_line,
+)
+
+
+SUCCESS_TEST_CASES = [
+ (
+ 'time="2024-02-02T08:14:10+01:00" level=warning msg="a network with name influxNetwork exists but was not'
+ ' created for project \\"influxdb\\".\\nSet `external: true` to use an existing network"',
+ {},
+ {
+ 'time': '2024-02-02T08:14:10+01:00',
+ 'level': 'warning',
+ 'msg': 'a network with name influxNetwork exists but was not created for project "influxdb".\nSet `external: true` to use an existing network',
+ },
+ ),
+ (
+ 'time="2024-02-02T08:14:10+01:00" level=warning msg="a network with name influxNetwork exists but was not'
+ ' created for project \\"influxdb\\".\\nSet `external: true` to use an existing network"',
+ {'logrus_mode': True},
+ {
+ 'time': '2024-02-02T08:14:10+01:00',
+ 'level': 'warning',
+ 'msg': 'a network with name influxNetwork exists but was not created for project "influxdb".\nSet `external: true` to use an existing network',
+ },
+ ),
+ (
+ 'foo=bar a=14 baz="hello kitty" cool%story=bro f %^asdf',
+ {},
+ {
+ 'foo': 'bar',
+ 'a': '14',
+ 'baz': 'hello kitty',
+ 'cool%story': 'bro',
+ 'f': None,
+ '%^asdf': None,
+ },
+ ),
+ (
+ '{"foo":"bar"}',
+ {},
+ {
+ '{': None,
+ 'foo': None,
+ ':': None,
+ 'bar': None,
+ '}': None,
+ },
+ ),
+]
+
+
+FAILURE_TEST_CASES = [
+ (
+ 'foo=bar a=14 baz="hello kitty" cool%story=bro f %^asdf',
+ {'logrus_mode': True},
+ 'Key must always be followed by "=" in logrus mode',
+ ),
+ (
+ '{}',
+ {'logrus_mode': True},
+ 'Key must always be followed by "=" in logrus mode',
+ ),
+ (
+ '[]',
+ {'logrus_mode': True},
+ 'Key must always be followed by "=" in logrus mode',
+ ),
+ (
+ '{"foo=bar": "baz=bam"}',
+ {'logrus_mode': True},
+ 'Key must always be followed by "=" in logrus mode',
+ ),
+]
+
+
+@pytest.mark.parametrize('line, kwargs, result', SUCCESS_TEST_CASES)
+def test_parse_line_success(line, kwargs, result):
+ res = parse_line(line, **kwargs)
+ print(repr(res))
+ assert res == result
+
+
+@pytest.mark.parametrize('line, kwargs, message', FAILURE_TEST_CASES)
+def test_parse_line_success(line, kwargs, message):
+ with pytest.raises(InvalidLogFmt) as exc:
+ parse_line(line, **kwargs)
+
+ print(repr(exc.value.args[0]))
+ assert exc.value.args[0] == message
diff --git a/ansible_collections/community/docker/tests/unit/plugins/module_utils/test_compose_v2.py b/ansible_collections/community/docker/tests/unit/plugins/module_utils/test_compose_v2.py
new file mode 100644
index 000000000..7292af2a7
--- /dev/null
+++ b/ansible_collections/community/docker/tests/unit/plugins/module_utils/test_compose_v2.py
@@ -0,0 +1,242 @@
+# Copyright 2022 Red Hat | Ansible
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import pytest
+
+from ansible_collections.community.docker.plugins.module_utils.compose_v2 import (
+ Event,
+ parse_events,
+)
+
+from .compose_v2_test_cases import EVENT_TEST_CASES
+
+
+EXTRA_TEST_CASES = [
+ (
+ '2.24.2-manual-build-dry-run',
+ '2.24.2',
+ True,
+ ' DRY-RUN MODE - build service foobar \n'
+ ' DRY-RUN MODE - ==> ==> writing image dryRun-8843d7f92416211de9ebb963ff4ce28125932878 \n'
+ ' DRY-RUN MODE - ==> ==> naming to my-python \n'
+ ' DRY-RUN MODE - Network compose_default Creating\n'
+ ' DRY-RUN MODE - Network compose_default Created\n'
+ ' DRY-RUN MODE - Container compose-foobar-1 Creating\n'
+ ' DRY-RUN MODE - Container compose-foobar-1 Created\n'
+ ' DRY-RUN MODE - Container ompose-foobar-1 Starting\n'
+ ' DRY-RUN MODE - Container ompose-foobar-1 Started\n',
+ [
+ Event(
+ 'service',
+ 'foobar',
+ 'Building',
+ None,
+ ),
+ Event(
+ 'network',
+ 'compose_default',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'network',
+ 'compose_default',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'compose-foobar-1',
+ 'Creating',
+ None,
+ ),
+ Event(
+ 'container',
+ 'compose-foobar-1',
+ 'Created',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ompose-foobar-1',
+ 'Starting',
+ None,
+ ),
+ Event(
+ 'container',
+ 'ompose-foobar-1',
+ 'Started',
+ None,
+ ),
+ ],
+ [],
+ ),
+ (
+ # https://github.com/ansible-collections/community.docker/issues/785
+ '2.20.0-manual-pull',
+ '2.20.0',
+ False,
+ '4f4fb700ef54 Waiting\n'
+ '238022553356 Downloading 541B/541B\n'
+ '972e292d3a60 Downloading 106kB/10.43MB\n'
+ 'f2543dc9f0a9 Downloading 25.36kB/2.425MB\n'
+ '972e292d3a60 Downloading 5.925MB/10.43MB\n'
+ 'f2543dc9f0a9 Downloading 2.219MB/2.425MB\n'
+ 'f2543dc9f0a9 Extracting 32.77kB/2.425MB\n'
+ '4f4fb700ef54 Downloading 32B/32B\n'
+ 'f2543dc9f0a9 Extracting 2.425MB/2.425MB\n'
+ '972e292d3a60 Extracting 131.1kB/10.43MB\n'
+ '972e292d3a60 Extracting 10.43MB/10.43MB\n'
+ '238022553356 Extracting 541B/541B\n'
+ '4f4fb700ef54 Extracting 32B/32B\n',
+ [
+ Event(
+ 'image-layer',
+ '4f4fb700ef54',
+ 'Waiting',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '238022553356',
+ 'Downloading',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '972e292d3a60',
+ 'Downloading',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ 'f2543dc9f0a9',
+ 'Downloading',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '972e292d3a60',
+ 'Downloading',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ 'f2543dc9f0a9',
+ 'Downloading',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ 'f2543dc9f0a9',
+ 'Extracting',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '4f4fb700ef54',
+ 'Downloading',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ 'f2543dc9f0a9',
+ 'Extracting',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '972e292d3a60',
+ 'Extracting',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '972e292d3a60',
+ 'Extracting',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '238022553356',
+ 'Extracting',
+ None,
+ ),
+ Event(
+ 'image-layer',
+ '4f4fb700ef54',
+ 'Extracting',
+ None,
+ ),
+ ],
+ [],
+ ),
+ (
+ # https://github.com/ansible-collections/community.docker/issues/787
+ '2.20.3-logrus-warn',
+ '2.20.3',
+ False,
+ 'time="2024-02-02T08:14:10+01:00" level=warning msg="a network with name influxNetwork exists but was not'
+ ' created for project \\"influxdb\\".\\nSet `external: true` to use an existing network"\n',
+ [],
+ [
+ 'a network with name influxNetwork exists but was not created for project "influxdb".\nSet `external: true` to use an existing network',
+ ],
+ ),
+ (
+ # https://github.com/ansible-collections/community.docker/issues/807
+ '2.20.3-image-warning-error',
+ '2.20.3',
+ False,
+ " dummy3 Warning \n"
+ " dummy2 Warning \n"
+ " dummy Error \n"
+ " dummy4 Warning Foo bar \n"
+ " dummy5 Error Bar baz bam \n",
+ [
+ Event(
+ 'unknown',
+ 'dummy',
+ 'Error',
+ None,
+ ),
+ Event(
+ 'unknown',
+ 'dummy5',
+ 'Error',
+ 'Bar baz bam',
+ ),
+ ],
+ [
+ 'Unspecified warning for dummy3',
+ 'Unspecified warning for dummy2',
+ 'dummy4: Foo bar',
+ ],
+ ),
+]
+
+_ALL_TEST_CASES = EVENT_TEST_CASES + EXTRA_TEST_CASES
+
+
+@pytest.mark.parametrize(
+ 'test_id, compose_version, dry_run, stderr, events, warnings',
+ _ALL_TEST_CASES,
+ ids=[tc[0] for tc in _ALL_TEST_CASES],
+)
+def test_parse_events(test_id, compose_version, dry_run, stderr, events, warnings):
+ collected_warnings = []
+
+ def collect_warning(msg):
+ collected_warnings.append(msg)
+
+ collected_events = parse_events(stderr, dry_run=dry_run, warn_function=collect_warning)
+
+ print(collected_events)
+ print(collected_warnings)
+
+ assert collected_events == events
+ assert collected_warnings == warnings
diff --git a/ansible_collections/community/docker/tests/unit/requirements.yml b/ansible_collections/community/docker/tests/unit/requirements.yml
index 586a6a1b3..e91ea4745 100644
--- a/ansible_collections/community/docker/tests/unit/requirements.yml
+++ b/ansible_collections/community/docker/tests/unit/requirements.yml
@@ -5,3 +5,4 @@
collections:
- community.internal_test_tools
+- community.library_inventory_filtering_v1
diff --git a/ansible_collections/community/docker/tests/utils/shippable/shippable.sh b/ansible_collections/community/docker/tests/utils/shippable/shippable.sh
index 2ca96b888..c824e2abf 100755
--- a/ansible_collections/community/docker/tests/utils/shippable/shippable.sh
+++ b/ansible_collections/community/docker/tests/utils/shippable/shippable.sh
@@ -65,22 +65,18 @@ else
retry pip install "https://github.com/ansible/ansible/archive/stable-${ansible_version}.tar.gz" --disable-pip-version-check
fi
-if [ "${SHIPPABLE_BUILD_ID:-}" ]; then
- export ANSIBLE_COLLECTIONS_PATHS="${HOME}/.ansible"
- SHIPPABLE_RESULT_DIR="$(pwd)/shippable"
- TEST_DIR="${ANSIBLE_COLLECTIONS_PATHS}/ansible_collections/community/docker"
- mkdir -p "${TEST_DIR}"
- cp -aT "${SHIPPABLE_BUILD_DIR}" "${TEST_DIR}"
- cd "${TEST_DIR}"
-else
- export ANSIBLE_COLLECTIONS_PATHS="${PWD}/../../../"
-fi
+export ANSIBLE_COLLECTIONS_PATHS="${PWD}/../../../"
if [ "${test}" == "sanity/extra" ]; then
retry pip install junit-xml --disable-pip-version-check
fi
# START: HACK
+
+retry git clone --depth=1 --single-branch --branch stable-1 https://github.com/ansible-collections/community.library_inventory_filtering.git "${ANSIBLE_COLLECTIONS_PATHS}/ansible_collections/community/library_inventory_filtering_v1"
+# NOTE: we're installing with git to work around Galaxy being a huge PITA (https://github.com/ansible/galaxy/issues/2429)
+# retry ansible-galaxy -vvv collection install community.library_inventory_filtering_v1
+
if [ "${test}" == "sanity/extra" ]; then
# Nothing further should be added to this list.
# This is to prevent modules or plugins in this collection having a runtime dependency on other collections.
diff --git a/ansible_collections/community/fortios/.github/workflows/ansible-test.yml b/ansible_collections/community/fortios/.github/workflows/ansible-test.yml
deleted file mode 100644
index 84667383f..000000000
--- a/ansible_collections/community/fortios/.github/workflows/ansible-test.yml
+++ /dev/null
@@ -1,117 +0,0 @@
-# README FIRST
-# 1. If you don't have unit tests remove that section
-# 2. If your collection depends on other collections ensure they are installed, see "Install collection dependencies"
-# If you need help please ask in #ansible-devel on Freenode IRC
-
-name: CI
-on:
- # Run CI against all pushes (direct commits, also merged PRs), Pull Requests
- push:
- pull_request:
- schedule:
- - cron: '0 6 * * *'
-env:
- NAMESPACE: community
- COLLECTION_NAME: fortios
-
-jobs:
-
-###
-# Sanity tests (REQUIRED)
-#
-# https://docs.ansible.com/ansible/latest/dev_guide/testing_sanity.html
-
- sanity:
- name: Sanity (Ⓐ${{ matrix.ansible }})
- strategy:
- matrix:
- ansible:
- # It's important that Sanity is tested against all stable-X.Y branches
- # Testing against `devel` may fail as new tests are added.
- - stable-2.9
- - stable-2.10
- - devel
- runs-on: ubuntu-latest
- steps:
-
- # ansible-test requires the collection to be in a directory in the form
- # .../ansible_collections/${{env.NAMESPACE}}/${{env.COLLECTION_NAME}}/
-
- - name: Check out code
- uses: actions/checkout@v2
- with:
- path: ansible_collections/${{env.NAMESPACE}}/${{env.COLLECTION_NAME}}
-
- - name: Set up Python
- uses: actions/setup-python@v2
- with:
- # it is just required to run that once as "ansible-test sanity" in the docker image
- # will run on all python versions it supports.
- python-version: 3.8
-
- # Install the head of the given branch (devel, stable-2.10)
- - name: Install ansible-base (${{ matrix.ansible }})
- run: pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz --disable-pip-version-check
-
- - name: Install collection dependencies
- run: ansible-galaxy collection install fortinet.fortios -p .
-
- # run ansible-test sanity inside of Docker.
- # The docker container has all the pinned dependencies that are required
- # and all python versions ansible supports.
- - name: Run sanity tests
- run: ansible-test sanity --docker -v --color
- working-directory: ./ansible_collections/${{env.NAMESPACE}}/${{env.COLLECTION_NAME}}
-
-###
-# Unit tests (OPTIONAL)
-#
-# https://docs.ansible.com/ansible/latest/dev_guide/testing_units.html
-
- units:
- runs-on: ubuntu-latest
- name: Units (Ⓐ${{ matrix.ansible }})
- strategy:
- # As soon as the first unit test fails, cancel the others to free up the CI queue
- fail-fast: true
- matrix:
- ansible:
- - stable-2.9
- - stable-2.10
- - devel
-
- steps:
- - name: Check out code
- uses: actions/checkout@v2
- with:
- path: ansible_collections/${{env.NAMESPACE}}/${{env.COLLECTION_NAME}}
-
- - name: Set up Python
- uses: actions/setup-python@v2
- with:
- # it is just required to run that once as "ansible-test units" in the docker image
- # will run on all python versions it supports.
- python-version: 3.8
-
- - name: Install ansible-base (${{ matrix.ansible }})
- run: pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz --disable-pip-version-check
-
- # OPTIONAL If your unit test requires Python libraries from other collections
- # Install them like this
- - name: Install collection dependencies
- run: ansible-galaxy collection install fortinet.fortios -p .
-
- # Run the unit tests
- - name: Run unit test
- run: ansible-test units -v --color --docker --coverage
- working-directory: ./ansible_collections/${{env.NAMESPACE}}/${{env.COLLECTION_NAME}}
-
- # ansible-test support producing code coverage date
- - name: Generate coverage report
- run: ansible-test coverage xml -v --requirements --group-by command --group-by version
- working-directory: ./ansible_collections/${{env.NAMESPACE}}/${{env.COLLECTION_NAME}}
-
- # See the reports at https://codecov.io/gh/GITHUBORG/REPONAME
- - uses: codecov/codecov-action@v1
- with:
- fail_ci_if_error: false
diff --git a/ansible_collections/community/fortios/CHANGELOG.rst b/ansible_collections/community/fortios/CHANGELOG.rst
deleted file mode 100644
index 315ee7cff..000000000
--- a/ansible_collections/community/fortios/CHANGELOG.rst
+++ /dev/null
@@ -1,23 +0,0 @@
-===============================
-community.fortios Release Notes
-===============================
-
-.. contents:: Topics
-
-
-v1.0.0
-======
-
-Release Summary
----------------
-
-This is the first stable release version of ``community.fortios`` after migrating from ``community.network``.
-
-v0.1.0
-======
-
-Release Summary
----------------
-
-This is the first pre-release version of ``community.fortios`` after migrating from ``community.network``.
-
diff --git a/ansible_collections/community/fortios/FILES.json b/ansible_collections/community/fortios/FILES.json
deleted file mode 100644
index ff661f230..000000000
--- a/ansible_collections/community/fortios/FILES.json
+++ /dev/null
@@ -1,705 +0,0 @@
-{
- "files": [
- {
- "name": ".",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "CHANGELOG.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "f68abff78f63afb5352c766e4db7ad5d175c7f694457f2366d9a7298add2fecd",
- "format": 1
- },
- {
- "name": ".github",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": ".github/workflows",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": ".github/workflows/ansible-test.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "19a6b3f421c758dcb1cff0df8b7b88d1c65102f67c681ff73df7a6ccbb568b7e",
- "format": 1
- },
- {
- "name": "meta",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "meta/runtime.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "df18179bb2f5447a56ac92261a911649b96821c0b2c08eea62d5cc6b0195203f",
- "format": 1
- },
- {
- "name": "LICENSE",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "3972dc9744f6499f0f9b2dbf76696f2ae7ad8af9b23dde66d6af86c9dfb36986",
- "format": 1
- },
- {
- "name": "plugins",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "plugins/httpapi",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "plugins/httpapi/fortianalyzer.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "648481e036a0932efec67ba2e420184c301e686ac033c6f0b0264db2355bcd3c",
- "format": 1
- },
- {
- "name": "plugins/httpapi/fortimanager.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "6ed4256edb77f5d249af3c5cd4712895e5983d30769e39cc55bb1b9d03ab4052",
- "format": 1
- },
- {
- "name": "plugins/module_utils",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "plugins/module_utils/fortianalyzer",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "plugins/module_utils/fortianalyzer/fortianalyzer.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "b0ff3d65975da31f0c7cb047020d4c6d46f3c89a79540d0b1247b2915ea0c4c6",
- "format": 1
- },
- {
- "name": "plugins/module_utils/fortianalyzer/common.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "6360ba52a6cfece6d1019a007a2e6eacfa27e4f336dad9ded728e2503a29b5e8",
- "format": 1
- },
- {
- "name": "plugins/modules",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "plugins/modules/fmgr_ha.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "464c7846058120a915d8f3cf01a0f6d9837a27fa9a2891387542621034dcc83b",
- "format": 1
- },
- {
- "name": "plugins/modules/fmgr_fwobj_ippool6.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "26f13eec55001dd57ef6d95776d5837b9d46a471093bd1935e24c3a58cfbaf62",
- "format": 1
- },
- {
- "name": "plugins/modules/faz_device.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "c8839a63bee525f35cffe283a77db7f3652d28821fa264616df887b19b9b54b7",
- "format": 1
- },
- {
- "name": "plugins/modules/fmgr_fwobj_service.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "47e80e81bc707b110b8e4ffc3eac0015452c776a0883f1803500f9a5c9023914",
- "format": 1
- },
- {
- "name": "plugins/modules/fmgr_secprof_wanopt.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "bf283ffb49c0eab3f2a9a38217f2808106318cff95065e6a978fb0c034a43e4f",
- "format": 1
- },
- {
- "name": "plugins/modules/fmgr_script.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "8ce447194af97e4edc1043b8016aef69ed69490f03a0d4c41d16db290a114792",
- "format": 1
- },
- {
- "name": "plugins/modules/fmgr_secprof_profile_group.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "2e9fe286983a0e0173ab745643105a859fa1ee3f1a00609c2ebd7bb5a58e7213",
- "format": 1
- },
- {
- "name": "plugins/modules/fmgr_fwpol_package.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "bc6a6339e096178f17cd1d65c0473f755355ce7ec0dfaa37d3091fedb3a4ff56",
- "format": 1
- },
- {
- "name": "plugins/modules/fmgr_fwpol_ipv4.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "ac7471486a82d16b5270dbc46dbb252d6936a44bd990d8160eaacde7f3ba07d5",
- "format": 1
- },
- {
- "name": "plugins/modules/fmgr_secprof_ssl_ssh.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "f9cc56f146984b5a3b8aa1ad2979f2cca998f66a11dab249fae1b23ea1c219d0",
- "format": 1
- },
- {
- "name": "plugins/modules/fmgr_secprof_av.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "ef51293e7d255b88fea7362657b24c84b24d5ba2233a287472ba761f6037566e",
- "format": 1
- },
- {
- "name": "plugins/modules/fmgr_device_provision_template.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "77b7ece676c515c4f119bd23c22a9d36c3a790a7af102dd4ff7d66ad2b2fe46c",
- "format": 1
- },
- {
- "name": "plugins/modules/fmgr_secprof_waf.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "cd2150060ab3e48aeeb26da90920cf8d2546391113031138a3da9ebe50fd7cc0",
- "format": 1
- },
- {
- "name": "plugins/modules/fmgr_device.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "bb4095f2afb5ecfa8b1e329510b5e73d88a1c8a154258b5211f677c0048ee172",
- "format": 1
- },
- {
- "name": "plugins/modules/fmgr_device_group.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "4d4d288abdb2c8c7cfa6a05782e780e00952b671661422a3a42784aeb00109f5",
- "format": 1
- },
- {
- "name": "plugins/modules/fmgr_secprof_voip.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "32416e5d4d45cbf3914f95928ea1927aa674bee30fad18b100952b031bd0d32d",
- "format": 1
- },
- {
- "name": "plugins/modules/fmgr_fwobj_vip.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "f2bebf470e60ac32e1a67036775096788b133f5d6875c04889ba27cd25ddab0d",
- "format": 1
- },
- {
- "name": "plugins/modules/fmgr_fwobj_ippool.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "a3f00e23fbd59441239df895739833423b076a450bd408973ab95acf3d3eadb8",
- "format": 1
- },
- {
- "name": "plugins/modules/fmgr_secprof_spam.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "e10c57eb626ea19a2eae26aadf66855240ad89d5b0a6413b377f4634296a8ed6",
- "format": 1
- },
- {
- "name": "plugins/modules/fmgr_fwobj_address.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "b61853c936ca55809f64d50eccfe5785273761499ecfd5e09990d6d392f082b2",
- "format": 1
- },
- {
- "name": "plugins/modules/fmgr_secprof_appctrl.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "baf802fe6fb4a51abd42b71918111b7f2a729e94d7e44badb379c2725784d0c4",
- "format": 1
- },
- {
- "name": "plugins/modules/fmgr_secprof_proxy.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "4afb0d6aa33741f82ace5765afadfb148a5554b79e71b289af4fc5618171995c",
- "format": 1
- },
- {
- "name": "plugins/modules/fmgr_query.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "b2cf28b5ba7f3fe79b46fa00b300a98fcfd5053970f700b0a716d39fd0022a74",
- "format": 1
- },
- {
- "name": "plugins/modules/fmgr_provisioning.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "320d318aa0597fd33e7af67a0ea73f4eef6ebe654b1b615b7376c7ab9dd52aa1",
- "format": 1
- },
- {
- "name": "plugins/modules/fmgr_secprof_web.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "1bc99ba796b46e37c01f1d56b0b03c56b6e1b51185d90707c14143dc4946d128",
- "format": 1
- },
- {
- "name": "plugins/modules/fmgr_secprof_dns.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "be27960fb24a6cf7a0b28c22a162c6d11e597f2a7b5dc5cd472e7bd35c2aeb62",
- "format": 1
- },
- {
- "name": "plugins/modules/fmgr_secprof_ips.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "b1e5ed9b5a781e70de17d09d44aa9969c11d9d87b11c3516a0eff9b551d9ce37",
- "format": 1
- },
- {
- "name": "plugins/modules/fmgr_device_config.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "e56d4cb2afe812e977686ce3e8e612a1547f9d08b3e0b8027e9a79ec4a0da8a2",
- "format": 1
- },
- {
- "name": "tests",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/sanity",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/sanity/ignore-2.10.txt",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "976f414f52ce7b547a43998ea1762723c53d4de828dc166f602be16f2651217c",
- "format": 1
- },
- {
- "name": "tests/sanity/ignore-2.9.txt",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "e6f4fcc6ef6baadfa69a5b0f3e68370e28f37476eccf83f1d0c1aef93544c65e",
- "format": 1
- },
- {
- "name": "tests/sanity/ignore-2.11.txt",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "976f414f52ce7b547a43998ea1762723c53d4de828dc166f602be16f2651217c",
- "format": 1
- },
- {
- "name": "tests/requirements.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "ba070b64632b89e1bef218788ded4fc3bf17ccb402ca9e35d40a3a1653ab94d5",
- "format": 1
- },
- {
- "name": "tests/unit",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/unit/compat",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/unit/compat/mock.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "0af958450cf6de3fbafe94b1111eae8ba5a8dbe1d785ffbb9df81f26e4946d99",
- "format": 1
- },
- {
- "name": "tests/unit/compat/unittest.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "5401a046e5ce71fa19b6d905abd0f9bdf816c0c635f7bdda6730b3ef06e67096",
- "format": 1
- },
- {
- "name": "tests/unit/compat/__init__.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
- "format": 1
- },
- {
- "name": "tests/unit/plugins",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/unit/plugins/modules",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/unit/plugins/modules/fixtures",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/unit/plugins/modules/fixtures/test_fmgr_secprof_spam.json",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "0a575e95971ecd816770d0042b105ebdbfa55a933132c07348cffd57e6140d0d",
- "format": 1
- },
- {
- "name": "tests/unit/plugins/modules/fixtures/test_fmgr_device.json",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "512852b623272348359d5c22b4d656eaf32614d592da774771dad99407acb24b",
- "format": 1
- },
- {
- "name": "tests/unit/plugins/modules/fixtures/test_fmgr_device_provision_template.json",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "7115c96deb7d4167ddbd5ae70d4fbc7e0054868e4a495d21e1a2c1e94914c269",
- "format": 1
- },
- {
- "name": "tests/unit/plugins/modules/fixtures/test_fmgr_secprof_ssl_ssh.json",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "7cd5c8a06c531dacd219e2d028ebe9d68d854b9220aaec0e4931c44799077b88",
- "format": 1
- },
- {
- "name": "tests/unit/plugins/modules/fixtures/test_fmgr_ha.json",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "1a8248aea277e191f77dbe58514c4af20625bd4fa7408496dac0a962b571b8dd",
- "format": 1
- },
- {
- "name": "tests/unit/plugins/modules/test_fmgr_fwpol_package.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "602ee00b0c287dd299d1d9597e7f68e85fd5d054210c840bcec4a25dd924455e",
- "format": 1
- },
- {
- "name": "tests/unit/plugins/modules/test_fmgr_fwobj_service.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "bcdfa628009e77f693216bb434077e79fa3810d0e49f75361600122a56836d6e",
- "format": 1
- },
- {
- "name": "tests/unit/plugins/modules/test_fmgr_secprof_profile_group.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "7d9177b4957df48428a7e2b3c36548844d48a5d487980edc076df69b55f41c2e",
- "format": 1
- },
- {
- "name": "tests/unit/plugins/modules/test_fmgr_fwobj_address.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "a9c11ea2ed943e513d7a2806008f1684badb007831bc0b91a34b51edeb46ae8c",
- "format": 1
- },
- {
- "name": "tests/unit/plugins/modules/test_fmgr_script.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "9a9a91a01073dd4285e9ba8dae75d5dbe76d75eb1c3e0d11fc6a9fa8ee3f899a",
- "format": 1
- },
- {
- "name": "tests/unit/plugins/modules/fortimanager_module.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "0f68461fc5f2da4e97dfcf93c6e9d9921f96b00b1bd7c30357953500adccfbcf",
- "format": 1
- },
- {
- "name": "tests/unit/plugins/modules/test_fmgr_secprof_voip.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "caf96e930ad2240f4a32284c2bf5d2991fd39fda7a384fc54412d106cef8104b",
- "format": 1
- },
- {
- "name": "tests/unit/plugins/modules/test_fmgr_device_provision_template.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "f5b87afcc6b8d888c343ee7508b6fb553cc2afaa0c5320a2b677c943547d61cd",
- "format": 1
- },
- {
- "name": "tests/unit/plugins/modules/test_fmgr_secprof_web.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "fd159e7e3dad055fa172f13ab0357cccbe65d623f433efdf746eaf098ad0d2a6",
- "format": 1
- },
- {
- "name": "tests/unit/plugins/modules/test_fmgr_device.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "912c1b107ace5ea1ed73b6f9def4a2d12a2d1bf39e8758ac1f79724418e18f6f",
- "format": 1
- },
- {
- "name": "tests/unit/plugins/modules/test_fmgr_provisioning.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "5727db87650d9eeaeacb052f453a6a5f10d01ed5aee6e4bd3e1347cd943bb98a",
- "format": 1
- },
- {
- "name": "tests/unit/plugins/modules/test_fmgr_query.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "8cc43dbeb28f2bff9b787804cfacd1414ae0ff720e67a8cb97bdc58d93f41b9d",
- "format": 1
- },
- {
- "name": "tests/unit/plugins/modules/test_fmgr_fwpol_ipv4.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "14a0e799bb15516eb787fd04a341388fe6c70ac4f27a6dc1cba70586299a90f6",
- "format": 1
- },
- {
- "name": "tests/unit/plugins/modules/utils.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "14ef338777c48584d98782de3939389d48469b8293f31e288570764d76dfed77",
- "format": 1
- },
- {
- "name": "tests/unit/plugins/modules/test_fmgr_secprof_appctrl.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "e3f5dcaafa90af79c97d8e09945cf88d9c28b04957b9e247f503ce66d2241b75",
- "format": 1
- },
- {
- "name": "tests/unit/plugins/modules/test_fmgr_secprof_waf.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "b91c96acdf10048def0c296dec10e535ea1c38c68433352172f09612295d0a4d",
- "format": 1
- },
- {
- "name": "tests/unit/plugins/modules/test_fmgr_secprof_av.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "77940e90f6496a6e010de0875ea42a06f72e4622e503c69e388060860da47074",
- "format": 1
- },
- {
- "name": "tests/unit/plugins/modules/test_fmgr_secprof_proxy.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "786e86942d08f2181665d19f215ca9a2008753b643cfbd4e16d01f554e16826d",
- "format": 1
- },
- {
- "name": "tests/unit/plugins/modules/test_fmgr_secprof_spam.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "b8f20bcd65f4c73ace45ef9728be4c1d82468aa610068836a1fa9b7c1c58bbe0",
- "format": 1
- },
- {
- "name": "tests/unit/plugins/modules/test_fmgr_fwobj_vip.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "97f9738e78513c52c9c64e6a144c6f2b63642d35b0e33c778ea02d06f7c91de9",
- "format": 1
- },
- {
- "name": "tests/unit/plugins/modules/test_fmgr_device_group.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "0448c4dc400cb579424f01b021f6a33f51c701d661921dcb5626fc225bf929d6",
- "format": 1
- },
- {
- "name": "tests/unit/plugins/modules/test_fmgr_secprof_dns.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "cea0267cea12a15e96bd02e97dc27f6491b785070e7822aae571abc585271643",
- "format": 1
- },
- {
- "name": "tests/unit/plugins/modules/test_fmgr_secprof_ssl_ssh.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "9ff2e6a7fc744ccab91b2c702f6fd2f2527445a71630b78d240fb4e2230fa1b2",
- "format": 1
- },
- {
- "name": "tests/unit/plugins/modules/test_fmgr_ha.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "d6ddf2c8a841b3186c81abcfac5bdb66d5e855feb23c4fb3f00daa1fd36b4f0a",
- "format": 1
- },
- {
- "name": "tests/unit/plugins/modules/test_fmgr_device_config.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "8401c3be5e4adff10719e9b2c1434f14d275c7e5a01db7fa8ff1be786c85c4c3",
- "format": 1
- },
- {
- "name": "tests/unit/plugins/modules/test_fmgr_secprof_wanopt.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "156710761420a3a12195b257997fb2886ee55eeada45d01e53379ab307a29d4c",
- "format": 1
- },
- {
- "name": "tests/unit/plugins/modules/test_fmgr_secprof_ips.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "502a60c2e7793b235792e30aa852a12d36aa1938dffb201f8853f0d105bb9c1e",
- "format": 1
- },
- {
- "name": "tests/unit/plugins/modules/test_fmgr_fwobj_ippool6.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "7df6a3c135a5bce1b7907a7446a7afb947d84ad0f18459ab9c597a983e52eddf",
- "format": 1
- },
- {
- "name": "tests/unit/plugins/modules/test_fmgr_fwobj_ippool.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "d23d38cd8739f947d2961ec5472c47999d9ef50aa6393c58834132eed7f5a57a",
- "format": 1
- },
- {
- "name": "tests/unit/requirements.txt",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "48ada20ce37d554c681d979a24be9fb42d23f5a7c065161191636eab7cfcf02a",
- "format": 1
- },
- {
- "name": "changelogs",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "changelogs/fragments",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "changelogs/fragments/.keep",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
- "format": 1
- },
- {
- "name": "changelogs/config.yaml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "7140e78998772ced00b93cd84d98708f056b1ab5738ce3957f56185bd17272e8",
- "format": 1
- },
- {
- "name": "changelogs/changelog.yaml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "aa39cb2256d5c5d10e56f79a5d481f7834fd9cdec126ed0e60f3d23c14cf514a",
- "format": 1
- },
- {
- "name": "README.md",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "9946eb44edaffa74dca585845d08650fdae505de464a43714d4a88d641c1fc31",
- "format": 1
- }
- ],
- "format": 1
-} \ No newline at end of file
diff --git a/ansible_collections/community/fortios/MANIFEST.json b/ansible_collections/community/fortios/MANIFEST.json
deleted file mode 100644
index e9644bc2c..000000000
--- a/ansible_collections/community/fortios/MANIFEST.json
+++ /dev/null
@@ -1,36 +0,0 @@
-{
- "collection_info": {
- "namespace": "community",
- "name": "fortios",
- "version": "1.0.0",
- "authors": [
- "Luke Weighall (github.com/lweighall)",
- "Andrew Welsh (github.com/Ghilli3)",
- "Jim Huber (github.com/p4r4n0y1ng)"
- ],
- "readme": "README.md",
- "tags": [
- "community",
- "fortios"
- ],
- "description": "modules for management of FortiOS devices",
- "license": [],
- "license_file": "LICENSE",
- "dependencies": {
- "ansible.netcommon": ">=1.0.0",
- "fortinet.fortios": ">=1.0.0"
- },
- "repository": "https://github.com/ansible-collections/community.fortios",
- "documentation": null,
- "homepage": "https://github.com/ansible-collections/community.fortios",
- "issues": "https://github.com/ansible-collections/community.fortios/issues"
- },
- "file_manifest_file": {
- "name": "FILES.json",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "49d0dc8fba167a3485191481126c7429bcd64d3ddc8733bdc1c94fdd05757fb1",
- "format": 1
- },
- "format": 1
-} \ No newline at end of file
diff --git a/ansible_collections/community/fortios/README.md b/ansible_collections/community/fortios/README.md
deleted file mode 100644
index a3a0353c8..000000000
--- a/ansible_collections/community/fortios/README.md
+++ /dev/null
@@ -1,99 +0,0 @@
-# community.fortios Collection
-<!-- Add CI and code coverage badges here. Samples included below. -->
-[![CI](https://github.com/ansible-collections/community.fortios/workflows/CI/badge.svg?event=push)](https://github.com/ansible-collections/community.fortios/actions) [![Codecov](https://img.shields.io/codecov/c/github/ansible-collections/community.fortios)](https://codecov.io/gh/ansible-collections/community.fortios)
-
-<!-- Describe the collection and why a user would want to use it. What does the collection do? -->
-
-This repo hosts the `community.fortios` Ansible Collection.
-
-The collection includes a variety of Ansible content to automate the management of FortiOS devices.
-
-## Tested with Ansible
-
-<!-- List the versions of Ansible the collection has been tested with. Must match what is in galaxy.yml. -->
-
-- `2.9`
-- `2.10`
-- `devel`
-
-## External requirements
-
-<!-- List any external resources the collection depends on, for example minimum versions of an OS, libraries, or utilities. Do not list other Ansible collections here. -->
-
-- None
-
-<!-- ### Supported connections -->
-
-<!-- Optional. If your collection supports only specific connection types (such as HTTPAPI, netconf, or others), list them here. -->
-
-## Included Content
-
-- **Modules**:
- - `faz_device`
- - `fmgr_device`
- - `fmgr_device_config`
- - `fmgr_device_group`
- - `fmgr_device_provision_template`
- - `fmgr_fwobj_address`
- - `fmgr_fwobj_ippool`
- - `fmgr_fwobj_ippool6`
- - `fmgr_fwobj_service`
- - `fmgr_fwobj_vip`
- - `fmgr_fwpol_ipv4`
- - `fmgr_fwpol_package`
- - `fmgr_ha`
- - `fmgr_provisioning`
- - `fmgr_query`
- - `fmgr_script`
- - `fmgr_secprof_appctrl`
- - `fmgr_secprof_av`
- - `fmgr_secprof_dns`
- - `fmgr_secprof_ips`
- - `fmgr_secprof_profile_group`
- - `fmgr_secprof_proxy`
- - `fmgr_secprof_spam`
- - `fmgr_secprof_ssl_ssh`
- - `fmgr_secprof_voip`
- - `fmgr_secprof_waf`
- - `fmgr_secprof_wanopt`
- - `fmgr_secprof_web`
-
-## Using this collection
-
-<!--Include some quick examples that cover the most common use cases for your collection content. -->
-
-See [Ansible Using collections](https://docs.ansible.com/ansible/latest/user_guide/collections_using.html) for more details.
-
-## Contributing to this collection
-
-<!--Describe how the community can contribute to your collection. At a minimum, include how and where users can create issues to report problems or request features for this collection. List contribution requirements, including preferred workflows and necessary testing, so you can benefit from community PRs. If you are following general Ansible contributor guidelines, you can link to - [Ansible Community Guide](https://docs.ansible.com/ansible/latest/community/index.html). -->
-
-[Ansible Community Guide](https://docs.ansible.com/ansible/latest/community/index.html)
-
-## Release notes
-
-See the [changelog](https://github.com/ansible-collections/community.fortios/tree/main/CHANGELOG.rst).
-
-<!-- ## Roadmap -->
-
-<!-- Optional. Include the roadmap for this collection, and the proposed release/versioning strategy so users can anticipate the upgrade/update cycle. -->
-
-## More information
-
-<!-- List out where the user can find additional information, such as working group meeting times, slack/IRC channels, or documentation for the product this collection automates. At a minimum, link to: -->
-
-- [Ansible Collection overview](https://github.com/ansible-collections/overview)
-- [Ansible User guide](https://docs.ansible.com/ansible/latest/user_guide/index.html)
-- [Ansible Developer guide](https://docs.ansible.com/ansible/latest/dev_guide/index.html)
-- [Ansible Collections Checklist](https://github.com/ansible-collections/overview/blob/master/collection_requirements.rst)
-- [Ansible Community code of conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html)
-- [The Bullhorn (the Ansible Contributor newsletter)](https://us19.campaign-archive.com/home/?u=56d874e027110e35dea0e03c1&id=d6635f5420)
-- [Changes impacting Contributors](https://github.com/ansible-collections/overview/issues/45)
-
-## Licensing
-
-<!-- Include the appropriate license information here and a pointer to the full licensing details. If the collection contains modules migrated from the ansible/ansible repo, you must use the same license that existed in the ansible/ansible repo. See the GNU license example below. -->
-
-GNU General Public License v3.0 or later.
-
-See [LICENSE](https://www.gnu.org/licenses/gpl-3.0.txt) to see the full text.
diff --git a/ansible_collections/community/fortios/changelogs/changelog.yaml b/ansible_collections/community/fortios/changelogs/changelog.yaml
deleted file mode 100644
index 0a0e43d15..000000000
--- a/ansible_collections/community/fortios/changelogs/changelog.yaml
+++ /dev/null
@@ -1,18 +0,0 @@
-ancestor: null
-releases:
- 0.1.0:
- changes:
- release_summary: 'This is the first pre-release version of ``community.fortios``
- after migrating from ``community.network``.
-
- '
- fragments:
- - summary.yaml
- release_date: '2021-01-14'
- 1.0.0:
- changes:
- release_summary: This is the first stable release version of ``community.fortios``
- after migrating from ``community.network``.
- fragments:
- - release.yaml
- release_date: '2021-01-18'
diff --git a/ansible_collections/community/fortios/changelogs/config.yaml b/ansible_collections/community/fortios/changelogs/config.yaml
deleted file mode 100644
index 91b6532af..000000000
--- a/ansible_collections/community/fortios/changelogs/config.yaml
+++ /dev/null
@@ -1,29 +0,0 @@
-changelog_filename_template: ../CHANGELOG.rst
-changelog_filename_version_depth: 0
-changes_file: changelog.yaml
-changes_format: combined
-keep_fragments: false
-mention_ancestor: true
-new_plugins_after_name: removed_features
-notesdir: fragments
-prelude_section_name: release_summary
-prelude_section_title: Release Summary
-sections:
-- - major_changes
- - Major Changes
-- - minor_changes
- - Minor Changes
-- - breaking_changes
- - Breaking Changes / Porting Guide
-- - deprecated_features
- - Deprecated Features
-- - removed_features
- - Removed Features (previously deprecated)
-- - security_fixes
- - Security Fixes
-- - bugfixes
- - Bugfixes
-- - known_issues
- - Known Issues
-title: community.fortios
-trivial_section_name: trivial
diff --git a/ansible_collections/community/fortios/meta/runtime.yml b/ansible_collections/community/fortios/meta/runtime.yml
deleted file mode 100644
index 2ee3c9fa9..000000000
--- a/ansible_collections/community/fortios/meta/runtime.yml
+++ /dev/null
@@ -1,2 +0,0 @@
----
-requires_ansible: '>=2.9.10'
diff --git a/ansible_collections/community/fortios/plugins/httpapi/fortianalyzer.py b/ansible_collections/community/fortios/plugins/httpapi/fortianalyzer.py
deleted file mode 100644
index 0e59ea48e..000000000
--- a/ansible_collections/community/fortios/plugins/httpapi/fortianalyzer.py
+++ /dev/null
@@ -1,453 +0,0 @@
-# Copyright (c) 2018 Fortinet and/or its affiliates.
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-DOCUMENTATION = '''
----
-author:
- - Luke Weighall (@lweighall)
- - Andrew Welsh (@Ghilli3)
- - Jim Huber (@p4r4n0y1ng)
-name: fortianalyzer
-short_description: HttpApi Plugin for Fortinet FortiAnalyzer Appliance or VM.
-description:
- - This HttpApi plugin provides methods to connect to Fortinet FortiAnalyzer Appliance or VM via JSON RPC API.
-
-'''
-
-import json
-from ansible.plugins.httpapi import HttpApiBase
-from ansible.module_utils.basic import to_text
-from ansible_collections.community.fortios.plugins.module_utils.fortianalyzer.common import BASE_HEADERS
-from ansible_collections.community.fortios.plugins.module_utils.fortianalyzer.common import FAZBaseException
-from ansible_collections.community.fortios.plugins.module_utils.fortianalyzer.common import FAZCommon
-from ansible_collections.community.fortios.plugins.module_utils.fortianalyzer.common import FAZMethods
-
-
-class HttpApi(HttpApiBase):
- def __init__(self, connection):
- super(HttpApi, self).__init__(connection)
- self._req_id = 0
- self._sid = None
- self._url = "/jsonrpc"
- self._host = None
- self._tools = FAZCommon
- self._debug = False
- self._connected_faz = None
- self._last_response_msg = None
- self._last_response_code = None
- self._last_data_payload = None
- self._last_url = None
- self._last_response_raw = None
- self._locked_adom_list = list()
- self._locked_adoms_by_user = list()
- self._uses_workspace = False
- self._uses_adoms = False
- self._adom_list = list()
- self._logged_in_user = None
-
- def set_become(self, become_context):
- """
- ELEVATION IS NOT REQUIRED ON FORTINET DEVICES - SKIPPED
- :param become_context: Unused input.
- :return: None
- """
- return None
-
- def update_auth(self, response, response_data):
- """
- TOKENS ARE NOT USED SO NO NEED TO UPDATE AUTH
- :param response: Unused input.
- :param response_data Unused_input.
- :return: None
- """
- return None
-
- def login(self, username, password):
- """
- This function will log the plugin into FortiAnalyzer, and return the results.
- :param username: Username of FortiAnalyzer Admin
- :param password: Password of FortiAnalyzer Admin
-
- :return: Dictionary of status if it logged in or not.
- """
-
- self._logged_in_user = username
- self.send_request(FAZMethods.EXEC, self._tools.format_request(FAZMethods.EXEC, "sys/login/user",
- passwd=password, user=username,))
-
- if "FortiAnalyzer object connected to FortiAnalyzer" in self.__str__():
- # If Login worked then inspect the FortiAnalyzer for Workspace Mode, and it's system information.
- self.inspect_faz()
- return
- else:
- raise FAZBaseException(msg="Unknown error while logging in...connection was lost during login operation..."
- " Exiting")
-
- def inspect_faz(self):
- # CHECK FOR WORKSPACE MODE TO SEE IF WE HAVE TO ENABLE ADOM LOCKS
- status = self.get_system_status()
- if status[0] == -11:
- # THE CONNECTION GOT LOST SOMEHOW, REMOVE THE SID AND REPORT BAD LOGIN
- self.logout()
- raise FAZBaseException(msg="Error -11 -- the Session ID was likely malformed somehow. Contact authors."
- " Exiting")
- elif status[0] == 0:
- try:
- self.check_mode()
- if self._uses_adoms:
- self.get_adom_list()
- if self._uses_workspace:
- self.get_locked_adom_list()
- self._connected_faz = status[1]
- self._host = self._connected_faz["Hostname"]
- except Exception:
- pass
- return
-
- def logout(self):
- """
- This function will logout of the FortiAnalyzer.
- """
- if self.sid is not None:
- # IF WE WERE USING WORKSPACES, THEN CLEAN UP OUR LOCKS IF THEY STILL EXIST
- if self.uses_workspace:
- self.get_lock_info()
- self.run_unlock()
- ret_code, response = self.send_request(FAZMethods.EXEC,
- self._tools.format_request(FAZMethods.EXEC, "sys/logout"))
- self.sid = None
- return ret_code, response
-
- def send_request(self, method, params):
- """
- Responsible for actual sending of data to the connection httpapi base plugin. Does some formatting as well.
- :param params: A formatted dictionary that was returned by self.common_datagram_params()
- before being called here.
- :param method: The preferred API Request method (GET, ADD, POST, etc....)
- :type method: basestring
-
- :return: Dictionary of status if it logged in or not.
- """
-
- try:
- if self.sid is None and params[0]["url"] != "sys/login/user":
- try:
- self.connection._connect()
- except Exception as err:
- raise FAZBaseException(
- msg="An problem happened with the httpapi plugin self-init connection process. "
- "Error: " + to_text(err))
- except IndexError:
- raise FAZBaseException("An attempt was made at communicating with a FAZ with "
- "no valid session and an incorrectly formatted request.")
- except Exception:
- raise FAZBaseException("An attempt was made at communicating with a FAZ with "
- "no valid session and an unexpected error was discovered.")
-
- self._update_request_id()
- json_request = {
- "method": method,
- "params": params,
- "session": self.sid,
- "id": self.req_id,
- "verbose": 1
- }
- data = json.dumps(json_request, ensure_ascii=False).replace('\\\\', '\\')
- try:
- # Sending URL and Data in Unicode, per Ansible Specifications for Connection Plugins
- response, response_data = self.connection.send(path=to_text(self._url), data=to_text(data),
- headers=BASE_HEADERS)
- # Get Unicode Response - Must convert from StringIO to unicode first so we can do a replace function below
- result = json.loads(to_text(response_data.getvalue()))
- self._update_self_from_response(result, self._url, data)
- return self._handle_response(result)
- except Exception as err:
- raise FAZBaseException(err)
-
- def _handle_response(self, response):
- self._set_sid(response)
- if isinstance(response["result"], list):
- result = response["result"][0]
- else:
- result = response["result"]
- if "data" in result:
- return result["status"]["code"], result["data"]
- else:
- return result["status"]["code"], result
-
- def _update_self_from_response(self, response, url, data):
- self._last_response_raw = response
- if isinstance(response["result"], list):
- result = response["result"][0]
- else:
- result = response["result"]
- if "status" in result:
- self._last_response_code = result["status"]["code"]
- self._last_response_msg = result["status"]["message"]
- self._last_url = url
- self._last_data_payload = data
-
- def _set_sid(self, response):
- if self.sid is None and "session" in response:
- self.sid = response["session"]
-
- def return_connected_faz(self):
- """
- Returns the data stored under self._connected_faz
-
- :return: dict
- """
- try:
- if self._connected_faz:
- return self._connected_faz
- except Exception:
- raise FAZBaseException("Couldn't Retrieve Connected FAZ Stats")
-
- def get_system_status(self):
- """
- Returns the system status page from the FortiAnalyzer, for logging and other uses.
- return: status
- """
- status = self.send_request(FAZMethods.GET, self._tools.format_request(FAZMethods.GET, "sys/status"))
- return status
-
- @property
- def debug(self):
- return self._debug
-
- @debug.setter
- def debug(self, val):
- self._debug = val
-
- @property
- def req_id(self):
- return self._req_id
-
- @req_id.setter
- def req_id(self, val):
- self._req_id = val
-
- def _update_request_id(self, reqid=0):
- self.req_id = reqid if reqid != 0 else self.req_id + 1
-
- @property
- def sid(self):
- return self._sid
-
- @sid.setter
- def sid(self, val):
- self._sid = val
-
- def __str__(self):
- if self.sid is not None and self.connection._url is not None:
- return "FortiAnalyzer object connected to FortiAnalyzer: " + to_text(self.connection._url)
- return "FortiAnalyzer object with no valid connection to a FortiAnalyzer appliance."
-
- ##################################
- # BEGIN DATABASE LOCK CONTEXT CODE
- ##################################
-
- @property
- def uses_workspace(self):
- return self._uses_workspace
-
- @uses_workspace.setter
- def uses_workspace(self, val):
- self._uses_workspace = val
-
- @property
- def uses_adoms(self):
- return self._uses_adoms
-
- @uses_adoms.setter
- def uses_adoms(self, val):
- self._uses_adoms = val
-
- def add_adom_to_lock_list(self, adom):
- if adom not in self._locked_adom_list:
- self._locked_adom_list.append(adom)
-
- def remove_adom_from_lock_list(self, adom):
- if adom in self._locked_adom_list:
- self._locked_adom_list.remove(adom)
-
- def check_mode(self):
- """
- Checks FortiAnalyzer for the use of Workspace mode
- """
- url = "/cli/global/system/global"
- code, resp_obj = self.send_request(FAZMethods.GET,
- self._tools.format_request(FAZMethods.GET,
- url,
- fields=["workspace-mode", "adom-status"]))
- try:
- if resp_obj["workspace-mode"] == "workflow":
- self.uses_workspace = True
- elif resp_obj["workspace-mode"] == "disabled":
- self.uses_workspace = False
- except KeyError:
- self.uses_workspace = False
- except Exception:
- raise FAZBaseException(msg="Couldn't determine workspace-mode in the plugin")
- try:
- if resp_obj["adom-status"] in [1, "enable"]:
- self.uses_adoms = True
- else:
- self.uses_adoms = False
- except KeyError:
- self.uses_adoms = False
- except Exception:
- raise FAZBaseException(msg="Couldn't determine adom-status in the plugin")
-
- def run_unlock(self):
- """
- Checks for ADOM status, if locked, it will unlock
- """
- for adom_locked in self._locked_adoms_by_user:
- adom = adom_locked["adom"]
- self.unlock_adom(adom)
-
- def lock_adom(self, adom=None, *args, **kwargs):
- """
- Locks an ADOM for changes
- """
- if adom:
- if adom.lower() == "global":
- url = "/dvmdb/global/workspace/lock/"
- else:
- url = "/dvmdb/adom/{adom}/workspace/lock/".format(adom=adom)
- else:
- url = "/dvmdb/adom/root/workspace/lock"
- code, respobj = self.send_request(FAZMethods.EXEC, self._tools.format_request(FAZMethods.EXEC, url))
- if code == 0 and respobj["status"]["message"].lower() == "ok":
- self.add_adom_to_lock_list(adom)
- return code, respobj
-
- def unlock_adom(self, adom=None, *args, **kwargs):
- """
- Unlocks an ADOM after changes
- """
- if adom:
- if adom.lower() == "global":
- url = "/dvmdb/global/workspace/unlock/"
- else:
- url = "/dvmdb/adom/{adom}/workspace/unlock/".format(adom=adom)
- else:
- url = "/dvmdb/adom/root/workspace/unlock"
- code, respobj = self.send_request(FAZMethods.EXEC, self._tools.format_request(FAZMethods.EXEC, url))
- if code == 0 and respobj["status"]["message"].lower() == "ok":
- self.remove_adom_from_lock_list(adom)
- return code, respobj
-
- def commit_changes(self, adom=None, aux=False, *args, **kwargs):
- """
- Commits changes to an ADOM
- """
- if adom:
- if aux:
- url = "/pm/config/adom/{adom}/workspace/commit".format(adom=adom)
- else:
- if adom.lower() == "global":
- url = "/dvmdb/global/workspace/commit/"
- else:
- url = "/dvmdb/adom/{adom}/workspace/commit".format(adom=adom)
- else:
- url = "/dvmdb/adom/root/workspace/commit"
- return self.send_request(FAZMethods.EXEC, self._tools.format_request(FAZMethods.EXEC, url))
-
- def get_lock_info(self, adom=None):
- """
- Gets ADOM lock info so it can be displayed with the error messages. Or if determined to be locked by ansible
- for some reason, then unlock it.
- """
- if not adom or adom == "root":
- url = "/dvmdb/adom/root/workspace/lockinfo"
- else:
- if adom.lower() == "global":
- url = "/dvmdb/global/workspace/lockinfo/"
- else:
- url = "/dvmdb/adom/{adom}/workspace/lockinfo/".format(adom=adom)
- datagram = {}
- data = self._tools.format_request(FAZMethods.GET, url, **datagram)
- resp_obj = self.send_request(FAZMethods.GET, data)
- code = resp_obj[0]
- if code != 0:
- self._module.fail_json(msg=("An error occurred trying to get the ADOM Lock Info. Error: " + to_text(resp_obj)))
- elif code == 0:
- try:
- if resp_obj[1]["status"]["message"] == "OK":
- self._lock_info = None
- except Exception:
- self._lock_info = resp_obj[1]
- return resp_obj
-
- def get_adom_list(self):
- """
- Gets the list of ADOMs for the FortiAnalyzer
- """
- if self.uses_adoms:
- url = "/dvmdb/adom"
- datagram = {}
- data = self._tools.format_request(FAZMethods.GET, url, **datagram)
- resp_obj = self.send_request(FAZMethods.GET, data)
- code = resp_obj[0]
- if code != 0:
- self._module.fail_json(msg=("An error occurred trying to get the ADOM Info. Error: " + to_text(resp_obj)))
- elif code == 0:
- num_of_adoms = len(resp_obj[1])
- append_list = ['root', ]
- for adom in resp_obj[1]:
- if adom["tab_status"] != "":
- append_list.append(to_text(adom["name"]))
- self._adom_list = append_list
- return resp_obj
-
- def get_locked_adom_list(self):
- """
- Gets the list of locked adoms
- """
- try:
- locked_list = list()
- locked_by_user_list = list()
- for adom in self._adom_list:
- adom_lock_info = self.get_lock_info(adom=adom)
- try:
- if adom_lock_info[1]["status"]["message"] == "OK":
- continue
- except Exception:
- pass
- try:
- if adom_lock_info[1][0]["lock_user"]:
- locked_list.append(to_text(adom))
- if adom_lock_info[1][0]["lock_user"] == self._logged_in_user:
- locked_by_user_list.append({"adom": to_text(adom), "user": to_text(adom_lock_info[1][0]["lock_user"])})
- except Exception as err:
- raise FAZBaseException(err)
- self._locked_adom_list = locked_list
- self._locked_adoms_by_user = locked_by_user_list
-
- except Exception as err:
- raise FAZBaseException(msg=("An error occurred while trying to get the locked adom list. Error: "
- + to_text(err)))
-
- #################################
- # END DATABASE LOCK CONTEXT CODE
- #################################
diff --git a/ansible_collections/community/fortios/plugins/httpapi/fortimanager.py b/ansible_collections/community/fortios/plugins/httpapi/fortimanager.py
deleted file mode 100644
index bbdaacb8d..000000000
--- a/ansible_collections/community/fortios/plugins/httpapi/fortimanager.py
+++ /dev/null
@@ -1,459 +0,0 @@
-# Copyright (c) 2018 Fortinet and/or its affiliates.
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-
-from __future__ import (absolute_import, division, print_function)
-
-__metaclass__ = type
-
-DOCUMENTATION = '''
----
-author:
- - Luke Weighall (@lweighall)
- - Andrew Welsh (@Ghilli3)
- - Jim Huber (@p4r4n0y1ng)
-name: fortimanager
-short_description: HttpApi Plugin for Fortinet FortiManager Appliance or VM.
-description:
- - This HttpApi plugin provides methods to connect to Fortinet FortiManager Appliance or VM via JSON RPC API.
-'''
-
-import json
-from ansible.errors import AnsibleError
-from ansible.plugins.httpapi import HttpApiBase
-from ansible.module_utils.basic import to_text
-
-try:
- from ansible_collections.fortinet.fortimanager.plugins.module_utils.common import BASE_HEADERS
- from ansible_collections.fortinet.fortimanager.plugins.module_utils.common import FMGBaseException
- from ansible_collections.fortinet.fortimanager.plugins.module_utils.common import FMGRCommon
- from ansible_collections.fortinet.fortimanager.plugins.module_utils.common import FMGRMethods
- HAS_FORTIMANAGER_COLLECTION = True
-except ImportError:
- HAS_FORTIMANAGER_COLLECTION = False
-
-
-class HttpApi(HttpApiBase):
- def __init__(self, connection):
- super(HttpApi, self).__init__(connection)
- self._req_id = 0
- self._sid = None
- self._url = "/jsonrpc"
- self._host = None
- self._tools = FMGRCommon
- self._debug = False
- self._connected_fmgr = None
- self._last_response_msg = None
- self._last_response_code = None
- self._last_data_payload = None
- self._last_url = None
- self._last_response_raw = None
- self._locked_adom_list = list()
- self._locked_adoms_by_user = list()
- self._uses_workspace = False
- self._uses_adoms = False
- self._adom_list = list()
- self._logged_in_user = None
- if not HAS_FORTIMANAGER_COLLECTION:
- raise AnsibleError("The community.fortios.fortimanager httpapi plugin requires the fortios.fortimanager collection.")
-
- def set_become(self, become_context):
- """
- ELEVATION IS NOT REQUIRED ON FORTINET DEVICES - SKIPPED.
- :param become_context: Unused input.
- :return: None
- """
- return None
-
- def update_auth(self, response, response_data):
- """
- TOKENS ARE NOT USED SO NO NEED TO UPDATE AUTH.
- :param response: Unused input.
- :param response_data Unused_input.
- :return: None
- """
- return None
-
- def login(self, username, password):
-
- """
- This function will log the plugin into FortiManager, and return the results.
- :param username: Username of FortiManager Admin
- :param password: Password of FortiManager Admin
-
- :return: Dictionary of status if it logged in or not.
- """
- self._logged_in_user = username
- self.send_request(FMGRMethods.EXEC, self._tools.format_request(FMGRMethods.EXEC, "sys/login/user",
- passwd=password, user=username, ))
-
- if "FortiManager object connected to FortiManager" in self.__str__():
- # If Login worked, then inspect the FortiManager for Workspace Mode, and it's system information.
- self.inspect_fmgr()
- return
- else:
- raise FMGBaseException(msg="Unknown error while logging in...connection was lost during login operation...."
- " Exiting")
-
- def inspect_fmgr(self):
- # CHECK FOR WORKSPACE MODE TO SEE IF WE HAVE TO ENABLE ADOM LOCKS
- status = self.get_system_status()
- if status[0] == -11:
- # THE CONNECTION GOT LOST SOMEHOW, REMOVE THE SID AND REPORT BAD LOGIN
- self.logout()
- raise FMGBaseException(msg="Error -11 -- the Session ID was likely malformed somehow. Contact authors."
- " Exiting")
- elif status[0] == 0:
- try:
- self.check_mode()
- if self._uses_adoms:
- self.get_adom_list()
- if self._uses_workspace:
- self.get_locked_adom_list()
- self._connected_fmgr = status[1]
- self._host = self._connected_fmgr["Hostname"]
- except BaseException:
- pass
- return
-
- def logout(self):
- """
- This function will logout of the FortiManager.
- """
- if self.sid is not None:
- # IF WE WERE USING WORKSPACES, THEN CLEAN UP OUR LOCKS IF THEY STILL EXIST
- if self.uses_workspace:
- self.get_lock_info()
- self.run_unlock()
- ret_code, response = self.send_request(FMGRMethods.EXEC,
- self._tools.format_request(FMGRMethods.EXEC, "sys/logout"))
- self.sid = None
- return ret_code, response
-
- def send_request(self, method, params):
- """
- Responsible for actual sending of data to the connection httpapi base plugin. Does some formatting too.
- :param params: A formatted dictionary that was returned by self.common_datagram_params()
- before being called here.
- :param method: The preferred API Request method (GET, ADD, POST, etc....)
- :type method: basestring
-
- :return: Dictionary of status, if it logged in or not.
- """
- try:
- if self.sid is None and params[0]["url"] != "sys/login/user":
- try:
- self.connection._connect()
- except Exception as err:
- raise FMGBaseException(
- msg="An problem happened with the httpapi plugin self-init connection process. "
- "Error: " + to_text(err))
- except IndexError:
- raise FMGBaseException("An attempt was made at communicating with a FMG with "
- "no valid session and an incorrectly formatted request.")
- except Exception as err:
- raise FMGBaseException("An attempt was made at communicating with a FMG with "
- "no valid session and an unexpected error was discovered. \n Error: " + to_text(err))
-
- self._update_request_id()
- json_request = {
- "method": method,
- "params": params,
- "session": self.sid,
- "id": self.req_id,
- "verbose": 1
- }
- data = json.dumps(json_request, ensure_ascii=False).replace('\\\\', '\\')
- try:
- # Sending URL and Data in Unicode, per Ansible Specifications for Connection Plugins
- response, response_data = self.connection.send(path=to_text(self._url), data=to_text(data),
- headers=BASE_HEADERS)
- # Get Unicode Response - Must convert from StringIO to unicode first so we can do a replace function below
- result = json.loads(to_text(response_data.getvalue()))
- self._update_self_from_response(result, self._url, data)
- return self._handle_response(result)
- except Exception as err:
- raise FMGBaseException(err)
-
- def _handle_response(self, response):
- self._set_sid(response)
- if isinstance(response["result"], list):
- result = response["result"][0]
- else:
- result = response["result"]
- if "data" in result:
- return result["status"]["code"], result["data"]
- else:
- return result["status"]["code"], result
-
- def _update_self_from_response(self, response, url, data):
- self._last_response_raw = response
- if isinstance(response["result"], list):
- result = response["result"][0]
- else:
- result = response["result"]
- if "status" in result:
- self._last_response_code = result["status"]["code"]
- self._last_response_msg = result["status"]["message"]
- self._last_url = url
- self._last_data_payload = data
-
- def _set_sid(self, response):
- if self.sid is None and "session" in response:
- self.sid = response["session"]
-
- def return_connected_fmgr(self):
- """
- Returns the data stored under self._connected_fmgr
-
- :return: dict
- """
- try:
- if self._connected_fmgr:
- return self._connected_fmgr
- except Exception:
- raise FMGBaseException("Couldn't Retrieve Connected FMGR Stats")
-
- def get_system_status(self):
- """
- Returns the system status page from the FortiManager, for logging and other uses.
- return: status
- """
- status = self.send_request(FMGRMethods.GET, self._tools.format_request(FMGRMethods.GET, "sys/status"))
- return status
-
- @property
- def debug(self):
- return self._debug
-
- @debug.setter
- def debug(self, val):
- self._debug = val
-
- @property
- def req_id(self):
- return self._req_id
-
- @req_id.setter
- def req_id(self, val):
- self._req_id = val
-
- def _update_request_id(self, reqid=0):
- self.req_id = reqid if reqid != 0 else self.req_id + 1
-
- @property
- def sid(self):
- return self._sid
-
- @sid.setter
- def sid(self, val):
- self._sid = val
-
- def __str__(self):
- if self.sid is not None and self.connection._url is not None:
- return "FortiManager object connected to FortiManager: " + to_text(self.connection._url)
- return "FortiManager object with no valid connection to a FortiManager appliance."
-
- ##################################
- # BEGIN DATABASE LOCK CONTEXT CODE
- ##################################
-
- @property
- def uses_workspace(self):
- return self._uses_workspace
-
- @uses_workspace.setter
- def uses_workspace(self, val):
- self._uses_workspace = val
-
- @property
- def uses_adoms(self):
- return self._uses_adoms
-
- @uses_adoms.setter
- def uses_adoms(self, val):
- self._uses_adoms = val
-
- def add_adom_to_lock_list(self, adom):
- if adom not in self._locked_adom_list:
- self._locked_adom_list.append(adom)
-
- def remove_adom_from_lock_list(self, adom):
- if adom in self._locked_adom_list:
- self._locked_adom_list.remove(adom)
-
- def check_mode(self):
- """
- Checks FortiManager for the use of Workspace mode
- """
- url = "/cli/global/system/global"
- code, resp_obj = self.send_request(FMGRMethods.GET,
- self._tools.format_request(FMGRMethods.GET,
- url,
- fields=["workspace-mode", "adom-status"]))
- try:
- if resp_obj["workspace-mode"] == "workflow":
- self.uses_workspace = True
- elif resp_obj["workspace-mode"] == "disabled":
- self.uses_workspace = False
- except KeyError:
- raise FMGBaseException(msg="Couldn't determine workspace-mode in the plugin")
- try:
- if resp_obj["adom-status"] in [1, "enable"]:
- self.uses_adoms = True
- else:
- self.uses_adoms = False
- except KeyError:
- raise FMGBaseException(msg="Couldn't determine adom-status in the plugin")
-
- def run_unlock(self):
- """
- Checks for ADOM status, if locked, it will unlock
- """
- for adom_locked in self._locked_adoms_by_user:
- adom = adom_locked["adom"]
- self.unlock_adom(adom)
-
- def lock_adom(self, adom=None, *args, **kwargs):
- """
- Locks an ADOM for changes
- """
- if adom:
- if adom.lower() == "global":
- url = "/dvmdb/global/workspace/lock/"
- else:
- url = "/dvmdb/adom/{adom}/workspace/lock/".format(adom=adom)
- else:
- url = "/dvmdb/adom/root/workspace/lock"
- code, respobj = self.send_request(FMGRMethods.EXEC, self._tools.format_request(FMGRMethods.EXEC, url))
- if code == 0 and respobj["status"]["message"].lower() == "ok":
- self.add_adom_to_lock_list(adom)
- return code, respobj
-
- def unlock_adom(self, adom=None, *args, **kwargs):
- """
- Unlocks an ADOM after changes
- """
- if adom:
- if adom.lower() == "global":
- url = "/dvmdb/global/workspace/unlock/"
- else:
- url = "/dvmdb/adom/{adom}/workspace/unlock/".format(adom=adom)
- else:
- url = "/dvmdb/adom/root/workspace/unlock"
- code, respobj = self.send_request(FMGRMethods.EXEC, self._tools.format_request(FMGRMethods.EXEC, url))
- if code == 0 and respobj["status"]["message"].lower() == "ok":
- self.remove_adom_from_lock_list(adom)
- return code, respobj
-
- def commit_changes(self, adom=None, aux=False, *args, **kwargs):
- """
- Commits changes to an ADOM
- """
- if adom:
- if aux:
- url = "/pm/config/adom/{adom}/workspace/commit".format(adom=adom)
- else:
- if adom.lower() == "global":
- url = "/dvmdb/global/workspace/commit/"
- else:
- url = "/dvmdb/adom/{adom}/workspace/commit".format(adom=adom)
- else:
- url = "/dvmdb/adom/root/workspace/commit"
- return self.send_request(FMGRMethods.EXEC, self._tools.format_request(FMGRMethods.EXEC, url))
-
- def get_lock_info(self, adom=None):
- """
- Gets ADOM lock info so it can be displayed with the error messages. Or if determined to be locked by ansible
- for some reason, then unlock it.
- """
- if not adom or adom == "root":
- url = "/dvmdb/adom/root/workspace/lockinfo"
- else:
- if adom.lower() == "global":
- url = "/dvmdb/global/workspace/lockinfo/"
- else:
- url = "/dvmdb/adom/{adom}/workspace/lockinfo/".format(adom=adom)
- datagram = {}
- data = self._tools.format_request(FMGRMethods.GET, url, **datagram)
- resp_obj = self.send_request(FMGRMethods.GET, data)
- code = resp_obj[0]
- if code != 0:
- self._module.fail_json(msg=("An error occurred trying to get the ADOM Lock Info. "
- "Error: " + to_text(resp_obj)))
- elif code == 0:
- try:
- if resp_obj[1]["status"]["message"] == "OK":
- self._lock_info = None
- except Exception:
- self._lock_info = resp_obj[1]
- return resp_obj
-
- def get_adom_list(self):
- """
- Gets the list of ADOMs for the FortiManager
- """
- if self.uses_adoms:
- url = "/dvmdb/adom"
- datagram = {}
- data = self._tools.format_request(FMGRMethods.GET, url, **datagram)
- resp_obj = self.send_request(FMGRMethods.GET, data)
- code = resp_obj[0]
- if code != 0:
- self._module.fail_json(msg=("An error occurred trying to get the ADOM Info. "
- "Error: " + to_text(resp_obj)))
- elif code == 0:
- num_of_adoms = len(resp_obj[1])
- append_list = ['root', ]
- for adom in resp_obj[1]:
- if adom["tab_status"] != "":
- append_list.append(to_text(adom["name"]))
- self._adom_list = append_list
- return resp_obj
-
- def get_locked_adom_list(self):
- """
- Gets the list of locked adoms
- """
- try:
- locked_list = list()
- locked_by_user_list = list()
- for adom in self._adom_list:
- adom_lock_info = self.get_lock_info(adom=adom)
- try:
- if adom_lock_info[1]["status"]["message"] == "OK":
- continue
- except IndexError as err:
- pass
- try:
- if adom_lock_info[1][0]["lock_user"]:
- locked_list.append(to_text(adom))
- if adom_lock_info[1][0]["lock_user"] == self._logged_in_user:
- locked_by_user_list.append({"adom": to_text(adom),
- "user": to_text(adom_lock_info[1][0]["lock_user"])})
- except Exception as err:
- raise FMGBaseException(err)
- self._locked_adom_list = locked_list
- self._locked_adoms_by_user = locked_by_user_list
-
- except Exception as err:
- raise FMGBaseException(msg=("An error occurred while trying to get the locked adom list. Error: "
- + to_text(err)))
-
- ################################
- # END DATABASE LOCK CONTEXT CODE
- ################################
diff --git a/ansible_collections/community/fortios/plugins/module_utils/fortianalyzer/common.py b/ansible_collections/community/fortios/plugins/module_utils/fortianalyzer/common.py
deleted file mode 100644
index 50cd95cc6..000000000
--- a/ansible_collections/community/fortios/plugins/module_utils/fortianalyzer/common.py
+++ /dev/null
@@ -1,291 +0,0 @@
-# This code is part of Ansible, but is an independent component.
-# This particular file snippet, and this file snippet only, is BSD licensed.
-# Modules you write using this snippet, which is embedded dynamically by Ansible
-# still belong to the author of the module, and may assign their own license
-# to the complete work.
-#
-# (c) 2017 Fortinet, Inc
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without modification,
-# are permitted provided that the following conditions are met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-# BEGIN STATIC DATA AND MESSAGES
-class FAZMethods:
- GET = "get"
- SET = "set"
- EXEC = "exec"
- EXECUTE = "exec"
- UPDATE = "update"
- ADD = "add"
- DELETE = "delete"
- REPLACE = "replace"
- CLONE = "clone"
- MOVE = "move"
-
-
-BASE_HEADERS = {
- 'Content-Type': 'application/json',
- 'Accept': 'application/json'
-}
-
-
-# FAZ RETURN CODES
-FAZ_RC = {
- "faz_return_codes": {
- 0: {
- "msg": "OK",
- "changed": True,
- "stop_on_success": True
- },
- -100000: {
- "msg": "Module returned without actually running anything. "
- "Check parameters, and please contact the authors if needed.",
- "failed": True
- },
- -2: {
- "msg": "Object already exists.",
- "skipped": True,
- "changed": False,
- "good_codes": [0, -2]
- },
- -6: {
- "msg": "Invalid Url. Sometimes this can happen because the path is mapped to a hostname or object that"
- " doesn't exist. Double check your input object parameters."
- },
- -3: {
- "msg": "Object doesn't exist.",
- "skipped": True,
- "changed": False,
- "good_codes": [0, -3]
- },
- -10131: {
- "msg": "Object dependency failed. Do all named objects in parameters exist?",
- "changed": False,
- "skipped": True
- },
- -9998: {
- "msg": "Duplicate object. Try using mode='set', if using add. STOPPING. Use 'ignore_errors=yes' in playbook"
- "to override and mark successful.",
- },
- -20042: {
- "msg": "Device Unreachable.",
- "skipped": True
- },
- -10033: {
- "msg": "Duplicate object. Try using mode='set', if using add.",
- "changed": False,
- "skipped": True
- },
- -10000: {
- "msg": "Duplicate object. Try using mode='set', if using add.",
- "changed": False,
- "skipped": True
- },
- -20010: {
- "msg": "Device already added to FortiAnalyzer. Serial number already in use.",
- "good_codes": [0, -20010],
- "changed": False,
- "stop_on_failure": False
- },
- -20002: {
- "msg": "Invalid Argument -- Does this Device exist on FortiAnalyzer?",
- "changed": False,
- "skipped": True,
- }
- }
-}
-
-DEFAULT_RESULT_OBJ = (-100000, {"msg": "Nothing Happened. Check that handle_response is being called!"})
-FAIL_SOCKET_MSG = {"msg": "Socket Path Empty! The persistent connection manager is messed up. "
- "Try again in a few moments."}
-
-
-# BEGIN ERROR EXCEPTIONS
-class FAZBaseException(Exception):
- """Wrapper to catch the unexpected"""
-
- def __init__(self, msg=None, *args, **kwargs):
- if msg is None:
- msg = "An exception occurred within the fortianalyzer.py httpapi connection plugin."
- super(FAZBaseException, self).__init__(msg, *args)
-
-# END ERROR CLASSES
-
-
-# BEGIN CLASSES
-class FAZCommon(object):
-
- @staticmethod
- def format_request(method, url, *args, **kwargs):
- """
- Formats the payload from the module, into a payload the API handler can use.
-
- :param url: Connection URL to access
- :type url: string
- :param method: The preferred API Request method (GET, ADD, POST, etc....)
- :type method: basestring
- :param kwargs: The payload dictionary from the module to be converted.
-
- :return: Properly formatted dictionary payload for API Request via Connection Plugin.
- :rtype: dict
- """
-
- params = [{"url": url}]
- if args:
- for arg in args:
- params[0].update(arg)
- if kwargs:
- keylist = list(kwargs)
- for k in keylist:
- kwargs[k.replace("__", "-")] = kwargs.pop(k)
- if method == "get" or method == "clone":
- params[0].update(kwargs)
- else:
- if kwargs.get("data", False):
- params[0]["data"] = kwargs["data"]
- else:
- params[0]["data"] = kwargs
- return params
-
- @staticmethod
- def split_comma_strings_into_lists(obj):
- """
- Splits a CSV String into a list. Also takes a dictionary, and converts any CSV strings in any key, to a list.
-
- :param obj: object in CSV format to be parsed.
- :type obj: str or dict
-
- :return: A list containing the CSV items.
- :rtype: list
- """
- return_obj = ()
- if isinstance(obj, dict):
- if len(obj) > 0:
- for k, v in obj.items():
- if isinstance(v, str):
- new_list = list()
- if "," in v:
- new_items = v.split(",")
- for item in new_items:
- new_list.append(item.strip())
- obj[k] = new_list
- return_obj = obj
- elif isinstance(obj, str):
- return_obj = obj.replace(" ", "").split(",")
-
- return return_obj
-
- @staticmethod
- def cidr_to_netmask(cidr):
- """
- Converts a CIDR Network string to full blown IP/Subnet format in decimal format.
- Decided not use IP Address module to keep includes to a minimum.
-
- :param cidr: String object in CIDR format to be processed
- :type cidr: str
-
- :return: A string object that looks like this "x.x.x.x/y.y.y.y"
- :rtype: str
- """
- if isinstance(cidr, str):
- cidr = int(cidr)
- mask = (0xffffffff >> (32 - cidr)) << (32 - cidr)
- return (str((0xff000000 & mask) >> 24) + '.'
- + str((0x00ff0000 & mask) >> 16) + '.'
- + str((0x0000ff00 & mask) >> 8) + '.'
- + str((0x000000ff & mask)))
-
- @staticmethod
- def paramgram_child_list_override(list_overrides, paramgram, module):
- """
- If a list of items was provided to a "parent" paramgram attribute, the paramgram needs to be rewritten.
- The child keys of the desired attribute need to be deleted, and then that "parent" keys' contents is replaced
- With the list of items that was provided.
-
- :param list_overrides: Contains the response from the FortiAnalyzer.
- :type list_overrides: list
- :param paramgram: Contains the paramgram passed to the modules' local modify function.
- :type paramgram: dict
- :param module: Contains the Ansible Module Object being used by the module.
- :type module: classObject
-
- :return: A new "paramgram" refactored to allow for multiple entries being added.
- :rtype: dict
- """
- if len(list_overrides) > 0:
- for list_variable in list_overrides:
- try:
- list_variable = list_variable.replace("-", "_")
- override_data = module.params[list_variable]
- if override_data:
- del paramgram[list_variable]
- paramgram[list_variable] = override_data
- except BaseException as e:
- raise FAZBaseException("Error occurred merging custom lists for the paramgram parent: " + str(e))
- return paramgram
-
- @staticmethod
- def syslog(module, msg):
- try:
- module.log(msg=msg)
- except BaseException:
- pass
-
-
-# RECURSIVE FUNCTIONS START
-def prepare_dict(obj):
- """
- Removes any keys from a dictionary that are only specific to our use in the module. FortiAnalyzer will reject
- requests with these empty/None keys in it.
-
- :param obj: Dictionary object to be processed.
- :type obj: dict
-
- :return: Processed dictionary.
- :rtype: dict
- """
-
- list_of_elems = ["mode", "adom", "host", "username", "password"]
-
- if isinstance(obj, dict):
- obj = dict((key, prepare_dict(value)) for (key, value) in obj.items() if key not in list_of_elems)
- return obj
-
-
-def scrub_dict(obj):
- """
- Removes any keys from a dictionary that are EMPTY -- this includes parent keys. FortiAnalyzer doesn't
- like empty keys in dictionaries
-
- :param obj: Dictionary object to be processed.
- :type obj: dict
-
- :return: Processed dictionary.
- :rtype: dict
- """
-
- if isinstance(obj, dict):
- return dict((k, scrub_dict(v)) for k, v in obj.items() if v and scrub_dict(v))
- else:
- return obj
diff --git a/ansible_collections/community/fortios/plugins/module_utils/fortianalyzer/fortianalyzer.py b/ansible_collections/community/fortios/plugins/module_utils/fortianalyzer/fortianalyzer.py
deleted file mode 100644
index 74e85e30c..000000000
--- a/ansible_collections/community/fortios/plugins/module_utils/fortianalyzer/fortianalyzer.py
+++ /dev/null
@@ -1,476 +0,0 @@
-# This code is part of Ansible, but is an independent component.
-# This particular file snippet, and this file snippet only, is BSD licensed.
-# Modules you write using this snippet, which is embedded dynamically by Ansible
-# still belong to the author of the module, and may assign their own license
-# to the complete work.
-#
-# (c) 2017 Fortinet, Inc
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without modification,
-# are permitted provided that the following conditions are met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-from ansible_collections.community.fortios.plugins.module_utils.fortianalyzer.common import FAZ_RC
-from ansible_collections.community.fortios.plugins.module_utils.fortianalyzer.common import FAZBaseException
-from ansible_collections.community.fortios.plugins.module_utils.fortianalyzer.common import FAZCommon
-from ansible_collections.community.fortios.plugins.module_utils.fortianalyzer.common import scrub_dict
-from ansible_collections.community.fortios.plugins.module_utils.fortianalyzer.common import FAZMethods
-
-
-# ACTIVE BUG WITH OUR DEBUG IMPORT CALL - BECAUSE IT'S UNDER MODULE_UTILITIES
-# WHEN module_common.recursive_finder() runs under the module loader, it looks for this namespace debug import
-# and because it's not there, it always fails, regardless of it being under a try/catch here.
-# we're going to move it to a different namespace.
-# # check for debug lib
-# try:
-# from ansible.module_utils.fortianalyzer.fortianalyzer_debug import debug_dump
-# HAS_FAZ_DEBUG = True
-# except:
-# HAS_FAZ_DEBUG = False
-
-
-# BEGIN HANDLER CLASSES
-class FortiAnalyzerHandler(object):
- def __init__(self, conn, module):
- self._conn = conn
- self._module = module
- self._tools = FAZCommon
- self._uses_workspace = None
- self._uses_adoms = None
- self._locked_adom_list = list()
- self._lock_info = None
-
- self.workspace_check()
- if self._uses_workspace:
- self.get_lock_info(adom=self._module.paramgram["adom"])
-
- def process_request(self, url, datagram, method):
- """
- Formats and Runs the API Request via Connection Plugin. Streamlined for use from Modules.
-
- :param url: Connection URL to access
- :type url: string
- :param datagram: The prepared payload for the API Request in dictionary format
- :type datagram: dict
- :param method: The preferred API Request method (GET, ADD, POST, etc....)
- :type method: basestring
-
- :return: Dictionary containing results of the API Request via Connection Plugin.
- :rtype: dict
- """
- try:
- adom = self._module.paramgram["adom"]
- if self.uses_workspace and adom not in self._locked_adom_list and method != FAZMethods.GET:
- self.lock_adom(adom=adom)
- except BaseException as err:
- raise FAZBaseException(err)
-
- data = self._tools.format_request(method, url, **datagram)
- response = self._conn.send_request(method, data)
-
- try:
- adom = self._module.paramgram["adom"]
- if self.uses_workspace and adom in self._locked_adom_list \
- and response[0] == 0 and method != FAZMethods.GET:
- self.commit_changes(adom=adom)
- except BaseException as err:
- raise FAZBaseException(err)
-
- # if HAS_FAZ_DEBUG:
- # try:
- # debug_dump(response, datagram, self._module.paramgram, url, method)
- # except BaseException:
- # pass
-
- return response
-
- def workspace_check(self):
- """
- Checks FortiAnalyzer for the use of Workspace mode.
- """
- url = "/cli/global/system/global"
- data = {"fields": ["workspace-mode", "adom-status"]}
- resp_obj = self.process_request(url, data, FAZMethods.GET)
- try:
- if resp_obj[1]["workspace-mode"] in ["workflow", "normal"]:
- self.uses_workspace = True
- elif resp_obj[1]["workspace-mode"] == "disabled":
- self.uses_workspace = False
- except KeyError:
- self.uses_workspace = False
- except BaseException as err:
- raise FAZBaseException(msg="Couldn't determine workspace-mode in the plugin. Error: " + str(err))
- try:
- if resp_obj[1]["adom-status"] in [1, "enable"]:
- self.uses_adoms = True
- else:
- self.uses_adoms = False
- except KeyError:
- self.uses_adoms = False
- except BaseException as err:
- raise FAZBaseException(msg="Couldn't determine adom-status in the plugin. Error: " + str(err))
-
- def run_unlock(self):
- """
- Checks for ADOM status, if locked, it will unlock
- """
- for adom_locked in self._locked_adom_list:
- self.unlock_adom(adom_locked)
-
- def lock_adom(self, adom=None):
- """
- Locks an ADOM for changes
- """
- if not adom or adom == "root":
- url = "/dvmdb/adom/root/workspace/lock"
- else:
- if adom.lower() == "global":
- url = "/dvmdb/global/workspace/lock/"
- else:
- url = "/dvmdb/adom/{adom}/workspace/lock/".format(adom=adom)
- datagram = {}
- data = self._tools.format_request(FAZMethods.EXEC, url, **datagram)
- resp_obj = self._conn.send_request(FAZMethods.EXEC, data)
- code = resp_obj[0]
- if code == 0 and resp_obj[1]["status"]["message"].lower() == "ok":
- self.add_adom_to_lock_list(adom)
- else:
- lockinfo = self.get_lock_info(adom=adom)
- self._module.fail_json(msg=("An error occurred trying to lock the adom. Error: "
- + str(resp_obj) + ", LOCK INFO: " + str(lockinfo)))
- return resp_obj
-
- def unlock_adom(self, adom=None):
- """
- Unlocks an ADOM after changes
- """
- if not adom or adom == "root":
- url = "/dvmdb/adom/root/workspace/unlock"
- else:
- if adom.lower() == "global":
- url = "/dvmdb/global/workspace/unlock/"
- else:
- url = "/dvmdb/adom/{adom}/workspace/unlock/".format(adom=adom)
- datagram = {}
- data = self._tools.format_request(FAZMethods.EXEC, url, **datagram)
- resp_obj = self._conn.send_request(FAZMethods.EXEC, data)
- code = resp_obj[0]
- if code == 0 and resp_obj[1]["status"]["message"].lower() == "ok":
- self.remove_adom_from_lock_list(adom)
- else:
- self._module.fail_json(msg=("An error occurred trying to unlock the adom. Error: " + str(resp_obj)))
- return resp_obj
-
- def get_lock_info(self, adom=None):
- """
- Gets ADOM lock info so it can be displayed with the error messages. Or if determined to be locked by ansible
- for some reason, then unlock it.
- """
- if not adom or adom == "root":
- url = "/dvmdb/adom/root/workspace/lockinfo"
- else:
- if adom.lower() == "global":
- url = "/dvmdb/global/workspace/lockinfo/"
- else:
- url = "/dvmdb/adom/{adom}/workspace/lockinfo/".format(adom=adom)
- datagram = {}
- data = self._tools.format_request(FAZMethods.GET, url, **datagram)
- resp_obj = self._conn.send_request(FAZMethods.GET, data)
- code = resp_obj[0]
- if code != 0:
- self._module.fail_json(msg=("An error occurred trying to get the ADOM Lock Info. Error: " + str(resp_obj)))
- elif code == 0:
- self._lock_info = resp_obj[1]
- return resp_obj
-
- def commit_changes(self, adom=None, aux=False):
- """
- Commits changes to an ADOM
- """
- if not adom or adom == "root":
- url = "/dvmdb/adom/root/workspace/commit"
- else:
- if aux:
- url = "/pm/config/adom/{adom}/workspace/commit".format(adom=adom)
- else:
- if adom.lower() == "global":
- url = "/dvmdb/global/workspace/commit/"
- else:
- url = "/dvmdb/adom/{adom}/workspace/commit".format(adom=adom)
- datagram = {}
- data = self._tools.format_request(FAZMethods.EXEC, url, **datagram)
- resp_obj = self._conn.send_request(FAZMethods.EXEC, data)
- code = resp_obj[0]
- if code != 0:
- self._module.fail_json(msg=("An error occurred trying to commit changes to the adom. Error: "
- + str(resp_obj)))
-
- def govern_response(self, module, results, msg=None, good_codes=None,
- stop_on_fail=None, stop_on_success=None, skipped=None,
- changed=None, unreachable=None, failed=None, success=None, changed_if_success=None,
- ansible_facts=None):
- """
- This function will attempt to apply default values to canned responses from FortiAnalyzer we know of.
- This saves time, and turns the response in the module into a "one-liner", while still giving us...
- the flexibility to directly use return_response in modules if we have too. This function saves repeated code.
-
- :param module: The Ansible Module CLASS object, used to run fail/exit json
- :type module: object
- :param msg: An overridable custom message from the module that called this.
- :type msg: string
- :param results: A dictionary object containing an API call results
- :type results: dict
- :param good_codes: A list of exit codes considered successful from FortiAnalyzer
- :type good_codes: list
- :param stop_on_fail: If true, stops playbook run when return code is NOT IN good codes (default: true)
- :type stop_on_fail: boolean
- :param stop_on_success: If true, stops playbook run when return code is IN good codes (default: false)
- :type stop_on_success: boolean
- :param changed: If True, tells Ansible that object was changed (default: false)
- :type skipped: boolean
- :param skipped: If True, tells Ansible that object was skipped (default: false)
- :type skipped: boolean
- :param unreachable: If True, tells Ansible that object was unreachable (default: false)
- :type unreachable: boolean
- :param failed: If True, tells Ansible that execution was a failure. Overrides good_codes. (default: false)
- :type unreachable: boolean
- :param success: If True, tells Ansible that execution was a success. Overrides good_codes. (default: false)
- :type unreachable: boolean
- :param changed_if_success: If True, defaults to changed if successful if you specify or not"
- :type changed_if_success: boolean
- :param ansible_facts: A prepared dictionary of ansible facts from the execution.
- :type ansible_facts: dict
- """
- if module is None and results is None:
- raise FAZBaseException("govern_response() was called without a module and/or results tuple! Fix!")
- # Get the Return code from results
- try:
- rc = results[0]
- except BaseException:
- raise FAZBaseException("govern_response() was called without the return code at results[0]")
-
- # init a few items
- rc_data = None
-
- # Get the default values for the said return code.
- try:
- rc_codes = FAZ_RC.get('faz_return_codes')
- rc_data = rc_codes.get(rc)
- except BaseException:
- pass
-
- if not rc_data:
- rc_data = {}
- # ONLY add to overrides if not none -- This is very important that the keys aren't added at this stage
- # if they are empty. And there aren't that many, so let's just do a few if then statements.
- if good_codes is not None:
- rc_data["good_codes"] = good_codes
- if stop_on_fail is not None:
- rc_data["stop_on_fail"] = stop_on_fail
- if stop_on_success is not None:
- rc_data["stop_on_success"] = stop_on_success
- if skipped is not None:
- rc_data["skipped"] = skipped
- if changed is not None:
- rc_data["changed"] = changed
- if unreachable is not None:
- rc_data["unreachable"] = unreachable
- if failed is not None:
- rc_data["failed"] = failed
- if success is not None:
- rc_data["success"] = success
- if changed_if_success is not None:
- rc_data["changed_if_success"] = changed_if_success
- if results is not None:
- rc_data["results"] = results
- if msg is not None:
- rc_data["msg"] = msg
- if ansible_facts is None:
- rc_data["ansible_facts"] = {}
- else:
- rc_data["ansible_facts"] = ansible_facts
-
- return self.return_response(module=module,
- results=results,
- msg=rc_data.get("msg", "NULL"),
- good_codes=rc_data.get("good_codes", (0,)),
- stop_on_fail=rc_data.get("stop_on_fail", True),
- stop_on_success=rc_data.get("stop_on_success", False),
- skipped=rc_data.get("skipped", False),
- changed=rc_data.get("changed", False),
- changed_if_success=rc_data.get("changed_if_success", False),
- unreachable=rc_data.get("unreachable", False),
- failed=rc_data.get("failed", False),
- success=rc_data.get("success", False),
- ansible_facts=rc_data.get("ansible_facts", dict()))
-
- def return_response(self, module, results, msg="NULL", good_codes=(0,),
- stop_on_fail=True, stop_on_success=False, skipped=False,
- changed=False, unreachable=False, failed=False, success=False, changed_if_success=True,
- ansible_facts=()):
- """
- This function controls the logout and error reporting after an method or function runs. The exit_json for
- ansible comes from logic within this function. If this function returns just the msg, it means to continue
- execution on the playbook. It is called from the ansible module, or from the self.govern_response function.
-
- :param module: The Ansible Module CLASS object, used to run fail/exit json
- :type module: object
- :param msg: An overridable custom message from the module that called this.
- :type msg: string
- :param results: A dictionary object containing an API call results
- :type results: dict
- :param good_codes: A list of exit codes considered successful from FortiAnalyzer
- :type good_codes: list
- :param stop_on_fail: If true, stops playbook run when return code is NOT IN good codes (default: true)
- :type stop_on_fail: boolean
- :param stop_on_success: If true, stops playbook run when return code is IN good codes (default: false)
- :type stop_on_success: boolean
- :param changed: If True, tells Ansible that object was changed (default: false)
- :type skipped: boolean
- :param skipped: If True, tells Ansible that object was skipped (default: false)
- :type skipped: boolean
- :param unreachable: If True, tells Ansible that object was unreachable (default: false)
- :type unreachable: boolean
- :param failed: If True, tells Ansible that execution was a failure. Overrides good_codes. (default: false)
- :type unreachable: boolean
- :param success: If True, tells Ansible that execution was a success. Overrides good_codes. (default: false)
- :type unreachable: boolean
- :param changed_if_success: If True, defaults to changed if successful if you specify or not"
- :type changed_if_success: boolean
- :param ansible_facts: A prepared dictionary of ansible facts from the execution.
- :type ansible_facts: dict
-
- :return: A string object that contains an error message
- :rtype: str
- """
-
- # VALIDATION ERROR
- if (len(results) == 0) or (failed and success) or (changed and unreachable):
- module.exit_json(msg="Handle_response was called with no results, or conflicting failed/success or "
- "changed/unreachable parameters. Fix the exit code on module. "
- "Generic Failure", failed=True)
-
- # IDENTIFY SUCCESS/FAIL IF NOT DEFINED
- if not failed and not success:
- if len(results) > 0:
- if results[0] not in good_codes:
- failed = True
- elif results[0] in good_codes:
- success = True
-
- if len(results) > 0:
- # IF NO MESSAGE WAS SUPPLIED, GET IT FROM THE RESULTS, IF THAT DOESN'T WORK, THEN WRITE AN ERROR MESSAGE
- if msg == "NULL":
- try:
- msg = results[1]['status']['message']
- except BaseException:
- msg = "No status message returned at results[1][status][message], " \
- "and none supplied to msg parameter for handle_response."
-
- if failed:
- # BECAUSE SKIPPED/FAILED WILL OFTEN OCCUR ON CODES THAT DON'T GET INCLUDED, THEY ARE CONSIDERED FAILURES
- # HOWEVER, THEY ARE MUTUALLY EXCLUSIVE, SO IF IT IS MARKED SKIPPED OR UNREACHABLE BY THE MODULE LOGIC
- # THEN REMOVE THE FAILED FLAG SO IT DOESN'T OVERRIDE THE DESIRED STATUS OF SKIPPED OR UNREACHABLE.
- if failed and skipped:
- failed = False
- if failed and unreachable:
- failed = False
- if stop_on_fail:
- if self._uses_workspace:
- try:
- self.run_unlock()
- except BaseException as err:
- raise FAZBaseException(msg=("Couldn't unlock ADOM! Error: " + str(err)))
- module.exit_json(msg=msg, failed=failed, changed=changed, unreachable=unreachable, skipped=skipped,
- results=results[1], ansible_facts=ansible_facts, rc=results[0],
- invocation={"module_args": ansible_facts["ansible_params"]})
- elif success:
- if changed_if_success:
- changed = True
- success = False
- if stop_on_success:
- if self._uses_workspace:
- try:
- self.run_unlock()
- except BaseException as err:
- raise FAZBaseException(msg=("Couldn't unlock ADOM! Error: " + str(err)))
- module.exit_json(msg=msg, success=success, changed=changed, unreachable=unreachable,
- skipped=skipped, results=results[1], ansible_facts=ansible_facts, rc=results[0],
- invocation={"module_args": ansible_facts["ansible_params"]})
- return msg
-
- @staticmethod
- def construct_ansible_facts(response, ansible_params, paramgram, *args, **kwargs):
- """
- Constructs a dictionary to return to ansible facts, containing various information about the execution.
-
- :param response: Contains the response from the FortiAnalyzer.
- :type response: dict
- :param ansible_params: Contains the parameters Ansible was called with.
- :type ansible_params: dict
- :param paramgram: Contains the paramgram passed to the modules' local modify function.
- :type paramgram: dict
- :param args: Free-form arguments that could be added.
- :param kwargs: Free-form keyword arguments that could be added.
-
- :return: A dictionary containing lots of information to append to Ansible Facts.
- :rtype: dict
- """
-
- facts = {
- "response": response,
- "ansible_params": scrub_dict(ansible_params),
- "paramgram": scrub_dict(paramgram),
- }
-
- if args:
- facts["custom_args"] = args
- if kwargs:
- facts.update(kwargs)
-
- return facts
-
- @property
- def uses_workspace(self):
- return self._uses_workspace
-
- @uses_workspace.setter
- def uses_workspace(self, val):
- self._uses_workspace = val
-
- @property
- def uses_adoms(self):
- return self._uses_adoms
-
- @uses_adoms.setter
- def uses_adoms(self, val):
- self._uses_adoms = val
-
- def add_adom_to_lock_list(self, adom):
- if adom not in self._locked_adom_list:
- self._locked_adom_list.append(adom)
-
- def remove_adom_from_lock_list(self, adom):
- if adom in self._locked_adom_list:
- self._locked_adom_list.remove(adom)
diff --git a/ansible_collections/community/fortios/plugins/modules/faz_device.py b/ansible_collections/community/fortios/plugins/modules/faz_device.py
deleted file mode 100644
index 07a695575..000000000
--- a/ansible_collections/community/fortios/plugins/modules/faz_device.py
+++ /dev/null
@@ -1,432 +0,0 @@
-#!/usr/bin/python
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-
-from __future__ import absolute_import, division, print_function
-
-__metaclass__ = type
-
-DOCUMENTATION = '''
----
-module: faz_device
-author: Luke Weighall (@lweighall)
-short_description: Add or remove device
-description:
- - Add or remove a device or list of devices to FortiAnalyzer Device Manager. ADOM Capable.
-
-options:
- adom:
- description:
- - The ADOM the configuration should belong to.
- required: true
- default: root
- type: str
-
- mode:
- description:
- - Add or delete devices. Or promote unregistered devices that are in the FortiAnalyzer "waiting pool"
- required: false
- default: add
- choices: ["add", "delete", "promote"]
- type: str
-
- device_username:
- description:
- - The username of the device being added to FortiAnalyzer.
- required: false
- type: str
-
- device_password:
- description:
- - The password of the device being added to FortiAnalyzer.
- required: false
- type: str
-
- device_ip:
- description:
- - The IP of the device being added to FortiAnalyzer.
- required: false
- type: str
-
- device_unique_name:
- description:
- - The desired "friendly" name of the device being added to FortiAnalyzer.
- required: false
- type: str
-
- device_serial:
- description:
- - The serial number of the device being added to FortiAnalyzer.
- required: false
- type: str
-
- os_type:
- description:
- - The os type of the device being added (default 0).
- required: true
- choices: ["unknown", "fos", "fsw", "foc", "fml", "faz", "fwb", "fch", "fct", "log", "fmg", "fsa", "fdd", "fac"]
- type: str
-
- mgmt_mode:
- description:
- - Management Mode of the device you are adding.
- choices: ["unreg", "fmg", "faz", "fmgfaz"]
- required: true
- type: str
-
- os_minor_vers:
- description:
- - Minor OS rev of the device.
- required: true
- type: str
-
- os_ver:
- description:
- - Major OS rev of the device
- required: true
- choices: ["unknown", "0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "6.0"]
- type: str
-
- platform_str:
- description:
- - Required for determine the platform for VM platforms. ie FortiGate-VM64
- required: false
- type: str
-
- faz_quota:
- description:
- - Specifies the quota for the device in FAZ
- required: False
- type: str
-'''
-
-EXAMPLES = '''
-- name: DISCOVER AND ADD DEVICE A PHYSICAL FORTIGATE
- community.fortios.faz_device:
- adom: "root"
- device_username: "admin"
- device_password: "admin"
- device_ip: "10.10.24.201"
- device_unique_name: "FGT1"
- device_serial: "FGVM000000117994"
- state: "present"
- mgmt_mode: "faz"
- os_type: "fos"
- os_ver: "5.0"
- minor_rev: 6
-
-
-- name: DISCOVER AND ADD DEVICE A VIRTUAL FORTIGATE
- community.fortios.faz_device:
- adom: "root"
- device_username: "admin"
- device_password: "admin"
- device_ip: "10.10.24.202"
- device_unique_name: "FGT2"
- mgmt_mode: "faz"
- os_type: "fos"
- os_ver: "5.0"
- minor_rev: 6
- state: "present"
- platform_str: "FortiGate-VM64"
-
-- name: DELETE DEVICE FGT01
- community.fortios.faz_device:
- adom: "root"
- device_unique_name: "ansible-fgt01"
- mode: "delete"
-
-- name: DELETE DEVICE FGT02
- community.fortios.faz_device:
- adom: "root"
- device_unique_name: "ansible-fgt02"
- mode: "delete"
-
-- name: PROMOTE FGT01 IN FAZ BY IP
- community.fortios.faz_device:
- adom: "root"
- device_password: "fortinet"
- device_ip: "10.7.220.151"
- device_username: "ansible"
- mgmt_mode: "faz"
- mode: "promote"
-
-
-- name: PROMOTE FGT02 IN FAZ
- community.fortios.faz_device:
- adom: "root"
- device_password: "fortinet"
- device_unique_name: "ansible-fgt02"
- device_username: "ansible"
- mgmt_mode: "faz"
- mode: "promote"
-
-'''
-
-RETURN = """
-api_result:
- description: full API response, includes status code and message
- returned: always
- type: str
-"""
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.connection import Connection
-from ansible_collections.community.fortios.plugins.module_utils.fortianalyzer.fortianalyzer import FortiAnalyzerHandler
-from ansible_collections.community.fortios.plugins.module_utils.fortianalyzer.common import FAZBaseException
-from ansible_collections.community.fortios.plugins.module_utils.fortianalyzer.common import FAZCommon
-from ansible_collections.community.fortios.plugins.module_utils.fortianalyzer.common import FAZMethods
-from ansible_collections.community.fortios.plugins.module_utils.fortianalyzer.common import DEFAULT_RESULT_OBJ
-from ansible_collections.community.fortios.plugins.module_utils.fortianalyzer.common import FAIL_SOCKET_MSG
-
-
-def faz_add_device(faz, paramgram):
- """
- This method is used to add devices to the faz or delete them
- """
-
- datagram = {
- "adom": paramgram["adom"],
- "device": {"adm_usr": paramgram["device_username"], "adm_pass": paramgram["device_password"],
- "ip": paramgram["ip"], "name": paramgram["device_unique_name"],
- "mgmt_mode": paramgram["mgmt_mode"], "os_type": paramgram["os_type"],
- "mr": paramgram["os_minor_vers"]}
- }
-
- if paramgram["platform_str"] is not None:
- datagram["device"]["platform_str"] = paramgram["platform_str"]
-
- if paramgram["sn"] is not None:
- datagram["device"]["sn"] = paramgram["sn"]
-
- if paramgram["device_action"] is not None:
- datagram["device"]["device_action"] = paramgram["device_action"]
-
- if paramgram["faz.quota"] is not None:
- datagram["device"]["faz.quota"] = paramgram["faz.quota"]
-
- url = '/dvm/cmd/add/device/'
- response = faz.process_request(url, datagram, FAZMethods.EXEC)
- return response
-
-
-def faz_delete_device(faz, paramgram):
- """
- This method deletes a device from the FAZ
- """
- datagram = {
- "adom": paramgram["adom"],
- "device": paramgram["device_unique_name"],
- }
-
- url = '/dvm/cmd/del/device/'
- response = faz.process_request(url, datagram, FAZMethods.EXEC)
- return response
-
-
-def faz_get_unknown_devices(faz):
- """
- This method gets devices with an unknown management type field
- """
-
- faz_filter = ["mgmt_mode", "==", "0"]
-
- datagram = {
- "filter": faz_filter
- }
-
- url = "/dvmdb/device"
- response = faz.process_request(url, datagram, FAZMethods.GET)
-
- return response
-
-
-def faz_approve_unregistered_device_by_ip(faz, paramgram):
- """
- This method approves unregistered devices by ip.
- """
- # TRY TO FIND DETAILS ON THIS UNREGISTERED DEVICE
- unknown_devices = faz_get_unknown_devices(faz)
- target_device = None
- if unknown_devices[0] == 0:
- for device in unknown_devices[1]:
- if device["ip"] == paramgram["ip"]:
- target_device = device
- else:
- return "No devices are waiting to be registered!"
-
- # now that we have the target device details...fill out the datagram and make the call to promote it
- if target_device is not None:
- target_device_paramgram = {
- "adom": paramgram["adom"],
- "ip": target_device["ip"],
- "device_username": paramgram["device_username"],
- "device_password": paramgram["device_password"],
- "device_unique_name": paramgram["device_unique_name"],
- "sn": target_device["sn"],
- "os_type": target_device["os_type"],
- "mgmt_mode": paramgram["mgmt_mode"],
- "os_minor_vers": target_device["mr"],
- "os_ver": target_device["os_ver"],
- "platform_str": target_device["platform_str"],
- "faz.quota": target_device["faz.quota"],
- "device_action": paramgram["device_action"]
- }
-
- add_device = faz_add_device(faz, target_device_paramgram)
- return add_device
-
- return str("Couldn't find the desired device with ip: " + str(paramgram["device_ip"]))
-
-
-def faz_approve_unregistered_device_by_name(faz, paramgram):
- # TRY TO FIND DETAILS ON THIS UNREGISTERED DEVICE
- unknown_devices = faz_get_unknown_devices(faz)
- target_device = None
- if unknown_devices[0] == 0:
- for device in unknown_devices[1]:
- if device["name"] == paramgram["device_unique_name"]:
- target_device = device
- else:
- return "No devices are waiting to be registered!"
-
- # now that we have the target device details...fill out the datagram and make the call to promote it
- if target_device is not None:
- target_device_paramgram = {
- "adom": paramgram["adom"],
- "ip": target_device["ip"],
- "device_username": paramgram["device_username"],
- "device_password": paramgram["device_password"],
- "device_unique_name": paramgram["device_unique_name"],
- "sn": target_device["sn"],
- "os_type": target_device["os_type"],
- "mgmt_mode": paramgram["mgmt_mode"],
- "os_minor_vers": target_device["mr"],
- "os_ver": target_device["os_ver"],
- "platform_str": target_device["platform_str"],
- "faz.quota": target_device["faz.quota"],
- "device_action": paramgram["device_action"]
- }
-
- add_device = faz_add_device(faz, target_device_paramgram)
- return add_device
-
- return str("Couldn't find the desired device with name: " + str(paramgram["device_unique_name"]))
-
-
-def main():
- argument_spec = dict(
- adom=dict(required=False, type="str", default="root"),
- mode=dict(choices=["add", "delete", "promote"], type="str", default="add"),
-
- device_ip=dict(required=False, type="str"),
- device_username=dict(required=False, type="str"),
- device_password=dict(required=False, type="str", no_log=True),
- device_unique_name=dict(required=False, type="str"),
- device_serial=dict(required=False, type="str"),
-
- os_type=dict(required=False, type="str", choices=["unknown", "fos", "fsw", "foc", "fml",
- "faz", "fwb", "fch", "fct", "log", "fmg",
- "fsa", "fdd", "fac"]),
- mgmt_mode=dict(required=False, type="str", choices=["unreg", "fmg", "faz", "fmgfaz"]),
- os_minor_vers=dict(required=False, type="str"),
- os_ver=dict(required=False, type="str", choices=["unknown", "0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "6.0"]),
- platform_str=dict(required=False, type="str"),
- faz_quota=dict(required=False, type="str")
- )
-
- required_if = [
- ['mode', 'delete', ['device_unique_name']],
- ['mode', 'add', ['device_serial', 'device_username',
- 'device_password', 'device_unique_name', 'device_ip', 'mgmt_mode', 'platform_str']]
-
- ]
-
- module = AnsibleModule(argument_spec, supports_check_mode=True, required_if=required_if, )
-
- # START SESSION LOGIC
- paramgram = {
- "adom": module.params["adom"],
- "mode": module.params["mode"],
- "ip": module.params["device_ip"],
- "device_username": module.params["device_username"],
- "device_password": module.params["device_password"],
- "device_unique_name": module.params["device_unique_name"],
- "sn": module.params["device_serial"],
- "os_type": module.params["os_type"],
- "mgmt_mode": module.params["mgmt_mode"],
- "os_minor_vers": module.params["os_minor_vers"],
- "os_ver": module.params["os_ver"],
- "platform_str": module.params["platform_str"],
- "faz.quota": module.params["faz_quota"],
- "device_action": None
- }
- # INSERT THE PARAMGRAM INTO THE MODULE SO WHEN WE PASS IT TO MOD_UTILS.FortiManagerHandler IT HAS THAT INFO
-
- if paramgram["mode"] == "add":
- paramgram["device_action"] = "add_model"
- elif paramgram["mode"] == "promote":
- paramgram["device_action"] = "promote_unreg"
- module.paramgram = paramgram
-
- # TRY TO INIT THE CONNECTION SOCKET PATH AND FortiManagerHandler OBJECT AND TOOLS
- faz = None
- if module._socket_path:
- connection = Connection(module._socket_path)
- faz = FortiAnalyzerHandler(connection, module)
- faz.tools = FAZCommon()
- else:
- module.fail_json(**FAIL_SOCKET_MSG)
-
- # BEGIN MODULE-SPECIFIC LOGIC -- THINGS NEED TO HAPPEN DEPENDING ON THE ENDPOINT AND OPERATION
- results = DEFAULT_RESULT_OBJ
-
- try:
- if paramgram["mode"] == "add":
- results = faz_add_device(faz, paramgram)
- except BaseException as err:
- raise FAZBaseException(msg="An error occurred trying to add the device. Error: " + str(err))
-
- try:
- if paramgram["mode"] == "promote":
- if paramgram["ip"] is not None:
- results = faz_approve_unregistered_device_by_ip(faz, paramgram)
- elif paramgram["device_unique_name"] is not None:
- results = faz_approve_unregistered_device_by_name(faz, paramgram)
- except BaseException as err:
- raise FAZBaseException(msg="An error occurred trying to promote the device. Error: " + str(err))
-
- try:
- if paramgram["mode"] == "delete":
- results = faz_delete_device(faz, paramgram)
- except BaseException as err:
- raise FAZBaseException(msg="An error occurred trying to delete the device. Error: " + str(err))
-
- # PROCESS RESULTS
- try:
- faz.govern_response(module=module, results=results,
- ansible_facts=faz.construct_ansible_facts(results, module.params, paramgram))
- except BaseException as err:
- raise FAZBaseException(msg="An error occurred with govern_response(). Error: " + str(err))
-
- # This should only be hit if faz.govern_response is missed or failed somehow. In fact. It should never be hit.
- # But it's here JIC.
- return module.exit_json(**results[1])
-
-
-if __name__ == "__main__":
- main()
diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_device.py b/ansible_collections/community/fortios/plugins/modules/fmgr_device.py
deleted file mode 100644
index 8f0c6045f..000000000
--- a/ansible_collections/community/fortios/plugins/modules/fmgr_device.py
+++ /dev/null
@@ -1,296 +0,0 @@
-#!/usr/bin/python
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-
-from __future__ import absolute_import, division, print_function
-
-__metaclass__ = type
-
-DOCUMENTATION = '''
----
-module: fmgr_device
-notes:
- - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
-author:
- - Luke Weighall (@lweighall)
- - Andrew Welsh (@Ghilli3)
- - Jim Huber (@p4r4n0y1ng)
-short_description: Add or remove device from FortiManager.
-description:
- - Add or remove a device or list of devices from FortiManager Device Manager using JSON RPC API.
-
-options:
- adom:
- description:
- - The ADOM the configuration should belong to.
- required: true
- default: root
-
- mode:
- description:
- - The desired mode of the specified object.
- required: false
- default: add
- choices: ["add", "delete"]
-
- blind_add:
- description:
- - When adding a device, module will check if it exists, and skip if it does.
- - If enabled, this option will stop the module from checking if it already exists, and blindly add the device.
- required: false
- default: "disable"
- choices: ["enable", "disable"]
-
- device_username:
- description:
- - The username of the device being added to FortiManager.
- required: false
-
- device_password:
- description:
- - The password of the device being added to FortiManager.
- required: false
-
- device_ip:
- description:
- - The IP of the device being added to FortiManager. Supports both IPv4 and IPv6.
- required: false
-
- device_unique_name:
- description:
- - The desired "friendly" name of the device being added to FortiManager.
- required: false
-
- device_serial:
- description:
- - The serial number of the device being added to FortiManager.
- required: false
-'''
-
-EXAMPLES = '''
-- name: DISCOVER AND ADD DEVICE FGT1
- community.fortios.fmgr_device:
- adom: "root"
- device_username: "admin"
- device_password: "admin"
- device_ip: "10.10.24.201"
- device_unique_name: "FGT1"
- device_serial: "FGVM000000117994"
- mode: "add"
- blind_add: "enable"
-
-- name: DISCOVER AND ADD DEVICE FGT2
- community.fortios.fmgr_device:
- adom: "root"
- device_username: "admin"
- device_password: "admin"
- device_ip: "10.10.24.202"
- device_unique_name: "FGT2"
- device_serial: "FGVM000000117992"
- mode: "delete"
-'''
-
-RETURN = """
-api_result:
- description: full API response, includes status code and message
- returned: always
- type: str
-"""
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.connection import Connection
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRMethods
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG
-
-
-def discover_device(fmgr, paramgram):
- """
- This method is used to discover devices before adding them to FMGR
-
- :param fmgr: The fmgr object instance from fmgr_utils.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
-
- :return: The response from the FortiManager
- :rtype: dict
- """
-
- datagram = {
- "odd_request_form": "True",
- "device": {"adm_usr": paramgram["device_username"],
- "adm_pass": paramgram["device_password"],
- "ip": paramgram["device_ip"]}
- }
-
- url = '/dvm/cmd/discover/device/'
-
- response = fmgr.process_request(url, datagram, FMGRMethods.EXEC)
- return response
-
-
-def add_device(fmgr, paramgram):
- """
- This method is used to add devices to the FMGR
-
- :param fmgr: The fmgr object instance from fmgr_utils.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
-
- :return: The response from the FortiManager
- :rtype: dict
- """
-
- datagram = {
- "adom": paramgram["adom"],
- "flags": ["create_task", "nonblocking"],
- "odd_request_form": "True",
- "device": {"adm_usr": paramgram["device_username"], "adm_pass": paramgram["device_password"],
- "ip": paramgram["device_ip"], "name": paramgram["device_unique_name"],
- "sn": paramgram["device_serial"], "mgmt_mode": "fmgfaz", "flags": 24}
- }
-
- url = '/dvm/cmd/add/device/'
- response = fmgr.process_request(url, datagram, FMGRMethods.EXEC)
- return response
-
-
-def delete_device(fmgr, paramgram):
- """
- This method deletes a device from the FMGR
-
- :param fmgr: The fmgr object instance from fmgr_utils.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
-
- :return: The response from the FortiManager
- :rtype: dict
- """
- datagram = {
- "adom": paramgram["adom"],
- "flags": ["create_task", "nonblocking"],
- "device": paramgram["device_unique_name"],
- }
-
- url = '/dvm/cmd/del/device/'
- response = fmgr.process_request(url, datagram, FMGRMethods.EXEC)
- return response
-
-
-def get_device(fmgr, paramgram):
- """
- This method attempts to find the firewall on FortiManager to see if it already exists.
-
- :param fmgr: The fmgr object instance from fmgr_utils.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
-
- :return: The response from the FortiManager
- :rtype: dict
- """
- datagram = {
- "adom": paramgram["adom"],
- "filter": ["name", "==", paramgram["device_unique_name"]],
- }
-
- url = '/dvmdb/adom/{adom}/device/{name}'.format(adom=paramgram["adom"],
- name=paramgram["device_unique_name"])
- response = fmgr.process_request(url, datagram, FMGRMethods.GET)
- return response
-
-
-def main():
- argument_spec = dict(
- adom=dict(required=False, type="str", default="root"),
- mode=dict(choices=["add", "delete"], type="str", default="add"),
- blind_add=dict(choices=["enable", "disable"], type="str", default="disable"),
- device_ip=dict(required=False, type="str"),
- device_username=dict(required=False, type="str"),
- device_password=dict(required=False, type="str", no_log=True),
- device_unique_name=dict(required=True, type="str"),
- device_serial=dict(required=False, type="str")
- )
-
- # BUILD MODULE OBJECT SO WE CAN BUILD THE PARAMGRAM
- module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
-
- # BUILD THE PARAMGRAM
- paramgram = {
- "device_ip": module.params["device_ip"],
- "device_username": module.params["device_username"],
- "device_password": module.params["device_password"],
- "device_unique_name": module.params["device_unique_name"],
- "device_serial": module.params["device_serial"],
- "adom": module.params["adom"],
- "mode": module.params["mode"]
- }
-
- # INSERT THE PARAMGRAM INTO THE MODULE SO WHEN WE PASS IT TO MOD_UTILS.FortiManagerHandler IT HAS THAT INFO
- module.paramgram = paramgram
-
- # TRY TO INIT THE CONNECTION SOCKET PATH AND FortiManagerHandler OBJECT AND TOOLS
- fmgr = None
- if module._socket_path:
- connection = Connection(module._socket_path)
- fmgr = FortiManagerHandler(connection, module)
- fmgr.tools = FMGRCommon()
- else:
- module.fail_json(**FAIL_SOCKET_MSG)
-
- # BEGIN MODULE-SPECIFIC LOGIC -- THINGS NEED TO HAPPEN DEPENDING ON THE ENDPOINT AND OPERATION
- results = DEFAULT_RESULT_OBJ
- try:
- if paramgram["mode"] == "add":
- # CHECK IF DEVICE EXISTS
- if module.params["blind_add"] == "disable":
- exists_results = get_device(fmgr, paramgram)
- fmgr.govern_response(module=module, results=exists_results, good_codes=(0, -3), changed=False,
- ansible_facts=fmgr.construct_ansible_facts(exists_results,
- module.params, paramgram))
-
- discover_results = discover_device(fmgr, paramgram)
- fmgr.govern_response(module=module, results=discover_results, stop_on_success=False,
- ansible_facts=fmgr.construct_ansible_facts(discover_results,
- module.params, paramgram))
-
- if discover_results[0] == 0:
- results = add_device(fmgr, paramgram)
- fmgr.govern_response(module=module, results=discover_results, stop_on_success=True,
- changed_if_success=True,
- ansible_facts=fmgr.construct_ansible_facts(discover_results,
- module.params, paramgram))
-
- if paramgram["mode"] == "delete":
- results = delete_device(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
-
- except Exception as err:
- raise FMGBaseException(err)
-
- return module.exit_json(**results[1])
-
-
-if __name__ == "__main__":
- main()
diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_device_config.py b/ansible_collections/community/fortios/plugins/modules/fmgr_device_config.py
deleted file mode 100644
index e36dad95f..000000000
--- a/ansible_collections/community/fortios/plugins/modules/fmgr_device_config.py
+++ /dev/null
@@ -1,231 +0,0 @@
-#!/usr/bin/python
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-DOCUMENTATION = '''
----
-module: fmgr_device_config
-notes:
- - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
-author:
- - Luke Weighall (@lweighall)
- - Andrew Welsh (@Ghilli3)
- - Jim Huber (@p4r4n0y1ng)
-short_description: Edit device configurations
-description:
- - Edit device configurations from FortiManager Device Manager using JSON RPC API.
-
-options:
- adom:
- description:
- - The ADOM the configuration should belong to.
- required: false
- default: root
-
- device_unique_name:
- description:
- - The unique device's name that you are editing. A.K.A. Friendly name of the device in FortiManager.
- required: True
-
- device_hostname:
- description:
- - The device's new hostname.
- required: false
-
- install_config:
- description:
- - Tells FMGR to attempt to install the config after making it.
- required: false
- default: disable
-
- interface:
- description:
- - The interface/port number you are editing.
- required: false
-
- interface_ip:
- description:
- - The IP and subnet of the interface/port you are editing.
- required: false
-
- interface_allow_access:
- description:
- - Specify what protocols are allowed on the interface, comma-separated list (see examples).
- required: false
-'''
-
-EXAMPLES = '''
-- name: CHANGE HOSTNAME
- community.fortios.fmgr_device_config:
- device_hostname: "ChangedbyAnsible"
- device_unique_name: "FGT1"
-
-- name: EDIT INTERFACE INFORMATION
- community.fortios.fmgr_device_config:
- adom: "root"
- device_unique_name: "FGT2"
- interface: "port3"
- interface_ip: "10.1.1.1/24"
- interface_allow_access: "ping, telnet, https"
-
-- name: INSTALL CONFIG
- community.fortios.fmgr_device_config:
- adom: "root"
- device_unique_name: "FGT1"
- install_config: "enable"
-'''
-
-RETURN = """
-api_result:
- description: full API response, includes status code and message
- returned: always
- type: str
-"""
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.connection import Connection
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRMethods
-
-
-def update_device_hostname(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
- datagram = {
- "hostname": paramgram["device_hostname"]
- }
-
- url = "pm/config/device/{device_name}/global/system/global".format(device_name=paramgram["device_unique_name"])
- response = fmgr.process_request(url, datagram, FMGRMethods.UPDATE)
- return response
-
-
-def update_device_interface(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
- access_list = list()
- allow_access_list = paramgram["interface_allow_access"].replace(' ', '')
- access_list = allow_access_list.split(',')
-
- datagram = {
- "allowaccess": access_list,
- "ip": paramgram["interface_ip"]
- }
-
- url = "/pm/config/device/{device_name}/global/system/interface" \
- "/{interface}".format(device_name=paramgram["device_unique_name"], interface=paramgram["interface"])
- response = fmgr.process_request(url, datagram, FMGRMethods.UPDATE)
- return response
-
-
-def exec_config(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
- datagram = {
- "scope": {
- "name": paramgram["device_unique_name"]
- },
- "adom": paramgram["adom"],
- "flags": "none"
- }
-
- url = "/securityconsole/install/device"
- response = fmgr.process_request(url, datagram, FMGRMethods.EXEC)
- return response
-
-
-def main():
- argument_spec = dict(
- adom=dict(required=False, type="str", default="root"),
- device_unique_name=dict(required=True, type="str"),
- device_hostname=dict(required=False, type="str"),
- interface=dict(required=False, type="str"),
- interface_ip=dict(required=False, type="str"),
- interface_allow_access=dict(required=False, type="str"),
- install_config=dict(required=False, type="str", default="disable"),
- )
-
- module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
- paramgram = {
- "device_unique_name": module.params["device_unique_name"],
- "device_hostname": module.params["device_hostname"],
- "interface": module.params["interface"],
- "interface_ip": module.params["interface_ip"],
- "interface_allow_access": module.params["interface_allow_access"],
- "install_config": module.params["install_config"],
- "adom": module.params["adom"]
- }
- module.paramgram = paramgram
- fmgr = None
- if module._socket_path:
- connection = Connection(module._socket_path)
- fmgr = FortiManagerHandler(connection, module)
- fmgr.tools = FMGRCommon()
- else:
- module.fail_json(**FAIL_SOCKET_MSG)
-
- # BEGIN MODULE-SPECIFIC LOGIC -- THINGS NEED TO HAPPEN DEPENDING ON THE ENDPOINT AND OPERATION
- results = DEFAULT_RESULT_OBJ
- try:
- if paramgram["device_hostname"] is not None:
- results = update_device_hostname(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
-
- if paramgram["interface_ip"] is not None or paramgram["interface_allow_access"] is not None:
- results = update_device_interface(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
-
- if paramgram["install_config"] == "enable":
- results = exec_config(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
-
- except Exception as err:
- raise FMGBaseException(err)
-
- return module.exit_json(**results[1])
-
-
-if __name__ == "__main__":
- main()
diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_device_group.py b/ansible_collections/community/fortios/plugins/modules/fmgr_device_group.py
deleted file mode 100644
index 9c8c0ad60..000000000
--- a/ansible_collections/community/fortios/plugins/modules/fmgr_device_group.py
+++ /dev/null
@@ -1,323 +0,0 @@
-#!/usr/bin/python
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-DOCUMENTATION = '''
----
-module: fmgr_device_group
-notes:
- - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
-author:
- - Luke Weighall (@lweighall)
- - Andrew Welsh (@Ghilli3)
- - Jim Huber (@p4r4n0y1ng)
-short_description: Alter FortiManager device groups.
-description:
- - Add or edit device groups and assign devices to device groups FortiManager Device Manager using JSON RPC API.
-
-options:
- adom:
- description:
- - The ADOM the configuration should belong to.
- required: false
- default: root
-
- vdom:
- description:
- - The VDOM of the Fortigate you want to add, must match the device in FMGR. Usually root.
- required: false
- default: root
-
- mode:
- description:
- - Sets one of three modes for managing the object.
- - Allows use of soft-adds instead of overwriting existing values
- choices: ['add', 'set', 'delete', 'update']
- required: false
- default: add
-
- grp_name:
- description:
- - The name of the device group.
- required: false
-
- grp_desc:
- description:
- - The description of the device group.
- required: false
-
- grp_members:
- description:
- - A comma separated list of device names or device groups to be added as members to the device group.
- - If Group Members are defined, and mode="delete", only group members will be removed.
- - If you want to delete a group itself, you must omit this parameter from the task in playbook.
- required: false
-
-'''
-
-
-EXAMPLES = '''
-- name: CREATE DEVICE GROUP
- community.fortios.fmgr_device_group:
- grp_name: "TestGroup"
- grp_desc: "CreatedbyAnsible"
- adom: "ansible"
- mode: "add"
-
-- name: CREATE DEVICE GROUP 2
- community.fortios.fmgr_device_group:
- grp_name: "AnsibleGroup"
- grp_desc: "CreatedbyAnsible"
- adom: "ansible"
- mode: "add"
-
-- name: ADD DEVICES TO DEVICE GROUP
- community.fortios.fmgr_device_group:
- mode: "add"
- grp_name: "TestGroup"
- grp_members: "FGT1,FGT2"
- adom: "ansible"
- vdom: "root"
-
-- name: REMOVE DEVICES TO DEVICE GROUP
- community.fortios.fmgr_device_group:
- mode: "delete"
- grp_name: "TestGroup"
- grp_members: "FGT1,FGT2"
- adom: "ansible"
-
-- name: DELETE DEVICE GROUP
- community.fortios.fmgr_device_group:
- grp_name: "AnsibleGroup"
- grp_desc: "CreatedbyAnsible"
- mode: "delete"
- adom: "ansible"
-'''
-
-RETURN = """
-api_result:
- description: full API response, includes status code and message
- returned: always
- type: str
-"""
-
-from ansible.module_utils.basic import AnsibleModule, env_fallback
-from ansible.module_utils.connection import Connection
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRMethods
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG
-
-
-def get_groups(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
-
- datagram = {
- "method": "get"
- }
-
- url = '/dvmdb/adom/{adom}/group'.format(adom=paramgram["adom"])
- response = fmgr.process_request(url, datagram, FMGRMethods.GET)
- return response
-
-
-def add_device_group(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
- # INIT A BASIC OBJECTS
- response = DEFAULT_RESULT_OBJ
- url = ""
- mode = paramgram["mode"]
-
- datagram = {
- "name": paramgram["grp_name"],
- "desc": paramgram["grp_desc"],
- "os_type": "fos"
- }
-
- url = '/dvmdb/adom/{adom}/group'.format(adom=paramgram["adom"])
-
- # IF MODE = SET -- USE THE 'SET' API CALL MODE
- if mode == "set":
- response = fmgr.process_request(url, datagram, FMGRMethods.SET)
- # IF MODE = UPDATE -- USER THE 'UPDATE' API CALL MODE
- elif mode == "update":
- response = fmgr.process_request(url, datagram, FMGRMethods.UPDATE)
- # IF MODE = ADD -- USE THE 'ADD' API CALL MODE
- elif mode == "add":
- response = fmgr.process_request(url, datagram, FMGRMethods.ADD)
-
- return response
-
-
-def delete_device_group(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
- # INIT A BASIC OBJECTS
- response = DEFAULT_RESULT_OBJ
- url = ""
-
- datagram = {
- "adom": paramgram["adom"],
- "name": paramgram["grp_name"]
- }
-
- url = '/dvmdb/adom/{adom}/group/{grp_name}'.format(adom=paramgram["adom"], grp_name=paramgram["grp_name"])
- response = fmgr.process_request(url, datagram, FMGRMethods.DELETE)
- return response
-
-
-def add_group_member(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
- # INIT A BASIC OBJECTS
- response = DEFAULT_RESULT_OBJ
- url = ""
- device_member_list = paramgram["grp_members"].replace(' ', '')
- device_member_list = device_member_list.split(',')
-
- for dev_name in device_member_list:
- datagram = {'name': dev_name, 'vdom': paramgram["vdom"]}
-
- url = '/dvmdb/adom/{adom}/group/{grp_name}/object member'.format(adom=paramgram["adom"],
- grp_name=paramgram["grp_name"])
- response = fmgr.process_request(url, datagram, FMGRMethods.ADD)
-
- return response
-
-
-def delete_group_member(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
- # INIT A BASIC OBJECTS
- response = DEFAULT_RESULT_OBJ
- url = ""
- device_member_list = paramgram["grp_members"].replace(' ', '')
- device_member_list = device_member_list.split(',')
-
- for dev_name in device_member_list:
- datagram = {'name': dev_name, 'vdom': paramgram["vdom"]}
-
- url = '/dvmdb/adom/{adom}/group/{grp_name}/object member'.format(adom=paramgram["adom"],
- grp_name=paramgram["grp_name"])
- response = fmgr.process_request(url, datagram, FMGRMethods.DELETE)
-
- return response
-
-
-def main():
- argument_spec = dict(
- adom=dict(required=False, type="str", default="root"),
- vdom=dict(required=False, type="str", default="root"),
- mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),
- grp_desc=dict(required=False, type="str"),
- grp_name=dict(required=True, type="str"),
- grp_members=dict(required=False, type="str"),
- )
-
- module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
- paramgram = {
- "mode": module.params["mode"],
- "grp_name": module.params["grp_name"],
- "grp_desc": module.params["grp_desc"],
- "grp_members": module.params["grp_members"],
- "adom": module.params["adom"],
- "vdom": module.params["vdom"]
- }
- module.paramgram = paramgram
- fmgr = None
- if module._socket_path:
- connection = Connection(module._socket_path)
- fmgr = FortiManagerHandler(connection, module)
- fmgr.tools = FMGRCommon()
- else:
- module.fail_json(**FAIL_SOCKET_MSG)
-
- # BEGIN MODULE-SPECIFIC LOGIC -- THINGS NEED TO HAPPEN DEPENDING ON THE ENDPOINT AND OPERATION
- results = DEFAULT_RESULT_OBJ
- try:
- # PROCESS THE GROUP ADDS FIRST
- if paramgram["grp_name"] is not None and paramgram["mode"] in ["add", "set", "update"]:
- # add device group
- results = add_device_group(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
-
- # PROCESS THE GROUP MEMBER ADDS
- if paramgram["grp_members"] is not None and paramgram["mode"] in ["add", "set", "update"]:
- # assign devices to device group
- results = add_group_member(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
-
- # PROCESS THE GROUP MEMBER DELETES
- if paramgram["grp_members"] is not None and paramgram["mode"] == "delete":
- # remove devices grom a group
- results = delete_group_member(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
-
- # PROCESS THE GROUP DELETES, ONLY IF GRP_MEMBERS IS NOT NULL TOO
- if paramgram["grp_name"] is not None and paramgram["mode"] == "delete" and paramgram["grp_members"] is None:
- # delete device group
- results = delete_device_group(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
- except Exception as err:
- raise FMGBaseException(err)
-
- return module.exit_json(**results[1])
-
-
-if __name__ == "__main__":
- main()
diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_device_provision_template.py b/ansible_collections/community/fortios/plugins/modules/fmgr_device_provision_template.py
deleted file mode 100644
index c71886943..000000000
--- a/ansible_collections/community/fortios/plugins/modules/fmgr_device_provision_template.py
+++ /dev/null
@@ -1,1546 +0,0 @@
-#!/usr/bin/python
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-
-from __future__ import absolute_import, division, print_function
-
-__metaclass__ = type
-
-DOCUMENTATION = '''
----
-module: fmgr_device_provision_template
-notes:
- - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
-author:
- - Luke Weighall (@lweighall)
- - Andrew Welsh (@Ghilli3)
- - Jim Huber (@p4r4n0y1ng)
-short_description: Manages Device Provisioning Templates in FortiManager.
-description:
- - Allows the editing and assignment of device provisioning templates in FortiManager.
-
-options:
- adom:
- description:
- - The ADOM the configuration should belong to.
- required: true
-
- mode:
- description:
- - Sets one of three modes for managing the object.
- - Allows use of soft-adds instead of overwriting existing values.
- choices: ['add', 'set', 'delete', 'update']
- required: false
- default: add
-
- device_unique_name:
- description:
- - The unique device's name that you are editing.
- required: True
-
- provisioning_template:
- description:
- - The provisioning template you want to apply (default = default).
- required: True
-
- provision_targets:
- description:
- - The friendly names of devices in FortiManager to assign the provisioning template to. CSV separated list.
- required: True
-
- snmp_status:
- description:
- - Enables or disables SNMP globally.
- required: False
- choices: ["enable", "disable"]
-
- snmp_v2c_query_port:
- description:
- - Sets the snmp v2c community query port.
- required: False
-
- snmp_v2c_trap_port:
- description:
- - Sets the snmp v2c community trap port.
- required: False
-
- snmp_v2c_status:
- description:
- - Enables or disables the v2c community specified.
- required: False
- choices: ["enable", "disable"]
-
- snmp_v2c_trap_status:
- description:
- - Enables or disables the v2c community specified for traps.
- required: False
- choices: ["enable", "disable"]
-
- snmp_v2c_query_status:
- description:
- - Enables or disables the v2c community specified for queries.
- required: False
- choices: ["enable", "disable"]
-
- snmp_v2c_name:
- description:
- - Specifies the v2c community name.
- required: False
-
- snmp_v2c_id:
- description:
- - Primary key for the snmp community. this must be unique!
- required: False
-
- snmp_v2c_trap_src_ipv4:
- description:
- - Source ip the traps should come from IPv4.
- required: False
-
- snmp_v2c_trap_hosts_ipv4:
- description: >
- - IPv4 addresses of the hosts that should get SNMP v2c traps, comma separated, must include mask
- ("10.7.220.59 255.255.255.255, 10.7.220.60 255.255.255.255").
- required: False
-
- snmp_v2c_query_hosts_ipv4:
- description: >
- - IPv4 addresses or subnets that are allowed to query SNMP v2c, comma separated
- ("10.7.220.59 255.255.255.0, 10.7.220.0 255.255.255.0").
- required: False
-
- snmpv3_auth_proto:
- description:
- - SNMPv3 auth protocol.
- required: False
- choices: ["md5", "sha"]
-
- snmpv3_auth_pwd:
- description:
- - SNMPv3 auth pwd __ currently not encrypted! ensure this file is locked down permissions wise!
- required: False
-
- snmpv3_name:
- description:
- - SNMPv3 user name.
- required: False
-
- snmpv3_notify_hosts:
- description:
- - List of ipv4 hosts to send snmpv3 traps to. Comma separated IPv4 list.
- required: False
-
- snmpv3_priv_proto:
- description:
- - SNMPv3 priv protocol.
- required: False
- choices: ["aes", "des", "aes256", "aes256cisco"]
-
- snmpv3_priv_pwd:
- description:
- - SNMPv3 priv pwd currently not encrypted! ensure this file is locked down permissions wise!
- required: False
-
- snmpv3_queries:
- description:
- - Allow snmpv3_queries.
- required: False
- choices: ["enable", "disable"]
-
- snmpv3_query_port:
- description:
- - SNMPv3 query port.
- required: False
-
- snmpv3_security_level:
- description:
- - SNMPv3 security level.
- required: False
- choices: ["no-auth-no-priv", "auth-no-priv", "auth-priv"]
-
- snmpv3_source_ip:
- description:
- - SNMPv3 source ipv4 address for traps.
- required: False
-
- snmpv3_status:
- description:
- - SNMPv3 user is enabled or disabled.
- required: False
- choices: ["enable", "disable"]
-
- snmpv3_trap_rport:
- description:
- - SNMPv3 trap remote port.
- required: False
-
- snmpv3_trap_status:
- description:
- - SNMPv3 traps is enabled or disabled.
- required: False
- choices: ["enable", "disable"]
-
- syslog_port:
- description:
- - Syslog port that will be set.
- required: False
-
- syslog_server:
- description:
- - Server the syslogs will be sent to.
- required: False
-
- syslog_status:
- description:
- - Enables or disables syslogs.
- required: False
- choices: ["enable", "disable"]
-
- syslog_mode:
- description:
- - Remote syslog logging over UDP/Reliable TCP.
- - choice | udp | Enable syslogging over UDP.
- - choice | legacy-reliable | Enable legacy reliable syslogging by RFC3195 (Reliable Delivery for Syslog).
- - choice | reliable | Enable reliable syslogging by RFC6587 (Transmission of Syslog Messages over TCP).
- required: false
- choices: ["udp", "legacy-reliable", "reliable"]
- default: "udp"
-
- syslog_filter:
- description:
- - Sets the logging level for syslog.
- required: False
- choices: ["emergency", "alert", "critical", "error", "warning", "notification", "information", "debug"]
-
- syslog_facility:
- description:
- - Remote syslog facility.
- - choice | kernel | Kernel messages.
- - choice | user | Random user-level messages.
- - choice | mail | Mail system.
- - choice | daemon | System daemons.
- - choice | auth | Security/authorization messages.
- - choice | syslog | Messages generated internally by syslog.
- - choice | lpr | Line printer subsystem.
- - choice | news | Network news subsystem.
- - choice | uucp | Network news subsystem.
- - choice | cron | Clock daemon.
- - choice | authpriv | Security/authorization messages (private).
- - choice | ftp | FTP daemon.
- - choice | ntp | NTP daemon.
- - choice | audit | Log audit.
- - choice | alert | Log alert.
- - choice | clock | Clock daemon.
- - choice | local0 | Reserved for local use.
- - choice | local1 | Reserved for local use.
- - choice | local2 | Reserved for local use.
- - choice | local3 | Reserved for local use.
- - choice | local4 | Reserved for local use.
- - choice | local5 | Reserved for local use.
- - choice | local6 | Reserved for local use.
- - choice | local7 | Reserved for local use.
- required: false
- choices: ["kernel", "user", "mail", "daemon", "auth", "syslog",
- "lpr", "news", "uucp", "cron", "authpriv", "ftp", "ntp", "audit",
- "alert", "clock", "local0", "local1", "local2", "local3", "local4", "local5", "local6", "local7"]
- default: "syslog"
-
- syslog_enc_algorithm:
- description:
- - Enable/disable reliable syslogging with TLS encryption.
- - choice | high | SSL communication with high encryption algorithms.
- - choice | low | SSL communication with low encryption algorithms.
- - choice | disable | Disable SSL communication.
- - choice | high-medium | SSL communication with high and medium encryption algorithms.
- required: false
- choices: ["high", "low", "disable", "high-medium"]
- default: "disable"
-
- syslog_certificate:
- description:
- - Certificate used to communicate with Syslog server if encryption on.
- required: false
-
- ntp_status:
- description:
- - Enables or disables ntp.
- required: False
- choices: ["enable", "disable"]
-
- ntp_sync_interval:
- description:
- - Sets the interval in minutes for ntp sync.
- required: False
-
- ntp_type:
- description:
- - Enables fortiguard servers or custom servers are the ntp source.
- required: False
- choices: ["fortiguard", "custom"]
-
- ntp_server:
- description:
- - Only used with custom ntp_type -- specifies IP of server to sync to -- comma separated ip addresses for multiples.
- required: False
-
- ntp_auth:
- description:
- - Enables or disables ntp authentication.
- required: False
- choices: ["enable", "disable"]
-
- ntp_auth_pwd:
- description:
- - Sets the ntp auth password.
- required: False
-
- ntp_v3:
- description:
- - Enables or disables ntpv3 (default is ntpv4).
- required: False
- choices: ["enable", "disable"]
-
- admin_https_redirect:
- description:
- - Enables or disables https redirect from http.
- required: False
- choices: ["enable", "disable"]
-
- admin_https_port:
- description:
- - SSL admin gui port number.
- required: False
-
- admin_http_port:
- description:
- - Non-SSL admin gui port number.
- required: False
-
- admin_timeout:
- description:
- - Admin timeout in minutes.
- required: False
-
- admin_language:
- description:
- - Sets the admin gui language.
- required: False
- choices: ["english", "simch", "japanese", "korean", "spanish", "trach", "french", "portuguese"]
-
- admin_switch_controller:
- description:
- - Enables or disables the switch controller.
- required: False
- choices: ["enable", "disable"]
-
- admin_gui_theme:
- description:
- - Changes the admin gui theme.
- required: False
- choices: ["green", "red", "blue", "melongene", "mariner"]
-
- admin_enable_fortiguard:
- description:
- - Enables FortiGuard security updates to their default settings.
- required: False
- choices: ["none", "direct", "this-fmg"]
-
- admin_fortianalyzer_target:
- description:
- - Configures faz target.
- required: False
-
- admin_fortiguard_target:
- description:
- - Configures fortiguard target.
- - admin_enable_fortiguard must be set to "direct".
- required: False
-
- smtp_username:
- description:
- - SMTP auth username.
- required: False
-
- smtp_password:
- description:
- - SMTP password.
- required: False
-
- smtp_port:
- description:
- - SMTP port number.
- required: False
-
- smtp_replyto:
- description:
- - SMTP reply to address.
- required: False
-
- smtp_conn_sec:
- description:
- - defines the ssl level for smtp.
- required: False
- choices: ["none", "starttls", "smtps"]
-
- smtp_server:
- description:
- - SMTP server ipv4 address.
- required: False
-
- smtp_source_ipv4:
- description:
- - SMTP source ip address.
- required: False
-
- smtp_validate_cert:
- description:
- - Enables or disables valid certificate checking for smtp.
- required: False
- choices: ["enable", "disable"]
-
- dns_suffix:
- description:
- - Sets the local dns domain suffix.
- required: False
-
- dns_primary_ipv4:
- description:
- - primary ipv4 dns forwarder.
- required: False
-
- dns_secondary_ipv4:
- description:
- - secondary ipv4 dns forwarder.
- required: False
-
- delete_provisioning_template:
- description:
- - If specified, all other options are ignored. The specified provisioning template will be deleted.
- required: False
-
-'''
-
-
-EXAMPLES = '''
-- name: SET SNMP SYSTEM INFO
- community.fortios.fmgr_device_provision_template:
- provisioning_template: "default"
- snmp_status: "enable"
- mode: "set"
-
-- name: SET SNMP SYSTEM INFO ANSIBLE ADOM
- community.fortios.fmgr_device_provision_template:
- provisioning_template: "default"
- snmp_status: "enable"
- mode: "set"
- adom: "ansible"
-
-- name: SET SNMP SYSTEM INFO different template (SNMPv2)
- community.fortios.fmgr_device_provision_template:
- provisioning_template: "ansibleTest"
- snmp_status: "enable"
- mode: "set"
- adom: "ansible"
- snmp_v2c_query_port: "162"
- snmp_v2c_trap_port: "161"
- snmp_v2c_status: "enable"
- snmp_v2c_trap_status: "enable"
- snmp_v2c_query_status: "enable"
- snmp_v2c_name: "ansibleV2c"
- snmp_v2c_id: "1"
- snmp_v2c_trap_src_ipv4: "10.7.220.41"
- snmp_v2c_trap_hosts_ipv4: "10.7.220.59 255.255.255.255, 10.7.220.60 255.255.255.255"
- snmp_v2c_query_hosts_ipv4: "10.7.220.59 255.255.255.255, 10.7.220.0 255.255.255.0"
-
-- name: SET SNMP SYSTEM INFO different template (SNMPv3)
- community.fortios.fmgr_device_provision_template:
- provisioning_template: "ansibleTest"
- snmp_status: "enable"
- mode: "set"
- adom: "ansible"
- snmpv3_auth_proto: "sha"
- snmpv3_auth_pwd: "fortinet"
- snmpv3_name: "ansibleSNMPv3"
- snmpv3_notify_hosts: "10.7.220.59,10.7.220.60"
- snmpv3_priv_proto: "aes256"
- snmpv3_priv_pwd: "fortinet"
- snmpv3_queries: "enable"
- snmpv3_query_port: "161"
- snmpv3_security_level: "auth_priv"
- snmpv3_source_ip: "0.0.0.0"
- snmpv3_status: "enable"
- snmpv3_trap_rport: "162"
- snmpv3_trap_status: "enable"
-
-- name: SET SYSLOG INFO
- community.fortios.fmgr_device_provision_template:
- provisioning_template: "ansibleTest"
- mode: "set"
- adom: "ansible"
- syslog_server: "10.7.220.59"
- syslog_port: "514"
- syslog_mode: "disable"
- syslog_status: "enable"
- syslog_filter: "information"
-
-- name: SET NTP TO FORTIGUARD
- community.fortios.fmgr_device_provision_template:
- provisioning_template: "ansibleTest"
- mode: "set"
- adom: "ansible"
- ntp_status: "enable"
- ntp_sync_interval: "60"
- type: "fortiguard"
-
-- name: SET NTP TO CUSTOM SERVER
- community.fortios.fmgr_device_provision_template:
- provisioning_template: "ansibleTest"
- mode: "set"
- adom: "ansible"
- ntp_status: "enable"
- ntp_sync_interval: "60"
- ntp_type: "custom"
- ntp_server: "10.7.220.32,10.7.220.1"
- ntp_auth: "enable"
- ntp_auth_pwd: "fortinet"
- ntp_v3: "disable"
-
-- name: SET ADMIN GLOBAL SETTINGS
- community.fortios.fmgr_device_provision_template:
- provisioning_template: "ansibleTest"
- mode: "set"
- adom: "ansible"
- admin_https_redirect: "enable"
- admin_https_port: "4433"
- admin_http_port: "8080"
- admin_timeout: "30"
- admin_language: "english"
- admin_switch_controller: "enable"
- admin_gui_theme: "blue"
- admin_enable_fortiguard: "direct"
- admin_fortiguard_target: "10.7.220.128"
- admin_fortianalyzer_target: "10.7.220.61"
-
-- name: SET CUSTOM SMTP SERVER
- community.fortios.fmgr_device_provision_template:
- provisioning_template: "ansibleTest"
- mode: "set"
- adom: "ansible"
- smtp_username: "ansible"
- smtp_password: "fortinet"
- smtp_port: "25"
- smtp_replyto: "ansible@do-not-reply.com"
- smtp_conn_sec: "starttls"
- smtp_server: "10.7.220.32"
- smtp_source_ipv4: "0.0.0.0"
- smtp_validate_cert: "disable"
-
-- name: SET DNS SERVERS
- community.fortios.fmgr_device_provision_template:
- provisioning_template: "ansibleTest"
- mode: "set"
- adom: "ansible"
- dns_suffix: "ansible.local"
- dns_primary_ipv4: "8.8.8.8"
- dns_secondary_ipv4: "4.4.4.4"
-
-- name: SET PROVISIONING TEMPLATE DEVICE TARGETS IN FORTIMANAGER
- community.fortios.fmgr_device_provision_template:
- provisioning_template: "ansibleTest"
- mode: "set"
- adom: "ansible"
- provision_targets: "FGT1, FGT2"
-
-- name: DELETE ENTIRE PROVISIONING TEMPLATE
- community.fortios.fmgr_device_provision_template:
- delete_provisioning_template: "ansibleTest"
- mode: "delete"
- adom: "ansible"
-
-'''
-RETURN = """
-api_result:
- description: full API response, includes status code and message
- returned: always
- type: str
-"""
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.connection import Connection
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRMethods
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG
-
-
-def get_devprof(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
-
- response = DEFAULT_RESULT_OBJ
- datagram = {}
-
- url = "/pm/devprof/adom/{adom}/{name}".format(adom=paramgram["adom"], name=paramgram["provisioning_template"])
- response = fmgr.process_request(url, datagram, FMGRMethods.GET)
-
- return response
-
-
-def set_devprof(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
-
- response = DEFAULT_RESULT_OBJ
- if paramgram["mode"] in ['set', 'add', 'update']:
- datagram = {
- "name": paramgram["provisioning_template"],
- "type": "devprof",
- "description": "CreatedByAnsible",
- }
- url = "/pm/devprof/adom/{adom}".format(adom=paramgram["adom"])
-
- elif paramgram["mode"] == "delete":
- datagram = {}
-
- url = "/pm/devprof/adom/{adom}/{name}".format(adom=paramgram["adom"],
- name=paramgram["delete_provisioning_template"])
-
- response = fmgr.process_request(url, datagram, paramgram["mode"])
- return response
-
-
-def get_devprof_scope(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
-
- response = DEFAULT_RESULT_OBJ
- datagram = {
- "name": paramgram["provisioning_template"],
- "type": "devprof",
- "description": "CreatedByAnsible",
- }
-
- url = "/pm/devprof/adom/{adom}".format(adom=paramgram["adom"])
- response = fmgr.process_request(url, datagram, FMGRMethods.GET)
-
- return response
-
-
-def set_devprof_scope(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
-
- response = DEFAULT_RESULT_OBJ
- if paramgram["mode"] in ['set', 'add', 'update']:
- datagram = {
- "name": paramgram["provisioning_template"],
- "type": "devprof",
- "description": "CreatedByAnsible",
- }
-
- targets = []
- for target in paramgram["provision_targets"].split(","):
- # split the host on the space to get the mask out
- new_target = {"name": target.strip()}
- targets.append(new_target)
-
- datagram["scope member"] = targets
-
- url = "/pm/devprof/adom/{adom}".format(adom=paramgram["adom"])
-
- elif paramgram["mode"] == "delete":
- datagram = {
- "name": paramgram["provisioning_template"],
- "type": "devprof",
- "description": "CreatedByAnsible",
- "scope member": paramgram["targets_to_add"]
- }
-
- url = "/pm/devprof/adom/{adom}".format(adom=paramgram["adom"])
-
- response = fmgr.process_request(url, datagram, FMGRMethods.SET)
- return response
-
-
-def set_devprof_snmp(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
- paramgram["mode"] = paramgram["mode"]
- adom = paramgram["adom"]
-
- response = DEFAULT_RESULT_OBJ
- datagram = {
- "status": paramgram["snmp_status"]
- }
- url = "/pm/config/adom/{adom}/devprof/" \
- "{provisioning_template}/system/snmp/sysinfo".format(adom=adom,
- provisioning_template=paramgram["provisioning_template"])
-
- response = fmgr.process_request(url, datagram, FMGRMethods.SET)
- return response
-
-
-def set_devprof_snmp_v2c(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
- paramgram["mode"] = paramgram["mode"]
- adom = paramgram["adom"]
-
- response = DEFAULT_RESULT_OBJ
- if paramgram["mode"] in ['set', 'add', 'update']:
- datagram = {
- "query-v2c-port": paramgram["snmp_v2c_query_port"],
- "trap-v2c-rport": paramgram["snmp_v2c_trap_port"],
- "status": paramgram["snmp_v2c_status"],
- "trap-v2c-status": paramgram["snmp_v2c_trap_status"],
- "query-v2c-status": paramgram["snmp_v2c_query_status"],
- "name": paramgram["snmp_v2c_name"],
- "id": paramgram["snmp_v2c_id"],
- "meta fields": dict(),
- "hosts": list(),
- "events": 411578417151,
- "query-v1-status": 0,
- "query-v1-port": 161,
- "trap-v1-status": 0,
- "trap-v1-lport": 162,
- "trap-v1-rport": 162,
- "trap-v2c-lport": 162,
- }
-
- # BUILD THE HOST STRINGS
- id_counter = 1
- if paramgram["snmp_v2c_trap_hosts_ipv4"] or paramgram["snmp_v2c_query_hosts_ipv4"]:
- hosts = []
- if paramgram["snmp_v2c_query_hosts_ipv4"]:
- for ipv4_host in paramgram["snmp_v2c_query_hosts_ipv4"].strip().split(","):
- # split the host on the space to get the mask out
- new_ipv4_host = {"ha-direct": "enable",
- "host-type": "query",
- "id": id_counter,
- "ip": ipv4_host.strip().split(),
- "meta fields": {},
- "source-ip": "0.0.0.0"}
- hosts.append(new_ipv4_host)
- id_counter += 1
-
- if paramgram["snmp_v2c_trap_hosts_ipv4"]:
- for ipv4_host in paramgram["snmp_v2c_trap_hosts_ipv4"].strip().split(","):
- # split the host on the space to get the mask out
- new_ipv4_host = {"ha-direct": "enable",
- "host-type": "trap",
- "id": id_counter,
- "ip": ipv4_host.strip().split(),
- "meta fields": {},
- "source-ip": paramgram["snmp_v2c_trap_src_ipv4"]}
- hosts.append(new_ipv4_host)
- id_counter += 1
- datagram["hosts"] = hosts
-
- url = "/pm/config/adom/{adom}/devprof/" \
- "{provisioning_template}/system/snmp/community".format(adom=adom,
- provisioning_template=paramgram[
- "provisioning_template"])
- elif paramgram["mode"] == "delete":
- datagram = {
- "confirm": 1
- }
-
- url = "/pm/config/adom/{adom}/" \
- "devprof/{provisioning_template}/" \
- "system/snmp/community/{snmp_v2c_id}".format(adom=adom,
- provisioning_template=paramgram["provisioning_template"],
- snmp_v2c_id=paramgram["snmp_v2c_id"])
-
- response = fmgr.process_request(url, datagram, paramgram["mode"])
- return response
-
-
-def set_devprof_snmp_v3(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
- paramgram["mode"] = paramgram["mode"]
- adom = paramgram["adom"]
-
- response = DEFAULT_RESULT_OBJ
- if paramgram["mode"] in ['set', 'add', 'update']:
- datagram = {}
- datagram["auth-pwd"] = paramgram["snmpv3_auth_pwd"]
- datagram["priv-pwd"] = paramgram["snmpv3_priv_pwd"]
- datagram["trap-rport"] = paramgram["snmpv3_trap_rport"]
- datagram["query-port"] = paramgram["snmpv3_query_port"]
- datagram["name"] = paramgram["snmpv3_name"]
- datagram["notify-hosts"] = paramgram["snmpv3_notify_hosts"].strip().split(",")
- datagram["events"] = 1647387997183
- datagram["trap-lport"] = 162
-
- datagram["source-ip"] = paramgram["snmpv3_source_ip"]
- datagram["ha-direct"] = 0
-
- url = "/pm/config/adom/{adom}/" \
- "devprof/{provisioning_template}/" \
- "system/snmp/user".format(adom=adom,
- provisioning_template=paramgram["provisioning_template"])
- elif paramgram["mode"] == "delete":
- datagram = {
- "confirm": 1
- }
-
- url = "/pm/config/adom/{adom}/devprof/" \
- "{provisioning_template}/system/snmp" \
- "/user/{snmpv3_name}".format(adom=adom,
- provisioning_template=paramgram["provisioning_template"],
- snmpv3_name=paramgram["snmpv3_name"])
-
- response = fmgr.process_request(url, datagram, paramgram["mode"])
- return response
-
-
-def set_devprof_syslog(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
- paramgram["mode"] = paramgram["mode"]
- adom = paramgram["adom"]
-
- response = DEFAULT_RESULT_OBJ
-
- datagram = {
- "status": paramgram["syslog_status"],
- "port": paramgram["syslog_port"],
- "server": paramgram["syslog_server"],
- "mode": paramgram["syslog_mode"],
- "facility": paramgram["syslog_facility"]
- }
-
- if paramgram["mode"] in ['set', 'add', 'update']:
- if paramgram["syslog_enc_algorithm"] in ["high", "low", "high-medium"] \
- and paramgram["syslog_certificate"] is not None:
- datagram["certificate"] = paramgram["certificate"]
- datagram["enc-algorithm"] = paramgram["syslog_enc_algorithm"]
-
- url = "/pm/config/adom/{adom}/" \
- "devprof/{provisioning_template}/" \
- "log/syslogd/setting".format(adom=adom,
- provisioning_template=paramgram["provisioning_template"])
- elif paramgram["mode"] == "delete":
- url = "/pm/config/adom/{adom}/" \
- "devprof/{provisioning_template}/" \
- "log/syslogd/setting".format(adom=adom,
- provisioning_template=paramgram["provisioning_template"])
-
- response = fmgr.process_request(url, datagram, paramgram["mode"])
- return response
-
-
-def set_devprof_syslog_filter(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
- paramgram["mode"] = paramgram["mode"]
- adom = paramgram["adom"]
- datagram = {
- "severity": paramgram["syslog_filter"]
- }
- response = DEFAULT_RESULT_OBJ
-
- url = "/pm/config/adom/{adom}" \
- "/devprof/{provisioning_template}" \
- "/log/syslogd/filter".format(adom=adom,
- provisioning_template=paramgram["provisioning_template"])
-
- response = fmgr.process_request(url, datagram, paramgram["mode"])
- return response
-
-
-def set_devprof_ntp(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
- paramgram["mode"] = paramgram["mode"]
- adom = paramgram["adom"]
-
- response = DEFAULT_RESULT_OBJ
-
- # IF SET TO FORTIGUARD, BUILD A STRING SPECIFIC TO THAT
- if paramgram["ntp_type"] == "fortiguard":
- datagram = {}
- if paramgram["ntp_status"] == "enable":
- datagram["ntpsync"] = 1
- if paramgram["ntp_status"] == "disable":
- datagram["ntpsync"] = 0
- if paramgram["ntp_sync_interval"] is None:
- datagram["syncinterval"] = 1
- else:
- datagram["syncinterval"] = paramgram["ntp_sync_interval"]
-
- datagram["type"] = 0
-
- # IF THE NTP TYPE IS CUSTOM BUILD THE SERVER LIST
- if paramgram["ntp_type"] == "custom":
- id_counter = 0
- key_counter = 0
- ntpservers = []
- datagram = {}
- if paramgram["ntp_status"] == "enable":
- datagram["ntpsync"] = 1
- if paramgram["ntp_status"] == "disable":
- datagram["ntpsync"] = 0
- try:
- datagram["syncinterval"] = paramgram["ntp_sync_interval"]
- except BaseException:
- datagram["syncinterval"] = 1
- datagram["type"] = 1
-
- for server in paramgram["ntp_server"].strip().split(","):
- id_counter += 1
- server_fields = dict()
-
- key_counter += 1
- if paramgram["ntp_auth"] == "enable":
- server_fields["authentication"] = 1
- server_fields["key"] = paramgram["ntp_auth_pwd"]
- server_fields["key-id"] = key_counter
- else:
- server_fields["authentication"] = 0
- server_fields["key"] = ""
- server_fields["key-id"] = key_counter
-
- if paramgram["ntp_v3"] == "enable":
- server_fields["ntp_v3"] = 1
- else:
- server_fields["ntp_v3"] = 0
-
- # split the host on the space to get the mask out
- new_ntp_server = {"authentication": server_fields["authentication"],
- "id": id_counter, "key": server_fields["key"],
- "key-id": id_counter, "ntpv3": server_fields["ntp_v3"],
- "server": server}
- ntpservers.append(new_ntp_server)
- datagram["ntpserver"] = ntpservers
-
- url = "/pm/config/adom/{adom}" \
- "/devprof/{provisioning_template}" \
- "/system/ntp".format(adom=adom,
- provisioning_template=paramgram["provisioning_template"])
- response = fmgr.process_request(url, datagram, paramgram["mode"])
- return response
-
-
-def set_devprof_admin(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
- paramgram["mode"] = paramgram["mode"]
- adom = paramgram["adom"]
-
- response = DEFAULT_RESULT_OBJ
- datagram = {
- "admin-https-redirect": paramgram["admin_https_redirect"],
- "admin-port": paramgram["admin_http_port"],
- "admin-sport": paramgram["admin_https_port"],
- "admintimeout": paramgram["admin_timeout"],
- "language": paramgram["admin_language"],
- "gui-theme": paramgram["admin_gui_theme"],
- "switch-controller": paramgram["admin_switch_controller"],
- }
- url = "/pm/config/adom/{adom}" \
- "/devprof/{provisioning_template}" \
- "/system/global".format(adom=adom,
- provisioning_template=paramgram["provisioning_template"])
-
- response = fmgr.process_request(url, datagram, paramgram["mode"])
- return response
-
-
-def set_devprof_smtp(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
- paramgram["mode"] = paramgram["mode"]
- adom = paramgram["adom"]
-
- response = DEFAULT_RESULT_OBJ
- datagram = {
- "port": paramgram["smtp_port"],
- "reply-to": paramgram["smtp_replyto"],
- "server": paramgram["smtp_server"],
- "source-ip": paramgram["smtp_source_ipv4"]
- }
-
- if paramgram["smtp_username"]:
- datagram["authenticate"] = 1
- datagram["username"] = paramgram["smtp_username"]
- datagram["password"] = paramgram["smtp_password"]
-
- if paramgram["smtp_conn_sec"] == "none":
- datagram["security"] = 0
- if paramgram["smtp_conn_sec"] == "starttls":
- datagram["security"] = 1
- if paramgram["smtp_conn_sec"] == "smtps":
- datagram["security"] = 2
-
- if paramgram["smtp_validate_cert"] == "enable":
- datagram["validate-server"] = 1
- else:
- datagram["validate-server"] = 0
-
- url = "/pm/config/adom/{adom}" \
- "/devprof/{provisioning_template}" \
- "/system/email-server".format(adom=adom,
- provisioning_template=paramgram["provisioning_template"])
-
- response = fmgr.process_request(url, datagram, paramgram["mode"])
- return response
-
-
-def set_devprof_dns(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
- paramgram["mode"] = paramgram["mode"]
- adom = paramgram["adom"]
-
- response = DEFAULT_RESULT_OBJ
- datagram = {
- "domain": paramgram["dns_suffix"],
- "primary": paramgram["dns_primary_ipv4"],
- "secondary": paramgram["dns_secondary_ipv4"],
- }
- url = "/pm/config/adom/{adom}" \
- "/devprof/{provisioning_template}" \
- "/system/dns".format(adom=adom,
- provisioning_template=paramgram["provisioning_template"])
-
- response = fmgr.process_request(url, datagram, paramgram["mode"])
- return response
-
-
-def set_devprof_toggle_fg(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
- paramgram["mode"] = paramgram["mode"]
- adom = paramgram["adom"]
- response = DEFAULT_RESULT_OBJ
- datagram = {}
- if paramgram["admin_enable_fortiguard"] in ["direct", "this-fmg"]:
- datagram["include-default-servers"] = "enable"
- elif paramgram["admin_enable_fortiguard"] == "none":
- datagram["include-default-servers"] = "disable"
-
- datagram["server-list"] = list()
-
- url = "/pm/config/adom/{adom}" \
- "/devprof/{provisioning_template}" \
- "/system/central-management".format(adom=adom,
- provisioning_template=paramgram["provisioning_template"])
- response = fmgr.process_request(url, datagram, FMGRMethods.SET)
-
- return response
-
-
-def set_devprof_fg(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
- paramgram["mode"] = paramgram["mode"]
- adom = paramgram["adom"]
-
- response = DEFAULT_RESULT_OBJ
- datagram = {
- "target": paramgram["admin_enable_fortiguard"],
- "target-ip": None
- }
-
- if paramgram["mode"] in ['set', 'add', 'update']:
- if paramgram["admin_fortiguard_target"] is not None and datagram["target"] == "direct":
- datagram["target-ip"] = paramgram["admin_fortiguard_target"]
-
- url = "/pm/config/adom/{adom}" \
- "/devprof/{provisioning_template}" \
- "/device/profile/fortiguard".format(adom=adom,
- provisioning_template=paramgram["provisioning_template"])
-
- response = fmgr.process_request(url, datagram, paramgram["mode"])
- return response
-
-
-def set_devprof_faz(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
- paramgram["mode"] = paramgram["mode"]
- adom = paramgram["adom"]
- response = DEFAULT_RESULT_OBJ
- datagram = {
- "target-ip": paramgram["admin_fortianalyzer_target"],
- "target": "others",
- }
- url = "/pm/config/adom/{adom}" \
- "/devprof/{provisioning_template}" \
- "/device/profile/fortianalyzer".format(adom=adom,
- provisioning_template=paramgram["provisioning_template"])
- if paramgram["mode"] == "delete":
- datagram["hastarget"] = "False"
-
- response = fmgr.process_request(url, datagram, paramgram["mode"])
- return response
-
-
-def main():
- argument_spec = dict(
- adom=dict(required=False, type="str"),
- mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),
-
- provisioning_template=dict(required=False, type="str"),
- provision_targets=dict(required=False, type="str"),
-
- device_unique_name=dict(required=False, type="str"),
- snmp_status=dict(required=False, type="str", choices=["enable", "disable"]),
- snmp_v2c_query_port=dict(required=False, type="int"),
- snmp_v2c_trap_port=dict(required=False, type="int"),
- snmp_v2c_status=dict(required=False, type="str", choices=["enable", "disable"]),
- snmp_v2c_trap_status=dict(required=False, type="str", choices=["enable", "disable"]),
- snmp_v2c_query_status=dict(required=False, type="str", choices=["enable", "disable"]),
- snmp_v2c_name=dict(required=False, type="str", no_log=True),
- snmp_v2c_id=dict(required=False, type="int"),
- snmp_v2c_trap_src_ipv4=dict(required=False, type="str"),
- snmp_v2c_trap_hosts_ipv4=dict(required=False, type="str"),
- snmp_v2c_query_hosts_ipv4=dict(required=False, type="str"),
-
- snmpv3_auth_proto=dict(required=False, type="str", choices=["md5", "sha"]),
- snmpv3_auth_pwd=dict(required=False, type="str", no_log=True),
- snmpv3_name=dict(required=False, type="str"),
- snmpv3_notify_hosts=dict(required=False, type="str"),
- snmpv3_priv_proto=dict(required=False, type="str", choices=["aes", "des", "aes256", "aes256cisco"]),
- snmpv3_priv_pwd=dict(required=False, type="str", no_log=True),
- snmpv3_queries=dict(required=False, type="str", choices=["enable", "disable"]),
- snmpv3_query_port=dict(required=False, type="int"),
- snmpv3_security_level=dict(required=False, type="str",
- choices=["no-auth-no-priv", "auth-no-priv", "auth-priv"]),
- snmpv3_source_ip=dict(required=False, type="str"),
- snmpv3_status=dict(required=False, type="str", choices=["enable", "disable"]),
- snmpv3_trap_rport=dict(required=False, type="int"),
- snmpv3_trap_status=dict(required=False, type="str", choices=["enable", "disable"]),
-
- syslog_port=dict(required=False, type="int"),
- syslog_server=dict(required=False, type="str"),
- syslog_mode=dict(required=False, type="str", choices=["udp", "legacy-reliable", "reliable"], default="udp"),
- syslog_status=dict(required=False, type="str", choices=["enable", "disable"]),
- syslog_filter=dict(required=False, type="str", choices=["emergency", "alert", "critical", "error",
- "warning", "notification", "information", "debug"]),
- syslog_enc_algorithm=dict(required=False, type="str", choices=["high", "low", "disable", "high-medium"],
- default="disable"),
- syslog_facility=dict(required=False, type="str", choices=["kernel", "user", "mail", "daemon", "auth",
- "syslog", "lpr", "news", "uucp", "cron", "authpriv",
- "ftp", "ntp", "audit", "alert", "clock", "local0",
- "local1", "local2", "local3", "local4", "local5",
- "local6", "local7"], default="syslog"),
- syslog_certificate=dict(required=False, type="str"),
-
- ntp_status=dict(required=False, type="str", choices=["enable", "disable"]),
- ntp_sync_interval=dict(required=False, type="int"),
- ntp_type=dict(required=False, type="str", choices=["fortiguard", "custom"]),
- ntp_server=dict(required=False, type="str"),
- ntp_auth=dict(required=False, type="str", choices=["enable", "disable"]),
- ntp_auth_pwd=dict(required=False, type="str", no_log=True),
- ntp_v3=dict(required=False, type="str", choices=["enable", "disable"]),
-
- admin_https_redirect=dict(required=False, type="str", choices=["enable", "disable"]),
- admin_https_port=dict(required=False, type="int"),
- admin_http_port=dict(required=False, type="int"),
- admin_timeout=dict(required=False, type="int"),
- admin_language=dict(required=False, type="str",
- choices=["english", "simch", "japanese", "korean",
- "spanish", "trach", "french", "portuguese"]),
- admin_switch_controller=dict(required=False, type="str", choices=["enable", "disable"]),
- admin_gui_theme=dict(required=False, type="str", choices=["green", "red", "blue", "melongene", "mariner"]),
- admin_enable_fortiguard=dict(required=False, type="str", choices=["none", "direct", "this-fmg"]),
- admin_fortianalyzer_target=dict(required=False, type="str"),
- admin_fortiguard_target=dict(required=False, type="str"),
-
- smtp_username=dict(required=False, type="str"),
- smtp_password=dict(required=False, type="str", no_log=True),
- smtp_port=dict(required=False, type="int"),
- smtp_replyto=dict(required=False, type="str"),
- smtp_conn_sec=dict(required=False, type="str", choices=["none", "starttls", "smtps"]),
- smtp_server=dict(required=False, type="str"),
- smtp_source_ipv4=dict(required=False, type="str"),
- smtp_validate_cert=dict(required=False, type="str", choices=["enable", "disable"]),
-
- dns_suffix=dict(required=False, type="str"),
- dns_primary_ipv4=dict(required=False, type="str"),
- dns_secondary_ipv4=dict(required=False, type="str"),
- delete_provisioning_template=dict(required=False, type="str")
- )
-
- module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
- paramgram = {
- "adom": module.params["adom"],
- "mode": module.params["mode"],
- "provision_targets": module.params["provision_targets"],
- "provisioning_template": module.params["provisioning_template"],
-
- "snmp_status": module.params["snmp_status"],
- "snmp_v2c_query_port": module.params["snmp_v2c_query_port"],
- "snmp_v2c_trap_port": module.params["snmp_v2c_trap_port"],
- "snmp_v2c_status": module.params["snmp_v2c_status"],
- "snmp_v2c_trap_status": module.params["snmp_v2c_trap_status"],
- "snmp_v2c_query_status": module.params["snmp_v2c_query_status"],
- "snmp_v2c_name": module.params["snmp_v2c_name"],
- "snmp_v2c_id": module.params["snmp_v2c_id"],
- "snmp_v2c_trap_src_ipv4": module.params["snmp_v2c_trap_src_ipv4"],
- "snmp_v2c_trap_hosts_ipv4": module.params["snmp_v2c_trap_hosts_ipv4"],
- "snmp_v2c_query_hosts_ipv4": module.params["snmp_v2c_query_hosts_ipv4"],
-
- "snmpv3_auth_proto": module.params["snmpv3_auth_proto"],
- "snmpv3_auth_pwd": module.params["snmpv3_auth_pwd"],
- "snmpv3_name": module.params["snmpv3_name"],
- "snmpv3_notify_hosts": module.params["snmpv3_notify_hosts"],
- "snmpv3_priv_proto": module.params["snmpv3_priv_proto"],
- "snmpv3_priv_pwd": module.params["snmpv3_priv_pwd"],
- "snmpv3_queries": module.params["snmpv3_queries"],
- "snmpv3_query_port": module.params["snmpv3_query_port"],
- "snmpv3_security_level": module.params["snmpv3_security_level"],
- "snmpv3_source_ip": module.params["snmpv3_source_ip"],
- "snmpv3_status": module.params["snmpv3_status"],
- "snmpv3_trap_rport": module.params["snmpv3_trap_rport"],
- "snmpv3_trap_status": module.params["snmpv3_trap_status"],
-
- "syslog_port": module.params["syslog_port"],
- "syslog_server": module.params["syslog_server"],
- "syslog_mode": module.params["syslog_mode"],
- "syslog_status": module.params["syslog_status"],
- "syslog_filter": module.params["syslog_filter"],
- "syslog_facility": module.params["syslog_facility"],
- "syslog_enc_algorithm": module.params["syslog_enc_algorithm"],
- "syslog_certificate": module.params["syslog_certificate"],
-
- "ntp_status": module.params["ntp_status"],
- "ntp_sync_interval": module.params["ntp_sync_interval"],
- "ntp_type": module.params["ntp_type"],
- "ntp_server": module.params["ntp_server"],
- "ntp_auth": module.params["ntp_auth"],
- "ntp_auth_pwd": module.params["ntp_auth_pwd"],
- "ntp_v3": module.params["ntp_v3"],
-
- "admin_https_redirect": module.params["admin_https_redirect"],
- "admin_https_port": module.params["admin_https_port"],
- "admin_http_port": module.params["admin_http_port"],
- "admin_timeout": module.params["admin_timeout"],
- "admin_language": module.params["admin_language"],
- "admin_switch_controller": module.params["admin_switch_controller"],
- "admin_gui_theme": module.params["admin_gui_theme"],
- "admin_enable_fortiguard": module.params["admin_enable_fortiguard"],
- "admin_fortianalyzer_target": module.params["admin_fortianalyzer_target"],
- "admin_fortiguard_target": module.params["admin_fortiguard_target"],
-
- "smtp_username": module.params["smtp_username"],
- "smtp_password": module.params["smtp_password"],
- "smtp_port": module.params["smtp_port"],
- "smtp_replyto": module.params["smtp_replyto"],
- "smtp_conn_sec": module.params["smtp_conn_sec"],
- "smtp_server": module.params["smtp_server"],
- "smtp_source_ipv4": module.params["smtp_source_ipv4"],
- "smtp_validate_cert": module.params["smtp_validate_cert"],
-
- "dns_suffix": module.params["dns_suffix"],
- "dns_primary_ipv4": module.params["dns_primary_ipv4"],
- "dns_secondary_ipv4": module.params["dns_secondary_ipv4"],
- "delete_provisioning_template": module.params["delete_provisioning_template"]
- }
- module.paramgram = paramgram
- fmgr = None
- if module._socket_path:
- connection = Connection(module._socket_path)
- fmgr = FortiManagerHandler(connection, module)
- fmgr.tools = FMGRCommon()
- else:
- module.fail_json(**FAIL_SOCKET_MSG)
-
- results = DEFAULT_RESULT_OBJ
- try:
- # CHECK IF WE ARE DELETING AN ENTIRE TEMPLATE. IF THAT'S THE CASE DO IT FIRST AND IGNORE THE REST.
- if paramgram["delete_provisioning_template"] is not None:
- results = set_devprof(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results, good_codes=[0, -10, -1],
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram),
- stop_on_success=True)
- except Exception as err:
- raise FMGBaseException(err)
-
- try:
- # CHECK TO SEE IF THE DEVPROF TEMPLATE EXISTS
- devprof = get_devprof(fmgr, paramgram)
- if devprof[0] != 0:
- results = set_devprof(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results, good_codes=[0, -2], stop_on_success=False,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
- except Exception as err:
- raise FMGBaseException(err)
-
- try:
- # PROCESS THE SNMP SETTINGS IF THE SNMP_STATUS VARIABLE IS SET
- if paramgram["snmp_status"] is not None:
- results = set_devprof_snmp(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results, good_codes=[0], stop_on_success=False,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
-
- # PROCESS THE SNMP V2C COMMUNITY SETTINGS IF THEY ARE ALL HERE
- if all(v is not None for v in (paramgram["snmp_v2c_query_port"], paramgram["snmp_v2c_trap_port"],
- paramgram["snmp_v2c_status"], paramgram["snmp_v2c_trap_status"],
- paramgram["snmp_v2c_query_status"], paramgram["snmp_v2c_name"],
- paramgram["snmp_v2c_id"])):
- results = set_devprof_snmp_v2c(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results, good_codes=[0, -10033], stop_on_success=True,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
-
- # PROCESS THE SNMPV3 USER IF THERE
- if all(v is not None for v in (
- [paramgram["snmpv3_auth_proto"], paramgram["snmpv3_auth_pwd"], paramgram["snmpv3_name"],
- paramgram["snmpv3_notify_hosts"], paramgram["snmpv3_priv_proto"],
- paramgram["snmpv3_priv_pwd"],
- paramgram["snmpv3_queries"],
- paramgram["snmpv3_query_port"], paramgram["snmpv3_security_level"],
- paramgram["snmpv3_source_ip"],
- paramgram["snmpv3_status"], paramgram["snmpv3_trap_rport"], paramgram["snmpv3_trap_status"]])):
-
- results = set_devprof_snmp_v3(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results, good_codes=[0, -10033, -10000, -3],
- stop_on_success=True,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
- except Exception as err:
- raise FMGBaseException(err)
-
- try:
- # PROCESS THE SYSLOG SETTINGS IF THE ALL THE NEEDED SYSLOG VARIABLES ARE PRESENT
- if all(v is not None for v in [paramgram["syslog_port"], paramgram["syslog_mode"],
- paramgram["syslog_server"], paramgram["syslog_status"]]):
- # enable syslog in the devprof template
- results = set_devprof_syslog(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results, good_codes=[0, -10033, -10000, -3],
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
- except Exception as err:
- raise FMGBaseException(err)
-
- try:
- # IF THE SYSLOG FILTER IS PRESENT THEN RUN THAT
- if paramgram["syslog_filter"] is not None:
- results = set_devprof_syslog_filter(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results, good_codes=[0],
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
- except Exception as err:
- raise FMGBaseException(err)
-
- try:
- # PROCESS NTP OPTIONS
- if paramgram["ntp_status"]:
- # VALIDATE INPUT
- if paramgram["ntp_type"] == "custom" and paramgram["ntp_server"] is None:
- module.exit_json(msg="You requested custom NTP type but did not provide ntp_server parameter.")
- if paramgram["ntp_auth"] == "enable" and paramgram["ntp_auth_pwd"] is None:
- module.exit_json(
- msg="You requested NTP Authentication but did not provide ntp_auth_pwd parameter.")
-
- results = set_devprof_ntp(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results, good_codes=[0],
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
- except Exception as err:
- raise FMGBaseException(err)
- try:
- # PROCESS THE ADMIN OPTIONS
- if any(v is not None for v in (
- paramgram["admin_https_redirect"], paramgram["admin_https_port"], paramgram["admin_http_port"],
- paramgram["admin_timeout"],
- paramgram["admin_language"], paramgram["admin_switch_controller"],
- paramgram["admin_gui_theme"])):
-
- results = set_devprof_admin(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results, good_codes=[0], stop_on_success=False,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
- except Exception as err:
- raise FMGBaseException(err)
-
- try:
- # PROCESS FORTIGUARD OPTIONS
- if paramgram["admin_enable_fortiguard"] is not None:
-
- results = set_devprof_toggle_fg(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results, good_codes=[0], stop_on_success=False,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
- results = set_devprof_fg(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results, good_codes=[0], stop_on_success=False,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
- except Exception as err:
- raise FMGBaseException(err)
-
- try:
- # PROCESS THE SMTP OPTIONS
- if all(v is not None for v in (
- paramgram["smtp_username"], paramgram["smtp_password"], paramgram["smtp_port"],
- paramgram["smtp_replyto"],
- paramgram["smtp_conn_sec"], paramgram["smtp_server"],
- paramgram["smtp_source_ipv4"], paramgram["smtp_validate_cert"])):
-
- results = set_devprof_smtp(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results, good_codes=[0], stop_on_success=False,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
- except Exception as err:
- raise FMGBaseException(err)
-
- try:
- # PROCESS THE DNS OPTIONS
- if any(v is not None for v in
- (paramgram["dns_suffix"], paramgram["dns_primary_ipv4"], paramgram["dns_secondary_ipv4"])):
- results = set_devprof_dns(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results, good_codes=[0], stop_on_success=False,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
- except Exception as err:
- raise FMGBaseException(err)
-
- try:
- # PROCESS THE admin_fortianalyzer_target OPTIONS
- if paramgram["admin_fortianalyzer_target"] is not None:
-
- results = set_devprof_faz(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results, good_codes=[0], stop_on_success=False,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
- except Exception as err:
- raise FMGBaseException(err)
-
- try:
- # PROCESS THE PROVISIONING TEMPLATE TARGET PARAMETER
- if paramgram["provision_targets"] is not None:
- if paramgram["mode"] != "delete":
- results = set_devprof_scope(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results, good_codes=[0], stop_on_success=False,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
-
- if paramgram["mode"] == "delete":
- # WE NEED TO FIGURE OUT WHAT'S THERE FIRST, BEFORE WE CAN RUN THIS
- targets_to_add = list()
- try:
- current_scope = get_devprof_scope(fmgr, paramgram)
- targets_to_remove = paramgram["provision_targets"].strip().split(",")
- targets = current_scope[1][1]["scope member"]
- for target in targets:
- if target["name"] not in targets_to_remove:
- target_append = {"name": target["name"]}
- targets_to_add.append(target_append)
- except BaseException:
- pass
- paramgram["targets_to_add"] = targets_to_add
- results = set_devprof_scope(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results, good_codes=[0, -10033, -10000, -3],
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
- except Exception as err:
- raise FMGBaseException(err)
-
- return module.exit_json(**results[1])
-
-
-if __name__ == "__main__":
- main()
diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_fwobj_address.py b/ansible_collections/community/fortios/plugins/modules/fmgr_fwobj_address.py
deleted file mode 100644
index c060c00d2..000000000
--- a/ansible_collections/community/fortios/plugins/modules/fmgr_fwobj_address.py
+++ /dev/null
@@ -1,661 +0,0 @@
-#!/usr/bin/python
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-DOCUMENTATION = '''
----
-module: fmgr_fwobj_address
-notes:
- - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
-author:
- - Luke Weighall (@lweighall)
- - Andrew Welsh (@Ghilli3)
- - Jim Huber (@p4r4n0y1ng)
-short_description: Allows the management of firewall objects in FortiManager
-description:
- - Allows for the management of IPv4, IPv6, and multicast address objects within FortiManager.
-
-options:
- adom:
- description:
- - The ADOM the configuration should belong to.
- required: false
- default: root
-
- allow_routing:
- description:
- - Enable/disable use of this address in the static route configuration.
- choices: ['enable', 'disable']
- default: 'disable'
-
- associated_interface:
- description:
- - Associated interface name.
-
- cache_ttl:
- description:
- - Minimal TTL of individual IP addresses in FQDN cache. Only applies when type = wildcard-fqdn.
-
- color:
- description:
- - Color of the object in FortiManager GUI.
- - Takes integers 1-32
- default: 22
-
- comment:
- description:
- - Comment for the object in FortiManager.
-
- country:
- description:
- - Country name. Required if type = geographic.
-
- end_ip:
- description:
- - End IP. Only used when ipv4 = iprange.
-
- group_members:
- description:
- - Address group member. If this is defined w/out group_name, the operation will fail.
-
- group_name:
- description:
- - Address group name. If this is defined in playbook task, all other options are ignored.
-
- ipv4:
- description:
- - Type of IPv4 Object.
- - Must not be specified with either multicast or IPv6 parameters.
- choices: ['ipmask', 'iprange', 'fqdn', 'wildcard', 'geography', 'wildcard-fqdn', 'group']
-
- ipv4addr:
- description:
- - IP and network mask. If only defining one IP use this parameter. (i.e. 10.7.220.30/255.255.255.255)
- - Can also define subnets (i.e. 10.7.220.0/255.255.255.0)
- - Also accepts CIDR (i.e. 10.7.220.0/24)
- - If Netmask is omitted after IP address, /32 is assumed.
- - When multicast is set to Broadcast Subnet the ipv4addr parameter is used to specify the subnet.
-
- ipv6:
- description:
- - Puts module into IPv6 mode.
- - Must not be specified with either ipv4 or multicast parameters.
- choices: ['ip', 'iprange', 'group']
-
- ipv6addr:
- description:
- - IPv6 address in full. (i.e. 2001:0db8:85a3:0000:0000:8a2e:0370:7334)
-
- fqdn:
- description:
- - Fully qualified domain name.
-
- mode:
- description:
- - Sets one of three modes for managing the object.
- choices: ['add', 'set', 'delete']
- default: add
-
- multicast:
- description:
- - Manages Multicast Address Objects.
- - Sets either a Multicast IP Range or a Broadcast Subnet.
- - Must not be specified with either ipv4 or ipv6 parameters.
- - When set to Broadcast Subnet the ipv4addr parameter is used to specify the subnet.
- - Can create IPv4 Multicast Objects (multicastrange and broadcastmask options -- uses start/end-ip and ipv4addr).
- choices: ['multicastrange', 'broadcastmask', 'ip6']
-
- name:
- description:
- - Friendly Name Address object name in FortiManager.
-
- obj_id:
- description:
- - Object ID for NSX.
-
- start_ip:
- description:
- - Start IP. Only used when ipv4 = iprange.
-
- visibility:
- description:
- - Enable/disable address visibility.
- choices: ['enable', 'disable']
- default: 'enable'
-
- wildcard:
- description:
- - IP address and wildcard netmask. Required if ipv4 = wildcard.
-
- wildcard_fqdn:
- description:
- - Wildcard FQDN. Required if ipv4 = wildcard-fqdn.
-'''
-
-EXAMPLES = '''
-- name: ADD IPv4 IP ADDRESS OBJECT
- community.fortios.fmgr_fwobj_address:
- ipv4: "ipmask"
- ipv4addr: "10.7.220.30/32"
- name: "ansible_v4Obj"
- comment: "Created by Ansible"
- color: "6"
-
-- name: ADD IPv4 IP ADDRESS OBJECT MORE OPTIONS
- community.fortios.fmgr_fwobj_address:
- ipv4: "ipmask"
- ipv4addr: "10.7.220.34/32"
- name: "ansible_v4Obj_MORE"
- comment: "Created by Ansible"
- color: "6"
- allow_routing: "enable"
- cache_ttl: "180"
- associated_interface: "port1"
- obj_id: "123"
-
-- name: ADD IPv4 IP ADDRESS SUBNET OBJECT
- community.fortios.fmgr_fwobj_address:
- ipv4: "ipmask"
- ipv4addr: "10.7.220.0/255.255.255.128"
- name: "ansible_subnet"
- comment: "Created by Ansible"
- mode: "set"
-
-- name: ADD IPv4 IP ADDRESS RANGE OBJECT
- community.fortios.fmgr_fwobj_address:
- ipv4: "iprange"
- start_ip: "10.7.220.1"
- end_ip: "10.7.220.125"
- name: "ansible_range"
- comment: "Created by Ansible"
-
-- name: ADD IPv4 IP ADDRESS WILDCARD OBJECT
- community.fortios.fmgr_fwobj_address:
- ipv4: "wildcard"
- wildcard: "10.7.220.30/255.255.255.255"
- name: "ansible_wildcard"
- comment: "Created by Ansible"
-
-- name: ADD IPv4 IP ADDRESS WILDCARD FQDN OBJECT
- community.fortios.fmgr_fwobj_address:
- ipv4: "wildcard-fqdn"
- wildcard_fqdn: "*.myds.com"
- name: "Synology myds DDNS service"
- comment: "Created by Ansible"
-
-- name: ADD IPv4 IP ADDRESS FQDN OBJECT
- community.fortios.fmgr_fwobj_address:
- ipv4: "fqdn"
- fqdn: "ansible.com"
- name: "ansible_fqdn"
- comment: "Created by Ansible"
-
-- name: ADD IPv4 IP ADDRESS GEO OBJECT
- community.fortios.fmgr_fwobj_address:
- ipv4: "geography"
- country: "usa"
- name: "ansible_geo"
- comment: "Created by Ansible"
-
-- name: ADD IPv6 ADDRESS
- community.fortios.fmgr_fwobj_address:
- ipv6: "ip"
- ipv6addr: "2001:0db8:85a3:0000:0000:8a2e:0370:7334"
- name: "ansible_v6Obj"
- comment: "Created by Ansible"
-
-- name: ADD IPv6 ADDRESS RANGE
- community.fortios.fmgr_fwobj_address:
- ipv6: "iprange"
- start_ip: "2001:0db8:85a3:0000:0000:8a2e:0370:7334"
- end_ip: "2001:0db8:85a3:0000:0000:8a2e:0370:7446"
- name: "ansible_v6range"
- comment: "Created by Ansible"
-
-- name: ADD IPv4 IP ADDRESS GROUP
- community.fortios.fmgr_fwobj_address:
- ipv4: "group"
- group_name: "ansibleIPv4Group"
- group_members: "ansible_fqdn, ansible_wildcard, ansible_range"
-
-- name: ADD IPv6 IP ADDRESS GROUP
- community.fortios.fmgr_fwobj_address:
- ipv6: "group"
- group_name: "ansibleIPv6Group"
- group_members: "ansible_v6Obj, ansible_v6range"
-
-- name: ADD MULTICAST RANGE
- community.fortios.fmgr_fwobj_address:
- multicast: "multicastrange"
- start_ip: "224.0.0.251"
- end_ip: "224.0.0.251"
- name: "ansible_multicastrange"
- comment: "Created by Ansible"
-
-- name: ADD BROADCAST SUBNET
- community.fortios.fmgr_fwobj_address:
- multicast: "broadcastmask"
- ipv4addr: "10.7.220.0/24"
- name: "ansible_broadcastSubnet"
- comment: "Created by Ansible"
-'''
-
-RETURN = """
-api_result:
- description: full API response, includes status code and message
- returned: always
- type: str
-"""
-
-
-import re
-from ansible.module_utils.basic import AnsibleModule, env_fallback
-from ansible.module_utils.connection import Connection
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG
-
-
-def fmgr_fwobj_ipv4(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
- # EVAL THE MODE PARAMETER FOR SET OR ADD
- if paramgram["mode"] in ['set', 'add']:
- # CREATE THE DATAGRAM DICTIONARY
- # ENSURE THE DATAGRAM KEYS MATCH THE JSON API GUIDE ATTRIBUTES, NOT WHAT IS IN ANSIBLE
- # SOME PARAMETERS SHOWN IN THIS DICTIONARY WE DON'T EVEN ASK THE USER FOR IN PLAYBOOKS BUT ARE REQUIRED
- datagram = {
- "comment": paramgram["comment"],
- "associated-interface": paramgram["associated-interface"],
- "cache-ttl": paramgram["cache-ttl"],
- "name": paramgram["name"],
- "allow-routing": paramgram["allow-routing"],
- "color": paramgram["color"],
- "meta fields": {},
- "dynamic_mapping": [],
- "visibility": paramgram["allow-routing"],
- "type": paramgram["ipv4"],
- }
-
- # SET THE CORRECT URL BASED ON THE TYPE (WE'RE DOING GROUPS IN THIS METHOD, TOO)
- if datagram["type"] == "group":
- url = '/pm/config/adom/{adom}/obj/firewall/addrgrp'.format(adom=paramgram["adom"])
- else:
- url = '/pm/config/adom/{adom}/obj/firewall/address'.format(adom=paramgram["adom"])
-
- #########################
- # IF type = 'ipmask'
- #########################
- if datagram["type"] == "ipmask":
- # CREATE THE SUBNET LIST OBJECT
- subnet = []
- # EVAL THE IPV4ADDR INPUT AND SPLIT THE IP ADDRESS FROM THE MASK AND APPEND THEM TO THE SUBNET LIST
- for subnets in paramgram["ipv4addr"].split("/"):
- subnet.append(subnets)
-
- # CHECK THAT THE SECOND ENTRY IN THE SUBNET LIST (WHAT WAS TO THE RIGHT OF THE / CHARACTER)
- # IS IN SUBNET MASK FORMAT AND NOT CIDR FORMAT.
- # IF IT IS IN CIDR FORMAT, WE NEED TO CONVERT IT TO SUBNET BIT MASK FORMAT FOR THE JSON API
- if not re.match(r'\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}', subnet[1]):
- # IF THE SUBNET PARAMETER INPUT DIDN'T LOOK LIKE xxx.xxx.xxx.xxx TO REGEX...
- # ... RUN IT THROUGH THE CIDR_TO_NETMASK() FUNCTION
- mask = fmgr._tools.cidr_to_netmask(subnet[1])
- # AND THEN UPDATE THE SUBNET LIST OBJECT
- subnet[1] = mask
-
- # INCLUDE THE SUBNET LIST OBJECT IN THE DATAGRAM DICTIONARY TO BE SUBMITTED
- datagram["subnet"] = subnet
-
- #########################
- # IF type = 'iprange'
- #########################
- if datagram["type"] == "iprange":
- datagram["start-ip"] = paramgram["start-ip"]
- datagram["end-ip"] = paramgram["end-ip"]
- datagram["subnet"] = ["0.0.0.0", "0.0.0.0"]
-
- #########################
- # IF type = 'geography'
- #########################
- if datagram["type"] == "geography":
- datagram["country"] = paramgram["country"]
-
- #########################
- # IF type = 'wildcard'
- #########################
- if datagram["type"] == "wildcard":
-
- subnet = []
- for subnets in paramgram["wildcard"].split("/"):
- subnet.append(subnets)
-
- if not re.match(r'\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}', subnet[1]):
- mask = fmgr._tools.cidr_to_netmask(subnet[1])
- subnet[1] = mask
-
- datagram["wildcard"] = subnet
-
- #########################
- # IF type = 'wildcard-fqdn'
- #########################
- if datagram["type"] == "wildcard-fqdn":
- datagram["wildcard-fqdn"] = paramgram["wildcard-fqdn"]
-
- #########################
- # IF type = 'fqdn'
- #########################
- if datagram["type"] == "fqdn":
- datagram["fqdn"] = paramgram["fqdn"]
-
- #########################
- # IF type = 'group'
- #########################
- if datagram["type"] == "group":
- datagram = {
- "comment": paramgram["comment"],
- "name": paramgram["group_name"],
- "color": paramgram["color"],
- "meta fields": {},
- "dynamic_mapping": [],
- "visibility": paramgram["visibility"]
- }
-
- members = []
- group_members = paramgram["group_members"].replace(" ", "")
- try:
- for member in group_members.split(","):
- members.append(member)
- except Exception:
- pass
-
- datagram["member"] = members
-
- # EVAL THE MODE PARAMETER FOR DELETE
- if paramgram["mode"] == "delete":
- # IF A GROUP, SET THE CORRECT NAME AND URL FOR THE GROUP ENDPOINT
- if paramgram["ipv4"] == "group":
- datagram = {}
- url = '/pm/config/adom/{adom}/obj/firewall/addrgrp/{name}'.format(adom=paramgram["adom"],
- name=paramgram["group_name"])
- # OTHERWISE WE'RE JUST GOING TO USE THE ADDRESS ENDPOINT
- else:
- datagram = {}
- url = '/pm/config/adom/{adom}/obj/firewall/address/{name}'.format(adom=paramgram["adom"],
- name=paramgram["name"])
-
- response = fmgr.process_request(url, datagram, paramgram["mode"])
- return response
-
-
-def fmgr_fwobj_ipv6(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
- # EVAL THE MODE PARAMETER FOR SET OR ADD
- if paramgram["mode"] in ['set', 'add']:
- # CREATE THE DATAGRAM DICTIONARY
- # ENSURE THE DATAGRAM KEYS MATCH THE JSON API GUIDE ATTRIBUTES, NOT WHAT IS IN ANSIBLE
- # SOME PARAMETERS SHOWN IN THIS DICTIONARY WE DON'T EVEN ASK THE USER FOR IN PLAYBOOKS BUT ARE REQUIRED
- datagram = {
- "comment": paramgram["comment"],
- "name": paramgram["name"],
- "color": paramgram["color"],
- "dynamic_mapping": [],
- "visibility": paramgram["visibility"],
- "type": paramgram["ipv6"]
- }
-
- # SET THE CORRECT URL BASED ON THE TYPE (WE'RE DOING GROUPS IN THIS METHOD, TOO)
- if datagram["type"] == "group":
- url = '/pm/config/adom/{adom}/obj/firewall/addrgrp6'.format(adom=paramgram["adom"])
- else:
- url = '/pm/config/adom/{adom}/obj/firewall/address6'.format(adom=paramgram["adom"])
-
- #########################
- # IF type = 'ip'
- #########################
- if datagram["type"] == "ip":
- datagram["type"] = "ipprefix"
- datagram["ip6"] = paramgram["ipv6addr"]
-
- #########################
- # IF type = 'iprange'
- #########################
- if datagram["type"] == "iprange":
- datagram["start-ip"] = paramgram["start-ip"]
- datagram["end-ip"] = paramgram["end-ip"]
-
- #########################
- # IF type = 'group'
- #########################
- if datagram["type"] == "group":
- datagram = None
- datagram = {
- "comment": paramgram["comment"],
- "name": paramgram["group_name"],
- "color": paramgram["color"],
- "visibility": paramgram["visibility"]
- }
-
- members = []
- group_members = paramgram["group_members"].replace(" ", "")
- try:
- for member in group_members.split(","):
- members.append(member)
- except Exception:
- pass
-
- datagram["member"] = members
-
- # EVAL THE MODE PARAMETER FOR DELETE
- if paramgram["mode"] == "delete":
- # IF A GROUP, SET THE CORRECT NAME AND URL FOR THE GROUP ENDPOINT
- if paramgram["ipv6"] == "group":
- datagram = {}
- url = '/pm/config/adom/{adom}/obj/firewall/addrgrp6/{name}'.format(adom=paramgram["adom"],
- name=paramgram["group_name"])
- # OTHERWISE WE'RE JUST GOING TO USE THE ADDRESS ENDPOINT
- else:
- datagram = {}
- url = '/pm/config/adom/{adom}/obj/firewall/address6/{name}'.format(adom=paramgram["adom"],
- name=paramgram["name"])
-
- response = fmgr.process_request(url, datagram, paramgram["mode"])
- return response
-
-
-def fmgr_fwobj_multicast(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
- # EVAL THE MODE PARAMETER FOR SET OR ADD
- if paramgram["mode"] in ['set', 'add']:
- # CREATE THE DATAGRAM DICTIONARY
- # ENSURE THE DATAGRAM KEYS MATCH THE JSON API GUIDE ATTRIBUTES, NOT WHAT IS IN ANSIBLE
- # SOME PARAMETERS SHOWN IN THIS DICTIONARY WE DON'T EVEN ASK THE USER FOR IN PLAYBOOKS BUT ARE REQUIRED
- datagram = {
- "associated-interface": paramgram["associated-interface"],
- "comment": paramgram["comment"],
- "name": paramgram["name"],
- "color": paramgram["color"],
- "type": paramgram["multicast"],
- "visibility": paramgram["visibility"],
- }
-
- # SET THE CORRECT URL
- url = '/pm/config/adom/{adom}/obj/firewall/multicast-address'.format(adom=paramgram["adom"])
-
- #########################
- # IF type = 'multicastrange'
- #########################
- if paramgram["multicast"] == "multicastrange":
- datagram["start-ip"] = paramgram["start-ip"]
- datagram["end-ip"] = paramgram["end-ip"]
- datagram["subnet"] = ["0.0.0.0", "0.0.0.0"]
-
- #########################
- # IF type = 'broadcastmask'
- #########################
- if paramgram["multicast"] == "broadcastmask":
- # EVAL THE IPV4ADDR INPUT AND SPLIT THE IP ADDRESS FROM THE MASK AND APPEND THEM TO THE SUBNET LIST
- subnet = []
- for subnets in paramgram["ipv4addr"].split("/"):
- subnet.append(subnets)
- # CHECK THAT THE SECOND ENTRY IN THE SUBNET LIST (WHAT WAS TO THE RIGHT OF THE / CHARACTER)
- # IS IN SUBNET MASK FORMAT AND NOT CIDR FORMAT.
- # IF IT IS IN CIDR FORMAT, WE NEED TO CONVERT IT TO SUBNET BIT MASK FORMAT FOR THE JSON API
- if not re.match(r'\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}', subnet[1]):
- # IF THE SUBNET PARAMETER INPUT DIDN'T LOOK LIKE 255.255.255.255 TO REGEX...
- # ... RUN IT THROUGH THE fmgr_cidr_to_netmask() FUNCTION
- mask = fmgr._tools.cidr_to_netmask(subnet[1])
- # AND THEN UPDATE THE SUBNET LIST OBJECT
- subnet[1] = mask
-
- # INCLUDE THE SUBNET LIST OBJECT IN THE DATAGRAM DICTIONARY TO BE SUBMITTED
- datagram["subnet"] = subnet
-
- # EVAL THE MODE PARAMETER FOR DELETE
- if paramgram["mode"] == "delete":
- datagram = {
- "name": paramgram["name"]
- }
- # SET THE CORRECT URL FOR DELETE
- url = '/pm/config/adom/{adom}/obj/firewall/multicast-address/{name}'.format(adom=paramgram["adom"],
- name=paramgram["name"])
-
- response = fmgr.process_request(url, datagram, paramgram["mode"])
- return response
-
-
-def main():
- argument_spec = dict(
- adom=dict(required=False, type="str", default="root"),
- mode=dict(choices=["add", "set", "delete"], type="str", default="add"),
-
- allow_routing=dict(required=False, type="str", choices=['enable', 'disable'], default="disable"),
- associated_interface=dict(required=False, type="str"),
- cache_ttl=dict(required=False, type="str"),
- color=dict(required=False, type="str", default=22),
- comment=dict(required=False, type="str"),
- country=dict(required=False, type="str"),
- fqdn=dict(required=False, type="str"),
- name=dict(required=False, type="str"),
- start_ip=dict(required=False, type="str"),
- end_ip=dict(required=False, type="str"),
- ipv4=dict(required=False, type="str", choices=['ipmask', 'iprange', 'fqdn', 'wildcard',
- 'geography', 'wildcard-fqdn', 'group']),
- visibility=dict(required=False, type="str", choices=['enable', 'disable'], default="enable"),
- wildcard=dict(required=False, type="str"),
- wildcard_fqdn=dict(required=False, type="str"),
- ipv6=dict(required=False, type="str", choices=['ip', 'iprange', 'group']),
- group_members=dict(required=False, type="str"),
- group_name=dict(required=False, type="str"),
- ipv4addr=dict(required=False, type="str"),
- ipv6addr=dict(required=False, type="str"),
- multicast=dict(required=False, type="str", choices=['multicastrange', 'broadcastmask', 'ip6']),
- obj_id=dict(required=False, type="str"),
-
- )
-
- module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False,
- mutually_exclusive=[
- ['ipv4', 'ipv6'],
- ['ipv4', 'multicast'],
- ['ipv6', 'multicast']
- ])
- paramgram = {
- "adom": module.params["adom"],
- "allow-routing": module.params["allow_routing"],
- "associated-interface": module.params["associated_interface"],
- "cache-ttl": module.params["cache_ttl"],
- "color": module.params["color"],
- "comment": module.params["comment"],
- "country": module.params["country"],
- "end-ip": module.params["end_ip"],
- "fqdn": module.params["fqdn"],
- "name": module.params["name"],
- "start-ip": module.params["start_ip"],
- "visibility": module.params["visibility"],
- "wildcard": module.params["wildcard"],
- "wildcard-fqdn": module.params["wildcard_fqdn"],
- "ipv6": module.params["ipv6"],
- "ipv4": module.params["ipv4"],
- "group_members": module.params["group_members"],
- "group_name": module.params["group_name"],
- "ipv4addr": module.params["ipv4addr"],
- "ipv6addr": module.params["ipv6addr"],
- "multicast": module.params["multicast"],
- "mode": module.params["mode"],
- "obj-id": module.params["obj_id"],
- }
-
- module.paramgram = paramgram
- fmgr = None
- if module._socket_path:
- connection = Connection(module._socket_path)
- fmgr = FortiManagerHandler(connection, module)
- fmgr._tools = FMGRCommon()
- else:
- module.fail_json(**FAIL_SOCKET_MSG)
-
- results = DEFAULT_RESULT_OBJ
- try:
- if paramgram["ipv4"]:
- results = fmgr_fwobj_ipv4(fmgr, paramgram)
-
- elif paramgram["ipv6"]:
- results = fmgr_fwobj_ipv6(fmgr, paramgram)
-
- elif paramgram["multicast"]:
- results = fmgr_fwobj_multicast(fmgr, paramgram)
-
- fmgr.govern_response(module=module, results=results,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
-
- except Exception as err:
- raise FMGBaseException(err)
-
- if results is not None:
- return module.exit_json(**results[1])
- else:
- return module.exit_json(msg="Couldn't find a proper ipv4 or ipv6 or multicast parameter "
- "to run in the logic tree. Exiting...")
-
-
-if __name__ == "__main__":
- main()
diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_fwobj_ippool.py b/ansible_collections/community/fortios/plugins/modules/fmgr_fwobj_ippool.py
deleted file mode 100644
index a0b39ab16..000000000
--- a/ansible_collections/community/fortios/plugins/modules/fmgr_fwobj_ippool.py
+++ /dev/null
@@ -1,442 +0,0 @@
-#!/usr/bin/python
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-DOCUMENTATION = '''
----
-module: fmgr_fwobj_ippool
-notes:
- - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
-author:
- - Luke Weighall (@lweighall)
- - Andrew Welsh (@Ghilli3)
- - Jim Huber (@p4r4n0y1ng)
-short_description: Allows the editing of IP Pool Objects within FortiManager.
-description:
- - Allows users to add/edit/delete IP Pool Objects.
-
-options:
- adom:
- description:
- - The ADOM the configuration should belong to.
- required: false
- default: root
-
- mode:
- description:
- - Sets one of three modes for managing the object.
- - Allows use of soft-adds instead of overwriting existing values
- choices: ['add', 'set', 'delete', 'update']
- required: false
- default: add
-
- type:
- description:
- - IP pool type (overload, one-to-one, fixed port range, or port block allocation).
- - choice | overload | IP addresses in the IP pool can be shared by clients.
- - choice | one-to-one | One to one mapping.
- - choice | fixed-port-range | Fixed port range.
- - choice | port-block-allocation | Port block allocation.
- required: false
- choices: ["overload", "one-to-one", "fixed-port-range", "port-block-allocation"]
-
- startip:
- description:
- - First IPv4 address (inclusive) in the range for the address pool (format xxx.xxx.xxx.xxx, Default| 0.0.0.0).
- required: false
-
- source_startip:
- description:
- - First IPv4 address (inclusive) in the range of the source addresses to be translated (format xxx.xxx.xxx.xxx,
- Default| 0.0.0.0).
- required: false
-
- source_endip:
- description:
- - Final IPv4 address (inclusive) in the range of the source addresses to be translated (format xxx.xxx.xxx.xxx,
- Default| 0.0.0.0).
- required: false
-
- permit_any_host:
- description:
- - Enable/disable full cone NAT.
- - choice | disable | Disable full cone NAT.
- - choice | enable | Enable full cone NAT.
- required: false
- choices: ["disable", "enable"]
-
- pba_timeout:
- description:
- - Port block allocation timeout (seconds).
- required: false
-
- num_blocks_per_user:
- description:
- - Number of addresses blocks that can be used by a user (1 to 128, default = 8).
- required: false
-
- name:
- description:
- - IP pool name.
- required: false
-
- endip:
- description:
- - Final IPv4 address (inclusive) in the range for the address pool (format xxx.xxx.xxx.xxx, Default| 0.0.0.0).
- required: false
-
- comments:
- description:
- - Comment.
- required: false
-
- block_size:
- description:
- - Number of addresses in a block (64 to 4096, default = 128).
- required: false
-
- associated_interface:
- description:
- - Associated interface name.
- required: false
-
- arp_reply:
- description:
- - Enable/disable replying to ARP requests when an IP Pool is added to a policy (default = enable).
- - choice | disable | Disable ARP reply.
- - choice | enable | Enable ARP reply.
- required: false
- choices: ["disable", "enable"]
-
- arp_intf:
- description:
- - Select an interface from available options that will reply to ARP requests. (If blank, any is selected).
- required: false
-
- dynamic_mapping:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameter.ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- dynamic_mapping_arp_intf:
- description:
- - Dynamic Mapping clone of original suffixed parameter.
- required: false
-
- dynamic_mapping_arp_reply:
- description:
- - Dynamic Mapping clone of original suffixed parameter.
- required: false
- choices: ["disable", "enable"]
-
- dynamic_mapping_associated_interface:
- description:
- - Dynamic Mapping clone of original suffixed parameter.
- required: false
-
- dynamic_mapping_block_size:
- description:
- - Dynamic Mapping clone of original suffixed parameter.
- required: false
-
- dynamic_mapping_comments:
- description:
- - Dynamic Mapping clone of original suffixed parameter.
- required: false
-
- dynamic_mapping_endip:
- description:
- - Dynamic Mapping clone of original suffixed parameter.
- required: false
-
- dynamic_mapping_num_blocks_per_user:
- description:
- - Dynamic Mapping clone of original suffixed parameter.
- required: false
-
- dynamic_mapping_pba_timeout:
- description:
- - Dynamic Mapping clone of original suffixed parameter.
- required: false
-
- dynamic_mapping_permit_any_host:
- description:
- - Dynamic Mapping clone of original suffixed parameter.
- required: false
- choices: ["disable", "enable"]
-
- dynamic_mapping_source_endip:
- description:
- - Dynamic Mapping clone of original suffixed parameter.
- required: false
-
- dynamic_mapping_source_startip:
- description:
- - Dynamic Mapping clone of original suffixed parameter.
- required: false
-
- dynamic_mapping_startip:
- description:
- - Dynamic Mapping clone of original suffixed parameter.
- required: false
-
- dynamic_mapping_type:
- description:
- - Dynamic Mapping clone of original suffixed parameter.
- required: false
- choices: ["overload", "one-to-one", "fixed-port-range", "port-block-allocation"]
-
-
-'''
-
-EXAMPLES = '''
-- name: ADD FMGR_FIREWALL_IPPOOL Overload
- community.fortios.fmgr_fwobj_ippool:
- mode: "add"
- adom: "ansible"
- name: "Ansible_pool4_overload"
- comments: "Created by ansible"
- type: "overload"
-
- # OPTIONS FOR ALL MODES
- startip: "10.10.10.10"
- endip: "10.10.10.100"
- arp_reply: "enable"
-
-- name: ADD FMGR_FIREWALL_IPPOOL one-to-one
- community.fortios.fmgr_fwobj_ippool:
- mode: "add"
- adom: "ansible"
- name: "Ansible_pool4_121"
- comments: "Created by ansible"
- type: "one-to-one"
-
- # OPTIONS FOR ALL MODES
- startip: "10.10.20.10"
- endip: "10.10.20.100"
- arp_reply: "enable"
-
-- name: ADD FMGR_FIREWALL_IPPOOL FIXED PORT RANGE
- community.fortios.fmgr_fwobj_ippool:
- mode: "add"
- adom: "ansible"
- name: "Ansible_pool4_fixed_port"
- comments: "Created by ansible"
- type: "fixed-port-range"
-
- # OPTIONS FOR ALL MODES
- startip: "10.10.40.10"
- endip: "10.10.40.100"
- arp_reply: "enable"
- # FIXED PORT RANGE OPTIONS
- source_startip: "192.168.20.1"
- source_endip: "192.168.20.20"
-
-- name: ADD FMGR_FIREWALL_IPPOOL PORT BLOCK ALLOCATION
- community.fortios.fmgr_fwobj_ippool:
- mode: "add"
- adom: "ansible"
- name: "Ansible_pool4_port_block_allocation"
- comments: "Created by ansible"
- type: "port-block-allocation"
-
- # OPTIONS FOR ALL MODES
- startip: "10.10.30.10"
- endip: "10.10.30.100"
- arp_reply: "enable"
- # PORT BLOCK ALLOCATION OPTIONS
- block_size: "128"
- num_blocks_per_user: "1"
-'''
-
-RETURN = """
-api_result:
- description: full API response, includes status code and message
- returned: always
- type: str
-"""
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.connection import Connection
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import prepare_dict
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import scrub_dict
-
-
-###############
-# START METHODS
-###############
-
-
-def fmgr_fwobj_ippool_modify(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
-
- mode = paramgram["mode"]
- adom = paramgram["adom"]
- # INIT A BASIC OBJECTS
- response = DEFAULT_RESULT_OBJ
- url = ""
- datagram = {}
-
- # EVAL THE MODE PARAMETER FOR SET OR ADD
- if mode in ['set', 'add', 'update']:
- url = '/pm/config/adom/{adom}/obj/firewall/ippool'.format(adom=adom)
- datagram = scrub_dict(prepare_dict(paramgram))
-
- # EVAL THE MODE PARAMETER FOR DELETE
- elif mode == "delete":
- # SET THE CORRECT URL FOR DELETE
- url = '/pm/config/adom/{adom}/obj/firewall/ippool/{name}'.format(adom=adom, name=paramgram["name"])
- datagram = {}
-
- response = fmgr.process_request(url, datagram, paramgram["mode"])
-
- return response
-
-
-#############
-# END METHODS
-#############
-
-
-def main():
- argument_spec = dict(
- adom=dict(type="str", default="root"),
- mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),
-
- type=dict(required=False, type="str", choices=["overload",
- "one-to-one",
- "fixed-port-range",
- "port-block-allocation"]),
- startip=dict(required=False, type="str"),
- source_startip=dict(required=False, type="str"),
- source_endip=dict(required=False, type="str"),
- permit_any_host=dict(required=False, type="str", choices=["disable", "enable"]),
- pba_timeout=dict(required=False, type="int"),
- num_blocks_per_user=dict(required=False, type="int"),
- name=dict(required=False, type="str"),
- endip=dict(required=False, type="str"),
- comments=dict(required=False, type="str"),
- block_size=dict(required=False, type="int"),
- associated_interface=dict(required=False, type="str"),
- arp_reply=dict(required=False, type="str", choices=["disable", "enable"]),
- arp_intf=dict(required=False, type="str"),
- dynamic_mapping=dict(required=False, type="list"),
- dynamic_mapping_arp_intf=dict(required=False, type="str"),
- dynamic_mapping_arp_reply=dict(required=False, type="str", choices=["disable", "enable"]),
- dynamic_mapping_associated_interface=dict(required=False, type="str"),
- dynamic_mapping_block_size=dict(required=False, type="int"),
- dynamic_mapping_comments=dict(required=False, type="str"),
- dynamic_mapping_endip=dict(required=False, type="str"),
- dynamic_mapping_num_blocks_per_user=dict(required=False, type="int"),
- dynamic_mapping_pba_timeout=dict(required=False, type="int"),
- dynamic_mapping_permit_any_host=dict(required=False, type="str", choices=["disable", "enable"]),
- dynamic_mapping_source_endip=dict(required=False, type="str"),
- dynamic_mapping_source_startip=dict(required=False, type="str"),
- dynamic_mapping_startip=dict(required=False, type="str"),
- dynamic_mapping_type=dict(required=False, type="str", choices=["overload",
- "one-to-one",
- "fixed-port-range",
- "port-block-allocation"]),
-
- )
-
- module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
- # MODULE PARAMGRAM
- paramgram = {
- "mode": module.params["mode"],
- "adom": module.params["adom"],
- "type": module.params["type"],
- "startip": module.params["startip"],
- "source-startip": module.params["source_startip"],
- "source-endip": module.params["source_endip"],
- "permit-any-host": module.params["permit_any_host"],
- "pba-timeout": module.params["pba_timeout"],
- "num-blocks-per-user": module.params["num_blocks_per_user"],
- "name": module.params["name"],
- "endip": module.params["endip"],
- "comments": module.params["comments"],
- "block-size": module.params["block_size"],
- "associated-interface": module.params["associated_interface"],
- "arp-reply": module.params["arp_reply"],
- "arp-intf": module.params["arp_intf"],
- "dynamic_mapping": {
- "arp-intf": module.params["dynamic_mapping_arp_intf"],
- "arp-reply": module.params["dynamic_mapping_arp_reply"],
- "associated-interface": module.params["dynamic_mapping_associated_interface"],
- "block-size": module.params["dynamic_mapping_block_size"],
- "comments": module.params["dynamic_mapping_comments"],
- "endip": module.params["dynamic_mapping_endip"],
- "num-blocks-per-user": module.params["dynamic_mapping_num_blocks_per_user"],
- "pba-timeout": module.params["dynamic_mapping_pba_timeout"],
- "permit-any-host": module.params["dynamic_mapping_permit_any_host"],
- "source-endip": module.params["dynamic_mapping_source_endip"],
- "source-startip": module.params["dynamic_mapping_source_startip"],
- "startip": module.params["dynamic_mapping_startip"],
- "type": module.params["dynamic_mapping_type"],
- }
- }
-
- module.paramgram = paramgram
- fmgr = None
- if module._socket_path:
- connection = Connection(module._socket_path)
- fmgr = FortiManagerHandler(connection, module)
- fmgr.tools = FMGRCommon()
- else:
- module.fail_json(**FAIL_SOCKET_MSG)
-
- list_overrides = ['dynamic_mapping']
- paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
- paramgram=paramgram, module=module)
- # UPDATE THE CHANGED PARAMGRAM
- module.paramgram = paramgram
-
- results = DEFAULT_RESULT_OBJ
- try:
- results = fmgr_fwobj_ippool_modify(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
-
- except Exception as err:
- raise FMGBaseException(err)
-
- return module.exit_json(**results[1])
-
-
-if __name__ == "__main__":
- main()
diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_fwobj_ippool6.py b/ansible_collections/community/fortios/plugins/modules/fmgr_fwobj_ippool6.py
deleted file mode 100644
index 15e8977fa..000000000
--- a/ansible_collections/community/fortios/plugins/modules/fmgr_fwobj_ippool6.py
+++ /dev/null
@@ -1,223 +0,0 @@
-#!/usr/bin/python
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-DOCUMENTATION = '''
----
-module: fmgr_fwobj_ippool6
-notes:
- - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
-author:
- - Luke Weighall (@lweighall)
- - Andrew Welsh (@Ghilli3)
- - Jim Huber (@p4r4n0y1ng)
-short_description: Allows the editing of IP Pool Objects within FortiManager.
-description:
- - Allows users to add/edit/delete IPv6 Pool Objects.
-
-options:
- adom:
- description:
- - The ADOM the configuration should belong to.
- required: false
- default: root
-
- mode:
- description:
- - Sets one of three modes for managing the object.
- - Allows use of soft-adds instead of overwriting existing values
- choices: ['add', 'set', 'delete', 'update']
- required: false
- default: add
-
- startip:
- description:
- - First IPv6 address (inclusive) in the range for the address pool.
- required: false
-
- name:
- description:
- - IPv6 IP pool name.
- required: false
-
- endip:
- description:
- - Final IPv6 address (inclusive) in the range for the address pool.
- required: false
-
- comments:
- description:
- - Comment.
- required: false
-
- dynamic_mapping:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- dynamic_mapping_comments:
- description:
- - Dynamic Mapping clone of original suffixed parameter.
- required: false
-
- dynamic_mapping_endip:
- description:
- - Dynamic Mapping clone of original suffixed parameter.
- required: false
-
- dynamic_mapping_startip:
- description:
- - Dynamic Mapping clone of original suffixed parameter.
- required: false
-
-
-'''
-
-EXAMPLES = '''
-- name: ADD FMGR_FIREWALL_IPPOOL6
- fmgr_firewall_ippool6:
- mode: "add"
- adom: "ansible"
- startip:
- name: "IPv6 IPPool"
- endip:
- comments: "Created by Ansible"
-
-- name: DELETE FMGR_FIREWALL_IPPOOL6
- fmgr_firewall_ippool6:
- mode: "delete"
- adom: "ansible"
- name: "IPv6 IPPool"
-'''
-
-RETURN = """
-api_result:
- description: full API response, includes status code and message
- returned: always
- type: str
-"""
-
-from ansible.module_utils.basic import AnsibleModule, env_fallback
-from ansible.module_utils.connection import Connection
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import prepare_dict
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import scrub_dict
-
-
-def fmgr_fwobj_ippool6_modify(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
-
- mode = paramgram["mode"]
- adom = paramgram["adom"]
- # INIT A BASIC OBJECTS
- response = DEFAULT_RESULT_OBJ
- url = ""
- datagram = {}
-
- # EVAL THE MODE PARAMETER FOR SET OR ADD
- if mode in ['set', 'add', 'update']:
- url = '/pm/config/adom/{adom}/obj/firewall/ippool6'.format(adom=adom)
- datagram = scrub_dict(prepare_dict(paramgram))
-
- # EVAL THE MODE PARAMETER FOR DELETE
- elif mode == "delete":
- # SET THE CORRECT URL FOR DELETE
- url = '/pm/config/adom/{adom}/obj/firewall/ippool6/{name}'.format(adom=adom, name=paramgram["name"])
- datagram = {}
-
- response = fmgr.process_request(url, datagram, paramgram["mode"])
- return response
-
-
-def main():
- argument_spec = dict(
- adom=dict(type="str", default="root"),
- mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),
- startip=dict(required=False, type="str"),
- name=dict(required=False, type="str"),
- endip=dict(required=False, type="str"),
- comments=dict(required=False, type="str"),
- dynamic_mapping=dict(required=False, type="list"),
- dynamic_mapping_comments=dict(required=False, type="str"),
- dynamic_mapping_endip=dict(required=False, type="str"),
- dynamic_mapping_startip=dict(required=False, type="str"),
-
- )
-
- module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
- # MODULE PARAMGRAM
- paramgram = {
- "mode": module.params["mode"],
- "adom": module.params["adom"],
- "startip": module.params["startip"],
- "name": module.params["name"],
- "endip": module.params["endip"],
- "comments": module.params["comments"],
- "dynamic_mapping": {
- "comments": module.params["dynamic_mapping_comments"],
- "endip": module.params["dynamic_mapping_endip"],
- "startip": module.params["dynamic_mapping_startip"],
- }
- }
- module.paramgram = paramgram
- fmgr = None
- if module._socket_path:
- connection = Connection(module._socket_path)
- fmgr = FortiManagerHandler(connection, module)
- fmgr.tools = FMGRCommon()
- else:
- module.fail_json(**FAIL_SOCKET_MSG)
-
- list_overrides = ['dynamic_mapping']
- paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
- paramgram=paramgram, module=module)
-
- results = DEFAULT_RESULT_OBJ
-
- try:
- results = fmgr_fwobj_ippool6_modify(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
-
- except Exception as err:
- raise FMGBaseException(err)
-
- return module.exit_json(**results[1])
-
-
-if __name__ == "__main__":
- main()
diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_fwobj_service.py b/ansible_collections/community/fortios/plugins/modules/fmgr_fwobj_service.py
deleted file mode 100644
index fb8a3597f..000000000
--- a/ansible_collections/community/fortios/plugins/modules/fmgr_fwobj_service.py
+++ /dev/null
@@ -1,617 +0,0 @@
-#!/usr/bin/python
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-
-from __future__ import absolute_import, division, print_function
-
-__metaclass__ = type
-
-DOCUMENTATION = '''
----
-module: fmgr_fwobj_service
-notes:
- - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
-author:
- - Luke Weighall (@lweighall)
- - Andrew Welsh (@Ghilli3)
- - Jim Huber (@p4r4n0y1ng)
-short_description: Manages FortiManager Firewall Service Objects.
-description:
- - Manages FortiManager Firewall Service Objects.
-
-options:
- adom:
- description:
- -The ADOM the configuration should belong to.
- required: false
- default: root
-
- app_category:
- description:
- - Application category ID.
- required: false
-
- app_service_type:
- description:
- - Application service type.
- required: false
-
- application:
- description:
- - Application ID.
- required: false
-
- category:
- description:
- - Service category.
- required: false
-
- check_reset_range:
- description:
- - Enable disable RST check.
- required: false
-
- color:
- description:
- - GUI icon color.
- required: false
- default: 22
-
- comment:
- description:
- - Comment.
- required: false
-
- custom_type:
- description:
- - Tells module what kind of custom service to be added.
- choices: ['tcp_udp_sctp', 'icmp', 'icmp6', 'ip', 'http', 'ftp', 'connect', 'socks_tcp', 'socks_udp', 'all']
- default: all
- required: false
-
- explicit_proxy:
- description:
- - Enable/disable explicit web proxy service.
- choices: ['enable', 'disable']
- default: 'disable'
- required: false
-
- fqdn:
- description:
- - Fully qualified domain name.
- required: false
- default: ""
-
- group_name:
- description:
- - Name of the Service Group.
- required: false
-
- group_member:
- description:
- - Comma-Seperated list of members' names.
- required: false
-
- icmp_code:
- description:
- - ICMP code.
- required: false
-
- icmp_type:
- description:
- - ICMP type.
- required: false
-
- iprange:
- description:
- - Start IP-End IP.
- required: false
- default: "0.0.0.0"
-
- name:
- description:
- - Custom service name.
- required: false
-
- mode:
- description:
- - Sets one of three modes for managing the object.
- choices: ['add', 'set', 'delete']
- default: add
- required: false
-
- object_type:
- description:
- - Tells module if we are adding a custom service, category, or group.
- choices: ['custom', 'group', 'category']
- required: false
-
- protocol:
- description:
- - Protocol type.
- required: false
-
- protocol_number:
- description:
- - IP protocol number.
- required: false
-
- sctp_portrange:
- description:
- - Multiple SCTP port ranges. Comma separated list of destination ports to add (i.e. '443,80').
- - Syntax is <destPort:sourcePort>
- - If no sourcePort is defined, it assumes all of them.
- - Ranges can be defined with a hyphen -
- - Examples -- '443' (destPort 443 only) '443:1000-2000' (destPort 443 from source ports 1000-2000).
- - String multiple together in same quotes, comma separated. ('443:1000-2000, 80:1000-2000').
- required: false
-
- session_ttl:
- description:
- - Session TTL (300 - 604800, 0 = default).
- required: false
- default: 0
-
- tcp_halfclose_timer:
- description:
- - TCP half close timeout (1 - 86400 sec, 0 = default).
- required: false
- default: 0
-
- tcp_halfopen_timer:
- description:
- - TCP half close timeout (1 - 86400 sec, 0 = default).
- required: false
- default: 0
-
- tcp_portrange:
- description:
- - Comma separated list of destination ports to add (i.e. '443,80').
- - Syntax is <destPort:sourcePort>
- - If no sourcePort is defined, it assumes all of them.
- - Ranges can be defined with a hyphen -
- - Examples -- '443' (destPort 443 only) '443:1000-2000' (destPort 443 from source ports 1000-2000).
- - String multiple together in same quotes, comma separated. ('443:1000-2000, 80:1000-2000').
- required: false
-
- tcp_timewait_timer:
- description:
- - TCP half close timeout (1 - 300 sec, 0 = default).
- required: false
- default: 0
-
- udp_idle_timer:
- description:
- - TCP half close timeout (0 - 86400 sec, 0 = default).
- required: false
- default: 0
-
- udp_portrange:
- description:
- - Comma separated list of destination ports to add (i.e. '443,80').
- - Syntax is <destPort:sourcePort>
- - If no sourcePort is defined, it assumes all of them.
- - Ranges can be defined with a hyphen -
- - Examples -- '443' (destPort 443 only) '443:1000-2000' (destPort 443 from source ports 1000-2000).
- - String multiple together in same quotes, comma separated. ('443:1000-2000, 80:1000-2000').
- required: false
-
- visibility:
- description:
- - Enable/disable service visibility.
- required: false
- choices: ["enable", "disable"]
- default: "enable"
-
-'''
-
-EXAMPLES = '''
-- name: ADD A CUSTOM SERVICE FOR TCP/UDP/SCP
- community.fortios.fmgr_fwobj_service:
- adom: "ansible"
- name: "ansible_custom_service"
- object_type: "custom"
- custom_type: "tcp_udp_sctp"
- tcp_portrange: "443"
- udp_portrange: "51"
- sctp_portrange: "100"
-
-- name: ADD A CUSTOM SERVICE FOR TCP/UDP/SCP WITH SOURCE RANGES AND MULTIPLES
- community.fortios.fmgr_fwobj_service:
- adom: "ansible"
- name: "ansible_custom_serviceWithSource"
- object_type: "custom"
- custom_type: "tcp_udp_sctp"
- tcp_portrange: "443:2000-1000,80-82:10000-20000"
- udp_portrange: "51:100-200,162:200-400"
- sctp_portrange: "100:2000-2500"
-
-- name: ADD A CUSTOM SERVICE FOR ICMP
- community.fortios.fmgr_fwobj_service:
- adom: "ansible"
- name: "ansible_custom_icmp"
- object_type: "custom"
- custom_type: "icmp"
- icmp_type: "8"
- icmp_code: "3"
-
-- name: ADD A CUSTOM SERVICE FOR ICMP6
- community.fortios.fmgr_fwobj_service:
- adom: "ansible"
- name: "ansible_custom_icmp6"
- object_type: "custom"
- custom_type: "icmp6"
- icmp_type: "5"
- icmp_code: "1"
-
-- name: ADD A CUSTOM SERVICE FOR IP - GRE
- community.fortios.fmgr_fwobj_service:
- adom: "ansible"
- name: "ansible_custom_icmp6"
- object_type: "custom"
- custom_type: "ip"
- protocol_number: "47"
-
-- name: ADD A CUSTOM PROXY FOR ALL WITH SOURCE RANGES AND MULTIPLES
- community.fortios.fmgr_fwobj_service:
- adom: "ansible"
- name: "ansible_custom_proxy_all"
- object_type: "custom"
- custom_type: "all"
- explicit_proxy: "enable"
- tcp_portrange: "443:2000-1000,80-82:10000-20000"
- iprange: "www.ansible.com"
-'''
-
-RETURN = """
-api_result:
- description: full API response, includes status code and message
- returned: always
- type: str
-"""
-
-from ansible.module_utils.basic import AnsibleModule, env_fallback
-from ansible.module_utils.connection import Connection
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import scrub_dict
-
-
-def fmgr_fwobj_service_custom(fmgr, paramgram):
- """
- description:
- - the tcp and udp-portrange parameters are in a list when there are multiple. they are not in a list when they
- singular or by themselves (only 1 was listed)
- - the syntax for this is (destPort:sourcePort). Ranges are (xxxx-xxxx) i.e. 443:443, or 443:1000-2000.
- - if you leave out the second field after the colon (source port) it assumes any source port (which is usual)
- - multiples would look like ['443:1000-2000','80']
- - a single would look simple like "443:1000-2000" without the list around it ( a string!)
- - the protocol parameter is the protocol NUMBER, not the string of it.
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
- response = DEFAULT_RESULT_OBJ
- if paramgram["mode"] in ['set', 'add']:
- # SET THE URL FOR ADD / SET
- url = '/pm/config/adom/{adom}/obj/firewall/service/custom'.format(adom=paramgram["adom"])
- # BUILD THE DEFAULT DATAGRAM
- datagram = {
- # ADVANCED OPTIONS
- "app-category": paramgram["app-category"],
- "app-service-type": paramgram["app-service-type"],
- "application": paramgram["application"],
- "category": paramgram["category"],
- "check-reset-range": paramgram["check-reset-range"],
- "color": paramgram["color"],
- "session-ttl": paramgram["session-ttl"],
- "tcp-halfclose-timer": paramgram["tcp-halfclose-timer"],
- "tcp-halfopen-timer": paramgram["tcp-halfopen-timer"],
- "tcp-timewait-timer": paramgram["tcp-timewait-timer"],
- "udp-idle-timer": paramgram["udp-idle-timer"],
- "visibility": paramgram["visibility"],
- "comment": paramgram["comment"],
- "proxy": paramgram["explicit-proxy"],
- "name": paramgram["name"]
- }
-
- if datagram["proxy"] == "disable":
- #######################################
- # object-type = "TCP/UDP/SCTP"
- #######################################
- if paramgram["custom_type"] == "tcp_udp_sctp":
- datagram["protocol"] = "TCP/UDP/SCTP"
- # PROCESS PORT RANGES TO PUT INTO THE PROPER SYNTAX
- if paramgram["tcp-portrange"] is not None:
- tcp_list = []
- for tcp in paramgram["tcp-portrange"].split(","):
- tcp = tcp.strip()
- tcp_list.append(tcp)
- datagram["tcp-portrange"] = tcp_list
-
- if paramgram["udp-portrange"] is not None:
- udp_list = []
- for udp in paramgram["udp-portrange"].split(","):
- udp = udp.strip()
- udp_list.append(udp)
- datagram["udp-portrange"] = udp_list
-
- if paramgram["sctp-portrange"] is not None:
- sctp_list = []
- for sctp in paramgram["sctp-portrange"].split(","):
- sctp = sctp.strip()
- sctp_list.append(sctp)
- datagram["sctp-portrange"] = sctp_list
-
- #######################################
- # object-type = "ICMP"
- #######################################
- if paramgram["custom_type"] == "icmp":
- datagram["icmpcode"] = paramgram["icmp_code"]
- datagram["icmptype"] = paramgram["icmp_type"]
- datagram["protocol"] = "ICMP"
-
- #######################################
- # object-type = "ICMP6"
- #######################################
- if paramgram["custom_type"] == "icmp6":
- datagram["icmpcode"] = paramgram["icmp_code"]
- datagram["icmptype"] = paramgram["icmp_type"]
- datagram["protocol"] = "ICMP6"
-
- #######################################
- # object-type = "IP"
- #######################################
- if paramgram["custom_type"] == "ip":
- datagram["protocol"] = "IP"
- datagram["protocol-number"] = paramgram["protocol-number"]
-
- #######################################
- # object-type in any of the explicit proxy options
- #######################################
- if datagram["proxy"] == "enable":
- datagram["protocol"] = paramgram["custom_type"].upper()
- datagram["iprange"] = paramgram["iprange"]
-
- # PROCESS PROXY TCP PORT RANGES TO PUT INTO THE PROPER SYNTAX
- if paramgram["tcp-portrange"] is not None:
- tcp_list = []
- for tcp in paramgram["tcp-portrange"].split(","):
- tcp = tcp.strip()
- tcp_list.append(tcp)
- datagram["tcp-portrange"] = tcp_list
-
- if paramgram["mode"] == "delete":
- datagram = {
- "name": paramgram["name"]
- }
- # SET DELETE URL
- url = '/pm/config/adom/{adom}/obj/firewall/service/custom' \
- '/{name}'.format(adom=paramgram["adom"], name=paramgram["name"])
-
- datagram = scrub_dict(datagram)
- response = fmgr.process_request(url, datagram, paramgram["mode"])
- return response
-
-
-def fmgr_fwobj_service_group(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
- response = DEFAULT_RESULT_OBJ
- if paramgram["mode"] in ['set', 'add']:
- url = '/pm/config/adom/{adom}/obj/firewall/service/group'.format(adom=paramgram["adom"])
- datagram = {
- "name": paramgram["group-name"],
- "comment": paramgram["comment"],
- "proxy": paramgram["explicit-proxy"],
- "color": paramgram["color"]
- }
-
- members = paramgram["group-member"]
- member = []
- for obj in members.split(","):
- member.append(obj.strip())
- datagram["member"] = member
-
- if paramgram["mode"] == "delete":
- datagram = {
- "name": paramgram["name"]
- }
- # SET DELETE URL
- url = '/pm/config/adom/{adom}/obj/firewall/service/group' \
- '/{name}'.format(adom=paramgram["adom"], name=paramgram["group-name"])
-
- datagram = scrub_dict(datagram)
- response = fmgr.process_request(url, datagram, paramgram["mode"])
- return response
-
-
-def fmgr_fwobj_service_category(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
- response = DEFAULT_RESULT_OBJ
- if paramgram["mode"] in ['set', 'add']:
- url = '/pm/config/adom/{adom}/obj/firewall/service/category'.format(adom=paramgram["adom"])
- # GET RID OF ANY WHITESPACE
- category = paramgram["category"]
- category = category.strip()
-
- datagram = {
- "name": paramgram["category"],
- "comment": "Created by Ansible"
- }
-
- # IF MODE = DELETE
- if paramgram["mode"] == "delete":
- datagram = {
- "name": paramgram["name"]
- }
- # SET DELETE URL
- url = '/pm/config/adom/{adom}/obj/firewall/service/category' \
- '/{name}'.format(adom=paramgram["adom"], name=paramgram["category"])
-
- datagram = scrub_dict(datagram)
- response = fmgr.process_request(url, datagram, paramgram["mode"])
- return response
-
-
-def main():
- argument_spec = dict(
- adom=dict(required=False, type="str", default="root"),
- mode=dict(required=False, type="str", choices=['add', 'set', 'delete'], default="add"),
- app_category=dict(required=False, type="str"),
- app_service_type=dict(required=False, type="str"),
- application=dict(required=False, type="str"),
- category=dict(required=False, type="str"),
- check_reset_range=dict(required=False, type="str"),
- color=dict(required=False, type="int", default=22),
- comment=dict(required=False, type="str"),
- custom_type=dict(required=False, type="str", choices=['tcp_udp_sctp', 'icmp', 'icmp6', 'ip', 'http', 'ftp',
- 'connect', 'socks_tcp', 'socks_udp', 'all'],
- default="all"),
- explicit_proxy=dict(required=False, type="str", choices=['enable', 'disable'], default="disable"),
- fqdn=dict(required=False, type="str", default=""),
- group_name=dict(required=False, type="str"),
- group_member=dict(required=False, type="str"),
- icmp_code=dict(required=False, type="int"),
- icmp_type=dict(required=False, type="int"),
- iprange=dict(required=False, type="str", default="0.0.0.0"),
- name=dict(required=False, type="str"),
- protocol=dict(required=False, type="str"),
- protocol_number=dict(required=False, type="int"),
- sctp_portrange=dict(required=False, type="str"),
- session_ttl=dict(required=False, type="int", default=0),
- object_type=dict(required=False, type="str", choices=['custom', 'group', 'category']),
- tcp_halfclose_timer=dict(required=False, type="int", default=0),
- tcp_halfopen_timer=dict(required=False, type="int", default=0),
- tcp_portrange=dict(required=False, type="str"),
- tcp_timewait_timer=dict(required=False, type="int", default=0),
- udp_idle_timer=dict(required=False, type="int", default=0),
- udp_portrange=dict(required=False, type="str"),
- visibility=dict(required=False, type="str", default="enable", choices=["enable", "disable"]),
-
- )
-
- module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
- # MODULE DATAGRAM
- paramgram = {
- "adom": module.params["adom"],
- "app-category": module.params["app_category"],
- "app-service-type": module.params["app_service_type"],
- "application": module.params["application"],
- "category": module.params["category"],
- "check-reset-range": module.params["check_reset_range"],
- "color": module.params["color"],
- "comment": module.params["comment"],
- "custom_type": module.params["custom_type"],
- "explicit-proxy": module.params["explicit_proxy"],
- "fqdn": module.params["fqdn"],
- "group-name": module.params["group_name"],
- "group-member": module.params["group_member"],
- "icmp_code": module.params["icmp_code"],
- "icmp_type": module.params["icmp_type"],
- "iprange": module.params["iprange"],
- "name": module.params["name"],
- "mode": module.params["mode"],
- "protocol": module.params["protocol"],
- "protocol-number": module.params["protocol_number"],
- "sctp-portrange": module.params["sctp_portrange"],
- "object_type": module.params["object_type"],
- "session-ttl": module.params["session_ttl"],
- "tcp-halfclose-timer": module.params["tcp_halfclose_timer"],
- "tcp-halfopen-timer": module.params["tcp_halfopen_timer"],
- "tcp-portrange": module.params["tcp_portrange"],
- "tcp-timewait-timer": module.params["tcp_timewait_timer"],
- "udp-idle-timer": module.params["udp_idle_timer"],
- "udp-portrange": module.params["udp_portrange"],
- "visibility": module.params["visibility"],
- }
- module.paramgram = paramgram
- fmgr = None
- if module._socket_path:
- connection = Connection(module._socket_path)
- fmgr = FortiManagerHandler(connection, module)
- fmgr.tools = FMGRCommon()
- else:
- module.fail_json(**FAIL_SOCKET_MSG)
-
- results = DEFAULT_RESULT_OBJ
-
- try:
- # CHECK FOR CATEGORIES TO ADD
- # THIS IS ONLY WHEN OBJECT_TYPE ISN'T SPECIFICALLY ADDING A CATEGORY!
- # WE NEED TO ADD THE CATEGORY BEFORE ADDING THE OBJECT
- # IF ANY category ARE DEFINED AND MODE IS ADD OR SET LETS ADD THOSE
- # THIS IS A "BLIND ADD" AND THE EXIT CODE FOR OBJECT ALREADY EXISTS IS TREATED AS A PASS
- if paramgram["category"] is not None and paramgram["mode"] in ['add', 'set'] \
- and paramgram["object_type"] != "category":
- category_add = fmgr_fwobj_service_category(fmgr, paramgram)
- fmgr.govern_response(module=module, results=category_add,
- ansible_facts=fmgr.construct_ansible_facts(category_add, module.params, paramgram))
- except Exception as err:
- raise FMGBaseException(err)
-
- try:
- # IF OBJECT_TYPE IS CATEGORY...
- if paramgram["object_type"] == 'category':
- results = fmgr_fwobj_service_category(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results, good_codes=[0, -2, -3],
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
- except Exception as err:
- raise FMGBaseException(err)
-
- try:
- # IF OBJECT_TYPE IS CUSTOM...
- if paramgram["object_type"] == 'custom':
- results = fmgr_fwobj_service_custom(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results, good_codes=[0, -2, -3],
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
- except Exception as err:
- raise FMGBaseException(err)
-
- try:
- # IF OBJECT_TYPE IS GROUP...
- if paramgram["object_type"] == 'group':
- results = fmgr_fwobj_service_group(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results, good_codes=[0, -2, -3],
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
- except Exception as err:
- raise FMGBaseException(err)
-
- return module.exit_json(**results[1])
-
-
-if __name__ == "__main__":
- main()
diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_fwobj_vip.py b/ansible_collections/community/fortios/plugins/modules/fmgr_fwobj_vip.py
deleted file mode 100644
index adba2e495..000000000
--- a/ansible_collections/community/fortios/plugins/modules/fmgr_fwobj_vip.py
+++ /dev/null
@@ -1,2424 +0,0 @@
-#!/usr/bin/python
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-
-from __future__ import absolute_import, division, print_function
-
-__metaclass__ = type
-
-DOCUMENTATION = '''
----
-module: fmgr_fwobj_vip
-notes:
- - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
-author:
- - Luke Weighall (@lweighall)
- - Andrew Welsh (@Ghilli3)
- - Jim Huber (@p4r4n0y1ng)
-short_description: Manages Virtual IPs objects in FortiManager
-description:
- - Manages Virtual IP objects in FortiManager for IPv4
-
-options:
- adom:
- description:
- - The ADOM the configuration should belong to.
- required: false
- default: root
-
- mode:
- description:
- - Sets one of three modes for managing the object.
- - Allows use of soft-adds instead of overwriting existing values
- choices: ['add', 'set', 'delete', 'update']
- required: false
- default: add
-
- websphere_server:
- description:
- - Enable to add an HTTP header to indicate SSL offloading for a WebSphere server.
- - choice | disable | Do not add HTTP header indicating SSL offload for WebSphere server.
- - choice | enable | Add HTTP header indicating SSL offload for WebSphere server.
- required: false
- choices: ["disable", "enable"]
-
- weblogic_server:
- description:
- - Enable to add an HTTP header to indicate SSL offloading for a WebLogic server.
- - choice | disable | Do not add HTTP header indicating SSL offload for WebLogic server.
- - choice | enable | Add HTTP header indicating SSL offload for WebLogic server.
- required: false
- choices: ["disable", "enable"]
-
- type:
- description:
- - Configure a static NAT, load balance, server load balance, DNS translation, or FQDN VIP.
- - choice | static-nat | Static NAT.
- - choice | load-balance | Load balance.
- - choice | server-load-balance | Server load balance.
- - choice | dns-translation | DNS translation.
- - choice | fqdn | FQDN Translation
- required: false
- choices: ["static-nat", "load-balance", "server-load-balance", "dns-translation", "fqdn"]
-
- ssl_server_session_state_type:
- description:
- - How to expire SSL sessions for the segment of the SSL connection between the server and the FortiGate.
- - choice | disable | Do not keep session states.
- - choice | time | Expire session states after this many minutes.
- - choice | count | Expire session states when this maximum is reached.
- - choice | both | Expire session states based on time or count, whichever occurs first.
- required: false
- choices: ["disable", "time", "count", "both"]
-
- ssl_server_session_state_timeout:
- description:
- - Number of minutes to keep FortiGate to Server SSL session state.
- required: false
-
- ssl_server_session_state_max:
- description:
- - Maximum number of FortiGate to Server SSL session states to keep.
- required: false
-
- ssl_server_min_version:
- description:
- - Lowest SSL/TLS version acceptable from a server. Use the client setting by default.
- - choice | ssl-3.0 | SSL 3.0.
- - choice | tls-1.0 | TLS 1.0.
- - choice | tls-1.1 | TLS 1.1.
- - choice | tls-1.2 | TLS 1.2.
- - choice | client | Use same value as client configuration.
- required: false
- choices: ["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2", "client"]
-
- ssl_server_max_version:
- description:
- - Highest SSL/TLS version acceptable from a server. Use the client setting by default.
- - choice | ssl-3.0 | SSL 3.0.
- - choice | tls-1.0 | TLS 1.0.
- - choice | tls-1.1 | TLS 1.1.
- - choice | tls-1.2 | TLS 1.2.
- - choice | client | Use same value as client configuration.
- required: false
- choices: ["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2", "client"]
-
- ssl_server_algorithm:
- description:
- - Permitted encryption algorithms for the server side of SSL full mode sessions according to encryption strength
- - choice | high | High encryption. Allow only AES and ChaCha.
- - choice | low | Low encryption. Allow AES, ChaCha, 3DES, RC4, and DES.
- - choice | medium | Medium encryption. Allow AES, ChaCha, 3DES, and RC4.
- - choice | custom | Custom encryption. Use ssl-server-cipher-suites to select the cipher suites that are allowed.
- - choice | client | Use the same encryption algorithms for both client and server sessions.
- required: false
- choices: ["high", "low", "medium", "custom", "client"]
-
- ssl_send_empty_frags:
- description:
- - Enable/disable sending empty fragments to avoid CBC IV attacks (SSL 3.0 &amp; TLS 1.0 only).
- - choice | disable | Do not send empty fragments.
- - choice | enable | Send empty fragments.
- required: false
- choices: ["disable", "enable"]
-
- ssl_pfs:
- description:
- - Select the cipher suites that can be used for SSL perfect forward secrecy (PFS).
- - choice | require | Allow only Diffie-Hellman cipher-suites, so PFS is applied.
- - choice | deny | Allow only non-Diffie-Hellman cipher-suites, so PFS is not applied.
- - choice | allow | Allow use of any cipher suite so PFS may or may not be used depending on the cipher suite
- required: false
- choices: ["require", "deny", "allow"]
-
- ssl_mode:
- description:
- - Apply SSL offloading mode
- - choice | half | Client to FortiGate SSL.
- - choice | full | Client to FortiGate and FortiGate to Server SSL.
- required: false
- choices: ["half", "full"]
-
- ssl_min_version:
- description:
- - Lowest SSL/TLS version acceptable from a client.
- - choice | ssl-3.0 | SSL 3.0.
- - choice | tls-1.0 | TLS 1.0.
- - choice | tls-1.1 | TLS 1.1.
- - choice | tls-1.2 | TLS 1.2.
- required: false
- choices: ["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]
-
- ssl_max_version:
- description:
- - Highest SSL/TLS version acceptable from a client.
- - choice | ssl-3.0 | SSL 3.0.
- - choice | tls-1.0 | TLS 1.0.
- - choice | tls-1.1 | TLS 1.1.
- - choice | tls-1.2 | TLS 1.2.
- required: false
- choices: ["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]
-
- ssl_http_match_host:
- description:
- - Enable/disable HTTP host matching for location conversion.
- - choice | disable | Do not match HTTP host.
- - choice | enable | Match HTTP host in response header.
- required: false
- choices: ["disable", "enable"]
-
- ssl_http_location_conversion:
- description:
- - Enable to replace HTTP with HTTPS in the reply's Location HTTP header field.
- - choice | disable | Disable HTTP location conversion.
- - choice | enable | Enable HTTP location conversion.
- required: false
- choices: ["disable", "enable"]
-
- ssl_hsts_include_subdomains:
- description:
- - Indicate that HSTS header applies to all subdomains.
- - choice | disable | HSTS header does not apply to subdomains.
- - choice | enable | HSTS header applies to subdomains.
- required: false
- choices: ["disable", "enable"]
-
- ssl_hsts_age:
- description:
- - Number of seconds the client should honour the HSTS setting.
- required: false
-
- ssl_hsts:
- description:
- - Enable/disable including HSTS header in response.
- - choice | disable | Do not add a HSTS header to each a HTTP response.
- - choice | enable | Add a HSTS header to each HTTP response.
- required: false
- choices: ["disable", "enable"]
-
- ssl_hpkp_report_uri:
- description:
- - URL to report HPKP violations to.
- required: false
-
- ssl_hpkp_primary:
- description:
- - Certificate to generate primary HPKP pin from.
- required: false
-
- ssl_hpkp_include_subdomains:
- description:
- - Indicate that HPKP header applies to all subdomains.
- - choice | disable | HPKP header does not apply to subdomains.
- - choice | enable | HPKP header applies to subdomains.
- required: false
- choices: ["disable", "enable"]
-
- ssl_hpkp_backup:
- description:
- - Certificate to generate backup HPKP pin from.
- required: false
-
- ssl_hpkp_age:
- description:
- - Number of seconds the client should honour the HPKP setting.
- required: false
-
- ssl_hpkp:
- description:
- - Enable/disable including HPKP header in response.
- - choice | disable | Do not add a HPKP header to each HTTP response.
- - choice | enable | Add a HPKP header to each a HTTP response.
- - choice | report-only | Add a HPKP Report-Only header to each HTTP response.
- required: false
- choices: ["disable", "enable", "report-only"]
-
- ssl_dh_bits:
- description:
- - Number of bits to use in the Diffie-Hellman exchange for RSA encryption of SSL sessions.
- - choice | 768 | 768-bit Diffie-Hellman prime.
- - choice | 1024 | 1024-bit Diffie-Hellman prime.
- - choice | 1536 | 1536-bit Diffie-Hellman prime.
- - choice | 2048 | 2048-bit Diffie-Hellman prime.
- - choice | 3072 | 3072-bit Diffie-Hellman prime.
- - choice | 4096 | 4096-bit Diffie-Hellman prime.
- required: false
- choices: ["768", "1024", "1536", "2048", "3072", "4096"]
-
- ssl_client_session_state_type:
- description:
- - How to expire SSL sessions for the segment of the SSL connection between the client and the FortiGate.
- - choice | disable | Do not keep session states.
- - choice | time | Expire session states after this many minutes.
- - choice | count | Expire session states when this maximum is reached.
- - choice | both | Expire session states based on time or count, whichever occurs first.
- required: false
- choices: ["disable", "time", "count", "both"]
-
- ssl_client_session_state_timeout:
- description:
- - Number of minutes to keep client to FortiGate SSL session state.
- required: false
-
- ssl_client_session_state_max:
- description:
- - Maximum number of client to FortiGate SSL session states to keep.
- required: false
-
- ssl_client_renegotiation:
- description:
- - Allow, deny, or require secure renegotiation of client sessions to comply with RFC 5746.
- - choice | deny | Abort any client initiated SSL re-negotiation attempt.
- - choice | allow | Allow a SSL client to renegotiate.
- - choice | secure | Abort any client initiated SSL re-negotiation attempt that does not use RFC 5746.
- required: false
- choices: ["deny", "allow", "secure"]
-
- ssl_client_fallback:
- description:
- - Enable/disable support for preventing Downgrade Attacks on client connections (RFC 7507).
- - choice | disable | Disable.
- - choice | enable | Enable.
- required: false
- choices: ["disable", "enable"]
-
- ssl_certificate:
- description:
- - The name of the SSL certificate to use for SSL acceleration.
- required: false
-
- ssl_algorithm:
- description:
- - Permitted encryption algorithms for SSL sessions according to encryption strength.
- - choice | high | High encryption. Allow only AES and ChaCha.
- - choice | medium | Medium encryption. Allow AES, ChaCha, 3DES, and RC4.
- - choice | low | Low encryption. Allow AES, ChaCha, 3DES, RC4, and DES.
- - choice | custom | Custom encryption. Use config ssl-cipher-suites to select the cipher suites that are allowed.
- required: false
- choices: ["high", "medium", "low", "custom"]
-
- srcintf_filter:
- description:
- - Interfaces to which the VIP applies. Separate the names with spaces.
- required: false
-
- src_filter:
- description:
- - Source address filter. Each address must be either an IP/subnet (x.x.x.x/n) or a range (x.x.x.x-y.y.y.y).
- - Separate addresses with spaces.
- required: false
-
- service:
- description:
- - Service name.
- required: false
-
- server_type:
- description:
- - Protocol to be load balanced by the virtual server (also called the server load balance virtual IP).
- - choice | http | HTTP
- - choice | https | HTTPS
- - choice | ssl | SSL
- - choice | tcp | TCP
- - choice | udp | UDP
- - choice | ip | IP
- - choice | imaps | IMAPS
- - choice | pop3s | POP3S
- - choice | smtps | SMTPS
- required: false
- choices: ["http", "https", "ssl", "tcp", "udp", "ip", "imaps", "pop3s", "smtps"]
-
- protocol:
- description:
- - Protocol to use when forwarding packets.
- - choice | tcp | TCP.
- - choice | udp | UDP.
- - choice | sctp | SCTP.
- - choice | icmp | ICMP.
- required: false
- choices: ["tcp", "udp", "sctp", "icmp"]
-
- portmapping_type:
- description:
- - Port mapping type.
- - choice | 1-to-1 | One to one.
- - choice | m-to-n | Many to many.
- required: false
- choices: ["1-to-1", "m-to-n"]
-
- portforward:
- description:
- - Enable/disable port forwarding.
- - choice | disable | Disable port forward.
- - choice | enable | Enable port forward.
- required: false
- choices: ["disable", "enable"]
-
- persistence:
- description:
- - Configure how to make sure that clients connect to the same server every time they make a request that is part
- - of the same session.
- - choice | none | None.
- - choice | http-cookie | HTTP cookie.
- - choice | ssl-session-id | SSL session ID.
- required: false
- choices: ["none", "http-cookie", "ssl-session-id"]
-
- outlook_web_access:
- description:
- - Enable to add the Front-End-Https header for Microsoft Outlook Web Access.
- - choice | disable | Disable Outlook Web Access support.
- - choice | enable | Enable Outlook Web Access support.
- required: false
- choices: ["disable", "enable"]
-
- nat_source_vip:
- description:
- - Enable to prevent unintended servers from using a virtual IP.
- - Disable to use the actual IP address of the server as the source address.
- - choice | disable | Do not force to NAT as VIP.
- - choice | enable | Force to NAT as VIP.
- required: false
- choices: ["disable", "enable"]
-
- name:
- description:
- - Virtual IP name.
- required: false
-
- monitor:
- description:
- - Name of the health check monitor to use when polling to determine a virtual server's connectivity status.
- required: false
-
- max_embryonic_connections:
- description:
- - Maximum number of incomplete connections.
- required: false
-
- mappedport:
- description:
- - Port number range on the destination network to which the external port number range is mapped.
- required: false
-
- mappedip:
- description:
- - IP address or address range on the destination network to which the external IP address is mapped.
- required: false
-
- mapped_addr:
- description:
- - Mapped FQDN address name.
- required: false
-
- ldb_method:
- description:
- - Method used to distribute sessions to real servers.
- - choice | static | Distribute to server based on source IP.
- - choice | round-robin | Distribute to server based round robin order.
- - choice | weighted | Distribute to server based on weight.
- - choice | least-session | Distribute to server with lowest session count.
- - choice | least-rtt | Distribute to server with lowest Round-Trip-Time.
- - choice | first-alive | Distribute to the first server that is alive.
- - choice | http-host | Distribute to server based on host field in HTTP header.
- required: false
- choices: ["static", "round-robin", "weighted", "least-session", "least-rtt", "first-alive", "http-host"]
-
- https_cookie_secure:
- description:
- - Enable/disable verification that inserted HTTPS cookies are secure.
- - choice | disable | Do not mark cookie as secure, allow sharing between an HTTP and HTTPS connection.
- - choice | enable | Mark inserted cookie as secure, cookie can only be used for HTTPS a connection.
- required: false
- choices: ["disable", "enable"]
-
- http_multiplex:
- description:
- - Enable/disable HTTP multiplexing.
- - choice | disable | Disable HTTP session multiplexing.
- - choice | enable | Enable HTTP session multiplexing.
- required: false
- choices: ["disable", "enable"]
-
- http_ip_header_name:
- description:
- - For HTTP multiplexing, enter a custom HTTPS header name. The orig client IP address is added to this header.
- - If empty, X-Forwarded-For is used.
- required: false
-
- http_ip_header:
- description:
- - For HTTP multiplexing, enable to add the original client IP address in the XForwarded-For HTTP header.
- - choice | disable | Disable adding HTTP header.
- - choice | enable | Enable adding HTTP header.
- required: false
- choices: ["disable", "enable"]
-
- http_cookie_share:
- description:
- - Control sharing of cookies across virtual servers. same-ip means a cookie from one virtual server can be used
- - by another. Disable stops cookie sharing.
- - choice | disable | Only allow HTTP cookie to match this virtual server.
- - choice | same-ip | Allow HTTP cookie to match any virtual server with same IP.
- required: false
- choices: ["disable", "same-ip"]
-
- http_cookie_path:
- description:
- - Limit HTTP cookie persistence to the specified path.
- required: false
-
- http_cookie_generation:
- description:
- - Generation of HTTP cookie to be accepted. Changing invalidates all existing cookies.
- required: false
-
- http_cookie_domain_from_host:
- description:
- - Enable/disable use of HTTP cookie domain from host field in HTTP.
- - choice | disable | Disable use of HTTP cookie domain from host field in HTTP (use http-cooke-domain setting).
- - choice | enable | Enable use of HTTP cookie domain from host field in HTTP.
- required: false
- choices: ["disable", "enable"]
-
- http_cookie_domain:
- description:
- - Domain that HTTP cookie persistence should apply to.
- required: false
-
- http_cookie_age:
- description:
- - Time in minutes that client web browsers should keep a cookie. Default is 60 seconds. 0 = no time limit.
- required: false
-
- gratuitous_arp_interval:
- description:
- - Enable to have the VIP send gratuitous ARPs. 0=disabled. Set from 5 up to 8640000 seconds to enable.
- required: false
-
- extport:
- description:
- - Incoming port number range that you want to map to a port number range on the destination network.
- required: false
-
- extip:
- description:
- - IP address or address range on the external interface that you want to map to an address or address range on t
- - he destination network.
- required: false
-
- extintf:
- description:
- - Interface connected to the source network that receives the packets that will be forwarded to the destination
- - network.
- required: false
-
- extaddr:
- description:
- - External FQDN address name.
- required: false
-
- dns_mapping_ttl:
- description:
- - DNS mapping TTL (Set to zero to use TTL in DNS response, default = 0).
- required: false
-
- comment:
- description:
- - Comment.
- required: false
-
- color:
- description:
- - Color of icon on the GUI.
- required: false
-
- arp_reply:
- description:
- - Enable to respond to ARP requests for this virtual IP address. Enabled by default.
- - choice | disable | Disable ARP reply.
- - choice | enable | Enable ARP reply.
- required: false
- choices: ["disable", "enable"]
-
- dynamic_mapping:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- dynamic_mapping_arp_reply:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - choice | disable |
- - choice | enable |
- required: false
- choices: ["disable", "enable"]
-
- dynamic_mapping_color:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- required: false
-
- dynamic_mapping_comment:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- required: false
-
- dynamic_mapping_dns_mapping_ttl:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- required: false
-
- dynamic_mapping_extaddr:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- required: false
-
- dynamic_mapping_extintf:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- required: false
-
- dynamic_mapping_extip:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- required: false
-
- dynamic_mapping_extport:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- required: false
-
- dynamic_mapping_gratuitous_arp_interval:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- required: false
-
- dynamic_mapping_http_cookie_age:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- required: false
-
- dynamic_mapping_http_cookie_domain:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- required: false
-
- dynamic_mapping_http_cookie_domain_from_host:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - choice | disable |
- - choice | enable |
- required: false
- choices: ["disable", "enable"]
-
- dynamic_mapping_http_cookie_generation:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- required: false
-
- dynamic_mapping_http_cookie_path:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- required: false
-
- dynamic_mapping_http_cookie_share:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - choice | disable |
- - choice | same-ip |
- required: false
- choices: ["disable", "same-ip"]
-
- dynamic_mapping_http_ip_header:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - choice | disable |
- - choice | enable |
- required: false
- choices: ["disable", "enable"]
-
- dynamic_mapping_http_ip_header_name:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- required: false
-
- dynamic_mapping_http_multiplex:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - choice | disable |
- - choice | enable |
- required: false
- choices: ["disable", "enable"]
-
- dynamic_mapping_https_cookie_secure:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - choice | disable |
- - choice | enable |
- required: false
- choices: ["disable", "enable"]
-
- dynamic_mapping_ldb_method:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - choice | static |
- - choice | round-robin |
- - choice | weighted |
- - choice | least-session |
- - choice | least-rtt |
- - choice | first-alive |
- - choice | http-host |
- required: false
- choices: ["static", "round-robin", "weighted", "least-session", "least-rtt", "first-alive", "http-host"]
-
- dynamic_mapping_mapped_addr:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- required: false
-
- dynamic_mapping_mappedip:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- required: false
-
- dynamic_mapping_mappedport:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- required: false
-
- dynamic_mapping_max_embryonic_connections:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- required: false
-
- dynamic_mapping_monitor:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- required: false
-
- dynamic_mapping_nat_source_vip:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - choice | disable |
- - choice | enable |
- required: false
- choices: ["disable", "enable"]
-
- dynamic_mapping_outlook_web_access:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - choice | disable |
- - choice | enable |
- required: false
- choices: ["disable", "enable"]
-
- dynamic_mapping_persistence:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - choice | none |
- - choice | http-cookie |
- - choice | ssl-session-id |
- required: false
- choices: ["none", "http-cookie", "ssl-session-id"]
-
- dynamic_mapping_portforward:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - choice | disable |
- - choice | enable |
- required: false
- choices: ["disable", "enable"]
-
- dynamic_mapping_portmapping_type:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - choice | 1-to-1 |
- - choice | m-to-n |
- required: false
- choices: ["1-to-1", "m-to-n"]
-
- dynamic_mapping_protocol:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - choice | tcp |
- - choice | udp |
- - choice | sctp |
- - choice | icmp |
- required: false
- choices: ["tcp", "udp", "sctp", "icmp"]
-
- dynamic_mapping_server_type:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - choice | http |
- - choice | https |
- - choice | ssl |
- - choice | tcp |
- - choice | udp |
- - choice | ip |
- - choice | imaps |
- - choice | pop3s |
- - choice | smtps |
- required: false
- choices: ["http", "https", "ssl", "tcp", "udp", "ip", "imaps", "pop3s", "smtps"]
-
- dynamic_mapping_service:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- required: false
-
- dynamic_mapping_src_filter:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- required: false
-
- dynamic_mapping_srcintf_filter:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- required: false
-
- dynamic_mapping_ssl_algorithm:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - choice | high |
- - choice | medium |
- - choice | low |
- - choice | custom |
- required: false
- choices: ["high", "medium", "low", "custom"]
-
- dynamic_mapping_ssl_certificate:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- required: false
-
- dynamic_mapping_ssl_client_fallback:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - choice | disable |
- - choice | enable |
- required: false
- choices: ["disable", "enable"]
-
- dynamic_mapping_ssl_client_renegotiation:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - choice | deny |
- - choice | allow |
- - choice | secure |
- required: false
- choices: ["deny", "allow", "secure"]
-
- dynamic_mapping_ssl_client_session_state_max:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- required: false
-
- dynamic_mapping_ssl_client_session_state_timeout:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- required: false
-
- dynamic_mapping_ssl_client_session_state_type:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - choice | disable |
- - choice | time |
- - choice | count |
- - choice | both |
- required: false
- choices: ["disable", "time", "count", "both"]
-
- dynamic_mapping_ssl_dh_bits:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - choice | 768 |
- - choice | 1024 |
- - choice | 1536 |
- - choice | 2048 |
- - choice | 3072 |
- - choice | 4096 |
- required: false
- choices: ["768", "1024", "1536", "2048", "3072", "4096"]
-
- dynamic_mapping_ssl_hpkp:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - choice | disable |
- - choice | enable |
- - choice | report-only |
- required: false
- choices: ["disable", "enable", "report-only"]
-
- dynamic_mapping_ssl_hpkp_age:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- required: false
-
- dynamic_mapping_ssl_hpkp_backup:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- required: false
-
- dynamic_mapping_ssl_hpkp_include_subdomains:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - choice | disable |
- - choice | enable |
- required: false
- choices: ["disable", "enable"]
-
- dynamic_mapping_ssl_hpkp_primary:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- required: false
-
- dynamic_mapping_ssl_hpkp_report_uri:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- required: false
-
- dynamic_mapping_ssl_hsts:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - choice | disable |
- - choice | enable |
- required: false
- choices: ["disable", "enable"]
-
- dynamic_mapping_ssl_hsts_age:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- required: false
-
- dynamic_mapping_ssl_hsts_include_subdomains:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - choice | disable |
- - choice | enable |
- required: false
- choices: ["disable", "enable"]
-
- dynamic_mapping_ssl_http_location_conversion:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - choice | disable |
- - choice | enable |
- required: false
- choices: ["disable", "enable"]
-
- dynamic_mapping_ssl_http_match_host:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - choice | disable |
- - choice | enable |
- required: false
- choices: ["disable", "enable"]
-
- dynamic_mapping_ssl_max_version:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - choice | ssl-3.0 |
- - choice | tls-1.0 |
- - choice | tls-1.1 |
- - choice | tls-1.2 |
- required: false
- choices: ["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]
-
- dynamic_mapping_ssl_min_version:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - choice | ssl-3.0 |
- - choice | tls-1.0 |
- - choice | tls-1.1 |
- - choice | tls-1.2 |
- required: false
- choices: ["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]
-
- dynamic_mapping_ssl_mode:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - choice | half |
- - choice | full |
- required: false
- choices: ["half", "full"]
-
- dynamic_mapping_ssl_pfs:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - choice | require |
- - choice | deny |
- - choice | allow |
- required: false
- choices: ["require", "deny", "allow"]
-
- dynamic_mapping_ssl_send_empty_frags:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - choice | disable |
- - choice | enable |
- required: false
- choices: ["disable", "enable"]
-
- dynamic_mapping_ssl_server_algorithm:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - choice | high |
- - choice | low |
- - choice | medium |
- - choice | custom |
- - choice | client |
- required: false
- choices: ["high", "low", "medium", "custom", "client"]
-
- dynamic_mapping_ssl_server_max_version:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - choice | ssl-3.0 |
- - choice | tls-1.0 |
- - choice | tls-1.1 |
- - choice | tls-1.2 |
- - choice | client |
- required: false
- choices: ["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2", "client"]
-
- dynamic_mapping_ssl_server_min_version:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - choice | ssl-3.0 |
- - choice | tls-1.0 |
- - choice | tls-1.1 |
- - choice | tls-1.2 |
- - choice | client |
- required: false
- choices: ["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2", "client"]
-
- dynamic_mapping_ssl_server_session_state_max:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- required: false
-
- dynamic_mapping_ssl_server_session_state_timeout:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- required: false
-
- dynamic_mapping_ssl_server_session_state_type:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - choice | disable |
- - choice | time |
- - choice | count |
- - choice | both |
- required: false
- choices: ["disable", "time", "count", "both"]
-
- dynamic_mapping_type:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - choice | static-nat |
- - choice | load-balance |
- - choice | server-load-balance |
- - choice | dns-translation |
- - choice | fqdn |
- required: false
- choices: ["static-nat", "load-balance", "server-load-balance", "dns-translation", "fqdn"]
-
- dynamic_mapping_weblogic_server:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - choice | disable |
- - choice | enable |
- required: false
- choices: ["disable", "enable"]
-
- dynamic_mapping_websphere_server:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - choice | disable |
- - choice | enable |
- required: false
- choices: ["disable", "enable"]
-
- dynamic_mapping_realservers_client_ip:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- required: false
-
- dynamic_mapping_realservers_healthcheck:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - choice | disable |
- - choice | enable |
- - choice | vip |
- required: false
- choices: ["disable", "enable", "vip"]
-
- dynamic_mapping_realservers_holddown_interval:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- required: false
-
- dynamic_mapping_realservers_http_host:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- required: false
-
- dynamic_mapping_realservers_ip:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- required: false
-
- dynamic_mapping_realservers_max_connections:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- required: false
-
- dynamic_mapping_realservers_monitor:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- required: false
-
- dynamic_mapping_realservers_port:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- required: false
-
- dynamic_mapping_realservers_seq:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- required: false
-
- dynamic_mapping_realservers_status:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - choice | active |
- - choice | standby |
- - choice | disable |
- required: false
- choices: ["active", "standby", "disable"]
-
- dynamic_mapping_realservers_weight:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- required: false
-
- dynamic_mapping_ssl_cipher_suites_cipher:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - choice | TLS-RSA-WITH-RC4-128-MD5 |
- - choice | TLS-RSA-WITH-RC4-128-SHA |
- - choice | TLS-RSA-WITH-DES-CBC-SHA |
- - choice | TLS-RSA-WITH-3DES-EDE-CBC-SHA |
- - choice | TLS-RSA-WITH-AES-128-CBC-SHA |
- - choice | TLS-RSA-WITH-AES-256-CBC-SHA |
- - choice | TLS-RSA-WITH-AES-128-CBC-SHA256 |
- - choice | TLS-RSA-WITH-AES-256-CBC-SHA256 |
- - choice | TLS-RSA-WITH-CAMELLIA-128-CBC-SHA |
- - choice | TLS-RSA-WITH-CAMELLIA-256-CBC-SHA |
- - choice | TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256 |
- - choice | TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256 |
- - choice | TLS-RSA-WITH-SEED-CBC-SHA |
- - choice | TLS-RSA-WITH-ARIA-128-CBC-SHA256 |
- - choice | TLS-RSA-WITH-ARIA-256-CBC-SHA384 |
- - choice | TLS-DHE-RSA-WITH-DES-CBC-SHA |
- - choice | TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA |
- - choice | TLS-DHE-RSA-WITH-AES-128-CBC-SHA |
- - choice | TLS-DHE-RSA-WITH-AES-256-CBC-SHA |
- - choice | TLS-DHE-RSA-WITH-AES-128-CBC-SHA256 |
- - choice | TLS-DHE-RSA-WITH-AES-256-CBC-SHA256 |
- - choice | TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA |
- - choice | TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA |
- - choice | TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256 |
- - choice | TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256 |
- - choice | TLS-DHE-RSA-WITH-SEED-CBC-SHA |
- - choice | TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256 |
- - choice | TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384 |
- - choice | TLS-ECDHE-RSA-WITH-RC4-128-SHA |
- - choice | TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA |
- - choice | TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA |
- - choice | TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA |
- - choice | TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256 |
- - choice | TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256 |
- - choice | TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256 |
- - choice | TLS-DHE-RSA-WITH-AES-128-GCM-SHA256 |
- - choice | TLS-DHE-RSA-WITH-AES-256-GCM-SHA384 |
- - choice | TLS-DHE-DSS-WITH-AES-128-CBC-SHA |
- - choice | TLS-DHE-DSS-WITH-AES-256-CBC-SHA |
- - choice | TLS-DHE-DSS-WITH-AES-128-CBC-SHA256 |
- - choice | TLS-DHE-DSS-WITH-AES-128-GCM-SHA256 |
- - choice | TLS-DHE-DSS-WITH-AES-256-CBC-SHA256 |
- - choice | TLS-DHE-DSS-WITH-AES-256-GCM-SHA384 |
- - choice | TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256 |
- - choice | TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256 |
- - choice | TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384 |
- - choice | TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384 |
- - choice | TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA |
- - choice | TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256 |
- - choice | TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256 |
- - choice | TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384 |
- - choice | TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384 |
- - choice | TLS-RSA-WITH-AES-128-GCM-SHA256 |
- - choice | TLS-RSA-WITH-AES-256-GCM-SHA384 |
- - choice | TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA |
- - choice | TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA |
- - choice | TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256 |
- - choice | TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256 |
- - choice | TLS-DHE-DSS-WITH-SEED-CBC-SHA |
- - choice | TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256 |
- - choice | TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384 |
- - choice | TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256 |
- - choice | TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384 |
- - choice | TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC-SHA256 |
- - choice | TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC-SHA384 |
- - choice | TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA |
- - choice | TLS-DHE-DSS-WITH-DES-CBC-SHA |
- required: false
- choices: ["TLS-RSA-WITH-RC4-128-MD5",
- "TLS-RSA-WITH-RC4-128-SHA",
- "TLS-RSA-WITH-DES-CBC-SHA",
- "TLS-RSA-WITH-3DES-EDE-CBC-SHA",
- "TLS-RSA-WITH-AES-128-CBC-SHA",
- "TLS-RSA-WITH-AES-256-CBC-SHA",
- "TLS-RSA-WITH-AES-128-CBC-SHA256",
- "TLS-RSA-WITH-AES-256-CBC-SHA256",
- "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA",
- "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA",
- "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256",
- "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256",
- "TLS-RSA-WITH-SEED-CBC-SHA",
- "TLS-RSA-WITH-ARIA-128-CBC-SHA256",
- "TLS-RSA-WITH-ARIA-256-CBC-SHA384",
- "TLS-DHE-RSA-WITH-DES-CBC-SHA",
- "TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA",
- "TLS-DHE-RSA-WITH-AES-128-CBC-SHA",
- "TLS-DHE-RSA-WITH-AES-256-CBC-SHA",
- "TLS-DHE-RSA-WITH-AES-128-CBC-SHA256",
- "TLS-DHE-RSA-WITH-AES-256-CBC-SHA256",
- "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA",
- "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA",
- "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256",
- "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256",
- "TLS-DHE-RSA-WITH-SEED-CBC-SHA",
- "TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256",
- "TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384",
- "TLS-ECDHE-RSA-WITH-RC4-128-SHA",
- "TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA",
- "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA",
- "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA",
- "TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256",
- "TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256",
- "TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256",
- "TLS-DHE-RSA-WITH-AES-128-GCM-SHA256",
- "TLS-DHE-RSA-WITH-AES-256-GCM-SHA384",
- "TLS-DHE-DSS-WITH-AES-128-CBC-SHA",
- "TLS-DHE-DSS-WITH-AES-256-CBC-SHA",
- "TLS-DHE-DSS-WITH-AES-128-CBC-SHA256",
- "TLS-DHE-DSS-WITH-AES-128-GCM-SHA256",
- "TLS-DHE-DSS-WITH-AES-256-CBC-SHA256",
- "TLS-DHE-DSS-WITH-AES-256-GCM-SHA384",
- "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256",
- "TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256",
- "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384",
- "TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384",
- "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA",
- "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256",
- "TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256",
- "TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384",
- "TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384",
- "TLS-RSA-WITH-AES-128-GCM-SHA256",
- "TLS-RSA-WITH-AES-256-GCM-SHA384",
- "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA",
- "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA",
- "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256",
- "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256",
- "TLS-DHE-DSS-WITH-SEED-CBC-SHA",
- "TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256",
- "TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384",
- "TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256",
- "TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384",
- "TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC-SHA256",
- "TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC-SHA384",
- "TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA",
- "TLS-DHE-DSS-WITH-DES-CBC-SHA"]
-
- dynamic_mapping_ssl_cipher_suites_versions:
- description:
- - Dynamic Mapping Version of Suffixed Option Name. Sub-Table. Same Descriptions as Parent.
- - FLAG Based Options. Specify multiple in list form.
- - flag | ssl-3.0 |
- - flag | tls-1.0 |
- - flag | tls-1.1 |
- - flag | tls-1.2 |
- required: false
- choices: ["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]
-
- realservers:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- realservers_client_ip:
- description:
- - Only clients in this IP range can connect to this real server.
- required: false
-
- realservers_healthcheck:
- description:
- - Enable to check the responsiveness of the real server before forwarding traffic.
- - choice | disable | Disable per server health check.
- - choice | enable | Enable per server health check.
- - choice | vip | Use health check defined in VIP.
- required: false
- choices: ["disable", "enable", "vip"]
-
- realservers_holddown_interval:
- description:
- - Time in seconds that the health check monitor monitors an unresponsive server that should be active.
- required: false
-
- realservers_http_host:
- description:
- - HTTP server domain name in HTTP header.
- required: false
-
- realservers_ip:
- description:
- - IP address of the real server.
- required: false
-
- realservers_max_connections:
- description:
- - Max number of active connections that can be directed to the real server. When reached, sessions are sent to
- - their real servers.
- required: false
-
- realservers_monitor:
- description:
- - Name of the health check monitor to use when polling to determine a virtual server's connectivity status.
- required: false
-
- realservers_port:
- description:
- - Port for communicating with the real server. Required if port forwarding is enabled.
- required: false
-
- realservers_seq:
- description:
- - Real Server Sequence Number
- required: false
-
- realservers_status:
- description:
- - Set the status of the real server to active so that it can accept traffic.
- - Or on standby or disabled so no traffic is sent.
- - choice | active | Server status active.
- - choice | standby | Server status standby.
- - choice | disable | Server status disable.
- required: false
- choices: ["active", "standby", "disable"]
-
- realservers_weight:
- description:
- - Weight of the real server. If weighted load balancing is enabled, the server with the highest weight gets more
- - connections.
- required: false
-
- ssl_cipher_suites:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- ssl_cipher_suites_cipher:
- description:
- - Cipher suite name.
- - choice | TLS-RSA-WITH-RC4-128-MD5 | Cipher suite TLS-RSA-WITH-RC4-128-MD5.
- - choice | TLS-RSA-WITH-RC4-128-SHA | Cipher suite TLS-RSA-WITH-RC4-128-SHA.
- - choice | TLS-RSA-WITH-DES-CBC-SHA | Cipher suite TLS-RSA-WITH-DES-CBC-SHA.
- - choice | TLS-RSA-WITH-3DES-EDE-CBC-SHA | Cipher suite TLS-RSA-WITH-3DES-EDE-CBC-SHA.
- - choice | TLS-RSA-WITH-AES-128-CBC-SHA | Cipher suite TLS-RSA-WITH-AES-128-CBC-SHA.
- - choice | TLS-RSA-WITH-AES-256-CBC-SHA | Cipher suite TLS-RSA-WITH-AES-256-CBC-SHA.
- - choice | TLS-RSA-WITH-AES-128-CBC-SHA256 | Cipher suite TLS-RSA-WITH-AES-128-CBC-SHA256.
- - choice | TLS-RSA-WITH-AES-256-CBC-SHA256 | Cipher suite TLS-RSA-WITH-AES-256-CBC-SHA256.
- - choice | TLS-RSA-WITH-CAMELLIA-128-CBC-SHA | Cipher suite TLS-RSA-WITH-CAMELLIA-128-CBC-SHA.
- - choice | TLS-RSA-WITH-CAMELLIA-256-CBC-SHA | Cipher suite TLS-RSA-WITH-CAMELLIA-256-CBC-SHA.
- - choice | TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256 | Cipher suite TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256.
- - choice | TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256 | Cipher suite TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256.
- - choice | TLS-RSA-WITH-SEED-CBC-SHA | Cipher suite TLS-RSA-WITH-SEED-CBC-SHA.
- - choice | TLS-RSA-WITH-ARIA-128-CBC-SHA256 | Cipher suite TLS-RSA-WITH-ARIA-128-CBC-SHA256.
- - choice | TLS-RSA-WITH-ARIA-256-CBC-SHA384 | Cipher suite TLS-RSA-WITH-ARIA-256-CBC-SHA384.
- - choice | TLS-DHE-RSA-WITH-DES-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-DES-CBC-SHA.
- - choice | TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA.
- - choice | TLS-DHE-RSA-WITH-AES-128-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-AES-128-CBC-SHA.
- - choice | TLS-DHE-RSA-WITH-AES-256-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-AES-256-CBC-SHA.
- - choice | TLS-DHE-RSA-WITH-AES-128-CBC-SHA256 | Cipher suite TLS-DHE-RSA-WITH-AES-128-CBC-SHA256.
- - choice | TLS-DHE-RSA-WITH-AES-256-CBC-SHA256 | Cipher suite TLS-DHE-RSA-WITH-AES-256-CBC-SHA256.
- - choice | TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA.
- - choice | TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA.
- - choice | TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256 | Cipher suite TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256.
- - choice | TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256 | Cipher suite TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256.
- - choice | TLS-DHE-RSA-WITH-SEED-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-SEED-CBC-SHA.
- - choice | TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256 | Cipher suite TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256.
- - choice | TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384 | Cipher suite TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384.
- - choice | TLS-ECDHE-RSA-WITH-RC4-128-SHA | Cipher suite TLS-ECDHE-RSA-WITH-RC4-128-SHA.
- - choice | TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA | Cipher suite TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA.
- - choice | TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA | Cipher suite TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA.
- - choice | TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA | Cipher suite TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA.
- - choice | TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256 | Cipher suite TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256.
- - choice | TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256 | Cipher suite TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256.
- - choice | TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256 | Cipher suite TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256.
- - choice | TLS-DHE-RSA-WITH-AES-128-GCM-SHA256 | Cipher suite TLS-DHE-RSA-WITH-AES-128-GCM-SHA256.
- - choice | TLS-DHE-RSA-WITH-AES-256-GCM-SHA384 | Cipher suite TLS-DHE-RSA-WITH-AES-256-GCM-SHA384.
- - choice | TLS-DHE-DSS-WITH-AES-128-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-AES-128-CBC-SHA.
- - choice | TLS-DHE-DSS-WITH-AES-256-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-AES-256-CBC-SHA.
- - choice | TLS-DHE-DSS-WITH-AES-128-CBC-SHA256 | Cipher suite TLS-DHE-DSS-WITH-AES-128-CBC-SHA256.
- - choice | TLS-DHE-DSS-WITH-AES-128-GCM-SHA256 | Cipher suite TLS-DHE-DSS-WITH-AES-128-GCM-SHA256.
- - choice | TLS-DHE-DSS-WITH-AES-256-CBC-SHA256 | Cipher suite TLS-DHE-DSS-WITH-AES-256-CBC-SHA256.
- - choice | TLS-DHE-DSS-WITH-AES-256-GCM-SHA384 | Cipher suite TLS-DHE-DSS-WITH-AES-256-GCM-SHA384.
- - choice | TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256 | Cipher suite TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256.
- - choice | TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256 | Cipher suite TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256.
- - choice | TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384 | Cipher suite TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384.
- - choice | TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384 | Cipher suite TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384.
- - choice | TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA | Cipher suite TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA.
- - choice | TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256 | Cipher suite TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256.
- - choice | TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256 | Cipher suite TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256.
- - choice | TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384 | Cipher suite TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384.
- - choice | TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384 | Cipher suite TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384.
- - choice | TLS-RSA-WITH-AES-128-GCM-SHA256 | Cipher suite TLS-RSA-WITH-AES-128-GCM-SHA256.
- - choice | TLS-RSA-WITH-AES-256-GCM-SHA384 | Cipher suite TLS-RSA-WITH-AES-256-GCM-SHA384.
- - choice | TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA | Cipher suite TLS-DSS-RSA-WITH-CAMELLIA-128-CBC-SHA.
- - choice | TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA.
- - choice | TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256 | Cipher suite TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256.
- - choice | TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256 | Cipher suite TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256.
- - choice | TLS-DHE-DSS-WITH-SEED-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-SEED-CBC-SHA.
- - choice | TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256 | Cipher suite TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256.
- - choice | TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384 | Cipher suite TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384.
- - choice | TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256 | Cipher suite TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256.
- - choice | TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384 | Cipher suite TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384.
- - choice | TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC-SHA256 | Cipher suite TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC_SHA256.
- - choice | TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC-SHA384 | Cipher suite TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC_SHA384.
- - choice | TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA.
- - choice | TLS-DHE-DSS-WITH-DES-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-DES-CBC-SHA.
- required: false
- choices: ["TLS-RSA-WITH-RC4-128-MD5",
- "TLS-RSA-WITH-RC4-128-SHA",
- "TLS-RSA-WITH-DES-CBC-SHA",
- "TLS-RSA-WITH-3DES-EDE-CBC-SHA",
- "TLS-RSA-WITH-AES-128-CBC-SHA",
- "TLS-RSA-WITH-AES-256-CBC-SHA",
- "TLS-RSA-WITH-AES-128-CBC-SHA256",
- "TLS-RSA-WITH-AES-256-CBC-SHA256",
- "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA",
- "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA",
- "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256",
- "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256",
- "TLS-RSA-WITH-SEED-CBC-SHA",
- "TLS-RSA-WITH-ARIA-128-CBC-SHA256",
- "TLS-RSA-WITH-ARIA-256-CBC-SHA384",
- "TLS-DHE-RSA-WITH-DES-CBC-SHA",
- "TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA",
- "TLS-DHE-RSA-WITH-AES-128-CBC-SHA",
- "TLS-DHE-RSA-WITH-AES-256-CBC-SHA",
- "TLS-DHE-RSA-WITH-AES-128-CBC-SHA256",
- "TLS-DHE-RSA-WITH-AES-256-CBC-SHA256",
- "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA",
- "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA",
- "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256",
- "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256",
- "TLS-DHE-RSA-WITH-SEED-CBC-SHA",
- "TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256",
- "TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384",
- "TLS-ECDHE-RSA-WITH-RC4-128-SHA",
- "TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA",
- "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA",
- "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA",
- "TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256",
- "TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256",
- "TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256",
- "TLS-DHE-RSA-WITH-AES-128-GCM-SHA256",
- "TLS-DHE-RSA-WITH-AES-256-GCM-SHA384",
- "TLS-DHE-DSS-WITH-AES-128-CBC-SHA",
- "TLS-DHE-DSS-WITH-AES-256-CBC-SHA",
- "TLS-DHE-DSS-WITH-AES-128-CBC-SHA256",
- "TLS-DHE-DSS-WITH-AES-128-GCM-SHA256",
- "TLS-DHE-DSS-WITH-AES-256-CBC-SHA256",
- "TLS-DHE-DSS-WITH-AES-256-GCM-SHA384",
- "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256",
- "TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256",
- "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384",
- "TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384",
- "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA",
- "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256",
- "TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256",
- "TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384",
- "TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384",
- "TLS-RSA-WITH-AES-128-GCM-SHA256",
- "TLS-RSA-WITH-AES-256-GCM-SHA384",
- "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA",
- "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA",
- "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256",
- "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256",
- "TLS-DHE-DSS-WITH-SEED-CBC-SHA",
- "TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256",
- "TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384",
- "TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256",
- "TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384",
- "TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC-SHA256",
- "TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC-SHA384",
- "TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA",
- "TLS-DHE-DSS-WITH-DES-CBC-SHA"]
-
- ssl_cipher_suites_versions:
- description:
- - SSL/TLS versions that the cipher suite can be used with.
- - FLAG Based Options. Specify multiple in list form.
- - flag | ssl-3.0 | SSL 3.0.
- - flag | tls-1.0 | TLS 1.0.
- - flag | tls-1.1 | TLS 1.1.
- - flag | tls-1.2 | TLS 1.2.
- required: false
- choices: ["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]
-
- ssl_server_cipher_suites:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- ssl_server_cipher_suites_cipher:
- description:
- - Cipher suite name.
- - choice | TLS-RSA-WITH-RC4-128-MD5 | Cipher suite TLS-RSA-WITH-RC4-128-MD5.
- - choice | TLS-RSA-WITH-RC4-128-SHA | Cipher suite TLS-RSA-WITH-RC4-128-SHA.
- - choice | TLS-RSA-WITH-DES-CBC-SHA | Cipher suite TLS-RSA-WITH-DES-CBC-SHA.
- - choice | TLS-RSA-WITH-3DES-EDE-CBC-SHA | Cipher suite TLS-RSA-WITH-3DES-EDE-CBC-SHA.
- - choice | TLS-RSA-WITH-AES-128-CBC-SHA | Cipher suite TLS-RSA-WITH-AES-128-CBC-SHA.
- - choice | TLS-RSA-WITH-AES-256-CBC-SHA | Cipher suite TLS-RSA-WITH-AES-256-CBC-SHA.
- - choice | TLS-RSA-WITH-AES-128-CBC-SHA256 | Cipher suite TLS-RSA-WITH-AES-128-CBC-SHA256.
- - choice | TLS-RSA-WITH-AES-256-CBC-SHA256 | Cipher suite TLS-RSA-WITH-AES-256-CBC-SHA256.
- - choice | TLS-RSA-WITH-CAMELLIA-128-CBC-SHA | Cipher suite TLS-RSA-WITH-CAMELLIA-128-CBC-SHA.
- - choice | TLS-RSA-WITH-CAMELLIA-256-CBC-SHA | Cipher suite TLS-RSA-WITH-CAMELLIA-256-CBC-SHA.
- - choice | TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256 | Cipher suite TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256.
- - choice | TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256 | Cipher suite TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256.
- - choice | TLS-RSA-WITH-SEED-CBC-SHA | Cipher suite TLS-RSA-WITH-SEED-CBC-SHA.
- - choice | TLS-RSA-WITH-ARIA-128-CBC-SHA256 | Cipher suite TLS-RSA-WITH-ARIA-128-CBC-SHA256.
- - choice | TLS-RSA-WITH-ARIA-256-CBC-SHA384 | Cipher suite TLS-RSA-WITH-ARIA-256-CBC-SHA384.
- - choice | TLS-DHE-RSA-WITH-DES-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-DES-CBC-SHA.
- - choice | TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA.
- - choice | TLS-DHE-RSA-WITH-AES-128-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-AES-128-CBC-SHA.
- - choice | TLS-DHE-RSA-WITH-AES-256-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-AES-256-CBC-SHA.
- - choice | TLS-DHE-RSA-WITH-AES-128-CBC-SHA256 | Cipher suite TLS-DHE-RSA-WITH-AES-128-CBC-SHA256.
- - choice | TLS-DHE-RSA-WITH-AES-256-CBC-SHA256 | Cipher suite TLS-DHE-RSA-WITH-AES-256-CBC-SHA256.
- - choice | TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA.
- - choice | TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA.
- - choice | TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256 | Cipher suite TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256.
- - choice | TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256 | Cipher suite TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256.
- - choice | TLS-DHE-RSA-WITH-SEED-CBC-SHA | Cipher suite TLS-DHE-RSA-WITH-SEED-CBC-SHA.
- - choice | TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256 | Cipher suite TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256.
- - choice | TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384 | Cipher suite TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384.
- - choice | TLS-ECDHE-RSA-WITH-RC4-128-SHA | Cipher suite TLS-ECDHE-RSA-WITH-RC4-128-SHA.
- - choice | TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA | Cipher suite TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA.
- - choice | TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA | Cipher suite TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA.
- - choice | TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA | Cipher suite TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA.
- - choice | TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256 | Cipher suite TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256.
- - choice | TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256 | Suite TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256.
- - choice | TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256 | Cipher suite TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256.
- - choice | TLS-DHE-RSA-WITH-AES-128-GCM-SHA256 | Cipher suite TLS-DHE-RSA-WITH-AES-128-GCM-SHA256.
- - choice | TLS-DHE-RSA-WITH-AES-256-GCM-SHA384 | Cipher suite TLS-DHE-RSA-WITH-AES-256-GCM-SHA384.
- - choice | TLS-DHE-DSS-WITH-AES-128-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-AES-128-CBC-SHA.
- - choice | TLS-DHE-DSS-WITH-AES-256-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-AES-256-CBC-SHA.
- - choice | TLS-DHE-DSS-WITH-AES-128-CBC-SHA256 | Cipher suite TLS-DHE-DSS-WITH-AES-128-CBC-SHA256.
- - choice | TLS-DHE-DSS-WITH-AES-128-GCM-SHA256 | Cipher suite TLS-DHE-DSS-WITH-AES-128-GCM-SHA256.
- - choice | TLS-DHE-DSS-WITH-AES-256-CBC-SHA256 | Cipher suite TLS-DHE-DSS-WITH-AES-256-CBC-SHA256.
- - choice | TLS-DHE-DSS-WITH-AES-256-GCM-SHA384 | Cipher suite TLS-DHE-DSS-WITH-AES-256-GCM-SHA384.
- - choice | TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256 | Cipher suite TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256.
- - choice | TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256 | Cipher suite TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256.
- - choice | TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384 | Cipher suite TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384.
- - choice | TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384 | Cipher suite TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384.
- - choice | TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA | Cipher suite TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA.
- - choice | TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256 | Cipher suite TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256.
- - choice | TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256 | Cipher suite TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256.
- - choice | TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384 | Cipher suite TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384.
- - choice | TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384 | Cipher suite TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384.
- - choice | TLS-RSA-WITH-AES-128-GCM-SHA256 | Cipher suite TLS-RSA-WITH-AES-128-GCM-SHA256.
- - choice | TLS-RSA-WITH-AES-256-GCM-SHA384 | Cipher suite TLS-RSA-WITH-AES-256-GCM-SHA384.
- - choice | TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA | Cipher suite TLS-DSS-RSA-WITH-CAMELLIA-128-CBC-SHA.
- - choice | TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA.
- - choice | TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256 | Cipher suite TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256.
- - choice | TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256 | Cipher suite TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256.
- - choice | TLS-DHE-DSS-WITH-SEED-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-SEED-CBC-SHA.
- - choice | TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256 | Cipher suite TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256.
- - choice | TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384 | Cipher suite TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384.
- - choice | TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256 | Cipher suite TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256.
- - choice | TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384 | Cipher suite TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384.
- - choice | TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC-SHA256 | Cipher suite TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC_SHA256.
- - choice | TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC-SHA384 | Cipher suite TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC_SHA384.
- - choice | TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA.
- - choice | TLS-DHE-DSS-WITH-DES-CBC-SHA | Cipher suite TLS-DHE-DSS-WITH-DES-CBC-SHA.
- required: false
- choices: ["TLS-RSA-WITH-RC4-128-MD5",
- "TLS-RSA-WITH-RC4-128-SHA",
- "TLS-RSA-WITH-DES-CBC-SHA",
- "TLS-RSA-WITH-3DES-EDE-CBC-SHA",
- "TLS-RSA-WITH-AES-128-CBC-SHA",
- "TLS-RSA-WITH-AES-256-CBC-SHA",
- "TLS-RSA-WITH-AES-128-CBC-SHA256",
- "TLS-RSA-WITH-AES-256-CBC-SHA256",
- "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA",
- "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA",
- "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256",
- "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256",
- "TLS-RSA-WITH-SEED-CBC-SHA",
- "TLS-RSA-WITH-ARIA-128-CBC-SHA256",
- "TLS-RSA-WITH-ARIA-256-CBC-SHA384",
- "TLS-DHE-RSA-WITH-DES-CBC-SHA",
- "TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA",
- "TLS-DHE-RSA-WITH-AES-128-CBC-SHA",
- "TLS-DHE-RSA-WITH-AES-256-CBC-SHA",
- "TLS-DHE-RSA-WITH-AES-128-CBC-SHA256",
- "TLS-DHE-RSA-WITH-AES-256-CBC-SHA256",
- "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA",
- "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA",
- "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256",
- "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256",
- "TLS-DHE-RSA-WITH-SEED-CBC-SHA",
- "TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256",
- "TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384",
- "TLS-ECDHE-RSA-WITH-RC4-128-SHA",
- "TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA",
- "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA",
- "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA",
- "TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256",
- "TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256",
- "TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256",
- "TLS-DHE-RSA-WITH-AES-128-GCM-SHA256",
- "TLS-DHE-RSA-WITH-AES-256-GCM-SHA384",
- "TLS-DHE-DSS-WITH-AES-128-CBC-SHA",
- "TLS-DHE-DSS-WITH-AES-256-CBC-SHA",
- "TLS-DHE-DSS-WITH-AES-128-CBC-SHA256",
- "TLS-DHE-DSS-WITH-AES-128-GCM-SHA256",
- "TLS-DHE-DSS-WITH-AES-256-CBC-SHA256",
- "TLS-DHE-DSS-WITH-AES-256-GCM-SHA384",
- "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256",
- "TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256",
- "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384",
- "TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384",
- "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA",
- "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256",
- "TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256",
- "TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384",
- "TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384",
- "TLS-RSA-WITH-AES-128-GCM-SHA256",
- "TLS-RSA-WITH-AES-256-GCM-SHA384",
- "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA",
- "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA",
- "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256",
- "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256",
- "TLS-DHE-DSS-WITH-SEED-CBC-SHA",
- "TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256",
- "TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384",
- "TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256",
- "TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384",
- "TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC-SHA256",
- "TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC-SHA384",
- "TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA",
- "TLS-DHE-DSS-WITH-DES-CBC-SHA"]
-
- ssl_server_cipher_suites_priority:
- description:
- - SSL/TLS cipher suites priority.
- required: false
-
- ssl_server_cipher_suites_versions:
- description:
- - SSL/TLS versions that the cipher suite can be used with.
- - FLAG Based Options. Specify multiple in list form.
- - flag | ssl-3.0 | SSL 3.0.
- - flag | tls-1.0 | TLS 1.0.
- - flag | tls-1.1 | TLS 1.1.
- - flag | tls-1.2 | TLS 1.2.
- required: false
- choices: ["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]
-
-
-'''
-
-EXAMPLES = '''
-# BASIC FULL STATIC NAT MAPPING
-- name: EDIT FMGR_FIREWALL_VIP SNAT
- community.fortios.fmgr_fwobj_vip:
- name: "Basic StaticNAT Map"
- mode: "set"
- adom: "ansible"
- type: "static-nat"
- extip: "82.72.192.185"
- extintf: "any"
- mappedip: "10.7.220.25"
- comment: "Created by Ansible"
- color: "17"
-
-# BASIC PORT PNAT MAPPING
-- name: EDIT FMGR_FIREWALL_VIP PNAT
- community.fortios.fmgr_fwobj_vip:
- name: "Basic PNAT Map Port 10443"
- mode: "set"
- adom: "ansible"
- type: "static-nat"
- extip: "82.72.192.185"
- extport: "10443"
- extintf: "any"
- portforward: "enable"
- protocol: "tcp"
- mappedip: "10.7.220.25"
- mappedport: "443"
- comment: "Created by Ansible"
- color: "17"
-
-# BASIC DNS TRANSLATION NAT
-- name: EDIT FMGR_FIREWALL_DNST
- community.fortios.fmgr_fwobj_vip:
- name: "Basic DNS Translation"
- mode: "set"
- adom: "ansible"
- type: "dns-translation"
- extip: "192.168.0.1-192.168.0.100"
- extintf: "dmz"
- mappedip: "3.3.3.0/24, 4.0.0.0/24"
- comment: "Created by Ansible"
- color: "12"
-
-# BASIC FQDN NAT
-- name: EDIT FMGR_FIREWALL_FQDN
- community.fortios.fmgr_fwobj_vip:
- name: "Basic FQDN Translation"
- mode: "set"
- adom: "ansible"
- type: "fqdn"
- mapped_addr: "google-play"
- comment: "Created by Ansible"
- color: "5"
-
-# DELETE AN ENTRY
-- name: DELETE FMGR_FIREWALL_VIP PNAT
- community.fortios.fmgr_fwobj_vip:
- name: "Basic PNAT Map Port 10443"
- mode: "delete"
- adom: "ansible"
-'''
-
-RETURN = """
-api_result:
- description: full API response, includes status code and message
- returned: always
- type: str
-"""
-
-from ansible.module_utils.basic import AnsibleModule, env_fallback
-from ansible.module_utils.connection import Connection
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRMethods
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import prepare_dict
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import scrub_dict
-
-
-def fmgr_firewall_vip_modify(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
-
- mode = paramgram["mode"]
- adom = paramgram["adom"]
- # INIT A BASIC OBJECTS
- response = DEFAULT_RESULT_OBJ
- url = ""
- datagram = {}
-
- # EVAL THE MODE PARAMETER FOR SET OR ADD
- if mode in ['set', 'add', 'update']:
- url = '/pm/config/adom/{adom}/obj/firewall/vip'.format(adom=adom)
- datagram = scrub_dict(prepare_dict(paramgram))
-
- # EVAL THE MODE PARAMETER FOR DELETE
- elif mode == "delete":
- # SET THE CORRECT URL FOR DELETE
- url = '/pm/config/adom/{adom}/obj/firewall/vip/{name}'.format(adom=adom, name=paramgram["name"])
- datagram = {}
-
- response = fmgr.process_request(url, datagram, paramgram["mode"])
- return response
-
-
-#############
-# END METHODS
-#############
-
-
-def main():
- argument_spec = dict(
- adom=dict(type="str", default="root"),
- mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),
-
- websphere_server=dict(required=False, type="str", choices=["disable", "enable"]),
- weblogic_server=dict(required=False, type="str", choices=["disable", "enable"]),
- type=dict(required=False, type="str",
- choices=["static-nat", "load-balance", "server-load-balance", "dns-translation", "fqdn"]),
- ssl_server_session_state_type=dict(required=False, type="str", choices=["disable", "time", "count", "both"]),
- ssl_server_session_state_timeout=dict(required=False, type="int"),
- ssl_server_session_state_max=dict(required=False, type="int"),
- ssl_server_min_version=dict(required=False, type="str",
- choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2", "client"]),
- ssl_server_max_version=dict(required=False, type="str",
- choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2", "client"]),
- ssl_server_algorithm=dict(required=False, type="str", choices=["high", "low", "medium", "custom", "client"]),
- ssl_send_empty_frags=dict(required=False, type="str", choices=["disable", "enable"]),
- ssl_pfs=dict(required=False, type="str", choices=["require", "deny", "allow"]),
- ssl_mode=dict(required=False, type="str", choices=["half", "full"]),
- ssl_min_version=dict(required=False, type="str", choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]),
- ssl_max_version=dict(required=False, type="str", choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]),
- ssl_http_match_host=dict(required=False, type="str", choices=["disable", "enable"]),
- ssl_http_location_conversion=dict(required=False, type="str", choices=["disable", "enable"]),
- ssl_hsts_include_subdomains=dict(required=False, type="str", choices=["disable", "enable"]),
- ssl_hsts_age=dict(required=False, type="int"),
- ssl_hsts=dict(required=False, type="str", choices=["disable", "enable"]),
- ssl_hpkp_report_uri=dict(required=False, type="str"),
- ssl_hpkp_primary=dict(required=False, type="str"),
- ssl_hpkp_include_subdomains=dict(required=False, type="str", choices=["disable", "enable"]),
- ssl_hpkp_backup=dict(required=False, type="str"),
- ssl_hpkp_age=dict(required=False, type="int"),
- ssl_hpkp=dict(required=False, type="str", choices=["disable", "enable", "report-only"]),
- ssl_dh_bits=dict(required=False, type="str", choices=["768", "1024", "1536", "2048", "3072", "4096"]),
- ssl_client_session_state_type=dict(required=False, type="str", choices=["disable", "time", "count", "both"]),
- ssl_client_session_state_timeout=dict(required=False, type="int"),
- ssl_client_session_state_max=dict(required=False, type="int"),
- ssl_client_renegotiation=dict(required=False, type="str", choices=["deny", "allow", "secure"]),
- ssl_client_fallback=dict(required=False, type="str", choices=["disable", "enable"]),
- ssl_certificate=dict(required=False, type="str"),
- ssl_algorithm=dict(required=False, type="str", choices=["high", "medium", "low", "custom"]),
- srcintf_filter=dict(required=False, type="str"),
- src_filter=dict(required=False, type="str"),
- service=dict(required=False, type="str"),
- server_type=dict(required=False, type="str",
- choices=["http", "https", "ssl", "tcp", "udp", "ip", "imaps", "pop3s", "smtps"]),
- protocol=dict(required=False, type="str", choices=["tcp", "udp", "sctp", "icmp"]),
- portmapping_type=dict(required=False, type="str", choices=["1-to-1", "m-to-n"]),
- portforward=dict(required=False, type="str", choices=["disable", "enable"]),
- persistence=dict(required=False, type="str", choices=["none", "http-cookie", "ssl-session-id"]),
- outlook_web_access=dict(required=False, type="str", choices=["disable", "enable"]),
- nat_source_vip=dict(required=False, type="str", choices=["disable", "enable"]),
- name=dict(required=False, type="str"),
- monitor=dict(required=False, type="str"),
- max_embryonic_connections=dict(required=False, type="int"),
- mappedport=dict(required=False, type="str"),
- mappedip=dict(required=False, type="str"),
- mapped_addr=dict(required=False, type="str"),
- ldb_method=dict(required=False, type="str",
- choices=["static", "round-robin", "weighted", "least-session", "least-rtt", "first-alive",
- "http-host"]),
- https_cookie_secure=dict(required=False, type="str", choices=["disable", "enable"]),
- http_multiplex=dict(required=False, type="str", choices=["disable", "enable"]),
- http_ip_header_name=dict(required=False, type="str"),
- http_ip_header=dict(required=False, type="str", choices=["disable", "enable"]),
- http_cookie_share=dict(required=False, type="str", choices=["disable", "same-ip"]),
- http_cookie_path=dict(required=False, type="str"),
- http_cookie_generation=dict(required=False, type="int"),
- http_cookie_domain_from_host=dict(required=False, type="str", choices=["disable", "enable"]),
- http_cookie_domain=dict(required=False, type="str"),
- http_cookie_age=dict(required=False, type="int"),
- gratuitous_arp_interval=dict(required=False, type="int"),
- extport=dict(required=False, type="str"),
- extip=dict(required=False, type="str"),
- extintf=dict(required=False, type="str"),
- extaddr=dict(required=False, type="str"),
- dns_mapping_ttl=dict(required=False, type="int"),
- comment=dict(required=False, type="str"),
- color=dict(required=False, type="int"),
- arp_reply=dict(required=False, type="str", choices=["disable", "enable"]),
- dynamic_mapping=dict(required=False, type="list"),
- dynamic_mapping_arp_reply=dict(required=False, type="str", choices=["disable", "enable"]),
- dynamic_mapping_color=dict(required=False, type="int"),
- dynamic_mapping_comment=dict(required=False, type="str"),
- dynamic_mapping_dns_mapping_ttl=dict(required=False, type="int"),
- dynamic_mapping_extaddr=dict(required=False, type="str"),
- dynamic_mapping_extintf=dict(required=False, type="str"),
- dynamic_mapping_extip=dict(required=False, type="str"),
- dynamic_mapping_extport=dict(required=False, type="str"),
- dynamic_mapping_gratuitous_arp_interval=dict(required=False, type="int"),
- dynamic_mapping_http_cookie_age=dict(required=False, type="int"),
- dynamic_mapping_http_cookie_domain=dict(required=False, type="str"),
- dynamic_mapping_http_cookie_domain_from_host=dict(required=False, type="str", choices=["disable", "enable"]),
- dynamic_mapping_http_cookie_generation=dict(required=False, type="int"),
- dynamic_mapping_http_cookie_path=dict(required=False, type="str"),
- dynamic_mapping_http_cookie_share=dict(required=False, type="str", choices=["disable", "same-ip"]),
- dynamic_mapping_http_ip_header=dict(required=False, type="str", choices=["disable", "enable"]),
- dynamic_mapping_http_ip_header_name=dict(required=False, type="str"),
- dynamic_mapping_http_multiplex=dict(required=False, type="str", choices=["disable", "enable"]),
- dynamic_mapping_https_cookie_secure=dict(required=False, type="str", choices=["disable", "enable"]),
- dynamic_mapping_ldb_method=dict(required=False, type="str", choices=["static",
- "round-robin",
- "weighted",
- "least-session",
- "least-rtt",
- "first-alive",
- "http-host"]),
- dynamic_mapping_mapped_addr=dict(required=False, type="str"),
- dynamic_mapping_mappedip=dict(required=False, type="str"),
- dynamic_mapping_mappedport=dict(required=False, type="str"),
- dynamic_mapping_max_embryonic_connections=dict(required=False, type="int"),
- dynamic_mapping_monitor=dict(required=False, type="str"),
- dynamic_mapping_nat_source_vip=dict(required=False, type="str", choices=["disable", "enable"]),
- dynamic_mapping_outlook_web_access=dict(required=False, type="str", choices=["disable", "enable"]),
- dynamic_mapping_persistence=dict(required=False, type="str", choices=["none", "http-cookie", "ssl-session-id"]),
- dynamic_mapping_portforward=dict(required=False, type="str", choices=["disable", "enable"]),
- dynamic_mapping_portmapping_type=dict(required=False, type="str", choices=["1-to-1", "m-to-n"]),
- dynamic_mapping_protocol=dict(required=False, type="str", choices=["tcp", "udp", "sctp", "icmp"]),
- dynamic_mapping_server_type=dict(required=False, type="str",
- choices=["http", "https", "ssl", "tcp", "udp", "ip", "imaps", "pop3s",
- "smtps"]),
- dynamic_mapping_service=dict(required=False, type="str"),
- dynamic_mapping_src_filter=dict(required=False, type="str"),
- dynamic_mapping_srcintf_filter=dict(required=False, type="str"),
- dynamic_mapping_ssl_algorithm=dict(required=False, type="str", choices=["high", "medium", "low", "custom"]),
- dynamic_mapping_ssl_certificate=dict(required=False, type="str"),
- dynamic_mapping_ssl_client_fallback=dict(required=False, type="str", choices=["disable", "enable"]),
- dynamic_mapping_ssl_client_renegotiation=dict(required=False, type="str", choices=["deny", "allow", "secure"]),
- dynamic_mapping_ssl_client_session_state_max=dict(required=False, type="int"),
- dynamic_mapping_ssl_client_session_state_timeout=dict(required=False, type="int"),
- dynamic_mapping_ssl_client_session_state_type=dict(required=False, type="str",
- choices=["disable", "time", "count", "both"]),
- dynamic_mapping_ssl_dh_bits=dict(required=False, type="str",
- choices=["768", "1024", "1536", "2048", "3072", "4096"]),
- dynamic_mapping_ssl_hpkp=dict(required=False, type="str", choices=["disable", "enable", "report-only"]),
- dynamic_mapping_ssl_hpkp_age=dict(required=False, type="int"),
- dynamic_mapping_ssl_hpkp_backup=dict(required=False, type="str"),
- dynamic_mapping_ssl_hpkp_include_subdomains=dict(required=False, type="str", choices=["disable", "enable"]),
- dynamic_mapping_ssl_hpkp_primary=dict(required=False, type="str"),
- dynamic_mapping_ssl_hpkp_report_uri=dict(required=False, type="str"),
- dynamic_mapping_ssl_hsts=dict(required=False, type="str", choices=["disable", "enable"]),
- dynamic_mapping_ssl_hsts_age=dict(required=False, type="int"),
- dynamic_mapping_ssl_hsts_include_subdomains=dict(required=False, type="str", choices=["disable", "enable"]),
- dynamic_mapping_ssl_http_location_conversion=dict(required=False, type="str", choices=["disable", "enable"]),
- dynamic_mapping_ssl_http_match_host=dict(required=False, type="str", choices=["disable", "enable"]),
- dynamic_mapping_ssl_max_version=dict(required=False, type="str",
- choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]),
- dynamic_mapping_ssl_min_version=dict(required=False, type="str",
- choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]),
- dynamic_mapping_ssl_mode=dict(required=False, type="str", choices=["half", "full"]),
- dynamic_mapping_ssl_pfs=dict(required=False, type="str", choices=["require", "deny", "allow"]),
- dynamic_mapping_ssl_send_empty_frags=dict(required=False, type="str", choices=["disable", "enable"]),
- dynamic_mapping_ssl_server_algorithm=dict(required=False, type="str",
- choices=["high", "low", "medium", "custom", "client"]),
- dynamic_mapping_ssl_server_max_version=dict(required=False, type="str",
- choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2", "client"]),
- dynamic_mapping_ssl_server_min_version=dict(required=False, type="str",
- choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2", "client"]),
- dynamic_mapping_ssl_server_session_state_max=dict(required=False, type="int"),
- dynamic_mapping_ssl_server_session_state_timeout=dict(required=False, type="int"),
- dynamic_mapping_ssl_server_session_state_type=dict(required=False, type="str",
- choices=["disable", "time", "count", "both"]),
- dynamic_mapping_type=dict(required=False, type="str",
- choices=["static-nat", "load-balance", "server-load-balance", "dns-translation",
- "fqdn"]),
- dynamic_mapping_weblogic_server=dict(required=False, type="str", choices=["disable", "enable"]),
- dynamic_mapping_websphere_server=dict(required=False, type="str", choices=["disable", "enable"]),
-
- dynamic_mapping_realservers_client_ip=dict(required=False, type="str"),
- dynamic_mapping_realservers_healthcheck=dict(required=False, type="str", choices=["disable", "enable", "vip"]),
- dynamic_mapping_realservers_holddown_interval=dict(required=False, type="int"),
- dynamic_mapping_realservers_http_host=dict(required=False, type="str"),
- dynamic_mapping_realservers_ip=dict(required=False, type="str"),
- dynamic_mapping_realservers_max_connections=dict(required=False, type="int"),
- dynamic_mapping_realservers_monitor=dict(required=False, type="str"),
- dynamic_mapping_realservers_port=dict(required=False, type="int"),
- dynamic_mapping_realservers_seq=dict(required=False, type="str"),
- dynamic_mapping_realservers_status=dict(required=False, type="str", choices=["active", "standby", "disable"]),
- dynamic_mapping_realservers_weight=dict(required=False, type="int"),
-
- dynamic_mapping_ssl_cipher_suites_cipher=dict(required=False,
- type="str",
- choices=["TLS-RSA-WITH-RC4-128-MD5",
- "TLS-RSA-WITH-RC4-128-SHA",
- "TLS-RSA-WITH-DES-CBC-SHA",
- "TLS-RSA-WITH-3DES-EDE-CBC-SHA",
- "TLS-RSA-WITH-AES-128-CBC-SHA",
- "TLS-RSA-WITH-AES-256-CBC-SHA",
- "TLS-RSA-WITH-AES-128-CBC-SHA256",
- "TLS-RSA-WITH-AES-256-CBC-SHA256",
- "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA",
- "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA",
- "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256",
- "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256",
- "TLS-RSA-WITH-SEED-CBC-SHA",
- "TLS-RSA-WITH-ARIA-128-CBC-SHA256",
- "TLS-RSA-WITH-ARIA-256-CBC-SHA384",
- "TLS-DHE-RSA-WITH-DES-CBC-SHA",
- "TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA",
- "TLS-DHE-RSA-WITH-AES-128-CBC-SHA",
- "TLS-DHE-RSA-WITH-AES-256-CBC-SHA",
- "TLS-DHE-RSA-WITH-AES-128-CBC-SHA256",
- "TLS-DHE-RSA-WITH-AES-256-CBC-SHA256",
- "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA",
- "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA",
- "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256",
- "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256",
- "TLS-DHE-RSA-WITH-SEED-CBC-SHA",
- "TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256",
- "TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384",
- "TLS-ECDHE-RSA-WITH-RC4-128-SHA",
- "TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA",
- "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA",
- "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA",
- "TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256",
- "TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256",
- "TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256",
- "TLS-DHE-RSA-WITH-AES-128-GCM-SHA256",
- "TLS-DHE-RSA-WITH-AES-256-GCM-SHA384",
- "TLS-DHE-DSS-WITH-AES-128-CBC-SHA",
- "TLS-DHE-DSS-WITH-AES-256-CBC-SHA",
- "TLS-DHE-DSS-WITH-AES-128-CBC-SHA256",
- "TLS-DHE-DSS-WITH-AES-128-GCM-SHA256",
- "TLS-DHE-DSS-WITH-AES-256-CBC-SHA256",
- "TLS-DHE-DSS-WITH-AES-256-GCM-SHA384",
- "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256",
- "TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256",
- "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384",
- "TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384",
- "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA",
- "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256",
- "TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256",
- "TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384",
- "TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384",
- "TLS-RSA-WITH-AES-128-GCM-SHA256",
- "TLS-RSA-WITH-AES-256-GCM-SHA384",
- "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA",
- "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA",
- "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256",
- "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256",
- "TLS-DHE-DSS-WITH-SEED-CBC-SHA",
- "TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256",
- "TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384",
- "TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256",
- "TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384",
- "TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC-SHA256",
- "TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC-SHA384",
- "TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA",
- "TLS-DHE-DSS-WITH-DES-CBC-SHA"]),
- dynamic_mapping_ssl_cipher_suites_versions=dict(required=False, type="str",
- choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]),
- realservers=dict(required=False, type="list"),
- realservers_client_ip=dict(required=False, type="str"),
- realservers_healthcheck=dict(required=False, type="str", choices=["disable", "enable", "vip"]),
- realservers_holddown_interval=dict(required=False, type="int"),
- realservers_http_host=dict(required=False, type="str"),
- realservers_ip=dict(required=False, type="str"),
- realservers_max_connections=dict(required=False, type="int"),
- realservers_monitor=dict(required=False, type="str"),
- realservers_port=dict(required=False, type="int"),
- realservers_seq=dict(required=False, type="str"),
- realservers_status=dict(required=False, type="str", choices=["active", "standby", "disable"]),
- realservers_weight=dict(required=False, type="int"),
- ssl_cipher_suites=dict(required=False, type="list"),
- ssl_cipher_suites_cipher=dict(required=False,
- type="str",
- choices=["TLS-RSA-WITH-RC4-128-MD5",
- "TLS-RSA-WITH-RC4-128-SHA",
- "TLS-RSA-WITH-DES-CBC-SHA",
- "TLS-RSA-WITH-3DES-EDE-CBC-SHA",
- "TLS-RSA-WITH-AES-128-CBC-SHA",
- "TLS-RSA-WITH-AES-256-CBC-SHA",
- "TLS-RSA-WITH-AES-128-CBC-SHA256",
- "TLS-RSA-WITH-AES-256-CBC-SHA256",
- "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA",
- "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA",
- "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256",
- "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256",
- "TLS-RSA-WITH-SEED-CBC-SHA",
- "TLS-RSA-WITH-ARIA-128-CBC-SHA256",
- "TLS-RSA-WITH-ARIA-256-CBC-SHA384",
- "TLS-DHE-RSA-WITH-DES-CBC-SHA",
- "TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA",
- "TLS-DHE-RSA-WITH-AES-128-CBC-SHA",
- "TLS-DHE-RSA-WITH-AES-256-CBC-SHA",
- "TLS-DHE-RSA-WITH-AES-128-CBC-SHA256",
- "TLS-DHE-RSA-WITH-AES-256-CBC-SHA256",
- "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA",
- "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA",
- "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256",
- "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256",
- "TLS-DHE-RSA-WITH-SEED-CBC-SHA",
- "TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256",
- "TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384",
- "TLS-ECDHE-RSA-WITH-RC4-128-SHA",
- "TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA",
- "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA",
- "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA",
- "TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256",
- "TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256",
- "TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256",
- "TLS-DHE-RSA-WITH-AES-128-GCM-SHA256",
- "TLS-DHE-RSA-WITH-AES-256-GCM-SHA384",
- "TLS-DHE-DSS-WITH-AES-128-CBC-SHA",
- "TLS-DHE-DSS-WITH-AES-256-CBC-SHA",
- "TLS-DHE-DSS-WITH-AES-128-CBC-SHA256",
- "TLS-DHE-DSS-WITH-AES-128-GCM-SHA256",
- "TLS-DHE-DSS-WITH-AES-256-CBC-SHA256",
- "TLS-DHE-DSS-WITH-AES-256-GCM-SHA384",
- "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256",
- "TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256",
- "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384",
- "TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384",
- "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA",
- "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256",
- "TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256",
- "TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384",
- "TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384",
- "TLS-RSA-WITH-AES-128-GCM-SHA256",
- "TLS-RSA-WITH-AES-256-GCM-SHA384",
- "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA",
- "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA",
- "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256",
- "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256",
- "TLS-DHE-DSS-WITH-SEED-CBC-SHA",
- "TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256",
- "TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384",
- "TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256",
- "TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384",
- "TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC-SHA256",
- "TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC-SHA384",
- "TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA",
- "TLS-DHE-DSS-WITH-DES-CBC-SHA"]),
- ssl_cipher_suites_versions=dict(required=False, type="str",
- choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]),
- ssl_server_cipher_suites=dict(required=False, type="list"),
- ssl_server_cipher_suites_cipher=dict(required=False,
- type="str",
- choices=["TLS-RSA-WITH-RC4-128-MD5",
- "TLS-RSA-WITH-RC4-128-SHA",
- "TLS-RSA-WITH-DES-CBC-SHA",
- "TLS-RSA-WITH-3DES-EDE-CBC-SHA",
- "TLS-RSA-WITH-AES-128-CBC-SHA",
- "TLS-RSA-WITH-AES-256-CBC-SHA",
- "TLS-RSA-WITH-AES-128-CBC-SHA256",
- "TLS-RSA-WITH-AES-256-CBC-SHA256",
- "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA",
- "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA",
- "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256",
- "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256",
- "TLS-RSA-WITH-SEED-CBC-SHA",
- "TLS-RSA-WITH-ARIA-128-CBC-SHA256",
- "TLS-RSA-WITH-ARIA-256-CBC-SHA384",
- "TLS-DHE-RSA-WITH-DES-CBC-SHA",
- "TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA",
- "TLS-DHE-RSA-WITH-AES-128-CBC-SHA",
- "TLS-DHE-RSA-WITH-AES-256-CBC-SHA",
- "TLS-DHE-RSA-WITH-AES-128-CBC-SHA256",
- "TLS-DHE-RSA-WITH-AES-256-CBC-SHA256",
- "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA",
- "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA",
- "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256",
- "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256",
- "TLS-DHE-RSA-WITH-SEED-CBC-SHA",
- "TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256",
- "TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384",
- "TLS-ECDHE-RSA-WITH-RC4-128-SHA",
- "TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA",
- "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA",
- "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA",
- "TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256",
- "TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256",
- "TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256",
- "TLS-DHE-RSA-WITH-AES-128-GCM-SHA256",
- "TLS-DHE-RSA-WITH-AES-256-GCM-SHA384",
- "TLS-DHE-DSS-WITH-AES-128-CBC-SHA",
- "TLS-DHE-DSS-WITH-AES-256-CBC-SHA",
- "TLS-DHE-DSS-WITH-AES-128-CBC-SHA256",
- "TLS-DHE-DSS-WITH-AES-128-GCM-SHA256",
- "TLS-DHE-DSS-WITH-AES-256-CBC-SHA256",
- "TLS-DHE-DSS-WITH-AES-256-GCM-SHA384",
- "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256",
- "TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256",
- "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384",
- "TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384",
- "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA",
- "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256",
- "TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256",
- "TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384",
- "TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384",
- "TLS-RSA-WITH-AES-128-GCM-SHA256",
- "TLS-RSA-WITH-AES-256-GCM-SHA384",
- "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA",
- "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA",
- "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256",
- "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256",
- "TLS-DHE-DSS-WITH-SEED-CBC-SHA",
- "TLS-DHE-DSS-WITH-ARIA-128-CBC-SHA256",
- "TLS-DHE-DSS-WITH-ARIA-256-CBC-SHA384",
- "TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256",
- "TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384",
- "TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC-SHA256",
- "TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC-SHA384",
- "TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA",
- "TLS-DHE-DSS-WITH-DES-CBC-SHA"]),
- ssl_server_cipher_suites_priority=dict(required=False, type="str"),
- ssl_server_cipher_suites_versions=dict(required=False, type="str",
- choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]),
-
- )
-
- module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
- # MODULE PARAMGRAM
- paramgram = {
- "mode": module.params["mode"],
- "adom": module.params["adom"],
- "websphere-server": module.params["websphere_server"],
- "weblogic-server": module.params["weblogic_server"],
- "type": module.params["type"],
- "ssl-server-session-state-type": module.params["ssl_server_session_state_type"],
- "ssl-server-session-state-timeout": module.params["ssl_server_session_state_timeout"],
- "ssl-server-session-state-max": module.params["ssl_server_session_state_max"],
- "ssl-server-min-version": module.params["ssl_server_min_version"],
- "ssl-server-max-version": module.params["ssl_server_max_version"],
- "ssl-server-algorithm": module.params["ssl_server_algorithm"],
- "ssl-send-empty-frags": module.params["ssl_send_empty_frags"],
- "ssl-pfs": module.params["ssl_pfs"],
- "ssl-mode": module.params["ssl_mode"],
- "ssl-min-version": module.params["ssl_min_version"],
- "ssl-max-version": module.params["ssl_max_version"],
- "ssl-http-match-host": module.params["ssl_http_match_host"],
- "ssl-http-location-conversion": module.params["ssl_http_location_conversion"],
- "ssl-hsts-include-subdomains": module.params["ssl_hsts_include_subdomains"],
- "ssl-hsts-age": module.params["ssl_hsts_age"],
- "ssl-hsts": module.params["ssl_hsts"],
- "ssl-hpkp-report-uri": module.params["ssl_hpkp_report_uri"],
- "ssl-hpkp-primary": module.params["ssl_hpkp_primary"],
- "ssl-hpkp-include-subdomains": module.params["ssl_hpkp_include_subdomains"],
- "ssl-hpkp-backup": module.params["ssl_hpkp_backup"],
- "ssl-hpkp-age": module.params["ssl_hpkp_age"],
- "ssl-hpkp": module.params["ssl_hpkp"],
- "ssl-dh-bits": module.params["ssl_dh_bits"],
- "ssl-client-session-state-type": module.params["ssl_client_session_state_type"],
- "ssl-client-session-state-timeout": module.params["ssl_client_session_state_timeout"],
- "ssl-client-session-state-max": module.params["ssl_client_session_state_max"],
- "ssl-client-renegotiation": module.params["ssl_client_renegotiation"],
- "ssl-client-fallback": module.params["ssl_client_fallback"],
- "ssl-certificate": module.params["ssl_certificate"],
- "ssl-algorithm": module.params["ssl_algorithm"],
- "srcintf-filter": module.params["srcintf_filter"],
- "src-filter": module.params["src_filter"],
- "service": module.params["service"],
- "server-type": module.params["server_type"],
- "protocol": module.params["protocol"],
- "portmapping-type": module.params["portmapping_type"],
- "portforward": module.params["portforward"],
- "persistence": module.params["persistence"],
- "outlook-web-access": module.params["outlook_web_access"],
- "nat-source-vip": module.params["nat_source_vip"],
- "name": module.params["name"],
- "monitor": module.params["monitor"],
- "max-embryonic-connections": module.params["max_embryonic_connections"],
- "mappedport": module.params["mappedport"],
- "mappedip": module.params["mappedip"],
- "mapped-addr": module.params["mapped_addr"],
- "ldb-method": module.params["ldb_method"],
- "https-cookie-secure": module.params["https_cookie_secure"],
- "http-multiplex": module.params["http_multiplex"],
- "http-ip-header-name": module.params["http_ip_header_name"],
- "http-ip-header": module.params["http_ip_header"],
- "http-cookie-share": module.params["http_cookie_share"],
- "http-cookie-path": module.params["http_cookie_path"],
- "http-cookie-generation": module.params["http_cookie_generation"],
- "http-cookie-domain-from-host": module.params["http_cookie_domain_from_host"],
- "http-cookie-domain": module.params["http_cookie_domain"],
- "http-cookie-age": module.params["http_cookie_age"],
- "gratuitous-arp-interval": module.params["gratuitous_arp_interval"],
- "extport": module.params["extport"],
- "extip": module.params["extip"],
- "extintf": module.params["extintf"],
- "extaddr": module.params["extaddr"],
- "dns-mapping-ttl": module.params["dns_mapping_ttl"],
- "comment": module.params["comment"],
- "color": module.params["color"],
- "arp-reply": module.params["arp_reply"],
- "dynamic_mapping": {
- "arp-reply": module.params["dynamic_mapping_arp_reply"],
- "color": module.params["dynamic_mapping_color"],
- "comment": module.params["dynamic_mapping_comment"],
- "dns-mapping-ttl": module.params["dynamic_mapping_dns_mapping_ttl"],
- "extaddr": module.params["dynamic_mapping_extaddr"],
- "extintf": module.params["dynamic_mapping_extintf"],
- "extip": module.params["dynamic_mapping_extip"],
- "extport": module.params["dynamic_mapping_extport"],
- "gratuitous-arp-interval": module.params["dynamic_mapping_gratuitous_arp_interval"],
- "http-cookie-age": module.params["dynamic_mapping_http_cookie_age"],
- "http-cookie-domain": module.params["dynamic_mapping_http_cookie_domain"],
- "http-cookie-domain-from-host": module.params["dynamic_mapping_http_cookie_domain_from_host"],
- "http-cookie-generation": module.params["dynamic_mapping_http_cookie_generation"],
- "http-cookie-path": module.params["dynamic_mapping_http_cookie_path"],
- "http-cookie-share": module.params["dynamic_mapping_http_cookie_share"],
- "http-ip-header": module.params["dynamic_mapping_http_ip_header"],
- "http-ip-header-name": module.params["dynamic_mapping_http_ip_header_name"],
- "http-multiplex": module.params["dynamic_mapping_http_multiplex"],
- "https-cookie-secure": module.params["dynamic_mapping_https_cookie_secure"],
- "ldb-method": module.params["dynamic_mapping_ldb_method"],
- "mapped-addr": module.params["dynamic_mapping_mapped_addr"],
- "mappedip": module.params["dynamic_mapping_mappedip"],
- "mappedport": module.params["dynamic_mapping_mappedport"],
- "max-embryonic-connections": module.params["dynamic_mapping_max_embryonic_connections"],
- "monitor": module.params["dynamic_mapping_monitor"],
- "nat-source-vip": module.params["dynamic_mapping_nat_source_vip"],
- "outlook-web-access": module.params["dynamic_mapping_outlook_web_access"],
- "persistence": module.params["dynamic_mapping_persistence"],
- "portforward": module.params["dynamic_mapping_portforward"],
- "portmapping-type": module.params["dynamic_mapping_portmapping_type"],
- "protocol": module.params["dynamic_mapping_protocol"],
- "server-type": module.params["dynamic_mapping_server_type"],
- "service": module.params["dynamic_mapping_service"],
- "src-filter": module.params["dynamic_mapping_src_filter"],
- "srcintf-filter": module.params["dynamic_mapping_srcintf_filter"],
- "ssl-algorithm": module.params["dynamic_mapping_ssl_algorithm"],
- "ssl-certificate": module.params["dynamic_mapping_ssl_certificate"],
- "ssl-client-fallback": module.params["dynamic_mapping_ssl_client_fallback"],
- "ssl-client-renegotiation": module.params["dynamic_mapping_ssl_client_renegotiation"],
- "ssl-client-session-state-max": module.params["dynamic_mapping_ssl_client_session_state_max"],
- "ssl-client-session-state-timeout": module.params["dynamic_mapping_ssl_client_session_state_timeout"],
- "ssl-client-session-state-type": module.params["dynamic_mapping_ssl_client_session_state_type"],
- "ssl-dh-bits": module.params["dynamic_mapping_ssl_dh_bits"],
- "ssl-hpkp": module.params["dynamic_mapping_ssl_hpkp"],
- "ssl-hpkp-age": module.params["dynamic_mapping_ssl_hpkp_age"],
- "ssl-hpkp-backup": module.params["dynamic_mapping_ssl_hpkp_backup"],
- "ssl-hpkp-include-subdomains": module.params["dynamic_mapping_ssl_hpkp_include_subdomains"],
- "ssl-hpkp-primary": module.params["dynamic_mapping_ssl_hpkp_primary"],
- "ssl-hpkp-report-uri": module.params["dynamic_mapping_ssl_hpkp_report_uri"],
- "ssl-hsts": module.params["dynamic_mapping_ssl_hsts"],
- "ssl-hsts-age": module.params["dynamic_mapping_ssl_hsts_age"],
- "ssl-hsts-include-subdomains": module.params["dynamic_mapping_ssl_hsts_include_subdomains"],
- "ssl-http-location-conversion": module.params["dynamic_mapping_ssl_http_location_conversion"],
- "ssl-http-match-host": module.params["dynamic_mapping_ssl_http_match_host"],
- "ssl-max-version": module.params["dynamic_mapping_ssl_max_version"],
- "ssl-min-version": module.params["dynamic_mapping_ssl_min_version"],
- "ssl-mode": module.params["dynamic_mapping_ssl_mode"],
- "ssl-pfs": module.params["dynamic_mapping_ssl_pfs"],
- "ssl-send-empty-frags": module.params["dynamic_mapping_ssl_send_empty_frags"],
- "ssl-server-algorithm": module.params["dynamic_mapping_ssl_server_algorithm"],
- "ssl-server-max-version": module.params["dynamic_mapping_ssl_server_max_version"],
- "ssl-server-min-version": module.params["dynamic_mapping_ssl_server_min_version"],
- "ssl-server-session-state-max": module.params["dynamic_mapping_ssl_server_session_state_max"],
- "ssl-server-session-state-timeout": module.params["dynamic_mapping_ssl_server_session_state_timeout"],
- "ssl-server-session-state-type": module.params["dynamic_mapping_ssl_server_session_state_type"],
- "type": module.params["dynamic_mapping_type"],
- "weblogic-server": module.params["dynamic_mapping_weblogic_server"],
- "websphere-server": module.params["dynamic_mapping_websphere_server"],
- "realservers": {
- "client-ip": module.params["dynamic_mapping_realservers_client_ip"],
- "healthcheck": module.params["dynamic_mapping_realservers_healthcheck"],
- "holddown-interval": module.params["dynamic_mapping_realservers_holddown_interval"],
- "http-host": module.params["dynamic_mapping_realservers_http_host"],
- "ip": module.params["dynamic_mapping_realservers_ip"],
- "max-connections": module.params["dynamic_mapping_realservers_max_connections"],
- "monitor": module.params["dynamic_mapping_realservers_monitor"],
- "port": module.params["dynamic_mapping_realservers_port"],
- "seq": module.params["dynamic_mapping_realservers_seq"],
- "status": module.params["dynamic_mapping_realservers_status"],
- "weight": module.params["dynamic_mapping_realservers_weight"],
- },
- "ssl-cipher-suites": {
- "cipher": module.params["dynamic_mapping_ssl_cipher_suites_cipher"],
- "versions": module.params["dynamic_mapping_ssl_cipher_suites_versions"],
- },
- },
- "realservers": {
- "client-ip": module.params["realservers_client_ip"],
- "healthcheck": module.params["realservers_healthcheck"],
- "holddown-interval": module.params["realservers_holddown_interval"],
- "http-host": module.params["realservers_http_host"],
- "ip": module.params["realservers_ip"],
- "max-connections": module.params["realservers_max_connections"],
- "monitor": module.params["realservers_monitor"],
- "port": module.params["realservers_port"],
- "seq": module.params["realservers_seq"],
- "status": module.params["realservers_status"],
- "weight": module.params["realservers_weight"],
- },
- "ssl-cipher-suites": {
- "cipher": module.params["ssl_cipher_suites_cipher"],
- "versions": module.params["ssl_cipher_suites_versions"],
- },
- "ssl-server-cipher-suites": {
- "cipher": module.params["ssl_server_cipher_suites_cipher"],
- "priority": module.params["ssl_server_cipher_suites_priority"],
- "versions": module.params["ssl_server_cipher_suites_versions"],
- }
- }
- module.paramgram = paramgram
- fmgr = None
- if module._socket_path:
- connection = Connection(module._socket_path)
- fmgr = FortiManagerHandler(connection, module)
- fmgr.tools = FMGRCommon()
- else:
- module.fail_json(**FAIL_SOCKET_MSG)
-
- list_overrides = ['dynamic_mapping', 'realservers', 'ssl-cipher-suites', 'ssl-server-cipher-suites']
- paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
- paramgram=paramgram, module=module)
-
- results = DEFAULT_RESULT_OBJ
- try:
- results = fmgr_firewall_vip_modify(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
-
- except Exception as err:
- raise FMGBaseException(err)
-
- return module.exit_json(**results[1])
-
-
-if __name__ == "__main__":
- main()
diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_fwpol_ipv4.py b/ansible_collections/community/fortios/plugins/modules/fmgr_fwpol_ipv4.py
deleted file mode 100644
index f0b0fd9c8..000000000
--- a/ansible_collections/community/fortios/plugins/modules/fmgr_fwpol_ipv4.py
+++ /dev/null
@@ -1,1355 +0,0 @@
-#!/usr/bin/python
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-
-from __future__ import absolute_import, division, print_function
-
-__metaclass__ = type
-
-DOCUMENTATION = '''
----
-module: fmgr_fwpol_ipv4
-notes:
- - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
-author:
- - Luke Weighall (@lweighall)
- - Andrew Welsh (@Ghilli3)
- - Jim Huber (@p4r4n0y1ng)
-short_description: Allows the add/delete of Firewall Policies on Packages in FortiManager.
-description:
- - Allows the add/delete of Firewall Policies on Packages in FortiManager.
-
-options:
- adom:
- description:
- - The ADOM the configuration should belong to.
- required: false
- default: root
-
- mode:
- description:
- - Sets one of three modes for managing the object.
- - Allows use of soft-adds instead of overwriting existing values
- choices: ['add', 'set', 'delete', 'update']
- required: false
- default: add
-
- package_name:
- description:
- - The policy package you want to modify
- required: false
- default: "default"
-
- fail_on_missing_dependency:
- description:
- - Normal behavior is to "skip" tasks that fail dependency checks, so other tasks can run.
- - If set to "enabled" if a failed dependency check happeens, Ansible will exit as with failure instead of skip.
- required: false
- default: "disable"
- choices: ["enable", "disable"]
-
- wsso:
- description:
- - Enable/disable WiFi Single Sign On (WSSO).
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- webfilter_profile:
- description:
- - Name of an existing Web filter profile.
- required: false
-
- webcache_https:
- description:
- - Enable/disable web cache for HTTPS.
- - choice | disable | Disable web cache for HTTPS.
- - choice | enable | Enable web cache for HTTPS.
- required: false
- choices: ["disable", "enable"]
-
- webcache:
- description:
- - Enable/disable web cache.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- wccp:
- description:
- - Enable/disable forwarding traffic matching this policy to a configured WCCP server.
- - choice | disable | Disable WCCP setting.
- - choice | enable | Enable WCCP setting.
- required: false
- choices: ["disable", "enable"]
-
- wanopt_profile:
- description:
- - WAN optimization profile.
- required: false
-
- wanopt_peer:
- description:
- - WAN optimization peer.
- required: false
-
- wanopt_passive_opt:
- description:
- - WAN optimization passive mode options. This option decides what IP address will be used to connect server.
- - choice | default | Allow client side WAN opt peer to decide.
- - choice | transparent | Use address of client to connect to server.
- - choice | non-transparent | Use local FortiGate address to connect to server.
- required: false
- choices: ["default", "transparent", "non-transparent"]
-
- wanopt_detection:
- description:
- - WAN optimization auto-detection mode.
- - choice | active | Active WAN optimization peer auto-detection.
- - choice | passive | Passive WAN optimization peer auto-detection.
- - choice | off | Turn off WAN optimization peer auto-detection.
- required: false
- choices: ["active", "passive", "off"]
-
- wanopt:
- description:
- - Enable/disable WAN optimization.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- waf_profile:
- description:
- - Name of an existing Web application firewall profile.
- required: false
-
- vpntunnel:
- description:
- - Policy-based IPsec VPN | name of the IPsec VPN Phase 1.
- required: false
-
- voip_profile:
- description:
- - Name of an existing VoIP profile.
- required: false
-
- vlan_filter:
- description:
- - Set VLAN filters.
- required: false
-
- vlan_cos_rev:
- description:
- - VLAN reverse direction user priority | 255 passthrough, 0 lowest, 7 highest..
- required: false
-
- vlan_cos_fwd:
- description:
- - VLAN forward direction user priority | 255 passthrough, 0 lowest, 7 highest.
- required: false
-
- utm_status:
- description:
- - Enable to add one or more security profiles (AV, IPS, etc.) to the firewall policy.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- users:
- description:
- - Names of individual users that can authenticate with this policy.
- required: false
-
- url_category:
- description:
- - URL category ID list.
- required: false
-
- traffic_shaper_reverse:
- description:
- - Reverse traffic shaper.
- required: false
-
- traffic_shaper:
- description:
- - Traffic shaper.
- required: false
-
- timeout_send_rst:
- description:
- - Enable/disable sending RST packets when TCP sessions expire.
- - choice | disable | Disable sending of RST packet upon TCP session expiration.
- - choice | enable | Enable sending of RST packet upon TCP session expiration.
- required: false
- choices: ["disable", "enable"]
-
- tcp_session_without_syn:
- description:
- - Enable/disable creation of TCP session without SYN flag.
- - choice | all | Enable TCP session without SYN.
- - choice | data-only | Enable TCP session data only.
- - choice | disable | Disable TCP session without SYN.
- required: false
- choices: ["all", "data-only", "disable"]
-
- tcp_mss_sender:
- description:
- - Sender TCP maximum segment size (MSS).
- required: false
-
- tcp_mss_receiver:
- description:
- - Receiver TCP maximum segment size (MSS).
- required: false
-
- status:
- description:
- - Enable or disable this policy.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- ssl_ssh_profile:
- description:
- - Name of an existing SSL SSH profile.
- required: false
-
- ssl_mirror_intf:
- description:
- - SSL mirror interface name.
- required: false
-
- ssl_mirror:
- description:
- - Enable to copy decrypted SSL traffic to a FortiGate interface (called SSL mirroring).
- - choice | disable | Disable SSL mirror.
- - choice | enable | Enable SSL mirror.
- required: false
- choices: ["disable", "enable"]
-
- ssh_filter_profile:
- description:
- - Name of an existing SSH filter profile.
- required: false
-
- srcintf:
- description:
- - Incoming (ingress) interface.
- required: false
-
- srcaddr_negate:
- description:
- - When enabled srcaddr specifies what the source address must NOT be.
- - choice | disable | Disable source address negate.
- - choice | enable | Enable source address negate.
- required: false
- choices: ["disable", "enable"]
-
- srcaddr:
- description:
- - Source address and address group names.
- required: false
-
- spamfilter_profile:
- description:
- - Name of an existing Spam filter profile.
- required: false
-
- session_ttl:
- description:
- - TTL in seconds for sessions accepted by this policy (0 means use the system default session TTL).
- required: false
-
- service_negate:
- description:
- - When enabled service specifies what the service must NOT be.
- - choice | disable | Disable negated service match.
- - choice | enable | Enable negated service match.
- required: false
- choices: ["disable", "enable"]
-
- service:
- description:
- - Service and service group names.
- required: false
-
- send_deny_packet:
- description:
- - Enable to send a reply when a session is denied or blocked by a firewall policy.
- - choice | disable | Disable deny-packet sending.
- - choice | enable | Enable deny-packet sending.
- required: false
- choices: ["disable", "enable"]
-
- schedule_timeout:
- description:
- - Enable to force current sessions to end when the schedule object times out.
- - choice | disable | Disable schedule timeout.
- - choice | enable | Enable schedule timeout.
- required: false
- choices: ["disable", "enable"]
-
- schedule:
- description:
- - Schedule name.
- required: false
-
- scan_botnet_connections:
- description:
- - Block or monitor connections to Botnet servers or disable Botnet scanning.
- - choice | disable | Do not scan connections to botnet servers.
- - choice | block | Block connections to botnet servers.
- - choice | monitor | Log connections to botnet servers.
- required: false
- choices: ["disable", "block", "monitor"]
-
- rtp_nat:
- description:
- - Enable Real Time Protocol (RTP) NAT.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- rtp_addr:
- description:
- - Address names if this is an RTP NAT policy.
- required: false
-
- rsso:
- description:
- - Enable/disable RADIUS single sign-on (RSSO).
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- replacemsg_override_group:
- description:
- - Override the default replacement message group for this policy.
- required: false
-
- redirect_url:
- description:
- - URL users are directed to after seeing and accepting the disclaimer or authenticating.
- required: false
-
- radius_mac_auth_bypass:
- description:
- - Enable MAC authentication bypass. The bypassed MAC address must be received from RADIUS server.
- - choice | disable | Disable MAC authentication bypass.
- - choice | enable | Enable MAC authentication bypass.
- required: false
- choices: ["disable", "enable"]
-
- profile_type:
- description:
- - Determine whether the firewall policy allows security profile groups or single profiles only.
- - choice | single | Do not allow security profile groups.
- - choice | group | Allow security profile groups.
- required: false
- choices: ["single", "group"]
-
- profile_protocol_options:
- description:
- - Name of an existing Protocol options profile.
- required: false
-
- profile_group:
- description:
- - Name of profile group.
- required: false
-
- poolname:
- description:
- - IP Pool names.
- required: false
-
- policyid:
- description:
- - Policy ID.
- required: false
-
- permit_stun_host:
- description:
- - Accept UDP packets from any Session Traversal Utilities for NAT (STUN) host.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- permit_any_host:
- description:
- - Accept UDP packets from any host.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- per_ip_shaper:
- description:
- - Per-IP traffic shaper.
- required: false
-
- outbound:
- description:
- - Policy-based IPsec VPN | only traffic from the internal network can initiate a VPN.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- ntlm_guest:
- description:
- - Enable/disable NTLM guest user access.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- ntlm_enabled_browsers:
- description:
- - HTTP-User-Agent value of supported browsers.
- required: false
-
- ntlm:
- description:
- - Enable/disable NTLM authentication.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- np_acceleration:
- description:
- - Enable/disable UTM Network Processor acceleration.
- - choice | disable | Disable UTM Network Processor acceleration.
- - choice | enable | Enable UTM Network Processor acceleration.
- required: false
- choices: ["disable", "enable"]
-
- natoutbound:
- description:
- - Policy-based IPsec VPN | apply source NAT to outbound traffic.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- natip:
- description:
- - Policy-based IPsec VPN | source NAT IP address for outgoing traffic.
- required: false
-
- natinbound:
- description:
- - Policy-based IPsec VPN | apply destination NAT to inbound traffic.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- nat:
- description:
- - Enable/disable source NAT.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- name:
- description:
- - Policy name.
- required: false
-
- mms_profile:
- description:
- - Name of an existing MMS profile.
- required: false
-
- match_vip:
- description:
- - Enable to match packets that have had their destination addresses changed by a VIP.
- - choice | disable | Do not match DNATed packet.
- - choice | enable | Match DNATed packet.
- required: false
- choices: ["disable", "enable"]
-
- logtraffic_start:
- description:
- - Record logs when a session starts and ends.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- logtraffic:
- description:
- - Enable or disable logging. Log all sessions or security profile sessions.
- - choice | disable | Disable all logging for this policy.
- - choice | all | Log all sessions accepted or denied by this policy.
- - choice | utm | Log traffic that has a security profile applied to it.
- required: false
- choices: ["disable", "all", "utm"]
-
- learning_mode:
- description:
- - Enable to allow everything, but log all of the meaningful data for security information gathering.
- - choice | disable | Disable learning mode in firewall policy.
- - choice | enable | Enable learning mode in firewall policy.
- required: false
- choices: ["disable", "enable"]
-
- label:
- description:
- - Label for the policy that appears when the GUI is in Section View mode.
- required: false
-
- ips_sensor:
- description:
- - Name of an existing IPS sensor.
- required: false
-
- ippool:
- description:
- - Enable to use IP Pools for source NAT.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- internet_service_src_negate:
- description:
- - When enabled internet-service-src specifies what the service must NOT be.
- - choice | disable | Disable negated Internet Service source match.
- - choice | enable | Enable negated Internet Service source match.
- required: false
- choices: ["disable", "enable"]
-
- internet_service_src_id:
- description:
- - Internet Service source ID.
- required: false
-
- internet_service_src_custom:
- description:
- - Custom Internet Service source name.
- required: false
-
- internet_service_src:
- description:
- - Enable/disable use of Internet Services in source for this policy. If enabled, source address is not used.
- - choice | disable | Disable use of Internet Services source in policy.
- - choice | enable | Enable use of Internet Services source in policy.
- required: false
- choices: ["disable", "enable"]
-
- internet_service_negate:
- description:
- - When enabled internet-service specifies what the service must NOT be.
- - choice | disable | Disable negated Internet Service match.
- - choice | enable | Enable negated Internet Service match.
- required: false
- choices: ["disable", "enable"]
-
- internet_service_id:
- description:
- - Internet Service ID.
- required: false
-
- internet_service_custom:
- description:
- - Custom Internet Service name.
- required: false
-
- internet_service:
- description:
- - Enable/disable use of Internet Services for this policy. If enabled, dstaddr and service are not used.
- - choice | disable | Disable use of Internet Services in policy.
- - choice | enable | Enable use of Internet Services in policy.
- required: false
- choices: ["disable", "enable"]
-
- inbound:
- description:
- - Policy-based IPsec VPN | only traffic from the remote network can initiate a VPN.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- identity_based_route:
- description:
- - Name of identity-based routing rule.
- required: false
-
- icap_profile:
- description:
- - Name of an existing ICAP profile.
- required: false
-
- gtp_profile:
- description:
- - GTP profile.
- required: false
-
- groups:
- description:
- - Names of user groups that can authenticate with this policy.
- required: false
-
- global_label:
- description:
- - Label for the policy that appears when the GUI is in Global View mode.
- required: false
-
- fsso_agent_for_ntlm:
- description:
- - FSSO agent to use for NTLM authentication.
- required: false
-
- fsso:
- description:
- - Enable/disable Fortinet Single Sign-On.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- fixedport:
- description:
- - Enable to prevent source NAT from changing a session's source port.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- firewall_session_dirty:
- description:
- - How to handle sessions if the configuration of this firewall policy changes.
- - choice | check-all | Flush all current sessions accepted by this policy.
- - choice | check-new | Continue to allow sessions already accepted by this policy.
- required: false
- choices: ["check-all", "check-new"]
-
- dstintf:
- description:
- - Outgoing (egress) interface.
- required: false
-
- dstaddr_negate:
- description:
- - When enabled dstaddr specifies what the destination address must NOT be.
- - choice | disable | Disable destination address negate.
- - choice | enable | Enable destination address negate.
- required: false
- choices: ["disable", "enable"]
-
- dstaddr:
- description:
- - Destination address and address group names.
- required: false
-
- dsri:
- description:
- - Enable DSRI to ignore HTTP server responses.
- - choice | disable | Disable DSRI.
- - choice | enable | Enable DSRI.
- required: false
- choices: ["disable", "enable"]
-
- dscp_value:
- description:
- - DSCP value.
- required: false
-
- dscp_negate:
- description:
- - Enable negated DSCP match.
- - choice | disable | Disable DSCP negate.
- - choice | enable | Enable DSCP negate.
- required: false
- choices: ["disable", "enable"]
-
- dscp_match:
- description:
- - Enable DSCP check.
- - choice | disable | Disable DSCP check.
- - choice | enable | Enable DSCP check.
- required: false
- choices: ["disable", "enable"]
-
- dnsfilter_profile:
- description:
- - Name of an existing DNS filter profile.
- required: false
-
- dlp_sensor:
- description:
- - Name of an existing DLP sensor.
- required: false
-
- disclaimer:
- description:
- - Enable/disable user authentication disclaimer.
- - choice | disable | Disable user authentication disclaimer.
- - choice | enable | Enable user authentication disclaimer.
- required: false
- choices: ["disable", "enable"]
-
- diffservcode_rev:
- description:
- - Change packet's reverse (reply) DiffServ to this value.
- required: false
-
- diffservcode_forward:
- description:
- - Change packet's DiffServ to this value.
- required: false
-
- diffserv_reverse:
- description:
- - Enable to change packet's reverse (reply) DiffServ values to the specified diffservcode-rev value.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- diffserv_forward:
- description:
- - Enable to change packet's DiffServ values to the specified diffservcode-forward value.
- - choice | disable | Disable WAN optimization.
- - choice | enable | Enable WAN optimization.
- required: false
- choices: ["disable", "enable"]
-
- devices:
- description:
- - Names of devices or device groups that can be matched by the policy.
- required: false
-
- delay_tcp_npu_session:
- description:
- - Enable TCP NPU session delay to guarantee packet order of 3-way handshake.
- - choice | disable | Disable TCP NPU session delay in order to guarantee packet order of 3-way handshake.
- - choice | enable | Enable TCP NPU session delay in order to guarantee packet order of 3-way handshake.
- required: false
- choices: ["disable", "enable"]
-
- custom_log_fields:
- description:
- - Custom fields to append to log messages for this policy.
- required: false
-
- comments:
- description:
- - Comment.
- required: false
-
- capture_packet:
- description:
- - Enable/disable capture packets.
- - choice | disable | Disable capture packets.
- - choice | enable | Enable capture packets.
- required: false
- choices: ["disable", "enable"]
-
- captive_portal_exempt:
- description:
- - Enable to exempt some users from the captive portal.
- - choice | disable | Disable exemption of captive portal.
- - choice | enable | Enable exemption of captive portal.
- required: false
- choices: ["disable", "enable"]
-
- block_notification:
- description:
- - Enable/disable block notification.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- av_profile:
- description:
- - Name of an existing Antivirus profile.
- required: false
-
- auto_asic_offload:
- description:
- - Enable/disable offloading security profile processing to CP processors.
- - choice | disable | Disable ASIC offloading.
- - choice | enable | Enable auto ASIC offloading.
- required: false
- choices: ["disable", "enable"]
-
- auth_redirect_addr:
- description:
- - HTTP-to-HTTPS redirect address for firewall authentication.
- required: false
-
- auth_path:
- description:
- - Enable/disable authentication-based routing.
- - choice | disable | Disable authentication-based routing.
- - choice | enable | Enable authentication-based routing.
- required: false
- choices: ["disable", "enable"]
-
- auth_cert:
- description:
- - HTTPS server certificate for policy authentication.
- required: false
-
- application_list:
- description:
- - Name of an existing Application list.
- required: false
-
- application:
- description:
- - Application ID list.
- required: false
-
- app_group:
- description:
- - Application group names.
- required: false
-
- app_category:
- description:
- - Application category ID list.
- required: false
-
- action:
- description:
- - Policy action (allow/deny/ipsec).
- - choice | deny | Blocks sessions that match the firewall policy.
- - choice | accept | Allows session that match the firewall policy.
- - choice | ipsec | Firewall policy becomes a policy-based IPsec VPN policy.
- required: false
- choices: ["deny", "accept", "ipsec"]
-
- vpn_dst_node:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED. This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- required: false
-
- vpn_dst_node_host:
- description:
- - VPN Destination Node Host.
- required: false
-
- vpn_dst_node_seq:
- description:
- - VPN Destination Node Seq.
- required: false
-
- vpn_dst_node_subnet:
- description:
- - VPN Destination Node Seq.
- required: false
-
- vpn_src_node:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED. This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- required: false
-
- vpn_src_node_host:
- description:
- - VPN Source Node Host.
- required: false
-
- vpn_src_node_seq:
- description:
- - VPN Source Node Seq.
- required: false
-
- vpn_src_node_subnet:
- description:
- - VPN Source Node.
- required: false
-
-
-'''
-
-EXAMPLES = '''
-- name: ADD VERY BASIC IPV4 POLICY WITH NO NAT (WIDE OPEN)
- community.fortios.fmgr_fwpol_ipv4:
- mode: "set"
- adom: "ansible"
- package_name: "default"
- name: "Basic_IPv4_Policy"
- comments: "Created by Ansible"
- action: "accept"
- dstaddr: "all"
- srcaddr: "all"
- dstintf: "any"
- srcintf: "any"
- logtraffic: "utm"
- service: "ALL"
- schedule: "always"
-
-- name: ADD VERY BASIC IPV4 POLICY WITH NAT AND MULTIPLE ENTRIES
- community.fortios.fmgr_fwpol_ipv4:
- mode: "set"
- adom: "ansible"
- package_name: "default"
- name: "Basic_IPv4_Policy_2"
- comments: "Created by Ansible"
- action: "accept"
- dstaddr: "google-play"
- srcaddr: "all"
- dstintf: "any"
- srcintf: "any"
- logtraffic: "utm"
- service: "HTTP, HTTPS"
- schedule: "always"
- nat: "enable"
- users: "karen, kevin"
-
-- name: ADD VERY BASIC IPV4 POLICY WITH NAT AND MULTIPLE ENTRIES AND SEC PROFILES
- community.fortios.fmgr_fwpol_ipv4:
- mode: "set"
- adom: "ansible"
- package_name: "default"
- name: "Basic_IPv4_Policy_3"
- comments: "Created by Ansible"
- action: "accept"
- dstaddr: "google-play, autoupdate.opera.com"
- srcaddr: "corp_internal"
- dstintf: "zone_wan1, zone_wan2"
- srcintf: "zone_int1"
- logtraffic: "utm"
- service: "HTTP, HTTPS"
- schedule: "always"
- nat: "enable"
- users: "karen, kevin"
- av_profile: "sniffer-profile"
- ips_sensor: "default"
-
-'''
-
-RETURN = """
-api_result:
- description: full API response, includes status code and message
- returned: always
- type: str
-"""
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.connection import Connection
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRMethods
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import prepare_dict
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import scrub_dict
-
-
-def fmgr_firewall_policy_modify(fmgr, paramgram):
- """
- fmgr_firewall_policy -- Add/Set/Deletes Firewall Policy Objects defined in the "paramgram"
-
- :param fmgr: The fmgr object instance from fmgr_utils.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
-
- :return: The response from the FortiManager
- :rtype: dict
- """
-
- mode = paramgram["mode"]
- adom = paramgram["adom"]
- # INIT A BASIC OBJECTS
- response = DEFAULT_RESULT_OBJ
- url = ""
- datagram = {}
-
- # EVAL THE MODE PARAMETER FOR SET OR ADD
- if mode in ['set', 'add', 'update']:
- url = '/pm/config/adom/{adom}/pkg/{pkg}/firewall/policy'.format(adom=adom, pkg=paramgram["package_name"])
- datagram = scrub_dict((prepare_dict(paramgram)))
- del datagram["package_name"]
- datagram = fmgr._tools.split_comma_strings_into_lists(datagram)
-
- # EVAL THE MODE PARAMETER FOR DELETE
- elif mode == "delete":
- url = '/pm/config/adom/{adom}/pkg/{pkg}/firewall' \
- '/policy/{policyid}'.format(adom=paramgram["adom"],
- pkg=paramgram["package_name"],
- policyid=paramgram["policyid"])
- datagram = {
- "policyid": paramgram["policyid"]
- }
-
- response = fmgr.process_request(url, datagram, paramgram["mode"])
- return response
-
-
-#############
-# END METHODS
-#############
-
-
-def main():
- argument_spec = dict(
- adom=dict(type="str", default="root"),
- mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),
- package_name=dict(type="str", required=False, default="default"),
- fail_on_missing_dependency=dict(type="str", required=False, default="disable", choices=["enable",
- "disable"]),
- wsso=dict(required=False, type="str", choices=["disable", "enable"]),
- webfilter_profile=dict(required=False, type="str"),
- webcache_https=dict(required=False, type="str", choices=["disable", "enable"]),
- webcache=dict(required=False, type="str", choices=["disable", "enable"]),
- wccp=dict(required=False, type="str", choices=["disable", "enable"]),
- wanopt_profile=dict(required=False, type="str"),
- wanopt_peer=dict(required=False, type="str"),
- wanopt_passive_opt=dict(required=False, type="str", choices=["default", "transparent", "non-transparent"]),
- wanopt_detection=dict(required=False, type="str", choices=["active", "passive", "off"]),
- wanopt=dict(required=False, type="str", choices=["disable", "enable"]),
- waf_profile=dict(required=False, type="str"),
- vpntunnel=dict(required=False, type="str"),
- voip_profile=dict(required=False, type="str"),
- vlan_filter=dict(required=False, type="str"),
- vlan_cos_rev=dict(required=False, type="int"),
- vlan_cos_fwd=dict(required=False, type="int"),
- utm_status=dict(required=False, type="str", choices=["disable", "enable"]),
- users=dict(required=False, type="str"),
- url_category=dict(required=False, type="str"),
- traffic_shaper_reverse=dict(required=False, type="str"),
- traffic_shaper=dict(required=False, type="str"),
- timeout_send_rst=dict(required=False, type="str", choices=["disable", "enable"]),
- tcp_session_without_syn=dict(required=False, type="str", choices=["all", "data-only", "disable"]),
- tcp_mss_sender=dict(required=False, type="int"),
- tcp_mss_receiver=dict(required=False, type="int"),
- status=dict(required=False, type="str", choices=["disable", "enable"]),
- ssl_ssh_profile=dict(required=False, type="str"),
- ssl_mirror_intf=dict(required=False, type="str"),
- ssl_mirror=dict(required=False, type="str", choices=["disable", "enable"]),
- ssh_filter_profile=dict(required=False, type="str"),
- srcintf=dict(required=False, type="str"),
- srcaddr_negate=dict(required=False, type="str", choices=["disable", "enable"]),
- srcaddr=dict(required=False, type="str"),
- spamfilter_profile=dict(required=False, type="str"),
- session_ttl=dict(required=False, type="int"),
- service_negate=dict(required=False, type="str", choices=["disable", "enable"]),
- service=dict(required=False, type="str"),
- send_deny_packet=dict(required=False, type="str", choices=["disable", "enable"]),
- schedule_timeout=dict(required=False, type="str", choices=["disable", "enable"]),
- schedule=dict(required=False, type="str"),
- scan_botnet_connections=dict(required=False, type="str", choices=["disable", "block", "monitor"]),
- rtp_nat=dict(required=False, type="str", choices=["disable", "enable"]),
- rtp_addr=dict(required=False, type="str"),
- rsso=dict(required=False, type="str", choices=["disable", "enable"]),
- replacemsg_override_group=dict(required=False, type="str"),
- redirect_url=dict(required=False, type="str"),
- radius_mac_auth_bypass=dict(required=False, type="str", choices=["disable", "enable"]),
- profile_type=dict(required=False, type="str", choices=["single", "group"]),
- profile_protocol_options=dict(required=False, type="str"),
- profile_group=dict(required=False, type="str"),
- poolname=dict(required=False, type="str"),
- policyid=dict(required=False, type="str"),
- permit_stun_host=dict(required=False, type="str", choices=["disable", "enable"]),
- permit_any_host=dict(required=False, type="str", choices=["disable", "enable"]),
- per_ip_shaper=dict(required=False, type="str"),
- outbound=dict(required=False, type="str", choices=["disable", "enable"]),
- ntlm_guest=dict(required=False, type="str", choices=["disable", "enable"]),
- ntlm_enabled_browsers=dict(required=False, type="str"),
- ntlm=dict(required=False, type="str", choices=["disable", "enable"]),
- np_acceleration=dict(required=False, type="str", choices=["disable", "enable"]),
- natoutbound=dict(required=False, type="str", choices=["disable", "enable"]),
- natip=dict(required=False, type="str"),
- natinbound=dict(required=False, type="str", choices=["disable", "enable"]),
- nat=dict(required=False, type="str", choices=["disable", "enable"]),
- name=dict(required=False, type="str"),
- mms_profile=dict(required=False, type="str"),
- match_vip=dict(required=False, type="str", choices=["disable", "enable"]),
- logtraffic_start=dict(required=False, type="str", choices=["disable", "enable"]),
- logtraffic=dict(required=False, type="str", choices=["disable", "all", "utm"]),
- learning_mode=dict(required=False, type="str", choices=["disable", "enable"]),
- label=dict(required=False, type="str"),
- ips_sensor=dict(required=False, type="str"),
- ippool=dict(required=False, type="str", choices=["disable", "enable"]),
- internet_service_src_negate=dict(required=False, type="str", choices=["disable", "enable"]),
- internet_service_src_id=dict(required=False, type="str"),
- internet_service_src_custom=dict(required=False, type="str"),
- internet_service_src=dict(required=False, type="str", choices=["disable", "enable"]),
- internet_service_negate=dict(required=False, type="str", choices=["disable", "enable"]),
- internet_service_id=dict(required=False, type="str"),
- internet_service_custom=dict(required=False, type="str"),
- internet_service=dict(required=False, type="str", choices=["disable", "enable"]),
- inbound=dict(required=False, type="str", choices=["disable", "enable"]),
- identity_based_route=dict(required=False, type="str"),
- icap_profile=dict(required=False, type="str"),
- gtp_profile=dict(required=False, type="str"),
- groups=dict(required=False, type="str"),
- global_label=dict(required=False, type="str"),
- fsso_agent_for_ntlm=dict(required=False, type="str"),
- fsso=dict(required=False, type="str", choices=["disable", "enable"]),
- fixedport=dict(required=False, type="str", choices=["disable", "enable"]),
- firewall_session_dirty=dict(required=False, type="str", choices=["check-all", "check-new"]),
- dstintf=dict(required=False, type="str"),
- dstaddr_negate=dict(required=False, type="str", choices=["disable", "enable"]),
- dstaddr=dict(required=False, type="str"),
- dsri=dict(required=False, type="str", choices=["disable", "enable"]),
- dscp_value=dict(required=False, type="str"),
- dscp_negate=dict(required=False, type="str", choices=["disable", "enable"]),
- dscp_match=dict(required=False, type="str", choices=["disable", "enable"]),
- dnsfilter_profile=dict(required=False, type="str"),
- dlp_sensor=dict(required=False, type="str"),
- disclaimer=dict(required=False, type="str", choices=["disable", "enable"]),
- diffservcode_rev=dict(required=False, type="str"),
- diffservcode_forward=dict(required=False, type="str"),
- diffserv_reverse=dict(required=False, type="str", choices=["disable", "enable"]),
- diffserv_forward=dict(required=False, type="str", choices=["disable", "enable"]),
- devices=dict(required=False, type="str"),
- delay_tcp_npu_session=dict(required=False, type="str", choices=["disable", "enable"]),
- custom_log_fields=dict(required=False, type="str"),
- comments=dict(required=False, type="str"),
- capture_packet=dict(required=False, type="str", choices=["disable", "enable"]),
- captive_portal_exempt=dict(required=False, type="str", choices=["disable", "enable"]),
- block_notification=dict(required=False, type="str", choices=["disable", "enable"]),
- av_profile=dict(required=False, type="str"),
- auto_asic_offload=dict(required=False, type="str", choices=["disable", "enable"]),
- auth_redirect_addr=dict(required=False, type="str"),
- auth_path=dict(required=False, type="str", choices=["disable", "enable"]),
- auth_cert=dict(required=False, type="str"),
- application_list=dict(required=False, type="str"),
- application=dict(required=False, type="str"),
- app_group=dict(required=False, type="str"),
- app_category=dict(required=False, type="str"),
- action=dict(required=False, type="str", choices=["deny", "accept", "ipsec"]),
- vpn_dst_node=dict(required=False, type="list"),
- vpn_dst_node_host=dict(required=False, type="str"),
- vpn_dst_node_seq=dict(required=False, type="str"),
- vpn_dst_node_subnet=dict(required=False, type="str"),
- vpn_src_node=dict(required=False, type="list"),
- vpn_src_node_host=dict(required=False, type="str"),
- vpn_src_node_seq=dict(required=False, type="str"),
- vpn_src_node_subnet=dict(required=False, type="str"),
-
- )
-
- module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
- # MODULE PARAMGRAM
- paramgram = {
- "mode": module.params["mode"],
- "adom": module.params["adom"],
- "package_name": module.params["package_name"],
- "wsso": module.params["wsso"],
- "webfilter-profile": module.params["webfilter_profile"],
- "webcache-https": module.params["webcache_https"],
- "webcache": module.params["webcache"],
- "wccp": module.params["wccp"],
- "wanopt-profile": module.params["wanopt_profile"],
- "wanopt-peer": module.params["wanopt_peer"],
- "wanopt-passive-opt": module.params["wanopt_passive_opt"],
- "wanopt-detection": module.params["wanopt_detection"],
- "wanopt": module.params["wanopt"],
- "waf-profile": module.params["waf_profile"],
- "vpntunnel": module.params["vpntunnel"],
- "voip-profile": module.params["voip_profile"],
- "vlan-filter": module.params["vlan_filter"],
- "vlan-cos-rev": module.params["vlan_cos_rev"],
- "vlan-cos-fwd": module.params["vlan_cos_fwd"],
- "utm-status": module.params["utm_status"],
- "users": module.params["users"],
- "url-category": module.params["url_category"],
- "traffic-shaper-reverse": module.params["traffic_shaper_reverse"],
- "traffic-shaper": module.params["traffic_shaper"],
- "timeout-send-rst": module.params["timeout_send_rst"],
- "tcp-session-without-syn": module.params["tcp_session_without_syn"],
- "tcp-mss-sender": module.params["tcp_mss_sender"],
- "tcp-mss-receiver": module.params["tcp_mss_receiver"],
- "status": module.params["status"],
- "ssl-ssh-profile": module.params["ssl_ssh_profile"],
- "ssl-mirror-intf": module.params["ssl_mirror_intf"],
- "ssl-mirror": module.params["ssl_mirror"],
- "ssh-filter-profile": module.params["ssh_filter_profile"],
- "srcintf": module.params["srcintf"],
- "srcaddr-negate": module.params["srcaddr_negate"],
- "srcaddr": module.params["srcaddr"],
- "spamfilter-profile": module.params["spamfilter_profile"],
- "session-ttl": module.params["session_ttl"],
- "service-negate": module.params["service_negate"],
- "service": module.params["service"],
- "send-deny-packet": module.params["send_deny_packet"],
- "schedule-timeout": module.params["schedule_timeout"],
- "schedule": module.params["schedule"],
- "scan-botnet-connections": module.params["scan_botnet_connections"],
- "rtp-nat": module.params["rtp_nat"],
- "rtp-addr": module.params["rtp_addr"],
- "rsso": module.params["rsso"],
- "replacemsg-override-group": module.params["replacemsg_override_group"],
- "redirect-url": module.params["redirect_url"],
- "radius-mac-auth-bypass": module.params["radius_mac_auth_bypass"],
- "profile-type": module.params["profile_type"],
- "profile-protocol-options": module.params["profile_protocol_options"],
- "profile-group": module.params["profile_group"],
- "poolname": module.params["poolname"],
- "policyid": module.params["policyid"],
- "permit-stun-host": module.params["permit_stun_host"],
- "permit-any-host": module.params["permit_any_host"],
- "per-ip-shaper": module.params["per_ip_shaper"],
- "outbound": module.params["outbound"],
- "ntlm-guest": module.params["ntlm_guest"],
- "ntlm-enabled-browsers": module.params["ntlm_enabled_browsers"],
- "ntlm": module.params["ntlm"],
- "np-acceleration": module.params["np_acceleration"],
- "natoutbound": module.params["natoutbound"],
- "natip": module.params["natip"],
- "natinbound": module.params["natinbound"],
- "nat": module.params["nat"],
- "name": module.params["name"],
- "mms-profile": module.params["mms_profile"],
- "match-vip": module.params["match_vip"],
- "logtraffic-start": module.params["logtraffic_start"],
- "logtraffic": module.params["logtraffic"],
- "learning-mode": module.params["learning_mode"],
- "label": module.params["label"],
- "ips-sensor": module.params["ips_sensor"],
- "ippool": module.params["ippool"],
- "internet-service-src-negate": module.params["internet_service_src_negate"],
- "internet-service-src-id": module.params["internet_service_src_id"],
- "internet-service-src-custom": module.params["internet_service_src_custom"],
- "internet-service-src": module.params["internet_service_src"],
- "internet-service-negate": module.params["internet_service_negate"],
- "internet-service-id": module.params["internet_service_id"],
- "internet-service-custom": module.params["internet_service_custom"],
- "internet-service": module.params["internet_service"],
- "inbound": module.params["inbound"],
- "identity-based-route": module.params["identity_based_route"],
- "icap-profile": module.params["icap_profile"],
- "gtp-profile": module.params["gtp_profile"],
- "groups": module.params["groups"],
- "global-label": module.params["global_label"],
- "fsso-agent-for-ntlm": module.params["fsso_agent_for_ntlm"],
- "fsso": module.params["fsso"],
- "fixedport": module.params["fixedport"],
- "firewall-session-dirty": module.params["firewall_session_dirty"],
- "dstintf": module.params["dstintf"],
- "dstaddr-negate": module.params["dstaddr_negate"],
- "dstaddr": module.params["dstaddr"],
- "dsri": module.params["dsri"],
- "dscp-value": module.params["dscp_value"],
- "dscp-negate": module.params["dscp_negate"],
- "dscp-match": module.params["dscp_match"],
- "dnsfilter-profile": module.params["dnsfilter_profile"],
- "dlp-sensor": module.params["dlp_sensor"],
- "disclaimer": module.params["disclaimer"],
- "diffservcode-rev": module.params["diffservcode_rev"],
- "diffservcode-forward": module.params["diffservcode_forward"],
- "diffserv-reverse": module.params["diffserv_reverse"],
- "diffserv-forward": module.params["diffserv_forward"],
- "devices": module.params["devices"],
- "delay-tcp-npu-session": module.params["delay_tcp_npu_session"],
- "custom-log-fields": module.params["custom_log_fields"],
- "comments": module.params["comments"],
- "capture-packet": module.params["capture_packet"],
- "captive-portal-exempt": module.params["captive_portal_exempt"],
- "block-notification": module.params["block_notification"],
- "av-profile": module.params["av_profile"],
- "auto-asic-offload": module.params["auto_asic_offload"],
- "auth-redirect-addr": module.params["auth_redirect_addr"],
- "auth-path": module.params["auth_path"],
- "auth-cert": module.params["auth_cert"],
- "application-list": module.params["application_list"],
- "application": module.params["application"],
- "app-group": module.params["app_group"],
- "app-category": module.params["app_category"],
- "action": module.params["action"],
- "vpn_dst_node": {
- "host": module.params["vpn_dst_node_host"],
- "seq": module.params["vpn_dst_node_seq"],
- "subnet": module.params["vpn_dst_node_subnet"],
- },
- "vpn_src_node": {
- "host": module.params["vpn_src_node_host"],
- "seq": module.params["vpn_src_node_seq"],
- "subnet": module.params["vpn_src_node_subnet"],
- }
- }
- module.paramgram = paramgram
- fmgr = None
- if module._socket_path:
- connection = Connection(module._socket_path)
- fmgr = FortiManagerHandler(connection, module)
- fmgr.tools = FMGRCommon()
- else:
- module.fail_json(**FAIL_SOCKET_MSG)
-
- list_overrides = ['vpn_dst_node', 'vpn_src_node']
- paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
- paramgram=paramgram, module=module)
-
- # BEGIN MODULE-SPECIFIC LOGIC -- THINGS NEED TO HAPPEN DEPENDING ON THE ENDPOINT AND OPERATION
- results = DEFAULT_RESULT_OBJ
- try:
- if paramgram["mode"] == "delete":
- # WE NEED TO GET THE POLICY ID FROM THE NAME OF THE POLICY TO DELETE IT
- url = '/pm/config/adom/{adom}/pkg/{pkg}/firewall' \
- '/policy/'.format(adom=paramgram["adom"],
- pkg=paramgram["package_name"])
- datagram = {
- "filter": ["name", "==", paramgram["name"]]
- }
- response = fmgr.process_request(url, datagram, FMGRMethods.GET)
- try:
- if response[1][0]["policyid"]:
- policy_id = response[1][0]["policyid"]
- paramgram["policyid"] = policy_id
- except BaseException:
- fmgr.return_response(module=module, results=response, good_codes=[0, ], stop_on_success=True,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram),
- msg="Couldn't find policy ID number for policy name specified.")
- except Exception as err:
- raise FMGBaseException(err)
-
- try:
- results = fmgr_firewall_policy_modify(fmgr, paramgram)
- if module.params["fail_on_missing_dependency"] == "disable":
- fmgr.govern_response(module=module, results=results, good_codes=[0, -9998],
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
- if module.params["fail_on_missing_dependency"] == "enable" and results[0] == -10131:
- fmgr.govern_response(module=module, results=results, good_codes=[0, ], failed=True, skipped=False,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
- except Exception as err:
- raise FMGBaseException(err)
-
- return module.exit_json(**results[1])
-
-
-if __name__ == "__main__":
- main()
diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_fwpol_package.py b/ansible_collections/community/fortios/plugins/modules/fmgr_fwpol_package.py
deleted file mode 100644
index 7b65393fd..000000000
--- a/ansible_collections/community/fortios/plugins/modules/fmgr_fwpol_package.py
+++ /dev/null
@@ -1,479 +0,0 @@
-#!/usr/bin/python
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-DOCUMENTATION = '''
----
-module: fmgr_fwpol_package
-notes:
- - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
-author:
- - Luke Weighall (@lweighall)
- - Andrew Welsh (@Ghilli3)
- - Jim Huber (@p4r4n0y1ng)
-short_description: Manages FortiManager Firewall Policies Packages.
-description:
- - Manages FortiManager Firewall Policies Packages. Policy Packages contain one or more Firewall Policies/Rules and
- are distritbuted via FortiManager to Fortigates.
- - This module controls the creation/edit/delete/assign of these packages.
-
-options:
- adom:
- description:
- - The ADOM the configuration should belong to.
- required: false
- default: root
-
- mode:
- description:
- - Sets one of three modes for managing the object.
- choices: ['add', 'set', 'delete']
- default: add
-
- name:
- description:
- - Name of the FortiManager package or folder.
- required: True
-
- object_type:
- description:
- - Are we managing packages or folders, or installing packages?
- required: True
- choices: ['pkg','folder','install']
-
- package_folder:
- description:
- - Name of the folder you want to put the package into.
- required: false
-
- central_nat:
- description:
- - Central NAT setting.
- required: false
- choices: ['enable', 'disable']
- default: disable
-
- fwpolicy_implicit_log:
- description:
- - Implicit Log setting for all IPv4 policies in package.
- required: false
- choices: ['enable', 'disable']
- default: disable
-
- fwpolicy6_implicit_log:
- description:
- - Implicit Log setting for all IPv6 policies in package.
- required: false
- choices: ['enable', 'disable']
- default: disable
-
- inspection_mode:
- description:
- - Inspection mode setting for the policies flow or proxy.
- required: false
- choices: ['flow', 'proxy']
- default: flow
-
- ngfw_mode:
- description:
- - NGFW mode setting for the policies flow or proxy.
- required: false
- choices: ['profile-based', 'policy-based']
- default: profile-based
-
- ssl_ssh_profile:
- description:
- - if policy-based ngfw-mode, refer to firewall ssl-ssh-profile.
- required: false
-
- scope_members:
- description:
- - The devices or scope that you want to assign this policy package to.
- required: false
-
- scope_members_vdom:
- description:
- - The members VDOM you want to assign the package to.
- required: false
- default: root
-
- parent_folder:
- description:
- - The parent folder name you want to add this object under.
- required: false
-
-'''
-
-
-EXAMPLES = '''
-- name: CREATE BASIC POLICY PACKAGE
- community.fortios.fmgr_fwpol_package:
- adom: "ansible"
- mode: "add"
- name: "testPackage"
- object_type: "pkg"
-
-- name: ADD PACKAGE WITH TARGETS
- community.fortios.fmgr_fwpol_package:
- mode: "add"
- adom: "ansible"
- name: "ansibleTestPackage1"
- object_type: "pkg"
- inspection_mode: "flow"
- ngfw_mode: "profile-based"
- scope_members: "seattle-fgt02, seattle-fgt03"
-
-- name: ADD FOLDER
- community.fortios.fmgr_fwpol_package:
- mode: "add"
- adom: "ansible"
- name: "ansibleTestFolder1"
- object_type: "folder"
-
-- name: ADD PACKAGE INTO PARENT FOLDER
- community.fortios.fmgr_fwpol_package:
- mode: "set"
- adom: "ansible"
- name: "ansibleTestPackage2"
- object_type: "pkg"
- parent_folder: "ansibleTestFolder1"
-
-- name: ADD FOLDER INTO PARENT FOLDER
- community.fortios.fmgr_fwpol_package:
- mode: "set"
- adom: "ansible"
- name: "ansibleTestFolder2"
- object_type: "folder"
- parent_folder: "ansibleTestFolder1"
-
-- name: INSTALL PACKAGE
- community.fortios.fmgr_fwpol_package:
- mode: "set"
- adom: "ansible"
- name: "ansibleTestPackage1"
- object_type: "install"
- scope_members: "seattle-fgt03, seattle-fgt02"
-
-- name: REMOVE PACKAGE
- community.fortios.fmgr_fwpol_package:
- mode: "delete"
- adom: "ansible"
- name: "ansibleTestPackage1"
- object_type: "pkg"
-
-- name: REMOVE NESTED PACKAGE
- community.fortios.fmgr_fwpol_package:
- mode: "delete"
- adom: "ansible"
- name: "ansibleTestPackage2"
- object_type: "pkg"
- parent_folder: "ansibleTestFolder1"
-
-- name: REMOVE NESTED FOLDER
- community.fortios.fmgr_fwpol_package:
- mode: "delete"
- adom: "ansible"
- name: "ansibleTestFolder2"
- object_type: "folder"
- parent_folder: "ansibleTestFolder1"
-
-- name: REMOVE FOLDER
- community.fortios.fmgr_fwpol_package:
- mode: "delete"
- adom: "ansible"
- name: "ansibleTestFolder1"
- object_type: "folder"
-'''
-RETURN = """
-api_result:
- description: full API response, includes status code and message
- returned: always
- type: str
-"""
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.connection import Connection
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRMethods
-
-
-def fmgr_fwpol_package(fmgr, paramgram):
- """
- This function will create FMGR Firewall Policy Packages, or delete them. It is also capable of assigning packages.
- This function DOES NOT install the package. See the function fmgr_fwpol_package_install()
-
- :param fmgr: The fmgr object instance from fmgr_utils.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
-
- :return: The response from the FortiManager
- :rtype: dict
- """
- if paramgram["mode"] in ['set', 'add']:
- url = '/pm/pkg/adom/{adom}'.format(adom=paramgram["adom"])
- members_list = []
-
- # CHECK FOR SCOPE MEMBERS AND CREATE THAT DICT
- if paramgram["scope_members"] is not None:
- members = FMGRCommon.split_comma_strings_into_lists(paramgram["scope_members"])
- for member in members:
- scope_dict = {
- "name": member,
- "vdom": paramgram["scope_members_vdom"],
- }
- members_list.append(scope_dict)
-
- # IF PARENT FOLDER IS NOT DEFINED
- if paramgram["parent_folder"] is None:
- datagram = {
- "type": paramgram["object_type"],
- "name": paramgram["name"],
- "scope member": members_list,
- "package settings": {
- "central-nat": paramgram["central-nat"],
- "fwpolicy-implicit-log": paramgram["fwpolicy-implicit-log"],
- "fwpolicy6-implicit-log": paramgram["fwpolicy6-implicit-log"],
- "inspection-mode": paramgram["inspection-mode"],
- "ngfw-mode": paramgram["ngfw-mode"],
- }
- }
-
- if paramgram["ngfw-mode"] == "policy-based" and paramgram["ssl-ssh-profile"] is not None:
- datagram["package settings"]["ssl-ssh-profile"] = paramgram["ssl-ssh-profile"]
-
- # IF PARENT FOLDER IS DEFINED
- if paramgram["parent_folder"] is not None:
- datagram = {
- "type": "folder",
- "name": paramgram["parent_folder"],
- "subobj": [{
- "name": paramgram["name"],
- "scope member": members_list,
- "type": "pkg",
- "package settings": {
- "central-nat": paramgram["central-nat"],
- "fwpolicy-implicit-log": paramgram["fwpolicy-implicit-log"],
- "fwpolicy6-implicit-log": paramgram["fwpolicy6-implicit-log"],
- "inspection-mode": paramgram["inspection-mode"],
- "ngfw-mode": paramgram["ngfw-mode"],
- }
- }]
- }
-
- # NORMAL DELETE NO PARENT
- if paramgram["mode"] == "delete" and paramgram["parent_folder"] is None:
- datagram = {
- "name": paramgram["name"]
- }
- # SET DELETE URL
- url = '/pm/pkg/adom/{adom}/{name}'.format(adom=paramgram["adom"], name=paramgram["name"])
-
- # DELETE WITH PARENT
- if paramgram["mode"] == "delete" and paramgram["parent_folder"] is not None:
- datagram = {
- "name": paramgram["name"]
- }
- # SET DELETE URL
- url = '/pm/pkg/adom/{adom}/{parent_folder}/{name}'.format(adom=paramgram["adom"],
- name=paramgram["name"],
- parent_folder=paramgram["parent_folder"])
-
- response = fmgr.process_request(url, datagram, paramgram["mode"])
- return response
-
-
-def fmgr_fwpol_package_folder(fmgr, paramgram):
- """
- This function will create folders for firewall packages. It can create down to two levels deep.
- We haven't yet tested for any more layers below two levels.
- parent_folders for multiple levels may need to defined as "level1/level2/level3" for the URL parameters and such.
-
- :param fmgr: The fmgr object instance from fmgr_utils.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
-
- :return: The response from the FortiManager
- :rtype: dict
- """
- if paramgram["mode"] in ['set', 'add']:
- url = '/pm/pkg/adom/{adom}'.format(adom=paramgram["adom"])
- # IF PARENT FOLDER IS NOT DEFINED
- if paramgram["parent_folder"] is None:
- datagram = {
- "type": paramgram["object_type"],
- "name": paramgram["name"],
- }
-
- # IF PARENT FOLDER IS DEFINED
- if paramgram["parent_folder"] is not None:
- datagram = {
- "type": paramgram["object_type"],
- "name": paramgram["parent_folder"],
- "subobj": [{
- "name": paramgram["name"],
- "type": paramgram["object_type"],
-
- }]
- }
- # NORMAL DELETE NO PARENT
- if paramgram["mode"] == "delete" and paramgram["parent_folder"] is None:
- datagram = {
- "name": paramgram["name"]
- }
- # SET DELETE URL
- url = '/pm/pkg/adom/{adom}/{name}'.format(adom=paramgram["adom"], name=paramgram["name"])
-
- # DELETE WITH PARENT
- if paramgram["mode"] == "delete" and paramgram["parent_folder"] is not None:
- datagram = {
- "name": paramgram["name"]
- }
- # SET DELETE URL
- url = '/pm/pkg/adom/{adom}/{parent_folder}/{name}'.format(adom=paramgram["adom"],
- name=paramgram["name"],
- parent_folder=paramgram["parent_folder"])
-
- response = fmgr.process_request(url, datagram, paramgram["mode"])
- return response
-
-
-def fmgr_fwpol_package_install(fmgr, paramgram):
- """
- This method/function installs FMGR FW Policy Packages to the scope members defined in the playbook.
-
- :param fmgr: The fmgr object instance from fmgr_utils.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
-
- :return: The response from the FortiManager
- :rtype: dict
- """
- # INIT BLANK MEMBERS LIST
- members_list = []
- # USE THE PARSE CSV FUNCTION TO GET A LIST FORMAT OF THE MEMBERS
- members = FMGRCommon.split_comma_strings_into_lists(paramgram["scope_members"])
- # USE THAT LIST TO BUILD THE DICTIONARIES NEEDED, AND ADD TO THE BLANK MEMBERS LIST
- for member in members:
- scope_dict = {
- "name": member,
- "vdom": paramgram["scope_members_vdom"],
- }
- members_list.append(scope_dict)
- # THEN FOR THE DATAGRAM, USING THE MEMBERS LIST CREATED ABOVE
- datagram = {
- "adom": paramgram["adom"],
- "pkg": paramgram["name"],
- "scope": members_list
- }
- # EXECUTE THE INSTALL REQUEST
- url = '/securityconsole/install/package'
- response = fmgr.process_request(url, datagram, FMGRMethods.EXEC)
- return response
-
-
-def main():
- argument_spec = dict(
- adom=dict(required=False, type="str", default="root"),
- mode=dict(choices=["add", "set", "delete"], type="str", default="add"),
-
- name=dict(required=False, type="str"),
- object_type=dict(required=True, type="str", choices=['pkg', 'folder', 'install']),
- package_folder=dict(required=False, type="str"),
- central_nat=dict(required=False, type="str", default="disable", choices=['enable', 'disable']),
- fwpolicy_implicit_log=dict(required=False, type="str", default="disable", choices=['enable', 'disable']),
- fwpolicy6_implicit_log=dict(required=False, type="str", default="disable", choices=['enable', 'disable']),
- inspection_mode=dict(required=False, type="str", default="flow", choices=['flow', 'proxy']),
- ngfw_mode=dict(required=False, type="str", default="profile-based", choices=['profile-based', 'policy-based']),
- ssl_ssh_profile=dict(required=False, type="str"),
- scope_members=dict(required=False, type="str"),
- scope_members_vdom=dict(required=False, type="str", default="root"),
- parent_folder=dict(required=False, type="str"),
-
- )
-
- module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
- # MODULE DATAGRAM
- paramgram = {
- "adom": module.params["adom"],
- "name": module.params["name"],
- "mode": module.params["mode"],
- "object_type": module.params["object_type"],
- "package-folder": module.params["package_folder"],
- "central-nat": module.params["central_nat"],
- "fwpolicy-implicit-log": module.params["fwpolicy_implicit_log"],
- "fwpolicy6-implicit-log": module.params["fwpolicy6_implicit_log"],
- "inspection-mode": module.params["inspection_mode"],
- "ngfw-mode": module.params["ngfw_mode"],
- "ssl-ssh-profile": module.params["ssl_ssh_profile"],
- "scope_members": module.params["scope_members"],
- "scope_members_vdom": module.params["scope_members_vdom"],
- "parent_folder": module.params["parent_folder"],
- }
- module.paramgram = paramgram
- fmgr = None
- if module._socket_path:
- connection = Connection(module._socket_path)
- fmgr = FortiManagerHandler(connection, module)
- fmgr.tools = FMGRCommon()
- else:
- module.fail_json(**FAIL_SOCKET_MSG)
-
- # BEGIN MODULE-SPECIFIC LOGIC -- THINGS NEED TO HAPPEN DEPENDING ON THE ENDPOINT AND OPERATION
- results = DEFAULT_RESULT_OBJ
-
- try:
- if paramgram["object_type"] == "pkg":
- results = fmgr_fwpol_package(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
- except Exception as err:
- raise FMGBaseException(err)
-
- try:
- # IF THE object_type IS FOLDER LETS RUN THAT METHOD
- if paramgram["object_type"] == "folder":
- results = fmgr_fwpol_package_folder(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
- except Exception as err:
- raise FMGBaseException(err)
-
- try:
- # IF THE object_type IS INSTALL AND NEEDED PARAMETERS ARE DEFINED INSTALL THE PACKAGE
- if paramgram["scope_members"] is not None and paramgram["name"] is not None and\
- paramgram["object_type"] == "install":
- results = fmgr_fwpol_package_install(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
- except Exception as err:
- raise FMGBaseException(err)
-
- return module.exit_json(**results[1])
-
-
-if __name__ == "__main__":
- main()
diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_ha.py b/ansible_collections/community/fortios/plugins/modules/fmgr_ha.py
deleted file mode 100644
index e24f11463..000000000
--- a/ansible_collections/community/fortios/plugins/modules/fmgr_ha.py
+++ /dev/null
@@ -1,349 +0,0 @@
-#!/usr/bin/python
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-DOCUMENTATION = '''
----
-module: fmgr_ha
-notes:
- - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
-author:
- - Luke Weighall (@lweighall)
- - Andrew Welsh (@Ghilli3)
- - Jim Huber (@p4r4n0y1ng)
-short_description: Manages the High-Availability State of FortiManager Clusters and Nodes.
-description: Change HA state or settings of FortiManager nodes (Standalone/Master/Slave).
-
-options:
- fmgr_ha_mode:
- description:
- - Sets the role of the FortiManager host for HA.
- required: false
- choices: ["standalone", "master", "slave"]
-
- fmgr_ha_peer_ipv4:
- description:
- - Sets the IPv4 address of a HA peer.
- required: false
-
- fmgr_ha_peer_ipv6:
- description:
- - Sets the IPv6 address of a HA peer.
- required: false
-
- fmgr_ha_peer_sn:
- description:
- - Sets the HA Peer Serial Number.
- required: false
-
- fmgr_ha_peer_status:
- description:
- - Sets the peer status to enable or disable.
- required: false
- choices: ["enable", "disable"]
-
- fmgr_ha_cluster_pw:
- description:
- - Sets the password for the HA cluster. Only required once. System remembers between HA mode switches.
- required: false
-
- fmgr_ha_cluster_id:
- description:
- - Sets the ID number of the HA cluster. Defaults to 1.
- required: false
- default: 1
-
- fmgr_ha_hb_threshold:
- description:
- - Sets heartbeat lost threshold (1-255).
- required: false
- default: 3
-
- fmgr_ha_hb_interval:
- description:
- - Sets the heartbeat interval (1-255).
- required: false
- default: 5
-
- fmgr_ha_file_quota:
- description:
- - Sets the File quota in MB (2048-20480).
- required: false
- default: 4096
-'''
-
-
-EXAMPLES = '''
-- name: SET FORTIMANAGER HA NODE TO MASTER
- community.fortios.fmgr_ha:
- fmgr_ha_mode: "master"
- fmgr_ha_cluster_pw: "fortinet"
- fmgr_ha_cluster_id: "1"
-
-- name: SET FORTIMANAGER HA NODE TO SLAVE
- community.fortios.fmgr_ha:
- fmgr_ha_mode: "slave"
- fmgr_ha_cluster_pw: "fortinet"
- fmgr_ha_cluster_id: "1"
-
-- name: SET FORTIMANAGER HA NODE TO STANDALONE
- community.fortios.fmgr_ha:
- fmgr_ha_mode: "standalone"
-
-- name: ADD FORTIMANAGER HA PEER
- community.fortios.fmgr_ha:
- fmgr_ha_peer_ipv4: "192.168.1.254"
- fmgr_ha_peer_sn: "FMG-VM1234567890"
- fmgr_ha_peer_status: "enable"
-
-- name: CREATE CLUSTER ON MASTER
- community.fortios.fmgr_ha:
- fmgr_ha_mode: "master"
- fmgr_ha_cluster_pw: "fortinet"
- fmgr_ha_cluster_id: "1"
- fmgr_ha_hb_threshold: "10"
- fmgr_ha_hb_interval: "15"
- fmgr_ha_file_quota: "2048"
-'''
-RETURN = """
-api_result:
- description: full API response, includes status code and message
- returned: always
- type: str
-"""
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.connection import Connection
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRMethods
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG
-
-
-def fmgr_set_ha_mode(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
- # INIT A BASIC OBJECTS
- response = DEFAULT_RESULT_OBJ
- url = ""
- datagram = {}
-
- if paramgram["fmgr_ha_cluster_pw"] is not None and str(paramgram["fmgr_ha_mode"].lower()) != "standalone":
- datagram = {
- "mode": paramgram["fmgr_ha_mode"],
- "file-quota": paramgram["fmgr_ha_file_quota"],
- "hb-interval": paramgram["fmgr_ha_hb_interval"],
- "hb-lost-threshold": paramgram["fmgr_ha_hb_threshold"],
- "password": paramgram["fmgr_ha_cluster_pw"],
- "clusterid": paramgram["fmgr_ha_cluster_id"]
- }
- elif str(paramgram["fmgr_ha_mode"].lower()) == "standalone":
- datagram = {
- "mode": paramgram["fmgr_ha_mode"],
- "file-quota": paramgram["fmgr_ha_file_quota"],
- "hb-interval": paramgram["fmgr_ha_hb_interval"],
- "hb-lost-threshold": paramgram["fmgr_ha_hb_threshold"],
- "clusterid": paramgram["fmgr_ha_cluster_id"]
- }
-
- url = '/cli/global/system/ha'
- response = fmgr.process_request(url, datagram, FMGRMethods.SET)
- return response
-
-
-def fmgr_get_ha_peer_list(fmgr):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
- # INIT A BASIC OBJECTS
- response = DEFAULT_RESULT_OBJ
-
- datagram = {}
- paramgram = {}
-
- url = '/cli/global/system/ha/peer/'
- response = fmgr.process_request(url, datagram, FMGRMethods.GET)
- return response
-
-
-def fmgr_set_ha_peer(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
-
- datagram = {
- "ip": paramgram["fmgr_ha_peer_ipv4"],
- "ip6": paramgram["fmgr_ha_peer_ipv6"],
- "serial-number": paramgram["fmgr_ha_peer_sn"],
- "status": paramgram["fmgr_ha_peer_status"],
- "id": paramgram["peer_id"]
- }
-
- url = '/cli/global/system/ha/peer/'
- response = fmgr.process_request(url, datagram, FMGRMethods.SET)
- return response
-
-
-def main():
- argument_spec = dict(
- fmgr_ha_mode=dict(required=False, type="str", choices=["standalone", "master", "slave"]),
- fmgr_ha_cluster_pw=dict(required=False, type="str", no_log=True),
- fmgr_ha_peer_status=dict(required=False, type="str", choices=["enable", "disable"]),
- fmgr_ha_peer_sn=dict(required=False, type="str"),
- fmgr_ha_peer_ipv4=dict(required=False, type="str"),
- fmgr_ha_peer_ipv6=dict(required=False, type="str"),
- fmgr_ha_hb_threshold=dict(required=False, type="int", default=3),
- fmgr_ha_hb_interval=dict(required=False, type="int", default=5),
- fmgr_ha_file_quota=dict(required=False, type="int", default=4096),
- fmgr_ha_cluster_id=dict(required=False, type="int", default=1)
- )
-
- required_if = [
- ['fmgr_ha_peer_ipv4', 'present', ['fmgr_ha_peer_sn', 'fmgr_ha_peer_status']],
- ['fmgr_ha_peer_ipv6', 'present', ['fmgr_ha_peer_sn', 'fmgr_ha_peer_status']],
- ['fmgr_ha_mode', 'master', ['fmgr_ha_cluster_pw', 'fmgr_ha_cluster_id']],
- ['fmgr_ha_mode', 'slave', ['fmgr_ha_cluster_pw', 'fmgr_ha_cluster_id']],
- ]
-
- module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, required_if=required_if)
- paramgram = {
- "fmgr_ha_mode": module.params["fmgr_ha_mode"],
- "fmgr_ha_cluster_pw": module.params["fmgr_ha_cluster_pw"],
- "fmgr_ha_peer_status": module.params["fmgr_ha_peer_status"],
- "fmgr_ha_peer_sn": module.params["fmgr_ha_peer_sn"],
- "fmgr_ha_peer_ipv4": module.params["fmgr_ha_peer_ipv4"],
- "fmgr_ha_peer_ipv6": module.params["fmgr_ha_peer_ipv6"],
- "fmgr_ha_hb_threshold": module.params["fmgr_ha_hb_threshold"],
- "fmgr_ha_hb_interval": module.params["fmgr_ha_hb_interval"],
- "fmgr_ha_file_quota": module.params["fmgr_ha_file_quota"],
- "fmgr_ha_cluster_id": module.params["fmgr_ha_cluster_id"],
- }
- module.paramgram = paramgram
- fmgr = None
- if module._socket_path:
- connection = Connection(module._socket_path)
- fmgr = FortiManagerHandler(connection, module)
- fmgr.tools = FMGRCommon()
- else:
- module.fail_json(**FAIL_SOCKET_MSG)
-
- # INIT FLAGS AND COUNTERS
- get_ha_peers = 0
- results = DEFAULT_RESULT_OBJ
- try:
- if any(v is not None for v in (paramgram["fmgr_ha_peer_sn"], paramgram["fmgr_ha_peer_ipv4"],
- paramgram["fmgr_ha_peer_ipv6"], paramgram["fmgr_ha_peer_status"])):
- get_ha_peers = 1
- except Exception as err:
- raise FMGBaseException(err)
- try:
- # IF HA MODE IS NOT NULL, SWITCH THAT
- if paramgram["fmgr_ha_mode"] is not None:
- if (str.lower(paramgram["fmgr_ha_mode"]) != "standalone" and paramgram["fmgr_ha_cluster_pw"] is not None)\
- or str.lower(paramgram["fmgr_ha_mode"]) == "standalone":
- results = fmgr_set_ha_mode(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results, stop_on_success=False,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
-
- elif str.lower(paramgram["fmgr_ha_mode"]) != "standalone" and\
- paramgram["fmgr_ha_mode"] is not None and\
- paramgram["fmgr_ha_cluster_pw"] is None:
- module.exit_json(msg="If setting HA Mode of MASTER or SLAVE, you must specify a cluster password")
-
- except Exception as err:
- raise FMGBaseException(err)
- # IF GET_HA_PEERS IS ENABLED, LETS PROCESS THE PEERS
- try:
- if get_ha_peers == 1:
- # GET THE CURRENT LIST OF PEERS FROM THE NODE
- peers = fmgr_get_ha_peer_list(fmgr)
- # GET LENGTH OF RETURNED PEERS LIST AND ADD ONE FOR THE NEXT ID
- paramgram["next_peer_id"] = len(peers[1]) + 1
- # SET THE ACTUAL NUMBER OF PEERS
- num_of_peers = len(peers[1])
- # SET THE PEER ID FOR DISABLE METHOD
- paramgram["peer_id"] = len(peers) - 1
- # SET THE PEER LOOPCOUNT TO 1 TO START THE LOOP
- peer_loopcount = 1
-
- # LOOP THROUGH PEERS TO FIND THE SERIAL NUMBER MATCH TO GET THE RIGHT PEER ID
- # IDEA BEING WE DON'T WANT TO SUBMIT A BAD peer_id THAT DOESN'T JIVE WITH CURRENT DB ON FMG
- # SO LETS SEARCH FOR IT, AND IF WE FIND IT, WE WILL CHANGE THE PEER ID VARIABLES TO MATCH
- # IF NOT FOUND, LIFE GOES ON AND WE ASSUME THAT WE'RE ADDING A PEER
- # AT WHICH POINT THE next_peer_id VARIABLE WILL HAVE THE RIGHT PRIMARY KEY
-
- if paramgram["fmgr_ha_peer_sn"] is not None:
- while peer_loopcount <= num_of_peers:
- # GET THE SERIAL NUMBER FOR CURRENT PEER IN LOOP TO COMPARE TO SN IN PLAYBOOK
- try:
- sn_compare = peers[1][peer_loopcount - 1]["serial-number"]
- # IF THE SN IN THE PEERS MATCHES THE PLAYBOOK SN, SET THE IDS
- if sn_compare == paramgram["fmgr_ha_peer_sn"]:
- paramgram["peer_id"] = peer_loopcount
- paramgram["next_peer_id"] = paramgram["peer_id"]
- except Exception as err:
- raise FMGBaseException(err)
- # ADVANCE THE LOOP AND REPEAT UNTIL DONE
- peer_loopcount += 1
-
- # IF THE PEER STATUS ISN'T IN THE PLAYBOOK, ASSUME ITS ENABLE
- if paramgram["fmgr_ha_peer_status"] is None:
- paramgram["fmgr_ha_peer_status"] = "enable"
-
- # IF THE PEER STATUS IS ENABLE, USE THE next_peer_id IN THE API CALL FOR THE ID
- if paramgram["fmgr_ha_peer_status"] == "enable":
- results = fmgr_set_ha_peer(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results, stop_on_success=True,
- ansible_facts=fmgr.construct_ansible_facts(results,
- module.params, paramgram))
-
- # IF THE PEER STATUS IS DISABLE, WE HAVE TO HANDLE THAT A BIT DIFFERENTLY
- # JUST USING TWO DIFFERENT peer_id 's HERE
- if paramgram["fmgr_ha_peer_status"] == "disable":
- results = fmgr_set_ha_peer(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results, stop_on_success=True,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
-
- except Exception as err:
- raise FMGBaseException(err)
-
- return module.exit_json(**results[1])
-
-
-if __name__ == "__main__":
- main()
diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_provisioning.py b/ansible_collections/community/fortios/plugins/modules/fmgr_provisioning.py
deleted file mode 100644
index da499cbe4..000000000
--- a/ansible_collections/community/fortios/plugins/modules/fmgr_provisioning.py
+++ /dev/null
@@ -1,360 +0,0 @@
-#!/usr/bin/python
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-
-from __future__ import absolute_import, division, print_function
-
-__metaclass__ = type
-
-DOCUMENTATION = '''
----
-module: fmgr_provisioning
-author: Andrew Welsh (@Ghilli3)
-short_description: Provision devices via FortiMananger
-description:
- - Add model devices on the FortiManager using jsonrpc API and have them pre-configured,
- so when central management is configured, the configuration is pushed down to the
- registering devices
-
-options:
- adom:
- description:
- - The administrative domain (admon) the configuration belongs to
- required: true
- vdom:
- description:
- - The virtual domain (vdom) the configuration belongs to
- host:
- description:
- - The FortiManager's Address.
- required: true
- username:
- description:
- - The username to log into the FortiManager
- required: true
- password:
- description:
- - The password associated with the username account.
- required: false
-
- policy_package:
- description:
- - The name of the policy package to be assigned to the device.
- required: True
- name:
- description:
- - The name of the device to be provisioned.
- required: True
- group:
- description:
- - The name of the device group the provisioned device can belong to.
- required: False
- serial:
- description:
- - The serial number of the device that will be provisioned.
- required: True
- platform:
- description:
- - The platform of the device, such as model number or VM.
- required: True
- description:
- description:
- - Description of the device to be provisioned.
- required: False
- os_version:
- description:
- - The Fortinet OS version to be used for the device, such as 5.0 or 6.0.
- required: True
- minor_release:
- description:
- - The minor release number such as 6.X.1, as X being the minor release.
- required: False
- patch_release:
- description:
- - The patch release number such as 6.0.X, as X being the patch release.
- required: False
- os_type:
- description:
- - The Fortinet OS type to be pushed to the device, such as 'FOS' for FortiOS.
- required: True
-'''
-
-EXAMPLES = '''
-- name: Create FGT1 Model Device
- community.fortios.fmgr_provisioning:
- host: "{{ inventory_hostname }}"
- username: "{{ username }}"
- password: "{{ password }}"
- adom: "root"
- vdom: "root"
- policy_package: "default"
- name: "FGT1"
- group: "Ansible"
- serial: "FGVM000000117994"
- platform: "FortiGate-VM64"
- description: "Provisioned by Ansible"
- os_version: '6.0'
- minor_release: 0
- patch_release: 0
- os_type: 'fos'
-
-
-- name: Create FGT2 Model Device
- community.fortios.fmgr_provisioning:
- host: "{{ inventory_hostname }}"
- username: "{{ username }}"
- password: "{{ password }}"
- adom: "root"
- vdom: "root"
- policy_package: "test_pp"
- name: "FGT2"
- group: "Ansible"
- serial: "FGVM000000117992"
- platform: "FortiGate-VM64"
- description: "Provisioned by Ansible"
- os_version: '5.0'
- minor_release: 6
- patch_release: 0
- os_type: 'fos'
-
-'''
-
-RETURN = """
-api_result:
- description: full API response, includes status code and message
- returned: always
- type: str
-"""
-
-from ansible.module_utils.basic import AnsibleModule, env_fallback
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import AnsibleFortiManager
-
-# check for pyFMG lib
-try:
- from pyFMG.fortimgr import FortiManager
- HAS_PYFMGR = True
-except ImportError:
- HAS_PYFMGR = False
-
-
-def dev_group_exists(fmg, dev_grp_name, adom):
- datagram = {
- 'adom': adom,
- 'name': dev_grp_name,
- }
-
- url = '/dvmdb/adom/{adom}/group/{dev_grp_name}'.format(adom=adom, dev_grp_name=dev_grp_name)
- response = fmg.get(url, datagram)
- return response
-
-
-def prov_template_exists(fmg, prov_template, adom, vdom):
- datagram = {
- 'name': prov_template,
- 'adom': adom,
- }
-
- url = '/pm/devprof/adom/{adom}/devprof/{name}'.format(adom=adom, name=prov_template)
- response = fmg.get(url, datagram)
- return response
-
-
-def create_model_device(fmg, name, serial, group, platform, os_version,
- os_type, minor_release, patch_release=0, adom='root'):
- datagram = {
- 'adom': adom,
- 'flags': ['create_task', 'nonblocking'],
- 'groups': [{'name': group, 'vdom': 'root'}],
- 'device': {
- 'mr': minor_release,
- 'name': name,
- 'sn': serial,
- 'mgmt_mode': 'fmg',
- 'device action': 'add_model',
- 'platform_str': platform,
- 'os_ver': os_version,
- 'os_type': os_type,
- 'patch': patch_release,
- 'desc': 'Provisioned by Ansible',
- }
- }
-
- url = '/dvm/cmd/add/device'
- response = fmg.execute(url, datagram)
- return response
-
-
-def update_flags(fmg, name):
- datagram = {
- 'flags': ['is_model', 'linked_to_model']
- }
- url = 'dvmdb/device/{name}'.format(name=name)
- response = fmg.update(url, datagram)
- return response
-
-
-def assign_provision_template(fmg, template, adom, target):
- datagram = {
- 'name': template,
- 'type': 'devprof',
- 'description': 'Provisioned by Ansible',
- 'scope member': [{'name': target}]
- }
- url = "/pm/devprof/adom/{adom}".format(adom=adom)
- response = fmg.update(url, datagram)
- return response
-
-
-def set_devprof_scope(self, provisioning_template, adom, provision_targets):
- """
- GET the DevProf (check to see if exists)
- """
- fields = dict()
- targets = []
- fields["name"] = provisioning_template
- fields["type"] = "devprof"
- fields["description"] = "CreatedByAnsible"
-
- for target in provision_targets.strip().split(","):
- # split the host on the space to get the mask out
- new_target = {"name": target}
- targets.append(new_target)
-
- fields["scope member"] = targets
-
- body = {"method": "set", "params": [{"url": "/pm/devprof/adom/{adom}".format(adom=adom),
- "data": fields, "session": self.session}]}
- response = self.make_request(body).json()
- return response
-
-
-def assign_dev_grp(fmg, grp_name, device_name, vdom, adom):
- datagram = {
- 'name': device_name,
- 'vdom': vdom,
- }
- url = "/dvmdb/adom/{adom}/group/{grp_name}/object member".format(adom=adom, grp_name=grp_name)
- response = fmg.set(url, datagram)
- return response
-
-
-def update_install_target(fmg, device, pp='default', vdom='root', adom='root'):
- datagram = {
- 'scope member': [{'name': device, 'vdom': vdom}],
- 'type': 'pkg'
- }
- url = '/pm/pkg/adom/{adom}/{pkg_name}'.format(adom=adom, pkg_name=pp)
- response = fmg.update(url, datagram)
- return response
-
-
-def install_pp(fmg, device, pp='default', vdom='root', adom='root'):
- datagram = {
- 'adom': adom,
- 'flags': 'nonblocking',
- 'pkg': pp,
- 'scope': [{'name': device, 'vdom': vdom}],
- }
- url = 'securityconsole/install/package'
- response = fmg.execute(url, datagram)
- return response
-
-
-def main():
-
- argument_spec = dict(
- adom=dict(required=False, type="str"),
- vdom=dict(required=False, type="str"),
- host=dict(required=True, type="str"),
- password=dict(fallback=(env_fallback, ["ANSIBLE_NET_PASSWORD"]), no_log=True),
- username=dict(fallback=(env_fallback, ["ANSIBLE_NET_USERNAME"]), no_log=True),
-
- policy_package=dict(required=False, type="str"),
- name=dict(required=False, type="str"),
- group=dict(required=False, type="str"),
- serial=dict(required=True, type="str"),
- platform=dict(required=True, type="str"),
- description=dict(required=False, type="str"),
- os_version=dict(required=True, type="str"),
- minor_release=dict(required=False, type="str"),
- patch_release=dict(required=False, type="str"),
- os_type=dict(required=False, type="str"),
-
- )
-
- module = AnsibleModule(argument_spec, supports_check_mode=True, )
-
- # check if params are set
- if module.params["host"] is None or module.params["username"] is None:
- module.fail_json(msg="Host and username are required for connection")
-
- # check if login failed
- fmg = AnsibleFortiManager(module, module.params["host"], module.params["username"], module.params["password"])
- response = fmg.login()
-
- if "FortiManager instance connnected" not in str(response):
- module.fail_json(msg="Connection to FortiManager Failed")
- else:
-
- if module.params["policy_package"] is None:
- module.params["policy_package"] = 'default'
- if module.params["adom"] is None:
- module.params["adom"] = 'root'
- if module.params["vdom"] is None:
- module.params["vdom"] = 'root'
- if module.params["platform"] is None:
- module.params["platform"] = 'FortiGate-VM64'
- if module.params["os_type"] is None:
- module.params["os_type"] = 'fos'
-
- results = create_model_device(fmg,
- module.params["name"],
- module.params["serial"],
- module.params["group"],
- module.params["platform"],
- module.params["os_ver"],
- module.params["os_type"],
- module.params["minor_release"],
- module.params["patch_release"],
- module.params["adom"])
- if results[0] != 0:
- module.fail_json(msg="Create model failed", **results)
-
- results = update_flags(fmg, module.params["name"])
- if results[0] != 0:
- module.fail_json(msg="Update device flags failed", **results)
-
- # results = assign_dev_grp(fmg, 'Ansible', 'FGVM000000117992', 'root', 'root')
- # if not results[0] == 0:
- # module.fail_json(msg="Setting device group failed", **results)
-
- results = update_install_target(fmg, module.params["name"], module.params["policy_package"])
- if results[0] != 0:
- module.fail_json(msg="Adding device target to package failed", **results)
-
- results = install_pp(fmg, module.params["name"], module.params["policy_package"])
- if results[0] != 0:
- module.fail_json(msg="Installing policy package failed", **results)
-
- fmg.logout()
-
- # results is returned as a tuple
- return module.exit_json(**results[1])
-
-
-if __name__ == "__main__":
- main()
diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_query.py b/ansible_collections/community/fortios/plugins/modules/fmgr_query.py
deleted file mode 100644
index 1ceb7dbb3..000000000
--- a/ansible_collections/community/fortios/plugins/modules/fmgr_query.py
+++ /dev/null
@@ -1,424 +0,0 @@
-#!/usr/bin/python
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-DOCUMENTATION = '''
----
-module: fmgr_query
-notes:
- - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
-author: Luke Weighall (@lweighall)
-short_description: Query FortiManager data objects for use in Ansible workflows.
-description:
- - Provides information on data objects within FortiManager so that playbooks can perform conditionals.
-
-options:
- adom:
- description:
- - The ADOM the configuration should belong to.
- required: false
- default: root
-
- object:
- description:
- - The data object we wish to query (device, package, rule, etc). Will expand choices as improves.
- required: true
- choices:
- - device
- - cluster_nodes
- - task
- - custom
-
- custom_endpoint:
- description:
- - ADVANCED USERS ONLY! REQUIRES KNOWLEDGE OF FMGR JSON API!
- - The HTTP Endpoint on FortiManager you wish to GET from.
- required: false
-
- custom_dict:
- description:
- - ADVANCED USERS ONLY! REQUIRES KNOWLEDGE OF FMGR JSON API!
- - DICTIONARY JSON FORMAT ONLY -- Custom dictionary/datagram to send to the endpoint.
- required: false
-
- device_ip:
- description:
- - The IP of the device you want to query.
- required: false
-
- device_unique_name:
- description:
- - The desired "friendly" name of the device you want to query.
- required: false
-
- device_serial:
- description:
- - The serial number of the device you want to query.
- required: false
-
- task_id:
- description:
- - The ID of the task you wish to query status on. If left blank and object = 'task' a list of tasks are returned.
- required: false
-
- nodes:
- description:
- - A LIST of firewalls in the cluster you want to verify i.e. ["firewall_A","firewall_B"].
- required: false
-'''
-
-
-EXAMPLES = '''
-- name: QUERY FORTIGATE DEVICE BY IP
- community.fortios.fmgr_query:
- object: "device"
- adom: "ansible"
- device_ip: "10.7.220.41"
-
-- name: QUERY FORTIGATE DEVICE BY SERIAL
- community.fortios.fmgr_query:
- adom: "ansible"
- object: "device"
- device_serial: "FGVM000000117992"
-
-- name: QUERY FORTIGATE DEVICE BY FRIENDLY NAME
- community.fortios.fmgr_query:
- adom: "ansible"
- object: "device"
- device_unique_name: "ansible-fgt01"
-
-- name: VERIFY CLUSTER MEMBERS AND STATUS
- community.fortios.fmgr_query:
- adom: "ansible"
- object: "cluster_nodes"
- device_unique_name: "fgt-cluster01"
- nodes: ["ansible-fgt01", "ansible-fgt02", "ansible-fgt03"]
-
-- name: GET STATUS OF TASK ID
- community.fortios.fmgr_query:
- adom: "ansible"
- object: "task"
- task_id: "3"
-
-- name: USE CUSTOM TYPE TO QUERY AVAILABLE SCRIPTS
- community.fortios.fmgr_query:
- adom: "ansible"
- object: "custom"
- custom_endpoint: "/dvmdb/adom/ansible/script"
- custom_dict: { "type": "cli" }
-'''
-
-RETURN = """
-api_result:
- description: full API response, includes status code and message
- returned: always
- type: str
-"""
-
-from ansible.module_utils.basic import AnsibleModule, env_fallback
-from ansible.module_utils.connection import Connection
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRMethods
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG
-
-
-def fmgr_get_custom(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
- # IF THE CUSTOM DICTIONARY (OFTEN CONTAINING FILTERS) IS DEFINED CREATED THAT
- if paramgram["custom_dict"] is not None:
- datagram = paramgram["custom_dict"]
- else:
- datagram = dict()
-
- # SET THE CUSTOM ENDPOINT PROVIDED
- url = paramgram["custom_endpoint"]
- # MAKE THE CALL AND RETURN RESULTS
- response = fmgr.process_request(url, datagram, FMGRMethods.GET)
- return response
-
-
-def fmgr_get_task_status(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
- # IF THE TASK_ID IS DEFINED, THEN GET THAT SPECIFIC TASK
- # OTHERWISE, GET ALL RECENT TASKS IN A LIST
- if paramgram["task_id"] is not None:
-
- datagram = {
- "adom": paramgram["adom"]
- }
- url = '/task/task/{task_id}'.format(task_id=paramgram["task_id"])
- response = fmgr.process_request(url, datagram, FMGRMethods.GET)
- else:
- datagram = {
- "adom": paramgram["adom"]
- }
- url = '/task/task'
- response = fmgr.process_request(url, datagram, FMGRMethods.GET)
- return response
-
-
-def fmgr_get_device(fmgr, paramgram):
- """
- This method is used to get information on devices. This will not work on HA_SLAVE nodes, only top level devices.
- Such as cluster objects and standalone devices.
-
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
- # FIRST TRY TO RUN AN UPDATE ON THE DEVICE
- # RUN A QUICK CLUSTER REFRESH/UPDATE ATTEMPT TO ENSURE WE'RE GETTING THE LATEST INFORMOATION
- response = DEFAULT_RESULT_OBJ
- url = ""
- datagram = {}
-
- update_url = '/dvm/cmd/update/device'
- update_dict = {
- "adom": paramgram['adom'],
- "device": paramgram['device_unique_name'],
- "flags": "create_task"
- }
- # DO THE UPDATE CALL
- fmgr.process_request(update_url, update_dict, FMGRMethods.EXEC)
-
- # SET THE URL
- url = '/dvmdb/adom/{adom}/device'.format(adom=paramgram["adom"])
- device_found = 0
- response = []
-
- # TRY TO FIND IT FIRST BY SERIAL NUMBER
- if paramgram["device_serial"] is not None:
- datagram = {
- "filter": ["sn", "==", paramgram["device_serial"]]
- }
- response = fmgr.process_request(url, datagram, FMGRMethods.GET)
- if len(response[1]) >= 0:
- device_found = 1
-
- # CHECK IF ANYTHING WAS RETURNED, IF NOT TRY DEVICE NAME PARAMETER
- if device_found == 0 and paramgram["device_unique_name"] is not None:
- datagram = {
- "filter": ["name", "==", paramgram["device_unique_name"]]
- }
- response = fmgr.process_request(url, datagram, FMGRMethods.GET)
- if len(response[1]) >= 0:
- device_found = 1
-
- # CHECK IF ANYTHING WAS RETURNED, IF NOT TRY DEVICE IP ADDRESS
- if device_found == 0 and paramgram["device_ip"] is not None:
- datagram = {
- "filter": ["ip", "==", paramgram["device_ip"]]
- }
- response = fmgr.process_request(url, datagram, FMGRMethods.GET)
- if len(response[1]) >= 0:
- device_found = 1
-
- return response
-
-
-def fmgr_get_cluster_nodes(fmgr, paramgram):
- """
- This method is used to get information on devices. This WILL work on HA_SLAVE nodes, but NOT top level standalone
- devices.
- Such as cluster objects and standalone devices.
-
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
- response = DEFAULT_RESULT_OBJ
- url = ""
- datagram = {}
- # USE THE DEVICE METHOD TO GET THE CLUSTER INFORMATION SO WE CAN SEE THE HA_SLAVE NODES
- response = fmgr_get_device(fmgr, paramgram)
- # CHECK FOR HA_SLAVE NODES, IF CLUSTER IS MISSING COMPLETELY THEN QUIT
- try:
- returned_nodes = response[1][0]["ha_slave"]
- num_of_nodes = len(returned_nodes)
- except Exception:
- error_msg = {"cluster_status": "MISSING"}
- return error_msg
-
- # INIT LOOP RESOURCES
- loop_count = 0
- good_nodes = []
- expected_nodes = list(paramgram["nodes"])
- missing_nodes = list(paramgram["nodes"])
- bad_status_nodes = []
-
- # LOOP THROUGH THE NODES AND GET THEIR STATUS TO BUILD THE RETURN JSON OBJECT
- # WE'RE ALSO CHECKING THE NODES IF THEY ARE BAD STATUS, OR PLAIN MISSING
- while loop_count < num_of_nodes:
- node_append = {
- "node_name": returned_nodes[loop_count]["name"],
- "node_serial": returned_nodes[loop_count]["sn"],
- "node_parent": returned_nodes[loop_count]["did"],
- "node_status": returned_nodes[loop_count]["status"],
- }
- # IF THE NODE IS IN THE EXPECTED NODES LIST AND WORKING THEN ADD IT TO GOOD NODES LIST
- if node_append["node_name"] in expected_nodes and node_append["node_status"] == 1:
- good_nodes.append(node_append["node_name"])
- # IF THE NODE IS IN THE EXPECTED NODES LIST BUT NOT WORKING THEN ADDED IT TO BAD_STATUS_NODES
- # IF THE NODE STATUS IS NOT 1 THEN ITS BAD
- if node_append["node_name"] in expected_nodes and node_append["node_status"] != 1:
- bad_status_nodes.append(node_append["node_name"])
- # REMOVE THE NODE FROM MISSING NODES LIST IF NOTHING IS WRONG WITH NODE -- LEAVING US A LIST OF
- # NOT WORKING NODES
- missing_nodes.remove(node_append["node_name"])
- loop_count += 1
-
- # BUILD RETURN OBJECT FROM NODE LISTS
- nodes = {
- "good_nodes": good_nodes,
- "expected_nodes": expected_nodes,
- "missing_nodes": missing_nodes,
- "bad_nodes": bad_status_nodes,
- "query_status": "good",
- }
- if len(nodes["good_nodes"]) == len(nodes["expected_nodes"]):
- nodes["cluster_status"] = "OK"
- else:
- nodes["cluster_status"] = "NOT-COMPLIANT"
- return nodes
-
-
-def main():
- argument_spec = dict(
- adom=dict(required=False, type="str", default="root"),
- object=dict(required=True, type="str", choices=["device", "cluster_nodes", "task", "custom"]),
- custom_endpoint=dict(required=False, type="str"),
- custom_dict=dict(required=False, type="dict"),
- device_ip=dict(required=False, type="str"),
- device_unique_name=dict(required=False, type="str"),
- device_serial=dict(required=False, type="str"),
- nodes=dict(required=False, type="list"),
- task_id=dict(required=False, type="str")
- )
-
- module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
- paramgram = {
- "adom": module.params["adom"],
- "object": module.params["object"],
- "device_ip": module.params["device_ip"],
- "device_unique_name": module.params["device_unique_name"],
- "device_serial": module.params["device_serial"],
- "nodes": module.params["nodes"],
- "task_id": module.params["task_id"],
- "custom_endpoint": module.params["custom_endpoint"],
- "custom_dict": module.params["custom_dict"]
- }
- module.paramgram = paramgram
- fmgr = None
- if module._socket_path:
- connection = Connection(module._socket_path)
- fmgr = FortiManagerHandler(connection, module)
- fmgr.tools = FMGRCommon()
- else:
- module.fail_json(**FAIL_SOCKET_MSG)
-
- results = DEFAULT_RESULT_OBJ
-
- try:
- # IF OBJECT IS DEVICE
- if paramgram["object"] == "device" and any(v is not None for v in [paramgram["device_unique_name"],
- paramgram["device_serial"],
- paramgram["device_ip"]]):
- results = fmgr_get_device(fmgr, paramgram)
- if results[0] not in [0]:
- module.fail_json(msg="Device query failed!")
- elif len(results[1]) == 0:
- module.exit_json(msg="Device NOT FOUND!")
- else:
- module.exit_json(msg="Device Found", **results[1][0])
- except Exception as err:
- raise FMGBaseException(err)
-
- try:
- # IF OBJECT IS CLUSTER_NODES
- if paramgram["object"] == "cluster_nodes" and paramgram["nodes"] is not None:
- results = fmgr_get_cluster_nodes(fmgr, paramgram)
- if results["cluster_status"] == "MISSING":
- module.exit_json(msg="No cluster device found!", **results)
- elif results["query_status"] == "good":
- module.exit_json(msg="Cluster Found - Showing Nodes", **results)
- elif results is None:
- module.fail_json(msg="Query FAILED -- Check module or playbook syntax")
- except Exception as err:
- raise FMGBaseException(err)
-
- try:
- # IF OBJECT IS TASK
- if paramgram["object"] == "task":
- results = fmgr_get_task_status(fmgr, paramgram)
- if results[0] != 0:
- module.fail_json(**results[1])
- if results[0] == 0:
- module.exit_json(**results[1])
- except Exception as err:
- raise FMGBaseException(err)
-
- try:
- # IF OBJECT IS CUSTOM
- if paramgram["object"] == "custom":
- results = fmgr_get_custom(fmgr, paramgram)
- if results[0] != 0:
- module.fail_json(msg="QUERY FAILED -- Please check syntax check JSON guide if needed.")
- if results[0] == 0:
- results_len = len(results[1])
- if results_len > 0:
- results_combine = dict()
- if isinstance(results[1], dict):
- results_combine["results"] = results[1]
- if isinstance(results[1], list):
- results_combine["results"] = results[1][0:results_len]
- module.exit_json(msg="Custom Query Success", **results_combine)
- else:
- module.exit_json(msg="NO RESULTS")
- except Exception as err:
- raise FMGBaseException(err)
-
- return module.exit_json(**results[1])
-
-
-if __name__ == "__main__":
- main()
diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_script.py b/ansible_collections/community/fortios/plugins/modules/fmgr_script.py
deleted file mode 100644
index d84606cce..000000000
--- a/ansible_collections/community/fortios/plugins/modules/fmgr_script.py
+++ /dev/null
@@ -1,262 +0,0 @@
-#!/usr/bin/python
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-
-from __future__ import absolute_import, division, print_function
-
-__metaclass__ = type
-
-DOCUMENTATION = '''
----
-module: fmgr_script
-notes:
- - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
-author: Andrew Welsh (@Ghilli3)
-short_description: Add/Edit/Delete and execute scripts
-description: Create/edit/delete scripts and execute the scripts on the FortiManager using jsonrpc API
-
-options:
- adom:
- description:
- - The administrative domain (admon) the configuration belongs to
- required: true
-
- vdom:
- description:
- - The virtual domain (vdom) the configuration belongs to
-
- mode:
- description:
- - The desired mode of the specified object. Execute will run the script.
- required: false
- default: "add"
- choices: ["add", "delete", "execute", "set"]
-
- script_name:
- description:
- - The name of the script.
- required: True
-
- script_type:
- description:
- - The type of script (CLI or TCL).
- required: false
-
- script_target:
- description:
- - The target of the script to be run.
- required: false
-
- script_description:
- description:
- - The description of the script.
- required: false
-
- script_content:
- description:
- - The script content that will be executed.
- required: false
-
- script_scope:
- description:
- - (datasource) The devices that the script will run on, can have both device member and device group member.
- required: false
-
- script_package:
- description:
- - (datasource) Policy package object to run the script against
- required: false
-'''
-
-EXAMPLES = '''
-- name: CREATE SCRIPT
- community.fortios.fmgr_script:
- adom: "root"
- script_name: "TestScript"
- script_type: "cli"
- script_target: "remote_device"
- script_description: "Create by Ansible"
- script_content: "get system status"
-
-- name: EXECUTE SCRIPT
- community.fortios.fmgr_script:
- adom: "root"
- script_name: "TestScript"
- mode: "execute"
- script_scope: "FGT1,FGT2"
-
-- name: DELETE SCRIPT
- community.fortios.fmgr_script:
- adom: "root"
- script_name: "TestScript"
- mode: "delete"
-'''
-
-RETURN = """
-api_result:
- description: full API response, includes status code and message
- returned: always
- type: str
-"""
-
-from ansible.module_utils.basic import AnsibleModule, env_fallback
-from ansible.module_utils.connection import Connection
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRMethods
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG
-
-
-def set_script(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
-
- datagram = {
- 'content': paramgram["script_content"],
- 'desc': paramgram["script_description"],
- 'name': paramgram["script_name"],
- 'target': paramgram["script_target"],
- 'type': paramgram["script_type"],
- }
-
- url = '/dvmdb/adom/{adom}/script/'.format(adom=paramgram["adom"])
- response = fmgr.process_request(url, datagram, FMGRMethods.SET)
- return response
-
-
-def delete_script(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
-
- datagram = {
- 'name': paramgram["script_name"],
- }
-
- url = '/dvmdb/adom/{adom}/script/{script_name}'.format(adom=paramgram["adom"], script_name=paramgram["script_name"])
- response = fmgr.process_request(url, datagram, FMGRMethods.DELETE)
- return response
-
-
-def execute_script(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
-
- scope_list = list()
- scope = paramgram["script_scope"].replace(' ', '')
- scope = scope.split(',')
- for dev_name in scope:
- scope_list.append({'name': dev_name, 'vdom': paramgram["vdom"]})
-
- datagram = {
- 'adom': paramgram["adom"],
- 'script': paramgram["script_name"],
- 'package': paramgram["script_package"],
- 'scope': scope_list,
- }
-
- url = '/dvmdb/adom/{adom}/script/execute'.format(adom=paramgram["adom"])
- response = fmgr.process_request(url, datagram, FMGRMethods.EXEC)
- return response
-
-
-def main():
- argument_spec = dict(
- adom=dict(required=False, type="str", default="root"),
- vdom=dict(required=False, type="str", default="root"),
- mode=dict(choices=["add", "execute", "set", "delete"], type="str", default="add"),
- script_name=dict(required=True, type="str"),
- script_type=dict(required=False, type="str"),
- script_target=dict(required=False, type="str"),
- script_description=dict(required=False, type="str"),
- script_content=dict(required=False, type="str"),
- script_scope=dict(required=False, type="str"),
- script_package=dict(required=False, type="str"),
- )
-
- module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
- paramgram = {
- "script_name": module.params["script_name"],
- "script_type": module.params["script_type"],
- "script_target": module.params["script_target"],
- "script_description": module.params["script_description"],
- "script_content": module.params["script_content"],
- "script_scope": module.params["script_scope"],
- "script_package": module.params["script_package"],
- "adom": module.params["adom"],
- "vdom": module.params["vdom"],
- "mode": module.params["mode"],
- }
- module.paramgram = paramgram
- fmgr = None
- if module._socket_path:
- connection = Connection(module._socket_path)
- fmgr = FortiManagerHandler(connection, module)
- fmgr.tools = FMGRCommon()
- else:
- module.fail_json(**FAIL_SOCKET_MSG)
-
- results = DEFAULT_RESULT_OBJ
-
- try:
- if paramgram["mode"] in ['add', 'set']:
- results = set_script(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results, msg="Operation Finished",
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, module.params))
- except Exception as err:
- raise FMGBaseException(err)
-
- try:
- if paramgram["mode"] == "execute":
- results = execute_script(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results, msg="Operation Finished",
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, module.params))
- except Exception as err:
- raise FMGBaseException(err)
-
- try:
- if paramgram["mode"] == "delete":
- results = delete_script(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results, msg="Operation Finished",
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, module.params))
- except Exception as err:
- raise FMGBaseException(err)
-
- return module.exit_json(**results[1])
-
-
-if __name__ == "__main__":
- main()
diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_appctrl.py b/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_appctrl.py
deleted file mode 100644
index aabd29859..000000000
--- a/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_appctrl.py
+++ /dev/null
@@ -1,516 +0,0 @@
-#!/usr/bin/python
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-
-from __future__ import absolute_import, division, print_function
-
-__metaclass__ = type
-
-DOCUMENTATION = '''
----
-module: fmgr_secprof_appctrl
-notes:
- - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
-author:
- - Luke Weighall (@lweighall)
- - Andrew Welsh (@Ghilli3)
- - Jim Huber (@p4r4n0y1ng)
-short_description: Manage application control security profiles
-description:
- - Manage application control security profiles within FortiManager
-
-options:
- adom:
- description:
- - The ADOM the configuration should belong to.
- required: false
- default: root
-
- mode:
- description:
- - Sets one of three modes for managing the object.
- - Allows use of soft-adds instead of overwriting existing values
- choices: ['add', 'set', 'delete', 'update']
- required: false
- default: add
-
- unknown_application_log:
- description:
- - Enable/disable logging for unknown applications.
- - choice | disable | Disable logging for unknown applications.
- - choice | enable | Enable logging for unknown applications.
- required: false
- choices: ["disable", "enable"]
-
- unknown_application_action:
- description:
- - Pass or block traffic from unknown applications.
- - choice | pass | Pass or allow unknown applications.
- - choice | block | Drop or block unknown applications.
- required: false
- choices: ["pass", "block"]
-
- replacemsg_group:
- description:
- - Replacement message group.
- required: false
-
- p2p_black_list:
- description:
- - NO DESCRIPTION PARSED ENTER MANUALLY
- - FLAG Based Options. Specify multiple in list form.
- - flag | skype | Skype.
- - flag | edonkey | Edonkey.
- - flag | bittorrent | Bit torrent.
- required: false
- choices: ["skype", "edonkey", "bittorrent"]
-
- other_application_log:
- description:
- - Enable/disable logging for other applications.
- - choice | disable | Disable logging for other applications.
- - choice | enable | Enable logging for other applications.
- required: false
- choices: ["disable", "enable"]
-
- other_application_action:
- description:
- - Action for other applications.
- - choice | pass | Allow sessions matching an application in this application list.
- - choice | block | Block sessions matching an application in this application list.
- required: false
- choices: ["pass", "block"]
-
- options:
- description:
- - NO DESCRIPTION PARSED ENTER MANUALLY
- - FLAG Based Options. Specify multiple in list form.
- - flag | allow-dns | Allow DNS.
- - flag | allow-icmp | Allow ICMP.
- - flag | allow-http | Allow generic HTTP web browsing.
- - flag | allow-ssl | Allow generic SSL communication.
- - flag | allow-quic | Allow QUIC.
- required: false
- choices: ["allow-dns", "allow-icmp", "allow-http", "allow-ssl", "allow-quic"]
-
- name:
- description:
- - List name.
- required: false
-
- extended_log:
- description:
- - Enable/disable extended logging.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- deep_app_inspection:
- description:
- - Enable/disable deep application inspection.
- - choice | disable | Disable deep application inspection.
- - choice | enable | Enable deep application inspection.
- required: false
- choices: ["disable", "enable"]
-
- comment:
- description:
- - comments
- required: false
-
- app_replacemsg:
- description:
- - Enable/disable replacement messages for blocked applications.
- - choice | disable | Disable replacement messages for blocked applications.
- - choice | enable | Enable replacement messages for blocked applications.
- required: false
- choices: ["disable", "enable"]
-
- entries:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED. This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, OMIT THE USE OF THIS PARAMETER
- - AND USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- entries_action:
- description:
- - Pass or block traffic, or reset connection for traffic from this application.
- - choice | pass | Pass or allow matching traffic.
- - choice | block | Block or drop matching traffic.
- - choice | reset | Reset sessions for matching traffic.
- required: false
- choices: ["pass", "block", "reset"]
-
- entries_application:
- description:
- - ID of allowed applications.
- required: false
-
- entries_behavior:
- description:
- - Application behavior filter.
- required: false
-
- entries_category:
- description:
- - Category ID list.
- required: false
-
- entries_log:
- description:
- - Enable/disable logging for this application list.
- - choice | disable | Disable logging.
- - choice | enable | Enable logging.
- required: false
- choices: ["disable", "enable"]
-
- entries_log_packet:
- description:
- - Enable/disable packet logging.
- - choice | disable | Disable packet logging.
- - choice | enable | Enable packet logging.
- required: false
- choices: ["disable", "enable"]
-
- entries_per_ip_shaper:
- description:
- - Per-IP traffic shaper.
- required: false
-
- entries_popularity:
- description:
- - Application popularity filter (1 - 5, from least to most popular).
- - FLAG Based Options. Specify multiple in list form.
- - flag | 1 | Popularity level 1.
- - flag | 2 | Popularity level 2.
- - flag | 3 | Popularity level 3.
- - flag | 4 | Popularity level 4.
- - flag | 5 | Popularity level 5.
- required: false
- choices: ["1", "2", "3", "4", "5"]
-
- entries_protocols:
- description:
- - Application protocol filter.
- required: false
-
- entries_quarantine:
- description:
- - Quarantine method.
- - choice | none | Quarantine is disabled.
- - choice | attacker | Block all traffic sent from attacker's IP address.
- - The attacker's IP address is also added to the banned user list. The target's address is not affected.
- required: false
- choices: ["none", "attacker"]
-
- entries_quarantine_expiry:
- description:
- - Duration of quarantine. (Format ###d##h##m, minimum 1m, maximum 364d23h59m, default = 5m).
- - Requires quarantine set to attacker.
- required: false
-
- entries_quarantine_log:
- description:
- - Enable/disable quarantine logging.
- - choice | disable | Disable quarantine logging.
- - choice | enable | Enable quarantine logging.
- required: false
- choices: ["disable", "enable"]
-
- entries_rate_count:
- description:
- - Count of the rate.
- required: false
-
- entries_rate_duration:
- description:
- - Duration (sec) of the rate.
- required: false
-
- entries_rate_mode:
- description:
- - Rate limit mode.
- - choice | periodical | Allow configured number of packets every rate-duration.
- - choice | continuous | Block packets once the rate is reached.
- required: false
- choices: ["periodical", "continuous"]
-
- entries_rate_track:
- description:
- - Track the packet protocol field.
- - choice | none |
- - choice | src-ip | Source IP.
- - choice | dest-ip | Destination IP.
- - choice | dhcp-client-mac | DHCP client.
- - choice | dns-domain | DNS domain.
- required: false
- choices: ["none", "src-ip", "dest-ip", "dhcp-client-mac", "dns-domain"]
-
- entries_risk:
- description:
- - Risk, or impact, of allowing traffic from this application to occur 1 - 5;
- - (Low, Elevated, Medium, High, and Critical).
- required: false
-
- entries_session_ttl:
- description:
- - Session TTL (0 = default).
- required: false
-
- entries_shaper:
- description:
- - Traffic shaper.
- required: false
-
- entries_shaper_reverse:
- description:
- - Reverse traffic shaper.
- required: false
-
- entries_sub_category:
- description:
- - Application Sub-category ID list.
- required: false
-
- entries_technology:
- description:
- - Application technology filter.
- required: false
-
- entries_vendor:
- description:
- - Application vendor filter.
- required: false
-
- entries_parameters_value:
- description:
- - Parameter value.
- required: false
-
-
-'''
-
-EXAMPLES = '''
- - name: DELETE Profile
- community.fortios.fmgr_secprof_appctrl:
- name: "Ansible_Application_Control_Profile"
- comment: "Created by Ansible Module TEST"
- mode: "delete"
-
- - name: CREATE Profile
- community.fortios.fmgr_secprof_appctrl:
- name: "Ansible_Application_Control_Profile"
- comment: "Created by Ansible Module TEST"
- mode: "set"
- entries: [{
- action: "block",
- log: "enable",
- log-packet: "enable",
- protocols: ["1"],
- quarantine: "attacker",
- quarantine-log: "enable",
- },
- {action: "pass",
- category: ["2","3","4"]},
- ]
-'''
-
-RETURN = """
-api_result:
- description: full API response, includes status code and message
- returned: always
- type: str
-"""
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.connection import Connection
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import prepare_dict
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import scrub_dict
-
-###############
-# START METHODS
-###############
-
-
-def fmgr_application_list_modify(fmgr, paramgram):
- """
- fmgr_application_list -- Modifies Application Control Profiles on FortiManager
-
- :param fmgr: The fmgr object instance from fmgr_utils.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
-
- :return: The response from the FortiManager
- :rtype: dict
- """
- # INIT A BASIC OBJECTS
- response = DEFAULT_RESULT_OBJ
- url = ""
- datagram = {}
-
- # EVAL THE MODE PARAMETER FOR SET OR ADD
- if paramgram["mode"] in ['set', 'add', 'update']:
- url = '/pm/config/adom/{adom}/obj/application/list'.format(adom=paramgram["adom"])
- datagram = scrub_dict(prepare_dict(paramgram))
-
- # EVAL THE MODE PARAMETER FOR DELETE
- elif paramgram["mode"] == "delete":
- # SET THE CORRECT URL FOR DELETE
- url = '/pm/config/adom/{adom}/obj/application/list/{name}'.format(adom=paramgram["adom"],
- name=paramgram["name"])
- datagram = {}
-
- response = fmgr.process_request(url, datagram, paramgram["mode"])
- return response
-
-
-#############
-# END METHODS
-#############
-
-
-def main():
- argument_spec = dict(
- adom=dict(type="str", default="root"),
- mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),
-
- unknown_application_log=dict(required=False, type="str", choices=["disable", "enable"]),
- unknown_application_action=dict(required=False, type="str", choices=["pass", "block"]),
- replacemsg_group=dict(required=False, type="str"),
- p2p_black_list=dict(required=False, type="str", choices=["skype", "edonkey", "bittorrent"]),
- other_application_log=dict(required=False, type="str", choices=["disable", "enable"]),
- other_application_action=dict(required=False, type="str", choices=["pass", "block"]),
- options=dict(required=False, type="str",
- choices=["allow-dns", "allow-icmp", "allow-http", "allow-ssl", "allow-quic"]),
- name=dict(required=False, type="str"),
- extended_log=dict(required=False, type="str", choices=["disable", "enable"]),
- deep_app_inspection=dict(required=False, type="str", choices=["disable", "enable"]),
- comment=dict(required=False, type="str"),
- app_replacemsg=dict(required=False, type="str", choices=["disable", "enable"]),
- entries=dict(required=False, type="list"),
- entries_action=dict(required=False, type="str", choices=["pass", "block", "reset"]),
- entries_application=dict(required=False, type="str"),
- entries_behavior=dict(required=False, type="str"),
- entries_category=dict(required=False, type="str"),
- entries_log=dict(required=False, type="str", choices=["disable", "enable"]),
- entries_log_packet=dict(required=False, type="str", choices=["disable", "enable"]),
- entries_per_ip_shaper=dict(required=False, type="str"),
- entries_popularity=dict(required=False, type="str", choices=["1", "2", "3", "4", "5"]),
- entries_protocols=dict(required=False, type="str"),
- entries_quarantine=dict(required=False, type="str", choices=["none", "attacker"]),
- entries_quarantine_expiry=dict(required=False, type="str"),
- entries_quarantine_log=dict(required=False, type="str", choices=["disable", "enable"]),
- entries_rate_count=dict(required=False, type="int"),
- entries_rate_duration=dict(required=False, type="int"),
- entries_rate_mode=dict(required=False, type="str", choices=["periodical", "continuous"]),
- entries_rate_track=dict(required=False, type="str",
- choices=["none", "src-ip", "dest-ip", "dhcp-client-mac", "dns-domain"]),
- entries_risk=dict(required=False, type="str"),
- entries_session_ttl=dict(required=False, type="int"),
- entries_shaper=dict(required=False, type="str"),
- entries_shaper_reverse=dict(required=False, type="str"),
- entries_sub_category=dict(required=False, type="str"),
- entries_technology=dict(required=False, type="str"),
- entries_vendor=dict(required=False, type="str"),
-
- entries_parameters_value=dict(required=False, type="str"),
-
- )
- module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
- # MODULE PARAMGRAM
- paramgram = {
- "mode": module.params["mode"],
- "adom": module.params["adom"],
- "unknown-application-log": module.params["unknown_application_log"],
- "unknown-application-action": module.params["unknown_application_action"],
- "replacemsg-group": module.params["replacemsg_group"],
- "p2p-black-list": module.params["p2p_black_list"],
- "other-application-log": module.params["other_application_log"],
- "other-application-action": module.params["other_application_action"],
- "options": module.params["options"],
- "name": module.params["name"],
- "extended-log": module.params["extended_log"],
- "deep-app-inspection": module.params["deep_app_inspection"],
- "comment": module.params["comment"],
- "app-replacemsg": module.params["app_replacemsg"],
- "entries": {
- "action": module.params["entries_action"],
- "application": module.params["entries_application"],
- "behavior": module.params["entries_behavior"],
- "category": module.params["entries_category"],
- "log": module.params["entries_log"],
- "log-packet": module.params["entries_log_packet"],
- "per-ip-shaper": module.params["entries_per_ip_shaper"],
- "popularity": module.params["entries_popularity"],
- "protocols": module.params["entries_protocols"],
- "quarantine": module.params["entries_quarantine"],
- "quarantine-expiry": module.params["entries_quarantine_expiry"],
- "quarantine-log": module.params["entries_quarantine_log"],
- "rate-count": module.params["entries_rate_count"],
- "rate-duration": module.params["entries_rate_duration"],
- "rate-mode": module.params["entries_rate_mode"],
- "rate-track": module.params["entries_rate_track"],
- "risk": module.params["entries_risk"],
- "session-ttl": module.params["entries_session_ttl"],
- "shaper": module.params["entries_shaper"],
- "shaper-reverse": module.params["entries_shaper_reverse"],
- "sub-category": module.params["entries_sub_category"],
- "technology": module.params["entries_technology"],
- "vendor": module.params["entries_vendor"],
- "parameters": {
- "value": module.params["entries_parameters_value"],
- }
- }
- }
- module.paramgram = paramgram
- fmgr = None
- if module._socket_path:
- connection = Connection(module._socket_path)
- fmgr = FortiManagerHandler(connection, module)
- fmgr.tools = FMGRCommon()
- else:
- module.fail_json(**FAIL_SOCKET_MSG)
-
- list_overrides = ['entries']
- paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
- paramgram=paramgram, module=module)
-
- results = DEFAULT_RESULT_OBJ
- try:
- results = fmgr_application_list_modify(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
- except Exception as err:
- raise FMGBaseException(err)
-
- return module.exit_json(**results[1])
-
-
-if __name__ == "__main__":
- main()
diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_av.py b/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_av.py
deleted file mode 100644
index 88375cf16..000000000
--- a/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_av.py
+++ /dev/null
@@ -1,1386 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-DOCUMENTATION = '''
----
-module: fmgr_secprof_av
-notes:
- - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
-author:
- - Luke Weighall (@lweighall)
- - Andrew Welsh (@Ghilli3)
- - Jim Huber (@p4r4n0y1ng)
-short_description: Manage security profile
-description:
- - Manage security profile groups for FortiManager objects
-
-options:
- adom:
- description:
- - The ADOM the configuration should belong to.
- required: false
- default: root
-
- mode:
- description:
- - Sets one of three modes for managing the object.
- - Allows use of soft-adds instead of overwriting existing values
- choices: ['add', 'set', 'delete', 'update']
- required: false
- default: add
-
- scan_mode:
- description:
- - Choose between full scan mode and quick scan mode.
- required: false
- choices:
- - quick
- - full
-
- replacemsg_group:
- description:
- - Replacement message group customized for this profile.
- required: false
-
- name:
- description:
- - Profile name.
- required: false
-
- mobile_malware_db:
- description:
- - Enable/disable using the mobile malware signature database.
- required: false
- choices:
- - disable
- - enable
-
- inspection_mode:
- description:
- - Inspection mode.
- required: false
- choices:
- - proxy
- - flow-based
-
- ftgd_analytics:
- description:
- - Settings to control which files are uploaded to FortiSandbox.
- required: false
- choices:
- - disable
- - suspicious
- - everything
-
- extended_log:
- description:
- - Enable/disable extended logging for antivirus.
- required: false
- choices:
- - disable
- - enable
-
- comment:
- description:
- - Comment.
- required: false
-
- av_virus_log:
- description:
- - Enable/disable AntiVirus logging.
- required: false
- choices:
- - disable
- - enable
-
- av_block_log:
- description:
- - Enable/disable logging for AntiVirus file blocking.
- required: false
- choices:
- - disable
- - enable
-
- analytics_wl_filetype:
- description:
- - Do not submit files matching this DLP file-pattern to FortiSandbox.
- required: false
-
- analytics_max_upload:
- description:
- - Maximum size of files that can be uploaded to FortiSandbox (1 - 395 MBytes, default = 10).
- required: false
-
- analytics_db:
- description:
- - Enable/disable using the FortiSandbox signature database to supplement the AV signature databases.
- required: false
- choices:
- - disable
- - enable
-
- analytics_bl_filetype:
- description:
- - Only submit files matching this DLP file-pattern to FortiSandbox.
- required: false
-
- content_disarm:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- content_disarm_cover_page:
- description:
- - Enable/disable inserting a cover page into the disarmed document.
- required: false
- choices:
- - disable
- - enable
-
- content_disarm_detect_only:
- description:
- - Enable/disable only detect disarmable files, do not alter content.
- required: false
- choices:
- - disable
- - enable
-
- content_disarm_office_embed:
- description:
- - Enable/disable stripping of embedded objects in Microsoft Office documents.
- required: false
- choices:
- - disable
- - enable
-
- content_disarm_office_hylink:
- description:
- - Enable/disable stripping of hyperlinks in Microsoft Office documents.
- required: false
- choices:
- - disable
- - enable
-
- content_disarm_office_linked:
- description:
- - Enable/disable stripping of linked objects in Microsoft Office documents.
- required: false
- choices:
- - disable
- - enable
-
- content_disarm_office_macro:
- description:
- - Enable/disable stripping of macros in Microsoft Office documents.
- required: false
- choices:
- - disable
- - enable
-
- content_disarm_original_file_destination:
- description:
- - Destination to send original file if active content is removed.
- required: false
- choices:
- - fortisandbox
- - quarantine
- - discard
-
- content_disarm_pdf_act_form:
- description:
- - Enable/disable stripping of actions that submit data to other targets in PDF documents.
- required: false
- choices:
- - disable
- - enable
-
- content_disarm_pdf_act_gotor:
- description:
- - Enable/disable stripping of links to other PDFs in PDF documents.
- required: false
- choices:
- - disable
- - enable
-
- content_disarm_pdf_act_java:
- description:
- - Enable/disable stripping of actions that execute JavaScript code in PDF documents.
- required: false
- choices:
- - disable
- - enable
-
- content_disarm_pdf_act_launch:
- description:
- - Enable/disable stripping of links to external applications in PDF documents.
- required: false
- choices:
- - disable
- - enable
-
- content_disarm_pdf_act_movie:
- description:
- - Enable/disable stripping of embedded movies in PDF documents.
- required: false
- choices:
- - disable
- - enable
-
- content_disarm_pdf_act_sound:
- description:
- - Enable/disable stripping of embedded sound files in PDF documents.
- required: false
- choices:
- - disable
- - enable
-
- content_disarm_pdf_embedfile:
- description:
- - Enable/disable stripping of embedded files in PDF documents.
- required: false
- choices:
- - disable
- - enable
-
- content_disarm_pdf_hyperlink:
- description:
- - Enable/disable stripping of hyperlinks from PDF documents.
- required: false
- choices:
- - disable
- - enable
-
- content_disarm_pdf_javacode:
- description:
- - Enable/disable stripping of JavaScript code in PDF documents.
- required: false
- choices:
- - disable
- - enable
-
- ftp:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- ftp_archive_block:
- description:
- - Select the archive types to block.
- - FLAG Based Options. Specify multiple in list form.
- required: false
- choices:
- - encrypted
- - corrupted
- - multipart
- - nested
- - mailbomb
- - unhandled
- - partiallycorrupted
- - fileslimit
- - timeout
-
- ftp_archive_log:
- description:
- - Select the archive types to log.
- - FLAG Based Options. Specify multiple in list form.
- required: false
- choices:
- - encrypted
- - corrupted
- - multipart
- - nested
- - mailbomb
- - unhandled
- - partiallycorrupted
- - fileslimit
- - timeout
-
- ftp_emulator:
- description:
- - Enable/disable the virus emulator.
- required: false
- choices:
- - disable
- - enable
-
- ftp_options:
- description:
- - Enable/disable FTP AntiVirus scanning, monitoring, and quarantine.
- - FLAG Based Options. Specify multiple in list form.
- required: false
- choices:
- - scan
- - quarantine
- - avmonitor
-
- ftp_outbreak_prevention:
- description:
- - Enable FortiGuard Virus Outbreak Prevention service.
- required: false
- choices:
- - disabled
- - files
- - full-archive
-
- http:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- http_archive_block:
- description:
- - Select the archive types to block.
- - FLAG Based Options. Specify multiple in list form.
- required: false
- choices:
- - encrypted
- - corrupted
- - multipart
- - nested
- - mailbomb
- - unhandled
- - partiallycorrupted
- - fileslimit
- - timeout
-
- http_archive_log:
- description:
- - Select the archive types to log.
- - FLAG Based Options. Specify multiple in list form.
- required: false
- choices:
- - encrypted
- - corrupted
- - multipart
- - nested
- - mailbomb
- - unhandled
- - partiallycorrupted
- - fileslimit
- - timeout
-
- http_content_disarm:
- description:
- - Enable Content Disarm and Reconstruction for this protocol.
- required: false
- choices:
- - disable
- - enable
-
- http_emulator:
- description:
- - Enable/disable the virus emulator.
- required: false
- choices:
- - disable
- - enable
-
- http_options:
- description:
- - Enable/disable HTTP AntiVirus scanning, monitoring, and quarantine.
- - FLAG Based Options. Specify multiple in list form.
- required: false
- choices:
- - scan
- - quarantine
- - avmonitor
-
- http_outbreak_prevention:
- description:
- - Enable FortiGuard Virus Outbreak Prevention service.
- required: false
- choices:
- - disabled
- - files
- - full-archive
-
- imap:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- imap_archive_block:
- description:
- - Select the archive types to block.
- - FLAG Based Options. Specify multiple in list form.
- required: false
- choices:
- - encrypted
- - corrupted
- - multipart
- - nested
- - mailbomb
- - unhandled
- - partiallycorrupted
- - fileslimit
- - timeout
-
- imap_archive_log:
- description:
- - Select the archive types to log.
- - FLAG Based Options. Specify multiple in list form.
- required: false
- choices:
- - encrypted
- - corrupted
- - multipart
- - nested
- - mailbomb
- - unhandled
- - partiallycorrupted
- - fileslimit
- - timeout
-
- imap_content_disarm:
- description:
- - Enable Content Disarm and Reconstruction for this protocol.
- required: false
- choices:
- - disable
- - enable
-
- imap_emulator:
- description:
- - Enable/disable the virus emulator.
- required: false
- choices:
- - disable
- - enable
-
- imap_executables:
- description:
- - Treat Windows executable files as viruses for the purpose of blocking or monitoring.
- required: false
- choices:
- - default
- - virus
-
- imap_options:
- description:
- - Enable/disable IMAP AntiVirus scanning, monitoring, and quarantine.
- - FLAG Based Options. Specify multiple in list form.
- required: false
- choices:
- - scan
- - quarantine
- - avmonitor
-
- imap_outbreak_prevention:
- description:
- - Enable FortiGuard Virus Outbreak Prevention service.
- required: false
- choices:
- - disabled
- - files
- - full-archive
-
- mapi:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- mapi_archive_block:
- description:
- - Select the archive types to block.
- - FLAG Based Options. Specify multiple in list form.
- required: false
- choices:
- - encrypted
- - corrupted
- - multipart
- - nested
- - mailbomb
- - unhandled
- - partiallycorrupted
- - fileslimit
- - timeout
-
- mapi_archive_log:
- description:
- - Select the archive types to log.
- - FLAG Based Options. Specify multiple in list form.
- required: false
- choices:
- - encrypted
- - corrupted
- - multipart
- - nested
- - mailbomb
- - unhandled
- - partiallycorrupted
- - fileslimit
- - timeout
-
- mapi_emulator:
- description:
- - Enable/disable the virus emulator.
- required: false
- choices:
- - disable
- - enable
-
- mapi_executables:
- description:
- - Treat Windows executable files as viruses for the purpose of blocking or monitoring.
- required: false
- choices:
- - default
- - virus
-
- mapi_options:
- description:
- - Enable/disable MAPI AntiVirus scanning, monitoring, and quarantine.
- - FLAG Based Options. Specify multiple in list form.
- required: false
- choices:
- - scan
- - quarantine
- - avmonitor
-
- mapi_outbreak_prevention:
- description:
- - Enable FortiGuard Virus Outbreak Prevention service.
- required: false
- choices:
- - disabled
- - files
- - full-archive
-
- nac_quar:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- nac_quar_expiry:
- description:
- - Duration of quarantine.
- required: false
-
- nac_quar_infected:
- description:
- - Enable/Disable quarantining infected hosts to the banned user list.
- required: false
- choices:
- - none
- - quar-src-ip
-
- nac_quar_log:
- description:
- - Enable/disable AntiVirus quarantine logging.
- required: false
- choices:
- - disable
- - enable
-
- nntp:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- nntp_archive_block:
- description:
- - Select the archive types to block.
- - FLAG Based Options. Specify multiple in list form.
- required: false
- choices:
- - encrypted
- - corrupted
- - multipart
- - nested
- - mailbomb
- - unhandled
- - partiallycorrupted
- - fileslimit
- - timeout
-
- nntp_archive_log:
- description:
- - Select the archive types to log.
- - FLAG Based Options. Specify multiple in list form.
- required: false
- choices:
- - encrypted
- - corrupted
- - multipart
- - nested
- - mailbomb
- - unhandled
- - partiallycorrupted
- - fileslimit
- - timeout
-
- nntp_emulator:
- description:
- - Enable/disable the virus emulator.
- required: false
- choices:
- - disable
- - enable
-
- nntp_options:
- description:
- - Enable/disable NNTP AntiVirus scanning, monitoring, and quarantine.
- - FLAG Based Options. Specify multiple in list form.
- required: false
- choices:
- - scan
- - quarantine
- - avmonitor
-
- nntp_outbreak_prevention:
- description:
- - Enable FortiGuard Virus Outbreak Prevention service.
- required: false
- choices:
- - disabled
- - files
- - full-archive
-
- pop3:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- pop3_archive_block:
- description:
- - Select the archive types to block.
- - FLAG Based Options. Specify multiple in list form.
- required: false
- choices:
- - encrypted
- - corrupted
- - multipart
- - nested
- - mailbomb
- - unhandled
- - partiallycorrupted
- - fileslimit
- - timeout
-
- pop3_archive_log:
- description:
- - Select the archive types to log.
- - FLAG Based Options. Specify multiple in list form.
- required: false
- choices:
- - encrypted
- - corrupted
- - multipart
- - nested
- - mailbomb
- - unhandled
- - partiallycorrupted
- - fileslimit
- - timeout
-
- pop3_content_disarm:
- description:
- - Enable Content Disarm and Reconstruction for this protocol.
- required: false
- choices:
- - disable
- - enable
-
- pop3_emulator:
- description:
- - Enable/disable the virus emulator.
- required: false
- choices:
- - disable
- - enable
-
- pop3_executables:
- description:
- - Treat Windows executable files as viruses for the purpose of blocking or monitoring.
- required: false
- choices:
- - default
- - virus
-
- pop3_options:
- description:
- - Enable/disable POP3 AntiVirus scanning, monitoring, and quarantine.
- - FLAG Based Options. Specify multiple in list form.
- required: false
- choices:
- - scan
- - quarantine
- - avmonitor
-
- pop3_outbreak_prevention:
- description:
- - Enable FortiGuard Virus Outbreak Prevention service.
- required: false
- choices:
- - disabled
- - files
- - full-archive
-
- smb:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- smb_archive_block:
- description:
- - Select the archive types to block.
- - FLAG Based Options. Specify multiple in list form.
- required: false
- choices:
- - encrypted
- - corrupted
- - multipart
- - nested
- - mailbomb
- - unhandled
- - partiallycorrupted
- - fileslimit
- - timeout
-
- smb_archive_log:
- description:
- - Select the archive types to log.
- - FLAG Based Options. Specify multiple in list form.
- required: false
- choices:
- - encrypted
- - corrupted
- - multipart
- - nested
- - mailbomb
- - unhandled
- - partiallycorrupted
- - fileslimit
- - timeout
-
- smb_emulator:
- description:
- - Enable/disable the virus emulator.
- required: false
- choices:
- - disable
- - enable
-
- smb_options:
- description:
- - Enable/disable SMB AntiVirus scanning, monitoring, and quarantine.
- - FLAG Based Options. Specify multiple in list form.
- required: false
- choices:
- - scan
- - quarantine
- - avmonitor
-
- smb_outbreak_prevention:
- description:
- - Enable FortiGuard Virus Outbreak Prevention service.
- required: false
- choices:
- - disabled
- - files
- - full-archive
-
- smtp:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- smtp_archive_block:
- description:
- - Select the archive types to block.
- - FLAG Based Options. Specify multiple in list form.
- required: false
- choices:
- - encrypted
- - corrupted
- - multipart
- - nested
- - mailbomb
- - unhandled
- - partiallycorrupted
- - fileslimit
- - timeout
-
- smtp_archive_log:
- description:
- - Select the archive types to log.
- - FLAG Based Options. Specify multiple in list form.
- required: false
- choices:
- - encrypted
- - corrupted
- - multipart
- - nested
- - mailbomb
- - unhandled
- - partiallycorrupted
- - fileslimit
- - timeout
-
- smtp_content_disarm:
- description:
- - Enable Content Disarm and Reconstruction for this protocol.
- required: false
- choices:
- - disable
- - enable
-
- smtp_emulator:
- description:
- - Enable/disable the virus emulator.
- required: false
- choices:
- - disable
- - enable
-
- smtp_executables:
- description:
- - Treat Windows executable files as viruses for the purpose of blocking or monitoring.
- required: false
- choices:
- - default
- - virus
-
- smtp_options:
- description:
- - Enable/disable SMTP AntiVirus scanning, monitoring, and quarantine.
- - FLAG Based Options. Specify multiple in list form.
- required: false
- choices:
- - scan
- - quarantine
- - avmonitor
-
- smtp_outbreak_prevention:
- description:
- - Enable FortiGuard Virus Outbreak Prevention service.
- required: false
- choices:
- - disabled
- - files
- - full-archive
-'''
-
-EXAMPLES = '''
- - name: DELETE Profile
- community.fortios.fmgr_secprof_av:
- name: "Ansible_AV_Profile"
- mode: "delete"
-
- - name: CREATE Profile
- community.fortios.fmgr_secprof_av:
- name: "Ansible_AV_Profile"
- comment: "Created by Ansible Module TEST"
- mode: "set"
- inspection_mode: "proxy"
- ftgd_analytics: "everything"
- av_block_log: "enable"
- av_virus_log: "enable"
- scan_mode: "full"
- mobile_malware_db: "enable"
- ftp_archive_block: "encrypted"
- ftp_outbreak_prevention: "files"
- ftp_archive_log: "timeout"
- ftp_emulator: "disable"
- ftp_options: "scan"
-'''
-
-RETURN = """
-api_result:
- description: full API response, includes status code and message
- returned: always
- type: str
-"""
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.connection import Connection
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import prepare_dict
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import scrub_dict
-
-###############
-# START METHODS
-###############
-
-
-def fmgr_antivirus_profile_modify(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
-
- mode = paramgram["mode"]
- adom = paramgram["adom"]
-
- response = DEFAULT_RESULT_OBJ
- # EVAL THE MODE PARAMETER FOR SET OR ADD
- if mode in ['set', 'add', 'update']:
- url = '/pm/config/adom/{adom}/obj/antivirus/profile'.format(adom=adom)
- datagram = scrub_dict(prepare_dict(paramgram))
-
- # EVAL THE MODE PARAMETER FOR DELETE
- else:
- # SET THE CORRECT URL FOR DELETE
- url = '/pm/config/adom/{adom}/obj/antivirus/profile/{name}'.format(adom=adom, name=paramgram["name"])
- datagram = {}
-
- response = fmgr.process_request(url, datagram, paramgram["mode"])
- return response
-
-#############
-# END METHODS
-#############
-
-
-def main():
- argument_spec = dict(
- adom=dict(required=False, type="str", default="root"),
- mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),
-
- scan_mode=dict(required=False, type="str", choices=["quick", "full"]),
- replacemsg_group=dict(required=False, type="dict"),
- name=dict(required=False, type="str"),
- mobile_malware_db=dict(required=False, type="str", choices=["disable", "enable"]),
- inspection_mode=dict(required=False, type="str", choices=["proxy", "flow-based"]),
- ftgd_analytics=dict(required=False, type="str", choices=["disable", "suspicious", "everything"]),
- extended_log=dict(required=False, type="str", choices=["disable", "enable"]),
- comment=dict(required=False, type="str"),
- av_virus_log=dict(required=False, type="str", choices=["disable", "enable"]),
- av_block_log=dict(required=False, type="str", choices=["disable", "enable"]),
- analytics_wl_filetype=dict(required=False, type="dict"),
- analytics_max_upload=dict(required=False, type="int"),
- analytics_db=dict(required=False, type="str", choices=["disable", "enable"]),
- analytics_bl_filetype=dict(required=False, type="dict"),
- content_disarm=dict(required=False, type="list"),
- content_disarm_cover_page=dict(required=False, type="str", choices=["disable", "enable"]),
- content_disarm_detect_only=dict(required=False, type="str", choices=["disable", "enable"]),
- content_disarm_office_embed=dict(required=False, type="str", choices=["disable", "enable"]),
- content_disarm_office_hylink=dict(required=False, type="str", choices=["disable", "enable"]),
- content_disarm_office_linked=dict(required=False, type="str", choices=["disable", "enable"]),
- content_disarm_office_macro=dict(required=False, type="str", choices=["disable", "enable"]),
- content_disarm_original_file_destination=dict(required=False, type="str", choices=["fortisandbox",
- "quarantine",
- "discard"]),
- content_disarm_pdf_act_form=dict(required=False, type="str", choices=["disable", "enable"]),
- content_disarm_pdf_act_gotor=dict(required=False, type="str", choices=["disable", "enable"]),
- content_disarm_pdf_act_java=dict(required=False, type="str", choices=["disable", "enable"]),
- content_disarm_pdf_act_launch=dict(required=False, type="str", choices=["disable", "enable"]),
- content_disarm_pdf_act_movie=dict(required=False, type="str", choices=["disable", "enable"]),
- content_disarm_pdf_act_sound=dict(required=False, type="str", choices=["disable", "enable"]),
- content_disarm_pdf_embedfile=dict(required=False, type="str", choices=["disable", "enable"]),
- content_disarm_pdf_hyperlink=dict(required=False, type="str", choices=["disable", "enable"]),
- content_disarm_pdf_javacode=dict(required=False, type="str", choices=["disable", "enable"]),
- ftp=dict(required=False, type="list"),
- ftp_archive_block=dict(required=False, type="str", choices=["encrypted",
- "corrupted",
- "multipart",
- "nested",
- "mailbomb",
- "unhandled",
- "partiallycorrupted",
- "fileslimit",
- "timeout"]),
- ftp_archive_log=dict(required=False, type="str", choices=["encrypted",
- "corrupted",
- "multipart",
- "nested",
- "mailbomb",
- "unhandled",
- "partiallycorrupted",
- "fileslimit",
- "timeout"]),
- ftp_emulator=dict(required=False, type="str", choices=["disable", "enable"]),
- ftp_options=dict(required=False, type="str", choices=["scan", "quarantine", "avmonitor"]),
- ftp_outbreak_prevention=dict(required=False, type="str", choices=["disabled", "files", "full-archive"]),
- http=dict(required=False, type="list"),
- http_archive_block=dict(required=False, type="str", choices=["encrypted",
- "corrupted",
- "multipart",
- "nested",
- "mailbomb",
- "unhandled",
- "partiallycorrupted",
- "fileslimit",
- "timeout"]),
- http_archive_log=dict(required=False, type="str", choices=["encrypted",
- "corrupted",
- "multipart",
- "nested",
- "mailbomb",
- "unhandled",
- "partiallycorrupted",
- "fileslimit",
- "timeout"]),
- http_content_disarm=dict(required=False, type="str", choices=["disable", "enable"]),
- http_emulator=dict(required=False, type="str", choices=["disable", "enable"]),
- http_options=dict(required=False, type="str", choices=["scan", "quarantine", "avmonitor"]),
- http_outbreak_prevention=dict(required=False, type="str", choices=["disabled", "files", "full-archive"]),
- imap=dict(required=False, type="list"),
- imap_archive_block=dict(required=False, type="str", choices=["encrypted",
- "corrupted",
- "multipart",
- "nested",
- "mailbomb",
- "unhandled",
- "partiallycorrupted",
- "fileslimit",
- "timeout"]),
- imap_archive_log=dict(required=False, type="str", choices=["encrypted",
- "corrupted",
- "multipart",
- "nested",
- "mailbomb",
- "unhandled",
- "partiallycorrupted",
- "fileslimit",
- "timeout"]),
- imap_content_disarm=dict(required=False, type="str", choices=["disable", "enable"]),
- imap_emulator=dict(required=False, type="str", choices=["disable", "enable"]),
- imap_executables=dict(required=False, type="str", choices=["default", "virus"]),
- imap_options=dict(required=False, type="str", choices=["scan", "quarantine", "avmonitor"]),
- imap_outbreak_prevention=dict(required=False, type="str", choices=["disabled", "files", "full-archive"]),
- mapi=dict(required=False, type="list"),
- mapi_archive_block=dict(required=False, type="str", choices=["encrypted",
- "corrupted",
- "multipart",
- "nested",
- "mailbomb",
- "unhandled",
- "partiallycorrupted",
- "fileslimit",
- "timeout"]),
- mapi_archive_log=dict(required=False, type="str", choices=["encrypted",
- "corrupted",
- "multipart",
- "nested",
- "mailbomb",
- "unhandled",
- "partiallycorrupted",
- "fileslimit",
- "timeout"]),
- mapi_emulator=dict(required=False, type="str", choices=["disable", "enable"]),
- mapi_executables=dict(required=False, type="str", choices=["default", "virus"]),
- mapi_options=dict(required=False, type="str", choices=["scan", "quarantine", "avmonitor"]),
- mapi_outbreak_prevention=dict(required=False, type="str", choices=["disabled", "files", "full-archive"]),
- nac_quar=dict(required=False, type="list"),
- nac_quar_expiry=dict(required=False, type="str"),
- nac_quar_infected=dict(required=False, type="str", choices=["none", "quar-src-ip"]),
- nac_quar_log=dict(required=False, type="str", choices=["disable", "enable"]),
- nntp=dict(required=False, type="list"),
- nntp_archive_block=dict(required=False, type="str", choices=["encrypted",
- "corrupted",
- "multipart",
- "nested",
- "mailbomb",
- "unhandled",
- "partiallycorrupted",
- "fileslimit",
- "timeout"]),
- nntp_archive_log=dict(required=False, type="str", choices=["encrypted",
- "corrupted",
- "multipart",
- "nested",
- "mailbomb",
- "unhandled",
- "partiallycorrupted",
- "fileslimit",
- "timeout"]),
- nntp_emulator=dict(required=False, type="str", choices=["disable", "enable"]),
- nntp_options=dict(required=False, type="str", choices=["scan", "quarantine", "avmonitor"]),
- nntp_outbreak_prevention=dict(required=False, type="str", choices=["disabled", "files", "full-archive"]),
- pop3=dict(required=False, type="list"),
- pop3_archive_block=dict(required=False, type="str", choices=["encrypted",
- "corrupted",
- "multipart",
- "nested",
- "mailbomb",
- "unhandled",
- "partiallycorrupted",
- "fileslimit",
- "timeout"]),
- pop3_archive_log=dict(required=False, type="str", choices=["encrypted",
- "corrupted",
- "multipart",
- "nested",
- "mailbomb",
- "unhandled",
- "partiallycorrupted",
- "fileslimit",
- "timeout"]),
- pop3_content_disarm=dict(required=False, type="str", choices=["disable", "enable"]),
- pop3_emulator=dict(required=False, type="str", choices=["disable", "enable"]),
- pop3_executables=dict(required=False, type="str", choices=["default", "virus"]),
- pop3_options=dict(required=False, type="str", choices=["scan", "quarantine", "avmonitor"]),
- pop3_outbreak_prevention=dict(required=False, type="str", choices=["disabled", "files", "full-archive"]),
- smb=dict(required=False, type="list"),
- smb_archive_block=dict(required=False, type="str", choices=["encrypted",
- "corrupted",
- "multipart",
- "nested",
- "mailbomb",
- "unhandled",
- "partiallycorrupted",
- "fileslimit",
- "timeout"]),
- smb_archive_log=dict(required=False, type="str", choices=["encrypted",
- "corrupted",
- "multipart",
- "nested",
- "mailbomb",
- "unhandled",
- "partiallycorrupted",
- "fileslimit",
- "timeout"]),
- smb_emulator=dict(required=False, type="str", choices=["disable", "enable"]),
- smb_options=dict(required=False, type="str", choices=["scan", "quarantine", "avmonitor"]),
- smb_outbreak_prevention=dict(required=False, type="str", choices=["disabled", "files", "full-archive"]),
- smtp=dict(required=False, type="list"),
- smtp_archive_block=dict(required=False, type="str", choices=["encrypted",
- "corrupted",
- "multipart",
- "nested",
- "mailbomb",
- "unhandled",
- "partiallycorrupted",
- "fileslimit",
- "timeout"]),
- smtp_archive_log=dict(required=False, type="str", choices=["encrypted",
- "corrupted",
- "multipart",
- "nested",
- "mailbomb",
- "unhandled",
- "partiallycorrupted",
- "fileslimit",
- "timeout"]),
- smtp_content_disarm=dict(required=False, type="str", choices=["disable", "enable"]),
- smtp_emulator=dict(required=False, type="str", choices=["disable", "enable"]),
- smtp_executables=dict(required=False, type="str", choices=["default", "virus"]),
- smtp_options=dict(required=False, type="str", choices=["scan", "quarantine", "avmonitor"]),
- smtp_outbreak_prevention=dict(required=False, type="str", choices=["disabled", "files", "full-archive"]),
-
- )
-
- module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
- # MODULE PARAMGRAM
- paramgram = {
- "mode": module.params["mode"],
- "adom": module.params["adom"],
- "scan-mode": module.params["scan_mode"],
- "replacemsg-group": module.params["replacemsg_group"],
- "name": module.params["name"],
- "mobile-malware-db": module.params["mobile_malware_db"],
- "inspection-mode": module.params["inspection_mode"],
- "ftgd-analytics": module.params["ftgd_analytics"],
- "extended-log": module.params["extended_log"],
- "comment": module.params["comment"],
- "av-virus-log": module.params["av_virus_log"],
- "av-block-log": module.params["av_block_log"],
- "analytics-wl-filetype": module.params["analytics_wl_filetype"],
- "analytics-max-upload": module.params["analytics_max_upload"],
- "analytics-db": module.params["analytics_db"],
- "analytics-bl-filetype": module.params["analytics_bl_filetype"],
- "content-disarm": {
- "cover-page": module.params["content_disarm_cover_page"],
- "detect-only": module.params["content_disarm_detect_only"],
- "office-embed": module.params["content_disarm_office_embed"],
- "office-hylink": module.params["content_disarm_office_hylink"],
- "office-linked": module.params["content_disarm_office_linked"],
- "office-macro": module.params["content_disarm_office_macro"],
- "original-file-destination": module.params["content_disarm_original_file_destination"],
- "pdf-act-form": module.params["content_disarm_pdf_act_form"],
- "pdf-act-gotor": module.params["content_disarm_pdf_act_gotor"],
- "pdf-act-java": module.params["content_disarm_pdf_act_java"],
- "pdf-act-launch": module.params["content_disarm_pdf_act_launch"],
- "pdf-act-movie": module.params["content_disarm_pdf_act_movie"],
- "pdf-act-sound": module.params["content_disarm_pdf_act_sound"],
- "pdf-embedfile": module.params["content_disarm_pdf_embedfile"],
- "pdf-hyperlink": module.params["content_disarm_pdf_hyperlink"],
- "pdf-javacode": module.params["content_disarm_pdf_javacode"],
- },
- "ftp": {
- "archive-block": module.params["ftp_archive_block"],
- "archive-log": module.params["ftp_archive_log"],
- "emulator": module.params["ftp_emulator"],
- "options": module.params["ftp_options"],
- "outbreak-prevention": module.params["ftp_outbreak_prevention"],
- },
- "http": {
- "archive-block": module.params["http_archive_block"],
- "archive-log": module.params["http_archive_log"],
- "content-disarm": module.params["http_content_disarm"],
- "emulator": module.params["http_emulator"],
- "options": module.params["http_options"],
- "outbreak-prevention": module.params["http_outbreak_prevention"],
- },
- "imap": {
- "archive-block": module.params["imap_archive_block"],
- "archive-log": module.params["imap_archive_log"],
- "content-disarm": module.params["imap_content_disarm"],
- "emulator": module.params["imap_emulator"],
- "executables": module.params["imap_executables"],
- "options": module.params["imap_options"],
- "outbreak-prevention": module.params["imap_outbreak_prevention"],
- },
- "mapi": {
- "archive-block": module.params["mapi_archive_block"],
- "archive-log": module.params["mapi_archive_log"],
- "emulator": module.params["mapi_emulator"],
- "executables": module.params["mapi_executables"],
- "options": module.params["mapi_options"],
- "outbreak-prevention": module.params["mapi_outbreak_prevention"],
- },
- "nac-quar": {
- "expiry": module.params["nac_quar_expiry"],
- "infected": module.params["nac_quar_infected"],
- "log": module.params["nac_quar_log"],
- },
- "nntp": {
- "archive-block": module.params["nntp_archive_block"],
- "archive-log": module.params["nntp_archive_log"],
- "emulator": module.params["nntp_emulator"],
- "options": module.params["nntp_options"],
- "outbreak-prevention": module.params["nntp_outbreak_prevention"],
- },
- "pop3": {
- "archive-block": module.params["pop3_archive_block"],
- "archive-log": module.params["pop3_archive_log"],
- "content-disarm": module.params["pop3_content_disarm"],
- "emulator": module.params["pop3_emulator"],
- "executables": module.params["pop3_executables"],
- "options": module.params["pop3_options"],
- "outbreak-prevention": module.params["pop3_outbreak_prevention"],
- },
- "smb": {
- "archive-block": module.params["smb_archive_block"],
- "archive-log": module.params["smb_archive_log"],
- "emulator": module.params["smb_emulator"],
- "options": module.params["smb_options"],
- "outbreak-prevention": module.params["smb_outbreak_prevention"],
- },
- "smtp": {
- "archive-block": module.params["smtp_archive_block"],
- "archive-log": module.params["smtp_archive_log"],
- "content-disarm": module.params["smtp_content_disarm"],
- "emulator": module.params["smtp_emulator"],
- "executables": module.params["smtp_executables"],
- "options": module.params["smtp_options"],
- "outbreak-prevention": module.params["smtp_outbreak_prevention"],
- }
- }
-
- module.paramgram = paramgram
- fmgr = None
- if module._socket_path:
- connection = Connection(module._socket_path)
- fmgr = FortiManagerHandler(connection, module)
- fmgr.tools = FMGRCommon()
- else:
- module.fail_json(**FAIL_SOCKET_MSG)
-
- list_overrides = ["content-disarm", "ftp", "http", "imap", "mapi", "nac-quar", "nntp", "pop3", "smb", "smtp"]
- paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
- paramgram=paramgram, module=module)
- module.paramgram = paramgram
-
- results = DEFAULT_RESULT_OBJ
-
- try:
- results = fmgr_antivirus_profile_modify(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
- except Exception as err:
- raise FMGBaseException(err)
-
- return module.exit_json(**results[1])
-
-
-if __name__ == "__main__":
- main()
diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_dns.py b/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_dns.py
deleted file mode 100644
index e6157ff4b..000000000
--- a/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_dns.py
+++ /dev/null
@@ -1,339 +0,0 @@
-#!/usr/bin/python
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-
-from __future__ import absolute_import, division, print_function
-
-__metaclass__ = type
-
-DOCUMENTATION = '''
----
-module: fmgr_secprof_dns
-notes:
- - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
-author:
- - Luke Weighall (@lweighall)
- - Andrew Welsh (@Ghilli3)
- - Jim Huber (@p4r4n0y1ng)
-short_description: Manage DNS security profiles in FortiManager
-description:
- - Manage DNS security profiles in FortiManager
-
-options:
- adom:
- description:
- - The ADOM the configuration should belong to.
- required: false
- default: root
-
- mode:
- description:
- - Sets one of three modes for managing the object.
- - Allows use of soft-adds instead of overwriting existing values.
- choices: ['add', 'set', 'delete', 'update']
- required: false
- default: add
-
- youtube_restrict:
- type: str
- description:
- - Set safe search for YouTube restriction level.
- - choice | strict | Enable strict safe seach for YouTube.
- - choice | moderate | Enable moderate safe search for YouTube.
- required: false
- choices: ["strict", "moderate"]
-
- sdns_ftgd_err_log:
- type: str
- description:
- - Enable/disable FortiGuard SDNS rating error logging.
- - choice | disable | Disable FortiGuard SDNS rating error logging.
- - choice | enable | Enable FortiGuard SDNS rating error logging.
- required: false
- choices: ["disable", "enable"]
-
- sdns_domain_log:
- type: str
- description:
- - Enable/disable domain filtering and botnet domain logging.
- - choice | disable | Disable domain filtering and botnet domain logging.
- - choice | enable | Enable domain filtering and botnet domain logging.
- required: false
- choices: ["disable", "enable"]
-
- safe_search:
- type: str
- description:
- - Enable/disable Google, Bing, and YouTube safe search.
- - choice | disable | Disable Google, Bing, and YouTube safe search.
- - choice | enable | Enable Google, Bing, and YouTube safe search.
- required: false
- choices: ["disable", "enable"]
-
- redirect_portal:
- type: str
- description:
- - IP address of the SDNS redirect portal.
- required: false
-
- name:
- type: str
- description:
- - Profile name.
- required: false
-
- log_all_domain:
- type: str
- description:
- - Enable/disable logging of all domains visited (detailed DNS logging).
- - choice | disable | Disable logging of all domains visited.
- - choice | enable | Enable logging of all domains visited.
- required: false
- choices: ["disable", "enable"]
-
- external_ip_blocklist:
- type: str
- description:
- - One or more external IP block lists.
- required: false
-
- comment:
- type: str
- description:
- - Comment for the security profile to show in the FortiManager GUI.
- required: false
-
- block_botnet:
- type: str
- description:
- - Enable/disable blocking botnet C&C; DNS lookups.
- - choice | disable | Disable blocking botnet C&C; DNS lookups.
- - choice | enable | Enable blocking botnet C&C; DNS lookups.
- required: false
- choices: ["disable", "enable"]
-
- block_action:
- type: str
- description:
- - Action to take for blocked domains.
- - choice | block | Return NXDOMAIN for blocked domains.
- - choice | redirect | Redirect blocked domains to SDNS portal.
- required: false
- choices: ["block", "redirect"]
-
- domain_filter_domain_filter_table:
- type: str
- description:
- - DNS domain filter table ID.
- required: false
-
- ftgd_dns_options:
- type: str
- description:
- - FortiGuard DNS filter options.
- - FLAG Based Options. Specify multiple in list form.
- - flag | error-allow | Allow all domains when FortiGuard DNS servers fail.
- - flag | ftgd-disable | Disable FortiGuard DNS domain rating.
- required: false
- choices: ["error-allow", "ftgd-disable"]
-
- ftgd_dns_filters_action:
- type: str
- description:
- - Action to take for DNS requests matching the category.
- - choice | monitor | Allow DNS requests matching the category and log the result.
- - choice | block | Block DNS requests matching the category.
- required: false
- choices: ["monitor", "block"]
-
- ftgd_dns_filters_category:
- type: str
- description:
- - Category number.
- required: false
-
- ftgd_dns_filters_log:
- type: str
- description:
- - Enable/disable DNS filter logging for this DNS profile.
- - choice | disable | Disable DNS filter logging.
- - choice | enable | Enable DNS filter logging.
- required: false
- choices: ["disable", "enable"]
-
-
-'''
-
-EXAMPLES = '''
- - name: DELETE Profile
- community.fortios.fmgr_secprof_dns:
- name: "Ansible_DNS_Profile"
- comment: "Created by Ansible Module TEST"
- mode: "delete"
-
- - name: CREATE Profile
- community.fortios.fmgr_secprof_dns:
- name: "Ansible_DNS_Profile"
- comment: "Created by Ansible Module TEST"
- mode: "set"
- block_action: "block"
-
-
-'''
-
-RETURN = """
-api_result:
- description: full API response, includes status code and message
- returned: always
- type: str
-"""
-
-from ansible.module_utils.basic import AnsibleModule, env_fallback
-from ansible.module_utils.connection import Connection
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRMethods
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import prepare_dict
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import scrub_dict
-
-
-###############
-# START METHODS
-###############
-
-
-def fmgr_dnsfilter_profile_modify(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
-
- mode = paramgram["mode"]
- adom = paramgram["adom"]
- url = ""
- datagram = {}
-
- response = DEFAULT_RESULT_OBJ
-
- # EVAL THE MODE PARAMETER FOR SET OR ADD
- if mode in ['set', 'add', 'update']:
- url = '/pm/config/adom/{adom}/obj/dnsfilter/profile'.format(adom=adom)
- datagram = scrub_dict(prepare_dict(paramgram))
-
- # EVAL THE MODE PARAMETER FOR DELETE
- elif mode == "delete":
- # SET THE CORRECT URL FOR DELETE
- url = '/pm/config/adom/{adom}/obj/dnsfilter/profile/{name}'.format(adom=adom, name=paramgram["name"])
- datagram = {}
-
- response = fmgr.process_request(url, datagram, paramgram["mode"])
-
- return response
-
-
-#############
-# END METHODS
-#############
-
-
-def main():
- argument_spec = dict(
- adom=dict(type="str", default="root"),
- mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),
-
- youtube_restrict=dict(required=False, type="str", choices=["strict", "moderate"]),
- sdns_ftgd_err_log=dict(required=False, type="str", choices=["disable", "enable"]),
- sdns_domain_log=dict(required=False, type="str", choices=["disable", "enable"]),
- safe_search=dict(required=False, type="str", choices=["disable", "enable"]),
- redirect_portal=dict(required=False, type="str"),
- name=dict(required=False, type="str"),
- log_all_domain=dict(required=False, type="str", choices=["disable", "enable"]),
- external_ip_blocklist=dict(required=False, type="str"),
- comment=dict(required=False, type="str"),
- block_botnet=dict(required=False, type="str", choices=["disable", "enable"]),
- block_action=dict(required=False, type="str", choices=["block", "redirect"]),
-
- domain_filter_domain_filter_table=dict(required=False, type="str"),
-
- ftgd_dns_options=dict(required=False, type="str", choices=["error-allow", "ftgd-disable"]),
-
- ftgd_dns_filters_action=dict(required=False, type="str", choices=["monitor", "block"]),
- ftgd_dns_filters_category=dict(required=False, type="str"),
- ftgd_dns_filters_log=dict(required=False, type="str", choices=["disable", "enable"]),
-
- )
-
- module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
- # MODULE PARAMGRAM
- paramgram = {
- "mode": module.params["mode"],
- "adom": module.params["adom"],
- "youtube-restrict": module.params["youtube_restrict"],
- "sdns-ftgd-err-log": module.params["sdns_ftgd_err_log"],
- "sdns-domain-log": module.params["sdns_domain_log"],
- "safe-search": module.params["safe_search"],
- "redirect-portal": module.params["redirect_portal"],
- "name": module.params["name"],
- "log-all-domain": module.params["log_all_domain"],
- "external-ip-blocklist": module.params["external_ip_blocklist"],
- "comment": module.params["comment"],
- "block-botnet": module.params["block_botnet"],
- "block-action": module.params["block_action"],
- "domain-filter": {
- "domain-filter-table": module.params["domain_filter_domain_filter_table"],
- },
- "ftgd-dns": {
- "options": module.params["ftgd_dns_options"],
- "filters": {
- "action": module.params["ftgd_dns_filters_action"],
- "category": module.params["ftgd_dns_filters_category"],
- "log": module.params["ftgd_dns_filters_log"],
- }
- }
- }
-
- module.paramgram = paramgram
- fmgr = None
- if module._socket_path:
- connection = Connection(module._socket_path)
- fmgr = FortiManagerHandler(connection, module)
- fmgr.tools = FMGRCommon()
- else:
- module.fail_json(**FAIL_SOCKET_MSG)
-
- results = DEFAULT_RESULT_OBJ
-
- try:
- results = fmgr_dnsfilter_profile_modify(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
-
- except Exception as err:
- raise FMGBaseException(err)
-
- return module.exit_json(**results[1])
-
-
-if __name__ == "__main__":
- main()
diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_ips.py b/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_ips.py
deleted file mode 100644
index 4b5f8996c..000000000
--- a/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_ips.py
+++ /dev/null
@@ -1,664 +0,0 @@
-#!/usr/bin/python
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-
-from __future__ import absolute_import, division, print_function
-
-__metaclass__ = type
-
-DOCUMENTATION = '''
----
-module: fmgr_secprof_ips
-notes:
- - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
-author:
- - Luke Weighall (@lweighall)
- - Andrew Welsh (@Ghilli3)
- - Jim Huber (@p4r4n0y1ng)
-short_description: Managing IPS security profiles in FortiManager
-description:
- - Managing IPS security profiles in FortiManager
-
-options:
- adom:
- description:
- - The ADOM the configuration should belong to.
- required: false
- default: root
-
- mode:
- description:
- - Sets one of three modes for managing the object.
- - Allows use of soft-adds instead of overwriting existing values
- choices: ['add', 'set', 'delete', 'update']
- required: false
- default: add
-
- replacemsg_group:
- description:
- - Replacement message group.
- required: false
-
- name:
- description:
- - Sensor name.
- required: false
-
- extended_log:
- description:
- - Enable/disable extended logging.
- required: false
- choices:
- - disable
- - enable
-
- comment:
- description:
- - Comment.
- required: false
-
- block_malicious_url:
- description:
- - Enable/disable malicious URL blocking.
- required: false
- choices:
- - disable
- - enable
-
- entries:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- entries_action:
- description:
- - Action taken with traffic in which signatures are detected.
- required: false
- choices:
- - pass
- - block
- - reset
- - default
-
- entries_application:
- description:
- - Applications to be protected. set application ? lists available applications. all includes
- all applications. other includes all unlisted applications.
- required: false
-
- entries_location:
- description:
- - Protect client or server traffic.
- required: false
-
- entries_log:
- description:
- - Enable/disable logging of signatures included in filter.
- required: false
- choices:
- - disable
- - enable
-
- entries_log_attack_context:
- description:
- - Enable/disable logging of attack context| URL buffer, header buffer, body buffer, packet buffer.
- required: false
- choices:
- - disable
- - enable
-
- entries_log_packet:
- description:
- - Enable/disable packet logging. Enable to save the packet that triggers the filter. You can
- download the packets in pcap format for diagnostic use.
- required: false
- choices:
- - disable
- - enable
-
- entries_os:
- description:
- - Operating systems to be protected. all includes all operating systems. other includes all
- unlisted operating systems.
- required: false
-
- entries_protocol:
- description:
- - Protocols to be examined. set protocol ? lists available protocols. all includes all protocols.
- other includes all unlisted protocols.
- required: false
-
- entries_quarantine:
- description:
- - Quarantine method.
- required: false
- choices:
- - none
- - attacker
-
- entries_quarantine_expiry:
- description:
- - Duration of quarantine.
- required: false
-
- entries_quarantine_log:
- description:
- - Enable/disable quarantine logging.
- required: false
- choices:
- - disable
- - enable
-
- entries_rate_count:
- description:
- - Count of the rate.
- required: false
-
- entries_rate_duration:
- description:
- - Duration (sec) of the rate.
- required: false
-
- entries_rate_mode:
- description:
- - Rate limit mode.
- required: false
- choices:
- - periodical
- - continuous
-
- entries_rate_track:
- description:
- - Track the packet protocol field.
- required: false
- choices:
- - none
- - src-ip
- - dest-ip
- - dhcp-client-mac
- - dns-domain
-
- entries_rule:
- description:
- - Identifies the predefined or custom IPS signatures to add to the sensor.
- required: false
-
- entries_severity:
- description:
- - Relative severity of the signature, from info to critical. Log messages generated by the signature
- include the severity.
- required: false
-
- entries_status:
- description:
- - Status of the signatures included in filter. default enables the filter and only use filters
- with default status of enable. Filters with default status of disable will not be used.
- required: false
- choices:
- - disable
- - enable
- - default
-
- entries_exempt_ip_dst_ip:
- description:
- - Destination IP address and netmask.
- required: false
-
- entries_exempt_ip_src_ip:
- description:
- - Source IP address and netmask.
- required: false
-
- filter:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- filter_action:
- description:
- - Action of selected rules.
- required: false
- choices:
- - pass
- - block
- - default
- - reset
-
- filter_application:
- description:
- - Vulnerable application filter.
- required: false
-
- filter_location:
- description:
- - Vulnerability location filter.
- required: false
-
- filter_log:
- description:
- - Enable/disable logging of selected rules.
- required: false
- choices:
- - disable
- - enable
-
- filter_log_packet:
- description:
- - Enable/disable packet logging of selected rules.
- required: false
- choices:
- - disable
- - enable
-
- filter_name:
- description:
- - Filter name.
- required: false
-
- filter_os:
- description:
- - Vulnerable OS filter.
- required: false
-
- filter_protocol:
- description:
- - Vulnerable protocol filter.
- required: false
-
- filter_quarantine:
- description:
- - Quarantine IP or interface.
- required: false
- choices:
- - none
- - attacker
-
- filter_quarantine_expiry:
- description:
- - Duration of quarantine in minute.
- required: false
-
- filter_quarantine_log:
- description:
- - Enable/disable logging of selected quarantine.
- required: false
- choices:
- - disable
- - enable
-
- filter_severity:
- description:
- - Vulnerability severity filter.
- required: false
-
- filter_status:
- description:
- - Selected rules status.
- required: false
- choices:
- - disable
- - enable
- - default
-
- override:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- override_action:
- description:
- - Action of override rule.
- required: false
- choices:
- - pass
- - block
- - reset
-
- override_log:
- description:
- - Enable/disable logging.
- required: false
- choices:
- - disable
- - enable
-
- override_log_packet:
- description:
- - Enable/disable packet logging.
- required: false
- choices:
- - disable
- - enable
-
- override_quarantine:
- description:
- - Quarantine IP or interface.
- required: false
- choices:
- - none
- - attacker
-
- override_quarantine_expiry:
- description:
- - Duration of quarantine in minute.
- required: false
-
- override_quarantine_log:
- description:
- - Enable/disable logging of selected quarantine.
- required: false
- choices:
- - disable
- - enable
-
- override_rule_id:
- description:
- - Override rule ID.
- required: false
-
- override_status:
- description:
- - Enable/disable status of override rule.
- required: false
- choices:
- - disable
- - enable
-
- override_exempt_ip_dst_ip:
- description:
- - Destination IP address and netmask.
- required: false
-
- override_exempt_ip_src_ip:
- description:
- - Source IP address and netmask.
- required: false
-'''
-
-EXAMPLES = '''
- - name: DELETE Profile
- community.fortios.fmgr_secprof_ips:
- name: "Ansible_IPS_Profile"
- comment: "Created by Ansible Module TEST"
- mode: "delete"
-
- - name: CREATE Profile
- community.fortios.fmgr_secprof_ips:
- name: "Ansible_IPS_Profile"
- comment: "Created by Ansible Module TEST"
- mode: "set"
- block_malicious_url: "enable"
- entries: [{severity: "high", action: "block", log-packet: "enable"}, {severity: "medium", action: "pass"}]
-'''
-
-RETURN = """
-api_result:
- description: full API response, includes status code and message
- returned: always
- type: str
-"""
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.connection import Connection
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import prepare_dict
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import scrub_dict
-
-
-###############
-# START METHODS
-###############
-
-
-def fmgr_ips_sensor_modify(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
-
- mode = paramgram["mode"]
- adom = paramgram["adom"]
- # INIT A BASIC OBJECTS
- response = DEFAULT_RESULT_OBJ
- url = ""
- datagram = {}
-
- # EVAL THE MODE PARAMETER FOR SET OR ADD
- if mode in ['set', 'add', 'update']:
- url = '/pm/config/adom/{adom}/obj/ips/sensor'.format(adom=adom)
- datagram = scrub_dict(prepare_dict(paramgram))
-
- # EVAL THE MODE PARAMETER FOR DELETE
- elif mode == "delete":
- # SET THE CORRECT URL FOR DELETE
- url = '/pm/config/adom/{adom}/obj/ips/sensor/{name}'.format(
- adom=adom, name=paramgram["name"])
- datagram = {}
-
- response = fmgr.process_request(url, datagram, paramgram["mode"])
-
- return response
-
-
-#############
-# END METHODS
-#############
-
-
-def main():
- argument_spec = dict(
- adom=dict(type="str", default="root"),
- mode=dict(choices=["add", "set", "delete", "update"],
- type="str", default="add"),
-
- replacemsg_group=dict(required=False, type="str"),
- name=dict(required=False, type="str"),
- extended_log=dict(required=False, type="str",
- choices=["disable", "enable"]),
- comment=dict(required=False, type="str"),
- block_malicious_url=dict(required=False, type="str", choices=[
- "disable", "enable"]),
- entries=dict(required=False, type="list"),
- entries_action=dict(required=False, type="str", choices=[
- "pass", "block", "reset", "default"]),
- entries_application=dict(required=False, type="str"),
- entries_location=dict(required=False, type="str"),
- entries_log=dict(required=False, type="str",
- choices=["disable", "enable"]),
- entries_log_attack_context=dict(
- required=False, type="str", choices=["disable", "enable"]),
- entries_log_packet=dict(required=False, type="str", choices=[
- "disable", "enable"]),
- entries_os=dict(required=False, type="str"),
- entries_protocol=dict(required=False, type="str"),
- entries_quarantine=dict(required=False, type="str", choices=[
- "none", "attacker"]),
- entries_quarantine_expiry=dict(required=False, type="str"),
- entries_quarantine_log=dict(
- required=False, type="str", choices=["disable", "enable"]),
- entries_rate_count=dict(required=False, type="int"),
- entries_rate_duration=dict(required=False, type="int"),
- entries_rate_mode=dict(required=False, type="str", choices=[
- "periodical", "continuous"]),
- entries_rate_track=dict(required=False, type="str",
- choices=["none", "src-ip", "dest-ip", "dhcp-client-mac", "dns-domain"]),
- entries_rule=dict(required=False, type="str"),
- entries_severity=dict(required=False, type="str"),
- entries_status=dict(required=False, type="str", choices=[
- "disable", "enable", "default"]),
-
- entries_exempt_ip_dst_ip=dict(required=False, type="str"),
- entries_exempt_ip_src_ip=dict(required=False, type="str"),
- filter=dict(required=False, type="list"),
- filter_action=dict(required=False, type="str", choices=[
- "pass", "block", "default", "reset"]),
- filter_application=dict(required=False, type="str"),
- filter_location=dict(required=False, type="str"),
- filter_log=dict(required=False, type="str",
- choices=["disable", "enable"]),
- filter_log_packet=dict(required=False, type="str",
- choices=["disable", "enable"]),
- filter_name=dict(required=False, type="str"),
- filter_os=dict(required=False, type="str"),
- filter_protocol=dict(required=False, type="str"),
- filter_quarantine=dict(required=False, type="str",
- choices=["none", "attacker"]),
- filter_quarantine_expiry=dict(required=False, type="int"),
- filter_quarantine_log=dict(required=False, type="str", choices=[
- "disable", "enable"]),
- filter_severity=dict(required=False, type="str"),
- filter_status=dict(required=False, type="str", choices=[
- "disable", "enable", "default"]),
- override=dict(required=False, type="list"),
- override_action=dict(required=False, type="str",
- choices=["pass", "block", "reset"]),
- override_log=dict(required=False, type="str",
- choices=["disable", "enable"]),
- override_log_packet=dict(required=False, type="str", choices=[
- "disable", "enable"]),
- override_quarantine=dict(required=False, type="str", choices=[
- "none", "attacker"]),
- override_quarantine_expiry=dict(required=False, type="int"),
- override_quarantine_log=dict(
- required=False, type="str", choices=["disable", "enable"]),
- override_rule_id=dict(required=False, type="str"),
- override_status=dict(required=False, type="str",
- choices=["disable", "enable"]),
-
- override_exempt_ip_dst_ip=dict(required=False, type="str"),
- override_exempt_ip_src_ip=dict(required=False, type="str"),
-
- )
-
- module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
- # MODULE PARAMGRAM
- paramgram = {
- "mode": module.params["mode"],
- "adom": module.params["adom"],
- "replacemsg-group": module.params["replacemsg_group"],
- "name": module.params["name"],
- "extended-log": module.params["extended_log"],
- "comment": module.params["comment"],
- "block-malicious-url": module.params["block_malicious_url"],
- "entries": {
- "action": module.params["entries_action"],
- "application": module.params["entries_application"],
- "location": module.params["entries_location"],
- "log": module.params["entries_log"],
- "log-attack-context": module.params["entries_log_attack_context"],
- "log-packet": module.params["entries_log_packet"],
- "os": module.params["entries_os"],
- "protocol": module.params["entries_protocol"],
- "quarantine": module.params["entries_quarantine"],
- "quarantine-expiry": module.params["entries_quarantine_expiry"],
- "quarantine-log": module.params["entries_quarantine_log"],
- "rate-count": module.params["entries_rate_count"],
- "rate-duration": module.params["entries_rate_duration"],
- "rate-mode": module.params["entries_rate_mode"],
- "rate-track": module.params["entries_rate_track"],
- "rule": module.params["entries_rule"],
- "severity": module.params["entries_severity"],
- "status": module.params["entries_status"],
- "exempt-ip": {
- "dst-ip": module.params["entries_exempt_ip_dst_ip"],
- "src-ip": module.params["entries_exempt_ip_src_ip"],
- },
- },
- "filter": {
- "action": module.params["filter_action"],
- "application": module.params["filter_application"],
- "location": module.params["filter_location"],
- "log": module.params["filter_log"],
- "log-packet": module.params["filter_log_packet"],
- "name": module.params["filter_name"],
- "os": module.params["filter_os"],
- "protocol": module.params["filter_protocol"],
- "quarantine": module.params["filter_quarantine"],
- "quarantine-expiry": module.params["filter_quarantine_expiry"],
- "quarantine-log": module.params["filter_quarantine_log"],
- "severity": module.params["filter_severity"],
- "status": module.params["filter_status"],
- },
- "override": {
- "action": module.params["override_action"],
- "log": module.params["override_log"],
- "log-packet": module.params["override_log_packet"],
- "quarantine": module.params["override_quarantine"],
- "quarantine-expiry": module.params["override_quarantine_expiry"],
- "quarantine-log": module.params["override_quarantine_log"],
- "rule-id": module.params["override_rule_id"],
- "status": module.params["override_status"],
- "exempt-ip": {
- "dst-ip": module.params["override_exempt_ip_dst_ip"],
- "src-ip": module.params["override_exempt_ip_src_ip"],
- }
- }
- }
- module.paramgram = paramgram
- fmgr = None
- if module._socket_path:
- connection = Connection(module._socket_path)
- fmgr = FortiManagerHandler(connection, module)
- fmgr.tools = FMGRCommon()
- else:
- module.fail_json(**FAIL_SOCKET_MSG)
-
- list_overrides = ['entries', 'filter', 'override']
-
- paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
- paramgram=paramgram, module=module)
-
- results = DEFAULT_RESULT_OBJ
- try:
- results = fmgr_ips_sensor_modify(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
-
- except Exception as err:
- raise FMGBaseException(err)
-
- return module.exit_json(**results[1])
-
-
-if __name__ == "__main__":
- main()
diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_profile_group.py b/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_profile_group.py
deleted file mode 100644
index 4c65abf5b..000000000
--- a/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_profile_group.py
+++ /dev/null
@@ -1,287 +0,0 @@
-#!/usr/bin/python
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-DOCUMENTATION = '''
----
-module: fmgr_secprof_profile_group
-notes:
- - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
-author:
- - Luke Weighall (@lweighall)
- - Andrew Welsh (@Ghilli3)
- - Jim Huber (@p4r4n0y1ng)
-short_description: Manage security profiles within FortiManager
-description:
- - Manage security profile group which allows you to create a group of security profiles and apply that to a policy.
-
-options:
- adom:
- description:
- - The ADOM the configuration should belong to.
- required: false
- default: root
-
- mode:
- description:
- - Sets one of three modes for managing the object.
- - Allows use of soft-adds instead of overwriting existing values.
- choices: ['add', 'set', 'delete', 'update']
- required: false
- default: add
-
- webfilter_profile:
- type: str
- description:
- - Name of an existing Web filter profile.
- required: false
-
- waf_profile:
- type: str
- description:
- - Name of an existing Web application firewall profile.
- required: false
-
- voip_profile:
- type: str
- description:
- - Name of an existing VoIP profile.
- required: false
-
- ssl_ssh_profile:
- type: str
- description:
- - Name of an existing SSL SSH profile.
- required: false
-
- ssh_filter_profile:
- type: str
- description:
- - Name of an existing SSH filter profile.
- required: false
-
- spamfilter_profile:
- type: str
- description:
- - Name of an existing Spam filter profile.
- required: false
-
- profile_protocol_options:
- type: str
- description:
- - Name of an existing Protocol options profile.
- required: false
-
- name:
- type: str
- description:
- - Profile group name.
- required: false
-
- mms_profile:
- type: str
- description:
- - Name of an existing MMS profile.
- required: false
-
- ips_sensor:
- type: str
- description:
- - Name of an existing IPS sensor.
- required: false
-
- icap_profile:
- type: str
- description:
- - Name of an existing ICAP profile.
- required: false
-
- dnsfilter_profile:
- type: str
- description:
- - Name of an existing DNS filter profile.
- required: false
-
- dlp_sensor:
- type: str
- description:
- - Name of an existing DLP sensor.
- required: false
-
- av_profile:
- type: str
- description:
- - Name of an existing Antivirus profile.
- required: false
-
- application_list:
- type: str
- description:
- - Name of an existing Application list.
- required: false
-
-
-'''
-
-EXAMPLES = '''
- - name: DELETE Profile
- community.fortios.fmgr_secprof_profile_group:
- name: "Ansible_TEST_Profile_Group"
- mode: "delete"
-
- - name: CREATE Profile
- community.fortios.fmgr_secprof_profile_group:
- name: "Ansible_TEST_Profile_Group"
- mode: "set"
- av_profile: "Ansible_AV_Profile"
- profile_protocol_options: "default"
-'''
-
-RETURN = """
-api_result:
- description: full API response, includes status code and message
- returned: always
- type: str
-"""
-
-from ansible.module_utils.basic import AnsibleModule, env_fallback
-from ansible.module_utils.connection import Connection
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRMethods
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import prepare_dict
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import scrub_dict
-
-
-###############
-# START METHODS
-###############
-
-
-def fmgr_firewall_profile_group_modify(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
-
- mode = paramgram["mode"]
- adom = paramgram["adom"]
- url = ""
- datagram = {}
-
- response = DEFAULT_RESULT_OBJ
-
- # EVAL THE MODE PARAMETER FOR SET OR ADD
- if mode in ['set', 'add', 'update']:
- url = '/pm/config/adom/{adom}/obj/firewall/profile-group'.format(adom=adom)
- datagram = scrub_dict(prepare_dict(paramgram))
-
- # EVAL THE MODE PARAMETER FOR DELETE
- elif mode == "delete":
- # SET THE CORRECT URL FOR DELETE
- url = '/pm/config/adom/{adom}/obj/firewall/profile-group/{name}'.format(adom=adom, name=paramgram["name"])
- datagram = {}
-
- response = fmgr.process_request(url, datagram, paramgram["mode"])
-
- return response
-
-
-#############
-# END METHODS
-#############
-
-
-def main():
- argument_spec = dict(
- adom=dict(type="str", default="root"),
- mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),
-
- webfilter_profile=dict(required=False, type="str"),
- waf_profile=dict(required=False, type="str"),
- voip_profile=dict(required=False, type="str"),
- ssl_ssh_profile=dict(required=False, type="str"),
- ssh_filter_profile=dict(required=False, type="str"),
- spamfilter_profile=dict(required=False, type="str"),
- profile_protocol_options=dict(required=False, type="str"),
- name=dict(required=False, type="str"),
- mms_profile=dict(required=False, type="str"),
- ips_sensor=dict(required=False, type="str"),
- icap_profile=dict(required=False, type="str"),
- dnsfilter_profile=dict(required=False, type="str"),
- dlp_sensor=dict(required=False, type="str"),
- av_profile=dict(required=False, type="str"),
- application_list=dict(required=False, type="str"),
-
- )
-
- module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
- # MODULE PARAMGRAM
- paramgram = {
- "mode": module.params["mode"],
- "adom": module.params["adom"],
- "webfilter-profile": module.params["webfilter_profile"],
- "waf-profile": module.params["waf_profile"],
- "voip-profile": module.params["voip_profile"],
- "ssl-ssh-profile": module.params["ssl_ssh_profile"],
- "ssh-filter-profile": module.params["ssh_filter_profile"],
- "spamfilter-profile": module.params["spamfilter_profile"],
- "profile-protocol-options": module.params["profile_protocol_options"],
- "name": module.params["name"],
- "mms-profile": module.params["mms_profile"],
- "ips-sensor": module.params["ips_sensor"],
- "icap-profile": module.params["icap_profile"],
- "dnsfilter-profile": module.params["dnsfilter_profile"],
- "dlp-sensor": module.params["dlp_sensor"],
- "av-profile": module.params["av_profile"],
- "application-list": module.params["application_list"],
-
- }
- module.paramgram = paramgram
- fmgr = None
- if module._socket_path:
- connection = Connection(module._socket_path)
- fmgr = FortiManagerHandler(connection, module)
- fmgr.tools = FMGRCommon()
- else:
- module.fail_json(**FAIL_SOCKET_MSG)
-
- results = DEFAULT_RESULT_OBJ
-
- try:
- results = fmgr_firewall_profile_group_modify(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
-
- except Exception as err:
- raise FMGBaseException(err)
-
- return module.exit_json(**results[1])
-
-
-if __name__ == "__main__":
- main()
diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_proxy.py b/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_proxy.py
deleted file mode 100644
index 1b3ce8d13..000000000
--- a/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_proxy.py
+++ /dev/null
@@ -1,332 +0,0 @@
-#!/usr/bin/python
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-DOCUMENTATION = '''
----
-module: fmgr_secprof_proxy
-notes:
- - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
-author:
- - Luke Weighall (@lweighall)
- - Andrew Welsh (@Ghilli3)
- - Jim Huber (@p4r4n0y1ng)
-short_description: Manage proxy security profiles in FortiManager
-description:
- - Manage proxy security profiles for FortiGates via FortiManager using the FMG API with playbooks
-
-options:
- adom:
- description:
- - The ADOM the configuration should belong to.
- required: false
- default: root
-
- mode:
- description:
- - Sets one of three modes for managing the object.
- - Allows use of soft-adds instead of overwriting existing values
- choices: ['add', 'set', 'delete', 'update']
- required: false
- default: add
-
- strip_encoding:
- description:
- - Enable/disable stripping unsupported encoding from the request header.
- - choice | disable | Disable stripping of unsupported encoding from the request header.
- - choice | enable | Enable stripping of unsupported encoding from the request header.
- required: false
- choices: ["disable", "enable"]
-
- name:
- description:
- - Profile name.
- required: false
-
- log_header_change:
- description:
- - Enable/disable logging HTTP header changes.
- - choice | disable | Disable Enable/disable logging HTTP header changes.
- - choice | enable | Enable Enable/disable logging HTTP header changes.
- required: false
- choices: ["disable", "enable"]
-
- header_x_forwarded_for:
- description:
- - Action to take on the HTTP x-forwarded-for header in forwarded requests| forwards (pass), adds, or removes the
- - HTTP header.
- - choice | pass | Forward the same HTTP header.
- - choice | add | Add the HTTP header.
- - choice | remove | Remove the HTTP header.
- required: false
- choices: ["pass", "add", "remove"]
-
- header_x_authenticated_user:
- description:
- - Action to take on the HTTP x-authenticated-user header in forwarded requests| forwards (pass), adds, or remove
- - s the HTTP header.
- - choice | pass | Forward the same HTTP header.
- - choice | add | Add the HTTP header.
- - choice | remove | Remove the HTTP header.
- required: false
- choices: ["pass", "add", "remove"]
-
- header_x_authenticated_groups:
- description:
- - Action to take on the HTTP x-authenticated-groups header in forwarded requests| forwards (pass), adds, or remo
- - ves the HTTP header.
- - choice | pass | Forward the same HTTP header.
- - choice | add | Add the HTTP header.
- - choice | remove | Remove the HTTP header.
- required: false
- choices: ["pass", "add", "remove"]
-
- header_via_response:
- description:
- - Action to take on the HTTP via header in forwarded responses| forwards (pass), adds, or removes the HTTP heade
- - r.
- - choice | pass | Forward the same HTTP header.
- - choice | add | Add the HTTP header.
- - choice | remove | Remove the HTTP header.
- required: false
- choices: ["pass", "add", "remove"]
-
- header_via_request:
- description:
- - Action to take on the HTTP via header in forwarded requests| forwards (pass), adds, or removes the HTTP header
- - .
- - choice | pass | Forward the same HTTP header.
- - choice | add | Add the HTTP header.
- - choice | remove | Remove the HTTP header.
- required: false
- choices: ["pass", "add", "remove"]
-
- header_front_end_https:
- description:
- - Action to take on the HTTP front-end-HTTPS header in forwarded requests| forwards (pass), adds, or removes the
- - HTTP header.
- - choice | pass | Forward the same HTTP header.
- - choice | add | Add the HTTP header.
- - choice | remove | Remove the HTTP header.
- required: false
- choices: ["pass", "add", "remove"]
-
- header_client_ip:
- description:
- - Actions to take on the HTTP client-IP header in forwarded requests| forwards (pass), adds, or removes the HTTP
- - header.
- - choice | pass | Forward the same HTTP header.
- - choice | add | Add the HTTP header.
- - choice | remove | Remove the HTTP header.
- required: false
- choices: ["pass", "add", "remove"]
-
- headers:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- headers_action:
- description:
- - Action when HTTP the header forwarded.
- - choice | add-to-request | Add the HTTP header to request.
- - choice | add-to-response | Add the HTTP header to response.
- - choice | remove-from-request | Remove the HTTP header from request.
- - choice | remove-from-response | Remove the HTTP header from response.
- required: false
- choices: ["add-to-request", "add-to-response", "remove-from-request", "remove-from-response"]
-
- headers_content:
- description:
- - HTTP header's content.
- required: false
-
- headers_name:
- description:
- - HTTP forwarded header name.
- required: false
-
-
-'''
-
-EXAMPLES = '''
- - name: DELETE Profile
- community.fortios.fmgr_secprof_proxy:
- name: "Ansible_Web_Proxy_Profile"
- mode: "delete"
-
- - name: CREATE Profile
- community.fortios.fmgr_secprof_proxy:
- name: "Ansible_Web_Proxy_Profile"
- mode: "set"
- header_client_ip: "pass"
- header_front_end_https: "add"
- header_via_request: "remove"
- header_via_response: "pass"
- header_x_authenticated_groups: "add"
- header_x_authenticated_user: "remove"
- strip_encoding: "enable"
- log_header_change: "enable"
- header_x_forwarded_for: "pass"
- headers_action: "add-to-request"
- headers_content: "test"
- headers_name: "test_header"
-'''
-
-RETURN = """
-api_result:
- description: full API response, includes status code and message
- returned: always
- type: str
-"""
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.connection import Connection
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import prepare_dict
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import scrub_dict
-
-
-###############
-# START METHODS
-###############
-
-
-def fmgr_web_proxy_profile_modify(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
-
- mode = paramgram["mode"]
- adom = paramgram["adom"]
-
- response = DEFAULT_RESULT_OBJ
- url = ""
- datagram = {}
-
- # EVAL THE MODE PARAMETER FOR SET OR ADD
- if mode in ['set', 'add', 'update']:
- url = '/pm/config/adom/{adom}/obj/web-proxy/profile'.format(adom=adom)
- datagram = scrub_dict(prepare_dict(paramgram))
-
- # EVAL THE MODE PARAMETER FOR DELETE
- elif mode == "delete":
- # SET THE CORRECT URL FOR DELETE
- url = '/pm/config/adom/{adom}/obj/web-proxy/profile/{name}'.format(adom=adom, name=paramgram["name"])
- datagram = {}
-
- response = fmgr.process_request(url, datagram, paramgram["mode"])
-
- return response
-
-
-#############
-# END METHODS
-#############
-
-
-def main():
- argument_spec = dict(
- adom=dict(type="str", default="root"),
- mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),
-
- strip_encoding=dict(required=False, type="str", choices=["disable", "enable"]),
- name=dict(required=False, type="str"),
- log_header_change=dict(required=False, type="str", choices=["disable", "enable"]),
- header_x_forwarded_for=dict(required=False, type="str", choices=["pass", "add", "remove"]),
- header_x_authenticated_user=dict(required=False, type="str", choices=["pass", "add", "remove"]),
- header_x_authenticated_groups=dict(required=False, type="str", choices=["pass", "add", "remove"]),
- header_via_response=dict(required=False, type="str", choices=["pass", "add", "remove"]),
- header_via_request=dict(required=False, type="str", choices=["pass", "add", "remove"]),
- header_front_end_https=dict(required=False, type="str", choices=["pass", "add", "remove"]),
- header_client_ip=dict(required=False, type="str", choices=["pass", "add", "remove"]),
- headers=dict(required=False, type="list"),
- headers_action=dict(required=False, type="str", choices=["add-to-request", "add-to-response",
- "remove-from-request", "remove-from-response"]),
- headers_content=dict(required=False, type="str"),
- headers_name=dict(required=False, type="str"),
-
- )
-
- module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
- # MODULE PARAMGRAM
- paramgram = {
- "mode": module.params["mode"],
- "adom": module.params["adom"],
- "strip-encoding": module.params["strip_encoding"],
- "name": module.params["name"],
- "log-header-change": module.params["log_header_change"],
- "header-x-forwarded-for": module.params["header_x_forwarded_for"],
- "header-x-authenticated-user": module.params["header_x_authenticated_user"],
- "header-x-authenticated-groups": module.params["header_x_authenticated_groups"],
- "header-via-response": module.params["header_via_response"],
- "header-via-request": module.params["header_via_request"],
- "header-front-end-https": module.params["header_front_end_https"],
- "header-client-ip": module.params["header_client_ip"],
- "headers": {
- "action": module.params["headers_action"],
- "content": module.params["headers_content"],
- "name": module.params["headers_name"],
- }
- }
-
- module.paramgram = paramgram
- fmgr = None
- if module._socket_path:
- connection = Connection(module._socket_path)
- fmgr = FortiManagerHandler(connection, module)
- fmgr.tools = FMGRCommon()
- else:
- module.fail_json(**FAIL_SOCKET_MSG)
-
- list_overrides = ['headers']
- paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
- paramgram=paramgram, module=module)
- module.paramgram = paramgram
-
- results = DEFAULT_RESULT_OBJ
- try:
- results = fmgr_web_proxy_profile_modify(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
-
- except Exception as err:
- raise FMGBaseException(err)
-
- return module.exit_json(**results[1])
-
-
-if __name__ == "__main__":
- main()
diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_spam.py b/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_spam.py
deleted file mode 100644
index ac5e918a8..000000000
--- a/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_spam.py
+++ /dev/null
@@ -1,607 +0,0 @@
-#!/usr/bin/python
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-DOCUMENTATION = '''
----
-module: fmgr_secprof_spam
-notes:
- - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
-author:
- - Luke Weighall (@lweighall)
- - Andrew Welsh (@Ghilli3)
- - Jim Huber (@p4r4n0y1ng)
-short_description: spam filter profile for FMG
-description:
- - Manage spam filter security profiles within FortiManager via API
-
-options:
- adom:
- description:
- - The ADOM the configuration should belong to.
- required: false
- default: root
-
- mode:
- description:
- - Sets one of three modes for managing the object.
- - Allows use of soft-adds instead of overwriting existing values
- choices: ['add', 'set', 'delete', 'update']
- required: false
- default: add
-
- spam_rbl_table:
- description:
- - Anti-spam DNSBL table ID.
- required: false
-
- spam_mheader_table:
- description:
- - Anti-spam MIME header table ID.
- required: false
-
- spam_log_fortiguard_response:
- description:
- - Enable/disable logging FortiGuard spam response.
- required: false
- choices:
- - disable
- - enable
-
- spam_log:
- description:
- - Enable/disable spam logging for email filtering.
- required: false
- choices:
- - disable
- - enable
-
- spam_iptrust_table:
- description:
- - Anti-spam IP trust table ID.
- required: false
-
- spam_filtering:
- description:
- - Enable/disable spam filtering.
- required: false
- choices:
- - disable
- - enable
-
- spam_bword_threshold:
- description:
- - Spam banned word threshold.
- required: false
-
- spam_bword_table:
- description:
- - Anti-spam banned word table ID.
- required: false
-
- spam_bwl_table:
- description:
- - Anti-spam black/white list table ID.
- required: false
-
- replacemsg_group:
- description:
- - Replacement message group.
- required: false
-
- options:
- description:
- - None
- - FLAG Based Options. Specify multiple in list form.
- required: false
- choices:
- - bannedword
- - spamfsip
- - spamfssubmit
- - spamfschksum
- - spamfsurl
- - spamhelodns
- - spamraddrdns
- - spamrbl
- - spamhdrcheck
- - spamfsphish
- - spambwl
-
- name:
- description:
- - Profile name.
- required: false
-
- flow_based:
- description:
- - Enable/disable flow-based spam filtering.
- required: false
- choices:
- - disable
- - enable
-
- external:
- description:
- - Enable/disable external Email inspection.
- required: false
- choices:
- - disable
- - enable
-
- comment:
- description:
- - Comment.
- required: false
-
- gmail:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- gmail_log:
- description:
- - Enable/disable logging.
- required: false
- choices:
- - disable
- - enable
-
- imap:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- imap_action:
- description:
- - Action for spam email.
- required: false
- choices:
- - pass
- - tag
-
- imap_log:
- description:
- - Enable/disable logging.
- required: false
- choices:
- - disable
- - enable
-
- imap_tag_msg:
- description:
- - Subject text or header added to spam email.
- required: false
-
- imap_tag_type:
- description:
- - Tag subject or header for spam email.
- - FLAG Based Options. Specify multiple in list form.
- required: false
- choices:
- - subject
- - header
- - spaminfo
-
- mapi:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- mapi_action:
- description:
- - Action for spam email.
- required: false
- choices:
- - pass
- - discard
-
- mapi_log:
- description:
- - Enable/disable logging.
- required: false
- choices:
- - disable
- - enable
-
- msn_hotmail:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- msn_hotmail_log:
- description:
- - Enable/disable logging.
- required: false
- choices:
- - disable
- - enable
-
- pop3:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- pop3_action:
- description:
- - Action for spam email.
- required: false
- choices:
- - pass
- - tag
-
- pop3_log:
- description:
- - Enable/disable logging.
- required: false
- choices:
- - disable
- - enable
-
- pop3_tag_msg:
- description:
- - Subject text or header added to spam email.
- required: false
-
- pop3_tag_type:
- description:
- - Tag subject or header for spam email.
- - FLAG Based Options. Specify multiple in list form.
- required: false
- choices:
- - subject
- - header
- - spaminfo
-
- smtp:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- smtp_action:
- description:
- - Action for spam email.
- required: false
- choices:
- - pass
- - tag
- - discard
-
- smtp_hdrip:
- description:
- - Enable/disable SMTP email header IP checks for spamfsip, spamrbl and spambwl filters.
- required: false
- choices:
- - disable
- - enable
-
- smtp_local_override:
- description:
- - Enable/disable local filter to override SMTP remote check result.
- required: false
- choices:
- - disable
- - enable
-
- smtp_log:
- description:
- - Enable/disable logging.
- required: false
- choices:
- - disable
- - enable
-
- smtp_tag_msg:
- description:
- - Subject text or header added to spam email.
- required: false
-
- smtp_tag_type:
- description:
- - Tag subject or header for spam email.
- - FLAG Based Options. Specify multiple in list form.
- required: false
- choices:
- - subject
- - header
- - spaminfo
-
- yahoo_mail:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- yahoo_mail_log:
- description:
- - Enable/disable logging.
- required: false
- choices:
- - disable
- - enable
-'''
-
-EXAMPLES = '''
- - name: DELETE Profile
- community.fortios.fmgr_secprof_spam:
- name: "Ansible_Spam_Filter_Profile"
- mode: "delete"
-
- - name: Create FMGR_SPAMFILTER_PROFILE
- community.fortios.fmgr_secprof_spam:
- host: "{{ inventory_hostname }}"
- username: "{{ username }}"
- password: "{{ password }}"
- mode: "set"
- adom: "root"
- spam_log_fortiguard_response: "enable"
- spam_iptrust_table:
- spam_filtering: "enable"
- spam_bword_threshold: 10
- options: ["bannedword", "spamfsip", "spamfsurl", "spamrbl", "spamfsphish", "spambwl"]
- name: "Ansible_Spam_Filter_Profile"
- flow_based: "enable"
- external: "enable"
- comment: "Created by Ansible"
- gmail_log: "enable"
- spam_log: "enable"
-'''
-
-RETURN = """
-api_result:
- description: full API response, includes status code and message
- returned: always
- type: str
-"""
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.connection import Connection
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import prepare_dict
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import scrub_dict
-
-###############
-# START METHODS
-###############
-
-
-def fmgr_spamfilter_profile_modify(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
-
- mode = paramgram["mode"]
- adom = paramgram["adom"]
-
- response = DEFAULT_RESULT_OBJ
- url = ""
- datagram = {}
-
- # EVAL THE MODE PARAMETER FOR SET OR ADD
- if mode in ['set', 'add', 'update']:
- url = '/pm/config/adom/{adom}/obj/spamfilter/profile'.format(adom=adom)
- datagram = scrub_dict(prepare_dict(paramgram))
-
- # EVAL THE MODE PARAMETER FOR DELETE
- elif mode == "delete":
- # SET THE CORRECT URL FOR DELETE
- url = '/pm/config/adom/{adom}/obj/spamfilter/profile/{name}'.format(adom=adom, name=paramgram["name"])
- datagram = {}
-
- response = fmgr.process_request(url, datagram, paramgram["mode"])
-
- return response
-
-
-#############
-# END METHODS
-#############
-
-
-def main():
- argument_spec = dict(
- adom=dict(type="str", default="root"),
- mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),
-
- spam_rbl_table=dict(required=False, type="str"),
- spam_mheader_table=dict(required=False, type="str"),
- spam_log_fortiguard_response=dict(required=False, type="str", choices=["disable", "enable"]),
- spam_log=dict(required=False, type="str", choices=["disable", "enable"]),
- spam_iptrust_table=dict(required=False, type="str"),
- spam_filtering=dict(required=False, type="str", choices=["disable", "enable"]),
- spam_bword_threshold=dict(required=False, type="int"),
- spam_bword_table=dict(required=False, type="str"),
- spam_bwl_table=dict(required=False, type="str"),
- replacemsg_group=dict(required=False, type="str"),
- options=dict(required=False, type="list", choices=["bannedword",
- "spamfsip",
- "spamfssubmit",
- "spamfschksum",
- "spamfsurl",
- "spamhelodns",
- "spamraddrdns",
- "spamrbl",
- "spamhdrcheck",
- "spamfsphish",
- "spambwl"]),
- name=dict(required=False, type="str"),
- flow_based=dict(required=False, type="str", choices=["disable", "enable"]),
- external=dict(required=False, type="str", choices=["disable", "enable"]),
- comment=dict(required=False, type="str"),
- gmail=dict(required=False, type="dict"),
- gmail_log=dict(required=False, type="str", choices=["disable", "enable"]),
- imap=dict(required=False, type="dict"),
- imap_action=dict(required=False, type="str", choices=["pass", "tag"]),
- imap_log=dict(required=False, type="str", choices=["disable", "enable"]),
- imap_tag_msg=dict(required=False, type="str"),
- imap_tag_type=dict(required=False, type="str", choices=["subject", "header", "spaminfo"]),
- mapi=dict(required=False, type="dict"),
- mapi_action=dict(required=False, type="str", choices=["pass", "discard"]),
- mapi_log=dict(required=False, type="str", choices=["disable", "enable"]),
- msn_hotmail=dict(required=False, type="dict"),
- msn_hotmail_log=dict(required=False, type="str", choices=["disable", "enable"]),
- pop3=dict(required=False, type="dict"),
- pop3_action=dict(required=False, type="str", choices=["pass", "tag"]),
- pop3_log=dict(required=False, type="str", choices=["disable", "enable"]),
- pop3_tag_msg=dict(required=False, type="str"),
- pop3_tag_type=dict(required=False, type="str", choices=["subject", "header", "spaminfo"]),
- smtp=dict(required=False, type="dict"),
- smtp_action=dict(required=False, type="str", choices=["pass", "tag", "discard"]),
- smtp_hdrip=dict(required=False, type="str", choices=["disable", "enable"]),
- smtp_local_override=dict(required=False, type="str", choices=["disable", "enable"]),
- smtp_log=dict(required=False, type="str", choices=["disable", "enable"]),
- smtp_tag_msg=dict(required=False, type="str"),
- smtp_tag_type=dict(required=False, type="str", choices=["subject", "header", "spaminfo"]),
- yahoo_mail=dict(required=False, type="dict"),
- yahoo_mail_log=dict(required=False, type="str", choices=["disable", "enable"]),
-
- )
-
- module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
- # MODULE PARAMGRAM
- paramgram = {
- "mode": module.params["mode"],
- "adom": module.params["adom"],
- "spam-rbl-table": module.params["spam_rbl_table"],
- "spam-mheader-table": module.params["spam_mheader_table"],
- "spam-log-fortiguard-response": module.params["spam_log_fortiguard_response"],
- "spam-log": module.params["spam_log"],
- "spam-iptrust-table": module.params["spam_iptrust_table"],
- "spam-filtering": module.params["spam_filtering"],
- "spam-bword-threshold": module.params["spam_bword_threshold"],
- "spam-bword-table": module.params["spam_bword_table"],
- "spam-bwl-table": module.params["spam_bwl_table"],
- "replacemsg-group": module.params["replacemsg_group"],
- "options": module.params["options"],
- "name": module.params["name"],
- "flow-based": module.params["flow_based"],
- "external": module.params["external"],
- "comment": module.params["comment"],
- "gmail": {
- "log": module.params["gmail_log"],
- },
- "imap": {
- "action": module.params["imap_action"],
- "log": module.params["imap_log"],
- "tag-msg": module.params["imap_tag_msg"],
- "tag-type": module.params["imap_tag_type"],
- },
- "mapi": {
- "action": module.params["mapi_action"],
- "log": module.params["mapi_log"],
- },
- "msn-hotmail": {
- "log": module.params["msn_hotmail_log"],
- },
- "pop3": {
- "action": module.params["pop3_action"],
- "log": module.params["pop3_log"],
- "tag-msg": module.params["pop3_tag_msg"],
- "tag-type": module.params["pop3_tag_type"],
- },
- "smtp": {
- "action": module.params["smtp_action"],
- "hdrip": module.params["smtp_hdrip"],
- "local-override": module.params["smtp_local_override"],
- "log": module.params["smtp_log"],
- "tag-msg": module.params["smtp_tag_msg"],
- "tag-type": module.params["smtp_tag_type"],
- },
- "yahoo-mail": {
- "log": module.params["yahoo_mail_log"],
- }
- }
- module.paramgram = paramgram
- fmgr = None
- if module._socket_path:
- connection = Connection(module._socket_path)
- fmgr = FortiManagerHandler(connection, module)
- fmgr.tools = FMGRCommon()
- else:
- module.fail_json(**FAIL_SOCKET_MSG)
-
- list_overrides = ['gmail', 'imap', 'mapi', 'msn-hotmail', 'pop3', 'smtp', 'yahoo-mail']
- paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
- paramgram=paramgram, module=module)
-
- results = DEFAULT_RESULT_OBJ
- try:
-
- results = fmgr_spamfilter_profile_modify(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
-
- except Exception as err:
- raise FMGBaseException(err)
-
- return module.exit_json(**results[1])
-
-
-if __name__ == "__main__":
- main()
diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_ssl_ssh.py b/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_ssl_ssh.py
deleted file mode 100644
index 1e9a0f7d7..000000000
--- a/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_ssl_ssh.py
+++ /dev/null
@@ -1,954 +0,0 @@
-#!/usr/bin/python
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-DOCUMENTATION = '''
----
-module: fmgr_secprof_ssl_ssh
-notes:
- - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
-author:
- - Luke Weighall (@lweighall)
- - Andrew Welsh (@Ghilli3)
- - Jim Huber (@p4r4n0y1ng)
-short_description: Manage SSL and SSH security profiles in FortiManager
-description:
- - Manage SSL and SSH security profiles in FortiManager via the FMG API
-
-options:
- adom:
- description:
- - The ADOM the configuration should belong to.
- required: false
- default: root
-
- mode:
- description:
- - Sets one of three modes for managing the object.
- - Allows use of soft-adds instead of overwriting existing values
- choices: ['add', 'set', 'delete', 'update']
- required: false
- default: add
-
- whitelist:
- description:
- - Enable/disable exempting servers by FortiGuard whitelist.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- use_ssl_server:
- description:
- - Enable/disable the use of SSL server table for SSL offloading.
- - choice | disable | Don't use SSL server configuration.
- - choice | enable | Use SSL server configuration.
- required: false
- choices: ["disable", "enable"]
-
- untrusted_caname:
- description:
- - Untrusted CA certificate used by SSL Inspection.
- required: false
-
- ssl_exemptions_log:
- description:
- - Enable/disable logging SSL exemptions.
- - choice | disable | Disable logging SSL exemptions.
- - choice | enable | Enable logging SSL exemptions.
- required: false
- choices: ["disable", "enable"]
-
- ssl_anomalies_log:
- description:
- - Enable/disable logging SSL anomalies.
- - choice | disable | Disable logging SSL anomalies.
- - choice | enable | Enable logging SSL anomalies.
- required: false
- choices: ["disable", "enable"]
-
- server_cert_mode:
- description:
- - Re-sign or replace the server's certificate.
- - choice | re-sign | Multiple clients connecting to multiple servers.
- - choice | replace | Protect an SSL server.
- required: false
- choices: ["re-sign", "replace"]
-
- server_cert:
- description:
- - Certificate used by SSL Inspection to replace server certificate.
- required: false
-
- rpc_over_https:
- description:
- - Enable/disable inspection of RPC over HTTPS.
- - choice | disable | Disable inspection of RPC over HTTPS.
- - choice | enable | Enable inspection of RPC over HTTPS.
- required: false
- choices: ["disable", "enable"]
-
- name:
- description:
- - Name.
- required: false
-
- mapi_over_https:
- description:
- - Enable/disable inspection of MAPI over HTTPS.
- - choice | disable | Disable inspection of MAPI over HTTPS.
- - choice | enable | Enable inspection of MAPI over HTTPS.
- required: false
- choices: ["disable", "enable"]
-
- comment:
- description:
- - Optional comments.
- required: false
-
- caname:
- description:
- - CA certificate used by SSL Inspection.
- required: false
-
- ftps:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- ftps_allow_invalid_server_cert:
- description:
- - When enabled, allows SSL sessions whose server certificate validation failed.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- ftps_client_cert_request:
- description:
- - Action based on client certificate request failure.
- - choice | bypass | Bypass.
- - choice | inspect | Inspect.
- - choice | block | Block.
- required: false
- choices: ["bypass", "inspect", "block"]
-
- ftps_ports:
- description:
- - Ports to use for scanning (1 - 65535, default = 443).
- required: false
-
- ftps_status:
- description:
- - Configure protocol inspection status.
- - choice | disable | Disable.
- - choice | deep-inspection | Full SSL inspection.
- required: false
- choices: ["disable", "deep-inspection"]
-
- ftps_unsupported_ssl:
- description:
- - Action based on the SSL encryption used being unsupported.
- - choice | bypass | Bypass.
- - choice | inspect | Inspect.
- - choice | block | Block.
- required: false
- choices: ["bypass", "inspect", "block"]
-
- ftps_untrusted_cert:
- description:
- - Allow, ignore, or block the untrusted SSL session server certificate.
- - choice | allow | Allow the untrusted server certificate.
- - choice | block | Block the connection when an untrusted server certificate is detected.
- - choice | ignore | Always take the server certificate as trusted.
- required: false
- choices: ["allow", "block", "ignore"]
-
- https:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- https_allow_invalid_server_cert:
- description:
- - When enabled, allows SSL sessions whose server certificate validation failed.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- https_client_cert_request:
- description:
- - Action based on client certificate request failure.
- - choice | bypass | Bypass.
- - choice | inspect | Inspect.
- - choice | block | Block.
- required: false
- choices: ["bypass", "inspect", "block"]
-
- https_ports:
- description:
- - Ports to use for scanning (1 - 65535, default = 443).
- required: false
-
- https_status:
- description:
- - Configure protocol inspection status.
- - choice | disable | Disable.
- - choice | certificate-inspection | Inspect SSL handshake only.
- - choice | deep-inspection | Full SSL inspection.
- required: false
- choices: ["disable", "certificate-inspection", "deep-inspection"]
-
- https_unsupported_ssl:
- description:
- - Action based on the SSL encryption used being unsupported.
- - choice | bypass | Bypass.
- - choice | inspect | Inspect.
- - choice | block | Block.
- required: false
- choices: ["bypass", "inspect", "block"]
-
- https_untrusted_cert:
- description:
- - Allow, ignore, or block the untrusted SSL session server certificate.
- - choice | allow | Allow the untrusted server certificate.
- - choice | block | Block the connection when an untrusted server certificate is detected.
- - choice | ignore | Always take the server certificate as trusted.
- required: false
- choices: ["allow", "block", "ignore"]
-
- imaps:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- imaps_allow_invalid_server_cert:
- description:
- - When enabled, allows SSL sessions whose server certificate validation failed.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- imaps_client_cert_request:
- description:
- - Action based on client certificate request failure.
- - choice | bypass | Bypass.
- - choice | inspect | Inspect.
- - choice | block | Block.
- required: false
- choices: ["bypass", "inspect", "block"]
-
- imaps_ports:
- description:
- - Ports to use for scanning (1 - 65535, default = 443).
- required: false
-
- imaps_status:
- description:
- - Configure protocol inspection status.
- - choice | disable | Disable.
- - choice | deep-inspection | Full SSL inspection.
- required: false
- choices: ["disable", "deep-inspection"]
-
- imaps_unsupported_ssl:
- description:
- - Action based on the SSL encryption used being unsupported.
- - choice | bypass | Bypass.
- - choice | inspect | Inspect.
- - choice | block | Block.
- required: false
- choices: ["bypass", "inspect", "block"]
-
- imaps_untrusted_cert:
- description:
- - Allow, ignore, or block the untrusted SSL session server certificate.
- - choice | allow | Allow the untrusted server certificate.
- - choice | block | Block the connection when an untrusted server certificate is detected.
- - choice | ignore | Always take the server certificate as trusted.
- required: false
- choices: ["allow", "block", "ignore"]
-
- pop3s:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- pop3s_allow_invalid_server_cert:
- description:
- - When enabled, allows SSL sessions whose server certificate validation failed.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- pop3s_client_cert_request:
- description:
- - Action based on client certificate request failure.
- - choice | bypass | Bypass.
- - choice | inspect | Inspect.
- - choice | block | Block.
- required: false
- choices: ["bypass", "inspect", "block"]
-
- pop3s_ports:
- description:
- - Ports to use for scanning (1 - 65535, default = 443).
- required: false
-
- pop3s_status:
- description:
- - Configure protocol inspection status.
- - choice | disable | Disable.
- - choice | deep-inspection | Full SSL inspection.
- required: false
- choices: ["disable", "deep-inspection"]
-
- pop3s_unsupported_ssl:
- description:
- - Action based on the SSL encryption used being unsupported.
- - choice | bypass | Bypass.
- - choice | inspect | Inspect.
- - choice | block | Block.
- required: false
- choices: ["bypass", "inspect", "block"]
-
- pop3s_untrusted_cert:
- description:
- - Allow, ignore, or block the untrusted SSL session server certificate.
- - choice | allow | Allow the untrusted server certificate.
- - choice | block | Block the connection when an untrusted server certificate is detected.
- - choice | ignore | Always take the server certificate as trusted.
- required: false
- choices: ["allow", "block", "ignore"]
-
- smtps:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- smtps_allow_invalid_server_cert:
- description:
- - When enabled, allows SSL sessions whose server certificate validation failed.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- smtps_client_cert_request:
- description:
- - Action based on client certificate request failure.
- - choice | bypass | Bypass.
- - choice | inspect | Inspect.
- - choice | block | Block.
- required: false
- choices: ["bypass", "inspect", "block"]
-
- smtps_ports:
- description:
- - Ports to use for scanning (1 - 65535, default = 443).
- required: false
-
- smtps_status:
- description:
- - Configure protocol inspection status.
- - choice | disable | Disable.
- - choice | deep-inspection | Full SSL inspection.
- required: false
- choices: ["disable", "deep-inspection"]
-
- smtps_unsupported_ssl:
- description:
- - Action based on the SSL encryption used being unsupported.
- - choice | bypass | Bypass.
- - choice | inspect | Inspect.
- - choice | block | Block.
- required: false
- choices: ["bypass", "inspect", "block"]
-
- smtps_untrusted_cert:
- description:
- - Allow, ignore, or block the untrusted SSL session server certificate.
- - choice | allow | Allow the untrusted server certificate.
- - choice | block | Block the connection when an untrusted server certificate is detected.
- - choice | ignore | Always take the server certificate as trusted.
- required: false
- choices: ["allow", "block", "ignore"]
-
- ssh:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- ssh_inspect_all:
- description:
- - Level of SSL inspection.
- - choice | disable | Disable.
- - choice | deep-inspection | Full SSL inspection.
- required: false
- choices: ["disable", "deep-inspection"]
-
- ssh_ports:
- description:
- - Ports to use for scanning (1 - 65535, default = 443).
- required: false
-
- ssh_ssh_algorithm:
- description:
- - Relative strength of encryption algorithms accepted during negotiation.
- - choice | compatible | Allow a broader set of encryption algorithms for best compatibility.
- - choice | high-encryption | Allow only AES-CTR, AES-GCM ciphers and high encryption algorithms.
- required: false
- choices: ["compatible", "high-encryption"]
-
- ssh_ssh_policy_check:
- description:
- - Enable/disable SSH policy check.
- - choice | disable | Disable SSH policy check.
- - choice | enable | Enable SSH policy check.
- required: false
- choices: ["disable", "enable"]
-
- ssh_ssh_tun_policy_check:
- description:
- - Enable/disable SSH tunnel policy check.
- - choice | disable | Disable SSH tunnel policy check.
- - choice | enable | Enable SSH tunnel policy check.
- required: false
- choices: ["disable", "enable"]
-
- ssh_status:
- description:
- - Configure protocol inspection status.
- - choice | disable | Disable.
- - choice | deep-inspection | Full SSL inspection.
- required: false
- choices: ["disable", "deep-inspection"]
-
- ssh_unsupported_version:
- description:
- - Action based on SSH version being unsupported.
- - choice | block | Block.
- - choice | bypass | Bypass.
- required: false
- choices: ["block", "bypass"]
-
- ssl:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- ssl_allow_invalid_server_cert:
- description:
- - When enabled, allows SSL sessions whose server certificate validation failed.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- ssl_client_cert_request:
- description:
- - Action based on client certificate request failure.
- - choice | bypass | Bypass.
- - choice | inspect | Inspect.
- - choice | block | Block.
- required: false
- choices: ["bypass", "inspect", "block"]
-
- ssl_inspect_all:
- description:
- - Level of SSL inspection.
- - choice | disable | Disable.
- - choice | certificate-inspection | Inspect SSL handshake only.
- - choice | deep-inspection | Full SSL inspection.
- required: false
- choices: ["disable", "certificate-inspection", "deep-inspection"]
-
- ssl_unsupported_ssl:
- description:
- - Action based on the SSL encryption used being unsupported.
- - choice | bypass | Bypass.
- - choice | inspect | Inspect.
- - choice | block | Block.
- required: false
- choices: ["bypass", "inspect", "block"]
-
- ssl_untrusted_cert:
- description:
- - Allow, ignore, or block the untrusted SSL session server certificate.
- - choice | allow | Allow the untrusted server certificate.
- - choice | block | Block the connection when an untrusted server certificate is detected.
- - choice | ignore | Always take the server certificate as trusted.
- required: false
- choices: ["allow", "block", "ignore"]
-
- ssl_exempt:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- ssl_exempt_address:
- description:
- - IPv4 address object.
- required: false
-
- ssl_exempt_address6:
- description:
- - IPv6 address object.
- required: false
-
- ssl_exempt_fortiguard_category:
- description:
- - FortiGuard category ID.
- required: false
-
- ssl_exempt_regex:
- description:
- - Exempt servers by regular expression.
- required: false
-
- ssl_exempt_type:
- description:
- - Type of address object (IPv4 or IPv6) or FortiGuard category.
- - choice | fortiguard-category | FortiGuard category.
- - choice | address | Firewall IPv4 address.
- - choice | address6 | Firewall IPv6 address.
- - choice | wildcard-fqdn | Fully Qualified Domain Name with wildcard characters.
- - choice | regex | Regular expression FQDN.
- required: false
- choices: ["fortiguard-category", "address", "address6", "wildcard-fqdn", "regex"]
-
- ssl_exempt_wildcard_fqdn:
- description:
- - Exempt servers by wildcard FQDN.
- required: false
-
- ssl_server:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- ssl_server_ftps_client_cert_request:
- description:
- - Action based on client certificate request failure during the FTPS handshake.
- - choice | bypass | Bypass.
- - choice | inspect | Inspect.
- - choice | block | Block.
- required: false
- choices: ["bypass", "inspect", "block"]
-
- ssl_server_https_client_cert_request:
- description:
- - Action based on client certificate request failure during the HTTPS handshake.
- - choice | bypass | Bypass.
- - choice | inspect | Inspect.
- - choice | block | Block.
- required: false
- choices: ["bypass", "inspect", "block"]
-
- ssl_server_imaps_client_cert_request:
- description:
- - Action based on client certificate request failure during the IMAPS handshake.
- - choice | bypass | Bypass.
- - choice | inspect | Inspect.
- - choice | block | Block.
- required: false
- choices: ["bypass", "inspect", "block"]
-
- ssl_server_ip:
- description:
- - IPv4 address of the SSL server.
- required: false
-
- ssl_server_pop3s_client_cert_request:
- description:
- - Action based on client certificate request failure during the POP3S handshake.
- - choice | bypass | Bypass.
- - choice | inspect | Inspect.
- - choice | block | Block.
- required: false
- choices: ["bypass", "inspect", "block"]
-
- ssl_server_smtps_client_cert_request:
- description:
- - Action based on client certificate request failure during the SMTPS handshake.
- - choice | bypass | Bypass.
- - choice | inspect | Inspect.
- - choice | block | Block.
- required: false
- choices: ["bypass", "inspect", "block"]
-
- ssl_server_ssl_other_client_cert_request:
- description:
- - Action based on client certificate request failure during an SSL protocol handshake.
- - choice | bypass | Bypass.
- - choice | inspect | Inspect.
- - choice | block | Block.
- required: false
- choices: ["bypass", "inspect", "block"]
-
-
-'''
-
-EXAMPLES = '''
- - name: DELETE Profile
- community.fortios.fmgr_secprof_ssl_ssh:
- name: Ansible_SSL_SSH_Profile
- mode: delete
-
- - name: CREATE Profile
- community.fortios.fmgr_secprof_ssl_ssh:
- name: Ansible_SSL_SSH_Profile
- comment: "Created by Ansible Module TEST"
- mode: set
- mapi_over_https: enable
- rpc_over_https: enable
- server_cert_mode: replace
- ssl_anomalies_log: enable
- ssl_exemptions_log: enable
- use_ssl_server: enable
- whitelist: enable
-'''
-
-RETURN = """
-api_result:
- description: full API response, includes status code and message
- returned: always
- type: str
-"""
-
-from ansible.module_utils.basic import AnsibleModule, env_fallback
-from ansible.module_utils.connection import Connection
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRMethods
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import prepare_dict
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import scrub_dict
-
-###############
-# START METHODS
-###############
-
-
-def fmgr_firewall_ssl_ssh_profile_modify(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
-
- mode = paramgram["mode"]
- adom = paramgram["adom"]
-
- response = DEFAULT_RESULT_OBJ
- url = ""
- datagram = {}
-
- # EVAL THE MODE PARAMETER FOR SET OR ADD
- if mode in ['set', 'add', 'update']:
- url = '/pm/config/adom/{adom}/obj/firewall/ssl-ssh-profile'.format(adom=adom)
- datagram = scrub_dict(prepare_dict(paramgram))
-
- # EVAL THE MODE PARAMETER FOR DELETE
- elif mode == "delete":
- # SET THE CORRECT URL FOR DELETE
- url = '/pm/config/adom/{adom}/obj/firewall/ssl-ssh-profile/{name}'.format(adom=adom, name=paramgram["name"])
- datagram = {}
-
- response = fmgr.process_request(url, datagram, paramgram["mode"])
-
- return response
-
-
-#############
-# END METHODS
-#############
-
-
-def main():
- argument_spec = dict(
- adom=dict(type="str", default="root"),
- mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),
-
- whitelist=dict(required=False, type="str", choices=["disable", "enable"]),
- use_ssl_server=dict(required=False, type="str", choices=["disable", "enable"]),
- untrusted_caname=dict(required=False, type="str"),
- ssl_exemptions_log=dict(required=False, type="str", choices=["disable", "enable"]),
- ssl_anomalies_log=dict(required=False, type="str", choices=["disable", "enable"]),
- server_cert_mode=dict(required=False, type="str", choices=["re-sign", "replace"]),
- server_cert=dict(required=False, type="str"),
- rpc_over_https=dict(required=False, type="str", choices=["disable", "enable"]),
- name=dict(required=False, type="str"),
- mapi_over_https=dict(required=False, type="str", choices=["disable", "enable"]),
- comment=dict(required=False, type="str"),
- caname=dict(required=False, type="str"),
- ftps=dict(required=False, type="list"),
- ftps_allow_invalid_server_cert=dict(required=False, type="str", choices=["disable", "enable"]),
- ftps_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
- ftps_ports=dict(required=False, type="str"),
- ftps_status=dict(required=False, type="str", choices=["disable", "deep-inspection"]),
- ftps_unsupported_ssl=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
- ftps_untrusted_cert=dict(required=False, type="str", choices=["allow", "block", "ignore"]),
- https=dict(required=False, type="list"),
- https_allow_invalid_server_cert=dict(required=False, type="str", choices=["disable", "enable"]),
- https_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
- https_ports=dict(required=False, type="str"),
- https_status=dict(required=False, type="str", choices=["disable", "certificate-inspection", "deep-inspection"]),
- https_unsupported_ssl=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
- https_untrusted_cert=dict(required=False, type="str", choices=["allow", "block", "ignore"]),
- imaps=dict(required=False, type="list"),
- imaps_allow_invalid_server_cert=dict(required=False, type="str", choices=["disable", "enable"]),
- imaps_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
- imaps_ports=dict(required=False, type="str"),
- imaps_status=dict(required=False, type="str", choices=["disable", "deep-inspection"]),
- imaps_unsupported_ssl=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
- imaps_untrusted_cert=dict(required=False, type="str", choices=["allow", "block", "ignore"]),
- pop3s=dict(required=False, type="list"),
- pop3s_allow_invalid_server_cert=dict(required=False, type="str", choices=["disable", "enable"]),
- pop3s_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
- pop3s_ports=dict(required=False, type="str"),
- pop3s_status=dict(required=False, type="str", choices=["disable", "deep-inspection"]),
- pop3s_unsupported_ssl=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
- pop3s_untrusted_cert=dict(required=False, type="str", choices=["allow", "block", "ignore"]),
- smtps=dict(required=False, type="list"),
- smtps_allow_invalid_server_cert=dict(required=False, type="str", choices=["disable", "enable"]),
- smtps_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
- smtps_ports=dict(required=False, type="str"),
- smtps_status=dict(required=False, type="str", choices=["disable", "deep-inspection"]),
- smtps_unsupported_ssl=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
- smtps_untrusted_cert=dict(required=False, type="str", choices=["allow", "block", "ignore"]),
- ssh=dict(required=False, type="list"),
- ssh_inspect_all=dict(required=False, type="str", choices=["disable", "deep-inspection"]),
- ssh_ports=dict(required=False, type="str"),
- ssh_ssh_algorithm=dict(required=False, type="str", choices=["compatible", "high-encryption"]),
- ssh_ssh_policy_check=dict(required=False, type="str", choices=["disable", "enable"]),
- ssh_ssh_tun_policy_check=dict(required=False, type="str", choices=["disable", "enable"]),
- ssh_status=dict(required=False, type="str", choices=["disable", "deep-inspection"]),
- ssh_unsupported_version=dict(required=False, type="str", choices=["block", "bypass"]),
- ssl=dict(required=False, type="list"),
- ssl_allow_invalid_server_cert=dict(required=False, type="str", choices=["disable", "enable"]),
- ssl_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
- ssl_inspect_all=dict(required=False, type="str", choices=["disable", "certificate-inspection",
- "deep-inspection"]),
- ssl_unsupported_ssl=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
- ssl_untrusted_cert=dict(required=False, type="str", choices=["allow", "block", "ignore"]),
- ssl_exempt=dict(required=False, type="list"),
- ssl_exempt_address=dict(required=False, type="str"),
- ssl_exempt_address6=dict(required=False, type="str"),
- ssl_exempt_fortiguard_category=dict(required=False, type="str"),
- ssl_exempt_regex=dict(required=False, type="str"),
- ssl_exempt_type=dict(required=False, type="str", choices=["fortiguard-category", "address", "address6",
- "wildcard-fqdn", "regex"]),
- ssl_exempt_wildcard_fqdn=dict(required=False, type="str"),
- ssl_server=dict(required=False, type="list"),
- ssl_server_ftps_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
- ssl_server_https_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
- ssl_server_imaps_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
- ssl_server_ip=dict(required=False, type="str"),
- ssl_server_pop3s_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
- ssl_server_smtps_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect", "block"]),
- ssl_server_ssl_other_client_cert_request=dict(required=False, type="str", choices=["bypass", "inspect",
- "block"]),
-
- )
-
- module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
- # MODULE PARAMGRAM
- paramgram = {
- "mode": module.params["mode"],
- "adom": module.params["adom"],
- "whitelist": module.params["whitelist"],
- "use-ssl-server": module.params["use_ssl_server"],
- "untrusted-caname": module.params["untrusted_caname"],
- "ssl-exemptions-log": module.params["ssl_exemptions_log"],
- "ssl-anomalies-log": module.params["ssl_anomalies_log"],
- "server-cert-mode": module.params["server_cert_mode"],
- "server-cert": module.params["server_cert"],
- "rpc-over-https": module.params["rpc_over_https"],
- "name": module.params["name"],
- "mapi-over-https": module.params["mapi_over_https"],
- "comment": module.params["comment"],
- "caname": module.params["caname"],
- "ftps": {
- "allow-invalid-server-cert": module.params["ftps_allow_invalid_server_cert"],
- "client-cert-request": module.params["ftps_client_cert_request"],
- "ports": module.params["ftps_ports"],
- "status": module.params["ftps_status"],
- "unsupported-ssl": module.params["ftps_unsupported_ssl"],
- "untrusted-cert": module.params["ftps_untrusted_cert"],
- },
- "https": {
- "allow-invalid-server-cert": module.params["https_allow_invalid_server_cert"],
- "client-cert-request": module.params["https_client_cert_request"],
- "ports": module.params["https_ports"],
- "status": module.params["https_status"],
- "unsupported-ssl": module.params["https_unsupported_ssl"],
- "untrusted-cert": module.params["https_untrusted_cert"],
- },
- "imaps": {
- "allow-invalid-server-cert": module.params["imaps_allow_invalid_server_cert"],
- "client-cert-request": module.params["imaps_client_cert_request"],
- "ports": module.params["imaps_ports"],
- "status": module.params["imaps_status"],
- "unsupported-ssl": module.params["imaps_unsupported_ssl"],
- "untrusted-cert": module.params["imaps_untrusted_cert"],
- },
- "pop3s": {
- "allow-invalid-server-cert": module.params["pop3s_allow_invalid_server_cert"],
- "client-cert-request": module.params["pop3s_client_cert_request"],
- "ports": module.params["pop3s_ports"],
- "status": module.params["pop3s_status"],
- "unsupported-ssl": module.params["pop3s_unsupported_ssl"],
- "untrusted-cert": module.params["pop3s_untrusted_cert"],
- },
- "smtps": {
- "allow-invalid-server-cert": module.params["smtps_allow_invalid_server_cert"],
- "client-cert-request": module.params["smtps_client_cert_request"],
- "ports": module.params["smtps_ports"],
- "status": module.params["smtps_status"],
- "unsupported-ssl": module.params["smtps_unsupported_ssl"],
- "untrusted-cert": module.params["smtps_untrusted_cert"],
- },
- "ssh": {
- "inspect-all": module.params["ssh_inspect_all"],
- "ports": module.params["ssh_ports"],
- "ssh-algorithm": module.params["ssh_ssh_algorithm"],
- "ssh-policy-check": module.params["ssh_ssh_policy_check"],
- "ssh-tun-policy-check": module.params["ssh_ssh_tun_policy_check"],
- "status": module.params["ssh_status"],
- "unsupported-version": module.params["ssh_unsupported_version"],
- },
- "ssl": {
- "allow-invalid-server-cert": module.params["ssl_allow_invalid_server_cert"],
- "client-cert-request": module.params["ssl_client_cert_request"],
- "inspect-all": module.params["ssl_inspect_all"],
- "unsupported-ssl": module.params["ssl_unsupported_ssl"],
- "untrusted-cert": module.params["ssl_untrusted_cert"],
- },
- "ssl-exempt": {
- "address": module.params["ssl_exempt_address"],
- "address6": module.params["ssl_exempt_address6"],
- "fortiguard-category": module.params["ssl_exempt_fortiguard_category"],
- "regex": module.params["ssl_exempt_regex"],
- "type": module.params["ssl_exempt_type"],
- "wildcard-fqdn": module.params["ssl_exempt_wildcard_fqdn"],
- },
- "ssl-server": {
- "ftps-client-cert-request": module.params["ssl_server_ftps_client_cert_request"],
- "https-client-cert-request": module.params["ssl_server_https_client_cert_request"],
- "imaps-client-cert-request": module.params["ssl_server_imaps_client_cert_request"],
- "ip": module.params["ssl_server_ip"],
- "pop3s-client-cert-request": module.params["ssl_server_pop3s_client_cert_request"],
- "smtps-client-cert-request": module.params["ssl_server_smtps_client_cert_request"],
- "ssl-other-client-cert-request": module.params["ssl_server_ssl_other_client_cert_request"],
- }
- }
-
- module.paramgram = paramgram
- fmgr = None
- if module._socket_path:
- connection = Connection(module._socket_path)
- fmgr = FortiManagerHandler(connection, module)
- fmgr.tools = FMGRCommon()
- else:
- module.fail_json(**FAIL_SOCKET_MSG)
-
- list_overrides = ['ftps', 'https', 'imaps', 'pop3s', 'smtps', 'ssh', 'ssl', 'ssl-exempt', 'ssl-server']
- paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
- paramgram=paramgram, module=module)
-
- results = DEFAULT_RESULT_OBJ
-
- try:
-
- results = fmgr_firewall_ssl_ssh_profile_modify(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
-
- except Exception as err:
- raise FMGBaseException(err)
-
- return module.exit_json(**results[1])
-
-
-if __name__ == "__main__":
- main()
diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_voip.py b/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_voip.py
deleted file mode 100644
index 31b71288a..000000000
--- a/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_voip.py
+++ /dev/null
@@ -1,1198 +0,0 @@
-#!/usr/bin/python
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-DOCUMENTATION = '''
----
-module: fmgr_secprof_voip
-notes:
- - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
-author:
- - Luke Weighall (@lweighall)
- - Andrew Welsh (@Ghilli3)
- - Jim Huber (@p4r4n0y1ng)
-short_description: VOIP security profiles in FMG
-description:
- - Manage VOIP security profiles in FortiManager via API
-
-options:
- adom:
- description:
- - The ADOM the configuration should belong to.
- required: false
- default: root
-
- mode:
- description:
- - Sets one of three modes for managing the object.
- - Allows use of soft-adds instead of overwriting existing values
- choices: ['add', 'set', 'delete', 'update']
- required: false
- default: add
-
- name:
- description:
- - Profile name.
- required: false
-
- comment:
- description:
- - Comment.
- required: false
-
- sccp:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- sccp_block_mcast:
- description:
- - Enable/disable block multicast RTP connections.
- - choice | disable | Disable status.
- - choice | enable | Enable status.
- required: false
- choices: ["disable", "enable"]
-
- sccp_log_call_summary:
- description:
- - Enable/disable log summary of SCCP calls.
- - choice | disable | Disable status.
- - choice | enable | Enable status.
- required: false
- choices: ["disable", "enable"]
-
- sccp_log_violations:
- description:
- - Enable/disable logging of SCCP violations.
- - choice | disable | Disable status.
- - choice | enable | Enable status.
- required: false
- choices: ["disable", "enable"]
-
- sccp_max_calls:
- description:
- - Maximum calls per minute per SCCP client (max 65535).
- required: false
-
- sccp_status:
- description:
- - Enable/disable SCCP.
- - choice | disable | Disable status.
- - choice | enable | Enable status.
- required: false
- choices: ["disable", "enable"]
-
- sccp_verify_header:
- description:
- - Enable/disable verify SCCP header content.
- - choice | disable | Disable status.
- - choice | enable | Enable status.
- required: false
- choices: ["disable", "enable"]
-
- sip:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- sip_ack_rate:
- description:
- - ACK request rate limit (per second, per policy).
- required: false
-
- sip_block_ack:
- description:
- - Enable/disable block ACK requests.
- - choice | disable | Disable status.
- - choice | enable | Enable status.
- required: false
- choices: ["disable", "enable"]
-
- sip_block_bye:
- description:
- - Enable/disable block BYE requests.
- - choice | disable | Disable status.
- - choice | enable | Enable status.
- required: false
- choices: ["disable", "enable"]
-
- sip_block_cancel:
- description:
- - Enable/disable block CANCEL requests.
- - choice | disable | Disable status.
- - choice | enable | Enable status.
- required: false
- choices: ["disable", "enable"]
-
- sip_block_geo_red_options:
- description:
- - Enable/disable block OPTIONS requests, but OPTIONS requests still notify for redundancy.
- - choice | disable | Disable status.
- - choice | enable | Enable status.
- required: false
- choices: ["disable", "enable"]
-
- sip_block_info:
- description:
- - Enable/disable block INFO requests.
- - choice | disable | Disable status.
- - choice | enable | Enable status.
- required: false
- choices: ["disable", "enable"]
-
- sip_block_invite:
- description:
- - Enable/disable block INVITE requests.
- - choice | disable | Disable status.
- - choice | enable | Enable status.
- required: false
- choices: ["disable", "enable"]
-
- sip_block_long_lines:
- description:
- - Enable/disable block requests with headers exceeding max-line-length.
- - choice | disable | Disable status.
- - choice | enable | Enable status.
- required: false
- choices: ["disable", "enable"]
-
- sip_block_message:
- description:
- - Enable/disable block MESSAGE requests.
- - choice | disable | Disable status.
- - choice | enable | Enable status.
- required: false
- choices: ["disable", "enable"]
-
- sip_block_notify:
- description:
- - Enable/disable block NOTIFY requests.
- - choice | disable | Disable status.
- - choice | enable | Enable status.
- required: false
- choices: ["disable", "enable"]
-
- sip_block_options:
- description:
- - Enable/disable block OPTIONS requests and no OPTIONS as notifying message for redundancy either.
- - choice | disable | Disable status.
- - choice | enable | Enable status.
- required: false
- choices: ["disable", "enable"]
-
- sip_block_prack:
- description:
- - Enable/disable block prack requests.
- - choice | disable | Disable status.
- - choice | enable | Enable status.
- required: false
- choices: ["disable", "enable"]
-
- sip_block_publish:
- description:
- - Enable/disable block PUBLISH requests.
- - choice | disable | Disable status.
- - choice | enable | Enable status.
- required: false
- choices: ["disable", "enable"]
-
- sip_block_refer:
- description:
- - Enable/disable block REFER requests.
- - choice | disable | Disable status.
- - choice | enable | Enable status.
- required: false
- choices: ["disable", "enable"]
-
- sip_block_register:
- description:
- - Enable/disable block REGISTER requests.
- - choice | disable | Disable status.
- - choice | enable | Enable status.
- required: false
- choices: ["disable", "enable"]
-
- sip_block_subscribe:
- description:
- - Enable/disable block SUBSCRIBE requests.
- - choice | disable | Disable status.
- - choice | enable | Enable status.
- required: false
- choices: ["disable", "enable"]
-
- sip_block_unknown:
- description:
- - Block unrecognized SIP requests (enabled by default).
- - choice | disable | Disable status.
- - choice | enable | Enable status.
- required: false
- choices: ["disable", "enable"]
-
- sip_block_update:
- description:
- - Enable/disable block UPDATE requests.
- - choice | disable | Disable status.
- - choice | enable | Enable status.
- required: false
- choices: ["disable", "enable"]
-
- sip_bye_rate:
- description:
- - BYE request rate limit (per second, per policy).
- required: false
-
- sip_call_keepalive:
- description:
- - Continue tracking calls with no RTP for this many minutes.
- required: false
-
- sip_cancel_rate:
- description:
- - CANCEL request rate limit (per second, per policy).
- required: false
-
- sip_contact_fixup:
- description:
- - Fixup contact anyway even if contact's IP|port doesn't match session's IP|port.
- - choice | disable | Disable status.
- - choice | enable | Enable status.
- required: false
- choices: ["disable", "enable"]
-
- sip_hnt_restrict_source_ip:
- description:
- - Enable/disable restrict RTP source IP to be the same as SIP source IP when HNT is enabled.
- - choice | disable | Disable status.
- - choice | enable | Enable status.
- required: false
- choices: ["disable", "enable"]
-
- sip_hosted_nat_traversal:
- description:
- - Hosted NAT Traversal (HNT).
- - choice | disable | Disable status.
- - choice | enable | Enable status.
- required: false
- choices: ["disable", "enable"]
-
- sip_info_rate:
- description:
- - INFO request rate limit (per second, per policy).
- required: false
-
- sip_invite_rate:
- description:
- - INVITE request rate limit (per second, per policy).
- required: false
-
- sip_ips_rtp:
- description:
- - Enable/disable allow IPS on RTP.
- - choice | disable | Disable status.
- - choice | enable | Enable status.
- required: false
- choices: ["disable", "enable"]
-
- sip_log_call_summary:
- description:
- - Enable/disable logging of SIP call summary.
- - choice | disable | Disable status.
- - choice | enable | Enable status.
- required: false
- choices: ["disable", "enable"]
-
- sip_log_violations:
- description:
- - Enable/disable logging of SIP violations.
- - choice | disable | Disable status.
- - choice | enable | Enable status.
- required: false
- choices: ["disable", "enable"]
-
- sip_malformed_header_allow:
- description:
- - Action for malformed Allow header.
- - choice | pass | Bypass malformed messages.
- - choice | discard | Discard malformed messages.
- - choice | respond | Respond with error code.
- required: false
- choices: ["pass", "discard", "respond"]
-
- sip_malformed_header_call_id:
- description:
- - Action for malformed Call-ID header.
- - choice | pass | Bypass malformed messages.
- - choice | discard | Discard malformed messages.
- - choice | respond | Respond with error code.
- required: false
- choices: ["pass", "discard", "respond"]
-
- sip_malformed_header_contact:
- description:
- - Action for malformed Contact header.
- - choice | pass | Bypass malformed messages.
- - choice | discard | Discard malformed messages.
- - choice | respond | Respond with error code.
- required: false
- choices: ["pass", "discard", "respond"]
-
- sip_malformed_header_content_length:
- description:
- - Action for malformed Content-Length header.
- - choice | pass | Bypass malformed messages.
- - choice | discard | Discard malformed messages.
- - choice | respond | Respond with error code.
- required: false
- choices: ["pass", "discard", "respond"]
-
- sip_malformed_header_content_type:
- description:
- - Action for malformed Content-Type header.
- - choice | pass | Bypass malformed messages.
- - choice | discard | Discard malformed messages.
- - choice | respond | Respond with error code.
- required: false
- choices: ["pass", "discard", "respond"]
-
- sip_malformed_header_cseq:
- description:
- - Action for malformed CSeq header.
- - choice | pass | Bypass malformed messages.
- - choice | discard | Discard malformed messages.
- - choice | respond | Respond with error code.
- required: false
- choices: ["pass", "discard", "respond"]
-
- sip_malformed_header_expires:
- description:
- - Action for malformed Expires header.
- - choice | pass | Bypass malformed messages.
- - choice | discard | Discard malformed messages.
- - choice | respond | Respond with error code.
- required: false
- choices: ["pass", "discard", "respond"]
-
- sip_malformed_header_from:
- description:
- - Action for malformed From header.
- - choice | pass | Bypass malformed messages.
- - choice | discard | Discard malformed messages.
- - choice | respond | Respond with error code.
- required: false
- choices: ["pass", "discard", "respond"]
-
- sip_malformed_header_max_forwards:
- description:
- - Action for malformed Max-Forwards header.
- - choice | pass | Bypass malformed messages.
- - choice | discard | Discard malformed messages.
- - choice | respond | Respond with error code.
- required: false
- choices: ["pass", "discard", "respond"]
-
- sip_malformed_header_p_asserted_identity:
- description:
- - Action for malformed P-Asserted-Identity header.
- - choice | pass | Bypass malformed messages.
- - choice | discard | Discard malformed messages.
- - choice | respond | Respond with error code.
- required: false
- choices: ["pass", "discard", "respond"]
-
- sip_malformed_header_rack:
- description:
- - Action for malformed RAck header.
- - choice | pass | Bypass malformed messages.
- - choice | discard | Discard malformed messages.
- - choice | respond | Respond with error code.
- required: false
- choices: ["pass", "discard", "respond"]
-
- sip_malformed_header_record_route:
- description:
- - Action for malformed Record-Route header.
- - choice | pass | Bypass malformed messages.
- - choice | discard | Discard malformed messages.
- - choice | respond | Respond with error code.
- required: false
- choices: ["pass", "discard", "respond"]
-
- sip_malformed_header_route:
- description:
- - Action for malformed Route header.
- - choice | pass | Bypass malformed messages.
- - choice | discard | Discard malformed messages.
- - choice | respond | Respond with error code.
- required: false
- choices: ["pass", "discard", "respond"]
-
- sip_malformed_header_rseq:
- description:
- - Action for malformed RSeq header.
- - choice | pass | Bypass malformed messages.
- - choice | discard | Discard malformed messages.
- - choice | respond | Respond with error code.
- required: false
- choices: ["pass", "discard", "respond"]
-
- sip_malformed_header_sdp_a:
- description:
- - Action for malformed SDP a line.
- - choice | pass | Bypass malformed messages.
- - choice | discard | Discard malformed messages.
- - choice | respond | Respond with error code.
- required: false
- choices: ["pass", "discard", "respond"]
-
- sip_malformed_header_sdp_b:
- description:
- - Action for malformed SDP b line.
- - choice | pass | Bypass malformed messages.
- - choice | discard | Discard malformed messages.
- - choice | respond | Respond with error code.
- required: false
- choices: ["pass", "discard", "respond"]
-
- sip_malformed_header_sdp_c:
- description:
- - Action for malformed SDP c line.
- - choice | pass | Bypass malformed messages.
- - choice | discard | Discard malformed messages.
- - choice | respond | Respond with error code.
- required: false
- choices: ["pass", "discard", "respond"]
-
- sip_malformed_header_sdp_i:
- description:
- - Action for malformed SDP i line.
- - choice | pass | Bypass malformed messages.
- - choice | discard | Discard malformed messages.
- - choice | respond | Respond with error code.
- required: false
- choices: ["pass", "discard", "respond"]
-
- sip_malformed_header_sdp_k:
- description:
- - Action for malformed SDP k line.
- - choice | pass | Bypass malformed messages.
- - choice | discard | Discard malformed messages.
- - choice | respond | Respond with error code.
- required: false
- choices: ["pass", "discard", "respond"]
-
- sip_malformed_header_sdp_m:
- description:
- - Action for malformed SDP m line.
- - choice | pass | Bypass malformed messages.
- - choice | discard | Discard malformed messages.
- - choice | respond | Respond with error code.
- required: false
- choices: ["pass", "discard", "respond"]
-
- sip_malformed_header_sdp_o:
- description:
- - Action for malformed SDP o line.
- - choice | pass | Bypass malformed messages.
- - choice | discard | Discard malformed messages.
- - choice | respond | Respond with error code.
- required: false
- choices: ["pass", "discard", "respond"]
-
- sip_malformed_header_sdp_r:
- description:
- - Action for malformed SDP r line.
- - choice | pass | Bypass malformed messages.
- - choice | discard | Discard malformed messages.
- - choice | respond | Respond with error code.
- required: false
- choices: ["pass", "discard", "respond"]
-
- sip_malformed_header_sdp_s:
- description:
- - Action for malformed SDP s line.
- - choice | pass | Bypass malformed messages.
- - choice | discard | Discard malformed messages.
- - choice | respond | Respond with error code.
- required: false
- choices: ["pass", "discard", "respond"]
-
- sip_malformed_header_sdp_t:
- description:
- - Action for malformed SDP t line.
- - choice | pass | Bypass malformed messages.
- - choice | discard | Discard malformed messages.
- - choice | respond | Respond with error code.
- required: false
- choices: ["pass", "discard", "respond"]
-
- sip_malformed_header_sdp_v:
- description:
- - Action for malformed SDP v line.
- - choice | pass | Bypass malformed messages.
- - choice | discard | Discard malformed messages.
- - choice | respond | Respond with error code.
- required: false
- choices: ["pass", "discard", "respond"]
-
- sip_malformed_header_sdp_z:
- description:
- - Action for malformed SDP z line.
- - choice | pass | Bypass malformed messages.
- - choice | discard | Discard malformed messages.
- - choice | respond | Respond with error code.
- required: false
- choices: ["pass", "discard", "respond"]
-
- sip_malformed_header_to:
- description:
- - Action for malformed To header.
- - choice | pass | Bypass malformed messages.
- - choice | discard | Discard malformed messages.
- - choice | respond | Respond with error code.
- required: false
- choices: ["pass", "discard", "respond"]
-
- sip_malformed_header_via:
- description:
- - Action for malformed VIA header.
- - choice | pass | Bypass malformed messages.
- - choice | discard | Discard malformed messages.
- - choice | respond | Respond with error code.
- required: false
- choices: ["pass", "discard", "respond"]
-
- sip_malformed_request_line:
- description:
- - Action for malformed request line.
- - choice | pass | Bypass malformed messages.
- - choice | discard | Discard malformed messages.
- - choice | respond | Respond with error code.
- required: false
- choices: ["pass", "discard", "respond"]
-
- sip_max_body_length:
- description:
- - Maximum SIP message body length (0 meaning no limit).
- required: false
-
- sip_max_dialogs:
- description:
- - Maximum number of concurrent calls/dialogs (per policy).
- required: false
-
- sip_max_idle_dialogs:
- description:
- - Maximum number established but idle dialogs to retain (per policy).
- required: false
-
- sip_max_line_length:
- description:
- - Maximum SIP header line length (78-4096).
- required: false
-
- sip_message_rate:
- description:
- - MESSAGE request rate limit (per second, per policy).
- required: false
-
- sip_nat_trace:
- description:
- - Enable/disable preservation of original IP in SDP i line.
- - choice | disable | Disable status.
- - choice | enable | Enable status.
- required: false
- choices: ["disable", "enable"]
-
- sip_no_sdp_fixup:
- description:
- - Enable/disable no SDP fix-up.
- - choice | disable | Disable status.
- - choice | enable | Enable status.
- required: false
- choices: ["disable", "enable"]
-
- sip_notify_rate:
- description:
- - NOTIFY request rate limit (per second, per policy).
- required: false
-
- sip_open_contact_pinhole:
- description:
- - Enable/disable open pinhole for non-REGISTER Contact port.
- - choice | disable | Disable status.
- - choice | enable | Enable status.
- required: false
- choices: ["disable", "enable"]
-
- sip_open_record_route_pinhole:
- description:
- - Enable/disable open pinhole for Record-Route port.
- - choice | disable | Disable status.
- - choice | enable | Enable status.
- required: false
- choices: ["disable", "enable"]
-
- sip_open_register_pinhole:
- description:
- - Enable/disable open pinhole for REGISTER Contact port.
- - choice | disable | Disable status.
- - choice | enable | Enable status.
- required: false
- choices: ["disable", "enable"]
-
- sip_open_via_pinhole:
- description:
- - Enable/disable open pinhole for Via port.
- - choice | disable | Disable status.
- - choice | enable | Enable status.
- required: false
- choices: ["disable", "enable"]
-
- sip_options_rate:
- description:
- - OPTIONS request rate limit (per second, per policy).
- required: false
-
- sip_prack_rate:
- description:
- - PRACK request rate limit (per second, per policy).
- required: false
-
- sip_preserve_override:
- description:
- - Override i line to preserve original IPS (default| append).
- - choice | disable | Disable status.
- - choice | enable | Enable status.
- required: false
- choices: ["disable", "enable"]
-
- sip_provisional_invite_expiry_time:
- description:
- - Expiry time for provisional INVITE (10 - 3600 sec).
- required: false
-
- sip_publish_rate:
- description:
- - PUBLISH request rate limit (per second, per policy).
- required: false
-
- sip_refer_rate:
- description:
- - REFER request rate limit (per second, per policy).
- required: false
-
- sip_register_contact_trace:
- description:
- - Enable/disable trace original IP/port within the contact header of REGISTER requests.
- - choice | disable | Disable status.
- - choice | enable | Enable status.
- required: false
- choices: ["disable", "enable"]
-
- sip_register_rate:
- description:
- - REGISTER request rate limit (per second, per policy).
- required: false
-
- sip_rfc2543_branch:
- description:
- - Enable/disable support via branch compliant with RFC 2543.
- - choice | disable | Disable status.
- - choice | enable | Enable status.
- required: false
- choices: ["disable", "enable"]
-
- sip_rtp:
- description:
- - Enable/disable create pinholes for RTP traffic to traverse firewall.
- - choice | disable | Disable status.
- - choice | enable | Enable status.
- required: false
- choices: ["disable", "enable"]
-
- sip_ssl_algorithm:
- description:
- - Relative strength of encryption algorithms accepted in negotiation.
- - choice | high | High encryption. Allow only AES and ChaCha.
- - choice | medium | Medium encryption. Allow AES, ChaCha, 3DES, and RC4.
- - choice | low | Low encryption. Allow AES, ChaCha, 3DES, RC4, and DES.
- required: false
- choices: ["high", "medium", "low"]
-
- sip_ssl_auth_client:
- description:
- - Require a client certificate and authenticate it with the peer/peergrp.
- required: false
-
- sip_ssl_auth_server:
- description:
- - Authenticate the server's certificate with the peer/peergrp.
- required: false
-
- sip_ssl_client_certificate:
- description:
- - Name of Certificate to offer to server if requested.
- required: false
-
- sip_ssl_client_renegotiation:
- description:
- - Allow/block client renegotiation by server.
- - choice | allow | Allow a SSL client to renegotiate.
- - choice | deny | Abort any SSL connection that attempts to renegotiate.
- - choice | secure | Reject any SSL connection that does not offer a RFC 5746 Secure Renegotiation Indication.
- required: false
- choices: ["allow", "deny", "secure"]
-
- sip_ssl_max_version:
- description:
- - Highest SSL/TLS version to negotiate.
- - choice | ssl-3.0 | SSL 3.0.
- - choice | tls-1.0 | TLS 1.0.
- - choice | tls-1.1 | TLS 1.1.
- - choice | tls-1.2 | TLS 1.2.
- required: false
- choices: ["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]
-
- sip_ssl_min_version:
- description:
- - Lowest SSL/TLS version to negotiate.
- - choice | ssl-3.0 | SSL 3.0.
- - choice | tls-1.0 | TLS 1.0.
- - choice | tls-1.1 | TLS 1.1.
- - choice | tls-1.2 | TLS 1.2.
- required: false
- choices: ["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]
-
- sip_ssl_mode:
- description:
- - SSL/TLS mode for encryption &amp; decryption of traffic.
- - choice | off | No SSL.
- - choice | full | Client to FortiGate and FortiGate to Server SSL.
- required: false
- choices: ["off", "full"]
-
- sip_ssl_pfs:
- description:
- - SSL Perfect Forward Secrecy.
- - choice | require | PFS mandatory.
- - choice | deny | PFS rejected.
- - choice | allow | PFS allowed.
- required: false
- choices: ["require", "deny", "allow"]
-
- sip_ssl_send_empty_frags:
- description:
- - Send empty fragments to avoid attack on CBC IV (SSL 3.0 &amp; TLS 1.0 only).
- - choice | disable | Do not send empty fragments.
- - choice | enable | Send empty fragments.
- required: false
- choices: ["disable", "enable"]
-
- sip_ssl_server_certificate:
- description:
- - Name of Certificate return to the client in every SSL connection.
- required: false
-
- sip_status:
- description:
- - Enable/disable SIP.
- - choice | disable | Disable status.
- - choice | enable | Enable status.
- required: false
- choices: ["disable", "enable"]
-
- sip_strict_register:
- description:
- - Enable/disable only allow the registrar to connect.
- - choice | disable | Disable status.
- - choice | enable | Enable status.
- required: false
- choices: ["disable", "enable"]
-
- sip_subscribe_rate:
- description:
- - SUBSCRIBE request rate limit (per second, per policy).
- required: false
-
- sip_unknown_header:
- description:
- - Action for unknown SIP header.
- - choice | pass | Bypass malformed messages.
- - choice | discard | Discard malformed messages.
- - choice | respond | Respond with error code.
- required: false
- choices: ["pass", "discard", "respond"]
-
- sip_update_rate:
- description:
- - UPDATE request rate limit (per second, per policy).
- required: false
-
-
-'''
-
-EXAMPLES = '''
- - name: DELETE Profile
- community.fortios.fmgr_secprof_voip:
- name: "Ansible_VOIP_Profile"
- mode: "delete"
-
- - name: Create FMGR_VOIP_PROFILE
- community.fortios.fmgr_secprof_voip:
- mode: "set"
- adom: "root"
- name: "Ansible_VOIP_Profile"
- comment: "Created by Ansible"
- sccp: {block-mcast: "enable", log-call-summary: "enable", log-violations: "enable", status: "enable"}
-'''
-
-RETURN = """
-api_result:
- description: full API response, includes status code and message
- returned: always
- type: str
-"""
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.connection import Connection
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import prepare_dict
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import scrub_dict
-
-
-###############
-# START METHODS
-###############
-
-
-def fmgr_voip_profile_modify(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
-
- mode = paramgram["mode"]
- adom = paramgram["adom"]
-
- response = DEFAULT_RESULT_OBJ
- url = ""
- datagram = {}
-
- # EVAL THE MODE PARAMETER FOR SET OR ADD
- if mode in ['set', 'add', 'update']:
- url = '/pm/config/adom/{adom}/obj/voip/profile'.format(adom=adom)
- datagram = scrub_dict(prepare_dict(paramgram))
-
- # EVAL THE MODE PARAMETER FOR DELETE
- elif mode == "delete":
- # SET THE CORRECT URL FOR DELETE
- url = '/pm/config/adom/{adom}/obj/voip/profile/{name}'.format(adom=adom, name=paramgram["name"])
- datagram = {}
-
- response = fmgr.process_request(url, datagram, paramgram["mode"])
-
- return response
-
-
-#############
-# END METHODS
-#############
-
-
-def main():
- argument_spec = dict(
- adom=dict(type="str", default="root"),
- mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),
-
- name=dict(required=False, type="str"),
- comment=dict(required=False, type="str"),
- sccp=dict(required=False, type="dict"),
- sccp_block_mcast=dict(required=False, type="str", choices=["disable", "enable"]),
- sccp_log_call_summary=dict(required=False, type="str", choices=["disable", "enable"]),
- sccp_log_violations=dict(required=False, type="str", choices=["disable", "enable"]),
- sccp_max_calls=dict(required=False, type="int"),
- sccp_status=dict(required=False, type="str", choices=["disable", "enable"]),
- sccp_verify_header=dict(required=False, type="str", choices=["disable", "enable"]),
- sip=dict(required=False, type="dict"),
- sip_ack_rate=dict(required=False, type="int"),
- sip_block_ack=dict(required=False, type="str", choices=["disable", "enable"]),
- sip_block_bye=dict(required=False, type="str", choices=["disable", "enable"]),
- sip_block_cancel=dict(required=False, type="str", choices=["disable", "enable"]),
- sip_block_geo_red_options=dict(required=False, type="str", choices=["disable", "enable"]),
- sip_block_info=dict(required=False, type="str", choices=["disable", "enable"]),
- sip_block_invite=dict(required=False, type="str", choices=["disable", "enable"]),
- sip_block_long_lines=dict(required=False, type="str", choices=["disable", "enable"]),
- sip_block_message=dict(required=False, type="str", choices=["disable", "enable"]),
- sip_block_notify=dict(required=False, type="str", choices=["disable", "enable"]),
- sip_block_options=dict(required=False, type="str", choices=["disable", "enable"]),
- sip_block_prack=dict(required=False, type="str", choices=["disable", "enable"]),
- sip_block_publish=dict(required=False, type="str", choices=["disable", "enable"]),
- sip_block_refer=dict(required=False, type="str", choices=["disable", "enable"]),
- sip_block_register=dict(required=False, type="str", choices=["disable", "enable"]),
- sip_block_subscribe=dict(required=False, type="str", choices=["disable", "enable"]),
- sip_block_unknown=dict(required=False, type="str", choices=["disable", "enable"]),
- sip_block_update=dict(required=False, type="str", choices=["disable", "enable"]),
- sip_bye_rate=dict(required=False, type="int"),
- sip_call_keepalive=dict(required=False, type="int"),
- sip_cancel_rate=dict(required=False, type="int"),
- sip_contact_fixup=dict(required=False, type="str", choices=["disable", "enable"]),
- sip_hnt_restrict_source_ip=dict(required=False, type="str", choices=["disable", "enable"]),
- sip_hosted_nat_traversal=dict(required=False, type="str", choices=["disable", "enable"]),
- sip_info_rate=dict(required=False, type="int"),
- sip_invite_rate=dict(required=False, type="int"),
- sip_ips_rtp=dict(required=False, type="str", choices=["disable", "enable"]),
- sip_log_call_summary=dict(required=False, type="str", choices=["disable", "enable"]),
- sip_log_violations=dict(required=False, type="str", choices=["disable", "enable"]),
- sip_malformed_header_allow=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
- sip_malformed_header_call_id=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
- sip_malformed_header_contact=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
- sip_malformed_header_content_length=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
- sip_malformed_header_content_type=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
- sip_malformed_header_cseq=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
- sip_malformed_header_expires=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
- sip_malformed_header_from=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
- sip_malformed_header_max_forwards=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
- sip_malformed_header_p_asserted_identity=dict(required=False, type="str", choices=["pass",
- "discard",
- "respond"]),
- sip_malformed_header_rack=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
- sip_malformed_header_record_route=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
- sip_malformed_header_route=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
- sip_malformed_header_rseq=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
- sip_malformed_header_sdp_a=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
- sip_malformed_header_sdp_b=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
- sip_malformed_header_sdp_c=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
- sip_malformed_header_sdp_i=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
- sip_malformed_header_sdp_k=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
- sip_malformed_header_sdp_m=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
- sip_malformed_header_sdp_o=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
- sip_malformed_header_sdp_r=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
- sip_malformed_header_sdp_s=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
- sip_malformed_header_sdp_t=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
- sip_malformed_header_sdp_v=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
- sip_malformed_header_sdp_z=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
- sip_malformed_header_to=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
- sip_malformed_header_via=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
- sip_malformed_request_line=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
- sip_max_body_length=dict(required=False, type="int"),
- sip_max_dialogs=dict(required=False, type="int"),
- sip_max_idle_dialogs=dict(required=False, type="int"),
- sip_max_line_length=dict(required=False, type="int"),
- sip_message_rate=dict(required=False, type="int"),
- sip_nat_trace=dict(required=False, type="str", choices=["disable", "enable"]),
- sip_no_sdp_fixup=dict(required=False, type="str", choices=["disable", "enable"]),
- sip_notify_rate=dict(required=False, type="int"),
- sip_open_contact_pinhole=dict(required=False, type="str", choices=["disable", "enable"]),
- sip_open_record_route_pinhole=dict(required=False, type="str", choices=["disable", "enable"]),
- sip_open_register_pinhole=dict(required=False, type="str", choices=["disable", "enable"]),
- sip_open_via_pinhole=dict(required=False, type="str", choices=["disable", "enable"]),
- sip_options_rate=dict(required=False, type="int"),
- sip_prack_rate=dict(required=False, type="int"),
- sip_preserve_override=dict(required=False, type="str", choices=["disable", "enable"]),
- sip_provisional_invite_expiry_time=dict(required=False, type="int"),
- sip_publish_rate=dict(required=False, type="int"),
- sip_refer_rate=dict(required=False, type="int"),
- sip_register_contact_trace=dict(required=False, type="str", choices=["disable", "enable"]),
- sip_register_rate=dict(required=False, type="int"),
- sip_rfc2543_branch=dict(required=False, type="str", choices=["disable", "enable"]),
- sip_rtp=dict(required=False, type="str", choices=["disable", "enable"]),
- sip_ssl_algorithm=dict(required=False, type="str", choices=["high", "medium", "low"]),
- sip_ssl_auth_client=dict(required=False, type="str"),
- sip_ssl_auth_server=dict(required=False, type="str"),
- sip_ssl_client_certificate=dict(required=False, type="str"),
- sip_ssl_client_renegotiation=dict(required=False, type="str", choices=["allow", "deny", "secure"]),
- sip_ssl_max_version=dict(required=False, type="str", choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]),
- sip_ssl_min_version=dict(required=False, type="str", choices=["ssl-3.0", "tls-1.0", "tls-1.1", "tls-1.2"]),
- sip_ssl_mode=dict(required=False, type="str", choices=["off", "full"]),
- sip_ssl_pfs=dict(required=False, type="str", choices=["require", "deny", "allow"]),
- sip_ssl_send_empty_frags=dict(required=False, type="str", choices=["disable", "enable"]),
- sip_ssl_server_certificate=dict(required=False, type="str"),
- sip_status=dict(required=False, type="str", choices=["disable", "enable"]),
- sip_strict_register=dict(required=False, type="str", choices=["disable", "enable"]),
- sip_subscribe_rate=dict(required=False, type="int"),
- sip_unknown_header=dict(required=False, type="str", choices=["pass", "discard", "respond"]),
- sip_update_rate=dict(required=False, type="int"),
-
- )
-
- module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
- # MODULE PARAMGRAM
- paramgram = {
- "mode": module.params["mode"],
- "adom": module.params["adom"],
- "name": module.params["name"],
- "comment": module.params["comment"],
- "sccp": {
- "block-mcast": module.params["sccp_block_mcast"],
- "log-call-summary": module.params["sccp_log_call_summary"],
- "log-violations": module.params["sccp_log_violations"],
- "max-calls": module.params["sccp_max_calls"],
- "status": module.params["sccp_status"],
- "verify-header": module.params["sccp_verify_header"],
- },
- "sip": {
- "ack-rate": module.params["sip_ack_rate"],
- "block-ack": module.params["sip_block_ack"],
- "block-bye": module.params["sip_block_bye"],
- "block-cancel": module.params["sip_block_cancel"],
- "block-geo-red-options": module.params["sip_block_geo_red_options"],
- "block-info": module.params["sip_block_info"],
- "block-invite": module.params["sip_block_invite"],
- "block-long-lines": module.params["sip_block_long_lines"],
- "block-message": module.params["sip_block_message"],
- "block-notify": module.params["sip_block_notify"],
- "block-options": module.params["sip_block_options"],
- "block-prack": module.params["sip_block_prack"],
- "block-publish": module.params["sip_block_publish"],
- "block-refer": module.params["sip_block_refer"],
- "block-register": module.params["sip_block_register"],
- "block-subscribe": module.params["sip_block_subscribe"],
- "block-unknown": module.params["sip_block_unknown"],
- "block-update": module.params["sip_block_update"],
- "bye-rate": module.params["sip_bye_rate"],
- "call-keepalive": module.params["sip_call_keepalive"],
- "cancel-rate": module.params["sip_cancel_rate"],
- "contact-fixup": module.params["sip_contact_fixup"],
- "hnt-restrict-source-ip": module.params["sip_hnt_restrict_source_ip"],
- "hosted-nat-traversal": module.params["sip_hosted_nat_traversal"],
- "info-rate": module.params["sip_info_rate"],
- "invite-rate": module.params["sip_invite_rate"],
- "ips-rtp": module.params["sip_ips_rtp"],
- "log-call-summary": module.params["sip_log_call_summary"],
- "log-violations": module.params["sip_log_violations"],
- "malformed-header-allow": module.params["sip_malformed_header_allow"],
- "malformed-header-call-id": module.params["sip_malformed_header_call_id"],
- "malformed-header-contact": module.params["sip_malformed_header_contact"],
- "malformed-header-content-length": module.params["sip_malformed_header_content_length"],
- "malformed-header-content-type": module.params["sip_malformed_header_content_type"],
- "malformed-header-cseq": module.params["sip_malformed_header_cseq"],
- "malformed-header-expires": module.params["sip_malformed_header_expires"],
- "malformed-header-from": module.params["sip_malformed_header_from"],
- "malformed-header-max-forwards": module.params["sip_malformed_header_max_forwards"],
- "malformed-header-p-asserted-identity": module.params["sip_malformed_header_p_asserted_identity"],
- "malformed-header-rack": module.params["sip_malformed_header_rack"],
- "malformed-header-record-route": module.params["sip_malformed_header_record_route"],
- "malformed-header-route": module.params["sip_malformed_header_route"],
- "malformed-header-rseq": module.params["sip_malformed_header_rseq"],
- "malformed-header-sdp-a": module.params["sip_malformed_header_sdp_a"],
- "malformed-header-sdp-b": module.params["sip_malformed_header_sdp_b"],
- "malformed-header-sdp-c": module.params["sip_malformed_header_sdp_c"],
- "malformed-header-sdp-i": module.params["sip_malformed_header_sdp_i"],
- "malformed-header-sdp-k": module.params["sip_malformed_header_sdp_k"],
- "malformed-header-sdp-m": module.params["sip_malformed_header_sdp_m"],
- "malformed-header-sdp-o": module.params["sip_malformed_header_sdp_o"],
- "malformed-header-sdp-r": module.params["sip_malformed_header_sdp_r"],
- "malformed-header-sdp-s": module.params["sip_malformed_header_sdp_s"],
- "malformed-header-sdp-t": module.params["sip_malformed_header_sdp_t"],
- "malformed-header-sdp-v": module.params["sip_malformed_header_sdp_v"],
- "malformed-header-sdp-z": module.params["sip_malformed_header_sdp_z"],
- "malformed-header-to": module.params["sip_malformed_header_to"],
- "malformed-header-via": module.params["sip_malformed_header_via"],
- "malformed-request-line": module.params["sip_malformed_request_line"],
- "max-body-length": module.params["sip_max_body_length"],
- "max-dialogs": module.params["sip_max_dialogs"],
- "max-idle-dialogs": module.params["sip_max_idle_dialogs"],
- "max-line-length": module.params["sip_max_line_length"],
- "message-rate": module.params["sip_message_rate"],
- "nat-trace": module.params["sip_nat_trace"],
- "no-sdp-fixup": module.params["sip_no_sdp_fixup"],
- "notify-rate": module.params["sip_notify_rate"],
- "open-contact-pinhole": module.params["sip_open_contact_pinhole"],
- "open-record-route-pinhole": module.params["sip_open_record_route_pinhole"],
- "open-register-pinhole": module.params["sip_open_register_pinhole"],
- "open-via-pinhole": module.params["sip_open_via_pinhole"],
- "options-rate": module.params["sip_options_rate"],
- "prack-rate": module.params["sip_prack_rate"],
- "preserve-override": module.params["sip_preserve_override"],
- "provisional-invite-expiry-time": module.params["sip_provisional_invite_expiry_time"],
- "publish-rate": module.params["sip_publish_rate"],
- "refer-rate": module.params["sip_refer_rate"],
- "register-contact-trace": module.params["sip_register_contact_trace"],
- "register-rate": module.params["sip_register_rate"],
- "rfc2543-branch": module.params["sip_rfc2543_branch"],
- "rtp": module.params["sip_rtp"],
- "ssl-algorithm": module.params["sip_ssl_algorithm"],
- "ssl-auth-client": module.params["sip_ssl_auth_client"],
- "ssl-auth-server": module.params["sip_ssl_auth_server"],
- "ssl-client-certificate": module.params["sip_ssl_client_certificate"],
- "ssl-client-renegotiation": module.params["sip_ssl_client_renegotiation"],
- "ssl-max-version": module.params["sip_ssl_max_version"],
- "ssl-min-version": module.params["sip_ssl_min_version"],
- "ssl-mode": module.params["sip_ssl_mode"],
- "ssl-pfs": module.params["sip_ssl_pfs"],
- "ssl-send-empty-frags": module.params["sip_ssl_send_empty_frags"],
- "ssl-server-certificate": module.params["sip_ssl_server_certificate"],
- "status": module.params["sip_status"],
- "strict-register": module.params["sip_strict_register"],
- "subscribe-rate": module.params["sip_subscribe_rate"],
- "unknown-header": module.params["sip_unknown_header"],
- "update-rate": module.params["sip_update_rate"],
- }
- }
-
- module.paramgram = paramgram
- fmgr = None
- if module._socket_path:
- connection = Connection(module._socket_path)
- fmgr = FortiManagerHandler(connection, module)
- fmgr.tools = FMGRCommon()
- else:
- module.fail_json(**FAIL_SOCKET_MSG)
-
- list_overrides = ['sccp', 'sip']
- paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
- paramgram=paramgram, module=module)
- module.paramgram = paramgram
-
- results = DEFAULT_RESULT_OBJ
- try:
-
- results = fmgr_voip_profile_modify(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
-
- except Exception as err:
- raise FMGBaseException(err)
-
- return module.exit_json(**results[1])
-
-
-if __name__ == "__main__":
- main()
diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_waf.py b/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_waf.py
deleted file mode 100644
index 6d7f40401..000000000
--- a/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_waf.py
+++ /dev/null
@@ -1,1477 +0,0 @@
-#!/usr/bin/python
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of`
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-
-from __future__ import absolute_import, division, print_function
-
-__metaclass__ = type
-
-DOCUMENTATION = '''
----
-module: fmgr_secprof_waf
-notes:
- - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
-author:
- - Luke Weighall (@lweighall)
- - Andrew Welsh (@Ghilli3)
- - Jim Huber (@p4r4n0y1ng)
-short_description: FortiManager web application firewall security profile
-description:
- - Manage web application firewall security profiles for FGTs via FMG
-
-options:
- adom:
- description:
- - The ADOM the configuration should belong to.
- required: false
- default: root
-
- mode:
- description:
- - Sets one of three modes for managing the object.
- - Allows use of soft-adds instead of overwriting existing values
- choices: ['add', 'set', 'delete', 'update']
- required: false
- default: add
-
- name:
- description:
- - WAF Profile name.
- required: false
-
- external:
- description:
- - Disable/Enable external HTTP Inspection.
- - choice | disable | Disable external inspection.
- - choice | enable | Enable external inspection.
- required: false
- choices: ["disable", "enable"]
-
- extended_log:
- description:
- - Enable/disable extended logging.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- comment:
- description:
- - Comment.
- required: false
-
- address_list:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- address_list_blocked_address:
- description:
- - Blocked address.
- required: false
-
- address_list_blocked_log:
- description:
- - Enable/disable logging on blocked addresses.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- address_list_severity:
- description:
- - Severity.
- - choice | low | Low severity.
- - choice | medium | Medium severity.
- - choice | high | High severity.
- required: false
- choices: ["low", "medium", "high"]
-
- address_list_status:
- description:
- - Status.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- address_list_trusted_address:
- description:
- - Trusted address.
- required: false
-
- constraint:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- constraint_content_length_action:
- description:
- - Action.
- - choice | allow | Allow.
- - choice | block | Block.
- required: false
- choices: ["allow", "block"]
-
- constraint_content_length_length:
- description:
- - Length of HTTP content in bytes (0 to 2147483647).
- required: false
-
- constraint_content_length_log:
- description:
- - Enable/disable logging.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- constraint_content_length_severity:
- description:
- - Severity.
- - choice | low | Low severity.
- - choice | medium | Medium severity.
- - choice | high | High severity.
- required: false
- choices: ["low", "medium", "high"]
-
- constraint_content_length_status:
- description:
- - Enable/disable the constraint.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- constraint_exception_address:
- description:
- - Host address.
- required: false
-
- constraint_exception_content_length:
- description:
- - HTTP content length in request.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- constraint_exception_header_length:
- description:
- - HTTP header length in request.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- constraint_exception_hostname:
- description:
- - Enable/disable hostname check.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- constraint_exception_line_length:
- description:
- - HTTP line length in request.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- constraint_exception_malformed:
- description:
- - Enable/disable malformed HTTP request check.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- constraint_exception_max_cookie:
- description:
- - Maximum number of cookies in HTTP request.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- constraint_exception_max_header_line:
- description:
- - Maximum number of HTTP header line.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- constraint_exception_max_range_segment:
- description:
- - Maximum number of range segments in HTTP range line.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- constraint_exception_max_url_param:
- description:
- - Maximum number of parameters in URL.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- constraint_exception_method:
- description:
- - Enable/disable HTTP method check.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- constraint_exception_param_length:
- description:
- - Maximum length of parameter in URL, HTTP POST request or HTTP body.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- constraint_exception_pattern:
- description:
- - URL pattern.
- required: false
-
- constraint_exception_regex:
- description:
- - Enable/disable regular expression based pattern match.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- constraint_exception_url_param_length:
- description:
- - Maximum length of parameter in URL.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- constraint_exception_version:
- description:
- - Enable/disable HTTP version check.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- constraint_header_length_action:
- description:
- - Action.
- - choice | allow | Allow.
- - choice | block | Block.
- required: false
- choices: ["allow", "block"]
-
- constraint_header_length_length:
- description:
- - Length of HTTP header in bytes (0 to 2147483647).
- required: false
-
- constraint_header_length_log:
- description:
- - Enable/disable logging.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- constraint_header_length_severity:
- description:
- - Severity.
- - choice | low | Low severity.
- - choice | medium | Medium severity.
- - choice | high | High severity.
- required: false
- choices: ["low", "medium", "high"]
-
- constraint_header_length_status:
- description:
- - Enable/disable the constraint.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- constraint_hostname_action:
- description:
- - Action for a hostname constraint.
- - choice | allow | Allow.
- - choice | block | Block.
- required: false
- choices: ["allow", "block"]
-
- constraint_hostname_log:
- description:
- - Enable/disable logging.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- constraint_hostname_severity:
- description:
- - Severity.
- - choice | low | Low severity.
- - choice | medium | Medium severity.
- - choice | high | High severity.
- required: false
- choices: ["low", "medium", "high"]
-
- constraint_hostname_status:
- description:
- - Enable/disable the constraint.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- constraint_line_length_action:
- description:
- - Action.
- - choice | allow | Allow.
- - choice | block | Block.
- required: false
- choices: ["allow", "block"]
-
- constraint_line_length_length:
- description:
- - Length of HTTP line in bytes (0 to 2147483647).
- required: false
-
- constraint_line_length_log:
- description:
- - Enable/disable logging.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- constraint_line_length_severity:
- description:
- - Severity.
- - choice | low | Low severity.
- - choice | medium | Medium severity.
- - choice | high | High severity.
- required: false
- choices: ["low", "medium", "high"]
-
- constraint_line_length_status:
- description:
- - Enable/disable the constraint.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- constraint_malformed_action:
- description:
- - Action.
- - choice | allow | Allow.
- - choice | block | Block.
- required: false
- choices: ["allow", "block"]
-
- constraint_malformed_log:
- description:
- - Enable/disable logging.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- constraint_malformed_severity:
- description:
- - Severity.
- - choice | low | Low severity.
- - choice | medium | Medium severity.
- - choice | high | High severity.
- required: false
- choices: ["low", "medium", "high"]
-
- constraint_malformed_status:
- description:
- - Enable/disable the constraint.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- constraint_max_cookie_action:
- description:
- - Action.
- - choice | allow | Allow.
- - choice | block | Block.
- required: false
- choices: ["allow", "block"]
-
- constraint_max_cookie_log:
- description:
- - Enable/disable logging.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- constraint_max_cookie_max_cookie:
- description:
- - Maximum number of cookies in HTTP request (0 to 2147483647).
- required: false
-
- constraint_max_cookie_severity:
- description:
- - Severity.
- - choice | low | Low severity.
- - choice | medium | Medium severity.
- - choice | high | High severity.
- required: false
- choices: ["low", "medium", "high"]
-
- constraint_max_cookie_status:
- description:
- - Enable/disable the constraint.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- constraint_max_header_line_action:
- description:
- - Action.
- - choice | allow | Allow.
- - choice | block | Block.
- required: false
- choices: ["allow", "block"]
-
- constraint_max_header_line_log:
- description:
- - Enable/disable logging.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- constraint_max_header_line_max_header_line:
- description:
- - Maximum number HTTP header lines (0 to 2147483647).
- required: false
-
- constraint_max_header_line_severity:
- description:
- - Severity.
- - choice | low | Low severity.
- - choice | medium | Medium severity.
- - choice | high | High severity.
- required: false
- choices: ["low", "medium", "high"]
-
- constraint_max_header_line_status:
- description:
- - Enable/disable the constraint.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- constraint_max_range_segment_action:
- description:
- - Action.
- - choice | allow | Allow.
- - choice | block | Block.
- required: false
- choices: ["allow", "block"]
-
- constraint_max_range_segment_log:
- description:
- - Enable/disable logging.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- constraint_max_range_segment_max_range_segment:
- description:
- - Maximum number of range segments in HTTP range line (0 to 2147483647).
- required: false
-
- constraint_max_range_segment_severity:
- description:
- - Severity.
- - choice | low | Low severity.
- - choice | medium | Medium severity.
- - choice | high | High severity.
- required: false
- choices: ["low", "medium", "high"]
-
- constraint_max_range_segment_status:
- description:
- - Enable/disable the constraint.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- constraint_max_url_param_action:
- description:
- - Action.
- - choice | allow | Allow.
- - choice | block | Block.
- required: false
- choices: ["allow", "block"]
-
- constraint_max_url_param_log:
- description:
- - Enable/disable logging.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- constraint_max_url_param_max_url_param:
- description:
- - Maximum number of parameters in URL (0 to 2147483647).
- required: false
-
- constraint_max_url_param_severity:
- description:
- - Severity.
- - choice | low | Low severity.
- - choice | medium | Medium severity.
- - choice | high | High severity.
- required: false
- choices: ["low", "medium", "high"]
-
- constraint_max_url_param_status:
- description:
- - Enable/disable the constraint.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- constraint_method_action:
- description:
- - Action.
- - choice | allow | Allow.
- - choice | block | Block.
- required: false
- choices: ["allow", "block"]
-
- constraint_method_log:
- description:
- - Enable/disable logging.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- constraint_method_severity:
- description:
- - Severity.
- - choice | low | Low severity.
- - choice | medium | Medium severity.
- - choice | high | High severity.
- required: false
- choices: ["low", "medium", "high"]
-
- constraint_method_status:
- description:
- - Enable/disable the constraint.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- constraint_param_length_action:
- description:
- - Action.
- - choice | allow | Allow.
- - choice | block | Block.
- required: false
- choices: ["allow", "block"]
-
- constraint_param_length_length:
- description:
- - Maximum length of parameter in URL, HTTP POST request or HTTP body in bytes (0 to 2147483647).
- required: false
-
- constraint_param_length_log:
- description:
- - Enable/disable logging.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- constraint_param_length_severity:
- description:
- - Severity.
- - choice | low | Low severity.
- - choice | medium | Medium severity.
- - choice | high | High severity.
- required: false
- choices: ["low", "medium", "high"]
-
- constraint_param_length_status:
- description:
- - Enable/disable the constraint.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- constraint_url_param_length_action:
- description:
- - Action.
- - choice | allow | Allow.
- - choice | block | Block.
- required: false
- choices: ["allow", "block"]
-
- constraint_url_param_length_length:
- description:
- - Maximum length of URL parameter in bytes (0 to 2147483647).
- required: false
-
- constraint_url_param_length_log:
- description:
- - Enable/disable logging.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- constraint_url_param_length_severity:
- description:
- - Severity.
- - choice | low | Low severity.
- - choice | medium | Medium severity.
- - choice | high | High severity.
- required: false
- choices: ["low", "medium", "high"]
-
- constraint_url_param_length_status:
- description:
- - Enable/disable the constraint.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- constraint_version_action:
- description:
- - Action.
- - choice | allow | Allow.
- - choice | block | Block.
- required: false
- choices: ["allow", "block"]
-
- constraint_version_log:
- description:
- - Enable/disable logging.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- constraint_version_severity:
- description:
- - Severity.
- - choice | low | Low severity.
- - choice | medium | Medium severity.
- - choice | high | High severity.
- required: false
- choices: ["low", "medium", "high"]
-
- constraint_version_status:
- description:
- - Enable/disable the constraint.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- method:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- method_default_allowed_methods:
- description:
- - Methods.
- - FLAG Based Options. Specify multiple in list form.
- - flag | delete | HTTP DELETE method.
- - flag | get | HTTP GET method.
- - flag | head | HTTP HEAD method.
- - flag | options | HTTP OPTIONS method.
- - flag | post | HTTP POST method.
- - flag | put | HTTP PUT method.
- - flag | trace | HTTP TRACE method.
- - flag | others | Other HTTP methods.
- - flag | connect | HTTP CONNECT method.
- required: false
- choices: ["delete", "get", "head", "options", "post", "put", "trace", "others", "connect"]
-
- method_log:
- description:
- - Enable/disable logging.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- method_severity:
- description:
- - Severity.
- - choice | low | low severity
- - choice | medium | medium severity
- - choice | high | High severity
- required: false
- choices: ["low", "medium", "high"]
-
- method_status:
- description:
- - Status.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- method_method_policy_address:
- description:
- - Host address.
- required: false
-
- method_method_policy_allowed_methods:
- description:
- - Allowed Methods.
- - FLAG Based Options. Specify multiple in list form.
- - flag | delete | HTTP DELETE method.
- - flag | get | HTTP GET method.
- - flag | head | HTTP HEAD method.
- - flag | options | HTTP OPTIONS method.
- - flag | post | HTTP POST method.
- - flag | put | HTTP PUT method.
- - flag | trace | HTTP TRACE method.
- - flag | others | Other HTTP methods.
- - flag | connect | HTTP CONNECT method.
- required: false
- choices: ["delete", "get", "head", "options", "post", "put", "trace", "others", "connect"]
-
- method_method_policy_pattern:
- description:
- - URL pattern.
- required: false
-
- method_method_policy_regex:
- description:
- - Enable/disable regular expression based pattern match.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- signature:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- signature_credit_card_detection_threshold:
- description:
- - The minimum number of Credit cards to detect violation.
- required: false
-
- signature_disabled_signature:
- description:
- - Disabled signatures
- required: false
-
- signature_disabled_sub_class:
- description:
- - Disabled signature subclasses.
- required: false
-
- signature_custom_signature_action:
- description:
- - Action.
- - choice | allow | Allow.
- - choice | block | Block.
- - choice | erase | Erase credit card numbers.
- required: false
- choices: ["allow", "block", "erase"]
-
- signature_custom_signature_case_sensitivity:
- description:
- - Case sensitivity in pattern.
- - choice | disable | Case insensitive in pattern.
- - choice | enable | Case sensitive in pattern.
- required: false
- choices: ["disable", "enable"]
-
- signature_custom_signature_direction:
- description:
- - Traffic direction.
- - choice | request | Match HTTP request.
- - choice | response | Match HTTP response.
- required: false
- choices: ["request", "response"]
-
- signature_custom_signature_log:
- description:
- - Enable/disable logging.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- signature_custom_signature_name:
- description:
- - Signature name.
- required: false
-
- signature_custom_signature_pattern:
- description:
- - Match pattern.
- required: false
-
- signature_custom_signature_severity:
- description:
- - Severity.
- - choice | low | Low severity.
- - choice | medium | Medium severity.
- - choice | high | High severity.
- required: false
- choices: ["low", "medium", "high"]
-
- signature_custom_signature_status:
- description:
- - Status.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- signature_custom_signature_target:
- description:
- - Match HTTP target.
- - FLAG Based Options. Specify multiple in list form.
- - flag | arg | HTTP arguments.
- - flag | arg-name | Names of HTTP arguments.
- - flag | req-body | HTTP request body.
- - flag | req-cookie | HTTP request cookies.
- - flag | req-cookie-name | HTTP request cookie names.
- - flag | req-filename | HTTP request file name.
- - flag | req-header | HTTP request headers.
- - flag | req-header-name | HTTP request header names.
- - flag | req-raw-uri | Raw URI of HTTP request.
- - flag | req-uri | URI of HTTP request.
- - flag | resp-body | HTTP response body.
- - flag | resp-hdr | HTTP response headers.
- - flag | resp-status | HTTP response status.
- required: false
- choices: ["arg","arg-name","req-body","req-cookie","req-cookie-name","req-filename","req-header","req-header-name",
- "req-raw-uri","req-uri","resp-body","resp-hdr","resp-status"]
-
- signature_main_class_action:
- description:
- - Action.
- - choice | allow | Allow.
- - choice | block | Block.
- - choice | erase | Erase credit card numbers.
- required: false
- choices: ["allow", "block", "erase"]
-
- signature_main_class_log:
- description:
- - Enable/disable logging.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- signature_main_class_severity:
- description:
- - Severity.
- - choice | low | Low severity.
- - choice | medium | Medium severity.
- - choice | high | High severity.
- required: false
- choices: ["low", "medium", "high"]
-
- signature_main_class_status:
- description:
- - Status.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- url_access:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- url_access_action:
- description:
- - Action.
- - choice | bypass | Allow the HTTP request, also bypass further WAF scanning.
- - choice | permit | Allow the HTTP request, and continue further WAF scanning.
- - choice | block | Block HTTP request.
- required: false
- choices: ["bypass", "permit", "block"]
-
- url_access_address:
- description:
- - Host address.
- required: false
-
- url_access_log:
- description:
- - Enable/disable logging.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- url_access_severity:
- description:
- - Severity.
- - choice | low | Low severity.
- - choice | medium | Medium severity.
- - choice | high | High severity.
- required: false
- choices: ["low", "medium", "high"]
-
- url_access_access_pattern_negate:
- description:
- - Enable/disable match negation.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- url_access_access_pattern_pattern:
- description:
- - URL pattern.
- required: false
-
- url_access_access_pattern_regex:
- description:
- - Enable/disable regular expression based pattern match.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- url_access_access_pattern_srcaddr:
- description:
- - Source address.
- required: false
-
-'''
-
-EXAMPLES = '''
- - name: DELETE Profile
- community.fortios.fmgr_secprof_waf:
- name: "Ansible_WAF_Profile"
- comment: "Created by Ansible Module TEST"
- mode: "delete"
-
- - name: CREATE Profile
- community.fortios.fmgr_secprof_waf:
- name: "Ansible_WAF_Profile"
- comment: "Created by Ansible Module TEST"
- mode: "set"
-'''
-
-RETURN = """
-api_result:
- description: full API response, includes status code and message
- returned: always
- type: str
-"""
-
-from ansible.module_utils.basic import AnsibleModule, env_fallback
-from ansible.module_utils.connection import Connection
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRMethods
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import prepare_dict
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import scrub_dict
-
-
-###############
-# START METHODS
-###############
-
-
-def fmgr_waf_profile_modify(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
- mode = paramgram["mode"]
- adom = paramgram["adom"]
- # INIT A BASIC OBJECTS
- response = DEFAULT_RESULT_OBJ
- url = ""
- datagram = {}
-
- # EVAL THE MODE PARAMETER FOR SET OR ADD
- if mode in ['set', 'add', 'update']:
- url = '/pm/config/adom/{adom}/obj/waf/profile'.format(adom=adom)
- datagram = scrub_dict(prepare_dict(paramgram))
-
- # EVAL THE MODE PARAMETER FOR DELETE
- elif mode == "delete":
- # SET THE CORRECT URL FOR DELETE
- url = '/pm/config/adom/{adom}/obj/waf/profile/{name}'.format(adom=adom, name=paramgram["name"])
- datagram = {}
-
- response = fmgr.process_request(url, datagram, paramgram["mode"])
-
- return response
-
-
-#############
-# END METHODS
-#############
-
-
-def main():
- argument_spec = dict(
- adom=dict(type="str", default="root"),
- mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),
-
- name=dict(required=False, type="str"),
- external=dict(required=False, type="str", choices=["disable", "enable"]),
- extended_log=dict(required=False, type="str", choices=["disable", "enable"]),
- comment=dict(required=False, type="str"),
- address_list=dict(required=False, type="list"),
- address_list_blocked_address=dict(required=False, type="str"),
- address_list_blocked_log=dict(required=False, type="str", choices=["disable", "enable"]),
- address_list_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
- address_list_status=dict(required=False, type="str", choices=["disable", "enable"]),
- address_list_trusted_address=dict(required=False, type="str"),
- constraint=dict(required=False, type="list"),
-
- constraint_content_length_action=dict(required=False, type="str", choices=["allow", "block"]),
- constraint_content_length_length=dict(required=False, type="int"),
- constraint_content_length_log=dict(required=False, type="str", choices=["disable", "enable"]),
- constraint_content_length_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
- constraint_content_length_status=dict(required=False, type="str", choices=["disable", "enable"]),
-
- constraint_exception_address=dict(required=False, type="str"),
- constraint_exception_content_length=dict(required=False, type="str", choices=["disable", "enable"]),
- constraint_exception_header_length=dict(required=False, type="str", choices=["disable", "enable"]),
- constraint_exception_hostname=dict(required=False, type="str", choices=["disable", "enable"]),
- constraint_exception_line_length=dict(required=False, type="str", choices=["disable", "enable"]),
- constraint_exception_malformed=dict(required=False, type="str", choices=["disable", "enable"]),
- constraint_exception_max_cookie=dict(required=False, type="str", choices=["disable", "enable"]),
- constraint_exception_max_header_line=dict(required=False, type="str", choices=["disable", "enable"]),
- constraint_exception_max_range_segment=dict(required=False, type="str", choices=["disable", "enable"]),
- constraint_exception_max_url_param=dict(required=False, type="str", choices=["disable", "enable"]),
- constraint_exception_method=dict(required=False, type="str", choices=["disable", "enable"]),
- constraint_exception_param_length=dict(required=False, type="str", choices=["disable", "enable"]),
- constraint_exception_pattern=dict(required=False, type="str"),
- constraint_exception_regex=dict(required=False, type="str", choices=["disable", "enable"]),
- constraint_exception_url_param_length=dict(required=False, type="str", choices=["disable", "enable"]),
- constraint_exception_version=dict(required=False, type="str", choices=["disable", "enable"]),
-
- constraint_header_length_action=dict(required=False, type="str", choices=["allow", "block"]),
- constraint_header_length_length=dict(required=False, type="int"),
- constraint_header_length_log=dict(required=False, type="str", choices=["disable", "enable"]),
- constraint_header_length_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
- constraint_header_length_status=dict(required=False, type="str", choices=["disable", "enable"]),
-
- constraint_hostname_action=dict(required=False, type="str", choices=["allow", "block"]),
- constraint_hostname_log=dict(required=False, type="str", choices=["disable", "enable"]),
- constraint_hostname_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
- constraint_hostname_status=dict(required=False, type="str", choices=["disable", "enable"]),
-
- constraint_line_length_action=dict(required=False, type="str", choices=["allow", "block"]),
- constraint_line_length_length=dict(required=False, type="int"),
- constraint_line_length_log=dict(required=False, type="str", choices=["disable", "enable"]),
- constraint_line_length_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
- constraint_line_length_status=dict(required=False, type="str", choices=["disable", "enable"]),
-
- constraint_malformed_action=dict(required=False, type="str", choices=["allow", "block"]),
- constraint_malformed_log=dict(required=False, type="str", choices=["disable", "enable"]),
- constraint_malformed_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
- constraint_malformed_status=dict(required=False, type="str", choices=["disable", "enable"]),
-
- constraint_max_cookie_action=dict(required=False, type="str", choices=["allow", "block"]),
- constraint_max_cookie_log=dict(required=False, type="str", choices=["disable", "enable"]),
- constraint_max_cookie_max_cookie=dict(required=False, type="int"),
- constraint_max_cookie_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
- constraint_max_cookie_status=dict(required=False, type="str", choices=["disable", "enable"]),
-
- constraint_max_header_line_action=dict(required=False, type="str", choices=["allow", "block"]),
- constraint_max_header_line_log=dict(required=False, type="str", choices=["disable", "enable"]),
- constraint_max_header_line_max_header_line=dict(required=False, type="int"),
- constraint_max_header_line_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
- constraint_max_header_line_status=dict(required=False, type="str", choices=["disable", "enable"]),
-
- constraint_max_range_segment_action=dict(required=False, type="str", choices=["allow", "block"]),
- constraint_max_range_segment_log=dict(required=False, type="str", choices=["disable", "enable"]),
- constraint_max_range_segment_max_range_segment=dict(required=False, type="int"),
- constraint_max_range_segment_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
- constraint_max_range_segment_status=dict(required=False, type="str", choices=["disable", "enable"]),
-
- constraint_max_url_param_action=dict(required=False, type="str", choices=["allow", "block"]),
- constraint_max_url_param_log=dict(required=False, type="str", choices=["disable", "enable"]),
- constraint_max_url_param_max_url_param=dict(required=False, type="int"),
- constraint_max_url_param_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
- constraint_max_url_param_status=dict(required=False, type="str", choices=["disable", "enable"]),
-
- constraint_method_action=dict(required=False, type="str", choices=["allow", "block"]),
- constraint_method_log=dict(required=False, type="str", choices=["disable", "enable"]),
- constraint_method_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
- constraint_method_status=dict(required=False, type="str", choices=["disable", "enable"]),
-
- constraint_param_length_action=dict(required=False, type="str", choices=["allow", "block"]),
- constraint_param_length_length=dict(required=False, type="int"),
- constraint_param_length_log=dict(required=False, type="str", choices=["disable", "enable"]),
- constraint_param_length_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
- constraint_param_length_status=dict(required=False, type="str", choices=["disable", "enable"]),
-
- constraint_url_param_length_action=dict(required=False, type="str", choices=["allow", "block"]),
- constraint_url_param_length_length=dict(required=False, type="int"),
- constraint_url_param_length_log=dict(required=False, type="str", choices=["disable", "enable"]),
- constraint_url_param_length_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
- constraint_url_param_length_status=dict(required=False, type="str", choices=["disable", "enable"]),
-
- constraint_version_action=dict(required=False, type="str", choices=["allow", "block"]),
- constraint_version_log=dict(required=False, type="str", choices=["disable", "enable"]),
- constraint_version_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
- constraint_version_status=dict(required=False, type="str", choices=["disable", "enable"]),
- method=dict(required=False, type="list"),
- method_default_allowed_methods=dict(required=False, type="str", choices=["delete",
- "get",
- "head",
- "options",
- "post",
- "put",
- "trace",
- "others",
- "connect"]),
- method_log=dict(required=False, type="str", choices=["disable", "enable"]),
- method_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
- method_status=dict(required=False, type="str", choices=["disable", "enable"]),
-
- method_method_policy_address=dict(required=False, type="str"),
- method_method_policy_allowed_methods=dict(required=False, type="str", choices=["delete",
- "get",
- "head",
- "options",
- "post",
- "put",
- "trace",
- "others",
- "connect"]),
- method_method_policy_pattern=dict(required=False, type="str"),
- method_method_policy_regex=dict(required=False, type="str", choices=["disable", "enable"]),
- signature=dict(required=False, type="list"),
- signature_credit_card_detection_threshold=dict(required=False, type="int"),
- signature_disabled_signature=dict(required=False, type="str"),
- signature_disabled_sub_class=dict(required=False, type="str"),
-
- signature_custom_signature_action=dict(required=False, type="str", choices=["allow", "block", "erase"]),
- signature_custom_signature_case_sensitivity=dict(required=False, type="str", choices=["disable", "enable"]),
- signature_custom_signature_direction=dict(required=False, type="str", choices=["request", "response"]),
- signature_custom_signature_log=dict(required=False, type="str", choices=["disable", "enable"]),
- signature_custom_signature_name=dict(required=False, type="str"),
- signature_custom_signature_pattern=dict(required=False, type="str"),
- signature_custom_signature_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
- signature_custom_signature_status=dict(required=False, type="str", choices=["disable", "enable"]),
- signature_custom_signature_target=dict(required=False, type="str", choices=["arg",
- "arg-name",
- "req-body",
- "req-cookie",
- "req-cookie-name",
- "req-filename",
- "req-header",
- "req-header-name",
- "req-raw-uri",
- "req-uri",
- "resp-body",
- "resp-hdr",
- "resp-status"]),
-
- signature_main_class_action=dict(required=False, type="str", choices=["allow", "block", "erase"]),
- signature_main_class_log=dict(required=False, type="str", choices=["disable", "enable"]),
- signature_main_class_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
- signature_main_class_status=dict(required=False, type="str", choices=["disable", "enable"]),
- url_access=dict(required=False, type="list"),
- url_access_action=dict(required=False, type="str", choices=["bypass", "permit", "block"]),
- url_access_address=dict(required=False, type="str"),
- url_access_log=dict(required=False, type="str", choices=["disable", "enable"]),
- url_access_severity=dict(required=False, type="str", choices=["low", "medium", "high"]),
-
- url_access_access_pattern_negate=dict(required=False, type="str", choices=["disable", "enable"]),
- url_access_access_pattern_pattern=dict(required=False, type="str"),
- url_access_access_pattern_regex=dict(required=False, type="str", choices=["disable", "enable"]),
- url_access_access_pattern_srcaddr=dict(required=False, type="str"),
-
- )
-
- module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
- # MODULE PARAMGRAM
- paramgram = {
- "mode": module.params["mode"],
- "adom": module.params["adom"],
- "name": module.params["name"],
- "external": module.params["external"],
- "extended-log": module.params["extended_log"],
- "comment": module.params["comment"],
- "address-list": {
- "blocked-address": module.params["address_list_blocked_address"],
- "blocked-log": module.params["address_list_blocked_log"],
- "severity": module.params["address_list_severity"],
- "status": module.params["address_list_status"],
- "trusted-address": module.params["address_list_trusted_address"],
- },
- "constraint": {
- "content-length": {
- "action": module.params["constraint_content_length_action"],
- "length": module.params["constraint_content_length_length"],
- "log": module.params["constraint_content_length_log"],
- "severity": module.params["constraint_content_length_severity"],
- "status": module.params["constraint_content_length_status"],
- },
- "exception": {
- "address": module.params["constraint_exception_address"],
- "content-length": module.params["constraint_exception_content_length"],
- "header-length": module.params["constraint_exception_header_length"],
- "hostname": module.params["constraint_exception_hostname"],
- "line-length": module.params["constraint_exception_line_length"],
- "malformed": module.params["constraint_exception_malformed"],
- "max-cookie": module.params["constraint_exception_max_cookie"],
- "max-header-line": module.params["constraint_exception_max_header_line"],
- "max-range-segment": module.params["constraint_exception_max_range_segment"],
- "max-url-param": module.params["constraint_exception_max_url_param"],
- "method": module.params["constraint_exception_method"],
- "param-length": module.params["constraint_exception_param_length"],
- "pattern": module.params["constraint_exception_pattern"],
- "regex": module.params["constraint_exception_regex"],
- "url-param-length": module.params["constraint_exception_url_param_length"],
- "version": module.params["constraint_exception_version"],
- },
- "header-length": {
- "action": module.params["constraint_header_length_action"],
- "length": module.params["constraint_header_length_length"],
- "log": module.params["constraint_header_length_log"],
- "severity": module.params["constraint_header_length_severity"],
- "status": module.params["constraint_header_length_status"],
- },
- "hostname": {
- "action": module.params["constraint_hostname_action"],
- "log": module.params["constraint_hostname_log"],
- "severity": module.params["constraint_hostname_severity"],
- "status": module.params["constraint_hostname_status"],
- },
- "line-length": {
- "action": module.params["constraint_line_length_action"],
- "length": module.params["constraint_line_length_length"],
- "log": module.params["constraint_line_length_log"],
- "severity": module.params["constraint_line_length_severity"],
- "status": module.params["constraint_line_length_status"],
- },
- "malformed": {
- "action": module.params["constraint_malformed_action"],
- "log": module.params["constraint_malformed_log"],
- "severity": module.params["constraint_malformed_severity"],
- "status": module.params["constraint_malformed_status"],
- },
- "max-cookie": {
- "action": module.params["constraint_max_cookie_action"],
- "log": module.params["constraint_max_cookie_log"],
- "max-cookie": module.params["constraint_max_cookie_max_cookie"],
- "severity": module.params["constraint_max_cookie_severity"],
- "status": module.params["constraint_max_cookie_status"],
- },
- "max-header-line": {
- "action": module.params["constraint_max_header_line_action"],
- "log": module.params["constraint_max_header_line_log"],
- "max-header-line": module.params["constraint_max_header_line_max_header_line"],
- "severity": module.params["constraint_max_header_line_severity"],
- "status": module.params["constraint_max_header_line_status"],
- },
- "max-range-segment": {
- "action": module.params["constraint_max_range_segment_action"],
- "log": module.params["constraint_max_range_segment_log"],
- "max-range-segment": module.params["constraint_max_range_segment_max_range_segment"],
- "severity": module.params["constraint_max_range_segment_severity"],
- "status": module.params["constraint_max_range_segment_status"],
- },
- "max-url-param": {
- "action": module.params["constraint_max_url_param_action"],
- "log": module.params["constraint_max_url_param_log"],
- "max-url-param": module.params["constraint_max_url_param_max_url_param"],
- "severity": module.params["constraint_max_url_param_severity"],
- "status": module.params["constraint_max_url_param_status"],
- },
- "method": {
- "action": module.params["constraint_method_action"],
- "log": module.params["constraint_method_log"],
- "severity": module.params["constraint_method_severity"],
- "status": module.params["constraint_method_status"],
- },
- "param-length": {
- "action": module.params["constraint_param_length_action"],
- "length": module.params["constraint_param_length_length"],
- "log": module.params["constraint_param_length_log"],
- "severity": module.params["constraint_param_length_severity"],
- "status": module.params["constraint_param_length_status"],
- },
- "url-param-length": {
- "action": module.params["constraint_url_param_length_action"],
- "length": module.params["constraint_url_param_length_length"],
- "log": module.params["constraint_url_param_length_log"],
- "severity": module.params["constraint_url_param_length_severity"],
- "status": module.params["constraint_url_param_length_status"],
- },
- "version": {
- "action": module.params["constraint_version_action"],
- "log": module.params["constraint_version_log"],
- "severity": module.params["constraint_version_severity"],
- "status": module.params["constraint_version_status"],
- },
- },
- "method": {
- "default-allowed-methods": module.params["method_default_allowed_methods"],
- "log": module.params["method_log"],
- "severity": module.params["method_severity"],
- "status": module.params["method_status"],
- "method-policy": {
- "address": module.params["method_method_policy_address"],
- "allowed-methods": module.params["method_method_policy_allowed_methods"],
- "pattern": module.params["method_method_policy_pattern"],
- "regex": module.params["method_method_policy_regex"],
- },
- },
- "signature": {
- "credit-card-detection-threshold": module.params["signature_credit_card_detection_threshold"],
- "disabled-signature": module.params["signature_disabled_signature"],
- "disabled-sub-class": module.params["signature_disabled_sub_class"],
- "custom-signature": {
- "action": module.params["signature_custom_signature_action"],
- "case-sensitivity": module.params["signature_custom_signature_case_sensitivity"],
- "direction": module.params["signature_custom_signature_direction"],
- "log": module.params["signature_custom_signature_log"],
- "name": module.params["signature_custom_signature_name"],
- "pattern": module.params["signature_custom_signature_pattern"],
- "severity": module.params["signature_custom_signature_severity"],
- "status": module.params["signature_custom_signature_status"],
- "target": module.params["signature_custom_signature_target"],
- },
- "main-class": {
- "action": module.params["signature_main_class_action"],
- "log": module.params["signature_main_class_log"],
- "severity": module.params["signature_main_class_severity"],
- "status": module.params["signature_main_class_status"],
- },
- },
- "url-access": {
- "action": module.params["url_access_action"],
- "address": module.params["url_access_address"],
- "log": module.params["url_access_log"],
- "severity": module.params["url_access_severity"],
- "access-pattern": {
- "negate": module.params["url_access_access_pattern_negate"],
- "pattern": module.params["url_access_access_pattern_pattern"],
- "regex": module.params["url_access_access_pattern_regex"],
- "srcaddr": module.params["url_access_access_pattern_srcaddr"],
- }
- }
- }
-
- module.paramgram = paramgram
- fmgr = None
- if module._socket_path:
- connection = Connection(module._socket_path)
- fmgr = FortiManagerHandler(connection, module)
- fmgr.tools = FMGRCommon()
- else:
- module.fail_json(**FAIL_SOCKET_MSG)
-
- list_overrides = ['address-list', 'constraint', 'method', 'signature', 'url-access']
- paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
- paramgram=paramgram, module=module)
-
- results = DEFAULT_RESULT_OBJ
-
- try:
- results = fmgr_waf_profile_modify(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
-
- except Exception as err:
- raise FMGBaseException(err)
-
- return module.exit_json(**results[1])
-
-
-if __name__ == "__main__":
- main()
diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_wanopt.py b/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_wanopt.py
deleted file mode 100644
index 68f0962b7..000000000
--- a/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_wanopt.py
+++ /dev/null
@@ -1,685 +0,0 @@
-#!/usr/bin/python
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-DOCUMENTATION = '''
----
-module: fmgr_secprof_wanopt
-notes:
- - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
-author:
- - Luke Weighall (@lweighall)
- - Andrew Welsh (@Ghilli3)
- - Jim Huber (@p4r4n0y1ng)
-short_description: WAN optimization
-description:
- - Manage WanOpt security profiles in FortiManager via API
-
-options:
- adom:
- description:
- - The ADOM the configuration should belong to.
- required: false
- default: root
-
- mode:
- description:
- - Sets one of three modes for managing the object.
- - Allows use of soft-adds instead of overwriting existing values
- choices: ['add', 'set', 'delete', 'update']
- required: false
- default: add
-
- transparent:
- description:
- - Enable/disable transparent mode.
- required: false
- choices:
- - disable
- - enable
-
- name:
- description:
- - Profile name.
- required: false
-
- comments:
- description:
- - Comment.
- required: false
-
- auth_group:
- description:
- - Optionally add an authentication group to restrict access to the WAN Optimization tunnel to
- peers in the authentication group.
- required: false
-
- cifs:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- cifs_byte_caching:
- description:
- - Enable/disable byte-caching for HTTP. Byte caching reduces the amount of traffic by caching
- file data sent across the WAN and in future serving if from the cache.
- required: false
- choices:
- - disable
- - enable
-
- cifs_log_traffic:
- description:
- - Enable/disable logging.
- required: false
- choices:
- - disable
- - enable
-
- cifs_port:
- description:
- - Single port number or port number range for CIFS. Only packets with a destination port number
- that matches this port number or range are accepted by this profile.
- required: false
-
- cifs_prefer_chunking:
- description:
- - Select dynamic or fixed-size data chunking for HTTP WAN Optimization.
- required: false
- choices:
- - dynamic
- - fix
-
- cifs_secure_tunnel:
- description:
- - Enable/disable securing the WAN Opt tunnel using SSL. Secure and non-secure tunnels use the
- same TCP port (7810).
- required: false
- choices:
- - disable
- - enable
-
- cifs_status:
- description:
- - Enable/disable HTTP WAN Optimization.
- required: false
- choices:
- - disable
- - enable
-
- cifs_tunnel_sharing:
- description:
- - Tunnel sharing mode for aggressive/non-aggressive and/or interactive/non-interactive protocols.
- required: false
- choices:
- - private
- - shared
- - express-shared
-
- ftp:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- ftp_byte_caching:
- description:
- - Enable/disable byte-caching for HTTP. Byte caching reduces the amount of traffic by caching
- file data sent across the WAN and in future serving if from the cache.
- required: false
- choices:
- - disable
- - enable
-
- ftp_log_traffic:
- description:
- - Enable/disable logging.
- required: false
- choices:
- - disable
- - enable
-
- ftp_port:
- description:
- - Single port number or port number range for FTP. Only packets with a destination port number
- that matches this port number or range are accepted by this profile.
- required: false
-
- ftp_prefer_chunking:
- description:
- - Select dynamic or fixed-size data chunking for HTTP WAN Optimization.
- required: false
- choices:
- - dynamic
- - fix
-
- ftp_secure_tunnel:
- description:
- - Enable/disable securing the WAN Opt tunnel using SSL. Secure and non-secure tunnels use the
- same TCP port (7810).
- required: false
- choices:
- - disable
- - enable
-
- ftp_status:
- description:
- - Enable/disable HTTP WAN Optimization.
- required: false
- choices:
- - disable
- - enable
-
- ftp_tunnel_sharing:
- description:
- - Tunnel sharing mode for aggressive/non-aggressive and/or interactive/non-interactive protocols.
- required: false
- choices:
- - private
- - shared
- - express-shared
-
- http:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- http_byte_caching:
- description:
- - Enable/disable byte-caching for HTTP. Byte caching reduces the amount of traffic by caching
- file data sent across the WAN and in future serving if from the cache.
- required: false
- choices:
- - disable
- - enable
-
- http_log_traffic:
- description:
- - Enable/disable logging.
- required: false
- choices:
- - disable
- - enable
-
- http_port:
- description:
- - Single port number or port number range for HTTP. Only packets with a destination port number
- that matches this port number or range are accepted by this profile.
- required: false
-
- http_prefer_chunking:
- description:
- - Select dynamic or fixed-size data chunking for HTTP WAN Optimization.
- required: false
- choices:
- - dynamic
- - fix
-
- http_secure_tunnel:
- description:
- - Enable/disable securing the WAN Opt tunnel using SSL. Secure and non-secure tunnels use the
- same TCP port (7810).
- required: false
- choices:
- - disable
- - enable
-
- http_ssl:
- description:
- - Enable/disable SSL/TLS offloading (hardware acceleration) for HTTPS traffic in this tunnel.
- required: false
- choices:
- - disable
- - enable
-
- http_ssl_port:
- description:
- - Port on which to expect HTTPS traffic for SSL/TLS offloading.
- required: false
-
- http_status:
- description:
- - Enable/disable HTTP WAN Optimization.
- required: false
- choices:
- - disable
- - enable
-
- http_tunnel_non_http:
- description:
- - Configure how to process non-HTTP traffic when a profile configured for HTTP traffic accepts
- a non-HTTP session. Can occur if an application sends non-HTTP traffic using an HTTP destination port.
- required: false
- choices:
- - disable
- - enable
-
- http_tunnel_sharing:
- description:
- - Tunnel sharing mode for aggressive/non-aggressive and/or interactive/non-interactive protocols.
- required: false
- choices:
- - private
- - shared
- - express-shared
-
- http_unknown_http_version:
- description:
- - How to handle HTTP sessions that do not comply with HTTP 0.9, 1.0, or 1.1.
- required: false
- choices:
- - best-effort
- - reject
- - tunnel
-
- mapi:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- mapi_byte_caching:
- description:
- - Enable/disable byte-caching for HTTP. Byte caching reduces the amount of traffic by caching
- file data sent across the WAN and in future serving if from the cache.
- required: false
- choices:
- - disable
- - enable
-
- mapi_log_traffic:
- description:
- - Enable/disable logging.
- required: false
- choices:
- - disable
- - enable
-
- mapi_port:
- description:
- - Single port number or port number range for MAPI. Only packets with a destination port number
- that matches this port number or range are accepted by this profile.
- required: false
-
- mapi_secure_tunnel:
- description:
- - Enable/disable securing the WAN Opt tunnel using SSL. Secure and non-secure tunnels use the
- same TCP port (7810).
- required: false
- choices:
- - disable
- - enable
-
- mapi_status:
- description:
- - Enable/disable HTTP WAN Optimization.
- required: false
- choices:
- - disable
- - enable
-
- mapi_tunnel_sharing:
- description:
- - Tunnel sharing mode for aggressive/non-aggressive and/or interactive/non-interactive protocols.
- required: false
- choices:
- - private
- - shared
- - express-shared
-
- tcp:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- tcp_byte_caching:
- description:
- - Enable/disable byte-caching for HTTP. Byte caching reduces the amount of traffic by caching
- file data sent across the WAN and in future serving if from the cache.
- required: false
- choices:
- - disable
- - enable
-
- tcp_byte_caching_opt:
- description:
- - Select whether TCP byte-caching uses system memory only or both memory and disk space.
- required: false
- choices:
- - mem-only
- - mem-disk
-
- tcp_log_traffic:
- description:
- - Enable/disable logging.
- required: false
- choices:
- - disable
- - enable
-
- tcp_port:
- description:
- - Single port number or port number range for TCP. Only packets with a destination port number
- that matches this port number or range are accepted by this profile.
- required: false
-
- tcp_secure_tunnel:
- description:
- - Enable/disable securing the WAN Opt tunnel using SSL. Secure and non-secure tunnels use the
- same TCP port (7810).
- required: false
- choices:
- - disable
- - enable
-
- tcp_ssl:
- description:
- - Enable/disable SSL/TLS offloading.
- required: false
- choices:
- - disable
- - enable
-
- tcp_ssl_port:
- description:
- - Port on which to expect HTTPS traffic for SSL/TLS offloading.
- required: false
-
- tcp_status:
- description:
- - Enable/disable HTTP WAN Optimization.
- required: false
- choices:
- - disable
- - enable
-
- tcp_tunnel_sharing:
- description:
- - Tunnel sharing mode for aggressive/non-aggressive and/or interactive/non-interactive protocols.
- required: false
- choices:
- - private
- - shared
- - express-shared
-
-'''
-
-EXAMPLES = '''
- - name: DELETE Profile
- community.fortios.fmgr_secprof_wanopt:
- name: "Ansible_WanOpt_Profile"
- mode: "delete"
-
- - name: Create FMGR_WANOPT_PROFILE
- community.fortios.fmgr_secprof_wanopt:
- mode: "set"
- adom: "root"
- transparent: "enable"
- name: "Ansible_WanOpt_Profile"
- comments: "Created by Ansible"
- cifs: {byte-caching: "enable",
- log-traffic: "enable",
- port: 80,
- prefer-chunking: "dynamic",
- status: "enable",
- tunnel-sharing: "private"}
- ftp: {byte-caching: "enable",
- log-traffic: "enable",
- port: 80,
- prefer-chunking: "dynamic",
- secure-tunnel: "disable",
- status: "enable",
- tunnel-sharing: "private"}
-'''
-
-RETURN = """
-api_result:
- description: full API response, includes status code and message
- returned: always
- type: str
-"""
-
-from ansible.module_utils.basic import AnsibleModule, env_fallback
-from ansible.module_utils.connection import Connection
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import prepare_dict
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import scrub_dict
-
-
-###############
-# START METHODS
-###############
-
-
-def fmgr_wanopt_profile_modify(fmgr, paramgram):
- """
- :param fmgr: The fmgr object instance from fortimanager.py
- :type fmgr: class object
- :param paramgram: The formatted dictionary of options to process
- :type paramgram: dict
- :return: The response from the FortiManager
- :rtype: dict
- """
-
- mode = paramgram["mode"]
- adom = paramgram["adom"]
-
- response = DEFAULT_RESULT_OBJ
- url = ""
- datagram = {}
-
- # EVAL THE MODE PARAMETER FOR SET OR ADD
- if mode in ['set', 'add', 'update']:
- url = '/pm/config/adom/{adom}/obj/wanopt/profile'.format(adom=adom)
- datagram = scrub_dict(prepare_dict(paramgram))
-
- # EVAL THE MODE PARAMETER FOR DELETE
- elif mode == "delete":
- # SET THE CORRECT URL FOR DELETE
- url = '/pm/config/adom/{adom}/obj/wanopt/profile/{name}'.format(adom=adom, name=paramgram["name"])
- datagram = {}
-
- response = fmgr.process_request(url, datagram, paramgram["mode"])
-
- return response
-
-
-#############
-# END METHODS
-#############
-
-
-def main():
- argument_spec = dict(
- adom=dict(type="str", default="root"),
- mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),
-
- transparent=dict(required=False, type="str", choices=["disable", "enable"]),
- name=dict(required=False, type="str"),
- comments=dict(required=False, type="str"),
- auth_group=dict(required=False, type="str"),
- cifs=dict(required=False, type="dict"),
- cifs_byte_caching=dict(required=False, type="str", choices=["disable", "enable"]),
- cifs_log_traffic=dict(required=False, type="str", choices=["disable", "enable"]),
- cifs_port=dict(required=False, type="str"),
- cifs_prefer_chunking=dict(required=False, type="str", choices=["dynamic", "fix"]),
- cifs_secure_tunnel=dict(required=False, type="str", choices=["disable", "enable"]),
- cifs_status=dict(required=False, type="str", choices=["disable", "enable"]),
- cifs_tunnel_sharing=dict(required=False, type="str", choices=["private", "shared", "express-shared"]),
- ftp=dict(required=False, type="dict"),
- ftp_byte_caching=dict(required=False, type="str", choices=["disable", "enable"]),
- ftp_log_traffic=dict(required=False, type="str", choices=["disable", "enable"]),
- ftp_port=dict(required=False, type="str"),
- ftp_prefer_chunking=dict(required=False, type="str", choices=["dynamic", "fix"]),
- ftp_secure_tunnel=dict(required=False, type="str", choices=["disable", "enable"]),
- ftp_status=dict(required=False, type="str", choices=["disable", "enable"]),
- ftp_tunnel_sharing=dict(required=False, type="str", choices=["private", "shared", "express-shared"]),
- http=dict(required=False, type="dict"),
- http_byte_caching=dict(required=False, type="str", choices=["disable", "enable"]),
- http_log_traffic=dict(required=False, type="str", choices=["disable", "enable"]),
- http_port=dict(required=False, type="str"),
- http_prefer_chunking=dict(required=False, type="str", choices=["dynamic", "fix"]),
- http_secure_tunnel=dict(required=False, type="str", choices=["disable", "enable"]),
- http_ssl=dict(required=False, type="str", choices=["disable", "enable"]),
- http_ssl_port=dict(required=False, type="str"),
- http_status=dict(required=False, type="str", choices=["disable", "enable"]),
- http_tunnel_non_http=dict(required=False, type="str", choices=["disable", "enable"]),
- http_tunnel_sharing=dict(required=False, type="str", choices=["private", "shared", "express-shared"]),
- http_unknown_http_version=dict(required=False, type="str", choices=["best-effort", "reject", "tunnel"]),
- mapi=dict(required=False, type="dict"),
- mapi_byte_caching=dict(required=False, type="str", choices=["disable", "enable"]),
- mapi_log_traffic=dict(required=False, type="str", choices=["disable", "enable"]),
- mapi_port=dict(required=False, type="str"),
- mapi_secure_tunnel=dict(required=False, type="str", choices=["disable", "enable"]),
- mapi_status=dict(required=False, type="str", choices=["disable", "enable"]),
- mapi_tunnel_sharing=dict(required=False, type="str", choices=["private", "shared", "express-shared"]),
- tcp=dict(required=False, type="dict"),
- tcp_byte_caching=dict(required=False, type="str", choices=["disable", "enable"]),
- tcp_byte_caching_opt=dict(required=False, type="str", choices=["mem-only", "mem-disk"]),
- tcp_log_traffic=dict(required=False, type="str", choices=["disable", "enable"]),
- tcp_port=dict(required=False, type="str"),
- tcp_secure_tunnel=dict(required=False, type="str", choices=["disable", "enable"]),
- tcp_ssl=dict(required=False, type="str", choices=["disable", "enable"]),
- tcp_ssl_port=dict(required=False, type="str"),
- tcp_status=dict(required=False, type="str", choices=["disable", "enable"]),
- tcp_tunnel_sharing=dict(required=False, type="str", choices=["private", "shared", "express-shared"]),
-
- )
-
- module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
- # MODULE PARAMGRAM
- paramgram = {
- "mode": module.params["mode"],
- "adom": module.params["adom"],
- "transparent": module.params["transparent"],
- "name": module.params["name"],
- "comments": module.params["comments"],
- "auth-group": module.params["auth_group"],
- "cifs": {
- "byte-caching": module.params["cifs_byte_caching"],
- "log-traffic": module.params["cifs_log_traffic"],
- "port": module.params["cifs_port"],
- "prefer-chunking": module.params["cifs_prefer_chunking"],
- "secure-tunnel": module.params["cifs_secure_tunnel"],
- "status": module.params["cifs_status"],
- "tunnel-sharing": module.params["cifs_tunnel_sharing"],
- },
- "ftp": {
- "byte-caching": module.params["ftp_byte_caching"],
- "log-traffic": module.params["ftp_log_traffic"],
- "port": module.params["ftp_port"],
- "prefer-chunking": module.params["ftp_prefer_chunking"],
- "secure-tunnel": module.params["ftp_secure_tunnel"],
- "status": module.params["ftp_status"],
- "tunnel-sharing": module.params["ftp_tunnel_sharing"],
- },
- "http": {
- "byte-caching": module.params["http_byte_caching"],
- "log-traffic": module.params["http_log_traffic"],
- "port": module.params["http_port"],
- "prefer-chunking": module.params["http_prefer_chunking"],
- "secure-tunnel": module.params["http_secure_tunnel"],
- "ssl": module.params["http_ssl"],
- "ssl-port": module.params["http_ssl_port"],
- "status": module.params["http_status"],
- "tunnel-non-http": module.params["http_tunnel_non_http"],
- "tunnel-sharing": module.params["http_tunnel_sharing"],
- "unknown-http-version": module.params["http_unknown_http_version"],
- },
- "mapi": {
- "byte-caching": module.params["mapi_byte_caching"],
- "log-traffic": module.params["mapi_log_traffic"],
- "port": module.params["mapi_port"],
- "secure-tunnel": module.params["mapi_secure_tunnel"],
- "status": module.params["mapi_status"],
- "tunnel-sharing": module.params["mapi_tunnel_sharing"],
- },
- "tcp": {
- "byte-caching": module.params["tcp_byte_caching"],
- "byte-caching-opt": module.params["tcp_byte_caching_opt"],
- "log-traffic": module.params["tcp_log_traffic"],
- "port": module.params["tcp_port"],
- "secure-tunnel": module.params["tcp_secure_tunnel"],
- "ssl": module.params["tcp_ssl"],
- "ssl-port": module.params["tcp_ssl_port"],
- "status": module.params["tcp_status"],
- "tunnel-sharing": module.params["tcp_tunnel_sharing"],
- }
- }
- module.paramgram = paramgram
- fmgr = None
- if module._socket_path:
- connection = Connection(module._socket_path)
- fmgr = FortiManagerHandler(connection, module)
- fmgr.tools = FMGRCommon()
- else:
- module.fail_json(**FAIL_SOCKET_MSG)
-
- list_overrides = ['cifs', 'ftp', 'http', 'mapi', 'tcp']
- paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
- paramgram=paramgram, module=module)
-
- results = DEFAULT_RESULT_OBJ
-
- try:
- results = fmgr_wanopt_profile_modify(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
-
- except Exception as err:
- raise FMGBaseException(err)
-
- return module.exit_json(**results[1])
-
-
-if __name__ == "__main__":
- main()
diff --git a/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_web.py b/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_web.py
deleted file mode 100644
index 427cd2e0b..000000000
--- a/ansible_collections/community/fortios/plugins/modules/fmgr_secprof_web.py
+++ /dev/null
@@ -1,1081 +0,0 @@
-#!/usr/bin/python
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-DOCUMENTATION = '''
----
-module: fmgr_secprof_web
-notes:
- - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
-author:
- - Luke Weighall (@lweighall)
- - Andrew Welsh (@Ghilli3)
- - Jim Huber (@p4r4n0y1ng)
-short_description: Manage web filter security profiles in FortiManager
-description:
- - Manage web filter security profiles in FortiManager through playbooks using the FMG API
-
-options:
- adom:
- description:
- - The ADOM the configuration should belong to.
- required: false
- default: root
-
- mode:
- description:
- - Sets one of three modes for managing the object.
- - Allows use of soft-adds instead of overwriting existing values
- choices: ['add', 'set', 'delete', 'update']
- required: false
- default: add
-
- youtube_channel_status:
- description:
- - YouTube channel filter status.
- - choice | disable | Disable YouTube channel filter.
- - choice | blacklist | Block matches.
- - choice | whitelist | Allow matches.
- required: false
- choices: ["disable", "blacklist", "whitelist"]
-
- wisp_servers:
- description:
- - WISP servers.
- required: false
-
- wisp_algorithm:
- description:
- - WISP server selection algorithm.
- - choice | auto-learning | Select the lightest loading healthy server.
- - choice | primary-secondary | Select the first healthy server in order.
- - choice | round-robin | Select the next healthy server.
- required: false
- choices: ["auto-learning", "primary-secondary", "round-robin"]
-
- wisp:
- description:
- - Enable/disable web proxy WISP.
- - choice | disable | Disable web proxy WISP.
- - choice | enable | Enable web proxy WISP.
- required: false
- choices: ["disable", "enable"]
-
- web_url_log:
- description:
- - Enable/disable logging URL filtering.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- web_invalid_domain_log:
- description:
- - Enable/disable logging invalid domain names.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- web_ftgd_quota_usage:
- description:
- - Enable/disable logging daily quota usage.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- web_ftgd_err_log:
- description:
- - Enable/disable logging rating errors.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- web_filter_vbs_log:
- description:
- - Enable/disable logging VBS scripts.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- web_filter_unknown_log:
- description:
- - Enable/disable logging unknown scripts.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- web_filter_referer_log:
- description:
- - Enable/disable logging referrers.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- web_filter_jscript_log:
- description:
- - Enable/disable logging JScripts.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- web_filter_js_log:
- description:
- - Enable/disable logging Java scripts.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- web_filter_cookie_removal_log:
- description:
- - Enable/disable logging blocked cookies.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- web_filter_cookie_log:
- description:
- - Enable/disable logging cookie filtering.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- web_filter_command_block_log:
- description:
- - Enable/disable logging blocked commands.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- web_filter_applet_log:
- description:
- - Enable/disable logging Java applets.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- web_filter_activex_log:
- description:
- - Enable/disable logging ActiveX.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- web_extended_all_action_log:
- description:
- - Enable/disable extended any filter action logging for web filtering.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- web_content_log:
- description:
- - Enable/disable logging logging blocked web content.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- replacemsg_group:
- description:
- - Replacement message group.
- required: false
-
- post_action:
- description:
- - Action taken for HTTP POST traffic.
- - choice | normal | Normal, POST requests are allowed.
- - choice | block | POST requests are blocked.
- required: false
- choices: ["normal", "block"]
-
- ovrd_perm:
- description:
- - FLAG Based Options. Specify multiple in list form.
- - flag | bannedword-override | Banned word override.
- - flag | urlfilter-override | URL filter override.
- - flag | fortiguard-wf-override | FortiGuard Web Filter override.
- - flag | contenttype-check-override | Content-type header override.
- required: false
- choices:
- - bannedword-override
- - urlfilter-override
- - fortiguard-wf-override
- - contenttype-check-override
-
- options:
- description:
- - FLAG Based Options. Specify multiple in list form.
- - flag | block-invalid-url | Block sessions contained an invalid domain name.
- - flag | jscript | Javascript block.
- - flag | js | JS block.
- - flag | vbs | VB script block.
- - flag | unknown | Unknown script block.
- - flag | wf-referer | Referring block.
- - flag | intrinsic | Intrinsic script block.
- - flag | wf-cookie | Cookie block.
- - flag | per-user-bwl | Per-user black/white list filter
- - flag | activexfilter | ActiveX filter.
- - flag | cookiefilter | Cookie filter.
- - flag | javafilter | Java applet filter.
- required: false
- choices:
- - block-invalid-url
- - jscript
- - js
- - vbs
- - unknown
- - wf-referer
- - intrinsic
- - wf-cookie
- - per-user-bwl
- - activexfilter
- - cookiefilter
- - javafilter
-
- name:
- description:
- - Profile name.
- required: false
-
- log_all_url:
- description:
- - Enable/disable logging all URLs visited.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- inspection_mode:
- description:
- - Web filtering inspection mode.
- - choice | proxy | Proxy.
- - choice | flow-based | Flow based.
- required: false
- choices: ["proxy", "flow-based"]
-
- https_replacemsg:
- description:
- - Enable replacement messages for HTTPS.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- extended_log:
- description:
- - Enable/disable extended logging for web filtering.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- comment:
- description:
- - Optional comments.
- required: false
-
- ftgd_wf:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- ftgd_wf_exempt_quota:
- description:
- - Do not stop quota for these categories.
- required: false
-
- ftgd_wf_max_quota_timeout:
- description:
- - Maximum FortiGuard quota used by single page view in seconds (excludes streams).
- required: false
-
- ftgd_wf_options:
- description:
- - Options for FortiGuard Web Filter.
- - FLAG Based Options. Specify multiple in list form.
- - flag | error-allow | Allow web pages with a rating error to pass through.
- - flag | rate-server-ip | Rate the server IP in addition to the domain name.
- - flag | connect-request-bypass | Bypass connection which has CONNECT request.
- - flag | ftgd-disable | Disable FortiGuard scanning.
- required: false
- choices: ["error-allow", "rate-server-ip", "connect-request-bypass", "ftgd-disable"]
-
- ftgd_wf_ovrd:
- description:
- - Allow web filter profile overrides.
- required: false
-
- ftgd_wf_rate_crl_urls:
- description:
- - Enable/disable rating CRL by URL.
- - choice | disable | Disable rating CRL by URL.
- - choice | enable | Enable rating CRL by URL.
- required: false
- choices: ["disable", "enable"]
-
- ftgd_wf_rate_css_urls:
- description:
- - Enable/disable rating CSS by URL.
- - choice | disable | Disable rating CSS by URL.
- - choice | enable | Enable rating CSS by URL.
- required: false
- choices: ["disable", "enable"]
-
- ftgd_wf_rate_image_urls:
- description:
- - Enable/disable rating images by URL.
- - choice | disable | Disable rating images by URL (blocked images are replaced with blanks).
- - choice | enable | Enable rating images by URL (blocked images are replaced with blanks).
- required: false
- choices: ["disable", "enable"]
-
- ftgd_wf_rate_javascript_urls:
- description:
- - Enable/disable rating JavaScript by URL.
- - choice | disable | Disable rating JavaScript by URL.
- - choice | enable | Enable rating JavaScript by URL.
- required: false
- choices: ["disable", "enable"]
-
- ftgd_wf_filters_action:
- description:
- - Action to take for matches.
- - choice | block | Block access.
- - choice | monitor | Allow access while logging the action.
- - choice | warning | Allow access after warning the user.
- - choice | authenticate | Authenticate user before allowing access.
- required: false
- choices: ["block", "monitor", "warning", "authenticate"]
-
- ftgd_wf_filters_auth_usr_grp:
- description:
- - Groups with permission to authenticate.
- required: false
-
- ftgd_wf_filters_category:
- description:
- - Categories and groups the filter examines.
- required: false
-
- ftgd_wf_filters_log:
- description:
- - Enable/disable logging.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- ftgd_wf_filters_override_replacemsg:
- description:
- - Override replacement message.
- required: false
-
- ftgd_wf_filters_warn_duration:
- description:
- - Duration of warnings.
- required: false
-
- ftgd_wf_filters_warning_duration_type:
- description:
- - Re-display warning after closing browser or after a timeout.
- - choice | session | After session ends.
- - choice | timeout | After timeout occurs.
- required: false
- choices: ["session", "timeout"]
-
- ftgd_wf_filters_warning_prompt:
- description:
- - Warning prompts in each category or each domain.
- - choice | per-domain | Per-domain warnings.
- - choice | per-category | Per-category warnings.
- required: false
- choices: ["per-domain", "per-category"]
-
- ftgd_wf_quota_category:
- description:
- - FortiGuard categories to apply quota to (category action must be set to monitor).
- required: false
-
- ftgd_wf_quota_duration:
- description:
- - Duration of quota.
- required: false
-
- ftgd_wf_quota_override_replacemsg:
- description:
- - Override replacement message.
- required: false
-
- ftgd_wf_quota_type:
- description:
- - Quota type.
- - choice | time | Use a time-based quota.
- - choice | traffic | Use a traffic-based quota.
- required: false
- choices: ["time", "traffic"]
-
- ftgd_wf_quota_unit:
- description:
- - Traffic quota unit of measurement.
- - choice | B | Quota in bytes.
- - choice | KB | Quota in kilobytes.
- - choice | MB | Quota in megabytes.
- - choice | GB | Quota in gigabytes.
- required: false
- choices: ["B", "KB", "MB", "GB"]
-
- ftgd_wf_quota_value:
- description:
- - Traffic quota value.
- required: false
-
- override:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- override_ovrd_cookie:
- description:
- - Allow/deny browser-based (cookie) overrides.
- - choice | deny | Deny browser-based (cookie) override.
- - choice | allow | Allow browser-based (cookie) override.
- required: false
- choices: ["deny", "allow"]
-
- override_ovrd_dur:
- description:
- - Override duration.
- required: false
-
- override_ovrd_dur_mode:
- description:
- - Override duration mode.
- - choice | constant | Constant mode.
- - choice | ask | Prompt for duration when initiating an override.
- required: false
- choices: ["constant", "ask"]
-
- override_ovrd_scope:
- description:
- - Override scope.
- - choice | user | Override for the user.
- - choice | user-group | Override for the user's group.
- - choice | ip | Override for the initiating IP.
- - choice | ask | Prompt for scope when initiating an override.
- - choice | browser | Create browser-based (cookie) override.
- required: false
- choices: ["user", "user-group", "ip", "ask", "browser"]
-
- override_ovrd_user_group:
- description:
- - User groups with permission to use the override.
- required: false
-
- override_profile:
- description:
- - Web filter profile with permission to create overrides.
- required: false
-
- override_profile_attribute:
- description:
- - Profile attribute to retrieve from the RADIUS server.
- - choice | User-Name | Use this attribute.
- - choice | NAS-IP-Address | Use this attribute.
- - choice | Framed-IP-Address | Use this attribute.
- - choice | Framed-IP-Netmask | Use this attribute.
- - choice | Filter-Id | Use this attribute.
- - choice | Login-IP-Host | Use this attribute.
- - choice | Reply-Message | Use this attribute.
- - choice | Callback-Number | Use this attribute.
- - choice | Callback-Id | Use this attribute.
- - choice | Framed-Route | Use this attribute.
- - choice | Framed-IPX-Network | Use this attribute.
- - choice | Class | Use this attribute.
- - choice | Called-Station-Id | Use this attribute.
- - choice | Calling-Station-Id | Use this attribute.
- - choice | NAS-Identifier | Use this attribute.
- - choice | Proxy-State | Use this attribute.
- - choice | Login-LAT-Service | Use this attribute.
- - choice | Login-LAT-Node | Use this attribute.
- - choice | Login-LAT-Group | Use this attribute.
- - choice | Framed-AppleTalk-Zone | Use this attribute.
- - choice | Acct-Session-Id | Use this attribute.
- - choice | Acct-Multi-Session-Id | Use this attribute.
- required: false
- choices:
- - User-Name
- - NAS-IP-Address
- - Framed-IP-Address
- - Framed-IP-Netmask
- - Filter-Id
- - Login-IP-Host
- - Reply-Message
- - Callback-Number
- - Callback-Id
- - Framed-Route
- - Framed-IPX-Network
- - Class
- - Called-Station-Id
- - Calling-Station-Id
- - NAS-Identifier
- - Proxy-State
- - Login-LAT-Service
- - Login-LAT-Node
- - Login-LAT-Group
- - Framed-AppleTalk-Zone
- - Acct-Session-Id
- - Acct-Multi-Session-Id
-
- override_profile_type:
- description:
- - Override profile type.
- - choice | list | Profile chosen from list.
- - choice | radius | Profile determined by RADIUS server.
- required: false
- choices: ["list", "radius"]
-
- url_extraction:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- url_extraction_redirect_header:
- description:
- - HTTP header name to use for client redirect on blocked requests
- required: false
-
- url_extraction_redirect_no_content:
- description:
- - Enable / Disable empty message-body entity in HTTP response
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- url_extraction_redirect_url:
- description:
- - HTTP header value to use for client redirect on blocked requests
- required: false
-
- url_extraction_server_fqdn:
- description:
- - URL extraction server FQDN (fully qualified domain name)
- required: false
-
- url_extraction_status:
- description:
- - Enable URL Extraction
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- web:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- web_blacklist:
- description:
- - Enable/disable automatic addition of URLs detected by FortiSandbox to blacklist.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- web_bword_table:
- description:
- - Banned word table ID.
- required: false
-
- web_bword_threshold:
- description:
- - Banned word score threshold.
- required: false
-
- web_content_header_list:
- description:
- - Content header list.
- required: false
-
- web_keyword_match:
- description:
- - Search keywords to log when match is found.
- required: false
-
- web_log_search:
- description:
- - Enable/disable logging all search phrases.
- - choice | disable | Disable setting.
- - choice | enable | Enable setting.
- required: false
- choices: ["disable", "enable"]
-
- web_safe_search:
- description:
- - Safe search type.
- - FLAG Based Options. Specify multiple in list form.
- - flag | url | Insert safe search string into URL.
- - flag | header | Insert safe search header.
- required: false
- choices: ["url", "header"]
-
- web_urlfilter_table:
- description:
- - URL filter table ID.
- required: false
-
- web_whitelist:
- description:
- - FortiGuard whitelist settings.
- - FLAG Based Options. Specify multiple in list form.
- - flag | exempt-av | Exempt antivirus.
- - flag | exempt-webcontent | Exempt web content.
- - flag | exempt-activex-java-cookie | Exempt ActiveX-JAVA-Cookie.
- - flag | exempt-dlp | Exempt DLP.
- - flag | exempt-rangeblock | Exempt RangeBlock.
- - flag | extended-log-others | Support extended log.
- required: false
- choices:
- - exempt-av
- - exempt-webcontent
- - exempt-activex-java-cookie
- - exempt-dlp
- - exempt-rangeblock
- - extended-log-others
-
- web_youtube_restrict:
- description:
- - YouTube EDU filter level.
- - choice | strict | Strict access for YouTube.
- - choice | none | Full access for YouTube.
- - choice | moderate | Moderate access for YouTube.
- required: false
- choices: ["strict", "none", "moderate"]
-
- youtube_channel_filter:
- description:
- - EXPERTS ONLY! KNOWLEDGE OF FMGR JSON API IS REQUIRED!
- - List of multiple child objects to be added. Expects a list of dictionaries.
- - Dictionaries must use FortiManager API parameters, not the ansible ones listed below.
- - If submitted, all other prefixed sub-parameters ARE IGNORED.
- - This object is MUTUALLY EXCLUSIVE with its options.
- - We expect that you know what you are doing with these list parameters, and are leveraging the JSON API Guide.
- - WHEN IN DOUBT, USE THE SUB OPTIONS BELOW INSTEAD TO CREATE OBJECTS WITH MULTIPLE TASKS
- required: false
-
- youtube_channel_filter_channel_id:
- description:
- - YouTube channel ID to be filtered.
- required: false
-
- youtube_channel_filter_comment:
- description:
- - Comment.
- required: false
-
-
-'''
-
-EXAMPLES = '''
- - name: DELETE Profile
- community.fortios.fmgr_secprof_web:
- name: "Ansible_Web_Filter_Profile"
- mode: "delete"
-
- - name: CREATE Profile
- community.fortios.fmgr_secprof_web:
- name: "Ansible_Web_Filter_Profile"
- comment: "Created by Ansible Module TEST"
- mode: "set"
- extended_log: "enable"
- inspection_mode: "proxy"
- log_all_url: "enable"
- options: "js"
- ovrd_perm: "bannedword-override"
- post_action: "block"
- web_content_log: "enable"
- web_extended_all_action_log: "enable"
- web_filter_activex_log: "enable"
- web_filter_applet_log: "enable"
- web_filter_command_block_log: "enable"
- web_filter_cookie_log: "enable"
- web_filter_cookie_removal_log: "enable"
- web_filter_js_log: "enable"
- web_filter_jscript_log: "enable"
- web_filter_referer_log: "enable"
- web_filter_unknown_log: "enable"
- web_filter_vbs_log: "enable"
- web_ftgd_err_log: "enable"
- web_ftgd_quota_usage: "enable"
- web_invalid_domain_log: "enable"
- web_url_log: "enable"
- wisp: "enable"
- wisp_algorithm: "auto-learning"
- youtube_channel_status: "blacklist"
-'''
-
-RETURN = """
-api_result:
- description: full API response, includes status code and message
- returned: always
- type: str
-"""
-
-from ansible.module_utils.basic import AnsibleModule, env_fallback
-from ansible.module_utils.connection import Connection
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGBaseException
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRCommon
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FMGRMethods
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import DEFAULT_RESULT_OBJ
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import prepare_dict
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import scrub_dict
-
-
-def fmgr_webfilter_profile_modify(fmgr, paramgram):
-
- mode = paramgram["mode"]
- adom = paramgram["adom"]
-
- response = DEFAULT_RESULT_OBJ
- url = ""
- datagram = {}
-
- # EVAL THE MODE PARAMETER FOR SET OR ADD
- if mode in ['set', 'add', 'update']:
- url = '/pm/config/adom/{adom}/obj/webfilter/profile'.format(adom=adom)
- datagram = scrub_dict(prepare_dict(paramgram))
-
- # EVAL THE MODE PARAMETER FOR DELETE
- elif mode == "delete":
- # SET THE CORRECT URL FOR DELETE
- url = '/pm/config/adom/{adom}/obj/webfilter/profile/{name}'.format(adom=adom, name=paramgram["name"])
- datagram = {}
-
- response = fmgr.process_request(url, datagram, paramgram["mode"])
-
- return response
-
-
-#############
-# END METHODS
-#############
-
-
-def main():
- argument_spec = dict(
- adom=dict(type="str", default="root"),
- mode=dict(choices=["add", "set", "delete", "update"], type="str", default="add"),
-
- youtube_channel_status=dict(required=False, type="str", choices=["disable", "blacklist", "whitelist"]),
- wisp_servers=dict(required=False, type="str"),
- wisp_algorithm=dict(required=False, type="str", choices=["auto-learning", "primary-secondary", "round-robin"]),
- wisp=dict(required=False, type="str", choices=["disable", "enable"]),
- web_url_log=dict(required=False, type="str", choices=["disable", "enable"]),
- web_invalid_domain_log=dict(required=False, type="str", choices=["disable", "enable"]),
- web_ftgd_quota_usage=dict(required=False, type="str", choices=["disable", "enable"]),
- web_ftgd_err_log=dict(required=False, type="str", choices=["disable", "enable"]),
- web_filter_vbs_log=dict(required=False, type="str", choices=["disable", "enable"]),
- web_filter_unknown_log=dict(required=False, type="str", choices=["disable", "enable"]),
- web_filter_referer_log=dict(required=False, type="str", choices=["disable", "enable"]),
- web_filter_jscript_log=dict(required=False, type="str", choices=["disable", "enable"]),
- web_filter_js_log=dict(required=False, type="str", choices=["disable", "enable"]),
- web_filter_cookie_removal_log=dict(required=False, type="str", choices=["disable", "enable"]),
- web_filter_cookie_log=dict(required=False, type="str", choices=["disable", "enable"]),
- web_filter_command_block_log=dict(required=False, type="str", choices=["disable", "enable"]),
- web_filter_applet_log=dict(required=False, type="str", choices=["disable", "enable"]),
- web_filter_activex_log=dict(required=False, type="str", choices=["disable", "enable"]),
- web_extended_all_action_log=dict(required=False, type="str", choices=["disable", "enable"]),
- web_content_log=dict(required=False, type="str", choices=["disable", "enable"]),
- replacemsg_group=dict(required=False, type="str"),
- post_action=dict(required=False, type="str", choices=["normal", "block"]),
- ovrd_perm=dict(required=False, type="list", choices=["bannedword-override",
- "urlfilter-override",
- "fortiguard-wf-override",
- "contenttype-check-override"]),
- options=dict(required=False, type="list", choices=["block-invalid-url",
- "jscript",
- "js",
- "vbs",
- "unknown",
- "wf-referer",
- "intrinsic",
- "wf-cookie",
- "per-user-bwl",
- "activexfilter",
- "cookiefilter",
- "javafilter"]),
- name=dict(required=False, type="str"),
- log_all_url=dict(required=False, type="str", choices=["disable", "enable"]),
- inspection_mode=dict(required=False, type="str", choices=["proxy", "flow-based"]),
- https_replacemsg=dict(required=False, type="str", choices=["disable", "enable"]),
- extended_log=dict(required=False, type="str", choices=["disable", "enable"]),
- comment=dict(required=False, type="str"),
- ftgd_wf=dict(required=False, type="list"),
- ftgd_wf_exempt_quota=dict(required=False, type="str"),
- ftgd_wf_max_quota_timeout=dict(required=False, type="int"),
- ftgd_wf_options=dict(required=False, type="str", choices=["error-allow", "rate-server-ip",
- "connect-request-bypass", "ftgd-disable"]),
- ftgd_wf_ovrd=dict(required=False, type="str"),
- ftgd_wf_rate_crl_urls=dict(required=False, type="str", choices=["disable", "enable"]),
- ftgd_wf_rate_css_urls=dict(required=False, type="str", choices=["disable", "enable"]),
- ftgd_wf_rate_image_urls=dict(required=False, type="str", choices=["disable", "enable"]),
- ftgd_wf_rate_javascript_urls=dict(required=False, type="str", choices=["disable", "enable"]),
-
- ftgd_wf_filters_action=dict(required=False, type="str", choices=["block", "monitor",
- "warning", "authenticate"]),
- ftgd_wf_filters_auth_usr_grp=dict(required=False, type="str"),
- ftgd_wf_filters_category=dict(required=False, type="str"),
- ftgd_wf_filters_log=dict(required=False, type="str", choices=["disable", "enable"]),
- ftgd_wf_filters_override_replacemsg=dict(required=False, type="str"),
- ftgd_wf_filters_warn_duration=dict(required=False, type="str"),
- ftgd_wf_filters_warning_duration_type=dict(required=False, type="str", choices=["session", "timeout"]),
- ftgd_wf_filters_warning_prompt=dict(required=False, type="str", choices=["per-domain", "per-category"]),
-
- ftgd_wf_quota_category=dict(required=False, type="str"),
- ftgd_wf_quota_duration=dict(required=False, type="str"),
- ftgd_wf_quota_override_replacemsg=dict(required=False, type="str"),
- ftgd_wf_quota_type=dict(required=False, type="str", choices=["time", "traffic"]),
- ftgd_wf_quota_unit=dict(required=False, type="str", choices=["B", "KB", "MB", "GB"]),
- ftgd_wf_quota_value=dict(required=False, type="int"),
- override=dict(required=False, type="list"),
- override_ovrd_cookie=dict(required=False, type="str", choices=["deny", "allow"]),
- override_ovrd_dur=dict(required=False, type="str"),
- override_ovrd_dur_mode=dict(required=False, type="str", choices=["constant", "ask"]),
- override_ovrd_scope=dict(required=False, type="str", choices=["user", "user-group", "ip", "ask", "browser"]),
- override_ovrd_user_group=dict(required=False, type="str"),
- override_profile=dict(required=False, type="str"),
- override_profile_attribute=dict(required=False, type="list", choices=["User-Name",
- "NAS-IP-Address",
- "Framed-IP-Address",
- "Framed-IP-Netmask",
- "Filter-Id",
- "Login-IP-Host",
- "Reply-Message",
- "Callback-Number",
- "Callback-Id",
- "Framed-Route",
- "Framed-IPX-Network",
- "Class",
- "Called-Station-Id",
- "Calling-Station-Id",
- "NAS-Identifier",
- "Proxy-State",
- "Login-LAT-Service",
- "Login-LAT-Node",
- "Login-LAT-Group",
- "Framed-AppleTalk-Zone",
- "Acct-Session-Id",
- "Acct-Multi-Session-Id"]),
- override_profile_type=dict(required=False, type="str", choices=["list", "radius"]),
- url_extraction=dict(required=False, type="list"),
- url_extraction_redirect_header=dict(required=False, type="str"),
- url_extraction_redirect_no_content=dict(required=False, type="str", choices=["disable", "enable"]),
- url_extraction_redirect_url=dict(required=False, type="str"),
- url_extraction_server_fqdn=dict(required=False, type="str"),
- url_extraction_status=dict(required=False, type="str", choices=["disable", "enable"]),
- web=dict(required=False, type="list"),
- web_blacklist=dict(required=False, type="str", choices=["disable", "enable"]),
- web_bword_table=dict(required=False, type="str"),
- web_bword_threshold=dict(required=False, type="int"),
- web_content_header_list=dict(required=False, type="str"),
- web_keyword_match=dict(required=False, type="str"),
- web_log_search=dict(required=False, type="str", choices=["disable", "enable"]),
- web_safe_search=dict(required=False, type="str", choices=["url", "header"]),
- web_urlfilter_table=dict(required=False, type="str"),
- web_whitelist=dict(required=False, type="list", choices=["exempt-av",
- "exempt-webcontent",
- "exempt-activex-java-cookie",
- "exempt-dlp",
- "exempt-rangeblock",
- "extended-log-others"]),
- web_youtube_restrict=dict(required=False, type="str", choices=["strict", "none", "moderate"]),
- youtube_channel_filter=dict(required=False, type="list"),
- youtube_channel_filter_channel_id=dict(required=False, type="str"),
- youtube_channel_filter_comment=dict(required=False, type="str"),
-
- )
-
- module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
- # MODULE PARAMGRAM
- paramgram = {
- "mode": module.params["mode"],
- "adom": module.params["adom"],
- "youtube-channel-status": module.params["youtube_channel_status"],
- "wisp-servers": module.params["wisp_servers"],
- "wisp-algorithm": module.params["wisp_algorithm"],
- "wisp": module.params["wisp"],
- "web-url-log": module.params["web_url_log"],
- "web-invalid-domain-log": module.params["web_invalid_domain_log"],
- "web-ftgd-quota-usage": module.params["web_ftgd_quota_usage"],
- "web-ftgd-err-log": module.params["web_ftgd_err_log"],
- "web-filter-vbs-log": module.params["web_filter_vbs_log"],
- "web-filter-unknown-log": module.params["web_filter_unknown_log"],
- "web-filter-referer-log": module.params["web_filter_referer_log"],
- "web-filter-jscript-log": module.params["web_filter_jscript_log"],
- "web-filter-js-log": module.params["web_filter_js_log"],
- "web-filter-cookie-removal-log": module.params["web_filter_cookie_removal_log"],
- "web-filter-cookie-log": module.params["web_filter_cookie_log"],
- "web-filter-command-block-log": module.params["web_filter_command_block_log"],
- "web-filter-applet-log": module.params["web_filter_applet_log"],
- "web-filter-activex-log": module.params["web_filter_activex_log"],
- "web-extended-all-action-log": module.params["web_extended_all_action_log"],
- "web-content-log": module.params["web_content_log"],
- "replacemsg-group": module.params["replacemsg_group"],
- "post-action": module.params["post_action"],
- "ovrd-perm": module.params["ovrd_perm"],
- "options": module.params["options"],
- "name": module.params["name"],
- "log-all-url": module.params["log_all_url"],
- "inspection-mode": module.params["inspection_mode"],
- "https-replacemsg": module.params["https_replacemsg"],
- "extended-log": module.params["extended_log"],
- "comment": module.params["comment"],
- "ftgd-wf": {
- "exempt-quota": module.params["ftgd_wf_exempt_quota"],
- "max-quota-timeout": module.params["ftgd_wf_max_quota_timeout"],
- "options": module.params["ftgd_wf_options"],
- "ovrd": module.params["ftgd_wf_ovrd"],
- "rate-crl-urls": module.params["ftgd_wf_rate_crl_urls"],
- "rate-css-urls": module.params["ftgd_wf_rate_css_urls"],
- "rate-image-urls": module.params["ftgd_wf_rate_image_urls"],
- "rate-javascript-urls": module.params["ftgd_wf_rate_javascript_urls"],
- "filters": {
- "action": module.params["ftgd_wf_filters_action"],
- "auth-usr-grp": module.params["ftgd_wf_filters_auth_usr_grp"],
- "category": module.params["ftgd_wf_filters_category"],
- "log": module.params["ftgd_wf_filters_log"],
- "override-replacemsg": module.params["ftgd_wf_filters_override_replacemsg"],
- "warn-duration": module.params["ftgd_wf_filters_warn_duration"],
- "warning-duration-type": module.params["ftgd_wf_filters_warning_duration_type"],
- "warning-prompt": module.params["ftgd_wf_filters_warning_prompt"],
- },
- "quota": {
- "category": module.params["ftgd_wf_quota_category"],
- "duration": module.params["ftgd_wf_quota_duration"],
- "override-replacemsg": module.params["ftgd_wf_quota_override_replacemsg"],
- "type": module.params["ftgd_wf_quota_type"],
- "unit": module.params["ftgd_wf_quota_unit"],
- "value": module.params["ftgd_wf_quota_value"],
- },
- },
- "override": {
- "ovrd-cookie": module.params["override_ovrd_cookie"],
- "ovrd-dur": module.params["override_ovrd_dur"],
- "ovrd-dur-mode": module.params["override_ovrd_dur_mode"],
- "ovrd-scope": module.params["override_ovrd_scope"],
- "ovrd-user-group": module.params["override_ovrd_user_group"],
- "profile": module.params["override_profile"],
- "profile-attribute": module.params["override_profile_attribute"],
- "profile-type": module.params["override_profile_type"],
- },
- "url-extraction": {
- "redirect-header": module.params["url_extraction_redirect_header"],
- "redirect-no-content": module.params["url_extraction_redirect_no_content"],
- "redirect-url": module.params["url_extraction_redirect_url"],
- "server-fqdn": module.params["url_extraction_server_fqdn"],
- "status": module.params["url_extraction_status"],
- },
- "web": {
- "blacklist": module.params["web_blacklist"],
- "bword-table": module.params["web_bword_table"],
- "bword-threshold": module.params["web_bword_threshold"],
- "content-header-list": module.params["web_content_header_list"],
- "keyword-match": module.params["web_keyword_match"],
- "log-search": module.params["web_log_search"],
- "safe-search": module.params["web_safe_search"],
- "urlfilter-table": module.params["web_urlfilter_table"],
- "whitelist": module.params["web_whitelist"],
- "youtube-restrict": module.params["web_youtube_restrict"],
- },
- "youtube-channel-filter": {
- "channel-id": module.params["youtube_channel_filter_channel_id"],
- "comment": module.params["youtube_channel_filter_comment"],
- }
- }
- module.paramgram = paramgram
- fmgr = None
- if module._socket_path:
- connection = Connection(module._socket_path)
- fmgr = FortiManagerHandler(connection, module)
- fmgr.tools = FMGRCommon()
- else:
- module.fail_json(**FAIL_SOCKET_MSG)
-
- list_overrides = ['ftgd-wf', 'override', 'url-extraction', 'web', 'youtube-channel-filter']
- paramgram = fmgr.tools.paramgram_child_list_override(list_overrides=list_overrides,
- paramgram=paramgram, module=module)
-
- results = DEFAULT_RESULT_OBJ
-
- try:
-
- results = fmgr_webfilter_profile_modify(fmgr, paramgram)
- fmgr.govern_response(module=module, results=results,
- ansible_facts=fmgr.construct_ansible_facts(results, module.params, paramgram))
-
- except Exception as err:
- raise FMGBaseException(err)
-
- return module.exit_json(**results[1])
-
-
-if __name__ == "__main__":
- main()
diff --git a/ansible_collections/community/fortios/tests/requirements.yml b/ansible_collections/community/fortios/tests/requirements.yml
deleted file mode 100644
index 36ee27096..000000000
--- a/ansible_collections/community/fortios/tests/requirements.yml
+++ /dev/null
@@ -1,2 +0,0 @@
-unit_tests_dependencies:
-- fortinet.fortios
diff --git a/ansible_collections/community/fortios/tests/sanity/ignore-2.10.txt b/ansible_collections/community/fortios/tests/sanity/ignore-2.10.txt
deleted file mode 100644
index 4a289a0fb..000000000
--- a/ansible_collections/community/fortios/tests/sanity/ignore-2.10.txt
+++ /dev/null
@@ -1,51 +0,0 @@
-plugins/modules/faz_device.py validate-modules:doc-required-mismatch
-plugins/modules/fmgr_device.py validate-modules:doc-required-mismatch
-plugins/modules/fmgr_device.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_device_config.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_device_group.py validate-modules:doc-required-mismatch
-plugins/modules/fmgr_device_group.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_device_provision_template.py validate-modules:doc-required-mismatch
-plugins/modules/fmgr_device_provision_template.py validate-modules:invalid-argument-name
-plugins/modules/fmgr_device_provision_template.py validate-modules:nonexistent-parameter-documented
-plugins/modules/fmgr_device_provision_template.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_fwobj_address.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_fwobj_ippool.py validate-modules:parameter-list-no-elements
-plugins/modules/fmgr_fwobj_ippool.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_fwobj_ippool6.py validate-modules:parameter-list-no-elements
-plugins/modules/fmgr_fwobj_ippool6.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_fwobj_service.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_fwobj_vip.py validate-modules:parameter-list-no-elements
-plugins/modules/fmgr_fwobj_vip.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_fwpol_ipv4.py validate-modules:parameter-list-no-elements
-plugins/modules/fmgr_fwpol_ipv4.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_fwpol_package.py validate-modules:doc-required-mismatch
-plugins/modules/fmgr_fwpol_package.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_ha.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_provisioning.py validate-modules:doc-missing-type
-plugins/modules/fmgr_provisioning.py validate-modules:doc-required-mismatch
-plugins/modules/fmgr_provisioning.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_query.py validate-modules:parameter-list-no-elements
-plugins/modules/fmgr_query.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_script.py validate-modules:doc-default-does-not-match-spec
-plugins/modules/fmgr_script.py validate-modules:doc-required-mismatch
-plugins/modules/fmgr_script.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_secprof_appctrl.py validate-modules:parameter-list-no-elements
-plugins/modules/fmgr_secprof_appctrl.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_secprof_av.py validate-modules:parameter-list-no-elements
-plugins/modules/fmgr_secprof_av.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_secprof_dns.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_secprof_ips.py validate-modules:parameter-list-no-elements
-plugins/modules/fmgr_secprof_ips.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_secprof_profile_group.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_secprof_proxy.py validate-modules:parameter-list-no-elements
-plugins/modules/fmgr_secprof_proxy.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_secprof_spam.py validate-modules:parameter-list-no-elements
-plugins/modules/fmgr_secprof_spam.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_secprof_ssl_ssh.py validate-modules:parameter-list-no-elements
-plugins/modules/fmgr_secprof_ssl_ssh.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_secprof_voip.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_secprof_waf.py validate-modules:parameter-list-no-elements
-plugins/modules/fmgr_secprof_waf.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_secprof_wanopt.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_secprof_web.py validate-modules:parameter-list-no-elements
-plugins/modules/fmgr_secprof_web.py validate-modules:parameter-type-not-in-doc
diff --git a/ansible_collections/community/fortios/tests/sanity/ignore-2.11.txt b/ansible_collections/community/fortios/tests/sanity/ignore-2.11.txt
deleted file mode 100644
index 4a289a0fb..000000000
--- a/ansible_collections/community/fortios/tests/sanity/ignore-2.11.txt
+++ /dev/null
@@ -1,51 +0,0 @@
-plugins/modules/faz_device.py validate-modules:doc-required-mismatch
-plugins/modules/fmgr_device.py validate-modules:doc-required-mismatch
-plugins/modules/fmgr_device.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_device_config.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_device_group.py validate-modules:doc-required-mismatch
-plugins/modules/fmgr_device_group.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_device_provision_template.py validate-modules:doc-required-mismatch
-plugins/modules/fmgr_device_provision_template.py validate-modules:invalid-argument-name
-plugins/modules/fmgr_device_provision_template.py validate-modules:nonexistent-parameter-documented
-plugins/modules/fmgr_device_provision_template.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_fwobj_address.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_fwobj_ippool.py validate-modules:parameter-list-no-elements
-plugins/modules/fmgr_fwobj_ippool.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_fwobj_ippool6.py validate-modules:parameter-list-no-elements
-plugins/modules/fmgr_fwobj_ippool6.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_fwobj_service.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_fwobj_vip.py validate-modules:parameter-list-no-elements
-plugins/modules/fmgr_fwobj_vip.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_fwpol_ipv4.py validate-modules:parameter-list-no-elements
-plugins/modules/fmgr_fwpol_ipv4.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_fwpol_package.py validate-modules:doc-required-mismatch
-plugins/modules/fmgr_fwpol_package.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_ha.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_provisioning.py validate-modules:doc-missing-type
-plugins/modules/fmgr_provisioning.py validate-modules:doc-required-mismatch
-plugins/modules/fmgr_provisioning.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_query.py validate-modules:parameter-list-no-elements
-plugins/modules/fmgr_query.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_script.py validate-modules:doc-default-does-not-match-spec
-plugins/modules/fmgr_script.py validate-modules:doc-required-mismatch
-plugins/modules/fmgr_script.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_secprof_appctrl.py validate-modules:parameter-list-no-elements
-plugins/modules/fmgr_secprof_appctrl.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_secprof_av.py validate-modules:parameter-list-no-elements
-plugins/modules/fmgr_secprof_av.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_secprof_dns.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_secprof_ips.py validate-modules:parameter-list-no-elements
-plugins/modules/fmgr_secprof_ips.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_secprof_profile_group.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_secprof_proxy.py validate-modules:parameter-list-no-elements
-plugins/modules/fmgr_secprof_proxy.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_secprof_spam.py validate-modules:parameter-list-no-elements
-plugins/modules/fmgr_secprof_spam.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_secprof_ssl_ssh.py validate-modules:parameter-list-no-elements
-plugins/modules/fmgr_secprof_ssl_ssh.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_secprof_voip.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_secprof_waf.py validate-modules:parameter-list-no-elements
-plugins/modules/fmgr_secprof_waf.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_secprof_wanopt.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_secprof_web.py validate-modules:parameter-list-no-elements
-plugins/modules/fmgr_secprof_web.py validate-modules:parameter-type-not-in-doc
diff --git a/ansible_collections/community/fortios/tests/sanity/ignore-2.9.txt b/ansible_collections/community/fortios/tests/sanity/ignore-2.9.txt
deleted file mode 100644
index fc1eac658..000000000
--- a/ansible_collections/community/fortios/tests/sanity/ignore-2.9.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-plugins/modules/fmgr_device.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_device_config.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_device_group.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_device_provision_template.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_fwobj_address.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_fwobj_ippool.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_fwobj_ippool6.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_fwobj_service.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_fwobj_vip.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_fwpol_ipv4.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_fwpol_package.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_ha.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_provisioning.py validate-modules:doc-missing-type
-plugins/modules/fmgr_provisioning.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_query.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_script.py validate-modules:doc-default-does-not-match-spec
-plugins/modules/fmgr_script.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_secprof_appctrl.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_secprof_av.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_secprof_dns.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_secprof_ips.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_secprof_profile_group.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_secprof_proxy.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_secprof_spam.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_secprof_ssl_ssh.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_secprof_voip.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_secprof_waf.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_secprof_wanopt.py validate-modules:parameter-type-not-in-doc
-plugins/modules/fmgr_secprof_web.py validate-modules:parameter-type-not-in-doc
diff --git a/ansible_collections/community/fortios/tests/unit/compat/mock.py b/ansible_collections/community/fortios/tests/unit/compat/mock.py
deleted file mode 100644
index 0972cd2e8..000000000
--- a/ansible_collections/community/fortios/tests/unit/compat/mock.py
+++ /dev/null
@@ -1,122 +0,0 @@
-# (c) 2014, Toshio Kuratomi <tkuratomi@ansible.com>
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-'''
-Compat module for Python3.x's unittest.mock module
-'''
-import sys
-
-# Python 2.7
-
-# Note: Could use the pypi mock library on python3.x as well as python2.x. It
-# is the same as the python3 stdlib mock library
-
-try:
- # Allow wildcard import because we really do want to import all of mock's
- # symbols into this compat shim
- # pylint: disable=wildcard-import,unused-wildcard-import
- from unittest.mock import *
-except ImportError:
- # Python 2
- # pylint: disable=wildcard-import,unused-wildcard-import
- try:
- from mock import *
- except ImportError:
- print('You need the mock library installed on python2.x to run tests')
-
-
-# Prior to 3.4.4, mock_open cannot handle binary read_data
-if sys.version_info >= (3,) and sys.version_info < (3, 4, 4):
- file_spec = None
-
- def _iterate_read_data(read_data):
- # Helper for mock_open:
- # Retrieve lines from read_data via a generator so that separate calls to
- # readline, read, and readlines are properly interleaved
- sep = b'\n' if isinstance(read_data, bytes) else '\n'
- data_as_list = [l + sep for l in read_data.split(sep)]
-
- if data_as_list[-1] == sep:
- # If the last line ended in a newline, the list comprehension will have an
- # extra entry that's just a newline. Remove this.
- data_as_list = data_as_list[:-1]
- else:
- # If there wasn't an extra newline by itself, then the file being
- # emulated doesn't have a newline to end the last line remove the
- # newline that our naive format() added
- data_as_list[-1] = data_as_list[-1][:-1]
-
- for line in data_as_list:
- yield line
-
- def mock_open(mock=None, read_data=''):
- """
- A helper function to create a mock to replace the use of `open`. It works
- for `open` called directly or used as a context manager.
-
- The `mock` argument is the mock object to configure. If `None` (the
- default) then a `MagicMock` will be created for you, with the API limited
- to methods or attributes available on standard file handles.
-
- `read_data` is a string for the `read` methoddline`, and `readlines` of the
- file handle to return. This is an empty string by default.
- """
- def _readlines_side_effect(*args, **kwargs):
- if handle.readlines.return_value is not None:
- return handle.readlines.return_value
- return list(_data)
-
- def _read_side_effect(*args, **kwargs):
- if handle.read.return_value is not None:
- return handle.read.return_value
- return type(read_data)().join(_data)
-
- def _readline_side_effect():
- if handle.readline.return_value is not None:
- while True:
- yield handle.readline.return_value
- for line in _data:
- yield line
-
- global file_spec
- if file_spec is None:
- import _io
- file_spec = list(set(dir(_io.TextIOWrapper)).union(set(dir(_io.BytesIO))))
-
- if mock is None:
- mock = MagicMock(name='open', spec=open)
-
- handle = MagicMock(spec=file_spec)
- handle.__enter__.return_value = handle
-
- _data = _iterate_read_data(read_data)
-
- handle.write.return_value = None
- handle.read.return_value = None
- handle.readline.return_value = None
- handle.readlines.return_value = None
-
- handle.read.side_effect = _read_side_effect
- handle.readline.side_effect = _readline_side_effect()
- handle.readlines.side_effect = _readlines_side_effect
-
- mock.return_value = handle
- return mock
diff --git a/ansible_collections/community/fortios/tests/unit/compat/unittest.py b/ansible_collections/community/fortios/tests/unit/compat/unittest.py
deleted file mode 100644
index 98f08ad6a..000000000
--- a/ansible_collections/community/fortios/tests/unit/compat/unittest.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# (c) 2014, Toshio Kuratomi <tkuratomi@ansible.com>
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-'''
-Compat module for Python2.7's unittest module
-'''
-
-import sys
-
-# Allow wildcard import because we really do want to import all of
-# unittests's symbols into this compat shim
-# pylint: disable=wildcard-import,unused-wildcard-import
-if sys.version_info < (2, 7):
- try:
- # Need unittest2 on python2.6
- from unittest2 import *
- except ImportError:
- print('You need unittest2 installed on python2.6.x to run tests')
-else:
- from unittest import *
diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/fixtures/test_fmgr_device.json b/ansible_collections/community/fortios/tests/unit/plugins/modules/fixtures/test_fmgr_device.json
deleted file mode 100644
index 90dba75f0..000000000
--- a/ansible_collections/community/fortios/tests/unit/plugins/modules/fixtures/test_fmgr_device.json
+++ /dev/null
@@ -1,934 +0,0 @@
-{
- "add_device": [
- {
- "url": "/dvm/cmd/add/device/",
- "raw_response": {
- "device": {
- "adm_pass": "fortinet",
- "os_ver": 6,
- "ip": "10.7.220.151",
- "mgmt.__data[6]": 1,
- "vm_mem": 1003,
- "maxvdom": 10,
- "conn_mode": 1,
- "platform_id": 112,
- "branch_pt": 231,
- "hostname": "ansible-fgt01",
- "source": 1,
- "mgmt_id": 1014939351,
- "version": 600,
- "build": 231,
- "mgmt_mode": 3,
- "adm_usr": "admin",
- "av_ver": "1.00000(2018-04-09 18:07)",
- "mgmt.__data[4]": 1052262400,
- "oid": 403,
- "conn_status": 1,
- "beta": -1,
- "dev_status": 1,
- "platform_str": "FortiGate-VM64",
- "last_checked": 1550698141,
- "vm_mem_limit": 6144,
- "mgmt.__data[0]": 3870643,
- "name": "FGT1",
- "tab_status": "<unknown>",
- "patch": 4,
- "vm_cpu_limit": 4,
- "vm_status": 3,
- "ips_ver": "6.00741(2015-12-01 02:30)",
- "flags": 2097169,
- "sn": "FGVM04TM18000391",
- "mr": 0,
- "os_type": 0,
- "vm_cpu": 1
- }
- },
- "datagram_sent": {
- "device": {
- "adm_pass": "fortinet",
- "name": "FGT1",
- "ip": "10.7.220.151",
- "flags": 24,
- "sn": null,
- "mgmt_mode": "fmgfaz",
- "adm_usr": "admin"
- },
- "flags": [
- "create_task",
- "nonblocking"
- ],
- "odd_request_form": "True",
- "adom": "ansible"
- },
- "paramgram_used": {
- "device_username": "admin",
- "adom": "ansible",
- "device_ip": "10.7.220.151",
- "device_unique_name": "FGT1",
- "mode": "add",
- "device_serial": null,
- "device_password": "fortinet"
- },
- "post_method": "exec"
- },
- {
- "url": "/dvm/cmd/add/device/",
- "paramgram_used": {
- "device_username": "admin",
- "adom": "ansible",
- "device_ip": "10.7.220.152",
- "device_unique_name": "FGT2",
- "mode": "add",
- "device_serial": null,
- "device_password": "fortinet"
- },
- "datagram_sent": {
- "device": {
- "adm_pass": "fortinet",
- "name": "FGT2",
- "ip": "10.7.220.152",
- "flags": 24,
- "sn": null,
- "mgmt_mode": "fmgfaz",
- "adm_usr": "admin"
- },
- "flags": [
- "create_task",
- "nonblocking"
- ],
- "odd_request_form": "True",
- "adom": "ansible"
- },
- "raw_response": {
- "device": {
- "adm_pass": "fortinet",
- "ip": "10.7.220.152",
- "mgmt.__data[6]": 1,
- "vm_mem": 1003,
- "maxvdom": 10,
- "conn_mode": 1,
- "vm_cpu_limit": 4,
- "vm_cpu": 1,
- "branch_pt": 231,
- "hostname": "ansible-fgt02",
- "source": 1,
- "mgmt_id": 1879100317,
- "version": 600,
- "build": 231,
- "mgmt_mode": 3,
- "adm_usr": "admin",
- "av_ver": "1.00000(2018-04-09 18:07)",
- "oid": 415,
- "conn_status": 1,
- "beta": -1,
- "dev_status": 1,
- "platform_str": "FortiGate-VM64",
- "last_checked": 1550698177,
- "patch": 4,
- "vm_mem_limit": 6144,
- "mgmt.__data[0]": 3870643,
- "name": "FGT2",
- "tab_status": "<unknown>",
- "mgmt.__data[4]": 1052262400,
- "platform_id": 112,
- "vm_status": 3,
- "ips_ver": "6.00741(2015-12-01 02:30)",
- "flags": 2097169,
- "sn": "FGVM04TM18000392",
- "mr": 0,
- "os_type": 0,
- "os_ver": 6
- }
- },
- "post_method": "exec"
- },
- {
- "url": "/dvm/cmd/add/device/",
- "raw_response": {
- "device": {
- "adm_pass": "fortinet",
- "os_ver": 6,
- "ip": "10.7.220.153",
- "mgmt.__data[6]": 1,
- "vm_mem": 1003,
- "maxvdom": 10,
- "conn_mode": 1,
- "platform_id": 112,
- "branch_pt": 231,
- "hostname": "ansible-fgt03",
- "source": 1,
- "mgmt_id": 104863251,
- "version": 600,
- "build": 231,
- "mgmt_mode": 3,
- "adm_usr": "admin",
- "av_ver": "1.00000(2018-04-09 18:07)",
- "mgmt.__data[4]": 1052262400,
- "oid": 427,
- "conn_status": 1,
- "beta": -1,
- "dev_status": 1,
- "platform_str": "FortiGate-VM64",
- "last_checked": 1550698204,
- "vm_mem_limit": 6144,
- "mgmt.__data[0]": 3870643,
- "name": "FGT3",
- "tab_status": "<unknown>",
- "patch": 4,
- "vm_cpu_limit": 4,
- "vm_status": 3,
- "ips_ver": "6.00741(2015-12-01 02:30)",
- "flags": 2097169,
- "sn": "FGVM04TM18000393",
- "mr": 0,
- "os_type": 0,
- "vm_cpu": 1
- }
- },
- "datagram_sent": {
- "device": {
- "adm_pass": "fortinet",
- "name": "FGT3",
- "ip": "10.7.220.153",
- "flags": 24,
- "sn": null,
- "mgmt_mode": "fmgfaz",
- "adm_usr": "admin"
- },
- "flags": [
- "create_task",
- "nonblocking"
- ],
- "odd_request_form": "True",
- "adom": "ansible"
- },
- "paramgram_used": {
- "device_username": "admin",
- "adom": "ansible",
- "device_ip": "10.7.220.153",
- "device_unique_name": "FGT3",
- "mode": "add",
- "device_serial": null,
- "device_password": "fortinet"
- },
- "post_method": "exec"
- }
- ],
- "discover_device": [
- {
- "url": "/dvm/cmd/discover/device/",
- "paramgram_used": {
- "device_username": "admin",
- "adom": "ansible",
- "device_ip": "10.7.220.151",
- "device_unique_name": "FGT1",
- "mode": "add",
- "device_serial": null,
- "device_password": "fortinet"
- },
- "datagram_sent": {
- "device": {
- "adm_pass": "fortinet",
- "ip": "10.7.220.151",
- "adm_usr": "admin"
- },
- "odd_request_form": "True"
- },
- "raw_response": {
- "device": {
- "adm_pass": "fortinet",
- "ip": "10.7.220.151",
- "vm_mem": 1003,
- "maxvdom": 10,
- "conn_mode": 1,
- "vm_cpu_limit": 4,
- "vm_cpu": 1,
- "branch_pt": 231,
- "hostname": "ansible-fgt01",
- "source": 1,
- "version": 600,
- "build": 231,
- "adm_usr": "admin",
- "av_ver": "1.00000(2018-04-09 18:07)",
- "conn_status": 1,
- "beta": -1,
- "dev_status": 1,
- "platform_str": "FortiGate-VM64",
- "last_checked": 1550698136,
- "vm_mem_limit": 6144,
- "name": "ansible-fgt01",
- "tab_status": "<unknown>",
- "patch": 4,
- "platform_id": 112,
- "vm_status": 3,
- "ips_ver": "6.00741(2015-12-01 02:30)",
- "flags": 2097153,
- "sn": "FGVM04TM18000391",
- "mr": 0,
- "os_type": 0,
- "os_ver": 6
- }
- },
- "post_method": "exec"
- },
- {
- "url": "/dvm/cmd/discover/device/",
- "raw_response": {
- "device": {
- "adm_pass": "fortinet",
- "os_ver": 6,
- "ip": "10.7.220.152",
- "vm_mem": 1003,
- "maxvdom": 10,
- "conn_mode": 1,
- "platform_id": 112,
- "branch_pt": 231,
- "hostname": "ansible-fgt02",
- "source": 1,
- "version": 600,
- "build": 231,
- "adm_usr": "admin",
- "av_ver": "1.00000(2018-04-09 18:07)",
- "conn_status": 1,
- "beta": -1,
- "dev_status": 1,
- "platform_str": "FortiGate-VM64",
- "last_checked": 1550698173,
- "vm_mem_limit": 6144,
- "name": "ansible-fgt02",
- "tab_status": "<unknown>",
- "patch": 4,
- "vm_cpu_limit": 4,
- "vm_status": 3,
- "ips_ver": "6.00741(2015-12-01 02:30)",
- "flags": 2097153,
- "sn": "FGVM04TM18000392",
- "mr": 0,
- "os_type": 0,
- "vm_cpu": 1
- }
- },
- "datagram_sent": {
- "device": {
- "adm_pass": "fortinet",
- "ip": "10.7.220.152",
- "adm_usr": "admin"
- },
- "odd_request_form": "True"
- },
- "paramgram_used": {
- "device_username": "admin",
- "adom": "ansible",
- "device_ip": "10.7.220.152",
- "device_unique_name": "FGT2",
- "mode": "add",
- "device_serial": null,
- "device_password": "fortinet"
- },
- "post_method": "exec"
- },
- {
- "url": "/dvm/cmd/discover/device/",
- "paramgram_used": {
- "device_username": "admin",
- "adom": "ansible",
- "device_ip": "10.7.220.153",
- "device_unique_name": "FGT3",
- "mode": "add",
- "device_serial": null,
- "device_password": "fortinet"
- },
- "datagram_sent": {
- "device": {
- "adm_pass": "fortinet",
- "ip": "10.7.220.153",
- "adm_usr": "admin"
- },
- "odd_request_form": "True"
- },
- "raw_response": {
- "device": {
- "adm_pass": "fortinet",
- "ip": "10.7.220.153",
- "vm_mem": 1003,
- "maxvdom": 10,
- "conn_mode": 1,
- "vm_cpu_limit": 4,
- "vm_cpu": 1,
- "branch_pt": 231,
- "hostname": "ansible-fgt03",
- "source": 1,
- "version": 600,
- "build": 231,
- "adm_usr": "admin",
- "av_ver": "1.00000(2018-04-09 18:07)",
- "conn_status": 1,
- "beta": -1,
- "dev_status": 1,
- "platform_str": "FortiGate-VM64",
- "last_checked": 1550698200,
- "vm_mem_limit": 6144,
- "name": "ansible-fgt03",
- "tab_status": "<unknown>",
- "patch": 4,
- "platform_id": 112,
- "vm_status": 3,
- "ips_ver": "6.00741(2015-12-01 02:30)",
- "flags": 2097153,
- "sn": "FGVM04TM18000393",
- "mr": 0,
- "os_type": 0,
- "os_ver": 6
- }
- },
- "post_method": "exec"
- }
- ],
- "get_device": [
- {
- "url": "/dvmdb/adom/ansible/device/FGT1",
- "raw_response": {
- "adm_pass": [
- "ENC",
- "tUEPOPpQM6XsNwOPcWyrWoPoKo2DMjtFqOYEzLfF+99FpTkDmKa+GTmwBMLV1ns0OYrNgWnk6RPbRjSZSvu2LPYvCcWfQONLEZ1HlczZ00kEtDRCvRxG6l7FGtcj1Pl7QO9khy2lKWx4/lbPmLNqCzwCmlkAO5fGXR3nCbWPXH5BrRwO"
- ],
- "faz.perm": 0,
- "foslic_ram": 0,
- "foslic_type": "temporary",
- "last_checked": 1550635232,
- "psk": "",
- "opts": 0,
- "ip": "10.7.220.151",
- "foslic_utm": null,
- "logdisk_size": 30235,
- "mgmt.__data[6]": 1,
- "foslic_last_sync": 0,
- "app_ver": "",
- "ips_ext": 0,
- "vm_mem": 1003,
- "mgmt.__data[4]": 1052262400,
- "maxvdom": 10,
- "conn_mode": "passive",
- "location_from": "GUI(10.0.0.151)",
- "mgmt.__data[1]": 0,
- "mgmt.__data[2]": 0,
- "faz.full_act": 0,
- "os_ver": "6.0",
- "node_flags": 0,
- "hostname": "ansible-fgt01",
- "mgmt.__data[5]": 0,
- "mgmt_id": 2076985412,
- "hw_rev_minor": 0,
- "mgmt_if": "port1",
- "source": "faz",
- "ha_mode": "standalone",
- "version": 600,
- "build": 231,
- "latitude": "47.473991",
- "foslic_cpu": 0,
- "last_resync": 1550634702,
- "desc": "",
- "adm_usr": "admin",
- "vm_lic_expire": 0,
- "ha_slave": null,
- "av_ver": "1.00000(2018-04-09 18:07)",
- "fsw_cnt": 0,
- "tunnel_cookie": "",
- "foslic_inst_time": 0,
- "lic_flags": 0,
- "checksum": "89 1f b7 b7 2a a6 af 54 c5 a5 aa e3 32 92 c7 55",
- "oid": 366,
- "conn_status": "up",
- "fex_cnt": 0,
- "mgmt.__data[3]": 0,
- "beta": -1,
- "ha_group_name": "",
- "dev_status": "installed",
- "platform_str": "FortiGate-VM64",
- "mgmt.__data[7]": 0,
- "faz.used": 0,
- "fap_cnt": 0,
- "foslic_dr_site": "disable",
- "mgmt_mode": "fmgfaz",
- "vdom": [
- {
- "status": null,
- "oid": 3,
- "name": "root",
- "node_flags": 0,
- "devid": "FGT1",
- "tab_status": null,
- "comments": "",
- "flags": null,
- "opmode": "nat",
- "ext_flags": 1,
- "rtm_prof_id": 0
- }
- ],
- "hdisk_size": 30720,
- "vm_mem_limit": 6144,
- "mgmt.__data[0]": 3870643,
- "ha_group_id": 0,
- "name": "FGT1",
- "faz.quota": 0,
- "mgt_vdom": "root",
- "tab_status": "",
- "tunnel_ip": "169.254.0.5",
- "longitude": "-122.260963",
- "patch": 4,
- "vm_cpu_limit": 4,
- "vm_status": 3,
- "lic_region": "",
- "hw_rev_major": 0,
- "flags": [
- "has_hdd",
- "reload"
- ],
- "sn": "FGVM04TM18000391",
- "mr": 0,
- "conf_status": "insync",
- "os_type": "fos",
- "ips_ver": "6.00741(2015-12-01 02:30)",
- "db_status": "nomod",
- "branch_pt": 231,
- "vm_cpu": 1
- },
- "datagram_sent": {
- "filter": [
- "name",
- "==",
- "FGT1"
- ],
- "adom": "ansible"
- },
- "paramgram_used": {
- "device_username": "admin",
- "adom": "ansible",
- "device_ip": "10.7.220.151",
- "device_unique_name": "FGT1",
- "mode": "add",
- "device_serial": null,
- "device_password": "fortinet"
- },
- "post_method": "get"
- },
- {
- "url": "/dvmdb/adom/ansible/device/FGT2",
- "paramgram_used": {
- "device_username": "admin",
- "adom": "ansible",
- "device_ip": "10.7.220.152",
- "device_unique_name": "FGT2",
- "mode": "add",
- "device_serial": null,
- "device_password": "fortinet"
- },
- "datagram_sent": {
- "filter": [
- "name",
- "==",
- "FGT2"
- ],
- "adom": "ansible"
- },
- "raw_response": {
- "adm_pass": [
- "ENC",
- "F27zJSIl5O8O5rlXIi7BzHIUO5d3ZAuNxoniR42zOxGHyqZCx1OyA81b7v6dNwE30nBhjqfD+IDRmSPEW6qxKIQ2UV5eh8zgDNj8i5lj5gTvbLN5A4BR4CMLQo7nYTTomHUJQrGPfYskuxm74JGik+di9TrqOhvpZL8d1zj3XHx5pq+d"
- ],
- "faz.perm": 0,
- "hostname": "ansible-fgt02",
- "foslic_type": "temporary",
- "mgmt.__data[7]": 0,
- "av_ver": "1.00000(2018-04-09 18:07)",
- "ip": "10.7.220.152",
- "foslic_utm": null,
- "logdisk_size": 30235,
- "mgmt.__data[6]": 1,
- "fsw_cnt": 0,
- "app_ver": "",
- "ips_ext": 0,
- "vm_mem": 1003,
- "maxvdom": 10,
- "conn_mode": "passive",
- "mgt_vdom": "root",
- "mgmt.__data[1]": 0,
- "hw_rev_major": 0,
- "name": "FGT2",
- "node_flags": 0,
- "foslic_ram": 0,
- "mgmt.__data[5]": 0,
- "ha_mode": "standalone",
- "hw_rev_minor": 0,
- "mgmt_if": "port1",
- "source": "faz",
- "mgmt_id": 1555154046,
- "version": 600,
- "build": 231,
- "latitude": "47.473991",
- "foslic_cpu": 0,
- "last_resync": 1550634728,
- "hdisk_size": 30720,
- "adm_usr": "admin",
- "vm_lic_expire": 0,
- "sn": "FGVM04TM18000392",
- "ha_slave": null,
- "psk": "",
- "foslic_last_sync": 0,
- "tunnel_cookie": "",
- "vm_mem_limit": 6144,
- "mr": 0,
- "lic_flags": 0,
- "oid": 378,
- "conn_status": "up",
- "fex_cnt": 0,
- "vm_cpu": 1,
- "beta": -1,
- "ha_group_name": "",
- "dev_status": "retrieved",
- "platform_str": "FortiGate-VM64",
- "last_checked": 1550634728,
- "branch_pt": 231,
- "faz.used": 0,
- "patch": 4,
- "fap_cnt": 0,
- "foslic_dr_site": "disable",
- "mgmt_mode": "fmgfaz",
- "vdom": [
- {
- "status": null,
- "oid": 3,
- "name": "root",
- "node_flags": 4,
- "devid": "FGT2",
- "tab_status": null,
- "comments": "",
- "flags": null,
- "opmode": "nat",
- "ext_flags": 1,
- "rtm_prof_id": 0
- }
- ],
- "desc": "",
- "foslic_inst_time": 0,
- "mgmt.__data[0]": 3870643,
- "ha_group_id": 0,
- "location_from": "GUI(10.0.0.151)",
- "faz.quota": 0,
- "faz.full_act": 0,
- "tab_status": "",
- "tunnel_ip": "169.254.0.3",
- "longitude": "-122.260963",
- "mgmt.__data[4]": 1052262400,
- "vm_cpu_limit": 4,
- "vm_status": 3,
- "lic_region": "",
- "mgmt.__data[2]": 0,
- "flags": [
- "has_hdd",
- "reload"
- ],
- "opts": 0,
- "checksum": "56 e9 a7 14 e2 61 05 f9 ec 2b 00 1e 36 bc af c8",
- "conf_status": "insync",
- "os_type": "fos",
- "ips_ver": "6.00741(2015-12-01 02:30)",
- "db_status": "mod",
- "mgmt.__data[3]": 0,
- "os_ver": "6.0"
- },
- "post_method": "get"
- },
- {
- "url": "/dvmdb/adom/ansible/device/FGT3",
- "raw_response": {
- "adm_pass": [
- "ENC",
- "F27zJSIl5O8O5rlXIi7BzHIUO5d3ZAuNxoniR42zOxGHyqZCx1OyA81b7v6dNwE30nBhjqfD+IDRmSPEW6qxKIQ2UV5eh8zgDNj8i5lj5gTvbLN5A4BR4CMLQo7nYTTomHUJQrGPfYskuxm74JGik+di9TrqOhvpZL8d1zj3XHx5pq+d"
- ],
- "faz.perm": 0,
- "foslic_ram": 0,
- "foslic_type": "temporary",
- "last_checked": 1550634754,
- "psk": "",
- "opts": 0,
- "ip": "10.7.220.153",
- "foslic_utm": null,
- "logdisk_size": 30235,
- "mgmt.__data[6]": 1,
- "foslic_last_sync": 0,
- "app_ver": "",
- "ips_ext": 0,
- "vm_mem": 1003,
- "mgmt.__data[4]": 1052262400,
- "desc": "",
- "maxvdom": 10,
- "conn_mode": "passive",
- "location_from": "GUI(10.0.0.151)",
- "mgmt.__data[1]": 0,
- "os_ver": "6.0",
- "faz.full_act": 0,
- "node_flags": 0,
- "hostname": "ansible-fgt03",
- "mgmt.__data[5]": 0,
- "mgmt_id": 1175062219,
- "hw_rev_minor": 0,
- "mgmt_if": "port1",
- "source": "faz",
- "ha_mode": "standalone",
- "version": 600,
- "build": 231,
- "latitude": "47.473991",
- "foslic_cpu": 0,
- "last_resync": 1550634754,
- "hdisk_size": 30720,
- "adm_usr": "admin",
- "vm_lic_expire": 0,
- "conf_status": "insync",
- "ha_slave": null,
- "av_ver": "1.00000(2018-04-09 18:07)",
- "fsw_cnt": 0,
- "tunnel_cookie": "",
- "foslic_inst_time": 0,
- "lic_flags": 0,
- "oid": 390,
- "conn_status": "up",
- "fex_cnt": 0,
- "mgmt.__data[3]": 0,
- "beta": -1,
- "ha_group_name": "",
- "dev_status": "retrieved",
- "platform_str": "FortiGate-VM64",
- "mgmt.__data[7]": 0,
- "faz.used": 0,
- "fap_cnt": 0,
- "foslic_dr_site": "disable",
- "mgmt_mode": "fmgfaz",
- "vdom": [
- {
- "status": null,
- "oid": 3,
- "name": "root",
- "node_flags": 4,
- "devid": "FGT3",
- "tab_status": null,
- "comments": "",
- "flags": null,
- "opmode": "nat",
- "ext_flags": 1,
- "rtm_prof_id": 0
- }
- ],
- "name": "FGT3",
- "vm_mem_limit": 6144,
- "mgmt.__data[0]": 3870643,
- "ha_group_id": 0,
- "mgmt.__data[2]": 0,
- "faz.quota": 0,
- "checksum": "30 fc af f5 58 e4 1e 2d 46 c0 07 4b b6 4b c2 1b",
- "tab_status": "",
- "tunnel_ip": "169.254.0.4",
- "longitude": "-122.260963",
- "patch": 4,
- "vm_cpu_limit": 4,
- "vm_status": 3,
- "lic_region": "",
- "mgt_vdom": "root",
- "flags": [
- "has_hdd",
- "reload"
- ],
- "sn": "FGVM04TM18000393",
- "mr": 0,
- "hw_rev_major": 0,
- "os_type": "fos",
- "ips_ver": "6.00741(2015-12-01 02:30)",
- "db_status": "mod",
- "branch_pt": 231,
- "vm_cpu": 1
- },
- "datagram_sent": {
- "filter": [
- "name",
- "==",
- "FGT3"
- ],
- "adom": "ansible"
- },
- "paramgram_used": {
- "device_username": "admin",
- "adom": "ansible",
- "device_ip": "10.7.220.153",
- "device_unique_name": "FGT3",
- "mode": "add",
- "device_serial": null,
- "device_password": "fortinet"
- },
- "post_method": "get"
- },
- {
- "raw_response": {
- "status": {
- "message": "Object does not exist",
- "code": -3
- },
- "url": "/dvmdb/adom/ansible/device/FGT1"
- },
- "datagram_sent": {
- "filter": [
- "name",
- "==",
- "FGT1"
- ],
- "adom": "ansible"
- },
- "paramgram_used": {
- "device_username": "admin",
- "adom": "ansible",
- "device_ip": "10.7.220.151",
- "device_unique_name": "FGT1",
- "mode": "add",
- "device_serial": null,
- "device_password": "fortinet"
- },
- "post_method": "get"
- },
- {
- "paramgram_used": {
- "device_username": "admin",
- "adom": "ansible",
- "device_ip": "10.7.220.152",
- "device_unique_name": "FGT2",
- "mode": "add",
- "device_serial": null,
- "device_password": "fortinet"
- },
- "datagram_sent": {
- "filter": [
- "name",
- "==",
- "FGT2"
- ],
- "adom": "ansible"
- },
- "raw_response": {
- "status": {
- "message": "Object does not exist",
- "code": -3
- },
- "url": "/dvmdb/adom/ansible/device/FGT2"
- },
- "post_method": "get"
- },
- {
- "raw_response": {
- "status": {
- "message": "Object does not exist",
- "code": -3
- },
- "url": "/dvmdb/adom/ansible/device/FGT3"
- },
- "datagram_sent": {
- "filter": [
- "name",
- "==",
- "FGT3"
- ],
- "adom": "ansible"
- },
- "paramgram_used": {
- "device_username": "admin",
- "adom": "ansible",
- "device_ip": "10.7.220.153",
- "device_unique_name": "FGT3",
- "mode": "add",
- "device_serial": null,
- "device_password": "fortinet"
- },
- "post_method": "get"
- }
- ],
- "delete_device": [
- {
- "paramgram_used": {
- "device_username": "admin",
- "adom": "root",
- "device_ip": "10.7.220.151",
- "device_unique_name": "FGT1",
- "mode": "delete",
- "device_serial": null,
- "device_password": "fortinet"
- },
- "datagram_sent": {
- "device": "FGT1",
- "flags": [
- "create_task",
- "nonblocking"
- ],
- "adom": "root"
- },
- "raw_response": {
- "status": {
- "message": "OK",
- "code": 0
- },
- "url": "/dvm/cmd/del/device/"
- },
- "post_method": "exec"
- },
- {
- "raw_response": {
- "status": {
- "message": "OK",
- "code": 0
- },
- "url": "/dvm/cmd/del/device/"
- },
- "datagram_sent": {
- "device": "FGT2",
- "flags": [
- "create_task",
- "nonblocking"
- ],
- "adom": "ansible"
- },
- "paramgram_used": {
- "device_username": "admin",
- "adom": "ansible",
- "device_ip": "10.7.220.152",
- "device_unique_name": "FGT2",
- "mode": "delete",
- "device_serial": null,
- "device_password": "fortinet"
- },
- "post_method": "exec"
- },
- {
- "paramgram_used": {
- "device_username": "admin",
- "adom": "ansible",
- "device_ip": "10.7.220.153",
- "device_unique_name": "FGT3",
- "mode": "delete",
- "device_serial": null,
- "device_password": "fortinet"
- },
- "datagram_sent": {
- "device": "FGT3",
- "flags": [
- "create_task",
- "nonblocking"
- ],
- "adom": "ansible"
- },
- "raw_response": {
- "status": {
- "message": "OK",
- "code": 0
- },
- "url": "/dvm/cmd/del/device/"
- },
- "post_method": "exec"
- }
- ]
-}
diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/fixtures/test_fmgr_device_provision_template.json b/ansible_collections/community/fortios/tests/unit/plugins/modules/fixtures/test_fmgr_device_provision_template.json
deleted file mode 100644
index fb65ca5da..000000000
--- a/ansible_collections/community/fortios/tests/unit/plugins/modules/fixtures/test_fmgr_device_provision_template.json
+++ /dev/null
@@ -1,2063 +0,0 @@
-{
- "set_devprof_admin": [
- {
- "paramgram_used": {
- "snmpv3_security_level": null,
- "snmp_v2c_query_status": null,
- "provision_targets": null,
- "ntp_type": null,
- "dns_suffix": null,
- "snmpv3_queries": null,
- "snmpv3_trap_status": null,
- "snmp_v2c_name": null,
- "syslog_facility": "syslog",
- "snmp_v2c_status": null,
- "smtp_validate_cert": null,
- "snmpv3_name": null,
- "snmp_v2c_id": null,
- "syslog_port": null,
- "ntp_server": null,
- "admin_https_port": 4433,
- "ntp_status": null,
- "syslog_server": null,
- "admin_switch_controller": "enable",
- "admin_timeout": 60,
- "snmpv3_auth_proto": null,
- "smtp_port": null,
- "snmpv3_priv_pwd": null,
- "smtp_server": null,
- "syslog_enc_algorithm": "disable",
- "snmp_v2c_query_hosts_ipv4": null,
- "smtp_username": null,
- "mode": "set",
- "syslog_certificate": null,
- "admin_fortiguard_target": null,
- "snmpv3_query_port": null,
- "smtp_password": null,
- "adom": "ansible",
- "snmpv3_notify_hosts": null,
- "syslog_mode": "udp",
- "snmp_v2c_query_port": null,
- "snmp_v2c_trap_status": null,
- "snmp_status": null,
- "syslog_status": null,
- "snmp_v2c_trap_hosts_ipv4": null,
- "admin_fortianalyzer_target": "10.7.220.38",
- "snmp_v2c_trap_src_ipv4": null,
- "admin_http_port": 8080,
- "dns_secondary_ipv4": null,
- "syslog_filter": null,
- "snmpv3_source_ip": null,
- "snmpv3_trap_rport": null,
- "admin_gui_theme": "blue",
- "ntp_sync_interval": null,
- "ntp_auth_pwd": null,
- "provisioning_template": "ansibleTest",
- "ntp_v3": null,
- "ntp_auth": null,
- "snmp_v2c_trap_port": null,
- "snmpv3_priv_proto": null,
- "admin_enable_fortiguard": "this-fmg",
- "dns_primary_ipv4": null,
- "admin_language": "english",
- "smtp_conn_sec": null,
- "snmpv3_auth_pwd": null,
- "smtp_source_ipv4": null,
- "snmpv3_status": null,
- "delete_provisioning_template": null,
- "smtp_replyto": null,
- "admin_https_redirect": "enable"
- },
- "datagram_sent": {
- "admintimeout": 60,
- "switch-controller": "enable",
- "language": "english",
- "admin-port": 8080,
- "gui-theme": "blue",
- "admin-https-redirect": "enable",
- "admin-sport": 4433
- },
- "raw_response": {
- "status": {
- "message": "OK",
- "code": 0
- },
- "url": "/pm/config/adom/ansible/devprof/ansibleTest/system/global"
- },
- "post_method": "set"
- }
- ],
- "set_devprof_snmp_v3": [
- {
- "paramgram_used": {
- "snmpv3_security_level": "auth-priv",
- "snmp_v2c_query_status": null,
- "provision_targets": null,
- "ntp_type": null,
- "dns_suffix": null,
- "snmpv3_queries": "enable",
- "snmpv3_trap_status": "enable",
- "snmp_v2c_name": null,
- "syslog_facility": "syslog",
- "snmp_v2c_status": null,
- "smtp_validate_cert": null,
- "snmpv3_name": "ansibleSNMPv3",
- "snmp_v2c_id": null,
- "syslog_port": null,
- "ntp_server": null,
- "admin_https_port": null,
- "ntp_status": null,
- "syslog_server": null,
- "admin_switch_controller": null,
- "admin_timeout": null,
- "snmpv3_auth_proto": "sha",
- "smtp_port": null,
- "snmpv3_priv_pwd": "fortinet",
- "smtp_server": null,
- "syslog_enc_algorithm": "disable",
- "snmp_v2c_query_hosts_ipv4": null,
- "smtp_username": null,
- "mode": "set",
- "syslog_certificate": null,
- "admin_fortiguard_target": null,
- "snmpv3_query_port": 161,
- "smtp_password": null,
- "adom": "ansible",
- "snmpv3_notify_hosts": "10.7.220.59,10.7.220.60",
- "syslog_mode": "udp",
- "snmp_v2c_query_port": null,
- "snmp_v2c_trap_status": null,
- "snmp_status": "enable",
- "syslog_status": null,
- "admin_https_redirect": null,
- "admin_fortianalyzer_target": null,
- "snmp_v2c_trap_src_ipv4": null,
- "admin_http_port": null,
- "dns_secondary_ipv4": null,
- "syslog_filter": null,
- "snmpv3_source_ip": "0.0.0.0",
- "snmpv3_trap_rport": 162,
- "admin_gui_theme": null,
- "ntp_sync_interval": null,
- "ntp_auth_pwd": null,
- "provisioning_template": "ansibleTest",
- "smtp_replyto": null,
- "ntp_auth": null,
- "snmp_v2c_trap_port": null,
- "snmpv3_priv_proto": "aes256",
- "admin_enable_fortiguard": null,
- "dns_primary_ipv4": null,
- "admin_language": null,
- "smtp_conn_sec": null,
- "snmpv3_auth_pwd": "fortinet",
- "smtp_source_ipv4": null,
- "snmpv3_status": "enable",
- "delete_provisioning_template": null,
- "snmp_v2c_trap_hosts_ipv4": null,
- "ntp_v3": null
- },
- "datagram_sent": {
- "notify-hosts": [
- "10.7.220.59",
- "10.7.220.60"
- ],
- "name": "ansibleSNMPv3",
- "query-port": 161,
- "auth-pwd": "fortinet",
- "source-ip": "0.0.0.0",
- "priv-pwd": "fortinet",
- "trap-lport": 162,
- "ha-direct": 0,
- "trap-rport": 162,
- "events": 1647387997183
- },
- "raw_response": {
- "status": {
- "message": "OK",
- "code": 0
- },
- "url": "/pm/config/adom/ansible/devprof/ansibleTest/system/snmp/user"
- },
- "post_method": "set"
- }
- ],
- "set_devprof_scope": [
- {
- "paramgram_used": {
- "snmpv3_security_level": null,
- "snmp_v2c_query_status": null,
- "provision_targets": "FGT1,FGT2",
- "ntp_type": null,
- "dns_suffix": null,
- "snmpv3_queries": null,
- "snmpv3_trap_status": null,
- "snmp_v2c_name": null,
- "syslog_facility": "syslog",
- "snmp_v2c_status": null,
- "smtp_validate_cert": null,
- "snmpv3_name": null,
- "snmp_v2c_id": null,
- "syslog_port": null,
- "ntp_server": null,
- "admin_https_port": null,
- "ntp_status": null,
- "syslog_server": null,
- "admin_switch_controller": null,
- "admin_timeout": null,
- "snmpv3_auth_proto": null,
- "smtp_port": null,
- "snmpv3_priv_pwd": null,
- "smtp_server": null,
- "syslog_enc_algorithm": "disable",
- "snmp_v2c_query_hosts_ipv4": null,
- "smtp_username": null,
- "mode": "set",
- "syslog_certificate": null,
- "admin_fortiguard_target": null,
- "snmpv3_query_port": null,
- "smtp_password": null,
- "adom": "ansible",
- "snmpv3_notify_hosts": null,
- "syslog_mode": "udp",
- "snmp_v2c_query_port": null,
- "snmp_v2c_trap_status": null,
- "snmp_status": null,
- "syslog_status": null,
- "admin_https_redirect": null,
- "admin_fortianalyzer_target": null,
- "snmp_v2c_trap_src_ipv4": null,
- "admin_http_port": null,
- "dns_secondary_ipv4": null,
- "syslog_filter": null,
- "snmpv3_source_ip": null,
- "snmpv3_trap_rport": null,
- "admin_gui_theme": null,
- "ntp_sync_interval": null,
- "ntp_auth_pwd": null,
- "provisioning_template": "ansibleTest",
- "smtp_replyto": null,
- "ntp_auth": null,
- "snmp_v2c_trap_port": null,
- "snmpv3_priv_proto": null,
- "admin_enable_fortiguard": null,
- "dns_primary_ipv4": null,
- "admin_language": null,
- "smtp_conn_sec": null,
- "snmpv3_auth_pwd": null,
- "smtp_source_ipv4": null,
- "snmpv3_status": null,
- "delete_provisioning_template": null,
- "snmp_v2c_trap_hosts_ipv4": null,
- "ntp_v3": null
- },
- "datagram_sent": {
- "type": "devprof",
- "name": "ansibleTest",
- "scope member": [
- {
- "name": "FGT1"
- },
- {
- "name": "FGT2"
- }
- ],
- "description": "CreatedByAnsible"
- },
- "raw_response": {
- "status": {
- "message": "OK",
- "code": 0
- },
- "url": "/pm/devprof/adom/ansible"
- },
- "post_method": "set"
- }
- ],
- "set_devprof_snmp": [
- {
- "paramgram_used": {
- "snmpv3_security_level": null,
- "snmp_v2c_query_status": null,
- "provision_targets": null,
- "ntp_type": null,
- "dns_suffix": null,
- "snmpv3_queries": null,
- "snmpv3_trap_status": null,
- "snmp_v2c_name": null,
- "syslog_facility": "syslog",
- "snmp_v2c_status": null,
- "smtp_validate_cert": null,
- "snmpv3_name": null,
- "snmp_v2c_id": null,
- "syslog_port": null,
- "ntp_server": null,
- "admin_https_port": null,
- "ntp_status": null,
- "syslog_server": null,
- "admin_switch_controller": null,
- "admin_timeout": null,
- "snmpv3_auth_proto": null,
- "smtp_port": null,
- "snmpv3_priv_pwd": null,
- "smtp_server": null,
- "syslog_enc_algorithm": "disable",
- "snmp_v2c_query_hosts_ipv4": null,
- "smtp_username": null,
- "mode": "set",
- "syslog_certificate": null,
- "admin_fortiguard_target": null,
- "snmpv3_query_port": null,
- "smtp_password": null,
- "adom": "ansible",
- "snmpv3_notify_hosts": null,
- "syslog_mode": "udp",
- "snmp_v2c_query_port": null,
- "snmp_v2c_trap_status": null,
- "snmp_status": "enable",
- "syslog_status": null,
- "admin_https_redirect": null,
- "admin_fortianalyzer_target": null,
- "snmp_v2c_trap_src_ipv4": null,
- "admin_http_port": null,
- "dns_secondary_ipv4": null,
- "syslog_filter": null,
- "snmpv3_source_ip": null,
- "snmpv3_trap_rport": null,
- "admin_gui_theme": null,
- "ntp_sync_interval": null,
- "ntp_auth_pwd": null,
- "provisioning_template": "ansibleTest",
- "smtp_replyto": null,
- "ntp_auth": null,
- "snmp_v2c_trap_port": null,
- "snmpv3_priv_proto": null,
- "admin_enable_fortiguard": null,
- "dns_primary_ipv4": null,
- "admin_language": null,
- "smtp_conn_sec": null,
- "snmpv3_auth_pwd": null,
- "smtp_source_ipv4": null,
- "snmpv3_status": null,
- "delete_provisioning_template": null,
- "snmp_v2c_trap_hosts_ipv4": null,
- "ntp_v3": null
- },
- "datagram_sent": {
- "status": "enable"
- },
- "raw_response": {
- "status": {
- "message": "OK",
- "code": 0
- },
- "url": "/pm/config/adom/ansible/devprof/ansibleTest/system/snmp/sysinfo"
- },
- "post_method": "set"
- },
- {
- "paramgram_used": {
- "snmpv3_security_level": null,
- "snmp_v2c_query_status": "enable",
- "provision_targets": null,
- "ntp_type": null,
- "dns_suffix": null,
- "snmpv3_queries": null,
- "snmpv3_trap_status": null,
- "snmp_v2c_name": "ansibleV2c",
- "syslog_facility": "syslog",
- "snmp_v2c_status": "enable",
- "smtp_validate_cert": null,
- "snmpv3_name": null,
- "snmp_v2c_id": 1,
- "syslog_port": null,
- "ntp_server": null,
- "admin_https_port": null,
- "ntp_status": null,
- "syslog_server": null,
- "admin_switch_controller": null,
- "admin_timeout": null,
- "snmpv3_auth_proto": null,
- "smtp_port": null,
- "snmpv3_priv_pwd": null,
- "smtp_server": null,
- "syslog_enc_algorithm": "disable",
- "snmp_v2c_query_hosts_ipv4": "10.7.220.59 255.255.255.255, 10.7.220.0 255.255.255.0",
- "smtp_username": null,
- "mode": "set",
- "syslog_certificate": null,
- "admin_fortiguard_target": null,
- "snmpv3_query_port": null,
- "smtp_password": null,
- "adom": "ansible",
- "snmpv3_notify_hosts": null,
- "syslog_mode": "udp",
- "snmp_v2c_query_port": 162,
- "snmp_v2c_trap_status": "enable",
- "snmp_status": "enable",
- "syslog_status": null,
- "admin_https_redirect": null,
- "admin_fortianalyzer_target": null,
- "snmp_v2c_trap_src_ipv4": "10.7.220.41",
- "admin_http_port": null,
- "dns_secondary_ipv4": null,
- "syslog_filter": null,
- "snmpv3_source_ip": null,
- "snmpv3_trap_rport": null,
- "admin_gui_theme": null,
- "ntp_sync_interval": null,
- "ntp_auth_pwd": null,
- "provisioning_template": "ansibleTest",
- "smtp_replyto": null,
- "ntp_auth": null,
- "snmp_v2c_trap_port": 161,
- "snmpv3_priv_proto": null,
- "admin_enable_fortiguard": null,
- "dns_primary_ipv4": null,
- "admin_language": null,
- "smtp_conn_sec": null,
- "snmpv3_auth_pwd": null,
- "smtp_source_ipv4": null,
- "snmpv3_status": null,
- "delete_provisioning_template": null,
- "snmp_v2c_trap_hosts_ipv4": "10.7.220.59 255.255.255.255, 10.7.220.60 255.255.255.255",
- "ntp_v3": null
- },
- "datagram_sent": {
- "status": "enable"
- },
- "raw_response": {
- "status": {
- "message": "OK",
- "code": 0
- },
- "url": "/pm/config/adom/ansible/devprof/ansibleTest/system/snmp/sysinfo"
- },
- "post_method": "set"
- },
- {
- "raw_response": {
- "status": {
- "message": "OK",
- "code": 0
- },
- "url": "/pm/config/adom/ansible/devprof/ansibleTest/system/snmp/sysinfo"
- },
- "datagram_sent": {
- "status": "enable"
- },
- "paramgram_used": {
- "snmpv3_security_level": "auth-priv",
- "snmp_v2c_query_status": null,
- "ntp_type": null,
- "dns_suffix": null,
- "snmpv3_queries": "enable",
- "snmpv3_trap_status": "enable",
- "snmp_v2c_name": null,
- "syslog_facility": "syslog",
- "snmp_v2c_status": null,
- "smtp_validate_cert": null,
- "snmpv3_name": "ansibleSNMPv3",
- "snmp_v2c_trap_src_ipv4": null,
- "syslog_port": null,
- "ntp_server": null,
- "admin_https_port": null,
- "ntp_status": null,
- "syslog_server": null,
- "dns_primary_ipv4": null,
- "admin_timeout": null,
- "snmpv3_auth_proto": "sha",
- "smtp_port": null,
- "snmpv3_priv_pwd": "fortinet",
- "smtp_server": null,
- "syslog_enc_algorithm": "disable",
- "dns_secondary_ipv4": null,
- "smtp_username": null,
- "snmpv3_auth_pwd": "fortinet",
- "syslog_certificate": null,
- "admin_fortiguard_target": null,
- "snmpv3_query_port": 161,
- "smtp_password": null,
- "adom": "ansible",
- "snmpv3_notify_hosts": "10.7.220.59,10.7.220.60",
- "syslog_mode": "udp",
- "snmp_v2c_query_port": null,
- "snmp_v2c_trap_status": null,
- "snmp_status": "enable",
- "syslog_status": null,
- "admin_fortianalyzer_target": null,
- "ntp_auth": null,
- "snmp_v2c_id": null,
- "admin_http_port": null,
- "ntp_v3": null,
- "snmp_v2c_query_hosts_ipv4": null,
- "ntp_sync_interval": null,
- "snmpv3_source_ip": "0.0.0.0",
- "snmpv3_trap_rport": 162,
- "admin_gui_theme": null,
- "syslog_filter": null,
- "ntp_auth_pwd": null,
- "provisioning_template": "ansibleTest",
- "smtp_replyto": null,
- "provision_targets": null,
- "snmp_v2c_trap_port": null,
- "snmpv3_priv_proto": "aes256",
- "admin_enable_fortiguard": null,
- "admin_switch_controller": null,
- "admin_language": null,
- "smtp_conn_sec": null,
- "mode": "set",
- "smtp_source_ipv4": null,
- "snmpv3_status": "enable",
- "delete_provisioning_template": null,
- "snmp_v2c_trap_hosts_ipv4": null,
- "admin_https_redirect": null
- },
- "post_method": "set"
- }
- ],
- "set_devprof": [
- {
- "raw_response": {
- "status": {
- "message": "OK",
- "code": 0
- },
- "url": "/pm/devprof/adom/ansible/ansibleTest"
- },
- "datagram_sent": {},
- "paramgram_used": {
- "snmpv3_security_level": null,
- "snmp_v2c_query_status": null,
- "smtp_port": null,
- "ntp_type": null,
- "dns_suffix": null,
- "snmpv3_queries": null,
- "snmpv3_trap_status": null,
- "snmp_v2c_name": null,
- "syslog_facility": "syslog",
- "snmp_v2c_status": null,
- "smtp_validate_cert": null,
- "snmpv3_name": null,
- "snmp_v2c_trap_src_ipv4": null,
- "syslog_port": null,
- "ntp_server": null,
- "admin_https_port": null,
- "ntp_status": null,
- "syslog_server": null,
- "dns_primary_ipv4": null,
- "admin_timeout": null,
- "snmpv3_auth_proto": null,
- "ntp_auth": null,
- "snmpv3_priv_pwd": null,
- "smtp_server": null,
- "syslog_enc_algorithm": "disable",
- "dns_secondary_ipv4": null,
- "smtp_replyto": null,
- "smtp_username": null,
- "snmpv3_auth_pwd": null,
- "syslog_certificate": null,
- "admin_fortiguard_target": null,
- "snmpv3_query_port": null,
- "smtp_password": null,
- "adom": "ansible",
- "snmpv3_notify_hosts": null,
- "syslog_mode": "udp",
- "snmp_v2c_query_port": null,
- "snmp_v2c_trap_status": null,
- "snmp_status": null,
- "syslog_status": null,
- "admin_fortianalyzer_target": null,
- "snmp_v2c_id": null,
- "admin_http_port": null,
- "snmp_v2c_query_hosts_ipv4": null,
- "ntp_sync_interval": null,
- "snmpv3_source_ip": null,
- "snmpv3_trap_rport": null,
- "admin_gui_theme": null,
- "syslog_filter": null,
- "ntp_auth_pwd": null,
- "provisioning_template": null,
- "snmp_v2c_trap_hosts_ipv4": null,
- "provision_targets": null,
- "snmp_v2c_trap_port": null,
- "snmpv3_priv_proto": null,
- "admin_enable_fortiguard": null,
- "admin_switch_controller": null,
- "admin_language": null,
- "smtp_conn_sec": null,
- "mode": "delete",
- "smtp_source_ipv4": null,
- "snmpv3_status": null,
- "delete_provisioning_template": "ansibleTest",
- "ntp_v3": null,
- "admin_https_redirect": null
- },
- "post_method": "delete"
- }
- ],
- "set_devprof_dns": [
- {
- "paramgram_used": {
- "snmpv3_security_level": null,
- "snmp_v2c_query_status": null,
- "provision_targets": null,
- "ntp_type": null,
- "dns_suffix": "ansible.local",
- "snmpv3_queries": null,
- "snmpv3_trap_status": null,
- "snmp_v2c_name": null,
- "syslog_facility": "syslog",
- "snmp_v2c_status": null,
- "smtp_validate_cert": null,
- "snmpv3_name": null,
- "snmp_v2c_id": null,
- "syslog_port": null,
- "ntp_server": null,
- "admin_https_port": null,
- "ntp_status": null,
- "syslog_server": null,
- "admin_switch_controller": null,
- "admin_timeout": null,
- "snmpv3_auth_proto": null,
- "smtp_port": null,
- "snmpv3_priv_pwd": null,
- "smtp_server": null,
- "syslog_enc_algorithm": "disable",
- "snmp_v2c_query_hosts_ipv4": null,
- "smtp_username": null,
- "mode": "set",
- "syslog_certificate": null,
- "admin_fortiguard_target": null,
- "snmpv3_query_port": null,
- "smtp_password": null,
- "adom": "ansible",
- "snmpv3_notify_hosts": null,
- "syslog_mode": "udp",
- "snmp_v2c_query_port": null,
- "snmp_v2c_trap_status": null,
- "snmp_status": null,
- "syslog_status": null,
- "snmp_v2c_trap_hosts_ipv4": null,
- "admin_fortianalyzer_target": null,
- "snmp_v2c_trap_src_ipv4": null,
- "admin_http_port": null,
- "dns_secondary_ipv4": "4.4.4.4",
- "syslog_filter": null,
- "snmpv3_source_ip": null,
- "snmpv3_trap_rport": null,
- "admin_gui_theme": null,
- "ntp_sync_interval": null,
- "ntp_auth_pwd": null,
- "provisioning_template": "ansibleTest",
- "ntp_v3": null,
- "ntp_auth": null,
- "snmp_v2c_trap_port": null,
- "snmpv3_priv_proto": null,
- "admin_enable_fortiguard": null,
- "dns_primary_ipv4": "8.8.8.8",
- "admin_language": null,
- "smtp_conn_sec": null,
- "snmpv3_auth_pwd": null,
- "smtp_source_ipv4": null,
- "snmpv3_status": null,
- "delete_provisioning_template": null,
- "smtp_replyto": null,
- "admin_https_redirect": null
- },
- "datagram_sent": {
- "domain": "ansible.local",
- "primary": "8.8.8.8",
- "secondary": "4.4.4.4"
- },
- "raw_response": {
- "status": {
- "message": "OK",
- "code": 0
- },
- "url": "/pm/config/adom/ansible/devprof/ansibleTest/system/dns"
- },
- "post_method": "set"
- }
- ],
- "set_devprof_syslog": [
- {
- "paramgram_used": {
- "snmpv3_security_level": null,
- "snmp_v2c_query_status": null,
- "provision_targets": null,
- "ntp_type": null,
- "dns_suffix": null,
- "snmpv3_queries": null,
- "snmpv3_trap_status": null,
- "snmp_v2c_name": null,
- "syslog_facility": "kernel",
- "snmp_v2c_status": null,
- "smtp_validate_cert": null,
- "snmpv3_name": null,
- "snmp_v2c_id": null,
- "syslog_port": 514,
- "ntp_server": null,
- "admin_https_port": null,
- "ntp_status": null,
- "syslog_server": "10.7.220.59",
- "admin_switch_controller": null,
- "admin_timeout": null,
- "snmpv3_auth_proto": null,
- "smtp_port": null,
- "snmpv3_priv_pwd": null,
- "smtp_server": null,
- "syslog_enc_algorithm": "disable",
- "snmp_v2c_query_hosts_ipv4": null,
- "smtp_username": null,
- "mode": "set",
- "syslog_certificate": null,
- "admin_fortiguard_target": null,
- "snmpv3_query_port": null,
- "smtp_password": null,
- "adom": "ansible",
- "snmpv3_notify_hosts": null,
- "syslog_mode": "udp",
- "snmp_v2c_query_port": null,
- "snmp_v2c_trap_status": null,
- "snmp_status": null,
- "syslog_status": "enable",
- "snmp_v2c_trap_hosts_ipv4": null,
- "admin_fortianalyzer_target": null,
- "snmp_v2c_trap_src_ipv4": null,
- "admin_http_port": null,
- "dns_secondary_ipv4": null,
- "syslog_filter": "critical",
- "snmpv3_source_ip": null,
- "snmpv3_trap_rport": null,
- "admin_gui_theme": null,
- "ntp_sync_interval": null,
- "ntp_auth_pwd": null,
- "provisioning_template": "ansibleTest",
- "ntp_v3": null,
- "ntp_auth": null,
- "snmp_v2c_trap_port": null,
- "snmpv3_priv_proto": null,
- "admin_enable_fortiguard": null,
- "dns_primary_ipv4": null,
- "admin_language": null,
- "smtp_conn_sec": null,
- "snmpv3_auth_pwd": null,
- "smtp_source_ipv4": null,
- "snmpv3_status": null,
- "delete_provisioning_template": null,
- "smtp_replyto": null,
- "admin_https_redirect": null
- },
- "datagram_sent": {
- "status": "enable",
- "mode": "udp",
- "server": "10.7.220.59",
- "port": 514,
- "facility": "kernel"
- },
- "raw_response": {
- "status": {
- "message": "OK",
- "code": 0
- },
- "url": "/pm/config/adom/ansible/devprof/ansibleTest/log/syslogd/setting"
- },
- "post_method": "set"
- }
- ],
- "set_devprof_snmp_v2c": [
- {
- "url": "/pm/config/adom/ansible/devprof/ansibleTest/system/snmp/community",
- "raw_response": {
- "id": 1
- },
- "datagram_sent": {
- "status": "enable",
- "trap-v2c-lport": 162,
- "trap-v2c-status": "enable",
- "name": "ansibleV2c",
- "query-v1-port": 161,
- "meta fields": {},
- "query-v1-status": 0,
- "trap-v2c-rport": 161,
- "trap-v1-rport": 162,
- "query-v2c-port": 162,
- "hosts": [
- {
- "ip": [
- "10.7.220.59",
- "255.255.255.255"
- ],
- "source-ip": "0.0.0.0",
- "meta fields": {},
- "ha-direct": "enable",
- "id": 1,
- "host-type": "query"
- },
- {
- "ip": [
- "10.7.220.0",
- "255.255.255.0"
- ],
- "source-ip": "0.0.0.0",
- "meta fields": {},
- "ha-direct": "enable",
- "id": 2,
- "host-type": "query"
- },
- {
- "ip": [
- "10.7.220.59",
- "255.255.255.255"
- ],
- "source-ip": "10.7.220.41",
- "meta fields": {},
- "ha-direct": "enable",
- "id": 3,
- "host-type": "trap"
- },
- {
- "ip": [
- "10.7.220.60",
- "255.255.255.255"
- ],
- "source-ip": "10.7.220.41",
- "meta fields": {},
- "ha-direct": "enable",
- "id": 4,
- "host-type": "trap"
- }
- ],
- "trap-v1-status": 0,
- "events": 411578417151,
- "query-v2c-status": "enable",
- "id": 1,
- "trap-v1-lport": 162
- },
- "paramgram_used": {
- "snmpv3_security_level": null,
- "snmp_v2c_query_status": "enable",
- "ntp_type": null,
- "dns_suffix": null,
- "snmpv3_queries": null,
- "snmpv3_trap_status": null,
- "snmp_v2c_name": "ansibleV2c",
- "syslog_facility": "syslog",
- "snmp_v2c_status": "enable",
- "smtp_validate_cert": null,
- "snmpv3_name": null,
- "snmp_v2c_trap_src_ipv4": "10.7.220.41",
- "syslog_port": null,
- "ntp_server": null,
- "admin_https_port": null,
- "ntp_status": null,
- "syslog_server": null,
- "dns_primary_ipv4": null,
- "admin_timeout": null,
- "snmpv3_auth_proto": null,
- "smtp_port": null,
- "snmpv3_priv_pwd": null,
- "smtp_server": null,
- "syslog_enc_algorithm": "disable",
- "dns_secondary_ipv4": null,
- "smtp_replyto": null,
- "smtp_username": null,
- "snmpv3_auth_pwd": null,
- "syslog_certificate": null,
- "admin_fortiguard_target": null,
- "snmpv3_query_port": null,
- "smtp_password": null,
- "adom": "ansible",
- "snmpv3_notify_hosts": null,
- "syslog_mode": "udp",
- "snmp_v2c_query_port": 162,
- "snmp_v2c_trap_status": "enable",
- "snmp_status": "enable",
- "syslog_status": null,
- "admin_fortianalyzer_target": null,
- "ntp_auth": null,
- "snmp_v2c_id": 1,
- "admin_http_port": null,
- "snmp_v2c_query_hosts_ipv4": "10.7.220.59 255.255.255.255, 10.7.220.0 255.255.255.0",
- "ntp_sync_interval": null,
- "snmpv3_source_ip": null,
- "snmpv3_trap_rport": null,
- "admin_gui_theme": null,
- "syslog_filter": null,
- "ntp_auth_pwd": null,
- "provisioning_template": "ansibleTest",
- "snmp_v2c_trap_hosts_ipv4": "10.7.220.59 255.255.255.255, 10.7.220.60 255.255.255.255",
- "provision_targets": null,
- "snmp_v2c_trap_port": 161,
- "snmpv3_priv_proto": null,
- "admin_enable_fortiguard": null,
- "admin_switch_controller": null,
- "admin_language": null,
- "smtp_conn_sec": null,
- "mode": "set",
- "smtp_source_ipv4": null,
- "snmpv3_status": null,
- "delete_provisioning_template": null,
- "ntp_v3": null,
- "admin_https_redirect": null
- },
- "post_method": "set"
- }
- ],
- "get_devprof": [
- {
- "url": "/pm/devprof/adom/ansible/ansibleTest",
- "raw_response": {
- "enabled options": [
- "dns",
- "ntp",
- "email",
- "admin",
- "snmp",
- "repmsg",
- "ftgd",
- "log"
- ],
- "oid": 1542,
- "type": "devprof",
- "description": "CreatedByAnsible",
- "name": "ansibleTest"
- },
- "datagram_sent": {},
- "paramgram_used": {
- "snmpv3_security_level": null,
- "snmp_v2c_query_status": null,
- "ntp_type": null,
- "dns_suffix": null,
- "snmpv3_queries": null,
- "snmpv3_trap_status": null,
- "snmp_v2c_name": null,
- "syslog_facility": "syslog",
- "snmp_v2c_status": null,
- "smtp_validate_cert": null,
- "snmpv3_name": null,
- "snmp_v2c_trap_src_ipv4": null,
- "syslog_port": null,
- "ntp_server": null,
- "admin_https_port": null,
- "ntp_status": null,
- "syslog_server": null,
- "dns_primary_ipv4": null,
- "admin_timeout": null,
- "snmpv3_auth_proto": null,
- "smtp_port": null,
- "snmpv3_priv_pwd": null,
- "smtp_server": null,
- "syslog_enc_algorithm": "disable",
- "dns_secondary_ipv4": null,
- "smtp_username": null,
- "snmpv3_auth_pwd": null,
- "syslog_certificate": null,
- "admin_fortiguard_target": null,
- "snmpv3_query_port": null,
- "smtp_password": null,
- "adom": "ansible",
- "snmpv3_notify_hosts": null,
- "syslog_mode": "udp",
- "snmp_v2c_query_port": null,
- "snmp_v2c_trap_status": null,
- "snmp_status": "enable",
- "syslog_status": null,
- "admin_fortianalyzer_target": null,
- "ntp_auth": null,
- "snmp_v2c_id": null,
- "admin_http_port": null,
- "ntp_v3": null,
- "snmp_v2c_query_hosts_ipv4": null,
- "ntp_sync_interval": null,
- "snmpv3_source_ip": null,
- "snmpv3_trap_rport": null,
- "admin_gui_theme": null,
- "syslog_filter": null,
- "ntp_auth_pwd": null,
- "provisioning_template": "ansibleTest",
- "smtp_replyto": null,
- "provision_targets": null,
- "snmp_v2c_trap_port": null,
- "snmpv3_priv_proto": null,
- "admin_enable_fortiguard": null,
- "admin_switch_controller": null,
- "admin_language": null,
- "smtp_conn_sec": null,
- "mode": "set",
- "smtp_source_ipv4": null,
- "snmpv3_status": null,
- "delete_provisioning_template": null,
- "snmp_v2c_trap_hosts_ipv4": null,
- "admin_https_redirect": null
- },
- "post_method": "get"
- },
- {
- "url": "/pm/devprof/adom/ansible/ansibleTest",
- "raw_response": {
- "enabled options": [
- "dns",
- "ntp",
- "email",
- "admin",
- "snmp",
- "repmsg",
- "ftgd",
- "log"
- ],
- "oid": 1542,
- "type": "devprof",
- "description": "CreatedByAnsible",
- "name": "ansibleTest"
- },
- "datagram_sent": {},
- "paramgram_used": {
- "snmpv3_security_level": null,
- "snmp_v2c_query_status": null,
- "ntp_type": null,
- "dns_suffix": null,
- "snmpv3_queries": null,
- "snmpv3_trap_status": null,
- "snmp_v2c_name": null,
- "syslog_facility": "kernel",
- "snmp_v2c_status": null,
- "smtp_validate_cert": null,
- "snmpv3_name": null,
- "snmp_v2c_trap_src_ipv4": null,
- "syslog_port": 514,
- "ntp_server": null,
- "admin_https_port": null,
- "ntp_status": null,
- "syslog_server": "10.7.220.59",
- "dns_primary_ipv4": null,
- "admin_timeout": null,
- "snmpv3_auth_proto": null,
- "smtp_port": null,
- "snmpv3_priv_pwd": null,
- "smtp_server": null,
- "syslog_enc_algorithm": "disable",
- "dns_secondary_ipv4": null,
- "smtp_replyto": null,
- "smtp_username": null,
- "snmpv3_auth_pwd": null,
- "syslog_certificate": null,
- "admin_fortiguard_target": null,
- "snmpv3_query_port": null,
- "smtp_password": null,
- "adom": "ansible",
- "snmpv3_notify_hosts": null,
- "syslog_mode": "udp",
- "snmp_v2c_query_port": null,
- "snmp_v2c_trap_status": null,
- "snmp_status": null,
- "syslog_status": "enable",
- "admin_fortianalyzer_target": null,
- "ntp_auth": null,
- "snmp_v2c_id": null,
- "admin_http_port": null,
- "snmp_v2c_query_hosts_ipv4": null,
- "ntp_sync_interval": null,
- "snmpv3_source_ip": null,
- "snmpv3_trap_rport": null,
- "admin_gui_theme": null,
- "syslog_filter": "critical",
- "ntp_auth_pwd": null,
- "provisioning_template": "ansibleTest",
- "snmp_v2c_trap_hosts_ipv4": null,
- "provision_targets": null,
- "snmp_v2c_trap_port": null,
- "snmpv3_priv_proto": null,
- "admin_enable_fortiguard": null,
- "admin_switch_controller": null,
- "admin_language": null,
- "smtp_conn_sec": null,
- "mode": "set",
- "smtp_source_ipv4": null,
- "snmpv3_status": null,
- "delete_provisioning_template": null,
- "ntp_v3": null,
- "admin_https_redirect": null
- },
- "post_method": "get"
- },
- {
- "url": "/pm/devprof/adom/ansible/ansibleTest",
- "raw_response": {
- "enabled options": [
- "dns",
- "ntp",
- "email",
- "admin",
- "snmp",
- "repmsg",
- "ftgd",
- "log"
- ],
- "oid": 1542,
- "type": "devprof",
- "description": "CreatedByAnsible",
- "name": "ansibleTest"
- },
- "datagram_sent": {},
- "paramgram_used": {
- "snmpv3_security_level": null,
- "snmp_v2c_query_status": "enable",
- "ntp_type": null,
- "dns_suffix": null,
- "snmpv3_queries": null,
- "snmpv3_trap_status": null,
- "snmp_v2c_name": "ansibleV2c",
- "syslog_facility": "syslog",
- "snmp_v2c_status": "enable",
- "smtp_validate_cert": null,
- "snmpv3_name": null,
- "snmp_v2c_trap_src_ipv4": "10.7.220.41",
- "syslog_port": null,
- "ntp_server": null,
- "admin_https_port": null,
- "ntp_status": null,
- "syslog_server": null,
- "dns_primary_ipv4": null,
- "admin_timeout": null,
- "snmpv3_auth_proto": null,
- "smtp_port": null,
- "snmpv3_priv_pwd": null,
- "smtp_server": null,
- "syslog_enc_algorithm": "disable",
- "dns_secondary_ipv4": null,
- "smtp_username": null,
- "snmpv3_auth_pwd": null,
- "syslog_certificate": null,
- "admin_fortiguard_target": null,
- "snmpv3_query_port": null,
- "smtp_password": null,
- "adom": "ansible",
- "snmpv3_notify_hosts": null,
- "syslog_mode": "udp",
- "snmp_v2c_query_port": 162,
- "snmp_v2c_trap_status": "enable",
- "snmp_status": "enable",
- "syslog_status": null,
- "admin_fortianalyzer_target": null,
- "ntp_auth": null,
- "snmp_v2c_id": 1,
- "admin_http_port": null,
- "ntp_v3": null,
- "snmp_v2c_query_hosts_ipv4": "10.7.220.59 255.255.255.255, 10.7.220.0 255.255.255.0",
- "ntp_sync_interval": null,
- "snmpv3_source_ip": null,
- "snmpv3_trap_rport": null,
- "admin_gui_theme": null,
- "syslog_filter": null,
- "ntp_auth_pwd": null,
- "provisioning_template": "ansibleTest",
- "smtp_replyto": null,
- "provision_targets": null,
- "snmp_v2c_trap_port": 161,
- "snmpv3_priv_proto": null,
- "admin_enable_fortiguard": null,
- "admin_switch_controller": null,
- "admin_language": null,
- "smtp_conn_sec": null,
- "mode": "set",
- "smtp_source_ipv4": null,
- "snmpv3_status": null,
- "delete_provisioning_template": null,
- "snmp_v2c_trap_hosts_ipv4": "10.7.220.59 255.255.255.255, 10.7.220.60 255.255.255.255",
- "admin_https_redirect": null
- },
- "post_method": "get"
- },
- {
- "url": "/pm/devprof/adom/ansible/ansibleTest",
- "paramgram_used": {
- "snmpv3_security_level": "auth-priv",
- "snmp_v2c_query_status": null,
- "provision_targets": null,
- "ntp_type": null,
- "dns_suffix": null,
- "snmpv3_queries": "enable",
- "snmpv3_trap_status": "enable",
- "snmp_v2c_name": null,
- "syslog_facility": "syslog",
- "snmp_v2c_status": null,
- "smtp_validate_cert": null,
- "snmpv3_name": "ansibleSNMPv3",
- "snmp_v2c_id": null,
- "syslog_port": null,
- "ntp_server": null,
- "admin_https_port": null,
- "ntp_status": null,
- "syslog_server": null,
- "admin_switch_controller": null,
- "admin_timeout": null,
- "snmpv3_auth_proto": "sha",
- "smtp_port": null,
- "snmpv3_priv_pwd": "fortinet",
- "smtp_server": null,
- "syslog_enc_algorithm": "disable",
- "snmp_v2c_query_hosts_ipv4": null,
- "smtp_username": null,
- "mode": "set",
- "syslog_certificate": null,
- "admin_fortiguard_target": null,
- "snmpv3_query_port": 161,
- "smtp_password": null,
- "adom": "ansible",
- "snmpv3_notify_hosts": "10.7.220.59,10.7.220.60",
- "syslog_mode": "udp",
- "snmp_v2c_query_port": null,
- "snmp_v2c_trap_status": null,
- "snmp_status": "enable",
- "syslog_status": null,
- "snmp_v2c_trap_hosts_ipv4": null,
- "admin_fortianalyzer_target": null,
- "snmp_v2c_trap_src_ipv4": null,
- "admin_http_port": null,
- "dns_secondary_ipv4": null,
- "syslog_filter": null,
- "snmpv3_source_ip": "0.0.0.0",
- "snmpv3_trap_rport": 162,
- "admin_gui_theme": null,
- "ntp_sync_interval": null,
- "ntp_auth_pwd": null,
- "provisioning_template": "ansibleTest",
- "ntp_v3": null,
- "ntp_auth": null,
- "snmp_v2c_trap_port": null,
- "snmpv3_priv_proto": "aes256",
- "admin_enable_fortiguard": null,
- "dns_primary_ipv4": null,
- "admin_language": null,
- "smtp_conn_sec": null,
- "snmpv3_auth_pwd": "fortinet",
- "smtp_source_ipv4": null,
- "snmpv3_status": "enable",
- "delete_provisioning_template": null,
- "smtp_replyto": null,
- "admin_https_redirect": null
- },
- "datagram_sent": {},
- "raw_response": {
- "enabled options": [
- "dns",
- "ntp",
- "email",
- "admin",
- "snmp",
- "repmsg",
- "ftgd",
- "log"
- ],
- "oid": 1542,
- "type": "devprof",
- "description": "CreatedByAnsible",
- "name": "ansibleTest"
- },
- "post_method": "get"
- },
- {
- "url": "/pm/devprof/adom/ansible/ansibleTest",
- "raw_response": {
- "enabled options": [
- "dns",
- "ntp",
- "email",
- "admin",
- "snmp",
- "repmsg",
- "ftgd",
- "log"
- ],
- "oid": 1542,
- "type": "devprof",
- "description": "CreatedByAnsible",
- "name": "ansibleTest"
- },
- "datagram_sent": {},
- "paramgram_used": {
- "snmpv3_security_level": null,
- "snmp_v2c_query_status": null,
- "ntp_type": "fortiguard",
- "dns_suffix": null,
- "snmpv3_queries": null,
- "snmpv3_trap_status": null,
- "snmp_v2c_name": null,
- "syslog_facility": "syslog",
- "snmp_v2c_status": null,
- "smtp_validate_cert": null,
- "snmpv3_name": null,
- "snmp_v2c_trap_src_ipv4": null,
- "syslog_port": null,
- "ntp_server": null,
- "admin_https_port": null,
- "ntp_status": "enable",
- "syslog_server": null,
- "dns_primary_ipv4": null,
- "admin_timeout": null,
- "snmpv3_auth_proto": null,
- "smtp_port": null,
- "snmpv3_priv_pwd": null,
- "smtp_server": null,
- "syslog_enc_algorithm": "disable",
- "dns_secondary_ipv4": null,
- "smtp_replyto": null,
- "smtp_username": null,
- "snmpv3_auth_pwd": null,
- "syslog_certificate": null,
- "admin_fortiguard_target": null,
- "snmpv3_query_port": null,
- "smtp_password": null,
- "adom": "ansible",
- "snmpv3_notify_hosts": null,
- "syslog_mode": "udp",
- "snmp_v2c_query_port": null,
- "snmp_v2c_trap_status": null,
- "snmp_status": null,
- "syslog_status": null,
- "admin_fortianalyzer_target": null,
- "ntp_auth": null,
- "snmp_v2c_id": null,
- "admin_http_port": null,
- "snmp_v2c_query_hosts_ipv4": null,
- "ntp_sync_interval": 60,
- "snmpv3_source_ip": null,
- "snmpv3_trap_rport": null,
- "admin_gui_theme": null,
- "syslog_filter": null,
- "ntp_auth_pwd": null,
- "provisioning_template": "ansibleTest",
- "snmp_v2c_trap_hosts_ipv4": null,
- "provision_targets": null,
- "snmp_v2c_trap_port": null,
- "snmpv3_priv_proto": null,
- "admin_enable_fortiguard": null,
- "admin_switch_controller": null,
- "admin_language": null,
- "smtp_conn_sec": null,
- "mode": "set",
- "smtp_source_ipv4": null,
- "snmpv3_status": null,
- "delete_provisioning_template": null,
- "ntp_v3": null,
- "admin_https_redirect": null
- },
- "post_method": "get"
- },
- {
- "url": "/pm/devprof/adom/ansible/ansibleTest",
- "raw_response": {
- "enabled options": [
- "dns",
- "ntp",
- "email",
- "admin",
- "snmp",
- "repmsg",
- "ftgd",
- "log"
- ],
- "oid": 1542,
- "type": "devprof",
- "description": "CreatedByAnsible",
- "name": "ansibleTest"
- },
- "datagram_sent": {},
- "paramgram_used": {
- "snmpv3_security_level": null,
- "snmp_v2c_query_status": null,
- "ntp_type": "custom",
- "dns_suffix": null,
- "snmpv3_queries": null,
- "snmpv3_trap_status": null,
- "snmp_v2c_name": null,
- "syslog_facility": "syslog",
- "snmp_v2c_status": null,
- "smtp_validate_cert": null,
- "snmpv3_name": null,
- "snmp_v2c_trap_src_ipv4": null,
- "syslog_port": null,
- "ntp_server": "10.7.220.32,10.7.220.1",
- "admin_https_port": null,
- "ntp_status": "enable",
- "syslog_server": null,
- "dns_primary_ipv4": null,
- "admin_timeout": null,
- "snmpv3_auth_proto": null,
- "smtp_port": null,
- "snmpv3_priv_pwd": null,
- "smtp_server": null,
- "syslog_enc_algorithm": "disable",
- "dns_secondary_ipv4": null,
- "smtp_username": null,
- "snmpv3_auth_pwd": null,
- "syslog_certificate": null,
- "admin_fortiguard_target": null,
- "snmpv3_query_port": null,
- "smtp_password": null,
- "adom": "ansible",
- "snmpv3_notify_hosts": null,
- "syslog_mode": "udp",
- "snmp_v2c_query_port": null,
- "snmp_v2c_trap_status": null,
- "snmp_status": null,
- "syslog_status": null,
- "admin_fortianalyzer_target": null,
- "ntp_auth": "enable",
- "snmp_v2c_id": null,
- "admin_http_port": null,
- "ntp_v3": null,
- "snmp_v2c_query_hosts_ipv4": null,
- "ntp_sync_interval": 60,
- "snmpv3_source_ip": null,
- "snmpv3_trap_rport": null,
- "admin_gui_theme": null,
- "syslog_filter": null,
- "ntp_auth_pwd": "fortinet",
- "provisioning_template": "ansibleTest",
- "smtp_replyto": null,
- "provision_targets": null,
- "snmp_v2c_trap_port": null,
- "snmpv3_priv_proto": null,
- "admin_enable_fortiguard": null,
- "admin_switch_controller": null,
- "admin_language": null,
- "smtp_conn_sec": null,
- "mode": "set",
- "smtp_source_ipv4": null,
- "snmpv3_status": null,
- "delete_provisioning_template": null,
- "snmp_v2c_trap_hosts_ipv4": null,
- "admin_https_redirect": null
- },
- "post_method": "get"
- },
- {
- "url": "/pm/devprof/adom/ansible/ansibleTest",
- "raw_response": {
- "enabled options": [
- "dns",
- "ntp",
- "email",
- "admin",
- "snmp",
- "repmsg",
- "ftgd",
- "log"
- ],
- "oid": 1542,
- "type": "devprof",
- "description": "CreatedByAnsible",
- "name": "ansibleTest"
- },
- "datagram_sent": {},
- "paramgram_used": {
- "snmpv3_security_level": null,
- "snmp_v2c_query_status": null,
- "ntp_type": null,
- "dns_suffix": null,
- "snmpv3_queries": null,
- "snmpv3_trap_status": null,
- "snmp_v2c_name": null,
- "syslog_facility": "syslog",
- "snmp_v2c_status": null,
- "smtp_validate_cert": null,
- "snmpv3_name": null,
- "snmp_v2c_trap_src_ipv4": null,
- "syslog_port": null,
- "ntp_server": null,
- "admin_https_port": 4433,
- "ntp_status": null,
- "syslog_server": null,
- "dns_primary_ipv4": null,
- "admin_timeout": 60,
- "snmpv3_auth_proto": null,
- "smtp_port": null,
- "snmpv3_priv_pwd": null,
- "smtp_server": null,
- "syslog_enc_algorithm": "disable",
- "dns_secondary_ipv4": null,
- "smtp_replyto": null,
- "smtp_username": null,
- "snmpv3_auth_pwd": null,
- "syslog_certificate": null,
- "admin_fortiguard_target": null,
- "snmpv3_query_port": null,
- "smtp_password": null,
- "adom": "ansible",
- "snmpv3_notify_hosts": null,
- "syslog_mode": "udp",
- "snmp_v2c_query_port": null,
- "snmp_v2c_trap_status": null,
- "snmp_status": null,
- "syslog_status": null,
- "admin_fortianalyzer_target": "10.7.220.38",
- "ntp_auth": null,
- "snmp_v2c_id": null,
- "admin_http_port": 8080,
- "snmp_v2c_query_hosts_ipv4": null,
- "ntp_sync_interval": null,
- "snmpv3_source_ip": null,
- "snmpv3_trap_rport": null,
- "admin_gui_theme": "blue",
- "syslog_filter": null,
- "ntp_auth_pwd": null,
- "provisioning_template": "ansibleTest",
- "snmp_v2c_trap_hosts_ipv4": null,
- "provision_targets": null,
- "snmp_v2c_trap_port": null,
- "snmpv3_priv_proto": null,
- "admin_enable_fortiguard": "this-fmg",
- "admin_switch_controller": "enable",
- "admin_language": "english",
- "smtp_conn_sec": null,
- "mode": "set",
- "smtp_source_ipv4": null,
- "snmpv3_status": null,
- "delete_provisioning_template": null,
- "ntp_v3": null,
- "admin_https_redirect": "enable"
- },
- "post_method": "get"
- },
- {
- "url": "/pm/devprof/adom/ansible/ansibleTest",
- "raw_response": {
- "enabled options": [
- "dns",
- "ntp",
- "email",
- "admin",
- "snmp",
- "repmsg",
- "ftgd",
- "log"
- ],
- "oid": 1542,
- "type": "devprof",
- "description": "CreatedByAnsible",
- "name": "ansibleTest"
- },
- "datagram_sent": {},
- "paramgram_used": {
- "snmpv3_security_level": null,
- "snmp_v2c_query_status": null,
- "ntp_type": null,
- "dns_suffix": null,
- "snmpv3_queries": null,
- "snmpv3_trap_status": null,
- "snmp_v2c_name": null,
- "syslog_facility": "syslog",
- "snmp_v2c_status": null,
- "smtp_validate_cert": "disable",
- "snmpv3_name": null,
- "snmp_v2c_trap_src_ipv4": null,
- "syslog_port": null,
- "ntp_server": null,
- "admin_https_port": null,
- "ntp_status": null,
- "syslog_server": null,
- "dns_primary_ipv4": null,
- "admin_timeout": null,
- "snmpv3_auth_proto": null,
- "smtp_port": 25,
- "snmpv3_priv_pwd": null,
- "smtp_server": "10.7.220.32",
- "syslog_enc_algorithm": "disable",
- "dns_secondary_ipv4": null,
- "smtp_username": "ansible",
- "snmpv3_auth_pwd": null,
- "syslog_certificate": null,
- "admin_fortiguard_target": null,
- "snmpv3_query_port": null,
- "smtp_password": "fortinet",
- "adom": "ansible",
- "snmpv3_notify_hosts": null,
- "syslog_mode": "udp",
- "snmp_v2c_query_port": null,
- "snmp_v2c_trap_status": null,
- "snmp_status": null,
- "syslog_status": null,
- "admin_fortianalyzer_target": null,
- "ntp_auth": null,
- "snmp_v2c_id": null,
- "admin_http_port": null,
- "ntp_v3": null,
- "snmp_v2c_query_hosts_ipv4": null,
- "ntp_sync_interval": null,
- "snmpv3_source_ip": null,
- "snmpv3_trap_rport": null,
- "admin_gui_theme": null,
- "syslog_filter": null,
- "ntp_auth_pwd": null,
- "provisioning_template": "ansibleTest",
- "smtp_replyto": "ansible@do-not-reply.com",
- "provision_targets": null,
- "snmp_v2c_trap_port": null,
- "snmpv3_priv_proto": null,
- "admin_enable_fortiguard": null,
- "admin_switch_controller": null,
- "admin_language": null,
- "smtp_conn_sec": "starttls",
- "mode": "set",
- "smtp_source_ipv4": "0.0.0.0",
- "snmpv3_status": null,
- "delete_provisioning_template": null,
- "snmp_v2c_trap_hosts_ipv4": null,
- "admin_https_redirect": null
- },
- "post_method": "get"
- },
- {
- "url": "/pm/devprof/adom/ansible/ansibleTest",
- "raw_response": {
- "enabled options": [
- "dns",
- "ntp",
- "email",
- "admin",
- "snmp",
- "repmsg",
- "ftgd",
- "log"
- ],
- "oid": 1542,
- "type": "devprof",
- "description": "CreatedByAnsible",
- "name": "ansibleTest"
- },
- "datagram_sent": {},
- "paramgram_used": {
- "snmpv3_security_level": null,
- "snmp_v2c_query_status": null,
- "ntp_type": null,
- "dns_suffix": "ansible.local",
- "snmpv3_queries": null,
- "snmpv3_trap_status": null,
- "snmp_v2c_name": null,
- "syslog_facility": "syslog",
- "snmp_v2c_status": null,
- "smtp_validate_cert": null,
- "snmpv3_name": null,
- "snmp_v2c_trap_src_ipv4": null,
- "syslog_port": null,
- "ntp_server": null,
- "admin_https_port": null,
- "ntp_status": null,
- "syslog_server": null,
- "dns_primary_ipv4": "8.8.8.8",
- "admin_timeout": null,
- "snmpv3_auth_proto": null,
- "smtp_port": null,
- "snmpv3_priv_pwd": null,
- "smtp_server": null,
- "syslog_enc_algorithm": "disable",
- "dns_secondary_ipv4": "4.4.4.4",
- "smtp_replyto": null,
- "smtp_username": null,
- "snmpv3_auth_pwd": null,
- "syslog_certificate": null,
- "admin_fortiguard_target": null,
- "snmpv3_query_port": null,
- "smtp_password": null,
- "adom": "ansible",
- "snmpv3_notify_hosts": null,
- "syslog_mode": "udp",
- "snmp_v2c_query_port": null,
- "snmp_v2c_trap_status": null,
- "snmp_status": null,
- "syslog_status": null,
- "admin_fortianalyzer_target": null,
- "ntp_auth": null,
- "snmp_v2c_id": null,
- "admin_http_port": null,
- "snmp_v2c_query_hosts_ipv4": null,
- "ntp_sync_interval": null,
- "snmpv3_source_ip": null,
- "snmpv3_trap_rport": null,
- "admin_gui_theme": null,
- "syslog_filter": null,
- "ntp_auth_pwd": null,
- "provisioning_template": "ansibleTest",
- "snmp_v2c_trap_hosts_ipv4": null,
- "provision_targets": null,
- "snmp_v2c_trap_port": null,
- "snmpv3_priv_proto": null,
- "admin_enable_fortiguard": null,
- "admin_switch_controller": null,
- "admin_language": null,
- "smtp_conn_sec": null,
- "mode": "set",
- "smtp_source_ipv4": null,
- "snmpv3_status": null,
- "delete_provisioning_template": null,
- "ntp_v3": null,
- "admin_https_redirect": null
- },
- "post_method": "get"
- },
- {
- "url": "/pm/devprof/adom/ansible/ansibleTest",
- "raw_response": {
- "enabled options": [
- "dns",
- "ntp",
- "email",
- "admin",
- "snmp",
- "repmsg",
- "ftgd",
- "log"
- ],
- "oid": 1542,
- "type": "devprof",
- "description": "CreatedByAnsible",
- "name": "ansibleTest"
- },
- "datagram_sent": {},
- "paramgram_used": {
- "snmpv3_security_level": null,
- "snmp_v2c_query_status": null,
- "ntp_type": null,
- "dns_suffix": null,
- "snmpv3_queries": null,
- "snmpv3_trap_status": null,
- "snmp_v2c_name": null,
- "syslog_facility": "syslog",
- "snmp_v2c_status": null,
- "smtp_validate_cert": null,
- "snmpv3_name": null,
- "snmp_v2c_trap_src_ipv4": null,
- "syslog_port": null,
- "ntp_server": null,
- "admin_https_port": null,
- "ntp_status": null,
- "syslog_server": null,
- "dns_primary_ipv4": null,
- "admin_timeout": null,
- "snmpv3_auth_proto": null,
- "smtp_port": null,
- "snmpv3_priv_pwd": null,
- "smtp_server": null,
- "syslog_enc_algorithm": "disable",
- "dns_secondary_ipv4": null,
- "smtp_username": null,
- "snmpv3_auth_pwd": null,
- "syslog_certificate": null,
- "admin_fortiguard_target": null,
- "snmpv3_query_port": null,
- "smtp_password": null,
- "adom": "ansible",
- "snmpv3_notify_hosts": null,
- "syslog_mode": "udp",
- "snmp_v2c_query_port": null,
- "snmp_v2c_trap_status": null,
- "snmp_status": null,
- "syslog_status": null,
- "admin_fortianalyzer_target": null,
- "ntp_auth": null,
- "snmp_v2c_id": null,
- "admin_http_port": null,
- "ntp_v3": null,
- "snmp_v2c_query_hosts_ipv4": null,
- "ntp_sync_interval": null,
- "snmpv3_source_ip": null,
- "snmpv3_trap_rport": null,
- "admin_gui_theme": null,
- "syslog_filter": null,
- "ntp_auth_pwd": null,
- "provisioning_template": "ansibleTest",
- "smtp_replyto": null,
- "provision_targets": "FGT1,FGT2",
- "snmp_v2c_trap_port": null,
- "snmpv3_priv_proto": null,
- "admin_enable_fortiguard": null,
- "admin_switch_controller": null,
- "admin_language": null,
- "smtp_conn_sec": null,
- "mode": "set",
- "smtp_source_ipv4": null,
- "snmpv3_status": null,
- "delete_provisioning_template": null,
- "snmp_v2c_trap_hosts_ipv4": null,
- "admin_https_redirect": null
- },
- "post_method": "get"
- }
- ],
- "set_devprof_ntp": [
- {
- "paramgram_used": {
- "snmpv3_security_level": null,
- "snmp_v2c_query_status": null,
- "provision_targets": null,
- "ntp_type": "fortiguard",
- "dns_suffix": null,
- "snmpv3_queries": null,
- "snmpv3_trap_status": null,
- "snmp_v2c_name": null,
- "syslog_facility": "syslog",
- "snmp_v2c_status": null,
- "smtp_validate_cert": null,
- "snmpv3_name": null,
- "snmp_v2c_id": null,
- "syslog_port": null,
- "ntp_server": null,
- "admin_https_port": null,
- "ntp_status": "enable",
- "syslog_server": null,
- "admin_switch_controller": null,
- "admin_timeout": null,
- "snmpv3_auth_proto": null,
- "smtp_port": null,
- "snmpv3_priv_pwd": null,
- "smtp_server": null,
- "syslog_enc_algorithm": "disable",
- "snmp_v2c_query_hosts_ipv4": null,
- "smtp_username": null,
- "mode": "set",
- "syslog_certificate": null,
- "admin_fortiguard_target": null,
- "snmpv3_query_port": null,
- "smtp_password": null,
- "adom": "ansible",
- "snmpv3_notify_hosts": null,
- "syslog_mode": "udp",
- "snmp_v2c_query_port": null,
- "snmp_v2c_trap_status": null,
- "snmp_status": null,
- "syslog_status": null,
- "snmp_v2c_trap_hosts_ipv4": null,
- "admin_fortianalyzer_target": null,
- "snmp_v2c_trap_src_ipv4": null,
- "admin_http_port": null,
- "dns_secondary_ipv4": null,
- "syslog_filter": null,
- "snmpv3_source_ip": null,
- "snmpv3_trap_rport": null,
- "admin_gui_theme": null,
- "ntp_sync_interval": 60,
- "ntp_auth_pwd": null,
- "provisioning_template": "ansibleTest",
- "ntp_v3": null,
- "ntp_auth": null,
- "snmp_v2c_trap_port": null,
- "snmpv3_priv_proto": null,
- "admin_enable_fortiguard": null,
- "dns_primary_ipv4": null,
- "admin_language": null,
- "smtp_conn_sec": null,
- "snmpv3_auth_pwd": null,
- "smtp_source_ipv4": null,
- "snmpv3_status": null,
- "delete_provisioning_template": null,
- "smtp_replyto": null,
- "admin_https_redirect": null
- },
- "datagram_sent": {
- "ntpsync": 1,
- "syncinterval": 60,
- "type": 0
- },
- "raw_response": {
- "status": {
- "message": "OK",
- "code": 0
- },
- "url": "/pm/config/adom/ansible/devprof/ansibleTest/system/ntp"
- },
- "post_method": "set"
- },
- {
- "paramgram_used": {
- "snmpv3_security_level": null,
- "snmp_v2c_query_status": null,
- "provision_targets": null,
- "ntp_type": "custom",
- "dns_suffix": null,
- "snmpv3_queries": null,
- "snmpv3_trap_status": null,
- "snmp_v2c_name": null,
- "syslog_facility": "syslog",
- "snmp_v2c_status": null,
- "smtp_validate_cert": null,
- "snmpv3_name": null,
- "snmp_v2c_id": null,
- "syslog_port": null,
- "ntp_server": "10.7.220.32,10.7.220.1",
- "admin_https_port": null,
- "ntp_status": "enable",
- "syslog_server": null,
- "admin_switch_controller": null,
- "admin_timeout": null,
- "snmpv3_auth_proto": null,
- "smtp_port": null,
- "snmpv3_priv_pwd": null,
- "smtp_server": null,
- "syslog_enc_algorithm": "disable",
- "snmp_v2c_query_hosts_ipv4": null,
- "smtp_username": null,
- "mode": "set",
- "syslog_certificate": null,
- "admin_fortiguard_target": null,
- "snmpv3_query_port": null,
- "smtp_password": null,
- "adom": "ansible",
- "snmpv3_notify_hosts": null,
- "syslog_mode": "udp",
- "snmp_v2c_query_port": null,
- "snmp_v2c_trap_status": null,
- "snmp_status": null,
- "syslog_status": null,
- "admin_https_redirect": null,
- "admin_fortianalyzer_target": null,
- "snmp_v2c_trap_src_ipv4": null,
- "admin_http_port": null,
- "dns_secondary_ipv4": null,
- "syslog_filter": null,
- "snmpv3_source_ip": null,
- "snmpv3_trap_rport": null,
- "admin_gui_theme": null,
- "ntp_sync_interval": 60,
- "ntp_auth_pwd": "fortinet",
- "provisioning_template": "ansibleTest",
- "smtp_replyto": null,
- "ntp_auth": "enable",
- "snmp_v2c_trap_port": null,
- "snmpv3_priv_proto": null,
- "admin_enable_fortiguard": null,
- "dns_primary_ipv4": null,
- "admin_language": null,
- "smtp_conn_sec": null,
- "snmpv3_auth_pwd": null,
- "smtp_source_ipv4": null,
- "snmpv3_status": null,
- "delete_provisioning_template": null,
- "snmp_v2c_trap_hosts_ipv4": null,
- "ntp_v3": null
- },
- "datagram_sent": {
- "ntpsync": 1,
- "syncinterval": 60,
- "type": 1,
- "ntpserver": [
- {
- "ntpv3": 0,
- "server": "10.7.220.32",
- "authentication": 1,
- "key": "fortinet",
- "id": 1,
- "key-id": 1
- },
- {
- "ntpv3": 0,
- "server": "10.7.220.1",
- "authentication": 1,
- "key": "fortinet",
- "id": 2,
- "key-id": 2
- }
- ]
- },
- "raw_response": {
- "status": {
- "message": "OK",
- "code": 0
- },
- "url": "/pm/config/adom/ansible/devprof/ansibleTest/system/ntp"
- },
- "post_method": "set"
- }
- ],
- "set_devprof_smtp": [
- {
- "paramgram_used": {
- "snmpv3_security_level": null,
- "snmp_v2c_query_status": null,
- "provision_targets": null,
- "ntp_type": null,
- "dns_suffix": null,
- "snmpv3_queries": null,
- "snmpv3_trap_status": null,
- "snmp_v2c_name": null,
- "syslog_facility": "syslog",
- "snmp_v2c_status": null,
- "smtp_validate_cert": "disable",
- "snmpv3_name": null,
- "snmp_v2c_id": null,
- "syslog_port": null,
- "ntp_server": null,
- "admin_https_port": null,
- "ntp_status": null,
- "syslog_server": null,
- "admin_switch_controller": null,
- "admin_timeout": null,
- "snmpv3_auth_proto": null,
- "smtp_port": 25,
- "snmpv3_priv_pwd": null,
- "smtp_server": "10.7.220.32",
- "syslog_enc_algorithm": "disable",
- "snmp_v2c_query_hosts_ipv4": null,
- "smtp_username": "ansible",
- "mode": "set",
- "syslog_certificate": null,
- "admin_fortiguard_target": null,
- "snmpv3_query_port": null,
- "smtp_password": "fortinet",
- "adom": "ansible",
- "snmpv3_notify_hosts": null,
- "syslog_mode": "udp",
- "snmp_v2c_query_port": null,
- "snmp_v2c_trap_status": null,
- "snmp_status": null,
- "syslog_status": null,
- "admin_https_redirect": null,
- "admin_fortianalyzer_target": null,
- "snmp_v2c_trap_src_ipv4": null,
- "admin_http_port": null,
- "dns_secondary_ipv4": null,
- "syslog_filter": null,
- "snmpv3_source_ip": null,
- "snmpv3_trap_rport": null,
- "admin_gui_theme": null,
- "ntp_sync_interval": null,
- "ntp_auth_pwd": null,
- "provisioning_template": "ansibleTest",
- "smtp_replyto": "ansible@do-not-reply.com",
- "ntp_auth": null,
- "snmp_v2c_trap_port": null,
- "snmpv3_priv_proto": null,
- "admin_enable_fortiguard": null,
- "dns_primary_ipv4": null,
- "admin_language": null,
- "smtp_conn_sec": "starttls",
- "snmpv3_auth_pwd": null,
- "smtp_source_ipv4": "0.0.0.0",
- "snmpv3_status": null,
- "delete_provisioning_template": null,
- "snmp_v2c_trap_hosts_ipv4": null,
- "ntp_v3": null
- },
- "datagram_sent": {
- "username": "ansible",
- "authenticate": 1,
- "source-ip": "0.0.0.0",
- "validate-server": 0,
- "server": "10.7.220.32",
- "port": 25,
- "security": 1,
- "password": "fortinet",
- "reply-to": "ansible@do-not-reply.com"
- },
- "raw_response": {
- "status": {
- "message": "OK",
- "code": 0
- },
- "url": "/pm/config/adom/ansible/devprof/ansibleTest/system/email-server"
- },
- "post_method": "set"
- }
- ]
-}
diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/fixtures/test_fmgr_ha.json b/ansible_collections/community/fortios/tests/unit/plugins/modules/fixtures/test_fmgr_ha.json
deleted file mode 100644
index 27c8483a5..000000000
--- a/ansible_collections/community/fortios/tests/unit/plugins/modules/fixtures/test_fmgr_ha.json
+++ /dev/null
@@ -1,241 +0,0 @@
-{
- "fmgr_set_ha_peer": [
- {
- "raw_response": {
- "status": {
- "message": "OK",
- "code": 0
- },
- "url": "/cli/global/system/ha/peer/"
- },
- "datagram_sent": {
- "status": "enable",
- "ip": "10.7.220.36",
- "serial-number": "FMG-VMTM18001882",
- "ip6": null,
- "id": 1
- },
- "paramgram_used": {
- "fmgr_ha_peer_sn": "FMG-VMTM18001882",
- "next_peer_id": 2,
- "fmgr_ha_hb_threshold": 3,
- "fmgr_ha_cluster_pw": null,
- "fmgr_ha_peer_ipv6": null,
- "fmgr_ha_peer_status": "enable",
- "fmgr_ha_file_quota": 4096,
- "fmgr_ha_cluster_id": 1,
- "peer_id": 1,
- "fmgr_ha_peer_ipv4": "10.7.220.36",
- "fmgr_ha_hb_interval": 5,
- "fmgr_ha_mode": null
- },
- "post_method": "set"
- },
- {
- "paramgram_used": {
- "fmgr_ha_peer_sn": "FMG-VMTM18001881",
- "next_peer_id": 1,
- "fmgr_ha_hb_threshold": 3,
- "fmgr_ha_cluster_pw": "fortinet",
- "fmgr_ha_hb_interval": 5,
- "fmgr_ha_cluster_id": 2,
- "fmgr_ha_file_quota": 4096,
- "fmgr_ha_peer_status": "enable",
- "peer_id": 1,
- "fmgr_ha_peer_ipv4": "10.7.220.35",
- "fmgr_ha_peer_ipv6": null,
- "fmgr_ha_mode": "slave"
- },
- "datagram_sent": {
- "status": "enable",
- "ip": "10.7.220.35",
- "serial-number": "FMG-VMTM18001881",
- "ip6": null,
- "id": 1
- },
- "raw_response": {
- "status": {
- "message": "OK",
- "code": 0
- },
- "url": "/cli/global/system/ha/peer/"
- },
- "post_method": "set"
- }
- ],
- "fmgr_get_ha_peer_list": [
- {
- "url": "/cli/global/system/ha/peer/",
- "paramgram_used": {
- "fmgr_ha_peer_sn": "FMG-VMTM18001882",
- "fmgr_ha_hb_threshold": 3,
- "fmgr_ha_cluster_pw": null,
- "fmgr_ha_peer_ipv6": null,
- "fmgr_ha_peer_status": "enable",
- "fmgr_ha_file_quota": 4096,
- "fmgr_ha_cluster_id": 1,
- "fmgr_ha_peer_ipv4": "10.7.220.36",
- "fmgr_ha_hb_interval": 5,
- "fmgr_ha_mode": null
- },
- "datagram_sent": {},
- "raw_response": [
- {
- "status": "enable",
- "ip": "10.7.220.140",
- "serial-number": "FMG-VM0A17005535",
- "ip6": "::",
- "id": 1
- }
- ],
- "post_method": "get"
- },
- {
- "url": "/cli/global/system/ha/peer/",
- "raw_response": [
- {
- "status": "enable",
- "ip": "10.7.220.35",
- "serial-number": "FMG-VMTM18001881",
- "ip6": "::",
- "id": 1
- }
- ],
- "datagram_sent": {},
- "paramgram_used": {
- "fmgr_ha_peer_sn": "FMG-VMTM18001881",
- "fmgr_ha_hb_threshold": 3,
- "fmgr_ha_cluster_pw": "fortinet",
- "fmgr_ha_hb_interval": 5,
- "fmgr_ha_cluster_id": 2,
- "fmgr_ha_file_quota": 4096,
- "fmgr_ha_peer_status": "enable",
- "fmgr_ha_peer_ipv4": "10.7.220.35",
- "fmgr_ha_peer_ipv6": null,
- "fmgr_ha_mode": "slave"
- },
- "post_method": "get"
- }
- ],
- "fmgr_set_ha_mode": [
- {
- "paramgram_used": {
- "fmgr_ha_peer_sn": null,
- "fmgr_ha_hb_threshold": 10,
- "fmgr_ha_cluster_pw": "fortinet",
- "fmgr_ha_peer_ipv6": null,
- "fmgr_ha_peer_status": null,
- "fmgr_ha_file_quota": 2048,
- "fmgr_ha_cluster_id": 2,
- "fmgr_ha_peer_ipv4": null,
- "fmgr_ha_hb_interval": 15,
- "fmgr_ha_mode": "master"
- },
- "datagram_sent": {
- "file-quota": 2048,
- "clusterid": 2,
- "hb-lost-threshold": 10,
- "mode": "master",
- "hb-interval": 15,
- "password": "fortinet"
- },
- "raw_response": {
- "status": {
- "message": "OK",
- "code": 0
- },
- "url": "/cli/global/system/ha"
- },
- "post_method": "set"
- },
- {
- "raw_response": {
- "status": {
- "message": "OK",
- "code": 0
- },
- "url": "/cli/global/system/ha"
- },
- "datagram_sent": {
- "file-quota": 4096,
- "clusterid": 2,
- "hb-lost-threshold": 3,
- "mode": "slave",
- "hb-interval": 5,
- "password": "fortinet"
- },
- "paramgram_used": {
- "fmgr_ha_peer_sn": null,
- "fmgr_ha_hb_threshold": 3,
- "fmgr_ha_cluster_pw": "fortinet",
- "fmgr_ha_hb_interval": 5,
- "fmgr_ha_cluster_id": 2,
- "fmgr_ha_file_quota": 4096,
- "fmgr_ha_peer_status": null,
- "fmgr_ha_peer_ipv4": null,
- "fmgr_ha_peer_ipv6": null,
- "fmgr_ha_mode": "slave"
- },
- "post_method": "set"
- },
- {
- "paramgram_used": {
- "fmgr_ha_peer_sn": "FMG-VMTM18001881",
- "fmgr_ha_hb_threshold": 3,
- "fmgr_ha_cluster_pw": "fortinet",
- "fmgr_ha_peer_ipv6": null,
- "fmgr_ha_peer_status": "enable",
- "fmgr_ha_file_quota": 4096,
- "fmgr_ha_cluster_id": 2,
- "fmgr_ha_peer_ipv4": "10.7.220.35",
- "fmgr_ha_hb_interval": 5,
- "fmgr_ha_mode": "slave"
- },
- "datagram_sent": {
- "file-quota": 4096,
- "clusterid": 2,
- "hb-lost-threshold": 3,
- "mode": "slave",
- "hb-interval": 5,
- "password": "fortinet"
- },
- "raw_response": {
- "status": {
- "message": "OK",
- "code": 0
- },
- "url": "/cli/global/system/ha"
- },
- "post_method": "set"
- },
- {
- "raw_response": {
- "status": {
- "message": "OK",
- "code": 0
- },
- "url": "/cli/global/system/ha"
- },
- "datagram_sent": {
- "hb-lost-threshold": 3,
- "hb-interval": 5,
- "clusterid": 1,
- "mode": "standalone",
- "file-quota": 4096
- },
- "paramgram_used": {
- "fmgr_ha_file_quota": 4096,
- "fmgr_ha_cluster_pw": null,
- "fmgr_ha_peer_sn": null,
- "fmgr_ha_hb_interval": 5,
- "fmgr_ha_cluster_id": 1,
- "fmgr_ha_mode": "standalone",
- "fmgr_ha_peer_status": null,
- "fmgr_ha_hb_threshold": 3,
- "fmgr_ha_peer_ipv4": null,
- "fmgr_ha_peer_ipv6": null
- },
- "post_method": "set"
- }
- ]
-}
diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/fixtures/test_fmgr_secprof_spam.json b/ansible_collections/community/fortios/tests/unit/plugins/modules/fixtures/test_fmgr_secprof_spam.json
deleted file mode 100644
index d75156e1d..000000000
--- a/ansible_collections/community/fortios/tests/unit/plugins/modules/fixtures/test_fmgr_secprof_spam.json
+++ /dev/null
@@ -1,157 +0,0 @@
-{
- "fmgr_spamfilter_profile_modify": [
- {
- "paramgram_used": {
- "comment": null,
- "smtp": {
- "local-override": null,
- "hdrip": null,
- "log": null,
- "tag-type": null,
- "tag-msg": null,
- "action": null
- },
- "spam-log": null,
- "gmail": {
- "log": null
- },
- "spam-bword-table": null,
- "mapi": {
- "action": null,
- "log": null
- },
- "flow-based": null,
- "spam-mheader-table": null,
- "spam-log-fortiguard-response": null,
- "yahoo-mail": {
- "log": null
- },
- "adom": "root",
- "pop3": {
- "action": null,
- "tag-msg": null,
- "tag-type": null,
- "log": null
- },
- "external": null,
- "spam-rbl-table": null,
- "imap": {
- "action": null,
- "tag-msg": null,
- "tag-type": null,
- "log": null
- },
- "spam-iptrust-table": null,
- "replacemsg-group": null,
- "name": "Ansible_Spam_Filter_Profile",
- "spam-bwl-table": null,
- "spam-filtering": null,
- "msn-hotmail": {
- "log": null
- },
- "spam-bword-threshold": null,
- "mode": "delete",
- "options": null
- },
- "datagram_sent": {},
- "raw_response": {
- "status": {
- "message": "OK",
- "code": 0
- },
- "url": "/pm/config/adom/root/obj/spamfilter/profile/Ansible_Spam_Filter_Profile"
- },
- "post_method": "delete"
- },
- {
- "raw_response": {
- "status": {
- "message": "OK",
- "code": 0
- },
- "url": "/pm/config/adom/root/obj/spamfilter/profile"
- },
- "datagram_sent": {
- "comment": "Created by Ansible",
- "spam-log-fortiguard-response": "enable",
- "spam-log": "enable",
- "name": "Ansible_Spam_Filter_Profile",
- "spam-filtering": "enable",
- "flow-based": "enable",
- "spam-bword-threshold": 10,
- "external": "enable",
- "options": [
- "bannedword",
- "spamfsip",
- "spamfsurl",
- "spamrbl",
- "spamfsphish",
- "spambwl"
- ],
- "gmail": {
- "log": "enable"
- }
- },
- "paramgram_used": {
- "comment": "Created by Ansible",
- "smtp": {
- "local-override": null,
- "hdrip": null,
- "log": null,
- "tag-type": null,
- "tag-msg": null,
- "action": null
- },
- "yahoo-mail": {
- "log": null
- },
- "gmail": {
- "log": "enable"
- },
- "spam-bword-table": null,
- "mapi": {
- "action": null,
- "log": null
- },
- "flow-based": "enable",
- "spam-mheader-table": null,
- "spam-log-fortiguard-response": "enable",
- "spam-log": "enable",
- "adom": "root",
- "pop3": {
- "action": null,
- "tag-type": null,
- "log": null,
- "tag-msg": null
- },
- "external": "enable",
- "spam-rbl-table": null,
- "imap": {
- "action": null,
- "tag-type": null,
- "log": null,
- "tag-msg": null
- },
- "spam-iptrust-table": null,
- "name": "Ansible_Spam_Filter_Profile",
- "replacemsg-group": null,
- "spam-bwl-table": null,
- "spam-filtering": "enable",
- "msn-hotmail": {
- "log": null
- },
- "spam-bword-threshold": 10,
- "mode": "set",
- "options": [
- "bannedword",
- "spamfsip",
- "spamfsurl",
- "spamrbl",
- "spamfsphish",
- "spambwl"
- ]
- },
- "post_method": "set"
- }
- ]
-}
diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/fixtures/test_fmgr_secprof_ssl_ssh.json b/ansible_collections/community/fortios/tests/unit/plugins/modules/fixtures/test_fmgr_secprof_ssl_ssh.json
deleted file mode 100644
index 6dc02883f..000000000
--- a/ansible_collections/community/fortios/tests/unit/plugins/modules/fixtures/test_fmgr_secprof_ssl_ssh.json
+++ /dev/null
@@ -1,214 +0,0 @@
-{
- "fmgr_firewall_ssl_ssh_profile_modify": [
- {
- "paramgram_used": {
- "comment": null,
- "untrusted-caname": null,
- "mapi-over-https": null,
- "whitelist": null,
- "caname": null,
- "ftps": {
- "status": null,
- "allow-invalid-server-cert": null,
- "unsupported-ssl": null,
- "client-cert-request": null,
- "ports": null,
- "untrusted-cert": null
- },
- "ssl-exemptions-log": null,
- "https": {
- "status": null,
- "allow-invalid-server-cert": null,
- "unsupported-ssl": null,
- "client-cert-request": null,
- "ports": null,
- "untrusted-cert": null
- },
- "imaps": {
- "status": null,
- "allow-invalid-server-cert": null,
- "unsupported-ssl": null,
- "client-cert-request": null,
- "ports": null,
- "untrusted-cert": null
- },
- "server-cert-mode": null,
- "adom": "root",
- "ssl-exempt": {
- "regex": null,
- "wildcard-fqdn": null,
- "fortiguard-category": null,
- "address6": null,
- "address": null,
- "type": null
- },
- "ssl": {
- "inspect-all": null,
- "allow-invalid-server-cert": null,
- "client-cert-request": null,
- "untrusted-cert": null,
- "unsupported-ssl": null
- },
- "ssh": {
- "status": null,
- "inspect-all": null,
- "ssh-tun-policy-check": null,
- "ssh-policy-check": null,
- "ssh-algorithm": null,
- "unsupported-version": null,
- "ports": null
- },
- "use-ssl-server": null,
- "server-cert": null,
- "name": "Ansible_SSL_SSH_Profile",
- "ssl-anomalies-log": null,
- "ssl-server": {
- "pop3s-client-cert-request": null,
- "imaps-client-cert-request": null,
- "smtps-client-cert-request": null,
- "ip": null,
- "ssl-other-client-cert-request": null,
- "https-client-cert-request": null,
- "ftps-client-cert-request": null
- },
- "smtps": {
- "status": null,
- "allow-invalid-server-cert": null,
- "unsupported-ssl": null,
- "client-cert-request": null,
- "ports": null,
- "untrusted-cert": null
- },
- "rpc-over-https": null,
- "mode": "delete",
- "pop3s": {
- "status": null,
- "allow-invalid-server-cert": null,
- "unsupported-ssl": null,
- "client-cert-request": null,
- "ports": null,
- "untrusted-cert": null
- }
- },
- "datagram_sent": {},
- "raw_response": {
- "status": {
- "message": "OK",
- "code": 0
- },
- "url": "/pm/config/adom/root/obj/firewall/ssl-ssh-profile/Ansible_SSL_SSH_Profile"
- },
- "post_method": "delete"
- },
- {
- "raw_response": {
- "status": {
- "message": "OK",
- "code": 0
- },
- "url": "/pm/config/adom/root/obj/firewall/ssl-ssh-profile"
- },
- "datagram_sent": {
- "comment": "Created by Ansible Module TEST",
- "server-cert-mode": "replace",
- "name": "Ansible_SSL_SSH_Profile",
- "ssl-anomalies-log": "enable",
- "mapi-over-https": "enable",
- "whitelist": "enable",
- "ssl-exemptions-log": "enable",
- "rpc-over-https": "enable",
- "use-ssl-server": "enable"
- },
- "paramgram_used": {
- "comment": "Created by Ansible Module TEST",
- "untrusted-caname": null,
- "mapi-over-https": "enable",
- "whitelist": "enable",
- "caname": null,
- "ftps": {
- "status": null,
- "allow-invalid-server-cert": null,
- "unsupported-ssl": null,
- "untrusted-cert": null,
- "client-cert-request": null,
- "ports": null
- },
- "ssl-exemptions-log": "enable",
- "https": {
- "status": null,
- "allow-invalid-server-cert": null,
- "unsupported-ssl": null,
- "untrusted-cert": null,
- "client-cert-request": null,
- "ports": null
- },
- "pop3s": {
- "status": null,
- "allow-invalid-server-cert": null,
- "unsupported-ssl": null,
- "untrusted-cert": null,
- "client-cert-request": null,
- "ports": null
- },
- "server-cert-mode": "replace",
- "adom": "root",
- "ssl-exempt": {
- "regex": null,
- "wildcard-fqdn": null,
- "fortiguard-category": null,
- "address6": null,
- "address": null,
- "type": null
- },
- "ssl": {
- "unsupported-ssl": null,
- "inspect-all": null,
- "allow-invalid-server-cert": null,
- "untrusted-cert": null,
- "client-cert-request": null
- },
- "ssh": {
- "status": null,
- "inspect-all": null,
- "ssh-tun-policy-check": null,
- "ssh-policy-check": null,
- "ssh-algorithm": null,
- "unsupported-version": null,
- "ports": null
- },
- "server-cert": null,
- "name": "Ansible_SSL_SSH_Profile",
- "ssl-anomalies-log": "enable",
- "ssl-server": {
- "pop3s-client-cert-request": null,
- "imaps-client-cert-request": null,
- "smtps-client-cert-request": null,
- "ip": null,
- "ssl-other-client-cert-request": null,
- "https-client-cert-request": null,
- "ftps-client-cert-request": null
- },
- "smtps": {
- "status": null,
- "allow-invalid-server-cert": null,
- "unsupported-ssl": null,
- "untrusted-cert": null,
- "client-cert-request": null,
- "ports": null
- },
- "imaps": {
- "status": null,
- "allow-invalid-server-cert": null,
- "unsupported-ssl": null,
- "untrusted-cert": null,
- "client-cert-request": null,
- "ports": null
- },
- "rpc-over-https": "enable",
- "mode": "set",
- "use-ssl-server": "enable"
- },
- "post_method": "set"
- }
- ]
-}
diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/fortimanager_module.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/fortimanager_module.py
deleted file mode 100644
index b45c6e01a..000000000
--- a/ansible_collections/community/fortios/tests/unit/plugins/modules/fortimanager_module.py
+++ /dev/null
@@ -1,64 +0,0 @@
-# (c) 2016 Red Hat Inc.
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-from ansible_collections.community.fortios.tests.unit.plugins.modules.utils import AnsibleExitJson, AnsibleFailJson, ModuleTestCase
-
-
-class TestFortimanagerModule(ModuleTestCase):
-
- def execute_module(self, failed=False, changed=False, commands=None, sort=True, defaults=False):
-
- self.load_fixtures(commands)
-
- if failed:
- result = self.failed()
- self.assertTrue(result['failed'], result)
- else:
- result = self.changed(changed)
- self.assertEqual(result['changed'], changed, result)
-
- if commands is not None:
- if sort:
- self.assertEqual(sorted(commands), sorted(result['commands']), result['commands'])
- else:
- self.assertEqual(commands, result['commands'], result['commands'])
-
- return result
-
- def failed(self):
- with self.assertRaises(AnsibleFailJson) as exc:
- self.module.main()
-
- result = exc.exception.args[0]
- self.assertTrue(result['failed'], result)
- return result
-
- def changed(self, changed=False):
- with self.assertRaises(AnsibleExitJson) as exc:
- self.module.main()
-
- result = exc.exception.args[0]
- self.assertEqual(result['changed'], changed, result)
- return result
-
- def load_fixtures(self, commands=None):
- pass
diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_device.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_device.py
deleted file mode 100644
index 0d3a3005d..000000000
--- a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_device.py
+++ /dev/null
@@ -1,272 +0,0 @@
-# Copyright 2018 Fortinet, Inc.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import os
-import json
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-import pytest
-
-try:
- from ansible_collections.community.fortios.plugins.modules import fmgr_device
-except ImportError:
- pytest.skip("Could not load required modules for testing", allow_module_level=True)
-
-
-def load_fixtures():
- fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format(
- filename=os.path.splitext(os.path.basename(__file__))[0])
- try:
- with open(fixture_path, "r") as fixture_file:
- fixture_data = json.load(fixture_file)
- except IOError:
- return []
- return [fixture_data]
-
-
-@pytest.fixture(autouse=True)
-def module_mock(mocker):
- connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule')
- return connection_class_mock
-
-
-@pytest.fixture(autouse=True)
-def connection_mock(mocker):
- connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_device.Connection')
- return connection_class_mock
-
-
-@pytest.fixture(scope="function", params=load_fixtures())
-def fixture_data(request):
- func_name = request.function.__name__.replace("test_", "")
- return request.param.get(func_name, None)
-
-
-fmg_instance = FortiManagerHandler(connection_mock, module_mock)
-
-
-def test_discover_device(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
- # Fixture sets used:###########################
-
- ##################################################
- # device_username: admin
- # adom: ansible
- # device_ip: 10.7.220.151
- # device_unique_name: FGT1
- # mode: exec
- # device_serial: None
- # device_password: fortinet
- ##################################################
- ##################################################
- # device_username: admin
- # adom: ansible
- # device_ip: 10.7.220.152
- # device_unique_name: FGT2
- # mode: exec
- # device_serial: None
- # device_password: fortinet
- ##################################################
- ##################################################
- # device_username: admin
- # adom: ansible
- # device_ip: 10.7.220.153
- # device_unique_name: FGT3
- # mode: exec
- # device_serial: None
- # device_password: fortinet
- ##################################################
-
- # Test using fixture 1 #
- output = fmgr_device.discover_device(fmg_instance, fixture_data[0]['paramgram_used'])
- assert isinstance(output['raw_response'], dict) is True
- # Test using fixture 2 #
- output = fmgr_device.discover_device(fmg_instance, fixture_data[1]['paramgram_used'])
- assert isinstance(output['raw_response'], dict) is True
- # Test using fixture 3 #
- output = fmgr_device.discover_device(fmg_instance, fixture_data[2]['paramgram_used'])
- assert isinstance(output['raw_response'], dict) is True
-
-
-def test_add_device(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
- # Fixture sets used:###########################
-
- ##################################################
- # device_username: admin
- # adom: ansible
- # device_ip: 10.7.220.151
- # device_unique_name: FGT1
- # mode: exec
- # device_serial: None
- # device_password: fortinet
- ##################################################
- ##################################################
- # device_username: admin
- # adom: ansible
- # device_ip: 10.7.220.152
- # device_unique_name: FGT2
- # mode: exec
- # device_serial: None
- # device_password: fortinet
- ##################################################
- ##################################################
- # device_username: admin
- # adom: ansible
- # device_ip: 10.7.220.153
- # device_unique_name: FGT3
- # mode: exec
- # device_serial: None
- # device_password: fortinet
- ##################################################
-
- # Test using fixture 1 #
- output = fmgr_device.add_device(fmg_instance, fixture_data[0]['paramgram_used'])
- assert isinstance(output['raw_response'], dict) is True
- # Test using fixture 2 #
- output = fmgr_device.add_device(fmg_instance, fixture_data[1]['paramgram_used'])
- assert isinstance(output['raw_response'], dict) is True
- # Test using fixture 3 #
- output = fmgr_device.add_device(fmg_instance, fixture_data[2]['paramgram_used'])
- assert isinstance(output['raw_response'], dict) is True
-
-
-def test_delete_device(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
- # Fixture sets used:###########################
-
- ##################################################
- # device_username: admin
- # adom: root
- # device_ip: 10.7.220.151
- # device_unique_name: FGT1
- # mode: exec
- # device_serial: None
- # device_password: fortinet
- ##################################################
- ##################################################
- # device_username: admin
- # adom: ansible
- # device_ip: 10.7.220.152
- # device_unique_name: FGT2
- # mode: exec
- # device_serial: None
- # device_password: fortinet
- ##################################################
- ##################################################
- # device_username: admin
- # adom: ansible
- # device_ip: 10.7.220.153
- # device_unique_name: FGT3
- # mode: exec
- # device_serial: None
- # device_password: fortinet
- ##################################################
-
- # Test using fixture 1 #
- output = fmgr_device.delete_device(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 2 #
- output = fmgr_device.delete_device(fmg_instance, fixture_data[1]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 3 #
- output = fmgr_device.delete_device(fmg_instance, fixture_data[2]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
-
-
-def test_get_device(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
- # Fixture sets used:###########################
-
- ##################################################
- # device_username: admin
- # adom: ansible
- # device_ip: 10.7.220.151
- # device_unique_name: FGT1
- # mode: get
- # device_serial: None
- # device_password: fortinet
- ##################################################
- ##################################################
- # device_username: admin
- # adom: ansible
- # device_ip: 10.7.220.152
- # device_unique_name: FGT2
- # mode: get
- # device_serial: None
- # device_password: fortinet
- ##################################################
- ##################################################
- # device_username: admin
- # adom: ansible
- # device_ip: 10.7.220.153
- # device_unique_name: FGT3
- # mode: get
- # device_serial: None
- # device_password: fortinet
- ##################################################
- ##################################################
- # device_username: admin
- # adom: ansible
- # device_ip: 10.7.220.151
- # device_unique_name: FGT1
- # mode: get
- # device_serial: None
- # device_password: fortinet
- ##################################################
- ##################################################
- # device_username: admin
- # adom: ansible
- # device_ip: 10.7.220.152
- # device_unique_name: FGT2
- # mode: get
- # device_serial: None
- # device_password: fortinet
- ##################################################
- ##################################################
- # device_username: admin
- # adom: ansible
- # device_ip: 10.7.220.153
- # device_unique_name: FGT3
- # mode: get
- # device_serial: None
- # device_password: fortinet
- ##################################################
-
- # Test using fixture 1 #
- output = fmgr_device.get_device(fmg_instance, fixture_data[0]['paramgram_used'])
- assert isinstance(output['raw_response'], dict) is True
- # Test using fixture 2 #
- output = fmgr_device.get_device(fmg_instance, fixture_data[1]['paramgram_used'])
- assert isinstance(output['raw_response'], dict) is True
- # Test using fixture 3 #
- output = fmgr_device.get_device(fmg_instance, fixture_data[2]['paramgram_used'])
- assert isinstance(output['raw_response'], dict) is True
- # Test using fixture 4 #
- output = fmgr_device.get_device(fmg_instance, fixture_data[3]['paramgram_used'])
- assert output['raw_response']['status']['code'] == -3
- # Test using fixture 5 #
- output = fmgr_device.get_device(fmg_instance, fixture_data[4]['paramgram_used'])
- assert output['raw_response']['status']['code'] == -3
- # Test using fixture 6 #
- output = fmgr_device.get_device(fmg_instance, fixture_data[5]['paramgram_used'])
- assert output['raw_response']['status']['code'] == -3
diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_device_config.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_device_config.py
deleted file mode 100644
index b0540e970..000000000
--- a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_device_config.py
+++ /dev/null
@@ -1,188 +0,0 @@
-# Copyright 2018 Fortinet, Inc.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import os
-import json
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-import pytest
-
-try:
- from ansible_collections.community.fortios.plugins.modules import fmgr_device_config
-except ImportError:
- pytest.skip("Could not load required modules for testing", allow_module_level=True)
-
-
-def load_fixtures():
- fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format(
- filename=os.path.splitext(os.path.basename(__file__))[0])
- try:
- with open(fixture_path, "r") as fixture_file:
- fixture_data = json.load(fixture_file)
- except IOError:
- return []
- return [fixture_data]
-
-
-@pytest.fixture(autouse=True)
-def module_mock(mocker):
- connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule')
- return connection_class_mock
-
-
-@pytest.fixture(autouse=True)
-def connection_mock(mocker):
- connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_device_config.Connection')
- return connection_class_mock
-
-
-@pytest.fixture(scope="function", params=load_fixtures())
-def fixture_data(request):
- func_name = request.function.__name__.replace("test_", "")
- return request.param.get(func_name, None)
-
-
-fmg_instance = FortiManagerHandler(connection_mock, module_mock)
-
-
-def test_update_device_hostname(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
- # Fixture sets used:###########################
-
- ##################################################
- # adom: ansible
- # interface: None
- # device_unique_name: FGT1
- # install_config: disable
- # device_hostname: ansible-fgt01
- # interface_ip: None
- # interface_allow_access: None
- # mode: update
- ##################################################
- ##################################################
- # adom: ansible
- # interface: None
- # device_unique_name: FGT2
- # install_config: disable
- # device_hostname: ansible-fgt02
- # interface_ip: None
- # interface_allow_access: None
- # mode: update
- ##################################################
- ##################################################
- # adom: ansible
- # interface: None
- # device_unique_name: FGT3
- # install_config: disable
- # device_hostname: ansible-fgt03
- # interface_ip: None
- # interface_allow_access: None
- # mode: update
- ##################################################
-
- # Test using fixture 1 #
- output = fmgr_device_config.update_device_hostname(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 2 #
- output = fmgr_device_config.update_device_hostname(fmg_instance, fixture_data[1]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 3 #
- output = fmgr_device_config.update_device_hostname(fmg_instance, fixture_data[2]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
-
-
-def test_update_device_interface(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
- # Fixture sets used:###########################
-
- ##################################################
- # adom: ansible
- # install_config: disable
- # device_unique_name: FGT1
- # interface: port2
- # device_hostname: None
- # interface_ip: 10.1.1.1/24
- # interface_allow_access: ping, telnet, https, http
- # mode: update
- ##################################################
- ##################################################
- # adom: ansible
- # install_config: disable
- # device_unique_name: FGT2
- # interface: port2
- # device_hostname: None
- # interface_ip: 10.1.2.1/24
- # interface_allow_access: ping, telnet, https, http
- # mode: update
- ##################################################
- ##################################################
- # adom: ansible
- # install_config: disable
- # device_unique_name: FGT3
- # interface: port2
- # device_hostname: None
- # interface_ip: 10.1.3.1/24
- # interface_allow_access: ping, telnet, https, http
- # mode: update
- ##################################################
-
- # Test using fixture 1 #
- output = fmgr_device_config.update_device_interface(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 2 #
- output = fmgr_device_config.update_device_interface(fmg_instance, fixture_data[1]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 3 #
- output = fmgr_device_config.update_device_interface(fmg_instance, fixture_data[2]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
-
-
-def test_exec_config(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
- # Fixture sets used:###########################
-
- ##################################################
- # adom: ansible
- # interface: None
- # device_unique_name: FGT1
- # install_config: enable
- # device_hostname: None
- # interface_ip: None
- # interface_allow_access: None
- # mode: exec
- ##################################################
- ##################################################
- # adom: ansible
- # install_config: enable
- # device_unique_name: FGT2, FGT3
- # interface: None
- # device_hostname: None
- # interface_ip: None
- # interface_allow_access: None
- # mode: exec
- ##################################################
-
- # Test using fixture 1 #
- output = fmgr_device_config.exec_config(fmg_instance, fixture_data[0]['paramgram_used'])
- assert isinstance(output['raw_response'], dict) is True
- # Test using fixture 2 #
- output = fmgr_device_config.exec_config(fmg_instance, fixture_data[1]['paramgram_used'])
- assert isinstance(output['raw_response'], dict) is True
diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_device_group.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_device_group.py
deleted file mode 100644
index 723c29b11..000000000
--- a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_device_group.py
+++ /dev/null
@@ -1,202 +0,0 @@
-# Copyright 2018 Fortinet, Inc.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import os
-import json
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-import pytest
-
-try:
- from ansible_collections.community.fortios.plugins.modules import fmgr_device_group
-except ImportError:
- pytest.skip("Could not load required modules for testing", allow_module_level=True)
-
-
-def load_fixtures():
- fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format(
- filename=os.path.splitext(os.path.basename(__file__))[0])
- try:
- with open(fixture_path, "r") as fixture_file:
- fixture_data = json.load(fixture_file)
- except IOError:
- return []
- return [fixture_data]
-
-
-@pytest.fixture(autouse=True)
-def module_mock(mocker):
- connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule')
- return connection_class_mock
-
-
-@pytest.fixture(autouse=True)
-def connection_mock(mocker):
- connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_device_group.Connection')
- return connection_class_mock
-
-
-@pytest.fixture(scope="function", params=load_fixtures())
-def fixture_data(request):
- func_name = request.function.__name__.replace("test_", "")
- return request.param.get(func_name, None)
-
-
-fmg_instance = FortiManagerHandler(connection_mock, module_mock)
-
-
-def test_add_device_group(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
- # Fixture sets used:###########################
-
- ##################################################
- # grp_desc: CreatedbyAnsible
- # adom: ansible
- # grp_members: None
- # mode: add
- # grp_name: TestGroup
- # vdom: root
- ##################################################
- ##################################################
- # grp_desc: CreatedbyAnsible
- # adom: ansible
- # grp_members: None
- # mode: add
- # grp_name: testtest
- # vdom: root
- ##################################################
- ##################################################
- # grp_desc: None
- # adom: ansible
- # grp_members: FGT1
- # mode: add
- # grp_name: TestGroup
- # vdom: root
- ##################################################
- ##################################################
- # grp_desc: None
- # adom: ansible
- # grp_members: FGT3
- # mode: add
- # grp_name: testtest
- # vdom: root
- ##################################################
-
- # Test using fixture 1 #
- output = fmgr_device_group.add_device_group(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == -2
- # Test using fixture 2 #
- output = fmgr_device_group.add_device_group(fmg_instance, fixture_data[1]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 3 #
- output = fmgr_device_group.add_device_group(fmg_instance, fixture_data[2]['paramgram_used'])
- assert output['raw_response']['status']['code'] == -2
- # Test using fixture 4 #
- output = fmgr_device_group.add_device_group(fmg_instance, fixture_data[3]['paramgram_used'])
- assert output['raw_response']['status']['code'] == -2
-
-
-def test_delete_device_group(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
- # Fixture sets used:###########################
-
- ##################################################
- # grp_desc: CreatedbyAnsible
- # adom: ansible
- # grp_members: None
- # mode: delete
- # grp_name: TestGroup
- # vdom: root
- ##################################################
- ##################################################
- # grp_desc: CreatedbyAnsible
- # adom: ansible
- # grp_members: None
- # mode: delete
- # grp_name: testtest
- # vdom: root
- ##################################################
-
- # Test using fixture 1 #
- output = fmgr_device_group.delete_device_group(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 2 #
- output = fmgr_device_group.delete_device_group(fmg_instance, fixture_data[1]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
-
-
-def test_add_group_member(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
- # Fixture sets used:###########################
-
- ##################################################
- # grp_desc: None
- # adom: ansible
- # grp_members: FGT1
- # mode: add
- # grp_name: TestGroup
- # vdom: root
- ##################################################
- ##################################################
- # grp_desc: None
- # adom: ansible
- # grp_members: FGT3
- # mode: add
- # grp_name: testtest
- # vdom: root
- ##################################################
-
- # Test using fixture 1 #
- output = fmgr_device_group.add_group_member(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 2 #
- output = fmgr_device_group.add_group_member(fmg_instance, fixture_data[1]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
-
-
-def test_delete_group_member(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
- # Fixture sets used:###########################
-
- ##################################################
- # grp_desc: None
- # adom: ansible
- # grp_members: FGT3
- # mode: delete
- # grp_name: testtest
- # vdom: root
- ##################################################
- ##################################################
- # grp_desc: None
- # adom: ansible
- # grp_members: FGT1
- # mode: delete
- # grp_name: TestGroup
- # vdom: root
- ##################################################
-
- # Test using fixture 1 #
- output = fmgr_device_group.delete_group_member(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 2 #
- output = fmgr_device_group.delete_group_member(fmg_instance, fixture_data[1]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_device_provision_template.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_device_provision_template.py
deleted file mode 100644
index 3ece0f222..000000000
--- a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_device_provision_template.py
+++ /dev/null
@@ -1,1758 +0,0 @@
-# Copyright 2018 Fortinet, Inc.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import os
-import json
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-import pytest
-
-try:
- from ansible_collections.community.fortios.plugins.modules import fmgr_device_provision_template
-except ImportError:
- pytest.skip("Could not load required modules for testing", allow_module_level=True)
-
-
-def load_fixtures():
- fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format(
- filename=os.path.splitext(os.path.basename(__file__))[0])
- try:
- with open(fixture_path, "r") as fixture_file:
- fixture_data = json.load(fixture_file)
- except IOError:
- return []
- return [fixture_data]
-
-
-@pytest.fixture(autouse=True)
-def module_mock(mocker):
- connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule')
- return connection_class_mock
-
-
-@pytest.fixture(autouse=True)
-def connection_mock(mocker):
- connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_device_provision_template.Connection')
- return connection_class_mock
-
-
-@pytest.fixture(scope="function", params=load_fixtures())
-def fixture_data(request):
- func_name = request.function.__name__.replace("test_", "")
- return request.param.get(func_name, None)
-
-
-fmg_instance = FortiManagerHandler(connection_mock, module_mock)
-
-
-def test_get_devprof(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
- # Fixture sets used:###########################
-
- ##################################################
- # snmpv3_security_level: None
- # snmp_v2c_query_status: None
- # ntp_type: None
- # dns_suffix: None
- # snmpv3_queries: None
- # snmpv3_trap_status: None
- # snmp_v2c_name: None
- # syslog_facility: syslog
- # snmp_v2c_status: None
- # smtp_validate_cert: None
- # snmpv3_name: None
- # snmp_v2c_trap_src_ipv4: None
- # syslog_port: None
- # ntp_server: None
- # admin_https_port: None
- # ntp_status: None
- # syslog_server: None
- # dns_primary_ipv4: None
- # admin_timeout: None
- # snmpv3_auth_proto: None
- # smtp_port: None
- # snmpv3_priv_pwd: None
- # smtp_server: None
- # syslog_enc_algorithm: disable
- # dns_secondary_ipv4: None
- # smtp_username: None
- # snmpv3_auth_pwd: None
- # syslog_certificate: None
- # admin_fortiguard_target: None
- # snmpv3_query_port: None
- # smtp_password: None
- # adom: ansible
- # snmpv3_notify_hosts: None
- # syslog_mode: udp
- # snmp_v2c_query_port: None
- # snmp_v2c_trap_status: None
- # snmp_status: enable
- # syslog_status: None
- # admin_fortianalyzer_target: None
- # ntp_auth: None
- # snmp_v2c_id: None
- # admin_http_port: None
- # ntp_v3: None
- # snmp_v2c_query_hosts_ipv4: None
- # ntp_sync_interval: None
- # snmpv3_source_ip: None
- # snmpv3_trap_rport: None
- # admin_gui_theme: None
- # syslog_filter: None
- # ntp_auth_pwd: None
- # provisioning_template: ansibleTest
- # smtp_replyto: None
- # provision_targets: None
- # snmp_v2c_trap_port: None
- # snmpv3_priv_proto: None
- # admin_enable_fortiguard: None
- # admin_switch_controller: None
- # admin_language: None
- # smtp_conn_sec: None
- # mode: get
- # smtp_source_ipv4: None
- # snmpv3_status: None
- # delete_provisioning_template: None
- # snmp_v2c_trap_hosts_ipv4: None
- # admin_https_redirect: None
- ##################################################
- ##################################################
- # snmpv3_security_level: None
- # snmp_v2c_query_status: None
- # ntp_type: None
- # dns_suffix: None
- # snmpv3_queries: None
- # snmpv3_trap_status: None
- # snmp_v2c_name: None
- # syslog_facility: kernel
- # snmp_v2c_status: None
- # smtp_validate_cert: None
- # snmpv3_name: None
- # snmp_v2c_trap_src_ipv4: None
- # syslog_port: 514
- # ntp_server: None
- # admin_https_port: None
- # ntp_status: None
- # syslog_server: 10.7.220.59
- # dns_primary_ipv4: None
- # admin_timeout: None
- # snmpv3_auth_proto: None
- # smtp_port: None
- # snmpv3_priv_pwd: None
- # smtp_server: None
- # syslog_enc_algorithm: disable
- # dns_secondary_ipv4: None
- # smtp_replyto: None
- # smtp_username: None
- # snmpv3_auth_pwd: None
- # syslog_certificate: None
- # admin_fortiguard_target: None
- # snmpv3_query_port: None
- # smtp_password: None
- # adom: ansible
- # snmpv3_notify_hosts: None
- # syslog_mode: udp
- # snmp_v2c_query_port: None
- # snmp_v2c_trap_status: None
- # snmp_status: None
- # syslog_status: enable
- # admin_fortianalyzer_target: None
- # ntp_auth: None
- # snmp_v2c_id: None
- # admin_http_port: None
- # snmp_v2c_query_hosts_ipv4: None
- # ntp_sync_interval: None
- # snmpv3_source_ip: None
- # snmpv3_trap_rport: None
- # admin_gui_theme: None
- # syslog_filter: critical
- # ntp_auth_pwd: None
- # provisioning_template: ansibleTest
- # snmp_v2c_trap_hosts_ipv4: None
- # provision_targets: None
- # snmp_v2c_trap_port: None
- # snmpv3_priv_proto: None
- # admin_enable_fortiguard: None
- # admin_switch_controller: None
- # admin_language: None
- # smtp_conn_sec: None
- # mode: get
- # smtp_source_ipv4: None
- # snmpv3_status: None
- # delete_provisioning_template: None
- # ntp_v3: None
- # admin_https_redirect: None
- ##################################################
- ##################################################
- # snmpv3_security_level: None
- # snmp_v2c_query_status: enable
- # ntp_type: None
- # dns_suffix: None
- # snmpv3_queries: None
- # snmpv3_trap_status: None
- # snmp_v2c_name: ansibleV2c
- # syslog_facility: syslog
- # snmp_v2c_status: enable
- # smtp_validate_cert: None
- # snmpv3_name: None
- # snmp_v2c_trap_src_ipv4: 10.7.220.41
- # syslog_port: None
- # ntp_server: None
- # admin_https_port: None
- # ntp_status: None
- # syslog_server: None
- # dns_primary_ipv4: None
- # admin_timeout: None
- # snmpv3_auth_proto: None
- # smtp_port: None
- # snmpv3_priv_pwd: None
- # smtp_server: None
- # syslog_enc_algorithm: disable
- # dns_secondary_ipv4: None
- # smtp_username: None
- # snmpv3_auth_pwd: None
- # syslog_certificate: None
- # admin_fortiguard_target: None
- # snmpv3_query_port: None
- # smtp_password: None
- # adom: ansible
- # snmpv3_notify_hosts: None
- # syslog_mode: udp
- # snmp_v2c_query_port: 162
- # snmp_v2c_trap_status: enable
- # snmp_status: enable
- # syslog_status: None
- # admin_fortianalyzer_target: None
- # ntp_auth: None
- # snmp_v2c_id: 1
- # admin_http_port: None
- # ntp_v3: None
- # snmp_v2c_query_hosts_ipv4: 10.7.220.59 255.255.255.255, 10.7.220.0 255.255.255.0
- # ntp_sync_interval: None
- # snmpv3_source_ip: None
- # snmpv3_trap_rport: None
- # admin_gui_theme: None
- # syslog_filter: None
- # ntp_auth_pwd: None
- # provisioning_template: ansibleTest
- # smtp_replyto: None
- # provision_targets: None
- # snmp_v2c_trap_port: 161
- # snmpv3_priv_proto: None
- # admin_enable_fortiguard: None
- # admin_switch_controller: None
- # admin_language: None
- # smtp_conn_sec: None
- # mode: get
- # smtp_source_ipv4: None
- # snmpv3_status: None
- # delete_provisioning_template: None
- # snmp_v2c_trap_hosts_ipv4: 10.7.220.59 255.255.255.255, 10.7.220.60 255.255.255.255
- # admin_https_redirect: None
- ##################################################
- ##################################################
- # snmpv3_security_level: auth-priv
- # snmp_v2c_query_status: None
- # provision_targets: None
- # ntp_type: None
- # dns_suffix: None
- # snmpv3_queries: enable
- # snmpv3_trap_status: enable
- # snmp_v2c_name: None
- # syslog_facility: syslog
- # snmp_v2c_status: None
- # smtp_validate_cert: None
- # snmpv3_name: ansibleSNMPv3
- # snmp_v2c_id: None
- # syslog_port: None
- # ntp_server: None
- # admin_https_port: None
- # ntp_status: None
- # syslog_server: None
- # admin_switch_controller: None
- # admin_timeout: None
- # snmpv3_auth_proto: sha
- # smtp_port: None
- # snmpv3_priv_pwd: fortinet
- # smtp_server: None
- # syslog_enc_algorithm: disable
- # snmp_v2c_query_hosts_ipv4: None
- # smtp_username: None
- # mode: get
- # syslog_certificate: None
- # admin_fortiguard_target: None
- # snmpv3_query_port: 161
- # smtp_password: None
- # adom: ansible
- # snmpv3_notify_hosts: 10.7.220.59,10.7.220.60
- # syslog_mode: udp
- # snmp_v2c_query_port: None
- # snmp_v2c_trap_status: None
- # snmp_status: enable
- # syslog_status: None
- # snmp_v2c_trap_hosts_ipv4: None
- # admin_fortianalyzer_target: None
- # snmp_v2c_trap_src_ipv4: None
- # admin_http_port: None
- # dns_secondary_ipv4: None
- # syslog_filter: None
- # snmpv3_source_ip: 0.0.0.0
- # snmpv3_trap_rport: 162
- # admin_gui_theme: None
- # ntp_sync_interval: None
- # ntp_auth_pwd: None
- # provisioning_template: ansibleTest
- # ntp_v3: None
- # ntp_auth: None
- # snmp_v2c_trap_port: None
- # snmpv3_priv_proto: aes256
- # admin_enable_fortiguard: None
- # dns_primary_ipv4: None
- # admin_language: None
- # smtp_conn_sec: None
- # snmpv3_auth_pwd: fortinet
- # smtp_source_ipv4: None
- # snmpv3_status: enable
- # delete_provisioning_template: None
- # smtp_replyto: None
- # admin_https_redirect: None
- ##################################################
- ##################################################
- # snmpv3_security_level: None
- # snmp_v2c_query_status: None
- # ntp_type: fortiguard
- # dns_suffix: None
- # snmpv3_queries: None
- # snmpv3_trap_status: None
- # snmp_v2c_name: None
- # syslog_facility: syslog
- # snmp_v2c_status: None
- # smtp_validate_cert: None
- # snmpv3_name: None
- # snmp_v2c_trap_src_ipv4: None
- # syslog_port: None
- # ntp_server: None
- # admin_https_port: None
- # ntp_status: enable
- # syslog_server: None
- # dns_primary_ipv4: None
- # admin_timeout: None
- # snmpv3_auth_proto: None
- # smtp_port: None
- # snmpv3_priv_pwd: None
- # smtp_server: None
- # syslog_enc_algorithm: disable
- # dns_secondary_ipv4: None
- # smtp_replyto: None
- # smtp_username: None
- # snmpv3_auth_pwd: None
- # syslog_certificate: None
- # admin_fortiguard_target: None
- # snmpv3_query_port: None
- # smtp_password: None
- # adom: ansible
- # snmpv3_notify_hosts: None
- # syslog_mode: udp
- # snmp_v2c_query_port: None
- # snmp_v2c_trap_status: None
- # snmp_status: None
- # syslog_status: None
- # admin_fortianalyzer_target: None
- # ntp_auth: None
- # snmp_v2c_id: None
- # admin_http_port: None
- # snmp_v2c_query_hosts_ipv4: None
- # ntp_sync_interval: 60
- # snmpv3_source_ip: None
- # snmpv3_trap_rport: None
- # admin_gui_theme: None
- # syslog_filter: None
- # ntp_auth_pwd: None
- # provisioning_template: ansibleTest
- # snmp_v2c_trap_hosts_ipv4: None
- # provision_targets: None
- # snmp_v2c_trap_port: None
- # snmpv3_priv_proto: None
- # admin_enable_fortiguard: None
- # admin_switch_controller: None
- # admin_language: None
- # smtp_conn_sec: None
- # mode: get
- # smtp_source_ipv4: None
- # snmpv3_status: None
- # delete_provisioning_template: None
- # ntp_v3: None
- # admin_https_redirect: None
- ##################################################
- ##################################################
- # snmpv3_security_level: None
- # snmp_v2c_query_status: None
- # ntp_type: custom
- # dns_suffix: None
- # snmpv3_queries: None
- # snmpv3_trap_status: None
- # snmp_v2c_name: None
- # syslog_facility: syslog
- # snmp_v2c_status: None
- # smtp_validate_cert: None
- # snmpv3_name: None
- # snmp_v2c_trap_src_ipv4: None
- # syslog_port: None
- # ntp_server: 10.7.220.32,10.7.220.1
- # admin_https_port: None
- # ntp_status: enable
- # syslog_server: None
- # dns_primary_ipv4: None
- # admin_timeout: None
- # snmpv3_auth_proto: None
- # smtp_port: None
- # snmpv3_priv_pwd: None
- # smtp_server: None
- # syslog_enc_algorithm: disable
- # dns_secondary_ipv4: None
- # smtp_username: None
- # snmpv3_auth_pwd: None
- # syslog_certificate: None
- # admin_fortiguard_target: None
- # snmpv3_query_port: None
- # smtp_password: None
- # adom: ansible
- # snmpv3_notify_hosts: None
- # syslog_mode: udp
- # snmp_v2c_query_port: None
- # snmp_v2c_trap_status: None
- # snmp_status: None
- # syslog_status: None
- # admin_fortianalyzer_target: None
- # ntp_auth: enable
- # snmp_v2c_id: None
- # admin_http_port: None
- # ntp_v3: None
- # snmp_v2c_query_hosts_ipv4: None
- # ntp_sync_interval: 60
- # snmpv3_source_ip: None
- # snmpv3_trap_rport: None
- # admin_gui_theme: None
- # syslog_filter: None
- # ntp_auth_pwd: fortinet
- # provisioning_template: ansibleTest
- # smtp_replyto: None
- # provision_targets: None
- # snmp_v2c_trap_port: None
- # snmpv3_priv_proto: None
- # admin_enable_fortiguard: None
- # admin_switch_controller: None
- # admin_language: None
- # smtp_conn_sec: None
- # mode: get
- # smtp_source_ipv4: None
- # snmpv3_status: None
- # delete_provisioning_template: None
- # snmp_v2c_trap_hosts_ipv4: None
- # admin_https_redirect: None
- ##################################################
- ##################################################
- # snmpv3_security_level: None
- # snmp_v2c_query_status: None
- # ntp_type: None
- # dns_suffix: None
- # snmpv3_queries: None
- # snmpv3_trap_status: None
- # snmp_v2c_name: None
- # syslog_facility: syslog
- # snmp_v2c_status: None
- # smtp_validate_cert: None
- # snmpv3_name: None
- # snmp_v2c_trap_src_ipv4: None
- # syslog_port: None
- # ntp_server: None
- # admin_https_port: 4433
- # ntp_status: None
- # syslog_server: None
- # dns_primary_ipv4: None
- # admin_timeout: 60
- # snmpv3_auth_proto: None
- # smtp_port: None
- # snmpv3_priv_pwd: None
- # smtp_server: None
- # syslog_enc_algorithm: disable
- # dns_secondary_ipv4: None
- # smtp_replyto: None
- # smtp_username: None
- # snmpv3_auth_pwd: None
- # syslog_certificate: None
- # admin_fortiguard_target: None
- # snmpv3_query_port: None
- # smtp_password: None
- # adom: ansible
- # snmpv3_notify_hosts: None
- # syslog_mode: udp
- # snmp_v2c_query_port: None
- # snmp_v2c_trap_status: None
- # snmp_status: None
- # syslog_status: None
- # admin_fortianalyzer_target: 10.7.220.38
- # ntp_auth: None
- # snmp_v2c_id: None
- # admin_http_port: 8080
- # snmp_v2c_query_hosts_ipv4: None
- # ntp_sync_interval: None
- # snmpv3_source_ip: None
- # snmpv3_trap_rport: None
- # admin_gui_theme: blue
- # syslog_filter: None
- # ntp_auth_pwd: None
- # provisioning_template: ansibleTest
- # snmp_v2c_trap_hosts_ipv4: None
- # provision_targets: None
- # snmp_v2c_trap_port: None
- # snmpv3_priv_proto: None
- # admin_enable_fortiguard: this-fmg
- # admin_switch_controller: enable
- # admin_language: english
- # smtp_conn_sec: None
- # mode: get
- # smtp_source_ipv4: None
- # snmpv3_status: None
- # delete_provisioning_template: None
- # ntp_v3: None
- # admin_https_redirect: enable
- ##################################################
- ##################################################
- # snmpv3_security_level: None
- # snmp_v2c_query_status: None
- # ntp_type: None
- # dns_suffix: None
- # snmpv3_queries: None
- # snmpv3_trap_status: None
- # snmp_v2c_name: None
- # syslog_facility: syslog
- # snmp_v2c_status: None
- # smtp_validate_cert: disable
- # snmpv3_name: None
- # snmp_v2c_trap_src_ipv4: None
- # syslog_port: None
- # ntp_server: None
- # admin_https_port: None
- # ntp_status: None
- # syslog_server: None
- # dns_primary_ipv4: None
- # admin_timeout: None
- # snmpv3_auth_proto: None
- # smtp_port: 25
- # snmpv3_priv_pwd: None
- # smtp_server: 10.7.220.32
- # syslog_enc_algorithm: disable
- # dns_secondary_ipv4: None
- # smtp_username: ansible
- # snmpv3_auth_pwd: None
- # syslog_certificate: None
- # admin_fortiguard_target: None
- # snmpv3_query_port: None
- # smtp_password: fortinet
- # adom: ansible
- # snmpv3_notify_hosts: None
- # syslog_mode: udp
- # snmp_v2c_query_port: None
- # snmp_v2c_trap_status: None
- # snmp_status: None
- # syslog_status: None
- # admin_fortianalyzer_target: None
- # ntp_auth: None
- # snmp_v2c_id: None
- # admin_http_port: None
- # ntp_v3: None
- # snmp_v2c_query_hosts_ipv4: None
- # ntp_sync_interval: None
- # snmpv3_source_ip: None
- # snmpv3_trap_rport: None
- # admin_gui_theme: None
- # syslog_filter: None
- # ntp_auth_pwd: None
- # provisioning_template: ansibleTest
- # smtp_replyto: ansible@do-not-reply.com
- # provision_targets: None
- # snmp_v2c_trap_port: None
- # snmpv3_priv_proto: None
- # admin_enable_fortiguard: None
- # admin_switch_controller: None
- # admin_language: None
- # smtp_conn_sec: starttls
- # mode: get
- # smtp_source_ipv4: 0.0.0.0
- # snmpv3_status: None
- # delete_provisioning_template: None
- # snmp_v2c_trap_hosts_ipv4: None
- # admin_https_redirect: None
- ##################################################
- ##################################################
- # snmpv3_security_level: None
- # snmp_v2c_query_status: None
- # ntp_type: None
- # dns_suffix: ansible.local
- # snmpv3_queries: None
- # snmpv3_trap_status: None
- # snmp_v2c_name: None
- # syslog_facility: syslog
- # snmp_v2c_status: None
- # smtp_validate_cert: None
- # snmpv3_name: None
- # snmp_v2c_trap_src_ipv4: None
- # syslog_port: None
- # ntp_server: None
- # admin_https_port: None
- # ntp_status: None
- # syslog_server: None
- # dns_primary_ipv4: 8.8.8.8
- # admin_timeout: None
- # snmpv3_auth_proto: None
- # smtp_port: None
- # snmpv3_priv_pwd: None
- # smtp_server: None
- # syslog_enc_algorithm: disable
- # dns_secondary_ipv4: 4.4.4.4
- # smtp_replyto: None
- # smtp_username: None
- # snmpv3_auth_pwd: None
- # syslog_certificate: None
- # admin_fortiguard_target: None
- # snmpv3_query_port: None
- # smtp_password: None
- # adom: ansible
- # snmpv3_notify_hosts: None
- # syslog_mode: udp
- # snmp_v2c_query_port: None
- # snmp_v2c_trap_status: None
- # snmp_status: None
- # syslog_status: None
- # admin_fortianalyzer_target: None
- # ntp_auth: None
- # snmp_v2c_id: None
- # admin_http_port: None
- # snmp_v2c_query_hosts_ipv4: None
- # ntp_sync_interval: None
- # snmpv3_source_ip: None
- # snmpv3_trap_rport: None
- # admin_gui_theme: None
- # syslog_filter: None
- # ntp_auth_pwd: None
- # provisioning_template: ansibleTest
- # snmp_v2c_trap_hosts_ipv4: None
- # provision_targets: None
- # snmp_v2c_trap_port: None
- # snmpv3_priv_proto: None
- # admin_enable_fortiguard: None
- # admin_switch_controller: None
- # admin_language: None
- # smtp_conn_sec: None
- # mode: get
- # smtp_source_ipv4: None
- # snmpv3_status: None
- # delete_provisioning_template: None
- # ntp_v3: None
- # admin_https_redirect: None
- ##################################################
- ##################################################
- # snmpv3_security_level: None
- # snmp_v2c_query_status: None
- # ntp_type: None
- # dns_suffix: None
- # snmpv3_queries: None
- # snmpv3_trap_status: None
- # snmp_v2c_name: None
- # syslog_facility: syslog
- # snmp_v2c_status: None
- # smtp_validate_cert: None
- # snmpv3_name: None
- # snmp_v2c_trap_src_ipv4: None
- # syslog_port: None
- # ntp_server: None
- # admin_https_port: None
- # ntp_status: None
- # syslog_server: None
- # dns_primary_ipv4: None
- # admin_timeout: None
- # snmpv3_auth_proto: None
- # smtp_port: None
- # snmpv3_priv_pwd: None
- # smtp_server: None
- # syslog_enc_algorithm: disable
- # dns_secondary_ipv4: None
- # smtp_username: None
- # snmpv3_auth_pwd: None
- # syslog_certificate: None
- # admin_fortiguard_target: None
- # snmpv3_query_port: None
- # smtp_password: None
- # adom: ansible
- # snmpv3_notify_hosts: None
- # syslog_mode: udp
- # snmp_v2c_query_port: None
- # snmp_v2c_trap_status: None
- # snmp_status: None
- # syslog_status: None
- # admin_fortianalyzer_target: None
- # ntp_auth: None
- # snmp_v2c_id: None
- # admin_http_port: None
- # ntp_v3: None
- # snmp_v2c_query_hosts_ipv4: None
- # ntp_sync_interval: None
- # snmpv3_source_ip: None
- # snmpv3_trap_rport: None
- # admin_gui_theme: None
- # syslog_filter: None
- # ntp_auth_pwd: None
- # provisioning_template: ansibleTest
- # smtp_replyto: None
- # provision_targets: FGT1,FGT2
- # snmp_v2c_trap_port: None
- # snmpv3_priv_proto: None
- # admin_enable_fortiguard: None
- # admin_switch_controller: None
- # admin_language: None
- # smtp_conn_sec: None
- # mode: get
- # smtp_source_ipv4: None
- # snmpv3_status: None
- # delete_provisioning_template: None
- # snmp_v2c_trap_hosts_ipv4: None
- # admin_https_redirect: None
- ##################################################
-
- # Test using fixture 1 #
- output = fmgr_device_provision_template.get_devprof(fmg_instance, fixture_data[0]['paramgram_used'])
- assert isinstance(output['raw_response'], dict) is True
- # Test using fixture 2 #
- output = fmgr_device_provision_template.get_devprof(fmg_instance, fixture_data[1]['paramgram_used'])
- assert isinstance(output['raw_response'], dict) is True
- # Test using fixture 3 #
- output = fmgr_device_provision_template.get_devprof(fmg_instance, fixture_data[2]['paramgram_used'])
- assert isinstance(output['raw_response'], dict) is True
- # Test using fixture 4 #
- output = fmgr_device_provision_template.get_devprof(fmg_instance, fixture_data[3]['paramgram_used'])
- assert isinstance(output['raw_response'], dict) is True
- # Test using fixture 5 #
- output = fmgr_device_provision_template.get_devprof(fmg_instance, fixture_data[4]['paramgram_used'])
- assert isinstance(output['raw_response'], dict) is True
- # Test using fixture 6 #
- output = fmgr_device_provision_template.get_devprof(fmg_instance, fixture_data[5]['paramgram_used'])
- assert isinstance(output['raw_response'], dict) is True
- # Test using fixture 7 #
- output = fmgr_device_provision_template.get_devprof(fmg_instance, fixture_data[6]['paramgram_used'])
- assert isinstance(output['raw_response'], dict) is True
- # Test using fixture 8 #
- output = fmgr_device_provision_template.get_devprof(fmg_instance, fixture_data[7]['paramgram_used'])
- assert isinstance(output['raw_response'], dict) is True
- # Test using fixture 9 #
- output = fmgr_device_provision_template.get_devprof(fmg_instance, fixture_data[8]['paramgram_used'])
- assert isinstance(output['raw_response'], dict) is True
- # Test using fixture 10 #
- output = fmgr_device_provision_template.get_devprof(fmg_instance, fixture_data[9]['paramgram_used'])
- assert isinstance(output['raw_response'], dict) is True
-
-
-def test_set_devprof(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
- # Fixture sets used:###########################
-
- ##################################################
- # snmpv3_security_level: None
- # snmp_v2c_query_status: None
- # smtp_port: None
- # ntp_type: None
- # dns_suffix: None
- # snmpv3_queries: None
- # snmpv3_trap_status: None
- # snmp_v2c_name: None
- # syslog_facility: syslog
- # snmp_v2c_status: None
- # smtp_validate_cert: None
- # snmpv3_name: None
- # snmp_v2c_trap_src_ipv4: None
- # syslog_port: None
- # ntp_server: None
- # admin_https_port: None
- # ntp_status: None
- # syslog_server: None
- # dns_primary_ipv4: None
- # admin_timeout: None
- # snmpv3_auth_proto: None
- # ntp_auth: None
- # snmpv3_priv_pwd: None
- # smtp_server: None
- # syslog_enc_algorithm: disable
- # dns_secondary_ipv4: None
- # smtp_replyto: None
- # smtp_username: None
- # snmpv3_auth_pwd: None
- # syslog_certificate: None
- # admin_fortiguard_target: None
- # snmpv3_query_port: None
- # smtp_password: None
- # adom: ansible
- # snmpv3_notify_hosts: None
- # syslog_mode: udp
- # snmp_v2c_query_port: None
- # snmp_v2c_trap_status: None
- # snmp_status: None
- # syslog_status: None
- # admin_fortianalyzer_target: None
- # snmp_v2c_id: None
- # admin_http_port: None
- # snmp_v2c_query_hosts_ipv4: None
- # ntp_sync_interval: None
- # snmpv3_source_ip: None
- # snmpv3_trap_rport: None
- # admin_gui_theme: None
- # syslog_filter: None
- # ntp_auth_pwd: None
- # provisioning_template: None
- # snmp_v2c_trap_hosts_ipv4: None
- # provision_targets: None
- # snmp_v2c_trap_port: None
- # snmpv3_priv_proto: None
- # admin_enable_fortiguard: None
- # admin_switch_controller: None
- # admin_language: None
- # smtp_conn_sec: None
- # mode: delete
- # smtp_source_ipv4: None
- # snmpv3_status: None
- # delete_provisioning_template: ansibleTest
- # ntp_v3: None
- # admin_https_redirect: None
- ##################################################
-
- # Test using fixture 1 #
- output = fmgr_device_provision_template.set_devprof(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
-
-
-def test_set_devprof_scope(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
- # Fixture sets used:###########################
-
- ##################################################
- # snmpv3_security_level: None
- # snmp_v2c_query_status: None
- # provision_targets: FGT1,FGT2
- # ntp_type: None
- # dns_suffix: None
- # snmpv3_queries: None
- # snmpv3_trap_status: None
- # snmp_v2c_name: None
- # syslog_facility: syslog
- # snmp_v2c_status: None
- # smtp_validate_cert: None
- # snmpv3_name: None
- # snmp_v2c_id: None
- # syslog_port: None
- # ntp_server: None
- # admin_https_port: None
- # ntp_status: None
- # syslog_server: None
- # admin_switch_controller: None
- # admin_timeout: None
- # snmpv3_auth_proto: None
- # smtp_port: None
- # snmpv3_priv_pwd: None
- # smtp_server: None
- # syslog_enc_algorithm: disable
- # snmp_v2c_query_hosts_ipv4: None
- # smtp_username: None
- # mode: set
- # syslog_certificate: None
- # admin_fortiguard_target: None
- # snmpv3_query_port: None
- # smtp_password: None
- # adom: ansible
- # snmpv3_notify_hosts: None
- # syslog_mode: udp
- # snmp_v2c_query_port: None
- # snmp_v2c_trap_status: None
- # snmp_status: None
- # syslog_status: None
- # admin_https_redirect: None
- # admin_fortianalyzer_target: None
- # snmp_v2c_trap_src_ipv4: None
- # admin_http_port: None
- # dns_secondary_ipv4: None
- # syslog_filter: None
- # snmpv3_source_ip: None
- # snmpv3_trap_rport: None
- # admin_gui_theme: None
- # ntp_sync_interval: None
- # ntp_auth_pwd: None
- # provisioning_template: ansibleTest
- # smtp_replyto: None
- # ntp_auth: None
- # snmp_v2c_trap_port: None
- # snmpv3_priv_proto: None
- # admin_enable_fortiguard: None
- # dns_primary_ipv4: None
- # admin_language: None
- # smtp_conn_sec: None
- # snmpv3_auth_pwd: None
- # smtp_source_ipv4: None
- # snmpv3_status: None
- # delete_provisioning_template: None
- # snmp_v2c_trap_hosts_ipv4: None
- # ntp_v3: None
- ##################################################
-
- # Test using fixture 1 #
- output = fmgr_device_provision_template.set_devprof_scope(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
-
-
-def test_set_devprof_snmp(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
- # Fixture sets used:###########################
-
- ##################################################
- # snmpv3_security_level: None
- # snmp_v2c_query_status: None
- # provision_targets: None
- # ntp_type: None
- # dns_suffix: None
- # snmpv3_queries: None
- # snmpv3_trap_status: None
- # snmp_v2c_name: None
- # syslog_facility: syslog
- # snmp_v2c_status: None
- # smtp_validate_cert: None
- # snmpv3_name: None
- # snmp_v2c_id: None
- # syslog_port: None
- # ntp_server: None
- # admin_https_port: None
- # ntp_status: None
- # syslog_server: None
- # admin_switch_controller: None
- # admin_timeout: None
- # snmpv3_auth_proto: None
- # smtp_port: None
- # snmpv3_priv_pwd: None
- # smtp_server: None
- # syslog_enc_algorithm: disable
- # snmp_v2c_query_hosts_ipv4: None
- # smtp_username: None
- # mode: set
- # syslog_certificate: None
- # admin_fortiguard_target: None
- # snmpv3_query_port: None
- # smtp_password: None
- # adom: ansible
- # snmpv3_notify_hosts: None
- # syslog_mode: udp
- # snmp_v2c_query_port: None
- # snmp_v2c_trap_status: None
- # snmp_status: enable
- # syslog_status: None
- # admin_https_redirect: None
- # admin_fortianalyzer_target: None
- # snmp_v2c_trap_src_ipv4: None
- # admin_http_port: None
- # dns_secondary_ipv4: None
- # syslog_filter: None
- # snmpv3_source_ip: None
- # snmpv3_trap_rport: None
- # admin_gui_theme: None
- # ntp_sync_interval: None
- # ntp_auth_pwd: None
- # provisioning_template: ansibleTest
- # smtp_replyto: None
- # ntp_auth: None
- # snmp_v2c_trap_port: None
- # snmpv3_priv_proto: None
- # admin_enable_fortiguard: None
- # dns_primary_ipv4: None
- # admin_language: None
- # smtp_conn_sec: None
- # snmpv3_auth_pwd: None
- # smtp_source_ipv4: None
- # snmpv3_status: None
- # delete_provisioning_template: None
- # snmp_v2c_trap_hosts_ipv4: None
- # ntp_v3: None
- ##################################################
- ##################################################
- # snmpv3_security_level: None
- # snmp_v2c_query_status: enable
- # provision_targets: None
- # ntp_type: None
- # dns_suffix: None
- # snmpv3_queries: None
- # snmpv3_trap_status: None
- # snmp_v2c_name: ansibleV2c
- # syslog_facility: syslog
- # snmp_v2c_status: enable
- # smtp_validate_cert: None
- # snmpv3_name: None
- # snmp_v2c_id: 1
- # syslog_port: None
- # ntp_server: None
- # admin_https_port: None
- # ntp_status: None
- # syslog_server: None
- # admin_switch_controller: None
- # admin_timeout: None
- # snmpv3_auth_proto: None
- # smtp_port: None
- # snmpv3_priv_pwd: None
- # smtp_server: None
- # syslog_enc_algorithm: disable
- # snmp_v2c_query_hosts_ipv4: 10.7.220.59 255.255.255.255, 10.7.220.0 255.255.255.0
- # smtp_username: None
- # mode: set
- # syslog_certificate: None
- # admin_fortiguard_target: None
- # snmpv3_query_port: None
- # smtp_password: None
- # adom: ansible
- # snmpv3_notify_hosts: None
- # syslog_mode: udp
- # snmp_v2c_query_port: 162
- # snmp_v2c_trap_status: enable
- # snmp_status: enable
- # syslog_status: None
- # admin_https_redirect: None
- # admin_fortianalyzer_target: None
- # snmp_v2c_trap_src_ipv4: 10.7.220.41
- # admin_http_port: None
- # dns_secondary_ipv4: None
- # syslog_filter: None
- # snmpv3_source_ip: None
- # snmpv3_trap_rport: None
- # admin_gui_theme: None
- # ntp_sync_interval: None
- # ntp_auth_pwd: None
- # provisioning_template: ansibleTest
- # smtp_replyto: None
- # ntp_auth: None
- # snmp_v2c_trap_port: 161
- # snmpv3_priv_proto: None
- # admin_enable_fortiguard: None
- # dns_primary_ipv4: None
- # admin_language: None
- # smtp_conn_sec: None
- # snmpv3_auth_pwd: None
- # smtp_source_ipv4: None
- # snmpv3_status: None
- # delete_provisioning_template: None
- # snmp_v2c_trap_hosts_ipv4: 10.7.220.59 255.255.255.255, 10.7.220.60 255.255.255.255
- # ntp_v3: None
- ##################################################
- ##################################################
- # snmpv3_security_level: auth-priv
- # snmp_v2c_query_status: None
- # ntp_type: None
- # dns_suffix: None
- # snmpv3_queries: enable
- # snmpv3_trap_status: enable
- # snmp_v2c_name: None
- # syslog_facility: syslog
- # snmp_v2c_status: None
- # smtp_validate_cert: None
- # snmpv3_name: ansibleSNMPv3
- # snmp_v2c_trap_src_ipv4: None
- # syslog_port: None
- # ntp_server: None
- # admin_https_port: None
- # ntp_status: None
- # syslog_server: None
- # dns_primary_ipv4: None
- # admin_timeout: None
- # snmpv3_auth_proto: sha
- # smtp_port: None
- # snmpv3_priv_pwd: fortinet
- # smtp_server: None
- # syslog_enc_algorithm: disable
- # dns_secondary_ipv4: None
- # smtp_username: None
- # snmpv3_auth_pwd: fortinet
- # syslog_certificate: None
- # admin_fortiguard_target: None
- # snmpv3_query_port: 161
- # smtp_password: None
- # adom: ansible
- # snmpv3_notify_hosts: 10.7.220.59,10.7.220.60
- # syslog_mode: udp
- # snmp_v2c_query_port: None
- # snmp_v2c_trap_status: None
- # snmp_status: enable
- # syslog_status: None
- # admin_fortianalyzer_target: None
- # ntp_auth: None
- # snmp_v2c_id: None
- # admin_http_port: None
- # ntp_v3: None
- # snmp_v2c_query_hosts_ipv4: None
- # ntp_sync_interval: None
- # snmpv3_source_ip: 0.0.0.0
- # snmpv3_trap_rport: 162
- # admin_gui_theme: None
- # syslog_filter: None
- # ntp_auth_pwd: None
- # provisioning_template: ansibleTest
- # smtp_replyto: None
- # provision_targets: None
- # snmp_v2c_trap_port: None
- # snmpv3_priv_proto: aes256
- # admin_enable_fortiguard: None
- # admin_switch_controller: None
- # admin_language: None
- # smtp_conn_sec: None
- # mode: set
- # smtp_source_ipv4: None
- # snmpv3_status: enable
- # delete_provisioning_template: None
- # snmp_v2c_trap_hosts_ipv4: None
- # admin_https_redirect: None
- ##################################################
-
- # Test using fixture 1 #
- output = fmgr_device_provision_template.set_devprof_snmp(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 2 #
- output = fmgr_device_provision_template.set_devprof_snmp(fmg_instance, fixture_data[1]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 3 #
- output = fmgr_device_provision_template.set_devprof_snmp(fmg_instance, fixture_data[2]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
-
-
-def test_set_devprof_snmp_v2c(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
- # Fixture sets used:###########################
-
- ##################################################
- # snmpv3_security_level: None
- # snmp_v2c_query_status: enable
- # ntp_type: None
- # dns_suffix: None
- # snmpv3_queries: None
- # snmpv3_trap_status: None
- # snmp_v2c_name: ansibleV2c
- # syslog_facility: syslog
- # snmp_v2c_status: enable
- # smtp_validate_cert: None
- # snmpv3_name: None
- # snmp_v2c_trap_src_ipv4: 10.7.220.41
- # syslog_port: None
- # ntp_server: None
- # admin_https_port: None
- # ntp_status: None
- # syslog_server: None
- # dns_primary_ipv4: None
- # admin_timeout: None
- # snmpv3_auth_proto: None
- # smtp_port: None
- # snmpv3_priv_pwd: None
- # smtp_server: None
- # syslog_enc_algorithm: disable
- # dns_secondary_ipv4: None
- # smtp_replyto: None
- # smtp_username: None
- # snmpv3_auth_pwd: None
- # syslog_certificate: None
- # admin_fortiguard_target: None
- # snmpv3_query_port: None
- # smtp_password: None
- # adom: ansible
- # snmpv3_notify_hosts: None
- # syslog_mode: udp
- # snmp_v2c_query_port: 162
- # snmp_v2c_trap_status: enable
- # snmp_status: enable
- # syslog_status: None
- # admin_fortianalyzer_target: None
- # ntp_auth: None
- # snmp_v2c_id: 1
- # admin_http_port: None
- # snmp_v2c_query_hosts_ipv4: 10.7.220.59 255.255.255.255, 10.7.220.0 255.255.255.0
- # ntp_sync_interval: None
- # snmpv3_source_ip: None
- # snmpv3_trap_rport: None
- # admin_gui_theme: None
- # syslog_filter: None
- # ntp_auth_pwd: None
- # provisioning_template: ansibleTest
- # snmp_v2c_trap_hosts_ipv4: 10.7.220.59 255.255.255.255, 10.7.220.60 255.255.255.255
- # provision_targets: None
- # snmp_v2c_trap_port: 161
- # snmpv3_priv_proto: None
- # admin_enable_fortiguard: None
- # admin_switch_controller: None
- # admin_language: None
- # smtp_conn_sec: None
- # mode: set
- # smtp_source_ipv4: None
- # snmpv3_status: None
- # delete_provisioning_template: None
- # ntp_v3: None
- # admin_https_redirect: None
- ##################################################
-
- # Test using fixture 1 #
- output = fmgr_device_provision_template.set_devprof_snmp_v2c(fmg_instance, fixture_data[0]['paramgram_used'])
- assert isinstance(output['raw_response'], dict) is True
-
-
-def test_set_devprof_snmp_v3(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
- # Fixture sets used:###########################
-
- ##################################################
- # snmpv3_security_level: auth-priv
- # snmp_v2c_query_status: None
- # provision_targets: None
- # ntp_type: None
- # dns_suffix: None
- # snmpv3_queries: enable
- # snmpv3_trap_status: enable
- # snmp_v2c_name: None
- # syslog_facility: syslog
- # snmp_v2c_status: None
- # smtp_validate_cert: None
- # snmpv3_name: ansibleSNMPv3
- # snmp_v2c_id: None
- # syslog_port: None
- # ntp_server: None
- # admin_https_port: None
- # ntp_status: None
- # syslog_server: None
- # admin_switch_controller: None
- # admin_timeout: None
- # snmpv3_auth_proto: sha
- # smtp_port: None
- # snmpv3_priv_pwd: fortinet
- # smtp_server: None
- # syslog_enc_algorithm: disable
- # snmp_v2c_query_hosts_ipv4: None
- # smtp_username: None
- # mode: set
- # syslog_certificate: None
- # admin_fortiguard_target: None
- # snmpv3_query_port: 161
- # smtp_password: None
- # adom: ansible
- # snmpv3_notify_hosts: 10.7.220.59,10.7.220.60
- # syslog_mode: udp
- # snmp_v2c_query_port: None
- # snmp_v2c_trap_status: None
- # snmp_status: enable
- # syslog_status: None
- # admin_https_redirect: None
- # admin_fortianalyzer_target: None
- # snmp_v2c_trap_src_ipv4: None
- # admin_http_port: None
- # dns_secondary_ipv4: None
- # syslog_filter: None
- # snmpv3_source_ip: 0.0.0.0
- # snmpv3_trap_rport: 162
- # admin_gui_theme: None
- # ntp_sync_interval: None
- # ntp_auth_pwd: None
- # provisioning_template: ansibleTest
- # smtp_replyto: None
- # ntp_auth: None
- # snmp_v2c_trap_port: None
- # snmpv3_priv_proto: aes256
- # admin_enable_fortiguard: None
- # dns_primary_ipv4: None
- # admin_language: None
- # smtp_conn_sec: None
- # snmpv3_auth_pwd: fortinet
- # smtp_source_ipv4: None
- # snmpv3_status: enable
- # delete_provisioning_template: None
- # snmp_v2c_trap_hosts_ipv4: None
- # ntp_v3: None
- ##################################################
-
- # Test using fixture 1 #
- output = fmgr_device_provision_template.set_devprof_snmp_v3(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
-
-
-def test_set_devprof_syslog(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
- # Fixture sets used:###########################
-
- ##################################################
- # snmpv3_security_level: None
- # snmp_v2c_query_status: None
- # provision_targets: None
- # ntp_type: None
- # dns_suffix: None
- # snmpv3_queries: None
- # snmpv3_trap_status: None
- # snmp_v2c_name: None
- # syslog_facility: kernel
- # snmp_v2c_status: None
- # smtp_validate_cert: None
- # snmpv3_name: None
- # snmp_v2c_id: None
- # syslog_port: 514
- # ntp_server: None
- # admin_https_port: None
- # ntp_status: None
- # syslog_server: 10.7.220.59
- # admin_switch_controller: None
- # admin_timeout: None
- # snmpv3_auth_proto: None
- # smtp_port: None
- # snmpv3_priv_pwd: None
- # smtp_server: None
- # syslog_enc_algorithm: disable
- # snmp_v2c_query_hosts_ipv4: None
- # smtp_username: None
- # mode: set
- # syslog_certificate: None
- # admin_fortiguard_target: None
- # snmpv3_query_port: None
- # smtp_password: None
- # adom: ansible
- # snmpv3_notify_hosts: None
- # syslog_mode: udp
- # snmp_v2c_query_port: None
- # snmp_v2c_trap_status: None
- # snmp_status: None
- # syslog_status: enable
- # snmp_v2c_trap_hosts_ipv4: None
- # admin_fortianalyzer_target: None
- # snmp_v2c_trap_src_ipv4: None
- # admin_http_port: None
- # dns_secondary_ipv4: None
- # syslog_filter: critical
- # snmpv3_source_ip: None
- # snmpv3_trap_rport: None
- # admin_gui_theme: None
- # ntp_sync_interval: None
- # ntp_auth_pwd: None
- # provisioning_template: ansibleTest
- # ntp_v3: None
- # ntp_auth: None
- # snmp_v2c_trap_port: None
- # snmpv3_priv_proto: None
- # admin_enable_fortiguard: None
- # dns_primary_ipv4: None
- # admin_language: None
- # smtp_conn_sec: None
- # snmpv3_auth_pwd: None
- # smtp_source_ipv4: None
- # snmpv3_status: None
- # delete_provisioning_template: None
- # smtp_replyto: None
- # admin_https_redirect: None
- ##################################################
-
- # Test using fixture 1 #
- output = fmgr_device_provision_template.set_devprof_syslog(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
-
-
-def test_set_devprof_ntp(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
- # Fixture sets used:###########################
-
- ##################################################
- # snmpv3_security_level: None
- # snmp_v2c_query_status: None
- # provision_targets: None
- # ntp_type: fortiguard
- # dns_suffix: None
- # snmpv3_queries: None
- # snmpv3_trap_status: None
- # snmp_v2c_name: None
- # syslog_facility: syslog
- # snmp_v2c_status: None
- # smtp_validate_cert: None
- # snmpv3_name: None
- # snmp_v2c_id: None
- # syslog_port: None
- # ntp_server: None
- # admin_https_port: None
- # ntp_status: enable
- # syslog_server: None
- # admin_switch_controller: None
- # admin_timeout: None
- # snmpv3_auth_proto: None
- # smtp_port: None
- # snmpv3_priv_pwd: None
- # smtp_server: None
- # syslog_enc_algorithm: disable
- # snmp_v2c_query_hosts_ipv4: None
- # smtp_username: None
- # mode: set
- # syslog_certificate: None
- # admin_fortiguard_target: None
- # snmpv3_query_port: None
- # smtp_password: None
- # adom: ansible
- # snmpv3_notify_hosts: None
- # syslog_mode: udp
- # snmp_v2c_query_port: None
- # snmp_v2c_trap_status: None
- # snmp_status: None
- # syslog_status: None
- # snmp_v2c_trap_hosts_ipv4: None
- # admin_fortianalyzer_target: None
- # snmp_v2c_trap_src_ipv4: None
- # admin_http_port: None
- # dns_secondary_ipv4: None
- # syslog_filter: None
- # snmpv3_source_ip: None
- # snmpv3_trap_rport: None
- # admin_gui_theme: None
- # ntp_sync_interval: 60
- # ntp_auth_pwd: None
- # provisioning_template: ansibleTest
- # ntp_v3: None
- # ntp_auth: None
- # snmp_v2c_trap_port: None
- # snmpv3_priv_proto: None
- # admin_enable_fortiguard: None
- # dns_primary_ipv4: None
- # admin_language: None
- # smtp_conn_sec: None
- # snmpv3_auth_pwd: None
- # smtp_source_ipv4: None
- # snmpv3_status: None
- # delete_provisioning_template: None
- # smtp_replyto: None
- # admin_https_redirect: None
- ##################################################
- ##################################################
- # snmpv3_security_level: None
- # snmp_v2c_query_status: None
- # provision_targets: None
- # ntp_type: custom
- # dns_suffix: None
- # snmpv3_queries: None
- # snmpv3_trap_status: None
- # snmp_v2c_name: None
- # syslog_facility: syslog
- # snmp_v2c_status: None
- # smtp_validate_cert: None
- # snmpv3_name: None
- # snmp_v2c_id: None
- # syslog_port: None
- # ntp_server: 10.7.220.32,10.7.220.1
- # admin_https_port: None
- # ntp_status: enable
- # syslog_server: None
- # admin_switch_controller: None
- # admin_timeout: None
- # snmpv3_auth_proto: None
- # smtp_port: None
- # snmpv3_priv_pwd: None
- # smtp_server: None
- # syslog_enc_algorithm: disable
- # snmp_v2c_query_hosts_ipv4: None
- # smtp_username: None
- # mode: set
- # syslog_certificate: None
- # admin_fortiguard_target: None
- # snmpv3_query_port: None
- # smtp_password: None
- # adom: ansible
- # snmpv3_notify_hosts: None
- # syslog_mode: udp
- # snmp_v2c_query_port: None
- # snmp_v2c_trap_status: None
- # snmp_status: None
- # syslog_status: None
- # admin_https_redirect: None
- # admin_fortianalyzer_target: None
- # snmp_v2c_trap_src_ipv4: None
- # admin_http_port: None
- # dns_secondary_ipv4: None
- # syslog_filter: None
- # snmpv3_source_ip: None
- # snmpv3_trap_rport: None
- # admin_gui_theme: None
- # ntp_sync_interval: 60
- # ntp_auth_pwd: fortinet
- # provisioning_template: ansibleTest
- # smtp_replyto: None
- # ntp_auth: enable
- # snmp_v2c_trap_port: None
- # snmpv3_priv_proto: None
- # admin_enable_fortiguard: None
- # dns_primary_ipv4: None
- # admin_language: None
- # smtp_conn_sec: None
- # snmpv3_auth_pwd: None
- # smtp_source_ipv4: None
- # snmpv3_status: None
- # delete_provisioning_template: None
- # snmp_v2c_trap_hosts_ipv4: None
- # ntp_v3: None
- ##################################################
-
- # Test using fixture 1 #
- output = fmgr_device_provision_template.set_devprof_ntp(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 2 #
- output = fmgr_device_provision_template.set_devprof_ntp(fmg_instance, fixture_data[1]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
-
-
-def test_set_devprof_admin(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
- # Fixture sets used:###########################
-
- ##################################################
- # snmpv3_security_level: None
- # snmp_v2c_query_status: None
- # provision_targets: None
- # ntp_type: None
- # dns_suffix: None
- # snmpv3_queries: None
- # snmpv3_trap_status: None
- # snmp_v2c_name: None
- # syslog_facility: syslog
- # snmp_v2c_status: None
- # smtp_validate_cert: None
- # snmpv3_name: None
- # snmp_v2c_id: None
- # syslog_port: None
- # ntp_server: None
- # admin_https_port: 4433
- # ntp_status: None
- # syslog_server: None
- # admin_switch_controller: enable
- # admin_timeout: 60
- # snmpv3_auth_proto: None
- # smtp_port: None
- # snmpv3_priv_pwd: None
- # smtp_server: None
- # syslog_enc_algorithm: disable
- # snmp_v2c_query_hosts_ipv4: None
- # smtp_username: None
- # mode: set
- # syslog_certificate: None
- # admin_fortiguard_target: None
- # snmpv3_query_port: None
- # smtp_password: None
- # adom: ansible
- # snmpv3_notify_hosts: None
- # syslog_mode: udp
- # snmp_v2c_query_port: None
- # snmp_v2c_trap_status: None
- # snmp_status: None
- # syslog_status: None
- # snmp_v2c_trap_hosts_ipv4: None
- # admin_fortianalyzer_target: 10.7.220.38
- # snmp_v2c_trap_src_ipv4: None
- # admin_http_port: 8080
- # dns_secondary_ipv4: None
- # syslog_filter: None
- # snmpv3_source_ip: None
- # snmpv3_trap_rport: None
- # admin_gui_theme: blue
- # ntp_sync_interval: None
- # ntp_auth_pwd: None
- # provisioning_template: ansibleTest
- # ntp_v3: None
- # ntp_auth: None
- # snmp_v2c_trap_port: None
- # snmpv3_priv_proto: None
- # admin_enable_fortiguard: this-fmg
- # dns_primary_ipv4: None
- # admin_language: english
- # smtp_conn_sec: None
- # snmpv3_auth_pwd: None
- # smtp_source_ipv4: None
- # snmpv3_status: None
- # delete_provisioning_template: None
- # smtp_replyto: None
- # admin_https_redirect: enable
- ##################################################
-
- # Test using fixture 1 #
- output = fmgr_device_provision_template.set_devprof_admin(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
-
-
-def test_set_devprof_smtp(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
- # Fixture sets used:###########################
-
- ##################################################
- # snmpv3_security_level: None
- # snmp_v2c_query_status: None
- # provision_targets: None
- # ntp_type: None
- # dns_suffix: None
- # snmpv3_queries: None
- # snmpv3_trap_status: None
- # snmp_v2c_name: None
- # syslog_facility: syslog
- # snmp_v2c_status: None
- # smtp_validate_cert: disable
- # snmpv3_name: None
- # snmp_v2c_id: None
- # syslog_port: None
- # ntp_server: None
- # admin_https_port: None
- # ntp_status: None
- # syslog_server: None
- # admin_switch_controller: None
- # admin_timeout: None
- # snmpv3_auth_proto: None
- # smtp_port: 25
- # snmpv3_priv_pwd: None
- # smtp_server: 10.7.220.32
- # syslog_enc_algorithm: disable
- # snmp_v2c_query_hosts_ipv4: None
- # smtp_username: ansible
- # mode: set
- # syslog_certificate: None
- # admin_fortiguard_target: None
- # snmpv3_query_port: None
- # smtp_password: fortinet
- # adom: ansible
- # snmpv3_notify_hosts: None
- # syslog_mode: udp
- # snmp_v2c_query_port: None
- # snmp_v2c_trap_status: None
- # snmp_status: None
- # syslog_status: None
- # admin_https_redirect: None
- # admin_fortianalyzer_target: None
- # snmp_v2c_trap_src_ipv4: None
- # admin_http_port: None
- # dns_secondary_ipv4: None
- # syslog_filter: None
- # snmpv3_source_ip: None
- # snmpv3_trap_rport: None
- # admin_gui_theme: None
- # ntp_sync_interval: None
- # ntp_auth_pwd: None
- # provisioning_template: ansibleTest
- # smtp_replyto: ansible@do-not-reply.com
- # ntp_auth: None
- # snmp_v2c_trap_port: None
- # snmpv3_priv_proto: None
- # admin_enable_fortiguard: None
- # dns_primary_ipv4: None
- # admin_language: None
- # smtp_conn_sec: starttls
- # snmpv3_auth_pwd: None
- # smtp_source_ipv4: 0.0.0.0
- # snmpv3_status: None
- # delete_provisioning_template: None
- # snmp_v2c_trap_hosts_ipv4: None
- # ntp_v3: None
- ##################################################
-
- # Test using fixture 1 #
- output = fmgr_device_provision_template.set_devprof_smtp(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
-
-
-def test_set_devprof_dns(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
- # Fixture sets used:###########################
-
- ##################################################
- # snmpv3_security_level: None
- # snmp_v2c_query_status: None
- # provision_targets: None
- # ntp_type: None
- # dns_suffix: ansible.local
- # snmpv3_queries: None
- # snmpv3_trap_status: None
- # snmp_v2c_name: None
- # syslog_facility: syslog
- # snmp_v2c_status: None
- # smtp_validate_cert: None
- # snmpv3_name: None
- # snmp_v2c_id: None
- # syslog_port: None
- # ntp_server: None
- # admin_https_port: None
- # ntp_status: None
- # syslog_server: None
- # admin_switch_controller: None
- # admin_timeout: None
- # snmpv3_auth_proto: None
- # smtp_port: None
- # snmpv3_priv_pwd: None
- # smtp_server: None
- # syslog_enc_algorithm: disable
- # snmp_v2c_query_hosts_ipv4: None
- # smtp_username: None
- # mode: set
- # syslog_certificate: None
- # admin_fortiguard_target: None
- # snmpv3_query_port: None
- # smtp_password: None
- # adom: ansible
- # snmpv3_notify_hosts: None
- # syslog_mode: udp
- # snmp_v2c_query_port: None
- # snmp_v2c_trap_status: None
- # snmp_status: None
- # syslog_status: None
- # snmp_v2c_trap_hosts_ipv4: None
- # admin_fortianalyzer_target: None
- # snmp_v2c_trap_src_ipv4: None
- # admin_http_port: None
- # dns_secondary_ipv4: 4.4.4.4
- # syslog_filter: None
- # snmpv3_source_ip: None
- # snmpv3_trap_rport: None
- # admin_gui_theme: None
- # ntp_sync_interval: None
- # ntp_auth_pwd: None
- # provisioning_template: ansibleTest
- # ntp_v3: None
- # ntp_auth: None
- # snmp_v2c_trap_port: None
- # snmpv3_priv_proto: None
- # admin_enable_fortiguard: None
- # dns_primary_ipv4: 8.8.8.8
- # admin_language: None
- # smtp_conn_sec: None
- # snmpv3_auth_pwd: None
- # smtp_source_ipv4: None
- # snmpv3_status: None
- # delete_provisioning_template: None
- # smtp_replyto: None
- # admin_https_redirect: None
- ##################################################
-
- # Test using fixture 1 #
- output = fmgr_device_provision_template.set_devprof_dns(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwobj_address.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwobj_address.py
deleted file mode 100644
index 97d4a3f00..000000000
--- a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwobj_address.py
+++ /dev/null
@@ -1,156 +0,0 @@
-# Copyright 2018 Fortinet, Inc.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import os
-import json
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-import pytest
-
-try:
- from ansible_collections.community.fortios.plugins.modules import fmgr_fwobj_address
-except ImportError:
- pytest.skip("Could not load required modules for testing", allow_module_level=True)
-
-
-def load_fixtures():
- fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format(
- filename=os.path.splitext(os.path.basename(__file__))[0])
- try:
- with open(fixture_path, "r") as fixture_file:
- fixture_data = json.load(fixture_file)
- except IOError:
- return []
- return [fixture_data]
-
-
-@pytest.fixture(autouse=True)
-def module_mock(mocker):
- connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule')
- return connection_class_mock
-
-
-@pytest.fixture(autouse=True)
-def connection_mock(mocker):
- connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_fwobj_address.Connection')
- return connection_class_mock
-
-
-@pytest.fixture(scope="function", params=load_fixtures())
-def fixture_data(request):
- func_name = request.function.__name__.replace("test_", "")
- return request.param.get(func_name, None)
-
-
-fmg_instance = FortiManagerHandler(connection_mock, module_mock)
-
-
-def test_fmgr_fwobj_ipv4(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
-
- # Test using fixture 1 #
- output = fmgr_fwobj_address.fmgr_fwobj_ipv4(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == -3
- # Test using fixture 2 #
- output = fmgr_fwobj_address.fmgr_fwobj_ipv4(fmg_instance, fixture_data[1]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 3 #
- output = fmgr_fwobj_address.fmgr_fwobj_ipv4(fmg_instance, fixture_data[2]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 4 #
- output = fmgr_fwobj_address.fmgr_fwobj_ipv4(fmg_instance, fixture_data[3]['paramgram_used'])
- assert output['raw_response']['status']['code'] == -3
- # Test using fixture 5 #
- output = fmgr_fwobj_address.fmgr_fwobj_ipv4(fmg_instance, fixture_data[4]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 6 #
- output = fmgr_fwobj_address.fmgr_fwobj_ipv4(fmg_instance, fixture_data[5]['paramgram_used'])
- assert output['raw_response']['status']['code'] == -3
- # Test using fixture 7 #
- output = fmgr_fwobj_address.fmgr_fwobj_ipv4(fmg_instance, fixture_data[6]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 8 #
- output = fmgr_fwobj_address.fmgr_fwobj_ipv4(fmg_instance, fixture_data[7]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 9 #
- output = fmgr_fwobj_address.fmgr_fwobj_ipv4(fmg_instance, fixture_data[8]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 10 #
- output = fmgr_fwobj_address.fmgr_fwobj_ipv4(fmg_instance, fixture_data[9]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 11 #
- output = fmgr_fwobj_address.fmgr_fwobj_ipv4(fmg_instance, fixture_data[10]['paramgram_used'])
- assert output['raw_response']['status']['code'] == -3
- # Test using fixture 12 #
- output = fmgr_fwobj_address.fmgr_fwobj_ipv4(fmg_instance, fixture_data[11]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 13 #
- output = fmgr_fwobj_address.fmgr_fwobj_ipv4(fmg_instance, fixture_data[12]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 14 #
- output = fmgr_fwobj_address.fmgr_fwobj_ipv4(fmg_instance, fixture_data[13]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 15 #
- output = fmgr_fwobj_address.fmgr_fwobj_ipv4(fmg_instance, fixture_data[14]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 16 #
- output = fmgr_fwobj_address.fmgr_fwobj_ipv4(fmg_instance, fixture_data[15]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 17 #
- output = fmgr_fwobj_address.fmgr_fwobj_ipv4(fmg_instance, fixture_data[16]['paramgram_used'])
- assert output['raw_response']['status']['code'] == -3
- # Test using fixture 18 #
- output = fmgr_fwobj_address.fmgr_fwobj_ipv4(fmg_instance, fixture_data[17]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
-
-
-def test_fmgr_fwobj_ipv6(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
-
- # Test using fixture 1 #
- output = fmgr_fwobj_address.fmgr_fwobj_ipv6(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == -3
- # Test using fixture 2 #
- output = fmgr_fwobj_address.fmgr_fwobj_ipv6(fmg_instance, fixture_data[1]['paramgram_used'])
- assert output['raw_response']['status']['code'] == -3
- # Test using fixture 3 #
- output = fmgr_fwobj_address.fmgr_fwobj_ipv6(fmg_instance, fixture_data[2]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 4 #
- output = fmgr_fwobj_address.fmgr_fwobj_ipv6(fmg_instance, fixture_data[3]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 5 #
- output = fmgr_fwobj_address.fmgr_fwobj_ipv6(fmg_instance, fixture_data[4]['paramgram_used'])
- assert output['raw_response']['status']['code'] == -10131
-
-
-def test_fmgr_fwobj_multicast(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
-
- # Test using fixture 1 #
- output = fmgr_fwobj_address.fmgr_fwobj_multicast(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 2 #
- output = fmgr_fwobj_address.fmgr_fwobj_multicast(fmg_instance, fixture_data[1]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 3 #
- output = fmgr_fwobj_address.fmgr_fwobj_multicast(fmg_instance, fixture_data[2]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwobj_ippool.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwobj_ippool.py
deleted file mode 100644
index 399fc4c8d..000000000
--- a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwobj_ippool.py
+++ /dev/null
@@ -1,90 +0,0 @@
-# Copyright 2018 Fortinet, Inc.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import os
-import json
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-import pytest
-
-try:
- from ansible_collections.community.fortios.plugins.modules import fmgr_fwobj_ippool
-except ImportError:
- pytest.skip("Could not load required modules for testing", allow_module_level=True)
-
-
-def load_fixtures():
- fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format(
- filename=os.path.splitext(os.path.basename(__file__))[0])
- try:
- with open(fixture_path, "r") as fixture_file:
- fixture_data = json.load(fixture_file)
- except IOError:
- return []
- return [fixture_data]
-
-
-@pytest.fixture(autouse=True)
-def module_mock(mocker):
- connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule')
- return connection_class_mock
-
-
-@pytest.fixture(autouse=True)
-def connection_mock(mocker):
- connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_fwobj_ippool.Connection')
- return connection_class_mock
-
-
-@pytest.fixture(scope="function", params=load_fixtures())
-def fixture_data(request):
- func_name = request.function.__name__.replace("test_", "")
- return request.param.get(func_name, None)
-
-
-fmg_instance = FortiManagerHandler(connection_mock, module_mock)
-
-
-def test_fmgr_fwobj_ippool_modify(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
-
- # Test using fixture 1 #
- output = fmgr_fwobj_ippool.fmgr_fwobj_ippool_modify(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 2 #
- output = fmgr_fwobj_ippool.fmgr_fwobj_ippool_modify(fmg_instance, fixture_data[1]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 3 #
- output = fmgr_fwobj_ippool.fmgr_fwobj_ippool_modify(fmg_instance, fixture_data[2]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 4 #
- output = fmgr_fwobj_ippool.fmgr_fwobj_ippool_modify(fmg_instance, fixture_data[3]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 5 #
- output = fmgr_fwobj_ippool.fmgr_fwobj_ippool_modify(fmg_instance, fixture_data[4]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 6 #
- output = fmgr_fwobj_ippool.fmgr_fwobj_ippool_modify(fmg_instance, fixture_data[5]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 7 #
- output = fmgr_fwobj_ippool.fmgr_fwobj_ippool_modify(fmg_instance, fixture_data[6]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 8 #
- output = fmgr_fwobj_ippool.fmgr_fwobj_ippool_modify(fmg_instance, fixture_data[7]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwobj_ippool6.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwobj_ippool6.py
deleted file mode 100644
index 04877ff5d..000000000
--- a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwobj_ippool6.py
+++ /dev/null
@@ -1,72 +0,0 @@
-# Copyright 2018 Fortinet, Inc.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import os
-import json
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-import pytest
-
-try:
- from ansible_collections.community.fortios.plugins.modules import fmgr_fwobj_ippool6
-except ImportError:
- pytest.skip("Could not load required modules for testing", allow_module_level=True)
-
-
-def load_fixtures():
- fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format(
- filename=os.path.splitext(os.path.basename(__file__))[0])
- try:
- with open(fixture_path, "r") as fixture_file:
- fixture_data = json.load(fixture_file)
- except IOError:
- return []
- return [fixture_data]
-
-
-@pytest.fixture(autouse=True)
-def module_mock(mocker):
- connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule')
- return connection_class_mock
-
-
-@pytest.fixture(autouse=True)
-def connection_mock(mocker):
- connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_fwobj_ippool6.Connection')
- return connection_class_mock
-
-
-@pytest.fixture(scope="function", params=load_fixtures())
-def fixture_data(request):
- func_name = request.function.__name__.replace("test_", "")
- return request.param.get(func_name, None)
-
-
-fmg_instance = FortiManagerHandler(connection_mock, module_mock)
-
-
-def test_fmgr_fwobj_ippool6_modify(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
-
- # Test using fixture 1 #
- output = fmgr_fwobj_ippool6.fmgr_fwobj_ippool6_modify(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 2 #
- output = fmgr_fwobj_ippool6.fmgr_fwobj_ippool6_modify(fmg_instance, fixture_data[1]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwobj_service.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwobj_service.py
deleted file mode 100644
index 57edff901..000000000
--- a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwobj_service.py
+++ /dev/null
@@ -1,123 +0,0 @@
-# Copyright 2018 Fortinet, Inc.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import os
-import json
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-import pytest
-
-try:
- from ansible_collections.community.fortios.plugins.modules import fmgr_fwobj_service
-except ImportError:
- pytest.skip("Could not load required modules for testing", allow_module_level=True)
-
-
-def load_fixtures():
- fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format(
- filename=os.path.splitext(os.path.basename(__file__))[0])
- try:
- with open(fixture_path, "r") as fixture_file:
- fixture_data = json.load(fixture_file)
- except IOError:
- return []
- return [fixture_data]
-
-
-@pytest.fixture(autouse=True)
-def module_mock(mocker):
- connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule')
- return connection_class_mock
-
-
-@pytest.fixture(autouse=True)
-def connection_mock(mocker):
- connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_fwobj_service.Connection')
- return connection_class_mock
-
-
-@pytest.fixture(scope="function", params=load_fixtures())
-def fixture_data(request):
- func_name = request.function.__name__.replace("test_", "")
- return request.param.get(func_name, None)
-
-
-fmg_instance = FortiManagerHandler(connection_mock, module_mock)
-
-
-def test_fmgr_fwobj_service_custom(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
-
- # Test using fixture 1 #
- output = fmgr_fwobj_service.fmgr_fwobj_service_custom(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 2 #
- output = fmgr_fwobj_service.fmgr_fwobj_service_custom(fmg_instance, fixture_data[1]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 3 #
- output = fmgr_fwobj_service.fmgr_fwobj_service_custom(fmg_instance, fixture_data[2]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 4 #
- output = fmgr_fwobj_service.fmgr_fwobj_service_custom(fmg_instance, fixture_data[3]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 5 #
- output = fmgr_fwobj_service.fmgr_fwobj_service_custom(fmg_instance, fixture_data[4]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 6 #
- output = fmgr_fwobj_service.fmgr_fwobj_service_custom(fmg_instance, fixture_data[5]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 7 #
- output = fmgr_fwobj_service.fmgr_fwobj_service_custom(fmg_instance, fixture_data[6]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 8 #
- output = fmgr_fwobj_service.fmgr_fwobj_service_custom(fmg_instance, fixture_data[7]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 9 #
- output = fmgr_fwobj_service.fmgr_fwobj_service_custom(fmg_instance, fixture_data[8]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 10 #
- output = fmgr_fwobj_service.fmgr_fwobj_service_custom(fmg_instance, fixture_data[9]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 11 #
- output = fmgr_fwobj_service.fmgr_fwobj_service_custom(fmg_instance, fixture_data[10]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 12 #
- output = fmgr_fwobj_service.fmgr_fwobj_service_custom(fmg_instance, fixture_data[11]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
-
-
-def test_fmgr_fwobj_service_group(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
-
- # Test using fixture 1 #
- output = fmgr_fwobj_service.fmgr_fwobj_service_group(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == -3
- # Test using fixture 2 #
- output = fmgr_fwobj_service.fmgr_fwobj_service_group(fmg_instance, fixture_data[1]['paramgram_used'])
- assert output['raw_response']['status']['code'] == -10131
-
-
-def test_fmgr_fwobj_service_category(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
-
- # Test using fixture 1 #
- output = fmgr_fwobj_service.fmgr_fwobj_service_category(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == -2
diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwobj_vip.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwobj_vip.py
deleted file mode 100644
index c8dbfc775..000000000
--- a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwobj_vip.py
+++ /dev/null
@@ -1,785 +0,0 @@
-# Copyright 2018 Fortinet, Inc.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import os
-import json
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-import pytest
-
-try:
- from ansible_collections.community.fortios.plugins.modules import fmgr_fwobj_vip
-except ImportError:
- pytest.skip("Could not load required modules for testing", allow_module_level=True)
-
-
-def load_fixtures():
- fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format(
- filename=os.path.splitext(os.path.basename(__file__))[0])
- try:
- with open(fixture_path, "r") as fixture_file:
- fixture_data = json.load(fixture_file)
- except IOError:
- return []
- return [fixture_data]
-
-
-@pytest.fixture(autouse=True)
-def module_mock(mocker):
- connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule')
- return connection_class_mock
-
-
-@pytest.fixture(autouse=True)
-def connection_mock(mocker):
- connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_fwobj_vip.Connection')
- return connection_class_mock
-
-
-@pytest.fixture(scope="function", params=load_fixtures())
-def fixture_data(request):
- func_name = request.function.__name__.replace("test_", "")
- return request.param.get(func_name, None)
-
-
-fmg_instance = FortiManagerHandler(connection_mock, module_mock)
-
-
-def test_fmgr_firewall_vip_modify(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
- # Fixture sets used:###########################
-
- ##################################################
- # comment: Created by Ansible
- # ssl-send-empty-frags: None
- # srcintf-filter: None
- # ssl-max-version: None
- # ssl-server-session-state-max: None
- # ssl-hpkp: None
- # mapped-addr: None
- # ssl-client-session-state-timeout: None
- # src-filter: None
- # server-type: None
- # ssl-hpkp-include-subdomains: None
- # ssl-http-location-conversion: None
- # https-cookie-secure: None
- # mappedip: 10.7.220.25
- # ssl-server-cipher-suites: {'priority': None, 'cipher': None, 'versions': None}
- # protocol: tcp
- # ssl-hpkp-backup: None
- # ssl-dh-bits: None
- # dns-mapping-ttl: None
- # ssl-hsts-age: None
- # extaddr: None
- # ssl-client-renegotiation: None
- # monitor: None
- # service: None
- # ssl-hpkp-age: None
- # http-cookie-age: None
- # weblogic-server: None
- # http-cookie-share: None
- # color: 17
- # ssl-mode: None
- # portforward: enable
- # http-multiplex: None
- # http-cookie-generation: None
- # ssl-client-fallback: None
- # extip: 82.72.192.185
- # extintf: any
- # persistence: None
- # websphere-server: None
- # nat-source-vip: None
- # portmapping-type: None
-
- # adom: ansible
- # ssl-client-session-state-max: None
- # http-ip-header: None
- # http-ip-header-name: None
- # ssl-certificate: None
- # ssl-hsts: None
- # arp-reply: None
- # ssl-hsts-include-subdomains: None
- # ssl-min-version: None
- # ldb-method: None
- # ssl-server-session-state-timeout: None
- # ssl-server-min-version: None
- # http-cookie-domain: None
- # mappedport: 443
- # name: Basic PNAT Map Port 10443
- # ssl-cipher-suites: {'cipher': None, 'versions': None}
- # ssl-hpkp-primary: None
- # outlook-web-access: None
- # ssl-server-session-state-type: None
- # ssl-client-session-state-type: None
-
- # ssl-http-match-host: None
-
- # ssl-server-max-version: None
- # ssl-hpkp-report-uri: None
- # http-cookie-domain-from-host: None
- # ssl-algorithm: None
- # gratuitous-arp-interval: None
- # extport: 10443
- # max-embryonic-connections: None
- # mode: set
- # http-cookie-path: None
- # ssl-pfs: None
- # ssl-server-algorithm: None
- ##################################################
- ##################################################
- # comment: Created by Ansible
- # ssl-send-empty-frags: None
- # srcintf-filter: None
- # ssl-max-version: None
- # ssl-server-session-state-max: None
- # ssl-hpkp: None
- # ssl-hsts-include-subdomains: None
- # mapped-addr: None
- # src-filter: None
- # server-type: None
- # mode: set
- # ssl-hpkp-include-subdomains: None
- # ssl-http-location-conversion: None
- # https-cookie-secure: None
- # mappedip: 3.3.3.0/24, 4.0.0.0/24
- # ssl-server-cipher-suites: {'priority': None, 'cipher': None, 'versions': None}
- # protocol: None
- # ssl-hpkp-backup: None
- # ssl-dh-bits: None
- # dns-mapping-ttl: None
- # ssl-hsts-age: None
- # ssl-client-renegotiation: None
- # monitor: None
- # service: None
- # ssl-hpkp-age: None
- # http-cookie-age: None
- # adom: ansible
- # http-cookie-share: None
- # ssl-server-session-state-timeout: None
- # color: 12
- # ssl-mode: None
- # portforward: None
- # http-cookie-generation: None
- # max-embryonic-connections: None
- # ssl-client-fallback: None
- # ssl-hpkp-report-uri: None
- # extip: 192.168.0.1-192.168.0.100
- # extintf: dmz
- # persistence: None
- # websphere-server: None
- # nat-source-vip: None
- # portmapping-type: None
- # http-ip-header-name: None
- # weblogic-server: None
- # ssl-client-session-state-max: None
- # http-ip-header: None
-
- # ssl-hsts: None
- # arp-reply: None
- # extaddr: None
- # ssl-min-version: None
- # ldb-method: None
- # ssl-certificate: None
- # ssl-server-min-version: None
- # http-cookie-domain: None
- # mappedport: None
- # outlook-web-access: None
- # ssl-cipher-suites: {'cipher': None, 'versions': None}
- # ssl-hpkp-primary: None
- # name: Basic DNS Translation
- # ssl-server-session-state-type: None
- # ssl-client-session-state-type: None
-
- # ssl-http-match-host: None
-
- # ssl-pfs: None
- # ssl-server-max-version: None
- # ssl-client-session-state-timeout: None
- # http-cookie-domain-from-host: None
- # extport: None
- # ssl-server-algorithm: None
- # gratuitous-arp-interval: None
- # http-cookie-path: None
- # ssl-algorithm: None
- # http-multiplex: None
- ##################################################
- ##################################################
- # comment: Created by Ansible
- # ssl-send-empty-frags: None
- # srcintf-filter: None
- # ssl-max-version: None
- # ssl-server-session-state-max: None
- # ssl-hpkp: None
- # mapped-addr: google-play
- # ssl-client-session-state-timeout: None
- # src-filter: None
- # ldb-method: None
- # server-type: None
- # ssl-hpkp-include-subdomains: None
- # ssl-client-renegotiation: None
- # ssl-http-location-conversion: None
- # https-cookie-secure: None
- # mappedip: None
- # ssl-server-cipher-suites: {'priority': None, 'cipher': None, 'versions': None}
- # protocol: None
- # ssl-hpkp-backup: None
- # ssl-dh-bits: None
- # dns-mapping-ttl: None
- # ssl-hsts-age: None
- # extaddr: None
- # monitor: None
- # service: None
- # ssl-hpkp-age: None
- # http-cookie-age: None
- # weblogic-server: None
- # http-cookie-share: None
- # color: 5
- # ssl-mode: None
- # portforward: None
- # http-cookie-generation: None
- # ssl-client-fallback: None
- # extip: None
- # extintf: None
- # persistence: None
- # websphere-server: None
- # nat-source-vip: None
- # portmapping-type: None
-
- # adom: ansible
- # ssl-client-session-state-max: None
- # http-ip-header: None
- # http-ip-header-name: None
- # ssl-certificate: None
- # ssl-hsts: None
- # arp-reply: None
- # extport: None
- # ssl-min-version: None
- # ssl-server-algorithm: None
- # ssl-server-session-state-timeout: None
- # ssl-server-min-version: None
- # http-cookie-domain: None
- # mappedport: None
- # name: Basic FQDN Translation
- # ssl-cipher-suites: {'cipher': None, 'versions': None}
- # ssl-hpkp-primary: None
- # outlook-web-access: None
- # ssl-server-session-state-type: None
- # ssl-client-session-state-type: None
-
- # ssl-http-match-host: None
-
- # ssl-server-max-version: None
- # ssl-hpkp-report-uri: None
- # http-cookie-domain-from-host: None
- # ssl-algorithm: None
- # gratuitous-arp-interval: None
- # ssl-hsts-include-subdomains: None
- # max-embryonic-connections: None
- # mode: set
- # http-cookie-path: None
- # ssl-pfs: None
- # http-multiplex: None
- ##################################################
- ##################################################
- # comment: Created by Ansible
- # ssl-send-empty-frags: None
- # srcintf-filter: None
- # ssl-max-version: None
- # ssl-server-session-state-max: None
- # ssl-hpkp: None
- # mapped-addr: None
- # src-filter: None
- # server-type: None
- # mode: set
- # ssl-hpkp-include-subdomains: None
- # extport: None
- # ssl-http-location-conversion: None
- # https-cookie-secure: None
- # mappedip: 10.7.220.25
- # ssl-server-cipher-suites: {'priority': None, 'cipher': None, 'versions': None}
- # protocol: None
- # ssl-hpkp-backup: None
- # ssl-dh-bits: None
- # dns-mapping-ttl: None
- # ssl-hsts-age: None
- # ssl-server-algorithm: None
- # extaddr: None
- # monitor: None
- # service: None
- # ssl-hpkp-age: None
- # http-cookie-age: None
- # adom: ansible
- # http-cookie-share: None
- # ssl-server-session-state-timeout: None
- # color: 17
- # ssl-mode: None
- # portforward: None
- # http-cookie-generation: None
- # max-embryonic-connections: None
- # ssl-client-fallback: None
- # ssl-hpkp-report-uri: None
- # extip: 82.72.192.185
- # extintf: any
- # persistence: None
- # websphere-server: None
- # nat-source-vip: None
- # portmapping-type: None
- # http-ip-header-name: None
- # weblogic-server: None
- # ssl-client-session-state-max: None
- # http-ip-header: None
-
- # ssl-hsts: None
- # arp-reply: None
- # ssl-client-renegotiation: None
- # ssl-min-version: None
- # ldb-method: None
- # ssl-certificate: None
- # ssl-server-min-version: None
- # http-cookie-domain: None
- # mappedport: None
- # outlook-web-access: None
- # ssl-cipher-suites: {'cipher': None, 'versions': None}
- # ssl-hpkp-primary: None
- # name: Basic StaticNAT Map
- # ssl-server-session-state-type: None
- # ssl-client-session-state-type: None
-
- # ssl-http-match-host: None
-
- # ssl-pfs: None
- # ssl-client-session-state-timeout: None
- # http-cookie-domain-from-host: None
- # ssl-hsts-include-subdomains: None
- # ssl-server-max-version: None
- # gratuitous-arp-interval: None
- # http-cookie-path: None
- # ssl-algorithm: None
- # http-multiplex: None
- ##################################################
- ##################################################
- # comment: Created by Ansible
- # ssl-send-empty-frags: None
- # srcintf-filter: None
- # ssl-max-version: None
- # ssl-server-session-state-max: None
- # ssl-hpkp: None
- # mapped-addr: None
- # ssl-client-session-state-timeout: None
- # src-filter: None
- # server-type: None
- # ssl-hpkp-include-subdomains: None
- # ssl-client-renegotiation: None
- # ssl-http-location-conversion: None
- # https-cookie-secure: None
- # mappedip: 10.7.220.25
- # ssl-server-cipher-suites: {'priority': None, 'cipher': None, 'versions': None}
- # protocol: tcp
- # ssl-hpkp-backup: None
- # ssl-dh-bits: None
- # dns-mapping-ttl: None
- # ssl-hsts-age: None
- # extaddr: None
- # monitor: None
- # service: None
- # ssl-hpkp-age: None
- # http-cookie-age: None
- # weblogic-server: None
- # http-cookie-share: None
- # color: 17
- # ssl-mode: None
- # portforward: enable
- # http-cookie-generation: None
- # ssl-client-fallback: None
- # extip: 82.72.192.185
- # extintf: any
- # persistence: None
- # websphere-server: None
- # nat-source-vip: None
- # portmapping-type: None
-
- # adom: ansible
- # ssl-client-session-state-max: None
- # http-ip-header: None
- # http-ip-header-name: None
- # ssl-min-version: None
- # ssl-certificate: None
- # ssl-hsts: None
- # arp-reply: None
- # ssl-hsts-include-subdomains: None
- # http-multiplex: None
- # ldb-method: None
- # ssl-server-session-state-timeout: None
- # ssl-server-min-version: None
- # http-cookie-domain: None
- # mappedport: 443
- # name: Basic PNAT Map Port 10443
- # ssl-cipher-suites: {'cipher': None, 'versions': None}
- # ssl-hpkp-primary: None
- # outlook-web-access: None
- # ssl-server-session-state-type: None
- # ssl-client-session-state-type: None
-
- # ssl-http-match-host: None
-
- # ssl-server-max-version: None
- # ssl-hpkp-report-uri: None
- # http-cookie-domain-from-host: None
- # ssl-algorithm: None
- # gratuitous-arp-interval: None
- # extport: 10443
- # max-embryonic-connections: None
- # mode: set
- # http-cookie-path: None
- # ssl-pfs: None
- # ssl-server-algorithm: None
- ##################################################
- ##################################################
- # comment: None
- # ssl-send-empty-frags: None
- # srcintf-filter: None
- # ssl-max-version: None
- # ssl-server-session-state-max: None
- # ssl-hpkp: None
- # ssl-hsts-include-subdomains: None
- # mapped-addr: None
- # src-filter: None
- # server-type: None
- # mode: delete
- # ssl-hpkp-include-subdomains: None
- # ssl-http-location-conversion: None
- # https-cookie-secure: None
- # mappedip: None
- # ssl-server-cipher-suites: {'priority': None, 'cipher': None, 'versions': None}
- # protocol: None
- # ssl-hpkp-backup: None
- # ssl-dh-bits: None
- # dns-mapping-ttl: None
- # ssl-hsts-age: None
- # extaddr: None
- # monitor: None
- # service: None
- # ssl-hpkp-age: None
- # http-cookie-age: None
- # adom: ansible
- # http-cookie-share: None
- # ssl-server-session-state-timeout: None
- # color: None
- # ssl-mode: None
- # portforward: None
- # http-cookie-generation: None
- # max-embryonic-connections: None
- # ssl-client-fallback: None
- # ssl-hpkp-report-uri: None
- # extip: None
- # extintf: None
- # persistence: None
- # websphere-server: None
- # nat-source-vip: None
- # portmapping-type: None
- # http-ip-header-name: None
- # weblogic-server: None
- # ssl-client-session-state-max: None
- # http-ip-header: None
-
- # ssl-hsts: None
- # arp-reply: None
- # ssl-client-renegotiation: None
- # http-multiplex: None
- # ldb-method: None
- # ssl-certificate: None
- # ssl-server-min-version: None
- # http-cookie-domain: None
- # mappedport: None
- # outlook-web-access: None
- # ssl-cipher-suites: {'cipher': None, 'versions': None}
- # ssl-hpkp-primary: None
- # name: Basic PNAT Map Port 10443
- # ssl-server-session-state-type: None
- # ssl-client-session-state-type: None
-
- # ssl-http-match-host: None
-
- # ssl-pfs: None
- # ssl-server-max-version: None
- # ssl-client-session-state-timeout: None
- # http-cookie-domain-from-host: None
- # extport: None
- # ssl-server-algorithm: None
- # gratuitous-arp-interval: None
- # http-cookie-path: None
- # ssl-algorithm: None
- # ssl-min-version: None
- ##################################################
- ##################################################
- # comment: None
- # ssl-send-empty-frags: None
- # srcintf-filter: None
- # ssl-max-version: None
- # ssl-server-session-state-max: None
- # mappedip: None
- # mapped-addr: None
- # ssl-client-session-state-timeout: None
- # src-filter: None
- # ldb-method: None
- # server-type: None
- # ssl-hpkp-include-subdomains: None
- # ssl-http-location-conversion: None
- # https-cookie-secure: None
- # ssl-hpkp: None
- # ssl-server-cipher-suites: {'priority': None, 'cipher': None, 'versions': None}
- # protocol: None
- # ssl-hpkp-backup: None
- # ssl-dh-bits: None
- # dns-mapping-ttl: None
- # ssl-hsts-age: None
- # extaddr: None
- # ssl-client-renegotiation: None
- # monitor: None
- # service: None
- # ssl-hpkp-age: None
- # http-cookie-age: None
- # weblogic-server: None
- # http-cookie-share: None
- # color: None
- # ssl-mode: None
- # portforward: None
- # http-cookie-generation: None
- # ssl-client-fallback: None
- # extip: None
- # extintf: None
- # persistence: None
- # websphere-server: None
- # nat-source-vip: None
- # portmapping-type: None
-
- # adom: ansible
- # ssl-client-session-state-max: None
- # http-ip-header: None
- # http-ip-header-name: None
- # ssl-certificate: None
- # ssl-hsts: None
- # arp-reply: None
- # extport: None
- # http-multiplex: None
- # ssl-server-algorithm: None
- # ssl-server-session-state-timeout: None
- # ssl-server-min-version: None
- # http-cookie-domain: None
- # mappedport: None
- # name: Basic StaticNAT Map
- # ssl-cipher-suites: {'cipher': None, 'versions': None}
- # ssl-hpkp-primary: None
- # outlook-web-access: None
- # ssl-server-session-state-type: None
- # ssl-client-session-state-type: None
-
- # ssl-http-match-host: None
-
- # ssl-server-max-version: None
- # ssl-hpkp-report-uri: None
- # http-cookie-domain-from-host: None
- # ssl-algorithm: None
- # gratuitous-arp-interval: None
- # ssl-hsts-include-subdomains: None
- # max-embryonic-connections: None
- # mode: delete
- # http-cookie-path: None
- # ssl-pfs: None
- # ssl-min-version: None
- ##################################################
- ##################################################
- # comment: None
- # ssl-send-empty-frags: None
- # srcintf-filter: None
- # ssl-max-version: None
- # ssl-server-session-state-max: None
- # mappedip: None
- # mapped-addr: None
- # src-filter: None
- # server-type: None
- # mode: delete
- # ssl-hpkp-include-subdomains: None
- # extport: None
- # ssl-http-location-conversion: None
- # https-cookie-secure: None
- # ssl-hpkp: None
- # ssl-server-cipher-suites: {'priority': None, 'cipher': None, 'versions': None}
- # protocol: None
- # ssl-hpkp-backup: None
- # ssl-dh-bits: None
- # dns-mapping-ttl: None
- # ssl-hsts-age: None
- # ssl-server-algorithm: None
- # ssl-client-renegotiation: None
- # monitor: None
- # service: None
- # ssl-hpkp-age: None
- # http-cookie-age: None
- # adom: ansible
- # http-cookie-share: None
- # ssl-server-session-state-timeout: None
- # color: None
- # ssl-mode: None
- # portforward: None
- # http-multiplex: None
- # http-cookie-generation: None
- # max-embryonic-connections: None
- # ssl-client-fallback: None
- # ssl-hpkp-report-uri: None
- # extip: None
- # extintf: None
- # persistence: None
- # websphere-server: None
- # nat-source-vip: None
- # portmapping-type: None
- # http-ip-header-name: None
- # weblogic-server: None
- # ssl-client-session-state-max: None
- # http-ip-header: None
- # ssl-hsts: None
- # arp-reply: None
- # extaddr: None
- # ssl-hpkp-primary: None
- # ldb-method: None
- # ssl-certificate: None
- # ssl-server-min-version: None
- # http-cookie-domain: None
- # mappedport: None
- # outlook-web-access: None
- # ssl-cipher-suites: {'cipher': None, 'versions': None}
- # ssl-client-session-state-type: None
- # name: Basic DNS Translation
- # ssl-server-session-state-type: None
-
- # ssl-http-match-host: None
- # ssl-pfs: None
- # ssl-client-session-state-timeout: None
- # http-cookie-domain-from-host: None
- # ssl-hsts-include-subdomains: None
- # ssl-server-max-version: None
- # gratuitous-arp-interval: None
- # http-cookie-path: None
- # ssl-algorithm: None
- # ssl-min-version: None
- ##################################################
- ##################################################
- # ldb-method: None
- # ssl-send-empty-frags: None
- # srcintf-filter: None
- # ssl-max-version: None
- # ssl-server-session-state-max: None
- # mappedip: None
- # ssl-hsts: None
- # mapped-addr: None
- # src-filter: None
- # server-type: None
- # ssl-hpkp-include-subdomains: None
- # ssl-client-renegotiation: None
- # ssl-http-location-conversion: None
- # https-cookie-secure: None
- # extip: None
- # ssl-hpkp: None
- # ssl-server-cipher-suites: {'priority': None, 'cipher': None, 'versions': None}
- # protocol: None
- # ssl-hpkp-backup: None
- # ssl-dh-bits: None
- # dns-mapping-ttl: None
- # ssl-hsts-age: None
- # extaddr: None
- # ssl-hpkp-primary: None
- # monitor: None
- # service: None
- # ssl-hpkp-age: None
- # http-cookie-age: None
- # weblogic-server: None
- # http-cookie-share: None
- # name: Basic FQDN Translation
- # color: None
- # ssl-mode: None
- # portforward: None
- # http-cookie-generation: None
- # ssl-client-fallback: None
-
- # http-ip-header: None
- # persistence: None
- # websphere-server: None
- # nat-source-vip: None
- # portmapping-type: None
- # adom: ansible
- # ssl-client-session-state-max: None
- # extintf: None
- # ssl-server-max-version: None
- # http-ip-header-name: None
- # ssl-certificate: None
- # ssl-server-session-state-type: None
- # arp-reply: None
- # ssl-hsts-include-subdomains: None
- # ssl-min-version: None
- # ssl-server-algorithm: None
- # ssl-server-session-state-timeout: None
- # ssl-server-min-version: None
- # http-cookie-domain: None
- # mappedport: None
- # outlook-web-access: None
- # ssl-cipher-suites: {'cipher': None, 'versions': None}
- # ssl-client-session-state-type: None
- # ssl-http-match-host: None
-
- # ssl-client-session-state-timeout: None
- # comment: None
- # ssl-hpkp-report-uri: None
- # http-cookie-domain-from-host: None
- # ssl-algorithm: None
- # gratuitous-arp-interval: None
- # extport: None
- # max-embryonic-connections: None
- # mode: delete
- # http-cookie-path: None
- # ssl-pfs: None
- # http-multiplex: None
- ##################################################
-
- # Test using fixture 1 #
- output = fmgr_fwobj_vip.fmgr_firewall_vip_modify(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 2 #
- output = fmgr_fwobj_vip.fmgr_firewall_vip_modify(fmg_instance, fixture_data[1]['paramgram_used'])
- assert output['raw_response']['status']['code'] == -10131
- # Test using fixture 3 #
- output = fmgr_fwobj_vip.fmgr_firewall_vip_modify(fmg_instance, fixture_data[2]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 4 #
- output = fmgr_fwobj_vip.fmgr_firewall_vip_modify(fmg_instance, fixture_data[3]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 5 #
- output = fmgr_fwobj_vip.fmgr_firewall_vip_modify(fmg_instance, fixture_data[4]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 6 #
- output = fmgr_fwobj_vip.fmgr_firewall_vip_modify(fmg_instance, fixture_data[5]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 7 #
- output = fmgr_fwobj_vip.fmgr_firewall_vip_modify(fmg_instance, fixture_data[6]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 8 #
- output = fmgr_fwobj_vip.fmgr_firewall_vip_modify(fmg_instance, fixture_data[7]['paramgram_used'])
- assert output['raw_response']['status']['code'] == -3
- # Test using fixture 9 #
- output = fmgr_fwobj_vip.fmgr_firewall_vip_modify(fmg_instance, fixture_data[8]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwpol_ipv4.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwpol_ipv4.py
deleted file mode 100644
index 767573e22..000000000
--- a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwpol_ipv4.py
+++ /dev/null
@@ -1,596 +0,0 @@
-# Copyright 2018 Fortinet, Inc.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import os
-import json
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-import pytest
-
-try:
- from ansible_collections.community.fortios.plugins.modules import fmgr_fwpol_ipv4
-except ImportError:
- pytest.skip("Could not load required modules for testing", allow_module_level=True)
-
-
-def load_fixtures():
- fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format(
- filename=os.path.splitext(os.path.basename(__file__))[0])
- try:
- with open(fixture_path, "r") as fixture_file:
- fixture_data = json.load(fixture_file)
- except IOError:
- return []
- return [fixture_data]
-
-
-@pytest.fixture(autouse=True)
-def module_mock(mocker):
- connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule')
- return connection_class_mock
-
-
-@pytest.fixture(autouse=True)
-def connection_mock(mocker):
- connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_fwpol_ipv4.Connection')
- return connection_class_mock
-
-
-@pytest.fixture(scope="function", params=load_fixtures())
-def fixture_data(request):
- func_name = request.function.__name__.replace("test_", "")
- return request.param.get(func_name, None)
-
-
-fmg_instance = FortiManagerHandler(connection_mock, module_mock)
-
-
-def test_fmgr_firewall_policy_modify(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
- # Fixture sets used:###########################
-
- ##################################################
- # wanopt-passive-opt: None
- # package_name: default
- # wanopt-detection: None
- # scan-botnet-connections: None
- # profile-group: None
- # wanopt-peer: None
- # dscp-match: None
- # replacemsg-override-group: None
- # internet-service-negate: None
- # np-acceleration: None
- # learning-mode: None
- # session-ttl: None
- # ntlm-guest: None
- # ips-sensor: None
- # diffservcode-rev: None
- # match-vip: None
- # natip: None
- # dlp-sensor: None
- # traffic-shaper: None
- # groups: None
- # schedule-timeout: None
- # name: Basic_IPv4_Policy
- # tcp-session-without-syn: None
- # ntlm: None
- # permit-stun-host: None
- # diffservcode-forward: None
- # internet-service-src-custom: None
- # mode: set
- # disclaimer: None
- # rtp-nat: None
- # auth-cert: None
- # timeout-send-rst: None
- # auth-redirect-addr: None
- # ssl-mirror-intf: None
- # identity-based-route: None
- # natoutbound: None
- # wanopt-profile: None
- # per-ip-shaper: None
- # profile-protocol-options: None
- # diffserv-forward: None
- # poolname: None
- # comments: Created by Ansible
- # label: None
- # global-label: None
- # firewall-session-dirty: None
- # wanopt: None
- # schedule: always
- # internet-service-id: None
- # auth-path: None
- # vlan-cos-fwd: None
- # custom-log-fields: None
- # dstintf: any
- # srcintf: any
- # block-notification: None
- # internet-service-src-id: None
- # redirect-url: None
- # waf-profile: None
- # ntlm-enabled-browsers: None
- # dscp-negate: None
- # action: accept
- # fsso-agent-for-ntlm: None
- # logtraffic: utm
- # vlan-filter: None
- # policyid: None
- # logtraffic-start: None
- # webcache-https: None
- # webfilter-profile: None
- # internet-service-src: None
- # webcache: None
- # utm-status: None
- # vpn_src_node: {'subnet': None, 'host': None, 'seq': None}
- # ippool: None
- # service: ALL
- # wccp: None
- # auto-asic-offload: None
- # dscp-value: None
- # url-category: None
- # capture-packet: None
- # adom: ansible
- # inbound: None
- # internet-service: None
- # profile-type: None
- # ssl-mirror: None
- # srcaddr-negate: None
- # gtp-profile: None
- # mms-profile: None
- # send-deny-packet: None
- # devices: None
- # permit-any-host: None
- # av-profile: None
- # internet-service-src-negate: None
- # service-negate: None
- # rsso: None
- # app-group: None
- # tcp-mss-sender: None
- # natinbound: None
- # fixedport: None
- # ssl-ssh-profile: None
- # outbound: None
- # spamfilter-profile: None
- # application-list: None
- # application: None
- # dnsfilter-profile: None
- # nat: None
- # fsso: None
- # vlan-cos-rev: None
- # status: None
- # dsri: None
- # users: None
- # voip-profile: None
- # dstaddr-negate: None
- # traffic-shaper-reverse: None
- # internet-service-custom: None
- # diffserv-reverse: None
- # srcaddr: all
- # ssh-filter-profile: None
- # delay-tcp-npu-session: None
- # icap-profile: None
- # captive-portal-exempt: None
- # vpn_dst_node: {'subnet': None, 'host': None, 'seq': None}
- # app-category: None
- # rtp-addr: None
- # wsso: None
- # tcp-mss-receiver: None
- # dstaddr: all
- # radius-mac-auth-bypass: None
- # vpntunnel: None
- ##################################################
- ##################################################
- # package_name: default
- # wanopt-detection: None
- # scan-botnet-connections: None
- # profile-group: None
- # dlp-sensor: None
- # dscp-match: None
- # replacemsg-override-group: None
- # internet-service-negate: None
- # np-acceleration: None
- # learning-mode: None
- # session-ttl: None
- # ntlm-guest: None
- # ips-sensor: None
- # diffservcode-rev: None
- # match-vip: None
- # natip: None
- # wanopt-peer: None
- # traffic-shaper: None
- # groups: None
- # schedule-timeout: None
- # name: Basic_IPv4_Policy_2
- # tcp-session-without-syn: None
- # rtp-nat: None
- # permit-stun-host: None
- # natoutbound: None
- # internet-service-src-custom: None
- # mode: set
- # logtraffic: utm
- # ntlm: None
- # auth-cert: None
- # timeout-send-rst: None
- # auth-redirect-addr: None
- # ssl-mirror-intf: None
- # identity-based-route: None
- # diffservcode-forward: None
- # wanopt-profile: None
- # per-ip-shaper: None
- # users: None
- # diffserv-forward: None
- # poolname: None
- # comments: Created by Ansible
- # label: None
- # global-label: None
- # firewall-session-dirty: None
- # wanopt: None
- # schedule: always
- # internet-service-id: None
- # auth-path: None
- # vlan-cos-fwd: None
- # custom-log-fields: None
- # dstintf: any
- # srcintf: any
- # block-notification: None
- # internet-service-src-id: None
- # redirect-url: None
- # waf-profile: None
- # ntlm-enabled-browsers: None
- # dscp-negate: None
- # action: accept
- # fsso-agent-for-ntlm: None
- # disclaimer: None
- # vlan-filter: None
- # dstaddr-negate: None
- # logtraffic-start: None
- # webcache-https: None
- # webfilter-profile: None
- # internet-service-src: None
- # webcache: None
- # utm-status: None
- # vpn_src_node: {'subnet': None, 'host': None, 'seq': None}
- # ippool: None
- # service: HTTP, HTTPS
- # wccp: None
- # auto-asic-offload: None
- # dscp-value: None
- # url-category: None
- # capture-packet: None
- # adom: ansible
- # inbound: None
- # internet-service: None
- # profile-type: None
- # ssl-mirror: None
- # srcaddr-negate: None
- # gtp-profile: None
- # mms-profile: None
- # send-deny-packet: None
- # devices: None
- # permit-any-host: None
- # av-profile: None
- # internet-service-src-negate: None
- # service-negate: None
- # rsso: None
- # application-list: None
- # app-group: None
- # tcp-mss-sender: None
- # natinbound: None
- # fixedport: None
- # ssl-ssh-profile: None
- # outbound: None
- # spamfilter-profile: None
- # wanopt-passive-opt: None
- # application: None
- # dnsfilter-profile: None
- # nat: enable
- # fsso: None
- # vlan-cos-rev: None
- # status: None
- # dsri: None
- # profile-protocol-options: None
- # voip-profile: None
- # policyid: None
- # traffic-shaper-reverse: None
- # internet-service-custom: None
- # diffserv-reverse: None
- # srcaddr: all
- # dstaddr: google-play
- # delay-tcp-npu-session: None
- # icap-profile: None
- # captive-portal-exempt: None
- # vpn_dst_node: {'subnet': None, 'host': None, 'seq': None}
- # app-category: None
- # rtp-addr: None
- # wsso: None
- # tcp-mss-receiver: None
- # ssh-filter-profile: None
- # radius-mac-auth-bypass: None
- # vpntunnel: None
- ##################################################
- ##################################################
- # wanopt-passive-opt: None
- # package_name: default
- # wanopt-detection: None
- # scan-botnet-connections: None
- # profile-group: None
- # wanopt-peer: None
- # dscp-match: None
- # replacemsg-override-group: None
- # internet-service-negate: None
- # np-acceleration: None
- # learning-mode: None
- # session-ttl: None
- # ntlm-guest: None
- # ips-sensor: None
- # diffservcode-rev: None
- # match-vip: None
- # natip: None
- # dlp-sensor: None
- # traffic-shaper: None
- # groups: None
- # schedule-timeout: None
- # name: Basic_IPv4_Policy
- # tcp-session-without-syn: None
- # ntlm: None
- # permit-stun-host: None
- # diffservcode-forward: None
- # internet-service-src-custom: None
- # mode: delete
- # disclaimer: None
- # rtp-nat: None
- # auth-cert: None
- # timeout-send-rst: None
- # auth-redirect-addr: None
- # ssl-mirror-intf: None
- # identity-based-route: None
- # natoutbound: None
- # wanopt-profile: None
- # per-ip-shaper: None
- # profile-protocol-options: None
- # diffserv-forward: None
- # poolname: None
- # comments: None
- # label: None
- # global-label: None
- # firewall-session-dirty: None
- # wanopt: None
- # schedule: None
- # internet-service-id: None
- # auth-path: None
- # vlan-cos-fwd: None
- # custom-log-fields: None
- # dstintf: None
- # srcintf: None
- # block-notification: None
- # internet-service-src-id: None
- # redirect-url: None
- # waf-profile: None
- # ntlm-enabled-browsers: None
- # dscp-negate: None
- # action: None
- # fsso-agent-for-ntlm: None
- # logtraffic: None
- # vlan-filter: None
- # policyid: 36
- # logtraffic-start: None
- # webcache-https: None
- # webfilter-profile: None
- # internet-service-src: None
- # webcache: None
- # utm-status: None
- # vpn_src_node: {'subnet': None, 'host': None, 'seq': None}
- # ippool: None
- # service: None
- # wccp: None
- # auto-asic-offload: None
- # dscp-value: None
- # url-category: None
- # capture-packet: None
- # adom: ansible
- # inbound: None
- # internet-service: None
- # profile-type: None
- # ssl-mirror: None
- # srcaddr-negate: None
- # gtp-profile: None
- # mms-profile: None
- # send-deny-packet: None
- # devices: None
- # permit-any-host: None
- # av-profile: None
- # internet-service-src-negate: None
- # service-negate: None
- # rsso: None
- # app-group: None
- # tcp-mss-sender: None
- # natinbound: None
- # fixedport: None
- # ssl-ssh-profile: None
- # outbound: None
- # spamfilter-profile: None
- # application-list: None
- # application: None
- # dnsfilter-profile: None
- # nat: None
- # fsso: None
- # vlan-cos-rev: None
- # status: None
- # dsri: None
- # users: None
- # voip-profile: None
- # dstaddr-negate: None
- # traffic-shaper-reverse: None
- # internet-service-custom: None
- # diffserv-reverse: None
- # srcaddr: None
- # ssh-filter-profile: None
- # delay-tcp-npu-session: None
- # icap-profile: None
- # captive-portal-exempt: None
- # vpn_dst_node: {'subnet': None, 'host': None, 'seq': None}
- # app-category: None
- # rtp-addr: None
- # wsso: None
- # tcp-mss-receiver: None
- # dstaddr: None
- # radius-mac-auth-bypass: None
- # vpntunnel: None
- ##################################################
- ##################################################
- # package_name: default
- # wanopt-detection: None
- # scan-botnet-connections: None
- # profile-group: None
- # dlp-sensor: None
- # dscp-match: None
- # replacemsg-override-group: None
- # internet-service-negate: None
- # np-acceleration: None
- # learning-mode: None
- # session-ttl: None
- # ntlm-guest: None
- # ips-sensor: None
- # diffservcode-rev: None
- # match-vip: None
- # natip: None
- # wanopt-peer: None
- # traffic-shaper: None
- # groups: None
- # schedule-timeout: None
- # name: Basic_IPv4_Policy_2
- # tcp-session-without-syn: None
- # rtp-nat: None
- # permit-stun-host: None
- # natoutbound: None
- # internet-service-src-custom: None
- # mode: delete
- # logtraffic: None
- # ntlm: None
- # auth-cert: None
- # timeout-send-rst: None
- # auth-redirect-addr: None
- # ssl-mirror-intf: None
- # identity-based-route: None
- # diffservcode-forward: None
- # wanopt-profile: None
- # per-ip-shaper: None
- # users: None
- # diffserv-forward: None
- # poolname: None
- # comments: None
- # label: None
- # global-label: None
- # firewall-session-dirty: None
- # wanopt: None
- # schedule: None
- # internet-service-id: None
- # auth-path: None
- # vlan-cos-fwd: None
- # custom-log-fields: None
- # dstintf: None
- # srcintf: None
- # block-notification: None
- # internet-service-src-id: None
- # redirect-url: None
- # waf-profile: None
- # ntlm-enabled-browsers: None
- # dscp-negate: None
- # action: None
- # fsso-agent-for-ntlm: None
- # disclaimer: None
- # vlan-filter: None
- # dstaddr-negate: None
- # logtraffic-start: None
- # webcache-https: None
- # webfilter-profile: None
- # internet-service-src: None
- # webcache: None
- # utm-status: None
- # vpn_src_node: {'subnet': None, 'host': None, 'seq': None}
- # ippool: None
- # service: None
- # wccp: None
- # auto-asic-offload: None
- # dscp-value: None
- # url-category: None
- # capture-packet: None
- # adom: ansible
- # internet-service: None
- # inbound: None
- # profile-type: None
- # ssl-mirror: None
- # srcaddr-negate: None
- # gtp-profile: None
- # mms-profile: None
- # send-deny-packet: None
- # devices: None
- # permit-any-host: None
- # av-profile: None
- # internet-service-src-negate: None
- # service-negate: None
- # rsso: None
- # application-list: None
- # app-group: None
- # tcp-mss-sender: None
- # natinbound: None
- # fixedport: None
- # ssl-ssh-profile: None
- # outbound: None
- # spamfilter-profile: None
- # wanopt-passive-opt: None
- # application: None
- # dnsfilter-profile: None
- # nat: None
- # fsso: None
- # vlan-cos-rev: None
- # status: None
- # dsri: None
- # profile-protocol-options: None
- # voip-profile: None
- # policyid: 37
- # traffic-shaper-reverse: None
- # internet-service-custom: None
- # diffserv-reverse: None
- # srcaddr: None
- # dstaddr: None
- # delay-tcp-npu-session: None
- # icap-profile: None
- # captive-portal-exempt: None
- # vpn_dst_node: {'subnet': None, 'host': None, 'seq': None}
- # app-category: None
- # rtp-addr: None
- # wsso: None
- # tcp-mss-receiver: None
- # ssh-filter-profile: None
- # radius-mac-auth-bypass: None
- # vpntunnel: None
- ##################################################
-
- # Test using fixture 1 #
- output = fmgr_fwpol_ipv4.fmgr_firewall_policy_modify(fmg_instance, fixture_data[0]['paramgram_used'])
- assert isinstance(output['raw_response'], dict) is True
- # Test using fixture 2 #
- output = fmgr_fwpol_ipv4.fmgr_firewall_policy_modify(fmg_instance, fixture_data[1]['paramgram_used'])
- assert isinstance(output['raw_response'], dict) is True
- # Test using fixture 3 #
- output = fmgr_fwpol_ipv4.fmgr_firewall_policy_modify(fmg_instance, fixture_data[2]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 4 #
- output = fmgr_fwpol_ipv4.fmgr_firewall_policy_modify(fmg_instance, fixture_data[3]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwpol_package.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwpol_package.py
deleted file mode 100644
index f6bc82b71..000000000
--- a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_fwpol_package.py
+++ /dev/null
@@ -1,97 +0,0 @@
-# Copyright 2018 Fortinet, Inc.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-
-__metaclass__ = type
-
-import os
-import json
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-import pytest
-
-try:
- from ansible_collections.community.fortios.plugins.modules import fmgr_fwpol_package
-except ImportError:
- pytest.skip("Could not load required modules for testing", allow_module_level=True)
-
-
-def load_fixtures():
- fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format(
- filename=os.path.splitext(os.path.basename(__file__))[0])
- try:
- with open(fixture_path, "r") as fixture_file:
- fixture_data = json.load(fixture_file)
- except IOError:
- return []
- return [fixture_data]
-
-
-@pytest.fixture(autouse=True)
-def module_mock(mocker):
- connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule')
- return connection_class_mock
-
-
-@pytest.fixture(autouse=True)
-def connection_mock(mocker):
- connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_fwpol_package.Connection')
- return connection_class_mock
-
-
-@pytest.fixture(scope="function", params=load_fixtures())
-def fixture_data(request):
- func_name = request.function.__name__.replace("test_", "")
- return request.param.get(func_name, None)
-
-
-fmg_instance = FortiManagerHandler(connection_mock, module_mock)
-
-
-def test_fmgr_fwpol_package(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
-
- # Test using fixture 1 #
- output = fmgr_fwpol_package.fmgr_fwpol_package(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 2 #
- output = fmgr_fwpol_package.fmgr_fwpol_package(fmg_instance, fixture_data[1]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 3 #
- output = fmgr_fwpol_package.fmgr_fwpol_package(fmg_instance, fixture_data[2]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 4 #
- output = fmgr_fwpol_package.fmgr_fwpol_package(fmg_instance, fixture_data[3]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
-
-
-def test_fmgr_fwpol_package_folder(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
-
- # Test using fixture 1 #
- output = fmgr_fwpol_package.fmgr_fwpol_package_folder(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 2 #
- output = fmgr_fwpol_package.fmgr_fwpol_package_folder(fmg_instance, fixture_data[1]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 3 #
- output = fmgr_fwpol_package.fmgr_fwpol_package_folder(fmg_instance, fixture_data[2]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 4 #
- output = fmgr_fwpol_package.fmgr_fwpol_package_folder(fmg_instance, fixture_data[3]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_ha.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_ha.py
deleted file mode 100644
index 6620275cc..000000000
--- a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_ha.py
+++ /dev/null
@@ -1,216 +0,0 @@
-# Copyright 2018 Fortinet, Inc.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import os
-import json
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-import pytest
-
-try:
- from ansible_collections.community.fortios.plugins.modules import fmgr_ha
-except ImportError:
- pytest.skip("Could not load required modules for testing", allow_module_level=True)
-
-
-def load_fixtures():
- fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format(
- filename=os.path.splitext(os.path.basename(__file__))[0])
- try:
- with open(fixture_path, "r") as fixture_file:
- fixture_data = json.load(fixture_file)
- except IOError:
- return []
- return [fixture_data]
-
-
-@pytest.fixture(autouse=True)
-def module_mock(mocker):
- connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule')
- return connection_class_mock
-
-
-@pytest.fixture(autouse=True)
-def connection_mock(mocker):
- connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_ha.Connection')
- return connection_class_mock
-
-
-@pytest.fixture(scope="function", params=load_fixtures())
-def fixture_data(request):
- func_name = request.function.__name__.replace("test_", "")
- return request.param.get(func_name, None)
-
-
-fmg_instance = FortiManagerHandler(connection_mock, module_mock)
-
-
-def test_fmgr_set_ha_mode(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
- # Fixture sets used:###########################
-
- ##################################################
- # fmgr_ha_peer_sn: None
- # fmgr_ha_hb_threshold: 10
- # fmgr_ha_cluster_pw: fortinet
- # fmgr_ha_peer_ipv6: None
- # fmgr_ha_peer_status: None
- # fmgr_ha_file_quota: 2048
- # fmgr_ha_cluster_id: 2
- # fmgr_ha_peer_ipv4: None
- # fmgr_ha_hb_interval: 15
- # fmgr_ha_mode: master
- # mode: set
- ##################################################
- ##################################################
- # fmgr_ha_peer_sn: None
- # fmgr_ha_hb_threshold: 3
- # fmgr_ha_cluster_pw: fortinet
- # fmgr_ha_hb_interval: 5
- # fmgr_ha_cluster_id: 2
- # fmgr_ha_file_quota: 4096
- # fmgr_ha_peer_status: None
- # fmgr_ha_peer_ipv4: None
- # fmgr_ha_peer_ipv6: None
- # fmgr_ha_mode: slave
- # mode: set
- ##################################################
- ##################################################
- # fmgr_ha_peer_sn: FMG-VMTM18001881
- # fmgr_ha_hb_threshold: 3
- # fmgr_ha_cluster_pw: fortinet
- # fmgr_ha_peer_ipv6: None
- # fmgr_ha_peer_status: enable
- # fmgr_ha_file_quota: 4096
- # fmgr_ha_cluster_id: 2
- # fmgr_ha_peer_ipv4: 10.7.220.35
- # fmgr_ha_hb_interval: 5
- # fmgr_ha_mode: slave
- # mode: set
- ##################################################
- ##################################################
- # fmgr_ha_file_quota: 4096
- # fmgr_ha_cluster_pw: None
- # fmgr_ha_peer_sn: None
- # fmgr_ha_hb_interval: 5
- # fmgr_ha_cluster_id: 1
- # fmgr_ha_mode: standalone
- # fmgr_ha_peer_status: None
- # fmgr_ha_hb_threshold: 3
- # fmgr_ha_peer_ipv4: None
- # fmgr_ha_peer_ipv6: None
- # mode: set
- ##################################################
-
- # Test using fixture 1 #
- output = fmgr_ha.fmgr_set_ha_mode(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 2 #
- output = fmgr_ha.fmgr_set_ha_mode(fmg_instance, fixture_data[1]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 3 #
- output = fmgr_ha.fmgr_set_ha_mode(fmg_instance, fixture_data[2]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 4 #
- output = fmgr_ha.fmgr_set_ha_mode(fmg_instance, fixture_data[3]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
-
-
-def test_fmgr_get_ha_peer_list(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
- # Fixture sets used:###########################
-
- ##################################################
- # fmgr_ha_peer_sn: FMG-VMTM18001882
- # fmgr_ha_hb_threshold: 3
- # fmgr_ha_cluster_pw: None
- # fmgr_ha_peer_ipv6: None
- # fmgr_ha_peer_status: enable
- # fmgr_ha_file_quota: 4096
- # fmgr_ha_cluster_id: 1
- # fmgr_ha_peer_ipv4: 10.7.220.36
- # fmgr_ha_hb_interval: 5
- # fmgr_ha_mode: None
- # mode: get
- ##################################################
- ##################################################
- # fmgr_ha_peer_sn: FMG-VMTM18001881
- # fmgr_ha_hb_threshold: 3
- # fmgr_ha_cluster_pw: fortinet
- # fmgr_ha_hb_interval: 5
- # fmgr_ha_cluster_id: 2
- # fmgr_ha_file_quota: 4096
- # fmgr_ha_peer_status: enable
- # fmgr_ha_peer_ipv4: 10.7.220.35
- # fmgr_ha_peer_ipv6: None
- # fmgr_ha_mode: slave
- # mode: get
- ##################################################
-
- # Test using fixture 1 #
- output = fmgr_ha.fmgr_get_ha_peer_list(fmg_instance)
- assert isinstance(output['raw_response'], list) is True
- # Test using fixture 2 #
- output = fmgr_ha.fmgr_get_ha_peer_list(fmg_instance)
- assert isinstance(output['raw_response'], list) is True
-
-
-def test_fmgr_set_ha_peer(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
- # Fixture sets used:###########################
-
- ##################################################
- # fmgr_ha_peer_sn: FMG-VMTM18001882
- # next_peer_id: 2
- # fmgr_ha_hb_threshold: 3
- # fmgr_ha_cluster_pw: None
- # fmgr_ha_peer_ipv6: None
- # fmgr_ha_peer_status: enable
- # fmgr_ha_file_quota: 4096
- # fmgr_ha_cluster_id: 1
- # peer_id: 1
- # fmgr_ha_peer_ipv4: 10.7.220.36
- # fmgr_ha_hb_interval: 5
- # fmgr_ha_mode: None
- # mode: set
- ##################################################
- ##################################################
- # fmgr_ha_peer_sn: FMG-VMTM18001881
- # next_peer_id: 1
- # fmgr_ha_hb_threshold: 3
- # fmgr_ha_cluster_pw: fortinet
- # fmgr_ha_hb_interval: 5
- # fmgr_ha_cluster_id: 2
- # fmgr_ha_file_quota: 4096
- # fmgr_ha_peer_status: enable
- # peer_id: 1
- # fmgr_ha_peer_ipv4: 10.7.220.35
- # fmgr_ha_peer_ipv6: None
- # fmgr_ha_mode: slave
- # mode: set
- ##################################################
-
- # Test using fixture 1 #
- output = fmgr_ha.fmgr_set_ha_peer(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 2 #
- output = fmgr_ha.fmgr_set_ha_peer(fmg_instance, fixture_data[1]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_provisioning.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_provisioning.py
deleted file mode 100644
index 96325db1b..000000000
--- a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_provisioning.py
+++ /dev/null
@@ -1,64 +0,0 @@
-# (c) 2016 Red Hat Inc.
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import pytest
-
-pytestmark = []
-try:
- from ansible_collections.community.fortios.plugins.modules import fmgr_provisioning
- from .fortimanager_module import TestFortimanagerModule
- from ansible_collections.community.fortios.tests.unit.plugins.modules.utils import set_module_args
-except ImportError:
- pytestmark.append(pytest.mark.skip("Could not load required modules for testing"))
-
-try:
- from pyFMG.fortimgr import FortiManager
-except ImportError:
- pytestmark.append(pytest.mark.skip("FortiManager tests require pyFMG package"))
-
-
-class TestFmgrProvisioningModule(TestFortimanagerModule):
-
- module = fmgr_provisioning
-
- def test_fmg_script_fail_connect(self):
- set_module_args(dict(host='1.1.1.1', username='admin', password='admin', adom='root',
- vdom='root', policy_package='root', name='FGT1', serial='FGVM000000117992',
- platform='FortiGate-VM64', os_version='5.0', minor_release='6',
- patch_release='0', os_type='fos'))
- result = self.execute_module(failed=True)
- self.assertEqual(result['msg'], 'Connection to FortiManager Failed')
-
- def test_fmg_script_login_fail_host(self):
- set_module_args(dict(username='admin', password='admin', adom='root',
- vdom='root', policy_package='root', name='FGT1', serial='FGVM000000117992',
- platform='FortiGate-VM64', os_version='5.0', minor_release='6',
- patch_release='0', os_type='fos'))
- result = self.execute_module(failed=True)
- self.assertEqual(result['msg'], 'missing required arguments: host')
-
- def test_fmg_script_login_fail_username(self):
- set_module_args(dict(host='1.1.1.1', password='admin', adom='root',
- vdom='root', policy_package='root', name='FGT1', serial='FGVM000000117992',
- platform='FortiGate-VM64', os_version='5.0', minor_release='6',
- patch_release='0', os_type='fos'))
- result = self.execute_module(failed=True)
- self.assertEqual(result['msg'], 'Host and username are required for connection')
diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_query.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_query.py
deleted file mode 100644
index a5470b680..000000000
--- a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_query.py
+++ /dev/null
@@ -1,106 +0,0 @@
-# Copyright 2018 Fortinet, Inc.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import os
-import json
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-import pytest
-
-try:
- from ansible_collections.community.fortios.plugins.modules import fmgr_query
-except ImportError:
- pytest.skip("Could not load required modules for testing", allow_module_level=True)
-
-
-def load_fixtures():
- fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format(
- filename=os.path.splitext(os.path.basename(__file__))[0])
- try:
- with open(fixture_path, "r") as fixture_file:
- fixture_data = json.load(fixture_file)
- except IOError:
- return []
- return [fixture_data]
-
-
-@pytest.fixture(autouse=True)
-def module_mock(mocker):
- connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule')
- return connection_class_mock
-
-
-@pytest.fixture(autouse=True)
-def connection_mock(mocker):
- connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_query.Connection')
- return connection_class_mock
-
-
-@pytest.fixture(scope="function", params=load_fixtures())
-def fixture_data(request):
- func_name = request.function.__name__.replace("test_", "")
- return request.param.get(func_name, None)
-
-
-fmg_instance = FortiManagerHandler(connection_mock, module_mock)
-
-
-def test_fmgr_get_custom(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
- # Fixture sets used:###########################
-
- ##################################################
- # custom_endpoint: /dvmdb/adom/ansible/script
- # device_ip: None
- # device_unique_name: None
- # task_id: None
- # adom: ansible
- # nodes: None
- # object: custom
- # device_serial: None
- # custom_dict: {'type': 'cli'}
- # mode: get
- ##################################################
-
- # Test using fixture 1 #
- output = fmgr_query.fmgr_get_custom(fmg_instance, fixture_data[0]['paramgram_used'])
- assert isinstance(output['raw_response'], list) is True
-
-
-def test_fmgr_get_task_status(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
- # Fixture sets used:###########################
-
- ##################################################
- # custom_endpoint: None
- # object: task
- # task_id: 247
- # adom: ansible
- # device_ip: None
- # custom_dict: None
- # device_unique_name: None
- # nodes: None
- # device_serial: None
- # mode: get
- ##################################################
-
- # Test using fixture 1 #
- output = fmgr_query.fmgr_get_task_status(fmg_instance, fixture_data[0]['paramgram_used'])
- assert isinstance(output['raw_response'], dict) is True
diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_script.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_script.py
deleted file mode 100644
index c834414aa..000000000
--- a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_script.py
+++ /dev/null
@@ -1,129 +0,0 @@
-# Copyright 2018 Fortinet, Inc.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import os
-import json
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-import pytest
-
-try:
- from ansible_collections.community.fortios.plugins.modules import fmgr_script
-except ImportError:
- pytest.skip("Could not load required modules for testing", allow_module_level=True)
-
-
-def load_fixtures():
- fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format(
- filename=os.path.splitext(os.path.basename(__file__))[0])
- try:
- with open(fixture_path, "r") as fixture_file:
- fixture_data = json.load(fixture_file)
- except IOError:
- return []
- return [fixture_data]
-
-
-@pytest.fixture(autouse=True)
-def module_mock(mocker):
- connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule')
- return connection_class_mock
-
-
-@pytest.fixture(autouse=True)
-def connection_mock(mocker):
- connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_script.Connection')
- return connection_class_mock
-
-
-@pytest.fixture(scope="function", params=load_fixtures())
-def fixture_data(request):
- func_name = request.function.__name__.replace("test_", "")
- return request.param.get(func_name, None)
-
-
-fmg_instance = FortiManagerHandler(connection_mock, module_mock)
-
-
-def test_set_script(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
- # Fixture sets used:###########################
-
- ##################################################
- # script_content: get system status
- # adom: ansible
- # script_scope: None
- # script_name: TestScript
- # script_target: remote_device
- # mode: set
- # script_description: Create by Ansible
- # script_package: None
- # vdom: root
- # script_type: cli
- ##################################################
-
- # Test using fixture 1 #
- output = fmgr_script.set_script(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
-
-
-def test_delete_script(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
- # Fixture sets used:###########################
-
- ##################################################
- # vdom: root
- # script_target: None
- # script_content: None
- # adom: ansible
- # script_description: None
- # script_package: None
- # mode: delete
- # script_scope: None
- # script_name: TestScript
- # script_type: None
- ##################################################
-
- # Test using fixture 1 #
- output = fmgr_script.delete_script(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
-
-
-def test_execute_script(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
- # Fixture sets used:###########################
-
- ##################################################
- # script_content: None
- # adom: ansible
- # script_scope: FGT1
- # script_name: TestScript
- # script_target: None
- # mode: exec
- # script_description: None
- # script_package: None
- # vdom: root
- # script_type: None
- ##################################################
-
- # Test using fixture 1 #
- output = fmgr_script.execute_script(fmg_instance, fixture_data[0]['paramgram_used'])
- assert isinstance(output['raw_response'], dict) is True
diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_appctrl.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_appctrl.py
deleted file mode 100644
index 0af21b25c..000000000
--- a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_appctrl.py
+++ /dev/null
@@ -1,78 +0,0 @@
-# Copyright 2018 Fortinet, Inc.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import os
-import json
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-import pytest
-
-try:
- from ansible_collections.community.fortios.plugins.modules import fmgr_secprof_appctrl
-except ImportError:
- pytest.skip("Could not load required modules for testing", allow_module_level=True)
-
-
-def load_fixtures():
- fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format(
- filename=os.path.splitext(os.path.basename(__file__))[0])
- try:
- with open(fixture_path, "r") as fixture_file:
- fixture_data = json.load(fixture_file)
- except IOError:
- return []
- return [fixture_data]
-
-
-@pytest.fixture(autouse=True)
-def module_mock(mocker):
- connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule')
- return connection_class_mock
-
-
-@pytest.fixture(autouse=True)
-def connection_mock(mocker):
- connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_secprof_appctrl.Connection')
- return connection_class_mock
-
-
-@pytest.fixture(scope="function", params=load_fixtures())
-def fixture_data(request):
- func_name = request.function.__name__.replace("test_", "")
- return request.param.get(func_name, None)
-
-
-fmg_instance = FortiManagerHandler(connection_mock, module_mock)
-
-
-def test_fmgr_application_list_modify(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
-
- # Test using fixture 1 #
- output = fmgr_secprof_appctrl.fmgr_application_list_modify(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 2 #
- output = fmgr_secprof_appctrl.fmgr_application_list_modify(fmg_instance, fixture_data[1]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 3 #
- output = fmgr_secprof_appctrl.fmgr_application_list_modify(fmg_instance, fixture_data[2]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 4 #
- output = fmgr_secprof_appctrl.fmgr_application_list_modify(fmg_instance, fixture_data[3]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_av.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_av.py
deleted file mode 100644
index f3e0d5aec..000000000
--- a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_av.py
+++ /dev/null
@@ -1,72 +0,0 @@
-# Copyright 2018 Fortinet, Inc.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import os
-import json
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-import pytest
-
-try:
- from ansible_collections.community.fortios.plugins.modules import fmgr_secprof_av
-except ImportError:
- pytest.skip("Could not load required modules for testing", allow_module_level=True)
-
-
-def load_fixtures():
- fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format(
- filename=os.path.splitext(os.path.basename(__file__))[0])
- try:
- with open(fixture_path, "r") as fixture_file:
- fixture_data = json.load(fixture_file)
- except IOError:
- return []
- return [fixture_data]
-
-
-@pytest.fixture(autouse=True)
-def module_mock(mocker):
- connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule')
- return connection_class_mock
-
-
-@pytest.fixture(autouse=True)
-def connection_mock(mocker):
- connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_secprof_av.Connection')
- return connection_class_mock
-
-
-@pytest.fixture(scope="function", params=load_fixtures())
-def fixture_data(request):
- func_name = request.function.__name__.replace("test_", "")
- return request.param.get(func_name, None)
-
-
-fmg_instance = FortiManagerHandler(connection_mock, module_mock)
-
-
-def test_fmgr_antivirus_profile_modify(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
-
- # Test using fixture 1 #
- output = fmgr_secprof_av.fmgr_antivirus_profile_modify(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 2 #
- output = fmgr_secprof_av.fmgr_antivirus_profile_modify(fmg_instance, fixture_data[1]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_dns.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_dns.py
deleted file mode 100644
index 6e429fd24..000000000
--- a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_dns.py
+++ /dev/null
@@ -1,88 +0,0 @@
-# Copyright 2018 Fortinet, Inc.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import os
-import json
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-import pytest
-
-try:
- from ansible_collections.community.fortios.plugins.modules import fmgr_secprof_dns
-except ImportError:
- pytest.skip("Could not load required modules for testing", allow_module_level=True)
-
-
-def load_fixtures():
- fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format(
- filename=os.path.splitext(os.path.basename(__file__))[0])
- try:
- with open(fixture_path, "r") as fixture_file:
- fixture_data = json.load(fixture_file)
- except IOError:
- return []
- return [fixture_data]
-
-
-@pytest.fixture(autouse=True)
-def module_mock(mocker):
- connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule')
- return connection_class_mock
-
-
-@pytest.fixture(autouse=True)
-def connection_mock(mocker):
- connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_secprof_dns.Connection')
- return connection_class_mock
-
-
-@pytest.fixture(scope="function", params=load_fixtures())
-def fixture_data(request):
- func_name = request.function.__name__.replace("test_", "")
- return request.param.get(func_name, None)
-
-
-fmg_instance = FortiManagerHandler(connection_mock, module_mock)
-
-
-def test_fmgr_dnsfilter_profile_modify(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
- # Fixture sets used:###########################
-
- ##################################################
- # comment: Created by Ansible Module TEST
- # ftgd-dns: {'options': None, 'filters': {'action': None, 'category': None, 'log': None}}
- # adom: root
- # youtube-restrict: None
- # sdns-domain-log: None
- # block-botnet: None
- # external-ip-blocklist: None
- # block-action: block
- # name: Ansible_DNS_Profile
- # redirect-portal: None
- # sdns-ftgd-err-log: None
- # safe-search: None
- # domain-filter: {'domain-filter-table': None}
- # log-all-domain: None
- # mode: set
- ##################################################
-
- # Test using fixture 1 #
- output = fmgr_secprof_dns.fmgr_dnsfilter_profile_modify(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_ips.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_ips.py
deleted file mode 100644
index 487807523..000000000
--- a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_ips.py
+++ /dev/null
@@ -1,69 +0,0 @@
-# Copyright 2018 Fortinet, Inc.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import os
-import json
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-import pytest
-
-try:
- from ansible_collections.community.fortios.plugins.modules import fmgr_secprof_ips
-except ImportError:
- pytest.skip("Could not load required modules for testing", allow_module_level=True)
-
-
-def load_fixtures():
- fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format(
- filename=os.path.splitext(os.path.basename(__file__))[0])
- try:
- with open(fixture_path, "r") as fixture_file:
- fixture_data = json.load(fixture_file)
- except IOError:
- return []
- return [fixture_data]
-
-
-@pytest.fixture(autouse=True)
-def module_mock(mocker):
- connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule')
- return connection_class_mock
-
-
-@pytest.fixture(autouse=True)
-def connection_mock(mocker):
- connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_secprof_ips.Connection')
- return connection_class_mock
-
-
-@pytest.fixture(scope="function", params=load_fixtures())
-def fixture_data(request):
- func_name = request.function.__name__.replace("test_", "")
- return request.param.get(func_name, None)
-
-
-fmg_instance = FortiManagerHandler(connection_mock, module_mock)
-
-
-def test_fmgr_ips_sensor_modify(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
-
- # Test using fixture 1 #
- output = fmgr_secprof_ips.fmgr_ips_sensor_modify(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_profile_group.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_profile_group.py
deleted file mode 100644
index 5c8fadde8..000000000
--- a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_profile_group.py
+++ /dev/null
@@ -1,112 +0,0 @@
-# Copyright 2018 Fortinet, Inc.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import os
-import json
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-import pytest
-
-try:
- from ansible_collections.community.fortios.plugins.modules import fmgr_secprof_profile_group
-except ImportError:
- pytest.skip("Could not load required modules for testing", allow_module_level=True)
-
-
-def load_fixtures():
- fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format(
- filename=os.path.splitext(os.path.basename(__file__))[0])
- try:
- with open(fixture_path, "r") as fixture_file:
- fixture_data = json.load(fixture_file)
- except IOError:
- return []
- return [fixture_data]
-
-
-@pytest.fixture(autouse=True)
-def module_mock(mocker):
- connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule')
- return connection_class_mock
-
-
-@pytest.fixture(autouse=True)
-def connection_mock(mocker):
- connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_secprof_profile_group.Connection')
- return connection_class_mock
-
-
-@pytest.fixture(scope="function", params=load_fixtures())
-def fixture_data(request):
- func_name = request.function.__name__.replace("test_", "")
- return request.param.get(func_name, None)
-
-
-fmg_instance = FortiManagerHandler(connection_mock, module_mock)
-
-
-def test_fmgr_firewall_profile_group_modify(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
- # Fixture sets used:###########################
-
- ##################################################
- # ssl-ssh-profile: None
- # waf-profile: None
- # adom: root
- # webfilter-profile: None
- # profile-protocol-options: None
- # application-list: None
- # icap-profile: None
- # voip-profile: None
- # ips-sensor: None
- # dnsfilter-profile: None
- # av-profile: None
- # spamfilter-profile: None
- # dlp-sensor: None
- # mode: delete
- # ssh-filter-profile: None
- # mms-profile: None
- # name: Ansible_TEST_Profile_Group
- ##################################################
- ##################################################
- # ssl-ssh-profile: None
- # application-list: None
- # waf-profile: None
- # adom: root
- # webfilter-profile: None
- # ips-sensor: None
- # spamfilter-profile: None
- # icap-profile: None
- # dnsfilter-profile: None
- # name: Ansible_TEST_Profile_Group
- # voip-profile: None
- # av-profile: Ansible_AV_Profile
- # mode: set
- # dlp-sensor: None
- # mms-profile: None
- # ssh-filter-profile: None
- # profile-protocol-options: default
- ##################################################
-
- # Test using fixture 1 #
- output = fmgr_secprof_profile_group.fmgr_firewall_profile_group_modify(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == -3
- # Test using fixture 2 #
- output = fmgr_secprof_profile_group.fmgr_firewall_profile_group_modify(fmg_instance, fixture_data[1]['paramgram_used'])
- assert output['raw_response']['status']['code'] == -10131
diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_proxy.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_proxy.py
deleted file mode 100644
index 61579327c..000000000
--- a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_proxy.py
+++ /dev/null
@@ -1,72 +0,0 @@
-# Copyright 2018 Fortinet, Inc.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import os
-import json
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-import pytest
-
-try:
- from ansible_collections.community.fortios.plugins.modules import fmgr_secprof_proxy
-except ImportError:
- pytest.skip("Could not load required modules for testing", allow_module_level=True)
-
-
-def load_fixtures():
- fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format(
- filename=os.path.splitext(os.path.basename(__file__))[0])
- try:
- with open(fixture_path, "r") as fixture_file:
- fixture_data = json.load(fixture_file)
- except IOError:
- return []
- return [fixture_data]
-
-
-@pytest.fixture(autouse=True)
-def module_mock(mocker):
- connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule')
- return connection_class_mock
-
-
-@pytest.fixture(autouse=True)
-def connection_mock(mocker):
- connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_secprof_proxy.Connection')
- return connection_class_mock
-
-
-@pytest.fixture(scope="function", params=load_fixtures())
-def fixture_data(request):
- func_name = request.function.__name__.replace("test_", "")
- return request.param.get(func_name, None)
-
-
-fmg_instance = FortiManagerHandler(connection_mock, module_mock)
-
-
-def test_fmgr_web_proxy_profile_modify(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
-
- # Test using fixture 1 #
- output = fmgr_secprof_proxy.fmgr_web_proxy_profile_modify(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 2 #
- output = fmgr_secprof_proxy.fmgr_web_proxy_profile_modify(fmg_instance, fixture_data[1]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_spam.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_spam.py
deleted file mode 100644
index 08e382b87..000000000
--- a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_spam.py
+++ /dev/null
@@ -1,72 +0,0 @@
-# Copyright 2018 Fortinet, Inc.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import os
-import json
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-import pytest
-
-try:
- from ansible_collections.community.fortios.plugins.modules import fmgr_secprof_spam
-except ImportError:
- pytest.skip("Could not load required modules for testing", allow_module_level=True)
-
-
-def load_fixtures():
- fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format(
- filename=os.path.splitext(os.path.basename(__file__))[0])
- try:
- with open(fixture_path, "r") as fixture_file:
- fixture_data = json.load(fixture_file)
- except IOError:
- return []
- return [fixture_data]
-
-
-@pytest.fixture(autouse=True)
-def module_mock(mocker):
- connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule')
- return connection_class_mock
-
-
-@pytest.fixture(autouse=True)
-def connection_mock(mocker):
- connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_secprof_spam.Connection')
- return connection_class_mock
-
-
-@pytest.fixture(scope="function", params=load_fixtures())
-def fixture_data(request):
- func_name = request.function.__name__.replace("test_", "")
- return request.param.get(func_name, None)
-
-
-fmg_instance = FortiManagerHandler(connection_mock, module_mock)
-
-
-def test_fmgr_spamfilter_profile_modify(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
-
- # Test using fixture 1 #
- output = fmgr_secprof_spam.fmgr_spamfilter_profile_modify(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 2 #
- output = fmgr_secprof_spam.fmgr_spamfilter_profile_modify(fmg_instance, fixture_data[1]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_ssl_ssh.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_ssl_ssh.py
deleted file mode 100644
index 0a0fa7bd2..000000000
--- a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_ssl_ssh.py
+++ /dev/null
@@ -1,69 +0,0 @@
-# Copyright 2018 Fortinet, Inc.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import os
-import json
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-import pytest
-
-try:
- from ansible_collections.community.fortios.plugins.modules import fmgr_secprof_ssl_ssh
-except ImportError:
- pytest.skip("Could not load required modules for testing", allow_module_level=True)
-
-
-def load_fixtures():
- fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format(
- filename=os.path.splitext(os.path.basename(__file__))[0])
- try:
- with open(fixture_path, "r") as fixture_file:
- fixture_data = json.load(fixture_file)
- except IOError:
- return []
- return [fixture_data]
-
-
-@pytest.fixture(autouse=True)
-def module_mock(mocker):
- connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule')
- return connection_class_mock
-
-
-@pytest.fixture(autouse=True)
-def connection_mock(mocker):
- connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_secprof_ssl_ssh.Connection')
- return connection_class_mock
-
-
-@pytest.fixture(scope="function", params=load_fixtures())
-def fixture_data(request):
- func_name = request.function.__name__.replace("test_", "")
- return request.param.get(func_name, None)
-
-
-fmg_instance = FortiManagerHandler(connection_mock, module_mock)
-
-
-def test_fmgr_firewall_ssl_ssh_profile_modify(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
- output = fmgr_secprof_ssl_ssh.fmgr_firewall_ssl_ssh_profile_modify(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- output = fmgr_secprof_ssl_ssh.fmgr_firewall_ssl_ssh_profile_modify(fmg_instance, fixture_data[1]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_voip.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_voip.py
deleted file mode 100644
index a13c654e5..000000000
--- a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_voip.py
+++ /dev/null
@@ -1,72 +0,0 @@
-# Copyright 2018 Fortinet, Inc.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import os
-import json
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-import pytest
-
-try:
- from ansible_collections.community.fortios.plugins.modules import fmgr_secprof_voip
-except ImportError:
- pytest.skip("Could not load required modules for testing", allow_module_level=True)
-
-
-def load_fixtures():
- fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format(
- filename=os.path.splitext(os.path.basename(__file__))[0])
- try:
- with open(fixture_path, "r") as fixture_file:
- fixture_data = json.load(fixture_file)
- except IOError:
- return []
- return [fixture_data]
-
-
-@pytest.fixture(autouse=True)
-def module_mock(mocker):
- connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule')
- return connection_class_mock
-
-
-@pytest.fixture(autouse=True)
-def connection_mock(mocker):
- connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_secprof_voip.Connection')
- return connection_class_mock
-
-
-@pytest.fixture(scope="function", params=load_fixtures())
-def fixture_data(request):
- func_name = request.function.__name__.replace("test_", "")
- return request.param.get(func_name, None)
-
-
-fmg_instance = FortiManagerHandler(connection_mock, module_mock)
-
-
-def test_fmgr_voip_profile_modify(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
-
- # Test using fixture 1 #
- output = fmgr_secprof_voip.fmgr_voip_profile_modify(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 2 #
- output = fmgr_secprof_voip.fmgr_voip_profile_modify(fmg_instance, fixture_data[1]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_waf.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_waf.py
deleted file mode 100644
index 10b21a4c5..000000000
--- a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_waf.py
+++ /dev/null
@@ -1,69 +0,0 @@
-# Copyright 2018 Fortinet, Inc.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import os
-import json
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-import pytest
-
-try:
- from ansible_collections.community.fortios.plugins.modules import fmgr_secprof_waf
-except ImportError:
- pytest.skip("Could not load required modules for testing", allow_module_level=True)
-
-
-def load_fixtures():
- fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format(
- filename=os.path.splitext(os.path.basename(__file__))[0])
- try:
- with open(fixture_path, "r") as fixture_file:
- fixture_data = json.load(fixture_file)
- except IOError:
- return []
- return [fixture_data]
-
-
-@pytest.fixture(autouse=True)
-def module_mock(mocker):
- connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule')
- return connection_class_mock
-
-
-@pytest.fixture(autouse=True)
-def connection_mock(mocker):
- connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_secprof_waf.Connection')
- return connection_class_mock
-
-
-@pytest.fixture(scope="function", params=load_fixtures())
-def fixture_data(request):
- func_name = request.function.__name__.replace("test_", "")
- return request.param.get(func_name, None)
-
-
-fmg_instance = FortiManagerHandler(connection_mock, module_mock)
-
-
-def test_fmgr_waf_profile_modify(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
- output = fmgr_secprof_waf.fmgr_waf_profile_modify(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- output = fmgr_secprof_waf.fmgr_waf_profile_modify(fmg_instance, fixture_data[1]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_wanopt.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_wanopt.py
deleted file mode 100644
index f6e2785b2..000000000
--- a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_wanopt.py
+++ /dev/null
@@ -1,72 +0,0 @@
-# Copyright 2018 Fortinet, Inc.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import os
-import json
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-import pytest
-
-try:
- from ansible_collections.community.fortios.plugins.modules import fmgr_secprof_wanopt
-except ImportError:
- pytest.skip("Could not load required modules for testing", allow_module_level=True)
-
-
-def load_fixtures():
- fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format(
- filename=os.path.splitext(os.path.basename(__file__))[0])
- try:
- with open(fixture_path, "r") as fixture_file:
- fixture_data = json.load(fixture_file)
- except IOError:
- return []
- return [fixture_data]
-
-
-@pytest.fixture(autouse=True)
-def module_mock(mocker):
- connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule')
- return connection_class_mock
-
-
-@pytest.fixture(autouse=True)
-def connection_mock(mocker):
- connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_secprof_wanopt.Connection')
- return connection_class_mock
-
-
-@pytest.fixture(scope="function", params=load_fixtures())
-def fixture_data(request):
- func_name = request.function.__name__.replace("test_", "")
- return request.param.get(func_name, None)
-
-
-fmg_instance = FortiManagerHandler(connection_mock, module_mock)
-
-
-def test_fmgr_wanopt_profile_modify(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
-
- # Test using fixture 1 #
- output = fmgr_secprof_wanopt.fmgr_wanopt_profile_modify(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
- # Test using fixture 2 #
- output = fmgr_secprof_wanopt.fmgr_wanopt_profile_modify(fmg_instance, fixture_data[1]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_web.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_web.py
deleted file mode 100644
index 56bdd9a4a..000000000
--- a/ansible_collections/community/fortios/tests/unit/plugins/modules/test_fmgr_secprof_web.py
+++ /dev/null
@@ -1,67 +0,0 @@
-# Copyright 2018 Fortinet, Inc.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <https://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import os
-import json
-from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager import FortiManagerHandler
-import pytest
-
-try:
- from ansible_collections.community.fortios.plugins.modules import fmgr_secprof_web
-except ImportError:
- pytest.skip("Could not load required modules for testing", allow_module_level=True)
-
-
-def load_fixtures():
- fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') + "/{filename}.json".format(
- filename=os.path.splitext(os.path.basename(__file__))[0])
- try:
- with open(fixture_path, "r") as fixture_file:
- fixture_data = json.load(fixture_file)
- except IOError:
- return []
- return [fixture_data]
-
-
-@pytest.fixture(autouse=True)
-def module_mock(mocker):
- connection_class_mock = mocker.patch('ansible.module_utils.basic.AnsibleModule')
- return connection_class_mock
-
-
-@pytest.fixture(autouse=True)
-def connection_mock(mocker):
- connection_class_mock = mocker.patch('ansible_collections.community.fortios.plugins.modules.fmgr_secprof_web.Connection')
- return connection_class_mock
-
-
-@pytest.fixture(scope="function", params=load_fixtures())
-def fixture_data(request):
- func_name = request.function.__name__.replace("test_", "")
- return request.param.get(func_name, None)
-
-
-fmg_instance = FortiManagerHandler(connection_mock, module_mock)
-
-
-def test_fmgr_webfilter_profile_modify(fixture_data, mocker):
- mocker.patch('ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.fortimanager.FortiManagerHandler.process_request',
- side_effect=fixture_data)
- output = fmgr_secprof_web.fmgr_webfilter_profile_modify(fmg_instance, fixture_data[0]['paramgram_used'])
- assert output['raw_response']['status']['code'] == 0
diff --git a/ansible_collections/community/fortios/tests/unit/plugins/modules/utils.py b/ansible_collections/community/fortios/tests/unit/plugins/modules/utils.py
deleted file mode 100644
index 66d2bcd2f..000000000
--- a/ansible_collections/community/fortios/tests/unit/plugins/modules/utils.py
+++ /dev/null
@@ -1,50 +0,0 @@
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-import json
-
-from ansible_collections.community.fortios.tests.unit.compat import unittest
-from ansible_collections.community.fortios.tests.unit.compat.mock import patch
-from ansible.module_utils import basic
-from ansible.module_utils._text import to_bytes
-
-
-def set_module_args(args):
- if '_ansible_remote_tmp' not in args:
- args['_ansible_remote_tmp'] = '/tmp'
- if '_ansible_keep_remote_files' not in args:
- args['_ansible_keep_remote_files'] = False
-
- args = json.dumps({'ANSIBLE_MODULE_ARGS': args})
- basic._ANSIBLE_ARGS = to_bytes(args)
-
-
-class AnsibleExitJson(Exception):
- pass
-
-
-class AnsibleFailJson(Exception):
- pass
-
-
-def exit_json(*args, **kwargs):
- if 'changed' not in kwargs:
- kwargs['changed'] = False
- raise AnsibleExitJson(kwargs)
-
-
-def fail_json(*args, **kwargs):
- kwargs['failed'] = True
- raise AnsibleFailJson(kwargs)
-
-
-class ModuleTestCase(unittest.TestCase):
-
- def setUp(self):
- self.mock_module = patch.multiple(basic.AnsibleModule, exit_json=exit_json, fail_json=fail_json)
- self.mock_module.start()
- self.mock_sleep = patch('time.sleep')
- self.mock_sleep.start()
- set_module_args({})
- self.addCleanup(self.mock_module.stop)
- self.addCleanup(self.mock_sleep.stop)
diff --git a/ansible_collections/community/fortios/tests/unit/requirements.txt b/ansible_collections/community/fortios/tests/unit/requirements.txt
deleted file mode 100644
index 9c9a11414..000000000
--- a/ansible_collections/community/fortios/tests/unit/requirements.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-unittest2 ; python_version <= '2.6'
-
-# requirements for FortiManager modules
-pyFMG
diff --git a/ansible_collections/community/general/.azure-pipelines/azure-pipelines.yml b/ansible_collections/community/general/.azure-pipelines/azure-pipelines.yml
index 07da25589..163d71b62 100644
--- a/ansible_collections/community/general/.azure-pipelines/azure-pipelines.yml
+++ b/ansible_collections/community/general/.azure-pipelines/azure-pipelines.yml
@@ -29,14 +29,14 @@ schedules:
always: true
branches:
include:
+ - stable-8
- stable-7
- - stable-6
- cron: 0 11 * * 0
displayName: Weekly (old stable branches)
always: true
branches:
include:
- - stable-5
+ - stable-6
variables:
- name: checkoutPath
@@ -53,7 +53,7 @@ variables:
resources:
containers:
- container: default
- image: quay.io/ansible/azure-pipelines-test-container:3.0.0
+ image: quay.io/ansible/azure-pipelines-test-container:4.0.1
pool: Standard
@@ -73,40 +73,40 @@ stages:
- test: 3
- test: 4
- test: extra
- - stage: Sanity_2_15
- displayName: Sanity 2.15
+ - stage: Sanity_2_16
+ displayName: Sanity 2.16
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
nameFormat: Test {0}
- testFormat: 2.15/sanity/{0}
+ testFormat: 2.16/sanity/{0}
targets:
- test: 1
- test: 2
- test: 3
- test: 4
- - stage: Sanity_2_14
- displayName: Sanity 2.14
+ - stage: Sanity_2_15
+ displayName: Sanity 2.15
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
nameFormat: Test {0}
- testFormat: 2.14/sanity/{0}
+ testFormat: 2.15/sanity/{0}
targets:
- test: 1
- test: 2
- test: 3
- test: 4
- - stage: Sanity_2_13
- displayName: Sanity 2.13
+ - stage: Sanity_2_14
+ displayName: Sanity 2.14
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
nameFormat: Test {0}
- testFormat: 2.13/sanity/{0}
+ testFormat: 2.14/sanity/{0}
targets:
- test: 1
- test: 2
@@ -122,13 +122,24 @@ stages:
nameFormat: Python {0}
testFormat: devel/units/{0}/1
targets:
- - test: 2.7
- - test: 3.6
- test: 3.7
- test: 3.8
- test: 3.9
- test: '3.10'
- test: '3.11'
+ - test: '3.12'
+ - stage: Units_2_16
+ displayName: Units 2.16
+ dependsOn: []
+ jobs:
+ - template: templates/matrix.yml
+ parameters:
+ nameFormat: Python {0}
+ testFormat: 2.16/units/{0}/1
+ targets:
+ - test: 2.7
+ - test: 3.6
+ - test: "3.11"
- stage: Units_2_15
displayName: Units 2.15
dependsOn: []
@@ -150,17 +161,6 @@ stages:
testFormat: 2.14/units/{0}/1
targets:
- test: 3.9
- - stage: Units_2_13
- displayName: Units 2.13
- dependsOn: []
- jobs:
- - template: templates/matrix.yml
- parameters:
- nameFormat: Python {0}
- testFormat: 2.13/units/{0}/1
- targets:
- - test: 2.7
- - test: 3.8
## Remote
- stage: Remote_devel_extra_vms
@@ -171,10 +171,10 @@ stages:
parameters:
testFormat: devel/{0}
targets:
- - name: Alpine 3.17
- test: alpine/3.17
- # - name: Fedora 37
- # test: fedora/37
+ - name: Alpine 3.19
+ test: alpine/3.19
+ # - name: Fedora 39
+ # test: fedora/39
- name: Ubuntu 22.04
test: ubuntu/22.04
groups:
@@ -187,14 +187,34 @@ stages:
parameters:
testFormat: devel/{0}
targets:
+ - name: macOS 14.3
+ test: macos/14.3
+ - name: RHEL 9.3
+ test: rhel/9.3
+ - name: FreeBSD 13.3
+ test: freebsd/13.3
+ - name: FreeBSD 14.0
+ test: freebsd/14.0
+ groups:
+ - 1
+ - 2
+ - 3
+ - stage: Remote_2_16
+ displayName: Remote 2.16
+ dependsOn: []
+ jobs:
+ - template: templates/matrix.yml
+ parameters:
+ testFormat: 2.16/{0}
+ targets:
- name: macOS 13.2
test: macos/13.2
- - name: RHEL 9.1
- test: rhel/9.1
+ - name: RHEL 9.2
+ test: rhel/9.2
+ - name: RHEL 8.8
+ test: rhel/8.8
- name: FreeBSD 13.2
test: freebsd/13.2
- - name: FreeBSD 12.4
- test: freebsd/12.4
groups:
- 1
- 2
@@ -207,10 +227,16 @@ stages:
parameters:
testFormat: 2.15/{0}
targets:
+ - name: RHEL 9.1
+ test: rhel/9.1
+ - name: RHEL 8.7
+ test: rhel/8.7
- name: RHEL 7.9
test: rhel/7.9
- - name: FreeBSD 13.1
- test: freebsd/13.1
+ # - name: FreeBSD 13.1
+ # test: freebsd/13.1
+ # - name: FreeBSD 12.4
+ # test: freebsd/12.4
groups:
- 1
- 2
@@ -223,50 +249,50 @@ stages:
parameters:
testFormat: 2.14/{0}
targets:
+ #- name: macOS 12.0
+ # test: macos/12.0
- name: RHEL 9.0
test: rhel/9.0
- - name: FreeBSD 12.3
- test: freebsd/12.3
+ #- name: FreeBSD 12.4
+ # test: freebsd/12.4
groups:
- 1
- 2
- 3
- - stage: Remote_2_13
- displayName: Remote 2.13
+
+### Docker
+ - stage: Docker_devel
+ displayName: Docker devel
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
- testFormat: 2.13/{0}
+ testFormat: devel/linux/{0}
targets:
- - name: macOS 12.0
- test: macos/12.0
- - name: RHEL 8.5
- test: rhel/8.5
- - name: FreeBSD 13.0
- test: freebsd/13.0
+ - name: Fedora 39
+ test: fedora39
+ - name: Ubuntu 20.04
+ test: ubuntu2004
+ - name: Ubuntu 22.04
+ test: ubuntu2204
+ - name: Alpine 3.19
+ test: alpine319
groups:
- 1
- 2
- 3
-
-### Docker
- - stage: Docker_devel
- displayName: Docker devel
+ - stage: Docker_2_16
+ displayName: Docker 2.16
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
- testFormat: devel/linux/{0}
+ testFormat: 2.16/linux/{0}
targets:
- - name: Fedora 37
- test: fedora37
+ - name: Fedora 38
+ test: fedora38
- name: openSUSE 15
test: opensuse15
- - name: Ubuntu 20.04
- test: ubuntu2004
- - name: Ubuntu 22.04
- test: ubuntu2204
- name: Alpine 3
test: alpine3
groups:
@@ -281,6 +307,8 @@ stages:
parameters:
testFormat: 2.15/linux/{0}
targets:
+ - name: Fedora 37
+ test: fedora37
- name: CentOS 7
test: centos7
groups:
@@ -295,24 +323,6 @@ stages:
parameters:
testFormat: 2.14/linux/{0}
targets:
- - name: Fedora 36
- test: fedora36
- groups:
- - 1
- - 2
- - 3
- - stage: Docker_2_13
- displayName: Docker 2.13
- dependsOn: []
- jobs:
- - template: templates/matrix.yml
- parameters:
- testFormat: 2.13/linux/{0}
- targets:
- - name: Fedora 35
- test: fedora35
- - name: openSUSE 15 py2
- test: opensuse15py2
- name: Alpine 3
test: alpine3
groups:
@@ -331,10 +341,10 @@ stages:
targets:
- name: Debian Bullseye
test: debian-bullseye/3.9
+ - name: Debian Bookworm
+ test: debian-bookworm/3.11
- name: ArchLinux
test: archlinux/3.11
- - name: CentOS Stream 8
- test: centos-stream8/3.9
groups:
- 1
- 2
@@ -350,7 +360,19 @@ stages:
nameFormat: Python {0}
testFormat: devel/generic/{0}/1
targets:
- - test: 2.7
+ - test: '3.7'
+ - test: '3.12'
+ - stage: Generic_2_16
+ displayName: Generic 2.16
+ dependsOn: []
+ jobs:
+ - template: templates/matrix.yml
+ parameters:
+ nameFormat: Python {0}
+ testFormat: 2.16/generic/{0}/1
+ targets:
+ - test: '2.7'
+ - test: '3.6'
- test: '3.11'
- stage: Generic_2_15
displayName: Generic 2.15
@@ -361,7 +383,7 @@ stages:
nameFormat: Python {0}
testFormat: 2.15/generic/{0}/1
targets:
- - test: 3.9
+ - test: '3.9'
- stage: Generic_2_14
displayName: Generic 2.14
dependsOn: []
@@ -372,42 +394,32 @@ stages:
testFormat: 2.14/generic/{0}/1
targets:
- test: '3.10'
- - stage: Generic_2_13
- displayName: Generic 2.13
- dependsOn: []
- jobs:
- - template: templates/matrix.yml
- parameters:
- nameFormat: Python {0}
- testFormat: 2.13/generic/{0}/1
- targets:
- - test: 3.9
- stage: Summary
condition: succeededOrFailed()
dependsOn:
- Sanity_devel
- - Sanity_2_13
- - Sanity_2_14
+ - Sanity_2_16
- Sanity_2_15
+ - Sanity_2_14
- Units_devel
- - Units_2_13
- - Units_2_14
+ - Units_2_16
- Units_2_15
+ - Units_2_14
- Remote_devel_extra_vms
- Remote_devel
- - Remote_2_13
- - Remote_2_14
+ - Remote_2_16
- Remote_2_15
+ - Remote_2_14
- Docker_devel
- - Docker_2_13
- - Docker_2_14
+ - Docker_2_16
- Docker_2_15
+ - Docker_2_14
- Docker_community_devel
# Right now all generic tests are disabled. Uncomment when at least one of them is re-enabled.
# - Generic_devel
-# - Generic_2_13
-# - Generic_2_14
+# - Generic_2_16
# - Generic_2_15
+# - Generic_2_14
jobs:
- template: templates/coverage.yml
diff --git a/ansible_collections/community/general/.github/BOTMETA.yml b/ansible_collections/community/general/.github/BOTMETA.yml
index c6379bdcb..64cbc7021 100644
--- a/ansible_collections/community/general/.github/BOTMETA.yml
+++ b/ansible_collections/community/general/.github/BOTMETA.yml
@@ -50,6 +50,8 @@ files:
$callbacks/cgroup_memory_recap.py: {}
$callbacks/context_demo.py: {}
$callbacks/counter_enabled.py: {}
+ $callbacks/default_without_diff.py:
+ maintainers: felixfontein
$callbacks/dense.py:
maintainers: dagwieers
$callbacks/diy.py:
@@ -97,6 +99,9 @@ files:
$connections/funcd.py:
maintainers: mscherer
$connections/iocage.py: {}
+ $connections/incus.py:
+ labels: incus
+ maintainers: stgraber
$connections/jail.py:
maintainers: $team_ansible_core
$connections/lxc.py: {}
@@ -119,7 +124,7 @@ files:
labels: hwc
maintainers: $team_huawei
$doc_fragments/nomad.py:
- maintainers: chris93111
+ maintainers: chris93111 apecnascimento
$doc_fragments/xenserver.py:
labels: xenserver
maintainers: bvitnik
@@ -133,6 +138,8 @@ files:
maintainers: giner
$filters/from_csv.py:
maintainers: Ajpantuso
+ $filters/from_ini.py:
+ maintainers: sscheib
$filters/groupby_as_dict.py:
maintainers: felixfontein
$filters/hashids.py:
@@ -144,8 +151,18 @@ files:
$filters/jc.py:
maintainers: kellyjonbrazil
$filters/json_query.py: {}
+ $filters/lists.py:
+ maintainers: cfiehe
+ $filters/lists_difference.yml:
+ maintainers: cfiehe
+ $filters/lists_intersect.yml:
+ maintainers: cfiehe
$filters/lists_mergeby.py:
maintainers: vbotka
+ $filters/lists_symmetric_difference.yml:
+ maintainers: cfiehe
+ $filters/lists_union.yml:
+ maintainers: cfiehe
$filters/random_mac.py: {}
$filters/time.py:
maintainers: resmo
@@ -153,6 +170,8 @@ files:
maintainers: resmo
$filters/to_hours.yml:
maintainers: resmo
+ $filters/to_ini.py:
+ maintainers: sscheib
$filters/to_milliseconds.yml:
maintainers: resmo
$filters/to_minutes.yml:
@@ -193,7 +212,7 @@ files:
labels: cloud opennebula
maintainers: feldsam
$inventories/proxmox.py:
- maintainers: $team_virt ilijamt
+ maintainers: $team_virt ilijamt krauthosting
$inventories/scaleway.py:
labels: cloud scaleway
maintainers: $team_scaleway
@@ -204,6 +223,8 @@ files:
maintainers: ddelnano shinuza
$lookups/:
labels: lookups
+ $lookups/bitwarden_secrets_manager.py:
+ maintainers: jantari
$lookups/bitwarden.py:
maintainers: lungj
$lookups/cartesian.py: {}
@@ -232,6 +253,8 @@ files:
$lookups/filetree.py:
maintainers: dagwieers
$lookups/flattened.py: {}
+ $lookups/github_app_access_token.py:
+ maintainers: weisheng-p
$lookups/hiera.py:
maintainers: jparrill
$lookups/keyring.py: {}
@@ -242,14 +265,16 @@ files:
labels: manifold
maintainers: galanoff
$lookups/merge_variables.py:
- maintainers: rlenferink m-a-r-k-e
+ maintainers: rlenferink m-a-r-k-e alpex8
$lookups/onepass:
labels: onepassword
maintainers: samdoran
$lookups/onepassword.py:
- maintainers: azenk scottsb
+ ignore: scottsb
+ maintainers: azenk
$lookups/onepassword_raw.py:
- maintainers: azenk scottsb
+ ignore: scottsb
+ maintainers: azenk
$lookups/passwordstore.py: {}
$lookups/random_pet.py:
maintainers: Akasurde
@@ -274,6 +299,8 @@ files:
$module_utils/gconftool2.py:
labels: gconftool2
maintainers: russoz
+ $module_utils/gio_mime.py:
+ maintainers: russoz
$module_utils/gitlab.py:
keywords: gitlab source_control
labels: gitlab
@@ -326,6 +353,9 @@ files:
$module_utils/scaleway.py:
labels: cloud scaleway
maintainers: $team_scaleway
+ $module_utils/snap.py:
+ labels: snap
+ maintainers: russoz
$module_utils/ssh.py:
maintainers: russoz
$module_utils/storage/hpe3par/hpe3par.py:
@@ -333,6 +363,9 @@ files:
$module_utils/utm_utils.py:
labels: utm_utils
maintainers: $team_e_spirit
+ $module_utils/vardict.py:
+ labels: vardict
+ maintainers: russoz
$module_utils/wdc_redfish_utils.py:
labels: wdc_redfish_utils
maintainers: $team_wdc
@@ -428,7 +461,7 @@ files:
ignore: resmo
maintainers: dmtrs
$modules/consul:
- ignore: colin-nolan
+ ignore: colin-nolan Hakon
maintainers: $team_consul
$modules/copr.py:
maintainers: schlupov
@@ -463,6 +496,8 @@ files:
maintainers: russoz
$modules/dnf_versionlock.py:
maintainers: moreda
+ $modules/dnf_config_manager.py:
+ maintainers: ahyattdev
$modules/dnsimple.py:
maintainers: drcapulet
$modules/dnsimple_info.py:
@@ -485,6 +520,9 @@ files:
$modules/facter.py:
labels: facter
maintainers: $team_ansible_core gamethis
+ $modules/facter_facts.py:
+ labels: facter
+ maintainers: russoz $team_ansible_core gamethis
$modules/filesize.py:
maintainers: quidame
$modules/filesystem.py:
@@ -507,8 +545,12 @@ files:
$modules/gem.py:
labels: gem
maintainers: $team_ansible_core johanwiren
+ $modules/gio_mime.py:
+ maintainers: russoz
$modules/git_config.py:
maintainers: djmattyg007 mgedmin
+ $modules/git_config_info.py:
+ maintainers: guenhter
$modules/github_:
maintainers: stpierre
$modules/github_deploy_key.py:
@@ -527,20 +569,33 @@ files:
keywords: gitlab source_control
maintainers: $team_gitlab
notify: jlozadad
+ ignore: dj-wasabi
$modules/gitlab_branch.py:
maintainers: paytroff
+ $modules/gitlab_issue.py:
+ maintainers: zvaraondrej
+ $modules/gitlab_label.py:
+ maintainers: gpongelli
+ $modules/gitlab_merge_request.py:
+ maintainers: zvaraondrej
+ $modules/gitlab_milestone.py:
+ maintainers: gpongelli
$modules/gitlab_project_variable.py:
maintainers: markuman
+ $modules/gitlab_instance_variable.py:
+ maintainers: benibr
$modules/gitlab_runner.py:
maintainers: SamyCoenen
$modules/gitlab_user.py:
maintainers: LennertMertens stgrace
+ $modules/gitlab_group_access_token.py:
+ maintainers: pixslx
+ $modules/gitlab_project_access_token.py:
+ maintainers: pixslx
$modules/grove.py:
maintainers: zimbatm
$modules/gunicorn.py:
maintainers: agmezr
- $modules/hana_query.py:
- maintainers: rainerleber
$modules/haproxy.py:
maintainers: ravibhure Normo
$modules/heroku_collaborator.py:
@@ -625,6 +680,11 @@ files:
maintainers: bregman-arie
$modules/ipa_:
maintainers: $team_ipa
+ ignore: fxfitz
+ $modules/ipa_dnsrecord.py:
+ maintainers: $team_ipa jwbernin
+ $modules/ipbase_info.py:
+ maintainers: dominikkukacka
$modules/ipa_pwpolicy.py:
maintainers: adralioh
$modules/ipa_service.py:
@@ -659,7 +719,9 @@ files:
labels: jboss
maintainers: $team_jboss jhoekx
$modules/jenkins_build.py:
- maintainers: brettmilford unnecessary-username
+ maintainers: brettmilford unnecessary-username juanmcasanova
+ $modules/jenkins_build_info.py:
+ maintainers: juanmcasanova
$modules/jenkins_job.py:
maintainers: sermilrod
$modules/jenkins_job_info.py:
@@ -669,9 +731,9 @@ files:
$modules/jenkins_script.py:
maintainers: hogarthj
$modules/jira.py:
- ignore: DWSR
+ ignore: DWSR tarka
labels: jira
- maintainers: Slezhuk tarka pertoft
+ maintainers: Slezhuk pertoft
$modules/kdeconfig.py:
maintainers: smeso
$modules/kernel_blacklist.py:
@@ -680,8 +742,16 @@ files:
maintainers: $team_keycloak
$modules/keycloak_authentication.py:
maintainers: elfelip Gaetan2907
+ $modules/keycloak_authentication_required_actions.py:
+ maintainers: Skrekulko
$modules/keycloak_authz_authorization_scope.py:
maintainers: mattock
+ $modules/keycloak_authz_permission.py:
+ maintainers: mattock
+ $modules/keycloak_authz_custom_policy.py:
+ maintainers: mattock
+ $modules/keycloak_authz_permission_info.py:
+ maintainers: mattock
$modules/keycloak_client_rolemapping.py:
maintainers: Gaetan2907
$modules/keycloak_clientscope.py:
@@ -700,12 +770,20 @@ files:
maintainers: kris2kris
$modules/keycloak_realm_info.py:
maintainers: fynncfchen
+ $modules/keycloak_realm_key.py:
+ maintainers: mattock
$modules/keycloak_role.py:
maintainers: laurpaum
+ $modules/keycloak_user.py:
+ maintainers: elfelip
$modules/keycloak_user_federation.py:
maintainers: laurpaum
+ $modules/keycloak_component_info.py:
+ maintainers: desand01
$modules/keycloak_user_rolemapping.py:
maintainers: bratwurzt
+ $modules/keycloak_realm_rolemapping.py:
+ maintainers: agross mhuysamen Gaetan2907
$modules/keyring.py:
maintainers: ahussey-redhat
$modules/keyring_info.py:
@@ -748,6 +826,8 @@ files:
maintainers: nerzhul
$modules/lvg.py:
maintainers: abulimov
+ $modules/lvg_rename.py:
+ maintainers: lszomor
$modules/lvol.py:
maintainers: abulimov jhoekx zigaSRC unkaputtbar112
$modules/lxc_container.py:
@@ -832,7 +912,7 @@ files:
$modules/nmcli.py:
maintainers: alcamie101
$modules/nomad_:
- maintainers: chris93111
+ maintainers: chris93111 apecnascimento
$modules/nosh.py:
maintainers: tacatac
$modules/npm.py:
@@ -917,7 +997,7 @@ files:
labels: pagerduty
maintainers: suprememoocow thaumos
$modules/pagerduty_alert.py:
- maintainers: ApsOps
+ maintainers: ApsOps xshen1
$modules/pagerduty_change.py:
maintainers: adamvaughan
$modules/pagerduty_user.py:
@@ -960,6 +1040,9 @@ files:
maintainers: $team_solaris dermute
$modules/pmem.py:
maintainers: mizumm
+ $modules/pnpm.py:
+ ignore: chrishoffman
+ maintainers: aretrosen
$modules/portage.py:
ignore: sayap
labels: portage
@@ -976,22 +1059,27 @@ files:
$modules/proxmox:
keywords: kvm libvirt proxmox qemu
labels: proxmox virt
- maintainers: $team_virt
+ maintainers: $team_virt UnderGreen krauthosting
+ ignore: tleguern
$modules/proxmox.py:
ignore: skvidal
- maintainers: UnderGreen
+ maintainers: UnderGreen krauthosting
$modules/proxmox_disk.py:
- maintainers: castorsky
+ maintainers: castorsky krauthosting
$modules/proxmox_kvm.py:
ignore: skvidal
- maintainers: helldorado
+ maintainers: helldorado krauthosting
$modules/proxmox_nic.py:
- maintainers: Kogelvis
+ maintainers: Kogelvis krauthosting
+ $modules/proxmox_node_info.py:
+ maintainers: jwbernin krauthosting
+ $modules/proxmox_storage_contents_info.py:
+ maintainers: l00ptr krauthosting
$modules/proxmox_tasks_info:
- maintainers: paginabianca
+ maintainers: paginabianca krauthosting
$modules/proxmox_template.py:
ignore: skvidal
- maintainers: UnderGreen
+ maintainers: UnderGreen krauthosting
$modules/pubnub_blocks.py:
maintainers: parfeon pubnub
$modules/pulp_repo.py:
@@ -1100,10 +1188,6 @@ files:
maintainers: nerzhul
$modules/runit.py:
maintainers: jsumners
- $modules/sap_task_list_execute:
- maintainers: rainerleber
- $modules/sapcar_extract.py:
- maintainers: RainerLeber
$modules/say.py:
maintainers: $team_ansible_core
ignore: mpdehaan
@@ -1178,6 +1262,8 @@ files:
ignore: ryansb
$modules/shutdown.py:
maintainers: nitzmahone samdoran aminvakil
+ $modules/simpleinit_msb.py:
+ maintainers: vaygr
$modules/sl_vm.py:
maintainers: mcltn
$modules/slack.py:
@@ -1190,7 +1276,7 @@ files:
maintainers: $team_solaris
$modules/snap.py:
labels: snap
- maintainers: angristan vcarceler
+ maintainers: angristan vcarceler russoz
$modules/snap_alias.py:
labels: snap
maintainers: russoz
@@ -1268,6 +1354,8 @@ files:
maintainers: nate-kingsley
$modules/urpmi.py:
maintainers: pmakowski
+ $modules/usb_facts.py:
+ maintainers: maxopoly
$modules/utm_:
keywords: sophos utm
maintainers: $team_e_spirit
@@ -1359,6 +1447,43 @@ files:
maintainers: $team_suse
$tests/a_module.py:
maintainers: felixfontein
+ $tests/fqdn_valid.py:
+ maintainers: vbotka
+#########################
+ docs/docsite/rst/filter_guide.rst: {}
+ docs/docsite/rst/filter_guide_abstract_informations.rst: {}
+ docs/docsite/rst/filter_guide_abstract_informations_counting_elements_in_sequence.rst:
+ maintainers: keilr
+ docs/docsite/rst/filter_guide_abstract_informations_dictionaries.rst:
+ maintainers: felixfontein giner
+ docs/docsite/rst/filter_guide_abstract_informations_grouping.rst:
+ maintainers: felixfontein
+ docs/docsite/rst/filter_guide_abstract_informations_lists_helper.rst:
+ maintainers: cfiehe
+ docs/docsite/rst/filter_guide_abstract_informations_merging_lists_of_dictionaries.rst:
+ maintainers: vbotka
+ docs/docsite/rst/filter_guide_conversions.rst:
+ maintainers: Ajpantuso kellyjonbrazil
+ docs/docsite/rst/filter_guide_creating_identifiers.rst:
+ maintainers: Ajpantuso
+ docs/docsite/rst/filter_guide_paths.rst: {}
+ docs/docsite/rst/filter_guide_selecting_json_data.rst: {}
+ docs/docsite/rst/filter_guide_working_with_times.rst:
+ maintainers: resmo
+ docs/docsite/rst/filter_guide_working_with_unicode.rst:
+ maintainers: Ajpantuso
+ docs/docsite/rst/filter_guide_working_with_versions.rst:
+ maintainers: ericzolf
+ docs/docsite/rst/guide_alicloud.rst:
+ maintainers: xiaozhu36
+ docs/docsite/rst/guide_online.rst:
+ maintainers: remyleone
+ docs/docsite/rst/guide_packet.rst:
+ maintainers: baldwinSPC nurfet-becirevic t0mk teebes
+ docs/docsite/rst/guide_scaleway.rst:
+ maintainers: $team_scaleway
+ docs/docsite/rst/test_guide.rst:
+ maintainers: felixfontein
#########################
tests/:
labels: tests
@@ -1389,14 +1514,14 @@ macros:
team_ansible_core:
team_aix: MorrisA bcoca d-little flynn1973 gforster kairoaraujo marvin-sinister mator molekuul ramooncamacho wtcross
team_bsd: JoergFiedler MacLemon bcoca dch jasperla mekanix opoplawski overhacked tuxillo
- team_consul: sgargan
+ team_consul: sgargan apollo13
team_cyberark_conjur: jvanderhoof ryanprior
team_e_spirit: MatrixCrawler getjack
team_flatpak: JayKayy oolongbrothers
- team_gitlab: Lunik Shaps dj-wasabi marwatk waheedi zanssa scodeman metanovii sh0shin nejch lgatellier suukit
+ team_gitlab: Lunik Shaps marwatk waheedi zanssa scodeman metanovii sh0shin nejch lgatellier suukit
team_hpux: bcoca davx8342
team_huawei: QijunPan TommyLike edisonxiang freesky-edward hwDCN niuzhenguo xuxiaowei0512 yanzhangi zengchen1024 zhongjun2
- team_ipa: Akasurde Nosmoht fxfitz justchris1
+ team_ipa: Akasurde Nosmoht justchris1
team_jboss: Wolfant jairojunior wbrefvem
team_keycloak: eikef ndclt mattock
team_linode: InTheCloudDan decentral1se displague rmcintosh Charliekenney23 LBGarber
@@ -1412,5 +1537,5 @@ macros:
team_scaleway: remyleone abarbare
team_solaris: bcoca fishman jasperla jpdasma mator scathatheworm troy2914 xen0l
team_suse: commel evrardjp lrupp toabctl AnderEnder alxgu andytom sealor
- team_virt: joshainglis karmab tleguern Thulium-Drake Ajpantuso
+ team_virt: joshainglis karmab Thulium-Drake Ajpantuso
team_wdc: mikemoerk
diff --git a/ansible_collections/community/general/.github/ISSUE_TEMPLATE/bug_report.yml b/ansible_collections/community/general/.github/ISSUE_TEMPLATE/bug_report.yml
index bd5030f2c..f64de2abe 100644
--- a/ansible_collections/community/general/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/ansible_collections/community/general/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -47,7 +47,7 @@ body:
label: Component Name
description: >-
Write the short name of the module, plugin, task or feature below,
- *use your best guess if unsure*.
+ *use your best guess if unsure*. Do not include `community.general.`!
placeholder: dnf, apt, yum, pip, user etc.
validations:
required: true
diff --git a/ansible_collections/community/general/.github/ISSUE_TEMPLATE/documentation_report.yml b/ansible_collections/community/general/.github/ISSUE_TEMPLATE/documentation_report.yml
index 3a2777f20..6ec49fcb3 100644
--- a/ansible_collections/community/general/.github/ISSUE_TEMPLATE/documentation_report.yml
+++ b/ansible_collections/community/general/.github/ISSUE_TEMPLATE/documentation_report.yml
@@ -46,8 +46,8 @@ body:
attributes:
label: Component Name
description: >-
- Write the short name of the rst file, module, plugin, task or
- feature below, *use your best guess if unsure*.
+ Write the short name of the file, module, plugin, task or feature below,
+ *use your best guess if unsure*. Do not include `community.general.`!
placeholder: mysql_user
validations:
required: true
diff --git a/ansible_collections/community/general/.github/ISSUE_TEMPLATE/feature_request.yml b/ansible_collections/community/general/.github/ISSUE_TEMPLATE/feature_request.yml
index 9630b67e1..f34564283 100644
--- a/ansible_collections/community/general/.github/ISSUE_TEMPLATE/feature_request.yml
+++ b/ansible_collections/community/general/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -42,8 +42,8 @@ body:
attributes:
label: Component Name
description: >-
- Write the short name of the module, plugin, task or feature below,
- *use your best guess if unsure*.
+ Write the short name of the module or plugin, or which other part(s) of the collection this feature affects.
+ *use your best guess if unsure*. Do not include `community.general.`!
placeholder: dnf, apt, yum, pip, user etc.
validations:
required: true
diff --git a/ansible_collections/community/general/.github/pull_request_template.md b/ansible_collections/community/general/.github/pull_request_template.md
new file mode 100644
index 000000000..29a2d2e36
--- /dev/null
+++ b/ansible_collections/community/general/.github/pull_request_template.md
@@ -0,0 +1,32 @@
+##### SUMMARY
+<!--- Describe the change below, including rationale and design decisions -->
+
+<!--- HINT: Include "Fixes #nnn" if you are fixing an existing issue -->
+
+<!--- Please do not forget to include a changelog fragment:
+ https://docs.ansible.com/ansible/devel/community/collection_development_process.html#creating-changelog-fragments
+ No need to include one for docs-only or test-only PR, and for new plugin/module PRs.
+ Read about more details in CONTRIBUTING.md.
+ -->
+
+##### ISSUE TYPE
+<!--- Pick one or more below and delete the rest.
+ 'Test Pull Request' is for PRs that add/extend tests without code changes. -->
+- Bugfix Pull Request
+- Docs Pull Request
+- Feature Pull Request
+- New Module/Plugin Pull Request
+- Refactoring Pull Request
+- Test Pull Request
+
+##### COMPONENT NAME
+<!--- Write the SHORT NAME of the module, plugin, task or feature below. -->
+
+##### ADDITIONAL INFORMATION
+<!--- Include additional information to help people understand the change here -->
+<!--- A step-by-step reproduction of the problem is helpful if there is no related issue -->
+
+<!--- Paste verbatim command output below, e.g. before and after your change -->
+```paste below
+
+```
diff --git a/ansible_collections/community/general/.github/pull_request_template.md.license b/ansible_collections/community/general/.github/pull_request_template.md.license
new file mode 100644
index 000000000..a1390a69e
--- /dev/null
+++ b/ansible_collections/community/general/.github/pull_request_template.md.license
@@ -0,0 +1,3 @@
+Copyright (c) Ansible Project
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
diff --git a/ansible_collections/community/general/.github/workflows/ansible-test.yml b/ansible_collections/community/general/.github/workflows/ansible-test.yml
index 8d5809cda..bc9daaa43 100644
--- a/ansible_collections/community/general/.github/workflows/ansible-test.yml
+++ b/ansible_collections/community/general/.github/workflows/ansible-test.yml
@@ -14,9 +14,9 @@ on:
- main
- stable-*
pull_request:
- # Run EOL CI once per day (at 10:00 UTC)
+ # Run EOL CI once per day (at 08:00 UTC)
schedule:
- - cron: '0 10 * * *'
+ - cron: '0 8 * * *'
concurrency:
# Make sure there is at most one active run per PR, but do not cancel any non-PR runs
@@ -29,22 +29,17 @@ jobs:
strategy:
matrix:
ansible:
- - '2.11'
- - '2.12'
+ - '2.13'
# Ansible-test on various stable branches does not yet work well with cgroups v2.
# Since ubuntu-latest now uses Ubuntu 22.04, we need to fall back to the ubuntu-20.04
# image for these stable branches. The list of branches where this is necessary will
# shrink over time, check out https://github.com/ansible-collections/news-for-maintainers/issues/28
# for the latest list.
- runs-on: >-
- ${{ contains(fromJson(
- '["2.9", "2.10", "2.11"]'
- ), matrix.ansible) && 'ubuntu-20.04' || 'ubuntu-latest' }}
+ runs-on: ubuntu-latest
steps:
- name: Perform sanity testing
uses: felixfontein/ansible-test-gh-action@main
with:
- ansible-core-github-repository-slug: ${{ contains(fromJson('["2.10", "2.11"]'), matrix.ansible) && 'felixfontein/ansible' || 'ansible/ansible' }}
ansible-core-version: stable-${{ matrix.ansible }}
coverage: ${{ github.event_name == 'schedule' && 'always' || 'never' }}
pull-request-change-detection: 'true'
@@ -56,10 +51,7 @@ jobs:
# image for these stable branches. The list of branches where this is necessary will
# shrink over time, check out https://github.com/ansible-collections/news-for-maintainers/issues/28
# for the latest list.
- runs-on: >-
- ${{ contains(fromJson(
- '["2.9", "2.10", "2.11"]'
- ), matrix.ansible) && 'ubuntu-20.04' || 'ubuntu-latest' }}
+ runs-on: ubuntu-latest
name: EOL Units (Ⓐ${{ matrix.ansible }}+py${{ matrix.python }})
strategy:
# As soon as the first unit test fails, cancel the others to free up the CI queue
@@ -72,13 +64,13 @@ jobs:
exclude:
- ansible: ''
include:
- - ansible: '2.11'
+ - ansible: '2.13'
python: '2.7'
- - ansible: '2.11'
- python: '3.5'
- - ansible: '2.12'
- python: '2.6'
- - ansible: '2.12'
+ - ansible: '2.13'
+ python: '3.8'
+ - ansible: '2.13'
+ python: '2.7'
+ - ansible: '2.13'
python: '3.8'
steps:
@@ -87,7 +79,6 @@ jobs:
Ansible version ${{ matrix.ansible }}
uses: felixfontein/ansible-test-gh-action@main
with:
- ansible-core-github-repository-slug: ${{ contains(fromJson('["2.10", "2.11"]'), matrix.ansible) && 'felixfontein/ansible' || 'ansible/ansible' }}
ansible-core-version: stable-${{ matrix.ansible }}
coverage: ${{ github.event_name == 'schedule' && 'always' || 'never' }}
pre-test-cmd: >-
@@ -104,10 +95,7 @@ jobs:
# image for these stable branches. The list of branches where this is necessary will
# shrink over time, check out https://github.com/ansible-collections/news-for-maintainers/issues/28
# for the latest list.
- runs-on: >-
- ${{ contains(fromJson(
- '["2.9", "2.10", "2.11"]'
- ), matrix.ansible) && 'ubuntu-20.04' || 'ubuntu-latest' }}
+ runs-on: ubuntu-latest
name: EOL I (Ⓐ${{ matrix.ansible }}+${{ matrix.docker }}+py${{ matrix.python }}:${{ matrix.target }})
strategy:
fail-fast: false
@@ -123,93 +111,47 @@ jobs:
exclude:
- ansible: ''
include:
- # 2.11
- - ansible: '2.11'
- docker: fedora32
+ # 2.13
+ - ansible: '2.13'
+ docker: fedora35
python: ''
target: azp/posix/1/
- - ansible: '2.11'
- docker: fedora32
+ - ansible: '2.13'
+ docker: fedora35
python: ''
target: azp/posix/2/
- - ansible: '2.11'
- docker: fedora32
+ - ansible: '2.13'
+ docker: fedora35
python: ''
target: azp/posix/3/
- - ansible: '2.11'
- docker: fedora33
+ - ansible: '2.13'
+ docker: opensuse15py2
python: ''
target: azp/posix/1/
- - ansible: '2.11'
- docker: fedora33
+ - ansible: '2.13'
+ docker: opensuse15py2
python: ''
target: azp/posix/2/
- - ansible: '2.11'
- docker: fedora33
+ - ansible: '2.13'
+ docker: opensuse15py2
python: ''
target: azp/posix/3/
- - ansible: '2.11'
+ - ansible: '2.13'
docker: alpine3
python: ''
target: azp/posix/1/
- - ansible: '2.11'
+ - ansible: '2.13'
docker: alpine3
python: ''
target: azp/posix/2/
- - ansible: '2.11'
+ - ansible: '2.13'
docker: alpine3
python: ''
target: azp/posix/3/
# Right now all generic tests are disabled. Uncomment when at least one of them is re-enabled.
- # - ansible: '2.11'
- # docker: default
- # python: '2.7'
- # target: azp/generic/1/
- # - ansible: '2.11'
- # docker: default
- # python: '3.5'
- # target: azp/generic/1/
- # 2.12
- - ansible: '2.12'
- docker: centos6
- python: ''
- target: azp/posix/1/
- - ansible: '2.12'
- docker: centos6
- python: ''
- target: azp/posix/2/
- - ansible: '2.12'
- docker: centos6
- python: ''
- target: azp/posix/3/
- - ansible: '2.12'
- docker: fedora34
- python: ''
- target: azp/posix/1/
- - ansible: '2.12'
- docker: fedora34
- python: ''
- target: azp/posix/2/
- - ansible: '2.12'
- docker: fedora34
- python: ''
- target: azp/posix/3/
- - ansible: '2.12'
- docker: ubuntu1804
- python: ''
- target: azp/posix/1/
- - ansible: '2.12'
- docker: ubuntu1804
- python: ''
- target: azp/posix/2/
- - ansible: '2.12'
- docker: ubuntu1804
- python: ''
- target: azp/posix/3/
- # Right now all generic tests are disabled. Uncomment when at least one of them is re-enabled.
- # - ansible: '2.12'
+ # - ansible: '2.13'
# docker: default
- # python: '3.8'
+ # python: '3.9'
# target: azp/generic/1/
steps:
@@ -219,7 +161,6 @@ jobs:
under Python ${{ matrix.python }}
uses: felixfontein/ansible-test-gh-action@main
with:
- ansible-core-github-repository-slug: ${{ contains(fromJson('["2.10", "2.11"]'), matrix.ansible) && 'felixfontein/ansible' || 'ansible/ansible' }}
ansible-core-version: stable-${{ matrix.ansible }}
coverage: ${{ github.event_name == 'schedule' && 'always' || 'never' }}
docker-image: ${{ matrix.docker }}
diff --git a/ansible_collections/community/general/.github/workflows/codeql-analysis.yml b/ansible_collections/community/general/.github/workflows/codeql-analysis.yml
index f7ab9450c..c93162a72 100644
--- a/ansible_collections/community/general/.github/workflows/codeql-analysis.yml
+++ b/ansible_collections/community/general/.github/workflows/codeql-analysis.yml
@@ -8,6 +8,7 @@ name: "Code scanning - action"
on:
schedule:
- cron: '26 19 * * 1'
+ workflow_dispatch:
permissions:
contents: read
@@ -23,39 +24,13 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v3
- with:
- # We must fetch at least the immediate parents so that if this is
- # a pull request then we can checkout the head.
- fetch-depth: 2
-
- # If this run was triggered by a pull request event, then checkout
- # the head of the pull request instead of the merge commit.
- - run: git checkout HEAD^2
- if: ${{ github.event_name == 'pull_request' }}
+ uses: actions/checkout@v4
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
- uses: github/codeql-action/init@v2
- # Override language selection by uncommenting this and choosing your languages
- # with:
- # languages: go, javascript, csharp, python, cpp, java
-
- # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
- # If this step fails, then you should remove it and run the build manually (see below)
- - name: Autobuild
- uses: github/codeql-action/autobuild@v2
-
- # ℹ️ Command-line programs to run using the OS shell.
- # 📚 https://git.io/JvXDl
-
- # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
- # and modify them (or add more) to build your code if your project
- # uses a compiled language
-
- #- run: |
- # make bootstrap
- # make release
+ uses: github/codeql-action/init@v3
+ with:
+ languages: python
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v2
+ uses: github/codeql-action/analyze@v3
diff --git a/ansible_collections/community/general/.github/workflows/import-galaxy.yml b/ansible_collections/community/general/.github/workflows/import-galaxy.yml
new file mode 100644
index 000000000..0c0ee402a
--- /dev/null
+++ b/ansible_collections/community/general/.github/workflows/import-galaxy.yml
@@ -0,0 +1,20 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+name: import-galaxy
+'on':
+ # Run CI against all pushes (direct commits, also merged PRs) to main, and all Pull Requests
+ push:
+ branches:
+ - main
+ - stable-*
+ pull_request:
+
+jobs:
+ import-galaxy:
+ permissions:
+ contents: read
+ name: Test to import built collection artifact with Galaxy importer
+ uses: ansible-community/github-action-test-galaxy-import/.github/workflows/test-galaxy-import.yml@main
diff --git a/ansible_collections/community/general/.github/workflows/reuse.yml b/ansible_collections/community/general/.github/workflows/reuse.yml
index 8467668f1..031e94cb7 100644
--- a/ansible_collections/community/general/.github/workflows/reuse.yml
+++ b/ansible_collections/community/general/.github/workflows/reuse.yml
@@ -22,14 +22,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha || '' }}
- - name: Install dependencies
- run: |
- pip install reuse
-
- - name: Check REUSE compliance
- run: |
- reuse lint
+ - name: REUSE Compliance Check
+ uses: fsfe/reuse-action@v3
diff --git a/ansible_collections/community/general/.pre-commit-config.yaml b/ansible_collections/community/general/.pre-commit-config.yaml
deleted file mode 100644
index 7e3d19094..000000000
--- a/ansible_collections/community/general/.pre-commit-config.yaml
+++ /dev/null
@@ -1,23 +0,0 @@
----
-# Copyright (c) Ansible Project
-# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
-# SPDX-License-Identifier: GPL-3.0-or-later
-
-repos:
- - repo: https://github.com/pre-commit/pre-commit-hooks
- rev: v4.0.1
- hooks:
- - id: trailing-whitespace
- - id: end-of-file-fixer
- - id: mixed-line-ending
- args: [--fix=lf]
- - id: fix-encoding-pragma
- - id: check-ast
- - id: check-merge-conflict
- - id: check-symlinks
- - repo: https://github.com/pre-commit/pygrep-hooks
- rev: v1.9.0
- hooks:
- - id: rst-backticks
- types: [file]
- files: changelogs/fragments/.*\.(yml|yaml)$
diff --git a/ansible_collections/community/general/CHANGELOG.md b/ansible_collections/community/general/CHANGELOG.md
new file mode 100644
index 000000000..08cac8a97
--- /dev/null
+++ b/ansible_collections/community/general/CHANGELOG.md
@@ -0,0 +1,708 @@
+# Community General Release Notes
+
+**Topics**
+
+- <a href="#v8-5-0">v8\.5\.0</a>
+ - <a href="#release-summary">Release Summary</a>
+ - <a href="#minor-changes">Minor Changes</a>
+ - <a href="#security-fixes">Security Fixes</a>
+ - <a href="#bugfixes">Bugfixes</a>
+ - <a href="#new-modules">New Modules</a>
+- <a href="#v8-4-0">v8\.4\.0</a>
+ - <a href="#release-summary-1">Release Summary</a>
+ - <a href="#minor-changes-1">Minor Changes</a>
+ - <a href="#bugfixes-1">Bugfixes</a>
+ - <a href="#new-plugins">New Plugins</a>
+ - <a href="#callback">Callback</a>
+ - <a href="#filter">Filter</a>
+ - <a href="#new-modules-1">New Modules</a>
+- <a href="#v8-3-0">v8\.3\.0</a>
+ - <a href="#release-summary-2">Release Summary</a>
+ - <a href="#minor-changes-2">Minor Changes</a>
+ - <a href="#deprecated-features">Deprecated Features</a>
+ - <a href="#bugfixes-2">Bugfixes</a>
+ - <a href="#new-modules-2">New Modules</a>
+- <a href="#v8-2-0">v8\.2\.0</a>
+ - <a href="#release-summary-3">Release Summary</a>
+ - <a href="#minor-changes-3">Minor Changes</a>
+ - <a href="#bugfixes-3">Bugfixes</a>
+ - <a href="#new-plugins-1">New Plugins</a>
+ - <a href="#connection">Connection</a>
+ - <a href="#filter-1">Filter</a>
+ - <a href="#lookup">Lookup</a>
+ - <a href="#new-modules-3">New Modules</a>
+- <a href="#v8-1-0">v8\.1\.0</a>
+ - <a href="#release-summary-4">Release Summary</a>
+ - <a href="#minor-changes-4">Minor Changes</a>
+ - <a href="#bugfixes-4">Bugfixes</a>
+ - <a href="#new-plugins-2">New Plugins</a>
+ - <a href="#lookup-1">Lookup</a>
+ - <a href="#test">Test</a>
+ - <a href="#new-modules-4">New Modules</a>
+- <a href="#v8-0-2">v8\.0\.2</a>
+ - <a href="#release-summary-5">Release Summary</a>
+ - <a href="#bugfixes-5">Bugfixes</a>
+- <a href="#v8-0-1">v8\.0\.1</a>
+ - <a href="#release-summary-6">Release Summary</a>
+ - <a href="#bugfixes-6">Bugfixes</a>
+- <a href="#v8-0-0">v8\.0\.0</a>
+ - <a href="#release-summary-7">Release Summary</a>
+ - <a href="#minor-changes-5">Minor Changes</a>
+ - <a href="#breaking-changes--porting-guide">Breaking Changes / Porting Guide</a>
+ - <a href="#deprecated-features-1">Deprecated Features</a>
+ - <a href="#removed-features-previously-deprecated">Removed Features \(previously deprecated\)</a>
+ - <a href="#bugfixes-7">Bugfixes</a>
+ - <a href="#known-issues">Known Issues</a>
+ - <a href="#new-plugins-3">New Plugins</a>
+ - <a href="#lookup-2">Lookup</a>
+ - <a href="#new-modules-5">New Modules</a>
+This changelog describes changes after version 7\.0\.0\.
+
+<a id="v8-5-0"></a>
+## v8\.5\.0
+
+<a id="release-summary"></a>
+### Release Summary
+
+Regular feature and bugfix release with security fixes\.
+
+<a id="minor-changes"></a>
+### Minor Changes
+
+* bitwarden lookup plugin \- allows to fetch all records of a given collection ID\, by allowing to pass an empty value for <code>search\_value</code> when <code>collection\_id</code> is provided \([https\://github\.com/ansible\-collections/community\.general/pull/8013](https\://github\.com/ansible\-collections/community\.general/pull/8013)\)\.
+* icinga2 inventory plugin \- adds new parameter <code>group\_by\_hostgroups</code> in order to make grouping by Icinga2 hostgroups optional \([https\://github\.com/ansible\-collections/community\.general/pull/7998](https\://github\.com/ansible\-collections/community\.general/pull/7998)\)\.
+* ini\_file \- support optional spaces between section names and their surrounding brackets \([https\://github\.com/ansible\-collections/community\.general/pull/8075](https\://github\.com/ansible\-collections/community\.general/pull/8075)\)\.
+* java\_cert \- enable <code>owner</code>\, <code>group</code>\, <code>mode</code>\, and other generic file arguments \([https\://github\.com/ansible\-collections/community\.general/pull/8116](https\://github\.com/ansible\-collections/community\.general/pull/8116)\)\.
+* ldap\_attrs \- module now supports diff mode\, showing which attributes are changed within an operation \([https\://github\.com/ansible\-collections/community\.general/pull/8073](https\://github\.com/ansible\-collections/community\.general/pull/8073)\)\.
+* lxd\_container \- uses <code>/1\.0/instances</code> API endpoint\, if available\. Falls back to <code>/1\.0/containers</code> or <code>/1\.0/virtual\-machines</code>\. Fixes issue when using Incus or LXD 5\.19 due to migrating to <code>/1\.0/instances</code> endpoint \([https\://github\.com/ansible\-collections/community\.general/pull/7980](https\://github\.com/ansible\-collections/community\.general/pull/7980)\)\.
+* nmcli \- allow setting <code>MTU</code> for <code>bond\-slave</code> interface types \([https\://github\.com/ansible\-collections/community\.general/pull/8118](https\://github\.com/ansible\-collections/community\.general/pull/8118)\)\.
+* proxmox \- adds <code>startup</code> parameters to configure startup order\, startup delay and shutdown delay \([https\://github\.com/ansible\-collections/community\.general/pull/8038](https\://github\.com/ansible\-collections/community\.general/pull/8038)\)\.
+* revbitspss lookup plugin \- removed a redundant unicode prefix\. The prefix was not necessary for Python 3 and has been cleaned up to streamline the code \([https\://github\.com/ansible\-collections/community\.general/pull/8087](https\://github\.com/ansible\-collections/community\.general/pull/8087)\)\.
+
+<a id="security-fixes"></a>
+### Security Fixes
+
+* cobbler\, gitlab\_runners\, icinga2\, linode\, lxd\, nmap\, online\, opennebula\, proxmox\, scaleway\, stackpath\_compute\, virtualbox\, and xen\_orchestra inventory plugin \- make sure all data received from the remote servers is marked as unsafe\, so remote code execution by obtaining texts that can be evaluated as templates is not possible \([https\://www\.die\-welt\.net/2024/03/remote\-code\-execution\-in\-ansible\-dynamic\-inventory\-plugins/](https\://www\.die\-welt\.net/2024/03/remote\-code\-execution\-in\-ansible\-dynamic\-inventory\-plugins/)\, [https\://github\.com/ansible\-collections/community\.general/pull/8098](https\://github\.com/ansible\-collections/community\.general/pull/8098)\)\.
+
+<a id="bugfixes"></a>
+### Bugfixes
+
+* aix\_filesystem \- fix issue with empty list items in crfs logic and option order \([https\://github\.com/ansible\-collections/community\.general/pull/8052](https\://github\.com/ansible\-collections/community\.general/pull/8052)\)\.
+* consul\_token \- fix token creation without <code>accessor\_id</code> \([https\://github\.com/ansible\-collections/community\.general/pull/8091](https\://github\.com/ansible\-collections/community\.general/pull/8091)\)\.
+* homebrew \- error returned from brew command was ignored and tried to parse empty JSON\. Fix now checks for an error and raises it to give accurate error message to users \([https\://github\.com/ansible\-collections/community\.general/issues/8047](https\://github\.com/ansible\-collections/community\.general/issues/8047)\)\.
+* ipa\_hbacrule \- the module uses a string for <code>ipaenabledflag</code> for new FreeIPA versions while the returned value is a boolean \([https\://github\.com/ansible\-collections/community\.general/pull/7880](https\://github\.com/ansible\-collections/community\.general/pull/7880)\)\.
+* ipa\_sudorule \- the module uses a string for <code>ipaenabledflag</code> for new FreeIPA versions while the returned value is a boolean \([https\://github\.com/ansible\-collections/community\.general/pull/7880](https\://github\.com/ansible\-collections/community\.general/pull/7880)\)\.
+* iptables\_state \- fix idempotency issues when restoring incomplete iptables dumps \([https\://github\.com/ansible\-collections/community\.general/issues/8029](https\://github\.com/ansible\-collections/community\.general/issues/8029)\)\.
+* linode inventory plugin \- add descriptive error message for linode inventory plugin \([https\://github\.com/ansible\-collections/community\.general/pull/8133](https\://github\.com/ansible\-collections/community\.general/pull/8133)\)\.
+* pacemaker\_cluster \- actually implement check mode\, which the module claims to support\. This means that until now the module also did changes in check mode \([https\://github\.com/ansible\-collections/community\.general/pull/8081](https\://github\.com/ansible\-collections/community\.general/pull/8081)\)\.
+* pam\_limits \- when the file does not exist\, do not create it in check mode \([https\://github\.com/ansible\-collections/community\.general/issues/8050](https\://github\.com/ansible\-collections/community\.general/issues/8050)\, [https\://github\.com/ansible\-collections/community\.general/pull/8057](https\://github\.com/ansible\-collections/community\.general/pull/8057)\)\.
+* proxmox\_kvm \- fixed status check getting from node\-specific API endpoint \([https\://github\.com/ansible\-collections/community\.general/issues/7817](https\://github\.com/ansible\-collections/community\.general/issues/7817)\)\.
+
+<a id="new-modules"></a>
+### New Modules
+
+* usb\_facts \- Allows listing information about USB devices
+
+<a id="v8-4-0"></a>
+## v8\.4\.0
+
+<a id="release-summary-1"></a>
+### Release Summary
+
+Regular bugfix and feature release\.
+
+<a id="minor-changes-1"></a>
+### Minor Changes
+
+* bitwarden lookup plugin \- add <code>bw\_session</code> option\, to pass session key instead of reading from env \([https\://github\.com/ansible\-collections/community\.general/pull/7994](https\://github\.com/ansible\-collections/community\.general/pull/7994)\)\.
+* gitlab\_deploy\_key\, gitlab\_group\_members\, gitlab\_group\_variable\, gitlab\_hook\, gitlab\_instance\_variable\, gitlab\_project\_badge\, gitlab\_project\_variable\, gitlab\_user \- improve API pagination and compatibility with different versions of <code>python\-gitlab</code> \([https\://github\.com/ansible\-collections/community\.general/pull/7790](https\://github\.com/ansible\-collections/community\.general/pull/7790)\)\.
+* gitlab\_hook \- adds <code>releases\_events</code> parameter for supporting Releases events triggers on GitLab hooks \([https\://github\.com/ansible\-collections/community\.general/pull/7956](https\://github\.com/ansible\-collections/community\.general/pull/7956)\)\.
+* icinga2 inventory plugin \- add Jinja2 templating support to <code>url</code>\, <code>user</code>\, and <code>password</code> paramenters \([https\://github\.com/ansible\-collections/community\.general/issues/7074](https\://github\.com/ansible\-collections/community\.general/issues/7074)\, [https\://github\.com/ansible\-collections/community\.general/pull/7996](https\://github\.com/ansible\-collections/community\.general/pull/7996)\)\.
+* mssql\_script \- adds transactional \(rollback/commit\) support via optional boolean param <code>transaction</code> \([https\://github\.com/ansible\-collections/community\.general/pull/7976](https\://github\.com/ansible\-collections/community\.general/pull/7976)\)\.
+* proxmox\_kvm \- add parameter <code>update\_unsafe</code> to avoid limitations when updating dangerous values \([https\://github\.com/ansible\-collections/community\.general/pull/7843](https\://github\.com/ansible\-collections/community\.general/pull/7843)\)\.
+* redfish\_config \- add command <code>SetServiceIdentification</code> to set service identification \([https\://github\.com/ansible\-collections/community\.general/issues/7916](https\://github\.com/ansible\-collections/community\.general/issues/7916)\)\.
+* sudoers \- add support for the <code>NOEXEC</code> tag in sudoers rules \([https\://github\.com/ansible\-collections/community\.general/pull/7983](https\://github\.com/ansible\-collections/community\.general/pull/7983)\)\.
+* terraform \- fix <code>diff\_mode</code> in state <code>absent</code> and when terraform <code>resource\_changes</code> does not exist \([https\://github\.com/ansible\-collections/community\.general/pull/7963](https\://github\.com/ansible\-collections/community\.general/pull/7963)\)\.
+
+<a id="bugfixes-1"></a>
+### Bugfixes
+
+* cargo \- fix idempotency issues when using a custom installation path for packages \(using the <code>\-\-path</code> parameter\)\. The initial installation runs fine\, but subsequent runs use the <code>get\_installed\(\)</code> function which did not check the given installation location\, before running <code>cargo install</code>\. This resulted in a false <code>changed</code> state\. Also the removal of packeges using <code>state\: absent</code> failed\, as the installation check did not use the given parameter \([https\://github\.com/ansible\-collections/community\.general/pull/7970](https\://github\.com/ansible\-collections/community\.general/pull/7970)\)\.
+* gitlab\_issue \- fix behavior to search GitLab issue\, using <code>search</code> keyword instead of <code>title</code> \([https\://github\.com/ansible\-collections/community\.general/issues/7846](https\://github\.com/ansible\-collections/community\.general/issues/7846)\)\.
+* gitlab\_runner \- fix pagination when checking for existing runners \([https\://github\.com/ansible\-collections/community\.general/pull/7790](https\://github\.com/ansible\-collections/community\.general/pull/7790)\)\.
+* keycloak\_client \- fixes issue when metadata is provided in desired state when task is in check mode \([https\://github\.com/ansible\-collections/community\.general/issues/1226](https\://github\.com/ansible\-collections/community\.general/issues/1226)\, [https\://github\.com/ansible\-collections/community\.general/pull/7881](https\://github\.com/ansible\-collections/community\.general/pull/7881)\)\.
+* modprobe \- listing modules files or modprobe files could trigger a FileNotFoundError if <code>/etc/modprobe\.d</code> or <code>/etc/modules\-load\.d</code> did not exist\. Relevant functions now return empty lists if the directories do not exist to avoid crashing the module \([https\://github\.com/ansible\-collections/community\.general/issues/7717](https\://github\.com/ansible\-collections/community\.general/issues/7717)\)\.
+* onepassword lookup plugin \- failed for fields that were in sections and had uppercase letters in the label/ID\. Field lookups are now case insensitive in all cases \([https\://github\.com/ansible\-collections/community\.general/pull/7919](https\://github\.com/ansible\-collections/community\.general/pull/7919)\)\.
+* pkgin \- pkgin \(pkgsrc package manager used by SmartOS\) raises erratic exceptions and spurious <code>changed\=true</code> \([https\://github\.com/ansible\-collections/community\.general/pull/7971](https\://github\.com/ansible\-collections/community\.general/pull/7971)\)\.
+* redfish\_info \- allow for a GET operation invoked by <code>GetUpdateStatus</code> to allow for an empty response body for cases where a service returns 204 No Content \([https\://github\.com/ansible\-collections/community\.general/issues/8003](https\://github\.com/ansible\-collections/community\.general/issues/8003)\)\.
+* redfish\_info \- correct uncaught exception when attempting to retrieve <code>Chassis</code> information \([https\://github\.com/ansible\-collections/community\.general/pull/7952](https\://github\.com/ansible\-collections/community\.general/pull/7952)\)\.
+
+<a id="new-plugins"></a>
+### New Plugins
+
+<a id="callback"></a>
+#### Callback
+
+* default\_without\_diff \- The default ansible callback without diff output
+
+<a id="filter"></a>
+#### Filter
+
+* lists\_difference \- Difference of lists with a predictive order
+* lists\_intersect \- Intersection of lists with a predictive order
+* lists\_symmetric\_difference \- Symmetric Difference of lists with a predictive order
+* lists\_union \- Union of lists with a predictive order
+
+<a id="new-modules-1"></a>
+### New Modules
+
+* gitlab\_group\_access\_token \- Manages GitLab group access tokens
+* gitlab\_project\_access\_token \- Manages GitLab project access tokens
+
+<a id="v8-3-0"></a>
+## v8\.3\.0
+
+<a id="release-summary-2"></a>
+### Release Summary
+
+Regular bugfix and feature release\.
+
+<a id="minor-changes-2"></a>
+### Minor Changes
+
+* consul\_auth\_method\, consul\_binding\_rule\, consul\_policy\, consul\_role\, consul\_session\, consul\_token \- added action group <code>community\.general\.consul</code> \([https\://github\.com/ansible\-collections/community\.general/pull/7897](https\://github\.com/ansible\-collections/community\.general/pull/7897)\)\.
+* consul\_policy \- added support for diff and check mode \([https\://github\.com/ansible\-collections/community\.general/pull/7878](https\://github\.com/ansible\-collections/community\.general/pull/7878)\)\.
+* consul\_policy\, consul\_role\, consul\_session \- removed dependency on <code>requests</code> and factored out common parts \([https\://github\.com/ansible\-collections/community\.general/pull/7826](https\://github\.com/ansible\-collections/community\.general/pull/7826)\, [https\://github\.com/ansible\-collections/community\.general/pull/7878](https\://github\.com/ansible\-collections/community\.general/pull/7878)\)\.
+* consul\_role \- <code>node\_identities</code> now expects a <code>node\_name</code> option to match the Consul API\, the old <code>name</code> is still supported as alias \([https\://github\.com/ansible\-collections/community\.general/pull/7878](https\://github\.com/ansible\-collections/community\.general/pull/7878)\)\.
+* consul\_role \- <code>service\_identities</code> now expects a <code>service\_name</code> option to match the Consul API\, the old <code>name</code> is still supported as alias \([https\://github\.com/ansible\-collections/community\.general/pull/7878](https\://github\.com/ansible\-collections/community\.general/pull/7878)\)\.
+* consul\_role \- added support for diff mode \([https\://github\.com/ansible\-collections/community\.general/pull/7878](https\://github\.com/ansible\-collections/community\.general/pull/7878)\)\.
+* consul\_role \- added support for templated policies \([https\://github\.com/ansible\-collections/community\.general/pull/7878](https\://github\.com/ansible\-collections/community\.general/pull/7878)\)\.
+* redfish\_info \- add command <code>GetServiceIdentification</code> to get service identification \([https\://github\.com/ansible\-collections/community\.general/issues/7882](https\://github\.com/ansible\-collections/community\.general/issues/7882)\)\.
+* terraform \- add support for <code>diff\_mode</code> for terraform resource\_changes \([https\://github\.com/ansible\-collections/community\.general/pull/7896](https\://github\.com/ansible\-collections/community\.general/pull/7896)\)\.
+
+<a id="deprecated-features"></a>
+### Deprecated Features
+
+* consul\_acl \- the module has been deprecated and will be removed in community\.general 10\.0\.0\. <code>consul\_token</code> and <code>consul\_policy</code> can be used instead \([https\://github\.com/ansible\-collections/community\.general/pull/7901](https\://github\.com/ansible\-collections/community\.general/pull/7901)\)\.
+
+<a id="bugfixes-2"></a>
+### Bugfixes
+
+* homebrew \- detect already installed formulae and casks using JSON output from <code>brew info</code> \([https\://github\.com/ansible\-collections/community\.general/issues/864](https\://github\.com/ansible\-collections/community\.general/issues/864)\)\.
+* incus connection plugin \- treats <code>inventory\_hostname</code> as a variable instead of a literal in remote connections \([https\://github\.com/ansible\-collections/community\.general/issues/7874](https\://github\.com/ansible\-collections/community\.general/issues/7874)\)\.
+* ipa\_otptoken \- the module expect <code>ipatokendisabled</code> as string but the <code>ipatokendisabled</code> value is returned as a boolean \([https\://github\.com/ansible\-collections/community\.general/pull/7795](https\://github\.com/ansible\-collections/community\.general/pull/7795)\)\.
+* ldap \- previously the order number \(if present\) was expected to follow an equals sign in the DN\. This makes it so the order number string is identified correctly anywhere within the DN \([https\://github\.com/ansible\-collections/community\.general/issues/7646](https\://github\.com/ansible\-collections/community\.general/issues/7646)\)\.
+* mssql\_script \- make the module work with Python 2 \([https\://github\.com/ansible\-collections/community\.general/issues/7818](https\://github\.com/ansible\-collections/community\.general/issues/7818)\, [https\://github\.com/ansible\-collections/community\.general/pull/7821](https\://github\.com/ansible\-collections/community\.general/pull/7821)\)\.
+* nmcli \- fix <code>connection\.slave\-type</code> wired to <code>bond</code> and not with parameter <code>slave\_type</code> in case of connection type <code>wifi</code> \([https\://github\.com/ansible\-collections/community\.general/issues/7389](https\://github\.com/ansible\-collections/community\.general/issues/7389)\)\.
+* proxmox \- fix updating a container config if the setting does not already exist \([https\://github\.com/ansible\-collections/community\.general/pull/7872](https\://github\.com/ansible\-collections/community\.general/pull/7872)\)\.
+
+<a id="new-modules-2"></a>
+### New Modules
+
+* consul\_acl\_bootstrap \- Bootstrap ACLs in Consul
+* consul\_auth\_method \- Manipulate Consul auth methods
+* consul\_binding\_rule \- Manipulate Consul binding rules
+* consul\_token \- Manipulate Consul tokens
+* gitlab\_label \- Creates/updates/deletes GitLab Labels belonging to project or group\.
+* gitlab\_milestone \- Creates/updates/deletes GitLab Milestones belonging to project or group
+
+<a id="v8-2-0"></a>
+## v8\.2\.0
+
+<a id="release-summary-3"></a>
+### Release Summary
+
+Regular bugfix and feature release\.
+
+<a id="minor-changes-3"></a>
+### Minor Changes
+
+* ipa\_dnsrecord \- adds ability to manage NS record types \([https\://github\.com/ansible\-collections/community\.general/pull/7737](https\://github\.com/ansible\-collections/community\.general/pull/7737)\)\.
+* ipa\_pwpolicy \- refactor module and exchange a sequence <code>if</code> statements with a <code>for</code> loop \([https\://github\.com/ansible\-collections/community\.general/pull/7723](https\://github\.com/ansible\-collections/community\.general/pull/7723)\)\.
+* ipa\_pwpolicy \- update module to support <code>maxrepeat</code>\, <code>maxsequence</code>\, <code>dictcheck</code>\, <code>usercheck</code>\, <code>gracelimit</code> parameters in FreeIPA password policies \([https\://github\.com/ansible\-collections/community\.general/pull/7723](https\://github\.com/ansible\-collections/community\.general/pull/7723)\)\.
+* keycloak\_realm\_key \- the <code>config\.algorithm</code> option now supports 8 additional key algorithms \([https\://github\.com/ansible\-collections/community\.general/pull/7698](https\://github\.com/ansible\-collections/community\.general/pull/7698)\)\.
+* keycloak\_realm\_key \- the <code>config\.certificate</code> option value is no longer defined with <code>no\_log\=True</code> \([https\://github\.com/ansible\-collections/community\.general/pull/7698](https\://github\.com/ansible\-collections/community\.general/pull/7698)\)\.
+* keycloak\_realm\_key \- the <code>provider\_id</code> option now supports RSA encryption key usage \(value <code>rsa\-enc</code>\) \([https\://github\.com/ansible\-collections/community\.general/pull/7698](https\://github\.com/ansible\-collections/community\.general/pull/7698)\)\.
+* keycloak\_user\_federation \- allow custom user storage providers to be set through <code>provider\_id</code> \([https\://github\.com/ansible\-collections/community\.general/pull/7789](https\://github\.com/ansible\-collections/community\.general/pull/7789)\)\.
+* mail \- add <code>Message\-ID</code> header\; which is required by some mail servers \([https\://github\.com/ansible\-collections/community\.general/pull/7740](https\://github\.com/ansible\-collections/community\.general/pull/7740)\)\.
+* mail module\, mail callback plugin \- allow to configure the domain name of the Message\-ID header with a new <code>message\_id\_domain</code> option \([https\://github\.com/ansible\-collections/community\.general/pull/7765](https\://github\.com/ansible\-collections/community\.general/pull/7765)\)\.
+* ssh\_config \- new feature to set <code>AddKeysToAgent</code> option to <code>yes</code> or <code>no</code> \([https\://github\.com/ansible\-collections/community\.general/pull/7703](https\://github\.com/ansible\-collections/community\.general/pull/7703)\)\.
+* ssh\_config \- new feature to set <code>IdentitiesOnly</code> option to <code>yes</code> or <code>no</code> \([https\://github\.com/ansible\-collections/community\.general/pull/7704](https\://github\.com/ansible\-collections/community\.general/pull/7704)\)\.
+* xcc\_redfish\_command \- added support for raw POSTs \(<code>command\=PostResource</code> in <code>category\=Raw</code>\) without a specific action info \([https\://github\.com/ansible\-collections/community\.general/pull/7746](https\://github\.com/ansible\-collections/community\.general/pull/7746)\)\.
+
+<a id="bugfixes-3"></a>
+### Bugfixes
+
+* keycloak\_identity\_provider \- <code>mappers</code> processing was not idempotent if the mappers configuration list had not been sorted by name \(in ascending order\)\. Fix resolves the issue by sorting mappers in the desired state using the same key which is used for obtaining existing state \([https\://github\.com/ansible\-collections/community\.general/pull/7418](https\://github\.com/ansible\-collections/community\.general/pull/7418)\)\.
+* keycloak\_identity\_provider \- it was not possible to reconfigure \(add\, remove\) <code>mappers</code> once they were created initially\. Removal was ignored\, adding new ones resulted in dropping the pre\-existing unmodified mappers\. Fix resolves the issue by supplying correct input to the internal update call \([https\://github\.com/ansible\-collections/community\.general/pull/7418](https\://github\.com/ansible\-collections/community\.general/pull/7418)\)\.
+* keycloak\_user \- when <code>force</code> is set\, but user does not exist\, do not try to delete it \([https\://github\.com/ansible\-collections/community\.general/pull/7696](https\://github\.com/ansible\-collections/community\.general/pull/7696)\)\.
+* proxmox\_kvm \- running <code>state\=template</code> will first check whether VM is already a template \([https\://github\.com/ansible\-collections/community\.general/pull/7792](https\://github\.com/ansible\-collections/community\.general/pull/7792)\)\.
+* statusio\_maintenance \- fix error caused by incorrectly formed API data payload\. Was raising \"Failed to create maintenance HTTP Error 400 Bad Request\" caused by bad data type for date/time and deprecated dict keys \([https\://github\.com/ansible\-collections/community\.general/pull/7754](https\://github\.com/ansible\-collections/community\.general/pull/7754)\)\.
+
+<a id="new-plugins-1"></a>
+### New Plugins
+
+<a id="connection"></a>
+#### Connection
+
+* incus \- Run tasks in Incus instances via the Incus CLI\.
+
+<a id="filter-1"></a>
+#### Filter
+
+* from\_ini \- Converts INI text input into a dictionary
+* to\_ini \- Converts a dictionary to the INI file format
+
+<a id="lookup"></a>
+#### Lookup
+
+* github\_app\_access\_token \- Obtain short\-lived Github App Access tokens
+
+<a id="new-modules-3"></a>
+### New Modules
+
+* dnf\_config\_manager \- Enable or disable dnf repositories using config\-manager
+* keycloak\_component\_info \- Retrive component info in Keycloak
+* keycloak\_realm\_rolemapping \- Allows administration of Keycloak realm role mappings into groups with the Keycloak API
+* proxmox\_node\_info \- Retrieve information about one or more Proxmox VE nodes
+* proxmox\_storage\_contents\_info \- List content from a Proxmox VE storage
+
+<a id="v8-1-0"></a>
+## v8\.1\.0
+
+<a id="release-summary-4"></a>
+### Release Summary
+
+Regular bugfix and feature release\.
+
+<a id="minor-changes-4"></a>
+### Minor Changes
+
+* bitwarden lookup plugin \- when looking for items using an item ID\, the item is now accessed directly with <code>bw get item</code> instead of searching through all items\. This doubles the lookup speed \([https\://github\.com/ansible\-collections/community\.general/pull/7468](https\://github\.com/ansible\-collections/community\.general/pull/7468)\)\.
+* elastic callback plugin \- close elastic client to not leak resources \([https\://github\.com/ansible\-collections/community\.general/pull/7517](https\://github\.com/ansible\-collections/community\.general/pull/7517)\)\.
+* git\_config \- allow multiple git configs for the same name with the new <code>add\_mode</code> option \([https\://github\.com/ansible\-collections/community\.general/pull/7260](https\://github\.com/ansible\-collections/community\.general/pull/7260)\)\.
+* git\_config \- the <code>after</code> and <code>before</code> fields in the <code>diff</code> of the return value can be a list instead of a string in case more configs with the same key are affected \([https\://github\.com/ansible\-collections/community\.general/pull/7260](https\://github\.com/ansible\-collections/community\.general/pull/7260)\)\.
+* git\_config \- when a value is unset\, all configs with the same key are unset \([https\://github\.com/ansible\-collections/community\.general/pull/7260](https\://github\.com/ansible\-collections/community\.general/pull/7260)\)\.
+* gitlab modules \- add <code>ca\_path</code> option \([https\://github\.com/ansible\-collections/community\.general/pull/7472](https\://github\.com/ansible\-collections/community\.general/pull/7472)\)\.
+* gitlab modules \- remove duplicate <code>gitlab</code> package check \([https\://github\.com/ansible\-collections/community\.general/pull/7486](https\://github\.com/ansible\-collections/community\.general/pull/7486)\)\.
+* gitlab\_runner \- add support for new runner creation workflow \([https\://github\.com/ansible\-collections/community\.general/pull/7199](https\://github\.com/ansible\-collections/community\.general/pull/7199)\)\.
+* ipa\_config \- adds <code>passkey</code> choice to <code>ipauserauthtype</code> parameter\'s choices \([https\://github\.com/ansible\-collections/community\.general/pull/7588](https\://github\.com/ansible\-collections/community\.general/pull/7588)\)\.
+* ipa\_sudorule \- adds options to include denied commands or command groups \([https\://github\.com/ansible\-collections/community\.general/pull/7415](https\://github\.com/ansible\-collections/community\.general/pull/7415)\)\.
+* ipa\_user \- adds <code>idp</code> and <code>passkey</code> choice to <code>ipauserauthtype</code> parameter\'s choices \([https\://github\.com/ansible\-collections/community\.general/pull/7589](https\://github\.com/ansible\-collections/community\.general/pull/7589)\)\.
+* irc \- add <code>validate\_certs</code> option\, and rename <code>use\_ssl</code> to <code>use\_tls</code>\, while keeping <code>use\_ssl</code> as an alias\. The default value for <code>validate\_certs</code> is <code>false</code> for backwards compatibility\. We recommend to every user of this module to explicitly set <code>use\_tls\=true</code> and <em class="title-reference">validate\_certs\=true\`</em> whenever possible\, especially when communicating to IRC servers over the internet \([https\://github\.com/ansible\-collections/community\.general/pull/7550](https\://github\.com/ansible\-collections/community\.general/pull/7550)\)\.
+* keycloak module utils \- expose error message from Keycloak server for HTTP errors in some specific situations \([https\://github\.com/ansible\-collections/community\.general/pull/7645](https\://github\.com/ansible\-collections/community\.general/pull/7645)\)\.
+* keycloak\_user\_federation \- add option for <code>krbPrincipalAttribute</code> \([https\://github\.com/ansible\-collections/community\.general/pull/7538](https\://github\.com/ansible\-collections/community\.general/pull/7538)\)\.
+* lvol \- change <code>pvs</code> argument type to list of strings \([https\://github\.com/ansible\-collections/community\.general/pull/7676](https\://github\.com/ansible\-collections/community\.general/pull/7676)\, [https\://github\.com/ansible\-collections/community\.general/issues/7504](https\://github\.com/ansible\-collections/community\.general/issues/7504)\)\.
+* lxd connection plugin \- tighten the detection logic for lxd <code>Instance not found</code> errors\, to avoid false detection on unrelated errors such as <code>/usr/bin/python3\: not found</code> \([https\://github\.com/ansible\-collections/community\.general/pull/7521](https\://github\.com/ansible\-collections/community\.general/pull/7521)\)\.
+* netcup\_dns \- adds support for record types <code>OPENPGPKEY</code>\, <code>SMIMEA</code>\, and <code>SSHFP</code> \([https\://github\.com/ansible\-collections/community\.general/pull/7489](https\://github\.com/ansible\-collections/community\.general/pull/7489)\)\.
+* nmcli \- add support for new connection type <code>loopback</code> \([https\://github\.com/ansible\-collections/community\.general/issues/6572](https\://github\.com/ansible\-collections/community\.general/issues/6572)\)\.
+* nmcli \- allow for <code>infiniband</code> slaves of <code>bond</code> interface types \([https\://github\.com/ansible\-collections/community\.general/pull/7569](https\://github\.com/ansible\-collections/community\.general/pull/7569)\)\.
+* nmcli \- allow for the setting of <code>MTU</code> for <code>infiniband</code> and <code>bond</code> interface types \([https\://github\.com/ansible\-collections/community\.general/pull/7499](https\://github\.com/ansible\-collections/community\.general/pull/7499)\)\.
+* onepassword lookup plugin \- support 1Password Connect with the opv2 client by setting the connect\_host and connect\_token parameters \([https\://github\.com/ansible\-collections/community\.general/pull/7116](https\://github\.com/ansible\-collections/community\.general/pull/7116)\)\.
+* onepassword\_raw lookup plugin \- support 1Password Connect with the opv2 client by setting the connect\_host and connect\_token parameters \([https\://github\.com/ansible\-collections/community\.general/pull/7116](https\://github\.com/ansible\-collections/community\.general/pull/7116)\)
+* passwordstore \- adds <code>timestamp</code> and <code>preserve</code> parameters to modify the stored password format \([https\://github\.com/ansible\-collections/community\.general/pull/7426](https\://github\.com/ansible\-collections/community\.general/pull/7426)\)\.
+* proxmox \- adds <code>template</code> value to the <code>state</code> parameter\, allowing conversion of container to a template \([https\://github\.com/ansible\-collections/community\.general/pull/7143](https\://github\.com/ansible\-collections/community\.general/pull/7143)\)\.
+* proxmox \- adds <code>update</code> parameter\, allowing update of an already existing containers configuration \([https\://github\.com/ansible\-collections/community\.general/pull/7540](https\://github\.com/ansible\-collections/community\.general/pull/7540)\)\.
+* proxmox inventory plugin \- adds an option to exclude nodes from the dynamic inventory generation\. The new setting is optional\, not using this option will behave as usual \([https\://github\.com/ansible\-collections/community\.general/issues/6714](https\://github\.com/ansible\-collections/community\.general/issues/6714)\, [https\://github\.com/ansible\-collections/community\.general/pull/7461](https\://github\.com/ansible\-collections/community\.general/pull/7461)\)\.
+* proxmox\_disk \- add ability to manipulate CD\-ROM drive \([https\://github\.com/ansible\-collections/community\.general/pull/7495](https\://github\.com/ansible\-collections/community\.general/pull/7495)\)\.
+* proxmox\_kvm \- adds <code>template</code> value to the <code>state</code> parameter\, allowing conversion of a VM to a template \([https\://github\.com/ansible\-collections/community\.general/pull/7143](https\://github\.com/ansible\-collections/community\.general/pull/7143)\)\.
+* proxmox\_kvm \- support the <code>hookscript</code> parameter \([https\://github\.com/ansible\-collections/community\.general/issues/7600](https\://github\.com/ansible\-collections/community\.general/issues/7600)\)\.
+* proxmox\_ostype \- it is now possible to specify the <code>ostype</code> when creating an LXC container \([https\://github\.com/ansible\-collections/community\.general/pull/7462](https\://github\.com/ansible\-collections/community\.general/pull/7462)\)\.
+* proxmox\_vm\_info \- add ability to retrieve configuration info \([https\://github\.com/ansible\-collections/community\.general/pull/7485](https\://github\.com/ansible\-collections/community\.general/pull/7485)\)\.
+* redfish\_info \- adding the <code>BootProgress</code> property when getting <code>Systems</code> info \([https\://github\.com/ansible\-collections/community\.general/pull/7626](https\://github\.com/ansible\-collections/community\.general/pull/7626)\)\.
+* ssh\_config \- adds <code>controlmaster</code>\, <code>controlpath</code> and <code>controlpersist</code> parameters \([https\://github\.com/ansible\-collections/community\.general/pull/7456](https\://github\.com/ansible\-collections/community\.general/pull/7456)\)\.
+
+<a id="bugfixes-4"></a>
+### Bugfixes
+
+* apt\-rpm \- the module did not upgrade packages if a newer version exists\. Now the package will be reinstalled if the candidate is newer than the installed version \([https\://github\.com/ansible\-collections/community\.general/issues/7414](https\://github\.com/ansible\-collections/community\.general/issues/7414)\)\.
+* cloudflare\_dns \- fix Cloudflare lookup of SHFP records \([https\://github\.com/ansible\-collections/community\.general/issues/7652](https\://github\.com/ansible\-collections/community\.general/issues/7652)\)\.
+* interface\_files \- also consider <code>address\_family</code> when changing <code>option\=method</code> \([https\://github\.com/ansible\-collections/community\.general/issues/7610](https\://github\.com/ansible\-collections/community\.general/issues/7610)\, [https\://github\.com/ansible\-collections/community\.general/pull/7612](https\://github\.com/ansible\-collections/community\.general/pull/7612)\)\.
+* irc \- replace <code>ssl\.wrap\_socket</code> that was removed from Python 3\.12 with code for creating a proper SSL context \([https\://github\.com/ansible\-collections/community\.general/pull/7542](https\://github\.com/ansible\-collections/community\.general/pull/7542)\)\.
+* keycloak\_\* \- fix Keycloak API client to quote <code>/</code> properly \([https\://github\.com/ansible\-collections/community\.general/pull/7641](https\://github\.com/ansible\-collections/community\.general/pull/7641)\)\.
+* keycloak\_authz\_permission \- resource payload variable for scope\-based permission was constructed as a string\, when it needs to be a list\, even for a single item \([https\://github\.com/ansible\-collections/community\.general/issues/7151](https\://github\.com/ansible\-collections/community\.general/issues/7151)\)\.
+* log\_entries callback plugin \- replace <code>ssl\.wrap\_socket</code> that was removed from Python 3\.12 with code for creating a proper SSL context \([https\://github\.com/ansible\-collections/community\.general/pull/7542](https\://github\.com/ansible\-collections/community\.general/pull/7542)\)\.
+* lvol \- test for output messages in both <code>stdout</code> and <code>stderr</code> \([https\://github\.com/ansible\-collections/community\.general/pull/7601](https\://github\.com/ansible\-collections/community\.general/pull/7601)\, [https\://github\.com/ansible\-collections/community\.general/issues/7182](https\://github\.com/ansible\-collections/community\.general/issues/7182)\)\.
+* onepassword lookup plugin \- field and section titles are now case insensitive when using op CLI version two or later\. This matches the behavior of version one \([https\://github\.com/ansible\-collections/community\.general/pull/7564](https\://github\.com/ansible\-collections/community\.general/pull/7564)\)\.
+* redhat\_subscription \- use the D\-Bus registration on RHEL 7 only on 7\.4 and
+ greater\; older versions of RHEL 7 do not have it
+ \([https\://github\.com/ansible\-collections/community\.general/issues/7622](https\://github\.com/ansible\-collections/community\.general/issues/7622)\,
+ [https\://github\.com/ansible\-collections/community\.general/pull/7624](https\://github\.com/ansible\-collections/community\.general/pull/7624)\)\.
+* terraform \- fix multiline string handling in complex variables \([https\://github\.com/ansible\-collections/community\.general/pull/7535](https\://github\.com/ansible\-collections/community\.general/pull/7535)\)\.
+
+<a id="new-plugins-2"></a>
+### New Plugins
+
+<a id="lookup-1"></a>
+#### Lookup
+
+* onepassword\_doc \- Fetch documents stored in 1Password
+
+<a id="test"></a>
+#### Test
+
+* fqdn\_valid \- Validates fully\-qualified domain names against RFC 1123
+
+<a id="new-modules-4"></a>
+### New Modules
+
+* git\_config\_info \- Read git configuration
+* gitlab\_issue \- Create\, update\, or delete GitLab issues
+* nomad\_token \- Manage Nomad ACL tokens
+
+<a id="v8-0-2"></a>
+## v8\.0\.2
+
+<a id="release-summary-5"></a>
+### Release Summary
+
+Bugfix release for inclusion in Ansible 9\.0\.0rc1\.
+
+<a id="bugfixes-5"></a>
+### Bugfixes
+
+* ocapi\_utils\, oci\_utils\, redfish\_utils module utils \- replace <code>type\(\)</code> calls with <code>isinstance\(\)</code> calls \([https\://github\.com/ansible\-collections/community\.general/pull/7501](https\://github\.com/ansible\-collections/community\.general/pull/7501)\)\.
+* pipx module utils \- change the CLI argument formatter for the <code>pip\_args</code> parameter \([https\://github\.com/ansible\-collections/community\.general/issues/7497](https\://github\.com/ansible\-collections/community\.general/issues/7497)\, [https\://github\.com/ansible\-collections/community\.general/pull/7506](https\://github\.com/ansible\-collections/community\.general/pull/7506)\)\.
+
+<a id="v8-0-1"></a>
+## v8\.0\.1
+
+<a id="release-summary-6"></a>
+### Release Summary
+
+Bugfix release for inclusion in Ansible 9\.0\.0b1\.
+
+<a id="bugfixes-6"></a>
+### Bugfixes
+
+* gitlab\_group\_members \- fix gitlab constants call in <code>gitlab\_group\_members</code> module \([https\://github\.com/ansible\-collections/community\.general/issues/7467](https\://github\.com/ansible\-collections/community\.general/issues/7467)\)\.
+* gitlab\_project\_members \- fix gitlab constants call in <code>gitlab\_project\_members</code> module \([https\://github\.com/ansible\-collections/community\.general/issues/7467](https\://github\.com/ansible\-collections/community\.general/issues/7467)\)\.
+* gitlab\_protected\_branches \- fix gitlab constants call in <code>gitlab\_protected\_branches</code> module \([https\://github\.com/ansible\-collections/community\.general/issues/7467](https\://github\.com/ansible\-collections/community\.general/issues/7467)\)\.
+* gitlab\_user \- fix gitlab constants call in <code>gitlab\_user</code> module \([https\://github\.com/ansible\-collections/community\.general/issues/7467](https\://github\.com/ansible\-collections/community\.general/issues/7467)\)\.
+* proxmox\_pool\_member \- absent state for type VM did not delete VMs from the pools \([https\://github\.com/ansible\-collections/community\.general/pull/7464](https\://github\.com/ansible\-collections/community\.general/pull/7464)\)\.
+* redfish\_command \- fix usage of message parsing in <code>SimpleUpdate</code> and <code>MultipartHTTPPushUpdate</code> commands to treat the lack of a <code>MessageId</code> as no message \([https\://github\.com/ansible\-collections/community\.general/issues/7465](https\://github\.com/ansible\-collections/community\.general/issues/7465)\, [https\://github\.com/ansible\-collections/community\.general/pull/7471](https\://github\.com/ansible\-collections/community\.general/pull/7471)\)\.
+
+<a id="v8-0-0"></a>
+## v8\.0\.0
+
+<a id="release-summary-7"></a>
+### Release Summary
+
+This is release 8\.0\.0 of <code>community\.general</code>\, released on 2023\-11\-01\.
+
+<a id="minor-changes-5"></a>
+### Minor Changes
+
+* The collection will start using semantic markup \([https\://github\.com/ansible\-collections/community\.general/pull/6539](https\://github\.com/ansible\-collections/community\.general/pull/6539)\)\.
+* VarDict module utils \- add method <code>VarDict\.as\_dict\(\)</code> to convert to a plain <code>dict</code> object \([https\://github\.com/ansible\-collections/community\.general/pull/6602](https\://github\.com/ansible\-collections/community\.general/pull/6602)\)\.
+* apt\_rpm \- extract package name from local <code>\.rpm</code> path when verifying
+ installation success\. Allows installing packages from local <code>\.rpm</code> files
+ \([https\://github\.com/ansible\-collections/community\.general/pull/7396](https\://github\.com/ansible\-collections/community\.general/pull/7396)\)\.
+* cargo \- add option <code>executable</code>\, which allows user to specify path to the cargo binary \([https\://github\.com/ansible\-collections/community\.general/pull/7352](https\://github\.com/ansible\-collections/community\.general/pull/7352)\)\.
+* cargo \- add option <code>locked</code> which allows user to specify install the locked version of dependency instead of latest compatible version \([https\://github\.com/ansible\-collections/community\.general/pull/6134](https\://github\.com/ansible\-collections/community\.general/pull/6134)\)\.
+* chroot connection plugin \- add <code>disable\_root\_check</code> option \([https\://github\.com/ansible\-collections/community\.general/pull/7099](https\://github\.com/ansible\-collections/community\.general/pull/7099)\)\.
+* cloudflare\_dns \- add CAA record support \([https\://github\.com/ansible\-collections/community\.general/pull/7399](https\://github\.com/ansible\-collections/community\.general/pull/7399)\)\.
+* cobbler inventory plugin \- add <code>exclude\_mgmt\_classes</code> and <code>include\_mgmt\_classes</code> options to exclude or include hosts based on management classes \([https\://github\.com/ansible\-collections/community\.general/pull/7184](https\://github\.com/ansible\-collections/community\.general/pull/7184)\)\.
+* cobbler inventory plugin \- add <code>inventory\_hostname</code> option to allow using the system name for the inventory hostname \([https\://github\.com/ansible\-collections/community\.general/pull/6502](https\://github\.com/ansible\-collections/community\.general/pull/6502)\)\.
+* cobbler inventory plugin \- add <code>want\_ip\_addresses</code> option to collect all interface DNS name to IP address mapping \([https\://github\.com/ansible\-collections/community\.general/pull/6711](https\://github\.com/ansible\-collections/community\.general/pull/6711)\)\.
+* cobbler inventory plugin \- add primary IP addess to <code>cobbler\_ipv4\_address</code> and IPv6 address to <code>cobbler\_ipv6\_address</code> host variable \([https\://github\.com/ansible\-collections/community\.general/pull/6711](https\://github\.com/ansible\-collections/community\.general/pull/6711)\)\.
+* cobbler inventory plugin \- add warning for systems with empty profiles \([https\://github\.com/ansible\-collections/community\.general/pull/6502](https\://github\.com/ansible\-collections/community\.general/pull/6502)\)\.
+* cobbler inventory plugin \- convert Ansible unicode strings to native Python unicode strings before passing user/password to XMLRPC client \([https\://github\.com/ansible\-collections/community\.general/pull/6923](https\://github\.com/ansible\-collections/community\.general/pull/6923)\)\.
+* consul\_session \- drops requirement for the <code>python\-consul</code> library to communicate with the Consul API\, instead relying on the existing <code>requests</code> library requirement \([https\://github\.com/ansible\-collections/community\.general/pull/6755](https\://github\.com/ansible\-collections/community\.general/pull/6755)\)\.
+* copr \- respawn module to use the system python interpreter when the <code>dnf</code> python module is not available in <code>ansible\_python\_interpreter</code> \([https\://github\.com/ansible\-collections/community\.general/pull/6522](https\://github\.com/ansible\-collections/community\.general/pull/6522)\)\.
+* cpanm \- minor refactor when creating the <code>CmdRunner</code> object \([https\://github\.com/ansible\-collections/community\.general/pull/7231](https\://github\.com/ansible\-collections/community\.general/pull/7231)\)\.
+* datadog\_monitor \- adds <code>notification\_preset\_name</code>\, <code>renotify\_occurrences</code> and <code>renotify\_statuses</code> parameters \([https\://github\.com/ansible\-collections/community\.general/issues/6521\,https\://github\.com/ansible\-collections/community\.general/issues/5823](https\://github\.com/ansible\-collections/community\.general/issues/6521\,https\://github\.com/ansible\-collections/community\.general/issues/5823)\)\.
+* dig lookup plugin \- add TCP option to enable the use of TCP connection during DNS lookup \([https\://github\.com/ansible\-collections/community\.general/pull/7343](https\://github\.com/ansible\-collections/community\.general/pull/7343)\)\.
+* ejabberd\_user \- module now using <code>CmdRunner</code> to execute external command \([https\://github\.com/ansible\-collections/community\.general/pull/7075](https\://github\.com/ansible\-collections/community\.general/pull/7075)\)\.
+* filesystem \- add <code>uuid</code> parameter for UUID change feature \([https\://github\.com/ansible\-collections/community\.general/pull/6680](https\://github\.com/ansible\-collections/community\.general/pull/6680)\)\.
+* gitlab\_group \- add option <code>force\_delete</code> \(default\: false\) which allows delete group even if projects exists in it \([https\://github\.com/ansible\-collections/community\.general/pull/7364](https\://github\.com/ansible\-collections/community\.general/pull/7364)\)\.
+* gitlab\_group\_variable \- add support for <code>raw</code> variables suboption \([https\://github\.com/ansible\-collections/community\.general/pull/7132](https\://github\.com/ansible\-collections/community\.general/pull/7132)\)\.
+* gitlab\_project\_variable \- add support for <code>raw</code> variables suboption \([https\://github\.com/ansible\-collections/community\.general/pull/7132](https\://github\.com/ansible\-collections/community\.general/pull/7132)\)\.
+* gitlab\_project\_variable \- minor refactor removing unnecessary code statements \([https\://github\.com/ansible\-collections/community\.general/pull/6928](https\://github\.com/ansible\-collections/community\.general/pull/6928)\)\.
+* gitlab\_runner \- minor refactor removing unnecessary code statements \([https\://github\.com/ansible\-collections/community\.general/pull/6927](https\://github\.com/ansible\-collections/community\.general/pull/6927)\)\.
+* htpasswd \- minor code improvements in the module \([https\://github\.com/ansible\-collections/community\.general/pull/6901](https\://github\.com/ansible\-collections/community\.general/pull/6901)\)\.
+* htpasswd \- the parameter <code>crypt\_scheme</code> is being renamed as <code>hash\_scheme</code> and added as an alias to it \([https\://github\.com/ansible\-collections/community\.general/pull/6841](https\://github\.com/ansible\-collections/community\.general/pull/6841)\)\.
+* icinga2\_host \- the <code>ip</code> option is no longer required\, since Icinga 2 allows for an empty address attribute \([https\://github\.com/ansible\-collections/community\.general/pull/7452](https\://github\.com/ansible\-collections/community\.general/pull/7452)\)\.
+* ini\_file \- add <code>ignore\_spaces</code> option \([https\://github\.com/ansible\-collections/community\.general/pull/7273](https\://github\.com/ansible\-collections/community\.general/pull/7273)\)\.
+* ini\_file \- add <code>modify\_inactive\_option</code> option \([https\://github\.com/ansible\-collections/community\.general/pull/7401](https\://github\.com/ansible\-collections/community\.general/pull/7401)\)\.
+* ipa\_config \- add module parameters to manage FreeIPA user and group objectclasses \([https\://github\.com/ansible\-collections/community\.general/pull/7019](https\://github\.com/ansible\-collections/community\.general/pull/7019)\)\.
+* ipa\_config \- adds <code>idp</code> choice to <code>ipauserauthtype</code> parameter\'s choices \([https\://github\.com/ansible\-collections/community\.general/pull/7051](https\://github\.com/ansible\-collections/community\.general/pull/7051)\)\.
+* jenkins\_build \- add new <code>detach</code> option\, which allows the module to exit successfully as long as the build is created \(default functionality is still waiting for the build to end before exiting\) \([https\://github\.com/ansible\-collections/community\.general/pull/7204](https\://github\.com/ansible\-collections/community\.general/pull/7204)\)\.
+* jenkins\_build \- add new <code>time\_between\_checks</code> option\, which allows to configure the wait time between requests to the Jenkins server \([https\://github\.com/ansible\-collections/community\.general/pull/7204](https\://github\.com/ansible\-collections/community\.general/pull/7204)\)\.
+* keycloak\_authentication \- added provider ID choices\, since Keycloak supports only those two specific ones \([https\://github\.com/ansible\-collections/community\.general/pull/6763](https\://github\.com/ansible\-collections/community\.general/pull/6763)\)\.
+* keycloak\_client\_rolemapping \- adds support for subgroups with additional parameter <code>parents</code> \([https\://github\.com/ansible\-collections/community\.general/pull/6687](https\://github\.com/ansible\-collections/community\.general/pull/6687)\)\.
+* keycloak\_role \- add composite roles support for realm and client roles \([https\://github\.com/ansible\-collections/community\.general/pull/6469](https\://github\.com/ansible\-collections/community\.general/pull/6469)\)\.
+* keyring \- minor refactor removing unnecessary code statements \([https\://github\.com/ansible\-collections/community\.general/pull/6927](https\://github\.com/ansible\-collections/community\.general/pull/6927)\)\.
+* ldap\_\* \- add new arguments <code>client\_cert</code> and <code>client\_key</code> to the LDAP modules in order to allow certificate authentication \([https\://github\.com/ansible\-collections/community\.general/pull/6668](https\://github\.com/ansible\-collections/community\.general/pull/6668)\)\.
+* ldap\_search \- add a new <code>page\_size</code> option to enable paged searches \([https\://github\.com/ansible\-collections/community\.general/pull/6648](https\://github\.com/ansible\-collections/community\.general/pull/6648)\)\.
+* locale\_gen \- module has been refactored to use <code>ModuleHelper</code> and <code>CmdRunner</code> \([https\://github\.com/ansible\-collections/community\.general/pull/6903](https\://github\.com/ansible\-collections/community\.general/pull/6903)\)\.
+* locale\_gen \- module now using <code>CmdRunner</code> to execute external commands \([https\://github\.com/ansible\-collections/community\.general/pull/6820](https\://github\.com/ansible\-collections/community\.general/pull/6820)\)\.
+* lvg \- add <code>active</code> and <code>inactive</code> values to the <code>state</code> option for active state management feature \([https\://github\.com/ansible\-collections/community\.general/pull/6682](https\://github\.com/ansible\-collections/community\.general/pull/6682)\)\.
+* lvg \- add <code>reset\_vg\_uuid</code>\, <code>reset\_pv\_uuid</code> options for UUID reset feature \([https\://github\.com/ansible\-collections/community\.general/pull/6682](https\://github\.com/ansible\-collections/community\.general/pull/6682)\)\.
+* lxc connection plugin \- properly handle a change of the <code>remote\_addr</code> option \([https\://github\.com/ansible\-collections/community\.general/pull/7373](https\://github\.com/ansible\-collections/community\.general/pull/7373)\)\.
+* lxd connection plugin \- automatically translate <code>remote\_addr</code> from FQDN to \(short\) hostname \([https\://github\.com/ansible\-collections/community\.general/pull/7360](https\://github\.com/ansible\-collections/community\.general/pull/7360)\)\.
+* lxd connection plugin \- update error parsing to work with newer messages mentioning instances \([https\://github\.com/ansible\-collections/community\.general/pull/7360](https\://github\.com/ansible\-collections/community\.general/pull/7360)\)\.
+* lxd inventory plugin \- add <code>server\_cert</code> option for trust anchor to use for TLS verification of server certificates \([https\://github\.com/ansible\-collections/community\.general/pull/7392](https\://github\.com/ansible\-collections/community\.general/pull/7392)\)\.
+* lxd inventory plugin \- add <code>server\_check\_hostname</code> option to disable hostname verification of server certificates \([https\://github\.com/ansible\-collections/community\.general/pull/7392](https\://github\.com/ansible\-collections/community\.general/pull/7392)\)\.
+* make \- add new <code>targets</code> parameter allowing multiple targets to be used with <code>make</code> \([https\://github\.com/ansible\-collections/community\.general/pull/6882](https\://github\.com/ansible\-collections/community\.general/pull/6882)\, [https\://github\.com/ansible\-collections/community\.general/issues/4919](https\://github\.com/ansible\-collections/community\.general/issues/4919)\)\.
+* make \- allows <code>params</code> to be used without value \([https\://github\.com/ansible\-collections/community\.general/pull/7180](https\://github\.com/ansible\-collections/community\.general/pull/7180)\)\.
+* mas \- disable sign\-in check for macOS 12\+ as <code>mas account</code> is non\-functional \([https\://github\.com/ansible\-collections/community\.general/pull/6520](https\://github\.com/ansible\-collections/community\.general/pull/6520)\)\.
+* newrelic\_deployment \- add option <code>app\_name\_exact\_match</code>\, which filters results for the exact app\_name provided \([https\://github\.com/ansible\-collections/community\.general/pull/7355](https\://github\.com/ansible\-collections/community\.general/pull/7355)\)\.
+* nmap inventory plugin \- now has a <code>use\_arp\_ping</code> option to allow the user to disable the default ARP ping query for a more reliable form \([https\://github\.com/ansible\-collections/community\.general/pull/7119](https\://github\.com/ansible\-collections/community\.general/pull/7119)\)\.
+* nmcli \- add support for <code>ipv4\.dns\-options</code> and <code>ipv6\.dns\-options</code> \([https\://github\.com/ansible\-collections/community\.general/pull/6902](https\://github\.com/ansible\-collections/community\.general/pull/6902)\)\.
+* nomad\_job\, nomad\_job\_info \- add <code>port</code> parameter \([https\://github\.com/ansible\-collections/community\.general/pull/7412](https\://github\.com/ansible\-collections/community\.general/pull/7412)\)\.
+* npm \- minor improvement on parameter validation \([https\://github\.com/ansible\-collections/community\.general/pull/6848](https\://github\.com/ansible\-collections/community\.general/pull/6848)\)\.
+* npm \- module now using <code>CmdRunner</code> to execute external commands \([https\://github\.com/ansible\-collections/community\.general/pull/6989](https\://github\.com/ansible\-collections/community\.general/pull/6989)\)\.
+* onepassword lookup plugin \- add service account support \([https\://github\.com/ansible\-collections/community\.general/issues/6635](https\://github\.com/ansible\-collections/community\.general/issues/6635)\, [https\://github\.com/ansible\-collections/community\.general/pull/6660](https\://github\.com/ansible\-collections/community\.general/pull/6660)\)\.
+* onepassword lookup plugin \- introduce <code>account\_id</code> option which allows specifying which account to use \([https\://github\.com/ansible\-collections/community\.general/pull/7308](https\://github\.com/ansible\-collections/community\.general/pull/7308)\)\.
+* onepassword\_raw lookup plugin \- add service account support \([https\://github\.com/ansible\-collections/community\.general/issues/6635](https\://github\.com/ansible\-collections/community\.general/issues/6635)\, [https\://github\.com/ansible\-collections/community\.general/pull/6660](https\://github\.com/ansible\-collections/community\.general/pull/6660)\)\.
+* onepassword\_raw lookup plugin \- introduce <code>account\_id</code> option which allows specifying which account to use \([https\://github\.com/ansible\-collections/community\.general/pull/7308](https\://github\.com/ansible\-collections/community\.general/pull/7308)\)\.
+* opentelemetry callback plugin \- add span attributes in the span event \([https\://github\.com/ansible\-collections/community\.general/pull/6531](https\://github\.com/ansible\-collections/community\.general/pull/6531)\)\.
+* opkg \- add <code>executable</code> parameter allowing to specify the path of the <code>opkg</code> command \([https\://github\.com/ansible\-collections/community\.general/pull/6862](https\://github\.com/ansible\-collections/community\.general/pull/6862)\)\.
+* opkg \- remove default value <code>\"\"</code> for parameter <code>force</code> as it causes the same behaviour of not having that parameter \([https\://github\.com/ansible\-collections/community\.general/pull/6513](https\://github\.com/ansible\-collections/community\.general/pull/6513)\)\.
+* pagerduty \- adds in option to use v2 API for creating pagerduty incidents \([https\://github\.com/ansible\-collections/community\.general/issues/6151](https\://github\.com/ansible\-collections/community\.general/issues/6151)\)
+* parted \- on resize\, use <code>\-\-fix</code> option if available \([https\://github\.com/ansible\-collections/community\.general/pull/7304](https\://github\.com/ansible\-collections/community\.general/pull/7304)\)\.
+* pnpm \- set correct version when state is latest or version is not mentioned\. Resolves previous idempotency problem \([https\://github\.com/ansible\-collections/community\.general/pull/7339](https\://github\.com/ansible\-collections/community\.general/pull/7339)\)\.
+* pritunl module utils \- ensure <code>validate\_certs</code> parameter is honoured in all methods \([https\://github\.com/ansible\-collections/community\.general/pull/7156](https\://github\.com/ansible\-collections/community\.general/pull/7156)\)\.
+* proxmox \- add <code>vmid</code> \(and <code>taskid</code> when possible\) to return values \([https\://github\.com/ansible\-collections/community\.general/pull/7263](https\://github\.com/ansible\-collections/community\.general/pull/7263)\)\.
+* proxmox \- support <code>timezone</code> parameter at container creation \([https\://github\.com/ansible\-collections/community\.general/pull/6510](https\://github\.com/ansible\-collections/community\.general/pull/6510)\)\.
+* proxmox inventory plugin \- add composite variables support for Proxmox nodes \([https\://github\.com/ansible\-collections/community\.general/issues/6640](https\://github\.com/ansible\-collections/community\.general/issues/6640)\)\.
+* proxmox\_kvm \- added support for <code>tpmstate0</code> parameter to configure TPM \(Trusted Platform Module\) disk\. TPM is required for Windows 11 installations \([https\://github\.com/ansible\-collections/community\.general/pull/6533](https\://github\.com/ansible\-collections/community\.general/pull/6533)\)\.
+* proxmox\_kvm \- enabled force restart of VM\, bringing the <code>force</code> parameter functionality in line with what is described in the docs \([https\://github\.com/ansible\-collections/community\.general/pull/6914](https\://github\.com/ansible\-collections/community\.general/pull/6914)\)\.
+* proxmox\_kvm \- re\-use <code>timeout</code> module param to forcefully shutdown a virtual machine when <code>state</code> is <code>stopped</code> \([https\://github\.com/ansible\-collections/community\.general/issues/6257](https\://github\.com/ansible\-collections/community\.general/issues/6257)\)\.
+* proxmox\_snap \- add <code>retention</code> parameter to delete old snapshots \([https\://github\.com/ansible\-collections/community\.general/pull/6576](https\://github\.com/ansible\-collections/community\.general/pull/6576)\)\.
+* proxmox\_vm\_info \- <code>node</code> parameter is no longer required\. Information can be obtained for the whole cluster \([https\://github\.com/ansible\-collections/community\.general/pull/6976](https\://github\.com/ansible\-collections/community\.general/pull/6976)\)\.
+* proxmox\_vm\_info \- non\-existing provided by name/vmid VM would return empty results instead of failing \([https\://github\.com/ansible\-collections/community\.general/pull/7049](https\://github\.com/ansible\-collections/community\.general/pull/7049)\)\.
+* pubnub\_blocks \- minor refactor removing unnecessary code statements \([https\://github\.com/ansible\-collections/community\.general/pull/6928](https\://github\.com/ansible\-collections/community\.general/pull/6928)\)\.
+* random\_string \- added new <code>ignore\_similar\_chars</code> and <code>similar\_chars</code> option to ignore certain chars \([https\://github\.com/ansible\-collections/community\.general/pull/7242](https\://github\.com/ansible\-collections/community\.general/pull/7242)\)\.
+* redfish\_command \- add <code>MultipartHTTPPushUpdate</code> command \([https\://github\.com/ansible\-collections/community\.general/issues/6471](https\://github\.com/ansible\-collections/community\.general/issues/6471)\, [https\://github\.com/ansible\-collections/community\.general/pull/6612](https\://github\.com/ansible\-collections/community\.general/pull/6612)\)\.
+* redfish\_command \- add <code>account\_types</code> and <code>oem\_account\_types</code> as optional inputs to <code>AddUser</code> \([https\://github\.com/ansible\-collections/community\.general/issues/6823](https\://github\.com/ansible\-collections/community\.general/issues/6823)\, [https\://github\.com/ansible\-collections/community\.general/pull/6871](https\://github\.com/ansible\-collections/community\.general/pull/6871)\)\.
+* redfish\_command \- add new option <code>update\_oem\_params</code> for the <code>MultipartHTTPPushUpdate</code> command \([https\://github\.com/ansible\-collections/community\.general/issues/7331](https\://github\.com/ansible\-collections/community\.general/issues/7331)\)\.
+* redfish\_config \- add <code>CreateVolume</code> command to allow creation of volumes on servers \([https\://github\.com/ansible\-collections/community\.general/pull/6813](https\://github\.com/ansible\-collections/community\.general/pull/6813)\)\.
+* redfish\_config \- add <code>DeleteAllVolumes</code> command to allow deletion of all volumes on servers \([https\://github\.com/ansible\-collections/community\.general/pull/6814](https\://github\.com/ansible\-collections/community\.general/pull/6814)\)\.
+* redfish\_config \- adding <code>SetSecureBoot</code> command \([https\://github\.com/ansible\-collections/community\.general/pull/7129](https\://github\.com/ansible\-collections/community\.general/pull/7129)\)\.
+* redfish\_info \- add <code>AccountTypes</code> and <code>OEMAccountTypes</code> to the output of <code>ListUsers</code> \([https\://github\.com/ansible\-collections/community\.general/issues/6823](https\://github\.com/ansible\-collections/community\.general/issues/6823)\, [https\://github\.com/ansible\-collections/community\.general/pull/6871](https\://github\.com/ansible\-collections/community\.general/pull/6871)\)\.
+* redfish\_info \- add support for <code>GetBiosRegistries</code> command \([https\://github\.com/ansible\-collections/community\.general/pull/7144](https\://github\.com/ansible\-collections/community\.general/pull/7144)\)\.
+* redfish\_info \- adds <code>LinkStatus</code> to NIC inventory \([https\://github\.com/ansible\-collections/community\.general/pull/7318](https\://github\.com/ansible\-collections/community\.general/pull/7318)\)\.
+* redfish\_info \- adds <code>ProcessorArchitecture</code> to CPU inventory \([https\://github\.com/ansible\-collections/community\.general/pull/6864](https\://github\.com/ansible\-collections/community\.general/pull/6864)\)\.
+* redfish\_info \- fix for <code>GetVolumeInventory</code>\, Controller name was getting populated incorrectly and duplicates were seen in the volumes retrieved \([https\://github\.com/ansible\-collections/community\.general/pull/6719](https\://github\.com/ansible\-collections/community\.general/pull/6719)\)\.
+* redfish\_info \- report <code>Id</code> in the output of <code>GetManagerInventory</code> \([https\://github\.com/ansible\-collections/community\.general/pull/7140](https\://github\.com/ansible\-collections/community\.general/pull/7140)\)\.
+* redfish\_utils \- use <code>Controllers</code> key in redfish data to obtain Storage controllers properties \([https\://github\.com/ansible\-collections/community\.general/pull/7081](https\://github\.com/ansible\-collections/community\.general/pull/7081)\)\.
+* redfish\_utils module utils \- add support for <code>PowerCycle</code> reset type for <code>redfish\_command</code> responses feature \([https\://github\.com/ansible\-collections/community\.general/issues/7083](https\://github\.com/ansible\-collections/community\.general/issues/7083)\)\.
+* redfish\_utils module utils \- add support for following <code>\@odata\.nextLink</code> pagination in <code>software\_inventory</code> responses feature \([https\://github\.com/ansible\-collections/community\.general/pull/7020](https\://github\.com/ansible\-collections/community\.general/pull/7020)\)\.
+* redfish\_utils module utils \- support <code>Volumes</code> in response for <code>GetDiskInventory</code> \([https\://github\.com/ansible\-collections/community\.general/pull/6819](https\://github\.com/ansible\-collections/community\.general/pull/6819)\)\.
+* redhat\_subscription \- the internal <code>RegistrationBase</code> class was folded
+ into the other internal <code>Rhsm</code> class\, as the separation had no purpose
+ anymore
+ \([https\://github\.com/ansible\-collections/community\.general/pull/6658](https\://github\.com/ansible\-collections/community\.general/pull/6658)\)\.
+* redis\_info \- refactor the redis\_info module to use the redis module\_utils enabling to pass TLS parameters to the Redis client \([https\://github\.com/ansible\-collections/community\.general/pull/7267](https\://github\.com/ansible\-collections/community\.general/pull/7267)\)\.
+* rhsm\_release \- improve/harden the way <code>subscription\-manager</code> is run\;
+ no behaviour change is expected
+ \([https\://github\.com/ansible\-collections/community\.general/pull/6669](https\://github\.com/ansible\-collections/community\.general/pull/6669)\)\.
+* rhsm\_repository \- the interaction with <code>subscription\-manager</code> was
+ refactored by grouping things together\, removing unused bits\, and hardening
+ the way it is run\; also\, the parsing of <code>subscription\-manager repos \-\-list</code>
+ was improved and made slightly faster\; no behaviour change is expected
+ \([https\://github\.com/ansible\-collections/community\.general/pull/6783](https\://github\.com/ansible\-collections/community\.general/pull/6783)\,
+ [https\://github\.com/ansible\-collections/community\.general/pull/6837](https\://github\.com/ansible\-collections/community\.general/pull/6837)\)\.
+* scaleway\_security\_group\_rule \- minor refactor removing unnecessary code statements \([https\://github\.com/ansible\-collections/community\.general/pull/6928](https\://github\.com/ansible\-collections/community\.general/pull/6928)\)\.
+* shutdown \- use <code>shutdown \-p \.\.\.</code> with FreeBSD to halt and power off machine \([https\://github\.com/ansible\-collections/community\.general/pull/7102](https\://github\.com/ansible\-collections/community\.general/pull/7102)\)\.
+* snap \- add option <code>dangerous</code> to the module\, that will map into the command line argument <code>\-\-dangerous</code>\, allowing unsigned snap files to be installed \([https\://github\.com/ansible\-collections/community\.general/pull/6908](https\://github\.com/ansible\-collections/community\.general/pull/6908)\, [https\://github\.com/ansible\-collections/community\.general/issues/5715](https\://github\.com/ansible\-collections/community\.general/issues/5715)\)\.
+* snap \- module is now aware of channel when deciding whether to install or refresh the snap \([https\://github\.com/ansible\-collections/community\.general/pull/6435](https\://github\.com/ansible\-collections/community\.general/pull/6435)\, [https\://github\.com/ansible\-collections/community\.general/issues/1606](https\://github\.com/ansible\-collections/community\.general/issues/1606)\)\.
+* sorcery \- add grimoire \(repository\) management support \([https\://github\.com/ansible\-collections/community\.general/pull/7012](https\://github\.com/ansible\-collections/community\.general/pull/7012)\)\.
+* sorcery \- minor refactor \([https\://github\.com/ansible\-collections/community\.general/pull/6525](https\://github\.com/ansible\-collections/community\.general/pull/6525)\)\.
+* supervisorctl \- allow to stop matching running processes before removing them with <code>stop\_before\_removing\=true</code> \([https\://github\.com/ansible\-collections/community\.general/pull/7284](https\://github\.com/ansible\-collections/community\.general/pull/7284)\)\.
+* tss lookup plugin \- allow to fetch secret IDs which are in a folder based on folder ID\. Previously\, we could not fetch secrets based on folder ID but now use <code>fetch\_secret\_ids\_from\_folder</code> option to indicate to fetch secret IDs based on folder ID \([https\://github\.com/ansible\-collections/community\.general/issues/6223](https\://github\.com/ansible\-collections/community\.general/issues/6223)\)\.
+* tss lookup plugin \- allow to fetch secret by path\. Previously\, we could not fetch secret by path but now use <code>secret\_path</code> option to indicate to fetch secret by secret path \([https\://github\.com/ansible\-collections/community\.general/pull/6881](https\://github\.com/ansible\-collections/community\.general/pull/6881)\)\.
+* unixy callback plugin \- add support for <code>check\_mode\_markers</code> option \([https\://github\.com/ansible\-collections/community\.general/pull/7179](https\://github\.com/ansible\-collections/community\.general/pull/7179)\)\.
+* vardict module utils \- added convenience methods to <code>VarDict</code> \([https\://github\.com/ansible\-collections/community\.general/pull/6647](https\://github\.com/ansible\-collections/community\.general/pull/6647)\)\.
+* xenserver\_guest\_info \- minor refactor removing unnecessary code statements \([https\://github\.com/ansible\-collections/community\.general/pull/6928](https\://github\.com/ansible\-collections/community\.general/pull/6928)\)\.
+* xenserver\_guest\_powerstate \- minor refactor removing unnecessary code statements \([https\://github\.com/ansible\-collections/community\.general/pull/6928](https\://github\.com/ansible\-collections/community\.general/pull/6928)\)\.
+* yum\_versionlock \- add support to pin specific package versions instead of only the package itself \([https\://github\.com/ansible\-collections/community\.general/pull/6861](https\://github\.com/ansible\-collections/community\.general/pull/6861)\, [https\://github\.com/ansible\-collections/community\.general/issues/4470](https\://github\.com/ansible\-collections/community\.general/issues/4470)\)\.
+
+<a id="breaking-changes--porting-guide"></a>
+### Breaking Changes / Porting Guide
+
+* collection\_version lookup plugin \- remove compatibility code for ansible\-base 2\.10 and ansible\-core 2\.11 \([https\://github\.com/ansible\-collections/community\.general/pull/7269](https\://github\.com/ansible\-collections/community\.general/pull/7269)\)\.
+* gitlab\_project \- add <code>default\_branch</code> support for project update\. If you used the module so far with <code>default\_branch</code> to update a project\, the value of <code>default\_branch</code> was ignored\. Make sure that you either do not pass a value if you are not sure whether it is the one you want to have to avoid unexpected breaking changes \([https\://github\.com/ansible\-collections/community\.general/pull/7158](https\://github\.com/ansible\-collections/community\.general/pull/7158)\)\.
+* selective callback plugin \- remove compatibility code for Ansible 2\.9 and ansible\-core 2\.10 \([https\://github\.com/ansible\-collections/community\.general/pull/7269](https\://github\.com/ansible\-collections/community\.general/pull/7269)\)\.
+* vardict module utils \- <code>VarDict</code> will no longer accept variables named <code>\_var</code>\, <code>get\_meta</code>\, and <code>as\_dict</code> \([https\://github\.com/ansible\-collections/community\.general/pull/6647](https\://github\.com/ansible\-collections/community\.general/pull/6647)\)\.
+* version module util \- remove fallback for ansible\-core 2\.11\. All modules and plugins that do version collections no longer work with ansible\-core 2\.11 \([https\://github\.com/ansible\-collections/community\.general/pull/7269](https\://github\.com/ansible\-collections/community\.general/pull/7269)\)\.
+
+<a id="deprecated-features-1"></a>
+### Deprecated Features
+
+* CmdRunner module utils \- deprecate <code>cmd\_runner\_fmt\.as\_default\_type\(\)</code> formatter \([https\://github\.com/ansible\-collections/community\.general/pull/6601](https\://github\.com/ansible\-collections/community\.general/pull/6601)\)\.
+* MH VarsMixin module utils \- deprecates <code>VarsMixin</code> and supporting classes in favor of plain <code>vardict</code> module util \([https\://github\.com/ansible\-collections/community\.general/pull/6649](https\://github\.com/ansible\-collections/community\.general/pull/6649)\)\.
+* ansible\_galaxy\_install \- the <code>ack\_ansible29</code> and <code>ack\_min\_ansiblecore211</code> options have been deprecated and will be removed in community\.general 9\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/7358](https\://github\.com/ansible\-collections/community\.general/pull/7358)\)\.
+* consul \- the <code>ack\_params\_state\_absent</code> option has been deprecated and will be removed in community\.general 10\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/7358](https\://github\.com/ansible\-collections/community\.general/pull/7358)\)\.
+* cpanm \- value <code>compatibility</code> is deprecated as default for parameter <code>mode</code> \([https\://github\.com/ansible\-collections/community\.general/pull/6512](https\://github\.com/ansible\-collections/community\.general/pull/6512)\)\.
+* ejabberd\_user \- deprecate the parameter <code>logging</code> in favour of producing more detailed information in the module output \([https\://github\.com/ansible\-collections/community\.general/pull/7043](https\://github\.com/ansible\-collections/community\.general/pull/7043)\)\.
+* flowdock \- module relies entirely on no longer responsive API endpoints\, and it will be removed in community\.general 9\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/6930](https\://github\.com/ansible\-collections/community\.general/pull/6930)\)\.
+* proxmox \- old feature flag <code>proxmox\_default\_behavior</code> will be removed in community\.general 10\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/6836](https\://github\.com/ansible\-collections/community\.general/pull/6836)\)\.
+* proxmox\_kvm \- deprecate the option <code>proxmox\_default\_behavior</code> \([https\://github\.com/ansible\-collections/community\.general/pull/7377](https\://github\.com/ansible\-collections/community\.general/pull/7377)\)\.
+* redfish\_info\, redfish\_config\, redfish\_command \- the default value <code>10</code> for the <code>timeout</code> option is deprecated and will change to <code>60</code> in community\.general 9\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/7295](https\://github\.com/ansible\-collections/community\.general/pull/7295)\)\.
+* redhat module utils \- the <code>module\_utils\.redhat</code> module is deprecated\, as
+ effectively unused\: the <code>Rhsm</code>\, <code>RhsmPool</code>\, and <code>RhsmPools</code> classes
+ will be removed in community\.general 9\.0\.0\; the <code>RegistrationBase</code> class
+ will be removed in community\.general 10\.0\.0 together with the
+ <code>rhn\_register</code> module\, as it is the only user of this class\; this means
+ that the whole <code>module\_utils\.redhat</code> module will be dropped in
+ community\.general 10\.0\.0\, so importing it without even using anything of it
+ will fail
+ \([https\://github\.com/ansible\-collections/community\.general/pull/6663](https\://github\.com/ansible\-collections/community\.general/pull/6663)\)\.
+* redhat\_subscription \- the <code>autosubscribe</code> alias for the <code>auto\_attach</code> option has been
+ deprecated for many years\, although only in the documentation\. Officially mark this alias
+ as deprecated\, and it will be removed in community\.general 9\.0\.0
+ \([https\://github\.com/ansible\-collections/community\.general/pull/6646](https\://github\.com/ansible\-collections/community\.general/pull/6646)\)\.
+* redhat\_subscription \- the <code>pool</code> option is deprecated in favour of the
+ more precise and flexible <code>pool\_ids</code> option
+ \([https\://github\.com/ansible\-collections/community\.general/pull/6650](https\://github\.com/ansible\-collections/community\.general/pull/6650)\)\.
+* rhsm\_repository \- <code>state\=present</code> has not been working as expected for many years\,
+ and it seems it was not noticed so far\; also\, \"presence\" is not really a valid concept
+ for subscription repositories\, which can only be enabled or disabled\. Hence\, mark the
+ <code>present</code> and <code>absent</code> values of the <code>state</code> option as deprecated\, slating them
+ for removal in community\.general 10\.0\.0
+ \([https\://github\.com/ansible\-collections/community\.general/pull/6673](https\://github\.com/ansible\-collections/community\.general/pull/6673)\)\.
+* stackdriver \- module relies entirely on no longer existent API endpoints\, and it will be removed in community\.general 9\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/6887](https\://github\.com/ansible\-collections/community\.general/pull/6887)\)\.
+* webfaction\_app \- module relies entirely on no longer existent API endpoints\, and it will be removed in community\.general 9\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/6909](https\://github\.com/ansible\-collections/community\.general/pull/6909)\)\.
+* webfaction\_db \- module relies entirely on no longer existent API endpoints\, and it will be removed in community\.general 9\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/6909](https\://github\.com/ansible\-collections/community\.general/pull/6909)\)\.
+* webfaction\_domain \- module relies entirely on no longer existent API endpoints\, and it will be removed in community\.general 9\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/6909](https\://github\.com/ansible\-collections/community\.general/pull/6909)\)\.
+* webfaction\_mailbox \- module relies entirely on no longer existent API endpoints\, and it will be removed in community\.general 9\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/6909](https\://github\.com/ansible\-collections/community\.general/pull/6909)\)\.
+* webfaction\_site \- module relies entirely on no longer existent API endpoints\, and it will be removed in community\.general 9\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/6909](https\://github\.com/ansible\-collections/community\.general/pull/6909)\)\.
+
+<a id="removed-features-previously-deprecated"></a>
+### Removed Features \(previously deprecated\)
+
+* The collection no longer supports ansible\-core 2\.11 and ansible\-core 2\.12\. Parts of the collection might still work on these ansible\-core versions\, but others might not \([https\://github\.com/ansible\-collections/community\.general/pull/7269](https\://github\.com/ansible\-collections/community\.general/pull/7269)\)\.
+* ansible\_galaxy\_install \- support for Ansible 2\.9 and ansible\-base 2\.10 has been removed \([https\://github\.com/ansible\-collections/community\.general/pull/7358](https\://github\.com/ansible\-collections/community\.general/pull/7358)\)\.
+* consul \- when <code>state\=absent</code>\, the options <code>script</code>\, <code>ttl</code>\, <code>tcp</code>\, <code>http</code>\, and <code>interval</code> can no longer be specified \([https\://github\.com/ansible\-collections/community\.general/pull/7358](https\://github\.com/ansible\-collections/community\.general/pull/7358)\)\.
+* gconftool2 \- <code>state\=get</code> has been removed\. Use the module <code>community\.general\.gconftool2\_info</code> instead \([https\://github\.com/ansible\-collections/community\.general/pull/7358](https\://github\.com/ansible\-collections/community\.general/pull/7358)\)\.
+* gitlab\_runner \- remove the default value for the <code>access\_level</code> option\. To restore the previous behavior\, explicitly set it to <code>ref\_protected</code> \([https\://github\.com/ansible\-collections/community\.general/pull/7358](https\://github\.com/ansible\-collections/community\.general/pull/7358)\)\.
+* htpasswd \- removed code for passlib \<1\.6 \([https\://github\.com/ansible\-collections/community\.general/pull/6901](https\://github\.com/ansible\-collections/community\.general/pull/6901)\)\.
+* manageiq\_polices \- <code>state\=list</code> has been removed\. Use the module <code>community\.general\.manageiq\_policies\_info</code> instead \([https\://github\.com/ansible\-collections/community\.general/pull/7358](https\://github\.com/ansible\-collections/community\.general/pull/7358)\)\.
+* manageiq\_tags \- <code>state\=list</code> has been removed\. Use the module <code>community\.general\.manageiq\_tags\_info</code> instead \([https\://github\.com/ansible\-collections/community\.general/pull/7358](https\://github\.com/ansible\-collections/community\.general/pull/7358)\)\.
+* mh\.mixins\.cmd module utils \- the <code>ArgFormat</code> class has been removed \([https\://github\.com/ansible\-collections/community\.general/pull/7358](https\://github\.com/ansible\-collections/community\.general/pull/7358)\)\.
+* mh\.mixins\.cmd module utils \- the <code>CmdMixin</code> mixin has been removed\. Use <code>community\.general\.plugins\.module\_utils\.cmd\_runner\.CmdRunner</code> instead \([https\://github\.com/ansible\-collections/community\.general/pull/7358](https\://github\.com/ansible\-collections/community\.general/pull/7358)\)\.
+* mh\.mixins\.cmd module utils \- the mh\.mixins\.cmd module utils has been removed after all its contents were removed \([https\://github\.com/ansible\-collections/community\.general/pull/7358](https\://github\.com/ansible\-collections/community\.general/pull/7358)\)\.
+* mh\.module\_helper module utils \- the <code>CmdModuleHelper</code> and <code>CmdStateModuleHelper</code> classes have been removed\. Use <code>community\.general\.plugins\.module\_utils\.cmd\_runner\.CmdRunner</code> instead \([https\://github\.com/ansible\-collections/community\.general/pull/7358](https\://github\.com/ansible\-collections/community\.general/pull/7358)\)\.
+* proxmox module utils \- removed unused imports \([https\://github\.com/ansible\-collections/community\.general/pull/6873](https\://github\.com/ansible\-collections/community\.general/pull/6873)\)\.
+* xfconf \- the deprecated <code>disable\_facts</code> option was removed \([https\://github\.com/ansible\-collections/community\.general/pull/7358](https\://github\.com/ansible\-collections/community\.general/pull/7358)\)\.
+
+<a id="bugfixes-7"></a>
+### Bugfixes
+
+* CmdRunner module utils \- does not attempt to resolve path if executable is a relative or absolute path \([https\://github\.com/ansible\-collections/community\.general/pull/7200](https\://github\.com/ansible\-collections/community\.general/pull/7200)\)\.
+* MH DependencyMixin module utils \- deprecation notice was popping up for modules not using dependencies \([https\://github\.com/ansible\-collections/community\.general/pull/6644](https\://github\.com/ansible\-collections/community\.general/pull/6644)\, [https\://github\.com/ansible\-collections/community\.general/issues/6639](https\://github\.com/ansible\-collections/community\.general/issues/6639)\)\.
+* bitwarden lookup plugin \- the plugin made assumptions about the structure of a Bitwarden JSON object which may have been broken by an update in the Bitwarden API\. Remove assumptions\, and allow queries for general fields such as <code>notes</code> \([https\://github\.com/ansible\-collections/community\.general/pull/7061](https\://github\.com/ansible\-collections/community\.general/pull/7061)\)\.
+* cmd\_runner module utils \- when a parameter in <code>argument\_spec</code> has no type\, meaning it is implicitly a <code>str</code>\, <code>CmdRunner</code> would fail trying to find the <code>type</code> key in that dictionary \([https\://github\.com/ansible\-collections/community\.general/pull/6968](https\://github\.com/ansible\-collections/community\.general/pull/6968)\)\.
+* cobbler inventory plugin \- fix calculation of cobbler\_ipv4/6\_address \([https\://github\.com/ansible\-collections/community\.general/pull/6925](https\://github\.com/ansible\-collections/community\.general/pull/6925)\)\.
+* composer \- fix impossible to run <code>working\_dir</code> dependent commands\. The module was throwing an error when trying to run a <code>working\_dir</code> dependent command\, because it tried to get the command help without passing the <code>working\_dir</code> \([https\://github\.com/ansible\-collections/community\.general/issues/3787](https\://github\.com/ansible\-collections/community\.general/issues/3787)\)\.
+* csv module utils \- detects and remove unicode BOM markers from incoming CSV content \([https\://github\.com/ansible\-collections/community\.general/pull/6662](https\://github\.com/ansible\-collections/community\.general/pull/6662)\)\.
+* datadog\_downtime \- presence of <code>rrule</code> param lead to the Datadog API returning Bad Request due to a missing recurrence type \([https\://github\.com/ansible\-collections/community\.general/pull/6811](https\://github\.com/ansible\-collections/community\.general/pull/6811)\)\.
+* ejabberd\_user \- module was failing to detect whether user was already created and/or password was changed \([https\://github\.com/ansible\-collections/community\.general/pull/7033](https\://github\.com/ansible\-collections/community\.general/pull/7033)\)\.
+* ejabberd\_user \- provide meaningful error message when the <code>ejabberdctl</code> command is not found \([https\://github\.com/ansible\-collections/community\.general/pull/7028](https\://github\.com/ansible\-collections/community\.general/pull/7028)\, [https\://github\.com/ansible\-collections/community\.general/issues/6949](https\://github\.com/ansible\-collections/community\.general/issues/6949)\)\.
+* github\_deploy\_key \- fix pagination behaviour causing a crash when only a single page of deploy keys exist \([https\://github\.com/ansible\-collections/community\.general/pull/7375](https\://github\.com/ansible\-collections/community\.general/pull/7375)\)\.
+* gitlab\_group \- the module passed parameters to the API call even when not set\. The module is now filtering out <code>None</code> values to remediate this \([https\://github\.com/ansible\-collections/community\.general/pull/6712](https\://github\.com/ansible\-collections/community\.general/pull/6712)\)\.
+* gitlab\_group\_variable \- deleted all variables when used with <code>purge\=true</code> due to missing <code>raw</code> property in KNOWN attributes \([https\://github\.com/ansible\-collections/community\.general/issues/7250](https\://github\.com/ansible\-collections/community\.general/issues/7250)\)\.
+* gitlab\_project\_variable \- deleted all variables when used with <code>purge\=true</code> due to missing <code>raw</code> property in KNOWN attributes \([https\://github\.com/ansible\-collections/community\.general/issues/7250](https\://github\.com/ansible\-collections/community\.general/issues/7250)\)\.
+* icinga2\_host \- fix a key error when updating an existing host \([https\://github\.com/ansible\-collections/community\.general/pull/6748](https\://github\.com/ansible\-collections/community\.general/pull/6748)\)\.
+* ini\_file \- add the <code>follow</code> paramter to follow the symlinks instead of replacing them \([https\://github\.com/ansible\-collections/community\.general/pull/6546](https\://github\.com/ansible\-collections/community\.general/pull/6546)\)\.
+* ini\_file \- fix a bug where the inactive options were not used when possible \([https\://github\.com/ansible\-collections/community\.general/pull/6575](https\://github\.com/ansible\-collections/community\.general/pull/6575)\)\.
+* ipa\_dnszone \- fix \'idnsallowsyncptr\' key error for reverse zone \([https\://github\.com/ansible\-collections/community\.general/pull/6906](https\://github\.com/ansible\-collections/community\.general/pull/6906)\, [https\://github\.com/ansible\-collections/community\.general/issues/6905](https\://github\.com/ansible\-collections/community\.general/issues/6905)\)\.
+* kernel\_blacklist \- simplified the mechanism to update the file\, fixing the error \([https\://github\.com/ansible\-collections/community\.general/pull/7382](https\://github\.com/ansible\-collections/community\.general/pull/7382)\, [https\://github\.com/ansible\-collections/community\.general/issues/7362](https\://github\.com/ansible\-collections/community\.general/issues/7362)\)\.
+* keycloak module util \- fix missing <code>http\_agent</code>\, <code>timeout</code>\, and <code>validate\_certs</code> <code>open\_url\(\)</code> parameters \([https\://github\.com/ansible\-collections/community\.general/pull/7067](https\://github\.com/ansible\-collections/community\.general/pull/7067)\)\.
+* keycloak module utils \- fix <code>is\_struct\_included</code> handling of lists of lists/dictionaries \([https\://github\.com/ansible\-collections/community\.general/pull/6688](https\://github\.com/ansible\-collections/community\.general/pull/6688)\)\.
+* keycloak module utils \- the function <code>get\_user\_by\_username</code> now return the user representation or <code>None</code> as stated in the documentation \([https\://github\.com/ansible\-collections/community\.general/pull/6758](https\://github\.com/ansible\-collections/community\.general/pull/6758)\)\.
+* keycloak\_authentication \- fix Keycloak authentication flow \(step or sub\-flow\) indexing during update\, if not specified by the user \([https\://github\.com/ansible\-collections/community\.general/pull/6734](https\://github\.com/ansible\-collections/community\.general/pull/6734)\)\.
+* keycloak\_client inventory plugin \- fix missing client secret \([https\://github\.com/ansible\-collections/community\.general/pull/6931](https\://github\.com/ansible\-collections/community\.general/pull/6931)\)\.
+* ldap\_search \- fix string normalization and the <code>base64\_attributes</code> option on Python 3 \([https\://github\.com/ansible\-collections/community\.general/issues/5704](https\://github\.com/ansible\-collections/community\.general/issues/5704)\, [https\://github\.com/ansible\-collections/community\.general/pull/7264](https\://github\.com/ansible\-collections/community\.general/pull/7264)\)\.
+* locale\_gen \- now works for locales without the underscore character such as <code>C\.UTF\-8</code> \([https\://github\.com/ansible\-collections/community\.general/pull/6774](https\://github\.com/ansible\-collections/community\.general/pull/6774)\, [https\://github\.com/ansible\-collections/community\.general/issues/5142](https\://github\.com/ansible\-collections/community\.general/issues/5142)\, [https\://github\.com/ansible\-collections/community\.general/issues/4305](https\://github\.com/ansible\-collections/community\.general/issues/4305)\)\.
+* lvol \- add support for percentage of origin size specification when creating snapshot volumes \([https\://github\.com/ansible\-collections/community\.general/issues/1630](https\://github\.com/ansible\-collections/community\.general/issues/1630)\, [https\://github\.com/ansible\-collections/community\.general/pull/7053](https\://github\.com/ansible\-collections/community\.general/pull/7053)\)\.
+* lxc connection plugin \- now handles <code>remote\_addr</code> defaulting to <code>inventory\_hostname</code> correctly \([https\://github\.com/ansible\-collections/community\.general/pull/7104](https\://github\.com/ansible\-collections/community\.general/pull/7104)\)\.
+* lxc connection plugin \- properly evaluate options \([https\://github\.com/ansible\-collections/community\.general/pull/7369](https\://github\.com/ansible\-collections/community\.general/pull/7369)\)\.
+* machinectl become plugin \- mark plugin as <code>require\_tty</code> to automatically disable pipelining\, with which this plugin is not compatible \([https\://github\.com/ansible\-collections/community\.general/issues/6932](https\://github\.com/ansible\-collections/community\.general/issues/6932)\, [https\://github\.com/ansible\-collections/community\.general/pull/6935](https\://github\.com/ansible\-collections/community\.general/pull/6935)\)\.
+* mail \- skip headers containing equals characters due to missing <code>maxsplit</code> on header key/value parsing \([https\://github\.com/ansible\-collections/community\.general/pull/7303](https\://github\.com/ansible\-collections/community\.general/pull/7303)\)\.
+* memset module utils \- make compatible with ansible\-core 2\.17 \([https\://github\.com/ansible\-collections/community\.general/pull/7379](https\://github\.com/ansible\-collections/community\.general/pull/7379)\)\.
+* nmap inventory plugin \- fix <code>get\_option</code> calls \([https\://github\.com/ansible\-collections/community\.general/pull/7323](https\://github\.com/ansible\-collections/community\.general/pull/7323)\)\.
+* nmap inventory plugin \- now uses <code>get\_option</code> in all cases to get its configuration information \([https\://github\.com/ansible\-collections/community\.general/pull/7119](https\://github\.com/ansible\-collections/community\.general/pull/7119)\)\.
+* nmcli \- fix bond option <code>xmit\_hash\_policy</code> \([https\://github\.com/ansible\-collections/community\.general/pull/6527](https\://github\.com/ansible\-collections/community\.general/pull/6527)\)\.
+* nmcli \- fix support for empty list \(in compare and scrape\) \([https\://github\.com/ansible\-collections/community\.general/pull/6769](https\://github\.com/ansible\-collections/community\.general/pull/6769)\)\.
+* nsupdate \- fix a possible <code>list index out of range</code> exception \([https\://github\.com/ansible\-collections/community\.general/issues/836](https\://github\.com/ansible\-collections/community\.general/issues/836)\)\.
+* oci\_utils module util \- fix inappropriate logical comparison expressions and makes them simpler\. The previous checks had logical short circuits \([https\://github\.com/ansible\-collections/community\.general/pull/7125](https\://github\.com/ansible\-collections/community\.general/pull/7125)\)\.
+* oci\_utils module utils \- avoid direct type comparisons \([https\://github\.com/ansible\-collections/community\.general/pull/7085](https\://github\.com/ansible\-collections/community\.general/pull/7085)\)\.
+* onepassword \- fix KeyError exception when trying to access value of a field that is not filled out in OnePassword item \([https\://github\.com/ansible\-collections/community\.general/pull/7241](https\://github\.com/ansible\-collections/community\.general/pull/7241)\)\.
+* openbsd\_pkg \- the pkg\_info\(1\) behavior has changed in OpenBSD \>7\.3\. The error message <code>Can\'t find</code> should not lead to an error case \([https\://github\.com/ansible\-collections/community\.general/pull/6785](https\://github\.com/ansible\-collections/community\.general/pull/6785)\)\.
+* pacman \- module recognizes the output of <code>yay</code> running as <code>root</code> \([https\://github\.com/ansible\-collections/community\.general/pull/6713](https\://github\.com/ansible\-collections/community\.general/pull/6713)\)\.
+* portage \- fix <code>changed\_use</code> and <code>newuse</code> not triggering rebuilds \([https\://github\.com/ansible\-collections/community\.general/issues/6008](https\://github\.com/ansible\-collections/community\.general/issues/6008)\, [https\://github\.com/ansible\-collections/community\.general/pull/6548](https\://github\.com/ansible\-collections/community\.general/pull/6548)\)\.
+* pritunl module utils \- fix incorrect URL parameter for orgnization add method \([https\://github\.com/ansible\-collections/community\.general/pull/7161](https\://github\.com/ansible\-collections/community\.general/pull/7161)\)\.
+* proxmox \- fix error when a configuration had no <code>template</code> field \([https\://github\.com/ansible\-collections/community\.general/pull/6838](https\://github\.com/ansible\-collections/community\.general/pull/6838)\, [https\://github\.com/ansible\-collections/community\.general/issues/5372](https\://github\.com/ansible\-collections/community\.general/issues/5372)\)\.
+* proxmox module utils \- add logic to detect whether an old Promoxer complains about the <code>token\_name</code> and <code>token\_value</code> parameters and provide a better error message when that happens \([https\://github\.com/ansible\-collections/community\.general/pull/6839](https\://github\.com/ansible\-collections/community\.general/pull/6839)\, [https\://github\.com/ansible\-collections/community\.general/issues/5371](https\://github\.com/ansible\-collections/community\.general/issues/5371)\)\.
+* proxmox module utils \- fix proxmoxer library version check \([https\://github\.com/ansible\-collections/community\.general/issues/6974](https\://github\.com/ansible\-collections/community\.general/issues/6974)\, [https\://github\.com/ansible\-collections/community\.general/issues/6975](https\://github\.com/ansible\-collections/community\.general/issues/6975)\, [https\://github\.com/ansible\-collections/community\.general/pull/6980](https\://github\.com/ansible\-collections/community\.general/pull/6980)\)\.
+* proxmox\_disk \- fix unable to create <code>cdrom</code> media due to <code>size</code> always being appended \([https\://github\.com/ansible\-collections/community\.general/pull/6770](https\://github\.com/ansible\-collections/community\.general/pull/6770)\)\.
+* proxmox\_kvm \- <code>absent</code> state with <code>force</code> specified failed to stop the VM due to the <code>timeout</code> value not being passed to <code>stop\_vm</code> \([https\://github\.com/ansible\-collections/community\.general/pull/6827](https\://github\.com/ansible\-collections/community\.general/pull/6827)\)\.
+* proxmox\_kvm \- <code>restarted</code> state did not actually restart a VM in some VM configurations\. The state now uses the Proxmox reboot endpoint instead of calling the <code>stop\_vm</code> and <code>start\_vm</code> functions \([https\://github\.com/ansible\-collections/community\.general/pull/6773](https\://github\.com/ansible\-collections/community\.general/pull/6773)\)\.
+* proxmox\_kvm \- allow creation of VM with existing name but new vmid \([https\://github\.com/ansible\-collections/community\.general/issues/6155](https\://github\.com/ansible\-collections/community\.general/issues/6155)\, [https\://github\.com/ansible\-collections/community\.general/pull/6709](https\://github\.com/ansible\-collections/community\.general/pull/6709)\)\.
+* proxmox\_kvm \- when <code>name</code> option is provided without <code>vmid</code> and VM with that name already exists then no new VM will be created \([https\://github\.com/ansible\-collections/community\.general/issues/6911](https\://github\.com/ansible\-collections/community\.general/issues/6911)\, [https\://github\.com/ansible\-collections/community\.general/pull/6981](https\://github\.com/ansible\-collections/community\.general/pull/6981)\)\.
+* proxmox\_tasks\_info \- remove <code>api\_user</code> \+ <code>api\_password</code> constraint from <code>required\_together</code> as it causes to require <code>api\_password</code> even when API token param is used \([https\://github\.com/ansible\-collections/community\.general/issues/6201](https\://github\.com/ansible\-collections/community\.general/issues/6201)\)\.
+* proxmox\_template \- require <code>requests\_toolbelt</code> module to fix issue with uploading large templates \([https\://github\.com/ansible\-collections/community\.general/issues/5579](https\://github\.com/ansible\-collections/community\.general/issues/5579)\, [https\://github\.com/ansible\-collections/community\.general/pull/6757](https\://github\.com/ansible\-collections/community\.general/pull/6757)\)\.
+* proxmox\_user\_info \- avoid direct type comparisons \([https\://github\.com/ansible\-collections/community\.general/pull/7085](https\://github\.com/ansible\-collections/community\.general/pull/7085)\)\.
+* redfish\_info \- fix <code>ListUsers</code> to not show empty account slots \([https\://github\.com/ansible\-collections/community\.general/issues/6771](https\://github\.com/ansible\-collections/community\.general/issues/6771)\, [https\://github\.com/ansible\-collections/community\.general/pull/6772](https\://github\.com/ansible\-collections/community\.general/pull/6772)\)\.
+* redhat\_subscription \- use the right D\-Bus options for the consumer type when
+ registering a RHEL system older than 9 or a RHEL 9 system older than 9\.2
+ and using <code>consumer\_type</code>
+ \([https\://github\.com/ansible\-collections/community\.general/pull/7378](https\://github\.com/ansible\-collections/community\.general/pull/7378)\)\.
+* refish\_utils module utils \- changing variable names to avoid issues occuring when fetching Volumes data \([https\://github\.com/ansible\-collections/community\.general/pull/6883](https\://github\.com/ansible\-collections/community\.general/pull/6883)\)\.
+* rhsm\_repository \- when using the <code>purge</code> option\, the <code>repositories</code>
+ dictionary element in the returned JSON is now properly updated according
+ to the pruning operation
+ \([https\://github\.com/ansible\-collections/community\.general/pull/6676](https\://github\.com/ansible\-collections/community\.general/pull/6676)\)\.
+* rundeck \- fix <code>TypeError</code> on 404 API response \([https\://github\.com/ansible\-collections/community\.general/pull/6983](https\://github\.com/ansible\-collections/community\.general/pull/6983)\)\.
+* selective callback plugin \- fix length of task name lines in output always being 3 characters longer than desired \([https\://github\.com/ansible\-collections/community\.general/pull/7374](https\://github\.com/ansible\-collections/community\.general/pull/7374)\)\.
+* snap \- an exception was being raised when snap list was empty \([https\://github\.com/ansible\-collections/community\.general/pull/7124](https\://github\.com/ansible\-collections/community\.general/pull/7124)\, [https\://github\.com/ansible\-collections/community\.general/issues/7120](https\://github\.com/ansible\-collections/community\.general/issues/7120)\)\.
+* snap \- assume default track <code>latest</code> in parameter <code>channel</code> when not specified \([https\://github\.com/ansible\-collections/community\.general/pull/6835](https\://github\.com/ansible\-collections/community\.general/pull/6835)\, [https\://github\.com/ansible\-collections/community\.general/issues/6821](https\://github\.com/ansible\-collections/community\.general/issues/6821)\)\.
+* snap \- change the change detection mechanism from \"parsing installation\" to \"comparing end state with initial state\" \([https\://github\.com/ansible\-collections/community\.general/pull/7340](https\://github\.com/ansible\-collections/community\.general/pull/7340)\, [https\://github\.com/ansible\-collections/community\.general/issues/7265](https\://github\.com/ansible\-collections/community\.general/issues/7265)\)\.
+* snap \- fix crash when multiple snaps are specified and one has <code>\-\-\-</code> in its description \([https\://github\.com/ansible\-collections/community\.general/pull/7046](https\://github\.com/ansible\-collections/community\.general/pull/7046)\)\.
+* snap \- fix the processing of the commands\' output\, stripping spaces and newlines from it \([https\://github\.com/ansible\-collections/community\.general/pull/6826](https\://github\.com/ansible\-collections/community\.general/pull/6826)\, [https\://github\.com/ansible\-collections/community\.general/issues/6803](https\://github\.com/ansible\-collections/community\.general/issues/6803)\)\.
+* sorcery \- fix interruption of the multi\-stage process \([https\://github\.com/ansible\-collections/community\.general/pull/7012](https\://github\.com/ansible\-collections/community\.general/pull/7012)\)\.
+* sorcery \- fix queue generation before the whole system rebuild \([https\://github\.com/ansible\-collections/community\.general/pull/7012](https\://github\.com/ansible\-collections/community\.general/pull/7012)\)\.
+* sorcery \- latest state no longer triggers update\_cache \([https\://github\.com/ansible\-collections/community\.general/pull/7012](https\://github\.com/ansible\-collections/community\.general/pull/7012)\)\.
+* terraform \- prevents <code>\-backend\-config</code> option double encapsulating with <code>shlex\_quote</code> function\. \([https\://github\.com/ansible\-collections/community\.general/pull/7301](https\://github\.com/ansible\-collections/community\.general/pull/7301)\)\.
+* tss lookup plugin \- fix multiple issues when using <code>fetch\_attachments\=true</code> \([https\://github\.com/ansible\-collections/community\.general/pull/6720](https\://github\.com/ansible\-collections/community\.general/pull/6720)\)\.
+* zypper \- added handling of zypper exitcode 102\. Changed state is set correctly now and rc 102 is still preserved to be evaluated by the playbook \([https\://github\.com/ansible\-collections/community\.general/pull/6534](https\://github\.com/ansible\-collections/community\.general/pull/6534)\)\.
+
+<a id="known-issues"></a>
+### Known Issues
+
+* Ansible markup will show up in raw form on ansible\-doc text output for ansible\-core before 2\.15\. If you have trouble deciphering the documentation markup\, please upgrade to ansible\-core 2\.15 \(or newer\)\, or read the HTML documentation on [https\://docs\.ansible\.com/ansible/devel/collections/community/general/](https\://docs\.ansible\.com/ansible/devel/collections/community/general/) \([https\://github\.com/ansible\-collections/community\.general/pull/6539](https\://github\.com/ansible\-collections/community\.general/pull/6539)\)\.
+
+<a id="new-plugins-3"></a>
+### New Plugins
+
+<a id="lookup-2"></a>
+#### Lookup
+
+* bitwarden\_secrets\_manager \- Retrieve secrets from Bitwarden Secrets Manager
+
+<a id="new-modules-5"></a>
+### New Modules
+
+* consul\_policy \- Manipulate Consul policies
+* consul\_role \- Manipulate Consul roles
+* facter\_facts \- Runs the discovery program C\(facter\) on the remote system and return Ansible facts
+* gio\_mime \- Set default handler for MIME type\, for applications using Gnome GIO
+* gitlab\_instance\_variable \- Creates\, updates\, or deletes GitLab instance variables
+* gitlab\_merge\_request \- Create\, update\, or delete GitLab merge requests
+* jenkins\_build\_info \- Get information about Jenkins builds
+* keycloak\_authentication\_required\_actions \- Allows administration of Keycloak authentication required actions
+* keycloak\_authz\_custom\_policy \- Allows administration of Keycloak client custom Javascript policies via Keycloak API
+* keycloak\_authz\_permission \- Allows administration of Keycloak client authorization permissions via Keycloak API
+* keycloak\_authz\_permission\_info \- Query Keycloak client authorization permissions information
+* keycloak\_realm\_key \- Allows administration of Keycloak realm keys via Keycloak API
+* keycloak\_user \- Create and configure a user in Keycloak
+* lvg\_rename \- Renames LVM volume groups
+* pnpm \- Manage node\.js packages with pnpm
+* proxmox\_pool \- Pool management for Proxmox VE cluster
+* proxmox\_pool\_member \- Add or delete members from Proxmox VE cluster pools
+* proxmox\_vm\_info \- Retrieve information about one or more Proxmox VE virtual machines
+* simpleinit\_msb \- Manage services on Source Mage GNU/Linux
diff --git a/ansible_collections/community/general/CHANGELOG.md.license b/ansible_collections/community/general/CHANGELOG.md.license
new file mode 100644
index 000000000..edff8c768
--- /dev/null
+++ b/ansible_collections/community/general/CHANGELOG.md.license
@@ -0,0 +1,3 @@
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
+SPDX-FileCopyrightText: Ansible Project
diff --git a/ansible_collections/community/general/CHANGELOG.rst b/ansible_collections/community/general/CHANGELOG.rst
index 9ddf616c3..da10a021b 100644
--- a/ansible_collections/community/general/CHANGELOG.rst
+++ b/ansible_collections/community/general/CHANGELOG.rst
@@ -4,229 +4,157 @@ Community General Release Notes
.. contents:: Topics
-This changelog describes changes after version 5.0.0.
+This changelog describes changes after version 7.0.0.
-v6.6.2
+v8.5.0
======
Release Summary
---------------
-Regular bugfix release.
-
-Bugfixes
---------
-
-- csv module utils - detects and remove unicode BOM markers from incoming CSV content (https://github.com/ansible-collections/community.general/pull/6662).
-- gitlab_group - the module passed parameters to the API call even when not set. The module is now filtering out ``None`` values to remediate this (https://github.com/ansible-collections/community.general/pull/6712).
-- ini_file - fix a bug where the inactive options were not used when possible (https://github.com/ansible-collections/community.general/pull/6575).
-- keycloak module utils - fix ``is_struct_included`` handling of lists of lists/dictionaries (https://github.com/ansible-collections/community.general/pull/6688).
-- keycloak module utils - the function ``get_user_by_username`` now return the user representation or ``None`` as stated in the documentation (https://github.com/ansible-collections/community.general/pull/6758).
-
-v6.6.1
-======
-
-Release Summary
----------------
-
-Regular bugfix release.
+Regular feature and bugfix release with security fixes.
Minor Changes
-------------
-- dconf - if ``gi.repository.GLib`` is missing, try to respawn in a Python interpreter that has it (https://github.com/ansible-collections/community.general/pull/6491).
-
-Bugfixes
---------
-
-- deps module utils - do not fail when dependency cannot be found (https://github.com/ansible-collections/community.general/pull/6479).
-- nmcli - fix bond option ``xmit_hash_policy`` (https://github.com/ansible-collections/community.general/pull/6527).
-- passwordstore lookup plugin - make compatible with ansible-core 2.16 (https://github.com/ansible-collections/community.general/pull/6447).
-- portage - fix ``changed_use`` and ``newuse`` not triggering rebuilds (https://github.com/ansible-collections/community.general/issues/6008, https://github.com/ansible-collections/community.general/pull/6548).
-- portage - update the logic for generating the emerge command arguments to ensure that ``withbdeps: false`` results in a passing an ``n`` argument with the ``--with-bdeps`` emerge flag (https://github.com/ansible-collections/community.general/issues/6451, https://github.com/ansible-collections/community.general/pull/6456).
-- proxmox_tasks_info - remove ``api_user`` + ``api_password`` constraint from ``required_together`` as it causes to require ``api_password`` even when API token param is used (https://github.com/ansible-collections/community.general/issues/6201).
-- puppet - handling ``noop`` parameter was not working at all, now it is has been fixed (https://github.com/ansible-collections/community.general/issues/6452, https://github.com/ansible-collections/community.general/issues/6458).
-- terraform - fix broken ``warn()`` call (https://github.com/ansible-collections/community.general/pull/6497).
-- xfs_quota - in case of a project quota, the call to ``xfs_quota`` did not initialize/reset the project (https://github.com/ansible-collections/community.general/issues/5143).
-- zypper - added handling of zypper exitcode 102. Changed state is set correctly now and rc 102 is still preserved to be evaluated by the playbook (https://github.com/ansible-collections/community.general/pull/6534).
-
-v6.6.0
-======
-
-Release Summary
----------------
+- bitwarden lookup plugin - allows to fetch all records of a given collection ID, by allowing to pass an empty value for ``search_value`` when ``collection_id`` is provided (https://github.com/ansible-collections/community.general/pull/8013).
+- icinga2 inventory plugin - adds new parameter ``group_by_hostgroups`` in order to make grouping by Icinga2 hostgroups optional (https://github.com/ansible-collections/community.general/pull/7998).
+- ini_file - support optional spaces between section names and their surrounding brackets (https://github.com/ansible-collections/community.general/pull/8075).
+- java_cert - enable ``owner``, ``group``, ``mode``, and other generic file arguments (https://github.com/ansible-collections/community.general/pull/8116).
+- ldap_attrs - module now supports diff mode, showing which attributes are changed within an operation (https://github.com/ansible-collections/community.general/pull/8073).
+- lxd_container - uses ``/1.0/instances`` API endpoint, if available. Falls back to ``/1.0/containers`` or ``/1.0/virtual-machines``. Fixes issue when using Incus or LXD 5.19 due to migrating to ``/1.0/instances`` endpoint (https://github.com/ansible-collections/community.general/pull/7980).
+- nmcli - allow setting ``MTU`` for ``bond-slave`` interface types (https://github.com/ansible-collections/community.general/pull/8118).
+- proxmox - adds ``startup`` parameters to configure startup order, startup delay and shutdown delay (https://github.com/ansible-collections/community.general/pull/8038).
+- revbitspss lookup plugin - removed a redundant unicode prefix. The prefix was not necessary for Python 3 and has been cleaned up to streamline the code (https://github.com/ansible-collections/community.general/pull/8087).
-Bugfix and feature release.
+Security Fixes
+--------------
-Minor Changes
--------------
-
-- cpanm - minor change, use feature from ``ModuleHelper`` (https://github.com/ansible-collections/community.general/pull/6385).
-- dconf - be forgiving about boolean values: convert them to GVariant booleans automatically (https://github.com/ansible-collections/community.general/pull/6206).
-- dconf - minor refactoring improving parameters and dependencies validation (https://github.com/ansible-collections/community.general/pull/6336).
-- deps module utils - add function ``failed()`` providing the ability to check the dependency check result without triggering an exception (https://github.com/ansible-collections/community.general/pull/6383).
-- dig lookup plugin - Support multiple domains to be queried as indicated in docs (https://github.com/ansible-collections/community.general/pull/6334).
-- gitlab_project - add new option ``topics`` for adding topics to GitLab projects (https://github.com/ansible-collections/community.general/pull/6278).
-- homebrew_cask - allows passing ``--greedy`` option to ``upgrade_all`` (https://github.com/ansible-collections/community.general/pull/6267).
-- idrac_redfish_command - add ``job_id`` to ``CreateBiosConfigJob`` response (https://github.com/ansible-collections/community.general/issues/5603).
-- ipa_hostgroup - add ``append`` parameter for adding a new hosts to existing hostgroups without changing existing hostgroup members (https://github.com/ansible-collections/community.general/pull/6203).
-- keycloak_authentication - add flow type option to sub flows to allow the creation of 'form-flow' sub flows like in Keycloak's built-in registration flow (https://github.com/ansible-collections/community.general/pull/6318).
-- mksysb - improved the output of the module in case of errors (https://github.com/ansible-collections/community.general/issues/6263).
-- nmap inventory plugin - added environment variables for configure ``address`` and ``exclude`` (https://github.com/ansible-collections/community.general/issues/6351).
-- nmcli - add ``macvlan`` connection type (https://github.com/ansible-collections/community.general/pull/6312).
-- pipx - add ``system_site_packages`` parameter to give application access to system-wide packages (https://github.com/ansible-collections/community.general/pull/6308).
-- pipx - ensure ``include_injected`` parameter works with ``state=upgrade`` and ``state=latest`` (https://github.com/ansible-collections/community.general/pull/6212).
-- puppet - add new options ``skip_tags`` to exclude certain tagged resources during a puppet agent or apply (https://github.com/ansible-collections/community.general/pull/6293).
-- terraform - remove state file check condition and error block, because in the native implementation of terraform will not cause errors due to the non-existent file (https://github.com/ansible-collections/community.general/pull/6296).
-- udm_dns_record - minor refactor to the code (https://github.com/ansible-collections/community.general/pull/6382).
+- cobbler, gitlab_runners, icinga2, linode, lxd, nmap, online, opennebula, proxmox, scaleway, stackpath_compute, virtualbox, and xen_orchestra inventory plugin - make sure all data received from the remote servers is marked as unsafe, so remote code execution by obtaining texts that can be evaluated as templates is not possible (https://www.die-welt.net/2024/03/remote-code-execution-in-ansible-dynamic-inventory-plugins/, https://github.com/ansible-collections/community.general/pull/8098).
Bugfixes
--------
-- archive - reduce RAM usage by generating CRC32 checksum over chunks (https://github.com/ansible-collections/community.general/pull/6274).
-- flatpak - fixes idempotency detection issues. In some cases the module could fail to properly detect already existing Flatpaks because of a parameter witch only checks the installed apps (https://github.com/ansible-collections/community.general/pull/6289).
-- icinga2_host - fix the data structure sent to Icinga to make use of host templates and template vars (https://github.com/ansible-collections/community.general/pull/6286).
-- idrac_redfish_command - allow user to specify ``resource_id`` for ``CreateBiosConfigJob`` to specify an exact manager (https://github.com/ansible-collections/community.general/issues/2090).
-- ini_file - make ``section`` parameter not required so it is possible to pass ``null`` as a value. This only was possible in the past due to a bug in ansible-core that now has been fixed (https://github.com/ansible-collections/community.general/pull/6404).
-- keycloak - improve error messages (https://github.com/ansible-collections/community.general/pull/6318).
-- one_vm - fix syntax error when creating VMs with a more complex template (https://github.com/ansible-collections/community.general/issues/6225).
-- pipx - fixed handling of ``install_deps=true`` with ``state=latest`` and ``state=upgrade`` (https://github.com/ansible-collections/community.general/pull/6303).
-- redhat_subscription - do not use D-Bus for registering when ``environment`` is specified, so it possible to specify again the environment names for registering, as the D-Bus APIs work only with IDs (https://github.com/ansible-collections/community.general/pull/6319).
-- redhat_subscription - try to unregister only when already registered when ``force_register`` is specified (https://github.com/ansible-collections/community.general/issues/6258, https://github.com/ansible-collections/community.general/pull/6259).
-- redhat_subscription - use the right D-Bus options for environments when registering a CentOS Stream 8 system and using ``environment`` (https://github.com/ansible-collections/community.general/pull/6275).
-- rhsm_release - make ``release`` parameter not required so it is possible to pass ``null`` as a value. This only was possible in the past due to a bug in ansible-core that now has been fixed (https://github.com/ansible-collections/community.general/pull/6401).
-- rundeck module utils - fix errors caused by the API empty responses (https://github.com/ansible-collections/community.general/pull/6300)
-- rundeck_acl_policy - fix ``TypeError - byte indices must be integers or slices, not str`` error caused by empty API response. Update the module to use ``module_utils.rundeck`` functions (https://github.com/ansible-collections/community.general/pull/5887, https://github.com/ansible-collections/community.general/pull/6300).
-- rundeck_project - update the module to use ``module_utils.rundeck`` functions (https://github.com/ansible-collections/community.general/issues/5742) (https://github.com/ansible-collections/community.general/pull/6300)
-- snap_alias - module would only recognize snap names containing letter, numbers or the underscore character, failing to identify valid snap names such as ``lxd.lxc`` (https://github.com/ansible-collections/community.general/pull/6361).
+- aix_filesystem - fix issue with empty list items in crfs logic and option order (https://github.com/ansible-collections/community.general/pull/8052).
+- consul_token - fix token creation without ``accessor_id`` (https://github.com/ansible-collections/community.general/pull/8091).
+- homebrew - error returned from brew command was ignored and tried to parse empty JSON. Fix now checks for an error and raises it to give accurate error message to users (https://github.com/ansible-collections/community.general/issues/8047).
+- ipa_hbacrule - the module uses a string for ``ipaenabledflag`` for new FreeIPA versions while the returned value is a boolean (https://github.com/ansible-collections/community.general/pull/7880).
+- ipa_sudorule - the module uses a string for ``ipaenabledflag`` for new FreeIPA versions while the returned value is a boolean (https://github.com/ansible-collections/community.general/pull/7880).
+- iptables_state - fix idempotency issues when restoring incomplete iptables dumps (https://github.com/ansible-collections/community.general/issues/8029).
+- linode inventory plugin - add descriptive error message for linode inventory plugin (https://github.com/ansible-collections/community.general/pull/8133).
+- pacemaker_cluster - actually implement check mode, which the module claims to support. This means that until now the module also did changes in check mode (https://github.com/ansible-collections/community.general/pull/8081).
+- pam_limits - when the file does not exist, do not create it in check mode (https://github.com/ansible-collections/community.general/issues/8050, https://github.com/ansible-collections/community.general/pull/8057).
+- proxmox_kvm - fixed status check getting from node-specific API endpoint (https://github.com/ansible-collections/community.general/issues/7817).
New Modules
-----------
-- btrfs_info - Query btrfs filesystem info
-- btrfs_subvolume - Manage btrfs subvolumes
-- ilo_redfish_command - Manages Out-Of-Band controllers using Redfish APIs
-- keycloak_authz_authorization_scope - Allows administration of Keycloak client authorization scopes via Keycloak API
-- keycloak_clientscope_type - Set the type of aclientscope in realm or client via Keycloak API
+- usb_facts - Allows listing information about USB devices
-v6.5.0
+v8.4.0
======
Release Summary
---------------
-Feature and bugfix release.
+Regular bugfix and feature release.
Minor Changes
-------------
-- apt_rpm - adds ``clean``, ``dist_upgrade`` and ``update_kernel`` parameters for clear caches, complete upgrade system, and upgrade kernel packages (https://github.com/ansible-collections/community.general/pull/5867).
-- dconf - parse GVariants for equality comparison when the Python module ``gi.repository`` is available (https://github.com/ansible-collections/community.general/pull/6049).
-- gitlab_runner - allow to register group runner (https://github.com/ansible-collections/community.general/pull/3935).
-- jira - add worklog functionality (https://github.com/ansible-collections/community.general/issues/6209, https://github.com/ansible-collections/community.general/pull/6210).
-- ldap modules - add ``ca_path`` option (https://github.com/ansible-collections/community.general/pull/6185).
-- make - add ``command`` return value to the module output (https://github.com/ansible-collections/community.general/pull/6160).
-- nmap inventory plugin - add new option ``open`` for only returning open ports (https://github.com/ansible-collections/community.general/pull/6200).
-- nmap inventory plugin - add new option ``port`` for port specific scan (https://github.com/ansible-collections/community.general/pull/6165).
-- nmcli - add ``default`` and ``default-or-eui64`` to the list of valid choices for ``addr_gen_mode6`` parameter (https://github.com/ansible-collections/community.general/pull/5974).
-- nmcli - add support for ``team.runner-fast-rate`` parameter for ``team`` connections (https://github.com/ansible-collections/community.general/issues/6065).
-- openbsd_pkg - set ``TERM`` to ``'dumb'`` in ``execute_command()`` to make module less dependant on the ``TERM`` environment variable set on the Ansible controller (https://github.com/ansible-collections/community.general/pull/6149).
-- pipx - optional ``install_apps`` parameter added to install applications from injected packages (https://github.com/ansible-collections/community.general/pull/6198).
-- proxmox_kvm - add new ``archive`` parameter. This is needed to create a VM from an archive (backup) (https://github.com/ansible-collections/community.general/pull/6159).
-- redfish_info - adds commands to retrieve the HPE ThermalConfiguration and FanPercentMinimum settings from iLO (https://github.com/ansible-collections/community.general/pull/6208).
-- redhat_subscription - credentials (``username``, ``activationkey``, and so on) are required now only if a system needs to be registered, or ``force_register`` is specified (https://github.com/ansible-collections/community.general/pull/5664).
-- redhat_subscription - the registration is done using the D-Bus ``rhsm`` service instead of spawning a ``subscription-manager register`` command, if possible; this avoids passing plain-text credentials as arguments to ``subscription-manager register``, which can be seen while that command runs (https://github.com/ansible-collections/community.general/pull/6122).
-- ssh_config - add ``proxyjump`` option (https://github.com/ansible-collections/community.general/pull/5970).
-- ssh_config - vendored StormSSH's config parser to avoid having to install StormSSH to use the module (https://github.com/ansible-collections/community.general/pull/6117).
-- znode module - optional ``use_tls`` parameter added for encrypted communication (https://github.com/ansible-collections/community.general/issues/6154).
+- bitwarden lookup plugin - add ``bw_session`` option, to pass session key instead of reading from env (https://github.com/ansible-collections/community.general/pull/7994).
+- gitlab_deploy_key, gitlab_group_members, gitlab_group_variable, gitlab_hook, gitlab_instance_variable, gitlab_project_badge, gitlab_project_variable, gitlab_user - improve API pagination and compatibility with different versions of ``python-gitlab`` (https://github.com/ansible-collections/community.general/pull/7790).
+- gitlab_hook - adds ``releases_events`` parameter for supporting Releases events triggers on GitLab hooks (https://github.com/ansible-collections/community.general/pull/7956).
+- icinga2 inventory plugin - add Jinja2 templating support to ``url``, ``user``, and ``password`` paramenters (https://github.com/ansible-collections/community.general/issues/7074, https://github.com/ansible-collections/community.general/pull/7996).
+- mssql_script - adds transactional (rollback/commit) support via optional boolean param ``transaction`` (https://github.com/ansible-collections/community.general/pull/7976).
+- proxmox_kvm - add parameter ``update_unsafe`` to avoid limitations when updating dangerous values (https://github.com/ansible-collections/community.general/pull/7843).
+- redfish_config - add command ``SetServiceIdentification`` to set service identification (https://github.com/ansible-collections/community.general/issues/7916).
+- sudoers - add support for the ``NOEXEC`` tag in sudoers rules (https://github.com/ansible-collections/community.general/pull/7983).
+- terraform - fix ``diff_mode`` in state ``absent`` and when terraform ``resource_changes`` does not exist (https://github.com/ansible-collections/community.general/pull/7963).
Bugfixes
--------
-- archive - avoid deprecated exception class on Python 3 (https://github.com/ansible-collections/community.general/pull/6180).
-- gitlab_runner - fix ``KeyError`` on runner creation and update (https://github.com/ansible-collections/community.general/issues/6112).
-- influxdb_user - fix running in check mode when the user does not exist yet (https://github.com/ansible-collections/community.general/pull/6111).
-- interfaces_file - fix reading options in lines not starting with a space (https://github.com/ansible-collections/community.general/issues/6120).
-- jail connection plugin - add ``inventory_hostname`` to vars under ``remote_addr``. This is needed for compatibility with ansible-core 2.13 (https://github.com/ansible-collections/community.general/pull/6118).
-- memset - fix memset urlerror handling (https://github.com/ansible-collections/community.general/pull/6114).
-- nmcli - fixed idempotency issue for bridge connections. Module forced default value of ``bridge.priority`` to nmcli if not set; if ``bridge.stp`` is disabled nmcli ignores it and keep default (https://github.com/ansible-collections/community.general/issues/3216, https://github.com/ansible-collections/community.general/issues/4683).
-- nmcli - fixed idempotency issue when module params is set to ``may_fail4=false`` and ``method4=disabled``; in this case nmcli ignores change and keeps their own default value ``yes`` (https://github.com/ansible-collections/community.general/pull/6106).
-- nmcli - implemented changing mtu value on vlan interfaces (https://github.com/ansible-collections/community.general/issues/4387).
-- opkg - fixes bug when using ``update_cache=true`` (https://github.com/ansible-collections/community.general/issues/6004).
-- redhat_subscription, rhsm_release, rhsm_repository - cleanly fail when not running as root, rather than hanging on an interactive ``console-helper`` prompt; they all interact with ``subscription-manager``, which already requires to be run as root (https://github.com/ansible-collections/community.general/issues/734, https://github.com/ansible-collections/community.general/pull/6211).
-- xenorchestra inventory plugin - fix failure to receive objects from server due to not checking the id of the response (https://github.com/ansible-collections/community.general/pull/6227).
-- yarn - fix ``global=true`` to not fail when `executable` wasn't specified (https://github.com/ansible-collections/community.general/pull/6132)
-- yarn - fixes bug where yarn module tasks would fail when warnings were emitted from Yarn. The ``yarn.list`` method was not filtering out warnings (https://github.com/ansible-collections/community.general/issues/6127).
+- cargo - fix idempotency issues when using a custom installation path for packages (using the ``--path`` parameter). The initial installation runs fine, but subsequent runs use the ``get_installed()`` function which did not check the given installation location, before running ``cargo install``. This resulted in a false ``changed`` state. Also the removal of packeges using ``state: absent`` failed, as the installation check did not use the given parameter (https://github.com/ansible-collections/community.general/pull/7970).
+- gitlab_issue - fix behavior to search GitLab issue, using ``search`` keyword instead of ``title`` (https://github.com/ansible-collections/community.general/issues/7846).
+- gitlab_runner - fix pagination when checking for existing runners (https://github.com/ansible-collections/community.general/pull/7790).
+- keycloak_client - fixes issue when metadata is provided in desired state when task is in check mode (https://github.com/ansible-collections/community.general/issues/1226, https://github.com/ansible-collections/community.general/pull/7881).
+- modprobe - listing modules files or modprobe files could trigger a FileNotFoundError if ``/etc/modprobe.d`` or ``/etc/modules-load.d`` did not exist. Relevant functions now return empty lists if the directories do not exist to avoid crashing the module (https://github.com/ansible-collections/community.general/issues/7717).
+- onepassword lookup plugin - failed for fields that were in sections and had uppercase letters in the label/ID. Field lookups are now case insensitive in all cases (https://github.com/ansible-collections/community.general/pull/7919).
+- pkgin - pkgin (pkgsrc package manager used by SmartOS) raises erratic exceptions and spurious ``changed=true`` (https://github.com/ansible-collections/community.general/pull/7971).
+- redfish_info - allow for a GET operation invoked by ``GetUpdateStatus`` to allow for an empty response body for cases where a service returns 204 No Content (https://github.com/ansible-collections/community.general/issues/8003).
+- redfish_info - correct uncaught exception when attempting to retrieve ``Chassis`` information (https://github.com/ansible-collections/community.general/pull/7952).
New Plugins
-----------
-Lookup
+Callback
+~~~~~~~~
+
+- default_without_diff - The default ansible callback without diff output
+
+Filter
~~~~~~
-- merge_variables - merge variables with a certain suffix
+- lists_difference - Difference of lists with a predictive order
+- lists_intersect - Intersection of lists with a predictive order
+- lists_symmetric_difference - Symmetric Difference of lists with a predictive order
+- lists_union - Union of lists with a predictive order
New Modules
-----------
-- kdeconfig - Manage KDE configuration files
+- gitlab_group_access_token - Manages GitLab group access tokens
+- gitlab_project_access_token - Manages GitLab project access tokens
-v6.4.0
+v8.3.0
======
Release Summary
---------------
-Regular feature and bugfix release.
+Regular bugfix and feature release.
Minor Changes
-------------
-- dnsimple - set custom User-Agent for API requests to DNSimple (https://github.com/ansible-collections/community.general/pull/5927).
-- flatpak_remote - add new boolean option ``enabled``. It controls, whether the remote is enabled or not (https://github.com/ansible-collections/community.general/pull/5926).
-- gitlab_project - add ``releases_access_level``, ``environments_access_level``, ``feature_flags_access_level``, ``infrastructure_access_level``, ``monitor_access_level``, and ``security_and_compliance_access_level`` options (https://github.com/ansible-collections/community.general/pull/5986).
-- jc filter plugin - added the ability to use parser plugins (https://github.com/ansible-collections/community.general/pull/6043).
-- keycloak_group - add new optional module parameter ``parents`` to properly handle keycloak subgroups (https://github.com/ansible-collections/community.general/pull/5814).
-- keycloak_user_federation - make ``org.keycloak.storage.ldap.mappers.LDAPStorageMapper`` the default value for mappers ``providerType`` (https://github.com/ansible-collections/community.general/pull/5863).
-- ldap modules - add ``xorder_discovery`` option (https://github.com/ansible-collections/community.general/issues/6045, https://github.com/ansible-collections/community.general/pull/6109).
-- lxd_container - add diff and check mode (https://github.com/ansible-collections/community.general/pull/5866).
-- mattermost, rocketchat, slack - replace missing default favicon with docs.ansible.com favicon (https://github.com/ansible-collections/community.general/pull/5928).
-- modprobe - add ``persistent`` option (https://github.com/ansible-collections/community.general/issues/4028, https://github.com/ansible-collections/community.general/pull/542).
-- osx_defaults - include stderr in error messages (https://github.com/ansible-collections/community.general/pull/6011).
-- proxmox - suppress urllib3 ``InsecureRequestWarnings`` when ``validate_certs`` option is ``false`` (https://github.com/ansible-collections/community.general/pull/5931).
-- redfish_command - adding ``EnableSecureBoot`` functionality (https://github.com/ansible-collections/community.general/pull/5899).
-- redfish_command - adding ``VerifyBiosAttributes`` functionality (https://github.com/ansible-collections/community.general/pull/5900).
-- sefcontext - add support for path substitutions (https://github.com/ansible-collections/community.general/issues/1193).
+- consul_auth_method, consul_binding_rule, consul_policy, consul_role, consul_session, consul_token - added action group ``community.general.consul`` (https://github.com/ansible-collections/community.general/pull/7897).
+- consul_policy - added support for diff and check mode (https://github.com/ansible-collections/community.general/pull/7878).
+- consul_policy, consul_role, consul_session - removed dependency on ``requests`` and factored out common parts (https://github.com/ansible-collections/community.general/pull/7826, https://github.com/ansible-collections/community.general/pull/7878).
+- consul_role - ``node_identities`` now expects a ``node_name`` option to match the Consul API, the old ``name`` is still supported as alias (https://github.com/ansible-collections/community.general/pull/7878).
+- consul_role - ``service_identities`` now expects a ``service_name`` option to match the Consul API, the old ``name`` is still supported as alias (https://github.com/ansible-collections/community.general/pull/7878).
+- consul_role - added support for diff mode (https://github.com/ansible-collections/community.general/pull/7878).
+- consul_role - added support for templated policies (https://github.com/ansible-collections/community.general/pull/7878).
+- redfish_info - add command ``GetServiceIdentification`` to get service identification (https://github.com/ansible-collections/community.general/issues/7882).
+- terraform - add support for ``diff_mode`` for terraform resource_changes (https://github.com/ansible-collections/community.general/pull/7896).
Deprecated Features
-------------------
-- gitlab_runner - the option ``access_level`` will lose its default value in community.general 8.0.0. From that version on, you have set this option to ``ref_protected`` explicitly, if you want to have a protected runner (https://github.com/ansible-collections/community.general/issues/5925).
+- consul_acl - the module has been deprecated and will be removed in community.general 10.0.0. ``consul_token`` and ``consul_policy`` can be used instead (https://github.com/ansible-collections/community.general/pull/7901).
Bugfixes
--------
-- cartesian and flattened lookup plugins - adjust to parameter deprecation in ansible-core 2.14's ``listify_lookup_plugin_terms`` helper function (https://github.com/ansible-collections/community.general/pull/6074).
-- cloudflare_dns - fixed the idempotency for SRV DNS records (https://github.com/ansible-collections/community.general/pull/5972).
-- cloudflare_dns - fixed the possiblity of setting a root-level SRV DNS record (https://github.com/ansible-collections/community.general/pull/5972).
-- github_webhook - fix always changed state when no secret is provided (https://github.com/ansible-collections/community.general/pull/5994).
-- jenkins_plugin - fix error due to undefined variable when updates file is not downloaded (https://github.com/ansible-collections/community.general/pull/6100).
-- keycloak_client - fix accidental replacement of value for attribute ``saml.signing.private.key`` with ``no_log`` in wrong contexts (https://github.com/ansible-collections/community.general/pull/5934).
-- lxd_* modules, lxd inventory plugin - fix TLS/SSL certificate validation problems by using the correct purpose when creating the TLS context (https://github.com/ansible-collections/community.general/issues/5616, https://github.com/ansible-collections/community.general/pull/6034).
-- nmcli - fix change handling of values specified as an integer 0 (https://github.com/ansible-collections/community.general/pull/5431).
-- nmcli - fix failure to handle WIFI settings when connection type not specified (https://github.com/ansible-collections/community.general/pull/5431).
-- nmcli - fix improper detection of changes to ``wifi.wake-on-wlan`` (https://github.com/ansible-collections/community.general/pull/5431).
-- nmcli - order is significant for lists of addresses (https://github.com/ansible-collections/community.general/pull/6048).
-- onepassword lookup plugin - Changed to ignore errors from "op account get" calls. Previously, errors would prevent auto-signin code from executing (https://github.com/ansible-collections/community.general/pull/5942).
-- terraform and timezone - slight refactoring to avoid linter reporting potentially undefined variables (https://github.com/ansible-collections/community.general/pull/5933).
-- various plugins and modules - remove unnecessary imports (https://github.com/ansible-collections/community.general/pull/5940).
-- yarn - fix ``global=true`` to check for the configured global folder instead of assuming the default (https://github.com/ansible-collections/community.general/pull/5829)
-- yarn - fix ``state=absent`` not working with ``global=true`` when the package does not include a binary (https://github.com/ansible-collections/community.general/pull/5829)
-- yarn - fix ``state=latest`` not working with ``global=true`` (https://github.com/ansible-collections/community.general/issues/5712).
-- zfs_delegate_admin - zfs allow output can now be parsed when uids/gids are not known to the host system (https://github.com/ansible-collections/community.general/pull/5943).
-- zypper - make package managing work on readonly filesystem of openSUSE MicroOS (https://github.com/ansible-collections/community.general/pull/5615).
-
-v6.3.0
+- homebrew - detect already installed formulae and casks using JSON output from ``brew info`` (https://github.com/ansible-collections/community.general/issues/864).
+- incus connection plugin - treats ``inventory_hostname`` as a variable instead of a literal in remote connections (https://github.com/ansible-collections/community.general/issues/7874).
+- ipa_otptoken - the module expect ``ipatokendisabled`` as string but the ``ipatokendisabled`` value is returned as a boolean (https://github.com/ansible-collections/community.general/pull/7795).
+- ldap - previously the order number (if present) was expected to follow an equals sign in the DN. This makes it so the order number string is identified correctly anywhere within the DN (https://github.com/ansible-collections/community.general/issues/7646).
+- mssql_script - make the module work with Python 2 (https://github.com/ansible-collections/community.general/issues/7818, https://github.com/ansible-collections/community.general/pull/7821).
+- nmcli - fix ``connection.slave-type`` wired to ``bond`` and not with parameter ``slave_type`` in case of connection type ``wifi`` (https://github.com/ansible-collections/community.general/issues/7389).
+- proxmox - fix updating a container config if the setting does not already exist (https://github.com/ansible-collections/community.general/pull/7872).
+
+New Modules
+-----------
+
+- consul_acl_bootstrap - Bootstrap ACLs in Consul
+- consul_auth_method - Manipulate Consul auth methods
+- consul_binding_rule - Manipulate Consul binding rules
+- consul_token - Manipulate Consul tokens
+- gitlab_label - Creates/updates/deletes GitLab Labels belonging to project or group.
+- gitlab_milestone - Creates/updates/deletes GitLab Milestones belonging to project or group
+
+v8.2.0
======
Release Summary
@@ -237,66 +165,57 @@ Regular bugfix and feature release.
Minor Changes
-------------
-- apache2_module - add module argument ``warn_mpm_absent`` to control whether warning are raised in some edge cases (https://github.com/ansible-collections/community.general/pull/5793).
-- bitwarden lookup plugin - can now retrieve secrets from custom fields (https://github.com/ansible-collections/community.general/pull/5694).
-- bitwarden lookup plugin - implement filtering results by ``collection_id`` parameter (https://github.com/ansible-collections/community.general/issues/5849).
-- dig lookup plugin - support CAA record type (https://github.com/ansible-collections/community.general/pull/5913).
-- gitlab_project - add ``builds_access_level``, ``container_registry_access_level`` and ``forking_access_level`` options (https://github.com/ansible-collections/community.general/pull/5706).
-- gitlab_runner - add new boolean option ``access_level_on_creation``. It controls, whether the value of ``access_level`` is used for runner registration or not. The option ``access_level`` has been ignored on registration so far and was only used on updates (https://github.com/ansible-collections/community.general/issues/5907, https://github.com/ansible-collections/community.general/pull/5908).
-- ilo_redfish_utils module utils - change implementation of DNS Server IP and NTP Server IP update (https://github.com/ansible-collections/community.general/pull/5804).
-- ipa_group - allow to add and remove external users with the ``external_user`` option (https://github.com/ansible-collections/community.general/pull/5897).
-- iptables_state - minor refactoring within the module (https://github.com/ansible-collections/community.general/pull/5844).
-- one_vm - add a new ``updateconf`` option which implements the ``one.vm.updateconf`` API call (https://github.com/ansible-collections/community.general/pull/5812).
-- opkg - refactored module to use ``CmdRunner`` for executing ``opkg`` (https://github.com/ansible-collections/community.general/pull/5718).
-- redhat_subscription - adds ``token`` parameter for subscription-manager authentication using Red Hat API token (https://github.com/ansible-collections/community.general/pull/5725).
-- snap - minor refactor when executing module (https://github.com/ansible-collections/community.general/pull/5773).
-- snap_alias - refactored module to use ``CmdRunner`` to execute ``snap`` (https://github.com/ansible-collections/community.general/pull/5486).
-- sudoers - add ``setenv`` parameters to support passing environment variables via sudo. (https://github.com/ansible-collections/community.general/pull/5883)
+- ipa_dnsrecord - adds ability to manage NS record types (https://github.com/ansible-collections/community.general/pull/7737).
+- ipa_pwpolicy - refactor module and exchange a sequence ``if`` statements with a ``for`` loop (https://github.com/ansible-collections/community.general/pull/7723).
+- ipa_pwpolicy - update module to support ``maxrepeat``, ``maxsequence``, ``dictcheck``, ``usercheck``, ``gracelimit`` parameters in FreeIPA password policies (https://github.com/ansible-collections/community.general/pull/7723).
+- keycloak_realm_key - the ``config.algorithm`` option now supports 8 additional key algorithms (https://github.com/ansible-collections/community.general/pull/7698).
+- keycloak_realm_key - the ``config.certificate`` option value is no longer defined with ``no_log=True`` (https://github.com/ansible-collections/community.general/pull/7698).
+- keycloak_realm_key - the ``provider_id`` option now supports RSA encryption key usage (value ``rsa-enc``) (https://github.com/ansible-collections/community.general/pull/7698).
+- keycloak_user_federation - allow custom user storage providers to be set through ``provider_id`` (https://github.com/ansible-collections/community.general/pull/7789).
+- mail - add ``Message-ID`` header; which is required by some mail servers (https://github.com/ansible-collections/community.general/pull/7740).
+- mail module, mail callback plugin - allow to configure the domain name of the Message-ID header with a new ``message_id_domain`` option (https://github.com/ansible-collections/community.general/pull/7765).
+- ssh_config - new feature to set ``AddKeysToAgent`` option to ``yes`` or ``no`` (https://github.com/ansible-collections/community.general/pull/7703).
+- ssh_config - new feature to set ``IdentitiesOnly`` option to ``yes`` or ``no`` (https://github.com/ansible-collections/community.general/pull/7704).
+- xcc_redfish_command - added support for raw POSTs (``command=PostResource`` in ``category=Raw``) without a specific action info (https://github.com/ansible-collections/community.general/pull/7746).
-Breaking Changes / Porting Guide
---------------------------------
+Bugfixes
+--------
-- ModuleHelper module utils - when the module sets output variables named ``msg``, ``exception``, ``output``, ``vars``, or ``changed``, the actual output will prefix those names with ``_`` (underscore symbol) only when they clash with output variables generated by ModuleHelper itself, which only occurs when handling exceptions. Please note that this breaking change does not require a new major release since before this release, it was not possible to add such variables to the output `due to a bug <https://github.com/ansible-collections/community.general/pull/5755>`__ (https://github.com/ansible-collections/community.general/pull/5765).
+- keycloak_identity_provider - ``mappers`` processing was not idempotent if the mappers configuration list had not been sorted by name (in ascending order). Fix resolves the issue by sorting mappers in the desired state using the same key which is used for obtaining existing state (https://github.com/ansible-collections/community.general/pull/7418).
+- keycloak_identity_provider - it was not possible to reconfigure (add, remove) ``mappers`` once they were created initially. Removal was ignored, adding new ones resulted in dropping the pre-existing unmodified mappers. Fix resolves the issue by supplying correct input to the internal update call (https://github.com/ansible-collections/community.general/pull/7418).
+- keycloak_user - when ``force`` is set, but user does not exist, do not try to delete it (https://github.com/ansible-collections/community.general/pull/7696).
+- proxmox_kvm - running ``state=template`` will first check whether VM is already a template (https://github.com/ansible-collections/community.general/pull/7792).
+- statusio_maintenance - fix error caused by incorrectly formed API data payload. Was raising "Failed to create maintenance HTTP Error 400 Bad Request" caused by bad data type for date/time and deprecated dict keys (https://github.com/ansible-collections/community.general/pull/7754).
-Deprecated Features
--------------------
+New Plugins
+-----------
-- consul - deprecate using parameters unused for ``state=absent`` (https://github.com/ansible-collections/community.general/pull/5772).
-- gitlab_runner - the default of the new option ``access_level_on_creation`` will change from ``false`` to ``true`` in community.general 7.0.0. This will cause ``access_level`` to be used during runner registration as well, and not only during updates (https://github.com/ansible-collections/community.general/pull/5908).
+Connection
+~~~~~~~~~~
-Bugfixes
---------
+- incus - Run tasks in Incus instances via the Incus CLI.
-- ModuleHelper - fix bug when adjusting the name of reserved output variables (https://github.com/ansible-collections/community.general/pull/5755).
-- alternatives - support subcommands on Fedora 37, which uses ``follower`` instead of ``slave`` (https://github.com/ansible-collections/community.general/pull/5794).
-- bitwarden lookup plugin - clarify what to do, if the bitwarden vault is not unlocked (https://github.com/ansible-collections/community.general/pull/5811).
-- dig lookup plugin - correctly handle DNSKEY record type's ``algorithm`` field (https://github.com/ansible-collections/community.general/pull/5914).
-- gem - fix force parameter not being passed to gem command when uninstalling (https://github.com/ansible-collections/community.general/pull/5822).
-- gem - fix hang due to interactive prompt for confirmation on specific version uninstall (https://github.com/ansible-collections/community.general/pull/5751).
-- gitlab_deploy_key - also update ``title`` and not just ``can_push`` (https://github.com/ansible-collections/community.general/pull/5888).
-- keycloak_user_federation - fixes federation creation issue. When a new federation was created and at the same time a default / standard mapper was also changed / updated the creation process failed as a bad None set variable led to a bad malformed url request (https://github.com/ansible-collections/community.general/pull/5750).
-- keycloak_user_federation - fixes idempotency detection issues. In some cases the module could fail to properly detect already existing user federations because of a buggy seemingly superflous extra query parameter (https://github.com/ansible-collections/community.general/pull/5732).
-- loganalytics callback plugin - adjust type of callback to ``notification``, it was incorrectly classified as ``aggregate`` before (https://github.com/ansible-collections/community.general/pull/5761).
-- logdna callback plugin - adjust type of callback to ``notification``, it was incorrectly classified as ``aggregate`` before (https://github.com/ansible-collections/community.general/pull/5761).
-- logstash callback plugin - adjust type of callback to ``notification``, it was incorrectly classified as ``aggregate`` before (https://github.com/ansible-collections/community.general/pull/5761).
-- nsupdate - fix zone lookup. The SOA record for an existing zone is returned as an answer RR and not as an authority RR (https://github.com/ansible-collections/community.general/issues/5817, https://github.com/ansible-collections/community.general/pull/5818).
-- proxmox_disk - fixed issue with read timeout on import action (https://github.com/ansible-collections/community.general/pull/5803).
-- redfish_utils - removed basic auth HTTP header when performing a GET on the service root resource and when performing a POST to the session collection (https://github.com/ansible-collections/community.general/issues/5886).
-- splunk callback plugin - adjust type of callback to ``notification``, it was incorrectly classified as ``aggregate`` before (https://github.com/ansible-collections/community.general/pull/5761).
-- sumologic callback plugin - adjust type of callback to ``notification``, it was incorrectly classified as ``aggregate`` before (https://github.com/ansible-collections/community.general/pull/5761).
-- syslog_json callback plugin - adjust type of callback to ``notification``, it was incorrectly classified as ``aggregate`` before (https://github.com/ansible-collections/community.general/pull/5761).
-- terraform - fix ``current`` workspace never getting appended to the ``all`` key in the ``workspace_ctf`` object (https://github.com/ansible-collections/community.general/pull/5735).
-- terraform - fix ``terraform init`` failure when there are multiple workspaces on the remote backend and when ``default`` workspace is missing by setting ``TF_WORKSPACE`` environmental variable to the value of ``workspace`` when used (https://github.com/ansible-collections/community.general/pull/5735).
-- terraform module - disable ANSI escape sequences during validation phase (https://github.com/ansible-collections/community.general/pull/5843).
-- xml - fixed a bug where empty ``children`` list would not be set (https://github.com/ansible-collections/community.general/pull/5808).
+Filter
+~~~~~~
+
+- from_ini - Converts INI text input into a dictionary
+- to_ini - Converts a dictionary to the INI file format
+
+Lookup
+~~~~~~
+
+- github_app_access_token - Obtain short-lived Github App Access tokens
New Modules
-----------
-- ocapi_command - Manages Out-Of-Band controllers using Open Composable API (OCAPI)
-- ocapi_info - Manages Out-Of-Band controllers using Open Composable API (OCAPI)
+- dnf_config_manager - Enable or disable dnf repositories using config-manager
+- keycloak_component_info - Retrive component info in Keycloak
+- keycloak_realm_rolemapping - Allows administration of Keycloak realm role mappings into groups with the Keycloak API
+- proxmox_node_info - Retrieve information about one or more Proxmox VE nodes
+- proxmox_storage_contents_info - List content from a Proxmox VE storage
-v6.2.0
+v8.1.0
======
Release Summary
@@ -307,399 +226,431 @@ Regular bugfix and feature release.
Minor Changes
-------------
-- opkg - allow installing a package in a certain version (https://github.com/ansible-collections/community.general/pull/5688).
-- proxmox - added new module parameter ``tags`` for use with PVE 7+ (https://github.com/ansible-collections/community.general/pull/5714).
-- puppet - refactored module to use ``CmdRunner`` for executing ``puppet`` (https://github.com/ansible-collections/community.general/pull/5612).
-- redhat_subscription - add a ``server_proxy_scheme`` parameter to configure the scheme for the proxy server (https://github.com/ansible-collections/community.general/pull/5662).
-- ssh_config - refactor code to module util to fix sanity check (https://github.com/ansible-collections/community.general/pull/5720).
-- sudoers - adds ``host`` parameter for setting hostname restrictions in sudoers rules (https://github.com/ansible-collections/community.general/issues/5702).
-
-Deprecated Features
--------------------
-
-- manageiq_policies - deprecate ``state=list`` in favour of using ``community.general.manageiq_policies_info`` (https://github.com/ansible-collections/community.general/pull/5721).
-- rax - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
-- rax_cbs - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
-- rax_cbs_attachments - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
-- rax_cdb - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
-- rax_cdb_database - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
-- rax_cdb_user - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
-- rax_clb - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
-- rax_clb_nodes - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
-- rax_clb_ssl - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
-- rax_dns - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
-- rax_dns_record - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
-- rax_facts - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
-- rax_files - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
-- rax_files_objects - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
-- rax_identity - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
-- rax_keypair - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
-- rax_meta - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
-- rax_mon_alarm - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
-- rax_mon_check - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
-- rax_mon_entity - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
-- rax_mon_notification - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
-- rax_mon_notification_plan - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
-- rax_network - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
-- rax_queue - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
-- rax_scaling_group - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
-- rax_scaling_policy - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
+- bitwarden lookup plugin - when looking for items using an item ID, the item is now accessed directly with ``bw get item`` instead of searching through all items. This doubles the lookup speed (https://github.com/ansible-collections/community.general/pull/7468).
+- elastic callback plugin - close elastic client to not leak resources (https://github.com/ansible-collections/community.general/pull/7517).
+- git_config - allow multiple git configs for the same name with the new ``add_mode`` option (https://github.com/ansible-collections/community.general/pull/7260).
+- git_config - the ``after`` and ``before`` fields in the ``diff`` of the return value can be a list instead of a string in case more configs with the same key are affected (https://github.com/ansible-collections/community.general/pull/7260).
+- git_config - when a value is unset, all configs with the same key are unset (https://github.com/ansible-collections/community.general/pull/7260).
+- gitlab modules - add ``ca_path`` option (https://github.com/ansible-collections/community.general/pull/7472).
+- gitlab modules - remove duplicate ``gitlab`` package check (https://github.com/ansible-collections/community.general/pull/7486).
+- gitlab_runner - add support for new runner creation workflow (https://github.com/ansible-collections/community.general/pull/7199).
+- ipa_config - adds ``passkey`` choice to ``ipauserauthtype`` parameter's choices (https://github.com/ansible-collections/community.general/pull/7588).
+- ipa_sudorule - adds options to include denied commands or command groups (https://github.com/ansible-collections/community.general/pull/7415).
+- ipa_user - adds ``idp`` and ``passkey`` choice to ``ipauserauthtype`` parameter's choices (https://github.com/ansible-collections/community.general/pull/7589).
+- irc - add ``validate_certs`` option, and rename ``use_ssl`` to ``use_tls``, while keeping ``use_ssl`` as an alias. The default value for ``validate_certs`` is ``false`` for backwards compatibility. We recommend to every user of this module to explicitly set ``use_tls=true`` and `validate_certs=true`` whenever possible, especially when communicating to IRC servers over the internet (https://github.com/ansible-collections/community.general/pull/7550).
+- keycloak module utils - expose error message from Keycloak server for HTTP errors in some specific situations (https://github.com/ansible-collections/community.general/pull/7645).
+- keycloak_user_federation - add option for ``krbPrincipalAttribute`` (https://github.com/ansible-collections/community.general/pull/7538).
+- lvol - change ``pvs`` argument type to list of strings (https://github.com/ansible-collections/community.general/pull/7676, https://github.com/ansible-collections/community.general/issues/7504).
+- lxd connection plugin - tighten the detection logic for lxd ``Instance not found`` errors, to avoid false detection on unrelated errors such as ``/usr/bin/python3: not found`` (https://github.com/ansible-collections/community.general/pull/7521).
+- netcup_dns - adds support for record types ``OPENPGPKEY``, ``SMIMEA``, and ``SSHFP`` (https://github.com/ansible-collections/community.general/pull/7489).
+- nmcli - add support for new connection type ``loopback`` (https://github.com/ansible-collections/community.general/issues/6572).
+- nmcli - allow for ``infiniband`` slaves of ``bond`` interface types (https://github.com/ansible-collections/community.general/pull/7569).
+- nmcli - allow for the setting of ``MTU`` for ``infiniband`` and ``bond`` interface types (https://github.com/ansible-collections/community.general/pull/7499).
+- onepassword lookup plugin - support 1Password Connect with the opv2 client by setting the connect_host and connect_token parameters (https://github.com/ansible-collections/community.general/pull/7116).
+- onepassword_raw lookup plugin - support 1Password Connect with the opv2 client by setting the connect_host and connect_token parameters (https://github.com/ansible-collections/community.general/pull/7116)
+- passwordstore - adds ``timestamp`` and ``preserve`` parameters to modify the stored password format (https://github.com/ansible-collections/community.general/pull/7426).
+- proxmox - adds ``template`` value to the ``state`` parameter, allowing conversion of container to a template (https://github.com/ansible-collections/community.general/pull/7143).
+- proxmox - adds ``update`` parameter, allowing update of an already existing containers configuration (https://github.com/ansible-collections/community.general/pull/7540).
+- proxmox inventory plugin - adds an option to exclude nodes from the dynamic inventory generation. The new setting is optional, not using this option will behave as usual (https://github.com/ansible-collections/community.general/issues/6714, https://github.com/ansible-collections/community.general/pull/7461).
+- proxmox_disk - add ability to manipulate CD-ROM drive (https://github.com/ansible-collections/community.general/pull/7495).
+- proxmox_kvm - adds ``template`` value to the ``state`` parameter, allowing conversion of a VM to a template (https://github.com/ansible-collections/community.general/pull/7143).
+- proxmox_kvm - support the ``hookscript`` parameter (https://github.com/ansible-collections/community.general/issues/7600).
+- proxmox_ostype - it is now possible to specify the ``ostype`` when creating an LXC container (https://github.com/ansible-collections/community.general/pull/7462).
+- proxmox_vm_info - add ability to retrieve configuration info (https://github.com/ansible-collections/community.general/pull/7485).
+- redfish_info - adding the ``BootProgress`` property when getting ``Systems`` info (https://github.com/ansible-collections/community.general/pull/7626).
+- ssh_config - adds ``controlmaster``, ``controlpath`` and ``controlpersist`` parameters (https://github.com/ansible-collections/community.general/pull/7456).
Bugfixes
--------
-- ansible_galaxy_install - set default to raise exception if command's return code is different from zero (https://github.com/ansible-collections/community.general/pull/5680).
-- ansible_galaxy_install - try ``C.UTF-8`` and then fall back to ``en_US.UTF-8`` before failing (https://github.com/ansible-collections/community.general/pull/5680).
-- gitlab_group_variables - fix dropping variables accidentally when GitLab introduced new properties (https://github.com/ansible-collections/community.general/pull/5667).
-- gitlab_project_variables - fix dropping variables accidentally when GitLab introduced new properties (https://github.com/ansible-collections/community.general/pull/5667).
-- lxc_container - fix the arguments of the lxc command which broke the creation and cloning of containers (https://github.com/ansible-collections/community.general/issues/5578).
-- opkg - fix issue that ``force=reinstall`` would not reinstall an existing package (https://github.com/ansible-collections/community.general/pull/5705).
-- proxmox_disk - fixed possible issues with redundant ``vmid`` parameter (https://github.com/ansible-collections/community.general/issues/5492, https://github.com/ansible-collections/community.general/pull/5672).
-- proxmox_nic - fixed possible issues with redundant ``vmid`` parameter (https://github.com/ansible-collections/community.general/issues/5492, https://github.com/ansible-collections/community.general/pull/5672).
-- unixy callback plugin - fix typo introduced when updating to use Ansible's configuration manager for handling options (https://github.com/ansible-collections/community.general/issues/5600).
-
-v6.1.0
-======
-
-Release Summary
----------------
-
-Regular bugfix and feature release.
-
-Minor Changes
--------------
+- apt-rpm - the module did not upgrade packages if a newer version exists. Now the package will be reinstalled if the candidate is newer than the installed version (https://github.com/ansible-collections/community.general/issues/7414).
+- cloudflare_dns - fix Cloudflare lookup of SHFP records (https://github.com/ansible-collections/community.general/issues/7652).
+- interface_files - also consider ``address_family`` when changing ``option=method`` (https://github.com/ansible-collections/community.general/issues/7610, https://github.com/ansible-collections/community.general/pull/7612).
+- irc - replace ``ssl.wrap_socket`` that was removed from Python 3.12 with code for creating a proper SSL context (https://github.com/ansible-collections/community.general/pull/7542).
+- keycloak_* - fix Keycloak API client to quote ``/`` properly (https://github.com/ansible-collections/community.general/pull/7641).
+- keycloak_authz_permission - resource payload variable for scope-based permission was constructed as a string, when it needs to be a list, even for a single item (https://github.com/ansible-collections/community.general/issues/7151).
+- log_entries callback plugin - replace ``ssl.wrap_socket`` that was removed from Python 3.12 with code for creating a proper SSL context (https://github.com/ansible-collections/community.general/pull/7542).
+- lvol - test for output messages in both ``stdout`` and ``stderr`` (https://github.com/ansible-collections/community.general/pull/7601, https://github.com/ansible-collections/community.general/issues/7182).
+- onepassword lookup plugin - field and section titles are now case insensitive when using op CLI version two or later. This matches the behavior of version one (https://github.com/ansible-collections/community.general/pull/7564).
+- redhat_subscription - use the D-Bus registration on RHEL 7 only on 7.4 and
+ greater; older versions of RHEL 7 do not have it
+ (https://github.com/ansible-collections/community.general/issues/7622,
+ https://github.com/ansible-collections/community.general/pull/7624).
+- terraform - fix multiline string handling in complex variables (https://github.com/ansible-collections/community.general/pull/7535).
-- cmd_runner module utils - ``cmd_runner_fmt.as_bool()`` can now take an extra parameter to format when value is false (https://github.com/ansible-collections/community.general/pull/5647).
-- gconftool2 - refactor using ``ModuleHelper`` and ``CmdRunner`` (https://github.com/ansible-collections/community.general/pull/5545).
-- java_certs - add more detailed error output when extracting certificate from PKCS12 fails (https://github.com/ansible-collections/community.general/pull/5550).
-- jenkins_plugin - refactor code to module util to fix sanity check (https://github.com/ansible-collections/community.general/pull/5565).
-- lxd_project - refactored code out to module utils to clear sanity check (https://github.com/ansible-collections/community.general/pull/5549).
-- nmap inventory plugin - add new options ``udp_scan``, ``icmp_timestamp``, and ``dns_resolve`` for different types of scans (https://github.com/ansible-collections/community.general/pull/5566).
-- rax_scaling_group - refactored out code to the ``rax`` module utils to clear the sanity check (https://github.com/ansible-collections/community.general/pull/5563).
-- redfish_command - add ``PerformRequestedOperations`` command to perform any operations necessary to continue the update flow (https://github.com/ansible-collections/community.general/issues/4276).
-- redfish_command - add ``update_apply_time`` to ``SimpleUpdate`` command (https://github.com/ansible-collections/community.general/issues/3910).
-- redfish_command - add ``update_status`` to output of ``SimpleUpdate`` command to allow a user monitor the update in progress (https://github.com/ansible-collections/community.general/issues/4276).
-- redfish_info - add ``GetUpdateStatus`` command to check the progress of a previous update request (https://github.com/ansible-collections/community.general/issues/4276).
-- redfish_utils module utils - added PUT (``put_request()``) functionality (https://github.com/ansible-collections/community.general/pull/5490).
-- slack - add option ``prepend_hash`` which allows to control whether a ``#`` is prepended to ``channel_id``. The current behavior (value ``auto``) is to prepend ``#`` unless some specific prefixes are found. That list of prefixes is incomplete, and there does not seem to exist a documented condition on when exactly ``#`` must not be prepended. We recommend to explicitly set ``prepend_hash=always`` or ``prepend_hash=never`` to avoid any ambiguity (https://github.com/ansible-collections/community.general/pull/5629).
-- spotinst_aws_elastigroup - add ``elements`` attribute when missing in ``list`` parameters (https://github.com/ansible-collections/community.general/pull/5553).
-- ssh_config - add ``host_key_algorithms`` option (https://github.com/ansible-collections/community.general/pull/5605).
-- udm_share - added ``elements`` attribute to ``list`` type parameters (https://github.com/ansible-collections/community.general/pull/5557).
-- udm_user - add ``elements`` attribute when missing in ``list`` parameters (https://github.com/ansible-collections/community.general/pull/5559).
+New Plugins
+-----------
-Deprecated Features
--------------------
+Lookup
+~~~~~~
-- The ``sap`` modules ``sapcar_extract``, ``sap_task_list_execute``, and ``hana_query``, will be removed from this collection in community.general 7.0.0 and replaced with redirects to ``community.sap_libs``. If you want to continue using these modules, make sure to also install ``community.sap_libs`` (it is part of the Ansible package) (https://github.com/ansible-collections/community.general/pull/5614).
+- onepassword_doc - Fetch documents stored in 1Password
-Bugfixes
---------
+Test
+~~~~
-- chroot connection plugin - add ``inventory_hostname`` to vars under ``remote_addr``. This is needed for compatibility with ansible-core 2.13 (https://github.com/ansible-collections/community.general/pull/5570).
-- cmd_runner module utils - fixed bug when handling default cases in ``cmd_runner_fmt.as_map()`` (https://github.com/ansible-collections/community.general/pull/5538).
-- cmd_runner module utils - formatting arguments ``cmd_runner_fmt.as_fixed()`` was expecting an non-existing argument (https://github.com/ansible-collections/community.general/pull/5538).
-- keycloak_client_rolemapping - calculate ``proposed`` and ``after`` return values properly (https://github.com/ansible-collections/community.general/pull/5619).
-- keycloak_client_rolemapping - remove only listed mappings with ``state=absent`` (https://github.com/ansible-collections/community.general/pull/5619).
-- proxmox inventory plugin - fix bug while templating when using templates for the ``url``, ``user``, ``password``, ``token_id``, or ``token_secret`` options (https://github.com/ansible-collections/community.general/pull/5640).
-- proxmox inventory plugin - handle tags delimited by semicolon instead of comma, which happens from Proxmox 7.3 on (https://github.com/ansible-collections/community.general/pull/5602).
-- redhat_subscription - do not ignore ``consumer_name`` and other variables if ``activationkey`` is specified (https://github.com/ansible-collections/community.general/issues/3486, https://github.com/ansible-collections/community.general/pull/5627).
-- redhat_subscription - do not pass arguments to ``subscription-manager register`` for things already configured; now a specified ``rhsm_baseurl`` is properly set for subscription-manager (https://github.com/ansible-collections/community.general/pull/5583).
-- unixy callback plugin - fix plugin to work with ansible-core 2.14 by using Ansible's configuration manager for handling options (https://github.com/ansible-collections/community.general/issues/5600).
-- vdo - now uses ``yaml.safe_load()`` to parse command output instead of the deprecated ``yaml.load()`` which is potentially unsafe. Using ``yaml.load()`` without explicitely setting a ``Loader=`` is also an error in pyYAML 6.0 (https://github.com/ansible-collections/community.general/pull/5632).
-- vmadm - fix for index out of range error in ``get_vm_uuid`` (https://github.com/ansible-collections/community.general/pull/5628).
+- fqdn_valid - Validates fully-qualified domain names against RFC 1123
New Modules
-----------
-- gitlab_project_badge - Manage project badges on GitLab Server
-- keycloak_clientsecret_info - Retrieve client secret via Keycloak API
-- keycloak_clientsecret_regenerate - Regenerate Keycloak client secret via Keycloak API
+- git_config_info - Read git configuration
+- gitlab_issue - Create, update, or delete GitLab issues
+- nomad_token - Manage Nomad ACL tokens
-v6.0.1
+v8.0.2
======
Release Summary
---------------
-Bugfix release for Ansible 7.0.0.
+Bugfix release for inclusion in Ansible 9.0.0rc1.
Bugfixes
--------
-- dependent lookup plugin - avoid warning on deprecated parameter for ``Templar.template()`` (https://github.com/ansible-collections/community.general/pull/5543).
-- jenkins_build - fix the logical flaw when deleting a Jenkins build (https://github.com/ansible-collections/community.general/pull/5514).
-- one_vm - avoid splitting labels that are ``None`` (https://github.com/ansible-collections/community.general/pull/5489).
-- onepassword_raw - add missing parameter to plugin documentation (https://github.com/ansible-collections/community.general/issues/5506).
-- proxmox_disk - avoid duplicate ``vmid`` reference (https://github.com/ansible-collections/community.general/issues/5492, https://github.com/ansible-collections/community.general/pull/5493).
+- ocapi_utils, oci_utils, redfish_utils module utils - replace ``type()`` calls with ``isinstance()`` calls (https://github.com/ansible-collections/community.general/pull/7501).
+- pipx module utils - change the CLI argument formatter for the ``pip_args`` parameter (https://github.com/ansible-collections/community.general/issues/7497, https://github.com/ansible-collections/community.general/pull/7506).
-v6.0.0
+v8.0.1
======
Release Summary
---------------
-New major release of community.general with lots of bugfixes, new features, some removed deprecated features, and some other breaking changes. Please check the coresponding sections of the changelog for more details.
+Bugfix release for inclusion in Ansible 9.0.0b1.
-Major Changes
--------------
+Bugfixes
+--------
+
+- gitlab_group_members - fix gitlab constants call in ``gitlab_group_members`` module (https://github.com/ansible-collections/community.general/issues/7467).
+- gitlab_project_members - fix gitlab constants call in ``gitlab_project_members`` module (https://github.com/ansible-collections/community.general/issues/7467).
+- gitlab_protected_branches - fix gitlab constants call in ``gitlab_protected_branches`` module (https://github.com/ansible-collections/community.general/issues/7467).
+- gitlab_user - fix gitlab constants call in ``gitlab_user`` module (https://github.com/ansible-collections/community.general/issues/7467).
+- proxmox_pool_member - absent state for type VM did not delete VMs from the pools (https://github.com/ansible-collections/community.general/pull/7464).
+- redfish_command - fix usage of message parsing in ``SimpleUpdate`` and ``MultipartHTTPPushUpdate`` commands to treat the lack of a ``MessageId`` as no message (https://github.com/ansible-collections/community.general/issues/7465, https://github.com/ansible-collections/community.general/pull/7471).
-- The internal structure of the collection was changed for modules and action plugins. These no longer live in a directory hierarchy ordered by topic, but instead are now all in a single (flat) directory. This has no impact on users *assuming they did not use internal FQCNs*. These will still work, but result in deprecation warnings. They were never officially supported and thus the redirects are kept as a courtsey, and this is not labelled as a breaking change. Note that for example the Ansible VScode plugin started recommending these internal names. If you followed its recommendation, you will now have to change back to the short names to avoid deprecation warnings, and potential errors in the future as these redirects will be removed in community.general 9.0.0 (https://github.com/ansible-collections/community.general/pull/5461).
-- newrelic_deployment - removed New Relic v1 API, added support for v2 API (https://github.com/ansible-collections/community.general/pull/5341).
+v8.0.0
+======
+
+Release Summary
+---------------
+
+This is release 8.0.0 of ``community.general``, released on 2023-11-01.
Minor Changes
-------------
-- Added MIT license as ``LICENSES/MIT.txt`` for tests/unit/plugins/modules/packaging/language/test_gem.py (https://github.com/ansible-collections/community.general/pull/5065).
-- All software licenses are now in the ``LICENSES/`` directory of the collection root (https://github.com/ansible-collections/community.general/pull/5065, https://github.com/ansible-collections/community.general/pull/5079, https://github.com/ansible-collections/community.general/pull/5080, https://github.com/ansible-collections/community.general/pull/5083, https://github.com/ansible-collections/community.general/pull/5087, https://github.com/ansible-collections/community.general/pull/5095, https://github.com/ansible-collections/community.general/pull/5098, https://github.com/ansible-collections/community.general/pull/5106).
-- ModuleHelper module utils - added property ``verbosity`` to base class (https://github.com/ansible-collections/community.general/pull/5035).
-- ModuleHelper module utils - improved ``ModuleHelperException``, using ``to_native()`` for the exception message (https://github.com/ansible-collections/community.general/pull/4755).
-- The collection repository conforms to the `REUSE specification <https://reuse.software/spec/>`__ except for the changelog fragments (https://github.com/ansible-collections/community.general/pull/5138).
-- ali_instance - minor refactor when checking for installed dependency (https://github.com/ansible-collections/community.general/pull/5240).
-- ali_instance_info - minor refactor when checking for installed dependency (https://github.com/ansible-collections/community.general/pull/5240).
-- alternatives - add ``state=absent`` to be able to remove an alternative (https://github.com/ansible-collections/community.general/pull/4654).
-- alternatives - add ``subcommands`` parameter (https://github.com/ansible-collections/community.general/pull/4654).
-- ansible_galaxy_install - minor refactoring using latest ``ModuleHelper`` updates (https://github.com/ansible-collections/community.general/pull/4752).
-- ansible_galaxy_install - refactored module to use ``CmdRunner`` to execute ``ansible-galaxy`` (https://github.com/ansible-collections/community.general/pull/5477).
-- apk - add ``world`` parameter for supporting a custom world file (https://github.com/ansible-collections/community.general/pull/4976).
-- bitwarden lookup plugin - add option ``search`` to search for other attributes than name (https://github.com/ansible-collections/community.general/pull/5297).
-- cartesian lookup plugin - start using Ansible's configuration manager to parse options (https://github.com/ansible-collections/community.general/pull/5440).
-- cmd_runner module util - added parameters ``check_mode_skip`` and ``check_mode_return`` to ``CmdRunner.context()``, so that the command is not executed when ``check_mode=True`` (https://github.com/ansible-collections/community.general/pull/4736).
-- cmd_runner module utils - add ``__call__`` method to invoke context (https://github.com/ansible-collections/community.general/pull/4791).
-- consul - adds ``ttl`` parameter for session (https://github.com/ansible-collections/community.general/pull/4996).
-- consul - minor refactoring (https://github.com/ansible-collections/community.general/pull/5367).
-- consul_session - adds ``token`` parameter for session (https://github.com/ansible-collections/community.general/pull/5193).
-- cpanm - refactored module to use ``CmdRunner`` to execute ``cpanm`` (https://github.com/ansible-collections/community.general/pull/5485).
-- cpanm - using ``do_raise()`` to raise exceptions in ``ModuleHelper`` derived modules (https://github.com/ansible-collections/community.general/pull/4674).
-- credstash lookup plugin - start using Ansible's configuration manager to parse options (https://github.com/ansible-collections/community.general/pull/5440).
-- dependent lookup plugin - start using Ansible's configuration manager to parse options (https://github.com/ansible-collections/community.general/pull/5440).
-- dig lookup plugin - add option ``fail_on_error`` to allow stopping execution on lookup failures (https://github.com/ansible-collections/community.general/pull/4973).
-- dig lookup plugin - start using Ansible's configuration manager to parse options. All documented options can now also be passed as lookup parameters (https://github.com/ansible-collections/community.general/pull/5440).
-- dnstxt lookup plugin - start using Ansible's configuration manager to parse options (https://github.com/ansible-collections/community.general/pull/5440).
-- filetree lookup plugin - start using Ansible's configuration manager to parse options (https://github.com/ansible-collections/community.general/pull/5440).
-- flattened lookup plugin - start using Ansible's configuration manager to parse options (https://github.com/ansible-collections/community.general/pull/5440).
-- gitlab module util - minor refactor when checking for installed dependency (https://github.com/ansible-collections/community.general/pull/5259).
-- gitlab_branch - minor refactor when checking for installed dependency (https://github.com/ansible-collections/community.general/pull/5259).
-- gitlab_deploy_key - minor refactor when checking for installed dependency (https://github.com/ansible-collections/community.general/pull/5259).
-- gitlab_group - minor refactor when checking for installed dependency (https://github.com/ansible-collections/community.general/pull/5259).
-- gitlab_group_members - minor refactor when checking for installed dependency (https://github.com/ansible-collections/community.general/pull/5259).
-- gitlab_group_variable - minor refactor when checking for installed dependency (https://github.com/ansible-collections/community.general/pull/5259).
-- gitlab_hook - minor refactor when checking for installed dependency (https://github.com/ansible-collections/community.general/pull/5259).
-- gitlab_hook - minor refactoring (https://github.com/ansible-collections/community.general/pull/5271).
-- gitlab_project - minor refactor when checking for installed dependency (https://github.com/ansible-collections/community.general/pull/5259).
-- gitlab_project_members - minor refactor when checking for installed dependency (https://github.com/ansible-collections/community.general/pull/5259).
-- gitlab_project_variable - minor refactor when checking for installed dependency (https://github.com/ansible-collections/community.general/pull/5259).
-- gitlab_protected_branch - minor refactor when checking for installed dependency (https://github.com/ansible-collections/community.general/pull/5259).
-- gitlab_runner - minor refactor when checking for installed dependency (https://github.com/ansible-collections/community.general/pull/5259).
-- gitlab_user - minor refactor when checking for installed dependency (https://github.com/ansible-collections/community.general/pull/5259).
-- hiera lookup plugin - start using Ansible's configuration manager to parse options. The Hiera executable and config file can now also be passed as lookup parameters (https://github.com/ansible-collections/community.general/pull/5440).
-- homebrew, homebrew_tap - added Homebrew on Linux path to defaults (https://github.com/ansible-collections/community.general/pull/5241).
-- hponcfg - refactored module to use ``CmdRunner`` to execute ``hponcfg`` (https://github.com/ansible-collections/community.general/pull/5483).
-- keycloak_* modules - add ``http_agent`` parameter with default value ``Ansible`` (https://github.com/ansible-collections/community.general/issues/5023).
-- keyring lookup plugin - start using Ansible's configuration manager to parse options (https://github.com/ansible-collections/community.general/pull/5440).
-- lastpass - use config manager for handling plugin options (https://github.com/ansible-collections/community.general/pull/5022).
-- ldap_attrs - allow for DNs to have ``{x}`` prefix on first RDN (https://github.com/ansible-collections/community.general/issues/977, https://github.com/ansible-collections/community.general/pull/5450).
-- linode inventory plugin - simplify option handling (https://github.com/ansible-collections/community.general/pull/5438).
-- listen_ports_facts - add new ``include_non_listening`` option which adds ``-a`` option to ``netstat`` and ``ss``. This shows both listening and non-listening (for TCP this means established connections) sockets, and returns ``state`` and ``foreign_address`` (https://github.com/ansible-collections/community.general/issues/4762, https://github.com/ansible-collections/community.general/pull/4953).
-- lmdb_kv lookup plugin - start using Ansible's configuration manager to parse options (https://github.com/ansible-collections/community.general/pull/5440).
-- lxc_container - minor refactoring (https://github.com/ansible-collections/community.general/pull/5358).
-- machinectl become plugin - can now be used with a password from another user than root, if a polkit rule is present (https://github.com/ansible-collections/community.general/pull/4849).
-- machinectl become plugin - combine the success command when building the become command to be consistent with other become plugins (https://github.com/ansible-collections/community.general/pull/5287).
-- manifold lookup plugin - start using Ansible's configuration manager to parse options (https://github.com/ansible-collections/community.general/pull/5440).
-- maven_artifact - add a new ``unredirected_headers`` option that can be used with ansible-core 2.12 and above. The default value is to not use ``Authorization`` and ``Cookie`` headers on redirects for security reasons. With ansible-core 2.11, all headers are still passed on for redirects (https://github.com/ansible-collections/community.general/pull/4812).
-- mksysb - refactored module to use ``CmdRunner`` to execute ``mksysb`` (https://github.com/ansible-collections/community.general/pull/5484).
-- mksysb - using ``do_raise()`` to raise exceptions in ``ModuleHelper`` derived modules (https://github.com/ansible-collections/community.general/pull/4674).
-- nagios - minor refactoring on parameter validation for different actions (https://github.com/ansible-collections/community.general/pull/5239).
-- netcup_dnsapi - add ``timeout`` parameter (https://github.com/ansible-collections/community.general/pull/5301).
-- nmcli - add ``transport_mode`` configuration for Infiniband devices (https://github.com/ansible-collections/community.general/pull/5361).
-- nmcli - add bond option ``xmit_hash_policy`` to bond options (https://github.com/ansible-collections/community.general/issues/5148).
-- nmcli - adds ``vpn`` type and parameter for supporting VPN with service type L2TP and PPTP (https://github.com/ansible-collections/community.general/pull/4746).
-- nmcli - honor IP options for VPNs (https://github.com/ansible-collections/community.general/pull/5228).
-- onepassword - support version 2 of the OnePassword CLI (https://github.com/ansible-collections/community.general/pull/4728)
-- opentelemetry callback plugin - allow configuring opentelementry callback via config file (https://github.com/ansible-collections/community.general/pull/4916).
-- opentelemetry callback plugin - send logs. This can be disabled by setting ``disable_logs=false`` (https://github.com/ansible-collections/community.general/pull/4175).
-- pacman - added parameters ``reason`` and ``reason_for`` to set/change the install reason of packages (https://github.com/ansible-collections/community.general/pull/4956).
-- passwordstore lookup plugin - allow options to be passed lookup options instead of being part of the term strings (https://github.com/ansible-collections/community.general/pull/5444).
-- passwordstore lookup plugin - allow using alternative password managers by detecting wrapper scripts, allow explicit configuration of pass and gopass backends (https://github.com/ansible-collections/community.general/issues/4766).
-- passwordstore lookup plugin - improve error messages to include stderr (https://github.com/ansible-collections/community.general/pull/5436)
-- pipx - added state ``latest`` to the module (https://github.com/ansible-collections/community.general/pull/5105).
-- pipx - changed implementation to use ``cmd_runner`` (https://github.com/ansible-collections/community.general/pull/5085).
-- pipx - module fails faster when ``name`` is missing for states ``upgrade`` and ``reinstall`` (https://github.com/ansible-collections/community.general/pull/5100).
-- pipx - using ``do_raise()`` to raise exceptions in ``ModuleHelper`` derived modules (https://github.com/ansible-collections/community.general/pull/4674).
-- pipx module utils - created new module util ``pipx`` providing a ``cmd_runner`` specific for the ``pipx`` module (https://github.com/ansible-collections/community.general/pull/5085).
-- portage - add knobs for Portage's ``--backtrack`` and ``--with-bdeps`` options (https://github.com/ansible-collections/community.general/pull/5349).
-- portage - use Portage's python module instead of calling gentoolkit-provided program in shell (https://github.com/ansible-collections/community.general/pull/5349).
-- proxmox inventory plugin - added new flag ``qemu_extended_statuses`` and new groups ``<group_prefix>prelaunch``, ``<group_prefix>paused``. They will be populated only when ``want_facts=true``, ``qemu_extended_statuses=true`` and only for ``QEMU`` machines (https://github.com/ansible-collections/community.general/pull/4723).
-- proxmox inventory plugin - simplify option handling code (https://github.com/ansible-collections/community.general/pull/5437).
-- proxmox module utils, the proxmox* modules - add ``api_task_ok`` helper to standardize API task status checks across all proxmox modules (https://github.com/ansible-collections/community.general/pull/5274).
-- proxmox_kvm - allow ``agent`` argument to be a string (https://github.com/ansible-collections/community.general/pull/5107).
-- proxmox_snap - add ``unbind`` param to support snapshotting containers with configured mountpoints (https://github.com/ansible-collections/community.general/pull/5274).
-- puppet - adds ``confdir`` parameter to configure a custom confir location (https://github.com/ansible-collections/community.general/pull/4740).
-- redfish - added new command GetVirtualMedia, VirtualMediaInsert and VirtualMediaEject to Systems category due to Redfish spec changes the virtualMedia resource location from Manager to System (https://github.com/ansible-collections/community.general/pull/5124).
-- redfish_config - add ``SetSessionService`` to set default session timeout policy (https://github.com/ansible-collections/community.general/issues/5008).
-- redfish_info - add ``GetManagerInventory`` to report list of Manager inventory information (https://github.com/ansible-collections/community.general/issues/4899).
-- seport - added new argument ``local`` (https://github.com/ansible-collections/community.general/pull/5203)
-- snap - using ``do_raise()`` to raise exceptions in ``ModuleHelper`` derived modules (https://github.com/ansible-collections/community.general/pull/4674).
-- sudoers - will attempt to validate the proposed sudoers rule using visudo if available, optionally skipped, or required (https://github.com/ansible-collections/community.general/pull/4794, https://github.com/ansible-collections/community.general/issues/4745).
-- terraform - adds capability to handle complex variable structures for ``variables`` parameter in the module. This must be enabled with the new ``complex_vars`` parameter (https://github.com/ansible-collections/community.general/pull/4797).
-- terraform - run ``terraform init`` with ``-no-color`` not to mess up the stdout of the task (https://github.com/ansible-collections/community.general/pull/5147).
-- wdc_redfish_command - add ``IndicatorLedOn`` and ``IndicatorLedOff`` commands for ``Chassis`` category (https://github.com/ansible-collections/community.general/pull/5059).
-- wdc_redfish_command - add ``PowerModeLow`` and ``PowerModeNormal`` commands for ``Chassis`` category (https://github.com/ansible-collections/community.general/pull/5145).
-- xfconf - add ``stdout``, ``stderr`` and ``cmd`` to the module results (https://github.com/ansible-collections/community.general/pull/5037).
-- xfconf - changed implementation to use ``cmd_runner`` (https://github.com/ansible-collections/community.general/pull/4776).
-- xfconf - use ``do_raise()`` instead of defining custom exception class (https://github.com/ansible-collections/community.general/pull/4975).
-- xfconf - using ``do_raise()`` to raise exceptions in ``ModuleHelper`` derived modules (https://github.com/ansible-collections/community.general/pull/4674).
-- xfconf module utils - created new module util ``xfconf`` providing a ``cmd_runner`` specific for ``xfconf`` modules (https://github.com/ansible-collections/community.general/pull/4776).
-- xfconf_info - changed implementation to use ``cmd_runner`` (https://github.com/ansible-collections/community.general/pull/4776).
-- xfconf_info - use ``do_raise()`` instead of defining custom exception class (https://github.com/ansible-collections/community.general/pull/4975).
-- znode - possibility to use ZooKeeper ACL authentication (https://github.com/ansible-collections/community.general/pull/5306).
+- The collection will start using semantic markup (https://github.com/ansible-collections/community.general/pull/6539).
+- VarDict module utils - add method ``VarDict.as_dict()`` to convert to a plain ``dict`` object (https://github.com/ansible-collections/community.general/pull/6602).
+- apt_rpm - extract package name from local ``.rpm`` path when verifying
+ installation success. Allows installing packages from local ``.rpm`` files
+ (https://github.com/ansible-collections/community.general/pull/7396).
+- cargo - add option ``executable``, which allows user to specify path to the cargo binary (https://github.com/ansible-collections/community.general/pull/7352).
+- cargo - add option ``locked`` which allows user to specify install the locked version of dependency instead of latest compatible version (https://github.com/ansible-collections/community.general/pull/6134).
+- chroot connection plugin - add ``disable_root_check`` option (https://github.com/ansible-collections/community.general/pull/7099).
+- cloudflare_dns - add CAA record support (https://github.com/ansible-collections/community.general/pull/7399).
+- cobbler inventory plugin - add ``exclude_mgmt_classes`` and ``include_mgmt_classes`` options to exclude or include hosts based on management classes (https://github.com/ansible-collections/community.general/pull/7184).
+- cobbler inventory plugin - add ``inventory_hostname`` option to allow using the system name for the inventory hostname (https://github.com/ansible-collections/community.general/pull/6502).
+- cobbler inventory plugin - add ``want_ip_addresses`` option to collect all interface DNS name to IP address mapping (https://github.com/ansible-collections/community.general/pull/6711).
+- cobbler inventory plugin - add primary IP addess to ``cobbler_ipv4_address`` and IPv6 address to ``cobbler_ipv6_address`` host variable (https://github.com/ansible-collections/community.general/pull/6711).
+- cobbler inventory plugin - add warning for systems with empty profiles (https://github.com/ansible-collections/community.general/pull/6502).
+- cobbler inventory plugin - convert Ansible unicode strings to native Python unicode strings before passing user/password to XMLRPC client (https://github.com/ansible-collections/community.general/pull/6923).
+- consul_session - drops requirement for the ``python-consul`` library to communicate with the Consul API, instead relying on the existing ``requests`` library requirement (https://github.com/ansible-collections/community.general/pull/6755).
+- copr - respawn module to use the system python interpreter when the ``dnf`` python module is not available in ``ansible_python_interpreter`` (https://github.com/ansible-collections/community.general/pull/6522).
+- cpanm - minor refactor when creating the ``CmdRunner`` object (https://github.com/ansible-collections/community.general/pull/7231).
+- datadog_monitor - adds ``notification_preset_name``, ``renotify_occurrences`` and ``renotify_statuses`` parameters (https://github.com/ansible-collections/community.general/issues/6521,https://github.com/ansible-collections/community.general/issues/5823).
+- dig lookup plugin - add TCP option to enable the use of TCP connection during DNS lookup (https://github.com/ansible-collections/community.general/pull/7343).
+- ejabberd_user - module now using ``CmdRunner`` to execute external command (https://github.com/ansible-collections/community.general/pull/7075).
+- filesystem - add ``uuid`` parameter for UUID change feature (https://github.com/ansible-collections/community.general/pull/6680).
+- gitlab_group - add option ``force_delete`` (default: false) which allows delete group even if projects exists in it (https://github.com/ansible-collections/community.general/pull/7364).
+- gitlab_group_variable - add support for ``raw`` variables suboption (https://github.com/ansible-collections/community.general/pull/7132).
+- gitlab_project_variable - add support for ``raw`` variables suboption (https://github.com/ansible-collections/community.general/pull/7132).
+- gitlab_project_variable - minor refactor removing unnecessary code statements (https://github.com/ansible-collections/community.general/pull/6928).
+- gitlab_runner - minor refactor removing unnecessary code statements (https://github.com/ansible-collections/community.general/pull/6927).
+- htpasswd - minor code improvements in the module (https://github.com/ansible-collections/community.general/pull/6901).
+- htpasswd - the parameter ``crypt_scheme`` is being renamed as ``hash_scheme`` and added as an alias to it (https://github.com/ansible-collections/community.general/pull/6841).
+- icinga2_host - the ``ip`` option is no longer required, since Icinga 2 allows for an empty address attribute (https://github.com/ansible-collections/community.general/pull/7452).
+- ini_file - add ``ignore_spaces`` option (https://github.com/ansible-collections/community.general/pull/7273).
+- ini_file - add ``modify_inactive_option`` option (https://github.com/ansible-collections/community.general/pull/7401).
+- ipa_config - add module parameters to manage FreeIPA user and group objectclasses (https://github.com/ansible-collections/community.general/pull/7019).
+- ipa_config - adds ``idp`` choice to ``ipauserauthtype`` parameter's choices (https://github.com/ansible-collections/community.general/pull/7051).
+- jenkins_build - add new ``detach`` option, which allows the module to exit successfully as long as the build is created (default functionality is still waiting for the build to end before exiting) (https://github.com/ansible-collections/community.general/pull/7204).
+- jenkins_build - add new ``time_between_checks`` option, which allows to configure the wait time between requests to the Jenkins server (https://github.com/ansible-collections/community.general/pull/7204).
+- keycloak_authentication - added provider ID choices, since Keycloak supports only those two specific ones (https://github.com/ansible-collections/community.general/pull/6763).
+- keycloak_client_rolemapping - adds support for subgroups with additional parameter ``parents`` (https://github.com/ansible-collections/community.general/pull/6687).
+- keycloak_role - add composite roles support for realm and client roles (https://github.com/ansible-collections/community.general/pull/6469).
+- keyring - minor refactor removing unnecessary code statements (https://github.com/ansible-collections/community.general/pull/6927).
+- ldap_* - add new arguments ``client_cert`` and ``client_key`` to the LDAP modules in order to allow certificate authentication (https://github.com/ansible-collections/community.general/pull/6668).
+- ldap_search - add a new ``page_size`` option to enable paged searches (https://github.com/ansible-collections/community.general/pull/6648).
+- locale_gen - module has been refactored to use ``ModuleHelper`` and ``CmdRunner`` (https://github.com/ansible-collections/community.general/pull/6903).
+- locale_gen - module now using ``CmdRunner`` to execute external commands (https://github.com/ansible-collections/community.general/pull/6820).
+- lvg - add ``active`` and ``inactive`` values to the ``state`` option for active state management feature (https://github.com/ansible-collections/community.general/pull/6682).
+- lvg - add ``reset_vg_uuid``, ``reset_pv_uuid`` options for UUID reset feature (https://github.com/ansible-collections/community.general/pull/6682).
+- lxc connection plugin - properly handle a change of the ``remote_addr`` option (https://github.com/ansible-collections/community.general/pull/7373).
+- lxd connection plugin - automatically translate ``remote_addr`` from FQDN to (short) hostname (https://github.com/ansible-collections/community.general/pull/7360).
+- lxd connection plugin - update error parsing to work with newer messages mentioning instances (https://github.com/ansible-collections/community.general/pull/7360).
+- lxd inventory plugin - add ``server_cert`` option for trust anchor to use for TLS verification of server certificates (https://github.com/ansible-collections/community.general/pull/7392).
+- lxd inventory plugin - add ``server_check_hostname`` option to disable hostname verification of server certificates (https://github.com/ansible-collections/community.general/pull/7392).
+- make - add new ``targets`` parameter allowing multiple targets to be used with ``make`` (https://github.com/ansible-collections/community.general/pull/6882, https://github.com/ansible-collections/community.general/issues/4919).
+- make - allows ``params`` to be used without value (https://github.com/ansible-collections/community.general/pull/7180).
+- mas - disable sign-in check for macOS 12+ as ``mas account`` is non-functional (https://github.com/ansible-collections/community.general/pull/6520).
+- newrelic_deployment - add option ``app_name_exact_match``, which filters results for the exact app_name provided (https://github.com/ansible-collections/community.general/pull/7355).
+- nmap inventory plugin - now has a ``use_arp_ping`` option to allow the user to disable the default ARP ping query for a more reliable form (https://github.com/ansible-collections/community.general/pull/7119).
+- nmcli - add support for ``ipv4.dns-options`` and ``ipv6.dns-options`` (https://github.com/ansible-collections/community.general/pull/6902).
+- nomad_job, nomad_job_info - add ``port`` parameter (https://github.com/ansible-collections/community.general/pull/7412).
+- npm - minor improvement on parameter validation (https://github.com/ansible-collections/community.general/pull/6848).
+- npm - module now using ``CmdRunner`` to execute external commands (https://github.com/ansible-collections/community.general/pull/6989).
+- onepassword lookup plugin - add service account support (https://github.com/ansible-collections/community.general/issues/6635, https://github.com/ansible-collections/community.general/pull/6660).
+- onepassword lookup plugin - introduce ``account_id`` option which allows specifying which account to use (https://github.com/ansible-collections/community.general/pull/7308).
+- onepassword_raw lookup plugin - add service account support (https://github.com/ansible-collections/community.general/issues/6635, https://github.com/ansible-collections/community.general/pull/6660).
+- onepassword_raw lookup plugin - introduce ``account_id`` option which allows specifying which account to use (https://github.com/ansible-collections/community.general/pull/7308).
+- opentelemetry callback plugin - add span attributes in the span event (https://github.com/ansible-collections/community.general/pull/6531).
+- opkg - add ``executable`` parameter allowing to specify the path of the ``opkg`` command (https://github.com/ansible-collections/community.general/pull/6862).
+- opkg - remove default value ``""`` for parameter ``force`` as it causes the same behaviour of not having that parameter (https://github.com/ansible-collections/community.general/pull/6513).
+- pagerduty - adds in option to use v2 API for creating pagerduty incidents (https://github.com/ansible-collections/community.general/issues/6151)
+- parted - on resize, use ``--fix`` option if available (https://github.com/ansible-collections/community.general/pull/7304).
+- pnpm - set correct version when state is latest or version is not mentioned. Resolves previous idempotency problem (https://github.com/ansible-collections/community.general/pull/7339).
+- pritunl module utils - ensure ``validate_certs`` parameter is honoured in all methods (https://github.com/ansible-collections/community.general/pull/7156).
+- proxmox - add ``vmid`` (and ``taskid`` when possible) to return values (https://github.com/ansible-collections/community.general/pull/7263).
+- proxmox - support ``timezone`` parameter at container creation (https://github.com/ansible-collections/community.general/pull/6510).
+- proxmox inventory plugin - add composite variables support for Proxmox nodes (https://github.com/ansible-collections/community.general/issues/6640).
+- proxmox_kvm - added support for ``tpmstate0`` parameter to configure TPM (Trusted Platform Module) disk. TPM is required for Windows 11 installations (https://github.com/ansible-collections/community.general/pull/6533).
+- proxmox_kvm - enabled force restart of VM, bringing the ``force`` parameter functionality in line with what is described in the docs (https://github.com/ansible-collections/community.general/pull/6914).
+- proxmox_kvm - re-use ``timeout`` module param to forcefully shutdown a virtual machine when ``state`` is ``stopped`` (https://github.com/ansible-collections/community.general/issues/6257).
+- proxmox_snap - add ``retention`` parameter to delete old snapshots (https://github.com/ansible-collections/community.general/pull/6576).
+- proxmox_vm_info - ``node`` parameter is no longer required. Information can be obtained for the whole cluster (https://github.com/ansible-collections/community.general/pull/6976).
+- proxmox_vm_info - non-existing provided by name/vmid VM would return empty results instead of failing (https://github.com/ansible-collections/community.general/pull/7049).
+- pubnub_blocks - minor refactor removing unnecessary code statements (https://github.com/ansible-collections/community.general/pull/6928).
+- random_string - added new ``ignore_similar_chars`` and ``similar_chars`` option to ignore certain chars (https://github.com/ansible-collections/community.general/pull/7242).
+- redfish_command - add ``MultipartHTTPPushUpdate`` command (https://github.com/ansible-collections/community.general/issues/6471, https://github.com/ansible-collections/community.general/pull/6612).
+- redfish_command - add ``account_types`` and ``oem_account_types`` as optional inputs to ``AddUser`` (https://github.com/ansible-collections/community.general/issues/6823, https://github.com/ansible-collections/community.general/pull/6871).
+- redfish_command - add new option ``update_oem_params`` for the ``MultipartHTTPPushUpdate`` command (https://github.com/ansible-collections/community.general/issues/7331).
+- redfish_config - add ``CreateVolume`` command to allow creation of volumes on servers (https://github.com/ansible-collections/community.general/pull/6813).
+- redfish_config - add ``DeleteAllVolumes`` command to allow deletion of all volumes on servers (https://github.com/ansible-collections/community.general/pull/6814).
+- redfish_config - adding ``SetSecureBoot`` command (https://github.com/ansible-collections/community.general/pull/7129).
+- redfish_info - add ``AccountTypes`` and ``OEMAccountTypes`` to the output of ``ListUsers`` (https://github.com/ansible-collections/community.general/issues/6823, https://github.com/ansible-collections/community.general/pull/6871).
+- redfish_info - add support for ``GetBiosRegistries`` command (https://github.com/ansible-collections/community.general/pull/7144).
+- redfish_info - adds ``LinkStatus`` to NIC inventory (https://github.com/ansible-collections/community.general/pull/7318).
+- redfish_info - adds ``ProcessorArchitecture`` to CPU inventory (https://github.com/ansible-collections/community.general/pull/6864).
+- redfish_info - fix for ``GetVolumeInventory``, Controller name was getting populated incorrectly and duplicates were seen in the volumes retrieved (https://github.com/ansible-collections/community.general/pull/6719).
+- redfish_info - report ``Id`` in the output of ``GetManagerInventory`` (https://github.com/ansible-collections/community.general/pull/7140).
+- redfish_utils - use ``Controllers`` key in redfish data to obtain Storage controllers properties (https://github.com/ansible-collections/community.general/pull/7081).
+- redfish_utils module utils - add support for ``PowerCycle`` reset type for ``redfish_command`` responses feature (https://github.com/ansible-collections/community.general/issues/7083).
+- redfish_utils module utils - add support for following ``@odata.nextLink`` pagination in ``software_inventory`` responses feature (https://github.com/ansible-collections/community.general/pull/7020).
+- redfish_utils module utils - support ``Volumes`` in response for ``GetDiskInventory`` (https://github.com/ansible-collections/community.general/pull/6819).
+- redhat_subscription - the internal ``RegistrationBase`` class was folded
+ into the other internal ``Rhsm`` class, as the separation had no purpose
+ anymore
+ (https://github.com/ansible-collections/community.general/pull/6658).
+- redis_info - refactor the redis_info module to use the redis module_utils enabling to pass TLS parameters to the Redis client (https://github.com/ansible-collections/community.general/pull/7267).
+- rhsm_release - improve/harden the way ``subscription-manager`` is run;
+ no behaviour change is expected
+ (https://github.com/ansible-collections/community.general/pull/6669).
+- rhsm_repository - the interaction with ``subscription-manager`` was
+ refactored by grouping things together, removing unused bits, and hardening
+ the way it is run; also, the parsing of ``subscription-manager repos --list``
+ was improved and made slightly faster; no behaviour change is expected
+ (https://github.com/ansible-collections/community.general/pull/6783,
+ https://github.com/ansible-collections/community.general/pull/6837).
+- scaleway_security_group_rule - minor refactor removing unnecessary code statements (https://github.com/ansible-collections/community.general/pull/6928).
+- shutdown - use ``shutdown -p ...`` with FreeBSD to halt and power off machine (https://github.com/ansible-collections/community.general/pull/7102).
+- snap - add option ``dangerous`` to the module, that will map into the command line argument ``--dangerous``, allowing unsigned snap files to be installed (https://github.com/ansible-collections/community.general/pull/6908, https://github.com/ansible-collections/community.general/issues/5715).
+- snap - module is now aware of channel when deciding whether to install or refresh the snap (https://github.com/ansible-collections/community.general/pull/6435, https://github.com/ansible-collections/community.general/issues/1606).
+- sorcery - add grimoire (repository) management support (https://github.com/ansible-collections/community.general/pull/7012).
+- sorcery - minor refactor (https://github.com/ansible-collections/community.general/pull/6525).
+- supervisorctl - allow to stop matching running processes before removing them with ``stop_before_removing=true`` (https://github.com/ansible-collections/community.general/pull/7284).
+- tss lookup plugin - allow to fetch secret IDs which are in a folder based on folder ID. Previously, we could not fetch secrets based on folder ID but now use ``fetch_secret_ids_from_folder`` option to indicate to fetch secret IDs based on folder ID (https://github.com/ansible-collections/community.general/issues/6223).
+- tss lookup plugin - allow to fetch secret by path. Previously, we could not fetch secret by path but now use ``secret_path`` option to indicate to fetch secret by secret path (https://github.com/ansible-collections/community.general/pull/6881).
+- unixy callback plugin - add support for ``check_mode_markers`` option (https://github.com/ansible-collections/community.general/pull/7179).
+- vardict module utils - added convenience methods to ``VarDict`` (https://github.com/ansible-collections/community.general/pull/6647).
+- xenserver_guest_info - minor refactor removing unnecessary code statements (https://github.com/ansible-collections/community.general/pull/6928).
+- xenserver_guest_powerstate - minor refactor removing unnecessary code statements (https://github.com/ansible-collections/community.general/pull/6928).
+- yum_versionlock - add support to pin specific package versions instead of only the package itself (https://github.com/ansible-collections/community.general/pull/6861, https://github.com/ansible-collections/community.general/issues/4470).
Breaking Changes / Porting Guide
--------------------------------
-- newrelic_deployment - ``revision`` is required for v2 API (https://github.com/ansible-collections/community.general/pull/5341).
-- scaleway_container_registry_info - no longer replace ``secret_environment_variables`` in the output by ``SENSITIVE_VALUE`` (https://github.com/ansible-collections/community.general/pull/5497).
+- collection_version lookup plugin - remove compatibility code for ansible-base 2.10 and ansible-core 2.11 (https://github.com/ansible-collections/community.general/pull/7269).
+- gitlab_project - add ``default_branch`` support for project update. If you used the module so far with ``default_branch`` to update a project, the value of ``default_branch`` was ignored. Make sure that you either do not pass a value if you are not sure whether it is the one you want to have to avoid unexpected breaking changes (https://github.com/ansible-collections/community.general/pull/7158).
+- selective callback plugin - remove compatibility code for Ansible 2.9 and ansible-core 2.10 (https://github.com/ansible-collections/community.general/pull/7269).
+- vardict module utils - ``VarDict`` will no longer accept variables named ``_var``, ``get_meta``, and ``as_dict`` (https://github.com/ansible-collections/community.general/pull/6647).
+- version module util - remove fallback for ansible-core 2.11. All modules and plugins that do version collections no longer work with ansible-core 2.11 (https://github.com/ansible-collections/community.general/pull/7269).
Deprecated Features
-------------------
-- ArgFormat module utils - deprecated along ``CmdMixin``, in favor of the ``cmd_runner_fmt`` module util (https://github.com/ansible-collections/community.general/pull/5370).
-- CmdMixin module utils - deprecated in favor of the ``CmdRunner`` module util (https://github.com/ansible-collections/community.general/pull/5370).
-- CmdModuleHelper module utils - deprecated in favor of the ``CmdRunner`` module util (https://github.com/ansible-collections/community.general/pull/5370).
-- CmdStateModuleHelper module utils - deprecated in favor of the ``CmdRunner`` module util (https://github.com/ansible-collections/community.general/pull/5370).
-- cmd_runner module utils - deprecated ``fmt`` in favour of ``cmd_runner_fmt`` as the parameter format object (https://github.com/ansible-collections/community.general/pull/4777).
-- django_manage - support for Django releases older than 4.1 has been deprecated and will be removed in community.general 9.0.0 (https://github.com/ansible-collections/community.general/pull/5400).
-- django_manage - support for the commands ``cleanup``, ``syncdb`` and ``validate`` that have been deprecated in Django long time ago will be removed in community.general 9.0.0 (https://github.com/ansible-collections/community.general/pull/5400).
-- django_manage - the behavior of "creating the virtual environment when missing" is being deprecated and will be removed in community.general version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5405).
-- gconftool2 - deprecates ``state=get`` in favor of using the module ``gconftool2_info`` (https://github.com/ansible-collections/community.general/pull/4778).
-- lxc_container - the module will no longer make any effort to support Python 2 (https://github.com/ansible-collections/community.general/pull/5304).
-- newrelic_deployment - ``appname`` and ``environment`` are no longer valid options in the v2 API. They will be removed in community.general 7.0.0 (https://github.com/ansible-collections/community.general/pull/5341).
-- proxmox - deprecated the current ``unprivileged`` default value, will be changed to ``true`` in community.general 7.0.0 (https://github.com/pull/5224).
-- xfconf - deprecated parameter ``disable_facts``, as since version 4.0.0 it only allows value ``true`` (https://github.com/ansible-collections/community.general/pull/4520).
+- CmdRunner module utils - deprecate ``cmd_runner_fmt.as_default_type()`` formatter (https://github.com/ansible-collections/community.general/pull/6601).
+- MH VarsMixin module utils - deprecates ``VarsMixin`` and supporting classes in favor of plain ``vardict`` module util (https://github.com/ansible-collections/community.general/pull/6649).
+- ansible_galaxy_install - the ``ack_ansible29`` and ``ack_min_ansiblecore211`` options have been deprecated and will be removed in community.general 9.0.0 (https://github.com/ansible-collections/community.general/pull/7358).
+- consul - the ``ack_params_state_absent`` option has been deprecated and will be removed in community.general 10.0.0 (https://github.com/ansible-collections/community.general/pull/7358).
+- cpanm - value ``compatibility`` is deprecated as default for parameter ``mode`` (https://github.com/ansible-collections/community.general/pull/6512).
+- ejabberd_user - deprecate the parameter ``logging`` in favour of producing more detailed information in the module output (https://github.com/ansible-collections/community.general/pull/7043).
+- flowdock - module relies entirely on no longer responsive API endpoints, and it will be removed in community.general 9.0.0 (https://github.com/ansible-collections/community.general/pull/6930).
+- proxmox - old feature flag ``proxmox_default_behavior`` will be removed in community.general 10.0.0 (https://github.com/ansible-collections/community.general/pull/6836).
+- proxmox_kvm - deprecate the option ``proxmox_default_behavior`` (https://github.com/ansible-collections/community.general/pull/7377).
+- redfish_info, redfish_config, redfish_command - the default value ``10`` for the ``timeout`` option is deprecated and will change to ``60`` in community.general 9.0.0 (https://github.com/ansible-collections/community.general/pull/7295).
+- redhat module utils - the ``module_utils.redhat`` module is deprecated, as
+ effectively unused: the ``Rhsm``, ``RhsmPool``, and ``RhsmPools`` classes
+ will be removed in community.general 9.0.0; the ``RegistrationBase`` class
+ will be removed in community.general 10.0.0 together with the
+ ``rhn_register`` module, as it is the only user of this class; this means
+ that the whole ``module_utils.redhat`` module will be dropped in
+ community.general 10.0.0, so importing it without even using anything of it
+ will fail
+ (https://github.com/ansible-collections/community.general/pull/6663).
+- redhat_subscription - the ``autosubscribe`` alias for the ``auto_attach`` option has been
+ deprecated for many years, although only in the documentation. Officially mark this alias
+ as deprecated, and it will be removed in community.general 9.0.0
+ (https://github.com/ansible-collections/community.general/pull/6646).
+- redhat_subscription - the ``pool`` option is deprecated in favour of the
+ more precise and flexible ``pool_ids`` option
+ (https://github.com/ansible-collections/community.general/pull/6650).
+- rhsm_repository - ``state=present`` has not been working as expected for many years,
+ and it seems it was not noticed so far; also, "presence" is not really a valid concept
+ for subscription repositories, which can only be enabled or disabled. Hence, mark the
+ ``present`` and ``absent`` values of the ``state`` option as deprecated, slating them
+ for removal in community.general 10.0.0
+ (https://github.com/ansible-collections/community.general/pull/6673).
+- stackdriver - module relies entirely on no longer existent API endpoints, and it will be removed in community.general 9.0.0 (https://github.com/ansible-collections/community.general/pull/6887).
+- webfaction_app - module relies entirely on no longer existent API endpoints, and it will be removed in community.general 9.0.0 (https://github.com/ansible-collections/community.general/pull/6909).
+- webfaction_db - module relies entirely on no longer existent API endpoints, and it will be removed in community.general 9.0.0 (https://github.com/ansible-collections/community.general/pull/6909).
+- webfaction_domain - module relies entirely on no longer existent API endpoints, and it will be removed in community.general 9.0.0 (https://github.com/ansible-collections/community.general/pull/6909).
+- webfaction_mailbox - module relies entirely on no longer existent API endpoints, and it will be removed in community.general 9.0.0 (https://github.com/ansible-collections/community.general/pull/6909).
+- webfaction_site - module relies entirely on no longer existent API endpoints, and it will be removed in community.general 9.0.0 (https://github.com/ansible-collections/community.general/pull/6909).
Removed Features (previously deprecated)
----------------------------------------
-- bitbucket* modules - ``username`` is no longer an alias of ``workspace``, but of ``user`` (https://github.com/ansible-collections/community.general/pull/5326).
-- gem - the default of the ``norc`` option changed from ``false`` to ``true`` (https://github.com/ansible-collections/community.general/pull/5326).
-- gitlab_group_members - ``gitlab_group`` must now always contain the full path, and no longer just the name or path (https://github.com/ansible-collections/community.general/pull/5326).
-- keycloak_authentication - the return value ``flow`` has been removed. Use ``end_state`` instead (https://github.com/ansible-collections/community.general/pull/5326).
-- keycloak_group - the return value ``group`` has been removed. Use ``end_state`` instead (https://github.com/ansible-collections/community.general/pull/5326).
-- lxd_container - the default of the ``ignore_volatile_options`` option changed from ``true`` to ``false`` (https://github.com/ansible-collections/community.general/pull/5326).
-- mail callback plugin - the ``sender`` option is now required (https://github.com/ansible-collections/community.general/pull/5326).
-- module_helper module utils - remove the ``VarDict`` attribute from ``ModuleHelper``. Import ``VarDict`` from ``ansible_collections.community.general.plugins.module_utils.mh.mixins.vars`` instead (https://github.com/ansible-collections/community.general/pull/5326).
-- proxmox inventory plugin - the default of the ``want_proxmox_nodes_ansible_host`` option changed from ``true`` to ``false`` (https://github.com/ansible-collections/community.general/pull/5326).
-- vmadm - the ``debug`` option has been removed. It was not used anyway (https://github.com/ansible-collections/community.general/pull/5326).
+- The collection no longer supports ansible-core 2.11 and ansible-core 2.12. Parts of the collection might still work on these ansible-core versions, but others might not (https://github.com/ansible-collections/community.general/pull/7269).
+- ansible_galaxy_install - support for Ansible 2.9 and ansible-base 2.10 has been removed (https://github.com/ansible-collections/community.general/pull/7358).
+- consul - when ``state=absent``, the options ``script``, ``ttl``, ``tcp``, ``http``, and ``interval`` can no longer be specified (https://github.com/ansible-collections/community.general/pull/7358).
+- gconftool2 - ``state=get`` has been removed. Use the module ``community.general.gconftool2_info`` instead (https://github.com/ansible-collections/community.general/pull/7358).
+- gitlab_runner - remove the default value for the ``access_level`` option. To restore the previous behavior, explicitly set it to ``ref_protected`` (https://github.com/ansible-collections/community.general/pull/7358).
+- htpasswd - removed code for passlib <1.6 (https://github.com/ansible-collections/community.general/pull/6901).
+- manageiq_polices - ``state=list`` has been removed. Use the module ``community.general.manageiq_policies_info`` instead (https://github.com/ansible-collections/community.general/pull/7358).
+- manageiq_tags - ``state=list`` has been removed. Use the module ``community.general.manageiq_tags_info`` instead (https://github.com/ansible-collections/community.general/pull/7358).
+- mh.mixins.cmd module utils - the ``ArgFormat`` class has been removed (https://github.com/ansible-collections/community.general/pull/7358).
+- mh.mixins.cmd module utils - the ``CmdMixin`` mixin has been removed. Use ``community.general.plugins.module_utils.cmd_runner.CmdRunner`` instead (https://github.com/ansible-collections/community.general/pull/7358).
+- mh.mixins.cmd module utils - the mh.mixins.cmd module utils has been removed after all its contents were removed (https://github.com/ansible-collections/community.general/pull/7358).
+- mh.module_helper module utils - the ``CmdModuleHelper`` and ``CmdStateModuleHelper`` classes have been removed. Use ``community.general.plugins.module_utils.cmd_runner.CmdRunner`` instead (https://github.com/ansible-collections/community.general/pull/7358).
+- proxmox module utils - removed unused imports (https://github.com/ansible-collections/community.general/pull/6873).
+- xfconf - the deprecated ``disable_facts`` option was removed (https://github.com/ansible-collections/community.general/pull/7358).
Bugfixes
--------
-- Include ``PSF-license.txt`` file for ``plugins/module_utils/_mount.py``.
-- Include ``simplified_bsd.txt`` license file for various module utils, the ``lxca_common`` docs fragment, and the ``utm_utils`` unit tests.
-- alternatives - do not set the priority if the priority was not set by the user (https://github.com/ansible-collections/community.general/pull/4810).
-- alternatives - only pass subcommands when they are specified as module arguments (https://github.com/ansible-collections/community.general/issues/4803, https://github.com/ansible-collections/community.general/issues/4804, https://github.com/ansible-collections/community.general/pull/4836).
-- alternatives - when ``subcommands`` is specified, ``link`` must be given for every subcommand. This was already mentioned in the documentation, but not enforced by the code (https://github.com/ansible-collections/community.general/pull/4836).
-- apache2_mod_proxy - avoid crash when reporting inability to parse balancer_member_page HTML caused by using an undefined variable in the error message (https://github.com/ansible-collections/community.general/pull/5111).
-- archive - avoid crash when ``lzma`` is not present and ``format`` is not ``xz`` (https://github.com/ansible-collections/community.general/pull/5393).
-- cmd_runner module utils - fix bug caused by using the ``command`` variable instead of ``self.command`` when looking for binary path (https://github.com/ansible-collections/community.general/pull/4903).
-- consul - fixed bug introduced in PR 4590 (https://github.com/ansible-collections/community.general/issues/4680).
-- credstash lookup plugin - pass plugin options to credstash for all terms, not just for the first (https://github.com/ansible-collections/community.general/pull/5440).
-- dig lookup plugin - add option to return empty result without empty strings, and return empty list instead of ``NXDOMAIN`` (https://github.com/ansible-collections/community.general/pull/5439, https://github.com/ansible-collections/community.general/issues/5428).
-- dig lookup plugin - fix evaluation of falsy values for boolean parameters ``fail_on_error`` and ``retry_servfail`` (https://github.com/ansible-collections/community.general/pull/5129).
-- dnsimple_info - correctly report missing library as ``requests`` and not ``another_library`` (https://github.com/ansible-collections/community.general/pull/5111).
-- dnstxt lookup plugin - add option to return empty result without empty strings, and return empty list instead of ``NXDOMAIN`` (https://github.com/ansible-collections/community.general/pull/5457, https://github.com/ansible-collections/community.general/issues/5428).
-- dsv lookup plugin - do not ignore the ``tld`` parameter (https://github.com/ansible-collections/community.general/pull/4911).
-- filesystem - handle ``fatresize --info`` output lines without ``:`` (https://github.com/ansible-collections/community.general/pull/4700).
-- filesystem - improve error messages when output cannot be parsed by including newlines in escaped form (https://github.com/ansible-collections/community.general/pull/4700).
-- funcd connection plugin - fix signature of ``exec_command`` (https://github.com/ansible-collections/community.general/pull/5111).
-- ini_file - minor refactor fixing a python lint error (https://github.com/ansible-collections/community.general/pull/5307).
-- iso_create - the module somtimes failed to add folders for Joliet and UDF formats (https://github.com/ansible-collections/community.general/issues/5275).
-- keycloak_realm - fix default groups and roles (https://github.com/ansible-collections/community.general/issues/4241).
-- keyring_info - fix the result from the keyring library never getting returned (https://github.com/ansible-collections/community.general/pull/4964).
-- ldap_attrs - fix bug which caused a ``Bad search filter`` error. The error was occuring when the ldap attribute value contained special characters such as ``(`` or ``*`` (https://github.com/ansible-collections/community.general/issues/5434, https://github.com/ansible-collections/community.general/pull/5435).
-- ldap_attrs - fix ordering issue by ignoring the ``{x}`` prefix on attribute values (https://github.com/ansible-collections/community.general/issues/977, https://github.com/ansible-collections/community.general/pull/5385).
-- listen_ports_facts - removed leftover ``EnvironmentError`` . The ``else`` clause had a wrong indentation. The check is now handled in the ``split_pid_name`` function (https://github.com/ansible-collections/community.general/pull/5202).
-- locale_gen - fix support for Ubuntu (https://github.com/ansible-collections/community.general/issues/5281).
-- lxc_container - the module has been updated to support Python 3 (https://github.com/ansible-collections/community.general/pull/5304).
-- lxd connection plugin - fix incorrect ``inventory_hostname`` in ``remote_addr``. This is needed for compatibility with ansible-core 2.13 (https://github.com/ansible-collections/community.general/issues/4886).
-- manageiq_alert_profiles - avoid crash when reporting unknown profile caused by trying to return an undefined variable (https://github.com/ansible-collections/community.general/pull/5111).
-- nmcli - avoid changed status for most cases with VPN connections (https://github.com/ansible-collections/community.general/pull/5126).
-- nmcli - fix error caused by adding undefined module arguments for list options (https://github.com/ansible-collections/community.general/issues/4373, https://github.com/ansible-collections/community.general/pull/4813).
-- nmcli - fix error when setting previously unset MAC address, ``gsm.apn`` or ``vpn.data``: current values were being normalized without checking if they might be ``None`` (https://github.com/ansible-collections/community.general/pull/5291).
-- nmcli - fix int options idempotence (https://github.com/ansible-collections/community.general/issues/4998).
-- nsupdate - compatibility with NS records (https://github.com/ansible-collections/community.general/pull/5112).
-- nsupdate - fix silent failures when updating ``NS`` entries from Bind9 managed DNS zones (https://github.com/ansible-collections/community.general/issues/4657).
-- opentelemetry callback plugin - support opentelemetry-api 1.13.0 that removed support for ``_time_ns`` (https://github.com/ansible-collections/community.general/pull/5342).
-- osx_defaults - no longer expand ``~`` in ``value`` to the user's home directory, or expand environment variables (https://github.com/ansible-collections/community.general/issues/5234, https://github.com/ansible-collections/community.general/pull/5243).
-- packet_ip_subnet - fix error reporting in case of invalid CIDR prefix lengths (https://github.com/ansible-collections/community.general/pull/5111).
-- pacman - fixed name resolution of URL packages (https://github.com/ansible-collections/community.general/pull/4959).
-- passwordstore lookup plugin - fix ``returnall`` for gopass (https://github.com/ansible-collections/community.general/pull/5027).
-- passwordstore lookup plugin - fix password store path detection for gopass (https://github.com/ansible-collections/community.general/pull/4955).
-- pfexec become plugin - remove superflous quotes preventing exe wrap from working as expected (https://github.com/ansible-collections/community.general/issues/3671, https://github.com/ansible-collections/community.general/pull/3889).
-- pip_package_info - remove usage of global variable (https://github.com/ansible-collections/community.general/pull/5111).
-- pkgng - fix case when ``pkg`` fails when trying to upgrade all packages (https://github.com/ansible-collections/community.general/issues/5363).
-- proxmox - fix error handling when getting VM by name when ``state=absent`` (https://github.com/ansible-collections/community.general/pull/4945).
-- proxmox inventory plugin - fix crash when ``enabled=1`` is used in agent config string (https://github.com/ansible-collections/community.general/pull/4910).
-- proxmox inventory plugin - fixed extended status detection for qemu (https://github.com/ansible-collections/community.general/pull/4816).
-- proxmox_kvm - fix ``agent`` parameter when boolean value is specified (https://github.com/ansible-collections/community.general/pull/5198).
-- proxmox_kvm - fix error handling when getting VM by name when ``state=absent`` (https://github.com/ansible-collections/community.general/pull/4945).
-- proxmox_kvm - fix exception when no ``agent`` argument is specified (https://github.com/ansible-collections/community.general/pull/5194).
-- proxmox_kvm - fix wrong condition (https://github.com/ansible-collections/community.general/pull/5108).
-- proxmox_kvm - replace new condition with proper condition to allow for using ``vmid`` on update (https://github.com/ansible-collections/community.general/pull/5206).
-- rax_clb_nodes - fix code to be compatible with Python 3 (https://github.com/ansible-collections/community.general/pull/4933).
-- redfish_command - fix the check if a virtual media is unmounted to just check for ``instered= false`` caused by Supermicro hardware that does not clear the ``ImageName`` (https://github.com/ansible-collections/community.general/pull/4839).
-- redfish_command - the Supermicro Redfish implementation only supports the ``image_url`` parameter in the underlying API calls to ``VirtualMediaInsert`` and ``VirtualMediaEject``. Any values set (or the defaults) for ``write_protected`` or ``inserted`` will be ignored (https://github.com/ansible-collections/community.general/pull/4839).
-- redfish_info - fix to ``GetChassisPower`` to correctly report power information when multiple chassis exist, but not all chassis report power information (https://github.com/ansible-collections/community.general/issues/4901).
-- redfish_utils module utils - centralize payload checking when performing modification requests to a Redfish service (https://github.com/ansible-collections/community.general/issues/5210/).
-- redhat_subscription - fix unsubscribing on RHEL 9 (https://github.com/ansible-collections/community.general/issues/4741).
-- redhat_subscription - make module idempotent when ``pool_ids`` are used (https://github.com/ansible-collections/community.general/issues/5313).
-- redis* modules - fix call to ``module.fail_json`` when failing because of missing Python libraries (https://github.com/ansible-collections/community.general/pull/4733).
-- slack - fix incorrect channel prefix ``#`` caused by incomplete pattern detection by adding ``G0`` and ``GF`` as channel ID patterns (https://github.com/ansible-collections/community.general/pull/5019).
-- slack - fix message update for channels which start with ``CP``. When ``message-id`` was passed it failed for channels which started with ``CP`` because the ``#`` symbol was added before the ``channel_id`` (https://github.com/ansible-collections/community.general/pull/5249).
-- snap - allow values in the ``options`` parameter to contain whitespaces (https://github.com/ansible-collections/community.general/pull/5475).
-- sudoers - ensure sudoers config files are created with the permissions requested by sudoers (0440) (https://github.com/ansible-collections/community.general/pull/4814).
-- sudoers - fix incorrect handling of ``state: absent`` (https://github.com/ansible-collections/community.general/issues/4852).
-- tss lookup plugin - adding support for updated Delinea library (https://github.com/DelineaXPM/python-tss-sdk/issues/9, https://github.com/ansible-collections/community.general/pull/5151).
-- virtualbox inventory plugin - skip parsing values with keys that have both a value and nested data. Skip parsing values that are nested more than two keys deep (https://github.com/ansible-collections/community.general/issues/5332, https://github.com/ansible-collections/community.general/pull/5348).
-- xcc_redfish_command - for compatibility due to Redfish spec changes the virtualMedia resource location changed from Manager to System (https://github.com/ansible-collections/community.general/pull/4682).
-- xenserver_facts - fix broken ``AnsibleModule`` call that prevented the module from working at all (https://github.com/ansible-collections/community.general/pull/5383).
-- xfconf - fix setting of boolean values (https://github.com/ansible-collections/community.general/issues/4999, https://github.com/ansible-collections/community.general/pull/5007).
-- zfs - fix wrong quoting of properties (https://github.com/ansible-collections/community.general/issues/4707, https://github.com/ansible-collections/community.general/pull/4726).
+- CmdRunner module utils - does not attempt to resolve path if executable is a relative or absolute path (https://github.com/ansible-collections/community.general/pull/7200).
+- MH DependencyMixin module utils - deprecation notice was popping up for modules not using dependencies (https://github.com/ansible-collections/community.general/pull/6644, https://github.com/ansible-collections/community.general/issues/6639).
+- bitwarden lookup plugin - the plugin made assumptions about the structure of a Bitwarden JSON object which may have been broken by an update in the Bitwarden API. Remove assumptions, and allow queries for general fields such as ``notes`` (https://github.com/ansible-collections/community.general/pull/7061).
+- cmd_runner module utils - when a parameter in ``argument_spec`` has no type, meaning it is implicitly a ``str``, ``CmdRunner`` would fail trying to find the ``type`` key in that dictionary (https://github.com/ansible-collections/community.general/pull/6968).
+- cobbler inventory plugin - fix calculation of cobbler_ipv4/6_address (https://github.com/ansible-collections/community.general/pull/6925).
+- composer - fix impossible to run ``working_dir`` dependent commands. The module was throwing an error when trying to run a ``working_dir`` dependent command, because it tried to get the command help without passing the ``working_dir`` (https://github.com/ansible-collections/community.general/issues/3787).
+- csv module utils - detects and remove unicode BOM markers from incoming CSV content (https://github.com/ansible-collections/community.general/pull/6662).
+- datadog_downtime - presence of ``rrule`` param lead to the Datadog API returning Bad Request due to a missing recurrence type (https://github.com/ansible-collections/community.general/pull/6811).
+- ejabberd_user - module was failing to detect whether user was already created and/or password was changed (https://github.com/ansible-collections/community.general/pull/7033).
+- ejabberd_user - provide meaningful error message when the ``ejabberdctl`` command is not found (https://github.com/ansible-collections/community.general/pull/7028, https://github.com/ansible-collections/community.general/issues/6949).
+- github_deploy_key - fix pagination behaviour causing a crash when only a single page of deploy keys exist (https://github.com/ansible-collections/community.general/pull/7375).
+- gitlab_group - the module passed parameters to the API call even when not set. The module is now filtering out ``None`` values to remediate this (https://github.com/ansible-collections/community.general/pull/6712).
+- gitlab_group_variable - deleted all variables when used with ``purge=true`` due to missing ``raw`` property in KNOWN attributes (https://github.com/ansible-collections/community.general/issues/7250).
+- gitlab_project_variable - deleted all variables when used with ``purge=true`` due to missing ``raw`` property in KNOWN attributes (https://github.com/ansible-collections/community.general/issues/7250).
+- icinga2_host - fix a key error when updating an existing host (https://github.com/ansible-collections/community.general/pull/6748).
+- ini_file - add the ``follow`` paramter to follow the symlinks instead of replacing them (https://github.com/ansible-collections/community.general/pull/6546).
+- ini_file - fix a bug where the inactive options were not used when possible (https://github.com/ansible-collections/community.general/pull/6575).
+- ipa_dnszone - fix 'idnsallowsyncptr' key error for reverse zone (https://github.com/ansible-collections/community.general/pull/6906, https://github.com/ansible-collections/community.general/issues/6905).
+- kernel_blacklist - simplified the mechanism to update the file, fixing the error (https://github.com/ansible-collections/community.general/pull/7382, https://github.com/ansible-collections/community.general/issues/7362).
+- keycloak module util - fix missing ``http_agent``, ``timeout``, and ``validate_certs`` ``open_url()`` parameters (https://github.com/ansible-collections/community.general/pull/7067).
+- keycloak module utils - fix ``is_struct_included`` handling of lists of lists/dictionaries (https://github.com/ansible-collections/community.general/pull/6688).
+- keycloak module utils - the function ``get_user_by_username`` now return the user representation or ``None`` as stated in the documentation (https://github.com/ansible-collections/community.general/pull/6758).
+- keycloak_authentication - fix Keycloak authentication flow (step or sub-flow) indexing during update, if not specified by the user (https://github.com/ansible-collections/community.general/pull/6734).
+- keycloak_client inventory plugin - fix missing client secret (https://github.com/ansible-collections/community.general/pull/6931).
+- ldap_search - fix string normalization and the ``base64_attributes`` option on Python 3 (https://github.com/ansible-collections/community.general/issues/5704, https://github.com/ansible-collections/community.general/pull/7264).
+- locale_gen - now works for locales without the underscore character such as ``C.UTF-8`` (https://github.com/ansible-collections/community.general/pull/6774, https://github.com/ansible-collections/community.general/issues/5142, https://github.com/ansible-collections/community.general/issues/4305).
+- lvol - add support for percentage of origin size specification when creating snapshot volumes (https://github.com/ansible-collections/community.general/issues/1630, https://github.com/ansible-collections/community.general/pull/7053).
+- lxc connection plugin - now handles ``remote_addr`` defaulting to ``inventory_hostname`` correctly (https://github.com/ansible-collections/community.general/pull/7104).
+- lxc connection plugin - properly evaluate options (https://github.com/ansible-collections/community.general/pull/7369).
+- machinectl become plugin - mark plugin as ``require_tty`` to automatically disable pipelining, with which this plugin is not compatible (https://github.com/ansible-collections/community.general/issues/6932, https://github.com/ansible-collections/community.general/pull/6935).
+- mail - skip headers containing equals characters due to missing ``maxsplit`` on header key/value parsing (https://github.com/ansible-collections/community.general/pull/7303).
+- memset module utils - make compatible with ansible-core 2.17 (https://github.com/ansible-collections/community.general/pull/7379).
+- nmap inventory plugin - fix ``get_option`` calls (https://github.com/ansible-collections/community.general/pull/7323).
+- nmap inventory plugin - now uses ``get_option`` in all cases to get its configuration information (https://github.com/ansible-collections/community.general/pull/7119).
+- nmcli - fix bond option ``xmit_hash_policy`` (https://github.com/ansible-collections/community.general/pull/6527).
+- nmcli - fix support for empty list (in compare and scrape) (https://github.com/ansible-collections/community.general/pull/6769).
+- nsupdate - fix a possible ``list index out of range`` exception (https://github.com/ansible-collections/community.general/issues/836).
+- oci_utils module util - fix inappropriate logical comparison expressions and makes them simpler. The previous checks had logical short circuits (https://github.com/ansible-collections/community.general/pull/7125).
+- oci_utils module utils - avoid direct type comparisons (https://github.com/ansible-collections/community.general/pull/7085).
+- onepassword - fix KeyError exception when trying to access value of a field that is not filled out in OnePassword item (https://github.com/ansible-collections/community.general/pull/7241).
+- openbsd_pkg - the pkg_info(1) behavior has changed in OpenBSD >7.3. The error message ``Can't find`` should not lead to an error case (https://github.com/ansible-collections/community.general/pull/6785).
+- pacman - module recognizes the output of ``yay`` running as ``root`` (https://github.com/ansible-collections/community.general/pull/6713).
+- portage - fix ``changed_use`` and ``newuse`` not triggering rebuilds (https://github.com/ansible-collections/community.general/issues/6008, https://github.com/ansible-collections/community.general/pull/6548).
+- pritunl module utils - fix incorrect URL parameter for orgnization add method (https://github.com/ansible-collections/community.general/pull/7161).
+- proxmox - fix error when a configuration had no ``template`` field (https://github.com/ansible-collections/community.general/pull/6838, https://github.com/ansible-collections/community.general/issues/5372).
+- proxmox module utils - add logic to detect whether an old Promoxer complains about the ``token_name`` and ``token_value`` parameters and provide a better error message when that happens (https://github.com/ansible-collections/community.general/pull/6839, https://github.com/ansible-collections/community.general/issues/5371).
+- proxmox module utils - fix proxmoxer library version check (https://github.com/ansible-collections/community.general/issues/6974, https://github.com/ansible-collections/community.general/issues/6975, https://github.com/ansible-collections/community.general/pull/6980).
+- proxmox_disk - fix unable to create ``cdrom`` media due to ``size`` always being appended (https://github.com/ansible-collections/community.general/pull/6770).
+- proxmox_kvm - ``absent`` state with ``force`` specified failed to stop the VM due to the ``timeout`` value not being passed to ``stop_vm`` (https://github.com/ansible-collections/community.general/pull/6827).
+- proxmox_kvm - ``restarted`` state did not actually restart a VM in some VM configurations. The state now uses the Proxmox reboot endpoint instead of calling the ``stop_vm`` and ``start_vm`` functions (https://github.com/ansible-collections/community.general/pull/6773).
+- proxmox_kvm - allow creation of VM with existing name but new vmid (https://github.com/ansible-collections/community.general/issues/6155, https://github.com/ansible-collections/community.general/pull/6709).
+- proxmox_kvm - when ``name`` option is provided without ``vmid`` and VM with that name already exists then no new VM will be created (https://github.com/ansible-collections/community.general/issues/6911, https://github.com/ansible-collections/community.general/pull/6981).
+- proxmox_tasks_info - remove ``api_user`` + ``api_password`` constraint from ``required_together`` as it causes to require ``api_password`` even when API token param is used (https://github.com/ansible-collections/community.general/issues/6201).
+- proxmox_template - require ``requests_toolbelt`` module to fix issue with uploading large templates (https://github.com/ansible-collections/community.general/issues/5579, https://github.com/ansible-collections/community.general/pull/6757).
+- proxmox_user_info - avoid direct type comparisons (https://github.com/ansible-collections/community.general/pull/7085).
+- redfish_info - fix ``ListUsers`` to not show empty account slots (https://github.com/ansible-collections/community.general/issues/6771, https://github.com/ansible-collections/community.general/pull/6772).
+- redhat_subscription - use the right D-Bus options for the consumer type when
+ registering a RHEL system older than 9 or a RHEL 9 system older than 9.2
+ and using ``consumer_type``
+ (https://github.com/ansible-collections/community.general/pull/7378).
+- refish_utils module utils - changing variable names to avoid issues occuring when fetching Volumes data (https://github.com/ansible-collections/community.general/pull/6883).
+- rhsm_repository - when using the ``purge`` option, the ``repositories``
+ dictionary element in the returned JSON is now properly updated according
+ to the pruning operation
+ (https://github.com/ansible-collections/community.general/pull/6676).
+- rundeck - fix ``TypeError`` on 404 API response (https://github.com/ansible-collections/community.general/pull/6983).
+- selective callback plugin - fix length of task name lines in output always being 3 characters longer than desired (https://github.com/ansible-collections/community.general/pull/7374).
+- snap - an exception was being raised when snap list was empty (https://github.com/ansible-collections/community.general/pull/7124, https://github.com/ansible-collections/community.general/issues/7120).
+- snap - assume default track ``latest`` in parameter ``channel`` when not specified (https://github.com/ansible-collections/community.general/pull/6835, https://github.com/ansible-collections/community.general/issues/6821).
+- snap - change the change detection mechanism from "parsing installation" to "comparing end state with initial state" (https://github.com/ansible-collections/community.general/pull/7340, https://github.com/ansible-collections/community.general/issues/7265).
+- snap - fix crash when multiple snaps are specified and one has ``---`` in its description (https://github.com/ansible-collections/community.general/pull/7046).
+- snap - fix the processing of the commands' output, stripping spaces and newlines from it (https://github.com/ansible-collections/community.general/pull/6826, https://github.com/ansible-collections/community.general/issues/6803).
+- sorcery - fix interruption of the multi-stage process (https://github.com/ansible-collections/community.general/pull/7012).
+- sorcery - fix queue generation before the whole system rebuild (https://github.com/ansible-collections/community.general/pull/7012).
+- sorcery - latest state no longer triggers update_cache (https://github.com/ansible-collections/community.general/pull/7012).
+- terraform - prevents ``-backend-config`` option double encapsulating with ``shlex_quote`` function. (https://github.com/ansible-collections/community.general/pull/7301).
+- tss lookup plugin - fix multiple issues when using ``fetch_attachments=true`` (https://github.com/ansible-collections/community.general/pull/6720).
+- zypper - added handling of zypper exitcode 102. Changed state is set correctly now and rc 102 is still preserved to be evaluated by the playbook (https://github.com/ansible-collections/community.general/pull/6534).
+
+Known Issues
+------------
+
+- Ansible markup will show up in raw form on ansible-doc text output for ansible-core before 2.15. If you have trouble deciphering the documentation markup, please upgrade to ansible-core 2.15 (or newer), or read the HTML documentation on https://docs.ansible.com/ansible/devel/collections/community/general/ (https://github.com/ansible-collections/community.general/pull/6539).
New Plugins
-----------
-Filter
-~~~~~~
-
-- counter - Counts hashable elements in a sequence
-
Lookup
~~~~~~
-- bitwarden - Retrieve secrets from Bitwarden
+- bitwarden_secrets_manager - Retrieve secrets from Bitwarden Secrets Manager
New Modules
-----------
-- gconftool2_info - Retrieve GConf configurations
-- iso_customize - Add/remove/change files in ISO file
-- keycloak_user_rolemapping - Allows administration of Keycloak user_rolemapping with the Keycloak API
-- keyring - Set or delete a passphrase using the Operating System's native keyring
-- keyring_info - Get a passphrase using the Operating System's native keyring
-- manageiq_policies_info - Listing of resource policy_profiles in ManageIQ
-- manageiq_tags_info - Retrieve resource tags in ManageIQ
-- pipx_info - Rretrieves information about applications installed with pipx
-- proxmox_disk - Management of a disk of a Qemu(KVM) VM in a Proxmox VE cluster.
-- scaleway_compute_private_network - Scaleway compute - private network management
-- scaleway_container - Scaleway Container management
-- scaleway_container_info - Retrieve information on Scaleway Container
-- scaleway_container_namespace - Scaleway Container namespace management
-- scaleway_container_namespace_info - Retrieve information on Scaleway Container namespace
-- scaleway_container_registry - Scaleway Container registry management module
-- scaleway_container_registry_info - Scaleway Container registry info module
-- scaleway_function - Scaleway Function management
-- scaleway_function_info - Retrieve information on Scaleway Function
-- scaleway_function_namespace - Scaleway Function namespace management
-- scaleway_function_namespace_info - Retrieve information on Scaleway Function namespace
-- wdc_redfish_command - Manages WDC UltraStar Data102 Out-Of-Band controllers using Redfish APIs
-- wdc_redfish_info - Manages WDC UltraStar Data102 Out-Of-Band controllers using Redfish APIs
+- consul_policy - Manipulate Consul policies
+- consul_role - Manipulate Consul roles
+- facter_facts - Runs the discovery program C(facter) on the remote system and return Ansible facts
+- gio_mime - Set default handler for MIME type, for applications using Gnome GIO
+- gitlab_instance_variable - Creates, updates, or deletes GitLab instance variables
+- gitlab_merge_request - Create, update, or delete GitLab merge requests
+- jenkins_build_info - Get information about Jenkins builds
+- keycloak_authentication_required_actions - Allows administration of Keycloak authentication required actions
+- keycloak_authz_custom_policy - Allows administration of Keycloak client custom Javascript policies via Keycloak API
+- keycloak_authz_permission - Allows administration of Keycloak client authorization permissions via Keycloak API
+- keycloak_authz_permission_info - Query Keycloak client authorization permissions information
+- keycloak_realm_key - Allows administration of Keycloak realm keys via Keycloak API
+- keycloak_user - Create and configure a user in Keycloak
+- lvg_rename - Renames LVM volume groups
+- pnpm - Manage node.js packages with pnpm
+- proxmox_pool - Pool management for Proxmox VE cluster
+- proxmox_pool_member - Add or delete members from Proxmox VE cluster pools
+- proxmox_vm_info - Retrieve information about one or more Proxmox VE virtual machines
+- simpleinit_msb - Manage services on Source Mage GNU/Linux
diff --git a/ansible_collections/community/general/CONTRIBUTING.md b/ansible_collections/community/general/CONTRIBUTING.md
index 358daa5e9..199e90c5b 100644
--- a/ansible_collections/community/general/CONTRIBUTING.md
+++ b/ansible_collections/community/general/CONTRIBUTING.md
@@ -31,7 +31,7 @@ Also, consider taking up a valuable, reviewed, but abandoned pull request which
* Try committing your changes with an informative but short commit message.
* Do not squash your commits and force-push to your branch if not needed. Reviews of your pull request are much easier with individual commits to comprehend the pull request history. All commits of your pull request branch will be squashed into one commit by GitHub upon merge.
* Do not add merge commits to your PR. The bot will complain and you will have to rebase ([instructions for rebasing](https://docs.ansible.com/ansible/latest/dev_guide/developing_rebasing.html)) to remove them before your PR can be merged. To avoid that git automatically does merges during pulls, you can configure it to do rebases instead by running `git config pull.rebase true` inside the repository checkout.
-* Make sure your PR includes a [changelog fragment](https://docs.ansible.com/ansible/devel/community/development_process.html#creating-changelog-fragments). (You must not include a fragment for new modules or new plugins, except for test and filter plugins. Also you shouldn't include one for docs-only changes. If you're not sure, simply don't include one, we'll tell you whether one is needed or not :) )
+* Make sure your PR includes a [changelog fragment](https://docs.ansible.com/ansible/devel/community/development_process.html#creating-changelog-fragments). (You must not include a fragment for new modules or new plugins. Also you shouldn't include one for docs-only changes. If you're not sure, simply don't include one, we'll tell you whether one is needed or not :) )
* Avoid reformatting unrelated parts of the codebase in your PR. These types of changes will likely be requested for reversion, create additional work for reviewers, and may cause approval to be delayed.
You can also read [our Quick-start development guide](https://github.com/ansible/community-docs/blob/main/create_pr_quick_start_guide.rst).
@@ -121,19 +121,3 @@ Creating new modules and plugins requires a bit more work than other Pull Reques
listed as `maintainers` will be pinged for new issues and PRs that modify the module/plugin or its tests.
When you add a new plugin/module, we expect that you perform maintainer duty for at least some time after contributing it.
-
-## pre-commit
-
-To help ensure high-quality contributions this repository includes a [pre-commit](https://pre-commit.com) configuration which
-corrects and tests against common issues that would otherwise cause CI to fail. To begin using these pre-commit hooks see
-the [Installation](#installation) section below.
-
-This is optional and not required to contribute to this repository.
-
-### Installation
-
-Follow the [instructions](https://pre-commit.com/#install) provided with pre-commit and run `pre-commit install` under the repository base. If for any reason you would like to disable the pre-commit hooks run `pre-commit uninstall`.
-
-This is optional to run it locally.
-
-You can trigger it locally with `pre-commit run --all-files` or even to run only for a given file `pre-commit run --files YOUR_FILE`.
diff --git a/ansible_collections/community/general/FILES.json b/ansible_collections/community/general/FILES.json
index 5db6d01e6..c84d62a88 100644
--- a/ansible_collections/community/general/FILES.json
+++ b/ansible_collections/community/general/FILES.json
@@ -109,7 +109,7 @@
"name": ".azure-pipelines/azure-pipelines.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "569cbda91c80aeddd6a357ea3f766669a76a4547ebbf54b7b32a4d09fe949ce9",
+ "chksum_sha256": "3a0a3c682a3f4926434b08f73ab1d362629d17db898358d8970c0a78d6195a74",
"format": 1
},
{
@@ -130,7 +130,7 @@
"name": ".github/ISSUE_TEMPLATE/bug_report.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c928fdf2a407181cd2733e99684a11060a3c2dfc4189a5e3c415ebd53f34f562",
+ "chksum_sha256": "740ac1f7961eef27fb64e6d42b864f07f3ac829909416d04e088a769ede6c8df",
"format": 1
},
{
@@ -144,14 +144,14 @@
"name": ".github/ISSUE_TEMPLATE/documentation_report.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "976b5f4c7544b9438724037369c27fdf474d8aa5fb55af19eb3853581c2ae0fb",
+ "chksum_sha256": "ba8c0bc1977eaa58884906d8cc8a1a4e22f742058ca966630232732c86cf6d7d",
"format": 1
},
{
"name": ".github/ISSUE_TEMPLATE/feature_request.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7d5c6b512bb5b8031886d043e9121d643c34a445dfc35e7c396f90facd9ae863",
+ "chksum_sha256": "11b2df0d0dcb22a7aed30a82a73ed68ff3007408c054539a8114119a231039e6",
"format": 1
},
{
@@ -165,28 +165,35 @@
"name": ".github/workflows/ansible-test.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b30123e188ab9c7e77cbc5dfd71585d7ba02ccd2ba07ae702757d5dc7c24bdbb",
+ "chksum_sha256": "881d33effb01a3b9c94026a3720af4fc2cc3f1c7fa93d48d4ffd2584b9e2db9d",
"format": 1
},
{
"name": ".github/workflows/codeql-analysis.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0ee0e5baf1022280bfe9bb31af5caa90bc70b3feada2e16c2404f14be8e30e9c",
+ "chksum_sha256": "4eb34c04ed677f1397fc42456d889a85760f292a1b23fb5b2e791bf25dcf1abf",
+ "format": 1
+ },
+ {
+ "name": ".github/workflows/import-galaxy.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "739c36223d6e0e6ccc98907c43cba53296e7b1ccd64a2d995c2ff21df4ab25a5",
"format": 1
},
{
"name": ".github/workflows/reuse.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3198de8ad067ccbb07ee9e461632f8ffce2e5eae1c77329ebb1935ed878811f0",
+ "chksum_sha256": "e2215871ff8514d68d7955a119aa9f95050bee28bf7aa309ebeea633892a099e",
"format": 1
},
{
"name": ".github/BOTMETA.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1e115baf123a80784ad9779135a969029087ee5104fe7d6f9e66fda6c1ec7e6d",
+ "chksum_sha256": "2f3ee06f8b6dad417086bf9cc5e0e7ff4519aa65139373c43e3fbe7cff572f3b",
"format": 1
},
{
@@ -204,6 +211,20 @@
"format": 1
},
{
+ "name": ".github/pull_request_template.md",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "8a1d0ac94233061c47e0fd7abe0726e4ca8a36b83b72efb432f9db793b7d1034",
+ "format": 1
+ },
+ {
+ "name": ".github/pull_request_template.md.license",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c111f1eddc1753ec6db64f82f4167c31ccb175960662c30ffbea6ee2f0ed47d0",
+ "format": 1
+ },
+ {
"name": ".github/settings.yml",
"ftype": "file",
"chksum_type": "sha256",
@@ -291,7 +312,7 @@
"name": "changelogs/changelog.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "06567fbbffc7f5357eba89d98577dd40b961bcef14ebb452111d609b1b019ae6",
+ "chksum_sha256": "cabe396ff93a6bc5327c16686af1c75f29d1b239ce7ceb6e25930f33690da3da",
"format": 1
},
{
@@ -305,7 +326,7 @@
"name": "changelogs/config.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4d9b70273177bcc2aac7752be98876e4bea048566ab55f1c1be2ac2e34f7f83b",
+ "chksum_sha256": "e207e9de9d07482a7e441694cf7228b7032639e7c85c56d5d9af454d3bf4e86f",
"format": 1
},
{
@@ -627,98 +648,133 @@
"name": "docs/docsite/rst/filter_guide_abstract_informations.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9673ab16c175d095503c01855617585ed74a750fe44ca53dd77a11b083712c2e",
+ "chksum_sha256": "f46cd19ccef0d531d8dd98606fe9165e97df0c848d2af0b7060c60620a8a2ff0",
"format": 1
},
{
"name": "docs/docsite/rst/filter_guide_abstract_informations_counting_elements_in_sequence.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "445709ac655c00442e6394a4726886d6365b799cd18674bdeec037bc725cc16e",
+ "chksum_sha256": "c734799d76f9f9bd16220dd8d10b7745680d4feba87c8877fc04bc4fcd4a2a1a",
"format": 1
},
{
"name": "docs/docsite/rst/filter_guide_abstract_informations_dictionaries.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "88e9098413c34026a6a56d676f1d10c46bbf8de27d6451dad0843e6d5942b201",
+ "chksum_sha256": "067e5c18555a3e05f871cc4febf2c640b4ed0c97978121178e90137f199aafe3",
"format": 1
},
{
"name": "docs/docsite/rst/filter_guide_abstract_informations_grouping.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "dcb3a21f1fc8b9cba37b42a83734bd2d4b6674235751b13de50add2984e9cb21",
+ "chksum_sha256": "5e19ac7e2f029124f6cf4b64a10a8e9ef1a67d8b8841481e93dd4b2b46a08934",
+ "format": 1
+ },
+ {
+ "name": "docs/docsite/rst/filter_guide_abstract_informations_lists_helper.rst",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "28a59873fbb195933ea1be7d7fab1d3f0e117712d69d243ad0b5c03e66ea2e2d",
"format": 1
},
{
"name": "docs/docsite/rst/filter_guide_abstract_informations_merging_lists_of_dictionaries.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a800545d0815aa27a81ee5a6953547cc95f73b892f55f3b1740dfcee17de1a31",
+ "chksum_sha256": "a0a81486d2b415efa2e2f8576b3aadb98125e74b10b2113f13f6dcf1e652faed",
"format": 1
},
{
"name": "docs/docsite/rst/filter_guide_conversions.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a55a01c7ea069d6cc1ba48873f9539cb75ff84893ca870c8bd57db43302461f1",
+ "chksum_sha256": "4a62ef97835a64be3bb9f4e1b27e700432fa644cd19517acf8877f2cb84bc2f6",
"format": 1
},
{
"name": "docs/docsite/rst/filter_guide_creating_identifiers.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b2dedef7bafae9792207e41391205f651edd21b4a0b57c541be82c4075f75226",
+ "chksum_sha256": "4ccf2d1c9f7940e70e6c59b14c08f7564f5725f66986e6b148791ac3d724e266",
"format": 1
},
{
"name": "docs/docsite/rst/filter_guide_paths.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9ba5e31891655d169ad835d65da51eeaebb542305bd2f004c5e275e941d1da1c",
+ "chksum_sha256": "509735f3fe05da9df80d62afce847cc2e1db30710b4e6017af2a8522de2bebc7",
"format": 1
},
{
"name": "docs/docsite/rst/filter_guide_selecting_json_data.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ae8db5288f8fdff26aa7927d6e83ca54e66b8c74caf23589bd09a32987558bd7",
+ "chksum_sha256": "591647d02465fb7e3c1e5fd274c396b2ddada1f8f733c432fe415cc6234f255b",
"format": 1
},
{
"name": "docs/docsite/rst/filter_guide_working_with_times.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2e6ea07f337f5d298ee8b5d4a7ab799f960010a85beddb7ffcb88651bbeb3c2d",
+ "chksum_sha256": "3231cfdd007720e152c77d9328cfc77700715610f39078c9d399c53dda8bfb5c",
"format": 1
},
{
"name": "docs/docsite/rst/filter_guide_working_with_unicode.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "dd0c1ac2407c97bb0b513566e17051ab20bc7f8313d68efa380bc308655d9151",
+ "chksum_sha256": "2332e0c2578032e39479a475d58b2ffc63f762dadce7d5a912d4302af40cdb6e",
"format": 1
},
{
"name": "docs/docsite/rst/filter_guide_working_with_versions.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "aed3270dc77a60e71ce47a3897b77a6e9ae8636661ccd07d650bd7040fc28359",
+ "chksum_sha256": "0984155f7feaf450efe473d41dc98374cd275762836fff74212335e9aba93ff6",
+ "format": 1
+ },
+ {
+ "name": "docs/docsite/rst/guide_alicloud.rst",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6c741a03c0fadd11eac1b008e2a1be6f73a88f03125278eef8d3eac5580113b0",
+ "format": 1
+ },
+ {
+ "name": "docs/docsite/rst/guide_online.rst",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "a1ed8b72429b98d47fd30e4d460e3fcd3db2db6e19868f8fb92018f64e6fb62e",
+ "format": 1
+ },
+ {
+ "name": "docs/docsite/rst/guide_packet.rst",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "2816545cf8a0f26c19ed3d182a7a744cc1787c419186392ebfa86b6f0bc07565",
+ "format": 1
+ },
+ {
+ "name": "docs/docsite/rst/guide_scaleway.rst",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9c3fec4ae1b7a6f5f403ff7ffd15c1794c7dd6f6d929985600d7b82d11ba1be9",
"format": 1
},
{
"name": "docs/docsite/rst/test_guide.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "93f17c0d2998ab3fcb6cc656787b36d0703eb364d4f4ed9aa2a120bef3ab0df7",
+ "chksum_sha256": "7c247ffc4b34d0a1b159aeb042077c84c0e46055d82a1704dd14d1ee74dc2387",
"format": 1
},
{
"name": "docs/docsite/extra-docs.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9e4dff32f91531f5acfe49caddbae8744d8b97c1395e4dff1102d62ab4d02de4",
+ "chksum_sha256": "f3f9cbc513d494da6c34cf6db49319f34645a8dd1ee79736360c0e48643e76af",
"format": 1
},
{
@@ -739,7 +795,7 @@
"name": "meta/runtime.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1476d80543a98566205d337aa4623bed629ada66da100604e0f9672d6c0d0922",
+ "chksum_sha256": "893ee2f56034e3e8ac5b9a73e689fef80921b692ba6da0e5db2fd330aad2a617",
"format": 1
},
{
@@ -760,14 +816,14 @@
"name": "plugins/action/iptables_state.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a53d66f79a6f4c656ca8ce128211b7c091f989ba6b90fd7941f1c5de54513827",
+ "chksum_sha256": "761d8eb9d29f828c35626f9235e476a6819a525d05c4fd87c070d308b89d7ec9",
"format": 1
},
{
"name": "plugins/action/shutdown.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "389a1ff6ec5c3894ca807c67b6cdcf189a32a738506ad7a23ba6e4b5ea3ccd51",
+ "chksum_sha256": "7b7d4ad894acdd70454adc6a4fc869e518975b9bce5224a1fa6b6013d50f4d0b",
"format": 1
},
{
@@ -802,7 +858,7 @@
"name": "plugins/become/machinectl.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1b645d8dedc9920a4f28fcb9f4e6dd6befd9d3185be40f29c05fed563c1d5d1a",
+ "chksum_sha256": "ec9263bc03779820095278c25e9ecbf9a0b8eaefbc8b3372d2f24750a6dd0169",
"format": 1
},
{
@@ -816,7 +872,7 @@
"name": "plugins/become/pfexec.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8ed536b92a9d1cdba5ede804fe4bb3721a253e4cbb4b50e34bc8e3e15cd113d2",
+ "chksum_sha256": "0e9148eb1ca6249a0c30b62722674096d526db2b51d25f94783a0fac1f20884a",
"format": 1
},
{
@@ -865,7 +921,7 @@
"name": "plugins/cache/redis.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "26a64d84e51d0d1186fec26495bc6cc2cc3f08afff425cbd5b7f15cf6f74f2c6",
+ "chksum_sha256": "077eb2d5eeea9381f207587b7f6f07ad4831b83706842cc64cde9085047ebc2f",
"format": 1
},
{
@@ -886,7 +942,7 @@
"name": "plugins/callback/cgroup_memory_recap.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "196e22c6129e0beb6535990c5c39af72b49f3790ba885d6329d921d8cbd0792d",
+ "chksum_sha256": "28e7c963b9284824c05d2f949398542f4e00931729067480d57724f57def66c9",
"format": 1
},
{
@@ -904,6 +960,13 @@
"format": 1
},
{
+ "name": "plugins/callback/default_without_diff.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9b8d5448ed1fddfdfc20b671ca5b92e5868543756549d28a9f3919fb00930fbf",
+ "format": 1
+ },
+ {
"name": "plugins/callback/dense.py",
"ftype": "file",
"chksum_type": "sha256",
@@ -914,14 +977,14 @@
"name": "plugins/callback/diy.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5fcf28099eb1e17c7d5f15fecbb428859da6a821ac1854eadb6c63896bfdb70f",
+ "chksum_sha256": "407b0aae0b736521268e5ac4c2e1c202985d7c904a1f82aea781bbb076f9d75e",
"format": 1
},
{
"name": "plugins/callback/elastic.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "aae5776261f50ab89a672387845fea6a8304f88000b12d8375c937e02f7226e2",
+ "chksum_sha256": "ae2fdc0619985f802a61c2db588e54e241174bb4916fe1385912cfbf46a3ac18",
"format": 1
},
{
@@ -963,7 +1026,7 @@
"name": "plugins/callback/logentries.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9534b6c7d2b5cc4a9ff4cab35199577e1bd02c26ac7f8a276777e8669c809335",
+ "chksum_sha256": "8c63c2496fbaa2122b246d76ca35beba058ef046f9fcdcb5ffdc20beb59cc1ec",
"format": 1
},
{
@@ -977,77 +1040,77 @@
"name": "plugins/callback/mail.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9ddb19f09ccaec02d0b1e98ed3ab6f80b9479c2e51871e9dd84a9d26eb95aca6",
+ "chksum_sha256": "d0ec6d45df97f52689941e4c20df3b65420e088f5968848e7fa2adabf05dd2c1",
"format": 1
},
{
"name": "plugins/callback/nrdp.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7b1aff2684e6a38243bdb30404fc76508c3c4cac8c1f4d29a2a4cf7cd00b1a46",
+ "chksum_sha256": "631025f390628574bcc98cbf55282e11ffd0da744de74c473e0a9a687bd12a58",
"format": 1
},
{
"name": "plugins/callback/null.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4d0e768ead6c718de5e958d0624992cc89447f0cf5f80af1462a7f78f2189572",
+ "chksum_sha256": "510148e7ef3baae67830e642fe276fd78df2199c0b8711012f08173f944046cd",
"format": 1
},
{
"name": "plugins/callback/opentelemetry.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d4ea1bad3bfbd276d03d006730a0168d3a969c545e0ffade75ba53cd1bf4e316",
+ "chksum_sha256": "06ee85c4b296298fc04a5c1fc85408761c5e6c2c2be40fa1302a5148be6aaac4",
"format": 1
},
{
"name": "plugins/callback/say.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fdc54bf0477494706798fcb6c288c8f4bb9fe70cfd928b5b1fa0a8da066cad75",
+ "chksum_sha256": "c3e268fb8ea056e88b1c5363a874cd46f780c257286d111127a7e4815b9cc270",
"format": 1
},
{
"name": "plugins/callback/selective.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5b4e414d25029a1e14d68eaa4ecb7763f7bf586cffb18c81676db2e9ed70a5bd",
+ "chksum_sha256": "6d0be54090941056d35f85cdfe73bb4bb7f9bba6971ecc9764a8522be7c13464",
"format": 1
},
{
"name": "plugins/callback/slack.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e7401eaba4487eea31250c44426ef10b8279f0b694ee4f8c17a882a36e51cf35",
+ "chksum_sha256": "0ffa99cf39cecdd29729e815abe36cac15e23125bbe22deea70fc961cbccdc15",
"format": 1
},
{
"name": "plugins/callback/splunk.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f8ca5cfcb34a88feaaedbdb9f44704252a3d29c2838c3829a48080285c077bed",
+ "chksum_sha256": "552c6c10b5ceed03a4728c8dee70d6211a1b208095c4ff4748ebf8c2110f4bf9",
"format": 1
},
{
"name": "plugins/callback/sumologic.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c5bfb9153b1c272983612fe52b199994c3e3d7f06cdeb7924215ae0fc8da17ed",
+ "chksum_sha256": "3265907f5d62128170d48eefda9901eb1f3d6bc36d9f93e5f900403850724d73",
"format": 1
},
{
"name": "plugins/callback/syslog_json.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c5880600ec24461f70479f7410db97f122bbdbf5e8bec3231bbb5fdaed3af45d",
+ "chksum_sha256": "903587b6911fb14187b3f069a83abab85655d8c3d8c80492e2fd5446ba632ce7",
"format": 1
},
{
"name": "plugins/callback/unixy.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bbdd306804eec63f89eade94447c24e784e83fcd5204e62eaf4261813e6fc875",
+ "chksum_sha256": "009b90cce9728a50ca0cbf6cb9cf20a76ac8604f9c79491408c89b91f24a11e2",
"format": 1
},
{
@@ -1068,14 +1131,21 @@
"name": "plugins/connection/chroot.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8648738b5146b4d4202b393895824ca2817b523f049307a414719cd72b7afcfd",
+ "chksum_sha256": "a5f2494a7c124974cb5553cf9931ed75f42ab5e8c6e78a05bbf52da7af692fb1",
"format": 1
},
{
"name": "plugins/connection/funcd.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d28756792fd00a8fc3a486f16ebcef60330447215d40291c390705937f29c0ab",
+ "chksum_sha256": "20450253d6503cee83593898efb446a4c434220e19ba597a7bbc70dc159a3da3",
+ "format": 1
+ },
+ {
+ "name": "plugins/connection/incus.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "1267c63435165ca105d2203fcb0091015ad232fcfc2e0e0c17b089f9d88318e2",
"format": 1
},
{
@@ -1096,14 +1166,14 @@
"name": "plugins/connection/lxc.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e3d4201d9dab79834210fbd187f0f7c03ae55ca9da989c75fc99b997fe4f1328",
+ "chksum_sha256": "3d8ed9d38e36d6c17f3afdfcebbb27282b2d14cacf766d3cd7f98755a9cee5c8",
"format": 1
},
{
"name": "plugins/connection/lxd.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9c698516a8b75ac6bbc3a1d94cbd83c1647e6739bc4401d83035cdd1d382e8ba",
+ "chksum_sha256": "0c0fc5bea407506a530e8955c76848639624d6b673c1104f2ecbe0e007365ac0",
"format": 1
},
{
@@ -1138,7 +1208,7 @@
"name": "plugins/doc_fragments/alicloud.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c755676691121db240cff2282cff319b9c83fbc442466b641617782cdfaf26b5",
+ "chksum_sha256": "59f3d223ef943ca1b8eaf16f5a15cec765ce9e3d647f2c7055fc79696e57cc06",
"format": 1
},
{
@@ -1152,42 +1222,49 @@
"name": "plugins/doc_fragments/auth_basic.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "44e2dc39beef434001c9d02d7ee65c3ac47c64fdebf8d8b304b957d5e5f00a8e",
+ "chksum_sha256": "117440a005e3b65ea40ad73b255cad6db2becc36dda37c7b52774ae262454615",
"format": 1
},
{
"name": "plugins/doc_fragments/bitbucket.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7521d6cda99a6c6bfb45a488bba864198a9238e4522d172ac9364663f4b24727",
+ "chksum_sha256": "994d72dbe5e6067aa35a08668e0fa9c5fc2e5501f12d2c5cd6a950705ca4da1f",
+ "format": 1
+ },
+ {
+ "name": "plugins/doc_fragments/consul.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "16c9b8dc132b77db794a3a96cb75b44900671648edf7962e64f49f65b5b263f3",
"format": 1
},
{
"name": "plugins/doc_fragments/dimensiondata.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ceefadbc09e96b3217066fe970117d94a7e8ad428a16f2ada6ec4f205b2feb7f",
+ "chksum_sha256": "7f46cdf546fb093b1e059f38fbe480d58ffcf60b9fcb92e66e107bc2b1aa7bc5",
"format": 1
},
{
"name": "plugins/doc_fragments/dimensiondata_wait.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e12eb961245371eeb738735a43a61586dd677259e18bc900362c608fb5afdad0",
+ "chksum_sha256": "ed0884d038ba1630008c63a012cbb8d6b25af36497ab0a265ad3592bd2f4ec00",
"format": 1
},
{
"name": "plugins/doc_fragments/emc.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f494e26b7e059222476883669eb84bff4e3bf711c72b5b9098d9ab2cca52d685",
+ "chksum_sha256": "bcf11b6cf0f5043dee3b6ef0c993a07199ec50627ec452b86ad4eaf062a034b9",
"format": 1
},
{
"name": "plugins/doc_fragments/gitlab.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f1a610f5bebc33d55c50efe3184598fae8e7583fb59b721b60c67be950e2e665",
+ "chksum_sha256": "155f24e7e4a1d60827bdaf200f2c66fd03cd50efc44032af72e89e77bb5c0790",
"format": 1
},
{
@@ -1201,119 +1278,126 @@
"name": "plugins/doc_fragments/hwc.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "013ee1403ffd53279ce5127f4a474474770551fe8a00262f70092bf627814ae5",
+ "chksum_sha256": "91ca186270b48b99dc3929d40b1e1dfe870344d757058f4219c9ccac05e71605",
"format": 1
},
{
"name": "plugins/doc_fragments/ibm_storage.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "68e232bf4207388f31008ecf453dbfc70ccc82701b3306f380b775bbab300b20",
+ "chksum_sha256": "125240a80d3fc5d59eec6549ea19ef22ee2722b5487f10e1785ae6474c9f8b16",
"format": 1
},
{
"name": "plugins/doc_fragments/influxdb.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "99f5ebfe593b8be6485f933769c54bfcfdf10824ad5d9e38178445057dc888a9",
+ "chksum_sha256": "dfa1e3ed1befae606e7d689633df3138e54fccbd950af8ff00b1445692c116e8",
"format": 1
},
{
"name": "plugins/doc_fragments/ipa.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e8f22086deb02c7ecf6905ba2c243e8bf2ae24d8c41d7322ac05d5634266bb3a",
+ "chksum_sha256": "88ff9545e0f4b8c4df8a0e14e7c145850752d3007ca68155bd35933b7ea53a86",
"format": 1
},
{
"name": "plugins/doc_fragments/keycloak.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b12e8398192f11de889fab0c344262ced06b7c95af284d02dd29f891d7c9309e",
+ "chksum_sha256": "b58659a0a78297208a8fefa4a1ada0b6880690bb066277cf8c34c50892e7dc1b",
"format": 1
},
{
"name": "plugins/doc_fragments/ldap.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f5b243ba89e49d3f4763a0a5115324e2fa8846753ae497848ccfd8300b03c0a4",
+ "chksum_sha256": "fbcac214c7ae1f917741aa19d4073d890ea7c834184feda374112b9ddd0c6920",
"format": 1
},
{
"name": "plugins/doc_fragments/lxca_common.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2dfb9df82cd901f3235da2432c1cda249d17a29ac8ced7fc53224680fc983800",
+ "chksum_sha256": "c99e43ef9b9ccfd8dbb57a0ff4f86e2781baab5560e228ba83a0cf728f234c61",
"format": 1
},
{
"name": "plugins/doc_fragments/manageiq.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4512fd57646adf145c618184b04e1747bf53e88acf2661c54419bc5877b091e7",
+ "chksum_sha256": "d5828b70c2919ba828a5cb8f94cff6120c38fa5cab0aeed6ddf763105af150c0",
"format": 1
},
{
"name": "plugins/doc_fragments/nomad.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2143922b22f3c4f2e8a8204ad8d8f0300fbb0a7a92f6efa4c4bd02c32a54b8c4",
+ "chksum_sha256": "fa0efaba97912259532368f22503318036928d0431757991336a26f1be20f7d2",
+ "format": 1
+ },
+ {
+ "name": "plugins/doc_fragments/onepassword.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6a8721cbc2bd32c6256f9f38ab7e78d487e08e7a0cc26aed4d315de304df9319",
"format": 1
},
{
"name": "plugins/doc_fragments/oneview.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cdcf470d5783d31e0afb6a735796a1017d3a8a21810857c0efd47ed2ecde7d1d",
+ "chksum_sha256": "c0347a4273d4c7bed7fd4c6eaa8a7f8c0d85b8f7368617672324468700286775",
"format": 1
},
{
"name": "plugins/doc_fragments/online.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5e838b205f84db6fb238cb5018e7e4a3b0f46953f6163e5a56e0779a74414f24",
+ "chksum_sha256": "088ef731102246a8d3ddad8322f16f4395c79df9b7073ed04da1310d2cae5052",
"format": 1
},
{
"name": "plugins/doc_fragments/opennebula.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "854ecc9b2169728ec65f56cb00f12996b715fc05cea520343b1df1951c2de778",
+ "chksum_sha256": "79a8cf51b8614836c7ffda245557317649bac538f327b0147a3bd37535ba50a8",
"format": 1
},
{
"name": "plugins/doc_fragments/openswitch.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a339c27247063dcc6678caf5051bb451fceffe23dd1da903963cb2fadf7b93fb",
+ "chksum_sha256": "3a5e89a592bb928a19bbce13f0c271e4ed5bd5f7045640ef806c561d17d23824",
"format": 1
},
{
"name": "plugins/doc_fragments/oracle.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2b2ec0d6017534a8da4559b983b61cfc305d65d6e1cb6e1be90274da362e731e",
+ "chksum_sha256": "bf75493dff0153142a07da75760719031333ccc079ae516ae4c6bada74c47878",
"format": 1
},
{
"name": "plugins/doc_fragments/oracle_creatable_resource.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "08b2ceae7cb7f166b9cd2bbefbc9994a4e00c88b13ca582e3ba84774340a3ccd",
+ "chksum_sha256": "dca1e21284741818ce7a10d73a0112c689bf8cda7029ea13079ffc7c0b460128",
"format": 1
},
{
"name": "plugins/doc_fragments/oracle_display_name_option.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "64260dad472862657ee961f79b7453be448ca3fa072cb5ad65a267f9dfe67ed7",
+ "chksum_sha256": "e8e7893197b3b76e5e361f334a5bad0c6ec44f9bdd0c8f6523db8077e4cebc2b",
"format": 1
},
{
"name": "plugins/doc_fragments/oracle_name_option.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2ad3676e31d808a1f6541f72763eda59ac5272ce5b1ccf5af2d8ad149f7f5907",
+ "chksum_sha256": "a3a6e93d00f37cd6a3368fbfb19f0f1d7d306894074248e611dbd8349cc2e93b",
"format": 1
},
{
@@ -1327,42 +1411,42 @@
"name": "plugins/doc_fragments/oracle_wait_options.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ab3ccc72af0335441b655e7d6c446854f59ace02fe70458c541375f8743a0c1a",
+ "chksum_sha256": "25f1dbc3f4f213c834484e8c214c1cd5d3d655b3972c4a4816dc23b7643744ed",
"format": 1
},
{
"name": "plugins/doc_fragments/pritunl.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "44037c8b801ec8d86fabde64045c8875acdbf86ec081b4308d443e09a3ccab87",
+ "chksum_sha256": "8e9c062b09f8645dc023774e10be57e07f1e02b0e31b8756d622779da2860ff1",
"format": 1
},
{
"name": "plugins/doc_fragments/proxmox.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9be758169d594fee836b038599c65b7979c455de3eb28d99bf064085d27be1ad",
+ "chksum_sha256": "37b7c45f450b785105492a38def5db93c9f37b75b00a0c0bc3c0cc6319e8e6bf",
"format": 1
},
{
"name": "plugins/doc_fragments/purestorage.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "82da8765cc1b51d71cb49699ed3deb5ed98f6e14a82a580999916899a5cd6b91",
+ "chksum_sha256": "0a9c88f37bb4e0ec64f4706ddc02f677480951abd0a9c270ed57520ab3f74335",
"format": 1
},
{
"name": "plugins/doc_fragments/rackspace.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "10624f5ce57c7423c959db433f9513a7db8c5e1893582bff54e6b0e3f78c348b",
+ "chksum_sha256": "cfca4c2528ec42c0f1c6ae9a67f6f4f76887dbbd44db5f5f1688ee49be5bdbe0",
"format": 1
},
{
"name": "plugins/doc_fragments/redis.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8e5a692f155845c4ac614351bbb146c96cf93f7e2de47f72943d1a1231294885",
+ "chksum_sha256": "0ee667065148da84c3852945c5f154d10264aa7b218ec725df43861715951a51",
"format": 1
},
{
@@ -1376,7 +1460,7 @@
"name": "plugins/doc_fragments/scaleway.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "536c5415d4d73a8e11b74e1a40068266d149333ecb8e0d297cccb66ba4120f30",
+ "chksum_sha256": "4f8c67a98a36214708b161c17394f671668c1118a6a40eee62c66e4994af073a",
"format": 1
},
{
@@ -1390,21 +1474,21 @@
"name": "plugins/doc_fragments/utm.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "40510c5612b11da5dc3bcb3c2b109857cd9d897c2ea5ae6ba8850292e30f4857",
+ "chksum_sha256": "976c8c5c962a66778d7af52c3ea17bdd3660327b78fa2e792086ec6133a3067f",
"format": 1
},
{
"name": "plugins/doc_fragments/vexata.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c7deb6fcfa73cb0e95d2ad54b17cd3c49f34d34b1290f195a309a3b973b2c9da",
+ "chksum_sha256": "e3ffc032b5533575147ea922cebe43e36f8da8b5d72c0ee17296c66a3faf48d8",
"format": 1
},
{
"name": "plugins/doc_fragments/xenserver.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "32f95a4762fc04041dc5f84abc1813b734add74f36dea833a31a2fd827877511",
+ "chksum_sha256": "a86be649d58013b3eefc7391f77e3c4e29c1c98b193561a95cbb49b9e3144538",
"format": 1
},
{
@@ -1446,7 +1530,14 @@
"name": "plugins/filter/from_csv.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8d7f66858c792e8f5d0b53987aad8d14252baa528b01779e3a8875f295aeebf4",
+ "chksum_sha256": "ac7a7798b2c9cea258f5a59b8e80dc9b0f9eea811393dfa0e760db8c670179fd",
+ "format": 1
+ },
+ {
+ "name": "plugins/filter/from_ini.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "aa388a5cdd894e1c3d1e66580dbd2947abc2a60b8a30b05fee1a5fb8bb8cc642",
"format": 1
},
{
@@ -1481,7 +1572,7 @@
"name": "plugins/filter/jc.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "76ae5c88d50a2333f2758be438cfcd4c4b9a1e91076df4c48edeed101932cbf3",
+ "chksum_sha256": "48d32c91e676999459560646027ac3002b7259353fb65dcfbacae951f0e8b19c",
"format": 1
},
{
@@ -1492,10 +1583,45 @@
"format": 1
},
{
+ "name": "plugins/filter/lists.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "564b7cabed78c74d48379ee8abb4232833ba4876c2952297b14cddc0930877bb",
+ "format": 1
+ },
+ {
+ "name": "plugins/filter/lists_difference.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "00ac85de38a8ef6ab75722f025667beb2324d2962a8a7f4323ed00fc1606dce9",
+ "format": 1
+ },
+ {
+ "name": "plugins/filter/lists_intersect.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "7b0fd37bfb4096c42bcef42ad7d4dbf01d8a8eb1733952c60de64da92255eefd",
+ "format": 1
+ },
+ {
"name": "plugins/filter/lists_mergeby.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "63b1474490930ed608cf35dea2a4e73fa4c80c640c346abae9b82c525b33f932",
+ "chksum_sha256": "4163df17512c4388bf020417cdd3f9919db9c6f1c23b2a57852bd10523a0abbe",
+ "format": 1
+ },
+ {
+ "name": "plugins/filter/lists_symmetric_difference.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "2b064bc49e8ad1f2fb8152b06362c6228c6db493e4f141e6d6a3ced6bfadae43",
+ "format": 1
+ },
+ {
+ "name": "plugins/filter/lists_union.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e51e23e662bc871f8f2f79a7eac15bb1c21ca11e00ab7a20ecb71ef4a7e40dd2",
"format": 1
},
{
@@ -1516,63 +1642,70 @@
"name": "plugins/filter/to_days.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d23445f7ad0ca22323568af7e75818b386dd3e0e81adc86b72045f48e3551600",
+ "chksum_sha256": "e9d41efc784e3ef852c0f5c7ef44949c1d0afd4a3a922d7b1e21ee25f17576b2",
"format": 1
},
{
"name": "plugins/filter/to_hours.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "29f218b85c66ccde6b6f422ae9eda6b4dd6c4f732ac6eac11673942135a852bf",
+ "chksum_sha256": "b4af30e3d234deade9f214501eec8bc0cd2cc6e375deab29f684f5f8932afe9f",
+ "format": 1
+ },
+ {
+ "name": "plugins/filter/to_ini.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "d1012ffb9f4d8626c948dc52bf36a4c42287e1deaf65eca1ecf954170d61fdc0",
"format": 1
},
{
"name": "plugins/filter/to_milliseconds.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a2b674758da200d530e4c7a57883d35b0d47216cf7693d7f29d44c84365b18a0",
+ "chksum_sha256": "c937ba86ce4f062cacb06f7fa1b8ede66750c6b39b3759ebd0d1af78670d2f32",
"format": 1
},
{
"name": "plugins/filter/to_minutes.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "29f4c579100170a46b7a177f923d48175557da42d51c4105451bf1761c041453",
+ "chksum_sha256": "a8fba82f4e4694a0834da995e94ee80ec334932d710f0e2d635b63bf0bb5b0bf",
"format": 1
},
{
"name": "plugins/filter/to_months.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "797dd5c490aa4ddf565b48c4ec4f7719704a94a1c7bd56fb6776d1470affe15c",
+ "chksum_sha256": "50a81390b0dfe9dd18ecc7bc7b98e1e4c0c71b411048853002d3bb2d07e6c0ea",
"format": 1
},
{
"name": "plugins/filter/to_seconds.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5a5587aa9f512aa4e408a4f4a13b949e25d4fbdc794d57e497557a20fcf2013b",
+ "chksum_sha256": "77cf3d8f7e35edef479c65af4b5c14a797be8d78c5abb9a74402005a26e8b780",
"format": 1
},
{
"name": "plugins/filter/to_time_unit.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9e126e417a274e75816c69275917b806a1c259aaa058cc84518a96a4c2084508",
+ "chksum_sha256": "18d09d11d3414ee06a6574893cde91d5f6ef1ea4ba3ff32e2474d138272cd9dc",
"format": 1
},
{
"name": "plugins/filter/to_weeks.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "04463eb7201b7e414cf32bc3c7d57b656ddac61eb46a631efe1f7d36a189b534",
+ "chksum_sha256": "e3ecf563747db2ae2c8326dbfd0fa78ba17411a8830f2be64a27fae521424a41",
"format": 1
},
{
"name": "plugins/filter/to_years.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5326aea9bd9fef4c5c06bcd4ac5ec2e36f5556c4e2bf83fa4e8535049e0255bb",
+ "chksum_sha256": "57af52768feb05e97694effcb0da2d6fff564d359150c3875150cd8562db7b0f",
"format": 1
},
{
@@ -1600,91 +1733,91 @@
"name": "plugins/inventory/cobbler.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2884871f47b923590017afbfe7677511d9692a41fc11f28285b9ef5178d8a391",
+ "chksum_sha256": "2a6cd6114bae928361af7ec60e99a4e85f9ed3b437c943bc60e23f4c21401c64",
"format": 1
},
{
"name": "plugins/inventory/gitlab_runners.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3e7b3bb1505bb24603c85b55ce42dc4176e3a59aab301746e36229b8f38051f1",
+ "chksum_sha256": "1fd2de379dbf83ba5fddafeb3fecb693ef5d35157ef5a8f0e9718d984ca4b9f4",
"format": 1
},
{
"name": "plugins/inventory/icinga2.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ac38a22836ded8fa733b0a9dda9ed63d67a63a603e7dba6764b3ca7df09cb7f4",
+ "chksum_sha256": "f9bdc281508bc222fd6e1f19c34575cd9dc5056ca3ca1d7a8f4481de1d24cf27",
"format": 1
},
{
"name": "plugins/inventory/linode.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c9f29484c6ca0940b25e9192a1f1adb2e63970ac5305d97225963f582475bfdf",
+ "chksum_sha256": "d2375902a364f0c8b8cc9d6f88512be7b4371d6dbfcda4e5707df404b5336ae2",
"format": 1
},
{
"name": "plugins/inventory/lxd.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1e5a52c6e31d407fdbd5127a86642c386e49ffe16a87bd923cab8da60d50ec1e",
+ "chksum_sha256": "6f501b691589f29ad2cf5954d98e2576e2944f88f9d23d74cece0f0850c77888",
"format": 1
},
{
"name": "plugins/inventory/nmap.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fb2f448c78fe0186248baaeef41f3fbdb57d648eda3c0ed5a2e5cfde482e306a",
+ "chksum_sha256": "76f3c42cba7bb30fa841ba9193a71c9ce857303c9d83d9d8d1ff04dfc4f1c726",
"format": 1
},
{
"name": "plugins/inventory/online.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5eb0fb5a8a0aee54a1198e84ff550f9d70a962b4a9f30643d08f5779c1578696",
+ "chksum_sha256": "533c5edf6b17e4b25628aad13fc5d7aba7c9ea1ae86e12d091c50aef12a8f775",
"format": 1
},
{
"name": "plugins/inventory/opennebula.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "08654f9aa131acaa382b0aed38a44b641f993effc3c3f50c38fc2d13b77802b3",
+ "chksum_sha256": "76f28fa3696a031e014d66ea1617fb5d98319dc6809dac3218f7a4d800ceff45",
"format": 1
},
{
"name": "plugins/inventory/proxmox.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7757c5e263bfd80d0fa3d8356fb1658d09f2030649a5332bf553a579fdfbcf90",
+ "chksum_sha256": "01313ffb0af966b9a4e2b6f95c1497359a98ae5847be4b9c324aae3c5e412f9c",
"format": 1
},
{
"name": "plugins/inventory/scaleway.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "87dbfcb3b4239cd3a2cf7718e3caab553def93060065970f39aa070fa988f254",
+ "chksum_sha256": "5663c4b332dda4720df71285671ef999c8eaa3e4e3335bca1e8e376e65585c46",
"format": 1
},
{
"name": "plugins/inventory/stackpath_compute.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9ccbe9c76dd2114c837bd6a3c504620619633ddf47a6699ea380ee33e2fc755a",
+ "chksum_sha256": "38003a1f85c8781d73ae5352d461c87c5a66db67810aa3113d5f15b1e07d3e06",
"format": 1
},
{
"name": "plugins/inventory/virtualbox.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b220b977c1442ca3a654614ce57e7754d9795630bf75a5dde4496c2913f2f40b",
+ "chksum_sha256": "0547e7940ec2940cb9ef4bd07b321b45a458792e6b2d572c2abceb72c4e78d26",
"format": 1
},
{
"name": "plugins/inventory/xen_orchestra.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "dbd0fa9d5b07b04f5f962c614c6459e5aebbbfa0a57f60f67dc9d843092f3b85",
+ "chksum_sha256": "d9b079b0215b6775490192fffae78fe46f088675348ae4129d7825aeda59bb0a",
"format": 1
},
{
@@ -1698,7 +1831,14 @@
"name": "plugins/lookup/bitwarden.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "522634e07df8ad975f3250ea21b207b9bd5eaa73da6850f8ad2ca00f6b0ece62",
+ "chksum_sha256": "5f0e069d8c299d2bb3087726049d7df8d03a4e545ba3d8df9fd429ed6767125d",
+ "format": 1
+ },
+ {
+ "name": "plugins/lookup/bitwarden_secrets_manager.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "5453a43746aad1262ded5a08d8ebad62f32f26ca22d1dd873320b3ba042345b3",
"format": 1
},
{
@@ -1719,14 +1859,14 @@
"name": "plugins/lookup/collection_version.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6b5a1ed7cc5304e6d0bd83354961571d808950a4fa29dbd4decca7df8d935776",
+ "chksum_sha256": "1d740effc5f1eeea24df09718201aa5ef43158a4a84044f64bf3e624e888de08",
"format": 1
},
{
"name": "plugins/lookup/consul_kv.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "08d9c175275635d7d51e3e5f060e2f0b0ec048dae84e2f9bc1b478002011cbc7",
+ "chksum_sha256": "4850b487746669f9555bb29a7b801ba99ff89fa0538a4fcaf083784b7b019a66",
"format": 1
},
{
@@ -1747,56 +1887,63 @@
"name": "plugins/lookup/dependent.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4d1c12d9e1687687c109175c8d8c2ce17947dfd4b632d813b2216ac43731e336",
+ "chksum_sha256": "a0666d75cfe762536614e943e90e2f6a77ac83f3daea54dae2fbed391de19d43",
"format": 1
},
{
"name": "plugins/lookup/dig.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "17a45ded85474b0db603aa78f2140375da36edaffd71c516e9c6a5cb3e800f1a",
+ "chksum_sha256": "d3e049d4c5a65d2e0ce02b21b84a668160536efe1ee64567156afb1444aa1c31",
"format": 1
},
{
"name": "plugins/lookup/dnstxt.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b6f60f231e06b1777eebc014d2759c2116ecdfee7fd8b65599b34e5a8d5b0fd5",
+ "chksum_sha256": "4a34dc55dc842b4222ce7a9d0de447a062b07ff96bdf9fbdf8840d6dd5731b56",
"format": 1
},
{
"name": "plugins/lookup/dsv.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8bc846802cbdd881f4ff48bdbd67d9dc534c56e4985ac8ded3e0b953cd999a76",
+ "chksum_sha256": "7c8df171cc7093c23c94b8011b484880cbfd3cff29c3155eaf975cc80c47cf73",
"format": 1
},
{
"name": "plugins/lookup/etcd.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ad620642d507aada986b475aa40d3aef112de77327a4861563d038ad9e8539be",
+ "chksum_sha256": "65c349c2c3b66cef5446f14fb4779aa4d79fda970844c20e5666655eb866f00e",
"format": 1
},
{
"name": "plugins/lookup/etcd3.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "52e06d25c01f3074ae330aba6a91446640fef7b2a8dacfaf7780830b2928e1cc",
+ "chksum_sha256": "bfde73af5bb093b7ce03a7cc717ea0f804f4da09623b4dff8ea63840ccbc7cd9",
"format": 1
},
{
"name": "plugins/lookup/filetree.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9e93f4a8a98de008d123400187a2ea2ce1fbd6bd2e5847c4b11d955e9b5e509c",
+ "chksum_sha256": "a8ba35eb207f2f1e66ce30e120668e0be03fadd640c30a0bb2041323542adfcd",
"format": 1
},
{
"name": "plugins/lookup/flattened.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8b668474a4d77fd40a59af01f3d6eb778080b674a20de20fb4725162d6da32ad",
+ "chksum_sha256": "b0daa8c67615407743e64682423341c6ef309319558193285ac3a8b568ffbd82",
+ "format": 1
+ },
+ {
+ "name": "plugins/lookup/github_app_access_token.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9b3fcf43f0ab1a810a11df36b61b328c42eb60c82c7af02cabc9ad5f3ee537d3",
"format": 1
},
{
@@ -1824,7 +1971,7 @@
"name": "plugins/lookup/lmdb_kv.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e3c22e4bb9041b8bd79d520f7d80e3429b26494f6884b71dcbee86711b9ec041",
+ "chksum_sha256": "0da4b230dd098b3e2f3490970be3306edfcf3ea614e5af83c47256f10012f452",
"format": 1
},
{
@@ -1838,28 +1985,35 @@
"name": "plugins/lookup/merge_variables.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5a7e1f8bb4cc16ab1b7a545847fb9f62eb25387e4681734ea5136ead9c5f8ac6",
+ "chksum_sha256": "ad758294be13db2a7cf07d9fae8fb187e87f0875360d5c61d909f99d18f707f9",
"format": 1
},
{
"name": "plugins/lookup/onepassword.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "12df22f733a259022dfe8bf439a3938d85d7d69d3b69dec770aa6e46a10d4a3d",
+ "chksum_sha256": "ad55ddf9826b97b591d44f11938ce889946abb29e6f3fbb5e430e5752066b0bd",
+ "format": 1
+ },
+ {
+ "name": "plugins/lookup/onepassword_doc.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "19159deb0cc1309c19351086e54bd4f90ad79a1340a26e18c6a52e66a848bb88",
"format": 1
},
{
"name": "plugins/lookup/onepassword_raw.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0997a0491899015d8d7fe4c3bc9de5f345b579de0c2c258cf50b358b42cf2fb0",
+ "chksum_sha256": "67372f4405c81aca4af6b241b142f1a497ebbb9d235741fad8136229761bc169",
"format": 1
},
{
"name": "plugins/lookup/passwordstore.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0fac37c01614ecfbde5ef49a93bcfe1218d4b4c010fee52cad93b41af8feffa9",
+ "chksum_sha256": "bf39d1661bdd94a94996a594cb00c55adc3bfa44e0041cf9c859f4125442565e",
"format": 1
},
{
@@ -1873,7 +2027,7 @@
"name": "plugins/lookup/random_string.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f81b451b1fbb8d49076bb90d8b40ceaa5200efa7845f1ea43464e56a6de1f3b2",
+ "chksum_sha256": "a2252a0072d729d53c0f2ee626465f82b7350846ce67ca4d44995671d0ecdb07",
"format": 1
},
{
@@ -1894,7 +2048,7 @@
"name": "plugins/lookup/revbitspss.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a486e0540059abfacbc0da7ad6d351e9758d7f53c6e94258f58cdafd5aff3b57",
+ "chksum_sha256": "d5481771804b647b21974c99d5806714a0ea6f15369703669844053f14a187f5",
"format": 1
},
{
@@ -1908,7 +2062,7 @@
"name": "plugins/lookup/tss.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e0ccc8d25f17ce7d8e8eedddad9c9d1343f26915f3e81a6b8ddbfbd45b6d0a6f",
+ "chksum_sha256": "15155cba511e6ae4f6d8f8cca26ea908d401064da18efbdddadc0fb4d836491b",
"format": 1
},
{
@@ -1936,7 +2090,7 @@
"name": "plugins/module_utils/identity/keycloak/keycloak.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "04d2f740ababea369bb587d1415ccd9a21b3886a485ba4668ee24d80e3ec3180",
+ "chksum_sha256": "b3f1080b3b46444e8eebd03321d1bba8a599b845b8d8bbc846ae2225ee2a33fe",
"format": 1
},
{
@@ -1961,13 +2115,6 @@
"format": 1
},
{
- "name": "plugins/module_utils/mh/mixins/cmd.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "27ea6b91f5fd744b8b1f7b035ae92c6d83dab8ab021dc95c519cf4c8d4c937e6",
- "format": 1
- },
- {
"name": "plugins/module_utils/mh/mixins/deprecate_attrs.py",
"ftype": "file",
"chksum_type": "sha256",
@@ -1978,7 +2125,7 @@
"name": "plugins/module_utils/mh/mixins/deps.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "572dd83d013ea9eca0762f8e0aaf92343b25bce6a867639102975015e5fe397e",
+ "chksum_sha256": "3aaf0f3bee07c87b4e9108cb474bcb96b715bbad0e77f578987d71ce7fe8dbdf",
"format": 1
},
{
@@ -1992,7 +2139,7 @@
"name": "plugins/module_utils/mh/mixins/vars.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "42321b2e74cdc6f133f06d2f3da04e7e1960abb99db89aa7115edaca45093ad5",
+ "chksum_sha256": "a34c555587e819fa58b076b872b7d7ae05e129818a98b259ead8c4f1a2fbc733",
"format": 1
},
{
@@ -2020,7 +2167,7 @@
"name": "plugins/module_utils/mh/module_helper.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "66325ed2b8f7656c0251e9b5c25b63f2f1c3600359bbe05cae1326cb5e9f4129",
+ "chksum_sha256": "f5070037ffb959097becab8baac019d21ee6fbb305f46f687977500fbcd5fa5f",
"format": 1
},
{
@@ -2041,7 +2188,7 @@
"name": "plugins/module_utils/net_tools/pritunl/api.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "276c8f9eac2319776a57a3e46d215467467b9b5f051b448696d07f9dfc322a12",
+ "chksum_sha256": "7152edad51e8f5abad1f98f00bc5e1005be7756e1bd1b86a3a39f5cdbd2fdfb1",
"format": 1
},
{
@@ -2055,7 +2202,7 @@
"name": "plugins/module_utils/oracle/oci_utils.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "98cb44c4b774079019929180f2edd90024f851efcd9c3a7bfdedf6f990af0974",
+ "chksum_sha256": "a4be8160601f53b3520d63dc70a852c3395c3a31e4e9d8f22046e8d9e4285afb",
"format": 1
},
{
@@ -2174,7 +2321,14 @@
"name": "plugins/module_utils/cmd_runner.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e1c38eda36d3d59456d730777b0fd54e443bc18b7f9f69adab9bc455d5ed94f7",
+ "chksum_sha256": "62306950ca87a1a83c8e7bb6e3072609181175687ac02e4ad30de2481112b5e4",
+ "format": 1
+ },
+ {
+ "name": "plugins/module_utils/consul.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9e572ae8233e2f4a72bbdaba9d39f0e0d631ff4ccb3684a32f853d0b7b6581bd",
"format": 1
},
{
@@ -2202,7 +2356,7 @@
"name": "plugins/module_utils/dimensiondata.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b7929553d9eeecb50d26984c90a105d491aa8a32d945eeb0f8b0ada1b340f21f",
+ "chksum_sha256": "b556a6bf6166c9044197ba7d2fd8bd78a30f9b52ea40a1327626810028d100ff",
"format": 1
},
{
@@ -2220,10 +2374,17 @@
"format": 1
},
{
+ "name": "plugins/module_utils/gio_mime.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "4cf1fd084311a0c06d81c72cc424fa4d10a76c85aadb459f4ad9e5ac34ca0309",
+ "format": 1
+ },
+ {
"name": "plugins/module_utils/gitlab.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c3e3fcf55708a48775b5834aeb414df8691b83de920b3acb6d112d88fd725b30",
+ "chksum_sha256": "11504e0b1cc93424e0ab0c496737eb412537558268624b36ab7860ca0a89e6ec",
"format": 1
},
{
@@ -2237,7 +2398,7 @@
"name": "plugins/module_utils/hwc_utils.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c06bb56716060cb481004f3a78d9debbb8c593de003958041c38913c8f78d52e",
+ "chksum_sha256": "902d6f842f07d568a019ccf99123aa23cceecc60527b839678b38246331e9e0b",
"format": 1
},
{
@@ -2286,7 +2447,7 @@
"name": "plugins/module_utils/ldap.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "882bd750b5018f04ec17023d2bdd8d5a0c9484cff87f457fc47e2a628868decd",
+ "chksum_sha256": "d0f34a3cc0472876585d6fb72e1b56b1e2584788e20c0b17cf8f8b03da6f8694",
"format": 1
},
{
@@ -2297,10 +2458,17 @@
"format": 1
},
{
+ "name": "plugins/module_utils/locale_gen.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6064b7e307cb9e5f0808bc20fdc153c286f08372051844adb208dce2efce8942",
+ "format": 1
+ },
+ {
"name": "plugins/module_utils/lxd.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b29b900addc911e4c600d06da6bbdfc5ed72e360b67fb6fcfcbe69c3e3ff1f21",
+ "chksum_sha256": "41a8e13e308e969a72aa9d23c19300bc572c13e6bd2a4fdfdfc9a2c29cbd669b",
"format": 1
},
{
@@ -2314,21 +2482,21 @@
"name": "plugins/module_utils/memset.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e2c53131d2efd0bc45cce11439cd11a1ee5b49b30882b83c816102c97be8af6a",
+ "chksum_sha256": "95fd5a2e0e92f049e0f700a3ba8cd0eac4d95ccea9e706a106135fa3973716e1",
"format": 1
},
{
"name": "plugins/module_utils/module_helper.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6f9ecf9c995a26bca5600a3de342fd29dab59b81b9cb1ee7277f7421ce8da203",
+ "chksum_sha256": "7eb6f642db5f83ec87a06e04f8d62436a9eec0058cff531cdebf20865c571b09",
"format": 1
},
{
"name": "plugins/module_utils/ocapi_utils.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4dac6655ca02c7b2d48f243e28bfb88156c1cbb6e0b6cd612cf2f2bef93776e6",
+ "chksum_sha256": "25f6257b4d41fd885fc4fb23ba6b3b72e176a5a205c2d44c12c750569ae81bdd",
"format": 1
},
{
@@ -2370,14 +2538,14 @@
"name": "plugins/module_utils/pipx.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e914c49bce660e3768d1a387197339a2e5813c24303b7b67442a52e43c5c2846",
+ "chksum_sha256": "9618c28cab0ed88eb25502e5b649ffc1e170dc510b14b641c34c537910759239",
"format": 1
},
{
"name": "plugins/module_utils/proxmox.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1c6b797f197c68cdd9a14c0a6f492083ca14eeb7798125b7dcd151894181ae4f",
+ "chksum_sha256": "756e2b829ba10cf0f2d177b8729b92007ef23edaf1a708c064b1cbdb9b96b02c",
"format": 1
},
{
@@ -2405,14 +2573,14 @@
"name": "plugins/module_utils/redfish_utils.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bbe905987ac0a4995ecfcb2ef01a8cf3ee644d4d3c03397e3960db3e35800748",
+ "chksum_sha256": "bc9400ba787e5570d9344c685596e7c3e04013ce32215c3874d168f2af57d980",
"format": 1
},
{
"name": "plugins/module_utils/redhat.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a13b858effcfc0989720e95f6cd7ea15b67d6140f9d2273fdddb6b304b4e9731",
+ "chksum_sha256": "43b96c1bce480ed6f9ed9d2a9aafed370295838ed6e5c235e0b7ca3381baf5aa",
"format": 1
},
{
@@ -2426,7 +2594,7 @@
"name": "plugins/module_utils/rundeck.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f013a30db68886db62035238eaa846def1945b9e7f990c90a1884d62dc546d48",
+ "chksum_sha256": "0718e463e10a42f9ded1851f689829e05f101ed42888f1abb5c058a90a52fe7e",
"format": 1
},
{
@@ -2440,7 +2608,14 @@
"name": "plugins/module_utils/scaleway.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "564f346365d0f82d668e173c01919ea3eb3d0080dcb693fb754d19ea704b7f9c",
+ "chksum_sha256": "bf3a6babbac970f45b6c9473704684b0980330f7e8cfc71e45513e9fa22aea35",
+ "format": 1
+ },
+ {
+ "name": "plugins/module_utils/snap.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "7ef6721d37d830b9b2685ef6969a4b3fcfab22145a7ed07cb92f3651509cf05f",
"format": 1
},
{
@@ -2465,10 +2640,17 @@
"format": 1
},
{
+ "name": "plugins/module_utils/vardict.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "d784bdbf44eb700303730e03a0c0082dcdd52c65c076bbdb5088eb79d556c4a2",
+ "format": 1
+ },
+ {
"name": "plugins/module_utils/version.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7af185b9a3367d00933f2e1e72202193d1bfca38ee16ed8d9779b778e9eef3b8",
+ "chksum_sha256": "8d19899c3f0e6ab7729cfe072f91786faffce0d19e35e2dc22c27512be6534f0",
"format": 1
},
{
@@ -2482,7 +2664,7 @@
"name": "plugins/module_utils/wdc_redfish_utils.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6efeb7ca07df481c907d9d462a55fd5e89626301952827a93b962b1c8c332930",
+ "chksum_sha256": "c486a92b8157932ad90abe568c77db7168e69dd0d815708c1831aa31a7cfefb7",
"format": 1
},
{
@@ -2517,77 +2699,77 @@
"name": "plugins/modules/airbrake_deployment.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "61f53ca65da913464b70f15361a8563b23cd449850ddea68acfb7d2ebcff3c43",
+ "chksum_sha256": "a6b2efdae0e89bf04ed10266df68325f36abfeb04a590e15bc48b095a62eed7d",
"format": 1
},
{
"name": "plugins/modules/aix_devices.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "88a79a5752332e5d5e93e4e301a4849ffce3db6289adfa7ef6f1a684a0ebf002",
+ "chksum_sha256": "786cf47cfafe0e66db06fa20d789d6a3e343196a3cf9480e4a56d81427c60ac0",
"format": 1
},
{
"name": "plugins/modules/aix_filesystem.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "13dd76495e56912361966ffc96a3067e8fb0bd70c0343977075765ce59816de7",
+ "chksum_sha256": "76c6c1b52220f8808fd8c2c4a06a9a0e9be8cff0f8abc5336cdc49a5d9ae52f3",
"format": 1
},
{
"name": "plugins/modules/aix_inittab.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d2ea663fea3d28a6779f28c394eef1da5764a6faa1ee036e7150689881a8cbb6",
+ "chksum_sha256": "46341ddb1f15f8ca498ed7cc7cbb655cc5cadf663bd7dc01e9698026cbead288",
"format": 1
},
{
"name": "plugins/modules/aix_lvg.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a43a54688f275a53925b5981f91b857fa4bf3e45451e81d16cc08878a4d8c6fc",
+ "chksum_sha256": "2c1ef75ecb60941acb518d592542b2f00246d87d3f166ea97e986c7fc2a571bf",
"format": 1
},
{
"name": "plugins/modules/aix_lvol.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e95f7b27c11751210397c322a9c80f0b2a39a0e1dc2d5ad380b6ca37342ccb39",
+ "chksum_sha256": "0e9cb99ceb284742b25feb71e5a105881cf8a31d5601e09dc7666106337b5449",
"format": 1
},
{
"name": "plugins/modules/alerta_customer.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d1d6187135a5e3a61ca9058fd5cc14f3bc1394ecc305ba31c741486d0579fbf7",
+ "chksum_sha256": "ca86a841faaf2bb367f88e4036f60aeafec8b6b7a2fb14dfd0632fdecc50442f",
"format": 1
},
{
"name": "plugins/modules/ali_instance.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "64eae2dcbaec70f75b96aa9724f99992b64036437d0094ccd1ab0cd3566b5ca8",
+ "chksum_sha256": "15566005f46be4bb3660d4685016b6774ed8a8158a62414ce4d02ef52ced30ed",
"format": 1
},
{
"name": "plugins/modules/ali_instance_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c7ba3b6cc1c672200ac8376595e39f53d6548b5ae3fa2c41054d5eac26af26df",
+ "chksum_sha256": "6a2b95caae902d74898f50dec80c4e3bf165b73f85b0819710c85dd9d0e21c16",
"format": 1
},
{
"name": "plugins/modules/alternatives.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b7708e5911a5012631d19f2cf676ad40c4096a9bffad399ada3bdb7d809a4215",
+ "chksum_sha256": "836ef884fdcb03e59cb15676c7bfae3ac09765f44c32cbaca68047728715a097",
"format": 1
},
{
"name": "plugins/modules/ansible_galaxy_install.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d2d972de8ec65fee8262adca0ca7cb4da8bf542f61e6ba5ff50385d542c8f505",
+ "chksum_sha256": "b69574b683937c5b7dbc4d541886fb370d8942f0d37c26bfee469456414d8022",
"format": 1
},
{
@@ -2601,63 +2783,63 @@
"name": "plugins/modules/apache2_module.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "53d4683bd5506977fb9b8a0196cc574a0152062a07cb95e637ee0a86826af3e8",
+ "chksum_sha256": "c049eaf8706f7c54499029691c7eb76861aa7f7cdb40c57126a1a02bb96bb4ad",
"format": 1
},
{
"name": "plugins/modules/apk.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b17bc58d0fefe4507ad6a218d6c712dd60e636f124c43e0dab88859074020b8e",
+ "chksum_sha256": "512c350d2b2eec9676a596016dcae4d17782a15ba582e9e761b8ab0963571a0f",
"format": 1
},
{
"name": "plugins/modules/apt_repo.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "45577358980c2d95993c4b1094a1366b2959c0660dce61e94408b032220e8b91",
+ "chksum_sha256": "4d3739da85ea8790dcf8b7ddf118b9e8785d7fef13deb833c079bcbfbc58f305",
"format": 1
},
{
"name": "plugins/modules/apt_rpm.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f1ca27a3d0002f64d8bf10c82cef83c5b400b2968428b3fd51473423e57e69f3",
+ "chksum_sha256": "0b60fc7bf785127673dd9eac1396da1d3cb759efe84e9f30b98530b82e5980c9",
"format": 1
},
{
"name": "plugins/modules/archive.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "48196a0adae35bab8227c076060cdab1b0b8eda419366f9c6e49cb0260d0253a",
+ "chksum_sha256": "01527c28a9b3d4d6c03e9dc6af1ef973d4e833d2f72ec19e287f6d6eaadccc00",
"format": 1
},
{
"name": "plugins/modules/atomic_container.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fd992ec654187c36c759f00e6bece67c76d5699392ac9acf182cb3a5f20c9eac",
+ "chksum_sha256": "53ed913b5deba92cc3decd1e87b2ec3177946313fe75996079a29ad2b2ab9f27",
"format": 1
},
{
"name": "plugins/modules/atomic_host.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a3269a9699e34da942ca8de49deadcc437e660a01333ab601084103fb5ec5519",
+ "chksum_sha256": "175ff5c69e6bbd59f2e21ae52dea644a0d8c285157c4f2df051ac0175e27bc0f",
"format": 1
},
{
"name": "plugins/modules/atomic_image.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6111aefe3a8db057a447d3ed38a113eda43872c51b3628a70e3c1df51ef90e8e",
+ "chksum_sha256": "1c691390295a9625ed8beecc194ac8e504a462b3d1ba97d7b9991f6a4588a061",
"format": 1
},
{
"name": "plugins/modules/awall.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "574ddd2d99728477339198d45323fc88c28dbcac72f71ee4e335becd7cf9243d",
+ "chksum_sha256": "9782e88668c1b50cfad6ebee2c4c322fd0928dc78ae0518d4024dfa37ed427a3",
"format": 1
},
{
@@ -2671,42 +2853,42 @@
"name": "plugins/modules/bearychat.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d35c57bf328848543735956341e5e2a74fd23c1a74e8a9d9f2c4c32edf0c95d5",
+ "chksum_sha256": "046376919e025f8af3c49d1136660f9b89b6201f19ef61dd93de2846a3a72fea",
"format": 1
},
{
"name": "plugins/modules/bigpanda.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d5ee7f8dcedb96c12df9f5302930259dd8f0a790d8c3dbdf9e29ad76cafb253b",
+ "chksum_sha256": "8880a5b9df7aa8870fc2c1bb9873e95fd6e63bc99cd0f9f38cfc8a40099b656d",
"format": 1
},
{
"name": "plugins/modules/bitbucket_access_key.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f3497a9aa116023b2062b1972b32167f8d85cb02457d43ea273e624353a2594f",
+ "chksum_sha256": "31a3dccc81a30bb8b41cbae77a2cf909bc339050bb795c7885b645635a751b83",
"format": 1
},
{
"name": "plugins/modules/bitbucket_pipeline_key_pair.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2f3c984da7de315a9f6d79e0c4ab11d9a580447346e27f1727e185e31b26bf02",
+ "chksum_sha256": "944a830eda81f65f5d92e12c0b517680bd70a5575b5af7164f37027f4dbb71c1",
"format": 1
},
{
"name": "plugins/modules/bitbucket_pipeline_known_host.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7f30db11c9f9350662470bac5b2f6482c03f4c64002c0e6eeae8e4bff65e4db7",
+ "chksum_sha256": "b24021e4bda4dbcb23e3f148fb0d612ff2c50321bbd78be648b5192969d6457e",
"format": 1
},
{
"name": "plugins/modules/bitbucket_pipeline_variable.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c654706e27b80c3f5952c00d518181728ea20aa8d3cf698ba06d22d78280db50",
+ "chksum_sha256": "ca50295af785900fc2257f2ae323e1c6750aae5464815addbe75e9d51d1c34b1",
"format": 1
},
{
@@ -2727,21 +2909,21 @@
"name": "plugins/modules/btrfs_subvolume.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c3988751919cc17180c909332e2dfca5adc78926c7eb5daf870ea7234b30210f",
+ "chksum_sha256": "ef8b5869c7b17e906409346ace86ccba1686bccea5f4f7ae90c7d40744b9fcce",
"format": 1
},
{
"name": "plugins/modules/bundler.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0a58a121c02fb4eefd237f48700275152c3b562821fc20828ff81838956964a5",
+ "chksum_sha256": "ec8245996530f653100b66fea893ef08bf42a90c14ab39cc3caa7d4b33f2ba66",
"format": 1
},
{
"name": "plugins/modules/bzr.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "55c6cf5c096655df5a7067809846a1ea005cf355cd22bb624b204f16c2f04ae4",
+ "chksum_sha256": "b86ce66fa82e1dfc208ed1ff6b1ac1dcbaf0e656741e232c59a6191d7923eb00",
"format": 1
},
{
@@ -2755,35 +2937,35 @@
"name": "plugins/modules/capabilities.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9e228b2a53ec1fe0c9f3dd4a483661cf32ecd00d29f8a5d21c7a9eaebafa5384",
+ "chksum_sha256": "175ecad770dc8a9c523c402179e6bc728d863a26459b5d2771cc359abc241350",
"format": 1
},
{
"name": "plugins/modules/cargo.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "18613d41168fcdb4dcb40b5058fd3965c886237cb094e81e457d5618fcbeaf59",
+ "chksum_sha256": "1f937d2d6b2eb1d54baaaddc8aad6e45ff219c1762ea07d73e028b1030b47601",
"format": 1
},
{
"name": "plugins/modules/catapult.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7b4258db56a0db7d27f8a433c9706164070b283bbfe5278bcfb677040e4f983c",
+ "chksum_sha256": "312d890f7b5797017da4a6f4d73a241f906582c12153bdeef67489676ae8edf2",
"format": 1
},
{
"name": "plugins/modules/circonus_annotation.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "070337dcd572ade38abb7f14b8f85d17ba2e6d27fd002c2d075fd071e827a0b3",
+ "chksum_sha256": "6b29120476e189b86b4fff5785f4c3c062b7d4f54b90c8b54dc60ef85030a199",
"format": 1
},
{
"name": "plugins/modules/cisco_webex.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6a9d8d7cc1a241e3e90f4ae44df576f27d77373aa6cf0a924aa48ab69ede585e",
+ "chksum_sha256": "ea743711b3f98582e61ad04121ba3a2cf21e050f46524a930e071284be15b74b",
"format": 1
},
{
@@ -2811,7 +2993,7 @@
"name": "plugins/modules/clc_firewall_policy.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "89d8aa1996b14e4326480ae02c1f4ce6a9a19748a48e8a0377cdeac2fa9595a2",
+ "chksum_sha256": "918e93155d81f37b4e81243d3b3a5c682329d6075735442bbd18995fe4da06a9",
"format": 1
},
{
@@ -2846,7 +3028,7 @@
"name": "plugins/modules/clc_server.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f71e092472a711dae840a74e28f2c4bd0fdb5a386cdbda75b31c02aa8542f7df",
+ "chksum_sha256": "be462ca0d4c5f0854a980699dc92b3442e7315529016a9fb50132c21595ec315",
"format": 1
},
{
@@ -2867,273 +3049,329 @@
"name": "plugins/modules/cloudflare_dns.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e21f7a548347aaa20c7a15ee21e87b9cd8aad634530bfa7158f1b00499a565c7",
+ "chksum_sha256": "bfe75b2d6815280e55121b0958c219cca514b7d2498ad38b0bafd1ff3581dde1",
"format": 1
},
{
"name": "plugins/modules/cobbler_sync.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0171f8da37611ebd0d09a66fdce9f2553340bf95c25e88fba7afb5175afd1ba5",
+ "chksum_sha256": "69bc8b3cd61a7d22073eaa6944e645ffd8133c7ed858b5cd130fc343d074b5ea",
"format": 1
},
{
"name": "plugins/modules/cobbler_system.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2d0e6981589cfac4f95f42f88d22981b5a229e1f576bf75c0d75be61288294ab",
+ "chksum_sha256": "de819b4c8494a9aa92e04609c29027c3357fc682aa4903f4fc3569289b088b02",
"format": 1
},
{
"name": "plugins/modules/composer.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fe4774f6714cbe5664372016499b92f12ca67a7c46ff0577f9fd5746acfed2b5",
+ "chksum_sha256": "631da3b0d7d1037b95b47a6899621fa05593e2616136abb54054d91020680fd4",
"format": 1
},
{
"name": "plugins/modules/consul.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1ad813c447c762bab9336caff71d652d2edb97ca70eb8ce2af221d332b32b8a6",
+ "chksum_sha256": "1cba4baf81e01fb05904d685495ac54f09aa1eba315eb61ac24898555065b5af",
"format": 1
},
{
"name": "plugins/modules/consul_acl.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bdda1625ec66ff4f70263e2736357b0146928d70e2e8a4a21d24a672aecb4d02",
+ "chksum_sha256": "8fa3f0aaf7ac1501d0271fcca278e51da9e0ef13c3d2496e13de4f6f95119e25",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/consul_acl_bootstrap.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "42e71e5603a3680a7e9af0b8df5f6597830070c7cd6f7335bbc239daa6a059d9",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/consul_auth_method.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "776c407945f239f40ea36e24f42606d20141316ffa7f36e95cb3f00efa4c6bcb",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/consul_binding_rule.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "bfc78b6b53d3ad705f099e2ed04eaff75ab0d1ef3d823b3de58d6881efe2178d",
"format": 1
},
{
"name": "plugins/modules/consul_kv.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5ca07e607fbd91d804f06a4253d7dd521a185297fc6dba146fe90592cd77a323",
+ "chksum_sha256": "633687d6e2e1895c6535f9410273ae7ed0ac86a9b426b2b001a3875c48e3ad29",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/consul_policy.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9fde6fe3a216b54e45b2946d83bb3d377ad73c094ef0f11ae374b240272b36b2",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/consul_role.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c4f9290e7af434c6f9431da4ebae95a5acf1857fcffe99340737e2748f3ebde2",
"format": 1
},
{
"name": "plugins/modules/consul_session.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "898216ffb17e046caee1a8b76919f23e621301153791a4e7f0f42f79ec1d82ed",
+ "chksum_sha256": "bf47bd1c93f8b046b6b744eae2972a221f74b4c3ff79c3c9557c243ab1de8ce3",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/consul_token.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "209599b1c6016b6758413d349c547b3483d6adee030c39824e3fbb23753fdf20",
"format": 1
},
{
"name": "plugins/modules/copr.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cc410451fa7014851722b0a561d86135d8994f73c4703d1253053af09d7afa08",
+ "chksum_sha256": "9d0a2861819ddaaa3420c0177df5b6713aa3c8bb1c517135719744a23783cc0f",
"format": 1
},
{
"name": "plugins/modules/cpanm.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "dec4310e0a59dd1b38fa2be99a3e1675354257b36b45d421d4731d696d7f0811",
+ "chksum_sha256": "876e283af86e02ac15cd33a266827b173a6537807fe0c1f7f6ae7c47f04a2f63",
"format": 1
},
{
"name": "plugins/modules/cronvar.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "43e6004fb2a3cfa103644fd98659094d118b525fa95c6edc094c2ad29a2e2b4d",
+ "chksum_sha256": "7544c32d84779e8583029cde935921097479d437e00b7da6cd058e9de3728204",
"format": 1
},
{
"name": "plugins/modules/crypttab.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0e7567a57d63152229ac5d3118d582035e25851b6c6ffaf0f45508c466ee3847",
+ "chksum_sha256": "ed6d521616d6e78b07207c6ef3c199084b9640f15b0469134227964b36ab03c3",
"format": 1
},
{
"name": "plugins/modules/datadog_downtime.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ea4c54f1167d979736b0c0444b483df2a63937a88a3032b4447e1f8a30380ce2",
+ "chksum_sha256": "ccf4aebc894a68fd5540751e525a967125878ac78eaea7a905970cea67f6c01e",
"format": 1
},
{
"name": "plugins/modules/datadog_event.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4722641c798040b65cda242e174e774324021f7ffd0d47ca68c84b4febb700cb",
+ "chksum_sha256": "ec66af9de5f6b097362cc3483bf3854c40a97c2e552884eea91aba1ba1f05d6d",
"format": 1
},
{
"name": "plugins/modules/datadog_monitor.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ecee40a0d6ceb1b8912a41b0ff8d7580420a41815e6cb61943424499688f949a",
+ "chksum_sha256": "97674e518d9adf25826dc079c069d97ba9eedeb49701a97bf0c9835040943548",
"format": 1
},
{
"name": "plugins/modules/dconf.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "35a674794b7755a49123c47a52f2f1a6508a5aaeb75be0bcc2a5efc0f827a8af",
+ "chksum_sha256": "a31b0994392da69ccce7b5a99b42958130ce39953211b79ee5b69971dab69411",
"format": 1
},
{
"name": "plugins/modules/deploy_helper.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3ddee0443e6d949053b71630781ba5776f6eea76c7f8d7d8195e747d816eed9a",
+ "chksum_sha256": "8bca737e8bd9b40b09cd538ef00ac82eaed1d76d0ea572ab0aee8593e496c6de",
"format": 1
},
{
"name": "plugins/modules/dimensiondata_network.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a0c18effde77249db9072d7052c9169eaae33fc5d35e13b9afb5840e26ef02c2",
+ "chksum_sha256": "faf906cd1b0ff16a3dbea053a9f4a9e13d12d4260abc9ac49c069b01a055957c",
"format": 1
},
{
"name": "plugins/modules/dimensiondata_vlan.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "215e05484909417e3a2918feafb04c2dbfc96391daaf2bdb3515aa2a2bdeff8e",
+ "chksum_sha256": "2d31eb72efda6c9dd4d76f787d450471d93ac46b9fa443cebc0babb7b4502b86",
"format": 1
},
{
"name": "plugins/modules/discord.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8b4023894a7ca06b59a8e73dc71ca1f3c1a41746abc70ab00576aa009af14f77",
+ "chksum_sha256": "0858b62826f6f51f10a9188a8ad07a147ccd4b8dd7e6c8bebaf7d891d81757a9",
"format": 1
},
{
"name": "plugins/modules/django_manage.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a181d9f341a0bea7759751f43153e6d3eea34b9fe539e79d464c4b4d4b169c9e",
+ "chksum_sha256": "f4bb7005611249c174550fa37b5f889c610b2c9b43a91357a549212983518ed4",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/dnf_config_manager.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "587eaf2c4c8adb6e8858e47f8605740b70105d08ffa5115df840773419c768ee",
"format": 1
},
{
"name": "plugins/modules/dnf_versionlock.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cd4d4e7267438d62b7e61fc58adb1ded77fe7312936c3b160aadd70ad43299d2",
+ "chksum_sha256": "ef1c69a02a6b3a34352ab2171e39e4ada6d2a9affe99bd43d5778ca33c6209da",
"format": 1
},
{
"name": "plugins/modules/dnsimple.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9a2b8510397393ee00f3417b8ef8852704a14628aa1cc6a1534d8714d6120773",
+ "chksum_sha256": "3c9d781594ba26454a71d717933c4554021bc440afeefad69f34388a0bd9faf8",
"format": 1
},
{
"name": "plugins/modules/dnsimple_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e354ead3473b1af341c014303d1ecdef39232492d11e0b72d488cb1f2a34ba4e",
+ "chksum_sha256": "470b0f99c8f1e08a75be312277dce8f7b092b0beb38495b092bbb75651db1764",
"format": 1
},
{
"name": "plugins/modules/dnsmadeeasy.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1d028ae81ae5c74b86bfbfbf07923295e306203d5e93aa6753dc80b613896545",
+ "chksum_sha256": "235ad6a648fcbcf9765acba3d1284dbd3012e232567d9becb38ad71f6dbe0566",
"format": 1
},
{
"name": "plugins/modules/dpkg_divert.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "83a4cf59d33a4bbae1235181b07bd4eb83644afd5752b35dd322e7fc7d32285a",
+ "chksum_sha256": "5c8d1120e68b66cd2d160f50fcfaf1335817f985d280abf37299a73575d8f79b",
"format": 1
},
{
"name": "plugins/modules/easy_install.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f20c091bd3ca00fac3c88de485484a79f6e3fd68fcac6ba0092aa7ee49d43d25",
+ "chksum_sha256": "d62fe9f23b08901b923295eea75686bc88c67e9c6f6431c424abf1d54ed884de",
"format": 1
},
{
"name": "plugins/modules/ejabberd_user.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "dea9018041169ae445b095a329224e358252d2abbce47e6410173dfe2076e318",
+ "chksum_sha256": "42d01267c34845425c5359744779587a011e7d2267a8528735c683f7651f7afc",
"format": 1
},
{
"name": "plugins/modules/elasticsearch_plugin.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "07806afbd2d9cac722bfb32e74c28816a303da9545729cc55db24d8b2203f9e3",
+ "chksum_sha256": "d389d0e1169feeeb784a03da29e1b15233e61a8e5fc4336c2b646ea5802fcf81",
"format": 1
},
{
"name": "plugins/modules/emc_vnx_sg_member.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a89bf3410bc5cb100eda22e6424c058c545933d84c962ed4d8a9a16a33c1f77f",
+ "chksum_sha256": "4da273dc80a981174bbecbf8014fc509338dced3cf9465d220c0f3021e08c306",
"format": 1
},
{
"name": "plugins/modules/etcd3.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cef71555963f9e74970afea3e2c34ec812598e55d1cc65426cc6bd87d5449649",
+ "chksum_sha256": "f82bc7e899525f415f62ac8c1286068f9fd2ef9ad9869dd1884ab42fa546279d",
"format": 1
},
{
"name": "plugins/modules/facter.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fefa49704a0faab55d93c64e9bb3a897240afa7596199fbdeb796e5fc9117f5b",
+ "chksum_sha256": "11f61230f8158ec941c3e6c7b14536d503c40ad1d69e121adb5c5fbd5bfbee22",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/facter_facts.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "a45bf6a8c4bcbbaeb93c34e9fb21d8a3aa7dcbef6c6dcecf21d92ca40bf4f48d",
"format": 1
},
{
"name": "plugins/modules/filesize.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ccdc039da2e7bc985df6f20dc147f4a6a2b6f3f4c9de71e22fb33b1b5649a47e",
+ "chksum_sha256": "bf197500e37a5013f486f8ea6a669a906a02da5d9c1568506cc3c8e8e0d43ec2",
"format": 1
},
{
"name": "plugins/modules/filesystem.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bf942ef1ee36fa86306681fbf839136a2ff55c9c93feb06bae1c79c4c98c52e8",
+ "chksum_sha256": "5c68cc92970f2e756d3f153b6724d53413819f13bd87967fba8c723779f0fbf5",
"format": 1
},
{
"name": "plugins/modules/flatpak.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "572543052381333cbacca489d5c03320d309a33adc8d6a2b88b71c1f22ccacae",
+ "chksum_sha256": "6a1ff04ef312b0acec7ec57c654bc462201dfd026f73bab41dd585ad726d00f4",
"format": 1
},
{
"name": "plugins/modules/flatpak_remote.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b7b8984c934cd3edb3f2b1c6747354d84a6a64e6d95084dac92b5c89b03fb7f9",
+ "chksum_sha256": "247ee82f159cf1f10912e8ad0a83d594cd6613176d46477ec934a56b14d548a3",
"format": 1
},
{
"name": "plugins/modules/flowdock.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d1418e6a06b4d774498cca8d240fe5c853e1c5cf72bd86a12391bd4d40c9bb0b",
+ "chksum_sha256": "10c9409960f0d5596746d6452e62cc8e9061be52746eca51eded7acf4675c299",
"format": 1
},
{
"name": "plugins/modules/gandi_livedns.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fb3f4e63a2ecf0be77f5ed073d69f0b42b4b81d2d96a7d3216df043b80514b5c",
+ "chksum_sha256": "3f2c3fb34518d6c96b87de85eed6fe35dedd51f7a4296b92c0e900c216a5611d",
"format": 1
},
{
"name": "plugins/modules/gconftool2.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "dbbdc41a2418dbd7b480a43f833ca14b63198b43478b8e842368158395429406",
+ "chksum_sha256": "ec975973c83bd7130c8fcf2b4176a9b28017e43448852a8b61464f1278f0dcab",
"format": 1
},
{
@@ -3147,21 +3385,35 @@
"name": "plugins/modules/gem.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2f5a22564c1ccdea0f4b3af94b8b63cc7557080a4aa3db5ab1ec562807c13eec",
+ "chksum_sha256": "af25183ded03801a2a2e532ae29d066b1c6f2942084fb9776f3c4688cc819433",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/gio_mime.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "39d0cf0cfe519f0c3018bd77b71dba31968146eb45e90ccccccefb3c6d9242a4",
"format": 1
},
{
"name": "plugins/modules/git_config.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3e94f13fd2a359baf7697256ce965845fb8e48a57fa76d5dfef45f0e632c8f46",
+ "chksum_sha256": "3764f124422fcd3be0c60b955a6286da22e458fff5023c57ba73d0e90d3842a7",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/git_config_info.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "68930a8a4294d843523f0d8f83d4d747164907e36799a52ee5cb32a1d95109ed",
"format": 1
},
{
"name": "plugins/modules/github_deploy_key.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "137403cd95b2a624146099fc99b18f91ada3486c3889e1b77ab2f80b0e81f796",
+ "chksum_sha256": "dbc30e9db6e277c5d4f83d7c19f7c61c2d45ae89a19e767f74501b0a06ec5bbb",
"format": 1
},
{
@@ -3175,133 +3427,182 @@
"name": "plugins/modules/github_key.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "65ed5462dbc99e29eec041be56b0bc58f20fee0b42b7493b5ad0c61440afc8c4",
+ "chksum_sha256": "79de6029d98cea3b3b2c2591e8c59168de2cc3395ef397c58b89dac9fc0df6a2",
"format": 1
},
{
"name": "plugins/modules/github_release.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cbab052066a16dab590f4490b5b0521100588adcef29b4b6b982da95d0c0ae5a",
+ "chksum_sha256": "a6f3e0d12f7e96124eb89d562a0bc53df6eb927ad95d4023b7f0a86028cd513e",
"format": 1
},
{
"name": "plugins/modules/github_repo.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9bc1f3d3d2d68c0230bd45530e9b211d636cba360d84b809e652841038a1d3d9",
+ "chksum_sha256": "f572ac68fa3c9a03c7cb1fb4a2173b0737144c4fe0e30d373f1cb234ea47f679",
"format": 1
},
{
"name": "plugins/modules/github_webhook.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "33456f8f87e5cbded64f859a5cd1e61e8258650016b6824b9c50d827ddcddc09",
+ "chksum_sha256": "68393d485e024ae2d0e801fcf60a452e55a389c5f2061572b09fa475e6b795b2",
"format": 1
},
{
"name": "plugins/modules/github_webhook_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "90770694707b05e7b6ac94c4c271ec155d3b589556f2521022b7a5e72e9dabef",
+ "chksum_sha256": "a71c8b235c4bd1b662c10131840d6a6d3273944f8317f3ce8225b6592f8db476",
"format": 1
},
{
"name": "plugins/modules/gitlab_branch.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4c6636a6e83f640c7cf14e7041fb9d0595fbed1a633afcd2183c57e1d8214e21",
+ "chksum_sha256": "89355f73df2051680b15912aea5c7b879d933b5603f7e1835a73f43d506046a8",
"format": 1
},
{
"name": "plugins/modules/gitlab_deploy_key.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b9b9d88004a4d1f5cf48b1dd9a53049c4c5e8c3d453e8b38e410c2c3e31a0e60",
+ "chksum_sha256": "b965e9474f932e63e31c08cfaa6b4db0deb4e303a6f146a1cebcbddcd9253894",
"format": 1
},
{
"name": "plugins/modules/gitlab_group.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e3356b420cade3e7a5ba52143ccc922c797080b3c1bb98dead09f6797dfc0963",
+ "chksum_sha256": "cd668e498e05ef511fb2b263e43a9707c6a84d4faa288660238992a3e21c74b0",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/gitlab_group_access_token.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "34b9bc3a8cb570c87293d4c7c0a097de6a712fecaea022515b900fb57cfe053a",
"format": 1
},
{
"name": "plugins/modules/gitlab_group_members.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f67e9cf379128eeac3ff3706c0aac0accecafbf92ec79c22dc2209b22fc2cec3",
+ "chksum_sha256": "163c863ee8f01b74fe9c94d84eacbf2422f0804f4c73826275e975d5447d4860",
"format": 1
},
{
"name": "plugins/modules/gitlab_group_variable.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "12f05607537bf35975deeb99dddf3c872677c68be436f65ab6bf9be1e35ff6c0",
+ "chksum_sha256": "ccbf3ff5143df1487ee5f47d446ff381d8fd02623788974b802e9b73af29d0d2",
"format": 1
},
{
"name": "plugins/modules/gitlab_hook.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8a2f7f9ef8577d63951574c861b4b22bed58b26dd03a1c691e08461a722b2af5",
+ "chksum_sha256": "91e6d75959ecb9b38478d19f4cc985ff9dcc7033532d3887b97903ac9c44627a",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/gitlab_instance_variable.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "82e925d0471853a602b9622004955dbe36bc99e51395b099774f0ed8e61e1d25",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/gitlab_issue.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c862d68cc3e2201f3bc3af96f67bf17a3780786c7f76e59544a3386a88c5c468",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/gitlab_label.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "25fff68c8d2541d8ef914428987a9a8141d66938694fa56693fc1309215361c3",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/gitlab_merge_request.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "d1077c57cc7dfe5579cde2f2c52fc9e1bad069b58bb56c71539a0a54be49f0b8",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/gitlab_milestone.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "3c6d14ab0a6c17a49e557946de3fbf80aa7dd07d9345a9aab2b1a11769978f80",
"format": 1
},
{
"name": "plugins/modules/gitlab_project.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9a16c658c9c07d087b58ad6d9ed93f6834a0536fce7e251e410969c1dfa0f0be",
+ "chksum_sha256": "67941a37a49d3b8d4d6aa0656ceb7f763709d72a8c990643f1cbb158d2fb49db",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/gitlab_project_access_token.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "489076b0839fd6eb90f88624b505bd39a846413d9a6c055f16f5768b2073a6e0",
"format": 1
},
{
"name": "plugins/modules/gitlab_project_badge.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cd2facd211bff8bf2d14465112e09b11b19ecc4b09854888cc811da931d082d9",
+ "chksum_sha256": "ea41a8c59d6d9616fa912720977c63de47bcc11e9721b771c58a5b6e46adff22",
"format": 1
},
{
"name": "plugins/modules/gitlab_project_members.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ae66350b3bdc618ed2acc6e938c484439d83901a1bbea3363c8fcecfbf6205a4",
+ "chksum_sha256": "06eca4180d59d7c50a681ffdba522d6ba38e5bf72d497a5d5ea04214e391dd02",
"format": 1
},
{
"name": "plugins/modules/gitlab_project_variable.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0621f2754563425f573978a5f89059fde433130eeda32c9d3c7ab1de86d61039",
+ "chksum_sha256": "1c0b829b236234d2f5e9f919743018dacc43b17301d2324779662dac43b251f7",
"format": 1
},
{
"name": "plugins/modules/gitlab_protected_branch.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0b01efa7f012007c6c36d65093d010b0f6965e3377e7a58d332376abdec6fae9",
+ "chksum_sha256": "112c7029747f50c98bc07e2a19406154b65a0d20e50b81e383c276efac27978b",
"format": 1
},
{
"name": "plugins/modules/gitlab_runner.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "44055222db26d6b2838f4cf2caec6273bf2cc62d9497142e70537ae8938fc1bb",
+ "chksum_sha256": "53194f5b56d5cf12630f312b1d8af77dd883d1910a50ae91577f5857e2de6f9c",
"format": 1
},
{
"name": "plugins/modules/gitlab_user.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "74e5e8205c49dcdd5d07acde697f5d47dadb0a3befa44ec167e817593b4d6a3c",
+ "chksum_sha256": "df2f6b18e3bb13ac1a5ed75c41b7d7dcadcb6c0491d76194b685c9bb4c60f97f",
"format": 1
},
{
"name": "plugins/modules/grove.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6d5fcf9d5009d954a38a5b7c0c8446ee93be48086f04b2d3410659f7e2fe9d63",
+ "chksum_sha256": "a09e4457a2906ba838f175b0cfda3c71763489b74f42597a6882b504c8ce69d7",
"format": 1
},
{
@@ -3312,45 +3613,38 @@
"format": 1
},
{
- "name": "plugins/modules/hana_query.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "8ed46857b938221cbcccdd8b2a766259d0aff61c7a3374e40c22676d404c733d",
- "format": 1
- },
- {
"name": "plugins/modules/haproxy.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2474e0d23cc1855af4b4b383ffdc78fd26a473271e487023826cbce1feb79402",
+ "chksum_sha256": "816d15aa1df4f09211a1e2e194609db779f32a9c1ae7f12c37fc52895c0e1a1a",
"format": 1
},
{
"name": "plugins/modules/heroku_collaborator.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "33afa89a26ac74c4885e8e2b0f341d4c80280b4d994e2152cd92c50ef6cc7699",
+ "chksum_sha256": "fcb7d206ce822dc4e0d1fb3a7aa12423ee758a060c5bf68d2c90b986ca0a5029",
"format": 1
},
{
"name": "plugins/modules/hg.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e47d7c753b41a38cad8178d09a79a27ad82b12902ca1695340279e8933c11453",
+ "chksum_sha256": "cb709b491043afb1a1525e23e206e59ce92ff590cd777029d78e1a7290a4b3da",
"format": 1
},
{
"name": "plugins/modules/hipchat.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "feec640748df0de0e9f31df56ff48dc30dd3ebf713cb04d36f2e0dc245a1d48d",
+ "chksum_sha256": "64a9fe4deea3a0eb743f00357e635b87333a690db0a5ab9eecb3cc46efe13375",
"format": 1
},
{
"name": "plugins/modules/homebrew.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ba91e275ac3da817b8f29e921435ff079d74f29f071627b368e05c84989316d9",
+ "chksum_sha256": "daf7098503d9cc6414a32fe5bf895506264c1dcb9bdd008842e111de5b0279d2",
"format": 1
},
{
@@ -3364,21 +3658,21 @@
"name": "plugins/modules/homebrew_tap.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ab90a789fbb734e0140eb07b1e963e8cdc0aaf42df7395f5f0e41b62add7b671",
+ "chksum_sha256": "b6d5e009e230af6e2b163b290d1e2c962949b1846a0044c488e729e399224412",
"format": 1
},
{
"name": "plugins/modules/homectl.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a267411a289f6c95485b3e6befc889066733592a54748cd0bc0357ce290a14bc",
+ "chksum_sha256": "f5af3533ea90dda0925e64715ea23b8aea4418020c0fb66115fa0595d452d749",
"format": 1
},
{
"name": "plugins/modules/honeybadger_deployment.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5e8c767f87c5c69d8376bb54d4cd7aa9fad0e85eec532d85f3308781d4373968",
+ "chksum_sha256": "e5c9e41c2e78f2dee16b20a8edf6a367757039faae0a019429baf2e27bd8767a",
"format": 1
},
{
@@ -3392,7 +3686,7 @@
"name": "plugins/modules/hpilo_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5028ceeb0bb4dbc4cff34e821fda3d731e833538626d21011590552aea63977d",
+ "chksum_sha256": "8e0db7b57d397e8f5b89e17c6fc03c422ea341e34a63c50a6a3ebf39bb30607a",
"format": 1
},
{
@@ -3406,14 +3700,14 @@
"name": "plugins/modules/htpasswd.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "76412e63b0374b59340592bfbeff5870a320845819111cebc8e3e31e5d942672",
+ "chksum_sha256": "515d1817a0b345fdee654bccf6b7f24f5f7e6d75ec19501344ec3ecbf64c52f1",
"format": 1
},
{
"name": "plugins/modules/hwc_ecs_instance.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "90f1bb75df403719b8e3e1703b1064a11e0d8e7175eddc02aca8c10ae875195d",
+ "chksum_sha256": "37add130a8879ca16047d25beae251fadead036f5688ca11877b35efd5d3285e",
"format": 1
},
{
@@ -3434,14 +3728,14 @@
"name": "plugins/modules/hwc_smn_topic.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ba47442d9a2834c09328430bd227597fc80f52e8f3ed6cd8f91b2088b404c508",
+ "chksum_sha256": "7d2f37287e703a3ae8cab77e01c567b479b2ccc75cc5286f5f71c05de997d57a",
"format": 1
},
{
"name": "plugins/modules/hwc_vpc_eip.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7b6bb34e76fa010ba9ae5d86d87128ede2e20e1489e694fc7e372a6ce57f4417",
+ "chksum_sha256": "0c377824fd364f9750cd225b5eef48cd447ddb03fba8cb20fb63a52f1f61e1d0",
"format": 1
},
{
@@ -3462,35 +3756,35 @@
"name": "plugins/modules/hwc_vpc_private_ip.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ebfb01db52cbb3869e6324cd718e8a0aa753627d962c41f54f3f8485134b6d05",
+ "chksum_sha256": "acf4e12da6fb09155140905a400773bb729ca0968a425e40de8b431fc57c7c4a",
"format": 1
},
{
"name": "plugins/modules/hwc_vpc_route.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bdd8097fb8db7ce573427f4b63875500eb268a4c790bf1186e50e067a34155c4",
+ "chksum_sha256": "7d55a6bbdba91d668d946af9f80550e1a051f32382c2c3dc2cdb7af6c7a9c179",
"format": 1
},
{
"name": "plugins/modules/hwc_vpc_security_group.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "25768a8fb5d1785090bb273cf6fe78057c09ec5773248c642cb8ed8d8a8c056e",
+ "chksum_sha256": "0b64bc05f57d820e6022d04905b45b61fee79efb68f89691a4ce81d58ede1acd",
"format": 1
},
{
"name": "plugins/modules/hwc_vpc_security_group_rule.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fcf0f661b4394f038c001c5a0ac8839eed3879d087c5e3ce8548b768e83ebe8f",
+ "chksum_sha256": "0701f533c835a012023cad9f0ed154e2e44c8e57037f6999e00133371c50065f",
"format": 1
},
{
"name": "plugins/modules/hwc_vpc_subnet.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c8f7cb86bc537788144014a829c9a19e2187a245431bdb8e34b4707d1811c4aa",
+ "chksum_sha256": "4e6d3f359f816f75537b8558d8c97d19a8044bbf146f2e2a74efc751d00928f3",
"format": 1
},
{
@@ -3539,14 +3833,14 @@
"name": "plugins/modules/icinga2_feature.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "648c11df285cccc27f6092474ad8197b474c66a67822b71a011313673e93abc3",
+ "chksum_sha256": "15090f9cf57152cd8b9ac3a4989aa2a20cdb735adf733107b4a3a5cac1ab96f3",
"format": 1
},
{
"name": "plugins/modules/icinga2_host.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "43390079098113985bd140ff26472af7ba5382dc2a91eb93c9eb2a2fc861af6c",
+ "chksum_sha256": "b6db57f456ef45fd9d2d6312ffc5314a2978b656611b92fde6498f3a9009b8c3",
"format": 1
},
{
@@ -3560,21 +3854,21 @@
"name": "plugins/modules/idrac_redfish_config.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8b6839158d5d6bed95253c9b9df23a36a31b5113dae8cd299bfe147528f1209f",
+ "chksum_sha256": "05ac7183431895d5c482ec7b9023085c1fb122d42453a7ccdc1b802f8722e134",
"format": 1
},
{
"name": "plugins/modules/idrac_redfish_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b3f93035acdaadc1974f04d9012c7f83e8a4783ed72f2f9818805ac86fa82cba",
+ "chksum_sha256": "3b94f44b3196f007b314c8d2a1fc920b883756ade0b06be9f40fef190f529a44",
"format": 1
},
{
"name": "plugins/modules/ilo_redfish_command.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a6cc52c3b511b626416ae92dabe3320c0883b692ad9a563110c2e654b916fe0d",
+ "chksum_sha256": "bc3a72c01393d41c05c3cb5afc6148ad72ad49a50beab497ac257f5a3e626fe3",
"format": 1
},
{
@@ -3595,14 +3889,14 @@
"name": "plugins/modules/imc_rest.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f0b9f8a0f8bcba2420b9fd3106bccf678f82d192464fcc6d9c0aaa0c8c584e27",
+ "chksum_sha256": "3b212b98cbc6821f9f079ad0d28596d375f1da710bc9d8110bc6a6f754a77ede",
"format": 1
},
{
"name": "plugins/modules/imgadm.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ba579d2844cfb2584ceb7447822e79b6a97f32a67c570e6de95c48acfc4fe952",
+ "chksum_sha256": "1efc63774f3109d148e5cc0694bdd9d4532e5d87b12ac3cffa1ec803b3603a5d",
"format": 1
},
{
@@ -3616,56 +3910,56 @@
"name": "plugins/modules/influxdb_database.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c9642c5169b3ad77918f02aa48eaecf3dc55993d109d3f42dcddceac0346af9a",
+ "chksum_sha256": "3231ec6f6b6e8d7ee48a3e7fb20973effa70c43fb1e8d00754773253d380bedd",
"format": 1
},
{
"name": "plugins/modules/influxdb_query.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "59d68108945a7a70a822b189834df11fe3310881a3b88c32d84467e1a4d7156b",
+ "chksum_sha256": "bb37fae5aac17b008e5ea4cb058afc1ac5c52a566d1f0fc2e4dc25d447b02395",
"format": 1
},
{
"name": "plugins/modules/influxdb_retention_policy.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "337879161084745755ca9f194e386ff4fd6ff15d68fecaee0a909d19216a34e6",
+ "chksum_sha256": "06498bef598ba09bf8d6d34757115aee2489d40bb2fd2e8f97b579b84248d61a",
"format": 1
},
{
"name": "plugins/modules/influxdb_user.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "73849db9a2dc5412d9e1d2adc17bcddd994f98b6ef27b1e19c0f9857fbe322be",
+ "chksum_sha256": "744159d99e8775dc106b496d9e34f1ee1e5103d85e6018cb698fd4724a5d68aa",
"format": 1
},
{
"name": "plugins/modules/influxdb_write.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f956300435269e206c7418bb77e7344c8a81628c048958601b2959216a6130e0",
+ "chksum_sha256": "a376d44a3cb6578c8413e7d1fc55702f41e1631c1e2901f6ede9bff21d128b1f",
"format": 1
},
{
"name": "plugins/modules/ini_file.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bf2f658550a534e1dbe6f7c3a3d6ce0754fbb77132814b4cffcbb0f1a1a309dc",
+ "chksum_sha256": "37638878ed3b6e5c2860382a8b2940eb20906b12da727c67c4c1e04f38e68255",
"format": 1
},
{
"name": "plugins/modules/installp.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9553388ae97679c6404b54478f3beb09bfc616415fca84a2ee0ab7172d94857a",
+ "chksum_sha256": "8c8d4f1272851b63589575bb29db5dca18627fab5f04c26e3917a14960ac2224",
"format": 1
},
{
"name": "plugins/modules/interfaces_file.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "578188df20d9c152973c586ec45a173dda8078b841d13c81473bbc6773ba36d1",
+ "chksum_sha256": "9f0bf38398dc485247870448a68e136bbc6a7b714e5395c18424a734268b3c29",
"format": 1
},
{
@@ -3679,49 +3973,49 @@
"name": "plugins/modules/ipa_config.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fcffb115c7f4a2a5f0b1cb51c9957ebcb3687c20c9d427036e857b57d1e70cb5",
+ "chksum_sha256": "bfbced8355ea6702349b925add93efe41b8c85f5e0411b90d11b125244cb9fc4",
"format": 1
},
{
"name": "plugins/modules/ipa_dnsrecord.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "36d587bfa5e91a7c32c84135b10ccd4f20351a497db84f15a2ca98087647c43b",
+ "chksum_sha256": "c8ae9aa977adb6ec60404eb8bf40adbaa7b1ce897e6707769d5e90230b40f16c",
"format": 1
},
{
"name": "plugins/modules/ipa_dnszone.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "130c2faa7317bd3c61bf1bcf1aa0ca91536069d527266f07f2cb24756149bc1e",
+ "chksum_sha256": "50ad7ac79675e690c47e34429213d24c8b58db4fe4c0f142938fe33a24bcbb06",
"format": 1
},
{
"name": "plugins/modules/ipa_group.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "55b2cec03a5818e2dd230556217bac0632517158a09f88c02d5ebc90e4b73dc2",
+ "chksum_sha256": "3d5cd1fca54a7207d9516e698b6c63467bd57b115d9538e32f51751d2ee205c5",
"format": 1
},
{
"name": "plugins/modules/ipa_hbacrule.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "82a40310df2e353d9d223145b6a713fe8f84065a3ddd96c7c11176eb90c6944a",
+ "chksum_sha256": "361846be47c60371f42b04006be9560c51e5d47586fbb0fdc3b031473d22e6c4",
"format": 1
},
{
"name": "plugins/modules/ipa_host.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "21a0543fc685a2fcaa15d14c29a19886cabb006a8cf06108f807bdc58cbc8024",
+ "chksum_sha256": "d9c6f5e95a1f0e94ddf0129674f2931a80afeedea0ec0c58c66e2ed8bad31425",
"format": 1
},
{
"name": "plugins/modules/ipa_hostgroup.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "721de84c76619b0d82fecfa226ca32efb862581e5b8220b82d6c1f40a781ec1c",
+ "chksum_sha256": "df511ac0ce310185567ecc78a1ac55e5a33bb71d74eb997614d87c1a8d1bc7c6",
"format": 1
},
{
@@ -3735,14 +4029,14 @@
"name": "plugins/modules/ipa_otptoken.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4bb4948657e723619f1b69a3c1721c41f26daa8c2e2e2ee7e6d700f1d0221ab2",
+ "chksum_sha256": "429eac3397f06ebccfe5b4f18e70cae84895d0ea65d2043cdad1c64a32bba2dc",
"format": 1
},
{
"name": "plugins/modules/ipa_pwpolicy.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ed9c231d05370490c4b3bba188c51af23b72347c93999a8562bda66363abf171",
+ "chksum_sha256": "f76d0c69f9bcc46bf762d7e22f7603c52725f4991080ce0e7cdc5575079e7a82",
"format": 1
},
{
@@ -3784,28 +4078,35 @@
"name": "plugins/modules/ipa_sudorule.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7a75e59ac3871f68e30635e78e4c7e559eaee9ee291df542c7695fafdd65ddb7",
+ "chksum_sha256": "9b9df8219d96db2cb4568462de5aa7bafbea0ba79909ad3eef776122568ecb42",
"format": 1
},
{
"name": "plugins/modules/ipa_user.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6a80805d7e93ebe02977b93b2a0a6018f938438c844e2887001f22c3f63f60fb",
+ "chksum_sha256": "142629db4947f3ddd9ab0911d616e03331feb7b775acf0c94524b035d356f431",
"format": 1
},
{
"name": "plugins/modules/ipa_vault.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b953ffad3a2288229cacb4c0f3f6f7a328e8e661e445dae6b848bbce477d025d",
+ "chksum_sha256": "aead6c60a239da8542c0b58a4a93242f8f8580cd54217c19b72a73c2d4ec68f1",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/ipbase_info.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "3a2a72f276a6ca41f8f4bbdc65d7070ac151a8f0d68b9985cbe0a8c95e3d736d",
"format": 1
},
{
"name": "plugins/modules/ipify_facts.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "955573422d24518b6a33dd3f0259cf56d0854b88796f18bc207a023a76f304ba",
+ "chksum_sha256": "b4501eeb9e97cea58ae57979d65c7814690124824f6f494d277a95f1bdce6484",
"format": 1
},
{
@@ -3819,56 +4120,56 @@
"name": "plugins/modules/ipmi_boot.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e00a40374e7b43a66a09cc3563b693a0c5a1a77d3111fcba226bb4c4cf8aad59",
+ "chksum_sha256": "c0fb01e3b14788766fd355b6cb6ba974c69994c084fcfc6ad6d2b637f75c143f",
"format": 1
},
{
"name": "plugins/modules/ipmi_power.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c889bbe8e7d91bd46cae1a9134dc1805f2c288f24545b191502a46c980868f8b",
+ "chksum_sha256": "660ee241b565e4e1e580a8da379ea27c9e27206a0cb6e6e0179ce45dc193425a",
"format": 1
},
{
"name": "plugins/modules/iptables_state.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e35e80b31daa94e712184454ba6d6d2bc455ff5c32b017d92444a942afcf8748",
+ "chksum_sha256": "6fd2395a7d3c726fe7d056e11c2c1a714e0b4e22fb45158674558090ff0f0ba4",
"format": 1
},
{
"name": "plugins/modules/ipwcli_dns.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7e208f3f019aa041e443a42a63abca695dd9ec4d8b90107e83e15162a8bfac03",
+ "chksum_sha256": "8254e4834d4fd530a614e90f20e23746e20610771a21abb8847462d7861d33ee",
"format": 1
},
{
"name": "plugins/modules/irc.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "be120bfc78b6c6f89eec96fe65167fc62a24a2e15ae7a74b55220710c7450a5d",
+ "chksum_sha256": "baf14942dc3f145739b1c8a666e9eb876d33eabfa552455a450c64e891a5f4fc",
"format": 1
},
{
"name": "plugins/modules/iso_create.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e51604740a940c53ec91965e76637ee0074912282c8ab1396f028852bbfe7644",
+ "chksum_sha256": "b00c2a18010ca4daa469ff4e41ae14d8173942a084a58af86151ef7964935bf1",
"format": 1
},
{
"name": "plugins/modules/iso_customize.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "94f55e28d70bd033bc34ee2b7e710a11328db8ff41425bfd6cda0e67f9c8dcbe",
+ "chksum_sha256": "092a00ddaa979ecf14424a6e28e179c076c474b625900dc5e0cf133d42fcc161",
"format": 1
},
{
"name": "plugins/modules/iso_extract.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9d88a5241865ad0f06052f5edc84e2d6ed7fc02647d29a48db583dbefc998f00",
+ "chksum_sha256": "0fe53beb918e5383c5bcb4367510437b5fe5209eed207ce6393a3b9425b1d838",
"format": 1
},
{
@@ -3882,126 +4183,161 @@
"name": "plugins/modules/java_cert.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a7e28cb732857e4633e9693f1f3d8ee0951198dd0d6045c52758d0903ba27b84",
+ "chksum_sha256": "f325def87c1b6ab8e1e1acf9829b9e0f7b22c773a35e5a9eee2116f1b4f37d9b",
"format": 1
},
{
"name": "plugins/modules/java_keystore.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "96dbf361d11844ac5f75ccd1ccae9b89d08895a681556d8ddd6df94c85c0087c",
+ "chksum_sha256": "d963eb8841adad5a5ee10bd0e89b4bf5bf67a23400ab552558605199aa8e9459",
"format": 1
},
{
"name": "plugins/modules/jboss.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a21306311a1caf21814914339c33f55df520682d88cd4c1e98118ecc5e7d558b",
+ "chksum_sha256": "7fa783b42beeaa6293a72097fea0e2efc1996cf4bcb0ca8cd226820fe4f69e3d",
"format": 1
},
{
"name": "plugins/modules/jenkins_build.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c2062703e429dcbc727e43a769ae92dab97e583b3978ea5e6d9b0ae3e9e9c932",
+ "chksum_sha256": "7171ed7a75f38753fb5c8e91d9ee76f7cdfc10dcedf7ff4734c911efba1f31f3",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/jenkins_build_info.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "bac1b1b12e2c9d7a0c062c68f2e53edbf6f8abbbd8cc012b5e26483a2c426fb8",
"format": 1
},
{
"name": "plugins/modules/jenkins_job.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ce169c941bf99bb517fe9d2231506d58eec2dcf05f66686dd06b02c90ab5bdac",
+ "chksum_sha256": "c08cc7dcad6d8eb2d0689a8a4b199e10ea2ec4a335f88caffcb08877ae0a80ab",
"format": 1
},
{
"name": "plugins/modules/jenkins_job_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0fae160ec57cb25c854235046b3d472162f5a69ba50be25d0d5ed49064cbcc20",
+ "chksum_sha256": "68764ca186d77682da9f496a78f4330b369af242ddb528aebd8534d883df34e3",
"format": 1
},
{
"name": "plugins/modules/jenkins_plugin.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a7d0bc2e1d0b489a489f35215ef019d5c54f079103875413a3573da687af7295",
+ "chksum_sha256": "74a8a8652a02b07ac5097580edf5ceb4593a1bc90cf592bf457f92eb172e0d9d",
"format": 1
},
{
"name": "plugins/modules/jenkins_script.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f378fae28794a824333172cedf723120617657460c9bbef2a48ad43bae500fd6",
+ "chksum_sha256": "6a29b7d79880c4e0c4436a25e14f061ac90dfad2a439266370b0dac7da8b67dd",
"format": 1
},
{
"name": "plugins/modules/jira.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f4be661192d0623095f417aacbf31a8af09f671f410fbe8cca7486e86cd8a49f",
+ "chksum_sha256": "5f7c270e3916ca51f4b299fe3188344fb51a19229db821e589c7655c2698ec87",
"format": 1
},
{
"name": "plugins/modules/kdeconfig.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bcc801825b1134d88c34aca85234fb913f2edb8caa0fd79145cf8aaad5604fb1",
+ "chksum_sha256": "12970ddfb6a68d20b2a263b6d82c1553cea08f11fd7e1108e9e94956dfdfd864",
"format": 1
},
{
"name": "plugins/modules/kernel_blacklist.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e9dcc62df8957ad080a0686f2bbab46214bd53bafdd99b1405e1c8d3c8d45595",
+ "chksum_sha256": "587992974b9adf733a25ee79241b68786b1425efa422ad6d4cd6d75e4c3b3a2a",
"format": 1
},
{
"name": "plugins/modules/keycloak_authentication.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2bdac1872012b3f79ff6ae64558e54d0647b9c1a5ee4620e6e98e36650f73039",
+ "chksum_sha256": "109622b63f28233c735dccb1b2325c844a13d5b3d156d2714fc31c26bf386a8c",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/keycloak_authentication_required_actions.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "596f73ac35ade21c06cff093015346c5d0d565ed810fefa99dfdd2dfb66a9d41",
"format": 1
},
{
"name": "plugins/modules/keycloak_authz_authorization_scope.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ea5f33a5cdf7989817fcec05d117765aa3a9b9504b9302377092f9f8fb1bae3d",
+ "chksum_sha256": "f084aab4398ffad75e60f96bacaa9ca988d6c138b20f01467885e54732ec063a",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/keycloak_authz_custom_policy.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "507947564b23b5ebcaa710270319acb9203bed6120828063d361a7c54a0a8a5a",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/keycloak_authz_permission.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ed071a9585ab073568a4d5a2d1ff2cff25033529044dfba914b10d1787f7627c",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/keycloak_authz_permission_info.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9ad139170d1099cb8a1b6098ae3cf0130d2d7f797f7e713dc363ba98314e6f63",
"format": 1
},
{
"name": "plugins/modules/keycloak_client.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "786a36a9240fa932746b973582ae45e6feeebc64a064e18517b08f98a7b31d68",
+ "chksum_sha256": "d1c5ee5cfeaaa3ea1653e2a3a43c642e95d6e837269a8f5bb967ae9f74e26139",
"format": 1
},
{
"name": "plugins/modules/keycloak_client_rolemapping.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8504fa2dace6ca2a7ceb56a1005b3e2a93dc80b1043504534681093b593d909a",
+ "chksum_sha256": "68fcfa25e112f9431d5456f098c51fa24d7797c55ad13a57603cca0752701fe7",
"format": 1
},
{
"name": "plugins/modules/keycloak_clientscope.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1f29a8133f2cdad9f0e7452a2f9512540b72ca60c0165b8ba2a2c7c902e20344",
+ "chksum_sha256": "944a9d01857144ae760d704e124b4dd3da31121358efd17058bf4024e3e111d5",
"format": 1
},
{
"name": "plugins/modules/keycloak_clientscope_type.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7c76a8ad81dcc5bd47591804ef0b1706329361f34926e9334d8a1f4450653753",
+ "chksum_sha256": "2f5a39ecd4475e031a5ae847281c8a384fe7eb6c3c2b9c2bcdd8ca493f23400e",
"format": 1
},
{
"name": "plugins/modules/keycloak_clientsecret_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4e1f37664f9e841c5adf1a7250ae272559fb4cdc002b74f3bad043a80a39156b",
+ "chksum_sha256": "e4134b3e4899412397f45bc4d83b950c552362282f6aea57d85fa51f28f01829",
"format": 1
},
{
@@ -4015,28 +4351,35 @@
"name": "plugins/modules/keycloak_clienttemplate.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "08aed4c4cdcdd833791170d9347830cd35c280de32731cdd225138be591f0cdf",
+ "chksum_sha256": "51ae2bb14c80773bc7dbfe159a9fda0337609ebea371904f0ac75010ce64e689",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/keycloak_component_info.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "800aa471adf38eed5e7dbbd817c899624e51fff1a8a2b99f3f6201be7583e6bf",
"format": 1
},
{
"name": "plugins/modules/keycloak_group.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "36775c495fc00d391b8835a1bd2aad0866da36a4bb33993b16755587bfeb34cc",
+ "chksum_sha256": "0b058ebb88015c079ede54921e0456a554cf12b5bd3389e980690b7b2099c681",
"format": 1
},
{
"name": "plugins/modules/keycloak_identity_provider.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d22ef8f28abbc9d18f4e6bb14dd1da8555f015cac982787fb6d315fd529b399d",
+ "chksum_sha256": "fdcb1beb383507dad083dd2ee7ede5f0fc1df884f8ae5548a0740b0cc4fdf5c2",
"format": 1
},
{
"name": "plugins/modules/keycloak_realm.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "60bb00520f91eaa275ac527b6232ec2f21a97c41fc24bca90f1e660404d4de93",
+ "chksum_sha256": "ded26fe5a5bd4422a8f91c31a266d502c23653087128af2753347601d4178391",
"format": 1
},
{
@@ -4047,31 +4390,52 @@
"format": 1
},
{
+ "name": "plugins/modules/keycloak_realm_key.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "b30dcc1320a6d759c0d9fc205260fb34d8df854b9535002815fe6e537a01c97f",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/keycloak_realm_rolemapping.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "78211490005e468d711cc8e92460853beeda987d5019b7278c13119a28cab1ef",
+ "format": 1
+ },
+ {
"name": "plugins/modules/keycloak_role.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "099fa1153a347ae9809057feabfa027d27607f48e7f9483ff0c7c419ecf4c60f",
+ "chksum_sha256": "edb6b6f6985ab662ed9a55868310cb73ec5bcddde5df1989d24d22cb2ec78842",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/keycloak_user.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "41321c30d2ae6a78835a460910599d96637905789463881c82517cfbc80f91d5",
"format": 1
},
{
"name": "plugins/modules/keycloak_user_federation.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "91ab78bf22dbc5875e54af1f26f264f88e7c32e8551f03872e0f8c2fdb37e63e",
+ "chksum_sha256": "1c7c871ab324312ba3730df9a30bd017220a89a09282d465ee6dbc234402181f",
"format": 1
},
{
"name": "plugins/modules/keycloak_user_rolemapping.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cae7fa40038590477b7f10b4fe54058307f62960d7d79196c93563155a4869dd",
+ "chksum_sha256": "57ccf8934b8cd7a675669eeaed94c26cde4a73fab5e7b2164b74c320e7bdb97b",
"format": 1
},
{
"name": "plugins/modules/keyring.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ad36fa8002c63a55a753416c392e97421bc4f579132c77c2ef82edccacbece8f",
+ "chksum_sha256": "c36c6cdbc8d1d053169974032f06113e8dd6ce0e5da4ca667ad02d1344c356b7",
"format": 1
},
{
@@ -4085,21 +4449,21 @@
"name": "plugins/modules/kibana_plugin.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "59d6bb301266fcd13f6cc50ed964d5caaf4df70d5ab933760e65244851314f0a",
+ "chksum_sha256": "b962b2223d5b7fb6ecdf8f3c6598f1856f9879de2b4a2e2d8664bba1cf80ae3b",
"format": 1
},
{
"name": "plugins/modules/launchd.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "356ab45e7f1f7f142b1c30977cd08700fa90b744d5ca8082e9c74905103f21fd",
+ "chksum_sha256": "239bdd1ceebfc51da46babbede85732efd5aca73719214225bd505c202cc4915",
"format": 1
},
{
"name": "plugins/modules/layman.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0de70649704ed2301401e6515ed8b3aaed22f6d19f4ef864ca8cdea34a5da63f",
+ "chksum_sha256": "5f43d089a5b9bff25dab227e84e060ff4d45bc2f50e2f20d3a022ecc2b3a7205",
"format": 1
},
{
@@ -4113,28 +4477,28 @@
"name": "plugins/modules/ldap_attrs.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "78510608583a757c3bc9912b584cb4c5d829ba6b70aabb908c08a1ca1af796a9",
+ "chksum_sha256": "ff73455c9fa202c47c87b22b3a73987a72870eb276ddcc676c8041fe750e14d7",
"format": 1
},
{
"name": "plugins/modules/ldap_entry.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e779d589911e22b4c681ef2df7e4fe2f217b8df2c6122de9ae0b441aa7eb164c",
+ "chksum_sha256": "66a1be27c982a0400b0240d2bab981c8b9d6dc1351a242598098184b7581173e",
"format": 1
},
{
"name": "plugins/modules/ldap_passwd.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "50788b0344b4cc48ff0dfcf43c1526f7b29aa6ff9f6588b3d2d2880bb5c3d95c",
+ "chksum_sha256": "2efd94853589cb3b25de31ba390bf1564dbfbd8b43a95853557eb2873f2ad547",
"format": 1
},
{
"name": "plugins/modules/ldap_search.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "509f169e92f7c26345e77f7d32fca4b8473dab07be80f110e62654b00abbea5c",
+ "chksum_sha256": "6d79f510a11d341738466cfbf4f59a6bda3d5bd4df45f3692b0653ab37d81946",
"format": 1
},
{
@@ -4148,21 +4512,21 @@
"name": "plugins/modules/linode.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9f9e1eeb9ee07644b74f49a20eac83be430214a40c3df052655c1f3be1fa5be5",
+ "chksum_sha256": "72015cc52b1db01f7e6c3391e33b6799661bfb7158a0bf8bd5418bfcc07f1011",
"format": 1
},
{
"name": "plugins/modules/linode_v4.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7fff3788dc38392139b78f5b5f5f5640ead22db632682f8c225095e9be97dc42",
+ "chksum_sha256": "858486e79155cbbdf7070e0f1883a3e055d22b04808fd0b01d0393f64292d9cb",
"format": 1
},
{
"name": "plugins/modules/listen_ports_facts.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9bd73959a007555bc3a6aa3381459319d26555afe21fcbb29b7ed7a1502454f6",
+ "chksum_sha256": "8a03fc1fd21b3958de37907ffae1a18a7df079910051dc99387b914bc42eab96",
"format": 1
},
{
@@ -4176,7 +4540,7 @@
"name": "plugins/modules/locale_gen.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f83eb084c5229b122bf26bc735fb6dda550ec38cec746ba023cb32f552e16c8a",
+ "chksum_sha256": "871d02439c640ec2f3ad62cae96a6093ffbb27d87bf80bb4638bdb2688fb32e6",
"format": 1
},
{
@@ -4204,21 +4568,28 @@
"name": "plugins/modules/lvg.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a20ea201e30b4e89136f651ac54c9f2c43dc49cdee53687973630564fc7a8543",
+ "chksum_sha256": "2b6d4d2fcc2a1b942dd81c4527ae89eef09e955f5f7dac84080741e3629c54a0",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/lvg_rename.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "a80cafb165108171ab6e38ca17530c1577de66618eb4433ecc6575fd646476c3",
"format": 1
},
{
"name": "plugins/modules/lvol.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "efa4568ddc6ae42d2908982e0c5dd7b989a240d6e4e9a6e2062a4f5e23d2d326",
+ "chksum_sha256": "c1009f4bb6c0c892f867827fd64ac299c644b634ec838d9c52f2a9be0e0ab71d",
"format": 1
},
{
"name": "plugins/modules/lxc_container.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3bca54560f809417f4ee9d1d3e878bb5e6ebc3b95f9874c30b94ba5b730d613d",
+ "chksum_sha256": "fd9569a9e9cfa5ba1e3cfd17f4dbbbc720bc87259a9fcb3a7987b1c59c5ad58e",
"format": 1
},
{
@@ -4239,119 +4610,119 @@
"name": "plugins/modules/lxd_container.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bbbf8c67ca4b6a8d3bd73ee55f377821f38678afc9f10ba0c929f4ddc52aa68e",
+ "chksum_sha256": "232e7553c192bd73a35bd0689e9d47a6eb29ca60690d4da6e763cf81dc079ee9",
"format": 1
},
{
"name": "plugins/modules/lxd_profile.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "89a85fdbd5d521d008e26667eadcb8850f31860ea28fe24c6c0c25364bdd726f",
+ "chksum_sha256": "fbda07c6fd6a83067fb1959c5da6c249c1bd75331d698e0be75164448248fafc",
"format": 1
},
{
"name": "plugins/modules/lxd_project.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ae8453ec8bd7c0cbf1f12ecf63ea9951cd65067219591a17517e5628f8d73b51",
+ "chksum_sha256": "39b67268d5d82ebd464553b9011c0decbd7500b82d6e386baf8933abdaa859b7",
"format": 1
},
{
"name": "plugins/modules/macports.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a5583e723feab3467549a14fbdd90e9098570182a8ca413d26a2dda683877cfb",
+ "chksum_sha256": "488f95a9d1944fd4aab3aa6cbd32adb06d3727d01c371c9f5d7de00a47ad8fd2",
"format": 1
},
{
"name": "plugins/modules/mail.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6000a725640848ece04ec174f729e48917e0caf81bda3aab71da87eb529ba66d",
+ "chksum_sha256": "aa0c4d074f2eff81098fcec26e53f0811a71e05e55ce0b6209d7658e713441d9",
"format": 1
},
{
"name": "plugins/modules/make.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e6a2d2294d9c7e1ee0edf9e45a3e3fb0a8df5b4b288df02ec8c6cea4c500e8bd",
+ "chksum_sha256": "d6a3adb9bea253db62b1c0b1b0f16fd088d84bbe3478e96bc1b578f90fd50b42",
"format": 1
},
{
"name": "plugins/modules/manageiq_alert_profiles.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3c6fbaf19ee5230630fdb636d15c257a5442e2e1119a1c7c51801c6f061e9593",
+ "chksum_sha256": "fcdfa7c49c1bd8f22bfea5b0a4629a494c79db12fa4ecb85c7cb974e6d5f9fc1",
"format": 1
},
{
"name": "plugins/modules/manageiq_alerts.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e3f271bae5ea27a6e0bf8830f75923fd090fe627369541c2241a174fbc0c3198",
+ "chksum_sha256": "c6a778ab7f7b4db30714314a09e6e19e5b527ea5e08d67b98653b90884539b29",
"format": 1
},
{
"name": "plugins/modules/manageiq_group.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b421343af34a9d5a515bf304ca63d3f9fb68e5d7ac2d8473bf4eeba1d9d54f2c",
+ "chksum_sha256": "f107c81bce538d8aa0d744062371dea4dd4210d3730120acb518b7c501139275",
"format": 1
},
{
"name": "plugins/modules/manageiq_policies.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "78ab36008d5219c0c1882f58add98c8fb8a03eb9d8b19edba97a73bd3b11f00f",
+ "chksum_sha256": "3b3cc1b9c1f82f802f7f702d6ddef1c00ddf1b1c368bd19a40a7e8c83ebbe321",
"format": 1
},
{
"name": "plugins/modules/manageiq_policies_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1b1e0e3d1c159b65ad47339aaa59d6c2dab98ee2269cecd7e0ace20aff4dec9e",
+ "chksum_sha256": "d9f08dda00046f622f675bcd23d2bf7bab1863ad3e9758e0e2f2c842f0081eae",
"format": 1
},
{
"name": "plugins/modules/manageiq_provider.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "398499db7253e6905ee4c0ff208044f6facff0474abd70323d39e83eb198a5dc",
+ "chksum_sha256": "f182583f24a384c9d3afb6a5ec5e77954bde690eee5ae92bdc867a7511a1962a",
"format": 1
},
{
"name": "plugins/modules/manageiq_tags.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "dcfa97c470a511b84140685853c841268e4f6c3823bcf98c28f2bc915af69cc0",
+ "chksum_sha256": "42a688822b02e65174cb1b88855ceb33cce04438a2168e8ad2f6cbdb0e5a9e7a",
"format": 1
},
{
"name": "plugins/modules/manageiq_tags_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2c77f48b292aadda5e88e5e2d772aeb1c5e63d2c2b82d999035bf8a089040196",
+ "chksum_sha256": "4772807ee36350d5c875dda03fa62cb660b709fa8c1d13a2c191f6c74b4abc07",
"format": 1
},
{
"name": "plugins/modules/manageiq_tenant.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "287d73123e32efde317cb17ed61e274819100a4958aa2246b390c1ed94426441",
+ "chksum_sha256": "a2061399c076113241f0bcb1e2bdf76408d198a429452e1093eeaf50f3e6449e",
"format": 1
},
{
"name": "plugins/modules/manageiq_user.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f6e36750b0a297e8f06969ef7d7023829ce79fb1342c6fb7dced840c5a9a8fec",
+ "chksum_sha256": "f73185fa6bc0486c9b6100509b97043e2498f419456468f5cfe63834925be9fc",
"format": 1
},
{
"name": "plugins/modules/mas.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1845b14d27fed8a50d2ba33aa35c4f31575112cd805746ffad0c2a8cb5f46cc2",
+ "chksum_sha256": "0341ed287b39d933ac642c1ae0e346cbf09d19b562601b1006fe91d7257087be",
"format": 1
},
{
@@ -4365,56 +4736,56 @@
"name": "plugins/modules/mattermost.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "052cee31d1efc1facdd72f7f052aa11ecf2e2328ab797538772de9b85e420cd3",
+ "chksum_sha256": "89c41eefaaab524856f125b6b09d4552308ad87f91089461d731eaea56f57a6c",
"format": 1
},
{
"name": "plugins/modules/maven_artifact.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "215b47621c95e9cb8720635bd7d51ad4becd598b467356f53b0a613d4f201b60",
+ "chksum_sha256": "f440294251bf64132848fe8b146a0b77ccdb424dbb94ed2e22d1eb554384acc3",
"format": 1
},
{
"name": "plugins/modules/memset_dns_reload.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "67156adb1ebb682de81595202295ffed3314bf6c42f786cf326b7c235082dba1",
+ "chksum_sha256": "5fa8801c4979e9375737785a0fcbccbc4fa526cc1f8de25fcfad0344cfe90fa1",
"format": 1
},
{
"name": "plugins/modules/memset_memstore_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "963abdb965c9991ec073a299cfae1c608d69c2330d4d885359799118ae9219fe",
+ "chksum_sha256": "002603d29f0971354b781950e613c7cc1fa060134164d30f16c8e4e0a6ef79fc",
"format": 1
},
{
"name": "plugins/modules/memset_server_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "46880ab646a1161611e2365d2f7c59b2bf178ef0f8fb61f8b08ef9bd2d01dda2",
+ "chksum_sha256": "e8800bd5cd967aad21864c3e48c4d892fc1c0c54a17684a13f62d5b930c3dfc8",
"format": 1
},
{
"name": "plugins/modules/memset_zone.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e0b008baf1976bbb58f8a1a74ddcbffb38d16ce7f812cb3aff22512cd495f03a",
+ "chksum_sha256": "8436fe873c41770bd54fc3afbf5abcab3fbd8f5e6070a1581bbc4838aa8c3a41",
"format": 1
},
{
"name": "plugins/modules/memset_zone_domain.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b176e85c5d585b0c9afd3234798cf820310f46c83dd33f61bf59fa3396d6765f",
+ "chksum_sha256": "8eb6c0f93cb41190416e0a6b7679840f38233d6c958360e4fc5403c68f86a2c4",
"format": 1
},
{
"name": "plugins/modules/memset_zone_record.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "60dcfae793c50c6ca8eb2377a46c962ec34df88e5b694f1dd8a0b0b00277e7ca",
+ "chksum_sha256": "e39ef79547f1d5114cedbb44202d78aa30a815583bb6cfb290ba9786586552e2",
"format": 1
},
{
@@ -4428,63 +4799,63 @@
"name": "plugins/modules/modprobe.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1cfb6e93ccb524a5e73a509801cc081f89b05743665bdbf93eafa8bf19e5e205",
+ "chksum_sha256": "81047aeb7e22ce60f5449e9b699869fc5cb167283df1a5b51fc22c1a8a94591e",
"format": 1
},
{
"name": "plugins/modules/monit.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4527c6ded10d22fd9fbe85227c85583e889a00abef6070b81c305fb3829efc8c",
+ "chksum_sha256": "af1b3cd9ce11b30e3e5e658529c26baaf21d073b8c18d7726fb580f433636b8f",
"format": 1
},
{
"name": "plugins/modules/mqtt.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9737efb497e1d65a7e04201eeece3221930f214ffcfca19c5fcd3815d88bddd3",
+ "chksum_sha256": "b98cd4ed31fe1ceeba43ed8f2289efca4d32a0ad945eccbf0a880e0b9d1830dd",
"format": 1
},
{
"name": "plugins/modules/mssql_db.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "58f7934c24577e50ff17e6a17c973c0f2ee238585c2e36a7db9da169a88b5df3",
+ "chksum_sha256": "5dd4ee9af6a312e76da88877c513c08469f3385a793b655cd759690c9ed15aab",
"format": 1
},
{
"name": "plugins/modules/mssql_script.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6a84081c1ada3a2365c6222391bcfac644ee43d27b1ac96e709593ff91aaebd3",
+ "chksum_sha256": "deda9a3d8c178f265420fc28658acd8e93b348b9e1ed39aa2b600ad34745cdd0",
"format": 1
},
{
"name": "plugins/modules/nagios.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "67262bdd025c90494cf2cba2e626d9b9407b953e30163e3cafd95f7dc4078211",
+ "chksum_sha256": "a089e8531a6a2f5d8bc8147823c1735a6528bac6f8ec050c36a8e36d340a155c",
"format": 1
},
{
"name": "plugins/modules/netcup_dns.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e43bdcff828eb8a5f731171c24fb8e37865480ff755cb49bbce04ddcaf36a49b",
+ "chksum_sha256": "c24a2dd6e99912970f59229a132b325bc432a46bdb8a65251680986a81d5fed8",
"format": 1
},
{
"name": "plugins/modules/newrelic_deployment.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "63382fef809beba707925b40ef71e7e0991ef61a4b966482e3ee203bdb574613",
+ "chksum_sha256": "3a0fd3703350dc482e2e47b3c728f1011a95c59b6ea2509a84b0aeb5d06727cf",
"format": 1
},
{
"name": "plugins/modules/nexmo.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "40bdf7a7433942e79e6c62a69c4912d005d7230e9df9956977b14a6624b7fffa",
+ "chksum_sha256": "8476d8938d237aa92945d91fdc40a53fdafbe03c1d0d88b7b97b146b226c6a30",
"format": 1
},
{
@@ -4498,77 +4869,84 @@
"name": "plugins/modules/nictagadm.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d27604d65e86fc707114f36f0d4045ffb721e648e1fb9374b84500ddce6bce0f",
+ "chksum_sha256": "651e04ab518ef6829908dcb815b2624d0b0898d6edced250caaa430c9377bc7f",
"format": 1
},
{
"name": "plugins/modules/nmcli.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "73e72cd822c2b4191b29c332b9ba8ed686a0023be4da89b9e578fd549b9b59a0",
+ "chksum_sha256": "04fef80fc4f380de8caa7d9b81a40b1ad6e224b9a34b7d384d82f0982ab0dad6",
"format": 1
},
{
"name": "plugins/modules/nomad_job.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0000e71629d0423f09de699378fec5a9af5160d18ea1abbd8c46743575f2ddd2",
+ "chksum_sha256": "35e8820eb223b21f94ac9ed9e0fe64f22c92751b1fbe54b464d6b34c6425c3a2",
"format": 1
},
{
"name": "plugins/modules/nomad_job_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e1849d4448a72a45405c4b06969737075066c6d969e47b1b7c806a9fc48ac1b5",
+ "chksum_sha256": "b6c682fccdc8437f4e0abc68dcaff42a4ab333cbc509eb3f0729d44f2b021db9",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/nomad_token.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "47d9dd7a400f91b171738d214301969818e65fac386239babd76d63007ae9254",
"format": 1
},
{
"name": "plugins/modules/nosh.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "27102003c63b13a1dcae92ccf912f8103ed630c9f33b27c40d09cafea6f22e87",
+ "chksum_sha256": "28d064c8cfec1fdb09e4ba2c1f7a1cf9ce4172343b8c34d0daa172e9e627d3d8",
"format": 1
},
{
"name": "plugins/modules/npm.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7087dff9d3c6fc79626ea106b60720dc04fe99d7e88c30e9c9fd83ec6d5f8529",
+ "chksum_sha256": "d4553236232002b1854f97979b593f5f32853637be3bf1a0a5c93ea5e8e7550d",
"format": 1
},
{
"name": "plugins/modules/nsupdate.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "58367cf4e6fd72c72a6bd003023d484d7ad3c827a962aa47920389ec43d6a6bf",
+ "chksum_sha256": "6ec291620632c7d0f39413afe9f3e3a8b884d1424d2cd0623644f421a0ca1a0a",
"format": 1
},
{
"name": "plugins/modules/ocapi_command.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d62a2cadb602263121a6d48423e58664a2875d3e7f3d936f8fe7035ec43ac9e3",
+ "chksum_sha256": "6249d70d40f2b4ecd60f155363d1d12b77c67e39240b14fc9a5468961fd74aa2",
"format": 1
},
{
"name": "plugins/modules/ocapi_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "868c13d527560182f2b8769c31fb5259ea8e9f3ce7cee9dc63b0e65f4d02856d",
+ "chksum_sha256": "f18fa10b32c145d9316f893c3ac505443d67a409e51c773b48465168c9d636ed",
"format": 1
},
{
"name": "plugins/modules/oci_vcn.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9544fc21fab87d851fe3878a7696fb3f01b8229bb347d35f58bc4079568038be",
+ "chksum_sha256": "40825a966106fe3d6ac2fed2375f28bfcc800e78c3495836daa1d3023e2b23cf",
"format": 1
},
{
"name": "plugins/modules/odbc.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "80377d34f6be998e7767a3aadad37f34e2d84ecd803f86e3520230da21e328f1",
+ "chksum_sha256": "69575d80b292429c3ffa42834a00c22555801610091fee4b8913b0e74aeb7cc9",
"format": 1
},
{
@@ -4596,189 +4974,189 @@
"name": "plugins/modules/one_host.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f4d38114de7384770892120ddd618f13eeff9c1506ed1758d637c88f5fa92267",
+ "chksum_sha256": "5740c4f8590605b182e66e8243a0622fd5ba5281c4088f9583d5814c75a1dfa3",
"format": 1
},
{
"name": "plugins/modules/one_image.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2401889a75569b4a76e7520ab5e6926a9c935af99fc01fb618dd8e13dc031fe0",
+ "chksum_sha256": "dc2a5686ec309e3e98dcc542e3f0cf1260ecad3e5c86a89b5b4ff88fddeded08",
"format": 1
},
{
"name": "plugins/modules/one_image_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cae82bf8f9c6b70088a7b0dc28b88618bfae78a8d4b2ddb8e9edc1f3b16e674c",
+ "chksum_sha256": "ea6b5cd74fb04cdcd4400a33531a33a84a1192e901cc6c6d2e1069150f0b1054",
"format": 1
},
{
"name": "plugins/modules/one_service.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d36d93fa6f5709527ac774211b53df76393ed322878376b5096c97a6eef21267",
+ "chksum_sha256": "ea5c1ee345dfe2df25f6c1e54a741cf075c6d372fefc90ba6bd464d102cf94be",
"format": 1
},
{
"name": "plugins/modules/one_template.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1dedffde8e661c8cd92059444f37fdda8b9d8f859db7b6e45a94877db78a8db1",
+ "chksum_sha256": "9ccfcaa067bba708280e6d942802ef198657ef84cfad209115f60fdbf9f749d2",
"format": 1
},
{
"name": "plugins/modules/one_vm.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "eef28a59197d6d0defc65858e43a0f7e89f080adc04f314fc6aead874123f970",
+ "chksum_sha256": "56d14ae7d9db52cbbf2642ff3f111febc7f2a65efce239072a1b57c23b7626c3",
"format": 1
},
{
"name": "plugins/modules/oneandone_firewall_policy.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0d4d2c4f97da3a4a4b19c508be9a3cc68cb48ad5cbc5bddf43047823fe95569c",
+ "chksum_sha256": "d44ffeb74fda22124545a5822582a1a3a4dc972b6433632c920a4c75bea181a9",
"format": 1
},
{
"name": "plugins/modules/oneandone_load_balancer.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2543504063531517ad213cc14171c8d143dc113b2e283885483ba9a41792788d",
+ "chksum_sha256": "0a0211274b23fc36a01068f2463a57b49ad698c25ba2db42a4745abb442bcd51",
"format": 1
},
{
"name": "plugins/modules/oneandone_monitoring_policy.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c2bd7ff548bd89b760a4d0e1ab0bfb5061e8199f5a566eea750492fb0cbf2f92",
+ "chksum_sha256": "7a32514c22ff7cd3fe0e3c027556d002572e32242f7dd538bcf079e2ec226589",
"format": 1
},
{
"name": "plugins/modules/oneandone_private_network.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d7579750ca046b8e114f4e542c8d087dfa8bae65fd848f4352b3a6ee5708bb82",
+ "chksum_sha256": "fb8832c9b8a42ae03ea7378ad8fa8546c56948fb7b4afb21d6ae05fa137cfe8d",
"format": 1
},
{
"name": "plugins/modules/oneandone_public_ip.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "20a161bc781932f3a564ebf7105c0659d56350a5b749a52eba1894707667ea87",
+ "chksum_sha256": "e0480ca5d08e09c399b66132a5dec07d1c3131882436f927f739ad81fd2f5fb7",
"format": 1
},
{
"name": "plugins/modules/oneandone_server.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bc5c8df04b6a65642acc6533a9f895b435c08844519ed5e89c3a35e5315a963b",
+ "chksum_sha256": "d69b524f23163c4f45970260c354c20a7a47e90cd758931b94a770aa6b19aad1",
"format": 1
},
{
"name": "plugins/modules/onepassword_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a2c8cbf0a37cdf4be5ebfbd715166df56bb95ac7f3b16f51547df4e0c843b148",
+ "chksum_sha256": "535a90fd2ffdec84d303ef731688412d3c5c257db086720ea1c46fe81ee8e209",
"format": 1
},
{
"name": "plugins/modules/oneview_datacenter_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0ead61d33f5b227f8c36d6a543a023a7406bbe8608a1b639e1f360a0c36dae67",
+ "chksum_sha256": "8f169643dcc8f93fbf6e2fd0fa8f73fd118c4ad2db8b2b6ce2b6cbab9e96c0d0",
"format": 1
},
{
"name": "plugins/modules/oneview_enclosure_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4e2bb44e9658481f1395f466f0a311857a7706cd9c3b6acf92ca5e049b70c997",
+ "chksum_sha256": "7663a36d24382c51b81f0c0e2a7adcfcebdde7806269bb2bbfd47bbdc43c4eea",
"format": 1
},
{
"name": "plugins/modules/oneview_ethernet_network.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0bf9e298685d31e6e3c65e90d310143a5fa73b1bf34d9d56c197f20d4beb2794",
+ "chksum_sha256": "6eb248e8730ce8f984b9e113931438fccf5532c715f2bfc66035670d8e1eca1f",
"format": 1
},
{
"name": "plugins/modules/oneview_ethernet_network_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "91dbf75f4ac93983c56f5a00786b42f0c3f8e265928aaa583e414657c6440a33",
+ "chksum_sha256": "ed2abf11904964f0ee289b37935aa0402bccba87ec1df58ecb7f3b0f4f968ae2",
"format": 1
},
{
"name": "plugins/modules/oneview_fc_network.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c98a3a0c78e7e0d047b0610f1ddf0fe4cfc9b5fda4dfb5dd4f9213490b2fb62a",
+ "chksum_sha256": "8d53971862a50c07397592488b0f07a2bd9a2e8bbc5f1558425e1c4e3a0a3671",
"format": 1
},
{
"name": "plugins/modules/oneview_fc_network_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bda33c70e7a21a37afbc964f92991fd9cef909655b45b7763177f87b5ae17b49",
+ "chksum_sha256": "5878b439976a1914a3b9d86eefc605b7ca029dc7a44fef9eefdca8ef2b60d6d8",
"format": 1
},
{
"name": "plugins/modules/oneview_fcoe_network.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d3b4739ad5cd6d89823d606b2d9a39b3def0e2967d6f8b04ae7f3fe2a821ed67",
+ "chksum_sha256": "236336f507fc4fba40a0c2661adf6751943ca147d14452e981faaecf57593597",
"format": 1
},
{
"name": "plugins/modules/oneview_fcoe_network_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "732dea52b31191cf263fb95460247631e1d4cbfc720472ef166842232ba252a9",
+ "chksum_sha256": "fcbb79de6a173ec67ea8bb683bc872acc28b40c7d38687b7df32ac5847d3fd61",
"format": 1
},
{
"name": "plugins/modules/oneview_logical_interconnect_group.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "21f72a3f8ea9ae75c8315b7a7b06b969f4b1a07c7da448cb70d54f484f84667b",
+ "chksum_sha256": "42a7e1b254f79f463bd1c018cdddedf71fc9712a21a30688dadbd83ff1b30236",
"format": 1
},
{
"name": "plugins/modules/oneview_logical_interconnect_group_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d5f38d9022dbcba12146d6223b0c82f4ebe7c9b8d307e4fbd01f3699b75d7386",
+ "chksum_sha256": "583e1c7b067b56f109aa83d8fdc6a9f0649a0657309ebb670c610dbdad44e8f7",
"format": 1
},
{
"name": "plugins/modules/oneview_network_set.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ba56e78c0e00440905d2b606a307fc3837f9c8f8b083c625f61c99b6c66790a4",
+ "chksum_sha256": "f4a7c3901c5bdc621c501601c5b52c1cea2b2d0c5a51e26baede56406fbea9af",
"format": 1
},
{
"name": "plugins/modules/oneview_network_set_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "79c582f5ee67a8fa4c1f07ed6895b4c5ad632b20b7fb60d3f8e49f4fd0f1ff3c",
+ "chksum_sha256": "16eddfb598ae1d2c57d4eee14662e75bdc1f446d99dbfa727341b21b93f4d9a5",
"format": 1
},
{
"name": "plugins/modules/oneview_san_manager.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9c6bbd6531cd68ee5480dab844ee81d3952dfb39c8cdfd7f06ee087358c92dbf",
+ "chksum_sha256": "ce56d4b988bae1515af0f303714c60e59542915b1f4ea3886ed2204c501e89b2",
"format": 1
},
{
"name": "plugins/modules/oneview_san_manager_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "45dca5e38ba6e094cb680adfd28624685d0cbd0e4a47f2cc42b1e811c253772b",
+ "chksum_sha256": "43680ae5eceb2d6705329096405e35a2b83b526d249d61a9159dbdc242b6041f",
"format": 1
},
{
@@ -4799,14 +5177,14 @@
"name": "plugins/modules/open_iscsi.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f464bbe532ae7e1106e90565ac75c492fcfbabc080e5bdcbd565e6a3c192233c",
+ "chksum_sha256": "72857e4b5250997f53d643fae355b85c79e9b9b2afd2c4f6a84c16f64bab5324",
"format": 1
},
{
"name": "plugins/modules/openbsd_pkg.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "22c4c4c87144f46406339180177a2dff11dde76122f78ab358e32d35065ac2a5",
+ "chksum_sha256": "aa5f9a76a91826cfcf340da018cee24dec149b5d858e9161023cf94e5867ac09",
"format": 1
},
{
@@ -4820,28 +5198,28 @@
"name": "plugins/modules/openwrt_init.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1fa03eb5cddc2d8deae385c4bdad8a5e8246fe91046cf9ce6e4b69042e2e64b2",
+ "chksum_sha256": "8c0a6eca597f2757132414fbc7863e7a72f6847905e36418d3d5a1d5333c3867",
"format": 1
},
{
"name": "plugins/modules/opkg.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "601f102a1c8cd8f88ab07b4fa35e785db85afcfa92ef130e62e572a6c923c275",
+ "chksum_sha256": "6fafc31bdc0f356419069a1b9f7c4f56d7ea2ba5059eecf3ebda5989b314f8a3",
"format": 1
},
{
"name": "plugins/modules/osx_defaults.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "362ae9073e6e548c4dad2d5924c3b823b12007674293ed337937df17f0bcefc6",
+ "chksum_sha256": "25083c7e2f8c702fd3c2739fe6527c69f3976e9bcef0263c3f8bdfd4a28746a0",
"format": 1
},
{
"name": "plugins/modules/ovh_ip_failover.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0b9b9566d7d0873f0bae9c4ad68fba0c7459534263ae0b8c729115a5e3eec532",
+ "chksum_sha256": "60fbf0d6b370f7c3a9bf89f176f4404ddfd1f26df250018ce84fa1d6a03b10e6",
"format": 1
},
{
@@ -4855,133 +5233,133 @@
"name": "plugins/modules/ovh_monthly_billing.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0e3cf12e8142224c835005cab6b805414349f5f46a05fbca2458aa381ae6e495",
+ "chksum_sha256": "292c75511b4cbf0444594f500a65c50612feccf011c0e380c0313e8b6b5f318d",
"format": 1
},
{
"name": "plugins/modules/pacemaker_cluster.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b761cbcb34a0fb34ee91f1961c8240a1850bb2ccd3f956fd4f1e3771302ccc21",
+ "chksum_sha256": "b7315a48d70ed0b3804c69343fd6361617669588c7812add4f0a3ff13e422788",
"format": 1
},
{
"name": "plugins/modules/packet_device.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "99b81cf01b9e511cb398b70d0ae91a3fa3dc0fd99d09a02b76c78950bfa00949",
+ "chksum_sha256": "50ae79c5202ca9aba4e54b35f6214db4375730e71130ff808737e519977720b9",
"format": 1
},
{
"name": "plugins/modules/packet_ip_subnet.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0bd48f1465a85505c88d0238904f073c9c13645d9102a7fa7706248b216cc7bf",
+ "chksum_sha256": "b257ea9e2a825802723df437876ad0cdbfe19f02508ba4ee3a35a461c841361e",
"format": 1
},
{
"name": "plugins/modules/packet_project.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6c33e79041bdfec0b870a3e869857f56e57ec17b6b9681d987d68e85cda5f9f0",
+ "chksum_sha256": "f212282ca4120d5c608e19301989fce7339efed96e47e61261594a43a42df8f3",
"format": 1
},
{
"name": "plugins/modules/packet_sshkey.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "24704cf647370970962dd477bc4c90bf8e503f331ad27bf242b1699737d16cbe",
+ "chksum_sha256": "5f6b9cc485064e9f484820f4fda33d19b092fab0aa55c14e58a3b0ce8eb36cff",
"format": 1
},
{
"name": "plugins/modules/packet_volume.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "94e3880ff25a60ab0c75fccbbe8b3fbb0e205e8aa5dfed53747706ad2aab032e",
+ "chksum_sha256": "ab6481ec44f12708564bdcc2e800f3084e9dc3bd7641f06fa29b4f2c7dd92cf8",
"format": 1
},
{
"name": "plugins/modules/packet_volume_attachment.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "29aee868278064f35c4b708fd8331f3b5455708f09c957008e0525c231a4e476",
+ "chksum_sha256": "ce755f9e4f5a40c614413717e5180090d3e34270b7a3dcda28ab17f52debfd55",
"format": 1
},
{
"name": "plugins/modules/pacman.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b70c839d4fad92b205572f88bcac91c39fc858566bd1b781d7a2c418cf0ce5b7",
+ "chksum_sha256": "3e92ff37a394cf3ee414ca9e55e928fae7d2875992630b8e80e7fad1c5d1273f",
"format": 1
},
{
"name": "plugins/modules/pacman_key.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8668d6e39f78c145841742a54e7914b9a9639d48a3fc73a74c95cd5fe2b139bb",
+ "chksum_sha256": "ed24b00e6350be27201aa0cde72f4d549755f2f78ade029fbcbb0e4b7b563dc4",
"format": 1
},
{
"name": "plugins/modules/pagerduty.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "827b0403a098b677ad7648e0c0b806de812b4cc9286c9ff4125579ec11211a92",
+ "chksum_sha256": "6da5163291f420d74945b2723ed5bf0acf0e43f9280793c17554143bbef6cb75",
"format": 1
},
{
"name": "plugins/modules/pagerduty_alert.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0ae2718f2b5d083fb37c02fddd2f2315edc16b9ef831ac37a95ab7a6e2f6e057",
+ "chksum_sha256": "e461db79f5ae0f4f5c74e2ab150e0a3d075f90f272cf3c7a4496a73ab7a1a286",
"format": 1
},
{
"name": "plugins/modules/pagerduty_change.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "eccea5f30455ff59c5fb7e0b03e92eeec4c0b39ce8bdbe94c65c51ba1f24a895",
+ "chksum_sha256": "13f3a20302ece4ae73d94292180ea986b8d24cf05c5c5c587481dd3fc55cdd2c",
"format": 1
},
{
"name": "plugins/modules/pagerduty_user.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8e9c07a48f2cd3b51a5c50717e30334ef853536e5c31031dcf23242a1fd64dac",
+ "chksum_sha256": "9251dac8e1431b9bd0ebf5057a795d168fe158d6b0bf92b558ad3ebf8e76413c",
"format": 1
},
{
"name": "plugins/modules/pam_limits.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1d91a2175af8cb34bd9c20ccd042d6c5ce12e39be8faf6c49eab3a2ab7c104f5",
+ "chksum_sha256": "40f8d0a4d1ccd86528694d9088c7574b90f6929fa20d539ceac8d7c3d4eec710",
"format": 1
},
{
"name": "plugins/modules/pamd.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fea2435d3591ec72e08230d6551a2cc08f8d4afb5a063e0b0953abf68d43d438",
+ "chksum_sha256": "4461074570a8bce91cdb3932727d9b37b0071e082ff5de5661ce2654f6f63063",
"format": 1
},
{
"name": "plugins/modules/parted.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c66bf9e1617bddad08b0a96a7c1df92828967e6edeb7ce2efc46d624a8bf12b0",
+ "chksum_sha256": "d7a222fa387aae5a78895f665d587f84416ad11f90b049a6d08b4ad8eca1886a",
"format": 1
},
{
"name": "plugins/modules/pear.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "60344b890209df445edec4f97458af01dc43e8db984e258a0bcecd9bb2ada464",
+ "chksum_sha256": "ddee63fc547bacc2faf777c975545bb78dac2f6dff1daa9b7741824337c0bad8",
"format": 1
},
{
"name": "plugins/modules/pids.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7bb378284631bdecab170086c5a5421ccd2eff1b660faff0f3df8b7650ad3e61",
+ "chksum_sha256": "7350069a2e0eeb3c8027c038379d1bbb2fa0d2e12f8a7cc9969a6cf6a4bc80fb",
"format": 1
},
{
@@ -4995,28 +5373,28 @@
"name": "plugins/modules/pip_package_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "90bff70ebcfe011f46b95ab1eb2da290b1fb16d671fe56079ab959a24768085c",
+ "chksum_sha256": "302fbc44c44225abc82fb5b3b9e8ce42bfbd039af72fe235543790c34f8abc47",
"format": 1
},
{
"name": "plugins/modules/pipx.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "02827e663efc2960091832160ff7ebef6eb8c5909aaf7a211e59bf6f12ef7aa4",
+ "chksum_sha256": "4c808a7b43647413be9b220f668517b0a0c263038c5c61e757af52b989942760",
"format": 1
},
{
"name": "plugins/modules/pipx_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c3cca85f8398db8755cf65c54ecf79d34f036d148cec69bb0cd03f4602f316d7",
+ "chksum_sha256": "85e936162c11a4fd2736b26644903c3533842d31d92c3a6161dc29ef0f36f3ed",
"format": 1
},
{
"name": "plugins/modules/pkg5.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bd3e53997319e1473d1e4faf830b2bf57c21737a72c99ad022560033aeb2a073",
+ "chksum_sha256": "64feebf19704a6c42841471d1b0cf4f398f7410361541c91d274a35d01813d43",
"format": 1
},
{
@@ -5030,35 +5408,42 @@
"name": "plugins/modules/pkgin.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9b742c95e442b624853223f54226001fbbd88268179f841e044c4eb0d9d8f16b",
+ "chksum_sha256": "1cf640944de02dc6028c8a0130bff6a3de7ee26a2dc6045b45950514e0bf8812",
"format": 1
},
{
"name": "plugins/modules/pkgng.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5640531afdc589158458b5cdf712f4e4a2d67df8129531028190e3d4e4d753d5",
+ "chksum_sha256": "66218eb8f8d9c18fa948550eeb614c2a2638509db9975124c245669c9816d7dd",
"format": 1
},
{
"name": "plugins/modules/pkgutil.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "86e47da21fba937908855043d154e241452d0deff13b2eac6210905b1701f07b",
+ "chksum_sha256": "8ccd30305460580b1b88f37a2f8067fcbf8d5c4a527132adeb36550533c097df",
"format": 1
},
{
"name": "plugins/modules/pmem.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c7e827132135a87a721efe2d6c9d58ce8a41e185bbc9084bfe813ac8b777c136",
+ "chksum_sha256": "26e875ff544a036b781b4e3173927c9f1a4fbd13b6e29397a1cb414988992203",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/pnpm.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "2fe13ce86afe1bc8dd98d9da6d77fd4360308348a55f04a53743c28c6d9afc92",
"format": 1
},
{
"name": "plugins/modules/portage.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4a9d8d46d4ad616cd560b6933287d90ebf00e36d84482dc3e6e49fa42bb198a3",
+ "chksum_sha256": "70474d22e85a3d8d191e870dce4ef4c4e0804ded42e6cb258454a313ef2f4155",
"format": 1
},
{
@@ -5072,7 +5457,7 @@
"name": "plugins/modules/pritunl_org.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e72265d0c72d3dd91a0c739eb73c150b5a438edb0debc6e12497cd1b709d9457",
+ "chksum_sha256": "ab4772625ea584511c04ae0b73ef0c3d6a7c05a35c38999e2529ff7cc502b646",
"format": 1
},
{
@@ -5086,63 +5471,63 @@
"name": "plugins/modules/pritunl_user.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "65dafbd54661337ac5c244d52ae1e4b80e6aa92d7b78fd3602077b390ec28a25",
+ "chksum_sha256": "a2262aa12c68c532c5630e80ae0d008b99fcf91893b74607fdd12b2a1c4ddda3",
"format": 1
},
{
"name": "plugins/modules/pritunl_user_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "29bcc9f395f5e956b34f787eab78f2233139a90db3984716e570ea3e9842d4bc",
+ "chksum_sha256": "099d579529c415f4d2b1513822873a4f057bf6ac4d67397c4b4c8087dff4d31a",
"format": 1
},
{
"name": "plugins/modules/profitbricks.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7e4c6262c494cfbf82248418fc37b9d12e68fc819d38defc67c1c23e58f12765",
+ "chksum_sha256": "80a20e582046ba0cff14fc08b992c76078dc1aa3535de744f96ce60aab40e1a5",
"format": 1
},
{
"name": "plugins/modules/profitbricks_datacenter.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a818198efa5b964bed4a2c06eabb42e70daffc64d24b520c8d127790035b550e",
+ "chksum_sha256": "471138b8725b2fa85c929eca1a10b5ec3cfd1b79a5cdb916b2cb81746963e4cd",
"format": 1
},
{
"name": "plugins/modules/profitbricks_nic.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bd644929dce276dceb3eed2c396f3996e9bbf7905cb8d3333ed4f7da9d84dfe4",
+ "chksum_sha256": "5aac6671ae9669ad43029bf88677b8661aa0a4443dad9068989c643ca3a0271e",
"format": 1
},
{
"name": "plugins/modules/profitbricks_volume.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "32ef48b857e64c0d5c4b555173a9c1f7ac94c630ff3e36a9a7605354989f046b",
+ "chksum_sha256": "4726eee5cff495e5e05f9004ddae2a92a4a2f16fb037ed8e1b10a8719d5401f8",
"format": 1
},
{
"name": "plugins/modules/profitbricks_volume_attachments.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6bb70965cedcee4229d3f509b0f80ecde71d59452f787108f799822657058649",
+ "chksum_sha256": "2ba94ba4bd8e280b26b0a184d3c8cd02acc8650d393b643d76aae828a33247f6",
"format": 1
},
{
"name": "plugins/modules/proxmox.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c2bfb21760298dc51986b35e7fd97641e16aa50214e5dac43cecc1b29787fdc4",
+ "chksum_sha256": "cbaf13c0a56641888d956a3f66827656027362667c00a5da98cfd9fb9c53709c",
"format": 1
},
{
"name": "plugins/modules/proxmox_disk.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e9d3ee1ffeecdd4061ec6a2d8933fd6617ad2133dea517b724543534440a13a9",
+ "chksum_sha256": "7eaf98c0876bdf7959cf06e68dbe617c86dd61c45dd1614d86ced3a3b00c8a6e",
"format": 1
},
{
@@ -5163,77 +5548,112 @@
"name": "plugins/modules/proxmox_kvm.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "108e41bcfc715a4afdc3858b2014aa4d6a738a881df534597863f965550f6f2e",
+ "chksum_sha256": "c148eb6fca047327772da3210a9fe947c4a14fda1405836f0f4c3ffa58da5385",
"format": 1
},
{
"name": "plugins/modules/proxmox_nic.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "114afcf1b6bd37a2075b4d9f1725d614da6ca3a43204995ecf155ebb39e33613",
+ "chksum_sha256": "52492a58319b75a634c109c5951be0f9fd1bfced0ac6ee97d00b103ab76087ff",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/proxmox_node_info.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "3f7053d278a05a60894b5cddb8091e09a27f6d6070b1f41282259cabb41960a1",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/proxmox_pool.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "83e86f259c2483e804efbe2966ead9e2eb38b3e1007ff6420e647eb57c6e4e17",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/proxmox_pool_member.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "77fdae49fd415dc3a8f88139a023bb2c2180d5d60f7b493aba9ddd25b3e6fb52",
"format": 1
},
{
"name": "plugins/modules/proxmox_snap.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "502dfe87410e493e6133260ec1a6ba45e47b61cf7ff7afc3ec2dfed42bca7c63",
+ "chksum_sha256": "a79a064dc6522db3c959e678ae66e54e8fe113fa6cca38c379824f429a9230c2",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/proxmox_storage_contents_info.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "207afdc6920a8da3a49b025dade19f6da69bccecee48ef4c1e8508c3baa3a509",
"format": 1
},
{
"name": "plugins/modules/proxmox_storage_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ebd62128dc3ffc469bb308b2959edc19b852442939d4a4b48114ed51f235d9af",
+ "chksum_sha256": "d860af5716ba13e1c0260dba4bcfb4e31d33c9c667063860565166d0ea766d72",
"format": 1
},
{
"name": "plugins/modules/proxmox_tasks_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b6f332dbfd66dda7fffc49c1b72872f4a2c9b746e8c8affba649f521f138ddf7",
+ "chksum_sha256": "781bdf531b30904b52fde1a5da54433b2c812b6efed34ead3733149f7b16dfbf",
"format": 1
},
{
"name": "plugins/modules/proxmox_template.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "747049ec9db4e6b920af301db484d629b52020fbf987c7689e4c0d34cfe429b6",
+ "chksum_sha256": "9c24e106b6dbcfb6a8d5830b7240c6c39bf6959f56591d8ad21cf4023a3cedd6",
"format": 1
},
{
"name": "plugins/modules/proxmox_user_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "03bbbbf2c76f4bd992f37ecc135b98aaa5ce5a77c670b4d538ad37701a4d6920",
+ "chksum_sha256": "085403351a23432173b41649b7bedd8653d48a4f690b427751f4ab09a99195d5",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/proxmox_vm_info.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "4850ad8b78e13bee186bcb49d2e9682723b86ca3fbf4dfba67d4760fc14fdfca",
"format": 1
},
{
"name": "plugins/modules/pubnub_blocks.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "50a1f072c611d640c217f7a1c16836f288dc4daf9eb88a58876a75ffb097e6a6",
+ "chksum_sha256": "16bed705f00c9c293ed52727d4a5c30043b1e23ef7c723ecb1d60012027952f8",
"format": 1
},
{
"name": "plugins/modules/pulp_repo.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c210e8698517338f402ebecf40f206fd3c032b9633118fb2c0c623b902c04754",
+ "chksum_sha256": "d41fbd39222fc77731c508810eb3645b3bb642ef5f16a55062207a953d969242",
"format": 1
},
{
"name": "plugins/modules/puppet.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c3d32772e05944219bf0211942003088474d1172a03b202ddd30bb1d24e0af25",
+ "chksum_sha256": "853adf09fa19769befaa28faf6c986ecfe5d85890a4db71fa0a0e64f08f9ec42",
"format": 1
},
{
"name": "plugins/modules/pushbullet.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cc4a405e57542b0d5a3b6f0baa5a9a4f9f9b9b13e8f09756fd390122be801292",
+ "chksum_sha256": "4dcccfe20b01885cab7902f859e500cac1c055318a1da6b1a3fad66a78435483",
"format": 1
},
{
@@ -5247,161 +5667,161 @@
"name": "plugins/modules/python_requirements_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4c1bdcb4a1b82fbcda14ecff1073319ab2eb315775536ccff4713f0b8b29295b",
+ "chksum_sha256": "71e20fb07bd84b5da02e0860c14e526ac34cafa1b3a1b0cff29f99d5f2c2d740",
"format": 1
},
{
"name": "plugins/modules/rax.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "260a3f7830f52a926daeade726cb1b6215443f38a201991d8af5d9c6736a71ca",
+ "chksum_sha256": "d5d71364c01d578d124b4f7064cb0850562144e68bb8f8a62000132703cf2776",
"format": 1
},
{
"name": "plugins/modules/rax_cbs.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a6df24e7edaa990dd7b49cbb3b6f531d38c1a8d249672619ea44ff6a78d59f45",
+ "chksum_sha256": "be5f3f94c241633837d888da6abb20f1c54d204f0077147efba813a56f835906",
"format": 1
},
{
"name": "plugins/modules/rax_cbs_attachments.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c26bb16985ec14e3054fec4586dd05fbd7f60e26f129ef6cf20d101059ba2fc5",
+ "chksum_sha256": "bb83467fd0fdaf72e0ecdb7ccfe67e73b365edeee122cb339f06718364ea1a50",
"format": 1
},
{
"name": "plugins/modules/rax_cdb.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e12cf034cdff7a969f042b7f89db3e5fb74a7879d97461d08d32bcce12f3bb22",
+ "chksum_sha256": "1a761ea8d19fb0492b758b4408be987712f64078f367ad9fd1e00d434aaa5bc0",
"format": 1
},
{
"name": "plugins/modules/rax_cdb_database.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "88a8df01fcd5e1935d835ff1d9e562ff7ccb0b749a3aa8090dd18131f8f1ba49",
+ "chksum_sha256": "83ad50782f35ed29183048e2e16655f14fa5178bef73537b5a08c641b4df9e15",
"format": 1
},
{
"name": "plugins/modules/rax_cdb_user.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cd662b9e594bb429304340db2fbd6b75dcb8e730626c65118c733aef1c7fdf1e",
+ "chksum_sha256": "50013e448f5b9136937d1cb028de27da11b6e4a68621b3c10be61f0614f7fce6",
"format": 1
},
{
"name": "plugins/modules/rax_clb.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5fff8b0f831320066275a2d6a3da52c200617b7263edde722bb022c1250fa6a8",
+ "chksum_sha256": "da925aea1e07ae825b7bc40cc2e76feba747bfd173c3c6308c4a169b6a2f4230",
"format": 1
},
{
"name": "plugins/modules/rax_clb_nodes.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cdb205a8704905e0295ba5ac81d491b3a9ac3c286919ee60a313cfa31e880129",
+ "chksum_sha256": "4a3dd3afe7a509edf5b1caedc8cb047c3b7493d5b3624a64735054df080c715c",
"format": 1
},
{
"name": "plugins/modules/rax_clb_ssl.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ab3cccef409b9febcd4721812e80dbfd180d2911c4007b5ba4502f800a9b6372",
+ "chksum_sha256": "3832d09feaac166d5c2d13e974bef481a931398a016f492637036ce7eac1a4e8",
"format": 1
},
{
"name": "plugins/modules/rax_dns.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "40d58d336dac0ce8c20947614a2406970f665fa44be14de4e9cbc54fb965e260",
+ "chksum_sha256": "2538f8f54a408dd0874028a7af529c3405b537341e5b12cf813ad9c3ae3922fd",
"format": 1
},
{
"name": "plugins/modules/rax_dns_record.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9d274d0ec45eb6c0b52f9d7a2eefbd497dc3170e5709524185a2f4acd1e4ee81",
+ "chksum_sha256": "36e1fd0124f8aef93f7cff308588a7c3e31f13485ccc06a97a7a29b23e9d2f67",
"format": 1
},
{
"name": "plugins/modules/rax_facts.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "77cdc7820cae18792f79ccc1dcd1796d6524b68125e5b16f557ad1e42a1189c8",
+ "chksum_sha256": "ef7335464fa3a7419b240dfe9e686e2ef4492c066638afe2bec23f196deff45b",
"format": 1
},
{
"name": "plugins/modules/rax_files.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "12f4bab820a8d7127ba347533b91ef576e23054254fca318200babf024fea94d",
+ "chksum_sha256": "ea66624516f6e40f8e5325587ce6adfd5a7eed178d458952078fbc298e92191a",
"format": 1
},
{
"name": "plugins/modules/rax_files_objects.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "42de8366e999ff5713acce6ac485cbe50b5243bc3c407ef6c6db1db0e347e7d0",
+ "chksum_sha256": "52860b588511beb773f68c0986529ab633a7480dc93ecb5e72db9d319b9f22e8",
"format": 1
},
{
"name": "plugins/modules/rax_identity.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "29e9b9171bac729414dabd84332886064f91e13c57ffa1dc5431c7ca9f69fe6c",
+ "chksum_sha256": "6056f23c9de97fc542dd9a3d34153cb19bae33aa4b2748122efc19b091151e70",
"format": 1
},
{
"name": "plugins/modules/rax_keypair.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9da9266facce9e73ca572c9739bf671f82c815a9aef9fcc66f78d97a5055cd86",
+ "chksum_sha256": "8ddbde316caea7e8d4471de2f0cf977b9a5095731f6904347fe254b97c8cdee8",
"format": 1
},
{
"name": "plugins/modules/rax_meta.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b3ae22fc326d950ab0c23bb5357719891365479820e82aedc366e490ec03b0fd",
+ "chksum_sha256": "096049737ae955b66423fd4b3d106c744002e83868dbe94ca5eb38f43cde5d78",
"format": 1
},
{
"name": "plugins/modules/rax_mon_alarm.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ae89f314313dcaa6301426e1c0568ae49a0f898a1d65f9c932e26d05b68b9fd3",
+ "chksum_sha256": "8faccb337eb09e5dd3d179227a4f21701fa3ffce159ce1398a65e49cc2f949ab",
"format": 1
},
{
"name": "plugins/modules/rax_mon_check.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "07078968df29c55d784e1b69d824b362d2c929926c64331035a700ef80078d5b",
+ "chksum_sha256": "966510c6e07ecdc533ae86afe9aaa973f11554a0568766c158c5f77e118d7193",
"format": 1
},
{
"name": "plugins/modules/rax_mon_entity.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "67d5683bd92879c39fbb3fb7cb30c4c4fc4226606d41feedf0acbcadd54f8907",
+ "chksum_sha256": "f64424b7cd32fafcafaeb1b4c04b33462c50131758d0a94feddee8b30e55c908",
"format": 1
},
{
"name": "plugins/modules/rax_mon_notification.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "78695081b337a5513bce3bf7ed25148c78c59475962264fe56a9813eecbff2db",
+ "chksum_sha256": "b4d41086547e52926f63bef2cf657e39bfe7a18609721e6ebb43f11fff33e5fa",
"format": 1
},
{
"name": "plugins/modules/rax_mon_notification_plan.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "03ca5592440ae3e56654578c1663c340642952176039de5123777d78df585225",
+ "chksum_sha256": "626442facabc3ed149f70be592093e36c3e347ddf49a6c77b61316253a271b5a",
"format": 1
},
{
@@ -5422,70 +5842,70 @@
"name": "plugins/modules/rax_scaling_group.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "57ef0775660592e06c446aa1898d976eaec3b4fa4a785dbb1fe9e0b7273987e5",
+ "chksum_sha256": "8cb942ee1f1ea3ea1b45f3699ba09f3fb7827c1376fefefc6f6cd03635c42f64",
"format": 1
},
{
"name": "plugins/modules/rax_scaling_policy.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1e1fe0c9f1d54bc7ab5f4bdceade1059d6776bd3b7cfaec79baf18b37a62b24a",
+ "chksum_sha256": "ee634c11356221ce4ee2b1f65b0d3b4b1faf5f7b4df612df10efd0c525053da6",
"format": 1
},
{
"name": "plugins/modules/read_csv.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3879eedf2f9a57f8782d9f0c37253d9be21882a73c1d745b27108a876b26e1aa",
+ "chksum_sha256": "bb214ec98fb10846d55f0d5c70c82fbdd7081c0923d0296f0739993818c454d6",
"format": 1
},
{
"name": "plugins/modules/redfish_command.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6b3aae9b595a6be520fa675b75cf63c76096829275f2a47c54e8f337db7a79c3",
+ "chksum_sha256": "e6875f2566585e7029e4d21f8f0dab3532c2032e95d907a248c71a4c15159f74",
"format": 1
},
{
"name": "plugins/modules/redfish_config.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ce450be810df3a98b5fac0bc7b1e2c50b7f1dc5afb87307a09b8145cfb98e523",
+ "chksum_sha256": "dc243175c35ab4ffa2d385a92972533c5e1d8ab24060d991a4f9a0b8e850133b",
"format": 1
},
{
"name": "plugins/modules/redfish_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "86e1d11a2b7ddc5f00ac5a34cb56a76048f6e27abe073a2c404089c0d5429d09",
+ "chksum_sha256": "bf2d8f80cadc119e53e6b2626d515a09799e4931d0bfc6d39c39020b65b8bf46",
"format": 1
},
{
"name": "plugins/modules/redhat_subscription.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fb514c4810686b3e2f682a3201772d405fca842ee01a11dcc0dff677806ca51f",
+ "chksum_sha256": "f6de85514d4fd75fa4ce6d76ad7889008d67a5625c3d7e20b62ace3e0df76f57",
"format": 1
},
{
"name": "plugins/modules/redis.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "01b399785ba7ac0e720a244f922959b466911097abe119058a9b95f40733ea0f",
+ "chksum_sha256": "eab32054651d9c430a8cda4f9749db12a19bf8e79a3b35ef4bf947075e1c41d3",
"format": 1
},
{
"name": "plugins/modules/redis_data.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bcde54fa9b831f37ba88f806b55eb1a5000cf355e85d0dcd46fe8c10a30954a4",
+ "chksum_sha256": "3ee8a5f0f3ad5367665e317d4d8c71888bdd7b3d964ec97d5e6aaa85d9f71f4d",
"format": 1
},
{
"name": "plugins/modules/redis_data_incr.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "56586f157ca36093c57283b9a5720ff33592c602344252e76f4cdf89fa685bb2",
+ "chksum_sha256": "059332fb94b923acd229b53117baa9b5940a1b979b89afcd230ee2e7852f8458",
"format": 1
},
{
@@ -5499,77 +5919,77 @@
"name": "plugins/modules/redis_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "55ce6ccc23b568b3b8b3ada05124c4fdbd7c4811ece274680acfd09db65ef116",
+ "chksum_sha256": "5c544a02b0415efa329c84abc4119e0039991bfadcbdae32d14d484c7443e47a",
"format": 1
},
{
"name": "plugins/modules/rhevm.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8dc25f0a5d69b8497fcdf9be1228e31ba39de028d22735147b46461635ed65f1",
+ "chksum_sha256": "4c700911c5b97adb1a7013634c181835428eef1ddd348d09a462c854fc473206",
"format": 1
},
{
"name": "plugins/modules/rhn_channel.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c9545ba247ae7ecb34f5b9edd18faf9f94d25196899d8ccf701ce3cff319dcd8",
+ "chksum_sha256": "6d63758c7918f3b1a3f2b83d4b7ff0be2a04337f13c629ce4a0610ca99a7d775",
"format": 1
},
{
"name": "plugins/modules/rhn_register.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a37c00e7e516636e87ee192b4fa56ef75025db675182edd383dcc7ce912b396a",
+ "chksum_sha256": "a1cc18411ccf82b6b602cee5e67b995fd2e2bbc652779b1be6b4e06a48649c61",
"format": 1
},
{
"name": "plugins/modules/rhsm_release.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c18edd6435ff9eb2face29e1934e1ddc7c214ab2e1ea4038299e434c3f98ff33",
+ "chksum_sha256": "23736b8a6242edcca8a51806ee058e41a7c5f0a4c9b48b284c86975181af019e",
"format": 1
},
{
"name": "plugins/modules/rhsm_repository.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1df2a80807ccc35ce842ce711d92b38087419c644614a939f7a5cfa19396059e",
+ "chksum_sha256": "68fb335cc7719e4ce3f143379e566b5e70423eb719b840e27600262971c20df2",
"format": 1
},
{
"name": "plugins/modules/riak.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "19bb95370c34da795cb2365588c046ea7f0fe2e5df78d19baa4f04d7bf4b9d9a",
+ "chksum_sha256": "c657448de8067ae71413bf74587e2df9dedbd923b9f13ba97bc977b14b2632ed",
"format": 1
},
{
"name": "plugins/modules/rocketchat.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6036e4ab63f42cc8c9379697d3e182743bdb5300d6d2819e533215525f70d853",
+ "chksum_sha256": "a02099242157363b58171719d9bf1d621b5d6d1fe19e58e24d64569306db00bb",
"format": 1
},
{
"name": "plugins/modules/rollbar_deployment.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cd7f5dc67e8eb3e442cd04e29910eb1b68592b2dc6c05e012af354c0098a3990",
+ "chksum_sha256": "9afb9b87ce86ca8a63332cdae5c552f7324959568495788dfd4a8dcfc4a6393a",
"format": 1
},
{
"name": "plugins/modules/rpm_ostree_pkg.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fb2559ef1284b23455cbd0c532fef23ec2b680bf1f374e2ca080874062646aef",
+ "chksum_sha256": "f68c48b939ec1eb2f67f4210e1e7aa78a498dac471c9a9ef8a01402af4b6f63f",
"format": 1
},
{
"name": "plugins/modules/rundeck_acl_policy.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e632a8b90b5780be4070fb083870b5e749622fe8678d9b26e1ae6893221310bc",
+ "chksum_sha256": "fca41eceb0556f43226755c6778ca220f668b3fe05cb7535d93c799ddcff30eb",
"format": 1
},
{
@@ -5583,7 +6003,7 @@
"name": "plugins/modules/rundeck_job_run.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "500cf6160948209fc5d10116247122ac38c12775d379ba82aa0fc00d2994aa66",
+ "chksum_sha256": "5595e8929f2545becf27be650390e9d83cb1205b5bc7e67e2095ffd4956e7252",
"format": 1
},
{
@@ -5597,21 +6017,7 @@
"name": "plugins/modules/runit.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d39edae3ea5ea850f6e59aa8074c40438c3472dcbcfdd4630bbdd1a49e312c41",
- "format": 1
- },
- {
- "name": "plugins/modules/sap_task_list_execute.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "ada516256b26d2db01d01ad9766aa2d2d72f47ecf36a5c2259e9e77163cf60e6",
- "format": 1
- },
- {
- "name": "plugins/modules/sapcar_extract.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "fc9fa7332cc7d968685f33f7f0195b9e4e64b4d56082d7aaa28d0e3899973f4b",
+ "chksum_sha256": "307fec0da8fb9970616f05215a591f8d64e741277771227efcba6f77d77d627b",
"format": 1
},
{
@@ -5625,21 +6031,21 @@
"name": "plugins/modules/scaleway_compute.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ff299f1bc19114b13ddfe1a151f8dc22eb213a4b30cc1237e7fce1a045ca03a9",
+ "chksum_sha256": "325e4bdbe81c4c280e847a290cd5b972d37ce11bb9cef0e25b152e17f4284f67",
"format": 1
},
{
"name": "plugins/modules/scaleway_compute_private_network.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1fdbf4eba9c54e90b0a4580bdaaaafe66c5b3e65307d75974a2333a44eddb202",
+ "chksum_sha256": "6b9f446f40945444eb86c1c1e9555bb5cbd7df529bdc4c9de668f8a334f04177",
"format": 1
},
{
"name": "plugins/modules/scaleway_container.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7e5399eecca5882522e8092b1cdf07366447aead777a9728bc62afdd5ee747ce",
+ "chksum_sha256": "518fc09ab167ec1134b8ddab1a55e9dca0a2f1de45b0f43264c5eb1d9f67c35a",
"format": 1
},
{
@@ -5653,7 +6059,7 @@
"name": "plugins/modules/scaleway_container_namespace.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2ce757a1e9efd759c3eeeeee2e808445b3c37f7a32a74979d721759cada2f840",
+ "chksum_sha256": "214004d3a5b246c8643329d992117c0ba1fff97926ce975f1ea16c2b2b2234ee",
"format": 1
},
{
@@ -5667,7 +6073,7 @@
"name": "plugins/modules/scaleway_container_registry.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a0aec542a806b8414234a9037570a395f59db239834ff2e3e38f175a109abdcf",
+ "chksum_sha256": "65ea0c97ecd21960822c1e1a99afcdda64b312b9288d867669bbf369633c35f4",
"format": 1
},
{
@@ -5681,14 +6087,14 @@
"name": "plugins/modules/scaleway_database_backup.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6729019f0e417f21305f25bfab6318bb6416f8fbc787ce76347df4303534db24",
+ "chksum_sha256": "c4f6d4e9fffcf2964debd7d40703841b7c841bd4f3335155698b548ab7f42ad1",
"format": 1
},
{
"name": "plugins/modules/scaleway_function.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "be7739acef5106d9f713962ecb326200c0b6cf2cc64120fa6df9283e04d9b3cc",
+ "chksum_sha256": "ce8f371ffea4103d1e29016819821882d94055564b48ad1821447d0f7df56069",
"format": 1
},
{
@@ -5702,7 +6108,7 @@
"name": "plugins/modules/scaleway_function_namespace.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fd802a0916f572b697b0d4a71b89870ad915551611660dac661e7a68a517e571",
+ "chksum_sha256": "7e0f9c8944bea71731abe0a26da4237abed750075bece76ad4ea730894616c6d",
"format": 1
},
{
@@ -5723,7 +6129,7 @@
"name": "plugins/modules/scaleway_ip.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "df0bed7f0300bb73600f15ad695cb9909dd319f953e4df541d05e0326bd1b05e",
+ "chksum_sha256": "5c9ccbe5f56fb101f0d73cd1f96aa84fd278e52f81e47be60b32a99d2634f9aa",
"format": 1
},
{
@@ -5751,14 +6157,14 @@
"name": "plugins/modules/scaleway_private_network.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4ef0e5f6203c85fb1b770ed3e019e36cd1ff9df293406173a3614a083621f954",
+ "chksum_sha256": "851833175cf7d204844a97a8e56ab21348581025678c32867fb3895dc1367c88",
"format": 1
},
{
"name": "plugins/modules/scaleway_security_group.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d1aeeff5b67ec38125f14bc75895a3046652ef72dee0379baf23be9b10a2c69d",
+ "chksum_sha256": "d254a211c9cf09b65bdd5087796a4f52b33b10d1e956f1d6686e4b226c1859db",
"format": 1
},
{
@@ -5772,7 +6178,7 @@
"name": "plugins/modules/scaleway_security_group_rule.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "193d731fe4d4a9874d5b4c4dcbf22110fe03931769b6e2ce169f6cc92b8f195e",
+ "chksum_sha256": "4b43832ea093524eeba234af9892b8e0492b6be81af86bbd8aea3f2def238dea",
"format": 1
},
{
@@ -5793,7 +6199,7 @@
"name": "plugins/modules/scaleway_sshkey.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f6dfc50e9ce49df289e96f6512aa30f44efbf907cc99f2eb159afcdc78117033",
+ "chksum_sha256": "7abc370b3dd91c5a5cd34cc6725ea1d0de6a5b338d138bafea18b50c38898d86",
"format": 1
},
{
@@ -5807,7 +6213,7 @@
"name": "plugins/modules/scaleway_volume.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2529f48861c04f84f41c6332abc0de93560e4118a532a240b4174390c5c18cab",
+ "chksum_sha256": "4cc26460fa42da7909d102aacc6027defe4cb18b13a67397b95f23691e864bf4",
"format": 1
},
{
@@ -5821,14 +6227,14 @@
"name": "plugins/modules/sefcontext.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d4cc9edd2f77fb303c88c446cd9947d20d80f130ecd26c242a346a2de7463137",
+ "chksum_sha256": "ea068d197e667e4cb95cc9f25b1899bc3bf5adefa95bcc8a3970d7adb9af982a",
"format": 1
},
{
"name": "plugins/modules/selinux_permissive.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a8bf1f27932d66c92b3be50bef20e451e12bced7a388ed22f94314f0221a499e",
+ "chksum_sha256": "54db40261d9cf811d8725bde63fd308e0b7d6167fa695a86a32c3c5a7023b419",
"format": 1
},
{
@@ -5842,21 +6248,21 @@
"name": "plugins/modules/sendgrid.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ec35e403a1b0b5cf24600e9b9b311e8f1c4dfd7cc202dddcf54efbeba113e6d0",
+ "chksum_sha256": "93923954198e79f4264297644549393ddc5db17208e6e30ac5427ae9b6891f53",
"format": 1
},
{
"name": "plugins/modules/sensu_check.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5e56acdfd74abe21700a59d282ff3ef0836c4c1973e4187e233396a7ef6cf20c",
+ "chksum_sha256": "88e282be17f64e48fe9e3b5a76d13a57210bd89f0c1a9db34b9ecfc81f9ad16c",
"format": 1
},
{
"name": "plugins/modules/sensu_client.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8f1429d29a0cb1efd92ebc5806f3c6fb4359f0b3c430c373bbfd467f46f07eb2",
+ "chksum_sha256": "ff126724145c0a86dbe9966c36e983d499465d65839d4bd99cdb4976f8f502fd",
"format": 1
},
{
@@ -5891,98 +6297,105 @@
"name": "plugins/modules/serverless.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8e8e88323c16862a0cb68894799a2389d4d70444890cbc73dadafaae6f8518fa",
+ "chksum_sha256": "de73d40832c0818f096b7011283848fdf0cd1a0a150cd988202bd93966948a77",
"format": 1
},
{
"name": "plugins/modules/shutdown.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "45e539174be9c8211012f7733e9a360e645dea32126f560070caed5c029bc3a6",
+ "chksum_sha256": "af85e3093f288d67b308e1bdb55e4f5a490bf40eee14c87d6af2c56e7f861161",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/simpleinit_msb.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "5e16568909b2b50d81f4ade73a0da85462adf8d601e6dc209d9f109f47d4741b",
"format": 1
},
{
"name": "plugins/modules/sl_vm.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a37782760e5b630306e0da41cdd1cd0566153c78bd1ccc6b9ad0ae15157ed35c",
+ "chksum_sha256": "bac0ff597fa47241d37020dc76ea84181bd83bdecbd22105dd5503b5ddcb4a4e",
"format": 1
},
{
"name": "plugins/modules/slack.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "29945ecfeee355e8cc00b5cff7bedae410f29f905b189433c1e3d0ca7f025125",
+ "chksum_sha256": "7360855ac2b099b586a8c705563ff5de66a380e259e613bb68cd2fd387b38c5c",
"format": 1
},
{
"name": "plugins/modules/slackpkg.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4e1f7f606fee691d5ca23334a3a25614083ace1e630116ee28667f8f226728fb",
+ "chksum_sha256": "bbe9e23ec032f7a25bdb7b0fd8f20811d08b058d1976def4b5011851229f4d88",
"format": 1
},
{
"name": "plugins/modules/smartos_image_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5601f8718c9f2c4a2914fd3d89bd50b412b793739b1d3145d9966707b8dfdd98",
+ "chksum_sha256": "b96545c99d8709d734accd39efc266737414a1a254eff86062abb07893db90b1",
"format": 1
},
{
"name": "plugins/modules/snap.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b56f9dd2ce887547d6675de578cfdaea1455a72052fdb9db5e6f1a7f72609617",
+ "chksum_sha256": "6d0a8e28420c83431d829397011eab016d1e2dd482632e43cb00967db7bfdb7c",
"format": 1
},
{
"name": "plugins/modules/snap_alias.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f7246c438210b143db250dd1d28e8e3ccf7bd7cec88dfd6f2de630193519897a",
+ "chksum_sha256": "b588f7b2969ce34f0071ab4a8c4a58a883eb165c3f4696c3ed91f3a95d287a0d",
"format": 1
},
{
"name": "plugins/modules/snmp_facts.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9a6e17f2fd377acfac49d130cb27403e7dc524f66555de7536901cf1252c5607",
+ "chksum_sha256": "026d4bd91cc717219d0c6b9686041be936927ec0b2ffe4d162e53aace879f3d9",
"format": 1
},
{
"name": "plugins/modules/solaris_zone.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e40e563faeadea10c511613f9192cadc08a12f6bd106bc72a908f9d306b9044d",
+ "chksum_sha256": "7bcb8f6ad7311a7c328971de145716880b9e33d87746fdfd12fffddac615c5c4",
"format": 1
},
{
"name": "plugins/modules/sorcery.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "94b2cb338fe113a445527fedfaa0b72c60a4431b041c293268937e0484f4b61c",
+ "chksum_sha256": "b3432095db995d56b5f95246c72b516379c098e0b2ced465fb20fcd1b8475215",
"format": 1
},
{
"name": "plugins/modules/spectrum_device.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c4a60520fa6819ea2ccf347a55b9cf7cd83efa45a60112fd934080e071eecef3",
+ "chksum_sha256": "57c6c3b500a197518cf188e34872e8fc2a1137342a08edf6c7f9a0f8dfd0478c",
"format": 1
},
{
"name": "plugins/modules/spectrum_model_attrs.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1ecf012b62d84d3d08d333623f81e866354e1a8511cd0fdd9d91f1a50c28a41e",
+ "chksum_sha256": "6b0424d6eb8ca295cdf0303ae1d8c5c5488ea8a9ca0ba3f012072c9fa700b858",
"format": 1
},
{
"name": "plugins/modules/spotinst_aws_elastigroup.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f8a1757291fd3bd65310cc1abfc801b332821f683b125282d35b981857c29b92",
+ "chksum_sha256": "bce6243efb2e105cca91acc299e1a8eea4273e5ae7a8af64c47752a51546679e",
"format": 1
},
{
@@ -5996,77 +6409,77 @@
"name": "plugins/modules/ssh_config.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "27d5f076fdf868b0f5685c31b80ebdd947b6766c6395e80c62d9757c569067a9",
+ "chksum_sha256": "233e53db7d3b7cdd61178d3c7b5fccb2ca8e8afff7bd3113ee116e72b7b3ecd2",
"format": 1
},
{
"name": "plugins/modules/stackdriver.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1229f4c3f84fb38de299df4374feab035d45b707b3ba3fcad69895c8f53f70fa",
+ "chksum_sha256": "260859e428425f3c3ac4bb559a3d4c82273e87301894ac350d8cdf2e193200ab",
"format": 1
},
{
"name": "plugins/modules/stacki_host.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a6c7a2c9e54b594da6e4e5124785a94e7fe57c511a8fd7053794234a78b84a00",
+ "chksum_sha256": "ce6d7be179e758d9b886d5c7cc54466dbf2782fdfcb08c7ddbdec7a2ebc61170",
"format": 1
},
{
"name": "plugins/modules/statsd.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "95c849c53213ad5834dbdb9b3cda95fe04a958dac354b182f070a3d28f0b16a5",
+ "chksum_sha256": "a556322b791af7bb16ff71fec285a276094b1be17a3a5e0e905215bef0458ab2",
"format": 1
},
{
"name": "plugins/modules/statusio_maintenance.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a00ca04cc99c19eab82911ac9cf11cb5df77cd29f96287d60dec2179d53a84ed",
+ "chksum_sha256": "afd8833c6c9896e742a7492aca76799e42d2a2a819efc511caade8a2d2091746",
"format": 1
},
{
"name": "plugins/modules/sudoers.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "51c0912f16fca1904d687fd0d08667f980fbaf2c6c8d27acbc0781c6729fc11d",
+ "chksum_sha256": "aa66bd698fec60c1641e538fc5149bf3099b86356e96889566de504ba631872c",
"format": 1
},
{
"name": "plugins/modules/supervisorctl.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2871ebc56d5cf531d5ce28fa3e9bd3a6138f598dac91d6e53c6b4bce00df9c40",
+ "chksum_sha256": "c68bef54a5e5171064b783342decdb71396970110663f32dacd2ed86a7faea38",
"format": 1
},
{
"name": "plugins/modules/svc.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bd1bad04d7dab8d937305c00ff71949a950e2e5ed33222a355f3b8f7176ff741",
+ "chksum_sha256": "98fe92a9d53d3bd790cea1d414a61c7cd5bdc49db06daad33f9651a8d67561cc",
"format": 1
},
{
"name": "plugins/modules/svr4pkg.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c6f917e3db5d8719897198e37df5a0ddad5f6c7dfe1c81a0325804c45118b630",
+ "chksum_sha256": "8194a64057dee3897d1d5c74d4dc557128183315f34bb102dbb47f9bdc8de1c4",
"format": 1
},
{
"name": "plugins/modules/swdepot.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ff26ea548d96299c8447de48651445e124eabb5cadf872a3d5f72e0ea78725fa",
+ "chksum_sha256": "548386259af581cf1c3ded8d4ea2ad595e3cedb5c6c7df3533c59d608161712b",
"format": 1
},
{
"name": "plugins/modules/swupd.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "97c4699f49179b56eeeeeeb7e27a357038220ba267d76bb4f983ed3a17c1042f",
+ "chksum_sha256": "054446bc7c26765070c6d9431c1f31474563da586e3868ea0f5043e9e9e2faf6",
"format": 1
},
{
@@ -6087,14 +6500,14 @@
"name": "plugins/modules/sysrc.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9ecb25783bb73e9863206433c90d81244cb131118b0a20d7ca94532a862d1bed",
+ "chksum_sha256": "7cbbb099da4296a5e3d02434b05ccb358e820b4788d763079e0c7880e7056133",
"format": 1
},
{
"name": "plugins/modules/sysupgrade.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4623dec27bfe0bccfbbb52af3f8cb2496667927d01594c3d36cd222d378aea3d",
+ "chksum_sha256": "a26e41813397e636eefa92b4220a6e5111cad89b30c375f93317cc4868bdcbde",
"format": 1
},
{
@@ -6108,21 +6521,21 @@
"name": "plugins/modules/telegram.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fa0e4b4784a6032107646b106cf5c5c73bdfa70461a638d3d88954a6122d9167",
+ "chksum_sha256": "4457098d3eb6a5963176df9845286f5dee76ada74777946d8ac5232bffe3b096",
"format": 1
},
{
"name": "plugins/modules/terraform.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a73aac1add13dd2adf8d7a7bfe0647d89b1b3392f50b5e7e0de751325fb28985",
+ "chksum_sha256": "16f6c1e55a7aa16213ab2d8ebdae7daa3dd414093481fca6dbf22ca044136011",
"format": 1
},
{
"name": "plugins/modules/timezone.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f1578903dc0f212f54d19119a34b4cfdd29766d117cdb82730e5892983424c00",
+ "chksum_sha256": "ba12998b86095d706d4ed3fe1cf5e2ee4cad497d5421355c2eb27fbf948c0df0",
"format": 1
},
{
@@ -6143,14 +6556,14 @@
"name": "plugins/modules/udm_dns_record.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "56ae686f1a5bb18536dfbec4523144053239bc423b96ea36d65dabec29aa4875",
+ "chksum_sha256": "e11b65b4f6f2a787e302018b495d3de409fa4356868e277cd6ce00e705d03563",
"format": 1
},
{
"name": "plugins/modules/udm_dns_zone.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fd76c1b0a0455eac1d0cf1f12cb663f76d52ddb5ba191b614873fc141dd6e223",
+ "chksum_sha256": "6378c88c74c505abb5bfd472080146a9ecadf3e0b6a59599a54de7bbce17079d",
"format": 1
},
{
@@ -6164,21 +6577,21 @@
"name": "plugins/modules/udm_share.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1427fe80978879d0b15c6eaab387bc25c92d3ac795716ada938a11221a59308a",
+ "chksum_sha256": "c2027edb9da1d109240373de4f8fa85411fe4ecec03bf364af9fca8158fa4707",
"format": 1
},
{
"name": "plugins/modules/udm_user.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "444060481fdea92619bd1ed1e3674c2afdf9b827716f0c8c3a28c39424072daf",
+ "chksum_sha256": "108d20d909305308b8e5e7a6bf5e323f154db4c473c02e47734e8fb0c8bc7b07",
"format": 1
},
{
"name": "plugins/modules/ufw.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8304e0c613c151c775e58ec4ccde4c58c028c55d2d709235fe0c24d9d63d26e7",
+ "chksum_sha256": "fc3dd683613264c826e86da6ba4670ce88239811474cb75e2f0eaffc2f76e1f0",
"format": 1
},
{
@@ -6192,7 +6605,14 @@
"name": "plugins/modules/urpmi.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0e8484d0c8d63292c3517ab7236afe02a5f9d78e00240493e959d02b0e136a5e",
+ "chksum_sha256": "c460b7ca149706b3908acf9a651f2c8f04b7f6fa7a6696d1669de82d426c6817",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/usb_facts.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "48558d79bcfaadb76c05e0f5e81e5094e29127d3345751b1dc0945dc4bb7213c",
"format": 1
},
{
@@ -6276,21 +6696,21 @@
"name": "plugins/modules/utm_proxy_location.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1c0e8b84a9927f6313f63f140b50ced9e3a3b64d86bdcc00020bf90dbf45b611",
+ "chksum_sha256": "bc51fc72ac307e97cd76aa24f0787d6b1da84db415234788e2a3326a529ae27e",
"format": 1
},
{
"name": "plugins/modules/utm_proxy_location_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7d955f1ef06ac3866d417111f251912f96b3e824002b8bb86b6be4b8168b7f24",
+ "chksum_sha256": "e59ba94417f2095c57e968369610c23483c6b30617dbb7d9e7dc23f10fe338b8",
"format": 1
},
{
"name": "plugins/modules/vdo.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ce7c3cd23ddcee51bc45c0b7dd2538fdb001d5fcd2c29fce59bb7499ee75672d",
+ "chksum_sha256": "151ef90f49f13f22d0b0d9c3a9e1e41747f3468613c68d2ec2d43936a655fbd5",
"format": 1
},
{
@@ -6304,28 +6724,28 @@
"name": "plugins/modules/vertica_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a46add11638e96d3d5975c3a696ae070003ade4bb9f0cea8092b2e1682f167c7",
+ "chksum_sha256": "51756d40a90a53d62acdfea2b98cb6ff9bb15f1f55a4aa653e7c6b20c8657cdd",
"format": 1
},
{
"name": "plugins/modules/vertica_role.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7d0a37d3bb220ea341f739ca959a96620103c20dbed5e1c531416814dd00814a",
+ "chksum_sha256": "9712d082dc6e89300c9be51c30023aee48ebb900de21120683d9b302ea2e2f72",
"format": 1
},
{
"name": "plugins/modules/vertica_schema.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3bc91a094f43aa44f8e47885a0396ede89297320f1db82aebe93c616199295a0",
+ "chksum_sha256": "a52fa480e0f06201eb4ddbacf9b9e28d40c921be24c64a6bb29ca0c162329186",
"format": 1
},
{
"name": "plugins/modules/vertica_user.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9ada565198074caf40a38ee9014070509869e1af8e7c5f0b04721fd26fa60e3a",
+ "chksum_sha256": "6f23f3bed0dd38ae33394fa6c769eac28d5d35b2d476a01571237ef24d640be1",
"format": 1
},
{
@@ -6346,7 +6766,7 @@
"name": "plugins/modules/vmadm.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "46a7e37ccbabf791d280c32800a91761fe62c421757eb32be6f17b1a47e55cb8",
+ "chksum_sha256": "e2e02c86b8e032e16609f79bd278c6dd34c24df95ba92b2e9b9f7231f835dbec",
"format": 1
},
{
@@ -6360,112 +6780,112 @@
"name": "plugins/modules/wdc_redfish_command.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1bdc9969cc4377b14a450b0a48c0236e6335ea5c4c74a3584c44db219ae6255e",
+ "chksum_sha256": "3633d36cc4847e89ce5ea6368274794abde9309f32f8e0445dcb4d5c14522f7c",
"format": 1
},
{
"name": "plugins/modules/wdc_redfish_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "78c5b119393dcb7073417b3491352efd917ac2d22a20c8f93889f383a869ff7d",
+ "chksum_sha256": "968b9d548bfa5a3594fdd212e4184db6c672fc8d2e2972e2e5ef13ab5d148f59",
"format": 1
},
{
"name": "plugins/modules/webfaction_app.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c48310ad10d6ec9fe163d07cdcb540580ea31e041746ec785e63975156ea3279",
+ "chksum_sha256": "6883576548556701abe0dae9e225b8cfd752d0f228fb9357db083b0ebe26b4a4",
"format": 1
},
{
"name": "plugins/modules/webfaction_db.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d9dd092e1ec2c318c4a70cb7fdb1a5dd7cfd9c56e4eb1af7dda4932b6099ad68",
+ "chksum_sha256": "40b0caf3268e4866ca3adbd73e29f3f340648eaa267dc52467b36b3215ba9bef",
"format": 1
},
{
"name": "plugins/modules/webfaction_domain.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "712f733337be663d0473deb9ed4a1f5001f87500cc592fb44f652bf25d172c93",
+ "chksum_sha256": "d46377b3af3d19a097ced017bebe348c843bf715397e18ef5f5d27803f0e696a",
"format": 1
},
{
"name": "plugins/modules/webfaction_mailbox.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "582f8918f64d1714629d56f436539fc0b8b0b19ec6c0a72e5659c3130422b4cf",
+ "chksum_sha256": "966032efd5039669f873f8a33d85573ca7536a261ea3b2eb11e7a1c00978365e",
"format": 1
},
{
"name": "plugins/modules/webfaction_site.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7847deec3494b81cb21f1d6b62d7fffbd940fbec7fb774af9f42f6dc938569b7",
+ "chksum_sha256": "1715e8e46b23d2cacda5560e722957ff3440e1f3800461c94c27c13c0582e325",
"format": 1
},
{
"name": "plugins/modules/xattr.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e973a3198180d2d467cd67bb0db529d460db3cae0019d3dd2ee11bd3848ba4a7",
+ "chksum_sha256": "35e909854ba85a1f6a47149c8daaa719f9581932548e71985cec58d35c36ee0e",
"format": 1
},
{
"name": "plugins/modules/xbps.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7dbdb9bd073b35704b4be41fef7d6cf4a911ac151a42fb875c7357a08a0be063",
+ "chksum_sha256": "b4ca0818a516e732854553da7b799d7976a9e1f23df238befe20c6222029562c",
"format": 1
},
{
"name": "plugins/modules/xcc_redfish_command.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a9ad104cd73bed87ae0d6c595b577fbb31ce360158eb27d6840ba4340ef2aee0",
+ "chksum_sha256": "eb5f497cc2822b1d76fe9c0f32fc2f90de76fdea0931cc27c8567361650e3026",
"format": 1
},
{
"name": "plugins/modules/xenserver_facts.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "93d1755c39b647d6a3b4d43c298388beb92f3c85a4e25e2b87e1388f4dd11bbf",
+ "chksum_sha256": "82f136865a7a63ca911b95be0a26ce9f9648c71950ae3e68871b1768eac0d902",
"format": 1
},
{
"name": "plugins/modules/xenserver_guest.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4a4dea9d8882bb70f9360f374d49de96220d60be2a71a0dcf51a2b0649fa8981",
+ "chksum_sha256": "e17993003454b93f2ef0744d9de77fe813288b8b94d9229b98e05a54e7ceec7b",
"format": 1
},
{
"name": "plugins/modules/xenserver_guest_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e82b5d7de8d6bbb5ba2061d50d85e770d4bd999ea54b02691f508f448b456323",
+ "chksum_sha256": "db26e9227dee955eccb0b7992fc57b60aa07f5447ac673fe8ce9888e89eb88a0",
"format": 1
},
{
"name": "plugins/modules/xenserver_guest_powerstate.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b055bf336e88377ae31041d358f7f37c1e4afb6d7fb7f38a8e2250052a713c05",
+ "chksum_sha256": "47a17d84a900f110900f4e4bd0db4c2c4cf6838f99497c93d49c803e71882c44",
"format": 1
},
{
"name": "plugins/modules/xfconf.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bec9b6404fa34fbcb581ff80d4e7b56de09c14cb1c89dc01c2370a4cd2b0902a",
+ "chksum_sha256": "dfde9c9bb1f06fc648e437411d5036530781b9753e939a04c2aee066883868b5",
"format": 1
},
{
"name": "plugins/modules/xfconf_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ee767fd48a7bfcf87c9ec27b594ea67d240b9031d4c149412fc507cdbed0d6cb",
+ "chksum_sha256": "fe226ac61a1a542d0a68fedbfa614b92953e557a35bc33daa85238f8579200fa",
"format": 1
},
{
@@ -6479,7 +6899,7 @@
"name": "plugins/modules/xml.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "38a4462c5b51edeb59f0fcb1a21443fe45b29f40c11787467f01fc316555e475",
+ "chksum_sha256": "801820433ca4c1410b22055ae52a7ab438787a232462e0d8125d43b180edd870",
"format": 1
},
{
@@ -6493,21 +6913,21 @@
"name": "plugins/modules/yum_versionlock.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8ef5cdecb75e8800be5b686dc0a492b00d75a71436f014bf88da207e9b5c6049",
+ "chksum_sha256": "2c0aca209e29a7a80c9e999560b5ef0b5031f93d8591f98887503317271566a4",
"format": 1
},
{
"name": "plugins/modules/zfs.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ca5769b13392ec15040a0cf9c96bae13bb029831b675d42bc8b89dee33b15e57",
+ "chksum_sha256": "acfd07c3b314c7f0ccc51f9a430a130bd8733ff3a1888d454d62aeb4c568793f",
"format": 1
},
{
"name": "plugins/modules/zfs_delegate_admin.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3d3c4c5f5761e5c70fc6d47284f7bfb4d8460e4d0a617b479da0540006e8a6b7",
+ "chksum_sha256": "d43df0da9e9884f2beaebd6b54203ccf0b681ce22d3949b0198e12d7119b4497",
"format": 1
},
{
@@ -6521,7 +6941,7 @@
"name": "plugins/modules/znode.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3501c9f3857eff254e298fee210edc0016e15265c69b3df7fd433d09ee8af9b4",
+ "chksum_sha256": "970a830098f10f4607e84a0f0e2f189ac74c64e6f069736d01964b3a2dbdbe4a",
"format": 1
},
{
@@ -6535,14 +6955,14 @@
"name": "plugins/modules/zypper.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d1dcde23c3dee87675bfd78d3885da676d707551baa6f0fcc45db7c829560344",
+ "chksum_sha256": "2599cb192bfeab63604c7ad63a7c281b88da6a0dec83663aaf8b460b5b1d134f",
"format": 1
},
{
"name": "plugins/modules/zypper_repository.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "03ebe5613a4a9c43bd9c21de4e58b4c4480fd0a3965e008bd68785210dba6141",
+ "chksum_sha256": "953c33402b610c20342a9065aacf0ae25e52a4bbd76f87c7dc3dd135f221f7d4",
"format": 1
},
{
@@ -6560,6 +6980,13 @@
"format": 1
},
{
+ "name": "plugins/test/fqdn_valid.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "af9ff54697c02e127711ea9d845abe3c9c038e9d02e9f632412bb44b8efd0400",
+ "format": 1
+ },
+ {
"name": "tests",
"ftype": "dir",
"chksum_type": null,
@@ -6626,7 +7053,7 @@
"name": "tests/integration/targets/aix_filesystem/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ae8e81aabb3f66ba309397f22c3805cae6bab9055f5ad8649fc30e6c1c7470c2",
+ "chksum_sha256": "2631917664e8daef7755171039c197db48e9681820003fffe53ea62515f132ef",
"format": 1
},
{
@@ -6752,7 +7179,7 @@
"name": "tests/integration/targets/alternatives/tasks/tests_set_priority.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f89b31c36f2412b455dd101e8cb42676f7aa4cce429167510ffa5fe9c900e558",
+ "chksum_sha256": "87ae8ea265994f5952b58dd1334a8173a6f27bdfb5edddb17e0b40acb6334464",
"format": 1
},
{
@@ -6871,7 +7298,7 @@
"name": "tests/integration/targets/ansible_galaxy_install/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "16a2fea9aaec069f0eb1971b262817e63bc08b018d6d58bd2d1c6b06415ec3fa",
+ "chksum_sha256": "4a921e78f0a89331ab88be027df367ffd57439737ff8eeed8499582b4efb8405",
"format": 1
},
{
@@ -6899,7 +7326,7 @@
"name": "tests/integration/targets/apache2_module/tasks/actualtest.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f87a33aa6bd1a53628e05dfa008ce665b9d2456c3b2beb019186cc6970cd6b18",
+ "chksum_sha256": "d81289b39973a430c16d7ab079d67b594a081ed5e80c5ada651ba6513a315aa0",
"format": 1
},
{
@@ -6917,6 +7344,34 @@
"format": 1
},
{
+ "name": "tests/integration/targets/apk",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/apk/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/apk/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "db4381edeee899f440e2392f23882f43a934978a9d2e25c12c26fac0d1a2aa96",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/apk/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c9f0057d73843124face1fd183f52658121ff5611fa75b96e9cd0bba0ff5835f",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/archive",
"ftype": "dir",
"chksum_type": null,
@@ -7011,7 +7466,7 @@
"name": "tests/integration/targets/archive/tests/core.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9baef7009f93b2218cb5a87822417edac461e52e4db8f4860c40b46910ed1d6e",
+ "chksum_sha256": "bc7e193a3c101808cafeda8802836bc2eede942724821191b00bfb5867c326e6",
"format": 1
},
{
@@ -7032,7 +7487,7 @@
"name": "tests/integration/targets/archive/tests/remove.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9404b81ec6b1952f02f0b26ce523c2323720d620ab48a1ecb81396e929d6b68f",
+ "chksum_sha256": "ea3e69d81fe5648be4536f5b1a5aa506885737f566a41e471efddcde56f10db4",
"format": 1
},
{
@@ -7165,7 +7620,7 @@
"name": "tests/integration/targets/btrfs_subvolume/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4ecf77a2c1e3f8e54ea570e1e133d2de539be44f334cc5b266778b4acea793da",
+ "chksum_sha256": "78eaaf3e1986c8e21084c3837c9198c567ccafd3402e47fd3f3b0e00d7b6c4f0",
"format": 1
},
{
@@ -7197,6 +7652,34 @@
"format": 1
},
{
+ "name": "tests/integration/targets/callback_default_without_diff",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/callback_default_without_diff/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/callback_default_without_diff/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f9a57261c99fcdbd2572a334fc8554994d48acfc83e1fd215fc9e75e484b9593",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/callback_default_without_diff/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "8348da0356811dd51f09b2c0ec68b0764d22cae61a09bc309698098584dae45d",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/callback_diy",
"ftype": "dir",
"chksum_type": null,
@@ -7312,14 +7795,14 @@
"name": "tests/integration/targets/cargo/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d23bc639ce5ca95d45f7fd6ca30245522170b0289f9208a275ca2ae0fd1bd733",
+ "chksum_sha256": "e5f66835ea6bd23ef85f61c95211e57f257d3f2ecab06d669afe311ba64045b3",
"format": 1
},
{
"name": "tests/integration/targets/cargo/tasks/setup.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ad0fd64eae29859a9b82e6fe7287afe12de85fefd83e38c866a90df04a396354",
+ "chksum_sha256": "be673b7c7d3233412b300feacfae48476628310b867e53d8adc5dff1624aa24e",
"format": 1
},
{
@@ -7330,6 +7813,13 @@
"format": 1
},
{
+ "name": "tests/integration/targets/cargo/tasks/test_rustup_cargo.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ab3b7a1663f45663ae9498fe0ac18ccefd53396325d97696a5a95c3f58b24b78",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/cargo/tasks/test_version.yml",
"ftype": "file",
"chksum_type": "sha256",
@@ -7375,7 +7865,7 @@
"name": "tests/integration/targets/cloud_init_data_facts/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a6b091960bb2e3d132701a7545e102d9dde29ece7b14559855742c87d2b915b0",
+ "chksum_sha256": "373a461c7e051cc4e976e7cc3e807f8acee8b7426b4d23e2b5fc05ab601b9c82",
"format": 1
},
{
@@ -7393,6 +7883,20 @@
"format": 1
},
{
+ "name": "tests/integration/targets/cmd_runner/action_plugins",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cmd_runner/action_plugins/_unsafe_assert.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "40e701a4db18050274cb0cea98b756925f6291de90a5afde36b647edda9cc7b0",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/cmd_runner/library",
"ftype": "dir",
"chksum_type": null,
@@ -7403,7 +7907,21 @@
"name": "tests/integration/targets/cmd_runner/library/cmd_echo.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1861ab39a9364d62a15466de58a3043ddcdd707f711a46f3dcadce314beda487",
+ "chksum_sha256": "c06fc4236c125498b033be4f72e5f623153f81e76264de4eba5c2236c82d2816",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cmd_runner/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/cmd_runner/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "3b4106020a362e34cbc75011bfa013d65acb8224f6fbc931cfc6438b67888627",
"format": 1
},
{
@@ -7417,14 +7935,14 @@
"name": "tests/integration/targets/cmd_runner/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9830d306710fa7218869552f7c23e0c62f1c8d5b94111c86204e9e4fe6ead182",
+ "chksum_sha256": "16f7b69384294dbe59eeb1d0b7894a078fec9dadfbfd5aca31c11fbe3ec143be",
"format": 1
},
{
"name": "tests/integration/targets/cmd_runner/tasks/test_cmd_echo.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "07e0cce6b96cebf03c15af6658c2b02af21d9ef087f9e5b4a4500313baf4a592",
+ "chksum_sha256": "84010d1e48b83fe630afd575bbc11f6b1ba9e0ac9672524677c104a8ff16ac49",
"format": 1
},
{
@@ -7438,7 +7956,7 @@
"name": "tests/integration/targets/cmd_runner/vars/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fd9cad1f291a0205aefd3eb749f5e5eaae28a97772c01a506605928ef2f4959e",
+ "chksum_sha256": "c6a180d32fb8f9f0e994230ca0015fe34b505ea91b1775659f9a7367d7fea597",
"format": 1
},
{
@@ -7505,6 +8023,34 @@
"format": 1
},
{
+ "name": "tests/integration/targets/connection_incus",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/connection_incus/runme.sh",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f560fd765c11ef6e6d01fce8aed19eabcba4f099185fd58d90ba49384a99dbdd",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/connection_incus/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0263e0920568d58006d948e60fffbfb6ebb50c6ee0099f04230cae48e97ef416",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/connection_incus/test_connection.inventory",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "4f17536ed7b1385e95b8b1fc59ed29cd1f834cb50444a6bf32ffb4be642cc03d",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/connection_jail",
"ftype": "dir",
"chksum_type": null,
@@ -7638,17 +8184,66 @@
"format": 1
},
{
+ "name": "tests/integration/targets/consul/tasks/consul_auth_method.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "493da6bb6caec79bc72e38e228fa447fbd9dbce71ef25df39c3a2853f28593f5",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/consul/tasks/consul_binding_rule.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fb57240ec9fe557e41811dadfb2791e8c30ec9e6c74bdb8bdecb15e561f64993",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/consul/tasks/consul_general.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e1c849d3c875159447507c9c4f7794150d8dcb559dd605d4af495fa454a259db",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/consul/tasks/consul_kv.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "192ae735a795c85251f654bf51c23b3ff2918ede764b427aa2b35904fa2ef4ed",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/consul/tasks/consul_policy.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "a75198d4c30c8eead0c918212aed118672f488caed58d8db927058105b079d77",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/consul/tasks/consul_role.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "51bd70ecc2688b3cac820fcab6f33f2b602f43ea1095798d9976b246c4907c8e",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/consul/tasks/consul_session.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c1b518f00b78109f1852c190ba1f870461045e624d839e3e548f2bda45efade6",
+ "chksum_sha256": "5a69a642e85b66ace4417d1a2bd61376720dd2088df934310dbaab202340a0dc",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/consul/tasks/consul_token.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "934e50996f0c1fd5b99e2e028d2d78567d11336e8b75fbbf20da0ddc1f3a0af2",
"format": 1
},
{
"name": "tests/integration/targets/consul/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a9f3d40eb77ab944532fbebcdca6fec27274c30206d295a918a12ffa5e42bbc2",
+ "chksum_sha256": "6bafc431979010557c06259d8b5cccc03f49d1ec2097a26118dd3a2091fd4cc7",
"format": 1
},
{
@@ -7662,7 +8257,7 @@
"name": "tests/integration/targets/consul/templates/consul_config.hcl.j2",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4f039dace9e85cd5cfd886bc61a87d7ceb1fe874f2de7ac8b25a444bce137fc7",
+ "chksum_sha256": "94f26d6d560944d187cb73d663bac8f200819fb1aaaf69fcd0edcf483b193686",
"format": 1
},
{
@@ -7690,7 +8285,7 @@
"name": "tests/integration/targets/copr/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "44c30a4e8597ecaa3b92b54391a62e9da4dec50e79a77b5ceb74621edf176292",
+ "chksum_sha256": "4e168ca32b9635aa6bfa8f38686085ae8234b547a7bdb5b41be526f590cda46d",
"format": 1
},
{
@@ -7844,7 +8439,7 @@
"name": "tests/integration/targets/deploy_helper/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "493434966f881b971f76b928e152d569a2540428e14cd6ca5fcd2bf1ba5c0863",
+ "chksum_sha256": "4615020372e8916d722796a75eb90a2e00e59b63404d9539d4510f3c1693307c",
"format": 1
},
{
@@ -8047,7 +8642,7 @@
"name": "tests/integration/targets/django_manage/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "21a4a6fceba1d357b08843ab08f2cf83d707e4be7375a3ab6368f07b0318f17f",
+ "chksum_sha256": "cdc75147abe7879885ad1dab4aca660397e5fbd537e65b7f2eefc611a544ba7c",
"format": 1
},
{
@@ -8156,6 +8751,62 @@
"format": 1
},
{
+ "name": "tests/integration/targets/ejabberd_user",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/ejabberd_user/handlers",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/ejabberd_user/handlers/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9964ed731dbccae19753245977388a1c7626c18e0ec3e3c0675c84049ba12cce",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/ejabberd_user/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/ejabberd_user/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e11ca6edae518cc531ab425daa9eb93f78f89b9ddd515deabd239e8c7925323d",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/ejabberd_user/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/ejabberd_user/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "947101155a8d19ee0d8bf4d74cd963d80ec75d6bd6b7fee8241631f2cf044583",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/ejabberd_user/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "a913fcb222e0ae4bc7481868fa7bfe48b3785df3843ad9eca43516be112e1a86",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/etcd3",
"ftype": "dir",
"chksum_type": null,
@@ -8201,7 +8852,7 @@
"name": "tests/integration/targets/etcd3/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c848396ab50443ff89d6f4ca88ed935253fef1da06ea0832dbcbc593e315a4fc",
+ "chksum_sha256": "a47ac50fa5e970be21c877ed0aba53b12fcadcacdc9bc79c11e32058b65bee63",
"format": 1
},
{
@@ -8264,7 +8915,7 @@
"name": "tests/integration/targets/filesize/tasks/sparse.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c7bd1d406b44a6ab39f6dbe8c422a4eca486647160fed701cc79ed36c166df6a",
+ "chksum_sha256": "65be72f558e8767c8debe2445c941279b5b2d5d4c6cb03ac13d3b7d9c0318449",
"format": 1
},
{
@@ -8299,7 +8950,7 @@
"name": "tests/integration/targets/filesystem/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "757cbeb22a88c3cdf9157a7391a7ac69f2a7ec1203242f89e326e5d6c96f4b76",
+ "chksum_sha256": "08185326e7b809ec8248cc5bf8276368f27b14a8cb0131cc2ae95676871ff8cc",
"format": 1
},
{
@@ -8348,7 +8999,7 @@
"name": "tests/integration/targets/filesystem/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b21b03a2123f134c171bf8c291350d5cf34b82c9f70c52866ad6f8bebb45d718",
+ "chksum_sha256": "6a587d4489a54a86e204cbef30a808fe543fef4be6e9e9f475b22287fd2d4f58",
"format": 1
},
{
@@ -8366,6 +9017,27 @@
"format": 1
},
{
+ "name": "tests/integration/targets/filesystem/tasks/reset_fs_uuid.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fa0421b7467dca5d9828e1fee8f431187ef708fcaad5fc5310c7839c4d23894b",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/filesystem/tasks/set_fs_uuid_on_creation.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "3c9a2ace7ffc7a3f09599a61f803adfb5d3c1ca160e9d394f403a158c6bb8d21",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/filesystem/tasks/set_fs_uuid_on_creation_with_opts.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "2ceac82effd7aa36e9ad1411638c54584c49142877f8c241f082aaf4c7d7d904",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/filesystem/tasks/setup.yml",
"ftype": "file",
"chksum_type": "sha256",
@@ -8425,7 +9097,7 @@
"name": "tests/integration/targets/filter_counter/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2908fcc4953a67530ae1d897c66e847d8281e02299b5563f9c751db06ba10036",
+ "chksum_sha256": "96646c5ab7118c53b8b722f6abe91a7ed4d3eed9be401faefb399d6a8f427c2e",
"format": 1
},
{
@@ -8453,7 +9125,7 @@
"name": "tests/integration/targets/filter_dict/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "370e79ab6fa9ddd49544f28facc1c94fc720419d9ad27b806b1e462c024d451c",
+ "chksum_sha256": "935444847dff7cf6ef6476a46c6b5699e240f499b003363925d82e983fc3aefc",
"format": 1
},
{
@@ -8481,7 +9153,7 @@
"name": "tests/integration/targets/filter_dict_kv/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2908fcc4953a67530ae1d897c66e847d8281e02299b5563f9c751db06ba10036",
+ "chksum_sha256": "96646c5ab7118c53b8b722f6abe91a7ed4d3eed9be401faefb399d6a8f427c2e",
"format": 1
},
{
@@ -8523,7 +9195,42 @@
"name": "tests/integration/targets/filter_from_csv/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2908fcc4953a67530ae1d897c66e847d8281e02299b5563f9c751db06ba10036",
+ "chksum_sha256": "96646c5ab7118c53b8b722f6abe91a7ed4d3eed9be401faefb399d6a8f427c2e",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/filter_from_ini",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/filter_from_ini/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/filter_from_ini/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "a07f8a902771d4130fb6735fb0acff4a9f8aead0f123cb43a539406e54184a59",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/filter_from_ini/vars",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/filter_from_ini/vars/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "1001297a7c71884c3851bf9cae6a958eee1a65e3bc11946d9628c714e5dd39ec",
"format": 1
},
{
@@ -8565,7 +9272,7 @@
"name": "tests/integration/targets/filter_groupby_as_dict/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "370e79ab6fa9ddd49544f28facc1c94fc720419d9ad27b806b1e462c024d451c",
+ "chksum_sha256": "935444847dff7cf6ef6476a46c6b5699e240f499b003363925d82e983fc3aefc",
"format": 1
},
{
@@ -8607,7 +9314,7 @@
"name": "tests/integration/targets/filter_hashids/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2908fcc4953a67530ae1d897c66e847d8281e02299b5563f9c751db06ba10036",
+ "chksum_sha256": "96646c5ab7118c53b8b722f6abe91a7ed4d3eed9be401faefb399d6a8f427c2e",
"format": 1
},
{
@@ -8649,7 +9356,7 @@
"name": "tests/integration/targets/filter_jc/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6e9844ad48a5f30a80790903f1f27f13c1c2676e79c50d706063bdd25e5b1da3",
+ "chksum_sha256": "9e9d6b05b403cf806593ce93e167711ec63fa02481a6cdc1f2f6041d643d0573",
"format": 1
},
{
@@ -8705,7 +9412,7 @@
"name": "tests/integration/targets/filter_json_query/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "04d550c69028ec48b216c053bb6d7ddb9e0e57fe93874138b09aff2776789444",
+ "chksum_sha256": "97aeafca6d46181e78434a9dfbd80a826ba334abe46e42d18b6304d7aca14e3c",
"format": 1
},
{
@@ -8723,6 +9430,48 @@
"format": 1
},
{
+ "name": "tests/integration/targets/filter_lists",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/filter_lists/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/filter_lists/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "a3a64013646090de20664eb7ef124f073b43ba432f44575daf4a060e2ed304bd",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/filter_lists/vars",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/filter_lists/vars/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f0f14176cc96c7ba313422b6496ef1e79045c03e6e70ac77677c39b7bd2fd5f9",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/filter_lists/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "96646c5ab7118c53b8b722f6abe91a7ed4d3eed9be401faefb399d6a8f427c2e",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/filter_lists_mergeby",
"ftype": "dir",
"chksum_type": null,
@@ -8775,7 +9524,7 @@
"name": "tests/integration/targets/filter_lists_mergeby/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2908fcc4953a67530ae1d897c66e847d8281e02299b5563f9c751db06ba10036",
+ "chksum_sha256": "96646c5ab7118c53b8b722f6abe91a7ed4d3eed9be401faefb399d6a8f427c2e",
"format": 1
},
{
@@ -8803,7 +9552,7 @@
"name": "tests/integration/targets/filter_path_join_shim/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "be8d8b0ca4ade5971990fe8ae0d00b52a1e6abd717be6ea768ccb9cb09a0807e",
+ "chksum_sha256": "4762e4d5adeeb09c1dbca4b156fc16c19f786f55765669aad0bc9f3b41edac9b",
"format": 1
},
{
@@ -8845,7 +9594,7 @@
"name": "tests/integration/targets/filter_random_mac/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "04d550c69028ec48b216c053bb6d7ddb9e0e57fe93874138b09aff2776789444",
+ "chksum_sha256": "97aeafca6d46181e78434a9dfbd80a826ba334abe46e42d18b6304d7aca14e3c",
"format": 1
},
{
@@ -8873,7 +9622,42 @@
"name": "tests/integration/targets/filter_time/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2908fcc4953a67530ae1d897c66e847d8281e02299b5563f9c751db06ba10036",
+ "chksum_sha256": "96646c5ab7118c53b8b722f6abe91a7ed4d3eed9be401faefb399d6a8f427c2e",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/filter_to_ini",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/filter_to_ini/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/filter_to_ini/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "7e22a177f1018cb3fb7d33f211b3d67febfdf94c4ad3a473a5b4d94ce608e696",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/filter_to_ini/vars",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/filter_to_ini/vars/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "4904a7ed81f74b549a410760227576dca416089991c2e1202dfa14e0f6ae8299",
"format": 1
},
{
@@ -8915,7 +9699,7 @@
"name": "tests/integration/targets/filter_unicode_normalize/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2908fcc4953a67530ae1d897c66e847d8281e02299b5563f9c751db06ba10036",
+ "chksum_sha256": "96646c5ab7118c53b8b722f6abe91a7ed4d3eed9be401faefb399d6a8f427c2e",
"format": 1
},
{
@@ -8943,7 +9727,7 @@
"name": "tests/integration/targets/filter_version_sort/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2908fcc4953a67530ae1d897c66e847d8281e02299b5563f9c751db06ba10036",
+ "chksum_sha256": "96646c5ab7118c53b8b722f6abe91a7ed4d3eed9be401faefb399d6a8f427c2e",
"format": 1
},
{
@@ -9188,7 +9972,7 @@
"name": "tests/integration/targets/gem/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "020f2d3391b7333827fb1597b69765ddb2c446f74ae4289940532c9b19f0339f",
+ "chksum_sha256": "87303b659cb6912a85bcb0bb9d36b37da7cf169fbdc196e26f0052703247bd58",
"format": 1
},
{
@@ -9244,7 +10028,7 @@
"name": "tests/integration/targets/git_config/files/gitconfig",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ecf5a7fd8075b61a600c5ffeedd56209f6b50ba1cacc3e25b52a7d6ffc930058",
+ "chksum_sha256": "c930a94d1cb790dbbb457349c6f14e8ee01670c8f4f99bb34b7401432fcd2b4e",
"format": 1
},
{
@@ -9293,14 +10077,14 @@
"name": "tests/integration/targets/git_config/tasks/get_set_state_present_file.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "741853733f1628c55e98da1060ed6f3d3ac55f8fc301382d88d31c4df1c20029",
+ "chksum_sha256": "fd95a0bfddcda9042499510380082833ac53e55059a247233aeec0c9f1519815",
"format": 1
},
{
"name": "tests/integration/targets/git_config/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e1d8282e63ce7b7eee45065c80c1fe9306d0f5e59f2a6275f3f9b59ac7759565",
+ "chksum_sha256": "e211e341a9f1b6c9f171373cf5b463d53ef8987cf95e5d08c84f219a4ced5339",
"format": 1
},
{
@@ -9311,10 +10095,24 @@
"format": 1
},
{
+ "name": "tests/integration/targets/git_config/tasks/set_multi_value.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "65ad961da7068a7aa23b5953f20560e7020b60cf19be7319c90fa88ff1026a60",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/git_config/tasks/set_value.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "8813ea4f9c4657a9c64a5938084a6e90d5d259b606020ef68ce8f64c9491ce48",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/git_config/tasks/set_value_with_tilde.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d7df2b83250b9ecddd3adc61e334de7d006fc645f23ea4ea6782134e30178744",
+ "chksum_sha256": "ceec2da15d56fe1520f3a59234038870f62a9bbb9734e537d2372c634eb310b8",
"format": 1
},
{
@@ -9346,6 +10144,13 @@
"format": 1
},
{
+ "name": "tests/integration/targets/git_config/tasks/unset_multi_value.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "bc61b0a6079833503166e0e846862721404cf471d2e57d68a73b384bb980322c",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/git_config/tasks/unset_no_value.yml",
"ftype": "file",
"chksum_type": "sha256",
@@ -9381,6 +10186,125 @@
"format": 1
},
{
+ "name": "tests/integration/targets/git_config_info",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/git_config_info/files",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/git_config_info/files/gitconfig",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "31c8e16479e6950c02cef8aa3b803b9dbe0452b06019ca62845dbb413b28e925",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/git_config_info/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/git_config_info/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "3b4106020a362e34cbc75011bfa013d65acb8224f6fbc931cfc6438b67888627",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/git_config_info/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/git_config_info/tasks/error_handling.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e842fe7a82d73b5353f76e9bd7a475cf54c66924fe4a2ccc641d711c0872ee4b",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/git_config_info/tasks/get_all_values.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f93633864a11930144afad0177c4ec6638b810a92dcdc46792326699c45502c9",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/git_config_info/tasks/get_multi_value.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "b1a1523f27f8c24d4137232a04b3f170884713325e4861f8b152ed21baeaf456",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/git_config_info/tasks/get_simple_value.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ea6775be26d468ef1b65f59ecd99b950f9be583643136e162d2276575467af93",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/git_config_info/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "feeac06682a424fbe822d5568bfa8a48e3bc24233f383b84ca5534c3c143bceb",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/git_config_info/tasks/setup.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "2d65b28d74bfbcc78ebf01b8a9ddd6c3939c50303153a84d49b5a3c05f320a78",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/git_config_info/tasks/setup_file.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "b72ee90e566e5fe67fd207ccc86e17b804d0873e115f708bdeb0933dd9e11dea",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/git_config_info/tasks/setup_global.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "39457f25bf856f9e890a3efb8322502d6c7ca0a304092a4678f0d4fea05228ac",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/git_config_info/vars",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/git_config_info/vars/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "274edd91b7a0d9245cf3291ce1a25e31e7b5d500f96be43b4946aae26752331c",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/git_config_info/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "a3e3401add1aae4e9d51ea5372aca862480b2b36f02879a8d6a56547710c3598",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/github_issue",
"ftype": "dir",
"chksum_type": null,
@@ -9549,6 +10473,48 @@
"format": 1
},
{
+ "name": "tests/integration/targets/gitlab_group_access_token",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_group_access_token/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_group_access_token/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e0173a1909514d8f0693c09e68871f5096ae4506b64974213ba02aed7deded30",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_group_access_token/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_group_access_token/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "947ed925420c358f8c6b0a158533dea621d75dd33fa8f4c288656609b5f1dd8f",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_group_access_token/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "d3447437c5aae0231cf623843756a50ca7e67b07d15fc1a9e1b85c216edff835",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/gitlab_group_members",
"ftype": "dir",
"chksum_type": null,
@@ -9661,6 +10627,244 @@
"format": 1
},
{
+ "name": "tests/integration/targets/gitlab_instance_variable",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_instance_variable/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_instance_variable/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "58e27e5a64d9337737437b525e9c879cef72e4f20a45b262f688ec115c223e3f",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_instance_variable/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "efa136c759c51db61ae085d265a6d6402c567e9bb00875292d45dbb00c1ed892",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_issue",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_issue/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_issue/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c7de5f3c50745e7fb9c0a418990c339bfc961b2654bb123d8f3586443c3a3e8f",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_issue/files",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_issue/files/description.md",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "38730f925a866d1552679c937e29e4a93ffff2c62cd4dd45af36c8eed0d15bc4",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_issue/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_issue/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "200e87b52d52a19cc79a5d4a1084ef77fae982d566a273f0d2516d8d33557871",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_issue/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e3af936ee0cf087fb087896746d41d8d7ae99e33506dbeb30068b51dd3f3f452",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_label",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_label/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_label/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "b2fcd88d332ea76fc8d8bc586430779eee08e2b237ce878fbe9400b8250d21d2",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_label/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_label/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9e05c81e24800d57f1402e492a1e5b0e80e6d556223c93e6b20ea3601a8b6843",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_label/README.md",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "5f86e10c9605733e77b7de9d2a196946ddc6f15491fd77fee9654795898d4952",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_label/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e3af936ee0cf087fb087896746d41d8d7ae99e33506dbeb30068b51dd3f3f452",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_merge_request",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_merge_request/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_merge_request/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e99adbea67409fe8e61637d4bfa1330d284c20a4d0ee110ae554139e037353de",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_merge_request/files",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_merge_request/files/description.md",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ebb6cbc8e9f34774017cdf66e4b409116822da6d2b5e1b45ec41c23f6f2deebe",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_merge_request/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_merge_request/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "30a35674ee04d0cd8221adf3d3e078e44490a7599a8b0980809e4d3bcbd0c472",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_merge_request/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e3af936ee0cf087fb087896746d41d8d7ae99e33506dbeb30068b51dd3f3f452",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_milestone",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_milestone/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_milestone/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "bcdd7b6fa0d0386aaa7acb3bf65cfba5285a5afab60bbb7308893ce1d631d486",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_milestone/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_milestone/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "cca03bd21ada6db7a608b824ae217fb3c27eb5be48ba81341f1fdfbbc3e85c82",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_milestone/README.md",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "b5d80bca7d2afc1052b42909637c958a9c11a935b32f954b2486a391eef1b8d3",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_milestone/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9f2e9c2089638d8a679fe98cd3570d01baf44d1898f1814843b4a5e9f60144fc",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/gitlab_project",
"ftype": "dir",
"chksum_type": null,
@@ -9703,6 +10907,48 @@
"format": 1
},
{
+ "name": "tests/integration/targets/gitlab_project_access_token",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_project_access_token/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_project_access_token/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "7ec27120ebe8a340ef8283e8a5deb3e296f0794e9d15ba1613706cc9e051c72e",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_project_access_token/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_project_access_token/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "b03b31a8f245507798083326aa0d17480cabd4abd621cf93bbed21e6e3912fb4",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/gitlab_project_access_token/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "d3447437c5aae0231cf623843756a50ca7e67b07d15fc1a9e1b85c216edff835",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/gitlab_project_badge",
"ftype": "dir",
"chksum_type": null,
@@ -9983,17 +11229,31 @@
"format": 1
},
{
- "name": "tests/integration/targets/homebrew/tasks/main.yml",
+ "name": "tests/integration/targets/homebrew/tasks/casks.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6dea53684420b39d7e51987f3cb6b74e57a7eec45999c4963d9b9208a518b887",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/homebrew/tasks/formulae.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "f3b0ace4227b32e8e9a7c3a35da793720787e2617f21621f8836d88f5d356b80",
"format": 1
},
{
+ "name": "tests/integration/targets/homebrew/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "63b4898f3fec452093d5f26f0d0d2ea42365739d61bbb92ef4973c3115d636f9",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/homebrew/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5891f82ed92622416753a31732b6210796f5eb1e4207b0b21c0ac86c3fffc6fa",
+ "chksum_sha256": "f5ad036c484e4b95376b2aa53d3f2fd2557e6b2395acff6522f8e7f5f185df83",
"format": 1
},
{
@@ -10035,7 +11295,7 @@
"name": "tests/integration/targets/homebrew_cask/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5891f82ed92622416753a31732b6210796f5eb1e4207b0b21c0ac86c3fffc6fa",
+ "chksum_sha256": "f5ad036c484e4b95376b2aa53d3f2fd2557e6b2395acff6522f8e7f5f185df83",
"format": 1
},
{
@@ -10063,7 +11323,77 @@
"name": "tests/integration/targets/homectl/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "07576b5ab2023931b1d1a1f7b6b9986c42ec71a6ac26b90397228eb0f7857eb5",
+ "chksum_sha256": "92306b5675244d20e85f42015388f767f6195f684bcdcc0e06044fb206679859",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/htpasswd",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/htpasswd/handlers",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/htpasswd/handlers/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "b86ac9b09b8d51752d56659c9e0fd143772e3ca15dba1b9c064faefe708dfe3d",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/htpasswd/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/htpasswd/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "3b4106020a362e34cbc75011bfa013d65acb8224f6fbc931cfc6438b67888627",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/htpasswd/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/htpasswd/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0f6a18ed63494fc4c839ab8a67677a7a62159a46eaf0de93ec4c9e84e0c2ac8c",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/htpasswd/vars",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/htpasswd/vars/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "285e834d1a5f360c5fa663b887508eb10a1beea8c1d3260db1cb955c0507b6ec",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/htpasswd/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f281b2b1ff0427e9bbe8f7b4258497cf8c136674ee9d95aaaca82003846810cc",
"format": 1
},
{
@@ -10574,7 +11904,7 @@
"name": "tests/integration/targets/ini_file/tasks/tests/00-basic.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "20eec1e8f2a9fc6a8f90bf28afc7eae22d402f7d5022b3543a05d495b2f3e83d",
+ "chksum_sha256": "20133af75b91bd3db4727312bc0a62ed2f161943bc087b23de003f011faba3ca",
"format": 1
},
{
@@ -10599,10 +11929,38 @@
"format": 1
},
{
+ "name": "tests/integration/targets/ini_file/tasks/tests/04-symlink.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "a2044bce63a8cadaa03686bd008a7148ebded4034bce871f10a009c04868dbc8",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/ini_file/tasks/tests/05-ignore_spaces.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "024c28b113112ca33c3919ba892da93902d73a3c8fccbbfb864ce9ccd55d1d0d",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/ini_file/tasks/tests/06-modify_inactive_option.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "b3878eadd23e106fc70d16d49b6250dd3810449b7c4486cf97ad2dbb1ce55fe4",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/ini_file/tasks/tests/07-section_name_spaces.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "71db0a44257814619da54f25a11a35ea95d63c43821d35059edf027e75dc8033",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/ini_file/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d957ff276ed44fd63d2202fdc938551d4379a951cb8b291a5558a1175c482b05",
+ "chksum_sha256": "3747adf416c4b3fa837c686860ec828985edd6a3b7e0c5993dd9da892085e7d6",
"format": 1
},
{
@@ -10665,7 +12023,7 @@
"name": "tests/integration/targets/interfaces_file/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8fd3fb5db340b283f4dd25e00f82324cac5d61539c008884ea89378652360a7b",
+ "chksum_sha256": "849e4bec85dbb41c9d3305cb95cda02af50ec1f074197296bb09aef73b3fe7d8",
"format": 1
},
{
@@ -10767,6 +12125,13 @@
"format": 1
},
{
+ "name": "tests/integration/targets/iptables_state/tasks/tests/02-partial-restore.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "b1188745c93fd3c62c66910cb549ce6bc7fa0571f4314b4c5e0b4b507d68c9d3",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/iptables_state/tasks/tests/10-rollback.yml",
"ftype": "file",
"chksum_type": "sha256",
@@ -10777,7 +12142,7 @@
"name": "tests/integration/targets/iptables_state/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3c349224883470255621679e4fe285c67b1a2538b135b57d75581a8f3404eb40",
+ "chksum_sha256": "8e6d9efb698387bd85ed5820c8b1b049b3d59838a030d231afafc2d65504e9bc",
"format": 1
},
{
@@ -10889,7 +12254,7 @@
"name": "tests/integration/targets/iso_create/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bad943e25b57511690c80988d8e4695ee980395e52cf9daf6fb93e6b14b2b78d",
+ "chksum_sha256": "f083d1e229c44a4f760b339203d82daa5640de9e94b209ce6b644d4167ffc7cb",
"format": 1
},
{
@@ -10945,7 +12310,7 @@
"name": "tests/integration/targets/iso_customize/tasks/iso_customize_exception.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "58d34a05df22d1b52617815e2b2b425a51af42f809bb93a3cb1fa123966366f4",
+ "chksum_sha256": "66f7f27900f686ae697878eaf8a78d38ed2a0b5480c77d8d25396dae9f18df48",
"format": 1
},
{
@@ -10973,7 +12338,7 @@
"name": "tests/integration/targets/iso_customize/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7fa272fd0b848965be407c1029f0091491346121c82ff3f801c5b4a0fd02a067",
+ "chksum_sha256": "5d893c0cf3610ae49501c41a635fe6f22df50a711616706e57eca46d64f91bbb",
"format": 1
},
{
@@ -11120,7 +12485,7 @@
"name": "tests/integration/targets/iso_extract/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "eeb6e9152c52bd05f9887bb2587664b23db23ddfb846d6ff4dbbf3ee4fa769a9",
+ "chksum_sha256": "f1d6b972f10c562a8e6811d7df90165cd0282d6c60eb43c0b4b6f06c97cc2fbe",
"format": 1
},
{
@@ -11155,7 +12520,7 @@
"name": "tests/integration/targets/java_cert/files/setupSSLServer.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3a70f0ef4ee25e120cacc5a56c6f1c79ea9d4f0d9783b3a20e438f4f256d2e0a",
+ "chksum_sha256": "2d31dbee7237997b4becb3ba1b56160d3adf6f2a1a355fc39d8555ff50cd5473",
"format": 1
},
{
@@ -11204,14 +12569,14 @@
"name": "tests/integration/targets/java_cert/tasks/state_change.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "627a1956eaaf4eb22605dfbe350d300843f18788b402c7dfe3c3d3f82894629f",
+ "chksum_sha256": "fdec45c3804e404f96bbd3abab819416e48add016600ac3ab125a7710bc7a023",
"format": 1
},
{
"name": "tests/integration/targets/java_cert/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e8f75e90e2d1d80d3b686b9b835939455728d1769063924648561d883e130434",
+ "chksum_sha256": "0fdc251c9f9ba0dac5c92ec1b738b8fe845b0623fdca407d07cbd33b26cee924",
"format": 1
},
{
@@ -11281,7 +12646,7 @@
"name": "tests/integration/targets/java_keystore/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e8f75e90e2d1d80d3b686b9b835939455728d1769063924648561d883e130434",
+ "chksum_sha256": "0fdc251c9f9ba0dac5c92ec1b738b8fe845b0623fdca407d07cbd33b26cee924",
"format": 1
},
{
@@ -11453,6 +12818,20 @@
"format": 1
},
{
+ "name": "tests/integration/targets/kernel_blacklist/handlers",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/kernel_blacklist/handlers/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "54d5807818b8441d319ab3a8bb19c6cca598c3c3a8234419f62b974e616029b4",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/kernel_blacklist/meta",
"ftype": "dir",
"chksum_type": null,
@@ -11477,14 +12856,14 @@
"name": "tests/integration/targets/kernel_blacklist/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d8ee51d3dbb085a368c392dcec89ffcaa67640ed29a64bcc8dec44a81e4a9b12",
+ "chksum_sha256": "9566a9fa4c5d364fba20c19d647c6668dbd0ba2cc4f0cb02ed3765f22c733cfe",
"format": 1
},
{
"name": "tests/integration/targets/kernel_blacklist/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4762e4d5adeeb09c1dbca4b156fc16c19f786f55765669aad0bc9f3b41edac9b",
+ "chksum_sha256": "f755a442e3b004ad7d328bb2b389ef3997e303fb60d634da920b48800f653567",
"format": 1
},
{
@@ -11533,7 +12912,189 @@
"name": "tests/integration/targets/keycloak_authz_authorization_scope/readme.adoc",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1a06315c33a9a4581d3fa90bda3255db1662bad238ecdf131e1a211f7a9153a9",
+ "chksum_sha256": "ac7c29f80425a401f361941164c63e647239c3c5e9f3e580c15792ce0672520d",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_authz_custom_policy",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_authz_custom_policy/policy",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_authz_custom_policy/policy/META-INF",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_authz_custom_policy/policy/META-INF/keycloak-scripts.json",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "278e40b0dc5a85f0f0477b7307b18e40aa2ea8b715f027d5e05a84a12b6d5745",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_authz_custom_policy/policy/META-INF/keycloak-scripts.json.license",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c111f1eddc1753ec6db64f82f4167c31ccb175960662c30ffbea6ee2f0ed47d0",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_authz_custom_policy/policy/Containerfile",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9cb96f8a5b228a31d4091173ec6644bd28a28e87000f7613223ce0f08f913f9f",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_authz_custom_policy/policy/Containerfile.license",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c111f1eddc1753ec6db64f82f4167c31ccb175960662c30ffbea6ee2f0ed47d0",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_authz_custom_policy/policy/build-policy.sh",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "7c482590eee6303535ac1663a770d2bd78e4ceefbfc35216ceed3f6796673245",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_authz_custom_policy/policy/build-policy.sh.license",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c111f1eddc1753ec6db64f82f4167c31ccb175960662c30ffbea6ee2f0ed47d0",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_authz_custom_policy/policy/policy-1.js",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c2317f9afb78c943615f160fa61893acbf372b02929f745bc42da4d892d2c5c1",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_authz_custom_policy/policy/policy-1.js.license",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c111f1eddc1753ec6db64f82f4167c31ccb175960662c30ffbea6ee2f0ed47d0",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_authz_custom_policy/policy/policy-2.js",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c2317f9afb78c943615f160fa61893acbf372b02929f745bc42da4d892d2c5c1",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_authz_custom_policy/policy/policy-2.js.license",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c111f1eddc1753ec6db64f82f4167c31ccb175960662c30ffbea6ee2f0ed47d0",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_authz_custom_policy/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_authz_custom_policy/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9dec6dd0cc4278652c1fd9f2468d91f81e8f2afdf14664bde0d8dee115737ca5",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_authz_custom_policy/vars",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_authz_custom_policy/vars/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "eff28a6b76beccc151aac7d4da652d00566c9e6b9240ee60b90060075f73f072",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_authz_custom_policy/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "efa136c759c51db61ae085d265a6d6402c567e9bb00875292d45dbb00c1ed892",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_authz_custom_policy/readme.adoc",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "cabb18c1c11875ced954be0713bf6b9e671b3299782d243c6d3a1c69e70c5b85",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_authz_permission",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_authz_permission/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_authz_permission/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "5295763d26a77219d9accaf6256709b1bb6ab016e9fc204763f131626b2aeb33",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_authz_permission/vars",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_authz_permission/vars/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "eff28a6b76beccc151aac7d4da652d00566c9e6b9240ee60b90060075f73f072",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_authz_permission/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "807e04d87d933b1ed6b5ad3f0781e570fd1e1e8bc445c300d91dbc4cd69c51d3",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_authz_permission/readme.adoc",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ac7c29f80425a401f361941164c63e647239c3c5e9f3e580c15792ce0672520d",
"format": 1
},
{
@@ -11554,7 +13115,7 @@
"name": "tests/integration/targets/keycloak_client/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "38a55d499da32e786f6a6d91c487399bc532aa2d6074e4ff8ed5d69b1e16a21d",
+ "chksum_sha256": "10f83e1b6754b9dbc932e5bc5e6dfd85d028dffb2f85c5f9023f197211ea85bc",
"format": 1
},
{
@@ -11568,21 +13129,14 @@
"name": "tests/integration/targets/keycloak_client/vars/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3f5745bfec883f9a58adcf2038d3bc3b65ef723b9cd28de29acdadfecbc8bffa",
+ "chksum_sha256": "6027fcfb0c835def3493c3a85f66f645afedd0fc316dace42fd88aa86521c916",
"format": 1
},
{
"name": "tests/integration/targets/keycloak_client/README.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3e79f52fafe919b9e05d3ad339d992eb6106f44c7f0f04f769f62347a124b709",
- "format": 1
- },
- {
- "name": "tests/integration/targets/keycloak_client/docker-compose.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "779896e621ae4fe9bad52c9b65fbacf02f1c9c76ce75589ea4f43e52382bf5d6",
+ "chksum_sha256": "fa414cd3fffa6242a67f51b7ad13b6c569e839e088451fd933a12a8f52ce412b",
"format": 1
},
{
@@ -11733,6 +13287,55 @@
"format": 1
},
{
+ "name": "tests/integration/targets/keycloak_component_info",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_component_info/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_component_info/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "24a52969e7e1df7aef3b792ac8a527410517b75fa0301626a37d1159c57ac38b",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_component_info/vars",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_component_info/vars/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "3079a737dc0395e13e581fcb9ddb41daea9e0104b63be63289661356e1fbf0c5",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_component_info/README.md",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "7afc46db4042858635a79d39ca7d325680bbc76f4ebe9acdf94218ce2ee00a6e",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_component_info/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "efa136c759c51db61ae085d265a6d6402c567e9bb00875292d45dbb00c1ed892",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/keycloak_group",
"ftype": "dir",
"chksum_type": null,
@@ -11792,7 +13395,56 @@
"name": "tests/integration/targets/keycloak_group/readme.adoc",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1a06315c33a9a4581d3fa90bda3255db1662bad238ecdf131e1a211f7a9153a9",
+ "chksum_sha256": "ac7c29f80425a401f361941164c63e647239c3c5e9f3e580c15792ce0672520d",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_group_rolemapping",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_group_rolemapping/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_group_rolemapping/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f8e24e984b9133b9800a4dbb516ce5bd2e261187cd09236d7a8067e354d89891",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_group_rolemapping/vars",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_group_rolemapping/vars/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "2f94f9637070c64fe5ac59d0e1f970b35c42116830c865fbf0f32bfec8f11e86",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_group_rolemapping/README.md",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ffab69968ad4dc9c44d5a75003df5304abefcfd0b3e75b3c7d7c1a8f81734e0a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_group_rolemapping/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "65e953937a091b4397e44ad07dd62941a169e1d3cc1de3b71d264ef6943ff55f",
"format": 1
},
{
@@ -11813,7 +13465,7 @@
"name": "tests/integration/targets/keycloak_identity_provider/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "df76d0849e85e9397055fabcdd56433132f08b66abab7a5843782c58ce6a06d0",
+ "chksum_sha256": "32177a1221cd9929bb79d40beed27c7ec9ac6a21f35767e6e467b6b40594d27f",
"format": 1
},
{
@@ -11838,6 +13490,55 @@
"format": 1
},
{
+ "name": "tests/integration/targets/keycloak_realm_key",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_realm_key/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_realm_key/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ba93b2467c64142845310289487afb535e869f67786f299cbc0f13f701105eaa",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_realm_key/vars",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_realm_key/vars/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "50179b1d2766332c123d6c059925674f8a24f9bbaca9b759609cc7218120a217",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_realm_key/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "efa136c759c51db61ae085d265a6d6402c567e9bb00875292d45dbb00c1ed892",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_realm_key/readme.adoc",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ac7c29f80425a401f361941164c63e647239c3c5e9f3e580c15792ce0672520d",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/keycloak_role",
"ftype": "dir",
"chksum_type": null,
@@ -11855,7 +13556,7 @@
"name": "tests/integration/targets/keycloak_role/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d3eb6077a613495dc72c150bc7d266a3fd4545754c34509358fb55d06f4f2b9c",
+ "chksum_sha256": "3cb496f876d9b368d7a41234df853329ac549e16ae98a3f98588df175ef8b660",
"format": 1
},
{
@@ -11869,7 +13570,14 @@
"name": "tests/integration/targets/keycloak_role/vars/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4ec512c21b18adafebfb9fe6603537768511a4976713c6e34abfa3e0538e482b",
+ "chksum_sha256": "4baa1e693198dfadbf42fbbce6d7bcea44b6e9d8aa517a6cd2891ba88fbbe0cf",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_role/README.md",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "88574a5465e7faa1a42ab4b2b85d238aaec243b2094a01991bfb0d1f86dae0af",
"format": 1
},
{
@@ -11880,6 +13588,55 @@
"format": 1
},
{
+ "name": "tests/integration/targets/keycloak_user",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_user/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_user/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "36df1447f34eff6e41fa47def30a91d1b216ac2964e8ddd22b3321f9d5512a5a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_user/vars",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_user/vars/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "7b8a48f0f2f40749cd991e5af7589b004662923152adfa4041e8146132b4ea45",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_user/README.md",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "384d55e02d3c6809f62a6434b2194a574fcef6c52320bed4b4669ef1401f3fe1",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/keycloak_user/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6c5cc33ddcf532aa9132293a8188b970d520e6e19a706adf4ac7f1dab4590df8",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/keycloak_user_federation",
"ftype": "dir",
"chksum_type": null,
@@ -12188,10 +13945,31 @@
"format": 1
},
{
+ "name": "tests/integration/targets/ldap_search/tasks/tests/auth.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "dbc6f6fc1d3d570cad0379d617732807bf1f23cdfd643555b74c68f5e5a18b99",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/ldap_search/tasks/tests/basic.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "dfba8f9dae76e2f7411bd8aedcf06e9fc8119ede9951152c80117625afed9409",
+ "chksum_sha256": "f18f0bee9f29a8408ccf21a26e18f0528d468525ad45604d026cc4a708851120",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/ldap_search/tasks/tests/pages.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "5b07dc0c9b491cc9a6c356ada23bd75d540d30f6f9ba685d8ffb24e18c9e21f5",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/ldap_search/tasks/tests/schema.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ab37adcf512ef5d8ecc5bfba5eff760b146e222c303f42316c63ecbac1ff3805",
"format": 1
},
{
@@ -12240,7 +14018,7 @@
"name": "tests/integration/targets/listen_ports_facts/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4175607d700d452a760e89d15d27699d44d81072adcedbe0284d4756fc9f842a",
+ "chksum_sha256": "a563a000bcf48c99fbbaf8f5fcb7601f04991d6d9625b132e3b1606f139554d8",
"format": 1
},
{
@@ -12265,24 +14043,38 @@
"format": 1
},
{
- "name": "tests/integration/targets/locale_gen/tasks/locale_gen.yml",
+ "name": "tests/integration/targets/locale_gen/tasks/basic.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b94a61252c6d59374173d10a28d4b928e9883a693fc44989c13706f1a0d919f2",
+ "chksum_sha256": "ca5e0531bdc0c48b4f4563e8db39495bb36ef33bf52e800874af8e09d388c4f2",
"format": 1
},
{
"name": "tests/integration/targets/locale_gen/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "28aed6856c5df5b7008c1fde1e883d95c4e4de338a2793a49149934c155df67e",
+ "chksum_sha256": "69ac18e1e350ee7f6442a0c305d3e0be7d5b95714490d1e00c005b7843cfff61",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/locale_gen/vars",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/locale_gen/vars/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ad5ee7750c0c38aabeeea39404fc030a4874cfee9334665d4dac3826de09b010",
"format": 1
},
{
"name": "tests/integration/targets/locale_gen/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "deb0b216a5f28d319dc0159ef9a51b469745c4a3fc2de6365c209a5e62198b72",
+ "chksum_sha256": "fa7bdc4c73efb205e23498b4713b42f288994f95f98a6e52807014d6a15e0bef",
"format": 1
},
{
@@ -12310,7 +14102,7 @@
"name": "tests/integration/targets/lookup_cartesian/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7df9be441bf519e667744b3a98e3935a9caeed6f0143a6ead07b027ea5ecf09e",
+ "chksum_sha256": "367185bf3f777aed17ce668828b5a36e440b0eccb7fbc581cdc6d830dca9c041",
"format": 1
},
{
@@ -12562,7 +14354,7 @@
"name": "tests/integration/targets/lookup_dependent/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f5e85f0e230188e33cebf3b8f98571da22922af25128f832be4732f02fe79dd6",
+ "chksum_sha256": "96646c5ab7118c53b8b722f6abe91a7ed4d3eed9be401faefb399d6a8f427c2e",
"format": 1
},
{
@@ -12604,7 +14396,7 @@
"name": "tests/integration/targets/lookup_dig/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4e53ae1d11ca1e278b274c7720587a0962b38b2967efe20a113cd3f24aff5c16",
+ "chksum_sha256": "4762e4d5adeeb09c1dbca4b156fc16c19f786f55765669aad0bc9f3b41edac9b",
"format": 1
},
{
@@ -12667,7 +14459,7 @@
"name": "tests/integration/targets/lookup_etcd3/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c3a758c35a3956b13431d57c60e786532f35da1490f5dd12a686a9b9fd10b323",
+ "chksum_sha256": "8e17b946c0ec392599ddab5a0859452d0adac54df4924b3d7138e034aa6d1ce4",
"format": 1
},
{
@@ -12716,7 +14508,7 @@
"name": "tests/integration/targets/lookup_flattened/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "15f11670744ee718a1e0afe11977fc26ed56858a7b679c5754b811632107454e",
+ "chksum_sha256": "97aeafca6d46181e78434a9dfbd80a826ba334abe46e42d18b6304d7aca14e3c",
"format": 1
},
{
@@ -12730,7 +14522,7 @@
"name": "tests/integration/targets/lookup_lmdb_kv/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0756df07f6ddd0e438bceb927e9103d9cec53187b91d1ec1d4c4b8c6fdc23558",
+ "chksum_sha256": "9a5bf4504067f8e89358bffa62577085c58cf290a2fa790234ecdee48b368ad6",
"format": 1
},
{
@@ -12772,14 +14564,14 @@
"name": "tests/integration/targets/lookup_merge_variables/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4e53ae1d11ca1e278b274c7720587a0962b38b2967efe20a113cd3f24aff5c16",
+ "chksum_sha256": "4762e4d5adeeb09c1dbca4b156fc16c19f786f55765669aad0bc9f3b41edac9b",
"format": 1
},
{
"name": "tests/integration/targets/lookup_merge_variables/runme.sh",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6ca79153640cdf426ee07f5a1e5c401d958cb713ed543718b87d747d1031dd24",
+ "chksum_sha256": "7e7ed20f6d74549dffd00a8f003cfab56317142535b49ff647ec90c0ce8c844e",
"format": 1
},
{
@@ -12790,6 +14582,20 @@
"format": 1
},
{
+ "name": "tests/integration/targets/lookup_merge_variables/test_all_hosts.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "deb2413f72ecdc74c669df5e9a8f23d8bb7043f8ea01689958c4228d1587acbf",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/lookup_merge_variables/test_inventory_all_hosts.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "acdbd02d72a7a0e7af195d6cfbb43f178651d9bc18e2c0ed15f31f11fd801683",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/lookup_merge_variables/test_with_env.yml",
"ftype": "file",
"chksum_type": "sha256",
@@ -12947,7 +14753,7 @@
"name": "tests/integration/targets/lookup_passwordstore/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4ec0d9677a42bf61ac68caf67be75a4d2e68577acebf9c9836054c538690aca9",
+ "chksum_sha256": "a53bb6130f631b58fd3cec70222197a5be8670d12925a4791a6faf6ee2d4af55",
"format": 1
},
{
@@ -12961,7 +14767,7 @@
"name": "tests/integration/targets/lookup_random_pet/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "15f11670744ee718a1e0afe11977fc26ed56858a7b679c5754b811632107454e",
+ "chksum_sha256": "97aeafca6d46181e78434a9dfbd80a826ba334abe46e42d18b6304d7aca14e3c",
"format": 1
},
{
@@ -12996,7 +14802,7 @@
"name": "tests/integration/targets/lookup_random_string/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "15f11670744ee718a1e0afe11977fc26ed56858a7b679c5754b811632107454e",
+ "chksum_sha256": "97aeafca6d46181e78434a9dfbd80a826ba334abe46e42d18b6304d7aca14e3c",
"format": 1
},
{
@@ -13024,7 +14830,7 @@
"name": "tests/integration/targets/lookup_random_words/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "15f11670744ee718a1e0afe11977fc26ed56858a7b679c5754b811632107454e",
+ "chksum_sha256": "97aeafca6d46181e78434a9dfbd80a826ba334abe46e42d18b6304d7aca14e3c",
"format": 1
},
{
@@ -13080,21 +14886,49 @@
"name": "tests/integration/targets/lvg/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1ad0a514f697052105236d6d2c453d275f200360ff3894c62af0f6d8c81fecb8",
+ "chksum_sha256": "1c61cb25b3af71f166a0fab76f8a6cc76ca147aaa03782244df611456535f332",
"format": 1
},
{
"name": "tests/integration/targets/lvg/tasks/setup.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "07a044358f1356bbae010ac78f2b1c7b095fa552553b8fafc9704461fb1f039c",
+ "chksum_sha256": "0d99fbe3762fd2f77f20dea7568be026de98af4484693a4c70b1088f067ee3c9",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/lvg/tasks/setup_missing_pv.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ae33999d5e48caa2db675b50978533ef374051ac3f3b6f414a0dd3e0ebd91aa6",
"format": 1
},
{
"name": "tests/integration/targets/lvg/tasks/teardown.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2bcc43bcc233cc9210754c593a5b466b88167357af43107126b7bf7cadd93855",
+ "chksum_sha256": "a78d0a442bb2c7ed52b21c485dca3b518c68267b67c653d23d6b4d18576901e0",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/lvg/tasks/teardown_missing_pv.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "139fe1b440656a93b92e7cf87307f4191d46dd89c298522156e0c59787781eec",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/lvg/tasks/test_active_change.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fb8460c4f65988cf27858afd9cc3e48d0f2b1c4e4937e31d4746dd972c3712d1",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/lvg/tasks/test_active_create.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e8d012d42cfcb4801d15bd776847d169cb5d43e82a0e6eca926edf970ca671b1",
"format": 1
},
{
@@ -13115,7 +14949,14 @@
"name": "tests/integration/targets/lvg/tasks/test_pvresize.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "24a67a6028e690611e279795cceb0a13f8cd2e3f4b652a3b63bb335f8f9828f3",
+ "chksum_sha256": "455595ccf94cecdee206d9be514437957412e3ea0bf64bbd0458931424ad2a86",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/lvg/tasks/test_uuid_reset.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "087cc402ad79ec76ba46c2597e3b4b1bd598c632a9c05b3f537de0f72bd31c06",
"format": 1
},
{
@@ -13126,6 +14967,132 @@
"format": 1
},
{
+ "name": "tests/integration/targets/lvg_rename",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/lvg_rename/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/lvg_rename/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fb1230e0d649f5495cdd98e7e8000061f7cf6ef8fcf2c041275abb1e3c27d72a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/lvg_rename/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/lvg_rename/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "72f6f365053cd57efd8dd135b0f63de87d9b8cd735d974c2401f6f34f85751ed",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/lvg_rename/tasks/setup.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "2a22b424ce28c864af27fd284b9bc41fc8f2e3970f5103939321d09e492fee05",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/lvg_rename/tasks/teardown.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "4254979f004e28b2b7f25df2207b97ea3a1e58d383273a8fed1ac51617b3c47b",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/lvg_rename/tasks/test.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9656eb76a0733b06bd304708876e4eec6f65077d49d8ed0849f24a9a19866948",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/lvg_rename/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9d0129639c9e6b3c8b0e7579bb0355e30705fb7fbe40bcb591210e39dfbd3512",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/lvol",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/lvol/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/lvol/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "2bfa19c3024fcba582ae0c934106ab0792de055dbaeb7620fbaf2a3ba6ffbace",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/lvol/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/lvol/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6ce6baeda36bc5dc4093a5912f412762d24e3964a37bc53f9b7a305e95e855bd",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/lvol/tasks/setup.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "2293ea3da8d1a5bd6d657f03c74a71081fee2d45cc10bcfe8397ddffa992cda2",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/lvol/tasks/teardown.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "85529873e02538d130626086331d50813274b2b534dc7303ae7602e3e22d1474",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/lvol/tasks/test_pvs.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "791c4ff7424ca84752a7e4294e686bfd5b5984b73fa647faeed58b73d8ef3df4",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/lvol/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "07343d5c5f99d5ceabeb2cbab3c741a14b760b6141bd4fe371725822c0c718cd",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/lxd_project",
"ftype": "dir",
"chksum_type": null,
@@ -13213,7 +15180,7 @@
"name": "tests/integration/targets/mail/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0f50538e1bc1f378a161b65870cc530b3880663a2968a4c8241bee083e03ca06",
+ "chksum_sha256": "14db8a6d9b4c12aaba4d38d59d4728c1554f43a777af1a19c8394356184296f2",
"format": 1
},
{
@@ -13241,7 +15208,7 @@
"name": "tests/integration/targets/mas/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "19cb6f818e0e402b838d921f912959636770f2c1be04ce698d1e0f33d136b6be",
+ "chksum_sha256": "d2cc52135c65b59c8f4da521391f50bd46a4535a3968db370bfdbae510e2cc7f",
"format": 1
},
{
@@ -13808,7 +15775,7 @@
"name": "tests/integration/targets/monit/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6270ea2c23a9e7bf3ead0602decdcab7bf7405a24251b23b5756974402759b57",
+ "chksum_sha256": "6d149a4876b4142b767a133c13955a7b04959a4f4af75c85686370897a92c06a",
"format": 1
},
{
@@ -13906,7 +15873,7 @@
"name": "tests/integration/targets/mssql_script/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "600161fe11bca5382381ae0bdfdf1a51cb43f00b7023701ddbde8598dcaa508b",
+ "chksum_sha256": "17848879f0570a23ec7eede13bb3ca4fed18369cfcd08eb27fed9a28e9b535d3",
"format": 1
},
{
@@ -13976,7 +15943,7 @@
"name": "tests/integration/targets/nomad/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e99003f7e70ca6802d437ffc7d4b53706b85def986fa33860eff6b679c0896e3",
+ "chksum_sha256": "9dbf1ec049922296b7ee2bf29cf0ce137dee565577a524aedb784baff974651b",
"format": 1
},
{
@@ -14039,7 +16006,7 @@
"name": "tests/integration/targets/npm/tasks/test.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "06c4f3d36f38c0ea5c2c9712cca7bb4782365bc1871f9034bd698d1126331b58",
+ "chksum_sha256": "a2e6705046cd3f37054c2f8bd656b95795b033afb1b3f71c409a026465034f4c",
"format": 1
},
{
@@ -14102,7 +16069,7 @@
"name": "tests/integration/targets/odbc/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "56ccd675892edef06817b40d8d6be532f7293765f1b52ddbae1f412725336249",
+ "chksum_sha256": "033b45d66c2ca6ecd276291fa0066c34dc98ec6263115927396c18f66a2d99a6",
"format": 1
},
{
@@ -14123,7 +16090,7 @@
"name": "tests/integration/targets/odbc/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "46ccdfc640a6941875ebc7366ae736a12058166f9eb0603d1b1851871a4641bd",
+ "chksum_sha256": "24f1fa8daab5bb606db8b38467d73c2589b098eabaa4b7435f024f4ceac8924f",
"format": 1
},
{
@@ -14193,7 +16160,7 @@
"name": "tests/integration/targets/one_host/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "02cb1e273b28df5ba99c3434be90308779ac4c7f4583c905ae133cdda3eb2811",
+ "chksum_sha256": "f738dbaffc4dacc6a0cfb8d7dc3b037b25112fba4ed20a93cccb034cddc76a68",
"format": 1
},
{
@@ -14298,7 +16265,7 @@
"name": "tests/integration/targets/osx_defaults/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7bf706da04a49c14a8c6e07827e48d81a00113633a86979e8f5d4abd2300e9b8",
+ "chksum_sha256": "8e1df26fec1b24dd05c880e8818e1bf995b349bd36fd15a1480b8eefcfdba971",
"format": 1
},
{
@@ -14316,6 +16283,20 @@
"format": 1
},
{
+ "name": "tests/integration/targets/pacman/handlers",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/pacman/handlers/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "8382cada5ec965efd90579550a1a04be33c446380e3a4f1518e396bb88ba08c5",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/pacman/meta",
"ftype": "dir",
"chksum_type": null,
@@ -14347,14 +16328,14 @@
"name": "tests/integration/targets/pacman/tasks/locally_installed_package.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b1798920a40f41a51b22500304a3186341db67c93dad97b3aa45448df7c4a300",
+ "chksum_sha256": "573cc368f9bdc853e46194126e10988cc5246be50e6623590b801be50a6795aa",
"format": 1
},
{
"name": "tests/integration/targets/pacman/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d052b4adb40acd4cdbfaf139411b0fb74af245c1fca9126000564ce1ce5d80e2",
+ "chksum_sha256": "2137c446350b735c98c57231f94a82c6bce04ef214f642ae1321fb098f7ddf75",
"format": 1
},
{
@@ -14375,7 +16356,7 @@
"name": "tests/integration/targets/pacman/tasks/remove_nosave.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b8e4738b88af420276caed70a1c76c5789043be60504ba95912085be1ae68d04",
+ "chksum_sha256": "483b515b6c5cb232ae6a270a8bb7163447bbec168b15e2457197ddef7081f6a7",
"format": 1
},
{
@@ -14386,6 +16367,13 @@
"format": 1
},
{
+ "name": "tests/integration/targets/pacman/tasks/yay-become.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ca3b460eaf0e8a50a21151ab38ec840faa18e0529ee29cd5f0564ff000aee95d",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/pacman/aliases",
"ftype": "file",
"chksum_type": "sha256",
@@ -14592,7 +16580,7 @@
"name": "tests/integration/targets/pids/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fbfba12288cabf657465e10ac584985224f3830c7d421342f5815b57ba6027c6",
+ "chksum_sha256": "d371cd5c923d5fe22f113bdf448ca8e5bb34e22ec1897963e16137b76d339e32",
"format": 1
},
{
@@ -14603,7 +16591,7 @@
"format": 1
},
{
- "name": "tests/integration/targets/pids/templates/obtainpid.sh",
+ "name": "tests/integration/targets/pids/templates/obtainpid.sh.j2",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "845eea7405e1d7deb8b10655a5688c96a2c4abb0c4861cea000f0e01a8222279",
@@ -14634,14 +16622,14 @@
"name": "tests/integration/targets/pipx/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cb78d7641bd06d9f3a500925c867787c8f63cce145859726b8218e0a0cdc4c31",
+ "chksum_sha256": "259a225bfc6e0503eb76b426de6e3a96270329dd9882198174e9b310ca5fed80",
"format": 1
},
{
"name": "tests/integration/targets/pipx/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b0f6bffe899b20d2d6c1b0df7e69da08e7730344bf267c3a80d56c8299af22f5",
+ "chksum_sha256": "60467481001ae1968fd4ed6b8a1d120d34f60d0c60f436cc359daaa9871a4a6d",
"format": 1
},
{
@@ -14669,7 +16657,7 @@
"name": "tests/integration/targets/pipx_info/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0cf6c820f954829c114e7d0d121752c43fce99ad9709ac40783ac1ca2acb3277",
+ "chksum_sha256": "78ff79ac85426ff32bd208fa12ef5b1c85f6eedb6ea507f78bbd5f68cea25fda",
"format": 1
},
{
@@ -14697,7 +16685,7 @@
"name": "tests/integration/targets/pkgng/tasks/freebsd.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d6e9d3dbb1920dc5a8be607b653e809e0ac967b4289d0ed4fc2cc6b13fb770da",
+ "chksum_sha256": "509a75baa3a667ed0857ae9050e5bff14c6045c4cc48e9f0ddd51ba40e287d62",
"format": 1
},
{
@@ -14792,6 +16780,69 @@
"format": 1
},
{
+ "name": "tests/integration/targets/pnpm",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/pnpm/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/pnpm/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "35dfb6bdfdb9176e795b5fe61ed2df04282630b6454d601463ec6fabb32e8e94",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/pnpm/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/pnpm/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c34610492a3532479e9c5aa324f02561b805b4825577389cfed07b0224884024",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/pnpm/tasks/run.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "8f97b9837a2b45c7f19b4b1b2607e8f08105ef0872529f0b234e4ae4f888689b",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/pnpm/templates",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/pnpm/templates/package.j2",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "686421a983225252b1288c5810e3f2dbf143627f12685f22bf872994d906c143",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/pnpm/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "810540c30a16b6b708cb13f262c34f9bed64e3888e006d0319919f9a48948c30",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/proxmox",
"ftype": "dir",
"chksum_type": null,
@@ -14809,7 +16860,7 @@
"name": "tests/integration/targets/proxmox/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8e699ba15bc92b1e2ddaf15c5ec2eeaddf21ca3ccc271610434154750043fef5",
+ "chksum_sha256": "022442d626485e97bd8aab4815a3c5d5b868f35fcf954373451497b74830711f",
"format": 1
},
{
@@ -14820,6 +16871,76 @@
"format": 1
},
{
+ "name": "tests/integration/targets/proxmox_pool",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/proxmox_pool/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/proxmox_pool/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "591b733803c9612e9cfdcae70808ba59a7bb9c3d223a34eb788fd275f749a40f",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/proxmox_pool/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/proxmox_pool/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "1711f98cc3530e91385d6c79357dc35bc26eb11ebfe8ff34650c3657254bd93a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/proxmox_pool/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c7dd6c30460431ab9115115880ac92698e9d49bf62809543134802ae02da0cbf",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/proxmox_template",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/proxmox_template/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/proxmox_template/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6b318c0b460553a96c5a3b202ae982b170cdc30129ecdcd35741f2e7629e0ace",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/proxmox_template/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "48acb717b0af50b382100ab5635a4d21298f5231390021dd2441e63ddb3f8557",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/python_requirements_info",
"ftype": "dir",
"chksum_type": null,
@@ -15061,7 +17182,7 @@
"name": "tests/integration/targets/scaleway_compute/tasks/pagination.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "62d53d3e698830c0e76b1a8b42bcb1f3636ba01acb8f377f1a387bce19955517",
+ "chksum_sha256": "e9cde809daec0d1a00038ebb89c139e45ab20a0cd120e5b2bd6b04bb088046b3",
"format": 1
},
{
@@ -15285,7 +17406,7 @@
"name": "tests/integration/targets/scaleway_container_registry/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ae2465a002101d0e936eca4abd36955e55255312037470434adad7899404cb97",
+ "chksum_sha256": "fd0b446333a91b156cfa31bf8958ded50afef2b4555f221ae9128696250bd2ed",
"format": 1
},
{
@@ -15565,7 +17686,7 @@
"name": "tests/integration/targets/scaleway_image_info/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e657049baf4c4904b741de7b0c597d9aa5921d2874edce0878ea17239e2c638b",
+ "chksum_sha256": "b9a6d16a488c93ccbb05ff876f350ec46184f61926d06f46df7a80032551837a",
"format": 1
},
{
@@ -15635,7 +17756,7 @@
"name": "tests/integration/targets/scaleway_ip_info/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "14ebc31e2938b9baacd6b105524f7afd36ac68a47726584c135c61c9381885c1",
+ "chksum_sha256": "a8fc646ff4e05bf0805551a198b5e054328a07a54931149c977a8c5642fd1dbf",
"format": 1
},
{
@@ -15705,7 +17826,7 @@
"name": "tests/integration/targets/scaleway_organization_info/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "369c65cf782280880d3ccabc262bb47816a66512e7a691facdd2d2ac7116915b",
+ "chksum_sha256": "bf93f12d8c7afbbbbd586253375a7031f9646333efca53ecfaa7a6bd63ccf5a1",
"format": 1
},
{
@@ -15775,7 +17896,7 @@
"name": "tests/integration/targets/scaleway_security_group_info/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "dda5e92c672c34999b52cf34defb55bacf5a07e8c06f1b80ddabd5c499327e30",
+ "chksum_sha256": "d25e53c49ed7f566de46ae28851b7df247621be26e5ad22ebd46bfc2e2c34d05",
"format": 1
},
{
@@ -15845,7 +17966,7 @@
"name": "tests/integration/targets/scaleway_server_info/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "49e4c5d7c55fa76eb8ebcc9816223d230a6f1eb038fd02c9ceeacc6d0f0c470d",
+ "chksum_sha256": "232289c9891e981244089339157ae4d6c34c8b6cead69d3d9dd8a7add5c76dc9",
"format": 1
},
{
@@ -15873,7 +17994,7 @@
"name": "tests/integration/targets/scaleway_snapshot_info/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "08b39422a4294f6dd7beaafb9869db0662efeddf009574b416c4531c6f8541a7",
+ "chksum_sha256": "b1631615a8a46e2c117bfc050518f5bf6def402f2fa53cde5c7d80d8a4ec6239",
"format": 1
},
{
@@ -16013,7 +18134,7 @@
"name": "tests/integration/targets/scaleway_volume_info/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a00602b6663fa18a7f993cef164e84cf4881a60d5e8ca2d8b28b3c08d9977e48",
+ "chksum_sha256": "0a6393846e20570d6c708568a9bf3c86dfd089c41300f634eceaf13e869f7b5d",
"format": 1
},
{
@@ -16307,7 +18428,7 @@
"name": "tests/integration/targets/setup_docker/handlers/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e0ad8f1433b5bc0a03934c2501da25f96dc7a671160f097ba7cdd5e0463bfaa7",
+ "chksum_sha256": "10bf1014c22c4cbb4bb0caa90d5c10abf0c784ae9d70cacf84d8fbbb01f30c66",
"format": 1
},
{
@@ -16349,7 +18470,7 @@
"name": "tests/integration/targets/setup_docker/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a58ccd0f97b0ed64adaa9a2a23c5f050f6571d943b7148094179eada2e7ac06d",
+ "chksum_sha256": "49e81a5b55673e01c8ac2b895f6821187c3f611dda66b7c83f854a7c8bb976ce",
"format": 1
},
{
@@ -16454,7 +18575,7 @@
"name": "tests/integration/targets/setup_etcd3/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2f5e876474ebb8b6ed9a88e27e86a57b42ccd56a21b956645bebd469cd784cb0",
+ "chksum_sha256": "d0e8fecc8b50b008b75a6ff884dcc94fbffb40b0ce4fe40ea3acbfd9bf7348c5",
"format": 1
},
{
@@ -16671,7 +18792,7 @@
"name": "tests/integration/targets/setup_java_keytool/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3367bea7a11f5f0255b026f1af941bd9f119b280b2307f200e357970af972635",
+ "chksum_sha256": "dcfb9d983d25b47fe88e62325ce03423f78134ec0f9063e23ac29ac090a36148",
"format": 1
},
{
@@ -16685,35 +18806,42 @@
"name": "tests/integration/targets/setup_java_keytool/vars/Alpine.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0d6ca1d7f8ecbe06e87ed2dad9fe015fed10aa906b70ace7969d5ce2138c5055",
+ "chksum_sha256": "62674e136825f326112f65084215b81e13409da0cf29552e807db6b136f1b2d0",
"format": 1
},
{
"name": "tests/integration/targets/setup_java_keytool/vars/Archlinux.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ed6856cf47b91a6b4eb9d12d66bbed74c753b64d8d9d17d4b08898b66b98077b",
+ "chksum_sha256": "2ce093ee7bfdd768b5c42318a46b628a7c07f709b81d76ba2ea91ac55d18c645",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_java_keytool/vars/Debian-12.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fc5d4dc24b1a03c833d63c025bdabf69240e5321e9bb2ad4f27e46c1e22dd805",
"format": 1
},
{
"name": "tests/integration/targets/setup_java_keytool/vars/Debian.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8345b870e0d770f7befef71644bfe288c2476f5be1fb8af1e72ad1d5fead25f2",
+ "chksum_sha256": "e1e2288cab1185ac64fd612243eae63436e24ba1b6b8c788a8e1f7f4e90890ce",
"format": 1
},
{
"name": "tests/integration/targets/setup_java_keytool/vars/RedHat.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8835b1f83d2b73f10c9bd61a6397629e1e5e85baed5330e57508ff39dcce7f35",
+ "chksum_sha256": "df5881e22cc65c8e4951575d2da6cd0b672dfe377ebc229044340240031b1a8c",
"format": 1
},
{
"name": "tests/integration/targets/setup_java_keytool/vars/Suse.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8835b1f83d2b73f10c9bd61a6397629e1e5e85baed5330e57508ff39dcce7f35",
+ "chksum_sha256": "df5881e22cc65c8e4951575d2da6cd0b672dfe377ebc229044340240031b1a8c",
"format": 1
},
{
@@ -16787,10 +18915,24 @@
"format": 1
},
{
+ "name": "tests/integration/targets/setup_openldap/files/cert_cnconfig.ldif",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ae3c192e6ca4a6ac70106b812af6fd2f709039f54a1a4ea6ac7df79475aee309",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_openldap/files/cert_cnconfig.ldif.license",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6eb915239f9f35407fa68fdc41ed6522f1fdcce11badbdcd6057548023179ac1",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/setup_openldap/files/initial_config.ldif",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "052e5c4ae036b07264d62bc8323599d8e6cee06bd193e926cb56f26d772bbd2b",
+ "chksum_sha256": "5cbd38bcc3b8f6e77524ed82dc299236ced561b517280e652ab4cc0bfc072781",
"format": 1
},
{
@@ -16839,7 +18981,7 @@
"name": "tests/integration/targets/setup_openldap/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9e448d91ca0403de001122c60d5fc4eb5976c77278cecd19b7e6fe1ad5c65451",
+ "chksum_sha256": "0af97b261ed37eba0685a735c70fdc48ce8bbf5d62f392be161efcd7ec5ae5a7",
"format": 1
},
{
@@ -17035,7 +19177,7 @@
"name": "tests/integration/targets/setup_pkg_mgr/tasks/archlinux.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ef4b0b90491f629bfd6a84cec74208ed90604faad98794d6f811adebcfeed991",
+ "chksum_sha256": "cd071a182e3762f530cddc36a67e55e9c1ea8c404bbc18316d8d12347f4fbe01",
"format": 1
},
{
@@ -17140,7 +19282,7 @@
"name": "tests/integration/targets/setup_postgresql_db/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "60882f6a10be5873cf18ee0e68aedb3bf29a4402308c4a7a22662631446793fb",
+ "chksum_sha256": "43349d9b57fa2fe1bc2b8dd05c0b1304c899df9fbfcd8056125f69156a5ac358",
"format": 1
},
{
@@ -17172,6 +19314,13 @@
"format": 1
},
{
+ "name": "tests/integration/targets/setup_postgresql_db/vars/Debian-12-py3.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f3d599547074ae33969f69fb30e328f5edce4522e7395a6380bbd9a0ef79260f",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/setup_postgresql_db/vars/Debian-8.yml",
"ftype": "file",
"chksum_type": "sha256",
@@ -17676,6 +19825,20 @@
"format": 1
},
{
+ "name": "tests/integration/targets/setup_snap/tasks/D-RedHat-9.1.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "cbcd1ecc87781db24708d223b8d65728cb711a00df02364526758c306650abc4",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_snap/tasks/D-RedHat-9.2.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "cbcd1ecc87781db24708d223b8d65728cb711a00df02364526758c306650abc4",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/setup_snap/tasks/Debian.yml",
"ftype": "file",
"chksum_type": "sha256",
@@ -17690,7 +19853,7 @@
"format": 1
},
{
- "name": "tests/integration/targets/setup_snap/tasks/D-RedHat-9.1.yml",
+ "name": "tests/integration/targets/setup_snap/tasks/D-RedHat-9.3.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "cbcd1ecc87781db24708d223b8d65728cb711a00df02364526758c306650abc4",
@@ -17749,42 +19912,84 @@
"name": "tests/integration/targets/setup_tls/files/ca_certificate.pem",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "968655920cc97bf5de84a0c52046b430110fe977b2cce46b1eff492dcf3f3f1d",
+ "chksum_sha256": "47ddc514d030d2dd28b98eb257b690b8aa94abc7b657b43caf6e32e2e5a6bf9d",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_tls/files/ca_certificate.pem.license",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c111f1eddc1753ec6db64f82f4167c31ccb175960662c30ffbea6ee2f0ed47d0",
"format": 1
},
{
"name": "tests/integration/targets/setup_tls/files/ca_key.pem",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fd5306c600316fd344a4027361e5a533cfb97461ff928b3550cd0d45b994b4d2",
+ "chksum_sha256": "0157029faae2207eaec99b67360db8ca46fe6964eb98165a0ca4ac56cbed7ebb",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_tls/files/ca_key.pem.license",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c111f1eddc1753ec6db64f82f4167c31ccb175960662c30ffbea6ee2f0ed47d0",
"format": 1
},
{
"name": "tests/integration/targets/setup_tls/files/client_certificate.pem",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e78c5033fa3e6e26e0bac11e1c66295edb40d761ea0d8c71af75cfa20dc54f53",
+ "chksum_sha256": "1c88ee01e59fe19f497b74f0fb15a6d705bbac6df554d16f2f80fc25d2723bad",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_tls/files/client_certificate.pem.license",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c111f1eddc1753ec6db64f82f4167c31ccb175960662c30ffbea6ee2f0ed47d0",
"format": 1
},
{
"name": "tests/integration/targets/setup_tls/files/client_key.pem",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fae1b92fb7fbd097804d7b4839024814632f2485b86263bb902da10fe49bc7ae",
+ "chksum_sha256": "1ffc8420355a69fecd60242feb89bfef5517292aa9129ea79e99bb36ffd80dc6",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_tls/files/client_key.pem.license",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c111f1eddc1753ec6db64f82f4167c31ccb175960662c30ffbea6ee2f0ed47d0",
"format": 1
},
{
"name": "tests/integration/targets/setup_tls/files/server_certificate.pem",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ec5e95d973d4a14e251248670f3d9a85a6caa257324e0645316eb6877f22304d",
+ "chksum_sha256": "a93a860161059bf8b6d065d2b01a5218a7beefdb075fa704e0139d4f96bdb61c",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_tls/files/server_certificate.pem.license",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c111f1eddc1753ec6db64f82f4167c31ccb175960662c30ffbea6ee2f0ed47d0",
"format": 1
},
{
"name": "tests/integration/targets/setup_tls/files/server_key.pem",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2e128fb808d4d6ac61949ca188d70ce0be9edf5775c185e4b8802b98bbb16375",
+ "chksum_sha256": "0bb0b33983d37d5b6404c0feb969e80d0787331f774d2b8024570133d65851f6",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_tls/files/server_key.pem.license",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c111f1eddc1753ec6db64f82f4167c31ccb175960662c30ffbea6ee2f0ed47d0",
"format": 1
},
{
@@ -17917,14 +20122,14 @@
"name": "tests/integration/targets/shutdown/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c481592019395e3fabb39d0b367d382a19d4dd4bf2073e8800dcfe5a907b2556",
+ "chksum_sha256": "99492266044d066c99bd8cc70861dd9b5c33844b64b2d71d9aaa87cb04d89829",
"format": 1
},
{
"name": "tests/integration/targets/shutdown/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4762e4d5adeeb09c1dbca4b156fc16c19f786f55765669aad0bc9f3b41edac9b",
+ "chksum_sha256": "32cec593e0676935e5e4a2ddd4ed59aaea210cff8ca9dc31dbf2a254fb87af48",
"format": 1
},
{
@@ -17945,7 +20150,7 @@
"name": "tests/integration/targets/snap/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "98df429f4ebdd37e193ab4ca32ccc35daaeca869c236e6f3cddefd3a83588a2c",
+ "chksum_sha256": "ad23e8f8043fbff11291e0055fe8694dafe5f3bf122a1a327f21bacd23c1230f",
"format": 1
},
{
@@ -17959,7 +20164,42 @@
"name": "tests/integration/targets/snap/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f701425c47a1521abf353d91f5ed172d40d46c8876ea00e44965e6d1d30cab4c",
+ "chksum_sha256": "f8e05e7aa1de2b74a9aab47cbdac6f6053fd59d6113d1e968521544a5b9b8285",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/snap/tasks/test.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c3d5437c52b3f54a57f138612652a01362cca5fe84e5e5d9ccfaa264d7047590",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/snap/tasks/test_3dash.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "2ad5b0155b7fc37f31ce82ac86b3f90af7012de111ae47137fea09b8dd51b3f2",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/snap/tasks/test_channel.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "06b6a509058dca27433debe5f007f8ea36f69a53ba25ca0f1d5d0bf71ab751ab",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/snap/tasks/test_dangerous.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "a52342f69c8177266519aeb8123230a4ae08c66e72e17bd0918c69fbef48d994",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/snap/tasks/test_empty_list.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "882ac3b4fedd4ff1cd2369d9c71596ea2fa938fc4cf4fbe796285877d41d35d0",
"format": 1
},
{
@@ -18106,14 +20346,14 @@
"name": "tests/integration/targets/ssh_config/tasks/options.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6663549e6526c05e0359d1c65d2b336e6f748e208e11a6a89c5948277de413c3",
+ "chksum_sha256": "fe030ad3d66f5ec5094aca445f802a814d58b312e791bb5de0ff30080dc3662b",
"format": 1
},
{
"name": "tests/integration/targets/ssh_config/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8053b06325a9c58c6856e1b6f938a87a865ede0f309053a1f7d5fcf4537492ee",
+ "chksum_sha256": "a8275df9ba04abbd2b325b9edf922741c6e83946547d1de995abcaa3e2580bc5",
"format": 1
},
{
@@ -18134,7 +20374,7 @@
"name": "tests/integration/targets/sudoers/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "48117b88b9e738d7fb5847da7e5fab3899feb74aa53f3867d5ca7553cf7ba484",
+ "chksum_sha256": "23d9327598221725d2fdc2bae766fd8084b85fdd56aa05b82587b577f9e9d2ee",
"format": 1
},
{
@@ -18372,7 +20612,7 @@
"name": "tests/integration/targets/sysrc/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7c0245eb91b4a52830cffc76315ce1152667b0b1e9ab8afbf2ae7ab306d250b1",
+ "chksum_sha256": "aedade3123f937a9c0e9eea4100151fec37836cf81c43f0227f1e912168108d4",
"format": 1
},
{
@@ -18456,7 +20696,7 @@
"name": "tests/integration/targets/terraform/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "432b4599aa787306d4da0bb4d1ad0ddb587fa68f5ab403db3de01689d69c3ba7",
+ "chksum_sha256": "8c9e5093ce69bff03dc6f392aad74ad1e45fa06a0ff66f3b86c583c0132b4e3f",
"format": 1
},
{
@@ -18614,6 +20854,69 @@
"format": 1
},
{
+ "name": "tests/integration/targets/test_fqdn_valid",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/test_fqdn_valid/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/test_fqdn_valid/tasks/fqdn_valid_1.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ac973af91c5ce272433055dc64e0d693a748d68ae111cd0202e121e529ad14cd",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/test_fqdn_valid/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "658bd791a876cc11a619d5cda60672a517d857864e6c0dd483e82eadd5c144fe",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/test_fqdn_valid/vars",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/test_fqdn_valid/vars/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "747b89bfb82461b7e4560294f3032885e19d5e18089aa790b56584cd342d9490",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/test_fqdn_valid/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "96646c5ab7118c53b8b722f6abe91a7ed4d3eed9be401faefb399d6a8f427c2e",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/test_fqdn_valid/runme.sh",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0f2a6741449c02e5197e4dd251eafa3068d504e5c73530529d026d0ca8dfef84",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/test_fqdn_valid/runme.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "5d3982f854f11115a0dadca44104f4878f0b165c3acacd152b8e604b572fa7c1",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/timezone",
"ftype": "dir",
"chksum_type": null,
@@ -18645,7 +20948,7 @@
"name": "tests/integration/targets/timezone/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f54963c431f59227cb4725d1a77f2315139be83cd8937b88c103b228248d5736",
+ "chksum_sha256": "f4c966d0ce85495702b3f86240e8eece21844116de5bb1e0ac23187ddf5f54b6",
"format": 1
},
{
@@ -18743,7 +21046,7 @@
"name": "tests/integration/targets/ufw/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "084563fba485ef388e28a3fe0f6b4dd1e16d72f44716e33549508f94ead343c7",
+ "chksum_sha256": "fb12d401d016f2581cbe66a32288fa25f5f3f48a359ff03f96f864bd0337b824",
"format": 1
},
{
@@ -19373,7 +21676,7 @@
"name": "tests/integration/targets/xml/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e777b6eff1946f9218fdbbed7a94e0572ab20c5824a20a1b2d2f0c829e54e0f9",
+ "chksum_sha256": "858eea95e060612db872246d929a8c2399df80fb46cc7c1f376efdd1eaebfdce",
"format": 1
},
{
@@ -19961,7 +22264,7 @@
"name": "tests/sanity/extra/botmeta.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f207a3b57027803486aa9e05811fa2efe76ba1d234de9face827b86bc8f48397",
+ "chksum_sha256": "a9d1b14c39802c48d498dd89d82d7f89adc4e3873e161e023b903e824c2f6033",
"format": 1
},
{
@@ -19982,7 +22285,7 @@
"name": "tests/sanity/extra/extra-docs.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0fbd87476e9c35e4c5feb31be4aa1e8fc6aebf0de13058e5a267879f741ec0bf",
+ "chksum_sha256": "c52e316daf1292bbb063be19429fd1f06e02bce3c9d4622a8dfc61fa3af06688",
"format": 1
},
{
@@ -20035,84 +22338,70 @@
"format": 1
},
{
- "name": "tests/sanity/ignore-2.11.txt",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "c7c385de70e0910e039428db73963993f69f78b50356722dbd34d1b953bfbdeb",
- "format": 1
- },
- {
- "name": "tests/sanity/ignore-2.11.txt.license",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "6eb915239f9f35407fa68fdc41ed6522f1fdcce11badbdcd6057548023179ac1",
- "format": 1
- },
- {
- "name": "tests/sanity/ignore-2.12.txt",
+ "name": "tests/sanity/ignore-2.13.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2348ca7c764b67e002e65d01e00c06a20eac1c2a8f9bf7c6bcb17dd6c35d07f9",
+ "chksum_sha256": "96fb0c5067f95b7ce1398bd26cc039eedf03fd8309844d7e59dec097ec594a2c",
"format": 1
},
{
- "name": "tests/sanity/ignore-2.12.txt.license",
+ "name": "tests/sanity/ignore-2.13.txt.license",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "6eb915239f9f35407fa68fdc41ed6522f1fdcce11badbdcd6057548023179ac1",
"format": 1
},
{
- "name": "tests/sanity/ignore-2.13.txt",
+ "name": "tests/sanity/ignore-2.14.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2348ca7c764b67e002e65d01e00c06a20eac1c2a8f9bf7c6bcb17dd6c35d07f9",
+ "chksum_sha256": "f1746096cd6755590272792fff8aa9884bde3a011fc8c71e24d9d43e6e847e4b",
"format": 1
},
{
- "name": "tests/sanity/ignore-2.13.txt.license",
+ "name": "tests/sanity/ignore-2.14.txt.license",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "6eb915239f9f35407fa68fdc41ed6522f1fdcce11badbdcd6057548023179ac1",
"format": 1
},
{
- "name": "tests/sanity/ignore-2.14.txt",
+ "name": "tests/sanity/ignore-2.15.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a459a712e8f6b2a8aed41fc1db2f16b6c6eea47a7d108deab3d98e3a6a7e54c6",
+ "chksum_sha256": "1960b0bd13753051ea1250ed6b1de8eb19b8f9e57901350c044d9cd884dc66a6",
"format": 1
},
{
- "name": "tests/sanity/ignore-2.14.txt.license",
+ "name": "tests/sanity/ignore-2.15.txt.license",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "6eb915239f9f35407fa68fdc41ed6522f1fdcce11badbdcd6057548023179ac1",
"format": 1
},
{
- "name": "tests/sanity/ignore-2.15.txt",
+ "name": "tests/sanity/ignore-2.16.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a459a712e8f6b2a8aed41fc1db2f16b6c6eea47a7d108deab3d98e3a6a7e54c6",
+ "chksum_sha256": "b49ac32679f36df6f32acffd654013de426897c51bb40e2024c1baa9b6044ae1",
"format": 1
},
{
- "name": "tests/sanity/ignore-2.15.txt.license",
+ "name": "tests/sanity/ignore-2.16.txt.license",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "6eb915239f9f35407fa68fdc41ed6522f1fdcce11badbdcd6057548023179ac1",
"format": 1
},
{
- "name": "tests/sanity/ignore-2.16.txt",
+ "name": "tests/sanity/ignore-2.17.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f0637ae63c9c7aba292802a108d1f3284def1f6a94171a7d0467c3bacc4725d1",
+ "chksum_sha256": "4aa6d180dd919a19b80a38b282923231f636556e4bf343b2cf36527d999b2124",
"format": 1
},
{
- "name": "tests/sanity/ignore-2.16.txt.license",
+ "name": "tests/sanity/ignore-2.17.txt.license",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "6eb915239f9f35407fa68fdc41ed6522f1fdcce11badbdcd6057548023179ac1",
@@ -20171,7 +22460,7 @@
"name": "tests/unit/mock/loader.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7504fd9d17a53a787f6f7b286765a66052bf6b1d980f7e2800cef8fcee83e627",
+ "chksum_sha256": "a9fc29c6e613dd574f5aa6c96585ddd74c31f0bdd1056206521b4e94c743f625",
"format": 1
},
{
@@ -20227,7 +22516,7 @@
"name": "tests/unit/plugins/become/helper.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "000efeb2d52da72504992e8156ef51f4e39dc4b842a19da167b4e3b23d215a38",
+ "chksum_sha256": "cafb18e458cd33e7f7ddacb17e6a9490e281ad277773dd0660a955bb52589a58",
"format": 1
},
{
@@ -20311,7 +22600,7 @@
"name": "tests/unit/plugins/callback/test_loganalytics.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0edd676b99891b7c36b8afba59662a266df303848a66f67cc3c9d73c8db19fbe",
+ "chksum_sha256": "45af49a11f9253655c2ae1b0ddde646ec20f4fbce8a5e8bddf468c4bb438a70c",
"format": 1
},
{
@@ -20339,7 +22628,7 @@
"name": "tests/unit/plugins/connection/test_lxc.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c8ec27b94b0e0ee8e12ead44e211c3fe591381245349647674afdcc8ab21e19c",
+ "chksum_sha256": "6193f2a1baf800982851b46f33bcc35cf0aab1afbe0084199a5a5f644d6d411b",
"format": 1
},
{
@@ -20409,14 +22698,14 @@
"name": "tests/unit/plugins/inventory/test_icinga2.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7923583ee86d43e8484a9ea1af5c10b05545d9f6099ae70ef0dabee858897d9c",
+ "chksum_sha256": "7f4a65be0a5e17093742df1362ba882e25a13c2c60c39e42b909ab990065f705",
"format": 1
},
{
"name": "tests/unit/plugins/inventory/test_linode.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d6d49875a49222175deba629f096b14dd83591f2a9b7b19762382f6d1f4fc101",
+ "chksum_sha256": "60dd8d2eb47e114340c825612fab776385224011b86e24d109931278250db509",
"format": 1
},
{
@@ -20437,7 +22726,7 @@
"name": "tests/unit/plugins/inventory/test_proxmox.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ec839664b7603f838f6e53564b22316c699e58804612a16760df67e474213bb0",
+ "chksum_sha256": "142e3d1b74021362e1fd06703c272fcd86c59f116b372c1866abaccc28514d5d",
"format": 1
},
{
@@ -20514,7 +22803,7 @@
"name": "tests/unit/plugins/lookup/onepassword_fixtures/v2_out_01.json",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a2816c9277e392cf97b5ac8c00016439497ea88f5cef37cfa9eb46c677ea580c",
+ "chksum_sha256": "ec5406c038535d71f89cd580d92ad914ed25d1e2b7d0b563c44919afe3e9043f",
"format": 1
},
{
@@ -20553,24 +22842,59 @@
"format": 1
},
{
- "name": "tests/unit/plugins/lookup/onepassword_common.py",
+ "name": "tests/unit/plugins/lookup/onepassword_fixtures/v2_out_04.json",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "1a9d4ba92b37f20ea5bb713d1dc69a65ee3bdc3e283be6fcbf58696d3a503b73",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/lookup/onepassword_fixtures/v2_out_04.json.license",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "04839c2a04633cfff4e774ca25a799a2ee02d73770398c7b3ac375d95d784f4b",
+ "chksum_sha256": "8e5224dc439dee9ae03a8c024f2e0434464c463dad0caf2d2bace082be69cb54",
"format": 1
},
{
- "name": "tests/unit/plugins/lookup/onepassword_conftest.py",
+ "name": "tests/unit/plugins/lookup/onepassword_fixtures/v2_out_05.json",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1264ad544cc4af2407e82659bf4e3f74de25083af53189680f9adff6c392bf7d",
+ "chksum_sha256": "19aacca4f6b3586b37424ab85f1b4bd541e47119d3ef2acc62829e10ade557bc",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/lookup/onepassword_fixtures/v2_out_05.json.license",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "8e5224dc439dee9ae03a8c024f2e0434464c463dad0caf2d2bace082be69cb54",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/lookup/conftest.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "caae05d2474f4c27a38ab52d83282dcd5175ada83bac13b3e03710ce4b322096",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/lookup/onepassword_common.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "8dc91ee8a788517f9528b28fa29f7028d5f85db1f937cfa6871b86a9ea52403e",
"format": 1
},
{
"name": "tests/unit/plugins/lookup/test_bitwarden.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f498f1ca02e67a8079777760280ba0215767362448e41cf9c4c320eccee0329f",
+ "chksum_sha256": "bc4558d979772df76cea11362731e59a669327b817f91be20e43f5619d1a1a22",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/lookup/test_bitwarden_secrets_manager.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0e2c9748d4f5bc2f4255a624777850c8922d2511830fcd243748dd3925ef626c",
"format": 1
},
{
@@ -20595,6 +22919,13 @@
"format": 1
},
{
+ "name": "tests/unit/plugins/lookup/test_github_app_access_token.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9ed2b96f40989d457add8fc7224112a521f77e9b818701372536b416945aa7de",
+ "format": 1
+ },
+ {
"name": "tests/unit/plugins/lookup/test_lastpass.py",
"ftype": "file",
"chksum_type": "sha256",
@@ -20612,14 +22943,14 @@
"name": "tests/unit/plugins/lookup/test_merge_variables.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a7d90bc6b420772235e64e370cdb68787476f016c97f1a331a154cc7edf16664",
+ "chksum_sha256": "96beb7ae4b4dc2eed0102f7f08d298ba619d167356771e4d4f2aa00b9507b18c",
"format": 1
},
{
"name": "tests/unit/plugins/lookup/test_onepassword.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "383ab17c21d213629460fa34515aed38aa618e7982671e49282a3657aaba5410",
+ "chksum_sha256": "5a0bf3a78f5472bed2a1a20595e6ad749d9f224a2afab271ef43e7294116f91b",
"format": 1
},
{
@@ -20682,7 +23013,7 @@
"name": "tests/unit/plugins/module_utils/hwc/test_hwc_utils.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c939a7d89cc202fc12e368fa4e82c4202c7671466bad41a6733f42c3b59fd6a6",
+ "chksum_sha256": "1c3125db25e8d830f3b026ccce0b4a3402abaae41d730255e4297a8ef23cb74c",
"format": 1
},
{
@@ -20927,7 +23258,7 @@
"name": "tests/unit/plugins/module_utils/test_cmd_runner.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "59e3f0ebd7da5145a43fdad5ad47607b980db8c6875091956888e588664d15b3",
+ "chksum_sha256": "fc1a28545ad32bc5c937219a3188ea421f7b177bf7c412b64c2081f3dffaaf58",
"format": 1
},
{
@@ -20955,7 +23286,7 @@
"name": "tests/unit/plugins/module_utils/test_module_helper.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d078f60eecd45ad986d514417ea96ea3dbfe4560bf8be72046b3ad80b9458f7d",
+ "chksum_sha256": "e2ceb70d568bf9cc76882753ede33b66b961a0252ac50c2167639c6b0144c84c",
"format": 1
},
{
@@ -20994,6 +23325,13 @@
"format": 1
},
{
+ "name": "tests/unit/plugins/module_utils/test_vardict.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "37b57239530d8178a24e02e607c3304fffd6a2c075498359e249201327becadb",
+ "format": 1
+ },
+ {
"name": "tests/unit/plugins/modules",
"ftype": "dir",
"chksum_type": null,
@@ -24063,7 +26401,14 @@
"name": "tests/unit/plugins/modules/gitlab.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e03e56f1492f532260e19fba71fba8a6fb459fad1d7ab255ec7bdf64a7fe5fb3",
+ "chksum_sha256": "59aa78e7134a497a944c08963e8d0786e66b0307ba3e96c15dfa36b48abbacaa",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/modules/helper.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "d92529c5e737c7a3b5aa3d9100502ea7b875f233d86f435c2453f9c77ae012f7",
"format": 1
},
{
@@ -24175,7 +26520,14 @@
"name": "tests/unit/plugins/modules/test_cpanm.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5eca61cd3da9592d95ddf8330313b450e3cd0cb1d599170a8c5efe7b2f5b470a",
+ "chksum_sha256": "ad70892f9beaaaa83b8f11f4201390877f183a5c4313e6a0c75145ad586d9a41",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/modules/test_cpanm.yaml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9f34f3edb8ae8ba4e017eab4740265089a1986d55066b8e6c70759604cc018b0",
"format": 1
},
{
@@ -24200,38 +26552,87 @@
"format": 1
},
{
+ "name": "tests/unit/plugins/modules/test_dnf_config_manager.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9e0e1fcab3d594d6bd0965282f7808f1f0683919d046f61828a39a59b52adda7",
+ "format": 1
+ },
+ {
"name": "tests/unit/plugins/modules/test_dnsimple.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1199b611a25718a42cb1587f29309a30c1c0b38b34234def4103faacbd67d23a",
+ "chksum_sha256": "d164a7c2a24e8f6c12bfdeca49622423b9e548aff516292be7acd108e9d42e7a",
"format": 1
},
{
"name": "tests/unit/plugins/modules/test_dnsimple_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d6920c0b0abe6edf0ecdafa076684903fbaae14bd76c562dffc4a530fcbfac23",
+ "chksum_sha256": "5863f626f99a6dbfe5bceb1ac851ef028a25dbf9b228ffb1d0d93b3d6fabbfeb",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/modules/test_facter_facts.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "d4eb761d0c5d0d70e36b1a553ffce888f9cb492233d1abd5303e20a81b80950a",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/modules/test_facter_facts.yaml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "51183ca92781ed952a2d856c45cc3afef8a4d73a3a564f439050e77ede2b614b",
"format": 1
},
{
"name": "tests/unit/plugins/modules/test_gconftool2.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f1d6b256e644b88ca86b4064b809e15af3ced724134f6eab575d95624684f0b0",
+ "chksum_sha256": "db86d27bf52e082b965fa368dda3effd00390f198039aa779d37bd013430d048",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/modules/test_gconftool2.yaml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "4509e503ad6727158aebcc5186780a7709990df9c574464edf502b1393b56803",
"format": 1
},
{
"name": "tests/unit/plugins/modules/test_gconftool2_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f4c348e06dda55c92674106ddb34f0e1c99d3c2c5699a49cd3b3af00999a17d2",
+ "chksum_sha256": "d47122bca7c06bd1bd779f65492ac5997e29289374c8625a2c9bf518bfcbf0c2",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/modules/test_gconftool2_info.yaml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9fc28b67a33580cdc3771884d278c74ab388466039c670ebb09dd7eae632761a",
"format": 1
},
{
"name": "tests/unit/plugins/modules/test_gem.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "acf58572377785d32f4c0a155410b32188f64296a388d7e055368d8551a2be30",
+ "chksum_sha256": "513696d9467350ba84f86988fd223c4767eb7e2bfacbccf96e541917c941ebc5",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/modules/test_gio_mime.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "a1d1f5587388c8624f0b328f81d38e63960e090f7194cd8063bf562e7257de0e",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/modules/test_gio_mime.yaml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c5b57782c84be5f20b6b479b41e4aa4c26f2dd9d804fb4f660d9a14af4dc56ee",
"format": 1
},
{
@@ -24256,6 +26657,13 @@
"format": 1
},
{
+ "name": "tests/unit/plugins/modules/test_gitlab_group_access_token.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "bd0e08b513f1e956652311dfc251f52332525810b32871fa7208f48aafef1467",
+ "format": 1
+ },
+ {
"name": "tests/unit/plugins/modules/test_gitlab_hook.py",
"ftype": "file",
"chksum_type": "sha256",
@@ -24270,6 +26678,13 @@
"format": 1
},
{
+ "name": "tests/unit/plugins/modules/test_gitlab_project_access_token.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "37257b5f7cc92f959ce4cd24fa9be3d2f18f6faccf07b691a9f9414264199533",
+ "format": 1
+ },
+ {
"name": "tests/unit/plugins/modules/test_gitlab_protected_branch.py",
"ftype": "file",
"chksum_type": "sha256",
@@ -24291,13 +26706,6 @@
"format": 1
},
{
- "name": "tests/unit/plugins/modules/test_hana_query.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "5c51841c4450843ab7f3b2445a0ce42b8fb64fdbbe26657dca5aba166a6b60b9",
- "format": 1
- },
- {
"name": "tests/unit/plugins/modules/test_homebrew.py",
"ftype": "file",
"chksum_type": "sha256",
@@ -24319,6 +26727,13 @@
"format": 1
},
{
+ "name": "tests/unit/plugins/modules/test_ini_file.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "677b4f61b8b76e4125c346d18559a25c12003859a557ef725de8906d422057e9",
+ "format": 1
+ },
+ {
"name": "tests/unit/plugins/modules/test_ipa_otpconfig.py",
"ftype": "file",
"chksum_type": "sha256",
@@ -24329,14 +26744,21 @@
"name": "tests/unit/plugins/modules/test_ipa_otptoken.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2938ebfd66222b52d1ae68081273901992d634e88039e2853309bf540b0bfc11",
+ "chksum_sha256": "89b3dbc597fc2b1a8df5fc7b8761defdf2d8b54646fd320f30b9aa261d5684ac",
"format": 1
},
{
"name": "tests/unit/plugins/modules/test_ipa_pwpolicy.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "df5849a5efdf159aa698b817615cec46fef0dee8085405c100027f15038c501b",
+ "chksum_sha256": "021a8caaea83da61a661486b401646d3b36f7422e892b2cb815ac6a3de999f5d",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/modules/test_ipbase.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "06a1a41140fca394449f964a0b36394188287b12a2c4c91dad2e72f894650227",
"format": 1
},
{
@@ -24350,7 +26772,14 @@
"name": "tests/unit/plugins/modules/test_jenkins_build.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a08bf75c34c58585fb721b8d4214b6e96f8bfd3fa1c391ab06af19c62ad7b6fa",
+ "chksum_sha256": "d5d27873fb38e6b8900a36101f3c8bf7027daa53d12c6124d2e5f6b1b707e7d7",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/modules/test_jenkins_build_info.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "4b090e3add89ab1b09a6b5be6a77e2dc612a4e3bde020103065fe731d799e813",
"format": 1
},
{
@@ -24368,6 +26797,13 @@
"format": 1
},
{
+ "name": "tests/unit/plugins/modules/test_keycloak_authentication_required_actions.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0d754f74526ba260573beb3d68c53ebc49a6dd2001c4b5d0a701f102457ba210",
+ "format": 1
+ },
+ {
"name": "tests/unit/plugins/modules/test_keycloak_client.py",
"ftype": "file",
"chksum_type": "sha256",
@@ -24378,7 +26814,7 @@
"name": "tests/unit/plugins/modules/test_keycloak_client_rolemapping.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ef725bd67a94176b71c2dd50c3a72e20cb30e87ed7cddd35b150f913125d2d9c",
+ "chksum_sha256": "96cb3e4f60ed6739371a6a6b043df3f571c8d1f77bd03b472e422e2163972630",
"format": 1
},
{
@@ -24413,14 +26849,21 @@
"name": "tests/unit/plugins/modules/test_keycloak_role.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7caddfcf79f22c4edd920a9309247a02d583cd3d5b92f97aae30a2ea852d262f",
+ "chksum_sha256": "d4741a45237de7f4fa48c56e63dbeaeedabc99f0a17e93fe565e4bbb83858556",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/modules/test_keycloak_user.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "2a1a4e7837a38e7ca3b396f50948a845368e21eeca99dbf7e7d3d8843b519b91",
"format": 1
},
{
"name": "tests/unit/plugins/modules/test_keycloak_user_federation.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b399e09b344c3de512a5daca087fc519c3af3a26bc039250ba619925e31e8f61",
+ "chksum_sha256": "c08ff5d8464bded16338c018194f6f92d7ad5e9635802bbb46dd1be129c96a8c",
"format": 1
},
{
@@ -24438,6 +26881,13 @@
"format": 1
},
{
+ "name": "tests/unit/plugins/modules/test_lvg_rename.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "7d5d38a33e298287f87129e3f24fa915855aecd3201bb4720aacfef9b42a38d5",
+ "format": 1
+ },
+ {
"name": "tests/unit/plugins/modules/test_lxca_cmms.py",
"ftype": "file",
"chksum_type": "sha256",
@@ -24469,7 +26919,7 @@
"name": "tests/unit/plugins/modules/test_modprobe.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "eb7183c6b205d2bcfc1b5ea9bc6b263bda61584ed09a112f386af9c47034a8e9",
+ "chksum_sha256": "3d1f85d48d05ce0f7e1e7364f716fec0d71c634d0d0e8f6a81cee233b8837bfb",
"format": 1
},
{
@@ -24483,14 +26933,21 @@
"name": "tests/unit/plugins/modules/test_nmcli.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "20c5fcfd0e0e12d1fd9ec9a72fb3731b637bb9a75531abb3788c7719c59790a8",
+ "chksum_sha256": "61b1d7d5afe5570b05212c00a2c4a0540e1b6dea081875a2da0602d3c65244d8",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/modules/test_nomad_token.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "da76aa21493063d15162d49050c91999aeaca6622909af69978dd9f0b058f80b",
"format": 1
},
{
"name": "tests/unit/plugins/modules/test_npm.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3f3cd31f4a5598afb5e772310574ac4ffa10e5d6806dfe531804cb2ac4d4c40a",
+ "chksum_sha256": "5ad058a6ac1a10e723f01da542ceff1478d507cc9198facf83bb1707bf1da90b",
"format": 1
},
{
@@ -24616,7 +27073,14 @@
"name": "tests/unit/plugins/modules/test_opkg.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "40515dbe28269da53c99ed6755eced47af692d04fd704813887cdec759a64e76",
+ "chksum_sha256": "a0702714025b03757e3363b5427069033df56c1fe41f272f47a7a6e8937e808c",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/modules/test_opkg.yaml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "58629623e64666ad05adf9cb5086399a3a00e1a5c4063fa0be46dc48cd7366f1",
"format": 1
},
{
@@ -24637,14 +27101,14 @@
"name": "tests/unit/plugins/modules/test_pagerduty.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c5b9304daa4b3b063e8d38ca0fb203a801b982c41ec9b092c7324230091f243b",
+ "chksum_sha256": "630b328e765b0c6f53073da70c9a804839c6265fcc65b0a637944135ee529fa3",
"format": 1
},
{
"name": "tests/unit/plugins/modules/test_pagerduty_alert.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9ecb84e28adb10476d71e031112ab241e5d65ba903e0236b01f670a42a2d7f9a",
+ "chksum_sha256": "b0514b3487f2fc57ebb91334f5c9bae669eb55d7d656ae3b15439e3b6886cf55",
"format": 1
},
{
@@ -24672,7 +27136,7 @@
"name": "tests/unit/plugins/modules/test_pkgin.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ec1ddfafcc64745b56a64322e1e738e1804ab2818a60f407afa36f4cde5c0cc2",
+ "chksum_sha256": "42314f5eea331f683936677b1a787a1a9941b9527bfc09e72f5a347ccb16c608",
"format": 1
},
{
@@ -24714,35 +27178,63 @@
"name": "tests/unit/plugins/modules/test_proxmox_kvm.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "04e48908fa164cdf8985990322c5de527240f7bff5585d34061e2a45d0796327",
+ "chksum_sha256": "be83ea11ceae50cad026021a1a24d8ac0dca9bfd1fcee2ec2ec04725d3cd2162",
"format": 1
},
{
"name": "tests/unit/plugins/modules/test_proxmox_snap.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c7ea09c7bf0c5c7e3bea29939ef1a62809f2f71a0cf6c8bd44c387534a8d279b",
+ "chksum_sha256": "d7075ea71f0323f06034b516d588ede805f73b5472165f3e0f5194862522e9db",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/modules/test_proxmox_storage_contents_info.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "281b5fe8711ccdaca37491b7b4787466eec96dc50fdda9ca3e4b344bcdbc03c0",
"format": 1
},
{
"name": "tests/unit/plugins/modules/test_proxmox_tasks_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "87e2f651fa4bb9a31aae30769b6f457c3239edf4bf0c45b5a42e1c75cf4c0c34",
+ "chksum_sha256": "b75c5dcf7412eb68b97204ea24bc15cc51f1b1d2a168c2fda20b440281faa6a9",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/modules/test_proxmox_template.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9ee6085c79b89674fbc15b2c42adf5ef9e8486cecb2c29179d2507741f26b787",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/modules/test_proxmox_vm_info.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "af927aa1f38dfd9743ed3fcefcbeecc35741e915599c7552a4d23e65a4dc6e8b",
"format": 1
},
{
"name": "tests/unit/plugins/modules/test_puppet.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cc1d25520eee8b3f7a076cd16658189dae51eaa84e0140308bf1744ec6d3e590",
+ "chksum_sha256": "d1118dcb89f558e941a543cec9eccea83884f8832d84fd28652a24ef09d4f069",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/modules/test_puppet.yaml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fd0aef324a3206562948e4dc8c7e756a2adaf9f43a7a0447c80f941c3d4ce153",
"format": 1
},
{
"name": "tests/unit/plugins/modules/test_redhat_subscription.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7b0cf4b34573499cae93cb33bae60249882486335e2ea255ad9f367929924cdd",
+ "chksum_sha256": "a9ae5c27711ac92652e2f05fa82933aa5be2cd26411d6735445517cd7cb6c4dc",
"format": 1
},
{
@@ -24770,7 +27262,7 @@
"name": "tests/unit/plugins/modules/test_redis_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a334e4a805528f22d9c788b25d16f18482bb6cbb11b448590be2981497514b76",
+ "chksum_sha256": "7f41b6e05569bb9d8b0cbcc94fb899d07c39f6ec190223fac17c2fea3a1bb9d9",
"format": 1
},
{
@@ -24791,7 +27283,14 @@
"name": "tests/unit/plugins/modules/test_rhsm_release.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "644c8f2b28c3b76e6278dcfba81a7ab528950d9621c76d59b09e0b0a459d9cf2",
+ "chksum_sha256": "4ebbed4dffa3aac3ef5d112cc5dbb165764fe2d78d53db4dd88a66ae9bcf226e",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/modules/test_rhsm_repository.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f7cc6518c57ee74c9785612a0af1bb96469490ba2fcd8b7bc2a08bd2f98144a0",
"format": 1
},
{
@@ -24802,38 +27301,38 @@
"format": 1
},
{
- "name": "tests/unit/plugins/modules/test_sap_task_list_execute.py",
+ "name": "tests/unit/plugins/modules/test_scaleway_compute_private_network.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bdc5b3e4764b387eca5d8e2f13a22df0dd5f0af65180c98b59e5d6b5233cd156",
+ "chksum_sha256": "c421141d861007f3a63f158c96bb162a0a0151e3f25168be32b35494a6d3fb4c",
"format": 1
},
{
- "name": "tests/unit/plugins/modules/test_sapcar_extract.py",
+ "name": "tests/unit/plugins/modules/test_scaleway_private_network.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c91b80fc5550b96998de44ba16994cebfd5f09340928eca3608dc4fd23ddfc3f",
+ "chksum_sha256": "fb660a5f32ef6d680c4f1677c22457f24cc938acbea9ac3e1e8828a0ba2402d4",
"format": 1
},
{
- "name": "tests/unit/plugins/modules/test_scaleway_compute_private_network.py",
+ "name": "tests/unit/plugins/modules/test_simpleinit_msb.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c421141d861007f3a63f158c96bb162a0a0151e3f25168be32b35494a6d3fb4c",
+ "chksum_sha256": "79e33136bdea669d13fadd0ffcdd689154ff5dd816617833eefb8e862cc928f9",
"format": 1
},
{
- "name": "tests/unit/plugins/modules/test_scaleway_private_network.py",
+ "name": "tests/unit/plugins/modules/test_slack.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fb660a5f32ef6d680c4f1677c22457f24cc938acbea9ac3e1e8828a0ba2402d4",
+ "chksum_sha256": "50b7e265c519fae30fc120ad86971c408efed696923b76d3a47f6f5f0ef186f5",
"format": 1
},
{
- "name": "tests/unit/plugins/modules/test_slack.py",
+ "name": "tests/unit/plugins/modules/test_snap.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ad7fbf9ae278156ff410db7361e0c5ded24ca1c4d5ddd149d885e07717b2f031",
+ "chksum_sha256": "072507bcc449590585124ecfd0af520ab745fc64721223ffbe1e7c4394b44002",
"format": 1
},
{
@@ -24879,6 +27378,13 @@
"format": 1
},
{
+ "name": "tests/unit/plugins/modules/test_usb_facts.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "21af3c137f93ce32de33c9163e42028e452493c818781c16206951936a18ab75",
+ "format": 1
+ },
+ {
"name": "tests/unit/plugins/modules/test_wdc_redfish_command.py",
"ftype": "file",
"chksum_type": "sha256",
@@ -24917,14 +27423,28 @@
"name": "tests/unit/plugins/modules/test_xfconf.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e50b18406f4bebb6640964a9a5413f69d4ff698efce29abeb3728d59c6acea89",
+ "chksum_sha256": "4100d54930fb5094b1be65f7887e7ac84dae0d1124ba048cdbfdc58120163809",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/modules/test_xfconf.yaml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "36fdb4adf4b6df2cbc8e1a7baf2f2da39b74a1ae66bb4ab0becaf9bafad24793",
"format": 1
},
{
"name": "tests/unit/plugins/modules/test_xfconf_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "adb44156b0f1f43c30b0620d97e77fe43dc9559b3bffadf2cea82ff995e9017d",
+ "chksum_sha256": "a32fd85cb2d4cf45b192418dcf250f1f43b084a4628fa7efeeef51022acd8e02",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/modules/test_xfconf_info.yaml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "2bc9eeacb830bdf886c1d00c012657f3bdf408922e8d1f5f49b283751aa1de4e",
"format": 1
},
{
@@ -24952,7 +27472,7 @@
"name": "tests/unit/requirements.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3b783ac041b809d1250b2b7c45d8c1979b78e043e2b1ea4df0522bbac747cb06",
+ "chksum_sha256": "5da134ecf80466a8cb9c020cee562b1e6cd8c2a2dd573fd776fb74a5c8306122",
"format": 1
},
{
@@ -25071,7 +27591,7 @@
"name": "tests/utils/shippable/shippable.sh",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "54ce4f452428c1c57cbc0e8bfdd03a958370f3c8df25f248cf5902cd1c5d0d34",
+ "chksum_sha256": "c15848885a4479e9a141e3ac52388984a5b64a01008a7317e619df6554990aee",
"format": 1
},
{
@@ -25085,14 +27605,14 @@
"name": "tests/utils/constraints.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0d07bc7e664261cae0a8ea453132fb629b5e491ad923e4f18a4adefbc63f49cd",
+ "chksum_sha256": "e04c1dc2b2763c9768a7eddf444d79b97a9b3aa4a67d0cd2491e310014e974b4",
"format": 1
},
{
"name": "tests/.gitignore",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "58cfc1cc2436abdda80f8c752f3157c649bd38c86379f93c653dc0f7f1deb766",
+ "chksum_sha256": "b1cbc85816eba36ff11d5ef7d7f91d05dd937954e696c6f2f8c14934d0ff7066",
"format": 1
},
{
@@ -25103,6 +27623,13 @@
"format": 1
},
{
+ "name": "tests/galaxy-importer.cfg",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "d4e70c7540d2f405f079373fea81ee9be93021d051333797b20e756212ce3f0f",
+ "format": 1
+ },
+ {
"name": ".gitignore",
"ftype": "file",
"chksum_type": "sha256",
@@ -25110,17 +27637,24 @@
"format": 1
},
{
- "name": ".pre-commit-config.yaml",
+ "name": "CHANGELOG.md",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "8ac8a8d20d770c47d3d6d743711f948dc353bab92ee076a1a915ea8fbb939110",
+ "format": 1
+ },
+ {
+ "name": "CHANGELOG.md.license",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0acbe42d25a24bf2ca023947755c7e4a9c695c2e12a6ae909698d86d6f7d2e35",
+ "chksum_sha256": "6eb915239f9f35407fa68fdc41ed6522f1fdcce11badbdcd6057548023179ac1",
"format": 1
},
{
"name": "CHANGELOG.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3e1236c2e69e23203c68ca9b688de63ac0079e88280d5c50e5647c2ce418ad83",
+ "chksum_sha256": "1754aca18ee20d425f062cab756afaf70000861eb78cd1c885e2387048c87d56",
"format": 1
},
{
@@ -25134,7 +27668,7 @@
"name": "CONTRIBUTING.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b00274eb3feefd31dfdefd9f17afe6e2d1e3627d3e2ff6614bc646189af7b40b",
+ "chksum_sha256": "2b729d659927dbf2ef866dc1160a32a704123c9e2be3fe1c1c8d2daa053a83ae",
"format": 1
},
{
@@ -25148,7 +27682,7 @@
"name": "README.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a5b28f24a1fee9d7f4028ad4c9bbcd239390e742fce58d7a72920ea2e706c13a",
+ "chksum_sha256": "af93da2f8ac939f7b71c6ed23caeb602a0601924282f8de07616270113c99e16",
"format": 1
},
{
diff --git a/ansible_collections/community/general/MANIFEST.json b/ansible_collections/community/general/MANIFEST.json
index fa90daa61..715cd85ea 100644
--- a/ansible_collections/community/general/MANIFEST.json
+++ b/ansible_collections/community/general/MANIFEST.json
@@ -2,7 +2,7 @@
"collection_info": {
"namespace": "community",
"name": "general",
- "version": "6.6.2",
+ "version": "8.5.0",
"authors": [
"Ansible (https://github.com/ansible)"
],
@@ -10,7 +10,7 @@
"tags": [
"community"
],
- "description": null,
+ "description": "The community.general collection is a part of the Ansible package and includes many modules and plugins supported by Ansible community which are not part of more specialized community collections.",
"license": [],
"license_file": "COPYING",
"dependencies": {},
@@ -23,7 +23,7 @@
"name": "FILES.json",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b4af3ab11a47cb58399cf5036c03082a247092a36ad50e2e415f17890dad1ae0",
+ "chksum_sha256": "a5ae0318b05662e01298f7e11a607b9d674196586dfa5665caccb08b58fc5f69",
"format": 1
},
"format": 1
diff --git a/ansible_collections/community/general/README.md b/ansible_collections/community/general/README.md
index dc5db2944..a63ae3201 100644
--- a/ansible_collections/community/general/README.md
+++ b/ansible_collections/community/general/README.md
@@ -6,7 +6,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
# Community General Collection
-[![Build Status](https://dev.azure.com/ansible/community.general/_apis/build/status/CI?branchName=stable-6)](https://dev.azure.com/ansible/community.general/_build?definitionId=31)
+[![Build Status](https://dev.azure.com/ansible/community.general/_apis/build/status/CI?branchName=stable-8)](https://dev.azure.com/ansible/community.general/_build?definitionId=31)
[![EOL CI](https://github.com/ansible-collections/community.general/workflows/EOL%20CI/badge.svg?event=push)](https://github.com/ansible-collections/community.general/actions)
[![Codecov](https://img.shields.io/codecov/c/github/ansible-collections/community.general)](https://codecov.io/gh/ansible-collections/community.general)
@@ -24,9 +24,7 @@ If you encounter abusive behavior violating the [Ansible Code of Conduct](https:
## Tested with Ansible
-Tested with the current ansible-core 2.11, ansible-core 2.12, ansible-core 2.13, ansible-core 2.14 releases and the current development version of ansible-core. Ansible-core versions before 2.11.0 are not supported. This includes all ansible-base 2.10 and Ansible 2.9 releases.
-
-Parts of this collection will not work with ansible-core 2.11 on Python 3.12+.
+Tested with the current ansible-core 2.13, ansible-core 2.14, ansible-core 2.15, ansible-core 2.16 releases and the current development version of ansible-core. Ansible-core versions before 2.13.0 are not supported. This includes all ansible-base 2.10 and Ansible 2.9 releases.
## External requirements
@@ -34,13 +32,13 @@ Some modules and plugins require external libraries. Please check the requiremen
## Included content
-Please check the included content on the [Ansible Galaxy page for this collection](https://galaxy.ansible.com/community/general) or the [documentation on the Ansible docs site](https://docs.ansible.com/ansible/latest/collections/community/general/).
+Please check the included content on the [Ansible Galaxy page for this collection](https://galaxy.ansible.com/ui/repo/published/community/general/) or the [documentation on the Ansible docs site](https://docs.ansible.com/ansible/latest/collections/community/general/).
## Using this collection
This collection is shipped with the Ansible package. So if you have it installed, no more action is required.
-If you have a minimal installation (only Ansible Core installed) or you want to use the latest version of the collection along with the whole Ansible package, you need to install the collection from [Ansible Galaxy](https://galaxy.ansible.com/community/general) manually with the `ansible-galaxy` command-line tool:
+If you have a minimal installation (only Ansible Core installed) or you want to use the latest version of the collection along with the whole Ansible package, you need to install the collection from [Ansible Galaxy](https://galaxy.ansible.com/ui/repo/published/community/general/) manually with the `ansible-galaxy` command-line tool:
ansible-galaxy collection install community.general
@@ -57,7 +55,7 @@ Note that if you install the collection manually, it will not be upgraded automa
ansible-galaxy collection install community.general --upgrade
```
-You can also install a specific version of the collection, for example, if you need to downgrade when something is broken in the latest version (please report an issue in this repository). Use the following syntax where `X.Y.Z` can be any [available version](https://galaxy.ansible.com/community/general):
+You can also install a specific version of the collection, for example, if you need to downgrade when something is broken in the latest version (please report an issue in this repository). Use the following syntax where `X.Y.Z` can be any [available version](https://galaxy.ansible.com/ui/repo/published/community/general/):
```bash
ansible-galaxy collection install community.general:==X.Y.Z
@@ -73,13 +71,13 @@ We are actively accepting new contributors.
All types of contributions are very welcome.
-You don't know how to start? Refer to our [contribution guide](https://github.com/ansible-collections/community.general/blob/stable-6/CONTRIBUTING.md)!
+You don't know how to start? Refer to our [contribution guide](https://github.com/ansible-collections/community.general/blob/main/CONTRIBUTING.md)!
-The current maintainers are listed in the [commit-rights.md](https://github.com/ansible-collections/community.general/blob/stable-6/commit-rights.md#people) file. If you have questions or need help, feel free to mention them in the proposals.
+The current maintainers are listed in the [commit-rights.md](https://github.com/ansible-collections/community.general/blob/main/commit-rights.md#people) file. If you have questions or need help, feel free to mention them in the proposals.
You can find more information in the [developer guide for collections](https://docs.ansible.com/ansible/devel/dev_guide/developing_collections.html#contributing-to-collections), and in the [Ansible Community Guide](https://docs.ansible.com/ansible/latest/community/index.html).
-Also for some notes specific to this collection see [our CONTRIBUTING documentation](https://github.com/ansible-collections/community.general/blob/stable-6/CONTRIBUTING.md).
+Also for some notes specific to this collection see [our CONTRIBUTING documentation](https://github.com/ansible-collections/community.general/blob/main/CONTRIBUTING.md).
### Running tests
@@ -89,7 +87,7 @@ See [here](https://docs.ansible.com/ansible/devel/dev_guide/developing_collectio
To learn how to maintain / become a maintainer of this collection, refer to:
-* [Committer guidelines](https://github.com/ansible-collections/community.general/blob/stable-6/commit-rights.md).
+* [Committer guidelines](https://github.com/ansible-collections/community.general/blob/main/commit-rights.md).
* [Maintainer guidelines](https://github.com/ansible/community-docs/blob/main/maintaining.rst).
It is necessary for maintainers of this collection to be subscribed to:
@@ -117,7 +115,7 @@ See the [Releasing guidelines](https://github.com/ansible/community-docs/blob/ma
## Release notes
-See the [changelog](https://github.com/ansible-collections/community.general/blob/stable-6/CHANGELOG.rst).
+See the [changelog](https://github.com/ansible-collections/community.general/blob/stable-8/CHANGELOG.md).
## Roadmap
@@ -136,8 +134,8 @@ See [this issue](https://github.com/ansible-collections/community.general/issues
This collection is primarily licensed and distributed as a whole under the GNU General Public License v3.0 or later.
-See [LICENSES/GPL-3.0-or-later.txt](https://github.com/ansible-collections/community.general/blob/stable-6/COPYING) for the full text.
+See [LICENSES/GPL-3.0-or-later.txt](https://github.com/ansible-collections/community.general/blob/main/COPYING) for the full text.
-Parts of the collection are licensed under the [BSD 2-Clause license](https://github.com/ansible-collections/community.general/blob/stable-6/LICENSES/BSD-2-Clause.txt), the [MIT license](https://github.com/ansible-collections/community.general/blob/stable-6/LICENSES/MIT.txt), and the [PSF 2.0 license](https://github.com/ansible-collections/community.general/blob/stable-6/LICENSES/PSF-2.0.txt).
+Parts of the collection are licensed under the [BSD 2-Clause license](https://github.com/ansible-collections/community.general/blob/main/LICENSES/BSD-2-Clause.txt), the [MIT license](https://github.com/ansible-collections/community.general/blob/main/LICENSES/MIT.txt), and the [PSF 2.0 license](https://github.com/ansible-collections/community.general/blob/main/LICENSES/PSF-2.0.txt).
All files have a machine readable `SDPX-License-Identifier:` comment denoting its respective license(s) or an equivalent entry in an accompanying `.license` file. Only changelog fragments (which will not be part of a release) are covered by a blanket statement in `.reuse/dep5`. This conforms to the [REUSE specification](https://reuse.software/spec/).
diff --git a/ansible_collections/community/general/changelogs/changelog.yaml b/ansible_collections/community/general/changelogs/changelog.yaml
index 3b6438f62..411df6ed2 100644
--- a/ansible_collections/community/general/changelogs/changelog.yaml
+++ b/ansible_collections/community/general/changelogs/changelog.yaml
@@ -1,1426 +1,1322 @@
-ancestor: 5.0.0
+ancestor: 7.0.0
releases:
- 6.0.0:
+ 8.0.0:
changes:
breaking_changes:
- - scaleway_container_registry_info - no longer replace ``secret_environment_variables``
- in the output by ``SENSITIVE_VALUE`` (https://github.com/ansible-collections/community.general/pull/5497).
+ - collection_version lookup plugin - remove compatibility code for ansible-base
+ 2.10 and ansible-core 2.11 (https://github.com/ansible-collections/community.general/pull/7269).
+ - gitlab_project - add ``default_branch`` support for project update. If you
+ used the module so far with ``default_branch`` to update a project, the value
+ of ``default_branch`` was ignored. Make sure that you either do not pass a
+ value if you are not sure whether it is the one you want to have to avoid
+ unexpected breaking changes (https://github.com/ansible-collections/community.general/pull/7158).
+ - selective callback plugin - remove compatibility code for Ansible 2.9 and
+ ansible-core 2.10 (https://github.com/ansible-collections/community.general/pull/7269).
+ - vardict module utils - ``VarDict`` will no longer accept variables named ``_var``,
+ ``get_meta``, and ``as_dict`` (https://github.com/ansible-collections/community.general/pull/6647).
+ - version module util - remove fallback for ansible-core 2.11. All modules and
+ plugins that do version collections no longer work with ansible-core 2.11
+ (https://github.com/ansible-collections/community.general/pull/7269).
bugfixes:
- - iso_create - the module somtimes failed to add folders for Joliet and UDF
- formats (https://github.com/ansible-collections/community.general/issues/5275).
- - ldap_attrs - fix bug which caused a ``Bad search filter`` error. The error
- was occuring when the ldap attribute value contained special characters such
- as ``(`` or ``*`` (https://github.com/ansible-collections/community.general/issues/5434,
- https://github.com/ansible-collections/community.general/pull/5435).
- - snap - allow values in the ``options`` parameter to contain whitespaces (https://github.com/ansible-collections/community.general/pull/5475).
+ - CmdRunner module utils - does not attempt to resolve path if executable is
+ a relative or absolute path (https://github.com/ansible-collections/community.general/pull/7200).
+ - MH DependencyMixin module utils - deprecation notice was popping up for modules
+ not using dependencies (https://github.com/ansible-collections/community.general/pull/6644,
+ https://github.com/ansible-collections/community.general/issues/6639).
+ - bitwarden lookup plugin - the plugin made assumptions about the structure
+ of a Bitwarden JSON object which may have been broken by an update in the
+ Bitwarden API. Remove assumptions, and allow queries for general fields such
+ as ``notes`` (https://github.com/ansible-collections/community.general/pull/7061).
+ - cmd_runner module utils - when a parameter in ``argument_spec`` has no type,
+ meaning it is implicitly a ``str``, ``CmdRunner`` would fail trying to find
+ the ``type`` key in that dictionary (https://github.com/ansible-collections/community.general/pull/6968).
+ - cobbler inventory plugin - fix calculation of cobbler_ipv4/6_address (https://github.com/ansible-collections/community.general/pull/6925).
+ - composer - fix impossible to run ``working_dir`` dependent commands. The module
+ was throwing an error when trying to run a ``working_dir`` dependent command,
+ because it tried to get the command help without passing the ``working_dir``
+ (https://github.com/ansible-collections/community.general/issues/3787).
+ - csv module utils - detects and remove unicode BOM markers from incoming CSV
+ content (https://github.com/ansible-collections/community.general/pull/6662).
+ - datadog_downtime - presence of ``rrule`` param lead to the Datadog API returning
+ Bad Request due to a missing recurrence type (https://github.com/ansible-collections/community.general/pull/6811).
+ - ejabberd_user - module was failing to detect whether user was already created
+ and/or password was changed (https://github.com/ansible-collections/community.general/pull/7033).
+ - ejabberd_user - provide meaningful error message when the ``ejabberdctl``
+ command is not found (https://github.com/ansible-collections/community.general/pull/7028,
+ https://github.com/ansible-collections/community.general/issues/6949).
+ - github_deploy_key - fix pagination behaviour causing a crash when only a single
+ page of deploy keys exist (https://github.com/ansible-collections/community.general/pull/7375).
+ - gitlab_group - the module passed parameters to the API call even when not
+ set. The module is now filtering out ``None`` values to remediate this (https://github.com/ansible-collections/community.general/pull/6712).
+ - gitlab_group_variable - deleted all variables when used with ``purge=true``
+ due to missing ``raw`` property in KNOWN attributes (https://github.com/ansible-collections/community.general/issues/7250).
+ - gitlab_project_variable - deleted all variables when used with ``purge=true``
+ due to missing ``raw`` property in KNOWN attributes (https://github.com/ansible-collections/community.general/issues/7250).
+ - icinga2_host - fix a key error when updating an existing host (https://github.com/ansible-collections/community.general/pull/6748).
+ - ini_file - add the ``follow`` paramter to follow the symlinks instead of replacing
+ them (https://github.com/ansible-collections/community.general/pull/6546).
+ - ini_file - fix a bug where the inactive options were not used when possible
+ (https://github.com/ansible-collections/community.general/pull/6575).
+ - ipa_dnszone - fix 'idnsallowsyncptr' key error for reverse zone (https://github.com/ansible-collections/community.general/pull/6906,
+ https://github.com/ansible-collections/community.general/issues/6905).
+ - kernel_blacklist - simplified the mechanism to update the file, fixing the
+ error (https://github.com/ansible-collections/community.general/pull/7382,
+ https://github.com/ansible-collections/community.general/issues/7362).
+ - keycloak module util - fix missing ``http_agent``, ``timeout``, and ``validate_certs``
+ ``open_url()`` parameters (https://github.com/ansible-collections/community.general/pull/7067).
+ - keycloak module utils - fix ``is_struct_included`` handling of lists of lists/dictionaries
+ (https://github.com/ansible-collections/community.general/pull/6688).
+ - keycloak module utils - the function ``get_user_by_username`` now return the
+ user representation or ``None`` as stated in the documentation (https://github.com/ansible-collections/community.general/pull/6758).
+ - keycloak_authentication - fix Keycloak authentication flow (step or sub-flow)
+ indexing during update, if not specified by the user (https://github.com/ansible-collections/community.general/pull/6734).
+ - keycloak_client inventory plugin - fix missing client secret (https://github.com/ansible-collections/community.general/pull/6931).
+ - ldap_search - fix string normalization and the ``base64_attributes`` option
+ on Python 3 (https://github.com/ansible-collections/community.general/issues/5704,
+ https://github.com/ansible-collections/community.general/pull/7264).
+ - locale_gen - now works for locales without the underscore character such as
+ ``C.UTF-8`` (https://github.com/ansible-collections/community.general/pull/6774,
+ https://github.com/ansible-collections/community.general/issues/5142, https://github.com/ansible-collections/community.general/issues/4305).
+ - lvol - add support for percentage of origin size specification when creating
+ snapshot volumes (https://github.com/ansible-collections/community.general/issues/1630,
+ https://github.com/ansible-collections/community.general/pull/7053).
+ - lxc connection plugin - now handles ``remote_addr`` defaulting to ``inventory_hostname``
+ correctly (https://github.com/ansible-collections/community.general/pull/7104).
+ - lxc connection plugin - properly evaluate options (https://github.com/ansible-collections/community.general/pull/7369).
+ - machinectl become plugin - mark plugin as ``require_tty`` to automatically
+ disable pipelining, with which this plugin is not compatible (https://github.com/ansible-collections/community.general/issues/6932,
+ https://github.com/ansible-collections/community.general/pull/6935).
+ - mail - skip headers containing equals characters due to missing ``maxsplit``
+ on header key/value parsing (https://github.com/ansible-collections/community.general/pull/7303).
+ - memset module utils - make compatible with ansible-core 2.17 (https://github.com/ansible-collections/community.general/pull/7379).
+ - nmap inventory plugin - fix ``get_option`` calls (https://github.com/ansible-collections/community.general/pull/7323).
+ - nmap inventory plugin - now uses ``get_option`` in all cases to get its configuration
+ information (https://github.com/ansible-collections/community.general/pull/7119).
+ - nmcli - fix bond option ``xmit_hash_policy`` (https://github.com/ansible-collections/community.general/pull/6527).
+ - nmcli - fix support for empty list (in compare and scrape) (https://github.com/ansible-collections/community.general/pull/6769).
+ - nsupdate - fix a possible ``list index out of range`` exception (https://github.com/ansible-collections/community.general/issues/836).
+ - oci_utils module util - fix inappropriate logical comparison expressions and
+ makes them simpler. The previous checks had logical short circuits (https://github.com/ansible-collections/community.general/pull/7125).
+ - oci_utils module utils - avoid direct type comparisons (https://github.com/ansible-collections/community.general/pull/7085).
+ - onepassword - fix KeyError exception when trying to access value of a field
+ that is not filled out in OnePassword item (https://github.com/ansible-collections/community.general/pull/7241).
+ - openbsd_pkg - the pkg_info(1) behavior has changed in OpenBSD >7.3. The error
+ message ``Can't find`` should not lead to an error case (https://github.com/ansible-collections/community.general/pull/6785).
+ - pacman - module recognizes the output of ``yay`` running as ``root`` (https://github.com/ansible-collections/community.general/pull/6713).
+ - portage - fix ``changed_use`` and ``newuse`` not triggering rebuilds (https://github.com/ansible-collections/community.general/issues/6008,
+ https://github.com/ansible-collections/community.general/pull/6548).
+ - pritunl module utils - fix incorrect URL parameter for orgnization add method
+ (https://github.com/ansible-collections/community.general/pull/7161).
+ - proxmox - fix error when a configuration had no ``template`` field (https://github.com/ansible-collections/community.general/pull/6838,
+ https://github.com/ansible-collections/community.general/issues/5372).
+ - proxmox module utils - add logic to detect whether an old Promoxer complains
+ about the ``token_name`` and ``token_value`` parameters and provide a better
+ error message when that happens (https://github.com/ansible-collections/community.general/pull/6839,
+ https://github.com/ansible-collections/community.general/issues/5371).
+ - proxmox module utils - fix proxmoxer library version check (https://github.com/ansible-collections/community.general/issues/6974,
+ https://github.com/ansible-collections/community.general/issues/6975, https://github.com/ansible-collections/community.general/pull/6980).
+ - proxmox_disk - fix unable to create ``cdrom`` media due to ``size`` always
+ being appended (https://github.com/ansible-collections/community.general/pull/6770).
+ - proxmox_kvm - ``absent`` state with ``force`` specified failed to stop the
+ VM due to the ``timeout`` value not being passed to ``stop_vm`` (https://github.com/ansible-collections/community.general/pull/6827).
+ - proxmox_kvm - ``restarted`` state did not actually restart a VM in some VM
+ configurations. The state now uses the Proxmox reboot endpoint instead of
+ calling the ``stop_vm`` and ``start_vm`` functions (https://github.com/ansible-collections/community.general/pull/6773).
+ - proxmox_kvm - allow creation of VM with existing name but new vmid (https://github.com/ansible-collections/community.general/issues/6155,
+ https://github.com/ansible-collections/community.general/pull/6709).
+ - proxmox_kvm - when ``name`` option is provided without ``vmid`` and VM with
+ that name already exists then no new VM will be created (https://github.com/ansible-collections/community.general/issues/6911,
+ https://github.com/ansible-collections/community.general/pull/6981).
+ - proxmox_tasks_info - remove ``api_user`` + ``api_password`` constraint from
+ ``required_together`` as it causes to require ``api_password`` even when API
+ token param is used (https://github.com/ansible-collections/community.general/issues/6201).
+ - proxmox_template - require ``requests_toolbelt`` module to fix issue with
+ uploading large templates (https://github.com/ansible-collections/community.general/issues/5579,
+ https://github.com/ansible-collections/community.general/pull/6757).
+ - proxmox_user_info - avoid direct type comparisons (https://github.com/ansible-collections/community.general/pull/7085).
+ - redfish_info - fix ``ListUsers`` to not show empty account slots (https://github.com/ansible-collections/community.general/issues/6771,
+ https://github.com/ansible-collections/community.general/pull/6772).
+ - 'redhat_subscription - use the right D-Bus options for the consumer type when
+
+ registering a RHEL system older than 9 or a RHEL 9 system older than 9.2
+
+ and using ``consumer_type``
+
+ (https://github.com/ansible-collections/community.general/pull/7378).
+
+ '
+ - refish_utils module utils - changing variable names to avoid issues occuring
+ when fetching Volumes data (https://github.com/ansible-collections/community.general/pull/6883).
+ - 'rhsm_repository - when using the ``purge`` option, the ``repositories``
+
+ dictionary element in the returned JSON is now properly updated according
+
+ to the pruning operation
+
+ (https://github.com/ansible-collections/community.general/pull/6676).
+
+ '
+ - rundeck - fix ``TypeError`` on 404 API response (https://github.com/ansible-collections/community.general/pull/6983).
+ - selective callback plugin - fix length of task name lines in output always
+ being 3 characters longer than desired (https://github.com/ansible-collections/community.general/pull/7374).
+ - snap - an exception was being raised when snap list was empty (https://github.com/ansible-collections/community.general/pull/7124,
+ https://github.com/ansible-collections/community.general/issues/7120).
+ - snap - assume default track ``latest`` in parameter ``channel`` when not specified
+ (https://github.com/ansible-collections/community.general/pull/6835, https://github.com/ansible-collections/community.general/issues/6821).
+ - snap - change the change detection mechanism from "parsing installation" to
+ "comparing end state with initial state" (https://github.com/ansible-collections/community.general/pull/7340,
+ https://github.com/ansible-collections/community.general/issues/7265).
+ - snap - fix crash when multiple snaps are specified and one has ``---`` in
+ its description (https://github.com/ansible-collections/community.general/pull/7046).
+ - snap - fix the processing of the commands' output, stripping spaces and newlines
+ from it (https://github.com/ansible-collections/community.general/pull/6826,
+ https://github.com/ansible-collections/community.general/issues/6803).
+ - sorcery - fix interruption of the multi-stage process (https://github.com/ansible-collections/community.general/pull/7012).
+ - sorcery - fix queue generation before the whole system rebuild (https://github.com/ansible-collections/community.general/pull/7012).
+ - sorcery - latest state no longer triggers update_cache (https://github.com/ansible-collections/community.general/pull/7012).
+ - terraform - prevents ``-backend-config`` option double encapsulating with
+ ``shlex_quote`` function. (https://github.com/ansible-collections/community.general/pull/7301).
+ - tss lookup plugin - fix multiple issues when using ``fetch_attachments=true``
+ (https://github.com/ansible-collections/community.general/pull/6720).
+ - zypper - added handling of zypper exitcode 102. Changed state is set correctly
+ now and rc 102 is still preserved to be evaluated by the playbook (https://github.com/ansible-collections/community.general/pull/6534).
+ deprecated_features:
+ - CmdRunner module utils - deprecate ``cmd_runner_fmt.as_default_type()`` formatter
+ (https://github.com/ansible-collections/community.general/pull/6601).
+ - MH VarsMixin module utils - deprecates ``VarsMixin`` and supporting classes
+ in favor of plain ``vardict`` module util (https://github.com/ansible-collections/community.general/pull/6649).
+ - ansible_galaxy_install - the ``ack_ansible29`` and ``ack_min_ansiblecore211``
+ options have been deprecated and will be removed in community.general 9.0.0
+ (https://github.com/ansible-collections/community.general/pull/7358).
+ - consul - the ``ack_params_state_absent`` option has been deprecated and will
+ be removed in community.general 10.0.0 (https://github.com/ansible-collections/community.general/pull/7358).
+ - cpanm - value ``compatibility`` is deprecated as default for parameter ``mode``
+ (https://github.com/ansible-collections/community.general/pull/6512).
+ - ejabberd_user - deprecate the parameter ``logging`` in favour of producing
+ more detailed information in the module output (https://github.com/ansible-collections/community.general/pull/7043).
+ - flowdock - module relies entirely on no longer responsive API endpoints, and
+ it will be removed in community.general 9.0.0 (https://github.com/ansible-collections/community.general/pull/6930).
+ - proxmox - old feature flag ``proxmox_default_behavior`` will be removed in
+ community.general 10.0.0 (https://github.com/ansible-collections/community.general/pull/6836).
+ - proxmox_kvm - deprecate the option ``proxmox_default_behavior`` (https://github.com/ansible-collections/community.general/pull/7377).
+ - redfish_info, redfish_config, redfish_command - the default value ``10`` for
+ the ``timeout`` option is deprecated and will change to ``60`` in community.general
+ 9.0.0 (https://github.com/ansible-collections/community.general/pull/7295).
+ - 'redhat module utils - the ``module_utils.redhat`` module is deprecated, as
+
+ effectively unused: the ``Rhsm``, ``RhsmPool``, and ``RhsmPools`` classes
+
+ will be removed in community.general 9.0.0; the ``RegistrationBase`` class
+
+ will be removed in community.general 10.0.0 together with the
+
+ ``rhn_register`` module, as it is the only user of this class; this means
+
+ that the whole ``module_utils.redhat`` module will be dropped in
+
+ community.general 10.0.0, so importing it without even using anything of it
+
+ will fail
+
+ (https://github.com/ansible-collections/community.general/pull/6663).
+
+ '
+ - 'redhat_subscription - the ``autosubscribe`` alias for the ``auto_attach``
+ option has been
+
+ deprecated for many years, although only in the documentation. Officially
+ mark this alias
+
+ as deprecated, and it will be removed in community.general 9.0.0
+
+ (https://github.com/ansible-collections/community.general/pull/6646).
+
+ '
+ - 'redhat_subscription - the ``pool`` option is deprecated in favour of the
+
+ more precise and flexible ``pool_ids`` option
+
+ (https://github.com/ansible-collections/community.general/pull/6650).
+
+ '
+ - 'rhsm_repository - ``state=present`` has not been working as expected for
+ many years,
+
+ and it seems it was not noticed so far; also, "presence" is not really a valid
+ concept
+
+ for subscription repositories, which can only be enabled or disabled. Hence,
+ mark the
+
+ ``present`` and ``absent`` values of the ``state`` option as deprecated, slating
+ them
+
+ for removal in community.general 10.0.0
+
+ (https://github.com/ansible-collections/community.general/pull/6673).
+
+ '
+ - stackdriver - module relies entirely on no longer existent API endpoints,
+ and it will be removed in community.general 9.0.0 (https://github.com/ansible-collections/community.general/pull/6887).
+ - webfaction_app - module relies entirely on no longer existent API endpoints,
+ and it will be removed in community.general 9.0.0 (https://github.com/ansible-collections/community.general/pull/6909).
+ - webfaction_db - module relies entirely on no longer existent API endpoints,
+ and it will be removed in community.general 9.0.0 (https://github.com/ansible-collections/community.general/pull/6909).
+ - webfaction_domain - module relies entirely on no longer existent API endpoints,
+ and it will be removed in community.general 9.0.0 (https://github.com/ansible-collections/community.general/pull/6909).
+ - webfaction_mailbox - module relies entirely on no longer existent API endpoints,
+ and it will be removed in community.general 9.0.0 (https://github.com/ansible-collections/community.general/pull/6909).
+ - webfaction_site - module relies entirely on no longer existent API endpoints,
+ and it will be removed in community.general 9.0.0 (https://github.com/ansible-collections/community.general/pull/6909).
+ known_issues:
+ - Ansible markup will show up in raw form on ansible-doc text output for ansible-core
+ before 2.15. If you have trouble deciphering the documentation markup, please
+ upgrade to ansible-core 2.15 (or newer), or read the HTML documentation on
+ https://docs.ansible.com/ansible/devel/collections/community/general/ (https://github.com/ansible-collections/community.general/pull/6539).
minor_changes:
- - ansible_galaxy_install - refactored module to use ``CmdRunner`` to execute
- ``ansible-galaxy`` (https://github.com/ansible-collections/community.general/pull/5477).
- - cpanm - refactored module to use ``CmdRunner`` to execute ``cpanm`` (https://github.com/ansible-collections/community.general/pull/5485).
- - hponcfg - refactored module to use ``CmdRunner`` to execute ``hponcfg`` (https://github.com/ansible-collections/community.general/pull/5483).
- - ldap_attrs - allow for DNs to have ``{x}`` prefix on first RDN (https://github.com/ansible-collections/community.general/issues/977,
- https://github.com/ansible-collections/community.general/pull/5450).
- - mksysb - refactored module to use ``CmdRunner`` to execute ``mksysb`` (https://github.com/ansible-collections/community.general/pull/5484).
- - onepassword - support version 2 of the OnePassword CLI (https://github.com/ansible-collections/community.general/pull/4728)
- release_summary: New major release of community.general with lots of bugfixes,
- new features, some removed deprecated features, and some other breaking changes.
- Please check the coresponding sections of the changelog for more details.
+ - The collection will start using semantic markup (https://github.com/ansible-collections/community.general/pull/6539).
+ - VarDict module utils - add method ``VarDict.as_dict()`` to convert to a plain
+ ``dict`` object (https://github.com/ansible-collections/community.general/pull/6602).
+ - 'apt_rpm - extract package name from local ``.rpm`` path when verifying
+
+ installation success. Allows installing packages from local ``.rpm`` files
+
+ (https://github.com/ansible-collections/community.general/pull/7396).
+
+ '
+ - cargo - add option ``executable``, which allows user to specify path to the
+ cargo binary (https://github.com/ansible-collections/community.general/pull/7352).
+ - cargo - add option ``locked`` which allows user to specify install the locked
+ version of dependency instead of latest compatible version (https://github.com/ansible-collections/community.general/pull/6134).
+ - chroot connection plugin - add ``disable_root_check`` option (https://github.com/ansible-collections/community.general/pull/7099).
+ - cloudflare_dns - add CAA record support (https://github.com/ansible-collections/community.general/pull/7399).
+ - cobbler inventory plugin - add ``exclude_mgmt_classes`` and ``include_mgmt_classes``
+ options to exclude or include hosts based on management classes (https://github.com/ansible-collections/community.general/pull/7184).
+ - cobbler inventory plugin - add ``inventory_hostname`` option to allow using
+ the system name for the inventory hostname (https://github.com/ansible-collections/community.general/pull/6502).
+ - cobbler inventory plugin - add ``want_ip_addresses`` option to collect all
+ interface DNS name to IP address mapping (https://github.com/ansible-collections/community.general/pull/6711).
+ - cobbler inventory plugin - add primary IP addess to ``cobbler_ipv4_address``
+ and IPv6 address to ``cobbler_ipv6_address`` host variable (https://github.com/ansible-collections/community.general/pull/6711).
+ - cobbler inventory plugin - add warning for systems with empty profiles (https://github.com/ansible-collections/community.general/pull/6502).
+ - cobbler inventory plugin - convert Ansible unicode strings to native Python
+ unicode strings before passing user/password to XMLRPC client (https://github.com/ansible-collections/community.general/pull/6923).
+ - consul_session - drops requirement for the ``python-consul`` library to communicate
+ with the Consul API, instead relying on the existing ``requests`` library
+ requirement (https://github.com/ansible-collections/community.general/pull/6755).
+ - copr - respawn module to use the system python interpreter when the ``dnf``
+ python module is not available in ``ansible_python_interpreter`` (https://github.com/ansible-collections/community.general/pull/6522).
+ - cpanm - minor refactor when creating the ``CmdRunner`` object (https://github.com/ansible-collections/community.general/pull/7231).
+ - datadog_monitor - adds ``notification_preset_name``, ``renotify_occurrences``
+ and ``renotify_statuses`` parameters (https://github.com/ansible-collections/community.general/issues/6521,https://github.com/ansible-collections/community.general/issues/5823).
+ - dig lookup plugin - add TCP option to enable the use of TCP connection during
+ DNS lookup (https://github.com/ansible-collections/community.general/pull/7343).
+ - ejabberd_user - module now using ``CmdRunner`` to execute external command
+ (https://github.com/ansible-collections/community.general/pull/7075).
+ - filesystem - add ``uuid`` parameter for UUID change feature (https://github.com/ansible-collections/community.general/pull/6680).
+ - 'gitlab_group - add option ``force_delete`` (default: false) which allows
+ delete group even if projects exists in it (https://github.com/ansible-collections/community.general/pull/7364).'
+ - gitlab_group_variable - add support for ``raw`` variables suboption (https://github.com/ansible-collections/community.general/pull/7132).
+ - gitlab_project_variable - add support for ``raw`` variables suboption (https://github.com/ansible-collections/community.general/pull/7132).
+ - gitlab_project_variable - minor refactor removing unnecessary code statements
+ (https://github.com/ansible-collections/community.general/pull/6928).
+ - gitlab_runner - minor refactor removing unnecessary code statements (https://github.com/ansible-collections/community.general/pull/6927).
+ - htpasswd - minor code improvements in the module (https://github.com/ansible-collections/community.general/pull/6901).
+ - htpasswd - the parameter ``crypt_scheme`` is being renamed as ``hash_scheme``
+ and added as an alias to it (https://github.com/ansible-collections/community.general/pull/6841).
+ - icinga2_host - the ``ip`` option is no longer required, since Icinga 2 allows
+ for an empty address attribute (https://github.com/ansible-collections/community.general/pull/7452).
+ - ini_file - add ``ignore_spaces`` option (https://github.com/ansible-collections/community.general/pull/7273).
+ - ini_file - add ``modify_inactive_option`` option (https://github.com/ansible-collections/community.general/pull/7401).
+ - ipa_config - add module parameters to manage FreeIPA user and group objectclasses
+ (https://github.com/ansible-collections/community.general/pull/7019).
+ - ipa_config - adds ``idp`` choice to ``ipauserauthtype`` parameter's choices
+ (https://github.com/ansible-collections/community.general/pull/7051).
+ - jenkins_build - add new ``detach`` option, which allows the module to exit
+ successfully as long as the build is created (default functionality is still
+ waiting for the build to end before exiting) (https://github.com/ansible-collections/community.general/pull/7204).
+ - jenkins_build - add new ``time_between_checks`` option, which allows to configure
+ the wait time between requests to the Jenkins server (https://github.com/ansible-collections/community.general/pull/7204).
+ - keycloak_authentication - added provider ID choices, since Keycloak supports
+ only those two specific ones (https://github.com/ansible-collections/community.general/pull/6763).
+ - keycloak_client_rolemapping - adds support for subgroups with additional parameter
+ ``parents`` (https://github.com/ansible-collections/community.general/pull/6687).
+ - keycloak_role - add composite roles support for realm and client roles (https://github.com/ansible-collections/community.general/pull/6469).
+ - keyring - minor refactor removing unnecessary code statements (https://github.com/ansible-collections/community.general/pull/6927).
+ - ldap_* - add new arguments ``client_cert`` and ``client_key`` to the LDAP
+ modules in order to allow certificate authentication (https://github.com/ansible-collections/community.general/pull/6668).
+ - ldap_search - add a new ``page_size`` option to enable paged searches (https://github.com/ansible-collections/community.general/pull/6648).
+ - locale_gen - module has been refactored to use ``ModuleHelper`` and ``CmdRunner``
+ (https://github.com/ansible-collections/community.general/pull/6903).
+ - locale_gen - module now using ``CmdRunner`` to execute external commands (https://github.com/ansible-collections/community.general/pull/6820).
+ - lvg - add ``active`` and ``inactive`` values to the ``state`` option for active
+ state management feature (https://github.com/ansible-collections/community.general/pull/6682).
+ - lvg - add ``reset_vg_uuid``, ``reset_pv_uuid`` options for UUID reset feature
+ (https://github.com/ansible-collections/community.general/pull/6682).
+ - lxc connection plugin - properly handle a change of the ``remote_addr`` option
+ (https://github.com/ansible-collections/community.general/pull/7373).
+ - lxd connection plugin - automatically translate ``remote_addr`` from FQDN
+ to (short) hostname (https://github.com/ansible-collections/community.general/pull/7360).
+ - lxd connection plugin - update error parsing to work with newer messages mentioning
+ instances (https://github.com/ansible-collections/community.general/pull/7360).
+ - lxd inventory plugin - add ``server_cert`` option for trust anchor to use
+ for TLS verification of server certificates (https://github.com/ansible-collections/community.general/pull/7392).
+ - lxd inventory plugin - add ``server_check_hostname`` option to disable hostname
+ verification of server certificates (https://github.com/ansible-collections/community.general/pull/7392).
+ - make - add new ``targets`` parameter allowing multiple targets to be used
+ with ``make`` (https://github.com/ansible-collections/community.general/pull/6882,
+ https://github.com/ansible-collections/community.general/issues/4919).
+ - make - allows ``params`` to be used without value (https://github.com/ansible-collections/community.general/pull/7180).
+ - mas - disable sign-in check for macOS 12+ as ``mas account`` is non-functional
+ (https://github.com/ansible-collections/community.general/pull/6520).
+ - newrelic_deployment - add option ``app_name_exact_match``, which filters results
+ for the exact app_name provided (https://github.com/ansible-collections/community.general/pull/7355).
+ - nmap inventory plugin - now has a ``use_arp_ping`` option to allow the user
+ to disable the default ARP ping query for a more reliable form (https://github.com/ansible-collections/community.general/pull/7119).
+ - nmcli - add support for ``ipv4.dns-options`` and ``ipv6.dns-options`` (https://github.com/ansible-collections/community.general/pull/6902).
+ - nomad_job, nomad_job_info - add ``port`` parameter (https://github.com/ansible-collections/community.general/pull/7412).
+ - npm - minor improvement on parameter validation (https://github.com/ansible-collections/community.general/pull/6848).
+ - npm - module now using ``CmdRunner`` to execute external commands (https://github.com/ansible-collections/community.general/pull/6989).
+ - onepassword lookup plugin - add service account support (https://github.com/ansible-collections/community.general/issues/6635,
+ https://github.com/ansible-collections/community.general/pull/6660).
+ - onepassword lookup plugin - introduce ``account_id`` option which allows specifying
+ which account to use (https://github.com/ansible-collections/community.general/pull/7308).
+ - onepassword_raw lookup plugin - add service account support (https://github.com/ansible-collections/community.general/issues/6635,
+ https://github.com/ansible-collections/community.general/pull/6660).
+ - onepassword_raw lookup plugin - introduce ``account_id`` option which allows
+ specifying which account to use (https://github.com/ansible-collections/community.general/pull/7308).
+ - opentelemetry callback plugin - add span attributes in the span event (https://github.com/ansible-collections/community.general/pull/6531).
+ - opkg - add ``executable`` parameter allowing to specify the path of the ``opkg``
+ command (https://github.com/ansible-collections/community.general/pull/6862).
+ - opkg - remove default value ``""`` for parameter ``force`` as it causes the
+ same behaviour of not having that parameter (https://github.com/ansible-collections/community.general/pull/6513).
+ - pagerduty - adds in option to use v2 API for creating pagerduty incidents
+ (https://github.com/ansible-collections/community.general/issues/6151)
+ - parted - on resize, use ``--fix`` option if available (https://github.com/ansible-collections/community.general/pull/7304).
+ - pnpm - set correct version when state is latest or version is not mentioned.
+ Resolves previous idempotency problem (https://github.com/ansible-collections/community.general/pull/7339).
+ - pritunl module utils - ensure ``validate_certs`` parameter is honoured in
+ all methods (https://github.com/ansible-collections/community.general/pull/7156).
+ - proxmox - add ``vmid`` (and ``taskid`` when possible) to return values (https://github.com/ansible-collections/community.general/pull/7263).
+ - proxmox - support ``timezone`` parameter at container creation (https://github.com/ansible-collections/community.general/pull/6510).
+ - proxmox inventory plugin - add composite variables support for Proxmox nodes
+ (https://github.com/ansible-collections/community.general/issues/6640).
+ - proxmox_kvm - added support for ``tpmstate0`` parameter to configure TPM (Trusted
+ Platform Module) disk. TPM is required for Windows 11 installations (https://github.com/ansible-collections/community.general/pull/6533).
+ - proxmox_kvm - enabled force restart of VM, bringing the ``force`` parameter
+ functionality in line with what is described in the docs (https://github.com/ansible-collections/community.general/pull/6914).
+ - proxmox_kvm - re-use ``timeout`` module param to forcefully shutdown a virtual
+ machine when ``state`` is ``stopped`` (https://github.com/ansible-collections/community.general/issues/6257).
+ - proxmox_snap - add ``retention`` parameter to delete old snapshots (https://github.com/ansible-collections/community.general/pull/6576).
+ - proxmox_vm_info - ``node`` parameter is no longer required. Information can
+ be obtained for the whole cluster (https://github.com/ansible-collections/community.general/pull/6976).
+ - proxmox_vm_info - non-existing provided by name/vmid VM would return empty
+ results instead of failing (https://github.com/ansible-collections/community.general/pull/7049).
+ - pubnub_blocks - minor refactor removing unnecessary code statements (https://github.com/ansible-collections/community.general/pull/6928).
+ - random_string - added new ``ignore_similar_chars`` and ``similar_chars`` option
+ to ignore certain chars (https://github.com/ansible-collections/community.general/pull/7242).
+ - redfish_command - add ``MultipartHTTPPushUpdate`` command (https://github.com/ansible-collections/community.general/issues/6471,
+ https://github.com/ansible-collections/community.general/pull/6612).
+ - redfish_command - add ``account_types`` and ``oem_account_types`` as optional
+ inputs to ``AddUser`` (https://github.com/ansible-collections/community.general/issues/6823,
+ https://github.com/ansible-collections/community.general/pull/6871).
+ - redfish_command - add new option ``update_oem_params`` for the ``MultipartHTTPPushUpdate``
+ command (https://github.com/ansible-collections/community.general/issues/7331).
+ - redfish_config - add ``CreateVolume`` command to allow creation of volumes
+ on servers (https://github.com/ansible-collections/community.general/pull/6813).
+ - redfish_config - add ``DeleteAllVolumes`` command to allow deletion of all
+ volumes on servers (https://github.com/ansible-collections/community.general/pull/6814).
+ - redfish_config - adding ``SetSecureBoot`` command (https://github.com/ansible-collections/community.general/pull/7129).
+ - redfish_info - add ``AccountTypes`` and ``OEMAccountTypes`` to the output
+ of ``ListUsers`` (https://github.com/ansible-collections/community.general/issues/6823,
+ https://github.com/ansible-collections/community.general/pull/6871).
+ - redfish_info - add support for ``GetBiosRegistries`` command (https://github.com/ansible-collections/community.general/pull/7144).
+ - redfish_info - adds ``LinkStatus`` to NIC inventory (https://github.com/ansible-collections/community.general/pull/7318).
+ - redfish_info - adds ``ProcessorArchitecture`` to CPU inventory (https://github.com/ansible-collections/community.general/pull/6864).
+ - redfish_info - fix for ``GetVolumeInventory``, Controller name was getting
+ populated incorrectly and duplicates were seen in the volumes retrieved (https://github.com/ansible-collections/community.general/pull/6719).
+ - redfish_info - report ``Id`` in the output of ``GetManagerInventory`` (https://github.com/ansible-collections/community.general/pull/7140).
+ - redfish_utils - use ``Controllers`` key in redfish data to obtain Storage
+ controllers properties (https://github.com/ansible-collections/community.general/pull/7081).
+ - redfish_utils module utils - add support for ``PowerCycle`` reset type for
+ ``redfish_command`` responses feature (https://github.com/ansible-collections/community.general/issues/7083).
+ - redfish_utils module utils - add support for following ``@odata.nextLink``
+ pagination in ``software_inventory`` responses feature (https://github.com/ansible-collections/community.general/pull/7020).
+ - redfish_utils module utils - support ``Volumes`` in response for ``GetDiskInventory``
+ (https://github.com/ansible-collections/community.general/pull/6819).
+ - 'redhat_subscription - the internal ``RegistrationBase`` class was folded
+
+ into the other internal ``Rhsm`` class, as the separation had no purpose
+
+ anymore
+
+ (https://github.com/ansible-collections/community.general/pull/6658).
+
+ '
+ - redis_info - refactor the redis_info module to use the redis module_utils
+ enabling to pass TLS parameters to the Redis client (https://github.com/ansible-collections/community.general/pull/7267).
+ - 'rhsm_release - improve/harden the way ``subscription-manager`` is run;
+
+ no behaviour change is expected
+
+ (https://github.com/ansible-collections/community.general/pull/6669).
+
+ '
+ - 'rhsm_repository - the interaction with ``subscription-manager`` was
+
+ refactored by grouping things together, removing unused bits, and hardening
+
+ the way it is run; also, the parsing of ``subscription-manager repos --list``
+
+ was improved and made slightly faster; no behaviour change is expected
+
+ (https://github.com/ansible-collections/community.general/pull/6783,
+
+ https://github.com/ansible-collections/community.general/pull/6837).
+
+ '
+ - scaleway_security_group_rule - minor refactor removing unnecessary code statements
+ (https://github.com/ansible-collections/community.general/pull/6928).
+ - shutdown - use ``shutdown -p ...`` with FreeBSD to halt and power off machine
+ (https://github.com/ansible-collections/community.general/pull/7102).
+ - snap - add option ``dangerous`` to the module, that will map into the command
+ line argument ``--dangerous``, allowing unsigned snap files to be installed
+ (https://github.com/ansible-collections/community.general/pull/6908, https://github.com/ansible-collections/community.general/issues/5715).
+ - snap - module is now aware of channel when deciding whether to install or
+ refresh the snap (https://github.com/ansible-collections/community.general/pull/6435,
+ https://github.com/ansible-collections/community.general/issues/1606).
+ - sorcery - add grimoire (repository) management support (https://github.com/ansible-collections/community.general/pull/7012).
+ - sorcery - minor refactor (https://github.com/ansible-collections/community.general/pull/6525).
+ - supervisorctl - allow to stop matching running processes before removing them
+ with ``stop_before_removing=true`` (https://github.com/ansible-collections/community.general/pull/7284).
+ - tss lookup plugin - allow to fetch secret IDs which are in a folder based
+ on folder ID. Previously, we could not fetch secrets based on folder ID but
+ now use ``fetch_secret_ids_from_folder`` option to indicate to fetch secret
+ IDs based on folder ID (https://github.com/ansible-collections/community.general/issues/6223).
+ - tss lookup plugin - allow to fetch secret by path. Previously, we could not
+ fetch secret by path but now use ``secret_path`` option to indicate to fetch
+ secret by secret path (https://github.com/ansible-collections/community.general/pull/6881).
+ - unixy callback plugin - add support for ``check_mode_markers`` option (https://github.com/ansible-collections/community.general/pull/7179).
+ - vardict module utils - added convenience methods to ``VarDict`` (https://github.com/ansible-collections/community.general/pull/6647).
+ - xenserver_guest_info - minor refactor removing unnecessary code statements
+ (https://github.com/ansible-collections/community.general/pull/6928).
+ - xenserver_guest_powerstate - minor refactor removing unnecessary code statements
+ (https://github.com/ansible-collections/community.general/pull/6928).
+ - yum_versionlock - add support to pin specific package versions instead of
+ only the package itself (https://github.com/ansible-collections/community.general/pull/6861,
+ https://github.com/ansible-collections/community.general/issues/4470).
+ release_summary: This is release 8.0.0 of ``community.general``, released on
+ 2023-11-01.
+ removed_features:
+ - The collection no longer supports ansible-core 2.11 and ansible-core 2.12.
+ Parts of the collection might still work on these ansible-core versions, but
+ others might not (https://github.com/ansible-collections/community.general/pull/7269).
+ - ansible_galaxy_install - support for Ansible 2.9 and ansible-base 2.10 has
+ been removed (https://github.com/ansible-collections/community.general/pull/7358).
+ - consul - when ``state=absent``, the options ``script``, ``ttl``, ``tcp``,
+ ``http``, and ``interval`` can no longer be specified (https://github.com/ansible-collections/community.general/pull/7358).
+ - gconftool2 - ``state=get`` has been removed. Use the module ``community.general.gconftool2_info``
+ instead (https://github.com/ansible-collections/community.general/pull/7358).
+ - gitlab_runner - remove the default value for the ``access_level`` option.
+ To restore the previous behavior, explicitly set it to ``ref_protected`` (https://github.com/ansible-collections/community.general/pull/7358).
+ - htpasswd - removed code for passlib <1.6 (https://github.com/ansible-collections/community.general/pull/6901).
+ - manageiq_polices - ``state=list`` has been removed. Use the module ``community.general.manageiq_policies_info``
+ instead (https://github.com/ansible-collections/community.general/pull/7358).
+ - manageiq_tags - ``state=list`` has been removed. Use the module ``community.general.manageiq_tags_info``
+ instead (https://github.com/ansible-collections/community.general/pull/7358).
+ - mh.mixins.cmd module utils - the ``ArgFormat`` class has been removed (https://github.com/ansible-collections/community.general/pull/7358).
+ - mh.mixins.cmd module utils - the ``CmdMixin`` mixin has been removed. Use
+ ``community.general.plugins.module_utils.cmd_runner.CmdRunner`` instead (https://github.com/ansible-collections/community.general/pull/7358).
+ - mh.mixins.cmd module utils - the mh.mixins.cmd module utils has been removed
+ after all its contents were removed (https://github.com/ansible-collections/community.general/pull/7358).
+ - mh.module_helper module utils - the ``CmdModuleHelper`` and ``CmdStateModuleHelper``
+ classes have been removed. Use ``community.general.plugins.module_utils.cmd_runner.CmdRunner``
+ instead (https://github.com/ansible-collections/community.general/pull/7358).
+ - proxmox module utils - removed unused imports (https://github.com/ansible-collections/community.general/pull/6873).
+ - xfconf - the deprecated ``disable_facts`` option was removed (https://github.com/ansible-collections/community.general/pull/7358).
fragments:
- - 4728-onepassword-v2.yml
- - 5435-escape-ldap-param.yml
- - 5450-allow-for-xordered-dns.yaml
- - 5468-iso-create-not-add-folders.yml
- - 5475-snap-option-value-whitespace.yml
- - 5477-ansible-galaxy-install-cmd-runner.yml
- - 5483-hponcfg-cmd-runner.yml
- - 5484-mksysb-cmd-runner.yml
- - 5485-cpanm-cmd-runner.yml
- - 5497-scaleway-filtering.yml
- - 6.0.0.yml
+ - 3787-pass-composer-working-dir.yml
+ - 6134-add-locked-option-for-cargo.yml
+ - 6223-get-secret-ids-by-folderid.yml
+ - 6435-snap-channel-aware.yml
+ - 6469-add-composites-support-for-keycloak-role.yml
+ - 6471-redfish-add-multipart-http-push-command.yml
+ - 6502-cobbler-inventory_hostname.yml
+ - 6510-proxmox-create-support_timezone.yaml
+ - 6512-cpanm-default-mode.yml
+ - 6513-opkg-default-force.yml
+ - 6520-mas-disable-signin.yaml
+ - 6522-copr-respawn.yaml
+ - 6523-datadog-monitor-notification-preset-name-and-renotify.yaml
+ - 6525-sorcery-import.yaml
+ - 6527-nmcli-bond-fix-xmit_hash_policy.yml
+ - 6531-opentelemetry-add-event-attributes.yml
+ - 6533-proxmox_kvm-tpmstate0-support.yaml
+ - 6534-zypper-exitcode-102-handled.yaml
+ - 6539-semantic-markup.yml
+ - 6548-portage-changed_use-newuse.yml
+ - 6554-proxmox-tasks-info-fix-required-password.yaml
+ - 6568-fix-get-user-by-username-in-keycloak-module-utils.yml
+ - 6570-handle-shutdown-timeout.yaml
+ - 6576-proxmox-snap-allow-to-remove-old-snapshots.yml
+ - 6601-cmdrunner-deprecate-default-type.yml
+ - 6602-vardict-as-dict.yml
+ - 6640-proxmox-composite-variables-support.yml
+ - 6644-dependencymixin-fix.yml
+ - 6646-redhat_subscription-deprecate-autosubscribe.yml
+ - 6647-vardict-methods.yml
+ - 6648_ldap_search_page_size.yml
+ - 6649-varsmixin-deprecation.yml
+ - 6650-redhat_subscription-deprecate-pool.yml
+ - 6658-redhat_subscription-internal-rhsm-refactor.yml
+ - 6660-onepassword-lookup-service-account.yaml
+ - 6662-csv-bom.yml
+ - 6663-deprecate-module_utils-redhat.yml
+ - 6668-ldap-client-cert.yml
+ - 6669-rhsm_release-internal-sub-man-exec.yml
+ - 6673-rhsm_repository-deprecate-present-absent.yml
+ - 6676-rhsm_repository-fix-returned-repositories-with-purge.yml
+ - 6680-filesystem-uuid-change.yml
+ - 6682-lvg-clonesupport.yml
+ - 6687-support-subgroups-for-keycloak-client-rolemapping.yml
+ - 6688-is-struct-included-bug-in-keycloak-py.yml
+ - 6709-proxmox-create-vm-with-existing-name.yml
+ - 6711-cobbler-ip-address.yml
+ - 6712-gitlab_group-filtered-for-none-values.yml
+ - 6713-yay-become.yml
+ - 6719-redfish-utils-fix-for-get-volume-inventory.yml
+ - 6720-tss-fix-fetch-attachments.yml
+ - 6734-keycloak-auth-management-indexing.yml
+ - 6748-icinga2_host-datafix.yml
+ - 6755-refactor-consul-session-to-use-requests-lib-instead-of-consul.yml
+ - 6757-proxmox-template-fix-upload-error.yml
+ - 6763-keycloak-auth-provider-choices.yml
+ - 6769-nmcli-fix-empty-list.yml
+ - 6770-proxmox_disk_create_cdrom.yml
+ - 6771-redfish-filter-empty-account-slots.yml
+ - 6773-proxmox_kvm-restarted-state-bug-fix.yaml
+ - 6774-locale-gen-fix.yml
+ - 6783-6837-rhsm_repository-internal-refactor.yml
+ - 6785-openbsd_pkg_pkg_info_handling.yml
+ - 6811-datadog-downtime-rrule-type.yaml
+ - 6813-redfish-config-add-create-volume.yml
+ - 6814-redfish-config-add-delete-all-volumes.yml
+ - 6819-redfish-utils-add-links-parameter-for-get_disk_inventory.yml
+ - 6820-locale-gen-cmdrunner.yml
+ - 6823-redfish-add-account-type-management.yml
+ - 6826-snap-out-strip.yml
+ - 6827-proxmox_kvm-force-delete-bug-fix.yaml
+ - 6835-snap-missing-track.yml
+ - 6836-proxmox-deprecate-compatibility.yml
+ - 6838-proxmox-dict-template.yml
+ - 6839-promoxer-tokens.yml
+ - 6841-htpasswd-crypt-scheme.yml
+ - 6848-npm-required-if.yml
+ - 6861-yum_versionlock_minor_change_add-pinning-specific-versions.yml
+ - 6862-opkg-exec.yml
+ - 6864-redfish-utils-fix-for-processorarchitecture-in-cpu-inventory.yaml
+ - 6873-proxmox-imports.yml
+ - 6882-make-multiple-targets.yml
+ - 6883-redfish-utils-changing-variable-names-in-get-volume-inventory.yml
+ - 6887-deprecate-stackdrive.yml
+ - 6901-htpasswd-refactor.yml
+ - 6902-added-support-in-nmcli-for-ipvx-dns-options.yml
+ - 6903-locale-gen-refactor.yml
+ - 6905-ipa_dnszone-key-error-fix.yml
+ - 6908-snap-dangerous.yml
+ - 6909-deprecate-webfaction.yml
+ - 6914-proxmox_kvm-enable-force-restart.yml
+ - 6923-cobbler-inventory_unicode.yml
+ - 6925-cobbler-inventory-bugfix.yml
+ - 6927-pylint-comments.yml
+ - 6928-noqa-comments.yml
+ - 6930-deprecate-flowdock.yml
+ - 6931-keycloak_client-inventory-bugfix.yml
+ - 6935-machinectl-become.yml
+ - 6949-ejabberdctl-error.yml
+ - 6968-cmdrunner-implicit-type.yml
+ - 6976-proxmox-vm-info-not-require-node.yml
+ - 6980-proxmox-fix-token-auth.yml
+ - 6981-proxmox-fix-vm-creation-when-only-name-provided.yml
+ - 6983-rundeck-fix-typerrror-on-404-api-response.yml
+ - 6989-npm-cmdrunner.yml
+ - 7012-sorcery-grimoire-mgmt.yml
+ - 7019-ipa_config-user-and-group-objectclasses.yml
+ - 7020-redfish-utils-pagination.yml
+ - 7033-ejabberd-user-bugs.yml
+ - 7043-ejabberd-user-deprecate-logging.yml
+ - 7046-snap-newline-before-separator.yml
+ - 7049-proxmox-vm-info-empty-results.yml
+ - 7051-ipa-config-new-choice-idp-to-ipauserauthtype.yml
+ - 7061-fix-bitwarden-get_field.yml
+ - 7067-keycloak-api-paramerter-fix.yml
+ - 7075-ejabberd-user-cmdrunner.yml
+ - 7081-redfish-utils-fix-for-storagecontrollers-deprecated-key.yaml
+ - 7085-sanity.yml
+ - 7099-chroot-disable-root-check-option.yml
+ - 7102-freebsd-shutdown-p.yml
+ - 7104_fix_lxc_remoteaddr_default.yml
+ - 7113-redfish-utils-power-cycle.yml
+ - 7118-nmap_inv_plugin_no_arp_option.yml
+ - 7124-snap-empty-list.yml
+ - 7125-fix-inappropriate-comparison.yml
+ - 7129-adding_set_secure_boot_command_to_redfish_config.yml
+ - 7132-gitlab-raw-variables.yml
+ - 7140-id-getmanagerinv-output.yml
+ - 7144-add-getbiosregistry-command-to-redfish-info.yml
+ - 7156-ensure-validate-certs-parameter-is-honoured.yml
+ - 7158-gitlab-project-default-branch-update.yml
+ - 7161-fix-incorrect-post-parameter.yml
+ - 7179-unixy-support-checkmode-markers.yml
+ - 7180-make_params_without_value.yml
+ - 7184-cobbler-mgmt-classes.yml
+ - 7200-cmd-runner-abs-path.yml
+ - 7219-fix-nsupdate-cname.yaml
+ - 7231-cpanm-adjustments.yml
+ - 7241-prevent-key-error-when-value-does-not-exist.yml
+ - 7242_ignore_similar_chars.yml
+ - 7251-gitlab-variables-deleteing-all-variables.yml
+ - 7263-proxmox-return-vmid-and-taskid.yaml
+ - 7264-ldap_search-strings.yml
+ - 7267-redis_info.yml
+ - 7273-ini_file_ignore_spaces.yml
+ - 7284-supervisorctl-stop-before-remove.yaml
+ - 7295-adding_deprecation_for_timeout_in_redfish_info_config_command.yml
+ - 7301-fix-backend-config-string-encapsulation.yml
+ - 7303-mail-incorrect-header-parsing.yml
+ - 7304-prevent-parted-warnings.yml
+ - 7308-onepassword-multi-acc.yml
+ - 7318-add-linkstatus-attribute-to-nic-inventory.yml
+ - 7323-nmap.yml
+ - 7330-redfish-utils-oem-params.yml
+ - 7339-pnpm-correct-version-when-state-latest.yml
+ - 7340-snap-fix.yml
+ - 7343-dig-tcp-option.yml
+ - 7352-add-executable-option-for-cargo.yml
+ - 7355-newrelic-deployment-add-exact-name.yml
+ - 7360-lxd-remote-addr-host.yml
+ - 7364-add-option-force-gitlab-group.yml
+ - 7369-fix-lxc-options.yml
+ - 7373-lxc-remote-addr-change.yml
+ - 7374-fix-selective-callback-taskname-length.yml
+ - 7375-fix-github-deploy-key-pagination.yml
+ - 7377-proxmox-kvm-deprecate-flag.yml
+ - 7378-redhat_subscription-dbus-consumer-type.yaml
+ - 7379-url.yml
+ - 7382-kernel-blacklist-bugfix.yml
+ - 7392-lxd-inventory-server-cert.yml
+ - 7396-fix-apt_rpm-local-rpm-installation.yml
+ - 7399-cloudflare_dns-add-CAA-record-support.yml
+ - 7401-ini-file-modify-inactive-option.yaml
+ - 7412-add-port-for-nomad-connection.yaml
+ - 7452-fix-icinga2_host-requiring-ip-key.yml
+ - 8.0.0.yml
+ - ansible-core-2.11-2.12.yml
+ - get-secret-by-path.yml
+ - improvements-to-jenkins-build-module.yml
+ - ini_file-preserve-symlink.yml
+ - ini_file-use-inactive-options-when-possible.yml
+ - lvol-pct-of-origin.yml
+ - removals.yml
+ - update-v2-pagerduty-alert.yml
modules:
- - description: Scaleway Container management
- name: scaleway_container
+ - description: Manipulate Consul policies
+ name: consul_policy
namespace: ''
- - description: Retrieve information on Scaleway Container
- name: scaleway_container_info
+ - description: Manipulate Consul roles
+ name: consul_role
namespace: ''
- - description: Scaleway Container namespace management
- name: scaleway_container_namespace
+ - description: Runs the discovery program C(facter) on the remote system and return
+ Ansible facts
+ name: facter_facts
namespace: ''
- - description: Retrieve information on Scaleway Container namespace
- name: scaleway_container_namespace_info
+ - description: Set default handler for MIME type, for applications using Gnome
+ GIO
+ name: gio_mime
namespace: ''
- - description: Scaleway Function management
- name: scaleway_function
+ - description: Creates, updates, or deletes GitLab instance variables
+ name: gitlab_instance_variable
namespace: ''
- - description: Retrieve information on Scaleway Function
- name: scaleway_function_info
+ - description: Create, update, or delete GitLab merge requests
+ name: gitlab_merge_request
namespace: ''
- release_date: '2022-11-07'
- 6.0.0-a1:
- changes:
- breaking_changes:
- - newrelic_deployment - ``revision`` is required for v2 API (https://github.com/ansible-collections/community.general/pull/5341).
- bugfixes:
- - Include ``PSF-license.txt`` file for ``plugins/module_utils/_mount.py``.
- - Include ``simplified_bsd.txt`` license file for various module utils, the
- ``lxca_common`` docs fragment, and the ``utm_utils`` unit tests.
- - alternatives - do not set the priority if the priority was not set by the
- user (https://github.com/ansible-collections/community.general/pull/4810).
- - alternatives - only pass subcommands when they are specified as module arguments
- (https://github.com/ansible-collections/community.general/issues/4803, https://github.com/ansible-collections/community.general/issues/4804,
- https://github.com/ansible-collections/community.general/pull/4836).
- - alternatives - when ``subcommands`` is specified, ``link`` must be given for
- every subcommand. This was already mentioned in the documentation, but not
- enforced by the code (https://github.com/ansible-collections/community.general/pull/4836).
- - apache2_mod_proxy - avoid crash when reporting inability to parse balancer_member_page
- HTML caused by using an undefined variable in the error message (https://github.com/ansible-collections/community.general/pull/5111).
- - archive - avoid crash when ``lzma`` is not present and ``format`` is not ``xz``
- (https://github.com/ansible-collections/community.general/pull/5393).
- - cmd_runner module utils - fix bug caused by using the ``command`` variable
- instead of ``self.command`` when looking for binary path (https://github.com/ansible-collections/community.general/pull/4903).
- - consul - fixed bug introduced in PR 4590 (https://github.com/ansible-collections/community.general/issues/4680).
- - credstash lookup plugin - pass plugin options to credstash for all terms,
- not just for the first (https://github.com/ansible-collections/community.general/pull/5440).
- - dig lookup plugin - add option to return empty result without empty strings,
- and return empty list instead of ``NXDOMAIN`` (https://github.com/ansible-collections/community.general/pull/5439,
- https://github.com/ansible-collections/community.general/issues/5428).
- - dig lookup plugin - fix evaluation of falsy values for boolean parameters
- ``fail_on_error`` and ``retry_servfail`` (https://github.com/ansible-collections/community.general/pull/5129).
- - dnsimple_info - correctly report missing library as ``requests`` and not ``another_library``
- (https://github.com/ansible-collections/community.general/pull/5111).
- - dnstxt lookup plugin - add option to return empty result without empty strings,
- and return empty list instead of ``NXDOMAIN`` (https://github.com/ansible-collections/community.general/pull/5457,
- https://github.com/ansible-collections/community.general/issues/5428).
- - dsv lookup plugin - do not ignore the ``tld`` parameter (https://github.com/ansible-collections/community.general/pull/4911).
- - filesystem - handle ``fatresize --info`` output lines without ``:`` (https://github.com/ansible-collections/community.general/pull/4700).
- - filesystem - improve error messages when output cannot be parsed by including
- newlines in escaped form (https://github.com/ansible-collections/community.general/pull/4700).
- - funcd connection plugin - fix signature of ``exec_command`` (https://github.com/ansible-collections/community.general/pull/5111).
- - ini_file - minor refactor fixing a python lint error (https://github.com/ansible-collections/community.general/pull/5307).
- - keycloak_realm - fix default groups and roles (https://github.com/ansible-collections/community.general/issues/4241).
- - keyring_info - fix the result from the keyring library never getting returned
- (https://github.com/ansible-collections/community.general/pull/4964).
- - ldap_attrs - fix ordering issue by ignoring the ``{x}`` prefix on attribute
- values (https://github.com/ansible-collections/community.general/issues/977,
- https://github.com/ansible-collections/community.general/pull/5385).
- - listen_ports_facts - removed leftover ``EnvironmentError`` . The ``else``
- clause had a wrong indentation. The check is now handled in the ``split_pid_name``
- function (https://github.com/ansible-collections/community.general/pull/5202).
- - locale_gen - fix support for Ubuntu (https://github.com/ansible-collections/community.general/issues/5281).
- - lxc_container - the module has been updated to support Python 3 (https://github.com/ansible-collections/community.general/pull/5304).
- - lxd connection plugin - fix incorrect ``inventory_hostname`` in ``remote_addr``.
- This is needed for compatibility with ansible-core 2.13 (https://github.com/ansible-collections/community.general/issues/4886).
- - manageiq_alert_profiles - avoid crash when reporting unknown profile caused
- by trying to return an undefined variable (https://github.com/ansible-collections/community.general/pull/5111).
- - nmcli - avoid changed status for most cases with VPN connections (https://github.com/ansible-collections/community.general/pull/5126).
- - nmcli - fix error caused by adding undefined module arguments for list options
- (https://github.com/ansible-collections/community.general/issues/4373, https://github.com/ansible-collections/community.general/pull/4813).
- - 'nmcli - fix error when setting previously unset MAC address, ``gsm.apn``
- or ``vpn.data``: current values were being normalized without checking if
- they might be ``None`` (https://github.com/ansible-collections/community.general/pull/5291).'
- - nmcli - fix int options idempotence (https://github.com/ansible-collections/community.general/issues/4998).
- - nsupdate - compatibility with NS records (https://github.com/ansible-collections/community.general/pull/5112).
- - nsupdate - fix silent failures when updating ``NS`` entries from Bind9 managed
- DNS zones (https://github.com/ansible-collections/community.general/issues/4657).
- - opentelemetry callback plugin - support opentelemetry-api 1.13.0 that removed
- support for ``_time_ns`` (https://github.com/ansible-collections/community.general/pull/5342).
- - osx_defaults - no longer expand ``~`` in ``value`` to the user's home directory,
- or expand environment variables (https://github.com/ansible-collections/community.general/issues/5234,
- https://github.com/ansible-collections/community.general/pull/5243).
- - packet_ip_subnet - fix error reporting in case of invalid CIDR prefix lengths
- (https://github.com/ansible-collections/community.general/pull/5111).
- - pacman - fixed name resolution of URL packages (https://github.com/ansible-collections/community.general/pull/4959).
- - passwordstore lookup plugin - fix ``returnall`` for gopass (https://github.com/ansible-collections/community.general/pull/5027).
- - passwordstore lookup plugin - fix password store path detection for gopass
- (https://github.com/ansible-collections/community.general/pull/4955).
- - pfexec become plugin - remove superflous quotes preventing exe wrap from working
- as expected (https://github.com/ansible-collections/community.general/issues/3671,
- https://github.com/ansible-collections/community.general/pull/3889).
- - pip_package_info - remove usage of global variable (https://github.com/ansible-collections/community.general/pull/5111).
- - pkgng - fix case when ``pkg`` fails when trying to upgrade all packages (https://github.com/ansible-collections/community.general/issues/5363).
- - proxmox - fix error handling when getting VM by name when ``state=absent``
- (https://github.com/ansible-collections/community.general/pull/4945).
- - proxmox inventory plugin - fix crash when ``enabled=1`` is used in agent config
- string (https://github.com/ansible-collections/community.general/pull/4910).
- - proxmox inventory plugin - fixed extended status detection for qemu (https://github.com/ansible-collections/community.general/pull/4816).
- - proxmox_kvm - fix ``agent`` parameter when boolean value is specified (https://github.com/ansible-collections/community.general/pull/5198).
- - proxmox_kvm - fix error handling when getting VM by name when ``state=absent``
- (https://github.com/ansible-collections/community.general/pull/4945).
- - proxmox_kvm - fix exception when no ``agent`` argument is specified (https://github.com/ansible-collections/community.general/pull/5194).
- - proxmox_kvm - fix wrong condition (https://github.com/ansible-collections/community.general/pull/5108).
- - proxmox_kvm - replace new condition with proper condition to allow for using
- ``vmid`` on update (https://github.com/ansible-collections/community.general/pull/5206).
- - rax_clb_nodes - fix code to be compatible with Python 3 (https://github.com/ansible-collections/community.general/pull/4933).
- - redfish_command - fix the check if a virtual media is unmounted to just check
- for ``instered= false`` caused by Supermicro hardware that does not clear
- the ``ImageName`` (https://github.com/ansible-collections/community.general/pull/4839).
- - redfish_command - the Supermicro Redfish implementation only supports the
- ``image_url`` parameter in the underlying API calls to ``VirtualMediaInsert``
- and ``VirtualMediaEject``. Any values set (or the defaults) for ``write_protected``
- or ``inserted`` will be ignored (https://github.com/ansible-collections/community.general/pull/4839).
- - redfish_info - fix to ``GetChassisPower`` to correctly report power information
- when multiple chassis exist, but not all chassis report power information
- (https://github.com/ansible-collections/community.general/issues/4901).
- - redfish_utils module utils - centralize payload checking when performing modification
- requests to a Redfish service (https://github.com/ansible-collections/community.general/issues/5210/).
- - redhat_subscription - fix unsubscribing on RHEL 9 (https://github.com/ansible-collections/community.general/issues/4741).
- - redhat_subscription - make module idempotent when ``pool_ids`` are used (https://github.com/ansible-collections/community.general/issues/5313).
- - redis* modules - fix call to ``module.fail_json`` when failing because of
- missing Python libraries (https://github.com/ansible-collections/community.general/pull/4733).
- - slack - fix incorrect channel prefix ``#`` caused by incomplete pattern detection
- by adding ``G0`` and ``GF`` as channel ID patterns (https://github.com/ansible-collections/community.general/pull/5019).
- - slack - fix message update for channels which start with ``CP``. When ``message-id``
- was passed it failed for channels which started with ``CP`` because the ``#``
- symbol was added before the ``channel_id`` (https://github.com/ansible-collections/community.general/pull/5249).
- - sudoers - ensure sudoers config files are created with the permissions requested
- by sudoers (0440) (https://github.com/ansible-collections/community.general/pull/4814).
- - 'sudoers - fix incorrect handling of ``state: absent`` (https://github.com/ansible-collections/community.general/issues/4852).'
- - tss lookup plugin - adding support for updated Delinea library (https://github.com/DelineaXPM/python-tss-sdk/issues/9,
- https://github.com/ansible-collections/community.general/pull/5151).
- - virtualbox inventory plugin - skip parsing values with keys that have both
- a value and nested data. Skip parsing values that are nested more than two
- keys deep (https://github.com/ansible-collections/community.general/issues/5332,
- https://github.com/ansible-collections/community.general/pull/5348).
- - xcc_redfish_command - for compatibility due to Redfish spec changes the virtualMedia
- resource location changed from Manager to System (https://github.com/ansible-collections/community.general/pull/4682).
- - xenserver_facts - fix broken ``AnsibleModule`` call that prevented the module
- from working at all (https://github.com/ansible-collections/community.general/pull/5383).
- - xfconf - fix setting of boolean values (https://github.com/ansible-collections/community.general/issues/4999,
- https://github.com/ansible-collections/community.general/pull/5007).
- - zfs - fix wrong quoting of properties (https://github.com/ansible-collections/community.general/issues/4707,
- https://github.com/ansible-collections/community.general/pull/4726).
- deprecated_features:
- - ArgFormat module utils - deprecated along ``CmdMixin``, in favor of the ``cmd_runner_fmt``
- module util (https://github.com/ansible-collections/community.general/pull/5370).
- - CmdMixin module utils - deprecated in favor of the ``CmdRunner`` module util
- (https://github.com/ansible-collections/community.general/pull/5370).
- - CmdModuleHelper module utils - deprecated in favor of the ``CmdRunner`` module
- util (https://github.com/ansible-collections/community.general/pull/5370).
- - CmdStateModuleHelper module utils - deprecated in favor of the ``CmdRunner``
- module util (https://github.com/ansible-collections/community.general/pull/5370).
- - cmd_runner module utils - deprecated ``fmt`` in favour of ``cmd_runner_fmt``
- as the parameter format object (https://github.com/ansible-collections/community.general/pull/4777).
- - django_manage - support for Django releases older than 4.1 has been deprecated
- and will be removed in community.general 9.0.0 (https://github.com/ansible-collections/community.general/pull/5400).
- - django_manage - support for the commands ``cleanup``, ``syncdb`` and ``validate``
- that have been deprecated in Django long time ago will be removed in community.general
- 9.0.0 (https://github.com/ansible-collections/community.general/pull/5400).
- - django_manage - the behavior of "creating the virtual environment when missing"
- is being deprecated and will be removed in community.general version 9.0.0
- (https://github.com/ansible-collections/community.general/pull/5405).
- - gconftool2 - deprecates ``state=get`` in favor of using the module ``gconftool2_info``
- (https://github.com/ansible-collections/community.general/pull/4778).
- - lxc_container - the module will no longer make any effort to support Python
- 2 (https://github.com/ansible-collections/community.general/pull/5304).
- - newrelic_deployment - ``appname`` and ``environment`` are no longer valid
- options in the v2 API. They will be removed in community.general 7.0.0 (https://github.com/ansible-collections/community.general/pull/5341).
- - proxmox - deprecated the current ``unprivileged`` default value, will be changed
- to ``true`` in community.general 7.0.0 (https://github.com/pull/5224).
- - xfconf - deprecated parameter ``disable_facts``, as since version 4.0.0 it
- only allows value ``true`` (https://github.com/ansible-collections/community.general/pull/4520).
- major_changes:
- - The internal structure of the collection was changed for modules and action
- plugins. These no longer live in a directory hierarchy ordered by topic, but
- instead are now all in a single (flat) directory. This has no impact on users
- *assuming they did not use internal FQCNs*. These will still work, but result
- in deprecation warnings. They were never officially supported and thus the
- redirects are kept as a courtsey, and this is not labelled as a breaking change.
- Note that for example the Ansible VScode plugin started recommending these
- internal names. If you followed its recommendation, you will now have to change
- back to the short names to avoid deprecation warnings, and potential errors
- in the future as these redirects will be removed in community.general 9.0.0
- (https://github.com/ansible-collections/community.general/pull/5461).
- - newrelic_deployment - removed New Relic v1 API, added support for v2 API (https://github.com/ansible-collections/community.general/pull/5341).
- minor_changes:
- - Added MIT license as ``LICENSES/MIT.txt`` for tests/unit/plugins/modules/packaging/language/test_gem.py
- (https://github.com/ansible-collections/community.general/pull/5065).
- - All software licenses are now in the ``LICENSES/`` directory of the collection
- root (https://github.com/ansible-collections/community.general/pull/5065,
- https://github.com/ansible-collections/community.general/pull/5079, https://github.com/ansible-collections/community.general/pull/5080,
- https://github.com/ansible-collections/community.general/pull/5083, https://github.com/ansible-collections/community.general/pull/5087,
- https://github.com/ansible-collections/community.general/pull/5095, https://github.com/ansible-collections/community.general/pull/5098,
- https://github.com/ansible-collections/community.general/pull/5106).
- - ModuleHelper module utils - added property ``verbosity`` to base class (https://github.com/ansible-collections/community.general/pull/5035).
- - ModuleHelper module utils - improved ``ModuleHelperException``, using ``to_native()``
- for the exception message (https://github.com/ansible-collections/community.general/pull/4755).
- - The collection repository conforms to the `REUSE specification <https://reuse.software/spec/>`__
- except for the changelog fragments (https://github.com/ansible-collections/community.general/pull/5138).
- - ali_instance - minor refactor when checking for installed dependency (https://github.com/ansible-collections/community.general/pull/5240).
- - ali_instance_info - minor refactor when checking for installed dependency
- (https://github.com/ansible-collections/community.general/pull/5240).
- - alternatives - add ``state=absent`` to be able to remove an alternative (https://github.com/ansible-collections/community.general/pull/4654).
- - alternatives - add ``subcommands`` parameter (https://github.com/ansible-collections/community.general/pull/4654).
- - ansible_galaxy_install - minor refactoring using latest ``ModuleHelper`` updates
- (https://github.com/ansible-collections/community.general/pull/4752).
- - apk - add ``world`` parameter for supporting a custom world file (https://github.com/ansible-collections/community.general/pull/4976).
- - bitwarden lookup plugin - add option ``search`` to search for other attributes
- than name (https://github.com/ansible-collections/community.general/pull/5297).
- - cartesian lookup plugin - start using Ansible's configuration manager to parse
- options (https://github.com/ansible-collections/community.general/pull/5440).
- - cmd_runner module util - added parameters ``check_mode_skip`` and ``check_mode_return``
- to ``CmdRunner.context()``, so that the command is not executed when ``check_mode=True``
- (https://github.com/ansible-collections/community.general/pull/4736).
- - cmd_runner module utils - add ``__call__`` method to invoke context (https://github.com/ansible-collections/community.general/pull/4791).
- - consul - adds ``ttl`` parameter for session (https://github.com/ansible-collections/community.general/pull/4996).
- - consul - minor refactoring (https://github.com/ansible-collections/community.general/pull/5367).
- - consul_session - adds ``token`` parameter for session (https://github.com/ansible-collections/community.general/pull/5193).
- - cpanm - using ``do_raise()`` to raise exceptions in ``ModuleHelper`` derived
- modules (https://github.com/ansible-collections/community.general/pull/4674).
- - credstash lookup plugin - start using Ansible's configuration manager to parse
- options (https://github.com/ansible-collections/community.general/pull/5440).
- - dependent lookup plugin - start using Ansible's configuration manager to parse
- options (https://github.com/ansible-collections/community.general/pull/5440).
- - dig lookup plugin - add option ``fail_on_error`` to allow stopping execution
- on lookup failures (https://github.com/ansible-collections/community.general/pull/4973).
- - dig lookup plugin - start using Ansible's configuration manager to parse options.
- All documented options can now also be passed as lookup parameters (https://github.com/ansible-collections/community.general/pull/5440).
- - dnstxt lookup plugin - start using Ansible's configuration manager to parse
- options (https://github.com/ansible-collections/community.general/pull/5440).
- - filetree lookup plugin - start using Ansible's configuration manager to parse
- options (https://github.com/ansible-collections/community.general/pull/5440).
- - flattened lookup plugin - start using Ansible's configuration manager to parse
- options (https://github.com/ansible-collections/community.general/pull/5440).
- - gitlab module util - minor refactor when checking for installed dependency
- (https://github.com/ansible-collections/community.general/pull/5259).
- - gitlab_branch - minor refactor when checking for installed dependency (https://github.com/ansible-collections/community.general/pull/5259).
- - gitlab_deploy_key - minor refactor when checking for installed dependency
- (https://github.com/ansible-collections/community.general/pull/5259).
- - gitlab_group - minor refactor when checking for installed dependency (https://github.com/ansible-collections/community.general/pull/5259).
- - gitlab_group_members - minor refactor when checking for installed dependency
- (https://github.com/ansible-collections/community.general/pull/5259).
- - gitlab_group_variable - minor refactor when checking for installed dependency
- (https://github.com/ansible-collections/community.general/pull/5259).
- - gitlab_hook - minor refactor when checking for installed dependency (https://github.com/ansible-collections/community.general/pull/5259).
- - gitlab_hook - minor refactoring (https://github.com/ansible-collections/community.general/pull/5271).
- - gitlab_project - minor refactor when checking for installed dependency (https://github.com/ansible-collections/community.general/pull/5259).
- - gitlab_project_members - minor refactor when checking for installed dependency
- (https://github.com/ansible-collections/community.general/pull/5259).
- - gitlab_project_variable - minor refactor when checking for installed dependency
- (https://github.com/ansible-collections/community.general/pull/5259).
- - gitlab_protected_branch - minor refactor when checking for installed dependency
- (https://github.com/ansible-collections/community.general/pull/5259).
- - gitlab_runner - minor refactor when checking for installed dependency (https://github.com/ansible-collections/community.general/pull/5259).
- - gitlab_user - minor refactor when checking for installed dependency (https://github.com/ansible-collections/community.general/pull/5259).
- - hiera lookup plugin - start using Ansible's configuration manager to parse
- options. The Hiera executable and config file can now also be passed as lookup
- parameters (https://github.com/ansible-collections/community.general/pull/5440).
- - homebrew, homebrew_tap - added Homebrew on Linux path to defaults (https://github.com/ansible-collections/community.general/pull/5241).
- - keycloak_* modules - add ``http_agent`` parameter with default value ``Ansible``
- (https://github.com/ansible-collections/community.general/issues/5023).
- - keyring lookup plugin - start using Ansible's configuration manager to parse
- options (https://github.com/ansible-collections/community.general/pull/5440).
- - lastpass - use config manager for handling plugin options (https://github.com/ansible-collections/community.general/pull/5022).
- - linode inventory plugin - simplify option handling (https://github.com/ansible-collections/community.general/pull/5438).
- - listen_ports_facts - add new ``include_non_listening`` option which adds ``-a``
- option to ``netstat`` and ``ss``. This shows both listening and non-listening
- (for TCP this means established connections) sockets, and returns ``state``
- and ``foreign_address`` (https://github.com/ansible-collections/community.general/issues/4762,
- https://github.com/ansible-collections/community.general/pull/4953).
- - lmdb_kv lookup plugin - start using Ansible's configuration manager to parse
- options (https://github.com/ansible-collections/community.general/pull/5440).
- - lxc_container - minor refactoring (https://github.com/ansible-collections/community.general/pull/5358).
- - machinectl become plugin - can now be used with a password from another user
- than root, if a polkit rule is present (https://github.com/ansible-collections/community.general/pull/4849).
- - machinectl become plugin - combine the success command when building the become
- command to be consistent with other become plugins (https://github.com/ansible-collections/community.general/pull/5287).
- - manifold lookup plugin - start using Ansible's configuration manager to parse
- options (https://github.com/ansible-collections/community.general/pull/5440).
- - maven_artifact - add a new ``unredirected_headers`` option that can be used
- with ansible-core 2.12 and above. The default value is to not use ``Authorization``
- and ``Cookie`` headers on redirects for security reasons. With ansible-core
- 2.11, all headers are still passed on for redirects (https://github.com/ansible-collections/community.general/pull/4812).
- - mksysb - using ``do_raise()`` to raise exceptions in ``ModuleHelper`` derived
- modules (https://github.com/ansible-collections/community.general/pull/4674).
- - nagios - minor refactoring on parameter validation for different actions (https://github.com/ansible-collections/community.general/pull/5239).
- - netcup_dnsapi - add ``timeout`` parameter (https://github.com/ansible-collections/community.general/pull/5301).
- - nmcli - add ``transport_mode`` configuration for Infiniband devices (https://github.com/ansible-collections/community.general/pull/5361).
- - nmcli - add bond option ``xmit_hash_policy`` to bond options (https://github.com/ansible-collections/community.general/issues/5148).
- - nmcli - adds ``vpn`` type and parameter for supporting VPN with service type
- L2TP and PPTP (https://github.com/ansible-collections/community.general/pull/4746).
- - nmcli - honor IP options for VPNs (https://github.com/ansible-collections/community.general/pull/5228).
- - opentelemetry callback plugin - allow configuring opentelementry callback
- via config file (https://github.com/ansible-collections/community.general/pull/4916).
- - opentelemetry callback plugin - send logs. This can be disabled by setting
- ``disable_logs=false`` (https://github.com/ansible-collections/community.general/pull/4175).
- - pacman - added parameters ``reason`` and ``reason_for`` to set/change the
- install reason of packages (https://github.com/ansible-collections/community.general/pull/4956).
- - passwordstore lookup plugin - allow options to be passed lookup options instead
- of being part of the term strings (https://github.com/ansible-collections/community.general/pull/5444).
- - passwordstore lookup plugin - allow using alternative password managers by
- detecting wrapper scripts, allow explicit configuration of pass and gopass
- backends (https://github.com/ansible-collections/community.general/issues/4766).
- - passwordstore lookup plugin - improve error messages to include stderr (https://github.com/ansible-collections/community.general/pull/5436)
- - pipx - added state ``latest`` to the module (https://github.com/ansible-collections/community.general/pull/5105).
- - pipx - changed implementation to use ``cmd_runner`` (https://github.com/ansible-collections/community.general/pull/5085).
- - pipx - module fails faster when ``name`` is missing for states ``upgrade``
- and ``reinstall`` (https://github.com/ansible-collections/community.general/pull/5100).
- - pipx - using ``do_raise()`` to raise exceptions in ``ModuleHelper`` derived
- modules (https://github.com/ansible-collections/community.general/pull/4674).
- - pipx module utils - created new module util ``pipx`` providing a ``cmd_runner``
- specific for the ``pipx`` module (https://github.com/ansible-collections/community.general/pull/5085).
- - portage - add knobs for Portage's ``--backtrack`` and ``--with-bdeps`` options
- (https://github.com/ansible-collections/community.general/pull/5349).
- - portage - use Portage's python module instead of calling gentoolkit-provided
- program in shell (https://github.com/ansible-collections/community.general/pull/5349).
- - proxmox inventory plugin - added new flag ``qemu_extended_statuses`` and new
- groups ``<group_prefix>prelaunch``, ``<group_prefix>paused``. They will be
- populated only when ``want_facts=true``, ``qemu_extended_statuses=true`` and
- only for ``QEMU`` machines (https://github.com/ansible-collections/community.general/pull/4723).
- - proxmox inventory plugin - simplify option handling code (https://github.com/ansible-collections/community.general/pull/5437).
- - proxmox module utils, the proxmox* modules - add ``api_task_ok`` helper to
- standardize API task status checks across all proxmox modules (https://github.com/ansible-collections/community.general/pull/5274).
- - proxmox_kvm - allow ``agent`` argument to be a string (https://github.com/ansible-collections/community.general/pull/5107).
- - proxmox_snap - add ``unbind`` param to support snapshotting containers with
- configured mountpoints (https://github.com/ansible-collections/community.general/pull/5274).
- - puppet - adds ``confdir`` parameter to configure a custom confir location
- (https://github.com/ansible-collections/community.general/pull/4740).
- - redfish - added new command GetVirtualMedia, VirtualMediaInsert and VirtualMediaEject
- to Systems category due to Redfish spec changes the virtualMedia resource
- location from Manager to System (https://github.com/ansible-collections/community.general/pull/5124).
- - redfish_config - add ``SetSessionService`` to set default session timeout
- policy (https://github.com/ansible-collections/community.general/issues/5008).
- - redfish_info - add ``GetManagerInventory`` to report list of Manager inventory
- information (https://github.com/ansible-collections/community.general/issues/4899).
- - seport - added new argument ``local`` (https://github.com/ansible-collections/community.general/pull/5203)
- - snap - using ``do_raise()`` to raise exceptions in ``ModuleHelper`` derived
- modules (https://github.com/ansible-collections/community.general/pull/4674).
- - sudoers - will attempt to validate the proposed sudoers rule using visudo
- if available, optionally skipped, or required (https://github.com/ansible-collections/community.general/pull/4794,
- https://github.com/ansible-collections/community.general/issues/4745).
- - terraform - adds capability to handle complex variable structures for ``variables``
- parameter in the module. This must be enabled with the new ``complex_vars``
- parameter (https://github.com/ansible-collections/community.general/pull/4797).
- - terraform - run ``terraform init`` with ``-no-color`` not to mess up the stdout
- of the task (https://github.com/ansible-collections/community.general/pull/5147).
- - wdc_redfish_command - add ``IndicatorLedOn`` and ``IndicatorLedOff`` commands
- for ``Chassis`` category (https://github.com/ansible-collections/community.general/pull/5059).
- - wdc_redfish_command - add ``PowerModeLow`` and ``PowerModeNormal`` commands
- for ``Chassis`` category (https://github.com/ansible-collections/community.general/pull/5145).
- - xfconf - add ``stdout``, ``stderr`` and ``cmd`` to the module results (https://github.com/ansible-collections/community.general/pull/5037).
- - xfconf - changed implementation to use ``cmd_runner`` (https://github.com/ansible-collections/community.general/pull/4776).
- - xfconf - use ``do_raise()`` instead of defining custom exception class (https://github.com/ansible-collections/community.general/pull/4975).
- - xfconf - using ``do_raise()`` to raise exceptions in ``ModuleHelper`` derived
- modules (https://github.com/ansible-collections/community.general/pull/4674).
- - xfconf module utils - created new module util ``xfconf`` providing a ``cmd_runner``
- specific for ``xfconf`` modules (https://github.com/ansible-collections/community.general/pull/4776).
- - xfconf_info - changed implementation to use ``cmd_runner`` (https://github.com/ansible-collections/community.general/pull/4776).
- - xfconf_info - use ``do_raise()`` instead of defining custom exception class
- (https://github.com/ansible-collections/community.general/pull/4975).
- - znode - possibility to use ZooKeeper ACL authentication (https://github.com/ansible-collections/community.general/pull/5306).
- release_summary: This is a pre-release for the upcoming 6.0.0 major release.
- The main objective of this pre-release is to make it possible to test the
- large stuctural changes by flattening the directory structure. See the corresponding
- entry in the changelog for details.
- removed_features:
- - bitbucket* modules - ``username`` is no longer an alias of ``workspace``,
- but of ``user`` (https://github.com/ansible-collections/community.general/pull/5326).
- - gem - the default of the ``norc`` option changed from ``false`` to ``true``
- (https://github.com/ansible-collections/community.general/pull/5326).
- - gitlab_group_members - ``gitlab_group`` must now always contain the full path,
- and no longer just the name or path (https://github.com/ansible-collections/community.general/pull/5326).
- - keycloak_authentication - the return value ``flow`` has been removed. Use
- ``end_state`` instead (https://github.com/ansible-collections/community.general/pull/5326).
- - keycloak_group - the return value ``group`` has been removed. Use ``end_state``
- instead (https://github.com/ansible-collections/community.general/pull/5326).
- - lxd_container - the default of the ``ignore_volatile_options`` option changed
- from ``true`` to ``false`` (https://github.com/ansible-collections/community.general/pull/5326).
- - mail callback plugin - the ``sender`` option is now required (https://github.com/ansible-collections/community.general/pull/5326).
- - module_helper module utils - remove the ``VarDict`` attribute from ``ModuleHelper``.
- Import ``VarDict`` from ``ansible_collections.community.general.plugins.module_utils.mh.mixins.vars``
- instead (https://github.com/ansible-collections/community.general/pull/5326).
- - proxmox inventory plugin - the default of the ``want_proxmox_nodes_ansible_host``
- option changed from ``true`` to ``false`` (https://github.com/ansible-collections/community.general/pull/5326).
- - vmadm - the ``debug`` option has been removed. It was not used anyway (https://github.com/ansible-collections/community.general/pull/5326).
- fragments:
- - 3671-illumos-pfexec.yml
- - 4175-opentelemetry_logs.yml
- - 4520-xfconf-deprecate-disable-facts.yml
- - 4654-alternatives-add-subcommands.yml
- - 4674-use-mh-raise.yaml
- - 4682-compatibility-virtualmedia-resource-location.yaml
- - 4700-code-changes.yml
- - 4712-consul-bugfix.yaml
- - 4719-fix-keycloak-realm.yaml
- - 4724-proxmox-qemu-extend.yaml
- - 4726-zfs.yml
- - 4733-redis-fail.yml
- - 4736-cmd-runner-skip-if-check.yml
- - 4740-puppet-feature.yaml
- - 4746-add-vpn-support-nmcli.yaml
- - 4752-ansible-galaxy-install-mh-updates.yml
- - 4755-mhexception-improvement.yml
- - 4776-xfconf-cmd-runner.yaml
- - 4777-cmd-runner-deprecate-fmt.yaml
- - 4778-gconftool2-deprecate-state-get.yaml
- - 4780-passwordstore-wrapper-compat.yml
- - 4791-cmd-runner-callable.yaml
- - 4794-sudoers-validation.yml
- - 4797-terraform-complex-variables.yml
- - 4809-redhat_subscription-unsubscribe.yaml
- - 4810-alternatives-bug.yml
- - 4812-expose-unredirected-headers.yml
- - 4813-fix-nmcli-convert-list.yaml
- - 4814-sudoers-file-permissions.yml
- - 4816-proxmox-fix-extended-status.yaml
- - 4836-alternatives.yml
- - 4839-fix-VirtualMediaInsert-Supermicro.yml
- - 4849-add-password-prompt-support-for-machinectl.yml
- - 4852-sudoers-state-absent.yml
- - 4886-fix-lxd-inventory-hostname.yml
- - 4899-add-GetManagerInventory-for-redfish_info.yml
- - 4901-fix-redfish-chassispower.yml
- - 4903-cmdrunner-bugfix.yaml
- - 4910-fix-for-agent-enabled.yml
- - 4911-dsv-honor-tld-option.yml
- - 4916-opentelemetry-ini-options.yaml
- - 4933-fix-rax-clb-nodes.yaml
- - 4945-fix-get_vm-int-parse-handling.yaml
- - 4953-listen-ports-facts-extend-output.yaml
- - 4955-fix-path-detection-for-gopass.yaml
- - 4956-pacman-install-reason.yaml
- - 4959-pacman-fix-url-packages-name.yaml
- - 4964-fix-keyring-info.yml
- - 4973-introduce-dig-lookup-argument.yaml
- - 4975-xfconf-use-do-raise.yaml
- - 4976-apk-add-support-for-a-custom-world-file.yaml
- - 4996-consul-session-ttl.yml
- - 4998-nmcli-fix-int-options-idempotence.yml
- - 4999-xfconf-bool.yml
- - 5008-addSetSessionService.yml
- - 5019-slack-support-more-groups.yml
- - 5022-lastpass-lookup-cleanup.yml
- - 5023-http-agent-param-keycloak.yml
- - 5027-fix-returnall-for-gopass.yaml
- - 5035-mh-base-verbosity.yaml
- - 5037-xfconf-add-cmd-output.yaml
- - 5059-wdc_redfish_command-indicator-leds.yml
- - 5085-pipx-use-cmd-runner.yaml
- - 5100-pipx-req-if.yaml
- - 5105-pipx-state-latest.yaml
- - 5107-proxmox-agent-argument.yaml
- - 5108-proxmox-node-name-condition.yml
- - 5111-fixes.yml
- - 5112-fix-nsupdate-ns-entry.yaml
- - 5124-compatibility-virtualmedia-resource-location.yaml
- - 5126-nmcli-remove-diffs.yml
- - 5129-dig-boolean-params-fix.yml
- - 5145-wdc-redfish-enclosure-power-state.yml
- - 5147-terraform-init-no-color.yml
- - 5149-nmcli-bond-option.yml
- - 5151-add-delinea-support-tss-lookup.yml
- - 5193-consul-session-token.yaml
- - 5194-fix-proxmox-agent-exception.yaml
- - 5198-proxmox.yml
- - 5202-bugfix-environmentError-wrong-indentation.yaml
- - 5203-seport-add-local-argument.yaml
- - 5206-proxmox-conditional-vmid.yml
- - 5210-redfish_utils-cleanup-of-configuration-logic-and-oem-checks.yaml
- - 5224-proxmox-unprivileged-default.yaml
- - 5228-nmcli-ip-options.yaml
- - 5239-nagios-refactor.yaml
- - 5240-unused-imports.yaml
- - 5241-homebrew-add-linux-path.yaml
- - 5243-osx-defaults-expand-user-flags.yml
- - 5249-add-new-channel-prefix.yml
- - 5259-gitlab-imports.yaml
- - 5271-gitlab_hook-refactor.yaml
- - 5274-proxmox-snap-container-with-mountpoints.yml
- - 5280-lxc_container-py3.yaml
- - 5282-locale_gen.yaml
- - 5287-machinectl-become-success.yml
- - 5291-fix-nmcli-error-when-setting-unset-mac-address.yaml
- - 5297-bitwarden-add-search-field.yml
- - 5301-netcup_dnsapi-timeout.yml
- - 5306-add-options-for-authentication.yml
- - 5307-ini_file-lint.yaml
- - 5313-fix-redhat_subscription-idempotency-pool_ids.yml
- - 5341-newrelic-v2-api-changes.yml
- - 5342-opentelemetry_bug_fix_opentelemetry-api-1.13.yml
- - 5348-fix-vbox-deeply-nested-hostvars.yml
- - 5349-drop-gentoolkit-more-knobs.yml
- - 5358-lxc-container-refactor.yml
- - 5361-nmcli-add-infiniband-transport-mode.yaml
- - 5367-consul-refactor.yaml
- - 5369-pkgng-fix-update-all.yaml
- - 5370-mh-cmdmixin-deprecation.yaml
- - 5377-nsupdate-ns-records-with-bind.yml
- - 5383-xenserver_facts.yml
- - 5385-search_s-based-_is_value_present.yaml
- - 5393-archive.yml
- - 5400-django-manage-deprecations.yml
- - 5404-django-manage-venv-deprecation.yml
- - 5436-passwordstore-errors.yml
- - 5437-proxmox.yml
- - 5438-linode.yml
- - 5439-dig-return-empty-result.yml
- - 5444-passwordstore-options.yml
- - 5457-dnstxt-empty.yml
- - 6.0.0-a1.yml
- - deprecation-removals.yml
- - licenses-2.yml
- - licenses.yml
- - lookup-options.yml
- - psf-license.yml
- - simplified-bsd-license.yml
- - unflatmap.yml
- modules:
- - description: Retrieve GConf configurations
- name: gconftool2_info
- namespace: ''
- - description: Add/remove/change files in ISO file
- name: iso_customize
- namespace: ''
- - description: Allows administration of Keycloak user_rolemapping with the Keycloak
- API
- name: keycloak_user_rolemapping
- namespace: ''
- - description: Set or delete a passphrase using the Operating System's native
- keyring
- name: keyring
+ - description: Get information about Jenkins builds
+ name: jenkins_build_info
namespace: ''
- - description: Get a passphrase using the Operating System's native keyring
- name: keyring_info
+ - description: Allows administration of Keycloak authentication required actions
+ name: keycloak_authentication_required_actions
namespace: ''
- - description: Listing of resource policy_profiles in ManageIQ
- name: manageiq_policies_info
+ - description: Allows administration of Keycloak client custom Javascript policies
+ via Keycloak API
+ name: keycloak_authz_custom_policy
namespace: ''
- - description: Retrieve resource tags in ManageIQ
- name: manageiq_tags_info
+ - description: Allows administration of Keycloak client authorization permissions
+ via Keycloak API
+ name: keycloak_authz_permission
namespace: ''
- - description: Rretrieves information about applications installed with pipx
- name: pipx_info
+ - description: Query Keycloak client authorization permissions information
+ name: keycloak_authz_permission_info
namespace: ''
- - description: Management of a disk of a Qemu(KVM) VM in a Proxmox VE cluster.
- name: proxmox_disk
+ - description: Allows administration of Keycloak realm keys via Keycloak API
+ name: keycloak_realm_key
namespace: ''
- - description: Scaleway compute - private network management
- name: scaleway_compute_private_network
+ - description: Create and configure a user in Keycloak
+ name: keycloak_user
namespace: ''
- - description: Scaleway Container registry management module
- name: scaleway_container_registry
+ - description: Renames LVM volume groups
+ name: lvg_rename
namespace: ''
- - description: Scaleway Container registry info module
- name: scaleway_container_registry_info
+ - description: Manage node.js packages with pnpm
+ name: pnpm
namespace: ''
- - description: Scaleway Function namespace management
- name: scaleway_function_namespace
+ - description: Pool management for Proxmox VE cluster
+ name: proxmox_pool
namespace: ''
- - description: Retrieve information on Scaleway Function namespace
- name: scaleway_function_namespace_info
+ - description: Add or delete members from Proxmox VE cluster pools
+ name: proxmox_pool_member
namespace: ''
- - description: Manages WDC UltraStar Data102 Out-Of-Band controllers using Redfish
- APIs
- name: wdc_redfish_command
+ - description: Retrieve information about one or more Proxmox VE virtual machines
+ name: proxmox_vm_info
namespace: ''
- - description: Manages WDC UltraStar Data102 Out-Of-Band controllers using Redfish
- APIs
- name: wdc_redfish_info
+ - description: Manage services on Source Mage GNU/Linux
+ name: simpleinit_msb
namespace: ''
plugins:
- filter:
- - description: Counts hashable elements in a sequence
- name: counter
- namespace: null
lookup:
- - description: Retrieve secrets from Bitwarden
- name: bitwarden
+ - description: Retrieve secrets from Bitwarden Secrets Manager
+ name: bitwarden_secrets_manager
namespace: null
- release_date: '2022-11-02'
- 6.0.1:
+ release_date: '2023-11-01'
+ 8.0.1:
changes:
bugfixes:
- - dependent lookup plugin - avoid warning on deprecated parameter for ``Templar.template()``
- (https://github.com/ansible-collections/community.general/pull/5543).
- - jenkins_build - fix the logical flaw when deleting a Jenkins build (https://github.com/ansible-collections/community.general/pull/5514).
- - one_vm - avoid splitting labels that are ``None`` (https://github.com/ansible-collections/community.general/pull/5489).
- - onepassword_raw - add missing parameter to plugin documentation (https://github.com/ansible-collections/community.general/issues/5506).
- - proxmox_disk - avoid duplicate ``vmid`` reference (https://github.com/ansible-collections/community.general/issues/5492,
- https://github.com/ansible-collections/community.general/pull/5493).
- release_summary: Bugfix release for Ansible 7.0.0.
+ - gitlab_group_members - fix gitlab constants call in ``gitlab_group_members``
+ module (https://github.com/ansible-collections/community.general/issues/7467).
+ - gitlab_project_members - fix gitlab constants call in ``gitlab_project_members``
+ module (https://github.com/ansible-collections/community.general/issues/7467).
+ - gitlab_protected_branches - fix gitlab constants call in ``gitlab_protected_branches``
+ module (https://github.com/ansible-collections/community.general/issues/7467).
+ - gitlab_user - fix gitlab constants call in ``gitlab_user`` module (https://github.com/ansible-collections/community.general/issues/7467).
+ - proxmox_pool_member - absent state for type VM did not delete VMs from the
+ pools (https://github.com/ansible-collections/community.general/pull/7464).
+ - redfish_command - fix usage of message parsing in ``SimpleUpdate`` and ``MultipartHTTPPushUpdate``
+ commands to treat the lack of a ``MessageId`` as no message (https://github.com/ansible-collections/community.general/issues/7465,
+ https://github.com/ansible-collections/community.general/pull/7471).
+ release_summary: Bugfix release for inclusion in Ansible 9.0.0b1.
fragments:
- - 5489-nonetype-in-get-vm-by-label.yml
- - 5493-proxmox.yml
- - 5506-onepassword_raw-missing-param.yml
- - 5514-fix-logical-flaw-when-deleting-jenkins-build.yml
- - 5543-dependent-template.yml
- - 6.0.1.yml
- release_date: '2022-11-15'
- 6.1.0:
+ - 7464-fix-vm-removal-in-proxmox_pool_member.yml
+ - 7465-redfish-firmware-update-message-id-hardening.yml
+ - 7467-fix-gitlab-constants-calls.yml
+ - 8.0.1.yml
+ release_date: '2023-11-06'
+ 8.0.2:
changes:
bugfixes:
- - chroot connection plugin - add ``inventory_hostname`` to vars under ``remote_addr``.
- This is needed for compatibility with ansible-core 2.13 (https://github.com/ansible-collections/community.general/pull/5570).
- - cmd_runner module utils - fixed bug when handling default cases in ``cmd_runner_fmt.as_map()``
- (https://github.com/ansible-collections/community.general/pull/5538).
- - cmd_runner module utils - formatting arguments ``cmd_runner_fmt.as_fixed()``
- was expecting an non-existing argument (https://github.com/ansible-collections/community.general/pull/5538).
- - keycloak_client_rolemapping - calculate ``proposed`` and ``after`` return
- values properly (https://github.com/ansible-collections/community.general/pull/5619).
- - keycloak_client_rolemapping - remove only listed mappings with ``state=absent``
- (https://github.com/ansible-collections/community.general/pull/5619).
- - proxmox inventory plugin - fix bug while templating when using templates for
- the ``url``, ``user``, ``password``, ``token_id``, or ``token_secret`` options
- (https://github.com/ansible-collections/community.general/pull/5640).
- - proxmox inventory plugin - handle tags delimited by semicolon instead of comma,
- which happens from Proxmox 7.3 on (https://github.com/ansible-collections/community.general/pull/5602).
- - redhat_subscription - do not ignore ``consumer_name`` and other variables
- if ``activationkey`` is specified (https://github.com/ansible-collections/community.general/issues/3486,
- https://github.com/ansible-collections/community.general/pull/5627).
- - redhat_subscription - do not pass arguments to ``subscription-manager register``
- for things already configured; now a specified ``rhsm_baseurl`` is properly
- set for subscription-manager (https://github.com/ansible-collections/community.general/pull/5583).
- - unixy callback plugin - fix plugin to work with ansible-core 2.14 by using
- Ansible's configuration manager for handling options (https://github.com/ansible-collections/community.general/issues/5600).
- - vdo - now uses ``yaml.safe_load()`` to parse command output instead of the
- deprecated ``yaml.load()`` which is potentially unsafe. Using ``yaml.load()``
- without explicitely setting a ``Loader=`` is also an error in pyYAML 6.0 (https://github.com/ansible-collections/community.general/pull/5632).
- - vmadm - fix for index out of range error in ``get_vm_uuid`` (https://github.com/ansible-collections/community.general/pull/5628).
- deprecated_features:
- - The ``sap`` modules ``sapcar_extract``, ``sap_task_list_execute``, and ``hana_query``,
- will be removed from this collection in community.general 7.0.0 and replaced
- with redirects to ``community.sap_libs``. If you want to continue using these
- modules, make sure to also install ``community.sap_libs`` (it is part of the
- Ansible package) (https://github.com/ansible-collections/community.general/pull/5614).
- minor_changes:
- - cmd_runner module utils - ``cmd_runner_fmt.as_bool()`` can now take an extra
- parameter to format when value is false (https://github.com/ansible-collections/community.general/pull/5647).
- - gconftool2 - refactor using ``ModuleHelper`` and ``CmdRunner`` (https://github.com/ansible-collections/community.general/pull/5545).
- - java_certs - add more detailed error output when extracting certificate from
- PKCS12 fails (https://github.com/ansible-collections/community.general/pull/5550).
- - jenkins_plugin - refactor code to module util to fix sanity check (https://github.com/ansible-collections/community.general/pull/5565).
- - lxd_project - refactored code out to module utils to clear sanity check (https://github.com/ansible-collections/community.general/pull/5549).
- - nmap inventory plugin - add new options ``udp_scan``, ``icmp_timestamp``,
- and ``dns_resolve`` for different types of scans (https://github.com/ansible-collections/community.general/pull/5566).
- - rax_scaling_group - refactored out code to the ``rax`` module utils to clear
- the sanity check (https://github.com/ansible-collections/community.general/pull/5563).
- - redfish_command - add ``PerformRequestedOperations`` command to perform any
- operations necessary to continue the update flow (https://github.com/ansible-collections/community.general/issues/4276).
- - redfish_command - add ``update_apply_time`` to ``SimpleUpdate`` command (https://github.com/ansible-collections/community.general/issues/3910).
- - redfish_command - add ``update_status`` to output of ``SimpleUpdate`` command
- to allow a user monitor the update in progress (https://github.com/ansible-collections/community.general/issues/4276).
- - redfish_info - add ``GetUpdateStatus`` command to check the progress of a
- previous update request (https://github.com/ansible-collections/community.general/issues/4276).
- - redfish_utils module utils - added PUT (``put_request()``) functionality (https://github.com/ansible-collections/community.general/pull/5490).
- - slack - add option ``prepend_hash`` which allows to control whether a ``#``
- is prepended to ``channel_id``. The current behavior (value ``auto``) is to
- prepend ``#`` unless some specific prefixes are found. That list of prefixes
- is incomplete, and there does not seem to exist a documented condition on
- when exactly ``#`` must not be prepended. We recommend to explicitly set ``prepend_hash=always``
- or ``prepend_hash=never`` to avoid any ambiguity (https://github.com/ansible-collections/community.general/pull/5629).
- - spotinst_aws_elastigroup - add ``elements`` attribute when missing in ``list``
- parameters (https://github.com/ansible-collections/community.general/pull/5553).
- - ssh_config - add ``host_key_algorithms`` option (https://github.com/ansible-collections/community.general/pull/5605).
- - udm_share - added ``elements`` attribute to ``list`` type parameters (https://github.com/ansible-collections/community.general/pull/5557).
- - udm_user - add ``elements`` attribute when missing in ``list`` parameters
- (https://github.com/ansible-collections/community.general/pull/5559).
- release_summary: Regular bugfix and feature release.
+ - ocapi_utils, oci_utils, redfish_utils module utils - replace ``type()`` calls
+ with ``isinstance()`` calls (https://github.com/ansible-collections/community.general/pull/7501).
+ - pipx module utils - change the CLI argument formatter for the ``pip_args``
+ parameter (https://github.com/ansible-collections/community.general/issues/7497,
+ https://github.com/ansible-collections/community.general/pull/7506).
+ release_summary: Bugfix release for inclusion in Ansible 9.0.0rc1.
fragments:
- - 3910-redfish-add-operation-apply-time-to-simple-update.yml
- - 4276-redfish-command-updates-for-full-simple-update-workflow.yml
- - 5490-adding-put-functionality.yml
- - 5538-cmd-runner-as-fixed.yml
- - 5545-gconftool-cmd-runner.yml
- - 5549-lxd-project-sanity.yml
- - 5550-java_certs-not-enough-info-on-error.yml
- - 5553-spotinst-aws-elasticgroup-sanity.yml
- - 5557-udm-share-sanity.yml
- - 5559-udm-user-sanity.yml
- - 5563-rax-scaling-group-sanity.yml
- - 5565-jenkins-plugin-sanity.yml
- - 5566-additional-flags-nmap.yml
- - 5570-chroot-plugin-fix-default-inventory_hostname.yml
- - 5583-redhat_subscription-subscribe-parameters.yaml
- - 5601-unixy-callback-use-config-manager.yml
- - 5602-proxmox-tags.yml
- - 5605-ssh-config-add-host-key-algorithms.yaml
- - 5619-keycloak-improvements.yml
- - 5627-redhat_subscription-subscribe-parameters-2.yaml
- - 5628-fix-vmadm-off-by-one.yml
- - 5629-add-prepend-hash-option-for-channel-id.yml
- - 5632-vdo-Use-yaml-safe-load-instead-of-yaml-load.yml
- - 5640-fix-typo-proxmox-inventory.yml
- - 5647-cmd-runner-as-bool-false.yml
- - 6.1.0.yml
- - sap-removal.yml
- modules:
- - description: Manage project badges on GitLab Server
- name: gitlab_project_badge
- namespace: ''
- - description: Retrieve client secret via Keycloak API
- name: keycloak_clientsecret_info
- namespace: ''
- - description: Regenerate Keycloak client secret via Keycloak API
- name: keycloak_clientsecret_regenerate
- namespace: ''
- release_date: '2022-12-06'
- 6.2.0:
+ - 7501-type.yml
+ - 7506-pipx-pipargs.yml
+ - 8.0.2.yml
+ release_date: '2023-11-13'
+ 8.1.0:
changes:
bugfixes:
- - ansible_galaxy_install - set default to raise exception if command's return
- code is different from zero (https://github.com/ansible-collections/community.general/pull/5680).
- - ansible_galaxy_install - try ``C.UTF-8`` and then fall back to ``en_US.UTF-8``
- before failing (https://github.com/ansible-collections/community.general/pull/5680).
- - gitlab_group_variables - fix dropping variables accidentally when GitLab introduced
- new properties (https://github.com/ansible-collections/community.general/pull/5667).
- - gitlab_project_variables - fix dropping variables accidentally when GitLab
- introduced new properties (https://github.com/ansible-collections/community.general/pull/5667).
- - lxc_container - fix the arguments of the lxc command which broke the creation
- and cloning of containers (https://github.com/ansible-collections/community.general/issues/5578).
- - opkg - fix issue that ``force=reinstall`` would not reinstall an existing
- package (https://github.com/ansible-collections/community.general/pull/5705).
- - proxmox_disk - fixed possible issues with redundant ``vmid`` parameter (https://github.com/ansible-collections/community.general/issues/5492,
- https://github.com/ansible-collections/community.general/pull/5672).
- - proxmox_nic - fixed possible issues with redundant ``vmid`` parameter (https://github.com/ansible-collections/community.general/issues/5492,
- https://github.com/ansible-collections/community.general/pull/5672).
- - unixy callback plugin - fix typo introduced when updating to use Ansible's
- configuration manager for handling options (https://github.com/ansible-collections/community.general/issues/5600).
- deprecated_features:
- - manageiq_policies - deprecate ``state=list`` in favour of using ``community.general.manageiq_policies_info``
- (https://github.com/ansible-collections/community.general/pull/5721).
- - rax - module relies on deprecates library ``pyrax``. Unless maintainers step
- up to work on the module, it will be marked as deprecated in community.general
- 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
- - rax_cbs - module relies on deprecates library ``pyrax``. Unless maintainers
- step up to work on the module, it will be marked as deprecated in community.general
- 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
- - rax_cbs_attachments - module relies on deprecates library ``pyrax``. Unless
- maintainers step up to work on the module, it will be marked as deprecated
- in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
- - rax_cdb - module relies on deprecates library ``pyrax``. Unless maintainers
- step up to work on the module, it will be marked as deprecated in community.general
- 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
- - rax_cdb_database - module relies on deprecates library ``pyrax``. Unless maintainers
- step up to work on the module, it will be marked as deprecated in community.general
- 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
- - rax_cdb_user - module relies on deprecates library ``pyrax``. Unless maintainers
- step up to work on the module, it will be marked as deprecated in community.general
- 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
- - rax_clb - module relies on deprecates library ``pyrax``. Unless maintainers
- step up to work on the module, it will be marked as deprecated in community.general
- 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
- - rax_clb_nodes - module relies on deprecates library ``pyrax``. Unless maintainers
- step up to work on the module, it will be marked as deprecated in community.general
- 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
- - rax_clb_ssl - module relies on deprecates library ``pyrax``. Unless maintainers
- step up to work on the module, it will be marked as deprecated in community.general
- 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
- - rax_dns - module relies on deprecates library ``pyrax``. Unless maintainers
- step up to work on the module, it will be marked as deprecated in community.general
- 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
- - rax_dns_record - module relies on deprecates library ``pyrax``. Unless maintainers
- step up to work on the module, it will be marked as deprecated in community.general
- 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
- - rax_facts - module relies on deprecates library ``pyrax``. Unless maintainers
- step up to work on the module, it will be marked as deprecated in community.general
- 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
- - rax_files - module relies on deprecates library ``pyrax``. Unless maintainers
- step up to work on the module, it will be marked as deprecated in community.general
- 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
- - rax_files_objects - module relies on deprecates library ``pyrax``. Unless
- maintainers step up to work on the module, it will be marked as deprecated
- in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
- - rax_identity - module relies on deprecates library ``pyrax``. Unless maintainers
- step up to work on the module, it will be marked as deprecated in community.general
- 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
- - rax_keypair - module relies on deprecates library ``pyrax``. Unless maintainers
- step up to work on the module, it will be marked as deprecated in community.general
- 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
- - rax_meta - module relies on deprecates library ``pyrax``. Unless maintainers
- step up to work on the module, it will be marked as deprecated in community.general
- 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
- - rax_mon_alarm - module relies on deprecates library ``pyrax``. Unless maintainers
- step up to work on the module, it will be marked as deprecated in community.general
- 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
- - rax_mon_check - module relies on deprecates library ``pyrax``. Unless maintainers
- step up to work on the module, it will be marked as deprecated in community.general
- 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
- - rax_mon_entity - module relies on deprecates library ``pyrax``. Unless maintainers
- step up to work on the module, it will be marked as deprecated in community.general
- 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
- - rax_mon_notification - module relies on deprecates library ``pyrax``. Unless
- maintainers step up to work on the module, it will be marked as deprecated
- in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
- - rax_mon_notification_plan - module relies on deprecates library ``pyrax``.
- Unless maintainers step up to work on the module, it will be marked as deprecated
- in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
- - rax_network - module relies on deprecates library ``pyrax``. Unless maintainers
- step up to work on the module, it will be marked as deprecated in community.general
- 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
- - rax_queue - module relies on deprecates library ``pyrax``. Unless maintainers
- step up to work on the module, it will be marked as deprecated in community.general
- 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
- - rax_scaling_group - module relies on deprecates library ``pyrax``. Unless
- maintainers step up to work on the module, it will be marked as deprecated
- in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
- - rax_scaling_policy - module relies on deprecates library ``pyrax``. Unless
- maintainers step up to work on the module, it will be marked as deprecated
- in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
- minor_changes:
- - opkg - allow installing a package in a certain version (https://github.com/ansible-collections/community.general/pull/5688).
- - proxmox - added new module parameter ``tags`` for use with PVE 7+ (https://github.com/ansible-collections/community.general/pull/5714).
- - puppet - refactored module to use ``CmdRunner`` for executing ``puppet`` (https://github.com/ansible-collections/community.general/pull/5612).
- - redhat_subscription - add a ``server_proxy_scheme`` parameter to configure
- the scheme for the proxy server (https://github.com/ansible-collections/community.general/pull/5662).
- - ssh_config - refactor code to module util to fix sanity check (https://github.com/ansible-collections/community.general/pull/5720).
- - sudoers - adds ``host`` parameter for setting hostname restrictions in sudoers
- rules (https://github.com/ansible-collections/community.general/issues/5702).
- release_summary: Regular bugfix and feature release.
- fragments:
- - 5612-puppet-cmd-runner.yml
- - 5659-fix-lxc_container-command.yml
- - 5662-redhat_subscription-server_proxy_scheme.yaml
- - 5666-gitlab-variables.yml
- - 5672-proxmox.yml
- - 5680-ansible_galaxy_install-fx-locale.yaml
- - 5688-opkg-module-install-certain-version.yml
- - 5703-sudoers-host-support.yml
- - 5705-opkg-fix-force-reinstall.yml
- - 5714-proxmox-lxc-tag-support.yml
- - 5720-ssh_config-plugin-sanity.yml
- - 5721-manageiq-policies-deprecate-list-state.yaml
- - 5733-rax-deprecation-notice.yml
- - 5744-unixy-callback-fix-config-manager-typo.yml
- - 6.2.0.yml
- release_date: '2023-01-04'
- 6.3.0:
- changes:
- breaking_changes:
- - 'ModuleHelper module utils - when the module sets output variables named ``msg``,
- ``exception``, ``output``, ``vars``, or ``changed``, the actual output will
- prefix those names with ``_`` (underscore symbol) only when they clash with
- output variables generated by ModuleHelper itself, which only occurs when
- handling exceptions. Please note that this breaking change does not require
- a new major release since before this release, it was not possible to add
- such variables to the output `due to a bug <https://github.com/ansible-collections/community.general/pull/5755>`__
- (https://github.com/ansible-collections/community.general/pull/5765).
+ - apt-rpm - the module did not upgrade packages if a newer version exists. Now
+ the package will be reinstalled if the candidate is newer than the installed
+ version (https://github.com/ansible-collections/community.general/issues/7414).
+ - cloudflare_dns - fix Cloudflare lookup of SHFP records (https://github.com/ansible-collections/community.general/issues/7652).
+ - interface_files - also consider ``address_family`` when changing ``option=method``
+ (https://github.com/ansible-collections/community.general/issues/7610, https://github.com/ansible-collections/community.general/pull/7612).
+ - irc - replace ``ssl.wrap_socket`` that was removed from Python 3.12 with code
+ for creating a proper SSL context (https://github.com/ansible-collections/community.general/pull/7542).
+ - keycloak_* - fix Keycloak API client to quote ``/`` properly (https://github.com/ansible-collections/community.general/pull/7641).
+ - keycloak_authz_permission - resource payload variable for scope-based permission
+ was constructed as a string, when it needs to be a list, even for a single
+ item (https://github.com/ansible-collections/community.general/issues/7151).
+ - log_entries callback plugin - replace ``ssl.wrap_socket`` that was removed
+ from Python 3.12 with code for creating a proper SSL context (https://github.com/ansible-collections/community.general/pull/7542).
+ - lvol - test for output messages in both ``stdout`` and ``stderr`` (https://github.com/ansible-collections/community.general/pull/7601,
+ https://github.com/ansible-collections/community.general/issues/7182).
+ - onepassword lookup plugin - field and section titles are now case insensitive
+ when using op CLI version two or later. This matches the behavior of version
+ one (https://github.com/ansible-collections/community.general/pull/7564).
+ - 'redhat_subscription - use the D-Bus registration on RHEL 7 only on 7.4 and
- '
- bugfixes:
- - ModuleHelper - fix bug when adjusting the name of reserved output variables
- (https://github.com/ansible-collections/community.general/pull/5755).
- - alternatives - support subcommands on Fedora 37, which uses ``follower`` instead
- of ``slave`` (https://github.com/ansible-collections/community.general/pull/5794).
- - bitwarden lookup plugin - clarify what to do, if the bitwarden vault is not
- unlocked (https://github.com/ansible-collections/community.general/pull/5811).
- - dig lookup plugin - correctly handle DNSKEY record type's ``algorithm`` field
- (https://github.com/ansible-collections/community.general/pull/5914).
- - gem - fix force parameter not being passed to gem command when uninstalling
- (https://github.com/ansible-collections/community.general/pull/5822).
- - gem - fix hang due to interactive prompt for confirmation on specific version
- uninstall (https://github.com/ansible-collections/community.general/pull/5751).
- - gitlab_deploy_key - also update ``title`` and not just ``can_push`` (https://github.com/ansible-collections/community.general/pull/5888).
- - keycloak_user_federation - fixes federation creation issue. When a new federation
- was created and at the same time a default / standard mapper was also changed
- / updated the creation process failed as a bad None set variable led to a
- bad malformed url request (https://github.com/ansible-collections/community.general/pull/5750).
- - 'keycloak_user_federation - fixes idempotency detection issues. In some cases
- the module could fail to properly detect already existing user federations
- because of a buggy seemingly superflous extra query parameter (https://github.com/ansible-collections/community.general/pull/5732).
+ greater; older versions of RHEL 7 do not have it
+
+ (https://github.com/ansible-collections/community.general/issues/7622,
+
+ https://github.com/ansible-collections/community.general/pull/7624).
'
- - loganalytics callback plugin - adjust type of callback to ``notification``,
- it was incorrectly classified as ``aggregate`` before (https://github.com/ansible-collections/community.general/pull/5761).
- - logdna callback plugin - adjust type of callback to ``notification``, it was
- incorrectly classified as ``aggregate`` before (https://github.com/ansible-collections/community.general/pull/5761).
- - logstash callback plugin - adjust type of callback to ``notification``, it
- was incorrectly classified as ``aggregate`` before (https://github.com/ansible-collections/community.general/pull/5761).
- - nsupdate - fix zone lookup. The SOA record for an existing zone is returned
- as an answer RR and not as an authority RR (https://github.com/ansible-collections/community.general/issues/5817,
- https://github.com/ansible-collections/community.general/pull/5818).
- - proxmox_disk - fixed issue with read timeout on import action (https://github.com/ansible-collections/community.general/pull/5803).
- - redfish_utils - removed basic auth HTTP header when performing a GET on the
- service root resource and when performing a POST to the session collection
- (https://github.com/ansible-collections/community.general/issues/5886).
- - splunk callback plugin - adjust type of callback to ``notification``, it was
- incorrectly classified as ``aggregate`` before (https://github.com/ansible-collections/community.general/pull/5761).
- - sumologic callback plugin - adjust type of callback to ``notification``, it
- was incorrectly classified as ``aggregate`` before (https://github.com/ansible-collections/community.general/pull/5761).
- - syslog_json callback plugin - adjust type of callback to ``notification``,
- it was incorrectly classified as ``aggregate`` before (https://github.com/ansible-collections/community.general/pull/5761).
- - terraform - fix ``current`` workspace never getting appended to the ``all``
- key in the ``workspace_ctf`` object (https://github.com/ansible-collections/community.general/pull/5735).
- - terraform - fix ``terraform init`` failure when there are multiple workspaces
- on the remote backend and when ``default`` workspace is missing by setting
- ``TF_WORKSPACE`` environmental variable to the value of ``workspace`` when
- used (https://github.com/ansible-collections/community.general/pull/5735).
- - terraform module - disable ANSI escape sequences during validation phase (https://github.com/ansible-collections/community.general/pull/5843).
- - xml - fixed a bug where empty ``children`` list would not be set (https://github.com/ansible-collections/community.general/pull/5808).
- deprecated_features:
- - consul - deprecate using parameters unused for ``state=absent`` (https://github.com/ansible-collections/community.general/pull/5772).
- - gitlab_runner - the default of the new option ``access_level_on_creation``
- will change from ``false`` to ``true`` in community.general 7.0.0. This will
- cause ``access_level`` to be used during runner registration as well, and
- not only during updates (https://github.com/ansible-collections/community.general/pull/5908).
+ - terraform - fix multiline string handling in complex variables (https://github.com/ansible-collections/community.general/pull/7535).
minor_changes:
- - apache2_module - add module argument ``warn_mpm_absent`` to control whether
- warning are raised in some edge cases (https://github.com/ansible-collections/community.general/pull/5793).
- - bitwarden lookup plugin - can now retrieve secrets from custom fields (https://github.com/ansible-collections/community.general/pull/5694).
- - bitwarden lookup plugin - implement filtering results by ``collection_id``
- parameter (https://github.com/ansible-collections/community.general/issues/5849).
- - dig lookup plugin - support CAA record type (https://github.com/ansible-collections/community.general/pull/5913).
- - gitlab_project - add ``builds_access_level``, ``container_registry_access_level``
- and ``forking_access_level`` options (https://github.com/ansible-collections/community.general/pull/5706).
- - gitlab_runner - add new boolean option ``access_level_on_creation``. It controls,
- whether the value of ``access_level`` is used for runner registration or not.
- The option ``access_level`` has been ignored on registration so far and was
- only used on updates (https://github.com/ansible-collections/community.general/issues/5907,
- https://github.com/ansible-collections/community.general/pull/5908).
- - ilo_redfish_utils module utils - change implementation of DNS Server IP and
- NTP Server IP update (https://github.com/ansible-collections/community.general/pull/5804).
- - ipa_group - allow to add and remove external users with the ``external_user``
- option (https://github.com/ansible-collections/community.general/pull/5897).
- - iptables_state - minor refactoring within the module (https://github.com/ansible-collections/community.general/pull/5844).
- - one_vm - add a new ``updateconf`` option which implements the ``one.vm.updateconf``
- API call (https://github.com/ansible-collections/community.general/pull/5812).
- - opkg - refactored module to use ``CmdRunner`` for executing ``opkg`` (https://github.com/ansible-collections/community.general/pull/5718).
- - redhat_subscription - adds ``token`` parameter for subscription-manager authentication
- using Red Hat API token (https://github.com/ansible-collections/community.general/pull/5725).
- - snap - minor refactor when executing module (https://github.com/ansible-collections/community.general/pull/5773).
- - snap_alias - refactored module to use ``CmdRunner`` to execute ``snap`` (https://github.com/ansible-collections/community.general/pull/5486).
- - sudoers - add ``setenv`` parameters to support passing environment variables
- via sudo. (https://github.com/ansible-collections/community.general/pull/5883)
+ - bitwarden lookup plugin - when looking for items using an item ID, the item
+ is now accessed directly with ``bw get item`` instead of searching through
+ all items. This doubles the lookup speed (https://github.com/ansible-collections/community.general/pull/7468).
+ - elastic callback plugin - close elastic client to not leak resources (https://github.com/ansible-collections/community.general/pull/7517).
+ - git_config - allow multiple git configs for the same name with the new ``add_mode``
+ option (https://github.com/ansible-collections/community.general/pull/7260).
+ - git_config - the ``after`` and ``before`` fields in the ``diff`` of the return
+ value can be a list instead of a string in case more configs with the same
+ key are affected (https://github.com/ansible-collections/community.general/pull/7260).
+ - git_config - when a value is unset, all configs with the same key are unset
+ (https://github.com/ansible-collections/community.general/pull/7260).
+ - gitlab modules - add ``ca_path`` option (https://github.com/ansible-collections/community.general/pull/7472).
+ - gitlab modules - remove duplicate ``gitlab`` package check (https://github.com/ansible-collections/community.general/pull/7486).
+ - gitlab_runner - add support for new runner creation workflow (https://github.com/ansible-collections/community.general/pull/7199).
+ - ipa_config - adds ``passkey`` choice to ``ipauserauthtype`` parameter's choices
+ (https://github.com/ansible-collections/community.general/pull/7588).
+ - ipa_sudorule - adds options to include denied commands or command groups (https://github.com/ansible-collections/community.general/pull/7415).
+ - ipa_user - adds ``idp`` and ``passkey`` choice to ``ipauserauthtype`` parameter's
+ choices (https://github.com/ansible-collections/community.general/pull/7589).
+ - irc - add ``validate_certs`` option, and rename ``use_ssl`` to ``use_tls``,
+ while keeping ``use_ssl`` as an alias. The default value for ``validate_certs``
+ is ``false`` for backwards compatibility. We recommend to every user of this
+ module to explicitly set ``use_tls=true`` and `validate_certs=true`` whenever
+ possible, especially when communicating to IRC servers over the internet (https://github.com/ansible-collections/community.general/pull/7550).
+ - keycloak module utils - expose error message from Keycloak server for HTTP
+ errors in some specific situations (https://github.com/ansible-collections/community.general/pull/7645).
+ - keycloak_user_federation - add option for ``krbPrincipalAttribute`` (https://github.com/ansible-collections/community.general/pull/7538).
+ - lvol - change ``pvs`` argument type to list of strings (https://github.com/ansible-collections/community.general/pull/7676,
+ https://github.com/ansible-collections/community.general/issues/7504).
+ - 'lxd connection plugin - tighten the detection logic for lxd ``Instance not
+ found`` errors, to avoid false detection on unrelated errors such as ``/usr/bin/python3:
+ not found`` (https://github.com/ansible-collections/community.general/pull/7521).'
+ - netcup_dns - adds support for record types ``OPENPGPKEY``, ``SMIMEA``, and
+ ``SSHFP`` (https://github.com/ansible-collections/community.general/pull/7489).
+ - nmcli - add support for new connection type ``loopback`` (https://github.com/ansible-collections/community.general/issues/6572).
+ - nmcli - allow for ``infiniband`` slaves of ``bond`` interface types (https://github.com/ansible-collections/community.general/pull/7569).
+ - nmcli - allow for the setting of ``MTU`` for ``infiniband`` and ``bond`` interface
+ types (https://github.com/ansible-collections/community.general/pull/7499).
+ - onepassword lookup plugin - support 1Password Connect with the opv2 client
+ by setting the connect_host and connect_token parameters (https://github.com/ansible-collections/community.general/pull/7116).
+ - onepassword_raw lookup plugin - support 1Password Connect with the opv2 client
+ by setting the connect_host and connect_token parameters (https://github.com/ansible-collections/community.general/pull/7116)
+ - passwordstore - adds ``timestamp`` and ``preserve`` parameters to modify the
+ stored password format (https://github.com/ansible-collections/community.general/pull/7426).
+ - proxmox - adds ``template`` value to the ``state`` parameter, allowing conversion
+ of container to a template (https://github.com/ansible-collections/community.general/pull/7143).
+ - proxmox - adds ``update`` parameter, allowing update of an already existing
+ containers configuration (https://github.com/ansible-collections/community.general/pull/7540).
+ - proxmox inventory plugin - adds an option to exclude nodes from the dynamic
+ inventory generation. The new setting is optional, not using this option will
+ behave as usual (https://github.com/ansible-collections/community.general/issues/6714,
+ https://github.com/ansible-collections/community.general/pull/7461).
+ - proxmox_disk - add ability to manipulate CD-ROM drive (https://github.com/ansible-collections/community.general/pull/7495).
+ - proxmox_kvm - adds ``template`` value to the ``state`` parameter, allowing
+ conversion of a VM to a template (https://github.com/ansible-collections/community.general/pull/7143).
+ - proxmox_kvm - support the ``hookscript`` parameter (https://github.com/ansible-collections/community.general/issues/7600).
+ - proxmox_ostype - it is now possible to specify the ``ostype`` when creating
+ an LXC container (https://github.com/ansible-collections/community.general/pull/7462).
+ - proxmox_vm_info - add ability to retrieve configuration info (https://github.com/ansible-collections/community.general/pull/7485).
+ - redfish_info - adding the ``BootProgress`` property when getting ``Systems``
+ info (https://github.com/ansible-collections/community.general/pull/7626).
+ - ssh_config - adds ``controlmaster``, ``controlpath`` and ``controlpersist``
+ parameters (https://github.com/ansible-collections/community.general/pull/7456).
release_summary: Regular bugfix and feature release.
fragments:
- - 5486-snap-alias-cmd-runner.yml
- - 5694-add-custom-fields-to-bitwarden.yml
- - 5706-add-builds-forks-container-registry.yml
- - 5718-opkg-refactor.yaml
- - 5725-redhat_subscription-add-red-hat-api-token.yml
- - 5732-bugfix-keycloak-userfed-idempotency.yml
- - 5735-terraform-init-fix-when-default-workspace-doesnt-exists.yaml
- - 5750-bugfixing-keycloak-usrfed-fail-when-update-default-mapper-simultaneously.yml
- - 5751-gem-fix-uninstall-hang.yml
- - 5755-mh-fix-output-conflict.yml
- - 5761-callback-types.yml
- - 5765-mh-lax-output-conflict.yml
- - 5772-consul-deprecate-params-when-absent.yml
- - 5773-snap-mh-execute.yml
- - 5793-apache2-module-npm-warnings.yml
- - 5794-alternatives-fedora37.yml
- - 5803-proxmox-read-timeout.yml
- - 5804-minor-changes-to-hpe-ilo-collection.yml
- - 5808-xml-children-parameter-does-not-exist.yml
- - 5811-clarify-bitwarden-error.yml
- - 5812-implement-updateconf-api-call.yml
- - 5818-nsupdate-fix-zone-lookup.yml
- - 5822-gem-uninstall-force.yml
- - 5843-terraform-validate-no-color.yml
- - 5844-iptables-state-refactor.yml
- - 5851-lookup-bitwarden-add-filter-by-collection-id-parameter.yml
- - 5883-sudoers-add-support-for-setenv-parameter.yml
- - 5886-redfish-correct-basic-auth-usage-on-session-creation.yml
- - 5888-update-key-title.yml
- - 5897-ipa_group-add-external-users.yml
- - 5907-fix-gitlab_runner-not-idempotent.yml
- - 5913-dig-caa.yml
- - 5914-dig-dnskey.yml
- - 6.3.0.yml
+ - 000-redhat_subscription-dbus-on-7.4-plus.yaml
+ - 5588-support-1password-connect.yml
+ - 6572-nmcli-add-support-loopback-type.yml
+ - 7143-proxmox-template.yml
+ - 7151-fix-keycloak_authz_permission-incorrect-resource-payload.yml
+ - 7199-gitlab-runner-new-creation-workflow.yml
+ - 7242-multi-values-for-same-name-in-git-config.yml
+ - 7426-add-timestamp-and-preserve-options-for-passwordstore.yaml
+ - 7456-add-ssh-control-master.yml
+ - 7461-proxmox-inventory-add-exclude-nodes.yaml
+ - 7462-Add-ostype-parameter-in-LXC-container-clone-of-ProxmoxVE.yaml
+ - 7472-gitlab-add-ca-path-option.yml
+ - 7485-proxmox_vm_info-config.yml
+ - 7486-gitlab-refactor-package-check.yml
+ - 7489-netcup-dns-record-types.yml
+ - 7495-proxmox_disk-manipulate-cdrom.yml
+ - 7499-allow-mtu-setting-on-bond-and-infiniband-interfaces.yml
+ - 7517-elastic-close-client.yaml
+ - 7535-terraform-fix-multiline-string-handling-in-complex-variables.yml
+ - 7538-add-krbprincipalattribute-option.yml
+ - 7540-proxmox-update config.yml
+ - 7542-irc-logentries-ssl.yml
+ - 7550-irc-use_tls-validate_certs.yml
+ - 7564-onepassword-lookup-case-insensitive.yaml
+ - 7569-infiniband-slave-support.yml
+ - 7577-fix-apt_rpm-module.yml
+ - 7588-ipa-config-new-choice-passkey-to-ipauserauthtype.yml
+ - 7589-ipa-config-new-choices-idp-and-passkey-to-ipauserauthtype.yml
+ - 7600-proxmox_kvm-hookscript.yml
+ - 7601-lvol-fix.yml
+ - 7612-interface_file-method.yml
+ - 7626-redfish-info-add-boot-progress-property.yml
+ - 7641-fix-keycloak-api-client-to-quote-properly.yml
+ - 7645-Keycloak-print-error-msg-from-server.yml
+ - 7653-fix-cloudflare-lookup.yml
+ - 7676-lvol-pvs-as-list.yml
+ - 8.1.0.yml
+ - add-ipa-sudorule-deny-cmd.yml
+ - bitwarden-lookup-performance.yaml
+ - lxd-instance-not-found-avoid-false-positives.yml
modules:
- - description: Manages Out-Of-Band controllers using Open Composable API (OCAPI)
- name: ocapi_command
+ - description: Read git configuration
+ name: git_config_info
namespace: ''
- - description: Manages Out-Of-Band controllers using Open Composable API (OCAPI)
- name: ocapi_info
+ - description: Create, update, or delete GitLab issues
+ name: gitlab_issue
namespace: ''
- release_date: '2023-01-31'
- 6.4.0:
- changes:
- bugfixes:
- - cartesian and flattened lookup plugins - adjust to parameter deprecation in
- ansible-core 2.14's ``listify_lookup_plugin_terms`` helper function (https://github.com/ansible-collections/community.general/pull/6074).
- - cloudflare_dns - fixed the idempotency for SRV DNS records (https://github.com/ansible-collections/community.general/pull/5972).
- - cloudflare_dns - fixed the possiblity of setting a root-level SRV DNS record
- (https://github.com/ansible-collections/community.general/pull/5972).
- - github_webhook - fix always changed state when no secret is provided (https://github.com/ansible-collections/community.general/pull/5994).
- - jenkins_plugin - fix error due to undefined variable when updates file is
- not downloaded (https://github.com/ansible-collections/community.general/pull/6100).
- - keycloak_client - fix accidental replacement of value for attribute ``saml.signing.private.key``
- with ``no_log`` in wrong contexts (https://github.com/ansible-collections/community.general/pull/5934).
- - lxd_* modules, lxd inventory plugin - fix TLS/SSL certificate validation problems
- by using the correct purpose when creating the TLS context (https://github.com/ansible-collections/community.general/issues/5616,
- https://github.com/ansible-collections/community.general/pull/6034).
- - nmcli - fix change handling of values specified as an integer 0 (https://github.com/ansible-collections/community.general/pull/5431).
- - nmcli - fix failure to handle WIFI settings when connection type not specified
- (https://github.com/ansible-collections/community.general/pull/5431).
- - nmcli - fix improper detection of changes to ``wifi.wake-on-wlan`` (https://github.com/ansible-collections/community.general/pull/5431).
- - nmcli - order is significant for lists of addresses (https://github.com/ansible-collections/community.general/pull/6048).
- - onepassword lookup plugin - Changed to ignore errors from "op account get"
- calls. Previously, errors would prevent auto-signin code from executing (https://github.com/ansible-collections/community.general/pull/5942).
- - terraform and timezone - slight refactoring to avoid linter reporting potentially
- undefined variables (https://github.com/ansible-collections/community.general/pull/5933).
- - various plugins and modules - remove unnecessary imports (https://github.com/ansible-collections/community.general/pull/5940).
- - yarn - fix ``global=true`` to check for the configured global folder instead
- of assuming the default (https://github.com/ansible-collections/community.general/pull/5829)
- - yarn - fix ``state=absent`` not working with ``global=true`` when the package
- does not include a binary (https://github.com/ansible-collections/community.general/pull/5829)
- - yarn - fix ``state=latest`` not working with ``global=true`` (https://github.com/ansible-collections/community.general/issues/5712).
- - zfs_delegate_admin - zfs allow output can now be parsed when uids/gids are
- not known to the host system (https://github.com/ansible-collections/community.general/pull/5943).
- - zypper - make package managing work on readonly filesystem of openSUSE MicroOS
- (https://github.com/ansible-collections/community.general/pull/5615).
- deprecated_features:
- - gitlab_runner - the option ``access_level`` will lose its default value in
- community.general 8.0.0. From that version on, you have set this option to
- ``ref_protected`` explicitly, if you want to have a protected runner (https://github.com/ansible-collections/community.general/issues/5925).
- minor_changes:
- - dnsimple - set custom User-Agent for API requests to DNSimple (https://github.com/ansible-collections/community.general/pull/5927).
- - flatpak_remote - add new boolean option ``enabled``. It controls, whether
- the remote is enabled or not (https://github.com/ansible-collections/community.general/pull/5926).
- - gitlab_project - add ``releases_access_level``, ``environments_access_level``,
- ``feature_flags_access_level``, ``infrastructure_access_level``, ``monitor_access_level``,
- and ``security_and_compliance_access_level`` options (https://github.com/ansible-collections/community.general/pull/5986).
- - jc filter plugin - added the ability to use parser plugins (https://github.com/ansible-collections/community.general/pull/6043).
- - keycloak_group - add new optional module parameter ``parents`` to properly
- handle keycloak subgroups (https://github.com/ansible-collections/community.general/pull/5814).
- - keycloak_user_federation - make ``org.keycloak.storage.ldap.mappers.LDAPStorageMapper``
- the default value for mappers ``providerType`` (https://github.com/ansible-collections/community.general/pull/5863).
- - ldap modules - add ``xorder_discovery`` option (https://github.com/ansible-collections/community.general/issues/6045,
- https://github.com/ansible-collections/community.general/pull/6109).
- - lxd_container - add diff and check mode (https://github.com/ansible-collections/community.general/pull/5866).
- - mattermost, rocketchat, slack - replace missing default favicon with docs.ansible.com
- favicon (https://github.com/ansible-collections/community.general/pull/5928).
- - modprobe - add ``persistent`` option (https://github.com/ansible-collections/community.general/issues/4028,
- https://github.com/ansible-collections/community.general/pull/542).
- - osx_defaults - include stderr in error messages (https://github.com/ansible-collections/community.general/pull/6011).
- - proxmox - suppress urllib3 ``InsecureRequestWarnings`` when ``validate_certs``
- option is ``false`` (https://github.com/ansible-collections/community.general/pull/5931).
- - redfish_command - adding ``EnableSecureBoot`` functionality (https://github.com/ansible-collections/community.general/pull/5899).
- - redfish_command - adding ``VerifyBiosAttributes`` functionality (https://github.com/ansible-collections/community.general/pull/5900).
- - sefcontext - add support for path substitutions (https://github.com/ansible-collections/community.general/issues/1193).
- release_summary: Regular feature and bugfix release.
- fragments:
- - 4028-modprobe-persistent-option.yml
- - 5431-nmcli-wifi.yml
- - 5615-zypper-transactional-update.yml
- - 5814-support-keycloak-subgroups.yml
- - 5829-fix-yarn-global.yml
- - 5830-sefcontext-path-subs.yml
- - 5863-providerType-defaulted-keycloak_userfed-mappers.yml
- - 5866-lxd_container-diff-and-check-mode.yml
- - 5899-adding-enablesecureboot-functionality-to-redfish-config.yml
- - 5900-adding-verifybiosattribute-fucntionality-to-redfish-command.yml
- - 5915-suppress-urllib3-insecure-request-warnings.yml
- - 5925-align_gitlab_runner_access_level_default_with_gitlab.yml
- - 5926-flatpak-remote-enabled.yml
- - 5927-set-user-agent-dnsimple.yml
- - 5928-fix-favicon-url.yml
- - 5933-linting.yml
- - 5934-fix-keycloak-sanitize_cr.yml
- - 5942-onepassword-ignore-errors-from-op-account-get.yml
- - 5943-zfs_delegate_admin-fix-zfs-allow-cannot-parse-unknown-uid-gid.yml
- - 5972-cloudflare-dns-srv-record.yml
- - 5985-add-new-gitlab-api-features.yml
- - 5994-github-webhook-secret.yml
- - 6.4.0.yml
- - 6011-osx-defaults-errors.yml
- - 6034-lxd-tls.yml
- - 6043-jc_plugin_parser_support.yml
- - 6045-xorder-discovery.yml
- - 6048-nmcli-addres-order.yml
- - 6074-loader_in_listify.yml.yml
- - 6100-jenkins_plugin.yml
- - remove-unneeded-imports.yml
- release_date: '2023-02-27'
- 6.5.0:
+ - description: Manage Nomad ACL tokens
+ name: nomad_token
+ namespace: ''
+ plugins:
+ lookup:
+ - description: Fetch documents stored in 1Password
+ name: onepassword_doc
+ namespace: null
+ test:
+ - description: Validates fully-qualified domain names against RFC 1123
+ name: fqdn_valid
+ namespace: null
+ release_date: '2023-12-04'
+ 8.2.0:
changes:
bugfixes:
- - archive - avoid deprecated exception class on Python 3 (https://github.com/ansible-collections/community.general/pull/6180).
- - gitlab_runner - fix ``KeyError`` on runner creation and update (https://github.com/ansible-collections/community.general/issues/6112).
- - influxdb_user - fix running in check mode when the user does not exist yet
- (https://github.com/ansible-collections/community.general/pull/6111).
- - interfaces_file - fix reading options in lines not starting with a space (https://github.com/ansible-collections/community.general/issues/6120).
- - jail connection plugin - add ``inventory_hostname`` to vars under ``remote_addr``.
- This is needed for compatibility with ansible-core 2.13 (https://github.com/ansible-collections/community.general/pull/6118).
- - memset - fix memset urlerror handling (https://github.com/ansible-collections/community.general/pull/6114).
- - nmcli - fixed idempotency issue for bridge connections. Module forced default
- value of ``bridge.priority`` to nmcli if not set; if ``bridge.stp`` is disabled
- nmcli ignores it and keep default (https://github.com/ansible-collections/community.general/issues/3216,
- https://github.com/ansible-collections/community.general/issues/4683).
- - nmcli - fixed idempotency issue when module params is set to ``may_fail4=false``
- and ``method4=disabled``; in this case nmcli ignores change and keeps their
- own default value ``yes`` (https://github.com/ansible-collections/community.general/pull/6106).
- - nmcli - implemented changing mtu value on vlan interfaces (https://github.com/ansible-collections/community.general/issues/4387).
- - opkg - fixes bug when using ``update_cache=true`` (https://github.com/ansible-collections/community.general/issues/6004).
- - redhat_subscription, rhsm_release, rhsm_repository - cleanly fail when not
- running as root, rather than hanging on an interactive ``console-helper``
- prompt; they all interact with ``subscription-manager``, which already requires
- to be run as root (https://github.com/ansible-collections/community.general/issues/734,
- https://github.com/ansible-collections/community.general/pull/6211).
- - xenorchestra inventory plugin - fix failure to receive objects from server
- due to not checking the id of the response (https://github.com/ansible-collections/community.general/pull/6227).
- - yarn - fix ``global=true`` to not fail when `executable` wasn't specified
- (https://github.com/ansible-collections/community.general/pull/6132)
- - yarn - fixes bug where yarn module tasks would fail when warnings were emitted
- from Yarn. The ``yarn.list`` method was not filtering out warnings (https://github.com/ansible-collections/community.general/issues/6127).
+ - keycloak_identity_provider - ``mappers`` processing was not idempotent if
+ the mappers configuration list had not been sorted by name (in ascending order).
+ Fix resolves the issue by sorting mappers in the desired state using the same
+ key which is used for obtaining existing state (https://github.com/ansible-collections/community.general/pull/7418).
+ - keycloak_identity_provider - it was not possible to reconfigure (add, remove)
+ ``mappers`` once they were created initially. Removal was ignored, adding
+ new ones resulted in dropping the pre-existing unmodified mappers. Fix resolves
+ the issue by supplying correct input to the internal update call (https://github.com/ansible-collections/community.general/pull/7418).
+ - keycloak_user - when ``force`` is set, but user does not exist, do not try
+ to delete it (https://github.com/ansible-collections/community.general/pull/7696).
+ - proxmox_kvm - running ``state=template`` will first check whether VM is already
+ a template (https://github.com/ansible-collections/community.general/pull/7792).
+ - statusio_maintenance - fix error caused by incorrectly formed API data payload.
+ Was raising "Failed to create maintenance HTTP Error 400 Bad Request" caused
+ by bad data type for date/time and deprecated dict keys (https://github.com/ansible-collections/community.general/pull/7754).
minor_changes:
- - apt_rpm - adds ``clean``, ``dist_upgrade`` and ``update_kernel`` parameters
- for clear caches, complete upgrade system, and upgrade kernel packages (https://github.com/ansible-collections/community.general/pull/5867).
- - dconf - parse GVariants for equality comparison when the Python module ``gi.repository``
- is available (https://github.com/ansible-collections/community.general/pull/6049).
- - gitlab_runner - allow to register group runner (https://github.com/ansible-collections/community.general/pull/3935).
- - jira - add worklog functionality (https://github.com/ansible-collections/community.general/issues/6209,
- https://github.com/ansible-collections/community.general/pull/6210).
- - ldap modules - add ``ca_path`` option (https://github.com/ansible-collections/community.general/pull/6185).
- - make - add ``command`` return value to the module output (https://github.com/ansible-collections/community.general/pull/6160).
- - nmap inventory plugin - add new option ``open`` for only returning open ports
- (https://github.com/ansible-collections/community.general/pull/6200).
- - nmap inventory plugin - add new option ``port`` for port specific scan (https://github.com/ansible-collections/community.general/pull/6165).
- - nmcli - add ``default`` and ``default-or-eui64`` to the list of valid choices
- for ``addr_gen_mode6`` parameter (https://github.com/ansible-collections/community.general/pull/5974).
- - nmcli - add support for ``team.runner-fast-rate`` parameter for ``team`` connections
- (https://github.com/ansible-collections/community.general/issues/6065).
- - openbsd_pkg - set ``TERM`` to ``'dumb'`` in ``execute_command()`` to make
- module less dependant on the ``TERM`` environment variable set on the Ansible
- controller (https://github.com/ansible-collections/community.general/pull/6149).
- - pipx - optional ``install_apps`` parameter added to install applications from
- injected packages (https://github.com/ansible-collections/community.general/pull/6198).
- - proxmox_kvm - add new ``archive`` parameter. This is needed to create a VM
- from an archive (backup) (https://github.com/ansible-collections/community.general/pull/6159).
- - redfish_info - adds commands to retrieve the HPE ThermalConfiguration and
- FanPercentMinimum settings from iLO (https://github.com/ansible-collections/community.general/pull/6208).
- - redhat_subscription - credentials (``username``, ``activationkey``, and so
- on) are required now only if a system needs to be registered, or ``force_register``
- is specified (https://github.com/ansible-collections/community.general/pull/5664).
- - redhat_subscription - the registration is done using the D-Bus ``rhsm`` service
- instead of spawning a ``subscription-manager register`` command, if possible;
- this avoids passing plain-text credentials as arguments to ``subscription-manager
- register``, which can be seen while that command runs (https://github.com/ansible-collections/community.general/pull/6122).
- - ssh_config - add ``proxyjump`` option (https://github.com/ansible-collections/community.general/pull/5970).
- - ssh_config - vendored StormSSH's config parser to avoid having to install
- StormSSH to use the module (https://github.com/ansible-collections/community.general/pull/6117).
- - znode module - optional ``use_tls`` parameter added for encrypted communication
- (https://github.com/ansible-collections/community.general/issues/6154).
- release_summary: Feature and bugfix release.
+ - ipa_dnsrecord - adds ability to manage NS record types (https://github.com/ansible-collections/community.general/pull/7737).
+ - ipa_pwpolicy - refactor module and exchange a sequence ``if`` statements with
+ a ``for`` loop (https://github.com/ansible-collections/community.general/pull/7723).
+ - ipa_pwpolicy - update module to support ``maxrepeat``, ``maxsequence``, ``dictcheck``,
+ ``usercheck``, ``gracelimit`` parameters in FreeIPA password policies (https://github.com/ansible-collections/community.general/pull/7723).
+ - keycloak_realm_key - the ``config.algorithm`` option now supports 8 additional
+ key algorithms (https://github.com/ansible-collections/community.general/pull/7698).
+ - keycloak_realm_key - the ``config.certificate`` option value is no longer
+ defined with ``no_log=True`` (https://github.com/ansible-collections/community.general/pull/7698).
+ - keycloak_realm_key - the ``provider_id`` option now supports RSA encryption
+ key usage (value ``rsa-enc``) (https://github.com/ansible-collections/community.general/pull/7698).
+ - keycloak_user_federation - allow custom user storage providers to be set through
+ ``provider_id`` (https://github.com/ansible-collections/community.general/pull/7789).
+ - mail - add ``Message-ID`` header; which is required by some mail servers (https://github.com/ansible-collections/community.general/pull/7740).
+ - mail module, mail callback plugin - allow to configure the domain name of
+ the Message-ID header with a new ``message_id_domain`` option (https://github.com/ansible-collections/community.general/pull/7765).
+ - ssh_config - new feature to set ``AddKeysToAgent`` option to ``yes`` or ``no``
+ (https://github.com/ansible-collections/community.general/pull/7703).
+ - ssh_config - new feature to set ``IdentitiesOnly`` option to ``yes`` or ``no``
+ (https://github.com/ansible-collections/community.general/pull/7704).
+ - xcc_redfish_command - added support for raw POSTs (``command=PostResource``
+ in ``category=Raw``) without a specific action info (https://github.com/ansible-collections/community.general/pull/7746).
+ release_summary: Regular bugfix and feature release.
fragments:
- - 3216-nmcli-bridge-idempotency-fix.yml
- - 3935-add-gitlab-group-runner.yml
- - 4387-nmcli-mtu-for-vlan-connection-fix.yml
- - 5664-redhat_subscription-credentials-when-needed.yaml
- - 5867-apt_rpm-add-clean-and-upgrade.yml
- - 5970-add-proxyjump-option-to-ssh-config.yml
- - 5974-nmcli_add_new_addr_gen_mode6_options.yml
- - 6.5.0.yml
- - 6049-dconf-strings.yml
- - 6065-nmcli-add-runner-fast-rate-option.yml
- - 6106-nmcli-ipv4-mayfail-idempotency-fix.yml
- - 6111-influxdb_user-check-mode.yaml
- - 6112-fix_key_error_in_gitlab_runner_creation_update.yml
- - 6114-memset-add-url-error-handling.yml
- - 6117-remove-stormssh-depend.yml
- - 6118-jail-plugin-fix-default-inventory_hostname.yml
- - 6119-opkg-update.yaml
- - 6122-redhat_subscription-subscribe-via-dbus.yaml
- - 6127-yarn-ignore-warnings.yml
- - 6131-fix-interfaces_file-for-no-leading-spaces.yml
- - 6138-fix-yarn-global.yml
- - 6149-openbsd_pkg-term.yml
- - 6154-znode-optional-tls.yml
- - 6158-create-proxmox-vm-from-archive.yml
- - 6160-add-command-make-output.yml
- - 6165-nmap-port.yml
- - 6180-replace-deprecated-badzipfile.yml
- - 6198-pipx-inject-install-apps.yml
- - 6200-adding-open-option-to-nmap.yml
- - 6208-hpe-thermal-fan-percent.yaml
- - 6210-add-worklog-functionality-to-jira.yml
- - 6211-rhsm-require-root.yml
- - 6227-xen-orchestra-check-response-id.yml
- - xxxx-ldap-ca-cert-file.yml
+ - 7418-kc_identity_provider-mapper-reconfiguration-fixes.yml
+ - 7696-avoid-attempt-to-delete-non-existing-user.yml
+ - 7698-improvements-to-keycloak_realm_key.yml
+ - 7703-ssh_config_add_keys_to_agent_option.yml
+ - 7704-ssh_config_identities_only_option.yml
+ - 7723-ipa-pwpolicy-update-pwpolicy-module.yml
+ - 7737-add-ipa-dnsrecord-ns-type.yml
+ - 7740-add-message-id-header-to-mail-module.yml
+ - 7746-raw_post-without-actions.yml
+ - 7754-fixed-payload-format.yml
+ - 7765-mail-message-id.yml
+ - 7789-keycloak-user-federation-custom-provider-type.yml
+ - 7791-proxmox_kvm-state-template-will-check-status-first.yaml
+ - 8.2.0.yml
modules:
- - description: Manage KDE configuration files
- name: kdeconfig
+ - description: Enable or disable dnf repositories using config-manager
+ name: dnf_config_manager
+ namespace: ''
+ - description: Retrive component info in Keycloak
+ name: keycloak_component_info
+ namespace: ''
+ - description: Allows administration of Keycloak realm role mappings into groups
+ with the Keycloak API
+ name: keycloak_realm_rolemapping
+ namespace: ''
+ - description: Retrieve information about one or more Proxmox VE nodes
+ name: proxmox_node_info
+ namespace: ''
+ - description: List content from a Proxmox VE storage
+ name: proxmox_storage_contents_info
namespace: ''
plugins:
+ connection:
+ - description: Run tasks in Incus instances via the Incus CLI.
+ name: incus
+ namespace: null
+ filter:
+ - description: Converts INI text input into a dictionary
+ name: from_ini
+ namespace: null
+ - description: Converts a dictionary to the INI file format
+ name: to_ini
+ namespace: null
lookup:
- - description: merge variables with a certain suffix
- name: merge_variables
+ - description: Obtain short-lived Github App Access tokens
+ name: github_app_access_token
namespace: null
- release_date: '2023-03-27'
- 6.6.0:
+ release_date: '2024-01-01'
+ 8.3.0:
changes:
bugfixes:
- - archive - reduce RAM usage by generating CRC32 checksum over chunks (https://github.com/ansible-collections/community.general/pull/6274).
- - flatpak - fixes idempotency detection issues. In some cases the module could
- fail to properly detect already existing Flatpaks because of a parameter witch
- only checks the installed apps (https://github.com/ansible-collections/community.general/pull/6289).
- - icinga2_host - fix the data structure sent to Icinga to make use of host templates
- and template vars (https://github.com/ansible-collections/community.general/pull/6286).
- - idrac_redfish_command - allow user to specify ``resource_id`` for ``CreateBiosConfigJob``
- to specify an exact manager (https://github.com/ansible-collections/community.general/issues/2090).
- - ini_file - make ``section`` parameter not required so it is possible to pass
- ``null`` as a value. This only was possible in the past due to a bug in ansible-core
- that now has been fixed (https://github.com/ansible-collections/community.general/pull/6404).
- - keycloak - improve error messages (https://github.com/ansible-collections/community.general/pull/6318).
- - one_vm - fix syntax error when creating VMs with a more complex template (https://github.com/ansible-collections/community.general/issues/6225).
- - pipx - fixed handling of ``install_deps=true`` with ``state=latest`` and ``state=upgrade``
- (https://github.com/ansible-collections/community.general/pull/6303).
- - redhat_subscription - do not use D-Bus for registering when ``environment``
- is specified, so it possible to specify again the environment names for registering,
- as the D-Bus APIs work only with IDs (https://github.com/ansible-collections/community.general/pull/6319).
- - redhat_subscription - try to unregister only when already registered when
- ``force_register`` is specified (https://github.com/ansible-collections/community.general/issues/6258,
- https://github.com/ansible-collections/community.general/pull/6259).
- - redhat_subscription - use the right D-Bus options for environments when registering
- a CentOS Stream 8 system and using ``environment`` (https://github.com/ansible-collections/community.general/pull/6275).
- - rhsm_release - make ``release`` parameter not required so it is possible to
- pass ``null`` as a value. This only was possible in the past due to a bug
- in ansible-core that now has been fixed (https://github.com/ansible-collections/community.general/pull/6401).
- - rundeck module utils - fix errors caused by the API empty responses (https://github.com/ansible-collections/community.general/pull/6300)
- - rundeck_acl_policy - fix ``TypeError - byte indices must be integers or slices,
- not str`` error caused by empty API response. Update the module to use ``module_utils.rundeck``
- functions (https://github.com/ansible-collections/community.general/pull/5887,
- https://github.com/ansible-collections/community.general/pull/6300).
- - rundeck_project - update the module to use ``module_utils.rundeck`` functions
- (https://github.com/ansible-collections/community.general/issues/5742) (https://github.com/ansible-collections/community.general/pull/6300)
- - snap_alias - module would only recognize snap names containing letter, numbers
- or the underscore character, failing to identify valid snap names such as
- ``lxd.lxc`` (https://github.com/ansible-collections/community.general/pull/6361).
+ - homebrew - detect already installed formulae and casks using JSON output from
+ ``brew info`` (https://github.com/ansible-collections/community.general/issues/864).
+ - incus connection plugin - treats ``inventory_hostname`` as a variable instead
+ of a literal in remote connections (https://github.com/ansible-collections/community.general/issues/7874).
+ - ipa_otptoken - the module expect ``ipatokendisabled`` as string but the ``ipatokendisabled``
+ value is returned as a boolean (https://github.com/ansible-collections/community.general/pull/7795).
+ - ldap - previously the order number (if present) was expected to follow an
+ equals sign in the DN. This makes it so the order number string is identified
+ correctly anywhere within the DN (https://github.com/ansible-collections/community.general/issues/7646).
+ - mssql_script - make the module work with Python 2 (https://github.com/ansible-collections/community.general/issues/7818,
+ https://github.com/ansible-collections/community.general/pull/7821).
+ - nmcli - fix ``connection.slave-type`` wired to ``bond`` and not with parameter
+ ``slave_type`` in case of connection type ``wifi`` (https://github.com/ansible-collections/community.general/issues/7389).
+ - proxmox - fix updating a container config if the setting does not already
+ exist (https://github.com/ansible-collections/community.general/pull/7872).
+ deprecated_features:
+ - consul_acl - the module has been deprecated and will be removed in community.general
+ 10.0.0. ``consul_token`` and ``consul_policy`` can be used instead (https://github.com/ansible-collections/community.general/pull/7901).
minor_changes:
- - cpanm - minor change, use feature from ``ModuleHelper`` (https://github.com/ansible-collections/community.general/pull/6385).
- - 'dconf - be forgiving about boolean values: convert them to GVariant booleans
- automatically (https://github.com/ansible-collections/community.general/pull/6206).'
- - dconf - minor refactoring improving parameters and dependencies validation
- (https://github.com/ansible-collections/community.general/pull/6336).
- - deps module utils - add function ``failed()`` providing the ability to check
- the dependency check result without triggering an exception (https://github.com/ansible-collections/community.general/pull/6383).
- - dig lookup plugin - Support multiple domains to be queried as indicated in
- docs (https://github.com/ansible-collections/community.general/pull/6334).
- - gitlab_project - add new option ``topics`` for adding topics to GitLab projects
- (https://github.com/ansible-collections/community.general/pull/6278).
- - homebrew_cask - allows passing ``--greedy`` option to ``upgrade_all`` (https://github.com/ansible-collections/community.general/pull/6267).
- - idrac_redfish_command - add ``job_id`` to ``CreateBiosConfigJob`` response
- (https://github.com/ansible-collections/community.general/issues/5603).
- - ipa_hostgroup - add ``append`` parameter for adding a new hosts to existing
- hostgroups without changing existing hostgroup members (https://github.com/ansible-collections/community.general/pull/6203).
- - keycloak_authentication - add flow type option to sub flows to allow the creation
- of 'form-flow' sub flows like in Keycloak's built-in registration flow (https://github.com/ansible-collections/community.general/pull/6318).
- - mksysb - improved the output of the module in case of errors (https://github.com/ansible-collections/community.general/issues/6263).
- - nmap inventory plugin - added environment variables for configure ``address``
- and ``exclude`` (https://github.com/ansible-collections/community.general/issues/6351).
- - nmcli - add ``macvlan`` connection type (https://github.com/ansible-collections/community.general/pull/6312).
- - pipx - add ``system_site_packages`` parameter to give application access to
- system-wide packages (https://github.com/ansible-collections/community.general/pull/6308).
- - pipx - ensure ``include_injected`` parameter works with ``state=upgrade``
- and ``state=latest`` (https://github.com/ansible-collections/community.general/pull/6212).
- - puppet - add new options ``skip_tags`` to exclude certain tagged resources
- during a puppet agent or apply (https://github.com/ansible-collections/community.general/pull/6293).
- - terraform - remove state file check condition and error block, because in
- the native implementation of terraform will not cause errors due to the non-existent
- file (https://github.com/ansible-collections/community.general/pull/6296).
- - udm_dns_record - minor refactor to the code (https://github.com/ansible-collections/community.general/pull/6382).
- release_summary: Bugfix and feature release.
+ - consul_auth_method, consul_binding_rule, consul_policy, consul_role, consul_session,
+ consul_token - added action group ``community.general.consul`` (https://github.com/ansible-collections/community.general/pull/7897).
+ - consul_policy - added support for diff and check mode (https://github.com/ansible-collections/community.general/pull/7878).
+ - consul_policy, consul_role, consul_session - removed dependency on ``requests``
+ and factored out common parts (https://github.com/ansible-collections/community.general/pull/7826,
+ https://github.com/ansible-collections/community.general/pull/7878).
+ - consul_role - ``node_identities`` now expects a ``node_name`` option to match
+ the Consul API, the old ``name`` is still supported as alias (https://github.com/ansible-collections/community.general/pull/7878).
+ - consul_role - ``service_identities`` now expects a ``service_name`` option
+ to match the Consul API, the old ``name`` is still supported as alias (https://github.com/ansible-collections/community.general/pull/7878).
+ - consul_role - added support for diff mode (https://github.com/ansible-collections/community.general/pull/7878).
+ - consul_role - added support for templated policies (https://github.com/ansible-collections/community.general/pull/7878).
+ - redfish_info - add command ``GetServiceIdentification`` to get service identification
+ (https://github.com/ansible-collections/community.general/issues/7882).
+ - terraform - add support for ``diff_mode`` for terraform resource_changes (https://github.com/ansible-collections/community.general/pull/7896).
+ release_summary: Regular bugfix and feature release.
fragments:
- - 2090-idrac-redfish-resource-id-fix.yml
- - 5603-redfish-idrac-job-id-in-response.yml
- - 6.6.0.yml
- - 6199-archive-generate-checksum-in-chunks.yml
- - 6203-add-append-option-to-ipa-hostgroup.yml
- - 6206-dconf-booleans.yml
- - 6212-pipx-include-injected.yml
- - 6259-redhat_subscription-fix-force.yaml
- - 6267-homebrew-cask-upgrade-all-greedy.yml
- - 6269-mksysb-output.yml
- - 6275-redhat_subscription-fix-environments-centos.yaml
- - 6277-add-topics-gitlab-project.yml
- - 6286-icinga2_host-template-and-template-vars.yml
- - 6289-bugfix-flatpak-check-if-already-installed.yml
- - 6293-add-puppet-skip-tags-option.yaml
- - 6294-fix-one_vm-instantiation.yml
- - 6296-LanceNero-Terraform_statefile_check.yml
- - 6300-rundeck-modules-fixes-and-improvements.yml
- - 6303-pipx-fix-state-latest-and-add-system-site-packages.yml
- - 6308-pipx-add-system-site-packages.yml
- - 6312-nmcli-add-macvlan-connection-type.yml
- - 6318-add-form-flow.yml
- - 6319-redhat_subscription-fix-environment-parameter.yaml
- - 6334-dig-support-multiple-domains.yml
- - 6336-dconf-refactor.yml
- - 6351-support-env-variables-to-nmap-dynamic-inventoiry.yaml
- - 6361-snap-alias-regex-bugfix.yml
- - 6382-udm-dns-record-refactor.yml
- - 6383-deps-failed.yml
- - 6385-cpan-mh-feat.yml
- - 6401-rhsm_release-required.yml
- - 6404-ini_file-section.yml
+ - 7389-nmcli-issue-with-creating-a-wifi-bridge-slave.yml
+ - 7646-fix-order-number-detection-in-dn.yml
+ - 7797-ipa-fix-otp-idempotency.yml
+ - 7821-mssql_script-py2.yml
+ - 7826-consul-modules-refactoring.yaml
+ - 7870-homebrew-cask-installed-detection.yml
+ - 7872-proxmox_fix-update-if-setting-doesnt-exist.yaml
+ - 7874-incus_connection_treats_inventory_hostname_as_literal_in_remotes.yml
+ - 7882-add-redfish-get-service-identification.yml
+ - 7896-add-terraform-diff-mode.yml
+ - 7897-consul-action-group.yaml
+ - 7901-consul-acl-deprecation.yaml
+ - 8.3.0.yml
modules:
- - description: Query btrfs filesystem info
- name: btrfs_info
+ - description: Bootstrap ACLs in Consul
+ name: consul_acl_bootstrap
+ namespace: ''
+ - description: Manipulate Consul auth methods
+ name: consul_auth_method
namespace: ''
- - description: Manage btrfs subvolumes
- name: btrfs_subvolume
+ - description: Manipulate Consul binding rules
+ name: consul_binding_rule
namespace: ''
- - description: Manages Out-Of-Band controllers using Redfish APIs
- name: ilo_redfish_command
+ - description: Manipulate Consul tokens
+ name: consul_token
namespace: ''
- - description: Allows administration of Keycloak client authorization scopes via
- Keycloak API
- name: keycloak_authz_authorization_scope
+ - description: Creates/updates/deletes GitLab Labels belonging to project or group.
+ name: gitlab_label
namespace: ''
- - description: Set the type of aclientscope in realm or client via Keycloak API
- name: keycloak_clientscope_type
+ - description: Creates/updates/deletes GitLab Milestones belonging to project
+ or group
+ name: gitlab_milestone
namespace: ''
- release_date: '2023-04-24'
- 6.6.1:
+ release_date: '2024-01-29'
+ 8.4.0:
changes:
bugfixes:
- - deps module utils - do not fail when dependency cannot be found (https://github.com/ansible-collections/community.general/pull/6479).
- - nmcli - fix bond option ``xmit_hash_policy`` (https://github.com/ansible-collections/community.general/pull/6527).
- - passwordstore lookup plugin - make compatible with ansible-core 2.16 (https://github.com/ansible-collections/community.general/pull/6447).
- - portage - fix ``changed_use`` and ``newuse`` not triggering rebuilds (https://github.com/ansible-collections/community.general/issues/6008,
- https://github.com/ansible-collections/community.general/pull/6548).
- - 'portage - update the logic for generating the emerge command arguments to
- ensure that ``withbdeps: false`` results in a passing an ``n`` argument with
- the ``--with-bdeps`` emerge flag (https://github.com/ansible-collections/community.general/issues/6451,
- https://github.com/ansible-collections/community.general/pull/6456).'
- - proxmox_tasks_info - remove ``api_user`` + ``api_password`` constraint from
- ``required_together`` as it causes to require ``api_password`` even when API
- token param is used (https://github.com/ansible-collections/community.general/issues/6201).
- - puppet - handling ``noop`` parameter was not working at all, now it is has
- been fixed (https://github.com/ansible-collections/community.general/issues/6452,
- https://github.com/ansible-collections/community.general/issues/6458).
- - terraform - fix broken ``warn()`` call (https://github.com/ansible-collections/community.general/pull/6497).
- - xfs_quota - in case of a project quota, the call to ``xfs_quota`` did not
- initialize/reset the project (https://github.com/ansible-collections/community.general/issues/5143).
- - zypper - added handling of zypper exitcode 102. Changed state is set correctly
- now and rc 102 is still preserved to be evaluated by the playbook (https://github.com/ansible-collections/community.general/pull/6534).
+ - 'cargo - fix idempotency issues when using a custom installation path for
+ packages (using the ``--path`` parameter). The initial installation runs fine,
+ but subsequent runs use the ``get_installed()`` function which did not check
+ the given installation location, before running ``cargo install``. This resulted
+ in a false ``changed`` state. Also the removal of packeges using ``state:
+ absent`` failed, as the installation check did not use the given parameter
+ (https://github.com/ansible-collections/community.general/pull/7970).'
+ - gitlab_issue - fix behavior to search GitLab issue, using ``search`` keyword
+ instead of ``title`` (https://github.com/ansible-collections/community.general/issues/7846).
+ - gitlab_runner - fix pagination when checking for existing runners (https://github.com/ansible-collections/community.general/pull/7790).
+ - keycloak_client - fixes issue when metadata is provided in desired state when
+ task is in check mode (https://github.com/ansible-collections/community.general/issues/1226,
+ https://github.com/ansible-collections/community.general/pull/7881).
+ - modprobe - listing modules files or modprobe files could trigger a FileNotFoundError
+ if ``/etc/modprobe.d`` or ``/etc/modules-load.d`` did not exist. Relevant
+ functions now return empty lists if the directories do not exist to avoid
+ crashing the module (https://github.com/ansible-collections/community.general/issues/7717).
+ - onepassword lookup plugin - failed for fields that were in sections and had
+ uppercase letters in the label/ID. Field lookups are now case insensitive
+ in all cases (https://github.com/ansible-collections/community.general/pull/7919).
+ - pkgin - pkgin (pkgsrc package manager used by SmartOS) raises erratic exceptions
+ and spurious ``changed=true`` (https://github.com/ansible-collections/community.general/pull/7971).
+ - redfish_info - allow for a GET operation invoked by ``GetUpdateStatus`` to
+ allow for an empty response body for cases where a service returns 204 No
+ Content (https://github.com/ansible-collections/community.general/issues/8003).
+ - redfish_info - correct uncaught exception when attempting to retrieve ``Chassis``
+ information (https://github.com/ansible-collections/community.general/pull/7952).
minor_changes:
- - dconf - if ``gi.repository.GLib`` is missing, try to respawn in a Python interpreter
- that has it (https://github.com/ansible-collections/community.general/pull/6491).
- release_summary: Regular bugfix release.
+ - bitwarden lookup plugin - add ``bw_session`` option, to pass session key instead
+ of reading from env (https://github.com/ansible-collections/community.general/pull/7994).
+ - gitlab_deploy_key, gitlab_group_members, gitlab_group_variable, gitlab_hook,
+ gitlab_instance_variable, gitlab_project_badge, gitlab_project_variable, gitlab_user
+ - improve API pagination and compatibility with different versions of ``python-gitlab``
+ (https://github.com/ansible-collections/community.general/pull/7790).
+ - gitlab_hook - adds ``releases_events`` parameter for supporting Releases events
+ triggers on GitLab hooks (https://github.com/ansible-collections/community.general/pull/7956).
+ - icinga2 inventory plugin - add Jinja2 templating support to ``url``, ``user``,
+ and ``password`` paramenters (https://github.com/ansible-collections/community.general/issues/7074,
+ https://github.com/ansible-collections/community.general/pull/7996).
+ - mssql_script - adds transactional (rollback/commit) support via optional boolean
+ param ``transaction`` (https://github.com/ansible-collections/community.general/pull/7976).
+ - proxmox_kvm - add parameter ``update_unsafe`` to avoid limitations when updating
+ dangerous values (https://github.com/ansible-collections/community.general/pull/7843).
+ - redfish_config - add command ``SetServiceIdentification`` to set service identification
+ (https://github.com/ansible-collections/community.general/issues/7916).
+ - sudoers - add support for the ``NOEXEC`` tag in sudoers rules (https://github.com/ansible-collections/community.general/pull/7983).
+ - terraform - fix ``diff_mode`` in state ``absent`` and when terraform ``resource_changes``
+ does not exist (https://github.com/ansible-collections/community.general/pull/7963).
+ release_summary: Regular bugfix and feature release.
fragments:
- - 5143-fix-xfs-quota-project-init.yml
- - 6.6.1.yml
- - 6456-fix-portage-withbdeps-false.yml
- - 6458-puppet-noop.yml
- - 6491-dconf-respawn.yml
- - 6497-terraform-fix.yml
- - 6527-nmcli-bond-fix-xmit_hash_policy.yml
- - 6534-zypper-exitcode-102-handled.yaml
- - 6548-portage-changed_use-newuse.yml
- - 6554-proxmox-tasks-info-fix-required-password.yaml
- - deps.yml
- - passwordstore-lock.yml
- release_date: '2023-05-22'
- 6.6.2:
+ - 7717-prevent-modprobe-error.yml
+ - 7790-gitlab-runner-api-pagination.yml
+ - 7843-proxmox_kvm-update_unsafe.yml
+ - 7847-gitlab-issue-title.yml
+ - 7881-fix-keycloak-client-ckeckmode.yml
+ - 7916-add-redfish-set-service-identification.yml
+ - 7919-onepassword-fieldname-casing.yaml
+ - 7951-fix-redfish_info-exception.yml
+ - 7956-adding-releases_events-option-to-gitlab_hook-module.yaml
+ - 7963-fix-terraform-diff-absent.yml
+ - 7970-fix-cargo-path-idempotency.yaml
+ - 7976-add-mssql_script-transactional-support.yml
+ - 7983-sudoers-add-support-noexec.yml
+ - 7994-bitwarden-session-arg.yaml
+ - 7996-add-templating-support-to-icinga2-inventory.yml
+ - 8.4.0.yml
+ - 8003-redfish-get-update-status-empty-response.yml
+ - pkgin.yml
+ modules:
+ - description: Manages GitLab group access tokens
+ name: gitlab_group_access_token
+ namespace: ''
+ - description: Manages GitLab project access tokens
+ name: gitlab_project_access_token
+ namespace: ''
+ plugins:
+ callback:
+ - description: The default ansible callback without diff output
+ name: default_without_diff
+ namespace: null
+ filter:
+ - description: Difference of lists with a predictive order
+ name: lists_difference
+ namespace: null
+ - description: Intersection of lists with a predictive order
+ name: lists_intersect
+ namespace: null
+ - description: Symmetric Difference of lists with a predictive order
+ name: lists_symmetric_difference
+ namespace: null
+ - description: Union of lists with a predictive order
+ name: lists_union
+ namespace: null
+ release_date: '2024-02-26'
+ 8.5.0:
changes:
bugfixes:
- - csv module utils - detects and remove unicode BOM markers from incoming CSV
- content (https://github.com/ansible-collections/community.general/pull/6662).
- - gitlab_group - the module passed parameters to the API call even when not
- set. The module is now filtering out ``None`` values to remediate this (https://github.com/ansible-collections/community.general/pull/6712).
- - ini_file - fix a bug where the inactive options were not used when possible
- (https://github.com/ansible-collections/community.general/pull/6575).
- - keycloak module utils - fix ``is_struct_included`` handling of lists of lists/dictionaries
- (https://github.com/ansible-collections/community.general/pull/6688).
- - keycloak module utils - the function ``get_user_by_username`` now return the
- user representation or ``None`` as stated in the documentation (https://github.com/ansible-collections/community.general/pull/6758).
- release_summary: Regular bugfix release.
+ - aix_filesystem - fix issue with empty list items in crfs logic and option
+ order (https://github.com/ansible-collections/community.general/pull/8052).
+ - consul_token - fix token creation without ``accessor_id`` (https://github.com/ansible-collections/community.general/pull/8091).
+ - homebrew - error returned from brew command was ignored and tried to parse
+ empty JSON. Fix now checks for an error and raises it to give accurate error
+ message to users (https://github.com/ansible-collections/community.general/issues/8047).
+ - ipa_hbacrule - the module uses a string for ``ipaenabledflag`` for new FreeIPA
+ versions while the returned value is a boolean (https://github.com/ansible-collections/community.general/pull/7880).
+ - ipa_sudorule - the module uses a string for ``ipaenabledflag`` for new FreeIPA
+ versions while the returned value is a boolean (https://github.com/ansible-collections/community.general/pull/7880).
+ - iptables_state - fix idempotency issues when restoring incomplete iptables
+ dumps (https://github.com/ansible-collections/community.general/issues/8029).
+ - linode inventory plugin - add descriptive error message for linode inventory
+ plugin (https://github.com/ansible-collections/community.general/pull/8133).
+ - pacemaker_cluster - actually implement check mode, which the module claims
+ to support. This means that until now the module also did changes in check
+ mode (https://github.com/ansible-collections/community.general/pull/8081).
+ - pam_limits - when the file does not exist, do not create it in check mode
+ (https://github.com/ansible-collections/community.general/issues/8050, https://github.com/ansible-collections/community.general/pull/8057).
+ - proxmox_kvm - fixed status check getting from node-specific API endpoint (https://github.com/ansible-collections/community.general/issues/7817).
+ minor_changes:
+ - bitwarden lookup plugin - allows to fetch all records of a given collection
+ ID, by allowing to pass an empty value for ``search_value`` when ``collection_id``
+ is provided (https://github.com/ansible-collections/community.general/pull/8013).
+ - icinga2 inventory plugin - adds new parameter ``group_by_hostgroups`` in order
+ to make grouping by Icinga2 hostgroups optional (https://github.com/ansible-collections/community.general/pull/7998).
+ - ini_file - support optional spaces between section names and their surrounding
+ brackets (https://github.com/ansible-collections/community.general/pull/8075).
+ - java_cert - enable ``owner``, ``group``, ``mode``, and other generic file
+ arguments (https://github.com/ansible-collections/community.general/pull/8116).
+ - ldap_attrs - module now supports diff mode, showing which attributes are changed
+ within an operation (https://github.com/ansible-collections/community.general/pull/8073).
+ - lxd_container - uses ``/1.0/instances`` API endpoint, if available. Falls
+ back to ``/1.0/containers`` or ``/1.0/virtual-machines``. Fixes issue when
+ using Incus or LXD 5.19 due to migrating to ``/1.0/instances`` endpoint (https://github.com/ansible-collections/community.general/pull/7980).
+ - nmcli - allow setting ``MTU`` for ``bond-slave`` interface types (https://github.com/ansible-collections/community.general/pull/8118).
+ - proxmox - adds ``startup`` parameters to configure startup order, startup
+ delay and shutdown delay (https://github.com/ansible-collections/community.general/pull/8038).
+ - revbitspss lookup plugin - removed a redundant unicode prefix. The prefix
+ was not necessary for Python 3 and has been cleaned up to streamline the code
+ (https://github.com/ansible-collections/community.general/pull/8087).
+ release_summary: Regular feature and bugfix release with security fixes.
+ security_fixes:
+ - cobbler, gitlab_runners, icinga2, linode, lxd, nmap, online, opennebula, proxmox,
+ scaleway, stackpath_compute, virtualbox, and xen_orchestra inventory plugin
+ - make sure all data received from the remote servers is marked as unsafe,
+ so remote code execution by obtaining texts that can be evaluated as templates
+ is not possible (https://www.die-welt.net/2024/03/remote-code-execution-in-ansible-dynamic-inventory-plugins/,
+ https://github.com/ansible-collections/community.general/pull/8098).
fragments:
- - 6.6.2.yml
- - 6568-fix-get-user-by-username-in-keycloak-module-utils.yml
- - 6662-csv-bom.yml
- - 6688-is-struct-included-bug-in-keycloak-py.yml
- - 6712-gitlab_group-filtered-for-none-values.yml
- - ini_file-use-inactive-options-when-possible.yml
- release_date: '2023-06-19'
+ - 7880-ipa-fix-sudo-and-hbcalrule-idempotence.yml
+ - 7953-proxmox_kvm-fix_status_check.yml
+ - 7998-icinga2-inventory-group_by_hostgroups-parameter.yml
+ - 8.5.0.yml
+ - 8013-bitwarden-full-collection-item-list.yaml
+ - 8029-iptables-state-restore-check-mode.yml
+ - 8038-proxmox-startup.yml
+ - 8048-fix-homebrew-module-error-reporting-on-become-true.yaml
+ - 8057-pam_limits-check-mode.yml
+ - 8073-ldap-attrs-diff.yml
+ - 8075-optional-space-around-section-names.yaml
+ - 8087-removed-redundant-unicode-prefixes.yml
+ - 8091-consul-token-fixes.yaml
+ - 8116-java_cert-enable-owner-group-mode-args.yml
+ - 8118-fix-bond-slave-honoring-mtu.yml
+ - 8133-add-error-message-for-linode-inventory-plugin.yaml
+ - aix_filesystem-crfs-issue.yml
+ - inventory-rce.yml
+ - lxd-instances-api-endpoint-added.yml
+ - pacemaker-cluster.yml
+ modules:
+ - description: Allows listing information about USB devices
+ name: usb_facts
+ namespace: ''
+ release_date: '2024-03-25'
diff --git a/ansible_collections/community/general/changelogs/config.yaml b/ansible_collections/community/general/changelogs/config.yaml
index 52e101e11..23afe36d2 100644
--- a/ansible_collections/community/general/changelogs/config.yaml
+++ b/ansible_collections/community/general/changelogs/config.yaml
@@ -12,6 +12,9 @@ mention_ancestor: true
flatmap: true
new_plugins_after_name: removed_features
notesdir: fragments
+output_formats:
+ - md
+ - rst
prelude_section_name: release_summary
prelude_section_title: Release Summary
sections:
diff --git a/ansible_collections/community/general/docs/docsite/extra-docs.yml b/ansible_collections/community/general/docs/docsite/extra-docs.yml
index 2171031ac..529573606 100644
--- a/ansible_collections/community/general/docs/docsite/extra-docs.yml
+++ b/ansible_collections/community/general/docs/docsite/extra-docs.yml
@@ -8,3 +8,9 @@ sections:
toctree:
- filter_guide
- test_guide
+ - title: Cloud Guides
+ toctree:
+ - guide_alicloud
+ - guide_online
+ - guide_packet
+ - guide_scaleway
diff --git a/ansible_collections/community/general/docs/docsite/rst/filter_guide_abstract_informations.rst b/ansible_collections/community/general/docs/docsite/rst/filter_guide_abstract_informations.rst
index 8f997f163..cac85089a 100644
--- a/ansible_collections/community/general/docs/docsite/rst/filter_guide_abstract_informations.rst
+++ b/ansible_collections/community/general/docs/docsite/rst/filter_guide_abstract_informations.rst
@@ -12,4 +12,5 @@ Abstract transformations
filter_guide_abstract_informations_dictionaries
filter_guide_abstract_informations_grouping
filter_guide_abstract_informations_merging_lists_of_dictionaries
+ filter_guide_abstract_informations_lists_helper
filter_guide_abstract_informations_counting_elements_in_sequence
diff --git a/ansible_collections/community/general/docs/docsite/rst/filter_guide_abstract_informations_counting_elements_in_sequence.rst b/ansible_collections/community/general/docs/docsite/rst/filter_guide_abstract_informations_counting_elements_in_sequence.rst
index dcadd5a79..98e8eb1c4 100644
--- a/ansible_collections/community/general/docs/docsite/rst/filter_guide_abstract_informations_counting_elements_in_sequence.rst
+++ b/ansible_collections/community/general/docs/docsite/rst/filter_guide_abstract_informations_counting_elements_in_sequence.rst
@@ -6,7 +6,7 @@
Counting elements in a sequence
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-The ``community.general.counter`` filter plugin allows you to count (hashable) elements in a sequence. Elements are returned as dictionary keys and their counts are stored as dictionary values.
+The :ansplugin:`community.general.counter filter plugin <community.general.counter#filter>` allows you to count (hashable) elements in a sequence. Elements are returned as dictionary keys and their counts are stored as dictionary values.
.. code-block:: yaml+jinja
diff --git a/ansible_collections/community/general/docs/docsite/rst/filter_guide_abstract_informations_dictionaries.rst b/ansible_collections/community/general/docs/docsite/rst/filter_guide_abstract_informations_dictionaries.rst
index 840bd1542..3059b0032 100644
--- a/ansible_collections/community/general/docs/docsite/rst/filter_guide_abstract_informations_dictionaries.rst
+++ b/ansible_collections/community/general/docs/docsite/rst/filter_guide_abstract_informations_dictionaries.rst
@@ -6,7 +6,7 @@
Dictionaries
^^^^^^^^^^^^
-You can use the ``dict_kv`` filter to create a single-entry dictionary with ``value | community.general.dict_kv(key)``:
+You can use the :ansplugin:`community.general.dict_kv filter <community.general.dict_kv#filter>` to create a single-entry dictionary with ``value | community.general.dict_kv(key)``:
.. code-block:: yaml+jinja
@@ -58,7 +58,7 @@ This produces:
.. versionadded:: 2.0.0
-If you need to convert a list of key-value pairs to a dictionary, you can use the ``dict`` function. Unfortunately, this function cannot be used with ``map``. For this, the ``community.general.dict`` filter can be used:
+If you need to convert a list of key-value pairs to a dictionary, you can use the ``dict`` function. Unfortunately, this function cannot be used with ``map``. For this, the :ansplugin:`community.general.dict filter <community.general.dict#filter>` can be used:
.. code-block:: yaml+jinja
diff --git a/ansible_collections/community/general/docs/docsite/rst/filter_guide_abstract_informations_grouping.rst b/ansible_collections/community/general/docs/docsite/rst/filter_guide_abstract_informations_grouping.rst
index 2cea7f9ba..cb1598965 100644
--- a/ansible_collections/community/general/docs/docsite/rst/filter_guide_abstract_informations_grouping.rst
+++ b/ansible_collections/community/general/docs/docsite/rst/filter_guide_abstract_informations_grouping.rst
@@ -6,7 +6,7 @@
Grouping
^^^^^^^^
-If you have a list of dictionaries, the Jinja2 ``groupby`` filter allows to group the list by an attribute. This results in a list of ``(grouper, list)`` namedtuples, where ``list`` contains all dictionaries where the selected attribute equals ``grouper``. If you know that for every ``grouper``, there will be a most one entry in that list, you can use the ``community.general.groupby_as_dict`` filter to convert the original list into a dictionary which maps ``grouper`` to the corresponding dictionary.
+If you have a list of dictionaries, the Jinja2 ``groupby`` filter allows to group the list by an attribute. This results in a list of ``(grouper, list)`` namedtuples, where ``list`` contains all dictionaries where the selected attribute equals ``grouper``. If you know that for every ``grouper``, there will be a most one entry in that list, you can use the :ansplugin:`community.general.groupby_as_dict filter <community.general.groupby_as_dict#filter>` to convert the original list into a dictionary which maps ``grouper`` to the corresponding dictionary.
One example is ``ansible_facts.mounts``, which is a list of dictionaries where each has one ``device`` element to indicate the device which is mounted. Therefore, ``ansible_facts.mounts | community.general.groupby_as_dict('device')`` is a dictionary mapping a device to the mount information:
diff --git a/ansible_collections/community/general/docs/docsite/rst/filter_guide_abstract_informations_lists_helper.rst b/ansible_collections/community/general/docs/docsite/rst/filter_guide_abstract_informations_lists_helper.rst
new file mode 100644
index 000000000..63db10a78
--- /dev/null
+++ b/ansible_collections/community/general/docs/docsite/rst/filter_guide_abstract_informations_lists_helper.rst
@@ -0,0 +1,81 @@
+..
+ Copyright (c) Ansible Project
+ GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+ SPDX-License-Identifier: GPL-3.0-or-later
+
+Union, intersection and difference of lists
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Starting with Ansible Core 2.16, the builtin filters :ansplugin:`ansible.builtin.union#filter`, :ansplugin:`ansible.builtin.intersect#filter`, :ansplugin:`ansible.builtin.difference#filter` and :ansplugin:`ansible.builtin.symmetric_difference#filter` began to behave differently and do no longer preserve the item order. Items in the resulting lists are returned in arbitrary order and the order can vary between subsequent runs.
+
+The Ansible community.general collection provides the following additional list filters:
+
+- :ansplugin:`community.general.lists_union#filter`
+- :ansplugin:`community.general.lists_intersect#filter`
+- :ansplugin:`community.general.lists_difference#filter`
+- :ansplugin:`community.general.lists_symmetric_difference#filter`
+
+These filters preserve the item order, eliminate duplicates and are an extended version of the builtin ones, because they can operate on more than two lists.
+
+.. note:: Stick to the builtin filters, when item order is not important or when you do not need the n-ary operating mode. The builtin filters are faster, because they rely mostly on sets as their underlying datastructure.
+
+Let us use the lists below in the following examples:
+
+.. code-block:: yaml
+
+ A: [9, 5, 7, 1, 9, 4, 10, 5, 9, 7]
+ B: [4, 1, 2, 8, 3, 1, 7]
+ C: [10, 2, 1, 9, 1]
+
+The union of ``A`` and ``B`` can be written as:
+
+.. code-block:: yaml+jinja
+
+ result: "{{ A | community.general.lists_union(B) }}"
+
+This statement produces:
+
+.. code-block:: yaml
+
+ result: [9, 5, 7, 1, 4, 10, 2, 8, 3]
+
+If you want to calculate the intersection of ``A``, ``B`` and ``C``, you can use the following statement:
+
+.. code-block:: yaml+jinja
+
+ result: "{{ A | community.general.lists_intersect(B, C) }}"
+
+Alternatively, you can use a list of lists as an input of the filter
+
+.. code-block:: yaml+jinja
+
+ result: "{{ [A, B] | community.general.lists_intersect(C) }}"
+
+or
+
+.. code-block:: yaml+jinja
+
+ result: "{{ [A, B, C] | community.general.lists_intersect(flatten=true) }}"
+
+All three statements are equivalent and give:
+
+.. code-block:: yaml
+
+ result: [1]
+
+.. note:: Be aware that in most cases, filter calls without any argument require ``flatten=true``, otherwise the input is returned as result. The reason for this is, that the input is considered as a variable argument and is wrapped by an additional outer list. ``flatten=true`` ensures that this list is removed before the input is processed by the filter logic.
+
+The filters ansplugin:`community.general.lists_difference#filter` or :ansplugin:`community.general.lists_symmetric_difference#filter` can be used in the same way as the filters in the examples above. They calculate the difference or the symmetric difference between two or more lists and preserve the item order.
+
+For example, the symmetric difference of ``A``, ``B`` and ``C`` may be written as:
+
+.. code-block:: yaml+jinja
+
+ result: "{{ A | community.general.lists_symmetric_difference(B, C) }}"
+
+This gives:
+
+.. code-block:: yaml
+
+ result: [5, 8, 3, 1]
+
diff --git a/ansible_collections/community/general/docs/docsite/rst/filter_guide_abstract_informations_merging_lists_of_dictionaries.rst b/ansible_collections/community/general/docs/docsite/rst/filter_guide_abstract_informations_merging_lists_of_dictionaries.rst
index 9b56e98d7..06fa79d16 100644
--- a/ansible_collections/community/general/docs/docsite/rst/filter_guide_abstract_informations_merging_lists_of_dictionaries.rst
+++ b/ansible_collections/community/general/docs/docsite/rst/filter_guide_abstract_informations_merging_lists_of_dictionaries.rst
@@ -6,7 +6,7 @@
Merging lists of dictionaries
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-If you have two or more lists of dictionaries and want to combine them into a list of merged dictionaries, where the dictionaries are merged by an attribute, you can use the ``lists_mergeby`` filter.
+If you have two or more lists of dictionaries and want to combine them into a list of merged dictionaries, where the dictionaries are merged by an attribute, you can use the :ansplugin:`community.general.lists_mergeby filter <community.general.lists_mergeby#filter>`.
.. note:: The output of the examples in this section use the YAML callback plugin. Quoting: "Ansible output that can be quite a bit easier to read than the default JSON formatting." See :ref:`the documentation for the community.general.yaml callback plugin <ansible_collections.community.general.yaml_callback>`.
@@ -76,15 +76,15 @@ This produces the same result as in the previous example:
name: meh
-The filter also accepts two optional parameters: ``recursive`` and ``list_merge``. These parameters are only supported when used with ansible-base 2.10 or ansible-core, but not with Ansible 2.9. This is available since community.general 4.4.0.
+The filter also accepts two optional parameters: :ansopt:`community.general.lists_mergeby#filter:recursive` and :ansopt:`community.general.lists_mergeby#filter:list_merge`. This is available since community.general 4.4.0.
**recursive**
- Is a boolean, default to ``False``. Should the ``community.general.lists_mergeby`` recursively merge nested hashes. Note: It does not depend on the value of the ``hash_behaviour`` setting in ``ansible.cfg``.
+ Is a boolean, default to ``false``. Should the :ansplugin:`community.general.lists_mergeby#filter` filter recursively merge nested hashes. Note: It does not depend on the value of the ``hash_behaviour`` setting in ``ansible.cfg``.
**list_merge**
- Is a string, its possible values are ``replace`` (default), ``keep``, ``append``, ``prepend``, ``append_rp`` or ``prepend_rp``. It modifies the behaviour of ``community.general.lists_mergeby`` when the hashes to merge contain arrays/lists.
+ Is a string, its possible values are :ansval:`replace` (default), :ansval:`keep`, :ansval:`append`, :ansval:`prepend`, :ansval:`append_rp` or :ansval:`prepend_rp`. It modifies the behaviour of :ansplugin:`community.general.lists_mergeby#filter` when the hashes to merge contain arrays/lists.
-The examples below set ``recursive=true`` and display the differences among all six options of ``list_merge``. Functionality of the parameters is exactly the same as in the filter ``combine``. See :ref:`Combining hashes/dictionaries <combine_filter>` to learn details about these options.
+The examples below set :ansopt:`community.general.lists_mergeby#filter:recursive=true` and display the differences among all six options of :ansopt:`community.general.lists_mergeby#filter:list_merge`. Functionality of the parameters is exactly the same as in the filter :ansplugin:`ansible.builtin.combine#filter`. See :ref:`Combining hashes/dictionaries <combine_filter>` to learn details about these options.
Let us use the lists below in the following examples
@@ -110,7 +110,7 @@ Let us use the lists below in the following examples
- name: myname02
param01: [3, 4, 4, {key: value}]
-Example ``list_merge=replace`` (default):
+Example :ansopt:`community.general.lists_mergeby#filter:list_merge=replace` (default):
.. code-block:: yaml+jinja
@@ -137,7 +137,7 @@ This produces:
- 4
- key: value
-Example ``list_merge=keep``:
+Example :ansopt:`community.general.lists_mergeby#filter:list_merge=keep`:
.. code-block:: yaml+jinja
@@ -165,7 +165,7 @@ This produces:
- 2
- 3
-Example ``list_merge=append``:
+Example :ansopt:`community.general.lists_mergeby#filter:list_merge=append`:
.. code-block:: yaml+jinja
@@ -198,7 +198,7 @@ This produces:
- 4
- key: value
-Example ``list_merge=prepend``:
+Example :ansopt:`community.general.lists_mergeby#filter:list_merge=prepend`:
.. code-block:: yaml+jinja
@@ -231,7 +231,7 @@ This produces:
- 2
- 3
-Example ``list_merge=append_rp``:
+Example :ansopt:`community.general.lists_mergeby#filter:list_merge=append_rp`:
.. code-block:: yaml+jinja
@@ -263,7 +263,7 @@ This produces:
- 4
- key: value
-Example ``list_merge=prepend_rp``:
+Example :ansopt:`community.general.lists_mergeby#filter:list_merge=prepend_rp`:
.. code-block:: yaml+jinja
diff --git a/ansible_collections/community/general/docs/docsite/rst/filter_guide_conversions.rst b/ansible_collections/community/general/docs/docsite/rst/filter_guide_conversions.rst
index 78970c17b..ca0401762 100644
--- a/ansible_collections/community/general/docs/docsite/rst/filter_guide_conversions.rst
+++ b/ansible_collections/community/general/docs/docsite/rst/filter_guide_conversions.rst
@@ -9,7 +9,7 @@ Conversions
Parsing CSV files
^^^^^^^^^^^^^^^^^
-Ansible offers the :ref:`community.general.read_csv module <ansible_collections.community.general.read_csv_module>` to read CSV files. Sometimes you need to convert strings to CSV files instead. For this, the ``from_csv`` filter exists.
+Ansible offers the :ansplugin:`community.general.read_csv module <community.general.read_csv#module>` to read CSV files. Sometimes you need to convert strings to CSV files instead. For this, the :ansplugin:`community.general.from_csv filter <community.general.from_csv#filter>` exists.
.. code-block:: yaml+jinja
@@ -42,7 +42,7 @@ This produces:
]
}
-The ``from_csv`` filter has several keyword arguments to control its behavior:
+The :ansplugin:`community.general.from_csv filter <community.general.from_csv#filter>` has several keyword arguments to control its behavior:
:dialect: Dialect of the CSV file. Default is ``excel``. Other possible choices are ``excel-tab`` and ``unix``. If one of ``delimiter``, ``skipinitialspace`` or ``strict`` is specified, ``dialect`` is ignored.
:fieldnames: A set of column names to use. If not provided, the first line of the CSV is assumed to contain the column names.
@@ -55,7 +55,7 @@ The ``from_csv`` filter has several keyword arguments to control its behavior:
Converting to JSON
^^^^^^^^^^^^^^^^^^
-`JC <https://pypi.org/project/jc/>`_ is a CLI tool and Python library which allows to interpret output of various CLI programs as JSON. It is also available as a filter in community.general. This filter needs the `jc Python library <https://pypi.org/project/jc/>`_ installed on the controller.
+`JC <https://pypi.org/project/jc/>`_ is a CLI tool and Python library which allows to interpret output of various CLI programs as JSON. It is also available as a filter in community.general, called :ansplugin:`community.general.jc#filter`. This filter needs the `jc Python library <https://pypi.org/project/jc/>`_ installed on the controller.
.. code-block:: yaml+jinja
diff --git a/ansible_collections/community/general/docs/docsite/rst/filter_guide_creating_identifiers.rst b/ansible_collections/community/general/docs/docsite/rst/filter_guide_creating_identifiers.rst
index af0a8b7ba..6e0c730c6 100644
--- a/ansible_collections/community/general/docs/docsite/rst/filter_guide_creating_identifiers.rst
+++ b/ansible_collections/community/general/docs/docsite/rst/filter_guide_creating_identifiers.rst
@@ -11,7 +11,7 @@ The following filters allow to create identifiers.
Hashids
^^^^^^^
-`Hashids <https://hashids.org/>`_ allow to convert sequences of integers to short unique string identifiers. This filter needs the `hashids Python library <https://pypi.org/project/hashids/>`_ installed on the controller.
+`Hashids <https://hashids.org/>`_ allow to convert sequences of integers to short unique string identifiers. The :ansplugin:`community.general.hashids_encode#filter` and :ansplugin:`community.general.hashids_decode#filter` filters need the `hashids Python library <https://pypi.org/project/hashids/>`_ installed on the controller.
.. code-block:: yaml+jinja
@@ -52,7 +52,7 @@ The hashids filters accept keyword arguments to allow fine-tuning the hashids ge
Random MACs
^^^^^^^^^^^
-You can use the ``random_mac`` filter to complete a partial `MAC address <https://en.wikipedia.org/wiki/MAC_address>`_ to a random 6-byte MAC address.
+You can use the :ansplugin:`community.general.random_mac filter <community.general.random_mac#filter>` to complete a partial `MAC address <https://en.wikipedia.org/wiki/MAC_address>`_ to a random 6-byte MAC address.
.. code-block:: yaml+jinja
diff --git a/ansible_collections/community/general/docs/docsite/rst/filter_guide_paths.rst b/ansible_collections/community/general/docs/docsite/rst/filter_guide_paths.rst
index dac893145..41185832f 100644
--- a/ansible_collections/community/general/docs/docsite/rst/filter_guide_paths.rst
+++ b/ansible_collections/community/general/docs/docsite/rst/filter_guide_paths.rst
@@ -6,14 +6,4 @@
Paths
-----
-The ``path_join`` filter has been added in ansible-base 2.10. If you want to use this filter, but also need to support Ansible 2.9, you can use ``community.general``'s ``path_join`` shim, ``community.general.path_join``. This filter redirects to ``path_join`` for ansible-base 2.10 and ansible-core 2.11 or newer, and re-implements the filter for Ansible 2.9.
-
-.. code-block:: yaml+jinja
-
- # ansible-base 2.10 or newer:
- path: {{ ('/etc', path, 'subdir', file) | path_join }}
-
- # Also works with Ansible 2.9:
- path: {{ ('/etc', path, 'subdir', file) | community.general.path_join }}
-
-.. versionadded:: 3.0.0
+The :ansplugin:`ansible.builtin.path_join filter <ansible.builtin.path_join#filter>` has been added in ansible-base 2.10. Community.general 3.0.0 and newer contains an alias ``community.general.path_join`` for this filter that could be used on Ansible 2.9 as well. Since community.general no longer supports Ansible 2.9, this is now a simple redirect to :ansplugin:`ansible.builtin.path_join filter <ansible.builtin.path_join#filter>`.
diff --git a/ansible_collections/community/general/docs/docsite/rst/filter_guide_selecting_json_data.rst b/ansible_collections/community/general/docs/docsite/rst/filter_guide_selecting_json_data.rst
index d8de07b92..73dbf985b 100644
--- a/ansible_collections/community/general/docs/docsite/rst/filter_guide_selecting_json_data.rst
+++ b/ansible_collections/community/general/docs/docsite/rst/filter_guide_selecting_json_data.rst
@@ -8,7 +8,7 @@
Selecting JSON data: JSON queries
---------------------------------
-To select a single element or a data subset from a complex data structure in JSON format (for example, Ansible facts), use the ``json_query`` filter. The ``json_query`` filter lets you query a complex JSON structure and iterate over it using a loop structure.
+To select a single element or a data subset from a complex data structure in JSON format (for example, Ansible facts), use the :ansplugin:`community.general.json_query filter <community.general.json_query#filter>`. The :ansplugin:`community.general.json_query#filter` filter lets you query a complex JSON structure and iterate over it using a loop structure.
.. note:: You must manually install the **jmespath** dependency on the Ansible controller before using this filter. This filter is built upon **jmespath**, and you can use the same syntax. For examples, see `jmespath examples <http://jmespath.org/examples.html>`_.
@@ -146,4 +146,4 @@ To extract ports from all clusters with name containing 'server1':
vars:
server_name_query: "domain.server[?contains(name,'server1')].port"
-.. note:: while using ``starts_with`` and ``contains``, you have to use `` to_json | from_json `` filter for correct parsing of data structure.
+.. note:: while using ``starts_with`` and ``contains``, you have to use ``to_json | from_json`` filter for correct parsing of data structure.
diff --git a/ansible_collections/community/general/docs/docsite/rst/filter_guide_working_with_times.rst b/ansible_collections/community/general/docs/docsite/rst/filter_guide_working_with_times.rst
index dc68f2a2e..032d44bb5 100644
--- a/ansible_collections/community/general/docs/docsite/rst/filter_guide_working_with_times.rst
+++ b/ansible_collections/community/general/docs/docsite/rst/filter_guide_working_with_times.rst
@@ -6,9 +6,9 @@
Working with times
------------------
-The ``to_time_unit`` filter allows to convert times from a human-readable string to a unit. For example, ``'4h 30min 12second' | community.general.to_time_unit('hour')`` gives the number of hours that correspond to 4 hours, 30 minutes and 12 seconds.
+The :ansplugin:`community.general.to_time_unit filter <community.general.to_time_unit#filter>` allows to convert times from a human-readable string to a unit. For example, ``'4h 30min 12second' | community.general.to_time_unit('hour')`` gives the number of hours that correspond to 4 hours, 30 minutes and 12 seconds.
-There are shorthands to directly convert to various units, like ``to_hours``, ``to_minutes``, ``to_seconds``, and so on. The following table lists all units that can be used:
+There are shorthands to directly convert to various units, like :ansplugin:`community.general.to_hours#filter`, :ansplugin:`community.general.to_minutes#filter`, :ansplugin:`community.general.to_seconds#filter`, and so on. The following table lists all units that can be used:
.. list-table:: Units
:widths: 25 25 25 25
@@ -21,37 +21,37 @@ There are shorthands to directly convert to various units, like ``to_hours``, ``
* - Millisecond
- 1/1000 second
- ``ms``, ``millisecond``, ``milliseconds``, ``msec``, ``msecs``, ``msecond``, ``mseconds``
- - ``to_milliseconds``
+ - :ansplugin:`community.general.to_milliseconds#filter`
* - Second
- 1 second
- ``s``, ``sec``, ``secs``, ``second``, ``seconds``
- - ``to_seconds``
+ - :ansplugin:`community.general.to_seconds#filter`
* - Minute
- 60 seconds
- ``m``, ``min``, ``mins``, ``minute``, ``minutes``
- - ``to_minutes``
+ - :ansplugin:`community.general.to_minutes#filter`
* - Hour
- 60*60 seconds
- ``h``, ``hour``, ``hours``
- - ``to_hours``
+ - :ansplugin:`community.general.to_hours#filter`
* - Day
- 24*60*60 seconds
- ``d``, ``day``, ``days``
- - ``to_days``
+ - :ansplugin:`community.general.to_days#filter`
* - Week
- 7*24*60*60 seconds
- ``w``, ``week``, ``weeks``
- - ``to_weeks``
+ - :ansplugin:`community.general.to_weeks#filter`
* - Month
- 30*24*60*60 seconds
- ``mo``, ``month``, ``months``
- - ``to_months``
+ - :ansplugin:`community.general.to_months#filter`
* - Year
- 365*24*60*60 seconds
- ``y``, ``year``, ``years``
- - ``to_years``
+ - :ansplugin:`community.general.to_years#filter`
-Note that months and years are using a simplified representation: a month is 30 days, and a year is 365 days. If you need different definitions of months or years, you can pass them as keyword arguments. For example, if you want a year to be 365.25 days, and a month to be 30.5 days, you can write ``'11months 4' | community.general.to_years(year=365.25, month=30.5)``. These keyword arguments can be specified to ``to_time_unit`` and to all shorthand filters.
+Note that months and years are using a simplified representation: a month is 30 days, and a year is 365 days. If you need different definitions of months or years, you can pass them as keyword arguments. For example, if you want a year to be 365.25 days, and a month to be 30.5 days, you can write ``'11months 4' | community.general.to_years(year=365.25, month=30.5)``. These keyword arguments can be specified to :ansplugin:`community.general.to_time_unit#filter` and to all shorthand filters.
.. code-block:: yaml+jinja
diff --git a/ansible_collections/community/general/docs/docsite/rst/filter_guide_working_with_unicode.rst b/ansible_collections/community/general/docs/docsite/rst/filter_guide_working_with_unicode.rst
index 2e5a67f8f..e75b0f871 100644
--- a/ansible_collections/community/general/docs/docsite/rst/filter_guide_working_with_unicode.rst
+++ b/ansible_collections/community/general/docs/docsite/rst/filter_guide_working_with_unicode.rst
@@ -6,9 +6,9 @@
Working with Unicode
---------------------
-`Unicode <https://unicode.org/main.html>`_ makes it possible to produce two strings which may be visually equivalent, but are comprised of distinctly different characters/character sequences. To address this ``Unicode`` defines `normalization forms <https://unicode.org/reports/tr15/>`_ which avoid these distinctions by choosing a unique character sequence for a given visual representation.
+`Unicode <https://unicode.org/main.html>`_ makes it possible to produce two strings which may be visually equivalent, but are comprised of distinctly different characters/character sequences. To address this Unicode defines `normalization forms <https://unicode.org/reports/tr15/>`_ which avoid these distinctions by choosing a unique character sequence for a given visual representation.
-You can use the ``community.general.unicode_normalize`` filter to normalize ``Unicode`` strings within your playbooks.
+You can use the :ansplugin:`community.general.unicode_normalize filter <community.general.unicode_normalize#filter>` to normalize Unicode strings within your playbooks.
.. code-block:: yaml+jinja
@@ -28,7 +28,7 @@ This produces:
"msg": true
}
-The ``community.general.unicode_normalize`` filter accepts a keyword argument to select the ``Unicode`` form used to normalize the input string.
+The :ansplugin:`community.general.unicode_normalize filter <community.general.unicode_normalize#filter>` accepts a keyword argument :ansopt:`community.general.unicode_normalize#filter:form` to select the Unicode form used to normalize the input string.
:form: One of ``'NFC'`` (default), ``'NFD'``, ``'NFKC'``, or ``'NFKD'``. See the `Unicode reference <https://unicode.org/reports/tr15/>`_ for more information.
diff --git a/ansible_collections/community/general/docs/docsite/rst/filter_guide_working_with_versions.rst b/ansible_collections/community/general/docs/docsite/rst/filter_guide_working_with_versions.rst
index 2488427b7..055bbcd21 100644
--- a/ansible_collections/community/general/docs/docsite/rst/filter_guide_working_with_versions.rst
+++ b/ansible_collections/community/general/docs/docsite/rst/filter_guide_working_with_versions.rst
@@ -6,7 +6,7 @@
Working with versions
---------------------
-If you need to sort a list of version numbers, the Jinja ``sort`` filter is problematic. Since it sorts lexicographically, ``2.10`` will come before ``2.9``. To treat version numbers correctly, you can use the ``version_sort`` filter:
+If you need to sort a list of version numbers, the Jinja ``sort`` filter is problematic. Since it sorts lexicographically, ``2.10`` will come before ``2.9``. To treat version numbers correctly, you can use the :ansplugin:`community.general.version_sort filter <community.general.version_sort#filter>`:
.. code-block:: yaml+jinja
diff --git a/ansible_collections/community/general/docs/docsite/rst/guide_alicloud.rst b/ansible_collections/community/general/docs/docsite/rst/guide_alicloud.rst
new file mode 100644
index 000000000..f38bd8df6
--- /dev/null
+++ b/ansible_collections/community/general/docs/docsite/rst/guide_alicloud.rst
@@ -0,0 +1,96 @@
+..
+ Copyright (c) Ansible Project
+ GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+ SPDX-License-Identifier: GPL-3.0-or-later
+
+.. _ansible_collections.community.general.docsite.guide_alicloud:
+
+Alibaba Cloud Compute Services Guide
+====================================
+
+Introduction
+````````````
+
+The community.general collection contains several modules for controlling and managing Alibaba Cloud Compute Services (Alicloud). This guide
+explains how to use the Alicloud Ansible modules together.
+
+All Alicloud modules require ``footmark`` - install it on your control machine with ``pip install footmark``.
+
+Cloud modules, including Alicloud modules, are usually executed on your local machine (the control machine) with ``connection: local``, rather than on remote machines defined in your hosts.
+
+Normally, you'll use the following pattern for plays that provision Alicloud resources:
+
+.. code-block:: yaml
+
+ - hosts: localhost
+ connection: local
+ vars:
+ - ...
+ tasks:
+ - ...
+
+Authentication
+``````````````
+
+You can specify your Alicloud authentication credentials (access key and secret key) by passing them as
+environment variables or by storing them in a vars file.
+
+To pass authentication credentials as environment variables:
+
+.. code-block:: console
+
+ export ALICLOUD_ACCESS_KEY='Alicloud123'
+ export ALICLOUD_SECRET_KEY='AlicloudSecret123'
+
+To store authentication credentials in a vars file, encrypt them with :ref:`Ansible Vault <vault>` to keep them secure, then list them:
+
+.. code-block:: yaml
+
+ ---
+ alicloud_access_key: "--REMOVED--"
+ alicloud_secret_key: "--REMOVED--"
+
+Note that if you store your credentials in a vars file, you need to refer to them in each Alicloud module. For example:
+
+.. code-block:: yaml+jinja
+
+ - community.general.ali_instance:
+ alicloud_access_key: "{{ alicloud_access_key }}"
+ alicloud_secret_key: "{{ alicloud_secret_key }}"
+ image_id: "..."
+
+Provisioning
+````````````
+
+Alicloud modules create Alicloud ECS instances (:ansplugin:`community.general.ali_instance#module`) and retrieve information on these (:ansplugin:`community.general.ali_instance_info#module`).
+
+You can use the ``count`` parameter to control the number of resources you create or terminate. For example, if you want exactly 5 instances tagged ``NewECS``, set the ``count`` of instances to 5 and the ``count_tag`` to ``NewECS``, as shown in the last task of the example playbook below. If there are no instances with the tag ``NewECS``, the task creates 5 new instances. If there are 2 instances with that tag, the task creates 3 more. If there are 8 instances with that tag, the task terminates 3 of those instances.
+
+If you do not specify a ``count_tag``, the task creates the number of instances you specify in ``count`` with the ``instance_name`` you provide.
+
+.. code-block:: yaml+jinja
+
+ # alicloud_setup.yml
+
+ - hosts: localhost
+ connection: local
+
+ tasks:
+ - name: Create a set of instances
+ community.general.ali_instance:
+ instance_type: ecs.n4.small
+ image_id: "{{ ami_id }}"
+ instance_name: "My-new-instance"
+ instance_tags:
+ Name: NewECS
+ Version: 0.0.1
+ count: 5
+ count_tag:
+ Name: NewECS
+ allocate_public_ip: true
+ max_bandwidth_out: 50
+ register: create_instance
+
+In the example playbook above, data about the instances created by this playbook is saved in the variable defined by the ``register`` keyword in the task.
+
+Each Alicloud module offers a variety of parameter options. Not all options are demonstrated in the above example. See each individual module for further details and examples.
diff --git a/ansible_collections/community/general/docs/docsite/rst/guide_online.rst b/ansible_collections/community/general/docs/docsite/rst/guide_online.rst
new file mode 100644
index 000000000..c233b403e
--- /dev/null
+++ b/ansible_collections/community/general/docs/docsite/rst/guide_online.rst
@@ -0,0 +1,49 @@
+..
+ Copyright (c) Ansible Project
+ GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+ SPDX-License-Identifier: GPL-3.0-or-later
+
+.. _ansible_collections.community.general.docsite.guide_online:
+
+****************
+Online.net Guide
+****************
+
+Introduction
+============
+
+Online is a French hosting company mainly known for providing bare-metal servers named Dedibox.
+Check it out: `https://www.online.net/en <https://www.online.net/en>`_
+
+Dynamic inventory for Online resources
+--------------------------------------
+
+Ansible has a dynamic inventory plugin that can list your resources.
+
+1. Create a YAML configuration such as ``online_inventory.yml`` with this content:
+
+ .. code-block:: yaml
+
+ plugin: community.general.online
+
+2. Set your ``ONLINE_TOKEN`` environment variable with your token.
+
+ You need to open an account and log into it before you can get a token.
+ You can find your token at the following page: `https://console.online.net/en/api/access <https://console.online.net/en/api/access>`_
+
+3. You can test that your inventory is working by running:
+
+ .. code-block:: console
+
+ $ ansible-inventory -v -i online_inventory.yml --list
+
+
+4. Now you can run your playbook or any other module with this inventory:
+
+ .. code-block:: ansible-output
+
+ $ ansible all -i online_inventory.yml -m ping
+ sd-96735 | SUCCESS => {
+ "changed": false,
+ "ping": "pong"
+ }
diff --git a/ansible_collections/community/general/docs/docsite/rst/guide_packet.rst b/ansible_collections/community/general/docs/docsite/rst/guide_packet.rst
new file mode 100644
index 000000000..9de5e3f61
--- /dev/null
+++ b/ansible_collections/community/general/docs/docsite/rst/guide_packet.rst
@@ -0,0 +1,214 @@
+..
+ Copyright (c) Ansible Project
+ GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+ SPDX-License-Identifier: GPL-3.0-or-later
+
+.. _ansible_collections.community.general.docsite.guide_packet:
+
+**********************************
+Packet.net Guide
+**********************************
+
+Introduction
+============
+
+`Packet.net <https://packet.net>`_ is a bare metal infrastructure host that is supported by the community.general collection through six cloud modules. The six modules are:
+
+- :ansplugin:`community.general.packet_device#module`: manages servers on Packet. You can use this module to create, restart and delete devices.
+- :ansplugin:`community.general.packet_ip_subnet#module`: assign IP subnet to a bare metal server
+- :ansplugin:`community.general.packet_project#module`: create/delete a project in Packet host
+- :ansplugin:`community.general.packet_sshkey#module`: adds a public SSH key from file or value to the Packet infrastructure. Every subsequently-created device will have this public key installed in .ssh/authorized_keys.
+- :ansplugin:`community.general.packet_volume#module`: create/delete a volume in Packet host
+- :ansplugin:`community.general.packet_volume_attachment#module`: attach/detach a volume to a device in the Packet host
+
+Note, this guide assumes you are familiar with Ansible and how it works. If you are not, have a look at their :ref:`docs <ansible_documentation>` before getting started.
+
+Requirements
+============
+
+The Packet modules connect to the Packet API using the `packet-python package <https://pypi.org/project/packet-python/>`_. You can install it with pip:
+
+.. code-block:: console
+
+ $ pip install packet-python
+
+In order to check the state of devices created by Ansible on Packet, it is a good idea to install one of the `Packet CLI clients <https://www.packet.net/developers/integrations/>`_. Otherwise you can check them through the `Packet portal <https://app.packet.net/portal>`_.
+
+To use the modules you will need a Packet API token. You can generate an API token through the Packet portal `here <https://app.packet.net/portal#/api-keys>`__. The simplest way to authenticate yourself is to set the Packet API token in an environment variable:
+
+.. code-block:: console
+
+ $ export PACKET_API_TOKEN=Bfse9F24SFtfs423Gsd3ifGsd43sSdfs
+
+If you are not comfortable exporting your API token, you can pass it as a parameter to the modules.
+
+On Packet, devices and reserved IP addresses belong to `projects <https://www.packet.com/developers/api/#projects>`_. In order to use the packet_device module, you need to specify the UUID of the project in which you want to create or manage devices. You can find a project's UUID in the Packet portal `here <https://app.packet.net/portal#/projects/list/table/>`_ (it is just under the project table) or through one of the available `CLIs <https://www.packet.net/developers/integrations/>`_.
+
+
+If you want to use a new SSH key pair in this tutorial, you can generate it to ``./id_rsa`` and ``./id_rsa.pub`` as:
+
+.. code-block:: console
+
+ $ ssh-keygen -t rsa -f ./id_rsa
+
+If you want to use an existing key pair, just copy the private and public key over to the playbook directory.
+
+
+Device Creation
+===============
+
+The following code block is a simple playbook that creates one `Type 0 <https://www.packet.com/cloud/servers/t1-small/>`_ server (the ``plan`` parameter). You have to supply ``plan`` and ``operating_system``. ``location`` defaults to ``ewr1`` (Parsippany, NJ). You can find all the possible values for the parameters through a `CLI client <https://www.packet.net/developers/integrations/>`_.
+
+.. code-block:: yaml+jinja
+
+ # playbook_create.yml
+
+ - name: Create Ubuntu device
+ hosts: localhost
+ tasks:
+
+ - community.general.packet_sshkey:
+ key_file: ./id_rsa.pub
+ label: tutorial key
+
+ - community.general.packet_device:
+ project_id: <your_project_id>
+ hostnames: myserver
+ operating_system: ubuntu_16_04
+ plan: baremetal_0
+ facility: sjc1
+
+After running ``ansible-playbook playbook_create.yml``, you should have a server provisioned on Packet. You can verify through a CLI or in the `Packet portal <https://app.packet.net/portal#/projects/list/table>`__.
+
+If you get an error with the message "failed to set machine state present, error: Error 404: Not Found", please verify your project UUID.
+
+
+Updating Devices
+================
+
+The two parameters used to uniquely identify Packet devices are: "device_ids" and "hostnames". Both parameters accept either a single string (later converted to a one-element list), or a list of strings.
+
+The ``device_ids`` and ``hostnames`` parameters are mutually exclusive. The following values are all acceptable:
+
+- device_ids: ``a27b7a83-fc93-435b-a128-47a5b04f2dcf``
+
+- hostnames: ``mydev1``
+
+- device_ids: ``[a27b7a83-fc93-435b-a128-47a5b04f2dcf, 4887130f-0ccd-49a0-99b0-323c1ceb527b]``
+
+- hostnames: ``[mydev1, mydev2]``
+
+In addition, hostnames can contain a special ``%d`` formatter along with a ``count`` parameter that lets you easily expand hostnames that follow a simple name and number pattern; in other words, ``hostnames: "mydev%d", count: 2`` will expand to [mydev1, mydev2].
+
+If your playbook acts on existing Packet devices, you can only pass the ``hostname`` and ``device_ids`` parameters. The following playbook shows how you can reboot a specific Packet device by setting the ``hostname`` parameter:
+
+.. code-block:: yaml+jinja
+
+ # playbook_reboot.yml
+
+ - name: reboot myserver
+ hosts: localhost
+ tasks:
+
+ - community.general.packet_device:
+ project_id: <your_project_id>
+ hostnames: myserver
+ state: rebooted
+
+You can also identify specific Packet devices with the ``device_ids`` parameter. The device's UUID can be found in the `Packet Portal <https://app.packet.net/portal>`_ or by using a `CLI <https://www.packet.net/developers/integrations/>`_. The following playbook removes a Packet device using the ``device_ids`` field:
+
+.. code-block:: yaml+jinja
+
+ # playbook_remove.yml
+
+ - name: remove a device
+ hosts: localhost
+ tasks:
+
+ - community.general.packet_device:
+ project_id: <your_project_id>
+ device_ids: <myserver_device_id>
+ state: absent
+
+
+More Complex Playbooks
+======================
+
+In this example, we will create a CoreOS cluster with `user data <https://packet.com/developers/docs/servers/key-features/user-data/>`_.
+
+
+The CoreOS cluster will use `etcd <https://etcd.io/>`_ for discovery of other servers in the cluster. Before provisioning your servers, you will need to generate a discovery token for your cluster:
+
+.. code-block:: console
+
+ $ curl -w "\n" 'https://discovery.etcd.io/new?size=3'
+
+The following playbook will create an SSH key, 3 Packet servers, and then wait until SSH is ready (or until 5 minutes passed). Make sure to substitute the discovery token URL in ``user_data``, and the ``project_id`` before running ``ansible-playbook``. Also, feel free to change ``plan`` and ``facility``.
+
+.. code-block:: yaml+jinja
+
+ # playbook_coreos.yml
+
+ - name: Start 3 CoreOS nodes in Packet and wait until SSH is ready
+ hosts: localhost
+ tasks:
+
+ - community.general.packet_sshkey:
+ key_file: ./id_rsa.pub
+ label: new
+
+ - community.general.packet_device:
+ hostnames: [coreos-one, coreos-two, coreos-three]
+ operating_system: coreos_beta
+ plan: baremetal_0
+ facility: ewr1
+ project_id: <your_project_id>
+ wait_for_public_IPv: 4
+ user_data: |
+ #cloud-config
+ coreos:
+ etcd2:
+ discovery: https://discovery.etcd.io/<token>
+ advertise-client-urls: http://$private_ipv4:2379,http://$private_ipv4:4001
+ initial-advertise-peer-urls: http://$private_ipv4:2380
+ listen-client-urls: http://0.0.0.0:2379,http://0.0.0.0:4001
+ listen-peer-urls: http://$private_ipv4:2380
+ fleet:
+ public-ip: $private_ipv4
+ units:
+ - name: etcd2.service
+ command: start
+ - name: fleet.service
+ command: start
+ register: newhosts
+
+ - name: wait for ssh
+ ansible.builtin.wait_for:
+ delay: 1
+ host: "{{ item.public_ipv4 }}"
+ port: 22
+ state: started
+ timeout: 500
+ loop: "{{ newhosts.results[0].devices }}"
+
+
+As with most Ansible modules, the default states of the Packet modules are idempotent, meaning the resources in your project will remain the same after re-runs of a playbook. Thus, we can keep the ``packet_sshkey`` module call in our playbook. If the public key is already in your Packet account, the call will have no effect.
+
+The second module call provisions 3 Packet Type 0 (specified using the ``plan`` parameter) servers in the project identified by the ``project_id`` parameter. The servers are all provisioned with CoreOS beta (the ``operating_system`` parameter) and are customized with cloud-config user data passed to the ``user_data`` parameter.
+
+The ``packet_device`` module has a ``wait_for_public_IPv`` that is used to specify the version of the IP address to wait for (valid values are ``4`` or ``6`` for IPv4 or IPv6). If specified, Ansible will wait until the GET API call for a device contains an Internet-routeable IP address of the specified version. When referring to an IP address of a created device in subsequent module calls, it is wise to use the ``wait_for_public_IPv`` parameter, or ``state: active`` in the packet_device module call.
+
+Run the playbook:
+
+.. code-block:: console
+
+ $ ansible-playbook playbook_coreos.yml
+
+Once the playbook quits, your new devices should be reachable through SSH. Try to connect to one and check if etcd has started properly:
+
+.. code-block:: console
+
+ tomk@work $ ssh -i id_rsa core@$one_of_the_servers_ip
+ core@coreos-one ~ $ etcdctl cluster-health
+
+If you have any questions or comments let us know! help@packet.net
diff --git a/ansible_collections/community/general/docs/docsite/rst/guide_scaleway.rst b/ansible_collections/community/general/docs/docsite/rst/guide_scaleway.rst
new file mode 100644
index 000000000..f3b7b24e0
--- /dev/null
+++ b/ansible_collections/community/general/docs/docsite/rst/guide_scaleway.rst
@@ -0,0 +1,320 @@
+..
+ Copyright (c) Ansible Project
+ GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+ SPDX-License-Identifier: GPL-3.0-or-later
+
+.. _ansible_collections.community.general.docsite.guide_scaleway:
+
+**************
+Scaleway Guide
+**************
+
+Introduction
+============
+
+`Scaleway <https://scaleway.com>`_ is a cloud provider supported by the community.general collection through a set of plugins and modules.
+Those modules are:
+
+- :ansplugin:`community.general.scaleway_compute#module`: manages servers on Scaleway. You can use this module to create, restart and delete servers.
+- :ansplugin:`community.general.scaleway_compute_private_network#module`
+- :ansplugin:`community.general.scaleway_container#module`
+- :ansplugin:`community.general.scaleway_container_info#module`
+- :ansplugin:`community.general.scaleway_container_namespace_info#module`
+- :ansplugin:`community.general.scaleway_container_namespace#module`
+- :ansplugin:`community.general.scaleway_container_registry_info#module`
+- :ansplugin:`community.general.scaleway_container_registry#module`
+- :ansplugin:`community.general.scaleway_database_backup#module`
+- :ansplugin:`community.general.scaleway_function#module`
+- :ansplugin:`community.general.scaleway_function_info#module`
+- :ansplugin:`community.general.scaleway_function_namespace_info#module`
+- :ansplugin:`community.general.scaleway_function_namespace#module`
+- :ansplugin:`community.general.scaleway_image_info#module`
+- :ansplugin:`community.general.scaleway_ip#module`
+- :ansplugin:`community.general.scaleway_ip_info#module`
+- :ansplugin:`community.general.scaleway_lb#module`
+- :ansplugin:`community.general.scaleway_organization_info#module`
+- :ansplugin:`community.general.scaleway_private_network#module`
+- :ansplugin:`community.general.scaleway_security_group#module`
+- :ansplugin:`community.general.scaleway_security_group_info#module`
+- :ansplugin:`community.general.scaleway_security_group_rule#module`
+- :ansplugin:`community.general.scaleway_server_info#module`
+- :ansplugin:`community.general.scaleway_snapshot_info#module`
+- :ansplugin:`community.general.scaleway_sshkey#module`: adds a public SSH key from a file or value to the Packet infrastructure. Every subsequently-created device will have this public key installed in .ssh/authorized_keys.
+- :ansplugin:`community.general.scaleway_user_data#module`
+- :ansplugin:`community.general.scaleway_volume#module`: manages volumes on Scaleway.
+- :ansplugin:`community.general.scaleway_volume_info#module`
+
+The plugins are:
+
+- :ansplugin:`community.general.scaleway#inventory`: inventory plugin
+
+
+.. note::
+ This guide assumes you are familiar with Ansible and how it works.
+ If you are not, have a look at :ref:`ansible_documentation` before getting started.
+
+Requirements
+============
+
+The Scaleway modules and inventory script connect to the Scaleway API using `Scaleway REST API <https://developer.scaleway.com>`_.
+To use the modules and inventory script you will need a Scaleway API token.
+You can generate an API token through the `Scaleway console's credential page <https://cloud.scaleway.com/#/credentials>`__.
+The simplest way to authenticate yourself is to set the Scaleway API token in an environment variable:
+
+.. code-block:: console
+
+ $ export SCW_TOKEN=00000000-1111-2222-3333-444444444444
+
+If you are not comfortable exporting your API token, you can pass it as a parameter to the modules using the ``api_token`` argument.
+
+If you want to use a new SSH key pair in this tutorial, you can generate it to ``./id_rsa`` and ``./id_rsa.pub`` as:
+
+.. code-block:: console
+
+ $ ssh-keygen -t rsa -f ./id_rsa
+
+If you want to use an existing key pair, just copy the private and public key over to the playbook directory.
+
+How to add an SSH key?
+======================
+
+Connection to Scaleway Compute nodes use Secure Shell.
+SSH keys are stored at the account level, which means that you can reuse the same SSH key in multiple nodes.
+The first step to configure Scaleway compute resources is to have at least one SSH key configured.
+
+:ansplugin:`community.general.scaleway_sshkey#module` is a module that manages SSH keys on your Scaleway account.
+You can add an SSH key to your account by including the following task in a playbook:
+
+.. code-block:: yaml+jinja
+
+ - name: "Add SSH key"
+ community.general.scaleway_sshkey:
+ ssh_pub_key: "ssh-rsa AAAA..."
+ state: "present"
+
+The ``ssh_pub_key`` parameter contains your ssh public key as a string. Here is an example inside a playbook:
+
+
+.. code-block:: yaml+jinja
+
+ - name: Test SSH key lifecycle on a Scaleway account
+ hosts: localhost
+ gather_facts: false
+ environment:
+ SCW_API_KEY: ""
+
+ tasks:
+
+ - community.general.scaleway_sshkey:
+ ssh_pub_key: "ssh-rsa AAAAB...424242 developer@example.com"
+ state: present
+ register: result
+
+ - ansible.builtin.assert:
+ that:
+ - result is success and result is changed
+
+How to create a compute instance?
+=================================
+
+Now that we have an SSH key configured, the next step is to spin up a server!
+:ansplugin:`community.general.scaleway_compute#module` is a module that can create, update and delete Scaleway compute instances:
+
+.. code-block:: yaml+jinja
+
+ - name: Create a server
+ community.general.scaleway_compute:
+ name: foobar
+ state: present
+ image: 00000000-1111-2222-3333-444444444444
+ organization: 00000000-1111-2222-3333-444444444444
+ region: ams1
+ commercial_type: START1-S
+
+Here are the parameter details for the example shown above:
+
+- ``name`` is the name of the instance (the one that will show up in your web console).
+- ``image`` is the UUID of the system image you would like to use.
+ A list of all images is available for each availability zone.
+- ``organization`` represents the organization that your account is attached to.
+- ``region`` represents the Availability Zone which your instance is in (for this example, ``par1`` and ``ams1``).
+- ``commercial_type`` represents the name of the commercial offers.
+ You can check out the Scaleway pricing page to find which instance is right for you.
+
+Take a look at this short playbook to see a working example using ``scaleway_compute``:
+
+.. code-block:: yaml+jinja
+
+ - name: Test compute instance lifecycle on a Scaleway account
+ hosts: localhost
+ gather_facts: false
+ environment:
+ SCW_API_KEY: ""
+
+ tasks:
+
+ - name: Create a server
+ register: server_creation_task
+ community.general.scaleway_compute:
+ name: foobar
+ state: present
+ image: 00000000-1111-2222-3333-444444444444
+ organization: 00000000-1111-2222-3333-444444444444
+ region: ams1
+ commercial_type: START1-S
+ wait: true
+
+ - ansible.builtin.debug:
+ var: server_creation_task
+
+ - ansible.builtin.assert:
+ that:
+ - server_creation_task is success
+ - server_creation_task is changed
+
+ - name: Run it
+ community.general.scaleway_compute:
+ name: foobar
+ state: running
+ image: 00000000-1111-2222-3333-444444444444
+ organization: 00000000-1111-2222-3333-444444444444
+ region: ams1
+ commercial_type: START1-S
+ wait: true
+ tags:
+ - web_server
+ register: server_run_task
+
+ - ansible.builtin.debug:
+ var: server_run_task
+
+ - ansible.builtin.assert:
+ that:
+ - server_run_task is success
+ - server_run_task is changed
+
+Dynamic Inventory Plugin
+========================
+
+Ansible ships with :ansplugin:`community.general.scaleway#inventory`.
+You can now get a complete inventory of your Scaleway resources through this plugin and filter it on
+different parameters (``regions`` and ``tags`` are currently supported).
+
+Let us create an example!
+Suppose that we want to get all hosts that got the tag web_server.
+Create a file named ``scaleway_inventory.yml`` with the following content:
+
+.. code-block:: yaml+jinja
+
+ plugin: community.general.scaleway
+ regions:
+ - ams1
+ - par1
+ tags:
+ - web_server
+
+This inventory means that we want all hosts that got the tag ``web_server`` on the zones ``ams1`` and ``par1``.
+Once you have configured this file, you can get the information using the following command:
+
+.. code-block:: console
+
+ $ ansible-inventory --list -i scaleway_inventory.yml
+
+The output will be:
+
+.. code-block:: json
+
+ {
+ "_meta": {
+ "hostvars": {
+ "dd8e3ae9-0c7c-459e-bc7b-aba8bfa1bb8d": {
+ "ansible_verbosity": 6,
+ "arch": "x86_64",
+ "commercial_type": "START1-S",
+ "hostname": "foobar",
+ "ipv4": "192.0.2.1",
+ "organization": "00000000-1111-2222-3333-444444444444",
+ "state": "running",
+ "tags": [
+ "web_server"
+ ]
+ }
+ }
+ },
+ "all": {
+ "children": [
+ "ams1",
+ "par1",
+ "ungrouped",
+ "web_server"
+ ]
+ },
+ "ams1": {},
+ "par1": {
+ "hosts": [
+ "dd8e3ae9-0c7c-459e-bc7b-aba8bfa1bb8d"
+ ]
+ },
+ "ungrouped": {},
+ "web_server": {
+ "hosts": [
+ "dd8e3ae9-0c7c-459e-bc7b-aba8bfa1bb8d"
+ ]
+ }
+ }
+
+As you can see, we get different groups of hosts.
+``par1`` and ``ams1`` are groups based on location.
+``web_server`` is a group based on a tag.
+
+In case a filter parameter is not defined, the plugin supposes all values possible are wanted.
+This means that for each tag that exists on your Scaleway compute nodes, a group based on each tag will be created.
+
+Scaleway S3 object storage
+==========================
+
+`Object Storage <https://www.scaleway.com/object-storage>`_ allows you to store any kind of objects (documents, images, videos, and so on).
+As the Scaleway API is S3 compatible, Ansible supports it natively through the amazon.aws modules: :ansplugin:`amazon.aws.s3_bucket#module`, :ansplugin:`amazon.aws.s3_object#module`.
+
+You can find many examples in the `scaleway_s3 integration tests <https://github.com/ansible/ansible-legacy-tests/tree/devel/test/legacy/roles/scaleway_s3>`_.
+
+.. code-block:: yaml+jinja
+
+ - hosts: myserver
+ vars:
+ scaleway_region: nl-ams
+ s3_url: https://s3.nl-ams.scw.cloud
+ environment:
+ # AWS_ACCESS_KEY matches your scaleway organization id available at https://cloud.scaleway.com/#/account
+ AWS_ACCESS_KEY: 00000000-1111-2222-3333-444444444444
+ # AWS_SECRET_KEY matches a secret token that you can retrieve at https://cloud.scaleway.com/#/credentials
+ AWS_SECRET_KEY: aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
+ module_defaults:
+ group/amazon.aws.aws:
+ s3_url: '{{ s3_url }}'
+ region: '{{ scaleway_region }}'
+ tasks:
+ # use a fact instead of a variable, otherwise template is evaluate each time variable is used
+ - ansible.builtin.set_fact:
+ bucket_name: "{{ 99999999 | random | to_uuid }}"
+
+ # "requester_pays:" is mandatory because Scaleway does not implement related API
+ # another way is to use amazon.aws.s3_object and "mode: create" !
+ - amazon.aws.s3_bucket:
+ name: '{{ bucket_name }}'
+ requester_pays:
+
+ - name: Another way to create the bucket
+ amazon.aws.s3_object:
+ bucket: '{{ bucket_name }}'
+ mode: create
+ encrypt: false
+ register: bucket_creation_check
+
+ - name: add something in the bucket
+ amazon.aws.s3_object:
+ mode: put
+ bucket: '{{ bucket_name }}'
+ src: /tmp/test.txt # needs to be created before
+ object: test.txt
+ encrypt: false # server side encryption must be disabled
diff --git a/ansible_collections/community/general/docs/docsite/rst/test_guide.rst b/ansible_collections/community/general/docs/docsite/rst/test_guide.rst
index b0b7885f9..7a261c755 100644
--- a/ansible_collections/community/general/docs/docsite/rst/test_guide.rst
+++ b/ansible_collections/community/general/docs/docsite/rst/test_guide.rst
@@ -15,7 +15,7 @@ The :ref:`community.general collection <plugins_in_community.general>` offers cu
Feature Tests
-------------
-The ``a_module`` test allows to check whether a given string refers to an existing module or action plugin. This can be useful in roles, which can use this to ensure that required modules are present ahead of time.
+The :ansplugin:`community.general.a_module test <community.general.a_module#test>` allows to check whether a given string refers to an existing module or action plugin. This can be useful in roles, which can use this to ensure that required modules are present ahead of time.
.. code-block:: yaml+jinja
diff --git a/ansible_collections/community/general/meta/runtime.yml b/ansible_collections/community/general/meta/runtime.yml
index 98a46f62d..4fe80ca25 100644
--- a/ansible_collections/community/general/meta/runtime.yml
+++ b/ansible_collections/community/general/meta/runtime.yml
@@ -3,7 +3,15 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
-requires_ansible: '>=2.11.0'
+requires_ansible: '>=2.13.0'
+action_groups:
+ consul:
+ - consul_auth_method
+ - consul_binding_rule
+ - consul_policy
+ - consul_role
+ - consul_session
+ - consul_token
plugin_routing:
connection:
docker:
@@ -22,6 +30,124 @@ plugin_routing:
nios_next_network:
redirect: infoblox.nios_modules.nios_next_network
modules:
+ consul_acl:
+ deprecation:
+ removal_version: 10.0.0
+ warning_text: Use community.general.consul_token and/or community.general.consul_policy instead.
+ rax_cbs_attachments:
+ deprecation:
+ removal_version: 9.0.0
+ warning_text: This module relies on the deprecated package pyrax.
+ rax_cbs:
+ deprecation:
+ removal_version: 9.0.0
+ warning_text: This module relies on the deprecated package pyrax.
+ rax_cdb_database:
+ deprecation:
+ removal_version: 9.0.0
+ warning_text: This module relies on the deprecated package pyrax.
+ rax_cdb_user:
+ deprecation:
+ removal_version: 9.0.0
+ warning_text: This module relies on the deprecated package pyrax.
+ rax_cdb:
+ deprecation:
+ removal_version: 9.0.0
+ warning_text: This module relies on the deprecated package pyrax.
+ rax_clb_nodes:
+ deprecation:
+ removal_version: 9.0.0
+ warning_text: This module relies on the deprecated package pyrax.
+ rax_clb_ssl:
+ deprecation:
+ removal_version: 9.0.0
+ warning_text: This module relies on the deprecated package pyrax.
+ rax_clb:
+ deprecation:
+ removal_version: 9.0.0
+ warning_text: This module relies on the deprecated package pyrax.
+ rax_dns_record:
+ deprecation:
+ removal_version: 9.0.0
+ warning_text: This module relies on the deprecated package pyrax.
+ rax_dns:
+ deprecation:
+ removal_version: 9.0.0
+ warning_text: This module relies on the deprecated package pyrax.
+ rax_facts:
+ deprecation:
+ removal_version: 9.0.0
+ warning_text: This module relies on the deprecated package pyrax.
+ rax_files_objects:
+ deprecation:
+ removal_version: 9.0.0
+ warning_text: This module relies on the deprecated package pyrax.
+ rax_files:
+ deprecation:
+ removal_version: 9.0.0
+ warning_text: This module relies on the deprecated package pyrax.
+ rax_identity:
+ deprecation:
+ removal_version: 9.0.0
+ warning_text: This module relies on the deprecated package pyrax.
+ rax_keypair:
+ deprecation:
+ removal_version: 9.0.0
+ warning_text: This module relies on the deprecated package pyrax.
+ rax_meta:
+ deprecation:
+ removal_version: 9.0.0
+ warning_text: This module relies on the deprecated package pyrax.
+ rax_mon_alarm:
+ deprecation:
+ removal_version: 9.0.0
+ warning_text: This module relies on the deprecated package pyrax.
+ rax:
+ deprecation:
+ removal_version: 9.0.0
+ warning_text: This module relies on the deprecated package pyrax.
+ rax_mon_check:
+ deprecation:
+ removal_version: 9.0.0
+ warning_text: This module relies on the deprecated package pyrax.
+ rax_mon_entity:
+ deprecation:
+ removal_version: 9.0.0
+ warning_text: This module relies on the deprecated package pyrax.
+ rax_mon_notification_plan:
+ deprecation:
+ removal_version: 9.0.0
+ warning_text: This module relies on the deprecated package pyrax.
+ rax_mon_notification:
+ deprecation:
+ removal_version: 9.0.0
+ warning_text: This module relies on the deprecated package pyrax.
+ rax_network:
+ deprecation:
+ removal_version: 9.0.0
+ warning_text: This module relies on the deprecated package pyrax.
+ rax_queue:
+ deprecation:
+ removal_version: 9.0.0
+ warning_text: This module relies on the deprecated package pyrax.
+ rax_scaling_group:
+ deprecation:
+ removal_version: 9.0.0
+ warning_text: This module relies on the deprecated package pyrax.
+ rax_scaling_policy:
+ deprecation:
+ removal_version: 9.0.0
+ warning_text: This module relies on the deprecated package pyrax.
+ rhn_channel:
+ deprecation:
+ removal_version: 10.0.0
+ warning_text: RHN is EOL, please contact the community.general maintainers
+ if still using this; see the module documentation for more details.
+ rhn_register:
+ deprecation:
+ removal_version: 10.0.0
+ warning_text: RHN is EOL, please contact the community.general maintainers
+ if still using this; see the module documentation for more details.
database.aerospike.aerospike_migrations:
redirect: community.general.aerospike_migrations
deprecation:
@@ -36,6 +162,12 @@ plugin_routing:
warning_text: You are using an internal name to access the community.general.airbrake_deployment
modules. This has never been supported or documented, and will stop working
in community.general 9.0.0.
+ stackdriver:
+ deprecation:
+ removal_version: 9.0.0
+ warning_text: This module relies on HTTPS APIs that do not exist anymore,
+ and any new development in the direction of providing an alternative should
+ happen in the context of the google.cloud collection.
system.aix_devices:
redirect: community.general.aix_devices
deprecation:
@@ -684,6 +816,11 @@ plugin_routing:
warning_text: You are using an internal name to access the community.general.flatpak_remote
modules. This has never been supported or documented, and will stop working
in community.general 9.0.0.
+ flowdock:
+ deprecation:
+ removal_version: 9.0.0
+ warning_text: This module relies on HTTPS APIs that do not exist anymore and
+ there is no clear path to update.
notification.flowdock:
redirect: community.general.flowdock
deprecation:
@@ -972,6 +1109,8 @@ plugin_routing:
warning_text: You are using an internal name to access the community.general.heroku_collaborator
modules. This has never been supported or documented, and will stop working
in community.general 9.0.0.
+ hana_query:
+ redirect: community.sap_libs.sap_hdbsql
hetzner_failover_ip:
redirect: community.hrobot.failover_ip
hetzner_failover_ip_info:
@@ -3389,6 +3528,10 @@ plugin_routing:
warning_text: You are using an internal name to access the community.general.redfish_info
modules. This has never been supported or documented, and will stop working
in community.general 9.0.0.
+ sapcar_extract:
+ redirect: community.sap_libs.sapcar_extract
+ sap_task_list_execute:
+ redirect: community.sap_libs.sap_task_list_execute
packaging.os.redhat_subscription:
redirect: community.general.redhat_subscription
deprecation:
@@ -4313,6 +4456,11 @@ plugin_routing:
warning_text: You are using an internal name to access the community.general.wdc_redfish_info
modules. This has never been supported or documented, and will stop working
in community.general 9.0.0.
+ webfaction_app:
+ deprecation:
+ removal_version: 9.0.0
+ warning_text: This module relies on HTTPS APIs that do not exist anymore and
+ there is no clear path to update.
cloud.webfaction.webfaction_app:
redirect: community.general.webfaction_app
deprecation:
@@ -4320,6 +4468,11 @@ plugin_routing:
warning_text: You are using an internal name to access the community.general.webfaction_app
modules. This has never been supported or documented, and will stop working
in community.general 9.0.0.
+ webfaction_db:
+ deprecation:
+ removal_version: 9.0.0
+ warning_text: This module relies on HTTPS APIs that do not exist anymore and
+ there is no clear path to update.
cloud.webfaction.webfaction_db:
redirect: community.general.webfaction_db
deprecation:
@@ -4327,6 +4480,11 @@ plugin_routing:
warning_text: You are using an internal name to access the community.general.webfaction_db
modules. This has never been supported or documented, and will stop working
in community.general 9.0.0.
+ webfaction_domain:
+ deprecation:
+ removal_version: 9.0.0
+ warning_text: This module relies on HTTPS APIs that do not exist anymore and
+ there is no clear path to update.
cloud.webfaction.webfaction_domain:
redirect: community.general.webfaction_domain
deprecation:
@@ -4334,6 +4492,11 @@ plugin_routing:
warning_text: You are using an internal name to access the community.general.webfaction_domain
modules. This has never been supported or documented, and will stop working
in community.general 9.0.0.
+ webfaction_mailbox:
+ deprecation:
+ removal_version: 9.0.0
+ warning_text: This module relies on HTTPS APIs that do not exist anymore and
+ there is no clear path to update.
cloud.webfaction.webfaction_mailbox:
redirect: community.general.webfaction_mailbox
deprecation:
@@ -4341,6 +4504,11 @@ plugin_routing:
warning_text: You are using an internal name to access the community.general.webfaction_mailbox
modules. This has never been supported or documented, and will stop working
in community.general 9.0.0.
+ webfaction_site:
+ deprecation:
+ removal_version: 9.0.0
+ warning_text: This module relies on HTTPS APIs that do not exist anymore and
+ there is no clear path to update.
cloud.webfaction.webfaction_site:
redirect: community.general.webfaction_site
deprecation:
@@ -4493,6 +4661,11 @@ plugin_routing:
modules. This has never been supported or documented, and will stop working
in community.general 9.0.0.
doc_fragments:
+ rackspace:
+ deprecation:
+ removal_version: 9.0.0
+ warning_text: This doc fragment is used by rax modules, that rely on the deprecated
+ package pyrax.
_gcp:
redirect: community.google._gcp
docker:
@@ -4508,6 +4681,10 @@ plugin_routing:
postgresql:
redirect: community.postgresql.postgresql
module_utils:
+ rax:
+ deprecation:
+ removal_version: 9.0.0
+ warning_text: This module util relies on the deprecated package pyrax.
docker.common:
redirect: community.docker.common
docker.swarm:
diff --git a/ansible_collections/community/general/plugins/action/iptables_state.py b/ansible_collections/community/general/plugins/action/iptables_state.py
index f59a7298b..4a27ef8a0 100644
--- a/ansible_collections/community/general/plugins/action/iptables_state.py
+++ b/ansible_collections/community/general/plugins/action/iptables_state.py
@@ -44,7 +44,7 @@ class ActionModule(ActionBase):
def _async_result(self, async_status_args, task_vars, timeout):
'''
- Retrieve results of the asynchonous task, and display them in place of
+ Retrieve results of the asynchronous task, and display them in place of
the async wrapper results (those with the ansible_job_id key).
'''
async_status = self._task.copy()
diff --git a/ansible_collections/community/general/plugins/action/shutdown.py b/ansible_collections/community/general/plugins/action/shutdown.py
index c2860f1d6..01201a640 100644
--- a/ansible_collections/community/general/plugins/action/shutdown.py
+++ b/ansible_collections/community/general/plugins/action/shutdown.py
@@ -6,6 +6,7 @@
# SPDX-License-Identifier: GPL-3.0-or-later
from __future__ import (absolute_import, division, print_function)
+
__metaclass__ = type
from ansible.errors import AnsibleError, AnsibleConnectionFailure
@@ -44,7 +45,7 @@ class ActionModule(ActionBase):
SHUTDOWN_COMMAND_ARGS = {
'alpine': '',
'void': '-h +{delay_min} "{message}"',
- 'freebsd': '-h +{delay_sec}s "{message}"',
+ 'freebsd': '-p +{delay_sec}s "{message}"',
'linux': DEFAULT_SHUTDOWN_COMMAND_ARGS,
'macosx': '-h +{delay_min} "{message}"',
'openbsd': '-h +{delay_min} "{message}"',
@@ -80,13 +81,6 @@ class ActionModule(ActionBase):
getattr(self, default_value))))
return value
- def get_shutdown_command_args(self, distribution):
- args = self._get_value_from_facts('SHUTDOWN_COMMAND_ARGS', distribution, 'DEFAULT_SHUTDOWN_COMMAND_ARGS')
- # Convert seconds to minutes. If less that 60, set it to 0.
- delay_sec = self.delay
- shutdown_message = self._task.args.get('msg', self.DEFAULT_SHUTDOWN_MESSAGE)
- return args.format(delay_sec=delay_sec, delay_min=delay_sec // 60, message=shutdown_message)
-
def get_distribution(self, task_vars):
# FIXME: only execute the module if we don't already have the facts we need
distribution = {}
@@ -101,7 +95,8 @@ class ActionModule(ActionBase):
to_native(module_output['module_stdout']).strip(),
to_native(module_output['module_stderr']).strip()))
distribution['name'] = module_output['ansible_facts']['ansible_distribution'].lower()
- distribution['version'] = to_text(module_output['ansible_facts']['ansible_distribution_version'].split('.')[0])
+ distribution['version'] = to_text(
+ module_output['ansible_facts']['ansible_distribution_version'].split('.')[0])
distribution['family'] = to_text(module_output['ansible_facts']['ansible_os_family'].lower())
display.debug("{action}: distribution: {dist}".format(action=self._task.action, dist=distribution))
return distribution
@@ -109,6 +104,23 @@ class ActionModule(ActionBase):
raise AnsibleError('Failed to get distribution information. Missing "{0}" in output.'.format(ke.args[0]))
def get_shutdown_command(self, task_vars, distribution):
+ def find_command(command, find_search_paths):
+ display.debug('{action}: running find module looking in {paths} to get path for "{command}"'.format(
+ action=self._task.action,
+ command=command,
+ paths=find_search_paths))
+ find_result = self._execute_module(
+ task_vars=task_vars,
+ # prevent collection search by calling with ansible.legacy (still allows library/ override of find)
+ module_name='ansible.legacy.find',
+ module_args={
+ 'paths': find_search_paths,
+ 'patterns': [command],
+ 'file_type': 'any'
+ }
+ )
+ return [x['path'] for x in find_result['files']]
+
shutdown_bin = self._get_value_from_facts('SHUTDOWN_COMMANDS', distribution, 'DEFAULT_SHUTDOWN_COMMAND')
default_search_paths = ['/sbin', '/usr/sbin', '/usr/local/sbin']
search_paths = self._task.args.get('search_paths', default_search_paths)
@@ -127,45 +139,53 @@ class ActionModule(ActionBase):
except TypeError:
raise AnsibleError(err_msg.format(search_paths))
- display.debug('{action}: running find module looking in {paths} to get path for "{command}"'.format(
- action=self._task.action,
- command=shutdown_bin,
- paths=search_paths))
- find_result = self._execute_module(
- task_vars=task_vars,
- # prevent collection search by calling with ansible.legacy (still allows library/ override of find)
- module_name='ansible.legacy.find',
- module_args={
- 'paths': search_paths,
- 'patterns': [shutdown_bin],
- 'file_type': 'any'
- }
- )
-
- full_path = [x['path'] for x in find_result['files']]
- if not full_path:
- raise AnsibleError('Unable to find command "{0}" in search paths: {1}'.format(shutdown_bin, search_paths))
- self._shutdown_command = full_path[0]
- return self._shutdown_command
+ full_path = find_command(shutdown_bin, search_paths) # find the path to the shutdown command
+ if not full_path: # if we could not find the shutdown command
+ display.vvv('Unable to find command "{0}" in search paths: {1}, will attempt a shutdown using systemd '
+ 'directly.'.format(shutdown_bin, search_paths)) # tell the user we will try with systemd
+ systemctl_search_paths = ['/bin', '/usr/bin']
+ full_path = find_command('systemctl', systemctl_search_paths) # find the path to the systemctl command
+ if not full_path: # if we couldn't find systemctl
+ raise AnsibleError(
+ 'Could not find command "{0}" in search paths: {1} or systemctl command in search paths: {2}, unable to shutdown.'.
+ format(shutdown_bin, search_paths, systemctl_search_paths)) # we give up here
+ else:
+ return "{0} poweroff".format(full_path[0]) # done, since we cannot use args with systemd shutdown
+
+ # systemd case taken care of, here we add args to the command
+ args = self._get_value_from_facts('SHUTDOWN_COMMAND_ARGS', distribution, 'DEFAULT_SHUTDOWN_COMMAND_ARGS')
+ # Convert seconds to minutes. If less that 60, set it to 0.
+ delay_sec = self.delay
+ shutdown_message = self._task.args.get('msg', self.DEFAULT_SHUTDOWN_MESSAGE)
+ return '{0} {1}'. \
+ format(
+ full_path[0],
+ args.format(
+ delay_sec=delay_sec,
+ delay_min=delay_sec // 60,
+ message=shutdown_message
+ )
+ )
def perform_shutdown(self, task_vars, distribution):
result = {}
shutdown_result = {}
- shutdown_command = self.get_shutdown_command(task_vars, distribution)
- shutdown_command_args = self.get_shutdown_command_args(distribution)
- shutdown_command_exec = '{0} {1}'.format(shutdown_command, shutdown_command_args)
+ shutdown_command_exec = self.get_shutdown_command(task_vars, distribution)
self.cleanup(force=True)
try:
display.vvv("{action}: shutting down server...".format(action=self._task.action))
- display.debug("{action}: shutting down server with command '{command}'".format(action=self._task.action, command=shutdown_command_exec))
+ display.debug("{action}: shutting down server with command '{command}'".
+ format(action=self._task.action, command=shutdown_command_exec))
if self._play_context.check_mode:
shutdown_result['rc'] = 0
else:
shutdown_result = self._low_level_execute_command(shutdown_command_exec, sudoable=self.DEFAULT_SUDOABLE)
except AnsibleConnectionFailure as e:
# If the connection is closed too quickly due to the system being shutdown, carry on
- display.debug('{action}: AnsibleConnectionFailure caught and handled: {error}'.format(action=self._task.action, error=to_text(e)))
+ display.debug(
+ '{action}: AnsibleConnectionFailure caught and handled: {error}'.format(action=self._task.action,
+ error=to_text(e)))
shutdown_result['rc'] = 0
if shutdown_result['rc'] != 0:
diff --git a/ansible_collections/community/general/plugins/become/machinectl.py b/ansible_collections/community/general/plugins/become/machinectl.py
index 461a3f635..9b9ac7ec5 100644
--- a/ansible_collections/community/general/plugins/become/machinectl.py
+++ b/ansible_collections/community/general/plugins/become/machinectl.py
@@ -68,7 +68,7 @@ DOCUMENTATION = '''
- section: machinectl_become_plugin
key: password
notes:
- - When not using this plugin with user C(root), it only works correctly with a polkit rule which will alter
+ - When not using this plugin with user V(root), it only works correctly with a polkit rule which will alter
the behaviour of machinectl. This rule must alter the prompt behaviour to ask directly for the user credentials,
if the user is allowed to perform the action (take a look at the examples section).
If such a rule is not present the plugin only work if it is used in context with the root user,
@@ -102,6 +102,7 @@ class BecomeModule(BecomeBase):
prompt = 'Password: '
fail = ('==== AUTHENTICATION FAILED ====',)
success = ('==== AUTHENTICATION COMPLETE ====',)
+ require_tty = True # see https://github.com/ansible-collections/community.general/issues/6932
@staticmethod
def remove_ansi_codes(line):
diff --git a/ansible_collections/community/general/plugins/become/pfexec.py b/ansible_collections/community/general/plugins/become/pfexec.py
index 392ee961f..2468a28a9 100644
--- a/ansible_collections/community/general/plugins/become/pfexec.py
+++ b/ansible_collections/community/general/plugins/become/pfexec.py
@@ -82,7 +82,7 @@ DOCUMENTATION = '''
env:
- name: ANSIBLE_PFEXEC_WRAP_EXECUTION
notes:
- - This plugin ignores I(become_user) as pfexec uses it's own C(exec_attr) to figure this out.
+ - This plugin ignores O(become_user) as pfexec uses it's own C(exec_attr) to figure this out.
'''
from ansible.plugins.become import BecomeBase
diff --git a/ansible_collections/community/general/plugins/cache/redis.py b/ansible_collections/community/general/plugins/cache/redis.py
index 8c0621717..c43b1dbb5 100644
--- a/ansible_collections/community/general/plugins/cache/redis.py
+++ b/ansible_collections/community/general/plugins/cache/redis.py
@@ -18,9 +18,9 @@ DOCUMENTATION = '''
_uri:
description:
- A colon separated string of connection information for Redis.
- - The format is C(host:port:db:password), for example C(localhost:6379:0:changeme).
- - To use encryption in transit, prefix the connection with C(tls://), as in C(tls://localhost:6379:0:changeme).
- - To use redis sentinel, use separator C(;), for example C(localhost:26379;localhost:26379;0:changeme). Requires redis>=2.9.0.
+ - The format is V(host:port:db:password), for example V(localhost:6379:0:changeme).
+ - To use encryption in transit, prefix the connection with V(tls://), as in V(tls://localhost:6379:0:changeme).
+ - To use redis sentinel, use separator V(;), for example V(localhost:26379;localhost:26379;0:changeme). Requires redis>=2.9.0.
required: true
env:
- name: ANSIBLE_CACHE_PLUGIN_CONNECTION
@@ -150,7 +150,7 @@ class CacheModule(BaseCacheModule):
# format: "localhost:26379;localhost2:26379;0:changeme"
connections = uri.split(';')
connection_args = connections.pop(-1)
- if len(connection_args) > 0: # hanle if no db nr is given
+ if len(connection_args) > 0: # handle if no db nr is given
connection_args = connection_args.split(':')
kw['db'] = connection_args.pop(0)
try:
diff --git a/ansible_collections/community/general/plugins/callback/cgroup_memory_recap.py b/ansible_collections/community/general/plugins/callback/cgroup_memory_recap.py
index ccdbcc9cf..d3961bf0c 100644
--- a/ansible_collections/community/general/plugins/callback/cgroup_memory_recap.py
+++ b/ansible_collections/community/general/plugins/callback/cgroup_memory_recap.py
@@ -24,7 +24,7 @@ DOCUMENTATION = '''
options:
max_mem_file:
required: true
- description: Path to cgroups C(memory.max_usage_in_bytes) file. Example C(/sys/fs/cgroup/memory/ansible_profile/memory.max_usage_in_bytes).
+ description: Path to cgroups C(memory.max_usage_in_bytes) file. Example V(/sys/fs/cgroup/memory/ansible_profile/memory.max_usage_in_bytes).
env:
- name: CGROUP_MAX_MEM_FILE
ini:
@@ -32,7 +32,7 @@ DOCUMENTATION = '''
key: max_mem_file
cur_mem_file:
required: true
- description: Path to C(memory.usage_in_bytes) file. Example C(/sys/fs/cgroup/memory/ansible_profile/memory.usage_in_bytes).
+ description: Path to C(memory.usage_in_bytes) file. Example V(/sys/fs/cgroup/memory/ansible_profile/memory.usage_in_bytes).
env:
- name: CGROUP_CUR_MEM_FILE
ini:
diff --git a/ansible_collections/community/general/plugins/callback/default_without_diff.py b/ansible_collections/community/general/plugins/callback/default_without_diff.py
new file mode 100644
index 000000000..c138cd445
--- /dev/null
+++ b/ansible_collections/community/general/plugins/callback/default_without_diff.py
@@ -0,0 +1,46 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2024, Felix Fontein <felix@fontein.de>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+DOCUMENTATION = r'''
+ name: default_without_diff
+ type: stdout
+ short_description: The default ansible callback without diff output
+ version_added: 8.4.0
+ description:
+ - This is basically the default ansible callback plugin (P(ansible.builtin.default#callback)) without
+ showing diff output. This can be useful when using another callback which sends more detailed information
+ to another service, like the L(ARA, https://ara.recordsansible.org/) callback, and you want diff output
+ sent to that plugin but not shown on the console output.
+ author: Felix Fontein (@felixfontein)
+ extends_documentation_fragment:
+ - ansible.builtin.default_callback
+ - ansible.builtin.result_format_callback
+'''
+
+EXAMPLES = r'''
+# Enable callback in ansible.cfg:
+ansible_config: |
+ [defaults]
+ stdout_callback = community.general.default_without_diff
+
+# Enable callback with environment variables:
+environment_variable: |
+ ANSIBLE_STDOUT_CALLBACK=community.general.default_without_diff
+'''
+
+from ansible.plugins.callback.default import CallbackModule as Default
+
+
+class CallbackModule(Default):
+ CALLBACK_VERSION = 2.0
+ CALLBACK_TYPE = 'stdout'
+ CALLBACK_NAME = 'community.general.default_without_diff'
+
+ def v2_on_file_diff(self, result):
+ pass
diff --git a/ansible_collections/community/general/plugins/callback/diy.py b/ansible_collections/community/general/plugins/callback/diy.py
index 75b3f4e24..cf9369e4b 100644
--- a/ansible_collections/community/general/plugins/callback/diy.py
+++ b/ansible_collections/community/general/plugins/callback/diy.py
@@ -18,7 +18,7 @@ DOCUMENTATION = r'''
extends_documentation_fragment:
- default_callback
notes:
- - Uses the C(default) callback plugin output when a custom callback message(C(msg)) is not provided.
+ - Uses the P(ansible.builtin.default#callback) callback plugin output when a custom callback V(message(msg\)) is not provided.
- Makes the callback event data available via the C(ansible_callback_diy) dictionary, which can be used in the templating context for the options.
The dictionary is only available in the templating context for the options. It is not a variable that is available via the other
various execution contexts, such as playbook, play, task etc.
@@ -40,8 +40,8 @@ DOCUMENTATION = r'''
if value C(is not None and not omit and length is greater than 0),
then the option is being used with output.
**Effect**: render value as template and output"
- - "Valid color values: C(black), C(bright gray), C(blue), C(white), C(green), C(bright blue), C(cyan), C(bright green), C(red), C(bright cyan),
- C(purple), C(bright red), C(yellow), C(bright purple), C(dark gray), C(bright yellow), C(magenta), C(bright magenta), C(normal)"
+ - "Valid color values: V(black), V(bright gray), V(blue), V(white), V(green), V(bright blue), V(cyan), V(bright green), V(red), V(bright cyan),
+ V(purple), V(bright red), V(yellow), V(bright purple), V(dark gray), V(bright yellow), V(magenta), V(bright magenta), V(normal)"
seealso:
- name: default – default Ansible screen output
description: The official documentation on the B(default) callback plugin.
@@ -62,7 +62,7 @@ DOCUMENTATION = r'''
on_any_msg_color:
description:
- - Output color to be used for I(on_any_msg).
+ - Output color to be used for O(on_any_msg).
- Template should render a L(valid color value,#notes).
ini:
- section: callback_diy
@@ -86,7 +86,7 @@ DOCUMENTATION = r'''
runner_on_failed_msg_color:
description:
- - Output color to be used for I(runner_on_failed_msg).
+ - Output color to be used for O(runner_on_failed_msg).
- Template should render a L(valid color value,#notes).
ini:
- section: callback_diy
@@ -110,7 +110,7 @@ DOCUMENTATION = r'''
runner_on_ok_msg_color:
description:
- - Output color to be used for I(runner_on_ok_msg).
+ - Output color to be used for O(runner_on_ok_msg).
- Template should render a L(valid color value,#notes).
ini:
- section: callback_diy
@@ -134,7 +134,7 @@ DOCUMENTATION = r'''
runner_on_skipped_msg_color:
description:
- - Output color to be used for I(runner_on_skipped_msg).
+ - Output color to be used for O(runner_on_skipped_msg).
- Template should render a L(valid color value,#notes).
ini:
- section: callback_diy
@@ -158,7 +158,7 @@ DOCUMENTATION = r'''
runner_on_unreachable_msg_color:
description:
- - Output color to be used for I(runner_on_unreachable_msg).
+ - Output color to be used for O(runner_on_unreachable_msg).
- Template should render a L(valid color value,#notes).
ini:
- section: callback_diy
@@ -182,7 +182,7 @@ DOCUMENTATION = r'''
playbook_on_start_msg_color:
description:
- - Output color to be used for I(playbook_on_start_msg).
+ - Output color to be used for O(playbook_on_start_msg).
- Template should render a L(valid color value,#notes).
ini:
- section: callback_diy
@@ -206,7 +206,7 @@ DOCUMENTATION = r'''
playbook_on_notify_msg_color:
description:
- - Output color to be used for I(playbook_on_notify_msg).
+ - Output color to be used for O(playbook_on_notify_msg).
- Template should render a L(valid color value,#notes).
ini:
- section: callback_diy
@@ -230,7 +230,7 @@ DOCUMENTATION = r'''
playbook_on_no_hosts_matched_msg_color:
description:
- - Output color to be used for I(playbook_on_no_hosts_matched_msg).
+ - Output color to be used for O(playbook_on_no_hosts_matched_msg).
- Template should render a L(valid color value,#notes).
ini:
- section: callback_diy
@@ -254,7 +254,7 @@ DOCUMENTATION = r'''
playbook_on_no_hosts_remaining_msg_color:
description:
- - Output color to be used for I(playbook_on_no_hosts_remaining_msg).
+ - Output color to be used for O(playbook_on_no_hosts_remaining_msg).
- Template should render a L(valid color value,#notes).
ini:
- section: callback_diy
@@ -278,7 +278,7 @@ DOCUMENTATION = r'''
playbook_on_task_start_msg_color:
description:
- - Output color to be used for I(playbook_on_task_start_msg).
+ - Output color to be used for O(playbook_on_task_start_msg).
- Template should render a L(valid color value,#notes).
ini:
- section: callback_diy
@@ -302,7 +302,7 @@ DOCUMENTATION = r'''
playbook_on_handler_task_start_msg_color:
description:
- - Output color to be used for I(playbook_on_handler_task_start_msg).
+ - Output color to be used for O(playbook_on_handler_task_start_msg).
- Template should render a L(valid color value,#notes).
ini:
- section: callback_diy
@@ -326,7 +326,7 @@ DOCUMENTATION = r'''
playbook_on_vars_prompt_msg_color:
description:
- - Output color to be used for I(playbook_on_vars_prompt_msg).
+ - Output color to be used for O(playbook_on_vars_prompt_msg).
- Template should render a L(valid color value,#notes).
ini:
- section: callback_diy
@@ -350,7 +350,7 @@ DOCUMENTATION = r'''
playbook_on_play_start_msg_color:
description:
- - Output color to be used for I(playbook_on_play_start_msg).
+ - Output color to be used for O(playbook_on_play_start_msg).
- Template should render a L(valid color value,#notes).
ini:
- section: callback_diy
@@ -374,7 +374,7 @@ DOCUMENTATION = r'''
playbook_on_stats_msg_color:
description:
- - Output color to be used for I(playbook_on_stats_msg).
+ - Output color to be used for O(playbook_on_stats_msg).
- Template should render a L(valid color value,#notes).
ini:
- section: callback_diy
@@ -398,7 +398,7 @@ DOCUMENTATION = r'''
on_file_diff_msg_color:
description:
- - Output color to be used for I(on_file_diff_msg).
+ - Output color to be used for O(on_file_diff_msg).
- Template should render a L(valid color value,#notes).
ini:
- section: callback_diy
@@ -422,7 +422,7 @@ DOCUMENTATION = r'''
playbook_on_include_msg_color:
description:
- - Output color to be used for I(playbook_on_include_msg).
+ - Output color to be used for O(playbook_on_include_msg).
- Template should render a L(valid color value,#notes).
ini:
- section: callback_diy
@@ -446,7 +446,7 @@ DOCUMENTATION = r'''
runner_item_on_ok_msg_color:
description:
- - Output color to be used for I(runner_item_on_ok_msg).
+ - Output color to be used for O(runner_item_on_ok_msg).
- Template should render a L(valid color value,#notes).
ini:
- section: callback_diy
@@ -470,7 +470,7 @@ DOCUMENTATION = r'''
runner_item_on_failed_msg_color:
description:
- - Output color to be used for I(runner_item_on_failed_msg).
+ - Output color to be used for O(runner_item_on_failed_msg).
- Template should render a L(valid color value,#notes).
ini:
- section: callback_diy
@@ -494,7 +494,7 @@ DOCUMENTATION = r'''
runner_item_on_skipped_msg_color:
description:
- - Output color to be used for I(runner_item_on_skipped_msg).
+ - Output color to be used for O(runner_item_on_skipped_msg).
- Template should render a L(valid color value,#notes).
ini:
- section: callback_diy
@@ -518,7 +518,7 @@ DOCUMENTATION = r'''
runner_retry_msg_color:
description:
- - Output color to be used for I(runner_retry_msg).
+ - Output color to be used for O(runner_retry_msg).
- Template should render a L(valid color value,#notes).
ini:
- section: callback_diy
@@ -542,7 +542,7 @@ DOCUMENTATION = r'''
runner_on_start_msg_color:
description:
- - Output color to be used for I(runner_on_start_msg).
+ - Output color to be used for O(runner_on_start_msg).
- Template should render a L(valid color value,#notes).
ini:
- section: callback_diy
@@ -566,7 +566,7 @@ DOCUMENTATION = r'''
runner_on_no_hosts_msg_color:
description:
- - Output color to be used for I(runner_on_no_hosts_msg).
+ - Output color to be used for O(runner_on_no_hosts_msg).
- Template should render a L(valid color value,#notes).
ini:
- section: callback_diy
@@ -590,7 +590,7 @@ DOCUMENTATION = r'''
playbook_on_setup_msg_color:
description:
- - Output color to be used for I(playbook_on_setup_msg).
+ - Output color to be used for O(playbook_on_setup_msg).
- Template should render a L(valid color value,#notes).
ini:
- section: callback_diy
diff --git a/ansible_collections/community/general/plugins/callback/elastic.py b/ansible_collections/community/general/plugins/callback/elastic.py
index 37526c155..0c94d1ba3 100644
--- a/ansible_collections/community/general/plugins/callback/elastic.py
+++ b/ansible_collections/community/general/plugins/callback/elastic.py
@@ -84,6 +84,7 @@ import time
import uuid
from collections import OrderedDict
+from contextlib import closing
from os.path import basename
from ansible.errors import AnsibleError, AnsibleRuntimeError
@@ -201,24 +202,25 @@ class ElasticSource(object):
apm_cli = self.init_apm_client(apm_server_url, apm_service_name, apm_verify_server_cert, apm_secret_token, apm_api_key)
if apm_cli:
- instrument() # Only call this once, as early as possible.
- if traceparent:
- parent = trace_parent_from_string(traceparent)
- apm_cli.begin_transaction("Session", trace_parent=parent, start=parent_start_time)
- else:
- apm_cli.begin_transaction("Session", start=parent_start_time)
- # Populate trace metadata attributes
- if self.ansible_version is not None:
- label(ansible_version=self.ansible_version)
- label(ansible_session=self.session, ansible_host_name=self.host, ansible_host_user=self.user)
- if self.ip_address is not None:
- label(ansible_host_ip=self.ip_address)
-
- for task_data in tasks:
- for host_uuid, host_data in task_data.host_data.items():
- self.create_span_data(apm_cli, task_data, host_data)
-
- apm_cli.end_transaction(name=__name__, result=status, duration=end_time - parent_start_time)
+ with closing(apm_cli):
+ instrument() # Only call this once, as early as possible.
+ if traceparent:
+ parent = trace_parent_from_string(traceparent)
+ apm_cli.begin_transaction("Session", trace_parent=parent, start=parent_start_time)
+ else:
+ apm_cli.begin_transaction("Session", start=parent_start_time)
+ # Populate trace metadata attributes
+ if self.ansible_version is not None:
+ label(ansible_version=self.ansible_version)
+ label(ansible_session=self.session, ansible_host_name=self.host, ansible_host_user=self.user)
+ if self.ip_address is not None:
+ label(ansible_host_ip=self.ip_address)
+
+ for task_data in tasks:
+ for host_uuid, host_data in task_data.host_data.items():
+ self.create_span_data(apm_cli, task_data, host_data)
+
+ apm_cli.end_transaction(name=__name__, result=status, duration=end_time - parent_start_time)
def create_span_data(self, apm_cli, task_data, host_data):
""" create the span with the given TaskData and HostData """
diff --git a/ansible_collections/community/general/plugins/callback/logentries.py b/ansible_collections/community/general/plugins/callback/logentries.py
index 22322a4df..d3feceb72 100644
--- a/ansible_collections/community/general/plugins/callback/logentries.py
+++ b/ansible_collections/community/general/plugins/callback/logentries.py
@@ -18,7 +18,7 @@ DOCUMENTATION = '''
requirements:
- whitelisting in configuration
- certifi (Python library)
- - flatdict (Python library), if you want to use the 'flatten' option
+ - flatdict (Python library), if you want to use the O(flatten) option
options:
api:
description: URI to the Logentries API.
@@ -90,9 +90,9 @@ examples: >
api = data.logentries.com
port = 10000
tls_port = 20000
- use_tls = no
+ use_tls = true
token = dd21fc88-f00a-43ff-b977-e3a4233c53af
- flatten = False
+ flatten = false
'''
import os
@@ -196,15 +196,11 @@ else:
class TLSSocketAppender(PlainTextSocketAppender):
def open_connection(self):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- sock = ssl.wrap_socket(
+ context = ssl.create_default_context(
+ purpose=ssl.Purpose.SERVER_AUTH,
+ cafile=certifi.where(), )
+ sock = context.wrap_socket(
sock=sock,
- keyfile=None,
- certfile=None,
- server_side=False,
- cert_reqs=ssl.CERT_REQUIRED,
- ssl_version=getattr(
- ssl, 'PROTOCOL_TLSv1_2', ssl.PROTOCOL_TLSv1),
- ca_certs=certifi.where(),
do_handshake_on_connect=True,
suppress_ragged_eofs=True, )
sock.connect((self.LE_API, self.LE_TLS_PORT))
diff --git a/ansible_collections/community/general/plugins/callback/mail.py b/ansible_collections/community/general/plugins/callback/mail.py
index 9e8314baf..1b847ea34 100644
--- a/ansible_collections/community/general/plugins/callback/mail.py
+++ b/ansible_collections/community/general/plugins/callback/mail.py
@@ -71,6 +71,16 @@ options:
ini:
- section: callback_mail
key: bcc
+ message_id_domain:
+ description:
+ - The domain name to use for the L(Message-ID header, https://en.wikipedia.org/wiki/Message-ID).
+ - The default is the hostname of the control node.
+ type: str
+ ini:
+ - section: callback_mail
+ key: message_id_domain
+ version_added: 8.2.0
+
'''
import json
@@ -131,7 +141,7 @@ class CallbackModule(CallbackBase):
content += 'To: %s\n' % ', '.join([email.utils.formataddr(pair) for pair in to_addresses])
if self.cc:
content += 'Cc: %s\n' % ', '.join([email.utils.formataddr(pair) for pair in cc_addresses])
- content += 'Message-ID: %s\n' % email.utils.make_msgid()
+ content += 'Message-ID: %s\n' % email.utils.make_msgid(domain=self.get_option('message_id_domain'))
content += 'Subject: %s\n\n' % subject.strip()
content += body
diff --git a/ansible_collections/community/general/plugins/callback/nrdp.py b/ansible_collections/community/general/plugins/callback/nrdp.py
index c16a3c7be..62f4a89ec 100644
--- a/ansible_collections/community/general/plugins/callback/nrdp.py
+++ b/ansible_collections/community/general/plugins/callback/nrdp.py
@@ -14,7 +14,7 @@ DOCUMENTATION = '''
short_description: Post task results to a Nagios server through nrdp
description:
- This callback send playbook result to Nagios.
- - Nagios shall use NRDP to recive passive events.
+ - Nagios shall use NRDP to receive passive events.
- The passive check is sent to a dedicated host/service for Ansible.
options:
url:
diff --git a/ansible_collections/community/general/plugins/callback/null.py b/ansible_collections/community/general/plugins/callback/null.py
index f53a24294..6aeeba313 100644
--- a/ansible_collections/community/general/plugins/callback/null.py
+++ b/ansible_collections/community/general/plugins/callback/null.py
@@ -15,7 +15,7 @@ DOCUMENTATION = '''
- set as main display callback
short_description: Don't display stuff to screen
description:
- - This callback prevents outputing events to screen.
+ - This callback prevents outputting events to screen.
'''
from ansible.plugins.callback import CallbackBase
@@ -24,7 +24,7 @@ from ansible.plugins.callback import CallbackBase
class CallbackModule(CallbackBase):
'''
- This callback wont print messages to stdout when new callback events are received.
+ This callback won't print messages to stdout when new callback events are received.
'''
CALLBACK_VERSION = 2.0
diff --git a/ansible_collections/community/general/plugins/callback/opentelemetry.py b/ansible_collections/community/general/plugins/callback/opentelemetry.py
index e00e1d71a..492e42071 100644
--- a/ansible_collections/community/general/plugins/callback/opentelemetry.py
+++ b/ansible_collections/community/general/plugins/callback/opentelemetry.py
@@ -32,10 +32,10 @@ DOCUMENTATION = '''
enable_from_environment:
type: str
description:
- - Whether to enable this callback only if the given environment variable exists and it is set to C(true).
+ - Whether to enable this callback only if the given environment variable exists and it is set to V(true).
- This is handy when you use Configuration as Code and want to send distributed traces
if running in the CI rather when running Ansible locally.
- - For such, it evaluates the given I(enable_from_environment) value as environment variable
+ - For such, it evaluates the given O(enable_from_environment) value as environment variable
and if set to true this plugin will be enabled.
env:
- name: ANSIBLE_OPENTELEMETRY_ENABLE_FROM_ENVIRONMENT
@@ -73,6 +73,17 @@ DOCUMENTATION = '''
- section: callback_opentelemetry
key: disable_logs
version_added: 5.8.0
+ disable_attributes_in_logs:
+ default: false
+ type: bool
+ description:
+ - Disable populating span attributes to the logs.
+ env:
+ - name: ANSIBLE_OPENTELEMETRY_DISABLE_ATTRIBUTES_IN_LOGS
+ ini:
+ - section: callback_opentelemetry
+ key: disable_attributes_in_logs
+ version_added: 7.1.0
requirements:
- opentelemetry-api (Python library)
- opentelemetry-exporter-otlp (Python library)
@@ -244,7 +255,7 @@ class OpenTelemetrySource(object):
task.dump = dump
task.add_host(HostData(host_uuid, host_name, status, result))
- def generate_distributed_traces(self, otel_service_name, ansible_playbook, tasks_data, status, traceparent, disable_logs):
+ def generate_distributed_traces(self, otel_service_name, ansible_playbook, tasks_data, status, traceparent, disable_logs, disable_attributes_in_logs):
""" generate distributed traces from the collected TaskData and HostData """
tasks = []
@@ -280,9 +291,9 @@ class OpenTelemetrySource(object):
for task in tasks:
for host_uuid, host_data in task.host_data.items():
with tracer.start_as_current_span(task.name, start_time=task.start, end_on_exit=False) as span:
- self.update_span_data(task, host_data, span, disable_logs)
+ self.update_span_data(task, host_data, span, disable_logs, disable_attributes_in_logs)
- def update_span_data(self, task_data, host_data, span, disable_logs):
+ def update_span_data(self, task_data, host_data, span, disable_logs, disable_attributes_in_logs):
""" update the span with the given TaskData and HostData """
name = '[%s] %s: %s' % (host_data.name, task_data.play, task_data.name)
@@ -315,39 +326,47 @@ class OpenTelemetrySource(object):
status = Status(status_code=StatusCode.UNSET)
span.set_status(status)
+
+ # Create the span and log attributes
+ attributes = {
+ "ansible.task.module": task_data.action,
+ "ansible.task.message": message,
+ "ansible.task.name": name,
+ "ansible.task.result": rc,
+ "ansible.task.host.name": host_data.name,
+ "ansible.task.host.status": host_data.status
+ }
if isinstance(task_data.args, dict) and "gather_facts" not in task_data.action:
names = tuple(self.transform_ansible_unicode_to_str(k) for k in task_data.args.keys())
values = tuple(self.transform_ansible_unicode_to_str(k) for k in task_data.args.values())
- self.set_span_attribute(span, ("ansible.task.args.name"), names)
- self.set_span_attribute(span, ("ansible.task.args.value"), values)
- self.set_span_attribute(span, "ansible.task.module", task_data.action)
- self.set_span_attribute(span, "ansible.task.message", message)
- self.set_span_attribute(span, "ansible.task.name", name)
- self.set_span_attribute(span, "ansible.task.result", rc)
- self.set_span_attribute(span, "ansible.task.host.name", host_data.name)
- self.set_span_attribute(span, "ansible.task.host.status", host_data.status)
+ attributes[("ansible.task.args.name")] = names
+ attributes[("ansible.task.args.value")] = values
+
+ self.set_span_attributes(span, attributes)
+
# This will allow to enrich the service map
self.add_attributes_for_service_map_if_possible(span, task_data)
# Send logs
if not disable_logs:
- span.add_event(task_data.dump)
- span.end(end_time=host_data.finish)
+ # This will avoid populating span attributes to the logs
+ span.add_event(task_data.dump, attributes={} if disable_attributes_in_logs else attributes)
+ span.end(end_time=host_data.finish)
- def set_span_attribute(self, span, attributeName, attributeValue):
- """ update the span attribute with the given attribute and value if not None """
+ def set_span_attributes(self, span, attributes):
+ """ update the span attributes with the given attributes if not None """
if span is None and self._display is not None:
self._display.warning('span object is None. Please double check if that is expected.')
else:
- if attributeValue is not None:
- span.set_attribute(attributeName, attributeValue)
+ if attributes is not None:
+ span.set_attributes(attributes)
def add_attributes_for_service_map_if_possible(self, span, task_data):
"""Update the span attributes with the service that the task interacted with, if possible."""
redacted_url = self.parse_and_redact_url_if_possible(task_data.args)
if redacted_url:
- self.set_span_attribute(span, "http.url", redacted_url.geturl())
+ span.set_attribute("http.url", redacted_url.geturl())
@staticmethod
def parse_and_redact_url_if_possible(args):
@@ -434,6 +453,7 @@ class CallbackModule(CallbackBase):
def __init__(self, display=None):
super(CallbackModule, self).__init__(display=display)
self.hide_task_arguments = None
+ self.disable_attributes_in_logs = None
self.disable_logs = None
self.otel_service_name = None
self.ansible_playbook = None
@@ -465,6 +485,8 @@ class CallbackModule(CallbackBase):
self.hide_task_arguments = self.get_option('hide_task_arguments')
+ self.disable_attributes_in_logs = self.get_option('disable_attributes_in_logs')
+
self.disable_logs = self.get_option('disable_logs')
self.otel_service_name = self.get_option('otel_service_name')
@@ -562,7 +584,8 @@ class CallbackModule(CallbackBase):
self.tasks_data,
status,
self.traceparent,
- self.disable_logs
+ self.disable_logs,
+ self.disable_attributes_in_logs
)
def v2_runner_on_async_failed(self, result, **kwargs):
diff --git a/ansible_collections/community/general/plugins/callback/say.py b/ansible_collections/community/general/plugins/callback/say.py
index 005725a22..9d96ad74d 100644
--- a/ansible_collections/community/general/plugins/callback/say.py
+++ b/ansible_collections/community/general/plugins/callback/say.py
@@ -18,8 +18,6 @@ DOCUMENTATION = '''
short_description: notify using software speech synthesizer
description:
- This plugin will use the C(say) or C(espeak) program to "speak" about play events.
- notes:
- - In Ansible 2.8, this callback has been renamed from C(osx_say) into M(community.general.say).
'''
import platform
diff --git a/ansible_collections/community/general/plugins/callback/selective.py b/ansible_collections/community/general/plugins/callback/selective.py
index 526975bd2..069675783 100644
--- a/ansible_collections/community/general/plugins/callback/selective.py
+++ b/ansible_collections/community/general/plugins/callback/selective.py
@@ -44,26 +44,17 @@ from ansible import constants as C
from ansible.plugins.callback import CallbackBase
from ansible.module_utils.common.text.converters import to_text
-try:
- codeCodes = C.COLOR_CODES
-except AttributeError:
- # This constant was moved to ansible.constants in
- # https://github.com/ansible/ansible/commit/1202dd000f10b0e8959019484f1c3b3f9628fc67
- # (will be included in ansible-core 2.11.0). For older Ansible/ansible-base versions,
- # we include from the original location.
- from ansible.utils.color import codeCodes
-
DONT_COLORIZE = False
COLORS = {
'normal': '\033[0m',
- 'ok': '\033[{0}m'.format(codeCodes[C.COLOR_OK]),
+ 'ok': '\033[{0}m'.format(C.COLOR_CODES[C.COLOR_OK]),
'bold': '\033[1m',
'not_so_bold': '\033[1m\033[34m',
- 'changed': '\033[{0}m'.format(codeCodes[C.COLOR_CHANGED]),
- 'failed': '\033[{0}m'.format(codeCodes[C.COLOR_ERROR]),
+ 'changed': '\033[{0}m'.format(C.COLOR_CODES[C.COLOR_CHANGED]),
+ 'failed': '\033[{0}m'.format(C.COLOR_CODES[C.COLOR_ERROR]),
'endc': '\033[0m',
- 'skipped': '\033[{0}m'.format(codeCodes[C.COLOR_SKIP]),
+ 'skipped': '\033[{0}m'.format(C.COLOR_CODES[C.COLOR_SKIP]),
}
@@ -115,8 +106,8 @@ class CallbackModule(CallbackBase):
line_length = 120
if self.last_skipped:
print()
- msg = colorize("# {0} {1}".format(task_name,
- '*' * (line_length - len(task_name))), 'bold')
+ line = "# {0} ".format(task_name)
+ msg = colorize("{0}{1}".format(line, '*' * (line_length - len(line))), 'bold')
print(msg)
def _indent_text(self, text, indent_level):
diff --git a/ansible_collections/community/general/plugins/callback/slack.py b/ansible_collections/community/general/plugins/callback/slack.py
index e9b84bbb3..e7a2743ec 100644
--- a/ansible_collections/community/general/plugins/callback/slack.py
+++ b/ansible_collections/community/general/plugins/callback/slack.py
@@ -18,7 +18,6 @@ DOCUMENTATION = '''
short_description: Sends play events to a Slack channel
description:
- This is an ansible callback plugin that sends status updates to a Slack channel during playbook execution.
- - Before Ansible 2.4 only environment variables were available for configuring this plugin.
options:
webhook_url:
required: true
diff --git a/ansible_collections/community/general/plugins/callback/splunk.py b/ansible_collections/community/general/plugins/callback/splunk.py
index 67ad944d2..d15547f44 100644
--- a/ansible_collections/community/general/plugins/callback/splunk.py
+++ b/ansible_collections/community/general/plugins/callback/splunk.py
@@ -36,8 +36,8 @@ DOCUMENTATION = '''
key: authtoken
validate_certs:
description: Whether to validate certificates for connections to HEC. It is not recommended to set to
- C(false) except when you are sure that nobody can intercept the connection
- between this plugin and HEC, as setting it to C(false) allows man-in-the-middle attacks!
+ V(false) except when you are sure that nobody can intercept the connection
+ between this plugin and HEC, as setting it to V(false) allows man-in-the-middle attacks!
env:
- name: SPLUNK_VALIDATE_CERTS
ini:
diff --git a/ansible_collections/community/general/plugins/callback/sumologic.py b/ansible_collections/community/general/plugins/callback/sumologic.py
index 998081c35..46ab3f0f7 100644
--- a/ansible_collections/community/general/plugins/callback/sumologic.py
+++ b/ansible_collections/community/general/plugins/callback/sumologic.py
@@ -6,7 +6,7 @@
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
-DOCUMENTATION = '''
+DOCUMENTATION = r'''
name: sumologic
type: notification
short_description: Sends task result events to Sumologic
@@ -15,8 +15,8 @@ description:
- This callback plugin will send task results as JSON formatted events to a Sumologic HTTP collector source.
requirements:
- Whitelisting this callback plugin
- - 'Create a HTTP collector source in Sumologic and specify a custom timestamp format of C(yyyy-MM-dd HH:mm:ss ZZZZ) and a custom timestamp locator
- of C("timestamp": "(.*)")'
+ - 'Create a HTTP collector source in Sumologic and specify a custom timestamp format of V(yyyy-MM-dd HH:mm:ss ZZZZ) and a custom timestamp locator
+ of V("timestamp": "(.*\)")'
options:
url:
description: URL to the Sumologic HTTP collector source.
diff --git a/ansible_collections/community/general/plugins/callback/syslog_json.py b/ansible_collections/community/general/plugins/callback/syslog_json.py
index 0f5ec4d0d..43d6ff2f9 100644
--- a/ansible_collections/community/general/plugins/callback/syslog_json.py
+++ b/ansible_collections/community/general/plugins/callback/syslog_json.py
@@ -16,7 +16,6 @@ DOCUMENTATION = '''
short_description: sends JSON events to syslog
description:
- This plugin logs ansible-playbook and ansible runs to a syslog server in JSON format.
- - Before Ansible 2.9 only environment variables were available for configuration.
options:
server:
description: Syslog server that will receive the event.
diff --git a/ansible_collections/community/general/plugins/callback/unixy.py b/ansible_collections/community/general/plugins/callback/unixy.py
index 02a2e46ba..4908202c2 100644
--- a/ansible_collections/community/general/plugins/callback/unixy.py
+++ b/ansible_collections/community/general/plugins/callback/unixy.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-# Copyright (c) 2017, Allyson Bowles <@akatch>
+# Copyright (c) 2023, Al Bowles <@akatch>
# Copyright (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
@@ -11,7 +11,7 @@ __metaclass__ = type
DOCUMENTATION = '''
name: unixy
type: stdout
- author: Allyson Bowles (@akatch)
+ author: Al Bowles (@akatch)
short_description: condensed Ansible output
description:
- Consolidated Ansible output in the style of LINUX/UNIX startup logs.
@@ -40,7 +40,6 @@ class CallbackModule(CallbackModule_default):
- Only display task names if the task runs on at least one host
- Add option to display all hostnames on a single line in the appropriate result color (failures may have a separate line)
- Consolidate stats display
- - Display whether run is in --check mode
- Don't show play name if no hosts found
'''
@@ -92,19 +91,31 @@ class CallbackModule(CallbackModule_default):
def v2_playbook_on_task_start(self, task, is_conditional):
self._get_task_display_name(task)
if self.task_display_name is not None:
- self._display.display("%s..." % self.task_display_name)
+ if task.check_mode and self.get_option('check_mode_markers'):
+ self._display.display("%s (check mode)..." % self.task_display_name)
+ else:
+ self._display.display("%s..." % self.task_display_name)
def v2_playbook_on_handler_task_start(self, task):
self._get_task_display_name(task)
if self.task_display_name is not None:
- self._display.display("%s (via handler)... " % self.task_display_name)
+ if task.check_mode and self.get_option('check_mode_markers'):
+ self._display.display("%s (via handler in check mode)... " % self.task_display_name)
+ else:
+ self._display.display("%s (via handler)... " % self.task_display_name)
def v2_playbook_on_play_start(self, play):
name = play.get_name().strip()
- if name and play.hosts:
- msg = u"\n- %s on hosts: %s -" % (name, ",".join(play.hosts))
+ if play.check_mode and self.get_option('check_mode_markers'):
+ if name and play.hosts:
+ msg = u"\n- %s (in check mode) on hosts: %s -" % (name, ",".join(play.hosts))
+ else:
+ msg = u"- check mode -"
else:
- msg = u"---"
+ if name and play.hosts:
+ msg = u"\n- %s on hosts: %s -" % (name, ",".join(play.hosts))
+ else:
+ msg = u"---"
self._display.display(msg)
@@ -227,8 +238,10 @@ class CallbackModule(CallbackModule_default):
self._display.display(" Ran out of hosts!", color=C.COLOR_ERROR)
def v2_playbook_on_start(self, playbook):
- # TODO display whether this run is happening in check mode
- self._display.display("Executing playbook %s" % basename(playbook._file_name))
+ if context.CLIARGS['check'] and self.get_option('check_mode_markers'):
+ self._display.display("Executing playbook %s in check mode" % basename(playbook._file_name))
+ else:
+ self._display.display("Executing playbook %s" % basename(playbook._file_name))
# show CLI arguments
if self._display.verbosity > 3:
diff --git a/ansible_collections/community/general/plugins/connection/chroot.py b/ansible_collections/community/general/plugins/connection/chroot.py
index ef6d5566d..810316aaa 100644
--- a/ansible_collections/community/general/plugins/connection/chroot.py
+++ b/ansible_collections/community/general/plugins/connection/chroot.py
@@ -46,8 +46,42 @@ DOCUMENTATION = '''
vars:
- name: ansible_chroot_exe
default: chroot
+ disable_root_check:
+ description:
+ - Do not check that the user is not root.
+ ini:
+ - section: chroot_connection
+ key: disable_root_check
+ env:
+ - name: ANSIBLE_CHROOT_DISABLE_ROOT_CHECK
+ vars:
+ - name: ansible_chroot_disable_root_check
+ default: false
+ type: bool
+ version_added: 7.3.0
'''
+EXAMPLES = r"""
+# Plugin requires root privileges for chroot, -E preserves your env (and location of ~/.ansible):
+# sudo -E ansible-playbook ...
+#
+# Static inventory file
+# [chroots]
+# /path/to/debootstrap
+# /path/to/feboostrap
+# /path/to/lxc-image
+# /path/to/chroot
+
+# playbook
+---
+- hosts: chroots
+ connection: community.general.chroot
+ tasks:
+ - debug:
+ msg: "This is coming from chroot environment"
+
+"""
+
import os
import os.path
import subprocess
@@ -81,11 +115,7 @@ class Connection(ConnectionBase):
self.chroot = self._play_context.remote_addr
- if os.geteuid() != 0:
- raise AnsibleError("chroot connection requires running as root")
-
- # we're running as root on the local system so do some
- # trivial checks for ensuring 'host' is actually a chroot'able dir
+ # do some trivial checks for ensuring 'host' is actually a chroot'able dir
if not os.path.isdir(self.chroot):
raise AnsibleError("%s is not a directory" % self.chroot)
@@ -99,6 +129,11 @@ class Connection(ConnectionBase):
def _connect(self):
""" connect to the chroot """
+ if not self.get_option('disable_root_check') and os.geteuid() != 0:
+ raise AnsibleError(
+ "chroot connection requires running as root. "
+ "You can override this check with the `disable_root_check` option.")
+
if os.path.isabs(self.get_option('chroot_exe')):
self.chroot_cmd = self.get_option('chroot_exe')
else:
diff --git a/ansible_collections/community/general/plugins/connection/funcd.py b/ansible_collections/community/general/plugins/connection/funcd.py
index 9f37f791d..219a8cccd 100644
--- a/ansible_collections/community/general/plugins/connection/funcd.py
+++ b/ansible_collections/community/general/plugins/connection/funcd.py
@@ -70,7 +70,7 @@ class Connection(ConnectionBase):
if in_data:
raise AnsibleError("Internal Error: this module does not support optimized module pipelining")
- # totally ignores privlege escalation
+ # totally ignores privilege escalation
display.vvv("EXEC %s" % cmd, host=self.host)
p = self.client.command.run(cmd)[self.host]
return p[0], p[1], p[2]
diff --git a/ansible_collections/community/general/plugins/connection/incus.py b/ansible_collections/community/general/plugins/connection/incus.py
new file mode 100644
index 000000000..81d6f971c
--- /dev/null
+++ b/ansible_collections/community/general/plugins/connection/incus.py
@@ -0,0 +1,169 @@
+# -*- coding: utf-8 -*-
+# Based on lxd.py (c) 2016, Matt Clay <matt@mystile.com>
+# (c) 2023, Stephane Graber <stgraber@stgraber.org>
+# Copyright (c) 2023 Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+DOCUMENTATION = """
+ author: Stéphane Graber (@stgraber)
+ name: incus
+ short_description: Run tasks in Incus instances via the Incus CLI.
+ description:
+ - Run commands or put/fetch files to an existing Incus instance using Incus CLI.
+ version_added: "8.2.0"
+ options:
+ remote_addr:
+ description:
+ - The instance identifier.
+ default: inventory_hostname
+ vars:
+ - name: inventory_hostname
+ - name: ansible_host
+ - name: ansible_incus_host
+ executable:
+ description:
+ - The shell to use for execution inside the instance.
+ default: /bin/sh
+ vars:
+ - name: ansible_executable
+ - name: ansible_incus_executable
+ remote:
+ description:
+ - The name of the Incus remote to use (per C(incus remote list)).
+ - Remotes are used to access multiple servers from a single client.
+ default: local
+ vars:
+ - name: ansible_incus_remote
+ project:
+ description:
+ - The name of the Incus project to use (per C(incus project list)).
+ - Projects are used to divide the instances running on a server.
+ default: default
+ vars:
+ - name: ansible_incus_project
+"""
+
+import os
+from subprocess import call, Popen, PIPE
+
+from ansible.errors import AnsibleError, AnsibleConnectionFailure, AnsibleFileNotFound
+from ansible.module_utils.common.process import get_bin_path
+from ansible.module_utils._text import to_bytes, to_text
+from ansible.plugins.connection import ConnectionBase
+
+
+class Connection(ConnectionBase):
+ """ Incus based connections """
+
+ transport = "incus"
+ has_pipelining = True
+ default_user = 'root'
+
+ def __init__(self, play_context, new_stdin, *args, **kwargs):
+ super(Connection, self).__init__(play_context, new_stdin, *args, **kwargs)
+
+ self._incus_cmd = get_bin_path("incus")
+
+ if not self._incus_cmd:
+ raise AnsibleError("incus command not found in PATH")
+
+ def _connect(self):
+ """connect to Incus (nothing to do here) """
+ super(Connection, self)._connect()
+
+ if not self._connected:
+ self._display.vvv(u"ESTABLISH Incus CONNECTION FOR USER: root",
+ host=self._instance())
+ self._connected = True
+
+ def _instance(self):
+ # Return only the leading part of the FQDN as the instance name
+ # as Incus instance names cannot be a FQDN.
+ return self.get_option('remote_addr').split(".")[0]
+
+ def exec_command(self, cmd, in_data=None, sudoable=True):
+ """ execute a command on the Incus host """
+ super(Connection, self).exec_command(cmd, in_data=in_data, sudoable=sudoable)
+
+ self._display.vvv(u"EXEC {0}".format(cmd),
+ host=self._instance())
+
+ local_cmd = [
+ self._incus_cmd,
+ "--project", self.get_option("project"),
+ "exec",
+ "%s:%s" % (self.get_option("remote"), self._instance()),
+ "--",
+ self._play_context.executable, "-c", cmd]
+
+ local_cmd = [to_bytes(i, errors='surrogate_or_strict') for i in local_cmd]
+ in_data = to_bytes(in_data, errors='surrogate_or_strict', nonstring='passthru')
+
+ process = Popen(local_cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE)
+ stdout, stderr = process.communicate(in_data)
+
+ stdout = to_text(stdout)
+ stderr = to_text(stderr)
+
+ if stderr == "Error: Instance is not running.\n":
+ raise AnsibleConnectionFailure("instance not running: %s" %
+ self._instance())
+
+ if stderr == "Error: Instance not found\n":
+ raise AnsibleConnectionFailure("instance not found: %s" %
+ self._instance())
+
+ return process.returncode, stdout, stderr
+
+ def put_file(self, in_path, out_path):
+ """ put a file from local to Incus """
+ super(Connection, self).put_file(in_path, out_path)
+
+ self._display.vvv(u"PUT {0} TO {1}".format(in_path, out_path),
+ host=self._instance())
+
+ if not os.path.isfile(to_bytes(in_path, errors='surrogate_or_strict')):
+ raise AnsibleFileNotFound("input path is not a file: %s" % in_path)
+
+ local_cmd = [
+ self._incus_cmd,
+ "--project", self.get_option("project"),
+ "file", "push", "--quiet",
+ in_path,
+ "%s:%s/%s" % (self.get_option("remote"),
+ self._instance(),
+ out_path)]
+
+ local_cmd = [to_bytes(i, errors='surrogate_or_strict') for i in local_cmd]
+
+ call(local_cmd)
+
+ def fetch_file(self, in_path, out_path):
+ """ fetch a file from Incus to local """
+ super(Connection, self).fetch_file(in_path, out_path)
+
+ self._display.vvv(u"FETCH {0} TO {1}".format(in_path, out_path),
+ host=self._instance())
+
+ local_cmd = [
+ self._incus_cmd,
+ "--project", self.get_option("project"),
+ "file", "pull", "--quiet",
+ "%s:%s/%s" % (self.get_option("remote"),
+ self._instance(),
+ in_path),
+ out_path]
+
+ local_cmd = [to_bytes(i, errors='surrogate_or_strict') for i in local_cmd]
+
+ call(local_cmd)
+
+ def close(self):
+ """ close the connection (nothing to do here) """
+ super(Connection, self).close()
+
+ self._connected = False
diff --git a/ansible_collections/community/general/plugins/connection/lxc.py b/ansible_collections/community/general/plugins/connection/lxc.py
index adf3eec1c..7bb5824fa 100644
--- a/ansible_collections/community/general/plugins/connection/lxc.py
+++ b/ansible_collections/community/general/plugins/connection/lxc.py
@@ -19,6 +19,7 @@ DOCUMENTATION = '''
- Container identifier
default: inventory_hostname
vars:
+ - name: inventory_hostname
- name: ansible_host
- name: ansible_lxc_host
executable:
@@ -59,7 +60,7 @@ class Connection(ConnectionBase):
def __init__(self, play_context, new_stdin, *args, **kwargs):
super(Connection, self).__init__(play_context, new_stdin, *args, **kwargs)
- self.container_name = self._play_context.remote_addr
+ self.container_name = None
self.container = None
def _connect(self):
@@ -67,12 +68,15 @@ class Connection(ConnectionBase):
super(Connection, self)._connect()
if not HAS_LIBLXC:
- msg = "lxc bindings for python2 are not installed"
+ msg = "lxc python bindings are not installed"
raise errors.AnsibleError(msg)
- if self.container:
+ container_name = self.get_option('remote_addr')
+ if self.container and self.container_name == container_name:
return
+ self.container_name = container_name
+
self._display.vvv("THIS IS A LOCAL LXC DIR", host=self.container_name)
self.container = _lxc.Container(self.container_name)
if self.container.state == "STOPPED":
@@ -117,7 +121,7 @@ class Connection(ConnectionBase):
super(Connection, self).exec_command(cmd, in_data=in_data, sudoable=sudoable)
# python2-lxc needs bytes. python3-lxc needs text.
- executable = to_native(self._play_context.executable, errors='surrogate_or_strict')
+ executable = to_native(self.get_option('executable'), errors='surrogate_or_strict')
local_cmd = [executable, '-c', to_native(cmd, errors='surrogate_or_strict')]
read_stdout, write_stdout = None, None
diff --git a/ansible_collections/community/general/plugins/connection/lxd.py b/ansible_collections/community/general/plugins/connection/lxd.py
index affb87dfd..0e784b85f 100644
--- a/ansible_collections/community/general/plugins/connection/lxd.py
+++ b/ansible_collections/community/general/plugins/connection/lxd.py
@@ -10,13 +10,15 @@ __metaclass__ = type
DOCUMENTATION = '''
author: Matt Clay (@mattclay) <matt@mystile.com>
name: lxd
- short_description: Run tasks in lxc containers via lxc CLI
+ short_description: Run tasks in LXD instances via C(lxc) CLI
description:
- - Run commands or put/fetch files to an existing lxc container using lxc CLI
+ - Run commands or put/fetch files to an existing instance using C(lxc) CLI.
options:
remote_addr:
description:
- - Container identifier.
+ - Instance (container/VM) identifier.
+ - Since community.general 8.0.0, a FQDN can be provided; in that case, the first component (the part before C(.))
+ is used as the instance identifier.
default: inventory_hostname
vars:
- name: inventory_hostname
@@ -24,7 +26,7 @@ DOCUMENTATION = '''
- name: ansible_lxd_host
executable:
description:
- - shell to use for execution inside container
+ - Shell to use for execution inside instance.
default: /bin/sh
vars:
- name: ansible_executable
@@ -69,32 +71,38 @@ class Connection(ConnectionBase):
raise AnsibleError("lxc command not found in PATH")
if self._play_context.remote_user is not None and self._play_context.remote_user != 'root':
- self._display.warning('lxd does not support remote_user, using container default: root')
+ self._display.warning('lxd does not support remote_user, using default: root')
+
+ def _host(self):
+ """ translate remote_addr to lxd (short) hostname """
+ return self.get_option("remote_addr").split(".", 1)[0]
def _connect(self):
"""connect to lxd (nothing to do here) """
super(Connection, self)._connect()
if not self._connected:
- self._display.vvv(u"ESTABLISH LXD CONNECTION FOR USER: root", host=self.get_option('remote_addr'))
+ self._display.vvv(u"ESTABLISH LXD CONNECTION FOR USER: root", host=self._host())
self._connected = True
def exec_command(self, cmd, in_data=None, sudoable=True):
""" execute a command on the lxd host """
super(Connection, self).exec_command(cmd, in_data=in_data, sudoable=sudoable)
- self._display.vvv(u"EXEC {0}".format(cmd), host=self.get_option('remote_addr'))
+ self._display.vvv(u"EXEC {0}".format(cmd), host=self._host())
local_cmd = [self._lxc_cmd]
if self.get_option("project"):
local_cmd.extend(["--project", self.get_option("project")])
local_cmd.extend([
"exec",
- "%s:%s" % (self.get_option("remote"), self.get_option("remote_addr")),
+ "%s:%s" % (self.get_option("remote"), self._host()),
"--",
self.get_option("executable"), "-c", cmd
])
+ self._display.vvvvv(u"EXEC {0}".format(local_cmd), host=self._host())
+
local_cmd = [to_bytes(i, errors='surrogate_or_strict') for i in local_cmd]
in_data = to_bytes(in_data, errors='surrogate_or_strict', nonstring='passthru')
@@ -104,11 +112,13 @@ class Connection(ConnectionBase):
stdout = to_text(stdout)
stderr = to_text(stderr)
- if stderr == "error: Container is not running.\n":
- raise AnsibleConnectionFailure("container not running: %s" % self.get_option('remote_addr'))
+ self._display.vvvvv(u"EXEC lxc output: {0} {1}".format(stdout, stderr), host=self._host())
+
+ if "is not running" in stderr:
+ raise AnsibleConnectionFailure("instance not running: %s" % self._host())
- if stderr == "error: not found\n":
- raise AnsibleConnectionFailure("container not found: %s" % self.get_option('remote_addr'))
+ if stderr.strip() == "Error: Instance not found" or stderr.strip() == "error: not found":
+ raise AnsibleConnectionFailure("instance not found: %s" % self._host())
return process.returncode, stdout, stderr
@@ -116,7 +126,7 @@ class Connection(ConnectionBase):
""" put a file from local to lxd """
super(Connection, self).put_file(in_path, out_path)
- self._display.vvv(u"PUT {0} TO {1}".format(in_path, out_path), host=self.get_option('remote_addr'))
+ self._display.vvv(u"PUT {0} TO {1}".format(in_path, out_path), host=self._host())
if not os.path.isfile(to_bytes(in_path, errors='surrogate_or_strict')):
raise AnsibleFileNotFound("input path is not a file: %s" % in_path)
@@ -127,7 +137,7 @@ class Connection(ConnectionBase):
local_cmd.extend([
"file", "push",
in_path,
- "%s:%s/%s" % (self.get_option("remote"), self.get_option("remote_addr"), out_path)
+ "%s:%s/%s" % (self.get_option("remote"), self._host(), out_path)
])
local_cmd = [to_bytes(i, errors='surrogate_or_strict') for i in local_cmd]
@@ -139,14 +149,14 @@ class Connection(ConnectionBase):
""" fetch a file from lxd to local """
super(Connection, self).fetch_file(in_path, out_path)
- self._display.vvv(u"FETCH {0} TO {1}".format(in_path, out_path), host=self.get_option('remote_addr'))
+ self._display.vvv(u"FETCH {0} TO {1}".format(in_path, out_path), host=self._host())
local_cmd = [self._lxc_cmd]
if self.get_option("project"):
local_cmd.extend(["--project", self.get_option("project")])
local_cmd.extend([
"file", "pull",
- "%s:%s/%s" % (self.get_option("remote"), self.get_option("remote_addr"), in_path),
+ "%s:%s/%s" % (self.get_option("remote"), self._host(), in_path),
out_path
])
diff --git a/ansible_collections/community/general/plugins/doc_fragments/alicloud.py b/ansible_collections/community/general/plugins/doc_fragments/alicloud.py
index f464e178c..b462fcacb 100644
--- a/ansible_collections/community/general/plugins/doc_fragments/alicloud.py
+++ b/ansible_collections/community/general/plugins/doc_fragments/alicloud.py
@@ -15,40 +15,40 @@ class ModuleDocFragment(object):
options:
alicloud_access_key:
description:
- - Alibaba Cloud access key. If not set then the value of environment variable C(ALICLOUD_ACCESS_KEY),
- C(ALICLOUD_ACCESS_KEY_ID) will be used instead.
+ - Alibaba Cloud access key. If not set then the value of environment variable E(ALICLOUD_ACCESS_KEY),
+ E(ALICLOUD_ACCESS_KEY_ID) will be used instead.
aliases: ['access_key_id', 'access_key']
type: str
alicloud_secret_key:
description:
- - Alibaba Cloud secret key. If not set then the value of environment variable C(ALICLOUD_SECRET_KEY),
- C(ALICLOUD_SECRET_ACCESS_KEY) will be used instead.
+ - Alibaba Cloud secret key. If not set then the value of environment variable E(ALICLOUD_SECRET_KEY),
+ E(ALICLOUD_SECRET_ACCESS_KEY) will be used instead.
aliases: ['secret_access_key', 'secret_key']
type: str
alicloud_region:
description:
- The Alibaba Cloud region to use. If not specified then the value of environment variable
- C(ALICLOUD_REGION), C(ALICLOUD_REGION_ID) will be used instead.
+ E(ALICLOUD_REGION), E(ALICLOUD_REGION_ID) will be used instead.
aliases: ['region', 'region_id']
required: true
type: str
alicloud_security_token:
description:
- The Alibaba Cloud security token. If not specified then the value of environment variable
- C(ALICLOUD_SECURITY_TOKEN) will be used instead.
+ E(ALICLOUD_SECURITY_TOKEN) will be used instead.
aliases: ['security_token']
type: str
alicloud_assume_role:
description:
- If provided with a role ARN, Ansible will attempt to assume this role using the supplied credentials.
- - The nested assume_role block supports I(alicloud_assume_role_arn), I(alicloud_assume_role_session_name),
- I(alicloud_assume_role_session_expiration) and I(alicloud_assume_role_policy)
+ - The nested assume_role block supports C(alicloud_assume_role_arn), C(alicloud_assume_role_session_name),
+ C(alicloud_assume_role_session_expiration) and C(alicloud_assume_role_policy).
type: dict
aliases: ['assume_role']
alicloud_assume_role_arn:
description:
- - The Alibaba Cloud role_arn. The ARN of the role to assume. If ARN is set to an empty string,
- it does not perform role switching. It supports environment variable ALICLOUD_ASSUME_ROLE_ARN.
+ - The Alibaba Cloud C(role_arn). The ARN of the role to assume. If ARN is set to an empty string,
+ it does not perform role switching. It supports environment variable E(ALICLOUD_ASSUME_ROLE_ARN).
ansible will execute with provided credentials.
aliases: ['assume_role_arn']
type: str
@@ -56,14 +56,14 @@ options:
description:
- The Alibaba Cloud session_name. The session name to use when assuming the role. If omitted,
'ansible' is passed to the AssumeRole call as session name. It supports environment variable
- ALICLOUD_ASSUME_ROLE_SESSION_NAME
+ E(ALICLOUD_ASSUME_ROLE_SESSION_NAME).
aliases: ['assume_role_session_name']
type: str
alicloud_assume_role_session_expiration:
description:
- - The Alibaba Cloud session_expiration. The time after which the established session for assuming
+ - The Alibaba Cloud C(session_expiration). The time after which the established session for assuming
role expires. Valid value range 900-3600 seconds. Default to 3600 (in this case Alicloud use own default
- value). It supports environment variable ALICLOUD_ASSUME_ROLE_SESSION_EXPIRATION
+ value). It supports environment variable E(ALICLOUD_ASSUME_ROLE_SESSION_EXPIRATION).
aliases: ['assume_role_session_expiration']
type: int
ecs_role_name:
@@ -79,31 +79,31 @@ options:
profile:
description:
- This is the Alicloud profile name as set in the shared credentials file. It can also be sourced from the
- ALICLOUD_PROFILE environment variable.
+ E(ALICLOUD_PROFILE) environment variable.
type: str
shared_credentials_file:
description:
- - This is the path to the shared credentials file. It can also be sourced from the ALICLOUD_SHARED_CREDENTIALS_FILE
+ - This is the path to the shared credentials file. It can also be sourced from the E(ALICLOUD_SHARED_CREDENTIALS_FILE)
environment variable.
- - If this is not set and a profile is specified, ~/.aliyun/config.json will be used.
+ - If this is not set and a profile is specified, C(~/.aliyun/config.json) will be used.
type: str
author:
- "He Guimin (@xiaozhu36)"
requirements:
- - "python >= 3.6"
+ - "Python >= 3.6"
notes:
- If parameters are not set within the module, the following
environment variables can be used in decreasing order of precedence
- C(ALICLOUD_ACCESS_KEY) or C(ALICLOUD_ACCESS_KEY_ID),
- C(ALICLOUD_SECRET_KEY) or C(ALICLOUD_SECRET_ACCESS_KEY),
- C(ALICLOUD_REGION) or C(ALICLOUD_REGION_ID),
- C(ALICLOUD_SECURITY_TOKEN),
- C(ALICLOUD_ECS_ROLE_NAME),
- C(ALICLOUD_SHARED_CREDENTIALS_FILE),
- C(ALICLOUD_PROFILE),
- C(ALICLOUD_ASSUME_ROLE_ARN),
- C(ALICLOUD_ASSUME_ROLE_SESSION_NAME),
- C(ALICLOUD_ASSUME_ROLE_SESSION_EXPIRATION),
- - C(ALICLOUD_REGION) or C(ALICLOUD_REGION_ID) can be typically be used to specify the
- ALICLOUD region, when required, but this can also be configured in the footmark config file
+ E(ALICLOUD_ACCESS_KEY) or E(ALICLOUD_ACCESS_KEY_ID),
+ E(ALICLOUD_SECRET_KEY) or E(ALICLOUD_SECRET_ACCESS_KEY),
+ E(ALICLOUD_REGION) or E(ALICLOUD_REGION_ID),
+ E(ALICLOUD_SECURITY_TOKEN),
+ E(ALICLOUD_ECS_ROLE_NAME),
+ E(ALICLOUD_SHARED_CREDENTIALS_FILE),
+ E(ALICLOUD_PROFILE),
+ E(ALICLOUD_ASSUME_ROLE_ARN),
+ E(ALICLOUD_ASSUME_ROLE_SESSION_NAME),
+ E(ALICLOUD_ASSUME_ROLE_SESSION_EXPIRATION).
+ - E(ALICLOUD_REGION) or E(ALICLOUD_REGION_ID) can be typically be used to specify the
+ Alicloud region, when required, but this can also be configured in the footmark config file
'''
diff --git a/ansible_collections/community/general/plugins/doc_fragments/auth_basic.py b/ansible_collections/community/general/plugins/doc_fragments/auth_basic.py
index 674fb1e9a..77d127c62 100644
--- a/ansible_collections/community/general/plugins/doc_fragments/auth_basic.py
+++ b/ansible_collections/community/general/plugins/doc_fragments/auth_basic.py
@@ -14,19 +14,19 @@ class ModuleDocFragment(object):
options:
api_url:
description:
- - The resolvable endpoint for the API
+ - The resolvable endpoint for the API.
type: str
api_username:
description:
- - The username to use for authentication against the API
+ - The username to use for authentication against the API.
type: str
api_password:
description:
- - The password to use for authentication against the API
+ - The password to use for authentication against the API.
type: str
validate_certs:
description:
- - Whether or not to validate SSL certs when supplying a https endpoint.
+ - Whether or not to validate SSL certs when supplying a HTTPS endpoint.
type: bool
default: true
'''
diff --git a/ansible_collections/community/general/plugins/doc_fragments/bitbucket.py b/ansible_collections/community/general/plugins/doc_fragments/bitbucket.py
index 703bb412a..0a66ea0a6 100644
--- a/ansible_collections/community/general/plugins/doc_fragments/bitbucket.py
+++ b/ansible_collections/community/general/plugins/doc_fragments/bitbucket.py
@@ -16,25 +16,25 @@ options:
client_id:
description:
- The OAuth consumer key.
- - If not set the environment variable C(BITBUCKET_CLIENT_ID) will be used.
+ - If not set the environment variable E(BITBUCKET_CLIENT_ID) will be used.
type: str
client_secret:
description:
- The OAuth consumer secret.
- - If not set the environment variable C(BITBUCKET_CLIENT_SECRET) will be used.
+ - If not set the environment variable E(BITBUCKET_CLIENT_SECRET) will be used.
type: str
user:
description:
- The username.
- - If not set the environment variable C(BITBUCKET_USERNAME) will be used.
- - I(username) is an alias of I(user) since community.genreal 6.0.0. It was an alias of I(workspace) before.
+ - If not set the environment variable E(BITBUCKET_USERNAME) will be used.
+ - O(ignore:username) is an alias of O(user) since community.general 6.0.0. It was an alias of O(workspace) before.
type: str
version_added: 4.0.0
aliases: [ username ]
password:
description:
- The App password.
- - If not set the environment variable C(BITBUCKET_PASSWORD) will be used.
+ - If not set the environment variable E(BITBUCKET_PASSWORD) will be used.
type: str
version_added: 4.0.0
notes:
diff --git a/ansible_collections/community/general/plugins/doc_fragments/consul.py b/ansible_collections/community/general/plugins/doc_fragments/consul.py
new file mode 100644
index 000000000..fbe3f33d4
--- /dev/null
+++ b/ansible_collections/community/general/plugins/doc_fragments/consul.py
@@ -0,0 +1,60 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) Ansible project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+class ModuleDocFragment:
+ # Common parameters for Consul modules
+ DOCUMENTATION = r"""
+options:
+ host:
+ description:
+ - Host of the consul agent, defaults to V(localhost).
+ default: localhost
+ type: str
+ port:
+ type: int
+ description:
+ - The port on which the consul agent is running.
+ default: 8500
+ scheme:
+ description:
+ - The protocol scheme on which the consul agent is running.
+ Defaults to V(http) and can be set to V(https) for secure connections.
+ default: http
+ type: str
+ validate_certs:
+ type: bool
+ description:
+ - Whether to verify the TLS certificate of the consul agent.
+ default: true
+ ca_path:
+ description:
+ - The CA bundle to use for https connections
+ type: str
+"""
+
+ TOKEN = r"""
+options:
+ token:
+ description:
+ - The token to use for authorization.
+ type: str
+"""
+
+ ACTIONGROUP_CONSUL = r"""
+options: {}
+attributes:
+ action_group:
+ description: Use C(group/community.general.consul) in C(module_defaults) to set defaults for this module.
+ support: full
+ membership:
+ - community.general.consul
+ version_added: 8.3.0
+"""
diff --git a/ansible_collections/community/general/plugins/doc_fragments/dimensiondata.py b/ansible_collections/community/general/plugins/doc_fragments/dimensiondata.py
index f8372431e..f4d624454 100644
--- a/ansible_collections/community/general/plugins/doc_fragments/dimensiondata.py
+++ b/ansible_collections/community/general/plugins/doc_fragments/dimensiondata.py
@@ -20,22 +20,22 @@ options:
region:
description:
- The target region.
- - Regions are defined in Apache libcloud project [libcloud/common/dimensiondata.py]
- - They are also listed in U(https://libcloud.readthedocs.io/en/latest/compute/drivers/dimensiondata.html)
- - Note that the default value "na" stands for "North America".
- - The module prepends 'dd-' to the region choice.
+ - Regions are defined in Apache libcloud project [libcloud/common/dimensiondata.py].
+ - They are also listed in U(https://libcloud.readthedocs.io/en/latest/compute/drivers/dimensiondata.html).
+ - Note that the default value C(na) stands for "North America".
+ - The module prepends C(dd-) to the region choice.
type: str
default: na
mcp_user:
description:
- The username used to authenticate to the CloudControl API.
- - If not specified, will fall back to C(MCP_USER) from environment variable or C(~/.dimensiondata).
+ - If not specified, will fall back to E(MCP_USER) from environment variable or C(~/.dimensiondata).
type: str
mcp_password:
description:
- The password used to authenticate to the CloudControl API.
- - If not specified, will fall back to C(MCP_PASSWORD) from environment variable or C(~/.dimensiondata).
- - Required if I(mcp_user) is specified.
+ - If not specified, will fall back to E(MCP_PASSWORD) from environment variable or C(~/.dimensiondata).
+ - Required if O(mcp_user) is specified.
type: str
location:
description:
@@ -44,7 +44,7 @@ options:
required: true
validate_certs:
description:
- - If C(false), SSL certificates will not be validated.
+ - If V(false), SSL certificates will not be validated.
- This should only be used on private instances of the CloudControl API that use self-signed certificates.
type: bool
default: true
diff --git a/ansible_collections/community/general/plugins/doc_fragments/dimensiondata_wait.py b/ansible_collections/community/general/plugins/doc_fragments/dimensiondata_wait.py
index d37152839..051d8ca1d 100644
--- a/ansible_collections/community/general/plugins/doc_fragments/dimensiondata_wait.py
+++ b/ansible_collections/community/general/plugins/doc_fragments/dimensiondata_wait.py
@@ -25,13 +25,13 @@ options:
wait_time:
description:
- The maximum amount of time (in seconds) to wait for the task to complete.
- - Only applicable if I(wait=true).
+ - Only applicable if O(wait=true).
type: int
default: 600
wait_poll_interval:
description:
- The amount of time (in seconds) to wait between checks for task completion.
- - Only applicable if I(wait=true).
+ - Only applicable if O(wait=true).
type: int
default: 2
- '''
+'''
diff --git a/ansible_collections/community/general/plugins/doc_fragments/emc.py b/ansible_collections/community/general/plugins/doc_fragments/emc.py
index e9e57a2c1..d685c510d 100644
--- a/ansible_collections/community/general/plugins/doc_fragments/emc.py
+++ b/ansible_collections/community/general/plugins/doc_fragments/emc.py
@@ -39,8 +39,7 @@ options:
default: sysadmin
requirements:
- An EMC VNX Storage device.
- - Ansible 2.7.
- - storops (0.5.10 or greater). Install using 'pip install storops'.
+ - storops (0.5.10 or greater). Install using C(pip install storops).
notes:
- - The modules prefixed with emc_vnx are built to support the EMC VNX storage platform.
+ - The modules prefixed with C(emc_vnx) are built to support the EMC VNX storage platform.
'''
diff --git a/ansible_collections/community/general/plugins/doc_fragments/gitlab.py b/ansible_collections/community/general/plugins/doc_fragments/gitlab.py
index 705a93c02..c6434c0ce 100644
--- a/ansible_collections/community/general/plugins/doc_fragments/gitlab.py
+++ b/ansible_collections/community/general/plugins/doc_fragments/gitlab.py
@@ -29,4 +29,9 @@ options:
- GitLab CI job token for logging in.
type: str
version_added: 4.2.0
+ ca_path:
+ description:
+ - The CA certificates bundle to use to verify GitLab server certificate.
+ type: str
+ version_added: 8.1.0
'''
diff --git a/ansible_collections/community/general/plugins/doc_fragments/hwc.py b/ansible_collections/community/general/plugins/doc_fragments/hwc.py
index d3cebb6db..8b9ae92b8 100644
--- a/ansible_collections/community/general/plugins/doc_fragments/hwc.py
+++ b/ansible_collections/community/general/plugins/doc_fragments/hwc.py
@@ -19,8 +19,8 @@ options:
required: true
user:
description:
- - The user name to login with (currently only user names are
- supported, and not user IDs).
+ - The user name to login with.
+ - Currently only user names are supported, and not user IDs.
type: str
required: true
password:
@@ -31,14 +31,13 @@ options:
domain:
description:
- The name of the Domain to scope to (Identity v3).
- (currently only domain names are supported, and not domain IDs).
+ - Currently only domain names are supported, and not domain IDs.
type: str
required: true
project:
description:
- The name of the Tenant (Identity v2) or Project (Identity v3).
- (currently only project names are supported, and not
- project IDs).
+ - Currently only project names are supported, and not project IDs.
type: str
required: true
region:
@@ -47,20 +46,20 @@ options:
type: str
id:
description:
- - The id of resource to be managed.
+ - The ID of resource to be managed.
type: str
notes:
- For authentication, you can set identity_endpoint using the
- C(ANSIBLE_HWC_IDENTITY_ENDPOINT) env variable.
+ E(ANSIBLE_HWC_IDENTITY_ENDPOINT) environment variable.
- For authentication, you can set user using the
- C(ANSIBLE_HWC_USER) env variable.
- - For authentication, you can set password using the C(ANSIBLE_HWC_PASSWORD) env
+ E(ANSIBLE_HWC_USER) environment variable.
+ - For authentication, you can set password using the E(ANSIBLE_HWC_PASSWORD) environment
variable.
- - For authentication, you can set domain using the C(ANSIBLE_HWC_DOMAIN) env
+ - For authentication, you can set domain using the E(ANSIBLE_HWC_DOMAIN) environment
variable.
- - For authentication, you can set project using the C(ANSIBLE_HWC_PROJECT) env
+ - For authentication, you can set project using the E(ANSIBLE_HWC_PROJECT) environment
variable.
- - For authentication, you can set region using the C(ANSIBLE_HWC_REGION) env variable.
+ - For authentication, you can set region using the E(ANSIBLE_HWC_REGION) environment variable.
- Environment variables values will only be used if the playbook values are
not set.
'''
diff --git a/ansible_collections/community/general/plugins/doc_fragments/ibm_storage.py b/ansible_collections/community/general/plugins/doc_fragments/ibm_storage.py
index ff38c3fc7..7783d9ca5 100644
--- a/ansible_collections/community/general/plugins/doc_fragments/ibm_storage.py
+++ b/ansible_collections/community/general/plugins/doc_fragments/ibm_storage.py
@@ -31,8 +31,7 @@ options:
required: true
notes:
- This module requires pyxcli python library.
- Use 'pip install pyxcli' in order to get pyxcli.
+ Use C(pip install pyxcli) in order to get pyxcli.
requirements:
- - python >= 2.7
- pyxcli
'''
diff --git a/ansible_collections/community/general/plugins/doc_fragments/influxdb.py b/ansible_collections/community/general/plugins/doc_fragments/influxdb.py
index 6aedd5ad3..fc0ca02ac 100644
--- a/ansible_collections/community/general/plugins/doc_fragments/influxdb.py
+++ b/ansible_collections/community/general/plugins/doc_fragments/influxdb.py
@@ -16,39 +16,36 @@ options:
hostname:
description:
- The hostname or IP address on which InfluxDB server is listening.
- - Since Ansible 2.5, defaulted to localhost.
type: str
default: localhost
username:
description:
- Username that will be used to authenticate against InfluxDB server.
- - Alias C(login_username) added in Ansible 2.5.
type: str
default: root
aliases: [ login_username ]
password:
description:
- Password that will be used to authenticate against InfluxDB server.
- - Alias C(login_password) added in Ansible 2.5.
type: str
default: root
aliases: [ login_password ]
port:
description:
- - The port on which InfluxDB server is listening
+ - The port on which InfluxDB server is listening.
type: int
default: 8086
path:
description:
- - The path on which InfluxDB server is accessible
- - Only available when using python-influxdb >= 5.1.0
+ - The path on which InfluxDB server is accessible.
+ - Only available when using python-influxdb >= 5.1.0.
type: str
default: ''
version_added: '0.2.0'
validate_certs:
description:
- - If set to C(false), the SSL certificates will not be validated.
- - This should only set to C(false) used on personally controlled sites using self-signed certificates.
+ - If set to V(false), the SSL certificates will not be validated.
+ - This should only set to V(false) used on personally controlled sites using self-signed certificates.
type: bool
default: true
ssl:
@@ -63,8 +60,8 @@ options:
retries:
description:
- Number of retries client will try before aborting.
- - C(0) indicates try until success.
- - Only available when using python-influxdb >= 4.1.0
+ - V(0) indicates try until success.
+ - Only available when using python-influxdb >= 4.1.0.
type: int
default: 3
use_udp:
diff --git a/ansible_collections/community/general/plugins/doc_fragments/ipa.py b/ansible_collections/community/general/plugins/doc_fragments/ipa.py
index 5051c5539..7e091a94a 100644
--- a/ansible_collections/community/general/plugins/doc_fragments/ipa.py
+++ b/ansible_collections/community/general/plugins/doc_fragments/ipa.py
@@ -16,61 +16,56 @@ options:
ipa_port:
description:
- Port of FreeIPA / IPA server.
- - If the value is not specified in the task, the value of environment variable C(IPA_PORT) will be used instead.
- - If both the environment variable C(IPA_PORT) and the value are not specified in the task, then default value is set.
- - Environment variable fallback mechanism is added in Ansible 2.5.
+ - If the value is not specified in the task, the value of environment variable E(IPA_PORT) will be used instead.
+ - If both the environment variable E(IPA_PORT) and the value are not specified in the task, then default value is set.
type: int
default: 443
ipa_host:
description:
- IP or hostname of IPA server.
- - If the value is not specified in the task, the value of environment variable C(IPA_HOST) will be used instead.
- - If both the environment variable C(IPA_HOST) and the value are not specified in the task, then DNS will be used to try to discover the FreeIPA server.
- - The relevant entry needed in FreeIPA is the 'ipa-ca' entry.
- - If neither the DNS entry, nor the environment C(IPA_HOST), nor the value are available in the task, then the default value will be used.
- - Environment variable fallback mechanism is added in Ansible 2.5.
+ - If the value is not specified in the task, the value of environment variable E(IPA_HOST) will be used instead.
+ - If both the environment variable E(IPA_HOST) and the value are not specified in the task, then DNS will be used to try to discover the FreeIPA server.
+ - The relevant entry needed in FreeIPA is the C(ipa-ca) entry.
+ - If neither the DNS entry, nor the environment E(IPA_HOST), nor the value are available in the task, then the default value will be used.
type: str
default: ipa.example.com
ipa_user:
description:
- Administrative account used on IPA server.
- - If the value is not specified in the task, the value of environment variable C(IPA_USER) will be used instead.
- - If both the environment variable C(IPA_USER) and the value are not specified in the task, then default value is set.
- - Environment variable fallback mechanism is added in Ansible 2.5.
+ - If the value is not specified in the task, the value of environment variable E(IPA_USER) will be used instead.
+ - If both the environment variable E(IPA_USER) and the value are not specified in the task, then default value is set.
type: str
default: admin
ipa_pass:
description:
- Password of administrative user.
- - If the value is not specified in the task, the value of environment variable C(IPA_PASS) will be used instead.
- - Note that if the 'urllib_gssapi' library is available, it is possible to use GSSAPI to authenticate to FreeIPA.
- - If the environment variable C(KRB5CCNAME) is available, the module will use this kerberos credentials cache to authenticate to the FreeIPA server.
- - If the environment variable C(KRB5_CLIENT_KTNAME) is available, and C(KRB5CCNAME) is not; the module will use this kerberos keytab to authenticate.
- - If GSSAPI is not available, the usage of 'ipa_pass' is required.
- - Environment variable fallback mechanism is added in Ansible 2.5.
+ - If the value is not specified in the task, the value of environment variable E(IPA_PASS) will be used instead.
+ - Note that if the C(urllib_gssapi) library is available, it is possible to use GSSAPI to authenticate to FreeIPA.
+ - If the environment variable E(KRB5CCNAME) is available, the module will use this kerberos credentials cache to authenticate to the FreeIPA server.
+ - If the environment variable E(KRB5_CLIENT_KTNAME) is available, and E(KRB5CCNAME) is not; the module will use this kerberos keytab to authenticate.
+ - If GSSAPI is not available, the usage of O(ipa_pass) is required.
type: str
ipa_prot:
description:
- Protocol used by IPA server.
- - If the value is not specified in the task, the value of environment variable C(IPA_PROT) will be used instead.
- - If both the environment variable C(IPA_PROT) and the value are not specified in the task, then default value is set.
- - Environment variable fallback mechanism is added in Ansible 2.5.
+ - If the value is not specified in the task, the value of environment variable E(IPA_PROT) will be used instead.
+ - If both the environment variable E(IPA_PROT) and the value are not specified in the task, then default value is set.
type: str
choices: [ http, https ]
default: https
validate_certs:
description:
- - This only applies if C(ipa_prot) is I(https).
- - If set to C(false), the SSL certificates will not be validated.
- - This should only set to C(false) used on personally controlled sites using self-signed certificates.
+ - This only applies if O(ipa_prot) is V(https).
+ - If set to V(false), the SSL certificates will not be validated.
+ - This should only set to V(false) used on personally controlled sites using self-signed certificates.
type: bool
default: true
ipa_timeout:
description:
- Specifies idle timeout (in seconds) for the connection.
- For bulk operations, you may want to increase this in order to avoid timeout from IPA server.
- - If the value is not specified in the task, the value of environment variable C(IPA_TIMEOUT) will be used instead.
- - If both the environment variable C(IPA_TIMEOUT) and the value are not specified in the task, then default value is set.
+ - If the value is not specified in the task, the value of environment variable E(IPA_TIMEOUT) will be used instead.
+ - If both the environment variable E(IPA_TIMEOUT) and the value are not specified in the task, then default value is set.
type: int
default: 10
'''
diff --git a/ansible_collections/community/general/plugins/doc_fragments/keycloak.py b/ansible_collections/community/general/plugins/doc_fragments/keycloak.py
index 5d79fad7c..9b21ce52c 100644
--- a/ansible_collections/community/general/plugins/doc_fragments/keycloak.py
+++ b/ansible_collections/community/general/plugins/doc_fragments/keycloak.py
@@ -23,7 +23,7 @@ options:
auth_client_id:
description:
- - OpenID Connect I(client_id) to authenticate to the API with.
+ - OpenID Connect C(client_id) to authenticate to the API with.
type: str
default: admin-cli
@@ -34,7 +34,7 @@ options:
auth_client_secret:
description:
- - Client Secret to use in conjunction with I(auth_client_id) (if required).
+ - Client Secret to use in conjunction with O(auth_client_id) (if required).
type: str
auth_username:
@@ -69,6 +69,7 @@ options:
type: int
default: 10
version_added: 4.5.0
+
http_agent:
description:
- Configures the HTTP User-Agent header.
diff --git a/ansible_collections/community/general/plugins/doc_fragments/ldap.py b/ansible_collections/community/general/plugins/doc_fragments/ldap.py
index b321c75eb..e11ab065d 100644
--- a/ansible_collections/community/general/plugins/doc_fragments/ldap.py
+++ b/ansible_collections/community/general/plugins/doc_fragments/ldap.py
@@ -21,7 +21,7 @@ options:
type: str
bind_pw:
description:
- - The password to use with I(bind_dn).
+ - The password to use with O(bind_dn).
type: str
default: ''
ca_path:
@@ -29,6 +29,18 @@ options:
- Set the path to PEM file with CA certs.
type: path
version_added: "6.5.0"
+ client_cert:
+ type: path
+ description:
+ - PEM formatted certificate chain file to be used for SSL client authentication.
+ - Required if O(client_key) is defined.
+ version_added: "7.1.0"
+ client_key:
+ type: path
+ description:
+ - PEM formatted file that contains your private key to be used for SSL client authentication.
+ - Required if O(client_cert) is defined.
+ version_added: "7.1.0"
dn:
required: true
description:
@@ -40,12 +52,12 @@ options:
type: str
description:
- Set the referrals chasing behavior.
- - C(anonymous) follow referrals anonymously. This is the default behavior.
- - C(disabled) disable referrals chasing. This sets C(OPT_REFERRALS) to off.
+ - V(anonymous) follow referrals anonymously. This is the default behavior.
+ - V(disabled) disable referrals chasing. This sets C(OPT_REFERRALS) to off.
version_added: 2.0.0
server_uri:
description:
- - The I(server_uri) parameter may be a comma- or whitespace-separated list of URIs containing only the schema, the host, and the port fields.
+ - The O(server_uri) parameter may be a comma- or whitespace-separated list of URIs containing only the schema, the host, and the port fields.
- The default value lets the underlying LDAP client library look for a UNIX domain socket in its default location.
- Note that when using multiple URIs you cannot determine to which URI your client gets connected.
- For URIs containing additional fields, particularly when using commas, behavior is undefined.
@@ -58,14 +70,13 @@ options:
default: false
validate_certs:
description:
- - If set to C(false), SSL certificates will not be validated.
+ - If set to V(false), SSL certificates will not be validated.
- This should only be used on sites using self-signed certificates.
type: bool
default: true
sasl_class:
description:
- The class to use for SASL authentication.
- - Possible choices are C(external), C(gssapi).
type: str
choices: ['external', 'gssapi']
default: external
@@ -73,10 +84,9 @@ options:
xorder_discovery:
description:
- Set the behavior on how to process Xordered DNs.
- - C(enable) will perform a C(ONELEVEL) search below the superior RDN to find the matching DN.
- - C(disable) will always use the DN unmodified (as passed by the I(dn) parameter).
- - C(auto) will only perform a search if the first RDN does not contain an index number (C({x})).
- - Possible choices are C(enable), C(auto), C(disable).
+ - V(enable) will perform a C(ONELEVEL) search below the superior RDN to find the matching DN.
+ - V(disable) will always use the DN unmodified (as passed by the O(dn) parameter).
+ - V(auto) will only perform a search if the first RDN does not contain an index number (C({x})).
type: str
choices: ['enable', 'auto', 'disable']
default: auto
diff --git a/ansible_collections/community/general/plugins/doc_fragments/lxca_common.py b/ansible_collections/community/general/plugins/doc_fragments/lxca_common.py
index b5e7d7294..eed6727c2 100644
--- a/ansible_collections/community/general/plugins/doc_fragments/lxca_common.py
+++ b/ansible_collections/community/general/plugins/doc_fragments/lxca_common.py
@@ -30,7 +30,7 @@ options:
auth_url:
description:
- - lxca https full web address
+ - lxca HTTPS full web address.
type: str
required: true
@@ -38,7 +38,6 @@ requirements:
- pylxca
notes:
- - Additional detail about pylxca can be found at U(https://github.com/lenovo/pylxca)
- - Playbooks using these modules can be found at U(https://github.com/lenovo/ansible.lenovo-lxca)
- - Check mode is not supported.
+ - Additional detail about pylxca can be found at U(https://github.com/lenovo/pylxca).
+ - Playbooks using these modules can be found at U(https://github.com/lenovo/ansible.lenovo-lxca).
'''
diff --git a/ansible_collections/community/general/plugins/doc_fragments/manageiq.py b/ansible_collections/community/general/plugins/doc_fragments/manageiq.py
index 030d68238..8afc183a5 100644
--- a/ansible_collections/community/general/plugins/doc_fragments/manageiq.py
+++ b/ansible_collections/community/general/plugins/doc_fragments/manageiq.py
@@ -21,30 +21,30 @@ options:
suboptions:
url:
description:
- - ManageIQ environment url. C(MIQ_URL) env var if set. otherwise, it is required to pass it.
+ - ManageIQ environment URL. E(MIQ_URL) environment variable if set. Otherwise, it is required to pass it.
type: str
required: false
username:
description:
- - ManageIQ username. C(MIQ_USERNAME) env var if set. otherwise, required if no token is passed in.
+ - ManageIQ username. E(MIQ_USERNAME) environment variable if set. Otherwise, required if no token is passed in.
type: str
password:
description:
- - ManageIQ password. C(MIQ_PASSWORD) env var if set. otherwise, required if no token is passed in.
+ - ManageIQ password. E(MIQ_PASSWORD) environment variable if set. Otherwise, required if no token is passed in.
type: str
token:
description:
- - ManageIQ token. C(MIQ_TOKEN) env var if set. otherwise, required if no username or password is passed in.
+ - ManageIQ token. E(MIQ_TOKEN) environment variable if set. Otherwise, required if no username or password is passed in.
type: str
validate_certs:
description:
- - Whether SSL certificates should be verified for HTTPS requests. defaults to True.
+ - Whether SSL certificates should be verified for HTTPS requests.
type: bool
default: true
aliases: [ verify_ssl ]
ca_cert:
description:
- - The path to a CA bundle file or directory with certificates. defaults to None.
+ - The path to a CA bundle file or directory with certificates.
type: str
aliases: [ ca_bundle_path ]
diff --git a/ansible_collections/community/general/plugins/doc_fragments/nomad.py b/ansible_collections/community/general/plugins/doc_fragments/nomad.py
index b19404e83..1571c211c 100644
--- a/ansible_collections/community/general/plugins/doc_fragments/nomad.py
+++ b/ansible_collections/community/general/plugins/doc_fragments/nomad.py
@@ -18,6 +18,12 @@ options:
- FQDN of Nomad server.
required: true
type: str
+ port:
+ description:
+ - Port of Nomad server.
+ type: int
+ default: 4646
+ version_added: 8.0.0
use_ssl:
description:
- Use TLS/SSL connection.
@@ -47,6 +53,6 @@ options:
type: str
token:
description:
- - ACL token for authentification.
+ - ACL token for authentication.
type: str
'''
diff --git a/ansible_collections/community/general/plugins/doc_fragments/onepassword.py b/ansible_collections/community/general/plugins/doc_fragments/onepassword.py
new file mode 100644
index 000000000..4035f8179
--- /dev/null
+++ b/ansible_collections/community/general/plugins/doc_fragments/onepassword.py
@@ -0,0 +1,79 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2023, Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+
+class ModuleDocFragment(object):
+ DOCUMENTATION = r'''
+requirements:
+ - See U(https://support.1password.com/command-line/)
+options:
+ master_password:
+ description: The password used to unlock the specified vault.
+ aliases: ['vault_password']
+ type: str
+ section:
+ description: Item section containing the field to retrieve (case-insensitive). If absent will return first match from any section.
+ domain:
+ description: Domain of 1Password.
+ default: '1password.com'
+ type: str
+ subdomain:
+ description: The 1Password subdomain to authenticate against.
+ type: str
+ account_id:
+ description: The account ID to target.
+ type: str
+ username:
+ description: The username used to sign in.
+ type: str
+ secret_key:
+ description: The secret key used when performing an initial sign in.
+ type: str
+ service_account_token:
+ description:
+ - The access key for a service account.
+ - Only works with 1Password CLI version 2 or later.
+ type: str
+ vault:
+ description: Vault containing the item to retrieve (case-insensitive). If absent will search all vaults.
+ type: str
+ connect_host:
+ description: The host for 1Password Connect. Must be used in combination with O(connect_token).
+ type: str
+ env:
+ - name: OP_CONNECT_HOST
+ version_added: 8.1.0
+ connect_token:
+ description: The token for 1Password Connect. Must be used in combination with O(connect_host).
+ type: str
+ env:
+ - name: OP_CONNECT_TOKEN
+ version_added: 8.1.0
+'''
+
+ LOOKUP = r'''
+options:
+ service_account_token:
+ env:
+ - name: OP_SERVICE_ACCOUNT_TOKEN
+ version_added: 8.2.0
+notes:
+ - This lookup will use an existing 1Password session if one exists. If not, and you have already
+ performed an initial sign in (meaning C(~/.op/config), C(~/.config/op/config) or C(~/.config/.op/config) exists), then only the
+ O(master_password) is required. You may optionally specify O(subdomain) in this scenario, otherwise the last used subdomain will be used by C(op).
+ - This lookup can perform an initial login by providing O(subdomain), O(username), O(secret_key), and O(master_password).
+ - Can target a specific account by providing the O(account_id).
+ - Due to the B(very) sensitive nature of these credentials, it is B(highly) recommended that you only pass in the minimal credentials
+ needed at any given time. Also, store these credentials in an Ansible Vault using a key that is equal to or greater in strength
+ to the 1Password master password.
+ - This lookup stores potentially sensitive data from 1Password as Ansible facts.
+ Facts are subject to caching if enabled, which means this data could be stored in clear text
+ on disk or in a database.
+ - Tested with C(op) version 2.7.2.
+'''
diff --git a/ansible_collections/community/general/plugins/doc_fragments/oneview.py b/ansible_collections/community/general/plugins/doc_fragments/oneview.py
index 54288e51f..a88226d7d 100644
--- a/ansible_collections/community/general/plugins/doc_fragments/oneview.py
+++ b/ansible_collections/community/general/plugins/doc_fragments/oneview.py
@@ -15,7 +15,7 @@ class ModuleDocFragment(object):
options:
config:
description:
- - Path to a .json configuration file containing the OneView client configuration.
+ - Path to a JSON configuration file containing the OneView client configuration.
The configuration file is optional and when used should be present in the host running the ansible commands.
If the file path is not provided, the configuration will be loaded from environment variables.
For links to example configuration files or how to use the environment variables verify the notes section.
@@ -42,7 +42,7 @@ options:
type: str
requirements:
- - python >= 2.7.9
+ - Python >= 2.7.9
notes:
- "A sample configuration file for the config parameter can be found at:
@@ -70,11 +70,11 @@ options:
options:
params:
description:
- - List of params to delimit, filter and sort the list of resources.
- - "params allowed:
- - C(start): The first item to return, using 0-based indexing.
- - C(count): The number of resources to return.
- - C(filter): A general filter/query string to narrow the list of items returned.
- - C(sort): The sort order of the returned data set."
+ - List of parameters to delimit, filter and sort the list of resources.
+ - "Parameter keys allowed are:"
+ - "C(start): The first item to return, using 0-based indexing."
+ - "C(count): The number of resources to return."
+ - "C(filter): A general filter/query string to narrow the list of items returned."
+ - "C(sort): The sort order of the returned data set."
type: dict
'''
diff --git a/ansible_collections/community/general/plugins/doc_fragments/online.py b/ansible_collections/community/general/plugins/doc_fragments/online.py
index d7e13765b..37e39cfa2 100644
--- a/ansible_collections/community/general/plugins/doc_fragments/online.py
+++ b/ansible_collections/community/general/plugins/doc_fragments/online.py
@@ -20,7 +20,7 @@ options:
aliases: [ oauth_token ]
api_url:
description:
- - Online API URL
+ - Online API URL.
type: str
default: 'https://api.online.net'
aliases: [ base_url ]
@@ -36,10 +36,10 @@ options:
type: bool
default: true
notes:
- - Also see the API documentation on U(https://console.online.net/en/api/)
- - If C(api_token) is not set within the module, the following
+ - Also see the API documentation on U(https://console.online.net/en/api/).
+ - If O(api_token) is not set within the module, the following
environment variables can be used in decreasing order of precedence
- C(ONLINE_TOKEN), C(ONLINE_API_KEY), C(ONLINE_OAUTH_TOKEN), C(ONLINE_API_TOKEN)
- - If one wants to use a different C(api_url) one can also set the C(ONLINE_API_URL)
+ E(ONLINE_TOKEN), E(ONLINE_API_KEY), E(ONLINE_OAUTH_TOKEN), E(ONLINE_API_TOKEN).
+ - If one wants to use a different O(api_url) one can also set the E(ONLINE_API_URL)
environment variable.
'''
diff --git a/ansible_collections/community/general/plugins/doc_fragments/opennebula.py b/ansible_collections/community/general/plugins/doc_fragments/opennebula.py
index 0fc323271..567faf1a7 100644
--- a/ansible_collections/community/general/plugins/doc_fragments/opennebula.py
+++ b/ansible_collections/community/general/plugins/doc_fragments/opennebula.py
@@ -15,26 +15,26 @@ options:
api_url:
description:
- The ENDPOINT URL of the XMLRPC server.
- - If not specified then the value of the ONE_URL environment variable, if any, is used.
+ - If not specified then the value of the E(ONE_URL) environment variable, if any, is used.
type: str
aliases:
- api_endpoint
api_username:
description:
- The name of the user for XMLRPC authentication.
- - If not specified then the value of the ONE_USERNAME environment variable, if any, is used.
+ - If not specified then the value of the E(ONE_USERNAME) environment variable, if any, is used.
type: str
api_password:
description:
- The password or token for XMLRPC authentication.
- - If not specified then the value of the ONE_PASSWORD environment variable, if any, is used.
+ - If not specified then the value of the E(ONE_PASSWORD) environment variable, if any, is used.
type: str
aliases:
- api_token
validate_certs:
description:
- - Whether to validate the SSL certificates or not.
- - This parameter is ignored if PYTHONHTTPSVERIFY environment variable is used.
+ - Whether to validate the TLS/SSL certificates or not.
+ - This parameter is ignored if E(PYTHONHTTPSVERIFY) environment variable is used.
type: bool
default: true
wait_timeout:
diff --git a/ansible_collections/community/general/plugins/doc_fragments/openswitch.py b/ansible_collections/community/general/plugins/doc_fragments/openswitch.py
index 9d5f0be74..a203a3b40 100644
--- a/ansible_collections/community/general/plugins/doc_fragments/openswitch.py
+++ b/ansible_collections/community/general/plugins/doc_fragments/openswitch.py
@@ -23,7 +23,7 @@ options:
port:
description:
- Specifies the port to use when building the connection to the remote
- device. This value applies to either I(cli) or I(rest). The port
+ device. This value applies to either O(transport=cli) or O(transport=rest). The port
value will default to the appropriate transport common port if
none is provided in the task. (cli=22, http=80, https=443). Note
this argument does not affect the SSH transport.
@@ -36,15 +36,15 @@ options:
either the CLI login or the eAPI authentication depending on which
transport is used. Note this argument does not affect the SSH
transport. If the value is not specified in the task, the value of
- environment variable C(ANSIBLE_NET_USERNAME) will be used instead.
+ environment variable E(ANSIBLE_NET_USERNAME) will be used instead.
type: str
password:
description:
- Specifies the password to use to authenticate the connection to
- the remote device. This is a common argument used for either I(cli)
- or I(rest) transports. Note this argument does not affect the SSH
+ the remote device. This is a common argument used for either O(transport=cli)
+ or O(transport=rest). Note this argument does not affect the SSH
transport. If the value is not specified in the task, the value of
- environment variable C(ANSIBLE_NET_PASSWORD) will be used instead.
+ environment variable E(ANSIBLE_NET_PASSWORD) will be used instead.
type: str
timeout:
description:
@@ -56,29 +56,29 @@ options:
ssh_keyfile:
description:
- Specifies the SSH key to use to authenticate the connection to
- the remote device. This argument is only used for the I(cli)
- transports. If the value is not specified in the task, the value of
- environment variable C(ANSIBLE_NET_SSH_KEYFILE) will be used instead.
+ the remote device. This argument is only used for O(transport=cli).
+ If the value is not specified in the task, the value of
+ environment variable E(ANSIBLE_NET_SSH_KEYFILE) will be used instead.
type: path
transport:
description:
- Configures the transport connection to use when connecting to the
remote device. The transport argument supports connectivity to the
- device over ssh, cli or REST.
+ device over SSH (V(ssh)), CLI (V(cli)), or REST (V(rest)).
required: true
type: str
choices: [ cli, rest, ssh ]
default: ssh
use_ssl:
description:
- - Configures the I(transport) to use SSL if set to C(true) only when the
- I(transport) argument is configured as rest. If the transport
- argument is not I(rest), this value is ignored.
+ - Configures the O(transport) to use SSL if set to V(true) only when the
+ O(transport) argument is configured as rest. If the transport
+ argument is not V(rest), this value is ignored.
type: bool
default: true
provider:
description:
- - Convenience method that allows all I(openswitch) arguments to be passed as
+ - Convenience method that allows all C(openswitch) arguments to be passed as
a dict object. All constraints (required, choices, etc) must be
met either by individual arguments or values in this dict.
type: dict
diff --git a/ansible_collections/community/general/plugins/doc_fragments/oracle.py b/ansible_collections/community/general/plugins/doc_fragments/oracle.py
index 9ca4706ba..ff0ed2fd5 100644
--- a/ansible_collections/community/general/plugins/doc_fragments/oracle.py
+++ b/ansible_collections/community/general/plugins/doc_fragments/oracle.py
@@ -10,36 +10,35 @@ __metaclass__ = type
class ModuleDocFragment(object):
DOCUMENTATION = """
requirements:
- - "python >= 2.7"
- - Python SDK for Oracle Cloud Infrastructure U(https://oracle-cloud-infrastructure-python-sdk.readthedocs.io)
+ - Python SDK for Oracle Cloud Infrastructure U(https://oracle-cloud-infrastructure-python-sdk.readthedocs.io)
notes:
- - For OCI python sdk configuration, please refer to
- U(https://oracle-cloud-infrastructure-python-sdk.readthedocs.io/en/latest/configuration.html)
+ - For OCI Python SDK configuration, please refer to
+ U(https://oracle-cloud-infrastructure-python-sdk.readthedocs.io/en/latest/configuration.html).
options:
config_file_location:
description:
- - Path to configuration file. If not set then the value of the OCI_CONFIG_FILE environment variable,
- if any, is used. Otherwise, defaults to ~/.oci/config.
+ - Path to configuration file. If not set then the value of the E(OCI_CONFIG_FILE) environment variable,
+ if any, is used. Otherwise, defaults to C(~/.oci/config).
type: str
config_profile_name:
description:
- - The profile to load from the config file referenced by C(config_file_location). If not set, then the
- value of the OCI_CONFIG_PROFILE environment variable, if any, is used. Otherwise, defaults to the
- "DEFAULT" profile in C(config_file_location).
+ - The profile to load from the config file referenced by O(config_file_location). If not set, then the
+ value of the E(OCI_CONFIG_PROFILE) environment variable, if any, is used. Otherwise, defaults to the
+ C(DEFAULT) profile in O(config_file_location).
default: "DEFAULT"
type: str
api_user:
description:
- The OCID of the user, on whose behalf, OCI APIs are invoked. If not set, then the
- value of the OCI_USER_OCID environment variable, if any, is used. This option is required if the user
- is not specified through a configuration file (See C(config_file_location)). To get the user's OCID,
+ value of the E(OCI_USER_OCID) environment variable, if any, is used. This option is required if the user
+ is not specified through a configuration file (See O(config_file_location)). To get the user's OCID,
please refer U(https://docs.us-phoenix-1.oraclecloud.com/Content/API/Concepts/apisigningkey.htm).
type: str
api_user_fingerprint:
description:
- - Fingerprint for the key pair being used. If not set, then the value of the OCI_USER_FINGERPRINT
+ - Fingerprint for the key pair being used. If not set, then the value of the E(OCI_USER_FINGERPRINT)
environment variable, if any, is used. This option is required if the key fingerprint is not
- specified through a configuration file (See C(config_file_location)). To get the key pair's
+ specified through a configuration file (See O(config_file_location)). To get the key pair's
fingerprint value please refer
U(https://docs.us-phoenix-1.oraclecloud.com/Content/API/Concepts/apisigningkey.htm).
type: str
@@ -47,21 +46,21 @@ class ModuleDocFragment(object):
description:
- Full path and filename of the private key (in PEM format). If not set, then the value of the
OCI_USER_KEY_FILE variable, if any, is used. This option is required if the private key is
- not specified through a configuration file (See C(config_file_location)). If the key is encrypted
- with a pass-phrase, the C(api_user_key_pass_phrase) option must also be provided.
+ not specified through a configuration file (See O(config_file_location)). If the key is encrypted
+ with a pass-phrase, the O(api_user_key_pass_phrase) option must also be provided.
type: path
api_user_key_pass_phrase:
description:
- - Passphrase used by the key referenced in C(api_user_key_file), if it is encrypted. If not set, then
+ - Passphrase used by the key referenced in O(api_user_key_file), if it is encrypted. If not set, then
the value of the OCI_USER_KEY_PASS_PHRASE variable, if any, is used. This option is required if the
- key passphrase is not specified through a configuration file (See C(config_file_location)).
+ key passphrase is not specified through a configuration file (See O(config_file_location)).
type: str
auth_type:
description:
- - The type of authentication to use for making API requests. By default C(auth_type="api_key") based
- authentication is performed and the API key (see I(api_user_key_file)) in your config file will be
+ - The type of authentication to use for making API requests. By default O(auth_type=api_key) based
+ authentication is performed and the API key (see O(api_user_key_file)) in your config file will be
used. If this 'auth_type' module option is not specified, the value of the OCI_ANSIBLE_AUTH_TYPE,
- if any, is used. Use C(auth_type="instance_principal") to use instance principal based authentication
+ if any, is used. Use O(auth_type=instance_principal) to use instance principal based authentication
when running ansible playbooks within an OCI compute instance.
choices: ['api_key', 'instance_principal']
default: 'api_key'
@@ -70,14 +69,14 @@ class ModuleDocFragment(object):
description:
- OCID of your tenancy. If not set, then the value of the OCI_TENANCY variable, if any, is
used. This option is required if the tenancy OCID is not specified through a configuration file
- (See C(config_file_location)). To get the tenancy OCID, please refer
- U(https://docs.us-phoenix-1.oraclecloud.com/Content/API/Concepts/apisigningkey.htm)
+ (See O(config_file_location)). To get the tenancy OCID, please refer to
+ U(https://docs.us-phoenix-1.oraclecloud.com/Content/API/Concepts/apisigningkey.htm).
type: str
region:
description:
- The Oracle Cloud Infrastructure region to use for all OCI API requests. If not set, then the
value of the OCI_REGION variable, if any, is used. This option is required if the region is
- not specified through a configuration file (See C(config_file_location)). Please refer to
+ not specified through a configuration file (See O(config_file_location)). Please refer to
U(https://docs.us-phoenix-1.oraclecloud.com/Content/General/Concepts/regions.htm) for more information
on OCI regions.
type: str
diff --git a/ansible_collections/community/general/plugins/doc_fragments/oracle_creatable_resource.py b/ansible_collections/community/general/plugins/doc_fragments/oracle_creatable_resource.py
index 529381919..9d2cc07c9 100644
--- a/ansible_collections/community/general/plugins/doc_fragments/oracle_creatable_resource.py
+++ b/ansible_collections/community/general/plugins/doc_fragments/oracle_creatable_resource.py
@@ -14,13 +14,13 @@ class ModuleDocFragment(object):
description: Whether to attempt non-idempotent creation of a resource. By default, create resource is an
idempotent operation, and doesn't create the resource if it already exists. Setting this option
to true, forcefully creates a copy of the resource, even if it already exists.This option is
- mutually exclusive with I(key_by).
+ mutually exclusive with O(key_by).
default: false
type: bool
key_by:
description: The list of comma-separated attributes of this resource which should be used to uniquely
identify an instance of the resource. By default, all the attributes of a resource except
- I(freeform_tags) are used to uniquely identify a resource.
+ O(freeform_tags) are used to uniquely identify a resource.
type: list
elements: str
"""
diff --git a/ansible_collections/community/general/plugins/doc_fragments/oracle_display_name_option.py b/ansible_collections/community/general/plugins/doc_fragments/oracle_display_name_option.py
index eae5f4459..b6bc0f229 100644
--- a/ansible_collections/community/general/plugins/doc_fragments/oracle_display_name_option.py
+++ b/ansible_collections/community/general/plugins/doc_fragments/oracle_display_name_option.py
@@ -11,7 +11,7 @@ class ModuleDocFragment(object):
DOCUMENTATION = """
options:
display_name:
- description: Use I(display_name) along with the other options to return only resources that match the given
+ description: Use O(display_name) along with the other options to return only resources that match the given
display name exactly.
type: str
"""
diff --git a/ansible_collections/community/general/plugins/doc_fragments/oracle_name_option.py b/ansible_collections/community/general/plugins/doc_fragments/oracle_name_option.py
index 362071f94..523eed702 100644
--- a/ansible_collections/community/general/plugins/doc_fragments/oracle_name_option.py
+++ b/ansible_collections/community/general/plugins/doc_fragments/oracle_name_option.py
@@ -11,7 +11,7 @@ class ModuleDocFragment(object):
DOCUMENTATION = """
options:
name:
- description: Use I(name) along with the other options to return only resources that match the given name
+ description: Use O(name) along with the other options to return only resources that match the given name
exactly.
type: str
"""
diff --git a/ansible_collections/community/general/plugins/doc_fragments/oracle_wait_options.py b/ansible_collections/community/general/plugins/doc_fragments/oracle_wait_options.py
index ce7ea776e..0ba253232 100644
--- a/ansible_collections/community/general/plugins/doc_fragments/oracle_wait_options.py
+++ b/ansible_collections/community/general/plugins/doc_fragments/oracle_wait_options.py
@@ -15,13 +15,13 @@ class ModuleDocFragment(object):
default: true
type: bool
wait_timeout:
- description: Time, in seconds, to wait when I(wait=true).
+ description: Time, in seconds, to wait when O(wait=true).
default: 1200
type: int
wait_until:
- description: The lifecycle state to wait for the resource to transition into when I(wait=true). By default,
- when I(wait=true), we wait for the resource to get into ACTIVE/ATTACHED/AVAILABLE/PROVISIONED/
- RUNNING applicable lifecycle state during create operation & to get into DELETED/DETACHED/
+ description: The lifecycle state to wait for the resource to transition into when O(wait=true). By default,
+ when O(wait=true), we wait for the resource to get into ACTIVE/ATTACHED/AVAILABLE/PROVISIONED/
+ RUNNING applicable lifecycle state during create operation and to get into DELETED/DETACHED/
TERMINATED lifecycle state during delete operation.
type: str
"""
diff --git a/ansible_collections/community/general/plugins/doc_fragments/pritunl.py b/ansible_collections/community/general/plugins/doc_fragments/pritunl.py
index 51ab979b5..396ee0866 100644
--- a/ansible_collections/community/general/plugins/doc_fragments/pritunl.py
+++ b/ansible_collections/community/general/plugins/doc_fragments/pritunl.py
@@ -38,7 +38,7 @@ options:
default: true
description:
- If certificates should be validated or not.
- - This should never be set to C(false), except if you are very sure that
+ - This should never be set to V(false), except if you are very sure that
your connection to the server can not be subject to a Man In The Middle
attack.
"""
diff --git a/ansible_collections/community/general/plugins/doc_fragments/proxmox.py b/ansible_collections/community/general/plugins/doc_fragments/proxmox.py
index e39af4f3a..4972da498 100644
--- a/ansible_collections/community/general/plugins/doc_fragments/proxmox.py
+++ b/ansible_collections/community/general/plugins/doc_fragments/proxmox.py
@@ -24,21 +24,23 @@ options:
api_password:
description:
- Specify the password to authenticate with.
- - You can use C(PROXMOX_PASSWORD) environment variable.
+ - You can use E(PROXMOX_PASSWORD) environment variable.
type: str
api_token_id:
description:
- Specify the token ID.
+ - Requires C(proxmoxer>=1.1.0) to work.
type: str
version_added: 1.3.0
api_token_secret:
description:
- Specify the token secret.
+ - Requires C(proxmoxer>=1.1.0) to work.
type: str
version_added: 1.3.0
validate_certs:
description:
- - If C(false), SSL certificates will not be validated.
+ - If V(false), SSL certificates will not be validated.
- This should only be used on personally controlled sites using self-signed certificates.
type: bool
default: false
@@ -55,7 +57,7 @@ options:
node:
description:
- Proxmox VE node on which to operate.
- - Only required for I(state=present).
+ - Only required for O(state=present).
- For every other states it will be autodiscovered.
type: str
pool:
diff --git a/ansible_collections/community/general/plugins/doc_fragments/purestorage.py b/ansible_collections/community/general/plugins/doc_fragments/purestorage.py
index 8db8c3b3d..823397763 100644
--- a/ansible_collections/community/general/plugins/doc_fragments/purestorage.py
+++ b/ansible_collections/community/general/plugins/doc_fragments/purestorage.py
@@ -32,11 +32,10 @@ options:
- FlashBlade API token for admin privileged user.
type: str
notes:
- - This module requires the C(purity_fb) Python library
- - You must set C(PUREFB_URL) and C(PUREFB_API) environment variables
- if I(fb_url) and I(api_token) arguments are not passed to the module directly
+ - This module requires the C(purity_fb) Python library.
+ - You must set E(PUREFB_URL) and E(PUREFB_API) environment variables
+ if O(fb_url) and O(api_token) arguments are not passed to the module directly.
requirements:
- - python >= 2.7
- purity_fb >= 1.1
'''
@@ -54,10 +53,9 @@ options:
type: str
required: true
notes:
- - This module requires the C(purestorage) Python library
- - You must set C(PUREFA_URL) and C(PUREFA_API) environment variables
- if I(fa_url) and I(api_token) arguments are not passed to the module directly
+ - This module requires the C(purestorage) Python library.
+ - You must set E(PUREFA_URL) and E(PUREFA_API) environment variables
+ if O(fa_url) and O(api_token) arguments are not passed to the module directly.
requirements:
- - python >= 2.7
- purestorage
'''
diff --git a/ansible_collections/community/general/plugins/doc_fragments/rackspace.py b/ansible_collections/community/general/plugins/doc_fragments/rackspace.py
index 9e2231602..f28be777c 100644
--- a/ansible_collections/community/general/plugins/doc_fragments/rackspace.py
+++ b/ansible_collections/community/general/plugins/doc_fragments/rackspace.py
@@ -15,18 +15,18 @@ class ModuleDocFragment(object):
options:
api_key:
description:
- - Rackspace API key, overrides I(credentials).
+ - Rackspace API key, overrides O(credentials).
type: str
aliases: [ password ]
credentials:
description:
- - File to find the Rackspace credentials in. Ignored if I(api_key) and
- I(username) are provided.
+ - File to find the Rackspace credentials in. Ignored if O(api_key) and
+ O(username) are provided.
type: path
aliases: [ creds_file ]
env:
description:
- - Environment as configured in I(~/.pyrax.cfg),
+ - Environment as configured in C(~/.pyrax.cfg),
see U(https://github.com/rackspace/pyrax/blob/master/docs/getting_started.md#pyrax-configuration).
type: str
region:
@@ -35,7 +35,7 @@ options:
type: str
username:
description:
- - Rackspace username, overrides I(credentials).
+ - Rackspace username, overrides O(credentials).
type: str
validate_certs:
description:
@@ -43,15 +43,14 @@ options:
type: bool
aliases: [ verify_ssl ]
requirements:
- - python >= 2.6
- pyrax
notes:
- - The following environment variables can be used, C(RAX_USERNAME),
- C(RAX_API_KEY), C(RAX_CREDS_FILE), C(RAX_CREDENTIALS), C(RAX_REGION).
- - C(RAX_CREDENTIALS) and C(RAX_CREDS_FILE) points to a credentials file
- appropriate for pyrax. See U(https://github.com/rackspace/pyrax/blob/master/docs/getting_started.md#authenticating)
- - C(RAX_USERNAME) and C(RAX_API_KEY) obviate the use of a credentials file
- - C(RAX_REGION) defines a Rackspace Public Cloud region (DFW, ORD, LON, ...)
+ - The following environment variables can be used, E(RAX_USERNAME),
+ E(RAX_API_KEY), E(RAX_CREDS_FILE), E(RAX_CREDENTIALS), E(RAX_REGION).
+ - E(RAX_CREDENTIALS) and E(RAX_CREDS_FILE) point to a credentials file
+ appropriate for pyrax. See U(https://github.com/rackspace/pyrax/blob/master/docs/getting_started.md#authenticating).
+ - E(RAX_USERNAME) and E(RAX_API_KEY) obviate the use of a credentials file.
+ - E(RAX_REGION) defines a Rackspace Public Cloud region (DFW, ORD, LON, ...).
'''
# Documentation fragment including attributes to enable communication
@@ -61,23 +60,23 @@ options:
api_key:
type: str
description:
- - Rackspace API key, overrides I(credentials).
+ - Rackspace API key, overrides O(credentials).
aliases: [ password ]
auth_endpoint:
type: str
description:
- The URI of the authentication service.
- - If not specified will be set to U(https://identity.api.rackspacecloud.com/v2.0/)
+ - If not specified will be set to U(https://identity.api.rackspacecloud.com/v2.0/).
credentials:
type: path
description:
- - File to find the Rackspace credentials in. Ignored if I(api_key) and
- I(username) are provided.
+ - File to find the Rackspace credentials in. Ignored if O(api_key) and
+ O(username) are provided.
aliases: [ creds_file ]
env:
type: str
description:
- - Environment as configured in I(~/.pyrax.cfg),
+ - Environment as configured in C(~/.pyrax.cfg),
see U(https://github.com/rackspace/pyrax/blob/master/docs/getting_started.md#pyrax-configuration).
identity_type:
type: str
@@ -99,20 +98,23 @@ options:
username:
type: str
description:
- - Rackspace username, overrides I(credentials).
+ - Rackspace username, overrides O(credentials).
validate_certs:
description:
- Whether or not to require SSL validation of API endpoints.
type: bool
aliases: [ verify_ssl ]
+deprecated:
+ removed_in: 9.0.0
+ why: This module relies on the deprecated package pyrax.
+ alternative: Use the Openstack modules instead.
requirements:
- - python >= 2.6
- pyrax
notes:
- - The following environment variables can be used, C(RAX_USERNAME),
- C(RAX_API_KEY), C(RAX_CREDS_FILE), C(RAX_CREDENTIALS), C(RAX_REGION).
- - C(RAX_CREDENTIALS) and C(RAX_CREDS_FILE) points to a credentials file
- appropriate for pyrax. See U(https://github.com/rackspace/pyrax/blob/master/docs/getting_started.md#authenticating)
- - C(RAX_USERNAME) and C(RAX_API_KEY) obviate the use of a credentials file
- - C(RAX_REGION) defines a Rackspace Public Cloud region (DFW, ORD, LON, ...)
+ - The following environment variables can be used, E(RAX_USERNAME),
+ E(RAX_API_KEY), E(RAX_CREDS_FILE), E(RAX_CREDENTIALS), E(RAX_REGION).
+ - E(RAX_CREDENTIALS) and E(RAX_CREDS_FILE) points to a credentials file
+ appropriate for pyrax. See U(https://github.com/rackspace/pyrax/blob/master/docs/getting_started.md#authenticating).
+ - E(RAX_USERNAME) and E(RAX_API_KEY) obviate the use of a credentials file.
+ - E(RAX_REGION) defines a Rackspace Public Cloud region (DFW, ORD, LON, ...).
'''
diff --git a/ansible_collections/community/general/plugins/doc_fragments/redis.py b/ansible_collections/community/general/plugins/doc_fragments/redis.py
index 2d4033051..fafb52c86 100644
--- a/ansible_collections/community/general/plugins/doc_fragments/redis.py
+++ b/ansible_collections/community/general/plugins/doc_fragments/redis.py
@@ -46,8 +46,8 @@ options:
default: true
ca_certs:
description:
- - Path to root certificates file. If not set and I(tls) is
- set to C(true), certifi ca-certificates will be used.
+ - Path to root certificates file. If not set and O(tls) is
+ set to V(true), certifi ca-certificates will be used.
type: str
requirements: [ "redis", "certifi" ]
diff --git a/ansible_collections/community/general/plugins/doc_fragments/scaleway.py b/ansible_collections/community/general/plugins/doc_fragments/scaleway.py
index b08d11dbb..bdb0dd056 100644
--- a/ansible_collections/community/general/plugins/doc_fragments/scaleway.py
+++ b/ansible_collections/community/general/plugins/doc_fragments/scaleway.py
@@ -42,10 +42,10 @@ options:
type: bool
default: true
notes:
- - Also see the API documentation on U(https://developer.scaleway.com/)
- - If C(api_token) is not set within the module, the following
+ - Also see the API documentation on U(https://developer.scaleway.com/).
+ - If O(api_token) is not set within the module, the following
environment variables can be used in decreasing order of precedence
- C(SCW_TOKEN), C(SCW_API_KEY), C(SCW_OAUTH_TOKEN) or C(SCW_API_TOKEN).
- - If one wants to use a different C(api_url) one can also set the C(SCW_API_URL)
+ E(SCW_TOKEN), E(SCW_API_KEY), E(SCW_OAUTH_TOKEN) or E(SCW_API_TOKEN).
+ - If one wants to use a different O(api_url) one can also set the E(SCW_API_URL)
environment variable.
'''
diff --git a/ansible_collections/community/general/plugins/doc_fragments/utm.py b/ansible_collections/community/general/plugins/doc_fragments/utm.py
index 73ad80503..3e0bc6e10 100644
--- a/ansible_collections/community/general/plugins/doc_fragments/utm.py
+++ b/ansible_collections/community/general/plugins/doc_fragments/utm.py
@@ -14,7 +14,7 @@ options:
headers:
description:
- A dictionary of additional headers to be sent to POST and PUT requests.
- - Is needed for some modules
+ - Is needed for some modules.
type: dict
required: false
default: {}
@@ -30,8 +30,9 @@ options:
default: 4444
utm_token:
description:
- - "The token used to identify at the REST-API. See U(https://www.sophos.com/en-us/medialibrary/\
- PDFs/documentation/UTMonAWS/Sophos-UTM-RESTful-API.pdf?la=en), Chapter 2.4.2."
+ - "The token used to identify at the REST-API. See
+ U(https://www.sophos.com/en-us/medialibrary/PDFs/documentation/UTMonAWS/Sophos-UTM-RESTful-API.pdf?la=en),
+ Chapter 2.4.2."
type: str
required: true
utm_protocol:
@@ -48,8 +49,8 @@ options:
state:
description:
- The desired state of the object.
- - C(present) will create or update an object
- - C(absent) will delete an object if it was present
+ - V(present) will create or update an object.
+ - V(absent) will delete an object if it was present.
type: str
choices: [ absent, present ]
default: present
diff --git a/ansible_collections/community/general/plugins/doc_fragments/vexata.py b/ansible_collections/community/general/plugins/doc_fragments/vexata.py
index ff79613ee..041f404d2 100644
--- a/ansible_collections/community/general/plugins/doc_fragments/vexata.py
+++ b/ansible_collections/community/general/plugins/doc_fragments/vexata.py
@@ -30,17 +30,19 @@ options:
user:
description:
- Vexata API user with administrative privileges.
+ - Uses the E(VEXATA_USER) environment variable as a fallback.
required: false
type: str
password:
description:
- Vexata API user password.
+ - Uses the E(VEXATA_PASSWORD) environment variable as a fallback.
required: false
type: str
validate_certs:
description:
- - Allows connection when SSL certificates are not valid. Set to C(false) when certificates are not trusted.
- - If set to C(true), please make sure Python >= 2.7.9 is installed on the given machine.
+ - Allows connection when SSL certificates are not valid. Set to V(false) when certificates are not trusted.
+ - If set to V(true), please make sure Python >= 2.7.9 is installed on the given machine.
required: false
type: bool
default: false
@@ -48,7 +50,6 @@ options:
requirements:
- Vexata VX100 storage array with VXOS >= v3.5.0 on storage array
- vexatapi >= 0.0.1
- - python >= 2.7
- - VEXATA_USER and VEXATA_PASSWORD environment variables must be set if
+ - E(VEXATA_USER) and E(VEXATA_PASSWORD) environment variables must be set if
user and password arguments are not passed to the module directly.
'''
diff --git a/ansible_collections/community/general/plugins/doc_fragments/xenserver.py b/ansible_collections/community/general/plugins/doc_fragments/xenserver.py
index eaee17384..681d959fa 100644
--- a/ansible_collections/community/general/plugins/doc_fragments/xenserver.py
+++ b/ansible_collections/community/general/plugins/doc_fragments/xenserver.py
@@ -15,27 +15,27 @@ options:
hostname:
description:
- The hostname or IP address of the XenServer host or XenServer pool master.
- - If the value is not specified in the task, the value of environment variable C(XENSERVER_HOST) will be used instead.
+ - If the value is not specified in the task, the value of environment variable E(XENSERVER_HOST) will be used instead.
type: str
default: localhost
aliases: [ host, pool ]
username:
description:
- The username to use for connecting to XenServer.
- - If the value is not specified in the task, the value of environment variable C(XENSERVER_USER) will be used instead.
+ - If the value is not specified in the task, the value of environment variable E(XENSERVER_USER) will be used instead.
type: str
default: root
aliases: [ admin, user ]
password:
description:
- The password to use for connecting to XenServer.
- - If the value is not specified in the task, the value of environment variable C(XENSERVER_PASSWORD) will be used instead.
+ - If the value is not specified in the task, the value of environment variable E(XENSERVER_PASSWORD) will be used instead.
type: str
aliases: [ pass, pwd ]
validate_certs:
description:
- - Allows connection when SSL certificates are not valid. Set to C(false) when certificates are not trusted.
- - If the value is not specified in the task, the value of environment variable C(XENSERVER_VALIDATE_CERTS) will be used instead.
+ - Allows connection when SSL certificates are not valid. Set to V(false) when certificates are not trusted.
+ - If the value is not specified in the task, the value of environment variable E(XENSERVER_VALIDATE_CERTS) will be used instead.
type: bool
default: true
'''
diff --git a/ansible_collections/community/general/plugins/filter/from_csv.py b/ansible_collections/community/general/plugins/filter/from_csv.py
index 6472b67b1..310138d49 100644
--- a/ansible_collections/community/general/plugins/filter/from_csv.py
+++ b/ansible_collections/community/general/plugins/filter/from_csv.py
@@ -23,7 +23,7 @@ DOCUMENTATION = '''
dialect:
description:
- The CSV dialect to use when parsing the CSV file.
- - Possible values include C(excel), C(excel-tab) or C(unix).
+ - Possible values include V(excel), V(excel-tab) or V(unix).
type: str
default: excel
fieldnames:
@@ -35,19 +35,19 @@ DOCUMENTATION = '''
delimiter:
description:
- A one-character string used to separate fields.
- - When using this parameter, you change the default value used by I(dialect).
+ - When using this parameter, you change the default value used by O(dialect).
- The default value depends on the dialect used.
type: str
skipinitialspace:
description:
- Whether to ignore any whitespaces immediately following the delimiter.
- - When using this parameter, you change the default value used by I(dialect).
+ - When using this parameter, you change the default value used by O(dialect).
- The default value depends on the dialect used.
type: bool
strict:
description:
- Whether to raise an exception on bad CSV input.
- - When using this parameter, you change the default value used by I(dialect).
+ - When using this parameter, you change the default value used by O(dialect).
- The default value depends on the dialect used.
type: bool
'''
@@ -56,7 +56,7 @@ EXAMPLES = '''
- name: Parse a CSV file's contents
ansible.builtin.debug:
msg: >-
- {{ csv_data | community.genera.from_csv(dialect='unix') }}
+ {{ csv_data | community.general.from_csv(dialect='unix') }}
vars:
csv_data: |
Column 1,Value
diff --git a/ansible_collections/community/general/plugins/filter/from_ini.py b/ansible_collections/community/general/plugins/filter/from_ini.py
new file mode 100644
index 000000000..d68b51092
--- /dev/null
+++ b/ansible_collections/community/general/plugins/filter/from_ini.py
@@ -0,0 +1,99 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2023, Steffen Scheib <steffen@scheib.me>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+DOCUMENTATION = r'''
+ name: from_ini
+ short_description: Converts INI text input into a dictionary
+ version_added: 8.2.0
+ author: Steffen Scheib (@sscheib)
+ description:
+ - Converts INI text input into a dictionary.
+ options:
+ _input:
+ description: A string containing an INI document.
+ type: string
+ required: true
+'''
+
+EXAMPLES = r'''
+ - name: Slurp an INI file
+ ansible.builtin.slurp:
+ src: /etc/rhsm/rhsm.conf
+ register: rhsm_conf
+
+ - name: Display the INI file as dictionary
+ ansible.builtin.debug:
+ var: rhsm_conf.content | b64decode | community.general.from_ini
+
+ - name: Set a new dictionary fact with the contents of the INI file
+ ansible.builtin.set_fact:
+ rhsm_dict: >-
+ {{
+ rhsm_conf.content | b64decode | community.general.from_ini
+ }}
+'''
+
+RETURN = '''
+ _value:
+ description: A dictionary representing the INI file.
+ type: dictionary
+'''
+
+__metaclass__ = type
+
+from ansible.errors import AnsibleFilterError
+from ansible.module_utils.six import string_types
+from ansible.module_utils.six.moves import StringIO
+from ansible.module_utils.six.moves.configparser import ConfigParser
+from ansible.module_utils.common.text.converters import to_native
+
+
+class IniParser(ConfigParser):
+ ''' Implements a configparser which is able to return a dict '''
+
+ def __init__(self):
+ super().__init__()
+ self.optionxform = str
+
+ def as_dict(self):
+ d = dict(self._sections)
+ for k in d:
+ d[k] = dict(self._defaults, **d[k])
+ d[k].pop('__name__', None)
+
+ if self._defaults:
+ d['DEFAULT'] = dict(self._defaults)
+
+ return d
+
+
+def from_ini(obj):
+ ''' Read the given string as INI file and return a dict '''
+
+ if not isinstance(obj, string_types):
+ raise AnsibleFilterError(f'from_ini requires a str, got {type(obj)}')
+
+ parser = IniParser()
+
+ try:
+ parser.read_file(StringIO(obj))
+ except Exception as ex:
+ raise AnsibleFilterError(f'from_ini failed to parse given string: '
+ f'{to_native(ex)}', orig_exc=ex)
+
+ return parser.as_dict()
+
+
+class FilterModule(object):
+ ''' Query filter '''
+
+ def filters(self):
+
+ return {
+ 'from_ini': from_ini
+ }
diff --git a/ansible_collections/community/general/plugins/filter/jc.py b/ansible_collections/community/general/plugins/filter/jc.py
index 3aa8d20a5..2fe3ef9d7 100644
--- a/ansible_collections/community/general/plugins/filter/jc.py
+++ b/ansible_collections/community/general/plugins/filter/jc.py
@@ -25,17 +25,17 @@ DOCUMENTATION = '''
parser:
description:
- The correct parser for the input data.
- - For example C(ifconfig).
+ - For example V(ifconfig).
- "Note: use underscores instead of dashes (if any) in the parser module name."
- See U(https://github.com/kellyjonbrazil/jc#parsers) for the latest list of parsers.
type: string
required: true
quiet:
- description: Set to C(false) to not suppress warnings.
+ description: Set to V(false) to not suppress warnings.
type: boolean
default: true
raw:
- description: Set to C(true) to return pre-processed JSON.
+ description: Set to V(true) to return pre-processed JSON.
type: boolean
default: false
requirements:
diff --git a/ansible_collections/community/general/plugins/filter/lists.py b/ansible_collections/community/general/plugins/filter/lists.py
new file mode 100644
index 000000000..d16f955c2
--- /dev/null
+++ b/ansible_collections/community/general/plugins/filter/lists.py
@@ -0,0 +1,210 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+from ansible.errors import AnsibleFilterError
+from ansible.module_utils.common.collections import is_sequence
+
+
+def remove_duplicates(lst):
+ seen = set()
+ seen_add = seen.add
+ result = []
+ for item in lst:
+ try:
+ if item not in seen:
+ seen_add(item)
+ result.append(item)
+ except TypeError:
+ # This happens for unhashable values `item`. If this happens,
+ # convert `seen` to a list and continue.
+ seen = list(seen)
+ seen_add = seen.append
+ if item not in seen:
+ seen_add(item)
+ result.append(item)
+ return result
+
+
+def flatten_list(lst):
+ result = []
+ for sublist in lst:
+ if not is_sequence(sublist):
+ msg = ("All arguments must be lists. %s is %s")
+ raise AnsibleFilterError(msg % (sublist, type(sublist)))
+ if len(sublist) > 0:
+ if all(is_sequence(sub) for sub in sublist):
+ for item in sublist:
+ result.append(item)
+ else:
+ result.append(sublist)
+ return result
+
+
+def lists_union(*args, **kwargs):
+ lists = args
+ flatten = kwargs.pop('flatten', False)
+
+ if kwargs:
+ # Some unused kwargs remain
+ raise AnsibleFilterError(
+ "lists_union() got unexpected keywords arguments: {0}".format(
+ ", ".join(kwargs.keys())
+ )
+ )
+
+ if flatten:
+ lists = flatten_list(args)
+
+ if not lists:
+ return []
+
+ if len(lists) == 1:
+ return lists[0]
+
+ a = lists[0]
+ for b in lists[1:]:
+ a = do_union(a, b)
+ return remove_duplicates(a)
+
+
+def do_union(a, b):
+ return a + b
+
+
+def lists_intersect(*args, **kwargs):
+ lists = args
+ flatten = kwargs.pop('flatten', False)
+
+ if kwargs:
+ # Some unused kwargs remain
+ raise AnsibleFilterError(
+ "lists_intersect() got unexpected keywords arguments: {0}".format(
+ ", ".join(kwargs.keys())
+ )
+ )
+
+ if flatten:
+ lists = flatten_list(args)
+
+ if not lists:
+ return []
+
+ if len(lists) == 1:
+ return lists[0]
+
+ a = remove_duplicates(lists[0])
+ for b in lists[1:]:
+ a = do_intersect(a, b)
+ return a
+
+
+def do_intersect(a, b):
+ isect = []
+ try:
+ other = set(b)
+ isect = [item for item in a if item in other]
+ except TypeError:
+ # This happens for unhashable values,
+ # use a list instead and redo.
+ other = list(b)
+ isect = [item for item in a if item in other]
+ return isect
+
+
+def lists_difference(*args, **kwargs):
+ lists = args
+ flatten = kwargs.pop('flatten', False)
+
+ if kwargs:
+ # Some unused kwargs remain
+ raise AnsibleFilterError(
+ "lists_difference() got unexpected keywords arguments: {0}".format(
+ ", ".join(kwargs.keys())
+ )
+ )
+
+ if flatten:
+ lists = flatten_list(args)
+
+ if not lists:
+ return []
+
+ if len(lists) == 1:
+ return lists[0]
+
+ a = remove_duplicates(lists[0])
+ for b in lists[1:]:
+ a = do_difference(a, b)
+ return a
+
+
+def do_difference(a, b):
+ diff = []
+ try:
+ other = set(b)
+ diff = [item for item in a if item not in other]
+ except TypeError:
+ # This happens for unhashable values,
+ # use a list instead and redo.
+ other = list(b)
+ diff = [item for item in a if item not in other]
+ return diff
+
+
+def lists_symmetric_difference(*args, **kwargs):
+ lists = args
+ flatten = kwargs.pop('flatten', False)
+
+ if kwargs:
+ # Some unused kwargs remain
+ raise AnsibleFilterError(
+ "lists_difference() got unexpected keywords arguments: {0}".format(
+ ", ".join(kwargs.keys())
+ )
+ )
+
+ if flatten:
+ lists = flatten_list(args)
+
+ if not lists:
+ return []
+
+ if len(lists) == 1:
+ return lists[0]
+
+ a = lists[0]
+ for b in lists[1:]:
+ a = do_symmetric_difference(a, b)
+ return a
+
+
+def do_symmetric_difference(a, b):
+ sym_diff = []
+ union = lists_union(a, b)
+ try:
+ isect = set(a) & set(b)
+ sym_diff = [item for item in union if item not in isect]
+ except TypeError:
+ # This happens for unhashable values,
+ # build the intersection of `a` and `b` backed
+ # by a list instead of a set and redo.
+ isect = lists_intersect(a, b)
+ sym_diff = [item for item in union if item not in isect]
+ return sym_diff
+
+
+class FilterModule(object):
+ ''' Ansible lists jinja2 filters '''
+
+ def filters(self):
+ return {
+ 'lists_union': lists_union,
+ 'lists_intersect': lists_intersect,
+ 'lists_difference': lists_difference,
+ 'lists_symmetric_difference': lists_symmetric_difference,
+ }
diff --git a/ansible_collections/community/general/plugins/filter/lists_difference.yml b/ansible_collections/community/general/plugins/filter/lists_difference.yml
new file mode 100644
index 000000000..9806a9f0b
--- /dev/null
+++ b/ansible_collections/community/general/plugins/filter/lists_difference.yml
@@ -0,0 +1,48 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+DOCUMENTATION:
+ name: lists_difference
+ short_description: Difference of lists with a predictive order
+ version_added: 8.4.0
+ description:
+ - Provide a unique list of all the elements from the first which do not appear in the other lists.
+ - The order of the items in the resulting list is preserved.
+ options:
+ _input:
+ description: A list.
+ type: list
+ elements: any
+ required: true
+ flatten:
+ description: Whether to remove one hierarchy level from the input list.
+ type: boolean
+ default: false
+ author:
+ - Christoph Fiehe (@cfiehe)
+
+EXAMPLES: |
+ - name: Return the difference of list1 and list2.
+ ansible.builtin.debug:
+ msg: "{{ list1 | community.general.lists_difference(list2) }}"
+ vars:
+ list1: [1, 2, 5, 3, 4, 10]
+ list2: [1, 2, 3, 4, 5, 11, 99]
+ # => [10]
+
+ - name: Return the difference of list1, list2 and list3.
+ ansible.builtin.debug:
+ msg: "{{ [list1, list2, list3] | community.general.lists_difference(flatten=true) }}"
+ vars:
+ list1: [1, 2, 5, 3, 4, 10]
+ list2: [1, 2, 3, 4, 5, 11, 99]
+ list3: [1, 2, 3, 4, 5, 10, 99, 101]
+ # => []
+
+RETURN:
+ _value:
+ description: A unique list of all the elements from the first list that do not appear on the other lists.
+ type: list
+ elements: any
diff --git a/ansible_collections/community/general/plugins/filter/lists_intersect.yml b/ansible_collections/community/general/plugins/filter/lists_intersect.yml
new file mode 100644
index 000000000..8253463de
--- /dev/null
+++ b/ansible_collections/community/general/plugins/filter/lists_intersect.yml
@@ -0,0 +1,48 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+DOCUMENTATION:
+ name: lists_intersect
+ short_description: Intersection of lists with a predictive order
+ version_added: 8.4.0
+ description:
+ - Provide a unique list of all the common elements of two or more lists.
+ - The order of the items in the resulting list is preserved.
+ options:
+ _input:
+ description: A list.
+ type: list
+ elements: any
+ required: true
+ flatten:
+ description: Whether to remove one hierarchy level from the input list.
+ type: boolean
+ default: false
+ author:
+ - Christoph Fiehe (@cfiehe)
+
+EXAMPLES: |
+ - name: Return the intersection of list1 and list2.
+ ansible.builtin.debug:
+ msg: "{{ list1 | community.general.lists_intersect(list2) }}"
+ vars:
+ list1: [1, 2, 5, 3, 4, 10]
+ list2: [1, 2, 3, 4, 5, 11, 99]
+ # => [1, 2, 5, 3, 4]
+
+ - name: Return the intersection of list1, list2 and list3.
+ ansible.builtin.debug:
+ msg: "{{ [list1, list2, list3] | community.general.lists_intersect(flatten=true) }}"
+ vars:
+ list1: [1, 2, 5, 3, 4, 10]
+ list2: [1, 2, 3, 4, 5, 11, 99]
+ list3: [1, 2, 3, 4, 5, 10, 99, 101]
+ # => [1, 2, 5, 3, 4]
+
+RETURN:
+ _value:
+ description: A unique list of all the common elements from the provided lists.
+ type: list
+ elements: any
diff --git a/ansible_collections/community/general/plugins/filter/lists_mergeby.py b/ansible_collections/community/general/plugins/filter/lists_mergeby.py
index 036dfe4d7..caf183492 100644
--- a/ansible_collections/community/general/plugins/filter/lists_mergeby.py
+++ b/ansible_collections/community/general/plugins/filter/lists_mergeby.py
@@ -12,9 +12,9 @@ DOCUMENTATION = '''
version_added: 2.0.0
author: Vladimir Botka (@vbotka)
description:
- - Merge two or more lists by attribute I(index). Optional parameters 'recursive' and 'list_merge'
+ - Merge two or more lists by attribute O(index). Optional parameters O(recursive) and O(list_merge)
control the merging of the lists in values. The function merge_hash from ansible.utils.vars
- is used. To learn details on how to use the parameters 'recursive' and 'list_merge' see
+ is used. To learn details on how to use the parameters O(recursive) and O(list_merge) see
Ansible User's Guide chapter "Using filters to manipulate data" section "Combining
hashes/dictionaries".
positional: another_list, index
diff --git a/ansible_collections/community/general/plugins/filter/lists_symmetric_difference.yml b/ansible_collections/community/general/plugins/filter/lists_symmetric_difference.yml
new file mode 100644
index 000000000..d985704c2
--- /dev/null
+++ b/ansible_collections/community/general/plugins/filter/lists_symmetric_difference.yml
@@ -0,0 +1,48 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+DOCUMENTATION:
+ name: lists_symmetric_difference
+ short_description: Symmetric Difference of lists with a predictive order
+ version_added: 8.4.0
+ description:
+ - Provide a unique list containing the symmetric difference of two or more lists.
+ - The order of the items in the resulting list is preserved.
+ options:
+ _input:
+ description: A list.
+ type: list
+ elements: any
+ required: true
+ flatten:
+ description: Whether to remove one hierarchy level from the input list.
+ type: boolean
+ default: false
+ author:
+ - Christoph Fiehe (@cfiehe)
+
+EXAMPLES: |
+ - name: Return the symmetric difference of list1 and list2.
+ ansible.builtin.debug:
+ msg: "{{ list1 | community.general.lists_symmetric_difference(list2) }}"
+ vars:
+ list1: [1, 2, 5, 3, 4, 10]
+ list2: [1, 2, 3, 4, 5, 11, 99]
+ # => [10, 11, 99]
+
+ - name: Return the symmetric difference of list1, list2 and list3.
+ ansible.builtin.debug:
+ msg: "{{ [list1, list2, list3] | community.general.lists_symmetric_difference(flatten=true) }}"
+ vars:
+ list1: [1, 2, 5, 3, 4, 10]
+ list2: [1, 2, 3, 4, 5, 11, 99]
+ list3: [1, 2, 3, 4, 5, 10, 99, 101]
+ # => [11, 1, 2, 3, 4, 5, 101]
+
+RETURN:
+ _value:
+ description: A unique list containing the symmetric difference of two or more lists.
+ type: list
+ elements: any
diff --git a/ansible_collections/community/general/plugins/filter/lists_union.yml b/ansible_collections/community/general/plugins/filter/lists_union.yml
new file mode 100644
index 000000000..ba6909083
--- /dev/null
+++ b/ansible_collections/community/general/plugins/filter/lists_union.yml
@@ -0,0 +1,48 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+DOCUMENTATION:
+ name: lists_union
+ short_description: Union of lists with a predictive order
+ version_added: 8.4.0
+ description:
+ - Provide a unique list of all the elements of two or more lists.
+ - The order of the items in the resulting list is preserved.
+ options:
+ _input:
+ description: A list.
+ type: list
+ elements: any
+ required: true
+ flatten:
+ description: Whether to remove one hierarchy level from the input list.
+ type: boolean
+ default: false
+ author:
+ - Christoph Fiehe (@cfiehe)
+
+EXAMPLES: |
+ - name: Return the union of list1, list2 and list3.
+ ansible.builtin.debug:
+ msg: "{{ list1 | community.general.lists_union(list2, list3) }}"
+ vars:
+ list1: [1, 2, 5, 3, 4, 10]
+ list2: [1, 2, 3, 4, 5, 11, 99]
+ list3: [1, 2, 3, 4, 5, 10, 99, 101]
+ # => [1, 2, 5, 3, 4, 10, 11, 99, 101]
+
+ - name: Return the union of list1 and list2.
+ ansible.builtin.debug:
+ msg: "{{ [list1, list2] | community.general.lists_union(flatten=true) }}"
+ vars:
+ list1: [1, 2, 5, 3, 4, 10]
+ list2: [1, 2, 3, 4, 5, 11, 99]
+ # => [1, 2, 5, 3, 4, 10, 11, 99]
+
+RETURN:
+ _value:
+ description: A unique list of all the elements from the provided lists.
+ type: list
+ elements: any
diff --git a/ansible_collections/community/general/plugins/filter/to_days.yml b/ansible_collections/community/general/plugins/filter/to_days.yml
index 19bc8faf2..b5f6424fa 100644
--- a/ansible_collections/community/general/plugins/filter/to_days.yml
+++ b/ansible_collections/community/general/plugins/filter/to_days.yml
@@ -13,12 +13,12 @@ DOCUMENTATION:
_input:
description:
- The time string to convert.
- - Can use the units C(y) and C(year) for a year, C(mo) and C(month) for a month, C(w) and C(week) for a week,
- C(d) and C(day) for a day, C(h) and C(hour) for a hour, C(m), C(min) and C(minute) for minutes, C(s), C(sec)
- and C(second) for seconds, C(ms), C(msec), C(msecond) and C(millisecond) for milliseconds. The suffix C(s)
- can be added to a unit as well, so C(seconds) is the same as C(second).
+ - Can use the units V(y) and V(year) for a year, V(mo) and V(month) for a month, V(w) and V(week) for a week,
+ V(d) and V(day) for a day, V(h) and V(hour) for a hour, V(m), V(min) and V(minute) for minutes, V(s), V(sec)
+ and V(second) for seconds, V(ms), V(msec), V(msecond) and V(millisecond) for milliseconds. The suffix V(s)
+ can be added to a unit as well, so V(seconds) is the same as V(second).
- Valid strings are space separated combinations of an integer with an optional minus sign and a unit.
- - Examples are C(1h), C(-5m), and C(3h -5m 6s).
+ - Examples are V(1h), V(-5m), and V(3h -5m 6s).
type: string
required: true
year:
diff --git a/ansible_collections/community/general/plugins/filter/to_hours.yml b/ansible_collections/community/general/plugins/filter/to_hours.yml
index 83826a590..353fdfc31 100644
--- a/ansible_collections/community/general/plugins/filter/to_hours.yml
+++ b/ansible_collections/community/general/plugins/filter/to_hours.yml
@@ -13,12 +13,12 @@ DOCUMENTATION:
_input:
description:
- The time string to convert.
- - Can use the units C(y) and C(year) for a year, C(mo) and C(month) for a month, C(w) and C(week) for a week,
- C(d) and C(day) for a day, C(h) and C(hour) for a hour, C(m), C(min) and C(minute) for minutes, C(s), C(sec)
- and C(second) for seconds, C(ms), C(msec), C(msecond) and C(millisecond) for milliseconds. The suffix C(s)
- can be added to a unit as well, so C(seconds) is the same as C(second).
+ - Can use the units V(y) and V(year) for a year, V(mo) and V(month) for a month, V(w) and V(week) for a week,
+ V(d) and V(day) for a day, V(h) and V(hour) for a hour, V(m), V(min) and V(minute) for minutes, V(s), V(sec)
+ and V(second) for seconds, V(ms), V(msec), V(msecond) and V(millisecond) for milliseconds. The suffix V(s)
+ can be added to a unit as well, so V(seconds) is the same as V(second).
- Valid strings are space separated combinations of an integer with an optional minus sign and a unit.
- - Examples are C(1h), C(-5m), and C(3h -5m 6s).
+ - Examples are V(1h), V(-5m), and V(3h -5m 6s).
type: string
required: true
year:
diff --git a/ansible_collections/community/general/plugins/filter/to_ini.py b/ansible_collections/community/general/plugins/filter/to_ini.py
new file mode 100644
index 000000000..22ef16d72
--- /dev/null
+++ b/ansible_collections/community/general/plugins/filter/to_ini.py
@@ -0,0 +1,105 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2023, Steffen Scheib <steffen@scheib.me>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+DOCUMENTATION = r'''
+ name: to_ini
+ short_description: Converts a dictionary to the INI file format
+ version_added: 8.2.0
+ author: Steffen Scheib (@sscheib)
+ description:
+ - Converts a dictionary to the INI file format.
+ options:
+ _input:
+ description: The dictionary that should be converted to the INI format.
+ type: dictionary
+ required: true
+'''
+
+EXAMPLES = r'''
+ - name: Define a dictionary
+ ansible.builtin.set_fact:
+ my_dict:
+ section_name:
+ key_name: 'key value'
+
+ another_section:
+ connection: 'ssh'
+
+ - name: Write dictionary to INI file
+ ansible.builtin.copy:
+ dest: /tmp/test.ini
+ content: '{{ my_dict | community.general.to_ini }}'
+
+ # /tmp/test.ini will look like this:
+ # [section_name]
+ # key_name = key value
+ #
+ # [another_section]
+ # connection = ssh
+'''
+
+RETURN = r'''
+ _value:
+ description: A string formatted as INI file.
+ type: string
+'''
+
+
+__metaclass__ = type
+
+from ansible.errors import AnsibleFilterError
+from ansible.module_utils.common._collections_compat import Mapping
+from ansible.module_utils.six.moves import StringIO
+from ansible.module_utils.six.moves.configparser import ConfigParser
+from ansible.module_utils.common.text.converters import to_native
+
+
+class IniParser(ConfigParser):
+ ''' Implements a configparser which sets the correct optionxform '''
+
+ def __init__(self):
+ super().__init__()
+ self.optionxform = str
+
+
+def to_ini(obj):
+ ''' Read the given dict and return an INI formatted string '''
+
+ if not isinstance(obj, Mapping):
+ raise AnsibleFilterError(f'to_ini requires a dict, got {type(obj)}')
+
+ ini_parser = IniParser()
+
+ try:
+ ini_parser.read_dict(obj)
+ except Exception as ex:
+ raise AnsibleFilterError('to_ini failed to parse given dict:'
+ f'{to_native(ex)}', orig_exc=ex)
+
+ # catching empty dicts
+ if obj == dict():
+ raise AnsibleFilterError('to_ini received an empty dict. '
+ 'An empty dict cannot be converted.')
+
+ config = StringIO()
+ ini_parser.write(config)
+
+ # config.getvalue() returns two \n at the end
+ # with the below insanity, we remove the very last character of
+ # the resulting string
+ return ''.join(config.getvalue().rsplit(config.getvalue()[-1], 1))
+
+
+class FilterModule(object):
+ ''' Query filter '''
+
+ def filters(self):
+
+ return {
+ 'to_ini': to_ini
+ }
diff --git a/ansible_collections/community/general/plugins/filter/to_milliseconds.yml b/ansible_collections/community/general/plugins/filter/to_milliseconds.yml
index b6bb7e4be..19ed02438 100644
--- a/ansible_collections/community/general/plugins/filter/to_milliseconds.yml
+++ b/ansible_collections/community/general/plugins/filter/to_milliseconds.yml
@@ -13,12 +13,12 @@ DOCUMENTATION:
_input:
description:
- The time string to convert.
- - Can use the units C(y) and C(year) for a year, C(mo) and C(month) for a month, C(w) and C(week) for a week,
- C(d) and C(day) for a day, C(h) and C(hour) for a hour, C(m), C(min) and C(minute) for minutes, C(s), C(sec)
- and C(second) for seconds, C(ms), C(msec), C(msecond) and C(millisecond) for milliseconds. The suffix C(s)
- can be added to a unit as well, so C(seconds) is the same as C(second).
+ - Can use the units V(y) and V(year) for a year, V(mo) and V(month) for a month, V(w) and V(week) for a week,
+ V(d) and V(day) for a day, V(h) and V(hour) for a hour, V(m), V(min) and V(minute) for minutes, V(s), V(sec)
+ and V(second) for seconds, V(ms), V(msec), V(msecond) and V(millisecond) for milliseconds. The suffix V(s)
+ can be added to a unit as well, so V(seconds) is the same as V(second).
- Valid strings are space separated combinations of an integer with an optional minus sign and a unit.
- - Examples are C(1h), C(-5m), and C(3h -5m 6s).
+ - Examples are V(1h), V(-5m), and V(3h -5m 6s).
type: string
required: true
year:
diff --git a/ansible_collections/community/general/plugins/filter/to_minutes.yml b/ansible_collections/community/general/plugins/filter/to_minutes.yml
index 3b85dadc4..e8d6f763a 100644
--- a/ansible_collections/community/general/plugins/filter/to_minutes.yml
+++ b/ansible_collections/community/general/plugins/filter/to_minutes.yml
@@ -13,12 +13,12 @@ DOCUMENTATION:
_input:
description:
- The time string to convert.
- - Can use the units C(y) and C(year) for a year, C(mo) and C(month) for a month, C(w) and C(week) for a week,
- C(d) and C(day) for a day, C(h) and C(hour) for a hour, C(m), C(min) and C(minute) for minutes, C(s), C(sec)
- and C(second) for seconds, C(ms), C(msec), C(msecond) and C(millisecond) for milliseconds. The suffix C(s)
- can be added to a unit as well, so C(seconds) is the same as C(second).
+ - Can use the units V(y) and V(year) for a year, V(mo) and V(month) for a month, V(w) and V(week) for a week,
+ V(d) and V(day) for a day, V(h) and V(hour) for a hour, V(m), V(min) and V(minute) for minutes, V(s), V(sec)
+ and V(second) for seconds, V(ms), V(msec), V(msecond) and V(millisecond) for milliseconds. The suffix V(s)
+ can be added to a unit as well, so V(seconds) is the same as V(second).
- Valid strings are space separated combinations of an integer with an optional minus sign and a unit.
- - Examples are C(1h), C(-5m), and C(3h -5m 6s).
+ - Examples are V(1h), V(-5m), and V(3h -5m 6s).
type: string
required: true
year:
diff --git a/ansible_collections/community/general/plugins/filter/to_months.yml b/ansible_collections/community/general/plugins/filter/to_months.yml
index f13cee918..1f1cd661d 100644
--- a/ansible_collections/community/general/plugins/filter/to_months.yml
+++ b/ansible_collections/community/general/plugins/filter/to_months.yml
@@ -13,12 +13,12 @@ DOCUMENTATION:
_input:
description:
- The time string to convert.
- - Can use the units C(y) and C(year) for a year, C(mo) and C(month) for a month, C(w) and C(week) for a week,
- C(d) and C(day) for a day, C(h) and C(hour) for a hour, C(m), C(min) and C(minute) for minutes, C(s), C(sec)
- and C(second) for seconds, C(ms), C(msec), C(msecond) and C(millisecond) for milliseconds. The suffix C(s)
- can be added to a unit as well, so C(seconds) is the same as C(second).
+ - Can use the units V(y) and V(year) for a year, V(mo) and V(month) for a month, V(w) and V(week) for a week,
+ V(d) and V(day) for a day, V(h) and V(hour) for a hour, V(m), V(min) and V(minute) for minutes, V(s), V(sec)
+ and V(second) for seconds, V(ms), V(msec), V(msecond) and V(millisecond) for milliseconds. The suffix V(s)
+ can be added to a unit as well, so V(seconds) is the same as V(second).
- Valid strings are space separated combinations of an integer with an optional minus sign and a unit.
- - Examples are C(1h), C(-5m), and C(3h -5m 6s).
+ - Examples are V(1h), V(-5m), and V(3h -5m 6s).
type: string
required: true
year:
diff --git a/ansible_collections/community/general/plugins/filter/to_seconds.yml b/ansible_collections/community/general/plugins/filter/to_seconds.yml
index d6e6c4e46..d858e062a 100644
--- a/ansible_collections/community/general/plugins/filter/to_seconds.yml
+++ b/ansible_collections/community/general/plugins/filter/to_seconds.yml
@@ -13,12 +13,12 @@ DOCUMENTATION:
_input:
description:
- The time string to convert.
- - Can use the units C(y) and C(year) for a year, C(mo) and C(month) for a month, C(w) and C(week) for a week,
- C(d) and C(day) for a day, C(h) and C(hour) for a hour, C(m), C(min) and C(minute) for minutes, C(s), C(sec)
- and C(second) for seconds, C(ms), C(msec), C(msecond) and C(millisecond) for milliseconds. The suffix C(s)
- can be added to a unit as well, so C(seconds) is the same as C(second).
+ - Can use the units V(y) and V(year) for a year, V(mo) and V(month) for a month, V(w) and V(week) for a week,
+ V(d) and V(day) for a day, V(h) and V(hour) for a hour, V(m), V(min) and V(minute) for minutes, V(s), V(sec)
+ and V(second) for seconds, V(ms), V(msec), V(msecond) and V(millisecond) for milliseconds. The suffix V(s)
+ can be added to a unit as well, so V(seconds) is the same as V(second).
- Valid strings are space separated combinations of an integer with an optional minus sign and a unit.
- - Examples are C(1h), C(-5m), and C(3h -5m 6s).
+ - Examples are V(1h), V(-5m), and V(3h -5m 6s).
type: string
required: true
year:
diff --git a/ansible_collections/community/general/plugins/filter/to_time_unit.yml b/ansible_collections/community/general/plugins/filter/to_time_unit.yml
index c0149f0ac..bda124865 100644
--- a/ansible_collections/community/general/plugins/filter/to_time_unit.yml
+++ b/ansible_collections/community/general/plugins/filter/to_time_unit.yml
@@ -14,12 +14,12 @@ DOCUMENTATION:
_input:
description:
- The time string to convert.
- - Can use the units C(y) and C(year) for a year, C(mo) and C(month) for a month, C(w) and C(week) for a week,
- C(d) and C(day) for a day, C(h) and C(hour) for a hour, C(m), C(min) and C(minute) for minutes, C(s), C(sec)
- and C(second) for seconds, C(ms), C(msec), C(msecond) and C(millisecond) for milliseconds. The suffix C(s)
- can be added to a unit as well, so C(seconds) is the same as C(second).
+ - Can use the units V(y) and V(year) for a year, V(mo) and V(month) for a month, V(w) and V(week) for a week,
+ V(d) and V(day) for a day, V(h) and V(hour) for a hour, V(m), V(min) and V(minute) for minutes, V(s), V(sec)
+ and V(second) for seconds, V(ms), V(msec), V(msecond) and V(millisecond) for milliseconds. The suffix V(s)
+ can be added to a unit as well, so V(seconds) is the same as V(second).
- Valid strings are space separated combinations of an integer with an optional minus sign and a unit.
- - Examples are C(1h), C(-5m), and C(3h -5m 6s).
+ - Examples are V(1h), V(-5m), and V(3h -5m 6s).
type: string
required: true
unit:
diff --git a/ansible_collections/community/general/plugins/filter/to_weeks.yml b/ansible_collections/community/general/plugins/filter/to_weeks.yml
index 499c38627..7bf31bb65 100644
--- a/ansible_collections/community/general/plugins/filter/to_weeks.yml
+++ b/ansible_collections/community/general/plugins/filter/to_weeks.yml
@@ -13,12 +13,12 @@ DOCUMENTATION:
_input:
description:
- The time string to convert.
- - Can use the units C(y) and C(year) for a year, C(mo) and C(month) for a month, C(w) and C(week) for a week,
- C(d) and C(day) for a day, C(h) and C(hour) for a hour, C(m), C(min) and C(minute) for minutes, C(s), C(sec)
- and C(second) for seconds, C(ms), C(msec), C(msecond) and C(millisecond) for milliseconds. The suffix C(s)
- can be added to a unit as well, so C(seconds) is the same as C(second).
+ - Can use the units V(y) and V(year) for a year, V(mo) and V(month) for a month, V(w) and V(week) for a week,
+ V(d) and V(day) for a day, V(h) and V(hour) for a hour, V(m), V(min) and V(minute) for minutes, V(s), V(sec)
+ and V(second) for seconds, V(ms), V(msec), V(msecond) and V(millisecond) for milliseconds. The suffix V(s)
+ can be added to a unit as well, so V(seconds) is the same as V(second).
- Valid strings are space separated combinations of an integer with an optional minus sign and a unit.
- - Examples are C(1h), C(-5m), and C(3h -5m 6s).
+ - Examples are V(1h), V(-5m), and V(3h -5m 6s).
type: string
required: true
year:
diff --git a/ansible_collections/community/general/plugins/filter/to_years.yml b/ansible_collections/community/general/plugins/filter/to_years.yml
index 1a244a276..33c85a3ec 100644
--- a/ansible_collections/community/general/plugins/filter/to_years.yml
+++ b/ansible_collections/community/general/plugins/filter/to_years.yml
@@ -13,12 +13,12 @@ DOCUMENTATION:
_input:
description:
- The time string to convert.
- - Can use the units C(y) and C(year) for a year, C(mo) and C(month) for a month, C(w) and C(week) for a week,
- C(d) and C(day) for a day, C(h) and C(hour) for a hour, C(m), C(min) and C(minute) for minutes, C(s), C(sec)
- and C(second) for seconds, C(ms), C(msec), C(msecond) and C(millisecond) for milliseconds. The suffix C(s)
- can be added to a unit as well, so C(seconds) is the same as C(second).
+ - Can use the units V(y) and V(year) for a year, V(mo) and V(month) for a month, V(w) and V(week) for a week,
+ V(d) and V(day) for a day, V(h) and V(hour) for a hour, V(m), V(min) and V(minute) for minutes, V(s), V(sec)
+ and V(second) for seconds, V(ms), V(msec), V(msecond) and V(millisecond) for milliseconds. The suffix V(s)
+ can be added to a unit as well, so V(seconds) is the same as V(second).
- Valid strings are space separated combinations of an integer with an optional minus sign and a unit.
- - Examples are C(1h), C(-5m), and C(3h -5m 6s).
+ - Examples are V(1h), V(-5m), and V(3h -5m 6s).
type: string
required: true
year:
diff --git a/ansible_collections/community/general/plugins/inventory/cobbler.py b/ansible_collections/community/general/plugins/inventory/cobbler.py
index 936a409ae..8ca36f426 100644
--- a/ansible_collections/community/general/plugins/inventory/cobbler.py
+++ b/ansible_collections/community/general/plugins/inventory/cobbler.py
@@ -13,12 +13,14 @@ DOCUMENTATION = '''
version_added: 1.0.0
description:
- Get inventory hosts from the cobbler service.
- - "Uses a configuration file as an inventory source, it must end in C(.cobbler.yml) or C(.cobbler.yaml) and has a C(plugin: cobbler) entry."
+ - "Uses a configuration file as an inventory source, it must end in C(.cobbler.yml) or C(.cobbler.yaml) and have a C(plugin: cobbler) entry."
+ - Adds the primary IP addresses to C(cobbler_ipv4_address) and C(cobbler_ipv6_address) host variables if defined in Cobbler. The primary IP address is
+ defined as the management interface if defined, or the interface who's DNS name matches the hostname of the system, or else the first interface found.
extends_documentation_fragment:
- inventory_cache
options:
plugin:
- description: The name of this plugin, it should always be set to C(community.general.cobbler) for this plugin to recognize it as it's own.
+ description: The name of this plugin, it should always be set to V(community.general.cobbler) for this plugin to recognize it as it's own.
required: true
choices: [ 'cobbler', 'community.general.cobbler' ]
url:
@@ -32,45 +34,73 @@ DOCUMENTATION = '''
env:
- name: COBBLER_USER
password:
- description: Cobbler authentication password
+ description: Cobbler authentication password.
required: false
env:
- name: COBBLER_PASSWORD
cache_fallback:
- description: Fallback to cached results if connection to cobbler fails
+ description: Fallback to cached results if connection to cobbler fails.
type: boolean
default: false
+ exclude_mgmt_classes:
+ description: Management classes to exclude from inventory.
+ type: list
+ default: []
+ elements: str
+ version_added: 7.4.0
exclude_profiles:
description:
- Profiles to exclude from inventory.
- - Ignored if I(include_profiles) is specified.
+ - Ignored if O(include_profiles) is specified.
type: list
default: []
elements: str
+ include_mgmt_classes:
+ description: Management classes to include from inventory.
+ type: list
+ default: []
+ elements: str
+ version_added: 7.4.0
include_profiles:
description:
- Profiles to include from inventory.
- If specified, all other profiles will be excluded.
- - I(exclude_profiles) is ignored if I(include_profiles) is specified.
+ - O(exclude_profiles) is ignored if O(include_profiles) is specified.
type: list
default: []
elements: str
version_added: 4.4.0
+ inventory_hostname:
+ description:
+ - What to use for the ansible inventory hostname.
+ - By default the networking hostname is used if defined, otherwise the DNS name of the management or first non-static interface.
+ - If set to V(system), the cobbler system name is used.
+ type: str
+ choices: [ 'hostname', 'system' ]
+ default: hostname
+ version_added: 7.1.0
group_by:
- description: Keys to group hosts by
+ description: Keys to group hosts by.
type: list
elements: string
default: [ 'mgmt_classes', 'owners', 'status' ]
group:
- description: Group to place all hosts into
+ description: Group to place all hosts into.
default: cobbler
group_prefix:
- description: Prefix to apply to cobbler groups
+ description: Prefix to apply to cobbler groups.
default: cobbler_
want_facts:
- description: Toggle, if C(true) the plugin will retrieve host facts from the server
+ description: Toggle, if V(true) the plugin will retrieve host facts from the server.
type: boolean
default: true
+ want_ip_addresses:
+ description:
+ - Toggle, if V(true) the plugin will add a C(cobbler_ipv4_addresses) and C(cobbleer_ipv6_addresses) dictionary to the defined O(group) mapping
+ interface DNS names to IP addresses.
+ type: boolean
+ default: true
+ version_added: 7.1.0
'''
EXAMPLES = '''
@@ -85,8 +115,9 @@ import socket
from ansible.errors import AnsibleError
from ansible.module_utils.common.text.converters import to_text
-from ansible.module_utils.six import iteritems
from ansible.plugins.inventory import BaseInventoryPlugin, Cacheable, to_safe_group_name
+from ansible.module_utils.six import text_type
+from ansible.utils.unsafe_proxy import wrap_var as make_unsafe
# xmlrpc
try:
@@ -128,7 +159,7 @@ class InventoryModule(BaseInventoryPlugin, Cacheable):
self.connection = xmlrpc_client.Server(self.cobbler_url, allow_none=True)
self.token = None
if self.get_option('user') is not None:
- self.token = self.connection.login(self.get_option('user'), self.get_option('password'))
+ self.token = self.connection.login(text_type(self.get_option('user')), text_type(self.get_option('password')))
return self.connection
def _init_cache(self):
@@ -198,9 +229,12 @@ class InventoryModule(BaseInventoryPlugin, Cacheable):
self.cache_key = self.get_cache_key(path)
self.use_cache = cache and self.get_option('cache')
+ self.exclude_mgmt_classes = self.get_option('exclude_mgmt_classes')
+ self.include_mgmt_classes = self.get_option('include_mgmt_classes')
self.exclude_profiles = self.get_option('exclude_profiles')
self.include_profiles = self.get_option('include_profiles')
self.group_by = self.get_option('group_by')
+ self.inventory_hostname = self.get_option('inventory_hostname')
for profile in self._get_profiles():
if profile['parent']:
@@ -236,22 +270,34 @@ class InventoryModule(BaseInventoryPlugin, Cacheable):
self.inventory.add_group(self.group)
self.display.vvvv('Added site group %s\n' % self.group)
+ ip_addresses = {}
+ ipv6_addresses = {}
for host in self._get_systems():
# Get the FQDN for the host and add it to the right groups
- hostname = host['hostname'] # None
+ if self.inventory_hostname == 'system':
+ hostname = make_unsafe(host['name']) # None
+ else:
+ hostname = make_unsafe(host['hostname']) # None
interfaces = host['interfaces']
- if self._exclude_profile(host['profile']):
- self.display.vvvv('Excluding host %s in profile %s\n' % (host['name'], host['profile']))
- continue
+ if set(host['mgmt_classes']) & set(self.include_mgmt_classes):
+ self.display.vvvv('Including host %s in mgmt_classes %s\n' % (host['name'], host['mgmt_classes']))
+ else:
+ if self._exclude_profile(host['profile']):
+ self.display.vvvv('Excluding host %s in profile %s\n' % (host['name'], host['profile']))
+ continue
+
+ if set(host['mgmt_classes']) & set(self.exclude_mgmt_classes):
+ self.display.vvvv('Excluding host %s in mgmt_classes %s\n' % (host['name'], host['mgmt_classes']))
+ continue
# hostname is often empty for non-static IP hosts
if hostname == '':
- for (iname, ivalue) in iteritems(interfaces):
+ for iname, ivalue in interfaces.items():
if ivalue['management'] or not ivalue['static']:
this_dns_name = ivalue.get('dns_name', None)
if this_dns_name is not None and this_dns_name != "":
- hostname = this_dns_name
+ hostname = make_unsafe(this_dns_name)
self.display.vvvv('Set hostname to %s from %s\n' % (hostname, iname))
if hostname == '':
@@ -262,8 +308,11 @@ class InventoryModule(BaseInventoryPlugin, Cacheable):
self.display.vvvv('Added host %s hostname %s\n' % (host['name'], hostname))
# Add host to profile group
- group_name = self._add_safe_group_name(host['profile'], child=hostname)
- self.display.vvvv('Added host %s to profile group %s\n' % (hostname, group_name))
+ if host['profile'] != '':
+ group_name = self._add_safe_group_name(host['profile'], child=hostname)
+ self.display.vvvv('Added host %s to profile group %s\n' % (hostname, group_name))
+ else:
+ self.display.warning('Host %s has an empty profile\n' % (hostname))
# Add host to groups specified by group_by fields
for group_by in self.group_by:
@@ -280,8 +329,51 @@ class InventoryModule(BaseInventoryPlugin, Cacheable):
self.inventory.add_child(self.group, hostname)
# Add host variables
+ ip_address = None
+ ip_address_first = None
+ ipv6_address = None
+ ipv6_address_first = None
+ for iname, ivalue in interfaces.items():
+ # Set to first interface or management interface if defined or hostname matches dns_name
+ if ivalue['ip_address'] != "":
+ if ip_address_first is None:
+ ip_address_first = ivalue['ip_address']
+ if ivalue['management']:
+ ip_address = ivalue['ip_address']
+ elif ivalue['dns_name'] == hostname and ip_address is None:
+ ip_address = ivalue['ip_address']
+ if ivalue['ipv6_address'] != "":
+ if ipv6_address_first is None:
+ ipv6_address_first = ivalue['ipv6_address']
+ if ivalue['management']:
+ ipv6_address = ivalue['ipv6_address']
+ elif ivalue['dns_name'] == hostname and ipv6_address is None:
+ ipv6_address = ivalue['ipv6_address']
+
+ # Collect all interface name mappings for adding to group vars
+ if self.get_option('want_ip_addresses'):
+ if ivalue['dns_name'] != "":
+ if ivalue['ip_address'] != "":
+ ip_addresses[ivalue['dns_name']] = ivalue['ip_address']
+ if ivalue['ipv6_address'] != "":
+ ip_addresses[ivalue['dns_name']] = ivalue['ipv6_address']
+
+ # Add ip_address to host if defined, use first if no management or matched dns_name
+ if ip_address is None and ip_address_first is not None:
+ ip_address = ip_address_first
+ if ip_address is not None:
+ self.inventory.set_variable(hostname, 'cobbler_ipv4_address', make_unsafe(ip_address))
+ if ipv6_address is None and ipv6_address_first is not None:
+ ipv6_address = ipv6_address_first
+ if ipv6_address is not None:
+ self.inventory.set_variable(hostname, 'cobbler_ipv6_address', make_unsafe(ipv6_address))
+
if self.get_option('want_facts'):
try:
- self.inventory.set_variable(hostname, 'cobbler', host)
+ self.inventory.set_variable(hostname, 'cobbler', make_unsafe(host))
except ValueError as e:
self.display.warning("Could not set host info for %s: %s" % (hostname, to_text(e)))
+
+ if self.get_option('want_ip_addresses'):
+ self.inventory.set_variable(self.group, 'cobbler_ipv4_addresses', make_unsafe(ip_addresses))
+ self.inventory.set_variable(self.group, 'cobbler_ipv6_addresses', make_unsafe(ipv6_addresses))
diff --git a/ansible_collections/community/general/plugins/inventory/gitlab_runners.py b/ansible_collections/community/general/plugins/inventory/gitlab_runners.py
index d68b8d4e2..536f4bb1b 100644
--- a/ansible_collections/community/general/plugins/inventory/gitlab_runners.py
+++ b/ansible_collections/community/general/plugins/inventory/gitlab_runners.py
@@ -14,7 +14,6 @@ DOCUMENTATION = '''
- Stefan Heitmüller (@morph027) <stefan.heitmueller@gmx.com>
short_description: Ansible dynamic inventory plugin for GitLab runners.
requirements:
- - python >= 2.7
- python-gitlab > 1.8.0
extends_documentation_fragment:
- constructed
@@ -84,6 +83,7 @@ keyed_groups:
from ansible.errors import AnsibleError, AnsibleParserError
from ansible.module_utils.common.text.converters import to_native
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable
+from ansible.utils.unsafe_proxy import wrap_var as make_unsafe
try:
import gitlab
@@ -106,11 +106,11 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
else:
runners = gl.runners.all()
for runner in runners:
- host = str(runner['id'])
+ host = make_unsafe(str(runner['id']))
ip_address = runner['ip_address']
- host_attrs = vars(gl.runners.get(runner['id']))['_attrs']
+ host_attrs = make_unsafe(vars(gl.runners.get(runner['id']))['_attrs'])
self.inventory.add_host(host, group='gitlab_runners')
- self.inventory.set_variable(host, 'ansible_host', ip_address)
+ self.inventory.set_variable(host, 'ansible_host', make_unsafe(ip_address))
if self.get_option('verbose_output', True):
self.inventory.set_variable(host, 'gitlab_runner_attributes', host_attrs)
diff --git a/ansible_collections/community/general/plugins/inventory/icinga2.py b/ansible_collections/community/general/plugins/inventory/icinga2.py
index 70e0f5733..6746bb8e0 100644
--- a/ansible_collections/community/general/plugins/inventory/icinga2.py
+++ b/ansible_collections/community/general/plugins/inventory/icinga2.py
@@ -58,11 +58,17 @@ DOCUMENTATION = '''
description:
- Allows the override of the inventory name based on different attributes.
- This allows for changing the way limits are used.
- - The current default, C(address), is sometimes not unique or present. We recommend to use C(name) instead.
+ - The current default, V(address), is sometimes not unique or present. We recommend to use V(name) instead.
type: string
default: address
choices: ['name', 'display_name', 'address']
version_added: 4.2.0
+ group_by_hostgroups:
+ description:
+ - Uses Icinga2 hostgroups as groups.
+ type: boolean
+ default: true
+ version_added: 8.4.0
'''
EXAMPLES = r'''
@@ -72,7 +78,7 @@ url: http://localhost:5665
user: ansible
password: secure
host_filter: \"linux-servers\" in host.groups
-validate_certs: false
+validate_certs: false # only do this when connecting to localhost!
inventory_attr: name
groups:
# simple name matching
@@ -96,6 +102,7 @@ from ansible.errors import AnsibleParserError
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable
from ansible.module_utils.urls import open_url
from ansible.module_utils.six.moves.urllib.error import HTTPError
+from ansible.utils.unsafe_proxy import wrap_var as make_unsafe
class InventoryModule(BaseInventoryPlugin, Constructable):
@@ -114,6 +121,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
self.ssl_verify = None
self.host_filter = None
self.inventory_attr = None
+ self.group_by_hostgroups = None
self.cache_key = None
self.use_cache = None
@@ -233,31 +241,32 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
"""Convert Icinga2 API data to JSON format for Ansible"""
groups_dict = {"_meta": {"hostvars": {}}}
for entry in json_data:
- host_attrs = entry['attrs']
+ host_attrs = make_unsafe(entry['attrs'])
if self.inventory_attr == "name":
- host_name = entry.get('name')
+ host_name = make_unsafe(entry.get('name'))
if self.inventory_attr == "address":
# When looking for address for inventory, if missing fallback to object name
if host_attrs.get('address', '') != '':
- host_name = host_attrs.get('address')
+ host_name = make_unsafe(host_attrs.get('address'))
else:
- host_name = entry.get('name')
+ host_name = make_unsafe(entry.get('name'))
if self.inventory_attr == "display_name":
host_name = host_attrs.get('display_name')
if host_attrs['state'] == 0:
host_attrs['state'] = 'on'
else:
host_attrs['state'] = 'off'
- host_groups = host_attrs.get('groups')
self.inventory.add_host(host_name)
- for group in host_groups:
- if group not in self.inventory.groups.keys():
- self.inventory.add_group(group)
- self.inventory.add_child(group, host_name)
+ if self.group_by_hostgroups:
+ host_groups = host_attrs.get('groups')
+ for group in host_groups:
+ if group not in self.inventory.groups.keys():
+ self.inventory.add_group(group)
+ self.inventory.add_child(group, host_name)
# If the address attribute is populated, override ansible_host with the value
if host_attrs.get('address') != '':
self.inventory.set_variable(host_name, 'ansible_host', host_attrs.get('address'))
- self.inventory.set_variable(host_name, 'hostname', entry.get('name'))
+ self.inventory.set_variable(host_name, 'hostname', make_unsafe(entry.get('name')))
self.inventory.set_variable(host_name, 'display_name', host_attrs.get('display_name'))
self.inventory.set_variable(host_name, 'state',
host_attrs['state'])
@@ -277,12 +286,23 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
self._read_config_data(path)
# Store the options from the YAML file
- self.icinga2_url = self.get_option('url').rstrip('/') + '/v1'
+ self.icinga2_url = self.get_option('url')
self.icinga2_user = self.get_option('user')
self.icinga2_password = self.get_option('password')
self.ssl_verify = self.get_option('validate_certs')
self.host_filter = self.get_option('host_filter')
self.inventory_attr = self.get_option('inventory_attr')
+ self.group_by_hostgroups = self.get_option('group_by_hostgroups')
+
+ if self.templar.is_template(self.icinga2_url):
+ self.icinga2_url = self.templar.template(variable=self.icinga2_url, disable_lookups=False)
+ if self.templar.is_template(self.icinga2_user):
+ self.icinga2_user = self.templar.template(variable=self.icinga2_user, disable_lookups=False)
+ if self.templar.is_template(self.icinga2_password):
+ self.icinga2_password = self.templar.template(variable=self.icinga2_password, disable_lookups=False)
+
+ self.icinga2_url = self.icinga2_url.rstrip('/') + '/v1'
+
# Not currently enabled
# self.cache_key = self.get_cache_key(path)
# self.use_cache = cache and self.get_option('cache')
diff --git a/ansible_collections/community/general/plugins/inventory/linode.py b/ansible_collections/community/general/plugins/inventory/linode.py
index b28cfa27b..fc79f12c5 100644
--- a/ansible_collections/community/general/plugins/inventory/linode.py
+++ b/ansible_collections/community/general/plugins/inventory/linode.py
@@ -12,7 +12,6 @@ DOCUMENTATION = r'''
- Luke Murphy (@decentral1se)
short_description: Ansible dynamic inventory plugin for Linode.
requirements:
- - python >= 2.7
- linode_api4 >= 2.0.0
description:
- Reads inventories from the Linode API v4.
@@ -123,6 +122,7 @@ compose:
from ansible.errors import AnsibleError
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable, Cacheable
+from ansible.utils.unsafe_proxy import wrap_var as make_unsafe
try:
@@ -199,20 +199,21 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
def _add_instances_to_groups(self):
"""Add instance names to their dynamic inventory groups."""
for instance in self.instances:
- self.inventory.add_host(instance.label, group=instance.group)
+ self.inventory.add_host(make_unsafe(instance.label), group=instance.group)
def _add_hostvars_for_instances(self):
"""Add hostvars for instances in the dynamic inventory."""
ip_style = self.get_option('ip_style')
for instance in self.instances:
hostvars = instance._raw_json
+ hostname = make_unsafe(instance.label)
for hostvar_key in hostvars:
if ip_style == 'api' and hostvar_key in ['ipv4', 'ipv6']:
continue
self.inventory.set_variable(
- instance.label,
+ hostname,
hostvar_key,
- hostvars[hostvar_key]
+ make_unsafe(hostvars[hostvar_key])
)
if ip_style == 'api':
ips = instance.ips.ipv4.public + instance.ips.ipv4.private
@@ -221,9 +222,9 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
for ip_type in set(ip.type for ip in ips):
self.inventory.set_variable(
- instance.label,
+ hostname,
ip_type,
- self._ip_data([ip for ip in ips if ip.type == ip_type])
+ make_unsafe(self._ip_data([ip for ip in ips if ip.type == ip_type]))
)
def _ip_data(self, ip_list):
@@ -254,30 +255,44 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
self._add_instances_to_groups()
self._add_hostvars_for_instances()
for instance in self.instances:
- variables = self.inventory.get_host(instance.label).get_vars()
+ hostname = make_unsafe(instance.label)
+ variables = self.inventory.get_host(hostname).get_vars()
self._add_host_to_composed_groups(
self.get_option('groups'),
variables,
- instance.label,
+ hostname,
strict=strict)
self._add_host_to_keyed_groups(
self.get_option('keyed_groups'),
variables,
- instance.label,
+ hostname,
strict=strict)
self._set_composite_vars(
self.get_option('compose'),
variables,
- instance.label,
+ hostname,
strict=strict)
def verify_file(self, path):
- """Verify the Linode configuration file."""
+ """Verify the Linode configuration file.
+
+ Return true/false if the config-file is valid for this plugin
+
+ Args:
+ str(path): path to the config
+ Kwargs:
+ None
+ Raises:
+ None
+ Returns:
+ bool(valid): is valid config file"""
+ valid = False
if super(InventoryModule, self).verify_file(path):
- endings = ('linode.yaml', 'linode.yml')
- if any((path.endswith(ending) for ending in endings)):
- return True
- return False
+ if path.endswith(("linode.yaml", "linode.yml")):
+ valid = True
+ else:
+ self.display.vvv('Inventory source not ending in "linode.yaml" or "linode.yml"')
+ return valid
def parse(self, inventory, loader, path, cache=True):
"""Dynamically parse Linode the cloud inventory."""
diff --git a/ansible_collections/community/general/plugins/inventory/lxd.py b/ansible_collections/community/general/plugins/inventory/lxd.py
index bd0a6ce00..c803f47dd 100644
--- a/ansible_collections/community/general/plugins/inventory/lxd.py
+++ b/ansible_collections/community/general/plugins/inventory/lxd.py
@@ -41,14 +41,28 @@ DOCUMENTATION = r'''
aliases: [ cert_file ]
default: $HOME/.config/lxc/client.crt
type: path
+ server_cert:
+ description:
+ - The server certificate file path.
+ type: path
+ version_added: 8.0.0
+ server_check_hostname:
+ description:
+ - This option controls if the server's hostname is checked as part of the HTTPS connection verification.
+ This can be useful to disable, if for example, the server certificate provided (see O(server_cert) option)
+ does not cover a name matching the one used to communicate with the server. Such mismatch is common as LXD
+ generates self-signed server certificates by default.
+ type: bool
+ default: true
+ version_added: 8.0.0
trust_password:
description:
- The client trusted password.
- You need to set this password on the lxd server before
running this module using the following command
C(lxc config set core.trust_password <some random password>)
- See U(https://www.stgraber.org/2016/04/18/lxd-api-direct-interaction/).
- - If I(trust_password) is set, this module send a request for authentication before sending any requests.
+ See U(https://documentation.ubuntu.com/lxd/en/latest/authentication/#adding-client-certificates-using-a-trust-password).
+ - If O(trust_password) is set, this module send a request for authentication before sending any requests.
type: str
state:
description: Filter the instance according to the current status.
@@ -62,7 +76,7 @@ DOCUMENTATION = r'''
version_added: 6.2.0
type_filter:
description:
- - Filter the instances by type C(virtual-machine), C(container) or C(both).
+ - Filter the instances by type V(virtual-machine), V(container) or V(both).
- The first version of the inventory only supported containers.
type: str
default: container
@@ -70,18 +84,18 @@ DOCUMENTATION = r'''
version_added: 4.2.0
prefered_instance_network_interface:
description:
- - If an instance has multiple network interfaces, select which one is the prefered as pattern.
+ - If an instance has multiple network interfaces, select which one is the preferred as pattern.
- Combined with the first number that can be found e.g. 'eth' + 0.
- - The option has been renamed from I(prefered_container_network_interface) to I(prefered_instance_network_interface) in community.general 3.8.0.
- The old name still works as an alias.
+ - The option has been renamed from O(prefered_container_network_interface) to O(prefered_instance_network_interface)
+ in community.general 3.8.0. The old name still works as an alias.
type: str
default: eth
aliases:
- prefered_container_network_interface
prefered_instance_network_family:
description:
- - If an instance has multiple network interfaces, which one is the prefered by family.
- - Specify C(inet) for IPv4 and C(inet6) for IPv6.
+ - If an instance has multiple network interfaces, which one is the preferred by family.
+ - Specify V(inet) for IPv4 and V(inet6) for IPv6.
type: str
default: inet
choices: [ 'inet', 'inet6' ]
@@ -161,6 +175,7 @@ from ansible.module_utils.six import raise_from
from ansible.errors import AnsibleError, AnsibleParserError
from ansible.module_utils.six.moves.urllib.parse import urlencode
from ansible_collections.community.general.plugins.module_utils.lxd import LXDClient, LXDClientException
+from ansible.utils.unsafe_proxy import wrap_var as make_unsafe
try:
import ipaddress
@@ -286,7 +301,7 @@ class InventoryModule(BaseInventoryPlugin):
urls = (url for url in url_list if self.validate_url(url))
for url in urls:
try:
- socket_connection = LXDClient(url, self.client_key, self.client_cert, self.debug)
+ socket_connection = LXDClient(url, self.client_key, self.client_cert, self.debug, self.server_cert, self.server_check_hostname)
return socket_connection
except LXDClientException as err:
error_storage[url] = err
@@ -359,7 +374,7 @@ class InventoryModule(BaseInventoryPlugin):
Kwargs:
None
Source:
- https://github.com/lxc/lxd/blob/master/doc/rest-api.md
+ https://documentation.ubuntu.com/lxd/en/latest/rest-api/
Raises:
None
Returns:
@@ -376,7 +391,7 @@ class InventoryModule(BaseInventoryPlugin):
def get_instance_data(self, names):
"""Create Inventory of the instance
- Iterate through the different branches of the instances and collect Informations.
+ Iterate through the different branches of the instances and collect Information.
Args:
list(names): List of instance names
@@ -398,7 +413,7 @@ class InventoryModule(BaseInventoryPlugin):
def get_network_data(self, names):
"""Create Inventory of the instance
- Iterate through the different branches of the instances and collect Informations.
+ Iterate through the different branches of the instances and collect Information.
Args:
list(names): List of instance names
@@ -451,12 +466,12 @@ class InventoryModule(BaseInventoryPlugin):
return network_configuration
def get_prefered_instance_network_interface(self, instance_name):
- """Helper to get the prefered interface of thr instance
+ """Helper to get the preferred interface of thr instance
- Helper to get the prefered interface provide by neme pattern from 'prefered_instance_network_interface'.
+ Helper to get the preferred interface provide by neme pattern from 'prefered_instance_network_interface'.
Args:
- str(containe_name): name of instance
+ str(instance_name): name of instance
Kwargs:
None
Raises:
@@ -481,7 +496,7 @@ class InventoryModule(BaseInventoryPlugin):
Helper to get the VLAN_ID from the instance
Args:
- str(containe_name): name of instance
+ str(instance_name): name of instance
Kwargs:
None
Raises:
@@ -563,7 +578,7 @@ class InventoryModule(BaseInventoryPlugin):
else:
path[instance_name][key] = value
except KeyError as err:
- raise AnsibleParserError("Unable to store Informations: {0}".format(to_native(err)))
+ raise AnsibleParserError("Unable to store Information: {0}".format(to_native(err)))
def extract_information_from_instance_configs(self):
"""Process configuration information
@@ -656,7 +671,7 @@ class InventoryModule(BaseInventoryPlugin):
if self._get_data_entry('inventory/{0}/network_interfaces'.format(instance_name)): # instance have network interfaces
self.inventory.set_variable(instance_name, 'ansible_connection', 'ssh')
- self.inventory.set_variable(instance_name, 'ansible_host', interface_selection(instance_name))
+ self.inventory.set_variable(instance_name, 'ansible_host', make_unsafe(interface_selection(instance_name)))
else:
self.inventory.set_variable(instance_name, 'ansible_connection', 'local')
@@ -682,31 +697,39 @@ class InventoryModule(BaseInventoryPlugin):
if self.filter.lower() != instance_state:
continue
# add instance
+ instance_name = make_unsafe(instance_name)
self.inventory.add_host(instance_name)
- # add network informations
+ # add network information
self.build_inventory_network(instance_name)
# add os
v = self._get_data_entry('inventory/{0}/os'.format(instance_name))
if v:
- self.inventory.set_variable(instance_name, 'ansible_lxd_os', v.lower())
+ self.inventory.set_variable(instance_name, 'ansible_lxd_os', make_unsafe(v.lower()))
# add release
v = self._get_data_entry('inventory/{0}/release'.format(instance_name))
if v:
- self.inventory.set_variable(instance_name, 'ansible_lxd_release', v.lower())
+ self.inventory.set_variable(
+ instance_name, 'ansible_lxd_release', make_unsafe(v.lower()))
# add profile
- self.inventory.set_variable(instance_name, 'ansible_lxd_profile', self._get_data_entry('inventory/{0}/profile'.format(instance_name)))
+ self.inventory.set_variable(
+ instance_name, 'ansible_lxd_profile', make_unsafe(self._get_data_entry('inventory/{0}/profile'.format(instance_name))))
# add state
- self.inventory.set_variable(instance_name, 'ansible_lxd_state', instance_state)
+ self.inventory.set_variable(
+ instance_name, 'ansible_lxd_state', make_unsafe(instance_state))
# add type
- self.inventory.set_variable(instance_name, 'ansible_lxd_type', self._get_data_entry('inventory/{0}/type'.format(instance_name)))
+ self.inventory.set_variable(
+ instance_name, 'ansible_lxd_type', make_unsafe(self._get_data_entry('inventory/{0}/type'.format(instance_name))))
# add location information
if self._get_data_entry('inventory/{0}/location'.format(instance_name)) != "none": # wrong type by lxd 'none' != 'None'
- self.inventory.set_variable(instance_name, 'ansible_lxd_location', self._get_data_entry('inventory/{0}/location'.format(instance_name)))
+ self.inventory.set_variable(
+ instance_name, 'ansible_lxd_location', make_unsafe(self._get_data_entry('inventory/{0}/location'.format(instance_name))))
# add VLAN_ID information
if self._get_data_entry('inventory/{0}/vlan_ids'.format(instance_name)):
- self.inventory.set_variable(instance_name, 'ansible_lxd_vlan_ids', self._get_data_entry('inventory/{0}/vlan_ids'.format(instance_name)))
+ self.inventory.set_variable(
+ instance_name, 'ansible_lxd_vlan_ids', make_unsafe(self._get_data_entry('inventory/{0}/vlan_ids'.format(instance_name))))
# add project
- self.inventory.set_variable(instance_name, 'ansible_lxd_project', self._get_data_entry('inventory/{0}/project'.format(instance_name)))
+ self.inventory.set_variable(
+ instance_name, 'ansible_lxd_project', make_unsafe(self._get_data_entry('inventory/{0}/project'.format(instance_name))))
def build_inventory_groups_location(self, group_name):
"""create group by attribute: location
@@ -979,7 +1002,7 @@ class InventoryModule(BaseInventoryPlugin):
for group_name in self.groupby:
if not group_name.isalnum():
raise AnsibleParserError('Invalid character(s) in groupname: {0}'.format(to_native(group_name)))
- group_type(group_name)
+ group_type(make_unsafe(group_name))
def build_inventory(self):
"""Build dynamic inventory
@@ -1078,6 +1101,8 @@ class InventoryModule(BaseInventoryPlugin):
try:
self.client_key = self.get_option('client_key')
self.client_cert = self.get_option('client_cert')
+ self.server_cert = self.get_option('server_cert')
+ self.server_check_hostname = self.get_option('server_check_hostname')
self.project = self.get_option('project')
self.debug = self.DEBUG
self.data = {} # store for inventory-data
diff --git a/ansible_collections/community/general/plugins/inventory/nmap.py b/ansible_collections/community/general/plugins/inventory/nmap.py
index a03cf3e6f..3a28007a3 100644
--- a/ansible_collections/community/general/plugins/inventory/nmap.py
+++ b/ansible_collections/community/general/plugins/inventory/nmap.py
@@ -23,7 +23,7 @@ DOCUMENTATION = '''
required: true
choices: ['nmap', 'community.general.nmap']
sudo:
- description: Set to C(true) to execute a C(sudo nmap) plugin scan.
+ description: Set to V(true) to execute a C(sudo nmap) plugin scan.
version_added: 4.8.0
default: false
type: boolean
@@ -36,7 +36,7 @@ DOCUMENTATION = '''
exclude:
description:
- List of addresses to exclude.
- - For example C(10.2.2.15-25) or C(10.2.2.15,10.2.2.16).
+ - For example V(10.2.2.15-25) or V(10.2.2.15,10.2.2.16).
type: list
elements: string
env:
@@ -45,8 +45,8 @@ DOCUMENTATION = '''
port:
description:
- Only scan specific port or port range (C(-p)).
- - For example, you could pass C(22) for a single port, C(1-65535) for a range of ports,
- or C(U:53,137,T:21-25,139,8080,S:9) to check port 53 with UDP, ports 21-25 with TCP, port 9 with SCTP, and ports 137, 139, and 8080 with all.
+ - For example, you could pass V(22) for a single port, V(1-65535) for a range of ports,
+ or V(U:53,137,T:21-25,139,8080,S:9) to check port 53 with UDP, ports 21-25 with TCP, port 9 with SCTP, and ports 137, 139, and 8080 with all.
type: string
version_added: 6.5.0
ports:
@@ -64,14 +64,14 @@ DOCUMENTATION = '''
udp_scan:
description:
- Scan via UDP.
- - Depending on your system you might need I(sudo=true) for this to work.
+ - Depending on your system you might need O(sudo=true) for this to work.
type: boolean
default: false
version_added: 6.1.0
icmp_timestamp:
description:
- Scan via ICMP Timestamp (C(-PP)).
- - Depending on your system you might need I(sudo=true) for this to work.
+ - Depending on your system you might need O(sudo=true) for this to work.
type: boolean
default: false
version_added: 6.1.0
@@ -81,10 +81,15 @@ DOCUMENTATION = '''
default: false
version_added: 6.5.0
dns_resolve:
- description: Whether to always (C(true)) or never (C(false)) do DNS resolution.
+ description: Whether to always (V(true)) or never (V(false)) do DNS resolution.
type: boolean
default: false
version_added: 6.1.0
+ use_arp_ping:
+ description: Whether to always (V(true)) use the quick ARP ping or (V(false)) a slower but more reliable method.
+ type: boolean
+ default: true
+ version_added: 7.4.0
notes:
- At least one of ipv4 or ipv6 is required to be True, both can be True, but they cannot both be False.
- 'TODO: add OS fingerprinting'
@@ -121,6 +126,7 @@ from ansible.errors import AnsibleParserError
from ansible.module_utils.common.text.converters import to_native, to_text
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable, Cacheable
from ansible.module_utils.common.process import get_bin_path
+from ansible.utils.unsafe_proxy import wrap_var as make_unsafe
class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
@@ -138,6 +144,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
strict = self.get_option('strict')
for host in hosts:
+ host = make_unsafe(host)
hostname = host['name']
self.inventory.add_host(hostname)
for var, value in host.items():
@@ -196,40 +203,43 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
# setup command
cmd = [self._nmap]
- if self._options['sudo']:
+ if self.get_option('sudo'):
cmd.insert(0, 'sudo')
- if self._options['port']:
+ if self.get_option('port'):
cmd.append('-p')
- cmd.append(self._options['port'])
+ cmd.append(self.get_option('port'))
- if not self._options['ports']:
+ if not self.get_option('ports'):
cmd.append('-sP')
- if self._options['ipv4'] and not self._options['ipv6']:
+ if self.get_option('ipv4') and not self.get_option('ipv6'):
cmd.append('-4')
- elif self._options['ipv6'] and not self._options['ipv4']:
+ elif self.get_option('ipv6') and not self.get_option('ipv4'):
cmd.append('-6')
- elif not self._options['ipv6'] and not self._options['ipv4']:
+ elif not self.get_option('ipv6') and not self.get_option('ipv4'):
raise AnsibleParserError('One of ipv4 or ipv6 must be enabled for this plugin')
- if self._options['exclude']:
+ if self.get_option('exclude'):
cmd.append('--exclude')
- cmd.append(','.join(self._options['exclude']))
+ cmd.append(','.join(self.get_option('exclude')))
- if self._options['dns_resolve']:
+ if self.get_option('dns_resolve'):
cmd.append('-n')
- if self._options['udp_scan']:
+ if self.get_option('udp_scan'):
cmd.append('-sU')
- if self._options['icmp_timestamp']:
+ if self.get_option('icmp_timestamp'):
cmd.append('-PP')
- if self._options['open']:
+ if self.get_option('open'):
cmd.append('--open')
- cmd.append(self._options['address'])
+ if not self.get_option('use_arp_ping'):
+ cmd.append('--disable-arp-ping')
+
+ cmd.append(self.get_option('address'))
try:
# execute
p = Popen(cmd, stdout=PIPE, stderr=PIPE)
diff --git a/ansible_collections/community/general/plugins/inventory/online.py b/ansible_collections/community/general/plugins/inventory/online.py
index 3fccd58d2..b3a9ecd37 100644
--- a/ansible_collections/community/general/plugins/inventory/online.py
+++ b/ansible_collections/community/general/plugins/inventory/online.py
@@ -68,6 +68,7 @@ from ansible.plugins.inventory import BaseInventoryPlugin
from ansible.module_utils.common.text.converters import to_text
from ansible.module_utils.ansible_release import __version__ as ansible_version
from ansible.module_utils.six.moves.urllib.parse import urljoin
+from ansible.utils.unsafe_proxy import wrap_var as make_unsafe
class InventoryModule(BaseInventoryPlugin):
@@ -169,20 +170,20 @@ class InventoryModule(BaseInventoryPlugin):
"support"
)
for attribute in targeted_attributes:
- self.inventory.set_variable(hostname, attribute, host_infos[attribute])
+ self.inventory.set_variable(hostname, attribute, make_unsafe(host_infos[attribute]))
if self.extract_public_ipv4(host_infos=host_infos):
- self.inventory.set_variable(hostname, "public_ipv4", self.extract_public_ipv4(host_infos=host_infos))
- self.inventory.set_variable(hostname, "ansible_host", self.extract_public_ipv4(host_infos=host_infos))
+ self.inventory.set_variable(hostname, "public_ipv4", make_unsafe(self.extract_public_ipv4(host_infos=host_infos)))
+ self.inventory.set_variable(hostname, "ansible_host", make_unsafe(self.extract_public_ipv4(host_infos=host_infos)))
if self.extract_private_ipv4(host_infos=host_infos):
- self.inventory.set_variable(hostname, "public_ipv4", self.extract_private_ipv4(host_infos=host_infos))
+ self.inventory.set_variable(hostname, "public_ipv4", make_unsafe(self.extract_private_ipv4(host_infos=host_infos)))
if self.extract_os_name(host_infos=host_infos):
- self.inventory.set_variable(hostname, "os_name", self.extract_os_name(host_infos=host_infos))
+ self.inventory.set_variable(hostname, "os_name", make_unsafe(self.extract_os_name(host_infos=host_infos)))
if self.extract_os_version(host_infos=host_infos):
- self.inventory.set_variable(hostname, "os_version", self.extract_os_name(host_infos=host_infos))
+ self.inventory.set_variable(hostname, "os_version", make_unsafe(self.extract_os_name(host_infos=host_infos)))
def _filter_host(self, host_infos, hostname_preferences):
@@ -201,6 +202,8 @@ class InventoryModule(BaseInventoryPlugin):
if not hostname:
return
+ hostname = make_unsafe(hostname)
+
self.inventory.add_host(host=hostname)
self._fill_host_variables(hostname=hostname, host_infos=host_infos)
@@ -210,6 +213,8 @@ class InventoryModule(BaseInventoryPlugin):
if not group:
return
+ group = make_unsafe(group)
+
self.inventory.add_group(group=group)
self.inventory.add_host(group=group, host=hostname)
diff --git a/ansible_collections/community/general/plugins/inventory/opennebula.py b/ansible_collections/community/general/plugins/inventory/opennebula.py
index 603920edc..3babfa232 100644
--- a/ansible_collections/community/general/plugins/inventory/opennebula.py
+++ b/ansible_collections/community/general/plugins/inventory/opennebula.py
@@ -17,9 +17,9 @@ DOCUMENTATION = r'''
- constructed
description:
- Get inventory hosts from OpenNebula cloud.
- - Uses an YAML configuration file ending with either I(opennebula.yml) or I(opennebula.yaml)
+ - Uses an YAML configuration file ending with either C(opennebula.yml) or C(opennebula.yaml)
to set parameter values.
- - Uses I(api_authfile), C(~/.one/one_auth), or C(ONE_AUTH) pointing to a OpenNebula credentials file.
+ - Uses O(api_authfile), C(~/.one/one_auth), or E(ONE_AUTH) pointing to a OpenNebula credentials file.
options:
plugin:
description: Token that ensures this is a source file for the 'opennebula' plugin.
@@ -31,7 +31,7 @@ DOCUMENTATION = r'''
- URL of the OpenNebula RPC server.
- It is recommended to use HTTPS so that the username/password are not
transferred over the network unencrypted.
- - If not set then the value of the C(ONE_URL) environment variable is used.
+ - If not set then the value of the E(ONE_URL) environment variable is used.
env:
- name: ONE_URL
required: true
@@ -39,29 +39,29 @@ DOCUMENTATION = r'''
api_username:
description:
- Name of the user to login into the OpenNebula RPC server. If not set
- then the value of the C(ONE_USERNAME) environment variable is used.
+ then the value of the E(ONE_USERNAME) environment variable is used.
env:
- name: ONE_USERNAME
type: string
api_password:
description:
- Password or a token of the user to login into OpenNebula RPC server.
- - If not set, the value of the C(ONE_PASSWORD) environment variable is used.
+ - If not set, the value of the E(ONE_PASSWORD) environment variable is used.
env:
- name: ONE_PASSWORD
required: false
type: string
api_authfile:
description:
- - If both I(api_username) or I(api_password) are not set, then it will try
+ - If both O(api_username) or O(api_password) are not set, then it will try
authenticate with ONE auth file. Default path is C(~/.one/one_auth).
- - Set environment variable C(ONE_AUTH) to override this path.
+ - Set environment variable E(ONE_AUTH) to override this path.
env:
- name: ONE_AUTH
required: false
type: string
hostname:
- description: Field to match the hostname. Note C(v4_first_ip) corresponds to the first IPv4 found on VM.
+ description: Field to match the hostname. Note V(v4_first_ip) corresponds to the first IPv4 found on VM.
type: string
default: v4_first_ip
choices:
@@ -97,6 +97,7 @@ except ImportError:
from ansible.errors import AnsibleError
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable
from ansible.module_utils.common.text.converters import to_native
+from ansible.utils.unsafe_proxy import wrap_var as make_unsafe
from collections import namedtuple
import os
@@ -215,6 +216,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
filter_by_label = self.get_option('filter_by_label')
servers = self._retrieve_servers(filter_by_label)
for server in servers:
+ server = make_unsafe(server)
hostname = server['name']
# check for labels
if group_by_labels and server['LABELS']:
diff --git a/ansible_collections/community/general/plugins/inventory/proxmox.py b/ansible_collections/community/general/plugins/inventory/proxmox.py
index dc2e1febc..ed55ef1b6 100644
--- a/ansible_collections/community/general/plugins/inventory/proxmox.py
+++ b/ansible_collections/community/general/plugins/inventory/proxmox.py
@@ -25,15 +25,15 @@ DOCUMENTATION = '''
- inventory_cache
options:
plugin:
- description: The name of this plugin, it should always be set to C(community.general.proxmox) for this plugin to recognize it as it's own.
+ description: The name of this plugin, it should always be set to V(community.general.proxmox) for this plugin to recognize it as it's own.
required: true
choices: ['community.general.proxmox']
type: str
url:
description:
- URL to Proxmox cluster.
- - If the value is not specified in the inventory configuration, the value of environment variable C(PROXMOX_URL) will be used instead.
- - Since community.general 4.7.0 you can also use templating to specify the value of the I(url).
+ - If the value is not specified in the inventory configuration, the value of environment variable E(PROXMOX_URL) will be used instead.
+ - Since community.general 4.7.0 you can also use templating to specify the value of the O(url).
default: 'http://localhost:8006'
type: str
env:
@@ -42,8 +42,8 @@ DOCUMENTATION = '''
user:
description:
- Proxmox authentication user.
- - If the value is not specified in the inventory configuration, the value of environment variable C(PROXMOX_USER) will be used instead.
- - Since community.general 4.7.0 you can also use templating to specify the value of the I(user).
+ - If the value is not specified in the inventory configuration, the value of environment variable E(PROXMOX_USER) will be used instead.
+ - Since community.general 4.7.0 you can also use templating to specify the value of the O(user).
required: true
type: str
env:
@@ -52,9 +52,9 @@ DOCUMENTATION = '''
password:
description:
- Proxmox authentication password.
- - If the value is not specified in the inventory configuration, the value of environment variable C(PROXMOX_PASSWORD) will be used instead.
- - Since community.general 4.7.0 you can also use templating to specify the value of the I(password).
- - If you do not specify a password, you must set I(token_id) and I(token_secret) instead.
+ - If the value is not specified in the inventory configuration, the value of environment variable E(PROXMOX_PASSWORD) will be used instead.
+ - Since community.general 4.7.0 you can also use templating to specify the value of the O(password).
+ - If you do not specify a password, you must set O(token_id) and O(token_secret) instead.
type: str
env:
- name: PROXMOX_PASSWORD
@@ -62,8 +62,8 @@ DOCUMENTATION = '''
token_id:
description:
- Proxmox authentication token ID.
- - If the value is not specified in the inventory configuration, the value of environment variable C(PROXMOX_TOKEN_ID) will be used instead.
- - To use token authentication, you must also specify I(token_secret). If you do not specify I(token_id) and I(token_secret),
+ - If the value is not specified in the inventory configuration, the value of environment variable E(PROXMOX_TOKEN_ID) will be used instead.
+ - To use token authentication, you must also specify O(token_secret). If you do not specify O(token_id) and O(token_secret),
you must set a password instead.
- Make sure to grant explicit pve permissions to the token or disable 'privilege separation' to use the users' privileges instead.
version_added: 4.8.0
@@ -73,8 +73,8 @@ DOCUMENTATION = '''
token_secret:
description:
- Proxmox authentication token secret.
- - If the value is not specified in the inventory configuration, the value of environment variable C(PROXMOX_TOKEN_SECRET) will be used instead.
- - To use token authentication, you must also specify I(token_id). If you do not specify I(token_id) and I(token_secret),
+ - If the value is not specified in the inventory configuration, the value of environment variable E(PROXMOX_TOKEN_SECRET) will be used instead.
+ - To use token authentication, you must also specify O(token_id). If you do not specify O(token_id) and O(token_secret),
you must set a password instead.
version_added: 4.8.0
type: str
@@ -95,27 +95,32 @@ DOCUMENTATION = '''
want_facts:
description:
- Gather LXC/QEMU configuration facts.
- - When I(want_facts) is set to C(true) more details about QEMU VM status are possible, besides the running and stopped states.
+ - When O(want_facts) is set to V(true) more details about QEMU VM status are possible, besides the running and stopped states.
Currently if the VM is running and it is suspended, the status will be running and the machine will be in C(running) group,
- but its actual state will be paused. See I(qemu_extended_statuses) for how to retrieve the real status.
+ but its actual state will be paused. See O(qemu_extended_statuses) for how to retrieve the real status.
default: false
type: bool
qemu_extended_statuses:
description:
- - Requires I(want_facts) to be set to C(true) to function. This will allow you to differentiate betweend C(paused) and C(prelaunch)
+ - Requires O(want_facts) to be set to V(true) to function. This will allow you to differentiate between C(paused) and C(prelaunch)
statuses of the QEMU VMs.
- - This introduces multiple groups [prefixed with I(group_prefix)] C(prelaunch) and C(paused).
+ - This introduces multiple groups [prefixed with O(group_prefix)] C(prelaunch) and C(paused).
default: false
type: bool
version_added: 5.1.0
want_proxmox_nodes_ansible_host:
version_added: 3.0.0
description:
- - Whether to set C(ansbile_host) for proxmox nodes.
- - When set to C(true) (default), will use the first available interface. This can be different from what you expect.
- - The default of this option changed from C(true) to C(false) in community.general 6.0.0.
+ - Whether to set C(ansible_host) for proxmox nodes.
+ - When set to V(true) (default), will use the first available interface. This can be different from what you expect.
+ - The default of this option changed from V(true) to V(false) in community.general 6.0.0.
type: bool
default: false
+ exclude_nodes:
+ description: Exclude proxmox nodes and the nodes-group from the inventory output.
+ type: bool
+ default: false
+ version_added: 8.1.0
filters:
version_added: 4.6.0
description: A list of Jinja templates that allow filtering hosts.
@@ -166,7 +171,6 @@ plugin: community.general.proxmox
url: http://pve.domain.com:8006
user: ansible@pve
password: secure
-validate_certs: false
want_facts: true
keyed_groups:
# proxmox_tags_parsed is an example of a fact only returned when 'want_facts=true'
@@ -187,10 +191,10 @@ want_proxmox_nodes_ansible_host: true
# Note: my_inv_var demonstrates how to add a string variable to every host used by the inventory.
# my.proxmox.yml
plugin: community.general.proxmox
-url: http://pve.domain.com:8006
+url: http://192.168.1.2:8006
user: ansible@pve
password: secure
-validate_certs: false
+validate_certs: false # only do this when you trust the network!
want_facts: true
want_proxmox_nodes_ansible_host: false
compose:
@@ -222,6 +226,7 @@ from ansible.module_utils.common.text.converters import to_native
from ansible.module_utils.six import string_types
from ansible.module_utils.six.moves.urllib.parse import urlencode
from ansible.utils.display import Display
+from ansible.utils.unsafe_proxy import wrap_var as make_unsafe
from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
@@ -330,7 +335,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
self._cache[self.cache_key][url] = data
- return self._cache[self.cache_key][url]
+ return make_unsafe(self._cache[self.cache_key][url])
def _get_nodes(self):
return self._get_json("%s/api2/json/nodes" % self.proxmox_url)
@@ -565,9 +570,9 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
for group in default_groups:
self.inventory.add_group(self._group('all_%s' % (group)))
-
nodes_group = self._group('nodes')
- self.inventory.add_group(nodes_group)
+ if not self.exclude_nodes:
+ self.inventory.add_group(nodes_group)
want_proxmox_nodes_ansible_host = self.get_option("want_proxmox_nodes_ansible_host")
@@ -577,19 +582,24 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
for node in self._get_nodes():
if not node.get('node'):
continue
-
- self.inventory.add_host(node['node'])
- if node['type'] == 'node':
+ if not self.exclude_nodes:
+ self.inventory.add_host(node['node'])
+ if node['type'] == 'node' and not self.exclude_nodes:
self.inventory.add_child(nodes_group, node['node'])
if node['status'] == 'offline':
continue
# get node IP address
- if want_proxmox_nodes_ansible_host:
+ if want_proxmox_nodes_ansible_host and not self.exclude_nodes:
ip = self._get_node_ip(node['node'])
self.inventory.set_variable(node['node'], 'ansible_host', ip)
+ # Setting composite variables
+ if not self.exclude_nodes:
+ variables = self.inventory.get_host(node['node']).get_vars()
+ self._set_composite_vars(self.get_option('compose'), variables, node['node'], strict=self.strict)
+
# add LXC/Qemu groups for the node
for ittype in ('lxc', 'qemu'):
node_type_group = self._group('%s_%s' % (node['node'], ittype))
@@ -631,8 +641,8 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
if self.get_option('qemu_extended_statuses') and not self.get_option('want_facts'):
raise AnsibleError('You must set want_facts to True if you want to use qemu_extended_statuses.')
-
# read rest of options
+ self.exclude_nodes = self.get_option('exclude_nodes')
self.cache_key = self.get_cache_key(path)
self.use_cache = cache and self.get_option('cache')
self.host_filters = self.get_option('filters')
diff --git a/ansible_collections/community/general/plugins/inventory/scaleway.py b/ansible_collections/community/general/plugins/inventory/scaleway.py
index 6aacc9f66..601129f56 100644
--- a/ansible_collections/community/general/plugins/inventory/scaleway.py
+++ b/ansible_collections/community/general/plugins/inventory/scaleway.py
@@ -37,7 +37,7 @@ DOCUMENTATION = r'''
scw_profile:
description:
- The config profile to use in config file.
- - By default uses the one specified as C(active_profile) in the config file, or falls back to C(default) if that is not defined.
+ - By default uses the one specified as C(active_profile) in the config file, or falls back to V(default) if that is not defined.
type: string
version_added: 4.4.0
oauth_token:
@@ -124,6 +124,7 @@ from ansible_collections.community.general.plugins.module_utils.scaleway import
from ansible.module_utils.urls import open_url
from ansible.module_utils.common.text.converters import to_native, to_text
from ansible.module_utils.six import raise_from
+from ansible.utils.unsafe_proxy import wrap_var as make_unsafe
import ansible.module_utils.six.moves.urllib.parse as urllib_parse
@@ -279,7 +280,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
zone_info = SCALEWAY_LOCATION[zone]
url = _build_server_url(zone_info["api_endpoint"])
- raw_zone_hosts_infos = _fetch_information(url=url, token=token)
+ raw_zone_hosts_infos = make_unsafe(_fetch_information(url=url, token=token))
for host_infos in raw_zone_hosts_infos:
@@ -341,4 +342,4 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
hostname_preference = self.get_option("hostnames")
for zone in self._get_zones(config_zones):
- self.do_zone_inventory(zone=zone, token=token, tags=tags, hostname_preferences=hostname_preference)
+ self.do_zone_inventory(zone=make_unsafe(zone), token=token, tags=tags, hostname_preferences=hostname_preference)
diff --git a/ansible_collections/community/general/plugins/inventory/stackpath_compute.py b/ansible_collections/community/general/plugins/inventory/stackpath_compute.py
index 39f880e82..9a556d39e 100644
--- a/ansible_collections/community/general/plugins/inventory/stackpath_compute.py
+++ b/ansible_collections/community/general/plugins/inventory/stackpath_compute.py
@@ -72,6 +72,7 @@ from ansible.plugins.inventory import (
Cacheable
)
from ansible.utils.display import Display
+from ansible.utils.unsafe_proxy import wrap_var as make_unsafe
display = Display()
@@ -271,7 +272,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
if not cache or cache_needs_update:
results = self._query()
- self._populate(results)
+ self._populate(make_unsafe(results))
# If the cache has expired/doesn't exist or
# if refresh_inventory/flush cache is used
diff --git a/ansible_collections/community/general/plugins/inventory/virtualbox.py b/ansible_collections/community/general/plugins/inventory/virtualbox.py
index c926d8b44..8604808e1 100644
--- a/ansible_collections/community/general/plugins/inventory/virtualbox.py
+++ b/ansible_collections/community/general/plugins/inventory/virtualbox.py
@@ -62,6 +62,7 @@ from ansible.module_utils.common.text.converters import to_bytes, to_native, to_
from ansible.module_utils.common._collections_compat import MutableMapping
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable, Cacheable
from ansible.module_utils.common.process import get_bin_path
+from ansible.utils.unsafe_proxy import wrap_var as make_unsafe
class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
@@ -116,6 +117,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
self._add_host_to_keyed_groups(self.get_option('keyed_groups'), hostvars[host], host, strict=strict)
def _populate_from_cache(self, source_data):
+ source_data = make_unsafe(source_data)
hostvars = source_data.pop('_meta', {}).get('hostvars', {})
for group in source_data:
if group == 'all':
@@ -162,7 +164,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
v = v.strip()
# found host
if k.startswith('Name') and ',' not in v: # some setting strings appear in Name
- current_host = v
+ current_host = make_unsafe(v)
if current_host not in hostvars:
hostvars[current_host] = {}
self.inventory.add_host(current_host)
@@ -170,12 +172,13 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
# try to get network info
netdata = self._query_vbox_data(current_host, netinfo)
if netdata:
- self.inventory.set_variable(current_host, 'ansible_host', netdata)
+ self.inventory.set_variable(current_host, 'ansible_host', make_unsafe(netdata))
# found groups
elif k == 'Groups':
for group in v.split('/'):
if group:
+ group = make_unsafe(group)
group = self.inventory.add_group(group)
self.inventory.add_child(group, current_host)
if group not in cacheable_results:
@@ -185,17 +188,17 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
else:
# found vars, accumulate in hostvars for clean inventory set
- pref_k = 'vbox_' + k.strip().replace(' ', '_')
+ pref_k = make_unsafe('vbox_' + k.strip().replace(' ', '_'))
leading_spaces = len(k) - len(k.lstrip(' '))
if 0 < leading_spaces <= 2:
if prevkey not in hostvars[current_host] or not isinstance(hostvars[current_host][prevkey], dict):
hostvars[current_host][prevkey] = {}
- hostvars[current_host][prevkey][pref_k] = v
+ hostvars[current_host][prevkey][pref_k] = make_unsafe(v)
elif leading_spaces > 2:
continue
else:
if v != '':
- hostvars[current_host][pref_k] = v
+ hostvars[current_host][pref_k] = make_unsafe(v)
if self._ungrouped_host(current_host, cacheable_results):
if 'ungrouped' not in cacheable_results:
cacheable_results['ungrouped'] = {'hosts': []}
diff --git a/ansible_collections/community/general/plugins/inventory/xen_orchestra.py b/ansible_collections/community/general/plugins/inventory/xen_orchestra.py
index ddbdd9bb0..96dd99770 100644
--- a/ansible_collections/community/general/plugins/inventory/xen_orchestra.py
+++ b/ansible_collections/community/general/plugins/inventory/xen_orchestra.py
@@ -23,21 +23,21 @@ DOCUMENTATION = '''
- inventory_cache
options:
plugin:
- description: The name of this plugin, it should always be set to C(community.general.xen_orchestra) for this plugin to recognize it as its own.
+ description: The name of this plugin, it should always be set to V(community.general.xen_orchestra) for this plugin to recognize it as its own.
required: true
choices: ['community.general.xen_orchestra']
type: str
api_host:
description:
- API host to XOA API.
- - If the value is not specified in the inventory configuration, the value of environment variable C(ANSIBLE_XO_HOST) will be used instead.
+ - If the value is not specified in the inventory configuration, the value of environment variable E(ANSIBLE_XO_HOST) will be used instead.
type: str
env:
- name: ANSIBLE_XO_HOST
user:
description:
- Xen Orchestra user.
- - If the value is not specified in the inventory configuration, the value of environment variable C(ANSIBLE_XO_USER) will be used instead.
+ - If the value is not specified in the inventory configuration, the value of environment variable E(ANSIBLE_XO_USER) will be used instead.
required: true
type: str
env:
@@ -45,7 +45,7 @@ DOCUMENTATION = '''
password:
description:
- Xen Orchestra password.
- - If the value is not specified in the inventory configuration, the value of environment variable C(ANSIBLE_XO_PASSWORD) will be used instead.
+ - If the value is not specified in the inventory configuration, the value of environment variable E(ANSIBLE_XO_PASSWORD) will be used instead.
required: true
type: str
env:
@@ -82,6 +82,7 @@ from time import sleep
from ansible.errors import AnsibleError
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable, Cacheable
+from ansible.utils.unsafe_proxy import wrap_var as make_unsafe
from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
@@ -347,4 +348,4 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
self.protocol = 'ws'
objects = self._get_objects()
- self._populate(objects)
+ self._populate(make_unsafe(objects))
diff --git a/ansible_collections/community/general/plugins/lookup/bitwarden.py b/ansible_collections/community/general/plugins/lookup/bitwarden.py
index 27de1afe6..2cb2d19a1 100644
--- a/ansible_collections/community/general/plugins/lookup/bitwarden.py
+++ b/ansible_collections/community/general/plugins/lookup/bitwarden.py
@@ -13,7 +13,7 @@ DOCUMENTATION = """
- bw (command line utility)
- be logged into bitwarden
- bitwarden vault unlocked
- - C(BW_SESSION) environment variable set
+ - E(BW_SESSION) environment variable set
short_description: Retrieve secrets from Bitwarden
version_added: 5.4.0
description:
@@ -25,7 +25,11 @@ DOCUMENTATION = """
type: list
elements: str
search:
- description: Field to retrieve, for example C(name) or C(id).
+ description:
+ - Field to retrieve, for example V(name) or V(id).
+ - If set to V(id), only zero or one element can be returned.
+ Use the Jinja C(first) filter to get the only list element.
+ - When O(collection_id) is set, this field can be undefined to retrieve the whole collection records.
type: str
default: name
version_added: 5.7.0
@@ -36,40 +40,57 @@ DOCUMENTATION = """
description: Collection ID to filter results by collection. Leave unset to skip filtering.
type: str
version_added: 6.3.0
+ bw_session:
+ description: Pass session key instead of reading from env.
+ type: str
+ version_added: 8.4.0
"""
EXAMPLES = """
-- name: "Get 'password' from Bitwarden record named 'a_test'"
+- name: "Get 'password' from all Bitwarden records named 'a_test'"
ansible.builtin.debug:
msg: >-
{{ lookup('community.general.bitwarden', 'a_test', field='password') }}
-- name: "Get 'password' from Bitwarden record with id 'bafba515-af11-47e6-abe3-af1200cd18b2'"
+- name: "Get 'password' from Bitwarden record with ID 'bafba515-af11-47e6-abe3-af1200cd18b2'"
ansible.builtin.debug:
msg: >-
- {{ lookup('community.general.bitwarden', 'bafba515-af11-47e6-abe3-af1200cd18b2', search='id', field='password') }}
+ {{ lookup('community.general.bitwarden', 'bafba515-af11-47e6-abe3-af1200cd18b2', search='id', field='password') | first }}
-- name: "Get 'password' from Bitwarden record named 'a_test' from collection"
+- name: "Get 'password' from all Bitwarden records named 'a_test' from collection"
ansible.builtin.debug:
msg: >-
{{ lookup('community.general.bitwarden', 'a_test', field='password', collection_id='bafba515-af11-47e6-abe3-af1200cd18b2') }}
-- name: "Get full Bitwarden record named 'a_test'"
+- name: "Get list of all full Bitwarden records named 'a_test'"
ansible.builtin.debug:
msg: >-
{{ lookup('community.general.bitwarden', 'a_test') }}
-- name: "Get custom field 'api_key' from Bitwarden record named 'a_test'"
+- name: "Get custom field 'api_key' from all Bitwarden records named 'a_test'"
ansible.builtin.debug:
msg: >-
{{ lookup('community.general.bitwarden', 'a_test', field='api_key') }}
+
+- name: "Get 'password' from all Bitwarden records named 'a_test', using given session key"
+ ansible.builtin.debug:
+ msg: >-
+ {{ lookup('community.general.bitwarden', 'a_test', field='password', bw_session='bXZ9B5TXi6...') }}
+
+- name: "Get all Bitwarden records from collection"
+ ansible.builtin.debug:
+ msg: >-
+ {{ lookup('community.general.bitwarden', None, collection_id='bafba515-af11-47e6-abe3-af1200cd18b2') }}
"""
RETURN = """
_raw:
- description: List of requested field or JSON object of list of matches.
+ description:
+ - A one-element list that contains a list of requested fields or JSON objects of matches.
+ - If you use C(query), you get a list of lists. If you use C(lookup) without C(wantlist=true),
+ this always gets reduced to a list of field values or JSON objects.
type: list
- elements: raw
+ elements: list
"""
from subprocess import Popen, PIPE
@@ -88,76 +109,120 @@ class Bitwarden(object):
def __init__(self, path='bw'):
self._cli_path = path
+ self._session = None
@property
def cli_path(self):
return self._cli_path
@property
+ def session(self):
+ return self._session
+
+ @session.setter
+ def session(self, value):
+ self._session = value
+
+ @property
def unlocked(self):
out, err = self._run(['status'], stdin="")
decoded = AnsibleJSONDecoder().raw_decode(out)[0]
return decoded['status'] == 'unlocked'
def _run(self, args, stdin=None, expected_rc=0):
+ if self.session:
+ args += ['--session', self.session]
+
p = Popen([self.cli_path] + args, stdout=PIPE, stderr=PIPE, stdin=PIPE)
out, err = p.communicate(to_bytes(stdin))
rc = p.wait()
if rc != expected_rc:
+ if len(args) > 2 and args[0] == 'get' and args[1] == 'item' and b'Not found.' in err:
+ return 'null', ''
raise BitwardenException(err)
return to_text(out, errors='surrogate_or_strict'), to_text(err, errors='surrogate_or_strict')
- def _get_matches(self, search_value, search_field, collection_id):
+ def _get_matches(self, search_value, search_field, collection_id=None):
"""Return matching records whose search_field is equal to key.
"""
# Prepare set of params for Bitwarden CLI
- params = ['list', 'items', '--search', search_value]
+ if search_value:
+ if search_field == 'id':
+ params = ['get', 'item', search_value]
+ else:
+ params = ['list', 'items', '--search', search_value]
+ if collection_id:
+ params.extend(['--collectionid', collection_id])
+ else:
+ if not collection_id:
+ raise AnsibleError("search_value is required if collection_id is not set.")
- if collection_id:
- params.extend(['--collectionid', collection_id])
+ params = ['list', 'items', '--collectionid', collection_id]
out, err = self._run(params)
# This includes things that matched in different fields.
initial_matches = AnsibleJSONDecoder().raw_decode(out)[0]
+ if search_field == 'id' or not search_value:
+ if initial_matches is None:
+ initial_matches = []
+ else:
+ initial_matches = [initial_matches]
+
# Filter to only include results from the right field.
return [item for item in initial_matches if item[search_field] == search_value]
- def get_field(self, field, search_value, search_field="name", collection_id=None):
+ def get_field(self, field, search_value=None, search_field="name", collection_id=None):
"""Return a list of the specified field for records whose search_field match search_value
and filtered by collection if collection has been provided.
If field is None, return the whole record for each match.
"""
matches = self._get_matches(search_value, search_field, collection_id)
-
- if field in ['autofillOnPageLoad', 'password', 'passwordRevisionDate', 'totp', 'uris', 'username']:
- return [match['login'][field] for match in matches]
- elif not field:
+ if not field:
return matches
- else:
- custom_field_matches = []
- for match in matches:
+ field_matches = []
+ for match in matches:
+ # if there are no custom fields, then `match` has no key 'fields'
+ if 'fields' in match:
+ custom_field_found = False
for custom_field in match['fields']:
- if custom_field['name'] == field:
- custom_field_matches.append(custom_field['value'])
- if matches and not custom_field_matches:
- raise AnsibleError("Custom field {field} does not exist in {search_value}".format(field=field, search_value=search_value))
- return custom_field_matches
+ if field == custom_field['name']:
+ field_matches.append(custom_field['value'])
+ custom_field_found = True
+ break
+ if custom_field_found:
+ continue
+ if 'login' in match and field in match['login']:
+ field_matches.append(match['login'][field])
+ continue
+ if field in match:
+ field_matches.append(match[field])
+ continue
+
+ if matches and not field_matches:
+ raise AnsibleError("field {field} does not exist in {search_value}".format(field=field, search_value=search_value))
+
+ return field_matches
class LookupModule(LookupBase):
- def run(self, terms, variables=None, **kwargs):
+ def run(self, terms=None, variables=None, **kwargs):
self.set_options(var_options=variables, direct=kwargs)
field = self.get_option('field')
search_field = self.get_option('search')
collection_id = self.get_option('collection_id')
+ _bitwarden.session = self.get_option('bw_session')
+
if not _bitwarden.unlocked:
raise AnsibleError("Bitwarden Vault locked. Run 'bw unlock'.")
+ if not terms:
+ return [_bitwarden.get_field(field, None, search_field, collection_id)]
+
return [_bitwarden.get_field(field, term, search_field, collection_id) for term in terms]
diff --git a/ansible_collections/community/general/plugins/lookup/bitwarden_secrets_manager.py b/ansible_collections/community/general/plugins/lookup/bitwarden_secrets_manager.py
new file mode 100644
index 000000000..2d6706bee
--- /dev/null
+++ b/ansible_collections/community/general/plugins/lookup/bitwarden_secrets_manager.py
@@ -0,0 +1,125 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2023, jantari (https://github.com/jantari)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+from __future__ import (absolute_import, division, print_function)
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+ name: bitwarden_secrets_manager
+ author:
+ - jantari (@jantari)
+ requirements:
+ - bws (command line utility)
+ short_description: Retrieve secrets from Bitwarden Secrets Manager
+ version_added: 7.2.0
+ description:
+ - Retrieve secrets from Bitwarden Secrets Manager.
+ options:
+ _terms:
+ description: Secret ID(s) to fetch values for.
+ required: true
+ type: list
+ elements: str
+ bws_access_token:
+ description: The BWS access token to use for this lookup.
+ env:
+ - name: BWS_ACCESS_TOKEN
+ required: true
+ type: str
+"""
+
+EXAMPLES = """
+- name: Get a secret relying on the BWS_ACCESS_TOKEN environment variable for authentication
+ ansible.builtin.debug:
+ msg: >-
+ {{ lookup("community.general.bitwarden_secrets_manager", "2bc23e48-4932-40de-a047-5524b7ddc972") }}
+
+- name: Get a secret passing an explicit access token for authentication
+ ansible.builtin.debug:
+ msg: >-
+ {{
+ lookup(
+ "community.general.bitwarden_secrets_manager",
+ "2bc23e48-4932-40de-a047-5524b7ddc972",
+ bws_access_token="9.4f570d14-4b54-42f5-bc07-60f4450b1db5.YmluYXJ5LXNvbWV0aGluZy0xMjMK:d2h5IGhlbGxvIHRoZXJlCg=="
+ )
+ }}
+
+- name: Get two different secrets each using a different access token for authentication
+ ansible.builtin.debug:
+ msg:
+ - '{{ lookup("community.general.bitwarden_secrets_manager", "2bc23e48-4932-40de-a047-5524b7ddc972", bws_access_token=token1) }}'
+ - '{{ lookup("community.general.bitwarden_secrets_manager", "9d89af4c-eb5d-41f5-bb0f-4ae81215c768", bws_access_token=token2) }}'
+ vars:
+ token1: "9.4f570d14-4b54-42f5-bc07-60f4450b1db5.YmluYXJ5LXNvbWV0aGluZy0xMjMK:d2h5IGhlbGxvIHRoZXJlCg=="
+ token2: "1.69b72797-6ea9-4687-a11e-848e41a30ae6.YW5zaWJsZSBpcyBncmVhdD8K:YW5zaWJsZSBpcyBncmVhdAo="
+
+- name: Get just the value of a secret
+ ansible.builtin.debug:
+ msg: >-
+ {{ lookup("community.general.bitwarden_secrets_manager", "2bc23e48-4932-40de-a047-5524b7ddc972").value }}
+"""
+
+RETURN = """
+ _raw:
+ description: List containing one or more secrets.
+ type: list
+ elements: dict
+"""
+
+from subprocess import Popen, PIPE
+
+from ansible.errors import AnsibleLookupError
+from ansible.module_utils.common.text.converters import to_text
+from ansible.parsing.ajson import AnsibleJSONDecoder
+from ansible.plugins.lookup import LookupBase
+
+
+class BitwardenSecretsManagerException(AnsibleLookupError):
+ pass
+
+
+class BitwardenSecretsManager(object):
+ def __init__(self, path='bws'):
+ self._cli_path = path
+
+ @property
+ def cli_path(self):
+ return self._cli_path
+
+ def _run(self, args, stdin=None):
+ p = Popen([self.cli_path] + args, stdout=PIPE, stderr=PIPE, stdin=PIPE)
+ out, err = p.communicate(stdin)
+ rc = p.wait()
+ return to_text(out, errors='surrogate_or_strict'), to_text(err, errors='surrogate_or_strict'), rc
+
+ def get_secret(self, secret_id, bws_access_token):
+ """Get and return the secret with the given secret_id.
+ """
+
+ # Prepare set of params for Bitwarden Secrets Manager CLI
+ # Color output was not always disabled correctly with the default 'auto' setting so explicitly disable it.
+ params = [
+ '--color', 'no',
+ '--access-token', bws_access_token,
+ 'get', 'secret', secret_id
+ ]
+
+ out, err, rc = self._run(params)
+ if rc != 0:
+ raise BitwardenSecretsManagerException(to_text(err))
+
+ return AnsibleJSONDecoder().raw_decode(out)[0]
+
+
+class LookupModule(LookupBase):
+ def run(self, terms, variables=None, **kwargs):
+ self.set_options(var_options=variables, direct=kwargs)
+ bws_access_token = self.get_option('bws_access_token')
+
+ return [_bitwarden_secrets_manager.get_secret(term, bws_access_token) for term in terms]
+
+
+_bitwarden_secrets_manager = BitwardenSecretsManager()
diff --git a/ansible_collections/community/general/plugins/lookup/collection_version.py b/ansible_collections/community/general/plugins/lookup/collection_version.py
index 4d25585b8..33316fc2b 100644
--- a/ansible_collections/community/general/plugins/lookup/collection_version.py
+++ b/ansible_collections/community/general/plugins/lookup/collection_version.py
@@ -13,22 +13,22 @@ short_description: Retrieves the version of an installed collection
description:
- This lookup allows to query the version of an installed collection, and to determine whether a
collection is installed at all.
- - By default it returns C(none) for non-existing collections and C(*) for collections without a
+ - By default it returns V(none) for non-existing collections and V(*) for collections without a
version number. The latter should only happen in development environments, or when installing
a collection from git which has no version in its C(galaxy.yml). This behavior can be adjusted
- by providing other values with I(result_not_found) and I(result_no_version).
+ by providing other values with O(result_not_found) and O(result_no_version).
options:
_terms:
description:
- The collections to look for.
- - For example C(community.general).
+ - For example V(community.general).
type: list
elements: str
required: true
result_not_found:
description:
- The value to return when the collection could not be found.
- - By default, C(none) is returned.
+ - By default, V(none) is returned.
type: string
default: ~
result_no_version:
@@ -36,7 +36,7 @@ options:
- The value to return when the collection has no version number.
- This can happen for collections installed from git which do not have a version number
in C(galaxy.yml).
- - By default, C(*) is returned.
+ - By default, V(*) is returned.
type: string
default: '*'
"""
@@ -51,11 +51,11 @@ RETURN = """
_raw:
description:
- The version number of the collections listed as input.
- - If a collection can not be found, it will return the value provided in I(result_not_found).
- By default, this is C(none).
+ - If a collection can not be found, it will return the value provided in O(result_not_found).
+ By default, this is V(none).
- If a collection can be found, but the version not identified, it will return the value provided in
- I(result_no_version). By default, this is C(*). This can happen for collections installed
- from git which do not have a version number in C(galaxy.yml).
+ O(result_no_version). By default, this is V(*). This can happen for collections installed
+ from git which do not have a version number in V(galaxy.yml).
type: list
elements: str
"""
@@ -98,15 +98,10 @@ def load_collection_meta(collection_pkg, no_version='*'):
if os.path.exists(manifest_path):
return load_collection_meta_manifest(manifest_path)
- # Try to load galaxy.y(a)ml
+ # Try to load galaxy.yml
galaxy_path = os.path.join(path, 'galaxy.yml')
- galaxy_alt_path = os.path.join(path, 'galaxy.yaml')
- # galaxy.yaml was only supported in ansible-base 2.10 and ansible-core 2.11. Support was removed
- # in https://github.com/ansible/ansible/commit/595413d11346b6f26bb3d9df2d8e05f2747508a3 for
- # ansible-core 2.12.
- for path in (galaxy_path, galaxy_alt_path):
- if os.path.exists(path):
- return load_collection_meta_galaxy(path, no_version=no_version)
+ if os.path.exists(galaxy_path):
+ return load_collection_meta_galaxy(galaxy_path, no_version=no_version)
return {}
diff --git a/ansible_collections/community/general/plugins/lookup/consul_kv.py b/ansible_collections/community/general/plugins/lookup/consul_kv.py
index f17f1b269..f8aadadc1 100644
--- a/ansible_collections/community/general/plugins/lookup/consul_kv.py
+++ b/ansible_collections/community/general/plugins/lookup/consul_kv.py
@@ -38,23 +38,20 @@ DOCUMENTATION = '''
default: localhost
description:
- The target to connect to, must be a resolvable address.
- Will be determined from C(ANSIBLE_CONSUL_URL) if that is set.
- - "C(ANSIBLE_CONSUL_URL) should look like this: C(https://my.consul.server:8500)"
- env:
- - name: ANSIBLE_CONSUL_URL
+ - Will be determined from E(ANSIBLE_CONSUL_URL) if that is set.
ini:
- section: lookup_consul
key: host
port:
description:
- The port of the target host to connect to.
- - If you use C(ANSIBLE_CONSUL_URL) this value will be used from there.
+ - If you use E(ANSIBLE_CONSUL_URL) this value will be used from there.
default: 8500
scheme:
default: http
description:
- Whether to use http or https.
- - If you use C(ANSIBLE_CONSUL_URL) this value will be used from there.
+ - If you use E(ANSIBLE_CONSUL_URL) this value will be used from there.
validate_certs:
default: true
description: Whether to verify the ssl connection or not.
@@ -71,7 +68,9 @@ DOCUMENTATION = '''
- section: lookup_consul
key: client_cert
url:
- description: "The target to connect to, should look like this: C(https://my.consul.server:8500)."
+ description:
+ - The target to connect to.
+ - "Should look like this: V(https://my.consul.server:8500)."
type: str
version_added: 1.0.0
env:
diff --git a/ansible_collections/community/general/plugins/lookup/dependent.py b/ansible_collections/community/general/plugins/lookup/dependent.py
index 54714344e..31634e6e6 100644
--- a/ansible_collections/community/general/plugins/lookup/dependent.py
+++ b/ansible_collections/community/general/plugins/lookup/dependent.py
@@ -22,7 +22,7 @@ options:
The name is the index that is used in the result object. The value is iterated over as described below.
- If the value is a list, it is simply iterated over.
- If the value is a dictionary, it is iterated over and returned as if they would be processed by the
- R(ansible.builtin.dict2items filter,ansible_collections.ansible.builtin.dict2items_filter).
+ P(ansible.builtin.dict2items#filter) filter.
- If the value is a string, it is evaluated as Jinja2 expressions which can access the previously chosen
elements with C(item.<index_name>). The result must be a list or a dictionary.
type: list
diff --git a/ansible_collections/community/general/plugins/lookup/dig.py b/ansible_collections/community/general/plugins/lookup/dig.py
index fa915220b..5be57cec7 100644
--- a/ansible_collections/community/general/plugins/lookup/dig.py
+++ b/ansible_collections/community/general/plugins/lookup/dig.py
@@ -21,7 +21,7 @@ DOCUMENTATION = '''
- In addition to (default) A record, it is also possible to specify a different record type that should be queried.
This can be done by either passing-in additional parameter of format qtype=TYPE to the dig lookup, or by appending /TYPE to the FQDN being queried.
- If multiple values are associated with the requested record, the results will be returned as a comma-separated list.
- In such cases you may want to pass option I(wantlist=true) to the lookup call, or alternatively use C(query) instead of C(lookup),
+ In such cases you may want to pass option C(wantlist=true) to the lookup call, or alternatively use C(query) instead of C(lookup),
which will result in the record values being returned as a list over which you can iterate later on.
- By default, the lookup will rely on system-wide configured DNS servers for performing the query.
It is also possible to explicitly specify DNS servers to query using the @DNS_SERVER_1,DNS_SERVER_2,...,DNS_SERVER_N notation.
@@ -34,8 +34,8 @@ DOCUMENTATION = '''
qtype:
description:
- Record type to query.
- - C(DLV) has been removed in community.general 6.0.0.
- - C(CAA) has been added in community.general 6.3.0.
+ - V(DLV) has been removed in community.general 6.0.0.
+ - V(CAA) has been added in community.general 6.3.0.
type: str
default: 'A'
choices: [A, ALL, AAAA, CAA, CNAME, DNAME, DNSKEY, DS, HINFO, LOC, MX, NAPTR, NS, NSEC3PARAM, PTR, RP, RRSIG, SOA, SPF, SRV, SSHFP, TLSA, TXT]
@@ -51,17 +51,17 @@ DOCUMENTATION = '''
fail_on_error:
description:
- Abort execution on lookup errors.
- - The default for this option will likely change to C(true) in the future.
- The current default, C(false), is used for backwards compatibility, and will result in empty strings
- or the string C(NXDOMAIN) in the result in case of errors.
+ - The default for this option will likely change to V(true) in the future.
+ The current default, V(false), is used for backwards compatibility, and will result in empty strings
+ or the string V(NXDOMAIN) in the result in case of errors.
default: false
type: bool
version_added: 5.4.0
real_empty:
description:
- - Return empty result without empty strings, and return empty list instead of C(NXDOMAIN).
- - The default for this option will likely change to C(true) in the future.
- - This option will be forced to C(true) if multiple domains to be queried are specified.
+ - Return empty result without empty strings, and return empty list instead of V(NXDOMAIN).
+ - The default for this option will likely change to V(true) in the future.
+ - This option will be forced to V(true) if multiple domains to be queried are specified.
default: false
type: bool
version_added: 6.0.0
@@ -70,6 +70,11 @@ DOCUMENTATION = '''
- "Class."
type: str
default: 'IN'
+ tcp:
+ description: Use TCP to lookup DNS records.
+ default: false
+ type: bool
+ version_added: 7.5.0
notes:
- ALL is not a record per-se, merely the listed fields are available for any record results you retrieve in the form of a dictionary.
- While the 'dig' lookup plugin supports anything which dnspython supports out of the box, only a subset can be converted into a dictionary.
@@ -329,6 +334,7 @@ class LookupModule(LookupBase):
flat = self.get_option('flat')
fail_on_error = self.get_option('fail_on_error')
real_empty = self.get_option('real_empty')
+ tcp = self.get_option('tcp')
try:
rdclass = dns.rdataclass.from_text(self.get_option('class'))
except Exception as e:
@@ -375,6 +381,8 @@ class LookupModule(LookupBase):
fail_on_error = boolean(arg)
elif opt == 'real_empty':
real_empty = boolean(arg)
+ elif opt == 'tcp':
+ tcp = boolean(arg)
continue
@@ -408,7 +416,7 @@ class LookupModule(LookupBase):
for domain in domains:
try:
- answers = myres.query(domain, qtype, rdclass=rdclass)
+ answers = myres.query(domain, qtype, rdclass=rdclass, tcp=tcp)
for rdata in answers:
s = rdata.to_text()
if qtype.upper() == 'TXT':
diff --git a/ansible_collections/community/general/plugins/lookup/dnstxt.py b/ansible_collections/community/general/plugins/lookup/dnstxt.py
index 55067dc82..1ce511b84 100644
--- a/ansible_collections/community/general/plugins/lookup/dnstxt.py
+++ b/ansible_collections/community/general/plugins/lookup/dnstxt.py
@@ -22,8 +22,8 @@ DOCUMENTATION = '''
elements: string
real_empty:
description:
- - Return empty result without empty strings, and return empty list instead of C(NXDOMAIN).
- - The default for this option will likely change to C(true) in the future.
+ - Return empty result without empty strings, and return empty list instead of V(NXDOMAIN).
+ - The default for this option will likely change to V(true) in the future.
default: false
type: bool
version_added: 6.0.0
diff --git a/ansible_collections/community/general/plugins/lookup/dsv.py b/ansible_collections/community/general/plugins/lookup/dsv.py
index 91a9d9921..2dbb7db3e 100644
--- a/ansible_collections/community/general/plugins/lookup/dsv.py
+++ b/ansible_collections/community/general/plugins/lookup/dsv.py
@@ -13,15 +13,15 @@ short_description: Get secrets from Thycotic DevOps Secrets Vault
version_added: 1.0.0
description:
- Uses the Thycotic DevOps Secrets Vault Python SDK to get Secrets from a
- DSV I(tenant) using a I(client_id) and I(client_secret).
+ DSV O(tenant) using a O(client_id) and O(client_secret).
requirements:
- python-dsv-sdk - https://pypi.org/project/python-dsv-sdk/
options:
_terms:
- description: The path to the secret, e.g. C(/staging/servers/web1).
+ description: The path to the secret, for example V(/staging/servers/web1).
required: true
tenant:
- description: The first format parameter in the default I(url_template).
+ description: The first format parameter in the default O(url_template).
env:
- name: DSV_TENANT
ini:
@@ -31,7 +31,7 @@ options:
tld:
default: com
description: The top-level domain of the tenant; the second format
- parameter in the default I(url_template).
+ parameter in the default O(url_template).
env:
- name: DSV_TLD
ini:
@@ -47,7 +47,7 @@ options:
key: client_id
required: true
client_secret:
- description: The client secret associated with the specific I(client_id).
+ description: The client secret associated with the specific O(client_id).
env:
- name: DSV_CLIENT_SECRET
ini:
diff --git a/ansible_collections/community/general/plugins/lookup/etcd.py b/ansible_collections/community/general/plugins/lookup/etcd.py
index d6a12293e..5135e7487 100644
--- a/ansible_collections/community/general/plugins/lookup/etcd.py
+++ b/ansible_collections/community/general/plugins/lookup/etcd.py
@@ -24,7 +24,7 @@ DOCUMENTATION = '''
required: true
url:
description:
- - Environment variable with the url for the etcd server
+ - Environment variable with the URL for the etcd server
default: 'http://127.0.0.1:4001'
env:
- name: ANSIBLE_ETCD_URL
@@ -39,6 +39,10 @@ DOCUMENTATION = '''
- toggle checking that the ssl certificates are valid, you normally only want to turn this off with self-signed certs.
default: true
type: boolean
+ seealso:
+ - module: community.general.etcd3
+ - plugin: community.general.etcd3
+ plugin_type: lookup
'''
EXAMPLES = '''
@@ -50,7 +54,7 @@ EXAMPLES = '''
ansible.builtin.debug:
msg: "{{ lookup('community.general.etcd', 'foo', 'bar', 'baz') }}"
-- name: "since Ansible 2.5 you can set server options inline"
+- name: "you can set server options inline"
ansible.builtin.debug:
msg: "{{ lookup('community.general.etcd', 'foo', version='v2', url='http://192.168.0.27:4001') }}"
'''
@@ -58,7 +62,7 @@ EXAMPLES = '''
RETURN = '''
_raw:
description:
- - list of values associated with input keys
+ - List of values associated with input keys.
type: list
elements: string
'''
diff --git a/ansible_collections/community/general/plugins/lookup/etcd3.py b/ansible_collections/community/general/plugins/lookup/etcd3.py
index 7f0a0cf90..0bda006e3 100644
--- a/ansible_collections/community/general/plugins/lookup/etcd3.py
+++ b/ansible_collections/community/general/plugins/lookup/etcd3.py
@@ -32,10 +32,10 @@ DOCUMENTATION = '''
default: false
endpoints:
description:
- - Counterpart of C(ETCDCTL_ENDPOINTS) environment variable.
- Specify the etcd3 connection with and URL form eg. C(https://hostname:2379) or C(<host>:<port>) form.
- - The C(host) part is overwritten by I(host) option, if defined.
- - The C(port) part is overwritten by I(port) option, if defined.
+ - Counterpart of E(ETCDCTL_ENDPOINTS) environment variable.
+ Specify the etcd3 connection with and URL form, for example V(https://hostname:2379), or V(<host>:<port>) form.
+ - The V(host) part is overwritten by O(host) option, if defined.
+ - The V(port) part is overwritten by O(port) option, if defined.
env:
- name: ETCDCTL_ENDPOINTS
default: '127.0.0.1:2379'
@@ -43,12 +43,12 @@ DOCUMENTATION = '''
host:
description:
- etcd3 listening client host.
- - Takes precedence over I(endpoints).
+ - Takes precedence over O(endpoints).
type: str
port:
description:
- etcd3 listening client port.
- - Takes precedence over I(endpoints).
+ - Takes precedence over O(endpoints).
type: int
ca_cert:
description:
@@ -89,13 +89,13 @@ DOCUMENTATION = '''
type: str
notes:
- - I(host) and I(port) options take precedence over (endpoints) option.
- - The recommended way to connect to etcd3 server is using C(ETCDCTL_ENDPOINT)
- environment variable and keep I(endpoints), I(host), and I(port) unused.
+ - O(host) and O(port) options take precedence over (endpoints) option.
+ - The recommended way to connect to etcd3 server is using E(ETCDCTL_ENDPOINT)
+ environment variable and keep O(endpoints), O(host), and O(port) unused.
seealso:
- module: community.general.etcd3
- - ref: ansible_collections.community.general.etcd_lookup
- description: The etcd v2 lookup.
+ - plugin: community.general.etcd
+ plugin_type: lookup
requirements:
- "etcd3 >= 0.10"
diff --git a/ansible_collections/community/general/plugins/lookup/filetree.py b/ansible_collections/community/general/plugins/lookup/filetree.py
index f12cc4519..2131de99a 100644
--- a/ansible_collections/community/general/plugins/lookup/filetree.py
+++ b/ansible_collections/community/general/plugins/lookup/filetree.py
@@ -65,7 +65,7 @@ RETURN = r"""
src:
description:
- Full path to file.
- - Not returned when I(item.state) is set to C(directory).
+ - Not returned when RV(_raw[].state) is set to V(directory).
type: path
root:
description: Allows filtering by original location.
diff --git a/ansible_collections/community/general/plugins/lookup/flattened.py b/ansible_collections/community/general/plugins/lookup/flattened.py
index e955b6478..0071417a0 100644
--- a/ansible_collections/community/general/plugins/lookup/flattened.py
+++ b/ansible_collections/community/general/plugins/lookup/flattened.py
@@ -19,7 +19,7 @@ DOCUMENTATION = '''
elements: raw
required: true
notes:
- - Unlike the R(items lookup,ansible_collections.ansible.builtin.items_lookup) which only flattens 1 level,
+ - Unlike the P(ansible.builtin.items#lookup) lookup which only flattens 1 level,
this plugin will continue to flatten until it cannot find lists anymore.
- Aka highlander plugin, there can only be one (list).
'''
diff --git a/ansible_collections/community/general/plugins/lookup/github_app_access_token.py b/ansible_collections/community/general/plugins/lookup/github_app_access_token.py
new file mode 100644
index 000000000..5cd99b81c
--- /dev/null
+++ b/ansible_collections/community/general/plugins/lookup/github_app_access_token.py
@@ -0,0 +1,156 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2023, Poh Wei Sheng <weisheng-p@hotmail.sg>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+DOCUMENTATION = '''
+ name: github_app_access_token
+ author:
+ - Poh Wei Sheng (@weisheng-p)
+ short_description: Obtain short-lived Github App Access tokens
+ version_added: '8.2.0'
+ requirements:
+ - jwt (https://github.com/GehirnInc/python-jwt)
+ description:
+ - This generates a Github access token that can be used with a C(git) command, if you use a Github App.
+ options:
+ key_path:
+ description:
+ - Path to your private key.
+ required: true
+ type: path
+ app_id:
+ description:
+ - Your GitHub App ID, you can find this in the Settings page.
+ required: true
+ type: str
+ installation_id:
+ description:
+ - The installation ID that contains the git repository you would like access to.
+ - As of 2023-12-24, this can be found via Settings page > Integrations > Application. The last part of the URL in the
+ configure button is the installation ID.
+ - Alternatively, you can use PyGithub (U(https://github.com/PyGithub/PyGithub)) to get your installation ID.
+ required: true
+ type: str
+ token_expiry:
+ description:
+ - How long the token should last for in seconds.
+ default: 600
+ type: int
+'''
+
+EXAMPLES = '''
+- name: Get access token to be used for git checkout with app_id=123456, installation_id=64209
+ ansible.builtin.git:
+ repo: >-
+ https://x-access-token:{{ github_token }}@github.com/hidden_user/super-secret-repo.git
+ dest: /srv/checkout
+ vars:
+ github_token: >-
+ lookup('community.general.github_app_access_token', key_path='/home/to_your/key',
+ app_id='123456', installation_id='64209')
+'''
+
+RETURN = '''
+ _raw:
+ description: A one-element list containing your GitHub access token.
+ type: list
+ elements: str
+'''
+
+
+try:
+ from jwt import JWT, jwk_from_pem
+ HAS_JWT = True
+except ImportError:
+ HAS_JWT = False
+
+import time
+import json
+from ansible.module_utils.urls import open_url
+from ansible.module_utils.six.moves.urllib.error import HTTPError
+from ansible.errors import AnsibleError
+from ansible.plugins.lookup import LookupBase
+from ansible.utils.display import Display
+
+if HAS_JWT:
+ jwt_instance = JWT()
+else:
+ jwk_from_pem = None
+ jwt_instance = None
+
+display = Display()
+
+
+def read_key(path):
+ try:
+ with open(path, 'rb') as pem_file:
+ return jwk_from_pem(pem_file.read())
+ except Exception as e:
+ raise AnsibleError("Error while parsing key file: {0}".format(e))
+
+
+def encode_jwt(app_id, jwk, exp=600):
+ now = int(time.time())
+ payload = {
+ 'iat': now,
+ 'exp': now + exp,
+ 'iss': app_id,
+ }
+ try:
+ return jwt_instance.encode(payload, jwk, alg='RS256')
+ except Exception as e:
+ raise AnsibleError("Error while encoding jwt: {0}".format(e))
+
+
+def post_request(generated_jwt, installation_id):
+ github_api_url = f'https://api.github.com/app/installations/{installation_id}/access_tokens'
+ headers = {
+ "Authorization": f'Bearer {generated_jwt}',
+ "Accept": "application/vnd.github.v3+json",
+ }
+ try:
+ response = open_url(github_api_url, headers=headers, method='POST')
+ except HTTPError as e:
+ try:
+ error_body = json.loads(e.read().decode())
+ display.vvv("Error returned: {0}".format(error_body))
+ except Exception:
+ error_body = {}
+ if e.code == 404:
+ raise AnsibleError("Github return error. Please confirm your installationd_id value is valid")
+ elif e.code == 401:
+ raise AnsibleError("Github return error. Please confirm your private key is valid")
+ raise AnsibleError("Unexpected data returned: {0} -- {1}".format(e, error_body))
+ response_body = response.read()
+ try:
+ json_data = json.loads(response_body.decode('utf-8'))
+ except json.decoder.JSONDecodeError as e:
+ raise AnsibleError("Error while dencoding JSON respone from github: {0}".format(e))
+ return json_data.get('token')
+
+
+def get_token(key_path, app_id, installation_id, expiry=600):
+ jwk = read_key(key_path)
+ generated_jwt = encode_jwt(app_id, jwk, exp=expiry)
+ return post_request(generated_jwt, installation_id)
+
+
+class LookupModule(LookupBase):
+ def run(self, terms, variables=None, **kwargs):
+ if not HAS_JWT:
+ raise AnsibleError('Python jwt library is required. '
+ 'Please install using "pip install jwt"')
+
+ self.set_options(var_options=variables, direct=kwargs)
+
+ t = get_token(
+ self.get_option('key_path'),
+ self.get_option('app_id'),
+ self.get_option('installation_id'),
+ self.get_option('token_expiry'),
+ )
+
+ return [t]
diff --git a/ansible_collections/community/general/plugins/lookup/lmdb_kv.py b/ansible_collections/community/general/plugins/lookup/lmdb_kv.py
index 0950249dc..a37cff956 100644
--- a/ansible_collections/community/general/plugins/lookup/lmdb_kv.py
+++ b/ansible_collections/community/general/plugins/lookup/lmdb_kv.py
@@ -15,7 +15,7 @@ DOCUMENTATION = '''
description:
- This lookup returns a list of results from an LMDB DB corresponding to a list of items given to it.
requirements:
- - lmdb (python library https://lmdb.readthedocs.io/en/release/)
+ - lmdb (Python library U(https://lmdb.readthedocs.io/en/release/))
options:
_terms:
description: List of keys to query.
diff --git a/ansible_collections/community/general/plugins/lookup/merge_variables.py b/ansible_collections/community/general/plugins/lookup/merge_variables.py
index cd5fa5b7d..4fc33014c 100644
--- a/ansible_collections/community/general/plugins/lookup/merge_variables.py
+++ b/ansible_collections/community/general/plugins/lookup/merge_variables.py
@@ -10,16 +10,17 @@ DOCUMENTATION = """
author:
- Roy Lenferink (@rlenferink)
- Mark Ettema (@m-a-r-k-e)
+ - Alexander Petrenz (@alpex8)
name: merge_variables
short_description: merge variables with a certain suffix
description:
- This lookup returns the merged result of all variables in scope that match the given prefixes, suffixes, or
- regular expressions, optionally.
+ regular expressions, optionally.
version_added: 6.5.0
options:
_terms:
description:
- - Depending on the value of I(pattern_type), this is a list of prefixes, suffixes, or regular expressions
+ - Depending on the value of O(pattern_type), this is a list of prefixes, suffixes, or regular expressions
that will be used to match all variables that should be merged.
required: true
type: list
@@ -45,11 +46,11 @@ DOCUMENTATION = """
override:
description:
- Return an error, print a warning or ignore it when a key will be overwritten.
- - The default behavior C(error) makes the plugin fail when a key would be overwritten.
- - When C(warn) and C(ignore) are used, note that it is important to know that the variables
+ - The default behavior V(error) makes the plugin fail when a key would be overwritten.
+ - When V(warn) and V(ignore) are used, note that it is important to know that the variables
are sorted by name before being merged. Keys for later variables in this order will overwrite
keys of the same name for variables earlier in this order. To avoid potential confusion,
- better use I(override=error) whenever possible.
+ better use O(override=error) whenever possible.
type: str
default: 'error'
choices:
@@ -61,6 +62,13 @@ DOCUMENTATION = """
ini:
- section: merge_variables_lookup
key: override
+ groups:
+ description:
+ - Search for variables accross hosts that belong to the given groups. This allows to collect configuration pieces
+ accross different hosts (for example a service on a host with its database on another host).
+ type: list
+ elements: str
+ version_added: 8.5.0
"""
EXAMPLES = """
@@ -131,22 +139,39 @@ def _verify_and_get_type(variable):
class LookupModule(LookupBase):
-
def run(self, terms, variables=None, **kwargs):
self.set_options(direct=kwargs)
initial_value = self.get_option("initial_value", None)
self._override = self.get_option('override', 'error')
self._pattern_type = self.get_option('pattern_type', 'regex')
+ self._groups = self.get_option('groups', None)
ret = []
for term in terms:
if not isinstance(term, str):
raise AnsibleError("Non-string type '{0}' passed, only 'str' types are allowed!".format(type(term)))
- ret.append(self._merge_vars(term, initial_value, variables))
+ if not self._groups: # consider only own variables
+ ret.append(self._merge_vars(term, initial_value, variables))
+ else: # consider variables of hosts in given groups
+ cross_host_merge_result = initial_value
+ for host in variables["hostvars"]:
+ if self._is_host_in_allowed_groups(variables["hostvars"][host]["group_names"]):
+ cross_host_merge_result = self._merge_vars(term, cross_host_merge_result, variables["hostvars"][host])
+ ret.append(cross_host_merge_result)
return ret
+ def _is_host_in_allowed_groups(self, host_groups):
+ if 'all' in self._groups:
+ return True
+
+ group_intersection = [host_group_name for host_group_name in host_groups if host_group_name in self._groups]
+ if group_intersection:
+ return True
+
+ return False
+
def _var_matches(self, key, search_pattern):
if self._pattern_type == "prefix":
return key.startswith(search_pattern)
@@ -162,7 +187,6 @@ class LookupModule(LookupBase):
display.vvv("Merge variables with {0}: {1}".format(self._pattern_type, search_pattern))
var_merge_names = sorted([key for key in variables.keys() if self._var_matches(key, search_pattern)])
display.vvv("The following variables will be merged: {0}".format(var_merge_names))
-
prev_var_type = None
result = None
diff --git a/ansible_collections/community/general/plugins/lookup/onepassword.py b/ansible_collections/community/general/plugins/lookup/onepassword.py
index 0e78e4b1a..8ca95de0b 100644
--- a/ansible_collections/community/general/plugins/lookup/onepassword.py
+++ b/ansible_collections/community/general/plugins/lookup/onepassword.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-# Copyright (c) 2018, Scott Buchanan <sbuchanan@ri.pn>
+# Copyright (c) 2018, Scott Buchanan <scott@buchanan.works>
# Copyright (c) 2016, Andrew Zenk <azenk@umn.edu> (lastpass.py used as starting point)
# Copyright (c) 2018, Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
@@ -14,48 +14,28 @@ DOCUMENTATION = '''
- Scott Buchanan (@scottsb)
- Andrew Zenk (@azenk)
- Sam Doran (@samdoran)
- requirements:
- - C(op) 1Password command line utility. See U(https://support.1password.com/command-line/)
- short_description: fetch field values from 1Password
+ short_description: Fetch field values from 1Password
description:
- - C(onepassword) wraps the C(op) command line utility to fetch specific field values from 1Password.
+ - P(community.general.onepassword#lookup) wraps the C(op) command line utility to fetch specific field values from 1Password.
+ requirements:
+ - C(op) 1Password command line utility
options:
_terms:
- description: identifier(s) (UUID, name, or subdomain; case-insensitive) of item(s) to retrieve.
+ description: Identifier(s) (case-insensitive UUID or name) of item(s) to retrieve.
required: true
- field:
- description: field to return from each matching item (case-insensitive).
- default: 'password'
- master_password:
- description: The password used to unlock the specified vault.
- aliases: ['vault_password']
- section:
- description: Item section containing the field to retrieve (case-insensitive). If absent will return first match from any section.
+ account_id:
+ version_added: 7.5.0
domain:
- description: Domain of 1Password.
version_added: 3.2.0
- default: '1password.com'
+ field:
+ description: Field to return from each matching item (case-insensitive).
+ default: 'password'
type: str
- subdomain:
- description: The 1Password subdomain to authenticate against.
- username:
- description: The username used to sign in.
- secret_key:
- description: The secret key used when performing an initial sign in.
- vault:
- description: Vault containing the item to retrieve (case-insensitive). If absent will search all vaults.
- notes:
- - This lookup will use an existing 1Password session if one exists. If not, and you have already
- performed an initial sign in (meaning C(~/.op/config), C(~/.config/op/config) or C(~/.config/.op/config) exists), then only the
- C(master_password) is required. You may optionally specify C(subdomain) in this scenario, otherwise the last used subdomain will be used by C(op).
- - This lookup can perform an initial login by providing C(subdomain), C(username), C(secret_key), and C(master_password).
- - Due to the B(very) sensitive nature of these credentials, it is B(highly) recommended that you only pass in the minimal credentials
- needed at any given time. Also, store these credentials in an Ansible Vault using a key that is equal to or greater in strength
- to the 1Password master password.
- - This lookup stores potentially sensitive data from 1Password as Ansible facts.
- Facts are subject to caching if enabled, which means this data could be stored in clear text
- on disk or in a database.
- - Tested with C(op) version 2.7.2
+ service_account_token:
+ version_added: 7.1.0
+ extends_documentation_fragment:
+ - community.general.onepassword
+ - community.general.onepassword.lookup
'''
EXAMPLES = """
@@ -74,24 +54,30 @@ EXAMPLES = """
- name: Retrieve password for HAL when not signed in to 1Password
ansible.builtin.debug:
- var: lookup('community.general.onepassword'
- 'HAL 9000'
- subdomain='Discovery'
+ var: lookup('community.general.onepassword',
+ 'HAL 9000',
+ subdomain='Discovery',
master_password=vault_master_password)
- name: Retrieve password for HAL when never signed in to 1Password
ansible.builtin.debug:
- var: lookup('community.general.onepassword'
- 'HAL 9000'
- subdomain='Discovery'
- master_password=vault_master_password
- username='tweety@acme.com'
+ var: lookup('community.general.onepassword',
+ 'HAL 9000',
+ subdomain='Discovery',
+ master_password=vault_master_password,
+ username='tweety@acme.com',
secret_key=vault_secret_key)
+
+- name: Retrieve password from specific account
+ ansible.builtin.debug:
+ var: lookup('community.general.onepassword',
+ 'HAL 9000',
+ account_id='abc123')
"""
RETURN = """
_raw:
- description: field data requested
+ description: Field data requested.
type: list
elements: str
"""
@@ -102,7 +88,7 @@ import json
import subprocess
from ansible.plugins.lookup import LookupBase
-from ansible.errors import AnsibleLookupError
+from ansible.errors import AnsibleLookupError, AnsibleOptionsError
from ansible.module_utils.common.process import get_bin_path
from ansible.module_utils.common.text.converters import to_bytes, to_text
from ansible.module_utils.six import with_metaclass
@@ -110,15 +96,38 @@ from ansible.module_utils.six import with_metaclass
from ansible_collections.community.general.plugins.module_utils.onepassword import OnePasswordConfig
+def _lower_if_possible(value):
+ """Return the lower case version value, otherwise return the value"""
+ try:
+ return value.lower()
+ except AttributeError:
+ return value
+
+
class OnePassCLIBase(with_metaclass(abc.ABCMeta, object)):
bin = "op"
- def __init__(self, subdomain=None, domain="1password.com", username=None, secret_key=None, master_password=None):
+ def __init__(
+ self,
+ subdomain=None,
+ domain="1password.com",
+ username=None,
+ secret_key=None,
+ master_password=None,
+ service_account_token=None,
+ account_id=None,
+ connect_host=None,
+ connect_token=None,
+ ):
self.subdomain = subdomain
self.domain = domain
self.username = username
self.master_password = master_password
self.secret_key = secret_key
+ self.service_account_token = service_account_token
+ self.account_id = account_id
+ self.connect_host = connect_host
+ self.connect_token = connect_token
self._path = None
self._version = None
@@ -286,7 +295,9 @@ class OnePassCLIv1(OnePassCLIBase):
def assert_logged_in(self):
args = ["get", "account"]
- if self.subdomain:
+ if self.account_id:
+ args.extend(["--account", self.account_id])
+ elif self.subdomain:
account = "{subdomain}.{domain}".format(subdomain=self.subdomain, domain=self.domain)
args.extend(["--account", account])
@@ -295,6 +306,14 @@ class OnePassCLIv1(OnePassCLIBase):
return not bool(rc)
def full_signin(self):
+ if self.connect_host or self.connect_token:
+ raise AnsibleLookupError(
+ "1Password Connect is not available with 1Password CLI version 1. Please use version 2 or later.")
+
+ if self.service_account_token:
+ raise AnsibleLookupError(
+ "1Password CLI version 1 does not support Service Accounts. Please use version 2 or later.")
+
required_params = [
"subdomain",
"username",
@@ -315,6 +334,10 @@ class OnePassCLIv1(OnePassCLIBase):
def get_raw(self, item_id, vault=None, token=None):
args = ["get", "item", item_id]
+
+ if self.account_id:
+ args.extend(["--account", self.account_id])
+
if vault is not None:
args += ["--vault={0}".format(vault)]
@@ -442,6 +465,7 @@ class OnePassCLIv2(OnePassCLIBase):
}
"""
data = json.loads(data_json)
+ field_name = _lower_if_possible(field_name)
for field in data.get("fields", []):
if section_title is None:
# If the field name exists in the section, return that value
@@ -450,28 +474,40 @@ class OnePassCLIv2(OnePassCLIBase):
# If the field name doesn't exist in the section, match on the value of "label"
# then "id" and return "value"
- if field.get("label") == field_name:
- return field["value"]
+ if field.get("label", "").lower() == field_name:
+ return field.get("value", "")
- if field.get("id") == field_name:
- return field["value"]
+ if field.get("id", "").lower() == field_name:
+ return field.get("value", "")
- # Look at the section data and get an indentifier. The value of 'id' is either a unique ID
+ # Look at the section data and get an identifier. The value of 'id' is either a unique ID
# or a human-readable string. If a 'label' field exists, prefer that since
# it is the value visible in the 1Password UI when both 'id' and 'label' exist.
section = field.get("section", {})
- current_section_title = section.get("label", section.get("id"))
+ section_title = _lower_if_possible(section_title)
+
+ current_section_title = section.get("label", section.get("id", "")).lower()
if section_title == current_section_title:
# In the correct section. Check "label" then "id" for the desired field_name
- if field.get("label") == field_name:
- return field["value"]
+ if field.get("label", "").lower() == field_name:
+ return field.get("value", "")
- if field.get("id") == field_name:
- return field["value"]
+ if field.get("id", "").lower() == field_name:
+ return field.get("value", "")
return ""
def assert_logged_in(self):
+ if self.connect_host and self.connect_token:
+ return True
+
+ if self.service_account_token:
+ args = ["whoami"]
+ environment_update = {"OP_SERVICE_ACCOUNT_TOKEN": self.service_account_token}
+ rc, out, err = self._run(args, environment_update=environment_update)
+
+ return not bool(rc)
+
args = ["account", "list"]
if self.subdomain:
account = "{subdomain}.{domain}".format(subdomain=self.subdomain, domain=self.domain)
@@ -484,7 +520,9 @@ class OnePassCLIv2(OnePassCLIBase):
# an interactive prompt. Only run 'op account get' after first listing accounts to see
# if there are any previously configured accounts.
args = ["account", "get"]
- if self.subdomain:
+ if self.account_id:
+ args.extend(["--account", self.account_id])
+ elif self.subdomain:
account = "{subdomain}.{domain}".format(subdomain=self.subdomain, domain=self.domain)
args.extend(["--account", account])
@@ -515,8 +553,28 @@ class OnePassCLIv2(OnePassCLIBase):
def get_raw(self, item_id, vault=None, token=None):
args = ["item", "get", item_id, "--format", "json"]
+
+ if self.account_id:
+ args.extend(["--account", self.account_id])
+
if vault is not None:
args += ["--vault={0}".format(vault)]
+
+ if self.connect_host and self.connect_token:
+ if vault is None:
+ raise AnsibleLookupError("'vault' is required with 1Password Connect")
+ environment_update = {
+ "OP_CONNECT_HOST": self.connect_host,
+ "OP_CONNECT_TOKEN": self.connect_token,
+ }
+ return self._run(args, environment_update=environment_update)
+
+ if self.service_account_token:
+ if vault is None:
+ raise AnsibleLookupError("'vault' is required with 'service_account_token'")
+ environment_update = {"OP_SERVICE_ACCOUNT_TOKEN": self.service_account_token}
+ return self._run(args, environment_update=environment_update)
+
if token is not None:
args += [to_bytes("--session=") + token]
@@ -533,25 +591,37 @@ class OnePassCLIv2(OnePassCLIBase):
class OnePass(object):
- def __init__(self, subdomain=None, domain="1password.com", username=None, secret_key=None, master_password=None):
+ def __init__(self, subdomain=None, domain="1password.com", username=None, secret_key=None, master_password=None,
+ service_account_token=None, account_id=None, connect_host=None, connect_token=None, cli_class=None):
self.subdomain = subdomain
self.domain = domain
self.username = username
self.secret_key = secret_key
self.master_password = master_password
+ self.service_account_token = service_account_token
+ self.account_id = account_id
+ self.connect_host = connect_host
+ self.connect_token = connect_token
self.logged_in = False
self.token = None
self._config = OnePasswordConfig()
- self._cli = self._get_cli_class()
+ self._cli = self._get_cli_class(cli_class)
+
+ if (self.connect_host or self.connect_token) and None in (self.connect_host, self.connect_token):
+ raise AnsibleOptionsError("connect_host and connect_token are required together")
+
+ def _get_cli_class(self, cli_class=None):
+ if cli_class is not None:
+ return cli_class(self.subdomain, self.domain, self.username, self.secret_key, self.master_password, self.service_account_token)
- def _get_cli_class(self):
version = OnePassCLIBase.get_current_version()
for cls in OnePassCLIBase.__subclasses__():
if cls.supports_version == version.split(".")[0]:
try:
- return cls(self.subdomain, self.domain, self.username, self.secret_key, self.master_password)
+ return cls(self.subdomain, self.domain, self.username, self.secret_key, self.master_password, self.service_account_token,
+ self.account_id, self.connect_host, self.connect_token)
except TypeError as e:
raise AnsibleLookupError(e)
@@ -614,8 +684,22 @@ class LookupModule(LookupBase):
username = self.get_option("username")
secret_key = self.get_option("secret_key")
master_password = self.get_option("master_password")
-
- op = OnePass(subdomain, domain, username, secret_key, master_password)
+ service_account_token = self.get_option("service_account_token")
+ account_id = self.get_option("account_id")
+ connect_host = self.get_option("connect_host")
+ connect_token = self.get_option("connect_token")
+
+ op = OnePass(
+ subdomain=subdomain,
+ domain=domain,
+ username=username,
+ secret_key=secret_key,
+ master_password=master_password,
+ service_account_token=service_account_token,
+ account_id=account_id,
+ connect_host=connect_host,
+ connect_token=connect_token,
+ )
op.assert_logged_in()
values = []
diff --git a/ansible_collections/community/general/plugins/lookup/onepassword_doc.py b/ansible_collections/community/general/plugins/lookup/onepassword_doc.py
new file mode 100644
index 000000000..ab24795df
--- /dev/null
+++ b/ansible_collections/community/general/plugins/lookup/onepassword_doc.py
@@ -0,0 +1,104 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2023, Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+DOCUMENTATION = '''
+ name: onepassword_doc
+ author:
+ - Sam Doran (@samdoran)
+ requirements:
+ - C(op) 1Password command line utility version 2 or later.
+ short_description: Fetch documents stored in 1Password
+ version_added: "8.1.0"
+ description:
+ - P(community.general.onepassword_doc#lookup) wraps C(op) command line utility to fetch one or more documents from 1Password.
+ notes:
+ - The document contents are a string exactly as stored in 1Password.
+ - This plugin requires C(op) version 2 or later.
+
+ options:
+ _terms:
+ description: Identifier(s) (case-insensitive UUID or name) of item(s) to retrieve.
+ required: true
+
+ extends_documentation_fragment:
+ - community.general.onepassword
+ - community.general.onepassword.lookup
+'''
+
+EXAMPLES = """
+- name: Retrieve a private key from 1Password
+ ansible.builtin.debug:
+ var: lookup('community.general.onepassword_doc', 'Private key')
+"""
+
+RETURN = """
+ _raw:
+ description: Requested document
+ type: list
+ elements: string
+"""
+
+from ansible_collections.community.general.plugins.lookup.onepassword import OnePass, OnePassCLIv2
+from ansible.errors import AnsibleLookupError
+from ansible.module_utils.common.text.converters import to_bytes
+from ansible.plugins.lookup import LookupBase
+
+
+class OnePassCLIv2Doc(OnePassCLIv2):
+ def get_raw(self, item_id, vault=None, token=None):
+ args = ["document", "get", item_id]
+ if vault is not None:
+ args = [*args, "--vault={0}".format(vault)]
+
+ if self.service_account_token:
+ if vault is None:
+ raise AnsibleLookupError("'vault' is required with 'service_account_token'")
+
+ environment_update = {"OP_SERVICE_ACCOUNT_TOKEN": self.service_account_token}
+ return self._run(args, environment_update=environment_update)
+
+ if token is not None:
+ args = [*args, to_bytes("--session=") + token]
+
+ return self._run(args)
+
+
+class LookupModule(LookupBase):
+ def run(self, terms, variables=None, **kwargs):
+ self.set_options(var_options=variables, direct=kwargs)
+
+ vault = self.get_option("vault")
+ subdomain = self.get_option("subdomain")
+ domain = self.get_option("domain", "1password.com")
+ username = self.get_option("username")
+ secret_key = self.get_option("secret_key")
+ master_password = self.get_option("master_password")
+ service_account_token = self.get_option("service_account_token")
+ account_id = self.get_option("account_id")
+ connect_host = self.get_option("connect_host")
+ connect_token = self.get_option("connect_token")
+
+ op = OnePass(
+ subdomain=subdomain,
+ domain=domain,
+ username=username,
+ secret_key=secret_key,
+ master_password=master_password,
+ service_account_token=service_account_token,
+ account_id=account_id,
+ connect_host=connect_host,
+ connect_token=connect_token,
+ cli_class=OnePassCLIv2Doc,
+ )
+ op.assert_logged_in()
+
+ values = []
+ for term in terms:
+ values.append(op.get_raw(term, vault))
+
+ return values
diff --git a/ansible_collections/community/general/plugins/lookup/onepassword_raw.py b/ansible_collections/community/general/plugins/lookup/onepassword_raw.py
index 9b87a3f61..3eef535a1 100644
--- a/ansible_collections/community/general/plugins/lookup/onepassword_raw.py
+++ b/ansible_collections/community/general/plugins/lookup/onepassword_raw.py
@@ -15,44 +15,23 @@ DOCUMENTATION = '''
- Andrew Zenk (@azenk)
- Sam Doran (@samdoran)
requirements:
- - C(op) 1Password command line utility. See U(https://support.1password.com/command-line/)
- short_description: fetch an entire item from 1Password
+ - C(op) 1Password command line utility
+ short_description: Fetch an entire item from 1Password
description:
- - C(onepassword_raw) wraps C(op) command line utility to fetch an entire item from 1Password
+ - P(community.general.onepassword_raw#lookup) wraps C(op) command line utility to fetch an entire item from 1Password.
options:
_terms:
- description: identifier(s) (UUID, name, or domain; case-insensitive) of item(s) to retrieve.
+ description: Identifier(s) (case-insensitive UUID or name) of item(s) to retrieve.
required: true
- master_password:
- description: The password used to unlock the specified vault.
- aliases: ['vault_password']
- section:
- description: Item section containing the field to retrieve (case-insensitive). If absent will return first match from any section.
- subdomain:
- description: The 1Password subdomain to authenticate against.
+ account_id:
+ version_added: 7.5.0
domain:
- description: Domain of 1Password.
version_added: 6.0.0
- default: '1password.com'
- type: str
- username:
- description: The username used to sign in.
- secret_key:
- description: The secret key used when performing an initial sign in.
- vault:
- description: Vault containing the item to retrieve (case-insensitive). If absent will search all vaults.
- notes:
- - This lookup will use an existing 1Password session if one exists. If not, and you have already
- performed an initial sign in (meaning C(~/.op/config exists)), then only the C(master_password) is required.
- You may optionally specify C(subdomain) in this scenario, otherwise the last used subdomain will be used by C(op).
- - This lookup can perform an initial login by providing C(subdomain), C(username), C(secret_key), and C(master_password).
- - Due to the B(very) sensitive nature of these credentials, it is B(highly) recommended that you only pass in the minimal credentials
- needed at any given time. Also, store these credentials in an Ansible Vault using a key that is equal to or greater in strength
- to the 1Password master password.
- - This lookup stores potentially sensitive data from 1Password as Ansible facts.
- Facts are subject to caching if enabled, which means this data could be stored in clear text
- on disk or in a database.
- - Tested with C(op) version 2.7.0
+ service_account_token:
+ version_added: 7.1.0
+ extends_documentation_fragment:
+ - community.general.onepassword
+ - community.general.onepassword.lookup
'''
EXAMPLES = """
@@ -67,7 +46,7 @@ EXAMPLES = """
RETURN = """
_raw:
- description: field data requested
+ description: Entire item requested.
type: list
elements: dict
"""
@@ -89,8 +68,22 @@ class LookupModule(LookupBase):
username = self.get_option("username")
secret_key = self.get_option("secret_key")
master_password = self.get_option("master_password")
+ service_account_token = self.get_option("service_account_token")
+ account_id = self.get_option("account_id")
+ connect_host = self.get_option("connect_host")
+ connect_token = self.get_option("connect_token")
- op = OnePass(subdomain, domain, username, secret_key, master_password)
+ op = OnePass(
+ subdomain=subdomain,
+ domain=domain,
+ username=username,
+ secret_key=secret_key,
+ master_password=master_password,
+ service_account_token=service_account_token,
+ account_id=account_id,
+ connect_host=connect_host,
+ connect_token=connect_token,
+ )
op.assert_logged_in()
values = []
diff --git a/ansible_collections/community/general/plugins/lookup/passwordstore.py b/ansible_collections/community/general/plugins/lookup/passwordstore.py
index 7e37a3785..7a6fca7a0 100644
--- a/ansible_collections/community/general/plugins/lookup/passwordstore.py
+++ b/ansible_collections/community/general/plugins/lookup/passwordstore.py
@@ -16,7 +16,7 @@ DOCUMENTATION = '''
- Enables Ansible to retrieve, create or update passwords from the passwordstore.org pass utility.
It also retrieves YAML style keys stored as multilines in the passwordfile.
- To avoid problems when accessing multiple secrets at once, add C(auto-expand-secmem) to
- C(~/.gnupg/gpg-agent.conf). Where this is not possible, consider using I(lock=readwrite) instead.
+ C(~/.gnupg/gpg-agent.conf). Where this is not possible, consider using O(lock=readwrite) instead.
options:
_terms:
description: query key.
@@ -24,16 +24,16 @@ DOCUMENTATION = '''
directory:
description:
- The directory of the password store.
- - If I(backend=pass), the default is C(~/.password-store) is used.
- - If I(backend=gopass), then the default is the C(path) field in C(~/.config/gopass/config.yml),
- falling back to C(~/.local/share/gopass/stores/root) if C(path) is not defined in the gopass config.
+ - If O(backend=pass), the default is V(~/.password-store) is used.
+ - If O(backend=gopass), then the default is the C(path) field in C(~/.config/gopass/config.yml),
+ falling back to V(~/.local/share/gopass/stores/root) if C(path) is not defined in the gopass config.
type: path
vars:
- name: passwordstore
env:
- name: PASSWORD_STORE_DIR
create:
- description: Create the password if it does not already exist. Takes precedence over C(missing).
+ description: Create the password if it does not already exist. Takes precedence over O(missing).
type: bool
default: false
overwrite:
@@ -43,7 +43,7 @@ DOCUMENTATION = '''
umask:
description:
- Sets the umask for the created .gpg files. The first octed must be greater than 3 (user readable).
- - Note pass' default value is C('077').
+ - Note pass' default value is V('077').
env:
- name: PASSWORD_STORE_UMASK
version_added: 1.3.0
@@ -52,7 +52,7 @@ DOCUMENTATION = '''
type: bool
default: false
subkey:
- description: Return a specific subkey of the password. When set to C(password), always returns the first line.
+ description: Return a specific subkey of the password. When set to V(password), always returns the first line.
type: str
default: password
userpass:
@@ -63,7 +63,7 @@ DOCUMENTATION = '''
type: integer
default: 16
backup:
- description: Used with C(overwrite=true). Backup the previous password in a subkey.
+ description: Used with O(overwrite=true). Backup the previous password in a subkey.
type: bool
default: false
nosymbols:
@@ -73,10 +73,10 @@ DOCUMENTATION = '''
missing:
description:
- List of preference about what to do if the password file is missing.
- - If I(create=true), the value for this option is ignored and assumed to be C(create).
- - If set to C(error), the lookup will error out if the passname does not exist.
- - If set to C(create), the passname will be created with the provided length I(length) if it does not exist.
- - If set to C(empty) or C(warn), will return a C(none) in case the passname does not exist.
+ - If O(create=true), the value for this option is ignored and assumed to be V(create).
+ - If set to V(error), the lookup will error out if the passname does not exist.
+ - If set to V(create), the passname will be created with the provided length O(length) if it does not exist.
+ - If set to V(empty) or V(warn), will return a V(none) in case the passname does not exist.
When using C(lookup) and not C(query), this will be translated to an empty string.
version_added: 3.1.0
type: str
@@ -89,9 +89,9 @@ DOCUMENTATION = '''
lock:
description:
- How to synchronize operations.
- - The default of C(write) only synchronizes write operations.
- - C(readwrite) synchronizes all operations (including read). This makes sure that gpg-agent is never called in parallel.
- - C(none) does not do any synchronization.
+ - The default of V(write) only synchronizes write operations.
+ - V(readwrite) synchronizes all operations (including read). This makes sure that gpg-agent is never called in parallel.
+ - V(none) does not do any synchronization.
ini:
- section: passwordstore_lookup
key: lock
@@ -104,8 +104,8 @@ DOCUMENTATION = '''
version_added: 4.5.0
locktimeout:
description:
- - Lock timeout applied when I(lock) is not C(none).
- - Time with a unit suffix, C(s), C(m), C(h) for seconds, minutes, and hours, respectively. For example, C(900s) equals C(15m).
+ - Lock timeout applied when O(lock) is not V(none).
+ - Time with a unit suffix, V(s), V(m), V(h) for seconds, minutes, and hours, respectively. For example, V(900s) equals V(15m).
- Correlates with C(pinentry-timeout) in C(~/.gnupg/gpg-agent.conf), see C(man gpg-agent) for details.
ini:
- section: passwordstore_lookup
@@ -116,8 +116,8 @@ DOCUMENTATION = '''
backend:
description:
- Specify which backend to use.
- - Defaults to C(pass), passwordstore.org's original pass utility.
- - C(gopass) support is incomplete.
+ - Defaults to V(pass), passwordstore.org's original pass utility.
+ - V(gopass) support is incomplete.
ini:
- section: passwordstore_lookup
key: backend
@@ -129,6 +129,16 @@ DOCUMENTATION = '''
- pass
- gopass
version_added: 5.2.0
+ timestamp:
+ description: Add the password generation information to the end of the file.
+ type: bool
+ default: true
+ version_added: 8.1.0
+ preserve:
+ description: Include the old (edited) password inside the pass file.
+ type: bool
+ default: true
+ version_added: 8.1.0
notes:
- The lookup supports passing all options as lookup parameters since community.general 6.0.0.
'''
@@ -386,11 +396,13 @@ class LookupModule(LookupBase):
# generate new password, insert old lines from current result and return new password
newpass = self.get_newpass()
datetime = time.strftime("%d/%m/%Y %H:%M:%S")
- msg = newpass + '\n'
- if self.passoutput[1:]:
- msg += '\n'.join(self.passoutput[1:]) + '\n'
- if self.paramvals['backup']:
- msg += "lookup_pass: old password was {0} (Updated on {1})\n".format(self.password, datetime)
+ msg = newpass
+ if self.paramvals['preserve'] or self.paramvals['timestamp']:
+ msg += '\n'
+ if self.paramvals['preserve'] and self.passoutput[1:]:
+ msg += '\n'.join(self.passoutput[1:]) + '\n'
+ if self.paramvals['timestamp'] and self.paramvals['backup']:
+ msg += "lookup_pass: old password was {0} (Updated on {1})\n".format(self.password, datetime)
try:
check_output2([self.pass_cmd, 'insert', '-f', '-m', self.passname], input=msg, env=self.env)
except (subprocess.CalledProcessError) as e:
@@ -402,7 +414,9 @@ class LookupModule(LookupBase):
# use pwgen to generate the password and insert values with pass -m
newpass = self.get_newpass()
datetime = time.strftime("%d/%m/%Y %H:%M:%S")
- msg = newpass + '\n' + "lookup_pass: First generated by ansible on {0}\n".format(datetime)
+ msg = newpass
+ if self.paramvals['timestamp']:
+ msg += '\n' + "lookup_pass: First generated by ansible on {0}\n".format(datetime)
try:
check_output2([self.pass_cmd, 'insert', '-f', '-m', self.passname], input=msg, env=self.env)
except (subprocess.CalledProcessError) as e:
@@ -465,6 +479,8 @@ class LookupModule(LookupBase):
'backup': self.get_option('backup'),
'missing': self.get_option('missing'),
'umask': self.get_option('umask'),
+ 'timestamp': self.get_option('timestamp'),
+ 'preserve': self.get_option('preserve'),
}
def run(self, terms, variables, **kwargs):
diff --git a/ansible_collections/community/general/plugins/lookup/random_string.py b/ansible_collections/community/general/plugins/lookup/random_string.py
index 199aa1396..d3b29629d 100644
--- a/ansible_collections/community/general/plugins/lookup/random_string.py
+++ b/ansible_collections/community/general/plugins/lookup/random_string.py
@@ -16,6 +16,8 @@ DOCUMENTATION = r"""
version_added: '3.2.0'
description:
- Generates random string based upon the given constraints.
+ - Uses L(random.SystemRandom,https://docs.python.org/3/library/random.html#random.SystemRandom),
+ so should be strong enough for cryptographic purposes.
options:
length:
description: The length of the string.
@@ -42,25 +44,25 @@ DOCUMENTATION = r"""
- Special characters are taken from Python standard library C(string).
See L(the documentation of string.punctuation,https://docs.python.org/3/library/string.html#string.punctuation)
for which characters will be used.
- - The choice of special characters can be changed to setting I(override_special).
+ - The choice of special characters can be changed to setting O(override_special).
default: true
type: bool
min_numeric:
description:
- Minimum number of numeric characters in the string.
- - If set, overrides I(numbers=false).
+ - If set, overrides O(numbers=false).
default: 0
type: int
min_upper:
description:
- Minimum number of uppercase alphabets in the string.
- - If set, overrides I(upper=false).
+ - If set, overrides O(upper=false).
default: 0
type: int
min_lower:
description:
- Minimum number of lowercase alphabets in the string.
- - If set, overrides I(lower=false).
+ - If set, overrides O(lower=false).
default: 0
type: int
min_special:
@@ -70,14 +72,27 @@ DOCUMENTATION = r"""
type: int
override_special:
description:
- - Overide a list of special characters to use in the string.
- - If set I(min_special) should be set to a non-default value.
+ - Override a list of special characters to use in the string.
+ - If set O(min_special) should be set to a non-default value.
type: str
override_all:
description:
- - Override all values of I(numbers), I(upper), I(lower), and I(special) with
+ - Override all values of O(numbers), O(upper), O(lower), and O(special) with
the given list of characters.
type: str
+ ignore_similar_chars:
+ description:
+ - Ignore similar characters, such as V(l) and V(1), or V(O) and V(0).
+ - These characters can be configured in O(similar_chars).
+ default: false
+ type: bool
+ version_added: 7.5.0
+ similar_chars:
+ description:
+ - Override a list of characters not to be use in the string.
+ default: "il1LoO0"
+ type: str
+ version_added: 7.5.0
base64:
description:
- Returns base64 encoded string.
@@ -101,7 +116,7 @@ EXAMPLES = r"""
var: lookup('community.general.random_string', base64=True)
# Example result: ['NHZ6eWN5Qk0=']
-- name: Generate a random string with 1 lower, 1 upper, 1 number and 1 special char (atleast)
+- name: Generate a random string with 1 lower, 1 upper, 1 number and 1 special char (at least)
ansible.builtin.debug:
var: lookup('community.general.random_string', min_lower=1, min_upper=1, min_special=1, min_numeric=1)
# Example result: ['&Qw2|E[-']
@@ -171,9 +186,17 @@ class LookupModule(LookupBase):
length = self.get_option("length")
base64_flag = self.get_option("base64")
override_all = self.get_option("override_all")
+ ignore_similar_chars = self.get_option("ignore_similar_chars")
+ similar_chars = self.get_option("similar_chars")
values = ""
available_chars_set = ""
+ if ignore_similar_chars:
+ number_chars = "".join([sc for sc in number_chars if sc not in similar_chars])
+ lower_chars = "".join([sc for sc in lower_chars if sc not in similar_chars])
+ upper_chars = "".join([sc for sc in upper_chars if sc not in similar_chars])
+ special_chars = "".join([sc for sc in special_chars if sc not in similar_chars])
+
if override_all:
# Override all the values
available_chars_set = override_all
diff --git a/ansible_collections/community/general/plugins/lookup/revbitspss.py b/ansible_collections/community/general/plugins/lookup/revbitspss.py
index 552970804..e4118e89e 100644
--- a/ansible_collections/community/general/plugins/lookup/revbitspss.py
+++ b/ansible_collections/community/general/plugins/lookup/revbitspss.py
@@ -25,7 +25,7 @@ options:
elements: string
base_url:
description:
- - This will be the base URL of the server, for example C(https://server-url-here).
+ - This will be the base URL of the server, for example V(https://server-url-here).
required: true
type: string
api_key:
@@ -100,7 +100,7 @@ class LookupModule(LookupBase):
result = []
for term in terms:
try:
- display.vvv(u"Secret Server lookup of Secret with ID %s" % term)
+ display.vvv("Secret Server lookup of Secret with ID %s" % term)
result.append({term: secret_server.get_pam_secret(term)})
except Exception as error:
raise AnsibleError("Secret Server lookup failure: %s" % error.message)
diff --git a/ansible_collections/community/general/plugins/lookup/tss.py b/ansible_collections/community/general/plugins/lookup/tss.py
index 935b5f4b4..80105ff71 100644
--- a/ansible_collections/community/general/plugins/lookup/tss.py
+++ b/ansible_collections/community/general/plugins/lookup/tss.py
@@ -13,10 +13,10 @@ short_description: Get secrets from Thycotic Secret Server
version_added: 1.0.0
description:
- Uses the Thycotic Secret Server Python SDK to get Secrets from Secret
- Server using token authentication with I(username) and I(password) on
- the REST API at I(base_url).
+ Server using token authentication with O(username) and O(password) on
+ the REST API at O(base_url).
- When using self-signed certificates the environment variable
- C(REQUESTS_CA_BUNDLE) can be set to a file containing the trusted certificates
+ E(REQUESTS_CA_BUNDLE) can be set to a file containing the trusted certificates
(in C(.pem) format).
- For example, C(export REQUESTS_CA_BUNDLE='/etc/ssl/certs/ca-bundle.trust.crt').
requirements:
@@ -26,8 +26,32 @@ options:
description: The integer ID of the secret.
required: true
type: int
+ secret_path:
+ description: Indicate a full path of secret including folder and secret name when the secret ID is set to 0.
+ required: false
+ type: str
+ version_added: 7.2.0
+ fetch_secret_ids_from_folder:
+ description:
+ - Boolean flag which indicates whether secret ids are in a folder is fetched by folder ID or not.
+ - V(true) then the terms will be considered as a folder IDs. Otherwise (default), they are considered as secret IDs.
+ required: false
+ type: bool
+ version_added: 7.1.0
+ fetch_attachments:
+ description:
+ - Boolean flag which indicates whether attached files will get downloaded or not.
+ - The download will only happen if O(file_download_path) has been provided.
+ required: false
+ type: bool
+ version_added: 7.0.0
+ file_download_path:
+ description: Indicate the file attachment download location.
+ required: false
+ type: path
+ version_added: 7.0.0
base_url:
- description: The base URL of the server, e.g. C(https://localhost/SecretServer).
+ description: The base URL of the server, for example V(https://localhost/SecretServer).
env:
- name: TSS_BASE_URL
ini:
@@ -44,7 +68,7 @@ options:
password:
description:
- The password associated with the supplied username.
- - Required when I(token) is not provided.
+ - Required when O(token) is not provided.
env:
- name: TSS_PASSWORD
ini:
@@ -54,7 +78,7 @@ options:
default: ""
description:
- The domain with which to request the OAuth2 Access Grant.
- - Optional when I(token) is not provided.
+ - Optional when O(token) is not provided.
- Requires C(python-tss-sdk) version 1.0.0 or greater.
env:
- name: TSS_DOMAIN
@@ -66,7 +90,7 @@ options:
token:
description:
- Existing token for Thycotic authorizer.
- - If provided, I(username) and I(password) are not needed.
+ - If provided, O(username) and O(password) are not needed.
- Requires C(python-tss-sdk) version 1.0.0 or greater.
env:
- name: TSS_TOKEN
@@ -157,39 +181,101 @@ EXAMPLES = r"""
tasks:
- ansible.builtin.debug:
msg: the password is {{ secret_password }}
+
+# Private key stores into certificate file which is attached with secret.
+# If fetch_attachments=True then private key file will be download on specified path
+# and file content will display in debug message.
+- hosts: localhost
+ vars:
+ secret: >-
+ {{
+ lookup(
+ 'community.general.tss',
+ 102,
+ fetch_attachments=True,
+ file_download_path='/home/certs',
+ base_url='https://secretserver.domain.com/SecretServer/',
+ token='thycotic_access_token'
+ )
+ }}
+ tasks:
+ - ansible.builtin.debug:
+ msg: >
+ the private key is {{
+ (secret['items']
+ | items2dict(key_name='slug',
+ value_name='itemValue'))['private-key']
+ }}
+
+# If fetch_secret_ids_from_folder=true then secret IDs are in a folder is fetched based on folder ID
+- hosts: localhost
+ vars:
+ secret: >-
+ {{
+ lookup(
+ 'community.general.tss',
+ 102,
+ fetch_secret_ids_from_folder=true,
+ base_url='https://secretserver.domain.com/SecretServer/',
+ token='thycotic_access_token'
+ )
+ }}
+ tasks:
+ - ansible.builtin.debug:
+ msg: >
+ the secret id's are {{
+ secret
+ }}
+
+# If secret ID is 0 and secret_path has value then secret is fetched by secret path
+- hosts: localhost
+ vars:
+ secret: >-
+ {{
+ lookup(
+ 'community.general.tss',
+ 0,
+ secret_path='\folderName\secretName'
+ base_url='https://secretserver.domain.com/SecretServer/',
+ username='user.name',
+ password='password'
+ )
+ }}
+ tasks:
+ - ansible.builtin.debug:
+ msg: >
+ the password is {{
+ (secret['items']
+ | items2dict(key_name='slug',
+ value_name='itemValue'))['password']
+ }}
"""
import abc
-
+import os
from ansible.errors import AnsibleError, AnsibleOptionsError
from ansible.module_utils import six
from ansible.plugins.lookup import LookupBase
from ansible.utils.display import Display
try:
- from thycotic.secrets.server import SecretServer, SecretServerError
+ from delinea.secrets.server import SecretServer, SecretServerError, PasswordGrantAuthorizer, DomainPasswordGrantAuthorizer, AccessTokenAuthorizer
HAS_TSS_SDK = True
+ HAS_DELINEA_SS_SDK = True
+ HAS_TSS_AUTHORIZER = True
except ImportError:
try:
- from delinea.secrets.server import SecretServer, SecretServerError
+ from thycotic.secrets.server import SecretServer, SecretServerError, PasswordGrantAuthorizer, DomainPasswordGrantAuthorizer, AccessTokenAuthorizer
HAS_TSS_SDK = True
+ HAS_DELINEA_SS_SDK = False
+ HAS_TSS_AUTHORIZER = True
except ImportError:
SecretServer = None
SecretServerError = None
HAS_TSS_SDK = False
-
-try:
- from thycotic.secrets.server import PasswordGrantAuthorizer, DomainPasswordGrantAuthorizer, AccessTokenAuthorizer
-
- HAS_TSS_AUTHORIZER = True
-except ImportError:
- try:
- from delinea.secrets.server import PasswordGrantAuthorizer, DomainPasswordGrantAuthorizer, AccessTokenAuthorizer
-
- HAS_TSS_AUTHORIZER = True
- except ImportError:
+ HAS_DELINEA_SS_SDK = False
PasswordGrantAuthorizer = None
DomainPasswordGrantAuthorizer = None
AccessTokenAuthorizer = None
@@ -211,13 +297,49 @@ class TSSClient(object):
else:
return TSSClientV0(**server_parameters)
- def get_secret(self, term):
+ def get_secret(self, term, secret_path, fetch_file_attachments, file_download_path):
display.debug("tss_lookup term: %s" % term)
-
secret_id = self._term_to_secret_id(term)
- display.vvv(u"Secret Server lookup of Secret with ID %d" % secret_id)
+ if secret_id == 0 and secret_path:
+ fetch_secret_by_path = True
+ display.vvv(u"Secret Server lookup of Secret with path %s" % secret_path)
+ else:
+ fetch_secret_by_path = False
+ display.vvv(u"Secret Server lookup of Secret with ID %d" % secret_id)
+
+ if fetch_file_attachments:
+ if fetch_secret_by_path:
+ obj = self._client.get_secret_by_path(secret_path, fetch_file_attachments)
+ else:
+ obj = self._client.get_secret(secret_id, fetch_file_attachments)
+ for i in obj['items']:
+ if file_download_path and os.path.isdir(file_download_path):
+ if i['isFile']:
+ try:
+ file_content = i['itemValue'].content
+ with open(os.path.join(file_download_path, str(obj['id']) + "_" + i['slug']), "wb") as f:
+ f.write(file_content)
+ except ValueError:
+ raise AnsibleOptionsError("Failed to download {0}".format(str(i['slug'])))
+ except AttributeError:
+ display.warning("Could not read file content for {0}".format(str(i['slug'])))
+ finally:
+ i['itemValue'] = "*** Not Valid For Display ***"
+ else:
+ raise AnsibleOptionsError("File download path does not exist")
+ return obj
+ else:
+ if fetch_secret_by_path:
+ return self._client.get_secret_by_path(secret_path, False)
+ else:
+ return self._client.get_secret_json(secret_id)
+
+ def get_secret_ids_by_folderid(self, term):
+ display.debug("tss_lookup term: %s" % term)
+ folder_id = self._term_to_folder_id(term)
+ display.vvv(u"Secret Server lookup of Secret id's with Folder ID %d" % folder_id)
- return self._client.get_secret_json(secret_id)
+ return self._client.get_secret_ids_by_folderid(folder_id)
@staticmethod
def _term_to_secret_id(term):
@@ -226,6 +348,13 @@ class TSSClient(object):
except ValueError:
raise AnsibleOptionsError("Secret ID must be an integer")
+ @staticmethod
+ def _term_to_folder_id(term):
+ try:
+ return int(term)
+ except ValueError:
+ raise AnsibleOptionsError("Folder ID must be an integer")
+
class TSSClientV0(TSSClient):
def __init__(self, **server_parameters):
@@ -294,6 +423,20 @@ class LookupModule(LookupBase):
)
try:
- return [tss.get_secret(term) for term in terms]
+ if self.get_option("fetch_secret_ids_from_folder"):
+ if HAS_DELINEA_SS_SDK:
+ return [tss.get_secret_ids_by_folderid(term) for term in terms]
+ else:
+ raise AnsibleError("latest python-tss-sdk must be installed to use this plugin")
+ else:
+ return [
+ tss.get_secret(
+ term,
+ self.get_option("secret_path"),
+ self.get_option("fetch_attachments"),
+ self.get_option("file_download_path"),
+ )
+ for term in terms
+ ]
except SecretServerError as error:
raise AnsibleError("Secret Server lookup failure: %s" % error.message)
diff --git a/ansible_collections/community/general/plugins/module_utils/cmd_runner.py b/ansible_collections/community/general/plugins/module_utils/cmd_runner.py
index 21d61a6a5..864987120 100644
--- a/ansible_collections/community/general/plugins/module_utils/cmd_runner.py
+++ b/ansible_collections/community/general/plugins/module_utils/cmd_runner.py
@@ -6,6 +6,7 @@
from __future__ import absolute_import, division, print_function
__metaclass__ = type
+import os
from functools import wraps
from ansible.module_utils.common.collections import is_sequence
@@ -147,6 +148,11 @@ class _Format(object):
@staticmethod
def as_default_type(_type, arg="", ignore_none=None):
+ #
+ # DEPRECATION: This method is deprecated and will be removed in community.general 10.0.0
+ #
+ # Instead of using the implicit formats provided here, use the explicit necessary format method.
+ #
fmt = _Format
if _type == "dict":
return fmt.as_func(lambda d: ["--{0}={1}".format(*a) for a in iteritems(d)], ignore_none=ignore_none)
@@ -199,11 +205,16 @@ class CmdRunner(object):
environ_update = {}
self.environ_update = environ_update
- self.command[0] = module.get_bin_path(self.command[0], opt_dirs=path_prefix, required=True)
+ _cmd = self.command[0]
+ self.command[0] = _cmd if (os.path.isabs(_cmd) or '/' in _cmd) else module.get_bin_path(_cmd, opt_dirs=path_prefix, required=True)
for mod_param_name, spec in iteritems(module.argument_spec):
if mod_param_name not in self.arg_formats:
- self.arg_formats[mod_param_name] = _Format.as_default_type(spec['type'], mod_param_name)
+ self.arg_formats[mod_param_name] = _Format.as_default_type(spec.get('type', 'str'), mod_param_name)
+
+ @property
+ def binary(self):
+ return self.command[0]
def __call__(self, args_order=None, output_process=None, ignore_value_none=True, check_mode_skip=False, check_mode_return=None, **kwargs):
if output_process is None:
@@ -309,11 +320,3 @@ class _CmdRunnerContext(object):
cmd_runner_fmt = _Format()
-
-#
-# The fmt form is deprecated and will be removed in community.general 7.0.0
-# Please use:
-# cmd_runner_fmt
-# Or, to retain the same effect, use:
-# from ansible_collections.community.general.plugins.module_utils.cmd_runner import cmd_runner_fmt as fmt
-fmt = cmd_runner_fmt
diff --git a/ansible_collections/community/general/plugins/module_utils/consul.py b/ansible_collections/community/general/plugins/module_utils/consul.py
new file mode 100644
index 000000000..68c1a130b
--- /dev/null
+++ b/ansible_collections/community/general/plugins/module_utils/consul.py
@@ -0,0 +1,321 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2022, Håkon Lerring
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+import copy
+import json
+
+from ansible.module_utils.six.moves.urllib import error as urllib_error
+from ansible.module_utils.six.moves.urllib.parse import urlencode
+from ansible.module_utils.urls import open_url
+
+
+def get_consul_url(configuration):
+ return "%s://%s:%s/v1" % (
+ configuration.scheme,
+ configuration.host,
+ configuration.port,
+ )
+
+
+def get_auth_headers(configuration):
+ if configuration.token is None:
+ return {}
+ else:
+ return {"X-Consul-Token": configuration.token}
+
+
+class RequestError(Exception):
+ def __init__(self, status, response_data=None):
+ self.status = status
+ self.response_data = response_data
+
+ def __str__(self):
+ if self.response_data is None:
+ # self.status is already the message (backwards compat)
+ return self.status
+ return "HTTP %d: %s" % (self.status, self.response_data)
+
+
+def handle_consul_response_error(response):
+ if 400 <= response.status_code < 600:
+ raise RequestError("%d %s" % (response.status_code, response.content))
+
+
+AUTH_ARGUMENTS_SPEC = dict(
+ host=dict(default="localhost"),
+ port=dict(type="int", default=8500),
+ scheme=dict(default="http"),
+ validate_certs=dict(type="bool", default=True),
+ token=dict(no_log=True),
+ ca_path=dict(),
+)
+
+
+def camel_case_key(key):
+ parts = []
+ for part in key.split("_"):
+ if part in {"id", "ttl", "jwks", "jwt", "oidc", "iam", "sts"}:
+ parts.append(part.upper())
+ else:
+ parts.append(part.capitalize())
+ return "".join(parts)
+
+
+STATE_PARAMETER = "state"
+STATE_PRESENT = "present"
+STATE_ABSENT = "absent"
+
+OPERATION_READ = "read"
+OPERATION_CREATE = "create"
+OPERATION_UPDATE = "update"
+OPERATION_DELETE = "remove"
+
+
+def _normalize_params(params, arg_spec):
+ final_params = {}
+ for k, v in params.items():
+ if k not in arg_spec: # Alias
+ continue
+ spec = arg_spec[k]
+ if (
+ spec.get("type") == "list"
+ and spec.get("elements") == "dict"
+ and spec.get("options")
+ and v
+ ):
+ v = [_normalize_params(d, spec["options"]) for d in v]
+ elif spec.get("type") == "dict" and spec.get("options") and v:
+ v = _normalize_params(v, spec["options"])
+ final_params[k] = v
+ return final_params
+
+
+class _ConsulModule:
+ """Base class for Consul modules.
+
+ This class is considered private, till the API is fully fleshed out.
+ As such backwards incompatible changes can occur even in bugfix releases.
+ """
+
+ api_endpoint = None # type: str
+ unique_identifier = None # type: str
+ result_key = None # type: str
+ create_only_fields = set()
+ params = {}
+
+ def __init__(self, module):
+ self._module = module
+ self.params = _normalize_params(module.params, module.argument_spec)
+ self.api_params = {
+ k: camel_case_key(k)
+ for k in self.params
+ if k not in STATE_PARAMETER and k not in AUTH_ARGUMENTS_SPEC
+ }
+
+ def execute(self):
+ obj = self.read_object()
+
+ changed = False
+ diff = {}
+ if self.params[STATE_PARAMETER] == STATE_PRESENT:
+ obj_from_module = self.module_to_obj(obj is not None)
+ if obj is None:
+ operation = OPERATION_CREATE
+ new_obj = self.create_object(obj_from_module)
+ diff = {"before": {}, "after": new_obj}
+ changed = True
+ else:
+ operation = OPERATION_UPDATE
+ if self._needs_update(obj, obj_from_module):
+ new_obj = self.update_object(obj, obj_from_module)
+ diff = {"before": obj, "after": new_obj}
+ changed = True
+ else:
+ new_obj = obj
+ elif self.params[STATE_PARAMETER] == STATE_ABSENT:
+ operation = OPERATION_DELETE
+ if obj is not None:
+ self.delete_object(obj)
+ changed = True
+ diff = {"before": obj, "after": {}}
+ else:
+ diff = {"before": {}, "after": {}}
+ new_obj = None
+ else:
+ raise RuntimeError("Unknown state supplied.")
+
+ result = {"changed": changed}
+ if changed:
+ result["operation"] = operation
+ if self._module._diff:
+ result["diff"] = diff
+ if self.result_key:
+ result[self.result_key] = new_obj
+ self._module.exit_json(**result)
+
+ def module_to_obj(self, is_update):
+ obj = {}
+ for k, v in self.params.items():
+ result = self.map_param(k, v, is_update)
+ if result:
+ obj[result[0]] = result[1]
+ return obj
+
+ def map_param(self, k, v, is_update):
+ def helper(item):
+ return {camel_case_key(k): v for k, v in item.items()}
+
+ def needs_camel_case(k):
+ spec = self._module.argument_spec[k]
+ return (
+ spec.get("type") == "list"
+ and spec.get("elements") == "dict"
+ and spec.get("options")
+ ) or (spec.get("type") == "dict" and spec.get("options"))
+
+ if k in self.api_params and v is not None:
+ if isinstance(v, dict) and needs_camel_case(k):
+ v = helper(v)
+ elif isinstance(v, (list, tuple)) and needs_camel_case(k):
+ v = [helper(i) for i in v]
+ if is_update and k in self.create_only_fields:
+ return
+ return camel_case_key(k), v
+
+ def _needs_update(self, api_obj, module_obj):
+ api_obj = copy.deepcopy(api_obj)
+ module_obj = copy.deepcopy(module_obj)
+ return self.needs_update(api_obj, module_obj)
+
+ def needs_update(self, api_obj, module_obj):
+ for k, v in module_obj.items():
+ if k not in api_obj:
+ return True
+ if api_obj[k] != v:
+ return True
+ return False
+
+ def prepare_object(self, existing, obj):
+ operational_attributes = {"CreateIndex", "CreateTime", "Hash", "ModifyIndex"}
+ existing = {
+ k: v for k, v in existing.items() if k not in operational_attributes
+ }
+ for k, v in obj.items():
+ existing[k] = v
+ return existing
+
+ def endpoint_url(self, operation, identifier=None):
+ if operation == OPERATION_CREATE:
+ return self.api_endpoint
+ elif identifier:
+ return "/".join([self.api_endpoint, identifier])
+ raise RuntimeError("invalid arguments passed")
+
+ def read_object(self):
+ url = self.endpoint_url(OPERATION_READ, self.params.get(self.unique_identifier))
+ try:
+ return self.get(url)
+ except RequestError as e:
+ if e.status == 404:
+ return
+ elif e.status == 403 and b"ACL not found" in e.response_data:
+ return
+ raise
+
+ def create_object(self, obj):
+ if self._module.check_mode:
+ return obj
+ else:
+ return self.put(self.api_endpoint, data=self.prepare_object({}, obj))
+
+ def update_object(self, existing, obj):
+ url = self.endpoint_url(
+ OPERATION_UPDATE, existing.get(camel_case_key(self.unique_identifier))
+ )
+ merged_object = self.prepare_object(existing, obj)
+ if self._module.check_mode:
+ return merged_object
+ else:
+ return self.put(url, data=merged_object)
+
+ def delete_object(self, obj):
+ if self._module.check_mode:
+ return {}
+ else:
+ url = self.endpoint_url(
+ OPERATION_DELETE, obj.get(camel_case_key(self.unique_identifier))
+ )
+ return self.delete(url)
+
+ def _request(self, method, url_parts, data=None, params=None):
+ module_params = self.params
+
+ if not isinstance(url_parts, (tuple, list)):
+ url_parts = [url_parts]
+ if params:
+ # Remove values that are None
+ params = {k: v for k, v in params.items() if v is not None}
+
+ ca_path = module_params.get("ca_path")
+ base_url = "%s://%s:%s/v1" % (
+ module_params["scheme"],
+ module_params["host"],
+ module_params["port"],
+ )
+ url = "/".join([base_url] + list(url_parts))
+
+ headers = {}
+ token = self.params.get("token")
+ if token:
+ headers["X-Consul-Token"] = token
+
+ try:
+ if data is not None:
+ data = json.dumps(data)
+ headers["Content-Type"] = "application/json"
+ if params:
+ url = "%s?%s" % (url, urlencode(params))
+ response = open_url(
+ url,
+ method=method,
+ data=data,
+ headers=headers,
+ validate_certs=module_params["validate_certs"],
+ ca_path=ca_path,
+ )
+ response_data = response.read()
+ status = (
+ response.status if hasattr(response, "status") else response.getcode()
+ )
+
+ except urllib_error.URLError as e:
+ if isinstance(e, urllib_error.HTTPError):
+ status = e.code
+ response_data = e.fp.read()
+ else:
+ self._module.fail_json(
+ msg="Could not connect to consul agent at %s:%s, error was %s"
+ % (module_params["host"], module_params["port"], str(e))
+ )
+ raise
+
+ if 400 <= status < 600:
+ raise RequestError(status, response_data)
+
+ return json.loads(response_data)
+
+ def get(self, url_parts, **kwargs):
+ return self._request("GET", url_parts, **kwargs)
+
+ def put(self, url_parts, **kwargs):
+ return self._request("PUT", url_parts, **kwargs)
+
+ def delete(self, url_parts, **kwargs):
+ return self._request("DELETE", url_parts, **kwargs)
diff --git a/ansible_collections/community/general/plugins/module_utils/dimensiondata.py b/ansible_collections/community/general/plugins/module_utils/dimensiondata.py
index 0300f6c1e..a5201f7de 100644
--- a/ansible_collections/community/general/plugins/module_utils/dimensiondata.py
+++ b/ansible_collections/community/general/plugins/module_utils/dimensiondata.py
@@ -39,7 +39,7 @@ except ImportError:
LIBCLOUD_IMP_ERR = traceback.format_exc()
HAS_LIBCLOUD = False
-# MCP 2.x version patten for location (datacenter) names.
+# MCP 2.x version pattern for location (datacenter) names.
#
# Note that this is not a totally reliable way of determining MCP version.
# Unfortunately, libcloud's NodeLocation currently makes no provision for extended properties.
diff --git a/ansible_collections/community/general/plugins/module_utils/gio_mime.py b/ansible_collections/community/general/plugins/module_utils/gio_mime.py
new file mode 100644
index 000000000..e01709487
--- /dev/null
+++ b/ansible_collections/community/general/plugins/module_utils/gio_mime.py
@@ -0,0 +1,32 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2022, Alexei Znamensky <russoz@gmail.com>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+from ansible_collections.community.general.plugins.module_utils.cmd_runner import CmdRunner, cmd_runner_fmt
+
+
+def gio_mime_runner(module, **kwargs):
+ return CmdRunner(
+ module,
+ command=['gio', 'mime'],
+ arg_formats=dict(
+ mime_type=cmd_runner_fmt.as_list(),
+ handler=cmd_runner_fmt.as_list(),
+ ),
+ **kwargs
+ )
+
+
+def gio_mime_get(runner, mime_type):
+ def process(rc, out, err):
+ if err.startswith("No default applications for"):
+ return None
+ out = out.splitlines()[0]
+ return out.split()[-1]
+
+ with runner("mime_type", output_process=process) as ctx:
+ return ctx.run(mime_type=mime_type)
diff --git a/ansible_collections/community/general/plugins/module_utils/gitlab.py b/ansible_collections/community/general/plugins/module_utils/gitlab.py
index 7cb59e4c2..f9872b877 100644
--- a/ansible_collections/community/general/plugins/module_utils/gitlab.py
+++ b/ansible_collections/community/general/plugins/module_utils/gitlab.py
@@ -10,6 +10,7 @@ __metaclass__ = type
from ansible.module_utils.basic import missing_required_lib
from ansible.module_utils.common.text.converters import to_native
+from ansible.module_utils.six import integer_types, string_types
from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
@@ -20,19 +21,35 @@ except ImportError:
import traceback
+
+def _determine_list_all_kwargs(version):
+ gitlab_version = LooseVersion(version)
+ if gitlab_version >= LooseVersion('4.0.0'):
+ # 4.0.0 removed 'as_list'
+ return {'iterator': True, 'per_page': 100}
+ elif gitlab_version >= LooseVersion('3.7.0'):
+ # 3.7.0 added 'get_all'
+ return {'as_list': False, 'get_all': True, 'per_page': 100}
+ else:
+ return {'as_list': False, 'all': True, 'per_page': 100}
+
+
GITLAB_IMP_ERR = None
try:
import gitlab
import requests
HAS_GITLAB_PACKAGE = True
+ list_all_kwargs = _determine_list_all_kwargs(gitlab.__version__)
except Exception:
gitlab = None
GITLAB_IMP_ERR = traceback.format_exc()
HAS_GITLAB_PACKAGE = False
+ list_all_kwargs = {}
def auth_argument_spec(spec=None):
arg_spec = (dict(
+ ca_path=dict(type='str'),
api_token=dict(type='str', no_log=True),
api_oauth_token=dict(type='str', no_log=True),
api_job_token=dict(type='str', no_log=True),
@@ -57,11 +74,11 @@ def find_project(gitlab_instance, identifier):
def find_group(gitlab_instance, identifier):
try:
- project = gitlab_instance.groups.get(identifier)
+ group = gitlab_instance.groups.get(identifier)
except Exception as e:
return None
- return project
+ return group
def ensure_gitlab_package(module):
@@ -73,33 +90,36 @@ def ensure_gitlab_package(module):
def gitlab_authentication(module):
+ ensure_gitlab_package(module)
+
gitlab_url = module.params['api_url']
validate_certs = module.params['validate_certs']
+ ca_path = module.params['ca_path']
gitlab_user = module.params['api_username']
gitlab_password = module.params['api_password']
gitlab_token = module.params['api_token']
gitlab_oauth_token = module.params['api_oauth_token']
gitlab_job_token = module.params['api_job_token']
- ensure_gitlab_package(module)
+ verify = ca_path if validate_certs and ca_path else validate_certs
try:
# python-gitlab library remove support for username/password authentication since 1.13.0
# Changelog : https://github.com/python-gitlab/python-gitlab/releases/tag/v1.13.0
# This condition allow to still support older version of the python-gitlab library
if LooseVersion(gitlab.__version__) < LooseVersion("1.13.0"):
- gitlab_instance = gitlab.Gitlab(url=gitlab_url, ssl_verify=validate_certs, email=gitlab_user, password=gitlab_password,
+ gitlab_instance = gitlab.Gitlab(url=gitlab_url, ssl_verify=verify, email=gitlab_user, password=gitlab_password,
private_token=gitlab_token, api_version=4)
else:
# We can create an oauth_token using a username and password
# https://docs.gitlab.com/ee/api/oauth2.html#authorization-code-flow
if gitlab_user:
data = {'grant_type': 'password', 'username': gitlab_user, 'password': gitlab_password}
- resp = requests.post(urljoin(gitlab_url, "oauth/token"), data=data, verify=validate_certs)
+ resp = requests.post(urljoin(gitlab_url, "oauth/token"), data=data, verify=verify)
resp_data = resp.json()
gitlab_oauth_token = resp_data["access_token"]
- gitlab_instance = gitlab.Gitlab(url=gitlab_url, ssl_verify=validate_certs, private_token=gitlab_token,
+ gitlab_instance = gitlab.Gitlab(url=gitlab_url, ssl_verify=verify, private_token=gitlab_token,
oauth_token=gitlab_oauth_token, job_token=gitlab_job_token, api_version=4)
gitlab_instance.auth()
@@ -115,9 +135,46 @@ def gitlab_authentication(module):
def filter_returned_variables(gitlab_variables):
# pop properties we don't know
existing_variables = [dict(x.attributes) for x in gitlab_variables]
- KNOWN = ['key', 'value', 'masked', 'protected', 'variable_type', 'environment_scope']
+ KNOWN = ['key', 'value', 'masked', 'protected', 'variable_type', 'environment_scope', 'raw']
for item in existing_variables:
for key in list(item.keys()):
if key not in KNOWN:
item.pop(key)
return existing_variables
+
+
+def vars_to_variables(vars, module):
+ # transform old vars to new variables structure
+ variables = list()
+ for item, value in vars.items():
+ if isinstance(value, (string_types, integer_types, float)):
+ variables.append(
+ {
+ "name": item,
+ "value": str(value),
+ "masked": False,
+ "protected": False,
+ "raw": False,
+ "variable_type": "env_var",
+ }
+ )
+
+ elif isinstance(value, dict):
+ new_item = {
+ "name": item,
+ "value": value.get('value'),
+ "masked": value.get('masked'),
+ "protected": value.get('protected'),
+ "raw": value.get('raw'),
+ "variable_type": value.get('variable_type'),
+ }
+
+ if value.get('environment_scope'):
+ new_item['environment_scope'] = value.get('environment_scope')
+
+ variables.append(new_item)
+
+ else:
+ module.fail_json(msg="value must be of type string, integer, float or dict")
+
+ return variables
diff --git a/ansible_collections/community/general/plugins/module_utils/hwc_utils.py b/ansible_collections/community/general/plugins/module_utils/hwc_utils.py
index a21cc8e48..86d29e272 100644
--- a/ansible_collections/community/general/plugins/module_utils/hwc_utils.py
+++ b/ansible_collections/community/general/plugins/module_utils/hwc_utils.py
@@ -203,7 +203,7 @@ class Config(object):
if url == "":
raise HwcClientException(
- 0, "Can not find the enpoint for %s" % service_type)
+ 0, "Cannot find the endpoint for %s" % service_type)
if url[-1] != "/":
url += "/"
@@ -351,7 +351,7 @@ def wait_to_finish(target, pending, refresh, timeout, min_interval=1, delay=3):
if pending and status not in pending:
raise HwcModuleException(
- "unexpect status(%s) occurred" % status)
+ "unexpected status(%s) occurred" % status)
if not is_last_time:
wait *= 2
@@ -362,7 +362,7 @@ def wait_to_finish(target, pending, refresh, timeout, min_interval=1, delay=3):
time.sleep(wait)
- raise HwcModuleException("asycn wait timeout after %d seconds" % timeout)
+ raise HwcModuleException("async wait timeout after %d seconds" % timeout)
def navigate_value(data, index, array_index=None):
diff --git a/ansible_collections/community/general/plugins/module_utils/identity/keycloak/keycloak.py b/ansible_collections/community/general/plugins/module_utils/identity/keycloak/keycloak.py
index 7e421f3bb..9e1c3f4d9 100644
--- a/ansible_collections/community/general/plugins/module_utils/identity/keycloak/keycloak.py
+++ b/ansible_collections/community/general/plugins/module_utils/identity/keycloak/keycloak.py
@@ -9,6 +9,7 @@ __metaclass__ = type
import json
import traceback
+import copy
from ansible.module_utils.urls import open_url
from ansible.module_utils.six.moves.urllib.parse import urlencode, quote
@@ -64,11 +65,21 @@ URL_CLIENT_GROUP_ROLEMAPPINGS_AVAILABLE = "{url}/admin/realms/{realm}/groups/{id
URL_CLIENT_GROUP_ROLEMAPPINGS_COMPOSITE = "{url}/admin/realms/{realm}/groups/{id}/role-mappings/clients/{client}/composite"
URL_USERS = "{url}/admin/realms/{realm}/users"
+URL_USER = "{url}/admin/realms/{realm}/users/{id}"
+URL_USER_ROLE_MAPPINGS = "{url}/admin/realms/{realm}/users/{id}/role-mappings"
+URL_USER_REALM_ROLE_MAPPINGS = "{url}/admin/realms/{realm}/users/{id}/role-mappings/realm"
+URL_USER_CLIENTS_ROLE_MAPPINGS = "{url}/admin/realms/{realm}/users/{id}/role-mappings/clients"
+URL_USER_CLIENT_ROLE_MAPPINGS = "{url}/admin/realms/{realm}/users/{id}/role-mappings/clients/{client_id}"
+URL_USER_GROUPS = "{url}/admin/realms/{realm}/users/{id}/groups"
+URL_USER_GROUP = "{url}/admin/realms/{realm}/users/{id}/groups/{group_id}"
+
URL_CLIENT_SERVICE_ACCOUNT_USER = "{url}/admin/realms/{realm}/clients/{id}/service-account-user"
URL_CLIENT_USER_ROLEMAPPINGS = "{url}/admin/realms/{realm}/users/{id}/role-mappings/clients/{client}"
URL_CLIENT_USER_ROLEMAPPINGS_AVAILABLE = "{url}/admin/realms/{realm}/users/{id}/role-mappings/clients/{client}/available"
URL_CLIENT_USER_ROLEMAPPINGS_COMPOSITE = "{url}/admin/realms/{realm}/users/{id}/role-mappings/clients/{client}/composite"
+URL_REALM_GROUP_ROLEMAPPINGS = "{url}/admin/realms/{realm}/groups/{group}/role-mappings/realm"
+
URL_CLIENTSECRET = "{url}/admin/realms/{realm}/clients/{id}/client-secret"
URL_AUTHENTICATION_FLOWS = "{url}/admin/realms/{realm}/authentication/flows"
@@ -81,6 +92,9 @@ URL_AUTHENTICATION_EXECUTION_CONFIG = "{url}/admin/realms/{realm}/authentication
URL_AUTHENTICATION_EXECUTION_RAISE_PRIORITY = "{url}/admin/realms/{realm}/authentication/executions/{id}/raise-priority"
URL_AUTHENTICATION_EXECUTION_LOWER_PRIORITY = "{url}/admin/realms/{realm}/authentication/executions/{id}/lower-priority"
URL_AUTHENTICATION_CONFIG = "{url}/admin/realms/{realm}/authentication/config/{id}"
+URL_AUTHENTICATION_REGISTER_REQUIRED_ACTION = "{url}/admin/realms/{realm}/authentication/register-required-action"
+URL_AUTHENTICATION_REQUIRED_ACTIONS = "{url}/admin/realms/{realm}/authentication/required-actions"
+URL_AUTHENTICATION_REQUIRED_ACTIONS_ALIAS = "{url}/admin/realms/{realm}/authentication/required-actions/{alias}"
URL_IDENTITY_PROVIDERS = "{url}/admin/realms/{realm}/identity-provider/instances"
URL_IDENTITY_PROVIDER = "{url}/admin/realms/{realm}/identity-provider/instances/{alias}"
@@ -93,6 +107,20 @@ URL_COMPONENT = "{url}/admin/realms/{realm}/components/{id}"
URL_AUTHZ_AUTHORIZATION_SCOPE = "{url}/admin/realms/{realm}/clients/{client_id}/authz/resource-server/scope/{id}"
URL_AUTHZ_AUTHORIZATION_SCOPES = "{url}/admin/realms/{realm}/clients/{client_id}/authz/resource-server/scope"
+# This URL is used for:
+# - Querying client authorization permissions
+# - Removing client authorization permissions
+URL_AUTHZ_POLICIES = "{url}/admin/realms/{realm}/clients/{client_id}/authz/resource-server/policy"
+URL_AUTHZ_POLICY = "{url}/admin/realms/{realm}/clients/{client_id}/authz/resource-server/policy/{id}"
+
+URL_AUTHZ_PERMISSION = "{url}/admin/realms/{realm}/clients/{client_id}/authz/resource-server/permission/{permission_type}/{id}"
+URL_AUTHZ_PERMISSIONS = "{url}/admin/realms/{realm}/clients/{client_id}/authz/resource-server/permission/{permission_type}"
+
+URL_AUTHZ_RESOURCES = "{url}/admin/realms/{realm}/clients/{client_id}/authz/resource-server/resource"
+
+URL_AUTHZ_CUSTOM_POLICY = "{url}/admin/realms/{realm}/clients/{client_id}/authz/resource-server/policy/{policy_type}"
+URL_AUTHZ_CUSTOM_POLICIES = "{url}/admin/realms/{realm}/clients/{client_id}/authz/resource-server/policy"
+
def keycloak_argument_spec():
"""
@@ -266,8 +294,8 @@ class KeycloakAPI(object):
if e.code == 404:
return None
else:
- self.module.fail_json(msg='Could not obtain realm %s: %s' % (realm, str(e)),
- exception=traceback.format_exc())
+ self.fail_open_url(e, msg='Could not obtain realm %s: %s' % (realm, str(e)),
+ exception=traceback.format_exc())
except ValueError as e:
self.module.fail_json(msg='API returned incorrect JSON when trying to obtain realm %s: %s' % (realm, str(e)),
exception=traceback.format_exc())
@@ -291,8 +319,8 @@ class KeycloakAPI(object):
if e.code == 404:
return None
else:
- self.module.fail_json(msg='Could not obtain realm %s: %s' % (realm, str(e)),
- exception=traceback.format_exc())
+ self.fail_open_url(e, msg='Could not obtain realm %s: %s' % (realm, str(e)),
+ exception=traceback.format_exc())
except ValueError as e:
self.module.fail_json(msg='API returned incorrect JSON when trying to obtain realm %s: %s' % (realm, str(e)),
exception=traceback.format_exc())
@@ -312,8 +340,8 @@ class KeycloakAPI(object):
return open_url(realm_url, method='PUT', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(realmrep), validate_certs=self.validate_certs)
except Exception as e:
- self.module.fail_json(msg='Could not update realm %s: %s' % (realm, str(e)),
- exception=traceback.format_exc())
+ self.fail_open_url(e, msg='Could not update realm %s: %s' % (realm, str(e)),
+ exception=traceback.format_exc())
def create_realm(self, realmrep):
""" Create a realm in keycloak
@@ -326,8 +354,8 @@ class KeycloakAPI(object):
return open_url(realm_url, method='POST', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(realmrep), validate_certs=self.validate_certs)
except Exception as e:
- self.module.fail_json(msg='Could not create realm %s: %s' % (realmrep['id'], str(e)),
- exception=traceback.format_exc())
+ self.fail_open_url(e, msg='Could not create realm %s: %s' % (realmrep['id'], str(e)),
+ exception=traceback.format_exc())
def delete_realm(self, realm="master"):
""" Delete a realm from Keycloak
@@ -341,8 +369,8 @@ class KeycloakAPI(object):
return open_url(realm_url, method='DELETE', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs)
except Exception as e:
- self.module.fail_json(msg='Could not delete realm %s: %s' % (realm, str(e)),
- exception=traceback.format_exc())
+ self.fail_open_url(e, msg='Could not delete realm %s: %s' % (realm, str(e)),
+ exception=traceback.format_exc())
def get_clients(self, realm='master', filter=None):
""" Obtains client representations for clients in a realm
@@ -363,7 +391,7 @@ class KeycloakAPI(object):
self.module.fail_json(msg='API returned incorrect JSON when trying to obtain list of clients for realm %s: %s'
% (realm, str(e)))
except Exception as e:
- self.module.fail_json(msg='Could not obtain list of clients for realm %s: %s'
+ self.fail_open_url(e, msg='Could not obtain list of clients for realm %s: %s'
% (realm, str(e)))
def get_client_by_clientid(self, client_id, realm='master'):
@@ -396,7 +424,7 @@ class KeycloakAPI(object):
if e.code == 404:
return None
else:
- self.module.fail_json(msg='Could not obtain client %s for realm %s: %s'
+ self.fail_open_url(e, msg='Could not obtain client %s for realm %s: %s'
% (id, realm, str(e)))
except ValueError as e:
self.module.fail_json(msg='API returned incorrect JSON when trying to obtain client %s for realm %s: %s'
@@ -431,7 +459,7 @@ class KeycloakAPI(object):
return open_url(client_url, method='PUT', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(clientrep), validate_certs=self.validate_certs)
except Exception as e:
- self.module.fail_json(msg='Could not update client %s in realm %s: %s'
+ self.fail_open_url(e, msg='Could not update client %s in realm %s: %s'
% (id, realm, str(e)))
def create_client(self, clientrep, realm="master"):
@@ -446,7 +474,7 @@ class KeycloakAPI(object):
return open_url(client_url, method='POST', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(clientrep), validate_certs=self.validate_certs)
except Exception as e:
- self.module.fail_json(msg='Could not create client %s in realm %s: %s'
+ self.fail_open_url(e, msg='Could not create client %s in realm %s: %s'
% (clientrep['clientId'], realm, str(e)))
def delete_client(self, id, realm="master"):
@@ -462,7 +490,7 @@ class KeycloakAPI(object):
return open_url(client_url, method='DELETE', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs)
except Exception as e:
- self.module.fail_json(msg='Could not delete client %s in realm %s: %s'
+ self.fail_open_url(e, msg='Could not delete client %s in realm %s: %s'
% (id, realm, str(e)))
def get_client_roles_by_id(self, cid, realm="master"):
@@ -478,7 +506,7 @@ class KeycloakAPI(object):
timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except Exception as e:
- self.module.fail_json(msg="Could not fetch rolemappings for client %s in realm %s: %s"
+ self.fail_open_url(e, msg="Could not fetch rolemappings for client %s in realm %s: %s"
% (cid, realm, str(e)))
def get_client_role_id_by_name(self, cid, name, realm="master"):
@@ -513,12 +541,12 @@ class KeycloakAPI(object):
if rid == role['id']:
return role
except Exception as e:
- self.module.fail_json(msg="Could not fetch rolemappings for client %s in group %s, realm %s: %s"
+ self.fail_open_url(e, msg="Could not fetch rolemappings for client %s in group %s, realm %s: %s"
% (cid, gid, realm, str(e)))
return None
def get_client_group_available_rolemappings(self, gid, cid, realm="master"):
- """ Fetch the available role of a client in a specified goup on the Keycloak server.
+ """ Fetch the available role of a client in a specified group on the Keycloak server.
:param gid: ID of the group from which to obtain the rolemappings.
:param cid: ID of the client from which to obtain the rolemappings.
@@ -531,7 +559,7 @@ class KeycloakAPI(object):
timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except Exception as e:
- self.module.fail_json(msg="Could not fetch available rolemappings for client %s in group %s, realm %s: %s"
+ self.fail_open_url(e, msg="Could not fetch available rolemappings for client %s in group %s, realm %s: %s"
% (cid, gid, realm, str(e)))
def get_client_group_composite_rolemappings(self, gid, cid, realm="master"):
@@ -548,7 +576,7 @@ class KeycloakAPI(object):
timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except Exception as e:
- self.module.fail_json(msg="Could not fetch available rolemappings for client %s in group %s, realm %s: %s"
+ self.fail_open_url(e, msg="Could not fetch available rolemappings for client %s in group %s, realm %s: %s"
% (cid, gid, realm, str(e)))
def get_role_by_id(self, rid, realm="master"):
@@ -564,7 +592,7 @@ class KeycloakAPI(object):
timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except Exception as e:
- self.module.fail_json(msg="Could not fetch role for id %s in realm %s: %s"
+ self.fail_open_url(e, msg="Could not fetch role for id %s in realm %s: %s"
% (rid, realm, str(e)))
def get_client_roles_by_id_composite_rolemappings(self, rid, cid, realm="master"):
@@ -581,7 +609,7 @@ class KeycloakAPI(object):
timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except Exception as e:
- self.module.fail_json(msg="Could not fetch role for id %s and cid %s in realm %s: %s"
+ self.fail_open_url(e, msg="Could not fetch role for id %s and cid %s in realm %s: %s"
% (rid, cid, realm, str(e)))
def add_client_roles_by_id_composite_rolemapping(self, rid, roles_rep, realm="master"):
@@ -597,11 +625,43 @@ class KeycloakAPI(object):
open_url(available_rolemappings_url, method="POST", http_agent=self.http_agent, headers=self.restheaders, data=json.dumps(roles_rep),
validate_certs=self.validate_certs, timeout=self.connection_timeout)
except Exception as e:
- self.module.fail_json(msg="Could not assign roles to composite role %s and realm %s: %s"
+ self.fail_open_url(e, msg="Could not assign roles to composite role %s and realm %s: %s"
% (rid, realm, str(e)))
+ def add_group_realm_rolemapping(self, gid, role_rep, realm="master"):
+ """ Add the specified realm role to specified group on the Keycloak server.
+
+ :param gid: ID of the group to add the role mapping.
+ :param role_rep: Representation of the role to assign.
+ :param realm: Realm from which to obtain the rolemappings.
+ :return: None.
+ """
+ url = URL_REALM_GROUP_ROLEMAPPINGS.format(url=self.baseurl, realm=realm, group=gid)
+ try:
+ open_url(url, method="POST", http_agent=self.http_agent, headers=self.restheaders, data=json.dumps(role_rep),
+ validate_certs=self.validate_certs, timeout=self.connection_timeout)
+ except Exception as e:
+ self.fail_open_url(e, msg="Could add realm role mappings for group %s, realm %s: %s"
+ % (gid, realm, str(e)))
+
+ def delete_group_realm_rolemapping(self, gid, role_rep, realm="master"):
+ """ Delete the specified realm role from the specified group on the Keycloak server.
+
+ :param gid: ID of the group from which to obtain the rolemappings.
+ :param role_rep: Representation of the role to assign.
+ :param realm: Realm from which to obtain the rolemappings.
+ :return: None.
+ """
+ url = URL_REALM_GROUP_ROLEMAPPINGS.format(url=self.baseurl, realm=realm, group=gid)
+ try:
+ open_url(url, method="DELETE", http_agent=self.http_agent, headers=self.restheaders, data=json.dumps(role_rep),
+ validate_certs=self.validate_certs, timeout=self.connection_timeout)
+ except Exception as e:
+ self.fail_open_url(e, msg="Could not delete realm role mappings for group %s, realm %s: %s"
+ % (gid, realm, str(e)))
+
def add_group_rolemapping(self, gid, cid, role_rep, realm="master"):
- """ Fetch the composite role of a client in a specified goup on the Keycloak server.
+ """ Fetch the composite role of a client in a specified group on the Keycloak server.
:param gid: ID of the group from which to obtain the rolemappings.
:param cid: ID of the client from which to obtain the rolemappings.
@@ -614,7 +674,7 @@ class KeycloakAPI(object):
open_url(available_rolemappings_url, method="POST", http_agent=self.http_agent, headers=self.restheaders, data=json.dumps(role_rep),
validate_certs=self.validate_certs, timeout=self.connection_timeout)
except Exception as e:
- self.module.fail_json(msg="Could not fetch available rolemappings for client %s in group %s, realm %s: %s"
+ self.fail_open_url(e, msg="Could not fetch available rolemappings for client %s in group %s, realm %s: %s"
% (cid, gid, realm, str(e)))
def delete_group_rolemapping(self, gid, cid, role_rep, realm="master"):
@@ -631,7 +691,7 @@ class KeycloakAPI(object):
open_url(available_rolemappings_url, method="DELETE", http_agent=self.http_agent, headers=self.restheaders, data=json.dumps(role_rep),
validate_certs=self.validate_certs, timeout=self.connection_timeout)
except Exception as e:
- self.module.fail_json(msg="Could not delete available rolemappings for client %s in group %s, realm %s: %s"
+ self.fail_open_url(e, msg="Could not delete available rolemappings for client %s in group %s, realm %s: %s"
% (cid, gid, realm, str(e)))
def get_client_user_rolemapping_by_id(self, uid, cid, rid, realm='master'):
@@ -652,7 +712,7 @@ class KeycloakAPI(object):
if rid == role['id']:
return role
except Exception as e:
- self.module.fail_json(msg="Could not fetch rolemappings for client %s and user %s, realm %s: %s"
+ self.fail_open_url(e, msg="Could not fetch rolemappings for client %s and user %s, realm %s: %s"
% (cid, uid, realm, str(e)))
return None
@@ -670,7 +730,7 @@ class KeycloakAPI(object):
timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except Exception as e:
- self.module.fail_json(msg="Could not fetch effective rolemappings for client %s and user %s, realm %s: %s"
+ self.fail_open_url(e, msg="Could not fetch effective rolemappings for client %s and user %s, realm %s: %s"
% (cid, uid, realm, str(e)))
def get_client_user_composite_rolemappings(self, uid, cid, realm="master"):
@@ -687,7 +747,7 @@ class KeycloakAPI(object):
timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except Exception as e:
- self.module.fail_json(msg="Could not fetch available rolemappings for user %s of realm %s: %s"
+ self.fail_open_url(e, msg="Could not fetch available rolemappings for user %s of realm %s: %s"
% (uid, realm, str(e)))
def get_realm_user_rolemapping_by_id(self, uid, rid, realm='master'):
@@ -707,7 +767,7 @@ class KeycloakAPI(object):
if rid == role['id']:
return role
except Exception as e:
- self.module.fail_json(msg="Could not fetch rolemappings for user %s, realm %s: %s"
+ self.fail_open_url(e, msg="Could not fetch rolemappings for user %s, realm %s: %s"
% (uid, realm, str(e)))
return None
@@ -724,7 +784,7 @@ class KeycloakAPI(object):
timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except Exception as e:
- self.module.fail_json(msg="Could not fetch available rolemappings for user %s of realm %s: %s"
+ self.fail_open_url(e, msg="Could not fetch available rolemappings for user %s of realm %s: %s"
% (uid, realm, str(e)))
def get_realm_user_composite_rolemappings(self, uid, realm="master"):
@@ -740,7 +800,7 @@ class KeycloakAPI(object):
timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except Exception as e:
- self.module.fail_json(msg="Could not fetch effective rolemappings for user %s, realm %s: %s"
+ self.fail_open_url(e, msg="Could not fetch effective rolemappings for user %s, realm %s: %s"
% (uid, realm, str(e)))
def get_user_by_username(self, username, realm="master"):
@@ -754,7 +814,8 @@ class KeycloakAPI(object):
users_url += '?username=%s&exact=true' % username
try:
userrep = None
- users = json.loads(to_native(open_url(users_url, method='GET', headers=self.restheaders, timeout=self.connection_timeout,
+ users = json.loads(to_native(open_url(users_url, method='GET', http_agent=self.http_agent, headers=self.restheaders,
+ timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
for user in users:
if user['username'] == username:
@@ -766,7 +827,7 @@ class KeycloakAPI(object):
self.module.fail_json(msg='API returned incorrect JSON when trying to obtain the user for realm %s and username %s: %s'
% (realm, username, str(e)))
except Exception as e:
- self.module.fail_json(msg='Could not obtain the user for realm %s and username %s: %s'
+ self.fail_open_url(e, msg='Could not obtain the user for realm %s and username %s: %s'
% (realm, username, str(e)))
def get_service_account_user_by_client_id(self, client_id, realm="master"):
@@ -780,13 +841,14 @@ class KeycloakAPI(object):
service_account_user_url = URL_CLIENT_SERVICE_ACCOUNT_USER.format(url=self.baseurl, realm=realm, id=cid)
try:
- return json.loads(to_native(open_url(service_account_user_url, method='GET', headers=self.restheaders, timeout=self.connection_timeout,
+ return json.loads(to_native(open_url(service_account_user_url, method='GET', http_agent=self.http_agent, headers=self.restheaders,
+ timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except ValueError as e:
self.module.fail_json(msg='API returned incorrect JSON when trying to obtain the service-account-user for realm %s and client_id %s: %s'
% (realm, client_id, str(e)))
except Exception as e:
- self.module.fail_json(msg='Could not obtain the service-account-user for realm %s and client_id %s: %s'
+ self.fail_open_url(e, msg='Could not obtain the service-account-user for realm %s and client_id %s: %s'
% (realm, client_id, str(e)))
def add_user_rolemapping(self, uid, cid, role_rep, realm="master"):
@@ -804,7 +866,7 @@ class KeycloakAPI(object):
open_url(user_realm_rolemappings_url, method="POST", http_agent=self.http_agent, headers=self.restheaders, data=json.dumps(role_rep),
validate_certs=self.validate_certs, timeout=self.connection_timeout)
except Exception as e:
- self.module.fail_json(msg="Could not map roles to userId %s for realm %s and roles %s: %s"
+ self.fail_open_url(e, msg="Could not map roles to userId %s for realm %s and roles %s: %s"
% (uid, realm, json.dumps(role_rep), str(e)))
else:
user_client_rolemappings_url = URL_CLIENT_USER_ROLEMAPPINGS.format(url=self.baseurl, realm=realm, id=uid, client=cid)
@@ -812,7 +874,7 @@ class KeycloakAPI(object):
open_url(user_client_rolemappings_url, method="POST", http_agent=self.http_agent, headers=self.restheaders, data=json.dumps(role_rep),
validate_certs=self.validate_certs, timeout=self.connection_timeout)
except Exception as e:
- self.module.fail_json(msg="Could not map roles to userId %s for client %s, realm %s and roles %s: %s"
+ self.fail_open_url(e, msg="Could not map roles to userId %s for client %s, realm %s and roles %s: %s"
% (cid, uid, realm, json.dumps(role_rep), str(e)))
def delete_user_rolemapping(self, uid, cid, role_rep, realm="master"):
@@ -830,7 +892,7 @@ class KeycloakAPI(object):
open_url(user_realm_rolemappings_url, method="DELETE", http_agent=self.http_agent, headers=self.restheaders, data=json.dumps(role_rep),
validate_certs=self.validate_certs, timeout=self.connection_timeout)
except Exception as e:
- self.module.fail_json(msg="Could not remove roles %s from userId %s, realm %s: %s"
+ self.fail_open_url(e, msg="Could not remove roles %s from userId %s, realm %s: %s"
% (json.dumps(role_rep), uid, realm, str(e)))
else:
user_client_rolemappings_url = URL_CLIENT_USER_ROLEMAPPINGS.format(url=self.baseurl, realm=realm, id=uid, client=cid)
@@ -838,7 +900,7 @@ class KeycloakAPI(object):
open_url(user_client_rolemappings_url, method="DELETE", http_agent=self.http_agent, headers=self.restheaders, data=json.dumps(role_rep),
validate_certs=self.validate_certs, timeout=self.connection_timeout)
except Exception as e:
- self.module.fail_json(msg="Could not remove roles %s for client %s from userId %s, realm %s: %s"
+ self.fail_open_url(e, msg="Could not remove roles %s for client %s from userId %s, realm %s: %s"
% (json.dumps(role_rep), cid, uid, realm, str(e)))
def get_client_templates(self, realm='master'):
@@ -856,7 +918,7 @@ class KeycloakAPI(object):
self.module.fail_json(msg='API returned incorrect JSON when trying to obtain list of client templates for realm %s: %s'
% (realm, str(e)))
except Exception as e:
- self.module.fail_json(msg='Could not obtain list of client templates for realm %s: %s'
+ self.fail_open_url(e, msg='Could not obtain list of client templates for realm %s: %s'
% (realm, str(e)))
def get_client_template_by_id(self, id, realm='master'):
@@ -875,7 +937,7 @@ class KeycloakAPI(object):
self.module.fail_json(msg='API returned incorrect JSON when trying to obtain client templates %s for realm %s: %s'
% (id, realm, str(e)))
except Exception as e:
- self.module.fail_json(msg='Could not obtain client template %s for realm %s: %s'
+ self.fail_open_url(e, msg='Could not obtain client template %s for realm %s: %s'
% (id, realm, str(e)))
def get_client_template_by_name(self, name, realm='master'):
@@ -918,7 +980,7 @@ class KeycloakAPI(object):
return open_url(url, method='PUT', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(clienttrep), validate_certs=self.validate_certs)
except Exception as e:
- self.module.fail_json(msg='Could not update client template %s in realm %s: %s'
+ self.fail_open_url(e, msg='Could not update client template %s in realm %s: %s'
% (id, realm, str(e)))
def create_client_template(self, clienttrep, realm="master"):
@@ -933,7 +995,7 @@ class KeycloakAPI(object):
return open_url(url, method='POST', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(clienttrep), validate_certs=self.validate_certs)
except Exception as e:
- self.module.fail_json(msg='Could not create client template %s in realm %s: %s'
+ self.fail_open_url(e, msg='Could not create client template %s in realm %s: %s'
% (clienttrep['clientId'], realm, str(e)))
def delete_client_template(self, id, realm="master"):
@@ -949,7 +1011,7 @@ class KeycloakAPI(object):
return open_url(url, method='DELETE', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs)
except Exception as e:
- self.module.fail_json(msg='Could not delete client template %s in realm %s: %s'
+ self.fail_open_url(e, msg='Could not delete client template %s in realm %s: %s'
% (id, realm, str(e)))
def get_clientscopes(self, realm="master"):
@@ -967,7 +1029,7 @@ class KeycloakAPI(object):
timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except Exception as e:
- self.module.fail_json(msg="Could not fetch list of clientscopes in realm %s: %s"
+ self.fail_open_url(e, msg="Could not fetch list of clientscopes in realm %s: %s"
% (realm, str(e)))
def get_clientscope_by_clientscopeid(self, cid, realm="master"):
@@ -989,7 +1051,7 @@ class KeycloakAPI(object):
if e.code == 404:
return None
else:
- self.module.fail_json(msg="Could not fetch clientscope %s in realm %s: %s"
+ self.fail_open_url(e, msg="Could not fetch clientscope %s in realm %s: %s"
% (cid, realm, str(e)))
except Exception as e:
self.module.fail_json(msg="Could not clientscope group %s in realm %s: %s"
@@ -1030,7 +1092,7 @@ class KeycloakAPI(object):
return open_url(clientscopes_url, method='POST', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(clientscoperep), validate_certs=self.validate_certs)
except Exception as e:
- self.module.fail_json(msg="Could not create clientscope %s in realm %s: %s"
+ self.fail_open_url(e, msg="Could not create clientscope %s in realm %s: %s"
% (clientscoperep['name'], realm, str(e)))
def update_clientscope(self, clientscoperep, realm="master"):
@@ -1046,7 +1108,7 @@ class KeycloakAPI(object):
data=json.dumps(clientscoperep), validate_certs=self.validate_certs)
except Exception as e:
- self.module.fail_json(msg='Could not update clientscope %s in realm %s: %s'
+ self.fail_open_url(e, msg='Could not update clientscope %s in realm %s: %s'
% (clientscoperep['name'], realm, str(e)))
def delete_clientscope(self, name=None, cid=None, realm="master"):
@@ -1084,7 +1146,7 @@ class KeycloakAPI(object):
validate_certs=self.validate_certs)
except Exception as e:
- self.module.fail_json(msg="Unable to delete clientscope %s: %s" % (cid, str(e)))
+ self.fail_open_url(e, msg="Unable to delete clientscope %s: %s" % (cid, str(e)))
def get_clientscope_protocolmappers(self, cid, realm="master"):
""" Fetch the name and ID of all clientscopes on the Keycloak server.
@@ -1102,7 +1164,7 @@ class KeycloakAPI(object):
timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except Exception as e:
- self.module.fail_json(msg="Could not fetch list of protocolmappers in realm %s: %s"
+ self.fail_open_url(e, msg="Could not fetch list of protocolmappers in realm %s: %s"
% (realm, str(e)))
def get_clientscope_protocolmapper_by_protocolmapperid(self, pid, cid, realm="master"):
@@ -1126,7 +1188,7 @@ class KeycloakAPI(object):
if e.code == 404:
return None
else:
- self.module.fail_json(msg="Could not fetch protocolmapper %s in realm %s: %s"
+ self.fail_open_url(e, msg="Could not fetch protocolmapper %s in realm %s: %s"
% (pid, realm, str(e)))
except Exception as e:
self.module.fail_json(msg="Could not fetch protocolmapper %s in realm %s: %s"
@@ -1169,7 +1231,7 @@ class KeycloakAPI(object):
return open_url(protocolmappers_url, method='POST', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(mapper_rep), validate_certs=self.validate_certs)
except Exception as e:
- self.module.fail_json(msg="Could not create protocolmapper %s in realm %s: %s"
+ self.fail_open_url(e, msg="Could not create protocolmapper %s in realm %s: %s"
% (mapper_rep['name'], realm, str(e)))
def update_clientscope_protocolmappers(self, cid, mapper_rep, realm="master"):
@@ -1186,7 +1248,7 @@ class KeycloakAPI(object):
data=json.dumps(mapper_rep), validate_certs=self.validate_certs)
except Exception as e:
- self.module.fail_json(msg='Could not update protocolmappers for clientscope %s in realm %s: %s'
+ self.fail_open_url(e, msg='Could not update protocolmappers for clientscope %s in realm %s: %s'
% (mapper_rep, realm, str(e)))
def get_default_clientscopes(self, realm, client_id=None):
@@ -1210,7 +1272,7 @@ class KeycloakAPI(object):
:param realm: Realm in which the clientscope resides.
:param client_id: The client in which the clientscope resides.
- :return The optinal clientscopes of this realm or client
+ :return The optional clientscopes of this realm or client
"""
url = URL_OPTIONAL_CLIENTSCOPES if client_id is None else URL_CLIENT_OPTIONAL_CLIENTSCOPES
return self._get_clientscopes_of_type(realm, url, 'optional', client_id)
@@ -1223,7 +1285,7 @@ class KeycloakAPI(object):
:param realm: Realm in which the clientscope resides.
:param url_template the template for the right type
- :param scope_type this can be either optinal or default
+ :param scope_type this can be either optional or default
:param client_id: The client in which the clientscope resides.
:return The clientscopes of the specified type of this realm
"""
@@ -1233,7 +1295,7 @@ class KeycloakAPI(object):
return json.loads(to_native(open_url(clientscopes_url, method="GET", http_agent=self.http_agent, headers=self.restheaders,
timeout=self.connection_timeout, validate_certs=self.validate_certs).read()))
except Exception as e:
- self.module.fail_json(msg="Could not fetch list of %s clientscopes in realm %s: %s" % (scope_type, realm, str(e)))
+ self.fail_open_url(e, msg="Could not fetch list of %s clientscopes in realm %s: %s" % (scope_type, realm, str(e)))
else:
cid = self.get_client_id(client_id=client_id, realm=realm)
clientscopes_url = url_template.format(url=self.baseurl, realm=realm, cid=cid)
@@ -1241,11 +1303,11 @@ class KeycloakAPI(object):
return json.loads(to_native(open_url(clientscopes_url, method="GET", http_agent=self.http_agent, headers=self.restheaders,
timeout=self.connection_timeout, validate_certs=self.validate_certs).read()))
except Exception as e:
- self.module.fail_json(msg="Could not fetch list of %s clientscopes in client %s: %s" % (scope_type, client_id, clientscopes_url))
+ self.fail_open_url(e, msg="Could not fetch list of %s clientscopes in client %s: %s" % (scope_type, client_id, clientscopes_url))
def _decide_url_type_clientscope(self, client_id=None, scope_type="default"):
"""Decides which url to use.
- :param scope_type this can be either optinal or default
+ :param scope_type this can be either optional or default
:param client_id: The client in which the clientscope resides.
"""
if client_id is None:
@@ -1312,7 +1374,7 @@ class KeycloakAPI(object):
except Exception as e:
place = 'realm' if client_id is None else 'client ' + client_id
- self.module.fail_json(msg="Unable to %s %s clientscope %s @ %s : %s" % (action, scope_type, id, place, str(e)))
+ self.fail_open_url(e, msg="Unable to %s %s clientscope %s @ %s : %s" % (action, scope_type, id, place, str(e)))
def create_clientsecret(self, id, realm="master"):
""" Generate a new client secret by id
@@ -1324,14 +1386,15 @@ class KeycloakAPI(object):
clientsecret_url = URL_CLIENTSECRET.format(url=self.baseurl, realm=realm, id=id)
try:
- return json.loads(to_native(open_url(clientsecret_url, method='POST', headers=self.restheaders, timeout=self.connection_timeout,
+ return json.loads(to_native(open_url(clientsecret_url, method='POST', http_agent=self.http_agent, headers=self.restheaders,
+ timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except HTTPError as e:
if e.code == 404:
return None
else:
- self.module.fail_json(msg='Could not obtain clientsecret of client %s for realm %s: %s'
+ self.fail_open_url(e, msg='Could not obtain clientsecret of client %s for realm %s: %s'
% (id, realm, str(e)))
except Exception as e:
self.module.fail_json(msg='Could not obtain clientsecret of client %s for realm %s: %s'
@@ -1347,14 +1410,15 @@ class KeycloakAPI(object):
clientsecret_url = URL_CLIENTSECRET.format(url=self.baseurl, realm=realm, id=id)
try:
- return json.loads(to_native(open_url(clientsecret_url, method='GET', headers=self.restheaders, timeout=self.connection_timeout,
+ return json.loads(to_native(open_url(clientsecret_url, method='GET', http_agent=self.http_agent, headers=self.restheaders,
+ timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except HTTPError as e:
if e.code == 404:
return None
else:
- self.module.fail_json(msg='Could not obtain clientsecret of client %s for realm %s: %s'
+ self.fail_open_url(e, msg='Could not obtain clientsecret of client %s for realm %s: %s'
% (id, realm, str(e)))
except Exception as e:
self.module.fail_json(msg='Could not obtain clientsecret of client %s for realm %s: %s'
@@ -1374,7 +1438,7 @@ class KeycloakAPI(object):
timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except Exception as e:
- self.module.fail_json(msg="Could not fetch list of groups in realm %s: %s"
+ self.fail_open_url(e, msg="Could not fetch list of groups in realm %s: %s"
% (realm, str(e)))
def get_group_by_groupid(self, gid, realm="master"):
@@ -1395,7 +1459,7 @@ class KeycloakAPI(object):
if e.code == 404:
return None
else:
- self.module.fail_json(msg="Could not fetch group %s in realm %s: %s"
+ self.fail_open_url(e, msg="Could not fetch group %s in realm %s: %s"
% (gid, realm, str(e)))
except Exception as e:
self.module.fail_json(msg="Could not fetch group %s in realm %s: %s"
@@ -1490,7 +1554,7 @@ class KeycloakAPI(object):
def get_subgroup_direct_parent(self, parents, realm="master", children_to_resolve=None):
""" Get keycloak direct parent group API object for a given chain of parents.
- To succesfully work the API for subgroups we actually dont need
+ To successfully work the API for subgroups we actually don't need
to "walk the whole tree" for nested groups but only need to know
the ID for the direct predecessor of current subgroup. This
method will guarantee us this information getting there with
@@ -1542,7 +1606,7 @@ class KeycloakAPI(object):
return open_url(groups_url, method='POST', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(grouprep), validate_certs=self.validate_certs)
except Exception as e:
- self.module.fail_json(msg="Could not create group %s in realm %s: %s"
+ self.fail_open_url(e, msg="Could not create group %s in realm %s: %s"
% (grouprep['name'], realm, str(e)))
def create_subgroup(self, parents, grouprep, realm="master"):
@@ -1570,7 +1634,7 @@ class KeycloakAPI(object):
return open_url(url, method='POST', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(grouprep), validate_certs=self.validate_certs)
except Exception as e:
- self.module.fail_json(msg="Could not create subgroup %s for parent group %s in realm %s: %s"
+ self.fail_open_url(e, msg="Could not create subgroup %s for parent group %s in realm %s: %s"
% (grouprep['name'], parent_id, realm, str(e)))
def update_group(self, grouprep, realm="master"):
@@ -1585,7 +1649,7 @@ class KeycloakAPI(object):
return open_url(group_url, method='PUT', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(grouprep), validate_certs=self.validate_certs)
except Exception as e:
- self.module.fail_json(msg='Could not update group %s in realm %s: %s'
+ self.fail_open_url(e, msg='Could not update group %s in realm %s: %s'
% (grouprep['name'], realm, str(e)))
def delete_group(self, name=None, groupid=None, realm="master"):
@@ -1622,7 +1686,7 @@ class KeycloakAPI(object):
return open_url(group_url, method='DELETE', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs)
except Exception as e:
- self.module.fail_json(msg="Unable to delete group %s: %s" % (groupid, str(e)))
+ self.fail_open_url(e, msg="Unable to delete group %s: %s" % (groupid, str(e)))
def get_realm_roles(self, realm='master'):
""" Obtains role representations for roles in a realm
@@ -1639,7 +1703,7 @@ class KeycloakAPI(object):
self.module.fail_json(msg='API returned incorrect JSON when trying to obtain list of roles for realm %s: %s'
% (realm, str(e)))
except Exception as e:
- self.module.fail_json(msg='Could not obtain list of roles for realm %s: %s'
+ self.fail_open_url(e, msg='Could not obtain list of roles for realm %s: %s'
% (realm, str(e)))
def get_realm_role(self, name, realm='master'):
@@ -1649,7 +1713,7 @@ class KeycloakAPI(object):
:param name: Name of the role to fetch.
:param realm: Realm in which the role resides; default 'master'.
"""
- role_url = URL_REALM_ROLE.format(url=self.baseurl, realm=realm, name=quote(name))
+ role_url = URL_REALM_ROLE.format(url=self.baseurl, realm=realm, name=quote(name, safe=''))
try:
return json.loads(to_native(open_url(role_url, method="GET", http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
@@ -1657,7 +1721,7 @@ class KeycloakAPI(object):
if e.code == 404:
return None
else:
- self.module.fail_json(msg='Could not fetch role %s in realm %s: %s'
+ self.fail_open_url(e, msg='Could not fetch role %s in realm %s: %s'
% (name, realm, str(e)))
except Exception as e:
self.module.fail_json(msg='Could not fetch role %s in realm %s: %s'
@@ -1671,10 +1735,13 @@ class KeycloakAPI(object):
"""
roles_url = URL_REALM_ROLES.format(url=self.baseurl, realm=realm)
try:
+ if "composites" in rolerep:
+ keycloak_compatible_composites = self.convert_role_composites(rolerep["composites"])
+ rolerep["composites"] = keycloak_compatible_composites
return open_url(roles_url, method='POST', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(rolerep), validate_certs=self.validate_certs)
except Exception as e:
- self.module.fail_json(msg='Could not create role %s in realm %s: %s'
+ self.fail_open_url(e, msg='Could not create role %s in realm %s: %s'
% (rolerep['name'], realm, str(e)))
def update_realm_role(self, rolerep, realm='master'):
@@ -1683,26 +1750,138 @@ class KeycloakAPI(object):
:param rolerep: A RoleRepresentation of the updated role.
:return HTTPResponse object on success
"""
- role_url = URL_REALM_ROLE.format(url=self.baseurl, realm=realm, name=quote(rolerep['name']))
+ role_url = URL_REALM_ROLE.format(url=self.baseurl, realm=realm, name=quote(rolerep['name']), safe='')
try:
- return open_url(role_url, method='PUT', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
- data=json.dumps(rolerep), validate_certs=self.validate_certs)
+ composites = None
+ if "composites" in rolerep:
+ composites = copy.deepcopy(rolerep["composites"])
+ del rolerep["composites"]
+ role_response = open_url(role_url, method='PUT', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
+ data=json.dumps(rolerep), validate_certs=self.validate_certs)
+ if composites is not None:
+ self.update_role_composites(rolerep=rolerep, composites=composites, realm=realm)
+ return role_response
+ except Exception as e:
+ self.fail_open_url(e, msg='Could not update role %s in realm %s: %s'
+ % (rolerep['name'], realm, str(e)))
+
+ def get_role_composites(self, rolerep, clientid=None, realm='master'):
+ composite_url = ''
+ try:
+ if clientid is not None:
+ client = self.get_client_by_clientid(client_id=clientid, realm=realm)
+ cid = client['id']
+ composite_url = URL_CLIENT_ROLE_COMPOSITES.format(url=self.baseurl, realm=realm, id=cid, name=quote(rolerep["name"], safe=''))
+ else:
+ composite_url = URL_REALM_ROLE_COMPOSITES.format(url=self.baseurl, realm=realm, name=quote(rolerep["name"], safe=''))
+ # Get existing composites
+ return json.loads(to_native(open_url(
+ composite_url,
+ method='GET',
+ http_agent=self.http_agent,
+ headers=self.restheaders,
+ timeout=self.connection_timeout,
+ validate_certs=self.validate_certs).read()))
+ except Exception as e:
+ self.fail_open_url(e, msg='Could not get role %s composites in realm %s: %s'
+ % (rolerep['name'], realm, str(e)))
+
+ def create_role_composites(self, rolerep, composites, clientid=None, realm='master'):
+ composite_url = ''
+ try:
+ if clientid is not None:
+ client = self.get_client_by_clientid(client_id=clientid, realm=realm)
+ cid = client['id']
+ composite_url = URL_CLIENT_ROLE_COMPOSITES.format(url=self.baseurl, realm=realm, id=cid, name=quote(rolerep["name"], safe=''))
+ else:
+ composite_url = URL_REALM_ROLE_COMPOSITES.format(url=self.baseurl, realm=realm, name=quote(rolerep["name"], safe=''))
+ # Get existing composites
+ # create new composites
+ return open_url(composite_url, method='POST', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
+ data=json.dumps(composites), validate_certs=self.validate_certs)
except Exception as e:
- self.module.fail_json(msg='Could not update role %s in realm %s: %s'
+ self.fail_open_url(e, msg='Could not create role %s composites in realm %s: %s'
% (rolerep['name'], realm, str(e)))
+ def delete_role_composites(self, rolerep, composites, clientid=None, realm='master'):
+ composite_url = ''
+ try:
+ if clientid is not None:
+ client = self.get_client_by_clientid(client_id=clientid, realm=realm)
+ cid = client['id']
+ composite_url = URL_CLIENT_ROLE_COMPOSITES.format(url=self.baseurl, realm=realm, id=cid, name=quote(rolerep["name"], safe=''))
+ else:
+ composite_url = URL_REALM_ROLE_COMPOSITES.format(url=self.baseurl, realm=realm, name=quote(rolerep["name"], safe=''))
+ # Get existing composites
+ # create new composites
+ return open_url(composite_url, method='DELETE', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
+ data=json.dumps(composites), validate_certs=self.validate_certs)
+ except Exception as e:
+ self.fail_open_url(e, msg='Could not create role %s composites in realm %s: %s'
+ % (rolerep['name'], realm, str(e)))
+
+ def update_role_composites(self, rolerep, composites, clientid=None, realm='master'):
+ # Get existing composites
+ existing_composites = self.get_role_composites(rolerep=rolerep, clientid=clientid, realm=realm)
+ composites_to_be_created = []
+ composites_to_be_deleted = []
+ for composite in composites:
+ composite_found = False
+ existing_composite_client = None
+ for existing_composite in existing_composites:
+ if existing_composite["clientRole"]:
+ existing_composite_client = self.get_client_by_id(existing_composite["containerId"], realm=realm)
+ if ("client_id" in composite
+ and composite['client_id'] is not None
+ and existing_composite_client["clientId"] == composite["client_id"]
+ and composite["name"] == existing_composite["name"]):
+ composite_found = True
+ break
+ else:
+ if (("client_id" not in composite or composite['client_id'] is None)
+ and composite["name"] == existing_composite["name"]):
+ composite_found = True
+ break
+ if (not composite_found and ('state' not in composite or composite['state'] == 'present')):
+ if "client_id" in composite and composite['client_id'] is not None:
+ client_roles = self.get_client_roles(clientid=composite['client_id'], realm=realm)
+ for client_role in client_roles:
+ if client_role['name'] == composite['name']:
+ composites_to_be_created.append(client_role)
+ break
+ else:
+ realm_role = self.get_realm_role(name=composite["name"], realm=realm)
+ composites_to_be_created.append(realm_role)
+ elif composite_found and 'state' in composite and composite['state'] == 'absent':
+ if "client_id" in composite and composite['client_id'] is not None:
+ client_roles = self.get_client_roles(clientid=composite['client_id'], realm=realm)
+ for client_role in client_roles:
+ if client_role['name'] == composite['name']:
+ composites_to_be_deleted.append(client_role)
+ break
+ else:
+ realm_role = self.get_realm_role(name=composite["name"], realm=realm)
+ composites_to_be_deleted.append(realm_role)
+
+ if len(composites_to_be_created) > 0:
+ # create new composites
+ self.create_role_composites(rolerep=rolerep, composites=composites_to_be_created, clientid=clientid, realm=realm)
+ if len(composites_to_be_deleted) > 0:
+ # delete new composites
+ self.delete_role_composites(rolerep=rolerep, composites=composites_to_be_deleted, clientid=clientid, realm=realm)
+
def delete_realm_role(self, name, realm='master'):
""" Delete a realm role.
:param name: The name of the role.
:param realm: The realm in which this role resides, default "master".
"""
- role_url = URL_REALM_ROLE.format(url=self.baseurl, realm=realm, name=quote(name))
+ role_url = URL_REALM_ROLE.format(url=self.baseurl, realm=realm, name=quote(name, safe=''))
try:
return open_url(role_url, method='DELETE', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs)
except Exception as e:
- self.module.fail_json(msg='Unable to delete role %s in realm %s: %s'
+ self.fail_open_url(e, msg='Unable to delete role %s in realm %s: %s'
% (name, realm, str(e)))
def get_client_roles(self, clientid, realm='master'):
@@ -1725,7 +1904,7 @@ class KeycloakAPI(object):
self.module.fail_json(msg='API returned incorrect JSON when trying to obtain list of roles for client %s in realm %s: %s'
% (clientid, realm, str(e)))
except Exception as e:
- self.module.fail_json(msg='Could not obtain list of roles for client %s in realm %s: %s'
+ self.fail_open_url(e, msg='Could not obtain list of roles for client %s in realm %s: %s'
% (clientid, realm, str(e)))
def get_client_role(self, name, clientid, realm='master'):
@@ -1741,7 +1920,7 @@ class KeycloakAPI(object):
if cid is None:
self.module.fail_json(msg='Could not find client %s in realm %s'
% (clientid, realm))
- role_url = URL_CLIENT_ROLE.format(url=self.baseurl, realm=realm, id=cid, name=quote(name))
+ role_url = URL_CLIENT_ROLE.format(url=self.baseurl, realm=realm, id=cid, name=quote(name, safe=''))
try:
return json.loads(to_native(open_url(role_url, method="GET", http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
@@ -1749,7 +1928,7 @@ class KeycloakAPI(object):
if e.code == 404:
return None
else:
- self.module.fail_json(msg='Could not fetch role %s in client %s of realm %s: %s'
+ self.fail_open_url(e, msg='Could not fetch role %s in client %s of realm %s: %s'
% (name, clientid, realm, str(e)))
except Exception as e:
self.module.fail_json(msg='Could not fetch role %s for client %s in realm %s: %s'
@@ -1769,12 +1948,30 @@ class KeycloakAPI(object):
% (clientid, realm))
roles_url = URL_CLIENT_ROLES.format(url=self.baseurl, realm=realm, id=cid)
try:
+ if "composites" in rolerep:
+ keycloak_compatible_composites = self.convert_role_composites(rolerep["composites"])
+ rolerep["composites"] = keycloak_compatible_composites
return open_url(roles_url, method='POST', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(rolerep), validate_certs=self.validate_certs)
except Exception as e:
- self.module.fail_json(msg='Could not create role %s for client %s in realm %s: %s'
+ self.fail_open_url(e, msg='Could not create role %s for client %s in realm %s: %s'
% (rolerep['name'], clientid, realm, str(e)))
+ def convert_role_composites(self, composites):
+ keycloak_compatible_composites = {
+ 'client': {},
+ 'realm': []
+ }
+ for composite in composites:
+ if 'state' not in composite or composite['state'] == 'present':
+ if "client_id" in composite and composite["client_id"] is not None:
+ if composite["client_id"] not in keycloak_compatible_composites["client"]:
+ keycloak_compatible_composites["client"][composite["client_id"]] = []
+ keycloak_compatible_composites["client"][composite["client_id"]].append(composite["name"])
+ else:
+ keycloak_compatible_composites["realm"].append(composite["name"])
+ return keycloak_compatible_composites
+
def update_client_role(self, rolerep, clientid, realm="master"):
""" Update an existing client role.
@@ -1787,12 +1984,19 @@ class KeycloakAPI(object):
if cid is None:
self.module.fail_json(msg='Could not find client %s in realm %s'
% (clientid, realm))
- role_url = URL_CLIENT_ROLE.format(url=self.baseurl, realm=realm, id=cid, name=quote(rolerep['name']))
- try:
- return open_url(role_url, method='PUT', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
- data=json.dumps(rolerep), validate_certs=self.validate_certs)
- except Exception as e:
- self.module.fail_json(msg='Could not update role %s for client %s in realm %s: %s'
+ role_url = URL_CLIENT_ROLE.format(url=self.baseurl, realm=realm, id=cid, name=quote(rolerep['name'], safe=''))
+ try:
+ composites = None
+ if "composites" in rolerep:
+ composites = copy.deepcopy(rolerep["composites"])
+ del rolerep['composites']
+ update_role_response = open_url(role_url, method='PUT', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
+ data=json.dumps(rolerep), validate_certs=self.validate_certs)
+ if composites is not None:
+ self.update_role_composites(rolerep=rolerep, clientid=clientid, composites=composites, realm=realm)
+ return update_role_response
+ except Exception as e:
+ self.fail_open_url(e, msg='Could not update role %s for client %s in realm %s: %s'
% (rolerep['name'], clientid, realm, str(e)))
def delete_client_role(self, name, clientid, realm="master"):
@@ -1806,12 +2010,12 @@ class KeycloakAPI(object):
if cid is None:
self.module.fail_json(msg='Could not find client %s in realm %s'
% (clientid, realm))
- role_url = URL_CLIENT_ROLE.format(url=self.baseurl, realm=realm, id=cid, name=quote(name))
+ role_url = URL_CLIENT_ROLE.format(url=self.baseurl, realm=realm, id=cid, name=quote(name, safe=''))
try:
return open_url(role_url, method='DELETE', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs)
except Exception as e:
- self.module.fail_json(msg='Unable to delete role %s for client %s in realm %s: %s'
+ self.fail_open_url(e, msg='Unable to delete role %s for client %s in realm %s: %s'
% (name, clientid, realm, str(e)))
def get_authentication_flow_by_alias(self, alias, realm='master'):
@@ -1833,7 +2037,7 @@ class KeycloakAPI(object):
break
return authentication_flow
except Exception as e:
- self.module.fail_json(msg="Unable get authentication flow %s: %s" % (alias, str(e)))
+ self.fail_open_url(e, msg="Unable get authentication flow %s: %s" % (alias, str(e)))
def delete_authentication_flow_by_id(self, id, realm='master'):
"""
@@ -1848,8 +2052,8 @@ class KeycloakAPI(object):
return open_url(flow_url, method='DELETE', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs)
except Exception as e:
- self.module.fail_json(msg='Could not delete authentication flow %s in realm %s: %s'
- % (id, realm, str(e)))
+ self.fail_open_url(e, msg='Could not delete authentication flow %s in realm %s: %s'
+ % (id, realm, str(e)))
def copy_auth_flow(self, config, realm='master'):
"""
@@ -1866,7 +2070,7 @@ class KeycloakAPI(object):
URL_AUTHENTICATION_FLOW_COPY.format(
url=self.baseurl,
realm=realm,
- copyfrom=quote(config["copyFrom"])),
+ copyfrom=quote(config["copyFrom"], safe='')),
method='POST',
http_agent=self.http_agent, headers=self.restheaders,
data=json.dumps(new_name),
@@ -1885,8 +2089,8 @@ class KeycloakAPI(object):
return flow
return None
except Exception as e:
- self.module.fail_json(msg='Could not copy authentication flow %s in realm %s: %s'
- % (config["alias"], realm, str(e)))
+ self.fail_open_url(e, msg='Could not copy authentication flow %s in realm %s: %s'
+ % (config["alias"], realm, str(e)))
def create_empty_auth_flow(self, config, realm='master'):
"""
@@ -1925,8 +2129,8 @@ class KeycloakAPI(object):
return flow
return None
except Exception as e:
- self.module.fail_json(msg='Could not create empty authentication flow %s in realm %s: %s'
- % (config["alias"], realm, str(e)))
+ self.fail_open_url(e, msg='Could not create empty authentication flow %s in realm %s: %s'
+ % (config["alias"], realm, str(e)))
def update_authentication_executions(self, flowAlias, updatedExec, realm='master'):
""" Update authentication executions
@@ -1940,15 +2144,15 @@ class KeycloakAPI(object):
URL_AUTHENTICATION_FLOW_EXECUTIONS.format(
url=self.baseurl,
realm=realm,
- flowalias=quote(flowAlias)),
+ flowalias=quote(flowAlias, safe='')),
method='PUT',
http_agent=self.http_agent, headers=self.restheaders,
data=json.dumps(updatedExec),
timeout=self.connection_timeout,
validate_certs=self.validate_certs)
except HTTPError as e:
- self.module.fail_json(msg="Unable to update execution '%s': %s: %s %s" %
- (flowAlias, repr(e), ";".join([e.url, e.msg, str(e.code), str(e.hdrs)]), str(updatedExec)))
+ self.fail_open_url(e, msg="Unable to update execution '%s': %s: %s %s"
+ % (flowAlias, repr(e), ";".join([e.url, e.msg, str(e.code), str(e.hdrs)]), str(updatedExec)))
except Exception as e:
self.module.fail_json(msg="Unable to update executions %s: %s" % (updatedExec, str(e)))
@@ -1971,7 +2175,7 @@ class KeycloakAPI(object):
timeout=self.connection_timeout,
validate_certs=self.validate_certs)
except Exception as e:
- self.module.fail_json(msg="Unable to add authenticationConfig %s: %s" % (executionId, str(e)))
+ self.fail_open_url(e, msg="Unable to add authenticationConfig %s: %s" % (executionId, str(e)))
def create_subflow(self, subflowName, flowAlias, realm='master', flowType='basic-flow'):
""" Create new sublow on the flow
@@ -1989,14 +2193,14 @@ class KeycloakAPI(object):
URL_AUTHENTICATION_FLOW_EXECUTIONS_FLOW.format(
url=self.baseurl,
realm=realm,
- flowalias=quote(flowAlias)),
+ flowalias=quote(flowAlias, safe='')),
method='POST',
http_agent=self.http_agent, headers=self.restheaders,
data=json.dumps(newSubFlow),
timeout=self.connection_timeout,
validate_certs=self.validate_certs)
except Exception as e:
- self.module.fail_json(msg="Unable to create new subflow %s: %s" % (subflowName, str(e)))
+ self.fail_open_url(e, msg="Unable to create new subflow %s: %s" % (subflowName, str(e)))
def create_execution(self, execution, flowAlias, realm='master'):
""" Create new execution on the flow
@@ -2013,15 +2217,15 @@ class KeycloakAPI(object):
URL_AUTHENTICATION_FLOW_EXECUTIONS_EXECUTION.format(
url=self.baseurl,
realm=realm,
- flowalias=quote(flowAlias)),
+ flowalias=quote(flowAlias, safe='')),
method='POST',
http_agent=self.http_agent, headers=self.restheaders,
data=json.dumps(newExec),
timeout=self.connection_timeout,
validate_certs=self.validate_certs)
except HTTPError as e:
- self.module.fail_json(msg="Unable to create new execution '%s' %s: %s: %s %s" %
- (flowAlias, execution["providerId"], repr(e), ";".join([e.url, e.msg, str(e.code), str(e.hdrs)]), str(newExec)))
+ self.fail_open_url(e, msg="Unable to create new execution '%s' %s: %s: %s %s"
+ % (flowAlias, execution["providerId"], repr(e), ";".join([e.url, e.msg, str(e.code), str(e.hdrs)]), str(newExec)))
except Exception as e:
self.module.fail_json(msg="Unable to create new execution '%s' %s: %s" % (flowAlias, execution["providerId"], repr(e)))
@@ -2057,7 +2261,7 @@ class KeycloakAPI(object):
timeout=self.connection_timeout,
validate_certs=self.validate_certs)
except Exception as e:
- self.module.fail_json(msg="Unable to change execution priority %s: %s" % (executionId, str(e)))
+ self.fail_open_url(e, msg="Unable to change execution priority %s: %s" % (executionId, str(e)))
def get_executions_representation(self, config, realm='master'):
"""
@@ -2073,7 +2277,7 @@ class KeycloakAPI(object):
URL_AUTHENTICATION_FLOW_EXECUTIONS.format(
url=self.baseurl,
realm=realm,
- flowalias=quote(config["alias"])),
+ flowalias=quote(config["alias"], safe='')),
method='GET',
http_agent=self.http_agent, headers=self.restheaders,
timeout=self.connection_timeout,
@@ -2094,8 +2298,121 @@ class KeycloakAPI(object):
execution["authenticationConfig"] = execConfig
return executions
except Exception as e:
- self.module.fail_json(msg='Could not get executions for authentication flow %s in realm %s: %s'
- % (config["alias"], realm, str(e)))
+ self.fail_open_url(e, msg='Could not get executions for authentication flow %s in realm %s: %s'
+ % (config["alias"], realm, str(e)))
+
+ def get_required_actions(self, realm='master'):
+ """
+ Get required actions.
+ :param realm: Realm name (not id).
+ :return: List of representations of the required actions.
+ """
+
+ try:
+ required_actions = json.load(
+ open_url(
+ URL_AUTHENTICATION_REQUIRED_ACTIONS.format(
+ url=self.baseurl,
+ realm=realm
+ ),
+ method='GET',
+ http_agent=self.http_agent, headers=self.restheaders,
+ timeout=self.connection_timeout,
+ validate_certs=self.validate_certs
+ )
+ )
+
+ return required_actions
+ except Exception:
+ return None
+
+ def register_required_action(self, rep, realm='master'):
+ """
+ Register required action.
+ :param rep: JSON containing 'providerId', and 'name' attributes.
+ :param realm: Realm name (not id).
+ :return: Representation of the required action.
+ """
+
+ data = {
+ 'name': rep['name'],
+ 'providerId': rep['providerId']
+ }
+
+ try:
+ return open_url(
+ URL_AUTHENTICATION_REGISTER_REQUIRED_ACTION.format(
+ url=self.baseurl,
+ realm=realm
+ ),
+ method='POST',
+ http_agent=self.http_agent, headers=self.restheaders,
+ data=json.dumps(data),
+ timeout=self.connection_timeout,
+ validate_certs=self.validate_certs
+ )
+ except Exception as e:
+ self.fail_open_url(
+ e,
+ msg='Unable to register required action %s in realm %s: %s'
+ % (rep["name"], realm, str(e))
+ )
+
+ def update_required_action(self, alias, rep, realm='master'):
+ """
+ Update required action.
+ :param alias: Alias of required action.
+ :param rep: JSON describing new state of required action.
+ :param realm: Realm name (not id).
+ :return: HTTPResponse object on success.
+ """
+
+ try:
+ return open_url(
+ URL_AUTHENTICATION_REQUIRED_ACTIONS_ALIAS.format(
+ url=self.baseurl,
+ alias=quote(alias, safe=''),
+ realm=realm
+ ),
+ method='PUT',
+ http_agent=self.http_agent, headers=self.restheaders,
+ data=json.dumps(rep),
+ timeout=self.connection_timeout,
+ validate_certs=self.validate_certs
+ )
+ except Exception as e:
+ self.fail_open_url(
+ e,
+ msg='Unable to update required action %s in realm %s: %s'
+ % (alias, realm, str(e))
+ )
+
+ def delete_required_action(self, alias, realm='master'):
+ """
+ Delete required action.
+ :param alias: Alias of required action.
+ :param realm: Realm name (not id).
+ :return: HTTPResponse object on success.
+ """
+
+ try:
+ return open_url(
+ URL_AUTHENTICATION_REQUIRED_ACTIONS_ALIAS.format(
+ url=self.baseurl,
+ alias=quote(alias, safe=''),
+ realm=realm
+ ),
+ method='DELETE',
+ http_agent=self.http_agent, headers=self.restheaders,
+ timeout=self.connection_timeout,
+ validate_certs=self.validate_certs
+ )
+ except Exception as e:
+ self.fail_open_url(
+ e,
+ msg='Unable to delete required action %s in realm %s: %s'
+ % (alias, realm, str(e))
+ )
def get_identity_providers(self, realm='master'):
""" Fetch representations for identity providers in a realm
@@ -2110,7 +2427,7 @@ class KeycloakAPI(object):
self.module.fail_json(msg='API returned incorrect JSON when trying to obtain list of identity providers for realm %s: %s'
% (realm, str(e)))
except Exception as e:
- self.module.fail_json(msg='Could not obtain list of identity providers for realm %s: %s'
+ self.fail_open_url(e, msg='Could not obtain list of identity providers for realm %s: %s'
% (realm, str(e)))
def get_identity_provider(self, alias, realm='master'):
@@ -2127,7 +2444,7 @@ class KeycloakAPI(object):
if e.code == 404:
return None
else:
- self.module.fail_json(msg='Could not fetch identity provider %s in realm %s: %s'
+ self.fail_open_url(e, msg='Could not fetch identity provider %s in realm %s: %s'
% (alias, realm, str(e)))
except Exception as e:
self.module.fail_json(msg='Could not fetch identity provider %s in realm %s: %s'
@@ -2144,7 +2461,7 @@ class KeycloakAPI(object):
return open_url(idps_url, method='POST', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(idprep), validate_certs=self.validate_certs)
except Exception as e:
- self.module.fail_json(msg='Could not create identity provider %s in realm %s: %s'
+ self.fail_open_url(e, msg='Could not create identity provider %s in realm %s: %s'
% (idprep['alias'], realm, str(e)))
def update_identity_provider(self, idprep, realm='master'):
@@ -2158,7 +2475,7 @@ class KeycloakAPI(object):
return open_url(idp_url, method='PUT', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(idprep), validate_certs=self.validate_certs)
except Exception as e:
- self.module.fail_json(msg='Could not update identity provider %s in realm %s: %s'
+ self.fail_open_url(e, msg='Could not update identity provider %s in realm %s: %s'
% (idprep['alias'], realm, str(e)))
def delete_identity_provider(self, alias, realm='master'):
@@ -2171,7 +2488,7 @@ class KeycloakAPI(object):
return open_url(idp_url, method='DELETE', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs)
except Exception as e:
- self.module.fail_json(msg='Unable to delete identity provider %s in realm %s: %s'
+ self.fail_open_url(e, msg='Unable to delete identity provider %s in realm %s: %s'
% (alias, realm, str(e)))
def get_identity_provider_mappers(self, alias, realm='master'):
@@ -2189,7 +2506,7 @@ class KeycloakAPI(object):
self.module.fail_json(msg='API returned incorrect JSON when trying to obtain list of identity provider mappers for idp %s in realm %s: %s'
% (alias, realm, str(e)))
except Exception as e:
- self.module.fail_json(msg='Could not obtain list of identity provider mappers for idp %s in realm %s: %s'
+ self.fail_open_url(e, msg='Could not obtain list of identity provider mappers for idp %s in realm %s: %s'
% (alias, realm, str(e)))
def get_identity_provider_mapper(self, mid, alias, realm='master'):
@@ -2208,7 +2525,7 @@ class KeycloakAPI(object):
if e.code == 404:
return None
else:
- self.module.fail_json(msg='Could not fetch mapper %s for identity provider %s in realm %s: %s'
+ self.fail_open_url(e, msg='Could not fetch mapper %s for identity provider %s in realm %s: %s'
% (mid, alias, realm, str(e)))
except Exception as e:
self.module.fail_json(msg='Could not fetch mapper %s for identity provider %s in realm %s: %s'
@@ -2226,7 +2543,7 @@ class KeycloakAPI(object):
return open_url(mappers_url, method='POST', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(mapper), validate_certs=self.validate_certs)
except Exception as e:
- self.module.fail_json(msg='Could not create identity provider mapper %s for idp %s in realm %s: %s'
+ self.fail_open_url(e, msg='Could not create identity provider mapper %s for idp %s in realm %s: %s'
% (mapper['name'], alias, realm, str(e)))
def update_identity_provider_mapper(self, mapper, alias, realm='master'):
@@ -2241,7 +2558,7 @@ class KeycloakAPI(object):
return open_url(mapper_url, method='PUT', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(mapper), validate_certs=self.validate_certs)
except Exception as e:
- self.module.fail_json(msg='Could not update mapper %s for identity provider %s in realm %s: %s'
+ self.fail_open_url(e, msg='Could not update mapper %s for identity provider %s in realm %s: %s'
% (mapper['id'], alias, realm, str(e)))
def delete_identity_provider_mapper(self, mid, alias, realm='master'):
@@ -2255,7 +2572,7 @@ class KeycloakAPI(object):
return open_url(mapper_url, method='DELETE', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs)
except Exception as e:
- self.module.fail_json(msg='Unable to delete mapper %s for identity provider %s in realm %s: %s'
+ self.fail_open_url(e, msg='Unable to delete mapper %s for identity provider %s in realm %s: %s'
% (mid, alias, realm, str(e)))
def get_components(self, filter=None, realm='master'):
@@ -2275,7 +2592,7 @@ class KeycloakAPI(object):
self.module.fail_json(msg='API returned incorrect JSON when trying to obtain list of components for realm %s: %s'
% (realm, str(e)))
except Exception as e:
- self.module.fail_json(msg='Could not obtain list of components for realm %s: %s'
+ self.fail_open_url(e, msg='Could not obtain list of components for realm %s: %s'
% (realm, str(e)))
def get_component(self, cid, realm='master'):
@@ -2292,7 +2609,7 @@ class KeycloakAPI(object):
if e.code == 404:
return None
else:
- self.module.fail_json(msg='Could not fetch component %s in realm %s: %s'
+ self.fail_open_url(e, msg='Could not fetch component %s in realm %s: %s'
% (cid, realm, str(e)))
except Exception as e:
self.module.fail_json(msg='Could not fetch component %s in realm %s: %s'
@@ -2315,7 +2632,7 @@ class KeycloakAPI(object):
return json.loads(to_native(open_url(comp_url, method="GET", http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except Exception as e:
- self.module.fail_json(msg='Could not create component in realm %s: %s'
+ self.fail_open_url(e, msg='Could not create component in realm %s: %s'
% (realm, str(e)))
def update_component(self, comprep, realm='master'):
@@ -2332,7 +2649,7 @@ class KeycloakAPI(object):
return open_url(comp_url, method='PUT', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(comprep), validate_certs=self.validate_certs)
except Exception as e:
- self.module.fail_json(msg='Could not update component %s in realm %s: %s'
+ self.fail_open_url(e, msg='Could not update component %s in realm %s: %s'
% (cid, realm, str(e)))
def delete_component(self, cid, realm='master'):
@@ -2345,12 +2662,12 @@ class KeycloakAPI(object):
return open_url(comp_url, method='DELETE', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs)
except Exception as e:
- self.module.fail_json(msg='Unable to delete component %s in realm %s: %s'
+ self.fail_open_url(e, msg='Unable to delete component %s in realm %s: %s'
% (cid, realm, str(e)))
def get_authz_authorization_scope_by_name(self, name, client_id, realm):
url = URL_AUTHZ_AUTHORIZATION_SCOPES.format(url=self.baseurl, client_id=client_id, realm=realm)
- search_url = "%s/search?name=%s" % (url, quote(name))
+ search_url = "%s/search?name=%s" % (url, quote(name, safe=''))
try:
return json.loads(to_native(open_url(search_url, method='GET', http_agent=self.http_agent, headers=self.restheaders,
@@ -2367,7 +2684,7 @@ class KeycloakAPI(object):
return open_url(url, method='POST', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(payload), validate_certs=self.validate_certs)
except Exception as e:
- self.module.fail_json(msg='Could not create authorization scope %s for client %s in realm %s: %s' % (payload['name'], client_id, realm, str(e)))
+ self.fail_open_url(e, msg='Could not create authorization scope %s for client %s in realm %s: %s' % (payload['name'], client_id, realm, str(e)))
def update_authz_authorization_scope(self, payload, id, client_id, realm):
"""Update an authorization scope for a Keycloak client"""
@@ -2377,7 +2694,7 @@ class KeycloakAPI(object):
return open_url(url, method='PUT', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(payload), validate_certs=self.validate_certs)
except Exception as e:
- self.module.fail_json(msg='Could not create update scope %s for client %s in realm %s: %s' % (payload['name'], client_id, realm, str(e)))
+ self.fail_open_url(e, msg='Could not create update scope %s for client %s in realm %s: %s' % (payload['name'], client_id, realm, str(e)))
def remove_authz_authorization_scope(self, id, client_id, realm):
"""Remove an authorization scope from a Keycloak client"""
@@ -2387,4 +2704,355 @@ class KeycloakAPI(object):
return open_url(url, method='DELETE', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs)
except Exception as e:
- self.module.fail_json(msg='Could not delete scope %s for client %s in realm %s: %s' % (id, client_id, realm, str(e)))
+ self.fail_open_url(e, msg='Could not delete scope %s for client %s in realm %s: %s' % (id, client_id, realm, str(e)))
+
+ def get_user_by_id(self, user_id, realm='master'):
+ """
+ Get a User by its ID.
+ :param user_id: ID of the user.
+ :param realm: Realm
+ :return: Representation of the user.
+ """
+ try:
+ user_url = URL_USER.format(
+ url=self.baseurl,
+ realm=realm,
+ id=user_id)
+ userrep = json.load(
+ open_url(
+ user_url,
+ method='GET',
+ http_agent=self.http_agent, headers=self.restheaders,
+ timeout=self.connection_timeout,
+ validate_certs=self.validate_certs))
+ return userrep
+ except Exception as e:
+ self.fail_open_url(e, msg='Could not get user %s in realm %s: %s'
+ % (user_id, realm, str(e)))
+
+ def create_user(self, userrep, realm='master'):
+ """
+ Create a new User.
+ :param userrep: Representation of the user to create
+ :param realm: Realm
+ :return: Representation of the user created.
+ """
+ try:
+ if 'attributes' in userrep and isinstance(userrep['attributes'], list):
+ attributes = copy.deepcopy(userrep['attributes'])
+ userrep['attributes'] = self.convert_user_attributes_to_keycloak_dict(attributes=attributes)
+ users_url = URL_USERS.format(
+ url=self.baseurl,
+ realm=realm)
+ open_url(users_url,
+ method='POST',
+ http_agent=self.http_agent, headers=self.restheaders,
+ data=json.dumps(userrep),
+ timeout=self.connection_timeout,
+ validate_certs=self.validate_certs)
+ created_user = self.get_user_by_username(
+ username=userrep['username'],
+ realm=realm)
+ return created_user
+ except Exception as e:
+ self.fail_open_url(e, msg='Could not create user %s in realm %s: %s'
+ % (userrep['username'], realm, str(e)))
+
+ def convert_user_attributes_to_keycloak_dict(self, attributes):
+ keycloak_user_attributes_dict = {}
+ for attribute in attributes:
+ if ('state' not in attribute or attribute['state'] == 'present') and 'name' in attribute:
+ keycloak_user_attributes_dict[attribute['name']] = attribute['values'] if 'values' in attribute else []
+ return keycloak_user_attributes_dict
+
+ def convert_keycloak_user_attributes_dict_to_module_list(self, attributes):
+ module_attributes_list = []
+ for key in attributes:
+ attr = {}
+ attr['name'] = key
+ attr['values'] = attributes[key]
+ module_attributes_list.append(attr)
+ return module_attributes_list
+
+ def update_user(self, userrep, realm='master'):
+ """
+ Update a User.
+ :param userrep: Representation of the user to update. This representation must include the ID of the user.
+ :param realm: Realm
+ :return: Representation of the updated user.
+ """
+ try:
+ if 'attributes' in userrep and isinstance(userrep['attributes'], list):
+ attributes = copy.deepcopy(userrep['attributes'])
+ userrep['attributes'] = self.convert_user_attributes_to_keycloak_dict(attributes=attributes)
+ user_url = URL_USER.format(
+ url=self.baseurl,
+ realm=realm,
+ id=userrep["id"])
+ open_url(
+ user_url,
+ method='PUT',
+ http_agent=self.http_agent, headers=self.restheaders,
+ data=json.dumps(userrep),
+ timeout=self.connection_timeout,
+ validate_certs=self.validate_certs)
+ updated_user = self.get_user_by_id(
+ user_id=userrep['id'],
+ realm=realm)
+ return updated_user
+ except Exception as e:
+ self.fail_open_url(e, msg='Could not update user %s in realm %s: %s'
+ % (userrep['username'], realm, str(e)))
+
+ def delete_user(self, user_id, realm='master'):
+ """
+ Delete a User.
+ :param user_id: ID of the user to be deleted
+ :param realm: Realm
+ :return: HTTP response.
+ """
+ try:
+ user_url = URL_USER.format(
+ url=self.baseurl,
+ realm=realm,
+ id=user_id)
+ return open_url(
+ user_url,
+ method='DELETE',
+ http_agent=self.http_agent, headers=self.restheaders,
+ timeout=self.connection_timeout,
+ validate_certs=self.validate_certs)
+ except Exception as e:
+ self.fail_open_url(e, msg='Could not delete user %s in realm %s: %s'
+ % (user_id, realm, str(e)))
+
+ def get_user_groups(self, user_id, realm='master'):
+ """
+ Get groups for a user.
+ :param user_id: User ID
+ :param realm: Realm
+ :return: Representation of the client groups.
+ """
+ try:
+ groups = []
+ user_groups_url = URL_USER_GROUPS.format(
+ url=self.baseurl,
+ realm=realm,
+ id=user_id)
+ user_groups = json.load(
+ open_url(
+ user_groups_url,
+ method='GET',
+ http_agent=self.http_agent, headers=self.restheaders,
+ timeout=self.connection_timeout,
+ validate_certs=self.validate_certs))
+ for user_group in user_groups:
+ groups.append(user_group["name"])
+ return groups
+ except Exception as e:
+ self.fail_open_url(e, msg='Could not get groups for user %s in realm %s: %s'
+ % (user_id, realm, str(e)))
+
+ def add_user_in_group(self, user_id, group_id, realm='master'):
+ """
+ Add a user to a group.
+ :param user_id: User ID
+ :param group_id: Group Id to add the user to.
+ :param realm: Realm
+ :return: HTTP Response
+ """
+ try:
+ user_group_url = URL_USER_GROUP.format(
+ url=self.baseurl,
+ realm=realm,
+ id=user_id,
+ group_id=group_id)
+ return open_url(
+ user_group_url,
+ method='PUT',
+ http_agent=self.http_agent, headers=self.restheaders,
+ timeout=self.connection_timeout,
+ validate_certs=self.validate_certs)
+ except Exception as e:
+ self.fail_open_url(e, msg='Could not add user %s in group %s in realm %s: %s'
+ % (user_id, group_id, realm, str(e)))
+
+ def remove_user_from_group(self, user_id, group_id, realm='master'):
+ """
+ Remove a user from a group for a user.
+ :param user_id: User ID
+ :param group_id: Group Id to add the user to.
+ :param realm: Realm
+ :return: HTTP response
+ """
+ try:
+ user_group_url = URL_USER_GROUP.format(
+ url=self.baseurl,
+ realm=realm,
+ id=user_id,
+ group_id=group_id)
+ return open_url(
+ user_group_url,
+ method='DELETE',
+ http_agent=self.http_agent, headers=self.restheaders,
+ timeout=self.connection_timeout,
+ validate_certs=self.validate_certs)
+ except Exception as e:
+ self.fail_open_url(e, msg='Could not remove user %s from group %s in realm %s: %s'
+ % (user_id, group_id, realm, str(e)))
+
+ def update_user_groups_membership(self, userrep, groups, realm='master'):
+ """
+ Update user's group membership
+ :param userrep: Representation of the user. This representation must include the ID.
+ :param realm: Realm
+ :return: True if group membership has been changed. False Otherwise.
+ """
+ changed = False
+ try:
+ user_existing_groups = self.get_user_groups(
+ user_id=userrep['id'],
+ realm=realm)
+ groups_to_add_and_remove = self.extract_groups_to_add_to_and_remove_from_user(groups)
+ # If group membership need to be changed
+ if not is_struct_included(groups_to_add_and_remove['add'], user_existing_groups):
+ # Get available groups in the realm
+ realm_groups = self.get_groups(realm=realm)
+ for realm_group in realm_groups:
+ if "name" in realm_group and realm_group["name"] in groups_to_add_and_remove['add']:
+ self.add_user_in_group(
+ user_id=userrep["id"],
+ group_id=realm_group["id"],
+ realm=realm)
+ changed = True
+ elif "name" in realm_group and realm_group['name'] in groups_to_add_and_remove['remove']:
+ self.remove_user_from_group(
+ user_id=userrep['id'],
+ group_id=realm_group['id'],
+ realm=realm)
+ changed = True
+ return changed
+ except Exception as e:
+ self.module.fail_json(msg='Could not update group membership for user %s in realm %s: %s'
+ % (userrep['id]'], realm, str(e)))
+
+ def extract_groups_to_add_to_and_remove_from_user(self, groups):
+ groups_extract = {}
+ groups_to_add = []
+ groups_to_remove = []
+ if isinstance(groups, list) and len(groups) > 0:
+ for group in groups:
+ group_name = group['name'] if isinstance(group, dict) and 'name' in group else group
+ if isinstance(group, dict) and ('state' not in group or group['state'] == 'present'):
+ groups_to_add.append(group_name)
+ else:
+ groups_to_remove.append(group_name)
+ groups_extract['add'] = groups_to_add
+ groups_extract['remove'] = groups_to_remove
+
+ return groups_extract
+
+ def convert_user_group_list_of_str_to_list_of_dict(self, groups):
+ list_of_groups = []
+ if isinstance(groups, list) and len(groups) > 0:
+ for group in groups:
+ if isinstance(group, str):
+ group_dict = {}
+ group_dict['name'] = group
+ list_of_groups.append(group_dict)
+ return list_of_groups
+
+ def create_authz_custom_policy(self, policy_type, payload, client_id, realm):
+ """Create a custom policy for a Keycloak client"""
+ url = URL_AUTHZ_CUSTOM_POLICY.format(url=self.baseurl, policy_type=policy_type, client_id=client_id, realm=realm)
+
+ try:
+ return open_url(url, method='POST', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
+ data=json.dumps(payload), validate_certs=self.validate_certs)
+ except Exception as e:
+ self.fail_open_url(e, msg='Could not create permission %s for client %s in realm %s: %s' % (payload['name'], client_id, realm, str(e)))
+
+ def remove_authz_custom_policy(self, policy_id, client_id, realm):
+ """Remove a custom policy from a Keycloak client"""
+ url = URL_AUTHZ_CUSTOM_POLICIES.format(url=self.baseurl, client_id=client_id, realm=realm)
+ delete_url = "%s/%s" % (url, policy_id)
+
+ try:
+ return open_url(delete_url, method='DELETE', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
+ validate_certs=self.validate_certs)
+ except Exception as e:
+ self.fail_open_url(e, msg='Could not delete custom policy %s for client %s in realm %s: %s' % (id, client_id, realm, str(e)))
+
+ def get_authz_permission_by_name(self, name, client_id, realm):
+ """Get authorization permission by name"""
+ url = URL_AUTHZ_POLICIES.format(url=self.baseurl, client_id=client_id, realm=realm)
+ search_url = "%s/search?name=%s" % (url, name.replace(' ', '%20'))
+
+ try:
+ return json.loads(to_native(open_url(search_url, method='GET', http_agent=self.http_agent, headers=self.restheaders,
+ timeout=self.connection_timeout,
+ validate_certs=self.validate_certs).read()))
+ except Exception:
+ return False
+
+ def create_authz_permission(self, payload, permission_type, client_id, realm):
+ """Create an authorization permission for a Keycloak client"""
+ url = URL_AUTHZ_PERMISSIONS.format(url=self.baseurl, permission_type=permission_type, client_id=client_id, realm=realm)
+
+ try:
+ return open_url(url, method='POST', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
+ data=json.dumps(payload), validate_certs=self.validate_certs)
+ except Exception as e:
+ self.fail_open_url(e, msg='Could not create permission %s for client %s in realm %s: %s' % (payload['name'], client_id, realm, str(e)))
+
+ def remove_authz_permission(self, id, client_id, realm):
+ """Create an authorization permission for a Keycloak client"""
+ url = URL_AUTHZ_POLICY.format(url=self.baseurl, id=id, client_id=client_id, realm=realm)
+
+ try:
+ return open_url(url, method='DELETE', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
+ validate_certs=self.validate_certs)
+ except Exception as e:
+ self.fail_open_url(e, msg='Could not delete permission %s for client %s in realm %s: %s' % (id, client_id, realm, str(e)))
+
+ def update_authz_permission(self, payload, permission_type, id, client_id, realm):
+ """Update a permission for a Keycloak client"""
+ url = URL_AUTHZ_PERMISSION.format(url=self.baseurl, permission_type=permission_type, id=id, client_id=client_id, realm=realm)
+
+ try:
+ return open_url(url, method='PUT', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
+ data=json.dumps(payload), validate_certs=self.validate_certs)
+ except Exception as e:
+ self.fail_open_url(e, msg='Could not create update permission %s for client %s in realm %s: %s' % (payload['name'], client_id, realm, str(e)))
+
+ def get_authz_resource_by_name(self, name, client_id, realm):
+ """Get authorization resource by name"""
+ url = URL_AUTHZ_RESOURCES.format(url=self.baseurl, client_id=client_id, realm=realm)
+ search_url = "%s/search?name=%s" % (url, name.replace(' ', '%20'))
+
+ try:
+ return json.loads(to_native(open_url(search_url, method='GET', http_agent=self.http_agent, headers=self.restheaders,
+ timeout=self.connection_timeout,
+ validate_certs=self.validate_certs).read()))
+ except Exception:
+ return False
+
+ def get_authz_policy_by_name(self, name, client_id, realm):
+ """Get authorization policy by name"""
+ url = URL_AUTHZ_POLICIES.format(url=self.baseurl, client_id=client_id, realm=realm)
+ search_url = "%s/search?name=%s&permission=false" % (url, name.replace(' ', '%20'))
+
+ try:
+ return json.loads(to_native(open_url(search_url, method='GET', http_agent=self.http_agent, headers=self.restheaders,
+ timeout=self.connection_timeout,
+ validate_certs=self.validate_certs).read()))
+ except Exception:
+ return False
+
+ def fail_open_url(self, e, msg, **kwargs):
+ try:
+ if isinstance(e, HTTPError):
+ msg = "%s: %s" % (msg, to_native(e.read()))
+ except Exception as ingore:
+ pass
+ self.module.fail_json(msg, **kwargs)
diff --git a/ansible_collections/community/general/plugins/module_utils/ldap.py b/ansible_collections/community/general/plugins/module_utils/ldap.py
index 655371321..fccf07304 100644
--- a/ansible_collections/community/general/plugins/module_utils/ldap.py
+++ b/ansible_collections/community/general/plugins/module_utils/ldap.py
@@ -42,11 +42,17 @@ def gen_specs(**specs):
'validate_certs': dict(default=True, type='bool'),
'sasl_class': dict(choices=['external', 'gssapi'], default='external', type='str'),
'xorder_discovery': dict(choices=['enable', 'auto', 'disable'], default='auto', type='str'),
+ 'client_cert': dict(default=None, type='path'),
+ 'client_key': dict(default=None, type='path'),
})
return specs
+def ldap_required_together():
+ return [['client_cert', 'client_key']]
+
+
class LdapGeneric(object):
def __init__(self, module):
# Shortcuts
@@ -60,6 +66,8 @@ class LdapGeneric(object):
self.verify_cert = self.module.params['validate_certs']
self.sasl_class = self.module.params['sasl_class']
self.xorder_discovery = self.module.params['xorder_discovery']
+ self.client_cert = self.module.params['client_cert']
+ self.client_key = self.module.params['client_key']
# Establish connection
self.connection = self._connect_to_ldap()
@@ -102,6 +110,10 @@ class LdapGeneric(object):
if self.ca_path:
ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, self.ca_path)
+ if self.client_cert and self.client_key:
+ ldap.set_option(ldap.OPT_X_TLS_CERTFILE, self.client_cert)
+ ldap.set_option(ldap.OPT_X_TLS_KEYFILE, self.client_key)
+
connection = ldap.initialize(self.server_uri)
if self.referrals_chasing == 'disabled':
@@ -127,5 +139,7 @@ class LdapGeneric(object):
def _xorder_dn(self):
# match X_ORDERed DNs
- regex = r"\w+=\{\d+\}.+"
- return re.match(regex, self.module.params['dn']) is not None
+ regex = r".+\{\d+\}.+"
+ explode_dn = ldap.dn.explode_dn(self.module.params['dn'])
+
+ return re.match(regex, explode_dn[0]) is not None
diff --git a/ansible_collections/community/general/plugins/module_utils/locale_gen.py b/ansible_collections/community/general/plugins/module_utils/locale_gen.py
new file mode 100644
index 000000000..ca35e17d3
--- /dev/null
+++ b/ansible_collections/community/general/plugins/module_utils/locale_gen.py
@@ -0,0 +1,31 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2023, Alexei Znamensky <russoz@gmail.com>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+from ansible_collections.community.general.plugins.module_utils.cmd_runner import CmdRunner, cmd_runner_fmt
+
+
+def locale_runner(module):
+ runner = CmdRunner(
+ module,
+ command=["locale", "-a"],
+ check_rc=True,
+ )
+ return runner
+
+
+def locale_gen_runner(module):
+ runner = CmdRunner(
+ module,
+ command="locale-gen",
+ arg_formats=dict(
+ name=cmd_runner_fmt.as_list(),
+ purge=cmd_runner_fmt.as_fixed('--purge'),
+ ),
+ check_rc=True,
+ )
+ return runner
diff --git a/ansible_collections/community/general/plugins/module_utils/lxd.py b/ansible_collections/community/general/plugins/module_utils/lxd.py
index 7f5362532..68a1c690f 100644
--- a/ansible_collections/community/general/plugins/module_utils/lxd.py
+++ b/ansible_collections/community/general/plugins/module_utils/lxd.py
@@ -41,7 +41,7 @@ class LXDClientException(Exception):
class LXDClient(object):
- def __init__(self, url, key_file=None, cert_file=None, debug=False):
+ def __init__(self, url, key_file=None, cert_file=None, debug=False, server_cert_file=None, server_check_hostname=True):
"""LXD Client.
:param url: The URL of the LXD server. (e.g. unix:/var/lib/lxd/unix.socket or https://127.0.0.1)
@@ -52,6 +52,10 @@ class LXDClient(object):
:type cert_file: ``str``
:param debug: The debug flag. The request and response are stored in logs when debug is true.
:type debug: ``bool``
+ :param server_cert_file: The path of the server certificate file.
+ :type server_cert_file: ``str``
+ :param server_check_hostname: Whether to check the server's hostname as part of TLS verification.
+ :type debug: ``bool``
"""
self.url = url
self.debug = debug
@@ -61,6 +65,10 @@ class LXDClient(object):
self.key_file = key_file
parts = generic_urlparse(urlparse(self.url))
ctx = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
+ if server_cert_file:
+ # Check that the received cert is signed by the provided server_cert_file
+ ctx.load_verify_locations(cafile=server_cert_file)
+ ctx.check_hostname = server_check_hostname
ctx.load_cert_chain(cert_file, keyfile=key_file)
self.connection = HTTPSConnection(parts.get('netloc'), context=ctx)
elif url.startswith('unix:'):
diff --git a/ansible_collections/community/general/plugins/module_utils/memset.py b/ansible_collections/community/general/plugins/module_utils/memset.py
index 374b40ff4..8ddf76907 100644
--- a/ansible_collections/community/general/plugins/module_utils/memset.py
+++ b/ansible_collections/community/general/plugins/module_utils/memset.py
@@ -14,8 +14,9 @@ from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
from ansible.module_utils.six.moves.urllib.parse import urlencode
-from ansible.module_utils.urls import open_url, urllib_error
+from ansible.module_utils.urls import open_url
from ansible.module_utils.basic import json
+import ansible.module_utils.six.moves.urllib.error as urllib_error
class Response(object):
@@ -78,7 +79,7 @@ def memset_api_call(api_key, api_method, payload=None):
msg = "Memset API returned an error ({0}, {1})." . format(response.json()['error_type'], response.json()['error'])
except urllib_error.URLError as e:
has_failed = True
- msg = "An URLError occured ({0})." . format(type(e))
+ msg = "An URLError occurred ({0})." . format(type(e))
response.stderr = "{0}" . format(e)
if msg is None:
diff --git a/ansible_collections/community/general/plugins/module_utils/mh/mixins/cmd.py b/ansible_collections/community/general/plugins/module_utils/mh/mixins/cmd.py
deleted file mode 100644
index a7d379394..000000000
--- a/ansible_collections/community/general/plugins/module_utils/mh/mixins/cmd.py
+++ /dev/null
@@ -1,205 +0,0 @@
-# -*- coding: utf-8 -*-
-# (c) 2020, Alexei Znamensky <russoz@gmail.com>
-# Copyright (c) 2020, Ansible Project
-# Simplified BSD License (see LICENSES/BSD-2-Clause.txt or https://opensource.org/licenses/BSD-2-Clause)
-# SPDX-License-Identifier: BSD-2-Clause
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-from functools import partial
-
-
-class ArgFormat(object):
- """
- Argument formatter for use as a command line parameter. Used in CmdMixin.
- """
- BOOLEAN = 0
- PRINTF = 1
- FORMAT = 2
- BOOLEAN_NOT = 3
-
- @staticmethod
- def stars_deco(num):
- if num == 1:
- def deco(f):
- return lambda v: f(*v)
- return deco
- elif num == 2:
- def deco(f):
- return lambda v: f(**v)
- return deco
-
- return lambda f: f
-
- def __init__(self, name, fmt=None, style=FORMAT, stars=0):
- """
- THIS CLASS IS BEING DEPRECATED.
- It was never meant to be used outside the scope of CmdMixin, and CmdMixin is being deprecated.
- See the deprecation notice in ``CmdMixin.__init__()`` below.
-
- Creates a CLI-formatter for one specific argument. The argument may be a module parameter or just a named parameter for
- the CLI command execution.
- :param name: Name of the argument to be formatted
- :param fmt: Either a str to be formatted (using or not printf-style) or a callable that does that
- :param style: Whether arg_format (as str) should use printf-style formatting.
- Ignored if arg_format is None or not a str (should be callable).
- :param stars: A int with 0, 1 or 2 value, indicating to formatting the value as: value, *value or **value
- """
- def printf_fmt(_fmt, v):
- try:
- return [_fmt % v]
- except TypeError as e:
- if e.args[0] != 'not all arguments converted during string formatting':
- raise
- return [_fmt]
-
- _fmts = {
- ArgFormat.BOOLEAN: lambda _fmt, v: ([_fmt] if bool(v) else []),
- ArgFormat.BOOLEAN_NOT: lambda _fmt, v: ([] if bool(v) else [_fmt]),
- ArgFormat.PRINTF: printf_fmt,
- ArgFormat.FORMAT: lambda _fmt, v: [_fmt.format(v)],
- }
-
- self.name = name
- self.stars = stars
- self.style = style
-
- if fmt is None:
- fmt = "{0}"
- style = ArgFormat.FORMAT
-
- if isinstance(fmt, str):
- func = _fmts[style]
- self.arg_format = partial(func, fmt)
- elif isinstance(fmt, list) or isinstance(fmt, tuple):
- self.arg_format = lambda v: [_fmts[style](f, v)[0] for f in fmt]
- elif hasattr(fmt, '__call__'):
- self.arg_format = fmt
- else:
- raise TypeError('Parameter fmt must be either: a string, a list/tuple of '
- 'strings or a function: type={0}, value={1}'.format(type(fmt), fmt))
-
- if stars:
- self.arg_format = (self.stars_deco(stars))(self.arg_format)
-
- def to_text(self, value):
- if value is None and self.style != ArgFormat.BOOLEAN_NOT:
- return []
- func = self.arg_format
- return [str(p) for p in func(value)]
-
-
-class CmdMixin(object):
- """
- THIS CLASS IS BEING DEPRECATED.
- See the deprecation notice in ``CmdMixin.__init__()`` below.
-
- Mixin for mapping module options to running a CLI command with its arguments.
- """
- command = None
- command_args_formats = {}
- run_command_fixed_options = {}
- check_rc = False
- force_lang = "C"
-
- @property
- def module_formats(self):
- result = {}
- for param in self.module.params.keys():
- result[param] = ArgFormat(param)
- return result
-
- @property
- def custom_formats(self):
- result = {}
- for param, fmt_spec in self.command_args_formats.items():
- result[param] = ArgFormat(param, **fmt_spec)
- return result
-
- def __init__(self, *args, **kwargs):
- super(CmdMixin, self).__init__(*args, **kwargs)
- self.module.deprecate(
- 'The CmdMixin used in classes CmdModuleHelper and CmdStateModuleHelper is being deprecated. '
- 'Modules should use community.general.plugins.module_utils.cmd_runner.CmdRunner instead.',
- version='8.0.0',
- collection_name='community.general',
- )
-
- def _calculate_args(self, extra_params=None, params=None):
- def add_arg_formatted_param(_cmd_args, arg_format, _value):
- args = list(arg_format.to_text(_value))
- return _cmd_args + args
-
- def find_format(_param):
- return self.custom_formats.get(_param, self.module_formats.get(_param))
-
- extra_params = extra_params or dict()
- cmd_args = list([self.command]) if isinstance(self.command, str) else list(self.command)
- try:
- cmd_args[0] = self.module.get_bin_path(cmd_args[0], required=True)
- except ValueError:
- pass
- param_list = params if params else self.vars.keys()
-
- for param in param_list:
- if isinstance(param, dict):
- if len(param) != 1:
- self.do_raise("run_command parameter as a dict must contain only one key: {0}".format(param))
- _param = list(param.keys())[0]
- fmt = find_format(_param)
- value = param[_param]
- elif isinstance(param, str):
- if param in self.vars.keys():
- fmt = find_format(param)
- value = self.vars[param]
- elif param in extra_params:
- fmt = find_format(param)
- value = extra_params[param]
- else:
- self.do_raise('Cannot determine value for parameter: {0}'.format(param))
- else:
- self.do_raise("run_command parameter must be either a str or a dict: {0}".format(param))
- cmd_args = add_arg_formatted_param(cmd_args, fmt, value)
-
- return cmd_args
-
- def process_command_output(self, rc, out, err):
- return rc, out, err
-
- def run_command(self,
- extra_params=None,
- params=None,
- process_output=None,
- publish_rc=True,
- publish_out=True,
- publish_err=True,
- publish_cmd=True,
- *args, **kwargs):
- cmd_args = self._calculate_args(extra_params, params)
- options = dict(self.run_command_fixed_options)
- options['check_rc'] = options.get('check_rc', self.check_rc)
- options.update(kwargs)
- env_update = dict(options.get('environ_update', {}))
- if self.force_lang:
- env_update.update({
- 'LANGUAGE': self.force_lang,
- 'LC_ALL': self.force_lang,
- })
- self.update_output(force_lang=self.force_lang)
- options['environ_update'] = env_update
- rc, out, err = self.module.run_command(cmd_args, *args, **options)
- if publish_rc:
- self.update_output(rc=rc)
- if publish_out:
- self.update_output(stdout=out)
- if publish_err:
- self.update_output(stderr=err)
- if publish_cmd:
- self.update_output(cmd_args=cmd_args)
- if process_output is None:
- _process = self.process_command_output
- else:
- _process = process_output
-
- return _process(rc, out, err)
diff --git a/ansible_collections/community/general/plugins/module_utils/mh/mixins/deps.py b/ansible_collections/community/general/plugins/module_utils/mh/mixins/deps.py
index bab8c090b..772df8c0e 100644
--- a/ansible_collections/community/general/plugins/module_utils/mh/mixins/deps.py
+++ b/ansible_collections/community/general/plugins/module_utils/mh/mixins/deps.py
@@ -38,6 +38,12 @@ class DependencyCtxMgr(object):
class DependencyMixin(ModuleHelperBase):
+ """
+ THIS CLASS IS BEING DEPRECATED.
+ See the deprecation notice in ``DependencyMixin.fail_on_missing_deps()`` below.
+
+ Mixin for mapping module options to running a CLI command with its arguments.
+ """
_dependencies = []
@classmethod
@@ -46,6 +52,14 @@ class DependencyMixin(ModuleHelperBase):
return cls._dependencies[-1]
def fail_on_missing_deps(self):
+ if not self._dependencies:
+ return
+ self.module.deprecate(
+ 'The DependencyMixin is being deprecated. '
+ 'Modules should use community.general.plugins.module_utils.deps instead.',
+ version='9.0.0',
+ collection_name='community.general',
+ )
for d in self._dependencies:
if not d.has_it:
self.module.fail_json(changed=False,
diff --git a/ansible_collections/community/general/plugins/module_utils/mh/mixins/vars.py b/ansible_collections/community/general/plugins/module_utils/mh/mixins/vars.py
index 6dfb29bab..91f4e4a18 100644
--- a/ansible_collections/community/general/plugins/module_utils/mh/mixins/vars.py
+++ b/ansible_collections/community/general/plugins/module_utils/mh/mixins/vars.py
@@ -11,6 +11,13 @@ import copy
class VarMeta(object):
+ """
+ DEPRECATION WARNING
+
+ This class is deprecated and will be removed in community.general 10.0.0
+ Modules should use the VarDict from plugins/module_utils/vardict.py instead.
+ """
+
NOTHING = object()
def __init__(self, diff=False, output=True, change=None, fact=False):
@@ -60,6 +67,12 @@ class VarMeta(object):
class VarDict(object):
+ """
+ DEPRECATION WARNING
+
+ This class is deprecated and will be removed in community.general 10.0.0
+ Modules should use the VarDict from plugins/module_utils/vardict.py instead.
+ """
def __init__(self):
self._data = dict()
self._meta = dict()
@@ -123,7 +136,12 @@ class VarDict(object):
class VarsMixin(object):
+ """
+ DEPRECATION WARNING
+ This class is deprecated and will be removed in community.general 10.0.0
+ Modules should use the VarDict from plugins/module_utils/vardict.py instead.
+ """
def __init__(self, module=None):
self.vars = VarDict()
super(VarsMixin, self).__init__(module)
diff --git a/ansible_collections/community/general/plugins/module_utils/mh/module_helper.py b/ansible_collections/community/general/plugins/module_utils/mh/module_helper.py
index c5973262d..c33efb16b 100644
--- a/ansible_collections/community/general/plugins/module_utils/mh/module_helper.py
+++ b/ansible_collections/community/general/plugins/module_utils/mh/module_helper.py
@@ -7,11 +7,11 @@
from __future__ import absolute_import, division, print_function
__metaclass__ = type
+
from ansible.module_utils.common.dict_transformations import dict_merge
# (TODO: remove AnsibleModule!) pylint: disable-next=unused-import
from ansible_collections.community.general.plugins.module_utils.mh.base import ModuleHelperBase, AnsibleModule # noqa: F401
-from ansible_collections.community.general.plugins.module_utils.mh.mixins.cmd import CmdMixin
from ansible_collections.community.general.plugins.module_utils.mh.mixins.state import StateMixin
from ansible_collections.community.general.plugins.module_utils.mh.mixins.deps import DependencyMixin
from ansible_collections.community.general.plugins.module_utils.mh.mixins.vars import VarsMixin
@@ -65,19 +65,3 @@ class ModuleHelper(DeprecateAttrsMixin, VarsMixin, DependencyMixin, ModuleHelper
class StateModuleHelper(StateMixin, ModuleHelper):
pass
-
-
-class CmdModuleHelper(CmdMixin, ModuleHelper):
- """
- THIS CLASS IS BEING DEPRECATED.
- See the deprecation notice in ``CmdMixin.__init__()``.
- """
- pass
-
-
-class CmdStateModuleHelper(CmdMixin, StateMixin, ModuleHelper):
- """
- THIS CLASS IS BEING DEPRECATED.
- See the deprecation notice in ``CmdMixin.__init__()``.
- """
- pass
diff --git a/ansible_collections/community/general/plugins/module_utils/module_helper.py b/ansible_collections/community/general/plugins/module_utils/module_helper.py
index 8a51de665..5aa16c057 100644
--- a/ansible_collections/community/general/plugins/module_utils/module_helper.py
+++ b/ansible_collections/community/general/plugins/module_utils/module_helper.py
@@ -7,14 +7,16 @@
from __future__ import absolute_import, division, print_function
__metaclass__ = type
+# pylint: disable=unused-import
-from ansible_collections.community.general.plugins.module_utils.mh.module_helper import ( # noqa: F401, pylint: disable=unused-import
- ModuleHelper, StateModuleHelper, CmdModuleHelper, CmdStateModuleHelper, AnsibleModule
+
+from ansible_collections.community.general.plugins.module_utils.mh.module_helper import (
+ ModuleHelper, StateModuleHelper, AnsibleModule
+)
+from ansible_collections.community.general.plugins.module_utils.mh.mixins.state import StateMixin # noqa: F401
+from ansible_collections.community.general.plugins.module_utils.mh.mixins.deps import DependencyCtxMgr, DependencyMixin # noqa: F401
+from ansible_collections.community.general.plugins.module_utils.mh.exceptions import ModuleHelperException # noqa: F401
+from ansible_collections.community.general.plugins.module_utils.mh.deco import (
+ cause_changes, module_fails_on_exception, check_mode_skip, check_mode_skip_returns,
)
-from ansible_collections.community.general.plugins.module_utils.mh.mixins.cmd import CmdMixin, ArgFormat # noqa: F401, pylint: disable=unused-import
-from ansible_collections.community.general.plugins.module_utils.mh.mixins.state import StateMixin # noqa: F401, pylint: disable=unused-import
-from ansible_collections.community.general.plugins.module_utils.mh.mixins.deps import DependencyCtxMgr # noqa: F401, pylint: disable=unused-import
-from ansible_collections.community.general.plugins.module_utils.mh.exceptions import ModuleHelperException # noqa: F401, pylint: disable=unused-import
-# pylint: disable-next=unused-import
-from ansible_collections.community.general.plugins.module_utils.mh.deco import cause_changes, module_fails_on_exception # noqa: F401
-from ansible_collections.community.general.plugins.module_utils.mh.mixins.vars import VarMeta, VarDict # noqa: F401, pylint: disable=unused-import
+from ansible_collections.community.general.plugins.module_utils.mh.mixins.vars import VarMeta, VarDict, VarsMixin # noqa: F401
diff --git a/ansible_collections/community/general/plugins/module_utils/net_tools/pritunl/api.py b/ansible_collections/community/general/plugins/module_utils/net_tools/pritunl/api.py
index cd2abc568..cc6db257d 100644
--- a/ansible_collections/community/general/plugins/module_utils/net_tools/pritunl/api.py
+++ b/ansible_collections/community/general/plugins/module_utils/net_tools/pritunl/api.py
@@ -79,7 +79,7 @@ def _post_pritunl_organization(
api_secret=api_secret,
base_url=base_url,
method="POST",
- path="/organization/%s",
+ path="/organization",
headers={"Content-Type": "application/json"},
data=json.dumps(organization_data),
validate_certs=validate_certs,
@@ -220,7 +220,7 @@ def post_pritunl_organization(
api_secret=api_secret,
base_url=base_url,
organization_data={"name": organization_name},
- validate_certs=True,
+ validate_certs=validate_certs,
)
if response.getcode() != 200:
@@ -248,7 +248,7 @@ def post_pritunl_user(
base_url=base_url,
organization_id=organization_id,
user_data=user_data,
- validate_certs=True,
+ validate_certs=validate_certs,
)
if response.getcode() != 200:
@@ -267,7 +267,7 @@ def post_pritunl_user(
organization_id=organization_id,
user_data=user_data,
user_id=user_id,
- validate_certs=True,
+ validate_certs=validate_certs,
)
if response.getcode() != 200:
@@ -287,7 +287,7 @@ def delete_pritunl_organization(
api_secret=api_secret,
base_url=base_url,
organization_id=organization_id,
- validate_certs=True,
+ validate_certs=validate_certs,
)
if response.getcode() != 200:
@@ -307,7 +307,7 @@ def delete_pritunl_user(
base_url=base_url,
organization_id=organization_id,
user_id=user_id,
- validate_certs=True,
+ validate_certs=validate_certs,
)
if response.getcode() != 200:
@@ -331,7 +331,7 @@ def pritunl_auth_request(
):
"""
Send an API call to a Pritunl server.
- Taken from https://pritunl.com/api and adaped work with Ansible open_url
+ Taken from https://pritunl.com/api and adapted to work with Ansible open_url
"""
auth_timestamp = str(int(time.time()))
auth_nonce = uuid.uuid4().hex
diff --git a/ansible_collections/community/general/plugins/module_utils/ocapi_utils.py b/ansible_collections/community/general/plugins/module_utils/ocapi_utils.py
index acc2ceae4..232c91506 100644
--- a/ansible_collections/community/general/plugins/module_utils/ocapi_utils.py
+++ b/ansible_collections/community/general/plugins/module_utils/ocapi_utils.py
@@ -432,7 +432,7 @@ class OcapiUtils(object):
else:
return response
details = response["data"]["Status"].get("Details")
- if type(details) is str:
+ if isinstance(details, str):
details = [details]
health_list = response["data"]["Status"]["Health"]
return_value = {
diff --git a/ansible_collections/community/general/plugins/module_utils/oracle/oci_utils.py b/ansible_collections/community/general/plugins/module_utils/oracle/oci_utils.py
index 3d9c20f2a..392692e7d 100644
--- a/ansible_collections/community/general/plugins/module_utils/oracle/oci_utils.py
+++ b/ansible_collections/community/general/plugins/module_utils/oracle/oci_utils.py
@@ -434,7 +434,7 @@ def check_and_update_attributes(
target_instance, attr_name, input_value, existing_value, changed
):
"""
- This function checks the difference between two resource attributes of literal types and sets the attrbute
+ This function checks the difference between two resource attributes of literal types and sets the attribute
value in the target instance type holding the attribute.
:param target_instance: The instance which contains the attribute whose values to be compared
:param attr_name: Name of the attribute whose value required to be compared
@@ -561,7 +561,7 @@ def are_lists_equal(s, t):
if s is None and t is None:
return True
- if (s is None and len(t) >= 0) or (t is None and len(s) >= 0) or (len(s) != len(t)):
+ if s is None or t is None or (len(s) != len(t)):
return False
if len(s) == 0:
@@ -570,7 +570,7 @@ def are_lists_equal(s, t):
s = to_dict(s)
t = to_dict(t)
- if type(s[0]) == dict:
+ if isinstance(s[0], dict):
# Handle list of dicts. Dictionary returned by the API may have additional keys. For example, a get call on
# service gateway has an attribute `services` which is a list of `ServiceIdResponseDetails`. This has a key
# `service_name` which is not provided in the list of `services` by a user while making an update call; only
@@ -604,9 +604,9 @@ def get_attr_to_update(get_fn, kwargs_get, module, update_attributes):
user_provided_attr_value = module.params.get(attr, None)
unequal_list_attr = (
- type(resources_attr_value) == list or type(user_provided_attr_value) == list
+ isinstance(resources_attr_value, list) or isinstance(user_provided_attr_value, list)
) and not are_lists_equal(user_provided_attr_value, resources_attr_value)
- unequal_attr = type(resources_attr_value) != list and to_dict(
+ unequal_attr = not isinstance(resources_attr_value, list) and to_dict(
resources_attr_value
) != to_dict(user_provided_attr_value)
if unequal_list_attr or unequal_attr:
@@ -785,7 +785,7 @@ def _get_attributes_to_consider(exclude_attributes, model, module):
attributes_to_consider = list(model.attribute_map)
if "freeform_tags" in attributes_to_consider:
attributes_to_consider.remove("freeform_tags")
- # Temporarily removing node_count as the exisiting resource does not reflect it
+ # Temporarily removing node_count as the existing resource does not reflect it
if "node_count" in attributes_to_consider:
attributes_to_consider.remove("node_count")
_debug("attributes to consider: {0}".format(attributes_to_consider))
@@ -936,9 +936,9 @@ def tuplize(d):
list_of_tuples = []
key_list = sorted(list(d.keys()))
for key in key_list:
- if type(d[key]) == list:
+ if isinstance(d[key], list):
# Convert a value which is itself a list of dict to a list of tuples.
- if d[key] and type(d[key][0]) == dict:
+ if d[key] and isinstance(d[key][0], dict):
sub_tuples = []
for sub_dict in d[key]:
sub_tuples.append(tuplize(sub_dict))
@@ -948,7 +948,7 @@ def tuplize(d):
list_of_tuples.append((sub_tuples is None, key, sub_tuples))
else:
list_of_tuples.append((d[key] is None, key, d[key]))
- elif type(d[key]) == dict:
+ elif isinstance(d[key], dict):
tupled_value = tuplize(d[key])
list_of_tuples.append((tupled_value is None, key, tupled_value))
else:
@@ -969,13 +969,13 @@ def sort_dictionary(d):
"""
sorted_d = {}
for key in d:
- if type(d[key]) == list:
- if d[key] and type(d[key][0]) == dict:
+ if isinstance(d[key], list):
+ if d[key] and isinstance(d[key][0], dict):
sorted_value = sort_list_of_dictionary(d[key])
sorted_d[key] = sorted_value
else:
sorted_d[key] = sorted(d[key])
- elif type(d[key]) == dict:
+ elif isinstance(d[key], dict):
sorted_d[key] = sort_dictionary(d[key])
else:
sorted_d[key] = d[key]
@@ -1026,10 +1026,7 @@ def check_if_user_value_matches_resources_attr(
return
if (
- resources_value_for_attr is None
- and len(user_provided_value_for_attr) >= 0
- or user_provided_value_for_attr is None
- and len(resources_value_for_attr) >= 0
+ resources_value_for_attr is None or user_provided_value_for_attr is None
):
res[0] = False
return
@@ -1044,7 +1041,7 @@ def check_if_user_value_matches_resources_attr(
if (
user_provided_value_for_attr
- and type(user_provided_value_for_attr[0]) == dict
+ and isinstance(user_provided_value_for_attr[0], dict)
):
# Process a list of dict
sorted_user_provided_value_for_attr = sort_list_of_dictionary(
@@ -1532,7 +1529,7 @@ def delete_and_wait(
result[resource_type] = resource
return result
# oci.wait_until() returns an instance of oci.util.Sentinel in case the resource is not found.
- if type(wait_response) is not Sentinel:
+ if not isinstance(wait_response, Sentinel):
resource = to_dict(wait_response.data)
else:
resource["lifecycle_state"] = "DELETED"
@@ -1547,7 +1544,7 @@ def delete_and_wait(
except ServiceError as ex:
# DNS API throws a 400 InvalidParameter when a zone id is provided for zone_name_or_id and if the zone
# resource is not available, instead of the expected 404. So working around this for now.
- if type(client) == oci.dns.DnsClient:
+ if isinstance(client, oci.dns.DnsClient):
if ex.status == 400 and ex.code == "InvalidParameter":
_debug(
"Resource {0} with {1} already deleted. So returning changed=False".format(
@@ -1774,7 +1771,7 @@ def update_class_type_attr_difference(
):
"""
Checks the difference and updates an attribute which is represented by a class
- instance. Not aplicable if the attribute type is a primitive value.
+ instance. Not applicable if the attribute type is a primitive value.
For example, if a class name is A with an attribute x, then if A.x = X(), then only
this method works.
:param update_class_details The instance which should be updated if there is change in
@@ -1936,7 +1933,7 @@ def get_target_resource_from_list(
module, list_resource_fn, target_resource_id=None, **kwargs
):
"""
- Returns a resource filtered by identifer from a list of resources. This method should be
+ Returns a resource filtered by identifier from a list of resources. This method should be
used as an alternative of 'get resource' method when 'get resource' is nor provided by
resource api. This method returns a wrapper of response object but that should not be
used as an input to 'wait_until' utility as this is only a partial wrapper of response object.
diff --git a/ansible_collections/community/general/plugins/module_utils/pipx.py b/ansible_collections/community/general/plugins/module_utils/pipx.py
index 2f19f352d..a385ec93e 100644
--- a/ansible_collections/community/general/plugins/module_utils/pipx.py
+++ b/ansible_collections/community/general/plugins/module_utils/pipx.py
@@ -42,7 +42,7 @@ def pipx_runner(module, command, **kwargs):
system_site_packages=fmt.as_bool("--system-site-packages"),
_list=fmt.as_fixed(['list', '--include-injected', '--json']),
editable=fmt.as_bool("--editable"),
- pip_args=fmt.as_opt_val('--pip-args'),
+ pip_args=fmt.as_opt_eq_val('--pip-args'),
),
environ_update={'USE_EMOJI': '0'},
check_rc=True,
diff --git a/ansible_collections/community/general/plugins/module_utils/proxmox.py b/ansible_collections/community/general/plugins/module_utils/proxmox.py
index 58287cec1..5fd783d65 100644
--- a/ansible_collections/community/general/plugins/module_utils/proxmox.py
+++ b/ansible_collections/community/general/plugins/module_utils/proxmox.py
@@ -7,17 +7,12 @@
from __future__ import absolute_import, division, print_function
__metaclass__ = type
-# (TODO: remove next line!)
-import atexit # noqa: F401, pylint: disable=unused-import
-# (TODO: remove next line!)
-import time # noqa: F401, pylint: disable=unused-import
-# (TODO: remove next line!)
-import re # noqa: F401, pylint: disable=unused-import
import traceback
PROXMOXER_IMP_ERR = None
try:
from proxmoxer import ProxmoxAPI
+ from proxmoxer import __version__ as proxmoxer_version
HAS_PROXMOXER = True
except ImportError:
HAS_PROXMOXER = False
@@ -25,8 +20,6 @@ except ImportError:
from ansible.module_utils.basic import env_fallback, missing_required_lib
-# (TODO: remove next line!)
-from ansible.module_utils.common.text.converters import to_native # noqa: F401, pylint: disable=unused-import
from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
@@ -79,6 +72,7 @@ class ProxmoxAnsible(object):
module.fail_json(msg=missing_required_lib('proxmoxer'), exception=PROXMOXER_IMP_ERR)
self.module = module
+ self.proxmoxer_version = proxmoxer_version
self.proxmox_api = self._connect()
# Test token validity
try:
@@ -98,6 +92,8 @@ class ProxmoxAnsible(object):
if api_password:
auth_args['password'] = api_password
else:
+ if self.proxmoxer_version < LooseVersion('1.1.0'):
+ self.module.fail_json('Using "token_name" and "token_value" require proxmoxer>=1.1.0')
auth_args['token_name'] = api_token_id
auth_args['token_value'] = api_token_secret
@@ -107,19 +103,30 @@ class ProxmoxAnsible(object):
self.module.fail_json(msg='%s' % e, exception=traceback.format_exc())
def version(self):
- apireturn = self.proxmox_api.version.get()
- return LooseVersion(apireturn['version'])
+ try:
+ apiversion = self.proxmox_api.version.get()
+ return LooseVersion(apiversion['version'])
+ except Exception as e:
+ self.module.fail_json(msg='Unable to retrieve Proxmox VE version: %s' % e)
def get_node(self, node):
- nodes = [n for n in self.proxmox_api.nodes.get() if n['node'] == node]
+ try:
+ nodes = [n for n in self.proxmox_api.nodes.get() if n['node'] == node]
+ except Exception as e:
+ self.module.fail_json(msg='Unable to retrieve Proxmox VE node: %s' % e)
return nodes[0] if nodes else None
def get_nextvmid(self):
- vmid = self.proxmox_api.cluster.nextid.get()
- return vmid
+ try:
+ return self.proxmox_api.cluster.nextid.get()
+ except Exception as e:
+ self.module.fail_json(msg='Unable to retrieve next free vmid: %s' % e)
def get_vmid(self, name, ignore_missing=False, choose_first_if_multiple=False):
- vms = [vm['vmid'] for vm in self.proxmox_api.cluster.resources.get(type='vm') if vm.get('name') == name]
+ try:
+ vms = [vm['vmid'] for vm in self.proxmox_api.cluster.resources.get(type='vm') if vm.get('name') == name]
+ except Exception as e:
+ self.module.fail_json(msg='Unable to retrieve list of VMs filtered by name %s: %s' % (name, e))
if not vms:
if ignore_missing:
@@ -132,7 +139,10 @@ class ProxmoxAnsible(object):
return vms[0]
def get_vm(self, vmid, ignore_missing=False):
- vms = [vm for vm in self.proxmox_api.cluster.resources.get(type='vm') if vm['vmid'] == int(vmid)]
+ try:
+ vms = [vm for vm in self.proxmox_api.cluster.resources.get(type='vm') if vm['vmid'] == int(vmid)]
+ except Exception as e:
+ self.module.fail_json(msg='Unable to retrieve list of VMs filtered by vmid %s: %s' % (vmid, e))
if vms:
return vms[0]
@@ -143,5 +153,44 @@ class ProxmoxAnsible(object):
self.module.fail_json(msg='VM with vmid %s does not exist in cluster' % vmid)
def api_task_ok(self, node, taskid):
- status = self.proxmox_api.nodes(node).tasks(taskid).status.get()
- return status['status'] == 'stopped' and status['exitstatus'] == 'OK'
+ try:
+ status = self.proxmox_api.nodes(node).tasks(taskid).status.get()
+ return status['status'] == 'stopped' and status['exitstatus'] == 'OK'
+ except Exception as e:
+ self.module.fail_json(msg='Unable to retrieve API task ID from node %s: %s' % (node, e))
+
+ def get_pool(self, poolid):
+ """Retrieve pool information
+
+ :param poolid: str - name of the pool
+ :return: dict - pool information
+ """
+ try:
+ return self.proxmox_api.pools(poolid).get()
+ except Exception as e:
+ self.module.fail_json(msg="Unable to retrieve pool %s information: %s" % (poolid, e))
+
+ def get_storages(self, type):
+ """Retrieve storages information
+
+ :param type: str, optional - type of storages
+ :return: list of dicts - array of storages
+ """
+ try:
+ return self.proxmox_api.storage.get(type=type)
+ except Exception as e:
+ self.module.fail_json(msg="Unable to retrieve storages information with type %s: %s" % (type, e))
+
+ def get_storage_content(self, node, storage, content=None, vmid=None):
+ try:
+ return (
+ self.proxmox_api.nodes(node)
+ .storage(storage)
+ .content()
+ .get(content=content, vmid=vmid)
+ )
+ except Exception as e:
+ self.module.fail_json(
+ msg="Unable to list content on %s, %s for %s and %s: %s"
+ % (node, storage, content, vmid, e)
+ )
diff --git a/ansible_collections/community/general/plugins/module_utils/redfish_utils.py b/ansible_collections/community/general/plugins/module_utils/redfish_utils.py
index 9b6470302..4c2057129 100644
--- a/ansible_collections/community/general/plugins/module_utils/redfish_utils.py
+++ b/ansible_collections/community/general/plugins/module_utils/redfish_utils.py
@@ -7,12 +7,21 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type
import json
+import os
+import random
+import string
+import gzip
+from io import BytesIO
from ansible.module_utils.urls import open_url
from ansible.module_utils.common.text.converters import to_native
from ansible.module_utils.common.text.converters import to_text
+from ansible.module_utils.common.text.converters import to_bytes
+from ansible.module_utils.six import text_type
from ansible.module_utils.six.moves import http_client
from ansible.module_utils.six.moves.urllib.error import URLError, HTTPError
from ansible.module_utils.six.moves.urllib.parse import urlparse
+from ansible.module_utils.ansible_release import __version__ as ansible_version
+from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
GET_HEADERS = {'accept': 'application/json', 'OData-Version': '4.0'}
POST_HEADERS = {'content-type': 'application/json', 'accept': 'application/json',
@@ -123,8 +132,10 @@ class RedfishUtils(object):
return resp
# The following functions are to send GET/POST/PATCH/DELETE requests
- def get_request(self, uri):
+ def get_request(self, uri, override_headers=None, allow_no_resp=False):
req_headers = dict(GET_HEADERS)
+ if override_headers:
+ req_headers.update(override_headers)
username, password, basic_auth = self._auth_params(req_headers)
try:
# Service root is an unauthenticated resource; remove credentials
@@ -136,8 +147,19 @@ class RedfishUtils(object):
force_basic_auth=basic_auth, validate_certs=False,
follow_redirects='all',
use_proxy=True, timeout=self.timeout)
- data = json.loads(to_native(resp.read()))
headers = dict((k.lower(), v) for (k, v) in resp.info().items())
+ try:
+ if headers.get('content-encoding') == 'gzip' and LooseVersion(ansible_version) < LooseVersion('2.14'):
+ # Older versions of Ansible do not automatically decompress the data
+ # Starting in 2.14, open_url will decompress the response data by default
+ data = json.loads(to_native(gzip.open(BytesIO(resp.read()), 'rt', encoding='utf-8').read()))
+ else:
+ data = json.loads(to_native(resp.read()))
+ except Exception as e:
+ # No response data; this is okay in certain cases
+ data = None
+ if not allow_no_resp:
+ raise
except HTTPError as e:
msg = self._get_extended_message(e)
return {'ret': False,
@@ -153,7 +175,7 @@ class RedfishUtils(object):
'msg': "Failed GET request to '%s': '%s'" % (uri, to_text(e))}
return {'ret': True, 'data': data, 'headers': headers, 'resp': resp}
- def post_request(self, uri, pyld):
+ def post_request(self, uri, pyld, multipart=False):
req_headers = dict(POST_HEADERS)
username, password, basic_auth = self._auth_params(req_headers)
try:
@@ -162,7 +184,14 @@ class RedfishUtils(object):
# header since this can cause conflicts with some services
if self.sessions_uri is not None and uri == (self.root_uri + self.sessions_uri):
basic_auth = False
- resp = open_url(uri, data=json.dumps(pyld),
+ if multipart:
+ # Multipart requests require special handling to encode the request body
+ multipart_encoder = self._prepare_multipart(pyld)
+ data = multipart_encoder[0]
+ req_headers['content-type'] = multipart_encoder[1]
+ else:
+ data = json.dumps(pyld)
+ resp = open_url(uri, data=data,
headers=req_headers, method="POST",
url_username=username, url_password=password,
force_basic_auth=basic_auth, validate_certs=False,
@@ -299,6 +328,59 @@ class RedfishUtils(object):
return {'ret': True, 'resp': resp}
@staticmethod
+ def _prepare_multipart(fields):
+ """Prepares a multipart body based on a set of fields provided.
+
+ Ideally it would have been good to use the existing 'prepare_multipart'
+ found in ansible.module_utils.urls, but it takes files and encodes them
+ as Base64 strings, which is not expected by Redfish services. It also
+ adds escaping of certain bytes in the payload, such as inserting '\r'
+ any time it finds a standalone '\n', which corrupts the image payload
+ send to the service. This implementation is simplified to Redfish's
+ usage and doesn't necessarily represent an exhaustive method of
+ building multipart requests.
+ """
+
+ def write_buffer(body, line):
+ # Adds to the multipart body based on the provided data type
+ # At this time there is only support for strings, dictionaries, and bytes (default)
+ if isinstance(line, text_type):
+ body.append(to_bytes(line, encoding='utf-8'))
+ elif isinstance(line, dict):
+ body.append(to_bytes(json.dumps(line), encoding='utf-8'))
+ else:
+ body.append(line)
+ return
+
+ # Generate a random boundary marker; may need to consider probing the
+ # payload for potential conflicts in the future
+ boundary = ''.join(random.choice(string.digits + string.ascii_letters) for i in range(30))
+ body = []
+ for form in fields:
+ # Fill in the form details
+ write_buffer(body, '--' + boundary)
+
+ # Insert the headers (Content-Disposition and Content-Type)
+ if 'filename' in fields[form]:
+ name = os.path.basename(fields[form]['filename']).replace('"', '\\"')
+ write_buffer(body, u'Content-Disposition: form-data; name="%s"; filename="%s"' % (to_text(form), to_text(name)))
+ else:
+ write_buffer(body, 'Content-Disposition: form-data; name="%s"' % form)
+ write_buffer(body, 'Content-Type: %s' % fields[form]['mime_type'])
+ write_buffer(body, '')
+
+ # Insert the payload; read from the file if not given by the caller
+ if 'content' not in fields[form]:
+ with open(to_bytes(fields[form]['filename'], errors='surrogate_or_strict'), 'rb') as f:
+ fields[form]['content'] = f.read()
+ write_buffer(body, fields[form]['content'])
+
+ # Finalize the entire request
+ write_buffer(body, '--' + boundary + '--')
+ write_buffer(body, '')
+ return (b'\r\n'.join(body), 'multipart/form-data; boundary=' + boundary)
+
+ @staticmethod
def _get_extended_message(error):
"""
Get Redfish ExtendedInfo message from response payload if present
@@ -652,7 +734,8 @@ class RedfishUtils(object):
properties = ['CacheSummary', 'FirmwareVersion', 'Identifiers',
'Location', 'Manufacturer', 'Model', 'Name', 'Id',
'PartNumber', 'SerialNumber', 'SpeedGbps', 'Status']
- key = "StorageControllers"
+ key = "Controllers"
+ deprecated_key = "StorageControllers"
# Find Storage service
response = self.get_request(self.root_uri + systems_uri)
@@ -680,7 +763,30 @@ class RedfishUtils(object):
data = response['data']
if key in data:
- controller_list = data[key]
+ controllers_uri = data[key][u'@odata.id']
+
+ response = self.get_request(self.root_uri + controllers_uri)
+ if response['ret'] is False:
+ return response
+ result['ret'] = True
+ data = response['data']
+
+ if data[u'Members']:
+ for controller_member in data[u'Members']:
+ controller_member_uri = controller_member[u'@odata.id']
+ response = self.get_request(self.root_uri + controller_member_uri)
+ if response['ret'] is False:
+ return response
+ result['ret'] = True
+ data = response['data']
+
+ controller_result = {}
+ for property in properties:
+ if property in data:
+ controller_result[property] = data[property]
+ controller_results.append(controller_result)
+ elif deprecated_key in data:
+ controller_list = data[deprecated_key]
for controller in controller_list:
controller_result = {}
for property in properties:
@@ -702,7 +808,7 @@ class RedfishUtils(object):
properties = ['BlockSizeBytes', 'CapableSpeedGbs', 'CapacityBytes',
'EncryptionAbility', 'EncryptionStatus',
'FailurePredicted', 'HotspareType', 'Id', 'Identifiers',
- 'Manufacturer', 'MediaType', 'Model', 'Name',
+ 'Links', 'Manufacturer', 'MediaType', 'Model', 'Name',
'PartNumber', 'PhysicalLocation', 'Protocol', 'Revision',
'RotationSpeedRPM', 'SerialNumber', 'Status']
@@ -735,7 +841,25 @@ class RedfishUtils(object):
return response
data = response['data']
controller_name = 'Controller 1'
- if 'StorageControllers' in data:
+ if 'Controllers' in data:
+ controllers_uri = data['Controllers'][u'@odata.id']
+
+ response = self.get_request(self.root_uri + controllers_uri)
+ if response['ret'] is False:
+ return response
+ result['ret'] = True
+ cdata = response['data']
+
+ if cdata[u'Members']:
+ controller_member_uri = cdata[u'Members'][0][u'@odata.id']
+
+ response = self.get_request(self.root_uri + controller_member_uri)
+ if response['ret'] is False:
+ return response
+ result['ret'] = True
+ cdata = response['data']
+ controller_name = cdata['Name']
+ elif 'StorageControllers' in data:
sc = data['StorageControllers']
if sc:
if 'Name' in sc[0]:
@@ -754,7 +878,12 @@ class RedfishUtils(object):
for property in properties:
if property in data:
if data[property] is not None:
- drive_result[property] = data[property]
+ if property == "Links":
+ if "Volumes" in data["Links"].keys():
+ volumes = [v["@odata.id"] for v in data["Links"]["Volumes"]]
+ drive_result["Volumes"] = volumes
+ else:
+ drive_result[property] = data[property]
drive_results.append(drive_result)
drives = {'Controller': controller_name,
'Drives': drive_results}
@@ -832,14 +961,32 @@ class RedfishUtils(object):
if data.get('Members'):
for controller in data[u'Members']:
controller_list.append(controller[u'@odata.id'])
- for c in controller_list:
+ for idx, c in enumerate(controller_list):
uri = self.root_uri + c
response = self.get_request(uri)
if response['ret'] is False:
return response
data = response['data']
- controller_name = 'Controller 1'
- if 'StorageControllers' in data:
+ controller_name = 'Controller %s' % str(idx)
+ if 'Controllers' in data:
+ response = self.get_request(self.root_uri + data['Controllers'][u'@odata.id'])
+ if response['ret'] is False:
+ return response
+ c_data = response['data']
+
+ if c_data.get('Members') and c_data['Members']:
+ response = self.get_request(self.root_uri + c_data['Members'][0][u'@odata.id'])
+ if response['ret'] is False:
+ return response
+ member_data = response['data']
+
+ if member_data:
+ if 'Name' in member_data:
+ controller_name = member_data['Name']
+ else:
+ controller_id = member_data.get('Id', '1')
+ controller_name = 'Controller %s' % controller_id
+ elif 'StorageControllers' in data:
sc = data['StorageControllers']
if sc:
if 'Name' in sc[0]:
@@ -848,6 +995,7 @@ class RedfishUtils(object):
sc_id = sc[0].get('Id', '1')
controller_name = 'Controller %s' % sc_id
volume_results = []
+ volume_list = []
if 'Volumes' in data:
# Get a list of all volumes and build respective URIs
volumes_uri = data[u'Volumes'][u'@odata.id']
@@ -948,7 +1096,12 @@ class RedfishUtils(object):
# command should be PowerOn, PowerForceOff, etc.
if not command.startswith('Power'):
return {'ret': False, 'msg': 'Invalid Command (%s)' % command}
- reset_type = command[5:]
+
+ # Commands (except PowerCycle) will be stripped of the 'Power' prefix
+ if command == 'PowerCycle':
+ reset_type = command
+ else:
+ reset_type = command[5:]
# map Reboot to a ResetType that does a reboot
if reset_type == 'Reboot':
@@ -1056,7 +1209,8 @@ class RedfishUtils(object):
user_list = []
users_results = []
# Get these entries, but does not fail if not found
- properties = ['Id', 'Name', 'UserName', 'RoleId', 'Locked', 'Enabled']
+ properties = ['Id', 'Name', 'UserName', 'RoleId', 'Locked', 'Enabled',
+ 'AccountTypes', 'OEMAccountTypes']
response = self.get_request(self.root_uri + self.accounts_uri)
if response['ret'] is False:
@@ -1079,6 +1233,12 @@ class RedfishUtils(object):
if property in data:
user[property] = data[property]
+ # Filter out empty account slots
+ # An empty account slot can be detected if the username is an empty
+ # string and if the account is disabled
+ if user.get('UserName', '') == '' and not user.get('Enabled', False):
+ continue
+
users_results.append(user)
result["entries"] = users_results
return result
@@ -1101,6 +1261,10 @@ class RedfishUtils(object):
payload['Password'] = user.get('account_password')
if user.get('account_roleid'):
payload['RoleId'] = user.get('account_roleid')
+ if user.get('account_accounttypes'):
+ payload['AccountTypes'] = user.get('account_accounttypes')
+ if user.get('account_oemaccounttypes'):
+ payload['OEMAccountTypes'] = user.get('account_oemaccounttypes')
return self.patch_request(self.root_uri + uri, payload, check_pyld=True)
def add_user(self, user):
@@ -1131,6 +1295,10 @@ class RedfishUtils(object):
payload['Password'] = user.get('account_password')
if user.get('account_roleid'):
payload['RoleId'] = user.get('account_roleid')
+ if user.get('account_accounttypes'):
+ payload['AccountTypes'] = user.get('account_accounttypes')
+ if user.get('account_oemaccounttypes'):
+ payload['OEMAccountTypes'] = user.get('account_oemaccounttypes')
if user.get('account_id'):
payload['Id'] = user.get('account_id')
@@ -1400,29 +1568,37 @@ class RedfishUtils(object):
def _software_inventory(self, uri):
result = {}
- response = self.get_request(self.root_uri + uri)
- if response['ret'] is False:
- return response
- result['ret'] = True
- data = response['data']
-
result['entries'] = []
- for member in data[u'Members']:
- uri = self.root_uri + member[u'@odata.id']
- # Get details for each software or firmware member
- response = self.get_request(uri)
+
+ while uri:
+ response = self.get_request(self.root_uri + uri)
if response['ret'] is False:
return response
result['ret'] = True
+
data = response['data']
- software = {}
- # Get these standard properties if present
- for key in ['Name', 'Id', 'Status', 'Version', 'Updateable',
- 'SoftwareId', 'LowestSupportedVersion', 'Manufacturer',
- 'ReleaseDate']:
- if key in data:
- software[key] = data.get(key)
- result['entries'].append(software)
+ if data.get('Members@odata.nextLink'):
+ uri = data.get('Members@odata.nextLink')
+ else:
+ uri = None
+
+ for member in data[u'Members']:
+ fw_uri = self.root_uri + member[u'@odata.id']
+ # Get details for each software or firmware member
+ response = self.get_request(fw_uri)
+ if response['ret'] is False:
+ return response
+ result['ret'] = True
+ data = response['data']
+ software = {}
+ # Get these standard properties if present
+ for key in ['Name', 'Id', 'Status', 'Version', 'Updateable',
+ 'SoftwareId', 'LowestSupportedVersion', 'Manufacturer',
+ 'ReleaseDate']:
+ if key in data:
+ software[key] = data.get(key)
+ result['entries'].append(software)
+
return result
def get_firmware_inventory(self):
@@ -1490,7 +1666,10 @@ class RedfishUtils(object):
# Scan the messages to see if next steps are needed
for message in operation_results['messages']:
- message_id = message['MessageId']
+ message_id = message.get('MessageId')
+ if message_id is None:
+ # While this is invalid, treat the lack of a MessageId as "no message"
+ continue
if message_id.startswith('Update.1.') and message_id.endswith('.OperationTransitionedToJob'):
# Operation rerouted to a job; update the status and handle
@@ -1572,6 +1751,64 @@ class RedfishUtils(object):
'msg': "SimpleUpdate requested",
'update_status': self._operation_results(response['resp'], response['data'])}
+ def multipath_http_push_update(self, update_opts):
+ """
+ Provides a software update via the URI specified by the
+ MultipartHttpPushUri property. Callers should adjust the 'timeout'
+ variable in the base object to accommodate the size of the image and
+ speed of the transfer. For example, a 200MB image will likely take
+ more than the default 10 second timeout.
+
+ :param update_opts: The parameters for the update operation
+ :return: dict containing the response of the update request
+ """
+ image_file = update_opts.get('update_image_file')
+ targets = update_opts.get('update_targets')
+ apply_time = update_opts.get('update_apply_time')
+ oem_params = update_opts.get('update_oem_params')
+
+ # Ensure the image file is provided
+ if not image_file:
+ return {'ret': False, 'msg':
+ 'Must specify update_image_file for the MultipartHTTPPushUpdate command'}
+ if not os.path.isfile(image_file):
+ return {'ret': False, 'msg':
+ 'Must specify a valid file for the MultipartHTTPPushUpdate command'}
+ try:
+ with open(image_file, 'rb') as f:
+ image_payload = f.read()
+ except Exception as e:
+ return {'ret': False, 'msg':
+ 'Could not read file %s' % image_file}
+
+ # Check that multipart HTTP push updates are supported
+ response = self.get_request(self.root_uri + self.update_uri)
+ if response['ret'] is False:
+ return response
+ data = response['data']
+ if 'MultipartHttpPushUri' not in data:
+ return {'ret': False, 'msg': 'Service does not support MultipartHttpPushUri'}
+ update_uri = data['MultipartHttpPushUri']
+
+ # Assemble the JSON payload portion of the request
+ payload = {"@Redfish.OperationApplyTime": "Immediate"}
+ if targets:
+ payload["Targets"] = targets
+ if apply_time:
+ payload["@Redfish.OperationApplyTime"] = apply_time
+ if oem_params:
+ payload["Oem"] = oem_params
+ multipart_payload = {
+ 'UpdateParameters': {'content': json.dumps(payload), 'mime_type': 'application/json'},
+ 'UpdateFile': {'filename': image_file, 'content': image_payload, 'mime_type': 'application/octet-stream'}
+ }
+ response = self.post_request(self.root_uri + update_uri, multipart_payload, multipart=True)
+ if response['ret'] is False:
+ return response
+ return {'ret': True, 'changed': True,
+ 'msg': "MultipartHTTPPushUpdate requested",
+ 'update_status': self._operation_results(response['resp'], response['data'])}
+
def get_update_status(self, update_handle):
"""
Gets the status of an update operation.
@@ -1584,7 +1821,7 @@ class RedfishUtils(object):
return {'ret': False, 'msg': 'Must provide a handle tracking the update.'}
# Get the task or job tracking the update
- response = self.get_request(self.root_uri + update_handle)
+ response = self.get_request(self.root_uri + update_handle, allow_no_resp=True)
if response['ret'] is False:
return response
@@ -2142,7 +2379,7 @@ class RedfishUtils(object):
key = "Processors"
# Get these entries, but does not fail if not found
properties = ['Id', 'Name', 'Manufacturer', 'Model', 'MaxSpeedMHz',
- 'TotalCores', 'TotalThreads', 'Status']
+ 'ProcessorArchitecture', 'TotalCores', 'TotalThreads', 'Status']
# Search for 'key' entry and extract URI from it
response = self.get_request(self.root_uri + systems_uri)
@@ -2246,7 +2483,7 @@ class RedfishUtils(object):
result = {}
properties = ['Name', 'Id', 'Description', 'FQDN', 'IPv4Addresses', 'IPv6Addresses',
'NameServers', 'MACAddress', 'PermanentMACAddress',
- 'SpeedMbps', 'MTUSize', 'AutoNeg', 'Status']
+ 'SpeedMbps', 'MTUSize', 'AutoNeg', 'Status', 'LinkStatus']
response = self.get_request(self.root_uri + resource_uri)
if response['ret'] is False:
return response
@@ -2678,8 +2915,7 @@ class RedfishUtils(object):
# Get a list of all Chassis and build URIs, then get all PowerSupplies
# from each Power entry in the Chassis
- chassis_uri_list = self.chassis_uris
- for chassis_uri in chassis_uri_list:
+ for chassis_uri in self.chassis_uris:
response = self.get_request(self.root_uri + chassis_uri)
if response['ret'] is False:
return response
@@ -2726,7 +2962,7 @@ class RedfishUtils(object):
result = {}
inventory = {}
# Get these entries, but does not fail if not found
- properties = ['Status', 'HostName', 'PowerState', 'Model', 'Manufacturer',
+ properties = ['Status', 'HostName', 'PowerState', 'BootProgress', 'Model', 'Manufacturer',
'PartNumber', 'SystemType', 'AssetTag', 'ServiceTag',
'SerialNumber', 'SKU', 'BiosVersion', 'MemorySummary',
'ProcessorSummary', 'TrustedModules', 'Name', 'Id']
@@ -3135,8 +3371,9 @@ class RedfishUtils(object):
result = {}
inventory = {}
# Get these entries, but does not fail if not found
- properties = ['FirmwareVersion', 'ManagerType', 'Manufacturer', 'Model',
- 'PartNumber', 'PowerState', 'SerialNumber', 'Status', 'UUID']
+ properties = ['Id', 'FirmwareVersion', 'ManagerType', 'Manufacturer', 'Model',
+ 'PartNumber', 'PowerState', 'SerialNumber', 'ServiceIdentification',
+ 'Status', 'UUID']
response = self.get_request(self.root_uri + manager_uri)
if response['ret'] is False:
@@ -3154,6 +3391,35 @@ class RedfishUtils(object):
def get_multi_manager_inventory(self):
return self.aggregate_managers(self.get_manager_inventory)
+ def get_service_identification(self, manager):
+ result = {}
+ if manager is None:
+ if len(self.manager_uris) == 1:
+ manager = self.manager_uris[0].split('/')[-1]
+ elif len(self.manager_uris) > 1:
+ entries = self.get_multi_manager_inventory()['entries']
+ managers = [m[0]['manager_uri'] for m in entries if m[1].get('ServiceIdentification')]
+ if len(managers) == 1:
+ manager = managers[0].split('/')[-1]
+ else:
+ self.module.fail_json(msg=[
+ "Multiple managers with ServiceIdentification were found: %s" % str(managers),
+ "Please specify by using the 'manager' parameter in your playbook"])
+ elif len(self.manager_uris) == 0:
+ self.module.fail_json(msg="No manager identities were found")
+ response = self.get_request(self.root_uri + '/redfish/v1/Managers/' + manager, override_headers=None)
+ try:
+ result['service_identification'] = response['data']['ServiceIdentification']
+ except Exception as e:
+ self.module.fail_json(msg="Service ID not found for manager %s" % manager)
+ result['ret'] = True
+ return result
+
+ def set_service_identification(self, service_id):
+ data = {"ServiceIdentification": service_id}
+ resp = self.patch_request(self.root_uri + '/redfish/v1/Managers/' + self.resource_id, data, check_pyld=True)
+ return resp
+
def set_session_service(self, sessions_config):
if sessions_config is None:
return {'ret': False, 'msg':
@@ -3218,34 +3484,285 @@ class RedfishUtils(object):
return self.patch_request(self.root_uri + secure_boot_url, body, check_pyld=True)
+ def set_secure_boot(self, secure_boot_enable):
+ # This function enable Secure Boot on an OOB controller
+
+ response = self.get_request(self.root_uri + self.systems_uri)
+ if response["ret"] is False:
+ return response
+
+ server_details = response["data"]
+ secure_boot_url = server_details["SecureBoot"]["@odata.id"]
+
+ response = self.get_request(self.root_uri + secure_boot_url)
+ if response["ret"] is False:
+ return response
+
+ body = {}
+ body["SecureBootEnable"] = secure_boot_enable
+
+ return self.patch_request(self.root_uri + secure_boot_url, body, check_pyld=True)
+
def get_hpe_thermal_config(self):
result = {}
key = "Thermal"
# Go through list
- for chassis_uri in self.chassis_uri_list:
+ for chassis_uri in self.chassis_uris:
response = self.get_request(self.root_uri + chassis_uri)
if response['ret'] is False:
return response
result['ret'] = True
data = response['data']
- oem = data.get['Oem']
- hpe = oem.get['Hpe']
- thermal_config = hpe.get('ThermalConfiguration')
- result["current_thermal_config"] = thermal_config
- return result
+ val = data.get('Oem', {}).get('Hpe', {}).get('ThermalConfiguration')
+ if val is not None:
+ return {"ret": True, "current_thermal_config": val}
+ return {"ret": False}
def get_hpe_fan_percent_min(self):
result = {}
key = "Thermal"
# Go through list
- for chassis_uri in self.chassis_uri_list:
+ for chassis_uri in self.chassis_uris:
response = self.get_request(self.root_uri + chassis_uri)
if response['ret'] is False:
return response
- result['ret'] = True
data = response['data']
- oem = data.get['Oem']
- hpe = oem.get['Hpe']
- fan_percent_min_config = hpe.get('FanPercentMinimum')
- result["fan_percent_min"] = fan_percent_min_config
- return result
+ val = data.get('Oem', {}).get('Hpe', {}).get('FanPercentMinimum')
+ if val is not None:
+ return {"ret": True, "fan_percent_min": val}
+ return {"ret": False}
+
+ def delete_volumes(self, storage_subsystem_id, volume_ids):
+ # Find the Storage resource from the requested ComputerSystem resource
+ response = self.get_request(self.root_uri + self.systems_uri)
+ if response['ret'] is False:
+ return response
+ data = response['data']
+ storage_uri = data.get('Storage', {}).get('@odata.id')
+ if storage_uri is None:
+ return {'ret': False, 'msg': 'Storage resource not found'}
+
+ # Get Storage Collection
+ response = self.get_request(self.root_uri + storage_uri)
+ if response['ret'] is False:
+ return response
+ data = response['data']
+
+ # Collect Storage Subsystems
+ self.storage_subsystems_uris = [i['@odata.id'] for i in response['data'].get('Members', [])]
+ if not self.storage_subsystems_uris:
+ return {
+ 'ret': False,
+ 'msg': "StorageCollection's Members array is either empty or missing"}
+
+ # Matching Storage Subsystem ID with user input
+ self.storage_subsystem_uri = ""
+ for storage_subsystem_uri in self.storage_subsystems_uris:
+ if storage_subsystem_uri.split("/")[-2] == storage_subsystem_id:
+ self.storage_subsystem_uri = storage_subsystem_uri
+
+ if not self.storage_subsystem_uri:
+ return {
+ 'ret': False,
+ 'msg': "Provided Storage Subsystem ID %s does not exist on the server" % storage_subsystem_id}
+
+ # Get Volume Collection
+ response = self.get_request(self.root_uri + self.storage_subsystem_uri)
+ if response['ret'] is False:
+ return response
+ data = response['data']
+
+ response = self.get_request(self.root_uri + data['Volumes']['@odata.id'])
+ if response['ret'] is False:
+ return response
+ data = response['data']
+
+ # Collect Volumes
+ self.volume_uris = [i['@odata.id'] for i in response['data'].get('Members', [])]
+ if not self.volume_uris:
+ return {
+ 'ret': True, 'changed': False,
+ 'msg': "VolumeCollection's Members array is either empty or missing"}
+
+ # Delete each volume
+ for volume in self.volume_uris:
+ if volume.split("/")[-1] in volume_ids:
+ response = self.delete_request(self.root_uri + volume)
+ if response['ret'] is False:
+ return response
+
+ return {'ret': True, 'changed': True,
+ 'msg': "The following volumes were deleted: %s" % str(volume_ids)}
+
+ def create_volume(self, volume_details, storage_subsystem_id):
+ # Find the Storage resource from the requested ComputerSystem resource
+ response = self.get_request(self.root_uri + self.systems_uri)
+ if response['ret'] is False:
+ return response
+ data = response['data']
+ storage_uri = data.get('Storage', {}).get('@odata.id')
+ if storage_uri is None:
+ return {'ret': False, 'msg': 'Storage resource not found'}
+
+ # Get Storage Collection
+ response = self.get_request(self.root_uri + storage_uri)
+ if response['ret'] is False:
+ return response
+ data = response['data']
+
+ # Collect Storage Subsystems
+ self.storage_subsystems_uris = [i['@odata.id'] for i in response['data'].get('Members', [])]
+ if not self.storage_subsystems_uris:
+ return {
+ 'ret': False,
+ 'msg': "StorageCollection's Members array is either empty or missing"}
+
+ # Matching Storage Subsystem ID with user input
+ self.storage_subsystem_uri = ""
+ for storage_subsystem_uri in self.storage_subsystems_uris:
+ if storage_subsystem_uri.split("/")[-2] == storage_subsystem_id:
+ self.storage_subsystem_uri = storage_subsystem_uri
+
+ if not self.storage_subsystem_uri:
+ return {
+ 'ret': False,
+ 'msg': "Provided Storage Subsystem ID %s does not exist on the server" % storage_subsystem_id}
+
+ # Validate input parameters
+ required_parameters = ['RAIDType', 'Drives', 'CapacityBytes']
+ allowed_parameters = ['DisplayName', 'InitializeMethod', 'MediaSpanCount',
+ 'Name', 'ReadCachePolicy', 'StripSizeBytes', 'VolumeUsage', 'WriteCachePolicy']
+
+ for parameter in required_parameters:
+ if not volume_details.get(parameter):
+ return {
+ 'ret': False,
+ 'msg': "%s are required parameter to create a volume" % str(required_parameters)}
+
+ # Navigate to the volume uri of the correct storage subsystem
+ response = self.get_request(self.root_uri + self.storage_subsystem_uri)
+ if response['ret'] is False:
+ return response
+ data = response['data']
+
+ # Deleting any volumes of RAIDType None present on the Storage Subsystem
+ response = self.get_request(self.root_uri + data['Volumes']['@odata.id'])
+ if response['ret'] is False:
+ return response
+ volume_data = response['data']
+
+ if "Members" in volume_data:
+ for member in volume_data["Members"]:
+ response = self.get_request(self.root_uri + member['@odata.id'])
+ if response['ret'] is False:
+ return response
+ member_data = response['data']
+
+ if member_data["RAIDType"] == "None":
+ response = self.delete_request(self.root_uri + member['@odata.id'])
+ if response['ret'] is False:
+ return response
+
+ # Construct payload and issue POST command to create volume
+ volume_details["Links"] = {}
+ volume_details["Links"]["Drives"] = []
+ for drive in volume_details["Drives"]:
+ volume_details["Links"]["Drives"].append({"@odata.id": drive})
+ del volume_details["Drives"]
+ payload = volume_details
+ response = self.post_request(self.root_uri + data['Volumes']['@odata.id'], payload)
+ if response['ret'] is False:
+ return response
+
+ return {'ret': True, 'changed': True,
+ 'msg': "Volume Created"}
+
+ def get_bios_registries(self):
+ # Get /redfish/v1
+ response = self.get_request(self.root_uri + self.systems_uri)
+ if not response["ret"]:
+ return response
+
+ server_details = response["data"]
+
+ # Get Registries URI
+ if "Bios" not in server_details:
+ msg = "Getting BIOS URI failed, Key 'Bios' not found in /redfish/v1/Systems/1/ response: %s"
+ return {
+ "ret": False,
+ "msg": msg % str(server_details)
+ }
+
+ bios_uri = server_details["Bios"]["@odata.id"]
+ bios_resp = self.get_request(self.root_uri + bios_uri)
+ if not bios_resp["ret"]:
+ return bios_resp
+
+ bios_data = bios_resp["data"]
+ attribute_registry = bios_data["AttributeRegistry"]
+
+ reg_uri = self.root_uri + self.service_root + "Registries/" + attribute_registry
+ reg_resp = self.get_request(reg_uri)
+ if not reg_resp["ret"]:
+ return reg_resp
+
+ reg_data = reg_resp["data"]
+
+ # Get BIOS attribute registry URI
+ lst = []
+
+ # Get the location URI
+ response = self.check_location_uri(reg_data, reg_uri)
+ if not response["ret"]:
+ return response
+
+ rsp_data, rsp_uri = response["rsp_data"], response["rsp_uri"]
+
+ if "RegistryEntries" not in rsp_data:
+ return {
+ "msg": "'RegistryEntries' not present in %s response, %s" % (rsp_uri, str(rsp_data)),
+ "ret": False
+ }
+
+ return {
+ "bios_registry": rsp_data,
+ "bios_registry_uri": rsp_uri,
+ "ret": True
+ }
+
+ def check_location_uri(self, resp_data, resp_uri):
+ # Get the location URI response
+ # return {"msg": self.creds, "ret": False}
+ vendor = self._get_vendor()['Vendor']
+ rsp_uri = ""
+ for loc in resp_data['Location']:
+ if loc['Language'] == "en":
+ rsp_uri = loc['Uri']
+ if vendor == 'HPE':
+ # WORKAROUND
+ # HPE systems with iLO 4 will have BIOS Attribute Registries location URI as a dictionary with key 'extref'
+ # Hence adding condition to fetch the Uri
+ if isinstance(loc['Uri'], dict) and "extref" in loc['Uri'].keys():
+ rsp_uri = loc['Uri']['extref']
+ if not rsp_uri:
+ msg = "Language 'en' not found in BIOS Attribute Registries location, URI: %s, response: %s"
+ return {
+ "ret": False,
+ "msg": msg % (resp_uri, str(resp_data))
+ }
+
+ res = self.get_request(self.root_uri + rsp_uri)
+ if res['ret'] is False:
+ # WORKAROUND
+ # HPE systems with iLO 4 or iLO5 compresses (gzip) for some URIs
+ # Hence adding encoding to the header
+ if vendor == 'HPE':
+ override_headers = {"Accept-Encoding": "gzip"}
+ res = self.get_request(self.root_uri + rsp_uri, override_headers=override_headers)
+ if res['ret']:
+ return {
+ "ret": True,
+ "rsp_data": res["data"],
+ "rsp_uri": rsp_uri
+ }
+ return res
diff --git a/ansible_collections/community/general/plugins/module_utils/redhat.py b/ansible_collections/community/general/plugins/module_utils/redhat.py
index f82cffaa0..110159ddf 100644
--- a/ansible_collections/community/general/plugins/module_utils/redhat.py
+++ b/ansible_collections/community/general/plugins/module_utils/redhat.py
@@ -24,6 +24,14 @@ from ansible.module_utils.six.moves import configparser
class RegistrationBase(object):
+ """
+ DEPRECATION WARNING
+
+ This class is deprecated and will be removed in community.general 10.0.0.
+ There is no replacement for it; please contact the community.general
+ maintainers in case you are using it.
+ """
+
def __init__(self, module, username=None, password=None):
self.module = module
self.username = username
@@ -71,10 +79,23 @@ class RegistrationBase(object):
class Rhsm(RegistrationBase):
+ """
+ DEPRECATION WARNING
+
+ This class is deprecated and will be removed in community.general 9.0.0.
+ There is no replacement for it; please contact the community.general
+ maintainers in case you are using it.
+ """
+
def __init__(self, module, username=None, password=None):
RegistrationBase.__init__(self, module, username, password)
self.config = self._read_config()
self.module = module
+ self.module.deprecate(
+ 'The Rhsm class is deprecated with no replacement.',
+ version='9.0.0',
+ collection_name='community.general',
+ )
def _read_config(self, rhsm_conf='/etc/rhsm/rhsm.conf'):
'''
@@ -200,14 +221,25 @@ class Rhsm(RegistrationBase):
class RhsmPool(object):
- '''
- Convenience class for housing subscription information
- '''
+ """
+ Convenience class for housing subscription information
+
+ DEPRECATION WARNING
+
+ This class is deprecated and will be removed in community.general 9.0.0.
+ There is no replacement for it; please contact the community.general
+ maintainers in case you are using it.
+ """
def __init__(self, module, **kwargs):
self.module = module
for k, v in kwargs.items():
setattr(self, k, v)
+ self.module.deprecate(
+ 'The RhsmPool class is deprecated with no replacement.',
+ version='9.0.0',
+ collection_name='community.general',
+ )
def __str__(self):
return str(self.__getattribute__('_name'))
@@ -223,11 +255,23 @@ class RhsmPool(object):
class RhsmPools(object):
"""
- This class is used for manipulating pools subscriptions with RHSM
+ This class is used for manipulating pools subscriptions with RHSM
+
+ DEPRECATION WARNING
+
+ This class is deprecated and will be removed in community.general 9.0.0.
+ There is no replacement for it; please contact the community.general
+ maintainers in case you are using it.
"""
+
def __init__(self, module):
self.module = module
self.products = self._load_product_list()
+ self.module.deprecate(
+ 'The RhsmPools class is deprecated with no replacement.',
+ version='9.0.0',
+ collection_name='community.general',
+ )
def __iter__(self):
return self.products.__iter__()
diff --git a/ansible_collections/community/general/plugins/module_utils/rundeck.py b/ansible_collections/community/general/plugins/module_utils/rundeck.py
index 6fb56fbae..7df68a360 100644
--- a/ansible_collections/community/general/plugins/module_utils/rundeck.py
+++ b/ansible_collections/community/general/plugins/module_utils/rundeck.py
@@ -72,7 +72,9 @@ def api_request(module, endpoint, data=None, method="GET"):
if info["status"] == 403:
module.fail_json(msg="Token authorization failed",
execution_info=json.loads(info["body"]))
- if info["status"] == 409:
+ elif info["status"] == 404:
+ return None, info
+ elif info["status"] == 409:
module.fail_json(msg="Job executions limit reached",
execution_info=json.loads(info["body"]))
elif info["status"] >= 500:
diff --git a/ansible_collections/community/general/plugins/module_utils/scaleway.py b/ansible_collections/community/general/plugins/module_utils/scaleway.py
index 43f209480..67b821103 100644
--- a/ansible_collections/community/general/plugins/module_utils/scaleway.py
+++ b/ansible_collections/community/general/plugins/module_utils/scaleway.py
@@ -303,7 +303,7 @@ class Scaleway(object):
wait_timeout = self.module.params["wait_timeout"]
wait_sleep_time = self.module.params["wait_sleep_time"]
- # Prevent requesting the ressource status too soon
+ # Prevent requesting the resource status too soon
time.sleep(wait_sleep_time)
start = datetime.datetime.utcnow()
diff --git a/ansible_collections/community/general/plugins/module_utils/snap.py b/ansible_collections/community/general/plugins/module_utils/snap.py
new file mode 100644
index 000000000..253269b9a
--- /dev/null
+++ b/ansible_collections/community/general/plugins/module_utils/snap.py
@@ -0,0 +1,48 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2023, Alexei Znamensky <russoz@gmail.com>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+from ansible_collections.community.general.plugins.module_utils.cmd_runner import CmdRunner, cmd_runner_fmt
+
+
+_alias_state_map = dict(
+ present='alias',
+ absent='unalias',
+ info='aliases',
+)
+
+_state_map = dict(
+ present='install',
+ absent='remove',
+ enabled='enable',
+ disabled='disable',
+ refresh='refresh',
+)
+
+
+def snap_runner(module, **kwargs):
+ runner = CmdRunner(
+ module,
+ "snap",
+ arg_formats=dict(
+ state_alias=cmd_runner_fmt.as_map(_alias_state_map), # snap_alias only
+ name=cmd_runner_fmt.as_list(),
+ alias=cmd_runner_fmt.as_list(), # snap_alias only
+ state=cmd_runner_fmt.as_map(_state_map),
+ _list=cmd_runner_fmt.as_fixed("list"),
+ _set=cmd_runner_fmt.as_fixed("set"),
+ get=cmd_runner_fmt.as_fixed(["get", "-d"]),
+ classic=cmd_runner_fmt.as_bool("--classic"),
+ channel=cmd_runner_fmt.as_func(lambda v: [] if v == 'stable' else ['--channel', '{0}'.format(v)]),
+ options=cmd_runner_fmt.as_list(),
+ info=cmd_runner_fmt.as_fixed("info"),
+ dangerous=cmd_runner_fmt.as_bool("--dangerous"),
+ ),
+ check_rc=False,
+ **kwargs
+ )
+ return runner
diff --git a/ansible_collections/community/general/plugins/module_utils/vardict.py b/ansible_collections/community/general/plugins/module_utils/vardict.py
new file mode 100644
index 000000000..cfcce4d4d
--- /dev/null
+++ b/ansible_collections/community/general/plugins/module_utils/vardict.py
@@ -0,0 +1,197 @@
+# -*- coding: utf-8 -*-
+# (c) 2023, Alexei Znamensky <russoz@gmail.com>
+# Copyright (c) 2023, Ansible Project
+# Simplified BSD License (see LICENSES/BSD-2-Clause.txt or https://opensource.org/licenses/BSD-2-Clause)
+# SPDX-License-Identifier: BSD-2-Clause
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+import copy
+
+
+class _Variable(object):
+ NOTHING = object()
+
+ def __init__(self, diff=False, output=True, change=None, fact=False, verbosity=0):
+ self.init = False
+ self.initial_value = None
+ self.value = None
+
+ self.diff = None
+ self._change = None
+ self.output = None
+ self.fact = None
+ self._verbosity = None
+ self.set_meta(output=output, diff=diff, change=change, fact=fact, verbosity=verbosity)
+
+ def getchange(self):
+ return self.diff if self._change is None else self._change
+
+ def setchange(self, value):
+ self._change = value
+
+ def getverbosity(self):
+ return self._verbosity
+
+ def setverbosity(self, v):
+ if not (0 <= v <= 4):
+ raise ValueError("verbosity must be an int in the range 0 to 4")
+ self._verbosity = v
+
+ change = property(getchange, setchange)
+ verbosity = property(getverbosity, setverbosity)
+
+ def set_meta(self, output=None, diff=None, change=None, fact=None, initial_value=NOTHING, verbosity=None):
+ """Set the metadata for the variable
+
+ Args:
+ output (bool, optional): flag indicating whether the variable should be in the output of the module. Defaults to None.
+ diff (bool, optional): flag indicating whether to generate diff mode output for this variable. Defaults to None.
+ change (bool, optional): flag indicating whether to track if changes happened to this variable. Defaults to None.
+ fact (bool, optional): flag indicating whether the variable should be exposed as a fact of the module. Defaults to None.
+ initial_value (any, optional): initial value of the variable, to be used with `change`. Defaults to NOTHING.
+ verbosity (int, optional): level of verbosity in which this variable is reported by the module as `output`, `fact` or `diff`. Defaults to None.
+ """
+ if output is not None:
+ self.output = output
+ if change is not None:
+ self.change = change
+ if diff is not None:
+ self.diff = diff
+ if fact is not None:
+ self.fact = fact
+ if initial_value is not _Variable.NOTHING:
+ self.initial_value = copy.deepcopy(initial_value)
+ if verbosity is not None:
+ self.verbosity = verbosity
+
+ def as_dict(self, meta_only=False):
+ d = {
+ "diff": self.diff,
+ "change": self.change,
+ "output": self.output,
+ "fact": self.fact,
+ "verbosity": self.verbosity,
+ }
+ if not meta_only:
+ d["initial_value"] = copy.deepcopy(self.initial_value)
+ d["value"] = self.value
+ return d
+
+ def set_value(self, value):
+ if not self.init:
+ self.initial_value = copy.deepcopy(value)
+ self.init = True
+ self.value = value
+ return self
+
+ def is_visible(self, verbosity):
+ return self.verbosity <= verbosity
+
+ @property
+ def has_changed(self):
+ return self.change and (self.initial_value != self.value)
+
+ @property
+ def diff_result(self):
+ if self.diff and self.has_changed:
+ return {'before': self.initial_value, 'after': self.value}
+ return
+
+ def __str__(self):
+ return "<_Variable: value={0!r}, initial={1!r}, diff={2}, output={3}, change={4}, verbosity={5}>".format(
+ self.value, self.initial_value, self.diff, self.output, self.change, self.verbosity
+ )
+
+
+class VarDict(object):
+ reserved_names = ('__vars__', '_var', 'var', 'set_meta', 'get_meta', 'set', 'output', 'diff', 'facts', 'has_changed', 'as_dict')
+
+ def __init__(self):
+ self.__vars__ = dict()
+
+ def __getitem__(self, item):
+ return self.__vars__[item].value
+
+ def __setitem__(self, key, value):
+ self.set(key, value)
+
+ def __getattr__(self, item):
+ try:
+ return self.__vars__[item].value
+ except KeyError:
+ return getattr(super(VarDict, self), item)
+
+ def __setattr__(self, key, value):
+ if key == '__vars__':
+ super(VarDict, self).__setattr__(key, value)
+ else:
+ self.set(key, value)
+
+ def _var(self, name):
+ return self.__vars__[name]
+
+ def var(self, name):
+ return self._var(name).as_dict()
+
+ def set_meta(self, name, **kwargs):
+ """Set the metadata for the variable
+
+ Args:
+ name (str): name of the variable having its metadata changed
+ output (bool, optional): flag indicating whether the variable should be in the output of the module. Defaults to None.
+ diff (bool, optional): flag indicating whether to generate diff mode output for this variable. Defaults to None.
+ change (bool, optional): flag indicating whether to track if changes happened to this variable. Defaults to None.
+ fact (bool, optional): flag indicating whether the variable should be exposed as a fact of the module. Defaults to None.
+ initial_value (any, optional): initial value of the variable, to be used with `change`. Defaults to NOTHING.
+ verbosity (int, optional): level of verbosity in which this variable is reported by the module as `output`, `fact` or `diff`. Defaults to None.
+ """
+ self._var(name).set_meta(**kwargs)
+
+ def get_meta(self, name):
+ return self._var(name).as_dict(meta_only=True)
+
+ def set(self, name, value, **kwargs):
+ """Set the value and optionally metadata for a variable. The variable is not required to exist prior to calling `set`.
+
+ For details on the accepted metada see the documentation for method `set_meta`.
+
+ Args:
+ name (str): name of the variable being changed
+ value (any): the value of the variable, it can be of any type
+
+ Raises:
+ ValueError: Raised if trying to set a variable with a reserved name.
+ """
+ if name in self.reserved_names:
+ raise ValueError("Name {0} is reserved".format(name))
+ if name in self.__vars__:
+ var = self._var(name)
+ var.set_meta(**kwargs)
+ else:
+ var = _Variable(**kwargs)
+ var.set_value(value)
+ self.__vars__[name] = var
+
+ def output(self, verbosity=0):
+ return dict((n, v.value) for n, v in self.__vars__.items() if v.output and v.is_visible(verbosity))
+
+ def diff(self, verbosity=0):
+ diff_results = [(n, v.diff_result) for n, v in self.__vars__.items() if v.diff_result and v.is_visible(verbosity)]
+ if diff_results:
+ before = dict((n, dr['before']) for n, dr in diff_results)
+ after = dict((n, dr['after']) for n, dr in diff_results)
+ return {'before': before, 'after': after}
+ return None
+
+ def facts(self, verbosity=0):
+ facts_result = dict((n, v.value) for n, v in self.__vars__.items() if v.fact and v.is_visible(verbosity))
+ return facts_result if facts_result else None
+
+ @property
+ def has_changed(self):
+ return any(var.has_changed for var in self.__vars__.values())
+
+ def as_dict(self):
+ return dict((name, var.value) for name, var in self.__vars__.items())
diff --git a/ansible_collections/community/general/plugins/module_utils/version.py b/ansible_collections/community/general/plugins/module_utils/version.py
index 369988197..935e8005e 100644
--- a/ansible_collections/community/general/plugins/module_utils/version.py
+++ b/ansible_collections/community/general/plugins/module_utils/version.py
@@ -10,13 +10,4 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type
-from ansible.module_utils.six import raise_from
-
-try:
- from ansible.module_utils.compat.version import LooseVersion # noqa: F401, pylint: disable=unused-import
-except ImportError:
- try:
- from distutils.version import LooseVersion # noqa: F401, pylint: disable=unused-import
- except ImportError as exc:
- msg = 'To use this plugin or module with ansible-core 2.11, you need to use Python < 3.12 with distutils.version present'
- raise_from(ImportError(msg), exc)
+from ansible.module_utils.compat.version import LooseVersion # noqa: F401, pylint: disable=unused-import
diff --git a/ansible_collections/community/general/plugins/module_utils/wdc_redfish_utils.py b/ansible_collections/community/general/plugins/module_utils/wdc_redfish_utils.py
index d27e02d7b..bc4b0c2cd 100644
--- a/ansible_collections/community/general/plugins/module_utils/wdc_redfish_utils.py
+++ b/ansible_collections/community/general/plugins/module_utils/wdc_redfish_utils.py
@@ -182,7 +182,7 @@ class WdcRedfishUtils(RedfishUtils):
:param str bundle_uri: HTTP URI of the firmware bundle.
:return: Firmware version number contained in the bundle, and whether or not the bundle is multi-tenant.
- Either value will be None if unable to deterine.
+ Either value will be None if unable to determine.
:rtype: str or None, bool or None
"""
bundle_temp_filename = fetch_file(module=self.module,
diff --git a/ansible_collections/community/general/plugins/modules/airbrake_deployment.py b/ansible_collections/community/general/plugins/modules/airbrake_deployment.py
index 42ac037e1..bad1b2c9d 100644
--- a/ansible_collections/community/general/plugins/modules/airbrake_deployment.py
+++ b/ansible_collections/community/general/plugins/modules/airbrake_deployment.py
@@ -72,7 +72,7 @@ options:
type: str
validate_certs:
description:
- - If C(false), SSL certificates for the target url will not be validated. This should only be used
+ - If V(false), SSL certificates for the target url will not be validated. This should only be used
on personally controlled sites using self-signed certificates.
required: false
default: true
diff --git a/ansible_collections/community/general/plugins/modules/aix_devices.py b/ansible_collections/community/general/plugins/modules/aix_devices.py
index ef4ed4961..a0f3cf48d 100644
--- a/ansible_collections/community/general/plugins/modules/aix_devices.py
+++ b/ansible_collections/community/general/plugins/modules/aix_devices.py
@@ -31,7 +31,7 @@ options:
device:
description:
- The name of the device.
- - C(all) is valid to rescan C(available) all devices (AIX cfgmgr command).
+ - V(all) is valid to rescan C(available) all devices (AIX cfgmgr command).
type: str
force:
description:
@@ -46,9 +46,9 @@ options:
state:
description:
- Controls the device state.
- - C(available) (alias C(present)) rescan a specific device or all devices (when C(device) is not specified).
- - C(removed) (alias C(absent) removes a device.
- - C(defined) changes device to Defined state.
+ - V(available) (alias V(present)) rescan a specific device or all devices (when O(device) is not specified).
+ - V(removed) (alias V(absent) removes a device.
+ - V(defined) changes device to Defined state.
type: str
choices: [ available, defined, removed ]
default: available
diff --git a/ansible_collections/community/general/plugins/modules/aix_filesystem.py b/ansible_collections/community/general/plugins/modules/aix_filesystem.py
index b1f363a93..6abf6317f 100644
--- a/ansible_collections/community/general/plugins/modules/aix_filesystem.py
+++ b/ansible_collections/community/general/plugins/modules/aix_filesystem.py
@@ -38,8 +38,8 @@ options:
type: list
elements: str
default:
- - agblksize='4096'
- - isnapshot='no'
+ - agblksize=4096
+ - isnapshot=no
auto_mount:
description:
- File system is automatically mounted at system restart.
@@ -58,7 +58,7 @@ options:
default: jfs2
permissions:
description:
- - Set file system permissions. C(rw) (read-write) or C(ro) (read-only).
+ - Set file system permissions. V(rw) (read-write) or V(ro) (read-only).
type: str
choices: [ ro, rw ]
default: rw
@@ -77,13 +77,13 @@ options:
type: str
rm_mount_point:
description:
- - Removes the mount point directory when used with state C(absent).
+ - Removes the mount point directory when used with state V(absent).
type: bool
default: false
size:
description:
- Specifies the file system size.
- - For already C(present) it will be resized.
+ - For already V(present) it will be resized.
- 512-byte blocks, Megabytes or Gigabytes. If the value has M specified
it will be in Megabytes. If the value has G specified it will be in
Gigabytes.
@@ -96,10 +96,10 @@ options:
state:
description:
- Controls the file system state.
- - C(present) check if file system exists, creates or resize.
- - C(absent) removes existing file system if already C(unmounted).
- - C(mounted) checks if the file system is mounted or mount the file system.
- - C(unmounted) check if the file system is unmounted or unmount the file system.
+ - V(present) check if file system exists, creates or resize.
+ - V(absent) removes existing file system if already V(unmounted).
+ - V(mounted) checks if the file system is mounted or mount the file system.
+ - V(unmounted) check if the file system is unmounted or unmount the file system.
type: str
choices: [ absent, mounted, present, unmounted ]
default: present
@@ -108,7 +108,7 @@ options:
- Specifies an existing volume group (VG).
type: str
notes:
- - For more C(attributes), please check "crfs" AIX manual.
+ - For more O(attributes), please check "crfs" AIX manual.
'''
EXAMPLES = r'''
@@ -365,7 +365,53 @@ def create_fs(
# Creates a LVM file system.
crfs_cmd = module.get_bin_path('crfs', True)
if not module.check_mode:
- cmd = [crfs_cmd, "-v", fs_type, "-m", filesystem, vg, device, mount_group, auto_mount, account_subsystem, "-p", permissions, size, "-a", attributes]
+ cmd = [crfs_cmd]
+
+ cmd.append("-v")
+ cmd.append(fs_type)
+
+ if vg:
+ (flag, value) = vg.split()
+ cmd.append(flag)
+ cmd.append(value)
+
+ if device:
+ (flag, value) = device.split()
+ cmd.append(flag)
+ cmd.append(value)
+
+ cmd.append("-m")
+ cmd.append(filesystem)
+
+ if mount_group:
+ (flag, value) = mount_group.split()
+ cmd.append(flag)
+ cmd.append(value)
+
+ if auto_mount:
+ (flag, value) = auto_mount.split()
+ cmd.append(flag)
+ cmd.append(value)
+
+ if account_subsystem:
+ (flag, value) = account_subsystem.split()
+ cmd.append(flag)
+ cmd.append(value)
+
+ cmd.append("-p")
+ cmd.append(permissions)
+
+ if size:
+ (flag, value) = size.split()
+ cmd.append(flag)
+ cmd.append(value)
+
+ if attributes:
+ splitted_attributes = attributes.split()
+ cmd.append("-a")
+ for value in splitted_attributes:
+ cmd.append(value)
+
rc, crfs_out, err = module.run_command(cmd)
if rc == 10:
@@ -461,7 +507,7 @@ def main():
module = AnsibleModule(
argument_spec=dict(
account_subsystem=dict(type='bool', default=False),
- attributes=dict(type='list', elements='str', default=["agblksize='4096'", "isnapshot='no'"]),
+ attributes=dict(type='list', elements='str', default=["agblksize=4096", "isnapshot=no"]),
auto_mount=dict(type='bool', default=True),
device=dict(type='str'),
filesystem=dict(type='str', required=True),
diff --git a/ansible_collections/community/general/plugins/modules/aix_inittab.py b/ansible_collections/community/general/plugins/modules/aix_inittab.py
index c2c968189..d4c9aa0b5 100644
--- a/ansible_collections/community/general/plugins/modules/aix_inittab.py
+++ b/ansible_collections/community/general/plugins/modules/aix_inittab.py
@@ -204,7 +204,7 @@ def main():
":" + module.params['action'] + ":" + module.params['command']
# If current entry exists or fields are different(if the entry does not
- # exists, then the entry wil be created
+ # exists, then the entry will be created
if (not current_entry['exist']) or (
module.params['runlevel'] != current_entry['runlevel'] or
module.params['action'] != current_entry['action'] or
diff --git a/ansible_collections/community/general/plugins/modules/aix_lvg.py b/ansible_collections/community/general/plugins/modules/aix_lvg.py
index d89c43de4..2892a68ad 100644
--- a/ansible_collections/community/general/plugins/modules/aix_lvg.py
+++ b/ansible_collections/community/general/plugins/modules/aix_lvg.py
@@ -36,13 +36,13 @@ options:
pvs:
description:
- List of comma-separated devices to use as physical devices in this volume group.
- - Required when creating or extending (C(present) state) the volume group.
- - If not informed reducing (C(absent) state) the volume group will be removed.
+ - Required when creating or extending (V(present) state) the volume group.
+ - If not informed reducing (V(absent) state) the volume group will be removed.
type: list
elements: str
state:
description:
- - Control if the volume group exists and volume group AIX state varyonvg C(varyon) or varyoffvg C(varyoff).
+ - Control if the volume group exists and volume group AIX state varyonvg V(varyon) or varyoffvg V(varyoff).
type: str
choices: [ absent, present, varyoff, varyon ]
default: present
diff --git a/ansible_collections/community/general/plugins/modules/aix_lvol.py b/ansible_collections/community/general/plugins/modules/aix_lvol.py
index 0a4a6eff5..1e7b42568 100644
--- a/ansible_collections/community/general/plugins/modules/aix_lvol.py
+++ b/ansible_collections/community/general/plugins/modules/aix_lvol.py
@@ -53,15 +53,15 @@ options:
policy:
description:
- Sets the interphysical volume allocation policy.
- - C(maximum) allocates logical partitions across the maximum number of physical volumes.
- - C(minimum) allocates logical partitions across the minimum number of physical volumes.
+ - V(maximum) allocates logical partitions across the maximum number of physical volumes.
+ - V(minimum) allocates logical partitions across the minimum number of physical volumes.
type: str
choices: [ maximum, minimum ]
default: maximum
state:
description:
- - Control if the logical volume exists. If C(present) and the
- volume does not already exist then the C(size) option is required.
+ - Control if the logical volume exists. If V(present) and the
+ volume does not already exist then the O(size) option is required.
type: str
choices: [ absent, present ]
default: present
@@ -72,7 +72,7 @@ options:
default: ''
pvs:
description:
- - A list of physical volumes e.g. C(hdisk1,hdisk2).
+ - A list of physical volumes, for example V(hdisk1,hdisk2).
type: list
elements: str
default: []
diff --git a/ansible_collections/community/general/plugins/modules/alerta_customer.py b/ansible_collections/community/general/plugins/modules/alerta_customer.py
index 120d98932..5e1a5f86c 100644
--- a/ansible_collections/community/general/plugins/modules/alerta_customer.py
+++ b/ansible_collections/community/general/plugins/modules/alerta_customer.py
@@ -58,7 +58,7 @@ options:
state:
description:
- Whether the customer should exist or not.
- - Both I(customer) and I(match) identify a customer that should be added or removed.
+ - Both O(customer) and O(match) identify a customer that should be added or removed.
type: str
choices: [ absent, present ]
default: present
diff --git a/ansible_collections/community/general/plugins/modules/ali_instance.py b/ansible_collections/community/general/plugins/modules/ali_instance.py
index 232c21ee0..087dc64b6 100644
--- a/ansible_collections/community/general/plugins/modules/ali_instance.py
+++ b/ansible_collections/community/general/plugins/modules/ali_instance.py
@@ -51,12 +51,12 @@ options:
type: str
image_id:
description:
- - Image ID used to launch instances. Required when I(state=present) and creating new ECS instances.
+ - Image ID used to launch instances. Required when O(state=present) and creating new ECS instances.
aliases: ['image']
type: str
instance_type:
description:
- - Instance type used to launch instances. Required when I(state=present) and creating new ECS instances.
+ - Instance type used to launch instances. Required when O(state=present) and creating new ECS instances.
aliases: ['type']
type: str
security_groups:
@@ -95,7 +95,7 @@ options:
max_bandwidth_out:
description:
- Maximum outgoing bandwidth to the public network, measured in Mbps (Megabits per second).
- Required when I(allocate_public_ip=true). Ignored when I(allocate_public_ip=false).
+ Required when O(allocate_public_ip=true). Ignored when O(allocate_public_ip=false).
default: 0
type: int
host_name:
@@ -134,16 +134,16 @@ options:
type: str
count:
description:
- - The number of the new instance. An integer value which indicates how many instances that match I(count_tag)
+ - The number of the new instance. An integer value which indicates how many instances that match O(count_tag)
should be running. Instances are either created or terminated based on this value.
default: 1
type: int
count_tag:
description:
- - I(count) determines how many instances based on a specific tag criteria should be present.
+ - O(count) determines how many instances based on a specific tag criteria should be present.
This can be expressed in multiple ways and is shown in the EXAMPLES section.
- The specified count_tag must already exist or be passed in as the I(tags) option.
- If it is not specified, it will be replaced by I(instance_name).
+ The specified count_tag must already exist or be passed in as the O(tags) option.
+ If it is not specified, it will be replaced by O(instance_name).
type: str
allocate_public_ip:
description:
@@ -159,7 +159,7 @@ options:
type: str
period:
description:
- - The charge duration of the instance, in months. Required when I(instance_charge_type=PrePaid).
+ - The charge duration of the instance, in months. Required when O(instance_charge_type=PrePaid).
- The valid value are [1-9, 12, 24, 36].
default: 1
type: int
@@ -170,13 +170,13 @@ options:
default: false
auto_renew_period:
description:
- - The duration of the automatic renew the charge of the instance. Required when I(auto_renew=true).
+ - The duration of the automatic renew the charge of the instance. Required when O(auto_renew=true).
choices: [1, 2, 3, 6, 12]
type: int
instance_ids:
description:
- A list of instance ids. It is required when need to operate existing instances.
- If it is specified, I(count) will lose efficacy.
+ If it is specified, O(count) will lose efficacy.
type: list
elements: str
force:
@@ -186,7 +186,7 @@ options:
type: bool
tags:
description:
- - A hash/dictionaries of instance tags, to add to the new instance or for starting/stopping instance by tag. C({"key":"value"})
+ - A hash/dictionaries of instance tags, to add to the new instance or for starting/stopping instance by tag. V({"key":"value"})
aliases: ["instance_tags"]
type: dict
version_added: '0.2.0'
@@ -229,7 +229,7 @@ options:
version_added: '0.2.0'
period_unit:
description:
- - The duration unit that you will buy the resource. It is valid when I(instance_charge_type=PrePaid).
+ - The duration unit that you will buy the resource. It is valid when O(instance_charge_type=PrePaid).
choices: ['Month', 'Week']
default: 'Month'
type: str
@@ -237,10 +237,10 @@ options:
dry_run:
description:
- Specifies whether to send a dry-run request.
- - If I(dry_run=true), Only a dry-run request is sent and no instance is created. The system checks whether the
+ - If O(dry_run=true), Only a dry-run request is sent and no instance is created. The system checks whether the
required parameters are set, and validates the request format, service permissions, and available ECS instances.
If the validation fails, the corresponding error code is returned. If the validation succeeds, the DryRunOperation error code is returned.
- - If I(dry_run=false), A request is sent. If the validation succeeds, the instance is created.
+ - If O(dry_run=false), A request is sent. If the validation succeeds, the instance is created.
default: false
type: bool
version_added: '0.2.0'
@@ -253,7 +253,7 @@ options:
author:
- "He Guimin (@xiaozhu36)"
requirements:
- - "python >= 3.6"
+ - "Python >= 3.6"
- "footmark >= 1.19.0"
extends_documentation_fragment:
- community.general.alicloud
diff --git a/ansible_collections/community/general/plugins/modules/ali_instance_info.py b/ansible_collections/community/general/plugins/modules/ali_instance_info.py
index e7ec7f395..d6a787374 100644
--- a/ansible_collections/community/general/plugins/modules/ali_instance_info.py
+++ b/ansible_collections/community/general/plugins/modules/ali_instance_info.py
@@ -31,7 +31,6 @@ short_description: Gather information on instances of Alibaba Cloud ECS
description:
- This module fetches data from the Open API in Alicloud.
The module must be called from within the ECS instance itself.
- - This module was called C(ali_instance_facts) before Ansible 2.9. The usage did not change.
attributes:
check_mode:
@@ -53,15 +52,15 @@ options:
description:
- A dict of filters to apply. Each dict item consists of a filter key and a filter value. The filter keys can be
all of request parameters. See U(https://www.alibabacloud.com/help/doc-detail/25506.htm) for parameter details.
- Filter keys can be same as request parameter name or be lower case and use underscore ("_") or dash ("-") to
- connect different words in one parameter. 'InstanceIds' should be a list.
- 'Tag.n.Key' and 'Tag.n.Value' should be a dict and using I(tags) instead.
+ Filter keys can be same as request parameter name or be lower case and use underscore (V("_")) or dash (V("-")) to
+ connect different words in one parameter. C(InstanceIds) should be a list.
+ C(Tag.n.Key) and C(Tag.n.Value) should be a dict and using O(tags) instead.
type: dict
version_added: '0.2.0'
author:
- "He Guimin (@xiaozhu36)"
requirements:
- - "python >= 3.6"
+ - "Python >= 3.6"
- "footmark >= 1.13.0"
extends_documentation_fragment:
- community.general.alicloud
diff --git a/ansible_collections/community/general/plugins/modules/alternatives.py b/ansible_collections/community/general/plugins/modules/alternatives.py
index 97d4f51fb..0d1b1e8cb 100644
--- a/ansible_collections/community/general/plugins/modules/alternatives.py
+++ b/ansible_collections/community/general/plugins/modules/alternatives.py
@@ -44,21 +44,21 @@ options:
description:
- The path to the symbolic link that should point to the real executable.
- This option is always required on RHEL-based distributions. On Debian-based distributions this option is
- required when the alternative I(name) is unknown to the system.
+ required when the alternative O(name) is unknown to the system.
type: path
priority:
description:
- - The priority of the alternative. If no priority is given for creation C(50) is used as a fallback.
+ - The priority of the alternative. If no priority is given for creation V(50) is used as a fallback.
type: int
state:
description:
- - C(present) - install the alternative (if not already installed), but do
+ - V(present) - install the alternative (if not already installed), but do
not set it as the currently selected alternative for the group.
- - C(selected) - install the alternative (if not already installed), and
+ - V(selected) - install the alternative (if not already installed), and
set it as the currently selected alternative for the group.
- - C(auto) - install the alternative (if not already installed), and
+ - V(auto) - install the alternative (if not already installed), and
set the group to auto mode. Added in community.general 5.1.0.
- - C(absent) - removes the alternative. Added in community.general 5.1.0.
+ - V(absent) - removes the alternative. Added in community.general 5.1.0.
choices: [ present, selected, auto, absent ]
default: selected
type: str
diff --git a/ansible_collections/community/general/plugins/modules/ansible_galaxy_install.py b/ansible_collections/community/general/plugins/modules/ansible_galaxy_install.py
index 0f38eabdf..3b0a8fd47 100644
--- a/ansible_collections/community/general/plugins/modules/ansible_galaxy_install.py
+++ b/ansible_collections/community/general/plugins/modules/ansible_galaxy_install.py
@@ -17,15 +17,13 @@ version_added: 3.5.0
description:
- This module allows the installation of Ansible collections or roles using C(ansible-galaxy).
notes:
- - >
- B(Ansible 2.9/2.10): The C(ansible-galaxy) command changed significantly between Ansible 2.9 and
- ansible-base 2.10 (later ansible-core 2.11). See comments in the parameters.
+ - Support for B(Ansible 2.9/2.10) was removed in community.general 8.0.0.
- >
The module will try and run using the C(C.UTF-8) locale.
If that fails, it will try C(en_US.UTF-8).
If that one also fails, the module will fail.
requirements:
- - Ansible 2.9, ansible-base 2.10, or ansible-core 2.11 or newer
+ - ansible-core 2.11 or newer
extends_documentation_fragment:
- community.general.attributes
attributes:
@@ -37,9 +35,8 @@ options:
type:
description:
- The type of installation performed by C(ansible-galaxy).
- - If I(type) is C(both), then I(requirements_file) must be passed and it may contain both roles and collections.
- - "Note however that the opposite is not true: if using a I(requirements_file), then I(type) can be any of the three choices."
- - "B(Ansible 2.9): The option C(both) will have the same effect as C(role)."
+ - If O(type=both), then O(requirements_file) must be passed and it may contain both roles and collections.
+ - "Note however that the opposite is not true: if using a O(requirements_file), then O(type) can be any of the three choices."
type: str
choices: [collection, role, both]
required: true
@@ -48,22 +45,21 @@ options:
- Name of the collection or role being installed.
- >
Versions can be specified with C(ansible-galaxy) usual formats.
- For example, the collection C(community.docker:1.6.1) or the role C(ansistrano.deploy,3.8.0).
- - I(name) and I(requirements_file) are mutually exclusive.
+ For example, the collection V(community.docker:1.6.1) or the role V(ansistrano.deploy,3.8.0).
+ - O(name) and O(requirements_file) are mutually exclusive.
type: str
requirements_file:
description:
- Path to a file containing a list of requirements to be installed.
- - It works for I(type) equals to C(collection) and C(role).
- - I(name) and I(requirements_file) are mutually exclusive.
- - "B(Ansible 2.9): It can only be used to install either I(type=role) or I(type=collection), but not both at the same run."
+ - It works for O(type) equals to V(collection) and V(role).
+ - O(name) and O(requirements_file) are mutually exclusive.
type: path
dest:
description:
- - The path to the directory containing your collections or roles, according to the value of I(type).
+ - The path to the directory containing your collections or roles, according to the value of O(type).
- >
- Please notice that C(ansible-galaxy) will not install collections with I(type=both), when I(requirements_file)
- contains both roles and collections and I(dest) is specified.
+ Please notice that C(ansible-galaxy) will not install collections with O(type=both), when O(requirements_file)
+ contains both roles and collections and O(dest) is specified.
type: path
no_deps:
description:
@@ -74,25 +70,17 @@ options:
force:
description:
- Force overwriting an existing role or collection.
- - Using I(force=true) is mandatory when downgrading.
- - "B(Ansible 2.9 and 2.10): Must be C(true) to upgrade roles and collections."
+ - Using O(force=true) is mandatory when downgrading.
type: bool
default: false
ack_ansible29:
description:
- - Acknowledge using Ansible 2.9 with its limitations, and prevents the module from generating warnings about them.
- - This option is completely ignored if using a version of Ansible greater than C(2.9.x).
- - Note that this option will be removed without any further deprecation warning once support
- for Ansible 2.9 is removed from this module.
+ - This option has no longer any effect and will be removed in community.general 9.0.0.
type: bool
default: false
ack_min_ansiblecore211:
description:
- - Acknowledge the module is deprecating support for Ansible 2.9 and ansible-base 2.10.
- - Support for those versions will be removed in community.general 8.0.0.
- At the same time, this option will be removed without any deprecation warning!
- - This option is completely ignored if using a version of ansible-core/ansible-base/Ansible greater than C(2.11).
- - For the sake of conciseness, setting this parameter to C(true) implies I(ack_ansible29=true).
+ - This option has no longer any effect and will be removed in community.general 9.0.0.
type: bool
default: false
"""
@@ -124,30 +112,29 @@ EXAMPLES = """
RETURN = """
type:
- description: The value of the I(type) parameter.
+ description: The value of the O(type) parameter.
type: str
returned: always
name:
- description: The value of the I(name) parameter.
+ description: The value of the O(name) parameter.
type: str
returned: always
dest:
- description: The value of the I(dest) parameter.
+ description: The value of the O(dest) parameter.
type: str
returned: always
requirements_file:
- description: The value of the I(requirements_file) parameter.
+ description: The value of the O(requirements_file) parameter.
type: str
returned: always
force:
- description: The value of the I(force) parameter.
+ description: The value of the O(force) parameter.
type: bool
returned: always
installed_roles:
description:
- - If I(requirements_file) is specified instead, returns dictionary with all the roles installed per path.
- - If I(name) is specified, returns that role name and the version installed per path.
- - "B(Ansible 2.9): Returns empty because C(ansible-galaxy) has no C(list) subcommand."
+ - If O(requirements_file) is specified instead, returns dictionary with all the roles installed per path.
+ - If O(name) is specified, returns that role name and the version installed per path.
type: dict
returned: always when installing roles
contains:
@@ -162,9 +149,8 @@ RETURN = """
ansistrano.deploy: 3.8.0
installed_collections:
description:
- - If I(requirements_file) is specified instead, returns dictionary with all the collections installed per path.
- - If I(name) is specified, returns that collection name and the version installed per path.
- - "B(Ansible 2.9): Returns empty because C(ansible-galaxy) has no C(list) subcommand."
+ - If O(requirements_file) is specified instead, returns dictionary with all the collections installed per path.
+ - If O(name) is specified, returns that collection name and the version installed per path.
type: dict
returned: always when installing collections
contains:
@@ -206,7 +192,6 @@ class AnsibleGalaxyInstall(ModuleHelper):
_RE_LIST_ROLE = re.compile(r'^- (?P<elem>\w+\.\w+),\s+(?P<version>[\d\.]+)\s*$')
_RE_INSTALL_OUTPUT = None # Set after determining ansible version, see __init_module__()
ansible_version = None
- is_ansible29 = None
output_params = ('type', 'name', 'dest', 'requirements_file', 'force', 'no_deps')
module = dict(
@@ -217,8 +202,18 @@ class AnsibleGalaxyInstall(ModuleHelper):
dest=dict(type='path'),
force=dict(type='bool', default=False),
no_deps=dict(type='bool', default=False),
- ack_ansible29=dict(type='bool', default=False),
- ack_min_ansiblecore211=dict(type='bool', default=False),
+ ack_ansible29=dict(
+ type='bool',
+ default=False,
+ removed_in_version='9.0.0',
+ removed_from_collection='community.general',
+ ),
+ ack_min_ansiblecore211=dict(
+ type='bool',
+ default=False,
+ removed_in_version='9.0.0',
+ removed_from_collection='community.general',
+ ),
),
mutually_exclusive=[('name', 'requirements_file')],
required_one_of=[('name', 'requirements_file')],
@@ -268,26 +263,22 @@ class AnsibleGalaxyInstall(ModuleHelper):
def __init_module__(self):
# self.runner = CmdRunner(self.module, command=self.command, arg_formats=self.command_args_formats, force_lang=self.force_lang)
self.runner, self.ansible_version = self._get_ansible_galaxy_version()
- if self.ansible_version < (2, 11) and not self.vars.ack_min_ansiblecore211:
- self.module.deprecate(
- "Support for Ansible 2.9 and ansible-base 2.10 is being deprecated. "
- "At the same time support for them is ended, also the ack_ansible29 option will be removed. "
- "Upgrading is strongly recommended, or set 'ack_min_ansiblecore211' to suppress this message.",
- version="8.0.0",
- collection_name="community.general",
+ if self.ansible_version < (2, 11):
+ self.module.fail_json(
+ msg="Support for Ansible 2.9 and ansible-base 2.10 has ben removed."
)
- self.is_ansible29 = self.ansible_version < (2, 10)
- if self.is_ansible29:
- self._RE_INSTALL_OUTPUT = re.compile(r"^(?:.*Installing '(?P<collection>\w+\.\w+):(?P<cversion>[\d\.]+)'.*"
- r'|- (?P<role>\w+\.\w+) \((?P<rversion>[\d\.]+)\)'
- r' was installed successfully)$')
- else:
- # Collection install output changed:
- # ansible-base 2.10: "coll.name (x.y.z)"
- # ansible-core 2.11+: "coll.name:x.y.z"
- self._RE_INSTALL_OUTPUT = re.compile(r'^(?:(?P<collection>\w+\.\w+)(?: \(|:)(?P<cversion>[\d\.]+)\)?'
- r'|- (?P<role>\w+\.\w+) \((?P<rversion>[\d\.]+)\))'
- r' was installed successfully$')
+ # Collection install output changed:
+ # ansible-base 2.10: "coll.name (x.y.z)"
+ # ansible-core 2.11+: "coll.name:x.y.z"
+ self._RE_INSTALL_OUTPUT = re.compile(r'^(?:(?P<collection>\w+\.\w+)(?: \(|:)(?P<cversion>[\d\.]+)\)?'
+ r'|- (?P<role>\w+\.\w+) \((?P<rversion>[\d\.]+)\))'
+ r' was installed successfully$')
+ self.vars.set("new_collections", {}, change=True)
+ self.vars.set("new_roles", {}, change=True)
+ if self.vars.type != "collection":
+ self.vars.installed_roles = self._list_roles()
+ if self.vars.type != "roles":
+ self.vars.installed_collections = self._list_collections()
def _list_element(self, _type, path_re, elem_re):
def process(rc, out, err):
@@ -322,24 +313,8 @@ class AnsibleGalaxyInstall(ModuleHelper):
def _list_roles(self):
return self._list_element('role', self._RE_LIST_PATH, self._RE_LIST_ROLE)
- def _setup29(self):
- self.vars.set("new_collections", {})
- self.vars.set("new_roles", {})
- self.vars.set("ansible29_change", False, change=True, output=False)
- if not (self.vars.ack_ansible29 or self.vars.ack_min_ansiblecore211):
- self.warn("Ansible 2.9 or older: unable to retrieve lists of roles and collections already installed")
- if self.vars.requirements_file is not None and self.vars.type == 'both':
- self.warn("Ansible 2.9 or older: will install only roles from requirement files")
-
- def _setup210plus(self):
- self.vars.set("new_collections", {}, change=True)
- self.vars.set("new_roles", {}, change=True)
- if self.vars.type != "collection":
- self.vars.installed_roles = self._list_roles()
- if self.vars.type != "roles":
- self.vars.installed_collections = self._list_collections()
-
def __run__(self):
+
def process(rc, out, err):
for line in out.splitlines():
match = self._RE_INSTALL_OUTPUT.match(line)
@@ -347,19 +322,9 @@ class AnsibleGalaxyInstall(ModuleHelper):
continue
if match.group("collection"):
self.vars.new_collections[match.group("collection")] = match.group("cversion")
- if self.is_ansible29:
- self.vars.ansible29_change = True
elif match.group("role"):
self.vars.new_roles[match.group("role")] = match.group("rversion")
- if self.is_ansible29:
- self.vars.ansible29_change = True
-
- if self.is_ansible29:
- if self.vars.type == 'both':
- raise ValueError("Type 'both' not supported in Ansible 2.9")
- self._setup29()
- else:
- self._setup210plus()
+
with self.runner("type galaxy_cmd force no_deps dest requirements_file name", output_process=process) as ctx:
ctx.run(galaxy_cmd="install")
if self.verbosity > 2:
diff --git a/ansible_collections/community/general/plugins/modules/apache2_module.py b/ansible_collections/community/general/plugins/modules/apache2_module.py
index 2e2456d74..a9fd72b24 100644
--- a/ansible_collections/community/general/plugins/modules/apache2_module.py
+++ b/ansible_collections/community/general/plugins/modules/apache2_module.py
@@ -37,7 +37,7 @@ options:
description:
- Identifier of the module as listed by C(apache2ctl -M).
This is optional and usually determined automatically by the common convention of
- appending C(_module) to I(name) as well as custom exception for popular modules.
+ appending V(_module) to O(name) as well as custom exception for popular modules.
required: false
force:
description:
@@ -154,7 +154,7 @@ def _get_ctl_binary(module):
if ctl_binary is not None:
return ctl_binary
- module.fail_json(msg="Neither of apache2ctl nor apachctl found. At least one apache control binary is necessary.")
+ module.fail_json(msg="Neither of apache2ctl nor apachectl found. At least one apache control binary is necessary.")
def _module_is_enabled(module):
diff --git a/ansible_collections/community/general/plugins/modules/apk.py b/ansible_collections/community/general/plugins/modules/apk.py
index e56b2165d..a6b058b93 100644
--- a/ansible_collections/community/general/plugins/modules/apk.py
+++ b/ansible_collections/community/general/plugins/modules/apk.py
@@ -17,7 +17,7 @@ DOCUMENTATION = '''
module: apk
short_description: Manages apk packages
description:
- - Manages I(apk) packages for Alpine Linux.
+ - Manages C(apk) packages for Alpine Linux.
author: "Kevin Brebanov (@kbrebanov)"
extends_documentation_fragment:
- community.general.attributes
@@ -35,7 +35,9 @@ options:
default: false
name:
description:
- - A package name, like C(foo), or multiple packages, like C(foo, bar).
+ - A package name, like V(foo), or multiple packages, like V(foo,bar).
+ - Do not include additional whitespace when specifying multiple packages as a string.
+ Prefer YAML lists over comma-separating multiple package names.
type: list
elements: str
no_cache:
@@ -53,15 +55,15 @@ options:
state:
description:
- Indicates the desired package(s) state.
- - C(present) ensures the package(s) is/are present. C(installed) can be used as an alias.
- - C(absent) ensures the package(s) is/are absent. C(removed) can be used as an alias.
- - C(latest) ensures the package(s) is/are present and the latest version(s).
+ - V(present) ensures the package(s) is/are present. V(installed) can be used as an alias.
+ - V(absent) ensures the package(s) is/are absent. V(removed) can be used as an alias.
+ - V(latest) ensures the package(s) is/are present and the latest version(s).
default: present
choices: [ "present", "absent", "latest", "installed", "removed" ]
type: str
update_cache:
description:
- - Update repository indexes. Can be run with other steps or on it's own.
+ - Update repository indexes. Can be run with other steps or on its own.
type: bool
default: false
upgrade:
@@ -76,8 +78,8 @@ options:
default: /etc/apk/world
version_added: 5.4.0
notes:
- - 'I(name) and I(upgrade) are mutually exclusive.'
- - When used with a C(loop:) each package will be processed individually, it is much more efficient to pass the list directly to the I(name) option.
+ - 'O(name) and O(upgrade) are mutually exclusive.'
+ - When used with a C(loop:) each package will be processed individually, it is much more efficient to pass the list directly to the O(name) option.
'''
EXAMPLES = '''
diff --git a/ansible_collections/community/general/plugins/modules/apt_repo.py b/ansible_collections/community/general/plugins/modules/apt_repo.py
index 556039027..4c82587d0 100644
--- a/ansible_collections/community/general/plugins/modules/apt_repo.py
+++ b/ansible_collections/community/general/plugins/modules/apt_repo.py
@@ -41,7 +41,7 @@ options:
remove_others:
description:
- Remove other then added repositories
- - Used if I(state=present)
+ - Used if O(state=present)
type: bool
default: false
update:
diff --git a/ansible_collections/community/general/plugins/modules/apt_rpm.py b/ansible_collections/community/general/plugins/modules/apt_rpm.py
index 8749086bb..de1b57411 100644
--- a/ansible_collections/community/general/plugins/modules/apt_rpm.py
+++ b/ansible_collections/community/general/plugins/modules/apt_rpm.py
@@ -16,7 +16,7 @@ DOCUMENTATION = '''
module: apt_rpm
short_description: APT-RPM package manager
description:
- - Manages packages with I(apt-rpm). Both low-level (I(rpm)) and high-level (I(apt-get)) package manager binaries required.
+ - Manages packages with C(apt-rpm). Both low-level (C(rpm)) and high-level (C(apt-get)) package manager binaries required.
extends_documentation_fragment:
- community.general.attributes
attributes:
@@ -28,6 +28,9 @@ options:
package:
description:
- List of packages to install, upgrade, or remove.
+ - Since community.general 8.0.0, may include paths to local C(.rpm) files
+ if O(state=installed) or O(state=present), requires C(rpm) python
+ module.
aliases: [ name, pkg ]
type: list
elements: str
@@ -63,6 +66,9 @@ options:
type: bool
default: false
version_added: 6.5.0
+requirements:
+ - C(rpm) python package (rpm bindings), optional. Required if O(package)
+ option includes local files.
author:
- Evgenii Terechkov (@evgkrsk)
'''
@@ -109,15 +115,48 @@ EXAMPLES = '''
'''
import os
-
-from ansible.module_utils.basic import AnsibleModule
-
+import re
+import traceback
+
+from ansible.module_utils.basic import (
+ AnsibleModule,
+ missing_required_lib,
+)
+from ansible.module_utils.common.text.converters import to_native
+
+try:
+ import rpm
+except ImportError:
+ HAS_RPM_PYTHON = False
+ RPM_PYTHON_IMPORT_ERROR = traceback.format_exc()
+else:
+ HAS_RPM_PYTHON = True
+ RPM_PYTHON_IMPORT_ERROR = None
+
+APT_CACHE = "/usr/bin/apt-cache"
APT_PATH = "/usr/bin/apt-get"
RPM_PATH = "/usr/bin/rpm"
APT_GET_ZERO = "\n0 upgraded, 0 newly installed"
UPDATE_KERNEL_ZERO = "\nTry to install new kernel "
+def local_rpm_package_name(path):
+ """return package name of a local rpm passed in.
+ Inspired by ansible.builtin.yum"""
+
+ ts = rpm.TransactionSet()
+ ts.setVSFlags(rpm._RPMVSF_NOSIGNATURES)
+ fd = os.open(path, os.O_RDONLY)
+ try:
+ header = ts.hdrFromFdno(fd)
+ except rpm.error as e:
+ return None
+ finally:
+ os.close(fd)
+
+ return to_native(header[rpm.RPMTAG_NAME])
+
+
def query_package(module, name):
# rpm -q returns 0 if the package is installed,
# 1 if it is not installed
@@ -128,11 +167,38 @@ def query_package(module, name):
return False
+def check_package_version(module, name):
+ # compare installed and candidate version
+ # if newest version already installed return True
+ # otherwise return False
+
+ rc, out, err = module.run_command([APT_CACHE, "policy", name], environ_update={"LANG": "C"})
+ installed = re.split("\n |: ", out)[2]
+ candidate = re.split("\n |: ", out)[4]
+ if installed >= candidate:
+ return True
+ return False
+
+
def query_package_provides(module, name):
# rpm -q returns 0 if the package is installed,
# 1 if it is not installed
+ if name.endswith('.rpm'):
+ # Likely a local RPM file
+ if not HAS_RPM_PYTHON:
+ module.fail_json(
+ msg=missing_required_lib('rpm'),
+ exception=RPM_PYTHON_IMPORT_ERROR,
+ )
+
+ name = local_rpm_package_name(name)
+
rc, out, err = module.run_command("%s -q --provides %s" % (RPM_PATH, name))
- return rc == 0
+ if rc == 0:
+ if check_package_version(module, name):
+ return True
+ else:
+ return False
def update_package_db(module):
diff --git a/ansible_collections/community/general/plugins/modules/archive.py b/ansible_collections/community/general/plugins/modules/archive.py
index 8748fb8a3..6784aa1ac 100644
--- a/ansible_collections/community/general/plugins/modules/archive.py
+++ b/ansible_collections/community/general/plugins/modules/archive.py
@@ -20,7 +20,7 @@ extends_documentation_fragment:
description:
- Creates or extends an archive.
- The source and archive are on the remote host, and the archive I(is not) copied to the local host.
- - Source files can be deleted after archival by specifying I(remove=True).
+ - Source files can be deleted after archival by specifying O(remove=True).
attributes:
check_mode:
support: full
@@ -36,27 +36,26 @@ options:
format:
description:
- The type of compression to use.
- - Support for xz was added in Ansible 2.5.
type: str
choices: [ bz2, gz, tar, xz, zip ]
default: gz
dest:
description:
- The file name of the destination archive. The parent directory must exists on the remote host.
- - This is required when C(path) refers to multiple files by either specifying a glob, a directory or multiple paths in a list.
+ - This is required when O(path) refers to multiple files by either specifying a glob, a directory or multiple paths in a list.
- If the destination archive already exists, it will be truncated and overwritten.
type: path
exclude_path:
description:
- - Remote absolute path, glob, or list of paths or globs for the file or files to exclude from I(path) list and glob expansion.
- - Use I(exclusion_patterns) to instead exclude files or subdirectories below any of the paths from the I(path) list.
+ - Remote absolute path, glob, or list of paths or globs for the file or files to exclude from O(path) list and glob expansion.
+ - Use O(exclusion_patterns) to instead exclude files or subdirectories below any of the paths from the O(path) list.
type: list
elements: path
default: []
exclusion_patterns:
description:
- Glob style patterns to exclude files or directories from the resulting archive.
- - This differs from I(exclude_path) which applies only to the source paths from I(path).
+ - This differs from O(exclude_path) which applies only to the source paths from O(path).
type: list
elements: path
version_added: 3.2.0
@@ -73,7 +72,7 @@ options:
type: bool
default: false
notes:
- - Can produce I(gzip), I(bzip2), I(lzma), and I(zip) compressed files or archives.
+ - Can produce C(gzip), C(bzip2), C(lzma), and C(zip) compressed files or archives.
- This module uses C(tarfile), C(zipfile), C(gzip), and C(bz2) packages on the target host to create archives.
These are part of the Python standard library for Python 2 and 3.
requirements:
@@ -144,16 +143,16 @@ EXAMPLES = r'''
RETURN = r'''
state:
description:
- The state of the input C(path).
+ The state of the input O(path).
type: str
returned: always
dest_state:
description:
- - The state of the I(dest) file.
- - C(absent) when the file does not exist.
- - C(archive) when the file is an archive.
- - C(compress) when the file is compressed, but not an archive.
- - C(incomplete) when the file is an archive, but some files under I(path) were not found.
+ - The state of the O(dest) file.
+ - V(absent) when the file does not exist.
+ - V(archive) when the file is an archive.
+ - V(compress) when the file is compressed, but not an archive.
+ - V(incomplete) when the file is an archive, but some files under O(path) were not found.
type: str
returned: success
version_added: 3.4.0
diff --git a/ansible_collections/community/general/plugins/modules/atomic_container.py b/ansible_collections/community/general/plugins/modules/atomic_container.py
index c26510296..d1567c892 100644
--- a/ansible_collections/community/general/plugins/modules/atomic_container.py
+++ b/ansible_collections/community/general/plugins/modules/atomic_container.py
@@ -21,7 +21,6 @@ notes:
- Host should support C(atomic) command
requirements:
- atomic
- - "python >= 2.6"
extends_documentation_fragment:
- community.general.attributes
attributes:
diff --git a/ansible_collections/community/general/plugins/modules/atomic_host.py b/ansible_collections/community/general/plugins/modules/atomic_host.py
index bb44c4489..ebb74caf1 100644
--- a/ansible_collections/community/general/plugins/modules/atomic_host.py
+++ b/ansible_collections/community/general/plugins/modules/atomic_host.py
@@ -21,7 +21,6 @@ notes:
- Host should be an atomic platform (verified by existence of '/run/ostree-booted' file).
requirements:
- atomic
- - python >= 2.6
extends_documentation_fragment:
- community.general.attributes
attributes:
@@ -33,7 +32,7 @@ options:
revision:
description:
- The version number of the atomic host to be deployed.
- - Providing C(latest) will upgrade to the latest available version.
+ - Providing V(latest) will upgrade to the latest available version.
default: 'latest'
aliases: [ version ]
type: str
diff --git a/ansible_collections/community/general/plugins/modules/atomic_image.py b/ansible_collections/community/general/plugins/modules/atomic_image.py
index 65aec1e9d..4bd15e27a 100644
--- a/ansible_collections/community/general/plugins/modules/atomic_image.py
+++ b/ansible_collections/community/general/plugins/modules/atomic_image.py
@@ -21,7 +21,6 @@ notes:
- Host should support C(atomic) command.
requirements:
- atomic
- - python >= 2.6
extends_documentation_fragment:
- community.general.attributes
attributes:
@@ -43,7 +42,7 @@ options:
state:
description:
- The state of the container image.
- - The state C(latest) will ensure container image is upgraded to the latest version and forcefully restart container, if running.
+ - The state V(latest) will ensure container image is upgraded to the latest version and forcefully restart container, if running.
choices: [ 'absent', 'latest', 'present' ]
default: 'latest'
type: str
diff --git a/ansible_collections/community/general/plugins/modules/awall.py b/ansible_collections/community/general/plugins/modules/awall.py
index da1b29f70..f3c2384b5 100644
--- a/ansible_collections/community/general/plugins/modules/awall.py
+++ b/ansible_collections/community/general/plugins/modules/awall.py
@@ -16,7 +16,7 @@ short_description: Manage awall policies
author: Ted Trask (@tdtrask) <ttrask01@yahoo.com>
description:
- This modules allows for enable/disable/activate of C(awall) policies.
- - Alpine Wall (I(awall)) generates a firewall configuration from the enabled policy files
+ - Alpine Wall (C(awall)) generates a firewall configuration from the enabled policy files
and activates the configuration on the system.
extends_documentation_fragment:
- community.general.attributes
@@ -41,11 +41,11 @@ options:
description:
- Activate the new firewall rules.
- Can be run with other steps or on its own.
- - Idempotency is affected if I(activate=true), as the module will always report a changed state.
+ - Idempotency is affected if O(activate=true), as the module will always report a changed state.
type: bool
default: false
notes:
- - At least one of I(name) and I(activate) is required.
+ - At least one of O(name) and O(activate) is required.
'''
EXAMPLES = r'''
diff --git a/ansible_collections/community/general/plugins/modules/bearychat.py b/ansible_collections/community/general/plugins/modules/bearychat.py
index 28f1f8fcd..f52737fac 100644
--- a/ansible_collections/community/general/plugins/modules/bearychat.py
+++ b/ansible_collections/community/general/plugins/modules/bearychat.py
@@ -27,7 +27,7 @@ options:
description:
- BearyChat WebHook URL. This authenticates you to the bearychat
service. It looks like
- C(https://hook.bearychat.com/=ae2CF/incoming/e61bd5c57b164e04b11ac02e66f47f60).
+ V(https://hook.bearychat.com/=ae2CF/incoming/e61bd5c57b164e04b11ac02e66f47f60).
required: true
text:
type: str
@@ -35,14 +35,14 @@ options:
- Message to send.
markdown:
description:
- - If C(true), text will be parsed as markdown.
+ - If V(true), text will be parsed as markdown.
default: true
type: bool
channel:
type: str
description:
- Channel to send the message to. If absent, the message goes to the
- default channel selected by the I(url).
+ default channel selected by the O(url).
attachments:
type: list
elements: dict
diff --git a/ansible_collections/community/general/plugins/modules/bigpanda.py b/ansible_collections/community/general/plugins/modules/bigpanda.py
index bab200bc4..7bde5fc1d 100644
--- a/ansible_collections/community/general/plugins/modules/bigpanda.py
+++ b/ansible_collections/community/general/plugins/modules/bigpanda.py
@@ -72,10 +72,10 @@ options:
description:
- Base URL of the API server.
required: false
- default: https://api.bigpanda.io
+ default: "https://api.bigpanda.io"
validate_certs:
description:
- - If C(false), SSL certificates for the target url will not be validated. This should only be used
+ - If V(false), SSL certificates for the target url will not be validated. This should only be used
on personally controlled sites using self-signed certificates.
required: false
default: true
diff --git a/ansible_collections/community/general/plugins/modules/bitbucket_access_key.py b/ansible_collections/community/general/plugins/modules/bitbucket_access_key.py
index 5ef199f7a..29c19b8b3 100644
--- a/ansible_collections/community/general/plugins/modules/bitbucket_access_key.py
+++ b/ansible_collections/community/general/plugins/modules/bitbucket_access_key.py
@@ -33,7 +33,7 @@ options:
workspace:
description:
- The repository owner.
- - I(username) used to be an alias of this option. Since community.general 6.0.0 it is an alias of I(user).
+ - "B(Note:) O(ignore:username) used to be an alias of this option. Since community.general 6.0.0 it is an alias of O(user)."
type: str
required: true
key:
diff --git a/ansible_collections/community/general/plugins/modules/bitbucket_pipeline_key_pair.py b/ansible_collections/community/general/plugins/modules/bitbucket_pipeline_key_pair.py
index d39c054b1..3bc41c298 100644
--- a/ansible_collections/community/general/plugins/modules/bitbucket_pipeline_key_pair.py
+++ b/ansible_collections/community/general/plugins/modules/bitbucket_pipeline_key_pair.py
@@ -33,7 +33,7 @@ options:
workspace:
description:
- The repository owner.
- - I(username) used to be an alias of this option. Since community.general 6.0.0 it is an alias of I(user).
+ - "B(Note:) O(ignore:username) used to be an alias of this option. Since community.general 6.0.0 it is an alias of O(user)."
type: str
required: true
public_key:
diff --git a/ansible_collections/community/general/plugins/modules/bitbucket_pipeline_known_host.py b/ansible_collections/community/general/plugins/modules/bitbucket_pipeline_known_host.py
index 28ff48739..3e6c4bfbf 100644
--- a/ansible_collections/community/general/plugins/modules/bitbucket_pipeline_known_host.py
+++ b/ansible_collections/community/general/plugins/modules/bitbucket_pipeline_known_host.py
@@ -14,7 +14,7 @@ module: bitbucket_pipeline_known_host
short_description: Manages Bitbucket pipeline known hosts
description:
- Manages Bitbucket pipeline known hosts under the "SSH Keys" menu.
- - The host fingerprint will be retrieved automatically, but in case of an error, one can use I(key) field to specify it manually.
+ - The host fingerprint will be retrieved automatically, but in case of an error, one can use O(key) field to specify it manually.
author:
- Evgeniy Krysanov (@catcombo)
extends_documentation_fragment:
@@ -36,7 +36,7 @@ options:
workspace:
description:
- The repository owner.
- - I(username) used to be an alias of this option. Since community.general 6.0.0 it is an alias of I(user).
+ - "B(Note:) O(ignore:username) used to be an alias of this option. Since community.general 6.0.0 it is an alias of O(user)."
type: str
required: true
name:
diff --git a/ansible_collections/community/general/plugins/modules/bitbucket_pipeline_variable.py b/ansible_collections/community/general/plugins/modules/bitbucket_pipeline_variable.py
index eac0d18dd..1ff8e4375 100644
--- a/ansible_collections/community/general/plugins/modules/bitbucket_pipeline_variable.py
+++ b/ansible_collections/community/general/plugins/modules/bitbucket_pipeline_variable.py
@@ -33,7 +33,7 @@ options:
workspace:
description:
- The repository owner.
- - I(username) used to be an alias of this option. Since community.general 6.0.0 it is an alias of I(user).
+ - "B(Note:) O(ignore:username) used to be an alias of this option. Since community.general 6.0.0 it is an alias of O(user)."
type: str
required: true
name:
@@ -58,7 +58,7 @@ options:
choices: [ absent, present ]
notes:
- Check mode is supported.
- - For secured values return parameter C(changed) is always C(True).
+ - For secured values return parameter C(changed) is always V(true).
'''
EXAMPLES = r'''
diff --git a/ansible_collections/community/general/plugins/modules/btrfs_subvolume.py b/ansible_collections/community/general/plugins/modules/btrfs_subvolume.py
index cd2ac6f97..864bb65a6 100644
--- a/ansible_collections/community/general/plugins/modules/btrfs_subvolume.py
+++ b/ansible_collections/community/general/plugins/modules/btrfs_subvolume.py
@@ -23,7 +23,7 @@ options:
default: false
default:
description:
- - Make the subvolume specified by I(name) the filesystem's default subvolume.
+ - Make the subvolume specified by O(name) the filesystem's default subvolume.
type: bool
default: false
filesystem_device:
@@ -49,7 +49,7 @@ options:
recursive:
description:
- When true, indicates that parent/child subvolumes should be created/removedas necessary
- to complete the operation (for I(state=present) and I(state=absent) respectively).
+ to complete the operation (for O(state=present) and O(state=absent) respectively).
type: bool
default: false
snapshot_source:
@@ -60,11 +60,11 @@ options:
snapshot_conflict:
description:
- Policy defining behavior when a subvolume already exists at the path of the requested snapshot.
- - C(skip) - Create a snapshot only if a subvolume does not yet exist at the target location, otherwise indicate that no change is required.
+ - V(skip) - Create a snapshot only if a subvolume does not yet exist at the target location, otherwise indicate that no change is required.
Warning, this option does not yet verify that the target subvolume was generated from a snapshot of the requested source.
- - C(clobber) - If a subvolume already exists at the requested location, delete it first.
+ - V(clobber) - If a subvolume already exists at the requested location, delete it first.
This option is not idempotent and will result in a new snapshot being generated on every execution.
- - C(error) - If a subvolume already exists at the requested location, return an error.
+ - V(error) - If a subvolume already exists at the requested location, return an error.
This option is not idempotent and will result in an error on replay of the module.
type: str
choices: [ skip, clobber, error ]
@@ -77,7 +77,7 @@ options:
default: present
notes:
- - If any or all of the options I(filesystem_device), I(filesystem_label) or I(filesystem_uuid) parameters are provided, there is expected
+ - If any or all of the options O(filesystem_device), O(filesystem_label) or O(filesystem_uuid) parameters are provided, there is expected
to be a matching btrfs filesystem. If none are provided and only a single btrfs filesystem exists or only a single
btrfs filesystem is mounted, that filesystem will be used; otherwise, the module will take no action and return an error.
@@ -201,7 +201,7 @@ modifications:
target_subvolume_id:
description:
- - The ID of the subvolume specified with the I(name) parameter, either pre-existing or created as part of module execution.
+ - The ID of the subvolume specified with the O(name) parameter, either pre-existing or created as part of module execution.
type: int
sample: 257
returned: Success and subvolume exists after module execution
diff --git a/ansible_collections/community/general/plugins/modules/bundler.py b/ansible_collections/community/general/plugins/modules/bundler.py
index 682dd334a..59f10800c 100644
--- a/ansible_collections/community/general/plugins/modules/bundler.py
+++ b/ansible_collections/community/general/plugins/modules/bundler.py
@@ -30,7 +30,7 @@ options:
state:
type: str
description:
- - The desired state of the Gem bundle. C(latest) updates gems to the most recent, acceptable version
+ - The desired state of the Gem bundle. V(latest) updates gems to the most recent, acceptable version
choices: [present, latest]
default: present
chdir:
@@ -44,19 +44,19 @@ options:
elements: str
description:
- A list of Gemfile groups to exclude during operations. This only
- applies when state is C(present). Bundler considers this
+ applies when O(state=present). Bundler considers this
a 'remembered' property for the Gemfile and will automatically exclude
- groups in future operations even if C(exclude_groups) is not set
+ groups in future operations even if O(exclude_groups) is not set
clean:
description:
- - Only applies if state is C(present). If set removes any gems on the
+ - Only applies if O(state=present). If set removes any gems on the
target host that are not in the gemfile
type: bool
default: false
gemfile:
type: path
description:
- - Only applies if state is C(present). The path to the gemfile to use to install gems.
+ - Only applies if O(state=present). The path to the gemfile to use to install gems.
- If not specified it will default to the Gemfile in current directory
local:
description:
@@ -65,31 +65,31 @@ options:
default: false
deployment_mode:
description:
- - Only applies if state is C(present). If set it will install gems in
+ - Only applies if O(state=present). If set it will install gems in
./vendor/bundle instead of the default location. Requires a Gemfile.lock
file to have been created prior
type: bool
default: false
user_install:
description:
- - Only applies if state is C(present). Installs gems in the local user's cache or for all users
+ - Only applies if O(state=present). Installs gems in the local user's cache or for all users
type: bool
default: true
gem_path:
type: path
description:
- - Only applies if state is C(present). Specifies the directory to
- install the gems into. If C(chdir) is set then this path is relative to
- C(chdir)
+ - Only applies if O(state=present). Specifies the directory to
+ install the gems into. If O(chdir) is set then this path is relative to
+ O(chdir)
- If not specified the default RubyGems gem paths will be used.
binstub_directory:
type: path
description:
- - Only applies if state is C(present). Specifies the directory to
+ - Only applies if O(state=present). Specifies the directory to
install any gem bins files to. When executed the bin files will run
within the context of the Gemfile and fail if any required gem
- dependencies are not installed. If C(chdir) is set then this path is
- relative to C(chdir)
+ dependencies are not installed. If O(chdir) is set then this path is
+ relative to O(chdir)
extra_args:
type: str
description:
diff --git a/ansible_collections/community/general/plugins/modules/bzr.py b/ansible_collections/community/general/plugins/modules/bzr.py
index e7aca7c6b..5a60d765c 100644
--- a/ansible_collections/community/general/plugins/modules/bzr.py
+++ b/ansible_collections/community/general/plugins/modules/bzr.py
@@ -16,7 +16,7 @@ author:
- André Paramés (@andreparames)
short_description: Deploy software (or files) from bzr branches
description:
- - Manage I(bzr) branches to deploy files or software.
+ - Manage C(bzr) branches to deploy files or software.
extends_documentation_fragment:
- community.general.attributes
attributes:
@@ -44,9 +44,8 @@ options:
type: str
force:
description:
- - If C(true), any modified files in the working
- tree will be discarded. Before 1.9 the default
- value was C(true).
+ - If V(true), any modified files in the working
+ tree will be discarded.
type: bool
default: false
executable:
diff --git a/ansible_collections/community/general/plugins/modules/capabilities.py b/ansible_collections/community/general/plugins/modules/capabilities.py
index 9b72ac6ea..a0b6d5222 100644
--- a/ansible_collections/community/general/plugins/modules/capabilities.py
+++ b/ansible_collections/community/general/plugins/modules/capabilities.py
@@ -30,7 +30,7 @@ options:
aliases: [ key ]
capability:
description:
- - Desired capability to set (with operator and flags, if state is C(present)) or remove (if state is C(absent))
+ - Desired capability to set (with operator and flags, if O(state=present)) or remove (if O(state=absent))
type: str
required: true
aliases: [ cap ]
diff --git a/ansible_collections/community/general/plugins/modules/cargo.py b/ansible_collections/community/general/plugins/modules/cargo.py
index 24be43741..ba9c05ed7 100644
--- a/ansible_collections/community/general/plugins/modules/cargo.py
+++ b/ansible_collections/community/general/plugins/modules/cargo.py
@@ -25,6 +25,12 @@ attributes:
diff_mode:
support: none
options:
+ executable:
+ description:
+ - Path to the C(cargo) installed in the system.
+ - If not specified, the module will look C(cargo) in E(PATH).
+ type: path
+ version_added: 7.5.0
name:
description:
- The name of a Rust package to install.
@@ -35,15 +41,23 @@ options:
description:
->
The base path where to install the Rust packages. Cargo automatically appends
- C(/bin). In other words, C(/usr/local) will become C(/usr/local/bin).
+ V(/bin). In other words, V(/usr/local) will become V(/usr/local/bin).
type: path
version:
description:
->
- The version to install. If I(name) contains multiple values, the module will
+ The version to install. If O(name) contains multiple values, the module will
try to install all of them in this version.
type: str
required: false
+ locked:
+ description:
+ - Install with locked dependencies.
+ - This is only used when installing packages.
+ required: false
+ type: bool
+ default: false
+ version_added: 7.5.0
state:
description:
- The state of the Rust package.
@@ -52,7 +66,7 @@ options:
default: present
choices: [ "present", "absent", "latest" ]
requirements:
- - cargo installed in bin path (recommended /usr/local/bin)
+ - cargo installed
"""
EXAMPLES = r"""
@@ -60,6 +74,11 @@ EXAMPLES = r"""
community.general.cargo:
name: ludusavi
+- name: Install "ludusavi" Rust package with locked dependencies
+ community.general.cargo:
+ name: ludusavi
+ locked: true
+
- name: Install "ludusavi" Rust package in version 0.10.0
community.general.cargo:
name: ludusavi
@@ -90,12 +109,12 @@ from ansible.module_utils.basic import AnsibleModule
class Cargo(object):
def __init__(self, module, **kwargs):
self.module = module
+ self.executable = [kwargs["executable"] or module.get_bin_path("cargo", True)]
self.name = kwargs["name"]
self.path = kwargs["path"]
self.state = kwargs["state"]
self.version = kwargs["version"]
-
- self.executable = [module.get_bin_path("cargo", True)]
+ self.locked = kwargs["locked"]
@property
def path(self):
@@ -118,6 +137,10 @@ class Cargo(object):
def get_installed(self):
cmd = ["install", "--list"]
+ if self.path:
+ cmd.append("--root")
+ cmd.append(self.path)
+
data, dummy = self._exec(cmd, True, False, False)
package_regex = re.compile(r"^([\w\-]+) v(.+):$")
@@ -132,6 +155,8 @@ class Cargo(object):
def install(self, packages=None):
cmd = ["install"]
cmd.extend(packages or self.name)
+ if self.locked:
+ cmd.append("--locked")
if self.path:
cmd.append("--root")
cmd.append(self.path)
@@ -160,15 +185,16 @@ class Cargo(object):
def main():
arg_spec = dict(
+ executable=dict(default=None, type="path"),
name=dict(required=True, type="list", elements="str"),
path=dict(default=None, type="path"),
state=dict(default="present", choices=["present", "absent", "latest"]),
version=dict(default=None, type="str"),
+ locked=dict(default=False, type="bool"),
)
module = AnsibleModule(argument_spec=arg_spec, supports_check_mode=True)
name = module.params["name"]
- path = module.params["path"]
state = module.params["state"]
version = module.params["version"]
@@ -180,7 +206,7 @@ def main():
LANG="C", LC_ALL="C", LC_MESSAGES="C", LC_CTYPE="C"
)
- cargo = Cargo(module, name=name, path=path, state=state, version=version)
+ cargo = Cargo(module, **module.params)
changed, out, err = False, None, None
installed_packages = cargo.get_installed()
if state == "present":
diff --git a/ansible_collections/community/general/plugins/modules/catapult.py b/ansible_collections/community/general/plugins/modules/catapult.py
index a3bbef6c4..acd839851 100644
--- a/ansible_collections/community/general/plugins/modules/catapult.py
+++ b/ansible_collections/community/general/plugins/modules/catapult.py
@@ -28,13 +28,13 @@ options:
src:
type: str
description:
- - One of your catapult telephone numbers the message should come from (must be in E.164 format, like C(+19195551212)).
+ - One of your catapult telephone numbers the message should come from (must be in E.164 format, like V(+19195551212)).
required: true
dest:
type: list
elements: str
description:
- - The phone number or numbers the message should be sent to (must be in E.164 format, like C(+19195551212)).
+ - The phone number or numbers the message should be sent to (must be in E.164 format, like V(+19195551212)).
required: true
msg:
type: str
diff --git a/ansible_collections/community/general/plugins/modules/circonus_annotation.py b/ansible_collections/community/general/plugins/modules/circonus_annotation.py
index 937610776..f3b94a052 100644
--- a/ansible_collections/community/general/plugins/modules/circonus_annotation.py
+++ b/ansible_collections/community/general/plugins/modules/circonus_annotation.py
@@ -52,12 +52,12 @@ options:
type: int
description:
- Unix timestamp of event start
- - If not specified, it defaults to I(now).
+ - If not specified, it defaults to "now".
stop:
type: int
description:
- Unix timestamp of event end
- - If not specified, it defaults to I(now) + I(duration).
+ - If not specified, it defaults to "now" + O(duration).
duration:
type: int
description:
diff --git a/ansible_collections/community/general/plugins/modules/cisco_webex.py b/ansible_collections/community/general/plugins/modules/cisco_webex.py
index 2e5cb50ea..caa77f576 100644
--- a/ansible_collections/community/general/plugins/modules/cisco_webex.py
+++ b/ansible_collections/community/general/plugins/modules/cisco_webex.py
@@ -17,7 +17,7 @@ description:
- Send a message to a Cisco Webex Teams Room or Individual with options to control the formatting.
author: Drew Rusell (@drew-russell)
notes:
- - The C(recipient_id) type must be valid for the supplied C(recipient_id).
+ - The O(recipient_type) must be valid for the supplied O(recipient_id).
- Full API documentation can be found at U(https://developer.webex.com/docs/api/basics).
extends_documentation_fragment:
@@ -40,7 +40,7 @@ options:
recipient_id:
description:
- - The unique identifier associated with the supplied C(recipient_type).
+ - The unique identifier associated with the supplied O(recipient_type).
required: true
type: str
diff --git a/ansible_collections/community/general/plugins/modules/clc_firewall_policy.py b/ansible_collections/community/general/plugins/modules/clc_firewall_policy.py
index c832571d3..b30037c6f 100644
--- a/ansible_collections/community/general/plugins/modules/clc_firewall_policy.py
+++ b/ansible_collections/community/general/plugins/modules/clc_firewall_policy.py
@@ -49,7 +49,7 @@ options:
description:
- The list of ports associated with the policy.
TCP and UDP can take in single ports or port ranges.
- - "Example: C(['any', 'icmp', 'TCP/123', 'UDP/123', 'TCP/123-456', 'UDP/123-456'])."
+ - "Example: V(['any', 'icmp', 'TCP/123', 'UDP/123', 'TCP/123-456', 'UDP/123-456'])."
type: list
elements: str
firewall_policy_id:
diff --git a/ansible_collections/community/general/plugins/modules/clc_server.py b/ansible_collections/community/general/plugins/modules/clc_server.py
index d2d019ff0..6bfe5a9b9 100644
--- a/ansible_collections/community/general/plugins/modules/clc_server.py
+++ b/ansible_collections/community/general/plugins/modules/clc_server.py
@@ -1501,7 +1501,7 @@ class ClcServer:
return aa_policy_id
#
- # This is the function that gets patched to the Request.server object using a lamda closure
+ # This is the function that gets patched to the Request.server object using a lambda closure
#
@staticmethod
diff --git a/ansible_collections/community/general/plugins/modules/cloudflare_dns.py b/ansible_collections/community/general/plugins/modules/cloudflare_dns.py
index 8f45fcef3..d2bea4266 100644
--- a/ansible_collections/community/general/plugins/modules/cloudflare_dns.py
+++ b/ansible_collections/community/general/plugins/modules/cloudflare_dns.py
@@ -13,8 +13,6 @@ DOCUMENTATION = r'''
module: cloudflare_dns
author:
- Michael Gruener (@mgruener)
-requirements:
- - python >= 2.6
short_description: Manage Cloudflare DNS records
description:
- "Manages dns records via the Cloudflare API, see the docs: U(https://api.cloudflare.com/)."
@@ -31,7 +29,7 @@ options:
- API token.
- Required for api token authentication.
- "You can obtain your API token from the bottom of the Cloudflare 'My Account' page, found here: U(https://dash.cloudflare.com/)."
- - Can be specified in C(CLOUDFLARE_TOKEN) environment variable since community.general 2.0.0.
+ - Can be specified in E(CLOUDFLARE_TOKEN) environment variable since community.general 2.0.0.
type: str
required: false
version_added: '0.2.0'
@@ -51,41 +49,54 @@ options:
algorithm:
description:
- Algorithm number.
- - Required for I(type=DS) and I(type=SSHFP) when I(state=present).
+ - Required for O(type=DS) and O(type=SSHFP) when O(state=present).
type: int
cert_usage:
description:
- Certificate usage number.
- - Required for I(type=TLSA) when I(state=present).
+ - Required for O(type=TLSA) when O(state=present).
type: int
choices: [ 0, 1, 2, 3 ]
+ flag:
+ description:
+ - Issuer Critical Flag.
+ - Required for O(type=CAA) when O(state=present).
+ type: int
+ choices: [ 0, 1 ]
+ version_added: 8.0.0
+ tag:
+ description:
+ - CAA issue restriction.
+ - Required for O(type=CAA) when O(state=present).
+ type: str
+ choices: [ issue, issuewild, iodef ]
+ version_added: 8.0.0
hash_type:
description:
- Hash type number.
- - Required for I(type=DS), I(type=SSHFP) and I(type=TLSA) when I(state=present).
+ - Required for O(type=DS), O(type=SSHFP) and O(type=TLSA) when O(state=present).
type: int
choices: [ 1, 2 ]
key_tag:
description:
- DNSSEC key tag.
- - Needed for I(type=DS) when I(state=present).
+ - Needed for O(type=DS) when O(state=present).
type: int
port:
description:
- Service port.
- - Required for I(type=SRV) and I(type=TLSA).
+ - Required for O(type=SRV) and O(type=TLSA).
type: int
priority:
description:
- Record priority.
- - Required for I(type=MX) and I(type=SRV)
+ - Required for O(type=MX) and O(type=SRV)
default: 1
type: int
proto:
description:
- - Service protocol. Required for I(type=SRV) and I(type=TLSA).
+ - Service protocol. Required for O(type=SRV) and O(type=TLSA).
- Common values are TCP and UDP.
- - Before Ansible 2.6 only TCP and UDP were available.
type: str
proxied:
description:
@@ -95,26 +106,26 @@ options:
record:
description:
- Record to add.
- - Required if I(state=present).
- - Default is C(@) (e.g. the zone name).
+ - Required if O(state=present).
+ - Default is V(@) (that is, the zone name).
type: str
default: '@'
aliases: [ name ]
selector:
description:
- Selector number.
- - Required for I(type=TLSA) when I(state=present).
+ - Required for O(type=TLSA) when O(state=present).
choices: [ 0, 1 ]
type: int
service:
description:
- Record service.
- - Required for I(type=SRV).
+ - Required for O(type=SRV).
type: str
solo:
description:
- Whether the record should be the only one for that record type and record name.
- - Only use with I(state=present).
+ - Only use with O(state=present).
- This will delete all other records with the same record name and type.
type: bool
state:
@@ -136,20 +147,20 @@ options:
default: 1
type:
description:
- - The type of DNS record to create. Required if I(state=present).
- - I(type=DS), I(type=SSHFP) and I(type=TLSA) added in Ansible 2.7.
+ - The type of DNS record to create. Required if O(state=present).
+ - Note that V(SPF) is no longer supported by CloudFlare. Support for it will be removed from community.general 9.0.0.
type: str
- choices: [ A, AAAA, CNAME, DS, MX, NS, SPF, SRV, SSHFP, TLSA, TXT ]
+ choices: [ A, AAAA, CNAME, DS, MX, NS, SPF, SRV, SSHFP, TLSA, CAA, TXT ]
value:
description:
- The record value.
- - Required for I(state=present).
+ - Required for O(state=present).
type: str
aliases: [ content ]
weight:
description:
- Service weight.
- - Required for I(type=SRV).
+ - Required for O(type=SRV).
type: int
default: 1
zone:
@@ -262,6 +273,15 @@ EXAMPLES = r'''
hash_type: 1
value: 6b76d034492b493e15a7376fccd08e63befdad0edab8e442562f532338364bf3
+- name: Create a CAA record subdomain.example.com
+ community.general.cloudflare_dns:
+ zone: example.com
+ record: subdomain
+ type: CAA
+ flag: 0
+ tag: issue
+ value: ca.example.com
+
- name: Create a DS record for subdomain.example.com
community.general.cloudflare_dns:
zone: example.com
@@ -291,7 +311,7 @@ record:
sample: "2016-03-25T19:09:42.516553Z"
data:
description: Additional record data.
- returned: success, if type is SRV, DS, SSHFP or TLSA
+ returned: success, if type is SRV, DS, SSHFP TLSA or CAA
type: dict
sample: {
name: "jabber",
@@ -391,6 +411,8 @@ class CloudflareAPI(object):
self.algorithm = module.params['algorithm']
self.cert_usage = module.params['cert_usage']
self.hash_type = module.params['hash_type']
+ self.flag = module.params['flag']
+ self.tag = module.params['tag']
self.key_tag = module.params['key_tag']
self.port = module.params['port']
self.priority = module.params['priority']
@@ -595,7 +617,7 @@ class CloudflareAPI(object):
def delete_dns_records(self, **kwargs):
params = {}
for param in ['port', 'proto', 'service', 'solo', 'type', 'record', 'value', 'weight', 'zone',
- 'algorithm', 'cert_usage', 'hash_type', 'selector', 'key_tag']:
+ 'algorithm', 'cert_usage', 'hash_type', 'selector', 'key_tag', 'flag', 'tag']:
if param in kwargs:
params[param] = kwargs[param]
else:
@@ -613,7 +635,7 @@ class CloudflareAPI(object):
content = str(params['key_tag']) + '\t' + str(params['algorithm']) + '\t' + str(params['hash_type']) + '\t' + params['value']
elif params['type'] == 'SSHFP':
if not (params['value'] is None or params['value'] == ''):
- content = str(params['algorithm']) + '\t' + str(params['hash_type']) + '\t' + params['value']
+ content = str(params['algorithm']) + ' ' + str(params['hash_type']) + ' ' + params['value'].upper()
elif params['type'] == 'TLSA':
if not (params['value'] is None or params['value'] == ''):
content = str(params['cert_usage']) + '\t' + str(params['selector']) + '\t' + str(params['hash_type']) + '\t' + params['value']
@@ -640,7 +662,7 @@ class CloudflareAPI(object):
def ensure_dns_record(self, **kwargs):
params = {}
for param in ['port', 'priority', 'proto', 'proxied', 'service', 'ttl', 'type', 'record', 'value', 'weight', 'zone',
- 'algorithm', 'cert_usage', 'hash_type', 'selector', 'key_tag']:
+ 'algorithm', 'cert_usage', 'hash_type', 'selector', 'key_tag', 'flag', 'tag']:
if param in kwargs:
params[param] = kwargs[param]
else:
@@ -726,7 +748,7 @@ class CloudflareAPI(object):
if (attr is None) or (attr == ''):
self.module.fail_json(msg="You must provide algorithm, hash_type and a value to create this record type")
sshfp_data = {
- "fingerprint": params['value'],
+ "fingerprint": params['value'].upper(),
"type": params['hash_type'],
"algorithm": params['algorithm'],
}
@@ -736,7 +758,7 @@ class CloudflareAPI(object):
'data': sshfp_data,
"ttl": params['ttl'],
}
- search_value = str(params['algorithm']) + '\t' + str(params['hash_type']) + '\t' + params['value']
+ search_value = str(params['algorithm']) + ' ' + str(params['hash_type']) + ' ' + params['value']
if params['type'] == 'TLSA':
for attr in [params['port'], params['proto'], params['cert_usage'], params['selector'], params['hash_type'], params['value']]:
@@ -757,12 +779,36 @@ class CloudflareAPI(object):
}
search_value = str(params['cert_usage']) + '\t' + str(params['selector']) + '\t' + str(params['hash_type']) + '\t' + params['value']
+ if params['type'] == 'CAA':
+ for attr in [params['flag'], params['tag'], params['value']]:
+ if (attr is None) or (attr == ''):
+ self.module.fail_json(msg="You must provide flag, tag and a value to create this record type")
+ caa_data = {
+ "flags": params['flag'],
+ "tag": params['tag'],
+ "value": params['value'],
+ }
+ new_record = {
+ "type": params['type'],
+ "name": params['record'],
+ 'data': caa_data,
+ "ttl": params['ttl'],
+ }
+ search_value = None
+
zone_id = self._get_zone_id(params['zone'])
records = self.get_dns_records(params['zone'], params['type'], search_record, search_value)
# in theory this should be impossible as cloudflare does not allow
# the creation of duplicate records but lets cover it anyways
if len(records) > 1:
- self.module.fail_json(msg="More than one record already exists for the given attributes. That should be impossible, please open an issue!")
+ # As Cloudflare API cannot filter record containing quotes
+ # CAA records must be compared locally
+ if params['type'] == 'CAA':
+ for rr in records:
+ if rr['data']['flags'] == caa_data['flags'] and rr['data']['tag'] == caa_data['tag'] and rr['data']['value'] == caa_data['value']:
+ return rr, self.changed
+ else:
+ self.module.fail_json(msg="More than one record already exists for the given attributes. That should be impossible, please open an issue!")
# record already exists, check if it must be updated
if len(records) == 1:
cur_record = records[0]
@@ -811,6 +857,8 @@ def main():
hash_type=dict(type='int', choices=[1, 2]),
key_tag=dict(type='int', no_log=False),
port=dict(type='int'),
+ flag=dict(type='int', choices=[0, 1]),
+ tag=dict(type='str', choices=['issue', 'issuewild', 'iodef']),
priority=dict(type='int', default=1),
proto=dict(type='str'),
proxied=dict(type='bool', default=False),
@@ -821,7 +869,7 @@ def main():
state=dict(type='str', default='present', choices=['absent', 'present']),
timeout=dict(type='int', default=30),
ttl=dict(type='int', default=1),
- type=dict(type='str', choices=['A', 'AAAA', 'CNAME', 'DS', 'MX', 'NS', 'SPF', 'SRV', 'SSHFP', 'TLSA', 'TXT']),
+ type=dict(type='str', choices=['A', 'AAAA', 'CNAME', 'DS', 'MX', 'NS', 'SPF', 'SRV', 'SSHFP', 'TLSA', 'CAA', 'TXT']),
value=dict(type='str', aliases=['content']),
weight=dict(type='int', default=1),
zone=dict(type='str', required=True, aliases=['domain']),
@@ -832,6 +880,7 @@ def main():
('state', 'absent', ['record']),
('type', 'SRV', ['proto', 'service']),
('type', 'TLSA', ['proto', 'port']),
+ ('type', 'CAA', ['flag', 'tag']),
],
)
@@ -858,6 +907,13 @@ def main():
and (module.params['value'] is None or module.params['value'] == ''))):
module.fail_json(msg="For TLSA records the params cert_usage, selector, hash_type and value all need to be defined, or not at all.")
+ if module.params['type'] == 'CAA':
+ if not ((module.params['flag'] is not None and module.params['tag'] is not None
+ and not (module.params['value'] is None or module.params['value'] == ''))
+ or (module.params['flag'] is None and module.params['tag'] is None
+ and (module.params['value'] is None or module.params['value'] == ''))):
+ module.fail_json(msg="For CAA records the params flag, tag and value all need to be defined, or not at all.")
+
if module.params['type'] == 'DS':
if not ((module.params['key_tag'] is not None and module.params['algorithm'] is not None and module.params['hash_type'] is not None
and not (module.params['value'] is None or module.params['value'] == ''))
diff --git a/ansible_collections/community/general/plugins/modules/cobbler_sync.py b/ansible_collections/community/general/plugins/modules/cobbler_sync.py
index d7acf4be6..4ec87c96c 100644
--- a/ansible_collections/community/general/plugins/modules/cobbler_sync.py
+++ b/ansible_collections/community/general/plugins/modules/cobbler_sync.py
@@ -30,7 +30,7 @@ options:
port:
description:
- Port number to be used for REST connection.
- - The default value depends on parameter C(use_ssl).
+ - The default value depends on parameter O(use_ssl).
type: int
username:
description:
@@ -43,13 +43,13 @@ options:
type: str
use_ssl:
description:
- - If C(false), an HTTP connection will be used instead of the default HTTPS connection.
+ - If V(false), an HTTP connection will be used instead of the default HTTPS connection.
type: bool
default: true
validate_certs:
description:
- - If C(false), SSL certificates will not be validated.
- - This should only set to C(false) when used on personally controlled sites using self-signed certificates.
+ - If V(false), SSL certificates will not be validated.
+ - This should only set to V(false) when used on personally controlled sites using self-signed certificates.
type: bool
default: true
author:
diff --git a/ansible_collections/community/general/plugins/modules/cobbler_system.py b/ansible_collections/community/general/plugins/modules/cobbler_system.py
index c30b4f1c1..cecc02f71 100644
--- a/ansible_collections/community/general/plugins/modules/cobbler_system.py
+++ b/ansible_collections/community/general/plugins/modules/cobbler_system.py
@@ -30,7 +30,7 @@ options:
port:
description:
- Port number to be used for REST connection.
- - The default value depends on parameter C(use_ssl).
+ - The default value depends on parameter O(use_ssl).
type: int
username:
description:
@@ -43,13 +43,13 @@ options:
type: str
use_ssl:
description:
- - If C(false), an HTTP connection will be used instead of the default HTTPS connection.
+ - If V(false), an HTTP connection will be used instead of the default HTTPS connection.
type: bool
default: true
validate_certs:
description:
- - If C(false), SSL certificates will not be validated.
- - This should only set to C(false) when used on personally controlled sites using self-signed certificates.
+ - If V(false), SSL certificates will not be validated.
+ - This should only set to V(false) when used on personally controlled sites using self-signed certificates.
type: bool
default: true
name:
@@ -144,11 +144,11 @@ EXAMPLES = r'''
RETURN = r'''
systems:
description: List of systems
- returned: I(state=query) and I(name) is not provided
+ returned: O(state=query) and O(name) is not provided
type: list
system:
description: (Resulting) information about the system we are working with
- returned: when I(name) is provided
+ returned: when O(name) is provided
type: dict
'''
diff --git a/ansible_collections/community/general/plugins/modules/composer.py b/ansible_collections/community/general/plugins/modules/composer.py
index 793abcda1..3d1c4a346 100644
--- a/ansible_collections/community/general/plugins/modules/composer.py
+++ b/ansible_collections/community/general/plugins/modules/composer.py
@@ -49,7 +49,7 @@ options:
description:
- Directory of your project (see --working-dir). This is required when
the command is not run globally.
- - Will be ignored if I(global_command=true).
+ - Will be ignored if O(global_command=true).
global_command:
description:
- Runs the specified command globally.
@@ -107,11 +107,11 @@ options:
composer_executable:
type: path
description:
- - Path to composer executable on the remote host, if composer is not in C(PATH) or a custom composer is needed.
+ - Path to composer executable on the remote host, if composer is not in E(PATH) or a custom composer is needed.
version_added: 3.2.0
requirements:
- php
- - composer installed in bin path (recommended /usr/local/bin) or specified in I(composer_executable)
+ - composer installed in bin path (recommended /usr/local/bin) or specified in O(composer_executable)
notes:
- Default options that are always appended in each execution are --no-ansi, --no-interaction and --no-progress if available.
- We received reports about issues on macOS if composer was installed by Homebrew. Please use the official install method to avoid issues.
@@ -170,10 +170,15 @@ def get_available_options(module, command='install'):
return command_help_json['definition']['options']
-def composer_command(module, command, arguments="", options=None, global_command=False):
+def composer_command(module, command, arguments="", options=None):
if options is None:
options = []
+ global_command = module.params['global_command']
+
+ if not global_command:
+ options.extend(['--working-dir', "'%s'" % module.params['working_dir']])
+
if module.params['executable'] is None:
php_path = module.get_bin_path("php", True, ["/usr/local/bin"])
else:
@@ -217,7 +222,6 @@ def main():
module.fail_json(msg="Use the 'arguments' param for passing arguments with the 'command'")
arguments = module.params['arguments']
- global_command = module.params['global_command']
available_options = get_available_options(module=module, command=command)
options = []
@@ -234,9 +238,6 @@ def main():
option = "--%s" % option
options.append(option)
- if not global_command:
- options.extend(['--working-dir', "'%s'" % module.params['working_dir']])
-
option_params = {
'prefer_source': 'prefer-source',
'prefer_dist': 'prefer-dist',
@@ -260,7 +261,7 @@ def main():
else:
module.exit_json(skipped=True, msg="command '%s' does not support check mode, skipping" % command)
- rc, out, err = composer_command(module, command, arguments, options, global_command)
+ rc, out, err = composer_command(module, command, arguments, options)
if rc != 0:
output = parse_out(err)
diff --git a/ansible_collections/community/general/plugins/modules/consul.py b/ansible_collections/community/general/plugins/modules/consul.py
index cc599be36..fe1a89883 100644
--- a/ansible_collections/community/general/plugins/modules/consul.py
+++ b/ansible_collections/community/general/plugins/modules/consul.py
@@ -21,8 +21,8 @@ description:
notify the health of the entire node to the cluster.
Service level checks do not require a check name or id as these are derived
by Consul from the Service name and id respectively by appending 'service:'
- Node level checks require a I(check_name) and optionally a I(check_id)."
- - Currently, there is no complete way to retrieve the script, interval or ttl
+ Node level checks require a O(check_name) and optionally a O(check_id)."
+ - Currently, there is no complete way to retrieve the script, interval or TTL
metadata for a registered check. Without this metadata it is not possible to
tell if the data supplied with ansible represents a change to a check. As a
result this does not attempt to determine changes and will always report a
@@ -56,7 +56,7 @@ options:
service_id:
type: str
description:
- - The ID for the service, must be unique per node. If I(state=absent),
+ - The ID for the service, must be unique per node. If O(state=absent),
defaults to the service name if supplied.
host:
type: str
@@ -86,12 +86,12 @@ options:
type: int
description:
- The port on which the service is listening. Can optionally be supplied for
- registration of a service, i.e. if I(service_name) or I(service_id) is set.
+ registration of a service, that is if O(service_name) or O(service_id) is set.
service_address:
type: str
description:
- The address to advertise that the service will be listening on.
- This value will be passed as the I(address) parameter to Consul's
+ This value will be passed as the C(address) parameter to Consul's
C(/v1/agent/service/register) API method, so refer to the Consul API
documentation for further details.
tags:
@@ -103,55 +103,69 @@ options:
type: str
description:
- The script/command that will be run periodically to check the health of the service.
- - Requires I(interval) to be provided.
+ - Requires O(interval) to be provided.
+ - Mutually exclusive with O(ttl), O(tcp) and O(http).
interval:
type: str
description:
- The interval at which the service check will be run.
- This is a number with a C(s) or C(m) suffix to signify the units of seconds or minutes e.g C(15s) or C(1m).
- If no suffix is supplied C(s) will be used by default, e.g. C(10) will be C(10s).
- - Required if one of the parameters I(script), I(http), or I(tcp) is specified.
+ This is a number with a V(s) or V(m) suffix to signify the units of seconds or minutes, for example V(15s) or V(1m).
+ If no suffix is supplied V(s) will be used by default, for example V(10) will be V(10s).
+ - Required if one of the parameters O(script), O(http), or O(tcp) is specified.
check_id:
type: str
description:
- - An ID for the service check. If I(state=absent), defaults to
- I(check_name). Ignored if part of a service definition.
+ - An ID for the service check. If O(state=absent), defaults to
+ O(check_name). Ignored if part of a service definition.
check_name:
type: str
description:
- Name for the service check. Required if standalone, ignored if
part of service definition.
+ check_node:
+ description:
+ - Node name.
+ # TODO: properly document!
+ type: str
+ check_host:
+ description:
+ - Host name.
+ # TODO: properly document!
+ type: str
ttl:
type: str
description:
- - Checks can be registered with a ttl instead of a I(script) and I(interval)
+ - Checks can be registered with a TTL instead of a O(script) and O(interval)
this means that the service will check in with the agent before the
- ttl expires. If it doesn't the check will be considered failed.
+ TTL expires. If it doesn't the check will be considered failed.
Required if registering a check and the script an interval are missing
- Similar to the interval this is a number with a C(s) or C(m) suffix to
- signify the units of seconds or minutes e.g C(15s) or C(1m).
- If no suffix is supplied C(s) will be used by default, e.g. C(10) will be C(10s).
+ Similar to the interval this is a number with a V(s) or V(m) suffix to
+ signify the units of seconds or minutes, for example V(15s) or V(1m).
+ If no suffix is supplied V(s) will be used by default, for example V(10) will be V(10s).
+ - Mutually exclusive with O(script), O(tcp) and O(http).
tcp:
type: str
description:
- Checks can be registered with a TCP port. This means that consul
will check if the connection attempt to that port is successful (that is, the port is currently accepting connections).
- The format is C(host:port), for example C(localhost:80).
- - Requires I(interval) to be provided.
+ The format is V(host:port), for example V(localhost:80).
+ - Requires O(interval) to be provided.
+ - Mutually exclusive with O(script), O(ttl) and O(http).
version_added: '1.3.0'
http:
type: str
description:
- Checks can be registered with an HTTP endpoint. This means that consul
will check that the http endpoint returns a successful HTTP status.
- - Requires I(interval) to be provided.
+ - Requires O(interval) to be provided.
+ - Mutually exclusive with O(script), O(ttl) and O(tcp).
timeout:
type: str
description:
- A custom HTTP check timeout. The consul default is 10 seconds.
- Similar to the interval this is a number with a C(s) or C(m) suffix to
- signify the units of seconds or minutes, e.g. C(15s) or C(1m).
- If no suffix is supplied C(s) will be used by default, e.g. C(10) will be C(10s).
+ Similar to the interval this is a number with a V(s) or V(m) suffix to
+ signify the units of seconds or minutes, for example V(15s) or V(1m).
+ If no suffix is supplied V(s) will be used by default, for example V(10) will be V(10s).
token:
type: str
description:
@@ -159,7 +173,7 @@ options:
ack_params_state_absent:
type: bool
description:
- - Disable deprecation warning when using parameters incompatible with I(state=absent).
+ - This parameter has no more effect and is deprecated. It will be removed in community.general 10.0.0.
'''
EXAMPLES = '''
@@ -377,13 +391,7 @@ def get_service_by_id_or_name(consul_api, service_id_or_name):
def parse_check(module):
- _checks = [module.params[p] for p in ('script', 'ttl', 'tcp', 'http') if module.params[p]]
-
- if len(_checks) > 1:
- module.fail_json(
- msg='checks are either script, tcp, http or ttl driven, supplying more than one does not make sense')
-
- if module.params['check_id'] or _checks:
+ if module.params['check_id'] or any(module.params[p] is not None for p in ('script', 'ttl', 'tcp', 'http')):
return ConsulCheck(
module.params['check_id'],
module.params['check_name'],
@@ -501,15 +509,9 @@ class ConsulCheck(object):
self.check = consul.Check.ttl(self.ttl)
if http:
- if interval is None:
- raise Exception('http check must specify interval')
-
self.check = consul.Check.http(http, self.interval, self.timeout)
if tcp:
- if interval is None:
- raise Exception('tcp check must specify interval')
-
regex = r"(?P<host>.*):(?P<port>(?:[0-9]+))$"
match = re.match(regex, tcp)
@@ -596,30 +598,33 @@ def main():
timeout=dict(type='str'),
tags=dict(type='list', elements='str'),
token=dict(no_log=True),
- ack_params_state_absent=dict(type='bool'),
+ ack_params_state_absent=dict(
+ type='bool',
+ removed_in_version='10.0.0',
+ removed_from_collection='community.general',
+ ),
),
+ mutually_exclusive=[
+ ('script', 'ttl', 'tcp', 'http'),
+ ],
required_if=[
('state', 'present', ['service_name']),
('state', 'absent', ['service_id', 'service_name', 'check_id', 'check_name'], True),
],
+ required_by={
+ 'script': 'interval',
+ 'http': 'interval',
+ 'tcp': 'interval',
+ },
supports_check_mode=False,
)
p = module.params
test_dependencies(module)
- if p['state'] == 'absent' and any(p[x] for x in ['script', 'ttl', 'tcp', 'http', 'interval']) and not p['ack_params_state_absent']:
- module.deprecate(
- "The use of parameters 'script', 'ttl', 'tcp', 'http', 'interval' along with 'state=absent' is deprecated. "
- "In community.general 8.0.0 their use will become an error. "
- "To suppress this deprecation notice, set parameter ack_params_state_absent=true.",
- version="8.0.0",
- collection_name="community.general",
+ if p['state'] == 'absent' and any(p[x] for x in ['script', 'ttl', 'tcp', 'http', 'interval']):
+ module.fail_json(
+ msg="The use of parameters 'script', 'ttl', 'tcp', 'http', 'interval' along with 'state=absent' is no longer allowed."
)
- # When reaching c.g 8.0.0:
- # - Replace the deprecation with a fail_json(), remove the "ack_params_state_absent" condition from the "if"
- # - Add mutually_exclusive for ('script', 'ttl', 'tcp', 'http'), then remove that validation from parse_check()
- # - Add required_by {'script': 'interval', 'http': 'interval', 'tcp': 'interval'}, then remove checks for 'interval' in ConsulCheck.__init__()
- # - Deprecate the parameter ack_params_state_absent
try:
register_with_consul(module)
diff --git a/ansible_collections/community/general/plugins/modules/consul_acl.py b/ansible_collections/community/general/plugins/modules/consul_acl.py
index 91f955228..4617090fd 100644
--- a/ansible_collections/community/general/plugins/modules/consul_acl.py
+++ b/ansible_collections/community/general/plugins/modules/consul_acl.py
@@ -26,6 +26,10 @@ attributes:
support: none
diff_mode:
support: none
+deprecated:
+ removed_in: 10.0.0
+ why: The legacy ACL system was removed from Consul.
+ alternative: Use M(community.general.consul_token) and/or M(community.general.consul_policy) instead.
options:
mgmt_token:
description:
@@ -156,7 +160,7 @@ token:
rules:
description: the HCL JSON representation of the rules associated to the ACL, in the format described in the
Consul documentation (https://www.consul.io/docs/guides/acl.html#rule-specification).
- returned: I(status) == "present"
+ returned: when O(state=present)
type: dict
sample: {
"key": {
diff --git a/ansible_collections/community/general/plugins/modules/consul_acl_bootstrap.py b/ansible_collections/community/general/plugins/modules/consul_acl_bootstrap.py
new file mode 100644
index 000000000..bf1da110b
--- /dev/null
+++ b/ansible_collections/community/general/plugins/modules/consul_acl_bootstrap.py
@@ -0,0 +1,108 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2024, Florian Apolloner (@apollo13)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+module: consul_acl_bootstrap
+short_description: Bootstrap ACLs in Consul
+version_added: 8.3.0
+description:
+ - Allows bootstrapping of ACLs in a Consul cluster, see
+ U(https://developer.hashicorp.com/consul/api-docs/acl#bootstrap-acls) for details.
+author:
+ - Florian Apolloner (@apollo13)
+extends_documentation_fragment:
+ - community.general.consul
+ - community.general.attributes
+attributes:
+ check_mode:
+ support: none
+ diff_mode:
+ support: none
+options:
+ state:
+ description:
+ - Whether the token should be present or absent.
+ choices: ['present', 'bootstrapped']
+ default: present
+ type: str
+ bootstrap_secret:
+ description:
+ - The secret to be used as secret ID for the initial token.
+ - Needs to be an UUID.
+ type: str
+"""
+
+EXAMPLES = """
+- name: Bootstrap the ACL system
+ community.general.consul_acl_bootstrap:
+ bootstrap_secret: 22eaeed1-bdbd-4651-724e-42ae6c43e387
+"""
+
+RETURN = """
+result:
+ description:
+ - The bootstrap result as returned by the consul HTTP API.
+ - "B(Note:) If O(bootstrap_secret) has been specified the C(SecretID) and
+ C(ID) will not contain the secret but C(VALUE_SPECIFIED_IN_NO_LOG_PARAMETER).
+ If you pass O(bootstrap_secret), make sure your playbook/role does not depend
+ on this return value!"
+ returned: changed
+ type: dict
+ sample:
+ AccessorID: 834a5881-10a9-a45b-f63c-490e28743557
+ CreateIndex: 25
+ CreateTime: '2024-01-21T20:26:27.114612038+01:00'
+ Description: Bootstrap Token (Global Management)
+ Hash: X2AgaFhnQGRhSSF/h0m6qpX1wj/HJWbyXcxkEM/5GrY=
+ ID: VALUE_SPECIFIED_IN_NO_LOG_PARAMETER
+ Local: false
+ ModifyIndex: 25
+ Policies:
+ - ID: 00000000-0000-0000-0000-000000000001
+ Name: global-management
+ SecretID: VALUE_SPECIFIED_IN_NO_LOG_PARAMETER
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.community.general.plugins.module_utils.consul import (
+ AUTH_ARGUMENTS_SPEC,
+ RequestError,
+ _ConsulModule,
+)
+
+_ARGUMENT_SPEC = {
+ "state": dict(type="str", choices=["present", "bootstrapped"], default="present"),
+ "bootstrap_secret": dict(type="str", no_log=True),
+}
+_ARGUMENT_SPEC.update(AUTH_ARGUMENTS_SPEC)
+_ARGUMENT_SPEC.pop("token")
+
+
+def main():
+ module = AnsibleModule(_ARGUMENT_SPEC)
+ consul_module = _ConsulModule(module)
+
+ data = {}
+ if "bootstrap_secret" in module.params:
+ data["BootstrapSecret"] = module.params["bootstrap_secret"]
+
+ try:
+ response = consul_module.put("acl/bootstrap", data=data)
+ except RequestError as e:
+ if e.status == 403 and b"ACL bootstrap no longer allowed" in e.response_data:
+ return module.exit_json(changed=False)
+ raise
+ else:
+ return module.exit_json(changed=True, result=response)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/general/plugins/modules/consul_auth_method.py b/ansible_collections/community/general/plugins/modules/consul_auth_method.py
new file mode 100644
index 000000000..afe549f6e
--- /dev/null
+++ b/ansible_collections/community/general/plugins/modules/consul_auth_method.py
@@ -0,0 +1,207 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2024, Florian Apolloner (@apollo13)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+module: consul_auth_method
+short_description: Manipulate Consul auth methods
+version_added: 8.3.0
+description:
+ - Allows the addition, modification and deletion of auth methods in a consul
+ cluster via the agent. For more details on using and configuring ACLs,
+ see U(https://www.consul.io/docs/guides/acl.html).
+author:
+ - Florian Apolloner (@apollo13)
+extends_documentation_fragment:
+ - community.general.consul
+ - community.general.consul.actiongroup_consul
+ - community.general.consul.token
+ - community.general.attributes
+attributes:
+ check_mode:
+ support: full
+ diff_mode:
+ support: partial
+ details:
+ - In check mode the diff will miss operational attributes.
+options:
+ state:
+ description:
+ - Whether the token should be present or absent.
+ choices: ['present', 'absent']
+ default: present
+ type: str
+ name:
+ description:
+ - Specifies a name for the ACL auth method.
+ - The name can contain alphanumeric characters, dashes C(-), and underscores C(_).
+ type: str
+ required: true
+ type:
+ description:
+ - The type of auth method being configured.
+ - This field is immutable.
+ - Required when the auth method is created.
+ type: str
+ choices: ['kubernetes', 'jwt', 'oidc', 'aws-iam']
+ description:
+ description:
+ - Free form human readable description of the auth method.
+ type: str
+ display_name:
+ description:
+ - An optional name to use instead of O(name) when displaying information about this auth method.
+ type: str
+ max_token_ttl:
+ description:
+ - This specifies the maximum life of any token created by this auth method.
+ - Can be specified in the form of V(60s) or V(5m) (that is, 60 seconds or 5 minutes, respectively).
+ type: str
+ token_locality:
+ description:
+ - Defines the kind of token that this auth method should produce.
+ type: str
+ choices: ['local', 'global']
+ config:
+ description:
+ - The raw configuration to use for the chosen auth method.
+ - Contents will vary depending upon the type chosen.
+ - Required when the auth method is created.
+ type: dict
+"""
+
+EXAMPLES = """
+- name: Create an auth method
+ community.general.consul_auth_method:
+ name: test
+ type: jwt
+ config:
+ jwt_validation_pubkeys:
+ - |
+ -----BEGIN PUBLIC KEY-----
+ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu1SU1LfVLPHCozMxH2Mo
+ 4lgOEePzNm0tRgeLezV6ffAt0gunVTLw7onLRnrq0/IzW7yWR7QkrmBL7jTKEn5u
+ +qKhbwKfBstIs+bMY2Zkp18gnTxKLxoS2tFczGkPLPgizskuemMghRniWaoLcyeh
+ kd3qqGElvW/VDL5AaWTg0nLVkjRo9z+40RQzuVaE8AkAFmxZzow3x+VJYKdjykkJ
+ 0iT9wCS0DRTXu269V264Vf/3jvredZiKRkgwlL9xNAwxXFg0x/XFw005UWVRIkdg
+ cKWTjpBP2dPwVZ4WWC+9aGVd+Gyn1o0CLelf4rEjGoXbAAEgAqeGUxrcIlbjXfbc
+ mwIDAQAB
+ -----END PUBLIC KEY-----
+ token: "{{ consul_management_token }}"
+
+- name: Delete auth method
+ community.general.consul_auth_method:
+ name: test
+ state: absent
+ token: "{{ consul_management_token }}"
+"""
+
+RETURN = """
+auth_method:
+ description: The auth method as returned by the consul HTTP API.
+ returned: always
+ type: dict
+ sample:
+ Config:
+ JWTValidationPubkeys:
+ - |-
+ -----BEGIN PUBLIC KEY-----
+ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu1SU1LfVLPHCozMxH2Mo
+ 4lgOEePzNm0tRgeLezV6ffAt0gunVTLw7onLRnrq0/IzW7yWR7QkrmBL7jTKEn5u
+ +qKhbwKfBstIs+bMY2Zkp18gnTxKLxoS2tFczGkPLPgizskuemMghRniWaoLcyeh
+ kd3qqGElvW/VDL5AaWTg0nLVkjRo9z+40RQzuVaE8AkAFmxZzow3x+VJYKdjykkJ
+ 0iT9wCS0DRTXu269V264Vf/3jvredZiKRkgwlL9xNAwxXFg0x/XFw005UWVRIkdg
+ cKWTjpBP2dPwVZ4WWC+9aGVd+Gyn1o0CLelf4rEjGoXbAAEgAqeGUxrcIlbjXfbc
+ mwIDAQAB
+ -----END PUBLIC KEY-----
+ CreateIndex: 416
+ ModifyIndex: 487
+ Name: test
+ Type: jwt
+operation:
+ description: The operation performed.
+ returned: changed
+ type: str
+ sample: update
+"""
+
+import re
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.community.general.plugins.module_utils.consul import (
+ AUTH_ARGUMENTS_SPEC,
+ _ConsulModule,
+ camel_case_key,
+)
+
+
+def normalize_ttl(ttl):
+ matches = re.findall(r"(\d+)(:h|m|s)", ttl)
+ ttl = 0
+ for value, unit in matches:
+ value = int(value)
+ if unit == "m":
+ value *= 60
+ elif unit == "h":
+ value *= 60 * 60
+ ttl += value
+
+ new_ttl = ""
+ hours, remainder = divmod(ttl, 3600)
+ if hours:
+ new_ttl += "{0}h".format(hours)
+ minutes, seconds = divmod(remainder, 60)
+ if minutes:
+ new_ttl += "{0}m".format(minutes)
+ if seconds:
+ new_ttl += "{0}s".format(seconds)
+ return new_ttl
+
+
+class ConsulAuthMethodModule(_ConsulModule):
+ api_endpoint = "acl/auth-method"
+ result_key = "auth_method"
+ unique_identifier = "name"
+
+ def map_param(self, k, v, is_update):
+ if k == "config" and v:
+ v = {camel_case_key(k2): v2 for k2, v2 in v.items()}
+ return super(ConsulAuthMethodModule, self).map_param(k, v, is_update)
+
+ def needs_update(self, api_obj, module_obj):
+ if "MaxTokenTTL" in module_obj:
+ module_obj["MaxTokenTTL"] = normalize_ttl(module_obj["MaxTokenTTL"])
+ return super(ConsulAuthMethodModule, self).needs_update(api_obj, module_obj)
+
+
+_ARGUMENT_SPEC = {
+ "name": dict(type="str", required=True),
+ "type": dict(type="str", choices=["kubernetes", "jwt", "oidc", "aws-iam"]),
+ "description": dict(type="str"),
+ "display_name": dict(type="str"),
+ "max_token_ttl": dict(type="str", no_log=False),
+ "token_locality": dict(type="str", choices=["local", "global"]),
+ "config": dict(type="dict"),
+ "state": dict(default="present", choices=["present", "absent"]),
+}
+_ARGUMENT_SPEC.update(AUTH_ARGUMENTS_SPEC)
+
+
+def main():
+ module = AnsibleModule(
+ _ARGUMENT_SPEC,
+ supports_check_mode=True,
+ )
+ consul_module = ConsulAuthMethodModule(module)
+ consul_module.execute()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/general/plugins/modules/consul_binding_rule.py b/ansible_collections/community/general/plugins/modules/consul_binding_rule.py
new file mode 100644
index 000000000..88496f867
--- /dev/null
+++ b/ansible_collections/community/general/plugins/modules/consul_binding_rule.py
@@ -0,0 +1,183 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2024, Florian Apolloner (@apollo13)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+module: consul_binding_rule
+short_description: Manipulate Consul binding rules
+version_added: 8.3.0
+description:
+ - Allows the addition, modification and deletion of binding rules in a consul
+ cluster via the agent. For more details on using and configuring binding rules,
+ see U(https://developer.hashicorp.com/consul/api-docs/acl/binding-rules).
+author:
+ - Florian Apolloner (@apollo13)
+extends_documentation_fragment:
+ - community.general.consul
+ - community.general.consul.actiongroup_consul
+ - community.general.consul.token
+ - community.general.attributes
+attributes:
+ check_mode:
+ support: full
+ diff_mode:
+ support: partial
+ details:
+ - In check mode the diff will miss operational attributes.
+options:
+ state:
+ description:
+ - Whether the binding rule should be present or absent.
+ choices: ['present', 'absent']
+ default: present
+ type: str
+ name:
+ description:
+ - Specifies a name for the binding rule.
+ - 'Note: This is used to identify the binding rule. But since the API does not support a name, it is prefixed to the description.'
+ type: str
+ required: true
+ description:
+ description:
+ - Free form human readable description of the binding rule.
+ type: str
+ auth_method:
+ description:
+ - The name of the auth method that this rule applies to.
+ type: str
+ required: true
+ selector:
+ description:
+ - Specifies the expression used to match this rule against valid identities returned from an auth method validation.
+ - If empty this binding rule matches all valid identities returned from the auth method.
+ type: str
+ bind_type:
+ description:
+ - Specifies the way the binding rule affects a token created at login.
+ type: str
+ choices: [service, node, role, templated-policy]
+ bind_name:
+ description:
+ - The name to bind to a token at login-time.
+ - What it binds to can be adjusted with different values of the O(bind_type) parameter.
+ type: str
+ bind_vars:
+ description:
+ - Specifies the templated policy variables when O(bind_type) is set to V(templated-policy).
+ type: dict
+"""
+
+EXAMPLES = """
+- name: Create a binding rule
+ community.general.consul_binding_rule:
+ name: my_name
+ description: example rule
+ auth_method: minikube
+ bind_type: service
+ bind_name: "{{ serviceaccount.name }}"
+ token: "{{ consul_management_token }}"
+
+- name: Remove a binding rule
+ community.general.consul_binding_rule:
+ name: my_name
+ auth_method: minikube
+ state: absent
+"""
+
+RETURN = """
+binding_rule:
+ description: The binding rule as returned by the consul HTTP API.
+ returned: always
+ type: dict
+ sample:
+ Description: "my_name: example rule"
+ AuthMethod: minikube
+ Selector: serviceaccount.namespace==default
+ BindType: service
+ BindName: "{{ serviceaccount.name }}"
+ CreateIndex: 30
+ ID: 59c8a237-e481-4239-9202-45f117950c5f
+ ModifyIndex: 33
+operation:
+ description: The operation performed.
+ returned: changed
+ type: str
+ sample: update
+"""
+
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.community.general.plugins.module_utils.consul import (
+ AUTH_ARGUMENTS_SPEC,
+ RequestError,
+ _ConsulModule,
+)
+
+
+class ConsulBindingRuleModule(_ConsulModule):
+ api_endpoint = "acl/binding-rule"
+ result_key = "binding_rule"
+ unique_identifier = "id"
+
+ def read_object(self):
+ url = "acl/binding-rules?authmethod={0}".format(self.params["auth_method"])
+ try:
+ results = self.get(url)
+ for result in results:
+ if result.get("Description").startswith(
+ "{0}: ".format(self.params["name"])
+ ):
+ return result
+ except RequestError as e:
+ if e.status == 404:
+ return
+ elif e.status == 403 and b"ACL not found" in e.response_data:
+ return
+ raise
+
+ def module_to_obj(self, is_update):
+ obj = super(ConsulBindingRuleModule, self).module_to_obj(is_update)
+ del obj["Name"]
+ return obj
+
+ def prepare_object(self, existing, obj):
+ final = super(ConsulBindingRuleModule, self).prepare_object(existing, obj)
+ name = self.params["name"]
+ description = final.pop("Description", "").split(": ", 1)[-1]
+ final["Description"] = "{0}: {1}".format(name, description)
+ return final
+
+
+_ARGUMENT_SPEC = {
+ "name": dict(type="str", required=True),
+ "description": dict(type="str"),
+ "auth_method": dict(type="str", required=True),
+ "selector": dict(type="str"),
+ "bind_type": dict(
+ type="str", choices=["service", "node", "role", "templated-policy"]
+ ),
+ "bind_name": dict(type="str"),
+ "bind_vars": dict(type="dict"),
+ "state": dict(default="present", choices=["present", "absent"]),
+}
+_ARGUMENT_SPEC.update(AUTH_ARGUMENTS_SPEC)
+
+
+def main():
+ module = AnsibleModule(
+ _ARGUMENT_SPEC,
+ supports_check_mode=True,
+ )
+ consul_module = ConsulBindingRuleModule(module)
+ consul_module.execute()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/general/plugins/modules/consul_kv.py b/ansible_collections/community/general/plugins/modules/consul_kv.py
index a4457f244..84169fc6b 100644
--- a/ansible_collections/community/general/plugins/modules/consul_kv.py
+++ b/ansible_collections/community/general/plugins/modules/consul_kv.py
@@ -17,7 +17,7 @@ description:
- Allows the retrieval, addition, modification and deletion of key/value entries in a
consul cluster via the agent. The entire contents of the record, including
the indices, flags and session are returned as C(value).
- - If the C(key) represents a prefix then note that when a value is removed, the existing
+ - If the O(key) represents a prefix then note that when a value is removed, the existing
value if any is returned as part of the results.
- See http://www.consul.io/docs/agent/http.html#kv for more details.
requirements:
@@ -36,14 +36,14 @@ attributes:
options:
state:
description:
- - The action to take with the supplied key and value. If the state is C(present) and I(value) is set, the key
- contents will be set to the value supplied and C(changed) will be set to C(true) only if the value was
- different to the current contents. If the state is C(present) and I(value) is not set, the existing value
- associated to the key will be returned. The state C(absent) will remove the key/value pair,
- again C(changed) will be set to true only if the key actually existed
+ - The action to take with the supplied key and value. If the state is V(present) and O(value) is set, the key
+ contents will be set to the value supplied and C(changed) will be set to V(true) only if the value was
+ different to the current contents. If the state is V(present) and O(value) is not set, the existing value
+ associated to the key will be returned. The state V(absent) will remove the key/value pair,
+ again C(changed) will be set to V(true) only if the key actually existed
prior to the removal. An attempt can be made to obtain or free the
- lock associated with a key/value pair with the states C(acquire) or
- C(release) respectively. a valid session must be supplied to make the
+ lock associated with a key/value pair with the states V(acquire) or
+ V(release) respectively. a valid session must be supplied to make the
attempt changed will be true if the attempt is successful, false
otherwise.
type: str
@@ -56,17 +56,17 @@ options:
required: true
value:
description:
- - The value should be associated with the given key, required if C(state)
- is C(present).
+ - The value should be associated with the given key, required if O(state)
+ is V(present).
type: str
recurse:
description:
- If the key represents a prefix, each entry with the prefix can be
- retrieved by setting this to C(true).
+ retrieved by setting this to V(true).
type: bool
retrieve:
description:
- - If the I(state) is C(present) and I(value) is set, perform a
+ - If the O(state) is V(present) and O(value) is set, perform a
read after setting the value and return this value.
default: true
type: bool
@@ -82,9 +82,9 @@ options:
type: str
cas:
description:
- - Used when acquiring a lock with a session. If the C(cas) is C(0), then
+ - Used when acquiring a lock with a session. If the O(cas) is V(0), then
Consul will only put the key if it does not already exist. If the
- C(cas) value is non-zero, then the key is only set if the index matches
+ O(cas) value is non-zero, then the key is only set if the index matches
the ModifyIndex of that key.
type: str
flags:
diff --git a/ansible_collections/community/general/plugins/modules/consul_policy.py b/ansible_collections/community/general/plugins/modules/consul_policy.py
new file mode 100644
index 000000000..f020622a0
--- /dev/null
+++ b/ansible_collections/community/general/plugins/modules/consul_policy.py
@@ -0,0 +1,164 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2022, Håkon Lerring
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+module: consul_policy
+short_description: Manipulate Consul policies
+version_added: 7.2.0
+description:
+ - Allows the addition, modification and deletion of policies in a consul
+ cluster via the agent. For more details on using and configuring ACLs,
+ see U(https://www.consul.io/docs/guides/acl.html).
+author:
+ - Håkon Lerring (@Hakon)
+extends_documentation_fragment:
+ - community.general.consul
+ - community.general.consul.actiongroup_consul
+ - community.general.consul.token
+ - community.general.attributes
+attributes:
+ check_mode:
+ support: full
+ version_added: 8.3.0
+ diff_mode:
+ support: partial
+ version_added: 8.3.0
+ details:
+ - In check mode the diff will miss operational attributes.
+options:
+ state:
+ description:
+ - Whether the policy should be present or absent.
+ choices: ['present', 'absent']
+ default: present
+ type: str
+ valid_datacenters:
+ description:
+ - Valid datacenters for the policy. All if list is empty.
+ type: list
+ elements: str
+ name:
+ description:
+ - The name that should be associated with the policy, this is opaque
+ to Consul.
+ required: true
+ type: str
+ description:
+ description:
+ - Description of the policy.
+ type: str
+ rules:
+ type: str
+ description:
+ - Rule document that should be associated with the current policy.
+"""
+
+EXAMPLES = """
+- name: Create a policy with rules
+ community.general.consul_policy:
+ host: consul1.example.com
+ token: some_management_acl
+ name: foo-access
+ rules: |
+ key "foo" {
+ policy = "read"
+ }
+ key "private/foo" {
+ policy = "deny"
+ }
+
+- name: Update the rules associated to a policy
+ community.general.consul_policy:
+ host: consul1.example.com
+ token: some_management_acl
+ name: foo-access
+ rules: |
+ key "foo" {
+ policy = "read"
+ }
+ key "private/foo" {
+ policy = "deny"
+ }
+ event "bbq" {
+ policy = "write"
+ }
+
+- name: Remove a policy
+ community.general.consul_policy:
+ host: consul1.example.com
+ token: some_management_acl
+ name: foo-access
+ state: absent
+"""
+
+RETURN = """
+policy:
+ description: The policy as returned by the consul HTTP API.
+ returned: always
+ type: dict
+ sample:
+ CreateIndex: 632
+ Description: Testing
+ Hash: rj5PeDHddHslkpW7Ij4OD6N4bbSXiecXFmiw2SYXg2A=
+ Name: foo-access
+ Rules: |-
+ key "foo" {
+ policy = "read"
+ }
+ key "private/foo" {
+ policy = "deny"
+ }
+operation:
+ description: The operation performed.
+ returned: changed
+ type: str
+ sample: update
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.community.general.plugins.module_utils.consul import (
+ AUTH_ARGUMENTS_SPEC,
+ OPERATION_READ,
+ _ConsulModule,
+)
+
+_ARGUMENT_SPEC = {
+ "name": dict(required=True),
+ "description": dict(required=False, type="str"),
+ "rules": dict(type="str"),
+ "valid_datacenters": dict(type="list", elements="str"),
+ "state": dict(default="present", choices=["present", "absent"]),
+}
+_ARGUMENT_SPEC.update(AUTH_ARGUMENTS_SPEC)
+
+
+class ConsulPolicyModule(_ConsulModule):
+ api_endpoint = "acl/policy"
+ result_key = "policy"
+ unique_identifier = "id"
+
+ def endpoint_url(self, operation, identifier=None):
+ if operation == OPERATION_READ:
+ return [self.api_endpoint, "name", self.params["name"]]
+ return super(ConsulPolicyModule, self).endpoint_url(operation, identifier)
+
+
+def main():
+ module = AnsibleModule(
+ _ARGUMENT_SPEC,
+ supports_check_mode=True,
+ )
+ consul_module = ConsulPolicyModule(module)
+ consul_module.execute()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/general/plugins/modules/consul_role.py b/ansible_collections/community/general/plugins/modules/consul_role.py
new file mode 100644
index 000000000..0da71507a
--- /dev/null
+++ b/ansible_collections/community/general/plugins/modules/consul_role.py
@@ -0,0 +1,281 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2022, Håkon Lerring
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+module: consul_role
+short_description: Manipulate Consul roles
+version_added: 7.5.0
+description:
+ - Allows the addition, modification and deletion of roles in a consul
+ cluster via the agent. For more details on using and configuring ACLs,
+ see U(https://www.consul.io/docs/guides/acl.html).
+author:
+ - Håkon Lerring (@Hakon)
+extends_documentation_fragment:
+ - community.general.consul
+ - community.general.consul.token
+ - community.general.consul.actiongroup_consul
+ - community.general.attributes
+attributes:
+ check_mode:
+ support: full
+ diff_mode:
+ support: partial
+ details:
+ - In check mode the diff will miss operational attributes.
+ version_added: 8.3.0
+options:
+ name:
+ description:
+ - A name used to identify the role.
+ required: true
+ type: str
+ state:
+ description:
+ - whether the role should be present or absent.
+ choices: ['present', 'absent']
+ default: present
+ type: str
+ description:
+ description:
+ - Description of the role.
+ - If not specified, the assigned description will not be changed.
+ type: str
+ policies:
+ type: list
+ elements: dict
+ description:
+ - List of policies to attach to the role. Each policy is a dict.
+ - If the parameter is left blank, any policies currently assigned will not be changed.
+ - Any empty array (V([])) will clear any policies previously set.
+ suboptions:
+ name:
+ description:
+ - The name of the policy to attach to this role; see M(community.general.consul_policy) for more info.
+ - Either this or O(policies[].id) must be specified.
+ type: str
+ id:
+ description:
+ - The ID of the policy to attach to this role; see M(community.general.consul_policy) for more info.
+ - Either this or O(policies[].name) must be specified.
+ type: str
+ templated_policies:
+ description:
+ - The list of templated policies that should be applied to the role.
+ type: list
+ elements: dict
+ version_added: 8.3.0
+ suboptions:
+ template_name:
+ description:
+ - The templated policy name.
+ type: str
+ required: true
+ template_variables:
+ description:
+ - The templated policy variables.
+ - Not all templated policies require variables.
+ type: dict
+ service_identities:
+ type: list
+ elements: dict
+ description:
+ - List of service identities to attach to the role.
+ - If not specified, any service identities currently assigned will not be changed.
+ - If the parameter is an empty array (V([])), any node identities assigned will be unassigned.
+ suboptions:
+ service_name:
+ description:
+ - The name of the node.
+ - Must not be longer than 256 characters, must start and end with a lowercase alphanumeric character.
+ - May only contain lowercase alphanumeric characters as well as - and _.
+ - This suboption has been renamed from O(service_identities[].name) to O(service_identities[].service_name)
+ in community.general 8.3.0. The old name can still be used.
+ type: str
+ required: true
+ aliases:
+ - name
+ datacenters:
+ description:
+ - The datacenters the policies will be effective.
+ - This will result in effective policy only being valid in this datacenter.
+ - If an empty array (V([])) is specified, the policies will valid in all datacenters.
+ - including those which do not yet exist but may in the future.
+ type: list
+ elements: str
+ node_identities:
+ type: list
+ elements: dict
+ description:
+ - List of node identities to attach to the role.
+ - If not specified, any node identities currently assigned will not be changed.
+ - If the parameter is an empty array (V([])), any node identities assigned will be unassigned.
+ suboptions:
+ node_name:
+ description:
+ - The name of the node.
+ - Must not be longer than 256 characters, must start and end with a lowercase alphanumeric character.
+ - May only contain lowercase alphanumeric characters as well as - and _.
+ - This suboption has been renamed from O(node_identities[].name) to O(node_identities[].node_name)
+ in community.general 8.3.0. The old name can still be used.
+ type: str
+ required: true
+ aliases:
+ - name
+ datacenter:
+ description:
+ - The nodes datacenter.
+ - This will result in effective policy only being valid in this datacenter.
+ type: str
+ required: true
+"""
+
+EXAMPLES = """
+- name: Create a role with 2 policies
+ community.general.consul_role:
+ host: consul1.example.com
+ token: some_management_acl
+ name: foo-role
+ policies:
+ - id: 783beef3-783f-f41f-7422-7087dc272765
+ - name: "policy-1"
+
+- name: Create a role with service identity
+ community.general.consul_role:
+ host: consul1.example.com
+ token: some_management_acl
+ name: foo-role-2
+ service_identities:
+ - name: web
+ datacenters:
+ - dc1
+
+- name: Create a role with node identity
+ community.general.consul_role:
+ host: consul1.example.com
+ token: some_management_acl
+ name: foo-role-3
+ node_identities:
+ - name: node-1
+ datacenter: dc2
+
+- name: Remove a role
+ community.general.consul_role:
+ host: consul1.example.com
+ token: some_management_acl
+ name: foo-role-3
+ state: absent
+"""
+
+RETURN = """
+role:
+ description: The role object.
+ returned: success
+ type: dict
+ sample:
+ {
+ "CreateIndex": 39,
+ "Description": "",
+ "Hash": "Trt0QJtxVEfvTTIcdTUbIJRr6Dsi6E4EcwSFxx9tCYM=",
+ "ID": "9a300b8d-48db-b720-8544-a37c0f5dafb5",
+ "ModifyIndex": 39,
+ "Name": "foo-role",
+ "Policies": [
+ {"ID": "b1a00172-d7a1-0e66-a12e-7a4045c4b774", "Name": "foo-access"}
+ ]
+ }
+operation:
+ description: The operation performed on the role.
+ returned: changed
+ type: str
+ sample: update
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.community.general.plugins.module_utils.consul import (
+ AUTH_ARGUMENTS_SPEC,
+ OPERATION_READ,
+ _ConsulModule,
+)
+
+
+class ConsulRoleModule(_ConsulModule):
+ api_endpoint = "acl/role"
+ result_key = "role"
+ unique_identifier = "id"
+
+ def endpoint_url(self, operation, identifier=None):
+ if operation == OPERATION_READ:
+ return [self.api_endpoint, "name", self.params["name"]]
+ return super(ConsulRoleModule, self).endpoint_url(operation, identifier)
+
+
+NAME_ID_SPEC = dict(
+ name=dict(type="str"),
+ id=dict(type="str"),
+)
+
+NODE_ID_SPEC = dict(
+ node_name=dict(type="str", required=True, aliases=["name"]),
+ datacenter=dict(type="str", required=True),
+)
+
+SERVICE_ID_SPEC = dict(
+ service_name=dict(type="str", required=True, aliases=["name"]),
+ datacenters=dict(type="list", elements="str"),
+)
+
+TEMPLATE_POLICY_SPEC = dict(
+ template_name=dict(type="str", required=True),
+ template_variables=dict(type="dict"),
+)
+
+_ARGUMENT_SPEC = {
+ "name": dict(type="str", required=True),
+ "description": dict(type="str"),
+ "policies": dict(
+ type="list",
+ elements="dict",
+ options=NAME_ID_SPEC,
+ mutually_exclusive=[("name", "id")],
+ required_one_of=[("name", "id")],
+ ),
+ "templated_policies": dict(
+ type="list",
+ elements="dict",
+ options=TEMPLATE_POLICY_SPEC,
+ ),
+ "node_identities": dict(
+ type="list",
+ elements="dict",
+ options=NODE_ID_SPEC,
+ ),
+ "service_identities": dict(
+ type="list",
+ elements="dict",
+ options=SERVICE_ID_SPEC,
+ ),
+ "state": dict(default="present", choices=["present", "absent"]),
+}
+_ARGUMENT_SPEC.update(AUTH_ARGUMENTS_SPEC)
+
+
+def main():
+ module = AnsibleModule(
+ _ARGUMENT_SPEC,
+ supports_check_mode=True,
+ )
+ consul_module = ConsulRoleModule(module)
+ consul_module.execute()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/general/plugins/modules/consul_session.py b/ansible_collections/community/general/plugins/modules/consul_session.py
index 246d13846..bd03b561a 100644
--- a/ansible_collections/community/general/plugins/modules/consul_session.py
+++ b/ansible_collections/community/general/plugins/modules/consul_session.py
@@ -16,12 +16,13 @@ description:
cluster. These sessions can then be used in conjunction with key value pairs
to implement distributed locks. In depth documentation for working with
sessions can be found at http://www.consul.io/docs/internals/sessions.html
-requirements:
- - python-consul
- - requests
author:
- Steve Gargan (@sgargan)
+ - Håkon Lerring (@Hakon)
extends_documentation_fragment:
+ - community.general.consul
+ - community.general.consul.actiongroup_consul
+ - community.general.consul.token
- community.general.attributes
attributes:
check_mode:
@@ -31,25 +32,25 @@ attributes:
options:
id:
description:
- - ID of the session, required when I(state) is either C(info) or
- C(remove).
+ - ID of the session, required when O(state) is either V(info) or
+ V(remove).
type: str
state:
description:
- Whether the session should be present i.e. created if it doesn't
- exist, or absent, removed if present. If created, the I(id) for the
- session is returned in the output. If C(absent), I(id) is
+ exist, or absent, removed if present. If created, the O(id) for the
+ session is returned in the output. If V(absent), O(id) is
required to remove the session. Info for a single session, all the
sessions for a node or all available sessions can be retrieved by
- specifying C(info), C(node) or C(list) for the I(state); for C(node)
- or C(info), the node I(name) or session I(id) is required as parameter.
+ specifying V(info), V(node) or V(list) for the O(state); for V(node)
+ or V(info), the node O(name) or session O(id) is required as parameter.
choices: [ absent, info, list, node, present ]
type: str
default: present
name:
description:
- The name that should be associated with the session. Required when
- I(state=node) is used.
+ O(state=node) is used.
type: str
delay:
description:
@@ -76,26 +77,6 @@ options:
the associated lock delay has expired.
type: list
elements: str
- host:
- description:
- - The host of the consul agent defaults to localhost.
- type: str
- default: localhost
- port:
- description:
- - The port on which the consul agent is running.
- type: int
- default: 8500
- scheme:
- description:
- - The protocol scheme on which the consul agent is running.
- type: str
- default: http
- validate_certs:
- description:
- - Whether to verify the TLS certificate of the consul agent.
- type: bool
- default: true
behavior:
description:
- The optional behavior that can be attached to the session when it
@@ -109,10 +90,6 @@ options:
type: int
version_added: 5.4.0
token:
- description:
- - The token key identifying an ACL rule set that controls access to
- the key value pair.
- type: str
version_added: 5.6.0
'''
@@ -147,37 +124,50 @@ EXAMPLES = '''
ttl: 600 # sec
'''
-try:
- import consul
- from requests.exceptions import ConnectionError
- python_consul_installed = True
-except ImportError:
- python_consul_installed = False
-
from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.community.general.plugins.module_utils.consul import (
+ AUTH_ARGUMENTS_SPEC, _ConsulModule
+)
-def execute(module):
+def execute(module, consul_module):
state = module.params.get('state')
if state in ['info', 'list', 'node']:
- lookup_sessions(module)
+ lookup_sessions(module, consul_module)
elif state == 'present':
- update_session(module)
+ update_session(module, consul_module)
else:
- remove_session(module)
+ remove_session(module, consul_module)
+
+
+def list_sessions(consul_module, datacenter):
+ return consul_module.get(
+ 'session/list',
+ params={'dc': datacenter})
+
+
+def list_sessions_for_node(consul_module, node, datacenter):
+ return consul_module.get(
+ ('session', 'node', node),
+ params={'dc': datacenter})
-def lookup_sessions(module):
+def get_session_info(consul_module, session_id, datacenter):
+ return consul_module.get(
+ ('session', 'info', session_id),
+ params={'dc': datacenter})
+
+
+def lookup_sessions(module, consul_module):
datacenter = module.params.get('datacenter')
state = module.params.get('state')
- consul_client = get_consul_api(module)
try:
if state == 'list':
- sessions_list = consul_client.session.list(dc=datacenter)
+ sessions_list = list_sessions(consul_module, datacenter)
# Ditch the index, this can be grabbed from the results
if sessions_list and len(sessions_list) >= 2:
sessions_list = sessions_list[1]
@@ -185,14 +175,14 @@ def lookup_sessions(module):
sessions=sessions_list)
elif state == 'node':
node = module.params.get('node')
- sessions = consul_client.session.node(node, dc=datacenter)
+ sessions = list_sessions_for_node(consul_module, node, datacenter)
module.exit_json(changed=True,
node=node,
sessions=sessions)
elif state == 'info':
session_id = module.params.get('id')
- session_by_id = consul_client.session.info(session_id, dc=datacenter)
+ session_by_id = get_session_info(consul_module, session_id, datacenter)
module.exit_json(changed=True,
session_id=session_id,
sessions=session_by_id)
@@ -201,7 +191,26 @@ def lookup_sessions(module):
module.fail_json(msg="Could not retrieve session info %s" % e)
-def update_session(module):
+def create_session(consul_module, name, behavior, ttl, node,
+ lock_delay, datacenter, checks):
+ create_data = {
+ "LockDelay": lock_delay,
+ "Node": node,
+ "Name": name,
+ "Checks": checks,
+ "Behavior": behavior,
+ }
+ if ttl is not None:
+ create_data["TTL"] = "%ss" % str(ttl) # TTL is in seconds
+ create_session_response_dict = consul_module.put(
+ 'session/create',
+ params={
+ 'dc': datacenter},
+ data=create_data)
+ return create_session_response_dict["ID"]
+
+
+def update_session(module, consul_module):
name = module.params.get('name')
delay = module.params.get('delay')
@@ -211,18 +220,16 @@ def update_session(module):
behavior = module.params.get('behavior')
ttl = module.params.get('ttl')
- consul_client = get_consul_api(module)
-
try:
- session = consul_client.session.create(
- name=name,
- behavior=behavior,
- ttl=ttl,
- node=node,
- lock_delay=delay,
- dc=datacenter,
- checks=checks
- )
+ session = create_session(consul_module,
+ name=name,
+ behavior=behavior,
+ ttl=ttl,
+ node=node,
+ lock_delay=delay,
+ datacenter=datacenter,
+ checks=checks
+ )
module.exit_json(changed=True,
session_id=session,
name=name,
@@ -235,13 +242,15 @@ def update_session(module):
module.fail_json(msg="Could not create/update session %s" % e)
-def remove_session(module):
- session_id = module.params.get('id')
+def destroy_session(consul_module, session_id):
+ return consul_module.put(('session', 'destroy', session_id))
- consul_client = get_consul_api(module)
+
+def remove_session(module, consul_module):
+ session_id = module.params.get('id')
try:
- consul_client.session.destroy(session_id)
+ destroy_session(consul_module, session_id)
module.exit_json(changed=True,
session_id=session_id)
@@ -250,36 +259,31 @@ def remove_session(module):
session_id, e))
-def get_consul_api(module):
- return consul.Consul(host=module.params.get('host'),
- port=module.params.get('port'),
- scheme=module.params.get('scheme'),
- verify=module.params.get('validate_certs'),
- token=module.params.get('token'))
-
-
-def test_dependencies(module):
- if not python_consul_installed:
- module.fail_json(msg="python-consul required for this module. "
- "see https://python-consul.readthedocs.io/en/latest/#installation")
-
-
def main():
argument_spec = dict(
checks=dict(type='list', elements='str'),
delay=dict(type='int', default='15'),
- behavior=dict(type='str', default='release', choices=['release', 'delete']),
+ behavior=dict(
+ type='str',
+ default='release',
+ choices=[
+ 'release',
+ 'delete']),
ttl=dict(type='int'),
- host=dict(type='str', default='localhost'),
- port=dict(type='int', default=8500),
- scheme=dict(type='str', default='http'),
- validate_certs=dict(type='bool', default=True),
id=dict(type='str'),
name=dict(type='str'),
node=dict(type='str'),
- state=dict(type='str', default='present', choices=['absent', 'info', 'list', 'node', 'present']),
+ state=dict(
+ type='str',
+ default='present',
+ choices=[
+ 'absent',
+ 'info',
+ 'list',
+ 'node',
+ 'present']),
datacenter=dict(type='str'),
- token=dict(type='str', no_log=True),
+ **AUTH_ARGUMENTS_SPEC
)
module = AnsibleModule(
@@ -291,14 +295,10 @@ def main():
],
supports_check_mode=False
)
-
- test_dependencies(module)
+ consul_module = _ConsulModule(module)
try:
- execute(module)
- except ConnectionError as e:
- module.fail_json(msg='Could not connect to consul agent at %s:%s, error was %s' % (
- module.params.get('host'), module.params.get('port'), e))
+ execute(module, consul_module)
except Exception as e:
module.fail_json(msg=str(e))
diff --git a/ansible_collections/community/general/plugins/modules/consul_token.py b/ansible_collections/community/general/plugins/modules/consul_token.py
new file mode 100644
index 000000000..eee419863
--- /dev/null
+++ b/ansible_collections/community/general/plugins/modules/consul_token.py
@@ -0,0 +1,331 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2024, Florian Apolloner (@apollo13)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+module: consul_token
+short_description: Manipulate Consul tokens
+version_added: 8.3.0
+description:
+ - Allows the addition, modification and deletion of tokens in a consul
+ cluster via the agent. For more details on using and configuring ACLs,
+ see U(https://www.consul.io/docs/guides/acl.html).
+author:
+ - Florian Apolloner (@apollo13)
+extends_documentation_fragment:
+ - community.general.consul
+ - community.general.consul.token
+ - community.general.consul.actiongroup_consul
+ - community.general.attributes
+attributes:
+ check_mode:
+ support: full
+ diff_mode:
+ support: partial
+ details:
+ - In check mode the diff will miss operational attributes.
+options:
+ state:
+ description:
+ - Whether the token should be present or absent.
+ choices: ['present', 'absent']
+ default: present
+ type: str
+ accessor_id:
+ description:
+ - Specifies a UUID to use as the token's Accessor ID.
+ If not specified a UUID will be generated for this field.
+ type: str
+ secret_id:
+ description:
+ - Specifies a UUID to use as the token's Secret ID.
+ If not specified a UUID will be generated for this field.
+ type: str
+ description:
+ description:
+ - Free form human readable description of the token.
+ type: str
+ policies:
+ type: list
+ elements: dict
+ description:
+ - List of policies to attach to the token. Each policy is a dict.
+ - If the parameter is left blank, any policies currently assigned will not be changed.
+ - Any empty array (V([])) will clear any policies previously set.
+ suboptions:
+ name:
+ description:
+ - The name of the policy to attach to this token; see M(community.general.consul_policy) for more info.
+ - Either this or O(policies[].id) must be specified.
+ type: str
+ id:
+ description:
+ - The ID of the policy to attach to this token; see M(community.general.consul_policy) for more info.
+ - Either this or O(policies[].name) must be specified.
+ type: str
+ roles:
+ type: list
+ elements: dict
+ description:
+ - List of roles to attach to the token. Each role is a dict.
+ - If the parameter is left blank, any roles currently assigned will not be changed.
+ - Any empty array (V([])) will clear any roles previously set.
+ suboptions:
+ name:
+ description:
+ - The name of the role to attach to this token; see M(community.general.consul_role) for more info.
+ - Either this or O(roles[].id) must be specified.
+ type: str
+ id:
+ description:
+ - The ID of the role to attach to this token; see M(community.general.consul_role) for more info.
+ - Either this or O(roles[].name) must be specified.
+ type: str
+ templated_policies:
+ description:
+ - The list of templated policies that should be applied to the role.
+ type: list
+ elements: dict
+ suboptions:
+ template_name:
+ description:
+ - The templated policy name.
+ type: str
+ required: true
+ template_variables:
+ description:
+ - The templated policy variables.
+ - Not all templated policies require variables.
+ type: dict
+ service_identities:
+ type: list
+ elements: dict
+ description:
+ - List of service identities to attach to the token.
+ - If not specified, any service identities currently assigned will not be changed.
+ - If the parameter is an empty array (V([])), any node identities assigned will be unassigned.
+ suboptions:
+ service_name:
+ description:
+ - The name of the service.
+ - Must not be longer than 256 characters, must start and end with a lowercase alphanumeric character.
+ - May only contain lowercase alphanumeric characters as well as V(-) and V(_).
+ type: str
+ required: true
+ datacenters:
+ description:
+ - The datacenters the token will be effective.
+ - If an empty array (V([])) is specified, the token will valid in all datacenters.
+ - including those which do not yet exist but may in the future.
+ type: list
+ elements: str
+ node_identities:
+ type: list
+ elements: dict
+ description:
+ - List of node identities to attach to the token.
+ - If not specified, any node identities currently assigned will not be changed.
+ - If the parameter is an empty array (V([])), any node identities assigned will be unassigned.
+ suboptions:
+ node_name:
+ description:
+ - The name of the node.
+ - Must not be longer than 256 characters, must start and end with a lowercase alphanumeric character.
+ - May only contain lowercase alphanumeric characters as well as V(-) and V(_).
+ type: str
+ required: true
+ datacenter:
+ description:
+ - The nodes datacenter.
+ - This will result in effective token only being valid in this datacenter.
+ type: str
+ required: true
+ local:
+ description:
+ - If true, indicates that the token should not be replicated globally
+ and instead be local to the current datacenter.
+ type: bool
+ expiration_ttl:
+ description:
+ - This is a convenience field and if set will initialize the C(expiration_time).
+ Can be specified in the form of V(60s) or V(5m) (that is, 60 seconds or 5 minutes,
+ respectively). Ingored when the token is updated!
+ type: str
+"""
+
+EXAMPLES = """
+- name: Create / Update a token by accessor_id
+ community.general.consul_token:
+ state: present
+ accessor_id: 07a7de84-c9c7-448a-99cc-beaf682efd21
+ token: 8adddd91-0bd6-d41d-ae1a-3b49cfa9a0e8
+ roles:
+ - name: role1
+ - name: role2
+ service_identities:
+ - service_name: service1
+ datacenters: [dc1, dc2]
+ node_identities:
+ - node_name: node1
+ datacenter: dc1
+ expiration_ttl: 50m
+
+- name: Delete a token
+ community.general.consul_token:
+ state: absent
+ accessor_id: 07a7de84-c9c7-448a-99cc-beaf682efd21
+ token: 8adddd91-0bd6-d41d-ae1a-3b49cfa9a0e8
+"""
+
+RETURN = """
+token:
+ description: The token as returned by the consul HTTP API.
+ returned: always
+ type: dict
+ sample:
+ AccessorID: 07a7de84-c9c7-448a-99cc-beaf682efd21
+ CreateIndex: 632
+ CreateTime: "2024-01-14T21:53:01.402749174+01:00"
+ Description: Testing
+ Hash: rj5PeDHddHslkpW7Ij4OD6N4bbSXiecXFmiw2SYXg2A=
+ Local: false
+ ModifyIndex: 633
+ SecretID: bd380fba-da17-7cee-8576-8d6427c6c930
+ ServiceIdentities: [{"ServiceName": "test"}]
+operation:
+ description: The operation performed.
+ returned: changed
+ type: str
+ sample: update
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.community.general.plugins.module_utils.consul import (
+ AUTH_ARGUMENTS_SPEC,
+ _ConsulModule,
+)
+
+
+def normalize_link_obj(api_obj, module_obj, key):
+ api_objs = api_obj.get(key)
+ module_objs = module_obj.get(key)
+ if api_objs is None or module_objs is None:
+ return
+ name_to_id = {i["Name"]: i["ID"] for i in api_objs}
+ id_to_name = {i["ID"]: i["Name"] for i in api_objs}
+
+ for obj in module_objs:
+ identifier = obj.get("ID")
+ name = obj.get("Name)")
+ if identifier and not name and identifier in id_to_name:
+ obj["Name"] = id_to_name[identifier]
+ if not identifier and name and name in name_to_id:
+ obj["ID"] = name_to_id[name]
+
+
+class ConsulTokenModule(_ConsulModule):
+ api_endpoint = "acl/token"
+ result_key = "token"
+ unique_identifier = "accessor_id"
+
+ create_only_fields = {"expiration_ttl"}
+
+ def read_object(self):
+ # if `accessor_id` is not supplied we can only create objects and are not idempotent
+ if not self.params.get(self.unique_identifier):
+ return None
+ return super(ConsulTokenModule, self).read_object()
+
+ def needs_update(self, api_obj, module_obj):
+ # SecretID is usually not supplied
+ if "SecretID" not in module_obj and "SecretID" in api_obj:
+ del api_obj["SecretID"]
+ normalize_link_obj(api_obj, module_obj, "Roles")
+ normalize_link_obj(api_obj, module_obj, "Policies")
+ # ExpirationTTL is only supported on create, not for update
+ # it writes to ExpirationTime, so we need to remove that as well
+ if "ExpirationTTL" in module_obj:
+ del module_obj["ExpirationTTL"]
+ return super(ConsulTokenModule, self).needs_update(api_obj, module_obj)
+
+
+NAME_ID_SPEC = dict(
+ name=dict(type="str"),
+ id=dict(type="str"),
+)
+
+NODE_ID_SPEC = dict(
+ node_name=dict(type="str", required=True),
+ datacenter=dict(type="str", required=True),
+)
+
+SERVICE_ID_SPEC = dict(
+ service_name=dict(type="str", required=True),
+ datacenters=dict(type="list", elements="str"),
+)
+
+TEMPLATE_POLICY_SPEC = dict(
+ template_name=dict(type="str", required=True),
+ template_variables=dict(type="dict"),
+)
+
+
+_ARGUMENT_SPEC = {
+ "description": dict(),
+ "accessor_id": dict(),
+ "secret_id": dict(no_log=True),
+ "roles": dict(
+ type="list",
+ elements="dict",
+ options=NAME_ID_SPEC,
+ mutually_exclusive=[("name", "id")],
+ required_one_of=[("name", "id")],
+ ),
+ "policies": dict(
+ type="list",
+ elements="dict",
+ options=NAME_ID_SPEC,
+ mutually_exclusive=[("name", "id")],
+ required_one_of=[("name", "id")],
+ ),
+ "templated_policies": dict(
+ type="list",
+ elements="dict",
+ options=TEMPLATE_POLICY_SPEC,
+ ),
+ "node_identities": dict(
+ type="list",
+ elements="dict",
+ options=NODE_ID_SPEC,
+ ),
+ "service_identities": dict(
+ type="list",
+ elements="dict",
+ options=SERVICE_ID_SPEC,
+ ),
+ "local": dict(type="bool"),
+ "expiration_ttl": dict(type="str"),
+ "state": dict(default="present", choices=["present", "absent"]),
+}
+_ARGUMENT_SPEC.update(AUTH_ARGUMENTS_SPEC)
+
+
+def main():
+ module = AnsibleModule(
+ _ARGUMENT_SPEC,
+ required_if=[("state", "absent", ["accessor_id"])],
+ supports_check_mode=True,
+ )
+ consul_module = ConsulTokenModule(module)
+ consul_module.execute()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/general/plugins/modules/copr.py b/ansible_collections/community/general/plugins/modules/copr.py
index 965c2a935..157a6c160 100644
--- a/ansible_collections/community/general/plugins/modules/copr.py
+++ b/ansible_collections/community/general/plugins/modules/copr.py
@@ -42,14 +42,14 @@ options:
type: str
state:
description:
- - Whether to set this project as C(enabled), C(disabled) or C(absent).
+ - Whether to set this project as V(enabled), V(disabled), or V(absent).
default: enabled
type: str
choices: [absent, enabled, disabled]
chroot:
description:
- The name of the chroot that you want to enable/disable/remove in the project,
- for example C(epel-7-x86_64). Default chroot is determined by the operating system,
+ for example V(epel-7-x86_64). Default chroot is determined by the operating system,
version of the operating system, and architecture on which the module is run.
type: str
"""
@@ -97,11 +97,26 @@ except ImportError:
DNF_IMP_ERR = traceback.format_exc()
HAS_DNF_PACKAGES = False
+from ansible.module_utils.common import respawn
from ansible.module_utils.six.moves.urllib.error import HTTPError
from ansible.module_utils.basic import missing_required_lib
-from ansible.module_utils import distro # pylint: disable=import-error
-from ansible.module_utils.basic import AnsibleModule # pylint: disable=import-error
-from ansible.module_utils.urls import open_url # pylint: disable=import-error
+from ansible.module_utils import distro
+from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.urls import open_url
+
+
+def _respawn_dnf():
+ if respawn.has_respawned():
+ return
+ system_interpreters = (
+ "/usr/libexec/platform-python",
+ "/usr/bin/python3",
+ "/usr/bin/python2",
+ "/usr/bin/python",
+ )
+ interpreter = respawn.probe_interpreters_for_module(system_interpreters, "dnf")
+ if interpreter:
+ respawn.respawn_module(interpreter)
class CoprModule(object):
@@ -460,6 +475,7 @@ def run_module():
params = module.params
if not HAS_DNF_PACKAGES:
+ _respawn_dnf()
module.fail_json(msg=missing_required_lib("dnf"), exception=DNF_IMP_ERR)
CoprModule.ansible_module = module
diff --git a/ansible_collections/community/general/plugins/modules/cpanm.py b/ansible_collections/community/general/plugins/modules/cpanm.py
index 6260992df..20ac3e714 100644
--- a/ansible_collections/community/general/plugins/modules/cpanm.py
+++ b/ansible_collections/community/general/plugins/modules/cpanm.py
@@ -27,8 +27,8 @@ options:
name:
type: str
description:
- - The Perl library to install. Valid values change according to the I(mode), see notes for more details.
- - Note that for installing from a local path the parameter I(from_path) should be used.
+ - The Perl library to install. Valid values change according to the O(mode), see notes for more details.
+ - Note that for installing from a local path the parameter O(from_path) should be used.
aliases: [pkg]
from_path:
type: path
@@ -59,7 +59,7 @@ options:
default: false
version:
description:
- - Version specification for the perl module. When I(mode) is C(new), C(cpanm) version operators are accepted.
+ - Version specification for the perl module. When O(mode) is V(new), C(cpanm) version operators are accepted.
type: str
executable:
description:
@@ -68,32 +68,24 @@ options:
mode:
description:
- Controls the module behavior. See notes below for more details.
+ - Default is V(compatibility) but that behavior is deprecated and will be changed to V(new) in community.general 9.0.0.
type: str
choices: [compatibility, new]
- default: compatibility
version_added: 3.0.0
name_check:
description:
- - When in C(new) mode, this parameter can be used to check if there is a module I(name) installed (at I(version), when specified).
+ - When O(mode=new), this parameter can be used to check if there is a module O(name) installed (at O(version), when specified).
type: str
version_added: 3.0.0
notes:
- Please note that U(http://search.cpan.org/dist/App-cpanminus/bin/cpanm, cpanm) must be installed on the remote host.
- - "This module now comes with a choice of execution I(mode): C(compatibility) or C(new)."
- - "C(compatibility) mode:"
- - When using C(compatibility) mode, the module will keep backward compatibility. This is the default mode.
- - I(name) must be either a module name or a distribution file.
- - >
- If the perl module given by I(name) is installed (at the exact I(version) when specified), then nothing happens.
- Otherwise, it will be installed using the C(cpanm) executable.
- - I(name) cannot be an URL, or a git URL.
- - C(cpanm) version specifiers do not work in this mode.
- - "C(new) mode:"
- - "When using C(new) mode, the module will behave differently"
- - >
- The I(name) parameter may refer to a module name, a distribution file,
- a HTTP URL or a git repository URL as described in C(cpanminus) documentation.
- - C(cpanm) version specifiers are recognized.
+ - "This module now comes with a choice of execution O(mode): V(compatibility) or V(new)."
+ - "O(mode=compatibility): When using V(compatibility) mode, the module will keep backward compatibility. This is the default mode.
+ O(name) must be either a module name or a distribution file. If the perl module given by O(name) is installed (at the exact O(version)
+ when specified), then nothing happens. Otherwise, it will be installed using the C(cpanm) executable. O(name) cannot be an URL, or a git URL.
+ C(cpanm) version specifiers do not work in this mode."
+ - "O(mode=new): When using V(new) mode, the module will behave differently. The O(name) parameter may refer to a module name, a distribution file,
+ a HTTP URL or a git repository URL as described in C(cpanminus) documentation. C(cpanm) version specifiers are recognized."
author:
- "Franck Cuny (@fcuny)"
- "Alexei Znamensky (@russoz)"
@@ -158,7 +150,7 @@ class CPANMinus(ModuleHelper):
mirror_only=dict(type='bool', default=False),
installdeps=dict(type='bool', default=False),
executable=dict(type='path'),
- mode=dict(type='str', choices=['compatibility', 'new'], default='compatibility'),
+ mode=dict(type='str', choices=['compatibility', 'new']),
name_check=dict(type='str')
),
required_one_of=[('name', 'from_path')],
@@ -176,6 +168,14 @@ class CPANMinus(ModuleHelper):
def __init_module__(self):
v = self.vars
+ if v.mode is None:
+ self.deprecate(
+ "The default value 'compatibility' for parameter 'mode' is being deprecated "
+ "and it will be replaced by 'new'",
+ version="9.0.0",
+ collection_name="community.general"
+ )
+ v.mode = "compatibility"
if v.mode == "compatibility":
if v.name_check:
self.do_raise("Parameter name_check can only be used with mode=new")
@@ -183,8 +183,9 @@ class CPANMinus(ModuleHelper):
if v.name and v.from_path:
self.do_raise("Parameters 'name' and 'from_path' are mutually exclusive when 'mode=new'")
- self.command = self.get_bin_path(v.executable if v.executable else self.command)
- self.vars.set("binary", self.command)
+ self.command = v.executable if v.executable else self.command
+ self.runner = CmdRunner(self.module, self.command, self.command_args_formats, check_rc=True)
+ self.vars.binary = self.runner.binary
def _is_package_installed(self, name, locallib, version):
def process(rc, out, err):
@@ -220,8 +221,6 @@ class CPANMinus(ModuleHelper):
self.do_raise(msg=err, cmd=self.vars.cmd_args)
return 'is up to date' not in err and 'is up to date' not in out
- runner = CmdRunner(self.module, self.command, self.command_args_formats, check_rc=True)
-
v = self.vars
pkg_param = 'from_path' if v.from_path else 'name'
@@ -235,7 +234,7 @@ class CPANMinus(ModuleHelper):
return
pkg_spec = self.sanitize_pkg_spec_version(v[pkg_param], v.version)
- with runner(['notest', 'locallib', 'mirror', 'mirror_only', 'installdeps', 'pkg_spec'], output_process=process) as ctx:
+ with self.runner(['notest', 'locallib', 'mirror', 'mirror_only', 'installdeps', 'pkg_spec'], output_process=process) as ctx:
self.changed = ctx.run(pkg_spec=pkg_spec)
diff --git a/ansible_collections/community/general/plugins/modules/cronvar.py b/ansible_collections/community/general/plugins/modules/cronvar.py
index 7effed2ae..fdcbc7d24 100644
--- a/ansible_collections/community/general/plugins/modules/cronvar.py
+++ b/ansible_collections/community/general/plugins/modules/cronvar.py
@@ -40,16 +40,16 @@ options:
value:
description:
- The value to set this variable to.
- - Required if I(state=present).
+ - Required if O(state=present).
type: str
insertafter:
description:
- If specified, the variable will be inserted after the variable specified.
- - Used with I(state=present).
+ - Used with O(state=present).
type: str
insertbefore:
description:
- - Used with I(state=present). If specified, the variable will be inserted
+ - Used with O(state=present). If specified, the variable will be inserted
just before the variable specified.
type: str
state:
@@ -61,18 +61,19 @@ options:
user:
description:
- The specific user whose crontab should be modified.
- - This parameter defaults to C(root) when unset.
+ - This parameter defaults to V(root) when unset.
type: str
cron_file:
description:
- If specified, uses this file instead of an individual user's crontab.
- - Without a leading C(/), this is assumed to be in I(/etc/cron.d).
- - With a leading C(/), this is taken as absolute.
+ - Without a leading V(/), this is assumed to be in C(/etc/cron.d).
+ - With a leading V(/), this is taken as absolute.
type: str
backup:
description:
- If set, create a backup of the crontab before it is modified.
The location of the backup is returned in the C(backup) variable by this module.
+ # TODO: C() above should be RV(), but return values have not been documented!
type: bool
default: false
requirements:
diff --git a/ansible_collections/community/general/plugins/modules/crypttab.py b/ansible_collections/community/general/plugins/modules/crypttab.py
index 6aea362e7..931a0c930 100644
--- a/ansible_collections/community/general/plugins/modules/crypttab.py
+++ b/ansible_collections/community/general/plugins/modules/crypttab.py
@@ -25,38 +25,38 @@ options:
name:
description:
- Name of the encrypted block device as it appears in the C(/etc/crypttab) file, or
- optionally prefixed with C(/dev/mapper/), as it appears in the filesystem. I(/dev/mapper/)
- will be stripped from I(name).
+ optionally prefixed with V(/dev/mapper/), as it appears in the filesystem. V(/dev/mapper/)
+ will be stripped from O(name).
type: str
required: true
state:
description:
- - Use I(present) to add a line to C(/etc/crypttab) or update its definition
+ - Use V(present) to add a line to C(/etc/crypttab) or update its definition
if already present.
- - Use I(absent) to remove a line with matching I(name).
- - Use I(opts_present) to add options to those already present; options with
+ - Use V(absent) to remove a line with matching O(name).
+ - Use V(opts_present) to add options to those already present; options with
different values will be updated.
- - Use I(opts_absent) to remove options from the existing set.
+ - Use V(opts_absent) to remove options from the existing set.
type: str
required: true
choices: [ absent, opts_absent, opts_present, present ]
backing_device:
description:
- Path to the underlying block device or file, or the UUID of a block-device
- prefixed with I(UUID=).
+ prefixed with V(UUID=).
type: str
password:
description:
- Encryption password, the path to a file containing the password, or
- C(-) or unset if the password should be entered at boot.
+ V(-) or unset if the password should be entered at boot.
type: path
opts:
description:
- - A comma-delimited list of options. See C(crypttab(5) ) for details.
+ - A comma-delimited list of options. See V(crypttab(5\)) for details.
type: str
path:
description:
- - Path to file to use instead of C(/etc/crypttab).
+ - Path to file to use instead of V(/etc/crypttab).
- This might be useful in a chroot environment.
type: path
default: /etc/crypttab
diff --git a/ansible_collections/community/general/plugins/modules/datadog_downtime.py b/ansible_collections/community/general/plugins/modules/datadog_downtime.py
index 6e506eb85..a3a6a660f 100644
--- a/ansible_collections/community/general/plugins/modules/datadog_downtime.py
+++ b/ansible_collections/community/general/plugins/modules/datadog_downtime.py
@@ -38,7 +38,7 @@ options:
api_host:
description:
- The URL to the Datadog API.
- - This value can also be set with the C(DATADOG_HOST) environment variable.
+ - This value can also be set with the E(DATADOG_HOST) environment variable.
required: false
default: https://api.datadoghq.com
type: str
@@ -57,7 +57,7 @@ options:
id:
description:
- The identifier of the downtime.
- - If empty, a new downtime gets created, otherwise it is either updated or deleted depending of the C(state).
+ - If empty, a new downtime gets created, otherwise it is either updated or deleted depending of the O(state).
- To keep your playbook idempotent, you should save the identifier in a file and read it in a lookup.
type: int
monitor_tags:
@@ -99,7 +99,7 @@ options:
- For example, to have a recurring event on the first day of each month,
select a type of rrule and set the C(FREQ) to C(MONTHLY) and C(BYMONTHDAY) to C(1).
- Most common rrule options from the iCalendar Spec are supported.
- - Attributes specifying the duration in C(RRULE) are not supported (e.g. C(DTSTART), C(DTEND), C(DURATION)).
+ - Attributes specifying the duration in C(RRULE) are not supported (for example C(DTSTART), C(DTEND), C(DURATION)).
type: str
"""
@@ -248,7 +248,8 @@ def build_downtime(module):
downtime.timezone = module.params["timezone"]
if module.params["rrule"]:
downtime.recurrence = DowntimeRecurrence(
- rrule=module.params["rrule"]
+ rrule=module.params["rrule"],
+ type="rrule",
)
return downtime
diff --git a/ansible_collections/community/general/plugins/modules/datadog_event.py b/ansible_collections/community/general/plugins/modules/datadog_event.py
index b8161eca6..6008b565b 100644
--- a/ansible_collections/community/general/plugins/modules/datadog_event.py
+++ b/ansible_collections/community/general/plugins/modules/datadog_event.py
@@ -82,7 +82,7 @@ options:
description: ["An arbitrary string to use for aggregation."]
validate_certs:
description:
- - If C(false), SSL certificates will not be validated. This should only be used
+ - If V(false), SSL certificates will not be validated. This should only be used
on personally controlled sites using self-signed certificates.
type: bool
default: true
diff --git a/ansible_collections/community/general/plugins/modules/datadog_monitor.py b/ansible_collections/community/general/plugins/modules/datadog_monitor.py
index f58df358b..75ae8c233 100644
--- a/ansible_collections/community/general/plugins/modules/datadog_monitor.py
+++ b/ansible_collections/community/general/plugins/modules/datadog_monitor.py
@@ -16,7 +16,6 @@ short_description: Manages Datadog monitors
description:
- Manages monitors within Datadog.
- Options as described on https://docs.datadoghq.com/api/.
- - The type C(event-v2) was added in community.general 4.8.0.
author: Sebastian Kornehl (@skornehl)
requirements: [datadog]
extends_documentation_fragment:
@@ -34,8 +33,8 @@ options:
type: str
api_host:
description:
- - The URL to the Datadog API. Default value is C(https://api.datadoghq.com).
- - This value can also be set with the C(DATADOG_HOST) environment variable.
+ - The URL to the Datadog API. Default value is V(https://api.datadoghq.com).
+ - This value can also be set with the E(DATADOG_HOST) environment variable.
required: false
type: str
version_added: '0.2.0'
@@ -59,8 +58,9 @@ options:
type:
description:
- The type of the monitor.
- - The types C(query alert), C(trace-analytics alert) and C(rum alert) were added in community.general 2.1.0.
- - The type C(composite) was added in community.general 3.4.0.
+ - The types V(query alert), V(trace-analytics alert) and V(rum alert) were added in community.general 2.1.0.
+ - The type V(composite) was added in community.general 3.4.0.
+ - The type V(event-v2 alert) was added in community.general 4.8.0.
choices:
- metric alert
- service check
@@ -117,7 +117,7 @@ options:
escalation_message:
description:
- A message to include with a re-notification. Supports the '@username' notification we allow elsewhere.
- - Not applicable if I(renotify_interval=None).
+ - Not applicable if O(renotify_interval=none).
type: str
notify_audit:
description:
@@ -130,7 +130,7 @@ options:
- A dictionary of thresholds by status.
- Only available for service checks and metric alerts.
- Because each of them can have multiple thresholds, we do not define them directly in the query.
- - "If not specified, it defaults to: C({'ok': 1, 'critical': 1, 'warning': 1})."
+ - "If not specified, it defaults to: V({'ok': 1, 'critical': 1, 'warning': 1})."
locked:
description:
- Whether changes to this monitor should be restricted to the creator or admins.
@@ -167,6 +167,32 @@ options:
- Integer from 1 (high) to 5 (low) indicating alert severity.
type: int
version_added: 4.6.0
+ notification_preset_name:
+ description:
+ - Toggles the display of additional content sent in the monitor notification.
+ choices:
+ - show_all
+ - hide_query
+ - hide_handles
+ - hide_all
+ type: str
+ version_added: 7.1.0
+ renotify_occurrences:
+ description:
+ - The number of times re-notification messages should be sent on the current status at the provided re-notification interval.
+ type: int
+ version_added: 7.1.0
+ renotify_statuses:
+ description:
+ - The types of monitor statuses for which re-notification messages are sent.
+ choices:
+ - alert
+ - warn
+ - no data
+ type: list
+ elements: str
+ version_added: 7.1.0
+
'''
EXAMPLES = '''
@@ -175,6 +201,10 @@ EXAMPLES = '''
type: "metric alert"
name: "Test monitor"
state: "present"
+ renotify_interval: 30
+ renotify_occurrences: 1
+ renotify_statuses: ["warn"]
+ notification_preset_name: "show_all"
query: "datadog.agent.up.over('host:host1').last(2).count_by_status()"
notification_message: "Host [[host.name]] with IP [[host.ip]] is failing to report to datadog."
api_key: "9775a026f1ca7d1c6c5af9d94d9595a4"
@@ -254,6 +284,9 @@ def main():
id=dict(),
include_tags=dict(required=False, default=True, type='bool'),
priority=dict(type='int'),
+ notification_preset_name=dict(choices=['show_all', 'hide_query', 'hide_handles', 'hide_all']),
+ renotify_occurrences=dict(type='int'),
+ renotify_statuses=dict(type='list', elements='str', choices=['alert', 'warn', 'no data']),
)
)
@@ -368,6 +401,9 @@ def install_monitor(module):
"new_host_delay": module.params['new_host_delay'],
"evaluation_delay": module.params['evaluation_delay'],
"include_tags": module.params['include_tags'],
+ "notification_preset_name": module.params['notification_preset_name'],
+ "renotify_occurrences": module.params['renotify_occurrences'],
+ "renotify_statuses": module.params['renotify_statuses'],
}
if module.params['type'] == "service check":
diff --git a/ansible_collections/community/general/plugins/modules/dconf.py b/ansible_collections/community/general/plugins/modules/dconf.py
index 8c325486c..065cf1a6a 100644
--- a/ansible_collections/community/general/plugins/modules/dconf.py
+++ b/ansible_collections/community/general/plugins/modules/dconf.py
@@ -46,11 +46,11 @@ notes:
- Keep in mind that the C(dconf) CLI tool, which this module wraps around,
utilises an unusual syntax for the values (GVariant). For example, if you
wanted to provide a string value, the correct syntax would be
- I(value="'myvalue'") - with single quotes as part of the Ansible parameter
+ O(value="'myvalue'") - with single quotes as part of the Ansible parameter
value.
- When using loops in combination with a value like
- "[('xkb', 'us'), ('xkb', 'se')]", you need to be aware of possible
- type conversions. Applying a filter C({{ item.value | string }})
+ V("[('xkb', 'us'\), ('xkb', 'se'\)]"), you need to be aware of possible
+ type conversions. Applying a filter V({{ item.value | string }})
to the parameter variable can avoid potential conversion problems.
- The easiest way to figure out exact syntax/value you need to provide for a
key is by making the configuration change in application affected by the
@@ -76,7 +76,7 @@ options:
- Value to set for the specified dconf key. Value should be specified in
GVariant format. Due to complexity of this format, it is best to have a
look at existing values in the dconf database.
- - Required for I(state=present).
+ - Required for O(state=present).
- Although the type is specified as "raw", it should typically be
specified as a string. However, boolean values in particular are
handled properly even when specified as booleans rather than strings
@@ -400,7 +400,7 @@ class DconfPreference(object):
rc, out, err = dbus_wrapper.run_command(command)
if rc != 0:
- self.module.fail_json(msg='dconf failed while reseting the value with error: %s' % err,
+ self.module.fail_json(msg='dconf failed while resetting the value with error: %s' % err,
out=out,
err=err)
diff --git a/ansible_collections/community/general/plugins/modules/deploy_helper.py b/ansible_collections/community/general/plugins/modules/deploy_helper.py
index f0246cae6..b47ed8254 100644
--- a/ansible_collections/community/general/plugins/modules/deploy_helper.py
+++ b/ansible_collections/community/general/plugins/modules/deploy_helper.py
@@ -20,8 +20,9 @@ description:
- The Deploy Helper manages some of the steps common in deploying software.
It creates a folder structure, manages a symlink for the current release
and cleans up old releases.
- - "Running it with the I(state=query) or I(state=present) will return the C(deploy_helper) fact.
- C(project_path), whatever you set in the I(path) parameter,
+ # TODO: convert below to RETURN documentation!
+ - "Running it with the O(state=query) or O(state=present) will return the C(deploy_helper) fact.
+ C(project_path), whatever you set in the O(path) parameter,
C(current_path), the path to the symlink that points to the active release,
C(releases_path), the path to the folder to keep releases in,
C(shared_path), the path to the folder to keep shared resources in,
@@ -50,33 +51,33 @@ options:
type: str
description:
- The state of the project.
- C(query) will only gather facts,
- C(present) will create the project I(root) folder, and in it the I(releases) and I(shared) folders,
- C(finalize) will remove the unfinished_filename file, create a symlink to the newly
- deployed release and optionally clean old releases,
- C(clean) will remove failed & old releases,
- C(absent) will remove the project folder (synonymous to the M(ansible.builtin.file) module with I(state=absent)).
+ - V(query) will only gather facts.
+ - V(present) will create the project C(root) folder, and in it the C(releases) and C(shared) folders.
+ - V(finalize) will remove the unfinished_filename file, create a symlink to the newly
+ deployed release and optionally clean old releases.
+ - V(clean) will remove failed & old releases.
+ - V(absent) will remove the project folder (synonymous to the M(ansible.builtin.file) module with O(state=absent)).
choices: [ present, finalize, absent, clean, query ]
default: present
release:
type: str
description:
- - The release version that is being deployed. Defaults to a timestamp format %Y%m%d%H%M%S (i.e. '20141119223359').
- This parameter is optional during I(state=present), but needs to be set explicitly for I(state=finalize).
- You can use the generated fact I(release={{ deploy_helper.new_release }}).
+ - The release version that is being deployed. Defaults to a timestamp format C(%Y%m%d%H%M%S) (for example V(20141119223359)).
+ This parameter is optional during O(state=present), but needs to be set explicitly for O(state=finalize).
+ You can use the generated fact C(release={{ deploy_helper.new_release }}).
releases_path:
type: str
description:
- - The name of the folder that will hold the releases. This can be relative to I(path) or absolute.
+ - The name of the folder that will hold the releases. This can be relative to O(path) or absolute.
Returned in the C(deploy_helper.releases_path) fact.
default: releases
shared_path:
type: path
description:
- - The name of the folder that will hold the shared resources. This can be relative to I(path) or absolute.
+ - The name of the folder that will hold the shared resources. This can be relative to O(path) or absolute.
If this is set to an empty string, no shared folder will be created.
Returned in the C(deploy_helper.shared_path) fact.
default: shared
@@ -84,38 +85,38 @@ options:
current_path:
type: path
description:
- - The name of the symlink that is created when the deploy is finalized. Used in I(finalize) and I(clean).
+ - The name of the symlink that is created when the deploy is finalized. Used in O(state=finalize) and O(state=clean).
Returned in the C(deploy_helper.current_path) fact.
default: current
unfinished_filename:
type: str
description:
- - The name of the file that indicates a deploy has not finished. All folders in the I(releases_path) that
- contain this file will be deleted on I(state=finalize) with I(clean=True), or I(state=clean). This file is
- automatically deleted from the I(new_release_path) during I(state=finalize).
+ - The name of the file that indicates a deploy has not finished. All folders in the O(releases_path) that
+ contain this file will be deleted on O(state=finalize) with O(clean=true), or O(state=clean). This file is
+ automatically deleted from the C(new_release_path) during O(state=finalize).
default: DEPLOY_UNFINISHED
clean:
description:
- - Whether to run the clean procedure in case of I(state=finalize).
+ - Whether to run the clean procedure in case of O(state=finalize).
type: bool
default: true
keep_releases:
type: int
description:
- - The number of old releases to keep when cleaning. Used in I(finalize) and I(clean). Any unfinished builds
+ - The number of old releases to keep when cleaning. Used in O(state=finalize) and O(state=clean). Any unfinished builds
will be deleted first, so only correct releases will count. The current version will not count.
default: 5
notes:
- - Facts are only returned for I(state=query) and I(state=present). If you use both, you should pass any overridden
+ - Facts are only returned for O(state=query) and O(state=present). If you use both, you should pass any overridden
parameters to both calls, otherwise the second call will overwrite the facts of the first one.
- - When using I(state=clean), the releases are ordered by I(creation date). You should be able to switch to a
+ - When using O(state=clean), the releases are ordered by I(creation date). You should be able to switch to a
new naming strategy without problems.
- - Because of the default behaviour of generating the I(new_release) fact, this module will not be idempotent
- unless you pass your own release name with I(release). Due to the nature of deploying software, this should not
+ - Because of the default behaviour of generating the C(new_release) fact, this module will not be idempotent
+ unless you pass your own release name with O(release). Due to the nature of deploying software, this should not
be much of a problem.
extends_documentation_fragment:
- ansible.builtin.files
diff --git a/ansible_collections/community/general/plugins/modules/dimensiondata_network.py b/ansible_collections/community/general/plugins/modules/dimensiondata_network.py
index 8c1469063..cfb7d61cd 100644
--- a/ansible_collections/community/general/plugins/modules/dimensiondata_network.py
+++ b/ansible_collections/community/general/plugins/modules/dimensiondata_network.py
@@ -84,7 +84,7 @@ EXAMPLES = '''
RETURN = '''
network:
description: Dictionary describing the network.
- returned: On success when I(state=present).
+ returned: On success when O(state=present).
type: complex
contains:
id:
diff --git a/ansible_collections/community/general/plugins/modules/dimensiondata_vlan.py b/ansible_collections/community/general/plugins/modules/dimensiondata_vlan.py
index 7d83ddc69..9d129f3de 100644
--- a/ansible_collections/community/general/plugins/modules/dimensiondata_vlan.py
+++ b/ansible_collections/community/general/plugins/modules/dimensiondata_vlan.py
@@ -51,20 +51,20 @@ options:
private_ipv4_prefix_size:
description:
- The size of the IPv4 address space, e.g 24.
- - Required, if C(private_ipv4_base_address) is specified.
+ - Required, if O(private_ipv4_base_address) is specified.
type: int
default: 0
state:
description:
- The desired state for the target VLAN.
- - C(readonly) ensures that the state is only ever read, not modified (the module will fail if the resource does not exist).
+ - V(readonly) ensures that the state is only ever read, not modified (the module will fail if the resource does not exist).
choices: [present, absent, readonly]
default: present
type: str
allow_expand:
description:
- Permit expansion of the target VLAN's network if the module parameters specify a larger network than the VLAN currently possesses.
- - If C(False), the module will fail under these conditions.
+ - If V(false), the module will fail under these conditions.
- This is intended to prevent accidental expansion of a VLAN's network (since this operation is not reversible).
type: bool
default: false
@@ -105,7 +105,7 @@ EXAMPLES = '''
RETURN = '''
vlan:
description: Dictionary describing the VLAN.
- returned: On success when I(state) is 'present'
+ returned: On success when O(state=present)
type: complex
contains:
id:
diff --git a/ansible_collections/community/general/plugins/modules/discord.py b/ansible_collections/community/general/plugins/modules/discord.py
index 8b5391d44..130649f07 100644
--- a/ansible_collections/community/general/plugins/modules/discord.py
+++ b/ansible_collections/community/general/plugins/modules/discord.py
@@ -43,7 +43,7 @@ options:
content:
description:
- Content of the message to the Discord channel.
- - At least one of I(content) and I(embeds) must be specified.
+ - At least one of O(content) and O(embeds) must be specified.
type: str
username:
description:
@@ -55,7 +55,7 @@ options:
type: str
tts:
description:
- - Set this to C(true) if this is a TTS (Text to Speech) message.
+ - Set this to V(true) if this is a TTS (Text to Speech) message.
type: bool
default: false
embeds:
@@ -63,7 +63,7 @@ options:
- Send messages as Embeds to the Discord channel.
- Embeds can have a colored border, embedded images, text fields and more.
- "Allowed parameters are described in the Discord Docs: U(https://discord.com/developers/docs/resources/channel#embed-object)"
- - At least one of I(content) and I(embeds) must be specified.
+ - At least one of O(content) and O(embeds) must be specified.
type: list
elements: dict
'''
diff --git a/ansible_collections/community/general/plugins/modules/django_manage.py b/ansible_collections/community/general/plugins/modules/django_manage.py
index 537cf0fa7..114ec0353 100644
--- a/ansible_collections/community/general/plugins/modules/django_manage.py
+++ b/ansible_collections/community/general/plugins/modules/django_manage.py
@@ -16,7 +16,7 @@ module: django_manage
short_description: Manages a Django application
description:
- Manages a Django application using the C(manage.py) application frontend to C(django-admin). With the
- I(virtualenv) parameter, all management commands will be executed by the given C(virtualenv) installation.
+ O(virtualenv) parameter, all management commands will be executed by the given C(virtualenv) installation.
extends_documentation_fragment:
- community.general.attributes
attributes:
@@ -29,20 +29,20 @@ options:
description:
- The name of the Django management command to run. The commands listed below are built in this module and have some basic parameter validation.
- >
- C(cleanup) - clean up old data from the database (deprecated in Django 1.5). This parameter will be
- removed in community.general 9.0.0. Use C(clearsessions) instead.
- - C(collectstatic) - Collects the static files into C(STATIC_ROOT).
- - C(createcachetable) - Creates the cache tables for use with the database cache backend.
- - C(flush) - Removes all data from the database.
- - C(loaddata) - Searches for and loads the contents of the named I(fixtures) into the database.
- - C(migrate) - Synchronizes the database state with models and migrations.
+ V(cleanup) - clean up old data from the database (deprecated in Django 1.5). This parameter will be
+ removed in community.general 9.0.0. Use V(clearsessions) instead.
+ - V(collectstatic) - Collects the static files into C(STATIC_ROOT).
+ - V(createcachetable) - Creates the cache tables for use with the database cache backend.
+ - V(flush) - Removes all data from the database.
+ - V(loaddata) - Searches for and loads the contents of the named O(fixtures) into the database.
+ - V(migrate) - Synchronizes the database state with models and migrations.
- >
- C(syncdb) - Synchronizes the database state with models and migrations (deprecated in Django 1.7).
- This parameter will be removed in community.general 9.0.0. Use C(migrate) instead.
- - C(test) - Runs tests for all installed apps.
+ V(syncdb) - Synchronizes the database state with models and migrations (deprecated in Django 1.7).
+ This parameter will be removed in community.general 9.0.0. Use V(migrate) instead.
+ - V(test) - Runs tests for all installed apps.
- >
- C(validate) - Validates all installed models (deprecated in Django 1.7). This parameter will be
- removed in community.general 9.0.0. Use C(check) instead.
+ V(validate) - Validates all installed models (deprecated in Django 1.7). This parameter will be
+ removed in community.general 9.0.0. Use V(check) instead.
- Other commands can be entered, but will fail if they are unknown to Django. Other commands that may
prompt for user input should be run with the C(--noinput) flag.
type: str
@@ -55,14 +55,14 @@ options:
aliases: [app_path, chdir]
settings:
description:
- - The Python path to the application's settings module, such as C(myapp.settings).
+ - The Python path to the application's settings module, such as V(myapp.settings).
type: path
required: false
pythonpath:
description:
- A directory to add to the Python path. Typically used to include the settings module if it is located
external to the application directory.
- - This would be equivalent to adding I(pythonpath)'s value to the C(PYTHONPATH) environment variable.
+ - This would be equivalent to adding O(pythonpath)'s value to the E(PYTHONPATH) environment variable.
type: path
required: false
aliases: [python_path]
@@ -73,54 +73,54 @@ options:
aliases: [virtual_env]
apps:
description:
- - A list of space-delimited apps to target. Used by the C(test) command.
+ - A list of space-delimited apps to target. Used by the V(test) command.
type: str
required: false
cache_table:
description:
- - The name of the table used for database-backed caching. Used by the C(createcachetable) command.
+ - The name of the table used for database-backed caching. Used by the V(createcachetable) command.
type: str
required: false
clear:
description:
- Clear the existing files before trying to copy or link the original file.
- - Used only with the C(collectstatic) command. The C(--noinput) argument will be added automatically.
+ - Used only with the V(collectstatic) command. The C(--noinput) argument will be added automatically.
required: false
default: false
type: bool
database:
description:
- - The database to target. Used by the C(createcachetable), C(flush), C(loaddata), C(syncdb),
- and C(migrate) commands.
+ - The database to target. Used by the V(createcachetable), V(flush), V(loaddata), V(syncdb),
+ and V(migrate) commands.
type: str
required: false
failfast:
description:
- - Fail the command immediately if a test fails. Used by the C(test) command.
+ - Fail the command immediately if a test fails. Used by the V(test) command.
required: false
default: false
type: bool
aliases: [fail_fast]
fixtures:
description:
- - A space-delimited list of fixture file names to load in the database. B(Required) by the C(loaddata) command.
+ - A space-delimited list of fixture file names to load in the database. B(Required) by the V(loaddata) command.
type: str
required: false
skip:
description:
- - Will skip over out-of-order missing migrations, you can only use this parameter with C(migrate) command.
+ - Will skip over out-of-order missing migrations, you can only use this parameter with V(migrate) command.
required: false
type: bool
merge:
description:
- Will run out-of-order or missing migrations as they are not rollback migrations, you can only use this
- parameter with C(migrate) command.
+ parameter with V(migrate) command.
required: false
type: bool
link:
description:
- Will create links to the files instead of copying them, you can only use this parameter with
- C(collectstatic) command.
+ V(collectstatic) command.
required: false
type: bool
testrunner:
@@ -133,9 +133,9 @@ options:
ack_venv_creation_deprecation:
description:
- >-
- When a I(virtualenv) is set but the virtual environment does not exist, the current behavior is
+ When a O(virtualenv) is set but the virtual environment does not exist, the current behavior is
to create a new virtual environment. That behavior is deprecated and if that case happens it will
- generate a deprecation warning. Set this flag to C(true) to suppress the deprecation warning.
+ generate a deprecation warning. Set this flag to V(true) to suppress the deprecation warning.
- Please note that you will receive no further warning about this being removed until the module
will start failing in such cases from community.general 9.0.0 on.
type: bool
@@ -146,19 +146,19 @@ notes:
B(ATTENTION - DEPRECATION): Support for Django releases older than 4.1 will be removed in
community.general version 9.0.0 (estimated to be released in May 2024).
Please notice that Django 4.1 requires Python 3.8 or greater.
- - C(virtualenv) (U(http://www.virtualenv.org)) must be installed on the remote host if the I(virtualenv) parameter
+ - C(virtualenv) (U(http://www.virtualenv.org)) must be installed on the remote host if the O(virtualenv) parameter
is specified. This requirement is deprecated and will be removed in community.general version 9.0.0.
- - This module will create a virtualenv if the I(virtualenv) parameter is specified and a virtual environment does not already
+ - This module will create a virtualenv if the O(virtualenv) parameter is specified and a virtual environment does not already
exist at the given location. This behavior is deprecated and will be removed in community.general version 9.0.0.
- - The parameter I(virtualenv) will remain in use, but it will require the specified virtualenv to exist.
+ - The parameter O(virtualenv) will remain in use, but it will require the specified virtualenv to exist.
The recommended way to create one in Ansible is by using M(ansible.builtin.pip).
- - This module assumes English error messages for the C(createcachetable) command to detect table existence,
+ - This module assumes English error messages for the V(createcachetable) command to detect table existence,
unfortunately.
- - To be able to use the C(migrate) command with django versions < 1.7, you must have C(south) installed and added
+ - To be able to use the V(migrate) command with django versions < 1.7, you must have C(south) installed and added
as an app in your settings.
- - To be able to use the C(collectstatic) command, you must have enabled staticfiles in your settings.
- - Your C(manage.py) application must be executable (rwxr-xr-x), and must have a valid shebang,
- i.e. C(#!/usr/bin/env python), for invoking the appropriate Python interpreter.
+ - To be able to use the V(collectstatic) command, you must have enabled staticfiles in your settings.
+ - Your C(manage.py) application must be executable (C(rwxr-xr-x)), and must have a valid shebang,
+ for example C(#!/usr/bin/env python), for invoking the appropriate Python interpreter.
seealso:
- name: django-admin and manage.py Reference
description: Reference for C(django-admin) or C(manage.py) commands.
diff --git a/ansible_collections/community/general/plugins/modules/dnf_config_manager.py b/ansible_collections/community/general/plugins/modules/dnf_config_manager.py
new file mode 100644
index 000000000..069fd0ddc
--- /dev/null
+++ b/ansible_collections/community/general/plugins/modules/dnf_config_manager.py
@@ -0,0 +1,225 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2023, Andrew Hyatt <andy@hyatt.xyz>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+DOCUMENTATION = r'''
+---
+module: dnf_config_manager
+short_description: Enable or disable dnf repositories using config-manager
+version_added: 8.2.0
+description:
+ - This module enables or disables repositories using the C(dnf config-manager) sub-command.
+author: Andrew Hyatt (@ahyattdev) <andy@hyatt.xyz>
+requirements:
+ - dnf
+ - dnf-plugins-core
+extends_documentation_fragment:
+ - community.general.attributes
+attributes:
+ check_mode:
+ support: full
+ diff_mode:
+ support: none
+options:
+ name:
+ description:
+ - Repository ID, for example V(crb).
+ default: []
+ required: false
+ type: list
+ elements: str
+ state:
+ description:
+ - Whether the repositories should be V(enabled) or V(disabled).
+ default: enabled
+ required: false
+ type: str
+ choices: [enabled, disabled]
+seealso:
+ - module: ansible.builtin.dnf
+ - module: ansible.builtin.yum_repository
+'''
+
+EXAMPLES = r'''
+- name: Ensure the crb repository is enabled
+ community.general.dnf_config_manager:
+ name: crb
+ state: enabled
+
+- name: Ensure the appstream and zfs repositories are disabled
+ community.general.dnf_config_manager:
+ name:
+ - appstream
+ - zfs
+ state: disabled
+'''
+
+RETURN = r'''
+repo_states_pre:
+ description: Repo IDs before action taken.
+ returned: success
+ type: dict
+ contains:
+ enabled:
+ description: Enabled repository IDs.
+ returned: success
+ type: list
+ elements: str
+ disabled:
+ description: Disabled repository IDs.
+ returned: success
+ type: list
+ elements: str
+ sample:
+ enabled:
+ - appstream
+ - baseos
+ - crb
+ disabled:
+ - appstream-debuginfo
+ - appstream-source
+ - baseos-debuginfo
+ - baseos-source
+ - crb-debug
+ - crb-source
+repo_states_post:
+ description: Repository states after action taken.
+ returned: success
+ type: dict
+ contains:
+ enabled:
+ description: Enabled repository IDs.
+ returned: success
+ type: list
+ elements: str
+ disabled:
+ description: Disabled repository IDs.
+ returned: success
+ type: list
+ elements: str
+ sample:
+ enabled:
+ - appstream
+ - baseos
+ - crb
+ disabled:
+ - appstream-debuginfo
+ - appstream-source
+ - baseos-debuginfo
+ - baseos-source
+ - crb-debug
+ - crb-source
+changed_repos:
+ description: Repositories changed.
+ returned: success
+ type: list
+ elements: str
+ sample: [ 'crb' ]
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+import os
+import re
+
+DNF_BIN = "/usr/bin/dnf"
+REPO_ID_RE = re.compile(r'^Repo-id\s*:\s*(\S+)$')
+REPO_STATUS_RE = re.compile(r'^Repo-status\s*:\s*(disabled|enabled)$')
+
+
+def get_repo_states(module):
+ rc, out, err = module.run_command([DNF_BIN, 'repolist', '--all', '--verbose'], check_rc=True)
+
+ repos = dict()
+ last_repo = ''
+ for i, line in enumerate(out.split('\n')):
+ m = REPO_ID_RE.match(line)
+ if m:
+ if len(last_repo) > 0:
+ module.fail_json(msg='dnf repolist parse failure: parsed another repo id before next status')
+ last_repo = m.group(1)
+ continue
+ m = REPO_STATUS_RE.match(line)
+ if m:
+ if len(last_repo) == 0:
+ module.fail_json(msg='dnf repolist parse failure: parsed status before repo id')
+ repos[last_repo] = m.group(1)
+ last_repo = ''
+ return repos
+
+
+def set_repo_states(module, repo_ids, state):
+ module.run_command([DNF_BIN, 'config-manager', '--set-{0}'.format(state)] + repo_ids, check_rc=True)
+
+
+def pack_repo_states_for_return(states):
+ enabled = []
+ disabled = []
+ for repo_id in states:
+ if states[repo_id] == 'enabled':
+ enabled.append(repo_id)
+ else:
+ disabled.append(repo_id)
+
+ # Sort for consistent results
+ enabled.sort()
+ disabled.sort()
+
+ return {'enabled': enabled, 'disabled': disabled}
+
+
+def main():
+ module_args = dict(
+ name=dict(type='list', elements='str', required=False, default=[]),
+ state=dict(type='str', required=False, choices=['enabled', 'disabled'], default='enabled')
+ )
+
+ result = dict(
+ changed=False
+ )
+
+ module = AnsibleModule(
+ argument_spec=module_args,
+ supports_check_mode=True
+ )
+
+ if not os.path.exists(DNF_BIN):
+ module.fail_json(msg="%s was not found" % DNF_BIN)
+
+ repo_states = get_repo_states(module)
+ result['repo_states_pre'] = pack_repo_states_for_return(repo_states)
+
+ desired_repo_state = module.params['state']
+ names = module.params['name']
+
+ to_change = []
+ for repo_id in names:
+ if repo_id not in repo_states:
+ module.fail_json(msg="did not find repo with ID '{0}' in dnf repolist --all --verbose".format(repo_id))
+ if repo_states[repo_id] != desired_repo_state:
+ to_change.append(repo_id)
+ result['changed'] = len(to_change) > 0
+ result['changed_repos'] = to_change
+
+ if module.check_mode:
+ module.exit_json(**result)
+
+ if len(to_change) > 0:
+ set_repo_states(module, to_change, desired_repo_state)
+
+ repo_states_post = get_repo_states(module)
+ result['repo_states_post'] = pack_repo_states_for_return(repo_states_post)
+
+ for repo_id in to_change:
+ if repo_states_post[repo_id] != desired_repo_state:
+ module.fail_json(msg="dnf config-manager failed to make '{0}' {1}".format(repo_id, desired_repo_state))
+
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/general/plugins/modules/dnf_versionlock.py b/ansible_collections/community/general/plugins/modules/dnf_versionlock.py
index fac3ad78d..3fcf132ea 100644
--- a/ansible_collections/community/general/plugins/modules/dnf_versionlock.py
+++ b/ansible_collections/community/general/plugins/modules/dnf_versionlock.py
@@ -38,7 +38,7 @@ options:
description:
- Package name spec to add or exclude to or delete from the C(locklist)
using the format expected by the C(dnf repoquery) command.
- - This parameter is mutually exclusive with I(state=clean).
+ - This parameter is mutually exclusive with O(state=clean).
type: list
required: false
elements: str
@@ -52,19 +52,19 @@ options:
default: false
state:
description:
- - Whether to add (C(present) or C(excluded)) to or remove (C(absent) or
- C(clean)) from the C(locklist).
- - C(present) will add a package name spec to the C(locklist). If there is a
+ - Whether to add (V(present) or V(excluded)) to or remove (V(absent) or
+ V(clean)) from the C(locklist).
+ - V(present) will add a package name spec to the C(locklist). If there is a
installed package that matches, then only that version will be added.
Otherwise, all available package versions will be added.
- - C(excluded) will add a package name spec as excluded to the
+ - V(excluded) will add a package name spec as excluded to the
C(locklist). It means that packages represented by the package name
spec will be excluded from transaction operations. All available
package versions will be added.
- - C(absent) will delete entries in the C(locklist) that match the
+ - V(absent) will delete entries in the C(locklist) that match the
package name spec.
- - C(clean) will delete all entries in the C(locklist). This option is
- mutually exclusive with C(name).
+ - V(clean) will delete all entries in the C(locklist). This option is
+ mutually exclusive with O(name).
choices: [ 'absent', 'clean', 'excluded', 'present' ]
type: str
default: present
diff --git a/ansible_collections/community/general/plugins/modules/dnsimple.py b/ansible_collections/community/general/plugins/modules/dnsimple.py
index df41f73a6..c5829e36e 100644
--- a/ansible_collections/community/general/plugins/modules/dnsimple.py
+++ b/ansible_collections/community/general/plugins/modules/dnsimple.py
@@ -26,13 +26,13 @@ attributes:
options:
account_email:
description:
- - Account email. If omitted, the environment variables C(DNSIMPLE_EMAIL) and C(DNSIMPLE_API_TOKEN) will be looked for.
+ - Account email. If omitted, the environment variables E(DNSIMPLE_EMAIL) and E(DNSIMPLE_API_TOKEN) will be looked for.
- "If those aren't found, a C(.dnsimple) file will be looked for, see: U(https://github.com/mikemaccana/dnsimple-python#getting-started)."
- "C(.dnsimple) config files are only supported in dnsimple-python<2.0.0"
type: str
account_api_token:
description:
- - Account API token. See I(account_email) for more information.
+ - Account API token. See O(account_email) for more information.
type: str
domain:
description:
@@ -77,7 +77,7 @@ options:
solo:
description:
- Whether the record should be the only one for that record type and record name.
- - Only use with C(state) is set to C(present) on a record.
+ - Only use with O(state) is set to V(present) on a record.
type: 'bool'
default: false
sandbox:
@@ -178,7 +178,7 @@ class DNSimpleV2():
client = Client(sandbox=self.sandbox, email=self.account_email, access_token=self.account_api_token, user_agent="ansible/community.general")
else:
msg = "Option account_email or account_api_token not provided. " \
- "Dnsimple authentiction with a .dnsimple config file is not " \
+ "Dnsimple authentication with a .dnsimple config file is not " \
"supported with dnsimple-python>=2.0.0"
raise DNSimpleException(msg)
client.identity.whoami()
@@ -225,24 +225,24 @@ class DNSimpleV2():
self.client.domains.delete_domain(self.account.id, domain)
def get_records(self, zone, dnsimple_filter=None):
- """return dns ressource records which match a specified filter"""
+ """return dns resource records which match a specified filter"""
records_list = self._get_paginated_result(self.client.zones.list_records,
account_id=self.account.id,
zone=zone, filter=dnsimple_filter)
return [d.__dict__ for d in records_list]
def delete_record(self, domain, rid):
- """delete a single dns ressource record"""
+ """delete a single dns resource record"""
self.client.zones.delete_record(self.account.id, domain, rid)
def update_record(self, domain, rid, ttl=None, priority=None):
- """update a single dns ressource record"""
+ """update a single dns resource record"""
zr = ZoneRecordUpdateInput(ttl=ttl, priority=priority)
result = self.client.zones.update_record(self.account.id, str(domain), str(rid), zr).data.__dict__
return result
def create_record(self, domain, name, record_type, content, ttl=None, priority=None):
- """create a single dns ressource record"""
+ """create a single dns resource record"""
zr = ZoneRecordInput(name=name, type=record_type, content=content, ttl=ttl, priority=priority)
return self.client.zones.create_record(self.account.id, str(domain), zr).data.__dict__
diff --git a/ansible_collections/community/general/plugins/modules/dnsimple_info.py b/ansible_collections/community/general/plugins/modules/dnsimple_info.py
index 52fd53303..46c2877f7 100644
--- a/ansible_collections/community/general/plugins/modules/dnsimple_info.py
+++ b/ansible_collections/community/general/plugins/modules/dnsimple_info.py
@@ -83,7 +83,7 @@ dnsimple_domain_info:
description: Returns a list of dictionaries of all domains associated with the supplied account ID.
type: list
elements: dict
- returned: success when I(name) is not specified
+ returned: success when O(name) is not specified
sample:
- account_id: 1234
created_at: '2021-10-16T21:25:42Z'
@@ -120,7 +120,7 @@ dnsimple_records_info:
description: Returns a list of dictionaries with all records for the domain supplied.
type: list
elements: dict
- returned: success when I(name) is specified, but I(record) is not
+ returned: success when O(name) is specified, but O(record) is not
sample:
- content: ns1.dnsimple.com admin.dnsimple.com
created_at: '2021-10-16T19:07:34Z'
@@ -174,7 +174,7 @@ dnsimple_records_info:
type: str
dnsimple_record_info:
description: Returns a list of dictionaries that match the record supplied.
- returned: success when I(name) and I(record) are specified
+ returned: success when O(name) and O(record) are specified
type: list
elements: dict
sample:
@@ -239,9 +239,9 @@ with deps.declare("requests"):
def build_url(account, key, is_sandbox):
headers = {'Accept': 'application/json',
- 'Authorization': 'Bearer ' + key}
- url = 'https://api{sandbox}.dnsimple.com/'.format(
- sandbox=".sandbox" if is_sandbox else "") + 'v2/' + account
+ 'Authorization': 'Bearer {0}'.format(key)}
+ sandbox = '.sandbox' if is_sandbox else ''
+ url = 'https://api{sandbox}.dnsimple.com/v2/{account}'.format(sandbox=sandbox, account=account)
req = Request(url=url, headers=headers)
prepped_request = req.prepare()
return prepped_request
@@ -250,19 +250,21 @@ def build_url(account, key, is_sandbox):
def iterate_data(module, request_object):
base_url = request_object.url
response = Session().send(request_object)
- if 'pagination' in response.json():
- data = response.json()["data"]
- pages = response.json()["pagination"]["total_pages"]
- if int(pages) > 1:
- for page in range(1, pages):
- page = page + 1
- request_object.url = base_url + '&page=' + str(page)
- new_results = Session().send(request_object)
- data = data + new_results.json()["data"]
- return data
- else:
+ if 'pagination' not in response.json():
module.fail_json('API Call failed, check ID, key and sandbox values')
+ data = response.json()["data"]
+ total_pages = response.json()["pagination"]["total_pages"]
+ page = 1
+
+ while page < total_pages:
+ page = page + 1
+ request_object.url = '{url}&page={page}'.format(url=base_url, page=page)
+ new_results = Session().send(request_object)
+ data = data + new_results.json()['data']
+
+ return data
+
def record_info(dnsimple_mod, req_obj):
req_obj.url, req_obj.method = req_obj.url + '/zones/' + dnsimple_mod.params["name"] + '/records?name=' + dnsimple_mod.params["record"], 'GET'
diff --git a/ansible_collections/community/general/plugins/modules/dnsmadeeasy.py b/ansible_collections/community/general/plugins/modules/dnsmadeeasy.py
index 44587ca39..47d9430e7 100644
--- a/ansible_collections/community/general/plugins/modules/dnsmadeeasy.py
+++ b/ansible_collections/community/general/plugins/modules/dnsmadeeasy.py
@@ -87,14 +87,14 @@ options:
validate_certs:
description:
- - If C(false), SSL certificates will not be validated. This should only be used
+ - If V(false), SSL certificates will not be validated. This should only be used
on personally controlled sites using self-signed certificates.
type: bool
default: true
monitor:
description:
- - If C(true), add or change the monitor. This is applicable only for A records.
+ - If V(true), add or change the monitor. This is applicable only for A records.
type: bool
default: false
@@ -133,7 +133,7 @@ options:
contactList:
description:
- Name or id of the contact list that the monitor will notify.
- - The default C('') means the Account Owner.
+ - The default V('') means the Account Owner.
type: str
httpFqdn:
@@ -153,7 +153,7 @@ options:
failover:
description:
- - If C(true), add or change the failover. This is applicable only for A records.
+ - If V(true), add or change the failover. This is applicable only for A records.
type: bool
default: false
@@ -509,15 +509,15 @@ class DME2(object):
return json.dumps(data, separators=(',', ':'))
def createRecord(self, data):
- # @TODO update the cache w/ resultant record + id when impleneted
+ # @TODO update the cache w/ resultant record + id when implemented
return self.query(self.record_url, 'POST', data)
def updateRecord(self, record_id, data):
- # @TODO update the cache w/ resultant record + id when impleneted
+ # @TODO update the cache w/ resultant record + id when implemented
return self.query(self.record_url + '/' + str(record_id), 'PUT', data)
def deleteRecord(self, record_id):
- # @TODO remove record from the cache when impleneted
+ # @TODO remove record from the cache when implemented
return self.query(self.record_url + '/' + str(record_id), 'DELETE')
def getMonitor(self, record_id):
diff --git a/ansible_collections/community/general/plugins/modules/dpkg_divert.py b/ansible_collections/community/general/plugins/modules/dpkg_divert.py
index 4a1651f51..5f0d924fe 100644
--- a/ansible_collections/community/general/plugins/modules/dpkg_divert.py
+++ b/ansible_collections/community/general/plugins/modules/dpkg_divert.py
@@ -20,13 +20,13 @@ description:
- A diversion is for C(dpkg) the knowledge that only a given package
(or the local administrator) is allowed to install a file at a given
location. Other packages shipping their own version of this file will
- be forced to I(divert) it, i.e. to install it at another location. It
+ be forced to O(divert) it, that is to install it at another location. It
allows one to keep changes in a file provided by a debian package by
preventing its overwrite at package upgrade.
- This module manages diversions of debian packages files using the
C(dpkg-divert) commandline tool. It can either create or remove a
diversion for a given file, but also update an existing diversion
- to modify its I(holder) and/or its I(divert) location.
+ to modify its O(holder) and/or its O(divert) location.
extends_documentation_fragment:
- community.general.attributes
attributes:
@@ -39,14 +39,14 @@ options:
description:
- The original and absolute path of the file to be diverted or
undiverted. This path is unique, i.e. it is not possible to get
- two diversions for the same I(path).
+ two diversions for the same O(path).
required: true
type: path
state:
description:
- - When I(state=absent), remove the diversion of the specified
- I(path); when I(state=present), create the diversion if it does
- not exist, or update its package I(holder) or I(divert) location,
+ - When O(state=absent), remove the diversion of the specified
+ O(path); when O(state=present), create the diversion if it does
+ not exist, or update its package O(holder) or O(divert) location,
if it already exists.
type: str
default: present
@@ -59,31 +59,31 @@ options:
- The actual package does not have to be installed or even to exist
for its name to be valid. If not specified, the diversion is hold
by 'LOCAL', that is reserved by/for dpkg for local diversions.
- - This parameter is ignored when I(state=absent).
+ - This parameter is ignored when O(state=absent).
type: str
divert:
description:
- The location where the versions of file will be diverted.
- Default is to add suffix C(.distrib) to the file path.
- - This parameter is ignored when I(state=absent).
+ - This parameter is ignored when O(state=absent).
type: path
rename:
description:
- - Actually move the file aside (when I(state=present)) or back (when
- I(state=absent)), but only when changing the state of the diversion.
+ - Actually move the file aside (when O(state=present)) or back (when
+ O(state=absent)), but only when changing the state of the diversion.
This parameter has no effect when attempting to add a diversion that
already exists or when removing an unexisting one.
- - Unless I(force=true), renaming fails if the destination file already
+ - Unless O(force=true), renaming fails if the destination file already
exists (this lock being a dpkg-divert feature, and bypassing it being
a module feature).
type: bool
default: false
force:
description:
- - When I(rename=true) and I(force=true), renaming is performed even if
+ - When O(rename=true) and O(force=true), renaming is performed even if
the target of the renaming exists, i.e. the existing contents of the
file at this location will be lost.
- - This parameter is ignored when I(rename=false).
+ - This parameter is ignored when O(rename=false).
type: bool
default: false
requirements:
diff --git a/ansible_collections/community/general/plugins/modules/easy_install.py b/ansible_collections/community/general/plugins/modules/easy_install.py
index 564493180..2e8fc2f4f 100644
--- a/ansible_collections/community/general/plugins/modules/easy_install.py
+++ b/ansible_collections/community/general/plugins/modules/easy_install.py
@@ -14,7 +14,7 @@ DOCUMENTATION = '''
module: easy_install
short_description: Installs Python libraries
description:
- - Installs Python libraries, optionally in a I(virtualenv)
+ - Installs Python libraries, optionally in a C(virtualenv)
extends_documentation_fragment:
- community.general.attributes
attributes:
@@ -26,13 +26,13 @@ options:
name:
type: str
description:
- - A Python library name
+ - A Python library name.
required: true
virtualenv:
type: str
description:
- - an optional I(virtualenv) directory path to install into. If the
- I(virtualenv) does not exist, it is created automatically
+ - An optional O(virtualenv) directory path to install into. If the
+ O(virtualenv) does not exist, it is created automatically.
virtualenv_site_packages:
description:
- Whether the virtual environment will inherit packages from the
@@ -46,21 +46,21 @@ options:
type: str
description:
- The command to create the virtual environment with. For example
- C(pyvenv), C(virtualenv), C(virtualenv2).
+ V(pyvenv), V(virtualenv), V(virtualenv2).
default: virtualenv
executable:
type: str
description:
- The explicit executable or a pathname to the executable to be used to
run easy_install for a specific version of Python installed in the
- system. For example C(easy_install-3.3), if there are both Python 2.7
+ system. For example V(easy_install-3.3), if there are both Python 2.7
and 3.3 installations in the system and you want to run easy_install
for the Python 3.3 installation.
default: easy_install
state:
type: str
description:
- - The desired state of the library. C(latest) ensures that the latest version is installed.
+ - The desired state of the library. V(latest) ensures that the latest version is installed.
choices: [present, latest]
default: present
notes:
@@ -68,8 +68,8 @@ notes:
libraries. Thus this module is not able to remove libraries. It is
generally recommended to use the M(ansible.builtin.pip) module which you can first install
using M(community.general.easy_install).
- - Also note that I(virtualenv) must be installed on the remote host if the
- C(virtualenv) parameter is specified.
+ - Also note that C(virtualenv) must be installed on the remote host if the
+ O(virtualenv) parameter is specified.
requirements: [ "virtualenv" ]
author: "Matt Wright (@mattupstate)"
'''
diff --git a/ansible_collections/community/general/plugins/modules/ejabberd_user.py b/ansible_collections/community/general/plugins/modules/ejabberd_user.py
index 397207ae6..d0b575e1c 100644
--- a/ansible_collections/community/general/plugins/modules/ejabberd_user.py
+++ b/ansible_collections/community/general/plugins/modules/ejabberd_user.py
@@ -78,6 +78,7 @@ EXAMPLES = '''
import syslog
from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.community.general.plugins.module_utils.cmd_runner import CmdRunner, cmd_runner_fmt
class EjabberdUser(object):
@@ -85,7 +86,7 @@ class EjabberdUser(object):
object manages user creation and deletion using ejabberdctl. The following
commands are currently supported:
* ejabberdctl register
- * ejabberdctl deregister
+ * ejabberdctl unregister
"""
def __init__(self, module):
@@ -95,6 +96,17 @@ class EjabberdUser(object):
self.host = module.params.get('host')
self.user = module.params.get('username')
self.pwd = module.params.get('password')
+ self.runner = CmdRunner(
+ module,
+ command="ejabberdctl",
+ arg_formats=dict(
+ cmd=cmd_runner_fmt.as_list(),
+ host=cmd_runner_fmt.as_list(),
+ user=cmd_runner_fmt.as_list(),
+ pwd=cmd_runner_fmt.as_list(),
+ ),
+ check_rc=False,
+ )
@property
def changed(self):
@@ -102,7 +114,7 @@ class EjabberdUser(object):
changed. It will return True if the user does not match the supplied
credentials and False if it does not
"""
- return self.run_command('check_password', [self.user, self.host, self.pwd])
+ return self.run_command('check_password', 'user host pwd', (lambda rc, out, err: bool(rc)))
@property
def exists(self):
@@ -110,7 +122,7 @@ class EjabberdUser(object):
host specified. If the user exists True is returned, otherwise False
is returned
"""
- return self.run_command('check_account', [self.user, self.host])
+ return self.run_command('check_account', 'user host', (lambda rc, out, err: not bool(rc)))
def log(self, entry):
""" This method will log information to the local syslog facility """
@@ -118,29 +130,36 @@ class EjabberdUser(object):
syslog.openlog('ansible-%s' % self.module._name)
syslog.syslog(syslog.LOG_NOTICE, entry)
- def run_command(self, cmd, options):
+ def run_command(self, cmd, options, process=None):
""" This method will run the any command specified and return the
returns using the Ansible common module
"""
- cmd = [self.module.get_bin_path('ejabberdctl'), cmd] + options
- self.log('command: %s' % " ".join(cmd))
- return self.module.run_command(cmd)
+ def _proc(*a):
+ return a
+
+ if process is None:
+ process = _proc
+
+ with self.runner("cmd " + options, output_process=process) as ctx:
+ res = ctx.run(cmd=cmd, host=self.host, user=self.user, pwd=self.pwd)
+ self.log('command: %s' % " ".join(ctx.run_info['cmd']))
+ return res
def update(self):
""" The update method will update the credentials for the user provided
"""
- return self.run_command('change_password', [self.user, self.host, self.pwd])
+ return self.run_command('change_password', 'user host pwd')
def create(self):
""" The create method will create a new user on the host with the
password provided
"""
- return self.run_command('register', [self.user, self.host, self.pwd])
+ return self.run_command('register', 'user host pwd')
def delete(self):
""" The delete method will delete the user from the host
"""
- return self.run_command('unregister', [self.user, self.host])
+ return self.run_command('unregister', 'user host')
def main():
@@ -150,7 +169,7 @@ def main():
username=dict(required=True, type='str'),
password=dict(type='str', no_log=True),
state=dict(default='present', choices=['present', 'absent']),
- logging=dict(default=False, type='bool') # deprecate in favour of c.g.syslogger?
+ logging=dict(default=False, type='bool', removed_in_version='10.0.0', removed_from_collection='community.general'),
),
required_if=[
('state', 'present', ['password']),
diff --git a/ansible_collections/community/general/plugins/modules/elasticsearch_plugin.py b/ansible_collections/community/general/plugins/modules/elasticsearch_plugin.py
index cd4bb45de..92b628a74 100644
--- a/ansible_collections/community/general/plugins/modules/elasticsearch_plugin.py
+++ b/ansible_collections/community/general/plugins/modules/elasticsearch_plugin.py
@@ -69,7 +69,6 @@ options:
plugin_bin:
description:
- Location of the plugin binary. If this file is not found, the default plugin binaries will be used.
- - The default changed in Ansible 2.4 to None.
type: path
plugin_dir:
description:
diff --git a/ansible_collections/community/general/plugins/modules/emc_vnx_sg_member.py b/ansible_collections/community/general/plugins/modules/emc_vnx_sg_member.py
index 487b6feef..b06cd01de 100644
--- a/ansible_collections/community/general/plugins/modules/emc_vnx_sg_member.py
+++ b/ansible_collections/community/general/plugins/modules/emc_vnx_sg_member.py
@@ -46,8 +46,8 @@ options:
state:
description:
- Indicates the desired lunid state.
- - C(present) ensures specified lunid is present in the Storage Group.
- - C(absent) ensures specified lunid is absent from Storage Group.
+ - V(present) ensures specified lunid is present in the Storage Group.
+ - V(absent) ensures specified lunid is absent from Storage Group.
default: present
choices: [ "present", "absent"]
type: str
diff --git a/ansible_collections/community/general/plugins/modules/etcd3.py b/ansible_collections/community/general/plugins/modules/etcd3.py
index 9cd027406..2fdc3f2f8 100644
--- a/ansible_collections/community/general/plugins/modules/etcd3.py
+++ b/ansible_collections/community/general/plugins/modules/etcd3.py
@@ -61,22 +61,22 @@ options:
type: str
description:
- The password to use for authentication.
- - Required if I(user) is defined.
+ - Required if O(user) is defined.
ca_cert:
type: path
description:
- The Certificate Authority to use to verify the etcd host.
- - Required if I(client_cert) and I(client_key) are defined.
+ - Required if O(client_cert) and O(client_key) are defined.
client_cert:
type: path
description:
- PEM formatted certificate chain file to be used for SSL client authentication.
- - Required if I(client_key) is defined.
+ - Required if O(client_key) is defined.
client_key:
type: path
description:
- PEM formatted file that contains your private key to be used for SSL client authentication.
- - Required if I(client_cert) is defined.
+ - Required if O(client_cert) is defined.
timeout:
type: int
description:
diff --git a/ansible_collections/community/general/plugins/modules/facter.py b/ansible_collections/community/general/plugins/modules/facter.py
index e7cf52e20..87017246a 100644
--- a/ansible_collections/community/general/plugins/modules/facter.py
+++ b/ansible_collections/community/general/plugins/modules/facter.py
@@ -11,7 +11,7 @@ __metaclass__ = type
DOCUMENTATION = '''
---
module: facter
-short_description: Runs the discovery program I(facter) on the remote system
+short_description: Runs the discovery program C(facter) on the remote system
description:
- Runs the C(facter) discovery program
(U(https://github.com/puppetlabs/facter)) on the remote system, returning
diff --git a/ansible_collections/community/general/plugins/modules/facter_facts.py b/ansible_collections/community/general/plugins/modules/facter_facts.py
new file mode 100644
index 000000000..abc3f87eb
--- /dev/null
+++ b/ansible_collections/community/general/plugins/modules/facter_facts.py
@@ -0,0 +1,90 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2023, Alexei Znamensky
+# Copyright (c) 2012, Michael DeHaan <michael.dehaan@gmail.com>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+DOCUMENTATION = '''
+---
+module: facter_facts
+short_description: Runs the discovery program C(facter) on the remote system and return Ansible facts
+version_added: 8.0.0
+description:
+ - Runs the C(facter) discovery program
+ (U(https://github.com/puppetlabs/facter)) on the remote system, returning Ansible facts from the
+ JSON data that can be useful for inventory purposes.
+extends_documentation_fragment:
+ - community.general.attributes
+ - community.general.attributes.facts
+ - community.general.attributes.facts_module
+options:
+ arguments:
+ description:
+ - Specifies arguments for facter.
+ type: list
+ elements: str
+requirements:
+ - facter
+ - ruby-json
+author:
+ - Ansible Core Team
+ - Michael DeHaan
+'''
+
+EXAMPLES = '''
+- name: Execute facter no arguments
+ community.general.facter_facts:
+
+- name: Execute facter with arguments
+ community.general.facter_facts:
+ arguments:
+ - -p
+ - system_uptime
+ - timezone
+ - is_virtual
+'''
+
+RETURN = r'''
+ansible_facts:
+ description: Dictionary with one key C(facter).
+ returned: always
+ type: dict
+ contains:
+ facter:
+ description: Dictionary containing facts discovered in the remote system.
+ returned: always
+ type: dict
+'''
+
+import json
+
+from ansible.module_utils.basic import AnsibleModule
+
+
+def main():
+ module = AnsibleModule(
+ argument_spec=dict(
+ arguments=dict(type='list', elements='str'),
+ ),
+ supports_check_mode=True,
+ )
+
+ facter_path = module.get_bin_path(
+ 'facter',
+ opt_dirs=['/opt/puppetlabs/bin'])
+
+ cmd = [facter_path, "--json"]
+ if module.params['arguments']:
+ cmd += module.params['arguments']
+
+ rc, out, err = module.run_command(cmd, check_rc=True)
+ module.exit_json(ansible_facts=dict(facter=json.loads(out)))
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/general/plugins/modules/filesize.py b/ansible_collections/community/general/plugins/modules/filesize.py
index b3eb90d61..83de68288 100644
--- a/ansible_collections/community/general/plugins/modules/filesize.py
+++ b/ansible_collections/community/general/plugins/modules/filesize.py
@@ -41,20 +41,20 @@ options:
description:
- Requested size of the file.
- The value is a number (either C(int) or C(float)) optionally followed
- by a multiplicative suffix, that can be one of C(B) (bytes), C(KB) or
- C(kB) (= 1000B), C(MB) or C(mB) (= 1000kB), C(GB) or C(gB) (= 1000MB),
- and so on for C(T), C(P), C(E), C(Z) and C(Y); or alternatively one of
- C(K), C(k) or C(KiB) (= 1024B); C(M), C(m) or C(MiB) (= 1024KiB);
- C(G), C(g) or C(GiB) (= 1024MiB); and so on.
+ by a multiplicative suffix, that can be one of V(B) (bytes), V(KB) or
+ V(kB) (= 1000B), V(MB) or V(mB) (= 1000kB), V(GB) or V(gB) (= 1000MB),
+ and so on for V(T), V(P), V(E), V(Z) and V(Y); or alternatively one of
+ V(K), V(k) or V(KiB) (= 1024B); V(M), V(m) or V(MiB) (= 1024KiB);
+ V(G), V(g) or V(GiB) (= 1024MiB); and so on.
- If the multiplicative suffix is not provided, the value is treated as
- an integer number of blocks of I(blocksize) bytes each (float values
+ an integer number of blocks of O(blocksize) bytes each (float values
are rounded to the closest integer).
- - When the I(size) value is equal to the current file size, does nothing.
- - When the I(size) value is bigger than the current file size, bytes from
- I(source) (if I(sparse) is not C(false)) are appended to the file
+ - When the O(size) value is equal to the current file size, does nothing.
+ - When the O(size) value is bigger than the current file size, bytes from
+ O(source) (if O(sparse) is not V(false)) are appended to the file
without truncating it, in other words, without modifying the existing
bytes of the file.
- - When the I(size) value is smaller than the current file size, it is
+ - When the O(size) value is smaller than the current file size, it is
truncated to the requested value without modifying bytes before this
value.
- That means that a file of any arbitrary size can be grown to any other
@@ -65,24 +65,24 @@ options:
blocksize:
description:
- Size of blocks, in bytes if not followed by a multiplicative suffix.
- - The numeric value (before the unit) C(MUST) be an integer (or a C(float)
+ - The numeric value (before the unit) B(MUST) be an integer (or a C(float)
if it equals an integer).
- If not set, the size of blocks is guessed from the OS and commonly
- results in C(512) or C(4096) bytes, that is used internally by the
- module or when I(size) has no unit.
+ results in V(512) or V(4096) bytes, that is used internally by the
+ module or when O(size) has no unit.
type: raw
source:
description:
- Device or file that provides input data to provision the file.
- - This parameter is ignored when I(sparse=true).
+ - This parameter is ignored when O(sparse=true).
type: path
default: /dev/zero
force:
description:
- Whether or not to overwrite the file if it exists, in other words, to
- truncate it from 0. When C(true), the module is not idempotent, that
- means it always reports I(changed=true).
- - I(force=true) and I(sparse=true) are mutually exclusive.
+ truncate it from 0. When V(true), the module is not idempotent, that
+ means it always reports C(changed=true).
+ - O(force=true) and O(sparse=true) are mutually exclusive.
type: bool
default: false
sparse:
@@ -91,7 +91,7 @@ options:
- This option is effective only on newly created files, or when growing a
file, only for the bytes to append.
- This option is not supported on OSes or filesystems not supporting sparse files.
- - I(force=true) and I(sparse=true) are mutually exclusive.
+ - O(force=true) and O(sparse=true) are mutually exclusive.
type: bool
default: false
unsafe_writes:
@@ -206,7 +206,7 @@ filesize:
type: int
sample: 1024
bytes:
- description: Size of the file, in bytes, as the product of C(blocks) and C(blocksize).
+ description: Size of the file, in bytes, as the product of RV(filesize.blocks) and RV(filesize.blocksize).
type: int
sample: 512000
iec:
diff --git a/ansible_collections/community/general/plugins/modules/filesystem.py b/ansible_collections/community/general/plugins/modules/filesystem.py
index 0e6b815b4..ec361245b 100644
--- a/ansible_collections/community/general/plugins/modules/filesystem.py
+++ b/ansible_collections/community/general/plugins/modules/filesystem.py
@@ -29,12 +29,12 @@ attributes:
options:
state:
description:
- - If I(state=present), the filesystem is created if it doesn't already
- exist, that is the default behaviour if I(state) is omitted.
- - If I(state=absent), filesystem signatures on I(dev) are wiped if it
+ - If O(state=present), the filesystem is created if it doesn't already
+ exist, that is the default behaviour if O(state) is omitted.
+ - If O(state=absent), filesystem signatures on O(dev) are wiped if it
contains a filesystem (as known by C(blkid)).
- - When I(state=absent), all other options but I(dev) are ignored, and the
- module doesn't fail if the device I(dev) doesn't actually exist.
+ - When O(state=absent), all other options but O(dev) are ignored, and the
+ module does not fail if the device O(dev) doesn't actually exist.
type: str
choices: [ present, absent ]
default: present
@@ -43,7 +43,7 @@ options:
choices: [ btrfs, ext2, ext3, ext4, ext4dev, f2fs, lvm, ocfs2, reiserfs, xfs, vfat, swap, ufs ]
description:
- Filesystem type to be created. This option is required with
- I(state=present) (or if I(state) is omitted).
+ O(state=present) (or if O(state) is omitted).
- ufs support has been added in community.general 3.4.0.
type: str
aliases: [type]
@@ -53,50 +53,68 @@ options:
regular file (both).
- When setting Linux-specific filesystem types on FreeBSD, this module
only works when applying to regular files, aka disk images.
- - Currently C(lvm) (Linux-only) and C(ufs) (FreeBSD-only) don't support
- a regular file as their target I(dev).
+ - Currently V(lvm) (Linux-only) and V(ufs) (FreeBSD-only) do not support
+ a regular file as their target O(dev).
- Support for character devices on FreeBSD has been added in community.general 3.4.0.
type: path
required: true
aliases: [device]
force:
description:
- - If C(true), allows to create new filesystem on devices that already has filesystem.
+ - If V(true), allows to create new filesystem on devices that already has filesystem.
type: bool
default: false
resizefs:
description:
- - If C(true), if the block device and filesystem size differ, grow the filesystem into the space.
+ - If V(true), if the block device and filesystem size differ, grow the filesystem into the space.
- Supported for C(btrfs), C(ext2), C(ext3), C(ext4), C(ext4dev), C(f2fs), C(lvm), C(xfs), C(ufs) and C(vfat) filesystems.
Attempts to resize other filesystem types will fail.
- XFS Will only grow if mounted. Currently, the module is based on commands
from C(util-linux) package to perform operations, so resizing of XFS is
not supported on FreeBSD systems.
- vFAT will likely fail if C(fatresize < 1.04).
+ - Mutually exclusive with O(uuid).
type: bool
default: false
opts:
description:
- List of options to be passed to C(mkfs) command.
type: str
+ uuid:
+ description:
+ - Set filesystem's UUID to the given value.
+ - The UUID options specified in O(opts) take precedence over this value.
+ - See xfs_admin(8) (C(xfs)), tune2fs(8) (C(ext2), C(ext3), C(ext4), C(ext4dev)) for possible values.
+ - For O(fstype=lvm) the value is ignored, it resets the PV UUID if set.
+ - Supported for O(fstype) being one of C(ext2), C(ext3), C(ext4), C(ext4dev), C(lvm), or C(xfs).
+ - This is B(not idempotent). Specifying this option will always result in a change.
+ - Mutually exclusive with O(resizefs).
+ type: str
+ version_added: 7.1.0
requirements:
- - Uses specific tools related to the I(fstype) for creating or resizing a
+ - Uses specific tools related to the O(fstype) for creating or resizing a
filesystem (from packages e2fsprogs, xfsprogs, dosfstools, and so on).
- Uses generic tools mostly related to the Operating System (Linux or
FreeBSD) or available on both, as C(blkid).
- On FreeBSD, either C(util-linux) or C(e2fsprogs) package is required.
notes:
- - Potential filesystems on I(dev) are checked using C(blkid). In case C(blkid)
+ - Potential filesystems on O(dev) are checked using C(blkid). In case C(blkid)
is unable to detect a filesystem (and in case C(fstyp) on FreeBSD is also
unable to detect a filesystem), this filesystem is overwritten even if
- I(force) is C(false).
+ O(force) is V(false).
- On FreeBSD systems, both C(e2fsprogs) and C(util-linux) packages provide
a C(blkid) command that is compatible with this module. However, these
packages conflict with each other, and only the C(util-linux) package
- provides the command required to not fail when I(state=absent).
+ provides the command required to not fail when O(state=absent).
seealso:
- module: community.general.filesize
- module: ansible.posix.mount
+ - name: xfs_admin(8) manpage for Linux
+ description: Manual page of the GNU/Linux's xfs_admin implementation
+ link: https://man7.org/linux/man-pages/man8/xfs_admin.8.html
+ - name: tune2fs(8) manpage for Linux
+ description: Manual page of the GNU/Linux's tune2fs implementation
+ link: https://man7.org/linux/man-pages/man8/tune2fs.8.html
'''
EXAMPLES = '''
@@ -120,6 +138,24 @@ EXAMPLES = '''
community.general.filesystem:
dev: /path/to/disk.img
fstype: vfat
+
+- name: Reset an xfs filesystem UUID on /dev/sdb1
+ community.general.filesystem:
+ fstype: xfs
+ dev: /dev/sdb1
+ uuid: generate
+
+- name: Reset an ext4 filesystem UUID on /dev/sdb1
+ community.general.filesystem:
+ fstype: ext4
+ dev: /dev/sdb1
+ uuid: random
+
+- name: Reset an LVM filesystem (PV) UUID on /dev/sdc
+ community.general.filesystem:
+ fstype: lvm
+ dev: /dev/sdc
+ uuid: random
'''
import os
@@ -178,10 +214,15 @@ class Filesystem(object):
MKFS = None
MKFS_FORCE_FLAGS = []
+ MKFS_SET_UUID_OPTIONS = None
+ MKFS_SET_UUID_EXTRA_OPTIONS = []
INFO = None
GROW = None
GROW_MAX_SPACE_FLAGS = []
GROW_MOUNTPOINT_ONLY = False
+ CHANGE_UUID = None
+ CHANGE_UUID_OPTION = None
+ CHANGE_UUID_OPTION_HAS_ARG = True
LANG_ENV = {'LANG': 'C', 'LC_ALL': 'C', 'LC_MESSAGES': 'C'}
@@ -200,13 +241,19 @@ class Filesystem(object):
"""
raise NotImplementedError()
- def create(self, opts, dev):
+ def create(self, opts, dev, uuid=None):
if self.module.check_mode:
return
+ if uuid and self.MKFS_SET_UUID_OPTIONS:
+ if not (set(self.MKFS_SET_UUID_OPTIONS) & set(opts)):
+ opts += [self.MKFS_SET_UUID_OPTIONS[0], uuid] + self.MKFS_SET_UUID_EXTRA_OPTIONS
+
mkfs = self.module.get_bin_path(self.MKFS, required=True)
cmd = [mkfs] + self.MKFS_FORCE_FLAGS + opts + [str(dev)]
self.module.run_command(cmd, check_rc=True)
+ if uuid and self.CHANGE_UUID and self.MKFS_SET_UUID_OPTIONS is None:
+ self.change_uuid(new_uuid=uuid, dev=dev)
def wipefs(self, dev):
if self.module.check_mode:
@@ -255,11 +302,31 @@ class Filesystem(object):
dummy, out, dummy = self.module.run_command(self.grow_cmd(grow_target), check_rc=True)
return out
+ def change_uuid_cmd(self, new_uuid, target):
+ """Build and return the UUID change command line as list."""
+ cmdline = [self.module.get_bin_path(self.CHANGE_UUID, required=True)]
+ if self.CHANGE_UUID_OPTION_HAS_ARG:
+ cmdline += [self.CHANGE_UUID_OPTION, new_uuid, target]
+ else:
+ cmdline += [self.CHANGE_UUID_OPTION, target]
+ return cmdline
+
+ def change_uuid(self, new_uuid, dev):
+ """Change filesystem UUID. Returns stdout of used command"""
+ if self.module.check_mode:
+ self.module.exit_json(change=True, msg='Changing %s filesystem UUID on device %s' % (self.fstype, dev))
+
+ dummy, out, dummy = self.module.run_command(self.change_uuid_cmd(new_uuid=new_uuid, target=str(dev)), check_rc=True)
+ return out
+
class Ext(Filesystem):
MKFS_FORCE_FLAGS = ['-F']
+ MKFS_SET_UUID_OPTIONS = ['-U']
INFO = 'tune2fs'
GROW = 'resize2fs'
+ CHANGE_UUID = 'tune2fs'
+ CHANGE_UUID_OPTION = "-U"
def get_fs_size(self, dev):
"""Get Block count and Block size and return their product."""
@@ -298,6 +365,8 @@ class XFS(Filesystem):
INFO = 'xfs_info'
GROW = 'xfs_growfs'
GROW_MOUNTPOINT_ONLY = True
+ CHANGE_UUID = "xfs_admin"
+ CHANGE_UUID_OPTION = "-U"
def get_fs_size(self, dev):
"""Get bsize and blocks and return their product."""
@@ -451,8 +520,13 @@ class VFAT(Filesystem):
class LVM(Filesystem):
MKFS = 'pvcreate'
MKFS_FORCE_FLAGS = ['-f']
+ MKFS_SET_UUID_OPTIONS = ['-u', '--uuid']
+ MKFS_SET_UUID_EXTRA_OPTIONS = ['--norestorefile']
INFO = 'pvs'
GROW = 'pvresize'
+ CHANGE_UUID = 'pvchange'
+ CHANGE_UUID_OPTION = '-u'
+ CHANGE_UUID_OPTION_HAS_ARG = False
def get_fs_size(self, dev):
"""Get and return PV size, in bytes."""
@@ -525,10 +599,14 @@ def main():
opts=dict(type='str'),
force=dict(type='bool', default=False),
resizefs=dict(type='bool', default=False),
+ uuid=dict(type='str', required=False),
),
required_if=[
('state', 'present', ['fstype'])
],
+ mutually_exclusive=[
+ ('resizefs', 'uuid'),
+ ],
supports_check_mode=True,
)
@@ -538,6 +616,7 @@ def main():
opts = module.params['opts']
force = module.params['force']
resizefs = module.params['resizefs']
+ uuid = module.params['uuid']
mkfs_opts = []
if opts is not None:
@@ -576,21 +655,30 @@ def main():
filesystem = klass(module)
+ if uuid and not (filesystem.CHANGE_UUID or filesystem.MKFS_SET_UUID_OPTIONS):
+ module.fail_json(changed=False, msg="module does not support UUID option for this filesystem (%s) yet." % fstype)
+
same_fs = fs and FILESYSTEMS.get(fs) == FILESYSTEMS[fstype]
- if same_fs and not resizefs and not force:
+ if same_fs and not resizefs and not uuid and not force:
module.exit_json(changed=False)
- elif same_fs and resizefs:
- if not filesystem.GROW:
- module.fail_json(changed=False, msg="module does not support resizing %s filesystem yet." % fstype)
+ elif same_fs:
+ if resizefs:
+ if not filesystem.GROW:
+ module.fail_json(changed=False, msg="module does not support resizing %s filesystem yet." % fstype)
+
+ out = filesystem.grow(dev)
+
+ module.exit_json(changed=True, msg=out)
+ elif uuid:
- out = filesystem.grow(dev)
+ out = filesystem.change_uuid(new_uuid=uuid, dev=dev)
- module.exit_json(changed=True, msg=out)
+ module.exit_json(changed=True, msg=out)
elif fs and not force:
module.fail_json(msg="'%s' is already used as %s, use force=true to overwrite" % (dev, fs), rc=rc, err=err)
# create fs
- filesystem.create(mkfs_opts, dev)
+ filesystem.create(opts=mkfs_opts, dev=dev, uuid=uuid)
changed = True
elif fs:
diff --git a/ansible_collections/community/general/plugins/modules/flatpak.py b/ansible_collections/community/general/plugins/modules/flatpak.py
index 40a13736f..80dbabdfa 100644
--- a/ansible_collections/community/general/plugins/modules/flatpak.py
+++ b/ansible_collections/community/general/plugins/modules/flatpak.py
@@ -39,8 +39,8 @@ options:
method:
description:
- The installation method to use.
- - Defines if the I(flatpak) is supposed to be installed globally for the whole C(system)
- or only for the current C(user).
+ - Defines if the C(flatpak) is supposed to be installed globally for the whole V(system)
+ or only for the current V(user).
type: str
choices: [ system, user ]
default: system
@@ -48,14 +48,14 @@ options:
description:
- The name of the flatpak to manage. To operate on several packages this
can accept a list of packages.
- - When used with I(state=present), I(name) can be specified as a URL to a
+ - When used with O(state=present), O(name) can be specified as a URL to a
C(flatpakref) file or the unique reverse DNS name that identifies a flatpak.
- Both C(https://) and C(http://) URLs are supported.
- - When supplying a reverse DNS name, you can use the I(remote) option to specify on what remote
+ - When supplying a reverse DNS name, you can use the O(remote) option to specify on what remote
to look for the flatpak. An example for a reverse DNS name is C(org.gnome.gedit).
- - When used with I(state=absent), it is recommended to specify the name in the reverse DNS
+ - When used with O(state=absent), it is recommended to specify the name in the reverse DNS
format.
- - When supplying a URL with I(state=absent), the module will try to match the
+ - When supplying a URL with O(state=absent), the module will try to match the
installed flatpak based on the name of the flatpakref to remove it. However, there is no
guarantee that the names of the flatpakref file and the reverse DNS name of the installed
flatpak do match.
@@ -74,7 +74,7 @@ options:
remote:
description:
- The flatpak remote (repository) to install the flatpak from.
- - By default, C(flathub) is assumed, but you do need to add the flathub flatpak_remote before
+ - By default, V(flathub) is assumed, but you do need to add the flathub flatpak_remote before
you can use this.
- See the M(community.general.flatpak_remote) module for managing flatpak remotes.
type: str
diff --git a/ansible_collections/community/general/plugins/modules/flatpak_remote.py b/ansible_collections/community/general/plugins/modules/flatpak_remote.py
index 9c097c411..a4eb3ea27 100644
--- a/ansible_collections/community/general/plugins/modules/flatpak_remote.py
+++ b/ansible_collections/community/general/plugins/modules/flatpak_remote.py
@@ -18,7 +18,7 @@ description:
- Allows users to add or remove flatpak remotes.
- The flatpak remotes concept is comparable to what is called repositories in other packaging
formats.
- - Currently, remote addition is only supported via I(flatpakrepo) file URLs.
+ - Currently, remote addition is only supported via C(flatpakrepo) file URLs.
- Existing remotes will not be updated.
- See the M(community.general.flatpak) module for managing flatpaks.
author:
@@ -42,26 +42,26 @@ options:
default: flatpak
flatpakrepo_url:
description:
- - The URL to the I(flatpakrepo) file representing the repository remote to add.
- - When used with I(state=present), the flatpak remote specified under the I(flatpakrepo_url)
- is added using the specified installation C(method).
- - When used with I(state=absent), this is not required.
- - Required when I(state=present).
+ - The URL to the C(flatpakrepo) file representing the repository remote to add.
+ - When used with O(state=present), the flatpak remote specified under the O(flatpakrepo_url)
+ is added using the specified installation O(method).
+ - When used with O(state=absent), this is not required.
+ - Required when O(state=present).
type: str
method:
description:
- The installation method to use.
- - Defines if the I(flatpak) is supposed to be installed globally for the whole C(system)
- or only for the current C(user).
+ - Defines if the C(flatpak) is supposed to be installed globally for the whole V(system)
+ or only for the current V(user).
type: str
choices: [ system, user ]
default: system
name:
description:
- The desired name for the flatpak remote to be registered under on the managed host.
- - When used with I(state=present), the remote will be added to the managed host under
- the specified I(name).
- - When used with I(state=absent) the remote with that name will be removed.
+ - When used with O(state=present), the remote will be added to the managed host under
+ the specified O(name).
+ - When used with O(state=absent) the remote with that name will be removed.
type: str
required: true
state:
diff --git a/ansible_collections/community/general/plugins/modules/flowdock.py b/ansible_collections/community/general/plugins/modules/flowdock.py
index c78716ba4..0e8a7461d 100644
--- a/ansible_collections/community/general/plugins/modules/flowdock.py
+++ b/ansible_collections/community/general/plugins/modules/flowdock.py
@@ -11,6 +11,12 @@ __metaclass__ = type
DOCUMENTATION = '''
---
+
+deprecated:
+ removed_in: 9.0.0
+ why: the endpoints this module relies on do not exist any more and do not resolve to IPs in DNS.
+ alternative: no known alternative at this point
+
module: flowdock
author: "Matt Coddington (@mcodd)"
short_description: Send a message to a flowdock
@@ -87,7 +93,7 @@ options:
required: false
validate_certs:
description:
- - If C(false), SSL certificates will not be validated. This should only be used
+ - If V(false), SSL certificates will not be validated. This should only be used
on personally controlled sites using self-signed certificates.
required: false
default: true
diff --git a/ansible_collections/community/general/plugins/modules/gandi_livedns.py b/ansible_collections/community/general/plugins/modules/gandi_livedns.py
index cc9dd630b..fdb7993a5 100644
--- a/ansible_collections/community/general/plugins/modules/gandi_livedns.py
+++ b/ansible_collections/community/general/plugins/modules/gandi_livedns.py
@@ -44,7 +44,7 @@ options:
ttl:
description:
- The TTL to give the new record.
- - Required when I(state=present).
+ - Required when O(state=present).
type: int
type:
description:
@@ -54,7 +54,7 @@ options:
values:
description:
- The record values.
- - Required when I(state=present).
+ - Required when O(state=present).
type: list
elements: str
domain:
diff --git a/ansible_collections/community/general/plugins/modules/gconftool2.py b/ansible_collections/community/general/plugins/modules/gconftool2.py
index 949e92b30..a40304a16 100644
--- a/ansible_collections/community/general/plugins/modules/gconftool2.py
+++ b/ansible_collections/community/general/plugins/modules/gconftool2.py
@@ -35,20 +35,20 @@ options:
type: str
description:
- Preference keys typically have simple values such as strings,
- integers, or lists of strings and integers. This is ignored if the state
- is "get". See man gconftool-2(1).
+ integers, or lists of strings and integers.
+ This is ignored unless O(state=present). See man gconftool-2(1).
value_type:
type: str
description:
- - The type of value being set. This is ignored if the state is "get".
+ - The type of value being set.
+ This is ignored unless O(state=present). See man gconftool-2(1).
choices: [ bool, float, int, string ]
state:
type: str
description:
- The action to take upon the key/value.
- - State C(get) is deprecated and will be removed in community.general 8.0.0. Please use the module M(community.general.gconftool2_info) instead.
required: true
- choices: [ absent, get, present ]
+ choices: [ absent, present ]
config_source:
type: str
description:
@@ -56,8 +56,8 @@ options:
See man gconftool-2(1).
direct:
description:
- - Access the config database directly, bypassing server. If direct is
- specified then the config_source must be specified as well.
+ - Access the config database directly, bypassing server. If O(direct) is
+ specified then the O(config_source) must be specified as well.
See man gconftool-2(1).
type: bool
default: false
@@ -73,17 +73,26 @@ EXAMPLES = """
RETURN = '''
key:
- description: The key specified in the module parameters
+ description: The key specified in the module parameters.
returned: success
type: str
sample: /desktop/gnome/interface/font_name
value_type:
- description: The type of the value that was changed
+ description: The type of the value that was changed.
returned: success
type: str
sample: string
value:
- description: The value of the preference key after executing the module
+ description:
+ - The value of the preference key after executing the module or V(null) if key is removed.
+ - From community.general 7.0.0 onwards it returns V(null) for a non-existent O(key), and returned V("") before that.
+ returned: success
+ type: str
+ sample: "Serif 12"
+ previous_value:
+ description:
+ - The value of the preference key before executing the module.
+ - From community.general 7.0.0 onwards it returns V(null) for a non-existent O(key), and returned V("") before that.
returned: success
type: str
sample: "Serif 12"
@@ -95,7 +104,6 @@ from ansible_collections.community.general.plugins.module_utils.gconftool2 impor
class GConftool(StateModuleHelper):
- change_params = ('value', )
diff_params = ('value', )
output_params = ('key', 'value_type')
facts_params = ('key', 'value_type')
@@ -105,13 +113,12 @@ class GConftool(StateModuleHelper):
key=dict(type='str', required=True, no_log=False),
value_type=dict(type='str', choices=['bool', 'float', 'int', 'string']),
value=dict(type='str'),
- state=dict(type='str', required=True, choices=['absent', 'get', 'present']),
+ state=dict(type='str', required=True, choices=['absent', 'present']),
direct=dict(type='bool', default=False),
config_source=dict(type='str'),
),
required_if=[
('state', 'present', ['value', 'value_type']),
- ('state', 'absent', ['value']),
('direct', True, ['config_source']),
],
supports_check_mode=True,
@@ -125,6 +132,7 @@ class GConftool(StateModuleHelper):
self.vars.set('previous_value', self._get(), fact=True)
self.vars.set('value_type', self.vars.value_type)
+ self.vars.set('_value', self.vars.previous_value, output=False, change=True)
self.vars.set_meta('value', initial_value=self.vars.previous_value)
self.vars.set('playbook_value', self.vars.value, fact=True)
@@ -132,27 +140,29 @@ class GConftool(StateModuleHelper):
def process(rc, out, err):
if err and fail_on_err:
self.ansible.fail_json(msg='gconftool-2 failed with error: %s' % (str(err)))
- self.vars.value = out.rstrip()
+ out = out.rstrip()
+ self.vars.value = None if out == "" else out
return self.vars.value
return process
def _get(self):
return self.runner("state key", output_process=self._make_process(False)).run(state="get")
- def state_get(self):
- self.deprecate(
- msg="State 'get' is deprecated. Please use the module community.general.gconftool2_info instead",
- version="8.0.0", collection_name="community.general"
- )
-
def state_absent(self):
with self.runner("state key", output_process=self._make_process(False)) as ctx:
ctx.run()
+ if self.verbosity >= 4:
+ self.vars.run_info = ctx.run_info
self.vars.set('new_value', None, fact=True)
+ self.vars._value = None
def state_present(self):
with self.runner("direct config_source value_type state key value", output_process=self._make_process(True)) as ctx:
- self.vars.set('new_value', ctx.run(), fact=True)
+ ctx.run()
+ if self.verbosity >= 4:
+ self.vars.run_info = ctx.run_info
+ self.vars.set('new_value', self._get(), fact=True)
+ self.vars._value = self.vars.new_value
def main():
diff --git a/ansible_collections/community/general/plugins/modules/gem.py b/ansible_collections/community/general/plugins/modules/gem.py
index 4bc99d39e..f51e3350d 100644
--- a/ansible_collections/community/general/plugins/modules/gem.py
+++ b/ansible_collections/community/general/plugins/modules/gem.py
@@ -31,7 +31,7 @@ options:
state:
type: str
description:
- - The desired state of the gem. C(latest) ensures that the latest version is installed.
+ - The desired state of the gem. V(latest) ensures that the latest version is installed.
required: false
choices: [present, absent, latest]
default: present
@@ -80,7 +80,7 @@ options:
default: true
description:
- Avoid loading any C(.gemrc) file. Ignored for RubyGems prior to 2.5.2.
- - The default changed from C(false) to C(true) in community.general 6.0.0.
+ - The default changed from V(false) to V(true) in community.general 6.0.0.
version_added: 3.3.0
env_shebang:
description:
diff --git a/ansible_collections/community/general/plugins/modules/gio_mime.py b/ansible_collections/community/general/plugins/modules/gio_mime.py
new file mode 100644
index 000000000..27f90581e
--- /dev/null
+++ b/ansible_collections/community/general/plugins/modules/gio_mime.py
@@ -0,0 +1,108 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright (c) 2022, Alexei Znamensky <russoz@gmail.com>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+DOCUMENTATION = '''
+module: gio_mime
+author:
+ - "Alexei Znamensky (@russoz)"
+short_description: Set default handler for MIME type, for applications using Gnome GIO
+version_added: 7.5.0
+description:
+ - This module allows configuring the default handler for a specific MIME type, to be used by applications built with th Gnome GIO API.
+extends_documentation_fragment:
+ - community.general.attributes
+attributes:
+ check_mode:
+ support: full
+ diff_mode:
+ support: full
+options:
+ mime_type:
+ description:
+ - MIME type for which a default handler will be set.
+ type: str
+ required: true
+ handler:
+ description:
+ - Default handler will be set for the MIME type.
+ type: str
+ required: true
+notes:
+ - This module is a thin wrapper around the C(gio mime) command (and subcommand).
+ - See man gio(1) for more details.
+seealso:
+ - name: GIO Documentation
+ description: Reference documentation for the GIO API..
+ link: https://docs.gtk.org/gio/
+'''
+
+EXAMPLES = """
+- name: Set chrome as the default handler for https
+ community.general.gio_mime:
+ mime_type: x-scheme-handler/https
+ handler: google-chrome.desktop
+ register: result
+"""
+
+RETURN = '''
+ handler:
+ description:
+ - The handler set as default.
+ returned: success
+ type: str
+ sample: google-chrome.desktop
+ stdout:
+ description:
+ - The output of the C(gio) command.
+ returned: success
+ type: str
+ sample: Set google-chrome.desktop as the default for x-scheme-handler/https
+ stderr:
+ description:
+ - The error output of the C(gio) command.
+ returned: failure
+ type: str
+ sample: 'gio: Failed to load info for handler "never-existed.desktop"'
+'''
+
+from ansible_collections.community.general.plugins.module_utils.module_helper import ModuleHelper
+from ansible_collections.community.general.plugins.module_utils.gio_mime import gio_mime_runner, gio_mime_get
+
+
+class GioMime(ModuleHelper):
+ output_params = ['handler']
+ module = dict(
+ argument_spec=dict(
+ mime_type=dict(type='str', required=True),
+ handler=dict(type='str', required=True),
+ ),
+ supports_check_mode=True,
+ )
+
+ def __init_module__(self):
+ self.runner = gio_mime_runner(self.module, check_rc=True)
+ self.vars.set_meta("handler", initial_value=gio_mime_get(self.runner, self.vars.mime_type), diff=True, change=True)
+
+ def __run__(self):
+ check_mode_return = (0, 'Module executed in check mode', '')
+ if self.vars.has_changed("handler"):
+ with self.runner.context(args_order=["mime_type", "handler"], check_mode_skip=True, check_mode_return=check_mode_return) as ctx:
+ rc, out, err = ctx.run()
+ self.vars.stdout = out
+ self.vars.stderr = err
+ if self.verbosity >= 4:
+ self.vars.run_info = ctx.run_info
+
+
+def main():
+ GioMime.execute()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/general/plugins/modules/git_config.py b/ansible_collections/community/general/plugins/modules/git_config.py
index d67312174..a8d2ebe97 100644
--- a/ansible_collections/community/general/plugins/modules/git_config.py
+++ b/ansible_collections/community/general/plugins/modules/git_config.py
@@ -20,7 +20,7 @@ author:
requirements: ['git']
short_description: Read and write git configuration
description:
- - The C(git_config) module changes git configuration by invoking 'git config'.
+ - The M(community.general.git_config) module changes git configuration by invoking C(git config).
This is needed if you do not want to use M(ansible.builtin.template) for the entire git
config file (for example because you need to change just C(user.email) in
/etc/.git/config). Solutions involving M(ansible.builtin.command) are cumbersome or
@@ -35,7 +35,7 @@ attributes:
options:
list_all:
description:
- - List all settings (optionally limited to a given I(scope)).
+ - List all settings (optionally limited to a given O(scope)).
type: bool
default: false
name:
@@ -50,23 +50,23 @@ options:
type: path
file:
description:
- - Path to an adhoc git configuration file to be managed using the C(file) scope.
+ - Path to an adhoc git configuration file to be managed using the V(file) scope.
type: path
version_added: 2.0.0
scope:
description:
- Specify which scope to read/set values from.
- This is required when setting config values.
- - If this is set to C(local), you must also specify the C(repo) parameter.
- - If this is set to C(file), you must also specify the C(file) parameter.
- - It defaults to system only when not using I(list_all)=C(true).
+ - If this is set to V(local), you must also specify the O(repo) parameter.
+ - If this is set to V(file), you must also specify the O(file) parameter.
+ - It defaults to system only when not using O(list_all=true).
choices: [ "file", "local", "global", "system" ]
type: str
state:
description:
- "Indicates the setting should be set/unset.
- This parameter has higher precedence than I(value) parameter:
- when I(state)=absent and I(value) is defined, I(value) is discarded."
+ This parameter has higher precedence than O(value) parameter:
+ when O(state=absent) and O(value) is defined, O(value) is discarded."
choices: [ 'present', 'absent' ]
default: 'present'
type: str
@@ -75,6 +75,16 @@ options:
- When specifying the name of a single setting, supply a value to
set that setting to the given value.
type: str
+ add_mode:
+ description:
+ - Specify if a value should replace the existing value(s) or if the new
+ value should be added alongside other values with the same name.
+ - This option is only relevant when adding/replacing values. If O(state=absent) or
+ values are just read out, this option is not considered.
+ choices: [ "add", "replace-all" ]
+ type: str
+ default: "replace-all"
+ version_added: 8.1.0
'''
EXAMPLES = '''
@@ -118,6 +128,15 @@ EXAMPLES = '''
name: color.ui
value: auto
+- name: Add several options for the same name
+ community.general.git_config:
+ name: push.pushoption
+ value: "{{ item }}"
+ add_mode: add
+ loop:
+ - merge_request.create
+ - merge_request.draft
+
- name: Make etckeeper not complaining when it is invoked by cron
community.general.git_config:
name: user.email
@@ -152,13 +171,13 @@ EXAMPLES = '''
RETURN = '''
---
config_value:
- description: When I(list_all=false) and value is not set, a string containing the value of the setting in name
+ description: When O(list_all=false) and value is not set, a string containing the value of the setting in name
returned: success
type: str
sample: "vim"
config_values:
- description: When I(list_all=true), a dict containing key/value pairs of multiple configuration settings
+ description: When O(list_all=true), a dict containing key/value pairs of multiple configuration settings
returned: success
type: dict
sample:
@@ -178,6 +197,7 @@ def main():
name=dict(type='str'),
repo=dict(type='path'),
file=dict(type='path'),
+ add_mode=dict(required=False, type='str', default='replace-all', choices=['add', 'replace-all']),
scope=dict(required=False, type='str', choices=['file', 'local', 'global', 'system']),
state=dict(required=False, type='str', default='present', choices=['present', 'absent']),
value=dict(required=False),
@@ -197,94 +217,118 @@ def main():
# Set the locale to C to ensure consistent messages.
module.run_command_environ_update = dict(LANG='C', LC_ALL='C', LC_MESSAGES='C', LC_CTYPE='C')
- if params['name']:
- name = params['name']
- else:
- name = None
+ name = params['name'] or ''
+ unset = params['state'] == 'absent'
+ new_value = params['value'] or ''
+ add_mode = params['add_mode']
- if params['scope']:
- scope = params['scope']
- elif params['list_all']:
- scope = None
- else:
- scope = 'system'
+ scope = determine_scope(params)
+ cwd = determine_cwd(scope, params)
- if params['state'] == 'absent':
- unset = 'unset'
- params['value'] = None
- else:
- unset = None
-
- if params['value']:
- new_value = params['value']
- else:
- new_value = None
+ base_args = [git_path, "config", "--includes"]
- args = [git_path, "config", "--includes"]
- if params['list_all']:
- args.append('-l')
if scope == 'file':
- args.append('-f')
- args.append(params['file'])
+ base_args.append('-f')
+ base_args.append(params['file'])
elif scope:
- args.append("--" + scope)
+ base_args.append("--" + scope)
+
+ list_args = list(base_args)
+
+ if params['list_all']:
+ list_args.append('-l')
+
if name:
- args.append(name)
+ list_args.append("--get-all")
+ list_args.append(name)
- if scope == 'local':
- dir = params['repo']
- elif params['list_all'] and params['repo']:
- # Include local settings from a specific repo when listing all available settings
- dir = params['repo']
- else:
- # Run from root directory to avoid accidentally picking up any local config settings
- dir = "/"
+ (rc, out, err) = module.run_command(list_args, cwd=cwd, expand_user_and_vars=False)
- (rc, out, err) = module.run_command(args, cwd=dir, expand_user_and_vars=False)
if params['list_all'] and scope and rc == 128 and 'unable to read config file' in err:
# This just means nothing has been set at the given scope
module.exit_json(changed=False, msg='', config_values={})
elif rc >= 2:
# If the return code is 1, it just means the option hasn't been set yet, which is fine.
- module.fail_json(rc=rc, msg=err, cmd=' '.join(args))
+ module.fail_json(rc=rc, msg=err, cmd=' '.join(list_args))
+
+ old_values = out.rstrip().splitlines()
if params['list_all']:
- values = out.rstrip().splitlines()
config_values = {}
- for value in values:
+ for value in old_values:
k, v = value.split('=', 1)
config_values[k] = v
module.exit_json(changed=False, msg='', config_values=config_values)
elif not new_value and not unset:
- module.exit_json(changed=False, msg='', config_value=out.rstrip())
+ module.exit_json(changed=False, msg='', config_value=old_values[0] if old_values else '')
elif unset and not out:
module.exit_json(changed=False, msg='no setting to unset')
+ elif new_value in old_values and (len(old_values) == 1 or add_mode == "add"):
+ module.exit_json(changed=False, msg="")
+
+ # Until this point, the git config was just read and in case no change is needed, the module has already exited.
+
+ set_args = list(base_args)
+ if unset:
+ set_args.append("--unset-all")
+ set_args.append(name)
else:
- old_value = out.rstrip()
- if old_value == new_value:
- module.exit_json(changed=False, msg="")
+ set_args.append("--" + add_mode)
+ set_args.append(name)
+ set_args.append(new_value)
if not module.check_mode:
- if unset:
- args.insert(len(args) - 1, "--" + unset)
- cmd = args
- else:
- cmd = args + [new_value]
- (rc, out, err) = module.run_command(cmd, cwd=dir, ignore_invalid_cwd=False, expand_user_and_vars=False)
+ (rc, out, err) = module.run_command(set_args, cwd=cwd, ignore_invalid_cwd=False, expand_user_and_vars=False)
if err:
- module.fail_json(rc=rc, msg=err, cmd=cmd)
+ module.fail_json(rc=rc, msg=err, cmd=set_args)
+
+ if unset:
+ after_values = []
+ elif add_mode == "add":
+ after_values = old_values + [new_value]
+ else:
+ after_values = [new_value]
module.exit_json(
msg='setting changed',
diff=dict(
- before_header=' '.join(args),
- before=old_value + "\n",
- after_header=' '.join(args),
- after=(new_value or '') + "\n"
+ before_header=' '.join(set_args),
+ before=build_diff_value(old_values),
+ after_header=' '.join(set_args),
+ after=build_diff_value(after_values),
),
changed=True
)
+def determine_scope(params):
+ if params['scope']:
+ return params['scope']
+ elif params['list_all']:
+ return ""
+ else:
+ return 'system'
+
+
+def build_diff_value(value):
+ if not value:
+ return "\n"
+ elif len(value) == 1:
+ return value[0] + "\n"
+ else:
+ return value
+
+
+def determine_cwd(scope, params):
+ if scope == 'local':
+ return params['repo']
+ elif params['list_all'] and params['repo']:
+ # Include local settings from a specific repo when listing all available settings
+ return params['repo']
+ else:
+ # Run from root directory to avoid accidentally picking up any local config settings
+ return "/"
+
+
if __name__ == '__main__':
main()
diff --git a/ansible_collections/community/general/plugins/modules/git_config_info.py b/ansible_collections/community/general/plugins/modules/git_config_info.py
new file mode 100644
index 000000000..147201fff
--- /dev/null
+++ b/ansible_collections/community/general/plugins/modules/git_config_info.py
@@ -0,0 +1,187 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2023, Guenther Grill <grill.guenther@gmail.com>
+#
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+
+DOCUMENTATION = '''
+---
+module: git_config_info
+author:
+ - Guenther Grill (@guenhter)
+version_added: 8.1.0
+requirements: ['git']
+short_description: Read git configuration
+description:
+ - The M(community.general.git_config_info) module reads the git configuration
+ by invoking C(git config).
+extends_documentation_fragment:
+ - community.general.attributes
+ - community.general.attributes.info_module
+options:
+ name:
+ description:
+ - The name of the setting to read.
+ - If not provided, all settings will be returned as RV(config_values).
+ type: str
+ path:
+ description:
+ - Path to a git repository or file for reading values from a specific repo.
+ - If O(scope) is V(local), this must point to a repository to read from.
+ - If O(scope) is V(file), this must point to specific git config file to read from.
+ - Otherwise O(path) is ignored if set.
+ type: path
+ scope:
+ description:
+ - Specify which scope to read values from.
+ - If set to V(global), the global git config is used. O(path) is ignored.
+ - If set to V(system), the system git config is used. O(path) is ignored.
+ - If set to V(local), O(path) must be set to the repo to read from.
+ - If set to V(file), O(path) must be set to the config file to read from.
+ choices: [ "global", "system", "local", "file" ]
+ default: "system"
+ type: str
+'''
+
+EXAMPLES = '''
+- name: Read a system wide config
+ community.general.git_config_info:
+ name: core.editor
+ register: result
+
+- name: Show value of core.editor
+ ansible.builtin.debug:
+ msg: "{{ result.config_value | default('(not set)', true) }}"
+
+- name: Read a global config from ~/.gitconfig
+ community.general.git_config_info:
+ name: alias.remotev
+ scope: global
+
+- name: Read a project specific config
+ community.general.git_config_info:
+ name: color.ui
+ scope: local
+ path: /etc
+
+- name: Read all global values
+ community.general.git_config_info:
+ scope: global
+
+- name: Read all system wide values
+ community.general.git_config_info:
+
+- name: Read all values of a specific file
+ community.general.git_config_info:
+ scope: file
+ path: /etc/gitconfig
+'''
+
+RETURN = '''
+---
+config_value:
+ description: >
+ When O(name) is set, a string containing the value of the setting in name. If O(name) is not set, empty.
+ If a config key such as V(push.pushoption) has more then one entry, just the first one is returned here.
+ returned: success if O(name) is set
+ type: str
+ sample: "vim"
+
+config_values:
+ description:
+ - This is a dictionary mapping a git configuration setting to a list of its values.
+ - When O(name) is not set, all configuration settings are returned here.
+ - When O(name) is set, only the setting specified in O(name) is returned here.
+ If that setting is not set, the key will still be present, and its value will be an empty list.
+ returned: success
+ type: dict
+ sample:
+ core.editor: ["vim"]
+ color.ui: ["auto"]
+ push.pushoption: ["merge_request.create", "merge_request.draft"]
+ alias.remotev: ["remote -v"]
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+
+
+def main():
+ module = AnsibleModule(
+ argument_spec=dict(
+ name=dict(type="str"),
+ path=dict(type="path"),
+ scope=dict(required=False, type="str", default="system", choices=["global", "system", "local", "file"]),
+ ),
+ required_if=[
+ ("scope", "local", ["path"]),
+ ("scope", "file", ["path"]),
+ ],
+ required_one_of=[],
+ supports_check_mode=True,
+ )
+
+ # We check error message for a pattern, so we need to make sure the messages appear in the form we're expecting.
+ # Set the locale to C to ensure consistent messages.
+ module.run_command_environ_update = dict(LANG='C', LC_ALL='C', LC_MESSAGES='C', LC_CTYPE='C')
+
+ name = module.params["name"]
+ path = module.params["path"]
+ scope = module.params["scope"]
+
+ run_cwd = path if scope == "local" else "/"
+ args = build_args(module, name, path, scope)
+
+ (rc, out, err) = module.run_command(args, cwd=run_cwd, expand_user_and_vars=False)
+
+ if rc == 128 and "unable to read config file" in err:
+ # This just means nothing has been set at the given scope
+ pass
+ elif rc >= 2:
+ # If the return code is 1, it just means the option hasn't been set yet, which is fine.
+ module.fail_json(rc=rc, msg=err, cmd=" ".join(args))
+
+ output_lines = out.strip("\0").split("\0") if out else []
+
+ if name:
+ first_value = output_lines[0] if output_lines else ""
+ config_values = {name: output_lines}
+ module.exit_json(changed=False, msg="", config_value=first_value, config_values=config_values)
+ else:
+ config_values = text_to_dict(output_lines)
+ module.exit_json(changed=False, msg="", config_value="", config_values=config_values)
+
+
+def build_args(module, name, path, scope):
+ git_path = module.get_bin_path("git", True)
+ args = [git_path, "config", "--includes", "--null", "--" + scope]
+
+ if scope == "file":
+ args.append(path)
+
+ if name:
+ args.extend(["--get-all", name])
+ else:
+ args.append("--list")
+
+ return args
+
+
+def text_to_dict(text_lines):
+ config_values = {}
+ for value in text_lines:
+ k, v = value.split("\n", 1)
+ if k in config_values:
+ config_values[k].append(v)
+ else:
+ config_values[k] = [v]
+ return config_values
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/general/plugins/modules/github_deploy_key.py b/ansible_collections/community/general/plugins/modules/github_deploy_key.py
index 322650bf7..ae90e04c9 100644
--- a/ansible_collections/community/general/plugins/modules/github_deploy_key.py
+++ b/ansible_collections/community/general/plugins/modules/github_deploy_key.py
@@ -58,7 +58,7 @@ options:
type: str
read_only:
description:
- - If C(true), the deploy key will only be able to read repository contents. Otherwise, the deploy key will be able to read and write.
+ - If V(true), the deploy key will only be able to read repository contents. Otherwise, the deploy key will be able to read and write.
type: bool
default: true
state:
@@ -69,7 +69,7 @@ options:
type: str
force:
description:
- - If C(true), forcefully adds the deploy key by deleting any existing deploy key with the same public key or title.
+ - If V(true), forcefully adds the deploy key by deleting any existing deploy key with the same public key or title.
type: bool
default: false
username:
@@ -78,15 +78,15 @@ options:
type: str
password:
description:
- - The password to authenticate with. Alternatively, a personal access token can be used instead of I(username) and I(password) combination.
+ - The password to authenticate with. Alternatively, a personal access token can be used instead of O(username) and O(password) combination.
type: str
token:
description:
- - The OAuth2 token or personal access token to authenticate with. Mutually exclusive with I(password).
+ - The OAuth2 token or personal access token to authenticate with. Mutually exclusive with O(password).
type: str
otp:
description:
- - The 6 digit One Time Password for 2-Factor Authentication. Required together with I(username) and I(password).
+ - The 6 digit One Time Password for 2-Factor Authentication. Required together with O(username) and O(password).
type: int
notes:
- "Refer to GitHub's API documentation here: https://developer.github.com/v3/repos/keys/."
@@ -227,7 +227,7 @@ class GithubDeployKey(object):
yield self.module.from_json(resp.read())
links = {}
- for x, y in findall(r'<([^>]+)>;\s*rel="(\w+)"', info["link"]):
+ for x, y in findall(r'<([^>]+)>;\s*rel="(\w+)"', info.get("link", '')):
links[y] = x
url = links.get('next')
diff --git a/ansible_collections/community/general/plugins/modules/github_key.py b/ansible_collections/community/general/plugins/modules/github_key.py
index 683a963a7..fa3a0a01f 100644
--- a/ansible_collections/community/general/plugins/modules/github_key.py
+++ b/ansible_collections/community/general/plugins/modules/github_key.py
@@ -34,7 +34,7 @@ options:
type: str
pubkey:
description:
- - SSH public key value. Required when I(state=present).
+ - SSH public key value. Required when O(state=present).
type: str
state:
description:
@@ -44,9 +44,9 @@ options:
type: str
force:
description:
- - The default is C(true), which will replace the existing remote key
- if it's different than C(pubkey). If C(false), the key will only be
- set if no key with the given I(name) exists.
+ - The default is V(true), which will replace the existing remote key
+ if it is different than O(pubkey). If V(false), the key will only be
+ set if no key with the given O(name) exists.
type: bool
default: true
@@ -82,8 +82,14 @@ EXAMPLES = '''
name: Access Key for Some Machine
token: '{{ github_access_token }}'
pubkey: '{{ ssh_pub_key.stdout }}'
-'''
+# Alternatively, a single task can be used reading a key from a file on the controller
+- name: Authorize key with GitHub
+ community.general.github_key:
+ name: Access Key for Some Machine
+ token: '{{ github_access_token }}'
+ pubkey: "{{ lookup('ansible.builtin.file', '/home/foo/.ssh/id_rsa.pub') }}"
+'''
import json
import re
diff --git a/ansible_collections/community/general/plugins/modules/github_release.py b/ansible_collections/community/general/plugins/modules/github_release.py
index 3ddd6c882..d8ee155b8 100644
--- a/ansible_collections/community/general/plugins/modules/github_release.py
+++ b/ansible_collections/community/general/plugins/modules/github_release.py
@@ -25,7 +25,7 @@ attributes:
options:
token:
description:
- - GitHub Personal Access Token for authenticating. Mutually exclusive with C(password).
+ - GitHub Personal Access Token for authenticating. Mutually exclusive with O(password).
type: str
user:
description:
@@ -34,7 +34,7 @@ options:
required: true
password:
description:
- - The GitHub account password for the user. Mutually exclusive with C(token).
+ - The GitHub account password for the user. Mutually exclusive with O(token).
type: str
repo:
description:
@@ -49,7 +49,7 @@ options:
choices: [ 'latest_release', 'create_release' ]
tag:
description:
- - Tag name when creating a release. Required when using action is set to C(create_release).
+ - Tag name when creating a release. Required when using O(action=create_release).
type: str
target:
description:
@@ -94,7 +94,7 @@ EXAMPLES = '''
repo: testrepo
action: latest_release
-- name: Get latest release of test repo using username and password. Ansible 2.4.
+- name: Get latest release of test repo using username and password
community.general.github_release:
user: testuser
password: secret123
diff --git a/ansible_collections/community/general/plugins/modules/github_repo.py b/ansible_collections/community/general/plugins/modules/github_repo.py
index 97076c58a..f02ad30ac 100644
--- a/ansible_collections/community/general/plugins/modules/github_repo.py
+++ b/ansible_collections/community/general/plugins/modules/github_repo.py
@@ -15,7 +15,7 @@ short_description: Manage your repositories on Github
version_added: 2.2.0
description:
- Manages Github repositories using PyGithub library.
- - Authentication can be done with I(access_token) or with I(username) and I(password).
+ - Authentication can be done with O(access_token) or with O(username) and O(password).
extends_documentation_fragment:
- community.general.attributes
attributes:
@@ -27,19 +27,19 @@ options:
username:
description:
- Username used for authentication.
- - This is only needed when not using I(access_token).
+ - This is only needed when not using O(access_token).
type: str
required: false
password:
description:
- Password used for authentication.
- - This is only needed when not using I(access_token).
+ - This is only needed when not using O(access_token).
type: str
required: false
access_token:
description:
- Token parameter for authentication.
- - This is only needed when not using I(username) and I(password).
+ - This is only needed when not using O(username) and O(password).
type: str
required: false
name:
@@ -50,17 +50,17 @@ options:
description:
description:
- Description for the repository.
- - Defaults to empty if I(force_defaults=true), which is the default in this module.
- - Defaults to empty if I(force_defaults=false) when creating a new repository.
- - This is only used when I(state) is C(present).
+ - Defaults to empty if O(force_defaults=true), which is the default in this module.
+ - Defaults to empty if O(force_defaults=false) when creating a new repository.
+ - This is only used when O(state) is V(present).
type: str
required: false
private:
description:
- Whether the repository should be private or not.
- - Defaults to C(false) if I(force_defaults=true), which is the default in this module.
- - Defaults to C(false) if I(force_defaults=false) when creating a new repository.
- - This is only used when I(state) is C(present).
+ - Defaults to V(false) if O(force_defaults=true), which is the default in this module.
+ - Defaults to V(false) if O(force_defaults=false) when creating a new repository.
+ - This is only used when O(state=present).
type: bool
required: false
state:
@@ -73,7 +73,7 @@ options:
organization:
description:
- Organization for the repository.
- - When I(state) is C(present), the repository will be created in the current user profile.
+ - When O(state=present), the repository will be created in the current user profile.
type: str
required: false
api_url:
@@ -84,8 +84,8 @@ options:
version_added: "3.5.0"
force_defaults:
description:
- - Overwrite current I(description) and I(private) attributes with defaults if set to C(true), which currently is the default.
- - The default for this option will be deprecated in a future version of this collection, and eventually change to C(false).
+ - Overwrite current O(description) and O(private) attributes with defaults if set to V(true), which currently is the default.
+ - The default for this option will be deprecated in a future version of this collection, and eventually change to V(false).
type: bool
default: true
required: false
@@ -125,7 +125,7 @@ EXAMPLES = '''
RETURN = '''
repo:
description: Repository information as JSON. See U(https://docs.github.com/en/rest/reference/repos#get-a-repository).
- returned: success and I(state) is C(present)
+ returned: success and O(state=present)
type: dict
'''
diff --git a/ansible_collections/community/general/plugins/modules/github_webhook.py b/ansible_collections/community/general/plugins/modules/github_webhook.py
index d47b7a82f..11b115750 100644
--- a/ansible_collections/community/general/plugins/modules/github_webhook.py
+++ b/ansible_collections/community/general/plugins/modules/github_webhook.py
@@ -61,7 +61,7 @@ options:
- >
A list of GitHub events the hook is triggered for. Events are listed at
U(https://developer.github.com/v3/activity/events/types/). Required
- unless C(state) is C(absent)
+ unless O(state=absent)
required: false
type: list
elements: str
diff --git a/ansible_collections/community/general/plugins/modules/github_webhook_info.py b/ansible_collections/community/general/plugins/modules/github_webhook_info.py
index a6f7c3e52..dcad02a36 100644
--- a/ansible_collections/community/general/plugins/modules/github_webhook_info.py
+++ b/ansible_collections/community/general/plugins/modules/github_webhook_info.py
@@ -14,7 +14,6 @@ module: github_webhook_info
short_description: Query information about GitHub webhooks
description:
- "Query information about GitHub webhooks"
- - This module was called C(github_webhook_facts) before Ansible 2.9. The usage did not change.
requirements:
- "PyGithub >= 1.3.5"
extends_documentation_fragment:
diff --git a/ansible_collections/community/general/plugins/modules/gitlab_branch.py b/ansible_collections/community/general/plugins/modules/gitlab_branch.py
index d7eecb33f..623c25644 100644
--- a/ansible_collections/community/general/plugins/modules/gitlab_branch.py
+++ b/ansible_collections/community/general/plugins/modules/gitlab_branch.py
@@ -16,7 +16,6 @@ description:
author:
- paytroff (@paytroff)
requirements:
- - python >= 2.7
- python-gitlab >= 2.3.0
extends_documentation_fragment:
- community.general.auth_basic
@@ -49,7 +48,7 @@ options:
ref_branch:
description:
- Reference branch to create from.
- - This must be specified if I(state=present).
+ - This must be specified if O(state=present).
type: str
'''
@@ -84,7 +83,7 @@ from ansible.module_utils.api import basic_auth_argument_spec
from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
from ansible_collections.community.general.plugins.module_utils.gitlab import (
- auth_argument_spec, gitlab_authentication, gitlab, ensure_gitlab_package
+ auth_argument_spec, gitlab_authentication, gitlab
)
@@ -144,7 +143,9 @@ def main():
],
supports_check_mode=False
)
- ensure_gitlab_package(module)
+
+ # check prerequisites and connect to gitlab server
+ gitlab_instance = gitlab_authentication(module)
project = module.params['project']
branch = module.params['branch']
@@ -156,7 +157,6 @@ def main():
module.fail_json(msg="community.general.gitlab_proteched_branch requires python-gitlab Python module >= 2.3.0 (installed version: [%s])."
" Please upgrade python-gitlab to version 2.3.0 or above." % gitlab_version)
- gitlab_instance = gitlab_authentication(module)
this_gitlab = GitlabBranch(module=module, project=project, gitlab_instance=gitlab_instance)
this_branch = this_gitlab.get_branch(branch)
diff --git a/ansible_collections/community/general/plugins/modules/gitlab_deploy_key.py b/ansible_collections/community/general/plugins/modules/gitlab_deploy_key.py
index 27cb01f87..7c0ff06b7 100644
--- a/ansible_collections/community/general/plugins/modules/gitlab_deploy_key.py
+++ b/ansible_collections/community/general/plugins/modules/gitlab_deploy_key.py
@@ -20,7 +20,6 @@ author:
- Marcus Watkins (@marwatk)
- Guillaume Martinez (@Lunik)
requirements:
- - python >= 2.7
- python-gitlab python module
extends_documentation_fragment:
- community.general.auth_basic
@@ -56,8 +55,8 @@ options:
default: false
state:
description:
- - When C(present) the deploy key added to the project if it doesn't exist.
- - When C(absent) it will be removed from the project if it exists.
+ - When V(present) the deploy key added to the project if it doesn't exist.
+ - When V(absent) it will be removed from the project if it exists.
default: present
type: str
choices: [ "present", "absent" ]
@@ -121,7 +120,7 @@ from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.common.text.converters import to_native
from ansible_collections.community.general.plugins.module_utils.gitlab import (
- auth_argument_spec, find_project, gitlab_authentication, gitlab, ensure_gitlab_package
+ auth_argument_spec, find_project, gitlab_authentication, gitlab, list_all_kwargs
)
@@ -209,8 +208,7 @@ class GitLabDeployKey(object):
@param key_title Title of the key
'''
def find_deploy_key(self, project, key_title):
- deploy_keys = project.keys.list(all=True)
- for deploy_key in deploy_keys:
+ for deploy_key in project.keys.list(**list_all_kwargs):
if (deploy_key.title == key_title):
return deploy_key
@@ -261,7 +259,9 @@ def main():
],
supports_check_mode=True,
)
- ensure_gitlab_package(module)
+
+ # check prerequisites and connect to gitlab server
+ gitlab_instance = gitlab_authentication(module)
state = module.params['state']
project_identifier = module.params['project']
@@ -269,8 +269,6 @@ def main():
key_keyfile = module.params['key']
key_can_push = module.params['can_push']
- gitlab_instance = gitlab_authentication(module)
-
gitlab_deploy_key = GitLabDeployKey(module, gitlab_instance)
project = find_project(gitlab_instance, project_identifier)
diff --git a/ansible_collections/community/general/plugins/modules/gitlab_group.py b/ansible_collections/community/general/plugins/modules/gitlab_group.py
index 4de1ffc5f..3d57b1852 100644
--- a/ansible_collections/community/general/plugins/modules/gitlab_group.py
+++ b/ansible_collections/community/general/plugins/modules/gitlab_group.py
@@ -20,7 +20,6 @@ author:
- Werner Dijkerman (@dj-wasabi)
- Guillaume Martinez (@Lunik)
requirements:
- - python >= 2.7
- python-gitlab python module
extends_documentation_fragment:
- community.general.auth_basic
@@ -94,6 +93,13 @@ options:
- This option is only used on creation, not for updates.
type: path
version_added: 4.2.0
+ force_delete:
+ description:
+ - Force delete group even if projects in it.
+ - Used only when O(state=absent).
+ type: bool
+ default: false
+ version_added: 7.5.0
'''
EXAMPLES = '''
@@ -101,7 +107,6 @@ EXAMPLES = '''
community.general.gitlab_group:
api_url: https://gitlab.example.com/
api_token: "{{ access_token }}"
- validate_certs: false
name: my_first_group
state: absent
@@ -171,7 +176,7 @@ from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.common.text.converters import to_native
from ansible_collections.community.general.plugins.module_utils.gitlab import (
- auth_argument_spec, find_group, gitlab_authentication, gitlab, ensure_gitlab_package
+ auth_argument_spec, find_group, gitlab_authentication, gitlab
)
@@ -279,12 +284,18 @@ class GitLabGroup(object):
return (changed, group)
- def delete_group(self):
+ '''
+ @param force To delete even if projects inside
+ '''
+ def delete_group(self, force=False):
group = self.group_object
- if len(group.projects.list(all=False)) >= 1:
+ if not force and len(group.projects.list(all=False)) >= 1:
self._module.fail_json(
- msg="There are still projects in this group. These needs to be moved or deleted before this group can be removed.")
+ msg=("There are still projects in this group. "
+ "These needs to be moved or deleted before this group can be removed. "
+ "Use 'force_delete' to 'true' to force deletion of existing projects.")
+ )
else:
if self._module.check_mode:
return True
@@ -295,7 +306,7 @@ class GitLabGroup(object):
self._module.fail_json(msg="Failed to delete group: %s " % to_native(e))
'''
- @param name Name of the groupe
+ @param name Name of the group
@param full_path Complete path of the Group including parent group path. <parent_path>/<group_path>
'''
def exists_group(self, project_identifier):
@@ -322,6 +333,7 @@ def main():
subgroup_creation_level=dict(type='str', choices=['maintainer', 'owner']),
require_two_factor_authentication=dict(type='bool'),
avatar_path=dict(type='path'),
+ force_delete=dict(type='bool', default=False),
))
module = AnsibleModule(
@@ -341,7 +353,9 @@ def main():
],
supports_check_mode=True,
)
- ensure_gitlab_package(module)
+
+ # check prerequisites and connect to gitlab server
+ gitlab_instance = gitlab_authentication(module)
group_name = module.params['name']
group_path = module.params['path']
@@ -354,8 +368,7 @@ def main():
subgroup_creation_level = module.params['subgroup_creation_level']
require_two_factor_authentication = module.params['require_two_factor_authentication']
avatar_path = module.params['avatar_path']
-
- gitlab_instance = gitlab_authentication(module)
+ force_delete = module.params['force_delete']
# Define default group_path based on group_name
if group_path is None:
@@ -375,7 +388,7 @@ def main():
if state == 'absent':
if group_exists:
- gitlab_group.delete_group()
+ gitlab_group.delete_group(force=force_delete)
module.exit_json(changed=True, msg="Successfully deleted group %s" % group_name)
else:
module.exit_json(changed=False, msg="Group deleted or does not exists")
diff --git a/ansible_collections/community/general/plugins/modules/gitlab_group_access_token.py b/ansible_collections/community/general/plugins/modules/gitlab_group_access_token.py
new file mode 100644
index 000000000..85bba205d
--- /dev/null
+++ b/ansible_collections/community/general/plugins/modules/gitlab_group_access_token.py
@@ -0,0 +1,320 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2024, Zoran Krleza (zoran.krleza@true-north.hr)
+# Based on code:
+# Copyright (c) 2019, Guillaume Martinez (lunik@tiwabbit.fr)
+# Copyright (c) 2018, Marcus Watkins <marwatk@marcuswatkins.net>
+# Copyright (c) 2013, Phillip Gentry <phillip@cx.com>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+DOCUMENTATION = r'''
+module: gitlab_group_access_token
+short_description: Manages GitLab group access tokens
+version_added: 8.4.0
+description:
+ - Creates and revokes group access tokens.
+author:
+ - Zoran Krleza (@pixslx)
+requirements:
+ - python-gitlab >= 3.1.0
+extends_documentation_fragment:
+ - community.general.auth_basic
+ - community.general.gitlab
+ - community.general.attributes
+notes:
+ - Access tokens can not be changed. If a parameter needs to be changed, an acceess token has to be recreated.
+ Whether tokens will be recreated is controlled by the O(recreate) option, which defaults to V(never).
+ - Token string is contained in the result only when access token is created or recreated. It can not be fetched afterwards.
+ - Token matching is done by comparing O(name) option.
+
+attributes:
+ check_mode:
+ support: full
+ diff_mode:
+ support: none
+
+options:
+ group:
+ description:
+ - ID or full path of group in the form of group/subgroup.
+ required: true
+ type: str
+ name:
+ description:
+ - Access token's name.
+ required: true
+ type: str
+ scopes:
+ description:
+ - Scope of the access token.
+ required: true
+ type: list
+ elements: str
+ aliases: ["scope"]
+ choices: ["api", "read_api", "read_registry", "write_registry", "read_repository", "write_repository", "create_runner", "ai_features", "k8s_proxy"]
+ access_level:
+ description:
+ - Access level of the access token.
+ type: str
+ default: maintainer
+ choices: ["guest", "reporter", "developer", "maintainer", "owner"]
+ expires_at:
+ description:
+ - Expiration date of the access token in C(YYYY-MM-DD) format.
+ - Make sure to quote this value in YAML to ensure it is kept as a string and not interpreted as a YAML date.
+ type: str
+ required: true
+ recreate:
+ description:
+ - Whether the access token will be recreated if it already exists.
+ - When V(never) the token will never be recreated.
+ - When V(always) the token will always be recreated.
+ - When V(state_change) the token will be recreated if there is a difference between desired state and actual state.
+ type: str
+ choices: ["never", "always", "state_change"]
+ default: never
+ state:
+ description:
+ - When V(present) the access token will be added to the group if it does not exist.
+ - When V(absent) it will be removed from the group if it exists.
+ default: present
+ type: str
+ choices: [ "present", "absent" ]
+'''
+
+EXAMPLES = r'''
+- name: "Creating a group access token"
+ community.general.gitlab_group_access_token:
+ api_url: https://gitlab.example.com/
+ api_token: "somegitlabapitoken"
+ group: "my_group/my_subgroup"
+ name: "group_token"
+ expires_at: "2024-12-31"
+ access_level: developer
+ scopes:
+ - api
+ - read_api
+ - read_repository
+ - write_repository
+ state: present
+
+- name: "Revoking a group access token"
+ community.general.gitlab_group_access_token:
+ api_url: https://gitlab.example.com/
+ api_token: "somegitlabapitoken"
+ group: "my_group/my_group"
+ name: "group_token"
+ expires_at: "2024-12-31"
+ scopes:
+ - api
+ - read_api
+ - read_repository
+ - write_repository
+ state: absent
+
+- name: "Change (recreate) existing token if its actual state is different than desired state"
+ community.general.gitlab_group_access_token:
+ api_url: https://gitlab.example.com/
+ api_token: "somegitlabapitoken"
+ group: "my_group/my_group"
+ name: "group_token"
+ expires_at: "2024-12-31"
+ scopes:
+ - api
+ - read_api
+ - read_repository
+ - write_repository
+ recreate: state_change
+ state: present
+'''
+
+RETURN = r'''
+access_token:
+ description:
+ - API object.
+ - Only contains the value of the token if the token was created or recreated.
+ returned: success and O(state=present)
+ type: dict
+'''
+
+from datetime import datetime
+
+from ansible.module_utils.api import basic_auth_argument_spec
+from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.common.text.converters import to_native
+
+from ansible_collections.community.general.plugins.module_utils.gitlab import (
+ auth_argument_spec, find_group, gitlab_authentication, gitlab
+)
+
+ACCESS_LEVELS = dict(guest=10, reporter=20, developer=30, maintainer=40, owner=50)
+
+
+class GitLabGroupAccessToken(object):
+ def __init__(self, module, gitlab_instance):
+ self._module = module
+ self._gitlab = gitlab_instance
+ self.access_token_object = None
+
+ '''
+ @param project Project Object
+ @param group Group Object
+ @param arguments Attributes of the access_token
+ '''
+ def create_access_token(self, group, arguments):
+ changed = False
+ if self._module.check_mode:
+ return True
+
+ try:
+ self.access_token_object = group.access_tokens.create(arguments)
+ changed = True
+ except (gitlab.exceptions.GitlabCreateError) as e:
+ self._module.fail_json(msg="Failed to create access token: %s " % to_native(e))
+
+ return changed
+
+ '''
+ @param project Project object
+ @param group Group Object
+ @param name of the access token
+ '''
+ def find_access_token(self, group, name):
+ access_tokens = group.access_tokens.list(all=True)
+ for access_token in access_tokens:
+ if (access_token.name == name):
+ self.access_token_object = access_token
+ return False
+ return False
+
+ def revoke_access_token(self):
+ if self._module.check_mode:
+ return True
+
+ changed = False
+ try:
+ self.access_token_object.delete()
+ changed = True
+ except (gitlab.exceptions.GitlabCreateError) as e:
+ self._module.fail_json(msg="Failed to revoke access token: %s " % to_native(e))
+
+ return changed
+
+ def access_tokens_equal(self):
+ if self.access_token_object.name != self._module.params['name']:
+ return False
+ if self.access_token_object.scopes != self._module.params['scopes']:
+ return False
+ if self.access_token_object.access_level != ACCESS_LEVELS[self._module.params['access_level']]:
+ return False
+ if self.access_token_object.expires_at != self._module.params['expires_at']:
+ return False
+ return True
+
+
+def main():
+ argument_spec = basic_auth_argument_spec()
+ argument_spec.update(auth_argument_spec())
+ argument_spec.update(dict(
+ state=dict(type='str', default="present", choices=["absent", "present"]),
+ group=dict(type='str', required=True),
+ name=dict(type='str', required=True),
+ scopes=dict(type='list',
+ required=True,
+ aliases=['scope'],
+ elements='str',
+ choices=['api',
+ 'read_api',
+ 'read_registry',
+ 'write_registry',
+ 'read_repository',
+ 'write_repository',
+ 'create_runner',
+ 'ai_features',
+ 'k8s_proxy']),
+ access_level=dict(type='str', required=False, default='maintainer', choices=['guest', 'reporter', 'developer', 'maintainer', 'owner']),
+ expires_at=dict(type='str', required=True),
+ recreate=dict(type='str', default='never', choices=['never', 'always', 'state_change'])
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ mutually_exclusive=[
+ ['api_username', 'api_token'],
+ ['api_username', 'api_oauth_token'],
+ ['api_username', 'api_job_token'],
+ ['api_token', 'api_oauth_token'],
+ ['api_token', 'api_job_token']
+ ],
+ required_together=[
+ ['api_username', 'api_password']
+ ],
+ required_one_of=[
+ ['api_username', 'api_token', 'api_oauth_token', 'api_job_token']
+ ],
+ supports_check_mode=True
+ )
+
+ state = module.params['state']
+ group_identifier = module.params['group']
+ name = module.params['name']
+ scopes = module.params['scopes']
+ access_level_str = module.params['access_level']
+ expires_at = module.params['expires_at']
+ recreate = module.params['recreate']
+
+ access_level = ACCESS_LEVELS[access_level_str]
+
+ try:
+ datetime.strptime(expires_at, '%Y-%m-%d')
+ except ValueError:
+ module.fail_json(msg="Argument expires_at is not in required format YYYY-MM-DD")
+
+ gitlab_instance = gitlab_authentication(module)
+
+ gitlab_access_token = GitLabGroupAccessToken(module, gitlab_instance)
+
+ group = find_group(gitlab_instance, group_identifier)
+ if group is None:
+ module.fail_json(msg="Failed to create access token: group %s does not exists" % group_identifier)
+
+ gitlab_access_token_exists = False
+ gitlab_access_token.find_access_token(group, name)
+ if gitlab_access_token.access_token_object is not None:
+ gitlab_access_token_exists = True
+
+ if state == 'absent':
+ if gitlab_access_token_exists:
+ gitlab_access_token.revoke_access_token()
+ module.exit_json(changed=True, msg="Successfully deleted access token %s" % name)
+ else:
+ module.exit_json(changed=False, msg="Access token does not exists")
+
+ if state == 'present':
+ if gitlab_access_token_exists:
+ if gitlab_access_token.access_tokens_equal():
+ if recreate == 'always':
+ gitlab_access_token.revoke_access_token()
+ gitlab_access_token.create_access_token(group, {'name': name, 'scopes': scopes, 'access_level': access_level, 'expires_at': expires_at})
+ module.exit_json(changed=True, msg="Successfully recreated access token", access_token=gitlab_access_token.access_token_object._attrs)
+ else:
+ module.exit_json(changed=False, msg="Access token already exists", access_token=gitlab_access_token.access_token_object._attrs)
+ else:
+ if recreate == 'never':
+ module.fail_json(msg="Access token already exists and its state is different. It can not be updated without recreating.")
+ else:
+ gitlab_access_token.revoke_access_token()
+ gitlab_access_token.create_access_token(group, {'name': name, 'scopes': scopes, 'access_level': access_level, 'expires_at': expires_at})
+ module.exit_json(changed=True, msg="Successfully recreated access token", access_token=gitlab_access_token.access_token_object._attrs)
+ else:
+ gitlab_access_token.create_access_token(group, {'name': name, 'scopes': scopes, 'access_level': access_level, 'expires_at': expires_at})
+ module.exit_json(changed=True, msg="Successfully created access token", access_token=gitlab_access_token.access_token_object._attrs)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/general/plugins/modules/gitlab_group_members.py b/ansible_collections/community/general/plugins/modules/gitlab_group_members.py
index 66298e882..ca82891e3 100644
--- a/ansible_collections/community/general/plugins/modules/gitlab_group_members.py
+++ b/ansible_collections/community/general/plugins/modules/gitlab_group_members.py
@@ -40,22 +40,22 @@ options:
gitlab_user:
description:
- A username or a list of usernames to add to/remove from the GitLab group.
- - Mutually exclusive with I(gitlab_users_access).
+ - Mutually exclusive with O(gitlab_users_access).
type: list
elements: str
access_level:
description:
- The access level for the user.
- - Required if I(state=present), user state is set to present.
- - Mutually exclusive with I(gitlab_users_access).
+ - Required if O(state=present), user state is set to present.
+ - Mutually exclusive with O(gitlab_users_access).
type: str
choices: ['guest', 'reporter', 'developer', 'maintainer', 'owner']
gitlab_users_access:
description:
- Provide a list of user to access level mappings.
- Every dictionary in this list specifies a user (by username) and the access level the user should have.
- - Mutually exclusive with I(gitlab_user) and I(access_level).
- - Use together with I(purge_users) to remove all users not specified here from the group.
+ - Mutually exclusive with O(gitlab_user) and O(access_level).
+ - Use together with O(purge_users) to remove all users not specified here from the group.
type: list
elements: dict
suboptions:
@@ -66,7 +66,7 @@ options:
access_level:
description:
- The access level for the user.
- - Required if I(state=present), user state is set to present.
+ - Required if O(state=present), user state is set to present.
type: str
choices: ['guest', 'reporter', 'developer', 'maintainer', 'owner']
required: true
@@ -74,16 +74,16 @@ options:
state:
description:
- State of the member in the group.
- - On C(present), it adds a user to a GitLab group.
- - On C(absent), it removes a user from a GitLab group.
+ - On V(present), it adds a user to a GitLab group.
+ - On V(absent), it removes a user from a GitLab group.
choices: ['present', 'absent']
default: 'present'
type: str
purge_users:
description:
- - Adds/remove users of the given access_level to match the given I(gitlab_user)/I(gitlab_users_access) list.
+ - Adds/remove users of the given access_level to match the given O(gitlab_user)/O(gitlab_users_access) list.
If omitted do not purge orphaned members.
- - Is only used when I(state=present).
+ - Is only used when O(state=present).
type: list
elements: str
choices: ['guest', 'reporter', 'developer', 'maintainer', 'owner']
@@ -160,7 +160,7 @@ from ansible.module_utils.api import basic_auth_argument_spec
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils.gitlab import (
- auth_argument_spec, gitlab_authentication, gitlab, ensure_gitlab_package
+ auth_argument_spec, gitlab_authentication, gitlab, list_all_kwargs
)
@@ -171,16 +171,20 @@ class GitLabGroup(object):
# get user id if the user exists
def get_user_id(self, gitlab_user):
- user_exists = self._gitlab.users.list(username=gitlab_user, all=True)
- if user_exists:
- return user_exists[0].id
+ return next(
+ (u.id for u in self._gitlab.users.list(username=gitlab_user, **list_all_kwargs)),
+ None
+ )
# get group id if group exists
def get_group_id(self, gitlab_group):
- groups = self._gitlab.groups.list(search=gitlab_group, all=True)
- for group in groups:
- if group.full_path == gitlab_group:
- return group.id
+ return next(
+ (
+ g.id for g in self._gitlab.groups.list(search=gitlab_group, **list_all_kwargs)
+ if g.full_path == gitlab_group
+ ),
+ None
+ )
# get all members in a group
def get_members_in_a_group(self, gitlab_group_id):
@@ -273,14 +277,16 @@ def main():
],
supports_check_mode=True,
)
- ensure_gitlab_package(module)
+
+ # check prerequisites and connect to gitlab server
+ gl = gitlab_authentication(module)
access_level_int = {
- 'guest': gitlab.GUEST_ACCESS,
- 'reporter': gitlab.REPORTER_ACCESS,
- 'developer': gitlab.DEVELOPER_ACCESS,
- 'maintainer': gitlab.MAINTAINER_ACCESS,
- 'owner': gitlab.OWNER_ACCESS,
+ 'guest': gitlab.const.GUEST_ACCESS,
+ 'reporter': gitlab.const.REPORTER_ACCESS,
+ 'developer': gitlab.const.DEVELOPER_ACCESS,
+ 'maintainer': gitlab.const.MAINTAINER_ACCESS,
+ 'owner': gitlab.const.OWNER_ACCESS,
}
gitlab_group = module.params['gitlab_group']
@@ -291,9 +297,6 @@ def main():
if purge_users:
purge_users = [access_level_int[level] for level in purge_users]
- # connect to gitlab server
- gl = gitlab_authentication(module)
-
group = GitLabGroup(module, gl)
gitlab_group_id = group.get_group_id(gitlab_group)
diff --git a/ansible_collections/community/general/plugins/modules/gitlab_group_variable.py b/ansible_collections/community/general/plugins/modules/gitlab_group_variable.py
index c7befe123..32e5aaa90 100644
--- a/ansible_collections/community/general/plugins/modules/gitlab_group_variable.py
+++ b/ansible_collections/community/general/plugins/modules/gitlab_group_variable.py
@@ -17,11 +17,10 @@ description:
- Creates a group variable if it does not exist.
- When a group variable does exist, its value will be updated when the values are different.
- Variables which are untouched in the playbook, but are not untouched in the GitLab group,
- they stay untouched (I(purge) is C(false)) or will be deleted (I(purge) is C(true)).
+ they stay untouched (O(purge=false)) or will be deleted (O(purge=true)).
author:
- Florent Madiot (@scodeman)
requirements:
- - python >= 2.7
- python-gitlab python module
extends_documentation_fragment:
- community.general.auth_basic
@@ -48,20 +47,21 @@ options:
type: str
purge:
description:
- - When set to C(true), delete all variables which are not untouched in the task.
+ - When set to V(true), delete all variables which are not untouched in the task.
default: false
type: bool
vars:
description:
- - When the list element is a simple key-value pair, set masked and protected to false.
- - When the list element is a dict with the keys I(value), I(masked) and I(protected), the user can
- have full control about whether a value should be masked, protected or both.
+ - When the list element is a simple key-value pair, masked, raw and protected will be set to false.
+ - When the list element is a dict with the keys C(value), C(masked), C(raw) and C(protected), the user can
+ have full control about whether a value should be masked, raw, protected or both.
- Support for group variables requires GitLab >= 9.5.
- Support for environment_scope requires GitLab Premium >= 13.11.
- Support for protected values requires GitLab >= 9.3.
- Support for masked values requires GitLab >= 11.10.
- - A I(value) must be a string or a number.
- - Field I(variable_type) must be a string with either C(env_var), which is the default, or C(file).
+ - Support for raw values requires GitLab >= 15.7.
+ - A C(value) must be a string or a number.
+ - Field C(variable_type) must be a string with either V(env_var), which is the default, or V(file).
- When a value is masked, it must be in Base64 and have a length of at least 8 characters.
See GitLab documentation on acceptable values for a masked variable (U(https://docs.gitlab.com/ce/ci/variables/#masked-variables)).
default: {}
@@ -70,7 +70,7 @@ options:
version_added: 4.5.0
description:
- A list of dictionaries that represents CI/CD variables.
- - This modules works internal with this sructure, even if the older I(vars) parameter is used.
+ - This modules works internal with this structure, even if the older O(vars) parameter is used.
default: []
type: list
elements: dict
@@ -83,21 +83,28 @@ options:
value:
description:
- The variable value.
- - Required when I(state=present).
+ - Required when O(state=present).
type: str
masked:
description:
- - Wether variable value is masked or not.
+ - Whether variable value is masked or not.
type: bool
default: false
protected:
description:
- - Wether variable value is protected or not.
+ - Whether variable value is protected or not.
type: bool
default: false
+ raw:
+ description:
+ - Whether variable value is raw or not.
+ - Support for raw values requires GitLab >= 15.7.
+ type: bool
+ default: false
+ version_added: '7.4.0'
variable_type:
description:
- - Wether a variable is an environment variable (C(env_var)) or a file (C(file)).
+ - Whether a variable is an environment variable (V(env_var)) or a file (V(file)).
type: str
choices: [ "env_var", "file" ]
default: env_var
@@ -126,6 +133,38 @@ EXAMPLES = r'''
variable_type: env_var
environment_scope: production
+- name: Set or update some CI/CD variables with raw value
+ community.general.gitlab_group_variable:
+ api_url: https://gitlab.com
+ api_token: secret_access_token
+ group: scodeman/testgroup/
+ purge: false
+ vars:
+ ACCESS_KEY_ID: abc123
+ SECRET_ACCESS_KEY:
+ value: 3214cbad
+ masked: true
+ protected: true
+ raw: true
+ variable_type: env_var
+ environment_scope: '*'
+
+- name: Set or update some CI/CD variables with expandable value
+ community.general.gitlab_group_variable:
+ api_url: https://gitlab.com
+ api_token: secret_access_token
+ group: scodeman/testgroup/
+ purge: false
+ vars:
+ ACCESS_KEY_ID: abc123
+ SECRET_ACCESS_KEY:
+ value: '$MY_OTHER_VARIABLE'
+ masked: true
+ protected: true
+ raw: false
+ variable_type: env_var
+ environment_scope: '*'
+
- name: Delete one variable
community.general.gitlab_group_variable:
api_url: https://gitlab.com
@@ -166,52 +205,12 @@ group_variable:
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.api import basic_auth_argument_spec
-from ansible.module_utils.six import string_types
-from ansible.module_utils.six import integer_types
-
from ansible_collections.community.general.plugins.module_utils.gitlab import (
- auth_argument_spec, gitlab_authentication, ensure_gitlab_package, filter_returned_variables
+ auth_argument_spec, gitlab_authentication, filter_returned_variables, vars_to_variables,
+ list_all_kwargs
)
-def vars_to_variables(vars, module):
- # transform old vars to new variables structure
- variables = list()
- for item, value in vars.items():
- if (isinstance(value, string_types) or
- isinstance(value, (integer_types, float))):
- variables.append(
- {
- "name": item,
- "value": str(value),
- "masked": False,
- "protected": False,
- "variable_type": "env_var",
- }
- )
-
- elif isinstance(value, dict):
- new_item = {"name": item, "value": value.get('value')}
-
- new_item = {
- "name": item,
- "value": value.get('value'),
- "masked": value.get('masked'),
- "protected": value.get('protected'),
- "variable_type": value.get('variable_type'),
- }
-
- if value.get('environment_scope'):
- new_item['environment_scope'] = value.get('environment_scope')
-
- variables.append(new_item)
-
- else:
- module.fail_json(msg="value must be of type string, integer, float or dict")
-
- return variables
-
-
class GitlabGroupVariables(object):
def __init__(self, module, gitlab_instance):
@@ -223,14 +222,7 @@ class GitlabGroupVariables(object):
return self.repo.groups.get(group_name)
def list_all_group_variables(self):
- page_nb = 1
- variables = []
- vars_page = self.group.variables.list(page=page_nb)
- while len(vars_page) > 0:
- variables += vars_page
- page_nb += 1
- vars_page = self.group.variables.list(page=page_nb)
- return variables
+ return list(self.group.variables.list(**list_all_kwargs))
def create_variable(self, var_obj):
if self._module.check_mode:
@@ -240,6 +232,7 @@ class GitlabGroupVariables(object):
"value": var_obj.get('value'),
"masked": var_obj.get('masked'),
"protected": var_obj.get('protected'),
+ "raw": var_obj.get('raw'),
"variable_type": var_obj.get('variable_type'),
}
if var_obj.get('environment_scope') is not None:
@@ -308,6 +301,8 @@ def native_python_main(this_gitlab, purge, requested_variables, state, module):
item['value'] = str(item.get('value'))
if item.get('protected') is None:
item['protected'] = False
+ if item.get('raw') is None:
+ item['raw'] = False
if item.get('masked') is None:
item['masked'] = False
if item.get('environment_scope') is None:
@@ -379,11 +374,14 @@ def main():
group=dict(type='str', required=True),
purge=dict(type='bool', required=False, default=False),
vars=dict(type='dict', required=False, default=dict(), no_log=True),
+ # please mind whenever changing the variables dict to also change module_utils/gitlab.py's
+ # KNOWN dict in filter_returned_variables or bad evil will happen
variables=dict(type='list', elements='dict', required=False, default=list(), options=dict(
name=dict(type='str', required=True),
value=dict(type='str', no_log=True),
masked=dict(type='bool', default=False),
protected=dict(type='bool', default=False),
+ raw=dict(type='bool', default=False),
environment_scope=dict(type='str', default='*'),
variable_type=dict(type='str', default='env_var', choices=["env_var", "file"])
)),
@@ -408,7 +406,9 @@ def main():
],
supports_check_mode=True
)
- ensure_gitlab_package(module)
+
+ # check prerequisites and connect to gitlab server
+ gitlab_instance = gitlab_authentication(module)
purge = module.params['purge']
var_list = module.params['vars']
@@ -423,8 +423,6 @@ def main():
if any(x['value'] is None for x in variables):
module.fail_json(msg='value parameter is required in state present')
- gitlab_instance = gitlab_authentication(module)
-
this_gitlab = GitlabGroupVariables(module=module, gitlab_instance=gitlab_instance)
changed, raw_return_value, before, after = native_python_main(this_gitlab, purge, variables, state, module)
diff --git a/ansible_collections/community/general/plugins/modules/gitlab_hook.py b/ansible_collections/community/general/plugins/modules/gitlab_hook.py
index adf90eb7b..58781d182 100644
--- a/ansible_collections/community/general/plugins/modules/gitlab_hook.py
+++ b/ansible_collections/community/general/plugins/modules/gitlab_hook.py
@@ -21,7 +21,6 @@ author:
- Marcus Watkins (@marwatk)
- Guillaume Martinez (@Lunik)
requirements:
- - python >= 2.7
- python-gitlab python module
extends_documentation_fragment:
- community.general.auth_basic
@@ -47,8 +46,8 @@ options:
type: str
state:
description:
- - When C(present) the hook will be updated to match the input or created if it doesn't exist.
- - When C(absent) hook will be deleted if it exists.
+ - When V(present) the hook will be updated to match the input or created if it doesn't exist.
+ - When V(absent) hook will be deleted if it exists.
default: present
type: str
choices: [ "present", "absent" ]
@@ -98,6 +97,11 @@ options:
- Trigger hook on wiki events.
type: bool
default: false
+ releases_events:
+ description:
+ - Trigger hook on release events.
+ type: bool
+ version_added: '8.4.0'
hook_validate_certs:
description:
- Whether GitLab will do SSL verification when triggering the hook.
@@ -123,7 +127,6 @@ EXAMPLES = '''
state: present
push_events: true
tag_push_events: true
- hook_validate_certs: false
token: "my-super-secret-token-that-my-ci-server-will-check"
- name: "Delete the previous hook"
@@ -171,7 +174,7 @@ from ansible.module_utils.api import basic_auth_argument_spec
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils.gitlab import (
- auth_argument_spec, find_project, gitlab_authentication, ensure_gitlab_package
+ auth_argument_spec, find_project, gitlab_authentication, list_all_kwargs
)
@@ -203,6 +206,7 @@ class GitLabHook(object):
'job_events': options['job_events'],
'pipeline_events': options['pipeline_events'],
'wiki_page_events': options['wiki_page_events'],
+ 'releases_events': options['releases_events'],
'enable_ssl_verification': options['enable_ssl_verification'],
'token': options['token'],
})
@@ -218,6 +222,7 @@ class GitLabHook(object):
'job_events': options['job_events'],
'pipeline_events': options['pipeline_events'],
'wiki_page_events': options['wiki_page_events'],
+ 'releases_events': options['releases_events'],
'enable_ssl_verification': options['enable_ssl_verification'],
'token': options['token'],
})
@@ -266,8 +271,7 @@ class GitLabHook(object):
@param hook_url Url to call on event
'''
def find_hook(self, project, hook_url):
- hooks = project.hooks.list(all=True)
- for hook in hooks:
+ for hook in project.hooks.list(**list_all_kwargs):
if (hook.url == hook_url):
return hook
@@ -304,6 +308,7 @@ def main():
job_events=dict(type='bool', default=False),
pipeline_events=dict(type='bool', default=False),
wiki_page_events=dict(type='bool', default=False),
+ releases_events=dict(type='bool', default=None),
hook_validate_certs=dict(type='bool', default=False, aliases=['enable_ssl_verification']),
token=dict(type='str', no_log=True),
))
@@ -325,7 +330,9 @@ def main():
],
supports_check_mode=True,
)
- ensure_gitlab_package(module)
+
+ # check prerequisites and connect to gitlab server
+ gitlab_instance = gitlab_authentication(module)
state = module.params['state']
project_identifier = module.params['project']
@@ -339,11 +346,10 @@ def main():
job_events = module.params['job_events']
pipeline_events = module.params['pipeline_events']
wiki_page_events = module.params['wiki_page_events']
+ releases_events = module.params['releases_events']
enable_ssl_verification = module.params['hook_validate_certs']
hook_token = module.params['token']
- gitlab_instance = gitlab_authentication(module)
-
gitlab_hook = GitLabHook(module, gitlab_instance)
project = find_project(gitlab_instance, project_identifier)
@@ -371,6 +377,7 @@ def main():
"job_events": job_events,
"pipeline_events": pipeline_events,
"wiki_page_events": wiki_page_events,
+ "releases_events": releases_events,
"enable_ssl_verification": enable_ssl_verification,
"token": hook_token,
}):
diff --git a/ansible_collections/community/general/plugins/modules/gitlab_instance_variable.py b/ansible_collections/community/general/plugins/modules/gitlab_instance_variable.py
new file mode 100644
index 000000000..cc2d812ca
--- /dev/null
+++ b/ansible_collections/community/general/plugins/modules/gitlab_instance_variable.py
@@ -0,0 +1,360 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2023, Benedikt Braunger (bebr@adm.ku.dk)
+# Based on code:
+# Copyright (c) 2020, Florent Madiot (scodeman@scode.io)
+# Copyright (c) 2019, Markus Bergholz (markuman@gmail.com)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+DOCUMENTATION = r'''
+module: gitlab_instance_variable
+short_description: Creates, updates, or deletes GitLab instance variables
+version_added: 7.1.0
+description:
+ - Creates a instance variable if it does not exist.
+ - When a instance variable does exist, its value will be updated if the values are different.
+ - Support for instance variables requires GitLab >= 13.0.
+ - Variables which are not mentioned in the modules options, but are present on the GitLab instance,
+ will either stay (O(purge=false)) or will be deleted (O(purge=true)).
+author:
+ - Benedikt Braunger (@benibr)
+requirements:
+ - python-gitlab python module
+extends_documentation_fragment:
+ - community.general.auth_basic
+ - community.general.gitlab
+ - community.general.attributes
+
+attributes:
+ check_mode:
+ support: full
+ diff_mode:
+ support: none
+
+options:
+ state:
+ description:
+ - Create or delete instance variable.
+ default: present
+ type: str
+ choices: ["present", "absent"]
+ purge:
+ description:
+ - When set to V(true), delete all variables which are not mentioned in the task.
+ default: false
+ type: bool
+ variables:
+ description:
+ - A list of dictionaries that represents CI/CD variables.
+ default: []
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description:
+ - The name of the variable.
+ type: str
+ required: true
+ value:
+ description:
+ - The variable value.
+ - Required when O(state=present).
+ type: str
+ masked:
+ description:
+ - Whether variable value is masked or not.
+ type: bool
+ default: false
+ protected:
+ description:
+ - Whether variable value is protected or not.
+ type: bool
+ default: false
+ variable_type:
+ description:
+ - Whether a variable is an environment variable (V(env_var)) or a file (V(file)).
+ type: str
+ choices: [ "env_var", "file" ]
+ default: env_var
+'''
+
+
+EXAMPLES = r'''
+- name: Set or update some CI/CD variables
+ community.general.gitlab_instance_variable:
+ api_url: https://gitlab.com
+ api_token: secret_access_token
+ purge: false
+ variables:
+ - name: ACCESS_KEY_ID
+ value: abc1312cba
+ - name: SECRET_ACCESS_KEY
+ value: 1337
+ masked: true
+ protected: true
+ variable_type: env_var
+
+- name: Delete one variable
+ community.general.gitlab_instance_variable:
+ api_url: https://gitlab.com
+ api_token: secret_access_token
+ state: absent
+ variables:
+ - name: ACCESS_KEY_ID
+'''
+
+RETURN = r'''
+instance_variable:
+ description: Four lists of the variablenames which were added, updated, removed or exist.
+ returned: always
+ type: dict
+ contains:
+ added:
+ description: A list of variables which were created.
+ returned: always
+ type: list
+ sample: ['ACCESS_KEY_ID', 'SECRET_ACCESS_KEY']
+ untouched:
+ description: A list of variables which exist.
+ returned: always
+ type: list
+ sample: ['ACCESS_KEY_ID', 'SECRET_ACCESS_KEY']
+ removed:
+ description: A list of variables which were deleted.
+ returned: always
+ type: list
+ sample: ['ACCESS_KEY_ID', 'SECRET_ACCESS_KEY']
+ updated:
+ description: A list pre-existing variables whose values have been set.
+ returned: always
+ type: list
+ sample: ['ACCESS_KEY_ID', 'SECRET_ACCESS_KEY']
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.api import basic_auth_argument_spec
+from ansible_collections.community.general.plugins.module_utils.gitlab import (
+ auth_argument_spec, gitlab_authentication, filter_returned_variables,
+ list_all_kwargs
+)
+
+
+class GitlabInstanceVariables(object):
+
+ def __init__(self, module, gitlab_instance):
+ self.instance = gitlab_instance
+ self._module = module
+
+ def list_all_instance_variables(self):
+ return list(self.instance.variables.list(**list_all_kwargs))
+
+ def create_variable(self, var_obj):
+ if self._module.check_mode:
+ return True
+ var = {
+ "key": var_obj.get('key'),
+ "value": var_obj.get('value'),
+ "masked": var_obj.get('masked'),
+ "protected": var_obj.get('protected'),
+ "variable_type": var_obj.get('variable_type'),
+ }
+
+ self.instance.variables.create(var)
+ return True
+
+ def update_variable(self, var_obj):
+ if self._module.check_mode:
+ return True
+ self.delete_variable(var_obj)
+ self.create_variable(var_obj)
+ return True
+
+ def delete_variable(self, var_obj):
+ if self._module.check_mode:
+ return True
+ self.instance.variables.delete(var_obj.get('key'))
+ return True
+
+
+def compare(requested_variables, existing_variables, state):
+ # we need to do this, because it was determined in a previous version - more or less buggy
+ # basically it is not necessary and might results in more/other bugs!
+ # but it is required and only relevant for check mode!!
+ # logic represents state 'present' when not purge. all other can be derived from that
+ # untouched => equal in both
+ # updated => name and scope are equal
+ # added => name and scope does not exist
+ untouched = list()
+ updated = list()
+ added = list()
+
+ if state == 'present':
+ existing_key_scope_vars = list()
+ for item in existing_variables:
+ existing_key_scope_vars.append({'key': item.get('key')})
+
+ for var in requested_variables:
+ if var in existing_variables:
+ untouched.append(var)
+ else:
+ compare_item = {'key': var.get('name')}
+ if compare_item in existing_key_scope_vars:
+ updated.append(var)
+ else:
+ added.append(var)
+
+ return untouched, updated, added
+
+
+def native_python_main(this_gitlab, purge, requested_variables, state, module):
+
+ change = False
+ return_value = dict(added=list(), updated=list(), removed=list(), untouched=list())
+
+ gitlab_keys = this_gitlab.list_all_instance_variables()
+ before = [x.attributes for x in gitlab_keys]
+
+ existing_variables = filter_returned_variables(gitlab_keys)
+
+ for item in requested_variables:
+ item['key'] = item.pop('name')
+ item['value'] = str(item.get('value'))
+ if item.get('protected') is None:
+ item['protected'] = False
+ if item.get('masked') is None:
+ item['masked'] = False
+ if item.get('variable_type') is None:
+ item['variable_type'] = 'env_var'
+
+ if module.check_mode:
+ untouched, updated, added = compare(requested_variables, existing_variables, state)
+
+ if state == 'present':
+ add_or_update = [x for x in requested_variables if x not in existing_variables]
+ for item in add_or_update:
+ try:
+ if this_gitlab.create_variable(item):
+ return_value['added'].append(item)
+
+ except Exception:
+ if this_gitlab.update_variable(item):
+ return_value['updated'].append(item)
+
+ if purge:
+ # refetch and filter
+ gitlab_keys = this_gitlab.list_all_instance_variables()
+ existing_variables = filter_returned_variables(gitlab_keys)
+
+ remove = [x for x in existing_variables if x not in requested_variables]
+ for item in remove:
+ if this_gitlab.delete_variable(item):
+ return_value['removed'].append(item)
+
+ elif state == 'absent':
+ # value does not matter on removing variables.
+ # key and environment scope are sufficient
+ for item in existing_variables:
+ item.pop('value')
+ item.pop('variable_type')
+ for item in requested_variables:
+ item.pop('value')
+ item.pop('variable_type')
+
+ if not purge:
+ remove_requested = [x for x in requested_variables if x in existing_variables]
+ for item in remove_requested:
+ if this_gitlab.delete_variable(item):
+ return_value['removed'].append(item)
+
+ else:
+ for item in existing_variables:
+ if this_gitlab.delete_variable(item):
+ return_value['removed'].append(item)
+
+ if module.check_mode:
+ return_value = dict(added=added, updated=updated, removed=return_value['removed'], untouched=untouched)
+
+ if len(return_value['added'] + return_value['removed'] + return_value['updated']) > 0:
+ change = True
+
+ gitlab_keys = this_gitlab.list_all_instance_variables()
+ after = [x.attributes for x in gitlab_keys]
+
+ return change, return_value, before, after
+
+
+def main():
+ argument_spec = basic_auth_argument_spec()
+ argument_spec.update(auth_argument_spec())
+ argument_spec.update(
+ purge=dict(type='bool', required=False, default=False),
+ variables=dict(type='list', elements='dict', required=False, default=list(), options=dict(
+ name=dict(type='str', required=True),
+ value=dict(type='str', no_log=True),
+ masked=dict(type='bool', default=False),
+ protected=dict(type='bool', default=False),
+ variable_type=dict(type='str', default='env_var', choices=["env_var", "file"])
+ )),
+ state=dict(type='str', default="present", choices=["absent", "present"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ mutually_exclusive=[
+ ['api_username', 'api_token'],
+ ['api_username', 'api_oauth_token'],
+ ['api_username', 'api_job_token'],
+ ['api_token', 'api_oauth_token'],
+ ['api_token', 'api_job_token'],
+ ],
+ required_together=[
+ ['api_username', 'api_password'],
+ ],
+ required_one_of=[
+ ['api_username', 'api_token', 'api_oauth_token', 'api_job_token']
+ ],
+ supports_check_mode=True
+ )
+
+ # check prerequisites and connect to gitlab server
+ gitlab_instance = gitlab_authentication(module)
+
+ purge = module.params['purge']
+ state = module.params['state']
+
+ variables = module.params['variables']
+
+ if state == 'present':
+ if any(x['value'] is None for x in variables):
+ module.fail_json(msg='value parameter is required in state present')
+
+ this_gitlab = GitlabInstanceVariables(module=module, gitlab_instance=gitlab_instance)
+
+ changed, raw_return_value, before, after = native_python_main(this_gitlab, purge, variables, state, module)
+
+ # postprocessing
+ for item in after:
+ item['name'] = item.pop('key')
+ for item in before:
+ item['name'] = item.pop('key')
+
+ untouched_key_name = 'key'
+ if not module.check_mode:
+ untouched_key_name = 'name'
+ raw_return_value['untouched'] = [x for x in before if x in after]
+
+ added = [x.get('key') for x in raw_return_value['added']]
+ updated = [x.get('key') for x in raw_return_value['updated']]
+ removed = [x.get('key') for x in raw_return_value['removed']]
+ untouched = [x.get(untouched_key_name) for x in raw_return_value['untouched']]
+ return_value = dict(added=added, updated=updated, removed=removed, untouched=untouched)
+
+ module.exit_json(changed=changed, instance_variable=return_value)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/general/plugins/modules/gitlab_issue.py b/ansible_collections/community/general/plugins/modules/gitlab_issue.py
new file mode 100644
index 000000000..6d95bf6cf
--- /dev/null
+++ b/ansible_collections/community/general/plugins/modules/gitlab_issue.py
@@ -0,0 +1,408 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2023, Ondrej Zvara (ozvara1@gmail.com)
+# Based on code:
+# Copyright (c) 2021, Lennert Mertens (lennert@nubera.be)
+# Copyright (c) 2021, Werner Dijkerman (ikben@werner-dijkerman.nl)
+# Copyright (c) 2015, Werner Dijkerman (ikben@werner-dijkerman.nl)
+# Copyright (c) 2019, Guillaume Martinez (lunik@tiwabbit.fr)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+DOCUMENTATION = '''
+module: gitlab_issue
+short_description: Create, update, or delete GitLab issues
+version_added: '8.1.0'
+description:
+ - Creates an issue if it does not exist.
+ - When an issue does exist, it will be updated if the provided parameters are different.
+ - When an issue does exist and O(state=absent), the issue will be deleted.
+ - When multiple issues are detected, the task fails.
+ - Existing issues are matched based on O(title) and O(state_filter) filters.
+author:
+ - zvaraondrej (@zvaraondrej)
+requirements:
+ - python-gitlab >= 2.3.0
+extends_documentation_fragment:
+ - community.general.auth_basic
+ - community.general.gitlab
+ - community.general.attributes
+
+attributes:
+ check_mode:
+ support: full
+ diff_mode:
+ support: none
+
+options:
+ assignee_ids:
+ description:
+ - A list of assignee usernames omitting V(@) character.
+ - Set to an empty array to unassign all assignees.
+ type: list
+ elements: str
+ description:
+ description:
+ - A description of the issue.
+ - Gets overridden by a content of file specified at O(description_path), if found.
+ type: str
+ description_path:
+ description:
+ - A path of file containing issue's description.
+ - Accepts MarkDown formatted files.
+ type: path
+ issue_type:
+ description:
+ - Type of the issue.
+ default: issue
+ type: str
+ choices: ["issue", "incident", "test_case"]
+ labels:
+ description:
+ - A list of label names.
+ - Set to an empty array to remove all labels.
+ type: list
+ elements: str
+ milestone_search:
+ description:
+ - The name of the milestone.
+ - Set to empty string to unassign milestone.
+ type: str
+ milestone_group_id:
+ description:
+ - The path or numeric ID of the group hosting desired milestone.
+ type: str
+ project:
+ description:
+ - The path or name of the project.
+ required: true
+ type: str
+ state:
+ description:
+ - Create or delete issue.
+ default: present
+ type: str
+ choices: ["present", "absent"]
+ state_filter:
+ description:
+ - Filter specifying state of issues while searching.
+ type: str
+ choices: ["opened", "closed"]
+ default: opened
+ title:
+ description:
+ - A title for the issue. The title is used as a unique identifier to ensure idempotency.
+ type: str
+ required: true
+'''
+
+
+EXAMPLES = '''
+- name: Create Issue
+ community.general.gitlab_issue:
+ api_url: https://gitlab.com
+ api_token: secret_access_token
+ project: "group1/project1"
+ title: "Ansible demo Issue"
+ description: "Demo Issue description"
+ labels:
+ - Ansible
+ - Demo
+ assignee_ids:
+ - testassignee
+ state_filter: "opened"
+ state: present
+
+- name: Delete Issue
+ community.general.gitlab_issue:
+ api_url: https://gitlab.com
+ api_token: secret_access_token
+ project: "group1/project1"
+ title: "Ansible demo Issue"
+ state_filter: "opened"
+ state: absent
+'''
+
+RETURN = r'''
+msg:
+ description: Success or failure message.
+ returned: always
+ type: str
+ sample: "Success"
+
+issue:
+ description: API object.
+ returned: success
+ type: dict
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.api import basic_auth_argument_spec
+from ansible.module_utils.common.text.converters import to_native, to_text
+
+from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
+from ansible_collections.community.general.plugins.module_utils.gitlab import (
+ auth_argument_spec, gitlab_authentication, gitlab, find_project, find_group
+)
+
+
+class GitlabIssue(object):
+
+ def __init__(self, module, project, gitlab_instance):
+ self._gitlab = gitlab_instance
+ self._module = module
+ self.project = project
+
+ '''
+ @param milestone_id Title of the milestone
+ '''
+ def get_milestone(self, milestone_id, group):
+ milestones = []
+ try:
+ milestones = group.milestones.list(search=milestone_id)
+ except gitlab.exceptions.GitlabGetError as e:
+ self._module.fail_json(msg="Failed to list the Milestones: %s" % to_native(e))
+
+ if len(milestones) > 1:
+ self._module.fail_json(msg="Multiple Milestones matched search criteria.")
+ if len(milestones) < 1:
+ self._module.fail_json(msg="No Milestones matched search criteria.")
+ if len(milestones) == 1:
+ try:
+ return group.milestones.get(id=milestones[0].id)
+ except gitlab.exceptions.GitlabGetError as e:
+ self._module.fail_json(msg="Failed to get the Milestones: %s" % to_native(e))
+
+ '''
+ @param title Title of the Issue
+ @param state_filter Issue's state to filter on
+ '''
+ def get_issue(self, title, state_filter):
+ issues = []
+ try:
+ issues = self.project.issues.list(query_parameters={"search": title, "in": "title", "state": state_filter})
+ except gitlab.exceptions.GitlabGetError as e:
+ self._module.fail_json(msg="Failed to list the Issues: %s" % to_native(e))
+
+ if len(issues) > 1:
+ self._module.fail_json(msg="Multiple Issues matched search criteria.")
+ if len(issues) == 1:
+ try:
+ return self.project.issues.get(id=issues[0].iid)
+ except gitlab.exceptions.GitlabGetError as e:
+ self._module.fail_json(msg="Failed to get the Issue: %s" % to_native(e))
+
+ '''
+ @param username Name of the user
+ '''
+ def get_user(self, username):
+ users = []
+ try:
+ users = [user for user in self.project.users.list(username=username, all=True) if user.username == username]
+ except gitlab.exceptions.GitlabGetError as e:
+ self._module.fail_json(msg="Failed to list the users: %s" % to_native(e))
+
+ if len(users) > 1:
+ self._module.fail_json(msg="Multiple Users matched search criteria.")
+ elif len(users) < 1:
+ self._module.fail_json(msg="No User matched search criteria.")
+ else:
+ return users[0]
+
+ '''
+ @param users List of usernames
+ '''
+ def get_user_ids(self, users):
+ return [self.get_user(user).id for user in users]
+
+ '''
+ @param options Options of the Issue
+ '''
+ def create_issue(self, options):
+ if self._module.check_mode:
+ self._module.exit_json(changed=True, msg="Successfully created Issue '%s'." % options["title"])
+
+ try:
+ return self.project.issues.create(options)
+ except gitlab.exceptions.GitlabCreateError as e:
+ self._module.fail_json(msg="Failed to create Issue: %s " % to_native(e))
+
+ '''
+ @param issue Issue object to delete
+ '''
+ def delete_issue(self, issue):
+ if self._module.check_mode:
+ self._module.exit_json(changed=True, msg="Successfully deleted Issue '%s'." % issue["title"])
+
+ try:
+ return issue.delete()
+ except gitlab.exceptions.GitlabDeleteError as e:
+ self._module.fail_json(msg="Failed to delete Issue: '%s'." % to_native(e))
+
+ '''
+ @param issue Issue object to update
+ @param options Options of the Issue
+ '''
+ def update_issue(self, issue, options):
+ if self._module.check_mode:
+ self._module.exit_json(changed=True, msg="Successfully updated Issue '%s'." % issue["title"])
+
+ try:
+ return self.project.issues.update(issue.iid, options)
+ except gitlab.exceptions.GitlabUpdateError as e:
+ self._module.fail_json(msg="Failed to update Issue %s." % to_native(e))
+
+ '''
+ @param issue Issue object to evaluate
+ @param options New options to update Issue with
+ '''
+ def issue_has_changed(self, issue, options):
+ for key, value in options.items():
+ if value is not None:
+
+ if key == 'milestone_id':
+ old_milestone = getattr(issue, 'milestone')['id'] if getattr(issue, 'milestone') else ""
+ if options[key] != old_milestone:
+ return True
+ elif key == 'assignee_ids':
+ if options[key] != sorted([user["id"] for user in getattr(issue, 'assignees')]):
+ return True
+
+ elif key == 'labels':
+ if options[key] != sorted(getattr(issue, key)):
+ return True
+
+ elif getattr(issue, key) != value:
+ return True
+
+ return False
+
+
+def main():
+ argument_spec = basic_auth_argument_spec()
+ argument_spec.update(auth_argument_spec())
+ argument_spec.update(
+ assignee_ids=dict(type='list', elements='str', required=False),
+ description=dict(type='str', required=False),
+ description_path=dict(type='path', required=False),
+ issue_type=dict(type='str', default='issue', choices=["issue", "incident", "test_case"], required=False),
+ labels=dict(type='list', elements='str', required=False),
+ milestone_search=dict(type='str', required=False),
+ milestone_group_id=dict(type='str', required=False),
+ project=dict(type='str', required=True),
+ state=dict(type='str', default="present", choices=["absent", "present"]),
+ state_filter=dict(type='str', default="opened", choices=["opened", "closed"]),
+ title=dict(type='str', required=True),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ mutually_exclusive=[
+ ['api_username', 'api_token'],
+ ['api_username', 'api_oauth_token'],
+ ['api_username', 'api_job_token'],
+ ['api_token', 'api_oauth_token'],
+ ['api_token', 'api_job_token'],
+ ['description', 'description_path'],
+ ],
+ required_together=[
+ ['api_username', 'api_password'],
+ ['milestone_search', 'milestone_group_id'],
+ ],
+ required_one_of=[
+ ['api_username', 'api_token', 'api_oauth_token', 'api_job_token']
+ ],
+ supports_check_mode=True
+ )
+
+ assignee_ids = module.params['assignee_ids']
+ description = module.params['description']
+ description_path = module.params['description_path']
+ issue_type = module.params['issue_type']
+ labels = module.params['labels']
+ milestone_id = module.params['milestone_search']
+ milestone_group_id = module.params['milestone_group_id']
+ project = module.params['project']
+ state = module.params['state']
+ state_filter = module.params['state_filter']
+ title = module.params['title']
+
+ gitlab_version = gitlab.__version__
+ if LooseVersion(gitlab_version) < LooseVersion('2.3.0'):
+ module.fail_json(msg="community.general.gitlab_issue requires python-gitlab Python module >= 2.3.0 (installed version: [%s])."
+ " Please upgrade python-gitlab to version 2.3.0 or above." % gitlab_version)
+
+ # check prerequisites and connect to gitlab server
+ gitlab_instance = gitlab_authentication(module)
+
+ this_project = find_project(gitlab_instance, project)
+ if this_project is None:
+ module.fail_json(msg="Failed to get the project: %s" % project)
+
+ this_gitlab = GitlabIssue(module=module, project=this_project, gitlab_instance=gitlab_instance)
+
+ if milestone_id and milestone_group_id:
+ this_group = find_group(gitlab_instance, milestone_group_id)
+ if this_group is None:
+ module.fail_json(msg="Failed to get the group: %s" % milestone_group_id)
+
+ milestone_id = this_gitlab.get_milestone(milestone_id, this_group).id
+
+ this_issue = this_gitlab.get_issue(title, state_filter)
+
+ if state == "present":
+ if description_path:
+ try:
+ with open(description_path, 'rb') as f:
+ description = to_text(f.read(), errors='surrogate_or_strict')
+ except IOError as e:
+ module.fail_json(msg='Cannot open {0}: {1}'.format(description_path, e))
+
+ # sorting necessary in order to properly detect changes, as we don't want to get false positive
+ # results due to differences in ids ordering;
+ assignee_ids = sorted(this_gitlab.get_user_ids(assignee_ids)) if assignee_ids else assignee_ids
+ labels = sorted(labels) if labels else labels
+
+ options = {
+ "title": title,
+ "description": description,
+ "labels": labels,
+ "issue_type": issue_type,
+ "milestone_id": milestone_id,
+ "assignee_ids": assignee_ids,
+ }
+
+ if not this_issue:
+ issue = this_gitlab.create_issue(options)
+ module.exit_json(
+ changed=True, msg="Created Issue '{t}'.".format(t=title),
+ issue=issue.asdict()
+ )
+ else:
+ if this_gitlab.issue_has_changed(this_issue, options):
+ issue = this_gitlab.update_issue(this_issue, options)
+ module.exit_json(
+ changed=True, msg="Updated Issue '{t}'.".format(t=title),
+ issue=issue
+ )
+ else:
+ module.exit_json(
+ changed=False, msg="Issue '{t}' already exists".format(t=title),
+ issue=this_issue.asdict()
+ )
+ elif state == "absent":
+ if not this_issue:
+ module.exit_json(changed=False, msg="Issue '{t}' does not exist or has already been deleted.".format(t=title))
+ else:
+ issue = this_gitlab.delete_issue(this_issue)
+ module.exit_json(
+ changed=True, msg="Issue '{t}' deleted.".format(t=title),
+ issue=issue
+ )
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/general/plugins/modules/gitlab_label.py b/ansible_collections/community/general/plugins/modules/gitlab_label.py
new file mode 100644
index 000000000..f2c8393f2
--- /dev/null
+++ b/ansible_collections/community/general/plugins/modules/gitlab_label.py
@@ -0,0 +1,500 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2023, Gabriele Pongelli (gabriele.pongelli@gmail.com)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+DOCUMENTATION = '''
+module: gitlab_label
+short_description: Creates/updates/deletes GitLab Labels belonging to project or group.
+version_added: 8.3.0
+description:
+ - When a label does not exist, it will be created.
+ - When a label does exist, its value will be updated when the values are different.
+ - Labels can be purged.
+author:
+ - "Gabriele Pongelli (@gpongelli)"
+requirements:
+ - python-gitlab python module
+extends_documentation_fragment:
+ - community.general.auth_basic
+ - community.general.gitlab
+ - community.general.attributes
+
+attributes:
+ check_mode:
+ support: full
+ diff_mode:
+ support: none
+
+options:
+ state:
+ description:
+ - Create or delete project or group label.
+ default: present
+ type: str
+ choices: ["present", "absent"]
+ purge:
+ description:
+ - When set to V(true), delete all labels which are not mentioned in the task.
+ default: false
+ type: bool
+ required: false
+ project:
+ description:
+ - The path and name of the project. Either this or O(group) is required.
+ required: false
+ type: str
+ group:
+ description:
+ - The path of the group. Either this or O(project) is required.
+ required: false
+ type: str
+ labels:
+ description:
+ - A list of dictionaries that represents gitlab project's or group's labels.
+ type: list
+ elements: dict
+ required: false
+ default: []
+ suboptions:
+ name:
+ description:
+ - The name of the label.
+ type: str
+ required: true
+ color:
+ description:
+ - The color of the label.
+ - Required when O(state=present).
+ type: str
+ priority:
+ description:
+ - Integer value to give priority to the label.
+ type: int
+ required: false
+ default: null
+ description:
+ description:
+ - Label's description.
+ type: str
+ default: null
+ new_name:
+ description:
+ - Optional field to change label's name.
+ type: str
+ default: null
+'''
+
+
+EXAMPLES = '''
+# same project's task can be executed for group
+- name: Create one Label
+ community.general.gitlab_label:
+ api_url: https://gitlab.com
+ api_token: secret_access_token
+ project: "group1/project1"
+ labels:
+ - name: label_one
+ color: "#123456"
+ state: present
+
+- name: Create many group labels
+ community.general.gitlab_label:
+ api_url: https://gitlab.com
+ api_token: secret_access_token
+ group: "group1"
+ labels:
+ - name: label_one
+ color: "#123456"
+ description: this is a label
+ priority: 20
+ - name: label_two
+ color: "#554422"
+ state: present
+
+- name: Create many project labels
+ community.general.gitlab_label:
+ api_url: https://gitlab.com
+ api_token: secret_access_token
+ project: "group1/project1"
+ labels:
+ - name: label_one
+ color: "#123456"
+ description: this is a label
+ priority: 20
+ - name: label_two
+ color: "#554422"
+ state: present
+
+- name: Set or update some labels
+ community.general.gitlab_label:
+ api_url: https://gitlab.com
+ api_token: secret_access_token
+ project: "group1/project1"
+ labels:
+ - name: label_one
+ color: "#224488"
+ state: present
+
+- name: Add label in check mode
+ community.general.gitlab_label:
+ api_url: https://gitlab.com
+ api_token: secret_access_token
+ project: "group1/project1"
+ labels:
+ - name: label_one
+ color: "#224488"
+ check_mode: true
+
+- name: Delete Label
+ community.general.gitlab_label:
+ api_url: https://gitlab.com
+ api_token: secret_access_token
+ project: "group1/project1"
+ labels:
+ - name: label_one
+ state: absent
+
+- name: Change Label name
+ community.general.gitlab_label:
+ api_url: https://gitlab.com
+ api_token: secret_access_token
+ project: "group1/project1"
+ labels:
+ - name: label_one
+ new_name: label_two
+ state: absent
+
+- name: Purge all labels
+ community.general.gitlab_label:
+ api_url: https://gitlab.com
+ api_token: secret_access_token
+ project: "group1/project1"
+ purge: true
+
+- name: Delete many labels
+ community.general.gitlab_label:
+ api_url: https://gitlab.com
+ api_token: secret_access_token
+ project: "group1/project1"
+ state: absent
+ labels:
+ - name: label-abc123
+ - name: label-two
+'''
+
+RETURN = '''
+labels:
+ description: Four lists of the labels which were added, updated, removed or exist.
+ returned: success
+ type: dict
+ contains:
+ added:
+ description: A list of labels which were created.
+ returned: always
+ type: list
+ sample: ['abcd', 'label-one']
+ untouched:
+ description: A list of labels which exist.
+ returned: always
+ type: list
+ sample: ['defg', 'new-label']
+ removed:
+ description: A list of labels which were deleted.
+ returned: always
+ type: list
+ sample: ['defg', 'new-label']
+ updated:
+ description: A list pre-existing labels whose values have been set.
+ returned: always
+ type: list
+ sample: ['defg', 'new-label']
+labels_obj:
+ description: API object.
+ returned: success
+ type: dict
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.api import basic_auth_argument_spec
+
+from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
+from ansible_collections.community.general.plugins.module_utils.gitlab import (
+ auth_argument_spec, gitlab_authentication, ensure_gitlab_package, find_group, find_project, gitlab
+)
+
+
+class GitlabLabels(object):
+
+ def __init__(self, module, gitlab_instance, group_id, project_id):
+ self._gitlab = gitlab_instance
+ self.gitlab_object = group_id if group_id else project_id
+ self.is_group_label = True if group_id else False
+ self._module = module
+
+ def list_all_labels(self):
+ page_nb = 1
+ labels = []
+ vars_page = self.gitlab_object.labels.list(page=page_nb)
+ while len(vars_page) > 0:
+ labels += vars_page
+ page_nb += 1
+ vars_page = self.gitlab_object.labels.list(page=page_nb)
+ return labels
+
+ def create_label(self, var_obj):
+ if self._module.check_mode:
+ return True, True
+
+ var = {
+ "name": var_obj.get('name'),
+ "color": var_obj.get('color'),
+ }
+
+ if var_obj.get('description') is not None:
+ var["description"] = var_obj.get('description')
+
+ if var_obj.get('priority') is not None:
+ var["priority"] = var_obj.get('priority')
+
+ _obj = self.gitlab_object.labels.create(var)
+ return True, _obj.asdict()
+
+ def update_label(self, var_obj):
+ if self._module.check_mode:
+ return True, True
+ _label = self.gitlab_object.labels.get(var_obj.get('name'))
+
+ if var_obj.get('new_name') is not None:
+ _label.new_name = var_obj.get('new_name')
+
+ if var_obj.get('description') is not None:
+ _label.description = var_obj.get('description')
+ if var_obj.get('priority') is not None:
+ _label.priority = var_obj.get('priority')
+
+ # save returns None
+ _label.save()
+ return True, _label.asdict()
+
+ def delete_label(self, var_obj):
+ if self._module.check_mode:
+ return True, True
+ _label = self.gitlab_object.labels.get(var_obj.get('name'))
+ # delete returns None
+ _label.delete()
+ return True, _label.asdict()
+
+
+def compare(requested_labels, existing_labels, state):
+ # we need to do this, because it was determined in a previous version - more or less buggy
+ # basically it is not necessary and might result in more/other bugs!
+ # but it is required and only relevant for check mode!!
+ # logic represents state 'present' when not purge. all other can be derived from that
+ # untouched => equal in both
+ # updated => name and scope are equal
+ # added => name and scope does not exist
+ untouched = list()
+ updated = list()
+ added = list()
+
+ if state == 'present':
+ _existing_labels = list()
+ for item in existing_labels:
+ _existing_labels.append({'name': item.get('name')})
+
+ for var in requested_labels:
+ if var in existing_labels:
+ untouched.append(var)
+ else:
+ compare_item = {'name': var.get('name')}
+ if compare_item in _existing_labels:
+ updated.append(var)
+ else:
+ added.append(var)
+
+ return untouched, updated, added
+
+
+def native_python_main(this_gitlab, purge, requested_labels, state, module):
+ change = False
+ return_value = dict(added=[], updated=[], removed=[], untouched=[])
+ return_obj = dict(added=[], updated=[], removed=[])
+
+ labels_before = [x.asdict() for x in this_gitlab.list_all_labels()]
+
+ # filter out and enrich before compare
+ for item in requested_labels:
+ # add defaults when not present
+ if item.get('description') is None:
+ item['description'] = ""
+ if item.get('new_name') is None:
+ item['new_name'] = None
+ if item.get('priority') is None:
+ item['priority'] = None
+
+ # group label does not have priority, removing for comparison
+ if this_gitlab.is_group_label:
+ item.pop('priority')
+
+ for item in labels_before:
+ # remove field only from server
+ item.pop('id')
+ item.pop('description_html')
+ item.pop('text_color')
+ item.pop('subscribed')
+ # field present only when it's a project's label
+ if 'is_project_label' in item:
+ item.pop('is_project_label')
+ item['new_name'] = None
+
+ if state == 'present':
+ add_or_update = [x for x in requested_labels if x not in labels_before]
+ for item in add_or_update:
+ try:
+ _rv, _obj = this_gitlab.create_label(item)
+ if _rv:
+ return_value['added'].append(item)
+ return_obj['added'].append(_obj)
+ except Exception:
+ # create raises exception with following error message when label already exists
+ _rv, _obj = this_gitlab.update_label(item)
+ if _rv:
+ return_value['updated'].append(item)
+ return_obj['updated'].append(_obj)
+
+ if purge:
+ # re-fetch
+ _labels = this_gitlab.list_all_labels()
+
+ for item in labels_before:
+ _rv, _obj = this_gitlab.delete_label(item)
+ if _rv:
+ return_value['removed'].append(item)
+ return_obj['removed'].append(_obj)
+
+ elif state == 'absent':
+ if not purge:
+ _label_names_requested = [x['name'] for x in requested_labels]
+ remove_requested = [x for x in labels_before if x['name'] in _label_names_requested]
+ for item in remove_requested:
+ _rv, _obj = this_gitlab.delete_label(item)
+ if _rv:
+ return_value['removed'].append(item)
+ return_obj['removed'].append(_obj)
+ else:
+ for item in labels_before:
+ _rv, _obj = this_gitlab.delete_label(item)
+ if _rv:
+ return_value['removed'].append(item)
+ return_obj['removed'].append(_obj)
+
+ if module.check_mode:
+ _untouched, _updated, _added = compare(requested_labels, labels_before, state)
+ return_value = dict(added=_added, updated=_updated, removed=return_value['removed'], untouched=_untouched)
+
+ if any(return_value[x] for x in ['added', 'removed', 'updated']):
+ change = True
+
+ labels_after = [x.asdict() for x in this_gitlab.list_all_labels()]
+
+ return change, return_value, labels_before, labels_after, return_obj
+
+
+def main():
+ argument_spec = basic_auth_argument_spec()
+ argument_spec.update(auth_argument_spec())
+ argument_spec.update(
+ project=dict(type='str', required=False, default=None),
+ group=dict(type='str', required=False, default=None),
+ purge=dict(type='bool', required=False, default=False),
+ labels=dict(type='list', elements='dict', required=False, default=list(),
+ options=dict(
+ name=dict(type='str', required=True),
+ color=dict(type='str', required=False),
+ description=dict(type='str', required=False),
+ priority=dict(type='int', required=False),
+ new_name=dict(type='str', required=False),)
+ ),
+ state=dict(type='str', default="present", choices=["absent", "present"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ mutually_exclusive=[
+ ['api_username', 'api_token'],
+ ['api_username', 'api_oauth_token'],
+ ['api_username', 'api_job_token'],
+ ['api_token', 'api_oauth_token'],
+ ['api_token', 'api_job_token'],
+ ['project', 'group'],
+ ],
+ required_together=[
+ ['api_username', 'api_password'],
+ ],
+ required_one_of=[
+ ['api_username', 'api_token', 'api_oauth_token', 'api_job_token'],
+ ['project', 'group']
+ ],
+ supports_check_mode=True
+ )
+ ensure_gitlab_package(module)
+
+ gitlab_project = module.params['project']
+ gitlab_group = module.params['group']
+ purge = module.params['purge']
+ label_list = module.params['labels']
+ state = module.params['state']
+
+ gitlab_version = gitlab.__version__
+ _min_gitlab = '3.2.0'
+ if LooseVersion(gitlab_version) < LooseVersion(_min_gitlab):
+ module.fail_json(msg="community.general.gitlab_label requires python-gitlab Python module >= %s "
+ "(installed version: [%s]). Please upgrade "
+ "python-gitlab to version %s or above." % (_min_gitlab, gitlab_version, _min_gitlab))
+
+ gitlab_instance = gitlab_authentication(module)
+
+ # find_project can return None, but the other must exist
+ gitlab_project_id = find_project(gitlab_instance, gitlab_project)
+
+ # find_group can return None, but the other must exist
+ gitlab_group_id = find_group(gitlab_instance, gitlab_group)
+
+ # if both not found, module must exist
+ if not gitlab_project_id and not gitlab_group_id:
+ if gitlab_project and not gitlab_project_id:
+ module.fail_json(msg="project '%s' not found." % gitlab_project)
+ if gitlab_group and not gitlab_group_id:
+ module.fail_json(msg="group '%s' not found." % gitlab_group)
+
+ this_gitlab = GitlabLabels(module=module, gitlab_instance=gitlab_instance, group_id=gitlab_group_id,
+ project_id=gitlab_project_id)
+
+ if state == 'present':
+ _existing_labels = [x.asdict()['name'] for x in this_gitlab.list_all_labels()]
+
+ # color is mandatory when creating label, but it's optional when changing name or updating other fields
+ if any(x['color'] is None and x['new_name'] is None and x['name'] not in _existing_labels for x in label_list):
+ module.fail_json(msg='color parameter is required for new labels')
+
+ change, raw_return_value, before, after, _obj = native_python_main(this_gitlab, purge, label_list, state, module)
+
+ if not module.check_mode:
+ raw_return_value['untouched'] = [x for x in before if x in after]
+
+ added = [x.get('name') for x in raw_return_value['added']]
+ updated = [x.get('name') for x in raw_return_value['updated']]
+ removed = [x.get('name') for x in raw_return_value['removed']]
+ untouched = [x.get('name') for x in raw_return_value['untouched']]
+ return_value = dict(added=added, updated=updated, removed=removed, untouched=untouched)
+
+ module.exit_json(changed=change, labels=return_value, labels_obj=_obj)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/general/plugins/modules/gitlab_merge_request.py b/ansible_collections/community/general/plugins/modules/gitlab_merge_request.py
new file mode 100644
index 000000000..5bb9cb9c7
--- /dev/null
+++ b/ansible_collections/community/general/plugins/modules/gitlab_merge_request.py
@@ -0,0 +1,416 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2023, Ondrej Zvara (ozvara1@gmail.com)
+# Based on code:
+# Copyright (c) 2021, Lennert Mertens (lennert@nubera.be)
+# Copyright (c) 2021, Werner Dijkerman (ikben@werner-dijkerman.nl)
+# Copyright (c) 2015, Werner Dijkerman (ikben@werner-dijkerman.nl)
+# Copyright (c) 2019, Guillaume Martinez (lunik@tiwabbit.fr)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+DOCUMENTATION = '''
+module: gitlab_merge_request
+short_description: Create, update, or delete GitLab merge requests
+version_added: 7.1.0
+description:
+ - Creates a merge request if it does not exist.
+ - When a single merge request does exist, it will be updated if the provided parameters are different.
+ - When a single merge request does exist and O(state=absent), the merge request will be deleted.
+ - When multiple merge requests are detected, the task fails.
+ - Existing merge requests are matched based on O(title), O(source_branch), O(target_branch),
+ and O(state_filter) filters.
+author:
+ - zvaraondrej (@zvaraondrej)
+requirements:
+ - python-gitlab >= 2.3.0
+extends_documentation_fragment:
+ - community.general.auth_basic
+ - community.general.gitlab
+ - community.general.attributes
+
+attributes:
+ check_mode:
+ support: full
+ diff_mode:
+ support: none
+
+options:
+ state:
+ description:
+ - Create or delete merge request.
+ default: present
+ type: str
+ choices: ["present", "absent"]
+ project:
+ description:
+ - The path or name of the project.
+ required: true
+ type: str
+ source_branch:
+ description:
+ - Merge request's source branch.
+ - Ignored while updating existing merge request.
+ required: true
+ type: str
+ target_branch:
+ description:
+ - Merge request's target branch.
+ required: true
+ type: str
+ title:
+ description:
+ - A title for the merge request.
+ type: str
+ required: true
+ description:
+ description:
+ - A description for the merge request.
+ - Gets overridden by a content of file specified at O(description_path), if found.
+ type: str
+ description_path:
+ description:
+ - A path of file containing merge request's description.
+ - Accepts MarkDown formatted files.
+ type: path
+ labels:
+ description:
+ - Comma separated list of label names.
+ type: str
+ default: ""
+ remove_source_branch:
+ description:
+ - Flag indicating if a merge request should remove the source branch when merging.
+ type: bool
+ default: false
+ state_filter:
+ description:
+ - Filter specifying state of merge requests while searching.
+ type: str
+ choices: ["opened", "closed", "locked", "merged"]
+ default: opened
+ assignee_ids:
+ description:
+ - Comma separated list of assignees usernames omitting V(@) character.
+ - Set to empty string to unassign all assignees.
+ type: str
+ reviewer_ids:
+ description:
+ - Comma separated list of reviewers usernames omitting V(@) character.
+ - Set to empty string to unassign all reviewers.
+ type: str
+'''
+
+
+EXAMPLES = '''
+- name: Create Merge Request from branch1 to branch2
+ community.general.gitlab_merge_request:
+ api_url: https://gitlab.com
+ api_token: secret_access_token
+ project: "group1/project1"
+ source_branch: branch1
+ target_branch: branch2
+ title: "Ansible demo MR"
+ description: "Demo MR description"
+ labels: "Ansible,Demo"
+ state_filter: "opened"
+ remove_source_branch: True
+ state: present
+
+- name: Delete Merge Request from branch1 to branch2
+ community.general.gitlab_merge_request:
+ api_url: https://gitlab.com
+ api_token: secret_access_token
+ project: "group1/project1"
+ source_branch: branch1
+ target_branch: branch2
+ title: "Ansible demo MR"
+ state_filter: "opened"
+ state: absent
+'''
+
+RETURN = r'''
+msg:
+ description: Success or failure message.
+ returned: always
+ type: str
+ sample: "Success"
+
+mr:
+ description: API object.
+ returned: success
+ type: dict
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.api import basic_auth_argument_spec
+from ansible.module_utils.common.text.converters import to_native, to_text
+
+from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
+from ansible_collections.community.general.plugins.module_utils.gitlab import (
+ auth_argument_spec, gitlab_authentication, gitlab, find_project
+)
+
+
+class GitlabMergeRequest(object):
+
+ def __init__(self, module, project, gitlab_instance):
+ self._gitlab = gitlab_instance
+ self._module = module
+ self.project = project
+
+ '''
+ @param branch Name of the branch
+ '''
+ def get_branch(self, branch):
+ try:
+ return self.project.branches.get(branch)
+ except gitlab.exceptions.GitlabGetError as e:
+ self._module.fail_json(msg="Failed to get the branch: %s" % to_native(e))
+
+ '''
+ @param title Title of the Merge Request
+ @param source_branch Merge Request's source branch
+ @param target_branch Merge Request's target branch
+ @param state_filter Merge Request's state to filter on
+ '''
+ def get_mr(self, title, source_branch, target_branch, state_filter):
+ mrs = []
+ try:
+ mrs = self.project.mergerequests.list(search=title, source_branch=source_branch, target_branch=target_branch, state=state_filter)
+ except gitlab.exceptions.GitlabGetError as e:
+ self._module.fail_json(msg="Failed to list the Merge Request: %s" % to_native(e))
+
+ if len(mrs) > 1:
+ self._module.fail_json(msg="Multiple Merge Requests matched search criteria.")
+ if len(mrs) == 1:
+ try:
+ return self.project.mergerequests.get(id=mrs[0].iid)
+ except gitlab.exceptions.GitlabGetError as e:
+ self._module.fail_json(msg="Failed to get the Merge Request: %s" % to_native(e))
+
+ '''
+ @param username Name of the user
+ '''
+ def get_user(self, username):
+ users = []
+ try:
+ users = [user for user in self.project.users.list(username=username, all=True) if user.username == username]
+ except gitlab.exceptions.GitlabGetError as e:
+ self._module.fail_json(msg="Failed to list the users: %s" % to_native(e))
+
+ if len(users) > 1:
+ self._module.fail_json(msg="Multiple Users matched search criteria.")
+ elif len(users) < 1:
+ self._module.fail_json(msg="No User matched search criteria.")
+ else:
+ return users[0]
+
+ '''
+ @param users List of usernames
+ '''
+ def get_user_ids(self, users):
+ return [self.get_user(user).id for user in users]
+
+ '''
+ @param options Options of the Merge Request
+ '''
+ def create_mr(self, options):
+ if self._module.check_mode:
+ self._module.exit_json(changed=True, msg="Successfully created the Merge Request %s" % options["title"])
+
+ try:
+ return self.project.mergerequests.create(options)
+ except gitlab.exceptions.GitlabCreateError as e:
+ self._module.fail_json(msg="Failed to create Merge Request: %s " % to_native(e))
+
+ '''
+ @param mr Merge Request object to delete
+ '''
+ def delete_mr(self, mr):
+ if self._module.check_mode:
+ self._module.exit_json(changed=True, msg="Successfully deleted the Merge Request %s" % mr["title"])
+
+ try:
+ return mr.delete()
+ except gitlab.exceptions.GitlabDeleteError as e:
+ self._module.fail_json(msg="Failed to delete Merge Request: %s " % to_native(e))
+
+ '''
+ @param mr Merge Request object to update
+ '''
+ def update_mr(self, mr, options):
+ if self._module.check_mode:
+ self._module.exit_json(changed=True, msg="Successfully updated the Merge Request %s" % mr["title"])
+
+ try:
+ return self.project.mergerequests.update(mr.iid, options)
+ except gitlab.exceptions.GitlabUpdateError as e:
+ self._module.fail_json(msg="Failed to update Merge Request: %s " % to_native(e))
+
+ '''
+ @param mr Merge Request object to evaluate
+ @param options New options to update MR with
+ '''
+ def mr_has_changed(self, mr, options):
+ for key, value in options.items():
+ if value is not None:
+ # see https://gitlab.com/gitlab-org/gitlab-foss/-/issues/27355
+ if key == 'remove_source_branch':
+ key = 'force_remove_source_branch'
+
+ if key == 'assignee_ids':
+ if options[key] != sorted([user["id"] for user in getattr(mr, 'assignees')]):
+ return True
+
+ elif key == 'reviewer_ids':
+ if options[key] != sorted([user["id"] for user in getattr(mr, 'reviewers')]):
+ return True
+
+ elif key == 'labels':
+ if options[key] != sorted(getattr(mr, key)):
+ return True
+
+ elif getattr(mr, key) != value:
+ return True
+
+ return False
+
+
+def main():
+ argument_spec = basic_auth_argument_spec()
+ argument_spec.update(auth_argument_spec())
+ argument_spec.update(
+ project=dict(type='str', required=True),
+ source_branch=dict(type='str', required=True),
+ target_branch=dict(type='str', required=True),
+ title=dict(type='str', required=True),
+ description=dict(type='str', required=False),
+ labels=dict(type='str', default="", required=False),
+ description_path=dict(type='path', required=False),
+ remove_source_branch=dict(type='bool', default=False, required=False),
+ state_filter=dict(type='str', default="opened", choices=["opened", "closed", "locked", "merged"]),
+ assignee_ids=dict(type='str', required=False),
+ reviewer_ids=dict(type='str', required=False),
+ state=dict(type='str', default="present", choices=["absent", "present"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ mutually_exclusive=[
+ ['api_username', 'api_token'],
+ ['api_username', 'api_oauth_token'],
+ ['api_username', 'api_job_token'],
+ ['api_token', 'api_oauth_token'],
+ ['api_token', 'api_job_token'],
+ ['description', 'description_path'],
+ ],
+ required_together=[
+ ['api_username', 'api_password'],
+ ],
+ required_one_of=[
+ ['api_username', 'api_token', 'api_oauth_token', 'api_job_token']
+ ],
+ required_if=[
+ ['state', 'present', ['source_branch', 'target_branch', 'title'], True],
+ ['state', 'absent', ['source_branch', 'target_branch', 'title'], True],
+ ],
+ supports_check_mode=True
+ )
+
+ # check prerequisites and connect to gitlab server
+ gitlab_instance = gitlab_authentication(module)
+
+ project = module.params['project']
+ source_branch = module.params['source_branch']
+ target_branch = module.params['target_branch']
+ title = module.params['title']
+ description = module.params['description']
+ labels = module.params['labels']
+ description_path = module.params['description_path']
+ remove_source_branch = module.params['remove_source_branch']
+ state_filter = module.params['state_filter']
+ assignee_ids = module.params['assignee_ids']
+ reviewer_ids = module.params['reviewer_ids']
+ state = module.params['state']
+
+ gitlab_version = gitlab.__version__
+ if LooseVersion(gitlab_version) < LooseVersion('2.3.0'):
+ module.fail_json(msg="community.general.gitlab_merge_request requires python-gitlab Python module >= 2.3.0 (installed version: [%s])."
+ " Please upgrade python-gitlab to version 2.3.0 or above." % gitlab_version)
+
+ this_project = find_project(gitlab_instance, project)
+ if this_project is None:
+ module.fail_json(msg="Failed to get the project: %s" % project)
+
+ this_gitlab = GitlabMergeRequest(module=module, project=this_project, gitlab_instance=gitlab_instance)
+
+ r_source_branch = this_gitlab.get_branch(source_branch)
+ if not r_source_branch:
+ module.fail_json(msg="Source branch {b} not exist.".format(b=r_source_branch))
+
+ r_target_branch = this_gitlab.get_branch(target_branch)
+ if not r_target_branch:
+ module.fail_json(msg="Destination branch {b} not exist.".format(b=r_target_branch))
+
+ this_mr = this_gitlab.get_mr(title, source_branch, target_branch, state_filter)
+
+ if state == "present":
+ if description_path:
+ try:
+ with open(description_path, 'rb') as f:
+ description = to_text(f.read(), errors='surrogate_or_strict')
+ except IOError as e:
+ module.fail_json(msg='Cannot open {0}: {1}'.format(description_path, e))
+
+ # sorting necessary in order to properly detect changes, as we don't want to get false positive
+ # results due to differences in ids ordering; see `mr_has_changed()`
+ assignee_ids = sorted(this_gitlab.get_user_ids(assignee_ids.split(","))) if assignee_ids else []
+ reviewer_ids = sorted(this_gitlab.get_user_ids(reviewer_ids.split(","))) if reviewer_ids else []
+ labels = sorted(labels.split(",")) if labels else []
+
+ options = {
+ "target_branch": target_branch,
+ "title": title,
+ "description": description,
+ "labels": labels,
+ "remove_source_branch": remove_source_branch,
+ "reviewer_ids": reviewer_ids,
+ "assignee_ids": assignee_ids,
+ }
+
+ if not this_mr:
+ options["source_branch"] = source_branch
+
+ mr = this_gitlab.create_mr(options)
+ module.exit_json(
+ changed=True, msg="Created the Merge Request {t} from branch {s} to branch {d}.".format(t=title, d=target_branch, s=source_branch),
+ mr=mr.asdict()
+ )
+ else:
+ if this_gitlab.mr_has_changed(this_mr, options):
+ mr = this_gitlab.update_mr(this_mr, options)
+ module.exit_json(
+ changed=True, msg="Merge Request {t} from branch {s} to branch {d} updated.".format(t=title, d=target_branch, s=source_branch),
+ mr=mr
+ )
+ else:
+ module.exit_json(
+ changed=False, msg="Merge Request {t} from branch {s} to branch {d} already exist".format(t=title, d=target_branch, s=source_branch),
+ mr=this_mr.asdict()
+ )
+ elif this_mr and state == "absent":
+ mr = this_gitlab.delete_mr(this_mr)
+ module.exit_json(
+ changed=True, msg="Merge Request {t} from branch {s} to branch {d} deleted.".format(t=title, d=target_branch, s=source_branch),
+ mr=mr
+ )
+ else:
+ module.exit_json(changed=False, msg="No changes are needed.", mr=this_mr.asdict())
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/general/plugins/modules/gitlab_milestone.py b/ansible_collections/community/general/plugins/modules/gitlab_milestone.py
new file mode 100644
index 000000000..0a616ea47
--- /dev/null
+++ b/ansible_collections/community/general/plugins/modules/gitlab_milestone.py
@@ -0,0 +1,496 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2023, Gabriele Pongelli (gabriele.pongelli@gmail.com)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+DOCUMENTATION = '''
+module: gitlab_milestone
+short_description: Creates/updates/deletes GitLab Milestones belonging to project or group
+version_added: 8.3.0
+description:
+ - When a milestone does not exist, it will be created.
+ - When a milestone does exist, its value will be updated when the values are different.
+ - Milestones can be purged.
+author:
+ - "Gabriele Pongelli (@gpongelli)"
+requirements:
+ - python-gitlab python module
+extends_documentation_fragment:
+ - community.general.auth_basic
+ - community.general.gitlab
+ - community.general.attributes
+
+attributes:
+ check_mode:
+ support: full
+ diff_mode:
+ support: none
+
+options:
+ state:
+ description:
+ - Create or delete milestone.
+ default: present
+ type: str
+ choices: ["present", "absent"]
+ purge:
+ description:
+ - When set to V(true), delete all milestone which are not mentioned in the task.
+ default: false
+ type: bool
+ required: false
+ project:
+ description:
+ - The path and name of the project. Either this or O(group) is required.
+ required: false
+ type: str
+ group:
+ description:
+ - The path of the group. Either this or O(project) is required.
+ required: false
+ type: str
+ milestones:
+ description:
+ - A list of dictionaries that represents gitlab project's or group's milestones.
+ type: list
+ elements: dict
+ required: false
+ default: []
+ suboptions:
+ title:
+ description:
+ - The name of the milestone.
+ type: str
+ required: true
+ due_date:
+ description:
+ - Milestone due date in YYYY-MM-DD format.
+ type: str
+ required: false
+ default: null
+ start_date:
+ description:
+ - Milestone start date in YYYY-MM-DD format.
+ type: str
+ required: false
+ default: null
+ description:
+ description:
+ - Milestone's description.
+ type: str
+ default: null
+'''
+
+
+EXAMPLES = '''
+# same project's task can be executed for group
+- name: Create one milestone
+ community.general.gitlab_milestone:
+ api_url: https://gitlab.com
+ api_token: secret_access_token
+ project: "group1/project1"
+ milestones:
+ - title: milestone_one
+ start_date: "2024-01-04"
+ state: present
+
+- name: Create many group milestones
+ community.general.gitlab_milestone:
+ api_url: https://gitlab.com
+ api_token: secret_access_token
+ group: "group1"
+ milestones:
+ - title: milestone_one
+ start_date: "2024-01-04"
+ description: this is a milestone
+ due_date: "2024-02-04"
+ - title: milestone_two
+ state: present
+
+- name: Create many project milestones
+ community.general.gitlab_milestone:
+ api_url: https://gitlab.com
+ api_token: secret_access_token
+ project: "group1/project1"
+ milestones:
+ - title: milestone_one
+ start_date: "2024-01-04"
+ description: this is a milestone
+ due_date: "2024-02-04"
+ - title: milestone_two
+ state: present
+
+- name: Set or update some milestones
+ community.general.gitlab_milestone:
+ api_url: https://gitlab.com
+ api_token: secret_access_token
+ project: "group1/project1"
+ milestones:
+ - title: milestone_one
+ start_date: "2024-05-04"
+ state: present
+
+- name: Add milestone in check mode
+ community.general.gitlab_milestone:
+ api_url: https://gitlab.com
+ api_token: secret_access_token
+ project: "group1/project1"
+ milestones:
+ - title: milestone_one
+ start_date: "2024-05-04"
+ check_mode: true
+
+- name: Delete milestone
+ community.general.gitlab_milestone:
+ api_url: https://gitlab.com
+ api_token: secret_access_token
+ project: "group1/project1"
+ milestones:
+ - title: milestone_one
+ state: absent
+
+- name: Purge all milestones
+ community.general.gitlab_milestone:
+ api_url: https://gitlab.com
+ api_token: secret_access_token
+ project: "group1/project1"
+ purge: true
+
+- name: Delete many milestones
+ community.general.gitlab_milestone:
+ api_url: https://gitlab.com
+ api_token: secret_access_token
+ project: "group1/project1"
+ state: absent
+ milestones:
+ - title: milestone-abc123
+ - title: milestone-two
+'''
+
+RETURN = '''
+milestones:
+ description: Four lists of the milestones which were added, updated, removed or exist.
+ returned: success
+ type: dict
+ contains:
+ added:
+ description: A list of milestones which were created.
+ returned: always
+ type: list
+ sample: ['abcd', 'milestone-one']
+ untouched:
+ description: A list of milestones which exist.
+ returned: always
+ type: list
+ sample: ['defg', 'new-milestone']
+ removed:
+ description: A list of milestones which were deleted.
+ returned: always
+ type: list
+ sample: ['defg', 'new-milestone']
+ updated:
+ description: A list pre-existing milestones whose values have been set.
+ returned: always
+ type: list
+ sample: ['defg', 'new-milestone']
+milestones_obj:
+ description: API object.
+ returned: success
+ type: dict
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.api import basic_auth_argument_spec
+
+from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
+from ansible_collections.community.general.plugins.module_utils.gitlab import (
+ auth_argument_spec, gitlab_authentication, ensure_gitlab_package, find_group, find_project, gitlab
+)
+from datetime import datetime
+
+
+class GitlabMilestones(object):
+
+ def __init__(self, module, gitlab_instance, group_id, project_id):
+ self._gitlab = gitlab_instance
+ self.gitlab_object = group_id if group_id else project_id
+ self.is_group_milestone = True if group_id else False
+ self._module = module
+
+ def list_all_milestones(self):
+ page_nb = 1
+ milestones = []
+ vars_page = self.gitlab_object.milestones.list(page=page_nb)
+ while len(vars_page) > 0:
+ milestones += vars_page
+ page_nb += 1
+ vars_page = self.gitlab_object.milestones.list(page=page_nb)
+ return milestones
+
+ def create_milestone(self, var_obj):
+ if self._module.check_mode:
+ return True, True
+
+ var = {
+ "title": var_obj.get('title'),
+ }
+
+ if var_obj.get('description') is not None:
+ var["description"] = var_obj.get('description')
+
+ if var_obj.get('start_date') is not None:
+ var["start_date"] = self.check_date(var_obj.get('start_date'))
+
+ if var_obj.get('due_date') is not None:
+ var["due_date"] = self.check_date(var_obj.get('due_date'))
+
+ _obj = self.gitlab_object.milestones.create(var)
+ return True, _obj.asdict()
+
+ def update_milestone(self, var_obj):
+ if self._module.check_mode:
+ return True, True
+ _milestone = self.gitlab_object.milestones.get(self.get_milestone_id(var_obj.get('title')))
+
+ if var_obj.get('description') is not None:
+ _milestone.description = var_obj.get('description')
+
+ if var_obj.get('start_date') is not None:
+ _milestone.start_date = var_obj.get('start_date')
+
+ if var_obj.get('due_date') is not None:
+ _milestone.due_date = var_obj.get('due_date')
+
+ # save returns None
+ _milestone.save()
+ return True, _milestone.asdict()
+
+ def get_milestone_id(self, _title):
+ _milestone_list = self.gitlab_object.milestones.list()
+ _found = list(filter(lambda x: x.title == _title, _milestone_list))
+ if _found:
+ return _found[0].id
+ else:
+ self._module.fail_json(msg="milestone '%s' not found." % _title)
+
+ def check_date(self, _date):
+ try:
+ datetime.strptime(_date, '%Y-%m-%d')
+ except ValueError:
+ self._module.fail_json(msg="milestone's date '%s' not in correct format." % _date)
+ return _date
+
+ def delete_milestone(self, var_obj):
+ if self._module.check_mode:
+ return True, True
+ _milestone = self.gitlab_object.milestones.get(self.get_milestone_id(var_obj.get('title')))
+ # delete returns None
+ _milestone.delete()
+ return True, _milestone.asdict()
+
+
+def compare(requested_milestones, existing_milestones, state):
+ # we need to do this, because it was determined in a previous version - more or less buggy
+ # basically it is not necessary and might result in more/other bugs!
+ # but it is required and only relevant for check mode!!
+ # logic represents state 'present' when not purge. all other can be derived from that
+ # untouched => equal in both
+ # updated => title are equal
+ # added => title does not exist
+ untouched = list()
+ updated = list()
+ added = list()
+
+ if state == 'present':
+ _existing_milestones = list()
+ for item in existing_milestones:
+ _existing_milestones.append({'title': item.get('title')})
+
+ for var in requested_milestones:
+ if var in existing_milestones:
+ untouched.append(var)
+ else:
+ compare_item = {'title': var.get('title')}
+ if compare_item in _existing_milestones:
+ updated.append(var)
+ else:
+ added.append(var)
+
+ return untouched, updated, added
+
+
+def native_python_main(this_gitlab, purge, requested_milestones, state, module):
+ change = False
+ return_value = dict(added=[], updated=[], removed=[], untouched=[])
+ return_obj = dict(added=[], updated=[], removed=[])
+
+ milestones_before = [x.asdict() for x in this_gitlab.list_all_milestones()]
+
+ # filter out and enrich before compare
+ for item in requested_milestones:
+ # add defaults when not present
+ if item.get('description') is None:
+ item['description'] = ""
+ if item.get('due_date') is None:
+ item['due_date'] = None
+ if item.get('start_date') is None:
+ item['start_date'] = None
+
+ for item in milestones_before:
+ # remove field only from server
+ item.pop('id')
+ item.pop('iid')
+ item.pop('created_at')
+ item.pop('expired')
+ item.pop('state')
+ item.pop('updated_at')
+ item.pop('web_url')
+ # group milestone has group_id, while project has project_id
+ if 'group_id' in item:
+ item.pop('group_id')
+ if 'project_id' in item:
+ item.pop('project_id')
+
+ if state == 'present':
+ add_or_update = [x for x in requested_milestones if x not in milestones_before]
+ for item in add_or_update:
+ try:
+ _rv, _obj = this_gitlab.create_milestone(item)
+ if _rv:
+ return_value['added'].append(item)
+ return_obj['added'].append(_obj)
+ except Exception:
+ # create raises exception with following error message when milestone already exists
+ _rv, _obj = this_gitlab.update_milestone(item)
+ if _rv:
+ return_value['updated'].append(item)
+ return_obj['updated'].append(_obj)
+
+ if purge:
+ # re-fetch
+ _milestones = this_gitlab.list_all_milestones()
+
+ for item in milestones_before:
+ _rv, _obj = this_gitlab.delete_milestone(item)
+ if _rv:
+ return_value['removed'].append(item)
+ return_obj['removed'].append(_obj)
+
+ elif state == 'absent':
+ if not purge:
+ _milestone_titles_requested = [x['title'] for x in requested_milestones]
+ remove_requested = [x for x in milestones_before if x['title'] in _milestone_titles_requested]
+ for item in remove_requested:
+ _rv, _obj = this_gitlab.delete_milestone(item)
+ if _rv:
+ return_value['removed'].append(item)
+ return_obj['removed'].append(_obj)
+ else:
+ for item in milestones_before:
+ _rv, _obj = this_gitlab.delete_milestone(item)
+ if _rv:
+ return_value['removed'].append(item)
+ return_obj['removed'].append(_obj)
+
+ if module.check_mode:
+ _untouched, _updated, _added = compare(requested_milestones, milestones_before, state)
+ return_value = dict(added=_added, updated=_updated, removed=return_value['removed'], untouched=_untouched)
+
+ if any(return_value[x] for x in ['added', 'removed', 'updated']):
+ change = True
+
+ milestones_after = [x.asdict() for x in this_gitlab.list_all_milestones()]
+
+ return change, return_value, milestones_before, milestones_after, return_obj
+
+
+def main():
+ argument_spec = basic_auth_argument_spec()
+ argument_spec.update(auth_argument_spec())
+ argument_spec.update(
+ project=dict(type='str', required=False, default=None),
+ group=dict(type='str', required=False, default=None),
+ purge=dict(type='bool', required=False, default=False),
+ milestones=dict(type='list', elements='dict', required=False, default=list(),
+ options=dict(
+ title=dict(type='str', required=True),
+ description=dict(type='str', required=False),
+ due_date=dict(type='str', required=False),
+ start_date=dict(type='str', required=False),)
+ ),
+ state=dict(type='str', default="present", choices=["absent", "present"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ mutually_exclusive=[
+ ['api_username', 'api_token'],
+ ['api_username', 'api_oauth_token'],
+ ['api_username', 'api_job_token'],
+ ['api_token', 'api_oauth_token'],
+ ['api_token', 'api_job_token'],
+ ['project', 'group'],
+ ],
+ required_together=[
+ ['api_username', 'api_password'],
+ ],
+ required_one_of=[
+ ['api_username', 'api_token', 'api_oauth_token', 'api_job_token'],
+ ['project', 'group']
+ ],
+ supports_check_mode=True
+ )
+ ensure_gitlab_package(module)
+
+ gitlab_project = module.params['project']
+ gitlab_group = module.params['group']
+ purge = module.params['purge']
+ milestone_list = module.params['milestones']
+ state = module.params['state']
+
+ gitlab_version = gitlab.__version__
+ _min_gitlab = '3.2.0'
+ if LooseVersion(gitlab_version) < LooseVersion(_min_gitlab):
+ module.fail_json(msg="community.general.gitlab_milestone requires python-gitlab Python module >= %s "
+ "(installed version: [%s]). Please upgrade "
+ "python-gitlab to version %s or above." % (_min_gitlab, gitlab_version, _min_gitlab))
+
+ gitlab_instance = gitlab_authentication(module)
+
+ # find_project can return None, but the other must exist
+ gitlab_project_id = find_project(gitlab_instance, gitlab_project)
+
+ # find_group can return None, but the other must exist
+ gitlab_group_id = find_group(gitlab_instance, gitlab_group)
+
+ # if both not found, module must exist
+ if not gitlab_project_id and not gitlab_group_id:
+ if gitlab_project and not gitlab_project_id:
+ module.fail_json(msg="project '%s' not found." % gitlab_project)
+ if gitlab_group and not gitlab_group_id:
+ module.fail_json(msg="group '%s' not found." % gitlab_group)
+
+ this_gitlab = GitlabMilestones(module=module, gitlab_instance=gitlab_instance, group_id=gitlab_group_id,
+ project_id=gitlab_project_id)
+
+ change, raw_return_value, before, after, _obj = native_python_main(this_gitlab, purge, milestone_list, state,
+ module)
+
+ if not module.check_mode:
+ raw_return_value['untouched'] = [x for x in before if x in after]
+
+ added = [x.get('title') for x in raw_return_value['added']]
+ updated = [x.get('title') for x in raw_return_value['updated']]
+ removed = [x.get('title') for x in raw_return_value['removed']]
+ untouched = [x.get('title') for x in raw_return_value['untouched']]
+ return_value = dict(added=added, updated=updated, removed=removed, untouched=untouched)
+
+ module.exit_json(changed=change, milestones=return_value, milestones_obj=_obj)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/general/plugins/modules/gitlab_project.py b/ansible_collections/community/general/plugins/modules/gitlab_project.py
index db360d578..f1b96bfac 100644
--- a/ansible_collections/community/general/plugins/modules/gitlab_project.py
+++ b/ansible_collections/community/general/plugins/modules/gitlab_project.py
@@ -15,13 +15,12 @@ module: gitlab_project
short_description: Creates/updates/deletes GitLab Projects
description:
- When the project does not exist in GitLab, it will be created.
- - When the project does exists and I(state=absent), the project will be deleted.
+ - When the project does exists and O(state=absent), the project will be deleted.
- When changes are made to the project, the project will be updated.
author:
- Werner Dijkerman (@dj-wasabi)
- Guillaume Martinez (@Lunik)
requirements:
- - python >= 2.7
- python-gitlab python module
extends_documentation_fragment:
- community.general.auth_basic
@@ -84,9 +83,9 @@ options:
default: true
visibility:
description:
- - C(private) Project access must be granted explicitly for each user.
- - C(internal) The project can be cloned by any logged in user.
- - C(public) The project can be cloned without any authentication.
+ - V(private) Project access must be granted explicitly for each user.
+ - V(internal) The project can be cloned by any logged in user.
+ - V(public) The project can be cloned without any authentication.
default: private
type: str
choices: ["private", "internal", "public"]
@@ -108,7 +107,7 @@ options:
merge_method:
description:
- What requirements are placed upon merges.
- - Possible values are C(merge), C(rebase_merge) merge commit with semi-linear history, C(ff) fast-forward merges only.
+ - Possible values are V(merge), V(rebase_merge) merge commit with semi-linear history, V(ff) fast-forward merges only.
type: str
choices: ["ff", "merge", "rebase_merge"]
default: merge
@@ -175,79 +174,81 @@ options:
version_added: "4.2.0"
default_branch:
description:
- - Default branch name for a new project.
- - This option is only used on creation, not for updates. This is also only used if I(initialize_with_readme=true).
+ - The default branch name for this project.
+ - For project creation, this option requires O(initialize_with_readme=true).
+ - For project update, the branch must exist.
+ - Supports project's default branch update since community.general 8.0.0.
type: str
version_added: "4.2.0"
builds_access_level:
description:
- - C(private) means that repository CI/CD is allowed only to project members.
- - C(disabled) means that repository CI/CD is disabled.
- - C(enabled) means that repository CI/CD is enabled.
+ - V(private) means that repository CI/CD is allowed only to project members.
+ - V(disabled) means that repository CI/CD is disabled.
+ - V(enabled) means that repository CI/CD is enabled.
type: str
choices: ["private", "disabled", "enabled"]
version_added: "6.2.0"
forking_access_level:
description:
- - C(private) means that repository forks is allowed only to project members.
- - C(disabled) means that repository forks are disabled.
- - C(enabled) means that repository forks are enabled.
+ - V(private) means that repository forks is allowed only to project members.
+ - V(disabled) means that repository forks are disabled.
+ - V(enabled) means that repository forks are enabled.
type: str
choices: ["private", "disabled", "enabled"]
version_added: "6.2.0"
container_registry_access_level:
description:
- - C(private) means that container registry is allowed only to project members.
- - C(disabled) means that container registry is disabled.
- - C(enabled) means that container registry is enabled.
+ - V(private) means that container registry is allowed only to project members.
+ - V(disabled) means that container registry is disabled.
+ - V(enabled) means that container registry is enabled.
type: str
choices: ["private", "disabled", "enabled"]
version_added: "6.2.0"
releases_access_level:
description:
- - C(private) means that accessing release is allowed only to project members.
- - C(disabled) means that accessing release is disabled.
- - C(enabled) means that accessing release is enabled.
+ - V(private) means that accessing release is allowed only to project members.
+ - V(disabled) means that accessing release is disabled.
+ - V(enabled) means that accessing release is enabled.
type: str
choices: ["private", "disabled", "enabled"]
version_added: "6.4.0"
environments_access_level:
description:
- - C(private) means that deployment to environment is allowed only to project members.
- - C(disabled) means that deployment to environment is disabled.
- - C(enabled) means that deployment to environment is enabled.
+ - V(private) means that deployment to environment is allowed only to project members.
+ - V(disabled) means that deployment to environment is disabled.
+ - V(enabled) means that deployment to environment is enabled.
type: str
choices: ["private", "disabled", "enabled"]
version_added: "6.4.0"
feature_flags_access_level:
description:
- - C(private) means that feature rollout is allowed only to project members.
- - C(disabled) means that feature rollout is disabled.
- - C(enabled) means that feature rollout is enabled.
+ - V(private) means that feature rollout is allowed only to project members.
+ - V(disabled) means that feature rollout is disabled.
+ - V(enabled) means that feature rollout is enabled.
type: str
choices: ["private", "disabled", "enabled"]
version_added: "6.4.0"
infrastructure_access_level:
description:
- - C(private) means that configuring infrastructure is allowed only to project members.
- - C(disabled) means that configuring infrastructure is disabled.
- - C(enabled) means that configuring infrastructure is enabled.
+ - V(private) means that configuring infrastructure is allowed only to project members.
+ - V(disabled) means that configuring infrastructure is disabled.
+ - V(enabled) means that configuring infrastructure is enabled.
type: str
choices: ["private", "disabled", "enabled"]
version_added: "6.4.0"
monitor_access_level:
description:
- - C(private) means that monitoring health is allowed only to project members.
- - C(disabled) means that monitoring health is disabled.
- - C(enabled) means that monitoring health is enabled.
+ - V(private) means that monitoring health is allowed only to project members.
+ - V(disabled) means that monitoring health is disabled.
+ - V(enabled) means that monitoring health is enabled.
type: str
choices: ["private", "disabled", "enabled"]
version_added: "6.4.0"
security_and_compliance_access_level:
description:
- - C(private) means that accessing security and complicance tab is allowed only to project members.
- - C(disabled) means that accessing security and complicance tab is disabled.
- - C(enabled) means that accessing security and complicance tab is enabled.
+ - V(private) means that accessing security and complicance tab is allowed only to project members.
+ - V(disabled) means that accessing security and complicance tab is disabled.
+ - V(enabled) means that accessing security and complicance tab is enabled.
type: str
choices: ["private", "disabled", "enabled"]
version_added: "6.4.0"
@@ -272,7 +273,6 @@ EXAMPLES = r'''
community.general.gitlab_project:
api_url: https://gitlab.example.com/
api_token: "{{ access_token }}"
- validate_certs: false
name: my_first_project
state: absent
delegate_to: localhost
@@ -338,7 +338,7 @@ from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.common.text.converters import to_native
from ansible_collections.community.general.plugins.module_utils.gitlab import (
- auth_argument_spec, find_group, find_project, gitlab_authentication, gitlab, ensure_gitlab_package
+ auth_argument_spec, find_group, find_project, gitlab_authentication, gitlab
)
from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
@@ -355,7 +355,7 @@ class GitLabProject(object):
@param namespace Namespace Object (User or Group)
@param options Options of the project
'''
- def create_or_update_project(self, project_name, namespace, options):
+ def create_or_update_project(self, module, project_name, namespace, options):
changed = False
project_options = {
'name': project_name,
@@ -395,6 +395,8 @@ class GitLabProject(object):
# Because we have already call userExists in main()
if self.project_object is None:
+ if options['default_branch'] and not options['initialize_with_readme']:
+ module.fail_json(msg="Param default_branch need param initialize_with_readme set to true")
project_options.update({
'path': options['path'],
'import_url': options['import_url'],
@@ -416,6 +418,8 @@ class GitLabProject(object):
changed = True
else:
+ if options['default_branch']:
+ project_options['default_branch'] = options['default_branch']
changed, project = self.update_project(self.project_object, project_options)
self.project_object = project
@@ -552,7 +556,9 @@ def main():
],
supports_check_mode=True,
)
- ensure_gitlab_package(module)
+
+ # check prerequisites and connect to gitlab server
+ gitlab_instance = gitlab_authentication(module)
group_identifier = module.params['group']
project_name = module.params['name']
@@ -590,11 +596,6 @@ def main():
security_and_compliance_access_level = module.params['security_and_compliance_access_level']
topics = module.params['topics']
- if default_branch and not initialize_with_readme:
- module.fail_json(msg="Param default_branch need param initialize_with_readme set to true")
-
- gitlab_instance = gitlab_authentication(module)
-
# Set project_path to project_name if it is empty.
if project_path is None:
project_path = project_name.replace(" ", "_")
@@ -636,7 +637,7 @@ def main():
if state == 'present':
- if gitlab_project.create_or_update_project(project_name, namespace, {
+ if gitlab_project.create_or_update_project(module, project_name, namespace, {
"path": project_path,
"description": project_description,
"initialize_with_readme": initialize_with_readme,
diff --git a/ansible_collections/community/general/plugins/modules/gitlab_project_access_token.py b/ansible_collections/community/general/plugins/modules/gitlab_project_access_token.py
new file mode 100644
index 000000000..e692a3057
--- /dev/null
+++ b/ansible_collections/community/general/plugins/modules/gitlab_project_access_token.py
@@ -0,0 +1,318 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2024, Zoran Krleza (zoran.krleza@true-north.hr)
+# Based on code:
+# Copyright (c) 2019, Guillaume Martinez (lunik@tiwabbit.fr)
+# Copyright (c) 2018, Marcus Watkins <marwatk@marcuswatkins.net>
+# Copyright (c) 2013, Phillip Gentry <phillip@cx.com>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+DOCUMENTATION = r'''
+module: gitlab_project_access_token
+short_description: Manages GitLab project access tokens
+version_added: 8.4.0
+description:
+ - Creates and revokes project access tokens.
+author:
+ - Zoran Krleza (@pixslx)
+requirements:
+ - python-gitlab >= 3.1.0
+extends_documentation_fragment:
+ - community.general.auth_basic
+ - community.general.gitlab
+ - community.general.attributes
+notes:
+ - Access tokens can not be changed. If a parameter needs to be changed, an acceess token has to be recreated.
+ Whether tokens will be recreated is controlled by the O(recreate) option, which defaults to V(never).
+ - Token string is contained in the result only when access token is created or recreated. It can not be fetched afterwards.
+ - Token matching is done by comparing O(name) option.
+
+attributes:
+ check_mode:
+ support: full
+ diff_mode:
+ support: none
+
+options:
+ project:
+ description:
+ - ID or full path of project in the form of group/name.
+ required: true
+ type: str
+ name:
+ description:
+ - Access token's name.
+ required: true
+ type: str
+ scopes:
+ description:
+ - Scope of the access token.
+ required: true
+ type: list
+ elements: str
+ aliases: ["scope"]
+ choices: ["api", "read_api", "read_registry", "write_registry", "read_repository", "write_repository", "create_runner", "ai_features", "k8s_proxy"]
+ access_level:
+ description:
+ - Access level of the access token.
+ type: str
+ default: maintainer
+ choices: ["guest", "reporter", "developer", "maintainer", "owner"]
+ expires_at:
+ description:
+ - Expiration date of the access token in C(YYYY-MM-DD) format.
+ - Make sure to quote this value in YAML to ensure it is kept as a string and not interpreted as a YAML date.
+ type: str
+ required: true
+ recreate:
+ description:
+ - Whether the access token will be recreated if it already exists.
+ - When V(never) the token will never be recreated.
+ - When V(always) the token will always be recreated.
+ - When V(state_change) the token will be recreated if there is a difference between desired state and actual state.
+ type: str
+ choices: ["never", "always", "state_change"]
+ default: never
+ state:
+ description:
+ - When V(present) the access token will be added to the project if it does not exist.
+ - When V(absent) it will be removed from the project if it exists.
+ default: present
+ type: str
+ choices: [ "present", "absent" ]
+'''
+
+EXAMPLES = r'''
+- name: "Creating a project access token"
+ community.general.gitlab_project_access_token:
+ api_url: https://gitlab.example.com/
+ api_token: "somegitlabapitoken"
+ project: "my_group/my_project"
+ name: "project_token"
+ expires_at: "2024-12-31"
+ access_level: developer
+ scopes:
+ - api
+ - read_api
+ - read_repository
+ - write_repository
+ state: present
+
+- name: "Revoking a project access token"
+ community.general.gitlab_project_access_token:
+ api_url: https://gitlab.example.com/
+ api_token: "somegitlabapitoken"
+ project: "my_group/my_project"
+ name: "project_token"
+ expires_at: "2024-12-31"
+ scopes:
+ - api
+ - read_api
+ - read_repository
+ - write_repository
+ state: absent
+
+- name: "Change (recreate) existing token if its actual state is different than desired state"
+ community.general.gitlab_project_access_token:
+ api_url: https://gitlab.example.com/
+ api_token: "somegitlabapitoken"
+ project: "my_group/my_project"
+ name: "project_token"
+ expires_at: "2024-12-31"
+ scopes:
+ - api
+ - read_api
+ - read_repository
+ - write_repository
+ recreate: state_change
+ state: present
+'''
+
+RETURN = r'''
+access_token:
+ description:
+ - API object.
+ - Only contains the value of the token if the token was created or recreated.
+ returned: success and O(state=present)
+ type: dict
+'''
+
+from datetime import datetime
+
+from ansible.module_utils.api import basic_auth_argument_spec
+from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.common.text.converters import to_native
+
+from ansible_collections.community.general.plugins.module_utils.gitlab import (
+ auth_argument_spec, find_project, gitlab_authentication, gitlab
+)
+
+ACCESS_LEVELS = dict(guest=10, reporter=20, developer=30, maintainer=40, owner=50)
+
+
+class GitLabProjectAccessToken(object):
+ def __init__(self, module, gitlab_instance):
+ self._module = module
+ self._gitlab = gitlab_instance
+ self.access_token_object = None
+
+ '''
+ @param project Project Object
+ @param arguments Attributes of the access_token
+ '''
+ def create_access_token(self, project, arguments):
+ changed = False
+ if self._module.check_mode:
+ return True
+
+ try:
+ self.access_token_object = project.access_tokens.create(arguments)
+ changed = True
+ except (gitlab.exceptions.GitlabCreateError) as e:
+ self._module.fail_json(msg="Failed to create access token: %s " % to_native(e))
+
+ return changed
+
+ '''
+ @param project Project object
+ @param name of the access token
+ '''
+ def find_access_token(self, project, name):
+ access_tokens = project.access_tokens.list(all=True)
+ for access_token in access_tokens:
+ if (access_token.name == name):
+ self.access_token_object = access_token
+ return False
+ return False
+
+ def revoke_access_token(self):
+ if self._module.check_mode:
+ return True
+
+ changed = False
+ try:
+ self.access_token_object.delete()
+ changed = True
+ except (gitlab.exceptions.GitlabCreateError) as e:
+ self._module.fail_json(msg="Failed to revoke access token: %s " % to_native(e))
+
+ return changed
+
+ def access_tokens_equal(self):
+ if self.access_token_object.name != self._module.params['name']:
+ return False
+ if self.access_token_object.scopes != self._module.params['scopes']:
+ return False
+ if self.access_token_object.access_level != ACCESS_LEVELS[self._module.params['access_level']]:
+ return False
+ if self.access_token_object.expires_at != self._module.params['expires_at']:
+ return False
+ return True
+
+
+def main():
+ argument_spec = basic_auth_argument_spec()
+ argument_spec.update(auth_argument_spec())
+ argument_spec.update(dict(
+ state=dict(type='str', default="present", choices=["absent", "present"]),
+ project=dict(type='str', required=True),
+ name=dict(type='str', required=True),
+ scopes=dict(type='list',
+ required=True,
+ aliases=['scope'],
+ elements='str',
+ choices=['api',
+ 'read_api',
+ 'read_registry',
+ 'write_registry',
+ 'read_repository',
+ 'write_repository',
+ 'create_runner',
+ 'ai_features',
+ 'k8s_proxy']),
+ access_level=dict(type='str', required=False, default='maintainer', choices=['guest', 'reporter', 'developer', 'maintainer', 'owner']),
+ expires_at=dict(type='str', required=True),
+ recreate=dict(type='str', default='never', choices=['never', 'always', 'state_change'])
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ mutually_exclusive=[
+ ['api_username', 'api_token'],
+ ['api_username', 'api_oauth_token'],
+ ['api_username', 'api_job_token'],
+ ['api_token', 'api_oauth_token'],
+ ['api_token', 'api_job_token']
+ ],
+ required_together=[
+ ['api_username', 'api_password']
+ ],
+ required_one_of=[
+ ['api_username', 'api_token', 'api_oauth_token', 'api_job_token']
+ ],
+ supports_check_mode=True
+ )
+
+ state = module.params['state']
+ project_identifier = module.params['project']
+ name = module.params['name']
+ scopes = module.params['scopes']
+ access_level_str = module.params['access_level']
+ expires_at = module.params['expires_at']
+ recreate = module.params['recreate']
+
+ access_level = ACCESS_LEVELS[access_level_str]
+
+ try:
+ datetime.strptime(expires_at, '%Y-%m-%d')
+ except ValueError:
+ module.fail_json(msg="Argument expires_at is not in required format YYYY-MM-DD")
+
+ gitlab_instance = gitlab_authentication(module)
+
+ gitlab_access_token = GitLabProjectAccessToken(module, gitlab_instance)
+
+ project = find_project(gitlab_instance, project_identifier)
+ if project is None:
+ module.fail_json(msg="Failed to create access token: project %s does not exists" % project_identifier)
+
+ gitlab_access_token_exists = False
+ gitlab_access_token.find_access_token(project, name)
+ if gitlab_access_token.access_token_object is not None:
+ gitlab_access_token_exists = True
+
+ if state == 'absent':
+ if gitlab_access_token_exists:
+ gitlab_access_token.revoke_access_token()
+ module.exit_json(changed=True, msg="Successfully deleted access token %s" % name)
+ else:
+ module.exit_json(changed=False, msg="Access token does not exists")
+
+ if state == 'present':
+ if gitlab_access_token_exists:
+ if gitlab_access_token.access_tokens_equal():
+ if recreate == 'always':
+ gitlab_access_token.revoke_access_token()
+ gitlab_access_token.create_access_token(project, {'name': name, 'scopes': scopes, 'access_level': access_level, 'expires_at': expires_at})
+ module.exit_json(changed=True, msg="Successfully recreated access token", access_token=gitlab_access_token.access_token_object._attrs)
+ else:
+ module.exit_json(changed=False, msg="Access token already exists", access_token=gitlab_access_token.access_token_object._attrs)
+ else:
+ if recreate == 'never':
+ module.fail_json(msg="Access token already exists and its state is different. It can not be updated without recreating.")
+ else:
+ gitlab_access_token.revoke_access_token()
+ gitlab_access_token.create_access_token(project, {'name': name, 'scopes': scopes, 'access_level': access_level, 'expires_at': expires_at})
+ module.exit_json(changed=True, msg="Successfully recreated access token", access_token=gitlab_access_token.access_token_object._attrs)
+ else:
+ gitlab_access_token.create_access_token(project, {'name': name, 'scopes': scopes, 'access_level': access_level, 'expires_at': expires_at})
+ module.exit_json(changed=True, msg="Successfully created access token", access_token=gitlab_access_token.access_token_object._attrs)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/general/plugins/modules/gitlab_project_badge.py b/ansible_collections/community/general/plugins/modules/gitlab_project_badge.py
index 5b1a8d3f1..fee938949 100644
--- a/ansible_collections/community/general/plugins/modules/gitlab_project_badge.py
+++ b/ansible_collections/community/general/plugins/modules/gitlab_project_badge.py
@@ -39,8 +39,8 @@ options:
state:
description:
- State of the badge in the project.
- - On C(present), it adds a badge to a GitLab project.
- - On C(absent), it removes a badge from a GitLab project.
+ - On V(present), it adds a badge to a GitLab project.
+ - On V(absent), it removes a badge from a GitLab project.
choices: ['present', 'absent']
default: 'present'
type: str
@@ -82,7 +82,7 @@ EXAMPLES = r'''
RETURN = '''
badge:
description: The badge information.
- returned: when I(state=present)
+ returned: when O(state=present)
type: dict
sample:
id: 1
@@ -97,7 +97,7 @@ from ansible.module_utils.api import basic_auth_argument_spec
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils.gitlab import (
- auth_argument_spec, gitlab_authentication, find_project, ensure_gitlab_package
+ auth_argument_spec, gitlab_authentication, find_project, list_all_kwargs
)
@@ -105,7 +105,7 @@ def present_strategy(module, gl, project, wished_badge):
changed = False
existing_badge = None
- for badge in project.badges.list(iterator=True):
+ for badge in project.badges.list(**list_all_kwargs):
if badge.image_url == wished_badge["image_url"]:
existing_badge = badge
break
@@ -135,7 +135,7 @@ def absent_strategy(module, gl, project, wished_badge):
changed = False
existing_badge = None
- for badge in project.badges.list(iterator=True):
+ for badge in project.badges.list(**list_all_kwargs):
if badge.image_url == wished_badge["image_url"]:
existing_badge = badge
break
@@ -159,13 +159,12 @@ state_strategy = {
def core(module):
- ensure_gitlab_package(module)
+ # check prerequisites and connect to gitlab server
+ gl = gitlab_authentication(module)
gitlab_project = module.params['project']
state = module.params['state']
- gl = gitlab_authentication(module)
-
project = find_project(gl, gitlab_project)
# project doesn't exist
if not project:
diff --git a/ansible_collections/community/general/plugins/modules/gitlab_project_members.py b/ansible_collections/community/general/plugins/modules/gitlab_project_members.py
index 905358443..2ce277f68 100644
--- a/ansible_collections/community/general/plugins/modules/gitlab_project_members.py
+++ b/ansible_collections/community/general/plugins/modules/gitlab_project_members.py
@@ -42,21 +42,21 @@ options:
gitlab_user:
description:
- A username or a list of usernames to add to/remove from the GitLab project.
- - Mutually exclusive with I(gitlab_users_access).
+ - Mutually exclusive with O(gitlab_users_access).
type: list
elements: str
access_level:
description:
- The access level for the user.
- - Required if I(state=present), user state is set to present.
+ - Required if O(state=present), user state is set to present.
type: str
choices: ['guest', 'reporter', 'developer', 'maintainer']
gitlab_users_access:
description:
- Provide a list of user to access level mappings.
- Every dictionary in this list specifies a user (by username) and the access level the user should have.
- - Mutually exclusive with I(gitlab_user) and I(access_level).
- - Use together with I(purge_users) to remove all users not specified here from the project.
+ - Mutually exclusive with O(gitlab_user) and O(access_level).
+ - Use together with O(purge_users) to remove all users not specified here from the project.
type: list
elements: dict
suboptions:
@@ -67,7 +67,7 @@ options:
access_level:
description:
- The access level for the user.
- - Required if I(state=present), user state is set to present.
+ - Required if O(state=present), user state is set to present.
type: str
choices: ['guest', 'reporter', 'developer', 'maintainer']
required: true
@@ -75,16 +75,16 @@ options:
state:
description:
- State of the member in the project.
- - On C(present), it adds a user to a GitLab project.
- - On C(absent), it removes a user from a GitLab project.
+ - On V(present), it adds a user to a GitLab project.
+ - On V(absent), it removes a user from a GitLab project.
choices: ['present', 'absent']
default: 'present'
type: str
purge_users:
description:
- - Adds/remove users of the given access_level to match the given I(gitlab_user)/I(gitlab_users_access) list.
+ - Adds/remove users of the given access_level to match the given O(gitlab_user)/O(gitlab_users_access) list.
If omitted do not purge orphaned members.
- - Is only used when I(state=present).
+ - Is only used when O(state=present).
type: list
elements: str
choices: ['guest', 'reporter', 'developer', 'maintainer']
@@ -106,7 +106,6 @@ EXAMPLES = r'''
community.general.gitlab_project_members:
api_url: 'https://gitlab.example.com'
api_token: 'Your-Private-Token'
- validate_certs: false
project: projectname
gitlab_user: username
state: absent
@@ -163,7 +162,7 @@ from ansible.module_utils.api import basic_auth_argument_spec
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils.gitlab import (
- auth_argument_spec, gitlab_authentication, gitlab, ensure_gitlab_package
+ auth_argument_spec, gitlab_authentication, gitlab
)
@@ -279,13 +278,15 @@ def main():
],
supports_check_mode=True,
)
- ensure_gitlab_package(module)
+
+ # check prerequisites and connect to gitlab server
+ gl = gitlab_authentication(module)
access_level_int = {
- 'guest': gitlab.GUEST_ACCESS,
- 'reporter': gitlab.REPORTER_ACCESS,
- 'developer': gitlab.DEVELOPER_ACCESS,
- 'maintainer': gitlab.MAINTAINER_ACCESS,
+ 'guest': gitlab.const.GUEST_ACCESS,
+ 'reporter': gitlab.const.REPORTER_ACCESS,
+ 'developer': gitlab.const.DEVELOPER_ACCESS,
+ 'maintainer': gitlab.const.MAINTAINER_ACCESS,
}
gitlab_project = module.params['project']
@@ -296,9 +297,6 @@ def main():
if purge_users:
purge_users = [access_level_int[level] for level in purge_users]
- # connect to gitlab server
- gl = gitlab_authentication(module)
-
project = GitLabProjectMembers(module, gl)
gitlab_project_id = project.get_project(gitlab_project)
diff --git a/ansible_collections/community/general/plugins/modules/gitlab_project_variable.py b/ansible_collections/community/general/plugins/modules/gitlab_project_variable.py
index 63569dd78..329e7a414 100644
--- a/ansible_collections/community/general/plugins/modules/gitlab_project_variable.py
+++ b/ansible_collections/community/general/plugins/modules/gitlab_project_variable.py
@@ -14,11 +14,10 @@ description:
- When a project variable does not exist, it will be created.
- When a project variable does exist, its value will be updated when the values are different.
- Variables which are untouched in the playbook, but are not untouched in the GitLab project,
- they stay untouched (I(purge) is C(false)) or will be deleted (I(purge) is C(true)).
+ they stay untouched (O(purge=false)) or will be deleted (O(purge=true)).
author:
- "Markus Bergholz (@markuman)"
requirements:
- - python >= 2.7
- python-gitlab python module
extends_documentation_fragment:
- community.general.auth_basic
@@ -51,16 +50,17 @@ options:
type: bool
vars:
description:
- - When the list element is a simple key-value pair, masked and protected will be set to false.
- - When the list element is a dict with the keys I(value), I(masked) and I(protected), the user can
- have full control about whether a value should be masked, protected or both.
+ - When the list element is a simple key-value pair, masked, raw and protected will be set to false.
+ - When the list element is a dict with the keys C(value), C(masked), C(raw) and C(protected), the user can
+ have full control about whether a value should be masked, raw, protected or both.
- Support for protected values requires GitLab >= 9.3.
- Support for masked values requires GitLab >= 11.10.
+ - Support for raw values requires GitLab >= 15.7.
- Support for environment_scope requires GitLab Premium >= 13.11.
- Support for variable_type requires GitLab >= 11.11.
- - A I(value) must be a string or a number.
- - Field I(variable_type) must be a string with either C(env_var), which is the default, or C(file).
- - Field I(environment_scope) must be a string defined by scope environment.
+ - A C(value) must be a string or a number.
+ - Field C(variable_type) must be a string with either V(env_var), which is the default, or V(file).
+ - Field C(environment_scope) must be a string defined by scope environment.
- When a value is masked, it must be in Base64 and have a length of at least 8 characters.
See GitLab documentation on acceptable values for a masked variable (https://docs.gitlab.com/ce/ci/variables/#masked-variables).
default: {}
@@ -69,7 +69,7 @@ options:
version_added: 4.4.0
description:
- A list of dictionaries that represents CI/CD variables.
- - This module works internal with this structure, even if the older I(vars) parameter is used.
+ - This module works internal with this structure, even if the older O(vars) parameter is used.
default: []
type: list
elements: dict
@@ -82,31 +82,38 @@ options:
value:
description:
- The variable value.
- - Required when I(state=present).
+ - Required when O(state=present).
type: str
masked:
description:
- - Wether variable value is masked or not.
+ - Whether variable value is masked or not.
- Support for masked values requires GitLab >= 11.10.
type: bool
default: false
protected:
description:
- - Wether variable value is protected or not.
+ - Whether variable value is protected or not.
- Support for protected values requires GitLab >= 9.3.
type: bool
default: false
+ raw:
+ description:
+ - Whether variable value is raw or not.
+ - Support for raw values requires GitLab >= 15.7.
+ type: bool
+ default: false
+ version_added: '7.4.0'
variable_type:
description:
- - Wether a variable is an environment variable (C(env_var)) or a file (C(file)).
- - Support for I(variable_type) requires GitLab >= 11.11.
+ - Whether a variable is an environment variable (V(env_var)) or a file (V(file)).
+ - Support for O(variables[].variable_type) requires GitLab >= 11.11.
type: str
choices: ["env_var", "file"]
default: env_var
environment_scope:
description:
- The scope for the variable.
- - Support for I(environment_scope) requires GitLab Premium >= 13.11.
+ - Support for O(variables[].environment_scope) requires GitLab Premium >= 13.11.
type: str
default: '*'
'''
@@ -143,6 +150,38 @@ EXAMPLES = '''
variable_type: env_var
environment_scope: '*'
+- name: Set or update some CI/CD variables with raw value
+ community.general.gitlab_project_variable:
+ api_url: https://gitlab.com
+ api_token: secret_access_token
+ project: markuman/dotfiles
+ purge: false
+ vars:
+ ACCESS_KEY_ID: abc123
+ SECRET_ACCESS_KEY:
+ value: 3214cbad
+ masked: true
+ protected: true
+ raw: true
+ variable_type: env_var
+ environment_scope: '*'
+
+- name: Set or update some CI/CD variables with expandable value
+ community.general.gitlab_project_variable:
+ api_url: https://gitlab.com
+ api_token: secret_access_token
+ project: markuman/dotfiles
+ purge: false
+ vars:
+ ACCESS_KEY_ID: abc123
+ SECRET_ACCESS_KEY:
+ value: '$MY_OTHER_VARIABLE'
+ masked: true
+ protected: true
+ raw: false
+ variable_type: env_var
+ environment_scope: '*'
+
- name: Delete one variable
community.general.gitlab_project_variable:
api_url: https://gitlab.com
@@ -181,62 +220,16 @@ project_variable:
sample: ['ACCESS_KEY_ID', 'SECRET_ACCESS_KEY']
'''
-import traceback
-from ansible.module_utils.basic import AnsibleModule, missing_required_lib
+from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.api import basic_auth_argument_spec
-from ansible.module_utils.six import string_types
-from ansible.module_utils.six import integer_types
-GITLAB_IMP_ERR = None
-try:
- import gitlab # noqa: F401, pylint: disable=unused-import
- HAS_GITLAB_PACKAGE = True
-except Exception:
- GITLAB_IMP_ERR = traceback.format_exc()
- HAS_GITLAB_PACKAGE = False
from ansible_collections.community.general.plugins.module_utils.gitlab import (
- auth_argument_spec, gitlab_authentication, ensure_gitlab_package, filter_returned_variables
+ auth_argument_spec, gitlab_authentication, filter_returned_variables, vars_to_variables,
+ list_all_kwargs
)
-def vars_to_variables(vars, module):
- # transform old vars to new variables structure
- variables = list()
- for item, value in vars.items():
- if (isinstance(value, string_types) or
- isinstance(value, (integer_types, float))):
- variables.append(
- {
- "name": item,
- "value": str(value),
- "masked": False,
- "protected": False,
- "variable_type": "env_var",
- }
- )
-
- elif isinstance(value, dict):
-
- new_item = {
- "name": item,
- "value": value.get('value'),
- "masked": value.get('masked'),
- "protected": value.get('protected'),
- "variable_type": value.get('variable_type'),
- }
-
- if value.get('environment_scope'):
- new_item['environment_scope'] = value.get('environment_scope')
-
- variables.append(new_item)
-
- else:
- module.fail_json(msg="value must be of type string, integer, float or dict")
-
- return variables
-
-
class GitlabProjectVariables(object):
def __init__(self, module, gitlab_instance):
@@ -248,14 +241,7 @@ class GitlabProjectVariables(object):
return self.repo.projects.get(project_name)
def list_all_project_variables(self):
- page_nb = 1
- variables = []
- vars_page = self.project.variables.list(page=page_nb)
- while len(vars_page) > 0:
- variables += vars_page
- page_nb += 1
- vars_page = self.project.variables.list(page=page_nb)
- return variables
+ return list(self.project.variables.list(**list_all_kwargs))
def create_variable(self, var_obj):
if self._module.check_mode:
@@ -266,6 +252,7 @@ class GitlabProjectVariables(object):
"value": var_obj.get('value'),
"masked": var_obj.get('masked'),
"protected": var_obj.get('protected'),
+ "raw": var_obj.get('raw'),
"variable_type": var_obj.get('variable_type'),
}
@@ -322,7 +309,7 @@ def compare(requested_variables, existing_variables, state):
def native_python_main(this_gitlab, purge, requested_variables, state, module):
change = False
- return_value = dict(added=list(), updated=list(), removed=list(), untouched=list())
+ return_value = dict(added=[], updated=[], removed=[], untouched=[])
gitlab_keys = this_gitlab.list_all_project_variables()
before = [x.attributes for x in gitlab_keys]
@@ -336,6 +323,8 @@ def native_python_main(this_gitlab, purge, requested_variables, state, module):
item['value'] = str(item.get('value'))
if item.get('protected') is None:
item['protected'] = False
+ if item.get('raw') is None:
+ item['raw'] = False
if item.get('masked') is None:
item['masked'] = False
if item.get('environment_scope') is None:
@@ -391,7 +380,7 @@ def native_python_main(this_gitlab, purge, requested_variables, state, module):
if module.check_mode:
return_value = dict(added=added, updated=updated, removed=return_value['removed'], untouched=untouched)
- if return_value['added'] or return_value['removed'] or return_value['updated']:
+ if any(return_value[x] for x in ['added', 'removed', 'updated']):
change = True
gitlab_keys = this_gitlab.list_all_project_variables()
@@ -407,11 +396,14 @@ def main():
project=dict(type='str', required=True),
purge=dict(type='bool', required=False, default=False),
vars=dict(type='dict', required=False, default=dict(), no_log=True),
+ # please mind whenever changing the variables dict to also change module_utils/gitlab.py's
+ # KNOWN dict in filter_returned_variables or bad evil will happen
variables=dict(type='list', elements='dict', required=False, default=list(), options=dict(
name=dict(type='str', required=True),
value=dict(type='str', no_log=True),
masked=dict(type='bool', default=False),
protected=dict(type='bool', default=False),
+ raw=dict(type='bool', default=False),
environment_scope=dict(type='str', default='*'),
variable_type=dict(type='str', default='env_var', choices=["env_var", "file"]),
)),
@@ -436,10 +428,9 @@ def main():
],
supports_check_mode=True
)
- ensure_gitlab_package(module)
- if not HAS_GITLAB_PACKAGE:
- module.fail_json(msg=missing_required_lib("python-gitlab"), exception=GITLAB_IMP_ERR)
+ # check prerequisites and connect to gitlab server
+ gitlab_instance = gitlab_authentication(module)
purge = module.params['purge']
var_list = module.params['vars']
@@ -452,9 +443,7 @@ def main():
if state == 'present':
if any(x['value'] is None for x in variables):
- module.fail_json(msg='value parameter is required in state present')
-
- gitlab_instance = gitlab_authentication(module)
+ module.fail_json(msg='value parameter is required for all variables in state present')
this_gitlab = GitlabProjectVariables(module=module, gitlab_instance=gitlab_instance)
diff --git a/ansible_collections/community/general/plugins/modules/gitlab_protected_branch.py b/ansible_collections/community/general/plugins/modules/gitlab_protected_branch.py
index fea374cbf..8d2d75736 100644
--- a/ansible_collections/community/general/plugins/modules/gitlab_protected_branch.py
+++ b/ansible_collections/community/general/plugins/modules/gitlab_protected_branch.py
@@ -16,7 +16,6 @@ description:
author:
- "Werner Dijkerman (@dj-wasabi)"
requirements:
- - python >= 2.7
- python-gitlab >= 2.3.0
extends_documentation_fragment:
- community.general.auth_basic
@@ -44,7 +43,7 @@ options:
name:
description:
- The name of the branch that needs to be protected.
- - Can make use a wildcard character for like C(production/*) or just have C(main) or C(develop) as value.
+ - Can make use a wildcard character for like V(production/*) or just have V(main) or V(develop) as value.
required: true
type: str
merge_access_levels:
@@ -83,7 +82,7 @@ from ansible.module_utils.api import basic_auth_argument_spec
from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
from ansible_collections.community.general.plugins.module_utils.gitlab import (
- auth_argument_spec, gitlab_authentication, gitlab, ensure_gitlab_package
+ auth_argument_spec, gitlab_authentication, gitlab
)
@@ -94,9 +93,9 @@ class GitlabProtectedBranch(object):
self._module = module
self.project = self.get_project(project)
self.ACCESS_LEVEL = {
- 'nobody': gitlab.NO_ACCESS,
- 'developer': gitlab.DEVELOPER_ACCESS,
- 'maintainer': gitlab.MAINTAINER_ACCESS
+ 'nobody': gitlab.const.NO_ACCESS,
+ 'developer': gitlab.const.DEVELOPER_ACCESS,
+ 'maintainer': gitlab.const.MAINTAINER_ACCESS
}
def get_project(self, project_name):
@@ -164,7 +163,9 @@ def main():
],
supports_check_mode=True
)
- ensure_gitlab_package(module)
+
+ # check prerequisites and connect to gitlab server
+ gitlab_instance = gitlab_authentication(module)
project = module.params['project']
name = module.params['name']
@@ -177,7 +178,6 @@ def main():
module.fail_json(msg="community.general.gitlab_proteched_branch requires python-gitlab Python module >= 2.3.0 (installed version: [%s])."
" Please upgrade python-gitlab to version 2.3.0 or above." % gitlab_version)
- gitlab_instance = gitlab_authentication(module)
this_gitlab = GitlabProtectedBranch(module=module, project=project, gitlab_instance=gitlab_instance)
p_branch = this_gitlab.protected_branch_exist(name=name)
diff --git a/ansible_collections/community/general/plugins/modules/gitlab_runner.py b/ansible_collections/community/general/plugins/modules/gitlab_runner.py
index a41b135fc..e6163a6b6 100644
--- a/ansible_collections/community/general/plugins/modules/gitlab_runner.py
+++ b/ansible_collections/community/general/plugins/modules/gitlab_runner.py
@@ -24,13 +24,12 @@ description:
To create shared runners, you need to ask your administrator to give you this token.
It can be found at U(https://$GITLAB_URL/admin/runners/).
notes:
- - To create a new runner at least the C(api_token), C(description) and C(api_url) options are required.
+ - To create a new runner at least the O(api_token), O(description) and O(api_url) options are required.
- Runners need to have unique descriptions.
author:
- Samy Coenen (@SamyCoenen)
- Guillaume Martinez (@Lunik)
requirements:
- - python >= 2.7
- python-gitlab >= 1.5.0
extends_documentation_fragment:
- community.general.auth_basic
@@ -47,14 +46,16 @@ options:
group:
description:
- ID or full path of the group in the form group/subgroup.
- - Mutually exclusive with I(owned) and I(project).
+ - Mutually exclusive with O(owned) and O(project).
+ - Must be group's numeric ID if O(registration_token) is not set and O(state=present).
type: str
version_added: '6.5.0'
project:
description:
- ID or full path of the project in the form of group/name.
- - Mutually exclusive with I(owned) since community.general 4.5.0.
- - Mutually exclusive with I(group).
+ - Mutually exclusive with O(owned) since community.general 4.5.0.
+ - Mutually exclusive with O(group).
+ - Must be project's numeric ID if O(registration_token) is not set and O(state=present).
type: str
version_added: '3.7.0'
description:
@@ -73,23 +74,35 @@ options:
type: str
registration_token:
description:
- - The registration token is used to register new runners.
- - Required if I(state) is C(present).
+ - The registration token is used to register new runners before GitLab 16.0.
+ - Required if O(state=present) for GitLab < 16.0.
+ - If set, the runner will be created using the old runner creation workflow.
+ - If not set, the runner will be created using the new runner creation workflow, introduced in GitLab 16.0.
+ - If not set, requires python-gitlab >= 4.0.0.
type: str
owned:
description:
- Searches only runners available to the user when searching for existing, when false admin token required.
- - Mutually exclusive with I(project) since community.general 4.5.0.
- - Mutually exclusive with I(group).
+ - Mutually exclusive with O(project) since community.general 4.5.0.
+ - Mutually exclusive with O(group).
default: false
type: bool
version_added: 2.0.0
active:
description:
- Define if the runners is immediately active after creation.
+ - Mutually exclusive with O(paused).
required: false
default: true
type: bool
+ paused:
+ description:
+ - Define if the runners is active or paused after creation.
+ - Mutually exclusive with O(active).
+ required: false
+ default: false
+ type: bool
+ version_added: 8.1.0
locked:
description:
- Determines if the runner is locked or not.
@@ -99,23 +112,24 @@ options:
access_level:
description:
- Determines if a runner can pick up jobs only from protected branches.
- - If I(access_level_on_creation) is not explicitly set to C(true), this option is ignored on registration and
+ - If O(access_level_on_creation) is not explicitly set to V(true), this option is ignored on registration and
is only applied on updates.
- - If set to C(not_protected), runner can pick up jobs from both protected and unprotected branches.
- - If set to C(ref_protected), runner can pick up jobs only from protected branches.
- - The current default is C(ref_protected). This will change to no default in community.general 8.0.0.
- From that version on, if this option is not specified explicitly, GitLab will use C(not_protected)
- on creation, and the value set will not be changed on any updates.
+ - If set to V(not_protected), runner can pick up jobs from both protected and unprotected branches.
+ - If set to V(ref_protected), runner can pick up jobs only from protected branches.
+ - Before community.general 8.0.0 the default was V(ref_protected). This was changed to no default in community.general 8.0.0.
+ If this option is not specified explicitly, GitLab will use V(not_protected) on creation, and the value set
+ will not be changed on any updates.
required: false
choices: ["not_protected", "ref_protected"]
type: str
access_level_on_creation:
description:
- Whether the runner should be registered with an access level or not.
- - If set to C(true), the value of I(access_level) is used for runner registration.
- - If set to C(false), GitLab registers the runner with the default access level.
- - The current default of this option is C(false). This default is deprecated and will change to C(true) in commuinty.general 7.0.0.
+ - If set to V(true), the value of O(access_level) is used for runner registration.
+ - If set to V(false), GitLab registers the runner with the default access level.
+ - The default of this option changed to V(true) in community.general 7.0.0. Before, it was V(false).
required: false
+ default: true
type: bool
version_added: 6.3.0
maximum_timeout:
@@ -205,15 +219,11 @@ from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.common.text.converters import to_native
from ansible_collections.community.general.plugins.module_utils.gitlab import (
- auth_argument_spec, gitlab_authentication, gitlab, ensure_gitlab_package
+ auth_argument_spec, gitlab_authentication, gitlab, list_all_kwargs
)
-try:
- cmp # pylint: disable=used-before-assignment
-except NameError:
- def cmp(a, b):
- return (a > b) - (a < b)
+from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
class GitLabRunner(object):
@@ -238,27 +248,34 @@ class GitLabRunner(object):
changed = False
arguments = {
- 'active': options['active'],
'locked': options['locked'],
'run_untagged': options['run_untagged'],
'maximum_timeout': options['maximum_timeout'],
'tag_list': options['tag_list'],
}
+
+ if options.get('paused') is not None:
+ arguments['paused'] = options['paused']
+ else:
+ arguments['active'] = options['active']
+
if options.get('access_level') is not None:
arguments['access_level'] = options['access_level']
# Because we have already call userExists in main()
if self.runner_object is None:
arguments['description'] = description
- arguments['token'] = options['registration_token']
+ if options.get('registration_token') is not None:
+ arguments['token'] = options['registration_token']
+ elif options.get('group') is not None:
+ arguments['runner_type'] = 'group_type'
+ arguments['group_id'] = options['group']
+ elif options.get('project') is not None:
+ arguments['runner_type'] = 'project_type'
+ arguments['project_id'] = options['project']
+ else:
+ arguments['runner_type'] = 'instance_type'
access_level_on_creation = self._module.params['access_level_on_creation']
- if access_level_on_creation is None:
- message = "The option 'access_level_on_creation' is unspecified, so 'false' is assumed. "\
- "That means any value of 'access_level' is ignored and GitLab registers the runner with its default value. "\
- "The option 'access_level_on_creation' will switch to 'true' in community.general 7.0.0"
- self._module.deprecate(message, version='7.0.0', collection_name='community.general')
- access_level_on_creation = False
-
if not access_level_on_creation:
arguments.pop('access_level', None)
@@ -266,19 +283,17 @@ class GitLabRunner(object):
changed = True
else:
changed, runner = self.update_runner(self.runner_object, arguments)
+ if changed:
+ if self._module.check_mode:
+ self._module.exit_json(changed=True, msg="Successfully updated the runner %s" % description)
+
+ try:
+ runner.save()
+ except Exception as e:
+ self._module.fail_json(msg="Failed to update runner: %s " % to_native(e))
self.runner_object = runner
- if changed:
- if self._module.check_mode:
- self._module.exit_json(changed=True, msg="Successfully created or updated the runner %s" % description)
-
- try:
- runner.save()
- except Exception as e:
- self._module.fail_json(msg="Failed to update runner: %s " % to_native(e))
- return True
- else:
- return False
+ return changed
'''
@param arguments Attributes of the runner
@@ -288,7 +303,12 @@ class GitLabRunner(object):
return True
try:
- runner = self._gitlab.runners.create(arguments)
+ if arguments.get('token') is not None:
+ runner = self._gitlab.runners.create(arguments)
+ elif LooseVersion(gitlab.__version__) < LooseVersion('4.0.0'):
+ self._module.fail_json(msg="New runner creation workflow requires python-gitlab 4.0.0 or higher")
+ else:
+ runner = self._gitlab.user.runners.create(arguments)
except (gitlab.exceptions.GitlabCreateError) as e:
self._module.fail_json(msg="Failed to create runner: %s " % to_native(e))
@@ -308,7 +328,7 @@ class GitLabRunner(object):
list1.sort()
list2 = arguments[arg_key]
list2.sort()
- if cmp(list1, list2):
+ if list1 != list2:
setattr(runner, arg_key, arguments[arg_key])
changed = True
else:
@@ -322,7 +342,7 @@ class GitLabRunner(object):
@param description Description of the runner
'''
def find_runner(self, description):
- runners = self._runners_endpoint(as_list=False)
+ runners = self._runners_endpoint(**list_all_kwargs)
for runner in runners:
# python-gitlab 2.2 through at least 2.5 returns a list of dicts for list() instead of a Runner
@@ -361,12 +381,13 @@ def main():
argument_spec.update(dict(
description=dict(type='str', required=True, aliases=["name"]),
active=dict(type='bool', default=True),
+ paused=dict(type='bool', default=False),
owned=dict(type='bool', default=False),
tag_list=dict(type='list', elements='str', default=[]),
run_untagged=dict(type='bool', default=True),
locked=dict(type='bool', default=False),
access_level=dict(type='str', choices=["not_protected", "ref_protected"]),
- access_level_on_creation=dict(type='bool'),
+ access_level_on_creation=dict(type='bool', default=True),
maximum_timeout=dict(type='int', default=3600),
registration_token=dict(type='str', no_log=True),
project=dict(type='str'),
@@ -385,6 +406,7 @@ def main():
['project', 'owned'],
['group', 'owned'],
['project', 'group'],
+ ['active', 'paused'],
],
required_together=[
['api_username', 'api_password'],
@@ -392,12 +414,11 @@ def main():
required_one_of=[
['api_username', 'api_token', 'api_oauth_token', 'api_job_token'],
],
- required_if=[
- ('state', 'present', ['registration_token']),
- ],
supports_check_mode=True,
)
- ensure_gitlab_package(module)
+
+ # check prerequisites and connect to gitlab server
+ gitlab_instance = gitlab_authentication(module)
state = module.params['state']
runner_description = module.params['description']
@@ -411,16 +432,6 @@ def main():
project = module.params['project']
group = module.params['group']
- if access_level is None:
- message = "The option 'access_level' is unspecified, so 'ref_protected' is assumed. "\
- "In order to align the module with GitLab's runner API, this option will lose "\
- "its default value in community.general 8.0.0. From that version on, you must set "\
- "this option to 'ref_protected' explicitly, if you want to have a protected runner, "\
- "otherwise GitLab's default access level gets applied, which is 'not_protected'"
- module.deprecate(message, version='8.0.0', collection_name='community.general')
- access_level = 'ref_protected'
-
- gitlab_instance = gitlab_authentication(module)
gitlab_project = None
gitlab_group = None
@@ -454,6 +465,8 @@ def main():
"access_level": access_level,
"maximum_timeout": maximum_timeout,
"registration_token": registration_token,
+ "group": group,
+ "project": project,
}):
module.exit_json(changed=True, runner=gitlab_runner.runner_object._attrs,
msg="Successfully created or updated the runner %s" % runner_description)
diff --git a/ansible_collections/community/general/plugins/modules/gitlab_user.py b/ansible_collections/community/general/plugins/modules/gitlab_user.py
index 94f371316..6e5ab4ece 100644
--- a/ansible_collections/community/general/plugins/modules/gitlab_user.py
+++ b/ansible_collections/community/general/plugins/modules/gitlab_user.py
@@ -27,7 +27,6 @@ author:
- Lennert Mertens (@LennertMertens)
- Stef Graces (@stgrace)
requirements:
- - python >= 2.7
- python-gitlab python module
- administrator rights on the GitLab server
extends_documentation_fragment:
@@ -45,7 +44,7 @@ options:
name:
description:
- Name of the user you want to create.
- - Required only if C(state) is set to C(present).
+ - Required only if O(state=present).
type: str
username:
description:
@@ -66,7 +65,7 @@ options:
email:
description:
- The email that belongs to the user.
- - Required only if C(state) is set to C(present).
+ - Required only if O(state=present).
type: str
sshkey_name:
description:
@@ -123,7 +122,7 @@ options:
identities:
description:
- List of identities to be added/updated for this user.
- - To remove all other identities from this user, set I(overwrite_identities=true).
+ - To remove all other identities from this user, set O(overwrite_identities=true).
type: list
elements: dict
suboptions:
@@ -139,8 +138,8 @@ options:
overwrite_identities:
description:
- Overwrite identities with identities added in this module.
- - This means that all identities that the user has and that are not listed in I(identities) are removed from the user.
- - This is only done if a list is provided for I(identities). To remove all identities, provide an empty list.
+ - This means that all identities that the user has and that are not listed in O(identities) are removed from the user.
+ - This is only done if a list is provided for O(identities). To remove all identities, provide an empty list.
type: bool
default: false
version_added: 3.3.0
@@ -151,7 +150,6 @@ EXAMPLES = '''
community.general.gitlab_user:
api_url: https://gitlab.example.com/
api_token: "{{ access_token }}"
- validate_certs: false
username: myusername
state: absent
@@ -191,7 +189,6 @@ EXAMPLES = '''
community.general.gitlab_user:
api_url: https://gitlab.example.com/
api_token: "{{ access_token }}"
- validate_certs: false
username: myusername
state: blocked
@@ -199,7 +196,6 @@ EXAMPLES = '''
community.general.gitlab_user:
api_url: https://gitlab.example.com/
api_token: "{{ access_token }}"
- validate_certs: false
username: myusername
state: unblocked
'''
@@ -234,7 +230,7 @@ from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.common.text.converters import to_native
from ansible_collections.community.general.plugins.module_utils.gitlab import (
- auth_argument_spec, find_group, gitlab_authentication, gitlab, ensure_gitlab_package
+ auth_argument_spec, find_group, gitlab_authentication, gitlab, list_all_kwargs
)
@@ -244,12 +240,12 @@ class GitLabUser(object):
self._gitlab = gitlab_instance
self.user_object = None
self.ACCESS_LEVEL = {
- 'guest': gitlab.GUEST_ACCESS,
- 'reporter': gitlab.REPORTER_ACCESS,
- 'developer': gitlab.DEVELOPER_ACCESS,
- 'master': gitlab.MAINTAINER_ACCESS,
- 'maintainer': gitlab.MAINTAINER_ACCESS,
- 'owner': gitlab.OWNER_ACCESS,
+ 'guest': gitlab.const.GUEST_ACCESS,
+ 'reporter': gitlab.const.REPORTER_ACCESS,
+ 'developer': gitlab.const.DEVELOPER_ACCESS,
+ 'master': gitlab.const.MAINTAINER_ACCESS,
+ 'maintainer': gitlab.const.MAINTAINER_ACCESS,
+ 'owner': gitlab.const.OWNER_ACCESS,
}
'''
@@ -349,9 +345,10 @@ class GitLabUser(object):
@param sshkey_name Name of the ssh key
'''
def ssh_key_exists(self, user, sshkey_name):
- keyList = map(lambda k: k.title, user.keys.list(all=True))
-
- return sshkey_name in keyList
+ return any(
+ k.title == sshkey_name
+ for k in user.keys.list(**list_all_kwargs)
+ )
'''
@param user User object
@@ -485,7 +482,7 @@ class GitLabUser(object):
'''
@param user User object
- @param identites List of identities to be added/updated
+ @param identities List of identities to be added/updated
@param overwrite_identities Overwrite user identities with identities passed to this module
'''
def add_identities(self, user, identities, overwrite_identities=False):
@@ -504,7 +501,7 @@ class GitLabUser(object):
'''
@param user User object
- @param identites List of identities to be added/updated
+ @param identities List of identities to be added/updated
'''
def delete_identities(self, user, identities):
changed = False
@@ -519,10 +516,13 @@ class GitLabUser(object):
@param username Username of the user
'''
def find_user(self, username):
- users = self._gitlab.users.list(search=username, all=True)
- for user in users:
- if (user.username == username):
- return user
+ return next(
+ (
+ user for user in self._gitlab.users.list(search=username, **list_all_kwargs)
+ if user.username == username
+ ),
+ None
+ )
'''
@param username Username of the user
@@ -616,7 +616,9 @@ def main():
('state', 'present', ['name', 'email']),
)
)
- ensure_gitlab_package(module)
+
+ # check prerequisites and connect to gitlab server
+ gitlab_instance = gitlab_authentication(module)
user_name = module.params['name']
state = module.params['state']
@@ -635,8 +637,6 @@ def main():
user_identities = module.params['identities']
overwrite_identities = module.params['overwrite_identities']
- gitlab_instance = gitlab_authentication(module)
-
gitlab_user = GitLabUser(module, gitlab_instance)
user_exists = gitlab_user.exists_user(user_username)
if user_exists:
diff --git a/ansible_collections/community/general/plugins/modules/grove.py b/ansible_collections/community/general/plugins/modules/grove.py
index b3e0508ff..b50546b4d 100644
--- a/ansible_collections/community/general/plugins/modules/grove.py
+++ b/ansible_collections/community/general/plugins/modules/grove.py
@@ -39,7 +39,7 @@ options:
type: str
description:
- Message content.
- - The alias I(message) is deprecated and will be removed in community.general 4.0.0.
+ - The alias O(ignore:message) has been removed in community.general 4.0.0.
required: true
url:
type: str
@@ -53,7 +53,7 @@ options:
required: false
validate_certs:
description:
- - If C(false), SSL certificates will not be validated. This should only be used
+ - If V(false), SSL certificates will not be validated. This should only be used
on personally controlled sites using self-signed certificates.
default: true
type: bool
diff --git a/ansible_collections/community/general/plugins/modules/hana_query.py b/ansible_collections/community/general/plugins/modules/hana_query.py
deleted file mode 100644
index 0b12e9935..000000000
--- a/ansible_collections/community/general/plugins/modules/hana_query.py
+++ /dev/null
@@ -1,219 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# Copyright (c) 2021, Rainer Leber <rainerleber@gmail.com>
-# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
-# SPDX-License-Identifier: GPL-3.0-or-later
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-DOCUMENTATION = r'''
----
-module: hana_query
-short_description: Execute SQL on HANA
-version_added: 3.2.0
-description: This module executes SQL statements on HANA with hdbsql.
-extends_documentation_fragment:
- - community.general.attributes
-attributes:
- check_mode:
- support: none
- diff_mode:
- support: none
-options:
- sid:
- description: The system ID.
- type: str
- required: true
- instance:
- description: The instance number.
- type: str
- required: true
- user:
- description: A dedicated username. The user could be also in hdbuserstore. Defaults to C(SYSTEM).
- type: str
- default: SYSTEM
- userstore:
- description: If C(true) the user must be in hdbuserstore.
- type: bool
- default: false
- version_added: 3.5.0
- password:
- description:
- - The password to connect to the database.
- - "B(Note:) Since the passwords have to be passed as command line arguments, I(userstore=true) should
- be used whenever possible, as command line arguments can be seen by other users
- on the same machine."
- type: str
- autocommit:
- description: Autocommit the statement.
- type: bool
- default: true
- host:
- description: The Host IP address. The port can be defined as well.
- type: str
- database:
- description: Define the database on which to connect.
- type: str
- encrypted:
- description: Use encrypted connection. Defaults to C(false).
- type: bool
- default: false
- filepath:
- description:
- - One or more files each containing one SQL query to run.
- - Must be a string or list containing strings.
- type: list
- elements: path
- query:
- description:
- - SQL query to run.
- - Must be a string or list containing strings. Please note that if you supply a string, it will be split by commas (C(,)) to a list.
- It is better to supply a one-element list instead to avoid mangled input.
- type: list
- elements: str
-author:
- - Rainer Leber (@rainerleber)
-'''
-
-EXAMPLES = r'''
-- name: Simple select query
- community.general.hana_query:
- sid: "hdb"
- instance: "01"
- password: "Test123"
- query: "select user_name from users"
-
-- name: Run several queries
- community.general.hana_query:
- sid: "hdb"
- instance: "01"
- password: "Test123"
- query:
- - "select user_name from users;"
- - select * from SYSTEM;
- host: "localhost"
- autocommit: false
-
-- name: Run several queries from file
- community.general.hana_query:
- sid: "hdb"
- instance: "01"
- password: "Test123"
- filepath:
- - /tmp/HANA_CPU_UtilizationPerCore_2.00.020+.txt
- - /tmp/HANA.txt
- host: "localhost"
-
-- name: Run several queries from user store
- community.general.hana_query:
- sid: "hdb"
- instance: "01"
- user: hdbstoreuser
- userstore: true
- query:
- - "select user_name from users;"
- - select * from users;
- autocommit: false
-'''
-
-RETURN = r'''
-query_result:
- description: List containing results of all queries executed (one sublist for every query).
- returned: on success
- type: list
- elements: list
- sample: [[{"Column": "Value1"}, {"Column": "Value2"}], [{"Column": "Value1"}, {"Column": "Value2"}]]
-'''
-
-import csv
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.six import StringIO
-from ansible.module_utils.common.text.converters import to_native
-
-
-def csv_to_list(rawcsv):
- reader_raw = csv.DictReader(StringIO(rawcsv))
- reader = [dict((k, v.strip()) for k, v in row.items()) for row in reader_raw]
- return list(reader)
-
-
-def main():
- module = AnsibleModule(
- argument_spec=dict(
- sid=dict(type='str', required=True),
- instance=dict(type='str', required=True),
- encrypted=dict(type='bool', default=False),
- host=dict(type='str', required=False),
- user=dict(type='str', default="SYSTEM"),
- userstore=dict(type='bool', default=False),
- password=dict(type='str', no_log=True),
- database=dict(type='str', required=False),
- query=dict(type='list', elements='str', required=False),
- filepath=dict(type='list', elements='path', required=False),
- autocommit=dict(type='bool', default=True),
- ),
- required_one_of=[('query', 'filepath')],
- required_if=[('userstore', False, ['password'])],
- supports_check_mode=False,
- )
- rc, out, err, out_raw = [0, [], "", ""]
-
- params = module.params
-
- sid = (params['sid']).upper()
- instance = params['instance']
- user = params['user']
- userstore = params['userstore']
- password = params['password']
- autocommit = params['autocommit']
- host = params['host']
- database = params['database']
- encrypted = params['encrypted']
-
- filepath = params['filepath']
- query = params['query']
-
- bin_path = "/usr/sap/{sid}/HDB{instance}/exe/hdbsql".format(sid=sid, instance=instance)
-
- try:
- command = [module.get_bin_path(bin_path, required=True)]
- except Exception as e:
- module.fail_json(msg='Failed to find hdbsql at the expected path "{0}". Please check SID and instance number: "{1}"'.format(bin_path, to_native(e)))
-
- if encrypted is True:
- command.extend(['-attemptencrypt'])
- if autocommit is False:
- command.extend(['-z'])
- if host is not None:
- command.extend(['-n', host])
- if database is not None:
- command.extend(['-d', database])
- # -x Suppresses additional output, such as the number of selected rows in a result set.
- if userstore:
- command.extend(['-x', '-U', user])
- else:
- command.extend(['-x', '-i', instance, '-u', user, '-p', password])
-
- if filepath is not None:
- command.extend(['-I'])
- for p in filepath:
- # makes a command like hdbsql -i 01 -u SYSTEM -p secret123# -I /tmp/HANA_CPU_UtilizationPerCore_2.00.020+.txt,
- # iterates through files and append the output to var out.
- query_command = command + [p]
- (rc, out_raw, err) = module.run_command(query_command)
- out.append(csv_to_list(out_raw))
- if query is not None:
- for q in query:
- # makes a command like hdbsql -i 01 -u SYSTEM -p secret123# "select user_name from users",
- # iterates through multiple commands and append the output to var out.
- query_command = command + [q]
- (rc, out_raw, err) = module.run_command(query_command)
- out.append(csv_to_list(out_raw))
- changed = True
-
- module.exit_json(changed=changed, rc=rc, query_result=out, stderr=err)
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/general/plugins/modules/haproxy.py b/ansible_collections/community/general/plugins/modules/haproxy.py
index 56f987d80..05f52d55c 100644
--- a/ansible_collections/community/general/plugins/modules/haproxy.py
+++ b/ansible_collections/community/general/plugins/modules/haproxy.py
@@ -65,7 +65,7 @@ options:
state:
description:
- Desired state of the provided backend host.
- - Note that C(drain) state was added in version 2.4.
+ - Note that V(drain) state was added in version 2.4.
- It is supported only by HAProxy version 1.5 or later,
- When used on versions < 1.5, it will be ignored.
type: str
@@ -73,13 +73,13 @@ options:
choices: [ disabled, drain, enabled ]
agent:
description:
- - Disable/enable agent checks (depending on I(state) value).
+ - Disable/enable agent checks (depending on O(state) value).
type: bool
default: false
version_added: 1.0.0
health:
description:
- - Disable/enable health checks (depending on I(state) value).
+ - Disable/enable health checks (depending on O(state) value).
type: bool
default: false
version_added: "1.0.0"
@@ -90,8 +90,8 @@ options:
default: false
wait:
description:
- - Wait until the server reports a status of C(UP) when I(state=enabled),
- status of C(MAINT) when I(state=disabled) or status of C(DRAIN) when I(state=drain).
+ - Wait until the server reports a status of C(UP) when O(state=enabled),
+ status of C(MAINT) when O(state=disabled) or status of C(DRAIN) when O(state=drain).
type: bool
default: false
wait_interval:
@@ -107,7 +107,7 @@ options:
weight:
description:
- The value passed in argument.
- - If the value ends with the C(%) sign, then the new weight will be
+ - If the value ends with the V(%) sign, then the new weight will be
relative to the initially configured weight.
- Relative weights are only permitted between 0 and 100% and absolute
weights are permitted between 0 and 256.
diff --git a/ansible_collections/community/general/plugins/modules/heroku_collaborator.py b/ansible_collections/community/general/plugins/modules/heroku_collaborator.py
index e7b0de3f9..e07ae333d 100644
--- a/ansible_collections/community/general/plugins/modules/heroku_collaborator.py
+++ b/ansible_collections/community/general/plugins/modules/heroku_collaborator.py
@@ -14,9 +14,9 @@ module: heroku_collaborator
short_description: Add or delete app collaborators on Heroku
description:
- Manages collaborators for Heroku apps.
- - If set to C(present) and heroku user is already collaborator, then do nothing.
- - If set to C(present) and heroku user is not collaborator, then add user to app.
- - If set to C(absent) and heroku user is collaborator, then delete user from app.
+ - If set to V(present) and heroku user is already collaborator, then do nothing.
+ - If set to V(present) and heroku user is not collaborator, then add user to app.
+ - If set to V(absent) and heroku user is collaborator, then delete user from app.
author:
- Marcel Arns (@marns93)
requirements:
@@ -56,8 +56,8 @@ options:
choices: ["present", "absent"]
default: "present"
notes:
- - C(HEROKU_API_KEY) and C(TF_VAR_HEROKU_API_KEY) env variable can be used instead setting C(api_key).
- - If you use I(--check), you can also pass the I(-v) flag to see affected apps in C(msg), e.g. ["heroku-example-app"].
+ - E(HEROKU_API_KEY) and E(TF_VAR_HEROKU_API_KEY) environment variables can be used instead setting O(api_key).
+ - If you use C(check_mode), you can also pass the C(-v) flag to see affected apps in C(msg), e.g. ["heroku-example-app"].
'''
EXAMPLES = '''
diff --git a/ansible_collections/community/general/plugins/modules/hg.py b/ansible_collections/community/general/plugins/modules/hg.py
index dbbd504b4..4b6b7c433 100644
--- a/ansible_collections/community/general/plugins/modules/hg.py
+++ b/ansible_collections/community/general/plugins/modules/hg.py
@@ -43,8 +43,7 @@ options:
type: str
force:
description:
- - Discards uncommitted changes. Runs C(hg update -C). Prior to
- 1.9, the default was C(true).
+ - Discards uncommitted changes. Runs C(hg update -C).
type: bool
default: false
purge:
@@ -54,12 +53,12 @@ options:
default: false
update:
description:
- - If C(false), do not retrieve new revisions from the origin repository
+ - If V(false), do not retrieve new revisions from the origin repository
type: bool
default: true
clone:
description:
- - If C(false), do not clone the repository if it does not exist locally.
+ - If V(false), do not clone the repository if it does not exist locally.
type: bool
default: true
executable:
diff --git a/ansible_collections/community/general/plugins/modules/hipchat.py b/ansible_collections/community/general/plugins/modules/hipchat.py
index 11b5fb735..83e253679 100644
--- a/ansible_collections/community/general/plugins/modules/hipchat.py
+++ b/ansible_collections/community/general/plugins/modules/hipchat.py
@@ -64,7 +64,7 @@ options:
default: true
validate_certs:
description:
- - If C(false), SSL certificates will not be validated. This should only be used
+ - If V(false), SSL certificates will not be validated. This should only be used
on personally controlled sites using self-signed certificates.
type: bool
default: true
diff --git a/ansible_collections/community/general/plugins/modules/homebrew.py b/ansible_collections/community/general/plugins/modules/homebrew.py
index 7592f95a4..5d471797a 100644
--- a/ansible_collections/community/general/plugins/modules/homebrew.py
+++ b/ansible_collections/community/general/plugins/modules/homebrew.py
@@ -42,9 +42,9 @@ options:
elements: str
path:
description:
- - "A C(:) separated list of paths to search for C(brew) executable.
- Since a package (I(formula) in homebrew parlance) location is prefixed relative to the actual path of I(brew) command,
- providing an alternative I(brew) path enables managing different set of packages in an alternative location in the system."
+ - "A V(:) separated list of paths to search for C(brew) executable.
+ Since a package (I(formula) in homebrew parlance) location is prefixed relative to the actual path of C(brew) command,
+ providing an alternative C(brew) path enables managing different set of packages in an alternative location in the system."
default: '/usr/local/bin:/opt/homebrew/bin:/home/linuxbrew/.linuxbrew/bin'
type: path
state:
@@ -78,7 +78,7 @@ options:
version_added: '0.2.0'
notes:
- When used with a C(loop:) each package will be processed individually,
- it is much more efficient to pass the list directly to the I(name) option.
+ it is much more efficient to pass the list directly to the O(name) option.
'''
EXAMPLES = '''
@@ -87,7 +87,7 @@ EXAMPLES = '''
name: foo
state: present
-# Install formula foo with 'brew' in alternate path C(/my/other/location/bin)
+# Install formula foo with 'brew' in alternate path (/my/other/location/bin)
- community.general.homebrew:
name: foo
path: /my/other/location/bin
@@ -165,6 +165,7 @@ changed_pkgs:
version_added: '0.2.0'
'''
+import json
import os.path
import re
@@ -184,6 +185,10 @@ def _create_regex_group_complement(s):
chars = filter(None, (line.split('#')[0].strip() for line in lines))
group = r'[^' + r''.join(chars) + r']'
return re.compile(group)
+
+
+def _check_package_in_json(json_output, package_type):
+ return bool(json_output.get(package_type, []) and json_output[package_type][0].get("installed"))
# /utils ------------------------------------------------------------------ }}}
@@ -479,17 +484,17 @@ class Homebrew(object):
cmd = [
"{brew_path}".format(brew_path=self.brew_path),
"info",
+ "--json=v2",
self.current_package,
]
rc, out, err = self.module.run_command(cmd)
- for line in out.split('\n'):
- if (
- re.search(r'Built from source', line)
- or re.search(r'Poured from bottle', line)
- ):
- return True
-
- return False
+ if err:
+ self.failed = True
+ self.message = err.strip()
+ raise HomebrewException(self.message)
+ data = json.loads(out)
+
+ return _check_package_in_json(data, "formulae") or _check_package_in_json(data, "casks")
def _current_package_is_outdated(self):
if not self.valid_package(self.current_package):
diff --git a/ansible_collections/community/general/plugins/modules/homebrew_tap.py b/ansible_collections/community/general/plugins/modules/homebrew_tap.py
index b230dbb34..151d09d32 100644
--- a/ansible_collections/community/general/plugins/modules/homebrew_tap.py
+++ b/ansible_collections/community/general/plugins/modules/homebrew_tap.py
@@ -42,7 +42,7 @@ options:
- The optional git URL of the repository to tap. The URL is not
assumed to be on GitHub, and the protocol doesn't have to be HTTP.
Any location and protocol that git can handle is fine.
- - I(name) option may not be a list of multiple taps (but a single
+ - O(name) option may not be a list of multiple taps (but a single
tap instead) when this option is provided.
required: false
type: str
@@ -55,7 +55,7 @@ options:
type: str
path:
description:
- - "A C(:) separated list of paths to search for C(brew) executable."
+ - "A V(:) separated list of paths to search for C(brew) executable."
default: '/usr/local/bin:/opt/homebrew/bin:/home/linuxbrew/.linuxbrew/bin'
type: path
version_added: '2.1.0'
diff --git a/ansible_collections/community/general/plugins/modules/homectl.py b/ansible_collections/community/general/plugins/modules/homectl.py
index 301e388d3..ca4c19a87 100644
--- a/ansible_collections/community/general/plugins/modules/homectl.py
+++ b/ansible_collections/community/general/plugins/modules/homectl.py
@@ -37,7 +37,7 @@ options:
- Homed requires this value to be in cleartext on user creation and updating a user.
- The module takes the password and generates a password hash in SHA-512 with 10000 rounds of salt generation using crypt.
- See U(https://systemd.io/USER_RECORD/).
- - This is required for I(state=present). When an existing user is updated this is checked against the stored hash in homed.
+ - This is required for O(state=present). When an existing user is updated this is checked against the stored hash in homed.
type: str
state:
description:
@@ -55,11 +55,11 @@ options:
disksize:
description:
- The intended home directory disk space.
- - Human readable value such as C(10G), C(10M), or C(10B).
+ - Human readable value such as V(10G), V(10M), or V(10B).
type: str
resize:
description:
- - When used with I(disksize) this will attempt to resize the home directory immediately.
+ - When used with O(disksize) this will attempt to resize the home directory immediately.
default: false
type: bool
realname:
@@ -90,7 +90,7 @@ options:
description:
- Path to use as home directory for the user.
- This is the directory the user's home directory is mounted to while the user is logged in.
- - This is not where the user's data is actually stored, see I(imagepath) for that.
+ - This is not where the user's data is actually stored, see O(imagepath) for that.
- Only used when a user is first created.
type: path
imagepath:
@@ -102,25 +102,25 @@ options:
uid:
description:
- Sets the UID of the user.
- - If using I(gid) homed requires the value to be the same.
+ - If using O(gid) homed requires the value to be the same.
- Only used when a user is first created.
type: int
gid:
description:
- Sets the gid of the user.
- - If using I(uid) homed requires the value to be the same.
+ - If using O(uid) homed requires the value to be the same.
- Only used when a user is first created.
type: int
mountopts:
description:
- String separated by comma each indicating mount options for a users home directory.
- - Valid options are C(nosuid), C(nodev) or C(noexec).
- - Homed by default uses C(nodev) and C(nosuid) while C(noexec) is off.
+ - Valid options are V(nosuid), V(nodev) or V(noexec).
+ - Homed by default uses V(nodev) and V(nosuid) while V(noexec) is off.
type: str
umask:
description:
- Sets the umask for the user's login sessions
- - Value from C(0000) to C(0777).
+ - Value from V(0000) to V(0777).
type: int
memberof:
description:
@@ -132,13 +132,13 @@ options:
description:
- The absolute path to the skeleton directory to populate a new home directory from.
- This is only used when a home directory is first created.
- - If not specified homed by default uses C(/etc/skel).
+ - If not specified homed by default uses V(/etc/skel).
aliases: [ 'skel' ]
type: path
shell:
description:
- Shell binary to use for terminal logins of given user.
- - If not specified homed by default uses C(/bin/bash).
+ - If not specified homed by default uses V(/bin/bash).
type: str
environment:
description:
@@ -151,7 +151,7 @@ options:
timezone:
description:
- Preferred timezone to use for the user.
- - Should be a tzdata compatible location string such as C(America/New_York).
+ - Should be a tzdata compatible location string such as V(America/New_York).
type: str
locked:
description:
@@ -160,7 +160,7 @@ options:
language:
description:
- The preferred language/locale for the user.
- - This should be in a format compatible with the C($LANG) environment variable.
+ - This should be in a format compatible with the E(LANG) environment variable.
type: str
passwordhint:
description:
@@ -393,7 +393,7 @@ class Homectl(object):
user_metadata.pop('status', None)
# Let last change Usec be updated by homed when command runs.
user_metadata.pop('lastChangeUSec', None)
- # Now only change fields that are called on leaving whats currently in the record intact.
+ # Now only change fields that are called on leaving what's currently in the record intact.
record = user_metadata
record['userName'] = self.name
@@ -439,7 +439,7 @@ class Homectl(object):
self.result['changed'] = True
if self.disksize:
- # convert humand readble to bytes
+ # convert human readable to bytes
if self.disksize != record.get('diskSize'):
record['diskSize'] = human_to_bytes(self.disksize)
self.result['changed'] = True
diff --git a/ansible_collections/community/general/plugins/modules/honeybadger_deployment.py b/ansible_collections/community/general/plugins/modules/honeybadger_deployment.py
index 820e4538e..cf52745ac 100644
--- a/ansible_collections/community/general/plugins/modules/honeybadger_deployment.py
+++ b/ansible_collections/community/general/plugins/modules/honeybadger_deployment.py
@@ -52,7 +52,7 @@ options:
default: "https://api.honeybadger.io/v1/deploys"
validate_certs:
description:
- - If C(false), SSL certificates for the target url will not be validated. This should only be used
+ - If V(false), SSL certificates for the target url will not be validated. This should only be used
on personally controlled sites using self-signed certificates.
type: bool
default: true
diff --git a/ansible_collections/community/general/plugins/modules/hpilo_info.py b/ansible_collections/community/general/plugins/modules/hpilo_info.py
index cef6597e4..d329764b4 100644
--- a/ansible_collections/community/general/plugins/modules/hpilo_info.py
+++ b/ansible_collections/community/general/plugins/modules/hpilo_info.py
@@ -19,8 +19,6 @@ description:
These information includes hardware and network related information useful
for provisioning (e.g. macaddress, uuid).
- This module requires the C(hpilo) python module.
-- This module was called C(hpilo_facts) before Ansible 2.9, returning C(ansible_facts).
- Note that the M(community.general.hpilo_info) module no longer returns C(ansible_facts)!
extends_documentation_fragment:
- community.general.attributes
- community.general.attributes.info_module
@@ -125,7 +123,7 @@ hw_uuid:
host_power_status:
description:
- Power status of host.
- - Will be one of C(ON), C(OFF) and C(UNKNOWN).
+ - Will be one of V(ON), V(OFF) and V(UNKNOWN).
returned: always
type: str
sample: "ON"
diff --git a/ansible_collections/community/general/plugins/modules/htpasswd.py b/ansible_collections/community/general/plugins/modules/htpasswd.py
index 180b02073..9633ce2fb 100644
--- a/ansible_collections/community/general/plugins/modules/htpasswd.py
+++ b/ansible_collections/community/general/plugins/modules/htpasswd.py
@@ -26,51 +26,53 @@ options:
required: true
aliases: [ dest, destfile ]
description:
- - Path to the file that contains the usernames and passwords
+ - Path to the file that contains the usernames and passwords.
name:
type: str
required: true
aliases: [ username ]
description:
- - User name to add or remove
+ - User name to add or remove.
password:
type: str
required: false
description:
- Password associated with user.
- Must be specified if user does not exist yet.
- crypt_scheme:
+ hash_scheme:
type: str
required: false
default: "apr_md5_crypt"
description:
- - Encryption scheme to be used. As well as the four choices listed
+ - Hashing scheme to be used. As well as the four choices listed
here, you can also use any other hash supported by passlib, such as
- C(portable_apache22) and C(host_apache24); or C(md5_crypt) and C(sha256_crypt),
- which are Linux passwd hashes. Only some schemes in addition to
+ V(portable_apache22) and V(host_apache24); or V(md5_crypt) and V(sha256_crypt),
+ which are Linux passwd hashes. Only some schemes in addition to
the four choices below will be compatible with Apache or Nginx, and
supported schemes depend on passlib version and its dependencies.
- See U(https://passlib.readthedocs.io/en/stable/lib/passlib.apache.html#passlib.apache.HtpasswdFile) parameter C(default_scheme).
- - 'Some of the available choices might be: C(apr_md5_crypt), C(des_crypt), C(ldap_sha1), C(plaintext).'
+ - 'Some of the available choices might be: V(apr_md5_crypt), V(des_crypt), V(ldap_sha1), V(plaintext).'
+ aliases: [crypt_scheme]
state:
type: str
required: false
choices: [ present, absent ]
default: "present"
description:
- - Whether the user entry should be present or not
+ - Whether the user entry should be present or not.
create:
required: false
type: bool
default: true
description:
- - Used with I(state=present). If specified, the file will be created
- if it does not already exist. If set to C(false), will fail if the
- file does not exist
+ - Used with O(state=present). If V(true), the file will be created
+ if it does not exist. Conversely, if set to V(false) and the file
+ does not exist it will fail.
notes:
- - "This module depends on the I(passlib) Python library, which needs to be installed on all target systems."
- - "On Debian, Ubuntu, or Fedora: install I(python-passlib)."
- - "On RHEL or CentOS: Enable EPEL, then install I(python-passlib)."
+ - "This module depends on the C(passlib) Python library, which needs to be installed on all target systems."
+ - "On Debian < 11, Ubuntu <= 20.04, or Fedora: install C(python-passlib)."
+ - "On Debian, Ubuntu: install C(python3-passlib)."
+ - "On RHEL or CentOS: Enable EPEL, then install C(python-passlib)."
requirements: [ passlib>=1.6 ]
author: "Ansible Core Team"
extends_documentation_fragment:
@@ -99,28 +101,22 @@ EXAMPLES = """
path: /etc/mail/passwords
name: alex
password: oedu2eGh
- crypt_scheme: md5_crypt
+ hash_scheme: md5_crypt
"""
import os
import tempfile
-import traceback
-from ansible.module_utils.basic import AnsibleModule, missing_required_lib
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.community.general.plugins.module_utils import deps
from ansible.module_utils.common.text.converters import to_native
-from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
-PASSLIB_IMP_ERR = None
-try:
+with deps.declare("passlib"):
from passlib.apache import HtpasswdFile, htpasswd_context
from passlib.context import CryptContext
- import passlib
-except ImportError:
- PASSLIB_IMP_ERR = traceback.format_exc()
- passlib_installed = False
-else:
- passlib_installed = True
+
apache_hashes = ["apr_md5_crypt", "des_crypt", "ldap_sha1", "plaintext"]
@@ -131,50 +127,34 @@ def create_missing_directories(dest):
os.makedirs(destpath)
-def present(dest, username, password, crypt_scheme, create, check_mode):
+def present(dest, username, password, hash_scheme, create, check_mode):
""" Ensures user is present
Returns (msg, changed) """
- if crypt_scheme in apache_hashes:
+ if hash_scheme in apache_hashes:
context = htpasswd_context
else:
- context = CryptContext(schemes=[crypt_scheme] + apache_hashes)
+ context = CryptContext(schemes=[hash_scheme] + apache_hashes)
if not os.path.exists(dest):
if not create:
raise ValueError('Destination %s does not exist' % dest)
if check_mode:
return ("Create %s" % dest, True)
create_missing_directories(dest)
- if LooseVersion(passlib.__version__) >= LooseVersion('1.6'):
- ht = HtpasswdFile(dest, new=True, default_scheme=crypt_scheme, context=context)
- else:
- ht = HtpasswdFile(dest, autoload=False, default=crypt_scheme, context=context)
- if getattr(ht, 'set_password', None):
- ht.set_password(username, password)
- else:
- ht.update(username, password)
+ ht = HtpasswdFile(dest, new=True, default_scheme=hash_scheme, context=context)
+ ht.set_password(username, password)
ht.save()
return ("Created %s and added %s" % (dest, username), True)
else:
- if LooseVersion(passlib.__version__) >= LooseVersion('1.6'):
- ht = HtpasswdFile(dest, new=False, default_scheme=crypt_scheme, context=context)
- else:
- ht = HtpasswdFile(dest, default=crypt_scheme, context=context)
+ ht = HtpasswdFile(dest, new=False, default_scheme=hash_scheme, context=context)
- found = None
- if getattr(ht, 'check_password', None):
- found = ht.check_password(username, password)
- else:
- found = ht.verify(username, password)
+ found = ht.check_password(username, password)
if found:
return ("%s already present" % username, False)
else:
if not check_mode:
- if getattr(ht, 'set_password', None):
- ht.set_password(username, password)
- else:
- ht.update(username, password)
+ ht.set_password(username, password)
ht.save()
return ("Add/update %s" % username, True)
@@ -183,10 +163,7 @@ def absent(dest, username, check_mode):
""" Ensures user is absent
Returns (msg, changed) """
- if LooseVersion(passlib.__version__) >= LooseVersion('1.6'):
- ht = HtpasswdFile(dest, new=False)
- else:
- ht = HtpasswdFile(dest)
+ ht = HtpasswdFile(dest, new=False)
if username not in ht.users():
return ("%s not present" % username, False)
@@ -215,7 +192,7 @@ def main():
path=dict(type='path', required=True, aliases=["dest", "destfile"]),
name=dict(type='str', required=True, aliases=["username"]),
password=dict(type='str', required=False, default=None, no_log=True),
- crypt_scheme=dict(type='str', required=False, default="apr_md5_crypt"),
+ hash_scheme=dict(type='str', required=False, default="apr_md5_crypt", aliases=["crypt_scheme"]),
state=dict(type='str', required=False, default="present", choices=["present", "absent"]),
create=dict(type='bool', default=True),
@@ -227,25 +204,18 @@ def main():
path = module.params['path']
username = module.params['name']
password = module.params['password']
- crypt_scheme = module.params['crypt_scheme']
+ hash_scheme = module.params['hash_scheme']
state = module.params['state']
create = module.params['create']
check_mode = module.check_mode
- if not passlib_installed:
- module.fail_json(msg=missing_required_lib("passlib"), exception=PASSLIB_IMP_ERR)
+ deps.validate(module)
+ # TODO double check if this hack below is still needed.
# Check file for blank lines in effort to avoid "need more than 1 value to unpack" error.
try:
- f = open(path, "r")
- except IOError:
- # No preexisting file to remove blank lines from
- f = None
- else:
- try:
+ with open(path, "r") as f:
lines = f.readlines()
- finally:
- f.close()
# If the file gets edited, it returns true, so only edit the file if it has blank lines
strip = False
@@ -259,15 +229,16 @@ def main():
if check_mode:
temp = tempfile.NamedTemporaryFile()
path = temp.name
- f = open(path, "w")
- try:
- [f.write(line) for line in lines if line.strip()]
- finally:
- f.close()
+ with open(path, "w") as f:
+ f.writelines(line for line in lines if line.strip())
+
+ except IOError:
+ # No preexisting file to remove blank lines from
+ pass
try:
if state == 'present':
- (msg, changed) = present(path, username, password, crypt_scheme, create, check_mode)
+ (msg, changed) = present(path, username, password, hash_scheme, create, check_mode)
elif state == 'absent':
if not os.path.exists(path):
module.exit_json(msg="%s not present" % username,
diff --git a/ansible_collections/community/general/plugins/modules/hwc_ecs_instance.py b/ansible_collections/community/general/plugins/modules/hwc_ecs_instance.py
index 434db242f..9ba95dc96 100644
--- a/ansible_collections/community/general/plugins/modules/hwc_ecs_instance.py
+++ b/ansible_collections/community/general/plugins/modules/hwc_ecs_instance.py
@@ -73,8 +73,8 @@ options:
name:
description:
- Specifies the ECS name. Value requirements consists of 1 to 64
- characters, including letters, digits, underscores C(_), hyphens
- (-), periods (.).
+ characters, including letters, digits, underscores (V(_)), hyphens
+ (V(-)), periods (V(.)).
type: str
required: true
nics:
@@ -306,8 +306,8 @@ RETURN = '''
name:
description:
- Specifies the ECS name. Value requirements "Consists of 1 to 64
- characters, including letters, digits, underscores C(_), hyphens
- (-), periods (.)".
+ characters, including letters, digits, underscores (V(_)), hyphens
+ (V(-)), periods (V(.)).".
type: str
returned: success
nics:
diff --git a/ansible_collections/community/general/plugins/modules/hwc_smn_topic.py b/ansible_collections/community/general/plugins/modules/hwc_smn_topic.py
index 88207d3f9..bb983fba7 100644
--- a/ansible_collections/community/general/plugins/modules/hwc_smn_topic.py
+++ b/ansible_collections/community/general/plugins/modules/hwc_smn_topic.py
@@ -45,7 +45,7 @@ options:
description:
- Name of the topic to be created. The topic name is a string of 1
to 256 characters. It must contain upper- or lower-case letters,
- digits, hyphens (-), and underscores C(_), and must start with a
+ digits, hyphens (V(-)), and underscores (V(_)), and must start with a
letter or digit.
type: str
required: true
@@ -85,7 +85,7 @@ name:
description:
- Name of the topic to be created. The topic name is a string of 1
to 256 characters. It must contain upper- or lower-case letters,
- digits, hyphens (-), and underscores C(_), and must start with a
+ digits, hyphens (V(-)), and underscores (V(_)), and must start with a
letter or digit.
returned: success
type: str
diff --git a/ansible_collections/community/general/plugins/modules/hwc_vpc_eip.py b/ansible_collections/community/general/plugins/modules/hwc_vpc_eip.py
index 9fc0361b3..5c4431940 100644
--- a/ansible_collections/community/general/plugins/modules/hwc_vpc_eip.py
+++ b/ansible_collections/community/general/plugins/modules/hwc_vpc_eip.py
@@ -75,7 +75,7 @@ options:
description:
- Specifies the bandwidth name. The value is a string of 1
to 64 characters that can contain letters, digits,
- underscores C(_), hyphens (-), and periods (.).
+ underscores (V(_)), hyphens (V(-)), and periods (V(.)).
type: str
required: true
size:
@@ -187,7 +187,7 @@ RETURN = '''
description:
- Specifies the bandwidth name. The value is a string of 1
to 64 characters that can contain letters, digits,
- underscores C(_), hyphens (-), and periods (.).
+ underscores (V(_)), hyphens (V(-)), and periods (V(.)).
type: str
returned: success
size:
diff --git a/ansible_collections/community/general/plugins/modules/hwc_vpc_private_ip.py b/ansible_collections/community/general/plugins/modules/hwc_vpc_private_ip.py
index c57ddc670..95e759f6f 100644
--- a/ansible_collections/community/general/plugins/modules/hwc_vpc_private_ip.py
+++ b/ansible_collections/community/general/plugins/modules/hwc_vpc_private_ip.py
@@ -19,8 +19,8 @@ description:
- vpc private ip management.
short_description: Creates a resource of Vpc/PrivateIP in Huawei Cloud
notes:
- - If I(id) option is provided, it takes precedence over I(subnet_id), I(ip_address) for private ip selection.
- - I(subnet_id), I(ip_address) are used for private ip selection. If more than one private ip with this options exists, execution is aborted.
+ - If O(id) option is provided, it takes precedence over O(subnet_id), O(ip_address) for private ip selection.
+ - O(subnet_id), O(ip_address) are used for private ip selection. If more than one private ip with this options exists, execution is aborted.
- No parameter support updating. If one of option is changed, the module will create a new resource.
version_added: '0.2.0'
author: Huawei Inc. (@huaweicloud)
diff --git a/ansible_collections/community/general/plugins/modules/hwc_vpc_route.py b/ansible_collections/community/general/plugins/modules/hwc_vpc_route.py
index 1612cac50..091b49b0c 100644
--- a/ansible_collections/community/general/plugins/modules/hwc_vpc_route.py
+++ b/ansible_collections/community/general/plugins/modules/hwc_vpc_route.py
@@ -19,8 +19,8 @@ description:
- vpc route management.
short_description: Creates a resource of Vpc/Route in Huawei Cloud
notes:
- - If I(id) option is provided, it takes precedence over I(destination), I(vpc_id), I(type) and I(next_hop) for route selection.
- - I(destination), I(vpc_id), I(type) and I(next_hop) are used for route selection. If more than one route with this options exists, execution is aborted.
+ - If O(id) option is provided, it takes precedence over O(destination), O(vpc_id), O(type), and O(next_hop) for route selection.
+ - O(destination), O(vpc_id), O(type) and O(next_hop) are used for route selection. If more than one route with this options exists, execution is aborted.
- No parameter support updating. If one of option is changed, the module will create a new resource.
version_added: '0.2.0'
author: Huawei Inc. (@huaweicloud)
diff --git a/ansible_collections/community/general/plugins/modules/hwc_vpc_security_group.py b/ansible_collections/community/general/plugins/modules/hwc_vpc_security_group.py
index c210b912d..aa65e801c 100644
--- a/ansible_collections/community/general/plugins/modules/hwc_vpc_security_group.py
+++ b/ansible_collections/community/general/plugins/modules/hwc_vpc_security_group.py
@@ -19,9 +19,9 @@ description:
- vpc security group management.
short_description: Creates a resource of Vpc/SecurityGroup in Huawei Cloud
notes:
- - If I(id) option is provided, it takes precedence over I(name),
- I(enterprise_project_id) and I(vpc_id) for security group selection.
- - I(name), I(enterprise_project_id) and I(vpc_id) are used for security
+ - If O(id) option is provided, it takes precedence over O(name),
+ O(enterprise_project_id), and O(vpc_id) for security group selection.
+ - O(name), O(enterprise_project_id) and O(vpc_id) are used for security
group selection. If more than one security group with this options exists,
execution is aborted.
- No parameter support updating. If one of option is changed, the module
@@ -45,8 +45,8 @@ options:
name:
description:
- Specifies the security group name. The value is a string of 1 to
- 64 characters that can contain letters, digits, underscores C(_),
- hyphens (-), and periods (.).
+ 64 characters that can contain letters, digits, underscores (V(_)),
+ hyphens (V(-)), and periods (V(.)).
type: str
required: true
enterprise_project_id:
@@ -79,8 +79,8 @@ RETURN = '''
name:
description:
- Specifies the security group name. The value is a string of 1 to
- 64 characters that can contain letters, digits, underscores C(_),
- hyphens (-), and periods (.).
+ 64 characters that can contain letters, digits, underscores (V(_)),
+ hyphens (V(-)), and periods (V(.)).
type: str
returned: success
enterprise_project_id:
diff --git a/ansible_collections/community/general/plugins/modules/hwc_vpc_security_group_rule.py b/ansible_collections/community/general/plugins/modules/hwc_vpc_security_group_rule.py
index bfb5d6a61..899647e8c 100644
--- a/ansible_collections/community/general/plugins/modules/hwc_vpc_security_group_rule.py
+++ b/ansible_collections/community/general/plugins/modules/hwc_vpc_security_group_rule.py
@@ -19,9 +19,9 @@ description:
- vpc security group management.
short_description: Creates a resource of Vpc/SecurityGroupRule in Huawei Cloud
notes:
- - If I(id) option is provided, it takes precedence over
- I(enterprise_project_id) for security group rule selection.
- - I(security_group_id) is used for security group rule selection. If more
+ - If O(id) option is provided, it takes precedence over
+ O(security_group_id) for security group rule selection.
+ - O(security_group_id) is used for security group rule selection. If more
than one security group rule with this options exists, execution is
aborted.
- No parameter support updating. If one of option is changed, the module
diff --git a/ansible_collections/community/general/plugins/modules/hwc_vpc_subnet.py b/ansible_collections/community/general/plugins/modules/hwc_vpc_subnet.py
index 7fb107f53..7ba747330 100644
--- a/ansible_collections/community/general/plugins/modules/hwc_vpc_subnet.py
+++ b/ansible_collections/community/general/plugins/modules/hwc_vpc_subnet.py
@@ -66,8 +66,8 @@ options:
name:
description:
- Specifies the subnet name. The value is a string of 1 to 64
- characters that can contain letters, digits, underscores C(_),
- hyphens (-), and periods (.).
+ characters that can contain letters, digits, underscores (V(_)),
+ hyphens (V(-)), and periods (V(.)).
type: str
required: true
vpc_id:
@@ -137,8 +137,8 @@ RETURN = '''
name:
description:
- Specifies the subnet name. The value is a string of 1 to 64
- characters that can contain letters, digits, underscores C(_),
- hyphens (-), and periods (.).
+ characters that can contain letters, digits, underscores (V(_)),
+ hyphens (V(-)), and periods (V(.)).
type: str
returned: success
vpc_id:
diff --git a/ansible_collections/community/general/plugins/modules/icinga2_feature.py b/ansible_collections/community/general/plugins/modules/icinga2_feature.py
index 6e6bc5416..0c79f6cba 100644
--- a/ansible_collections/community/general/plugins/modules/icinga2_feature.py
+++ b/ansible_collections/community/general/plugins/modules/icinga2_feature.py
@@ -37,10 +37,10 @@ options:
state:
type: str
description:
- - If set to C(present) and feature is disabled, then feature is enabled.
- - If set to C(present) and feature is already enabled, then nothing is changed.
- - If set to C(absent) and feature is enabled, then feature is disabled.
- - If set to C(absent) and feature is already disabled, then nothing is changed.
+ - If set to V(present) and feature is disabled, then feature is enabled.
+ - If set to V(present) and feature is already enabled, then nothing is changed.
+ - If set to V(absent) and feature is enabled, then feature is disabled.
+ - If set to V(absent) and feature is already disabled, then nothing is changed.
choices: [ "present", "absent" ]
default: present
'''
diff --git a/ansible_collections/community/general/plugins/modules/icinga2_host.py b/ansible_collections/community/general/plugins/modules/icinga2_host.py
index 7f25c55d9..ec04d8df7 100644
--- a/ansible_collections/community/general/plugins/modules/icinga2_host.py
+++ b/ansible_collections/community/general/plugins/modules/icinga2_host.py
@@ -31,13 +31,13 @@ options:
- HTTP, HTTPS, or FTP URL in the form (http|https|ftp)://[user[:pass]]@host.domain[:port]/path
use_proxy:
description:
- - If C(false), it will not use a proxy, even if one is defined in
+ - If V(false), it will not use a proxy, even if one is defined in
an environment variable on the target hosts.
type: bool
default: true
validate_certs:
description:
- - If C(false), SSL certificates will not be validated. This should only be used
+ - If V(false), SSL certificates will not be validated. This should only be used
on personally controlled sites using self-signed certificates.
type: bool
default: true
@@ -45,12 +45,12 @@ options:
type: str
description:
- The username for use in HTTP basic authentication.
- - This parameter can be used without C(url_password) for sites that allow empty passwords.
+ - This parameter can be used without O(url_password) for sites that allow empty passwords.
url_password:
type: str
description:
- The password for use in HTTP basic authentication.
- - If the C(url_username) parameter is not specified, the C(url_password) parameter will not be used.
+ - If the O(url_username) parameter is not specified, the O(url_password) parameter will not be used.
force_basic_auth:
description:
- httplib2, the library used by the uri module only sends authentication information when a webservice
@@ -64,12 +64,12 @@ options:
description:
- PEM formatted certificate chain file to be used for SSL client
authentication. This file can also include the key as well, and if
- the key is included, C(client_key) is not required.
+ the key is included, O(client_key) is not required.
client_key:
type: path
description:
- PEM formatted file that contains your private key to be used for SSL
- client authentication. If C(client_cert) contains both the certificate
+ client authentication. If O(client_cert) contains both the certificate
and key, this option is not required.
state:
type: str
@@ -101,12 +101,12 @@ options:
type: str
description:
- The name used to display the host.
- - If not specified, it defaults to the value of the I(name) parameter.
+ - If not specified, it defaults to the value of the O(name) parameter.
ip:
type: str
description:
- The IP address of the host.
- required: true
+ - This is no longer required since community.general 8.0.0.
variables:
type: dict
description:
@@ -243,7 +243,7 @@ def main():
template=dict(default=None),
check_command=dict(default="hostalive"),
display_name=dict(default=None),
- ip=dict(required=True),
+ ip=dict(),
variables=dict(type='dict', default=None),
)
@@ -306,7 +306,7 @@ def main():
module.exit_json(changed=False, name=name, data=data)
# Template attribute is not allowed in modification
- del data['attrs']['templates']
+ del data['templates']
ret = icinga.modify(name, data)
diff --git a/ansible_collections/community/general/plugins/modules/idrac_redfish_config.py b/ansible_collections/community/general/plugins/modules/idrac_redfish_config.py
index cc47e62d2..0388bf00f 100644
--- a/ansible_collections/community/general/plugins/modules/idrac_redfish_config.py
+++ b/ansible_collections/community/general/plugins/modules/idrac_redfish_config.py
@@ -33,9 +33,9 @@ options:
required: true
description:
- List of commands to execute on iDRAC.
- - I(SetManagerAttributes), I(SetLifecycleControllerAttributes) and
- I(SetSystemAttributes) are mutually exclusive commands when C(category)
- is I(Manager).
+ - V(SetManagerAttributes), V(SetLifecycleControllerAttributes) and
+ V(SetSystemAttributes) are mutually exclusive commands when O(category)
+ is V(Manager).
type: list
elements: str
baseuri:
diff --git a/ansible_collections/community/general/plugins/modules/idrac_redfish_info.py b/ansible_collections/community/general/plugins/modules/idrac_redfish_info.py
index aece61664..90b355d13 100644
--- a/ansible_collections/community/general/plugins/modules/idrac_redfish_info.py
+++ b/ansible_collections/community/general/plugins/modules/idrac_redfish_info.py
@@ -16,8 +16,6 @@ description:
- Builds Redfish URIs locally and sends them to remote iDRAC controllers to
get information back.
- For use with Dell EMC iDRAC operations that require Redfish OEM extensions.
- - This module was called C(idrac_redfish_facts) before Ansible 2.9, returning C(ansible_facts).
- Note that the M(community.general.idrac_redfish_info) module no longer returns C(ansible_facts)!
extends_documentation_fragment:
- community.general.attributes
- community.general.attributes.info_module
@@ -35,7 +33,7 @@ options:
required: true
description:
- List of commands to execute on iDRAC.
- - C(GetManagerAttributes) returns the list of dicts containing iDRAC,
+ - V(GetManagerAttributes) returns the list of dicts containing iDRAC,
LifecycleController and System attributes.
type: list
elements: str
diff --git a/ansible_collections/community/general/plugins/modules/ilo_redfish_command.py b/ansible_collections/community/general/plugins/modules/ilo_redfish_command.py
index 0ec385e73..e0e28f855 100644
--- a/ansible_collections/community/general/plugins/modules/ilo_redfish_command.py
+++ b/ansible_collections/community/general/plugins/modules/ilo_redfish_command.py
@@ -84,7 +84,7 @@ ilo_redfish_command:
type: dict
contains:
ret:
- description: Return True/False based on whether the operation was performed succesfully.
+ description: Return True/False based on whether the operation was performed successfully.
type: bool
msg:
description: Status of the operation performed on the iLO.
diff --git a/ansible_collections/community/general/plugins/modules/imc_rest.py b/ansible_collections/community/general/plugins/modules/imc_rest.py
index 4bbaad23a..113d341e8 100644
--- a/ansible_collections/community/general/plugins/modules/imc_rest.py
+++ b/ansible_collections/community/general/plugins/modules/imc_rest.py
@@ -51,16 +51,16 @@ options:
description:
- Name of the absolute path of the filename that includes the body
of the http request being sent to the Cisco IMC REST API.
- - Parameter C(path) is mutual exclusive with parameter C(content).
+ - Parameter O(path) is mutual exclusive with parameter O(content).
aliases: [ 'src', 'config_file' ]
type: path
content:
description:
- - When used instead of C(path), sets the content of the API requests directly.
+ - When used instead of O(path), sets the content of the API requests directly.
- This may be convenient to template simple requests, for anything complex use the M(ansible.builtin.template) module.
- You can collate multiple IMC XML fragments and they will be processed sequentially in a single stream,
the Cisco IMC output is subsequently merged.
- - Parameter C(content) is mutual exclusive with parameter C(path).
+ - Parameter O(content) is mutual exclusive with parameter O(path).
type: str
protocol:
description:
@@ -72,14 +72,14 @@ options:
description:
- The socket level timeout in seconds.
- This is the time that every single connection (every fragment) can spend.
- If this C(timeout) is reached, the module will fail with a
+ If this O(timeout) is reached, the module will fail with a
C(Connection failure) indicating that C(The read operation timed out).
default: 60
type: int
validate_certs:
description:
- - If C(false), SSL certificates will not be validated.
- - This should only set to C(false) used on personally controlled sites using self-signed certificates.
+ - If V(false), SSL certificates will not be validated.
+ - This should only set to V(false) used on personally controlled sites using self-signed certificates.
type: bool
default: true
notes:
@@ -88,7 +88,7 @@ notes:
- Any configConfMo change requested has a return status of 'modified', even if there was no actual change
from the previous configuration. As a result, this module will always report a change on subsequent runs.
In case this behaviour is fixed in a future update to Cisco IMC, this module will automatically adapt.
-- If you get a C(Connection failure) related to C(The read operation timed out) increase the C(timeout)
+- If you get a C(Connection failure) related to C(The read operation timed out) increase the O(timeout)
parameter. Some XML fragments can take longer than the default timeout.
- More information about the IMC REST API is available from
U(http://www.cisco.com/c/en/us/td/docs/unified_computing/ucs/c/sw/api/3_0/b_Cisco_IMC_api_301.html)
@@ -100,7 +100,7 @@ EXAMPLES = r'''
hostname: '{{ imc_hostname }}'
username: '{{ imc_username }}'
password: '{{ imc_password }}'
- validate_certs: false
+ validate_certs: false # only do this when you trust the network!
content: |
<configConfMo><inConfig>
<computeRackUnit dn="sys/rack-unit-1" adminPower="down"/>
@@ -112,7 +112,7 @@ EXAMPLES = r'''
hostname: '{{ imc_hostname }}'
username: '{{ imc_username }}'
password: '{{ imc_password }}'
- validate_certs: false
+ validate_certs: false # only do this when you trust the network!
timeout: 120
content: |
<!-- Configure Serial-on-LAN -->
@@ -137,7 +137,7 @@ EXAMPLES = r'''
hostname: '{{ imc_hostname }}'
username: '{{ imc_username }}'
password: '{{ imc_password }}'
- validate_certs: false
+ validate_certs: false # only do this when you trust the network!
content: |
<!-- Configure PXE boot -->
<configConfMo><inConfig>
@@ -155,7 +155,7 @@ EXAMPLES = r'''
hostname: '{{ imc_host }}'
username: '{{ imc_username }}'
password: '{{ imc_password }}'
- validate_certs: false
+ validate_certs: false # only do this when you trust the network!
content: |
<configConfMo><inConfig>
<lsbootStorage dn="sys/rack-unit-1/boot-policy/storage-read-write" access="read-write" order="1" type="storage"/>
@@ -167,7 +167,7 @@ EXAMPLES = r'''
hostname: '{{ imc_host }}'
username: '{{ imc_username }}'
password: '{{ imc_password }}'
- validate_certs: false
+ validate_certs: false # only do this when you trust the network!
content: |
<configConfMo><inConfig>
<computeRackUnit dn="sys/rack-unit-1" usrLbl="Customer Lab - POD{{ pod_id }} - {{ inventory_hostname_short }}"/>
@@ -179,7 +179,7 @@ EXAMPLES = r'''
hostname: '{{ imc_host }}'
username: '{{ imc_username }}'
password: '{{ imc_password }}'
- validate_certs: false
+ validate_certs: false # only do this when you trust the network!
timeout: 120
content: |
<configConfMo><inConfig>
diff --git a/ansible_collections/community/general/plugins/modules/imgadm.py b/ansible_collections/community/general/plugins/modules/imgadm.py
index 6e4b81098..a247547fc 100644
--- a/ansible_collections/community/general/plugins/modules/imgadm.py
+++ b/ansible_collections/community/general/plugins/modules/imgadm.py
@@ -44,9 +44,9 @@ options:
required: true
choices: [ present, absent, deleted, imported, updated, vacuumed ]
description:
- - State the object operated on should be in. C(imported) is an alias for
- for C(present) and C(deleted) for C(absent). When set to C(vacuumed)
- and C(uuid) to C(*), it will remove all unused images.
+ - State the object operated on should be in. V(imported) is an alias for
+ for V(present) and V(deleted) for V(absent). When set to V(vacuumed)
+ and O(uuid=*), it will remove all unused images.
type: str
type:
@@ -60,11 +60,8 @@ options:
uuid:
required: false
description:
- - Image UUID. Can either be a full UUID or C(*) for all images.
+ - Image UUID. Can either be a full UUID or V(*) for all images.
type: str
-
-requirements:
- - python >= 2.6
'''
EXAMPLES = '''
@@ -142,7 +139,7 @@ class Imgadm(object):
self.uuid = module.params['uuid']
# Since there are a number of (natural) aliases, prevent having to look
- # them up everytime we operate on `state`.
+ # them up every time we operate on `state`.
if self.params['state'] in ['present', 'imported', 'updated']:
self.present = True
else:
@@ -174,7 +171,7 @@ class Imgadm(object):
# There is no feedback from imgadm(1M) to determine if anything
# was actually changed. So treat this as an 'always-changes' operation.
- # Note that 'imgadm -v' produces unparseable JSON...
+ # Note that 'imgadm -v' produces unparsable JSON...
self.changed = True
def manage_sources(self):
diff --git a/ansible_collections/community/general/plugins/modules/influxdb_database.py b/ansible_collections/community/general/plugins/modules/influxdb_database.py
index 046b16e18..a12326da5 100644
--- a/ansible_collections/community/general/plugins/modules/influxdb_database.py
+++ b/ansible_collections/community/general/plugins/modules/influxdb_database.py
@@ -17,7 +17,6 @@ description:
- Manage InfluxDB databases.
author: "Kamil Szczygiel (@kamsz)"
requirements:
- - "python >= 2.6"
- "influxdb >= 0.9"
- requests
attributes:
diff --git a/ansible_collections/community/general/plugins/modules/influxdb_query.py b/ansible_collections/community/general/plugins/modules/influxdb_query.py
index c2e3d8acc..fda98d184 100644
--- a/ansible_collections/community/general/plugins/modules/influxdb_query.py
+++ b/ansible_collections/community/general/plugins/modules/influxdb_query.py
@@ -16,7 +16,6 @@ description:
- Query data points from InfluxDB.
author: "René Moser (@resmo)"
requirements:
- - "python >= 2.6"
- "influxdb >= 0.9"
attributes:
check_mode:
diff --git a/ansible_collections/community/general/plugins/modules/influxdb_retention_policy.py b/ansible_collections/community/general/plugins/modules/influxdb_retention_policy.py
index 28d5450ff..f1c13a811 100644
--- a/ansible_collections/community/general/plugins/modules/influxdb_retention_policy.py
+++ b/ansible_collections/community/general/plugins/modules/influxdb_retention_policy.py
@@ -17,7 +17,6 @@ description:
- Manage InfluxDB retention policies.
author: "Kamil Szczygiel (@kamsz)"
requirements:
- - "python >= 2.6"
- "influxdb >= 0.9"
- requests
attributes:
@@ -46,14 +45,14 @@ options:
duration:
description:
- Determines how long InfluxDB should keep the data. If specified, it
- should be C(INF) or at least one hour. If not specified, C(INF) is
+ should be V(INF) or at least one hour. If not specified, V(INF) is
assumed. Supports complex duration expressions with multiple units.
- - Required only if I(state) is set to C(present).
+ - Required only if O(state) is set to V(present).
type: str
replication:
description:
- Determines how many independent copies of each point are stored in the cluster.
- - Required only if I(state) is set to C(present).
+ - Required only if O(state) is set to V(present).
type: int
default:
description:
@@ -115,7 +114,6 @@ EXAMPLES = r'''
duration: INF
replication: 1
ssl: false
- validate_certs: false
shard_group_duration: 1w
state: present
@@ -127,7 +125,6 @@ EXAMPLES = r'''
duration: 5d1h30m
replication: 1
ssl: false
- validate_certs: false
shard_group_duration: 1d10h30m
state: present
diff --git a/ansible_collections/community/general/plugins/modules/influxdb_user.py b/ansible_collections/community/general/plugins/modules/influxdb_user.py
index bbd0f8f5a..ca4201db1 100644
--- a/ansible_collections/community/general/plugins/modules/influxdb_user.py
+++ b/ansible_collections/community/general/plugins/modules/influxdb_user.py
@@ -18,7 +18,6 @@ description:
- Manage InfluxDB users.
author: "Vitaliy Zhhuta (@zhhuta)"
requirements:
- - "python >= 2.6"
- "influxdb >= 0.9"
attributes:
check_mode:
diff --git a/ansible_collections/community/general/plugins/modules/influxdb_write.py b/ansible_collections/community/general/plugins/modules/influxdb_write.py
index f95b6dae8..76e6449bb 100644
--- a/ansible_collections/community/general/plugins/modules/influxdb_write.py
+++ b/ansible_collections/community/general/plugins/modules/influxdb_write.py
@@ -16,7 +16,6 @@ description:
- Write data points into InfluxDB.
author: "René Moser (@resmo)"
requirements:
- - "python >= 2.6"
- "influxdb >= 0.9"
attributes:
check_mode:
diff --git a/ansible_collections/community/general/plugins/modules/ini_file.py b/ansible_collections/community/general/plugins/modules/ini_file.py
index 874f10ae0..ec71a9473 100644
--- a/ansible_collections/community/general/plugins/modules/ini_file.py
+++ b/ansible_collections/community/general/plugins/modules/ini_file.py
@@ -4,6 +4,7 @@
# Copyright (c) 2012, Jan-Piet Mens <jpmens () gmail.com>
# Copyright (c) 2015, Ales Nosek <anosek.nosek () gmail.com>
# Copyright (c) 2017, Ansible Project
+# Copyright (c) 2023, Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
@@ -22,8 +23,7 @@ description:
- Manage (add, remove, change) individual settings in an INI-style file without having
to manage the file as a whole with, say, M(ansible.builtin.template) or M(ansible.builtin.assemble).
- Adds missing sections if they don't exist.
- - Before Ansible 2.0, comments are discarded when the source file is read, and therefore will not show up in the destination file.
- - Since Ansible 2.3, this module adds missing ending newlines to files to keep in line with the POSIX standard, even when
+ - This module adds missing ending newlines to files to keep in line with the POSIX standard, even when
no other modifications need to be applied.
attributes:
check_mode:
@@ -34,35 +34,34 @@ options:
path:
description:
- Path to the INI-style file; this file is created if required.
- - Before Ansible 2.3 this option was only usable as I(dest).
type: path
required: true
aliases: [ dest ]
section:
description:
- - Section name in INI file. This is added if I(state=present) automatically when
+ - Section name in INI file. This is added if O(state=present) automatically when
a single value is being set.
- - If left empty, being omitted, or being set to C(null), the I(option) will be placed before the first I(section).
- - Using C(null) is also required if the config format does not support sections.
+ - If being omitted, the O(option) will be placed before the first O(section).
+ - Omitting O(section) is also required if the config format does not support sections.
type: str
option:
description:
- - If set (required for changing a I(value)), this is the name of the option.
- - May be omitted if adding/removing a whole I(section).
+ - If set (required for changing a O(value)), this is the name of the option.
+ - May be omitted if adding/removing a whole O(section).
type: str
value:
description:
- - The string value to be associated with an I(option).
- - May be omitted when removing an I(option).
- - Mutually exclusive with I(values).
- - I(value=v) is equivalent to I(values=[v]).
+ - The string value to be associated with an O(option).
+ - May be omitted when removing an O(option).
+ - Mutually exclusive with O(values).
+ - O(value=v) is equivalent to O(values=[v]).
type: str
values:
description:
- - The string value to be associated with an I(option).
- - May be omitted when removing an I(option).
- - Mutually exclusive with I(value).
- - I(value=v) is equivalent to I(values=[v]).
+ - The string value to be associated with an O(option).
+ - May be omitted when removing an O(option).
+ - Mutually exclusive with O(value).
+ - O(value=v) is equivalent to O(values=[v]).
type: list
elements: str
version_added: 3.6.0
@@ -74,22 +73,22 @@ options:
default: false
state:
description:
- - If set to C(absent) and I(exclusive) set to C(true) all matching I(option) lines are removed.
- - If set to C(absent) and I(exclusive) set to C(false) the specified I(option=value) lines are removed,
- but the other I(option)s with the same name are not touched.
- - If set to C(present) and I(exclusive) set to C(false) the specified I(option=values) lines are added,
- but the other I(option)s with the same name are not touched.
- - If set to C(present) and I(exclusive) set to C(true) all given I(option=values) lines will be
- added and the other I(option)s with the same name are removed.
+ - If set to V(absent) and O(exclusive) set to V(true) all matching O(option) lines are removed.
+ - If set to V(absent) and O(exclusive) set to V(false) the specified O(option=value) lines are removed,
+ but the other O(option)s with the same name are not touched.
+ - If set to V(present) and O(exclusive) set to V(false) the specified O(option=values) lines are added,
+ but the other O(option)s with the same name are not touched.
+ - If set to V(present) and O(exclusive) set to V(true) all given O(option=values) lines will be
+ added and the other O(option)s with the same name are removed.
type: str
choices: [ absent, present ]
default: present
exclusive:
description:
- - If set to C(true) (default), all matching I(option) lines are removed when I(state=absent),
- or replaced when I(state=present).
- - If set to C(false), only the specified I(value(s)) are added when I(state=present),
- or removed when I(state=absent), and existing ones are not modified.
+ - If set to V(true) (default), all matching O(option) lines are removed when O(state=absent),
+ or replaced when O(state=present).
+ - If set to V(false), only the specified O(value)/O(values) are added when O(state=present),
+ or removed when O(state=absent), and existing ones are not modified.
type: bool
default: true
version_added: 3.6.0
@@ -98,9 +97,15 @@ options:
- Do not insert spaces before and after '=' symbol.
type: bool
default: false
+ ignore_spaces:
+ description:
+ - Do not change a line if doing so would only add or remove spaces before or after the V(=) symbol.
+ type: bool
+ default: false
+ version_added: 7.5.0
create:
description:
- - If set to C(false), the module will fail if the file does not already exist.
+ - If set to V(false), the module will fail if the file does not already exist.
- By default it will create the file if it is missing.
type: bool
default: true
@@ -109,9 +114,23 @@ options:
- Allow option without value and without '=' symbol.
type: bool
default: false
+ modify_inactive_option:
+ description:
+ - By default the module replaces a commented line that matches the given option.
+ - Set this option to V(false) to avoid this. This is useful when you want to keep commented example
+ C(key=value) pairs for documentation purposes.
+ type: bool
+ default: true
+ version_added: 8.0.0
+ follow:
+ description:
+ - This flag indicates that filesystem links, if they exist, should be followed.
+ - O(follow=true) can modify O(path) when combined with parameters such as O(mode).
+ type: bool
+ default: false
+ version_added: 7.1.0
notes:
- - While it is possible to add an I(option) without specifying a I(value), this makes no sense.
- - As of Ansible 2.3, the I(dest) option has been changed to I(path) as default, but I(dest) still works as well.
+ - While it is possible to add an O(option) without specifying a O(value), this makes no sense.
- As of community.general 3.2.0, UTF-8 BOM markers are discarded when reading files.
author:
- Jan-Piet Mens (@jpmens)
@@ -119,7 +138,6 @@ author:
'''
EXAMPLES = r'''
-# Before Ansible 2.3, option 'dest' was used instead of 'path'
- name: Ensure "fav=lemonade is in section "[drinks]" in specified file
community.general.ini_file:
path: /etc/conf
@@ -157,6 +175,13 @@ EXAMPLES = r'''
- pepsi
mode: '0600'
state: present
+
+- name: Add "beverage=lemon juice" outside a section in specified file
+ community.general.ini_file:
+ path: /etc/conf
+ option: beverage
+ value: lemon juice
+ state: present
'''
import io
@@ -171,27 +196,35 @@ from ansible.module_utils.common.text.converters import to_bytes, to_text
def match_opt(option, line):
option = re.escape(option)
- return re.match('[#;]?( |\t)*(%s)( |\t)*(=|$)( |\t)*(.*)' % option, line)
+ return re.match('([#;]?)( |\t)*(%s)( |\t)*(=|$)( |\t)*(.*)' % option, line)
def match_active_opt(option, line):
option = re.escape(option)
- return re.match('( |\t)*(%s)( |\t)*(=|$)( |\t)*(.*)' % option, line)
-
-
-def update_section_line(changed, section_lines, index, changed_lines, newline, msg):
- option_changed = section_lines[index] != newline
+ return re.match('()( |\t)*(%s)( |\t)*(=|$)( |\t)*(.*)' % option, line)
+
+
+def update_section_line(option, changed, section_lines, index, changed_lines, ignore_spaces, newline, msg):
+ option_changed = None
+ if ignore_spaces:
+ old_match = match_opt(option, section_lines[index])
+ if not old_match.group(1):
+ new_match = match_opt(option, newline)
+ option_changed = old_match.group(7) != new_match.group(7)
+ if option_changed is None:
+ option_changed = section_lines[index] != newline
+ if option_changed:
+ section_lines[index] = newline
changed = changed or option_changed
if option_changed:
msg = 'option changed'
- section_lines[index] = newline
changed_lines[index] = 1
return (changed, msg)
def do_ini(module, filename, section=None, option=None, values=None,
state='present', exclusive=True, backup=False, no_extra_spaces=False,
- create=True, allow_no_value=False):
+ ignore_spaces=False, create=True, allow_no_value=False, modify_inactive_option=True, follow=False):
if section is not None:
section = to_text(section)
@@ -210,15 +243,20 @@ def do_ini(module, filename, section=None, option=None, values=None,
after_header='%s (content)' % filename,
)
- if not os.path.exists(filename):
+ if follow and os.path.islink(filename):
+ target_filename = os.path.realpath(filename)
+ else:
+ target_filename = filename
+
+ if not os.path.exists(target_filename):
if not create:
- module.fail_json(rc=257, msg='Destination %s does not exist!' % filename)
- destpath = os.path.dirname(filename)
+ module.fail_json(rc=257, msg='Destination %s does not exist!' % target_filename)
+ destpath = os.path.dirname(target_filename)
if not os.path.exists(destpath) and not module.check_mode:
os.makedirs(destpath)
ini_lines = []
else:
- with io.open(filename, 'r', encoding="utf-8-sig") as ini_file:
+ with io.open(target_filename, 'r', encoding="utf-8-sig") as ini_file:
ini_lines = [to_text(line) for line in ini_file.readlines()]
if module._diff:
@@ -266,9 +304,11 @@ def do_ini(module, filename, section=None, option=None, values=None,
before = after = []
section_lines = []
+ section_pattern = re.compile(to_text(r'^\[\s*%s\s*]' % re.escape(section.strip())))
+
for index, line in enumerate(ini_lines):
# find start and end of section
- if line.startswith(u'[%s]' % section):
+ if section_pattern.match(line):
within_section = True
section_start = index
elif line.startswith(u'['):
@@ -283,6 +323,12 @@ def do_ini(module, filename, section=None, option=None, values=None,
# Keep track of changed section_lines
changed_lines = [0] * len(section_lines)
+ # Determine whether to consider using commented out/inactive options or only active ones
+ if modify_inactive_option:
+ match_function = match_opt
+ else:
+ match_function = match_active_opt
+
# handling multiple instances of option=value when state is 'present' with/without exclusive is a bit complex
#
# 1. edit all lines where we have a option=value pair with a matching value in values[]
@@ -292,10 +338,10 @@ def do_ini(module, filename, section=None, option=None, values=None,
if state == 'present' and option:
for index, line in enumerate(section_lines):
- if match_opt(option, line):
- match = match_opt(option, line)
- if values and match.group(6) in values:
- matched_value = match.group(6)
+ if match_function(option, line):
+ match = match_function(option, line)
+ if values and match.group(7) in values:
+ matched_value = match.group(7)
if not matched_value and allow_no_value:
# replace existing option with no value line(s)
newline = u'%s\n' % option
@@ -303,12 +349,12 @@ def do_ini(module, filename, section=None, option=None, values=None,
else:
# replace existing option=value line(s)
newline = assignment_format % (option, matched_value)
- (changed, msg) = update_section_line(changed, section_lines, index, changed_lines, newline, msg)
+ (changed, msg) = update_section_line(option, changed, section_lines, index, changed_lines, ignore_spaces, newline, msg)
values.remove(matched_value)
elif not values and allow_no_value:
# replace existing option with no value line(s)
newline = u'%s\n' % option
- (changed, msg) = update_section_line(changed, section_lines, index, changed_lines, newline, msg)
+ (changed, msg) = update_section_line(option, changed, section_lines, index, changed_lines, ignore_spaces, newline, msg)
option_no_value_present = True
break
@@ -316,14 +362,14 @@ def do_ini(module, filename, section=None, option=None, values=None,
# override option with no value to option with value if not allow_no_value
if len(values) > 0:
for index, line in enumerate(section_lines):
- if not changed_lines[index] and match_opt(option, line):
+ if not changed_lines[index] and match_function(option, line):
newline = assignment_format % (option, values.pop(0))
- (changed, msg) = update_section_line(changed, section_lines, index, changed_lines, newline, msg)
+ (changed, msg) = update_section_line(option, changed, section_lines, index, changed_lines, ignore_spaces, newline, msg)
if len(values) == 0:
break
# remove all remaining option occurrences from the rest of the section
for index in range(len(section_lines) - 1, 0, -1):
- if not changed_lines[index] and match_opt(option, section_lines[index]):
+ if not changed_lines[index] and match_function(option, section_lines[index]):
del section_lines[index]
del changed_lines[index]
changed = True
@@ -367,7 +413,7 @@ def do_ini(module, filename, section=None, option=None, values=None,
section_lines = new_section_lines
elif not exclusive and len(values) > 0:
# delete specified option=value line(s)
- new_section_lines = [i for i in section_lines if not (match_active_opt(option, i) and match_active_opt(option, i).group(6) in values)]
+ new_section_lines = [i for i in section_lines if not (match_active_opt(option, i) and match_active_opt(option, i).group(7) in values)]
if section_lines != new_section_lines:
changed = True
msg = 'option changed'
@@ -404,7 +450,7 @@ def do_ini(module, filename, section=None, option=None, values=None,
backup_file = None
if changed and not module.check_mode:
if backup:
- backup_file = module.backup_local(filename)
+ backup_file = module.backup_local(target_filename)
encoded_ini_lines = [to_bytes(line) for line in ini_lines]
try:
@@ -416,10 +462,10 @@ def do_ini(module, filename, section=None, option=None, values=None,
module.fail_json(msg="Unable to create temporary file %s", traceback=traceback.format_exc())
try:
- module.atomic_move(tmpfile, filename)
+ module.atomic_move(tmpfile, target_filename)
except IOError:
module.ansible.fail_json(msg='Unable to move temporary \
- file %s to %s, IOError' % (tmpfile, filename), traceback=traceback.format_exc())
+ file %s to %s, IOError' % (tmpfile, target_filename), traceback=traceback.format_exc())
return (changed, backup_file, diff, msg)
@@ -437,8 +483,11 @@ def main():
state=dict(type='str', default='present', choices=['absent', 'present']),
exclusive=dict(type='bool', default=True),
no_extra_spaces=dict(type='bool', default=False),
+ ignore_spaces=dict(type='bool', default=False),
allow_no_value=dict(type='bool', default=False),
- create=dict(type='bool', default=True)
+ modify_inactive_option=dict(type='bool', default=True),
+ create=dict(type='bool', default=True),
+ follow=dict(type='bool', default=False)
),
mutually_exclusive=[
['value', 'values']
@@ -456,8 +505,11 @@ def main():
exclusive = module.params['exclusive']
backup = module.params['backup']
no_extra_spaces = module.params['no_extra_spaces']
+ ignore_spaces = module.params['ignore_spaces']
allow_no_value = module.params['allow_no_value']
+ modify_inactive_option = module.params['modify_inactive_option']
create = module.params['create']
+ follow = module.params['follow']
if state == 'present' and not allow_no_value and value is None and not values:
module.fail_json(msg="Parameter 'value(s)' must be defined if state=present and allow_no_value=False.")
@@ -467,7 +519,9 @@ def main():
elif values is None:
values = []
- (changed, backup_file, diff, msg) = do_ini(module, path, section, option, values, state, exclusive, backup, no_extra_spaces, create, allow_no_value)
+ (changed, backup_file, diff, msg) = do_ini(
+ module, path, section, option, values, state, exclusive, backup,
+ no_extra_spaces, ignore_spaces, create, allow_no_value, modify_inactive_option, follow)
if not module.check_mode and os.path.exists(path):
file_args = module.load_file_common_arguments(module.params)
diff --git a/ansible_collections/community/general/plugins/modules/installp.py b/ansible_collections/community/general/plugins/modules/installp.py
index 41064363d..4b5a6949c 100644
--- a/ansible_collections/community/general/plugins/modules/installp.py
+++ b/ansible_collections/community/general/plugins/modules/installp.py
@@ -32,7 +32,7 @@ options:
name:
description:
- One or more packages to install or remove.
- - Use C(all) to install all packages available on informed C(repository_path).
+ - Use V(all) to install all packages available on informed O(repository_path).
type: list
elements: str
required: true
@@ -133,7 +133,7 @@ def _check_new_pkg(module, package, repository_path):
def _check_installed_pkg(module, package, repository_path):
"""
Check the package on AIX.
- It verifies if the package is installed and informations
+ It verifies if the package is installed and information
:param module: Ansible module parameters spec.
:param package: Package/fileset name.
diff --git a/ansible_collections/community/general/plugins/modules/interfaces_file.py b/ansible_collections/community/general/plugins/modules/interfaces_file.py
index f19c019f4..98103082e 100644
--- a/ansible_collections/community/general/plugins/modules/interfaces_file.py
+++ b/ansible_collections/community/general/plugins/modules/interfaces_file.py
@@ -12,14 +12,14 @@ __metaclass__ = type
DOCUMENTATION = '''
---
module: interfaces_file
-short_description: Tweak settings in /etc/network/interfaces files
+short_description: Tweak settings in C(/etc/network/interfaces) files
extends_documentation_fragment:
- ansible.builtin.files
- community.general.attributes
description:
- Manage (add, remove, change) individual interface options in an interfaces-style file without having
to manage the file as a whole with, say, M(ansible.builtin.template) or M(ansible.builtin.assemble). Interface has to be presented in a file.
- - Read information about interfaces from interfaces-styled files
+ - Read information about interfaces from interfaces-styled files.
attributes:
check_mode:
support: full
@@ -29,27 +29,27 @@ options:
dest:
type: path
description:
- - Path to the interfaces file
+ - Path to the interfaces file.
default: /etc/network/interfaces
iface:
type: str
description:
- - Name of the interface, required for value changes or option remove
+ - Name of the interface, required for value changes or option remove.
address_family:
type: str
description:
- - Address family of the interface, useful if same interface name is used for both inet and inet6
+ - Address family of the interface, useful if same interface name is used for both V(inet) and V(inet6).
option:
type: str
description:
- - Name of the option, required for value changes or option remove
+ - Name of the option, required for value changes or option remove.
value:
type: str
description:
- - If I(option) is not presented for the I(interface) and I(state) is C(present) option will be added.
- If I(option) already exists and is not C(pre-up), C(up), C(post-up) or C(down), it's value will be updated.
- C(pre-up), C(up), C(post-up) and C(down) options can't be updated, only adding new options, removing existing
- ones or cleaning the whole option set are supported
+ - If O(option) is not presented for the O(iface) and O(state) is V(present) option will be added.
+ If O(option) already exists and is not V(pre-up), V(up), V(post-up) or V(down), it's value will be updated.
+ V(pre-up), V(up), V(post-up) and V(down) options cannot be updated, only adding new options, removing existing
+ ones or cleaning the whole option set are supported.
backup:
description:
- Create a backup file including the timestamp information so you can get
@@ -59,77 +59,81 @@ options:
state:
type: str
description:
- - If set to C(absent) the option or section will be removed if present instead of created.
+ - If set to V(absent) the option or section will be removed if present instead of created.
default: "present"
choices: [ "present", "absent" ]
notes:
- - If option is defined multiple times last one will be updated but all will be deleted in case of an absent state
+ - If option is defined multiple times last one will be updated but all will be deleted in case of an absent state.
requirements: []
author: "Roman Belyakovsky (@hryamzik)"
'''
RETURN = '''
dest:
- description: destination file/path
+ description: Destination file/path.
returned: success
type: str
sample: "/etc/network/interfaces"
ifaces:
- description: interfaces dictionary
+ description: Interfaces dictionary.
returned: success
- type: complex
+ type: dict
contains:
ifaces:
- description: interface dictionary
+ description: Interface dictionary.
returned: success
type: dict
contains:
eth0:
- description: Name of the interface
+ description: Name of the interface.
returned: success
type: dict
contains:
address_family:
- description: interface address family
+ description: Interface address family.
returned: success
type: str
sample: "inet"
method:
- description: interface method
+ description: Interface method.
returned: success
type: str
sample: "manual"
mtu:
- description: other options, all values returned as strings
+ description: Other options, all values returned as strings.
returned: success
type: str
sample: "1500"
pre-up:
- description: list of C(pre-up) scripts
+ description: List of C(pre-up) scripts.
returned: success
type: list
+ elements: str
sample:
- "route add -net 10.10.10.0/24 gw 10.10.10.1 dev eth1"
- "route add -net 10.10.11.0/24 gw 10.10.11.1 dev eth2"
up:
- description: list of C(up) scripts
+ description: List of C(up) scripts.
returned: success
type: list
+ elements: str
sample:
- "route add -net 10.10.10.0/24 gw 10.10.10.1 dev eth1"
- "route add -net 10.10.11.0/24 gw 10.10.11.1 dev eth2"
post-up:
- description: list of C(post-up) scripts
+ description: List of C(post-up) scripts.
returned: success
type: list
+ elements: str
sample:
- "route add -net 10.10.10.0/24 gw 10.10.10.1 dev eth1"
- "route add -net 10.10.11.0/24 gw 10.10.11.1 dev eth2"
down:
- description: list of C(down) scripts
+ description: List of C(down) scripts.
returned: success
type: list
+ elements: str
sample:
- "route del -net 10.10.10.0/24 gw 10.10.10.1 dev eth1"
- "route del -net 10.10.11.0/24 gw 10.10.11.1 dev eth2"
@@ -336,6 +340,8 @@ def addOptionAfterLine(option, value, iface, lines, last_line_dict, iface_option
changed = False
for ln in lines:
if ln.get('line_type', '') == 'iface' and ln.get('iface', '') == iface and value != ln.get('params', {}).get('method', ''):
+ if address_family is not None and ln.get('address_family') != address_family:
+ continue
changed = True
ln['line'] = re.sub(ln.get('params', {}).get('method', '') + '$', value, ln.get('line'))
ln['params']['method'] = value
diff --git a/ansible_collections/community/general/plugins/modules/ipa_config.py b/ansible_collections/community/general/plugins/modules/ipa_config.py
index ec94b58d4..871643fd7 100644
--- a/ansible_collections/community/general/plugins/modules/ipa_config.py
+++ b/ansible_collections/community/general/plugins/modules/ipa_config.py
@@ -40,6 +40,12 @@ options:
aliases: ["primarygroup"]
type: str
version_added: '2.5.0'
+ ipagroupobjectclasses:
+ description: A list of group objectclasses.
+ aliases: ["groupobjectclasses"]
+ type: list
+ elements: str
+ version_added: '7.3.0'
ipagroupsearchfields:
description: A list of fields to search in when searching for groups.
aliases: ["groupsearchfields"]
@@ -85,12 +91,21 @@ options:
elements: str
version_added: '3.7.0'
ipauserauthtype:
- description: The authentication type to use by default.
+ description:
+ - The authentication type to use by default.
+ - The choice V(idp) has been added in community.general 7.3.0.
+ - The choice V(passkey) has been added in community.general 8.1.0.
aliases: ["userauthtype"]
- choices: ["password", "radius", "otp", "pkinit", "hardened", "disabled"]
+ choices: ["password", "radius", "otp", "pkinit", "hardened", "idp", "passkey", "disabled"]
type: list
elements: str
version_added: '2.5.0'
+ ipauserobjectclasses:
+ description: A list of user objectclasses.
+ aliases: ["userobjectclasses"]
+ type: list
+ elements: str
+ version_added: '7.3.0'
ipausersearchfields:
description: A list of fields to search in when searching for users.
aliases: ["usersearchfields"]
@@ -235,11 +250,12 @@ class ConfigIPAClient(IPAClient):
def get_config_dict(ipaconfigstring=None, ipadefaultloginshell=None,
ipadefaultemaildomain=None, ipadefaultprimarygroup=None,
- ipagroupsearchfields=None, ipahomesrootdir=None,
- ipakrbauthzdata=None, ipamaxusernamelength=None,
- ipapwdexpadvnotify=None, ipasearchrecordslimit=None,
- ipasearchtimelimit=None, ipaselinuxusermaporder=None,
- ipauserauthtype=None, ipausersearchfields=None):
+ ipagroupsearchfields=None, ipagroupobjectclasses=None,
+ ipahomesrootdir=None, ipakrbauthzdata=None,
+ ipamaxusernamelength=None, ipapwdexpadvnotify=None,
+ ipasearchrecordslimit=None, ipasearchtimelimit=None,
+ ipaselinuxusermaporder=None, ipauserauthtype=None,
+ ipausersearchfields=None, ipauserobjectclasses=None):
config = {}
if ipaconfigstring is not None:
config['ipaconfigstring'] = ipaconfigstring
@@ -249,6 +265,8 @@ def get_config_dict(ipaconfigstring=None, ipadefaultloginshell=None,
config['ipadefaultemaildomain'] = ipadefaultemaildomain
if ipadefaultprimarygroup is not None:
config['ipadefaultprimarygroup'] = ipadefaultprimarygroup
+ if ipagroupobjectclasses is not None:
+ config['ipagroupobjectclasses'] = ipagroupobjectclasses
if ipagroupsearchfields is not None:
config['ipagroupsearchfields'] = ','.join(ipagroupsearchfields)
if ipahomesrootdir is not None:
@@ -267,6 +285,8 @@ def get_config_dict(ipaconfigstring=None, ipadefaultloginshell=None,
config['ipaselinuxusermaporder'] = '$'.join(ipaselinuxusermaporder)
if ipauserauthtype is not None:
config['ipauserauthtype'] = ipauserauthtype
+ if ipauserobjectclasses is not None:
+ config['ipauserobjectclasses'] = ipauserobjectclasses
if ipausersearchfields is not None:
config['ipausersearchfields'] = ','.join(ipausersearchfields)
@@ -283,6 +303,7 @@ def ensure(module, client):
ipadefaultloginshell=module.params.get('ipadefaultloginshell'),
ipadefaultemaildomain=module.params.get('ipadefaultemaildomain'),
ipadefaultprimarygroup=module.params.get('ipadefaultprimarygroup'),
+ ipagroupobjectclasses=module.params.get('ipagroupobjectclasses'),
ipagroupsearchfields=module.params.get('ipagroupsearchfields'),
ipahomesrootdir=module.params.get('ipahomesrootdir'),
ipakrbauthzdata=module.params.get('ipakrbauthzdata'),
@@ -293,6 +314,7 @@ def ensure(module, client):
ipaselinuxusermaporder=module.params.get('ipaselinuxusermaporder'),
ipauserauthtype=module.params.get('ipauserauthtype'),
ipausersearchfields=module.params.get('ipausersearchfields'),
+ ipauserobjectclasses=module.params.get('ipauserobjectclasses'),
)
ipa_config = client.config_show()
diff = get_config_diff(client, ipa_config, module_config)
@@ -322,6 +344,8 @@ def main():
ipadefaultloginshell=dict(type='str', aliases=['loginshell']),
ipadefaultemaildomain=dict(type='str', aliases=['emaildomain']),
ipadefaultprimarygroup=dict(type='str', aliases=['primarygroup']),
+ ipagroupobjectclasses=dict(type='list', elements='str',
+ aliases=['groupobjectclasses']),
ipagroupsearchfields=dict(type='list', elements='str',
aliases=['groupsearchfields']),
ipahomesrootdir=dict(type='str', aliases=['homesrootdir']),
@@ -337,9 +361,11 @@ def main():
ipauserauthtype=dict(type='list', elements='str',
aliases=['userauthtype'],
choices=["password", "radius", "otp", "pkinit",
- "hardened", "disabled"]),
+ "hardened", "idp", "passkey", "disabled"]),
ipausersearchfields=dict(type='list', elements='str',
aliases=['usersearchfields']),
+ ipauserobjectclasses=dict(type='list', elements='str',
+ aliases=['userobjectclasses']),
)
module = AnsibleModule(
diff --git a/ansible_collections/community/general/plugins/modules/ipa_dnsrecord.py b/ansible_collections/community/general/plugins/modules/ipa_dnsrecord.py
index b1a90141b..cb4ce03dd 100644
--- a/ansible_collections/community/general/plugins/modules/ipa_dnsrecord.py
+++ b/ansible_collections/community/general/plugins/modules/ipa_dnsrecord.py
@@ -35,22 +35,24 @@ options:
record_type:
description:
- The type of DNS record name.
- - Currently, 'A', 'AAAA', 'A6', 'CNAME', 'DNAME', 'PTR', 'TXT', 'SRV' and 'MX' are supported.
+ - Currently, 'A', 'AAAA', 'A6', 'CNAME', 'DNAME', 'NS', 'PTR', 'TXT', 'SRV' and 'MX' are supported.
- "'A6', 'CNAME', 'DNAME' and 'TXT' are added in version 2.5."
- "'SRV' and 'MX' are added in version 2.8."
+ - "'NS' are added in comunity.general 8.2.0."
required: false
default: 'A'
- choices: ['A', 'AAAA', 'A6', 'CNAME', 'DNAME', 'MX', 'PTR', 'SRV', 'TXT']
+ choices: ['A', 'AAAA', 'A6', 'CNAME', 'DNAME', 'MX', 'NS', 'PTR', 'SRV', 'TXT']
type: str
record_value:
description:
- Manage DNS record name with this value.
- - Mutually exclusive with I(record_values), and exactly one of I(record_value) and I(record_values) has to be specified.
- - Use I(record_values) if you need to specify multiple values.
+ - Mutually exclusive with O(record_values), and exactly one of O(record_value) and O(record_values) has to be specified.
+ - Use O(record_values) if you need to specify multiple values.
- In the case of 'A' or 'AAAA' record types, this will be the IP address.
- In the case of 'A6' record type, this will be the A6 Record data.
- In the case of 'CNAME' record type, this will be the hostname.
- In the case of 'DNAME' record type, this will be the DNAME target.
+ - In the case of 'NS' record type, this will be the name server hostname. Hostname must already have a valid A or AAAA record.
- In the case of 'PTR' record type, this will be the hostname.
- In the case of 'TXT' record type, this will be a text.
- In the case of 'SRV' record type, this will be a service record.
@@ -59,11 +61,12 @@ options:
record_values:
description:
- Manage DNS record name with this value.
- - Mutually exclusive with I(record_value), and exactly one of I(record_value) and I(record_values) has to be specified.
+ - Mutually exclusive with O(record_value), and exactly one of O(record_value) and O(record_values) has to be specified.
- In the case of 'A' or 'AAAA' record types, this will be the IP address.
- In the case of 'A6' record type, this will be the A6 Record data.
- In the case of 'CNAME' record type, this will be the hostname.
- In the case of 'DNAME' record type, this will be the DNAME target.
+ - In the case of 'NS' record type, this will be the name server hostname. Hostname must already have a valid A or AAAA record.
- In the case of 'PTR' record type, this will be the hostname.
- In the case of 'TXT' record type, this will be a text.
- In the case of 'SRV' record type, this will be a service record.
@@ -73,7 +76,7 @@ options:
record_ttl:
description:
- Set the TTL for the record.
- - Applies only when adding a new or changing the value of I(record_value) or I(record_values).
+ - Applies only when adding a new or changing the value of O(record_value) or O(record_values).
required: false
type: int
state:
@@ -162,6 +165,16 @@ EXAMPLES = r'''
ipa_user: admin
ipa_pass: topsecret
state: absent
+
+- name: Ensure an NS record for a subdomain is present
+ community,general.ipa_dnsrecord:
+ name: subdomain
+ zone_name: example.com
+ record_type: 'NS'
+ record_value: 'ns1.subdomain.exmaple.com'
+ ipa_host: ipa.example.com
+ ipa_user: admin
+ ipa_pass: ChangeMe!
'''
RETURN = r'''
@@ -205,6 +218,8 @@ class DNSRecordIPAClient(IPAClient):
item.update(cname_part_hostname=value)
elif details['record_type'] == 'DNAME':
item.update(dname_part_target=value)
+ elif details['record_type'] == 'NS':
+ item.update(ns_part_hostname=value)
elif details['record_type'] == 'PTR':
item.update(ptr_part_hostname=value)
elif details['record_type'] == 'TXT':
@@ -241,6 +256,8 @@ def get_dnsrecord_dict(details=None):
module_dnsrecord.update(cnamerecord=details['record_values'])
elif details['record_type'] == 'DNAME' and details['record_values']:
module_dnsrecord.update(dnamerecord=details['record_values'])
+ elif details['record_type'] == 'NS' and details['record_values']:
+ module_dnsrecord.update(nsrecord=details['record_values'])
elif details['record_type'] == 'PTR' and details['record_values']:
module_dnsrecord.update(ptrrecord=details['record_values'])
elif details['record_type'] == 'TXT' and details['record_values']:
@@ -311,7 +328,7 @@ def ensure(module, client):
def main():
- record_types = ['A', 'AAAA', 'A6', 'CNAME', 'DNAME', 'PTR', 'TXT', 'SRV', 'MX']
+ record_types = ['A', 'AAAA', 'A6', 'CNAME', 'DNAME', 'NS', 'PTR', 'TXT', 'SRV', 'MX']
argument_spec = ipa_argument_spec()
argument_spec.update(
zone_name=dict(type='str', required=True),
diff --git a/ansible_collections/community/general/plugins/modules/ipa_dnszone.py b/ansible_collections/community/general/plugins/modules/ipa_dnszone.py
index 06c93841e..6699b0525 100644
--- a/ansible_collections/community/general/plugins/modules/ipa_dnszone.py
+++ b/ansible_collections/community/general/plugins/modules/ipa_dnszone.py
@@ -152,7 +152,8 @@ def ensure(module, client):
changed = True
if not module.check_mode:
client.dnszone_add(zone_name=zone_name, details={'idnsallowdynupdate': dynamicupdate, 'idnsallowsyncptr': allowsyncptr})
- elif ipa_dnszone['idnsallowdynupdate'][0] != str(dynamicupdate).upper() or ipa_dnszone['idnsallowsyncptr'][0] != str(allowsyncptr).upper():
+ elif ipa_dnszone['idnsallowdynupdate'][0] != str(dynamicupdate).upper() or \
+ ipa_dnszone.get('idnsallowsyncptr') and ipa_dnszone['idnsallowsyncptr'][0] != str(allowsyncptr).upper():
changed = True
if not module.check_mode:
client.dnszone_mod(zone_name=zone_name, details={'idnsallowdynupdate': dynamicupdate, 'idnsallowsyncptr': allowsyncptr})
diff --git a/ansible_collections/community/general/plugins/modules/ipa_group.py b/ansible_collections/community/general/plugins/modules/ipa_group.py
index 87e7f0e66..92470606f 100644
--- a/ansible_collections/community/general/plugins/modules/ipa_group.py
+++ b/ansible_collections/community/general/plugins/modules/ipa_group.py
@@ -22,8 +22,8 @@ attributes:
options:
append:
description:
- - If C(true), add the listed I(user) and I(group) to the group members.
- - If C(false), only the listed I(user) and I(group) will be group members, removing any other members.
+ - If V(true), add the listed O(user) and O(group) to the group members.
+ - If V(false), only the listed O(user) and O(group) will be group members, removing any other members.
default: false
type: bool
version_added: 4.0.0
@@ -50,9 +50,9 @@ options:
group:
description:
- List of group names assigned to this group.
- - If I(append=false) and an empty list is passed all groups will be removed from this group.
+ - If O(append=false) and an empty list is passed all groups will be removed from this group.
- Groups that are already assigned but not passed will be removed.
- - If I(append=true) the listed groups will be assigned without removing other groups.
+ - If O(append=true) the listed groups will be assigned without removing other groups.
- If option is omitted assigned groups will not be checked or changed.
type: list
elements: str
@@ -63,20 +63,20 @@ options:
user:
description:
- List of user names assigned to this group.
- - If I(append=false) and an empty list is passed all users will be removed from this group.
+ - If O(append=false) and an empty list is passed all users will be removed from this group.
- Users that are already assigned but not passed will be removed.
- - If I(append=true) the listed users will be assigned without removing other users.
+ - If O(append=true) the listed users will be assigned without removing other users.
- If option is omitted assigned users will not be checked or changed.
type: list
elements: str
external_user:
description:
- List of external users assigned to this group.
- - Behaves identically to I(user) with respect to I(append) attribute.
- - List entries can be in C(DOMAIN\\username) or SID format.
+ - Behaves identically to O(user) with respect to O(append) attribute.
+ - List entries can be in V(DOMAIN\\\\username) or SID format.
- Unless SIDs are provided, the module will always attempt to make changes even if the group already has all the users.
This is because only SIDs are returned by IPA query.
- - I(external=true) is needed for this option to work.
+ - O(external=true) is needed for this option to work.
type: list
elements: str
version_added: 6.3.0
diff --git a/ansible_collections/community/general/plugins/modules/ipa_hbacrule.py b/ansible_collections/community/general/plugins/modules/ipa_hbacrule.py
index b7633262b..77a4d0d48 100644
--- a/ansible_collections/community/general/plugins/modules/ipa_hbacrule.py
+++ b/ansible_collections/community/general/plugins/modules/ipa_hbacrule.py
@@ -161,6 +161,7 @@ import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils.ipa import IPAClient, ipa_argument_spec
from ansible.module_utils.common.text.converters import to_native
+from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
class HBACRuleIPAClient(IPAClient):
@@ -231,10 +232,17 @@ def ensure(module, client):
name = module.params['cn']
state = module.params['state']
+ ipa_version = client.get_ipa_version()
if state in ['present', 'enabled']:
- ipaenabledflag = 'TRUE'
+ if LooseVersion(ipa_version) < LooseVersion('4.9.10'):
+ ipaenabledflag = 'TRUE'
+ else:
+ ipaenabledflag = True
else:
- ipaenabledflag = 'FALSE'
+ if LooseVersion(ipa_version) < LooseVersion('4.9.10'):
+ ipaenabledflag = 'FALSE'
+ else:
+ ipaenabledflag = False
host = module.params['host']
hostcategory = module.params['hostcategory']
diff --git a/ansible_collections/community/general/plugins/modules/ipa_host.py b/ansible_collections/community/general/plugins/modules/ipa_host.py
index d561401d4..b37a606d7 100644
--- a/ansible_collections/community/general/plugins/modules/ipa_host.py
+++ b/ansible_collections/community/general/plugins/modules/ipa_host.py
@@ -80,7 +80,7 @@ options:
type: str
update_dns:
description:
- - If set C("True") with state as C("absent"), then removes DNS records of the host managed by FreeIPA DNS.
+ - If set V(true) with O(state=absent), then removes DNS records of the host managed by FreeIPA DNS.
- This option has no effect for states other than "absent".
type: bool
random_password:
@@ -118,7 +118,6 @@ EXAMPLES = r'''
ipa_host: ipa.example.com
ipa_user: admin
ipa_pass: topsecret
- validate_certs: false
random_password: true
- name: Ensure host is disabled
diff --git a/ansible_collections/community/general/plugins/modules/ipa_hostgroup.py b/ansible_collections/community/general/plugins/modules/ipa_hostgroup.py
index 12232de89..70749c35b 100644
--- a/ansible_collections/community/general/plugins/modules/ipa_hostgroup.py
+++ b/ansible_collections/community/general/plugins/modules/ipa_hostgroup.py
@@ -22,8 +22,8 @@ attributes:
options:
append:
description:
- - If C(true), add the listed I(host) to the I(hostgroup).
- - If C(false), only the listed I(host) will be in I(hostgroup), removing any other hosts.
+ - If V(true), add the listed O(host) to the O(hostgroup).
+ - If V(false), only the listed O(host) will be in O(hostgroup), removing any other hosts.
default: false
type: bool
version_added: 6.6.0
diff --git a/ansible_collections/community/general/plugins/modules/ipa_otptoken.py b/ansible_collections/community/general/plugins/modules/ipa_otptoken.py
index f25ab6023..567674f93 100644
--- a/ansible_collections/community/general/plugins/modules/ipa_otptoken.py
+++ b/ansible_collections/community/general/plugins/modules/ipa_otptoken.py
@@ -48,7 +48,7 @@ options:
description: Assigned user of the token.
type: str
enabled:
- description: Mark the token as enabled (default C(true)).
+ description: Mark the token as enabled (default V(true)).
default: true
type: bool
notbefore:
@@ -237,7 +237,7 @@ def get_otptoken_dict(ansible_to_ipa, uniqueid=None, newuniqueid=None, otptype=N
if owner is not None:
otptoken[ansible_to_ipa['owner']] = owner
if enabled is not None:
- otptoken[ansible_to_ipa['enabled']] = 'FALSE' if enabled else 'TRUE'
+ otptoken[ansible_to_ipa['enabled']] = False if enabled else True
if notbefore is not None:
otptoken[ansible_to_ipa['notbefore']] = notbefore + 'Z'
if notafter is not None:
diff --git a/ansible_collections/community/general/plugins/modules/ipa_pwpolicy.py b/ansible_collections/community/general/plugins/modules/ipa_pwpolicy.py
index 6a6c4318b..ba7d70291 100644
--- a/ansible_collections/community/general/plugins/modules/ipa_pwpolicy.py
+++ b/ansible_collections/community/general/plugins/modules/ipa_pwpolicy.py
@@ -64,6 +64,26 @@ options:
lockouttime:
description: Period (in seconds) for which users are locked out.
type: str
+ gracelimit:
+ description: Maximum number of LDAP logins after password expiration.
+ type: int
+ version_added: 8.2.0
+ maxrepeat:
+ description: Maximum number of allowed same consecutive characters in the new password.
+ type: int
+ version_added: 8.2.0
+ maxsequence:
+ description: Maximum length of monotonic character sequences in the new password. An example of a monotonic sequence of length 5 is V(12345).
+ type: int
+ version_added: 8.2.0
+ dictcheck:
+ description: Check whether the password (with possible modifications) matches a word in a dictionary (using cracklib).
+ type: bool
+ version_added: 8.2.0
+ usercheck:
+ description: Check whether the password (with possible modifications) contains the user name in some form (if the name has > 3 characters).
+ type: bool
+ version_added: 8.2.0
extends_documentation_fragment:
- community.general.ipa.documentation
- community.general.attributes
@@ -93,9 +113,15 @@ EXAMPLES = r'''
historylength: '16'
minclasses: '4'
priority: '10'
+ minlength: '6'
maxfailcount: '4'
failinterval: '600'
lockouttime: '1200'
+ gracelimit: 3
+ maxrepeat: 3
+ maxsequence: 3
+ dictcheck: true
+ usercheck: true
ipa_host: ipa.example.com
ipa_user: admin
ipa_pass: topsecret
@@ -159,26 +185,35 @@ class PwPolicyIPAClient(IPAClient):
def get_pwpolicy_dict(maxpwdlife=None, minpwdlife=None, historylength=None, minclasses=None,
minlength=None, priority=None, maxfailcount=None, failinterval=None,
- lockouttime=None):
+ lockouttime=None, gracelimit=None, maxrepeat=None, maxsequence=None, dictcheck=None, usercheck=None):
pwpolicy = {}
- if maxpwdlife is not None:
- pwpolicy['krbmaxpwdlife'] = maxpwdlife
- if minpwdlife is not None:
- pwpolicy['krbminpwdlife'] = minpwdlife
- if historylength is not None:
- pwpolicy['krbpwdhistorylength'] = historylength
- if minclasses is not None:
- pwpolicy['krbpwdmindiffchars'] = minclasses
- if minlength is not None:
- pwpolicy['krbpwdminlength'] = minlength
- if priority is not None:
- pwpolicy['cospriority'] = priority
- if maxfailcount is not None:
- pwpolicy['krbpwdmaxfailure'] = maxfailcount
- if failinterval is not None:
- pwpolicy['krbpwdfailurecountinterval'] = failinterval
- if lockouttime is not None:
- pwpolicy['krbpwdlockoutduration'] = lockouttime
+ pwpolicy_options = {
+ 'krbmaxpwdlife': maxpwdlife,
+ 'krbminpwdlife': minpwdlife,
+ 'krbpwdhistorylength': historylength,
+ 'krbpwdmindiffchars': minclasses,
+ 'krbpwdminlength': minlength,
+ 'cospriority': priority,
+ 'krbpwdmaxfailure': maxfailcount,
+ 'krbpwdfailurecountinterval': failinterval,
+ 'krbpwdlockoutduration': lockouttime,
+ 'passwordgracelimit': gracelimit,
+ 'ipapwdmaxrepeat': maxrepeat,
+ 'ipapwdmaxsequence': maxsequence,
+ }
+
+ pwpolicy_boolean_options = {
+ 'ipapwddictcheck': dictcheck,
+ 'ipapwdusercheck': usercheck,
+ }
+
+ for option, value in pwpolicy_options.items():
+ if value is not None:
+ pwpolicy[option] = to_native(value)
+
+ for option, value in pwpolicy_boolean_options.items():
+ if value is not None:
+ pwpolicy[option] = bool(value)
return pwpolicy
@@ -199,7 +234,13 @@ def ensure(module, client):
priority=module.params.get('priority'),
maxfailcount=module.params.get('maxfailcount'),
failinterval=module.params.get('failinterval'),
- lockouttime=module.params.get('lockouttime'))
+ lockouttime=module.params.get('lockouttime'),
+ gracelimit=module.params.get('gracelimit'),
+ maxrepeat=module.params.get('maxrepeat'),
+ maxsequence=module.params.get('maxsequence'),
+ dictcheck=module.params.get('dictcheck'),
+ usercheck=module.params.get('usercheck'),
+ )
ipa_pwpolicy = client.pwpolicy_find(name=name)
@@ -236,7 +277,13 @@ def main():
priority=dict(type='str'),
maxfailcount=dict(type='str'),
failinterval=dict(type='str'),
- lockouttime=dict(type='str'))
+ lockouttime=dict(type='str'),
+ gracelimit=dict(type='int'),
+ maxrepeat=dict(type='int'),
+ maxsequence=dict(type='int'),
+ dictcheck=dict(type='bool'),
+ usercheck=dict(type='bool'),
+ )
module = AnsibleModule(argument_spec=argument_spec,
supports_check_mode=True)
diff --git a/ansible_collections/community/general/plugins/modules/ipa_sudorule.py b/ansible_collections/community/general/plugins/modules/ipa_sudorule.py
index 59b4eb19e..223f6b6de 100644
--- a/ansible_collections/community/general/plugins/modules/ipa_sudorule.py
+++ b/ansible_collections/community/general/plugins/modules/ipa_sudorule.py
@@ -47,6 +47,22 @@ options:
type: list
elements: str
version_added: 2.0.0
+ deny_cmd:
+ description:
+ - List of denied commands assigned to the rule.
+ - If an empty list is passed all commands will be removed from the rule.
+ - If option is omitted commands will not be checked or changed.
+ type: list
+ elements: str
+ version_added: 8.1.0
+ deny_cmdgroup:
+ description:
+ - List of denied command groups assigned to the rule.
+ - If an empty list is passed all command groups will be removed from the rule.
+ - If option is omitted command groups will not be checked or changed.
+ type: list
+ elements: str
+ version_added: 8.1.0
description:
description:
- Description of the sudo rule.
@@ -56,14 +72,14 @@ options:
- List of hosts assigned to the rule.
- If an empty list is passed all hosts will be removed from the rule.
- If option is omitted hosts will not be checked or changed.
- - Option C(hostcategory) must be omitted to assign hosts.
+ - Option O(hostcategory) must be omitted to assign hosts.
type: list
elements: str
hostcategory:
description:
- Host category the rule applies to.
- - If 'all' is passed one must omit C(host) and C(hostgroup).
- - Option C(host) and C(hostgroup) must be omitted to assign 'all'.
+ - If V(all) is passed one must omit O(host) and O(hostgroup).
+ - Option O(host) and O(hostgroup) must be omitted to assign V(all).
choices: ['all']
type: str
hostgroup:
@@ -71,7 +87,7 @@ options:
- List of host groups assigned to the rule.
- If an empty list is passed all host groups will be removed from the rule.
- If option is omitted host groups will not be checked or changed.
- - Option C(hostcategory) must be omitted to assign host groups.
+ - Option O(hostcategory) must be omitted to assign host groups.
type: list
elements: str
runasextusers:
@@ -186,6 +202,7 @@ import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils.ipa import IPAClient, ipa_argument_spec
from ansible.module_utils.common.text.converters import to_native
+from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
class SudoRuleIPAClient(IPAClient):
@@ -246,6 +263,12 @@ class SudoRuleIPAClient(IPAClient):
def sudorule_add_allow_command_group(self, name, item):
return self._post_json(method='sudorule_add_allow_command', name=name, item={'sudocmdgroup': item})
+ def sudorule_add_deny_command(self, name, item):
+ return self._post_json(method='sudorule_add_deny_command', name=name, item={'sudocmd': item})
+
+ def sudorule_add_deny_command_group(self, name, item):
+ return self._post_json(method='sudorule_add_deny_command', name=name, item={'sudocmdgroup': item})
+
def sudorule_remove_allow_command(self, name, item):
return self._post_json(method='sudorule_remove_allow_command', name=name, item=item)
@@ -303,6 +326,8 @@ def ensure(module, client):
cmd = module.params['cmd']
cmdgroup = module.params['cmdgroup']
cmdcategory = module.params['cmdcategory']
+ deny_cmd = module.params['deny_cmd']
+ deny_cmdgroup = module.params['deny_cmdgroup']
host = module.params['host']
hostcategory = module.params['hostcategory']
hostgroup = module.params['hostgroup']
@@ -310,10 +335,17 @@ def ensure(module, client):
runasgroupcategory = module.params['runasgroupcategory']
runasextusers = module.params['runasextusers']
+ ipa_version = client.get_ipa_version()
if state in ['present', 'enabled']:
- ipaenabledflag = 'TRUE'
+ if LooseVersion(ipa_version) < LooseVersion('4.9.10'):
+ ipaenabledflag = 'TRUE'
+ else:
+ ipaenabledflag = True
else:
- ipaenabledflag = 'FALSE'
+ if LooseVersion(ipa_version) < LooseVersion('4.9.10'):
+ ipaenabledflag = 'FALSE'
+ else:
+ ipaenabledflag = False
sudoopt = module.params['sudoopt']
user = module.params['user']
@@ -359,6 +391,16 @@ def ensure(module, client):
if not module.check_mode:
client.sudorule_add_allow_command_group(name=name, item=cmdgroup)
+ if deny_cmd is not None:
+ changed = category_changed(module, client, 'cmdcategory', ipa_sudorule) or changed
+ if not module.check_mode:
+ client.sudorule_add_deny_command(name=name, item=deny_cmd)
+
+ if deny_cmdgroup is not None:
+ changed = category_changed(module, client, 'cmdcategory', ipa_sudorule) or changed
+ if not module.check_mode:
+ client.sudorule_add_deny_command_group(name=name, item=deny_cmdgroup)
+
if runasusercategory is not None:
changed = category_changed(module, client, 'iparunasusercategory', ipa_sudorule) or changed
@@ -433,6 +475,8 @@ def main():
cmdgroup=dict(type='list', elements='str'),
cmdcategory=dict(type='str', choices=['all']),
cn=dict(type='str', required=True, aliases=['name']),
+ deny_cmd=dict(type='list', elements='str'),
+ deny_cmdgroup=dict(type='list', elements='str'),
description=dict(type='str'),
host=dict(type='list', elements='str'),
hostcategory=dict(type='str', choices=['all']),
@@ -447,7 +491,9 @@ def main():
runasextusers=dict(type='list', elements='str'))
module = AnsibleModule(argument_spec=argument_spec,
mutually_exclusive=[['cmdcategory', 'cmd'],
+ ['cmdcategory', 'deny_cmd'],
['cmdcategory', 'cmdgroup'],
+ ['cmdcategory', 'deny_cmdgroup'],
['hostcategory', 'host'],
['hostcategory', 'hostgroup'],
['usercategory', 'user'],
diff --git a/ansible_collections/community/general/plugins/modules/ipa_user.py b/ansible_collections/community/general/plugins/modules/ipa_user.py
index 17b72176e..e8a1858d0 100644
--- a/ansible_collections/community/general/plugins/modules/ipa_user.py
+++ b/ansible_collections/community/general/plugins/modules/ipa_user.py
@@ -30,7 +30,9 @@ options:
default: 'always'
choices: [ always, on_create ]
givenname:
- description: First name.
+ description:
+ - First name.
+ - If user does not exist and O(state=present), the usage of O(givenname) is required.
type: str
krbpasswordexpiration:
description:
@@ -51,10 +53,12 @@ options:
password:
description:
- Password for a user.
- - Will not be set for an existing user unless I(update_password=always), which is the default.
+ - Will not be set for an existing user unless O(update_password=always), which is the default.
type: str
sn:
- description: Surname.
+ description:
+ - Surname.
+ - If user does not exist and O(state=present), the usage of O(sn) is required.
type: str
sshpubkey:
description:
@@ -99,7 +103,9 @@ options:
userauthtype:
description:
- The authentication type to use for the user.
- choices: ["password", "radius", "otp", "pkinit", "hardened"]
+ - To remove all authentication types from the user, use an empty list V([]).
+ - The choice V(idp) and V(passkey) has been added in community.general 8.1.0.
+ choices: ["password", "radius", "otp", "pkinit", "hardened", "idp", "passkey"]
type: list
elements: str
version_added: '1.2.0'
@@ -374,7 +380,7 @@ def main():
title=dict(type='str'),
homedirectory=dict(type='str'),
userauthtype=dict(type='list', elements='str',
- choices=['password', 'radius', 'otp', 'pkinit', 'hardened']))
+ choices=['password', 'radius', 'otp', 'pkinit', 'hardened', 'idp', 'passkey']))
module = AnsibleModule(argument_spec=argument_spec,
supports_check_mode=True)
diff --git a/ansible_collections/community/general/plugins/modules/ipa_vault.py b/ansible_collections/community/general/plugins/modules/ipa_vault.py
index 84b72c1ab..88947e470 100644
--- a/ansible_collections/community/general/plugins/modules/ipa_vault.py
+++ b/ansible_collections/community/general/plugins/modules/ipa_vault.py
@@ -93,7 +93,6 @@ EXAMPLES = r'''
ipa_host: ipa.example.com
ipa_user: admin
ipa_pass: topsecret
- validate_certs: false
- name: Ensure vault is present for Admin user
community.general.ipa_vault:
diff --git a/ansible_collections/community/general/plugins/modules/ipbase_info.py b/ansible_collections/community/general/plugins/modules/ipbase_info.py
new file mode 100644
index 000000000..c6a5511b7
--- /dev/null
+++ b/ansible_collections/community/general/plugins/modules/ipbase_info.py
@@ -0,0 +1,304 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2023, Dominik Kukacka <dominik.kukacka@gmail.com>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+DOCUMENTATION = '''
+---
+module: "ipbase_info"
+version_added: "7.0.0"
+short_description: "Retrieve IP geolocation and other facts of a host's IP address using the ipbase.com API"
+description:
+ - "Retrieve IP geolocation and other facts of a host's IP address using the ipbase.com API"
+author: "Dominik Kukacka (@dominikkukacka)"
+extends_documentation_fragment:
+ - "community.general.attributes"
+ - "community.general.attributes.info_module"
+options:
+ ip:
+ description:
+ - "The IP you want to get the info for. If not specified the API will detect the IP automatically."
+ required: false
+ type: str
+ apikey:
+ description:
+ - "The API key for the request if you need more requests."
+ required: false
+ type: str
+ hostname:
+ description:
+ - "If the O(hostname) parameter is set to V(true), the API response will contain the hostname of the IP."
+ required: false
+ type: bool
+ default: false
+ language:
+ description:
+ - "An ISO Alpha 2 Language Code for localizing the IP data"
+ required: false
+ type: str
+ default: "en"
+notes:
+ - "Check U(https://ipbase.com/) for more information."
+'''
+
+EXAMPLES = '''
+- name: "Get IP geolocation information of the primary outgoing IP"
+ community.general.ipbase_info:
+ register: my_ip_info
+
+- name: "Get IP geolocation information of a specific IP"
+ community.general.ipbase_info:
+ ip: "8.8.8.8"
+ register: my_ip_info
+
+
+- name: "Get IP geolocation information of a specific IP with all other possible parameters"
+ community.general.ipbase_info:
+ ip: "8.8.8.8"
+ apikey: "xxxxxxxxxxxxxxxxxxxxxx"
+ hostname: true
+ language: "de"
+ register: my_ip_info
+
+'''
+
+RETURN = '''
+data:
+ description: "JSON parsed response from ipbase.com. Please refer to U(https://ipbase.com/docs/info) for the detailed structure of the response."
+ returned: success
+ type: dict
+ sample: {
+ "ip": "1.1.1.1",
+ "hostname": "one.one.one.one",
+ "type": "v4",
+ "range_type": {
+ "type": "PUBLIC",
+ "description": "Public address"
+ },
+ "connection": {
+ "asn": 13335,
+ "organization": "Cloudflare, Inc.",
+ "isp": "APNIC Research and Development",
+ "range": "1.1.1.1/32"
+ },
+ "location": {
+ "geonames_id": 5332870,
+ "latitude": 34.053611755371094,
+ "longitude": -118.24549865722656,
+ "zip": "90012",
+ "continent": {
+ "code": "NA",
+ "name": "North America",
+ "name_translated": "North America"
+ },
+ "country": {
+ "alpha2": "US",
+ "alpha3": "USA",
+ "calling_codes": [
+ "+1"
+ ],
+ "currencies": [
+ {
+ "symbol": "$",
+ "name": "US Dollar",
+ "symbol_native": "$",
+ "decimal_digits": 2,
+ "rounding": 0,
+ "code": "USD",
+ "name_plural": "US dollars"
+ }
+ ],
+ "emoji": "...",
+ "ioc": "USA",
+ "languages": [
+ {
+ "name": "English",
+ "name_native": "English"
+ }
+ ],
+ "name": "United States",
+ "name_translated": "United States",
+ "timezones": [
+ "America/New_York",
+ "America/Detroit",
+ "America/Kentucky/Louisville",
+ "America/Kentucky/Monticello",
+ "America/Indiana/Indianapolis",
+ "America/Indiana/Vincennes",
+ "America/Indiana/Winamac",
+ "America/Indiana/Marengo",
+ "America/Indiana/Petersburg",
+ "America/Indiana/Vevay",
+ "America/Chicago",
+ "America/Indiana/Tell_City",
+ "America/Indiana/Knox",
+ "America/Menominee",
+ "America/North_Dakota/Center",
+ "America/North_Dakota/New_Salem",
+ "America/North_Dakota/Beulah",
+ "America/Denver",
+ "America/Boise",
+ "America/Phoenix",
+ "America/Los_Angeles",
+ "America/Anchorage",
+ "America/Juneau",
+ "America/Sitka",
+ "America/Metlakatla",
+ "America/Yakutat",
+ "America/Nome",
+ "America/Adak",
+ "Pacific/Honolulu"
+ ],
+ "is_in_european_union": false,
+ "fips": "US",
+ "geonames_id": 6252001,
+ "hasc_id": "US",
+ "wikidata_id": "Q30"
+ },
+ "city": {
+ "fips": "644000",
+ "alpha2": null,
+ "geonames_id": 5368753,
+ "hasc_id": null,
+ "wikidata_id": "Q65",
+ "name": "Los Angeles",
+ "name_translated": "Los Angeles"
+ },
+ "region": {
+ "fips": "US06",
+ "alpha2": "US-CA",
+ "geonames_id": 5332921,
+ "hasc_id": "US.CA",
+ "wikidata_id": "Q99",
+ "name": "California",
+ "name_translated": "California"
+ }
+ },
+ "tlds": [
+ ".us"
+ ],
+ "timezone": {
+ "id": "America/Los_Angeles",
+ "current_time": "2023-05-04T04:30:28-07:00",
+ "code": "PDT",
+ "is_daylight_saving": true,
+ "gmt_offset": -25200
+ },
+ "security": {
+ "is_anonymous": false,
+ "is_datacenter": false,
+ "is_vpn": false,
+ "is_bot": false,
+ "is_abuser": true,
+ "is_known_attacker": true,
+ "is_proxy": false,
+ "is_spam": false,
+ "is_tor": false,
+ "is_icloud_relay": false,
+ "threat_score": 100
+ },
+ "domains": {
+ "count": 10943,
+ "domains": [
+ "eliwise.academy",
+ "accountingprose.academy",
+ "pistola.academy",
+ "1and1-test-ntlds-fr.accountant",
+ "omnergy.africa"
+ ]
+ }
+ }
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible.module_utils.urls import fetch_url
+
+from ansible.module_utils.six.moves.urllib.parse import urlencode
+
+
+USER_AGENT = 'ansible-community.general.ipbase_info/0.1.0'
+BASE_URL = 'https://api.ipbase.com/v2/info'
+
+
+class IpbaseInfo(object):
+
+ def __init__(self, module):
+ self.module = module
+
+ def _get_url_data(self, url):
+ response, info = fetch_url(
+ self.module,
+ url,
+ force=True,
+ timeout=10,
+ headers={
+ 'Accept': 'application/json',
+ 'User-Agent': USER_AGENT,
+ })
+
+ if info['status'] != 200:
+ self.module.fail_json(msg='The API request to ipbase.com returned an error status code {0}'.format(info['status']))
+ else:
+ try:
+ content = response.read()
+ result = self.module.from_json(content.decode('utf8'))
+ except ValueError:
+ self.module.fail_json(
+ msg='Failed to parse the ipbase.com response: '
+ '{0} {1}'.format(url, content))
+ else:
+ return result
+
+ def info(self):
+
+ ip = self.module.params['ip']
+ apikey = self.module.params['apikey']
+ hostname = self.module.params['hostname']
+ language = self.module.params['language']
+
+ url = BASE_URL
+
+ params = {}
+ if ip:
+ params['ip'] = ip
+
+ if apikey:
+ params['apikey'] = apikey
+
+ if hostname:
+ params['hostname'] = 1
+
+ if language:
+ params['language'] = language
+
+ if params:
+ url += '?' + urlencode(params)
+
+ return self._get_url_data(url)
+
+
+def main():
+ module_args = dict(
+ ip=dict(type='str', required=False, no_log=False),
+ apikey=dict(type='str', required=False, no_log=True),
+ hostname=dict(type='bool', required=False, no_log=False, default=False),
+ language=dict(type='str', required=False, no_log=False, default='en'),
+ )
+
+ module = AnsibleModule(
+ argument_spec=module_args,
+ supports_check_mode=True,
+ )
+
+ ipbase = IpbaseInfo(module)
+ module.exit_json(**ipbase.info())
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/general/plugins/modules/ipify_facts.py b/ansible_collections/community/general/plugins/modules/ipify_facts.py
index ab96d7e94..ff17d7e54 100644
--- a/ansible_collections/community/general/plugins/modules/ipify_facts.py
+++ b/ansible_collections/community/general/plugins/modules/ipify_facts.py
@@ -35,7 +35,7 @@ options:
default: 10
validate_certs:
description:
- - When set to C(NO), SSL certificates will not be validated.
+ - When set to V(false), SSL certificates will not be validated.
type: bool
default: true
notes:
diff --git a/ansible_collections/community/general/plugins/modules/ipmi_boot.py b/ansible_collections/community/general/plugins/modules/ipmi_boot.py
index 7a4d2b6ec..9f0016560 100644
--- a/ansible_collections/community/general/plugins/modules/ipmi_boot.py
+++ b/ansible_collections/community/general/plugins/modules/ipmi_boot.py
@@ -93,7 +93,6 @@ options:
type: bool
default: false
requirements:
- - "python >= 2.6"
- pyghmi
author: "Bulat Gaifullin (@bgaifullin) <gaifullinbf@gmail.com>"
'''
diff --git a/ansible_collections/community/general/plugins/modules/ipmi_power.py b/ansible_collections/community/general/plugins/modules/ipmi_power.py
index e152f35eb..587cee06f 100644
--- a/ansible_collections/community/general/plugins/modules/ipmi_power.py
+++ b/ansible_collections/community/general/plugins/modules/ipmi_power.py
@@ -58,7 +58,7 @@ options:
- shutdown -- Have system request OS proper shutdown
- reset -- Request system reset without waiting for OS
- boot -- If system is off, then 'on', else 'reset'"
- - Either this option or I(machine) is required.
+ - Either this option or O(machine) is required.
choices: ['on', 'off', shutdown, reset, boot]
type: str
timeout:
@@ -70,7 +70,7 @@ options:
description:
- Provide a list of the remote target address for the bridge IPMI request,
and the power status.
- - Either this option or I(state) is required.
+ - Either this option or O(state) is required.
required: false
type: list
elements: dict
@@ -83,14 +83,13 @@ options:
required: true
state:
description:
- - Whether to ensure that the machine specified by I(targetAddress) in desired state.
- - If this option is not set, the power state is set by I(state).
- - If both this option and I(state) are set, this option takes precedence over I(state).
+ - Whether to ensure that the machine specified by O(machine[].targetAddress) in desired state.
+ - If this option is not set, the power state is set by O(state).
+ - If both this option and O(state) are set, this option takes precedence over O(state).
choices: ['on', 'off', shutdown, reset, boot]
type: str
requirements:
- - "python >= 2.6"
- pyghmi
author: "Bulat Gaifullin (@bgaifullin) <gaifullinbf@gmail.com>"
'''
@@ -98,18 +97,18 @@ author: "Bulat Gaifullin (@bgaifullin) <gaifullinbf@gmail.com>"
RETURN = '''
powerstate:
description: The current power state of the machine.
- returned: success and I(machine) is not provided
+ returned: success and O(machine) is not provided
type: str
sample: 'on'
status:
description: The current power state of the machine when the machine option is set.
- returned: success and I(machine) is provided
+ returned: success and O(machine) is provided
type: list
elements: dict
version_added: 4.3.0
contains:
powerstate:
- description: The current power state of the machine specified by I(targetAddress).
+ description: The current power state of the machine specified by RV(status[].targetAddress).
type: str
targetAddress:
description: The remote target address.
diff --git a/ansible_collections/community/general/plugins/modules/iptables_state.py b/ansible_collections/community/general/plugins/modules/iptables_state.py
index d0ea7ad79..b0cc3bd3f 100644
--- a/ansible_collections/community/general/plugins/modules/iptables_state.py
+++ b/ansible_collections/community/general/plugins/modules/iptables_state.py
@@ -34,8 +34,8 @@ description:
notes:
- The rollback feature is not a module option and depends on task's
attributes. To enable it, the module must be played asynchronously, i.e.
- by setting task attributes I(poll) to C(0), and I(async) to a value less
- or equal to C(ANSIBLE_TIMEOUT). If I(async) is greater, the rollback will
+ by setting task attributes C(poll) to V(0), and C(async) to a value less
+ or equal to C(ANSIBLE_TIMEOUT). If C(async) is greater, the rollback will
still happen if it shall happen, but you will experience a connection
timeout instead of more relevant info returned by the module after its
failure.
@@ -52,7 +52,7 @@ options:
counters:
description:
- Save or restore the values of all packet and byte counters.
- - When C(true), the module is not idempotent.
+ - When V(true), the module is not idempotent.
type: bool
default: false
ip_version:
@@ -65,14 +65,14 @@ options:
description:
- Specify the path to the C(modprobe) program internally used by iptables
related commands to load kernel modules.
- - By default, C(/proc/sys/kernel/modprobe) is inspected to determine the
+ - By default, V(/proc/sys/kernel/modprobe) is inspected to determine the
executable's path.
type: path
noflush:
description:
- - For I(state=restored), ignored otherwise.
- - If C(false), restoring iptables rules from a file flushes (deletes)
- all previous contents of the respective table(s). If C(true), the
+ - For O(state=restored), ignored otherwise.
+ - If V(false), restoring iptables rules from a file flushes (deletes)
+ all previous contents of the respective table(s). If V(true), the
previous rules are left untouched (but policies are updated anyway,
for all built-in chains).
type: bool
@@ -92,10 +92,10 @@ options:
required: true
table:
description:
- - When I(state=restored), restore only the named table even if the input
+ - When O(state=restored), restore only the named table even if the input
file contains other tables. Fail if the named table is not declared in
the file.
- - When I(state=saved), restrict output to the specified table. If not
+ - When O(state=saved), restrict output to the specified table. If not
specified, output includes all active tables.
type: str
choices: [ filter, nat, mangle, raw, security ]
@@ -207,7 +207,9 @@ saved:
"# Completed"
]
tables:
- description: The iptables we have interest for when module starts.
+ description:
+ - The iptables on the system before the module has run, separated by table.
+ - If the option O(table) is used, only this table is included.
type: dict
contains:
table:
@@ -346,20 +348,27 @@ def filter_and_format_state(string):
return lines
-def per_table_state(command, state):
+def parse_per_table_state(all_states_dump):
'''
Convert raw iptables-save output into usable datastructure, for reliable
comparisons between initial and final states.
'''
+ lines = filter_and_format_state(all_states_dump)
tables = dict()
- for t in TABLES:
- COMMAND = list(command)
- if '*%s' % t in state.splitlines():
- COMMAND.extend(['--table', t])
- dummy, out, dummy = module.run_command(COMMAND, check_rc=True)
- out = re.sub(r'(^|\n)(# Generated|# Completed|[*]%s|COMMIT)[^\n]*' % t, r'', out)
- out = re.sub(r' *\[[0-9]+:[0-9]+\] *', r'', out)
- tables[t] = [tt for tt in out.splitlines() if tt != '']
+ current_table = ''
+ current_list = list()
+ for line in lines:
+ if re.match(r'^[*](filter|mangle|nat|raw|security)$', line):
+ current_table = line[1:]
+ continue
+ if line == 'COMMIT':
+ tables[current_table] = current_list
+ current_table = ''
+ current_list = list()
+ continue
+ if line.startswith('# '):
+ continue
+ current_list.append(line)
return tables
@@ -458,7 +467,7 @@ def main():
# The issue comes when wanting to restore state from empty iptable-save's
# output... what happens when, say:
# - no table is specified, and iptables-save's output is only nat table;
- # - we give filter's ruleset to iptables-restore, that locks ourselve out
+ # - we give filter's ruleset to iptables-restore, that locks ourselves out
# of the host;
# then trying to roll iptables state back to the previous (working) setup
# doesn't override current filter table because no filter table is stored
@@ -486,7 +495,7 @@ def main():
# Depending on the value of 'table', initref_state may differ from
# initial_state.
(rc, stdout, stderr) = module.run_command(SAVECOMMAND, check_rc=True)
- tables_before = per_table_state(SAVECOMMAND, stdout)
+ tables_before = parse_per_table_state(stdout)
initref_state = filter_and_format_state(stdout)
if state == 'saved':
@@ -583,14 +592,17 @@ def main():
(rc, stdout, stderr) = module.run_command(SAVECOMMAND, check_rc=True)
restored_state = filter_and_format_state(stdout)
-
+ tables_after = parse_per_table_state('\n'.join(restored_state))
if restored_state not in (initref_state, initial_state):
- if module.check_mode:
- changed = True
- else:
- tables_after = per_table_state(SAVECOMMAND, stdout)
- if tables_after != tables_before:
+ for table_name, table_content in tables_after.items():
+ if table_name not in tables_before:
+ # Would initialize a table, which doesn't exist yet
+ changed = True
+ break
+ if tables_before[table_name] != table_content:
+ # Content of some table changes
changed = True
+ break
if _back is None or module.check_mode:
module.exit_json(
@@ -633,7 +645,7 @@ def main():
os.remove(b_back)
(rc, stdout, stderr) = module.run_command(SAVECOMMAND, check_rc=True)
- tables_rollback = per_table_state(SAVECOMMAND, stdout)
+ tables_rollback = parse_per_table_state(stdout)
msg = (
"Failed to confirm state restored from %s after %ss. "
diff --git a/ansible_collections/community/general/plugins/modules/ipwcli_dns.py b/ansible_collections/community/general/plugins/modules/ipwcli_dns.py
index 7b05aefb7..3ffad79fb 100644
--- a/ansible_collections/community/general/plugins/modules/ipwcli_dns.py
+++ b/ansible_collections/community/general/plugins/modules/ipwcli_dns.py
@@ -54,7 +54,7 @@ options:
address:
description:
- The IP address for the A or AAAA record.
- - Required for I(type=A) or I(type=AAAA).
+ - Required for O(type=A) or O(type=AAAA).
type: str
ttl:
description:
@@ -80,38 +80,38 @@ options:
port:
description:
- Sets the port of the SRV record.
- - Required for I(type=SRV).
+ - Required for O(type=SRV).
type: int
target:
description:
- Sets the target of the SRV record.
- - Required for I(type=SRV).
+ - Required for O(type=SRV).
type: str
order:
description:
- Sets the order of the NAPTR record.
- - Required for I(type=NAPTR).
+ - Required for O(type=NAPTR).
type: int
preference:
description:
- Sets the preference of the NAPTR record.
- - Required for I(type=NAPTR).
+ - Required for O(type=NAPTR).
type: int
flags:
description:
- Sets one of the possible flags of NAPTR record.
- - Required for I(type=NAPTR).
+ - Required for O(type=NAPTR).
type: str
choices: ['S', 'A', 'U', 'P']
service:
description:
- Sets the service of the NAPTR record.
- - Required for I(type=NAPTR).
+ - Required for O(type=NAPTR).
type: str
replacement:
description:
- Sets the replacement of the NAPTR record.
- - Required for I(type=NAPTR).
+ - Required for O(type=NAPTR).
type: str
username:
description:
diff --git a/ansible_collections/community/general/plugins/modules/irc.py b/ansible_collections/community/general/plugins/modules/irc.py
index 6cd7bc120..00ff299ee 100644
--- a/ansible_collections/community/general/plugins/modules/irc.py
+++ b/ansible_collections/community/general/plugins/modules/irc.py
@@ -50,8 +50,7 @@ options:
color:
type: str
description:
- - Text color for the message. ("none" is a valid option in 1.6 or later, in 1.6 and prior, the default color is black, not "none").
- Added 11 more colors in version 2.0.
+ - Text color for the message.
default: "none"
choices: [ "none", "white", "black", "blue", "green", "red", "brown", "purple", "orange", "yellow", "light_green", "teal", "light_cyan",
"light_blue", "pink", "gray", "light_gray"]
@@ -79,11 +78,17 @@ options:
- Timeout to use while waiting for successful registration and join
messages, this is to prevent an endless loop
default: 30
- use_ssl:
+ use_tls:
description:
- Designates whether TLS/SSL should be used when connecting to the IRC server
+ - O(use_tls) is available since community.general 8.1.0, before the option
+ was exlusively called O(use_ssl). The latter is now an alias of O(use_tls).
+ - B(Note:) for security reasons, you should always set O(use_tls=true) and
+ O(validate_certs=true) whenever possible.
type: bool
default: false
+ aliases:
+ - use_ssl
part:
description:
- Designates whether user should part from channel after sending message or not.
@@ -96,6 +101,16 @@ options:
- Text style for the message. Note italic does not work on some clients
choices: [ "bold", "underline", "reverse", "italic", "none" ]
default: none
+ validate_certs:
+ description:
+ - If set to V(false), the SSL certificates will not be validated.
+ - This should always be set to V(true). Using V(false) is unsafe and should only be done
+ if the network between between Ansible and the IRC server is known to be safe.
+ - B(Note:) for security reasons, you should always set O(use_tls=true) and
+ O(validate_certs=true) whenever possible.
+ default: false
+ type: bool
+ version_added: 8.1.0
# informational: requirements for nodes
requirements: [ socket ]
@@ -108,6 +123,8 @@ EXAMPLES = '''
- name: Send a message to an IRC channel from nick ansible
community.general.irc:
server: irc.example.net
+ use_tls: true
+ validate_certs: true
channel: #t1
msg: Hello world
@@ -116,6 +133,8 @@ EXAMPLES = '''
module: irc
port: 6669
server: irc.example.net
+ use_tls: true
+ validate_certs: true
channel: #t1
msg: 'All finished at {{ ansible_date_time.iso8601 }}'
color: red
@@ -126,6 +145,8 @@ EXAMPLES = '''
module: irc
port: 6669
server: irc.example.net
+ use_tls: true
+ validate_certs: true
channel: #t1
nick_to:
- nick1
@@ -150,7 +171,8 @@ from ansible.module_utils.basic import AnsibleModule
def send_msg(msg, server='localhost', port='6667', channel=None, nick_to=None, key=None, topic=None,
- nick="ansible", color='none', passwd=False, timeout=30, use_ssl=False, part=True, style=None):
+ nick="ansible", color='none', passwd=False, timeout=30, use_tls=False, validate_certs=True,
+ part=True, style=None):
'''send message to IRC'''
nick_to = [] if nick_to is None else nick_to
@@ -194,8 +216,20 @@ def send_msg(msg, server='localhost', port='6667', channel=None, nick_to=None, k
message = styletext + colortext + msg
irc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- if use_ssl:
- irc = ssl.wrap_socket(irc)
+ if use_tls:
+ if validate_certs:
+ try:
+ context = ssl.create_default_context()
+ except AttributeError:
+ raise Exception('Need at least Python 2.7.9 for SSL certificate validation')
+ else:
+ if getattr(ssl, 'PROTOCOL_TLS', None) is not None:
+ # Supported since Python 2.7.13
+ context = ssl.SSLContext(ssl.PROTOCOL_TLS)
+ else:
+ context = ssl.SSLContext()
+ context.verify_mode = ssl.CERT_NONE
+ irc = context.wrap_socket(irc)
irc.connect((server, int(port)))
if passwd:
@@ -275,7 +309,8 @@ def main():
passwd=dict(no_log=True),
timeout=dict(type='int', default=30),
part=dict(type='bool', default=True),
- use_ssl=dict(type='bool', default=False)
+ use_tls=dict(type='bool', default=False, aliases=['use_ssl']),
+ validate_certs=dict(type='bool', default=False),
),
supports_check_mode=True,
required_one_of=[['channel', 'nick_to']]
@@ -294,12 +329,13 @@ def main():
key = module.params["key"]
passwd = module.params["passwd"]
timeout = module.params["timeout"]
- use_ssl = module.params["use_ssl"]
+ use_tls = module.params["use_tls"]
part = module.params["part"]
style = module.params["style"]
+ validate_certs = module.params["validate_certs"]
try:
- send_msg(msg, server, port, channel, nick_to, key, topic, nick, color, passwd, timeout, use_ssl, part, style)
+ send_msg(msg, server, port, channel, nick_to, key, topic, nick, color, passwd, timeout, use_tls, validate_certs, part, style)
except Exception as e:
module.fail_json(msg="unable to send to IRC: %s" % to_native(e), exception=traceback.format_exc())
diff --git a/ansible_collections/community/general/plugins/modules/iso_create.py b/ansible_collections/community/general/plugins/modules/iso_create.py
index 4b51be96d..c39c710d5 100644
--- a/ansible_collections/community/general/plugins/modules/iso_create.py
+++ b/ansible_collections/community/general/plugins/modules/iso_create.py
@@ -19,7 +19,6 @@ author:
- Diane Wang (@Tomorrow9) <dianew@vmware.com>
requirements:
- "pycdlib"
- - "python >= 2.7"
version_added: '0.2.0'
extends_documentation_fragment:
@@ -35,7 +34,7 @@ options:
src_files:
description:
- This is a list of absolute paths of source files or folders which will be contained in the new generated ISO file.
- - Will fail if specified file or folder in C(src_files) does not exist on local machine.
+ - Will fail if specified file or folder in O(src_files) does not exist on local machine.
- 'Note: With all ISO9660 levels from 1 to 3, all file names are restricted to uppercase letters, numbers and
underscores (_). File names are limited to 31 characters, directory nesting is limited to 8 levels, and path
names are limited to 255 characters.'
@@ -51,9 +50,9 @@ options:
interchange_level:
description:
- The ISO9660 interchange level to use, it dictates the rules on the names of files.
- - Levels and valid values C(1), C(2), C(3), C(4) are supported.
- - The default value is level C(1), which is the most conservative, level C(3) is recommended.
- - ISO9660 file names at interchange level C(1) cannot have more than 8 characters or 3 characters in the extension.
+ - Levels and valid values V(1), V(2), V(3), V(4) are supported.
+ - The default value is level V(1), which is the most conservative, level V(3) is recommended.
+ - ISO9660 file names at interchange level V(1) cannot have more than 8 characters or 3 characters in the extension.
type: int
default: 1
choices: [1, 2, 3, 4]
@@ -64,23 +63,23 @@ options:
rock_ridge:
description:
- Whether to make this ISO have the Rock Ridge extensions or not.
- - Valid values are C(1.09), C(1.10) or C(1.12), means adding the specified Rock Ridge version to the ISO.
- - If unsure, set C(1.09) to ensure maximum compatibility.
+ - Valid values are V(1.09), V(1.10) or V(1.12), means adding the specified Rock Ridge version to the ISO.
+ - If unsure, set V(1.09) to ensure maximum compatibility.
- If not specified, then not add Rock Ridge extension to the ISO.
type: str
choices: ['1.09', '1.10', '1.12']
joliet:
description:
- - Support levels and valid values are C(1), C(2), or C(3).
- - Level C(3) is by far the most common.
+ - Support levels and valid values are V(1), V(2), or V(3).
+ - Level V(3) is by far the most common.
- If not specified, then no Joliet support is added.
type: int
choices: [1, 2, 3]
udf:
description:
- Whether to add UDF support to this ISO.
- - If set to C(True), then version 2.60 of the UDF spec is used.
- - If not specified or set to C(False), then no UDF support is added.
+ - If set to V(true), then version 2.60 of the UDF spec is used.
+ - If not specified or set to V(false), then no UDF support is added.
type: bool
default: false
'''
diff --git a/ansible_collections/community/general/plugins/modules/iso_customize.py b/ansible_collections/community/general/plugins/modules/iso_customize.py
index 9add080b1..543faaa5e 100644
--- a/ansible_collections/community/general/plugins/modules/iso_customize.py
+++ b/ansible_collections/community/general/plugins/modules/iso_customize.py
@@ -15,12 +15,11 @@ module: iso_customize
short_description: Add/remove/change files in ISO file
description:
- This module is used to add/remove/change files in ISO file.
- - The file inside ISO will be overwritten if it exists by option I(add_files).
+ - The file inside ISO will be overwritten if it exists by option O(add_files).
author:
- Yuhua Zou (@ZouYuhua) <zouy@vmware.com>
requirements:
- "pycdlib"
- - "python >= 2.7"
version_added: '5.8.0'
extends_documentation_fragment:
@@ -70,9 +69,9 @@ options:
type: str
required: true
notes:
-- The C(pycdlib) library states it supports Python 2.7 and 3.4 only.
+- The C(pycdlib) library states it supports Python 2.7 and 3.4+.
- >
- The function I(add_file) in pycdlib will overwrite the existing file in ISO with type ISO9660 / Rock Ridge 1.12 / Joliet / UDF.
+ The function C(add_file) in pycdlib will overwrite the existing file in ISO with type ISO9660 / Rock Ridge 1.12 / Joliet / UDF.
But it will not overwrite the existing file in ISO with Rock Ridge 1.09 / 1.10.
So we take workaround "delete the existing file and then add file for ISO with Rock Ridge".
'''
diff --git a/ansible_collections/community/general/plugins/modules/iso_extract.py b/ansible_collections/community/general/plugins/modules/iso_extract.py
index 599cbe4de..087ef2843 100644
--- a/ansible_collections/community/general/plugins/modules/iso_extract.py
+++ b/ansible_collections/community/general/plugins/modules/iso_extract.py
@@ -58,21 +58,18 @@ options:
required: true
force:
description:
- - If C(true), which will replace the remote file when contents are different than the source.
- - If C(false), the file will only be extracted and copied if the destination does not already exist.
+ - If V(true), which will replace the remote file when contents are different than the source.
+ - If V(false), the file will only be extracted and copied if the destination does not already exist.
type: bool
default: true
executable:
description:
- The path to the C(7z) executable to use for extracting files from the ISO.
- - If not provided, it will assume the value C(7z).
+ - If not provided, it will assume the value V(7z).
type: path
notes:
- Only the file checksum (content) is taken into account when extracting files
- from the ISO image. If I(force=false), only checks the presence of the file.
-- In Ansible 2.3 this module was using C(mount) and C(umount) commands only,
- requiring root access. This is no longer needed with the introduction of 7zip
- for extraction.
+ from the ISO image. If O(force=false), only checks the presence of the file.
'''
EXAMPLES = r'''
diff --git a/ansible_collections/community/general/plugins/modules/java_cert.py b/ansible_collections/community/general/plugins/modules/java_cert.py
index a188b16c3..72302b12c 100644
--- a/ansible_collections/community/general/plugins/modules/java_cert.py
+++ b/ansible_collections/community/general/plugins/modules/java_cert.py
@@ -18,6 +18,7 @@ description:
and optionally private keys to a given java keystore, or remove them from it.
extends_documentation_fragment:
- community.general.attributes
+ - ansible.builtin.files
attributes:
check_mode:
support: full
@@ -27,7 +28,7 @@ options:
cert_url:
description:
- Basic URL to fetch SSL certificate from.
- - Exactly one of C(cert_url), C(cert_path) or C(pkcs12_path) is required to load certificate.
+ - Exactly one of O(cert_url), O(cert_path), or O(pkcs12_path) is required to load certificate.
type: str
cert_port:
description:
@@ -38,7 +39,7 @@ options:
cert_path:
description:
- Local path to load certificate from.
- - Exactly one of C(cert_url), C(cert_path) or C(pkcs12_path) is required to load certificate.
+ - Exactly one of O(cert_url), O(cert_path), or O(pkcs12_path) is required to load certificate.
type: path
cert_alias:
description:
@@ -54,10 +55,10 @@ options:
pkcs12_path:
description:
- Local path to load PKCS12 keystore from.
- - Unlike C(cert_url) and C(cert_path), the PKCS12 keystore embeds the private key matching
+ - Unlike O(cert_url) and O(cert_path), the PKCS12 keystore embeds the private key matching
the certificate, and is used to import both the certificate and its private key into the
java keystore.
- - Exactly one of C(cert_url), C(cert_path) or C(pkcs12_path) is required to load certificate.
+ - Exactly one of O(cert_url), O(cert_path), or O(pkcs12_path) is required to load certificate.
type: path
pkcs12_password:
description:
@@ -98,6 +99,24 @@ options:
type: str
choices: [ absent, present ]
default: present
+ mode:
+ version_added: 8.5.0
+ owner:
+ version_added: 8.5.0
+ group:
+ version_added: 8.5.0
+ seuser:
+ version_added: 8.5.0
+ serole:
+ version_added: 8.5.0
+ setype:
+ version_added: 8.5.0
+ selevel:
+ version_added: 8.5.0
+ unsafe_writes:
+ version_added: 8.5.0
+ attributes:
+ version_added: 8.5.0
requirements: [openssl, keytool]
author:
- Adam Hamsik (@haad)
@@ -331,6 +350,12 @@ def build_proxy_options():
return proxy_opts
+def _update_permissions(module, keystore_path):
+ """ Updates keystore file attributes as necessary """
+ file_args = module.load_file_common_arguments(module.params, path=keystore_path)
+ return module.set_fs_attributes_if_different(file_args, False)
+
+
def _download_cert_url(module, executable, url, port):
""" Fetches the certificate from the remote URL using `keytool -printcert...`
The PEM formatted string is returned """
@@ -375,15 +400,15 @@ def import_pkcs12_path(module, executable, pkcs12_path, pkcs12_pass, pkcs12_alia
# Use local certificate from local path and import it to a java keystore
(import_rc, import_out, import_err) = module.run_command(import_cmd, data=secret_data, check_rc=False)
-
diff = {'before': '\n', 'after': '%s\n' % keystore_alias}
- if import_rc == 0 and os.path.exists(keystore_path):
- module.exit_json(changed=True, msg=import_out,
- rc=import_rc, cmd=import_cmd, stdout=import_out,
- error=import_err, diff=diff)
- else:
+
+ if import_rc != 0 or not os.path.exists(keystore_path):
module.fail_json(msg=import_out, rc=import_rc, cmd=import_cmd, error=import_err)
+ return dict(changed=True, msg=import_out,
+ rc=import_rc, cmd=import_cmd, stdout=import_out,
+ error=import_err, diff=diff)
+
def import_cert_path(module, executable, path, keystore_path, keystore_pass, alias, keystore_type, trust_cacert):
''' Import certificate from path into keystore located on
@@ -408,17 +433,17 @@ def import_cert_path(module, executable, path, keystore_path, keystore_pass, ali
(import_rc, import_out, import_err) = module.run_command(import_cmd,
data="%s\n%s" % (keystore_pass, keystore_pass),
check_rc=False)
-
diff = {'before': '\n', 'after': '%s\n' % alias}
- if import_rc == 0:
- module.exit_json(changed=True, msg=import_out,
- rc=import_rc, cmd=import_cmd, stdout=import_out,
- error=import_err, diff=diff)
- else:
- module.fail_json(msg=import_out, rc=import_rc, cmd=import_cmd)
+ if import_rc != 0:
+ module.fail_json(msg=import_out, rc=import_rc, cmd=import_cmd, error=import_err)
+
+ return dict(changed=True, msg=import_out,
+ rc=import_rc, cmd=import_cmd, stdout=import_out,
+ error=import_err, diff=diff)
-def delete_cert(module, executable, keystore_path, keystore_pass, alias, keystore_type, exit_after=True):
+
+def delete_cert(module, executable, keystore_path, keystore_pass, alias, keystore_type):
''' Delete certificate identified with alias from keystore on keystore_path '''
del_cmd = [
executable,
@@ -434,13 +459,13 @@ def delete_cert(module, executable, keystore_path, keystore_pass, alias, keystor
# Delete SSL certificate from keystore
(del_rc, del_out, del_err) = module.run_command(del_cmd, data=keystore_pass, check_rc=True)
+ diff = {'before': '%s\n' % alias, 'after': None}
- if exit_after:
- diff = {'before': '%s\n' % alias, 'after': None}
+ if del_rc != 0:
+ module.fail_json(msg=del_out, rc=del_rc, cmd=del_cmd, error=del_err)
- module.exit_json(changed=True, msg=del_out,
- rc=del_rc, cmd=del_cmd, stdout=del_out,
- error=del_err, diff=diff)
+ return dict(changed=True, msg=del_out, rc=del_rc, cmd=del_cmd,
+ stdout=del_out, error=del_err, diff=diff)
def test_keytool(module, executable):
@@ -485,6 +510,7 @@ def main():
['cert_url', 'cert_path', 'pkcs12_path']
],
supports_check_mode=True,
+ add_file_common_args=True,
)
url = module.params.get('cert_url')
@@ -526,12 +552,14 @@ def main():
module.add_cleanup_file(new_certificate)
module.add_cleanup_file(old_certificate)
+ result = dict()
+
if state == 'absent' and alias_exists:
if module.check_mode:
module.exit_json(changed=True)
- # delete and exit
- delete_cert(module, executable, keystore_path, keystore_pass, cert_alias, keystore_type)
+ # delete
+ result = delete_cert(module, executable, keystore_path, keystore_pass, cert_alias, keystore_type)
# dump certificate to enroll in the keystore on disk and compute digest
if state == 'present':
@@ -569,16 +597,20 @@ def main():
if alias_exists:
# The certificate in the keystore does not match with the one we want to be present
# The existing certificate must first be deleted before we insert the correct one
- delete_cert(module, executable, keystore_path, keystore_pass, cert_alias, keystore_type, exit_after=False)
+ delete_cert(module, executable, keystore_path, keystore_pass, cert_alias, keystore_type)
if pkcs12_path:
- import_pkcs12_path(module, executable, pkcs12_path, pkcs12_pass, pkcs12_alias,
- keystore_path, keystore_pass, cert_alias, keystore_type)
+ result = import_pkcs12_path(module, executable, pkcs12_path, pkcs12_pass, pkcs12_alias,
+ keystore_path, keystore_pass, cert_alias, keystore_type)
else:
- import_cert_path(module, executable, new_certificate, keystore_path,
- keystore_pass, cert_alias, keystore_type, trust_cacert)
+ result = import_cert_path(module, executable, new_certificate, keystore_path,
+ keystore_pass, cert_alias, keystore_type, trust_cacert)
+
+ if os.path.exists(keystore_path):
+ changed_permissions = _update_permissions(module, keystore_path)
+ result['changed'] = result.get('changed', False) or changed_permissions
- module.exit_json(changed=False)
+ module.exit_json(**result)
if __name__ == "__main__":
diff --git a/ansible_collections/community/general/plugins/modules/java_keystore.py b/ansible_collections/community/general/plugins/modules/java_keystore.py
index 7c2c4884d..2aeab75c0 100644
--- a/ansible_collections/community/general/plugins/modules/java_keystore.py
+++ b/ansible_collections/community/general/plugins/modules/java_keystore.py
@@ -36,7 +36,7 @@ options:
- If the fingerprint of the provided certificate does not match the
fingerprint of the certificate bundled in the keystore, the keystore
is regenerated with the provided certificate.
- - Exactly one of I(certificate) or I(certificate_path) is required.
+ - Exactly one of O(certificate) or O(certificate_path) is required.
type: str
certificate_path:
description:
@@ -44,18 +44,18 @@ options:
- If the fingerprint of the provided certificate does not match the
fingerprint of the certificate bundled in the keystore, the keystore
is regenerated with the provided certificate.
- - Exactly one of I(certificate) or I(certificate_path) is required.
+ - Exactly one of O(certificate) or O(certificate_path) is required.
type: path
version_added: '3.0.0'
private_key:
description:
- Content of the private key used to create the keystore.
- - Exactly one of I(private_key) or I(private_key_path) is required.
+ - Exactly one of O(private_key) or O(private_key_path) is required.
type: str
private_key_path:
description:
- Location of the private key used to create the keystore.
- - Exactly one of I(private_key) or I(private_key_path) is required.
+ - Exactly one of O(private_key) or O(private_key_path) is required.
type: path
version_added: '3.0.0'
private_key_passphrase:
@@ -108,13 +108,13 @@ options:
- Type of the Java keystore.
- When this option is omitted and the keystore doesn't already exist, the
behavior follows C(keytool)'s default store type which depends on
- Java version; C(pkcs12) since Java 9 and C(jks) prior (may also
- be C(pkcs12) if new default has been backported to this version).
+ Java version; V(pkcs12) since Java 9 and V(jks) prior (may also
+ be V(pkcs12) if new default has been backported to this version).
- When this option is omitted and the keystore already exists, the current
type is left untouched, unless another option leads to overwrite the
keystore (in that case, this option behaves like for keystore creation).
- - When I(keystore_type) is set, the keystore is created with this type if
- it doesn't already exist, or is overwritten to match the given type in
+ - When O(keystore_type) is set, the keystore is created with this type if
+ it does not already exist, or is overwritten to match the given type in
case of mismatch.
type: str
choices:
@@ -122,9 +122,9 @@ options:
- pkcs12
version_added: 3.3.0
requirements:
- - openssl in PATH (when I(ssl_backend=openssl))
+ - openssl in PATH (when O(ssl_backend=openssl))
- keytool in PATH
- - cryptography >= 3.0 (when I(ssl_backend=cryptography))
+ - cryptography >= 3.0 (when O(ssl_backend=cryptography))
author:
- Guillaume Grossetie (@Mogztter)
- quidame (@quidame)
@@ -135,13 +135,13 @@ seealso:
- module: community.crypto.openssl_pkcs12
- module: community.general.java_cert
notes:
- - I(certificate) and I(private_key) require that their contents are available
- on the controller (either inline in a playbook, or with the C(file) lookup),
- while I(certificate_path) and I(private_key_path) require that the files are
+ - O(certificate) and O(private_key) require that their contents are available
+ on the controller (either inline in a playbook, or with the P(ansible.builtin.file#lookup) lookup),
+ while O(certificate_path) and O(private_key_path) require that the files are
available on the target host.
- - By design, any change of a value of options I(keystore_type), I(name) or
- I(password), as well as changes of key or certificate materials will cause
- the existing I(dest) to be overwritten.
+ - By design, any change of a value of options O(keystore_type), O(name) or
+ O(password), as well as changes of key or certificate materials will cause
+ the existing O(dest) to be overwritten.
'''
EXAMPLES = '''
diff --git a/ansible_collections/community/general/plugins/modules/jboss.py b/ansible_collections/community/general/plugins/modules/jboss.py
index b389e7e66..3d07a38d6 100644
--- a/ansible_collections/community/general/plugins/modules/jboss.py
+++ b/ansible_collections/community/general/plugins/modules/jboss.py
@@ -30,8 +30,8 @@ options:
src:
description:
- The remote path of the application ear or war to deploy.
- - Required when I(state=present).
- - Ignored when I(state=absent).
+ - Required when O(state=present).
+ - Ignored when O(state=absent).
type: path
deploy_path:
default: /var/lib/jbossas/standalone/deployments
@@ -46,7 +46,7 @@ options:
type: str
notes:
- The JBoss standalone deployment-scanner has to be enabled in standalone.xml
- - The module can wait until I(deployment) file is deployed/undeployed by deployment-scanner.
+ - The module can wait until O(deployment) file is deployed/undeployed by deployment-scanner.
Duration of waiting time depends on scan-interval parameter from standalone.xml.
- Ensure no identically named application is deployed through the JBoss CLI
seealso:
diff --git a/ansible_collections/community/general/plugins/modules/jenkins_build.py b/ansible_collections/community/general/plugins/modules/jenkins_build.py
index 4f9520224..6d830849e 100644
--- a/ansible_collections/community/general/plugins/modules/jenkins_build.py
+++ b/ansible_collections/community/general/plugins/modules/jenkins_build.py
@@ -20,6 +20,7 @@ requirements:
author:
- Brett Milford (@brettmilford)
- Tong He (@unnecessary-username)
+ - Juan Casanova (@juanmcasanova)
extends_documentation_fragment:
- community.general.attributes
attributes:
@@ -48,7 +49,7 @@ options:
state:
description:
- Attribute that specifies if the build is to be created, deleted or stopped.
- - The C(stopped) state has been added in community.general 3.3.0.
+ - The V(stopped) state has been added in community.general 3.3.0.
default: present
choices: ['present', 'absent', 'stopped']
type: str
@@ -65,6 +66,19 @@ options:
description:
- User to authenticate with the Jenkins server.
type: str
+ detach:
+ description:
+ - Enable detached mode to not wait for the build end.
+ default: false
+ type: bool
+ version_added: 7.4.0
+ time_between_checks:
+ description:
+ - Time in seconds to wait between requests to the Jenkins server.
+ - This times must be higher than the configured quiet time for the job.
+ default: 10
+ type: int
+ version_added: 7.4.0
'''
EXAMPLES = '''
@@ -152,6 +166,8 @@ class JenkinsBuild:
self.user = module.params.get('user')
self.jenkins_url = module.params.get('url')
self.build_number = module.params.get('build_number')
+ self.detach = module.params.get('detach')
+ self.time_between_checks = module.params.get('time_between_checks')
self.server = self.get_jenkins_connection()
self.result = {
@@ -235,7 +251,14 @@ class JenkinsBuild:
build_status = self.get_build_status()
if build_status['result'] is None:
- sleep(10)
+ # If detached mode is active mark as success, we wouldn't be able to get here if it didn't exist
+ if self.detach:
+ result['changed'] = True
+ result['build_info'] = build_status
+
+ return result
+
+ sleep(self.time_between_checks)
self.get_result()
else:
if self.state == "stopped" and build_status['result'] == "ABORTED":
@@ -273,6 +296,8 @@ def main():
token=dict(no_log=True),
url=dict(default="http://localhost:8080"),
user=dict(),
+ detach=dict(type='bool', default=False),
+ time_between_checks=dict(type='int', default=10),
),
mutually_exclusive=[['password', 'token']],
required_if=[['state', 'absent', ['build_number'], True], ['state', 'stopped', ['build_number'], True]],
@@ -288,7 +313,7 @@ def main():
else:
jenkins_build.absent_build()
- sleep(10)
+ sleep(jenkins_build.time_between_checks)
result = jenkins_build.get_result()
module.exit_json(**result)
diff --git a/ansible_collections/community/general/plugins/modules/jenkins_build_info.py b/ansible_collections/community/general/plugins/modules/jenkins_build_info.py
new file mode 100644
index 000000000..eae6eb937
--- /dev/null
+++ b/ansible_collections/community/general/plugins/modules/jenkins_build_info.py
@@ -0,0 +1,210 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+DOCUMENTATION = '''
+---
+module: jenkins_build_info
+short_description: Get information about Jenkins builds
+version_added: 7.4.0
+description:
+ - Get information about Jenkins builds with Jenkins REST API.
+requirements:
+ - "python-jenkins >= 0.4.12"
+author:
+ - Juan Casanova (@juanmcasanova)
+extends_documentation_fragment:
+ - community.general.attributes
+ - community.general.attributes.info_module
+options:
+ name:
+ description:
+ - Name of the Jenkins job to which the build belongs.
+ required: true
+ type: str
+ build_number:
+ description:
+ - An integer which specifies a build of a job.
+ - If not specified the last build information will be returned.
+ type: int
+ password:
+ description:
+ - Password to authenticate with the Jenkins server.
+ type: str
+ token:
+ description:
+ - API token used to authenticate with the Jenkins server.
+ type: str
+ url:
+ description:
+ - URL of the Jenkins server.
+ default: http://localhost:8080
+ type: str
+ user:
+ description:
+ - User to authenticate with the Jenkins server.
+ type: str
+'''
+
+EXAMPLES = '''
+- name: Get information about a jenkins build using basic authentication
+ community.general.jenkins_build_info:
+ name: "test-check"
+ build_number: 1
+ user: admin
+ password: asdfg
+ url: http://localhost:8080
+
+- name: Get information about a jenkins build anonymously
+ community.general.jenkins_build_info:
+ name: "stop-check"
+ build_number: 3
+ url: http://localhost:8080
+
+- name: Get information about a jenkins build using token authentication
+ community.general.jenkins_build_info:
+ name: "delete-experiment"
+ build_number: 30
+ user: Jenkins
+ token: abcdefghijklmnopqrstuvwxyz123456
+ url: http://localhost:8080
+'''
+
+RETURN = '''
+---
+name:
+ description: Name of the jenkins job.
+ returned: success
+ type: str
+ sample: "test-job"
+state:
+ description: State of the jenkins job.
+ returned: success
+ type: str
+ sample: present
+user:
+ description: User used for authentication.
+ returned: success
+ type: str
+ sample: admin
+url:
+ description: URL to connect to the Jenkins server.
+ returned: success
+ type: str
+ sample: https://jenkins.mydomain.com
+build_info:
+ description: Build info of the jenkins job.
+ returned: success
+ type: dict
+'''
+
+import traceback
+
+JENKINS_IMP_ERR = None
+try:
+ import jenkins
+ python_jenkins_installed = True
+except ImportError:
+ JENKINS_IMP_ERR = traceback.format_exc()
+ python_jenkins_installed = False
+
+from ansible.module_utils.basic import AnsibleModule, missing_required_lib
+from ansible.module_utils.common.text.converters import to_native
+
+
+class JenkinsBuildInfo:
+
+ def __init__(self, module):
+ self.module = module
+
+ self.name = module.params.get('name')
+ self.password = module.params.get('password')
+ self.token = module.params.get('token')
+ self.user = module.params.get('user')
+ self.jenkins_url = module.params.get('url')
+ self.build_number = module.params.get('build_number')
+ self.server = self.get_jenkins_connection()
+
+ self.result = {
+ 'changed': False,
+ 'url': self.jenkins_url,
+ 'name': self.name,
+ 'user': self.user,
+ }
+
+ def get_jenkins_connection(self):
+ try:
+ if (self.user and self.password):
+ return jenkins.Jenkins(self.jenkins_url, self.user, self.password)
+ elif (self.user and self.token):
+ return jenkins.Jenkins(self.jenkins_url, self.user, self.token)
+ elif (self.user and not (self.password or self.token)):
+ return jenkins.Jenkins(self.jenkins_url, self.user)
+ else:
+ return jenkins.Jenkins(self.jenkins_url)
+ except Exception as e:
+ self.module.fail_json(msg='Unable to connect to Jenkins server, %s' % to_native(e))
+
+ def get_build_status(self):
+ try:
+ if self.build_number is None:
+ job_info = self.server.get_job_info(self.name)
+ self.build_number = job_info['lastBuild']['number']
+
+ return self.server.get_build_info(self.name, self.build_number)
+ except jenkins.JenkinsException as e:
+ response = {}
+ response["result"] = "ABSENT"
+ return response
+ except Exception as e:
+ self.module.fail_json(msg='Unable to fetch build information, %s' % to_native(e),
+ exception=traceback.format_exc())
+
+ def get_result(self):
+ result = self.result
+ build_status = self.get_build_status()
+
+ if build_status['result'] == "ABSENT":
+ result['failed'] = True
+ result['build_info'] = build_status
+
+ return result
+
+
+def test_dependencies(module):
+ if not python_jenkins_installed:
+ module.fail_json(
+ msg=missing_required_lib("python-jenkins",
+ url="https://python-jenkins.readthedocs.io/en/latest/install.html"),
+ exception=JENKINS_IMP_ERR)
+
+
+def main():
+ module = AnsibleModule(
+ argument_spec=dict(
+ build_number=dict(type='int'),
+ name=dict(required=True),
+ password=dict(no_log=True),
+ token=dict(no_log=True),
+ url=dict(default="http://localhost:8080"),
+ user=dict(),
+ ),
+ mutually_exclusive=[['password', 'token']],
+ supports_check_mode=True,
+ )
+
+ test_dependencies(module)
+ jenkins_build_info = JenkinsBuildInfo(module)
+
+ result = jenkins_build_info.get_result()
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/general/plugins/modules/jenkins_job.py b/ansible_collections/community/general/plugins/modules/jenkins_job.py
index 09b006448..e8301041f 100644
--- a/ansible_collections/community/general/plugins/modules/jenkins_job.py
+++ b/ansible_collections/community/general/plugins/modules/jenkins_job.py
@@ -30,14 +30,14 @@ options:
description:
- config in XML format.
- Required if job does not yet exist.
- - Mutually exclusive with I(enabled).
- - Considered if I(state=present).
+ - Mutually exclusive with O(enabled).
+ - Considered if O(state=present).
required: false
enabled:
description:
- Whether the job should be enabled or disabled.
- - Mutually exclusive with I(config).
- - Considered if I(state=present).
+ - Mutually exclusive with O(config).
+ - Considered if O(state=present).
type: bool
required: false
name:
@@ -77,10 +77,10 @@ options:
type: bool
default: true
description:
- - If set to C(false), the SSL certificates will not be validated.
- This should only set to C(false) used on personally controlled sites
+ - If set to V(false), the SSL certificates will not be validated.
+ This should only set to V(false) used on personally controlled sites
using self-signed certificates as it avoids verifying the source site.
- - The C(python-jenkins) library only handles this by using the environment variable C(PYTHONHTTPSVERIFY).
+ - The C(python-jenkins) library only handles this by using the environment variable E(PYTHONHTTPSVERIFY).
version_added: 2.3.0
'''
diff --git a/ansible_collections/community/general/plugins/modules/jenkins_job_info.py b/ansible_collections/community/general/plugins/modules/jenkins_job_info.py
index ba6a53117..40e1d7aea 100644
--- a/ansible_collections/community/general/plugins/modules/jenkins_job_info.py
+++ b/ansible_collections/community/general/plugins/modules/jenkins_job_info.py
@@ -15,7 +15,6 @@ module: jenkins_job_info
short_description: Get information about Jenkins jobs
description:
- This module can be used to query information about which Jenkins jobs which already exists.
- - This module was called C(jenkins_job_info) before Ansible 2.9. The usage did not change.
requirements:
- "python-jenkins >= 0.4.12"
extends_documentation_fragment:
@@ -38,12 +37,12 @@ options:
type: str
description:
- Password to authenticate with the Jenkins server.
- - This is mutually exclusive with I(token).
+ - This is mutually exclusive with O(token).
token:
type: str
description:
- API token used to authenticate with the Jenkins server.
- - This is mutually exclusive with I(password).
+ - This is mutually exclusive with O(password).
url:
type: str
description:
@@ -55,8 +54,8 @@ options:
- User to authenticate with the Jenkins server.
validate_certs:
description:
- - If set to C(False), the SSL certificates will not be validated.
- - This should only set to C(False) used on personally controlled sites using self-signed certificates.
+ - If set to V(false), the SSL certificates will not be validated.
+ - This should only set to V(false) used on personally controlled sites using self-signed certificates.
default: true
type: bool
author:
@@ -122,7 +121,6 @@ EXAMPLES = '''
user: admin
token: 126df5c60d66c66e3b75b11104a16a8a
url: https://jenkins.example.com
- validate_certs: false
register: my_jenkins_job_info
'''
diff --git a/ansible_collections/community/general/plugins/modules/jenkins_plugin.py b/ansible_collections/community/general/plugins/modules/jenkins_plugin.py
index 2fbc83e03..13a804a50 100644
--- a/ansible_collections/community/general/plugins/modules/jenkins_plugin.py
+++ b/ansible_collections/community/general/plugins/modules/jenkins_plugin.py
@@ -27,7 +27,7 @@ options:
group:
type: str
description:
- - Name of the Jenkins group on the OS.
+ - GID or name of the Jenkins group on the OS.
default: jenkins
jenkins_home:
type: path
@@ -47,13 +47,13 @@ options:
owner:
type: str
description:
- - Name of the Jenkins user on the OS.
+ - UID or name of the Jenkins user on the OS.
default: jenkins
state:
type: str
description:
- Desired plugin state.
- - If the C(latest) is set, the check for new version will be performed
+ - If set to V(latest), the check for new version will be performed
every time. This is suitable to keep the plugin up-to-date.
choices: [absent, present, pinned, unpinned, enabled, disabled, latest]
default: present
@@ -65,18 +65,18 @@ options:
updates_expiration:
type: int
description:
- - Number of seconds after which a new copy of the I(update-center.json)
+ - Number of seconds after which a new copy of the C(update-center.json)
file is downloaded. This is used to avoid the need to download the
- plugin to calculate its checksum when C(latest) is specified.
- - Set it to C(0) if no cache file should be used. In that case, the
+ plugin to calculate its checksum when O(state=latest) is specified.
+ - Set it to V(0) if no cache file should be used. In that case, the
plugin file will always be downloaded to calculate its checksum when
- C(latest) is specified.
+ O(state=latest) is specified.
default: 86400
updates_url:
type: list
elements: str
description:
- - A list of base URL(s) to retrieve I(update-center.json), and direct plugin files from.
+ - A list of base URL(s) to retrieve C(update-center.json), and direct plugin files from.
- This can be a list since community.general 3.3.0.
default: ['https://updates.jenkins.io', 'http://mirrors.jenkins.io']
update_json_url_segment:
@@ -90,14 +90,14 @@ options:
type: list
elements: str
description:
- - Path inside the I(updates_url) to get latest plugins from.
+ - Path inside the O(updates_url) to get latest plugins from.
default: ['latest']
version_added: 3.3.0
versioned_plugins_url_segments:
type: list
elements: str
description:
- - Path inside the I(updates_url) to get specific version of plugins from.
+ - Path inside the O(updates_url) to get specific version of plugins from.
default: ['download/plugins', 'plugins']
version_added: 3.3.0
url:
@@ -114,11 +114,11 @@ options:
- It might take longer to verify that the correct version is installed.
This is especially true if a specific version number is specified.
- Quote the version to prevent the value to be interpreted as float. For
- example if C(1.20) would be unquoted, it would become C(1.2).
+ example if V(1.20) would be unquoted, it would become V(1.2).
with_dependencies:
description:
- Defines whether to install plugin dependencies.
- - This option takes effect only if the I(version) is not defined.
+ - This option takes effect only if the O(version) is not defined.
type: bool
default: true
@@ -127,11 +127,11 @@ notes:
the plugin files on the disk. Only if the plugin is not installed yet and
no version is specified, the API installation is performed which requires
only the Web UI credentials.
- - It's necessary to notify the handler or call the I(service) module to
+ - It is necessary to notify the handler or call the M(ansible.builtin.service) module to
restart the Jenkins service after a new plugin was installed.
- Pinning works only if the plugin is installed and Jenkins service was
successfully restarted after the plugin installation.
- - It is not possible to run the module remotely by changing the I(url)
+ - It is not possible to run the module remotely by changing the O(url)
parameter to point to the Jenkins server. The module must be used on the
host where Jenkins runs as it needs direct access to the plugin files.
extends_documentation_fragment:
@@ -196,6 +196,29 @@ EXAMPLES = '''
url: http://localhost:8888
#
+# Example of how to authenticate with serverless deployment
+#
+- name: Update plugins on ECS Fargate Jenkins instance
+ community.general.jenkins_plugin:
+ # plugin name and version
+ name: ws-cleanup
+ version: '0.45'
+ # Jenkins home path mounted on ec2-helper VM (example)
+ jenkins_home: "/mnt/{{ jenkins_instance }}"
+ # matching the UID/GID to one in official Jenkins image
+ owner: 1000
+ group: 1000
+ # Jenkins instance URL and admin credentials
+ url: "https://{{ jenkins_instance }}.com/"
+ url_username: admin
+ url_password: p4ssw0rd
+ # make module work from EC2 which has local access
+ # to EFS mount as well as Jenkins URL
+ delegate_to: ec2-helper
+ vars:
+ jenkins_instance: foobar
+
+#
# Example of a Play which handles Jenkins restarts during the state changes
#
- name: Jenkins Master play
diff --git a/ansible_collections/community/general/plugins/modules/jenkins_script.py b/ansible_collections/community/general/plugins/modules/jenkins_script.py
index 7f83ebcdb..030c8e6fa 100644
--- a/ansible_collections/community/general/plugins/modules/jenkins_script.py
+++ b/ansible_collections/community/general/plugins/modules/jenkins_script.py
@@ -42,8 +42,8 @@ options:
default: http://localhost:8080
validate_certs:
description:
- - If set to C(false), the SSL certificates will not be validated.
- This should only set to C(false) used on personally controlled sites
+ - If set to V(false), the SSL certificates will not be validated.
+ This should only set to V(false) used on personally controlled sites
using self-signed certificates as it avoids verifying the source site.
type: bool
default: true
@@ -99,7 +99,7 @@ EXAMPLES = '''
user: admin
password: admin
url: https://localhost
- validate_certs: false
+ validate_certs: false # only do this when you trust the network!
'''
RETURN = '''
diff --git a/ansible_collections/community/general/plugins/modules/jira.py b/ansible_collections/community/general/plugins/modules/jira.py
index 85097c4b7..c36cf9937 100644
--- a/ansible_collections/community/general/plugins/modules/jira.py
+++ b/ansible_collections/community/general/plugins/modules/jira.py
@@ -44,25 +44,25 @@ options:
choices: [ attach, comment, create, edit, fetch, link, search, transition, update, worklog ]
description:
- The operation to perform.
- - C(worklog) was added in community.genereal 6.5.0.
+ - V(worklog) was added in community.general 6.5.0.
username:
type: str
description:
- The username to log-in with.
- - Must be used with I(password). Mutually exclusive with I(token).
+ - Must be used with O(password). Mutually exclusive with O(token).
password:
type: str
description:
- The password to log-in with.
- - Must be used with I(username). Mutually exclusive with I(token).
+ - Must be used with O(username). Mutually exclusive with O(token).
token:
type: str
description:
- The personal access token to log-in with.
- - Mutually exclusive with I(username) and I(password).
+ - Mutually exclusive with O(username) and O(password).
version_added: 4.2.0
project:
@@ -128,20 +128,20 @@ options:
type: str
required: false
description:
- - Only used when I(operation) is C(transition), and a bit of a misnomer, it actually refers to the transition name.
+ - Only used when O(operation) is V(transition), and a bit of a misnomer, it actually refers to the transition name.
assignee:
type: str
required: false
description:
- - Sets the the assignee when I(operation) is C(create), C(transition) or C(edit).
- - Recent versions of JIRA no longer accept a user name as a user identifier. In that case, use I(account_id) instead.
+ - Sets the the assignee when O(operation) is V(create), V(transition), or V(edit).
+ - Recent versions of JIRA no longer accept a user name as a user identifier. In that case, use O(account_id) instead.
- Note that JIRA may not allow changing field values on specific transitions or states.
account_id:
type: str
description:
- - Sets the account identifier for the assignee when I(operation) is C(create), C(transition) or C(edit).
+ - Sets the account identifier for the assignee when O(operation) is V(create), V(transition), or V(edit).
- Note that JIRA may not allow changing field values on specific transitions or states.
version_added: 2.5.0
@@ -183,8 +183,8 @@ options:
maxresults:
required: false
description:
- - Limit the result of I(operation=search). If no value is specified, the default jira limit will be used.
- - Used when I(operation=search) only, ignored otherwise.
+ - Limit the result of O(operation=search). If no value is specified, the default jira limit will be used.
+ - Used when O(operation=search) only, ignored otherwise.
type: int
version_added: '0.2.0'
@@ -198,7 +198,7 @@ options:
validate_certs:
required: false
description:
- - Require valid SSL certificates (set to C(false) if you'd like to use self-signed certificates)
+ - Require valid SSL certificates (set to V(false) if you would like to use self-signed certificates)
default: true
type: bool
@@ -212,12 +212,12 @@ options:
required: true
type: path
description:
- - The path to the file to upload (from the remote node) or, if I(content) is specified,
+ - The path to the file to upload (from the remote node) or, if O(attachment.content) is specified,
the filename to use for the attachment.
content:
type: str
description:
- - The Base64 encoded contents of the file to attach. If not specified, the contents of I(filename) will be
+ - The Base64 encoded contents of the file to attach. If not specified, the contents of O(attachment.filename) will be
used instead.
mimetype:
type: str
@@ -227,7 +227,7 @@ options:
notes:
- "Currently this only works with basic-auth, or tokens."
- - "To use with JIRA Cloud, pass the login e-mail as the I(username) and the API token as I(password)."
+ - "To use with JIRA Cloud, pass the login e-mail as the O(username) and the API token as O(password)."
author:
- "Steve Smith (@tarka)"
@@ -799,7 +799,7 @@ class JIRA(StateModuleHelper):
if msg:
self.module.fail_json(msg=', '.join(msg))
self.module.fail_json(msg=to_native(error))
- # Fallback print body, if it cant be decoded
+ # Fallback print body, if it can't be decoded
self.module.fail_json(msg=to_native(info['body']))
body = response.read()
diff --git a/ansible_collections/community/general/plugins/modules/kdeconfig.py b/ansible_collections/community/general/plugins/modules/kdeconfig.py
index 42a08dd64..4e8d39521 100644
--- a/ansible_collections/community/general/plugins/modules/kdeconfig.py
+++ b/ansible_collections/community/general/plugins/modules/kdeconfig.py
@@ -35,11 +35,11 @@ options:
suboptions:
group:
description:
- - The option's group. One between this and I(groups) is required.
+ - The option's group. One between this and O(values[].groups) is required.
type: str
groups:
description:
- - List of the option's groups. One between this and I(group) is required.
+ - List of the option's groups. One between this and O(values[].group) is required.
type: list
elements: str
key:
@@ -49,12 +49,12 @@ options:
required: true
value:
description:
- - The option's value. One between this and I(bool_value) is required.
+ - The option's value. One between this and O(values[].bool_value) is required.
type: str
bool_value:
description:
- Boolean value.
- - One between this and I(value) is required.
+ - One between this and O(values[].value) is required.
type: bool
required: true
backup:
diff --git a/ansible_collections/community/general/plugins/modules/kernel_blacklist.py b/ansible_collections/community/general/plugins/modules/kernel_blacklist.py
index 1b40999ca..b5bd90403 100644
--- a/ansible_collections/community/general/plugins/modules/kernel_blacklist.py
+++ b/ansible_collections/community/general/plugins/modules/kernel_blacklist.py
@@ -53,7 +53,6 @@ EXAMPLES = '''
import os
import re
-import tempfile
from ansible_collections.community.general.plugins.module_utils.module_helper import StateModuleHelper
@@ -106,16 +105,10 @@ class Blacklist(StateModuleHelper):
def __quit_module__(self):
if self.has_changed() and not self.module.check_mode:
- dummy, tmpfile = tempfile.mkstemp()
- try:
- os.remove(tmpfile)
- self.module.preserved_copy(self.vars.filename, tmpfile) # ensure right perms/ownership
- with open(tmpfile, 'w') as fd:
- fd.writelines(["{0}\n".format(x) for x in self.vars.lines])
- self.module.atomic_move(tmpfile, self.vars.filename)
- finally:
- if os.path.exists(tmpfile):
- os.remove(tmpfile)
+ bkp = self.module.backup_local(self.vars.filename)
+ with open(self.vars.filename, "w") as fd:
+ fd.writelines(["{0}\n".format(x) for x in self.vars.lines])
+ self.module.add_cleanup_file(bkp)
def main():
diff --git a/ansible_collections/community/general/plugins/modules/keycloak_authentication.py b/ansible_collections/community/general/plugins/modules/keycloak_authentication.py
index 6143d9d5c..bc2898d9b 100644
--- a/ansible_collections/community/general/plugins/modules/keycloak_authentication.py
+++ b/ansible_collections/community/general/plugins/modules/keycloak_authentication.py
@@ -43,6 +43,7 @@ options:
providerId:
description:
- C(providerId) for the new flow when not copied from an existing flow.
+ choices: [ "basic-flow", "client-flow" ]
type: str
copyFrom:
description:
@@ -97,7 +98,7 @@ options:
type: bool
default: false
description:
- - If C(true), allows to remove the authentication flow and recreate it.
+ - If V(true), allows to remove the authentication flow and recreate it.
extends_documentation_fragment:
- community.general.keycloak
@@ -109,77 +110,77 @@ author:
'''
EXAMPLES = '''
- - name: Create an authentication flow from first broker login and add an execution to it.
- community.general.keycloak_authentication:
- auth_keycloak_url: http://localhost:8080/auth
- auth_realm: master
- auth_username: admin
- auth_password: password
- realm: master
- alias: "Copy of first broker login"
- copyFrom: "first broker login"
- authenticationExecutions:
- - providerId: "test-execution1"
- requirement: "REQUIRED"
- authenticationConfig:
- alias: "test.execution1.property"
- config:
- test1.property: "value"
- - providerId: "test-execution2"
- requirement: "REQUIRED"
- authenticationConfig:
- alias: "test.execution2.property"
- config:
- test2.property: "value"
- state: present
-
- - name: Re-create the authentication flow
- community.general.keycloak_authentication:
- auth_keycloak_url: http://localhost:8080/auth
- auth_realm: master
- auth_username: admin
- auth_password: password
- realm: master
- alias: "Copy of first broker login"
- copyFrom: "first broker login"
- authenticationExecutions:
- - providerId: "test-provisioning"
- requirement: "REQUIRED"
- authenticationConfig:
- alias: "test.provisioning.property"
- config:
- test.provisioning.property: "value"
- state: present
- force: true
-
- - name: Create an authentication flow with subflow containing an execution.
- community.general.keycloak_authentication:
- auth_keycloak_url: http://localhost:8080/auth
- auth_realm: master
- auth_username: admin
- auth_password: password
- realm: master
- alias: "Copy of first broker login"
- copyFrom: "first broker login"
- authenticationExecutions:
- - providerId: "test-execution1"
- requirement: "REQUIRED"
- - displayName: "New Subflow"
- requirement: "REQUIRED"
- - providerId: "auth-cookie"
- requirement: "REQUIRED"
- flowAlias: "New Sublow"
- state: present
-
- - name: Remove authentication.
- community.general.keycloak_authentication:
- auth_keycloak_url: http://localhost:8080/auth
- auth_realm: master
- auth_username: admin
- auth_password: password
- realm: master
- alias: "Copy of first broker login"
- state: absent
+- name: Create an authentication flow from first broker login and add an execution to it.
+ community.general.keycloak_authentication:
+ auth_keycloak_url: http://localhost:8080/auth
+ auth_realm: master
+ auth_username: admin
+ auth_password: password
+ realm: master
+ alias: "Copy of first broker login"
+ copyFrom: "first broker login"
+ authenticationExecutions:
+ - providerId: "test-execution1"
+ requirement: "REQUIRED"
+ authenticationConfig:
+ alias: "test.execution1.property"
+ config:
+ test1.property: "value"
+ - providerId: "test-execution2"
+ requirement: "REQUIRED"
+ authenticationConfig:
+ alias: "test.execution2.property"
+ config:
+ test2.property: "value"
+ state: present
+
+- name: Re-create the authentication flow
+ community.general.keycloak_authentication:
+ auth_keycloak_url: http://localhost:8080/auth
+ auth_realm: master
+ auth_username: admin
+ auth_password: password
+ realm: master
+ alias: "Copy of first broker login"
+ copyFrom: "first broker login"
+ authenticationExecutions:
+ - providerId: "test-provisioning"
+ requirement: "REQUIRED"
+ authenticationConfig:
+ alias: "test.provisioning.property"
+ config:
+ test.provisioning.property: "value"
+ state: present
+ force: true
+
+- name: Create an authentication flow with subflow containing an execution.
+ community.general.keycloak_authentication:
+ auth_keycloak_url: http://localhost:8080/auth
+ auth_realm: master
+ auth_username: admin
+ auth_password: password
+ realm: master
+ alias: "Copy of first broker login"
+ copyFrom: "first broker login"
+ authenticationExecutions:
+ - providerId: "test-execution1"
+ requirement: "REQUIRED"
+ - displayName: "New Subflow"
+ requirement: "REQUIRED"
+ - providerId: "auth-cookie"
+ requirement: "REQUIRED"
+ flowAlias: "New Sublow"
+ state: present
+
+- name: Remove authentication.
+ community.general.keycloak_authentication:
+ auth_keycloak_url: http://localhost:8080/auth
+ auth_realm: master
+ auth_username: admin
+ auth_password: password
+ realm: master
+ alias: "Copy of first broker login"
+ state: absent
'''
RETURN = '''
@@ -279,6 +280,8 @@ def create_or_update_executions(kc, config, realm='master'):
# Compare the executions to see if it need changes
if not is_struct_included(new_exec, existing_executions[exec_index], exclude_key) or exec_index != new_exec_index:
exec_found = True
+ if new_exec['index'] is None:
+ new_exec_index = exec_index
before += str(existing_executions[exec_index]) + '\n'
id_to_update = existing_executions[exec_index]["id"]
# Remove exec from list in case 2 exec with same name
@@ -331,7 +334,7 @@ def main():
meta_args = dict(
realm=dict(type='str', required=True),
alias=dict(type='str', required=True),
- providerId=dict(type='str'),
+ providerId=dict(type='str', choices=["basic-flow", "client-flow"]),
description=dict(type='str'),
copyFrom=dict(type='str'),
authenticationExecutions=dict(type='list', elements='dict',
diff --git a/ansible_collections/community/general/plugins/modules/keycloak_authentication_required_actions.py b/ansible_collections/community/general/plugins/modules/keycloak_authentication_required_actions.py
new file mode 100644
index 000000000..5ffbd2033
--- /dev/null
+++ b/ansible_collections/community/general/plugins/modules/keycloak_authentication_required_actions.py
@@ -0,0 +1,457 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2017, Eike Frost <ei@kefro.st>
+# Copyright (c) 2021, Christophe Gilles <christophe.gilles54@gmail.com>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or
+# https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+DOCUMENTATION = '''
+---
+module: keycloak_authentication_required_actions
+
+short_description: Allows administration of Keycloak authentication required actions
+
+description:
+ - This module can register, update and delete required actions.
+ - It also filters out any duplicate required actions by their alias. The first occurrence is preserved.
+
+version_added: 7.1.0
+
+attributes:
+ check_mode:
+ support: full
+ diff_mode:
+ support: full
+
+options:
+ realm:
+ description:
+ - The name of the realm in which are the authentication required actions.
+ required: true
+ type: str
+ required_actions:
+ elements: dict
+ description:
+ - Authentication required action.
+ suboptions:
+ alias:
+ description:
+ - Unique name of the required action.
+ required: true
+ type: str
+ config:
+ description:
+ - Configuration for the required action.
+ type: dict
+ defaultAction:
+ description:
+ - Indicates, if any new user will have the required action assigned to it.
+ type: bool
+ enabled:
+ description:
+ - Indicates, if the required action is enabled or not.
+ type: bool
+ name:
+ description:
+ - Displayed name of the required action. Required for registration.
+ type: str
+ priority:
+ description:
+ - Priority of the required action.
+ type: int
+ providerId:
+ description:
+ - Provider ID of the required action. Required for registration.
+ type: str
+ type: list
+ state:
+ choices: [ "absent", "present" ]
+ description:
+ - Control if the realm authentication required actions are going to be registered/updated (V(present)) or deleted (V(absent)).
+ required: true
+ type: str
+
+extends_documentation_fragment:
+ - community.general.keycloak
+ - community.general.attributes
+
+author:
+ - Skrekulko (@Skrekulko)
+'''
+
+EXAMPLES = '''
+- name: Register a new required action.
+ community.general.keycloak_authentication_required_actions:
+ auth_client_id: "admin-cli"
+ auth_keycloak_url: "http://localhost:8080"
+ auth_password: "password"
+ auth_realm: "master"
+ auth_username: "admin"
+ realm: "master"
+ required_action:
+ - alias: "TERMS_AND_CONDITIONS"
+ name: "Terms and conditions"
+ providerId: "TERMS_AND_CONDITIONS"
+ enabled: true
+ state: "present"
+
+- name: Update the newly registered required action.
+ community.general.keycloak_authentication_required_actions:
+ auth_client_id: "admin-cli"
+ auth_keycloak_url: "http://localhost:8080"
+ auth_password: "password"
+ auth_realm: "master"
+ auth_username: "admin"
+ realm: "master"
+ required_action:
+ - alias: "TERMS_AND_CONDITIONS"
+ enabled: false
+ state: "present"
+
+- name: Delete the updated registered required action.
+ community.general.keycloak_authentication_required_actions:
+ auth_client_id: "admin-cli"
+ auth_keycloak_url: "http://localhost:8080"
+ auth_password: "password"
+ auth_realm: "master"
+ auth_username: "admin"
+ realm: "master"
+ required_action:
+ - alias: "TERMS_AND_CONDITIONS"
+ state: "absent"
+'''
+
+RETURN = '''
+msg:
+ description: Message as to what action was taken.
+ returned: always
+ type: str
+
+end_state:
+ description: Representation of the authentication required actions after module execution.
+ returned: on success
+ type: complex
+ contains:
+ alias:
+ description:
+ - Unique name of the required action.
+ sample: test-provider-id
+ type: str
+ config:
+ description:
+ - Configuration for the required action.
+ sample: {}
+ type: dict
+ defaultAction:
+ description:
+ - Indicates, if any new user will have the required action assigned to it.
+ sample: false
+ type: bool
+ enabled:
+ description:
+ - Indicates, if the required action is enabled or not.
+ sample: false
+ type: bool
+ name:
+ description:
+ - Displayed name of the required action. Required for registration.
+ sample: Test provider ID
+ type: str
+ priority:
+ description:
+ - Priority of the required action.
+ sample: 90
+ type: int
+ providerId:
+ description:
+ - Provider ID of the required action. Required for registration.
+ sample: test-provider-id
+ type: str
+
+'''
+
+from ansible_collections.community.general.plugins.module_utils.identity.keycloak.keycloak import KeycloakAPI, \
+ keycloak_argument_spec, get_token, KeycloakError
+from ansible.module_utils.basic import AnsibleModule
+
+
+def sanitize_required_actions(objects):
+ for obj in objects:
+ alias = obj['alias']
+ name = obj['name']
+ provider_id = obj['providerId']
+
+ if not name:
+ obj['name'] = alias
+
+ if provider_id != alias:
+ obj['providerId'] = alias
+
+ return objects
+
+
+def filter_duplicates(objects):
+ filtered_objects = {}
+
+ for obj in objects:
+ alias = obj["alias"]
+
+ if alias not in filtered_objects:
+ filtered_objects[alias] = obj
+
+ return list(filtered_objects.values())
+
+
+def main():
+ """
+ Module execution
+
+ :return:
+ """
+ argument_spec = keycloak_argument_spec()
+
+ meta_args = dict(
+ realm=dict(type='str', required=True),
+ required_actions=dict(
+ type='list',
+ elements='dict',
+ options=dict(
+ alias=dict(type='str', required=True),
+ config=dict(type='dict'),
+ defaultAction=dict(type='bool'),
+ enabled=dict(type='bool'),
+ name=dict(type='str'),
+ priority=dict(type='int'),
+ providerId=dict(type='str')
+ )
+ ),
+ state=dict(type='str', choices=['present', 'absent'], required=True)
+ )
+
+ argument_spec.update(meta_args)
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_one_of=([['token', 'auth_realm', 'auth_username', 'auth_password']]),
+ required_together=([['auth_realm', 'auth_username', 'auth_password']])
+ )
+
+ result = dict(changed=False, msg='', end_state={}, diff=dict(before={}, after={}))
+
+ # Obtain access token, initialize API
+ try:
+ connection_header = get_token(module.params)
+ except KeycloakError as e:
+ module.fail_json(msg=str(e))
+
+ kc = KeycloakAPI(module, connection_header)
+
+ # Convenience variables
+ realm = module.params.get('realm')
+ desired_required_actions = module.params.get('required_actions')
+ state = module.params.get('state')
+
+ # Sanitize required actions
+ desired_required_actions = sanitize_required_actions(desired_required_actions)
+
+ # Filter out duplicate required actions
+ desired_required_actions = filter_duplicates(desired_required_actions)
+
+ # Get required actions
+ before_required_actions = kc.get_required_actions(realm=realm)
+
+ if state == 'present':
+ # Initialize empty lists to hold the required actions that need to be
+ # registered, updated, and original ones of the updated one
+ register_required_actions = []
+ before_updated_required_actions = []
+ updated_required_actions = []
+
+ # Loop through the desired required actions and check if they exist in the before required actions
+ for desired_required_action in desired_required_actions:
+ found = False
+
+ # Loop through the before required actions and check if the aliases match
+ for before_required_action in before_required_actions:
+ if desired_required_action['alias'] == before_required_action['alias']:
+ update_required = False
+
+ # Fill in the parameters
+ for k, v in before_required_action.items():
+ if k not in desired_required_action or desired_required_action[k] is None:
+ desired_required_action[k] = v
+
+ # Loop through the keys of the desired and before required actions
+ # and check if there are any differences between them
+ for key in desired_required_action.keys():
+ if key in before_required_action and desired_required_action[key] != before_required_action[key]:
+ update_required = True
+ break
+
+ # If there are differences, add the before and desired required actions
+ # to their respective lists for updating
+ if update_required:
+ before_updated_required_actions.append(before_required_action)
+ updated_required_actions.append(desired_required_action)
+ found = True
+ break
+ # If the desired required action is not found in the before required actions,
+ # add it to the list of required actions to register
+ if not found:
+ # Check if name is provided
+ if 'name' not in desired_required_action or desired_required_action['name'] is None:
+ module.fail_json(
+ msg='Unable to register required action %s in realm %s: name not included'
+ % (desired_required_action['alias'], realm)
+ )
+
+ # Check if provider ID is provided
+ if 'providerId' not in desired_required_action or desired_required_action['providerId'] is None:
+ module.fail_json(
+ msg='Unable to register required action %s in realm %s: providerId not included'
+ % (desired_required_action['alias'], realm)
+ )
+
+ register_required_actions.append(desired_required_action)
+
+ # Handle diff
+ if module._diff:
+ diff_required_actions = updated_required_actions.copy()
+ diff_required_actions.extend(register_required_actions)
+
+ result['diff'] = dict(
+ before=before_updated_required_actions,
+ after=diff_required_actions
+ )
+
+ # Handle changed
+ if register_required_actions or updated_required_actions:
+ result['changed'] = True
+
+ # Handle check mode
+ if module.check_mode:
+ if register_required_actions or updated_required_actions:
+ result['change'] = True
+ result['msg'] = 'Required actions would be registered/updated'
+ else:
+ result['change'] = False
+ result['msg'] = 'Required actions would not be registered/updated'
+
+ module.exit_json(**result)
+
+ # Register required actions
+ if register_required_actions:
+ for register_required_action in register_required_actions:
+ kc.register_required_action(realm=realm, rep=register_required_action)
+ kc.update_required_action(alias=register_required_action['alias'], realm=realm, rep=register_required_action)
+
+ # Update required actions
+ if updated_required_actions:
+ for updated_required_action in updated_required_actions:
+ kc.update_required_action(alias=updated_required_action['alias'], realm=realm, rep=updated_required_action)
+
+ # Initialize the final list of required actions
+ final_required_actions = []
+
+ # Iterate over the before_required_actions
+ for before_required_action in before_required_actions:
+ # Check if there is an updated_required_action with the same alias
+ updated_required_action_found = False
+
+ for updated_required_action in updated_required_actions:
+ if updated_required_action['alias'] == before_required_action['alias']:
+ # Merge the two dictionaries, favoring the values from updated_required_action
+ merged_dict = {}
+ for key in before_required_action.keys():
+ if key in updated_required_action:
+ merged_dict[key] = updated_required_action[key]
+ else:
+ merged_dict[key] = before_required_action[key]
+
+ for key in updated_required_action.keys():
+ if key not in before_required_action:
+ merged_dict[key] = updated_required_action[key]
+
+ # Add the merged dictionary to the final list of required actions
+ final_required_actions.append(merged_dict)
+
+ # Mark the updated_required_action as found
+ updated_required_action_found = True
+
+ # Stop looking for updated_required_action
+ break
+
+ # If no matching updated_required_action was found, add the before_required_action to the final list of required actions
+ if not updated_required_action_found:
+ final_required_actions.append(before_required_action)
+
+ # Append any remaining updated_required_actions that were not merged
+ for updated_required_action in updated_required_actions:
+ if not any(updated_required_action['alias'] == action['alias'] for action in final_required_actions):
+ final_required_actions.append(updated_required_action)
+
+ # Append newly registered required actions
+ final_required_actions.extend(register_required_actions)
+
+ # Handle message and end state
+ result['msg'] = 'Required actions registered/updated'
+ result['end_state'] = final_required_actions
+ else:
+ # Filter out the deleted required actions
+ final_required_actions = []
+ delete_required_actions = []
+
+ for before_required_action in before_required_actions:
+ delete_action = False
+
+ for desired_required_action in desired_required_actions:
+ if before_required_action['alias'] == desired_required_action['alias']:
+ delete_action = True
+ break
+
+ if not delete_action:
+ final_required_actions.append(before_required_action)
+ else:
+ delete_required_actions.append(before_required_action)
+
+ # Handle diff
+ if module._diff:
+ result['diff'] = dict(
+ before=before_required_actions,
+ after=final_required_actions
+ )
+
+ # Handle changed
+ if delete_required_actions:
+ result['changed'] = True
+
+ # Handle check mode
+ if module.check_mode:
+ if final_required_actions:
+ result['change'] = True
+ result['msg'] = 'Required actions would be deleted'
+ else:
+ result['change'] = False
+ result['msg'] = 'Required actions would not be deleted'
+
+ module.exit_json(**result)
+
+ # Delete required actions
+ if delete_required_actions:
+ for delete_required_action in delete_required_actions:
+ kc.delete_required_action(alias=delete_required_action['alias'], realm=realm)
+
+ # Handle message and end state
+ result['msg'] = 'Required actions deleted'
+ result['end_state'] = final_required_actions
+
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/general/plugins/modules/keycloak_authz_authorization_scope.py b/ansible_collections/community/general/plugins/modules/keycloak_authz_authorization_scope.py
index c451d3751..5eef9ac76 100644
--- a/ansible_collections/community/general/plugins/modules/keycloak_authz_authorization_scope.py
+++ b/ansible_collections/community/general/plugins/modules/keycloak_authz_authorization_scope.py
@@ -40,8 +40,8 @@ options:
state:
description:
- State of the authorization scope.
- - On C(present), the authorization scope will be created (or updated if it exists already).
- - On C(absent), the authorization scope will be removed if it exists.
+ - On V(present), the authorization scope will be created (or updated if it exists already).
+ - On V(absent), the authorization scope will be removed if it exists.
choices: ['present', 'absent']
default: 'present'
type: str
@@ -108,22 +108,22 @@ end_state:
id:
description: ID of the authorization scope.
type: str
- returned: when I(state=present)
+ returned: when O(state=present)
sample: a6ab1cf2-1001-40ec-9f39-48f23b6a0a41
name:
description: Name of the authorization scope.
type: str
- returned: when I(state=present)
+ returned: when O(state=present)
sample: file:delete
display_name:
description: Display name of the authorization scope.
type: str
- returned: when I(state=present)
+ returned: when O(state=present)
sample: File delete
icon_uri:
description: Icon URI for the authorization scope.
type: str
- returned: when I(state=present)
+ returned: when O(state=present)
sample: http://localhost/icon.png
'''
diff --git a/ansible_collections/community/general/plugins/modules/keycloak_authz_custom_policy.py b/ansible_collections/community/general/plugins/modules/keycloak_authz_custom_policy.py
new file mode 100644
index 000000000..8363c252e
--- /dev/null
+++ b/ansible_collections/community/general/plugins/modules/keycloak_authz_custom_policy.py
@@ -0,0 +1,211 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2017, Eike Frost <ei@kefro.st>
+# Copyright (c) 2021, Christophe Gilles <christophe.gilles54@gmail.com>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or
+# https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+DOCUMENTATION = '''
+---
+module: keycloak_authz_custom_policy
+
+short_description: Allows administration of Keycloak client custom Javascript policies via Keycloak API
+
+version_added: 7.5.0
+
+description:
+ - This module allows the administration of Keycloak client custom Javascript via the Keycloak REST
+ API. Custom Javascript policies are only available if a client has Authorization enabled and if
+ they have been deployed to the Keycloak server as JAR files.
+
+ - This module requires access to the REST API via OpenID Connect; the user connecting and the realm
+ being used must have the requisite access rights. In a default Keycloak installation, admin-cli
+ and an admin user would work, as would a separate realm definition with the scope tailored
+ to your needs and a user having the expected roles.
+
+ - The names of module options are snake_cased versions of the camelCase options used by Keycloak.
+ The Authorization Services paths and payloads have not officially been documented by the Keycloak project.
+ U(https://www.puppeteers.net/blog/keycloak-authorization-services-rest-api-paths-and-payload/)
+
+attributes:
+ check_mode:
+ support: full
+ diff_mode:
+ support: none
+
+options:
+ state:
+ description:
+ - State of the custom policy.
+ - On V(present), the custom policy will be created (or updated if it exists already).
+ - On V(absent), the custom policy will be removed if it exists.
+ choices: ['present', 'absent']
+ default: 'present'
+ type: str
+ name:
+ description:
+ - Name of the custom policy to create.
+ type: str
+ required: true
+ policy_type:
+ description:
+ - The type of the policy. This must match the name of the custom policy deployed to the server.
+ - Multiple policies pointing to the same policy type can be created, but their names have to differ.
+ type: str
+ required: true
+ client_id:
+ description:
+ - The V(clientId) of the Keycloak client that should have the custom policy attached to it.
+ - This is usually a human-readable name of the Keycloak client.
+ type: str
+ required: true
+ realm:
+ description:
+ - The name of the Keycloak realm the Keycloak client is in.
+ type: str
+ required: true
+
+extends_documentation_fragment:
+ - community.general.keycloak
+ - community.general.attributes
+
+author:
+ - Samuli Seppänen (@mattock)
+'''
+
+EXAMPLES = '''
+- name: Manage Keycloak custom authorization policy
+ community.general.keycloak_authz_custom_policy:
+ name: OnlyOwner
+ state: present
+ policy_type: script-policy.js
+ client_id: myclient
+ realm: myrealm
+ auth_keycloak_url: http://localhost:8080/auth
+ auth_username: keycloak
+ auth_password: keycloak
+ auth_realm: master
+'''
+
+RETURN = '''
+msg:
+ description: Message as to what action was taken.
+ returned: always
+ type: str
+
+end_state:
+ description: Representation of the custom policy after module execution.
+ returned: on success
+ type: dict
+ contains:
+ name:
+ description: Name of the custom policy.
+ type: str
+ returned: when I(state=present)
+ sample: file:delete
+ policy_type:
+ description: Type of custom policy.
+ type: str
+ returned: when I(state=present)
+ sample: File delete
+
+'''
+
+from ansible_collections.community.general.plugins.module_utils.identity.keycloak.keycloak import KeycloakAPI, \
+ keycloak_argument_spec, get_token, KeycloakError
+from ansible.module_utils.basic import AnsibleModule
+
+
+def main():
+ """
+ Module execution
+
+ :return:
+ """
+ argument_spec = keycloak_argument_spec()
+
+ meta_args = dict(
+ state=dict(type='str', default='present',
+ choices=['present', 'absent']),
+ name=dict(type='str', required=True),
+ policy_type=dict(type='str', required=True),
+ client_id=dict(type='str', required=True),
+ realm=dict(type='str', required=True)
+ )
+
+ argument_spec.update(meta_args)
+
+ module = AnsibleModule(argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_one_of=(
+ [['token', 'auth_realm', 'auth_username', 'auth_password']]),
+ required_together=([['auth_realm', 'auth_username', 'auth_password']]))
+
+ result = dict(changed=False, msg='', end_state={})
+
+ # Obtain access token, initialize API
+ try:
+ connection_header = get_token(module.params)
+ except KeycloakError as e:
+ module.fail_json(msg=str(e))
+
+ kc = KeycloakAPI(module, connection_header)
+
+ # Convenience variables
+ state = module.params.get('state')
+ name = module.params.get('name')
+ policy_type = module.params.get('policy_type')
+ client_id = module.params.get('client_id')
+ realm = module.params.get('realm')
+
+ cid = kc.get_client_id(client_id, realm=realm)
+ if not cid:
+ module.fail_json(msg='Invalid client %s for realm %s' %
+ (client_id, realm))
+
+ before_authz_custom_policy = kc.get_authz_policy_by_name(
+ name=name, client_id=cid, realm=realm)
+
+ desired_authz_custom_policy = {}
+ desired_authz_custom_policy['name'] = name
+ desired_authz_custom_policy['type'] = policy_type
+
+ # Modifying existing custom policies is not possible
+ if before_authz_custom_policy and state == 'present':
+ result['msg'] = "Custom policy %s already exists" % (name)
+ result['changed'] = False
+ result['end_state'] = desired_authz_custom_policy
+ elif not before_authz_custom_policy and state == 'present':
+ if module.check_mode:
+ result['msg'] = "Would create custom policy %s" % (name)
+ else:
+ kc.create_authz_custom_policy(
+ payload=desired_authz_custom_policy, policy_type=policy_type, client_id=cid, realm=realm)
+ result['msg'] = "Custom policy %s created" % (name)
+
+ result['changed'] = True
+ result['end_state'] = desired_authz_custom_policy
+ elif before_authz_custom_policy and state == 'absent':
+ if module.check_mode:
+ result['msg'] = "Would remove custom policy %s" % (name)
+ else:
+ kc.remove_authz_custom_policy(
+ policy_id=before_authz_custom_policy['id'], client_id=cid, realm=realm)
+ result['msg'] = "Custom policy %s removed" % (name)
+
+ result['changed'] = True
+ result['end_state'] = {}
+ elif not before_authz_custom_policy and state == 'absent':
+ result['msg'] = "Custom policy %s does not exist" % (name)
+ result['changed'] = False
+ result['end_state'] = {}
+
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/general/plugins/modules/keycloak_authz_permission.py b/ansible_collections/community/general/plugins/modules/keycloak_authz_permission.py
new file mode 100644
index 000000000..ef81fb8c3
--- /dev/null
+++ b/ansible_collections/community/general/plugins/modules/keycloak_authz_permission.py
@@ -0,0 +1,433 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2017, Eike Frost <ei@kefro.st>
+# Copyright (c) 2021, Christophe Gilles <christophe.gilles54@gmail.com>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or
+# https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+DOCUMENTATION = '''
+---
+module: keycloak_authz_permission
+
+version_added: 7.2.0
+
+short_description: Allows administration of Keycloak client authorization permissions via Keycloak API
+
+description:
+ - This module allows the administration of Keycloak client authorization permissions via the Keycloak REST
+ API. Authorization permissions are only available if a client has Authorization enabled.
+
+ - There are some peculiarities in JSON paths and payloads for authorization permissions. In particular
+ POST and PUT operations are targeted at permission endpoints, whereas GET requests go to policies
+ endpoint. To make matters more interesting the JSON responses from GET requests return data in a
+ different format than what is expected for POST and PUT. The end result is that it is not possible to
+ detect changes to things like policies, scopes or resources - at least not without a large number of
+ additional API calls. Therefore this module always updates authorization permissions instead of
+ attempting to determine if changes are truly needed.
+
+ - This module requires access to the REST API via OpenID Connect; the user connecting and the realm
+ being used must have the requisite access rights. In a default Keycloak installation, admin-cli
+ and an admin user would work, as would a separate realm definition with the scope tailored
+ to your needs and a user having the expected roles.
+
+ - The names of module options are snake_cased versions of the camelCase options used by Keycloak.
+ The Authorization Services paths and payloads have not officially been documented by the Keycloak project.
+ U(https://www.puppeteers.net/blog/keycloak-authorization-services-rest-api-paths-and-payload/)
+
+attributes:
+ check_mode:
+ support: full
+ diff_mode:
+ support: none
+
+options:
+ state:
+ description:
+ - State of the authorization permission.
+ - On V(present), the authorization permission will be created (or updated if it exists already).
+ - On V(absent), the authorization permission will be removed if it exists.
+ choices: ['present', 'absent']
+ default: 'present'
+ type: str
+ name:
+ description:
+ - Name of the authorization permission to create.
+ type: str
+ required: true
+ description:
+ description:
+ - The description of the authorization permission.
+ type: str
+ required: false
+ permission_type:
+ description:
+ - The type of authorization permission.
+ - On V(scope) create a scope-based permission.
+ - On V(resource) create a resource-based permission.
+ type: str
+ required: true
+ choices:
+ - resource
+ - scope
+ decision_strategy:
+ description:
+ - The decision strategy to use with this permission.
+ type: str
+ default: UNANIMOUS
+ required: false
+ choices:
+ - UNANIMOUS
+ - AFFIRMATIVE
+ - CONSENSUS
+ resources:
+ description:
+ - Resource names to attach to this permission.
+ - Scope-based permissions can only include one resource.
+ - Resource-based permissions can include multiple resources.
+ type: list
+ elements: str
+ default: []
+ required: false
+ scopes:
+ description:
+ - Scope names to attach to this permission.
+ - Resource-based permissions cannot have scopes attached to them.
+ type: list
+ elements: str
+ default: []
+ required: false
+ policies:
+ description:
+ - Policy names to attach to this permission.
+ type: list
+ elements: str
+ default: []
+ required: false
+ client_id:
+ description:
+ - The clientId of the keycloak client that should have the authorization scope.
+ - This is usually a human-readable name of the Keycloak client.
+ type: str
+ required: true
+ realm:
+ description:
+ - The name of the Keycloak realm the Keycloak client is in.
+ type: str
+ required: true
+
+extends_documentation_fragment:
+ - community.general.keycloak
+ - community.general.attributes
+
+author:
+ - Samuli Seppänen (@mattock)
+'''
+
+EXAMPLES = '''
+- name: Manage scope-based Keycloak authorization permission
+ community.general.keycloak_authz_permission:
+ name: ScopePermission
+ state: present
+ description: Scope permission
+ permission_type: scope
+ scopes:
+ - file:delete
+ policies:
+ - Default Policy
+ client_id: myclient
+ realm: myrealm
+ auth_keycloak_url: http://localhost:8080/auth
+ auth_username: keycloak
+ auth_password: keycloak
+ auth_realm: master
+
+- name: Manage resource-based Keycloak authorization permission
+ community.general.keycloak_authz_permission:
+ name: ResourcePermission
+ state: present
+ description: Resource permission
+ permission_type: resource
+ resources:
+ - Default Resource
+ policies:
+ - Default Policy
+ client_id: myclient
+ realm: myrealm
+ auth_keycloak_url: http://localhost:8080/auth
+ auth_username: keycloak
+ auth_password: keycloak
+ auth_realm: master
+'''
+
+RETURN = '''
+msg:
+ description: Message as to what action was taken.
+ returned: always
+ type: str
+
+end_state:
+ description: Representation of the authorization permission after module execution.
+ returned: on success
+ type: complex
+ contains:
+ id:
+ description: ID of the authorization permission.
+ type: str
+ returned: when O(state=present)
+ sample: 9da05cd2-b273-4354-bbd8-0c133918a454
+ name:
+ description: Name of the authorization permission.
+ type: str
+ returned: when O(state=present)
+ sample: ResourcePermission
+ description:
+ description: Description of the authorization permission.
+ type: str
+ returned: when O(state=present)
+ sample: Resource Permission
+ type:
+ description: Type of the authorization permission.
+ type: str
+ returned: when O(state=present)
+ sample: resource
+ decisionStrategy:
+ description: The decision strategy to use.
+ type: str
+ returned: when O(state=present)
+ sample: UNANIMOUS
+ logic:
+ description: The logic used for the permission (part of the payload, but has a fixed value).
+ type: str
+ returned: when O(state=present)
+ sample: POSITIVE
+ resources:
+ description: IDs of resources attached to this permission.
+ type: list
+ returned: when O(state=present)
+ sample:
+ - 49e052ff-100d-4b79-a9dd-52669ed3c11d
+ scopes:
+ description: IDs of scopes attached to this permission.
+ type: list
+ returned: when O(state=present)
+ sample:
+ - 9da05cd2-b273-4354-bbd8-0c133918a454
+ policies:
+ description: IDs of policies attached to this permission.
+ type: list
+ returned: when O(state=present)
+ sample:
+ - 9da05cd2-b273-4354-bbd8-0c133918a454
+'''
+
+from ansible_collections.community.general.plugins.module_utils.identity.keycloak.keycloak import KeycloakAPI, \
+ keycloak_argument_spec, get_token, KeycloakError
+from ansible.module_utils.basic import AnsibleModule
+
+
+def main():
+ """
+ Module execution
+
+ :return:
+ """
+ argument_spec = keycloak_argument_spec()
+
+ meta_args = dict(
+ state=dict(type='str', default='present',
+ choices=['present', 'absent']),
+ name=dict(type='str', required=True),
+ description=dict(type='str', required=False),
+ permission_type=dict(type='str', choices=['scope', 'resource'], required=True),
+ decision_strategy=dict(type='str', default='UNANIMOUS',
+ choices=['UNANIMOUS', 'AFFIRMATIVE', 'CONSENSUS']),
+ resources=dict(type='list', elements='str', default=[], required=False),
+ scopes=dict(type='list', elements='str', default=[], required=False),
+ policies=dict(type='list', elements='str', default=[], required=False),
+ client_id=dict(type='str', required=True),
+ realm=dict(type='str', required=True)
+ )
+
+ argument_spec.update(meta_args)
+
+ module = AnsibleModule(argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_one_of=(
+ [['token', 'auth_realm', 'auth_username', 'auth_password']]),
+ required_together=([['auth_realm', 'auth_username', 'auth_password']]))
+
+ # Convenience variables
+ state = module.params.get('state')
+ name = module.params.get('name')
+ description = module.params.get('description')
+ permission_type = module.params.get('permission_type')
+ decision_strategy = module.params.get('decision_strategy')
+ realm = module.params.get('realm')
+ client_id = module.params.get('client_id')
+ realm = module.params.get('realm')
+ resources = module.params.get('resources')
+ scopes = module.params.get('scopes')
+ policies = module.params.get('policies')
+
+ if permission_type == 'scope' and state == 'present':
+ if scopes == []:
+ module.fail_json(msg='Scopes need to defined when permission type is set to scope!')
+ if len(resources) > 1:
+ module.fail_json(msg='Only one resource can be defined for a scope permission!')
+
+ if permission_type == 'resource' and state == 'present':
+ if resources == []:
+ module.fail_json(msg='A resource need to defined when permission type is set to resource!')
+ if scopes != []:
+ module.fail_json(msg='Scopes cannot be defined when permission type is set to resource!')
+
+ result = dict(changed=False, msg='', end_state={})
+
+ # Obtain access token, initialize API
+ try:
+ connection_header = get_token(module.params)
+ except KeycloakError as e:
+ module.fail_json(msg=str(e))
+
+ kc = KeycloakAPI(module, connection_header)
+
+ # Get id of the client based on client_id
+ cid = kc.get_client_id(client_id, realm=realm)
+ if not cid:
+ module.fail_json(msg='Invalid client %s for realm %s' %
+ (client_id, realm))
+
+ # Get current state of the permission using its name as the search
+ # filter. This returns False if it is not found.
+ permission = kc.get_authz_permission_by_name(
+ name=name, client_id=cid, realm=realm)
+
+ # Generate a JSON payload for Keycloak Admin API. This is needed for
+ # "create" and "update" operations.
+ payload = {}
+ payload['name'] = name
+ payload['description'] = description
+ payload['type'] = permission_type
+ payload['decisionStrategy'] = decision_strategy
+ payload['logic'] = 'POSITIVE'
+ payload['scopes'] = []
+ payload['resources'] = []
+ payload['policies'] = []
+
+ if permission_type == 'scope':
+ # Add the resource id, if any, to the payload. While the data type is a
+ # list, it is only possible to have one entry in it based on what Keycloak
+ # Admin Console does.
+ r = False
+ resource_scopes = []
+
+ if resources:
+ r = kc.get_authz_resource_by_name(resources[0], cid, realm)
+ if not r:
+ module.fail_json(msg='Unable to find authorization resource with name %s for client %s in realm %s' % (resources[0], cid, realm))
+ else:
+ payload['resources'].append(r['_id'])
+
+ for rs in r['scopes']:
+ resource_scopes.append(rs['id'])
+
+ # Generate a list of scope ids based on scope names. Fail if the
+ # defined resource does not include all those scopes.
+ for scope in scopes:
+ s = kc.get_authz_authorization_scope_by_name(scope, cid, realm)
+ if r and not s['id'] in resource_scopes:
+ module.fail_json(msg='Resource %s does not include scope %s for client %s in realm %s' % (resources[0], scope, client_id, realm))
+ else:
+ payload['scopes'].append(s['id'])
+
+ elif permission_type == 'resource':
+ if resources:
+ for resource in resources:
+ r = kc.get_authz_resource_by_name(resource, cid, realm)
+ if not r:
+ module.fail_json(msg='Unable to find authorization resource with name %s for client %s in realm %s' % (resource, cid, realm))
+ else:
+ payload['resources'].append(r['_id'])
+
+ # Add policy ids, if any, to the payload.
+ if policies:
+ for policy in policies:
+ p = kc.get_authz_policy_by_name(policy, cid, realm)
+
+ if p:
+ payload['policies'].append(p['id'])
+ else:
+ module.fail_json(msg='Unable to find authorization policy with name %s for client %s in realm %s' % (policy, client_id, realm))
+
+ # Add "id" to payload for update operations
+ if permission:
+ payload['id'] = permission['id']
+
+ # Handle the special case where the user attempts to change an already
+ # existing permission's type - something that can't be done without a
+ # full delete -> (re)create cycle.
+ if permission['type'] != payload['type']:
+ module.fail_json(msg='Modifying the type of permission (scope/resource) is not supported: \
+ permission %s of client %s in realm %s unchanged' % (permission['id'], cid, realm))
+
+ # Updating an authorization permission is tricky for several reasons.
+ # Firstly, the current permission is retrieved using a _policy_ endpoint,
+ # not from a permission endpoint. Also, the data that is returned is in a
+ # different format than what is expected by the payload. So, comparing the
+ # current state attribute by attribute to the payload is not possible. For
+ # example the data contains a JSON object "config" which may contain the
+ # authorization type, but which is no required in the payload. Moreover,
+ # information about resources, scopes and policies is _not_ present in the
+ # data. So, there is no way to determine if any of those fields have
+ # changed. Therefore the best options we have are
+ #
+ # a) Always apply the payload without checking the current state
+ # b) Refuse to make any changes to any settings (only support create and delete)
+ #
+ # The approach taken here is a).
+ #
+ if permission and state == 'present':
+ if module.check_mode:
+ result['msg'] = 'Notice: unable to check current resources, scopes and policies for permission. \
+ Would apply desired state without checking the current state.'
+ else:
+ kc.update_authz_permission(payload=payload, permission_type=permission_type, id=permission['id'], client_id=cid, realm=realm)
+ result['msg'] = 'Notice: unable to check current resources, scopes and policies for permission. \
+ Applying desired state without checking the current state.'
+
+ # Assume that something changed, although we don't know if that is the case.
+ result['changed'] = True
+ result['end_state'] = payload
+ elif not permission and state == 'present':
+ if module.check_mode:
+ result['msg'] = 'Would create permission'
+ else:
+ kc.create_authz_permission(payload=payload, permission_type=permission_type, client_id=cid, realm=realm)
+ result['msg'] = 'Permission created'
+
+ result['changed'] = True
+ result['end_state'] = payload
+ elif permission and state == 'absent':
+ if module.check_mode:
+ result['msg'] = 'Would remove permission'
+ else:
+ kc.remove_authz_permission(id=permission['id'], client_id=cid, realm=realm)
+ result['msg'] = 'Permission removed'
+
+ result['changed'] = True
+
+ elif not permission and state == 'absent':
+ result['changed'] = False
+ else:
+ module.fail_json(msg='Unable to determine what to do with permission %s of client %s in realm %s' % (
+ name, client_id, realm))
+
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/general/plugins/modules/keycloak_authz_permission_info.py b/ansible_collections/community/general/plugins/modules/keycloak_authz_permission_info.py
new file mode 100644
index 000000000..8b4e96b41
--- /dev/null
+++ b/ansible_collections/community/general/plugins/modules/keycloak_authz_permission_info.py
@@ -0,0 +1,173 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2017, Eike Frost <ei@kefro.st>
+# Copyright (c) 2021, Christophe Gilles <christophe.gilles54@gmail.com>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or
+# https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+DOCUMENTATION = '''
+---
+module: keycloak_authz_permission_info
+
+version_added: 7.2.0
+
+short_description: Query Keycloak client authorization permissions information
+
+description:
+ - This module allows querying information about Keycloak client authorization permissions from the
+ resources endpoint via the Keycloak REST API. Authorization permissions are only available if a
+ client has Authorization enabled.
+
+ - This module requires access to the REST API via OpenID Connect; the user connecting and the realm
+ being used must have the requisite access rights. In a default Keycloak installation, admin-cli
+ and an admin user would work, as would a separate realm definition with the scope tailored
+ to your needs and a user having the expected roles.
+
+ - The names of module options are snake_cased versions of the camelCase options used by Keycloak.
+ The Authorization Services paths and payloads have not officially been documented by the Keycloak project.
+ U(https://www.puppeteers.net/blog/keycloak-authorization-services-rest-api-paths-and-payload/)
+
+options:
+ name:
+ description:
+ - Name of the authorization permission to create.
+ type: str
+ required: true
+ client_id:
+ description:
+ - The clientId of the keycloak client that should have the authorization scope.
+ - This is usually a human-readable name of the Keycloak client.
+ type: str
+ required: true
+ realm:
+ description:
+ - The name of the Keycloak realm the Keycloak client is in.
+ type: str
+ required: true
+
+extends_documentation_fragment:
+ - community.general.keycloak
+ - community.general.attributes
+ - community.general.attributes.info_module
+
+author:
+ - Samuli Seppänen (@mattock)
+'''
+
+EXAMPLES = '''
+- name: Query Keycloak authorization permission
+ community.general.keycloak_authz_permission_info:
+ name: ScopePermission
+ client_id: myclient
+ realm: myrealm
+ auth_keycloak_url: http://localhost:8080/auth
+ auth_username: keycloak
+ auth_password: keycloak
+ auth_realm: master
+'''
+
+RETURN = '''
+msg:
+ description: Message as to what action was taken.
+ returned: always
+ type: str
+
+queried_state:
+ description: State of the resource (a policy) as seen by Keycloak.
+ returned: on success
+ type: complex
+ contains:
+ id:
+ description: ID of the authorization permission.
+ type: str
+ sample: 9da05cd2-b273-4354-bbd8-0c133918a454
+ name:
+ description: Name of the authorization permission.
+ type: str
+ sample: ResourcePermission
+ description:
+ description: Description of the authorization permission.
+ type: str
+ sample: Resource Permission
+ type:
+ description: Type of the authorization permission.
+ type: str
+ sample: resource
+ decisionStrategy:
+ description: The decision strategy.
+ type: str
+ sample: UNANIMOUS
+ logic:
+ description: The logic used for the permission (part of the payload, but has a fixed value).
+ type: str
+ sample: POSITIVE
+ config:
+ description: Configuration of the permission (empty in all observed cases).
+ type: dict
+ sample: {}
+'''
+
+from ansible_collections.community.general.plugins.module_utils.identity.keycloak.keycloak import KeycloakAPI, \
+ keycloak_argument_spec, get_token, KeycloakError
+from ansible.module_utils.basic import AnsibleModule
+
+
+def main():
+ """
+ Module execution
+
+ :return:
+ """
+ argument_spec = keycloak_argument_spec()
+
+ meta_args = dict(
+ name=dict(type='str', required=True),
+ client_id=dict(type='str', required=True),
+ realm=dict(type='str', required=True)
+ )
+
+ argument_spec.update(meta_args)
+
+ module = AnsibleModule(argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_one_of=(
+ [['token', 'auth_realm', 'auth_username', 'auth_password']]),
+ required_together=([['auth_realm', 'auth_username', 'auth_password']]))
+
+ # Convenience variables
+ name = module.params.get('name')
+ client_id = module.params.get('client_id')
+ realm = module.params.get('realm')
+
+ result = dict(changed=False, msg='', queried_state={})
+
+ # Obtain access token, initialize API
+ try:
+ connection_header = get_token(module.params)
+ except KeycloakError as e:
+ module.fail_json(msg=str(e))
+
+ kc = KeycloakAPI(module, connection_header)
+
+ # Get id of the client based on client_id
+ cid = kc.get_client_id(client_id, realm=realm)
+ if not cid:
+ module.fail_json(msg='Invalid client %s for realm %s' %
+ (client_id, realm))
+
+ # Get current state of the permission using its name as the search
+ # filter. This returns False if it is not found.
+ permission = kc.get_authz_permission_by_name(
+ name=name, client_id=cid, realm=realm)
+
+ result['queried_state'] = permission
+
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/general/plugins/modules/keycloak_client.py b/ansible_collections/community/general/plugins/modules/keycloak_client.py
index ee687fcb4..b151e4541 100644
--- a/ansible_collections/community/general/plugins/modules/keycloak_client.py
+++ b/ansible_collections/community/general/plugins/modules/keycloak_client.py
@@ -40,8 +40,8 @@ options:
state:
description:
- State of the client
- - On C(present), the client will be created (or updated if it exists already).
- - On C(absent), the client will be removed if it exists
+ - On V(present), the client will be created (or updated if it exists already).
+ - On V(absent), the client will be removed if it exists
choices: ['present', 'absent']
default: 'present'
type: str
@@ -55,7 +55,7 @@ options:
client_id:
description:
- Client id of client to be worked on. This is usually an alphanumeric name chosen by
- you. Either this or I(id) is required. If you specify both, I(id) takes precedence.
+ you. Either this or O(id) is required. If you specify both, O(id) takes precedence.
This is 'clientId' in the Keycloak REST API.
aliases:
- clientId
@@ -63,13 +63,13 @@ options:
id:
description:
- - Id of client to be worked on. This is usually an UUID. Either this or I(client_id)
+ - Id of client to be worked on. This is usually an UUID. Either this or O(client_id)
is required. If you specify both, this takes precedence.
type: str
name:
description:
- - Name of the client (this is not the same as I(client_id)).
+ - Name of the client (this is not the same as O(client_id)).
type: str
description:
@@ -108,12 +108,12 @@ options:
client_authenticator_type:
description:
- - How do clients authenticate with the auth server? Either C(client-secret) or
- C(client-jwt) can be chosen. When using C(client-secret), the module parameter
- I(secret) can set it, while for C(client-jwt), you can use the keys C(use.jwks.url),
- C(jwks.url), and C(jwt.credential.certificate) in the I(attributes) module parameter
+ - How do clients authenticate with the auth server? Either V(client-secret) or
+ V(client-jwt) can be chosen. When using V(client-secret), the module parameter
+ O(secret) can set it, while for V(client-jwt), you can use the keys C(use.jwks.url),
+ C(jwks.url), and C(jwt.credential.certificate) in the O(attributes) module parameter
to configure its behavior.
- This is 'clientAuthenticatorType' in the Keycloak REST API.
+ - This is 'clientAuthenticatorType' in the Keycloak REST API.
choices: ['client-secret', 'client-jwt']
aliases:
- clientAuthenticatorType
@@ -121,7 +121,7 @@ options:
secret:
description:
- - When using I(client_authenticator_type) C(client-secret) (the default), you can
+ - When using O(client_authenticator_type=client-secret) (the default), you can
specify a secret here (otherwise one will be generated if it does not exit). If
changing this secret, the module will not register a change currently (but the
changed secret will be saved).
@@ -246,7 +246,8 @@ options:
protocol:
description:
- - Type of client (either C(openid-connect) or C(saml).
+ - Type of client.
+ - At creation only, default value will be V(openid-connect) if O(protocol) is omitted.
type: str
choices: ['openid-connect', 'saml']
@@ -286,7 +287,7 @@ options:
use_template_config:
description:
- - Whether or not to use configuration from the I(client_template).
+ - Whether or not to use configuration from the O(client_template).
This is 'useTemplateConfig' in the Keycloak REST API.
aliases:
- useTemplateConfig
@@ -294,7 +295,7 @@ options:
use_template_scope:
description:
- - Whether or not to use scope configuration from the I(client_template).
+ - Whether or not to use scope configuration from the O(client_template).
This is 'useTemplateScope' in the Keycloak REST API.
aliases:
- useTemplateScope
@@ -302,7 +303,7 @@ options:
use_template_mappers:
description:
- - Whether or not to use mapper configuration from the I(client_template).
+ - Whether or not to use mapper configuration from the O(client_template).
This is 'useTemplateMappers' in the Keycloak REST API.
aliases:
- useTemplateMappers
@@ -391,38 +392,37 @@ options:
protocol:
description:
- - This is either C(openid-connect) or C(saml), this specifies for which protocol this protocol mapper.
- is active.
+ - This specifies for which protocol this protocol mapper is active.
choices: ['openid-connect', 'saml']
type: str
protocolMapper:
description:
- - The Keycloak-internal name of the type of this protocol-mapper. While an exhaustive list is
+ - "The Keycloak-internal name of the type of this protocol-mapper. While an exhaustive list is
impossible to provide since this may be extended through SPIs by the user of Keycloak,
- by default Keycloak as of 3.4 ships with at least
- - C(docker-v2-allow-all-mapper)
- - C(oidc-address-mapper)
- - C(oidc-full-name-mapper)
- - C(oidc-group-membership-mapper)
- - C(oidc-hardcoded-claim-mapper)
- - C(oidc-hardcoded-role-mapper)
- - C(oidc-role-name-mapper)
- - C(oidc-script-based-protocol-mapper)
- - C(oidc-sha256-pairwise-sub-mapper)
- - C(oidc-usermodel-attribute-mapper)
- - C(oidc-usermodel-client-role-mapper)
- - C(oidc-usermodel-property-mapper)
- - C(oidc-usermodel-realm-role-mapper)
- - C(oidc-usersessionmodel-note-mapper)
- - C(saml-group-membership-mapper)
- - C(saml-hardcode-attribute-mapper)
- - C(saml-hardcode-role-mapper)
- - C(saml-role-list-mapper)
- - C(saml-role-name-mapper)
- - C(saml-user-attribute-mapper)
- - C(saml-user-property-mapper)
- - C(saml-user-session-note-mapper)
+ by default Keycloak as of 3.4 ships with at least:"
+ - V(docker-v2-allow-all-mapper)
+ - V(oidc-address-mapper)
+ - V(oidc-full-name-mapper)
+ - V(oidc-group-membership-mapper)
+ - V(oidc-hardcoded-claim-mapper)
+ - V(oidc-hardcoded-role-mapper)
+ - V(oidc-role-name-mapper)
+ - V(oidc-script-based-protocol-mapper)
+ - V(oidc-sha256-pairwise-sub-mapper)
+ - V(oidc-usermodel-attribute-mapper)
+ - V(oidc-usermodel-client-role-mapper)
+ - V(oidc-usermodel-property-mapper)
+ - V(oidc-usermodel-realm-role-mapper)
+ - V(oidc-usersessionmodel-note-mapper)
+ - V(saml-group-membership-mapper)
+ - V(saml-hardcode-attribute-mapper)
+ - V(saml-hardcode-role-mapper)
+ - V(saml-role-list-mapper)
+ - V(saml-role-name-mapper)
+ - V(saml-user-attribute-mapper)
+ - V(saml-user-property-mapper)
+ - V(saml-user-session-note-mapper)
- An exhaustive list of available mappers on your installation can be obtained on
the admin console by going to Server Info -> Providers and looking under
'protocol-mapper'.
@@ -431,10 +431,10 @@ options:
config:
description:
- Dict specifying the configuration options for the protocol mapper; the
- contents differ depending on the value of I(protocolMapper) and are not documented
+ contents differ depending on the value of O(protocol_mappers[].protocolMapper) and are not documented
other than by the source of the mappers and its parent class(es). An example is given
below. It is easiest to obtain valid config values by dumping an already-existing
- protocol mapper configuration through check-mode in the I(existing) field.
+ protocol mapper configuration through check-mode in the RV(existing) field.
type: dict
attributes:
@@ -478,7 +478,7 @@ options:
saml.signature.algorithm:
description:
- - Signature algorithm used to sign SAML documents. One of C(RSA_SHA256), C(RSA_SHA1), C(RSA_SHA512), or C(DSA_SHA1).
+ - Signature algorithm used to sign SAML documents. One of V(RSA_SHA256), V(RSA_SHA1), V(RSA_SHA512), or V(DSA_SHA1).
saml.signing.certificate:
description:
@@ -503,15 +503,15 @@ options:
saml_name_id_format:
description:
- - For SAML clients, the NameID format to use (one of C(username), C(email), C(transient), or C(persistent))
+ - For SAML clients, the NameID format to use (one of V(username), V(email), V(transient), or V(persistent))
saml_signature_canonicalization_method:
description:
- SAML signature canonicalization method. This is one of four values, namely
- C(http://www.w3.org/2001/10/xml-exc-c14n#) for EXCLUSIVE,
- C(http://www.w3.org/2001/10/xml-exc-c14n#WithComments) for EXCLUSIVE_WITH_COMMENTS,
- C(http://www.w3.org/TR/2001/REC-xml-c14n-20010315) for INCLUSIVE, and
- C(http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments) for INCLUSIVE_WITH_COMMENTS.
+ V(http://www.w3.org/2001/10/xml-exc-c14n#) for EXCLUSIVE,
+ V(http://www.w3.org/2001/10/xml-exc-c14n#WithComments) for EXCLUSIVE_WITH_COMMENTS,
+ V(http://www.w3.org/TR/2001/REC-xml-c14n-20010315) for INCLUSIVE, and
+ V(http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments) for INCLUSIVE_WITH_COMMENTS.
saml_single_logout_service_url_post:
description:
@@ -523,12 +523,12 @@ options:
user.info.response.signature.alg:
description:
- - For OpenID-Connect clients, JWA algorithm for signed UserInfo-endpoint responses. One of C(RS256) or C(unsigned).
+ - For OpenID-Connect clients, JWA algorithm for signed UserInfo-endpoint responses. One of V(RS256) or V(unsigned).
request.object.signature.alg:
description:
- For OpenID-Connect clients, JWA algorithm which the client needs to use when sending
- OIDC request object. One of C(any), C(none), C(RS256).
+ OIDC request object. One of V(any), V(none), V(RS256).
use.jwks.url:
description:
@@ -717,11 +717,16 @@ end_state:
'''
from ansible_collections.community.general.plugins.module_utils.identity.keycloak.keycloak import KeycloakAPI, camel, \
- keycloak_argument_spec, get_token, KeycloakError
+ keycloak_argument_spec, get_token, KeycloakError, is_struct_included
from ansible.module_utils.basic import AnsibleModule
import copy
+PROTOCOL_OPENID_CONNECT = 'openid-connect'
+PROTOCOL_SAML = 'saml'
+CLIENT_META_DATA = ['authorizationServicesEnabled']
+
+
def normalise_cr(clientrep, remove_ids=False):
""" Re-sorts any properties where the order so that diff's is minimised, and adds default values where appropriate so that the
the change detection is more effective.
@@ -780,7 +785,7 @@ def main():
consentText=dict(type='str'),
id=dict(type='str'),
name=dict(type='str'),
- protocol=dict(type='str', choices=['openid-connect', 'saml']),
+ protocol=dict(type='str', choices=[PROTOCOL_OPENID_CONNECT, PROTOCOL_SAML]),
protocolMapper=dict(type='str'),
config=dict(type='dict'),
)
@@ -814,7 +819,7 @@ def main():
authorization_services_enabled=dict(type='bool', aliases=['authorizationServicesEnabled']),
public_client=dict(type='bool', aliases=['publicClient']),
frontchannel_logout=dict(type='bool', aliases=['frontchannelLogout']),
- protocol=dict(type='str', choices=['openid-connect', 'saml']),
+ protocol=dict(type='str', choices=[PROTOCOL_OPENID_CONNECT, PROTOCOL_SAML]),
attributes=dict(type='dict'),
full_scope_allowed=dict(type='bool', aliases=['fullScopeAllowed']),
node_re_registration_timeout=dict(type='int', aliases=['nodeReRegistrationTimeout']),
@@ -912,6 +917,8 @@ def main():
if 'clientId' not in desired_client:
module.fail_json(msg='client_id needs to be specified when creating a new client')
+ if 'protocol' not in desired_client:
+ desired_client['protocol'] = PROTOCOL_OPENID_CONNECT
if module._diff:
result['diff'] = dict(before='', after=sanitize_cr(desired_client))
@@ -940,7 +947,7 @@ def main():
if module._diff:
result['diff'] = dict(before=sanitize_cr(before_norm),
after=sanitize_cr(desired_norm))
- result['changed'] = (before_norm != desired_norm)
+ result['changed'] = not is_struct_included(desired_norm, before_norm, CLIENT_META_DATA)
module.exit_json(**result)
diff --git a/ansible_collections/community/general/plugins/modules/keycloak_client_rolemapping.py b/ansible_collections/community/general/plugins/modules/keycloak_client_rolemapping.py
index 57dcac48d..be419904a 100644
--- a/ansible_collections/community/general/plugins/modules/keycloak_client_rolemapping.py
+++ b/ansible_collections/community/general/plugins/modules/keycloak_client_rolemapping.py
@@ -43,8 +43,8 @@ options:
state:
description:
- State of the client_rolemapping.
- - On C(present), the client_rolemapping will be created if it does not yet exist, or updated with the parameters you provide.
- - On C(absent), the client_rolemapping will be removed if it exists.
+ - On V(present), the client_rolemapping will be created if it does not yet exist, or updated with the parameters you provide.
+ - On V(absent), the client_rolemapping will be removed if it exists.
default: 'present'
type: str
choices:
@@ -63,6 +63,33 @@ options:
- Name of the group to be mapped.
- This parameter is required (can be replaced by gid for less API call).
+ parents:
+ version_added: "7.1.0"
+ type: list
+ description:
+ - List of parent groups for the group to handle sorted top to bottom.
+ - >-
+ Set this if your group is a subgroup and you do not provide the GID in O(gid).
+ elements: dict
+ suboptions:
+ id:
+ type: str
+ description:
+ - Identify parent by ID.
+ - Needs less API calls than using O(parents[].name).
+ - A deep parent chain can be started at any point when first given parent is given as ID.
+ - Note that in principle both ID and name can be specified at the same time
+ but current implementation only always use just one of them, with ID
+ being preferred.
+ name:
+ type: str
+ description:
+ - Identify parent by name.
+ - Needs more internal API calls than using O(parents[].id) to map names to ID's under the hood.
+ - When giving a parent chain with only names it must be complete up to the top.
+ - Note that in principle both ID and name can be specified at the same time
+ but current implementation only always use just one of them, with ID
+ being preferred.
gid:
type: str
description:
@@ -73,7 +100,7 @@ options:
client_id:
type: str
description:
- - Name of the client to be mapped (different than I(cid)).
+ - Name of the client to be mapped (different than O(cid)).
- This parameter is required (can be replaced by cid for less API call).
cid:
@@ -144,6 +171,24 @@ EXAMPLES = '''
id: role_id2
delegate_to: localhost
+- name: Map a client role to a subgroup, authentication with token
+ community.general.keycloak_client_rolemapping:
+ realm: MyCustomRealm
+ auth_client_id: admin-cli
+ auth_keycloak_url: https://auth.example.com/auth
+ token: TOKEN
+ state: present
+ client_id: client1
+ group_name: subgroup1
+ parents:
+ - name: parent-group
+ roles:
+ - name: role_name1
+ id: role_id1
+ - name: role_name2
+ id: role_id2
+ delegate_to: localhost
+
- name: Unmap client role from a group
community.general.keycloak_client_rolemapping:
realm: MyCustomRealm
@@ -230,6 +275,13 @@ def main():
realm=dict(default='master'),
gid=dict(type='str'),
group_name=dict(type='str'),
+ parents=dict(
+ type='list', elements='dict',
+ options=dict(
+ id=dict(type='str'),
+ name=dict(type='str')
+ ),
+ ),
cid=dict(type='str'),
client_id=dict(type='str'),
roles=dict(type='list', elements='dict', options=roles_spec),
@@ -259,6 +311,7 @@ def main():
gid = module.params.get('gid')
group_name = module.params.get('group_name')
roles = module.params.get('roles')
+ parents = module.params.get('parents')
# Check the parameters
if cid is None and client_id is None:
@@ -268,7 +321,7 @@ def main():
# Get the potential missing parameters
if gid is None:
- group_rep = kc.get_group_by_name(group_name, realm=realm)
+ group_rep = kc.get_group_by_name(group_name, realm=realm, parents=parents)
if group_rep is not None:
gid = group_rep['id']
else:
diff --git a/ansible_collections/community/general/plugins/modules/keycloak_clientscope.py b/ansible_collections/community/general/plugins/modules/keycloak_clientscope.py
index a23d92867..d37af5f0c 100644
--- a/ansible_collections/community/general/plugins/modules/keycloak_clientscope.py
+++ b/ansible_collections/community/general/plugins/modules/keycloak_clientscope.py
@@ -43,8 +43,8 @@ options:
state:
description:
- State of the client_scope.
- - On C(present), the client_scope will be created if it does not yet exist, or updated with the parameters you provide.
- - On C(absent), the client_scope will be removed if it exists.
+ - On V(present), the client_scope will be created if it does not yet exist, or updated with the parameters you provide.
+ - On V(absent), the client_scope will be removed if it exists.
default: 'present'
type: str
choices:
@@ -103,28 +103,28 @@ options:
- "The Keycloak-internal name of the type of this protocol-mapper. While an exhaustive list is
impossible to provide since this may be extended through SPIs by the user of Keycloak,
by default Keycloak as of 3.4 ships with at least:"
- - C(docker-v2-allow-all-mapper)
- - C(oidc-address-mapper)
- - C(oidc-full-name-mapper)
- - C(oidc-group-membership-mapper)
- - C(oidc-hardcoded-claim-mapper)
- - C(oidc-hardcoded-role-mapper)
- - C(oidc-role-name-mapper)
- - C(oidc-script-based-protocol-mapper)
- - C(oidc-sha256-pairwise-sub-mapper)
- - C(oidc-usermodel-attribute-mapper)
- - C(oidc-usermodel-client-role-mapper)
- - C(oidc-usermodel-property-mapper)
- - C(oidc-usermodel-realm-role-mapper)
- - C(oidc-usersessionmodel-note-mapper)
- - C(saml-group-membership-mapper)
- - C(saml-hardcode-attribute-mapper)
- - C(saml-hardcode-role-mapper)
- - C(saml-role-list-mapper)
- - C(saml-role-name-mapper)
- - C(saml-user-attribute-mapper)
- - C(saml-user-property-mapper)
- - C(saml-user-session-note-mapper)
+ - V(docker-v2-allow-all-mapper)
+ - V(oidc-address-mapper)
+ - V(oidc-full-name-mapper)
+ - V(oidc-group-membership-mapper)
+ - V(oidc-hardcoded-claim-mapper)
+ - V(oidc-hardcoded-role-mapper)
+ - V(oidc-role-name-mapper)
+ - V(oidc-script-based-protocol-mapper)
+ - V(oidc-sha256-pairwise-sub-mapper)
+ - V(oidc-usermodel-attribute-mapper)
+ - V(oidc-usermodel-client-role-mapper)
+ - V(oidc-usermodel-property-mapper)
+ - V(oidc-usermodel-realm-role-mapper)
+ - V(oidc-usersessionmodel-note-mapper)
+ - V(saml-group-membership-mapper)
+ - V(saml-hardcode-attribute-mapper)
+ - V(saml-hardcode-role-mapper)
+ - V(saml-role-list-mapper)
+ - V(saml-role-name-mapper)
+ - V(saml-user-attribute-mapper)
+ - V(saml-user-property-mapper)
+ - V(saml-user-session-note-mapper)
- An exhaustive list of available mappers on your installation can be obtained on
the admin console by going to Server Info -> Providers and looking under
'protocol-mapper'.
@@ -143,10 +143,10 @@ options:
config:
description:
- Dict specifying the configuration options for the protocol mapper; the
- contents differ depending on the value of I(protocolMapper) and are not documented
+ contents differ depending on the value of O(protocol_mappers[].protocolMapper) and are not documented
other than by the source of the mappers and its parent class(es). An example is given
below. It is easiest to obtain valid config values by dumping an already-existing
- protocol mapper configuration through check-mode in the C(existing) return value.
+ protocol mapper configuration through check-mode in the RV(existing) return value.
type: dict
attributes:
diff --git a/ansible_collections/community/general/plugins/modules/keycloak_clientscope_type.py b/ansible_collections/community/general/plugins/modules/keycloak_clientscope_type.py
index facf02aa4..37a5d3be9 100644
--- a/ansible_collections/community/general/plugins/modules/keycloak_clientscope_type.py
+++ b/ansible_collections/community/general/plugins/modules/keycloak_clientscope_type.py
@@ -40,7 +40,7 @@ options:
client_id:
description:
- - The I(client_id) of the client. If not set the clientscop types are set as a default for the realm.
+ - The O(client_id) of the client. If not set the clientscop types are set as a default for the realm.
aliases:
- clientId
type: str
@@ -67,7 +67,7 @@ author:
EXAMPLES = '''
- name: Set default client scopes on realm level
- community.general.keycloak_clientsecret_info:
+ community.general.keycloak_clientscope_type:
auth_client_id: admin-cli
auth_keycloak_url: https://auth.example.com/auth
auth_realm: master
@@ -79,7 +79,7 @@ EXAMPLES = '''
- name: Set default and optional client scopes on client level with token auth
- community.general.keycloak_clientsecret_info:
+ community.general.keycloak_clientscope_type:
auth_client_id: admin-cli
auth_keycloak_url: https://auth.example.com/auth
token: TOKEN
diff --git a/ansible_collections/community/general/plugins/modules/keycloak_clientsecret_info.py b/ansible_collections/community/general/plugins/modules/keycloak_clientsecret_info.py
index 98a41ad20..c77262035 100644
--- a/ansible_collections/community/general/plugins/modules/keycloak_clientsecret_info.py
+++ b/ansible_collections/community/general/plugins/modules/keycloak_clientsecret_info.py
@@ -26,8 +26,8 @@ description:
and a user having the expected roles.
- When retrieving a new client secret, where possible provide the client's
- I(id) (not I(client_id)) to the module. This removes a lookup to the API to
- translate the I(client_id) into the client ID.
+ O(id) (not O(client_id)) to the module. This removes a lookup to the API to
+ translate the O(client_id) into the client ID.
- "Note that this module returns the client secret. To avoid this showing up in the logs,
please add C(no_log: true) to the task."
@@ -48,7 +48,7 @@ options:
client_id:
description:
- - The I(client_id) of the client. Passing this instead of I(id) results in an
+ - The O(client_id) of the client. Passing this instead of O(id) results in an
extra API call.
aliases:
- clientId
diff --git a/ansible_collections/community/general/plugins/modules/keycloak_clienttemplate.py b/ansible_collections/community/general/plugins/modules/keycloak_clienttemplate.py
index d2555afc5..cd7f6c09b 100644
--- a/ansible_collections/community/general/plugins/modules/keycloak_clienttemplate.py
+++ b/ansible_collections/community/general/plugins/modules/keycloak_clienttemplate.py
@@ -38,8 +38,8 @@ options:
state:
description:
- State of the client template.
- - On C(present), the client template will be created (or updated if it exists already).
- - On C(absent), the client template will be removed if it exists
+ - On V(present), the client template will be created (or updated if it exists already).
+ - On V(absent), the client template will be removed if it exists
choices: ['present', 'absent']
default: 'present'
type: str
@@ -67,7 +67,7 @@ options:
protocol:
description:
- - Type of client template (either C(openid-connect) or C(saml).
+ - Type of client template.
choices: ['openid-connect', 'saml']
type: str
@@ -106,38 +106,37 @@ options:
protocol:
description:
- - This is either C(openid-connect) or C(saml), this specifies for which protocol this protocol mapper.
- is active.
+ - This specifies for which protocol this protocol mapper is active.
choices: ['openid-connect', 'saml']
type: str
protocolMapper:
description:
- - The Keycloak-internal name of the type of this protocol-mapper. While an exhaustive list is
+ - "The Keycloak-internal name of the type of this protocol-mapper. While an exhaustive list is
impossible to provide since this may be extended through SPIs by the user of Keycloak,
- by default Keycloak as of 3.4 ships with at least
- - C(docker-v2-allow-all-mapper)
- - C(oidc-address-mapper)
- - C(oidc-full-name-mapper)
- - C(oidc-group-membership-mapper)
- - C(oidc-hardcoded-claim-mapper)
- - C(oidc-hardcoded-role-mapper)
- - C(oidc-role-name-mapper)
- - C(oidc-script-based-protocol-mapper)
- - C(oidc-sha256-pairwise-sub-mapper)
- - C(oidc-usermodel-attribute-mapper)
- - C(oidc-usermodel-client-role-mapper)
- - C(oidc-usermodel-property-mapper)
- - C(oidc-usermodel-realm-role-mapper)
- - C(oidc-usersessionmodel-note-mapper)
- - C(saml-group-membership-mapper)
- - C(saml-hardcode-attribute-mapper)
- - C(saml-hardcode-role-mapper)
- - C(saml-role-list-mapper)
- - C(saml-role-name-mapper)
- - C(saml-user-attribute-mapper)
- - C(saml-user-property-mapper)
- - C(saml-user-session-note-mapper)
+ by default Keycloak as of 3.4 ships with at least:"
+ - V(docker-v2-allow-all-mapper)
+ - V(oidc-address-mapper)
+ - V(oidc-full-name-mapper)
+ - V(oidc-group-membership-mapper)
+ - V(oidc-hardcoded-claim-mapper)
+ - V(oidc-hardcoded-role-mapper)
+ - V(oidc-role-name-mapper)
+ - V(oidc-script-based-protocol-mapper)
+ - V(oidc-sha256-pairwise-sub-mapper)
+ - V(oidc-usermodel-attribute-mapper)
+ - V(oidc-usermodel-client-role-mapper)
+ - V(oidc-usermodel-property-mapper)
+ - V(oidc-usermodel-realm-role-mapper)
+ - V(oidc-usersessionmodel-note-mapper)
+ - V(saml-group-membership-mapper)
+ - V(saml-hardcode-attribute-mapper)
+ - V(saml-hardcode-role-mapper)
+ - V(saml-role-list-mapper)
+ - V(saml-role-name-mapper)
+ - V(saml-user-attribute-mapper)
+ - V(saml-user-property-mapper)
+ - V(saml-user-session-note-mapper)
- An exhaustive list of available mappers on your installation can be obtained on
the admin console by going to Server Info -> Providers and looking under
'protocol-mapper'.
@@ -146,10 +145,10 @@ options:
config:
description:
- Dict specifying the configuration options for the protocol mapper; the
- contents differ depending on the value of I(protocolMapper) and are not documented
+ contents differ depending on the value of O(protocol_mappers[].protocolMapper) and are not documented
other than by the source of the mappers and its parent class(es). An example is given
below. It is easiest to obtain valid config values by dumping an already-existing
- protocol mapper configuration through check-mode in the I(existing) field.
+ protocol mapper configuration through check-mode in the RV(existing) field.
type: dict
attributes:
@@ -160,9 +159,9 @@ options:
type: dict
notes:
- - The Keycloak REST API defines further fields (namely I(bearerOnly), I(consentRequired), I(standardFlowEnabled),
- I(implicitFlowEnabled), I(directAccessGrantsEnabled), I(serviceAccountsEnabled), I(publicClient), and
- I(frontchannelLogout)) which, while available with keycloak_client, do not have any effect on
+ - The Keycloak REST API defines further fields (namely C(bearerOnly), C(consentRequired), C(standardFlowEnabled),
+ C(implicitFlowEnabled), C(directAccessGrantsEnabled), C(serviceAccountsEnabled), C(publicClient), and
+ C(frontchannelLogout)) which, while available with keycloak_client, do not have any effect on
Keycloak client-templates and are discarded if supplied with an API request changing client-templates. As such,
they are not available through this module.
diff --git a/ansible_collections/community/general/plugins/modules/keycloak_component_info.py b/ansible_collections/community/general/plugins/modules/keycloak_component_info.py
new file mode 100644
index 000000000..a788735d9
--- /dev/null
+++ b/ansible_collections/community/general/plugins/modules/keycloak_component_info.py
@@ -0,0 +1,169 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) Ansible project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+DOCUMENTATION = '''
+---
+module: keycloak_component_info
+
+short_description: Retrive component info in Keycloak
+
+version_added: 8.2.0
+
+description:
+ - This module retrive information on component from Keycloak.
+options:
+ realm:
+ description:
+ - The name of the realm.
+ required: true
+ type: str
+ name:
+ description:
+ - Name of the Component.
+ type: str
+ provider_type:
+ description:
+ - Provider type of components.
+ - "Example:
+ V(org.keycloak.storage.UserStorageProvider),
+ V(org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy),
+ V(org.keycloak.keys.KeyProvider),
+ V(org.keycloak.userprofile.UserProfileProvider),
+ V(org.keycloak.storage.ldap.mappers.LDAPStorageMapper)."
+ type: str
+ parent_id:
+ description:
+ - Container ID of the components.
+ type: str
+
+
+extends_documentation_fragment:
+ - community.general.keycloak
+ - community.general.attributes
+ - community.general.attributes.info_module
+
+author:
+ - Andre Desrosiers (@desand01)
+'''
+
+EXAMPLES = '''
+ - name: Retrive info of a UserStorageProvider named myldap
+ community.general.keycloak_component_info:
+ auth_keycloak_url: http://localhost:8080/auth
+ auth_sername: admin
+ auth_password: password
+ auth_realm: master
+ realm: myrealm
+ name: myldap
+ provider_type: org.keycloak.storage.UserStorageProvider
+
+ - name: Retrive key info component
+ community.general.keycloak_component_info:
+ auth_keycloak_url: http://localhost:8080/auth
+ auth_sername: admin
+ auth_password: password
+ auth_realm: master
+ realm: myrealm
+ name: rsa-enc-generated
+ provider_type: org.keycloak.keys.KeyProvider
+
+ - name: Retrive all component from realm master
+ community.general.keycloak_component_info:
+ auth_keycloak_url: http://localhost:8080/auth
+ auth_sername: admin
+ auth_password: password
+ auth_realm: master
+ realm: myrealm
+
+ - name: Retrive all sub components of parent component filter by type
+ community.general.keycloak_component_info:
+ auth_keycloak_url: http://localhost:8080/auth
+ auth_sername: admin
+ auth_password: password
+ auth_realm: master
+ realm: myrealm
+ parent_id: "075ef2fa-19fc-4a6d-bf4c-249f57365fd2"
+ provider_type: "org.keycloak.storage.ldap.mappers.LDAPStorageMapper"
+
+
+'''
+
+RETURN = '''
+components:
+ description: JSON representation of components.
+ returned: always
+ type: list
+ elements: dict
+'''
+
+from ansible_collections.community.general.plugins.module_utils.identity.keycloak.keycloak import KeycloakAPI, \
+ keycloak_argument_spec, get_token, KeycloakError
+from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.six.moves.urllib.parse import quote
+
+
+def main():
+ """
+ Module execution
+
+ :return:
+ """
+ argument_spec = keycloak_argument_spec()
+
+ meta_args = dict(
+ name=dict(type='str'),
+ realm=dict(type='str', required=True),
+ parent_id=dict(type='str'),
+ provider_type=dict(type='str'),
+ )
+
+ argument_spec.update(meta_args)
+
+ module = AnsibleModule(argument_spec=argument_spec,
+ supports_check_mode=True)
+
+ result = dict(changed=False, components=[])
+
+ # Obtain access token, initialize API
+ try:
+ connection_header = get_token(module.params)
+ except KeycloakError as e:
+ module.fail_json(msg=str(e))
+
+ kc = KeycloakAPI(module, connection_header)
+
+ realm = module.params.get('realm')
+ parentId = module.params.get('parent_id')
+ name = module.params.get('name')
+ providerType = module.params.get('provider_type')
+
+ objRealm = kc.get_realm_by_id(realm)
+ if not objRealm:
+ module.fail_json(msg="Failed to retrive realm '{realm}'".format(realm=realm))
+
+ filters = []
+
+ if parentId:
+ filters.append("parent=%s" % (quote(parentId, safe='')))
+ else:
+ filters.append("parent=%s" % (quote(objRealm['id'], safe='')))
+
+ if name:
+ filters.append("name=%s" % (quote(name, safe='')))
+ if providerType:
+ filters.append("type=%s" % (quote(providerType, safe='')))
+
+ result['components'] = kc.get_components(filter="&".join(filters), realm=realm)
+
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/general/plugins/modules/keycloak_group.py b/ansible_collections/community/general/plugins/modules/keycloak_group.py
index 399bc5b4f..5398a4b5d 100644
--- a/ansible_collections/community/general/plugins/modules/keycloak_group.py
+++ b/ansible_collections/community/general/plugins/modules/keycloak_group.py
@@ -41,9 +41,9 @@ options:
state:
description:
- State of the group.
- - On C(present), the group will be created if it does not yet exist, or updated with the parameters you provide.
+ - On V(present), the group will be created if it does not yet exist, or updated with the parameters you provide.
- >-
- On C(absent), the group will be removed if it exists. Be aware that absenting
+ On V(absent), the group will be removed if it exists. Be aware that absenting
a group with subgroups will automatically delete all its subgroups too.
default: 'present'
type: str
@@ -93,7 +93,7 @@ options:
type: str
description:
- Identify parent by ID.
- - Needs less API calls than using I(name).
+ - Needs less API calls than using O(parents[].name).
- A deep parent chain can be started at any point when first given parent is given as ID.
- Note that in principle both ID and name can be specified at the same time
but current implementation only always use just one of them, with ID
@@ -102,14 +102,14 @@ options:
type: str
description:
- Identify parent by name.
- - Needs more internal API calls than using I(id) to map names to ID's under the hood.
+ - Needs more internal API calls than using O(parents[].id) to map names to ID's under the hood.
- When giving a parent chain with only names it must be complete up to the top.
- Note that in principle both ID and name can be specified at the same time
but current implementation only always use just one of them, with ID
being preferred.
notes:
- - Presently, the I(realmRoles), I(clientRoles) and I(access) attributes returned by the Keycloak API
+ - Presently, the RV(end_state.realmRoles), RV(end_state.clientRoles), and RV(end_state.access) attributes returned by the Keycloak API
are read-only for groups. This limitation will be removed in a later version of this module.
extends_documentation_fragment:
diff --git a/ansible_collections/community/general/plugins/modules/keycloak_identity_provider.py b/ansible_collections/community/general/plugins/modules/keycloak_identity_provider.py
index 0d12ae03a..588f553e8 100644
--- a/ansible_collections/community/general/plugins/modules/keycloak_identity_provider.py
+++ b/ansible_collections/community/general/plugins/modules/keycloak_identity_provider.py
@@ -36,8 +36,8 @@ options:
state:
description:
- State of the identity provider.
- - On C(present), the identity provider will be created if it does not yet exist, or updated with the parameters you provide.
- - On C(absent), the identity provider will be removed if it exists.
+ - On V(present), the identity provider will be created if it does not yet exist, or updated with the parameters you provide.
+ - On V(absent), the identity provider will be removed if it exists.
default: 'present'
type: str
choices:
@@ -120,16 +120,16 @@ options:
provider_id:
description:
- - Protocol used by this provider (supported values are C(oidc) or C(saml)).
+ - Protocol used by this provider (supported values are V(oidc) or V(saml)).
aliases:
- providerId
type: str
config:
description:
- - Dict specifying the configuration options for the provider; the contents differ depending on the value of I(providerId).
- Examples are given below for C(oidc) and C(saml). It is easiest to obtain valid config values by dumping an already-existing
- identity provider configuration through check-mode in the I(existing) field.
+ - Dict specifying the configuration options for the provider; the contents differ depending on the value of O(provider_id).
+ Examples are given below for V(oidc) and V(saml). It is easiest to obtain valid config values by dumping an already-existing
+ identity provider configuration through check-mode in the RV(existing) field.
type: dict
suboptions:
hide_on_login_page:
@@ -271,7 +271,8 @@ options:
config:
description:
- - Dict specifying the configuration options for the mapper; the contents differ depending on the value of I(identityProviderMapper).
+ - Dict specifying the configuration options for the mapper; the contents differ depending on the value of
+ O(mappers[].identityProviderMapper).
type: dict
extends_documentation_fragment:
@@ -541,10 +542,14 @@ def main():
old_mapper = dict()
new_mapper = old_mapper.copy()
new_mapper.update(change)
- if new_mapper != old_mapper:
- if changeset.get('mappers') is None:
- changeset['mappers'] = list()
- changeset['mappers'].append(new_mapper)
+
+ if changeset.get('mappers') is None:
+ changeset['mappers'] = list()
+ # eventually this holds all desired mappers, unchanged, modified and newly added
+ changeset['mappers'].append(new_mapper)
+
+ # ensure idempotency in case module.params.mappers is not sorted by name
+ changeset['mappers'] = sorted(changeset['mappers'], key=lambda x: x.get('id') if x.get('name') is None else x['name'])
# Prepare the desired values using the existing values (non-existence results in a dict that is save to use as a basis)
desired_idp = before_idp.copy()
@@ -611,10 +616,17 @@ def main():
# do the update
desired_idp = desired_idp.copy()
updated_mappers = desired_idp.pop('mappers', [])
+ original_mappers = list(before_idp.get('mappers', []))
+
kc.update_identity_provider(desired_idp, realm)
for mapper in updated_mappers:
if mapper.get('id') is not None:
- kc.update_identity_provider_mapper(mapper, alias, realm)
+ # only update existing if there is a change
+ for i, orig in enumerate(original_mappers):
+ if mapper['id'] == orig['id']:
+ del original_mappers[i]
+ if mapper != orig:
+ kc.update_identity_provider_mapper(mapper, alias, realm)
else:
if mapper.get('identityProviderAlias') is None:
mapper['identityProviderAlias'] = alias
diff --git a/ansible_collections/community/general/plugins/modules/keycloak_realm.py b/ansible_collections/community/general/plugins/modules/keycloak_realm.py
index 53f81be48..9f2e72b52 100644
--- a/ansible_collections/community/general/plugins/modules/keycloak_realm.py
+++ b/ansible_collections/community/general/plugins/modules/keycloak_realm.py
@@ -42,8 +42,8 @@ options:
state:
description:
- State of the realm.
- - On C(present), the realm will be created (or updated if it exists already).
- - On C(absent), the realm will be removed if it exists.
+ - On V(present), the realm will be created (or updated if it exists already).
+ - On V(absent), the realm will be removed if it exists.
choices: ['present', 'absent']
default: 'present'
type: str
diff --git a/ansible_collections/community/general/plugins/modules/keycloak_realm_key.py b/ansible_collections/community/general/plugins/modules/keycloak_realm_key.py
new file mode 100644
index 000000000..6e762fba9
--- /dev/null
+++ b/ansible_collections/community/general/plugins/modules/keycloak_realm_key.py
@@ -0,0 +1,475 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2017, Eike Frost <ei@kefro.st>
+# Copyright (c) 2021, Christophe Gilles <christophe.gilles54@gmail.com>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or
+# https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+DOCUMENTATION = '''
+---
+module: keycloak_realm_key
+
+short_description: Allows administration of Keycloak realm keys via Keycloak API
+
+version_added: 7.5.0
+
+description:
+ - This module allows the administration of Keycloak realm keys via the Keycloak REST API. It
+ requires access to the REST API via OpenID Connect; the user connecting and the realm being
+ used must have the requisite access rights. In a default Keycloak installation, admin-cli
+ and an admin user would work, as would a separate realm definition with the scope tailored
+ to your needs and a user having the expected roles.
+
+ - The names of module options are snake_cased versions of the camelCase ones found in the
+ Keycloak API and its documentation at U(https://www.keycloak.org/docs-api/8.0/rest-api/index.html).
+ Aliases are provided so camelCased versions can be used as well.
+
+ - This module is unable to detect changes to the actual cryptographic key after importing it.
+ However, if some other property is changed alongside the cryptographic key, then the key
+ will also get changed as a side-effect, as the JSON payload needs to include the private key.
+ This can be considered either a bug or a feature, as the alternative would be to always
+ update the realm key whether it has changed or not.
+
+ - If certificate is not explicitly provided it will be dynamically created by Keycloak.
+ Therefore comparing the current state of the certificate to the desired state (which may be
+ empty) is not possible.
+
+attributes:
+ check_mode:
+ support: full
+ diff_mode:
+ support: partial
+
+options:
+ state:
+ description:
+ - State of the keycloak realm key.
+ - On V(present), the realm key will be created (or updated if it exists already).
+ - On V(absent), the realm key will be removed if it exists.
+ choices: ['present', 'absent']
+ default: 'present'
+ type: str
+ name:
+ description:
+ - Name of the realm key to create.
+ type: str
+ required: true
+ force:
+ description:
+ - Enforce the state of the private key and certificate. This is not automatically the
+ case as this module is unable to determine the current state of the private key and
+ thus cannot trigger an update based on an actual divergence. That said, a private key
+ update may happen even if force is false as a side-effect of other changes.
+ default: false
+ type: bool
+ parent_id:
+ description:
+ - The parent_id of the realm key. In practice the ID (name) of the realm.
+ type: str
+ required: true
+ provider_id:
+ description:
+ - The name of the "provider ID" for the key.
+ - The value V(rsa-enc) has been added in community.general 8.2.0.
+ choices: ['rsa', 'rsa-enc']
+ default: 'rsa'
+ type: str
+ config:
+ description:
+ - Dict specifying the key and its properties.
+ type: dict
+ suboptions:
+ active:
+ description:
+ - Whether they key is active or inactive. Not to be confused with the state
+ of the Ansible resource managed by the O(state) parameter.
+ default: true
+ type: bool
+ enabled:
+ description:
+ - Whether the key is enabled or disabled. Not to be confused with the state
+ of the Ansible resource managed by the O(state) parameter.
+ default: true
+ type: bool
+ priority:
+ description:
+ - The priority of the key.
+ type: int
+ required: true
+ algorithm:
+ description:
+ - Key algorithm.
+ - The values V(RS384), V(RS512), V(PS256), V(PS384), V(PS512), V(RSA1_5),
+ V(RSA-OAEP), V(RSA-OAEP-256) have been added in community.general 8.2.0.
+ default: RS256
+ choices: ['RS256', 'RS384', 'RS512', 'PS256', 'PS384', 'PS512', 'RSA1_5', 'RSA-OAEP', 'RSA-OAEP-256']
+ type: str
+ private_key:
+ description:
+ - The private key as an ASCII string. Contents of the key must match O(config.algorithm)
+ and O(provider_id).
+ - Please note that the module cannot detect whether the private key specified differs from the
+ current state's private key. Use O(force=true) to force the module to update the private key
+ if you expect it to be updated.
+ required: true
+ type: str
+ certificate:
+ description:
+ - A certificate signed with the private key as an ASCII string. Contents of the
+ key must match O(config.algorithm) and O(provider_id).
+ - If you want Keycloak to automatically generate a certificate using your private key
+ then set this to an empty string.
+ required: true
+ type: str
+notes:
+ - Current value of the private key cannot be fetched from Keycloak.
+ Therefore comparing its desired state to the current state is not
+ possible.
+ - If certificate is not explicitly provided it will be dynamically created
+ by Keycloak. Therefore comparing the current state of the certificate to
+ the desired state (which may be empty) is not possible.
+ - Due to the private key and certificate options the module is
+ B(not fully idempotent). You can use O(force=true) to force the module
+ to always update if you know that the private key might have changed.
+
+extends_documentation_fragment:
+ - community.general.keycloak
+ - community.general.attributes
+
+author:
+ - Samuli Seppänen (@mattock)
+'''
+
+EXAMPLES = '''
+- name: Manage Keycloak realm key (certificate autogenerated by Keycloak)
+ community.general.keycloak_realm_key:
+ name: custom
+ state: present
+ parent_id: master
+ provider_id: rsa
+ auth_keycloak_url: http://localhost:8080/auth
+ auth_username: keycloak
+ auth_password: keycloak
+ auth_realm: master
+ config:
+ private_key: "{{ private_key }}"
+ certificate: ""
+ enabled: true
+ active: true
+ priority: 120
+ algorithm: RS256
+- name: Manage Keycloak realm key and certificate
+ community.general.keycloak_realm_key:
+ name: custom
+ state: present
+ parent_id: master
+ provider_id: rsa
+ auth_keycloak_url: http://localhost:8080/auth
+ auth_username: keycloak
+ auth_password: keycloak
+ auth_realm: master
+ config:
+ private_key: "{{ private_key }}"
+ certificate: "{{ certificate }}"
+ enabled: true
+ active: true
+ priority: 120
+ algorithm: RS256
+'''
+
+RETURN = '''
+msg:
+ description: Message as to what action was taken.
+ returned: always
+ type: str
+
+end_state:
+ description: Representation of the keycloak_realm_key after module execution.
+ returned: on success
+ type: dict
+ contains:
+ id:
+ description: ID of the realm key.
+ type: str
+ returned: when O(state=present)
+ sample: 5b7ec13f-99da-46ad-8326-ab4c73cf4ce4
+ name:
+ description: Name of the realm key.
+ type: str
+ returned: when O(state=present)
+ sample: mykey
+ parentId:
+ description: ID of the realm this key belongs to.
+ type: str
+ returned: when O(state=present)
+ sample: myrealm
+ providerId:
+ description: The ID of the key provider.
+ type: str
+ returned: when O(state=present)
+ sample: rsa
+ providerType:
+ description: The type of provider.
+ type: str
+ returned: when O(state=present)
+ config:
+ description: Realm key configuration.
+ type: dict
+ returned: when O(state=present)
+ sample: {
+ "active": ["true"],
+ "algorithm": ["RS256"],
+ "enabled": ["true"],
+ "priority": ["140"]
+ }
+'''
+
+from ansible_collections.community.general.plugins.module_utils.identity.keycloak.keycloak import KeycloakAPI, camel, \
+ keycloak_argument_spec, get_token, KeycloakError
+from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.six.moves.urllib.parse import urlencode
+from copy import deepcopy
+
+
+def main():
+ """
+ Module execution
+
+ :return:
+ """
+ argument_spec = keycloak_argument_spec()
+
+ meta_args = dict(
+ state=dict(type='str', default='present', choices=['present', 'absent']),
+ name=dict(type='str', required=True),
+ force=dict(type='bool', default=False),
+ parent_id=dict(type='str', required=True),
+ provider_id=dict(type='str', default='rsa', choices=['rsa', 'rsa-enc']),
+ config=dict(
+ type='dict',
+ options=dict(
+ active=dict(type='bool', default=True),
+ enabled=dict(type='bool', default=True),
+ priority=dict(type='int', required=True),
+ algorithm=dict(
+ type="str",
+ default="RS256",
+ choices=[
+ "RS256",
+ "RS384",
+ "RS512",
+ "PS256",
+ "PS384",
+ "PS512",
+ "RSA1_5",
+ "RSA-OAEP",
+ "RSA-OAEP-256",
+ ],
+ ),
+ private_key=dict(type='str', required=True, no_log=True),
+ certificate=dict(type='str', required=True)
+ )
+ )
+ )
+
+ argument_spec.update(meta_args)
+
+ module = AnsibleModule(argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_one_of=([['token', 'auth_realm', 'auth_username', 'auth_password']]),
+ required_together=([['auth_realm', 'auth_username', 'auth_password']]))
+
+ # Initialize the result object. Only "changed" seems to have special
+ # meaning for Ansible.
+ result = dict(changed=False, msg='', end_state={}, diff=dict(before={}, after={}))
+
+ # This will include the current state of the realm key if it is already
+ # present. This is only used for diff-mode.
+ before_realm_key = {}
+ before_realm_key['config'] = {}
+
+ # Obtain access token, initialize API
+ try:
+ connection_header = get_token(module.params)
+ except KeycloakError as e:
+ module.fail_json(msg=str(e))
+
+ kc = KeycloakAPI(module, connection_header)
+
+ params_to_ignore = list(keycloak_argument_spec().keys()) + ["state", "force"]
+
+ # Filter and map the parameters names that apply to the role
+ component_params = [x for x in module.params
+ if x not in params_to_ignore and
+ module.params.get(x) is not None]
+
+ # We only support one component provider type in this module
+ provider_type = 'org.keycloak.keys.KeyProvider'
+
+ # Build a proposed changeset from parameters given to this module
+ changeset = {}
+ changeset['config'] = {}
+
+ # Generate a JSON payload for Keycloak Admin API from the module
+ # parameters. Parameters that do not belong to the JSON payload (e.g.
+ # "state" or "auth_keycloal_url") have been filtered away earlier (see
+ # above).
+ #
+ # This loop converts Ansible module parameters (snake-case) into
+ # Keycloak-compatible format (camel-case). For example private_key
+ # becomes privateKey.
+ #
+ # It also converts bool, str and int parameters into lists with a single
+ # entry of 'str' type. Bool values are also lowercased. This is required
+ # by Keycloak.
+ #
+ for component_param in component_params:
+ if component_param == 'config':
+ for config_param in module.params.get('config'):
+ changeset['config'][camel(config_param)] = []
+ raw_value = module.params.get('config')[config_param]
+ if isinstance(raw_value, bool):
+ value = str(raw_value).lower()
+ else:
+ value = str(raw_value)
+
+ changeset['config'][camel(config_param)].append(value)
+ else:
+ # No need for camelcase in here as these are one word parameters
+ new_param_value = module.params.get(component_param)
+ changeset[camel(component_param)] = new_param_value
+
+ # As provider_type is not a module parameter we have to add it to the
+ # changeset explicitly.
+ changeset['providerType'] = provider_type
+
+ # Make a deep copy of the changeset. This is use when determining
+ # changes to the current state.
+ changeset_copy = deepcopy(changeset)
+
+ # It is not possible to compare current keys to desired keys, because the
+ # certificate parameter is a base64-encoded binary blob created on the fly
+ # when a key is added. Moreover, the Keycloak Admin API does not seem to
+ # return the value of the private key for comparison. So, in effect, it we
+ # just have to ignore changes to the keys. However, as the privateKey
+ # parameter needs be present in the JSON payload, any changes done to any
+ # other parameters (e.g. config.priority) will trigger update of the keys
+ # as a side-effect.
+ del changeset_copy['config']['privateKey']
+ del changeset_copy['config']['certificate']
+
+ # Make it easier to refer to current module parameters
+ name = module.params.get('name')
+ force = module.params.get('force')
+ state = module.params.get('state')
+ enabled = module.params.get('enabled')
+ provider_id = module.params.get('provider_id')
+ parent_id = module.params.get('parent_id')
+
+ # Get a list of all Keycloak components that are of keyprovider type.
+ realm_keys = kc.get_components(urlencode(dict(type=provider_type, parent=parent_id)), parent_id)
+
+ # If this component is present get its key ID. Confusingly the key ID is
+ # also known as the Provider ID.
+ key_id = None
+
+ # Track individual parameter changes
+ changes = ""
+
+ # This tells Ansible whether the key was changed (added, removed, modified)
+ result['changed'] = False
+
+ # Loop through the list of components. If we encounter a component whose
+ # name matches the value of the name parameter then assume the key is
+ # already present.
+ for key in realm_keys:
+ if key['name'] == name:
+ key_id = key['id']
+ changeset['id'] = key_id
+ changeset_copy['id'] = key_id
+
+ # Compare top-level parameters
+ for param, value in changeset.items():
+ before_realm_key[param] = key[param]
+
+ if changeset_copy[param] != key[param] and param != 'config':
+ changes += "%s: %s -> %s, " % (param, key[param], changeset_copy[param])
+ result['changed'] = True
+
+ # Compare parameters under the "config" key
+ for p, v in changeset_copy['config'].items():
+ before_realm_key['config'][p] = key['config'][p]
+ if changeset_copy['config'][p] != key['config'][p]:
+ changes += "config.%s: %s -> %s, " % (p, key['config'][p], changeset_copy['config'][p])
+ result['changed'] = True
+
+ # Sanitize linefeeds for the privateKey. Without this the JSON payload
+ # will be invalid.
+ changeset['config']['privateKey'][0] = changeset['config']['privateKey'][0].replace('\\n', '\n')
+ changeset['config']['certificate'][0] = changeset['config']['certificate'][0].replace('\\n', '\n')
+
+ # Check all the possible states of the resource and do what is needed to
+ # converge current state with desired state (create, update or delete
+ # the key).
+ if key_id and state == 'present':
+ if result['changed']:
+ if module._diff:
+ del before_realm_key['config']['privateKey']
+ del before_realm_key['config']['certificate']
+ result['diff'] = dict(before=before_realm_key, after=changeset_copy)
+
+ if module.check_mode:
+ result['msg'] = "Realm key %s would be changed: %s" % (name, changes.strip(", "))
+ else:
+ kc.update_component(changeset, parent_id)
+ result['msg'] = "Realm key %s changed: %s" % (name, changes.strip(", "))
+ elif not result['changed'] and force:
+ kc.update_component(changeset, parent_id)
+ result['changed'] = True
+ result['msg'] = "Realm key %s was forcibly updated" % (name)
+ else:
+ result['msg'] = "Realm key %s was in sync" % (name)
+
+ result['end_state'] = changeset_copy
+ elif key_id and state == 'absent':
+ if module._diff:
+ del before_realm_key['config']['privateKey']
+ del before_realm_key['config']['certificate']
+ result['diff'] = dict(before=before_realm_key, after={})
+
+ if module.check_mode:
+ result['changed'] = True
+ result['msg'] = "Realm key %s would be deleted" % (name)
+ else:
+ kc.delete_component(key_id, parent_id)
+ result['changed'] = True
+ result['msg'] = "Realm key %s deleted" % (name)
+
+ result['end_state'] = {}
+ elif not key_id and state == 'present':
+ if module._diff:
+ result['diff'] = dict(before={}, after=changeset_copy)
+
+ if module.check_mode:
+ result['changed'] = True
+ result['msg'] = "Realm key %s would be created" % (name)
+ else:
+ kc.create_component(changeset, parent_id)
+ result['changed'] = True
+ result['msg'] = "Realm key %s created" % (name)
+
+ result['end_state'] = changeset_copy
+ elif not key_id and state == 'absent':
+ result['changed'] = False
+ result['msg'] = "Realm key %s not present" % (name)
+ result['end_state'] = {}
+
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/general/plugins/modules/keycloak_realm_rolemapping.py b/ansible_collections/community/general/plugins/modules/keycloak_realm_rolemapping.py
new file mode 100644
index 000000000..693cf9894
--- /dev/null
+++ b/ansible_collections/community/general/plugins/modules/keycloak_realm_rolemapping.py
@@ -0,0 +1,391 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) Ansible project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+DOCUMENTATION = '''
+---
+module: keycloak_realm_rolemapping
+
+short_description: Allows administration of Keycloak realm role mappings into groups with the Keycloak API
+
+version_added: 8.2.0
+
+description:
+ - This module allows you to add, remove or modify Keycloak realm role
+ mappings into groups with the Keycloak REST API. It requires access to the
+ REST API via OpenID Connect; the user connecting and the client being used
+ must have the requisite access rights. In a default Keycloak installation,
+ admin-cli and an admin user would work, as would a separate client
+ definition with the scope tailored to your needs and a user having the
+ expected roles.
+
+ - The names of module options are snake_cased versions of the camelCase ones found in the
+ Keycloak API and its documentation at U(https://www.keycloak.org/docs-api/18.0/rest-api/index.html).
+
+ - Attributes are multi-valued in the Keycloak API. All attributes are lists of individual values and will
+ be returned that way by this module. You may pass single values for attributes when calling the module,
+ and this will be translated into a list suitable for the API.
+
+ - When updating a group_rolemapping, where possible provide the role ID to the module. This removes a lookup
+ to the API to translate the name into the role ID.
+
+attributes:
+ check_mode:
+ support: full
+ diff_mode:
+ support: full
+
+options:
+ state:
+ description:
+ - State of the realm_rolemapping.
+ - On C(present), the realm_rolemapping will be created if it does not yet exist, or updated with the parameters you provide.
+ - On C(absent), the realm_rolemapping will be removed if it exists.
+ default: 'present'
+ type: str
+ choices:
+ - present
+ - absent
+
+ realm:
+ type: str
+ description:
+ - They Keycloak realm under which this role_representation resides.
+ default: 'master'
+
+ group_name:
+ type: str
+ description:
+ - Name of the group to be mapped.
+ - This parameter is required (can be replaced by gid for less API call).
+
+ parents:
+ type: list
+ description:
+ - List of parent groups for the group to handle sorted top to bottom.
+ - >-
+ Set this if your group is a subgroup and you do not provide the GID in O(gid).
+ elements: dict
+ suboptions:
+ id:
+ type: str
+ description:
+ - Identify parent by ID.
+ - Needs less API calls than using O(parents[].name).
+ - A deep parent chain can be started at any point when first given parent is given as ID.
+ - Note that in principle both ID and name can be specified at the same time
+ but current implementation only always use just one of them, with ID
+ being preferred.
+ name:
+ type: str
+ description:
+ - Identify parent by name.
+ - Needs more internal API calls than using O(parents[].id) to map names to ID's under the hood.
+ - When giving a parent chain with only names it must be complete up to the top.
+ - Note that in principle both ID and name can be specified at the same time
+ but current implementation only always use just one of them, with ID
+ being preferred.
+ gid:
+ type: str
+ description:
+ - ID of the group to be mapped.
+ - This parameter is not required for updating or deleting the rolemapping but
+ providing it will reduce the number of API calls required.
+
+ roles:
+ description:
+ - Roles to be mapped to the group.
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ type: str
+ description:
+ - Name of the role_representation.
+ - This parameter is required only when creating or updating the role_representation.
+ id:
+ type: str
+ description:
+ - The unique identifier for this role_representation.
+ - This parameter is not required for updating or deleting a role_representation but
+ providing it will reduce the number of API calls required.
+
+extends_documentation_fragment:
+ - community.general.keycloak
+ - community.general.attributes
+
+author:
+ - Gaëtan Daubresse (@Gaetan2907)
+ - Marius Huysamen (@mhuysamen)
+ - Alexander Groß (@agross)
+'''
+
+EXAMPLES = '''
+- name: Map a client role to a group, authentication with credentials
+ community.general.keycloak_realm_rolemapping:
+ realm: MyCustomRealm
+ auth_client_id: admin-cli
+ auth_keycloak_url: https://auth.example.com/auth
+ auth_realm: master
+ auth_username: USERNAME
+ auth_password: PASSWORD
+ state: present
+ group_name: group1
+ roles:
+ - name: role_name1
+ id: role_id1
+ - name: role_name2
+ id: role_id2
+ delegate_to: localhost
+
+- name: Map a client role to a group, authentication with token
+ community.general.keycloak_realm_rolemapping:
+ realm: MyCustomRealm
+ auth_client_id: admin-cli
+ auth_keycloak_url: https://auth.example.com/auth
+ token: TOKEN
+ state: present
+ group_name: group1
+ roles:
+ - name: role_name1
+ id: role_id1
+ - name: role_name2
+ id: role_id2
+ delegate_to: localhost
+
+- name: Map a client role to a subgroup, authentication with token
+ community.general.keycloak_realm_rolemapping:
+ realm: MyCustomRealm
+ auth_client_id: admin-cli
+ auth_keycloak_url: https://auth.example.com/auth
+ token: TOKEN
+ state: present
+ group_name: subgroup1
+ parents:
+ - name: parent-group
+ roles:
+ - name: role_name1
+ id: role_id1
+ - name: role_name2
+ id: role_id2
+ delegate_to: localhost
+
+- name: Unmap realm role from a group
+ community.general.keycloak_realm_rolemapping:
+ realm: MyCustomRealm
+ auth_client_id: admin-cli
+ auth_keycloak_url: https://auth.example.com/auth
+ auth_realm: master
+ auth_username: USERNAME
+ auth_password: PASSWORD
+ state: absent
+ group_name: group1
+ roles:
+ - name: role_name1
+ id: role_id1
+ - name: role_name2
+ id: role_id2
+ delegate_to: localhost
+'''
+
+RETURN = '''
+msg:
+ description: Message as to what action was taken.
+ returned: always
+ type: str
+ sample: "Role role1 assigned to group group1."
+
+proposed:
+ description: Representation of proposed client role mapping.
+ returned: always
+ type: dict
+ sample: {
+ clientId: "test"
+ }
+
+existing:
+ description:
+ - Representation of existing client role mapping.
+ - The sample is truncated.
+ returned: always
+ type: dict
+ sample: {
+ "adminUrl": "http://www.example.com/admin_url",
+ "attributes": {
+ "request.object.signature.alg": "RS256",
+ }
+ }
+
+end_state:
+ description:
+ - Representation of client role mapping after module execution.
+ - The sample is truncated.
+ returned: on success
+ type: dict
+ sample: {
+ "adminUrl": "http://www.example.com/admin_url",
+ "attributes": {
+ "request.object.signature.alg": "RS256",
+ }
+ }
+'''
+
+from ansible_collections.community.general.plugins.module_utils.identity.keycloak.keycloak import (
+ KeycloakAPI, keycloak_argument_spec, get_token, KeycloakError,
+)
+from ansible.module_utils.basic import AnsibleModule
+
+
+def main():
+ """
+ Module execution
+
+ :return:
+ """
+ argument_spec = keycloak_argument_spec()
+
+ roles_spec = dict(
+ name=dict(type='str'),
+ id=dict(type='str'),
+ )
+
+ meta_args = dict(
+ state=dict(default='present', choices=['present', 'absent']),
+ realm=dict(default='master'),
+ gid=dict(type='str'),
+ group_name=dict(type='str'),
+ parents=dict(
+ type='list', elements='dict',
+ options=dict(
+ id=dict(type='str'),
+ name=dict(type='str')
+ ),
+ ),
+ roles=dict(type='list', elements='dict', options=roles_spec),
+ )
+
+ argument_spec.update(meta_args)
+
+ module = AnsibleModule(argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_one_of=([['token', 'auth_realm', 'auth_username', 'auth_password']]),
+ required_together=([['auth_realm', 'auth_username', 'auth_password']]))
+
+ result = dict(changed=False, msg='', diff={}, proposed={}, existing={}, end_state={})
+
+ # Obtain access token, initialize API
+ try:
+ connection_header = get_token(module.params)
+ except KeycloakError as e:
+ module.fail_json(msg=str(e))
+
+ kc = KeycloakAPI(module, connection_header)
+
+ realm = module.params.get('realm')
+ state = module.params.get('state')
+ gid = module.params.get('gid')
+ group_name = module.params.get('group_name')
+ roles = module.params.get('roles')
+ parents = module.params.get('parents')
+
+ # Check the parameters
+ if gid is None and group_name is None:
+ module.fail_json(msg='Either the `group_name` or `gid` has to be specified.')
+
+ # Get the potential missing parameters
+ if gid is None:
+ group_rep = kc.get_group_by_name(group_name, realm=realm, parents=parents)
+ if group_rep is not None:
+ gid = group_rep['id']
+ else:
+ module.fail_json(msg='Could not fetch group %s:' % group_name)
+ else:
+ group_rep = kc.get_group_by_groupid(gid, realm=realm)
+
+ if roles is None:
+ module.exit_json(msg="Nothing to do (no roles specified).")
+ else:
+ for role_index, role in enumerate(roles, start=0):
+ if role['name'] is None and role['id'] is None:
+ module.fail_json(msg='Either the `name` or `id` has to be specified on each role.')
+ # Fetch missing role_id
+ if role['id'] is None:
+ role_rep = kc.get_realm_role(role['name'], realm=realm)
+ if role_rep is not None:
+ role['id'] = role_rep['id']
+ else:
+ module.fail_json(msg='Could not fetch realm role %s by name:' % (role['name']))
+ # Fetch missing role_name
+ else:
+ for realm_role in kc.get_realm_roles(realm=realm):
+ if realm_role['id'] == role['id']:
+ role['name'] = realm_role['name']
+ break
+
+ if role['name'] is None:
+ module.fail_json(msg='Could not fetch realm role %s by ID' % (role['id']))
+
+ assigned_roles_before = group_rep.get('realmRoles', [])
+
+ result['existing'] = assigned_roles_before
+ result['proposed'] = list(assigned_roles_before) if assigned_roles_before else []
+
+ update_roles = []
+ for role_index, role in enumerate(roles, start=0):
+ # Fetch roles to assign if state present
+ if state == 'present':
+ if any(assigned == role['name'] for assigned in assigned_roles_before):
+ pass
+ else:
+ update_roles.append({
+ 'id': role['id'],
+ 'name': role['name'],
+ })
+ result['proposed'].append(role['name'])
+ # Fetch roles to remove if state absent
+ else:
+ if any(assigned == role['name'] for assigned in assigned_roles_before):
+ update_roles.append({
+ 'id': role['id'],
+ 'name': role['name'],
+ })
+ if role['name'] in result['proposed']: # Handle double removal
+ result['proposed'].remove(role['name'])
+
+ if len(update_roles):
+ result['changed'] = True
+ if module._diff:
+ result['diff'] = dict(before=assigned_roles_before, after=result['proposed'])
+ if module.check_mode:
+ module.exit_json(**result)
+
+ if state == 'present':
+ # Assign roles
+ kc.add_group_realm_rolemapping(gid=gid, role_rep=update_roles, realm=realm)
+ result['msg'] = 'Realm roles %s assigned to groupId %s.' % (update_roles, gid)
+ else:
+ # Remove mapping of role
+ kc.delete_group_realm_rolemapping(gid=gid, role_rep=update_roles, realm=realm)
+ result['msg'] = 'Realm roles %s removed from groupId %s.' % (update_roles, gid)
+
+ if gid is None:
+ assigned_roles_after = kc.get_group_by_name(group_name, realm=realm, parents=parents).get('realmRoles', [])
+ else:
+ assigned_roles_after = kc.get_group_by_groupid(gid, realm=realm).get('realmRoles', [])
+ result['end_state'] = assigned_roles_after
+ module.exit_json(**result)
+ # Do nothing
+ else:
+ result['changed'] = False
+ result['msg'] = 'Nothing to do, roles %s are %s with group %s.' % (roles, 'mapped' if state == 'present' else 'not mapped', group_name)
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/general/plugins/modules/keycloak_role.py b/ansible_collections/community/general/plugins/modules/keycloak_role.py
index bbec5f591..f3e01483f 100644
--- a/ansible_collections/community/general/plugins/modules/keycloak_role.py
+++ b/ansible_collections/community/general/plugins/modules/keycloak_role.py
@@ -40,8 +40,8 @@ options:
state:
description:
- State of the role.
- - On C(present), the role will be created if it does not yet exist, or updated with the parameters you provide.
- - On C(absent), the role will be removed if it exists.
+ - On V(present), the role will be created if it does not yet exist, or updated with the parameters you provide.
+ - On V(absent), the role will be removed if it exists.
default: 'present'
type: str
choices:
@@ -77,6 +77,42 @@ options:
description:
- A dict of key/value pairs to set as custom attributes for the role.
- Values may be single values (e.g. a string) or a list of strings.
+ composite:
+ description:
+ - If V(true), the role is a composition of other realm and/or client role.
+ default: false
+ type: bool
+ version_added: 7.1.0
+ composites:
+ description:
+ - List of roles to include to the composite realm role.
+ - If the composite role is a client role, the C(clientId) (not ID of the client) must be specified.
+ default: []
+ type: list
+ elements: dict
+ version_added: 7.1.0
+ suboptions:
+ name:
+ description:
+ - Name of the role. This can be the name of a REALM role or a client role.
+ type: str
+ required: true
+ client_id:
+ description:
+ - Client ID if the role is a client role. Do not include this option for a REALM role.
+ - Use the client ID you can see in the Keycloak console, not the technical ID of the client.
+ type: str
+ required: false
+ aliases:
+ - clientId
+ state:
+ description:
+ - Create the composite if present, remove it if absent.
+ type: str
+ choices:
+ - present
+ - absent
+ default: present
extends_documentation_fragment:
- community.general.keycloak
@@ -198,8 +234,9 @@ end_state:
'''
from ansible_collections.community.general.plugins.module_utils.identity.keycloak.keycloak import KeycloakAPI, camel, \
- keycloak_argument_spec, get_token, KeycloakError
+ keycloak_argument_spec, get_token, KeycloakError, is_struct_included
from ansible.module_utils.basic import AnsibleModule
+import copy
def main():
@@ -210,6 +247,12 @@ def main():
"""
argument_spec = keycloak_argument_spec()
+ composites_spec = dict(
+ name=dict(type='str', required=True),
+ client_id=dict(type='str', aliases=['clientId'], required=False),
+ state=dict(type='str', default='present', choices=['present', 'absent'])
+ )
+
meta_args = dict(
state=dict(type='str', default='present', choices=['present', 'absent']),
name=dict(type='str', required=True),
@@ -217,6 +260,8 @@ def main():
realm=dict(type='str', default='master'),
client_id=dict(type='str'),
attributes=dict(type='dict'),
+ composites=dict(type='list', default=[], options=composites_spec, elements='dict'),
+ composite=dict(type='bool', default=False),
)
argument_spec.update(meta_args)
@@ -250,7 +295,7 @@ def main():
# Filter and map the parameters names that apply to the role
role_params = [x for x in module.params
- if x not in list(keycloak_argument_spec().keys()) + ['state', 'realm', 'client_id', 'composites'] and
+ if x not in list(keycloak_argument_spec().keys()) + ['state', 'realm', 'client_id'] and
module.params.get(x) is not None]
# See if it already exists in Keycloak
@@ -269,10 +314,10 @@ def main():
new_param_value = module.params.get(param)
old_value = before_role[param] if param in before_role else None
if new_param_value != old_value:
- changeset[camel(param)] = new_param_value
+ changeset[camel(param)] = copy.deepcopy(new_param_value)
# Prepare the desired values using the existing values (non-existence results in a dict that is save to use as a basis)
- desired_role = before_role.copy()
+ desired_role = copy.deepcopy(before_role)
desired_role.update(changeset)
result['proposed'] = changeset
@@ -309,6 +354,9 @@ def main():
kc.create_client_role(desired_role, clientid, realm)
after_role = kc.get_client_role(name, clientid, realm)
+ if after_role['composite']:
+ after_role['composites'] = kc.get_role_composites(rolerep=after_role, clientid=clientid, realm=realm)
+
result['end_state'] = after_role
result['msg'] = 'Role {name} has been created'.format(name=name)
@@ -316,10 +364,25 @@ def main():
else:
if state == 'present':
+ compare_exclude = []
+ if 'composites' in desired_role and isinstance(desired_role['composites'], list) and len(desired_role['composites']) > 0:
+ composites = kc.get_role_composites(rolerep=before_role, clientid=clientid, realm=realm)
+ before_role['composites'] = []
+ for composite in composites:
+ before_composite = {}
+ if composite['clientRole']:
+ composite_client = kc.get_client_by_id(id=composite['containerId'], realm=realm)
+ before_composite['client_id'] = composite_client['clientId']
+ else:
+ before_composite['client_id'] = None
+ before_composite['name'] = composite['name']
+ before_composite['state'] = 'present'
+ before_role['composites'].append(before_composite)
+ else:
+ compare_exclude.append('composites')
# Process an update
-
# no changes
- if desired_role == before_role:
+ if is_struct_included(desired_role, before_role, exclude=compare_exclude):
result['changed'] = False
result['end_state'] = desired_role
result['msg'] = "No changes required to role {name}.".format(name=name)
@@ -341,6 +404,8 @@ def main():
else:
kc.update_client_role(desired_role, clientid, realm)
after_role = kc.get_client_role(name, clientid, realm)
+ if after_role['composite']:
+ after_role['composites'] = kc.get_role_composites(rolerep=after_role, clientid=clientid, realm=realm)
result['end_state'] = after_role
diff --git a/ansible_collections/community/general/plugins/modules/keycloak_user.py b/ansible_collections/community/general/plugins/modules/keycloak_user.py
new file mode 100644
index 000000000..1aeff0da5
--- /dev/null
+++ b/ansible_collections/community/general/plugins/modules/keycloak_user.py
@@ -0,0 +1,542 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2019, INSPQ (@elfelip)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+
+DOCUMENTATION = '''
+---
+module: keycloak_user
+short_description: Create and configure a user in Keycloak
+description:
+ - This module creates, removes, or updates Keycloak users.
+version_added: 7.1.0
+options:
+ auth_username:
+ aliases: []
+ realm:
+ description:
+ - The name of the realm in which is the client.
+ default: master
+ type: str
+ username:
+ description:
+ - Username for the user.
+ required: true
+ type: str
+ id:
+ description:
+ - ID of the user on the Keycloak server if known.
+ type: str
+ enabled:
+ description:
+ - Enabled user.
+ type: bool
+ email_verified:
+ description:
+ - Check the validity of user email.
+ default: false
+ type: bool
+ aliases:
+ - emailVerified
+ first_name:
+ description:
+ - The user's first name.
+ required: false
+ type: str
+ aliases:
+ - firstName
+ last_name:
+ description:
+ - The user's last name.
+ required: false
+ type: str
+ aliases:
+ - lastName
+ email:
+ description:
+ - User email.
+ required: false
+ type: str
+ federation_link:
+ description:
+ - Federation Link.
+ required: false
+ type: str
+ aliases:
+ - federationLink
+ service_account_client_id:
+ description:
+ - Description of the client Application.
+ required: false
+ type: str
+ aliases:
+ - serviceAccountClientId
+ client_consents:
+ description:
+ - Client Authenticator Type.
+ type: list
+ elements: dict
+ default: []
+ aliases:
+ - clientConsents
+ suboptions:
+ client_id:
+ description:
+ - Client ID of the client role. Not the technical ID of the client.
+ type: str
+ required: true
+ aliases:
+ - clientId
+ roles:
+ description:
+ - List of client roles to assign to the user.
+ type: list
+ required: true
+ elements: str
+ groups:
+ description:
+ - List of groups for the user.
+ type: list
+ elements: dict
+ default: []
+ suboptions:
+ name:
+ description:
+ - Name of the group.
+ type: str
+ state:
+ description:
+ - Control whether the user must be member of this group or not.
+ choices: [ "present", "absent" ]
+ default: present
+ type: str
+ credentials:
+ description:
+ - User credentials.
+ default: []
+ type: list
+ elements: dict
+ suboptions:
+ type:
+ description:
+ - Credential type.
+ type: str
+ required: true
+ value:
+ description:
+ - Value of the credential.
+ type: str
+ required: true
+ temporary:
+ description:
+ - If V(true), the users are required to reset their credentials at next login.
+ type: bool
+ default: false
+ required_actions:
+ description:
+ - RequiredActions user Auth.
+ default: []
+ type: list
+ elements: str
+ aliases:
+ - requiredActions
+ federated_identities:
+ description:
+ - List of IDPs of user.
+ default: []
+ type: list
+ elements: str
+ aliases:
+ - federatedIdentities
+ attributes:
+ description:
+ - List of user attributes.
+ required: false
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description:
+ - Name of the attribute.
+ type: str
+ values:
+ description:
+ - Values for the attribute as list.
+ type: list
+ elements: str
+ state:
+ description:
+ - Control whether the attribute must exists or not.
+ choices: [ "present", "absent" ]
+ default: present
+ type: str
+ access:
+ description:
+ - list user access.
+ required: false
+ type: dict
+ disableable_credential_types:
+ description:
+ - list user Credential Type.
+ default: []
+ type: list
+ elements: str
+ aliases:
+ - disableableCredentialTypes
+ origin:
+ description:
+ - user origin.
+ required: false
+ type: str
+ self:
+ description:
+ - user self administration.
+ required: false
+ type: str
+ state:
+ description:
+ - Control whether the user should exists or not.
+ choices: [ "present", "absent" ]
+ default: present
+ type: str
+ force:
+ description:
+ - If V(true), allows to remove user and recreate it.
+ type: bool
+ default: false
+extends_documentation_fragment:
+ - community.general.keycloak
+ - community.general.attributes
+attributes:
+ check_mode:
+ support: full
+ diff_mode:
+ support: full
+notes:
+ - The module does not modify the user ID of an existing user.
+author:
+ - Philippe Gauthier (@elfelip)
+'''
+
+EXAMPLES = '''
+- name: Create a user user1
+ community.general.keycloak_user:
+ auth_keycloak_url: http://localhost:8080/auth
+ auth_username: admin
+ auth_password: password
+ realm: master
+ username: user1
+ firstName: user1
+ lastName: user1
+ email: user1
+ enabled: true
+ emailVerified: false
+ credentials:
+ - type: password
+ value: password
+ temporary: false
+ attributes:
+ - name: attr1
+ values:
+ - value1
+ state: present
+ - name: attr2
+ values:
+ - value2
+ state: absent
+ groups:
+ - name: group1
+ state: present
+ state: present
+
+- name: Re-create a User
+ community.general.keycloak_user:
+ auth_keycloak_url: http://localhost:8080/auth
+ auth_username: admin
+ auth_password: password
+ realm: master
+ username: user1
+ firstName: user1
+ lastName: user1
+ email: user1
+ enabled: true
+ emailVerified: false
+ credentials:
+ - type: password
+ value: password
+ temporary: false
+ attributes:
+ - name: attr1
+ values:
+ - value1
+ state: present
+ - name: attr2
+ values:
+ - value2
+ state: absent
+ groups:
+ - name: group1
+ state: present
+ state: present
+
+- name: Re-create a User
+ community.general.keycloak_user:
+ auth_keycloak_url: http://localhost:8080/auth
+ auth_username: admin
+ auth_password: password
+ realm: master
+ username: user1
+ firstName: user1
+ lastName: user1
+ email: user1
+ enabled: true
+ emailVerified: false
+ credentials:
+ - type: password
+ value: password
+ temporary: false
+ attributes:
+ - name: attr1
+ values:
+ - value1
+ state: present
+ - name: attr2
+ values:
+ - value2
+ state: absent
+ groups:
+ - name: group1
+ state: present
+ state: present
+ force: true
+
+- name: Remove User
+ community.general.keycloak_user:
+ auth_keycloak_url: http://localhost:8080/auth
+ auth_username: admin
+ auth_password: password
+ realm: master
+ username: user1
+ state: absent
+'''
+
+RETURN = '''
+msg:
+ description: Message as to what action was taken.
+ returned: always
+ type: str
+ sample: User f18c709c-03d6-11ee-970b-c74bf2721112 created
+proposed:
+ description: Representation of the proposed user.
+ returned: on success
+ type: dict
+existing:
+ description: Representation of the existing user.
+ returned: on success
+ type: dict
+end_state:
+ description: Representation of the user after module execution
+ returned: on success
+ type: dict
+changed:
+ description: Return V(true) if the operation changed the user on the keycloak server, V(false) otherwise.
+ returned: always
+ type: bool
+'''
+from ansible_collections.community.general.plugins.module_utils.identity.keycloak.keycloak import KeycloakAPI, camel, \
+ keycloak_argument_spec, get_token, KeycloakError, is_struct_included
+from ansible.module_utils.basic import AnsibleModule
+import copy
+
+
+def main():
+ argument_spec = keycloak_argument_spec()
+ argument_spec['auth_username']['aliases'] = []
+ credential_spec = dict(
+ type=dict(type='str', required=True),
+ value=dict(type='str', required=True),
+ temporary=dict(type='bool', default=False)
+ )
+ client_consents_spec = dict(
+ client_id=dict(type='str', required=True, aliases=['clientId']),
+ roles=dict(type='list', elements='str', required=True)
+ )
+ attributes_spec = dict(
+ name=dict(type='str'),
+ values=dict(type='list', elements='str'),
+ state=dict(type='str', choices=['present', 'absent'], default='present')
+ )
+ groups_spec = dict(
+ name=dict(type='str'),
+ state=dict(type='str', choices=['present', 'absent'], default='present')
+ )
+ meta_args = dict(
+ realm=dict(type='str', default='master'),
+ self=dict(type='str'),
+ id=dict(type='str'),
+ username=dict(type='str', required=True),
+ first_name=dict(type='str', aliases=['firstName']),
+ last_name=dict(type='str', aliases=['lastName']),
+ email=dict(type='str'),
+ enabled=dict(type='bool'),
+ email_verified=dict(type='bool', default=False, aliases=['emailVerified']),
+ federation_link=dict(type='str', aliases=['federationLink']),
+ service_account_client_id=dict(type='str', aliases=['serviceAccountClientId']),
+ attributes=dict(type='list', elements='dict', options=attributes_spec),
+ access=dict(type='dict'),
+ groups=dict(type='list', default=[], elements='dict', options=groups_spec),
+ disableable_credential_types=dict(type='list', default=[], aliases=['disableableCredentialTypes'], elements='str'),
+ required_actions=dict(type='list', default=[], aliases=['requiredActions'], elements='str'),
+ credentials=dict(type='list', default=[], elements='dict', options=credential_spec),
+ federated_identities=dict(type='list', default=[], aliases=['federatedIdentities'], elements='str'),
+ client_consents=dict(type='list', default=[], aliases=['clientConsents'], elements='dict', options=client_consents_spec),
+ origin=dict(type='str'),
+ state=dict(choices=["absent", "present"], default='present'),
+ force=dict(type='bool', default=False),
+ )
+ argument_spec.update(meta_args)
+
+ module = AnsibleModule(argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_one_of=([['token', 'auth_realm', 'auth_username', 'auth_password']]),
+ required_together=([['auth_realm', 'auth_username', 'auth_password']]))
+
+ result = dict(changed=False, msg='', diff={}, proposed={}, existing={}, end_state={})
+
+ # Obtain access token, initialize API
+ try:
+ connection_header = get_token(module.params)
+ except KeycloakError as e:
+ module.fail_json(msg=str(e))
+
+ kc = KeycloakAPI(module, connection_header)
+
+ realm = module.params.get('realm')
+ state = module.params.get('state')
+ force = module.params.get('force')
+ username = module.params.get('username')
+ groups = module.params.get('groups')
+
+ # Filter and map the parameters names that apply to the user
+ user_params = [x for x in module.params
+ if x not in list(keycloak_argument_spec().keys()) + ['state', 'realm', 'force', 'groups'] and
+ module.params.get(x) is not None]
+
+ before_user = kc.get_user_by_username(username=username, realm=realm)
+
+ if before_user is None:
+ before_user = {}
+
+ changeset = {}
+
+ for param in user_params:
+ new_param_value = module.params.get(param)
+ if param == 'attributes' and param in before_user:
+ old_value = kc.convert_keycloak_user_attributes_dict_to_module_list(attributes=before_user['attributes'])
+ else:
+ old_value = before_user[param] if param in before_user else None
+ if new_param_value != old_value:
+ if old_value is not None and param == 'attributes':
+ for old_attribute in old_value:
+ old_attribute_found = False
+ for new_attribute in new_param_value:
+ if new_attribute['name'] == old_attribute['name']:
+ old_attribute_found = True
+ if not old_attribute_found:
+ new_param_value.append(copy.deepcopy(old_attribute))
+ if isinstance(new_param_value, dict):
+ changeset[camel(param)] = copy.deepcopy(new_param_value)
+ else:
+ changeset[camel(param)] = new_param_value
+ # Prepare the desired values using the existing values (non-existence results in a dict that is save to use as a basis)
+ desired_user = copy.deepcopy(before_user)
+ desired_user.update(changeset)
+
+ result['proposed'] = changeset
+ result['existing'] = before_user
+
+ changed = False
+
+ # Cater for when it doesn't exist (an empty dict)
+ if state == 'absent':
+ if not before_user:
+ # Do nothing and exit
+ if module._diff:
+ result['diff'] = dict(before='', after='')
+ result['changed'] = False
+ result['end_state'] = {}
+ result['msg'] = 'Role does not exist, doing nothing.'
+ module.exit_json(**result)
+ else:
+ # Delete user
+ kc.delete_user(user_id=before_user['id'], realm=realm)
+ result["msg"] = 'User %s deleted' % (before_user['username'])
+ changed = True
+
+ else:
+ after_user = {}
+ if force and before_user: # If the force option is set to true
+ # Delete the existing user
+ kc.delete_user(user_id=before_user["id"], realm=realm)
+
+ if not before_user or force:
+ # Process a creation
+ changed = True
+
+ if username is None:
+ module.fail_json(msg='username must be specified when creating a new user')
+
+ if module._diff:
+ result['diff'] = dict(before='', after=desired_user)
+
+ if module.check_mode:
+ module.exit_json(**result)
+ # Create the user
+ after_user = kc.create_user(userrep=desired_user, realm=realm)
+ result["msg"] = 'User %s created' % (desired_user['username'])
+ # Add user ID to new representation
+ desired_user['id'] = after_user["id"]
+ else:
+ excludes = [
+ "access",
+ "notBefore",
+ "createdTimestamp",
+ "totp",
+ "credentials",
+ "disableableCredentialTypes",
+ "groups",
+ "clientConsents",
+ "federatedIdentities",
+ "requiredActions"]
+ # Add user ID to new representation
+ desired_user['id'] = before_user["id"]
+
+ # Compare users
+ if not (is_struct_included(desired_user, before_user, excludes)): # If the new user does not introduce a change to the existing user
+ # Update the user
+ after_user = kc.update_user(userrep=desired_user, realm=realm)
+ changed = True
+
+ # set user groups
+ if kc.update_user_groups_membership(userrep=desired_user, groups=groups, realm=realm):
+ changed = True
+ # Get the user groups
+ after_user["groups"] = kc.get_user_groups(user_id=desired_user["id"], realm=realm)
+ result["end_state"] = after_user
+ if changed:
+ result["msg"] = 'User %s updated' % (desired_user['username'])
+ else:
+ result["msg"] = 'No changes made for user %s' % (desired_user['username'])
+
+ result['changed'] = changed
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/general/plugins/modules/keycloak_user_federation.py b/ansible_collections/community/general/plugins/modules/keycloak_user_federation.py
index c0dc5d271..fee0d1265 100644
--- a/ansible_collections/community/general/plugins/modules/keycloak_user_federation.py
+++ b/ansible_collections/community/general/plugins/modules/keycloak_user_federation.py
@@ -36,9 +36,9 @@ options:
state:
description:
- State of the user federation.
- - On C(present), the user federation will be created if it does not yet exist, or updated with
+ - On V(present), the user federation will be created if it does not yet exist, or updated with
the parameters you provide.
- - On C(absent), the user federation will be removed if it exists.
+ - On V(absent), the user federation will be removed if it exists.
default: 'present'
type: str
choices:
@@ -54,7 +54,7 @@ options:
id:
description:
- The unique ID for this user federation. If left empty, the user federation will be searched
- by its I(name).
+ by its O(name).
type: str
name:
@@ -64,18 +64,15 @@ options:
provider_id:
description:
- - Provider for this user federation.
+ - Provider for this user federation. Built-in providers are V(ldap), V(kerberos), and V(sssd).
+ Custom user storage providers can also be used.
aliases:
- providerId
type: str
- choices:
- - ldap
- - kerberos
- - sssd
provider_type:
description:
- - Component type for user federation (only supported value is C(org.keycloak.storage.UserStorageProvider)).
+ - Component type for user federation (only supported value is V(org.keycloak.storage.UserStorageProvider)).
aliases:
- providerType
default: org.keycloak.storage.UserStorageProvider
@@ -91,10 +88,10 @@ options:
config:
description:
- Dict specifying the configuration options for the provider; the contents differ depending on
- the value of I(provider_id). Examples are given below for C(ldap), C(kerberos) and C(sssd).
+ the value of O(provider_id). Examples are given below for V(ldap), V(kerberos) and V(sssd).
It is easiest to obtain valid config values by dumping an already-existing user federation
- configuration through check-mode in the I(existing) field.
- - The value C(sssd) has been supported since community.general 4.2.0.
+ configuration through check-mode in the RV(existing) field.
+ - The value V(sssd) has been supported since community.general 4.2.0.
type: dict
suboptions:
enabled:
@@ -111,15 +108,15 @@ options:
importEnabled:
description:
- - If C(true), LDAP users will be imported into Keycloak DB and synced by the configured
+ - If V(true), LDAP users will be imported into Keycloak DB and synced by the configured
sync policies.
default: true
type: bool
editMode:
description:
- - C(READ_ONLY) is a read-only LDAP store. C(WRITABLE) means data will be synced back to LDAP
- on demand. C(UNSYNCED) means user data will be imported, but not synced back to LDAP.
+ - V(READ_ONLY) is a read-only LDAP store. V(WRITABLE) means data will be synced back to LDAP
+ on demand. V(UNSYNCED) means user data will be imported, but not synced back to LDAP.
type: str
choices:
- READ_ONLY
@@ -136,13 +133,13 @@ options:
vendor:
description:
- LDAP vendor (provider).
- - Use short name. For instance, write C(rhds) for "Red Hat Directory Server".
+ - Use short name. For instance, write V(rhds) for "Red Hat Directory Server".
type: str
usernameLDAPAttribute:
description:
- Name of LDAP attribute, which is mapped as Keycloak username. For many LDAP server
- vendors it can be C(uid). For Active directory it can be C(sAMAccountName) or C(cn).
+ vendors it can be V(uid). For Active directory it can be V(sAMAccountName) or V(cn).
The attribute should be filled for all LDAP user records you want to import from
LDAP to Keycloak.
type: str
@@ -151,15 +148,15 @@ options:
description:
- Name of LDAP attribute, which is used as RDN (top attribute) of typical user DN.
Usually it's the same as Username LDAP attribute, however it is not required. For
- example for Active directory, it is common to use C(cn) as RDN attribute when
- username attribute might be C(sAMAccountName).
+ example for Active directory, it is common to use V(cn) as RDN attribute when
+ username attribute might be V(sAMAccountName).
type: str
uuidLDAPAttribute:
description:
- Name of LDAP attribute, which is used as unique object identifier (UUID) for objects
- in LDAP. For many LDAP server vendors, it is C(entryUUID); however some are different.
- For example for Active directory it should be C(objectGUID). If your LDAP server does
+ in LDAP. For many LDAP server vendors, it is V(entryUUID); however some are different.
+ For example for Active directory it should be V(objectGUID). If your LDAP server does
not support the notion of UUID, you can use any other attribute that is supposed to
be unique among LDAP users in tree.
type: str
@@ -167,7 +164,7 @@ options:
userObjectClasses:
description:
- All values of LDAP objectClass attribute for users in LDAP divided by comma.
- For example C(inetOrgPerson, organizationalPerson). Newly created Keycloak users
+ For example V(inetOrgPerson, organizationalPerson). Newly created Keycloak users
will be written to LDAP with all those object classes and existing LDAP user records
are found just if they contain all those object classes.
type: str
@@ -251,8 +248,8 @@ options:
useTruststoreSpi:
description:
- Specifies whether LDAP connection will use the truststore SPI with the truststore
- configured in standalone.xml/domain.xml. C(Always) means that it will always use it.
- C(Never) means that it will not use it. C(Only for ldaps) means that it will use if
+ configured in standalone.xml/domain.xml. V(always) means that it will always use it.
+ V(never) means that it will not use it. V(ldapsOnly) means that it will use if
your connection URL use ldaps. Note even if standalone.xml/domain.xml is not
configured, the default Java cacerts or certificate specified by
C(javax.net.ssl.trustStore) property will be used.
@@ -297,7 +294,7 @@ options:
connectionPoolingDebug:
description:
- A string that indicates the level of debug output to produce. Example valid values are
- C(fine) (trace connection creation and removal) and C(all) (all debugging information).
+ V(fine) (trace connection creation and removal) and V(all) (all debugging information).
type: str
connectionPoolingInitSize:
@@ -321,7 +318,7 @@ options:
connectionPoolingProtocol:
description:
- A list of space-separated protocol types of connections that may be pooled.
- Valid types are C(plain) and C(ssl).
+ Valid types are V(plain) and V(ssl).
type: str
connectionPoolingTimeout:
@@ -342,17 +339,27 @@ options:
- Name of kerberos realm.
type: str
+ krbPrincipalAttribute:
+ description:
+ - Name of the LDAP attribute, which refers to Kerberos principal.
+ This is used to lookup appropriate LDAP user after successful Kerberos/SPNEGO authentication in Keycloak.
+ When this is empty, the LDAP user will be looked based on LDAP username corresponding
+ to the first part of his Kerberos principal. For instance, for principal C(john@KEYCLOAK.ORG),
+ it will assume that LDAP username is V(john).
+ type: str
+ version_added: 8.1.0
+
serverPrincipal:
description:
- Full name of server principal for HTTP service including server and domain name. For
- example C(HTTP/host.foo.org@FOO.ORG). Use C(*) to accept any service principal in the
+ example V(HTTP/host.foo.org@FOO.ORG). Use V(*) to accept any service principal in the
KeyTab file.
type: str
keyTab:
description:
- Location of Kerberos KeyTab file containing the credentials of server principal. For
- example C(/etc/krb5.keytab).
+ example V(/etc/krb5.keytab).
type: str
debug:
@@ -451,7 +458,7 @@ options:
providerId:
description:
- - The mapper type for this mapper (for instance C(user-attribute-ldap-mapper)).
+ - The mapper type for this mapper (for instance V(user-attribute-ldap-mapper)).
type: str
providerType:
@@ -464,6 +471,7 @@ options:
description:
- Dict specifying the configuration options for the mapper; the contents differ
depending on the value of I(identityProviderMapper).
+ # TODO: what is identityProviderMapper above???
type: dict
extends_documentation_fragment:
@@ -763,6 +771,7 @@ def main():
readTimeout=dict(type='int'),
searchScope=dict(type='str', choices=['1', '2'], default='1'),
serverPrincipal=dict(type='str'),
+ krbPrincipalAttribute=dict(type='str'),
startTls=dict(type='bool', default=False),
syncRegistrations=dict(type='bool', default=False),
trustEmail=dict(type='bool', default=False),
@@ -793,7 +802,7 @@ def main():
realm=dict(type='str', default='master'),
id=dict(type='str'),
name=dict(type='str'),
- provider_id=dict(type='str', aliases=['providerId'], choices=['ldap', 'kerberos', 'sssd']),
+ provider_id=dict(type='str', aliases=['providerId']),
provider_type=dict(type='str', aliases=['providerType'], default='org.keycloak.storage.UserStorageProvider'),
parent_id=dict(type='str', aliases=['parentId']),
mappers=dict(type='list', elements='dict', options=mapper_spec),
diff --git a/ansible_collections/community/general/plugins/modules/keycloak_user_rolemapping.py b/ansible_collections/community/general/plugins/modules/keycloak_user_rolemapping.py
index d754e313a..59727a346 100644
--- a/ansible_collections/community/general/plugins/modules/keycloak_user_rolemapping.py
+++ b/ansible_collections/community/general/plugins/modules/keycloak_user_rolemapping.py
@@ -42,8 +42,8 @@ options:
state:
description:
- State of the user_rolemapping.
- - On C(present), the user_rolemapping will be created if it does not yet exist, or updated with the parameters you provide.
- - On C(absent), the user_rolemapping will be removed if it exists.
+ - On V(present), the user_rolemapping will be created if it does not yet exist, or updated with the parameters you provide.
+ - On V(absent), the user_rolemapping will be removed if it exists.
default: 'present'
type: str
choices:
@@ -79,8 +79,8 @@ options:
client_id:
type: str
description:
- - Name of the client to be mapped (different than I(cid)).
- - This parameter is required if I(cid) is not provided (can be replaced by I(cid)
+ - Name of the client to be mapped (different than O(cid)).
+ - This parameter is required if O(cid) is not provided (can be replaced by O(cid)
to reduce the number of API calls that must be made).
cid:
diff --git a/ansible_collections/community/general/plugins/modules/keyring.py b/ansible_collections/community/general/plugins/modules/keyring.py
index ada22ed58..8329b727b 100644
--- a/ansible_collections/community/general/plugins/modules/keyring.py
+++ b/ansible_collections/community/general/plugins/modules/keyring.py
@@ -106,7 +106,7 @@ def del_passphrase(module):
try:
keyring.delete_password(module.params["service"], module.params["username"])
return None
- except keyring.errors.KeyringLocked as keyring_locked_err: # pylint: disable=unused-variable
+ except keyring.errors.KeyringLocked:
delete_argument = (
'echo "%s" | gnome-keyring-daemon --unlock\nkeyring del %s %s\n'
% (
@@ -140,7 +140,7 @@ def set_passphrase(module):
module.params["user_password"],
)
return None
- except keyring.errors.KeyringLocked as keyring_locked_err: # pylint: disable=unused-variable
+ except keyring.errors.KeyringLocked:
set_argument = (
'echo "%s" | gnome-keyring-daemon --unlock\nkeyring set %s %s\n%s\n'
% (
diff --git a/ansible_collections/community/general/plugins/modules/kibana_plugin.py b/ansible_collections/community/general/plugins/modules/kibana_plugin.py
index a52eda2fd..f6744b396 100644
--- a/ansible_collections/community/general/plugins/modules/kibana_plugin.py
+++ b/ansible_collections/community/general/plugins/modules/kibana_plugin.py
@@ -60,7 +60,7 @@ options:
version:
description:
- Version of the plugin to be installed.
- - If plugin exists with previous version, plugin will NOT be updated unless C(force) is set to yes.
+ - If plugin exists with previous version, plugin will B(not) be updated unless O(force) is set to V(true).
type: str
force:
description:
diff --git a/ansible_collections/community/general/plugins/modules/launchd.py b/ansible_collections/community/general/plugins/modules/launchd.py
index 13a8ce086..e5942ea7c 100644
--- a/ansible_collections/community/general/plugins/modules/launchd.py
+++ b/ansible_collections/community/general/plugins/modules/launchd.py
@@ -32,14 +32,14 @@ options:
required: true
state:
description:
- - C(started)/C(stopped) are idempotent actions that will not run
+ - V(started)/V(stopped) are idempotent actions that will not run
commands unless necessary.
- - Launchd does not support C(restarted) nor C(reloaded) natively.
+ - Launchd does not support V(restarted) nor V(reloaded) natively.
These will trigger a stop/start (restarted) or an unload/load
(reloaded).
- - C(restarted) unloads and loads the service before start to ensure
+ - V(restarted) unloads and loads the service before start to ensure
that the latest job definition (plist) is used.
- - C(reloaded) unloads and loads the service to ensure that the latest
+ - V(reloaded) unloads and loads the service to ensure that the latest
job definition (plist) is used. Whether a service is started or
stopped depends on the content of the definition file.
type: str
@@ -54,7 +54,7 @@ options:
- Whether the service should not be restarted automatically by launchd.
- Services might have the 'KeepAlive' attribute set to true in a launchd configuration.
In case this is set to true, stopping a service will cause that launchd starts the service again.
- - Set this option to C(true) to let this module change the 'KeepAlive' attribute to false.
+ - Set this option to V(true) to let this module change the 'KeepAlive' attribute to V(false).
type: bool
default: false
notes:
diff --git a/ansible_collections/community/general/plugins/modules/layman.py b/ansible_collections/community/general/plugins/modules/layman.py
index 940ac30d1..13d514274 100644
--- a/ansible_collections/community/general/plugins/modules/layman.py
+++ b/ansible_collections/community/general/plugins/modules/layman.py
@@ -19,7 +19,6 @@ description:
- Uses Layman to manage an additional repositories for the Portage package manager on Gentoo Linux.
Please note that Layman must be installed on a managed node prior using this module.
requirements:
- - "python >= 2.6"
- layman python module
extends_documentation_fragment:
- community.general.attributes
@@ -32,27 +31,27 @@ options:
name:
description:
- The overlay id to install, synchronize, or uninstall.
- Use 'ALL' to sync all of the installed overlays (can be used only when I(state=updated)).
+ Use 'ALL' to sync all of the installed overlays (can be used only when O(state=updated)).
required: true
type: str
list_url:
description:
- An URL of the alternative overlays list that defines the overlay to install.
- This list will be fetched and saved under C(${overlay_defs})/${name}.xml), where
- C(overlay_defs) is readed from the Layman's configuration.
+ This list will be fetched and saved under C(${overlay_defs}/${name}.xml), where
+ C(overlay_defs) is read from the Layman's configuration.
aliases: [url]
type: str
state:
description:
- - Whether to install (C(present)), sync (C(updated)), or uninstall (C(absent)) the overlay.
+ - Whether to install (V(present)), sync (V(updated)), or uninstall (V(absent)) the overlay.
default: present
choices: [present, absent, updated]
type: str
validate_certs:
description:
- - If C(false), SSL certificates will not be validated. This should only be
- set to C(false) when no other option exists. Prior to 1.9.3 the code
- defaulted to C(false).
+ - If V(false), SSL certificates will not be validated. This should only be
+ set to V(false) when no other option exists. Prior to 1.9.3 the code
+ defaulted to V(false).
type: bool
default: true
'''
diff --git a/ansible_collections/community/general/plugins/modules/ldap_attrs.py b/ansible_collections/community/general/plugins/modules/ldap_attrs.py
index c2cac8644..7986833a6 100644
--- a/ansible_collections/community/general/plugins/modules/ldap_attrs.py
+++ b/ansible_collections/community/general/plugins/modules/ldap_attrs.py
@@ -25,10 +25,10 @@ notes:
bind over a UNIX domain socket. This works well with the default Ubuntu
install for example, which includes a cn=peercred,cn=external,cn=auth ACL
rule allowing root to modify the server configuration. If you need to use
- a simple bind to access your server, pass the credentials in I(bind_dn)
- and I(bind_pw).
- - For I(state=present) and I(state=absent), all value comparisons are
- performed on the server for maximum accuracy. For I(state=exact), values
+ a simple bind to access your server, pass the credentials in O(bind_dn)
+ and O(bind_pw).
+ - For O(state=present) and O(state=absent), all value comparisons are
+ performed on the server for maximum accuracy. For O(state=exact), values
have to be compared in Python, which obviously ignores LDAP matching
rules. This should work out in most cases, but it is theoretically
possible to see spurious changes when target and actual values are
@@ -44,7 +44,8 @@ attributes:
check_mode:
support: full
diff_mode:
- support: none
+ support: full
+ version_added: 8.5.0
options:
state:
required: false
@@ -52,11 +53,11 @@ options:
choices: [present, absent, exact]
default: present
description:
- - The state of the attribute values. If C(present), all given attribute
- values will be added if they're missing. If C(absent), all given
- attribute values will be removed if present. If C(exact), the set of
+ - The state of the attribute values. If V(present), all given attribute
+ values will be added if they're missing. If V(absent), all given
+ attribute values will be removed if present. If V(exact), the set of
attribute values will be forced to exactly those provided and no others.
- If I(state=exact) and the attribute I(value) is empty, all values for
+ If O(state=exact) and the attribute value is empty, all values for
this attribute will be removed.
attributes:
required: true
@@ -69,16 +70,16 @@ options:
readability for long string values by using YAML block modifiers as seen in the
examples for this module.
- Note that when using values that YAML/ansible-core interprets as other types,
- like C(yes), C(no) (booleans), or C(2.10) (float), make sure to quote them if
+ like V(yes), V(no) (booleans), or V(2.10) (float), make sure to quote them if
these are meant to be strings. Otherwise the wrong values may be sent to LDAP.
ordered:
required: false
type: bool
default: false
description:
- - If C(true), prepend list values with X-ORDERED index numbers in all
+ - If V(true), prepend list values with X-ORDERED index numbers in all
attributes specified in the current task. This is useful mostly with
- I(olcAccess) attribute to easily manage LDAP Access Control Lists.
+ C(olcAccess) attribute to easily manage LDAP Access Control Lists.
extends_documentation_fragment:
- community.general.ldap.documentation
- community.general.attributes
@@ -182,7 +183,7 @@ import traceback
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible.module_utils.common.text.converters import to_native, to_bytes, to_text
-from ansible_collections.community.general.plugins.module_utils.ldap import LdapGeneric, gen_specs
+from ansible_collections.community.general.plugins.module_utils.ldap import LdapGeneric, gen_specs, ldap_required_together
import re
@@ -207,7 +208,7 @@ class LdapAttrs(LdapGeneric):
self.ordered = self.module.params['ordered']
def _order_values(self, values):
- """ Preprend X-ORDERED index numbers to attribute's values. """
+ """ Prepend X-ORDERED index numbers to attribute's values. """
ordered_values = []
if isinstance(values, list):
@@ -235,26 +236,38 @@ class LdapAttrs(LdapGeneric):
def add(self):
modlist = []
+ new_attrs = {}
for name, values in self.module.params['attributes'].items():
norm_values = self._normalize_values(values)
+ added_values = []
for value in norm_values:
if self._is_value_absent(name, value):
modlist.append((ldap.MOD_ADD, name, value))
-
- return modlist
+ added_values.append(value)
+ if added_values:
+ new_attrs[name] = norm_values
+ return modlist, {}, new_attrs
def delete(self):
modlist = []
+ old_attrs = {}
+ new_attrs = {}
for name, values in self.module.params['attributes'].items():
norm_values = self._normalize_values(values)
+ removed_values = []
for value in norm_values:
if self._is_value_present(name, value):
+ removed_values.append(value)
modlist.append((ldap.MOD_DELETE, name, value))
-
- return modlist
+ if removed_values:
+ old_attrs[name] = norm_values
+ new_attrs[name] = [value for value in norm_values if value not in removed_values]
+ return modlist, old_attrs, new_attrs
def exact(self):
modlist = []
+ old_attrs = {}
+ new_attrs = {}
for name, values in self.module.params['attributes'].items():
norm_values = self._normalize_values(values)
try:
@@ -272,8 +285,13 @@ class LdapAttrs(LdapGeneric):
modlist.append((ldap.MOD_DELETE, name, None))
else:
modlist.append((ldap.MOD_REPLACE, name, norm_values))
+ old_attrs[name] = current
+ new_attrs[name] = norm_values
+ if len(current) == 1 and len(norm_values) == 1:
+ old_attrs[name] = current[0]
+ new_attrs[name] = norm_values[0]
- return modlist
+ return modlist, old_attrs, new_attrs
def _is_value_present(self, name, value):
""" True if the target attribute has the given value. """
@@ -300,6 +318,7 @@ def main():
state=dict(type='str', default='present', choices=['absent', 'exact', 'present']),
),
supports_check_mode=True,
+ required_together=ldap_required_together(),
)
if not HAS_LDAP:
@@ -308,16 +327,18 @@ def main():
# Instantiate the LdapAttr object
ldap = LdapAttrs(module)
+ old_attrs = None
+ new_attrs = None
state = module.params['state']
# Perform action
if state == 'present':
- modlist = ldap.add()
+ modlist, old_attrs, new_attrs = ldap.add()
elif state == 'absent':
- modlist = ldap.delete()
+ modlist, old_attrs, new_attrs = ldap.delete()
elif state == 'exact':
- modlist = ldap.exact()
+ modlist, old_attrs, new_attrs = ldap.exact()
changed = False
@@ -330,7 +351,7 @@ def main():
except Exception as e:
module.fail_json(msg="Attribute action failed.", details=to_native(e))
- module.exit_json(changed=changed, modlist=modlist)
+ module.exit_json(changed=changed, modlist=modlist, diff={"before": old_attrs, "after": new_attrs})
if __name__ == '__main__':
diff --git a/ansible_collections/community/general/plugins/modules/ldap_entry.py b/ansible_collections/community/general/plugins/modules/ldap_entry.py
index 619bbf927..5deaf7c4c 100644
--- a/ansible_collections/community/general/plugins/modules/ldap_entry.py
+++ b/ansible_collections/community/general/plugins/modules/ldap_entry.py
@@ -24,8 +24,8 @@ notes:
bind over a UNIX domain socket. This works well with the default Ubuntu
install for example, which includes a cn=peercred,cn=external,cn=auth ACL
rule allowing root to modify the server configuration. If you need to use
- a simple bind to access your server, pass the credentials in I(bind_dn)
- and I(bind_pw).
+ a simple bind to access your server, pass the credentials in O(bind_dn)
+ and O(bind_pw).
author:
- Jiri Tyr (@jtyr)
requirements:
@@ -38,7 +38,7 @@ attributes:
options:
attributes:
description:
- - If I(state=present), attributes necessary to create an entry. Existing
+ - If O(state=present), attributes necessary to create an entry. Existing
entries are never modified. To assert specific attribute values on an
existing entry, use M(community.general.ldap_attrs) module instead.
- Each attribute value can be a string for single-valued attributes or
@@ -47,13 +47,13 @@ options:
readability for long string values by using YAML block modifiers as seen in the
examples for this module.
- Note that when using values that YAML/ansible-core interprets as other types,
- like C(yes), C(no) (booleans), or C(2.10) (float), make sure to quote them if
+ like V(yes), V(no) (booleans), or V(2.10) (float), make sure to quote them if
these are meant to be strings. Otherwise the wrong values may be sent to LDAP.
type: dict
default: {}
objectClass:
description:
- - If I(state=present), value or list of values to use when creating
+ - If O(state=present), value or list of values to use when creating
the entry. It can either be a string or an actual list of
strings.
type: list
@@ -66,7 +66,7 @@ options:
type: str
recursive:
description:
- - If I(state=delete), a flag indicating whether a single entry or the
+ - If O(state=delete), a flag indicating whether a single entry or the
whole branch must be deleted.
type: bool
default: false
@@ -151,7 +151,7 @@ import traceback
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible.module_utils.common.text.converters import to_native, to_bytes
-from ansible_collections.community.general.plugins.module_utils.ldap import LdapGeneric, gen_specs
+from ansible_collections.community.general.plugins.module_utils.ldap import LdapGeneric, gen_specs, ldap_required_together
LDAP_IMP_ERR = None
try:
@@ -213,7 +213,7 @@ class LdapEntry(LdapGeneric):
self.connection.delete_s(self.dn)
def _delete_recursive():
- """ Attempt recurive deletion using the subtree-delete control.
+ """ Attempt recursive deletion using the subtree-delete control.
If that fails, do it manually. """
try:
subtree_delete = ldap.controls.ValueLessRequestControl('1.2.840.113556.1.4.805')
@@ -255,6 +255,7 @@ def main():
),
required_if=[('state', 'present', ['objectClass'])],
supports_check_mode=True,
+ required_together=ldap_required_together(),
)
if not HAS_LDAP:
diff --git a/ansible_collections/community/general/plugins/modules/ldap_passwd.py b/ansible_collections/community/general/plugins/modules/ldap_passwd.py
index f47fa330e..5044586b0 100644
--- a/ansible_collections/community/general/plugins/modules/ldap_passwd.py
+++ b/ansible_collections/community/general/plugins/modules/ldap_passwd.py
@@ -20,10 +20,10 @@ description:
notes:
- The default authentication settings will attempt to use a SASL EXTERNAL
bind over a UNIX domain socket. This works well with the default Ubuntu
- install for example, which includes a cn=peercred,cn=external,cn=auth ACL
+ install for example, which includes a C(cn=peercred,cn=external,cn=auth) ACL
rule allowing root to modify the server configuration. If you need to use
- a simple bind to access your server, pass the credentials in I(bind_dn)
- and I(bind_pw).
+ a simple bind to access your server, pass the credentials in O(bind_dn)
+ and O(bind_pw).
author:
- Keller Fuchs (@KellerFuchs)
requirements:
@@ -36,7 +36,7 @@ attributes:
options:
passwd:
description:
- - The (plaintext) password to be set for I(dn).
+ - The (plaintext) password to be set for O(dn).
type: str
extends_documentation_fragment:
- community.general.ldap.documentation
@@ -72,7 +72,7 @@ modlist:
import traceback
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
-from ansible_collections.community.general.plugins.module_utils.ldap import LdapGeneric, gen_specs
+from ansible_collections.community.general.plugins.module_utils.ldap import LdapGeneric, gen_specs, ldap_required_together
LDAP_IMP_ERR = None
try:
@@ -133,6 +133,7 @@ def main():
module = AnsibleModule(
argument_spec=gen_specs(passwd=dict(no_log=True)),
supports_check_mode=True,
+ required_together=ldap_required_together(),
)
if not HAS_LDAP:
diff --git a/ansible_collections/community/general/plugins/modules/ldap_search.py b/ansible_collections/community/general/plugins/modules/ldap_search.py
index ad79a2d73..45744e634 100644
--- a/ansible_collections/community/general/plugins/modules/ldap_search.py
+++ b/ansible_collections/community/general/plugins/modules/ldap_search.py
@@ -21,8 +21,8 @@ notes:
bind over a UNIX domain socket. This works well with the default Ubuntu
install for example, which includes a C(cn=peercred,cn=external,cn=auth) ACL
rule allowing root to modify the server configuration. If you need to use
- a simple bind to access your server, pass the credentials in I(bind_dn)
- and I(bind_pw).
+ a simple bind to access your server, pass the credentials in O(bind_dn)
+ and O(bind_pw).
author:
- Sebastian Pfahl (@eryx12o45)
requirements:
@@ -59,8 +59,27 @@ options:
default: false
type: bool
description:
- - Set to C(true) to return the full attribute schema of entries, not
- their attribute values. Overrides I(attrs) when provided.
+ - Set to V(true) to return the full attribute schema of entries, not
+ their attribute values. Overrides O(attrs) when provided.
+ page_size:
+ default: 0
+ type: int
+ description:
+ - The page size when performing a simple paged result search (RFC 2696).
+ This setting can be tuned to reduce issues with timeouts and server limits.
+ - Setting the page size to V(0) (default) disables paged searching.
+ version_added: 7.1.0
+ base64_attributes:
+ description:
+ - If provided, all attribute values returned that are listed in this option
+ will be Base64 encoded.
+ - If the special value V(*) appears in this list, all attributes will be
+ Base64 encoded.
+ - All other attribute values will be converted to UTF-8 strings. If they
+ contain binary data, please note that invalid UTF-8 bytes will be omitted.
+ type: list
+ elements: str
+ version_added: 7.0.0
extends_documentation_fragment:
- community.general.ldap.documentation
- community.general.attributes
@@ -81,11 +100,28 @@ EXAMPLES = r"""
register: ldap_group_gids
"""
+RESULTS = """
+results:
+ description:
+ - For every entry found, one dictionary will be returned.
+ - Every dictionary contains a key C(dn) with the entry's DN as a value.
+ - Every attribute of the entry found is added to the dictionary. If the key
+ has precisely one value, that value is taken directly, otherwise the key's
+ value is a list.
+ - Note that all values (for single-element lists) and list elements (for multi-valued
+ lists) will be UTF-8 strings. Some might contain Base64-encoded binary data; which
+ ones is determined by the O(base64_attributes) option.
+ type: list
+ elements: dict
+"""
+
+import base64
import traceback
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
-from ansible.module_utils.common.text.converters import to_native
-from ansible_collections.community.general.plugins.module_utils.ldap import LdapGeneric, gen_specs
+from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text
+from ansible.module_utils.six import binary_type, string_types, text_type
+from ansible_collections.community.general.plugins.module_utils.ldap import LdapGeneric, gen_specs, ldap_required_together
LDAP_IMP_ERR = None
try:
@@ -105,8 +141,11 @@ def main():
filter=dict(type='str', default='(objectClass=*)'),
attrs=dict(type='list', elements='str'),
schema=dict(type='bool', default=False),
+ page_size=dict(type='int', default=0),
+ base64_attributes=dict(type='list', elements='str'),
),
supports_check_mode=True,
+ required_together=ldap_required_together(),
)
if not HAS_LDAP:
@@ -118,16 +157,30 @@ def main():
except Exception as exception:
module.fail_json(msg="Attribute action failed.", details=to_native(exception))
- module.exit_json(changed=False)
+
+def _normalize_string(val, convert_to_base64):
+ if isinstance(val, (string_types, binary_type)):
+ if isinstance(val, text_type):
+ val = to_bytes(val, encoding='utf-8')
+ if convert_to_base64:
+ val = to_text(base64.b64encode(val))
+ else:
+ # See https://github.com/ansible/ansible/issues/80258#issuecomment-1477038952 for details.
+ # We want to make sure that all strings are properly UTF-8 encoded, even if they were not,
+ # or happened to be byte strings.
+ val = to_text(val, 'utf-8', errors='replace')
+ # See also https://github.com/ansible-collections/community.general/issues/5704.
+ return val
-def _extract_entry(dn, attrs):
+def _extract_entry(dn, attrs, base64_attributes):
extracted = {'dn': dn}
for attr, val in list(attrs.items()):
+ convert_to_base64 = '*' in base64_attributes or attr in base64_attributes
if len(val) == 1:
- extracted[attr] = val[0]
+ extracted[attr] = _normalize_string(val[0], convert_to_base64)
else:
- extracted[attr] = val
+ extracted[attr] = [_normalize_string(v, convert_to_base64) for v in val]
return extracted
@@ -137,12 +190,14 @@ class LdapSearch(LdapGeneric):
self.filterstr = self.module.params['filter']
self.attrlist = []
+ self.page_size = self.module.params['page_size']
self._load_scope()
self._load_attrs()
self._load_schema()
+ self._base64_attributes = set(self.module.params['base64_attributes'] or [])
def _load_schema(self):
- self.schema = self.module.boolean(self.module.params['schema'])
+ self.schema = self.module.params['schema']
if self.schema:
self.attrsonly = 1
else:
@@ -165,22 +220,32 @@ class LdapSearch(LdapGeneric):
self.module.exit_json(changed=False, results=results)
def perform_search(self):
+ ldap_entries = []
+ controls = []
+ if self.page_size > 0:
+ controls.append(ldap.controls.libldap.SimplePagedResultsControl(True, size=self.page_size, cookie=''))
try:
- results = self.connection.search_s(
- self.dn,
- self.scope,
- filterstr=self.filterstr,
- attrlist=self.attrlist,
- attrsonly=self.attrsonly
- )
- ldap_entries = []
- for result in results:
- if isinstance(result[1], dict):
- if self.schema:
- ldap_entries.append(dict(dn=result[0], attrs=list(result[1].keys())))
- else:
- ldap_entries.append(_extract_entry(result[0], result[1]))
- return ldap_entries
+ while True:
+ response = self.connection.search_ext(
+ self.dn,
+ self.scope,
+ filterstr=self.filterstr,
+ attrlist=self.attrlist,
+ attrsonly=self.attrsonly,
+ serverctrls=controls,
+ )
+ rtype, results, rmsgid, serverctrls = self.connection.result3(response)
+ for result in results:
+ if isinstance(result[1], dict):
+ if self.schema:
+ ldap_entries.append(dict(dn=result[0], attrs=list(result[1].keys())))
+ else:
+ ldap_entries.append(_extract_entry(result[0], result[1], self._base64_attributes))
+ cookies = [c.cookie for c in serverctrls if c.controlType == ldap.controls.libldap.SimplePagedResultsControl.controlType]
+ if self.page_size > 0 and cookies and cookies[0]:
+ controls[0].cookie = cookies[0]
+ else:
+ return ldap_entries
except ldap.NO_SUCH_OBJECT:
self.module.fail_json(msg="Base not found: {0}".format(self.dn))
diff --git a/ansible_collections/community/general/plugins/modules/linode.py b/ansible_collections/community/general/plugins/modules/linode.py
index 404e7a393..9e04ac63d 100644
--- a/ansible_collections/community/general/plugins/modules/linode.py
+++ b/ansible_collections/community/general/plugins/modules/linode.py
@@ -31,7 +31,7 @@ options:
api_key:
description:
- Linode API key.
- - C(LINODE_API_KEY) env variable can be used instead.
+ - E(LINODE_API_KEY) environment variable can be used instead.
type: str
required: true
name:
@@ -124,7 +124,7 @@ options:
private_ip:
description:
- Add private IPv4 address when Linode is created.
- - Default is C(false).
+ - Default is V(false).
type: bool
ssh_pub_key:
description:
@@ -149,7 +149,7 @@ options:
type: int
wait:
description:
- - wait for the instance to be in state C(running) before returning
+ - wait for the instance to be in state V(running) before returning
type: bool
default: true
wait_timeout:
@@ -163,7 +163,6 @@ options:
type: bool
default: true
requirements:
- - python >= 2.6
- linode-python
author:
- Vincent Viallet (@zbal)
diff --git a/ansible_collections/community/general/plugins/modules/linode_v4.py b/ansible_collections/community/general/plugins/modules/linode_v4.py
index f213af125..da885f3a5 100644
--- a/ansible_collections/community/general/plugins/modules/linode_v4.py
+++ b/ansible_collections/community/general/plugins/modules/linode_v4.py
@@ -14,7 +14,6 @@ module: linode_v4
short_description: Manage instances on the Linode cloud
description: Manage instances on the Linode cloud.
requirements:
- - python >= 2.7
- linode_api4 >= 2.0.0
author:
- Luke Murphy (@decentral1se)
@@ -62,7 +61,7 @@ options:
type: str
private_ip:
description:
- - If C(true), the created Linode will have private networking enabled and
+ - If V(true), the created Linode will have private networking enabled and
assigned a private IPv4 address.
type: bool
default: false
@@ -95,7 +94,7 @@ options:
access_token:
description:
- The Linode API v4 access token. It may also be specified by exposing
- the C(LINODE_ACCESS_TOKEN) environment variable. See
+ the E(LINODE_ACCESS_TOKEN) environment variable. See
U(https://www.linode.com/docs/api#access-and-authentication).
required: true
type: str
diff --git a/ansible_collections/community/general/plugins/modules/listen_ports_facts.py b/ansible_collections/community/general/plugins/modules/listen_ports_facts.py
index bc630e1d2..08030a8b3 100644
--- a/ansible_collections/community/general/plugins/modules/listen_ports_facts.py
+++ b/ansible_collections/community/general/plugins/modules/listen_ports_facts.py
@@ -40,7 +40,8 @@ options:
include_non_listening:
description:
- Show both listening and non-listening sockets (for TCP this means established connections).
- - Adds the return values C(state) and C(foreign_address) to the returned facts.
+ - Adds the return values RV(ansible_facts.tcp_listen[].state), RV(ansible_facts.udp_listen[].state),
+ RV(ansible_facts.tcp_listen[].foreign_address), and RV(ansible_facts.udp_listen[].foreign_address) to the returned facts.
type: bool
default: false
version_added: 5.4.0
@@ -96,13 +97,13 @@ ansible_facts:
sample: "0.0.0.0"
foreign_address:
description: The address of the remote end of the socket.
- returned: if I(include_non_listening=true)
+ returned: if O(include_non_listening=true)
type: str
sample: "10.80.0.1"
version_added: 5.4.0
state:
description: The state of the socket.
- returned: if I(include_non_listening=true)
+ returned: if O(include_non_listening=true)
type: str
sample: "ESTABLISHED"
version_added: 5.4.0
@@ -148,13 +149,13 @@ ansible_facts:
sample: "0.0.0.0"
foreign_address:
description: The address of the remote end of the socket.
- returned: if I(include_non_listening=true)
+ returned: if O(include_non_listening=true)
type: str
sample: "10.80.0.1"
version_added: 5.4.0
state:
description: The state of the socket. UDP is a connectionless protocol. Shows UCONN or ESTAB.
- returned: if I(include_non_listening=true)
+ returned: if O(include_non_listening=true)
type: str
sample: "UCONN"
version_added: 5.4.0
@@ -199,7 +200,7 @@ from ansible.module_utils.basic import AnsibleModule
def split_pid_name(pid_name):
"""
Split the entry PID/Program name into the PID (int) and the name (str)
- :param pid_name: PID/Program String seperated with a dash. E.g 51/sshd: returns pid = 51 and name = sshd
+ :param pid_name: PID/Program String separated with a dash. E.g 51/sshd: returns pid = 51 and name = sshd
:return: PID (int) and the program name (str)
"""
try:
diff --git a/ansible_collections/community/general/plugins/modules/locale_gen.py b/ansible_collections/community/general/plugins/modules/locale_gen.py
index fccdf977a..0dd76c9ab 100644
--- a/ansible_collections/community/general/plugins/modules/locale_gen.py
+++ b/ansible_collections/community/general/plugins/modules/locale_gen.py
@@ -35,6 +35,8 @@ options:
- Whether the locale shall be present.
choices: [ absent, present ]
default: present
+notes:
+ - This module does not support RHEL-based systems.
'''
EXAMPLES = '''
@@ -46,154 +48,31 @@ EXAMPLES = '''
import os
import re
-from subprocess import Popen, PIPE, call
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.common.text.converters import to_native
-
-LOCALE_NORMALIZATION = {
- ".utf8": ".UTF-8",
- ".eucjp": ".EUC-JP",
- ".iso885915": ".ISO-8859-15",
- ".cp1251": ".CP1251",
- ".koi8r": ".KOI8-R",
- ".armscii8": ".ARMSCII-8",
- ".euckr": ".EUC-KR",
- ".gbk": ".GBK",
- ".gb18030": ".GB18030",
- ".euctw": ".EUC-TW",
-}
-
-
-# ===========================================
-# location module specific support methods.
-#
-
-def is_available(name, ubuntuMode):
- """Check if the given locale is available on the system. This is done by
- checking either :
- * if the locale is present in /etc/locales.gen
- * or if the locale is present in /usr/share/i18n/SUPPORTED"""
- if ubuntuMode:
- __regexp = r'^(?P<locale>\S+_\S+) (?P<charset>\S+)\s*$'
- __locales_available = '/usr/share/i18n/SUPPORTED'
- else:
- __regexp = r'^#{0,1}\s*(?P<locale>\S+_\S+) (?P<charset>\S+)\s*$'
- __locales_available = '/etc/locale.gen'
-
- re_compiled = re.compile(__regexp)
- fd = open(__locales_available, 'r')
- for line in fd:
- result = re_compiled.match(line)
- if result and result.group('locale') == name:
- return True
- fd.close()
- return False
-
-
-def is_present(name):
- """Checks if the given locale is currently installed."""
- output = Popen(["locale", "-a"], stdout=PIPE).communicate()[0]
- output = to_native(output)
- return any(fix_case(name) == fix_case(line) for line in output.splitlines())
-
-
-def fix_case(name):
- """locale -a might return the encoding in either lower or upper case.
- Passing through this function makes them uniform for comparisons."""
- for s, r in LOCALE_NORMALIZATION.items():
- name = name.replace(s, r)
- return name
-
-
-def replace_line(existing_line, new_line):
- """Replaces lines in /etc/locale.gen"""
- try:
- f = open("/etc/locale.gen", "r")
- lines = [line.replace(existing_line, new_line) for line in f]
- finally:
- f.close()
- try:
- f = open("/etc/locale.gen", "w")
- f.write("".join(lines))
- finally:
- f.close()
-
-
-def set_locale(name, enabled=True):
- """ Sets the state of the locale. Defaults to enabled. """
- search_string = r'#{0,1}\s*%s (?P<charset>.+)' % name
- if enabled:
- new_string = r'%s \g<charset>' % (name)
- else:
- new_string = r'# %s \g<charset>' % (name)
- try:
- f = open("/etc/locale.gen", "r")
- lines = [re.sub(search_string, new_string, line) for line in f]
- finally:
- f.close()
- try:
- f = open("/etc/locale.gen", "w")
- f.write("".join(lines))
- finally:
- f.close()
-
-
-def apply_change(targetState, name):
- """Create or remove locale.
-
- Keyword arguments:
- targetState -- Desired state, either present or absent.
- name -- Name including encoding such as de_CH.UTF-8.
- """
- if targetState == "present":
- # Create locale.
- set_locale(name, enabled=True)
- else:
- # Delete locale.
- set_locale(name, enabled=False)
-
- localeGenExitValue = call("locale-gen")
- if localeGenExitValue != 0:
- raise EnvironmentError(localeGenExitValue, "locale.gen failed to execute, it returned " + str(localeGenExitValue))
-
-
-def apply_change_ubuntu(targetState, name):
- """Create or remove locale.
-
- Keyword arguments:
- targetState -- Desired state, either present or absent.
- name -- Name including encoding such as de_CH.UTF-8.
- """
- if targetState == "present":
- # Create locale.
- # Ubuntu's patched locale-gen automatically adds the new locale to /var/lib/locales/supported.d/local
- localeGenExitValue = call(["locale-gen", name])
- else:
- # Delete locale involves discarding the locale from /var/lib/locales/supported.d/local and regenerating all locales.
- try:
- f = open("/var/lib/locales/supported.d/local", "r")
- content = f.readlines()
- finally:
- f.close()
- try:
- f = open("/var/lib/locales/supported.d/local", "w")
- for line in content:
- locale, charset = line.split(' ')
- if locale != name:
- f.write(line)
- finally:
- f.close()
- # Purge locales and regenerate.
- # Please provide a patch if you know how to avoid regenerating the locales to keep!
- localeGenExitValue = call(["locale-gen", "--purge"])
-
- if localeGenExitValue != 0:
- raise EnvironmentError(localeGenExitValue, "locale.gen failed to execute, it returned " + str(localeGenExitValue))
-
-def main():
- module = AnsibleModule(
+from ansible_collections.community.general.plugins.module_utils.module_helper import StateModuleHelper
+from ansible_collections.community.general.plugins.module_utils.mh.deco import check_mode_skip
+
+from ansible_collections.community.general.plugins.module_utils.locale_gen import locale_runner, locale_gen_runner
+
+
+class LocaleGen(StateModuleHelper):
+ LOCALE_NORMALIZATION = {
+ ".utf8": ".UTF-8",
+ ".eucjp": ".EUC-JP",
+ ".iso885915": ".ISO-8859-15",
+ ".cp1251": ".CP1251",
+ ".koi8r": ".KOI8-R",
+ ".armscii8": ".ARMSCII-8",
+ ".euckr": ".EUC-KR",
+ ".gbk": ".GBK",
+ ".gb18030": ".GB18030",
+ ".euctw": ".EUC-TW",
+ }
+ LOCALE_GEN = "/etc/locale.gen"
+ LOCALE_SUPPORTED = "/var/lib/locales/supported.d/"
+
+ output_params = ["name"]
+ module = dict(
argument_spec=dict(
name=dict(type='str', required=True),
state=dict(type='str', default='present', choices=['absent', 'present']),
@@ -201,42 +80,133 @@ def main():
supports_check_mode=True,
)
- name = module.params['name']
- state = module.params['state']
-
- if not os.path.exists("/var/lib/locales/supported.d/"):
- if os.path.exists("/etc/locale.gen"):
- # We found the common way to manage locales.
- ubuntuMode = False
+ def __init_module__(self):
+ self.vars.set("ubuntu_mode", False)
+ if os.path.exists(self.LOCALE_SUPPORTED):
+ self.vars.ubuntu_mode = True
+ else:
+ if not os.path.exists(self.LOCALE_GEN):
+ self.do_raise("{0} and {1} are missing. Is the package \"locales\" installed?".format(
+ self.LOCALE_SUPPORTED, self.LOCALE_GEN
+ ))
+
+ if not self.is_available():
+ self.do_raise("The locale you've entered is not available on your system.")
+
+ self.vars.set("is_present", self.is_present(), output=False)
+ self.vars.set("state_tracking", self._state_name(self.vars.is_present), output=False, change=True)
+
+ def __quit_module__(self):
+ self.vars.state_tracking = self._state_name(self.is_present())
+
+ @staticmethod
+ def _state_name(present):
+ return "present" if present else "absent"
+
+ def is_available(self):
+ """Check if the given locale is available on the system. This is done by
+ checking either :
+ * if the locale is present in /etc/locales.gen
+ * or if the locale is present in /usr/share/i18n/SUPPORTED"""
+ __regexp = r'^#?\s*(?P<locale>\S+[\._\S]+) (?P<charset>\S+)\s*$'
+ if self.vars.ubuntu_mode:
+ __locales_available = '/usr/share/i18n/SUPPORTED'
+ else:
+ __locales_available = '/etc/locale.gen'
+
+ re_compiled = re.compile(__regexp)
+ with open(__locales_available, 'r') as fd:
+ lines = fd.readlines()
+ res = [re_compiled.match(line) for line in lines]
+ if self.verbosity >= 4:
+ self.vars.available_lines = lines
+ if any(r.group("locale") == self.vars.name for r in res if r):
+ return True
+ # locale may be installed but not listed in the file, for example C.UTF-8 in some systems
+ return self.is_present()
+
+ def is_present(self):
+ runner = locale_runner(self.module)
+ with runner() as ctx:
+ rc, out, err = ctx.run()
+ if self.verbosity >= 4:
+ self.vars.locale_run_info = ctx.run_info
+ return any(self.fix_case(self.vars.name) == self.fix_case(line) for line in out.splitlines())
+
+ def fix_case(self, name):
+ """locale -a might return the encoding in either lower or upper case.
+ Passing through this function makes them uniform for comparisons."""
+ for s, r in self.LOCALE_NORMALIZATION.items():
+ name = name.replace(s, r)
+ return name
+
+ def set_locale(self, name, enabled=True):
+ """ Sets the state of the locale. Defaults to enabled. """
+ search_string = r'#?\s*%s (?P<charset>.+)' % re.escape(name)
+ if enabled:
+ new_string = r'%s \g<charset>' % (name)
else:
- module.fail_json(msg="/etc/locale.gen and /var/lib/locales/supported.d/local are missing. Is the package \"locales\" installed?")
- else:
- # Ubuntu created its own system to manage locales.
- ubuntuMode = True
-
- if not is_available(name, ubuntuMode):
- module.fail_json(msg="The locale you've entered is not available "
- "on your system.")
-
- if is_present(name):
- prev_state = "present"
- else:
- prev_state = "absent"
- changed = (prev_state != state)
-
- if module.check_mode:
- module.exit_json(changed=changed)
- else:
- if changed:
- try:
- if ubuntuMode is False:
- apply_change(state, name)
- else:
- apply_change_ubuntu(state, name)
- except EnvironmentError as e:
- module.fail_json(msg=to_native(e), exitValue=e.errno)
-
- module.exit_json(name=name, changed=changed, msg="OK")
+ new_string = r'# %s \g<charset>' % (name)
+ re_search = re.compile(search_string)
+ with open("/etc/locale.gen", "r") as fr:
+ lines = [re_search.sub(new_string, line) for line in fr]
+ with open("/etc/locale.gen", "w") as fw:
+ fw.write("".join(lines))
+
+ def apply_change(self, targetState, name):
+ """Create or remove locale.
+
+ Keyword arguments:
+ targetState -- Desired state, either present or absent.
+ name -- Name including encoding such as de_CH.UTF-8.
+ """
+
+ self.set_locale(name, enabled=(targetState == "present"))
+
+ runner = locale_gen_runner(self.module)
+ with runner() as ctx:
+ ctx.run()
+
+ def apply_change_ubuntu(self, targetState, name):
+ """Create or remove locale.
+
+ Keyword arguments:
+ targetState -- Desired state, either present or absent.
+ name -- Name including encoding such as de_CH.UTF-8.
+ """
+ runner = locale_gen_runner(self.module)
+
+ if targetState == "present":
+ # Create locale.
+ # Ubuntu's patched locale-gen automatically adds the new locale to /var/lib/locales/supported.d/local
+ with runner() as ctx:
+ ctx.run()
+ else:
+ # Delete locale involves discarding the locale from /var/lib/locales/supported.d/local and regenerating all locales.
+ with open("/var/lib/locales/supported.d/local", "r") as fr:
+ content = fr.readlines()
+ with open("/var/lib/locales/supported.d/local", "w") as fw:
+ for line in content:
+ locale, charset = line.split(' ')
+ if locale != name:
+ fw.write(line)
+ # Purge locales and regenerate.
+ # Please provide a patch if you know how to avoid regenerating the locales to keep!
+ with runner("purge") as ctx:
+ ctx.run()
+
+ @check_mode_skip
+ def __state_fallback__(self):
+ if self.vars.state_tracking == self.vars.state:
+ return
+ if self.vars.ubuntu_mode:
+ self.apply_change_ubuntu(self.vars.state, self.vars.name)
+ else:
+ self.apply_change(self.vars.state, self.vars.name)
+
+
+def main():
+ LocaleGen.execute()
if __name__ == '__main__':
diff --git a/ansible_collections/community/general/plugins/modules/lvg.py b/ansible_collections/community/general/plugins/modules/lvg.py
index 60eaaa42b..8a6384369 100644
--- a/ansible_collections/community/general/plugins/modules/lvg.py
+++ b/ansible_collections/community/general/plugins/modules/lvg.py
@@ -39,10 +39,10 @@ options:
elements: str
pesize:
description:
- - "The size of the physical extent. I(pesize) must be a power of 2 of at least 1 sector
+ - "The size of the physical extent. O(pesize) must be a power of 2 of at least 1 sector
(where the sector size is the largest sector size of the PVs currently used in the VG),
or at least 128KiB."
- - Since Ansible 2.6, pesize can be optionally suffixed by a UNIT (k/K/m/M/g/G), default unit is megabyte.
+ - O(pesize) can be optionally suffixed by a UNIT (k/K/m/M/g/G), default unit is megabyte.
type: str
default: "4"
pv_options:
@@ -52,7 +52,7 @@ options:
default: ''
pvresize:
description:
- - If C(true), resize the physical volume to the maximum available size.
+ - If V(true), resize the physical volume to the maximum available size.
type: bool
default: false
version_added: '0.2.0'
@@ -63,15 +63,33 @@ options:
default: ''
state:
description:
- - Control if the volume group exists.
+ - Control if the volume group exists and it's state.
+ - The states V(active) and V(inactive) implies V(present) state. Added in 7.1.0
+ - "If V(active) or V(inactive), the module manages the VG's logical volumes current state.
+ The module also handles the VG's autoactivation state if supported
+ unless when creating a volume group and the autoactivation option specified in O(vg_options)."
type: str
- choices: [ absent, present ]
+ choices: [ absent, present, active, inactive ]
default: present
force:
description:
- - If C(true), allows to remove volume group with logical volumes.
+ - If V(true), allows to remove volume group with logical volumes.
type: bool
default: false
+ reset_vg_uuid:
+ description:
+ - Whether the volume group's UUID is regenerated.
+ - This is B(not idempotent). Specifying this parameter always results in a change.
+ type: bool
+ default: false
+ version_added: 7.1.0
+ reset_pv_uuid:
+ description:
+ - Whether the volume group's physical volumes' UUIDs are regenerated.
+ - This is B(not idempotent). Specifying this parameter always results in a change.
+ type: bool
+ default: false
+ version_added: 7.1.0
seealso:
- module: community.general.filesystem
- module: community.general.lvol
@@ -112,6 +130,30 @@ EXAMPLES = r'''
vg: resizableVG
pvs: /dev/sda3
pvresize: true
+
+- name: Deactivate a volume group
+ community.general.lvg:
+ state: inactive
+ vg: vg.services
+
+- name: Activate a volume group
+ community.general.lvg:
+ state: active
+ vg: vg.services
+
+- name: Reset a volume group UUID
+ community.general.lvg:
+ state: inactive
+ vg: vg.services
+ reset_vg_uuid: true
+
+- name: Reset both volume group and pv UUID
+ community.general.lvg:
+ state: inactive
+ vg: vg.services
+ pvs: /dev/sdb1,/dev/sdc5
+ reset_vg_uuid: true
+ reset_pv_uuid: true
'''
import itertools
@@ -119,6 +161,8 @@ import os
from ansible.module_utils.basic import AnsibleModule
+VG_AUTOACTIVATION_OPT = '--setautoactivation'
+
def parse_vgs(data):
vgs = []
@@ -156,6 +200,178 @@ def parse_pvs(module, data):
return pvs
+def find_vg(module, vg):
+ if not vg:
+ return None
+ vgs_cmd = module.get_bin_path('vgs', True)
+ dummy, current_vgs, dummy = module.run_command("%s --noheadings -o vg_name,pv_count,lv_count --separator ';'" % vgs_cmd, check_rc=True)
+
+ vgs = parse_vgs(current_vgs)
+
+ for test_vg in vgs:
+ if test_vg['name'] == vg:
+ this_vg = test_vg
+ break
+ else:
+ this_vg = None
+
+ return this_vg
+
+
+def is_autoactivation_supported(module, vg_cmd):
+ autoactivation_supported = False
+ dummy, vgchange_opts, dummy = module.run_command([vg_cmd, '--help'], check_rc=True)
+
+ if VG_AUTOACTIVATION_OPT in vgchange_opts:
+ autoactivation_supported = True
+
+ return autoactivation_supported
+
+
+def activate_vg(module, vg, active):
+ changed = False
+ vgchange_cmd = module.get_bin_path('vgchange', True)
+ vgs_cmd = module.get_bin_path('vgs', True)
+ vgs_fields = ['lv_attr']
+
+ autoactivation_enabled = False
+ autoactivation_supported = is_autoactivation_supported(module=module, vg_cmd=vgchange_cmd)
+
+ if autoactivation_supported:
+ vgs_fields.append('autoactivation')
+
+ vgs_cmd_with_opts = [vgs_cmd, '--noheadings', '-o', ','.join(vgs_fields), '--separator', ';', vg]
+ dummy, current_vg_lv_states, dummy = module.run_command(vgs_cmd_with_opts, check_rc=True)
+
+ lv_active_count = 0
+ lv_inactive_count = 0
+
+ for line in current_vg_lv_states.splitlines():
+ parts = line.strip().split(';')
+ if parts[0][4] == 'a':
+ lv_active_count += 1
+ else:
+ lv_inactive_count += 1
+ if autoactivation_supported:
+ autoactivation_enabled = autoactivation_enabled or parts[1] == 'enabled'
+
+ activate_flag = None
+ if active and lv_inactive_count > 0:
+ activate_flag = 'y'
+ elif not active and lv_active_count > 0:
+ activate_flag = 'n'
+
+ # Extra logic necessary because vgchange returns error when autoactivation is already set
+ if autoactivation_supported:
+ if active and not autoactivation_enabled:
+ if module.check_mode:
+ changed = True
+ else:
+ module.run_command([vgchange_cmd, VG_AUTOACTIVATION_OPT, 'y', vg], check_rc=True)
+ changed = True
+ elif not active and autoactivation_enabled:
+ if module.check_mode:
+ changed = True
+ else:
+ module.run_command([vgchange_cmd, VG_AUTOACTIVATION_OPT, 'n', vg], check_rc=True)
+ changed = True
+
+ if activate_flag is not None:
+ if module.check_mode:
+ changed = True
+ else:
+ module.run_command([vgchange_cmd, '--activate', activate_flag, vg], check_rc=True)
+ changed = True
+
+ return changed
+
+
+def append_vgcreate_options(module, state, vgoptions):
+ vgcreate_cmd = module.get_bin_path('vgcreate', True)
+
+ autoactivation_supported = is_autoactivation_supported(module=module, vg_cmd=vgcreate_cmd)
+
+ if autoactivation_supported and state in ['active', 'inactive']:
+ if VG_AUTOACTIVATION_OPT not in vgoptions:
+ if state == 'active':
+ vgoptions += [VG_AUTOACTIVATION_OPT, 'y']
+ else:
+ vgoptions += [VG_AUTOACTIVATION_OPT, 'n']
+
+
+def get_pv_values_for_resize(module, device):
+ pvdisplay_cmd = module.get_bin_path('pvdisplay', True)
+ pvdisplay_ops = ["--units", "b", "--columns", "--noheadings", "--nosuffix", "--separator", ";", "-o", "dev_size,pv_size,pe_start,vg_extent_size"]
+ pvdisplay_cmd_device_options = [pvdisplay_cmd, device] + pvdisplay_ops
+
+ dummy, pv_values, dummy = module.run_command(pvdisplay_cmd_device_options, check_rc=True)
+
+ values = pv_values.strip().split(';')
+
+ dev_size = int(values[0])
+ pv_size = int(values[1])
+ pe_start = int(values[2])
+ vg_extent_size = int(values[3])
+
+ return (dev_size, pv_size, pe_start, vg_extent_size)
+
+
+def resize_pv(module, device):
+ changed = False
+ pvresize_cmd = module.get_bin_path('pvresize', True)
+
+ dev_size, pv_size, pe_start, vg_extent_size = get_pv_values_for_resize(module=module, device=device)
+ if (dev_size - (pe_start + pv_size)) > vg_extent_size:
+ if module.check_mode:
+ changed = True
+ else:
+ # If there is a missing pv on the machine, versions of pvresize rc indicates failure.
+ rc, out, err = module.run_command([pvresize_cmd, device])
+ dummy, new_pv_size, dummy, dummy = get_pv_values_for_resize(module=module, device=device)
+ if pv_size == new_pv_size:
+ module.fail_json(msg="Failed executing pvresize command.", rc=rc, err=err, out=out)
+ else:
+ changed = True
+
+ return changed
+
+
+def reset_uuid_pv(module, device):
+ changed = False
+ pvs_cmd = module.get_bin_path('pvs', True)
+ pvs_cmd_with_opts = [pvs_cmd, '--noheadings', '-o', 'uuid', device]
+ pvchange_cmd = module.get_bin_path('pvchange', True)
+ pvchange_cmd_with_opts = [pvchange_cmd, '-u', device]
+
+ dummy, orig_uuid, dummy = module.run_command(pvs_cmd_with_opts, check_rc=True)
+
+ if module.check_mode:
+ changed = True
+ else:
+ # If there is a missing pv on the machine, pvchange rc indicates failure.
+ pvchange_rc, pvchange_out, pvchange_err = module.run_command(pvchange_cmd_with_opts)
+ dummy, new_uuid, dummy = module.run_command(pvs_cmd_with_opts, check_rc=True)
+ if orig_uuid.strip() == new_uuid.strip():
+ module.fail_json(msg="PV (%s) UUID change failed" % (device), rc=pvchange_rc, err=pvchange_err, out=pvchange_out)
+ else:
+ changed = True
+
+ return changed
+
+
+def reset_uuid_vg(module, vg):
+ changed = False
+ vgchange_cmd = module.get_bin_path('vgchange', True)
+ vgchange_cmd_with_opts = [vgchange_cmd, '-u', vg]
+ if module.check_mode:
+ changed = True
+ else:
+ module.run_command(vgchange_cmd_with_opts, check_rc=True)
+ changed = True
+
+ return changed
+
+
def main():
module = AnsibleModule(
argument_spec=dict(
@@ -165,9 +381,14 @@ def main():
pv_options=dict(type='str', default=''),
pvresize=dict(type='bool', default=False),
vg_options=dict(type='str', default=''),
- state=dict(type='str', default='present', choices=['absent', 'present']),
+ state=dict(type='str', default='present', choices=['absent', 'present', 'active', 'inactive']),
force=dict(type='bool', default=False),
+ reset_vg_uuid=dict(type='bool', default=False),
+ reset_pv_uuid=dict(type='bool', default=False),
),
+ required_if=[
+ ['reset_pv_uuid', True, ['pvs']],
+ ],
supports_check_mode=True,
)
@@ -178,18 +399,25 @@ def main():
pesize = module.params['pesize']
pvoptions = module.params['pv_options'].split()
vgoptions = module.params['vg_options'].split()
+ reset_vg_uuid = module.boolean(module.params['reset_vg_uuid'])
+ reset_pv_uuid = module.boolean(module.params['reset_pv_uuid'])
+
+ this_vg = find_vg(module=module, vg=vg)
+ present_state = state in ['present', 'active', 'inactive']
+ pvs_required = present_state and this_vg is None
+ changed = False
dev_list = []
if module.params['pvs']:
dev_list = list(module.params['pvs'])
- elif state == 'present':
+ elif pvs_required:
module.fail_json(msg="No physical volumes given.")
# LVM always uses real paths not symlinks so replace symlinks with actual path
for idx, dev in enumerate(dev_list):
dev_list[idx] = os.path.realpath(dev)
- if state == 'present':
+ if present_state:
# check given devices
for test_dev in dev_list:
if not os.path.exists(test_dev):
@@ -216,25 +444,9 @@ def main():
if used_pvs:
module.fail_json(msg="Device %s is already in %s volume group." % (used_pvs[0]['name'], used_pvs[0]['vg_name']))
- vgs_cmd = module.get_bin_path('vgs', True)
- rc, current_vgs, err = module.run_command("%s --noheadings -o vg_name,pv_count,lv_count --separator ';'" % vgs_cmd)
-
- if rc != 0:
- module.fail_json(msg="Failed executing vgs command.", rc=rc, err=err)
-
- changed = False
-
- vgs = parse_vgs(current_vgs)
-
- for test_vg in vgs:
- if test_vg['name'] == vg:
- this_vg = test_vg
- break
- else:
- this_vg = None
-
if this_vg is None:
- if state == 'present':
+ if present_state:
+ append_vgcreate_options(module=module, state=state, vgoptions=vgoptions)
# create VG
if module.check_mode:
changed = True
@@ -268,68 +480,61 @@ def main():
module.fail_json(msg="Failed to remove volume group %s" % (vg), rc=rc, err=err)
else:
module.fail_json(msg="Refuse to remove non-empty volume group %s without force=true" % (vg))
+ # activate/deactivate existing VG
+ elif state == 'active':
+ changed = activate_vg(module=module, vg=vg, active=True)
+ elif state == 'inactive':
+ changed = activate_vg(module=module, vg=vg, active=False)
+
+ # reset VG uuid
+ if reset_vg_uuid:
+ changed = reset_uuid_vg(module=module, vg=vg) or changed
# resize VG
- current_devs = [os.path.realpath(pv['name']) for pv in pvs if pv['vg_name'] == vg]
- devs_to_remove = list(set(current_devs) - set(dev_list))
- devs_to_add = list(set(dev_list) - set(current_devs))
-
- if current_devs:
- if state == 'present' and pvresize:
- for device in current_devs:
- pvresize_cmd = module.get_bin_path('pvresize', True)
- pvdisplay_cmd = module.get_bin_path('pvdisplay', True)
- pvdisplay_ops = ["--units", "b", "--columns", "--noheadings", "--nosuffix"]
- pvdisplay_cmd_device_options = [pvdisplay_cmd, device] + pvdisplay_ops
- rc, dev_size, err = module.run_command(pvdisplay_cmd_device_options + ["-o", "dev_size"])
- dev_size = int(dev_size.replace(" ", ""))
- rc, pv_size, err = module.run_command(pvdisplay_cmd_device_options + ["-o", "pv_size"])
- pv_size = int(pv_size.replace(" ", ""))
- rc, pe_start, err = module.run_command(pvdisplay_cmd_device_options + ["-o", "pe_start"])
- pe_start = int(pe_start.replace(" ", ""))
- rc, vg_extent_size, err = module.run_command(pvdisplay_cmd_device_options + ["-o", "vg_extent_size"])
- vg_extent_size = int(vg_extent_size.replace(" ", ""))
- if (dev_size - (pe_start + pv_size)) > vg_extent_size:
- if module.check_mode:
+ if dev_list:
+ current_devs = [os.path.realpath(pv['name']) for pv in pvs if pv['vg_name'] == vg]
+ devs_to_remove = list(set(current_devs) - set(dev_list))
+ devs_to_add = list(set(dev_list) - set(current_devs))
+
+ if current_devs:
+ if present_state:
+ for device in current_devs:
+ if pvresize:
+ changed = resize_pv(module=module, device=device) or changed
+ if reset_pv_uuid:
+ changed = reset_uuid_pv(module=module, device=device) or changed
+
+ if devs_to_add or devs_to_remove:
+ if module.check_mode:
+ changed = True
+ else:
+ if devs_to_add:
+ devs_to_add_string = ' '.join(devs_to_add)
+ # create PV
+ pvcreate_cmd = module.get_bin_path('pvcreate', True)
+ for current_dev in devs_to_add:
+ rc, dummy, err = module.run_command([pvcreate_cmd] + pvoptions + ['-f', str(current_dev)])
+ if rc == 0:
+ changed = True
+ else:
+ module.fail_json(msg="Creating physical volume '%s' failed" % current_dev, rc=rc, err=err)
+ # add PV to our VG
+ vgextend_cmd = module.get_bin_path('vgextend', True)
+ rc, dummy, err = module.run_command("%s %s %s" % (vgextend_cmd, vg, devs_to_add_string))
+ if rc == 0:
changed = True
else:
- rc, dummy, err = module.run_command([pvresize_cmd, device])
- if rc != 0:
- module.fail_json(msg="Failed executing pvresize command.", rc=rc, err=err)
- else:
- changed = True
+ module.fail_json(msg="Unable to extend %s by %s." % (vg, devs_to_add_string), rc=rc, err=err)
- if devs_to_add or devs_to_remove:
- if module.check_mode:
- changed = True
- else:
- if devs_to_add:
- devs_to_add_string = ' '.join(devs_to_add)
- # create PV
- pvcreate_cmd = module.get_bin_path('pvcreate', True)
- for current_dev in devs_to_add:
- rc, dummy, err = module.run_command([pvcreate_cmd] + pvoptions + ['-f', str(current_dev)])
+ # remove some PV from our VG
+ if devs_to_remove:
+ devs_to_remove_string = ' '.join(devs_to_remove)
+ vgreduce_cmd = module.get_bin_path('vgreduce', True)
+ rc, dummy, err = module.run_command("%s --force %s %s" % (vgreduce_cmd, vg, devs_to_remove_string))
if rc == 0:
changed = True
else:
- module.fail_json(msg="Creating physical volume '%s' failed" % current_dev, rc=rc, err=err)
- # add PV to our VG
- vgextend_cmd = module.get_bin_path('vgextend', True)
- rc, dummy, err = module.run_command("%s %s %s" % (vgextend_cmd, vg, devs_to_add_string))
- if rc == 0:
- changed = True
- else:
- module.fail_json(msg="Unable to extend %s by %s." % (vg, devs_to_add_string), rc=rc, err=err)
-
- # remove some PV from our VG
- if devs_to_remove:
- devs_to_remove_string = ' '.join(devs_to_remove)
- vgreduce_cmd = module.get_bin_path('vgreduce', True)
- rc, dummy, err = module.run_command("%s --force %s %s" % (vgreduce_cmd, vg, devs_to_remove_string))
- if rc == 0:
- changed = True
- else:
- module.fail_json(msg="Unable to reduce %s by %s." % (vg, devs_to_remove_string), rc=rc, err=err)
+ module.fail_json(msg="Unable to reduce %s by %s." % (vg, devs_to_remove_string), rc=rc, err=err)
module.exit_json(changed=changed)
diff --git a/ansible_collections/community/general/plugins/modules/lvg_rename.py b/ansible_collections/community/general/plugins/modules/lvg_rename.py
new file mode 100644
index 000000000..bd48ffa62
--- /dev/null
+++ b/ansible_collections/community/general/plugins/modules/lvg_rename.py
@@ -0,0 +1,170 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) Contributors to the Ansible project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+DOCUMENTATION = r'''
+---
+author:
+ - Laszlo Szomor (@lszomor)
+module: lvg_rename
+short_description: Renames LVM volume groups
+description:
+ - This module renames volume groups using the C(vgchange) command.
+extends_documentation_fragment:
+ - community.general.attributes
+attributes:
+ check_mode:
+ support: full
+ diff_mode:
+ support: full
+version_added: 7.1.0
+options:
+ vg:
+ description:
+ - The name or UUID of the source VG.
+ - See V(vgrename(8\)) for valid values.
+ type: str
+ required: true
+ vg_new:
+ description:
+ - The new name of the VG.
+ - See V(lvm(8\)) for valid names.
+ type: str
+ required: true
+seealso:
+- module: community.general.lvg
+notes:
+ - This module does not modify VG renaming-related configurations like C(fstab) entries or boot parameters.
+'''
+
+EXAMPLES = r'''
+- name: Rename a VG by name
+ community.general.lvg_rename:
+ vg: vg_orig_name
+ vg_new: vg_new_name
+
+- name: Rename a VG by UUID
+ community.general.lvg_rename:
+ vg_uuid: SNgd0Q-rPYa-dPB8-U1g6-4WZI-qHID-N7y9Vj
+ vg_new: vg_new_name
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+
+argument_spec = dict(
+ vg=dict(type='str', required=True,),
+ vg_new=dict(type='str', required=True,),
+)
+
+
+class LvgRename(object):
+ def __init__(self, module):
+ '''
+ Orchestrates the lvg_rename module logic.
+
+ :param module: An AnsibleModule instance.
+ '''
+ self.module = module
+ self.result = {'changed': False}
+ self.vg_list = []
+ self._load_params()
+
+ def run(self):
+ """Performs the module logic."""
+
+ self._load_vg_list()
+
+ old_vg_exists = self._is_vg_exists(vg=self.vg)
+ new_vg_exists = self._is_vg_exists(vg=self.vg_new)
+
+ if old_vg_exists:
+ if new_vg_exists:
+ self.module.fail_json(msg='The new VG name (%s) is already in use.' % (self.vg_new))
+ else:
+ self._rename_vg()
+ else:
+ if new_vg_exists:
+ self.result['msg'] = 'The new VG (%s) already exists, nothing to do.' % (self.vg_new)
+ self.module.exit_json(**self.result)
+ else:
+ self.module.fail_json(msg='Both current (%s) and new (%s) VG are missing.' % (self.vg, self.vg_new))
+
+ self.module.exit_json(**self.result)
+
+ def _load_params(self):
+ """Load the parameters from the module."""
+
+ self.vg = self.module.params['vg']
+ self.vg_new = self.module.params['vg_new']
+
+ def _load_vg_list(self):
+ """Load the VGs from the system."""
+
+ vgs_cmd = self.module.get_bin_path('vgs', required=True)
+ vgs_cmd_with_opts = [vgs_cmd, '--noheadings', '--separator', ';', '-o', 'vg_name,vg_uuid']
+ dummy, vg_raw_list, dummy = self.module.run_command(vgs_cmd_with_opts, check_rc=True)
+
+ for vg_info in vg_raw_list.splitlines():
+ vg_name, vg_uuid = vg_info.strip().split(';')
+ self.vg_list.append(vg_name)
+ self.vg_list.append(vg_uuid)
+
+ def _is_vg_exists(self, vg):
+ '''
+ Checks VG existence by name or UUID. It removes the '/dev/' prefix before checking.
+
+ :param vg: A string with the name or UUID of the VG.
+ :returns: A boolean indicates whether the VG exists or not.
+ '''
+
+ vg_found = False
+ dev_prefix = '/dev/'
+
+ if vg.startswith(dev_prefix):
+ vg_id = vg[len(dev_prefix):]
+ else:
+ vg_id = vg
+
+ vg_found = vg_id in self.vg_list
+
+ return vg_found
+
+ def _rename_vg(self):
+ """Renames the volume group."""
+
+ vgrename_cmd = self.module.get_bin_path('vgrename', required=True)
+
+ if self.module._diff:
+ self.result['diff'] = {'before': {'vg': self.vg}, 'after': {'vg': self.vg_new}}
+
+ if self.module.check_mode:
+ self.result['msg'] = "Running in check mode. The module would rename VG %s to %s." % (self.vg, self.vg_new)
+ self.result['changed'] = True
+ else:
+ vgrename_cmd_with_opts = [vgrename_cmd, self.vg, self.vg_new]
+ dummy, vg_rename_out, dummy = self.module.run_command(vgrename_cmd_with_opts, check_rc=True)
+
+ self.result['msg'] = vg_rename_out
+ self.result['changed'] = True
+
+
+def setup_module_object():
+ module = AnsibleModule(argument_spec=argument_spec,
+ supports_check_mode=True)
+ return module
+
+
+def main():
+ module = setup_module_object()
+ lvg_rename = LvgRename(module=module)
+ lvg_rename.run()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/general/plugins/modules/lvol.py b/ansible_collections/community/general/plugins/modules/lvol.py
index d193a4e83..a2a870260 100644
--- a/ansible_collections/community/general/plugins/modules/lvol.py
+++ b/ansible_collections/community/general/plugins/modules/lvol.py
@@ -41,18 +41,18 @@ options:
description:
- The size of the logical volume, according to lvcreate(8) --size, by
default in megabytes or optionally with one of [bBsSkKmMgGtTpPeE] units; or
- according to lvcreate(8) --extents as a percentage of [VG|PVS|FREE];
+ according to lvcreate(8) --extents as a percentage of [VG|PVS|FREE|ORIGIN];
Float values must begin with a digit.
- When resizing, apart from specifying an absolute size you may, according to
lvextend(8)|lvreduce(8) C(--size), specify the amount to extend the logical volume with
- the prefix C(+) or the amount to reduce the logical volume by with prefix C(-).
- - Resizing using C(+) or C(-) was not supported prior to community.general 3.0.0.
- - Please note that when using C(+) or C(-), the module is B(not idempotent).
+ the prefix V(+) or the amount to reduce the logical volume by with prefix V(-).
+ - Resizing using V(+) or V(-) was not supported prior to community.general 3.0.0.
+ - Please note that when using V(+), V(-), or percentage of FREE, the module is B(not idempotent).
state:
type: str
description:
- - Control if the logical volume exists. If C(present) and the
- volume does not already exist then the C(size) option is required.
+ - Control if the logical volume exists. If V(present) and the
+ volume does not already exist then the O(size) option is required.
choices: [ absent, present ]
default: present
active:
@@ -73,11 +73,12 @@ options:
snapshot:
type: str
description:
- - The name of the snapshot volume
+ - The name of a snapshot volume to be configured. When creating a snapshot volume, the O(lv) parameter specifies the origin volume.
pvs:
- type: str
+ type: list
+ elements: str
description:
- - Comma separated list of physical volumes (e.g. /dev/sda,/dev/sdb).
+ - List of physical volumes (for example V(/dev/sda, /dev/sdb)).
thinpool:
type: str
description:
@@ -110,7 +111,9 @@ EXAMPLES = '''
vg: firefly
lv: test
size: 512
- pvs: /dev/sda,/dev/sdb
+ pvs:
+ - /dev/sda
+ - /dev/sdb
- name: Create cache pool logical volume
community.general.lvol:
@@ -299,7 +302,7 @@ def main():
shrink=dict(type='bool', default=True),
active=dict(type='bool', default=True),
snapshot=dict(type='str'),
- pvs=dict(type='str'),
+ pvs=dict(type='list', elements='str'),
resizefs=dict(type='bool', default=False),
thinpool=dict(type='str'),
),
@@ -340,7 +343,7 @@ def main():
if pvs is None:
pvs = ""
else:
- pvs = pvs.replace(",", " ")
+ pvs = " ".join(pvs)
if opts is None:
opts = ""
@@ -368,10 +371,10 @@ def main():
if size_percent > 100:
module.fail_json(msg="Size percentage cannot be larger than 100%")
size_whole = size_parts[1]
- if size_whole == 'ORIGIN':
- module.fail_json(msg="Snapshot Volumes are not supported")
- elif size_whole not in ['VG', 'PVS', 'FREE']:
- module.fail_json(msg="Specify extents as a percentage of VG|PVS|FREE")
+ if size_whole == 'ORIGIN' and snapshot is None:
+ module.fail_json(msg="Percentage of ORIGIN supported only for snapshot volumes")
+ elif size_whole not in ['VG', 'PVS', 'FREE', 'ORIGIN']:
+ module.fail_json(msg="Specify extents as a percentage of VG|PVS|FREE|ORIGIN")
size_opt = 'l'
size_unit = ''
@@ -552,9 +555,9 @@ def main():
elif rc == 0:
changed = True
msg = "Volume %s resized to %s%s" % (this_lv['name'], size_requested, unit)
- elif "matches existing size" in err:
+ elif "matches existing size" in err or "matches existing size" in out:
module.exit_json(changed=False, vg=vg, lv=this_lv['name'], size=this_lv['size'])
- elif "not larger than existing size" in err:
+ elif "not larger than existing size" in err or "not larger than existing size" in out:
module.exit_json(changed=False, vg=vg, lv=this_lv['name'], size=this_lv['size'], msg="Original size is larger than requested size", err=err)
else:
module.fail_json(msg="Unable to resize %s to %s%s" % (lv, size, size_unit), rc=rc, err=err)
@@ -585,9 +588,9 @@ def main():
module.fail_json(msg="Unable to resize %s to %s%s" % (lv, size, size_unit), rc=rc, err=err, out=out)
elif rc == 0:
changed = True
- elif "matches existing size" in err:
+ elif "matches existing size" in err or "matches existing size" in out:
module.exit_json(changed=False, vg=vg, lv=this_lv['name'], size=this_lv['size'])
- elif "not larger than existing size" in err:
+ elif "not larger than existing size" in err or "not larger than existing size" in out:
module.exit_json(changed=False, vg=vg, lv=this_lv['name'], size=this_lv['size'], msg="Original size is larger than requested size", err=err)
else:
module.fail_json(msg="Unable to resize %s to %s%s" % (lv, size, size_unit), rc=rc, err=err)
diff --git a/ansible_collections/community/general/plugins/modules/lxc_container.py b/ansible_collections/community/general/plugins/modules/lxc_container.py
index aec8f12dc..7ded041e9 100644
--- a/ansible_collections/community/general/plugins/modules/lxc_container.py
+++ b/ansible_collections/community/general/plugins/modules/lxc_container.py
@@ -92,7 +92,7 @@ options:
type: str
lxc_path:
description:
- - Place container under C(PATH).
+ - Place container under E(PATH).
type: path
container_log:
description:
@@ -111,7 +111,7 @@ options:
- debug
- DEBUG
description:
- - Set the log level for a container where I(container_log) was set.
+ - Set the log level for a container where O(container_log) was set.
type: str
required: false
default: INFO
@@ -158,7 +158,7 @@ options:
- clone
description:
- Define the state of a container.
- - If you clone a container using I(clone_name) the newly cloned
+ - If you clone a container using O(clone_name) the newly cloned
container created in a stopped state.
- The running container will be stopped while the clone operation is
happening and upon completion of the clone the original container
@@ -178,17 +178,17 @@ notes:
- Containers must have a unique name. If you attempt to create a container
with a name that already exists in the users namespace the module will
simply return as "unchanged".
- - The I(container_command) can be used with any state except C(absent). If
- used with state C(stopped) the container will be C(started), the command
- executed, and then the container C(stopped) again. Likewise if I(state=stopped)
+ - The O(container_command) can be used with any state except V(absent). If
+ used with state V(stopped) the container will be V(started), the command
+ executed, and then the container V(stopped) again. Likewise if O(state=stopped)
and the container does not exist it will be first created,
- C(started), the command executed, and then C(stopped). If you use a "|"
+ V(started), the command executed, and then V(stopped). If you use a "|"
in the variable you can use common script formatting within the variable
- itself. The I(container_command) option will always execute as BASH.
- When using I(container_command), a log file is created in the C(/tmp/) directory
+ itself. The O(container_command) option will always execute as BASH.
+ When using O(container_command), a log file is created in the C(/tmp/) directory
which contains both C(stdout) and C(stderr) of any command executed.
- - If I(archive=true) the system will attempt to create a compressed
- tarball of the running container. The I(archive) option supports LVM backed
+ - If O(archive=true) the system will attempt to create a compressed
+ tarball of the running container. The O(archive) option supports LVM backed
containers and will create a snapshot of the running container when
creating the archive.
- If your distro does not have a package for C(python3-lxc), which is a
@@ -1277,7 +1277,7 @@ class LxcContainerManagement(object):
"""
vg = self._get_lxc_vg()
- free_space, messurement = self._get_vg_free_pe(vg_name=vg)
+ free_space, measurement = self._get_vg_free_pe(vg_name=vg)
if free_space < float(snapshot_size_gb):
message = (
diff --git a/ansible_collections/community/general/plugins/modules/lxd_container.py b/ansible_collections/community/general/plugins/modules/lxd_container.py
index f10fc4872..9fd1b183b 100644
--- a/ansible_collections/community/general/plugins/modules/lxd_container.py
+++ b/ansible_collections/community/general/plugins/modules/lxd_container.py
@@ -34,32 +34,33 @@ options:
project:
description:
- 'Project of an instance.
- See U(https://github.com/lxc/lxd/blob/master/doc/projects.md).'
+ See U(https://documentation.ubuntu.com/lxd/en/latest/projects/).'
required: false
type: str
version_added: 4.8.0
architecture:
description:
- - 'The architecture for the instance (for example C(x86_64) or C(i686)).
- See U(https://github.com/lxc/lxd/blob/master/doc/rest-api.md#post-1).'
+ - 'The architecture for the instance (for example V(x86_64) or V(i686)).
+ See U(https://documentation.ubuntu.com/lxd/en/latest/api/#/instances/instance_get).'
type: str
required: false
config:
description:
- - 'The config for the instance (for example C({"limits.cpu": "2"})).
- See U(https://github.com/lxc/lxd/blob/master/doc/rest-api.md#post-1).'
+ - 'The config for the instance (for example V({"limits.cpu": "2"})).
+ See U(https://documentation.ubuntu.com/lxd/en/latest/api/#/instances/instance_get).'
- If the instance already exists and its "config" values in metadata
- obtained from the LXD API U(https://github.com/lxc/lxd/blob/master/doc/rest-api.md#instances-containers-and-virtual-machines)
- are different, this module tries to apply the configurations.
- - The keys starting with C(volatile.) are ignored for this comparison when I(ignore_volatile_options=true).
+ obtained from the LXD API U(https://documentation.ubuntu.com/lxd/en/latest/api/#/instances/instance_get)
+ are different, then this module tries to apply the configurations
+ U(https://documentation.ubuntu.com/lxd/en/latest/api/#/instances/instance_put).
+ - The keys starting with C(volatile.) are ignored for this comparison when O(ignore_volatile_options=true).
type: dict
required: false
ignore_volatile_options:
description:
- - If set to C(true), options starting with C(volatile.) are ignored. As a result,
+ - If set to V(true), options starting with C(volatile.) are ignored. As a result,
they are reapplied for each execution.
- - This default behavior can be changed by setting this option to C(false).
- - The default value changed from C(true) to C(false) in community.general 6.0.0.
+ - This default behavior can be changed by setting this option to V(false).
+ - The default value changed from V(true) to V(false) in community.general 6.0.0.
type: bool
required: false
default: false
@@ -72,26 +73,23 @@ options:
devices:
description:
- 'The devices for the instance
- (for example C({ "rootfs": { "path": "/dev/kvm", "type": "unix-char" }})).
- See U(https://github.com/lxc/lxd/blob/master/doc/rest-api.md#post-1).'
+ (for example V({ "rootfs": { "path": "/dev/kvm", "type": "unix-char" }})).
+ See U(https://documentation.ubuntu.com/lxd/en/latest/api/#/instances/instance_get).'
type: dict
required: false
ephemeral:
description:
- - Whether or not the instance is ephemeral (for example C(true) or C(false)).
- See U(https://github.com/lxc/lxd/blob/master/doc/rest-api.md#post-1).
+ - Whether or not the instance is ephemeral (for example V(true) or V(false)).
+ See U(https://documentation.ubuntu.com/lxd/en/latest/api/#/instances/instance_get).
required: false
type: bool
source:
description:
- 'The source for the instance
- (e.g. { "type": "image",
- "mode": "pull",
- "server": "https://images.linuxcontainers.org",
- "protocol": "lxd",
- "alias": "ubuntu/xenial/amd64" }).'
- - 'See U(https://github.com/lxc/lxd/blob/master/doc/rest-api.md#post-1) for complete API documentation.'
- - 'Note that C(protocol) accepts two choices: C(lxd) or C(simplestreams).'
+ (for example V({ "type": "image", "mode": "pull", "server": "https://images.linuxcontainers.org",
+ "protocol": "lxd", "alias": "ubuntu/xenial/amd64" })).'
+ - 'See U(https://documentation.ubuntu.com/lxd/en/latest/api/) for complete API documentation.'
+ - 'Note that C(protocol) accepts two choices: V(lxd) or V(simplestreams).'
required: false
type: dict
state:
@@ -125,7 +123,7 @@ options:
type: int
type:
description:
- - Instance type can be either C(virtual-machine) or C(container).
+ - Instance type can be either V(virtual-machine) or V(container).
required: false
default: container
choices:
@@ -135,7 +133,7 @@ options:
version_added: 4.1.0
wait_for_ipv4_addresses:
description:
- - If this is true, the C(lxd_container) waits until IPv4 addresses
+ - If this is V(true), the C(lxd_container) waits until IPv4 addresses
are set to the all network interfaces in the instance after
starting or restarting.
required: false
@@ -143,14 +141,14 @@ options:
type: bool
wait_for_container:
description:
- - If set to C(true), the tasks will wait till the task reports a
+ - If set to V(true), the tasks will wait till the task reports a
success status when performing container operations.
default: false
type: bool
version_added: 4.4.0
force_stop:
description:
- - If this is true, the C(lxd_container) forces to stop the instance
+ - If this is V(true), the C(lxd_container) forces to stop the instance
when it stops or restarts the instance.
required: false
default: false
@@ -201,7 +199,8 @@ notes:
2.1, the later requires python to be installed in the instance which can
be done with the command module.
- You can copy a file from the host to the instance
- with the Ansible M(ansible.builtin.copy) and M(ansible.builtin.template) module and the C(community.general.lxd) connection plugin.
+ with the Ansible M(ansible.builtin.copy) and M(ansible.builtin.template) module
+ and the P(community.general.lxd#connection) connection plugin.
See the example below.
- You can copy a file in the created instance to the localhost
with C(command=lxc file pull instance_name/dir/filename filename).
@@ -437,12 +436,12 @@ ANSIBLE_LXD_DEFAULT_URL = 'unix:/var/lib/lxd/unix.socket'
# CONFIG_PARAMS is a list of config attribute names.
CONFIG_PARAMS = [
- 'architecture', 'config', 'devices', 'ephemeral', 'profiles', 'source'
+ 'architecture', 'config', 'devices', 'ephemeral', 'profiles', 'source', 'type'
]
# CONFIG_CREATION_PARAMS is a list of attribute names that are only applied
# on instance creation.
-CONFIG_CREATION_PARAMS = ['source']
+CONFIG_CREATION_PARAMS = ['source', 'type']
class LXDContainerManagement(object):
@@ -468,13 +467,6 @@ class LXDContainerManagement(object):
self.type = self.module.params['type']
- # LXD Rest API provides additional endpoints for creating containers and virtual-machines.
- self.api_endpoint = None
- if self.type == 'container':
- self.api_endpoint = '/1.0/containers'
- elif self.type == 'virtual-machine':
- self.api_endpoint = '/1.0/virtual-machines'
-
self.key_file = self.module.params.get('client_key')
if self.key_file is None:
self.key_file = '{0}/.config/lxc/client.key'.format(os.environ['HOME'])
@@ -500,6 +492,18 @@ class LXDContainerManagement(object):
)
except LXDClientException as e:
self.module.fail_json(msg=e.msg)
+
+ # LXD (3.19) Rest API provides instances endpoint, failback to containers and virtual-machines
+ # https://documentation.ubuntu.com/lxd/en/latest/rest-api/#instances-containers-and-virtual-machines
+ self.api_endpoint = '/1.0/instances'
+ check_api_endpoint = self.client.do('GET', '{0}?project='.format(self.api_endpoint), ok_error_codes=[404])
+
+ if check_api_endpoint['error_code'] == 404:
+ if self.type == 'container':
+ self.api_endpoint = '/1.0/containers'
+ elif self.type == 'virtual-machine':
+ self.api_endpoint = '/1.0/virtual-machines'
+
self.trust_password = self.module.params.get('trust_password', None)
self.actions = []
self.diff = {'before': {}, 'after': {}}
@@ -552,6 +556,8 @@ class LXDContainerManagement(object):
url = '{0}?{1}'.format(url, urlencode(url_params))
config = self.config.copy()
config['name'] = self.name
+ if self.type not in self.api_endpoint:
+ config['type'] = self.type
if not self.module.check_mode:
self.client.do('POST', url, config, wait_for_container=self.wait_for_container)
self.actions.append('create')
diff --git a/ansible_collections/community/general/plugins/modules/lxd_profile.py b/ansible_collections/community/general/plugins/modules/lxd_profile.py
index 45f499b78..13660fd91 100644
--- a/ansible_collections/community/general/plugins/modules/lxd_profile.py
+++ b/ansible_collections/community/general/plugins/modules/lxd_profile.py
@@ -32,7 +32,7 @@ options:
project:
description:
- 'Project of a profile.
- See U(https://github.com/lxc/lxd/blob/master/doc/projects.md).'
+ See U(https://documentation.ubuntu.com/lxd/en/latest/projects/).'
type: str
required: false
version_added: 4.8.0
@@ -43,12 +43,13 @@ options:
config:
description:
- 'The config for the instance (e.g. {"limits.memory": "4GB"}).
- See U(https://github.com/lxc/lxd/blob/master/doc/rest-api.md#patch-3)'
+ See U(https://documentation.ubuntu.com/lxd/en/latest/api/#/profiles/profile_get).'
- If the profile already exists and its "config" value in metadata
obtained from
GET /1.0/profiles/<name>
- U(https://github.com/lxc/lxd/blob/master/doc/rest-api.md#get-19)
- are different, they this module tries to apply the configurations.
+ U(https://documentation.ubuntu.com/lxd/en/latest/api/#/profiles/profile_get)
+ are different, then this module tries to apply the configurations
+ U(https://documentation.ubuntu.com/lxd/en/latest/api/#/profiles/profile_put).
- Not all config values are supported to apply the existing profile.
Maybe you need to delete and recreate a profile.
required: false
@@ -57,14 +58,14 @@ options:
description:
- 'The devices for the profile
(e.g. {"rootfs": {"path": "/dev/kvm", "type": "unix-char"}).
- See U(https://github.com/lxc/lxd/blob/master/doc/rest-api.md#patch-3)'
+ See U(https://documentation.ubuntu.com/lxd/en/latest/api/#/profiles/profile_get).'
required: false
type: dict
new_name:
description:
- A new name of a profile.
- If this parameter is specified a profile will be renamed to this name.
- See U(https://github.com/lxc/lxd/blob/master/doc/rest-api.md#post-11)
+ See U(https://documentation.ubuntu.com/lxd/en/latest/api/#/profiles/profile_post).
required: false
type: str
merge_profile:
@@ -419,7 +420,7 @@ class LXDProfileManagement(object):
Rebuild the Profile by the configuration provided in the play.
Existing configurations are discarded.
- This ist the default behavior.
+ This is the default behavior.
Args:
dict(config): Dict with the old config in 'metadata' and new config in 'config'
diff --git a/ansible_collections/community/general/plugins/modules/lxd_project.py b/ansible_collections/community/general/plugins/modules/lxd_project.py
index 983531fa0..0d321808a 100644
--- a/ansible_collections/community/general/plugins/modules/lxd_project.py
+++ b/ansible_collections/community/general/plugins/modules/lxd_project.py
@@ -34,19 +34,20 @@ options:
type: str
config:
description:
- - 'The config for the project (for example C({"features.profiles": "true"})).
- See U(https://linuxcontainers.org/lxd/docs/master/projects/).'
+ - 'The config for the project (for example V({"features.profiles": "true"})).
+ See U(https://documentation.ubuntu.com/lxd/en/latest/api/#/projects/project_get).'
- If the project already exists and its "config" value in metadata
obtained from
C(GET /1.0/projects/<name>)
- U(https://linuxcontainers.org/lxd/docs/master/api/#/projects/project_get)
- are different, then this module tries to apply the configurations.
+ U(https://documentation.ubuntu.com/lxd/en/latest/api/#/projects/project_get)
+ are different, then this module tries to apply the configurations
+ U(https://documentation.ubuntu.com/lxd/en/latest/api/#/projects/project_put).
type: dict
new_name:
description:
- A new name of a project.
- If this parameter is specified a project will be renamed to this name.
- See U(https://linuxcontainers.org/lxd/docs/master/api/#/projects/project_post).
+ See U(https://documentation.ubuntu.com/lxd/en/latest/api/#/projects/project_post).
required: false
type: str
merge_project:
@@ -98,7 +99,7 @@ options:
running this module using the following command:
C(lxc config set core.trust_password <some random password>)
See U(https://www.stgraber.org/2016/04/18/lxd-api-direct-interaction/).'
- - If I(trust_password) is set, this module send a request for
+ - If O(trust_password) is set, this module send a request for
authentication before sending any requests.
required: false
type: str
@@ -146,7 +147,7 @@ logs:
elements: dict
contains:
type:
- description: Type of actions performed, currently only C(sent request).
+ description: Type of actions performed, currently only V(sent request).
type: str
sample: "sent request"
request:
@@ -166,7 +167,7 @@ logs:
type: str
sample: "(too long to be placed here)"
timeout:
- description: Timeout of HTTP request, C(null) if unset.
+ description: Timeout of HTTP request, V(null) if unset.
type: int
sample: null
response:
diff --git a/ansible_collections/community/general/plugins/modules/macports.py b/ansible_collections/community/general/plugins/modules/macports.py
index 6f40d0938..e81fb9142 100644
--- a/ansible_collections/community/general/plugins/modules/macports.py
+++ b/ansible_collections/community/general/plugins/modules/macports.py
@@ -55,7 +55,7 @@ options:
variant:
description:
- A port variant specification.
- - 'C(variant) is only supported with state: I(installed)/I(present).'
+ - 'O(variant) is only supported with O(state=installed) and O(state=present).'
aliases: ['variants']
type: str
'''
diff --git a/ansible_collections/community/general/plugins/modules/mail.py b/ansible_collections/community/general/plugins/modules/mail.py
index feaac6923..1916c140c 100644
--- a/ansible_collections/community/general/plugins/modules/mail.py
+++ b/ansible_collections/community/general/plugins/modules/mail.py
@@ -114,18 +114,18 @@ options:
default: utf-8
subtype:
description:
- - The minor mime type, can be either C(plain) or C(html).
- - The major type is always C(text).
+ - The minor mime type, can be either V(plain) or V(html).
+ - The major type is always V(text).
type: str
choices: [ html, plain ]
default: plain
secure:
description:
- - If C(always), the connection will only send email if the connection is Encrypted.
+ - If V(always), the connection will only send email if the connection is Encrypted.
If the server doesn't accept the encrypted connection it will fail.
- - If C(try), the connection will attempt to setup a secure SSL/TLS session, before trying to send.
- - If C(never), the connection will not attempt to setup a secure SSL/TLS session, before sending
- - If C(starttls), the connection will try to upgrade to a secure SSL/TLS connection, before sending.
+ - If V(try), the connection will attempt to setup a secure SSL/TLS session, before trying to send.
+ - If V(never), the connection will not attempt to setup a secure SSL/TLS session, before sending
+ - If V(starttls), the connection will try to upgrade to a secure SSL/TLS connection, before sending.
If it is unable to do so it will fail.
type: str
choices: [ always, never, starttls, try ]
@@ -140,6 +140,13 @@ options:
- Allows for manual specification of host for EHLO.
type: str
version_added: 3.8.0
+ message_id_domain:
+ description:
+ - The domain name to use for the L(Message-ID header, https://en.wikipedia.org/wiki/Message-ID).
+ - Note that this is only available on Python 3+. On Python 2, this value will be ignored.
+ type: str
+ default: ansible
+ version_added: 8.2.0
'''
EXAMPLES = r'''
@@ -205,10 +212,11 @@ EXAMPLES = r'''
body: System {{ ansible_hostname }} has been successfully provisioned.
secure: starttls
-- name: Sending an e-mail using StartTLS, remote server, custom EHLO
+- name: Sending an e-mail using StartTLS, remote server, custom EHLO, and timeout of 10 seconds
community.general.mail:
host: some.smtp.host.tld
port: 25
+ timeout: 10
ehlohost: my-resolvable-hostname.tld
to: John Smith <john.smith@example.com>
subject: Ansible-report
@@ -221,7 +229,7 @@ import smtplib
import ssl
import traceback
from email import encoders
-from email.utils import parseaddr, formataddr, formatdate
+from email.utils import parseaddr, formataddr, formatdate, make_msgid
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
@@ -253,6 +261,7 @@ def main():
subtype=dict(type='str', default='plain', choices=['html', 'plain']),
secure=dict(type='str', default='try', choices=['always', 'never', 'starttls', 'try']),
timeout=dict(type='int', default=20),
+ message_id_domain=dict(type='str', default='ansible'),
),
required_together=[['password', 'username']],
)
@@ -274,6 +283,7 @@ def main():
subtype = module.params.get('subtype')
secure = module.params.get('secure')
timeout = module.params.get('timeout')
+ message_id_domain = module.params['message_id_domain']
code = 0
secure_state = False
@@ -348,13 +358,19 @@ def main():
msg['From'] = formataddr((sender_phrase, sender_addr))
msg['Date'] = formatdate(localtime=True)
msg['Subject'] = Header(subject, charset)
+ try:
+ msg['Message-ID'] = make_msgid(domain=message_id_domain)
+ except TypeError:
+ # `domain` is only available in Python 3
+ msg['Message-ID'] = make_msgid()
+ module.warn("The Message-ID domain cannot be set on Python 2; the system's hostname is used")
msg.preamble = "Multipart message"
for header in headers:
# NOTE: Backward compatible with old syntax using '|' as delimiter
for hdr in [x.strip() for x in header.split('|')]:
try:
- h_key, h_val = hdr.split('=')
+ h_key, h_val = hdr.split('=', 1)
h_val = to_native(Header(h_val, charset))
msg.add_header(h_key, h_val)
except Exception:
@@ -382,7 +398,7 @@ def main():
part = MIMEText(body + "\n\n", _subtype=subtype, _charset=charset)
msg.attach(part)
- # NOTE: Backware compatibility with old syntax using space as delimiter is not retained
+ # NOTE: Backward compatibility with old syntax using space as delimiter is not retained
# This breaks files with spaces in it :-(
for filename in attach_files:
try:
diff --git a/ansible_collections/community/general/plugins/modules/make.py b/ansible_collections/community/general/plugins/modules/make.py
index ebff6cfe1..39392afca 100644
--- a/ansible_collections/community/general/plugins/modules/make.py
+++ b/ansible_collections/community/general/plugins/modules/make.py
@@ -49,12 +49,22 @@ options:
params:
description:
- Any extra parameters to pass to make.
+ - If the value is empty, only the key will be used. For example, V(FOO:) will produce V(FOO), not V(FOO=).
type: dict
target:
description:
- The target to run.
- - Typically this would be something like C(install), C(test), or C(all).
+ - Typically this would be something like V(install), V(test), or V(all).
+ - O(target) and O(targets) are mutually exclusive.
type: str
+ targets:
+ description:
+ - The list of targets to run.
+ - Typically this would be something like V(install), V(test), or V(all).
+ - O(target) and O(targets) are mutually exclusive.
+ type: list
+ elements: str
+ version_added: 7.2.0
'''
EXAMPLES = r'''
@@ -81,12 +91,24 @@ EXAMPLES = r'''
chdir: /home/ubuntu/cool-project
target: all
file: /some-project/Makefile
+
+- name: build arm64 kernel on FreeBSD, with 16 parallel jobs
+ community.general.make:
+ chdir: /usr/src
+ jobs: 16
+ target: buildkernel
+ params:
+ # This adds -DWITH_FDT to the command line:
+ -DWITH_FDT:
+ # The following adds TARGET=arm64 TARGET_ARCH=aarch64 to the command line:
+ TARGET: arm64
+ TARGET_ARCH: aarch64
'''
RETURN = r'''
chdir:
description:
- - The value of the module parameter I(chdir).
+ - The value of the module parameter O(chdir).
type: str
returned: success
command:
@@ -97,24 +119,30 @@ command:
version_added: 6.5.0
file:
description:
- - The value of the module parameter I(file).
+ - The value of the module parameter O(file).
type: str
returned: success
jobs:
description:
- - The value of the module parameter I(jobs).
+ - The value of the module parameter O(jobs).
type: int
returned: success
params:
description:
- - The value of the module parameter I(params).
+ - The value of the module parameter O(params).
type: dict
returned: success
target:
description:
- - The value of the module parameter I(target).
+ - The value of the module parameter O(target).
+ type: str
+ returned: success
+targets:
+ description:
+ - The value of the module parameter O(targets).
type: str
returned: success
+ version_added: 7.2.0
'''
from ansible.module_utils.six import iteritems
@@ -155,12 +183,14 @@ def main():
module = AnsibleModule(
argument_spec=dict(
target=dict(type='str'),
+ targets=dict(type='list', elements='str'),
params=dict(type='dict'),
chdir=dict(type='path', required=True),
file=dict(type='path'),
make=dict(type='path'),
jobs=dict(type='int'),
),
+ mutually_exclusive=[('target', 'targets')],
supports_check_mode=True,
)
@@ -172,9 +202,8 @@ def main():
if not make_path:
# Fall back to system make
make_path = module.get_bin_path('make', required=True)
- make_target = module.params['target']
if module.params['params'] is not None:
- make_parameters = [k + '=' + str(v) for k, v in iteritems(module.params['params'])]
+ make_parameters = [k + (('=' + str(v)) if v is not None else '') for k, v in iteritems(module.params['params'])]
else:
make_parameters = []
@@ -188,7 +217,10 @@ def main():
base_command.extend(["-f", module.params['file']])
# add make target
- base_command.append(make_target)
+ if module.params['target']:
+ base_command.append(module.params['target'])
+ elif module.params['targets']:
+ base_command.extend(module.params['targets'])
# add makefile parameters
base_command.extend(make_parameters)
@@ -206,8 +238,7 @@ def main():
changed = False
else:
# The target isn't up to date, so we need to run it
- rc, out, err = run_command(base_command, module,
- check_rc=True)
+ rc, out, err = run_command(base_command, module, check_rc=True)
changed = True
# We don't report the return code, as if this module failed
@@ -221,6 +252,7 @@ def main():
stdout=out,
stderr=err,
target=module.params['target'],
+ targets=module.params['targets'],
params=module.params['params'],
chdir=module.params['chdir'],
file=module.params['file'],
diff --git a/ansible_collections/community/general/plugins/modules/manageiq_alert_profiles.py b/ansible_collections/community/general/plugins/modules/manageiq_alert_profiles.py
index c6cefad6a..eb6424bcd 100644
--- a/ansible_collections/community/general/plugins/modules/manageiq_alert_profiles.py
+++ b/ansible_collections/community/general/plugins/modules/manageiq_alert_profiles.py
@@ -72,7 +72,7 @@ EXAMPLES = '''
url: 'http://127.0.0.1:3000'
username: 'admin'
password: 'smartvm'
- validate_certs: false
+ validate_certs: false # only do this when you trust the network!
- name: Delete an alert profile from ManageIQ
community.general.manageiq_alert_profiles:
@@ -82,7 +82,7 @@ EXAMPLES = '''
url: 'http://127.0.0.1:3000'
username: 'admin'
password: 'smartvm'
- validate_certs: false
+ validate_certs: false # only do this when you trust the network!
'''
RETURN = '''
diff --git a/ansible_collections/community/general/plugins/modules/manageiq_alerts.py b/ansible_collections/community/general/plugins/modules/manageiq_alerts.py
index 518b29f1f..53f40fb00 100644
--- a/ansible_collections/community/general/plugins/modules/manageiq_alerts.py
+++ b/ansible_collections/community/general/plugins/modules/manageiq_alerts.py
@@ -91,7 +91,7 @@ EXAMPLES = '''
url: 'http://127.0.0.1:3000'
username: 'admin'
password: 'smartvm'
- validate_certs: false
+ validate_certs: false # only do this when you trust the network!
- name: Add an alert with a "miq expression" to ManageIQ
community.general.manageiq_alerts:
@@ -118,7 +118,7 @@ EXAMPLES = '''
url: 'http://127.0.0.1:3000'
username: 'admin'
password: 'smartvm'
- validate_certs: false
+ validate_certs: false # only do this when you trust the network!
- name: Delete an alert from ManageIQ
community.general.manageiq_alerts:
@@ -128,7 +128,7 @@ EXAMPLES = '''
url: 'http://127.0.0.1:3000'
username: 'admin'
password: 'smartvm'
- validate_certs: false
+ validate_certs: false # only do this when you trust the network!
'''
RETURN = '''
diff --git a/ansible_collections/community/general/plugins/modules/manageiq_group.py b/ansible_collections/community/general/plugins/modules/manageiq_group.py
index a142a939f..e060b9a01 100644
--- a/ansible_collections/community/general/plugins/modules/manageiq_group.py
+++ b/ansible_collections/community/general/plugins/modules/manageiq_group.py
@@ -52,7 +52,7 @@ options:
type: str
description:
- The the group role name
- - The C(role_id) has precedence over the C(role) when supplied.
+ - The O(role_id) has precedence over the O(role) when supplied.
required: false
default: null
tenant_id:
@@ -65,7 +65,7 @@ options:
type: str
description:
- The tenant for the group identified by the tenant name.
- - The C(tenant_id) has precedence over the C(tenant) when supplied.
+ - The O(tenant_id) has precedence over the O(tenant) when supplied.
- Tenant names are case sensitive.
required: false
default: null
@@ -78,7 +78,7 @@ options:
type: str
description:
- In merge mode existing categories are kept or updated, new categories are added.
- - In replace mode all categories will be replaced with the supplied C(managed_filters).
+ - In replace mode all categories will be replaced with the supplied O(managed_filters).
choices: [ merge, replace ]
default: replace
belongsto_filters:
@@ -90,8 +90,8 @@ options:
belongsto_filters_merge_mode:
type: str
description:
- - In merge mode existing settings are merged with the supplied C(belongsto_filters).
- - In replace mode current values are replaced with the supplied C(belongsto_filters).
+ - In merge mode existing settings are merged with the supplied O(belongsto_filters).
+ - In replace mode current values are replaced with the supplied O(belongsto_filters).
choices: [ merge, replace ]
default: replace
'''
@@ -103,10 +103,10 @@ EXAMPLES = '''
role: 'EvmRole-user'
tenant: 'my_tenant'
manageiq_connection:
- url: 'https://manageiq_server'
+ url: 'http://127.0.0.1:3000'
username: 'admin'
password: 'smartvm'
- validate_certs: false
+ validate_certs: false # only do this when you trust the network!
- name: Create a group in ManageIQ with the role EvmRole-user and tenant with tenant_id 4
community.general.manageiq_group:
@@ -114,10 +114,10 @@ EXAMPLES = '''
role: 'EvmRole-user'
tenant_id: 4
manageiq_connection:
- url: 'https://manageiq_server'
+ url: 'http://127.0.0.1:3000'
username: 'admin'
password: 'smartvm'
- validate_certs: false
+ validate_certs: false # only do this when you trust the network!
- name:
- Create or update a group in ManageIQ with the role EvmRole-user and tenant my_tenant.
@@ -140,10 +140,10 @@ EXAMPLES = '''
- "/belongsto/ExtManagementSystem|ProviderName/EmsFolder|Datacenters/EmsFolder|dc_name/EmsFolder|host/EmsCluster|Cluster name"
belongsto_filters_merge_mode: merge
manageiq_connection:
- url: 'https://manageiq_server'
+ url: 'http://127.0.0.1:3000'
username: 'admin'
password: 'smartvm'
- validate_certs: false
+ validate_certs: false # only do this when you trust the network!
- name: Delete a group in ManageIQ
community.general.manageiq_group:
diff --git a/ansible_collections/community/general/plugins/modules/manageiq_policies.py b/ansible_collections/community/general/plugins/modules/manageiq_policies.py
index 061168f7f..f2101ad28 100644
--- a/ansible_collections/community/general/plugins/modules/manageiq_policies.py
+++ b/ansible_collections/community/general/plugins/modules/manageiq_policies.py
@@ -32,20 +32,16 @@ options:
state:
type: str
description:
- - C(absent) - policy_profiles should not exist,
- - C(present) - policy_profiles should exist,
- - >
- C(list) - list current policy_profiles and policies.
- This state is deprecated and will be removed 8.0.0.
- Please use the module M(community.general.manageiq_policies_info) instead.
- choices: ['absent', 'present', 'list']
+ - V(absent) - policy_profiles should not exist,
+ - V(present) - policy_profiles should exist,
+ choices: ['absent', 'present']
default: 'present'
policy_profiles:
type: list
elements: dict
description:
- - List of dictionaries, each includes the policy_profile C(name) key.
- - Required if I(state) is C(present) or C(absent).
+ - List of dictionaries, each includes the policy_profile V(name) key.
+ - Required if O(state) is V(present) or V(absent).
resource_type:
type: str
description:
@@ -58,12 +54,12 @@ options:
type: str
description:
- The name of the resource to which the profile should be [un]assigned.
- - Must be specified if I(resource_id) is not set. Both options are mutually exclusive.
+ - Must be specified if O(resource_id) is not set. Both options are mutually exclusive.
resource_id:
type: int
description:
- The ID of the resource to which the profile should be [un]assigned.
- - Must be specified if I(resource_name) is not set. Both options are mutually exclusive.
+ - Must be specified if O(resource_name) is not set. Both options are mutually exclusive.
version_added: 2.2.0
'''
@@ -78,7 +74,7 @@ EXAMPLES = '''
url: 'http://127.0.0.1:3000'
username: 'admin'
password: 'smartvm'
- validate_certs: false
+ validate_certs: false # only do this when you trust the network!
- name: Unassign a policy_profile for a provider in ManageIQ
community.general.manageiq_policies:
@@ -91,18 +87,7 @@ EXAMPLES = '''
url: 'http://127.0.0.1:3000'
username: 'admin'
password: 'smartvm'
- validate_certs: false
-
-- name: List current policy_profile and policies for a provider in ManageIQ
- community.general.manageiq_policies:
- state: list
- resource_name: 'EngLab'
- resource_type: 'provider'
- manageiq_connection:
- url: 'http://127.0.0.1:3000'
- username: 'admin'
- password: 'smartvm'
- validate_certs: false
+ validate_certs: false # only do this when you trust the network!
'''
RETURN = '''
@@ -144,7 +129,7 @@ from ansible_collections.community.general.plugins.module_utils.manageiq import
def main():
- actions = {'present': 'assign', 'absent': 'unassign', 'list': 'list'}
+ actions = {'present': 'assign', 'absent': 'unassign'}
argument_spec = dict(
policy_profiles=dict(type='list', elements='dict'),
resource_id=dict(type='int'),
@@ -152,7 +137,7 @@ def main():
resource_type=dict(required=True, type='str',
choices=list(manageiq_entities().keys())),
state=dict(required=False, type='str',
- choices=['present', 'absent', 'list'], default='present'),
+ choices=['present', 'absent'], default='present'),
)
# add the manageiq connection arguments to the arguments
argument_spec.update(manageiq_argument_spec())
@@ -173,13 +158,6 @@ def main():
resource_name = module.params['resource_name']
state = module.params['state']
- if state == "list":
- module.deprecate(
- 'The value "list" for "state" is deprecated. Please use community.general.manageiq_policies_info instead.',
- version='8.0.0',
- collection_name='community.general'
- )
-
# get the action and resource type
action = actions[state]
resource_type = manageiq_entities()[resource_type_key]
@@ -187,13 +165,8 @@ def main():
manageiq = ManageIQ(module)
manageiq_policies = manageiq.policies(resource_id, resource_type, resource_name)
- if action == 'list':
- # return a list of current profiles for this object
- current_profiles = manageiq_policies.query_resource_profiles()
- res_args = dict(changed=False, profiles=current_profiles)
- else:
- # assign or unassign the profiles
- res_args = manageiq_policies.assign_or_unassign_profiles(policy_profiles, action)
+ # assign or unassign the profiles
+ res_args = manageiq_policies.assign_or_unassign_profiles(policy_profiles, action)
module.exit_json(**res_args)
diff --git a/ansible_collections/community/general/plugins/modules/manageiq_policies_info.py b/ansible_collections/community/general/plugins/modules/manageiq_policies_info.py
index 8a75ef646..fda7dcadf 100644
--- a/ansible_collections/community/general/plugins/modules/manageiq_policies_info.py
+++ b/ansible_collections/community/general/plugins/modules/manageiq_policies_info.py
@@ -38,12 +38,12 @@ options:
type: str
description:
- The name of the resource to obtain the profile for.
- - Must be specified if I(resource_id) is not set. Both options are mutually exclusive.
+ - Must be specified if O(resource_id) is not set. Both options are mutually exclusive.
resource_id:
type: int
description:
- The ID of the resource to obtain the profile for.
- - Must be specified if I(resource_name) is not set. Both options are mutually exclusive.
+ - Must be specified if O(resource_name) is not set. Both options are mutually exclusive.
'''
EXAMPLES = '''
diff --git a/ansible_collections/community/general/plugins/modules/manageiq_provider.py b/ansible_collections/community/general/plugins/modules/manageiq_provider.py
index bbc27214b..e6ded9ea7 100644
--- a/ansible_collections/community/general/plugins/modules/manageiq_provider.py
+++ b/ansible_collections/community/general/plugins/modules/manageiq_provider.py
@@ -75,6 +75,7 @@ options:
provider:
description: Default endpoint connection information, required if state is true.
+ type: dict
suboptions:
hostname:
type: str
@@ -104,9 +105,30 @@ options:
certificate_authority:
type: str
description: The CA bundle string with custom certificates. defaults to None.
+ path:
+ type: str
+ description:
+ - TODO needs documentation.
+ project:
+ type: str
+ description:
+ - TODO needs documentation.
+ role:
+ type: str
+ description:
+ - TODO needs documentation.
+ subscription:
+ type: str
+ description:
+ - TODO needs documentation.
+ uid_ems:
+ type: str
+ description:
+ - TODO needs documentation.
metrics:
description: Metrics endpoint connection information.
+ type: dict
suboptions:
hostname:
type: str
@@ -138,10 +160,27 @@ options:
description: The CA bundle string with custom certificates. defaults to None.
path:
type: str
- description: Database name for oVirt metrics. Defaults to C(ovirt_engine_history).
+ description: Database name for oVirt metrics. Defaults to V(ovirt_engine_history).
+ project:
+ type: str
+ description:
+ - TODO needs documentation.
+ role:
+ type: str
+ description:
+ - TODO needs documentation.
+ subscription:
+ type: str
+ description:
+ - TODO needs documentation.
+ uid_ems:
+ type: str
+ description:
+ - TODO needs documentation.
alerts:
description: Alerts endpoint connection information.
+ type: dict
suboptions:
hostname:
type: str
@@ -171,9 +210,30 @@ options:
certificate_authority:
type: str
description: The CA bundle string with custom certificates. defaults to None.
+ path:
+ type: str
+ description:
+ - TODO needs documentation.
+ project:
+ type: str
+ description:
+ - TODO needs documentation.
+ role:
+ type: str
+ description:
+ - TODO needs documentation.
+ subscription:
+ type: str
+ description:
+ - TODO needs documentation.
+ uid_ems:
+ type: str
+ description:
+ - TODO needs documentation.
ssh_keypair:
description: SSH key pair used for SSH connections to all hosts in this provider.
+ type: dict
suboptions:
hostname:
type: str
@@ -191,6 +251,43 @@ options:
type: bool
default: true
aliases: [ verify_ssl ]
+ security_protocol:
+ type: str
+ choices: ['ssl-with-validation','ssl-with-validation-custom-ca','ssl-without-validation', 'non-ssl']
+ description:
+ - TODO needs documentation.
+ certificate_authority:
+ type: str
+ description:
+ - TODO needs documentation.
+ password:
+ type: str
+ description:
+ - TODO needs documentation.
+ path:
+ type: str
+ description:
+ - TODO needs documentation.
+ project:
+ type: str
+ description:
+ - TODO needs documentation.
+ role:
+ type: str
+ description:
+ - TODO needs documentation.
+ subscription:
+ type: str
+ description:
+ - TODO needs documentation.
+ uid_ems:
+ type: str
+ description:
+ - TODO needs documentation.
+ port:
+ type: int
+ description:
+ - TODO needs documentation.
'''
EXAMPLES = '''
@@ -438,7 +535,7 @@ EXAMPLES = '''
url: 'https://cf-6af0.rhpds.opentlc.com'
username: 'admin'
password: 'password'
- validate_certs: false
+ validate_certs: true
- name: Create a new OpenStack Director provider in ManageIQ with rsa keypair
community.general.manageiq_provider:
diff --git a/ansible_collections/community/general/plugins/modules/manageiq_tags.py b/ansible_collections/community/general/plugins/modules/manageiq_tags.py
index 7e190d49c..3ab5eca4f 100644
--- a/ansible_collections/community/general/plugins/modules/manageiq_tags.py
+++ b/ansible_collections/community/general/plugins/modules/manageiq_tags.py
@@ -32,17 +32,16 @@ options:
state:
type: str
description:
- - C(absent) - tags should not exist.
- - C(present) - tags should exist.
- - C(list) - list current tags.
- choices: ['absent', 'present', 'list']
+ - V(absent) - tags should not exist.
+ - V(present) - tags should exist.
+ choices: ['absent', 'present']
default: 'present'
tags:
type: list
elements: dict
description:
- - C(tags) - list of dictionaries, each includes C(name) and c(category) keys.
- - Required if I(state) is C(present) or C(absent).
+ - V(tags) - list of dictionaries, each includes C(name) and C(category) keys.
+ - Required if O(state) is V(present) or V(absent).
resource_type:
type: str
description:
@@ -55,11 +54,11 @@ options:
type: str
description:
- The name of the resource at which tags will be controlled.
- - Must be specified if I(resource_id) is not set. Both options are mutually exclusive.
+ - Must be specified if O(resource_id) is not set. Both options are mutually exclusive.
resource_id:
description:
- The ID of the resource at which tags will be controlled.
- - Must be specified if I(resource_name) is not set. Both options are mutually exclusive.
+ - Must be specified if O(resource_name) is not set. Both options are mutually exclusive.
type: int
version_added: 2.2.0
'''
@@ -78,7 +77,7 @@ EXAMPLES = '''
url: 'http://127.0.0.1:3000'
username: 'admin'
password: 'smartvm'
- validate_certs: false
+ validate_certs: false # only do this when connecting to localhost!
- name: Create new tags for a provider in ManageIQ.
community.general.manageiq_tags:
@@ -93,7 +92,7 @@ EXAMPLES = '''
url: 'http://127.0.0.1:3000'
username: 'admin'
password: 'smartvm'
- validate_certs: false
+ validate_certs: false # only do this when connecting to localhost!
- name: Remove tags for a provider in ManageIQ.
community.general.manageiq_tags:
@@ -109,18 +108,7 @@ EXAMPLES = '''
url: 'http://127.0.0.1:3000'
username: 'admin'
password: 'smartvm'
- validate_certs: false
-
-- name: List current tags for a provider in ManageIQ.
- community.general.manageiq_tags:
- state: list
- resource_name: 'EngLab'
- resource_type: 'provider'
- manageiq_connection:
- url: 'http://127.0.0.1:3000'
- username: 'admin'
- password: 'smartvm'
- validate_certs: false
+ validate_certs: false # only do this when connecting to localhost!
'''
RETURN = '''
@@ -133,7 +121,7 @@ from ansible_collections.community.general.plugins.module_utils.manageiq import
def main():
- actions = {'present': 'assign', 'absent': 'unassign', 'list': 'list'}
+ actions = {'present': 'assign', 'absent': 'unassign'}
argument_spec = dict(
tags=dict(type='list', elements='dict'),
resource_id=dict(type='int'),
@@ -141,7 +129,7 @@ def main():
resource_type=dict(required=True, type='str',
choices=list(manageiq_entities().keys())),
state=dict(required=False, type='str',
- choices=['present', 'absent', 'list'], default='present'),
+ choices=['present', 'absent'], default='present'),
)
# add the manageiq connection arguments to the arguments
argument_spec.update(manageiq_argument_spec())
@@ -174,13 +162,8 @@ def main():
manageiq_tags = ManageIQTags(manageiq, resource_type, resource_id)
- if action == 'list':
- # return a list of current tags for this object
- current_tags = manageiq_tags.query_resource_tags()
- res_args = dict(changed=False, tags=current_tags)
- else:
- # assign or unassign the tags
- res_args = manageiq_tags.assign_or_unassign_tags(tags, action)
+ # assign or unassign the tags
+ res_args = manageiq_tags.assign_or_unassign_tags(tags, action)
module.exit_json(**res_args)
diff --git a/ansible_collections/community/general/plugins/modules/manageiq_tags_info.py b/ansible_collections/community/general/plugins/modules/manageiq_tags_info.py
index af71e150c..75e111540 100644
--- a/ansible_collections/community/general/plugins/modules/manageiq_tags_info.py
+++ b/ansible_collections/community/general/plugins/modules/manageiq_tags_info.py
@@ -36,11 +36,11 @@ options:
type: str
description:
- The name of the resource at which tags will be controlled.
- - Must be specified if I(resource_id) is not set. Both options are mutually exclusive.
+ - Must be specified if O(resource_id) is not set. Both options are mutually exclusive.
resource_id:
description:
- The ID of the resource at which tags will be controlled.
- - Must be specified if I(resource_name) is not set. Both options are mutually exclusive.
+ - Must be specified if O(resource_name) is not set. Both options are mutually exclusive.
type: int
'''
diff --git a/ansible_collections/community/general/plugins/modules/manageiq_tenant.py b/ansible_collections/community/general/plugins/modules/manageiq_tenant.py
index d68e26a73..a5a56191e 100644
--- a/ansible_collections/community/general/plugins/modules/manageiq_tenant.py
+++ b/ansible_collections/community/general/plugins/modules/manageiq_tenant.py
@@ -50,13 +50,13 @@ options:
type: int
description:
- The id of the parent tenant. If not supplied the root tenant is used.
- - The C(parent_id) takes president over C(parent) when supplied
+ - The O(parent_id) takes president over O(parent) when supplied
required: false
default: null
parent:
type: str
description:
- - The name of the parent tenant. If not supplied and no C(parent_id) is supplied the root tenant is used.
+ - The name of the parent tenant. If not supplied and no O(parent_id) is supplied the root tenant is used.
required: false
default: null
quotas:
@@ -83,7 +83,7 @@ EXAMPLES = '''
url: 'http://127.0.0.1:3000'
username: 'admin'
password: 'smartvm'
- validate_certs: false
+ validate_certs: false # only do this when you trust the network!
- name: Create a tenant in ManageIQ
community.general.manageiq_tenant:
@@ -94,7 +94,7 @@ EXAMPLES = '''
url: 'http://127.0.0.1:3000'
username: 'admin'
password: 'smartvm'
- validate_certs: false
+ validate_certs: false # only do this when you trust the network!
- name: Delete a tenant in ManageIQ
community.general.manageiq_tenant:
@@ -105,7 +105,7 @@ EXAMPLES = '''
url: 'http://127.0.0.1:3000'
username: 'admin'
password: 'smartvm'
- validate_certs: false
+ validate_certs: false # only do this when you trust the network!
- name: Set tenant quota for cpu_allocated, mem_allocated, remove quota for vms_allocated
community.general.manageiq_tenant:
@@ -119,7 +119,7 @@ EXAMPLES = '''
url: 'http://127.0.0.1:3000'
username: 'admin'
password: 'smartvm'
- validate_certs: false
+ validate_certs: false # only do this when you trust the network!
- name: Delete a tenant in ManageIQ using a token
@@ -130,7 +130,7 @@ EXAMPLES = '''
manageiq_connection:
url: 'http://127.0.0.1:3000'
token: 'sometoken'
- validate_certs: false
+ validate_certs: false # only do this when you trust the network!
'''
RETURN = '''
diff --git a/ansible_collections/community/general/plugins/modules/manageiq_user.py b/ansible_collections/community/general/plugins/modules/manageiq_user.py
index 0d3d8718b..0d8a81984 100644
--- a/ansible_collections/community/general/plugins/modules/manageiq_user.py
+++ b/ansible_collections/community/general/plugins/modules/manageiq_user.py
@@ -60,7 +60,7 @@ options:
default: always
choices: ['always', 'on_create']
description:
- - C(always) will update passwords unconditionally. C(on_create) will only set the password for a newly created user.
+ - V(always) will update passwords unconditionally. V(on_create) will only set the password for a newly created user.
'''
EXAMPLES = '''
@@ -75,7 +75,7 @@ EXAMPLES = '''
url: 'http://127.0.0.1:3000'
username: 'admin'
password: 'smartvm'
- validate_certs: false
+ validate_certs: false # only do this when you trust the network!
- name: Create a new user in ManageIQ using a token
community.general.manageiq_user:
@@ -87,7 +87,7 @@ EXAMPLES = '''
manageiq_connection:
url: 'http://127.0.0.1:3000'
token: 'sometoken'
- validate_certs: false
+ validate_certs: false # only do this when you trust the network!
- name: Delete a user in ManageIQ
community.general.manageiq_user:
@@ -97,7 +97,7 @@ EXAMPLES = '''
url: 'http://127.0.0.1:3000'
username: 'admin'
password: 'smartvm'
- validate_certs: false
+ validate_certs: false # only do this when you trust the network!
- name: Delete a user in ManageIQ using a token
community.general.manageiq_user:
@@ -106,7 +106,7 @@ EXAMPLES = '''
manageiq_connection:
url: 'http://127.0.0.1:3000'
token: 'sometoken'
- validate_certs: false
+ validate_certs: false # only do this when you trust the network!
- name: Update email of user in ManageIQ
community.general.manageiq_user:
@@ -116,7 +116,7 @@ EXAMPLES = '''
url: 'http://127.0.0.1:3000'
username: 'admin'
password: 'smartvm'
- validate_certs: false
+ validate_certs: false # only do this when you trust the network!
- name: Update email of user in ManageIQ using a token
community.general.manageiq_user:
@@ -125,7 +125,7 @@ EXAMPLES = '''
manageiq_connection:
url: 'http://127.0.0.1:3000'
token: 'sometoken'
- validate_certs: false
+ validate_certs: false # only do this when you trust the network!
'''
RETURN = '''
diff --git a/ansible_collections/community/general/plugins/modules/mas.py b/ansible_collections/community/general/plugins/modules/mas.py
index 5b8958beb..8bb80840c 100644
--- a/ansible_collections/community/general/plugins/modules/mas.py
+++ b/ansible_collections/community/general/plugins/modules/mas.py
@@ -36,7 +36,7 @@ options:
state:
description:
- Desired state of the app installation.
- - The C(absent) value requires root permissions, also see the examples.
+ - The V(absent) value requires root permissions, also see the examples.
type: str
choices:
- absent
@@ -53,6 +53,8 @@ requirements:
- macOS 10.11+
- "mas-cli (U(https://github.com/mas-cli/mas)) 1.5.0+ available as C(mas) in the bin path"
- The Apple ID to use already needs to be signed in to the Mac App Store (check with C(mas account)).
+ - The feature of "checking if user is signed in" is disabled for anyone using macOS 12.0+.
+ - Users need to sign in via the Mac App Store GUI beforehand for anyone using macOS 12.0+ due to U(https://github.com/mas-cli/mas/issues/417).
'''
EXAMPLES = '''
@@ -106,6 +108,9 @@ import os
from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
+import platform
+NOT_WORKING_MAC_VERSION_MAS_ACCOUNT = '12.0'
+
class Mas(object):
@@ -115,6 +120,7 @@ class Mas(object):
# Initialize data properties
self.mas_path = self.module.get_bin_path('mas')
self._checked_signin = False
+ self._mac_version = platform.mac_ver()[0] or '0.0'
self._installed = None # Populated only if needed
self._outdated = None # Populated only if needed
self.count_install = 0
@@ -156,14 +162,16 @@ class Mas(object):
def check_signin(self):
''' Verifies that the user is signed in to the Mac App Store '''
-
# Only check this once per execution
if self._checked_signin:
return
-
- rc, out, err = self.run(['account'])
- if out.split("\n", 1)[0].rstrip() == 'Not signed in':
- self.module.fail_json(msg='You must be signed in to the Mac App Store')
+ if LooseVersion(self._mac_version) >= LooseVersion(NOT_WORKING_MAC_VERSION_MAS_ACCOUNT):
+ # Checking if user is signed-in is disabled due to https://github.com/mas-cli/mas/issues/417
+ self.module.log('WARNING: You must be signed in via the Mac App Store GUI beforehand else error will occur')
+ else:
+ rc, out, err = self.run(['account'])
+ if out.split("\n", 1)[0].rstrip() == 'Not signed in':
+ self.module.fail_json(msg='You must be signed in to the Mac App Store')
self._checked_signin = True
diff --git a/ansible_collections/community/general/plugins/modules/mattermost.py b/ansible_collections/community/general/plugins/modules/mattermost.py
index 29894c3a7..154040a8f 100644
--- a/ansible_collections/community/general/plugins/modules/mattermost.py
+++ b/ansible_collections/community/general/plugins/modules/mattermost.py
@@ -39,26 +39,26 @@ options:
description:
- Mattermost webhook api key. Log into your mattermost site, go to
Menu -> Integration -> Incoming Webhook -> Add Incoming Webhook.
- This will give you full URL. api_key is the last part.
+ This will give you full URL. O(api_key) is the last part.
http://mattermost.example.com/hooks/C(API_KEY)
required: true
text:
type: str
description:
- Text to send. Note that the module does not handle escaping characters.
- - Required when I(attachments) is not set.
+ - Required when O(attachments) is not set.
attachments:
type: list
elements: dict
description:
- Define a list of attachments.
- For more information, see U(https://developers.mattermost.com/integrate/admin-guide/admin-message-attachments/).
- - Required when I(text) is not set.
+ - Required when O(text) is not set.
version_added: 4.3.0
channel:
type: str
description:
- - Channel to send the message to. If absent, the message goes to the channel selected for the I(api_key).
+ - Channel to send the message to. If absent, the message goes to the channel selected for the O(api_key).
username:
type: str
description:
@@ -71,7 +71,7 @@ options:
default: https://docs.ansible.com/favicon.ico
validate_certs:
description:
- - If C(false), SSL certificates will not be validated. This should only be used
+ - If V(false), SSL certificates will not be validated. This should only be used
on personally controlled sites using self-signed certificates.
default: true
type: bool
diff --git a/ansible_collections/community/general/plugins/modules/maven_artifact.py b/ansible_collections/community/general/plugins/modules/maven_artifact.py
index 3f9defa52..0dc020c37 100644
--- a/ansible_collections/community/general/plugins/modules/maven_artifact.py
+++ b/ansible_collections/community/general/plugins/modules/maven_artifact.py
@@ -43,14 +43,14 @@ options:
type: str
description:
- The maven version coordinate
- - Mutually exclusive with I(version_by_spec).
+ - Mutually exclusive with O(version_by_spec).
version_by_spec:
type: str
description:
- The maven dependency version ranges.
- See supported version ranges on U(https://cwiki.apache.org/confluence/display/MAVENOLD/Dependency+Mediation+and+Conflict+Resolution)
- The range type "(,1.0],[1.2,)" and "(,1.1),(1.1,)" is not supported.
- - Mutually exclusive with I(version).
+ - Mutually exclusive with O(version).
version_added: '0.2.0'
classifier:
type: str
@@ -111,48 +111,48 @@ options:
default: 10
validate_certs:
description:
- - If C(false), SSL certificates will not be validated. This should only be set to C(false) when no other option exists.
+ - If V(false), SSL certificates will not be validated. This should only be set to V(false) when no other option exists.
type: bool
default: true
client_cert:
description:
- PEM formatted certificate chain file to be used for SSL client authentication.
- - This file can also include the key as well, and if the key is included, I(client_key) is not required.
+ - This file can also include the key as well, and if the key is included, O(client_key) is not required.
type: path
version_added: '1.3.0'
client_key:
description:
- PEM formatted file that contains your private key to be used for SSL client authentication.
- - If I(client_cert) contains both the certificate and key, this option is not required.
+ - If O(client_cert) contains both the certificate and key, this option is not required.
type: path
version_added: '1.3.0'
keep_name:
description:
- - If C(true), the downloaded artifact's name is preserved, i.e the version number remains part of it.
- - This option only has effect when C(dest) is a directory and C(version) is set to C(latest) or C(version_by_spec)
+ - If V(true), the downloaded artifact's name is preserved, i.e the version number remains part of it.
+ - This option only has effect when O(dest) is a directory and O(version) is set to V(latest) or O(version_by_spec)
is defined.
type: bool
default: false
verify_checksum:
type: str
description:
- - If C(never), the MD5/SHA1 checksum will never be downloaded and verified.
- - If C(download), the MD5/SHA1 checksum will be downloaded and verified only after artifact download. This is the default.
- - If C(change), the MD5/SHA1 checksum will be downloaded and verified if the destination already exist,
+ - If V(never), the MD5/SHA1 checksum will never be downloaded and verified.
+ - If V(download), the MD5/SHA1 checksum will be downloaded and verified only after artifact download. This is the default.
+ - If V(change), the MD5/SHA1 checksum will be downloaded and verified if the destination already exist,
to verify if they are identical. This was the behaviour before 2.6. Since it downloads the checksum before (maybe)
downloading the artifact, and since some repository software, when acting as a proxy/cache, return a 404 error
if the artifact has not been cached yet, it may fail unexpectedly.
- If you still need it, you should consider using C(always) instead - if you deal with a checksum, it is better to
+ If you still need it, you should consider using V(always) instead - if you deal with a checksum, it is better to
use it to verify integrity after download.
- - C(always) combines C(download) and C(change).
+ - V(always) combines V(download) and V(change).
required: false
default: 'download'
choices: ['never', 'download', 'change', 'always']
checksum_alg:
type: str
description:
- - If C(md5), checksums will use the MD5 algorithm. This is the default.
- - If C(sha1), checksums will use the SHA1 algorithm. This can be used on systems configured to use
+ - If V(md5), checksums will use the MD5 algorithm. This is the default.
+ - If V(sha1), checksums will use the SHA1 algorithm. This can be used on systems configured to use
FIPS-compliant algorithms, since MD5 will be blocked on such systems.
default: 'md5'
choices: ['md5', 'sha1']
@@ -162,14 +162,14 @@ options:
elements: str
version_added: 5.2.0
description:
- - A list of headers that should not be included in the redirection. This headers are sent to the fetch_url C(fetch_url) function.
- - On ansible-core version 2.12 or later, the default of this option is C([Authorization, Cookie]).
+ - A list of headers that should not be included in the redirection. This headers are sent to the C(fetch_url) function.
+ - On ansible-core version 2.12 or later, the default of this option is V([Authorization, Cookie]).
- Useful if the redirection URL does not need to have sensitive headers in the request.
- Requires ansible-core version 2.12 or later.
directory_mode:
type: str
description:
- - Filesystem permission mode applied recursively to I(dest) when it is a directory.
+ - Filesystem permission mode applied recursively to O(dest) when it is a directory.
extends_documentation_fragment:
- ansible.builtin.files
- community.general.attributes
diff --git a/ansible_collections/community/general/plugins/modules/memset_dns_reload.py b/ansible_collections/community/general/plugins/modules/memset_dns_reload.py
index a1168724f..668c8c0bf 100644
--- a/ansible_collections/community/general/plugins/modules/memset_dns_reload.py
+++ b/ansible_collections/community/general/plugins/modules/memset_dns_reload.py
@@ -18,8 +18,8 @@ notes:
happen every 15 minutes by default, however you can request an immediate reload if
later tasks rely on the records being created. An API key generated via the
Memset customer control panel is required with the following minimum scope -
- I(dns.reload). If you wish to poll the job status to wait until the reload has
- completed, then I(job.status) is also required.
+ C(dns.reload). If you wish to poll the job status to wait until the reload has
+ completed, then C(job.status) is also required.
description:
- Request a reload of Memset's DNS infrastructure, and optionally poll until it finishes.
extends_documentation_fragment:
diff --git a/ansible_collections/community/general/plugins/modules/memset_memstore_info.py b/ansible_collections/community/general/plugins/modules/memset_memstore_info.py
index 5fc9d79e1..c00ef15eb 100644
--- a/ansible_collections/community/general/plugins/modules/memset_memstore_info.py
+++ b/ansible_collections/community/general/plugins/modules/memset_memstore_info.py
@@ -15,10 +15,9 @@ author: "Simon Weald (@glitchcrab)"
short_description: Retrieve Memstore product usage information
notes:
- An API key generated via the Memset customer control panel is needed with the
- following minimum scope - I(memstore.usage).
+ following minimum scope - C(memstore.usage).
description:
- Retrieve Memstore product usage information.
- - This module was called C(memset_memstore_facts) before Ansible 2.9. The usage did not change.
extends_documentation_fragment:
- community.general.attributes
- community.general.attributes.info_module
@@ -36,7 +35,7 @@ options:
required: true
type: str
description:
- - The Memstore product name (i.e. C(mstestyaa1)).
+ - The Memstore product name (that is, C(mstestyaa1)).
'''
EXAMPLES = '''
diff --git a/ansible_collections/community/general/plugins/modules/memset_server_info.py b/ansible_collections/community/general/plugins/modules/memset_server_info.py
index ecc0375eb..78ea99df3 100644
--- a/ansible_collections/community/general/plugins/modules/memset_server_info.py
+++ b/ansible_collections/community/general/plugins/modules/memset_server_info.py
@@ -15,10 +15,9 @@ author: "Simon Weald (@glitchcrab)"
short_description: Retrieve server information
notes:
- An API key generated via the Memset customer control panel is needed with the
- following minimum scope - I(server.info).
+ following minimum scope - C(server.info).
description:
- Retrieve server information.
- - This module was called C(memset_server_facts) before Ansible 2.9. The usage did not change.
extends_documentation_fragment:
- community.general.attributes
- community.general.attributes.info_module
@@ -36,7 +35,7 @@ options:
required: true
type: str
description:
- - The server product name (i.e. C(testyaa1)).
+ - The server product name (that is, C(testyaa1)).
'''
EXAMPLES = '''
diff --git a/ansible_collections/community/general/plugins/modules/memset_zone.py b/ansible_collections/community/general/plugins/modules/memset_zone.py
index e17472e39..f520d5446 100644
--- a/ansible_collections/community/general/plugins/modules/memset_zone.py
+++ b/ansible_collections/community/general/plugins/modules/memset_zone.py
@@ -17,7 +17,7 @@ notes:
- Zones can be thought of as a logical group of domains, all of which share the
same DNS records (i.e. they point to the same IP). An API key generated via the
Memset customer control panel is needed with the following minimum scope -
- I(dns.zone_create), I(dns.zone_delete), I(dns.zone_list).
+ C(dns.zone_create), C(dns.zone_delete), C(dns.zone_list).
description:
- Manage DNS zones in a Memset account.
extends_documentation_fragment:
diff --git a/ansible_collections/community/general/plugins/modules/memset_zone_domain.py b/ansible_collections/community/general/plugins/modules/memset_zone_domain.py
index 172a48be2..e07ac1ff0 100644
--- a/ansible_collections/community/general/plugins/modules/memset_zone_domain.py
+++ b/ansible_collections/community/general/plugins/modules/memset_zone_domain.py
@@ -17,9 +17,9 @@ notes:
- Zone domains can be thought of as a collection of domains, all of which share the
same DNS records (i.e. they point to the same IP). An API key generated via the
Memset customer control panel is needed with the following minimum scope -
- I(dns.zone_domain_create), I(dns.zone_domain_delete), I(dns.zone_domain_list).
+ C(dns.zone_domain_create), C(dns.zone_domain_delete), C(dns.zone_domain_list).
- Currently this module can only create one domain at a time. Multiple domains should
- be created using C(with_items).
+ be created using C(loop).
description:
- Manage DNS zone domains in a Memset account.
extends_documentation_fragment:
diff --git a/ansible_collections/community/general/plugins/modules/memset_zone_record.py b/ansible_collections/community/general/plugins/modules/memset_zone_record.py
index 4e56a11ca..8406d93d2 100644
--- a/ansible_collections/community/general/plugins/modules/memset_zone_record.py
+++ b/ansible_collections/community/general/plugins/modules/memset_zone_record.py
@@ -17,9 +17,9 @@ notes:
- Zones can be thought of as a logical group of domains, all of which share the
same DNS records (i.e. they point to the same IP). An API key generated via the
Memset customer control panel is needed with the following minimum scope -
- I(dns.zone_create), I(dns.zone_delete), I(dns.zone_list).
+ C(dns.zone_create), C(dns.zone_delete), C(dns.zone_list).
- Currently this module can only create one DNS record at a time. Multiple records
- should be created using C(with_items).
+ should be created using C(loop).
description:
- Manage DNS records in a Memset account.
extends_documentation_fragment:
diff --git a/ansible_collections/community/general/plugins/modules/modprobe.py b/ansible_collections/community/general/plugins/modules/modprobe.py
index 6389d758d..f271b3946 100644
--- a/ansible_collections/community/general/plugins/modules/modprobe.py
+++ b/ansible_collections/community/general/plugins/modules/modprobe.py
@@ -49,14 +49,14 @@ options:
description:
- Persistency between reboots for configured module.
- This option creates files in C(/etc/modules-load.d/) and C(/etc/modprobe.d/) that make your module configuration persistent during reboots.
- - If C(present), adds module name to C(/etc/modules-load.d/) and params to C(/etc/modprobe.d/) so the module will be loaded on next reboot.
- - If C(absent), will comment out module name from C(/etc/modules-load.d/) and comment out params from C(/etc/modprobe.d/) so the module will not be
+ - If V(present), adds module name to C(/etc/modules-load.d/) and params to C(/etc/modprobe.d/) so the module will be loaded on next reboot.
+ - If V(absent), will comment out module name from C(/etc/modules-load.d/) and comment out params from C(/etc/modprobe.d/) so the module will not be
loaded on next reboot.
- - If C(disabled), will not touch anything and leave C(/etc/modules-load.d/) and C(/etc/modprobe.d/) as it is.
+ - If V(disabled), will not touch anything and leave C(/etc/modules-load.d/) and C(/etc/modprobe.d/) as it is.
- Note that it is usually a better idea to rely on the automatic module loading by PCI IDs, USB IDs, DMI IDs or similar triggers encoded in the
kernel modules themselves instead of configuration like this.
- In fact, most modern kernel modules are prepared for automatic loading already.
- - "B(Note:) This option works only with distributions that use C(systemd) when set to values other than C(disabled)."
+ - "B(Note:) This option works only with distributions that use C(systemd) when set to values other than V(disabled)."
'''
EXAMPLES = '''
@@ -232,12 +232,16 @@ class Modprobe(object):
@property
def modules_files(self):
+ if not os.path.isdir(MODULES_LOAD_LOCATION):
+ return []
modules_paths = [os.path.join(MODULES_LOAD_LOCATION, path)
for path in os.listdir(MODULES_LOAD_LOCATION)]
return [path for path in modules_paths if os.path.isfile(path)]
@property
def modprobe_files(self):
+ if not os.path.isdir(PARAMETERS_FILES_LOCATION):
+ return []
modules_paths = [os.path.join(PARAMETERS_FILES_LOCATION, path)
for path in os.listdir(PARAMETERS_FILES_LOCATION)]
return [path for path in modules_paths if os.path.isfile(path)]
diff --git a/ansible_collections/community/general/plugins/modules/monit.py b/ansible_collections/community/general/plugins/modules/monit.py
index d2a160678..5475ab1e5 100644
--- a/ansible_collections/community/general/plugins/modules/monit.py
+++ b/ansible_collections/community/general/plugins/modules/monit.py
@@ -14,7 +14,7 @@ DOCUMENTATION = '''
module: monit
short_description: Manage the state of a program monitored via Monit
description:
- - Manage the state of a program monitored via I(Monit).
+ - Manage the state of a program monitored via Monit.
extends_documentation_fragment:
- community.general.attributes
attributes:
@@ -25,7 +25,7 @@ attributes:
options:
name:
description:
- - The name of the I(monit) program/process to manage.
+ - The name of the C(monit) program/process to manage.
required: true
type: str
state:
diff --git a/ansible_collections/community/general/plugins/modules/mqtt.py b/ansible_collections/community/general/plugins/modules/mqtt.py
index 389382649..f8d64e6a0 100644
--- a/ansible_collections/community/general/plugins/modules/mqtt.py
+++ b/ansible_collections/community/general/plugins/modules/mqtt.py
@@ -40,7 +40,7 @@ options:
password:
type: str
description:
- - Password for C(username) to authenticate against the broker.
+ - Password for O(username) to authenticate against the broker.
client_id:
type: str
description:
@@ -54,8 +54,8 @@ options:
payload:
type: str
description:
- - Payload. The special string C("None") may be used to send a NULL
- (i.e. empty) payload which is useful to simply notify with the I(topic)
+ - Payload. The special string V("None") may be used to send a NULL
+ (that is, empty) payload which is useful to simply notify with the O(topic)
or to clear previously retained messages.
required: true
qos:
diff --git a/ansible_collections/community/general/plugins/modules/mssql_db.py b/ansible_collections/community/general/plugins/modules/mssql_db.py
index 4006033cf..a85f721fc 100644
--- a/ansible_collections/community/general/plugins/modules/mssql_db.py
+++ b/ansible_collections/community/general/plugins/modules/mssql_db.py
@@ -71,7 +71,6 @@ notes:
- Requires the pymssql Python package on the remote host. For Ubuntu, this
is as easy as pip install pymssql (See M(ansible.builtin.pip).)
requirements:
- - python >= 2.7
- pymssql
author: Vedit Firat Arig (@vedit)
'''
diff --git a/ansible_collections/community/general/plugins/modules/mssql_script.py b/ansible_collections/community/general/plugins/modules/mssql_script.py
index 1696000db..b1713092c 100644
--- a/ansible_collections/community/general/plugins/modules/mssql_script.py
+++ b/ansible_collections/community/general/plugins/modules/mssql_script.py
@@ -46,33 +46,41 @@ options:
type: str
required: true
login_port:
- description: Port of the MSSQL server. Requires I(login_host) be defined as well.
+ description: Port of the MSSQL server. Requires O(login_host) be defined as well.
default: 1433
type: int
script:
description:
- The SQL script to be executed.
- - Script can contain multiple SQL statements. Multiple Batches can be separated by C(GO) command.
+ - Script can contain multiple SQL statements. Multiple Batches can be separated by V(GO) command.
- Each batch must return at least one result set.
required: true
type: str
+ transaction:
+ description:
+ - If transactional mode is requested, start a transaction and commit the change only if the script succeed.
+ Otherwise, rollback the transaction.
+ - If transactional mode is not requested (default), automatically commit the change.
+ type: bool
+ default: false
+ version_added: 8.4.0
output:
description:
- - With C(default) each row will be returned as a list of values. See C(query_results).
- - Output format C(dict) will return dictionary with the column names as keys. See C(query_results_dict).
- - C(dict) requires named columns to be returned by each query otherwise an error is thrown.
+ - With V(default) each row will be returned as a list of values. See RV(query_results).
+ - Output format V(dict) will return dictionary with the column names as keys. See RV(query_results_dict).
+ - V(dict) requires named columns to be returned by each query otherwise an error is thrown.
choices: [ "dict", "default" ]
default: 'default'
type: str
params:
description: |
- Parameters passed to the script as SQL parameters. ('SELECT %(name)s"' with C(example: '{"name": "John Doe"}).)'
+ Parameters passed to the script as SQL parameters.
+ (Query V('SELECT %(name\)s"') with V(example: '{"name": "John Doe"}).)'
type: dict
notes:
- Requires the pymssql Python package on the remote host. For Ubuntu, this
is as easy as C(pip install pymssql) (See M(ansible.builtin.pip).)
requirements:
- - python >= 2.7
- pymssql
author:
@@ -105,6 +113,19 @@ EXAMPLES = r'''
- result_params.query_results[0][0][0][0] == 'msdb'
- result_params.query_results[0][0][0][1] == 'ONLINE'
+- name: Query within a transaction
+ community.general.mssql_script:
+ login_user: "{{ mssql_login_user }}"
+ login_password: "{{ mssql_login_password }}"
+ login_host: "{{ mssql_host }}"
+ login_port: "{{ mssql_port }}"
+ script: |
+ UPDATE sys.SomeTable SET desc = 'some_table_desc' WHERE name = %(dbname)s
+ UPDATE sys.AnotherTable SET desc = 'another_table_desc' WHERE name = %(dbname)s
+ transaction: true
+ params:
+ dbname: msdb
+
- name: two batches with default output
community.general.mssql_script:
login_user: "{{ mssql_login_user }}"
@@ -148,17 +169,17 @@ EXAMPLES = r'''
RETURN = r'''
query_results:
- description: List of batches (queries separated by C(GO) keyword).
+ description: List of batches (queries separated by V(GO) keyword).
type: list
elements: list
- returned: success and I(output=default)
+ returned: success and O(output=default)
sample: [[[["Batch 0 - Select 0"]], [["Batch 0 - Select 1"]]], [[["Batch 1 - Select 0"]]]]
contains:
queries:
description:
- List of result sets of each query.
- If a query returns no results, the results of this and all the following queries will not be included in the output.
- - Use the C(GO) keyword in I(script) to separate queries.
+ - Use the V(GO) keyword in O(script) to separate queries.
type: list
elements: list
contains:
@@ -175,10 +196,10 @@ query_results:
example: ["Batch 0 - Select 0"]
returned: success, if output is default
query_results_dict:
- description: List of batches (queries separated by C(GO) keyword).
+ description: List of batches (queries separated by V(GO) keyword).
type: list
elements: list
- returned: success and I(output=dict)
+ returned: success and O(output=dict)
sample: [[[["Batch 0 - Select 0"]], [["Batch 0 - Select 1"]]], [[["Batch 1 - Select 0"]]]]
contains:
queries:
@@ -230,6 +251,7 @@ def run_module():
script=dict(required=True),
output=dict(default='default', choices=['dict', 'default']),
params=dict(type='dict'),
+ transaction=dict(type='bool', default=False),
)
result = dict(
@@ -252,6 +274,8 @@ def run_module():
script = module.params['script']
output = module.params['output']
sql_params = module.params['params']
+ # Added param to set the transactional mode (true/false)
+ transaction = module.params['transaction']
login_querystring = login_host
if login_port != 1433:
@@ -273,21 +297,40 @@ def run_module():
module.fail_json(msg="unable to connect, check login_user and login_password are correct, or alternatively check your "
"@sysconfdir@/freetds.conf / ${HOME}/.freetds.conf")
- conn.autocommit(True)
+ # If transactional mode is requested, start a transaction
+ conn.autocommit(not transaction)
query_results_key = 'query_results'
if output == 'dict':
cursor = conn.cursor(as_dict=True)
query_results_key = 'query_results_dict'
- queries = script.split('\nGO\n')
+ # Process the script into batches
+ queries = []
+ current_batch = []
+ for statement in script.splitlines(True):
+ # Ignore the Byte Order Mark, if found
+ if statement.strip() == '\uFEFF':
+ continue
+
+ # Assume each 'GO' is on its own line but may have leading/trailing whitespace
+ # and be of mixed-case
+ if statement.strip().upper() != 'GO':
+ current_batch.append(statement)
+ else:
+ queries.append(''.join(current_batch))
+ current_batch = []
+ if len(current_batch) > 0:
+ queries.append(''.join(current_batch))
+
result['changed'] = True
if module.check_mode:
module.exit_json(**result)
query_results = []
- try:
- for query in queries:
+ for query in queries:
+ # Catch and exit on any bad query errors
+ try:
cursor.execute(query, sql_params)
qry_result = []
rows = cursor.fetchall()
@@ -295,8 +338,24 @@ def run_module():
qry_result.append(rows)
rows = cursor.fetchall()
query_results.append(qry_result)
- except Exception as e:
- return module.fail_json(msg="query failed", query=query, error=str(e), **result)
+ except Exception as e:
+ # We know we executed the statement so this error just means we have no resultset
+ # which is ok (eg UPDATE/INSERT)
+ if (
+ type(e).__name__ == 'OperationalError' and
+ str(e) == 'Statement not executed or executed statement has no resultset'
+ ):
+ query_results.append([])
+ else:
+ # Rollback transaction before failing the module in case of error
+ if transaction:
+ conn.rollback()
+ error_msg = '%s: %s' % (type(e).__name__, str(e))
+ module.fail_json(msg="query failed", query=query, error=error_msg, **result)
+
+ # Commit transaction before exiting the module in case of no error
+ if transaction:
+ conn.commit()
# ensure that the result is json serializable
qry_results = json.loads(json.dumps(query_results, default=clean_output))
diff --git a/ansible_collections/community/general/plugins/modules/nagios.py b/ansible_collections/community/general/plugins/modules/nagios.py
index 1831d0496..783aa88e2 100644
--- a/ansible_collections/community/general/plugins/modules/nagios.py
+++ b/ansible_collections/community/general/plugins/modules/nagios.py
@@ -21,13 +21,13 @@ short_description: Perform common tasks in Nagios related to downtime and notifi
description:
- "The C(nagios) module has two basic functions: scheduling downtime and toggling alerts for services or hosts."
- The C(nagios) module is not idempotent.
- - All actions require the I(host) parameter to be given explicitly. In playbooks you can use the C({{inventory_hostname}}) variable to refer
+ - All actions require the O(host) parameter to be given explicitly. In playbooks you can use the C({{inventory_hostname}}) variable to refer
to the host the playbook is currently running on.
- - You can specify multiple services at once by separating them with commas, .e.g. I(services=httpd,nfs,puppet).
- - When specifying what service to handle there is a special service value, I(host), which will handle alerts/downtime/acknowledge for the I(host itself),
- e.g., I(service=host). This keyword may not be given with other services at the same time.
- I(Setting alerts/downtime/acknowledge for a host does not affect alerts/downtime/acknowledge for any of the services running on it.)
- To schedule downtime for all services on particular host use keyword "all", e.g., I(service=all).
+ - You can specify multiple services at once by separating them with commas, .e.g. O(services=httpd,nfs,puppet).
+ - When specifying what service to handle there is a special service value, O(host), which will handle alerts/downtime/acknowledge for the I(host itself),
+ for example O(services=host). This keyword may not be given with other services at the same time.
+ B(Setting alerts/downtime/acknowledge for a host does not affect alerts/downtime/acknowledge for any of the services running on it.)
+ To schedule downtime for all services on particular host use keyword "all", for example O(services=all).
extends_documentation_fragment:
- community.general.attributes
attributes:
@@ -41,7 +41,7 @@ options:
- Action to take.
- servicegroup options were added in 2.0.
- delete_downtime options were added in 2.2.
- - The C(acknowledge) and C(forced_check) actions were added in community.general 1.2.0.
+ - The V(acknowledge) and V(forced_check) actions were added in community.general 1.2.0.
required: true
choices: [ "downtime", "delete_downtime", "enable_alerts", "disable_alerts", "silence", "unsilence",
"silence_nagios", "unsilence_nagios", "command", "servicegroup_service_downtime",
@@ -59,12 +59,12 @@ options:
author:
description:
- Author to leave downtime comments as.
- Only used when I(action) is C(downtime) or C(acknowledge).
+ Only used when O(action) is V(downtime) or V(acknowledge).
type: str
default: Ansible
comment:
description:
- - Comment when I(action) is C(downtime) or C(acknowledge).
+ - Comment when O(action) is V(downtime) or V(acknowledge).
type: str
default: Scheduling downtime
start:
@@ -75,27 +75,24 @@ options:
minutes:
description:
- Minutes to schedule downtime for.
- - Only usable with the C(downtime) action.
+ - Only usable with O(action=downtime).
type: int
default: 30
services:
description:
- - >
- What to manage downtime/alerts for. Separate multiple services with commas.
- I(service) is an alias for I(services).
- B(Required) option when I(action) is one of: C(downtime), C(acknowledge), C(forced_check), C(enable_alerts), C(disable_alerts).
+ - What to manage downtime/alerts for. Separate multiple services with commas.
+ - "B(Required) option when O(action) is one of: V(downtime), V(acknowledge), V(forced_check), V(enable_alerts), V(disable_alerts)."
aliases: [ "service" ]
type: str
servicegroup:
description:
- The Servicegroup we want to set downtimes/alerts for.
- B(Required) option when using the C(servicegroup_service_downtime) amd C(servicegroup_host_downtime).
+ - B(Required) option when using the V(servicegroup_service_downtime) and V(servicegroup_host_downtime) O(action).
type: str
command:
description:
- - The raw command to send to nagios, which
- should not include the submitted time header or the line-feed
- B(Required) option when using the C(command) action.
+ - The raw command to send to nagios, which should not include the submitted time header or the line-feed.
+ - B(Required) option when using the V(command) O(action).
type: str
author: "Tim Bielawa (@tbielawa)"
diff --git a/ansible_collections/community/general/plugins/modules/netcup_dns.py b/ansible_collections/community/general/plugins/modules/netcup_dns.py
index 77be50b2c..cba70c0fa 100644
--- a/ansible_collections/community/general/plugins/modules/netcup_dns.py
+++ b/ansible_collections/community/general/plugins/modules/netcup_dns.py
@@ -46,14 +46,17 @@ options:
type: str
record:
description:
- - Record to add or delete, supports wildcard (*). Default is C(@) (e.g. the zone name).
+ - Record to add or delete, supports wildcard (V(*)). Default is V(@) (that is, the zone name).
default: "@"
aliases: [ name ]
type: str
type:
description:
- Record type.
- choices: ['A', 'AAAA', 'MX', 'CNAME', 'CAA', 'SRV', 'TXT', 'TLSA', 'NS', 'DS']
+ - Support for V(OPENPGPKEY), V(SMIMEA) and V(SSHFP) was added in community.general 8.1.0.
+ - Record types V(OPENPGPKEY) and V(SMIMEA) require nc-dnsapi >= 0.1.5.
+ - Record type V(SSHFP) requires nc-dnsapi >= 0.1.6.
+ choices: ['A', 'AAAA', 'MX', 'CNAME', 'CAA', 'SRV', 'TXT', 'TLSA', 'NS', 'DS', 'OPENPGPKEY', 'SMIMEA', 'SSHFP']
required: true
type: str
value:
@@ -65,11 +68,11 @@ options:
type: bool
default: false
description:
- - Whether the record should be the only one for that record type and record name. Only use with I(state=present).
+ - Whether the record should be the only one for that record type and record name. Only use with O(state=present).
- This will delete all other records with the same record name and type.
priority:
description:
- - Record priority. Required for I(type=MX).
+ - Record priority. Required for O(type=MX).
required: false
type: int
state:
@@ -169,7 +172,7 @@ records:
sample: fancy-hostname
type:
description: the record type
- returned: succcess
+ returned: success
type: str
sample: A
value:
@@ -213,7 +216,9 @@ def main():
domain=dict(required=True),
record=dict(required=False, default='@', aliases=['name']),
- type=dict(required=True, choices=['A', 'AAAA', 'MX', 'CNAME', 'CAA', 'SRV', 'TXT', 'TLSA', 'NS', 'DS']),
+ type=dict(required=True, choices=['A', 'AAAA', 'MX', 'CNAME', 'CAA', 'SRV', 'TXT',
+ 'TLSA', 'NS', 'DS', 'OPENPGPKEY', 'SMIMEA',
+ 'SSHFP']),
value=dict(required=True),
priority=dict(required=False, type='int'),
solo=dict(required=False, type='bool', default=False),
diff --git a/ansible_collections/community/general/plugins/modules/newrelic_deployment.py b/ansible_collections/community/general/plugins/modules/newrelic_deployment.py
index ac9903b57..e5a116082 100644
--- a/ansible_collections/community/general/plugins/modules/newrelic_deployment.py
+++ b/ansible_collections/community/general/plugins/modules/newrelic_deployment.py
@@ -32,14 +32,14 @@ options:
app_name:
type: str
description:
- - The value of app_name in the newrelic.yml file used by the application.
- - One of I(app_name) or I(application_id) is required.
+ - The value of C(app_name) in the C(newrelic.yml) file used by the application.
+ - One of O(app_name) or O(application_id) is required.
required: false
application_id:
type: str
description:
- The application ID found in the metadata of the application in APM.
- - One of I(app_name) or I(application_id) is required.
+ - One of O(app_name) or O(application_id) is required.
required: false
changelog:
type: str
@@ -61,25 +61,21 @@ options:
description:
- The name of the user/process that triggered this deployment
required: false
- appname:
- type: str
- description:
- - Name of the application.
- - This option has been deprecated and will be removed in community.general 7.0.0. Please do not use.
- required: false
- environment:
- type: str
- description:
- - The environment for this deployment.
- - This option has been deprecated and will be removed community.general 7.0.0. Please do not use.
- required: false
validate_certs:
description:
- - If C(false), SSL certificates will not be validated. This should only be used
+ - If V(false), SSL certificates will not be validated. This should only be used
on personally controlled sites using self-signed certificates.
required: false
default: true
type: bool
+ app_name_exact_match:
+ type: bool
+ description:
+ - If this flag is set to V(true) then the application ID lookup by name would only work for an exact match.
+ If set to V(false) it returns the first result.
+ required: false
+ default: false
+ version_added: 7.5.0
requirements: []
'''
@@ -113,11 +109,11 @@ def main():
description=dict(required=False),
revision=dict(required=True),
user=dict(required=False),
- appname=dict(required=False, removed_in_version='7.0.0', removed_from_collection='community.general'),
- environment=dict(required=False, removed_in_version='7.0.0', removed_from_collection='community.general'),
validate_certs=dict(default=True, type='bool'),
+ app_name_exact_match=dict(required=False, type='bool', default=False),
),
required_one_of=[['app_name', 'application_id']],
+ required_if=[('app_name_exact_match', True, ['app_name'])],
supports_check_mode=True
)
@@ -125,7 +121,6 @@ def main():
params = {}
if module.params["app_name"] and module.params["application_id"]:
module.fail_json(msg="only one of 'app_name' or 'application_id' can be set")
-
app_id = None
if module.params["app_name"]:
app_id = get_application_id(module)
@@ -164,6 +159,7 @@ def main():
def get_application_id(module):
url = "https://api.newrelic.com/v2/applications.json"
data = "filter[name]=%s" % module.params["app_name"]
+ application_id = None
headers = {
'Api-Key': module.params["token"],
}
@@ -175,7 +171,17 @@ def get_application_id(module):
if result is None or len(result.get("applications", "")) == 0:
module.fail_json(msg='No application found with name "%s"' % module.params["app_name"])
- return result["applications"][0]["id"]
+ if module.params["app_name_exact_match"]:
+ for item in result["applications"]:
+ if item["name"] == module.params["app_name"]:
+ application_id = item["id"]
+ break
+ if application_id is None:
+ module.fail_json(msg='No application found with exact name "%s"' % module.params["app_name"])
+ else:
+ application_id = result["applications"][0]["id"]
+
+ return application_id
if __name__ == '__main__':
diff --git a/ansible_collections/community/general/plugins/modules/nexmo.py b/ansible_collections/community/general/plugins/modules/nexmo.py
index 7461c1cb9..39f127f98 100644
--- a/ansible_collections/community/general/plugins/modules/nexmo.py
+++ b/ansible_collections/community/general/plugins/modules/nexmo.py
@@ -50,7 +50,7 @@ options:
required: true
validate_certs:
description:
- - If C(false), SSL certificates will not be validated. This should only be used
+ - If V(false), SSL certificates will not be validated. This should only be used
on personally controlled sites using self-signed certificates.
type: bool
default: true
diff --git a/ansible_collections/community/general/plugins/modules/nictagadm.py b/ansible_collections/community/general/plugins/modules/nictagadm.py
index 074e09b4a..5b81861e8 100644
--- a/ansible_collections/community/general/plugins/modules/nictagadm.py
+++ b/ansible_collections/community/general/plugins/modules/nictagadm.py
@@ -31,23 +31,23 @@ options:
type: str
mac:
description:
- - Specifies the I(mac) address to attach the nic tag to when not creating an I(etherstub).
- - Parameters I(mac) and I(etherstub) are mutually exclusive.
+ - Specifies the O(mac) address to attach the nic tag to when not creating an O(etherstub).
+ - Parameters O(mac) and O(etherstub) are mutually exclusive.
type: str
etherstub:
description:
- - Specifies that the nic tag will be attached to a created I(etherstub).
- - Parameter I(etherstub) is mutually exclusive with both I(mtu), and I(mac).
+ - Specifies that the nic tag will be attached to a created O(etherstub).
+ - Parameter O(etherstub) is mutually exclusive with both O(mtu), and O(mac).
type: bool
default: false
mtu:
description:
- - Specifies the size of the I(mtu) of the desired nic tag.
- - Parameters I(mtu) and I(etherstub) are mutually exclusive.
+ - Specifies the size of the O(mtu) of the desired nic tag.
+ - Parameters O(mtu) and O(etherstub) are mutually exclusive.
type: int
force:
description:
- - When I(state) is absent set this switch will use the C(-f) parameter and delete the nic tag regardless of existing VMs.
+ - When O(state=absent) this switch will use the C(-f) parameter and delete the nic tag regardless of existing VMs.
type: bool
default: false
state:
diff --git a/ansible_collections/community/general/plugins/modules/nmcli.py b/ansible_collections/community/general/plugins/modules/nmcli.py
index 08680bf6e..9360ce37d 100644
--- a/ansible_collections/community/general/plugins/modules/nmcli.py
+++ b/ansible_collections/community/general/plugins/modules/nmcli.py
@@ -52,23 +52,25 @@ options:
description:
- The interface to bind the connection to.
- The connection will only be applicable to this interface name.
- - A special value of C('*') can be used for interface-independent connections.
+ - A special value of V('*') can be used for interface-independent connections.
- The ifname argument is mandatory for all connection types except bond, team, bridge, vlan and vpn.
- - This parameter defaults to C(conn_name) when left unset for all connection types except vpn that removes it.
+ - This parameter defaults to O(conn_name) when left unset for all connection types except vpn that removes it.
type: str
type:
description:
- This is the type of device or network connection that you wish to create or modify.
- - Type C(dummy) is added in community.general 3.5.0.
- - Type C(generic) is added in Ansible 2.5.
- - Type C(infiniband) is added in community.general 2.0.0.
- - Type C(gsm) is added in community.general 3.7.0.
- - Type C(macvlan) is added in community.general 6.6.0.
- - Type C(wireguard) is added in community.general 4.3.0.
- - Type C(vpn) is added in community.general 5.1.0.
+ - Type V(dummy) is added in community.general 3.5.0.
+ - Type V(gsm) is added in community.general 3.7.0.
+ - Type V(infiniband) is added in community.general 2.0.0.
+ - Type V(loopback) is added in community.general 8.1.0.
+ - Type V(macvlan) is added in community.general 6.6.0.
+ - Type V(wireguard) is added in community.general 4.3.0.
+ - Type V(vpn) is added in community.general 5.1.0.
+ - Using V(bond-slave), V(bridge-slave), or V(team-slave) implies V(ethernet) connection type with corresponding O(slave_type) option.
+ - If you want to control non-ethernet connection attached to V(bond), V(bridge), or V(team) consider using O(slave_type) option.
type: str
choices: [ bond, bond-slave, bridge, bridge-slave, dummy, ethernet, generic, gre, infiniband, ipip, macvlan, sit, team, team-slave, vlan, vxlan,
- wifi, gsm, wireguard, vpn ]
+ wifi, gsm, wireguard, vpn, loopback ]
mode:
description:
- This is the type of device or network connection that you wish to create for a bond or bridge.
@@ -81,21 +83,28 @@ options:
type: str
choices: [ datagram, connected ]
version_added: 5.8.0
+ slave_type:
+ description:
+ - Type of the device of this slave's master connection (for example V(bond)).
+ type: str
+ choices: [ 'bond', 'bridge', 'team' ]
+ version_added: 7.0.0
master:
description:
- Master <master (ifname, or connection UUID or conn_name) of bridge, team, bond master connection profile.
+ - Mandatory if O(slave_type) is defined.
type: str
ip4:
description:
- List of IPv4 addresses to this interface.
- - Use the format C(192.0.2.24/24) or C(192.0.2.24).
- - If defined and I(method4) is not specified, automatically set C(ipv4.method) to C(manual).
+ - Use the format V(192.0.2.24/24) or V(192.0.2.24).
+ - If defined and O(method4) is not specified, automatically set C(ipv4.method) to V(manual).
type: list
elements: str
gw4:
description:
- The IPv4 gateway for this interface.
- - Use the format C(192.0.2.1).
+ - Use the format V(192.0.2.1).
- This parameter is mutually_exclusive with never_default4 parameter.
type: str
gw4_ignore_auto:
@@ -107,8 +116,8 @@ options:
routes4:
description:
- The list of IPv4 routes.
- - Use the format C(192.0.3.0/24 192.0.2.1).
- - To specify more complex routes, use the I(routes4_extended) option.
+ - Use the format V(192.0.3.0/24 192.0.2.1).
+ - To specify more complex routes, use the O(routes4_extended) option.
type: list
elements: str
version_added: 2.0.0
@@ -121,12 +130,12 @@ options:
ip:
description:
- IP or prefix of route.
- - Use the format C(192.0.3.0/24).
+ - Use the format V(192.0.3.0/24).
type: str
required: true
next_hop:
description:
- - Use the format C(192.0.2.1).
+ - Use the format V(192.0.2.1).
type: str
metric:
description:
@@ -160,7 +169,7 @@ options:
version_added: 2.0.0
routing_rules4:
description:
- - Is the same as in an C(ip route add) command, except always requires specifying a priority.
+ - Is the same as in an C(ip rule add) command, except always requires specifying a priority.
type: list
elements: str
version_added: 3.3.0
@@ -174,7 +183,7 @@ options:
dns4:
description:
- A list of up to 3 DNS servers.
- - The entries must be IPv4 addresses, for example C(192.0.2.53).
+ - The entries must be IPv4 addresses, for example V(192.0.2.53).
elements: str
type: list
dns4_search:
@@ -182,6 +191,12 @@ options:
- A list of DNS search domains.
elements: str
type: list
+ dns4_options:
+ description:
+ - A list of DNS options.
+ elements: str
+ type: list
+ version_added: 7.2.0
dns4_ignore_auto:
description:
- Ignore automatically configured IPv4 name servers.
@@ -191,28 +206,28 @@ options:
method4:
description:
- Configuration method to be used for IPv4.
- - If I(ip4) is set, C(ipv4.method) is automatically set to C(manual) and this parameter is not needed.
+ - If O(ip4) is set, C(ipv4.method) is automatically set to V(manual) and this parameter is not needed.
type: str
choices: [auto, link-local, manual, shared, disabled]
version_added: 2.2.0
may_fail4:
description:
- - If you need I(ip4) configured before C(network-online.target) is reached, set this option to C(false).
- - This option applies when C(method4) is not C(disabled).
+ - If you need O(ip4) configured before C(network-online.target) is reached, set this option to V(false).
+ - This option applies when O(method4) is not V(disabled).
type: bool
default: true
version_added: 3.3.0
ip6:
description:
- List of IPv6 addresses to this interface.
- - Use the format C(abbe::cafe/128) or C(abbe::cafe).
- - If defined and I(method6) is not specified, automatically set C(ipv6.method) to C(manual).
+ - Use the format V(abbe::cafe/128) or V(abbe::cafe).
+ - If defined and O(method6) is not specified, automatically set C(ipv6.method) to V(manual).
type: list
elements: str
gw6:
description:
- The IPv6 gateway for this interface.
- - Use the format C(2001:db8::1).
+ - Use the format V(2001:db8::1).
type: str
gw6_ignore_auto:
description:
@@ -223,8 +238,8 @@ options:
routes6:
description:
- The list of IPv6 routes.
- - Use the format C(fd12:3456:789a:1::/64 2001:dead:beef::1).
- - To specify more complex routes, use the I(routes6_extended) option.
+ - Use the format V(fd12:3456:789a:1::/64 2001:dead:beef::1).
+ - To specify more complex routes, use the O(routes6_extended) option.
type: list
elements: str
version_added: 4.4.0
@@ -237,12 +252,12 @@ options:
ip:
description:
- IP or prefix of route.
- - Use the format C(fd12:3456:789a:1::/64).
+ - Use the format V(fd12:3456:789a:1::/64).
type: str
required: true
next_hop:
description:
- - Use the format C(2001:dead:beef::1).
+ - Use the format V(2001:dead:beef::1).
type: str
metric:
description:
@@ -273,7 +288,7 @@ options:
dns6:
description:
- A list of up to 3 DNS servers.
- - The entries must be IPv6 addresses, for example C(2001:4860:4860::8888).
+ - The entries must be IPv6 addresses, for example V(2001:4860:4860::8888).
elements: str
type: list
dns6_search:
@@ -281,6 +296,12 @@ options:
- A list of DNS search domains.
elements: str
type: list
+ dns6_options:
+ description:
+ - A list of DNS options.
+ elements: str
+ type: list
+ version_added: 7.2.0
dns6_ignore_auto:
description:
- Ignore automatically configured IPv6 name servers.
@@ -290,8 +311,8 @@ options:
method6:
description:
- Configuration method to be used for IPv6
- - If I(ip6) is set, C(ipv6.method) is automatically set to C(manual) and this parameter is not needed.
- - C(disabled) was added in community.general 3.3.0.
+ - If O(ip6) is set, C(ipv6.method) is automatically set to V(manual) and this parameter is not needed.
+ - V(disabled) was added in community.general 3.3.0.
type: str
choices: [ignore, auto, dhcp, link-local, manual, shared, disabled]
version_added: 2.2.0
@@ -304,7 +325,7 @@ options:
addr_gen_mode6:
description:
- Configure method for creating the address for use with IPv6 Stateless Address Autoconfiguration.
- - C(default) and C(deafult-or-eui64) have been added in community.general 6.5.0.
+ - V(default) and V(default-or-eui64) have been added in community.general 6.5.0.
type: str
choices: [default, default-or-eui64, eui64, stable-privacy]
version_added: 4.2.0
@@ -312,7 +333,7 @@ options:
description:
- The connection MTU, e.g. 9000. This can't be applied when creating the interface and is done once the interface has been created.
- Can be used when modifying Team, VLAN, Ethernet (Future plans to implement wifi, gsm, pppoe, infiniband)
- - This parameter defaults to C(1500) when unset.
+ - This parameter defaults to V(1500) when unset.
type: int
dhcp_client_id:
description:
@@ -325,7 +346,7 @@ options:
miimon:
description:
- This is only used with bond - miimon.
- - This parameter defaults to C(100) when unset.
+ - This parameter defaults to V(100) when unset.
type: int
downdelay:
description:
@@ -397,9 +418,9 @@ options:
description:
- This is only used with 'bridge-slave' - 'hairpin mode' for the slave, which allows frames to be sent back out through the slave the
frame was received on.
- - The default value is C(true), but that is being deprecated
- and it will be changed to C(false) in community.general 7.0.0.
+ - The default change to V(false) in community.general 7.0.0. It used to be V(true) before.
type: bool
+ default: false
runner:
description:
- This is the type of device or network connection that you wish to create for a team.
@@ -417,9 +438,9 @@ options:
runner_fast_rate:
description:
- Option specifies the rate at which our link partner is asked to transmit LACPDU
- packets. If this is C(true) then packets will be sent once per second. Otherwise they
+ packets. If this is V(true) then packets will be sent once per second. Otherwise they
will be sent every 30 seconds.
- - Only allowed for C(lacp) runner.
+ - Only allowed for O(runner=lacp).
type: bool
version_added: 6.5.0
vlanid:
@@ -469,13 +490,13 @@ options:
ip_tunnel_input_key:
description:
- The key used for tunnel input packets.
- - Only used when I(type=gre).
+ - Only used when O(type=gre).
type: str
version_added: 3.6.0
ip_tunnel_output_key:
description:
- The key used for tunnel output packets.
- - Only used when I(type=gre).
+ - Only used when O(type=gre).
type: str
version_added: 3.6.0
zone:
@@ -491,23 +512,25 @@ options:
- 'An up-to-date list of supported attributes can be found here:
U(https://networkmanager.dev/docs/api/latest/settings-802-11-wireless-security.html).'
- 'For instance to use common WPA-PSK auth with a password:
- C({key-mgmt: wpa-psk, psk: my_password}).'
+ V({key-mgmt: wpa-psk, psk: my_password}).'
type: dict
suboptions:
auth-alg:
description:
- - When WEP is used (that is, if I(key-mgmt) = C(none) or C(ieee8021x)) indicate the 802.11 authentication algorithm required by the AP here.
- - One of C(open) for Open System, C(shared) for Shared Key, or C(leap) for Cisco LEAP.
- - When using Cisco LEAP (that is, if I(key-mgmt=ieee8021x) and I(auth-alg=leap)) the I(leap-username) and I(leap-password) properties
+ - When WEP is used (that is, if O(wifi_sec.key-mgmt) is V(none) or V(ieee8021x)) indicate the 802.11
+ authentication algorithm required by the AP here.
+ - One of V(open) for Open System, V(shared) for Shared Key, or V(leap) for Cisco LEAP.
+ - When using Cisco LEAP (that is, if O(wifi_sec.key-mgmt=ieee8021x) and O(wifi_sec.auth-alg=leap))
+ the O(wifi_sec.leap-username) and O(wifi_sec.leap-password) properties
must be specified.
type: str
choices: [ open, shared, leap ]
fils:
description:
- Indicates whether Fast Initial Link Setup (802.11ai) must be enabled for the connection.
- - One of C(0) (use global default value), C(1) (disable FILS), C(2) (enable FILS if the supplicant and the access point support it) or C(3)
+ - One of V(0) (use global default value), V(1) (disable FILS), V(2) (enable FILS if the supplicant and the access point support it) or V(3)
(enable FILS and fail if not supported).
- - When set to C(0) and no global default is set, FILS will be optionally enabled.
+ - When set to V(0) and no global default is set, FILS will be optionally enabled.
type: int
choices: [ 0, 1, 2, 3 ]
default: 0
@@ -522,20 +545,20 @@ options:
key-mgmt:
description:
- Key management used for the connection.
- - One of C(none) (WEP or no password protection), C(ieee8021x) (Dynamic WEP), C(owe) (Opportunistic Wireless Encryption), C(wpa-psk) (WPA2
- + WPA3 personal), C(sae) (WPA3 personal only), C(wpa-eap) (WPA2 + WPA3 enterprise) or C(wpa-eap-suite-b-192) (WPA3 enterprise only).
+ - One of V(none) (WEP or no password protection), V(ieee8021x) (Dynamic WEP), V(owe) (Opportunistic Wireless Encryption), V(wpa-psk) (WPA2
+ + WPA3 personal), V(sae) (WPA3 personal only), V(wpa-eap) (WPA2 + WPA3 enterprise) or V(wpa-eap-suite-b-192) (WPA3 enterprise only).
- This property must be set for any Wi-Fi connection that uses security.
type: str
choices: [ none, ieee8021x, owe, wpa-psk, sae, wpa-eap, wpa-eap-suite-b-192 ]
leap-password-flags:
- description: Flags indicating how to handle the I(leap-password) property.
+ description: Flags indicating how to handle the O(wifi_sec.leap-password) property.
type: list
elements: int
leap-password:
- description: The login password for legacy LEAP connections (that is, if I(key-mgmt=ieee8021x) and I(auth-alg=leap)).
+ description: The login password for legacy LEAP connections (that is, if O(wifi_sec.key-mgmt=ieee8021x) and O(wifi_sec.auth-alg=leap)).
type: str
leap-username:
- description: The login username for legacy LEAP connections (that is, if I(key-mgmt=ieee8021x) and I(auth-alg=leap)).
+ description: The login username for legacy LEAP connections (that is, if O(wifi_sec.key-mgmt=ieee8021x) and O(wifi_sec.auth-alg=leap)).
type: str
pairwise:
description:
@@ -548,68 +571,72 @@ options:
pmf:
description:
- Indicates whether Protected Management Frames (802.11w) must be enabled for the connection.
- - One of C(0) (use global default value), C(1) (disable PMF), C(2) (enable PMF if the supplicant and the access point support it) or C(3)
- (enable PMF and fail if not supported).
- - When set to C(0) and no global default is set, PMF will be optionally enabled.
+ - One of V(0) (use global default value), V(1) (disable PMF), V(2) (enable PMF if the
+ supplicant and the access point support it) or V(3) (enable PMF and fail if not supported).
+ - When set to V(0) and no global default is set, PMF will be optionally enabled.
type: int
choices: [ 0, 1, 2, 3 ]
default: 0
proto:
description:
- List of strings specifying the allowed WPA protocol versions to use.
- - Each element may be C(wpa) (allow WPA) or C(rsn) (allow WPA2/RSN).
+ - Each element may be V(wpa) (allow WPA) or V(rsn) (allow WPA2/RSN).
- If not specified, both WPA and RSN connections are allowed.
type: list
elements: str
choices: [ wpa, rsn ]
psk-flags:
- description: Flags indicating how to handle the I(psk) property.
+ description: Flags indicating how to handle the O(wifi_sec.psk) property.
type: list
elements: int
psk:
description:
- Pre-Shared-Key for WPA networks.
- - For WPA-PSK, it is either an ASCII passphrase of 8 to 63 characters that is (as specified in the 802.11i standard) hashed to derive the
+ - For WPA-PSK, it is either an ASCII passphrase of 8 to 63 characters that is
+ (as specified in the 802.11i standard) hashed to derive the
actual key, or the key in form of 64 hexadecimal character.
- The WPA3-Personal networks use a passphrase of any length for SAE authentication.
type: str
wep-key-flags:
- description: Flags indicating how to handle the I(wep-key0), I(wep-key1), I(wep-key2), and I(wep-key3) properties.
+ description:
+ - Flags indicating how to handle the O(wifi_sec.wep-key0), O(wifi_sec.wep-key1),
+ O(wifi_sec.wep-key2), and O(wifi_sec.wep-key3) properties.
type: list
elements: int
wep-key-type:
description:
- Controls the interpretation of WEP keys.
- - Allowed values are C(1), in which case the key is either a 10- or 26-character hexadecimal string, or a 5- or 13-character ASCII
- password; or C(2), in which case the passphrase is provided as a string and will be hashed using the de-facto MD5 method to derive the
+ - Allowed values are V(1), in which case the key is either a 10- or 26-character hexadecimal string, or a 5- or 13-character ASCII
+ password; or V(2), in which case the passphrase is provided as a string and will be hashed using the de-facto MD5 method to derive the
actual WEP key.
type: int
choices: [ 1, 2 ]
wep-key0:
description:
- Index 0 WEP key. This is the WEP key used in most networks.
- - See the I(wep-key-type) property for a description of how this key is interpreted.
+ - See the O(wifi_sec.wep-key-type) property for a description of how this key is interpreted.
type: str
wep-key1:
description:
- Index 1 WEP key. This WEP index is not used by most networks.
- - See the I(wep-key-type) property for a description of how this key is interpreted.
+ - See the O(wifi_sec.wep-key-type) property for a description of how this key is interpreted.
type: str
wep-key2:
description:
- Index 2 WEP key. This WEP index is not used by most networks.
- - See the I(wep-key-type) property for a description of how this key is interpreted.
+ - See the O(wifi_sec.wep-key-type) property for a description of how this key is interpreted.
type: str
wep-key3:
description:
- Index 3 WEP key. This WEP index is not used by most networks.
- - See the I(wep-key-type) property for a description of how this key is interpreted.
+ - See the O(wifi_sec.wep-key-type) property for a description of how this key is interpreted.
type: str
wep-tx-keyidx:
description:
- - When static WEP is used (that is, if I(key-mgmt=none)) and a non-default WEP key index is used by the AP, put that WEP key index here.
- - Valid values are C(0) (default key) through C(3).
- - Note that some consumer access points (like the Linksys WRT54G) number the keys C(1) - C(4).
+ - When static WEP is used (that is, if O(wifi_sec.key-mgmt=none)) and a non-default WEP key index
+ is used by the AP, put that WEP key index here.
+ - Valid values are V(0) (default key) through V(3).
+ - Note that some consumer access points (like the Linksys WRT54G) number the keys V(1) to V(4).
type: int
choices: [ 0, 1, 2, 3 ]
default: 0
@@ -618,7 +645,7 @@ options:
- Flags indicating which mode of WPS is to be used if any.
- There is little point in changing the default setting as NetworkManager will automatically determine whether it is feasible to start WPS
enrollment from the Access Point capabilities.
- - WPS can be disabled by setting this property to a value of C(1).
+ - WPS can be disabled by setting this property to a value of V(1).
type: int
default: 0
version_added: 3.0.0
@@ -634,34 +661,34 @@ options:
- 'An up-to-date list of supported attributes can be found here:
U(https://networkmanager.dev/docs/api/latest/settings-802-11-wireless.html).'
- 'For instance to create a hidden AP mode WiFi connection:
- C({hidden: true, mode: ap}).'
+ V({hidden: true, mode: ap}).'
type: dict
suboptions:
ap-isolation:
description:
- Configures AP isolation, which prevents communication between wireless devices connected to this AP.
- - This property can be set to a value different from C(-1) only when the interface is configured in AP mode.
- - If set to C(1), devices are not able to communicate with each other. This increases security because it protects devices against attacks
+ - This property can be set to a value different from V(-1) only when the interface is configured in AP mode.
+ - If set to V(1), devices are not able to communicate with each other. This increases security because it protects devices against attacks
from other clients in the network. At the same time, it prevents devices to access resources on the same wireless networks as file
shares, printers, etc.
- - If set to C(0), devices can talk to each other.
- - When set to C(-1), the global default is used; in case the global default is unspecified it is assumed to be C(0).
+ - If set to V(0), devices can talk to each other.
+ - When set to V(-1), the global default is used; in case the global default is unspecified it is assumed to be V(0).
type: int
choices: [ -1, 0, 1 ]
default: -1
assigned-mac-address:
description:
- The new field for the cloned MAC address.
- - It can be either a hardware address in ASCII representation, or one of the special values C(preserve), C(permanent), C(random) or
- C(stable).
- - This field replaces the deprecated I(cloned-mac-address) on D-Bus, which can only contain explicit hardware addresses.
- - Note that this property only exists in D-Bus API. libnm and nmcli continue to call this property I(cloned-mac-address).
+ - It can be either a hardware address in ASCII representation, or one of the special values V(preserve), V(permanent), V(random) or
+ V(stable).
+ - This field replaces the deprecated O(wifi.cloned-mac-address) on D-Bus, which can only contain explicit hardware addresses.
+ - Note that this property only exists in D-Bus API. libnm and nmcli continue to call this property C(cloned-mac-address).
type: str
band:
description:
- 802.11 frequency band of the network.
- - One of C(a) for 5GHz 802.11a or C(bg) for 2.4GHz 802.11.
- - This will lock associations to the Wi-Fi network to the specific band, so for example, if C(a) is specified, the device will not
+ - One of V(a) for 5GHz 802.11a or V(bg) for 2.4GHz 802.11.
+ - This will lock associations to the Wi-Fi network to the specific band, so for example, if V(a) is specified, the device will not
associate with the same network in the 2.4GHz band even if the network's settings are compatible.
- This setting depends on specific driver capability and may not work with all drivers.
type: str
@@ -676,38 +703,38 @@ options:
description:
- Wireless channel to use for the Wi-Fi connection.
- The device will only join (or create for Ad-Hoc networks) a Wi-Fi network on the specified channel.
- - Because channel numbers overlap between bands, this property also requires the I(band) property to be set.
+ - Because channel numbers overlap between bands, this property also requires the O(wifi.band) property to be set.
type: int
default: 0
cloned-mac-address:
description:
- - This D-Bus field is deprecated in favor of I(assigned-mac-address) which is more flexible and allows specifying special variants like
- C(random).
- - For libnm and nmcli, this field is called I(cloned-mac-address).
+ - This D-Bus field is deprecated in favor of O(wifi.assigned-mac-address) which is more flexible and allows specifying special variants like
+ V(random).
+ - For libnm and nmcli, this field is called C(cloned-mac-address).
type: str
generate-mac-address-mask:
description:
- - With I(cloned-mac-address) setting C(random) or C(stable), by default all bits of the MAC address are scrambled and a
+ - With O(wifi.cloned-mac-address) setting V(random) or V(stable), by default all bits of the MAC address are scrambled and a
locally-administered, unicast MAC address is created. This property allows to specify that certain bits are fixed.
- Note that the least significant bit of the first MAC address will always be unset to create a unicast MAC address.
- - If the property is C(null), it is eligible to be overwritten by a default connection setting.
- - If the value is still c(null) or an empty string, the default is to create a locally-administered, unicast MAC address.
+ - If the property is V(null), it is eligible to be overwritten by a default connection setting.
+ - If the value is still V(null) or an empty string, the default is to create a locally-administered, unicast MAC address.
- If the value contains one MAC address, this address is used as mask. The set bits of the mask are to be filled with the current MAC
address of the device, while the unset bits are subject to randomization.
- - Setting C(FE:FF:FF:00:00:00) means to preserve the OUI of the current MAC address and only randomize the lower 3 bytes using the
- C(random) or C(stable) algorithm.
+ - Setting V(FE:FF:FF:00:00:00) means to preserve the OUI of the current MAC address and only randomize the lower 3 bytes using the
+ V(random) or V(stable) algorithm.
- If the value contains one additional MAC address after the mask, this address is used instead of the current MAC address to fill the bits
that shall not be randomized.
- - For example, a value of C(FE:FF:FF:00:00:00 68:F7:28:00:00:00) will set the OUI of the MAC address to 68:F7:28, while the lower bits are
+ - For example, a value of V(FE:FF:FF:00:00:00 68:F7:28:00:00:00) will set the OUI of the MAC address to 68:F7:28, while the lower bits are
randomized.
- - A value of C(02:00:00:00:00:00 00:00:00:00:00:00) will create a fully scrambled globally-administered, burned-in MAC address.
+ - A value of V(02:00:00:00:00:00 00:00:00:00:00:00) will create a fully scrambled globally-administered, burned-in MAC address.
- If the value contains more than one additional MAC addresses, one of them is chosen randomly. For example,
- C(02:00:00:00:00:00 00:00:00:00:00:00 02:00:00:00:00:00) will create a fully scrambled MAC address, randomly locally or globally
+ V(02:00:00:00:00:00 00:00:00:00:00:00 02:00:00:00:00:00) will create a fully scrambled MAC address, randomly locally or globally
administered.
type: str
hidden:
description:
- - If C(true), indicates that the network is a non-broadcasting network that hides its SSID. This works both in infrastructure and AP mode.
+ - If V(true), indicates that the network is a non-broadcasting network that hides its SSID. This works both in infrastructure and AP mode.
- In infrastructure mode, various workarounds are used for a more reliable discovery of hidden networks, such as probe-scanning the SSID.
However, these workarounds expose inherent insecurities with hidden SSID networks, and thus hidden SSID networks should be used with
caution.
@@ -719,14 +746,14 @@ options:
mac-address-blacklist:
description:
- A list of permanent MAC addresses of Wi-Fi devices to which this connection should never apply.
- - Each MAC address should be given in the standard hex-digits-and-colons notation (for example, C(00:11:22:33:44:55)).
+ - Each MAC address should be given in the standard hex-digits-and-colons notation (for example, V(00:11:22:33:44:55)).
type: list
elements: str
mac-address-randomization:
description:
- - One of C(0) (never randomize unless the user has set a global default to randomize and the supplicant supports randomization), C(1)
- (never randomize the MAC address), or C(2) (always randomize the MAC address).
- - This property is deprecated for I(cloned-mac-address).
+ - One of V(0) (never randomize unless the user has set a global default to randomize and the supplicant supports randomization), V(1)
+ (never randomize the MAC address), or V(2) (always randomize the MAC address).
+ - This property is deprecated for O(wifi.cloned-mac-address).
type: int
default: 0
choices: [ 0, 1, 2 ]
@@ -736,7 +763,7 @@ options:
- This property does not change the MAC address of the device (for example for MAC spoofing).
type: str
mode:
- description: Wi-Fi network mode. If blank, C(infrastructure) is assumed.
+ description: Wi-Fi network mode. If blank, V(infrastructure) is assumed.
type: str
choices: [ infrastructure, mesh, adhoc, ap ]
default: infrastructure
@@ -746,7 +773,7 @@ options:
default: 0
powersave:
description:
- - One of C(2) (disable Wi-Fi power saving), C(3) (enable Wi-Fi power saving), C(1) (don't touch currently configure setting) or C(0) (use
+ - One of V(2) (disable Wi-Fi power saving), V(3) (enable Wi-Fi power saving), V(1) (don't touch currently configure setting) or V(0) (use
the globally configured value).
- All other values are reserved.
type: int
@@ -755,7 +782,7 @@ options:
rate:
description:
- If non-zero, directs the device to only use the specified bitrate for communication with the access point.
- - Units are in Kb/s, so for example C(5500) = 5.5 Mbit/s.
+ - Units are in Kb/s, so for example V(5500) = 5.5 Mbit/s.
- This property is highly driver dependent and not all devices support setting a static bitrate.
type: int
default: 0
@@ -769,11 +796,11 @@ options:
wake-on-wlan:
description:
- The NMSettingWirelessWakeOnWLan options to enable. Not all devices support all options.
- - May be any combination of C(NM_SETTING_WIRELESS_WAKE_ON_WLAN_ANY) (C(0x2)), C(NM_SETTING_WIRELESS_WAKE_ON_WLAN_DISCONNECT) (C(0x4)),
- C(NM_SETTING_WIRELESS_WAKE_ON_WLAN_MAGIC) (C(0x8)), C(NM_SETTING_WIRELESS_WAKE_ON_WLAN_GTK_REKEY_FAILURE) (C(0x10)),
- C(NM_SETTING_WIRELESS_WAKE_ON_WLAN_EAP_IDENTITY_REQUEST) (C(0x20)), C(NM_SETTING_WIRELESS_WAKE_ON_WLAN_4WAY_HANDSHAKE) (C(0x40)),
- C(NM_SETTING_WIRELESS_WAKE_ON_WLAN_RFKILL_RELEASE) (C(0x80)), C(NM_SETTING_WIRELESS_WAKE_ON_WLAN_TCP) (C(0x100)) or the special values
- C(0x1) (to use global settings) and C(0x8000) (to disable management of Wake-on-LAN in NetworkManager).
+ - May be any combination of C(NM_SETTING_WIRELESS_WAKE_ON_WLAN_ANY) (V(0x2)), C(NM_SETTING_WIRELESS_WAKE_ON_WLAN_DISCONNECT) (V(0x4)),
+ C(NM_SETTING_WIRELESS_WAKE_ON_WLAN_MAGIC) (V(0x8)), C(NM_SETTING_WIRELESS_WAKE_ON_WLAN_GTK_REKEY_FAILURE) (V(0x10)),
+ C(NM_SETTING_WIRELESS_WAKE_ON_WLAN_EAP_IDENTITY_REQUEST) (V(0x20)), C(NM_SETTING_WIRELESS_WAKE_ON_WLAN_4WAY_HANDSHAKE) (V(0x40)),
+ C(NM_SETTING_WIRELESS_WAKE_ON_WLAN_RFKILL_RELEASE) (V(0x80)), C(NM_SETTING_WIRELESS_WAKE_ON_WLAN_TCP) (V(0x100)) or the special values
+ V(0x1) (to use global settings) and V(0x8000) (to disable management of Wake-on-LAN in NetworkManager).
- Note the option values' sum must be specified in order to combine multiple options.
type: int
default: 1
@@ -781,7 +808,7 @@ options:
ignore_unsupported_suboptions:
description:
- Ignore suboptions which are invalid or unsupported by the version of NetworkManager/nmcli installed on the host.
- - Only I(wifi) and I(wifi_sec) options are currently affected.
+ - Only O(wifi) and O(wifi_sec) options are currently affected.
type: bool
default: false
version_added: 3.6.0
@@ -792,7 +819,7 @@ options:
- 'An up-to-date list of supported attributes can be found here:
U(https://networkmanager.dev/docs/api/latest/settings-gsm.html).'
- 'For instance to use apn, pin, username and password:
- C({apn: provider.apn, pin: 1234, username: apn.username, password: apn.password}).'
+ V({apn: provider.apn, pin: 1234, username: apn.username, password: apn.password}).'
type: dict
version_added: 3.7.0
suboptions:
@@ -804,18 +831,18 @@ options:
- The APN may only be composed of the characters a-z, 0-9, ., and - per GSM 03.60 Section 14.9.
type: str
auto-config:
- description: When C(true), the settings such as I(gsm.apn), I(gsm.username), or I(gsm.password) will default to values that match the network
+ description: When V(true), the settings such as O(gsm.apn), O(gsm.username), or O(gsm.password) will default to values that match the network
the modem will register to in the Mobile Broadband Provider database.
type: bool
default: false
device-id:
description:
- - The device unique identifier (as given by the C(WWAN) management service) which this connection applies to.
+ - The device unique identifier (as given by the V(WWAN) management service) which this connection applies to.
- If given, the connection will only apply to the specified device.
type: str
home-only:
description:
- - When C(true), only connections to the home network will be allowed.
+ - When V(true), only connections to the home network will be allowed.
- Connections to roaming networks will not be made.
type: bool
default: false
@@ -840,13 +867,13 @@ options:
type: str
password-flags:
description:
- - NMSettingSecretFlags indicating how to handle the I(password) property.
+ - NMSettingSecretFlags indicating how to handle the O(gsm.password) property.
- 'Following choices are allowed:
- C(0) B(NONE): The system is responsible for providing and storing this secret (default),
- C(1) B(AGENT_OWNED): A user secret agent is responsible for providing and storing this secret; when it is required agents will be
+ V(0) B(NONE): The system is responsible for providing and storing this secret (default),
+ V(1) B(AGENT_OWNED): A user secret agent is responsible for providing and storing this secret; when it is required agents will be
asked to retrieve it
- C(2) B(NOT_SAVED): This secret should not be saved, but should be requested from the user each time it is needed
- C(4) B(NOT_REQUIRED): In situations where it cannot be automatically determined that the secret is required
+ V(2) B(NOT_SAVED): This secret should not be saved, but should be requested from the user each time it is needed
+ V(4) B(NOT_REQUIRED): In situations where it cannot be automatically determined that the secret is required
(some VPNs and PPP providers do not require all secrets) this flag indicates that the specific secret is not required.'
type: int
choices: [ 0, 1, 2 , 4 ]
@@ -858,21 +885,21 @@ options:
type: str
pin-flags:
description:
- - NMSettingSecretFlags indicating how to handle the I(gsm.pin) property.
- - See I(gsm.password-flags) for NMSettingSecretFlags choices.
+ - NMSettingSecretFlags indicating how to handle the O(gsm.pin) property.
+ - See O(gsm.password-flags) for NMSettingSecretFlags choices.
type: int
choices: [ 0, 1, 2 , 4 ]
default: 0
sim-id:
description:
- The SIM card unique identifier (as given by the C(WWAN) management service) which this connection applies to.
- - 'If given, the connection will apply to any device also allowed by I(gsm.device-id) which contains a SIM card matching
+ - 'If given, the connection will apply to any device also allowed by O(gsm.device-id) which contains a SIM card matching
the given identifier.'
type: str
sim-operator-id:
description:
- - A MCC/MNC string like C(310260) or C(21601I) identifying the specific mobile network operator which this connection applies to.
- - 'If given, the connection will apply to any device also allowed by I(gsm.device-id) and I(gsm.sim-id) which contains a SIM card
+ - A MCC/MNC string like V(310260) or V(21601I) identifying the specific mobile network operator which this connection applies to.
+ - 'If given, the connection will apply to any device also allowed by O(gsm.device-id) and O(gsm.sim-id) which contains a SIM card
provisioned by the given operator.'
type: str
username:
@@ -892,8 +919,8 @@ options:
mode:
description:
- The macvlan mode, which specifies the communication mechanism between multiple macvlans on the same lower device.
- - 'Following choices are allowed: C(1) B(vepa), C(2) B(bridge), C(3) B(private), C(4) B(passthru)
- and C(5) B(source)'
+ - 'Following choices are allowed: V(1) B(vepa), V(2) B(bridge), V(3) B(private), V(4) B(passthru)
+ and V(5) B(source)'
type: int
choices: [ 1, 2, 3, 4, 5 ]
required: true
@@ -919,7 +946,7 @@ options:
- 'An up-to-date list of supported attributes can be found here:
U(https://networkmanager.dev/docs/api/latest/settings-wireguard.html).'
- 'For instance to configure a listen port:
- C({listen-port: 12345}).'
+ V({listen-port: 12345}).'
type: dict
version_added: 4.3.0
suboptions:
@@ -927,19 +954,19 @@ options:
description:
- The 32-bit fwmark for outgoing packets.
- The use of fwmark is optional and is by default off. Setting it to 0 disables it.
- - Note that I(wireguard.ip4-auto-default-route) or I(wireguard.ip6-auto-default-route) enabled, implies to automatically choose a fwmark.
+ - Note that O(wireguard.ip4-auto-default-route) or O(wireguard.ip6-auto-default-route) enabled, implies to automatically choose a fwmark.
type: int
ip4-auto-default-route:
description:
- Whether to enable special handling of the IPv4 default route.
- - If enabled, the IPv4 default route from I(wireguard.peer-routes) will be placed to a dedicated routing-table and two policy
+ - If enabled, the IPv4 default route from O(wireguard.peer-routes) will be placed to a dedicated routing-table and two policy
routing rules will be added.
- The fwmark number is also used as routing-table for the default-route, and if fwmark is zero, an unused fwmark/table is chosen
automatically. This corresponds to what wg-quick does with Table=auto and what WireGuard calls "Improved Rule-based Routing"
type: bool
ip6-auto-default-route:
description:
- - Like I(wireguard.ip4-auto-default-route), but for the IPv6 default route.
+ - Like O(wireguard.ip4-auto-default-route), but for the IPv6 default route.
type: bool
listen-port:
description: The WireGuard connection listen-port. If not specified, the port will be chosen randomly when the
@@ -954,18 +981,18 @@ options:
peer-routes:
description:
- Whether to automatically add routes for the AllowedIPs ranges of the peers.
- - If C(true) (the default), NetworkManager will automatically add routes in the routing tables according to C(ipv4.route-table) and
+ - If V(true) (the default), NetworkManager will automatically add routes in the routing tables according to C(ipv4.route-table) and
C(ipv6.route-table). Usually you want this automatism enabled.
- - If C(false), no such routes are added automatically. In this case, the user may want to configure static routes in C(ipv4.routes)
+ - If V(false), no such routes are added automatically. In this case, the user may want to configure static routes in C(ipv4.routes)
and C(ipv6.routes), respectively.
- - Note that if the peer's AllowedIPs is C(0.0.0.0/0) or C(::/0) and the profile's C(ipv4.never-default) or C(ipv6.never-default)
+ - Note that if the peer's AllowedIPs is V(0.0.0.0/0) or V(::/0) and the profile's C(ipv4.never-default) or C(ipv6.never-default)
setting is enabled, the peer route for this peer won't be added automatically.
type: bool
private-key:
description: The 256 bit private-key in base64 encoding.
type: str
private-key-flags:
- description: C(NMSettingSecretFlags) indicating how to handle the I(wireguard.private-key) property.
+ description: C(NMSettingSecretFlags) indicating how to handle the O(wireguard.private-key) property.
type: int
choices: [ 0, 1, 2 ]
vpn:
@@ -985,19 +1012,19 @@ options:
type: str
required: true
gateway:
- description: The gateway to connection. It can be an IP address (for example C(192.0.2.1))
- or a FQDN address (for example C(vpn.example.com)).
+ description: The gateway to connection. It can be an IP address (for example V(192.0.2.1))
+ or a FQDN address (for example V(vpn.example.com)).
type: str
required: true
password-flags:
description:
- - NMSettingSecretFlags indicating how to handle the I(password) property.
+ - NMSettingSecretFlags indicating how to handle the C(vpn.password) property.
- 'Following choices are allowed:
- C(0) B(NONE): The system is responsible for providing and storing this secret (default);
- C(1) B(AGENT_OWNED): A user secret agent is responsible for providing and storing this secret; when it is required agents will be
+ V(0) B(NONE): The system is responsible for providing and storing this secret (default);
+ V(1) B(AGENT_OWNED): A user secret agent is responsible for providing and storing this secret; when it is required agents will be
asked to retrieve it;
- C(2) B(NOT_SAVED): This secret should not be saved, but should be requested from the user each time it is needed;
- C(4) B(NOT_REQUIRED): In situations where it cannot be automatically determined that the secret is required
+ V(2) B(NOT_SAVED): This secret should not be saved, but should be requested from the user each time it is needed;
+ V(4) B(NOT_REQUIRED): In situations where it cannot be automatically determined that the secret is required
(some VPNs and PPP providers do not require all secrets) this flag indicates that the specific secret is not required.'
type: int
choices: [ 0, 1, 2 , 4 ]
@@ -1009,14 +1036,14 @@ options:
ipsec-enabled:
description:
- Enable or disable IPSec tunnel to L2TP host.
- - This option is need when C(service-type) is C(org.freedesktop.NetworkManager.l2tp).
+ - This option is need when O(vpn.service-type) is V(org.freedesktop.NetworkManager.l2tp).
type: bool
ipsec-psk:
description:
- The pre-shared key in base64 encoding.
- >
- You can encode using this Ansible jinja2 expression: C("0s{{ '[YOUR PRE-SHARED KEY]' | ansible.builtin.b64encode }}").
- - This is only used when I(ipsec-enabled=true).
+ You can encode using this Ansible jinja2 expression: V("0s{{ '[YOUR PRE-SHARED KEY]' | ansible.builtin.b64encode }}").
+ - This is only used when O(vpn.ipsec-enabled=true).
type: str
'''
@@ -1429,6 +1456,55 @@ EXAMPLES = r'''
autoconnect: false
state: present
+## Creating bond attached to bridge example
+- name: Create bond attached to bridge
+ community.general.nmcli:
+ type: bond
+ conn_name: bond0
+ slave_type: bridge
+ master: br0
+ state: present
+
+- name: Create master bridge
+ community.general.nmcli:
+ type: bridge
+ conn_name: br0
+ method4: disabled
+ method6: disabled
+ state: present
+
+## Creating vlan connection attached to bridge
+- name: Create master bridge
+ community.general.nmcli:
+ type: bridge
+ conn_name: br0
+ state: present
+
+- name: Create VLAN 5
+ community.general.nmcli:
+ type: vlan
+ conn_name: eth0.5
+ slave_type: bridge
+ master: br0
+ vlandev: eth0
+ vlanid: 5
+ state: present
+
+## Defining ip rules while setting a static IP
+## table 'production' is set with id 200 in this example.
+- name: Set Static ips for interface with ip rules and routes
+ community.general.nmcli:
+ type: ethernet
+ conn_name: 'eth0'
+ ip4: '192.168.1.50'
+ gw4: '192.168.1.1'
+ state: present
+ routes4_extended:
+ - ip: "0.0.0.0/0"
+ next_hop: "192.168.1.1"
+ table: "production"
+ routing_rules4:
+ - "priority 0 from 192.168.1.50 table 200"
'''
RETURN = r"""#
@@ -1475,6 +1551,7 @@ class Nmcli(object):
self.ignore_unsupported_suboptions = module.params['ignore_unsupported_suboptions']
self.autoconnect = module.params['autoconnect']
self.conn_name = module.params['conn_name']
+ self.slave_type = module.params['slave_type']
self.master = module.params['master']
self.ifname = module.params['ifname']
self.type = module.params['type']
@@ -1488,6 +1565,7 @@ class Nmcli(object):
self.never_default4 = module.params['never_default4']
self.dns4 = module.params['dns4']
self.dns4_search = module.params['dns4_search']
+ self.dns4_options = module.params['dns4_options']
self.dns4_ignore_auto = module.params['dns4_ignore_auto']
self.method4 = module.params['method4']
self.may_fail4 = module.params['may_fail4']
@@ -1499,6 +1577,7 @@ class Nmcli(object):
self.route_metric6 = module.params['route_metric6']
self.dns6 = module.params['dns6']
self.dns6_search = module.params['dns6_search']
+ self.dns6_options = module.params['dns6_options']
self.dns6_ignore_auto = module.params['dns6_ignore_auto']
self.method6 = module.params['method6']
self.ip_privacy6 = module.params['ip_privacy6']
@@ -1519,8 +1598,7 @@ class Nmcli(object):
self.hellotime = module.params['hellotime']
self.maxage = module.params['maxage']
self.ageingtime = module.params['ageingtime']
- # hairpin should be back to normal in 7.0.0
- self._hairpin = module.params['hairpin']
+ self.hairpin = module.params['hairpin']
self.path_cost = module.params['path_cost']
self.mac = module.params['mac']
self.runner = module.params['runner']
@@ -1571,17 +1649,13 @@ class Nmcli(object):
self.edit_commands = []
- @property
- def hairpin(self):
- if self._hairpin is None:
- self.module.deprecate(
- "Parameter 'hairpin' default value will change from true to false in community.general 7.0.0. "
- "Set the value explicitly to suppress this warning.",
- version='7.0.0', collection_name='community.general',
- )
- # Should be False in 7.0.0 but then that should be in argument_specs
- self._hairpin = True
- return self._hairpin
+ self.extra_options_validation()
+
+ def extra_options_validation(self):
+ """ Additional validation of options set passed to module that cannot be implemented in module's argspecs. """
+ if self.type not in ("bridge-slave", "team-slave", "bond-slave"):
+ if self.master is None and self.slave_type is not None:
+ self.module.fail_json(msg="'master' option is required when 'slave_type' is specified.")
def execute_command(self, cmd, use_unsafe_shell=False, data=None):
if isinstance(cmd, list):
@@ -1610,6 +1684,7 @@ class Nmcli(object):
'ipv4.dhcp-client-id': self.dhcp_client_id,
'ipv4.dns': self.dns4,
'ipv4.dns-search': self.dns4_search,
+ 'ipv4.dns-options': self.dns4_options,
'ipv4.ignore-auto-dns': self.dns4_ignore_auto,
'ipv4.gateway': self.gw4,
'ipv4.ignore-auto-routes': self.gw4_ignore_auto,
@@ -1622,6 +1697,7 @@ class Nmcli(object):
'ipv6.addresses': self.enforce_ipv6_cidr_notation(self.ip6),
'ipv6.dns': self.dns6,
'ipv6.dns-search': self.dns6_search,
+ 'ipv6.dns-options': self.dns6_options,
'ipv6.ignore-auto-dns': self.dns6_ignore_auto,
'ipv6.gateway': self.gw6,
'ipv6.ignore-auto-routes': self.gw6_ignore_auto,
@@ -1647,6 +1723,7 @@ class Nmcli(object):
if self.slave_conn_type:
options.update({
'connection.master': self.master,
+ 'connection.slave-type': self.slave_type,
})
# Options specific to a connection type.
@@ -1662,9 +1739,17 @@ class Nmcli(object):
'xmit_hash_policy': self.xmit_hash_policy,
})
elif self.type == 'bond-slave':
- options.update({
- 'connection.slave-type': 'bond',
- })
+ if self.slave_type and self.slave_type != 'bond':
+ self.module.fail_json(msg="Connection type '%s' cannot be combined with '%s' slave-type. "
+ "Allowed slave-type for '%s' is 'bond'."
+ % (self.type, self.slave_type, self.type)
+ )
+ if not self.slave_type:
+ self.module.warn("Connection 'slave-type' property automatically set to 'bond' "
+ "because of using 'bond-slave' connection type.")
+ options.update({
+ 'connection.slave-type': 'bond',
+ })
elif self.type == 'bridge':
options.update({
'bridge.ageing-time': self.ageingtime,
@@ -1674,7 +1759,7 @@ class Nmcli(object):
'bridge.priority': self.priority,
'bridge.stp': self.stp,
})
- # priority make sense when stp enabed, otherwise nmcli keeps bridge-priority to 32768 regrdless of input.
+ # priority make sense when stp enabled, otherwise nmcli keeps bridge-priority to 32768 regrdless of input.
# force ignoring to save idempotency
if self.stp:
options.update({'bridge.priority': self.priority})
@@ -1688,16 +1773,36 @@ class Nmcli(object):
'team.runner-fast-rate': self.runner_fast_rate,
})
elif self.type == 'bridge-slave':
+ if self.slave_type and self.slave_type != 'bridge':
+ self.module.fail_json(msg="Connection type '%s' cannot be combined with '%s' slave-type. "
+ "Allowed slave-type for '%s' is 'bridge'."
+ % (self.type, self.slave_type, self.type)
+ )
+ if not self.slave_type:
+ self.module.warn("Connection 'slave-type' property automatically set to 'bridge' "
+ "because of using 'bridge-slave' connection type.")
+ options.update({'connection.slave-type': 'bridge'})
+ self.module.warn(
+ "Connection type as 'bridge-slave' implies 'ethernet' connection with 'bridge' slave-type. "
+ "Consider using slave_type='bridge' with necessary type."
+ )
options.update({
- 'connection.slave-type': 'bridge',
'bridge-port.path-cost': self.path_cost,
'bridge-port.hairpin-mode': self.hairpin,
'bridge-port.priority': self.slavepriority,
})
elif self.type == 'team-slave':
- options.update({
- 'connection.slave-type': 'team',
- })
+ if self.slave_type and self.slave_type != 'team':
+ self.module.fail_json(msg="Connection type '%s' cannot be combined with '%s' slave-type. "
+ "Allowed slave-type for '%s' is 'team'."
+ % (self.type, self.slave_type, self.type)
+ )
+ if not self.slave_type:
+ self.module.warn("Connection 'slave-type' property automatically set to 'team' "
+ "because of using 'team-slave' connection type.")
+ options.update({
+ 'connection.slave-type': 'team',
+ })
elif self.tunnel_conn_type:
options.update({
'ip-tunnel.local': self.ip_tunnel_local,
@@ -1727,7 +1832,7 @@ class Nmcli(object):
elif self.type == 'wifi':
options.update({
'802-11-wireless.ssid': self.ssid,
- 'connection.slave-type': 'bond' if self.master else None,
+ 'connection.slave-type': ('bond' if self.slave_type is None else self.slave_type) if self.master else None,
})
if self.wifi:
for name, value in self.wifi.items():
@@ -1833,6 +1938,7 @@ class Nmcli(object):
'macvlan',
'wireguard',
'vpn',
+ 'loopback',
)
@property
@@ -1845,15 +1951,21 @@ class Nmcli(object):
@property
def mtu_conn_type(self):
return self.type in (
+ 'bond',
+ 'bond-slave',
'dummy',
'ethernet',
+ 'infiniband',
'team-slave',
'vlan',
)
@property
def mtu_setting(self):
- return '802-3-ethernet.mtu'
+ if self.type == 'infiniband':
+ return 'infiniband.mtu'
+ else:
+ return '802-3-ethernet.mtu'
@staticmethod
def mtu_to_string(mtu):
@@ -1882,10 +1994,17 @@ class Nmcli(object):
@property
def slave_conn_type(self):
return self.type in (
+ 'ethernet',
+ 'bridge',
+ 'bond',
+ 'vlan',
+ 'team',
+ 'wifi',
'bond-slave',
'bridge-slave',
'team-slave',
'wifi',
+ 'infiniband',
)
@property
@@ -1963,10 +2082,12 @@ class Nmcli(object):
'ipv6.addresses',
'ipv4.dns',
'ipv4.dns-search',
+ 'ipv4.dns-options',
'ipv4.routes',
'ipv4.routing-rules',
'ipv6.dns',
'ipv6.dns-search',
+ 'ipv6.dns-options',
'ipv6.routes',
'802-11-wireless-security.group',
'802-11-wireless-security.leap-password-flags',
@@ -2104,7 +2225,10 @@ class Nmcli(object):
if key and len(pair) > 1:
raw_value = pair[1].lstrip()
if raw_value == '--':
- conn_info[key] = None
+ if key_type == list:
+ conn_info[key] = []
+ else:
+ conn_info[key] = None
elif key == 'bond.options':
# Aliases such as 'miimon', 'downdelay' are equivalent to the +bond.options 'option=value' syntax.
opts = raw_value.split(',')
@@ -2191,7 +2315,7 @@ class Nmcli(object):
# We can't just do `if not value` because then if there's a value
# of 0 specified as an integer it'll be interpreted as empty when
# it actually isn't.
- if value != 0 and not value:
+ if value not in (0, []) and not value:
continue
if key in conn_info:
@@ -2276,6 +2400,7 @@ def main():
state=dict(type='str', required=True, choices=['absent', 'present']),
conn_name=dict(type='str', required=True),
master=dict(type='str'),
+ slave_type=dict(type='str', choices=['bond', 'bridge', 'team']),
ifname=dict(type='str'),
type=dict(type='str',
choices=[
@@ -2299,6 +2424,7 @@ def main():
'macvlan',
'wireguard',
'vpn',
+ 'loopback',
]),
ip4=dict(type='list', elements='str'),
gw4=dict(type='str'),
@@ -2321,6 +2447,7 @@ def main():
never_default4=dict(type='bool', default=False),
dns4=dict(type='list', elements='str'),
dns4_search=dict(type='list', elements='str'),
+ dns4_options=dict(type='list', elements='str'),
dns4_ignore_auto=dict(type='bool', default=False),
method4=dict(type='str', choices=['auto', 'link-local', 'manual', 'shared', 'disabled']),
may_fail4=dict(type='bool', default=True),
@@ -2330,6 +2457,7 @@ def main():
gw6_ignore_auto=dict(type='bool', default=False),
dns6=dict(type='list', elements='str'),
dns6_search=dict(type='list', elements='str'),
+ dns6_options=dict(type='list', elements='str'),
dns6_ignore_auto=dict(type='bool', default=False),
routes6=dict(type='list', elements='str'),
routes6_extended=dict(type='list',
@@ -2369,7 +2497,7 @@ def main():
hellotime=dict(type='int', default=2),
maxage=dict(type='int', default=20),
ageingtime=dict(type='int', default=300),
- hairpin=dict(type='bool'),
+ hairpin=dict(type='bool', default=False),
path_cost=dict(type='int', default=100),
# team specific vars
runner=dict(type='str', default='roundrobin',
@@ -2432,7 +2560,7 @@ def main():
if nmcli.runner_fast_rate is not None and nmcli.runner != "lacp":
nmcli.module.fail_json(msg="runner-fast-rate is only allowed for runner lacp")
# team-slave checks
- if nmcli.type == 'team-slave':
+ if nmcli.type == 'team-slave' or nmcli.slave_type == 'team':
if nmcli.master is None:
nmcli.module.fail_json(msg="Please specify a name for the master when type is %s" % nmcli.type)
if nmcli.ifname is None:
diff --git a/ansible_collections/community/general/plugins/modules/nomad_job.py b/ansible_collections/community/general/plugins/modules/nomad_job.py
index ca76536b4..87e8ec04c 100644
--- a/ansible_collections/community/general/plugins/modules/nomad_job.py
+++ b/ansible_collections/community/general/plugins/modules/nomad_job.py
@@ -33,7 +33,7 @@ options:
description:
- Name of job for delete, stop and start job without source.
- Name of job for delete, stop and start job without source.
- - Either this or I(content) must be specified.
+ - Either this or O(content) must be specified.
type: str
state:
description:
@@ -49,7 +49,7 @@ options:
content:
description:
- Content of Nomad job.
- - Either this or I(name) must be specified.
+ - Either this or O(name) must be specified.
type: str
content_format:
description:
@@ -71,6 +71,14 @@ EXAMPLES = '''
content: "{{ lookup('ansible.builtin.file', 'job.hcl') }}"
timeout: 120
+- name: Connect with port to create job
+ community.general.nomad_job:
+ host: localhost
+ port: 4645
+ state: present
+ content: "{{ lookup('ansible.builtin.file', 'job.hcl') }}"
+ timeout: 120
+
- name: Stop job
community.general.nomad_job:
host: localhost
@@ -103,6 +111,7 @@ def run():
module = AnsibleModule(
argument_spec=dict(
host=dict(required=True, type='str'),
+ port=dict(type='int', default=4646),
state=dict(required=True, choices=['present', 'absent']),
use_ssl=dict(type='bool', default=True),
timeout=dict(type='int', default=5),
@@ -132,6 +141,7 @@ def run():
nomad_client = nomad.Nomad(
host=module.params.get('host'),
+ port=module.params.get('port'),
secure=module.params.get('use_ssl'),
timeout=module.params.get('timeout'),
verify=module.params.get('validate_certs'),
diff --git a/ansible_collections/community/general/plugins/modules/nomad_job_info.py b/ansible_collections/community/general/plugins/modules/nomad_job_info.py
index 5ee25a57a..bd7cf8ca9 100644
--- a/ansible_collections/community/general/plugins/modules/nomad_job_info.py
+++ b/ansible_collections/community/general/plugins/modules/nomad_job_info.py
@@ -29,8 +29,6 @@ options:
- Name of job for Get info.
- If not specified, lists all jobs.
type: str
-notes:
- - C(check_mode) is supported.
seealso:
- name: Nomad jobs documentation
description: Complete documentation for Nomad API jobs.
@@ -283,6 +281,7 @@ def run():
module = AnsibleModule(
argument_spec=dict(
host=dict(required=True, type='str'),
+ port=dict(type='int', default=4646),
use_ssl=dict(type='bool', default=True),
timeout=dict(type='int', default=5),
validate_certs=dict(type='bool', default=True),
@@ -302,6 +301,7 @@ def run():
nomad_client = nomad.Nomad(
host=module.params.get('host'),
+ port=module.params.get('port'),
secure=module.params.get('use_ssl'),
timeout=module.params.get('timeout'),
verify=module.params.get('validate_certs'),
diff --git a/ansible_collections/community/general/plugins/modules/nomad_token.py b/ansible_collections/community/general/plugins/modules/nomad_token.py
new file mode 100644
index 000000000..51a2f9716
--- /dev/null
+++ b/ansible_collections/community/general/plugins/modules/nomad_token.py
@@ -0,0 +1,301 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2023, Pedro Nascimento <apecnascimento@gmail.com>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+DOCUMENTATION = '''
+---
+module: nomad_token
+author: Pedro Nascimento (@apecnascimento)
+version_added: "8.1.0"
+short_description: Manage Nomad ACL tokens
+description:
+ - This module allows to create Bootstrap tokens, create ACL tokens, update ACL tokens, and delete ACL tokens.
+requirements:
+ - python-nomad
+extends_documentation_fragment:
+ - community.general.nomad
+ - community.general.attributes
+attributes:
+ check_mode:
+ support: none
+ diff_mode:
+ support: none
+options:
+ name:
+ description:
+ - Name of ACL token to create.
+ type: str
+ token_type:
+ description:
+ - The type of the token can be V(client), V(management), or V(bootstrap).
+ choices: ["client", "management", "bootstrap"]
+ type: str
+ default: "client"
+ policies:
+ description:
+ - A list of the policies assigned to the token.
+ type: list
+ elements: str
+ default: []
+ global_replicated:
+ description:
+ - Indicates whether or not the token was created with the C(--global).
+ type: bool
+ default: false
+ state:
+ description:
+ - Create or remove ACL token.
+ choices: ["present", "absent"]
+ required: true
+ type: str
+
+seealso:
+ - name: Nomad ACL documentation
+ description: Complete documentation for Nomad API ACL.
+ link: https://developer.hashicorp.com/nomad/api-docs/acl/tokens
+'''
+
+EXAMPLES = '''
+- name: Create boostrap token
+ community.general.nomad_token:
+ host: localhost
+ token_type: bootstrap
+ state: present
+
+- name: Create ACL token
+ community.general.nomad_token:
+ host: localhost
+ name: "Dev token"
+ token_type: client
+ policies:
+ - readonly
+ global_replicated: false
+ state: absent
+
+- name: Update ACL token Dev token
+ community.general.nomad_token:
+ host: localhost
+ name: "Dev token"
+ token_type: client
+ policies:
+ - readonly
+ - devpolicy
+ global_replicated: false
+ state: absent
+
+- name: Delete ACL token
+ community.general.nomad_token:
+ host: localhost
+ name: "Dev token"
+ state: absent
+'''
+
+RETURN = '''
+result:
+ description: Result returned by nomad.
+ returned: always
+ type: dict
+ sample: {
+ "accessor_id": "0d01c55f-8d63-f832-04ff-1866d4eb594e",
+ "create_index": 14,
+ "create_time": "2023-11-12T18:48:34.248857001Z",
+ "expiration_time": null,
+ "expiration_ttl": "",
+ "global": true,
+ "hash": "eSn8H8RVqh8As8WQNnC2vlBRqXy6DECogc5umzX0P30=",
+ "modify_index": 836,
+ "name": "devs",
+ "policies": [
+ "readonly"
+ ],
+ "roles": null,
+ "secret_id": "12e878ab-e1f6-e103-b4c4-3b5173bb4cea",
+ "type": "client"
+ }
+'''
+
+from ansible.module_utils.basic import AnsibleModule, missing_required_lib
+from ansible.module_utils.common.text.converters import to_native
+
+import_nomad = None
+
+try:
+ import nomad
+
+ import_nomad = True
+except ImportError:
+ import_nomad = False
+
+
+def get_token(name, nomad_client):
+ tokens = nomad_client.acl.get_tokens()
+ token = next((token for token in tokens
+ if token.get('Name') == name), None)
+ return token
+
+
+def transform_response(nomad_response):
+ transformed_response = {
+ "accessor_id": nomad_response['AccessorID'],
+ "create_index": nomad_response['CreateIndex'],
+ "create_time": nomad_response['CreateTime'],
+ "expiration_ttl": nomad_response['ExpirationTTL'],
+ "expiration_time": nomad_response['ExpirationTime'],
+ "global": nomad_response['Global'],
+ "hash": nomad_response['Hash'],
+ "modify_index": nomad_response['ModifyIndex'],
+ "name": nomad_response['Name'],
+ "policies": nomad_response['Policies'],
+ "roles": nomad_response['Roles'],
+ "secret_id": nomad_response['SecretID'],
+ "type": nomad_response['Type']
+ }
+
+ return transformed_response
+
+
+argument_spec = dict(
+ host=dict(required=True, type='str'),
+ port=dict(type='int', default=4646),
+ state=dict(required=True, choices=['present', 'absent']),
+ use_ssl=dict(type='bool', default=True),
+ timeout=dict(type='int', default=5),
+ validate_certs=dict(type='bool', default=True),
+ client_cert=dict(type='path'),
+ client_key=dict(type='path'),
+ namespace=dict(type='str'),
+ token=dict(type='str', no_log=True),
+ name=dict(type='str'),
+ token_type=dict(choices=['client', 'management', 'bootstrap'], default='client'),
+ policies=dict(type='list', elements='str', default=[]),
+ global_replicated=dict(type='bool', default=False),
+)
+
+
+def setup_module_object():
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=False,
+ required_one_of=[
+ ['name', 'token_type']
+ ],
+ required_if=[
+ ('token_type', 'client', ('name',)),
+ ('token_type', 'management', ('name',)),
+ ],
+ )
+ return module
+
+
+def setup_nomad_client(module):
+ if not import_nomad:
+ module.fail_json(msg=missing_required_lib("python-nomad"))
+
+ certificate_ssl = (module.params.get('client_cert'), module.params.get('client_key'))
+
+ nomad_client = nomad.Nomad(
+ host=module.params.get('host'),
+ port=module.params.get('port'),
+ secure=module.params.get('use_ssl'),
+ timeout=module.params.get('timeout'),
+ verify=module.params.get('validate_certs'),
+ cert=certificate_ssl,
+ namespace=module.params.get('namespace'),
+ token=module.params.get('token')
+ )
+
+ return nomad_client
+
+
+def run(module):
+ nomad_client = setup_nomad_client(module)
+
+ msg = ""
+ result = {}
+ changed = False
+ if module.params.get('state') == "present":
+
+ if module.params.get('token_type') == 'bootstrap':
+ try:
+ current_token = get_token('Bootstrap Token', nomad_client)
+ if current_token:
+ msg = "ACL bootstrap already exist."
+ else:
+ nomad_result = nomad_client.acl.generate_bootstrap()
+ msg = "Boostrap token created."
+ result = transform_response(nomad_result)
+ changed = True
+
+ except nomad.api.exceptions.URLNotAuthorizedNomadException:
+ try:
+ nomad_result = nomad_client.acl.generate_bootstrap()
+ msg = "Boostrap token created."
+ result = transform_response(nomad_result)
+ changed = True
+
+ except Exception as e:
+ module.fail_json(msg=to_native(e))
+ else:
+ try:
+ token_info = {
+ "Name": module.params.get('name'),
+ "Type": module.params.get('token_type'),
+ "Policies": module.params.get('policies'),
+ "Global": module.params.get('global_replicated')
+ }
+
+ current_token = get_token(token_info['Name'], nomad_client)
+
+ if current_token:
+ token_info['AccessorID'] = current_token['AccessorID']
+ nomad_result = nomad_client.acl.update_token(current_token['AccessorID'], token_info)
+ msg = "ACL token updated."
+ result = transform_response(nomad_result)
+ changed = True
+
+ else:
+ nomad_result = nomad_client.acl.create_token(token_info)
+ msg = "ACL token Created."
+ result = transform_response(nomad_result)
+ changed = True
+
+ except Exception as e:
+ module.fail_json(msg=to_native(e))
+
+ if module.params.get('state') == "absent":
+
+ if not module.params.get('name'):
+ module.fail_json(msg="name is needed to delete token.")
+
+ if module.params.get('token_type') == 'bootstrap' or module.params.get('name') == 'Bootstrap Token':
+ module.fail_json(msg="Delete ACL bootstrap token is not allowed.")
+
+ try:
+ token = get_token(module.params.get('name'), nomad_client)
+ if token:
+ nomad_client.acl.delete_token(token.get('AccessorID'))
+ msg = 'ACL token deleted.'
+ changed = True
+ else:
+ msg = "No token with name '{0}' found".format(module.params.get('name'))
+
+ except Exception as e:
+ module.fail_json(msg=to_native(e))
+
+ module.exit_json(changed=changed, msg=msg, result=result)
+
+
+def main():
+ module = setup_module_object()
+ run(module)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/general/plugins/modules/nosh.py b/ansible_collections/community/general/plugins/modules/nosh.py
index 2dfb8d590..0e03142d8 100644
--- a/ansible_collections/community/general/plugins/modules/nosh.py
+++ b/ansible_collections/community/general/plugins/modules/nosh.py
@@ -36,26 +36,26 @@ options:
required: false
choices: [ started, stopped, reset, restarted, reloaded ]
description:
- - C(started)/C(stopped) are idempotent actions that will not run
+ - V(started)/V(stopped) are idempotent actions that will not run
commands unless necessary.
- C(restarted) will always bounce the service.
- C(reloaded) will send a SIGHUP or start the service.
- C(reset) will start or stop the service according to whether it is
+ V(restarted) will always bounce the service.
+ V(reloaded) will send a SIGHUP or start the service.
+ V(reset) will start or stop the service according to whether it is
enabled or not.
enabled:
required: false
type: bool
description:
- Enable or disable the service, independently of C(*.preset) file
- preference or running state. Mutually exclusive with I(preset). Will take
- effect prior to I(state=reset).
+ preference or running state. Mutually exclusive with O(preset). Will take
+ effect prior to O(state=reset).
preset:
required: false
type: bool
description:
- Enable or disable the service according to local preferences in C(*.preset) files.
- Mutually exclusive with I(enabled). Only has an effect if set to true. Will take
- effect prior to I(state=reset).
+ Mutually exclusive with O(enabled). Only has an effect if set to true. Will take
+ effect prior to O(state=reset).
user:
required: false
default: false
@@ -146,12 +146,12 @@ preset:
type: bool
sample: 'False'
state:
- description: service process run state, C(None) if the service is not loaded and will not be started
+ description: service process run state, V(none) if the service is not loaded and will not be started
returned: if state option is used
type: str
sample: "reloaded"
status:
- description: A dictionary with the key=value pairs returned by C(system-control show-json) or C(None) if the service is not loaded
+ description: A dictionary with the key=value pairs returned by C(system-control show-json) or V(none) if the service is not loaded
returned: success
type: complex
contains:
diff --git a/ansible_collections/community/general/plugins/modules/npm.py b/ansible_collections/community/general/plugins/modules/npm.py
index 013fd6e57..e6dc0b772 100644
--- a/ansible_collections/community/general/plugins/modules/npm.py
+++ b/ansible_collections/community/general/plugins/modules/npm.py
@@ -150,6 +150,7 @@ import re
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.common.text.converters import to_native
+from ansible_collections.community.general.plugins.module_utils.cmd_runner import CmdRunner, cmd_runner_fmt
class Npm(object):
@@ -172,33 +173,29 @@ class Npm(object):
else:
self.executable = [module.get_bin_path('npm', True)]
- if kwargs['version'] and self.state != 'absent':
- self.name_version = self.name + '@' + str(self.version)
+ if kwargs['version'] and kwargs['state'] != 'absent':
+ self.name_version = self.name + '@' + str(kwargs['version'])
else:
self.name_version = self.name
+ self.runner = CmdRunner(
+ module,
+ command=self.executable,
+ arg_formats=dict(
+ exec_args=cmd_runner_fmt.as_list(),
+ global_=cmd_runner_fmt.as_bool('--global'),
+ production=cmd_runner_fmt.as_bool('--production'),
+ ignore_scripts=cmd_runner_fmt.as_bool('--ignore-scripts'),
+ unsafe_perm=cmd_runner_fmt.as_bool('--unsafe-perm'),
+ name_version=cmd_runner_fmt.as_list(),
+ registry=cmd_runner_fmt.as_opt_val('--registry'),
+ no_optional=cmd_runner_fmt.as_bool('--no-optional'),
+ no_bin_links=cmd_runner_fmt.as_bool('--no-bin-links'),
+ )
+ )
+
def _exec(self, args, run_in_check_mode=False, check_rc=True, add_package_name=True):
if not self.module.check_mode or (self.module.check_mode and run_in_check_mode):
- cmd = self.executable + args
-
- if self.glbl:
- cmd.append('--global')
- if self.production and ('install' in cmd or 'update' in cmd or 'ci' in cmd):
- cmd.append('--production')
- if self.ignore_scripts:
- cmd.append('--ignore-scripts')
- if self.unsafe_perm:
- cmd.append('--unsafe-perm')
- if self.name_version and add_package_name:
- cmd.append(self.name_version)
- if self.registry:
- cmd.append('--registry')
- cmd.append(self.registry)
- if self.no_optional:
- cmd.append('--no-optional')
- if self.no_bin_links:
- cmd.append('--no-bin-links')
-
# If path is specified, cd into that path and run the command.
cwd = None
if self.path:
@@ -208,8 +205,19 @@ class Npm(object):
self.module.fail_json(msg="path %s is not a directory" % self.path)
cwd = self.path
- rc, out, err = self.module.run_command(cmd, check_rc=check_rc, cwd=cwd)
+ params = dict(self.module.params)
+ params['exec_args'] = args
+ params['global_'] = self.glbl
+ params['production'] = self.production and ('install' in args or 'update' in args or 'ci' in args)
+ params['name_version'] = self.name_version if add_package_name else None
+
+ with self.runner(
+ "exec_args global_ production ignore_scripts unsafe_perm name_version registry no_optional no_bin_links",
+ check_rc=check_rc, cwd=cwd
+ ) as ctx:
+ rc, out, err = ctx.run(**params)
return out
+
return ''
def list(self):
@@ -269,12 +277,12 @@ class Npm(object):
def main():
arg_spec = dict(
- name=dict(default=None, type='str'),
- path=dict(default=None, type='path'),
- version=dict(default=None, type='str'),
+ name=dict(type='str'),
+ path=dict(type='path'),
+ version=dict(type='str'),
production=dict(default=False, type='bool'),
- executable=dict(default=None, type='path'),
- registry=dict(default=None, type='str'),
+ executable=dict(type='path'),
+ registry=dict(type='str'),
state=dict(default='present', choices=['present', 'absent', 'latest']),
ignore_scripts=dict(default=False, type='bool'),
unsafe_perm=dict(default=False, type='bool'),
@@ -285,34 +293,35 @@ def main():
arg_spec['global'] = dict(default=False, type='bool')
module = AnsibleModule(
argument_spec=arg_spec,
- supports_check_mode=True
+ required_if=[('state', 'absent', ['name'])],
+ supports_check_mode=True,
)
name = module.params['name']
path = module.params['path']
version = module.params['version']
glbl = module.params['global']
- production = module.params['production']
- executable = module.params['executable']
- registry = module.params['registry']
state = module.params['state']
- ignore_scripts = module.params['ignore_scripts']
- unsafe_perm = module.params['unsafe_perm']
- ci = module.params['ci']
- no_optional = module.params['no_optional']
- no_bin_links = module.params['no_bin_links']
if not path and not glbl:
module.fail_json(msg='path must be specified when not using global')
- if state == 'absent' and not name:
- module.fail_json(msg='uninstalling a package is only available for named packages')
- npm = Npm(module, name=name, path=path, version=version, glbl=glbl, production=production,
- executable=executable, registry=registry, ignore_scripts=ignore_scripts,
- unsafe_perm=unsafe_perm, state=state, no_optional=no_optional, no_bin_links=no_bin_links)
+ npm = Npm(module,
+ name=name,
+ path=path,
+ version=version,
+ glbl=glbl,
+ production=module.params['production'],
+ executable=module.params['executable'],
+ registry=module.params['registry'],
+ ignore_scripts=module.params['ignore_scripts'],
+ unsafe_perm=module.params['unsafe_perm'],
+ state=state,
+ no_optional=module.params['no_optional'],
+ no_bin_links=module.params['no_bin_links'])
changed = False
- if ci:
+ if module.params['ci']:
npm.ci_install()
changed = True
elif state == 'present':
diff --git a/ansible_collections/community/general/plugins/modules/nsupdate.py b/ansible_collections/community/general/plugins/modules/nsupdate.py
index b2a84f76b..63750165c 100644
--- a/ansible_collections/community/general/plugins/modules/nsupdate.py
+++ b/ansible_collections/community/general/plugins/modules/nsupdate.py
@@ -45,29 +45,28 @@ options:
type: str
port:
description:
- - Use this TCP port when connecting to C(server).
+ - Use this TCP port when connecting to O(server).
default: 53
type: int
key_name:
description:
- - Use TSIG key name to authenticate against DNS C(server)
+ - Use TSIG key name to authenticate against DNS O(server)
type: str
key_secret:
description:
- - Use TSIG key secret, associated with C(key_name), to authenticate against C(server)
+ - Use TSIG key secret, associated with O(key_name), to authenticate against O(server)
type: str
key_algorithm:
description:
- - Specify key algorithm used by C(key_secret).
+ - Specify key algorithm used by O(key_secret).
choices: ['HMAC-MD5.SIG-ALG.REG.INT', 'hmac-md5', 'hmac-sha1', 'hmac-sha224', 'hmac-sha256', 'hmac-sha384',
'hmac-sha512']
default: 'hmac-md5'
type: str
zone:
description:
- - DNS record will be modified on this C(zone).
+ - DNS record will be modified on this O(zone).
- When omitted DNS will be queried to attempt finding the correct zone.
- - Starting with Ansible 2.7 this parameter is optional.
type: str
record:
description:
@@ -467,10 +466,8 @@ class RecordManager(object):
if lookup.rcode() != dns.rcode.NOERROR:
self.module.fail_json(msg='Failed to lookup TTL of existing matching record.')
- if self.module.params['type'] == 'NS':
- current_ttl = lookup.answer[0].ttl if lookup.answer else lookup.authority[0].ttl
- else:
- current_ttl = lookup.answer[0].ttl
+ current_ttl = lookup.answer[0].ttl if lookup.answer else lookup.authority[0].ttl
+
return current_ttl != self.module.params['ttl']
diff --git a/ansible_collections/community/general/plugins/modules/ocapi_command.py b/ansible_collections/community/general/plugins/modules/ocapi_command.py
index ed2366736..b6b9b6b98 100644
--- a/ansible_collections/community/general/plugins/modules/ocapi_command.py
+++ b/ansible_collections/community/general/plugins/modules/ocapi_command.py
@@ -41,17 +41,17 @@ options:
- Base URI of OOB controller.
type: str
proxy_slot_number:
- description: For proxied inband requests, the slot number of the IOM. Only applies if I(baseuri) is a proxy server.
+ description: For proxied inband requests, the slot number of the IOM. Only applies if O(baseuri) is a proxy server.
type: int
update_image_path:
required: false
description:
- - For C(FWUpload), the path on the local filesystem of the firmware update image.
+ - For O(command=FWUpload), the path on the local filesystem of the firmware update image.
type: str
job_name:
required: false
description:
- - For C(DeleteJob) command, the name of the job to delete.
+ - For O(command=DeleteJob) command, the name of the job to delete.
type: str
username:
required: true
diff --git a/ansible_collections/community/general/plugins/modules/ocapi_info.py b/ansible_collections/community/general/plugins/modules/ocapi_info.py
index d7dfdccc7..9906d804c 100644
--- a/ansible_collections/community/general/plugins/modules/ocapi_info.py
+++ b/ansible_collections/community/general/plugins/modules/ocapi_info.py
@@ -38,7 +38,7 @@ options:
- Base URI of OOB controller.
type: str
proxy_slot_number:
- description: For proxied inband requests, the slot number of the IOM. Only applies if I(baseuri) is a proxy server.
+ description: For proxied inband requests, the slot number of the IOM. Only applies if O(baseuri) is a proxy server.
type: int
username:
required: true
@@ -83,45 +83,45 @@ msg:
sample: "Action was successful"
percentComplete:
- description: Percent complete of the relevant operation. Applies to C(JobStatus) command.
+ description: Percent complete of the relevant operation. Applies to O(command=JobStatus).
returned: when supported
type: int
sample: 99
operationStatus:
- description: Status of the relevant operation. Applies to C(JobStatus) command. See OCAPI documentation for details.
+ description: Status of the relevant operation. Applies to O(command=JobStatus). See OCAPI documentation for details.
returned: when supported
type: str
sample: "Activate needed"
operationStatusId:
- description: Integer value of status (corresponds to operationStatus). Applies to C(JobStatus) command. See OCAPI documentation for details.
+ description: Integer value of status (corresponds to operationStatus). Applies to O(command=JobStatus). See OCAPI documentation for details.
returned: when supported
type: int
sample: 65540
operationHealth:
- description: Health of the operation. Applies to C(JobStatus) command. See OCAPI documentation for details.
+ description: Health of the operation. Applies to O(command=JobStatus). See OCAPI documentation for details.
returned: when supported
type: str
sample: "OK"
operationHealthId:
description: >
- Integer value for health of the operation (corresponds to C(operationHealth)). Applies to C(JobStatus) command.
+ Integer value for health of the operation (corresponds to RV(operationHealth)). Applies to O(command=JobStatus).
See OCAPI documentation for details.
returned: when supported
type: str
sample: "OK"
details:
- description: Details of the relevant operation. Applies to C(JobStatus) command.
+ description: Details of the relevant operation. Applies to O(command=JobStatus).
returned: when supported
type: list
elements: str
status:
- description: Dict containing status information. See OCAPI documentation for details.
+ description: Dictionary containing status information. See OCAPI documentation for details.
returned: when supported
type: dict
sample: {
diff --git a/ansible_collections/community/general/plugins/modules/oci_vcn.py b/ansible_collections/community/general/plugins/modules/oci_vcn.py
index 4e6487b8f..bf110b94b 100644
--- a/ansible_collections/community/general/plugins/modules/oci_vcn.py
+++ b/ansible_collections/community/general/plugins/modules/oci_vcn.py
@@ -23,12 +23,12 @@ attributes:
support: none
options:
cidr_block:
- description: The CIDR IP address block of the VCN. Required when creating a VCN with I(state=present).
+ description: The CIDR IP address block of the VCN. Required when creating a VCN with O(state=present).
type: str
required: false
compartment_id:
- description: The OCID of the compartment to contain the VCN. Required when creating a VCN with I(state=present).
- This option is mutually exclusive with I(vcn_id).
+ description: The OCID of the compartment to contain the VCN. Required when creating a VCN with O(state=present).
+ This option is mutually exclusive with O(vcn_id).
type: str
display_name:
description: A user-friendly name. Does not have to be unique, and it's changeable.
@@ -42,13 +42,13 @@ options:
with a letter. The value cannot be changed.
type: str
state:
- description: Create or update a VCN with I(state=present). Use I(state=absent) to delete a VCN.
+ description: Create or update a VCN with O(state=present). Use O(state=absent) to delete a VCN.
type: str
default: present
choices: ['present', 'absent']
vcn_id:
- description: The OCID of the VCN. Required when deleting a VCN with I(state=absent) or updating a VCN
- with I(state=present). This option is mutually exclusive with I(compartment_id).
+ description: The OCID of the VCN. Required when deleting a VCN with O(state=absent) or updating a VCN
+ with O(state=present). This option is mutually exclusive with O(compartment_id).
type: str
aliases: [ 'id' ]
author: "Rohit Chaware (@rohitChaware)"
diff --git a/ansible_collections/community/general/plugins/modules/odbc.py b/ansible_collections/community/general/plugins/modules/odbc.py
index fbc4b63ae..bc2e89656 100644
--- a/ansible_collections/community/general/plugins/modules/odbc.py
+++ b/ansible_collections/community/general/plugins/modules/odbc.py
@@ -43,12 +43,11 @@ options:
description:
- Perform a commit after the execution of the SQL query.
- Some databases allow a commit after a select whereas others raise an exception.
- - Default is C(true) to support legacy module behavior.
+ - Default is V(true) to support legacy module behavior.
type: bool
default: true
version_added: 1.3.0
requirements:
- - "python >= 2.6"
- "pyodbc"
notes:
diff --git a/ansible_collections/community/general/plugins/modules/one_host.py b/ansible_collections/community/general/plugins/modules/one_host.py
index c4578f950..eea112173 100644
--- a/ansible_collections/community/general/plugins/modules/one_host.py
+++ b/ansible_collections/community/general/plugins/modules/one_host.py
@@ -38,11 +38,11 @@ options:
state:
description:
- Takes the host to the desired lifecycle state.
- - If C(absent) the host will be deleted from the cluster.
- - If C(present) the host will be created in the cluster (includes C(enabled), C(disabled) and C(offline) states).
- - If C(enabled) the host is fully operational.
- - C(disabled), e.g. to perform maintenance operations.
- - C(offline), host is totally offline.
+ - If V(absent) the host will be deleted from the cluster.
+ - If V(present) the host will be created in the cluster (includes V(enabled), V(disabled) and V(offline) states).
+ - If V(enabled) the host is fully operational.
+ - V(disabled), e.g. to perform maintenance operations.
+ - V(offline), host is totally offline.
choices:
- absent
- present
diff --git a/ansible_collections/community/general/plugins/modules/one_image.py b/ansible_collections/community/general/plugins/modules/one_image.py
index a50b33e93..a0081a0fe 100644
--- a/ansible_collections/community/general/plugins/modules/one_image.py
+++ b/ansible_collections/community/general/plugins/modules/one_image.py
@@ -29,32 +29,32 @@ options:
- URL of the OpenNebula RPC server.
- It is recommended to use HTTPS so that the username/password are not
- transferred over the network unencrypted.
- - If not set then the value of the C(ONE_URL) environment variable is used.
+ - If not set then the value of the E(ONE_URL) environment variable is used.
type: str
api_username:
description:
- Name of the user to login into the OpenNebula RPC server. If not set
- - then the value of the C(ONE_USERNAME) environment variable is used.
+ - then the value of the E(ONE_USERNAME) environment variable is used.
type: str
api_password:
description:
- Password of the user to login into OpenNebula RPC server. If not set
- - then the value of the C(ONE_PASSWORD) environment variable is used.
+ - then the value of the E(ONE_PASSWORD) environment variable is used.
type: str
id:
description:
- - A C(id) of the image you would like to manage.
+ - A O(id) of the image you would like to manage.
type: int
name:
description:
- - A C(name) of the image you would like to manage.
+ - A O(name) of the image you would like to manage.
type: str
state:
description:
- - C(present) - state that is used to manage the image
- - C(absent) - delete the image
- - C(cloned) - clone the image
- - C(renamed) - rename the image to the C(new_name)
+ - V(present) - state that is used to manage the image
+ - V(absent) - delete the image
+ - V(cloned) - clone the image
+ - V(renamed) - rename the image to the O(new_name)
choices: ["present", "absent", "cloned", "renamed"]
default: present
type: str
@@ -65,7 +65,7 @@ options:
new_name:
description:
- A name that will be assigned to the existing or new image.
- - In the case of cloning, by default C(new_name) will take the name of the origin image with the prefix 'Copy of'.
+ - In the case of cloning, by default O(new_name) will take the name of the origin image with the prefix 'Copy of'.
type: str
author:
- "Milan Ilic (@ilicmilan)"
diff --git a/ansible_collections/community/general/plugins/modules/one_image_info.py b/ansible_collections/community/general/plugins/modules/one_image_info.py
index 938f0ef2a..c9d7c4035 100644
--- a/ansible_collections/community/general/plugins/modules/one_image_info.py
+++ b/ansible_collections/community/general/plugins/modules/one_image_info.py
@@ -14,7 +14,6 @@ module: one_image_info
short_description: Gather information on OpenNebula images
description:
- Gather information on OpenNebula images.
- - This module was called C(one_image_facts) before Ansible 2.9. The usage did not change.
requirements:
- pyone
extends_documentation_fragment:
@@ -26,17 +25,17 @@ options:
- URL of the OpenNebula RPC server.
- It is recommended to use HTTPS so that the username/password are not
- transferred over the network unencrypted.
- - If not set then the value of the C(ONE_URL) environment variable is used.
+ - If not set then the value of the E(ONE_URL) environment variable is used.
type: str
api_username:
description:
- Name of the user to login into the OpenNebula RPC server. If not set
- - then the value of the C(ONE_USERNAME) environment variable is used.
+ - then the value of the E(ONE_USERNAME) environment variable is used.
type: str
api_password:
description:
- Password of the user to login into OpenNebula RPC server. If not set
- - then the value of the C(ONE_PASSWORD) environment variable is used.
+ - then the value of the E(ONE_PASSWORD) environment variable is used.
type: str
ids:
description:
@@ -46,10 +45,10 @@ options:
elements: str
name:
description:
- - A C(name) of the image whose facts will be gathered.
- - If the C(name) begins with '~' the C(name) will be used as regex pattern
+ - A O(name) of the image whose facts will be gathered.
+ - If the O(name) begins with V(~) the O(name) will be used as regex pattern
- which restricts the list of images (whose facts will be returned) whose names match specified regex.
- - Also, if the C(name) begins with '~*' case-insensitive matching will be performed.
+ - Also, if the O(name) begins with V(~*) case-insensitive matching will be performed.
- See examples for more details.
type: str
author:
diff --git a/ansible_collections/community/general/plugins/modules/one_service.py b/ansible_collections/community/general/plugins/modules/one_service.py
index 4f5143887..81b42c0ec 100644
--- a/ansible_collections/community/general/plugins/modules/one_service.py
+++ b/ansible_collections/community/general/plugins/modules/one_service.py
@@ -26,15 +26,15 @@ options:
description:
- URL of the OpenNebula OneFlow API server.
- It is recommended to use HTTPS so that the username/password are not transferred over the network unencrypted.
- - If not set then the value of the ONEFLOW_URL environment variable is used.
+ - If not set then the value of the E(ONEFLOW_URL) environment variable is used.
type: str
api_username:
description:
- - Name of the user to login into the OpenNebula OneFlow API server. If not set then the value of the C(ONEFLOW_USERNAME) environment variable is used.
+ - Name of the user to login into the OpenNebula OneFlow API server. If not set then the value of the E(ONEFLOW_USERNAME) environment variable is used.
type: str
api_password:
description:
- - Password of the user to login into OpenNebula OneFlow API server. If not set then the value of the C(ONEFLOW_PASSWORD) environment variable is used.
+ - Password of the user to login into OpenNebula OneFlow API server. If not set then the value of the E(ONEFLOW_PASSWORD) environment variable is used.
type: str
template_name:
description:
@@ -54,20 +54,20 @@ options:
type: str
unique:
description:
- - Setting I(unique=true) will make sure that there is only one service instance running with a name set with C(service_name) when
- instantiating a service from a template specified with I(template_id) or I(template_name). Check examples below.
+ - Setting O(unique=true) will make sure that there is only one service instance running with a name set with O(service_name) when
+ instantiating a service from a template specified with O(template_id) or O(template_name). Check examples below.
type: bool
default: false
state:
description:
- - C(present) - instantiate a service from a template specified with I(template_id) or I(template_name).
- - C(absent) - terminate an instance of a service specified with I(template_id) or I(template_name).
+ - V(present) - instantiate a service from a template specified with O(template_id) or O(template_name).
+ - V(absent) - terminate an instance of a service specified with O(template_id) or O(template_name).
choices: ["present", "absent"]
default: present
type: str
mode:
description:
- - Set permission mode of a service instance in octet format, e.g. C(600) to give owner C(use) and C(manage) and nothing to group and others.
+ - Set permission mode of a service instance in octet format, for example V(0600) to give owner C(use) and C(manage) and nothing to group and others.
type: str
owner_id:
description:
diff --git a/ansible_collections/community/general/plugins/modules/one_template.py b/ansible_collections/community/general/plugins/modules/one_template.py
index 97d0f856e..06460fee5 100644
--- a/ansible_collections/community/general/plugins/modules/one_template.py
+++ b/ansible_collections/community/general/plugins/modules/one_template.py
@@ -34,12 +34,12 @@ attributes:
options:
id:
description:
- - A I(id) of the template you would like to manage. If not set then a
- - new template will be created with the given I(name).
+ - A O(id) of the template you would like to manage. If not set then a
+ - new template will be created with the given O(name).
type: int
name:
description:
- - A I(name) of the template you would like to manage. If a template with
+ - A O(name) of the template you would like to manage. If a template with
- the given name does not exist it will be created, otherwise it will be
- managed by this module.
type: str
@@ -49,8 +49,8 @@ options:
type: str
state:
description:
- - C(present) - state that is used to manage the template.
- - C(absent) - delete the template.
+ - V(present) - state that is used to manage the template.
+ - V(absent) - delete the template.
choices: ["present", "absent"]
default: present
type: str
@@ -116,36 +116,36 @@ RETURN = '''
id:
description: template id
type: int
- returned: when I(state=present)
+ returned: when O(state=present)
sample: 153
name:
description: template name
type: str
- returned: when I(state=present)
+ returned: when O(state=present)
sample: app1
template:
description: the parsed template
type: dict
- returned: when I(state=present)
+ returned: when O(state=present)
group_id:
description: template's group id
type: int
- returned: when I(state=present)
+ returned: when O(state=present)
sample: 1
group_name:
description: template's group name
type: str
- returned: when I(state=present)
+ returned: when O(state=present)
sample: one-users
owner_id:
description: template's owner id
type: int
- returned: when I(state=present)
+ returned: when O(state=present)
sample: 143
owner_name:
description: template's owner name
type: str
- returned: when I(state=present)
+ returned: when O(state=present)
sample: ansible-test
'''
diff --git a/ansible_collections/community/general/plugins/modules/one_vm.py b/ansible_collections/community/general/plugins/modules/one_vm.py
index 1bbf47466..8ee9c8560 100644
--- a/ansible_collections/community/general/plugins/modules/one_vm.py
+++ b/ansible_collections/community/general/plugins/modules/one_vm.py
@@ -29,25 +29,25 @@ options:
description:
- URL of the OpenNebula RPC server.
- It is recommended to use HTTPS so that the username/password are not
- - transferred over the network unencrypted.
- - If not set then the value of the C(ONE_URL) environment variable is used.
+ transferred over the network unencrypted.
+ - If not set then the value of the E(ONE_URL) environment variable is used.
type: str
api_username:
description:
- Name of the user to login into the OpenNebula RPC server. If not set
- - then the value of the C(ONE_USERNAME) environment variable is used.
+ then the value of the E(ONE_USERNAME) environment variable is used.
type: str
api_password:
description:
- Password of the user to login into OpenNebula RPC server. If not set
- - then the value of the C(ONE_PASSWORD) environment variable is used.
- - if both I(api_username) or I(api_password) are not set, then it will try
- - authenticate with ONE auth file. Default path is "~/.one/one_auth".
- - Set environment variable C(ONE_AUTH) to override this path.
+ then the value of the E(ONE_PASSWORD) environment variable is used.
+ if both O(api_username) or O(api_password) are not set, then it will try
+ authenticate with ONE auth file. Default path is "~/.one/one_auth".
+ - Set environment variable E(ONE_AUTH) to override this path.
type: str
template_name:
description:
- - Name of VM template to use to create a new instace
+ - Name of VM template to use to create a new instance
type: str
template_id:
description:
@@ -60,32 +60,32 @@ options:
type: bool
instance_ids:
description:
- - A list of instance ids used for states':' C(absent), C(running), C(rebooted), C(poweredoff)
+ - 'A list of instance ids used for states: V(absent), V(running), V(rebooted), V(poweredoff).'
aliases: ['ids']
type: list
elements: int
state:
description:
- - C(present) - create instances from a template specified with C(template_id)/C(template_name).
- - C(running) - run instances
- - C(poweredoff) - power-off instances
- - C(rebooted) - reboot instances
- - C(absent) - terminate instances
+ - V(present) - create instances from a template specified with C(template_id)/C(template_name).
+ - V(running) - run instances
+ - V(poweredoff) - power-off instances
+ - V(rebooted) - reboot instances
+ - V(absent) - terminate instances
choices: ["present", "absent", "running", "rebooted", "poweredoff"]
default: present
type: str
hard:
description:
- - Reboot, power-off or terminate instances C(hard)
+ - Reboot, power-off or terminate instances C(hard).
default: false
type: bool
wait:
description:
- Wait for the instance to reach its desired state before returning. Keep
- - in mind if you are waiting for instance to be in running state it
- - doesn't mean that you will be able to SSH on that machine only that
- - boot process have started on that instance, see 'wait_for' example for
- - details.
+ in mind if you are waiting for instance to be in running state it
+ doesn't mean that you will be able to SSH on that machine only that
+ boot process have started on that instance, see 'wait_for' example for
+ details.
default: true
type: bool
wait_timeout:
@@ -96,36 +96,36 @@ options:
attributes:
description:
- A dictionary of key/value attributes to add to new instances, or for
- - setting C(state) of instances with these attributes.
+ setting C(state) of instances with these attributes.
- Keys are case insensitive and OpenNebula automatically converts them to upper case.
- Be aware C(NAME) is a special attribute which sets the name of the VM when it's deployed.
- C(#) character(s) can be appended to the C(NAME) and the module will automatically add
- - indexes to the names of VMs.
+ indexes to the names of VMs.
- For example':' C(NAME':' foo-###) would create VMs with names C(foo-000), C(foo-001),...
- - When used with C(count_attributes) and C(exact_count) the module will
- - match the base name without the index part.
+ - When used with O(count_attributes) and O(exact_count) the module will
+ match the base name without the index part.
default: {}
type: dict
labels:
description:
- A list of labels to associate with new instances, or for setting
- - C(state) of instances with these labels.
+ C(state) of instances with these labels.
default: []
type: list
elements: str
count_attributes:
description:
- A dictionary of key/value attributes that can only be used with
- - C(exact_count) to determine how many nodes based on a specific
- - attributes criteria should be deployed. This can be expressed in
- - multiple ways and is shown in the EXAMPLES section.
+ O(exact_count) to determine how many nodes based on a specific
+ attributes criteria should be deployed. This can be expressed in
+ multiple ways and is shown in the EXAMPLES section.
type: dict
count_labels:
description:
- - A list of labels that can only be used with C(exact_count) to determine
- - how many nodes based on a specific labels criteria should be deployed.
- - This can be expressed in multiple ways and is shown in the EXAMPLES
- - section.
+ - A list of labels that can only be used with O(exact_count) to determine
+ how many nodes based on a specific labels criteria should be deployed.
+ This can be expressed in multiple ways and is shown in the EXAMPLES
+ section.
type: list
elements: str
count:
@@ -135,14 +135,14 @@ options:
type: int
exact_count:
description:
- - Indicates how many instances that match C(count_attributes) and
- - C(count_labels) parameters should be deployed. Instances are either
- - created or terminated based on this value.
- - NOTE':' Instances with the least IDs will be terminated first.
+ - Indicates how many instances that match O(count_attributes) and
+ O(count_labels) parameters should be deployed. Instances are either
+ created or terminated based on this value.
+ - 'B(NOTE:) Instances with the least IDs will be terminated first.'
type: int
mode:
description:
- - Set permission mode of the instance in octet format, e.g. C(600) to give owner C(use) and C(manage) and nothing to group and others.
+ - Set permission mode of the instance in octet format, for example V(0600) to give owner C(use) and C(manage) and nothing to group and others.
type: str
owner_id:
description:
@@ -159,14 +159,14 @@ options:
disk_size:
description:
- The size of the disk created for new instances (in MB, GB, TB,...).
- - NOTE':' If The Template hats Multiple Disks the Order of the Sizes is
- - matched against the order specified in C(template_id)/C(template_name).
+ - 'B(NOTE:) If The Template hats Multiple Disks the Order of the Sizes is
+ matched against the order specified in O(template_id)/O(template_name).'
type: list
elements: str
cpu:
description:
- Percentage of CPU divided by 100 required for the new instance. Half a
- - processor is written 0.5.
+ processor is written 0.5.
type: float
vcpu:
description:
@@ -183,8 +183,8 @@ options:
- Creates an image from a VM disk.
- It is a dictionary where you have to specify C(name) of the new image.
- Optionally you can specify C(disk_id) of the disk you want to save. By default C(disk_id) is 0.
- - I(NOTE)':' This operation will only be performed on the first VM (if more than one VM ID is passed)
- - and the VM has to be in the C(poweredoff) state.
+ - 'B(NOTE:) This operation will only be performed on the first VM (if more than one VM ID is passed)
+ and the VM has to be in the C(poweredoff) state.'
- Also this operation will fail if an image with specified C(name) already exists.
type: dict
persistent:
@@ -195,17 +195,17 @@ options:
version_added: '0.2.0'
datastore_id:
description:
- - Name of Datastore to use to create a new instace
+ - Name of Datastore to use to create a new instance
version_added: '0.2.0'
type: int
datastore_name:
description:
- - Name of Datastore to use to create a new instace
+ - Name of Datastore to use to create a new instance
version_added: '0.2.0'
type: str
updateconf:
description:
- - When I(instance_ids) is provided, updates running VMs with the C(updateconf) API call.
+ - When O(instance_ids) is provided, updates running VMs with the C(updateconf) API call.
- When new VMs are being created, emulates the C(updateconf) API call via direct template merge.
- Allows for complete modifications of the C(CONTEXT) attribute.
type: dict
@@ -445,12 +445,12 @@ EXAMPLES = '''
RETURN = '''
instances_ids:
- description: a list of instances ids whose state is changed or which are fetched with C(instance_ids) option.
+ description: a list of instances ids whose state is changed or which are fetched with O(instance_ids) option.
type: list
returned: success
sample: [ 1234, 1235 ]
instances:
- description: a list of instances info whose state is changed or which are fetched with C(instance_ids) option.
+ description: a list of instances info whose state is changed or which are fetched with O(instance_ids) option.
type: complex
returned: success
contains:
@@ -562,7 +562,7 @@ instances:
tagged_instances:
description:
- A list of instances info based on a specific attributes and/or
- - labels that are specified with C(count_attributes) and C(count_labels)
+ - labels that are specified with O(count_attributes) and O(count_labels)
- options.
type: complex
returned: success
@@ -1390,7 +1390,7 @@ def check_name_attribute(module, attributes):
if attributes.get("NAME"):
import re
if re.match(r'^[^#]+#*$', attributes.get("NAME")) is None:
- module.fail_json(msg="Ilegal 'NAME' attribute: '" + attributes.get("NAME") +
+ module.fail_json(msg="Illegal 'NAME' attribute: '" + attributes.get("NAME") +
"' .Signs '#' are allowed only at the end of the name and the name cannot contain only '#'.")
diff --git a/ansible_collections/community/general/plugins/modules/oneandone_firewall_policy.py b/ansible_collections/community/general/plugins/modules/oneandone_firewall_policy.py
index 37dca74f2..dfcabf6f6 100644
--- a/ansible_collections/community/general/plugins/modules/oneandone_firewall_policy.py
+++ b/ansible_collections/community/general/plugins/modules/oneandone_firewall_policy.py
@@ -110,7 +110,6 @@ options:
requirements:
- "1and1"
- - "python >= 2.6"
author:
- "Amel Ajdinovic (@aajdinov)"
diff --git a/ansible_collections/community/general/plugins/modules/oneandone_load_balancer.py b/ansible_collections/community/general/plugins/modules/oneandone_load_balancer.py
index 7f7af9c4f..da361ef2d 100644
--- a/ansible_collections/community/general/plugins/modules/oneandone_load_balancer.py
+++ b/ansible_collections/community/general/plugins/modules/oneandone_load_balancer.py
@@ -40,7 +40,7 @@ options:
api_url:
description:
- Custom API URL. Overrides the
- ONEANDONE_API_URL environment variable.
+ E(ONEANDONE_API_URL) environment variable.
type: str
required: false
name:
@@ -83,7 +83,7 @@ options:
datacenter:
description:
- ID or country code of the datacenter where the load balancer will be created.
- - If not specified, it defaults to I(US).
+ - If not specified, it defaults to V(US).
type: str
choices: [ "US", "ES", "DE", "GB" ]
required: false
@@ -148,7 +148,6 @@ options:
requirements:
- "1and1"
- - "python >= 2.6"
author:
- Amel Ajdinovic (@aajdinov)
diff --git a/ansible_collections/community/general/plugins/modules/oneandone_monitoring_policy.py b/ansible_collections/community/general/plugins/modules/oneandone_monitoring_policy.py
index 6118645bf..abdf8ca7a 100644
--- a/ansible_collections/community/general/plugins/modules/oneandone_monitoring_policy.py
+++ b/ansible_collections/community/general/plugins/modules/oneandone_monitoring_policy.py
@@ -207,7 +207,6 @@ options:
requirements:
- "1and1"
- - "python >= 2.6"
author:
- "Amel Ajdinovic (@aajdinov)"
diff --git a/ansible_collections/community/general/plugins/modules/oneandone_private_network.py b/ansible_collections/community/general/plugins/modules/oneandone_private_network.py
index 114bf2f22..cf74597ed 100644
--- a/ansible_collections/community/general/plugins/modules/oneandone_private_network.py
+++ b/ansible_collections/community/general/plugins/modules/oneandone_private_network.py
@@ -95,7 +95,6 @@ options:
requirements:
- "1and1"
- - "python >= 2.6"
author:
- Amel Ajdinovic (@aajdinov)
diff --git a/ansible_collections/community/general/plugins/modules/oneandone_public_ip.py b/ansible_collections/community/general/plugins/modules/oneandone_public_ip.py
index df5476feb..2dceb41bf 100644
--- a/ansible_collections/community/general/plugins/modules/oneandone_public_ip.py
+++ b/ansible_collections/community/general/plugins/modules/oneandone_public_ip.py
@@ -81,7 +81,6 @@ options:
requirements:
- "1and1"
- - "python >= 2.6"
author:
- Amel Ajdinovic (@aajdinov)
diff --git a/ansible_collections/community/general/plugins/modules/oneandone_server.py b/ansible_collections/community/general/plugins/modules/oneandone_server.py
index 59f504178..b6653b48b 100644
--- a/ansible_collections/community/general/plugins/modules/oneandone_server.py
+++ b/ansible_collections/community/general/plugins/modules/oneandone_server.py
@@ -62,7 +62,7 @@ options:
- The instance size name or ID of the server.
It is required only for 'present' state, and it is mutually exclusive with
vcore, cores_per_processor, ram, and hdds parameters.
- - 'The available choices are: C(S), C(M), C(L), C(XL), C(XXL), C(3XL), C(4XL), C(5XL)'
+ - 'The available choices are: V(S), V(M), V(L), V(XL), V(XXL), V(3XL), V(4XL), V(5XL)'
type: str
vcore:
description:
@@ -148,7 +148,6 @@ options:
requirements:
- "1and1"
- - "python >= 2.6"
author:
- "Amel Ajdinovic (@aajdinov)"
diff --git a/ansible_collections/community/general/plugins/modules/onepassword_info.py b/ansible_collections/community/general/plugins/modules/onepassword_info.py
index bb814c443..b63352790 100644
--- a/ansible_collections/community/general/plugins/modules/onepassword_info.py
+++ b/ansible_collections/community/general/plugins/modules/onepassword_info.py
@@ -20,15 +20,12 @@ requirements:
- C(op) 1Password command line utility. See U(https://support.1password.com/command-line/)
notes:
- Tested with C(op) version 0.5.5
- - "Based on the C(onepassword) lookup plugin by Scott Buchanan <sbuchanan@ri.pn>."
+ - "Based on the P(community.general.onepassword#lookup) lookup plugin by Scott Buchanan <sbuchanan@ri.pn>."
short_description: Gather items from 1Password
description:
- M(community.general.onepassword_info) wraps the C(op) command line utility to fetch data about one or more 1Password items.
- A fatal error occurs if any of the items being searched for can not be found.
- Recommend using with the C(no_log) option to avoid logging the values of the secrets being retrieved.
- - This module was called C(onepassword_facts) before Ansible 2.9, returning C(ansible_facts).
- Note that the M(community.general.onepassword_info) module no longer returns C(ansible_facts)!
- You must now use the C(register) option to use the facts in other tasks.
extends_documentation_fragment:
- community.general.attributes
- community.general.attributes.info_module
@@ -39,7 +36,7 @@ options:
description:
- A list of one or more search terms.
- Each search term can either be a simple string or it can be a dictionary for more control.
- - When passing a simple string, I(field) is assumed to be C(password).
+ - When passing a simple string, O(search_terms[].field) is assumed to be V(password).
- When passing a dictionary, the following fields are available.
suboptions:
name:
@@ -82,7 +79,7 @@ options:
type: str
description:
- The master password for your subdomain.
- - This is always required when specifying C(auto_login).
+ - This is always required when specifying O(auto_login).
required: true
secret_key:
type: str
diff --git a/ansible_collections/community/general/plugins/modules/oneview_datacenter_info.py b/ansible_collections/community/general/plugins/modules/oneview_datacenter_info.py
index 541f3d669..ed04e2279 100644
--- a/ansible_collections/community/general/plugins/modules/oneview_datacenter_info.py
+++ b/ansible_collections/community/general/plugins/modules/oneview_datacenter_info.py
@@ -13,8 +13,6 @@ module: oneview_datacenter_info
short_description: Retrieve information about the OneView Data Centers
description:
- Retrieve information about the OneView Data Centers.
- - This module was called C(oneview_datacenter_facts) before Ansible 2.9, returning C(ansible_facts).
- Note that the M(community.general.oneview_datacenter_info) module no longer returns C(ansible_facts)!
requirements:
- "hpOneView >= 2.0.1"
author:
diff --git a/ansible_collections/community/general/plugins/modules/oneview_enclosure_info.py b/ansible_collections/community/general/plugins/modules/oneview_enclosure_info.py
index 3e593b7ae..4e203a50a 100644
--- a/ansible_collections/community/general/plugins/modules/oneview_enclosure_info.py
+++ b/ansible_collections/community/general/plugins/modules/oneview_enclosure_info.py
@@ -14,8 +14,6 @@ module: oneview_enclosure_info
short_description: Retrieve information about one or more Enclosures
description:
- Retrieve information about one or more of the Enclosures from OneView.
- - This module was called C(oneview_enclosure_facts) before Ansible 2.9, returning C(ansible_facts).
- Note that the M(community.general.oneview_enclosure_info) module no longer returns C(ansible_facts)!
requirements:
- hpOneView >= 2.0.1
author:
@@ -34,7 +32,7 @@ options:
options:
description:
- "List with options to gather additional information about an Enclosure and related resources.
- Options allowed: C(script), C(environmentalConfiguration), and C(utilization). For the option C(utilization),
+ Options allowed: V(script), V(environmentalConfiguration), and V(utilization). For the option V(utilization),
you can provide specific parameters."
type: list
elements: raw
@@ -77,7 +75,7 @@ EXAMPLES = '''
delegate_to: localhost
register: result
-- name: Print fetched information about paginated, filtered ans sorted list of Enclosures
+- name: Print fetched information about paginated, filtered and sorted list of Enclosures
ansible.builtin.debug:
msg: "{{ result.enclosures }}"
diff --git a/ansible_collections/community/general/plugins/modules/oneview_ethernet_network.py b/ansible_collections/community/general/plugins/modules/oneview_ethernet_network.py
index 8eb63db5a..981d949cd 100644
--- a/ansible_collections/community/general/plugins/modules/oneview_ethernet_network.py
+++ b/ansible_collections/community/general/plugins/modules/oneview_ethernet_network.py
@@ -28,9 +28,9 @@ options:
state:
description:
- Indicates the desired state for the Ethernet Network resource.
- - C(present) will ensure data properties are compliant with OneView.
- - C(absent) will remove the resource from OneView, if it exists.
- - C(default_bandwidth_reset) will reset the network connection template to the default.
+ - V(present) will ensure data properties are compliant with OneView.
+ - V(absent) will remove the resource from OneView, if it exists.
+ - V(default_bandwidth_reset) will reset the network connection template to the default.
type: str
default: present
choices: [present, absent, default_bandwidth_reset]
diff --git a/ansible_collections/community/general/plugins/modules/oneview_ethernet_network_info.py b/ansible_collections/community/general/plugins/modules/oneview_ethernet_network_info.py
index e107f3b47..7da008b04 100644
--- a/ansible_collections/community/general/plugins/modules/oneview_ethernet_network_info.py
+++ b/ansible_collections/community/general/plugins/modules/oneview_ethernet_network_info.py
@@ -13,8 +13,6 @@ module: oneview_ethernet_network_info
short_description: Retrieve the information about one or more of the OneView Ethernet Networks
description:
- Retrieve the information about one or more of the Ethernet Networks from OneView.
- - This module was called C(oneview_ethernet_network_facts) before Ansible 2.9, returning C(ansible_facts).
- Note that the M(community.general.oneview_ethernet_network_info) module no longer returns C(ansible_facts)!
requirements:
- hpOneView >= 2.0.1
author:
@@ -33,7 +31,7 @@ options:
options:
description:
- "List with options to gather additional information about an Ethernet Network and related resources.
- Options allowed: C(associatedProfiles) and C(associatedUplinkGroups)."
+ Options allowed: V(associatedProfiles) and V(associatedUplinkGroups)."
type: list
elements: str
extends_documentation_fragment:
diff --git a/ansible_collections/community/general/plugins/modules/oneview_fc_network.py b/ansible_collections/community/general/plugins/modules/oneview_fc_network.py
index 4c5f867e2..9f0c4358b 100644
--- a/ansible_collections/community/general/plugins/modules/oneview_fc_network.py
+++ b/ansible_collections/community/general/plugins/modules/oneview_fc_network.py
@@ -25,8 +25,8 @@ options:
state:
description:
- Indicates the desired state for the Fibre Channel Network resource.
- C(present) will ensure data properties are compliant with OneView.
- C(absent) will remove the resource from OneView, if it exists.
+ V(present) will ensure data properties are compliant with OneView.
+ V(absent) will remove the resource from OneView, if it exists.
type: str
choices: ['present', 'absent']
required: true
diff --git a/ansible_collections/community/general/plugins/modules/oneview_fc_network_info.py b/ansible_collections/community/general/plugins/modules/oneview_fc_network_info.py
index d4044b08b..096af4830 100644
--- a/ansible_collections/community/general/plugins/modules/oneview_fc_network_info.py
+++ b/ansible_collections/community/general/plugins/modules/oneview_fc_network_info.py
@@ -13,8 +13,6 @@ module: oneview_fc_network_info
short_description: Retrieve the information about one or more of the OneView Fibre Channel Networks
description:
- Retrieve the information about one or more of the Fibre Channel Networks from OneView.
- - This module was called C(oneview_fc_network_facts) before Ansible 2.9, returning C(ansible_facts).
- Note that the M(community.general.oneview_fc_network_info) module no longer returns C(ansible_facts)!
requirements:
- hpOneView >= 2.0.1
author:
diff --git a/ansible_collections/community/general/plugins/modules/oneview_fcoe_network.py b/ansible_collections/community/general/plugins/modules/oneview_fcoe_network.py
index 73eef5af0..e1216b1d9 100644
--- a/ansible_collections/community/general/plugins/modules/oneview_fcoe_network.py
+++ b/ansible_collections/community/general/plugins/modules/oneview_fcoe_network.py
@@ -14,7 +14,7 @@ short_description: Manage OneView FCoE Network resources
description:
- Provides an interface to manage FCoE Network resources. Can create, update, or delete.
requirements:
- - "python >= 2.7.9"
+ - "Python >= 2.7.9"
- "hpOneView >= 4.0.0"
author: "Felipe Bulsoni (@fgbulsoni)"
attributes:
@@ -26,8 +26,8 @@ options:
state:
description:
- Indicates the desired state for the FCoE Network resource.
- C(present) will ensure data properties are compliant with OneView.
- C(absent) will remove the resource from OneView, if it exists.
+ V(present) will ensure data properties are compliant with OneView.
+ V(absent) will remove the resource from OneView, if it exists.
type: str
default: present
choices: ['present', 'absent']
diff --git a/ansible_collections/community/general/plugins/modules/oneview_fcoe_network_info.py b/ansible_collections/community/general/plugins/modules/oneview_fcoe_network_info.py
index d9ee1b379..b3460d59a 100644
--- a/ansible_collections/community/general/plugins/modules/oneview_fcoe_network_info.py
+++ b/ansible_collections/community/general/plugins/modules/oneview_fcoe_network_info.py
@@ -13,8 +13,6 @@ module: oneview_fcoe_network_info
short_description: Retrieve the information about one or more of the OneView FCoE Networks
description:
- Retrieve the information about one or more of the FCoE Networks from OneView.
- - This module was called C(oneview_fcoe_network_facts) before Ansible 2.9, returning C(ansible_facts).
- Note that the M(community.general.oneview_fcoe_network_info) module no longer returns C(ansible_facts)!
requirements:
- hpOneView >= 2.0.1
author:
diff --git a/ansible_collections/community/general/plugins/modules/oneview_logical_interconnect_group.py b/ansible_collections/community/general/plugins/modules/oneview_logical_interconnect_group.py
index cd8e87528..d1303f011 100644
--- a/ansible_collections/community/general/plugins/modules/oneview_logical_interconnect_group.py
+++ b/ansible_collections/community/general/plugins/modules/oneview_logical_interconnect_group.py
@@ -29,8 +29,8 @@ options:
state:
description:
- Indicates the desired state for the Logical Interconnect Group resource.
- C(absent) will remove the resource from OneView, if it exists.
- C(present) will ensure data properties are compliant with OneView.
+ V(absent) will remove the resource from OneView, if it exists.
+ V(present) will ensure data properties are compliant with OneView.
type: str
choices: [absent, present]
default: present
diff --git a/ansible_collections/community/general/plugins/modules/oneview_logical_interconnect_group_info.py b/ansible_collections/community/general/plugins/modules/oneview_logical_interconnect_group_info.py
index 0111bf2c1..6f6a908f2 100644
--- a/ansible_collections/community/general/plugins/modules/oneview_logical_interconnect_group_info.py
+++ b/ansible_collections/community/general/plugins/modules/oneview_logical_interconnect_group_info.py
@@ -14,8 +14,6 @@ module: oneview_logical_interconnect_group_info
short_description: Retrieve information about one or more of the OneView Logical Interconnect Groups
description:
- Retrieve information about one or more of the Logical Interconnect Groups from OneView
- - This module was called C(oneview_logical_interconnect_group_facts) before Ansible 2.9, returning C(ansible_facts).
- Note that the M(community.general.oneview_logical_interconnect_group_info) module no longer returns C(ansible_facts)!
requirements:
- hpOneView >= 2.0.1
author:
diff --git a/ansible_collections/community/general/plugins/modules/oneview_network_set.py b/ansible_collections/community/general/plugins/modules/oneview_network_set.py
index a6a62a05c..0efd417d6 100644
--- a/ansible_collections/community/general/plugins/modules/oneview_network_set.py
+++ b/ansible_collections/community/general/plugins/modules/oneview_network_set.py
@@ -28,8 +28,8 @@ options:
state:
description:
- Indicates the desired state for the Network Set resource.
- - C(present) will ensure data properties are compliant with OneView.
- - C(absent) will remove the resource from OneView, if it exists.
+ - V(present) will ensure data properties are compliant with OneView.
+ - V(absent) will remove the resource from OneView, if it exists.
type: str
default: present
choices: ['present', 'absent']
diff --git a/ansible_collections/community/general/plugins/modules/oneview_network_set_info.py b/ansible_collections/community/general/plugins/modules/oneview_network_set_info.py
index d1a1f2913..cef53d8fc 100644
--- a/ansible_collections/community/general/plugins/modules/oneview_network_set_info.py
+++ b/ansible_collections/community/general/plugins/modules/oneview_network_set_info.py
@@ -13,8 +13,6 @@ module: oneview_network_set_info
short_description: Retrieve information about the OneView Network Sets
description:
- Retrieve information about the Network Sets from OneView.
- - This module was called C(oneview_network_set_facts) before Ansible 2.9, returning C(ansible_facts).
- Note that the M(community.general.oneview_network_set_info) module no longer returns C(ansible_facts)!
requirements:
- hpOneView >= 2.0.1
author:
@@ -34,8 +32,8 @@ options:
options:
description:
- "List with options to gather information about Network Set.
- Option allowed: C(withoutEthernet).
- The option C(withoutEthernet) retrieves the list of network_sets excluding Ethernet networks."
+ Option allowed: V(withoutEthernet).
+ The option V(withoutEthernet) retrieves the list of network_sets excluding Ethernet networks."
type: list
elements: str
diff --git a/ansible_collections/community/general/plugins/modules/oneview_san_manager.py b/ansible_collections/community/general/plugins/modules/oneview_san_manager.py
index 65a016b1c..15282aec2 100644
--- a/ansible_collections/community/general/plugins/modules/oneview_san_manager.py
+++ b/ansible_collections/community/general/plugins/modules/oneview_san_manager.py
@@ -28,9 +28,9 @@ options:
state:
description:
- Indicates the desired state for the Uplink Set resource.
- - C(present) ensures data properties are compliant with OneView.
- - C(absent) removes the resource from OneView, if it exists.
- - C(connection_information_set) updates the connection information for the SAN Manager. This operation is non-idempotent.
+ - V(present) ensures data properties are compliant with OneView.
+ - V(absent) removes the resource from OneView, if it exists.
+ - V(connection_information_set) updates the connection information for the SAN Manager. This operation is non-idempotent.
type: str
default: present
choices: [present, absent, connection_information_set]
diff --git a/ansible_collections/community/general/plugins/modules/oneview_san_manager_info.py b/ansible_collections/community/general/plugins/modules/oneview_san_manager_info.py
index 9b00a6bb5..f994280ca 100644
--- a/ansible_collections/community/general/plugins/modules/oneview_san_manager_info.py
+++ b/ansible_collections/community/general/plugins/modules/oneview_san_manager_info.py
@@ -13,8 +13,6 @@ module: oneview_san_manager_info
short_description: Retrieve information about one or more of the OneView SAN Managers
description:
- Retrieve information about one or more of the SAN Managers from OneView
- - This module was called C(oneview_san_manager_facts) before Ansible 2.9, returning C(ansible_facts).
- Note that the M(community.general.oneview_san_manager_info) module no longer returns C(ansible_facts)!
requirements:
- hpOneView >= 2.0.1
author:
@@ -34,10 +32,10 @@ options:
description:
- List of params to delimit, filter and sort the list of resources.
- "params allowed:
- - C(start): The first item to return, using 0-based indexing.
- - C(count): The number of resources to return.
- - C(query): A general query string to narrow the list of resources returned.
- - C(sort): The sort order of the returned data set."
+ - V(start): The first item to return, using 0-based indexing.
+ - V(count): The number of resources to return.
+ - V(query): A general query string to narrow the list of resources returned.
+ - V(sort): The sort order of the returned data set."
type: dict
extends_documentation_fragment:
- community.general.oneview
diff --git a/ansible_collections/community/general/plugins/modules/open_iscsi.py b/ansible_collections/community/general/plugins/modules/open_iscsi.py
index af08d1c54..163042cc4 100644
--- a/ansible_collections/community/general/plugins/modules/open_iscsi.py
+++ b/ansible_collections/community/general/plugins/modules/open_iscsi.py
@@ -85,7 +85,7 @@ options:
- Whether the list of target nodes on the portal should be
(re)discovered and added to the persistent iSCSI database.
- Keep in mind that C(iscsiadm) discovery resets configuration, like C(node.startup)
- to manual, hence combined with I(auto_node_startup=true) will always return
+ to manual, hence combined with O(auto_node_startup=true) will always return
a changed state.
type: bool
default: false
@@ -97,7 +97,7 @@ options:
rescan:
description:
- Rescan an established session for discovering new targets.
- - When I(target) is omitted, will rescan all sessions.
+ - When O(target) is omitted, will rescan all sessions.
type: bool
default: false
version_added: 4.1.0
diff --git a/ansible_collections/community/general/plugins/modules/openbsd_pkg.py b/ansible_collections/community/general/plugins/modules/openbsd_pkg.py
index 2baea828a..c83113611 100644
--- a/ansible_collections/community/general/plugins/modules/openbsd_pkg.py
+++ b/ansible_collections/community/general/plugins/modules/openbsd_pkg.py
@@ -34,9 +34,9 @@ options:
elements: str
state:
description:
- - C(present) will make sure the package is installed.
- C(latest) will make sure the latest version of the package is installed.
- C(absent) will make sure the specified package is not installed.
+ - V(present) will make sure the package is installed.
+ - V(latest) will make sure the latest version of the package is installed.
+ - V(absent) will make sure the specified package is not installed.
choices: [ absent, latest, present, installed, removed ]
default: present
type: str
@@ -46,19 +46,19 @@ options:
a binary. Requires that the port source tree is already installed.
Automatically builds and installs the 'sqlports' package, if it is
not already installed.
- - Mutually exclusive with I(snapshot).
+ - Mutually exclusive with O(snapshot).
type: bool
default: false
snapshot:
description:
- Force C(%c) and C(%m) to expand to C(snapshots), even on a release kernel.
- - Mutually exclusive with I(build).
+ - Mutually exclusive with O(build).
type: bool
default: false
version_added: 1.3.0
ports_dir:
description:
- - When used in combination with the C(build) option, allows overriding
+ - When used in combination with the O(build) option, allows overriding
the default ports source directory.
default: /usr/ports
type: path
@@ -77,7 +77,7 @@ options:
default: false
notes:
- When used with a C(loop:) each package will be processed individually,
- it is much more efficient to pass the list directly to the I(name) option.
+ it is much more efficient to pass the list directly to the O(name) option.
'''
EXAMPLES = '''
@@ -169,7 +169,11 @@ def get_package_state(names, pkg_spec, module):
rc, stdout, stderr = execute_command(command, module)
if stderr:
- module.fail_json(msg="failed in get_package_state(): " + stderr)
+ match = re.search(r"^Can't find inst:%s$" % re.escape(name), stderr)
+ if match:
+ pkg_spec[name]['installed_state'] = False
+ else:
+ module.fail_json(msg="failed in get_package_state(): " + stderr)
if stdout:
# If the requested package name is just a stem, like "python", we may
diff --git a/ansible_collections/community/general/plugins/modules/openwrt_init.py b/ansible_collections/community/general/plugins/modules/openwrt_init.py
index a0e156b33..46fdea5e2 100644
--- a/ansible_collections/community/general/plugins/modules/openwrt_init.py
+++ b/ansible_collections/community/general/plugins/modules/openwrt_init.py
@@ -32,8 +32,9 @@ options:
state:
type: str
description:
- - C(started)/C(stopped) are idempotent actions that will not run commands unless necessary.
- C(restarted) will always bounce the service. C(reloaded) will always reload.
+ - V(started)/V(stopped) are idempotent actions that will not run commands unless necessary.
+ - V(restarted) will always bounce the service.
+ - V(reloaded) will always reload.
choices: [ 'started', 'stopped', 'restarted', 'reloaded' ]
enabled:
description:
@@ -43,7 +44,7 @@ options:
type: str
description:
- If the service does not respond to the 'running' command, name a
- substring to look for as would be found in the output of the I(ps)
+ substring to look for as would be found in the output of the C(ps)
command as a stand-in for a 'running' result. If the string is found,
the service will be assumed to be running.
notes:
diff --git a/ansible_collections/community/general/plugins/modules/opkg.py b/ansible_collections/community/general/plugins/modules/opkg.py
index d2ac314d0..757c88c5d 100644
--- a/ansible_collections/community/general/plugins/modules/opkg.py
+++ b/ansible_collections/community/general/plugins/modules/opkg.py
@@ -46,6 +46,8 @@ options:
force:
description:
- The C(opkg --force) parameter used.
+ - Passing V("") as value and not passing any value at all have both
+ the same effect of B(not) using any C(--force-) parameter.
choices:
- ""
- "depends"
@@ -58,13 +60,17 @@ options:
- "remove"
- "checksum"
- "removal-of-dependent-packages"
- default: ""
type: str
update_cache:
description:
- Update the package DB first.
default: false
type: bool
+ executable:
+ description:
+ - The executable location for C(opkg).
+ type: path
+ version_added: 7.2.0
requirements:
- opkg
- python
@@ -105,6 +111,7 @@ EXAMPLES = '''
force: overwrite
'''
+import os
from ansible_collections.community.general.plugins.module_utils.cmd_runner import CmdRunner, cmd_runner_fmt
from ansible_collections.community.general.plugins.module_utils.module_helper import StateModuleHelper
@@ -114,9 +121,10 @@ class Opkg(StateModuleHelper):
argument_spec=dict(
name=dict(aliases=["pkg"], required=True, type="list", elements="str"),
state=dict(default="present", choices=["present", "installed", "absent", "removed"]),
- force=dict(default="", choices=["", "depends", "maintainer", "reinstall", "overwrite", "downgrade", "space", "postinstall", "remove",
- "checksum", "removal-of-dependent-packages"]),
+ force=dict(choices=["", "depends", "maintainer", "reinstall", "overwrite", "downgrade", "space",
+ "postinstall", "remove", "checksum", "removal-of-dependent-packages"]),
update_cache=dict(default=False, type='bool'),
+ executable=dict(type="path"),
),
)
@@ -137,15 +145,18 @@ class Opkg(StateModuleHelper):
value = None
return cmd_runner_fmt.as_optval("--force-")(value, ctx_ignore_none=True)
+ dir, cmd = os.path.split(self.vars.executable) if self.vars.executable else (None, "opkg")
+
self.runner = CmdRunner(
self.module,
- command="opkg",
+ command=cmd,
arg_formats=dict(
package=cmd_runner_fmt.as_list(),
state=cmd_runner_fmt.as_map(state_map),
force=cmd_runner_fmt.as_func(_force),
- update_cache=cmd_runner_fmt.as_bool("update")
+ update_cache=cmd_runner_fmt.as_bool("update"),
),
+ path_prefix=dir,
)
if self.vars.update_cache:
diff --git a/ansible_collections/community/general/plugins/modules/osx_defaults.py b/ansible_collections/community/general/plugins/modules/osx_defaults.py
index 161584373..336e95332 100644
--- a/ansible_collections/community/general/plugins/modules/osx_defaults.py
+++ b/ansible_collections/community/general/plugins/modules/osx_defaults.py
@@ -38,7 +38,7 @@ options:
host:
description:
- The host on which the preference should apply.
- - The special value C(currentHost) corresponds to the C(-currentHost) switch of the defaults commandline tool.
+ - The special value V(currentHost) corresponds to the C(-currentHost) switch of the defaults commandline tool.
type: str
key:
description:
@@ -58,13 +58,12 @@ options:
value:
description:
- The value to write.
- - Only required when I(state=present).
+ - Only required when O(state=present).
type: raw
state:
description:
- The state of the user defaults.
- - If set to C(list) will query the given parameter specified by C(key). Returns 'null' is nothing found or mis-spelled.
- - C(list) added in version 2.8.
+ - If set to V(list) will query the given parameter specified by O(key). Returns V(null) is nothing found or mis-spelled.
type: str
choices: [ absent, list, present ]
default: present
diff --git a/ansible_collections/community/general/plugins/modules/ovh_ip_failover.py b/ansible_collections/community/general/plugins/modules/ovh_ip_failover.py
index cd3639a4c..58d340e3e 100644
--- a/ansible_collections/community/general/plugins/modules/ovh_ip_failover.py
+++ b/ansible_collections/community/general/plugins/modules/ovh_ip_failover.py
@@ -19,7 +19,7 @@ description:
author: "Pascal HERAUD (@pascalheraud)"
notes:
- Uses the python OVH Api U(https://github.com/ovh/python-ovh).
- You have to create an application (a key and secret) with a consummer
+ You have to create an application (a key and secret) with a consumer
key as described into U(https://docs.ovh.com/gb/en/customer/first-steps-with-ovh-api/)
requirements:
- ovh >= 0.4.8
diff --git a/ansible_collections/community/general/plugins/modules/ovh_monthly_billing.py b/ansible_collections/community/general/plugins/modules/ovh_monthly_billing.py
index 43d64e618..c2f503e3a 100644
--- a/ansible_collections/community/general/plugins/modules/ovh_monthly_billing.py
+++ b/ansible_collections/community/general/plugins/modules/ovh_monthly_billing.py
@@ -16,7 +16,7 @@ author: Francois Lallart (@fraff)
version_added: '0.2.0'
short_description: Manage OVH monthly billing
description:
- - Enable monthly billing on OVH cloud intances (be aware OVH does not allow to disable it).
+ - Enable monthly billing on OVH cloud instances (be aware OVH does not allow to disable it).
requirements: [ "ovh" ]
extends_documentation_fragment:
- community.general.attributes
diff --git a/ansible_collections/community/general/plugins/modules/pacemaker_cluster.py b/ansible_collections/community/general/plugins/modules/pacemaker_cluster.py
index 47b827908..60d8656ac 100644
--- a/ansible_collections/community/general/plugins/modules/pacemaker_cluster.py
+++ b/ansible_collections/community/general/plugins/modules/pacemaker_cluster.py
@@ -188,6 +188,8 @@ def main():
if cluster_state == state:
module.exit_json(changed=changed, out=cluster_state)
else:
+ if module.check_mode:
+ module.exit_json(changed=True)
set_cluster(module, state, timeout, force)
cluster_state = get_cluster_status(module)
if cluster_state == state:
@@ -201,12 +203,16 @@ def main():
if node_state[1].strip().lower() == state:
module.exit_json(changed=changed, out=cluster_state)
else:
+ if module.check_mode:
+ module.exit_json(changed=True)
# Set cluster status if needed
set_cluster(module, state, timeout, force)
cluster_state = get_node_status(module, node)
module.exit_json(changed=True, out=cluster_state)
if state in ['restart']:
+ if module.check_mode:
+ module.exit_json(changed=True)
set_cluster(module, 'offline', timeout, force)
cluster_state = get_cluster_status(module)
if cluster_state == 'offline':
@@ -220,6 +226,8 @@ def main():
module.fail_json(msg="Failed during the restart of the cluster, the cluster can't be stopped")
if state in ['cleanup']:
+ if module.check_mode:
+ module.exit_json(changed=True)
clean_cluster(module, timeout)
cluster_state = get_cluster_status(module)
module.exit_json(changed=True,
diff --git a/ansible_collections/community/general/plugins/modules/packet_device.py b/ansible_collections/community/general/plugins/modules/packet_device.py
index d220c5f8f..519a7031e 100644
--- a/ansible_collections/community/general/plugins/modules/packet_device.py
+++ b/ansible_collections/community/general/plugins/modules/packet_device.py
@@ -40,7 +40,7 @@ attributes:
options:
auth_token:
description:
- - Packet API token. You can also supply it in env var C(PACKET_API_TOKEN).
+ - Packet API token. You can also supply it in environment variable E(PACKET_API_TOKEN).
type: str
count:
@@ -82,8 +82,8 @@ options:
hostnames:
description:
- A hostname of a device, or a list of hostnames.
- - If given string or one-item list, you can use the C("%d") Python string format to expand numbers from I(count).
- - If only one hostname, it might be expanded to list if I(count)>1.
+ - If given string or one-item list, you can use the C("%d") Python string format to expand numbers from O(count).
+ - If only one hostname, it might be expanded to list if O(count)>1.
aliases: [name]
type: list
elements: str
@@ -114,8 +114,8 @@ options:
state:
description:
- Desired state of the device.
- - If set to C(present) (the default), the module call will return immediately after the device-creating HTTP request successfully returns.
- - If set to C(active), the module call will block until all the specified devices are in state active due to the Packet API, or until I(wait_timeout).
+ - If set to V(present) (the default), the module call will return immediately after the device-creating HTTP request successfully returns.
+ - If set to V(active), the module call will block until all the specified devices are in state active due to the Packet API, or until O(wait_timeout).
choices: [present, absent, active, inactive, rebooted]
default: present
type: str
@@ -135,8 +135,8 @@ options:
wait_timeout:
description:
- - How long (seconds) to wait either for automatic IP address assignment, or for the device to reach the C(active) I(state).
- - If I(wait_for_public_IPv) is set and I(state) is C(active), the module will wait for both events consequently, applying the timeout twice.
+ - How long (seconds) to wait either for automatic IP address assignment, or for the device to reach the V(active) state.
+ - If O(wait_for_public_IPv) is set and O(state=active), the module will wait for both events consequently, applying the timeout twice.
default: 900
type: int
@@ -161,7 +161,7 @@ requirements:
'''
EXAMPLES = '''
-# All the examples assume that you have your Packet API token in env var PACKET_API_TOKEN.
+# All the examples assume that you have your Packet API token in environment variable PACKET_API_TOKEN.
# You can also pass it to the auth_token parameter of the module instead.
# Creating devices
diff --git a/ansible_collections/community/general/plugins/modules/packet_ip_subnet.py b/ansible_collections/community/general/plugins/modules/packet_ip_subnet.py
index afeb7ea04..530cfe3a7 100644
--- a/ansible_collections/community/general/plugins/modules/packet_ip_subnet.py
+++ b/ansible_collections/community/general/plugins/modules/packet_ip_subnet.py
@@ -40,7 +40,7 @@ attributes:
options:
auth_token:
description:
- - Packet API token. You can also supply it in env var C(PACKET_API_TOKEN).
+ - Packet API token. You can also supply it in environment variable E(PACKET_API_TOKEN).
type: str
hostname:
@@ -77,16 +77,15 @@ options:
state:
description:
- Desired state of the IP subnet on the specified device.
- - With state == C(present), you must specify either hostname or device_id. Subnet with given CIDR will then be assigned to the specified device.
- - With state == C(absent), you can specify either hostname or device_id. The subnet will be removed from specified devices.
- - If you leave both hostname and device_id empty, the subnet will be removed from any device it's assigned to.
+ - With O(state=present), you must specify either O(hostname) or O(device_id). Subnet with given CIDR will then be assigned to the specified device.
+ - With O(state=absent), you can specify either O(hostname) or O(device_id). The subnet will be removed from specified devices.
+ - If you leave both O(hostname) and O(device_id) empty, the subnet will be removed from any device it's assigned to.
choices: ['present', 'absent']
default: 'present'
type: str
requirements:
- "packet-python >= 1.35"
- - "python >= 2.6"
'''
EXAMPLES = '''
diff --git a/ansible_collections/community/general/plugins/modules/packet_project.py b/ansible_collections/community/general/plugins/modules/packet_project.py
index da4a2bb89..d8c991dba 100644
--- a/ansible_collections/community/general/plugins/modules/packet_project.py
+++ b/ansible_collections/community/general/plugins/modules/packet_project.py
@@ -51,7 +51,7 @@ options:
auth_token:
description:
- - Packet api token. You can also supply it in env var C(PACKET_API_TOKEN).
+ - Packet api token. You can also supply it in environment variable E(PACKET_API_TOKEN).
type: str
name:
@@ -76,7 +76,6 @@ options:
type: str
requirements:
- - "python >= 2.6"
- "packet-python >= 1.40"
'''
diff --git a/ansible_collections/community/general/plugins/modules/packet_sshkey.py b/ansible_collections/community/general/plugins/modules/packet_sshkey.py
index 97f55ba23..6519735dc 100644
--- a/ansible_collections/community/general/plugins/modules/packet_sshkey.py
+++ b/ansible_collections/community/general/plugins/modules/packet_sshkey.py
@@ -32,7 +32,7 @@ options:
type: str
auth_token:
description:
- - Packet API token. You can also supply it in env var C(PACKET_API_TOKEN).
+ - Packet API token. You can also supply it in environment variable E(PACKET_API_TOKEN).
type: str
label:
description:
@@ -57,7 +57,6 @@ options:
type: path
requirements:
- - "python >= 2.6"
- packet-python
'''
diff --git a/ansible_collections/community/general/plugins/modules/packet_volume.py b/ansible_collections/community/general/plugins/modules/packet_volume.py
index 910d64b55..659e8d8aa 100644
--- a/ansible_collections/community/general/plugins/modules/packet_volume.py
+++ b/ansible_collections/community/general/plugins/modules/packet_volume.py
@@ -50,7 +50,7 @@ options:
auth_token:
description:
- - Packet API token. You can also supply it in env var C(PACKET_API_TOKEN).
+ - Packet API token. You can also supply it in environment variable E(PACKET_API_TOKEN).
type: str
name:
@@ -122,7 +122,6 @@ options:
type: str
requirements:
- - "python >= 2.6"
- "packet-python >= 1.35"
'''
diff --git a/ansible_collections/community/general/plugins/modules/packet_volume_attachment.py b/ansible_collections/community/general/plugins/modules/packet_volume_attachment.py
index 7f6c68e05..a46fef55c 100644
--- a/ansible_collections/community/general/plugins/modules/packet_volume_attachment.py
+++ b/ansible_collections/community/general/plugins/modules/packet_volume_attachment.py
@@ -48,7 +48,7 @@ options:
auth_token:
description:
- - Packet API token. You can also supply it in env var C(PACKET_API_TOKEN).
+ - Packet API token. You can also supply it in environment variable E(PACKET_API_TOKEN).
type: str
project_id:
@@ -73,7 +73,6 @@ options:
type: str
requirements:
- - "python >= 2.6"
- "packet-python >= 1.35"
'''
diff --git a/ansible_collections/community/general/plugins/modules/pacman.py b/ansible_collections/community/general/plugins/modules/pacman.py
index 66f58155d..7f67b9103 100644
--- a/ansible_collections/community/general/plugins/modules/pacman.py
+++ b/ansible_collections/community/general/plugins/modules/pacman.py
@@ -34,17 +34,17 @@ options:
name:
description:
- Name or list of names of the package(s) or file(s) to install, upgrade, or remove.
- Can't be used in combination with C(upgrade).
+ Cannot be used in combination with O(upgrade).
aliases: [ package, pkg ]
type: list
elements: str
state:
description:
- - Whether to install (C(present) or C(installed), C(latest)), or remove (C(absent) or C(removed)) a package.
- - C(present) and C(installed) will simply ensure that a desired package is installed.
- - C(latest) will update the specified package if it is not of the latest available version.
- - C(absent) and C(removed) will remove the specified package.
+ - Whether to install (V(present) or V(installed), V(latest)), or remove (V(absent) or V(removed)) a package.
+ - V(present) and V(installed) will simply ensure that a desired package is installed.
+ - V(latest) will update the specified package if it is not of the latest available version.
+ - V(absent) and V(removed) will remove the specified package.
default: present
choices: [ absent, installed, latest, present, removed ]
type: str
@@ -52,9 +52,9 @@ options:
force:
description:
- When removing packages, forcefully remove them, without any checks.
- Same as I(extra_args="--nodeps --nodeps").
- When combined with I(update_cache), force a refresh of all package databases.
- Same as I(update_cache_extra_args="--refresh --refresh").
+ Same as O(extra_args="--nodeps --nodeps").
+ - When combined with O(update_cache), force a refresh of all package databases.
+ Same as O(update_cache_extra_args="--refresh --refresh").
default: false
type: bool
@@ -79,7 +79,7 @@ options:
extra_args:
description:
- - Additional option to pass to pacman when enforcing C(state).
+ - Additional option to pass to pacman when enforcing O(state).
default: ''
type: str
@@ -87,28 +87,28 @@ options:
description:
- Whether or not to refresh the master package lists.
- This can be run as part of a package installation or as a separate step.
- - If not specified, it defaults to C(false).
+ - If not specified, it defaults to V(false).
- Please note that this option only had an influence on the module's C(changed) state
- if I(name) and I(upgrade) are not specified before community.general 5.0.0.
+ if O(name) and O(upgrade) are not specified before community.general 5.0.0.
See the examples for how to keep the old behavior.
type: bool
update_cache_extra_args:
description:
- - Additional option to pass to pacman when enforcing C(update_cache).
+ - Additional option to pass to pacman when enforcing O(update_cache).
default: ''
type: str
upgrade:
description:
- Whether or not to upgrade the whole system.
- Can't be used in combination with C(name).
- - If not specified, it defaults to C(false).
+ Cannot be used in combination with O(name).
+ - If not specified, it defaults to V(false).
type: bool
upgrade_extra_args:
description:
- - Additional option to pass to pacman when enforcing C(upgrade).
+ - Additional option to pass to pacman when enforcing O(upgrade).
default: ''
type: str
@@ -121,8 +121,8 @@ options:
reason_for:
description:
- - Set the install reason for C(all) packages or only for C(new) packages.
- - In case of I(state=latest) already installed packages which will be updated to a newer version are not counted as C(new).
+ - Set the install reason for V(all) packages or only for V(new) packages.
+ - In case of O(state=latest) already installed packages which will be updated to a newer version are not counted as V(new).
default: new
choices: [ all, new ]
type: str
@@ -130,20 +130,23 @@ options:
notes:
- When used with a C(loop:) each package will be processed individually,
- it is much more efficient to pass the list directly to the I(name) option.
- - To use an AUR helper (I(executable) option), a few extra setup steps might be required beforehand.
+ it is much more efficient to pass the list directly to the O(name) option.
+ - To use an AUR helper (O(executable) option), a few extra setup steps might be required beforehand.
For example, a dedicated build user with permissions to install packages could be necessary.
+ - >
+ In the tests, while using C(yay) as the O(executable) option, the module failed to install AUR packages
+ with the error: C(error: target not found: <pkg>).
"""
RETURN = """
packages:
description:
- A list of packages that have been changed.
- - Before community.general 4.5.0 this was only returned when I(upgrade=true).
+ - Before community.general 4.5.0 this was only returned when O(upgrade=true).
In community.general 4.5.0, it was sometimes omitted when the package list is empty,
- but since community.general 4.6.0 it is always returned when I(name) is specified or
- I(upgrade=true).
- returned: success and I(name) is specified or I(upgrade=true)
+ but since community.general 4.6.0 it is always returned when O(name) is specified or
+ O(upgrade=true).
+ returned: success and O(name) is specified or O(upgrade=true)
type: list
elements: str
sample: [ package, other-package ]
@@ -151,8 +154,8 @@ packages:
cache_updated:
description:
- The changed status of C(pacman -Sy).
- - Useful when I(name) or I(upgrade=true) are specified next to I(update_cache=true).
- returned: success, when I(update_cache=true)
+ - Useful when O(name) or O(upgrade=true) are specified next to O(update_cache=true).
+ returned: success, when O(update_cache=true)
type: bool
sample: false
version_added: 4.6.0
@@ -263,6 +266,7 @@ EXAMPLES = """
reason_for: all
"""
+import re
import shlex
from ansible.module_utils.basic import AnsibleModule
from collections import defaultdict, namedtuple
@@ -418,7 +422,7 @@ class Pacman(object):
for p in name_ver:
# With Pacman v6.0.1 - libalpm v13.0.1, --upgrade outputs "loading packages..." on stdout. strip that.
# When installing from URLs, pacman can also output a 'nothing to do' message. strip that too.
- if "loading packages" in p or "there is nothing to do" in p:
+ if "loading packages" in p or "there is nothing to do" in p or 'Avoid running' in p:
continue
name, version = p.split()
if name in self.inventory["installed_pkgs"]:
@@ -706,11 +710,12 @@ class Pacman(object):
installed_pkgs = {}
dummy, stdout, dummy = self.m.run_command([self.pacman_path, "--query"], check_rc=True)
# Format of a line: "pacman 6.0.1-2"
+ query_re = re.compile(r'^\s*(?P<pkg>\S+)\s+(?P<ver>\S+)\s*$')
for l in stdout.splitlines():
- l = l.strip()
- if not l:
+ query_match = query_re.match(l)
+ if not query_match:
continue
- pkg, ver = l.split()
+ pkg, ver = query_match.groups()
installed_pkgs[pkg] = ver
installed_groups = defaultdict(set)
@@ -721,11 +726,12 @@ class Pacman(object):
# base-devel file
# base-devel findutils
# ...
+ query_groups_re = re.compile(r'^\s*(?P<group>\S+)\s+(?P<pkg>\S+)\s*$')
for l in stdout.splitlines():
- l = l.strip()
- if not l:
+ query_groups_match = query_groups_re.match(l)
+ if not query_groups_match:
continue
- group, pkgname = l.split()
+ group, pkgname = query_groups_match.groups()
installed_groups[group].add(pkgname)
available_pkgs = {}
@@ -747,11 +753,12 @@ class Pacman(object):
# vim-plugins vim-airline-themes
# vim-plugins vim-ale
# ...
+ sync_groups_re = re.compile(r'^\s*(?P<group>\S+)\s+(?P<pkg>\S+)\s*$')
for l in stdout.splitlines():
- l = l.strip()
- if not l:
+ sync_groups_match = sync_groups_re.match(l)
+ if not sync_groups_match:
continue
- group, pkg = l.split()
+ group, pkg = sync_groups_match.groups()
available_groups[group].add(pkg)
upgradable_pkgs = {}
@@ -759,9 +766,14 @@ class Pacman(object):
[self.pacman_path, "--query", "--upgrades"], check_rc=False
)
+ stdout = stdout.splitlines()
+ if stdout and "Avoid running" in stdout[0]:
+ stdout = stdout[1:]
+ stdout = "\n".join(stdout)
+
# non-zero exit with nothing in stdout -> nothing to upgrade, all good
# stderr can have warnings, so not checked here
- if rc == 1 and stdout == "":
+ if rc == 1 and not stdout:
pass # nothing to upgrade
elif rc == 0:
# Format of lines:
@@ -771,7 +783,7 @@ class Pacman(object):
l = l.strip()
if not l:
continue
- if "[ignored]" in l:
+ if "[ignored]" in l or "Avoid running" in l:
continue
s = l.split()
if len(s) != 4:
diff --git a/ansible_collections/community/general/plugins/modules/pacman_key.py b/ansible_collections/community/general/plugins/modules/pacman_key.py
index 4d4c4afac..4b7b2639e 100644
--- a/ansible_collections/community/general/plugins/modules/pacman_key.py
+++ b/ansible_collections/community/general/plugins/modules/pacman_key.py
@@ -19,10 +19,10 @@ description:
- Add or remove gpg keys from the pacman keyring.
notes:
- Use full-length key ID (40 characters).
- - Keys will be verified when using I(data), I(file), or I(url) unless I(verify) is overridden.
+ - Keys will be verified when using O(data), O(file), or O(url) unless O(verify) is overridden.
- Keys will be locally signed after being imported into the keyring.
- - If the key ID exists in the keyring, the key will not be added unless I(force_update) is specified.
- - I(data), I(file), I(url), and I(keyserver) are mutually exclusive.
+ - If the key ID exists in the keyring, the key will not be added unless O(force_update) is specified.
+ - O(data), O(file), O(url), and O(keyserver) are mutually exclusive.
requirements:
- gpg
- pacman-key
@@ -73,7 +73,7 @@ options:
keyring:
description:
- The full path to the keyring folder on the remote server.
- - If not specified, module will use pacman's default (C(/etc/pacman.d/gnupg)).
+ - If not specified, module will use pacman's default (V(/etc/pacman.d/gnupg)).
- Useful if the remote system requires an alternative gnupg directory.
type: path
default: /etc/pacman.d/gnupg
@@ -88,11 +88,13 @@ options:
EXAMPLES = '''
- name: Import a key via local file
community.general.pacman_key:
+ id: 01234567890ABCDE01234567890ABCDE12345678
data: "{{ lookup('file', 'keyfile.asc') }}"
state: present
- name: Import a key via remote file
community.general.pacman_key:
+ id: 01234567890ABCDE01234567890ABCDE12345678
file: /tmp/keyfile.asc
state: present
diff --git a/ansible_collections/community/general/plugins/modules/pagerduty.py b/ansible_collections/community/general/plugins/modules/pagerduty.py
index bed3629be..596c4f4da 100644
--- a/ansible_collections/community/general/plugins/modules/pagerduty.py
+++ b/ansible_collections/community/general/plugins/modules/pagerduty.py
@@ -43,7 +43,7 @@ options:
user:
type: str
description:
- - PagerDuty user ID. Obsolete. Please, use I(token) for authorization.
+ - PagerDuty user ID. Obsolete. Please, use O(token) for authorization.
token:
type: str
description:
@@ -80,7 +80,7 @@ options:
default: Created by Ansible
validate_certs:
description:
- - If C(false), SSL certificates will not be validated. This should only be used
+ - If V(false), SSL certificates will not be validated. This should only be used
on personally controlled sites using self-signed certificates.
type: bool
default: true
diff --git a/ansible_collections/community/general/plugins/modules/pagerduty_alert.py b/ansible_collections/community/general/plugins/modules/pagerduty_alert.py
index 45bec92c6..3c0327e5a 100644
--- a/ansible_collections/community/general/plugins/modules/pagerduty_alert.py
+++ b/ansible_collections/community/general/plugins/modules/pagerduty_alert.py
@@ -16,6 +16,7 @@ description:
- This module will let you trigger, acknowledge or resolve a PagerDuty incident by sending events
author:
- "Amanpreet Singh (@ApsOps)"
+ - "Xiao Shen (@xshen1)"
requirements:
- PagerDuty API access
extends_documentation_fragment:
@@ -30,20 +31,25 @@ options:
type: str
description:
- PagerDuty unique subdomain. Obsolete. It is not used with PagerDuty REST v2 API.
+ api_key:
+ type: str
+ description:
+ - The pagerduty API key (readonly access), generated on the pagerduty site.
+ - Required if O(api_version=v1).
+ integration_key:
+ type: str
+ description:
+ - The GUID of one of your 'Generic API' services.
+ - This is the 'integration key' listed on a 'Integrations' tab of PagerDuty service.
service_id:
type: str
description:
- ID of PagerDuty service when incidents will be triggered, acknowledged or resolved.
- required: true
+ - Required if O(api_version=v1).
service_key:
type: str
description:
- - The GUID of one of your "Generic API" services. Obsolete. Please use I(integration_key).
- integration_key:
- type: str
- description:
- - The GUID of one of your "Generic API" services.
- - This is the "integration key" listed on a "Integrations" tab of PagerDuty service.
+ - The GUID of one of your 'Generic API' services. Obsolete. Please use O(integration_key).
state:
type: str
description:
@@ -53,40 +59,96 @@ options:
- 'triggered'
- 'acknowledged'
- 'resolved'
- api_key:
+ api_version:
type: str
description:
- - The pagerduty API key (readonly access), generated on the pagerduty site.
- required: true
+ - The API version we want to use to run the module.
+ - V1 is more limited with option we can provide to trigger incident.
+ - V2 has more variables for example, O(severity), O(source), O(custom_details), etc.
+ default: 'v1'
+ choices:
+ - 'v1'
+ - 'v2'
+ version_added: 7.4.0
+ client:
+ type: str
+ description:
+ - The name of the monitoring client that is triggering this event.
+ required: false
+ client_url:
+ type: str
+ description:
+ - The URL of the monitoring client that is triggering this event.
+ required: false
+ component:
+ type: str
+ description:
+ - Component of the source machine that is responsible for the event, for example C(mysql) or C(eth0).
+ required: false
+ version_added: 7.4.0
+ custom_details:
+ type: dict
+ description:
+ - Additional details about the event and affected system.
+ - A dictionary with custom keys and values.
+ required: false
+ version_added: 7.4.0
desc:
type: str
description:
- - For C(triggered) I(state) - Required. Short description of the problem that led to this trigger. This field (or a truncated version)
+ - For O(state=triggered) - Required. Short description of the problem that led to this trigger. This field (or a truncated version)
will be used when generating phone calls, SMS messages and alert emails. It will also appear on the incidents tables in the PagerDuty UI.
The maximum length is 1024 characters.
- - For C(acknowledged) or C(resolved) I(state) - Text that will appear in the incident's log associated with this event.
+ - For O(state=acknowledged) or O(state=resolved) - Text that will appear in the incident's log associated with this event.
required: false
default: Created via Ansible
+ incident_class:
+ type: str
+ description:
+ - The class/type of the event, for example C(ping failure) or C(cpu load).
+ required: false
+ version_added: 7.4.0
incident_key:
type: str
description:
- - Identifies the incident to which this I(state) should be applied.
- - For C(triggered) I(state) - If there's no open (i.e. unresolved) incident with this key, a new one will be created. If there's already an
- open incident with a matching key, this event will be appended to that incident's log. The event key provides an easy way to "de-dup"
- problem reports.
- - For C(acknowledged) or C(resolved) I(state) - This should be the incident_key you received back when the incident was first opened by a
+ - Identifies the incident to which this O(state) should be applied.
+ - For O(state=triggered) - If there's no open (i.e. unresolved) incident with this key, a new one will be created. If there's already an
+ open incident with a matching key, this event will be appended to that incident's log. The event key provides an easy way to 'de-dup'
+ problem reports. If no O(incident_key) is provided, then it will be generated by PagerDuty.
+ - For O(state=acknowledged) or O(state=resolved) - This should be the incident_key you received back when the incident was first opened by a
trigger event. Acknowledge events referencing resolved or nonexistent incidents will be discarded.
required: false
- client:
+ link_url:
type: str
description:
- - The name of the monitoring client that is triggering this event.
+ - Relevant link url to the alert. For example, the website or the job link.
required: false
- client_url:
+ version_added: 7.4.0
+ link_text:
type: str
description:
- - The URL of the monitoring client that is triggering this event.
+ - A short description of the link_url.
required: false
+ version_added: 7.4.0
+ source:
+ type: str
+ description:
+ - The unique location of the affected system, preferably a hostname or FQDN.
+ - Required in case of O(state=trigger) and O(api_version=v2).
+ required: false
+ version_added: 7.4.0
+ severity:
+ type: str
+ description:
+ - The perceived severity of the status the event is describing with respect to the affected system.
+ - Required in case of O(state=trigger) and O(api_version=v2).
+ default: 'critical'
+ choices:
+ - 'critical'
+ - 'warning'
+ - 'error'
+ - 'info'
+ version_added: 7.4.0
'''
EXAMPLES = '''
@@ -127,12 +189,50 @@ EXAMPLES = '''
state: resolved
incident_key: somekey
desc: "some text for incident's log"
+
+- name: Trigger an v2 incident with just the basic options
+ community.general.pagerduty_alert:
+ integration_key: xxx
+ api_version: v2
+ source: My Ansible Script
+ state: triggered
+ desc: problem that led to this trigger
+
+- name: Trigger an v2 incident with more options
+ community.general.pagerduty_alert:
+ integration_key: xxx
+ api_version: v2
+ source: My Ansible Script
+ state: triggered
+ desc: problem that led to this trigger
+ incident_key: somekey
+ client: Sample Monitoring Service
+ client_url: http://service.example.com
+ component: mysql
+ incident_class: ping failure
+ link_url: https://pagerduty.com
+ link_text: PagerDuty
+
+- name: Acknowledge an incident based on incident_key using v2
+ community.general.pagerduty_alert:
+ api_version: v2
+ integration_key: xxx
+ incident_key: somekey
+ state: acknowledged
+
+- name: Resolve an incident based on incident_key
+ community.general.pagerduty_alert:
+ api_version: v2
+ integration_key: xxx
+ incident_key: somekey
+ state: resolved
'''
import json
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.urls import fetch_url
from ansible.module_utils.six.moves.urllib.parse import urlparse, urlencode, urlunparse
+from datetime import datetime
def check(module, name, state, service_id, integration_key, api_key, incident_key=None, http_call=fetch_url):
@@ -175,8 +275,8 @@ def check(module, name, state, service_id, integration_key, api_key, incident_ke
return incidents[0], False
-def send_event(module, service_key, event_type, desc,
- incident_key=None, client=None, client_url=None):
+def send_event_v1(module, service_key, event_type, desc,
+ incident_key=None, client=None, client_url=None):
url = "https://events.pagerduty.com/generic/2010-04-15/create_event.json"
headers = {
"Content-type": "application/json"
@@ -200,61 +300,127 @@ def send_event(module, service_key, event_type, desc,
return json_out
+def send_event_v2(module, service_key, event_type, payload, link,
+ incident_key=None, client=None, client_url=None):
+ url = "https://events.pagerduty.com/v2/enqueue"
+ headers = {
+ "Content-type": "application/json"
+ }
+ data = {
+ "routing_key": service_key,
+ "event_action": event_type,
+ "payload": payload,
+ "client": client,
+ "client_url": client_url,
+ }
+ if link:
+ data["links"] = [link]
+ if incident_key:
+ data["dedup_key"] = incident_key
+ if event_type != "trigger":
+ data.pop("payload")
+ response, info = fetch_url(module, url, method="post",
+ headers=headers, data=json.dumps(data))
+ if info["status"] != 202:
+ module.fail_json(msg="failed to %s. Reason: %s" %
+ (event_type, info['msg']))
+ json_out = json.loads(response.read())
+ return json_out, True
+
+
def main():
module = AnsibleModule(
argument_spec=dict(
name=dict(required=False),
- service_id=dict(required=True),
- service_key=dict(required=False, no_log=True),
+ api_key=dict(required=False, no_log=True),
integration_key=dict(required=False, no_log=True),
- api_key=dict(required=True, no_log=True),
- state=dict(required=True,
- choices=['triggered', 'acknowledged', 'resolved']),
- client=dict(required=False, default=None),
- client_url=dict(required=False, default=None),
+ service_id=dict(required=False),
+ service_key=dict(required=False, no_log=True),
+ state=dict(
+ required=True, choices=['triggered', 'acknowledged', 'resolved']
+ ),
+ api_version=dict(type='str', default='v1', choices=['v1', 'v2']),
+ client=dict(required=False),
+ client_url=dict(required=False),
+ component=dict(required=False),
+ custom_details=dict(required=False, type='dict'),
desc=dict(required=False, default='Created via Ansible'),
- incident_key=dict(required=False, default=None, no_log=False)
+ incident_class=dict(required=False),
+ incident_key=dict(required=False, no_log=False),
+ link_url=dict(required=False),
+ link_text=dict(required=False),
+ source=dict(required=False),
+ severity=dict(
+ default='critical', choices=['critical', 'warning', 'error', 'info']
+ ),
),
- supports_check_mode=True
+ required_if=[
+ ('api_version', 'v1', ['service_id', 'api_key']),
+ ('state', 'acknowledged', ['incident_key']),
+ ('state', 'resolved', ['incident_key']),
+ ],
+ required_one_of=[('service_key', 'integration_key')],
+ supports_check_mode=True,
)
name = module.params['name']
- service_id = module.params['service_id']
- integration_key = module.params['integration_key']
- service_key = module.params['service_key']
- api_key = module.params['api_key']
- state = module.params['state']
- client = module.params['client']
- client_url = module.params['client_url']
- desc = module.params['desc']
- incident_key = module.params['incident_key']
-
+ service_id = module.params.get('service_id')
+ integration_key = module.params.get('integration_key')
+ service_key = module.params.get('service_key')
+ api_key = module.params.get('api_key')
+ state = module.params.get('state')
+ client = module.params.get('client')
+ client_url = module.params.get('client_url')
+ desc = module.params.get('desc')
+ incident_key = module.params.get('incident_key')
+ payload = {
+ 'summary': desc,
+ 'source': module.params.get('source'),
+ 'timestamp': datetime.now().isoformat(),
+ 'severity': module.params.get('severity'),
+ 'component': module.params.get('component'),
+ 'class': module.params.get('incident_class'),
+ 'custom_details': module.params.get('custom_details'),
+ }
+ link = {}
+ if module.params.get('link_url'):
+ link['href'] = module.params.get('link_url')
+ if module.params.get('link_text'):
+ link['text'] = module.params.get('link_text')
if integration_key is None:
- if service_key is not None:
- integration_key = service_key
- module.warn('"service_key" is obsolete parameter and will be removed.'
- ' Please, use "integration_key" instead')
- else:
- module.fail_json(msg="'integration_key' is required parameter")
+ integration_key = service_key
+ module.warn(
+ '"service_key" is obsolete parameter and will be removed.'
+ ' Please, use "integration_key" instead'
+ )
state_event_dict = {
'triggered': 'trigger',
'acknowledged': 'acknowledge',
- 'resolved': 'resolve'
+ 'resolved': 'resolve',
}
event_type = state_event_dict[state]
-
- if event_type != 'trigger' and incident_key is None:
- module.fail_json(msg="incident_key is required for "
- "acknowledge or resolve events")
-
- out, changed = check(module, name, state, service_id,
- integration_key, api_key, incident_key)
-
- if not module.check_mode and changed is True:
- out = send_event(module, integration_key, event_type, desc,
- incident_key, client, client_url)
+ if module.params.get('api_version') == 'v1':
+ out, changed = check(module, name, state, service_id,
+ integration_key, api_key, incident_key)
+ if not module.check_mode and changed is True:
+ out = send_event_v1(module, integration_key, event_type, desc,
+ incident_key, client, client_url)
+ else:
+ changed = True
+ if event_type == 'trigger' and not payload['source']:
+ module.fail_json(msg='"service" is a required variable for v2 api endpoint.')
+ out, changed = send_event_v2(
+ module,
+ integration_key,
+ event_type,
+ payload,
+ link,
+ incident_key,
+ client,
+ client_url,
+ )
module.exit_json(result=out, changed=changed)
diff --git a/ansible_collections/community/general/plugins/modules/pagerduty_change.py b/ansible_collections/community/general/plugins/modules/pagerduty_change.py
index 6af5d58ea..1a1e50dcf 100644
--- a/ansible_collections/community/general/plugins/modules/pagerduty_change.py
+++ b/ansible_collections/community/general/plugins/modules/pagerduty_change.py
@@ -25,7 +25,7 @@ attributes:
check_mode:
support: full
details:
- - Check mode simply does nothing except returning C(changed=true) in case the I(url) seems to be correct.
+ - Check mode simply does nothing except returning C(changed=true) in case the O(url) seems to be correct.
diff_mode:
support: none
options:
@@ -61,7 +61,7 @@ options:
type: str
environment:
description:
- - The environment name, typically C(production), C(staging), etc.
+ - The environment name, typically V(production), V(staging), and so on.
required: false
type: str
link_url:
@@ -82,7 +82,7 @@ options:
type: str
validate_certs:
description:
- - If C(false), SSL certificates for the target URL will not be validated.
+ - If V(false), SSL certificates for the target URL will not be validated.
This should only be used on personally controlled sites using self-signed certificates.
required: false
default: true
diff --git a/ansible_collections/community/general/plugins/modules/pagerduty_user.py b/ansible_collections/community/general/plugins/modules/pagerduty_user.py
index 9c9805bff..eb8a30956 100644
--- a/ansible_collections/community/general/plugins/modules/pagerduty_user.py
+++ b/ansible_collections/community/general/plugins/modules/pagerduty_user.py
@@ -40,7 +40,7 @@ options:
pd_email:
description:
- The user's email address.
- - I(pd_email) is the unique identifier used and cannot be updated using this module.
+ - O(pd_email) is the unique identifier used and cannot be updated using this module.
required: true
type: str
pd_role:
@@ -52,15 +52,15 @@ options:
state:
description:
- State of the user.
- - On C(present), it creates a user if the user doesn't exist.
- - On C(absent), it removes a user if the account exists.
+ - On V(present), it creates a user if the user doesn't exist.
+ - On V(absent), it removes a user if the account exists.
choices: ['present', 'absent']
default: 'present'
type: str
pd_teams:
description:
- The teams to which the user belongs.
- - Required if I(state=present).
+ - Required if O(state=present).
type: list
elements: str
'''
diff --git a/ansible_collections/community/general/plugins/modules/pam_limits.py b/ansible_collections/community/general/plugins/modules/pam_limits.py
index dbb70045d..f97ea6602 100644
--- a/ansible_collections/community/general/plugins/modules/pam_limits.py
+++ b/ansible_collections/community/general/plugins/modules/pam_limits.py
@@ -15,8 +15,8 @@ author:
- "Sebastien Rohaut (@usawa)"
short_description: Modify Linux PAM limits
description:
- - The C(pam_limits) module modifies PAM limits.
- - The default file is C(/etc/security/limits.conf).
+ - The M(community.general.pam_limits) module modifies PAM limits.
+ - The default file is V(/etc/security/limits.conf).
- For the full documentation, see C(man 5 limits.conf).
extends_documentation_fragment:
- community.general.attributes
@@ -68,8 +68,8 @@ options:
type: str
description:
- The value of the limit.
- - Value must either be C(unlimited), C(infinity) or C(-1), all of which indicate no limit, or a limit of 0 or larger.
- - Value must be a number in the range -20 to 19 inclusive, if I(limit_item) is set to C(nice) or C(priority).
+ - Value must either be V(unlimited), V(infinity) or V(-1), all of which indicate no limit, or a limit of 0 or larger.
+ - Value must be a number in the range -20 to 19 inclusive, if O(limit_item) is set to V(nice) or V(priority).
- Refer to the C(man 5 limits.conf) manual pages for more details.
required: true
backup:
@@ -81,7 +81,7 @@ options:
default: false
use_min:
description:
- - If set to C(true), the minimal value will be used or conserved.
+ - If set to V(true), the minimal value will be used or conserved.
- If the specified value is inferior to the value in the file,
file content is replaced with the new value, else content is not modified.
required: false
@@ -89,7 +89,7 @@ options:
default: false
use_max:
description:
- - If set to C(true), the maximal value will be used or conserved.
+ - If set to V(true), the maximal value will be used or conserved.
- If the specified value is superior to the value in the file,
file content is replaced with the new value, else content is not modified.
required: false
@@ -108,7 +108,7 @@ options:
required: false
default: ''
notes:
- - If I(dest) file does not exist, it is created.
+ - If O(dest) file does not exist, it is created.
'''
EXAMPLES = r'''
@@ -175,7 +175,6 @@ def main():
limits_conf = '/etc/security/limits.conf'
module = AnsibleModule(
- # not checking because of daisy chain to file module
argument_spec=dict(
domain=dict(required=True, type='str'),
limit_type=dict(required=True, type='str', choices=pam_types),
@@ -201,6 +200,7 @@ def main():
new_comment = module.params['comment']
changed = False
+ does_not_exist = False
if os.path.isfile(limits_conf):
if not os.access(limits_conf, os.W_OK):
@@ -208,7 +208,7 @@ def main():
else:
limits_conf_dir = os.path.dirname(limits_conf)
if os.path.isdir(limits_conf_dir) and os.access(limits_conf_dir, os.W_OK):
- open(limits_conf, 'a').close()
+ does_not_exist = True
changed = True
else:
module.fail_json(msg="directory %s is not writable (check presence, access rights, use sudo)" % limits_conf_dir)
@@ -224,15 +224,20 @@ def main():
space_pattern = re.compile(r'\s+')
+ if does_not_exist:
+ lines = []
+ else:
+ with open(limits_conf, 'rb') as f:
+ lines = list(f)
+
message = ''
- f = open(limits_conf, 'rb')
# Tempfile
nf = tempfile.NamedTemporaryFile(mode='w+')
found = False
new_value = value
- for line in f:
+ for line in lines:
line = to_native(line, errors='surrogate_or_strict')
if line.startswith('#'):
nf.write(line)
@@ -323,17 +328,17 @@ def main():
message = new_limit
nf.write(new_limit)
- f.close()
nf.flush()
- with open(limits_conf, 'r') as content:
- content_current = content.read()
-
with open(nf.name, 'r') as content:
content_new = content.read()
if not module.check_mode:
- # Copy tempfile to newfile
+ if does_not_exist:
+ with open(limits_conf, 'a'):
+ pass
+
+ # Move tempfile to newfile
module.atomic_move(nf.name, limits_conf)
try:
@@ -344,7 +349,7 @@ def main():
res_args = dict(
changed=changed,
msg=message,
- diff=dict(before=content_current, after=content_new),
+ diff=dict(before=b''.join(lines), after=content_new),
)
if backup:
diff --git a/ansible_collections/community/general/plugins/modules/pamd.py b/ansible_collections/community/general/plugins/modules/pamd.py
index 6ffc8624e..0ad4c8787 100644
--- a/ansible_collections/community/general/plugins/modules/pamd.py
+++ b/ansible_collections/community/general/plugins/modules/pamd.py
@@ -37,7 +37,7 @@ options:
type:
description:
- The type of the PAM rule being modified.
- - The C(type), C(control) and C(module_path) all must match a rule to be modified.
+ - The O(type), O(control), and O(module_path) options all must match a rule to be modified.
type: str
required: true
choices: [ account, -account, auth, -auth, password, -password, session, -session ]
@@ -46,13 +46,13 @@ options:
- The control of the PAM rule being modified.
- This may be a complicated control with brackets. If this is the case, be
sure to put "[bracketed controls]" in quotes.
- - The C(type), C(control) and C(module_path) all must match a rule to be modified.
+ - The O(type), O(control), and O(module_path) options all must match a rule to be modified.
type: str
required: true
module_path:
description:
- The module path of the PAM rule being modified.
- - The C(type), C(control) and C(module_path) all must match a rule to be modified.
+ - The O(type), O(control), and O(module_path) options all must match a rule to be modified.
type: str
required: true
new_type:
@@ -70,9 +70,9 @@ options:
type: str
module_arguments:
description:
- - When state is C(updated), the module_arguments will replace existing module_arguments.
- - When state is C(args_absent) args matching those listed in module_arguments will be removed.
- - When state is C(args_present) any args listed in module_arguments are added if
+ - When O(state=updated), the O(module_arguments) will replace existing module_arguments.
+ - When O(state=args_absent) args matching those listed in O(module_arguments) will be removed.
+ - When O(state=args_present) any args listed in O(module_arguments) are added if
missing from the existing rule.
- Furthermore, if the module argument takes a value denoted by C(=),
the value will be changed to that specified in module_arguments.
@@ -80,15 +80,15 @@ options:
elements: str
state:
description:
- - The default of C(updated) will modify an existing rule if type,
+ - The default of V(updated) will modify an existing rule if type,
control and module_path all match an existing rule.
- - With C(before), the new rule will be inserted before a rule matching type,
+ - With V(before), the new rule will be inserted before a rule matching type,
control and module_path.
- - Similarly, with C(after), the new rule will be inserted after an existing rulematching type,
+ - Similarly, with V(after), the new rule will be inserted after an existing rulematching type,
control and module_path.
- - With either C(before) or C(after) new_type, new_control, and new_module_path must all be specified.
- - If state is C(args_absent) or C(args_present), new_type, new_control, and new_module_path will be ignored.
- - State C(absent) will remove the rule. The 'absent' state was added in Ansible 2.4.
+ - With either V(before) or V(after) O(new_type), O(new_control), and O(new_module_path) must all be specified.
+ - If state is V(args_absent) or V(args_present), O(new_type), O(new_control), and O(new_module_path) will be ignored.
+ - State V(absent) will remove the rule.
type: str
choices: [ absent, before, after, args_absent, args_present, updated ]
default: updated
diff --git a/ansible_collections/community/general/plugins/modules/parted.py b/ansible_collections/community/general/plugins/modules/parted.py
index 8e6038180..382e47a47 100644
--- a/ansible_collections/community/general/plugins/modules/parted.py
+++ b/ansible_collections/community/general/plugins/modules/parted.py
@@ -21,10 +21,10 @@ description:
check the GNU parted manual.
requirements:
- This module requires C(parted) version 1.8.3 and above.
- - Option I(align) (except C(undefined)) requires C(parted) 2.1 or above.
+ - Option O(align) (except V(undefined)) requires C(parted) 2.1 or above.
- If the version of C(parted) is below 3.1, it requires a Linux version running
the C(sysfs) file system C(/sys/).
- - Requires the C(resizepart) command when using the I(resize) parameter.
+ - Requires the C(resizepart) command when using the O(resize) parameter.
extends_documentation_fragment:
- community.general.attributes
attributes:
@@ -42,7 +42,7 @@ options:
required: true
align:
description:
- - Set alignment for newly created partitions. Use C(undefined) for parted default aligment.
+ - Set alignment for newly created partitions. Use V(undefined) for parted default alignment.
type: str
choices: [ cylinder, minimal, none, optimal, undefined ]
default: optimal
@@ -63,16 +63,16 @@ options:
label:
description:
- Disk label type or partition table to use.
- - If I(device) already contains a different label, it will be changed to I(label)
+ - If O(device) already contains a different label, it will be changed to O(label)
and any previous partitions will be lost.
- - A I(name) must be specified for a C(gpt) partition table.
+ - A O(name) must be specified for a V(gpt) partition table.
type: str
choices: [ aix, amiga, bsd, dvh, gpt, loop, mac, msdos, pc98, sun ]
default: msdos
part_type:
description:
- - May be specified only with I(label=msdos) or I(label=dvh).
- - Neither I(part_type) nor I(name) may be used with I(label=sun).
+ - May be specified only with O(label=msdos) or O(label=dvh).
+ - Neither O(part_type) nor O(name) may be used with O(label=sun).
type: str
choices: [ extended, logical, primary ]
default: primary
@@ -82,8 +82,8 @@ options:
that is, the "distance" from the start of the disk. Negative numbers
specify distance from the end of the disk.
- The distance can be specified with all the units supported by parted
- (except compat) and it is case sensitive, e.g. C(10GiB), C(15%).
- - Using negative values may require setting of I(fs_type) (see notes).
+ (except compat) and it is case sensitive, for example V(10GiB), V(15%).
+ - Using negative values may require setting of O(fs_type) (see notes).
type: str
default: 0%
part_end:
@@ -92,7 +92,7 @@ options:
that is, the "distance" from the start of the disk. Negative numbers
specify distance from the end of the disk.
- The distance can be specified with all the units supported by parted
- (except compat) and it is case sensitive, e.g. C(10GiB), C(15%).
+ (except compat) and it is case sensitive, for example V(10GiB), V(15%).
type: str
default: 100%
name:
@@ -106,19 +106,19 @@ options:
state:
description:
- Whether to create or delete a partition.
- - If set to C(info) the module will only return the device information.
+ - If set to V(info) the module will only return the device information.
type: str
choices: [ absent, present, info ]
default: info
fs_type:
description:
- If specified and the partition does not exist, will set filesystem type to given partition.
- - Parameter optional, but see notes below about negative I(part_start) values.
+ - Parameter optional, but see notes below about negative O(part_start) values.
type: str
version_added: '0.2.0'
resize:
description:
- - Call C(resizepart) on existing partitions to match the size specified by I(part_end).
+ - Call C(resizepart) on existing partitions to match the size specified by O(part_end).
type: bool
default: false
version_added: '1.3.0'
@@ -128,9 +128,9 @@ notes:
installed on the system is before version 3.1, the module queries the kernel
through C(/sys/) to obtain disk information. In this case the units CHS and
CYL are not supported.
- - Negative I(part_start) start values were rejected if I(fs_type) was not given.
- This bug was fixed in parted 3.2.153. If you want to use negative I(part_start),
- specify I(fs_type) as well or make sure your system contains newer parted.
+ - Negative O(part_start) start values were rejected if O(fs_type) was not given.
+ This bug was fixed in parted 3.2.153. If you want to use negative O(part_start),
+ specify O(fs_type) as well or make sure your system contains newer parted.
'''
RETURN = r'''
@@ -569,8 +569,18 @@ def parted(script, device, align):
if align == 'undefined':
align_option = ''
+ """
+ Use option --fix (-f) if available. Versions prior
+ to 3.4.64 don't have it. For more information see:
+ http://savannah.gnu.org/news/?id=10114
+ """
+ if parted_version() >= (3, 4, 64):
+ script_option = '-s -f'
+ else:
+ script_option = '-s'
+
if script and not module.check_mode:
- command = "%s -s -m %s %s -- %s" % (parted_exec, align_option, device, script)
+ command = "%s %s -m %s %s -- %s" % (parted_exec, script_option, align_option, device, script)
rc, out, err = module.run_command(command)
if rc != 0:
diff --git a/ansible_collections/community/general/plugins/modules/pear.py b/ansible_collections/community/general/plugins/modules/pear.py
index d7cb01b92..36770de6c 100644
--- a/ansible_collections/community/general/plugins/modules/pear.py
+++ b/ansible_collections/community/general/plugins/modules/pear.py
@@ -48,12 +48,12 @@ options:
description:
- List of regular expressions that can be used to detect prompts during pear package installation to answer the expected question.
- Prompts will be processed in the same order as the packages list.
- - You can optionnally specify an answer to any question in the list.
+ - You can optionally specify an answer to any question in the list.
- If no answer is provided, the list item will only contain the regular expression.
- "To specify an answer, the item will be a dict with the regular expression as key and the answer as value C(my_regular_expression: 'an_answer')."
- You can provide a list containing items with or without answer.
- A prompt list can be shorter or longer than the packages list but will issue a warning.
- - If you want to specify that a package will not need prompts in the middle of a list, C(null).
+ - If you want to specify that a package will not need prompts in the middle of a list, V(null).
type: list
elements: raw
version_added: 0.2.0
@@ -87,7 +87,7 @@ EXAMPLES = r'''
- name: Install multiple pear/pecl packages at once with prompts.
Prompts will be processed on the same order as the packages order.
If there is more prompts than packages, packages without prompts will be installed without any prompt expected.
- If there is more packages than prompts, additionnal prompts will be ignored.
+ If there is more packages than prompts, additional prompts will be ignored.
community.general.pear:
name: pecl/gnupg, pecl/apcu
state: present
@@ -98,7 +98,7 @@ EXAMPLES = r'''
- name: Install multiple pear/pecl packages at once skipping the first prompt.
Prompts will be processed on the same order as the packages order.
If there is more prompts than packages, packages without prompts will be installed without any prompt expected.
- If there is more packages than prompts, additionnal prompts will be ignored.
+ If there is more packages than prompts, additional prompts will be ignored.
community.general.pear:
name: pecl/gnupg, pecl/apcu
state: present
diff --git a/ansible_collections/community/general/plugins/modules/pids.py b/ansible_collections/community/general/plugins/modules/pids.py
index 665adb142..590f1e85a 100644
--- a/ansible_collections/community/general/plugins/modules/pids.py
+++ b/ansible_collections/community/general/plugins/modules/pids.py
@@ -31,7 +31,7 @@ options:
type: str
version_added: 3.0.0
ignore_case:
- description: Ignore case in pattern if using the I(pattern) option.
+ description: Ignore case in pattern if using the O(pattern) option.
type: bool
default: false
version_added: 3.0.0
diff --git a/ansible_collections/community/general/plugins/modules/pip_package_info.py b/ansible_collections/community/general/plugins/modules/pip_package_info.py
index 2cde7218d..6aea178ce 100644
--- a/ansible_collections/community/general/plugins/modules/pip_package_info.py
+++ b/ansible_collections/community/general/plugins/modules/pip_package_info.py
@@ -21,7 +21,7 @@ options:
clients:
description:
- A list of the pip executables that will be used to get the packages.
- They can be supplied with the full path or just the executable name, for example C(pip3.7).
+ They can be supplied with the full path or just the executable name, for example V(pip3.7).
default: ['pip']
required: false
type: list
diff --git a/ansible_collections/community/general/plugins/modules/pipx.py b/ansible_collections/community/general/plugins/modules/pipx.py
index dfa2f4300..705cc71a7 100644
--- a/ansible_collections/community/general/plugins/modules/pipx.py
+++ b/ansible_collections/community/general/plugins/modules/pipx.py
@@ -30,8 +30,8 @@ options:
default: install
description:
- Desired state for the application.
- - The states C(present) and C(absent) are aliases to C(install) and C(uninstall), respectively.
- - The state C(latest) is equivalent to executing the task twice, with state C(install) and then C(upgrade).
+ - The states V(present) and V(absent) are aliases to V(install) and V(uninstall), respectively.
+ - The state V(latest) is equivalent to executing the task twice, with state V(install) and then V(upgrade).
It was added in community.general 5.5.0.
name:
type: str
@@ -39,60 +39,60 @@ options:
- >
The name of the application to be installed. It must to be a simple package name.
For passing package specifications or installing from URLs or directories,
- please use the I(source) option.
+ please use the O(source) option.
source:
type: str
description:
- >
If the application source, such as a package with version specifier, or an URL,
directory or any other accepted specification. See C(pipx) documentation for more details.
- - When specified, the C(pipx) command will use I(source) instead of I(name).
+ - When specified, the C(pipx) command will use O(source) instead of O(name).
install_apps:
description:
- Add apps from the injected packages.
- - Only used when I(state=inject).
+ - Only used when O(state=inject).
type: bool
default: false
version_added: 6.5.0
install_deps:
description:
- Include applications of dependent packages.
- - Only used when I(state=install), I(state=latest), or I(state=inject).
+ - Only used when O(state=install), O(state=latest), or O(state=inject).
type: bool
default: false
inject_packages:
description:
- Packages to be injected into an existing virtual environment.
- - Only used when I(state=inject).
+ - Only used when O(state=inject).
type: list
elements: str
force:
description:
- Force modification of the application's virtual environment. See C(pipx) for details.
- - Only used when I(state=install), I(state=upgrade), I(state=upgrade_all), I(state=latest), or I(state=inject).
+ - Only used when O(state=install), O(state=upgrade), O(state=upgrade_all), O(state=latest), or O(state=inject).
type: bool
default: false
include_injected:
description:
- Upgrade the injected packages along with the application.
- - Only used when I(state=upgrade), I(state=upgrade_all), or I(state=latest).
- - This is used with I(state=upgrade) and I(state=latest) since community.general 6.6.0.
+ - Only used when O(state=upgrade), O(state=upgrade_all), or O(state=latest).
+ - This is used with O(state=upgrade) and O(state=latest) since community.general 6.6.0.
type: bool
default: false
index_url:
description:
- Base URL of Python Package Index.
- - Only used when I(state=install), I(state=upgrade), I(state=latest), or I(state=inject).
+ - Only used when O(state=install), O(state=upgrade), O(state=latest), or O(state=inject).
type: str
python:
description:
- Python version to be used when creating the application virtual environment. Must be 3.6+.
- - Only used when I(state=install), I(state=latest), I(state=reinstall), or I(state=reinstall_all).
+ - Only used when O(state=install), O(state=latest), O(state=reinstall), or O(state=reinstall_all).
type: str
system_site_packages:
description:
- Give application virtual environment access to the system site-packages directory.
- - Only used when I(state=install) or I(state=latest).
+ - Only used when O(state=install) or O(state=latest).
type: bool
default: false
version_added: 6.6.0
diff --git a/ansible_collections/community/general/plugins/modules/pipx_info.py b/ansible_collections/community/general/plugins/modules/pipx_info.py
index e2bb7fdae..34f9681b0 100644
--- a/ansible_collections/community/general/plugins/modules/pipx_info.py
+++ b/ansible_collections/community/general/plugins/modules/pipx_info.py
@@ -37,7 +37,7 @@ options:
include_raw:
description:
- Returns the raw output of C(pipx list --json).
- - The raw output is not affected by I(include_deps) or I(include_injected).
+ - The raw output is not affected by O(include_deps) or O(include_injected).
type: bool
default: false
executable:
@@ -51,7 +51,7 @@ notes:
- This module does not install the C(pipx) python package, however that can be easily done with the module M(ansible.builtin.pip).
- This module does not require C(pipx) to be in the shell C(PATH), but it must be loadable by Python as a module.
- >
- This module will honor C(pipx) environment variables such as but not limited to C(PIPX_HOME) and C(PIPX_BIN_DIR)
+ This module will honor C(pipx) environment variables such as but not limited to E(PIPX_HOME) and E(PIPX_BIN_DIR)
passed using the R(environment Ansible keyword, playbooks_environment).
- This module requires C(pipx) version 0.16.2.1 or above.
- Please note that C(pipx) requires Python 3.6 or above.
@@ -98,20 +98,20 @@ application:
type: str
sample: "3.24.0"
dependencies:
- description: The dependencies of the installed application, when I(include_deps=true).
+ description: The dependencies of the installed application, when O(include_deps=true).
returned: success
type: list
elements: str
sample: ["virtualenv"]
injected:
- description: The injected packages for the installed application, when I(include_injected=true).
+ description: The injected packages for the installed application, when O(include_injected=true).
returned: success
type: dict
sample:
licenses: "0.6.1"
raw_output:
- description: The raw output of the C(pipx list) command, when I(include_raw=true). Used for debugging.
+ description: The raw output of the C(pipx list) command, when O(include_raw=true). Used for debugging.
returned: success
type: dict
diff --git a/ansible_collections/community/general/plugins/modules/pkg5.py b/ansible_collections/community/general/plugins/modules/pkg5.py
index f6bc77a71..c4aace9f2 100644
--- a/ansible_collections/community/general/plugins/modules/pkg5.py
+++ b/ansible_collections/community/general/plugins/modules/pkg5.py
@@ -29,13 +29,13 @@ options:
name:
description:
- An FRMI of the package(s) to be installed/removed/updated.
- - Multiple packages may be specified, separated by C(,).
+ - Multiple packages may be specified, separated by V(,).
required: true
type: list
elements: str
state:
description:
- - Whether to install (I(present), I(latest)), or remove (I(absent)) a package.
+ - Whether to install (V(present), V(latest)), or remove (V(absent)) a package.
choices: [ absent, latest, present, installed, removed, uninstalled ]
default: present
type: str
diff --git a/ansible_collections/community/general/plugins/modules/pkgin.py b/ansible_collections/community/general/plugins/modules/pkgin.py
index c08b25218..5b2e478b8 100644
--- a/ansible_collections/community/general/plugins/modules/pkgin.py
+++ b/ansible_collections/community/general/plugins/modules/pkgin.py
@@ -30,7 +30,7 @@ author:
notes:
- "Known bug with pkgin < 0.8.0: if a package is removed and another
package depends on it, the other package will be silently removed as
- well. New to Ansible 1.9: check-mode support."
+ well."
extends_documentation_fragment:
- community.general.attributes
attributes:
@@ -174,6 +174,13 @@ def query_package(module, name):
# '<' - installed but out of date
# '=' - installed and up to date
# '>' - installed but newer than the repository version
+
+ if (package in ('reading local summary...',
+ 'processing local summary...',
+ 'downloading pkg_summary.xz done.')) or \
+ (package.startswith('processing remote summary (')):
+ continue
+
pkgname_with_version, raw_state = package.split(splitchar)[0:2]
# Search for package, stripping version
@@ -317,7 +324,7 @@ def do_upgrade_packages(module, full=False):
format_pkgin_command(module, cmd))
if rc == 0:
- if re.search('^nothing to do.\n$', out):
+ if re.search('^(.*\n|)nothing to do.\n$', out):
module.exit_json(changed=False, msg="nothing left to upgrade")
else:
module.fail_json(msg="could not %s packages" % cmd, stdout=out, stderr=err)
diff --git a/ansible_collections/community/general/plugins/modules/pkgng.py b/ansible_collections/community/general/plugins/modules/pkgng.py
index b9d4422c0..88c9b8e3b 100644
--- a/ansible_collections/community/general/plugins/modules/pkgng.py
+++ b/ansible_collections/community/general/plugins/modules/pkgng.py
@@ -31,13 +31,7 @@ options:
name:
description:
- Name or list of names of packages to install/remove.
- - "With I(name=*), I(state=latest) will operate, but I(state=present) and I(state=absent) will be noops."
- - >
- Warning: In Ansible 2.9 and earlier this module had a misfeature
- where I(name=*) with I(state=latest) or I(state=present) would
- install every package from every package repository, filling up
- the machines disk. Avoid using them unless you are certain that
- your role will only be used with newer versions.
+ - "With O(name=*), O(state=latest) will operate, but O(state=present) and O(state=absent) will be noops."
required: true
aliases: [pkg]
type: list
@@ -45,7 +39,6 @@ options:
state:
description:
- State of the package.
- - 'Note: C(latest) added in 2.7.'
choices: [ 'present', 'latest', 'absent' ]
required: false
default: present
@@ -59,8 +52,8 @@ options:
annotation:
description:
- A list of keyvalue-pairs of the form
- C(<+/-/:><key>[=<value>]). A C(+) denotes adding an annotation, a
- C(-) denotes removing an annotation, and C(:) denotes modifying an
+ C(<+/-/:><key>[=<value>]). A V(+) denotes adding an annotation, a
+ V(-) denotes removing an annotation, and V(:) denotes modifying an
annotation.
If setting or modifying annotations, a value must be provided.
required: false
@@ -79,19 +72,19 @@ options:
description:
- For pkgng versions 1.5 and later, pkg will install all packages
within the specified root directory.
- - Can not be used together with I(chroot) or I(jail) options.
+ - Can not be used together with O(chroot) or O(jail) options.
required: false
type: path
chroot:
description:
- Pkg will chroot in the specified environment.
- - Can not be used together with I(rootdir) or I(jail) options.
+ - Can not be used together with O(rootdir) or O(jail) options.
required: false
type: path
jail:
description:
- Pkg will execute in the given jail name or id.
- - Can not be used together with I(chroot) or I(rootdir) options.
+ - Can not be used together with O(chroot) or O(rootdir) options.
type: str
autoremove:
description:
@@ -102,7 +95,7 @@ options:
ignore_osver:
description:
- Ignore FreeBSD OS version check, useful on -STABLE and -CURRENT branches.
- - Defines the C(IGNORE_OSVERSION) environment variable.
+ - Defines the E(IGNORE_OSVERSION) environment variable.
required: false
type: bool
default: false
@@ -111,7 +104,7 @@ author: "bleader (@bleader)"
notes:
- When using pkgsite, be careful that already in cache packages won't be downloaded again.
- When used with a C(loop:) each package will be processed individually,
- it is much more efficient to pass the list directly to the I(name) option.
+ it is much more efficient to pass the list directly to the O(name) option.
'''
EXAMPLES = '''
diff --git a/ansible_collections/community/general/plugins/modules/pkgutil.py b/ansible_collections/community/general/plugins/modules/pkgutil.py
index 5af74c1f3..15f98a9d4 100644
--- a/ansible_collections/community/general/plugins/modules/pkgutil.py
+++ b/ansible_collections/community/general/plugins/modules/pkgutil.py
@@ -36,7 +36,7 @@ options:
name:
description:
- The name of the package.
- - When using I(state=latest), this can be C('*'), which updates all installed packages managed by pkgutil.
+ - When using O(state=latest), this can be V('*'), which updates all installed packages managed by pkgutil.
type: list
required: true
elements: str
@@ -49,19 +49,19 @@ options:
type: str
state:
description:
- - Whether to install (C(present)/C(installed)), or remove (C(absent)/C(removed)) packages.
- - The upgrade (C(latest)) operation will update/install the packages to the latest version available.
+ - Whether to install (V(present)/V(installed)), or remove (V(absent)/V(removed)) packages.
+ - The upgrade (V(latest)) operation will update/install the packages to the latest version available.
type: str
required: true
choices: [ absent, installed, latest, present, removed ]
update_catalog:
description:
- - If you always want to refresh your catalog from the mirror, even when it's not stale, set this to C(true).
+ - If you always want to refresh your catalog from the mirror, even when it's not stale, set this to V(true).
type: bool
default: false
force:
description:
- - To allow the update process to downgrade packages to match what is present in the repository, set this to C(true).
+ - To allow the update process to downgrade packages to match what is present in the repository, set this to V(true).
- This is useful for rolling back to stable from testing, or similar operations.
type: bool
default: false
diff --git a/ansible_collections/community/general/plugins/modules/pmem.py b/ansible_collections/community/general/plugins/modules/pmem.py
index d7fcb8e01..4d10c448e 100644
--- a/ansible_collections/community/general/plugins/modules/pmem.py
+++ b/ansible_collections/community/general/plugins/modules/pmem.py
@@ -30,10 +30,10 @@ attributes:
options:
appdirect:
description:
- - Percentage of the total capacity to use in AppDirect Mode (C(0)-C(100)).
+ - Percentage of the total capacity to use in AppDirect Mode (V(0)-V(100)).
- Create AppDirect capacity utilizing hardware interleaving across the
requested PMem modules if applicable given the specified target.
- - Total of I(appdirect), I(memorymode) and I(reserved) must be C(100)
+ - Total of O(appdirect), O(memorymode) and O(reserved) must be V(100)
type: int
appdirect_interleaved:
description:
@@ -43,20 +43,20 @@ options:
default: true
memorymode:
description:
- - Percentage of the total capacity to use in Memory Mode (C(0)-C(100)).
+ - Percentage of the total capacity to use in Memory Mode (V(0)-V(100)).
type: int
reserved:
description:
- - Percentage of the capacity to reserve (C(0)-C(100)). I(reserved) will not be mapped
+ - Percentage of the capacity to reserve (V(0)-V(100)). O(reserved) will not be mapped
into the system physical address space and will be presented as reserved
capacity with Show Device and Show Memory Resources Commands.
- - I(reserved) will be set automatically if this is not configured.
+ - O(reserved) will be set automatically if this is not configured.
type: int
required: false
socket:
description:
- This enables to set the configuration for each socket by using the socket ID.
- - Total of I(appdirect), I(memorymode) and I(reserved) must be C(100) within one socket.
+ - Total of O(appdirect), O(memorymode) and O(reserved) must be V(100) within one socket.
type: list
elements: dict
suboptions:
@@ -66,7 +66,7 @@ options:
required: true
appdirect:
description:
- - Percentage of the total capacity to use in AppDirect Mode (C(0)-C(100)) within the socket ID.
+ - Percentage of the total capacity to use in AppDirect Mode (V(0)-V(100)) within the socket ID.
type: int
required: true
appdirect_interleaved:
@@ -77,12 +77,12 @@ options:
default: true
memorymode:
description:
- - Percentage of the total capacity to use in Memory Mode (C(0)-C(100)) within the socket ID.
+ - Percentage of the total capacity to use in Memory Mode (V(0)-V(100)) within the socket ID.
type: int
required: true
reserved:
description:
- - Percentage of the capacity to reserve (C(0)-C(100)) within the socket ID.
+ - Percentage of the capacity to reserve (V(0)-V(100)) within the socket ID.
type: int
namespace:
description:
@@ -104,8 +104,8 @@ options:
choices: ['pmem', 'blk']
size:
description:
- - The size of namespace. This option supports the suffixes C(k) or C(K) or C(KB) for KiB,
- C(m) or C(M) or C(MB) for MiB, C(g) or C(G) or C(GB) for GiB and C(t) or C(T) or C(TB) for TiB.
+ - The size of namespace. This option supports the suffixes V(k) or V(K) or V(KB) for KiB,
+ V(m) or V(M) or V(MB) for MiB, V(g) or V(G) or V(GB) for GiB and V(t) or V(T) or V(TB) for TiB.
- This option is required if multiple namespaces are configured.
- If this option is not set, all of the available space of a region is configured.
type: str
@@ -113,7 +113,7 @@ options:
namespace_append:
description:
- Enable to append the new namespaces to the system.
- - The default is C(false) so the all existing namespaces not listed in I(namespace) are removed.
+ - The default is V(false) so the all existing namespaces not listed in O(namespace) are removed.
type: bool
default: false
required: false
@@ -128,8 +128,8 @@ reboot_required:
result:
description:
- Shows the value of AppDirect, Memory Mode and Reserved size in bytes.
- - If I(socket) argument is provided, shows the values in each socket with C(socket) which contains the socket ID.
- - If I(namespace) argument is provided, shows the detail of each namespace.
+ - If O(socket) argument is provided, shows the values in each socket with C(socket) which contains the socket ID.
+ - If O(namespace) argument is provided, shows the detail of each namespace.
returned: success
type: list
elements: dict
diff --git a/ansible_collections/community/general/plugins/modules/pnpm.py b/ansible_collections/community/general/plugins/modules/pnpm.py
new file mode 100644
index 000000000..315b07ba8
--- /dev/null
+++ b/ansible_collections/community/general/plugins/modules/pnpm.py
@@ -0,0 +1,462 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2023 Aritra Sen <aretrosen@proton.me>
+# Copyright (c) 2017 Chris Hoffman <christopher.hoffman@gmail.com>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+---
+module: pnpm
+short_description: Manage node.js packages with pnpm
+version_added: 7.4.0
+description:
+ - Manage node.js packages with the L(pnpm package manager, https://pnpm.io/).
+author:
+ - "Aritra Sen (@aretrosen)"
+ - "Chris Hoffman (@chrishoffman), creator of NPM Ansible module"
+extends_documentation_fragment:
+ - community.general.attributes
+attributes:
+ check_mode:
+ support: full
+ diff_mode:
+ support: none
+options:
+ name:
+ description:
+ - The name of a node.js library to install.
+ - All packages in package.json are installed if not provided.
+ type: str
+ required: false
+ alias:
+ description:
+ - Alias of the node.js library.
+ type: str
+ required: false
+ path:
+ description:
+ - The base path to install the node.js libraries.
+ type: path
+ required: false
+ version:
+ description:
+ - The version of the library to be installed, in semver format.
+ type: str
+ required: false
+ global:
+ description:
+ - Install the node.js library globally.
+ required: false
+ default: false
+ type: bool
+ executable:
+ description:
+ - The executable location for pnpm.
+ - The default location it searches for is E(PATH), fails if not set.
+ type: path
+ required: false
+ ignore_scripts:
+ description:
+ - Use the C(--ignore-scripts) flag when installing.
+ required: false
+ type: bool
+ default: false
+ no_optional:
+ description:
+ - Do not install optional packages, equivalent to C(--no-optional).
+ required: false
+ type: bool
+ default: false
+ production:
+ description:
+ - Install dependencies in production mode.
+ - Pnpm will ignore any dependencies under C(devDependencies) in package.json.
+ required: false
+ type: bool
+ default: false
+ dev:
+ description:
+ - Install dependencies in development mode.
+ - Pnpm will ignore any regular dependencies in C(package.json).
+ required: false
+ default: false
+ type: bool
+ optional:
+ description:
+ - Install dependencies in optional mode.
+ required: false
+ default: false
+ type: bool
+ state:
+ description:
+ - Installation state of the named node.js library.
+ - If V(absent) is selected, a name option must be provided.
+ type: str
+ required: false
+ default: present
+ choices: ["present", "absent", "latest"]
+requirements:
+ - Pnpm executable present in E(PATH).
+"""
+
+EXAMPLES = """
+- name: Install "tailwindcss" node.js package.
+ community.general.pnpm:
+ name: tailwindcss
+ path: /app/location
+
+- name: Install "tailwindcss" node.js package on version 3.3.2
+ community.general.pnpm:
+ name: tailwindcss
+ version: 3.3.2
+ path: /app/location
+
+- name: Install "tailwindcss" node.js package globally.
+ community.general.pnpm:
+ name: tailwindcss
+ global: true
+
+- name: Install "tailwindcss" node.js package as dev dependency.
+ community.general.pnpm:
+ name: tailwindcss
+ path: /app/location
+ dev: true
+
+- name: Install "tailwindcss" node.js package as optional dependency.
+ community.general.pnpm:
+ name: tailwindcss
+ path: /app/location
+ optional: true
+
+- name: Install "tailwindcss" node.js package version 0.1.3 as tailwind-1
+ community.general.pnpm:
+ name: tailwindcss
+ alias: tailwind-1
+ version: 0.1.3
+ path: /app/location
+
+- name: Remove the globally-installed package "tailwindcss".
+ community.general.pnpm:
+ name: tailwindcss
+ global: true
+ state: absent
+
+- name: Install packages based on package.json.
+ community.general.pnpm:
+ path: /app/location
+
+- name: Update all packages in package.json to their latest version.
+ community.general.pnpm:
+ path: /app/location
+ state: latest
+"""
+import json
+import os
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.common.text.converters import to_native
+
+
+class Pnpm(object):
+ def __init__(self, module, **kwargs):
+ self.module = module
+ self.name = kwargs["name"]
+ self.alias = kwargs["alias"]
+ self.version = kwargs["version"]
+ self.path = kwargs["path"]
+ self.globally = kwargs["globally"]
+ self.executable = kwargs["executable"]
+ self.ignore_scripts = kwargs["ignore_scripts"]
+ self.no_optional = kwargs["no_optional"]
+ self.production = kwargs["production"]
+ self.dev = kwargs["dev"]
+ self.optional = kwargs["optional"]
+
+ self.alias_name_ver = None
+
+ if self.alias is not None:
+ self.alias_name_ver = self.alias + "@npm:"
+
+ if self.name is not None:
+ self.alias_name_ver = (self.alias_name_ver or "") + self.name
+ if self.version is not None:
+ self.alias_name_ver = self.alias_name_ver + "@" + str(self.version)
+ else:
+ self.alias_name_ver = self.alias_name_ver + "@latest"
+
+ def _exec(self, args, run_in_check_mode=False, check_rc=True):
+ if not self.module.check_mode or (self.module.check_mode and run_in_check_mode):
+ cmd = self.executable + args
+
+ if self.globally:
+ cmd.append("-g")
+
+ if self.ignore_scripts:
+ cmd.append("--ignore-scripts")
+
+ if self.no_optional:
+ cmd.append("--no-optional")
+
+ if self.production:
+ cmd.append("-P")
+
+ if self.dev:
+ cmd.append("-D")
+
+ if self.name and self.optional:
+ cmd.append("-O")
+
+ # If path is specified, cd into that path and run the command.
+ cwd = None
+ if self.path:
+ if not os.path.exists(self.path):
+ os.makedirs(self.path)
+
+ if not os.path.isdir(self.path):
+ self.module.fail_json(msg="Path %s is not a directory" % self.path)
+
+ if not self.alias_name_ver and not os.path.isfile(
+ os.path.join(self.path, "package.json")
+ ):
+ self.module.fail_json(
+ msg="package.json does not exist in provided path"
+ )
+
+ cwd = self.path
+
+ _rc, out, err = self.module.run_command(cmd, check_rc=check_rc, cwd=cwd)
+ return out, err
+
+ return None, None
+
+ def missing(self):
+ if not os.path.isfile(os.path.join(self.path, "pnpm-lock.yaml")):
+ return True
+
+ cmd = ["list", "--json"]
+
+ if self.name is not None:
+ cmd.append(self.name)
+
+ try:
+ out, err = self._exec(cmd, True, False)
+ if err is not None and err != "":
+ raise Exception(out)
+
+ data = json.loads(out)
+ except Exception as e:
+ self.module.fail_json(
+ msg="Failed to parse pnpm output with error %s" % to_native(e)
+ )
+
+ if "error" in data:
+ return True
+
+ data = data[0]
+
+ for typedep in [
+ "dependencies",
+ "devDependencies",
+ "optionalDependencies",
+ "unsavedDependencies",
+ ]:
+ if typedep not in data:
+ continue
+
+ for dep, prop in data[typedep].items():
+ if self.alias is not None and self.alias != dep:
+ continue
+
+ name = prop["from"] if self.alias is not None else dep
+ if self.name != name:
+ continue
+
+ if self.version is None or self.version == prop["version"]:
+ return False
+
+ break
+
+ return True
+
+ def install(self):
+ if self.alias_name_ver is not None:
+ return self._exec(["add", self.alias_name_ver])
+ return self._exec(["install"])
+
+ def update(self):
+ return self._exec(["update", "--latest"])
+
+ def uninstall(self):
+ if self.alias is not None:
+ return self._exec(["remove", self.alias])
+ return self._exec(["remove", self.name])
+
+ def list_outdated(self):
+ if not os.path.isfile(os.path.join(self.path, "pnpm-lock.yaml")):
+ return list()
+
+ cmd = ["outdated", "--format", "json"]
+ try:
+ out, err = self._exec(cmd, True, False)
+
+ # BUG: It will not show correct error sometimes, like when it has
+ # plain text output intermingled with a {}
+ if err is not None and err != "":
+ raise Exception(out)
+
+ # HACK: To fix the above bug, the following hack is implemented
+ data_lines = out.splitlines(True)
+
+ out = None
+ for line in data_lines:
+ if len(line) > 0 and line[0] == "{":
+ out = line
+ continue
+
+ if len(line) > 0 and line[0] == "}":
+ out += line
+ break
+
+ if out is not None:
+ out += line
+
+ data = json.loads(out)
+ except Exception as e:
+ self.module.fail_json(
+ msg="Failed to parse pnpm output with error %s" % to_native(e)
+ )
+
+ return data.keys()
+
+
+def main():
+ arg_spec = dict(
+ name=dict(default=None),
+ alias=dict(default=None),
+ path=dict(default=None, type="path"),
+ version=dict(default=None),
+ executable=dict(default=None, type="path"),
+ ignore_scripts=dict(default=False, type="bool"),
+ no_optional=dict(default=False, type="bool"),
+ production=dict(default=False, type="bool"),
+ dev=dict(default=False, type="bool"),
+ optional=dict(default=False, type="bool"),
+ state=dict(default="present", choices=["present", "absent", "latest"]),
+ )
+ arg_spec["global"] = dict(default=False, type="bool")
+ module = AnsibleModule(argument_spec=arg_spec, supports_check_mode=True)
+
+ name = module.params["name"]
+ alias = module.params["alias"]
+ path = module.params["path"]
+ version = module.params["version"]
+ globally = module.params["global"]
+ ignore_scripts = module.params["ignore_scripts"]
+ no_optional = module.params["no_optional"]
+ production = module.params["production"]
+ dev = module.params["dev"]
+ optional = module.params["optional"]
+ state = module.params["state"]
+
+ if module.params["executable"]:
+ executable = module.params["executable"].split(" ")
+ else:
+ executable = [module.get_bin_path("pnpm", True)]
+
+ if name is None and version is not None:
+ module.fail_json(msg="version is meaningless when name is not provided")
+
+ if name is None and alias is not None:
+ module.fail_json(msg="alias is meaningless when name is not provided")
+
+ if path is None and not globally:
+ module.fail_json(msg="path must be specified when not using global")
+ elif path is not None and globally:
+ module.fail_json(msg="Cannot specify path when doing global installation")
+
+ if globally and (production or dev or optional):
+ module.fail_json(
+ msg="Options production, dev, and optional is meaningless when installing packages globally"
+ )
+
+ if name is not None and path is not None and globally:
+ module.fail_json(msg="path should not be mentioned when installing globally")
+
+ if production and dev and optional:
+ module.fail_json(
+ msg="Options production and dev and optional don't go together"
+ )
+
+ if production and dev:
+ module.fail_json(msg="Options production and dev don't go together")
+
+ if production and optional:
+ module.fail_json(msg="Options production and optional don't go together")
+
+ if dev and optional:
+ module.fail_json(msg="Options dev and optional don't go together")
+
+ if name is not None and name[0:4] == "http" and version is not None:
+ module.fail_json(msg="Semver not supported on remote url downloads")
+
+ if name is None and optional:
+ module.fail_json(
+ msg="Optional not available when package name not provided, use no_optional instead"
+ )
+
+ if state == "absent" and name is None:
+ module.fail_json(msg="Package name is required for uninstalling")
+
+ if globally:
+ _rc, out, _err = module.run_command(executable + ["root", "-g"], check_rc=True)
+ path, _tail = os.path.split(out.strip())
+
+ pnpm = Pnpm(
+ module,
+ name=name,
+ alias=alias,
+ path=path,
+ version=version,
+ globally=globally,
+ executable=executable,
+ ignore_scripts=ignore_scripts,
+ no_optional=no_optional,
+ production=production,
+ dev=dev,
+ optional=optional,
+ )
+
+ changed = False
+ out = ""
+ err = ""
+ if state == "present":
+ if pnpm.missing():
+ changed = True
+ out, err = pnpm.install()
+ elif state == "latest":
+ outdated = pnpm.list_outdated()
+ if name is not None:
+ if pnpm.missing() or name in outdated:
+ changed = True
+ out, err = pnpm.install()
+ elif len(outdated):
+ changed = True
+ out, err = pnpm.update()
+ else: # absent
+ if not pnpm.missing():
+ changed = True
+ out, err = pnpm.uninstall()
+
+ module.exit_json(changed=changed, out=out, err=err)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/general/plugins/modules/portage.py b/ansible_collections/community/general/plugins/modules/portage.py
index 1c6b36537..112f6d2d7 100644
--- a/ansible_collections/community/general/plugins/modules/portage.py
+++ b/ansible_collections/community/general/plugins/modules/portage.py
@@ -33,7 +33,7 @@ attributes:
options:
package:
description:
- - Package atom or set, e.g. C(sys-apps/foo) or C(>foo-2.13) or C(@world)
+ - Package atom or set, for example V(sys-apps/foo) or V(>foo-2.13) or V(@world)
aliases: [name]
type: list
elements: str
@@ -124,8 +124,8 @@ options:
sync:
description:
- Sync package repositories first
- - If C(yes), perform "emerge --sync"
- - If C(web), perform "emerge-webrsync"
+ - If V(yes), perform "emerge --sync"
+ - If V(web), perform "emerge-webrsync"
choices: [ "web", "yes", "no" ]
type: str
diff --git a/ansible_collections/community/general/plugins/modules/pritunl_org.py b/ansible_collections/community/general/plugins/modules/pritunl_org.py
index df2df4494..4945a8fc2 100644
--- a/ansible_collections/community/general/plugins/modules/pritunl_org.py
+++ b/ansible_collections/community/general/plugins/modules/pritunl_org.py
@@ -37,9 +37,9 @@ options:
type: bool
default: false
description:
- - If I(force) is C(true) and I(state) is C(absent), the module
+ - If O(force) is V(true) and O(state) is V(absent), the module
will delete the organization, no matter if it contains users
- or not. By default I(force) is C(false), which will cause the
+ or not. By default O(force) is V(false), which will cause the
module to fail the deletion of the organization when it contains
users.
@@ -50,9 +50,9 @@ options:
- present
- absent
description:
- - If C(present), the module adds organization I(name) to
- Pritunl. If C(absent), attempt to delete the organization
- from Pritunl (please read about I(force) usage).
+ - If V(present), the module adds organization O(name) to
+ Pritunl. If V(absent), attempt to delete the organization
+ from Pritunl (please read about O(force) usage).
"""
EXAMPLES = """
diff --git a/ansible_collections/community/general/plugins/modules/pritunl_user.py b/ansible_collections/community/general/plugins/modules/pritunl_user.py
index 5aac23393..bdbc335d9 100644
--- a/ansible_collections/community/general/plugins/modules/pritunl_user.py
+++ b/ansible_collections/community/general/plugins/modules/pritunl_user.py
@@ -40,9 +40,9 @@ options:
- present
- absent
description:
- - If C(present), the module adds user I(user_name) to
- the Pritunl I(organization). If C(absent), removes the user
- I(user_name) from the Pritunl I(organization).
+ - If V(present), the module adds user O(user_name) to
+ the Pritunl O(organization). If V(absent), removes the user
+ O(user_name) from the Pritunl O(organization).
user_name:
type: str
@@ -56,7 +56,7 @@ options:
required: false
default: null
description:
- - Email address associated with the user I(user_name).
+ - Email address associated with the user O(user_name).
user_type:
type: str
@@ -66,7 +66,7 @@ options:
- client
- server
description:
- - Type of the user I(user_name).
+ - Type of the user O(user_name).
user_groups:
type: list
@@ -74,27 +74,27 @@ options:
required: false
default: null
description:
- - List of groups associated with the user I(user_name).
+ - List of groups associated with the user O(user_name).
user_disabled:
type: bool
required: false
default: null
description:
- - Enable/Disable the user I(user_name).
+ - Enable/Disable the user O(user_name).
user_gravatar:
type: bool
required: false
default: null
description:
- - Enable/Disable Gravatar usage for the user I(user_name).
+ - Enable/Disable Gravatar usage for the user O(user_name).
user_mac_addresses:
type: list
elements: str
description:
- - Allowed MAC addresses for the user I(user_name).
+ - Allowed MAC addresses for the user O(user_name).
version_added: 5.0.0
"""
diff --git a/ansible_collections/community/general/plugins/modules/pritunl_user_info.py b/ansible_collections/community/general/plugins/modules/pritunl_user_info.py
index 7b0399061..3f8f62003 100644
--- a/ansible_collections/community/general/plugins/modules/pritunl_user_info.py
+++ b/ansible_collections/community/general/plugins/modules/pritunl_user_info.py
@@ -43,7 +43,7 @@ options:
- client
- server
description:
- - Type of the user I(user_name).
+ - Type of the user O(user_name).
"""
EXAMPLES = """
diff --git a/ansible_collections/community/general/plugins/modules/profitbricks.py b/ansible_collections/community/general/plugins/modules/profitbricks.py
index c8bcceb93..875bd78c4 100644
--- a/ansible_collections/community/general/plugins/modules/profitbricks.py
+++ b/ansible_collections/community/general/plugins/modules/profitbricks.py
@@ -130,7 +130,7 @@ options:
state:
description:
- create or terminate instances
- - 'The choices available are: C(running), C(stopped), C(absent), C(present).'
+ - 'The choices available are: V(running), V(stopped), V(absent), V(present).'
type: str
default: 'present'
disk_type:
@@ -142,7 +142,6 @@ options:
requirements:
- "profitbricks"
- - "python >= 2.6"
author: Matt Baldwin (@baldwinSPC) <baldwin@stackpointcloud.com>
'''
diff --git a/ansible_collections/community/general/plugins/modules/profitbricks_datacenter.py b/ansible_collections/community/general/plugins/modules/profitbricks_datacenter.py
index a096db752..4aa1fa5ee 100644
--- a/ansible_collections/community/general/plugins/modules/profitbricks_datacenter.py
+++ b/ansible_collections/community/general/plugins/modules/profitbricks_datacenter.py
@@ -63,7 +63,7 @@ options:
state:
description:
- Create or terminate datacenters.
- - "The available choices are: C(present), C(absent)."
+ - "The available choices are: V(present), V(absent)."
type: str
required: false
default: 'present'
diff --git a/ansible_collections/community/general/plugins/modules/profitbricks_nic.py b/ansible_collections/community/general/plugins/modules/profitbricks_nic.py
index 17a30b052..9498be15d 100644
--- a/ansible_collections/community/general/plugins/modules/profitbricks_nic.py
+++ b/ansible_collections/community/general/plugins/modules/profitbricks_nic.py
@@ -65,7 +65,7 @@ options:
state:
description:
- Indicate desired state of the resource
- - "The available choices are: C(present), C(absent)."
+ - "The available choices are: V(present), V(absent)."
type: str
required: false
default: 'present'
diff --git a/ansible_collections/community/general/plugins/modules/profitbricks_volume.py b/ansible_collections/community/general/plugins/modules/profitbricks_volume.py
index f9d257b68..f623da712 100644
--- a/ansible_collections/community/general/plugins/modules/profitbricks_volume.py
+++ b/ansible_collections/community/general/plugins/modules/profitbricks_volume.py
@@ -68,7 +68,7 @@ options:
licence_type:
description:
- The licence type for the volume. This is used when the image is non-standard.
- - "The available choices are: C(LINUX), C(WINDOWS), C(UNKNOWN), C(OTHER)."
+ - "The available choices are: V(LINUX), V(WINDOWS), V(UNKNOWN), V(OTHER)."
type: str
required: false
default: UNKNOWN
@@ -113,7 +113,7 @@ options:
state:
description:
- create or terminate datacenters
- - "The available choices are: C(present), C(absent)."
+ - "The available choices are: V(present), V(absent)."
type: str
required: false
default: 'present'
diff --git a/ansible_collections/community/general/plugins/modules/profitbricks_volume_attachments.py b/ansible_collections/community/general/plugins/modules/profitbricks_volume_attachments.py
index 75cd73df3..76459515e 100644
--- a/ansible_collections/community/general/plugins/modules/profitbricks_volume_attachments.py
+++ b/ansible_collections/community/general/plugins/modules/profitbricks_volume_attachments.py
@@ -58,7 +58,7 @@ options:
state:
description:
- Indicate desired state of the resource
- - "The available choices are: C(present), C(absent)."
+ - "The available choices are: V(present), V(absent)."
type: str
required: false
default: 'present'
diff --git a/ansible_collections/community/general/plugins/modules/proxmox.py b/ansible_collections/community/general/plugins/modules/proxmox.py
index 315ee601a..47f3faa4f 100644
--- a/ansible_collections/community/general/plugins/modules/proxmox.py
+++ b/ansible_collections/community/general/plugins/modules/proxmox.py
@@ -13,9 +13,9 @@ DOCUMENTATION = '''
module: proxmox
short_description: Management of instances in Proxmox VE cluster
description:
- - allows you to create/delete/stop instances in Proxmox VE cluster
- - Starting in Ansible 2.1, it automatically detects containerization type (lxc for PVE 4, openvz for older)
- - Since community.general 4.0.0 on, there are no more default values, see I(proxmox_default_behavior).
+ - Allows you to create/delete/stop instances in Proxmox VE cluster.
+ - The module automatically detects containerization type (lxc for PVE 4, openvz for older).
+ - Since community.general 4.0.0 on, there are no more default values, see O(proxmox_default_behavior).
attributes:
check_mode:
support: none
@@ -29,45 +29,46 @@ options:
hostname:
description:
- the instance hostname
- - required only for C(state=present)
+ - required only for O(state=present)
- must be unique if vmid is not passed
type: str
ostemplate:
description:
- the template for VM creating
- - required only for C(state=present)
+ - required only for O(state=present)
type: str
disk:
description:
- This option was previously described as "hard disk size in GB for instance" however several formats describing
a lxc mount are permitted.
- - Older versions of Proxmox will accept a numeric value for size using the I(storage) parameter to automatically
+ - Older versions of Proxmox will accept a numeric value for size using the O(storage) parameter to automatically
choose which storage to allocate from, however new versions enforce the C(<STORAGE>:<SIZE>) syntax.
- "Additional options are available by using some combination of the following key-value pairs as a
comma-delimited list C([volume=]<volume> [,acl=<1|0>] [,mountoptions=<opt[;opt...]>] [,quota=<1|0>]
[,replicate=<1|0>] [,ro=<1|0>] [,shared=<1|0>] [,size=<DiskSize>])."
- See U(https://pve.proxmox.com/wiki/Linux_Container) for a full description.
- - This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(3).
+ - This option has no default unless O(proxmox_default_behavior) is set to V(compatibility); then the default is V(3).
+ - Should not be used in conjunction with O(storage).
type: str
cores:
description:
- Specify number of cores per socket.
- - This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(1).
+ - This option has no default unless O(proxmox_default_behavior) is set to V(compatibility); then the default is V(1).
type: int
cpus:
description:
- numbers of allocated cpus for instance
- - This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(1).
+ - This option has no default unless O(proxmox_default_behavior) is set to V(compatibility); then the default is V(1).
type: int
memory:
description:
- memory size in MB for instance
- - This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(512).
+ - This option has no default unless O(proxmox_default_behavior) is set to V(compatibility); then the default is V(512).
type: int
swap:
description:
- swap memory size in MB for instance
- - This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(0).
+ - This option has no default unless O(proxmox_default_behavior) is set to V(compatibility); then the default is V(0).
type: int
netif:
description:
@@ -80,6 +81,15 @@ options:
type: list
elements: str
version_added: 2.0.0
+ startup:
+ description:
+ - Specifies the startup order of the container.
+ - Use C(order=#) where C(#) is a non-negative number to define the general startup order. Shutdown in done with reverse ordering.
+ - Use C(up=#) where C(#) is in seconds, to specify a delay to wait before the next VM is started.
+ - Use C(down=#) where C(#) is in seconds, to specify a delay to wait before the next VM is stopped.
+ type: list
+ elements: str
+ version_added: 8.5.0
mounts:
description:
- specifies additional mounts (separate disks) for the container. As a hash/dictionary defining mount points
@@ -91,17 +101,26 @@ options:
onboot:
description:
- specifies whether a VM will be started during system bootup
- - This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(false).
+ - This option has no default unless O(proxmox_default_behavior) is set to V(compatibility); then the default is V(false).
type: bool
storage:
description:
- target storage
+ - Should not be used in conjunction with O(disk).
type: str
default: 'local'
+ ostype:
+ description:
+ - Specifies the C(ostype) of the LXC container.
+ - If set to V(auto), no C(ostype) will be provided on instance creation.
+ choices: ['auto', 'debian', 'devuan', 'ubuntu', 'centos', 'fedora', 'opensuse', 'archlinux', 'alpine', 'gentoo', 'nixos', 'unmanaged']
+ type: str
+ default: 'auto'
+ version_added: 8.1.0
cpuunits:
description:
- CPU weight for a VM
- - This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(1000).
+ - This option has no default unless O(proxmox_default_behavior) is set to V(compatibility); then the default is V(1000).
type: int
nameserver:
description:
@@ -114,7 +133,7 @@ options:
tags:
description:
- List of tags to apply to the container.
- - Tags must start with C([a-z0-9_]) followed by zero or more of the following characters C([a-z0-9_-+.]).
+ - Tags must start with V([a-z0-9_]) followed by zero or more of the following characters V([a-z0-9_-+.]).
- Tags are only available in Proxmox 7+.
type: list
elements: str
@@ -124,12 +143,18 @@ options:
- timeout for operations
type: int
default: 30
+ update:
+ description:
+ - If V(true), the container will be updated with new values.
+ type: bool
+ default: false
+ version_added: 8.1.0
force:
description:
- - forcing operations
- - can be used only with states C(present), C(stopped), C(restarted)
- - with C(state=present) force option allow to overwrite existing container
- - with states C(stopped) , C(restarted) allow to force stop instance
+ - Forcing operations.
+ - Can be used only with states V(present), V(stopped), V(restarted).
+ - with O(state=present) force option allow to overwrite existing container.
+ - with states V(stopped), V(restarted) allow to force stop instance.
type: bool
default: false
purge:
@@ -137,15 +162,16 @@ options:
- Remove container from all related configurations.
- For example backup jobs, replication jobs, or HA.
- Related ACLs and Firewall entries will always be removed.
- - Used with state C(absent).
+ - Used with O(state=absent).
type: bool
default: false
version_added: 2.3.0
state:
description:
- Indicate desired state of the instance
+ - V(template) was added in community.general 8.1.0.
type: str
- choices: ['present', 'started', 'absent', 'stopped', 'restarted']
+ choices: ['present', 'started', 'absent', 'stopped', 'restarted', 'template']
default: present
pubkey:
description:
@@ -154,10 +180,9 @@ options:
unprivileged:
description:
- Indicate if the container should be unprivileged.
- - >
- The default value for this parameter is C(false) but that is deprecated
- and it will be replaced with C(true) in community.general 7.0.0.
+ - The default change to V(true) in community.general 7.0.0. It used to be V(false) before.
type: bool
+ default: true
description:
description:
- Specify the description for the container. Only used on the configuration web interface.
@@ -169,15 +194,25 @@ options:
- Script that will be executed during various steps in the containers lifetime.
type: str
version_added: '0.2.0'
+ timezone:
+ description:
+ - Timezone used by the container, accepts values like V(Europe/Paris).
+ - The special value V(host) configures the same timezone used by Proxmox host.
+ type: str
+ version_added: '7.1.0'
proxmox_default_behavior:
description:
- As of community.general 4.0.0, various options no longer have default values.
These default values caused problems when users expected different behavior from Proxmox
by default or filled options which caused problems when set.
- - The value C(compatibility) (default before community.general 4.0.0) will ensure that the default values
- are used when the values are not explicitly specified by the user. The new default is C(no_defaults),
+ - The value V(compatibility) (default before community.general 4.0.0) will ensure that the default values
+ are used when the values are not explicitly specified by the user. The new default is V(no_defaults),
which makes sure these options have no defaults.
- - This affects the I(disk), I(cores), I(cpus), I(memory), I(onboot), I(swap), I(cpuunits) options.
+ - This affects the O(disk), O(cores), O(cpus), O(memory), O(onboot), O(swap), and O(cpuunits) options.
+ - >
+ This parameter is now B(deprecated) and it will be removed in community.general 10.0.0.
+ By then, the module's behavior should be to not set default values, equivalent to V(no_defaults).
+ If a consistent set of defaults is needed, the playbook or role should be responsible for setting it.
type: str
default: no_defaults
choices:
@@ -187,23 +222,25 @@ options:
clone:
description:
- ID of the container to be cloned.
- - I(description), I(hostname), and I(pool) will be copied from the cloned container if not specified.
- - The type of clone created is defined by the I(clone_type) parameter.
+ - O(description), O(hostname), and O(pool) will be copied from the cloned container if not specified.
+ - The type of clone created is defined by the O(clone_type) parameter.
- This operator is only supported for Proxmox clusters that use LXC containerization (PVE version >= 4).
type: int
version_added: 4.3.0
clone_type:
description:
- Type of the clone created.
- - C(full) creates a full clone, and I(storage) must be specified.
- - C(linked) creates a linked clone, and the cloned container must be a template container.
- - C(opportunistic) creates a linked clone if the cloned container is a template container, and a full clone if not.
- I(storage) may be specified, if not it will fall back to the default.
+ - V(full) creates a full clone, and O(storage) must be specified.
+ - V(linked) creates a linked clone, and the cloned container must be a template container.
+ - V(opportunistic) creates a linked clone if the cloned container is a template container, and a full clone if not.
+ O(storage) may be specified, if not it will fall back to the default.
type: str
choices: ['full', 'linked', 'opportunistic']
default: opportunistic
version_added: 4.3.0
author: Sergei Antipov (@UnderGreen)
+seealso:
+ - module: community.general.proxmox_vm_info
extends_documentation_fragment:
- community.general.proxmox.documentation
- community.general.proxmox.selection
@@ -222,6 +259,18 @@ EXAMPLES = r'''
hostname: example.org
ostemplate: 'local:vztmpl/ubuntu-14.04-x86_64.tar.gz'
+- name: Create new container with minimal options specifying disk storage location and size
+ community.general.proxmox:
+ vmid: 100
+ node: uk-mc02
+ api_user: root@pam
+ api_password: 1q2w3e
+ api_host: node1
+ password: 123456
+ hostname: example.org
+ ostemplate: 'local:vztmpl/ubuntu-14.04-x86_64.tar.gz'
+ disk: 'local-lvm:20'
+
- name: Create new container with hookscript and description
community.general.proxmox:
vmid: 100
@@ -300,7 +349,7 @@ EXAMPLES = r'''
api_host: node1
password: 123456
hostname: example.org
- ostemplate: local:vztmpl/ubuntu-14.04-x86_64.tar.gz'
+ ostemplate: 'local:vztmpl/ubuntu-14.04-x86_64.tar.gz'
mounts: '{"mp0":"local:8,mp=/mnt/test/"}'
- name: Create new container with minimal options defining a cpu core limit
@@ -312,9 +361,21 @@ EXAMPLES = r'''
api_host: node1
password: 123456
hostname: example.org
- ostemplate: local:vztmpl/ubuntu-14.04-x86_64.tar.gz'
+ ostemplate: 'local:vztmpl/ubuntu-14.04-x86_64.tar.gz'
cores: 2
+- name: Create new container with minimal options and same timezone as proxmox host
+ community.general.proxmox:
+ vmid: 100
+ node: uk-mc02
+ api_user: root@pam
+ api_password: 1q2w3e
+ api_host: node1
+ password: 123456
+ hostname: example.org
+ ostemplate: 'local:vztmpl/ubuntu-14.04-x86_64.tar.gz'
+ timezone: host
+
- name: Create a new container with nesting enabled and allows the use of CIFS/NFS inside the container.
community.general.proxmox:
vmid: 100
@@ -324,7 +385,7 @@ EXAMPLES = r'''
api_host: node1
password: 123456
hostname: example.org
- ostemplate: local:vztmpl/ubuntu-14.04-x86_64.tar.gz'
+ ostemplate: 'local:vztmpl/ubuntu-14.04-x86_64.tar.gz'
features:
- nesting=1
- mount=cifs,nfs
@@ -352,6 +413,16 @@ EXAMPLES = r'''
hostname: clone.example.org
storage: local
+- name: Update container configuration
+ community.general.proxmox:
+ vmid: 100
+ node: uk-mc02
+ api_user: root@pam
+ api_password: 1q2w3e
+ api_host: node1
+ netif: '{"net0":"name=eth0,gw=192.168.0.1,ip=192.168.0.3/24,bridge=vmbr0"}'
+ update: true
+
- name: Start container
community.general.proxmox:
vmid: 100
@@ -396,6 +467,23 @@ EXAMPLES = r'''
api_host: node1
state: restarted
+- name: Convert container to template
+ community.general.proxmox:
+ vmid: 100
+ api_user: root@pam
+ api_password: 1q2w3e
+ api_host: node1
+ state: template
+
+- name: Convert container to template (stop container if running)
+ community.general.proxmox:
+ vmid: 100
+ api_user: root@pam
+ api_password: 1q2w3e
+ api_host: node1
+ state: template
+ force: true
+
- name: Remove container
community.general.proxmox:
vmid: 100
@@ -427,27 +515,105 @@ class ProxmoxLxcAnsible(ProxmoxAnsible):
"""Check if the specified container is a template."""
proxmox_node = self.proxmox_api.nodes(node)
config = getattr(proxmox_node, VZ_TYPE)(vmid).config.get()
- return config['template']
+ return config.get('template', False)
+
+ def update_config(self, vmid, node, disk, cpus, memory, swap, **kwargs):
+ if VZ_TYPE != "lxc":
+ self.module.fail_json(
+ changed=False,
+ msg="Updating configuration is only supported for LXC enabled proxmox clusters.",
+ )
+
+ # Version limited features
+ minimum_version = {"tags": "6.1", "timezone": "6.3"}
+ proxmox_node = self.proxmox_api.nodes(node)
+
+ pve_version = self.version()
+
+ # Fail on unsupported features
+ for option, version in minimum_version.items():
+ if pve_version < LooseVersion(version) and option in kwargs:
+ self.module.fail_json(
+ changed=False,
+ msg="Feature {option} is only supported in PVE {version}+, and you're using PVE {pve_version}".format(
+ option=option, version=version, pve_version=pve_version
+ ),
+ )
+
+ # Remove all empty kwarg entries
+ kwargs = dict((k, v) for k, v in kwargs.items() if v is not None)
+
+ if cpus is not None:
+ kwargs["cpulimit"] = cpus
+ if disk is not None:
+ kwargs["rootfs"] = disk
+ if memory is not None:
+ kwargs["memory"] = memory
+ if swap is not None:
+ kwargs["swap"] = swap
+ if "netif" in kwargs:
+ kwargs.update(kwargs["netif"])
+ del kwargs["netif"]
+ if "mounts" in kwargs:
+ kwargs.update(kwargs["mounts"])
+ del kwargs["mounts"]
+ # LXC tags are expected to be valid and presented as a comma/semi-colon delimited string
+ if "tags" in kwargs:
+ re_tag = re.compile(r"^[a-z0-9_][a-z0-9_\-\+\.]*$")
+ for tag in kwargs["tags"]:
+ if not re_tag.match(tag):
+ self.module.fail_json(msg="%s is not a valid tag" % tag)
+ kwargs["tags"] = ",".join(kwargs["tags"])
+
+ # fetch the current config
+ current_config = getattr(proxmox_node, VZ_TYPE)(vmid).config.get()
+
+ # compare the requested config against the current
+ update_config = False
+ for (arg, value) in kwargs.items():
+ # if the arg isn't in the current config, it needs to be updated
+ if arg not in current_config:
+ update_config = True
+ break
+ # some values are lists, the order isn't always the same, so split them and compare by key
+ if isinstance(value, str):
+ current_values = current_config[arg].split(",")
+ requested_values = value.split(",")
+ for new_value in requested_values:
+ if new_value not in current_values:
+ update_config = True
+ break
+ # if it's not a list (or string) just compare the current value
+ else:
+ # some types don't match with the API, so forcing to string for comparison
+ if str(value) != str(current_config[arg]):
+ update_config = True
+ break
+
+ if update_config:
+ getattr(proxmox_node, VZ_TYPE)(vmid).config.put(vmid=vmid, node=node, **kwargs)
+ else:
+ self.module.exit_json(changed=False, msg="Container config is already up to date")
def create_instance(self, vmid, node, disk, storage, cpus, memory, swap, timeout, clone, **kwargs):
# Version limited features
minimum_version = {
- 'tags': 7,
+ 'tags': '6.1',
+ 'timezone': '6.3'
}
proxmox_node = self.proxmox_api.nodes(node)
# Remove all empty kwarg entries
kwargs = dict((k, v) for k, v in kwargs.items() if v is not None)
- version = self.version()
- pve_major_version = 3 if version < LooseVersion('4.0') else version.version[0]
+ pve_version = self.version()
# Fail on unsupported features
for option, version in minimum_version.items():
- if pve_major_version < version and option in kwargs:
- self.module.fail_json(changed=False, msg="Feature {option} is only supported in PVE {version}+, and you're using PVE {pve_major_version}".
- format(option=option, version=version, pve_major_version=pve_major_version))
+ if pve_version < LooseVersion(version) and option in kwargs:
+ self.module.fail_json(changed=False, msg="Feature {option} is only supported in PVE {version}+, and you're using PVE {pve_version}".
+ format(option=option, version=version, pve_version=pve_version))
if VZ_TYPE == 'lxc':
kwargs['cpulimit'] = cpus
@@ -474,6 +640,9 @@ class ProxmoxLxcAnsible(ProxmoxAnsible):
self.module.fail_json(msg='%s is not a valid tag' % tag)
kwargs['tags'] = ",".join(kwargs['tags'])
+ if kwargs.get('ostype') == 'auto':
+ kwargs.pop('ostype')
+
if clone is not None:
if VZ_TYPE != 'lxc':
self.module.fail_json(changed=False, msg="Clone operator is only supported for LXC enabled proxmox clusters.")
@@ -523,7 +692,7 @@ class ProxmoxLxcAnsible(ProxmoxAnsible):
return True
timeout -= 1
if timeout == 0:
- self.module.fail_json(msg='Reached timeout while waiting for creating VM. Last line in task before timeout: %s' %
+ self.module.fail_json(vmid=vmid, node=node, msg='Reached timeout while waiting for creating VM. Last line in task before timeout: %s' %
proxmox_node.tasks(taskid).log.get()[:1])
time.sleep(1)
@@ -536,7 +705,7 @@ class ProxmoxLxcAnsible(ProxmoxAnsible):
return True
timeout -= 1
if timeout == 0:
- self.module.fail_json(msg='Reached timeout while waiting for starting VM. Last line in task before timeout: %s' %
+ self.module.fail_json(vmid=vmid, taskid=taskid, msg='Reached timeout while waiting for starting VM. Last line in task before timeout: %s' %
self.proxmox_api.nodes(vm['node']).tasks(taskid).log.get()[:1])
time.sleep(1)
@@ -552,12 +721,19 @@ class ProxmoxLxcAnsible(ProxmoxAnsible):
return True
timeout -= 1
if timeout == 0:
- self.module.fail_json(msg='Reached timeout while waiting for stopping VM. Last line in task before timeout: %s' %
+ self.module.fail_json(vmid=vmid, taskid=taskid, msg='Reached timeout while waiting for stopping VM. Last line in task before timeout: %s' %
self.proxmox_api.nodes(vm['node']).tasks(taskid).log.get()[:1])
time.sleep(1)
return False
+ def convert_to_template(self, vm, vmid, timeout, force):
+ if getattr(self.proxmox_api.nodes(vm['node']), VZ_TYPE)(vmid).status.current.get()['status'] == 'running' and force:
+ self.stop_instance(vm, vmid, timeout, force)
+ # not sure why, but templating a container doesn't return a taskid
+ getattr(self.proxmox_api.nodes(vm['node']), VZ_TYPE)(vmid).template.post()
+ return True
+
def umount_instance(self, vm, vmid, timeout):
taskid = getattr(self.proxmox_api.nodes(vm['node']), VZ_TYPE)(vmid).status.umount.post()
while timeout:
@@ -565,7 +741,7 @@ class ProxmoxLxcAnsible(ProxmoxAnsible):
return True
timeout -= 1
if timeout == 0:
- self.module.fail_json(msg='Reached timeout while waiting for unmounting VM. Last line in task before timeout: %s' %
+ self.module.fail_json(vmid=vmid, taskid=taskid, msg='Reached timeout while waiting for unmounting VM. Last line in task before timeout: %s' %
self.proxmox_api.nodes(vm['node']).tasks(taskid).log.get()[:1])
time.sleep(1)
@@ -589,21 +765,28 @@ def main():
netif=dict(type='dict'),
mounts=dict(type='dict'),
ip_address=dict(),
+ ostype=dict(default='auto', choices=[
+ 'auto', 'debian', 'devuan', 'ubuntu', 'centos', 'fedora', 'opensuse', 'archlinux', 'alpine', 'gentoo', 'nixos', 'unmanaged'
+ ]),
onboot=dict(type='bool'),
features=dict(type='list', elements='str'),
+ startup=dict(type='list', elements='str'),
storage=dict(default='local'),
cpuunits=dict(type='int'),
nameserver=dict(),
searchdomain=dict(),
timeout=dict(type='int', default=30),
+ update=dict(type='bool', default=False),
force=dict(type='bool', default=False),
purge=dict(type='bool', default=False),
- state=dict(default='present', choices=['present', 'absent', 'stopped', 'started', 'restarted']),
+ state=dict(default='present', choices=['present', 'absent', 'stopped', 'started', 'restarted', 'template']),
pubkey=dict(type='str'),
- unprivileged=dict(type='bool'),
+ unprivileged=dict(type='bool', default=True),
description=dict(type='str'),
hookscript=dict(type='str'),
- proxmox_default_behavior=dict(type='str', default='no_defaults', choices=['compatibility', 'no_defaults']),
+ timezone=dict(type='str'),
+ proxmox_default_behavior=dict(type='str', default='no_defaults', choices=['compatibility', 'no_defaults'],
+ removed_in_version='9.0.0', removed_from_collection='community.general'),
clone=dict(type='int'),
clone_type=dict(default='opportunistic', choices=['full', 'linked', 'opportunistic']),
tags=dict(type='list', elements='str')
@@ -614,14 +797,15 @@ def main():
argument_spec=module_args,
required_if=[
('state', 'present', ['node', 'hostname']),
- ('state', 'present', ('clone', 'ostemplate'), True), # Require one of clone and ostemplate. Together with mutually_exclusive this ensures that we
- # either clone a container or create a new one from a template file.
+ # Require one of clone, ostemplate, or update. Together with mutually_exclusive this ensures that we
+ # either clone a container or create a new one from a template file.
+ ('state', 'present', ('clone', 'ostemplate', 'update'), True),
],
required_together=[
('api_token_id', 'api_token_secret')
],
required_one_of=[('api_password', 'api_token_id')],
- mutually_exclusive=[('clone', 'ostemplate')], # Creating a new container is done either by cloning an existing one, or based on a template.
+ mutually_exclusive=[('clone', 'ostemplate', 'update')], # Creating a new container is done either by cloning an existing one, or based on a template.
)
proxmox = ProxmoxLxcAnsible(module)
@@ -643,14 +827,6 @@ def main():
timeout = module.params['timeout']
clone = module.params['clone']
- if module.params['unprivileged'] is None:
- module.params['unprivileged'] = False
- module.deprecate(
- 'The default value `false` for the parameter "unprivileged" is deprecated and it will be replaced with `true`',
- version='7.0.0',
- collection_name='community.general'
- )
-
if module.params['proxmox_default_behavior'] == 'compatibility':
old_default_values = dict(
disk="3",
@@ -677,21 +853,59 @@ def main():
# Create a new container
if state == 'present' and clone is None:
try:
- if proxmox.get_vm(vmid, ignore_missing=True) and not module.params['force']:
- module.exit_json(changed=False, msg="VM with vmid = %s is already exists" % vmid)
+ if proxmox.get_vm(vmid, ignore_missing=True):
+ if module.params["update"]:
+ try:
+ proxmox.update_config(vmid, node, disk, cpus, memory, swap,
+ cores=module.params["cores"],
+ hostname=module.params["hostname"],
+ netif=module.params["netif"],
+ mounts=module.params["mounts"],
+ ip_address=module.params["ip_address"],
+ onboot=ansible_to_proxmox_bool(module.params["onboot"]),
+ cpuunits=module.params["cpuunits"],
+ nameserver=module.params["nameserver"],
+ searchdomain=module.params["searchdomain"],
+ features=",".join(module.params["features"])
+ if module.params["features"] is not None
+ else None,
+ startup=",".join(module.params["startup"])
+ if module.params["startup"] is not None
+ else None,
+ description=module.params["description"],
+ hookscript=module.params["hookscript"],
+ timezone=module.params["timezone"],
+ tags=module.params["tags"])
+ module.exit_json(
+ changed=True,
+ vmid=vmid,
+ msg="Configured VM %s" % (vmid),
+ )
+ except Exception as e:
+ module.fail_json(
+ vmid=vmid,
+ msg="Configuration of %s VM %s failed with exception: %s"
+ % (VZ_TYPE, vmid, e),
+ )
+ if not module.params["force"]:
+ module.exit_json(
+ changed=False,
+ vmid=vmid,
+ msg="VM with vmid = %s is already exists" % vmid,
+ )
# If no vmid was passed, there cannot be another VM named 'hostname'
if (not module.params['vmid'] and
proxmox.get_vmid(hostname, ignore_missing=True) and
not module.params['force']):
vmid = proxmox.get_vmid(hostname)
- module.exit_json(changed=False, msg="VM with hostname %s already exists and has ID number %s" % (hostname, vmid))
+ module.exit_json(changed=False, vmid=vmid, msg="VM with hostname %s already exists and has ID number %s" % (hostname, vmid))
elif not proxmox.get_node(node):
- module.fail_json(msg="node '%s' not exists in cluster" % node)
+ module.fail_json(vmid=vmid, msg="node '%s' not exists in cluster" % node)
elif not proxmox.content_check(node, module.params['ostemplate'], template_store):
- module.fail_json(msg="ostemplate '%s' not exists on node %s and storage %s"
+ module.fail_json(vmid=vmid, msg="ostemplate '%s' not exists on node %s and storage %s"
% (module.params['ostemplate'], node, template_store))
except Exception as e:
- module.fail_json(msg="Pre-creation checks of {VZ_TYPE} VM {vmid} failed with exception: {e}".format(VZ_TYPE=VZ_TYPE, vmid=vmid, e=e))
+ module.fail_json(vmid=vmid, msg="Pre-creation checks of {VZ_TYPE} VM {vmid} failed with exception: {e}".format(VZ_TYPE=VZ_TYPE, vmid=vmid, e=e))
try:
proxmox.create_instance(vmid, node, disk, storage, cpus, memory, swap, timeout, clone,
@@ -702,6 +916,7 @@ def main():
ostemplate=module.params['ostemplate'],
netif=module.params['netif'],
mounts=module.params['mounts'],
+ ostype=module.params['ostype'],
ip_address=module.params['ip_address'],
onboot=ansible_to_proxmox_bool(module.params['onboot']),
cpuunits=module.params['cpuunits'],
@@ -710,48 +925,50 @@ def main():
force=ansible_to_proxmox_bool(module.params['force']),
pubkey=module.params['pubkey'],
features=",".join(module.params['features']) if module.params['features'] is not None else None,
+ startup=",".join(module.params['startup']) if module.params['startup'] is not None else None,
unprivileged=ansible_to_proxmox_bool(module.params['unprivileged']),
description=module.params['description'],
hookscript=module.params['hookscript'],
+ timezone=module.params['timezone'],
tags=module.params['tags'])
- module.exit_json(changed=True, msg="Deployed VM %s from template %s" % (vmid, module.params['ostemplate']))
+ module.exit_json(changed=True, vmid=vmid, msg="Deployed VM %s from template %s" % (vmid, module.params['ostemplate']))
except Exception as e:
- module.fail_json(msg="Creation of %s VM %s failed with exception: %s" % (VZ_TYPE, vmid, e))
+ module.fail_json(vmid=vmid, msg="Creation of %s VM %s failed with exception: %s" % (VZ_TYPE, vmid, e))
# Clone a container
elif state == 'present' and clone is not None:
try:
if proxmox.get_vm(vmid, ignore_missing=True) and not module.params['force']:
- module.exit_json(changed=False, msg="VM with vmid = %s is already exists" % vmid)
+ module.exit_json(changed=False, vmid=vmid, msg="VM with vmid = %s is already exists" % vmid)
# If no vmid was passed, there cannot be another VM named 'hostname'
if (not module.params['vmid'] and
proxmox.get_vmid(hostname, ignore_missing=True) and
not module.params['force']):
vmid = proxmox.get_vmid(hostname)
- module.exit_json(changed=False, msg="VM with hostname %s already exists and has ID number %s" % (hostname, vmid))
+ module.exit_json(changed=False, vmid=vmid, msg="VM with hostname %s already exists and has ID number %s" % (hostname, vmid))
if not proxmox.get_vm(clone, ignore_missing=True):
- module.exit_json(changed=False, msg="Container to be cloned does not exist")
+ module.exit_json(changed=False, vmid=vmid, msg="Container to be cloned does not exist")
except Exception as e:
- module.fail_json(msg="Pre-clone checks of {VZ_TYPE} VM {vmid} failed with exception: {e}".format(VZ_TYPE=VZ_TYPE, vmid=vmid, e=e))
+ module.fail_json(vmid=vmid, msg="Pre-clone checks of {VZ_TYPE} VM {vmid} failed with exception: {e}".format(VZ_TYPE=VZ_TYPE, vmid=vmid, e=e))
try:
proxmox.create_instance(vmid, node, disk, storage, cpus, memory, swap, timeout, clone)
- module.exit_json(changed=True, msg="Cloned VM %s from %s" % (vmid, clone))
+ module.exit_json(changed=True, vmid=vmid, msg="Cloned VM %s from %s" % (vmid, clone))
except Exception as e:
- module.fail_json(msg="Cloning %s VM %s failed with exception: %s" % (VZ_TYPE, vmid, e))
+ module.fail_json(vmid=vmid, msg="Cloning %s VM %s failed with exception: %s" % (VZ_TYPE, vmid, e))
elif state == 'started':
try:
vm = proxmox.get_vm(vmid)
if getattr(proxmox.proxmox_api.nodes(vm['node']), VZ_TYPE)(vmid).status.current.get()['status'] == 'running':
- module.exit_json(changed=False, msg="VM %s is already running" % vmid)
+ module.exit_json(changed=False, vmid=vmid, msg="VM %s is already running" % vmid)
if proxmox.start_instance(vm, vmid, timeout):
- module.exit_json(changed=True, msg="VM %s started" % vmid)
+ module.exit_json(changed=True, vmid=vmid, msg="VM %s started" % vmid)
except Exception as e:
- module.fail_json(msg="starting of VM %s failed with exception: %s" % (vmid, e))
+ module.fail_json(vmid=vmid, msg="starting of VM %s failed with exception: %s" % (vmid, e))
elif state == 'stopped':
try:
@@ -760,18 +977,27 @@ def main():
if getattr(proxmox.proxmox_api.nodes(vm['node']), VZ_TYPE)(vmid).status.current.get()['status'] == 'mounted':
if module.params['force']:
if proxmox.umount_instance(vm, vmid, timeout):
- module.exit_json(changed=True, msg="VM %s is shutting down" % vmid)
+ module.exit_json(changed=True, vmid=vmid, msg="VM %s is shutting down" % vmid)
else:
- module.exit_json(changed=False, msg=("VM %s is already shutdown, but mounted. "
- "You can use force option to umount it.") % vmid)
+ module.exit_json(changed=False, vmid=vmid,
+ msg=("VM %s is already shutdown, but mounted. You can use force option to umount it.") % vmid)
if getattr(proxmox.proxmox_api.nodes(vm['node']), VZ_TYPE)(vmid).status.current.get()['status'] == 'stopped':
- module.exit_json(changed=False, msg="VM %s is already shutdown" % vmid)
+ module.exit_json(changed=False, vmid=vmid, msg="VM %s is already shutdown" % vmid)
if proxmox.stop_instance(vm, vmid, timeout, force=module.params['force']):
- module.exit_json(changed=True, msg="VM %s is shutting down" % vmid)
+ module.exit_json(changed=True, vmid=vmid, msg="VM %s is shutting down" % vmid)
+ except Exception as e:
+ module.fail_json(vmid=vmid, msg="stopping of VM %s failed with exception: %s" % (vmid, e))
+
+ elif state == 'template':
+ try:
+ vm = proxmox.get_vm(vmid)
+
+ proxmox.convert_to_template(vm, vmid, timeout, force=module.params['force'])
+ module.exit_json(changed=True, msg="VM %s is converted to template" % vmid)
except Exception as e:
- module.fail_json(msg="stopping of VM %s failed with exception: %s" % (vmid, e))
+ module.fail_json(vmid=vmid, msg="conversion of VM %s to template failed with exception: %s" % (vmid, e))
elif state == 'restarted':
try:
@@ -779,28 +1005,28 @@ def main():
vm_status = getattr(proxmox.proxmox_api.nodes(vm['node']), VZ_TYPE)(vmid).status.current.get()['status']
if vm_status in ['stopped', 'mounted']:
- module.exit_json(changed=False, msg="VM %s is not running" % vmid)
+ module.exit_json(changed=False, vmid=vmid, msg="VM %s is not running" % vmid)
if (proxmox.stop_instance(vm, vmid, timeout, force=module.params['force']) and
proxmox.start_instance(vm, vmid, timeout)):
- module.exit_json(changed=True, msg="VM %s is restarted" % vmid)
+ module.exit_json(changed=True, vmid=vmid, msg="VM %s is restarted" % vmid)
except Exception as e:
- module.fail_json(msg="restarting of VM %s failed with exception: %s" % (vmid, e))
+ module.fail_json(vmid=vmid, msg="restarting of VM %s failed with exception: %s" % (vmid, e))
elif state == 'absent':
if not vmid:
- module.exit_json(changed=False, msg='VM with hostname = %s is already absent' % hostname)
+ module.exit_json(changed=False, vmid=vmid, msg='VM with hostname = %s is already absent' % hostname)
try:
vm = proxmox.get_vm(vmid, ignore_missing=True)
if not vm:
- module.exit_json(changed=False, msg="VM %s does not exist" % vmid)
+ module.exit_json(changed=False, vmid=vmid, msg="VM %s does not exist" % vmid)
vm_status = getattr(proxmox.proxmox_api.nodes(vm['node']), VZ_TYPE)(vmid).status.current.get()['status']
if vm_status == 'running':
- module.exit_json(changed=False, msg="VM %s is running. Stop it before deletion." % vmid)
+ module.exit_json(changed=False, vmid=vmid, msg="VM %s is running. Stop it before deletion." % vmid)
if vm_status == 'mounted':
- module.exit_json(changed=False, msg="VM %s is mounted. Stop it with force option before deletion." % vmid)
+ module.exit_json(changed=False, vmid=vmid, msg="VM %s is mounted. Stop it with force option before deletion." % vmid)
delete_params = {}
@@ -811,15 +1037,15 @@ def main():
while timeout:
if proxmox.api_task_ok(vm['node'], taskid):
- module.exit_json(changed=True, msg="VM %s removed" % vmid)
+ module.exit_json(changed=True, vmid=vmid, taskid=taskid, msg="VM %s removed" % vmid)
timeout -= 1
if timeout == 0:
- module.fail_json(msg='Reached timeout while waiting for removing VM. Last line in task before timeout: %s'
+ module.fail_json(vmid=vmid, taskid=taskid, msg='Reached timeout while waiting for removing VM. Last line in task before timeout: %s'
% proxmox.proxmox_api.nodes(vm['node']).tasks(taskid).log.get()[:1])
time.sleep(1)
except Exception as e:
- module.fail_json(msg="deletion of VM %s failed with exception: %s" % (vmid, to_native(e)))
+ module.fail_json(vmid=vmid, msg="deletion of VM %s failed with exception: %s" % (vmid, to_native(e)))
if __name__ == '__main__':
diff --git a/ansible_collections/community/general/plugins/modules/proxmox_disk.py b/ansible_collections/community/general/plugins/modules/proxmox_disk.py
index df6735cc0..69a7300df 100644
--- a/ansible_collections/community/general/plugins/modules/proxmox_disk.py
+++ b/ansible_collections/community/general/plugins/modules/proxmox_disk.py
@@ -25,17 +25,17 @@ options:
name:
description:
- The unique name of the VM.
- - You can specify either I(name) or I(vmid) or both of them.
+ - You can specify either O(name) or O(vmid) or both of them.
type: str
vmid:
description:
- The unique ID of the VM.
- - You can specify either I(vmid) or I(name) or both of them.
+ - You can specify either O(vmid) or O(name) or both of them.
type: int
disk:
description:
- - The disk key (C(unused[n]), C(ide[n]), C(sata[n]), C(scsi[n]) or C(virtio[n])) you want to operate on.
- - Disk buses (IDE, SATA and so on) have fixed ranges of C(n) that accepted by Proxmox API.
+ - The disk key (V(unused[n]), V(ide[n]), V(sata[n]), V(scsi[n]) or V(virtio[n])) you want to operate on.
+ - Disk buses (IDE, SATA and so on) have fixed ranges of V(n) that accepted by Proxmox API.
- >
For IDE: 0-3;
for SCSI: 0-30;
@@ -48,79 +48,79 @@ options:
description:
- Indicates desired state of the disk.
- >
- I(state=present) can be used to create, replace disk or update options in existing disk. It will create missing
- disk or update options in existing one by default. See the I(create) parameter description to control behavior
+ O(state=present) can be used to create, replace disk or update options in existing disk. It will create missing
+ disk or update options in existing one by default. See the O(create) parameter description to control behavior
of this option.
- - Some updates on options (like I(cache)) are not being applied instantly and require VM restart.
+ - Some updates on options (like O(cache)) are not being applied instantly and require VM restart.
- >
- Use I(state=detached) to detach existing disk from VM but do not remove it entirely.
- When I(state=detached) and disk is C(unused[n]) it will be left in same state (not removed).
+ Use O(state=detached) to detach existing disk from VM but do not remove it entirely.
+ When O(state=detached) and disk is V(unused[n]) it will be left in same state (not removed).
- >
- I(state=moved) may be used to change backing storage for the disk in bounds of the same VM
+ O(state=moved) may be used to change backing storage for the disk in bounds of the same VM
or to send the disk to another VM (using the same backing storage).
- >
- I(state=resized) intended to change the disk size. As of Proxmox 7.2 you can only increase the disk size
+ O(state=resized) intended to change the disk size. As of Proxmox 7.2 you can only increase the disk size
because shrinking disks is not supported by the PVE API and has to be done manually.
- - To entirely remove the disk from backing storage use I(state=absent).
+ - To entirely remove the disk from backing storage use O(state=absent).
type: str
choices: ['present', 'resized', 'detached', 'moved', 'absent']
default: present
create:
description:
- - With I(create) flag you can control behavior of I(state=present).
- - When I(create=disabled) it will not create new disk (if not exists) but will update options in existing disk.
- - When I(create=regular) it will either create new disk (if not exists) or update options in existing disk.
- - When I(create=forced) it will always create new disk (if disk exists it will be detached and left unused).
+ - With O(create) flag you can control behavior of O(state=present).
+ - When O(create=disabled) it will not create new disk (if not exists) but will update options in existing disk.
+ - When O(create=regular) it will either create new disk (if not exists) or update options in existing disk.
+ - When O(create=forced) it will always create new disk (if disk exists it will be detached and left unused).
type: str
choices: ['disabled', 'regular', 'forced']
default: regular
storage:
description:
- The drive's backing storage.
- - Used only when I(state) is C(present).
+ - Used only when O(state) is V(present).
type: str
size:
description:
- - Desired volume size in GB to allocate when I(state=present) (specify I(size) without suffix).
+ - Desired volume size in GB to allocate when O(state=present) (specify O(size) without suffix).
- >
- New (or additional) size of volume when I(state=resized). With the C(+) sign
+ New (or additional) size of volume when O(state=resized). With the V(+) sign
the value is added to the actual size of the volume
and without it, the value is taken as an absolute one.
type: str
bwlimit:
description:
- Override I/O bandwidth limit (in KB/s).
- - Used only when I(state=moved).
+ - Used only when O(state=moved).
type: int
delete_moved:
description:
- Delete the original disk after successful copy.
- By default the original disk is kept as unused disk.
- - Used only when I(state=moved).
+ - Used only when O(state=moved).
type: bool
target_disk:
description:
- - The config key the disk will be moved to on the target VM (for example, C(ide0) or C(scsi1)).
+ - The config key the disk will be moved to on the target VM (for example, V(ide0) or V(scsi1)).
- Default is the source disk key.
- - Used only when I(state=moved).
+ - Used only when O(state=moved).
type: str
target_storage:
description:
- - Move the disk to this storage when I(state=moved).
+ - Move the disk to this storage when O(state=moved).
- You can move between storages only in scope of one VM.
- - Mutually exclusive with I(target_vmid).
- - Consider increasing I(timeout) in case of large disk images or slow storage backend.
+ - Mutually exclusive with O(target_vmid).
+ - Consider increasing O(timeout) in case of large disk images or slow storage backend.
type: str
target_vmid:
description:
- - The (unique) ID of the VM where disk will be placed when I(state=moved).
+ - The (unique) ID of the VM where disk will be placed when O(state=moved).
- You can move disk between VMs only when the same storage is used.
- - Mutually exclusive with I(target_vmid).
+ - Mutually exclusive with O(target_vmid).
type: int
timeout:
description:
- Timeout in seconds to wait for slow operations such as importing disk or moving disk between storages.
- - Used only when I(state) is C(present) or C(moved).
+ - Used only when O(state) is V(present) or V(moved).
type: int
default: 600
aio:
@@ -177,13 +177,13 @@ options:
- Volume string format
- C(<STORAGE>:<VMID>/<FULL_NAME>) or C(<ABSOLUTE_PATH>/<FULL_NAME>)
- Attention! Only root can use absolute paths.
- - This parameter is mutually exclusive with I(size).
- - Increase I(timeout) parameter when importing large disk images or using slow storage.
+ - This parameter is mutually exclusive with O(size).
+ - Increase O(timeout) parameter when importing large disk images or using slow storage.
type: str
iops:
description:
- Maximum total r/w I/O in operations per second.
- - You can specify either total limit or per operation (mutually exclusive with I(iops_rd) and I(iops_wr)).
+ - You can specify either total limit or per operation (mutually exclusive with O(iops_rd) and O(iops_wr)).
type: int
iops_max:
description:
@@ -196,7 +196,7 @@ options:
iops_rd:
description:
- Maximum read I/O in operations per second.
- - You can specify either read or total limit (mutually exclusive with I(iops)).
+ - You can specify either read or total limit (mutually exclusive with O(iops)).
type: int
iops_rd_max:
description:
@@ -209,7 +209,7 @@ options:
iops_wr:
description:
- Maximum write I/O in operations per second.
- - You can specify either write or total limit (mutually exclusive with I(iops)).
+ - You can specify either write or total limit (mutually exclusive with O(iops)).
type: int
iops_wr_max:
description:
@@ -227,7 +227,7 @@ options:
description:
- Maximum total r/w speed in megabytes per second.
- Can be fractional but use with caution - fractionals less than 1 are not supported officially.
- - You can specify either total limit or per operation (mutually exclusive with I(mbps_rd) and I(mbps_wr)).
+ - You can specify either total limit or per operation (mutually exclusive with O(mbps_rd) and O(mbps_wr)).
type: float
mbps_max:
description:
@@ -236,7 +236,7 @@ options:
mbps_rd:
description:
- Maximum read speed in megabytes per second.
- - You can specify either read or total limit (mutually exclusive with I(mbps)).
+ - You can specify either read or total limit (mutually exclusive with O(mbps)).
type: float
mbps_rd_max:
description:
@@ -245,7 +245,7 @@ options:
mbps_wr:
description:
- Maximum write speed in megabytes per second.
- - You can specify either write or total limit (mutually exclusive with I(mbps)).
+ - You can specify either write or total limit (mutually exclusive with O(mbps)).
type: float
mbps_wr_max:
description:
@@ -256,6 +256,16 @@ options:
- The drive's media type.
type: str
choices: ['cdrom', 'disk']
+ iso_image:
+ description:
+ - The ISO image to be mounted on the specified in O(disk) CD-ROM.
+ - O(media=cdrom) needs to be specified for this option to work.
+ - "Image string format:"
+ - V(<STORAGE>:iso/<ISO_NAME>) to mount ISO.
+ - V(cdrom) to use physical CD/DVD drive.
+ - V(none) to unmount image from existent CD-ROM or create empty CD-ROM drive.
+ type: str
+ version_added: 8.1.0
queues:
description:
- Number of queues (SCSI only).
@@ -312,7 +322,7 @@ options:
choices: ['enospc', 'ignore', 'report', 'stop']
wwn:
description:
- - The drive's worldwide name, encoded as 16 bytes hex string, prefixed by C(0x).
+ - The drive's worldwide name, encoded as 16 bytes hex string, prefixed by V(0x).
type: str
extends_documentation_fragment:
- community.general.proxmox.documentation
@@ -412,6 +422,18 @@ EXAMPLES = '''
vmid: 101
disk: scsi4
state: absent
+
+- name: Mount ISO image on CD-ROM (create drive if missing)
+ community.general.proxmox_disk:
+ api_host: node1
+ api_user: root@pam
+ api_token_id: token1
+ api_token_secret: some-token-data
+ vmid: 101
+ disk: ide2
+ media: cdrom
+ iso_image: local:iso/favorite_distro_amd64.iso
+ state: present
'''
RETURN = '''
@@ -435,17 +457,41 @@ from time import sleep
def disk_conf_str_to_dict(config_string):
+ """
+ Transform Proxmox configuration string for disk element into dictionary which has
+ volume option parsed in '{ storage }:{ volume }' format and other options parsed
+ in '{ option }={ value }' format. This dictionary will be compared afterward with
+ attributes that user passed to this module in playbook.\n
+ config_string examples:
+ - local-lvm:vm-100-disk-0,ssd=1,discard=on,size=25G
+ - local:iso/new-vm-ignition.iso,media=cdrom,size=70k
+ - none,media=cdrom
+ :param config_string: Retrieved from Proxmox API configuration string
+ :return: Dictionary with volume option divided into parts ('volume_name', 'storage_name', 'volume') \n
+ and other options as key:value.
+ """
config = config_string.split(',')
- storage_volume = config.pop(0).split(':')
- config.sort()
- storage_name = storage_volume[0]
- volume_name = storage_volume[1]
- config_current = dict(
- volume='%s:%s' % (storage_name, volume_name),
- storage_name=storage_name,
- volume_name=volume_name
- )
+ # When empty CD-ROM drive present, the volume part of config string is "none".
+ storage_volume = config.pop(0)
+ if storage_volume in ["none", "cdrom"]:
+ config_current = dict(
+ volume=storage_volume,
+ storage_name=None,
+ volume_name=None,
+ size=None,
+ )
+ else:
+ storage_volume = storage_volume.split(':')
+ storage_name = storage_volume[0]
+ volume_name = storage_volume[1]
+ config_current = dict(
+ volume='%s:%s' % (storage_name, volume_name),
+ storage_name=storage_name,
+ volume_name=volume_name,
+ )
+
+ config.sort()
for option in config:
k, v = option.split('=')
config_current[k] = v
@@ -497,41 +543,61 @@ class ProxmoxDiskAnsible(ProxmoxAnsible):
if (create == 'regular' and disk not in vm_config) or (create == 'forced'):
# CREATE
- attributes = self.get_create_attributes()
- import_string = attributes.pop('import_from', None)
+ playbook_config = self.get_create_attributes()
+ import_string = playbook_config.pop('import_from', None)
+ iso_image = self.module.params.get('iso_image', None)
if import_string:
+ # When 'import_from' option is present in task options.
config_str = "%s:%s,import-from=%s" % (self.module.params["storage"], "0", import_string)
timeout_str = "Reached timeout while importing VM disk. Last line in task before timeout: %s"
ok_str = "Disk %s imported into VM %s"
+ elif iso_image is not None:
+ # disk=<busN>, media=cdrom, iso_image=<ISO_NAME>
+ config_str = iso_image
+ ok_str = "CD-ROM was created on %s bus in VM %s"
else:
- config_str = "%s:%s" % (self.module.params["storage"], self.module.params["size"])
+ config_str = self.module.params["storage"]
+ if self.module.params.get("media") != "cdrom":
+ config_str += ":%s" % (self.module.params["size"])
ok_str = "Disk %s created in VM %s"
timeout_str = "Reached timeout while creating VM disk. Last line in task before timeout: %s"
- for k, v in attributes.items():
+ for k, v in playbook_config.items():
config_str += ',%s=%s' % (k, v)
disk_config_to_apply = {self.module.params["disk"]: config_str}
if create in ['disabled', 'regular'] and disk in vm_config:
# UPDATE
- disk_config = disk_conf_str_to_dict(vm_config[disk])
- config_str = disk_config["volume"]
ok_str = "Disk %s updated in VM %s"
- attributes = self.get_create_attributes()
+ iso_image = self.module.params.get('iso_image', None)
+
+ proxmox_config = disk_conf_str_to_dict(vm_config[disk])
# 'import_from' fails on disk updates
- attributes.pop('import_from', None)
+ playbook_config = self.get_create_attributes()
+ playbook_config.pop('import_from', None)
- for k, v in attributes.items():
+ # Begin composing configuration string
+ if iso_image is not None:
+ config_str = iso_image
+ else:
+ config_str = proxmox_config["volume"]
+ # Append all mandatory fields from playbook_config
+ for k, v in playbook_config.items():
config_str += ',%s=%s' % (k, v)
- # Now compare old and new config to detect if changes are needed
+ # Append to playbook_config fields which are constants for disk images
for option in ['size', 'storage_name', 'volume', 'volume_name']:
- attributes.update({option: disk_config[option]})
+ playbook_config.update({option: proxmox_config[option]})
+ # CD-ROM is special disk device and its disk image is subject to change
+ if iso_image is not None:
+ playbook_config['volume'] = iso_image
# Values in params are numbers, but strings are needed to compare with disk_config
- attributes = dict((k, str(v)) for k, v in attributes.items())
- if disk_config == attributes:
+ playbook_config = dict((k, str(v)) for k, v in playbook_config.items())
+
+ # Now compare old and new config to detect if changes are needed
+ if proxmox_config == playbook_config:
return False, "Disk %s is up to date in VM %s" % (disk, vmid)
disk_config_to_apply = {self.module.params["disk"]: config_str}
@@ -600,6 +666,7 @@ def main():
iops_wr_max=dict(type='int'),
iops_wr_max_length=dict(type='int'),
iothread=dict(type='bool'),
+ iso_image=dict(type='str'),
mbps=dict(type='float'),
mbps_max=dict(type='float'),
mbps_rd=dict(type='float'),
@@ -664,6 +731,7 @@ def main():
'iops_max_length': 'iops_max',
'iops_rd_max_length': 'iops_rd_max',
'iops_wr_max_length': 'iops_wr_max',
+ 'iso_image': 'media',
},
supports_check_mode=False,
mutually_exclusive=[
diff --git a/ansible_collections/community/general/plugins/modules/proxmox_kvm.py b/ansible_collections/community/general/plugins/modules/proxmox_kvm.py
index 1dba5f4ea..8779dcdc1 100644
--- a/ansible_collections/community/general/plugins/modules/proxmox_kvm.py
+++ b/ansible_collections/community/general/plugins/modules/proxmox_kvm.py
@@ -14,7 +14,7 @@ module: proxmox_kvm
short_description: Management of Qemu(KVM) Virtual Machines in Proxmox VE cluster
description:
- Allows you to create/delete/stop Qemu(KVM) Virtual Machines in Proxmox VE cluster.
- - Since community.general 4.0.0 on, there are no more default values, see I(proxmox_default_behavior).
+ - Since community.general 4.0.0 on, there are no more default values, see O(proxmox_default_behavior).
author: "Abdoul Bah (@helldorado) <bahabdoul at gmail.com>"
attributes:
check_mode:
@@ -30,31 +30,31 @@ options:
acpi:
description:
- Specify if ACPI should be enabled/disabled.
- - This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(true).
+ - This option has no default unless O(proxmox_default_behavior) is set to V(compatibility); then the default is V(true).
type: bool
agent:
description:
- Specify if the QEMU Guest Agent should be enabled/disabled.
- Since community.general 5.5.0, this can also be a string instead of a boolean.
- This allows to specify values such as C(enabled=1,fstrim_cloned_disks=1).
+ This allows to specify values such as V(enabled=1,fstrim_cloned_disks=1).
type: str
args:
description:
- Pass arbitrary arguments to kvm.
- This option is for experts only!
- - If I(proxmox_default_behavior) is set to C(compatiblity), this option has a default of
- C(-serial unix:/var/run/qemu-server/<vmid>.serial,server,nowait).
+ - If O(proxmox_default_behavior) is set to V(compatibility), this option has a default of
+ V(-serial unix:/var/run/qemu-server/<vmid>.serial,server,nowait).
type: str
autostart:
description:
- Specify if the VM should be automatically restarted after crash (currently ignored in PVE API).
- - This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(false).
+ - This option has no default unless O(proxmox_default_behavior) is set to V(compatibility); then the default is V(false).
type: bool
balloon:
description:
- Specify the amount of RAM for the VM in MB.
- Using zero disables the balloon driver.
- - This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(0).
+ - This option has no default unless O(proxmox_default_behavior) is set to V(compatibility); then the default is V(0).
type: int
bios:
description:
@@ -63,13 +63,14 @@ options:
choices: ['seabios', 'ovmf']
boot:
description:
- - Specify the boot order -> boot on floppy C(a), hard disk C(c), CD-ROM C(d), or network C(n).
+ - Specify the boot order -> boot on floppy V(a), hard disk V(c), CD-ROM V(d), or network V(n).
+ - For newer versions of Proxmox VE, use a boot order like V(order=scsi0;net0;hostpci0).
- You can combine to set order.
- - This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(cnd).
+ - This option has no default unless O(proxmox_default_behavior) is set to V(compatibility); then the default is V(cnd).
type: str
bootdisk:
description:
- - Enable booting from specified disk. C((ide|sata|scsi|virtio)\d+)
+ - 'Enable booting from specified disk. Format V((ide|sata|scsi|virtio\)\\d+).'
type: str
cicustom:
description:
@@ -84,8 +85,8 @@ options:
citype:
description:
- 'cloud-init: Specifies the cloud-init configuration format.'
- - The default depends on the configured operating system type (C(ostype)).
- - We use the C(nocloud) format for Linux, and C(configdrive2) for Windows.
+ - The default depends on the configured operating system type (V(ostype)).
+ - We use the V(nocloud) format for Linux, and V(configdrive2) for Windows.
type: str
choices: ['nocloud', 'configdrive2']
version_added: 1.3.0
@@ -96,17 +97,17 @@ options:
version_added: 1.3.0
clone:
description:
- - Name of VM to be cloned. If I(vmid) is set, I(clone) can take an arbitrary value but is required for initiating the clone.
+ - Name of VM to be cloned. If O(vmid) is set, O(clone) can take an arbitrary value but is required for initiating the clone.
type: str
cores:
description:
- Specify number of cores per socket.
- - This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(1).
+ - This option has no default unless O(proxmox_default_behavior) is set to V(compatibility); then the default is V(1).
type: int
cpu:
description:
- Specify emulated CPU type.
- - This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(kvm64).
+ - This option has no default unless O(proxmox_default_behavior) is set to V(compatibility); then the default is V(kvm64).
type: str
cpulimit:
description:
@@ -117,7 +118,7 @@ options:
description:
- Specify CPU weight for a VM.
- You can disable fair-scheduler configuration by setting this to 0
- - This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(1000).
+ - This option has no default unless O(proxmox_default_behavior) is set to V(compatibility); then the default is V(1000).
type: int
delete:
description:
@@ -136,24 +137,24 @@ options:
efidisk0:
description:
- Specify a hash/dictionary of EFI disk options.
- - Requires I(bios=ovmf) to be set to be able to use it.
+ - Requires O(bios=ovmf) to be set to be able to use it.
type: dict
suboptions:
storage:
description:
- - C(storage) is the storage identifier where to create the disk.
+ - V(storage) is the storage identifier where to create the disk.
type: str
format:
description:
- - C(format) is the drive's backing file's data format. Please refer to the Proxmox VE Administrator Guide,
+ - V(format) is the drive's backing file's data format. Please refer to the Proxmox VE Administrator Guide,
section Proxmox VE Storage (see U(https://pve.proxmox.com/pve-docs/chapter-pvesm.html) for the latest
version, tables 3 to 14) to find out format supported by the provided storage backend.
type: str
efitype:
description:
- - C(efitype) indicates the size of the EFI disk.
- - C(2m) will allow for a 2MB EFI disk, which will be enough to persist boot order and new boot entries.
- - C(4m) will allow for a 4MB EFI disk, which will additionally allow to store EFI keys in order to enable
+ - V(efitype) indicates the size of the EFI disk.
+ - V(2m) will allow for a 2MB EFI disk, which will be enough to persist boot order and new boot entries.
+ - V(4m) will allow for a 4MB EFI disk, which will additionally allow to store EFI keys in order to enable
Secure Boot
type: str
choices:
@@ -161,27 +162,27 @@ options:
- 4m
pre_enrolled_keys:
description:
- - C(pre_enrolled_keys) indicates whether EFI keys for Secure Boot should be enrolled C(1) in the VM firmware
+ - V(pre_enrolled_keys) indicates whether EFI keys for Secure Boot should be enrolled V(1) in the VM firmware
upon creation or not (0).
- - If set to C(1), Secure Boot will also be enabled by default when the VM is created.
+ - If set to V(1), Secure Boot will also be enabled by default when the VM is created.
type: bool
version_added: 4.5.0
force:
description:
- Allow to force stop VM.
- - Can be used with states C(stopped), C(restarted) and C(absent).
- - This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(false).
+ - Can be used with states V(stopped), V(restarted), and V(absent).
+ - This option has no default unless O(proxmox_default_behavior) is set to V(compatibility); then the default is V(false).
type: bool
format:
description:
- Target drive's backing file's data format.
- Used only with clone
- - Use I(format=unspecified) and I(full=false) for a linked clone.
+ - Use O(format=unspecified) and O(full=false) for a linked clone.
- Please refer to the Proxmox VE Administrator Guide, section Proxmox VE Storage (see
U(https://pve.proxmox.com/pve-docs/chapter-pvesm.html) for the latest version, tables 3 to 14) to find out format
supported by the provided storage backend.
- - This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(qcow2).
- If I(proxmox_default_behavior) is set to C(no_defaults), not specifying this option is equivalent to setting it to C(unspecified).
+ - This option has no default unless O(proxmox_default_behavior) is set to V(compatibility); then the default is V(qcow2).
+ If O(proxmox_default_behavior) is set to V(no_defaults), not specifying this option is equivalent to setting it to V(unspecified).
type: str
choices: [ "cloop", "cow", "qcow", "qcow2", "qed", "raw", "vmdk", "unspecified" ]
freeze:
@@ -195,22 +196,27 @@ options:
- Used only with clone
type: bool
default: true
+ hookscript:
+ description:
+ - Script that will be executed during various steps in the containers lifetime.
+ type: str
+ version_added: 8.1.0
hostpci:
description:
- - Specify a hash/dictionary of map host pci devices into guest. C(hostpci='{"key":"value", "key":"value"}').
+ - Specify a hash/dictionary of map host pci devices into guest. O(hostpci='{"key":"value", "key":"value"}').
- Keys allowed are - C(hostpci[n]) where 0 ≤ n ≤ N.
- Values allowed are - C("host="HOSTPCIID[;HOSTPCIID2...]",pcie="1|0",rombar="1|0",x-vga="1|0"").
- The C(host) parameter is Host PCI device pass through. HOSTPCIID syntax is C(bus:dev.func) (hexadecimal numbers).
- - C(pcie=boolean) I(default=0) Choose the PCI-express bus (needs the q35 machine model).
- - C(rombar=boolean) I(default=1) Specify whether or not the device's ROM will be visible in the guest's memory map.
- - C(x-vga=boolean) I(default=0) Enable vfio-vga device support.
+ - C(pcie=boolean) C(default=0) Choose the PCI-express bus (needs the q35 machine model).
+ - C(rombar=boolean) C(default=1) Specify whether or not the device's ROM will be visible in the guest's memory map.
+ - C(x-vga=boolean) C(default=0) Enable vfio-vga device support.
- /!\ This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
type: dict
hotplug:
description:
- Selectively enable hotplug features.
- - This is a comma separated list of hotplug features C('network', 'disk', 'cpu', 'memory' and 'usb').
- - Value 0 disables hotplug completely and value 1 is an alias for the default C('network,disk,usb').
+ - This is a comma separated list of hotplug features V(network), V(disk), V(cpu), V(memory), and V(usb).
+ - Value 0 disables hotplug completely and value 1 is an alias for the default V(network,disk,usb).
type: str
hugepages:
description:
@@ -219,7 +225,7 @@ options:
choices: ['any', '2', '1024']
ide:
description:
- - A hash/dictionary of volume used as IDE hard disk or CD-ROM. C(ide='{"key":"value", "key":"value"}').
+ - A hash/dictionary of volume used as IDE hard disk or CD-ROM. O(ide='{"key":"value", "key":"value"}').
- Keys allowed are - C(ide[n]) where 0 ≤ n ≤ 3.
- Values allowed are - C("storage:size,format=value").
- C(storage) is the storage identifier where to create the disk.
@@ -231,7 +237,7 @@ options:
ipconfig:
description:
- 'cloud-init: Set the IP configuration.'
- - A hash/dictionary of network ip configurations. C(ipconfig='{"key":"value", "key":"value"}').
+ - A hash/dictionary of network ip configurations. O(ipconfig='{"key":"value", "key":"value"}').
- Keys allowed are - C(ipconfig[n]) where 0 ≤ n ≤ network interfaces.
- Values allowed are - C("[gw=<GatewayIPv4>] [,gw6=<GatewayIPv6>] [,ip=<IPv4Format/CIDR>] [,ip6=<IPv6Format/CIDR>]").
- 'cloud-init: Specify IP addresses and gateways for the corresponding interface.'
@@ -248,7 +254,7 @@ options:
kvm:
description:
- Enable/disable KVM hardware virtualization.
- - This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(true).
+ - This option has no default unless O(proxmox_default_behavior) is set to V(compatibility); then the default is V(true).
type: bool
localtime:
description:
@@ -263,13 +269,19 @@ options:
machine:
description:
- Specifies the Qemu machine type.
- - type => C((pc|pc(-i440fx)?-\d+\.\d+(\.pxe)?|q35|pc-q35-\d+\.\d+(\.pxe)?))
+ - 'Type => V((pc|pc(-i440fx\)?-\\d+\\.\\d+(\\.pxe\)?|q35|pc-q35-\\d+\\.\\d+(\\.pxe\)?\)).'
type: str
memory:
description:
- Memory size in MB for instance.
- - This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(512).
+ - This option has no default unless O(proxmox_default_behavior) is set to V(compatibility); then the default is V(512).
type: int
+ migrate:
+ description:
+ - Migrate the VM to O(node) if it is on another node.
+ type: bool
+ default: false
+ version_added: 7.0.0
migrate_downtime:
description:
- Sets maximum tolerated downtime (in seconds) for migrations.
@@ -281,8 +293,9 @@ options:
type: int
name:
description:
- - Specifies the VM name. Only used on the configuration web interface.
- - Required only for C(state=present).
+ - Specifies the VM name. Name could be non-unique across the cluster.
+ - Required only for O(state=present).
+ - With O(state=present) if O(vmid) not provided and VM with name exists in the cluster then no changes will be made.
type: str
nameservers:
description:
@@ -293,7 +306,7 @@ options:
version_added: 1.3.0
net:
description:
- - A hash/dictionary of network interfaces for the VM. C(net='{"key":"value", "key":"value"}').
+ - A hash/dictionary of network interfaces for the VM. O(net='{"key":"value", "key":"value"}').
- Keys allowed are - C(net[n]) where 0 ≤ n ≤ N.
- Values allowed are - C("model="XX:XX:XX:XX:XX:XX",bridge="value",rate="value",tag="value",firewall="1|0",trunks="vlanid"").
- Model is one of C(e1000 e1000-82540em e1000-82544gc e1000-82545em i82551 i82557b i82559er ne2k_isa ne2k_pci pcnet rtl8139 virtio vmxnet3).
@@ -309,7 +322,7 @@ options:
type: int
numa:
description:
- - A hash/dictionaries of NUMA topology. C(numa='{"key":"value", "key":"value"}').
+ - A hash/dictionaries of NUMA topology. O(numa='{"key":"value", "key":"value"}').
- Keys allowed are - C(numa[n]) where 0 ≤ n ≤ N.
- Values allowed are - C("cpu="<id[-id];...>",hostnodes="<id[-id];...>",memory="number",policy="(bind|interleave|preferred)"").
- C(cpus) CPUs accessing this NUMA node.
@@ -324,18 +337,18 @@ options:
onboot:
description:
- Specifies whether a VM will be started during system bootup.
- - This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(true).
+ - This option has no default unless O(proxmox_default_behavior) is set to V(compatibility); then the default is V(true).
type: bool
ostype:
description:
- Specifies guest operating system. This is used to enable special optimization/features for specific operating systems.
- The l26 is Linux 2.6/3.X Kernel.
- - This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(l26).
+ - This option has no default unless O(proxmox_default_behavior) is set to V(compatibility); then the default is V(l26).
type: str
choices: ['other', 'wxp', 'w2k', 'w2k3', 'w2k8', 'wvista', 'win7', 'win8', 'win10', 'win11', 'l24', 'l26', 'solaris']
parallel:
description:
- - A hash/dictionary of map host parallel devices. C(parallel='{"key":"value", "key":"value"}').
+ - A hash/dictionary of map host parallel devices. O(parallel='{"key":"value", "key":"value"}').
- Keys allowed are - (parallel[n]) where 0 ≤ n ≤ 2.
- Values allowed are - C("/dev/parport\d+|/dev/usb/lp\d+").
type: dict
@@ -345,7 +358,7 @@ options:
type: bool
reboot:
description:
- - Allow reboot. If set to C(true), the VM exit on reboot.
+ - Allow reboot. If set to V(true), the VM exit on reboot.
type: bool
revert:
description:
@@ -353,7 +366,7 @@ options:
type: str
sata:
description:
- - A hash/dictionary of volume used as sata hard disk or CD-ROM. C(sata='{"key":"value", "key":"value"}').
+ - A hash/dictionary of volume used as sata hard disk or CD-ROM. O(sata='{"key":"value", "key":"value"}').
- Keys allowed are - C(sata[n]) where 0 ≤ n ≤ 5.
- Values allowed are - C("storage:size,format=value").
- C(storage) is the storage identifier where to create the disk.
@@ -364,8 +377,8 @@ options:
type: dict
scsi:
description:
- - A hash/dictionary of volume used as SCSI hard disk or CD-ROM. C(scsi='{"key":"value", "key":"value"}').
- - Keys allowed are - C(sata[n]) where 0 ≤ n ≤ 13.
+ - A hash/dictionary of volume used as SCSI hard disk or CD-ROM. O(scsi='{"key":"value", "key":"value"}').
+ - Keys allowed are - C(scsi[n]) where 0 ≤ n ≤ 13.
- Values allowed are - C("storage:size,format=value").
- C(storage) is the storage identifier where to create the disk.
- C(size) is the size of the disk in GB.
@@ -387,9 +400,9 @@ options:
version_added: 1.3.0
serial:
description:
- - A hash/dictionary of serial device to create inside the VM. C('{"key":"value", "key":"value"}').
+ - A hash/dictionary of serial device to create inside the VM. V('{"key":"value", "key":"value"}').
- Keys allowed are - serial[n](str; required) where 0 ≤ n ≤ 3.
- - Values allowed are - C((/dev/.+|socket)).
+ - Values allowed are - V((/dev/.+|socket\)).
- /!\ If you pass through a host serial device, it is no longer possible to migrate such machines - use with special care.
type: dict
shares:
@@ -407,6 +420,14 @@ options:
smbios:
description:
- Specifies SMBIOS type 1 fields.
+ - "Comma separated, Base64 encoded (optional) SMBIOS properties:"
+ - V([base64=<1|0>] [,family=<Base64 encoded string>])
+ - V([,manufacturer=<Base64 encoded string>])
+ - V([,product=<Base64 encoded string>])
+ - V([,serial=<Base64 encoded string>])
+ - V([,sku=<Base64 encoded string>])
+ - V([,uuid=<UUID>])
+ - V([,version=<Base64 encoded string>])
type: str
snapname:
description:
@@ -415,7 +436,7 @@ options:
sockets:
description:
- Sets the number of CPU sockets. (1 - N).
- - This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(1).
+ - This option has no default unless O(proxmox_default_behavior) is set to V(compatibility); then the default is V(1).
type: int
sshkeys:
description:
@@ -425,20 +446,21 @@ options:
startdate:
description:
- Sets the initial date of the real time clock.
- - Valid format for date are C('now') or C('2016-09-25T16:01:21') or C('2016-09-25').
+ - Valid format for date are V('now') or V('2016-09-25T16:01:21') or V('2016-09-25').
type: str
startup:
description:
- - Startup and shutdown behavior. C([[order=]\d+] [,up=\d+] [,down=\d+]).
+ - Startup and shutdown behavior. V([[order=]\\d+] [,up=\\d+] [,down=\\d+]).
- Order is a non-negative number defining the general startup order.
- Shutdown in done with reverse ordering.
type: str
state:
description:
- Indicates desired state of the instance.
- - If C(current), the current state of the VM will be fetched. You can access it with C(results.status)
+ - If V(current), the current state of the VM will be fetched. You can access it with C(results.status)
+ - V(template) was added in community.general 8.1.0.
type: str
- choices: ['present', 'started', 'absent', 'stopped', 'restarted','current']
+ choices: ['present', 'started', 'absent', 'stopped', 'restarted', 'current', 'template']
default: present
storage:
description:
@@ -447,12 +469,12 @@ options:
tablet:
description:
- Enables/disables the USB tablet device.
- - This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(false).
+ - This option has no default unless O(proxmox_default_behavior) is set to V(compatibility); then the default is V(false).
type: bool
tags:
description:
- List of tags to apply to the VM instance.
- - Tags must start with C([a-z0-9_]) followed by zero or more of the following characters C([a-z0-9_-+.]).
+ - Tags must start with V([a-z0-9_]) followed by zero or more of the following characters V([a-z0-9_-+.]).
- Tags are only available in Proxmox 6+.
type: list
elements: str
@@ -469,21 +491,48 @@ options:
template:
description:
- Enables/disables the template.
- - This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(false).
+ - This option has no default unless O(proxmox_default_behavior) is set to V(compatibility); then the default is V(false).
type: bool
timeout:
description:
- Timeout for operations.
+ - When used with O(state=stopped) the option sets a graceful timeout for VM stop after which a VM will be forcefully stopped.
type: int
default: 30
+ tpmstate0:
+ description:
+ - A hash/dictionary of options for the Trusted Platform Module disk.
+ - A TPM state disk is required for Windows 11 installations.
+ suboptions:
+ storage:
+ description:
+ - O(tpmstate0.storage) is the storage identifier where to create the disk.
+ type: str
+ required: true
+ version:
+ description:
+ - The TPM version to use.
+ type: str
+ choices: ['1.2', '2.0']
+ default: '2.0'
+ type: dict
+ version_added: 7.1.0
update:
description:
- - If C(true), the VM will be updated with new value.
- - Cause of the operations of the API and security reasons, I have disabled the update of the following parameters
- - C(net, virtio, ide, sata, scsi). Per example updating C(net) update the MAC address and C(virtio) create always new disk...
- - Update of C(pool) is disabled. It needs an additional API endpoint not covered by this module.
+ - If V(true), the VM will be updated with new value.
+ - Because of the operations of the API and security reasons, I have disabled the update of the following parameters
+ O(net), O(virtio), O(ide), O(sata), O(scsi). Per example updating O(net) update the MAC address and C(virtio) create always new disk...
+ This security feature can be disabled by setting the O(update_unsafe) to V(true).
+ - Update of O(pool) is disabled. It needs an additional API endpoint not covered by this module.
+ type: bool
+ default: false
+ update_unsafe:
+ description:
+ - If V(true), do not enforce limitations on parameters O(net), O(virtio), O(ide), O(sata), O(scsi), O(efidisk0), and O(tpmstate0).
+ Use this option with caution because an improper configuration might result in a permanent loss of data (e.g. disk recreated).
type: bool
default: false
+ version_added: 8.4.0
vcpus:
description:
- Sets number of hotplugged vcpus.
@@ -491,13 +540,13 @@ options:
vga:
description:
- Select VGA type. If you want to use high resolution modes (>= 1280x1024x16) then you should use option 'std' or 'vmware'.
- - This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(std).
+ - This option has no default unless O(proxmox_default_behavior) is set to V(compatibility); then the default is V(std).
type: str
choices: ['std', 'cirrus', 'vmware', 'qxl', 'serial0', 'serial1', 'serial2', 'serial3', 'qxl2', 'qxl3', 'qxl4']
virtio:
description:
- - A hash/dictionary of volume used as VIRTIO hard disk. C(virtio='{"key":"value", "key":"value"}').
- - Keys allowed are - C(virto[n]) where 0 ≤ n ≤ 15.
+ - A hash/dictionary of volume used as VIRTIO hard disk. O(virtio='{"key":"value", "key":"value"}').
+ - Keys allowed are - C(virtio[n]) where 0 ≤ n ≤ 15.
- Values allowed are - C("storage:size,format=value").
- C(storage) is the storage identifier where to create the disk.
- C(size) is the size of the disk in GB.
@@ -514,18 +563,21 @@ options:
- As of community.general 4.0.0, various options no longer have default values.
These default values caused problems when users expected different behavior from Proxmox
by default or filled options which caused problems when set.
- - The value C(compatibility) (default before community.general 4.0.0) will ensure that the default values
- are used when the values are not explicitly specified by the user. The new default is C(no_defaults),
+ - The value V(compatibility) (default before community.general 4.0.0) will ensure that the default values
+ are used when the values are not explicitly specified by the user. The new default is V(no_defaults),
which makes sure these options have no defaults.
- - This affects the I(acpi), I(autostart), I(balloon), I(boot), I(cores), I(cpu),
- I(cpuunits), I(force), I(format), I(kvm), I(memory), I(onboot), I(ostype), I(sockets),
- I(tablet), I(template), I(vga), options.
+ - This affects the O(acpi), O(autostart), O(balloon), O(boot), O(cores), O(cpu),
+ O(cpuunits), O(force), O(format), O(kvm), O(memory), O(onboot), O(ostype), O(sockets),
+ O(tablet), O(template), and O(vga) options.
+ - This option is deprecated and will be removed in community.general 10.0.0.
type: str
default: no_defaults
choices:
- compatibility
- no_defaults
version_added: "1.3.0"
+seealso:
+ - module: community.general.proxmox_vm_info
extends_documentation_fragment:
- community.general.proxmox.documentation
- community.general.proxmox.selection
@@ -754,6 +806,25 @@ EXAMPLES = '''
node: sabrewulf
state: restarted
+- name: Convert VM to template
+ community.general.proxmox_kvm:
+ api_user: root@pam
+ api_password: secret
+ api_host: helldorado
+ name: spynal
+ node: sabrewulf
+ state: template
+
+- name: Convert VM to template (stop VM if running)
+ community.general.proxmox_kvm:
+ api_user: root@pam
+ api_password: secret
+ api_host: helldorado
+ name: spynal
+ node: sabrewulf
+ state: template
+ force: true
+
- name: Remove VM
community.general.proxmox_kvm:
api_user: root@pam
@@ -763,6 +834,15 @@ EXAMPLES = '''
node: sabrewulf
state: absent
+- name: Get VM current state
+ community.general.proxmox_kvm:
+ api_user: root@pam
+ api_password: secret
+ api_host: helldorado
+ name: spynal
+ node: sabrewulf
+ state: current
+
- name: Update VM configuration
community.general.proxmox_kvm:
api_user: root@pam
@@ -774,6 +854,20 @@ EXAMPLES = '''
memory: 16384
update: true
+- name: Update VM configuration (incl. unsafe options)
+ community.general.proxmox_kvm:
+ api_user: root@pam
+ api_password: secret
+ api_host: helldorado
+ name: spynal
+ node: sabrewulf
+ cores: 8
+ memory: 16384
+ net:
+ net0: virtio,bridge=vmbr1
+ update: true
+ update_unsafe: true
+
- name: Delete QEMU parameters
community.general.proxmox_kvm:
api_user: root@pam
@@ -791,6 +885,26 @@ EXAMPLES = '''
name: spynal
node: sabrewulf
revert: 'template,cpulimit'
+
+- name: Migrate VM on second node
+ community.general.proxmox_kvm:
+ api_user: root@pam
+ api_password: secret
+ api_host: helldorado
+ name: spynal
+ node: sabrewulf-2
+ migrate: true
+
+- name: Add hookscript to existing VM
+ community.general.proxmox_kvm:
+ api_user: root@pam
+ api_password: secret
+ api_host: helldorado
+ vmid: 999
+ node: sabrewulf
+ hookscript: local:snippets/hookscript.pl
+ update: true
+
'''
RETURN = '''
@@ -874,6 +988,9 @@ class ProxmoxKvmAnsible(ProxmoxAnsible):
def wait_for_task(self, node, taskid):
timeout = self.module.params['timeout']
+ if self.module.params['state'] == 'stopped':
+ # Increase task timeout in case of stopped state to be sure it waits longer than VM stop operation itself
+ timeout += 10
while timeout:
if self.api_task_ok(node, taskid):
@@ -886,12 +1003,12 @@ class ProxmoxKvmAnsible(ProxmoxAnsible):
time.sleep(1)
return False
- def create_vm(self, vmid, newid, node, name, memory, cpu, cores, sockets, update, **kwargs):
+ def create_vm(self, vmid, newid, node, name, memory, cpu, cores, sockets, update, update_unsafe, **kwargs):
# Available only in PVE 4
only_v4 = ['force', 'protection', 'skiplock']
only_v6 = ['ciuser', 'cipassword', 'sshkeys', 'ipconfig', 'tags']
- # valide clone parameters
+ # valid clone parameters
valid_clone_params = ['format', 'full', 'pool', 'snapname', 'storage', 'target']
clone_params = {}
# Default args for vm. Note: -args option is for experts only. It allows you to pass arbitrary arguments to kvm.
@@ -923,21 +1040,24 @@ class ProxmoxKvmAnsible(ProxmoxAnsible):
urlencoded_ssh_keys = quote(kwargs['sshkeys'], safe='')
kwargs['sshkeys'] = str(urlencoded_ssh_keys)
- # If update, don't update disk (virtio, efidisk0, ide, sata, scsi) and network interface
+ # If update, don't update disk (virtio, efidisk0, tpmstate0, ide, sata, scsi) and network interface, unless update_unsafe=True
# pool parameter not supported by qemu/<vmid>/config endpoint on "update" (PVE 6.2) - only with "create"
if update:
- if 'virtio' in kwargs:
- del kwargs['virtio']
- if 'sata' in kwargs:
- del kwargs['sata']
- if 'scsi' in kwargs:
- del kwargs['scsi']
- if 'ide' in kwargs:
- del kwargs['ide']
- if 'efidisk0' in kwargs:
- del kwargs['efidisk0']
- if 'net' in kwargs:
- del kwargs['net']
+ if update_unsafe is False:
+ if 'virtio' in kwargs:
+ del kwargs['virtio']
+ if 'sata' in kwargs:
+ del kwargs['sata']
+ if 'scsi' in kwargs:
+ del kwargs['scsi']
+ if 'ide' in kwargs:
+ del kwargs['ide']
+ if 'efidisk0' in kwargs:
+ del kwargs['efidisk0']
+ if 'tpmstate0' in kwargs:
+ del kwargs['tpmstate0']
+ if 'net' in kwargs:
+ del kwargs['net']
if 'force' in kwargs:
del kwargs['force']
if 'pool' in kwargs:
@@ -951,7 +1071,7 @@ class ProxmoxKvmAnsible(ProxmoxAnsible):
# Flatten efidisk0 option to a string so that it's a string which is what Proxmoxer and the API expect
if 'efidisk0' in kwargs:
efidisk0_str = ''
- # Regexp to catch underscores in keys name, to replace them after by hypens
+ # Regexp to catch underscores in keys name, to replace them after by hyphens
hyphen_re = re.compile(r'_')
# If present, the storage definition should be the first argument
if 'storage' in kwargs['efidisk0']:
@@ -963,6 +1083,13 @@ class ProxmoxKvmAnsible(ProxmoxAnsible):
if 'storage' != k])
kwargs['efidisk0'] = efidisk0_str
+ # Flatten tpmstate0 option to a string so that it's a string which is what Proxmoxer and the API expect
+ if 'tpmstate0' in kwargs:
+ kwargs['tpmstate0'] = '{storage}:1,version=v{version}'.format(
+ storage=kwargs['tpmstate0'].get('storage'),
+ version=kwargs['tpmstate0'].get('version')
+ )
+
# Convert all dict in kwargs to elements.
# For hostpci[n], ide[n], net[n], numa[n], parallel[n], sata[n], scsi[n], serial[n], virtio[n], ipconfig[n]
for k in list(kwargs.keys()):
@@ -1043,16 +1170,53 @@ class ProxmoxKvmAnsible(ProxmoxAnsible):
return False
return True
- def stop_vm(self, vm, force):
+ def stop_vm(self, vm, force, timeout):
vmid = vm['vmid']
proxmox_node = self.proxmox_api.nodes(vm['node'])
- taskid = proxmox_node.qemu(vmid).status.shutdown.post(forceStop=(1 if force else 0))
+ taskid = proxmox_node.qemu(vmid).status.shutdown.post(forceStop=(1 if force else 0), timeout=timeout)
if not self.wait_for_task(vm['node'], taskid):
self.module.fail_json(msg='Reached timeout while waiting for stopping VM. Last line in task before timeout: %s' %
proxmox_node.tasks(taskid).log.get()[:1])
return False
return True
+ def restart_vm(self, vm, force, **status):
+ vmid = vm['vmid']
+ try:
+ proxmox_node = self.proxmox_api.nodes(vm['node'])
+ taskid = proxmox_node.qemu(vmid).status.reset.post() if force else proxmox_node.qemu(vmid).status.reboot.post()
+ if not self.wait_for_task(vm['node'], taskid):
+ self.module.fail_json(msg='Reached timeout while waiting for rebooting VM. Last line in task before timeout: %s' %
+ proxmox_node.tasks(taskid).log.get()[:1])
+ return False
+ return True
+ except Exception as e:
+ self.module.fail_json(vmid=vmid, msg="restarting of VM %s failed with exception: %s" % (vmid, e))
+ return False
+
+ def convert_to_template(self, vm, timeout, force):
+ vmid = vm['vmid']
+ try:
+ proxmox_node = self.proxmox_api.nodes(vm['node'])
+ if proxmox_node.qemu(vmid).status.current.get()['status'] == 'running' and force:
+ self.stop_instance(vm, vmid, timeout, force)
+ # not sure why, but templating a container doesn't return a taskid
+ proxmox_node.qemu(vmid).template.post()
+ return True
+ except Exception as e:
+ self.module.fail_json(vmid=vmid, msg="conversion of VM %s to template failed with exception: %s" % (vmid, e))
+ return False
+
+ def migrate_vm(self, vm, target_node):
+ vmid = vm['vmid']
+ proxmox_node = self.proxmox_api.nodes(vm['node'])
+ taskid = proxmox_node.qemu(vmid).migrate.post(vmid=vmid, node=vm['node'], target=target_node, online=1)
+ if not self.wait_for_task(vm['node'], taskid):
+ self.module.fail_json(msg='Reached timeout while waiting for migrating VM. Last line in task before timeout: %s' %
+ proxmox_node.tasks(taskid).log.get()[:1])
+ return False
+ return True
+
def main():
module_args = proxmox_auth_argument_spec()
@@ -1089,6 +1253,7 @@ def main():
format=dict(type='str', choices=['cloop', 'cow', 'qcow', 'qcow2', 'qed', 'raw', 'vmdk', 'unspecified']),
freeze=dict(type='bool'),
full=dict(type='bool', default=True),
+ hookscript=dict(type='str'),
hostpci=dict(type='dict'),
hotplug=dict(type='str'),
hugepages=dict(choices=['any', '2', '1024']),
@@ -1100,6 +1265,7 @@ def main():
lock=dict(choices=['migrate', 'backup', 'snapshot', 'rollback']),
machine=dict(type='str'),
memory=dict(type='int'),
+ migrate=dict(type='bool', default=False),
migrate_downtime=dict(type='int'),
migrate_speed=dict(type='int'),
name=dict(type='str'),
@@ -1129,7 +1295,7 @@ def main():
sshkeys=dict(type='str', no_log=False),
startdate=dict(type='str'),
startup=dict(),
- state=dict(default='present', choices=['present', 'absent', 'stopped', 'started', 'restarted', 'current']),
+ state=dict(default='present', choices=['present', 'absent', 'stopped', 'started', 'restarted', 'current', 'template']),
storage=dict(type='str'),
tablet=dict(type='bool'),
tags=dict(type='list', elements='str'),
@@ -1137,13 +1303,23 @@ def main():
tdf=dict(type='bool'),
template=dict(type='bool'),
timeout=dict(type='int', default=30),
+ tpmstate0=dict(type='dict',
+ options=dict(
+ storage=dict(type='str', required=True),
+ version=dict(type='str', choices=['2.0', '1.2'], default='2.0')
+ )),
update=dict(type='bool', default=False),
+ update_unsafe=dict(type='bool', default=False),
vcpus=dict(type='int'),
vga=dict(choices=['std', 'cirrus', 'vmware', 'qxl', 'serial0', 'serial1', 'serial2', 'serial3', 'qxl2', 'qxl3', 'qxl4']),
virtio=dict(type='dict'),
vmid=dict(type='int'),
watchdog=dict(),
- proxmox_default_behavior=dict(type='str', default='no_defaults', choices=['compatibility', 'no_defaults']),
+ proxmox_default_behavior=dict(type='str',
+ default='no_defaults',
+ choices=['compatibility', 'no_defaults'],
+ removed_from_collection='community.general',
+ removed_in_version='10.0.0'),
)
module_args.update(kvm_args)
@@ -1159,6 +1335,7 @@ def main():
cpu = module.params['cpu']
cores = module.params['cores']
delete = module.params['delete']
+ migrate = module.params['migrate']
memory = module.params['memory']
name = module.params['name']
newid = module.params['newid']
@@ -1167,6 +1344,7 @@ def main():
sockets = module.params['sockets']
state = module.params['state']
update = bool(module.params['update'])
+ update_unsafe = bool(module.params['update_unsafe'])
vmid = module.params['vmid']
validate_certs = module.params['validate_certs']
@@ -1200,11 +1378,15 @@ def main():
# If vmid is not defined then retrieve its value from the vm name,
# the cloned vm name or retrieve the next free VM id from ProxmoxAPI.
if not vmid:
- if state == 'present' and not update and not clone and not delete and not revert:
- try:
- vmid = proxmox.get_nextvmid()
- except Exception:
- module.fail_json(msg="Can't get the next vmid for VM {0} automatically. Ensure your cluster state is good".format(name))
+ if state == 'present' and not update and not clone and not delete and not revert and not migrate:
+ existing_vmid = proxmox.get_vmid(name, ignore_missing=True)
+ if existing_vmid:
+ vmid = existing_vmid
+ else:
+ try:
+ vmid = proxmox.get_nextvmid()
+ except Exception:
+ module.fail_json(msg="Can't get the next vmid for VM {0} automatically. Ensure your cluster state is good".format(name))
else:
clone_target = clone or name
vmid = proxmox.get_vmid(clone_target, ignore_missing=True)
@@ -1247,20 +1429,32 @@ def main():
except Exception as e:
module.fail_json(vmid=vmid, msg='Unable to revert settings on VM {0} with vmid {1}: Maybe is not a pending task... '.format(name, vmid) + str(e))
+ if migrate:
+ try:
+ vm = proxmox.get_vm(vmid)
+ vm_node = vm['node']
+ if node != vm_node:
+ proxmox.migrate_vm(vm, node)
+ module.exit_json(changed=True, vmid=vmid, msg="VM {0} has been migrated from {1} to {2}".format(vmid, vm_node, node))
+ else:
+ module.exit_json(changed=False, vmid=vmid, msg="VM {0} is already on {1}".format(vmid, node))
+ except Exception as e:
+ module.fail_json(vmid=vmid, msg='Unable to migrate VM {0} from {1} to {2}: {3}'.format(vmid, vm_node, node, e))
+
if state == 'present':
+ if not (update or clone) and proxmox.get_vm(vmid, ignore_missing=True):
+ module.exit_json(changed=False, vmid=vmid, msg="VM with vmid <%s> already exists" % vmid)
+ elif not (update or clone or vmid) and proxmox.get_vmid(name, ignore_missing=True):
+ module.exit_json(changed=False, vmid=proxmox.get_vmid(name), msg="VM with name <%s> already exists" % name)
+ elif not node:
+ module.fail_json(msg='node is mandatory for creating/updating VM')
+ elif update and not any([vmid, name]):
+ module.fail_json(msg='vmid or name is mandatory for updating VM')
+ elif not proxmox.get_node(node):
+ module.fail_json(msg="node '%s' does not exist in cluster" % node)
+
try:
- if proxmox.get_vm(vmid, ignore_missing=True) and not (update or clone):
- module.exit_json(changed=False, vmid=vmid, msg="VM with vmid <%s> already exists" % vmid)
- elif proxmox.get_vmid(name, ignore_missing=True) and not (update or clone):
- module.exit_json(changed=False, vmid=proxmox.get_vmid(name), msg="VM with name <%s> already exists" % name)
- elif not node:
- module.fail.json(msg='node is mandatory for creating/updating VM')
- elif update and not any([vmid, name]):
- module.fail_json(msg='vmid or name is mandatory for updating VM')
- elif not proxmox.get_node(node):
- module.fail_json(msg="node '%s' does not exist in cluster" % node)
-
- proxmox.create_vm(vmid, newid, node, name, memory, cpu, cores, sockets, update,
+ proxmox.create_vm(vmid, newid, node, name, memory, cpu, cores, sockets, update, update_unsafe,
archive=module.params['archive'],
acpi=module.params['acpi'],
agent=module.params['agent'],
@@ -1280,6 +1474,7 @@ def main():
efidisk0=module.params['efidisk0'],
force=module.params['force'],
freeze=module.params['freeze'],
+ hookscript=module.params['hookscript'],
hostpci=module.params['hostpci'],
hotplug=module.params['hotplug'],
hugepages=module.params['hugepages'],
@@ -1317,6 +1512,7 @@ def main():
target=module.params['target'],
tdf=module.params['tdf'],
template=module.params['template'],
+ tpmstate0=module.params['tpmstate0'],
vcpus=module.params['vcpus'],
vga=module.params['vga'],
virtio=module.params['virtio'],
@@ -1329,12 +1525,6 @@ def main():
sata=module.params['sata'],
scsi=module.params['scsi'],
virtio=module.params['virtio'])
- if update:
- module.exit_json(changed=True, vmid=vmid, msg="VM %s with vmid %s updated" % (name, vmid))
- elif clone is not None:
- module.exit_json(changed=True, vmid=newid, msg="VM %s with newid %s cloned from vm with vmid %s" % (name, newid, vmid))
- else:
- module.exit_json(changed=True, msg="VM %s with vmid %s deployed" % (name, vmid), **results)
except Exception as e:
if update:
module.fail_json(vmid=vmid, msg="Unable to update vm {0} with vmid {1}=".format(name, vmid) + str(e))
@@ -1343,14 +1533,23 @@ def main():
else:
module.fail_json(vmid=vmid, msg="creation of qemu VM %s with vmid %s failed with exception=%s" % (name, vmid, e))
+ if update:
+ module.exit_json(changed=True, vmid=vmid, msg="VM %s with vmid %s updated" % (name, vmid))
+ elif clone is not None:
+ module.exit_json(changed=True, vmid=newid, msg="VM %s with newid %s cloned from vm with vmid %s" % (name, newid, vmid))
+ else:
+ module.exit_json(changed=True, msg="VM %s with vmid %s deployed" % (name, vmid), **results)
+
elif state == 'started':
+ if not vmid:
+ module.fail_json(msg='VM with name = %s does not exist in cluster' % name)
+
status = {}
try:
- if not vmid:
- module.fail_json(msg='VM with name = %s does not exist in cluster' % name)
vm = proxmox.get_vm(vmid)
- status['status'] = vm['status']
- if vm['status'] == 'running':
+ current = proxmox.proxmox_api.nodes(vm['node']).qemu(vmid).status.current.get()['status']
+ status['status'] = current
+ if current == 'running':
module.exit_json(changed=False, vmid=vmid, msg="VM %s is already running" % vmid, **status)
if proxmox.start_vm(vm):
@@ -1359,52 +1558,68 @@ def main():
module.fail_json(vmid=vmid, msg="starting of VM %s failed with exception: %s" % (vmid, e), **status)
elif state == 'stopped':
+ if not vmid:
+ module.fail_json(msg='VM with name = %s does not exist in cluster' % name)
+
status = {}
try:
- if not vmid:
- module.fail_json(msg='VM with name = %s does not exist in cluster' % name)
-
vm = proxmox.get_vm(vmid)
-
- status['status'] = vm['status']
- if vm['status'] == 'stopped':
+ current = proxmox.proxmox_api.nodes(vm['node']).qemu(vmid).status.current.get()['status']
+ status['status'] = current
+ if current == 'stopped':
module.exit_json(changed=False, vmid=vmid, msg="VM %s is already stopped" % vmid, **status)
- if proxmox.stop_vm(vm, force=module.params['force']):
- module.exit_json(changed=True, vmid=vmid, msg="VM %s is shutting down" % vmid, **status)
+ proxmox.stop_vm(vm, force=module.params['force'], timeout=module.params['timeout'])
+ module.exit_json(changed=True, vmid=vmid, msg="VM %s is shutting down" % vmid, **status)
except Exception as e:
module.fail_json(vmid=vmid, msg="stopping of VM %s failed with exception: %s" % (vmid, e), **status)
- elif state == 'restarted':
+ elif state == 'template':
+ if not vmid:
+ module.fail_json(msg='VM with name = %s does not exist in cluster' % name)
+
status = {}
try:
- if not vmid:
- module.fail_json(msg='VM with name = %s does not exist in cluster' % name)
-
vm = proxmox.get_vm(vmid)
- status['status'] = vm['status']
- if vm['status'] == 'stopped':
- module.exit_json(changed=False, vmid=vmid, msg="VM %s is not running" % vmid, **status)
- if proxmox.stop_vm(vm, force=module.params['force']) and proxmox.start_vm(vm):
- module.exit_json(changed=True, vmid=vmid, msg="VM %s is restarted" % vmid, **status)
+ if vm['template'] == 1:
+ module.exit_json(changed=False, vmid=vmid, msg="VM %s is already a template" % vmid, **status)
+
+ if proxmox.convert_to_template(vm, force=module.params['force'], timeout=module.params['timeout']):
+ module.exit_json(changed=True, vmid=vmid, msg="VM %s is converting to template" % vmid, **status)
except Exception as e:
- module.fail_json(vmid=vmid, msg="restarting of VM %s failed with exception: %s" % (vmid, e), **status)
+ module.fail_json(vmid=vmid, msg="conversion of VM %s to template failed with exception: %s" % (vmid, e), **status)
+
+ elif state == 'restarted':
+ if not vmid:
+ module.fail_json(msg='VM with name = %s does not exist in cluster' % name)
+
+ status = {}
+ vm = proxmox.get_vm(vmid)
+ current = proxmox.proxmox_api.nodes(vm['node']).qemu(vmid).status.current.get()['status']
+ status['status'] = current
+ if current == 'stopped':
+ module.exit_json(changed=False, vmid=vmid, msg="VM %s is not running" % vmid, **status)
+
+ if proxmox.restart_vm(vm, force=module.params['force']):
+ module.exit_json(changed=True, vmid=vmid, msg="VM %s is restarted" % vmid, **status)
elif state == 'absent':
status = {}
if not vmid:
module.exit_json(changed=False, msg='VM with name = %s is already absent' % name)
+
try:
vm = proxmox.get_vm(vmid, ignore_missing=True)
if not vm:
module.exit_json(changed=False, vmid=vmid)
proxmox_node = proxmox.proxmox_api.nodes(vm['node'])
- status['status'] = vm['status']
- if vm['status'] == 'running':
+ current = proxmox_node.qemu(vmid).status.current.get()['status']
+ status['status'] = current
+ if current == 'running':
if module.params['force']:
- proxmox.stop_vm(vm, True)
+ proxmox.stop_vm(vm, True, timeout=module.params['timeout'])
else:
module.exit_json(changed=False, vmid=vmid, msg="VM %s is running. Stop it before deletion or use force=true." % vmid)
taskid = proxmox_node.qemu.delete(vmid)
diff --git a/ansible_collections/community/general/plugins/modules/proxmox_nic.py b/ansible_collections/community/general/plugins/modules/proxmox_nic.py
index 26d07c7ec..9afe49447 100644
--- a/ansible_collections/community/general/plugins/modules/proxmox_nic.py
+++ b/ansible_collections/community/general/plugins/modules/proxmox_nic.py
@@ -24,7 +24,7 @@ attributes:
options:
bridge:
description:
- - Add this interface to the specified bridge device. The Proxmox VE default bridge is called C(vmbr0).
+ - Add this interface to the specified bridge device. The Proxmox VE default bridge is called V(vmbr0).
type: str
firewall:
description:
@@ -33,7 +33,7 @@ options:
default: false
interface:
description:
- - Name of the interface, should be C(net[n]) where C(1 ≤ n ≤ 31).
+ - Name of the interface, should be V(net[n]) where C(1 ≤ n ≤ 31).
type: str
required: true
link_down:
@@ -43,7 +43,7 @@ options:
default: false
mac:
description:
- - C(XX:XX:XX:XX:XX:XX) should be a unique MAC address. This is automatically generated if not specified.
+ - V(XX:XX:XX:XX:XX:XX) should be a unique MAC address. This is automatically generated if not specified.
- When not specified this module will keep the MAC address the same when changing an existing interface.
type: str
model:
@@ -56,13 +56,13 @@ options:
mtu:
description:
- Force MTU, for C(virtio) model only, setting will be ignored otherwise.
- - Set to C(1) to use the bridge MTU.
+ - Set to V(1) to use the bridge MTU.
- Value should be C(1 ≤ n ≤ 65520).
type: int
name:
description:
- Specifies the VM name. Only used on the configuration web interface.
- - Required only for I(state=present).
+ - Required only for O(state=present).
type: str
queues:
description:
diff --git a/ansible_collections/community/general/plugins/modules/proxmox_node_info.py b/ansible_collections/community/general/plugins/modules/proxmox_node_info.py
new file mode 100644
index 000000000..82ef7aa38
--- /dev/null
+++ b/ansible_collections/community/general/plugins/modules/proxmox_node_info.py
@@ -0,0 +1,140 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright John Berninger (@jberning) <john.berninger at gmail.com>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+
+DOCUMENTATION = '''
+---
+module: proxmox_node_info
+short_description: Retrieve information about one or more Proxmox VE nodes
+version_added: 8.2.0
+description:
+ - Retrieve information about one or more Proxmox VE nodes.
+author: John Berninger (@jwbernin)
+extends_documentation_fragment:
+ - community.general.proxmox.documentation
+ - community.general.attributes
+ - community.general.attributes.info_module
+'''
+
+
+EXAMPLES = '''
+- name: List existing nodes
+ community.general.proxmox_node_info:
+ api_host: proxmox1
+ api_user: root@pam
+ api_password: "{{ password | default(omit) }}"
+ api_token_id: "{{ token_id | default(omit) }}"
+ api_token_secret: "{{ token_secret | default(omit) }}"
+ register: proxmox_nodes
+'''
+
+
+RETURN = '''
+proxmox_nodes:
+ description: List of Proxmox VE nodes.
+ returned: always, but can be empty
+ type: list
+ elements: dict
+ contains:
+ cpu:
+ description: Current CPU usage in fractional shares of this host's total available CPU.
+ returned: on success
+ type: float
+ disk:
+ description: Current local disk usage of this host.
+ returned: on success
+ type: int
+ id:
+ description: Identity of the node.
+ returned: on success
+ type: str
+ level:
+ description: Support level. Can be blank if not under a paid support contract.
+ returned: on success
+ type: str
+ maxcpu:
+ description: Total number of available CPUs on this host.
+ returned: on success
+ type: int
+ maxdisk:
+ description: Size of local disk in bytes.
+ returned: on success
+ type: int
+ maxmem:
+ description: Memory size in bytes.
+ returned: on success
+ type: int
+ mem:
+ description: Used memory in bytes.
+ returned: on success
+ type: int
+ node:
+ description: Short hostname of this node.
+ returned: on success
+ type: str
+ ssl_fingerprint:
+ description: SSL fingerprint of the node certificate.
+ returned: on success
+ type: str
+ status:
+ description: Node status.
+ returned: on success
+ type: str
+ type:
+ description: Object type being returned.
+ returned: on success
+ type: str
+ uptime:
+ description: Node uptime in seconds.
+ returned: on success
+ type: int
+'''
+
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.community.general.plugins.module_utils.proxmox import (
+ proxmox_auth_argument_spec, ProxmoxAnsible)
+
+
+class ProxmoxNodeInfoAnsible(ProxmoxAnsible):
+ def get_nodes(self):
+ nodes = self.proxmox_api.nodes.get()
+ return nodes
+
+
+def proxmox_node_info_argument_spec():
+ return dict()
+
+
+def main():
+ module_args = proxmox_auth_argument_spec()
+ node_info_args = proxmox_node_info_argument_spec()
+ module_args.update(node_info_args)
+
+ module = AnsibleModule(
+ argument_spec=module_args,
+ required_one_of=[('api_password', 'api_token_id')],
+ required_together=[('api_token_id', 'api_token_secret')],
+ supports_check_mode=True,
+ )
+ result = dict(
+ changed=False
+ )
+
+ proxmox = ProxmoxNodeInfoAnsible(module)
+
+ nodes = proxmox.get_nodes()
+ result['proxmox_nodes'] = nodes
+
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/general/plugins/modules/proxmox_pool.py b/ansible_collections/community/general/plugins/modules/proxmox_pool.py
new file mode 100644
index 000000000..704632070
--- /dev/null
+++ b/ansible_collections/community/general/plugins/modules/proxmox_pool.py
@@ -0,0 +1,180 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2023, Sergei Antipov (UnderGreen) <greendayonfire@gmail.com>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+DOCUMENTATION = r"""
+---
+module: proxmox_pool
+short_description: Pool management for Proxmox VE cluster
+description:
+ - Create or delete a pool for Proxmox VE clusters.
+ - For pool members management please consult M(community.general.proxmox_pool_member) module.
+version_added: 7.1.0
+author: "Sergei Antipov (@UnderGreen) <greendayonfire@gmail.com>"
+attributes:
+ check_mode:
+ support: full
+ diff_mode:
+ support: none
+options:
+ poolid:
+ description:
+ - The pool ID.
+ type: str
+ aliases: [ "name" ]
+ required: true
+ state:
+ description:
+ - Indicate desired state of the pool.
+ - The pool must be empty prior deleting it with O(state=absent).
+ choices: ['present', 'absent']
+ default: present
+ type: str
+ comment:
+ description:
+ - Specify the description for the pool.
+ - Parameter is ignored when pool already exists or O(state=absent).
+ type: str
+
+extends_documentation_fragment:
+ - community.general.proxmox.documentation
+ - community.general.attributes
+"""
+
+EXAMPLES = """
+- name: Create new Proxmox VE pool
+ community.general.proxmox_pool:
+ api_host: node1
+ api_user: root@pam
+ api_password: password
+ poolid: test
+ comment: 'New pool'
+
+- name: Delete the Proxmox VE pool
+ community.general.proxmox_pool:
+ api_host: node1
+ api_user: root@pam
+ api_password: password
+ poolid: test
+ state: absent
+"""
+
+RETURN = """
+poolid:
+ description: The pool ID.
+ returned: success
+ type: str
+ sample: test
+msg:
+ description: A short message on what the module did.
+ returned: always
+ type: str
+ sample: "Pool test successfully created"
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.community.general.plugins.module_utils.proxmox import (proxmox_auth_argument_spec, ProxmoxAnsible)
+
+
+class ProxmoxPoolAnsible(ProxmoxAnsible):
+
+ def is_pool_existing(self, poolid):
+ """Check whether pool already exist
+
+ :param poolid: str - name of the pool
+ :return: bool - is pool exists?
+ """
+ try:
+ pools = self.proxmox_api.pools.get()
+ for pool in pools:
+ if pool['poolid'] == poolid:
+ return True
+ return False
+ except Exception as e:
+ self.module.fail_json(msg="Unable to retrieve pools: {0}".format(e))
+
+ def is_pool_empty(self, poolid):
+ """Check whether pool has members
+
+ :param poolid: str - name of the pool
+ :return: bool - is pool empty?
+ """
+ return True if not self.get_pool(poolid)['members'] else False
+
+ def create_pool(self, poolid, comment=None):
+ """Create Proxmox VE pool
+
+ :param poolid: str - name of the pool
+ :param comment: str, optional - Description of a pool
+ :return: None
+ """
+ if self.is_pool_existing(poolid):
+ self.module.exit_json(changed=False, poolid=poolid, msg="Pool {0} already exists".format(poolid))
+
+ if self.module.check_mode:
+ return
+
+ try:
+ self.proxmox_api.pools.post(poolid=poolid, comment=comment)
+ except Exception as e:
+ self.module.fail_json(msg="Failed to create pool with ID {0}: {1}".format(poolid, e))
+
+ def delete_pool(self, poolid):
+ """Delete Proxmox VE pool
+
+ :param poolid: str - name of the pool
+ :return: None
+ """
+ if not self.is_pool_existing(poolid):
+ self.module.exit_json(changed=False, poolid=poolid, msg="Pool {0} doesn't exist".format(poolid))
+
+ if self.is_pool_empty(poolid):
+ if self.module.check_mode:
+ return
+
+ try:
+ self.proxmox_api.pools(poolid).delete()
+ except Exception as e:
+ self.module.fail_json(msg="Failed to delete pool with ID {0}: {1}".format(poolid, e))
+ else:
+ self.module.fail_json(msg="Can't delete pool {0} with members. Please remove members from pool first.".format(poolid))
+
+
+def main():
+ module_args = proxmox_auth_argument_spec()
+ pools_args = dict(
+ poolid=dict(type="str", aliases=["name"], required=True),
+ comment=dict(type="str"),
+ state=dict(default="present", choices=["present", "absent"]),
+ )
+
+ module_args.update(pools_args)
+
+ module = AnsibleModule(
+ argument_spec=module_args,
+ required_together=[("api_token_id", "api_token_secret")],
+ required_one_of=[("api_password", "api_token_id")],
+ supports_check_mode=True
+ )
+
+ poolid = module.params["poolid"]
+ comment = module.params["comment"]
+ state = module.params["state"]
+
+ proxmox = ProxmoxPoolAnsible(module)
+
+ if state == "present":
+ proxmox.create_pool(poolid, comment)
+ module.exit_json(changed=True, poolid=poolid, msg="Pool {0} successfully created".format(poolid))
+ else:
+ proxmox.delete_pool(poolid)
+ module.exit_json(changed=True, poolid=poolid, msg="Pool {0} successfully deleted".format(poolid))
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/general/plugins/modules/proxmox_pool_member.py b/ansible_collections/community/general/plugins/modules/proxmox_pool_member.py
new file mode 100644
index 000000000..7d6b24949
--- /dev/null
+++ b/ansible_collections/community/general/plugins/modules/proxmox_pool_member.py
@@ -0,0 +1,238 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2023, Sergei Antipov (UnderGreen) <greendayonfire@gmail.com>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+DOCUMENTATION = r"""
+---
+module: proxmox_pool_member
+short_description: Add or delete members from Proxmox VE cluster pools
+description:
+ - Create or delete a pool member in Proxmox VE clusters.
+version_added: 7.1.0
+author: "Sergei Antipov (@UnderGreen) <greendayonfire@gmail.com>"
+attributes:
+ check_mode:
+ support: full
+ diff_mode:
+ support: full
+options:
+ poolid:
+ description:
+ - The pool ID.
+ type: str
+ aliases: [ "name" ]
+ required: true
+ member:
+ description:
+ - Specify the member name.
+ - For O(type=storage) it is a storage name.
+ - For O(type=vm) either vmid or vm name could be used.
+ type: str
+ required: true
+ type:
+ description:
+ - Member type to add/remove from the pool.
+ choices: ["vm", "storage"]
+ default: vm
+ type: str
+ state:
+ description:
+ - Indicate desired state of the pool member.
+ choices: ['present', 'absent']
+ default: present
+ type: str
+
+extends_documentation_fragment:
+ - community.general.proxmox.documentation
+ - community.general.attributes
+"""
+
+EXAMPLES = """
+- name: Add new VM to Proxmox VE pool
+ community.general.proxmox_pool_member:
+ api_host: node1
+ api_user: root@pam
+ api_password: password
+ poolid: test
+ member: 101
+
+- name: Add new storage to Proxmox VE pool
+ community.general.proxmox_pool_member:
+ api_host: node1
+ api_user: root@pam
+ api_password: password
+ poolid: test
+ member: zfs-data
+ type: storage
+
+- name: Remove VM from the Proxmox VE pool using VM name
+ community.general.proxmox_pool_member:
+ api_host: node1
+ api_user: root@pam
+ api_password: password
+ poolid: test
+ member: pxe.home.arpa
+ state: absent
+
+- name: Remove storage from the Proxmox VE pool
+ community.general.proxmox_pool_member:
+ api_host: node1
+ api_user: root@pam
+ api_password: password
+ poolid: test
+ member: zfs-storage
+ type: storage
+ state: absent
+"""
+
+RETURN = """
+poolid:
+ description: The pool ID.
+ returned: success
+ type: str
+ sample: test
+member:
+ description: Member name.
+ returned: success
+ type: str
+ sample: 101
+msg:
+ description: A short message on what the module did.
+ returned: always
+ type: str
+ sample: "Member 101 deleted from the pool test"
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.community.general.plugins.module_utils.proxmox import (proxmox_auth_argument_spec, ProxmoxAnsible)
+
+
+class ProxmoxPoolMemberAnsible(ProxmoxAnsible):
+
+ def pool_members(self, poolid):
+ vms = []
+ storage = []
+ for member in self.get_pool(poolid)["members"]:
+ if member["type"] == "storage":
+ storage.append(member["storage"])
+ else:
+ vms.append(member["vmid"])
+
+ return (vms, storage)
+
+ def add_pool_member(self, poolid, member, member_type):
+ current_vms_members, current_storage_members = self.pool_members(poolid)
+ all_members_before = current_storage_members + current_vms_members
+ all_members_after = all_members_before.copy()
+ diff = {"before": {"members": all_members_before}, "after": {"members": all_members_after}}
+
+ try:
+ if member_type == "storage":
+ storages = self.get_storages(type=None)
+ if member not in [storage["storage"] for storage in storages]:
+ self.module.fail_json(msg="Storage {0} doesn't exist in the cluster".format(member))
+ if member in current_storage_members:
+ self.module.exit_json(changed=False, poolid=poolid, member=member,
+ diff=diff, msg="Member {0} is already part of the pool {1}".format(member, poolid))
+
+ all_members_after.append(member)
+ if self.module.check_mode:
+ return diff
+
+ self.proxmox_api.pools(poolid).put(storage=[member])
+ return diff
+ else:
+ try:
+ vmid = int(member)
+ except ValueError:
+ vmid = self.get_vmid(member)
+
+ if vmid in current_vms_members:
+ self.module.exit_json(changed=False, poolid=poolid, member=member,
+ diff=diff, msg="VM {0} is already part of the pool {1}".format(member, poolid))
+
+ all_members_after.append(member)
+
+ if not self.module.check_mode:
+ self.proxmox_api.pools(poolid).put(vms=[vmid])
+ return diff
+ except Exception as e:
+ self.module.fail_json(msg="Failed to add a new member ({0}) to the pool {1}: {2}".format(member, poolid, e))
+
+ def delete_pool_member(self, poolid, member, member_type):
+ current_vms_members, current_storage_members = self.pool_members(poolid)
+ all_members_before = current_storage_members + current_vms_members
+ all_members_after = all_members_before.copy()
+ diff = {"before": {"members": all_members_before}, "after": {"members": all_members_after}}
+
+ try:
+ if member_type == "storage":
+ if member not in current_storage_members:
+ self.module.exit_json(changed=False, poolid=poolid, member=member,
+ diff=diff, msg="Member {0} is not part of the pool {1}".format(member, poolid))
+
+ all_members_after.remove(member)
+ if self.module.check_mode:
+ return diff
+
+ self.proxmox_api.pools(poolid).put(storage=[member], delete=1)
+ return diff
+ else:
+ try:
+ vmid = int(member)
+ except ValueError:
+ vmid = self.get_vmid(member)
+
+ if vmid not in current_vms_members:
+ self.module.exit_json(changed=False, poolid=poolid, member=member,
+ diff=diff, msg="VM {0} is not part of the pool {1}".format(member, poolid))
+
+ all_members_after.remove(vmid)
+
+ if not self.module.check_mode:
+ self.proxmox_api.pools(poolid).put(vms=[vmid], delete=1)
+ return diff
+ except Exception as e:
+ self.module.fail_json(msg="Failed to delete a member ({0}) from the pool {1}: {2}".format(member, poolid, e))
+
+
+def main():
+ module_args = proxmox_auth_argument_spec()
+ pool_members_args = dict(
+ poolid=dict(type="str", aliases=["name"], required=True),
+ member=dict(type="str", required=True),
+ type=dict(default="vm", choices=["vm", "storage"]),
+ state=dict(default="present", choices=["present", "absent"]),
+ )
+
+ module_args.update(pool_members_args)
+
+ module = AnsibleModule(
+ argument_spec=module_args,
+ required_together=[("api_token_id", "api_token_secret")],
+ required_one_of=[("api_password", "api_token_id")],
+ supports_check_mode=True
+ )
+
+ poolid = module.params["poolid"]
+ member = module.params["member"]
+ member_type = module.params["type"]
+ state = module.params["state"]
+
+ proxmox = ProxmoxPoolMemberAnsible(module)
+
+ if state == "present":
+ diff = proxmox.add_pool_member(poolid, member, member_type)
+ module.exit_json(changed=True, poolid=poolid, member=member, diff=diff, msg="New member {0} added to the pool {1}".format(member, poolid))
+ else:
+ diff = proxmox.delete_pool_member(poolid, member, member_type)
+ module.exit_json(changed=True, poolid=poolid, member=member, diff=diff, msg="Member {0} deleted from the pool {1}".format(member, poolid))
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/general/plugins/modules/proxmox_snap.py b/ansible_collections/community/general/plugins/modules/proxmox_snap.py
index 0c17f8376..4991423c2 100644
--- a/ansible_collections/community/general/plugins/modules/proxmox_snap.py
+++ b/ansible_collections/community/general/plugins/modules/proxmox_snap.py
@@ -34,7 +34,7 @@ options:
state:
description:
- Indicate desired state of the instance snapshot.
- - The C(rollback) value was added in community.general 4.8.0.
+ - The V(rollback) value was added in community.general 4.8.0.
choices: ['present', 'absent', 'rollback']
default: present
type: str
@@ -49,7 +49,7 @@ options:
- Allows to snapshot a container even if it has configured mountpoints.
- Temporarily disables all configured mountpoints, takes snapshot, and finally restores original configuration.
- If running, the container will be stopped and restarted to apply config changes.
- - Due to restrictions in the Proxmox API this option can only be used authenticating as C(root@pam) with I(api_password), API tokens do not work either.
+ - Due to restrictions in the Proxmox API this option can only be used authenticating as V(root@pam) with O(api_password), API tokens do not work either.
- See U(https://pve.proxmox.com/pve-docs/api-viewer/#/nodes/{node}/lxc/{vmid}/config) (PUT tab) for more details.
default: false
type: bool
@@ -74,10 +74,19 @@ options:
- Name of the snapshot that has to be created/deleted/restored.
default: 'ansible_snap'
type: str
+ retention:
+ description:
+ - Remove old snapshots if there are more than O(retention) snapshots.
+ - If O(retention) is set to V(0), all snapshots will be kept.
+ - This is only used when O(state=present) and when an actual snapshot is created.
+ If no snapshot is created, all existing snapshots will be kept.
+ default: 0
+ type: int
+ version_added: 7.1.0
notes:
- Requires proxmoxer and requests modules on host. These modules can be installed with pip.
-requirements: [ "proxmoxer", "python >= 2.7", "requests" ]
+requirements: [ "proxmoxer", "requests" ]
author: Jeffrey van Pelt (@Thulium-Drake)
extends_documentation_fragment:
- community.general.proxmox.documentation
@@ -94,6 +103,16 @@ EXAMPLES = r'''
state: present
snapname: pre-updates
+- name: Create new container snapshot and keep only the 2 newest snapshots
+ community.general.proxmox_snap:
+ api_user: root@pam
+ api_password: 1q2w3e
+ api_host: node1
+ vmid: 100
+ state: present
+ snapname: snapshot-42
+ retention: 2
+
- name: Create new snapshot for a container with configured mountpoints
community.general.proxmox_snap:
api_user: root@pam
@@ -190,7 +209,15 @@ class ProxmoxSnapAnsible(ProxmoxAnsible):
time.sleep(1)
return False
- def snapshot_create(self, vm, vmid, timeout, snapname, description, vmstate, unbind):
+ def snapshot_retention(self, vm, vmid, retention):
+ # ignore the last snapshot, which is the current state
+ snapshots = self.snapshot(vm, vmid).get()[:-1]
+ if retention > 0 and len(snapshots) > retention:
+ # sort by age, oldest first
+ for snap in sorted(snapshots, key=lambda x: x['snaptime'])[:len(snapshots) - retention]:
+ self.snapshot(vm, vmid)(snap['name']).delete()
+
+ def snapshot_create(self, vm, vmid, timeout, snapname, description, vmstate, unbind, retention):
if self.module.check_mode:
return True
@@ -217,9 +244,7 @@ class ProxmoxSnapAnsible(ProxmoxAnsible):
while timeout:
if self.api_task_ok(vm['node'], taskid):
- if vm['type'] == 'lxc' and unbind is True and mountpoints:
- self._container_mp_restore(vm, vmid, timeout, unbind, mountpoints, vmstatus)
- return True
+ break
if timeout == 0:
self.module.fail_json(msg='Reached timeout while waiting for creating VM snapshot. Last line in task before timeout: %s' %
self.proxmox_api.nodes(vm['node']).tasks(taskid).log.get()[:1])
@@ -228,7 +253,9 @@ class ProxmoxSnapAnsible(ProxmoxAnsible):
timeout -= 1
if vm['type'] == 'lxc' and unbind is True and mountpoints:
self._container_mp_restore(vm, vmid, timeout, unbind, mountpoints, vmstatus)
- return False
+
+ self.snapshot_retention(vm, vmid, retention)
+ return timeout > 0
def snapshot_remove(self, vm, vmid, timeout, snapname, force):
if self.module.check_mode:
@@ -275,6 +302,7 @@ def main():
force=dict(type='bool', default=False),
unbind=dict(type='bool', default=False),
vmstate=dict(type='bool', default=False),
+ retention=dict(type='int', default=0),
)
module_args.update(snap_args)
@@ -294,6 +322,7 @@ def main():
force = module.params['force']
unbind = module.params['unbind']
vmstate = module.params['vmstate']
+ retention = module.params['retention']
# If hostname is set get the VM id from ProxmoxAPI
if not vmid and hostname:
@@ -309,7 +338,7 @@ def main():
if i['name'] == snapname:
module.exit_json(changed=False, msg="Snapshot %s is already present" % snapname)
- if proxmox.snapshot_create(vm, vmid, timeout, snapname, description, vmstate, unbind):
+ if proxmox.snapshot_create(vm, vmid, timeout, snapname, description, vmstate, unbind, retention):
if module.check_mode:
module.exit_json(changed=False, msg="Snapshot %s would be created" % snapname)
else:
diff --git a/ansible_collections/community/general/plugins/modules/proxmox_storage_contents_info.py b/ansible_collections/community/general/plugins/modules/proxmox_storage_contents_info.py
new file mode 100644
index 000000000..498490fe4
--- /dev/null
+++ b/ansible_collections/community/general/plugins/modules/proxmox_storage_contents_info.py
@@ -0,0 +1,144 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright Julian Vanden Broeck (@l00ptr) <julian.vandenbroeck at dalibo.com>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+---
+module: proxmox_storage_contents_info
+short_description: List content from a Proxmox VE storage
+version_added: 8.2.0
+description:
+ - Retrieves information about stored objects on a specific storage attached to a node.
+options:
+ storage:
+ description:
+ - Only return content stored on that specific storage.
+ aliases: ['name']
+ type: str
+ required: true
+ node:
+ description:
+ - Proxmox node to which the storage is attached.
+ type: str
+ required: true
+ content:
+ description:
+ - Filter on a specific content type.
+ type: str
+ choices: ["all", "backup", "rootdir", "images", "iso"]
+ default: "all"
+ vmid:
+ description:
+ - Filter on a specific VMID.
+ type: int
+author: Julian Vanden Broeck (@l00ptr)
+extends_documentation_fragment:
+ - community.general.proxmox.documentation
+ - community.general.attributes
+ - community.general.attributes.info_module
+"""
+
+
+EXAMPLES = """
+- name: List existing storages
+ community.general.proxmox_storage_contents_info:
+ api_host: helldorado
+ api_user: root@pam
+ api_password: "{{ password | default(omit) }}"
+ api_token_id: "{{ token_id | default(omit) }}"
+ api_token_secret: "{{ token_secret | default(omit) }}"
+ storage: lvm2
+ content: backup
+ vmid: 130
+"""
+
+
+RETURN = """
+proxmox_storage_content:
+ description: Content of of storage attached to a node.
+ type: list
+ returned: success
+ elements: dict
+ contains:
+ content:
+ description: Proxmox content of listed objects on this storage.
+ type: str
+ returned: success
+ ctime:
+ description: Creation time of the listed objects.
+ type: str
+ returned: success
+ format:
+ description: Format of the listed objects (can be V(raw), V(pbs-vm), V(iso),...).
+ type: str
+ returned: success
+ size:
+ description: Size of the listed objects.
+ type: int
+ returned: success
+ subtype:
+ description: Subtype of the listed objects (can be V(qemu) or V(lxc)).
+ type: str
+ returned: When storage is dedicated to backup, typically on PBS storage.
+ verification:
+ description: Backup verification status of the listed objects.
+ type: dict
+ returned: When storage is dedicated to backup, typically on PBS storage.
+ sample: {
+ "state": "ok",
+ "upid": "UPID:backup-srv:00130F49:1A12D8375:00001CD7:657A2258:verificationjob:daily\\x3av\\x2dd0cc18c5\\x2d8707:root@pam:"
+ }
+ volid:
+ description: Volume identifier of the listed objects.
+ type: str
+ returned: success
+"""
+
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.community.general.plugins.module_utils.proxmox import (
+ ProxmoxAnsible, proxmox_auth_argument_spec)
+
+
+def proxmox_storage_info_argument_spec():
+ return dict(
+ storage=dict(type="str", required=True, aliases=["name"]),
+ content=dict(type="str", required=False, default="all", choices=["all", "backup", "rootdir", "images", "iso"]),
+ vmid=dict(type="int"),
+ node=dict(required=True, type="str"),
+ )
+
+
+def main():
+ module_args = proxmox_auth_argument_spec()
+ storage_info_args = proxmox_storage_info_argument_spec()
+ module_args.update(storage_info_args)
+
+ module = AnsibleModule(
+ argument_spec=module_args,
+ required_one_of=[("api_password", "api_token_id")],
+ required_together=[("api_token_id", "api_token_secret")],
+ supports_check_mode=True,
+ )
+ result = dict(changed=False)
+ proxmox = ProxmoxAnsible(module)
+ res = proxmox.get_storage_content(
+ node=module.params["node"],
+ storage=module.params["storage"],
+ content=None if module.params["content"] == "all" else module.params["content"],
+ vmid=module.params["vmid"],
+ )
+ result["proxmox_storage_content"] = res
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/general/plugins/modules/proxmox_storage_info.py b/ansible_collections/community/general/plugins/modules/proxmox_storage_info.py
index fd3759364..3c29e59cf 100644
--- a/ansible_collections/community/general/plugins/modules/proxmox_storage_info.py
+++ b/ansible_collections/community/general/plugins/modules/proxmox_storage_info.py
@@ -19,12 +19,12 @@ description:
options:
storage:
description:
- - Only return informations on a specific storage.
+ - Only return information on a specific storage.
aliases: ['name']
type: str
type:
description:
- - Filter on a specifc storage type.
+ - Filter on a specific storage type.
type: str
author: Tristan Le Guern (@tleguern)
extends_documentation_fragment:
diff --git a/ansible_collections/community/general/plugins/modules/proxmox_tasks_info.py b/ansible_collections/community/general/plugins/modules/proxmox_tasks_info.py
index a2e66b38d..d31a04980 100644
--- a/ansible_collections/community/general/plugins/modules/proxmox_tasks_info.py
+++ b/ansible_collections/community/general/plugins/modules/proxmox_tasks_info.py
@@ -37,7 +37,7 @@ extends_documentation_fragment:
EXAMPLES = '''
- name: List tasks on node01
- community.general.proxmox_task_info:
+ community.general.proxmox_tasks_info:
api_host: proxmoxhost
api_user: root@pam
api_password: '{{ password | default(omit) }}'
@@ -47,7 +47,7 @@ EXAMPLES = '''
register: result
- name: Retrieve information about specific tasks on node01
- community.general.proxmox_task_info:
+ community.general.proxmox_tasks_info:
api_host: proxmoxhost
api_user: root@pam
api_password: '{{ password | default(omit) }}'
diff --git a/ansible_collections/community/general/plugins/modules/proxmox_template.py b/ansible_collections/community/general/plugins/modules/proxmox_template.py
index 2bf24ff84..615bfc182 100644
--- a/ansible_collections/community/general/plugins/modules/proxmox_template.py
+++ b/ansible_collections/community/general/plugins/modules/proxmox_template.py
@@ -28,18 +28,18 @@ options:
src:
description:
- Path to uploaded file.
- - Required only for I(state=present).
+ - Required only for O(state=present).
type: path
template:
description:
- The template name.
- - Required for I(state=absent) to delete a template.
- - Required for I(state=present) to download an appliance container template (pveam).
+ - Required for O(state=absent) to delete a template.
+ - Required for O(state=present) to download an appliance container template (pveam).
type: str
content_type:
description:
- Content type.
- - Required only for I(state=present).
+ - Required only for O(state=present).
type: str
default: 'vztmpl'
choices: ['vztmpl', 'iso']
@@ -55,7 +55,7 @@ options:
default: 30
force:
description:
- - It can only be used with I(state=present), existing template will be overwritten.
+ - It can only be used with O(state=present), existing template will be overwritten.
type: bool
default: false
state:
@@ -65,7 +65,8 @@ options:
choices: ['present', 'absent']
default: present
notes:
- - Requires C(proxmoxer) and C(requests) modules on host. This modules can be installed with M(ansible.builtin.pip).
+ - Requires C(proxmoxer) and C(requests) modules on host. Those modules can be installed with M(ansible.builtin.pip).
+ - C(proxmoxer) >= 1.2.0 requires C(requests_toolbelt) to upload files larger than 256 MB.
author: Sergei Antipov (@UnderGreen)
extends_documentation_fragment:
- community.general.proxmox.documentation
@@ -123,15 +124,29 @@ EXAMPLES = '''
import os
import time
+import traceback
-from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible_collections.community.general.plugins.module_utils.proxmox import (proxmox_auth_argument_spec, ProxmoxAnsible)
+from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
+
+REQUESTS_TOOLBELT_ERR = None
+try:
+ # requests_toolbelt is used internally by proxmoxer module
+ import requests_toolbelt # noqa: F401, pylint: disable=unused-import
+ HAS_REQUESTS_TOOLBELT = True
+except ImportError:
+ HAS_REQUESTS_TOOLBELT = False
+ REQUESTS_TOOLBELT_ERR = traceback.format_exc()
class ProxmoxTemplateAnsible(ProxmoxAnsible):
def get_template(self, node, storage, content_type, template):
- return [True for tmpl in self.proxmox_api.nodes(node).storage(storage).content.get()
- if tmpl['volid'] == '%s:%s/%s' % (storage, content_type, template)]
+ try:
+ return [True for tmpl in self.proxmox_api.nodes(node).storage(storage).content.get()
+ if tmpl['volid'] == '%s:%s/%s' % (storage, content_type, template)]
+ except Exception as e:
+ self.module.fail_json(msg="Failed to retrieve template '%s:%s/%s': %s" % (storage, content_type, template, e))
def task_status(self, node, taskid, timeout):
"""
@@ -149,12 +164,24 @@ class ProxmoxTemplateAnsible(ProxmoxAnsible):
return False
def upload_template(self, node, storage, content_type, realpath, timeout):
- taskid = self.proxmox_api.nodes(node).storage(storage).upload.post(content=content_type, filename=open(realpath, 'rb'))
- return self.task_status(node, taskid, timeout)
+ stats = os.stat(realpath)
+ if (LooseVersion(self.proxmoxer_version) >= LooseVersion('1.2.0') and
+ stats.st_size > 268435456 and not HAS_REQUESTS_TOOLBELT):
+ self.module.fail_json(msg="'requests_toolbelt' module is required to upload files larger than 256MB",
+ exception=missing_required_lib('requests_toolbelt'))
+
+ try:
+ taskid = self.proxmox_api.nodes(node).storage(storage).upload.post(content=content_type, filename=open(realpath, 'rb'))
+ return self.task_status(node, taskid, timeout)
+ except Exception as e:
+ self.module.fail_json(msg="Uploading template %s failed with error: %s" % (realpath, e))
def download_template(self, node, storage, template, timeout):
- taskid = self.proxmox_api.nodes(node).aplinfo.post(storage=storage, template=template)
- return self.task_status(node, taskid, timeout)
+ try:
+ taskid = self.proxmox_api.nodes(node).aplinfo.post(storage=storage, template=template)
+ return self.task_status(node, taskid, timeout)
+ except Exception as e:
+ self.module.fail_json(msg="Downloading template %s failed with error: %s" % (template, e))
def delete_template(self, node, storage, content_type, template, timeout):
volid = '%s:%s/%s' % (storage, content_type, template)
@@ -199,35 +226,32 @@ def main():
timeout = module.params['timeout']
if state == 'present':
- try:
- content_type = module.params['content_type']
- src = module.params['src']
+ content_type = module.params['content_type']
+ src = module.params['src']
- # download appliance template
- if content_type == 'vztmpl' and not src:
- template = module.params['template']
+ # download appliance template
+ if content_type == 'vztmpl' and not src:
+ template = module.params['template']
- if not template:
- module.fail_json(msg='template param for downloading appliance template is mandatory')
+ if not template:
+ module.fail_json(msg='template param for downloading appliance template is mandatory')
- if proxmox.get_template(node, storage, content_type, template) and not module.params['force']:
- module.exit_json(changed=False, msg='template with volid=%s:%s/%s already exists' % (storage, content_type, template))
+ if proxmox.get_template(node, storage, content_type, template) and not module.params['force']:
+ module.exit_json(changed=False, msg='template with volid=%s:%s/%s already exists' % (storage, content_type, template))
- if proxmox.download_template(node, storage, template, timeout):
- module.exit_json(changed=True, msg='template with volid=%s:%s/%s downloaded' % (storage, content_type, template))
+ if proxmox.download_template(node, storage, template, timeout):
+ module.exit_json(changed=True, msg='template with volid=%s:%s/%s downloaded' % (storage, content_type, template))
- template = os.path.basename(src)
- if proxmox.get_template(node, storage, content_type, template) and not module.params['force']:
- module.exit_json(changed=False, msg='template with volid=%s:%s/%s is already exists' % (storage, content_type, template))
- elif not src:
- module.fail_json(msg='src param to uploading template file is mandatory')
- elif not (os.path.exists(src) and os.path.isfile(src)):
- module.fail_json(msg='template file on path %s not exists' % src)
-
- if proxmox.upload_template(node, storage, content_type, src, timeout):
- module.exit_json(changed=True, msg='template with volid=%s:%s/%s uploaded' % (storage, content_type, template))
- except Exception as e:
- module.fail_json(msg="uploading/downloading of template %s failed with exception: %s" % (template, e))
+ template = os.path.basename(src)
+ if proxmox.get_template(node, storage, content_type, template) and not module.params['force']:
+ module.exit_json(changed=False, msg='template with volid=%s:%s/%s is already exists' % (storage, content_type, template))
+ elif not src:
+ module.fail_json(msg='src param to uploading template file is mandatory')
+ elif not (os.path.exists(src) and os.path.isfile(src)):
+ module.fail_json(msg='template file on path %s not exists' % src)
+
+ if proxmox.upload_template(node, storage, content_type, src, timeout):
+ module.exit_json(changed=True, msg='template with volid=%s:%s/%s uploaded' % (storage, content_type, template))
elif state == 'absent':
try:
diff --git a/ansible_collections/community/general/plugins/modules/proxmox_user_info.py b/ansible_collections/community/general/plugins/modules/proxmox_user_info.py
index a515f2b45..20154528a 100644
--- a/ansible_collections/community/general/plugins/modules/proxmox_user_info.py
+++ b/ansible_collections/community/general/plugins/modules/proxmox_user_info.py
@@ -193,14 +193,14 @@ class ProxmoxUser:
self.user[k] = v
elif k in ['groups', 'tokens'] and (v == '' or v is None):
self.user[k] = []
- elif k == 'groups' and type(v) == str:
+ elif k == 'groups' and isinstance(v, str):
self.user['groups'] = v.split(',')
- elif k == 'tokens' and type(v) == list:
+ elif k == 'tokens' and isinstance(v, list):
for token in v:
if 'privsep' in token:
token['privsep'] = proxmox_to_ansible_bool(token['privsep'])
self.user['tokens'] = v
- elif k == 'tokens' and type(v) == dict:
+ elif k == 'tokens' and isinstance(v, dict):
self.user['tokens'] = list()
for tokenid, tokenvalues in v.items():
t = tokenvalues
diff --git a/ansible_collections/community/general/plugins/modules/proxmox_vm_info.py b/ansible_collections/community/general/plugins/modules/proxmox_vm_info.py
new file mode 100644
index 000000000..30342b684
--- /dev/null
+++ b/ansible_collections/community/general/plugins/modules/proxmox_vm_info.py
@@ -0,0 +1,267 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2023, Sergei Antipov <greendayonfire at gmail.com>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+---
+module: proxmox_vm_info
+short_description: Retrieve information about one or more Proxmox VE virtual machines
+version_added: 7.2.0
+description:
+ - Retrieve information about one or more Proxmox VE virtual machines.
+author: 'Sergei Antipov (@UnderGreen) <greendayonfire at gmail dot com>'
+options:
+ node:
+ description:
+ - Restrict results to a specific Proxmox VE node.
+ type: str
+ type:
+ description:
+ - Restrict results to a specific virtual machine(s) type.
+ type: str
+ choices:
+ - all
+ - qemu
+ - lxc
+ default: all
+ vmid:
+ description:
+ - Restrict results to a specific virtual machine by using its ID.
+ - If VM with the specified vmid does not exist in a cluster then resulting list will be empty.
+ type: int
+ name:
+ description:
+ - Restrict results to a specific virtual machine(s) by using their name.
+ - If VM(s) with the specified name do not exist in a cluster then the resulting list will be empty.
+ type: str
+ config:
+ description:
+ - Whether to retrieve the VM configuration along with VM status.
+ - If set to V(none) (default), no configuration will be returned.
+ - If set to V(current), the current running configuration will be returned.
+ - If set to V(pending), the configuration with pending changes applied will be returned.
+ type: str
+ choices:
+ - none
+ - current
+ - pending
+ default: none
+ version_added: 8.1.0
+extends_documentation_fragment:
+ - community.general.proxmox.documentation
+ - community.general.attributes
+ - community.general.attributes.info_module
+"""
+
+EXAMPLES = """
+- name: List all existing virtual machines on node
+ community.general.proxmox_vm_info:
+ api_host: proxmoxhost
+ api_user: root@pam
+ api_token_id: '{{ token_id | default(omit) }}'
+ api_token_secret: '{{ token_secret | default(omit) }}'
+ node: node01
+
+- name: List all QEMU virtual machines on node
+ community.general.proxmox_vm_info:
+ api_host: proxmoxhost
+ api_user: root@pam
+ api_password: '{{ password | default(omit) }}'
+ node: node01
+ type: qemu
+
+- name: Retrieve information about specific VM by ID
+ community.general.proxmox_vm_info:
+ api_host: proxmoxhost
+ api_user: root@pam
+ api_password: '{{ password | default(omit) }}'
+ node: node01
+ type: qemu
+ vmid: 101
+
+- name: Retrieve information about specific VM by name and get current configuration
+ community.general.proxmox_vm_info:
+ api_host: proxmoxhost
+ api_user: root@pam
+ api_password: '{{ password | default(omit) }}'
+ node: node01
+ type: lxc
+ name: lxc05.home.arpa
+ config: current
+"""
+
+RETURN = """
+proxmox_vms:
+ description: List of virtual machines.
+ returned: on success
+ type: list
+ elements: dict
+ sample:
+ [
+ {
+ "cpu": 0.258944410905281,
+ "cpus": 1,
+ "disk": 0,
+ "diskread": 0,
+ "diskwrite": 0,
+ "id": "qemu/100",
+ "maxcpu": 1,
+ "maxdisk": 34359738368,
+ "maxmem": 4294967296,
+ "mem": 35158379,
+ "name": "pxe.home.arpa",
+ "netin": 99715803,
+ "netout": 14237835,
+ "node": "pve",
+ "pid": 1947197,
+ "status": "running",
+ "template": False,
+ "type": "qemu",
+ "uptime": 135530,
+ "vmid": 100
+ },
+ {
+ "cpu": 0,
+ "cpus": 1,
+ "disk": 0,
+ "diskread": 0,
+ "diskwrite": 0,
+ "id": "qemu/101",
+ "maxcpu": 1,
+ "maxdisk": 0,
+ "maxmem": 536870912,
+ "mem": 0,
+ "name": "test1",
+ "netin": 0,
+ "netout": 0,
+ "node": "pve",
+ "status": "stopped",
+ "template": False,
+ "type": "qemu",
+ "uptime": 0,
+ "vmid": 101
+ }
+ ]
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.community.general.plugins.module_utils.proxmox import (
+ proxmox_auth_argument_spec,
+ ProxmoxAnsible,
+ proxmox_to_ansible_bool,
+)
+
+
+class ProxmoxVmInfoAnsible(ProxmoxAnsible):
+ def get_vms_from_cluster_resources(self):
+ try:
+ return self.proxmox_api.cluster().resources().get(type="vm")
+ except Exception as e:
+ self.module.fail_json(
+ msg="Failed to retrieve VMs information from cluster resources: %s" % e
+ )
+
+ def get_vms_from_nodes(self, cluster_machines, type, vmid=None, name=None, node=None, config=None):
+ # Leave in dict only machines that user wants to know about
+ filtered_vms = {
+ vm: info for vm, info in cluster_machines.items() if not (
+ type != info["type"]
+ or (node and info["node"] != node)
+ or (vmid and int(info["vmid"]) != vmid)
+ or (name is not None and info["name"] != name)
+ )
+ }
+ # Get list of unique node names and loop through it to get info about machines.
+ nodes = frozenset([info["node"] for vm, info in filtered_vms.items()])
+ for this_node in nodes:
+ # "type" is mandatory and can have only values of "qemu" or "lxc". Seems that use of reflection is safe.
+ call_vm_getter = getattr(self.proxmox_api.nodes(this_node), type)
+ vms_from_this_node = call_vm_getter().get()
+ for detected_vm in vms_from_this_node:
+ this_vm_id = int(detected_vm["vmid"])
+ desired_vm = filtered_vms.get(this_vm_id, None)
+ if desired_vm:
+ desired_vm.update(detected_vm)
+ desired_vm["vmid"] = this_vm_id
+ desired_vm["template"] = proxmox_to_ansible_bool(desired_vm["template"])
+ # When user wants to retrieve the VM configuration
+ if config != "none":
+ # pending = 0, current = 1
+ config_type = 0 if config == "pending" else 1
+ # GET /nodes/{node}/qemu/{vmid}/config current=[0/1]
+ desired_vm["config"] = call_vm_getter(this_vm_id).config().get(current=config_type)
+ return filtered_vms
+
+ def get_qemu_vms(self, cluster_machines, vmid=None, name=None, node=None, config=None):
+ try:
+ return self.get_vms_from_nodes(cluster_machines, "qemu", vmid, name, node, config)
+ except Exception as e:
+ self.module.fail_json(msg="Failed to retrieve QEMU VMs information: %s" % e)
+
+ def get_lxc_vms(self, cluster_machines, vmid=None, name=None, node=None, config=None):
+ try:
+ return self.get_vms_from_nodes(cluster_machines, "lxc", vmid, name, node, config)
+ except Exception as e:
+ self.module.fail_json(msg="Failed to retrieve LXC VMs information: %s" % e)
+
+
+def main():
+ module_args = proxmox_auth_argument_spec()
+ vm_info_args = dict(
+ node=dict(type="str", required=False),
+ type=dict(
+ type="str", choices=["lxc", "qemu", "all"], default="all", required=False
+ ),
+ vmid=dict(type="int", required=False),
+ name=dict(type="str", required=False),
+ config=dict(
+ type="str", choices=["none", "current", "pending"],
+ default="none", required=False
+ ),
+ )
+ module_args.update(vm_info_args)
+
+ module = AnsibleModule(
+ argument_spec=module_args,
+ required_together=[("api_token_id", "api_token_secret")],
+ required_one_of=[("api_password", "api_token_id")],
+ supports_check_mode=True,
+ )
+
+ proxmox = ProxmoxVmInfoAnsible(module)
+ node = module.params["node"]
+ type = module.params["type"]
+ vmid = module.params["vmid"]
+ name = module.params["name"]
+ config = module.params["config"]
+
+ result = dict(changed=False)
+
+ if node and proxmox.get_node(node) is None:
+ module.fail_json(msg="Node %s doesn't exist in PVE cluster" % node)
+
+ vms_cluster_resources = proxmox.get_vms_from_cluster_resources()
+ cluster_machines = {int(machine["vmid"]): machine for machine in vms_cluster_resources}
+ vms = {}
+
+ if type == "lxc":
+ vms = proxmox.get_lxc_vms(cluster_machines, vmid, name, node, config)
+ elif type == "qemu":
+ vms = proxmox.get_qemu_vms(cluster_machines, vmid, name, node, config)
+ else:
+ vms = proxmox.get_qemu_vms(cluster_machines, vmid, name, node, config)
+ vms.update(proxmox.get_lxc_vms(cluster_machines, vmid, name, node, config))
+
+ result["proxmox_vms"] = [info for vm, info in sorted(vms.items())]
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/general/plugins/modules/pubnub_blocks.py b/ansible_collections/community/general/plugins/modules/pubnub_blocks.py
index a03553c5c..34098873a 100644
--- a/ansible_collections/community/general/plugins/modules/pubnub_blocks.py
+++ b/ansible_collections/community/general/plugins/modules/pubnub_blocks.py
@@ -27,7 +27,6 @@ author:
- PubNub <support@pubnub.com> (@pubnub)
- Sergey Mamontov <sergey@pubnub.com> (@parfeon)
requirements:
- - "python >= 2.7"
- "pubnub_blocks_client >= 1.0"
extends_documentation_fragment:
- community.general.attributes
@@ -40,15 +39,15 @@ options:
email:
description:
- Email from account for which new session should be started.
- - "Not required if C(cache) contains result of previous module call (in
+ - "Not required if O(cache) contains result of previous module call (in
same play)."
required: false
type: str
default: ''
password:
description:
- - Password which match to account to which specified C(email) belong.
- - "Not required if C(cache) contains result of previous module call (in
+ - Password which match to account to which specified O(email) belong.
+ - "Not required if O(cache) contains result of previous module call (in
same play)."
required: false
type: str
@@ -63,7 +62,7 @@ options:
default: {}
account:
description:
- - "Name of PubNub account for from which C(application) will be used to
+ - "Name of PubNub account for from which O(application) will be used to
manage blocks."
- "User's account will be used if value not set or empty."
type: str
@@ -71,7 +70,7 @@ options:
application:
description:
- "Name of target PubNub application for which blocks configuration on
- specific C(keyset) will be done."
+ specific O(keyset) will be done."
type: str
required: true
keyset:
@@ -102,7 +101,7 @@ options:
event_handlers:
description:
- "List of event handlers which should be updated for specified block
- C(name)."
+ O(name)."
- "Each entry for new event handler should contain: C(name), C(src),
C(channels), C(event). C(name) used as event handler name which can be
used later to make changes to it."
@@ -110,7 +109,7 @@ options:
- "C(channels) is name of channel from which event handler is waiting
for events."
- "C(event) is type of event which is able to trigger event handler:
- I(js-before-publish), I(js-after-publish), I(js-after-presence)."
+ C(js-before-publish), C(js-after-publish), C(js-after-presence)."
- "Each entry for existing handlers should contain C(name) (so target
handler can be identified). Rest parameters (C(src), C(channels) and
C(event)) can be added if changes required for them."
@@ -127,7 +126,7 @@ options:
description:
- "List of fields which should be changed by block itself (doesn't
affect any event handlers)."
- - "Possible options for change is: C(name)."
+ - "Possible options for change is: O(name)."
required: false
default: {}
type: dict
@@ -136,7 +135,7 @@ options:
- "This key allow to try skip certificates check when performing REST API
calls. Sometimes host may have issues with certificates on it and this
will cause problems to call PubNub REST API."
- - If check should be ignored C(False) should be passed to this parameter.
+ - If check should be ignored V(false) should be passed to this parameter.
required: false
default: true
type: bool
@@ -243,7 +242,7 @@ import os
try:
# Import PubNub BLOCKS client.
- from pubnub_blocks_client import User, Account, Owner, Application, Keyset # noqa: F401, pylint: disable=unused-import
+ from pubnub_blocks_client import User
from pubnub_blocks_client import Block, EventHandler
from pubnub_blocks_client import exceptions
HAS_PUBNUB_BLOCKS_CLIENT = True
diff --git a/ansible_collections/community/general/plugins/modules/pulp_repo.py b/ansible_collections/community/general/plugins/modules/pulp_repo.py
index d7333f89e..c581fa318 100644
--- a/ansible_collections/community/general/plugins/modules/pulp_repo.py
+++ b/ansible_collections/community/general/plugins/modules/pulp_repo.py
@@ -67,7 +67,7 @@ options:
aliases: [ importer_ssl_client_cert ]
feed_client_key:
description:
- - Private key to the certificate specified in I(importer_ssl_client_cert),
+ - Private key to the certificate specified in O(feed_client_cert),
assuming it is not included in the certificate file itself. This can be
the file content or the path to the file.
type: str
@@ -105,7 +105,7 @@ options:
type: str
publish_distributor:
description:
- - Distributor to use when state is C(publish). The default is to
+ - Distributor to use when O(state=publish). The default is to
publish all distributors.
type: str
pulp_host:
@@ -119,13 +119,13 @@ options:
type: str
repo_type:
description:
- - Repo plugin type to use (i.e. C(rpm), C(docker)).
+ - Repo plugin type to use (that is, V(rpm), V(docker)).
default: rpm
type: str
repoview:
description:
- Whether to generate repoview files for a published repository. Setting
- this to C(true) automatically activates C(generate_sqlite).
+ this to V(true) automatically activates O(generate_sqlite).
required: false
type: bool
default: false
@@ -141,23 +141,23 @@ options:
default: true
state:
description:
- - The repo state. A state of C(sync) will queue a sync of the repo.
+ - The repo state. A state of V(sync) will queue a sync of the repo.
This is asynchronous but not delayed like a scheduled sync. A state of
- C(publish) will use the repository's distributor to publish the content.
+ V(publish) will use the repository's distributor to publish the content.
default: present
choices: [ "present", "absent", "sync", "publish" ]
type: str
url_password:
description:
- The password for use in HTTP basic authentication to the pulp API.
- If the I(url_username) parameter is not specified, the I(url_password)
+ If the O(url_username) parameter is not specified, the O(url_password)
parameter will not be used.
url_username:
description:
- The username for use in HTTP basic authentication to the pulp API.
validate_certs:
description:
- - If C(false), SSL certificates will not be validated. This should only be
+ - If V(false), SSL certificates will not be validated. This should only be
used on personally controlled sites using self-signed certificates.
type: bool
default: true
diff --git a/ansible_collections/community/general/plugins/modules/puppet.py b/ansible_collections/community/general/plugins/modules/puppet.py
index cd580791b..86eac062a 100644
--- a/ansible_collections/community/general/plugins/modules/puppet.py
+++ b/ansible_collections/community/general/plugins/modules/puppet.py
@@ -13,7 +13,7 @@ DOCUMENTATION = r'''
module: puppet
short_description: Runs puppet
description:
- - Runs I(puppet) agent or apply in a reliable manner.
+ - Runs C(puppet) agent or apply in a reliable manner.
extends_documentation_fragment:
- community.general.attributes
attributes:
@@ -24,7 +24,7 @@ attributes:
options:
timeout:
description:
- - How long to wait for I(puppet) to finish.
+ - How long to wait for C(puppet) to finish.
type: str
default: 30m
puppetmaster:
@@ -42,8 +42,8 @@ options:
noop:
description:
- Override puppet.conf noop mode.
- - When C(true), run Puppet agent with C(--noop) switch set.
- - When C(false), run Puppet agent with C(--no-noop) switch set.
+ - When V(true), run Puppet agent with C(--noop) switch set.
+ - When V(false), run Puppet agent with C(--no-noop) switch set.
- When unset (default), use default or puppet.conf value if defined.
type: bool
facts:
@@ -67,8 +67,8 @@ options:
logdest:
description:
- Where the puppet logs should go, if puppet apply is being used.
- - C(all) will go to both C(console) and C(syslog).
- - C(stdout) will be deprecated and replaced by C(console).
+ - V(all) will go to both C(console) and C(syslog).
+ - V(stdout) will be deprecated and replaced by C(console).
type: str
choices: [ all, stdout, syslog ]
default: stdout
@@ -114,8 +114,6 @@ options:
show_diff:
description:
- Whether to print file changes details
- - Alias C(show-diff) has been deprecated and will be removed in community.general 7.0.0.
- aliases: ['show-diff']
type: bool
default: false
requirements:
@@ -198,9 +196,7 @@ def main():
noop=dict(type='bool'),
logdest=dict(type='str', default='stdout', choices=['all', 'stdout', 'syslog']),
# The following is not related to Ansible's diff; see https://github.com/ansible-collections/community.general/pull/3980#issuecomment-1005666154
- show_diff=dict(
- type='bool', default=False, aliases=['show-diff'],
- deprecated_aliases=[dict(name='show-diff', version='7.0.0', collection_name='community.general')]),
+ show_diff=dict(type='bool', default=False),
facts=dict(type='dict'),
facter_basename=dict(type='str', default='ansible'),
environment=dict(type='str'),
diff --git a/ansible_collections/community/general/plugins/modules/pushbullet.py b/ansible_collections/community/general/plugins/modules/pushbullet.py
index c7e20c373..673f30cc3 100644
--- a/ansible_collections/community/general/plugins/modules/pushbullet.py
+++ b/ansible_collections/community/general/plugins/modules/pushbullet.py
@@ -59,7 +59,7 @@ options:
url:
type: str
description:
- - URL field, used when I(push_type) is C(link).
+ - URL field, used when O(push_type=link).
notes:
- Requires pushbullet.py Python package on the remote host.
diff --git a/ansible_collections/community/general/plugins/modules/python_requirements_info.py b/ansible_collections/community/general/plugins/modules/python_requirements_info.py
index 231114a1d..8e709440d 100644
--- a/ansible_collections/community/general/plugins/modules/python_requirements_info.py
+++ b/ansible_collections/community/general/plugins/modules/python_requirements_info.py
@@ -12,7 +12,6 @@ module: python_requirements_info
short_description: Show python path and assert dependency versions
description:
- Get info about available Python requirements on the target host, including listing required libraries and gathering versions.
- - This module was called C(python_requirements_facts) before Ansible 2.9. The usage did not change.
extends_documentation_fragment:
- community.general.attributes
- community.general.attributes.info_module
@@ -23,8 +22,8 @@ options:
description: >
A list of version-likes or module names to check for installation.
Supported operators: <, >, <=, >=, or ==. The bare module name like
- I(ansible), the module with a specific version like I(boto3==1.6.1), or a
- partial version like I(requests>2) are all valid specifications.
+ V(ansible), the module with a specific version like V(boto3==1.6.1), or a
+ partial version like V(requests>2) are all valid specifications.
default: []
author:
- Will Thames (@willthames)
@@ -92,7 +91,7 @@ python_system_path:
- /usr/local/opt/python@2/site-packages/
- /usr/lib/python/site-packages/
valid:
- description: A dictionary of dependencies that matched their desired versions. If no version was specified, then I(desired) will be null
+ description: A dictionary of dependencies that matched their desired versions. If no version was specified, then RV(ignore:desired) will be null
returned: always
type: dict
sample:
diff --git a/ansible_collections/community/general/plugins/modules/rax.py b/ansible_collections/community/general/plugins/modules/rax.py
index 47c0a6d1b..76e429944 100644
--- a/ansible_collections/community/general/plugins/modules/rax.py
+++ b/ansible_collections/community/general/plugins/modules/rax.py
@@ -24,15 +24,15 @@ options:
auto_increment:
description:
- Whether or not to increment a single number with the name of the
- created servers. Only applicable when used with the I(group) attribute
+ created servers. Only applicable when used with the O(group) attribute
or meta key.
type: bool
default: true
boot_from_volume:
description:
- Whether or not to boot the instance from a Cloud Block Storage volume.
- If C(true) and I(image) is specified a new volume will be created at
- boot time. I(boot_volume_size) is required with I(image) to create a
+ If V(true) and O(image) is specified a new volume will be created at
+ boot time. O(boot_volume_size) is required with O(image) to create a
new volume at boot time.
type: bool
default: false
@@ -45,11 +45,11 @@ options:
type: int
description:
- Size of the volume to create in Gigabytes. This is only required with
- I(image) and I(boot_from_volume).
+ O(image) and O(boot_from_volume).
default: 100
boot_volume_terminate:
description:
- - Whether the I(boot_volume) or newly created volume from I(image) will
+ - Whether the O(boot_volume) or newly created volume from O(image) will
be terminated when the server is terminated
type: bool
default: false
@@ -72,16 +72,16 @@ options:
type: str
description:
- Disk partitioning strategy
- - If not specified it will assume the value C(auto).
+ - If not specified it will assume the value V(auto).
choices:
- auto
- manual
exact_count:
description:
- Explicitly ensure an exact count of instances, used with
- state=active/present. If specified as C(true) and I(count) is less than
+ state=active/present. If specified as V(true) and O(count) is less than
the servers matched, servers will be deleted to match the count. If
- the number of matched servers is fewer than specified in I(count)
+ the number of matched servers is fewer than specified in O(count)
additional servers will be added.
type: bool
default: false
@@ -116,7 +116,7 @@ options:
type: str
description:
- image to use for the instance. Can be an C(id), C(human_id) or C(name).
- With I(boot_from_volume), a Cloud Block Storage volume will be created
+ With O(boot_from_volume), a Cloud Block Storage volume will be created
with this image
instance_ids:
type: list
@@ -161,7 +161,7 @@ options:
type: str
description:
- Data to be uploaded to the servers config drive. This option implies
- I(config_drive). Can be a file path or a string
+ O(config_drive). Can be a file path or a string
wait:
description:
- wait for the instance to be in state 'running' before returning
@@ -176,11 +176,11 @@ author:
- "Jesse Keating (@omgjlk)"
- "Matt Martz (@sivel)"
notes:
- - I(exact_count) can be "destructive" if the number of running servers in
- the I(group) is larger than that specified in I(count). In such a case, the
- I(state) is effectively set to C(absent) and the extra servers are deleted.
- In the case of deletion, the returned data structure will have C(action)
- set to C(delete), and the oldest servers in the group will be deleted.
+ - O(exact_count) can be "destructive" if the number of running servers in
+ the O(group) is larger than that specified in O(count). In such a case, the
+ O(state) is effectively set to V(absent) and the extra servers are deleted.
+ In the case of deletion, the returned data structure will have RV(ignore:action)
+ set to V(delete), and the oldest servers in the group will be deleted.
extends_documentation_fragment:
- community.general.rackspace.openstack
- community.general.attributes
diff --git a/ansible_collections/community/general/plugins/modules/rax_cbs.py b/ansible_collections/community/general/plugins/modules/rax_cbs.py
index c99626904..77e7cebad 100644
--- a/ansible_collections/community/general/plugins/modules/rax_cbs.py
+++ b/ansible_collections/community/general/plugins/modules/rax_cbs.py
@@ -13,9 +13,7 @@ DOCUMENTATION = '''
module: rax_cbs
short_description: Manipulate Rackspace Cloud Block Storage Volumes
description:
- - Manipulate Rackspace Cloud Block Storage Volumes
- - This module relies on the C(pyrax) package which is deprecated in favour of using Openstack API.
- - Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0.
+ - Manipulate Rackspace Cloud Block Storage Volumes
attributes:
check_mode:
support: none
diff --git a/ansible_collections/community/general/plugins/modules/rax_cbs_attachments.py b/ansible_collections/community/general/plugins/modules/rax_cbs_attachments.py
index 8f540fa0f..00b860a90 100644
--- a/ansible_collections/community/general/plugins/modules/rax_cbs_attachments.py
+++ b/ansible_collections/community/general/plugins/modules/rax_cbs_attachments.py
@@ -13,9 +13,7 @@ DOCUMENTATION = '''
module: rax_cbs_attachments
short_description: Manipulate Rackspace Cloud Block Storage Volume Attachments
description:
- - Manipulate Rackspace Cloud Block Storage Volume Attachments
- - This module relies on the C(pyrax) package which is deprecated in favour of using Openstack API.
- - Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0.
+ - Manipulate Rackspace Cloud Block Storage Volume Attachments
attributes:
check_mode:
support: none
diff --git a/ansible_collections/community/general/plugins/modules/rax_cdb.py b/ansible_collections/community/general/plugins/modules/rax_cdb.py
index cf0366d3b..9538579fa 100644
--- a/ansible_collections/community/general/plugins/modules/rax_cdb.py
+++ b/ansible_collections/community/general/plugins/modules/rax_cdb.py
@@ -16,8 +16,6 @@ description:
- creates / deletes or resize a Rackspace Cloud Databases instance
and optionally waits for it to be 'running'. The name option needs to be
unique since it's used to identify the instance.
- - This module relies on the C(pyrax) package which is deprecated in favour of using Openstack API.
- - Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0.
attributes:
check_mode:
support: none
@@ -49,7 +47,7 @@ options:
type: str
description:
- version of database (MySQL supports 5.1 and 5.6, MariaDB supports 10, Percona supports 5.6)
- - "The available choices are: C(5.1), C(5.6) and C(10)."
+ - "The available choices are: V(5.1), V(5.6) and V(10)."
default: '5.6'
aliases: ['version']
state:
diff --git a/ansible_collections/community/general/plugins/modules/rax_cdb_database.py b/ansible_collections/community/general/plugins/modules/rax_cdb_database.py
index 35b076aad..b0db11814 100644
--- a/ansible_collections/community/general/plugins/modules/rax_cdb_database.py
+++ b/ansible_collections/community/general/plugins/modules/rax_cdb_database.py
@@ -13,8 +13,6 @@ module: rax_cdb_database
short_description: Create / delete a database in the Cloud Databases
description:
- create / delete a database in the Cloud Databases.
- - This module relies on the C(pyrax) package which is deprecated in favour of using Openstack API.
- - Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0.
attributes:
check_mode:
support: none
diff --git a/ansible_collections/community/general/plugins/modules/rax_cdb_user.py b/ansible_collections/community/general/plugins/modules/rax_cdb_user.py
index a2cd675d9..6ee86c4fe 100644
--- a/ansible_collections/community/general/plugins/modules/rax_cdb_user.py
+++ b/ansible_collections/community/general/plugins/modules/rax_cdb_user.py
@@ -14,8 +14,6 @@ module: rax_cdb_user
short_description: Create / delete a Rackspace Cloud Database
description:
- create / delete a database in the Cloud Databases.
- - This module relies on the C(pyrax) package which is deprecated in favour of using Openstack API.
- - Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0.
attributes:
check_mode:
support: none
diff --git a/ansible_collections/community/general/plugins/modules/rax_clb.py b/ansible_collections/community/general/plugins/modules/rax_clb.py
index 9a4ca4f89..23c795f39 100644
--- a/ansible_collections/community/general/plugins/modules/rax_clb.py
+++ b/ansible_collections/community/general/plugins/modules/rax_clb.py
@@ -13,9 +13,7 @@ DOCUMENTATION = '''
module: rax_clb
short_description: Create / delete a load balancer in Rackspace Public Cloud
description:
- - creates / deletes a Rackspace Public Cloud load balancer.
- - This module relies on the C(pyrax) package which is deprecated in favour of using Openstack API.
- - Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0.
+ - creates / deletes a Rackspace Public Cloud load balancer.
attributes:
check_mode:
support: none
diff --git a/ansible_collections/community/general/plugins/modules/rax_clb_nodes.py b/ansible_collections/community/general/plugins/modules/rax_clb_nodes.py
index 219f0c2ba..c076dced7 100644
--- a/ansible_collections/community/general/plugins/modules/rax_clb_nodes.py
+++ b/ansible_collections/community/general/plugins/modules/rax_clb_nodes.py
@@ -13,9 +13,7 @@ DOCUMENTATION = '''
module: rax_clb_nodes
short_description: Add, modify and remove nodes from a Rackspace Cloud Load Balancer
description:
- - Adds, modifies and removes nodes from a Rackspace Cloud Load Balancer.
- - This module relies on the C(pyrax) package which is deprecated in favour of using Openstack API.
- - Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0.
+ - Adds, modifies and removes nodes from a Rackspace Cloud Load Balancer
attributes:
check_mode:
support: none
diff --git a/ansible_collections/community/general/plugins/modules/rax_clb_ssl.py b/ansible_collections/community/general/plugins/modules/rax_clb_ssl.py
index 5dca9d3ec..b794130cf 100644
--- a/ansible_collections/community/general/plugins/modules/rax_clb_ssl.py
+++ b/ansible_collections/community/general/plugins/modules/rax_clb_ssl.py
@@ -12,9 +12,7 @@ DOCUMENTATION = '''
module: rax_clb_ssl
short_description: Manage SSL termination for a Rackspace Cloud Load Balancer
description:
- - Set up, reconfigure, or remove SSL termination for an existing load balancer.
- - This module relies on the C(pyrax) package which is deprecated in favour of using Openstack API.
- - Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0.
+- Set up, reconfigure, or remove SSL termination for an existing load balancer.
attributes:
check_mode:
support: none
diff --git a/ansible_collections/community/general/plugins/modules/rax_dns.py b/ansible_collections/community/general/plugins/modules/rax_dns.py
index e70b76914..31782cd88 100644
--- a/ansible_collections/community/general/plugins/modules/rax_dns.py
+++ b/ansible_collections/community/general/plugins/modules/rax_dns.py
@@ -13,9 +13,7 @@ DOCUMENTATION = '''
module: rax_dns
short_description: Manage domains on Rackspace Cloud DNS
description:
- - Manage domains on Rackspace Cloud DNS.
- - This module relies on the C(pyrax) package which is deprecated in favour of using Openstack API.
- - Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0.
+ - Manage domains on Rackspace Cloud DNS
attributes:
check_mode:
support: none
diff --git a/ansible_collections/community/general/plugins/modules/rax_dns_record.py b/ansible_collections/community/general/plugins/modules/rax_dns_record.py
index fd3ad47ce..cb3cd279e 100644
--- a/ansible_collections/community/general/plugins/modules/rax_dns_record.py
+++ b/ansible_collections/community/general/plugins/modules/rax_dns_record.py
@@ -13,9 +13,7 @@ DOCUMENTATION = '''
module: rax_dns_record
short_description: Manage DNS records on Rackspace Cloud DNS
description:
- - Manage DNS records on Rackspace Cloud DNS.
- - This module relies on the C(pyrax) package which is deprecated in favour of using Openstack API.
- - Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0.
+ - Manage DNS records on Rackspace Cloud DNS
attributes:
check_mode:
support: none
@@ -92,11 +90,9 @@ options:
notes:
- "It is recommended that plays utilizing this module be run with
C(serial: 1) to avoid exceeding the API request limit imposed by
- the Rackspace CloudDNS API"
+ the Rackspace CloudDNS API."
- To manipulate a C(PTR) record either C(loadbalancer) or C(server) must be
- supplied
- - As of version 1.7, the C(type) field is required and no longer defaults to an C(A) record.
- - C(PTR) record support was added in version 1.7
+ supplied.
author: "Matt Martz (@sivel)"
extends_documentation_fragment:
- community.general.rackspace
diff --git a/ansible_collections/community/general/plugins/modules/rax_facts.py b/ansible_collections/community/general/plugins/modules/rax_facts.py
index 9e63fec38..f8bb0e050 100644
--- a/ansible_collections/community/general/plugins/modules/rax_facts.py
+++ b/ansible_collections/community/general/plugins/modules/rax_facts.py
@@ -14,8 +14,6 @@ module: rax_facts
short_description: Gather facts for Rackspace Cloud Servers
description:
- Gather facts for Rackspace Cloud Servers.
- - This module relies on the C(pyrax) package which is deprecated in favour of using Openstack API.
- - Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0.
attributes:
check_mode:
version_added: 3.3.0
diff --git a/ansible_collections/community/general/plugins/modules/rax_files.py b/ansible_collections/community/general/plugins/modules/rax_files.py
index 2d52ebc0f..a63e107eb 100644
--- a/ansible_collections/community/general/plugins/modules/rax_files.py
+++ b/ansible_collections/community/general/plugins/modules/rax_files.py
@@ -13,9 +13,7 @@ DOCUMENTATION = '''
module: rax_files
short_description: Manipulate Rackspace Cloud Files Containers
description:
- - Manipulate Rackspace Cloud Files Containers.
- - This module relies on the C(pyrax) package which is deprecated in favour of using Openstack API.
- - Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0.
+ - Manipulate Rackspace Cloud Files Containers
attributes:
check_mode:
support: none
diff --git a/ansible_collections/community/general/plugins/modules/rax_files_objects.py b/ansible_collections/community/general/plugins/modules/rax_files_objects.py
index 08a5cd4e2..bbcdfe4f8 100644
--- a/ansible_collections/community/general/plugins/modules/rax_files_objects.py
+++ b/ansible_collections/community/general/plugins/modules/rax_files_objects.py
@@ -14,8 +14,6 @@ module: rax_files_objects
short_description: Upload, download, and delete objects in Rackspace Cloud Files
description:
- Upload, download, and delete objects in Rackspace Cloud Files.
- - This module relies on the C(pyrax) package which is deprecated in favour of using Openstack API.
- - Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0.
attributes:
check_mode:
support: none
@@ -25,7 +23,7 @@ options:
clear_meta:
description:
- Optionally clear existing metadata when applying metadata to existing objects.
- Selecting this option is only appropriate when setting I(type=meta).
+ Selecting this option is only appropriate when setting O(type=meta).
type: bool
default: false
container:
@@ -38,7 +36,7 @@ options:
description:
- The destination of a C(get) operation; i.e. a local directory, C(/home/user/myfolder).
Used to specify the destination of an operation on a remote object; i.e. a file name,
- C(file1), or a comma-separated list of remote objects, C(file1,file2,file17).
+ V(file1), or a comma-separated list of remote objects, V(file1,file2,file17).
expires:
type: int
description:
@@ -52,8 +50,8 @@ options:
type: str
description:
- >
- The method of operation to be performed: C(put) to upload files, C(get) to download files or
- C(delete) to remove remote objects in Cloud Files.
+ The method of operation to be performed: V(put) to upload files, V(get) to download files or
+ V(delete) to remove remote objects in Cloud Files.
choices:
- get
- put
@@ -63,8 +61,8 @@ options:
type: str
description:
- Source from which to upload files. Used to specify a remote object as a source for
- an operation, i.e. a file name, C(file1), or a comma-separated list of remote objects,
- C(file1,file2,file17). Parameters I(src) and I(dest) are mutually exclusive on remote-only object operations
+ an operation, i.e. a file name, V(file1), or a comma-separated list of remote objects,
+ V(file1,file2,file17). Parameters O(src) and O(dest) are mutually exclusive on remote-only object operations
structure:
description:
- Used to specify whether to maintain nested directory structure when downloading objects
diff --git a/ansible_collections/community/general/plugins/modules/rax_identity.py b/ansible_collections/community/general/plugins/modules/rax_identity.py
index 19f803953..b2eb15627 100644
--- a/ansible_collections/community/general/plugins/modules/rax_identity.py
+++ b/ansible_collections/community/general/plugins/modules/rax_identity.py
@@ -13,9 +13,7 @@ DOCUMENTATION = '''
module: rax_identity
short_description: Load Rackspace Cloud Identity
description:
- - Verifies Rackspace Cloud credentials and returns identity information.
- - This module relies on the C(pyrax) package which is deprecated in favour of using Openstack API.
- - Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0.
+ - Verifies Rackspace Cloud credentials and returns identity information
attributes:
check_mode:
support: none
diff --git a/ansible_collections/community/general/plugins/modules/rax_keypair.py b/ansible_collections/community/general/plugins/modules/rax_keypair.py
index 22750f03c..d7d7a2cc3 100644
--- a/ansible_collections/community/general/plugins/modules/rax_keypair.py
+++ b/ansible_collections/community/general/plugins/modules/rax_keypair.py
@@ -13,9 +13,7 @@ DOCUMENTATION = '''
module: rax_keypair
short_description: Create a keypair for use with Rackspace Cloud Servers
description:
- - Create a keypair for use with Rackspace Cloud Servers.
- - This module relies on the C(pyrax) package which is deprecated in favour of using Openstack API.
- - Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0.
+ - Create a keypair for use with Rackspace Cloud Servers
attributes:
check_mode:
support: none
diff --git a/ansible_collections/community/general/plugins/modules/rax_meta.py b/ansible_collections/community/general/plugins/modules/rax_meta.py
index 751300858..7b52e906f 100644
--- a/ansible_collections/community/general/plugins/modules/rax_meta.py
+++ b/ansible_collections/community/general/plugins/modules/rax_meta.py
@@ -13,9 +13,7 @@ DOCUMENTATION = '''
module: rax_meta
short_description: Manipulate metadata for Rackspace Cloud Servers
description:
- - Manipulate metadata for Rackspace Cloud Servers.
- - This module relies on the C(pyrax) package which is deprecated in favour of using Openstack API.
- - Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0.
+ - Manipulate metadata for Rackspace Cloud Servers
attributes:
check_mode:
support: none
diff --git a/ansible_collections/community/general/plugins/modules/rax_mon_alarm.py b/ansible_collections/community/general/plugins/modules/rax_mon_alarm.py
index f6e650ec0..b66611a90 100644
--- a/ansible_collections/community/general/plugins/modules/rax_mon_alarm.py
+++ b/ansible_collections/community/general/plugins/modules/rax_mon_alarm.py
@@ -13,14 +13,12 @@ DOCUMENTATION = '''
module: rax_mon_alarm
short_description: Create or delete a Rackspace Cloud Monitoring alarm
description:
- - Create or delete a Rackspace Cloud Monitoring alarm that associates an
- existing rax_mon_entity, rax_mon_check, and rax_mon_notification_plan with
- criteria that specify what conditions will trigger which levels of
- notifications. Rackspace monitoring module flow | rax_mon_entity ->
- rax_mon_check -> rax_mon_notification -> rax_mon_notification_plan ->
- *rax_mon_alarm*.
- - This module relies on the C(pyrax) package which is deprecated in favour of using Openstack API.
- - Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0.
+- Create or delete a Rackspace Cloud Monitoring alarm that associates an
+ existing rax_mon_entity, rax_mon_check, and rax_mon_notification_plan with
+ criteria that specify what conditions will trigger which levels of
+ notifications. Rackspace monitoring module flow | rax_mon_entity ->
+ rax_mon_check -> rax_mon_notification -> rax_mon_notification_plan ->
+ *rax_mon_alarm*
attributes:
check_mode:
support: none
@@ -30,7 +28,7 @@ options:
state:
type: str
description:
- - Ensure that the alarm with this C(label) exists or does not exist.
+ - Ensure that the alarm with this O(label) exists or does not exist.
choices: [ "present", "absent" ]
required: false
default: present
diff --git a/ansible_collections/community/general/plugins/modules/rax_mon_check.py b/ansible_collections/community/general/plugins/modules/rax_mon_check.py
index 6a0ad03a3..253c26dcf 100644
--- a/ansible_collections/community/general/plugins/modules/rax_mon_check.py
+++ b/ansible_collections/community/general/plugins/modules/rax_mon_check.py
@@ -14,14 +14,12 @@ module: rax_mon_check
short_description: Create or delete a Rackspace Cloud Monitoring check for an
existing entity.
description:
- - Create or delete a Rackspace Cloud Monitoring check associated with an
- existing rax_mon_entity. A check is a specific test or measurement that is
- performed, possibly from different monitoring zones, on the systems you
- monitor. Rackspace monitoring module flow | rax_mon_entity ->
- *rax_mon_check* -> rax_mon_notification -> rax_mon_notification_plan ->
- rax_mon_alarm
- - This module relies on the C(pyrax) package which is deprecated in favour of using Openstack API.
- - Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0.
+- Create or delete a Rackspace Cloud Monitoring check associated with an
+ existing rax_mon_entity. A check is a specific test or measurement that is
+ performed, possibly from different monitoring zones, on the systems you
+ monitor. Rackspace monitoring module flow | rax_mon_entity ->
+ *rax_mon_check* -> rax_mon_notification -> rax_mon_notification_plan ->
+ rax_mon_alarm
attributes:
check_mode:
support: none
@@ -31,7 +29,7 @@ options:
state:
type: str
description:
- - Ensure that a check with this C(label) exists or does not exist.
+ - Ensure that a check with this O(label) exists or does not exist.
choices: ["present", "absent"]
default: present
entity_id:
@@ -52,27 +50,27 @@ options:
that have a non-null C(agent_id).
- |
Choices for this option are:
- - C(remote.dns)
- - C(remote.ftp-banner)
- - C(remote.http)
- - C(remote.imap-banner)
- - C(remote.mssql-banner)
- - C(remote.mysql-banner)
- - C(remote.ping)
- - C(remote.pop3-banner)
- - C(remote.postgresql-banner)
- - C(remote.smtp-banner)
- - C(remote.smtp)
- - C(remote.ssh)
- - C(remote.tcp)
- - C(remote.telnet-banner)
- - C(agent.filesystem)
- - C(agent.memory)
- - C(agent.load_average)
- - C(agent.cpu)
- - C(agent.disk)
- - C(agent.network)
- - C(agent.plugin)
+ - V(remote.dns)
+ - V(remote.ftp-banner)
+ - V(remote.http)
+ - V(remote.imap-banner)
+ - V(remote.mssql-banner)
+ - V(remote.mysql-banner)
+ - V(remote.ping)
+ - V(remote.pop3-banner)
+ - V(remote.postgresql-banner)
+ - V(remote.smtp-banner)
+ - V(remote.smtp)
+ - V(remote.ssh)
+ - V(remote.tcp)
+ - V(remote.telnet-banner)
+ - V(agent.filesystem)
+ - V(agent.memory)
+ - V(agent.load_average)
+ - V(agent.cpu)
+ - V(agent.disk)
+ - V(agent.network)
+ - V(agent.plugin)
required: true
monitoring_zones_poll:
type: str
@@ -83,15 +81,15 @@ options:
target_hostname:
type: str
description:
- - One of I(target_hostname) and I(target_alias) is required for remote.* checks,
+ - One of O(target_hostname) and O(target_alias) is required for remote.* checks,
but prohibited for agent.* checks. The hostname this check should target.
Must be a valid IPv4, IPv6, or FQDN.
target_alias:
type: str
description:
- - One of I(target_alias) and I(target_hostname) is required for remote.* checks,
+ - One of O(target_alias) and O(target_hostname) is required for remote.* checks,
but prohibited for agent.* checks. Use the corresponding key in the entity's
- I(ip_addresses) hash to resolve an IP address to target.
+ C(ip_addresses) hash to resolve an IP address to target.
details:
type: dict
default: {}
@@ -101,7 +99,7 @@ options:
256 items.
disabled:
description:
- - If C(true), ensure the check is created, but don't actually use it yet.
+ - If V(true), ensure the check is created, but don't actually use it yet.
type: bool
default: false
metadata:
diff --git a/ansible_collections/community/general/plugins/modules/rax_mon_entity.py b/ansible_collections/community/general/plugins/modules/rax_mon_entity.py
index b42bd173b..fbad9f98f 100644
--- a/ansible_collections/community/general/plugins/modules/rax_mon_entity.py
+++ b/ansible_collections/community/general/plugins/modules/rax_mon_entity.py
@@ -13,13 +13,11 @@ DOCUMENTATION = '''
module: rax_mon_entity
short_description: Create or delete a Rackspace Cloud Monitoring entity
description:
- - Create or delete a Rackspace Cloud Monitoring entity, which represents a device
- to monitor. Entities associate checks and alarms with a target system and
- provide a convenient, centralized place to store IP addresses. Rackspace
- monitoring module flow | *rax_mon_entity* -> rax_mon_check ->
- rax_mon_notification -> rax_mon_notification_plan -> rax_mon_alarm.
- - This module relies on the C(pyrax) package which is deprecated in favour of using Openstack API.
- - Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0.
+- Create or delete a Rackspace Cloud Monitoring entity, which represents a device
+ to monitor. Entities associate checks and alarms with a target system and
+ provide a convenient, centralized place to store IP addresses. Rackspace
+ monitoring module flow | *rax_mon_entity* -> rax_mon_check ->
+ rax_mon_notification -> rax_mon_notification_plan -> rax_mon_alarm
attributes:
check_mode:
support: none
diff --git a/ansible_collections/community/general/plugins/modules/rax_mon_notification.py b/ansible_collections/community/general/plugins/modules/rax_mon_notification.py
index 91d079359..7539f2a37 100644
--- a/ansible_collections/community/general/plugins/modules/rax_mon_notification.py
+++ b/ansible_collections/community/general/plugins/modules/rax_mon_notification.py
@@ -26,7 +26,7 @@ options:
state:
type: str
description:
- - Ensure that the notification with this C(label) exists or does not exist.
+ - Ensure that the notification with this O(label) exists or does not exist.
choices: ['present', 'absent']
default: present
label:
diff --git a/ansible_collections/community/general/plugins/modules/rax_mon_notification_plan.py b/ansible_collections/community/general/plugins/modules/rax_mon_notification_plan.py
index ac8b189aa..31647304b 100644
--- a/ansible_collections/community/general/plugins/modules/rax_mon_notification_plan.py
+++ b/ansible_collections/community/general/plugins/modules/rax_mon_notification_plan.py
@@ -14,12 +14,10 @@ module: rax_mon_notification_plan
short_description: Create or delete a Rackspace Cloud Monitoring notification
plan.
description:
- - Create or delete a Rackspace Cloud Monitoring notification plan by
- associating existing rax_mon_notifications with severity levels. Rackspace
- monitoring module flow | rax_mon_entity -> rax_mon_check ->
- rax_mon_notification -> *rax_mon_notification_plan* -> rax_mon_alarm.
- - This module relies on the C(pyrax) package which is deprecated in favour of using Openstack API.
- - Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0.
+- Create or delete a Rackspace Cloud Monitoring notification plan by
+ associating existing rax_mon_notifications with severity levels. Rackspace
+ monitoring module flow | rax_mon_entity -> rax_mon_check ->
+ rax_mon_notification -> *rax_mon_notification_plan* -> rax_mon_alarm
attributes:
check_mode:
support: none
@@ -29,7 +27,7 @@ options:
state:
type: str
description:
- - Ensure that the notification plan with this C(label) exists or does not
+ - Ensure that the notification plan with this O(label) exists or does not
exist.
choices: ['present', 'absent']
default: present
diff --git a/ansible_collections/community/general/plugins/modules/rax_scaling_group.py b/ansible_collections/community/general/plugins/modules/rax_scaling_group.py
index 677a75b33..f4bb79025 100644
--- a/ansible_collections/community/general/plugins/modules/rax_scaling_group.py
+++ b/ansible_collections/community/general/plugins/modules/rax_scaling_group.py
@@ -36,7 +36,7 @@ options:
type: str
description:
- Disk partitioning strategy
- - If not specified, it will fallback to C(auto).
+ - If not specified, it will fallback to V(auto).
choices:
- auto
- manual
@@ -53,7 +53,7 @@ options:
image:
type: str
description:
- - image to use for the instance. Can be an C(id), C(human_id) or C(name)
+ - image to use for the instance. Can be an C(id), C(human_id) or C(name).
required: true
key_name:
type: str
@@ -113,7 +113,7 @@ options:
type: str
description:
- Data to be uploaded to the servers config drive. This option implies
- I(config_drive). Can be a file path or a string
+ O(config_drive). Can be a file path or a string
wait:
description:
- wait for the scaling group to finish provisioning the minimum amount of
diff --git a/ansible_collections/community/general/plugins/modules/rax_scaling_policy.py b/ansible_collections/community/general/plugins/modules/rax_scaling_policy.py
index 60b48bb2a..2869a6910 100644
--- a/ansible_collections/community/general/plugins/modules/rax_scaling_policy.py
+++ b/ansible_collections/community/general/plugins/modules/rax_scaling_policy.py
@@ -25,18 +25,18 @@ options:
description:
- The UTC time when this policy will be executed. The time must be
formatted according to C(yyyy-MM-dd'T'HH:mm:ss.SSS) such as
- C(2013-05-19T08:07:08Z)
+ V(2013-05-19T08:07:08Z)
change:
type: int
description:
- The change, either as a number of servers or as a percentage, to make
in the scaling group. If this is a percentage, you must set
- I(is_percent) to C(true) also.
+ O(is_percent) to V(true) also.
cron:
type: str
description:
- The time when the policy will be executed, as a cron entry. For
- example, if this is parameter is set to C(1 0 * * *)
+ example, if this is parameter is set to V(1 0 * * *).
cooldown:
type: int
description:
@@ -51,7 +51,7 @@ options:
many servers should be in the scaling group.
is_percent:
description:
- - Whether the value in I(change) is a percent value
+ - Whether the value in O(change) is a percent value
default: false
type: bool
name:
diff --git a/ansible_collections/community/general/plugins/modules/read_csv.py b/ansible_collections/community/general/plugins/modules/read_csv.py
index f2a359fa7..3c5901318 100644
--- a/ansible_collections/community/general/plugins/modules/read_csv.py
+++ b/ansible_collections/community/general/plugins/modules/read_csv.py
@@ -33,13 +33,13 @@ options:
key:
description:
- The column name used as a key for the resulting dictionary.
- - If C(key) is unset, the module returns a list of dictionaries,
+ - If O(key) is unset, the module returns a list of dictionaries,
where each dictionary is a row in the CSV file.
type: str
dialect:
description:
- The CSV dialect to use when parsing the CSV file.
- - Possible values include C(excel), C(excel-tab) or C(unix).
+ - Possible values include V(excel), V(excel-tab) or V(unix).
type: str
default: excel
fieldnames:
@@ -50,29 +50,31 @@ options:
elements: str
unique:
description:
- - Whether the C(key) used is expected to be unique.
+ - Whether the O(key) used is expected to be unique.
type: bool
default: true
delimiter:
description:
- A one-character string used to separate fields.
- - When using this parameter, you change the default value used by I(dialect).
+ - When using this parameter, you change the default value used by O(dialect).
- The default value depends on the dialect used.
type: str
skipinitialspace:
description:
- Whether to ignore any whitespaces immediately following the delimiter.
- - When using this parameter, you change the default value used by I(dialect).
+ - When using this parameter, you change the default value used by O(dialect).
- The default value depends on the dialect used.
type: bool
strict:
description:
- Whether to raise an exception on bad CSV input.
- - When using this parameter, you change the default value used by I(dialect).
+ - When using this parameter, you change the default value used by O(dialect).
- The default value depends on the dialect used.
type: bool
-notes:
-- Ansible also ships with the C(csvfile) lookup plugin, which can be used to do selective lookups in CSV files from Jinja.
+seealso:
+ - plugin: ansible.builtin.csvfile
+ plugin_type: lookup
+ description: Can be used to do selective lookups in CSV files from Jinja.
'''
EXAMPLES = r'''
diff --git a/ansible_collections/community/general/plugins/modules/redfish_command.py b/ansible_collections/community/general/plugins/modules/redfish_command.py
index 400677eab..e66380493 100644
--- a/ansible_collections/community/general/plugins/modules/redfish_command.py
+++ b/ansible_collections/community/general/plugins/modules/redfish_command.py
@@ -85,6 +85,22 @@ options:
description:
- Role of account to add/modify.
type: str
+ account_types:
+ required: false
+ aliases: [ account_accounttypes ]
+ description:
+ - Array of account types to apply to a user account.
+ type: list
+ elements: str
+ version_added: '7.2.0'
+ oem_account_types:
+ required: false
+ aliases: [ account_oemaccounttypes ]
+ description:
+ - Array of OEM account types to apply to a user account.
+ type: list
+ elements: str
+ version_added: '7.2.0'
bootdevice:
required: false
description:
@@ -93,7 +109,8 @@ options:
timeout:
description:
- Timeout in seconds for HTTP requests to OOB controller.
- default: 10
+ - The default value for this param is C(10) but that is being deprecated
+ and it will be replaced with C(60) in community.general 9.0.0.
type: int
boot_override_mode:
description:
@@ -137,6 +154,12 @@ options:
- URI of the image for the update.
type: str
version_added: '0.2.0'
+ update_image_file:
+ required: false
+ description:
+ - Filename, with optional path, of the image for the update.
+ type: path
+ version_added: '7.1.0'
update_protocol:
required: false
description:
@@ -180,6 +203,12 @@ options:
- InMaintenanceWindowOnReset
- OnStartUpdateRequest
version_added: '6.1.0'
+ update_oem_params:
+ required: false
+ description:
+ - Properties for HTTP Multipart Push Updates.
+ type: dict
+ version_added: '7.5.0'
update_handle:
required: false
description:
@@ -374,6 +403,20 @@ EXAMPLES = '''
new_password: "{{ new_password }}"
roleid: "{{ roleid }}"
+ - name: Add user with specified account types
+ community.general.redfish_command:
+ category: Accounts
+ command: AddUser
+ baseuri: "{{ baseuri }}"
+ username: "{{ username }}"
+ password: "{{ password }}"
+ new_username: "{{ new_username }}"
+ new_password: "{{ new_password }}"
+ roleid: "{{ roleid }}"
+ account_types:
+ - Redfish
+ - WebUI
+
- name: Add user using new option aliases
community.general.redfish_command:
category: Accounts
@@ -541,6 +584,32 @@ EXAMPLES = '''
username: operator
password: supersecretpwd
+ - name: Multipart HTTP push update; timeout is 600 seconds to allow for a
+ large image transfer
+ community.general.redfish_command:
+ category: Update
+ command: MultipartHTTPPushUpdate
+ baseuri: "{{ baseuri }}"
+ username: "{{ username }}"
+ password: "{{ password }}"
+ timeout: 600
+ update_image_file: ~/images/myupdate.img
+
+ - name: Multipart HTTP push with additional options; timeout is 600 seconds
+ to allow for a large image transfer
+ community.general.redfish_command:
+ category: Update
+ command: MultipartHTTPPushUpdate
+ baseuri: "{{ baseuri }}"
+ username: "{{ username }}"
+ password: "{{ password }}"
+ timeout: 600
+ update_image_file: ~/images/myupdate.img
+ update_targets:
+ - /redfish/v1/UpdateService/FirmwareInventory/BMC
+ update_oem_params:
+ PreserveConfiguration: false
+
- name: Perform requested operations to continue the update
community.general.redfish_command:
category: Update
@@ -687,7 +756,7 @@ from ansible.module_utils.common.text.converters import to_native
# More will be added as module features are expanded
CATEGORY_COMMANDS_ALL = {
"Systems": ["PowerOn", "PowerForceOff", "PowerForceRestart", "PowerGracefulRestart",
- "PowerGracefulShutdown", "PowerReboot", "SetOneTimeBoot", "EnableContinuousBootOverride", "DisableBootOverride",
+ "PowerGracefulShutdown", "PowerReboot", "PowerCycle", "SetOneTimeBoot", "EnableContinuousBootOverride", "DisableBootOverride",
"IndicatorLedOn", "IndicatorLedOff", "IndicatorLedBlink", "VirtualMediaInsert", "VirtualMediaEject", "VerifyBiosAttributes"],
"Chassis": ["IndicatorLedOn", "IndicatorLedOff", "IndicatorLedBlink"],
"Accounts": ["AddUser", "EnableUser", "DeleteUser", "DisableUser",
@@ -697,7 +766,7 @@ CATEGORY_COMMANDS_ALL = {
"Manager": ["GracefulRestart", "ClearLogs", "VirtualMediaInsert",
"VirtualMediaEject", "PowerOn", "PowerForceOff", "PowerForceRestart",
"PowerGracefulRestart", "PowerGracefulShutdown", "PowerReboot"],
- "Update": ["SimpleUpdate", "PerformRequestedOperations"],
+ "Update": ["SimpleUpdate", "MultipartHTTPPushUpdate", "PerformRequestedOperations"],
}
@@ -717,17 +786,21 @@ def main():
new_username=dict(aliases=["account_username"]),
new_password=dict(aliases=["account_password"], no_log=True),
roleid=dict(aliases=["account_roleid"]),
+ account_types=dict(type='list', elements='str', aliases=["account_accounttypes"]),
+ oem_account_types=dict(type='list', elements='str', aliases=["account_oemaccounttypes"]),
update_username=dict(type='str', aliases=["account_updatename"]),
account_properties=dict(type='dict', default={}),
bootdevice=dict(),
- timeout=dict(type='int', default=10),
+ timeout=dict(type='int'),
uefi_target=dict(),
boot_next=dict(),
boot_override_mode=dict(choices=['Legacy', 'UEFI']),
resource_id=dict(),
update_image_uri=dict(),
+ update_image_file=dict(type='path'),
update_protocol=dict(),
update_targets=dict(type='list', elements='str', default=[]),
+ update_oem_params=dict(type='dict'),
update_creds=dict(
type='dict',
options=dict(
@@ -766,6 +839,16 @@ def main():
supports_check_mode=False
)
+ if module.params['timeout'] is None:
+ timeout = 10
+ module.deprecate(
+ 'The default value {0} for parameter param1 is being deprecated and it will be replaced by {1}'.format(
+ 10, 60
+ ),
+ version='9.0.0',
+ collection_name='community.general'
+ )
+
category = module.params['category']
command_list = module.params['command']
@@ -775,12 +858,16 @@ def main():
'token': module.params['auth_token']}
# user to add/modify/delete
- user = {'account_id': module.params['id'],
- 'account_username': module.params['new_username'],
- 'account_password': module.params['new_password'],
- 'account_roleid': module.params['roleid'],
- 'account_updatename': module.params['update_username'],
- 'account_properties': module.params['account_properties']}
+ user = {
+ 'account_id': module.params['id'],
+ 'account_username': module.params['new_username'],
+ 'account_password': module.params['new_password'],
+ 'account_roleid': module.params['roleid'],
+ 'account_accounttypes': module.params['account_types'],
+ 'account_oemaccounttypes': module.params['oem_account_types'],
+ 'account_updatename': module.params['update_username'],
+ 'account_properties': module.params['account_properties'],
+ }
# timeout
timeout = module.params['timeout']
@@ -791,10 +878,12 @@ def main():
# update options
update_opts = {
'update_image_uri': module.params['update_image_uri'],
+ 'update_image_file': module.params['update_image_file'],
'update_protocol': module.params['update_protocol'],
'update_targets': module.params['update_targets'],
'update_creds': module.params['update_creds'],
'update_apply_time': module.params['update_apply_time'],
+ 'update_oem_params': module.params['update_oem_params'],
'update_handle': module.params['update_handle'],
}
@@ -940,6 +1029,10 @@ def main():
result = rf_utils.simple_update(update_opts)
if 'update_status' in result:
return_values['update_status'] = result['update_status']
+ elif command == "MultipartHTTPPushUpdate":
+ result = rf_utils.multipath_http_push_update(update_opts)
+ if 'update_status' in result:
+ return_values['update_status'] = result['update_status']
elif command == "PerformRequestedOperations":
result = rf_utils.perform_requested_update_operations(update_opts['update_handle'])
diff --git a/ansible_collections/community/general/plugins/modules/redfish_config.py b/ansible_collections/community/general/plugins/modules/redfish_config.py
index 9f31870e3..1fea9e7cd 100644
--- a/ansible_collections/community/general/plugins/modules/redfish_config.py
+++ b/ansible_collections/community/general/plugins/modules/redfish_config.py
@@ -64,7 +64,8 @@ options:
timeout:
description:
- Timeout in seconds for HTTP requests to OOB controller.
- default: 10
+ - The default value for this param is C(10) but that is being deprecated
+ and it will be replaced with C(60) in community.general 9.0.0.
type: int
boot_order:
required: false
@@ -87,6 +88,12 @@ options:
- ID of the System, Manager or Chassis to modify.
type: str
version_added: '0.2.0'
+ service_id:
+ required: false
+ description:
+ - ID of the manager to update.
+ type: str
+ version_added: '8.4.0'
nic_addr:
required: false
description:
@@ -130,7 +137,35 @@ options:
type: dict
default: {}
version_added: '5.7.0'
-
+ storage_subsystem_id:
+ required: false
+ description:
+ - Id of the Storage Subsystem on which the volume is to be created.
+ type: str
+ default: ''
+ version_added: '7.3.0'
+ volume_ids:
+ required: false
+ description:
+ - List of IDs of volumes to be deleted.
+ type: list
+ default: []
+ elements: str
+ version_added: '7.3.0'
+ secure_boot_enable:
+ required: false
+ description:
+ - Setting parameter to enable or disable SecureBoot.
+ type: bool
+ default: True
+ version_added: '7.5.0'
+ volume_details:
+ required: false
+ description:
+ - Setting dict of volume to be created.
+ type: dict
+ default: {}
+ version_added: '7.5.0'
author:
- "Jose Delarosa (@jose-delarosa)"
- "T S Kushal (@TSKushal)"
@@ -272,6 +307,48 @@ EXAMPLES = '''
baseuri: "{{ baseuri }}"
username: "{{ username }}"
password: "{{ password }}"
+
+ - name: Set SecureBoot
+ community.general.redfish_config:
+ category: Systems
+ command: SetSecureBoot
+ baseuri: "{{ baseuri }}"
+ username: "{{ username }}"
+ password: "{{ password }}"
+ secure_boot_enable: True
+
+ - name: Delete All Volumes
+ community.general.redfish_config:
+ category: Systems
+ command: DeleteVolumes
+ baseuri: "{{ baseuri }}"
+ username: "{{ username }}"
+ password: "{{ password }}"
+ storage_subsystem_id: "DExxxxxx"
+ volume_ids: ["volume1", "volume2"]
+
+ - name: Create Volume
+ community.general.redfish_config:
+ category: Systems
+ command: CreateVolume
+ baseuri: "{{ baseuri }}"
+ username: "{{ username }}"
+ password: "{{ password }}"
+ storage_subsystem_id: "DExxxxxx"
+ volume_details:
+ Name: "MR Volume"
+ RAIDType: "RAID0"
+ Drives:
+ - "/redfish/v1/Systems/1/Storage/DE00B000/Drives/1"
+
+ - name: Set service identification to {{ service_id }}
+ community.general.redfish_config:
+ category: Manager
+ command: SetServiceIdentification
+ service_id: "{{ service_id }}"
+ baseuri: "{{ baseuri }}"
+ username: "{{ username }}"
+ password: "{{ password }}"
'''
RETURN = '''
@@ -290,8 +367,8 @@ from ansible.module_utils.common.text.converters import to_native
# More will be added as module features are expanded
CATEGORY_COMMANDS_ALL = {
"Systems": ["SetBiosDefaultSettings", "SetBiosAttributes", "SetBootOrder",
- "SetDefaultBootOrder", "EnableSecureBoot"],
- "Manager": ["SetNetworkProtocols", "SetManagerNic", "SetHostInterface"],
+ "SetDefaultBootOrder", "EnableSecureBoot", "SetSecureBoot", "DeleteVolumes", "CreateVolume"],
+ "Manager": ["SetNetworkProtocols", "SetManagerNic", "SetHostInterface", "SetServiceIdentification"],
"Sessions": ["SetSessionService"],
}
@@ -307,13 +384,14 @@ def main():
password=dict(no_log=True),
auth_token=dict(no_log=True),
bios_attributes=dict(type='dict', default={}),
- timeout=dict(type='int', default=10),
+ timeout=dict(type='int'),
boot_order=dict(type='list', elements='str', default=[]),
network_protocols=dict(
type='dict',
default={}
),
resource_id=dict(),
+ service_id=dict(),
nic_addr=dict(default='null'),
nic_config=dict(
type='dict',
@@ -323,6 +401,10 @@ def main():
hostinterface_config=dict(type='dict', default={}),
hostinterface_id=dict(),
sessions_config=dict(type='dict', default={}),
+ storage_subsystem_id=dict(type='str', default=''),
+ volume_ids=dict(type='list', default=[], elements='str'),
+ secure_boot_enable=dict(type='bool', default=True),
+ volume_details=dict(type='dict', default={})
),
required_together=[
('username', 'password'),
@@ -336,6 +418,16 @@ def main():
supports_check_mode=False
)
+ if module.params['timeout'] is None:
+ timeout = 10
+ module.deprecate(
+ 'The default value {0} for parameter param1 is being deprecated and it will be replaced by {1}'.format(
+ 10, 60
+ ),
+ version='9.0.0',
+ collection_name='community.general'
+ )
+
category = module.params['category']
command_list = module.params['command']
@@ -369,9 +461,23 @@ def main():
# HostInterface instance ID
hostinterface_id = module.params['hostinterface_id']
+ # Service Identification
+ service_id = module.params['service_id']
+
# Sessions config options
sessions_config = module.params['sessions_config']
+ # Volume deletion options
+ storage_subsystem_id = module.params['storage_subsystem_id']
+ volume_ids = module.params['volume_ids']
+
+ # Set SecureBoot options
+ secure_boot_enable = module.params['secure_boot_enable']
+
+ # Volume creation options
+ volume_details = module.params['volume_details']
+ storage_subsystem_id = module.params['storage_subsystem_id']
+
# Build root URI
root_uri = "https://" + module.params['baseuri']
rf_utils = RedfishUtils(creds, root_uri, timeout, module,
@@ -405,6 +511,12 @@ def main():
result = rf_utils.set_default_boot_order()
elif command == "EnableSecureBoot":
result = rf_utils.enable_secure_boot()
+ elif command == "SetSecureBoot":
+ result = rf_utils.set_secure_boot(secure_boot_enable)
+ elif command == "DeleteVolumes":
+ result = rf_utils.delete_volumes(storage_subsystem_id, volume_ids)
+ elif command == "CreateVolume":
+ result = rf_utils.create_volume(volume_details, storage_subsystem_id)
elif category == "Manager":
# execute only if we find a Manager service resource
@@ -419,6 +531,8 @@ def main():
result = rf_utils.set_manager_nic(nic_addr, nic_config)
elif command == "SetHostInterface":
result = rf_utils.set_hostinterface_attributes(hostinterface_config, hostinterface_id)
+ elif command == "SetServiceIdentification":
+ result = rf_utils.set_service_identification(service_id)
elif category == "Sessions":
# execute only if we find a Sessions resource
diff --git a/ansible_collections/community/general/plugins/modules/redfish_info.py b/ansible_collections/community/general/plugins/modules/redfish_info.py
index 364df40b5..0b39bb6fa 100644
--- a/ansible_collections/community/general/plugins/modules/redfish_info.py
+++ b/ansible_collections/community/general/plugins/modules/redfish_info.py
@@ -16,8 +16,6 @@ description:
- Builds Redfish URIs locally and sends them to remote OOB controllers to
get information back.
- Information retrieved is placed in a location specified by the user.
- - This module was called C(redfish_facts) before Ansible 2.9, returning C(ansible_facts).
- Note that the M(community.general.redfish_info) module no longer returns C(ansible_facts)!
extends_documentation_fragment:
- community.general.attributes
- community.general.attributes.info_module
@@ -57,10 +55,16 @@ options:
- Security token for authenticating to OOB controller.
type: str
version_added: 2.3.0
+ manager:
+ description:
+ - Name of manager on OOB controller to target.
+ type: str
+ version_added: '8.3.0'
timeout:
description:
- Timeout in seconds for HTTP requests to OOB controller.
- default: 10
+ - The default value for this param is C(10) but that is being deprecated
+ and it will be replaced with C(60) in community.general 9.0.0.
type: int
update_handle:
required: false
@@ -249,6 +253,15 @@ EXAMPLES = '''
username: "{{ username }}"
password: "{{ password }}"
+ - name: Get service identification
+ community.general.redfish_info:
+ category: Manager
+ command: GetServiceIdentification
+ manager: "{{ manager }}"
+ baseuri: "{{ baseuri }}"
+ username: "{{ username }}"
+ password: "{{ password }}"
+
- name: Get software inventory
community.general.redfish_info:
category: Update
@@ -337,6 +350,14 @@ EXAMPLES = '''
baseuri: "{{ baseuri }}"
username: "{{ username }}"
password: "{{ password }}"
+
+ - name: Get BIOS registry
+ community.general.redfish_info:
+ category: Systems
+ command: GetBiosRegistries
+ baseuri: "{{ baseuri }}"
+ username: "{{ username }}"
+ password: "{{ password }}"
'''
RETURN = '''
@@ -354,7 +375,7 @@ CATEGORY_COMMANDS_ALL = {
"Systems": ["GetSystemInventory", "GetPsuInventory", "GetCpuInventory",
"GetMemoryInventory", "GetNicInventory", "GetHealthReport",
"GetStorageControllerInventory", "GetDiskInventory", "GetVolumeInventory",
- "GetBiosAttributes", "GetBootOrder", "GetBootOverride", "GetVirtualMedia"],
+ "GetBiosAttributes", "GetBootOrder", "GetBootOverride", "GetVirtualMedia", "GetBiosRegistries"],
"Chassis": ["GetFanInventory", "GetPsuInventory", "GetChassisPower",
"GetChassisThermals", "GetChassisInventory", "GetHealthReport", "GetHPEThermalConfig", "GetHPEFanPercentMin"],
"Accounts": ["ListUsers"],
@@ -362,7 +383,7 @@ CATEGORY_COMMANDS_ALL = {
"Update": ["GetFirmwareInventory", "GetFirmwareUpdateCapabilities", "GetSoftwareInventory",
"GetUpdateStatus"],
"Manager": ["GetManagerNicInventory", "GetVirtualMedia", "GetLogs", "GetNetworkProtocols",
- "GetHealthReport", "GetHostInterfaces", "GetManagerInventory"],
+ "GetHealthReport", "GetHostInterfaces", "GetManagerInventory", "GetServiceIdentification"],
}
CATEGORY_COMMANDS_DEFAULT = {
@@ -386,8 +407,9 @@ def main():
username=dict(),
password=dict(no_log=True),
auth_token=dict(no_log=True),
- timeout=dict(type='int', default=10),
+ timeout=dict(type='int'),
update_handle=dict(),
+ manager=dict(),
),
required_together=[
('username', 'password'),
@@ -401,6 +423,16 @@ def main():
supports_check_mode=True,
)
+ if module.params['timeout'] is None:
+ timeout = 10
+ module.deprecate(
+ 'The default value {0} for parameter param1 is being deprecated and it will be replaced by {1}'.format(
+ 10, 60
+ ),
+ version='9.0.0',
+ collection_name='community.general'
+ )
+
# admin credentials used for authentication
creds = {'user': module.params['username'],
'pswd': module.params['password'],
@@ -412,6 +444,9 @@ def main():
# update handle
update_handle = module.params['update_handle']
+ # manager
+ manager = module.params['manager']
+
# Build root URI
root_uri = "https://" + module.params['baseuri']
rf_utils = RedfishUtils(creds, root_uri, timeout, module)
@@ -478,6 +513,8 @@ def main():
result["health_report"] = rf_utils.get_multi_system_health_report()
elif command == "GetVirtualMedia":
result["virtual_media"] = rf_utils.get_multi_virtualmedia(category)
+ elif command == "GetBiosRegistries":
+ result["bios_registries"] = rf_utils.get_bios_registries()
elif category == "Chassis":
# execute only if we find Chassis resource
@@ -560,6 +597,8 @@ def main():
result["host_interfaces"] = rf_utils.get_hostinterfaces()
elif command == "GetManagerInventory":
result["manager"] = rf_utils.get_multi_manager_inventory()
+ elif command == "GetServiceIdentification":
+ result["service_id"] = rf_utils.get_service_identification(manager)
# Return data back
module.exit_json(redfish_facts=result)
diff --git a/ansible_collections/community/general/plugins/modules/redhat_subscription.py b/ansible_collections/community/general/plugins/modules/redhat_subscription.py
index 79b0d4b4c..d4b47d5d5 100644
--- a/ansible_collections/community/general/plugins/modules/redhat_subscription.py
+++ b/ansible_collections/community/general/plugins/modules/redhat_subscription.py
@@ -26,21 +26,21 @@ notes:
C(subscription-manager) itself gets credentials only as arguments of command line
parameters, which is I(not) secure, as they can be easily stolen by checking the
process listing on the system. Due to limitations of the D-Bus interface of C(rhsm),
- the module will I(not) use D-Bus for registation when trying either to register
- using I(token), or when specifying I(environment), or when the system is old
- (typically RHEL 6 and older).
+ the module will I(not) use D-Bus for registration when trying either to register
+ using O(token), or when specifying O(environment), or when the system is old
+ (typically RHEL 7 older than 7.4, RHEL 6, and older).
- In order to register a system, subscription-manager requires either a username and password, or an activationkey and an Organization ID.
- - Since 2.5 values for I(server_hostname), I(server_insecure), I(rhsm_baseurl),
- I(server_proxy_hostname), I(server_proxy_port), I(server_proxy_user) and
- I(server_proxy_password) are no longer taken from the C(/etc/rhsm/rhsm.conf)
- config file and default to None.
+ - Since 2.5 values for O(server_hostname), O(server_insecure), O(rhsm_baseurl),
+ O(server_proxy_hostname), O(server_proxy_port), O(server_proxy_user) and
+ O(server_proxy_password) are no longer taken from the C(/etc/rhsm/rhsm.conf)
+ config file and default to V(null).
- It is possible to interact with C(subscription-manager) only as root,
so root permissions are required to successfully run this module.
- - Since community.general 6.5.0, credentials (that is, I(username) and I(password),
- I(activationkey), or I(token)) are needed only in case the the system is not registered,
- or I(force_register) is specified; this makes it possible to use the module to tweak an
- already registered system, for example attaching pools to it (using I(pool), or I(pool_ids)),
- and modifying the C(syspurpose) attributes (using I(syspurpose)).
+ - Since community.general 6.5.0, credentials (that is, O(username) and O(password),
+ O(activationkey), or O(token)) are needed only in case the the system is not registered,
+ or O(force_register) is specified; this makes it possible to use the module to tweak an
+ already registered system, for example attaching pools to it (using O(pool), or O(pool_ids)),
+ and modifying the C(syspurpose) attributes (using O(syspurpose)).
requirements:
- subscription-manager
- Optionally the C(dbus) Python library; this is usually included in the OS
@@ -55,7 +55,7 @@ attributes:
options:
state:
description:
- - whether to register and subscribe (C(present)), or unregister (C(absent)) a system
+ - whether to register and subscribe (V(present)), or unregister (V(absent)) a system
choices: [ "present", "absent" ]
default: "present"
type: str
@@ -74,11 +74,11 @@ options:
version_added: 6.3.0
server_hostname:
description:
- - Specify an alternative Red Hat Subscription Management or Red Hat Satellite or Katello server
+ - Specify an alternative Red Hat Subscription Management or Red Hat Satellite or Katello server.
type: str
server_insecure:
description:
- - Enable or disable https server certificate verification when connecting to C(server_hostname)
+ - Enable or disable https server certificate verification when connecting to O(server_hostname).
type: str
server_prefix:
description:
@@ -104,7 +104,7 @@ options:
type: str
server_proxy_scheme:
description:
- - Specify an HTTP proxy scheme, for example C(http) or C(https).
+ - Specify an HTTP proxy scheme, for example V(http) or V(https).
type: str
version_added: 6.2.0
server_proxy_port:
@@ -122,7 +122,9 @@ options:
auto_attach:
description:
- Upon successful registration, auto-consume available subscriptions
- - Added in favor of deprecated autosubscribe in 2.5.
+ - |
+ Please note that the alias O(autosubscribe) will be removed in
+ community.general 9.0.0.
type: bool
aliases: [autosubscribe]
activationkey:
@@ -140,18 +142,26 @@ options:
pool:
description:
- |
- Specify a subscription pool name to consume. Regular expressions accepted. Use I(pool_ids) instead if
- possible, as it is much faster. Mutually exclusive with I(pool_ids).
+ Specify a subscription pool name to consume. Regular expressions accepted.
+ Mutually exclusive with O(pool_ids).
+ - |
+ Please use O(pool_ids) instead: specifying pool IDs is much faster,
+ and it avoids to match new pools that become available for the
+ system and are not explicitly wanted. Also, this option does not
+ support quantities.
+ - |
+ This option is deprecated for the reasons mentioned above,
+ and it will be removed in community.general 10.0.0.
default: '^$'
type: str
pool_ids:
description:
- |
- Specify subscription pool IDs to consume. Prefer over I(pool) when possible as it is much faster.
- A pool ID may be specified as a C(string) - just the pool ID (ex. C(0123456789abcdef0123456789abcdef)),
- or as a C(dict) with the pool ID as the key, and a quantity as the value (ex.
- C(0123456789abcdef0123456789abcdef: 2). If the quantity is provided, it is used to consume multiple
- entitlements from a pool (the pool must support this). Mutually exclusive with I(pool).
+ Specify subscription pool IDs to consume. Prefer over O(pool) when possible as it is much faster.
+ A pool ID may be specified as a C(string) - just the pool ID (for example V(0123456789abcdef0123456789abcdef)),
+ or as a C(dict) with the pool ID as the key, and a quantity as the value (for example
+ V(0123456789abcdef0123456789abcdef: 2). If the quantity is provided, it is used to consume multiple
+ entitlements from a pool (the pool must support this). Mutually exclusive with O(pool).
default: []
type: list
elements: raw
@@ -205,8 +215,8 @@ options:
elements: str
sync:
description:
- - When this option is true, then syspurpose attributes are synchronized with
- RHSM server immediately. When this option is false, then syspurpose attributes
+ - When this option is V(true), then syspurpose attributes are synchronized with
+ RHSM server immediately. When this option is V(false), then syspurpose attributes
will be synchronized with RHSM server by rhsmcertd daemon.
type: bool
default: false
@@ -323,32 +333,12 @@ from ansible.module_utils import distro
SUBMAN_CMD = None
-class RegistrationBase(object):
+class Rhsm(object):
REDHAT_REPO = "/etc/yum.repos.d/redhat.repo"
- def __init__(self, module, username=None, password=None, token=None):
+ def __init__(self, module):
self.module = module
- self.username = username
- self.password = password
- self.token = token
-
- def configure(self):
- raise NotImplementedError("Must be implemented by a sub-class")
-
- def enable(self):
- # Remove any existing redhat.repo
- if isfile(self.REDHAT_REPO):
- unlink(self.REDHAT_REPO)
-
- def register(self):
- raise NotImplementedError("Must be implemented by a sub-class")
-
- def unregister(self):
- raise NotImplementedError("Must be implemented by a sub-class")
-
- def unsubscribe(self):
- raise NotImplementedError("Must be implemented by a sub-class")
def update_plugin_conf(self, plugin, enabled=True):
plugin_conf = '/etc/yum/pluginconf.d/%s.conf' % plugin
@@ -369,22 +359,15 @@ class RegistrationBase(object):
fd.close()
self.module.atomic_move(tmpfile, plugin_conf)
- def subscribe(self, **kwargs):
- raise NotImplementedError("Must be implemented by a sub-class")
-
-
-class Rhsm(RegistrationBase):
- def __init__(self, module, username=None, password=None, token=None):
- RegistrationBase.__init__(self, module, username, password, token)
- self.module = module
-
def enable(self):
'''
Enable the system to receive updates from subscription-manager.
This involves updating affected yum plugins and removing any
conflicting yum repositories.
'''
- RegistrationBase.enable(self)
+ # Remove any existing redhat.repo
+ if isfile(self.REDHAT_REPO):
+ unlink(self.REDHAT_REPO)
self.update_plugin_conf('rhnplugin', False)
self.update_plugin_conf('subscription-manager', True)
@@ -431,6 +414,30 @@ class Rhsm(RegistrationBase):
else:
return False
+ def _has_dbus_interface(self):
+ """
+ Checks whether subscription-manager has a D-Bus interface.
+
+ :returns: bool -- whether subscription-manager has a D-Bus interface.
+ """
+
+ def str2int(s, default=0):
+ try:
+ return int(s)
+ except ValueError:
+ return default
+
+ distro_id = distro.id()
+ distro_version = tuple(str2int(p) for p in distro.version_parts())
+
+ # subscription-manager in any supported Fedora version has the interface.
+ if distro_id == 'fedora':
+ return True
+ # Any other distro: assume it is EL;
+ # the D-Bus interface was added to subscription-manager in RHEL 7.4.
+ return (distro_version[0] == 7 and distro_version[1] >= 4) or \
+ distro_version[0] >= 8
+
def _can_connect_to_dbus(self):
"""
Checks whether it is possible to connect to the system D-Bus bus.
@@ -474,7 +481,8 @@ class Rhsm(RegistrationBase):
# of rhsm, so always use the CLI in that case;
# also, since the specified environments are names, and the D-Bus APIs
# require IDs for the environments, use the CLI also in that case
- if not token and not environment and self._can_connect_to_dbus():
+ if (not token and not environment and self._has_dbus_interface() and
+ self._can_connect_to_dbus()):
self._register_using_dbus(was_registered, username, password, auto_attach,
activationkey, org_id, consumer_type,
consumer_name, consumer_id,
@@ -588,7 +596,34 @@ class Rhsm(RegistrationBase):
register_opts = {}
if consumer_type:
- register_opts['consumer_type'] = consumer_type
+ # The option for the consumer type used to be 'type' in versions
+ # of RHEL before 9 & in RHEL 9 before 9.2, and then it changed to
+ # 'consumer_type'; since the Register*() D-Bus functions reject
+ # unknown options, we have to pass the right option depending on
+ # the version -- funky.
+ def supports_option_consumer_type():
+ # subscription-manager in any supported Fedora version
+ # has the new option.
+ if distro_id == 'fedora':
+ return True
+ # Check for RHEL 9 >= 9.2, or RHEL >= 10.
+ if distro_id == 'rhel' and \
+ ((distro_version[0] == 9 and distro_version[1] >= 2) or
+ distro_version[0] >= 10):
+ return True
+ # CentOS: since the change was only done in EL 9, then there is
+ # only CentOS Stream for 9, and thus we can assume it has the
+ # latest version of subscription-manager.
+ if distro_id == 'centos' and distro_version[0] >= 9:
+ return True
+ # Unknown or old distro: assume it does not support
+ # the new option.
+ return False
+
+ consumer_type_key = 'type'
+ if supports_option_consumer_type():
+ consumer_type_key = 'consumer_type'
+ register_opts[consumer_type_key] = consumer_type
if consumer_name:
register_opts['name'] = consumer_name
if consumer_id:
@@ -1056,9 +1091,6 @@ class SysPurpose(object):
def main():
- # Load RHSM configuration from file
- rhsm = Rhsm(None)
-
# Note: the default values for parameters are:
# 'type': 'str', 'default': None, 'required': False
# So there is no need to repeat these values for each parameter.
@@ -1074,11 +1106,25 @@ def main():
'server_port': {},
'rhsm_baseurl': {},
'rhsm_repo_ca_cert': {},
- 'auto_attach': {'aliases': ['autosubscribe'], 'type': 'bool'},
+ 'auto_attach': {
+ 'type': 'bool',
+ 'aliases': ['autosubscribe'],
+ 'deprecated_aliases': [
+ {
+ 'name': 'autosubscribe',
+ 'version': '9.0.0',
+ 'collection_name': 'community.general',
+ },
+ ],
+ },
'activationkey': {'no_log': True},
'org_id': {},
'environment': {},
- 'pool': {'default': '^$'},
+ 'pool': {
+ 'default': '^$',
+ 'removed_in_version': '10.0.0',
+ 'removed_from_collection': 'community.general',
+ },
'pool_ids': {'default': [], 'type': 'list', 'elements': 'raw'},
'consumer_type': {},
'consumer_name': {},
@@ -1119,7 +1165,9 @@ def main():
msg="Interacting with subscription-manager requires root permissions ('become: true')"
)
- rhsm.module = module
+ # Load RHSM configuration from file
+ rhsm = Rhsm(module)
+
state = module.params['state']
username = module.params['username']
password = module.params['password']
diff --git a/ansible_collections/community/general/plugins/modules/redis.py b/ansible_collections/community/general/plugins/modules/redis.py
index 1778a067e..207927cb7 100644
--- a/ansible_collections/community/general/plugins/modules/redis.py
+++ b/ansible_collections/community/general/plugins/modules/redis.py
@@ -26,9 +26,9 @@ options:
command:
description:
- The selected redis command
- - C(config) ensures a configuration setting on an instance.
- - C(flush) flushes all the instance or a specified db.
- - C(replica) sets a redis instance in replica or master mode. (C(slave) is an alias for C(replica).)
+ - V(config) ensures a configuration setting on an instance.
+ - V(flush) flushes all the instance or a specified db.
+ - V(replica) sets a redis instance in replica or master mode. (V(slave) is an alias for V(replica).)
choices: [ config, flush, replica, slave ]
type: str
tls:
@@ -51,7 +51,7 @@ options:
replica_mode:
description:
- The mode of the redis instance [replica command]
- - C(slave) is an alias for C(replica).
+ - V(slave) is an alias for V(replica).
default: replica
choices: [ master, replica, slave ]
type: str
@@ -75,7 +75,7 @@ options:
value:
description:
- A redis config value. When memory size is needed, it is possible
- to specify it in the usal form of 1KB, 2M, 400MB where the base is 1024.
+ to specify it in the usual form of 1KB, 2M, 400MB where the base is 1024.
Units are case insensitive i.e. 1m = 1mb = 1M = 1MB.
type: str
diff --git a/ansible_collections/community/general/plugins/modules/redis_data.py b/ansible_collections/community/general/plugins/modules/redis_data.py
index c0c8dcc9a..fe5cc07ef 100644
--- a/ansible_collections/community/general/plugins/modules/redis_data.py
+++ b/ansible_collections/community/general/plugins/modules/redis_data.py
@@ -121,12 +121,12 @@ EXAMPLES = '''
RETURN = '''
old_value:
description: Value of key before setting.
- returned: on_success if state is C(present) and key exists in database.
+ returned: on_success if O(state=present) and key exists in database.
type: str
sample: 'old_value_of_key'
value:
description: Value key was set to.
- returned: on success if state is C(present).
+ returned: on success if O(state=present).
type: str
sample: 'new_value_of_key'
msg:
diff --git a/ansible_collections/community/general/plugins/modules/redis_data_incr.py b/ansible_collections/community/general/plugins/modules/redis_data_incr.py
index f927fb11f..b359e0cb9 100644
--- a/ansible_collections/community/general/plugins/modules/redis_data_incr.py
+++ b/ansible_collections/community/general/plugins/modules/redis_data_incr.py
@@ -16,15 +16,15 @@ version_added: 4.0.0
description:
- Increment integers or float keys in Redis database and get new value.
- Default increment for all keys is 1. For specific increments use the
- I(increment_int) and I(increment_float) options.
+ O(increment_int) and O(increment_float) options.
author: "Andreas Botzner (@paginabianca)"
attributes:
check_mode:
support: partial
details:
- - For C(check_mode) to work, the specified I(redis_user) needs permission to
+ - For C(check_mode) to work, the specified O(login_user) needs permission to
run the C(GET) command on the key, otherwise the module will fail.
- - When using I(check_mode) the module will try to calculate the value that
+ - When using C(check_mode) the module will try to calculate the value that
Redis would return. If the key is not present, 0.0 is used as value.
diff_mode:
support: none
diff --git a/ansible_collections/community/general/plugins/modules/redis_info.py b/ansible_collections/community/general/plugins/modules/redis_info.py
index b9900a7ca..f352d53d7 100644
--- a/ansible_collections/community/general/plugins/modules/redis_info.py
+++ b/ansible_collections/community/general/plugins/modules/redis_info.py
@@ -17,30 +17,21 @@ version_added: '0.2.0'
description:
- Gathers information and statistics about Redis servers.
extends_documentation_fragment:
+- community.general.redis
- community.general.attributes
- community.general.attributes.info_module
options:
- login_host:
- description:
- - The host running the database.
- type: str
- default: localhost
- login_port:
- description:
- - The port to connect to.
- type: int
- default: 6379
- login_password:
- description:
- - The password used to authenticate with, when authentication is enabled for the Redis server.
- type: str
-notes:
-- Requires the redis-py Python package on the remote host. You can
- install it with pip (C(pip install redis)) or with a package manager.
- U(https://github.com/andymccurdy/redis-py)
+ login_user:
+ version_added: 7.5.0
+ validate_certs:
+ version_added: 7.5.0
+ tls:
+ default: false
+ version_added: 7.5.0
+ ca_certs:
+ version_added: 7.5.0
seealso:
- module: community.general.redis
-requirements: [ redis ]
author: "Pavlo Bashynskyi (@levonet)"
'''
@@ -199,8 +190,10 @@ except ImportError:
REDIS_IMP_ERR = traceback.format_exc()
HAS_REDIS_PACKAGE = False
-from ansible.module_utils.basic import AnsibleModule, missing_required_lib
+from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.common.text.converters import to_native
+from ansible_collections.community.general.plugins.module_utils.redis import (
+ fail_imports, redis_auth_argument_spec, redis_auth_params)
def redis_client(**client_params):
@@ -210,23 +203,16 @@ def redis_client(**client_params):
# Module execution.
def main():
module = AnsibleModule(
- argument_spec=dict(
- login_host=dict(type='str', default='localhost'),
- login_port=dict(type='int', default=6379),
- login_password=dict(type='str', no_log=True),
- ),
+ argument_spec=redis_auth_argument_spec(tls_default=False),
supports_check_mode=True,
)
- if not HAS_REDIS_PACKAGE:
- module.fail_json(msg=missing_required_lib('redis'), exception=REDIS_IMP_ERR)
+ fail_imports(module, module.params['tls'])
- login_host = module.params['login_host']
- login_port = module.params['login_port']
- login_password = module.params['login_password']
+ redis_params = redis_auth_params(module)
# Connect and check
- client = redis_client(host=login_host, port=login_port, password=login_password)
+ client = redis_client(**redis_params)
try:
client.ping()
except Exception as e:
diff --git a/ansible_collections/community/general/plugins/modules/rhevm.py b/ansible_collections/community/general/plugins/modules/rhevm.py
index c129a2df5..7f2300997 100644
--- a/ansible_collections/community/general/plugins/modules/rhevm.py
+++ b/ansible_collections/community/general/plugins/modules/rhevm.py
@@ -141,14 +141,14 @@ options:
default: true
cd_drive:
description:
- - The CD you wish to have mounted on the VM when I(state = 'CD').
+ - The CD you wish to have mounted on the VM when O(state=cd).
type: str
timeout:
description:
- The timeout you wish to define for power actions.
- - When I(state = 'up').
- - When I(state = 'down').
- - When I(state = 'restarted').
+ - When O(state=up).
+ - When O(state=down).
+ - When O(state=restarted).
type: int
'''
diff --git a/ansible_collections/community/general/plugins/modules/rhn_channel.py b/ansible_collections/community/general/plugins/modules/rhn_channel.py
index e544af51e..b69bb0c68 100644
--- a/ansible_collections/community/general/plugins/modules/rhn_channel.py
+++ b/ansible_collections/community/general/plugins/modules/rhn_channel.py
@@ -60,13 +60,23 @@ options:
type: str
validate_certs:
description:
- - If C(False), SSL certificates will not be validated.
- - This should only set to C(False) when used on self controlled sites
+ - If V(false), SSL certificates will not be validated.
+ - This should only set to V(false) when used on self controlled sites
using self-signed certificates, and you are absolutely sure that nobody
can modify traffic between the module and the site.
type: bool
default: true
version_added: '0.2.0'
+deprecated:
+ removed_in: 10.0.0
+ why: |
+ RHN hosted at redhat.com was discontinued years ago, and Spacewalk 5
+ (which uses RHN) is EOL since 2020, May 31st; while this module could
+ work on Uyuni / SUSE Manager (fork of Spacewalk 5), we have not heard
+ about anyone using it in those setups.
+ alternative: |
+ Contact the community.general maintainers to report the usage of this
+ module, and potentially step up to maintain it.
'''
EXAMPLES = '''
diff --git a/ansible_collections/community/general/plugins/modules/rhn_register.py b/ansible_collections/community/general/plugins/modules/rhn_register.py
index 1fe9297d2..cd1b708e4 100644
--- a/ansible_collections/community/general/plugins/modules/rhn_register.py
+++ b/ansible_collections/community/general/plugins/modules/rhn_register.py
@@ -32,7 +32,7 @@ attributes:
options:
state:
description:
- - Whether to register (C(present)), or unregister (C(absent)) a system.
+ - Whether to register (V(present)), or unregister (V(absent)) a system.
type: str
choices: [ absent, present ]
default: present
@@ -47,7 +47,7 @@ options:
server_url:
description:
- Specify an alternative Red Hat Network server URL.
- - The default is the current value of I(serverURL) from C(/etc/sysconfig/rhn/up2date).
+ - The default is the current value of C(serverURL) from C(/etc/sysconfig/rhn/up2date).
type: str
activationkey:
description:
@@ -80,14 +80,24 @@ options:
default: []
enable_eus:
description:
- - If C(false), extended update support will be requested.
+ - If V(false), extended update support will be requested.
type: bool
default: false
nopackages:
description:
- - If C(true), the registered node will not upload its installed packages information to Satellite server.
+ - If V(true), the registered node will not upload its installed packages information to Satellite server.
type: bool
default: false
+deprecated:
+ removed_in: 10.0.0
+ why: |
+ RHN hosted at redhat.com was discontinued years ago, and Spacewalk 5
+ (which uses RHN) is EOL since 2020, May 31st; while this module could
+ work on Uyuni / SUSE Manager (fork of Spacewalk 5), we have not heard
+ about anyone using it in those setups.
+ alternative: |
+ Contact the community.general maintainers to report the usage of this
+ module, and potentially step up to maintain it.
'''
EXAMPLES = r'''
diff --git a/ansible_collections/community/general/plugins/modules/rhsm_release.py b/ansible_collections/community/general/plugins/modules/rhsm_release.py
index 6ac4da6e4..8c74ca819 100644
--- a/ansible_collections/community/general/plugins/modules/rhsm_release.py
+++ b/ansible_collections/community/general/plugins/modules/rhsm_release.py
@@ -16,7 +16,7 @@ description:
- Sets or unsets the release version used by RHSM repositories.
notes:
- This module will fail on an unregistered system.
- Use the C(redhat_subscription) module to register a system
+ Use the M(community.general.redhat_subscription) module to register a system
prior to setting the RHSM release.
- It is possible to interact with C(subscription-manager) only as root,
so root permissions are required to successfully run this module.
@@ -33,7 +33,7 @@ options:
release:
description:
- RHSM release version to use.
- - To unset either pass C(null) for this option, or omit this option.
+ - To unset either pass V(null) for this option, or omit this option.
type: str
author:
- Sean Myers (@seandst)
@@ -77,9 +77,9 @@ def _sm_release(module, *args):
# pass args to s-m release, e.g. _sm_release(module, '--set', '0.1') becomes
# "subscription-manager release --set 0.1"
sm_bin = module.get_bin_path('subscription-manager', required=True)
- cmd = '{0} release {1}'.format(sm_bin, " ".join(args))
+ cmd = [sm_bin, 'release'] + list(args)
# delegate nonzero rc handling to run_command
- return module.run_command(cmd, check_rc=True)
+ return module.run_command(cmd, check_rc=True, expand_user_and_vars=False)
def get_release(module):
diff --git a/ansible_collections/community/general/plugins/modules/rhsm_repository.py b/ansible_collections/community/general/plugins/modules/rhsm_repository.py
index eea6e3857..e58389102 100644
--- a/ansible_collections/community/general/plugins/modules/rhsm_repository.py
+++ b/ansible_collections/community/general/plugins/modules/rhsm_repository.py
@@ -18,7 +18,7 @@ description:
author: Giovanni Sciortino (@giovannisciortino)
notes:
- In order to manage RHSM repositories the system must be already registered
- to RHSM manually or using the Ansible C(redhat_subscription) module.
+ to RHSM manually or using the Ansible M(community.general.redhat_subscription) module.
- It is possible to interact with C(subscription-manager) only as root,
so root permissions are required to successfully run this module.
@@ -36,6 +36,10 @@ options:
description:
- If state is equal to present or disabled, indicates the desired
repository state.
+ - |
+ Please note that V(present) and V(absent) are deprecated, and will be
+ removed in community.general 10.0.0; please use V(enabled) and
+ V(disabled) instead.
choices: [present, enabled, absent, disabled]
default: "enabled"
type: str
@@ -49,8 +53,8 @@ options:
elements: str
purge:
description:
- - Disable all currently enabled repositories that are not not specified in C(name).
- Only set this to C(True) if passing in a list of repositories to the C(name) field.
+ - Disable all currently enabled repositories that are not not specified in O(name).
+ Only set this to V(true) if passing in a list of repositories to the O(name) field.
Using this with C(loop) will most likely not have the desired result.
type: bool
default: false
@@ -86,93 +90,88 @@ repositories:
type: list
'''
-import re
import os
from fnmatch import fnmatch
from copy import deepcopy
from ansible.module_utils.basic import AnsibleModule
-def run_subscription_manager(module, arguments):
- # Execute subscription-manager with arguments and manage common errors
- rhsm_bin = module.get_bin_path('subscription-manager')
- if not rhsm_bin:
- module.fail_json(msg='The executable file subscription-manager was not found in PATH')
-
- lang_env = dict(LANG='C', LC_ALL='C', LC_MESSAGES='C')
- rc, out, err = module.run_command("%s %s" % (rhsm_bin, " ".join(arguments)), environ_update=lang_env)
-
- if rc == 0 and out == 'This system has no repositories available through subscriptions.\n':
- module.fail_json(msg='This system has no repositories available through subscriptions')
- elif rc == 1:
- module.fail_json(msg='subscription-manager failed with the following error: %s' % err)
- else:
- return rc, out, err
-
-
-def get_repository_list(module, list_parameter):
- # Generate RHSM repository list and return a list of dict
- if list_parameter == 'list_enabled':
- rhsm_arguments = ['repos', '--list-enabled']
- elif list_parameter == 'list_disabled':
- rhsm_arguments = ['repos', '--list-disabled']
- elif list_parameter == 'list':
- rhsm_arguments = ['repos', '--list']
- rc, out, err = run_subscription_manager(module, rhsm_arguments)
-
- skip_lines = [
- '+----------------------------------------------------------+',
- ' Available Repositories in /etc/yum.repos.d/redhat.repo'
- ]
- repo_id_re = re.compile(r'Repo ID:\s+(.*)')
- repo_name_re = re.compile(r'Repo Name:\s+(.*)')
- repo_url_re = re.compile(r'Repo URL:\s+(.*)')
- repo_enabled_re = re.compile(r'Enabled:\s+(.*)')
-
- repo_id = ''
- repo_name = ''
- repo_url = ''
- repo_enabled = ''
-
- repo_result = []
- for line in out.splitlines():
- if line == '' or line in skip_lines:
- continue
-
- repo_id_match = repo_id_re.match(line)
- if repo_id_match:
- repo_id = repo_id_match.group(1)
- continue
-
- repo_name_match = repo_name_re.match(line)
- if repo_name_match:
- repo_name = repo_name_match.group(1)
- continue
-
- repo_url_match = repo_url_re.match(line)
- if repo_url_match:
- repo_url = repo_url_match.group(1)
- continue
-
- repo_enabled_match = repo_enabled_re.match(line)
- if repo_enabled_match:
- repo_enabled = repo_enabled_match.group(1)
-
- repo = {
- "id": repo_id,
- "name": repo_name,
- "url": repo_url,
- "enabled": True if repo_enabled == '1' else False
- }
-
- repo_result.append(repo)
-
- return repo_result
-
-
-def repository_modify(module, state, name, purge=False):
+class Rhsm(object):
+ def __init__(self, module):
+ self.module = module
+ self.rhsm_bin = self.module.get_bin_path('subscription-manager', required=True)
+ self.rhsm_kwargs = {
+ 'environ_update': dict(LANG='C', LC_ALL='C', LC_MESSAGES='C'),
+ 'expand_user_and_vars': False,
+ 'use_unsafe_shell': False,
+ }
+
+ def run_repos(self, arguments):
+ """
+ Execute `subscription-manager repos` with arguments and manage common errors
+ """
+ rc, out, err = self.module.run_command(
+ [self.rhsm_bin, 'repos'] + arguments,
+ **self.rhsm_kwargs
+ )
+
+ if rc == 0 and out == 'This system has no repositories available through subscriptions.\n':
+ self.module.fail_json(msg='This system has no repositories available through subscriptions')
+ elif rc == 1:
+ self.module.fail_json(msg='subscription-manager failed with the following error: %s' % err)
+ else:
+ return rc, out, err
+
+ def list_repositories(self):
+ """
+ Generate RHSM repository list and return a list of dict
+ """
+ rc, out, err = self.run_repos(['--list'])
+
+ repo_id = ''
+ repo_name = ''
+ repo_url = ''
+ repo_enabled = ''
+
+ repo_result = []
+ for line in out.splitlines():
+ # ignore lines that are:
+ # - empty
+ # - "+---------[...]" -- i.e. header
+ # - " Available Repositories [...]" -- i.e. header
+ if line == '' or line[0] == '+' or line[0] == ' ':
+ continue
+
+ if line.startswith('Repo ID: '):
+ repo_id = line[9:].lstrip()
+ continue
+
+ if line.startswith('Repo Name: '):
+ repo_name = line[11:].lstrip()
+ continue
+
+ if line.startswith('Repo URL: '):
+ repo_url = line[10:].lstrip()
+ continue
+
+ if line.startswith('Enabled: '):
+ repo_enabled = line[9:].lstrip()
+
+ repo = {
+ "id": repo_id,
+ "name": repo_name,
+ "url": repo_url,
+ "enabled": True if repo_enabled == '1' else False
+ }
+
+ repo_result.append(repo)
+
+ return repo_result
+
+
+def repository_modify(module, rhsm, state, name, purge=False):
name = set(name)
- current_repo_list = get_repository_list(module, 'list')
+ current_repo_list = rhsm.list_repositories()
updated_repo_list = deepcopy(current_repo_list)
matched_existing_repo = {}
for repoid in name:
@@ -187,7 +186,7 @@ def repository_modify(module, state, name, purge=False):
results = []
diff_before = ""
diff_after = ""
- rhsm_arguments = ['repos']
+ rhsm_arguments = []
for repoid in matched_existing_repo:
if len(matched_existing_repo[repoid]) == 0:
@@ -222,6 +221,9 @@ def repository_modify(module, state, name, purge=False):
diff_after.join("Repository '{repoid}' is disabled for this system\n".format(repoid=repoid))
results.append("Repository '{repoid}' is disabled for this system".format(repoid=repoid))
rhsm_arguments.extend(['--disable', repoid])
+ for updated_repo in updated_repo_list:
+ if updated_repo['id'] in difference:
+ updated_repo['enabled'] = False
diff = {'before': diff_before,
'after': diff_after,
@@ -229,7 +231,7 @@ def repository_modify(module, state, name, purge=False):
'after_header': "RHSM repositories"}
if not module.check_mode and changed:
- rc, out, err = run_subscription_manager(module, rhsm_arguments)
+ rc, out, err = rhsm.run_repos(rhsm_arguments)
results = out.splitlines()
module.exit_json(results=results, changed=changed, repositories=updated_repo_list, diff=diff)
@@ -249,11 +251,21 @@ def main():
msg="Interacting with subscription-manager requires root permissions ('become: true')"
)
+ rhsm = Rhsm(module)
+
name = module.params['name']
state = module.params['state']
purge = module.params['purge']
- repository_modify(module, state, name, purge)
+ if state in ['present', 'absent']:
+ replacement = 'enabled' if state == 'present' else 'disabled'
+ module.deprecate(
+ 'state=%s is deprecated; please use state=%s instead' % (state, replacement),
+ version='10.0.0',
+ collection_name='community.general',
+ )
+
+ repository_modify(module, rhsm, state, name, purge)
if __name__ == '__main__':
diff --git a/ansible_collections/community/general/plugins/modules/riak.py b/ansible_collections/community/general/plugins/modules/riak.py
index 024e5424d..fe295d2d6 100644
--- a/ansible_collections/community/general/plugins/modules/riak.py
+++ b/ansible_collections/community/general/plugins/modules/riak.py
@@ -64,7 +64,7 @@ options:
type: str
validate_certs:
description:
- - If C(false), SSL certificates will not be validated. This should only be used
+ - If V(false), SSL certificates will not be validated. This should only be used
on personally controlled sites using self-signed certificates.
type: bool
default: true
diff --git a/ansible_collections/community/general/plugins/modules/rocketchat.py b/ansible_collections/community/general/plugins/modules/rocketchat.py
index 23d6d529e..473f0150a 100644
--- a/ansible_collections/community/general/plugins/modules/rocketchat.py
+++ b/ansible_collections/community/general/plugins/modules/rocketchat.py
@@ -29,8 +29,8 @@ options:
domain:
type: str
description:
- - The domain for your environment without protocol. (i.e.
- C(example.com) or C(chat.example.com))
+ - The domain for your environment without protocol. (For example
+ V(example.com) or V(chat.example.com).)
required: true
token:
type: str
@@ -42,7 +42,7 @@ options:
protocol:
type: str
description:
- - Specify the protocol used to send notification messages before the webhook url. (i.e. http or https)
+ - Specify the protocol used to send notification messages before the webhook URL (that is, V(http) or V(https)).
default: https
choices:
- 'http'
@@ -54,7 +54,7 @@ options:
channel:
type: str
description:
- - Channel to send the message to. If absent, the message goes to the channel selected for the I(token)
+ - Channel to send the message to. If absent, the message goes to the channel selected for the O(token)
specified during the creation of webhook.
username:
type: str
@@ -70,18 +70,20 @@ options:
type: str
description:
- Emoji for the message sender. The representation for the available emojis can be
- got from Rocket Chat. (for example :thumbsup:) (if I(icon_emoji) is set, I(icon_url) will not be used)
+ got from Rocket Chat.
+ - For example V(:thumbsup:).
+ - If O(icon_emoji) is set, O(icon_url) will not be used.
link_names:
type: int
description:
- - Automatically create links for channels and usernames in I(msg).
+ - Automatically create links for channels and usernames in O(msg).
default: 1
choices:
- 1
- 0
validate_certs:
description:
- - If C(false), SSL certificates will not be validated. This should only be used
+ - If V(false), SSL certificates will not be validated. This should only be used
on personally controlled sites using self-signed certificates.
type: bool
default: true
diff --git a/ansible_collections/community/general/plugins/modules/rollbar_deployment.py b/ansible_collections/community/general/plugins/modules/rollbar_deployment.py
index 314e65bc6..4bce9ab98 100644
--- a/ansible_collections/community/general/plugins/modules/rollbar_deployment.py
+++ b/ansible_collections/community/general/plugins/modules/rollbar_deployment.py
@@ -63,7 +63,7 @@ options:
default: 'https://api.rollbar.com/api/1/deploy/'
validate_certs:
description:
- - If C(false), SSL certificates for the target url will not be validated.
+ - If V(false), SSL certificates for the target url will not be validated.
This should only be used on personally controlled sites using
self-signed certificates.
required: false
diff --git a/ansible_collections/community/general/plugins/modules/rpm_ostree_pkg.py b/ansible_collections/community/general/plugins/modules/rpm_ostree_pkg.py
index 52219cd1b..826c33f2d 100644
--- a/ansible_collections/community/general/plugins/modules/rpm_ostree_pkg.py
+++ b/ansible_collections/community/general/plugins/modules/rpm_ostree_pkg.py
@@ -35,8 +35,8 @@ options:
state:
description:
- State of the overlay package.
- - C(present) simply ensures that a desired package is installed.
- - C(absent) removes the specified package.
+ - V(present) simply ensures that a desired package is installed.
+ - V(absent) removes the specified package.
choices: [ 'absent', 'present' ]
default: 'present'
type: str
diff --git a/ansible_collections/community/general/plugins/modules/rundeck_acl_policy.py b/ansible_collections/community/general/plugins/modules/rundeck_acl_policy.py
index 77026e633..8f21a3268 100644
--- a/ansible_collections/community/general/plugins/modules/rundeck_acl_policy.py
+++ b/ansible_collections/community/general/plugins/modules/rundeck_acl_policy.py
@@ -108,11 +108,11 @@ rundeck_response:
returned: failed
type: str
before:
- description: Dictionary containing ACL policy informations before modification.
+ description: Dictionary containing ACL policy information before modification.
returned: success
type: dict
after:
- description: Dictionary containing ACL policy informations after modification.
+ description: Dictionary containing ACL policy information after modification.
returned: success
type: dict
'''
diff --git a/ansible_collections/community/general/plugins/modules/rundeck_job_run.py b/ansible_collections/community/general/plugins/modules/rundeck_job_run.py
index 894f1bb6f..2ef144740 100644
--- a/ansible_collections/community/general/plugins/modules/rundeck_job_run.py
+++ b/ansible_collections/community/general/plugins/modules/rundeck_job_run.py
@@ -42,7 +42,7 @@ options:
type: str
description:
- Schedule the job execution to run at specific date and time.
- - ISO-8601 date and time format like C(2021-10-05T15:45:00-03:00).
+ - ISO-8601 date and time format like V(2021-10-05T15:45:00-03:00).
loglevel:
type: str
description:
@@ -64,12 +64,12 @@ options:
description:
- Job execution wait timeout in seconds.
- If the timeout is reached, the job will be aborted.
- - Keep in mind that there is a sleep based on I(wait_execution_delay) after each job status check.
+ - Keep in mind that there is a sleep based on O(wait_execution_delay) after each job status check.
default: 120
abort_on_timeout:
type: bool
description:
- - Send a job abort request if exceeded the I(wait_execution_timeout) specified.
+ - Send a job abort request if exceeded the O(wait_execution_timeout) specified.
default: false
extends_documentation_fragment:
- community.general.rundeck
diff --git a/ansible_collections/community/general/plugins/modules/runit.py b/ansible_collections/community/general/plugins/modules/runit.py
index 7c5882af8..2f1609ca6 100644
--- a/ansible_collections/community/general/plugins/modules/runit.py
+++ b/ansible_collections/community/general/plugins/modules/runit.py
@@ -31,11 +31,11 @@ options:
required: true
state:
description:
- - C(started)/C(stopped) are idempotent actions that will not run
- commands unless necessary. C(restarted) will always bounce the
- service (sv restart) and C(killed) will always bounce the service (sv force-stop).
- C(reloaded) will send a HUP (sv reload).
- C(once) will run a normally downed sv once (sv once), not really
+ - V(started)/V(stopped) are idempotent actions that will not run
+ commands unless necessary. V(restarted) will always bounce the
+ service (sv restart) and V(killed) will always bounce the service (sv force-stop).
+ V(reloaded) will send a HUP (sv reload).
+ V(once) will run a normally downed sv once (sv once), not really
an idempotent operation.
type: str
choices: [ killed, once, reloaded, restarted, started, stopped ]
diff --git a/ansible_collections/community/general/plugins/modules/sap_task_list_execute.py b/ansible_collections/community/general/plugins/modules/sap_task_list_execute.py
deleted file mode 100644
index 14b347e44..000000000
--- a/ansible_collections/community/general/plugins/modules/sap_task_list_execute.py
+++ /dev/null
@@ -1,348 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# Copyright (c) 2021, Rainer Leber <rainerleber@gmail.com>
-# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
-# SPDX-License-Identifier: GPL-3.0-or-later
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-DOCUMENTATION = r'''
----
-module: sap_task_list_execute
-short_description: Perform SAP Task list execution
-version_added: "3.5.0"
-description:
- - The C(sap_task_list_execute) module depends on C(pyrfc) Python library (version 2.4.0 and upwards).
- Depending on distribution you are using, you may need to install additional packages to
- have these available.
- - Tasks in the task list which requires manual activities will be confirmed automatically.
- - This module will use the RFC package C(STC_TM_API).
-extends_documentation_fragment:
- - community.general.attributes
-attributes:
- check_mode:
- support: none
- diff_mode:
- support: none
-
-requirements:
- - pyrfc >= 2.4.0
- - xmltodict
-
-options:
- conn_username:
- description: The required username for the SAP system.
- required: true
- type: str
- conn_password:
- description: The required password for the SAP system.
- required: true
- type: str
- host:
- description: The required host for the SAP system. Can be either an FQDN or IP Address.
- required: true
- type: str
- sysnr:
- description:
- - The system number of the SAP system.
- - You must quote the value to ensure retaining the leading zeros.
- default: '00'
- type: str
- client:
- description:
- - The client number to connect to.
- - You must quote the value to ensure retaining the leading zeros.
- default: '000'
- type: str
- task_to_execute:
- description: The task list which will be executed.
- required: true
- type: str
- task_parameters:
- description:
- - The tasks and the parameters for execution.
- - If the task list do not need any parameters. This could be empty.
- - If only specific tasks from the task list should be executed.
- The tasks even when no parameter is needed must be provided.
- Alongside with the module parameter I(task_skip=true).
- type: list
- elements: dict
- suboptions:
- TASKNAME:
- description: The name of the task in the task list.
- type: str
- required: true
- FIELDNAME:
- description: The name of the field of the task.
- type: str
- VALUE:
- description: The value which have to be set.
- type: raw
- task_settings:
- description:
- - Setting for the execution of the task list. This can be the following as in TCODE SE80 described.
- Check Mode C(CHECKRUN), Background Processing Active C(BATCH) (this is the default value),
- Asynchronous Execution C(ASYNC), Trace Mode C(TRACE), Server Name C(BATCH_TARGET).
- default: ['BATCH']
- type: list
- elements: str
- task_skip:
- description:
- - If this parameter is C(true) not defined tasks in I(task_parameters) are skipped.
- - This could be the case when only certain tasks should run from the task list.
- default: false
- type: bool
-
-author:
- - Rainer Leber (@rainerleber)
-'''
-
-EXAMPLES = r'''
-# Pass in a message
-- name: Test task execution
- community.general.sap_task_list_execute:
- conn_username: DDIC
- conn_password: Passwd1234
- host: 10.1.8.10
- sysnr: '01'
- client: '000'
- task_to_execute: SAP_BASIS_SSL_CHECK
- task_settings: batch
-
-- name: Pass in input parameters
- community.general.sap_task_list_execute:
- conn_username: DDIC
- conn_password: Passwd1234
- host: 10.1.8.10
- sysnr: '00'
- client: '000'
- task_to_execute: SAP_BASIS_SSL_CHECK
- task_parameters :
- - { 'TASKNAME': 'CL_STCT_CHECK_SEC_CRYPTO', 'FIELDNAME': 'P_OPT2', 'VALUE': 'X' }
- - TASKNAME: CL_STCT_CHECK_SEC_CRYPTO
- FIELDNAME: P_OPT3
- VALUE: X
- task_settings: batch
-
-# Exported environement variables.
-- name: Hint if module will fail with error message like ImportError libsapnwrfc.so...
- community.general.sap_task_list_execute:
- conn_username: DDIC
- conn_password: Passwd1234
- host: 10.1.8.10
- sysnr: '00'
- client: '000'
- task_to_execute: SAP_BASIS_SSL_CHECK
- task_settings: batch
- environment:
- SAPNWRFC_HOME: /usr/local/sap/nwrfcsdk
- LD_LIBRARY_PATH: /usr/local/sap/nwrfcsdk/lib
-'''
-
-RETURN = r'''
-msg:
- description: A small execution description.
- type: str
- returned: always
- sample: 'Successful'
-out:
- description: A complete description of the executed tasks. If this is available.
- type: list
- elements: dict
- returned: on success
- sample: [...,{
- "LOG": {
- "STCTM_S_LOG": [
- {
- "ACTIVITY": "U_CONFIG",
- "ACTIVITY_DESCR": "Configuration changed",
- "DETAILS": null,
- "EXEC_ID": "20210728184903.815739",
- "FIELD": null,
- "ID": "STC_TASK",
- "LOG_MSG_NO": "000000",
- "LOG_NO": null,
- "MESSAGE": "For radiobutton group ICM too many options are set; choose only one option",
- "MESSAGE_V1": "ICM",
- "MESSAGE_V2": null,
- "MESSAGE_V3": null,
- "MESSAGE_V4": null,
- "NUMBER": "048",
- "PARAMETER": null,
- "PERIOD": "M",
- "PERIOD_DESCR": "Maintenance",
- "ROW": "0",
- "SRC_LINE": "170",
- "SRC_OBJECT": "CL_STCTM_REPORT_UI IF_STCTM_UI_TASK~SET_PARAMETERS",
- "SYSTEM": null,
- "TIMESTMP": "20210728184903",
- "TSTPNM": "DDIC",
- "TYPE": "E"
- },...
- ]}}]
-'''
-
-from ansible.module_utils.basic import AnsibleModule, missing_required_lib
-import traceback
-try:
- from pyrfc import Connection
-except ImportError:
- HAS_PYRFC_LIBRARY = False
- PYRFC_LIBRARY_IMPORT_ERROR = traceback.format_exc()
-else:
- HAS_PYRFC_LIBRARY = True
- PYRFC_LIBRARY_IMPORT_ERROR = None
-try:
- import xmltodict
-except ImportError:
- HAS_XMLTODICT_LIBRARY = False
- XMLTODICT_LIBRARY_IMPORT_ERROR = traceback.format_exc()
-else:
- HAS_XMLTODICT_LIBRARY = True
- XMLTODICT_LIBRARY_IMPORT_ERROR = None
-
-
-def call_rfc_method(connection, method_name, kwargs):
- # PyRFC call function
- return connection.call(method_name, **kwargs)
-
-
-def process_exec_settings(task_settings):
- # processes task settings to objects
- exec_settings = {}
- for settings in task_settings:
- temp_dict = {settings.upper(): 'X'}
- for key, value in temp_dict.items():
- exec_settings[key] = value
- return exec_settings
-
-
-def xml_to_dict(xml_raw):
- try:
- xml_parsed = xmltodict.parse(xml_raw, dict_constructor=dict)
- xml_dict = xml_parsed['asx:abap']['asx:values']['SESSION']['TASKLIST']
- except KeyError:
- xml_dict = "No logs available."
- return xml_dict
-
-
-def run_module():
-
- params_spec = dict(
- TASKNAME=dict(type='str', required=True),
- FIELDNAME=dict(type='str'),
- VALUE=dict(type='raw'),
- )
-
- # define available arguments/parameters a user can pass to the module
- module = AnsibleModule(
- argument_spec=dict(
- # values for connection
- conn_username=dict(type='str', required=True),
- conn_password=dict(type='str', required=True, no_log=True),
- host=dict(type='str', required=True),
- sysnr=dict(type='str', default="00"),
- client=dict(type='str', default="000"),
- # values for execution tasks
- task_to_execute=dict(type='str', required=True),
- task_parameters=dict(type='list', elements='dict', options=params_spec),
- task_settings=dict(type='list', elements='str', default=['BATCH']),
- task_skip=dict(type='bool', default=False),
- ),
- supports_check_mode=False,
- )
- result = dict(changed=False, msg='', out={})
-
- params = module.params
-
- username = params['conn_username'].upper()
- password = params['conn_password']
- host = params['host']
- sysnr = params['sysnr']
- client = params['client']
-
- task_parameters = params['task_parameters']
- task_to_execute = params['task_to_execute']
- task_settings = params['task_settings']
- task_skip = params['task_skip']
-
- if not HAS_PYRFC_LIBRARY:
- module.fail_json(
- msg=missing_required_lib('pyrfc'),
- exception=PYRFC_LIBRARY_IMPORT_ERROR)
-
- if not HAS_XMLTODICT_LIBRARY:
- module.fail_json(
- msg=missing_required_lib('xmltodict'),
- exception=XMLTODICT_LIBRARY_IMPORT_ERROR)
-
- # basic RFC connection with pyrfc
- try:
- conn = Connection(user=username, passwd=password, ashost=host, sysnr=sysnr, client=client)
- except Exception as err:
- result['error'] = str(err)
- result['msg'] = 'Something went wrong connecting to the SAP system.'
- module.fail_json(**result)
-
- try:
- raw_params = call_rfc_method(conn, 'STC_TM_SCENARIO_GET_PARAMETERS',
- {'I_SCENARIO_ID': task_to_execute})
- except Exception as err:
- result['error'] = str(err)
- result['msg'] = 'The task list does not exsist.'
- module.fail_json(**result)
- exec_settings = process_exec_settings(task_settings)
- # initialize session task
- session_init = call_rfc_method(conn, 'STC_TM_SESSION_BEGIN',
- {'I_SCENARIO_ID': task_to_execute,
- 'I_INIT_ONLY': 'X'})
- # Confirm Tasks which requires manual activities from Task List Run
- for task in raw_params['ET_PARAMETER']:
- call_rfc_method(conn, 'STC_TM_TASK_CONFIRM',
- {'I_SESSION_ID': session_init['E_SESSION_ID'],
- 'I_TASKNAME': task['TASKNAME']})
- if task_skip:
- for task in raw_params['ET_PARAMETER']:
- call_rfc_method(conn, 'STC_TM_TASK_SKIP',
- {'I_SESSION_ID': session_init['E_SESSION_ID'],
- 'I_TASKNAME': task['TASKNAME'], 'I_SKIP_DEP_TASKS': 'X'})
- # unskip defined tasks and set parameters
- if task_parameters is not None:
- for task in task_parameters:
- call_rfc_method(conn, 'STC_TM_TASK_UNSKIP',
- {'I_SESSION_ID': session_init['E_SESSION_ID'],
- 'I_TASKNAME': task['TASKNAME'], 'I_UNSKIP_DEP_TASKS': 'X'})
-
- call_rfc_method(conn, 'STC_TM_SESSION_SET_PARAMETERS',
- {'I_SESSION_ID': session_init['E_SESSION_ID'],
- 'IT_PARAMETER': task_parameters})
- # start the task
- try:
- session_start = call_rfc_method(conn, 'STC_TM_SESSION_RESUME',
- {'I_SESSION_ID': session_init['E_SESSION_ID'],
- 'IS_EXEC_SETTINGS': exec_settings})
- except Exception as err:
- result['error'] = str(err)
- result['msg'] = 'Something went wrong. See error.'
- module.fail_json(**result)
- # get task logs because the execution may successfully but the tasks shows errors or warnings
- # returned value is ABAPXML https://help.sap.com/doc/abapdocu_755_index_htm/7.55/en-US/abenabap_xslt_asxml_general.htm
- session_log = call_rfc_method(conn, 'STC_TM_SESSION_GET_LOG',
- {'I_SESSION_ID': session_init['E_SESSION_ID']})
-
- task_list = xml_to_dict(session_log['E_LOG'])
-
- result['changed'] = True
- result['msg'] = session_start['E_STATUS_DESCR']
- result['out'] = task_list
-
- module.exit_json(**result)
-
-
-def main():
- run_module()
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/general/plugins/modules/sapcar_extract.py b/ansible_collections/community/general/plugins/modules/sapcar_extract.py
deleted file mode 100644
index badd466e1..000000000
--- a/ansible_collections/community/general/plugins/modules/sapcar_extract.py
+++ /dev/null
@@ -1,228 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# Copyright (c) 2021, Rainer Leber <rainerleber@gmail.com>
-# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
-# SPDX-License-Identifier: GPL-3.0-or-later
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-DOCUMENTATION = '''
----
-module: sapcar_extract
-short_description: Manages SAP SAPCAR archives
-version_added: "3.2.0"
-description:
- - Provides support for unpacking C(sar)/C(car) files with the SAPCAR binary from SAP and pulling
- information back into Ansible.
-extends_documentation_fragment:
- - community.general.attributes
-attributes:
- check_mode:
- support: partial
- details:
- - Always returns C(changed=true) in check mode.
- diff_mode:
- support: none
-options:
- path:
- description: The path to the SAR/CAR file.
- type: path
- required: true
- dest:
- description:
- - The destination where SAPCAR extracts the SAR file. Missing folders will be created.
- If this parameter is not provided it will unpack in the same folder as the SAR file.
- type: path
- binary_path:
- description:
- - The path to the SAPCAR binary, for example, C(/home/dummy/sapcar) or C(https://myserver/SAPCAR).
- If this parameter is not provided the module will look in C(PATH).
- type: path
- signature:
- description:
- - If C(true) the signature will be extracted.
- default: false
- type: bool
- security_library:
- description:
- - The path to the security library, for example, C(/usr/sap/hostctrl/exe/libsapcrytp.so), for signature operations.
- type: path
- manifest:
- description:
- - The name of the manifest.
- default: "SIGNATURE.SMF"
- type: str
- remove:
- description:
- - If C(true) the SAR/CAR file will be removed. B(This should be used with caution!)
- default: false
- type: bool
-author:
- - Rainer Leber (@RainerLeber)
-'''
-
-EXAMPLES = """
-- name: Extract SAR file
- community.general.sapcar_extract:
- path: "~/source/hana.sar"
-
-- name: Extract SAR file with destination
- community.general.sapcar_extract:
- path: "~/source/hana.sar"
- dest: "~/test/"
-
-- name: Extract SAR file with destination and download from webserver can be a fileshare as well
- community.general.sapcar_extract:
- path: "~/source/hana.sar"
- dest: "~/dest/"
- binary_path: "https://myserver/SAPCAR"
-
-- name: Extract SAR file and delete SAR after extract
- community.general.sapcar_extract:
- path: "~/source/hana.sar"
- remove: true
-
-- name: Extract SAR file with manifest
- community.general.sapcar_extract:
- path: "~/source/hana.sar"
- signature: true
-
-- name: Extract SAR file with manifest and rename it
- community.general.sapcar_extract:
- path: "~/source/hana.sar"
- manifest: "MyNewSignature.SMF"
- signature: true
-"""
-
-import os
-from tempfile import NamedTemporaryFile
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.urls import open_url
-from ansible.module_utils.common.text.converters import to_native
-
-
-def get_list_of_files(dir_name):
- # create a list of file and directories
- # names in the given directory
- list_of_file = os.listdir(dir_name)
- allFiles = list()
- # Iterate over all the entries
- for entry in list_of_file:
- # Create full path
- fullPath = os.path.join(dir_name, entry)
- # If entry is a directory then get the list of files in this directory
- if os.path.isdir(fullPath):
- allFiles = allFiles + [fullPath]
- allFiles = allFiles + get_list_of_files(fullPath)
- else:
- allFiles.append(fullPath)
- return allFiles
-
-
-def download_SAPCAR(binary_path, module):
- bin_path = None
- # download sapcar binary if url is provided otherwise path is returned
- if binary_path is not None:
- if binary_path.startswith('https://') or binary_path.startswith('http://'):
- random_file = NamedTemporaryFile(delete=False)
- with open_url(binary_path) as response:
- with random_file as out_file:
- data = response.read()
- out_file.write(data)
- os.chmod(out_file.name, 0o700)
- bin_path = out_file.name
- module.add_cleanup_file(bin_path)
- else:
- bin_path = binary_path
- return bin_path
-
-
-def check_if_present(command, path, dest, signature, manifest, module):
- # manipuliating output from SAR file for compare with already extracted files
- iter_command = [command, '-tvf', path]
- sar_out = module.run_command(iter_command)[1]
- sar_raw = sar_out.split("\n")[1:]
- if dest[-1] != "/":
- dest = dest + "/"
- sar_files = [dest + x.split(" ")[-1] for x in sar_raw if x]
- # remove any SIGNATURE.SMF from list because it will not unpacked if signature is false
- if not signature:
- sar_files = [item for item in sar_files if '.SMF' not in item]
- # if signature is renamed manipulate files in list of sar file for compare.
- if manifest != "SIGNATURE.SMF":
- sar_files = [item for item in sar_files if '.SMF' not in item]
- sar_files = sar_files + [manifest]
- # get extracted files if present
- files_extracted = get_list_of_files(dest)
- # compare extracted files with files in sar file
- present = all(elem in files_extracted for elem in sar_files)
- return present
-
-
-def main():
- module = AnsibleModule(
- argument_spec=dict(
- path=dict(type='path', required=True),
- dest=dict(type='path'),
- binary_path=dict(type='path'),
- signature=dict(type='bool', default=False),
- security_library=dict(type='path'),
- manifest=dict(type='str', default="SIGNATURE.SMF"),
- remove=dict(type='bool', default=False),
- ),
- supports_check_mode=True,
- )
- rc, out, err = [0, "", ""]
- params = module.params
- check_mode = module.check_mode
-
- path = params['path']
- dest = params['dest']
- signature = params['signature']
- security_library = params['security_library']
- manifest = params['manifest']
- remove = params['remove']
-
- bin_path = download_SAPCAR(params['binary_path'], module)
-
- if dest is None:
- dest_head_tail = os.path.split(path)
- dest = dest_head_tail[0] + '/'
- else:
- if not os.path.exists(dest):
- os.makedirs(dest, 0o755)
-
- if bin_path is not None:
- command = [module.get_bin_path(bin_path, required=True)]
- else:
- try:
- command = [module.get_bin_path('sapcar', required=True)]
- except Exception as e:
- module.fail_json(msg='Failed to find SAPCAR at the expected path or URL "{0}". Please check whether it is available: {1}'
- .format(bin_path, to_native(e)))
-
- present = check_if_present(command[0], path, dest, signature, manifest, module)
-
- if not present:
- command.extend(['-xvf', path, '-R', dest])
- if security_library:
- command.extend(['-L', security_library])
- if signature:
- command.extend(['-manifest', manifest])
- if not check_mode:
- (rc, out, err) = module.run_command(command, check_rc=True)
- changed = True
- else:
- changed = False
- out = "already unpacked"
-
- if remove:
- os.remove(path)
-
- module.exit_json(changed=changed, message=rc, stdout=out,
- stderr=err, command=' '.join(command))
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/general/plugins/modules/scaleway_compute.py b/ansible_collections/community/general/plugins/modules/scaleway_compute.py
index 9bd821807..7f85bc668 100644
--- a/ansible_collections/community/general/plugins/modules/scaleway_compute.py
+++ b/ansible_collections/community/general/plugins/modules/scaleway_compute.py
@@ -37,8 +37,8 @@ options:
description:
- Manage public IP on a Scaleway server
- Could be Scaleway IP address UUID
- - C(dynamic) Means that IP is destroyed at the same time the host is destroyed
- - C(absent) Means no public IP at all
+ - V(dynamic) Means that IP is destroyed at the same time the host is destroyed
+ - V(absent) Means no public IP at all
default: absent
enable_ipv6:
@@ -62,13 +62,13 @@ options:
type: str
description:
- Organization identifier.
- - Exactly one of I(project) and I(organization) must be specified.
+ - Exactly one of O(project) and O(organization) must be specified.
project:
type: str
description:
- Project identifier.
- - Exactly one of I(project) and I(organization) must be specified.
+ - Exactly one of O(project) and O(organization) must be specified.
version_added: 4.3.0
state:
diff --git a/ansible_collections/community/general/plugins/modules/scaleway_compute_private_network.py b/ansible_collections/community/general/plugins/modules/scaleway_compute_private_network.py
index 9a9d9adde..b41720be5 100644
--- a/ansible_collections/community/general/plugins/modules/scaleway_compute_private_network.py
+++ b/ansible_collections/community/general/plugins/modules/scaleway_compute_private_network.py
@@ -49,7 +49,7 @@ options:
region:
type: str
description:
- - Scaleway region to use (for example C(par1)).
+ - Scaleway region to use (for example V(par1)).
required: true
choices:
- ams1
@@ -98,7 +98,7 @@ EXAMPLES = '''
RETURN = '''
scaleway_compute_private_network:
description: Information on the VPC.
- returned: success when I(state=present)
+ returned: success when O(state=present)
type: dict
sample:
{
diff --git a/ansible_collections/community/general/plugins/modules/scaleway_container.py b/ansible_collections/community/general/plugins/modules/scaleway_container.py
index 19ffae419..8764a7634 100644
--- a/ansible_collections/community/general/plugins/modules/scaleway_container.py
+++ b/ansible_collections/community/general/plugins/modules/scaleway_container.py
@@ -51,7 +51,7 @@ options:
region:
type: str
description:
- - Scaleway region to use (for example C(fr-par)).
+ - Scaleway region to use (for example V(fr-par)).
required: true
choices:
- fr-par
@@ -90,7 +90,7 @@ options:
secret_environment_variables:
description:
- Secret environment variables of the container namespace.
- - Updating thoses values will not output a C(changed) state in Ansible.
+ - Updating those values will not output a C(changed) state in Ansible.
- Injected in container at runtime.
type: dict
default: {}
@@ -109,7 +109,7 @@ options:
privacy:
description:
- Privacy policies define whether a container can be executed anonymously.
- - Choose C(public) to enable anonymous execution, or C(private) to protect your container with an authentication mechanism provided by the Scaleway API.
+ - Choose V(public) to enable anonymous execution, or V(private) to protect your container with an authentication mechanism provided by the Scaleway API.
type: str
default: public
choices:
@@ -174,7 +174,7 @@ EXAMPLES = '''
RETURN = '''
container:
description: The container information.
- returned: when I(state=present)
+ returned: when O(state=present)
type: dict
sample:
cpu_limit: 140
diff --git a/ansible_collections/community/general/plugins/modules/scaleway_container_namespace.py b/ansible_collections/community/general/plugins/modules/scaleway_container_namespace.py
index fb01b8672..fd56a7d43 100644
--- a/ansible_collections/community/general/plugins/modules/scaleway_container_namespace.py
+++ b/ansible_collections/community/general/plugins/modules/scaleway_container_namespace.py
@@ -51,7 +51,7 @@ options:
region:
type: str
description:
- - Scaleway region to use (for example C(fr-par)).
+ - Scaleway region to use (for example V(fr-par)).
required: true
choices:
- fr-par
@@ -80,7 +80,7 @@ options:
secret_environment_variables:
description:
- Secret environment variables of the container namespace.
- - Updating thoses values will not output a C(changed) state in Ansible.
+ - Updating those values will not output a C(changed) state in Ansible.
- Injected in containers at runtime.
type: dict
default: {}
@@ -110,7 +110,7 @@ EXAMPLES = '''
RETURN = '''
container_namespace:
description: The container namespace information.
- returned: when I(state=present)
+ returned: when O(state=present)
type: dict
sample:
description: ""
diff --git a/ansible_collections/community/general/plugins/modules/scaleway_container_registry.py b/ansible_collections/community/general/plugins/modules/scaleway_container_registry.py
index 5eee571ec..6344a7ae6 100644
--- a/ansible_collections/community/general/plugins/modules/scaleway_container_registry.py
+++ b/ansible_collections/community/general/plugins/modules/scaleway_container_registry.py
@@ -34,7 +34,7 @@ options:
state:
type: str
description:
- - Indicate desired state of the container regitry.
+ - Indicate desired state of the container registry.
default: present
choices:
- present
@@ -49,7 +49,7 @@ options:
region:
type: str
description:
- - Scaleway region to use (for example C(fr-par)).
+ - Scaleway region to use (for example V(fr-par)).
required: true
choices:
- fr-par
@@ -72,7 +72,7 @@ options:
type: str
description:
- Default visibility policy.
- - Everyone will be able to pull images from a C(public) registry.
+ - Everyone will be able to pull images from a V(public) registry.
choices:
- public
- private
@@ -99,7 +99,7 @@ EXAMPLES = '''
RETURN = '''
container_registry:
description: The container registry information.
- returned: when I(state=present)
+ returned: when O(state=present)
type: dict
sample:
created_at: "2022-10-14T09:51:07.949716Z"
diff --git a/ansible_collections/community/general/plugins/modules/scaleway_database_backup.py b/ansible_collections/community/general/plugins/modules/scaleway_database_backup.py
index edc9f6cab..592ec0b7f 100644
--- a/ansible_collections/community/general/plugins/modules/scaleway_database_backup.py
+++ b/ansible_collections/community/general/plugins/modules/scaleway_database_backup.py
@@ -32,10 +32,10 @@ options:
state:
description:
- Indicate desired state of the database backup.
- - C(present) creates a backup.
- - C(absent) deletes the backup.
- - C(exported) creates a download link for the backup.
- - C(restored) restores the backup to a new database.
+ - V(present) creates a backup.
+ - V(absent) deletes the backup.
+ - V(exported) creates a download link for the backup.
+ - V(restored) restores the backup to a new database.
type: str
default: present
choices:
@@ -46,7 +46,7 @@ options:
region:
description:
- - Scaleway region to use (for example C(fr-par)).
+ - Scaleway region to use (for example V(fr-par)).
type: str
required: true
choices:
@@ -57,37 +57,37 @@ options:
id:
description:
- UUID used to identify the database backup.
- - Required for C(absent), C(exported) and C(restored) states.
+ - Required for V(absent), V(exported) and V(restored) states.
type: str
name:
description:
- Name used to identify the database backup.
- - Required for C(present) state.
- - Ignored when I(state=absent), I(state=exported) or I(state=restored).
+ - Required for V(present) state.
+ - Ignored when O(state=absent), O(state=exported) or O(state=restored).
type: str
required: false
database_name:
description:
- Name used to identify the database.
- - Required for C(present) and C(restored) states.
- - Ignored when I(state=absent) or I(state=exported).
+ - Required for V(present) and V(restored) states.
+ - Ignored when O(state=absent) or O(state=exported).
type: str
required: false
instance_id:
description:
- UUID of the instance associated to the database backup.
- - Required for C(present) and C(restored) states.
- - Ignored when I(state=absent) or I(state=exported).
+ - Required for V(present) and V(restored) states.
+ - Ignored when O(state=absent) or O(state=exported).
type: str
required: false
expires_at:
description:
- Expiration datetime of the database backup (ISO 8601 format).
- - Ignored when I(state=absent), I(state=exported) or I(state=restored).
+ - Ignored when O(state=absent), O(state=exported) or O(state=restored).
type: str
required: false
@@ -145,7 +145,7 @@ EXAMPLES = '''
RETURN = '''
metadata:
description: Backup metadata.
- returned: when I(state=present), I(state=exported) or I(state=restored)
+ returned: when O(state=present), O(state=exported), or O(state=restored)
type: dict
sample: {
"metadata": {
diff --git a/ansible_collections/community/general/plugins/modules/scaleway_function.py b/ansible_collections/community/general/plugins/modules/scaleway_function.py
index 378545866..eb121cd9c 100644
--- a/ansible_collections/community/general/plugins/modules/scaleway_function.py
+++ b/ansible_collections/community/general/plugins/modules/scaleway_function.py
@@ -51,7 +51,7 @@ options:
region:
type: str
description:
- - Scaleway region to use (for example C(fr-par)).
+ - Scaleway region to use (for example V(fr-par)).
required: true
choices:
- fr-par
@@ -90,7 +90,7 @@ options:
secret_environment_variables:
description:
- Secret environment variables of the function.
- - Updating thoses values will not output a C(changed) state in Ansible.
+ - Updating those values will not output a C(changed) state in Ansible.
- Injected in function at runtime.
type: dict
default: {}
@@ -121,7 +121,7 @@ options:
privacy:
description:
- Privacy policies define whether a function can be executed anonymously.
- - Choose C(public) to enable anonymous execution, or C(private) to protect your function with an authentication mechanism provided by the Scaleway API.
+ - Choose V(public) to enable anonymous execution, or V(private) to protect your function with an authentication mechanism provided by the Scaleway API.
type: str
default: public
choices:
@@ -160,7 +160,7 @@ EXAMPLES = '''
RETURN = '''
function:
description: The function information.
- returned: when I(state=present)
+ returned: when O(state=present)
type: dict
sample:
cpu_limit: 140
diff --git a/ansible_collections/community/general/plugins/modules/scaleway_function_namespace.py b/ansible_collections/community/general/plugins/modules/scaleway_function_namespace.py
index f6310b35b..0ea31e9bc 100644
--- a/ansible_collections/community/general/plugins/modules/scaleway_function_namespace.py
+++ b/ansible_collections/community/general/plugins/modules/scaleway_function_namespace.py
@@ -51,7 +51,7 @@ options:
region:
type: str
description:
- - Scaleway region to use (for example C(fr-par)).
+ - Scaleway region to use (for example V(fr-par)).
required: true
choices:
- fr-par
@@ -80,7 +80,7 @@ options:
secret_environment_variables:
description:
- Secret environment variables of the function namespace.
- - Updating thoses values will not output a C(changed) state in Ansible.
+ - Updating those values will not output a C(changed) state in Ansible.
- Injected in functions at runtime.
type: dict
default: {}
@@ -110,7 +110,7 @@ EXAMPLES = '''
RETURN = '''
function_namespace:
description: The function namespace information.
- returned: when I(state=present)
+ returned: when O(state=present)
type: dict
sample:
description: ""
diff --git a/ansible_collections/community/general/plugins/modules/scaleway_ip.py b/ansible_collections/community/general/plugins/modules/scaleway_ip.py
index cf8e2e601..1c9042742 100644
--- a/ansible_collections/community/general/plugins/modules/scaleway_ip.py
+++ b/ansible_collections/community/general/plugins/modules/scaleway_ip.py
@@ -94,8 +94,8 @@ EXAMPLES = '''
RETURN = '''
data:
- description: This is only present when I(state=present).
- returned: when I(state=present)
+ description: This is only present when O(state=present).
+ returned: when O(state=present)
type: dict
sample: {
"ips": [
diff --git a/ansible_collections/community/general/plugins/modules/scaleway_private_network.py b/ansible_collections/community/general/plugins/modules/scaleway_private_network.py
index 33fb7381c..0cc9b900f 100644
--- a/ansible_collections/community/general/plugins/modules/scaleway_private_network.py
+++ b/ansible_collections/community/general/plugins/modules/scaleway_private_network.py
@@ -48,7 +48,7 @@ options:
region:
type: str
description:
- - Scaleway region to use (for example C(par1)).
+ - Scaleway region to use (for example V(par1)).
required: true
choices:
- ams1
@@ -93,7 +93,7 @@ EXAMPLES = '''
RETURN = '''
scaleway_private_network:
description: Information on the VPC.
- returned: success when I(state=present)
+ returned: success when O(state=present)
type: dict
sample:
{
diff --git a/ansible_collections/community/general/plugins/modules/scaleway_security_group.py b/ansible_collections/community/general/plugins/modules/scaleway_security_group.py
index 5523da41c..c09bc34ba 100644
--- a/ansible_collections/community/general/plugins/modules/scaleway_security_group.py
+++ b/ansible_collections/community/general/plugins/modules/scaleway_security_group.py
@@ -45,7 +45,7 @@ options:
region:
description:
- - Scaleway region to use (for example C(par1)).
+ - Scaleway region to use (for example V(par1)).
type: str
required: true
choices:
@@ -110,8 +110,8 @@ EXAMPLES = '''
RETURN = '''
data:
- description: This is only present when I(state=present).
- returned: when I(state=present)
+ description: This is only present when O(state=present).
+ returned: when O(state=present)
type: dict
sample: {
"scaleway_security_group": {
diff --git a/ansible_collections/community/general/plugins/modules/scaleway_security_group_rule.py b/ansible_collections/community/general/plugins/modules/scaleway_security_group_rule.py
index 136631d03..9cbb2eb57 100644
--- a/ansible_collections/community/general/plugins/modules/scaleway_security_group_rule.py
+++ b/ansible_collections/community/general/plugins/modules/scaleway_security_group_rule.py
@@ -22,8 +22,6 @@ description:
extends_documentation_fragment:
- community.general.scaleway
- community.general.attributes
-requirements:
- - ipaddress
attributes:
check_mode:
@@ -44,7 +42,7 @@ options:
region:
type: str
description:
- - Scaleway region to use (for example C(par1)).
+ - Scaleway region to use (for example V(par1)).
required: true
choices:
- ams1
@@ -119,8 +117,8 @@ EXAMPLES = '''
RETURN = '''
data:
- description: This is only present when I(state=present).
- returned: when I(state=present)
+ description: This is only present when O(state=present).
+ returned: when O(state=present)
type: dict
sample: {
"scaleway_security_group_rule": {
@@ -137,19 +135,8 @@ data:
}
'''
-import traceback
-
from ansible_collections.community.general.plugins.module_utils.scaleway import SCALEWAY_LOCATION, scaleway_argument_spec, Scaleway, payload_from_object
-from ansible.module_utils.basic import AnsibleModule, missing_required_lib
-
-try:
- from ipaddress import ip_network # noqa: F401, pylint: disable=unused-import
-except ImportError:
- IPADDRESS_IMP_ERR = traceback.format_exc()
- HAS_IPADDRESS = False
-else:
- IPADDRESS_IMP_ERR = None
- HAS_IPADDRESS = True
+from ansible.module_utils.basic import AnsibleModule
def get_sgr_from_api(security_group_rules, security_group_rule):
@@ -272,8 +259,6 @@ def main():
argument_spec=argument_spec,
supports_check_mode=True,
)
- if not HAS_IPADDRESS:
- module.fail_json(msg=missing_required_lib('ipaddress'), exception=IPADDRESS_IMP_ERR)
core(module)
diff --git a/ansible_collections/community/general/plugins/modules/scaleway_sshkey.py b/ansible_collections/community/general/plugins/modules/scaleway_sshkey.py
index a39e57aa3..5647f9cd0 100644
--- a/ansible_collections/community/general/plugins/modules/scaleway_sshkey.py
+++ b/ansible_collections/community/general/plugins/modules/scaleway_sshkey.py
@@ -72,8 +72,8 @@ EXAMPLES = '''
RETURN = '''
data:
- description: This is only present when I(state=present).
- returned: when I(state=present)
+ description: This is only present when O(state=present).
+ returned: when O(state=present)
type: dict
sample: {
"ssh_public_keys": [
diff --git a/ansible_collections/community/general/plugins/modules/scaleway_volume.py b/ansible_collections/community/general/plugins/modules/scaleway_volume.py
index 2ff09da54..46d72288e 100644
--- a/ansible_collections/community/general/plugins/modules/scaleway_volume.py
+++ b/ansible_collections/community/general/plugins/modules/scaleway_volume.py
@@ -96,8 +96,8 @@ EXAMPLES = '''
RETURN = '''
data:
- description: This is only present when I(state=present).
- returned: when I(state=present)
+ description: This is only present when O(state=present).
+ returned: when O(state=present)
type: dict
sample: {
"volume": {
diff --git a/ansible_collections/community/general/plugins/modules/sefcontext.py b/ansible_collections/community/general/plugins/modules/sefcontext.py
index b2fb36767..19c128fa7 100644
--- a/ansible_collections/community/general/plugins/modules/sefcontext.py
+++ b/ansible_collections/community/general/plugins/modules/sefcontext.py
@@ -36,43 +36,43 @@ options:
description:
- The file type that should have SELinux contexts applied.
- "The following file type options are available:"
- - C(a) for all files,
- - C(b) for block devices,
- - C(c) for character devices,
- - C(d) for directories,
- - C(f) for regular files,
- - C(l) for symbolic links,
- - C(p) for named pipes,
- - C(s) for socket files.
+ - V(a) for all files,
+ - V(b) for block devices,
+ - V(c) for character devices,
+ - V(d) for directories,
+ - V(f) for regular files,
+ - V(l) for symbolic links,
+ - V(p) for named pipes,
+ - V(s) for socket files.
type: str
choices: [ a, b, c, d, f, l, p, s ]
default: a
setype:
description:
- - SELinux type for the specified I(target).
+ - SELinux type for the specified O(target).
type: str
substitute:
description:
- - Path to use to substitute file context(s) for the specified I(target). The context labeling for the I(target) subtree is made equivalent to this path.
+ - Path to use to substitute file context(s) for the specified O(target). The context labeling for the O(target) subtree is made equivalent to this path.
- This is also referred to as SELinux file context equivalence and it implements the C(equal) functionality of the SELinux management tools.
version_added: 6.4.0
type: str
aliases: [ equal ]
seuser:
description:
- - SELinux user for the specified I(target).
- - Defaults to C(system_u) for new file contexts and to existing value when modifying file contexts.
+ - SELinux user for the specified O(target).
+ - Defaults to V(system_u) for new file contexts and to existing value when modifying file contexts.
type: str
selevel:
description:
- - SELinux range for the specified I(target).
- - Defaults to C(s0) for new file contexts and to existing value when modifying file contexts.
+ - SELinux range for the specified O(target).
+ - Defaults to V(s0) for new file contexts and to existing value when modifying file contexts.
type: str
aliases: [ serange ]
state:
description:
- - Whether the SELinux file context must be C(absent) or C(present).
- - Specifying C(absent) without either I(setype) or I(substitute) deletes both SELinux type or path substitution mappings that match I(target).
+ - Whether the SELinux file context must be V(absent) or V(present).
+ - Specifying V(absent) without either O(setype) or O(substitute) deletes both SELinux type or path substitution mappings that match O(target).
type: str
choices: [ absent, present ]
default: present
@@ -89,8 +89,8 @@ options:
default: false
notes:
- The changes are persistent across reboots.
-- I(setype) and I(substitute) are mutually exclusive.
-- If I(state=present) then one of I(setype) or I(substitute) is mandatory.
+- O(setype) and O(substitute) are mutually exclusive.
+- If O(state=present) then one of O(setype) or O(substitute) is mandatory.
- The M(community.general.sefcontext) module does not modify existing files to the new
SELinux context(s), so it is advisable to first create the SELinux
file contexts before creating files, or run C(restorecon) manually
diff --git a/ansible_collections/community/general/plugins/modules/selinux_permissive.py b/ansible_collections/community/general/plugins/modules/selinux_permissive.py
index 7249a01b8..80439e1de 100644
--- a/ansible_collections/community/general/plugins/modules/selinux_permissive.py
+++ b/ansible_collections/community/general/plugins/modules/selinux_permissive.py
@@ -37,7 +37,7 @@ options:
no_reload:
description:
- Disable reloading of the SELinux policy after making change to a domain's permissive setting.
- - The default is C(false), which causes policy to be reloaded when a domain changes state.
+ - The default is V(false), which causes policy to be reloaded when a domain changes state.
- Reloading the policy does not work on older versions of the C(policycoreutils-python) library, for example in EL 6."
type: bool
default: false
diff --git a/ansible_collections/community/general/plugins/modules/sendgrid.py b/ansible_collections/community/general/plugins/modules/sendgrid.py
index 2c0cc9a5b..b4f6b6eaf 100644
--- a/ansible_collections/community/general/plugins/modules/sendgrid.py
+++ b/ansible_collections/community/general/plugins/modules/sendgrid.py
@@ -24,7 +24,6 @@ notes:
account."
- "In order to use api_key, cc, bcc, attachments, from_name, html_body, headers
you must pip install sendgrid"
- - "since 2.2 I(username) and I(password) are not required if you supply an I(api_key)"
requirements:
- sendgrid Python library 1.6.22 or lower (Sendgrid API V2 supported)
extends_documentation_fragment:
@@ -39,12 +38,12 @@ options:
type: str
description:
- Username for logging into the SendGrid account.
- - Since 2.2 it is only required if I(api_key) is not supplied.
+ - It is only required if O(api_key) is not supplied.
password:
type: str
description:
- Password that corresponds to the username.
- - Since 2.2 it is only required if I(api_key) is not supplied.
+ - It is only required if O(api_key) is not supplied.
from_address:
type: str
description:
diff --git a/ansible_collections/community/general/plugins/modules/sensu_check.py b/ansible_collections/community/general/plugins/modules/sensu_check.py
index 1ac2316a8..1430d6a6c 100644
--- a/ansible_collections/community/general/plugins/modules/sensu_check.py
+++ b/ansible_collections/community/general/plugins/modules/sensu_check.py
@@ -16,7 +16,7 @@ short_description: Manage Sensu checks
description:
- Manage the checks that should be run on a machine by I(Sensu).
- Most options do not have a default and will not be added to the check definition unless specified.
- - All defaults except I(path), I(state), I(backup) and I(metric) are not managed by this module,
+ - All defaults except O(path), O(state), O(backup) and O(metric) are not managed by this module,
- they are simply specified for your convenience.
extends_documentation_fragment:
- community.general.attributes
@@ -42,8 +42,8 @@ options:
type: str
description:
- Path to the json file of the check to be added/removed.
- - Will be created if it does not exist (unless I(state=absent)).
- - The parent folders need to exist when I(state=present), otherwise an error will be thrown
+ - Will be created if it does not exist (unless O(state=absent)).
+ - The parent folders need to exist when O(state=present), otherwise an error will be thrown
default: /etc/sensu/conf.d/checks.json
backup:
description:
@@ -54,7 +54,7 @@ options:
command:
type: str
description:
- - Path to the sensu check to run (not required when I(state=absent))
+ - Path to the sensu check to run (not required when O(state=absent))
handlers:
type: list
elements: str
@@ -82,7 +82,7 @@ options:
handle:
description:
- Whether the check should be handled or not
- - Default is C(false).
+ - Default is V(false).
type: bool
subdue_begin:
type: str
@@ -105,14 +105,14 @@ options:
standalone:
description:
- Whether the check should be scheduled by the sensu client or server
- - This option obviates the need for specifying the I(subscribers) option
- - Default is C(false).
+ - This option obviates the need for specifying the O(subscribers) option
+ - Default is V(false).
type: bool
publish:
description:
- Whether the check should be scheduled at all.
- You can still issue it via the sensu api
- - Default is C(false).
+ - Default is V(false).
type: bool
occurrences:
type: int
@@ -127,7 +127,7 @@ options:
description:
- Classifies the check as an aggregate check,
- making it available via the aggregate API
- - Default is C(false).
+ - Default is V(false).
type: bool
low_flap_threshold:
type: int
diff --git a/ansible_collections/community/general/plugins/modules/sensu_client.py b/ansible_collections/community/general/plugins/modules/sensu_client.py
index 2e0bd12ee..eca0804b0 100644
--- a/ansible_collections/community/general/plugins/modules/sensu_client.py
+++ b/ansible_collections/community/general/plugins/modules/sensu_client.py
@@ -77,7 +77,7 @@ options:
deregister:
description:
- If a deregistration event should be created upon Sensu client process stop.
- - Default is C(false).
+ - Default is V(false).
type: bool
deregistration:
type: dict
diff --git a/ansible_collections/community/general/plugins/modules/serverless.py b/ansible_collections/community/general/plugins/modules/serverless.py
index 67d673d4d..8aa9396d6 100644
--- a/ansible_collections/community/general/plugins/modules/serverless.py
+++ b/ansible_collections/community/general/plugins/modules/serverless.py
@@ -46,13 +46,13 @@ options:
region:
description:
- AWS region to deploy the service to.
- - This parameter defaults to C(us-east-1).
+ - This parameter defaults to V(us-east-1).
type: str
default: ''
deploy:
description:
- Whether or not to deploy artifacts after building them.
- - When this option is C(false) all the functions will be built, but no stack update will be run to send them out.
+ - When this option is V(false) all the functions will be built, but no stack update will be run to send them out.
- This is mostly useful for generating artifacts to be stored/deployed elsewhere.
type: bool
default: true
diff --git a/ansible_collections/community/general/plugins/modules/shutdown.py b/ansible_collections/community/general/plugins/modules/shutdown.py
index 5d66fad16..d8108425e 100644
--- a/ansible_collections/community/general/plugins/modules/shutdown.py
+++ b/ansible_collections/community/general/plugins/modules/shutdown.py
@@ -12,8 +12,10 @@ DOCUMENTATION = r'''
module: shutdown
short_description: Shut down a machine
notes:
- - C(PATH) is ignored on the remote node when searching for the C(shutdown) command. Use I(search_paths)
+ - E(PATH) is ignored on the remote node when searching for the C(shutdown) command. Use O(search_paths)
to specify locations to search if the default paths do not work.
+ - The O(msg) and O(delay) options are not supported when a shutdown command is not found in O(search_paths), instead
+ the module will attempt to shutdown the system by calling C(systemctl shutdown).
description:
- Shut downs a machine.
version_added: "1.1.0"
@@ -45,7 +47,7 @@ options:
search_paths:
description:
- Paths to search on the remote machine for the C(shutdown) command.
- - I(Only) these paths will be searched for the C(shutdown) command. C(PATH) is ignored in the remote node when searching for the C(shutdown) command.
+ - I(Only) these paths will be searched for the C(shutdown) command. E(PATH) is ignored in the remote node when searching for the C(shutdown) command.
type: list
elements: path
default: ['/sbin', '/usr/sbin', '/usr/local/sbin']
@@ -74,7 +76,7 @@ EXAMPLES = r'''
RETURN = r'''
shutdown:
- description: C(true) if the machine has been shut down.
+ description: V(true) if the machine has been shut down.
returned: always
type: bool
sample: true
diff --git a/ansible_collections/community/general/plugins/modules/simpleinit_msb.py b/ansible_collections/community/general/plugins/modules/simpleinit_msb.py
new file mode 100644
index 000000000..92738471c
--- /dev/null
+++ b/ansible_collections/community/general/plugins/modules/simpleinit_msb.py
@@ -0,0 +1,322 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2016-2023, Vlad Glagolev <scm@vaygr.net>
+#
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = '''
+---
+module: simpleinit_msb
+short_description: Manage services on Source Mage GNU/Linux
+version_added: 7.5.0
+description:
+ - Controls services on remote hosts using C(simpleinit-msb).
+notes:
+ - This module needs ansible-core 2.15.5 or newer. Older versions have a broken and insufficient daemonize functionality.
+author: "Vlad Glagolev (@vaygr)"
+extends_documentation_fragment:
+ - community.general.attributes
+attributes:
+ check_mode:
+ support: full
+ diff_mode:
+ support: none
+options:
+ name:
+ type: str
+ description:
+ - Name of the service.
+ required: true
+ aliases: ['service']
+ state:
+ type: str
+ required: false
+ choices: [ running, started, stopped, restarted, reloaded ]
+ description:
+ - V(started)/V(stopped) are idempotent actions that will not run
+ commands unless necessary. V(restarted) will always bounce the
+ service. V(reloaded) will always reload.
+ - At least one of O(state) and O(enabled) are required.
+ - Note that V(reloaded) will start the
+ service if it is not already started, even if your chosen init
+ system would not normally.
+ enabled:
+ type: bool
+ required: false
+ description:
+ - Whether the service should start on boot.
+ - At least one of O(state) and O(enabled) are required.
+'''
+
+EXAMPLES = '''
+- name: Example action to start service httpd, if not running
+ community.general.simpleinit_msb:
+ name: httpd
+ state: started
+
+- name: Example action to stop service httpd, if running
+ community.general.simpleinit_msb:
+ name: httpd
+ state: stopped
+
+- name: Example action to restart service httpd, in all cases
+ community.general.simpleinit_msb:
+ name: httpd
+ state: restarted
+
+- name: Example action to reload service httpd, in all cases
+ community.general.simpleinit_msb:
+ name: httpd
+ state: reloaded
+
+- name: Example action to enable service httpd, and not touch the running state
+ community.general.simpleinit_msb:
+ name: httpd
+ enabled: true
+'''
+
+import os
+import re
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.service import daemonize
+
+
+class SimpleinitMSB(object):
+ """
+ Main simpleinit-msb service manipulation class
+ """
+
+ def __init__(self, module):
+ self.module = module
+ self.name = module.params['name']
+ self.state = module.params['state']
+ self.enable = module.params['enabled']
+ self.changed = False
+ self.running = None
+ self.action = None
+ self.telinit_cmd = None
+ self.svc_change = False
+
+ def execute_command(self, cmd, daemon=False):
+ if not daemon:
+ return self.module.run_command(cmd)
+ else:
+ return daemonize(self.module, cmd)
+
+ def check_service_changed(self):
+ if self.state and self.running is None:
+ self.module.fail_json(msg="failed determining service state, possible typo of service name?")
+ # Find out if state has changed
+ if not self.running and self.state in ["started", "running", "reloaded"]:
+ self.svc_change = True
+ elif self.running and self.state in ["stopped", "reloaded"]:
+ self.svc_change = True
+ elif self.state == "restarted":
+ self.svc_change = True
+ if self.module.check_mode and self.svc_change:
+ self.module.exit_json(changed=True, msg='service state changed')
+
+ def modify_service_state(self):
+ # Only do something if state will change
+ if self.svc_change:
+ # Control service
+ if self.state in ['started', 'running']:
+ self.action = "start"
+ elif not self.running and self.state == 'reloaded':
+ self.action = "start"
+ elif self.state == 'stopped':
+ self.action = "stop"
+ elif self.state == 'reloaded':
+ self.action = "reload"
+ elif self.state == 'restarted':
+ self.action = "restart"
+
+ if self.module.check_mode:
+ self.module.exit_json(changed=True, msg='changing service state')
+
+ return self.service_control()
+ else:
+ # If nothing needs to change just say all is well
+ rc = 0
+ err = ''
+ out = ''
+ return rc, out, err
+
+ def get_service_tools(self):
+ paths = ['/sbin', '/usr/sbin', '/bin', '/usr/bin']
+ binaries = ['telinit']
+ location = dict()
+
+ for binary in binaries:
+ location[binary] = self.module.get_bin_path(binary, opt_dirs=paths)
+
+ if location.get('telinit', False) and os.path.exists("/etc/init.d/smgl_init"):
+ self.telinit_cmd = location['telinit']
+
+ if self.telinit_cmd is None:
+ self.module.fail_json(msg='cannot find telinit script for simpleinit-msb, aborting...')
+
+ def get_service_status(self):
+ self.action = "status"
+ rc, status_stdout, status_stderr = self.service_control()
+
+ if self.running is None and status_stdout.count('\n') <= 1:
+ cleanout = status_stdout.lower().replace(self.name.lower(), '')
+
+ if "is not running" in cleanout:
+ self.running = False
+ elif "is running" in cleanout:
+ self.running = True
+
+ return self.running
+
+ def service_enable(self):
+ # Check if the service is already enabled/disabled
+ if not self.enable ^ self.service_enabled():
+ return
+
+ action = "boot" + ("enable" if self.enable else "disable")
+
+ (rc, out, err) = self.execute_command("%s %s %s" % (self.telinit_cmd, action, self.name))
+
+ self.changed = True
+
+ for line in err.splitlines():
+ if self.enable and line.find('already enabled') != -1:
+ self.changed = False
+ break
+ if not self.enable and line.find('already disabled') != -1:
+ self.changed = False
+ break
+
+ if not self.changed:
+ return
+
+ return (rc, out, err)
+
+ def service_enabled(self):
+ self.service_exists()
+
+ (rc, out, err) = self.execute_command("%s %sd" % (self.telinit_cmd, self.enable))
+
+ service_enabled = False if self.enable else True
+
+ rex = re.compile(r'^%s$' % self.name)
+
+ for line in out.splitlines():
+ if rex.match(line):
+ service_enabled = True if self.enable else False
+ break
+
+ return service_enabled
+
+ def service_exists(self):
+ (rc, out, err) = self.execute_command("%s list" % self.telinit_cmd)
+
+ service_exists = False
+
+ rex = re.compile(r'^\w+\s+%s$' % self.name)
+
+ for line in out.splitlines():
+ if rex.match(line):
+ service_exists = True
+ break
+
+ if not service_exists:
+ self.module.fail_json(msg='telinit could not find the requested service: %s' % self.name)
+
+ def service_control(self):
+ self.service_exists()
+
+ svc_cmd = "%s run %s" % (self.telinit_cmd, self.name)
+
+ rc_state, stdout, stderr = self.execute_command("%s %s" % (svc_cmd, self.action), daemon=True)
+
+ return (rc_state, stdout, stderr)
+
+
+def build_module():
+ return AnsibleModule(
+ argument_spec=dict(
+ name=dict(required=True, aliases=['service']),
+ state=dict(choices=['running', 'started', 'stopped', 'restarted', 'reloaded']),
+ enabled=dict(type='bool'),
+ ),
+ supports_check_mode=True,
+ required_one_of=[['state', 'enabled']],
+ )
+
+
+def main():
+ module = build_module()
+
+ service = SimpleinitMSB(module)
+
+ rc = 0
+ out = ''
+ err = ''
+ result = {}
+ result['name'] = service.name
+
+ # Find service management tools
+ service.get_service_tools()
+
+ # Enable/disable service startup at boot if requested
+ if service.module.params['enabled'] is not None:
+ service.service_enable()
+ result['enabled'] = service.enable
+
+ if module.params['state'] is None:
+ # Not changing the running state, so bail out now.
+ result['changed'] = service.changed
+ module.exit_json(**result)
+
+ result['state'] = service.state
+
+ service.get_service_status()
+
+ # Calculate if request will change service state
+ service.check_service_changed()
+
+ # Modify service state if necessary
+ (rc, out, err) = service.modify_service_state()
+
+ if rc != 0:
+ if err:
+ module.fail_json(msg=err)
+ else:
+ module.fail_json(msg=out)
+
+ result['changed'] = service.changed | service.svc_change
+ if service.module.params['enabled'] is not None:
+ result['enabled'] = service.module.params['enabled']
+
+ if not service.module.params['state']:
+ status = service.get_service_status()
+ if status is None:
+ result['state'] = 'absent'
+ elif status is False:
+ result['state'] = 'started'
+ else:
+ result['state'] = 'stopped'
+ else:
+ # as we may have just bounced the service the service command may not
+ # report accurate state at this moment so just show what we ran
+ if service.module.params['state'] in ['started', 'restarted', 'running', 'reloaded']:
+ result['state'] = 'started'
+ else:
+ result['state'] = 'stopped'
+
+ module.exit_json(**result)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/general/plugins/modules/sl_vm.py b/ansible_collections/community/general/plugins/modules/sl_vm.py
index 94055d1d2..1604ffc11 100644
--- a/ansible_collections/community/general/plugins/modules/sl_vm.py
+++ b/ansible_collections/community/general/plugins/modules/sl_vm.py
@@ -158,7 +158,7 @@ options:
state:
description:
- Create, or cancel a virtual instance.
- - Specify C(present) for create, C(absent) to cancel.
+ - Specify V(present) for create, V(absent) to cancel.
choices: [ absent, present ]
default: present
type: str
@@ -173,7 +173,6 @@ options:
default: 600
type: int
requirements:
- - python >= 2.6
- softlayer >= 4.1.1
author:
- Matt Colton (@mcltn)
diff --git a/ansible_collections/community/general/plugins/modules/slack.py b/ansible_collections/community/general/plugins/modules/slack.py
index 4e26f1973..41dd4f5db 100644
--- a/ansible_collections/community/general/plugins/modules/slack.py
+++ b/ansible_collections/community/general/plugins/modules/slack.py
@@ -19,7 +19,7 @@ DOCUMENTATION = """
module: slack
short_description: Send Slack notifications
description:
- - The C(slack) module sends notifications to U(http://slack.com) via the Incoming WebHook integration
+ - The M(community.general.slack) module sends notifications to U(http://slack.com) via the Incoming WebHook integration
author: "Ramon de la Fuente (@ramondelafuente)"
extends_documentation_fragment:
- community.general.attributes
@@ -32,8 +32,8 @@ options:
domain:
type: str
description:
- - Slack (sub)domain for your environment without protocol. (i.e.
- C(example.slack.com)) In 1.8 and beyond, this is deprecated and may
+ - Slack (sub)domain for your environment without protocol. (For example
+ V(example.slack.com).) In Ansible 1.8 and beyond, this is deprecated and may
be ignored. See token documentation for information.
token:
type: str
@@ -41,9 +41,9 @@ options:
- Slack integration token. This authenticates you to the slack service.
Make sure to use the correct type of token, depending on what method you use.
- "Webhook token:
- Prior to 1.8, a token looked like C(3Ffe373sfhRE6y42Fg3rvf4GlK). In
- 1.8 and above, ansible adapts to the new slack API where tokens look
- like C(G922VJP24/D921DW937/3Ffe373sfhRE6y42Fg3rvf4GlK). If tokens
+ Prior to Ansible 1.8, a token looked like V(3Ffe373sfhRE6y42Fg3rvf4GlK). In
+ Ansible 1.8 and above, Ansible adapts to the new slack API where tokens look
+ like V(G922VJP24/D921DW937/3Ffe373sfhRE6y42Fg3rvf4GlK). If tokens
are in the new format then slack will ignore any value of domain. If
the token is in the old format the domain is required. Ansible has no
control of when slack will get rid of the old API. When slack does
@@ -55,8 +55,8 @@ options:
that the incoming webhooks can be added. The key is on the end of the
URL given to you in that section."
- "WebAPI token:
- Slack WebAPI requires a personal, bot or work application token. These tokens start with C(xoxp-), C(xoxb-)
- or C(xoxa-), eg. C(xoxb-1234-56789abcdefghijklmnop). WebAPI token is required if you intend to receive thread_id.
+ Slack WebAPI requires a personal, bot or work application token. These tokens start with V(xoxp-), V(xoxb-)
+ or V(xoxa-), for example V(xoxb-1234-56789abcdefghijklmnop). WebAPI token is required if you intend to receive thread_id.
See Slack's documentation (U(https://api.slack.com/docs/token-types)) for more information."
required: true
msg:
@@ -68,7 +68,7 @@ options:
channel:
type: str
description:
- - Channel to send the message to. If absent, the message goes to the channel selected for the I(token).
+ - Channel to send the message to. If absent, the message goes to the channel selected for the O(token).
thread_id:
description:
- Optional. Timestamp of parent message to thread this message. https://api.slack.com/docs/message-threading
@@ -76,7 +76,7 @@ options:
message_id:
description:
- Optional. Message ID to edit, instead of posting a new message.
- - If supplied I(channel_id) must be in form of C(C0xxxxxxx). use C({{ slack_response.channel_id }}) to get I(channel_id) from previous task run.
+ - If supplied O(channel) must be in form of C(C0xxxxxxx). use C({{ slack_response.channel_id }}) to get RV(ignore:channel_id) from previous task run.
- Corresponds to C(ts) in the Slack API (U(https://api.slack.com/messaging/modifying)).
type: str
version_added: 1.2.0
@@ -88,17 +88,17 @@ options:
icon_url:
type: str
description:
- - URL for the message sender's icon (default C(https://docs.ansible.com/favicon.ico))
+ - URL for the message sender's icon.
default: https://docs.ansible.com/favicon.ico
icon_emoji:
type: str
description:
- Emoji for the message sender. See Slack documentation for options.
- (if I(icon_emoji) is set, I(icon_url) will not be used)
+ - If O(icon_emoji) is set, O(icon_url) will not be used.
link_names:
type: int
description:
- - Automatically create links for channels and usernames in I(msg).
+ - Automatically create links for channels and usernames in O(msg).
default: 1
choices:
- 1
@@ -112,7 +112,7 @@ options:
- 'none'
validate_certs:
description:
- - If C(false), SSL certificates will not be validated. This should only be used
+ - If V(false), SSL certificates will not be validated. This should only be used
on personally controlled sites using self-signed certificates.
type: bool
default: true
@@ -121,7 +121,6 @@ options:
description:
- Allow text to use default colors - use the default of 'normal' to not send a custom color bar at the start of the message.
- Allowed values for color can be one of 'normal', 'good', 'warning', 'danger', any valid 3 digit or 6 digit hex color value.
- - Specifying value in hex is supported since Ansible 2.8.
default: 'normal'
attachments:
type: list
@@ -139,12 +138,12 @@ options:
prepend_hash:
type: str
description:
- - Setting for automatically prepending a C(#) symbol on the passed in I(channel_id).
- - The C(auto) method prepends a C(#) unless I(channel_id) starts with one of C(#), C(@), C(C0), C(GF), C(G0), C(CP).
- These prefixes only cover a small set of the prefixes that should not have a C(#) prepended.
- Since an exact condition which I(channel_id) values must not have the C(#) prefix is not known,
- the value C(auto) for this option will be deprecated in the future. It is best to explicitly set
- I(prepend_hash=always) or I(prepend_hash=never) to obtain the needed behavior.
+ - Setting for automatically prepending a V(#) symbol on the passed in O(channel).
+ - The V(auto) method prepends a V(#) unless O(channel) starts with one of V(#), V(@), V(C0), V(GF), V(G0), V(CP).
+ These prefixes only cover a small set of the prefixes that should not have a V(#) prepended.
+ Since an exact condition which O(channel) values must not have the V(#) prefix is not known,
+ the value V(auto) for this option will be deprecated in the future. It is best to explicitly set
+ O(prepend_hash=always) or O(prepend_hash=never) to obtain the needed behavior.
choices:
- 'always'
- 'never'
diff --git a/ansible_collections/community/general/plugins/modules/slackpkg.py b/ansible_collections/community/general/plugins/modules/slackpkg.py
index 208061a4c..e3d7a1542 100644
--- a/ansible_collections/community/general/plugins/modules/slackpkg.py
+++ b/ansible_collections/community/general/plugins/modules/slackpkg.py
@@ -40,7 +40,7 @@ options:
state:
description:
- - state of the package, you can use "installed" as an alias for C(present) and removed as one for C(absent).
+ - State of the package, you can use V(installed) as an alias for V(present) and V(removed) as one for V(absent).
choices: [ 'present', 'absent', 'latest', 'installed', 'removed' ]
required: false
default: present
diff --git a/ansible_collections/community/general/plugins/modules/smartos_image_info.py b/ansible_collections/community/general/plugins/modules/smartos_image_info.py
index e93ffb9ac..1a25b4668 100644
--- a/ansible_collections/community/general/plugins/modules/smartos_image_info.py
+++ b/ansible_collections/community/general/plugins/modules/smartos_image_info.py
@@ -15,8 +15,6 @@ module: smartos_image_info
short_description: Get SmartOS image details
description:
- Retrieve information about all installed images on SmartOS.
- - This module was called C(smartos_image_facts) before Ansible 2.9, returning C(ansible_facts).
- Note that the M(community.general.smartos_image_info) module no longer returns C(ansible_facts)!
author: Adam Števko (@xen0l)
extends_documentation_fragment:
- community.general.attributes
@@ -29,9 +27,9 @@ options:
filters:
description:
- Criteria for selecting image. Can be any value from image
- manifest and 'published_date', 'published', 'source', 'clones',
- and 'size'. More information can be found at U(https://smartos.org/man/1m/imgadm)
- under 'imgadm list'.
+ manifest and C(published_date), C(published), C(source), C(clones),
+ and C(size). More information can be found at U(https://smartos.org/man/1m/imgadm)
+ under C(imgadm list).
type: str
'''
diff --git a/ansible_collections/community/general/plugins/modules/snap.py b/ansible_collections/community/general/plugins/modules/snap.py
index 4b798d6e2..fd1676480 100644
--- a/ansible_collections/community/general/plugins/modules/snap.py
+++ b/ansible_collections/community/general/plugins/modules/snap.py
@@ -17,7 +17,7 @@ DOCUMENTATION = '''
module: snap
short_description: Manages snaps
description:
- - "Manages snaps packages."
+ - Manages snaps packages.
extends_documentation_fragment:
- community.general.attributes
attributes:
@@ -28,14 +28,20 @@ attributes:
options:
name:
description:
- - Name of the snaps.
+ - Name of the snaps to be installed.
+ - Any named snap accepted by the C(snap) command is valid.
+ - >
+ Notice that snap files might require O(dangerous=true) to ignore the error
+ "cannot find signatures with metadata for snap".
required: true
type: list
elements: str
state:
description:
- Desired state of the package.
- required: false
+ - >
+ When O(state=present) the module will use C(snap install) if the snap is not installed,
+ and C(snap refresh) if it is installed but from a different channel.
default: present
choices: [ absent, present, enabled, disabled ]
type: str
@@ -43,7 +49,7 @@ options:
description:
- Confinement policy. The classic confinement allows a snap to have
the same level of access to the system as "classic" packages,
- like those managed by APT. This option corresponds to the --classic argument.
+ like those managed by APT. This option corresponds to the C(--classic) argument.
This option can only be specified if there is a single snap in the task.
type: bool
required: false
@@ -52,18 +58,29 @@ options:
description:
- Define which release of a snap is installed and tracked for updates.
This option can only be specified if there is a single snap in the task.
+ - If not passed, the C(snap) command will default to V(stable).
+ - If the value passed does not contain the C(track), it will default to C(latest).
+ For example, if V(edge) is passed, the module will assume the channel to be V(latest/edge).
+ - See U(https://snapcraft.io/docs/channels) for more details about snap channels.
type: str
required: false
- default: stable
options:
description:
- Set options with pattern C(key=value) or C(snap:key=value). If a snap name is given, the option will be applied
- to that snap only. If the snap name is omitted, the options will be applied to all snaps listed in I(name). Options will
+ to that snap only. If the snap name is omitted, the options will be applied to all snaps listed in O(name). Options will
only be applied to active snaps.
required: false
type: list
elements: str
version_added: 4.4.0
+ dangerous:
+ description:
+ - Install the given snap file even if there are no pre-acknowledged signatures for it,
+ meaning it was not verified and could be dangerous.
+ type: bool
+ required: false
+ default: false
+ version_added: 7.2.0
author:
- Victor Carceler (@vcarceler) <vcarceler@iespuigcastellar.xeill.net>
@@ -154,51 +171,29 @@ import numbers
from ansible.module_utils.common.text.converters import to_native
-from ansible_collections.community.general.plugins.module_utils.module_helper import (
- CmdStateModuleHelper, ArgFormat
-)
+from ansible_collections.community.general.plugins.module_utils.module_helper import StateModuleHelper
+from ansible_collections.community.general.plugins.module_utils.snap import snap_runner
-__state_map = dict(
- present='install',
- absent='remove',
- enabled='enable',
- disabled='disable',
- info='info', # not public
- list='list', # not public
- set='set', # not public
- get='get', # not public
-)
+class Snap(StateModuleHelper):
+ NOT_INSTALLED = 0
+ CHANNEL_MISMATCH = 1
+ INSTALLED = 2
-
-def _state_map(value):
- return [__state_map[value]]
-
-
-class Snap(CmdStateModuleHelper):
__disable_re = re.compile(r'(?:\S+\s+){5}(?P<notes>\S+)')
__set_param_re = re.compile(r'(?P<snap_prefix>\S+:)?(?P<key>\S+)\s*=\s*(?P<value>.+)')
+ __list_re = re.compile(r'^(?P<name>\S+)\s+\S+\s+\S+\s+(?P<channel>\S+)')
module = dict(
argument_spec={
'name': dict(type='list', elements='str', required=True),
- 'state': dict(type='str', default='present',
- choices=['absent', 'present', 'enabled', 'disabled']),
+ 'state': dict(type='str', default='present', choices=['absent', 'present', 'enabled', 'disabled']),
'classic': dict(type='bool', default=False),
- 'channel': dict(type='str', default='stable'),
+ 'channel': dict(type='str'),
'options': dict(type='list', elements='str'),
+ 'dangerous': dict(type='bool', default=False),
},
supports_check_mode=True,
)
- command = "snap"
- command_args_formats = dict(
- actionable_snaps=dict(fmt=lambda v: v),
- state=dict(fmt=_state_map),
- classic=dict(fmt="--classic", style=ArgFormat.BOOLEAN),
- channel=dict(fmt=lambda v: [] if v == 'stable' else ['--channel', '{0}'.format(v)]),
- options=dict(fmt=list),
- json_format=dict(fmt="-d", style=ArgFormat.BOOLEAN),
- )
- check_rc = False
@staticmethod
def _first_non_zero(a):
@@ -208,19 +203,63 @@ class Snap(CmdStateModuleHelper):
return 0
- def _run_multiple_commands(self, commands):
- outputs = [(c,) + self.run_command(params=c) for c in commands]
- results = ([], [], [], [])
- for output in outputs:
- for i in range(4):
- results[i].append(output[i])
-
- return [
- '; '.join([to_native(x) for x in results[0]]),
- self._first_non_zero(results[1]),
- '\n'.join(results[2]),
- '\n'.join(results[3]),
- ]
+ def __init_module__(self):
+ self.runner = snap_runner(self.module)
+ # if state=present there might be file names passed in 'name', in
+ # which case they must be converted to their actual snap names, which
+ # is done using the names_from_snaps() method calling 'snap info'.
+ self.vars.set("snapinfo_run_info", [], output=(self.verbosity >= 4))
+ self.vars.set("status_run_info", [], output=(self.verbosity >= 4))
+ self.vars.set("status_out", None, output=(self.verbosity >= 4))
+ self.vars.set("run_info", [], output=(self.verbosity >= 4))
+
+ if self.vars.state == "present":
+ self.vars.set("snap_names", self.names_from_snaps(self.vars.name))
+ status_var = "snap_names"
+ else:
+ status_var = "name"
+ self.vars.set("status_var", status_var, output=False)
+ self.vars.set("snap_status", self.snap_status(self.vars[self.vars.status_var], self.vars.channel), output=False, change=True)
+ self.vars.set("snap_status_map", dict(zip(self.vars.name, self.vars.snap_status)), output=False, change=True)
+
+ def __quit_module__(self):
+ self.vars.snap_status = self.snap_status(self.vars[self.vars.status_var], self.vars.channel)
+ if self.vars.channel is None:
+ self.vars.channel = "stable"
+
+ def _run_multiple_commands(self, commands, actionable_names, bundle=True, refresh=False):
+ results_cmd = []
+ results_rc = []
+ results_out = []
+ results_err = []
+ results_run_info = []
+
+ state = "refresh" if refresh else self.vars.state
+
+ with self.runner(commands + ["name"]) as ctx:
+ if bundle:
+ rc, out, err = ctx.run(state=state, name=actionable_names)
+ results_cmd.append(commands + actionable_names)
+ results_rc.append(rc)
+ results_out.append(out.strip())
+ results_err.append(err.strip())
+ results_run_info.append(ctx.run_info)
+ else:
+ for name in actionable_names:
+ rc, out, err = ctx.run(state=state, name=name)
+ results_cmd.append(commands + [name])
+ results_rc.append(rc)
+ results_out.append(out.strip())
+ results_err.append(err.strip())
+ results_run_info.append(ctx.run_info)
+
+ return (
+ '; '.join([to_native(x) for x in results_cmd]),
+ self._first_non_zero(results_rc),
+ '\n'.join(results_out),
+ '\n'.join(results_err),
+ results_run_info,
+ )
def convert_json_subtree_to_map(self, json_subtree, prefix=None):
option_map = {}
@@ -234,7 +273,6 @@ class Snap(CmdStateModuleHelper):
if isinstance(value, (str, float, bool, numbers.Integral)):
option_map[full_key] = str(value)
-
else:
option_map.update(self.convert_json_subtree_to_map(json_subtree=value, prefix=full_key))
@@ -245,8 +283,8 @@ class Snap(CmdStateModuleHelper):
return self.convert_json_subtree_to_map(json_object)
def retrieve_option_map(self, snap_name):
- params = [{'state': 'get'}, {'name': snap_name}, {'json_format': True}]
- rc, out, err = self.run_command(params=params)
+ with self.runner("get name") as ctx:
+ rc, out, err = ctx.run(name=snap_name)
if rc != 0:
return {}
@@ -258,18 +296,73 @@ class Snap(CmdStateModuleHelper):
try:
option_map = self.convert_json_to_map(out)
-
+ return option_map
except Exception as e:
self.do_raise(
msg="Parsing option map returned by 'snap get {0}' triggers exception '{1}', output:\n'{2}'".format(snap_name, str(e), out))
- return option_map
+ def names_from_snaps(self, snaps):
+ def process_one(rc, out, err):
+ res = [line for line in out.split("\n") if line.startswith("name:")]
+ name = res[0].split()[1]
+ return [name]
+
+ def process_many(rc, out, err):
+ # This needs to be "\n---" instead of just "---" because otherwise
+ # if a snap uses "---" in its description then that will incorrectly
+ # be interpreted as a separator between snaps in the output.
+ outputs = out.split("\n---")
+ res = []
+ for sout in outputs:
+ res.extend(process_one(rc, sout, ""))
+ return res
+
+ def process(rc, out, err):
+ if len(snaps) == 1:
+ check_error = err
+ process_ = process_one
+ else:
+ check_error = out
+ process_ = process_many
+
+ if "warning: no snap found" in check_error:
+ self.do_raise("Snaps not found: {0}.".format([x.split()[-1]
+ for x in out.split('\n')
+ if x.startswith("warning: no snap found")]))
+ return process_(rc, out, err)
+
+ names = []
+ if snaps:
+ with self.runner("info name", output_process=process) as ctx:
+ try:
+ names = ctx.run(name=snaps)
+ finally:
+ self.vars.snapinfo_run_info.append(ctx.run_info)
+ return names
+
+ def snap_status(self, snap_name, channel):
+ def _status_check(name, channel, installed):
+ match = [c for n, c in installed if n == name]
+ if not match:
+ return Snap.NOT_INSTALLED
+ if channel and match[0] not in (channel, "latest/{0}".format(channel)):
+ return Snap.CHANNEL_MISMATCH
+ else:
+ return Snap.INSTALLED
+
+ with self.runner("_list") as ctx:
+ rc, out, err = ctx.run(check_rc=True)
+ list_out = out.split('\n')[1:]
+ list_out = [self.__list_re.match(x) for x in list_out]
+ list_out = [(m.group('name'), m.group('channel')) for m in list_out if m]
+ self.vars.status_out = list_out
+ self.vars.status_run_info = ctx.run_info
- def is_snap_installed(self, snap_name):
- return 0 == self.run_command(params=[{'state': 'list'}, {'name': snap_name}])[0]
+ return [_status_check(n, channel, list_out) for n in snap_name]
def is_snap_enabled(self, snap_name):
- rc, out, err = self.run_command(params=[{'state': 'list'}, {'name': snap_name}])
+ with self.runner("_list name") as ctx:
+ rc, out, err = ctx.run(name=snap_name)
if rc != 0:
return None
result = out.splitlines()[1]
@@ -279,22 +372,22 @@ class Snap(CmdStateModuleHelper):
notes = match.group('notes')
return "disabled" not in notes.split(',')
- def process_actionable_snaps(self, actionable_snaps):
+ def _present(self, actionable_snaps, refresh=False):
self.changed = True
self.vars.snaps_installed = actionable_snaps
- if self.module.check_mode:
+ if self.check_mode:
return
- params = ['state', 'classic', 'channel'] # get base cmd parts
+ params = ['state', 'classic', 'channel', 'dangerous'] # get base cmd parts
has_one_pkg_params = bool(self.vars.classic) or self.vars.channel != 'stable'
has_multiple_snaps = len(actionable_snaps) > 1
if has_one_pkg_params and has_multiple_snaps:
- commands = [params + [{'actionable_snaps': [s]}] for s in actionable_snaps]
+ self.vars.cmd, rc, out, err, run_info = self._run_multiple_commands(params, actionable_snaps, bundle=False, refresh=refresh)
else:
- commands = [params + [{'actionable_snaps': actionable_snaps}]]
- self.vars.cmd, rc, out, err = self._run_multiple_commands(commands)
+ self.vars.cmd, rc, out, err, run_info = self._run_multiple_commands(params, actionable_snaps, refresh=refresh)
+ self.vars.run_info = run_info
if rc == 0:
return
@@ -314,10 +407,13 @@ class Snap(CmdStateModuleHelper):
self.vars.meta('classic').set(output=True)
self.vars.meta('channel').set(output=True)
- actionable_snaps = [s for s in self.vars.name if not self.is_snap_installed(s)]
- if actionable_snaps:
- self.process_actionable_snaps(actionable_snaps)
+ actionable_refresh = [snap for snap in self.vars.name if self.vars.snap_status_map[snap] == Snap.CHANNEL_MISMATCH]
+ if actionable_refresh:
+ self._present(actionable_refresh, refresh=True)
+ actionable_install = [snap for snap in self.vars.name if self.vars.snap_status_map[snap] == Snap.NOT_INSTALLED]
+ if actionable_install:
+ self._present(actionable_install)
self.set_options()
@@ -325,7 +421,7 @@ class Snap(CmdStateModuleHelper):
if self.vars.options is None:
return
- actionable_snaps = [s for s in self.vars.name if self.is_snap_installed(s)]
+ actionable_snaps = [s for s in self.vars.name if self.vars.snap_status_map[s] != Snap.NOT_INSTALLED]
overall_options_changed = []
for snap_name in actionable_snaps:
@@ -360,11 +456,9 @@ class Snap(CmdStateModuleHelper):
if options_changed:
self.changed = True
- if not self.module.check_mode:
- params = [{'state': 'set'}, {'name': snap_name}, {'options': options_changed}]
-
- rc, out, err = self.run_command(params=params)
-
+ if not self.check_mode:
+ with self.runner("_set name options") as ctx:
+ rc, out, err = ctx.run(name=snap_name, options=options_changed)
if rc != 0:
if 'has no "configure" hook' in err:
msg = "Snap '{snap}' does not have any configurable options".format(snap=snap_name)
@@ -377,18 +471,16 @@ class Snap(CmdStateModuleHelper):
if overall_options_changed:
self.vars.options_changed = overall_options_changed
- def _generic_state_action(self, actionable_func, actionable_var, params=None):
+ def _generic_state_action(self, actionable_func, actionable_var, params):
actionable_snaps = [s for s in self.vars.name if actionable_func(s)]
if not actionable_snaps:
return
self.changed = True
self.vars[actionable_var] = actionable_snaps
- if self.module.check_mode:
+ if self.check_mode:
return
- if params is None:
- params = ['state']
- commands = [params + [{'actionable_snaps': actionable_snaps}]]
- self.vars.cmd, rc, out, err = self._run_multiple_commands(commands)
+ self.vars.cmd, rc, out, err, run_info = self._run_multiple_commands(params, actionable_snaps)
+ self.vars.run_info = run_info
if rc == 0:
return
msg = "Ooops! Snap operation failed while executing '{cmd}', please examine logs and " \
@@ -396,7 +488,7 @@ class Snap(CmdStateModuleHelper):
self.do_raise(msg=msg)
def state_absent(self):
- self._generic_state_action(self.is_snap_installed, "snaps_removed", ['classic', 'channel', 'state'])
+ self._generic_state_action(lambda s: self.vars.snap_status_map[s] != Snap.NOT_INSTALLED, "snaps_removed", ['classic', 'channel', 'state'])
def state_enabled(self):
self._generic_state_action(lambda s: not self.is_snap_enabled(s), "snaps_enabled", ['classic', 'channel', 'state'])
diff --git a/ansible_collections/community/general/plugins/modules/snap_alias.py b/ansible_collections/community/general/plugins/modules/snap_alias.py
index 19fbef003..54448c6f3 100644
--- a/ansible_collections/community/general/plugins/modules/snap_alias.py
+++ b/ansible_collections/community/general/plugins/modules/snap_alias.py
@@ -86,15 +86,8 @@ snap_aliases:
import re
-from ansible_collections.community.general.plugins.module_utils.cmd_runner import CmdRunner, cmd_runner_fmt
from ansible_collections.community.general.plugins.module_utils.module_helper import StateModuleHelper
-
-
-_state_map = dict(
- present='alias',
- absent='unalias',
- info='aliases',
-)
+from ansible_collections.community.general.plugins.module_utils.snap import snap_runner
class SnapAlias(StateModuleHelper):
@@ -113,18 +106,12 @@ class SnapAlias(StateModuleHelper):
supports_check_mode=True,
)
- command_args_formats = {
- "state": cmd_runner_fmt.as_map(_state_map),
- "name": cmd_runner_fmt.as_list(),
- "alias": cmd_runner_fmt.as_list(),
- }
-
def _aliases(self):
n = self.vars.name
return {n: self._get_aliases_for(n)} if n else self._get_aliases()
def __init_module__(self):
- self.runner = CmdRunner(self.module, "snap", self.command_args_formats, check_rc=False)
+ self.runner = snap_runner(self.module)
self.vars.set("snap_aliases", self._aliases(), change=True, diff=True)
def __quit_module__(self):
@@ -141,8 +128,8 @@ class SnapAlias(StateModuleHelper):
results[snap] = results.get(snap, []) + [alias]
return results
- with self.runner("state name", check_rc=True, output_process=process) as ctx:
- aliases = ctx.run(state="info")
+ with self.runner("state_alias name", check_rc=True, output_process=process) as ctx:
+ aliases = ctx.run(state_alias="info")
if self.verbosity >= 4:
self.vars.get_aliases_run_info = ctx.run_info
return aliases
@@ -164,8 +151,8 @@ class SnapAlias(StateModuleHelper):
for _alias in self.vars.alias:
if not self._has_alias(self.vars.name, _alias):
self.changed = True
- with self.runner("state name alias", check_mode_skip=True) as ctx:
- ctx.run(alias=_alias)
+ with self.runner("state_alias name alias", check_mode_skip=True) as ctx:
+ ctx.run(state_alias=self.vars.state, alias=_alias)
if self.verbosity >= 4:
self.vars.run_info = ctx.run_info
@@ -173,16 +160,16 @@ class SnapAlias(StateModuleHelper):
if not self.vars.alias:
if self._has_alias(self.vars.name):
self.changed = True
- with self.runner("state name", check_mode_skip=True) as ctx:
- ctx.run()
+ with self.runner("state_alias name", check_mode_skip=True) as ctx:
+ ctx.run(state_alias=self.vars.state)
if self.verbosity >= 4:
self.vars.run_info = ctx.run_info
else:
for _alias in self.vars.alias:
if self._has_alias(self.vars.name, _alias):
self.changed = True
- with self.runner("state alias", check_mode_skip=True) as ctx:
- ctx.run(alias=_alias)
+ with self.runner("state_alias alias", check_mode_skip=True) as ctx:
+ ctx.run(state_alias=self.vars.state, alias=_alias)
if self.verbosity >= 4:
self.vars.run_info = ctx.run_info
diff --git a/ansible_collections/community/general/plugins/modules/snmp_facts.py b/ansible_collections/community/general/plugins/modules/snmp_facts.py
index e54473ffa..aecc08f32 100644
--- a/ansible_collections/community/general/plugins/modules/snmp_facts.py
+++ b/ansible_collections/community/general/plugins/modules/snmp_facts.py
@@ -36,46 +36,46 @@ options:
required: true
version:
description:
- - SNMP Version to use, C(v2), C(v2c) or C(v3).
+ - SNMP Version to use, V(v2), V(v2c) or V(v3).
type: str
required: true
choices: [ v2, v2c, v3 ]
community:
description:
- - The SNMP community string, required if I(version) is C(v2) or C(v2c).
+ - The SNMP community string, required if O(version) is V(v2) or V(v2c).
type: str
level:
description:
- Authentication level.
- - Required if I(version) is C(v3).
+ - Required if O(version=v3).
type: str
choices: [ authNoPriv, authPriv ]
username:
description:
- Username for SNMPv3.
- - Required if I(version) is C(v3).
+ - Required if O(version=v3).
type: str
integrity:
description:
- Hashing algorithm.
- - Required if I(version) is C(v3).
+ - Required if O(version=v3).
type: str
choices: [ md5, sha ]
authkey:
description:
- Authentication key.
- - Required I(version) is C(v3).
+ - Required O(version=v3).
type: str
privacy:
description:
- Encryption algorithm.
- - Required if I(level) is C(authPriv).
+ - Required if O(level=authPriv).
type: str
choices: [ aes, des ]
privkey:
description:
- Encryption key.
- - Required if I(level) is C(authPriv).
+ - Required if O(level=authPriv).
type: str
timeout:
description:
@@ -137,7 +137,7 @@ ansible_sysname:
type: str
sample: ubuntu-user
ansible_syslocation:
- description: The physical location of this node (e.g., C(telephone closet, 3rd floor)).
+ description: The physical location of this node (for example, V(telephone closet, 3rd floor)).
returned: success
type: str
sample: Sitting on the Dock of the Bay
diff --git a/ansible_collections/community/general/plugins/modules/solaris_zone.py b/ansible_collections/community/general/plugins/modules/solaris_zone.py
index 0f970704e..d9f44589d 100644
--- a/ansible_collections/community/general/plugins/modules/solaris_zone.py
+++ b/ansible_collections/community/general/plugins/modules/solaris_zone.py
@@ -29,16 +29,16 @@ attributes:
options:
state:
description:
- - C(present), configure and install the zone.
- - C(installed), synonym for C(present).
- - C(running), if the zone already exists, boot it, otherwise, configure and install
+ - V(present), configure and install the zone.
+ - V(installed), synonym for V(present).
+ - V(running), if the zone already exists, boot it, otherwise, configure and install
the zone first, then boot it.
- - C(started), synonym for C(running).
- - C(stopped), shutdown a zone.
- - C(absent), destroy the zone.
- - C(configured), configure the ready so that it's to be attached.
- - C(attached), attach a zone, but do not boot it.
- - C(detached), shutdown and detach a zone
+ - V(started), synonym for V(running).
+ - V(stopped), shutdown a zone.
+ - V(absent), destroy the zone.
+ - V(configured), configure the ready so that it's to be attached.
+ - V(attached), attach a zone, but do not boot it.
+ - V(detached), shutdown and detach a zone
type: str
choices: [ absent, attached, configured, detached, installed, present, running, started, stopped ]
default: present
@@ -46,8 +46,8 @@ options:
description:
- Zone name.
- A zone name must be unique name.
- - A zone name must begin with an alpha-numeric character.
- - The name can contain alpha-numeric characters, underbars I(_), hyphens I(-), and periods I(.).
+ - A zone name must begin with an alphanumeric character.
+ - The name can contain alphanumeric characters, underscores V(_), hyphens V(-), and periods V(.).
- The name cannot be longer than 64 characters.
type: str
required: true
@@ -58,7 +58,7 @@ options:
type: str
sparse:
description:
- - Whether to create a sparse (C(true)) or whole root (C(false)) zone.
+ - Whether to create a sparse (V(true)) or whole root (V(false)) zone.
type: bool
default: false
root_password:
diff --git a/ansible_collections/community/general/plugins/modules/sorcery.py b/ansible_collections/community/general/plugins/modules/sorcery.py
index 3278ce0ab..4fcf46a05 100644
--- a/ansible_collections/community/general/plugins/modules/sorcery.py
+++ b/ansible_collections/community/general/plugins/modules/sorcery.py
@@ -1,7 +1,7 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
-# Copyright (c) 2015-2016, Vlad Glagolev <scm@vaygr.net>
+# Copyright (c) 2015-2023, Vlad Glagolev <scm@vaygr.net>
#
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
@@ -10,7 +10,7 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type
-DOCUMENTATION = '''
+DOCUMENTATION = r'''
---
module: sorcery
short_description: Package manager for Source Mage GNU/Linux
@@ -20,8 +20,7 @@ author: "Vlad Glagolev (@vaygr)"
notes:
- When all three components are selected, the update goes by the sequence --
Sorcery -> Grimoire(s) -> Spell(s); you cannot override it.
- - grimoire handling (i.e. add/remove, including SCM/rsync versions) is not
- yet supported.
+ - Grimoire handling is supported since community.general 7.3.0.
requirements:
- bash
extends_documentation_fragment:
@@ -34,21 +33,31 @@ attributes:
options:
name:
description:
- - Name of the spell
- - multiple names can be given, separated by commas
- - special value '*' in conjunction with states C(latest) or
- C(rebuild) will update or rebuild the whole system respectively
- aliases: ["spell"]
+ - Name of the spell or grimoire.
+ - Multiple names can be given, separated by commas.
+ - Special value V(*) in conjunction with states V(latest) or
+ V(rebuild) will update or rebuild the whole system respectively
+ - The alias O(grimoire) was added in community.general 7.3.0.
+ aliases: ["spell", "grimoire"]
type: list
elements: str
+ repository:
+ description:
+ - Repository location.
+ - If specified, O(name) represents grimoire(s) instead of spell(s).
+ - Special value V(*) will pull grimoire from the official location.
+ - Only single item in O(name) in conjunction with V(*) can be used.
+ - O(state=absent) must be used with a special value V(*).
+ type: str
+ version_added: 7.3.0
+
state:
description:
- - Whether to cast, dispel or rebuild a package
- - state C(cast) is an equivalent of C(present), not C(latest)
- - state C(latest) always triggers I(update_cache=true)
- - state C(rebuild) implies cast of all specified spells, not only
- those existed before
+ - Whether to cast, dispel or rebuild a package.
+ - State V(cast) is an equivalent of V(present), not V(latest).
+ - State V(rebuild) implies cast of all specified spells, not only
+ those existed before.
choices: ["present", "latest", "absent", "cast", "dispelled", "rebuild"]
default: "present"
type: str
@@ -56,32 +65,32 @@ options:
depends:
description:
- Comma-separated list of _optional_ dependencies to build a spell
- (or make sure it is built) with; use +/- in front of dependency
- to turn it on/off ('+' is optional though)
- - this option is ignored if C(name) parameter is equal to '*' or
- contains more than one spell
- - providers must be supplied in the form recognized by Sorcery, e.g.
- 'openssl(SSL)'
+ (or make sure it is built) with; use V(+)/V(-) in front of dependency
+ to turn it on/off (V(+) is optional though).
+ - This option is ignored if O(name) parameter is equal to V(*) or
+ contains more than one spell.
+ - Providers must be supplied in the form recognized by Sorcery,
+ for example 'V(openssl(SSL\))'.
type: str
update:
description:
- - Whether or not to update sorcery scripts at the very first stage
+ - Whether or not to update sorcery scripts at the very first stage.
type: bool
default: false
update_cache:
description:
- - Whether or not to update grimoire collection before casting spells
+ - Whether or not to update grimoire collection before casting spells.
type: bool
default: false
aliases: ["update_codex"]
cache_valid_time:
description:
- - Time in seconds to invalidate grimoire collection on update
- - especially useful for SCM and rsync grimoires
- - makes sense only in pair with C(update_cache)
+ - Time in seconds to invalidate grimoire collection on update.
+ - Especially useful for SCM and rsync grimoires.
+ - Makes sense only in pair with O(update_cache).
type: int
default: 0
'''
@@ -148,6 +157,30 @@ EXAMPLES = '''
update_codex: true
cache_valid_time: 86400
+- name: Make sure stable grimoire is present
+ community.general.sorcery:
+ name: stable
+ repository: '*'
+ state: present
+
+- name: Make sure binary and stable-rc grimoires are removed
+ community.general.sorcery:
+ grimoire: binary,stable-rc
+ repository: '*'
+ state: absent
+
+- name: Make sure games grimoire is pulled from rsync
+ community.general.sorcery:
+ grimoire: games
+ repository: "rsync://download.sourcemage.org::codex/games"
+ state: present
+
+- name: Make sure a specific branch of stable grimoire is pulled from git
+ community.general.sorcery:
+ grimoire: stable.git
+ repository: "git://download.sourcemage.org/smgl/grimoire.git:stable.git:stable-0.62"
+ state: present
+
- name: Update only Sorcery itself
community.general.sorcery:
update: true
@@ -165,6 +198,8 @@ import re
import shutil
import sys
+from ansible.module_utils.basic import AnsibleModule
+
# auto-filled at module init
SORCERY = {
@@ -178,6 +213,8 @@ SORCERY = {
SORCERY_LOG_DIR = "/var/log/sorcery"
SORCERY_STATE_DIR = "/var/state/sorcery"
+NA = "N/A"
+
def get_sorcery_ver(module):
""" Get Sorcery version. """
@@ -218,9 +255,11 @@ def codex_fresh(codex, module):
return True
-def codex_list(module):
+def codex_list(module, skip_new=False):
""" List valid grimoire collection. """
+ params = module.params
+
codex = {}
cmd_scribe = "%s index" % SORCERY['scribe']
@@ -239,6 +278,10 @@ def codex_list(module):
if match:
codex[match.group('grim')] = match.group('ver')
+ # return only specified grimoires unless requested to skip new
+ if params['repository'] and not skip_new:
+ codex = dict((x, codex.get(x, NA)) for x in params['name'])
+
if not codex:
module.fail_json(msg="no grimoires to operate on; add at least one")
@@ -256,8 +299,7 @@ def update_sorcery(module):
changed = False
if module.check_mode:
- if not module.params['name'] and not module.params['update_cache']:
- module.exit_json(changed=True, msg="would have updated Sorcery")
+ return (True, "would have updated Sorcery")
else:
sorcery_ver = get_sorcery_ver(module)
@@ -271,9 +313,7 @@ def update_sorcery(module):
if sorcery_ver != get_sorcery_ver(module):
changed = True
- if not module.params['name'] and not module.params['update_cache']:
- module.exit_json(changed=changed,
- msg="successfully updated Sorcery")
+ return (changed, "successfully updated Sorcery")
def update_codex(module):
@@ -292,28 +332,29 @@ def update_codex(module):
fresh = codex_fresh(codex, module)
if module.check_mode:
- if not params['name']:
- if not fresh:
- changed = True
+ if not fresh:
+ changed = True
- module.exit_json(changed=changed, msg="would have updated Codex")
- elif not fresh or params['name'] and params['state'] == 'latest':
- # SILENT is required as a workaround for query() in libgpg
- module.run_command_environ_update.update(dict(SILENT='1'))
+ return (changed, "would have updated Codex")
+ else:
+ if not fresh:
+ # SILENT is required as a workaround for query() in libgpg
+ module.run_command_environ_update.update(dict(SILENT='1'))
- cmd_scribe = "%s update" % SORCERY['scribe']
+ cmd_scribe = "%s update" % SORCERY['scribe']
- rc, stdout, stderr = module.run_command(cmd_scribe)
+ if params['repository']:
+ cmd_scribe += ' %s' % ' '.join(codex.keys())
- if rc != 0:
- module.fail_json(msg="unable to update Codex: " + stdout)
+ rc, stdout, stderr = module.run_command(cmd_scribe)
- if codex != codex_list(module):
- changed = True
+ if rc != 0:
+ module.fail_json(msg="unable to update Codex: " + stdout)
- if not params['name']:
- module.exit_json(changed=changed,
- msg="successfully updated Codex")
+ if codex != codex_list(module):
+ changed = True
+
+ return (changed, "successfully updated Codex")
def match_depends(module):
@@ -446,6 +487,65 @@ def match_depends(module):
return depends_ok
+def manage_grimoires(module):
+ """ Add or remove grimoires. """
+
+ params = module.params
+ grimoires = params['name']
+ url = params['repository']
+
+ codex = codex_list(module, True)
+
+ if url == '*':
+ if params['state'] in ('present', 'latest', 'absent'):
+ if params['state'] == 'absent':
+ action = "remove"
+ todo = set(grimoires) & set(codex)
+ else:
+ action = "add"
+ todo = set(grimoires) - set(codex)
+
+ if not todo:
+ return (False, "all grimoire(s) are already %sed" % action[:5])
+
+ if module.check_mode:
+ return (True, "would have %sed grimoire(s)" % action[:5])
+
+ cmd_scribe = "%s %s %s" % (SORCERY['scribe'], action, ' '.join(todo))
+
+ rc, stdout, stderr = module.run_command(cmd_scribe)
+
+ if rc != 0:
+ module.fail_json(msg="failed to %s one or more grimoire(s): %s" % (action, stdout))
+
+ return (True, "successfully %sed one or more grimoire(s)" % action[:5])
+ else:
+ module.fail_json(msg="unsupported operation on '*' repository value")
+ else:
+ if params['state'] in ('present', 'latest'):
+ if len(grimoires) > 1:
+ module.fail_json(msg="using multiple items with repository is invalid")
+
+ grimoire = grimoires[0]
+
+ if grimoire in codex:
+ return (False, "grimoire %s already exists" % grimoire)
+
+ if module.check_mode:
+ return (True, "would have added grimoire %s from %s" % (grimoire, url))
+
+ cmd_scribe = "%s add %s from %s" % (SORCERY['scribe'], grimoire, url)
+
+ rc, stdout, stderr = module.run_command(cmd_scribe)
+
+ if rc != 0:
+ module.fail_json(msg="failed to add grimoire %s from %s: %s" % (grimoire, url, stdout))
+
+ return (True, "successfully added grimoire %s from %s" % (grimoire, url))
+ else:
+ module.fail_json(msg="unsupported operation on repository value")
+
+
def manage_spells(module):
""" Cast or dispel spells.
@@ -471,7 +571,7 @@ def manage_spells(module):
# see update_codex()
module.run_command_environ_update.update(dict(SILENT='1'))
- cmd_sorcery = "%s queue"
+ cmd_sorcery = "%s queue" % SORCERY['sorcery']
rc, stdout, stderr = module.run_command(cmd_sorcery)
@@ -490,7 +590,7 @@ def manage_spells(module):
except IOError:
module.fail_json(msg="failed to restore the update queue")
- module.exit_json(changed=True, msg="would have updated the system")
+ return (True, "would have updated the system")
cmd_cast = "%s --queue" % SORCERY['cast']
@@ -499,12 +599,12 @@ def manage_spells(module):
if rc != 0:
module.fail_json(msg="failed to update the system")
- module.exit_json(changed=True, msg="successfully updated the system")
+ return (True, "successfully updated the system")
else:
- module.exit_json(changed=False, msg="the system is already up to date")
+ return (False, "the system is already up to date")
elif params['state'] == 'rebuild':
if module.check_mode:
- module.exit_json(changed=True, msg="would have rebuilt the system")
+ return (True, "would have rebuilt the system")
cmd_sorcery = "%s rebuild" % SORCERY['sorcery']
@@ -513,7 +613,7 @@ def manage_spells(module):
if rc != 0:
module.fail_json(msg="failed to rebuild the system: " + stdout)
- module.exit_json(changed=True, msg="successfully rebuilt the system")
+ return (True, "successfully rebuilt the system")
else:
module.fail_json(msg="unsupported operation on '*' name value")
else:
@@ -575,39 +675,40 @@ def manage_spells(module):
if cast_queue:
if module.check_mode:
- module.exit_json(changed=True, msg="would have cast spell(s)")
+ return (True, "would have cast spell(s)")
cmd_cast = "%s -c %s" % (SORCERY['cast'], ' '.join(cast_queue))
rc, stdout, stderr = module.run_command(cmd_cast)
if rc != 0:
- module.fail_json(msg="failed to cast spell(s): %s" + stdout)
+ module.fail_json(msg="failed to cast spell(s): " + stdout)
- module.exit_json(changed=True, msg="successfully cast spell(s)")
+ return (True, "successfully cast spell(s)")
elif params['state'] != 'absent':
- module.exit_json(changed=False, msg="spell(s) are already cast")
+ return (False, "spell(s) are already cast")
if dispel_queue:
if module.check_mode:
- module.exit_json(changed=True, msg="would have dispelled spell(s)")
+ return (True, "would have dispelled spell(s)")
cmd_dispel = "%s %s" % (SORCERY['dispel'], ' '.join(dispel_queue))
rc, stdout, stderr = module.run_command(cmd_dispel)
if rc != 0:
- module.fail_json(msg="failed to dispel spell(s): %s" + stdout)
+ module.fail_json(msg="failed to dispel spell(s): " + stdout)
- module.exit_json(changed=True, msg="successfully dispelled spell(s)")
+ return (True, "successfully dispelled spell(s)")
else:
- module.exit_json(changed=False, msg="spell(s) are already dispelled")
+ return (False, "spell(s) are already dispelled")
def main():
module = AnsibleModule(
argument_spec=dict(
- name=dict(default=None, aliases=['spell'], type='list', elements='str'),
+ name=dict(default=None, aliases=['spell', 'grimoire'], type='list', elements='str'),
+ repository=dict(default=None, type='str'),
state=dict(default='present', choices=['present', 'latest',
'absent', 'cast', 'dispelled', 'rebuild']),
depends=dict(default=None),
@@ -636,18 +737,34 @@ def main():
elif params['state'] in ('absent', 'dispelled'):
params['state'] = 'absent'
+ changed = {
+ 'sorcery': (False, NA),
+ 'grimoires': (False, NA),
+ 'codex': (False, NA),
+ 'spells': (False, NA)
+ }
+
if params['update']:
- update_sorcery(module)
+ changed['sorcery'] = update_sorcery(module)
- if params['update_cache'] or params['state'] == 'latest':
- update_codex(module)
+ if params['name'] and params['repository']:
+ changed['grimoires'] = manage_grimoires(module)
- if params['name']:
- manage_spells(module)
+ if params['update_cache']:
+ changed['codex'] = update_codex(module)
+ if params['name'] and not params['repository']:
+ changed['spells'] = manage_spells(module)
+
+ if any(x[0] for x in changed.values()):
+ state_msg = "state changed"
+ state_changed = True
+ else:
+ state_msg = "no change in state"
+ state_changed = False
+
+ module.exit_json(changed=state_changed, msg=state_msg + ": " + '; '.join(x[1] for x in changed.values()))
-# import module snippets
-from ansible.module_utils.basic import AnsibleModule
if __name__ == '__main__':
main()
diff --git a/ansible_collections/community/general/plugins/modules/spectrum_device.py b/ansible_collections/community/general/plugins/modules/spectrum_device.py
index 5cfc07664..7cf7cf915 100644
--- a/ansible_collections/community/general/plugins/modules/spectrum_device.py
+++ b/ansible_collections/community/general/plugins/modules/spectrum_device.py
@@ -9,7 +9,7 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type
-DOCUMENTATION = '''
+DOCUMENTATION = r'''
---
module: spectrum_device
short_description: Creates/deletes devices in CA Spectrum
@@ -36,7 +36,7 @@ options:
type: str
description:
- SNMP community used for device discovery.
- - Required when I(state=present).
+ - Required when O(state=present).
required: true
landscape:
type: str
@@ -46,8 +46,8 @@ options:
state:
type: str
description:
- - On C(present) creates the device when it does not exist.
- - On C(absent) removes the device when it exists.
+ - On V(present) creates the device when it does not exist.
+ - On V(absent) removes the device when it exists.
choices: ['present', 'absent']
default: 'present'
url:
@@ -55,7 +55,7 @@ options:
aliases: [ oneclick_url ]
required: true
description:
- - HTTP, HTTPS URL of the Oneclick server in the form C((http|https)://host.domain[:port]).
+ - HTTP, HTTPS URL of the Oneclick server in the form V((http|https\)://host.domain[:port]).
url_username:
type: str
aliases: [ oneclick_user ]
@@ -70,12 +70,12 @@ options:
- Oneclick user password.
use_proxy:
description:
- - if C(false), it will not use a proxy, even if one is defined in an environment variable on the target hosts.
+ - if V(false), it will not use a proxy, even if one is defined in an environment variable on the target hosts.
default: true
type: bool
validate_certs:
description:
- - If C(false), SSL certificates will not be validated. This should only be used
+ - If V(false), SSL certificates will not be validated. This should only be used
on personally controlled sites using self-signed certificates.
default: true
type: bool
diff --git a/ansible_collections/community/general/plugins/modules/spectrum_model_attrs.py b/ansible_collections/community/general/plugins/modules/spectrum_model_attrs.py
index 028ad7f9f..43983a11a 100644
--- a/ansible_collections/community/general/plugins/modules/spectrum_model_attrs.py
+++ b/ansible_collections/community/general/plugins/modules/spectrum_model_attrs.py
@@ -21,8 +21,6 @@ author:
notes:
- Tested on CA Spectrum version 10.4.2.0.189.
- Model creation and deletion are not possible with this module. For that use M(community.general.spectrum_device) instead.
-requirements:
- - 'python >= 2.7'
extends_documentation_fragment:
- community.general.attributes
attributes:
@@ -50,7 +48,7 @@ options:
aliases: [password]
use_proxy:
description:
- - if C(false), it will not use a proxy, even if one is defined in
+ - if V(false), it will not use a proxy, even if one is defined in
an environment variable on the target hosts.
default: true
required: false
@@ -67,7 +65,7 @@ options:
required: true
validate_certs:
description:
- - Validate SSL certificates. Only change this to C(false) if you can guarantee that you are talking to the correct endpoint and there is no
+ - Validate SSL certificates. Only change this to V(false) if you can guarantee that you are talking to the correct endpoint and there is no
man-in-the-middle attack happening.
type: bool
default: true
@@ -109,7 +107,7 @@ options:
required: true
value:
description:
- - Attribute value. Empty strings should be C("") or C(null).
+ - Attribute value. Empty strings should be V("") or V(null).
type: str
required: true
'''
diff --git a/ansible_collections/community/general/plugins/modules/spotinst_aws_elastigroup.py b/ansible_collections/community/general/plugins/modules/spotinst_aws_elastigroup.py
index 02f2d3c5c..45556f621 100644
--- a/ansible_collections/community/general/plugins/modules/spotinst_aws_elastigroup.py
+++ b/ansible_collections/community/general/plugins/modules/spotinst_aws_elastigroup.py
@@ -19,7 +19,6 @@ description:
token = <YOUR TOKEN>
Full documentation available at https://help.spotinst.com/hc/en-us/articles/115003530285-Ansible-
requirements:
- - python >= 2.7
- spotinst_sdk >= 1.0.38
extends_documentation_fragment:
- community.general.attributes
@@ -46,13 +45,13 @@ options:
description:
- A Personal API Access Token issued by Spotinst.
- >-
- When not specified, the module will try to obtain it, in that order, from: environment variable C(SPOTINST_TOKEN), or from the credentials path.
+ When not specified, the module will try to obtain it, in that order, from: environment variable E(SPOTINST_TOKEN), or from the credentials path.
type: str
availability_vs_cost:
description:
- The strategy orientation.
- - "The choices available are: C(availabilityOriented), C(costOriented), C(balanced)."
+ - "The choices available are: V(availabilityOriented), V(costOriented), V(balanced)."
required: true
type: str
@@ -127,7 +126,7 @@ options:
elastic_ips:
description:
- - List of ElasticIps Allocation Ids (Example C(eipalloc-9d4e16f8)) to associate to the group instances
+ - List of ElasticIps Allocation Ids (example V(eipalloc-9d4e16f8)) to associate to the group instances
type: list
elements: str
@@ -139,7 +138,7 @@ options:
health_check_grace_period:
description:
- The amount of time, in seconds, after the instance has launched to start and check its health.
- - If not specified, it defaults to C(300).
+ - If not specified, it defaults to V(300).
type: int
health_check_unhealthy_duration_before_replacement:
@@ -150,7 +149,7 @@ options:
health_check_type:
description:
- The service to use for the health check.
- - "The choices available are: C(ELB), C(HCS), C(TARGET_GROUP), C(MLB), C(EC2)."
+ - "The choices available are: V(ELB), V(HCS), V(TARGET_GROUP), V(MLB), V(EC2)."
type: str
iam_role_name:
@@ -266,14 +265,14 @@ options:
opsworks:
description:
- - The elastigroup OpsWorks integration configration.;
+ - The elastigroup OpsWorks integration configuration.;
Expects the following key -
layer_id (String)
type: dict
persistence:
description:
- - The Stateful elastigroup configration.;
+ - The Stateful elastigroup configuration.;
Accepts the following keys -
should_persist_root_device (Boolean),
should_persist_block_devices (Boolean),
@@ -283,7 +282,7 @@ options:
product:
description:
- Operation system type.
- - "Available choices are: C(Linux/UNIX), C(SUSE Linux), C(Windows), C(Linux/UNIX (Amazon VPC)), C(SUSE Linux (Amazon VPC))."
+ - "Available choices are: V(Linux/UNIX), V(SUSE Linux), V(Windows), V(Linux/UNIX (Amazon VPC)), V(SUSE Linux (Amazon VPC))."
required: true
type: str
@@ -404,7 +403,7 @@ options:
tenancy:
description:
- Dedicated vs shared tenancy.
- - "The available choices are: C(default), C(dedicated)."
+ - "The available choices are: V(default), V(dedicated)."
type: str
terminate_at_end_of_billing_hour:
@@ -415,7 +414,7 @@ options:
unit:
description:
- The capacity unit to launch instances by.
- - "The available choices are: C(instance), C(weight)."
+ - "The available choices are: V(instance), V(weight)."
type: str
up_scaling_policies:
diff --git a/ansible_collections/community/general/plugins/modules/ssh_config.py b/ansible_collections/community/general/plugins/modules/ssh_config.py
index 672ac8c47..e89e087b3 100644
--- a/ansible_collections/community/general/plugins/modules/ssh_config.py
+++ b/ansible_collections/community/general/plugins/modules/ssh_config.py
@@ -38,20 +38,20 @@ options:
user:
description:
- Which user account this configuration file belongs to.
- - If none given and I(ssh_config_file) is not specified, C(/etc/ssh/ssh_config) is used.
+ - If none given and O(ssh_config_file) is not specified, C(/etc/ssh/ssh_config) is used.
- If a user is given, C(~/.ssh/config) is used.
- - Mutually exclusive with I(ssh_config_file).
+ - Mutually exclusive with O(ssh_config_file).
type: str
group:
description:
- Which group this configuration file belongs to.
- - If none given, I(user) is used.
+ - If none given, O(user) is used.
type: str
host:
description:
- The endpoint this configuration is valid for.
- Can be an actual address on the internet or an alias that will
- connect to the value of I(hostname).
+ connect to the value of O(hostname).
required: true
type: str
hostname:
@@ -70,8 +70,17 @@ options:
description:
- The path to an identity file (SSH private key) that will be used
when connecting to this host.
- - File need to exist and have mode C(0600) to be valid.
+ - File need to exist and have mode V(0600) to be valid.
type: path
+ identities_only:
+ description:
+ - Specifies that SSH should only use the configured authentication
+ identity and certificate files (either the default files, or
+ those explicitly configured in the C(ssh_config) files or passed on
+ the ssh command-line), even if ssh-agent or a PKCS11Provider or
+ SecurityKeyProvider offers more identities.
+ type: bool
+ version_added: 8.2.0
user_known_hosts_file:
description:
- Sets the user known hosts file option.
@@ -84,12 +93,12 @@ options:
proxycommand:
description:
- Sets the C(ProxyCommand) option.
- - Mutually exclusive with I(proxyjump).
+ - Mutually exclusive with O(proxyjump).
type: str
proxyjump:
description:
- Sets the C(ProxyJump) option.
- - Mutually exclusive with I(proxycommand).
+ - Mutually exclusive with O(proxycommand).
type: str
version_added: 6.5.0
forward_agent:
@@ -97,17 +106,38 @@ options:
- Sets the C(ForwardAgent) option.
type: bool
version_added: 4.0.0
+ add_keys_to_agent:
+ description:
+ - Sets the C(AddKeysToAgent) option.
+ type: bool
+ version_added: 8.2.0
ssh_config_file:
description:
- SSH config file.
- - If I(user) and this option are not specified, C(/etc/ssh/ssh_config) is used.
- - Mutually exclusive with I(user).
+ - If O(user) and this option are not specified, C(/etc/ssh/ssh_config) is used.
+ - Mutually exclusive with O(user).
type: path
host_key_algorithms:
description:
- Sets the C(HostKeyAlgorithms) option.
type: str
version_added: 6.1.0
+ controlmaster:
+ description:
+ - Sets the C(ControlMaster) option.
+ choices: [ 'yes', 'no', 'ask', 'auto', 'autoask' ]
+ type: str
+ version_added: 8.1.0
+ controlpath:
+ description:
+ - Sets the C(ControlPath) option.
+ type: str
+ version_added: 8.1.0
+ controlpersist:
+ description:
+ - Sets the C(ControlPersist) option.
+ type: str
+ version_added: 8.1.0
requirements:
- paramiko
'''
@@ -177,6 +207,22 @@ from ansible_collections.community.general.plugins.module_utils._stormssh import
from ansible_collections.community.general.plugins.module_utils.ssh import determine_config_file
+def convert_bool(value):
+ if value is True:
+ return 'yes'
+ if value is False:
+ return 'no'
+ return None
+
+
+def fix_bool_str(value):
+ if value == 'True':
+ return 'yes'
+ if value == 'False':
+ return 'no'
+ return value
+
+
class SSHConfig(object):
def __init__(self, module):
self.module = module
@@ -213,20 +259,20 @@ class SSHConfig(object):
hostname=self.params.get('hostname'),
port=self.params.get('port'),
identity_file=self.params.get('identity_file'),
+ identities_only=convert_bool(self.params.get('identities_only')),
user=self.params.get('remote_user'),
strict_host_key_checking=self.params.get('strict_host_key_checking'),
user_known_hosts_file=self.params.get('user_known_hosts_file'),
proxycommand=self.params.get('proxycommand'),
proxyjump=self.params.get('proxyjump'),
host_key_algorithms=self.params.get('host_key_algorithms'),
+ forward_agent=convert_bool(self.params.get('forward_agent')),
+ add_keys_to_agent=convert_bool(self.params.get('add_keys_to_agent')),
+ controlmaster=self.params.get('controlmaster'),
+ controlpath=self.params.get('controlpath'),
+ controlpersist=fix_bool_str(self.params.get('controlpersist')),
)
- # Convert True / False to 'yes' / 'no' for usage in ssh_config
- if self.params['forward_agent'] is True:
- args['forward_agent'] = 'yes'
- if self.params['forward_agent'] is False:
- args['forward_agent'] = 'no'
-
config_changed = False
hosts_changed = []
hosts_change_diff = []
@@ -312,17 +358,23 @@ def main():
hostname=dict(type='str'),
host_key_algorithms=dict(type='str', no_log=False),
identity_file=dict(type='path'),
+ identities_only=dict(type='bool'),
port=dict(type='str'),
proxycommand=dict(type='str', default=None),
proxyjump=dict(type='str', default=None),
forward_agent=dict(type='bool'),
+ add_keys_to_agent=dict(type='bool'),
remote_user=dict(type='str'),
ssh_config_file=dict(default=None, type='path'),
state=dict(type='str', default='present', choices=['present', 'absent']),
strict_host_key_checking=dict(
+ type='str',
default=None,
choices=['yes', 'no', 'ask']
),
+ controlmaster=dict(type='str', default=None, choices=['yes', 'no', 'ask', 'auto', 'autoask']),
+ controlpath=dict(type='str', default=None),
+ controlpersist=dict(type='str', default=None),
user=dict(default=None, type='str'),
user_known_hosts_file=dict(type='str', default=None),
),
diff --git a/ansible_collections/community/general/plugins/modules/stackdriver.py b/ansible_collections/community/general/plugins/modules/stackdriver.py
index cf7cb2f47..35b2b0dc1 100644
--- a/ansible_collections/community/general/plugins/modules/stackdriver.py
+++ b/ansible_collections/community/general/plugins/modules/stackdriver.py
@@ -10,6 +10,11 @@ __metaclass__ = type
DOCUMENTATION = '''
+deprecated:
+ removed_in: 9.0.0
+ why: the endpoints this module relies on do not exist any more and do not resolve to IPs in DNS.
+ alternative: no known alternative at this point
+
module: stackdriver
short_description: Send code deploy and annotation events to stackdriver
description:
diff --git a/ansible_collections/community/general/plugins/modules/stacki_host.py b/ansible_collections/community/general/plugins/modules/stacki_host.py
index e286bc961..57440a24d 100644
--- a/ansible_collections/community/general/plugins/modules/stacki_host.py
+++ b/ansible_collections/community/general/plugins/modules/stacki_host.py
@@ -30,13 +30,13 @@ options:
type: str
stacki_user:
description:
- - Username for authenticating with Stacki API, but if not specified, the environment variable C(stacki_user) is used instead.
+ - Username for authenticating with Stacki API, but if not specified, the environment variable E(stacki_user) is used instead.
required: true
type: str
stacki_password:
description:
- Password for authenticating with Stacki API, but if not
- specified, the environment variable C(stacki_password) is used instead.
+ specified, the environment variable E(stacki_password) is used instead.
required: true
type: str
stacki_endpoint:
@@ -61,7 +61,7 @@ options:
type: str
force_install:
description:
- - Set value to C(true) to force node into install state if it already exists in stacki.
+ - Set value to V(true) to force node into install state if it already exists in stacki.
type: bool
default: false
state:
@@ -72,21 +72,21 @@ options:
default: present
appliance:
description:
- - Applicance to be used in host creation.
- - Required if I(state) is C(present) and host does not yet exist.
+ - Appliance to be used in host creation.
+ - Required if O(state=present) and host does not yet exist.
type: str
default: backend
rack:
description:
- Rack to be used in host creation.
- - Required if I(state) is C(present) and host does not yet exist.
+ - Required if O(state=present) and host does not yet exist.
type: int
default: 0
rank:
description:
- Rank to be used in host creation.
- In Stacki terminology, the rank is the position of the machine in a rack.
- - Required if I(state) is C(present) and host does not yet exist.
+ - Required if O(state=present) and host does not yet exist.
type: int
default: 0
network:
diff --git a/ansible_collections/community/general/plugins/modules/statsd.py b/ansible_collections/community/general/plugins/modules/statsd.py
index 65d33b709..8bc0f0b18 100644
--- a/ansible_collections/community/general/plugins/modules/statsd.py
+++ b/ansible_collections/community/general/plugins/modules/statsd.py
@@ -14,8 +14,8 @@ version_added: 2.1.0
description:
- The C(statsd) module sends metrics to StatsD.
- For more information, see U(https://statsd-metrics.readthedocs.io/en/latest/).
- - Supported metric types are C(counter) and C(gauge).
- Currently unupported metric types are C(timer), C(set), and C(gaugedelta).
+ - Supported metric types are V(counter) and V(gauge).
+ Currently unupported metric types are V(timer), V(set), and V(gaugedelta).
author: "Mark Mercado (@mamercad)"
requirements:
- statsd
@@ -30,7 +30,7 @@ options:
state:
type: str
description:
- - State of the check, only C(present) makes sense.
+ - State of the check, only V(present) makes sense.
choices: ["present"]
default: present
host:
@@ -42,7 +42,7 @@ options:
type: int
default: 8125
description:
- - The port on C(host) which StatsD is listening on.
+ - The port on O(host) which StatsD is listening on.
protocol:
type: str
default: udp
@@ -53,7 +53,7 @@ options:
type: float
default: 1.0
description:
- - Sender timeout, only applicable if C(protocol) is C(tcp).
+ - Sender timeout, only applicable if O(protocol) is V(tcp).
metric:
type: str
required: true
@@ -79,7 +79,7 @@ options:
type: bool
default: false
description:
- - If the metric is of type C(gauge), change the value by C(delta).
+ - If the metric is of type V(gauge), change the value by O(delta).
'''
EXAMPLES = '''
diff --git a/ansible_collections/community/general/plugins/modules/statusio_maintenance.py b/ansible_collections/community/general/plugins/modules/statusio_maintenance.py
index 31b422453..e6b34b709 100644
--- a/ansible_collections/community/general/plugins/modules/statusio_maintenance.py
+++ b/ansible_collections/community/general/plugins/modules/statusio_maintenance.py
@@ -286,25 +286,24 @@ def create_maintenance(auth_headers, url, statuspage, host_ids,
returned_date, maintenance_notify_now,
maintenance_notify_72_hr, maintenance_notify_24_hr,
maintenance_notify_1_hr):
- returned_dates = [[x] for x in returned_date]
component_id = []
container_id = []
for val in host_ids:
component_id.append(val['component_id'])
container_id.append(val['container_id'])
+ infrastructure_id = [i + '-' + j for i, j in zip(component_id, container_id)]
try:
values = json.dumps({
"statuspage_id": statuspage,
- "components": component_id,
- "containers": container_id,
"all_infrastructure_affected": str(int(all_infrastructure_affected)),
+ "infrastructure_affected": infrastructure_id,
"automation": str(int(automation)),
"maintenance_name": title,
"maintenance_details": desc,
- "date_planned_start": returned_dates[0],
- "time_planned_start": returned_dates[1],
- "date_planned_end": returned_dates[2],
- "time_planned_end": returned_dates[3],
+ "date_planned_start": returned_date[0],
+ "time_planned_start": returned_date[1],
+ "date_planned_end": returned_date[2],
+ "time_planned_end": returned_date[3],
"maintenance_notify_now": str(int(maintenance_notify_now)),
"maintenance_notify_72_hr": str(int(maintenance_notify_72_hr)),
"maintenance_notify_24_hr": str(int(maintenance_notify_24_hr)),
diff --git a/ansible_collections/community/general/plugins/modules/sudoers.py b/ansible_collections/community/general/plugins/modules/sudoers.py
index fd8289b1c..a392b4adf 100644
--- a/ansible_collections/community/general/plugins/modules/sudoers.py
+++ b/ansible_collections/community/general/plugins/modules/sudoers.py
@@ -31,13 +31,13 @@ options:
description:
- The commands allowed by the sudoers rule.
- Multiple can be added by passing a list of commands.
- - Use C(ALL) for all commands.
+ - Use V(ALL) for all commands.
type: list
elements: str
group:
description:
- The name of the group for the sudoers rule.
- - This option cannot be used in conjunction with I(user).
+ - This option cannot be used in conjunction with O(user).
type: str
name:
required: true
@@ -45,6 +45,12 @@ options:
- The name of the sudoers rule.
- This will be used for the filename for the sudoers file managed by this rule.
type: str
+ noexec:
+ description:
+ - Whether a command is prevented to run further commands itself.
+ default: false
+ type: bool
+ version_added: 8.4.0
nopassword:
description:
- Whether a password will be required to run the sudo'd command.
@@ -83,13 +89,13 @@ options:
user:
description:
- The name of the user for the sudoers rule.
- - This option cannot be used in conjunction with I(group).
+ - This option cannot be used in conjunction with O(group).
type: str
validation:
description:
- - If C(absent), the sudoers rule will be added without validation.
- - If C(detect) and visudo is available, then the sudoers rule will be validated by visudo.
- - If C(required), visudo must be available to validate the sudoers rule.
+ - If V(absent), the sudoers rule will be added without validation.
+ - If V(detect) and visudo is available, then the sudoers rule will be validated by visudo.
+ - If V(required), visudo must be available to validate the sudoers rule.
type: str
default: detect
choices: [ absent, detect, required ]
@@ -143,6 +149,15 @@ EXAMPLES = '''
user: alice
commands: /usr/local/bin/upload
setenv: true
+
+- name: >-
+ Allow alice to sudo /usr/bin/less but prevent less from
+ running further commands itself
+ community.general.sudoers:
+ name: allow-alice-restricted-less
+ user: alice
+ commands: /usr/bin/less
+ noexec: true
'''
import os
@@ -162,6 +177,7 @@ class Sudoers(object):
self.user = module.params['user']
self.group = module.params['group']
self.state = module.params['state']
+ self.noexec = module.params['noexec']
self.nopassword = module.params['nopassword']
self.setenv = module.params['setenv']
self.host = module.params['host']
@@ -205,13 +221,15 @@ class Sudoers(object):
owner = '%{group}'.format(group=self.group)
commands_str = ', '.join(self.commands)
+ noexec_str = 'NOEXEC:' if self.noexec else ''
nopasswd_str = 'NOPASSWD:' if self.nopassword else ''
setenv_str = 'SETENV:' if self.setenv else ''
runas_str = '({runas})'.format(runas=self.runas) if self.runas is not None else ''
- return "{owner} {host}={runas}{nopasswd}{setenv} {commands}\n".format(
+ return "{owner} {host}={runas}{noexec}{nopasswd}{setenv} {commands}\n".format(
owner=owner,
host=self.host,
runas=runas_str,
+ noexec=noexec_str,
nopasswd=nopasswd_str,
setenv=setenv_str,
commands=commands_str
@@ -258,6 +276,10 @@ def main():
'name': {
'required': True,
},
+ 'noexec': {
+ 'type': 'bool',
+ 'default': False,
+ },
'nopassword': {
'type': 'bool',
'default': True,
diff --git a/ansible_collections/community/general/plugins/modules/supervisorctl.py b/ansible_collections/community/general/plugins/modules/supervisorctl.py
index e9df16108..e8d9c89a6 100644
--- a/ansible_collections/community/general/plugins/modules/supervisorctl.py
+++ b/ansible_collections/community/general/plugins/modules/supervisorctl.py
@@ -27,9 +27,8 @@ options:
type: str
description:
- The name of the supervisord program or group to manage.
- - The name will be taken as group name when it ends with a colon I(:)
- - Group support is only available in Ansible version 1.6 or later.
- - If I(name=all), all programs and program groups will be managed.
+ - The name will be taken as group name when it ends with a colon V(:).
+ - If O(name=all), all programs and program groups will be managed.
required: true
config:
type: path
@@ -53,6 +52,13 @@ options:
- The desired state of program/group.
required: true
choices: [ "present", "started", "stopped", "restarted", "absent", "signalled" ]
+ stop_before_removing:
+ type: bool
+ description:
+ - Use O(stop_before_removing=true) to stop the program/group before removing it
+ required: false
+ default: false
+ version_added: 7.5.0
signal:
type: str
description:
@@ -62,9 +68,10 @@ options:
description:
- path to supervisorctl executable
notes:
- - When C(state) = I(present), the module will call C(supervisorctl reread) then C(supervisorctl add) if the program/group does not exist.
- - When C(state) = I(restarted), the module will call C(supervisorctl update) then call C(supervisorctl restart).
- - When C(state) = I(absent), the module will call C(supervisorctl reread) then C(supervisorctl remove) to remove the target program/group.
+ - When O(state=present), the module will call C(supervisorctl reread) then C(supervisorctl add) if the program/group does not exist.
+ - When O(state=restarted), the module will call C(supervisorctl update) then call C(supervisorctl restart).
+ - When O(state=absent), the module will call C(supervisorctl reread) then C(supervisorctl remove) to remove the target program/group.
+ If the program/group is still running, the action will fail. If you want to stop the program/group before removing, use O(stop_before_removing=true).
requirements: [ "supervisorctl" ]
author:
- "Matt Wright (@mattupstate)"
@@ -121,6 +128,7 @@ def main():
password=dict(type='str', no_log=True),
supervisorctl_path=dict(type='path'),
state=dict(type='str', required=True, choices=['present', 'started', 'restarted', 'stopped', 'absent', 'signalled']),
+ stop_before_removing=dict(type='bool', default=False),
signal=dict(type='str'),
)
@@ -136,6 +144,7 @@ def main():
is_group = True
name = name.rstrip(':')
state = module.params['state']
+ stop_before_removing = module.params.get('stop_before_removing')
config = module.params.get('config')
server_url = module.params.get('server_url')
username = module.params.get('username')
@@ -199,22 +208,27 @@ def main():
matched.append((process_name, status))
return matched
- def take_action_on_processes(processes, status_filter, action, expected_result):
+ def take_action_on_processes(processes, status_filter, action, expected_result, exit_module=True):
to_take_action_on = []
for process_name, status in processes:
if status_filter(status):
to_take_action_on.append(process_name)
if len(to_take_action_on) == 0:
+ if not exit_module:
+ return
module.exit_json(changed=False, name=name, state=state)
if module.check_mode:
+ if not exit_module:
+ return
module.exit_json(changed=True)
for process_name in to_take_action_on:
rc, out, err = run_supervisorctl(action, process_name, check_rc=True)
if '%s: %s' % (process_name, expected_result) not in out:
module.fail_json(msg=out)
- module.exit_json(changed=True, name=name, state=state, affected=to_take_action_on)
+ if exit_module:
+ module.exit_json(changed=True, name=name, state=state, affected=to_take_action_on)
if state == 'restarted':
rc, out, err = run_supervisorctl('update', check_rc=True)
@@ -230,6 +244,9 @@ def main():
if len(processes) == 0:
module.exit_json(changed=False, name=name, state=state)
+ if stop_before_removing:
+ take_action_on_processes(processes, lambda s: s in ('RUNNING', 'STARTING'), 'stop', 'stopped', exit_module=False)
+
if module.check_mode:
module.exit_json(changed=True)
run_supervisorctl('reread', check_rc=True)
diff --git a/ansible_collections/community/general/plugins/modules/svc.py b/ansible_collections/community/general/plugins/modules/svc.py
index bd2eaeb22..b327ddfd6 100644
--- a/ansible_collections/community/general/plugins/modules/svc.py
+++ b/ansible_collections/community/general/plugins/modules/svc.py
@@ -31,11 +31,11 @@ options:
required: true
state:
description:
- - C(Started)/C(stopped) are idempotent actions that will not run
- commands unless necessary. C(restarted) will always bounce the
- svc (svc -t) and C(killed) will always bounce the svc (svc -k).
- C(reloaded) will send a sigusr1 (svc -1).
- C(once) will run a normally downed svc once (svc -o), not really
+ - V(started)/V(stopped) are idempotent actions that will not run
+ commands unless necessary. V(restarted) will always bounce the
+ svc (svc -t) and V(killed) will always bounce the svc (svc -k).
+ V(reloaded) will send a sigusr1 (svc -1).
+ V(once) will run a normally downed svc once (svc -o), not really
an idempotent operation.
type: str
choices: [ killed, once, reloaded, restarted, started, stopped ]
diff --git a/ansible_collections/community/general/plugins/modules/svr4pkg.py b/ansible_collections/community/general/plugins/modules/svr4pkg.py
index e8c410482..db9902c77 100644
--- a/ansible_collections/community/general/plugins/modules/svr4pkg.py
+++ b/ansible_collections/community/general/plugins/modules/svr4pkg.py
@@ -31,14 +31,14 @@ attributes:
options:
name:
description:
- - Package name, e.g. C(SUNWcsr)
+ - Package name, for example V(SUNWcsr).
required: true
type: str
state:
description:
- - Whether to install (C(present)), or remove (C(absent)) a package.
- - If the package is to be installed, then I(src) is required.
+ - Whether to install (V(present)), or remove (V(absent)) a package.
+ - If the package is to be installed, then O(src) is required.
- The SVR4 package system doesn't provide an upgrade operation. You need to uninstall the old, then install the new package.
required: true
choices: ["present", "absent"]
@@ -46,17 +46,17 @@ options:
src:
description:
- - Specifies the location to install the package from. Required when I(state=present).
- - "Can be any path acceptable to the C(pkgadd) command's C(-d) option. e.g.: C(somefile.pkg), C(/dir/with/pkgs), C(http:/server/mypkgs.pkg)."
+ - Specifies the location to install the package from. Required when O(state=present).
+ - "Can be any path acceptable to the C(pkgadd) command's C(-d) option. For example: V(somefile.pkg), V(/dir/with/pkgs), V(http:/server/mypkgs.pkg)."
- If using a file or directory, they must already be accessible by the host. See the M(ansible.builtin.copy) module for a way to get them there.
type: str
proxy:
description:
- - HTTP[s] proxy to be used if I(src) is a URL.
+ - HTTP[s] proxy to be used if O(src) is a URL.
type: str
response_file:
description:
- - Specifies the location of a response file to be used if package expects input on install. (added in Ansible 1.4)
+ - Specifies the location of a response file to be used if package expects input on install.
required: false
type: str
zone:
diff --git a/ansible_collections/community/general/plugins/modules/swdepot.py b/ansible_collections/community/general/plugins/modules/swdepot.py
index c4660c70d..28a8ce314 100644
--- a/ansible_collections/community/general/plugins/modules/swdepot.py
+++ b/ansible_collections/community/general/plugins/modules/swdepot.py
@@ -36,7 +36,7 @@ options:
type: str
state:
description:
- - whether to install (C(present), C(latest)), or remove (C(absent)) a package.
+ - whether to install (V(present), V(latest)), or remove (V(absent)) a package.
required: true
choices: [ 'present', 'latest', 'absent']
type: str
diff --git a/ansible_collections/community/general/plugins/modules/swupd.py b/ansible_collections/community/general/plugins/modules/swupd.py
index efd7ca7c1..16738c8cb 100644
--- a/ansible_collections/community/general/plugins/modules/swupd.py
+++ b/ansible_collections/community/general/plugins/modules/swupd.py
@@ -50,8 +50,8 @@ options:
type: str
state:
description:
- - Indicates the desired (I)bundle state. C(present) ensures the bundle
- is installed while C(absent) ensures the (I)bundle is not installed.
+ - Indicates the desired (I)bundle state. V(present) ensures the bundle
+ is installed while V(absent) ensures the (I)bundle is not installed.
default: present
choices: [present, absent]
type: str
@@ -62,7 +62,7 @@ options:
default: false
url:
description:
- - Overrides both I(contenturl) and I(versionurl).
+ - Overrides both O(contenturl) and O(versionurl).
type: str
verify:
description:
diff --git a/ansible_collections/community/general/plugins/modules/sysrc.py b/ansible_collections/community/general/plugins/modules/sysrc.py
index 9652b629a..6780975d4 100644
--- a/ansible_collections/community/general/plugins/modules/sysrc.py
+++ b/ansible_collections/community/general/plugins/modules/sysrc.py
@@ -33,28 +33,28 @@ options:
required: true
value:
description:
- - The value to set when I(state=present).
- - The value to add when I(state=value_present).
- - The value to remove when I(state=value_absent).
+ - The value to set when O(state=present).
+ - The value to add when O(state=value_present).
+ - The value to remove when O(state=value_absent).
type: str
state:
description:
- - Use I(present) to add the variable.
- - Use I(absent) to remove the variable.
- - Use I(value_present) to add the value to the existing variable.
- - Use I(value_absent) to remove the value from the existing variable.
+ - Use V(present) to add the variable.
+ - Use V(absent) to remove the variable.
+ - Use V(value_present) to add the value to the existing variable.
+ - Use V(value_absent) to remove the value from the existing variable.
type: str
default: "present"
choices: [ absent, present, value_present, value_absent ]
path:
description:
- - Path to file to use instead of C(/etc/rc.conf).
+ - Path to file to use instead of V(/etc/rc.conf).
type: str
default: "/etc/rc.conf"
delim:
description:
- - Delimiter to be used instead of C( ).
- - Only used when I(state=value_present) or I(state=value_absent).
+ - Delimiter to be used instead of V(" ") (space).
+ - Only used when O(state=value_present) or O(state=value_absent).
default: " "
type: str
jail:
@@ -62,7 +62,7 @@ options:
- Name or ID of the jail to operate on.
type: str
notes:
- - The C(name) cannot contain periods as sysrc does not support OID style names.
+ - The O(name) cannot contain periods as sysrc does not support OID style names.
'''
EXAMPLES = r'''
@@ -222,7 +222,7 @@ def main():
# OID style names are not supported
if not re.match('^[a-zA-Z0-9_]+$', name):
module.fail_json(
- msg="Name may only contain alpha-numeric and underscore characters"
+ msg="Name may only contain alphanumeric and underscore characters"
)
value = module.params.pop('value')
diff --git a/ansible_collections/community/general/plugins/modules/sysupgrade.py b/ansible_collections/community/general/plugins/modules/sysupgrade.py
index ac80e0196..639fa345a 100644
--- a/ansible_collections/community/general/plugins/modules/sysupgrade.py
+++ b/ansible_collections/community/general/plugins/modules/sysupgrade.py
@@ -43,7 +43,7 @@ options:
fetch_only:
description:
- Fetch and verify files and create /bsd.upgrade but do not reboot.
- - Set to C(false) if you want sysupgrade to reboot. This will cause Ansible to error, as it expects the module to exit gracefully. See the examples.
+ - Set to V(false) if you want sysupgrade to reboot. This will cause Ansible to error, as it expects the module to exit gracefully. See the examples.
default: true
type: bool
installurl:
diff --git a/ansible_collections/community/general/plugins/modules/telegram.py b/ansible_collections/community/general/plugins/modules/telegram.py
index d13e90fd5..963c66353 100644
--- a/ansible_collections/community/general/plugins/modules/telegram.py
+++ b/ansible_collections/community/general/plugins/modules/telegram.py
@@ -20,7 +20,7 @@ short_description: Send notifications via telegram
description:
- Send notifications via telegram bot, to a verified group or user.
- - Also, the user may try to use any other telegram bot API method, if you specify I(api_method) argument.
+ - Also, the user may try to use any other telegram bot API method, if you specify O(api_method) argument.
notes:
- You will require a telegram account and create telegram bot to use this module.
extends_documentation_fragment:
@@ -47,7 +47,7 @@ options:
type: dict
description:
- Any parameters for the method.
- - For reference to default method, C(SendMessage), see U(https://core.telegram.org/bots/api#sendmessage).
+ - For reference to default method, V(SendMessage), see U(https://core.telegram.org/bots/api#sendmessage).
version_added: 2.0.0
'''
diff --git a/ansible_collections/community/general/plugins/modules/terraform.py b/ansible_collections/community/general/plugins/modules/terraform.py
index f9f809220..5906657c6 100644
--- a/ansible_collections/community/general/plugins/modules/terraform.py
+++ b/ansible_collections/community/general/plugins/modules/terraform.py
@@ -21,7 +21,8 @@ attributes:
check_mode:
support: full
diff_mode:
- support: none
+ support: full
+ version_added: 8.3.0
options:
state:
choices: ['planned', 'present', 'absent']
@@ -55,7 +56,7 @@ options:
version_added: 3.0.0
workspace:
description:
- - The terraform workspace to work with. This sets the C(TF_WORKSPACE) environmental variable
+ - The terraform workspace to work with. This sets the E(TF_WORKSPACE) environmental variable
that is used to override workspace selection. For more information about workspaces
have a look at U(https://developer.hashicorp.com/terraform/language/state/workspaces).
type: str
@@ -83,7 +84,6 @@ options:
description:
- The path to a variables file for Terraform to fill into the TF
configurations. This can accept a list of paths to multiple variables files.
- - Up until Ansible 2.9, this option was usable as I(variables_file).
type: list
elements: path
aliases: [ 'variables_file' ]
@@ -91,18 +91,18 @@ options:
description:
- A group of key-values pairs to override template variables or those in variables files.
By default, only string and number values are allowed, which are passed on unquoted.
- - Support complex variable structures (lists, dictionaries, numbers, and booleans) to reflect terraform variable syntax when I(complex_vars=true).
+ - Support complex variable structures (lists, dictionaries, numbers, and booleans) to reflect terraform variable syntax when O(complex_vars=true).
- Ansible integers or floats are mapped to terraform numbers.
- Ansible strings are mapped to terraform strings.
- Ansible dictionaries are mapped to terraform objects.
- Ansible lists are mapped to terraform lists.
- Ansible booleans are mapped to terraform booleans.
- - "B(Note) passwords passed as variables will be visible in the log output. Make sure to use I(no_log=true) in production!"
+ - "B(Note) passwords passed as variables will be visible in the log output. Make sure to use C(no_log=true) in production!"
type: dict
complex_vars:
description:
- Enable/disable capability to handle complex variable structures for C(terraform).
- - If C(true) the I(variables) also accepts dictionaries, lists, and booleans to be passed to C(terraform).
+ - If V(true) the O(variables) also accepts dictionaries, lists, and booleans to be passed to C(terraform).
Strings that are passed are correctly quoted.
- When disabled, supports only simple variables (strings, integers, and floats), and passes them on unquoted.
type: bool
@@ -135,7 +135,7 @@ options:
type: bool
overwrite_init:
description:
- - Run init even if C(.terraform/terraform.tfstate) already exists in I(project_path).
+ - Run init even if C(.terraform/terraform.tfstate) already exists in O(project_path).
default: true
type: bool
version_added: '3.2.0'
@@ -165,7 +165,7 @@ options:
check_destroy:
description:
- Apply only when no resources are destroyed. Note that this only prevents "destroy" actions,
- but not "destroy and re-create" actions. This option is ignored when I(state=absent).
+ but not "destroy and re-create" actions. This option is ignored when O(state=absent).
type: bool
default: false
version_added: '3.3.0'
@@ -251,7 +251,7 @@ EXAMPLES = """
RETURN = """
outputs:
type: complex
- description: A dictionary of all the TF outputs by their assigned name. Use C(.outputs.MyOutputName.value) to access the value.
+ description: A dictionary of all the TF outputs by their assigned name. Use RV(ignore:outputs.MyOutputName.value) to access the value.
returned: on success
sample: '{"bukkit_arn": {"sensitive": false, "type": "string", "value": "arn:aws:s3:::tf-test-bukkit"}'
contains:
@@ -325,7 +325,7 @@ def init_plugins(bin_path, project_path, backend_config, backend_config_files, i
for key, val in backend_config.items():
command.extend([
'-backend-config',
- shlex_quote('{0}={1}'.format(key, val))
+ '{0}={1}'.format(key, val)
])
if backend_config_files:
for f in backend_config_files:
@@ -376,7 +376,7 @@ def remove_workspace(bin_path, project_path, workspace):
_workspace_cmd(bin_path, project_path, 'delete', workspace)
-def build_plan(command, project_path, variables_args, state_file, targets, state, apply_args, plan_path=None):
+def build_plan(command, project_path, variables_args, state_file, targets, state, args, plan_path=None):
if plan_path is None:
f, plan_path = tempfile.mkstemp(suffix='.tfplan')
@@ -389,11 +389,15 @@ def build_plan(command, project_path, variables_args, state_file, targets, state
plan_command.append(c)
if state == "present":
- for a in apply_args:
+ for a in args:
local_command.remove(a)
for c in local_command[1:]:
plan_command.append(c)
+ if state == "absent":
+ for a in args:
+ plan_command.append(a)
+
plan_command.extend(['-input=false', '-no-color', '-detailed-exitcode', '-out', plan_path])
for t in targets:
@@ -429,6 +433,49 @@ def build_plan(command, project_path, variables_args, state_file, targets, state
))
+def get_diff(diff_output):
+ def get_tf_resource_address(e):
+ return e['resource']
+
+ diff_json_output = json.loads(diff_output)
+
+ # Ignore diff if resource_changes does not exists in tfplan
+ if 'resource_changes' in diff_json_output:
+ tf_reosource_changes = diff_json_output['resource_changes']
+ else:
+ module.warn("Cannot find resource_changes in terraform plan, diff/check ignored")
+ return False, {}
+
+ diff_after = []
+ diff_before = []
+ changed = False
+ for item in tf_reosource_changes:
+ item_change = item['change']
+ tf_before_state = {'resource': item['address'], 'change': item['change']['before']}
+ tf_after_state = {'resource': item['address'], 'change': item['change']['after']}
+
+ if item_change['actions'] == ['update'] or item_change['actions'] == ['delete', 'create']:
+ diff_before.append(tf_before_state)
+ diff_after.append(tf_after_state)
+ changed = True
+
+ if item_change['actions'] == ['delete']:
+ diff_before.append(tf_before_state)
+ changed = True
+
+ if item_change['actions'] == ['create']:
+ diff_after.append(tf_after_state)
+ changed = True
+
+ diff_before.sort(key=get_tf_resource_address)
+ diff_after.sort(key=get_tf_resource_address)
+
+ return changed, dict(
+ before=({'data': diff_before}),
+ after=({'data': diff_after}),
+ )
+
+
def main():
global module
module = AnsibleModule(
@@ -514,7 +561,7 @@ def main():
def format_args(vars):
if isinstance(vars, str):
- return '"{string}"'.format(string=vars.replace('\\', '\\\\').replace('"', '\\"'))
+ return '"{string}"'.format(string=vars.replace('\\', '\\\\').replace('"', '\\"')).replace('\n', '\\n')
elif isinstance(vars, bool):
if vars:
return 'true'
@@ -620,6 +667,23 @@ def main():
"Consider switching the 'check_destroy' to false to suppress this error")
command.append(plan_file)
+ result_diff = dict()
+ if module._diff or module.check_mode:
+ if state == 'absent':
+ plan_absent_args = ['-destroy']
+ plan_file, needs_application, out, err, command = build_plan(command, project_path, variables_args, state_file,
+ module.params.get('targets'), state, plan_absent_args, plan_file)
+ diff_command = [command[0], 'show', '-json', plan_file]
+ rc, diff_output, err = module.run_command(diff_command, check_rc=False, cwd=project_path)
+ changed, result_diff = get_diff(diff_output)
+ if rc != 0:
+ if workspace_ctx["current"] != workspace:
+ select_workspace(command[0], project_path, workspace_ctx["current"])
+ module.fail_json(msg=err.rstrip(), rc=rc, stdout=out,
+ stdout_lines=out.splitlines(), stderr=err,
+ stderr_lines=err.splitlines(),
+ cmd=' '.join(command))
+
if needs_application and not module.check_mode and state != 'planned':
rc, out, err = module.run_command(command, check_rc=False, cwd=project_path)
if rc != 0:
@@ -652,7 +716,18 @@ def main():
if state == 'absent' and workspace != 'default' and purge_workspace is True:
remove_workspace(command[0], project_path, workspace)
- module.exit_json(changed=changed, state=state, workspace=workspace, outputs=outputs, stdout=out, stderr=err, command=' '.join(command))
+ result = {
+ 'state': state,
+ 'workspace': workspace,
+ 'outputs': outputs,
+ 'stdout': out,
+ 'stderr': err,
+ 'command': ' '.join(command),
+ 'changed': changed,
+ 'diff': result_diff,
+ }
+
+ module.exit_json(**result)
if __name__ == '__main__':
diff --git a/ansible_collections/community/general/plugins/modules/timezone.py b/ansible_collections/community/general/plugins/modules/timezone.py
index 05849e4bb..e027290e8 100644
--- a/ansible_collections/community/general/plugins/modules/timezone.py
+++ b/ansible_collections/community/general/plugins/modules/timezone.py
@@ -22,9 +22,6 @@ description:
On AIX, C(chtz) is used.
- Make sure that the zoneinfo files are installed with the appropriate OS package, like C(tzdata) (usually always installed,
when not using a minimal installation like Alpine Linux).
- - As of Ansible 2.3 support was added for SmartOS and BSDs.
- - As of Ansible 2.4 support was added for macOS.
- - As of Ansible 2.9 support was added for AIX 6.1+
- Windows and HPUX are not supported, please let us know if you find any other OS/distro in which this fails.
extends_documentation_fragment:
- community.general.attributes
@@ -53,8 +50,9 @@ options:
choices: [ local, UTC ]
notes:
- On SmartOS the C(sm-set-timezone) utility (part of the smtools package) is required to set the zone timezone
- - On AIX only Olson/tz database timezones are useable (POSIX is not supported).
- - An OS reboot is also required on AIX for the new timezone setting to take effect.
+ - On AIX only Olson/tz database timezones are usable (POSIX is not supported).
+ An OS reboot is also required on AIX for the new timezone setting to take effect.
+ Note that AIX 6.1+ is needed (OS level 61 or newer).
author:
- Shinichi TAMURA (@tmshn)
- Jasper Lievisse Adriaanse (@jasperla)
@@ -447,7 +445,7 @@ class NosystemdTimezone(Timezone):
filename: The name of the file to edit.
regexp: The regular expression to search with.
value: The line which will be inserted.
- key: For what key the file is being editted.
+ key: For what key the file is being edited.
"""
# Read the file
try:
@@ -725,7 +723,7 @@ class BSDTimezone(Timezone):
localtime_file = '/etc/localtime'
# Strategy 1:
- # If /etc/localtime does not exist, assum the timezone is UTC.
+ # If /etc/localtime does not exist, assume the timezone is UTC.
if not os.path.exists(localtime_file):
self.module.warn('Could not read /etc/localtime. Assuming UTC.')
return 'UTC'
diff --git a/ansible_collections/community/general/plugins/modules/udm_dns_record.py b/ansible_collections/community/general/plugins/modules/udm_dns_record.py
index 849c84a2d..99fe10c63 100644
--- a/ansible_collections/community/general/plugins/modules/udm_dns_record.py
+++ b/ansible_collections/community/general/plugins/modules/udm_dns_record.py
@@ -21,7 +21,7 @@ description:
It uses the python API of the UCS to create a new object or edit it."
requirements:
- Univention
- - ipaddress (for I(type=ptr_record))
+ - ipaddress (for O(type=ptr_record))
extends_documentation_fragment:
- community.general.attributes
attributes:
@@ -48,21 +48,21 @@ options:
required: true
description:
- Corresponding DNS zone for this record, e.g. example.com.
- - For PTR records this has to be the full reverse zone (for example C(1.1.192.in-addr.arpa)).
+ - For PTR records this has to be the full reverse zone (for example V(1.1.192.in-addr.arpa)).
type:
type: str
required: true
description:
- - "Define the record type. C(host_record) is a A or AAAA record,
- C(alias) is a CNAME, C(ptr_record) is a PTR record, C(srv_record)
- is a SRV record and C(txt_record) is a TXT record."
- - "The available choices are: C(host_record), C(alias), C(ptr_record), C(srv_record), C(txt_record)."
+ - "Define the record type. V(host_record) is a A or AAAA record,
+ V(alias) is a CNAME, V(ptr_record) is a PTR record, V(srv_record)
+ is a SRV record and V(txt_record) is a TXT record."
+ - "The available choices are: V(host_record), V(alias), V(ptr_record), V(srv_record), V(txt_record)."
data:
type: dict
default: {}
description:
- - "Additional data for this record, e.g. ['a': '192.0.2.1'].
- Required if I(state=present)."
+ - "Additional data for this record, for example V({'a': '192.0.2.1'})."
+ - Required if O(state=present).
'''
diff --git a/ansible_collections/community/general/plugins/modules/udm_dns_zone.py b/ansible_collections/community/general/plugins/modules/udm_dns_zone.py
index 19f24fa1c..387d5cc45 100644
--- a/ansible_collections/community/general/plugins/modules/udm_dns_zone.py
+++ b/ansible_collections/community/general/plugins/modules/udm_dns_zone.py
@@ -38,26 +38,26 @@ options:
required: true
description:
- Define if the zone is a forward or reverse DNS zone.
- - "The available choices are: C(forward_zone), C(reverse_zone)."
+ - "The available choices are: V(forward_zone), V(reverse_zone)."
zone:
type: str
required: true
description:
- - DNS zone name, e.g. C(example.com).
+ - DNS zone name, for example V(example.com).
aliases: [name]
nameserver:
type: list
elements: str
default: []
description:
- - List of appropriate name servers. Required if I(state=present).
+ - List of appropriate name servers. Required if O(state=present).
interfaces:
type: list
elements: str
default: []
description:
- List of interface IP addresses, on which the server should
- response this zone. Required if I(state=present).
+ response this zone. Required if O(state=present).
refresh:
type: int
diff --git a/ansible_collections/community/general/plugins/modules/udm_share.py b/ansible_collections/community/general/plugins/modules/udm_share.py
index 274391335..8ae243b3d 100644
--- a/ansible_collections/community/general/plugins/modules/udm_share.py
+++ b/ansible_collections/community/general/plugins/modules/udm_share.py
@@ -42,18 +42,17 @@ options:
host:
required: false
description:
- - Host FQDN (server which provides the share), e.g. C({{
- ansible_fqdn }}). Required if I(state=present).
+ - Host FQDN (server which provides the share), for example V({{ ansible_fqdn }}). Required if O(state=present).
type: str
path:
required: false
description:
- - Directory on the providing server, e.g. C(/home). Required if I(state=present).
+ - Directory on the providing server, for example V(/home). Required if O(state=present).
type: path
sambaName:
required: false
description:
- - Windows name. Required if I(state=present).
+ - Windows name. Required if O(state=present).
type: str
aliases: [ samba_name ]
ou:
diff --git a/ansible_collections/community/general/plugins/modules/udm_user.py b/ansible_collections/community/general/plugins/modules/udm_user.py
index 05c5ad359..dcbf0ec85 100644
--- a/ansible_collections/community/general/plugins/modules/udm_user.py
+++ b/ansible_collections/community/general/plugins/modules/udm_user.py
@@ -42,15 +42,15 @@ options:
type: str
firstname:
description:
- - First name. Required if I(state=present).
+ - First name. Required if O(state=present).
type: str
lastname:
description:
- - Last name. Required if I(state=present).
+ - Last name. Required if O(state=present).
type: str
password:
description:
- - Password. Required if I(state=present).
+ - Password. Required if O(state=present).
type: str
birthday:
description:
@@ -103,13 +103,13 @@ options:
description:
- "POSIX groups, the LDAP DNs of the groups will be found with the
LDAP filter for each group as $GROUP:
- C((&(objectClass=posixGroup)(cn=$GROUP)))."
+ V((&(objectClass=posixGroup\\)(cn=$GROUP\\)\\))."
type: list
elements: str
home_share:
description:
- "Home NFS share. Must be a LDAP DN, e.g.
- C(cn=home,cn=shares,ou=school,dc=example,dc=com)."
+ V(cn=home,cn=shares,ou=school,dc=example,dc=com)."
aliases: [ homeShare ]
type: str
home_share_path:
@@ -126,7 +126,7 @@ options:
elements: str
homedrive:
description:
- - Windows home drive, e.g. C("H:").
+ - Windows home drive, for example V("H:").
type: str
mail_alternative_address:
default: []
@@ -189,7 +189,7 @@ options:
primary_group:
description:
- Primary group. This must be the group LDAP DN.
- - If not specified, it defaults to C(cn=Domain Users,cn=groups,$LDAP_BASE_DN).
+ - If not specified, it defaults to V(cn=Domain Users,cn=groups,$LDAP_BASE_DN).
aliases: [ primaryGroup ]
type: str
profilepath:
@@ -224,7 +224,7 @@ options:
default: []
sambahome:
description:
- - Windows home path, e.g. C('\\$FQDN\$USERNAME').
+ - Windows home path, for example V('\\\\$FQDN\\$USERNAME').
type: str
scriptpath:
description:
@@ -253,7 +253,7 @@ options:
type: str
title:
description:
- - Title, e.g. C(Prof.).
+ - Title, for example V(Prof.).
type: str
unixhome:
description:
@@ -262,33 +262,33 @@ options:
type: str
userexpiry:
description:
- - Account expiry date, e.g. C(1999-12-31).
+ - Account expiry date, for example V(1999-12-31).
- If not specified, it defaults to the current day plus one year.
type: str
position:
default: ''
description:
- "Define the whole position of users object inside the LDAP tree,
- e.g. C(cn=employee,cn=users,ou=school,dc=example,dc=com)."
+ for example V(cn=employee,cn=users,ou=school,dc=example,dc=com)."
type: str
update_password:
default: always
choices: [ always, on_create ]
description:
- - "C(always) will update passwords if they differ.
- C(on_create) will only set the password for newly created users."
+ - "V(always) will update passwords if they differ.
+ V(on_create) will only set the password for newly created users."
type: str
ou:
default: ''
description:
- - "Organizational Unit inside the LDAP Base DN, e.g. C(school) for
+ - "Organizational Unit inside the LDAP Base DN, for example V(school) for
LDAP OU C(ou=school,dc=example,dc=com)."
type: str
subpath:
default: 'cn=users'
description:
- - "LDAP subpath inside the organizational unit, e.g.
- C(cn=teachers,cn=users) for LDAP container
+ - "LDAP subpath inside the organizational unit, for example
+ V(cn=teachers,cn=users) for LDAP container
C(cn=teachers,cn=users,dc=example,dc=com)."
type: str
'''
@@ -302,7 +302,7 @@ EXAMPLES = '''
firstname: Foo
lastname: Bar
-- name: Create a user with the DN C(uid=foo,cn=teachers,cn=users,ou=school,dc=school,dc=example,dc=com)
+- name: Create a user with the DN uid=foo,cn=teachers,cn=users,ou=school,dc=school,dc=example,dc=com
community.general.udm_user:
name: foo
password: secure_password
@@ -312,7 +312,7 @@ EXAMPLES = '''
subpath: 'cn=teachers,cn=users'
# or define the position
-- name: Create a user with the DN C(uid=foo,cn=teachers,cn=users,ou=school,dc=school,dc=example,dc=com)
+- name: Create a user with the DN uid=foo,cn=teachers,cn=users,ou=school,dc=school,dc=example,dc=com
community.general.udm_user:
name: foo
password: secure_password
diff --git a/ansible_collections/community/general/plugins/modules/ufw.py b/ansible_collections/community/general/plugins/modules/ufw.py
index 45c98fd63..5d187793b 100644
--- a/ansible_collections/community/general/plugins/modules/ufw.py
+++ b/ansible_collections/community/general/plugins/modules/ufw.py
@@ -35,10 +35,10 @@ attributes:
options:
state:
description:
- - C(enabled) reloads firewall and enables firewall on boot.
- - C(disabled) unloads firewall and disables firewall on boot.
- - C(reloaded) reloads firewall.
- - C(reset) disables and resets firewall to installation defaults.
+ - V(enabled) reloads firewall and enables firewall on boot.
+ - V(disabled) unloads firewall and disables firewall on boot.
+ - V(reloaded) reloads firewall.
+ - V(reset) disables and resets firewall to installation defaults.
type: str
choices: [ disabled, enabled, reloaded, reset ]
default:
@@ -50,7 +50,7 @@ options:
direction:
description:
- Select direction for a rule or default policy command. Mutually
- exclusive with I(interface_in) and I(interface_out).
+ exclusive with O(interface_in) and O(interface_out).
type: str
choices: [ in, incoming, out, outgoing, routed ]
logging:
@@ -62,24 +62,24 @@ options:
description:
- Insert the corresponding rule as rule number NUM.
- Note that ufw numbers rules starting with 1.
- - If I(delete=true) and a value is provided for I(insert),
- then I(insert) is ignored.
+ - If O(delete=true) and a value is provided for O(insert),
+ then O(insert) is ignored.
type: int
insert_relative_to:
description:
- - Allows to interpret the index in I(insert) relative to a position.
- - C(zero) interprets the rule number as an absolute index (i.e. 1 is
+ - Allows to interpret the index in O(insert) relative to a position.
+ - V(zero) interprets the rule number as an absolute index (i.e. 1 is
the first rule).
- - C(first-ipv4) interprets the rule number relative to the index of the
+ - V(first-ipv4) interprets the rule number relative to the index of the
first IPv4 rule, or relative to the position where the first IPv4 rule
would be if there is currently none.
- - C(last-ipv4) interprets the rule number relative to the index of the
+ - V(last-ipv4) interprets the rule number relative to the index of the
last IPv4 rule, or relative to the position where the last IPv4 rule
would be if there is currently none.
- - C(first-ipv6) interprets the rule number relative to the index of the
+ - V(first-ipv6) interprets the rule number relative to the index of the
first IPv6 rule, or relative to the position where the first IPv6 rule
would be if there is currently none.
- - C(last-ipv6) interprets the rule number relative to the index of the
+ - V(last-ipv6) interprets the rule number relative to the index of the
last IPv6 rule, or relative to the position where the last IPv6 rule
would be if there is currently none.
type: str
@@ -130,32 +130,32 @@ options:
delete:
description:
- Delete rule.
- - If I(delete=true) and a value is provided for I(insert),
- then I(insert) is ignored.
+ - If O(delete=true) and a value is provided for O(insert),
+ then O(insert) is ignored.
type: bool
default: false
interface:
description:
- Specify interface for the rule. The direction (in or out) used
- for the interface depends on the value of I(direction). See
- I(interface_in) and I(interface_out) for routed rules that needs
+ for the interface depends on the value of O(direction). See
+ O(interface_in) and O(interface_out) for routed rules that needs
to supply both an input and output interface. Mutually
- exclusive with I(interface_in) and I(interface_out).
+ exclusive with O(interface_in) and O(interface_out).
type: str
aliases: [ if ]
interface_in:
description:
- Specify input interface for the rule. This is mutually
- exclusive with I(direction) and I(interface). However, it is
- compatible with I(interface_out) for routed rules.
+ exclusive with O(direction) and O(interface). However, it is
+ compatible with O(interface_out) for routed rules.
type: str
aliases: [ if_in ]
version_added: '0.2.0'
interface_out:
description:
- Specify output interface for the rule. This is mutually
- exclusive with I(direction) and I(interface). However, it is
- compatible with I(interface_in) for routed rules.
+ exclusive with O(direction) and O(interface). However, it is
+ compatible with O(interface_in) for routed rules.
type: str
aliases: [ if_out ]
version_added: '0.2.0'
diff --git a/ansible_collections/community/general/plugins/modules/urpmi.py b/ansible_collections/community/general/plugins/modules/urpmi.py
index 34e099e4d..75c0af90f 100644
--- a/ansible_collections/community/general/plugins/modules/urpmi.py
+++ b/ansible_collections/community/general/plugins/modules/urpmi.py
@@ -16,7 +16,7 @@ DOCUMENTATION = '''
module: urpmi
short_description: Urpmi manager
description:
- - Manages packages with I(urpmi) (such as for Mageia or Mandriva)
+ - Manages packages with C(urpmi) (such as for Mageia or Mandriva)
extends_documentation_fragment:
- community.general.attributes
attributes:
@@ -45,19 +45,19 @@ options:
default: false
no_recommends:
description:
- - Corresponds to the C(--no-recommends) option for I(urpmi).
+ - Corresponds to the C(--no-recommends) option for C(urpmi).
type: bool
default: true
force:
description:
- Assume "yes" is the answer to any question urpmi has to ask.
- Corresponds to the C(--force) option for I(urpmi).
+ Corresponds to the C(--force) option for C(urpmi).
type: bool
default: true
root:
description:
- Specifies an alternative install root, relative to which all packages will be installed.
- Corresponds to the C(--root) option for I(urpmi).
+ Corresponds to the C(--root) option for C(urpmi).
aliases: [ installroot ]
type: str
author:
diff --git a/ansible_collections/community/general/plugins/modules/usb_facts.py b/ansible_collections/community/general/plugins/modules/usb_facts.py
new file mode 100644
index 000000000..340c71ee5
--- /dev/null
+++ b/ansible_collections/community/general/plugins/modules/usb_facts.py
@@ -0,0 +1,113 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2024, Max Maxopoly <max@dermax.org>
+#
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+
+DOCUMENTATION = '''
+---
+module: usb_facts
+short_description: Allows listing information about USB devices
+version_added: 8.5.0
+description:
+ - Allows retrieving information about available USB devices through C(lsusb).
+author:
+ - Max Maxopoly (@maxopoly)
+extends_documentation_fragment:
+ - community.general.attributes
+ - community.general.attributes.facts
+ - community.general.attributes.facts_module
+requirements:
+ - lsusb binary on PATH (usually installed through the package usbutils and preinstalled on many systems)
+'''
+
+EXAMPLES = '''
+- name: Get information about USB devices
+ community.general.usb_facts:
+
+- name: Print information about USB devices
+ ansible.builtin.debug:
+ msg: "On bus {{ item.bus }} device {{ item.device }} with id {{ item.id }} is {{ item.name }}"
+ loop: "{{ ansible_facts.usb_devices }}"
+'''
+
+RETURN = r'''
+ansible_facts:
+ description: Dictionary containing details of connected USB devices.
+ returned: always
+ type: dict
+ contains:
+ usb_devices:
+ description: A list of USB devices available.
+ returned: always
+ type: list
+ elements: dict
+ contains:
+ bus:
+ description: The bus the usb device is connected to.
+ returned: always
+ type: str
+ sample: "001"
+ device:
+ description: The device number occupied on the bus.
+ returned: always
+ type: str
+ sample: "002"
+ id:
+ description: ID of the USB device.
+ returned: always
+ type: str
+ sample: "1d6b:0002"
+ name:
+ description: Human readable name of the device.
+ returned: always
+ type: str
+ sample: Linux Foundation 2.0 root hub
+'''
+
+import re
+from ansible.module_utils.basic import AnsibleModule
+
+
+def parse_lsusb(module, lsusb_path):
+ rc, stdout, stderr = module.run_command(lsusb_path, check_rc=True)
+ regex = re.compile(r'^Bus (\d{3}) Device (\d{3}): ID ([0-9a-f]{4}:[0-9a-f]{4}) (.*)$')
+ usb_devices = []
+ for line in stdout.splitlines():
+ match = re.match(regex, line)
+ if not match:
+ module.fail_json(msg="failed to parse unknown lsusb output %s" % (line), stdout=stdout, stderr=stderr)
+ current_device = {
+ 'bus': match.group(1),
+ 'device': match.group(2),
+ 'id': match.group(3),
+ 'name': match.group(4)
+ }
+ usb_devices.append(current_device)
+ return_value = {
+ "usb_devices": usb_devices
+ }
+ module.exit_json(msg="parsed %s USB devices" % (len(usb_devices)), stdout=stdout, stderr=stderr, ansible_facts=return_value)
+
+
+def main():
+ module = AnsibleModule(
+ {},
+ supports_check_mode=True
+ )
+
+ # Set LANG env since we parse stdout
+ module.run_command_environ_update = dict(LANGUAGE='C', LC_ALL='C')
+
+ lsusb_path = module.get_bin_path('lsusb', required=True)
+ parse_lsusb(module, lsusb_path)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/general/plugins/modules/utm_proxy_location.py b/ansible_collections/community/general/plugins/modules/utm_proxy_location.py
index c22de7b92..736f564d5 100644
--- a/ansible_collections/community/general/plugins/modules/utm_proxy_location.py
+++ b/ansible_collections/community/general/plugins/modules/utm_proxy_location.py
@@ -170,7 +170,7 @@ result:
description: The list of the denied network names
type: list
hot_standby:
- description: Use hot standy
+ description: Use hot standby
type: bool
path:
description: Path name
diff --git a/ansible_collections/community/general/plugins/modules/utm_proxy_location_info.py b/ansible_collections/community/general/plugins/modules/utm_proxy_location_info.py
index 58a32107b..4e4ba9b13 100644
--- a/ansible_collections/community/general/plugins/modules/utm_proxy_location_info.py
+++ b/ansible_collections/community/general/plugins/modules/utm_proxy_location_info.py
@@ -88,7 +88,7 @@ result:
description: The list of the denied network names
type: list
hot_standby:
- description: Use hot standy
+ description: Use hot standby
type: bool
path:
description: Path name
diff --git a/ansible_collections/community/general/plugins/modules/vdo.py b/ansible_collections/community/general/plugins/modules/vdo.py
index f1ea40e2e..8b0e74596 100644
--- a/ansible_collections/community/general/plugins/modules/vdo.py
+++ b/ansible_collections/community/general/plugins/modules/vdo.py
@@ -57,7 +57,7 @@ options:
activated:
description:
- The "activate" status for a VDO volume. If this is set
- to C(false), the VDO volume cannot be started, and it will
+ to V(false), the VDO volume cannot be started, and it will
not start on system startup. However, on initial
creation, a VDO volume with "activated" set to "off"
will be running, until stopped. This is the default
diff --git a/ansible_collections/community/general/plugins/modules/vertica_info.py b/ansible_collections/community/general/plugins/modules/vertica_info.py
index 3106be3b3..93ccc6844 100644
--- a/ansible_collections/community/general/plugins/modules/vertica_info.py
+++ b/ansible_collections/community/general/plugins/modules/vertica_info.py
@@ -15,8 +15,6 @@ module: vertica_info
short_description: Gathers Vertica database facts
description:
- Gathers Vertica database information.
- - This module was called C(vertica_facts) before Ansible 2.9, returning C(ansible_facts).
- Note that the M(community.general.vertica_info) module no longer returns C(ansible_facts)!
extends_documentation_fragment:
- community.general.attributes
- community.general.attributes.info_module
diff --git a/ansible_collections/community/general/plugins/modules/vertica_role.py b/ansible_collections/community/general/plugins/modules/vertica_role.py
index 704594a12..a1ef40c7a 100644
--- a/ansible_collections/community/general/plugins/modules/vertica_role.py
+++ b/ansible_collections/community/general/plugins/modules/vertica_role.py
@@ -36,7 +36,7 @@ options:
type: str
state:
description:
- - Whether to create C(present), drop C(absent) or lock C(locked) a role.
+ - Whether to create V(present), drop V(absent) or lock V(locked) a role.
choices: ['present', 'absent']
default: present
type: str
diff --git a/ansible_collections/community/general/plugins/modules/vertica_schema.py b/ansible_collections/community/general/plugins/modules/vertica_schema.py
index 01f8f721e..95e434ef3 100644
--- a/ansible_collections/community/general/plugins/modules/vertica_schema.py
+++ b/ansible_collections/community/general/plugins/modules/vertica_schema.py
@@ -50,7 +50,7 @@ options:
type: str
state:
description:
- - Whether to create C(present), or drop C(absent) a schema.
+ - Whether to create V(present), or drop V(absent) a schema.
default: present
choices: ['present', 'absent']
type: str
diff --git a/ansible_collections/community/general/plugins/modules/vertica_user.py b/ansible_collections/community/general/plugins/modules/vertica_user.py
index a6a5b5951..7a62bec44 100644
--- a/ansible_collections/community/general/plugins/modules/vertica_user.py
+++ b/ansible_collections/community/general/plugins/modules/vertica_user.py
@@ -8,7 +8,7 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type
-DOCUMENTATION = '''
+DOCUMENTATION = r'''
---
module: vertica_user
short_description: Adds or removes Vertica database users and assigns roles
@@ -44,7 +44,7 @@ options:
- The user's password encrypted by the MD5 algorithm.
- The password must be generated with the format C("md5" + md5[password + username]),
resulting in a total of 35 characters. An easy way to do this is by querying
- the Vertica database with select 'md5'||md5('<user_password><user_name>').
+ the Vertica database with select V('md5'||md5('<user_password><user_name>'\)).
type: str
expired:
description:
@@ -53,7 +53,7 @@ options:
ldap:
description:
- Set to true if users are authenticated via LDAP.
- - The user will be created with password expired and set to I($ldap$).
+ - The user will be created with password expired and set to V($ldap$).
type: bool
roles:
description:
@@ -62,7 +62,7 @@ options:
type: str
state:
description:
- - Whether to create C(present), drop C(absent) or lock C(locked) a user.
+ - Whether to create (V(present)), drop (V(absent)), or lock (V(locked)) a user.
choices: ['present', 'absent', 'locked']
default: present
type: str
diff --git a/ansible_collections/community/general/plugins/modules/vmadm.py b/ansible_collections/community/general/plugins/modules/vmadm.py
index 56ade17e4..bfe614837 100644
--- a/ansible_collections/community/general/plugins/modules/vmadm.py
+++ b/ansible_collections/community/general/plugins/modules/vmadm.py
@@ -39,7 +39,7 @@ options:
choices: [ joyent, joyent-minimal, lx, kvm, bhyve ]
default: joyent
description:
- - Type of virtual machine. The C(bhyve) option was added in community.general 0.2.0.
+ - Type of virtual machine. The V(bhyve) option was added in community.general 0.2.0.
type: str
boot:
required: false
@@ -50,7 +50,7 @@ options:
required: false
description:
- Sets a limit on the amount of CPU time that can be used by a VM.
- Use C(0) for no cap.
+ Use V(0) for no cap.
type: int
cpu_shares:
required: false
@@ -95,7 +95,7 @@ options:
docker:
required: false
description:
- - Docker images need this flag enabled along with the I(brand) set to C(lx).
+ - Docker images need this flag enabled along with the O(brand) set to C(lx).
type: bool
filesystems:
required: false
@@ -147,8 +147,8 @@ options:
internal_metadata_namespace:
required: false
description:
- - List of namespaces to be set as I(internal_metadata-only); these namespaces
- will come from I(internal_metadata) rather than I(customer_metadata).
+ - List of namespaces to be set as C(internal_metadata-only); these namespaces
+ will come from O(internal_metadata) rather than O(customer_metadata).
type: str
kernel_version:
required: false
@@ -164,7 +164,7 @@ options:
required: false
description:
- Resolvers in C(/etc/resolv.conf) will be updated when updating
- the I(resolvers) property.
+ the O(resolvers) property.
type: bool
max_locked_memory:
required: false
@@ -263,11 +263,11 @@ options:
choices: [ present, running, absent, deleted, stopped, created, restarted, rebooted ]
default: running
description:
- - States for the VM to be in. Please note that C(present), C(stopped) and C(restarted)
- operate on a VM that is currently provisioned. C(present) means that the VM will be
- created if it was absent, and that it will be in a running state. C(absent) will
+ - States for the VM to be in. Please note that V(present), V(stopped) and V(restarted)
+ operate on a VM that is currently provisioned. V(present) means that the VM will be
+ created if it was absent, and that it will be in a running state. V(absent) will
shutdown the zone before removing it.
- C(stopped) means the zone will be created if it doesn't exist already, before shutting
+ V(stopped) means the zone will be created if it does not exist already, before shutting
it down.
type: str
tmpfs:
@@ -278,7 +278,7 @@ options:
uuid:
required: false
description:
- - UUID of the VM. Can either be a full UUID or C(*) for all VMs.
+ - UUID of the VM. Can either be a full UUID or V(*) for all VMs.
type: str
vcpus:
required: false
@@ -309,8 +309,8 @@ options:
vnc_port:
required: false
description:
- - TCP port to listen of the VNC server. Or set C(0) for random,
- or C(-1) to disable.
+ - TCP port to listen of the VNC server. Or set V(0) for random,
+ or V(-1) to disable.
type: int
zfs_data_compression:
required: false
@@ -354,8 +354,6 @@ options:
description:
- ZFS pool the VM's zone dataset will be created in.
type: str
-requirements:
- - python >= 2.6
'''
EXAMPLES = '''
diff --git a/ansible_collections/community/general/plugins/modules/wdc_redfish_command.py b/ansible_collections/community/general/plugins/modules/wdc_redfish_command.py
index a51d454d9..93c4811af 100644
--- a/ansible_collections/community/general/plugins/modules/wdc_redfish_command.py
+++ b/ansible_collections/community/general/plugins/modules/wdc_redfish_command.py
@@ -38,11 +38,11 @@ options:
elements: str
baseuri:
description:
- - Base URI of OOB controller. Must include this or I(ioms).
+ - Base URI of OOB controller. Must include this or O(ioms).
type: str
ioms:
description:
- - List of IOM FQDNs for the enclosure. Must include this or I(baseuri).
+ - List of IOM FQDNs for the enclosure. Must include this or O(baseuri).
type: list
elements: str
username:
@@ -65,7 +65,7 @@ options:
resource_id:
required: false
description:
- - ID of the component to modify, such as C(Enclosure), C(IOModuleAFRU), C(PowerSupplyBFRU), C(FanExternalFRU3), or C(FanInternalFRU).
+ - ID of the component to modify, such as V(Enclosure), V(IOModuleAFRU), V(PowerSupplyBFRU), V(FanExternalFRU3), or V(FanInternalFRU).
type: str
version_added: 5.4.0
update_image_uri:
diff --git a/ansible_collections/community/general/plugins/modules/wdc_redfish_info.py b/ansible_collections/community/general/plugins/modules/wdc_redfish_info.py
index 038e1a72d..03ae67fcf 100644
--- a/ansible_collections/community/general/plugins/modules/wdc_redfish_info.py
+++ b/ansible_collections/community/general/plugins/modules/wdc_redfish_info.py
@@ -33,11 +33,11 @@ options:
elements: str
baseuri:
description:
- - Base URI of OOB controller. Must include this or I(ioms).
+ - Base URI of OOB controller. Must include this or O(ioms).
type: str
ioms:
description:
- - List of IOM FQDNs for the enclosure. Must include this or I(baseuri).
+ - List of IOM FQDNs for the enclosure. Must include this or O(baseuri).
type: list
elements: str
username:
diff --git a/ansible_collections/community/general/plugins/modules/webfaction_app.py b/ansible_collections/community/general/plugins/modules/webfaction_app.py
index 7a4702675..81bfc8b68 100644
--- a/ansible_collections/community/general/plugins/modules/webfaction_app.py
+++ b/ansible_collections/community/general/plugins/modules/webfaction_app.py
@@ -19,6 +19,12 @@ __metaclass__ = type
DOCUMENTATION = '''
---
+
+deprecated:
+ removed_in: 9.0.0
+ why: the endpoints this module relies on do not exist any more and do not resolve to IPs in DNS.
+ alternative: no known alternative at this point
+
module: webfaction_app
short_description: Add or remove applications on a Webfaction host
description:
@@ -27,9 +33,9 @@ author: Quentin Stafford-Fraser (@quentinsf)
notes:
- >
You can run playbooks that use this on a local machine, or on a Webfaction host, or elsewhere, since the scripts use the remote webfaction API.
- The location is not important. However, running them on multiple hosts I(simultaneously) is best avoided. If you don't specify I(localhost) as
- your host, you may want to add C(serial: 1) to the plays.
- - See `the webfaction API <https://docs.webfaction.com/xmlrpc-api/>`_ for more info.
+ The location is not important. However, running them on multiple hosts I(simultaneously) is best avoided. If you do not specify C(localhost) as
+ your host, you may want to add C(serial=1) to the plays.
+ - See L(the webfaction API, https://docs.webfaction.com/xmlrpc-api/) for more info.
extends_documentation_fragment:
- community.general.attributes
diff --git a/ansible_collections/community/general/plugins/modules/webfaction_db.py b/ansible_collections/community/general/plugins/modules/webfaction_db.py
index c4742cb21..5428de5b6 100644
--- a/ansible_collections/community/general/plugins/modules/webfaction_db.py
+++ b/ansible_collections/community/general/plugins/modules/webfaction_db.py
@@ -16,6 +16,12 @@ __metaclass__ = type
DOCUMENTATION = '''
---
+
+deprecated:
+ removed_in: 9.0.0
+ why: the endpoints this module relies on do not exist any more and do not resolve to IPs in DNS.
+ alternative: no known alternative at this point
+
module: webfaction_db
short_description: Add or remove a database on Webfaction
description:
@@ -24,9 +30,9 @@ author: Quentin Stafford-Fraser (@quentinsf)
notes:
- >
You can run playbooks that use this on a local machine, or on a Webfaction host, or elsewhere, since the scripts use the remote webfaction API.
- The location is not important. However, running them on multiple hosts I(simultaneously) is best avoided. If you don't specify I(localhost) as
- your host, you may want to add C(serial: 1) to the plays.
- - See `the webfaction API <https://docs.webfaction.com/xmlrpc-api/>`_ for more info.
+ The location is not important. However, running them on multiple hosts I(simultaneously) is best avoided. If you do not specify C(localhost) as
+ your host, you may want to add C(serial=1) to the plays.
+ - See L(the webfaction API, https://docs.webfaction.com/xmlrpc-api/) for more info.
extends_documentation_fragment:
- community.general.attributes
attributes:
diff --git a/ansible_collections/community/general/plugins/modules/webfaction_domain.py b/ansible_collections/community/general/plugins/modules/webfaction_domain.py
index 9bffec3cd..4c87a539a 100644
--- a/ansible_collections/community/general/plugins/modules/webfaction_domain.py
+++ b/ansible_collections/community/general/plugins/modules/webfaction_domain.py
@@ -13,19 +13,25 @@ __metaclass__ = type
DOCUMENTATION = '''
---
+
+deprecated:
+ removed_in: 9.0.0
+ why: the endpoints this module relies on do not exist any more and do not resolve to IPs in DNS.
+ alternative: no known alternative at this point
+
module: webfaction_domain
short_description: Add or remove domains and subdomains on Webfaction
description:
- Add or remove domains or subdomains on a Webfaction host. Further documentation at https://github.com/quentinsf/ansible-webfaction.
author: Quentin Stafford-Fraser (@quentinsf)
notes:
- - If you are I(deleting) domains by using I(state=absent), then note that if you specify subdomains, just those particular subdomains will be deleted.
- If you don't specify subdomains, the domain will be deleted.
+ - If you are I(deleting) domains by using O(state=absent), then note that if you specify subdomains, just those particular subdomains will be deleted.
+ If you do not specify subdomains, the domain will be deleted.
- >
You can run playbooks that use this on a local machine, or on a Webfaction host, or elsewhere, since the scripts use the remote webfaction API.
- The location is not important. However, running them on multiple hosts I(simultaneously) is best avoided. If you don't specify I(localhost) as
- your host, you may want to add C(serial: 1) to the plays.
- - See `the webfaction API <https://docs.webfaction.com/xmlrpc-api/>`_ for more info.
+ The location is not important. However, running them on multiple hosts I(simultaneously) is best avoided. If you do not specify C(localhost) as
+ your host, you may want to add C(serial=1) to the plays.
+ - See L(the webfaction API, https://docs.webfaction.com/xmlrpc-api/) for more info.
extends_documentation_fragment:
- community.general.attributes
diff --git a/ansible_collections/community/general/plugins/modules/webfaction_mailbox.py b/ansible_collections/community/general/plugins/modules/webfaction_mailbox.py
index 2b543c5b1..119dfd283 100644
--- a/ansible_collections/community/general/plugins/modules/webfaction_mailbox.py
+++ b/ansible_collections/community/general/plugins/modules/webfaction_mailbox.py
@@ -13,6 +13,12 @@ __metaclass__ = type
DOCUMENTATION = '''
---
+
+deprecated:
+ removed_in: 9.0.0
+ why: the endpoints this module relies on do not exist any more and do not resolve to IPs in DNS.
+ alternative: no known alternative at this point
+
module: webfaction_mailbox
short_description: Add or remove mailboxes on Webfaction
description:
@@ -21,9 +27,9 @@ author: Quentin Stafford-Fraser (@quentinsf)
notes:
- >
You can run playbooks that use this on a local machine, or on a Webfaction host, or elsewhere, since the scripts use the remote webfaction API.
- The location is not important. However, running them on multiple hosts I(simultaneously) is best avoided. If you don't specify I(localhost) as
- your host, you may want to add C(serial: 1) to the plays.
- - See `the webfaction API <https://docs.webfaction.com/xmlrpc-api/>`_ for more info.
+ The location is not important. However, running them on multiple hosts I(simultaneously) is best avoided. If you do not specify C(localhost) as
+ your host, you may want to add C(serial=1) to the plays.
+ - See L(the webfaction API, https://docs.webfaction.com/xmlrpc-api/) for more info.
extends_documentation_fragment:
- community.general.attributes
diff --git a/ansible_collections/community/general/plugins/modules/webfaction_site.py b/ansible_collections/community/general/plugins/modules/webfaction_site.py
index 385f55211..7795c45fe 100644
--- a/ansible_collections/community/general/plugins/modules/webfaction_site.py
+++ b/ansible_collections/community/general/plugins/modules/webfaction_site.py
@@ -13,20 +13,26 @@ __metaclass__ = type
DOCUMENTATION = '''
---
+
+deprecated:
+ removed_in: 9.0.0
+ why: the endpoints this module relies on do not exist any more and do not resolve to IPs in DNS.
+ alternative: no known alternative at this point
+
module: webfaction_site
short_description: Add or remove a website on a Webfaction host
description:
- Add or remove a website on a Webfaction host. Further documentation at https://github.com/quentinsf/ansible-webfaction.
author: Quentin Stafford-Fraser (@quentinsf)
notes:
- - Sadly, you I(do) need to know your webfaction hostname for the C(host) parameter. But at least, unlike the API, you don't need to know the IP
+ - Sadly, you I(do) need to know your webfaction hostname for the C(host) parameter. But at least, unlike the API, you do not need to know the IP
address. You can use a DNS name.
- If a site of the same name exists in the account but on a different host, the operation will exit.
- >
You can run playbooks that use this on a local machine, or on a Webfaction host, or elsewhere, since the scripts use the remote webfaction API.
- The location is not important. However, running them on multiple hosts I(simultaneously) is best avoided. If you don't specify I(localhost) as
- your host, you may want to add C(serial: 1) to the plays.
- - See `the webfaction API <https://docs.webfaction.com/xmlrpc-api/>`_ for more info.
+ The location is not important. However, running them on multiple hosts I(simultaneously) is best avoided. If you do not specify C(localhost) as
+ your host, you may want to add C(serial=1) to the plays.
+ - See L(the webfaction API, https://docs.webfaction.com/xmlrpc-api/) for more info.
extends_documentation_fragment:
- community.general.attributes
diff --git a/ansible_collections/community/general/plugins/modules/xattr.py b/ansible_collections/community/general/plugins/modules/xattr.py
index 0b44fdaad..7a5f3b431 100644
--- a/ansible_collections/community/general/plugins/modules/xattr.py
+++ b/ansible_collections/community/general/plugins/modules/xattr.py
@@ -27,7 +27,6 @@ options:
path:
description:
- The full path of the file/object to get the facts of.
- - Before 2.3 this option was only usable as I(name).
type: path
required: true
aliases: [ name ]
@@ -42,27 +41,25 @@ options:
type: str
value:
description:
- - The value to set the named name/key to, it automatically sets the I(state) to C(present).
+ - The value to set the named name/key to, it automatically sets the O(state) to V(present).
type: str
state:
description:
- defines which state you want to do.
- C(read) retrieves the current value for a I(key) (default)
- C(present) sets I(path) to C(value), default if value is set
- C(all) dumps all data
- C(keys) retrieves all keys
- C(absent) deletes the key
+ V(read) retrieves the current value for a O(key) (default)
+ V(present) sets O(path) to O(value), default if value is set
+ V(all) dumps all data
+ V(keys) retrieves all keys
+ V(absent) deletes the key
type: str
choices: [ absent, all, keys, present, read ]
default: read
follow:
description:
- - If C(true), dereferences symlinks and sets/gets attributes on symlink target,
+ - If V(true), dereferences symlinks and sets/gets attributes on symlink target,
otherwise acts on symlink itself.
type: bool
default: true
-notes:
- - As of Ansible 2.3, the I(name) option has been changed to I(path) as default, but I(name) still works as well.
author:
- Brian Coca (@bcoca)
'''
diff --git a/ansible_collections/community/general/plugins/modules/xbps.py b/ansible_collections/community/general/plugins/modules/xbps.py
index 1fea5b384..bcbbb3f02 100644
--- a/ansible_collections/community/general/plugins/modules/xbps.py
+++ b/ansible_collections/community/general/plugins/modules/xbps.py
@@ -62,7 +62,7 @@ options:
- Whether or not to upgrade the xbps package when necessary.
Before installing new packages,
xbps requires the user to update the xbps package itself.
- Thus when this option is set to C(false),
+ Thus when this option is set to V(false),
upgrades and installations will fail when xbps is not up to date.
type: bool
default: true
diff --git a/ansible_collections/community/general/plugins/modules/xcc_redfish_command.py b/ansible_collections/community/general/plugins/modules/xcc_redfish_command.py
index 494ea061e..1e77d0f8d 100644
--- a/ansible_collections/community/general/plugins/modules/xcc_redfish_command.py
+++ b/ansible_collections/community/general/plugins/modules/xcc_redfish_command.py
@@ -592,8 +592,9 @@ class XCCRedfishUtils(RedfishUtils):
def raw_post_resource(self, resource_uri, request_body):
if resource_uri is None:
return {'ret': False, 'msg': "resource_uri is missing"}
+ resource_uri_has_actions = True
if '/Actions/' not in resource_uri:
- return {'ret': False, 'msg': "Bad uri %s. Keyword /Actions/ should be included in uri" % resource_uri}
+ resource_uri_has_actions = False
if request_body is None:
return {'ret': False, 'msg': "request_body is missing"}
# get action base uri data for further checking
@@ -602,7 +603,10 @@ class XCCRedfishUtils(RedfishUtils):
if response['ret'] is False:
return response
if 'Actions' not in response['data']:
- return {'ret': False, 'msg': "Actions property not found in %s" % action_base_uri}
+ if resource_uri_has_actions:
+ return {'ret': False, 'msg': "Actions property not found in %s" % action_base_uri}
+ else:
+ response['data']['Actions'] = {}
# check resouce_uri with target uri found in action base uri data
action_found = False
@@ -634,7 +638,7 @@ class XCCRedfishUtils(RedfishUtils):
else:
action_target_uri_list.append(response['data']['Actions']['Oem'][key]['target'])
- if not action_found:
+ if not action_found and resource_uri_has_actions:
return {'ret': False,
'msg': 'Specified resource_uri is not a supported action target uri, please specify a supported target uri instead. Supported uri: %s'
% (str(action_target_uri_list))}
diff --git a/ansible_collections/community/general/plugins/modules/xenserver_facts.py b/ansible_collections/community/general/plugins/modules/xenserver_facts.py
index 9924c4a9e..685522f49 100644
--- a/ansible_collections/community/general/plugins/modules/xenserver_facts.py
+++ b/ansible_collections/community/general/plugins/modules/xenserver_facts.py
@@ -135,7 +135,7 @@ def change_keys(recs, key='uuid', filter_func=None):
for param_name, param_value in rec.items():
# param_value may be of type xmlrpc.client.DateTime,
- # which is not simply convertable to str.
+ # which is not simply convertible to str.
# Use 'value' attr to get the str value,
# following an example in xmlrpc.client.DateTime document
if hasattr(param_value, "value"):
diff --git a/ansible_collections/community/general/plugins/modules/xenserver_guest.py b/ansible_collections/community/general/plugins/modules/xenserver_guest.py
index 7659ee2ae..110bc8875 100644
--- a/ansible_collections/community/general/plugins/modules/xenserver_guest.py
+++ b/ansible_collections/community/general/plugins/modules/xenserver_guest.py
@@ -25,26 +25,25 @@ notes:
Citrix Hypervisor/XenServer SDK (downloadable from Citrix website). Copy the XenAPI.py file from the SDK to your Python site-packages on your
Ansible Control Node to use it. Latest version of the library can also be acquired from GitHub:
U(https://raw.githubusercontent.com/xapi-project/xen-api/master/scripts/examples/python/XenAPI/XenAPI.py)'
-- 'If no scheme is specified in I(hostname), module defaults to C(http://) because C(https://) is problematic in most setups. Make sure you are
+- 'If no scheme is specified in O(hostname), module defaults to C(http://) because C(https://) is problematic in most setups. Make sure you are
accessing XenServer host in trusted environment or use C(https://) scheme explicitly.'
-- 'To use C(https://) scheme for I(hostname) you have to either import host certificate to your OS certificate store or use I(validate_certs): C(false)
+- 'To use C(https://) scheme for O(hostname) you have to either import host certificate to your OS certificate store or use O(validate_certs=false)
which requires XenAPI library from XenServer 7.2 SDK or newer and Python 2.7.9 or newer.'
-- 'Network configuration inside a guest OS, by using I(networks.type), I(networks.ip), I(networks.gateway) etc. parameters, is supported on
+- 'Network configuration inside a guest OS, by using O(networks[].type), O(networks[].ip), O(networks[].gateway) etc. parameters, is supported on
XenServer 7.0 or newer for Windows guests by using official XenServer Guest agent support for network configuration. The module will try to
detect if such support is available and utilize it, else it will use a custom method of configuration via xenstore. Since XenServer Guest
- agent only support None and Static types of network configuration, where None means DHCP configured interface, I(networks.type) and I(networks.type6)
- values C(none) and C(dhcp) have same effect. More info here:
+ agent only support None and Static types of network configuration, where None means DHCP configured interface, O(networks[].type) and O(networks[].type6)
+ values V(none) and V(dhcp) have same effect. More info here:
U(https://www.citrix.com/community/citrix-developer/citrix-hypervisor-developer/citrix-hypervisor-developing-products/citrix-hypervisor-staticip.html)'
- 'On platforms without official support for network configuration inside a guest OS, network parameters will be written to xenstore
- C(vm-data/networks/<vif_device>) key. Parameters can be inspected by using C(xenstore ls) and C(xenstore read) tools on \*nix guests or trough
+ C(vm-data/networks/<vif_device>) key. Parameters can be inspected by using C(xenstore ls) and C(xenstore read) tools on \*nix guests or through
WMI interface on Windows guests. They can also be found in VM facts C(instance.xenstore_data) key as returned by the module. It is up to the user
to implement a boot time scripts or custom agent that will read the parameters from xenstore and configure network with given parameters.
Take note that for xenstore data to become available inside a guest, a VM restart is needed hence module will require VM restart if any
- parameter is changed. This is a limitation of XenAPI and xenstore. Considering these limitations, network configuration trough xenstore is most
- useful for bootstraping newly deployed VMs, much less for reconfiguring existing ones. More info here:
+ parameter is changed. This is a limitation of XenAPI and xenstore. Considering these limitations, network configuration through xenstore is most
+ useful for bootstrapping newly deployed VMs, much less for reconfiguring existing ones. More info here:
U(https://support.citrix.com/article/CTX226713)'
requirements:
-- python >= 2.6
- XenAPI
attributes:
check_mode:
@@ -55,10 +54,10 @@ options:
state:
description:
- Specify the state VM should be in.
- - If I(state) is set to C(present) and VM exists, ensure the VM configuration conforms to given parameters.
- - If I(state) is set to C(present) and VM does not exist, then VM is deployed with given parameters.
- - If I(state) is set to C(absent) and VM exists, then VM is removed with its associated components.
- - If I(state) is set to C(poweredon) and VM does not exist, then VM is deployed with given parameters and powered on automatically.
+ - If O(state) is set to V(present) and VM exists, ensure the VM configuration conforms to given parameters.
+ - If O(state) is set to V(present) and VM does not exist, then VM is deployed with given parameters.
+ - If O(state) is set to V(absent) and VM exists, then VM is removed with its associated components.
+ - If O(state) is set to V(poweredon) and VM does not exist, then VM is deployed with given parameters and powered on automatically.
type: str
default: present
choices: [ present, absent, poweredon ]
@@ -66,7 +65,7 @@ options:
description:
- Name of the VM to work with.
- VMs running on XenServer do not necessarily have unique names. The module will fail if multiple VMs with same name are found.
- - In case of multiple VMs with same name, use I(uuid) to uniquely specify VM to manage.
+ - In case of multiple VMs with same name, use O(uuid) to uniquely specify VM to manage.
- This parameter is case sensitive.
type: str
aliases: [ name_label ]
@@ -84,7 +83,7 @@ options:
description:
- Name of a template, an existing VM (must be shut down) or a snapshot that should be used to create VM.
- Templates/VMs/snapshots on XenServer do not necessarily have unique names. The module will fail if multiple templates with same name are found.
- - In case of multiple templates/VMs/snapshots with same name, use I(template_uuid) to uniquely specify source template.
+ - In case of multiple templates/VMs/snapshots with same name, use O(template_uuid) to uniquely specify source template.
- If VM already exists, this setting will be ignored.
- This parameter is case sensitive.
type: str
@@ -117,7 +116,7 @@ options:
type: int
num_cpu_cores_per_socket:
description:
- - Number of Cores Per Socket. I(num_cpus) has to be a multiple of I(num_cpu_cores_per_socket).
+ - Number of Cores Per Socket. O(hardware.num_cpus) has to be a multiple of O(hardware.num_cpu_cores_per_socket).
type: int
memory_mb:
description:
@@ -128,7 +127,7 @@ options:
- A list of disks to add to VM.
- All parameters are case sensitive.
- Removing or detaching existing disks of VM is not supported.
- - New disks are required to have either a I(size) or one of I(size_[tb,gb,mb,kb,b]) parameters specified.
+ - New disks are required to have either a O(disks[].size) or one of O(ignore:disks[].size_[tb,gb,mb,kb,b]) parameters specified.
- VM needs to be shut down to reconfigure disk size.
type: list
elements: dict
@@ -136,7 +135,7 @@ options:
suboptions:
size:
description:
- - 'Disk size with unit. Unit must be: C(b), C(kb), C(mb), C(gb), C(tb). VM needs to be shut down to reconfigure this parameter.'
+ - 'Disk size with unit. Unit must be: V(b), V(kb), V(mb), V(gb), V(tb). VM needs to be shut down to reconfigure this parameter.'
- If no unit is specified, size is assumed to be in bytes.
type: str
size_b:
@@ -184,13 +183,13 @@ options:
suboptions:
type:
description:
- - The type of CD-ROM. With C(none) the CD-ROM device will be present but empty.
+ - The type of CD-ROM. With V(none) the CD-ROM device will be present but empty.
type: str
choices: [ none, iso ]
iso_name:
description:
- - 'The file name of an ISO image from one of the XenServer ISO Libraries (implies I(type): C(iso)).'
- - Required if I(type) is set to C(iso).
+ - 'The file name of an ISO image from one of the XenServer ISO Libraries (implies O(cdrom.type=iso)).'
+ - Required if O(cdrom.type) is set to V(iso).
type: str
networks:
description:
@@ -212,17 +211,17 @@ options:
type: str
type:
description:
- - Type of IPv4 assignment. Value C(none) means whatever is default for OS.
+ - Type of IPv4 assignment. Value V(none) means whatever is default for OS.
- On some operating systems it could be DHCP configured (e.g. Windows) or unconfigured interface (e.g. Linux).
type: str
choices: [ none, dhcp, static ]
ip:
description:
- - 'Static IPv4 address (implies I(type): C(static)). Can include prefix in format C(<IPv4 address>/<prefix>) instead of using C(netmask).'
+ - 'Static IPv4 address (implies O(networks[].type=static)). Can include prefix in format C(<IPv4 address>/<prefix>) instead of using C(netmask).'
type: str
netmask:
description:
- - Static IPv4 netmask required for I(ip) if prefix is not specified.
+ - Static IPv4 netmask required for O(networks[].ip) if prefix is not specified.
type: str
gateway:
description:
@@ -230,12 +229,12 @@ options:
type: str
type6:
description:
- - Type of IPv6 assignment. Value C(none) means whatever is default for OS.
+ - Type of IPv6 assignment. Value V(none) means whatever is default for OS.
type: str
choices: [ none, dhcp, static ]
ip6:
description:
- - 'Static IPv6 address (implies I(type6): C(static)) with prefix in format C(<IPv6 address>/<prefix>).'
+ - 'Static IPv6 address (implies O(networks[].type6=static)) with prefix in format C(<IPv6 address>/<prefix>).'
type: str
gateway6:
description:
@@ -249,8 +248,8 @@ options:
custom_params:
description:
- Define a list of custom VM params to set on VM.
- - Useful for advanced users familiar with managing VM params trough xe CLI.
- - A custom value object takes two fields I(key) and I(value) (see example below).
+ - Useful for advanced users familiar with managing VM params through xe CLI.
+ - A custom value object takes two fields O(custom_params[].key) and O(custom_params[].value) (see example below).
type: list
elements: dict
suboptions:
@@ -266,13 +265,13 @@ options:
required: true
wait_for_ip_address:
description:
- - Wait until XenServer detects an IP address for the VM. If I(state) is set to C(absent), this parameter is ignored.
+ - Wait until XenServer detects an IP address for the VM. If O(state) is set to V(absent), this parameter is ignored.
- This requires XenServer Tools to be preinstalled on the VM to work properly.
type: bool
default: false
state_change_timeout:
description:
- - 'By default, module will wait indefinitely for VM to accquire an IP address if I(wait_for_ip_address): C(true).'
+ - 'By default, module will wait indefinitely for VM to acquire an IP address if O(wait_for_ip_address=true).'
- If this parameter is set to positive value, the module will instead wait specified number of seconds for the state change.
- In case of timeout, module will generate an error message.
type: int
@@ -301,7 +300,6 @@ EXAMPLES = r'''
hostname: "{{ xenserver_hostname }}"
username: "{{ xenserver_username }}"
password: "{{ xenserver_password }}"
- validate_certs: false
folder: /testvms
name: testvm_2
state: poweredon
@@ -328,7 +326,6 @@ EXAMPLES = r'''
hostname: "{{ xenserver_hostname }}"
username: "{{ xenserver_username }}"
password: "{{ xenserver_password }}"
- validate_certs: false
folder: /testvms
name: testvm_6
is_template: true
@@ -990,7 +987,7 @@ class XenServerVM(XenServerObject):
vif_device = vm_vif_params['device']
# A user could have manually changed network
- # or mac e.g. trough XenCenter and then also
+ # or mac e.g. through XenCenter and then also
# make those changes in playbook manually.
# In that case, module will not detect any
# changes and info in xenstore_data will
diff --git a/ansible_collections/community/general/plugins/modules/xenserver_guest_info.py b/ansible_collections/community/general/plugins/modules/xenserver_guest_info.py
index dd28cf7d0..68050f950 100644
--- a/ansible_collections/community/general/plugins/modules/xenserver_guest_info.py
+++ b/ansible_collections/community/general/plugins/modules/xenserver_guest_info.py
@@ -27,16 +27,14 @@ notes:
accessing XenServer host in trusted environment or use C(https://) scheme explicitly.'
- 'To use C(https://) scheme for C(hostname) you have to either import host certificate to your OS certificate store or use C(validate_certs: no)
which requires XenAPI library from XenServer 7.2 SDK or newer and Python 2.7.9 or newer.'
-- This module was called C(xenserver_guest_facts) before Ansible 2.9. The usage did not change.
requirements:
-- python >= 2.6
- XenAPI
options:
name:
description:
- Name of the VM to gather facts from.
- VMs running on XenServer do not necessarily have unique names. The module will fail if multiple VMs with same name are found.
- - In case of multiple VMs with same name, use C(uuid) to uniquely specify VM to manage.
+ - In case of multiple VMs with same name, use O(uuid) to uniquely specify VM to manage.
- This parameter is case sensitive.
type: str
aliases: [ name_label ]
@@ -151,12 +149,6 @@ instance:
}
'''
-HAS_XENAPI = False
-try:
- import XenAPI # noqa: F401, pylint: disable=unused-import
- HAS_XENAPI = True
-except ImportError:
- pass
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils.xenserver import (xenserver_common_argument_spec, XenServerObject, get_object_ref,
diff --git a/ansible_collections/community/general/plugins/modules/xenserver_guest_powerstate.py b/ansible_collections/community/general/plugins/modules/xenserver_guest_powerstate.py
index ba88bbf1d..c4e4f5976 100644
--- a/ansible_collections/community/general/plugins/modules/xenserver_guest_powerstate.py
+++ b/ansible_collections/community/general/plugins/modules/xenserver_guest_powerstate.py
@@ -28,7 +28,6 @@ notes:
- 'To use C(https://) scheme for C(hostname) you have to either import host certificate to your OS certificate store or use C(validate_certs: no)
which requires XenAPI library from XenServer 7.2 SDK or newer and Python 2.7.9 or newer.'
requirements:
-- python >= 2.6
- XenAPI
attributes:
check_mode:
@@ -39,8 +38,8 @@ options:
state:
description:
- Specify the state VM should be in.
- - If C(state) is set to value other than C(present), then VM is transitioned into required state and facts are returned.
- - If C(state) is set to C(present), then VM is just checked for existence and facts are returned.
+ - If O(state) is set to value other than V(present), then VM is transitioned into required state and facts are returned.
+ - If O(state) is set to V(present), then VM is just checked for existence and facts are returned.
type: str
default: present
choices: [ powered-on, powered-off, restarted, shutdown-guest, reboot-guest, suspended, present ]
@@ -48,7 +47,7 @@ options:
description:
- Name of the VM to manage.
- VMs running on XenServer do not necessarily have unique names. The module will fail if multiple VMs with same name are found.
- - In case of multiple VMs with same name, use C(uuid) to uniquely specify VM to manage.
+ - In case of multiple VMs with same name, use O(uuid) to uniquely specify VM to manage.
- This parameter is case sensitive.
type: str
aliases: [ name_label ]
@@ -65,7 +64,7 @@ options:
default: false
state_change_timeout:
description:
- - 'By default, module will wait indefinitely for VM to change state or acquire an IP address if C(wait_for_ip_address: true).'
+ - 'By default, module will wait indefinitely for VM to change state or acquire an IP address if O(wait_for_ip_address=true).'
- If this parameter is set to positive value, the module will instead wait specified number of seconds for the state change.
- In case of timeout, module will generate an error message.
type: int
@@ -177,12 +176,6 @@ instance:
}
'''
-HAS_XENAPI = False
-try:
- import XenAPI # noqa: F401, pylint: disable=unused-import
- HAS_XENAPI = True
-except ImportError:
- pass
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils.xenserver import (xenserver_common_argument_spec, XenServerObject, get_object_ref,
diff --git a/ansible_collections/community/general/plugins/modules/xfconf.py b/ansible_collections/community/general/plugins/modules/xfconf.py
index 567117d40..8ed44c675 100644
--- a/ansible_collections/community/general/plugins/modules/xfconf.py
+++ b/ansible_collections/community/general/plugins/modules/xfconf.py
@@ -58,15 +58,15 @@ options:
value_type:
description:
- The type of value being set.
- - When providing more than one I(value_type), the length of the list must
- be equal to the length of I(value).
- - If only one I(value_type) is provided, but I(value) contains more than
- on element, that I(value_type) will be applied to all elements of I(value).
- - If the I(property) being set is an array and it can possibly have ony one
- element in the array, then I(force_array=true) must be used to ensure
+ - When providing more than one O(value_type), the length of the list must
+ be equal to the length of O(value).
+ - If only one O(value_type) is provided, but O(value) contains more than
+ on element, that O(value_type) will be applied to all elements of O(value).
+ - If the O(property) being set is an array and it can possibly have only one
+ element in the array, then O(force_array=true) must be used to ensure
that C(xfconf-query) will interpret the value as an array rather than a
scalar.
- - Support for C(uchar), C(char), C(uint64), and C(int64) has been added in community.general 4.8.0.
+ - Support for V(uchar), V(char), V(uint64), and V(int64) has been added in community.general 4.8.0.
type: list
elements: str
choices: [ string, int, double, bool, uint, uchar, char, uint64, int64, float ]
@@ -74,7 +74,7 @@ options:
type: str
description:
- The action to take upon the property/value.
- - The state C(get) has been removed in community.general 5.0.0. Please use the module M(community.general.xfconf_info) instead.
+ - The state V(get) has been removed in community.general 5.0.0. Please use the module M(community.general.xfconf_info) instead.
choices: [ present, absent ]
default: "present"
force_array:
@@ -84,13 +84,6 @@ options:
default: false
aliases: ['array']
version_added: 1.0.0
- disable_facts:
- description:
- - The value C(false) is no longer allowed since community.general 4.0.0.
- - This option is deprecated, and will be removed in community.general 8.0.0.
- type: bool
- default: true
- version_added: 2.1.0
'''
EXAMPLES = """
@@ -130,9 +123,8 @@ RETURN = '''
sample: "/Xft/DPI"
value_type:
description:
- - The type of the value that was changed (C(none) for C(reset)
- state). Either a single string value or a list of strings for array
- types.
+ - The type of the value that was changed (V(none) for O(state=reset)).
+ Either a single string value or a list of strings for array types.
- This is a string or a list of strings.
returned: success
type: any
@@ -181,7 +173,6 @@ class XFConfProperty(StateModuleHelper):
change_params = ('value', )
diff_params = ('value', )
output_params = ('property', 'channel', 'value')
- facts_params = ('property', 'channel', 'value')
module = dict(
argument_spec=dict(
state=dict(type='str', choices=("present", "absent"), default="present"),
@@ -191,11 +182,6 @@ class XFConfProperty(StateModuleHelper):
choices=('string', 'int', 'double', 'bool', 'uint', 'uchar', 'char', 'uint64', 'int64', 'float')),
value=dict(type='list', elements='raw'),
force_array=dict(type='bool', default=False, aliases=['array']),
- disable_facts=dict(
- type='bool', default=True,
- removed_in_version='8.0.0',
- removed_from_collection='community.general'
- ),
),
required_if=[('state', 'present', ['value', 'value_type'])],
required_together=[('value', 'value_type')],
@@ -204,20 +190,14 @@ class XFConfProperty(StateModuleHelper):
default_state = 'present'
- def update_xfconf_output(self, **kwargs):
- self.update_vars(meta={"output": True, "fact": True}, **kwargs)
-
def __init_module__(self):
self.runner = xfconf_runner(self.module)
self.does_not = 'Property "{0}" does not exist on channel "{1}".'.format(self.vars.property,
self.vars.channel)
- self.vars.set('previous_value', self._get(), fact=True)
- self.vars.set('type', self.vars.value_type, fact=True)
+ self.vars.set('previous_value', self._get())
+ self.vars.set('type', self.vars.value_type)
self.vars.meta('value').set(initial_value=self.vars.previous_value)
- if self.vars.disable_facts is False:
- self.do_raise('Returning results as facts has been removed. Stop using disable_facts=false.')
-
def process_command_output(self, rc, out, err):
if err.rstrip() == self.does_not:
return None
diff --git a/ansible_collections/community/general/plugins/modules/xfconf_info.py b/ansible_collections/community/general/plugins/modules/xfconf_info.py
index 0a99201ef..844ef3c11 100644
--- a/ansible_collections/community/general/plugins/modules/xfconf_info.py
+++ b/ansible_collections/community/general/plugins/modules/xfconf_info.py
@@ -36,8 +36,8 @@ options:
- >
A Xfce preference key is an element in the Xfconf repository
that corresponds to an application preference.
- - If provided, then I(channel) is required.
- - If not provided and a I(channel) is provided, then the module will list all available properties in that I(channel).
+ - If provided, then O(channel) is required.
+ - If not provided and a O(channel) is provided, then the module will list all available properties in that O(channel).
type: str
notes:
- See man xfconf-query(1) for more details.
@@ -82,7 +82,7 @@ RETURN = '''
properties:
description:
- List of available properties for a specific channel.
- - Returned by passing only the I(channel) parameter to the module.
+ - Returned by passing only the O(channel) parameter to the module.
returned: success
type: list
elements: str
diff --git a/ansible_collections/community/general/plugins/modules/xml.py b/ansible_collections/community/general/plugins/modules/xml.py
index 5b9bba355..a3c12b8ee 100644
--- a/ansible_collections/community/general/plugins/modules/xml.py
+++ b/ansible_collections/community/general/plugins/modules/xml.py
@@ -29,18 +29,18 @@ options:
description:
- Path to the file to operate on.
- This file must exist ahead of time.
- - This parameter is required, unless I(xmlstring) is given.
+ - This parameter is required, unless O(xmlstring) is given.
type: path
aliases: [ dest, file ]
xmlstring:
description:
- A string containing XML on which to operate.
- - This parameter is required, unless I(path) is given.
+ - This parameter is required, unless O(path) is given.
type: str
xpath:
description:
- A valid XPath expression describing the item(s) you want to manipulate.
- - Operates on the document root, C(/), by default.
+ - Operates on the document root, V(/), by default.
type: str
namespaces:
description:
@@ -57,43 +57,43 @@ options:
aliases: [ ensure ]
attribute:
description:
- - The attribute to select when using parameter I(value).
- - This is a string, not prepended with C(@).
+ - The attribute to select when using parameter O(value).
+ - This is a string, not prepended with V(@).
type: raw
value:
description:
- Desired state of the selected attribute.
- - Either a string, or to unset a value, the Python C(None) keyword (YAML Equivalent, C(null)).
+ - Either a string, or to unset a value, the Python V(None) keyword (YAML Equivalent, V(null)).
- Elements default to no value (but present).
- Attributes default to an empty string.
type: raw
add_children:
description:
- - Add additional child-element(s) to a selected element for a given I(xpath).
+ - Add additional child-element(s) to a selected element for a given O(xpath).
- Child elements must be given in a list and each item may be either a string
- (eg. C(children=ansible) to add an empty C(<ansible/>) child element),
+ (for example C(children=ansible) to add an empty C(<ansible/>) child element),
or a hash where the key is an element name and the value is the element value.
- - This parameter requires I(xpath) to be set.
+ - This parameter requires O(xpath) to be set.
type: list
elements: raw
set_children:
description:
- - Set the child-element(s) of a selected element for a given I(xpath).
+ - Set the child-element(s) of a selected element for a given O(xpath).
- Removes any existing children.
- - Child elements must be specified as in I(add_children).
- - This parameter requires I(xpath) to be set.
+ - Child elements must be specified as in O(add_children).
+ - This parameter requires O(xpath) to be set.
type: list
elements: raw
count:
description:
- - Search for a given I(xpath) and provide the count of any matches.
- - This parameter requires I(xpath) to be set.
+ - Search for a given O(xpath) and provide the count of any matches.
+ - This parameter requires O(xpath) to be set.
type: bool
default: false
print_match:
description:
- - Search for a given I(xpath) and print out any matches.
- - This parameter requires I(xpath) to be set.
+ - Search for a given O(xpath) and print out any matches.
+ - This parameter requires O(xpath) to be set.
type: bool
default: false
pretty_print:
@@ -103,13 +103,13 @@ options:
default: false
content:
description:
- - Search for a given I(xpath) and get content.
- - This parameter requires I(xpath) to be set.
+ - Search for a given O(xpath) and get content.
+ - This parameter requires O(xpath) to be set.
type: str
choices: [ attribute, text ]
input_type:
description:
- - Type of input for I(add_children) and I(set_children).
+ - Type of input for O(add_children) and O(set_children).
type: str
choices: [ xml, yaml ]
default: yaml
@@ -127,20 +127,20 @@ options:
default: false
insertbefore:
description:
- - Add additional child-element(s) before the first selected element for a given I(xpath).
+ - Add additional child-element(s) before the first selected element for a given O(xpath).
- Child elements must be given in a list and each item may be either a string
- (eg. C(children=ansible) to add an empty C(<ansible/>) child element),
+ (for example C(children=ansible) to add an empty C(<ansible/>) child element),
or a hash where the key is an element name and the value is the element value.
- - This parameter requires I(xpath) to be set.
+ - This parameter requires O(xpath) to be set.
type: bool
default: false
insertafter:
description:
- - Add additional child-element(s) after the last selected element for a given I(xpath).
+ - Add additional child-element(s) after the last selected element for a given O(xpath).
- Child elements must be given in a list and each item may be either a string
- (eg. C(children=ansible) to add an empty C(<ansible/>) child element),
+ (for example C(children=ansible) to add an empty C(<ansible/>) child element),
or a hash where the key is an element name and the value is the element value.
- - This parameter requires I(xpath) to be set.
+ - This parameter requires O(xpath) to be set.
type: bool
default: false
requirements:
@@ -149,7 +149,7 @@ notes:
- Use the C(--check) and C(--diff) options when testing your expressions.
- The diff output is automatically pretty-printed, so may not reflect the actual file content, only the file structure.
- This module does not handle complicated xpath expressions, so limit xpath selectors to simple expressions.
-- Beware that in case your XML elements are namespaced, you need to use the I(namespaces) parameter, see the examples.
+- Beware that in case your XML elements are namespaced, you need to use the O(namespaces) parameter, see the examples.
- Namespaces prefix should be used for all children of an element where namespace is defined, unless another namespace is defined for them.
seealso:
- name: Xml module development community wiki
@@ -338,7 +338,7 @@ actions:
backup_file:
description: The name of the backup file that was created
type: str
- returned: when I(backup=true)
+ returned: when O(backup=true)
sample: /path/to/file.xml.1942.2017-08-24@14:16:01~
count:
description: The count of xpath matches.
diff --git a/ansible_collections/community/general/plugins/modules/yum_versionlock.py b/ansible_collections/community/general/plugins/modules/yum_versionlock.py
index e5d32dc77..0cbf9be39 100644
--- a/ansible_collections/community/general/plugins/modules/yum_versionlock.py
+++ b/ansible_collections/community/general/plugins/modules/yum_versionlock.py
@@ -1,6 +1,6 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
-# Copyright (c) 2018, Florian Paul Azim Hoberg <florian.hoberg@credativ.de>
+# Copyright (c) 2018, Florian Paul Azim Hoberg (@gyptazy) <gyptazy@gyptazy.ch>
#
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
@@ -25,14 +25,15 @@ attributes:
options:
name:
description:
- - Package name or a list of package names with optional wildcards.
+ - Package name or a list of package names with optional version or wildcards.
+ - Specifying versions is supported since community.general 7.2.0.
type: list
required: true
elements: str
state:
description:
- - If state is C(present), package(s) will be added to yum versionlock list.
- - If state is C(absent), package(s) will be removed from yum versionlock list.
+ - If state is V(present), package(s) will be added to yum versionlock list.
+ - If state is V(absent), package(s) will be removed from yum versionlock list.
choices: [ 'absent', 'present' ]
type: str
default: present
@@ -50,7 +51,14 @@ EXAMPLES = r'''
- name: Prevent Apache / httpd from being updated
community.general.yum_versionlock:
state: present
- name: httpd
+ name:
+ - httpd
+
+- name: Prevent Apache / httpd version 2.4.57-2 from being updated
+ community.general.yum_versionlock:
+ state: present
+ name:
+ - httpd-0:2.4.57-2.el9
- name: Prevent multiple packages from being updated
community.general.yum_versionlock:
@@ -111,22 +119,30 @@ class YumVersionLock:
def ensure_state(self, packages, command):
""" Ensure packages state """
rc, out, err = self.module.run_command([self.yum_bin, "-q", "versionlock", command] + packages)
+ # If no package can be found this will be written on stdout with rc 0
+ if 'No package found for' in out:
+ self.module.fail_json(msg=out)
if rc == 0:
return True
self.module.fail_json(msg="Error: " + to_native(err) + to_native(out))
def match(entry, name):
+ match = False
m = NEVRA_RE_YUM.match(entry)
if not m:
m = NEVRA_RE_DNF.match(entry)
if not m:
return False
- return fnmatch(m.group("name"), name)
+ if fnmatch(m.group("name"), name):
+ match = True
+ if entry.rstrip('.*') == name:
+ match = True
+ return match
def main():
- """ start main program to add/remove a package to yum versionlock"""
+ """ start main program to add/delete a package to yum versionlock """
module = AnsibleModule(
argument_spec=dict(
state=dict(default='present', choices=['present', 'absent']),
diff --git a/ansible_collections/community/general/plugins/modules/zfs.py b/ansible_collections/community/general/plugins/modules/zfs.py
index 4cd79c36e..f23cc4580 100644
--- a/ansible_collections/community/general/plugins/modules/zfs.py
+++ b/ansible_collections/community/general/plugins/modules/zfs.py
@@ -24,19 +24,19 @@ attributes:
- In certain situations it may report a task as changed that will not be reported
as changed when C(check_mode) is disabled.
- For example, this might occur when the zpool C(altroot) option is set or when
- a size is written using human-readable notation, such as C(1M) or C(1024K),
- instead of as an unqualified byte count, such as C(1048576).
+ a size is written using human-readable notation, such as V(1M) or V(1024K),
+ instead of as an unqualified byte count, such as V(1048576).
diff_mode:
support: full
options:
name:
description:
- - File system, snapshot or volume name e.g. C(rpool/myfs).
+ - File system, snapshot or volume name, for example V(rpool/myfs).
required: true
type: str
state:
description:
- - Whether to create (C(present)), or remove (C(absent)) a
+ - Whether to create (V(present)), or remove (V(absent)) a
file system, snapshot or volume. All parents/children
will be created/destroyed as needed to reach the desired state.
choices: [ absent, present ]
diff --git a/ansible_collections/community/general/plugins/modules/zfs_delegate_admin.py b/ansible_collections/community/general/plugins/modules/zfs_delegate_admin.py
index 0536f1a28..24f742220 100644
--- a/ansible_collections/community/general/plugins/modules/zfs_delegate_admin.py
+++ b/ansible_collections/community/general/plugins/modules/zfs_delegate_admin.py
@@ -15,7 +15,7 @@ short_description: Manage ZFS delegated administration (user admin privileges)
description:
- Manages ZFS file system delegated administration permissions, which allow unprivileged users to perform ZFS
operations normally restricted to the superuser.
- - See the C(zfs allow) section of C(zfs(1M)) for detailed explanations of options.
+ - See the C(zfs allow) section of V(zfs(1M\)) for detailed explanations of options.
- This module attempts to adhere to the behavior of the command line tool as much as possible.
requirements:
- "A ZFS/OpenZFS implementation that supports delegation with C(zfs allow), including: Solaris >= 10, illumos (all
@@ -30,14 +30,14 @@ attributes:
options:
name:
description:
- - File system or volume name e.g. C(rpool/myfs).
+ - File system or volume name, for example V(rpool/myfs).
required: true
type: str
state:
description:
- - Whether to allow (C(present)), or unallow (C(absent)) a permission.
- - When set to C(present), at least one "entity" param of I(users), I(groups), or I(everyone) are required.
- - When set to C(absent), removes permissions from the specified entities, or removes all permissions if no entity params are specified.
+ - Whether to allow (V(present)), or unallow (V(absent)) a permission.
+ - When set to V(present), at least one "entity" param of O(users), O(groups), or O(everyone) are required.
+ - When set to V(absent), removes permissions from the specified entities, or removes all permissions if no entity params are specified.
choices: [ absent, present ]
default: present
type: str
@@ -58,22 +58,22 @@ options:
default: false
permissions:
description:
- - The list of permission(s) to delegate (required if C(state) is C(present)).
+ - The list of permission(s) to delegate (required if O(state=present)).
- Supported permissions depend on the ZFS version in use. See for example
U(https://openzfs.github.io/openzfs-docs/man/8/zfs-allow.8.html) for OpenZFS.
type: list
elements: str
local:
description:
- - Apply permissions to C(name) locally (C(zfs allow -l)).
+ - Apply permissions to O(name) locally (C(zfs allow -l)).
type: bool
descendents:
description:
- - Apply permissions to C(name)'s descendents (C(zfs allow -d)).
+ - Apply permissions to O(name)'s descendents (C(zfs allow -d)).
type: bool
recursive:
description:
- - Unallow permissions recursively (ignored when C(state) is C(present)).
+ - Unallow permissions recursively (ignored when O(state=present)).
type: bool
default: false
author:
diff --git a/ansible_collections/community/general/plugins/modules/znode.py b/ansible_collections/community/general/plugins/modules/znode.py
index f5aa54ef8..e8f7f1dc7 100644
--- a/ansible_collections/community/general/plugins/modules/znode.py
+++ b/ansible_collections/community/general/plugins/modules/znode.py
@@ -66,9 +66,9 @@ options:
version_added: 5.8.0
auth_credential:
description:
- - The authentication credential value. Depends on I(auth_scheme).
- - The format for I(auth_scheme=digest) is C(user:password),
- and the format for I(auth_scheme=sasl) is C(user:password).
+ - The authentication credential value. Depends on O(auth_scheme).
+ - The format for O(auth_scheme=digest) is C(user:password),
+ and the format for O(auth_scheme=sasl) is C(user:password).
type: str
required: false
version_added: 5.8.0
@@ -81,7 +81,6 @@ options:
version_added: '6.5.0'
requirements:
- kazoo >= 2.1
- - python >= 2.6
author: "Trey Perry (@treyperry)"
'''
diff --git a/ansible_collections/community/general/plugins/modules/zypper.py b/ansible_collections/community/general/plugins/modules/zypper.py
index b47131d3d..fae859fe7 100644
--- a/ansible_collections/community/general/plugins/modules/zypper.py
+++ b/ansible_collections/community/general/plugins/modules/zypper.py
@@ -42,22 +42,22 @@ attributes:
options:
name:
description:
- - Package name C(name) or package specifier or a list of either.
- - Can include a version like C(name=1.0), C(name>3.4) or C(name<=2.7). If a version is given, C(oldpackage) is implied and zypper is allowed to
+ - Package name V(name) or package specifier or a list of either.
+ - Can include a version like V(name=1.0), V(name>3.4) or V(name<=2.7). If a version is given, V(oldpackage) is implied and zypper is allowed to
update the package within the version range given.
- You can also pass a url or a local path to a rpm file.
- - When using I(state=latest), this can be '*', which updates all installed packages.
+ - When using O(state=latest), this can be '*', which updates all installed packages.
required: true
aliases: [ 'pkg' ]
type: list
elements: str
state:
description:
- - C(present) will make sure the package is installed.
- C(latest) will make sure the latest version of the package is installed.
- C(absent) will make sure the specified package is not installed.
- C(dist-upgrade) will make sure the latest version of all installed packages from all enabled repositories is installed.
- - When using C(dist-upgrade), I(name) should be C('*').
+ - V(present) will make sure the package is installed.
+ V(latest) will make sure the latest version of the package is installed.
+ V(absent) will make sure the specified package is not installed.
+ V(dist-upgrade) will make sure the latest version of all installed packages from all enabled repositories is installed.
+ - When using V(dist-upgrade), O(name) should be V('*').
required: false
choices: [ present, latest, absent, dist-upgrade, installed, removed ]
default: "present"
@@ -78,14 +78,14 @@ options:
disable_gpg_check:
description:
- Whether to disable to GPG signature checking of the package
- signature being installed. Has an effect only if state is
- I(present) or I(latest).
+ signature being installed. Has an effect only if O(state) is
+ V(present) or V(latest).
required: false
default: false
type: bool
disable_recommends:
description:
- - Corresponds to the C(--no-recommends) option for I(zypper). Default behavior (C(true)) modifies zypper's default behavior; C(false) does
+ - Corresponds to the C(--no-recommends) option for I(zypper). Default behavior (V(true)) modifies zypper's default behavior; V(false) does
install recommended packages.
required: false
default: true
@@ -146,7 +146,7 @@ options:
version_added: '4.6.0'
notes:
- When used with a C(loop:) each package will be processed individually,
- it is much more efficient to pass the list directly to the I(name) option.
+ it is much more efficient to pass the list directly to the O(name) option.
# informational: requirements for nodes
requirements:
- "zypper >= 1.0 # included in openSUSE >= 11.1 or SUSE Linux Enterprise Server/Desktop >= 11.0"
@@ -205,7 +205,7 @@ EXAMPLES = '''
allow_vendor_change: true
extra_args: '--allow-arch-change'
-- name: Perform a installaion of nmap with the install option replacefiles
+- name: Perform a installation of nmap with the install option replacefiles
community.general.zypper:
name: 'nmap'
state: latest
diff --git a/ansible_collections/community/general/plugins/modules/zypper_repository.py b/ansible_collections/community/general/plugins/modules/zypper_repository.py
index cccd9c579..5a0356cc3 100644
--- a/ansible_collections/community/general/plugins/modules/zypper_repository.py
+++ b/ansible_collections/community/general/plugins/modules/zypper_repository.py
@@ -47,8 +47,7 @@ options:
disable_gpg_check:
description:
- Whether to disable GPG signature checking of
- all packages. Has an effect only if state is
- I(present).
+ all packages. Has an effect only if O(state=present).
- Needs zypper version >= 1.6.2.
type: bool
default: false
@@ -73,7 +72,7 @@ options:
auto_import_keys:
description:
- Automatically import the gpg signing key of the new or changed repository.
- - Has an effect only if state is I(present). Has no effect on existing (unchanged) repositories or in combination with I(absent).
+ - Has an effect only if O(state=present). Has no effect on existing (unchanged) repositories or in combination with O(state=absent).
- Implies runrefresh.
- Only works with C(.repo) files if `name` is given explicitly.
type: bool
diff --git a/ansible_collections/community/general/plugins/test/fqdn_valid.py b/ansible_collections/community/general/plugins/test/fqdn_valid.py
new file mode 100644
index 000000000..1ec774207
--- /dev/null
+++ b/ansible_collections/community/general/plugins/test/fqdn_valid.py
@@ -0,0 +1,103 @@
+# Copyright (c) 2023, Vladimir Botka <vbotka@gmail.com>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+from ansible.errors import AnsibleError
+from ansible.module_utils.six import raise_from
+
+try:
+ from fqdn import FQDN
+except ImportError as imp_exc:
+ ANOTHER_LIBRARY_IMPORT_ERROR = imp_exc
+else:
+ ANOTHER_LIBRARY_IMPORT_ERROR = None
+
+
+DOCUMENTATION = '''
+ name: fqdn_valid
+ short_description: Validates fully-qualified domain names against RFC 1123
+ version_added: 8.1.0
+ author: Vladimir Botka (@vbotka)
+ requirements:
+ - fqdn>=1.5.1 (PyPI)
+ description:
+ - This test validates Fully Qualified Domain Names (FQDNs)
+ conforming to the Internet Engineering Task Force specification
+ RFC 1123 and RFC 952.
+ - The design intent is to validate that a string would be
+ traditionally acceptable as a public Internet hostname to
+ RFC-conforming software, which is a strict subset of the logic
+ in modern web browsers like Mozilla Firefox and Chromium that
+ determines whether make a DNS lookup.
+ - Certificate Authorities like Let's Encrypt run a narrower set of
+ string validation logic to determine validity for issuance. This
+ test is not intended to achieve functional parity with CA
+ issuance.
+ - Single label names are allowed by default (O(min_labels=1)).
+ options:
+ _input:
+ description: Name of the host.
+ type: str
+ required: true
+ min_labels:
+ description: Required minimum of labels, separated by period.
+ default: 1
+ type: int
+ required: false
+ allow_underscores:
+ description: Allow underscore characters.
+ default: false
+ type: bool
+ required: false
+'''
+
+EXAMPLES = '''
+- name: Make sure that hostname is valid
+ ansible.builtin.assert:
+ that: hostname is community.general.fqdn_valid
+
+- name: Make sure that hostname is at least 3 labels long (a.b.c)
+ ansible.builtin.assert:
+ that: hostname is community.general.fqdn_valid(min_labels=3)
+
+- name: Make sure that hostname is at least 2 labels long (a.b). Allow '_'
+ ansible.builtin.assert:
+ that: hostname is community.general.fqdn_valid(min_labels=2, allow_underscores=True)
+'''
+
+RETURN = '''
+ _value:
+ description: Whether the name is valid.
+ type: bool
+'''
+
+
+def fqdn_valid(name, min_labels=1, allow_underscores=False):
+ """
+ Example:
+ - 'srv.example.com' is community.general.fqdn_valid
+ - 'foo_bar.example.com' is community.general.fqdn_valid(allow_underscores=True)
+ """
+
+ if ANOTHER_LIBRARY_IMPORT_ERROR:
+ raise_from(
+ AnsibleError('Python package fqdn must be installed to use this test.'),
+ ANOTHER_LIBRARY_IMPORT_ERROR
+ )
+
+ fobj = FQDN(name, min_labels=min_labels, allow_underscores=allow_underscores)
+ return (fobj.is_valid)
+
+
+class TestModule(object):
+ ''' Ansible test hostname validity.
+ https://pypi.org/project/fqdn/
+ '''
+
+ def tests(self):
+ return {
+ 'fqdn_valid': fqdn_valid,
+ }
diff --git a/ansible_collections/community/general/tests/.gitignore b/ansible_collections/community/general/tests/.gitignore
index 6edf5dc10..0d36555dd 100644
--- a/ansible_collections/community/general/tests/.gitignore
+++ b/ansible_collections/community/general/tests/.gitignore
@@ -3,3 +3,4 @@
# SPDX-License-Identifier: GPL-3.0-or-later
output/
+integration/inventory
diff --git a/ansible_collections/community/general/tests/galaxy-importer.cfg b/ansible_collections/community/general/tests/galaxy-importer.cfg
new file mode 100644
index 000000000..5ab20d06a
--- /dev/null
+++ b/ansible_collections/community/general/tests/galaxy-importer.cfg
@@ -0,0 +1,8 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+[galaxy-importer]
+# This is only needed to make Zuul's third-party-check happy.
+# It is not needed by anything else.
+run_ansible_doc=false
diff --git a/ansible_collections/community/general/tests/integration/targets/aix_filesystem/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/aix_filesystem/tasks/main.yml
index 25146062d..878088f4e 100644
--- a/ansible_collections/community/general/tests/integration/targets/aix_filesystem/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/aix_filesystem/tasks/main.yml
@@ -90,7 +90,7 @@
size: -2G
state: present
-- name: Resizing /mksysb to 100G (no enought space)
+- name: Resizing /mksysb to 100G (not enough space)
aix_filesystem:
filesystem: /mksysb
size: +100G
diff --git a/ansible_collections/community/general/tests/integration/targets/alternatives/tasks/tests_set_priority.yml b/ansible_collections/community/general/tests/integration/targets/alternatives/tasks/tests_set_priority.yml
index 46cf48e59..9bc523b0d 100644
--- a/ansible_collections/community/general/tests/integration/targets/alternatives/tasks/tests_set_priority.yml
+++ b/ansible_collections/community/general/tests/integration/targets/alternatives/tasks/tests_set_priority.yml
@@ -22,7 +22,7 @@
assert:
that:
- 'alternative is changed'
- - 'cmd.stdout == "dummy{{ item }}"'
+ - 'cmd.stdout == "dummy" ~ item'
- name: check that alternative has been updated
command: "grep -Pzq '/bin/dummy{{ item }}\\n{{ 60 + item|int }}' '{{ alternatives_dir }}/dummy'"
diff --git a/ansible_collections/community/general/tests/integration/targets/ansible_galaxy_install/aliases b/ansible_collections/community/general/tests/integration/targets/ansible_galaxy_install/aliases
index 13655b194..297477ac9 100644
--- a/ansible_collections/community/general/tests/integration/targets/ansible_galaxy_install/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/ansible_galaxy_install/aliases
@@ -4,5 +4,4 @@
azp/posix/3
destructive
-skip/python2.6
context/controller # While this is not really true, this module mainly is run on the controller, *and* needs access to the ansible-galaxy CLI tool
diff --git a/ansible_collections/community/general/tests/integration/targets/apache2_module/tasks/actualtest.yml b/ansible_collections/community/general/tests/integration/targets/apache2_module/tasks/actualtest.yml
index 3301a16b1..6fd10ce57 100644
--- a/ansible_collections/community/general/tests/integration/targets/apache2_module/tasks/actualtest.yml
+++ b/ansible_collections/community/general/tests/integration/targets/apache2_module/tasks/actualtest.yml
@@ -73,7 +73,7 @@
state: absent
force: true
- - name: reenable autoindex
+ - name: re-enable autoindex
community.general.apache2_module:
name: autoindex
state: present
diff --git a/ansible_collections/community/general/tests/integration/targets/apk/aliases b/ansible_collections/community/general/tests/integration/targets/apk/aliases
new file mode 100644
index 000000000..6e8c01586
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/apk/aliases
@@ -0,0 +1,13 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+azp/posix/2
+needs/root
+destructive
+skip/aix
+skip/osx
+skip/macos
+skip/freebsd
+skip/rhel
+skip/ubuntu \ No newline at end of file
diff --git a/ansible_collections/community/general/tests/integration/targets/apk/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/apk/tasks/main.yml
new file mode 100644
index 000000000..0e1b0ae42
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/apk/tasks/main.yml
@@ -0,0 +1,160 @@
+####################################################################
+# WARNING: These are designed specifically for Ansible tests #
+# and should not be used as examples of how to write Ansible roles #
+####################################################################
+
+# Copyright (c) 2024, Max Maxopoly <max@dermax.org>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+- name: Run apk tests on Alpine
+ when: ansible_distribution in ['Alpine']
+ block:
+ - name: Ensure vim is not installed
+ community.general.apk:
+ name: vim
+ state: absent
+
+ - name: Install vim
+ community.general.apk:
+ name: vim
+ state: present
+ register: results
+
+ - name: Ensure vim was installed
+ ansible.builtin.assert:
+ that:
+ - results is changed
+ - (results.packages | length) >= 1 # vim has dependencies, so depending on the base image this number may vary
+
+ - name: Install vim again
+ community.general.apk:
+ name: vim
+ state: present
+ register: results
+
+ - name: Ensure vim was not installed again
+ ansible.builtin.assert:
+ that:
+ - results is not changed
+ - (results.packages | default([]) | length) == 0
+
+ - name: Ensure vim is not installed
+ community.general.apk:
+ name: vim
+ state: absent
+ register: results
+
+ - name: Ensure vim was uninstalled
+ ansible.builtin.assert:
+ that:
+ - results is changed
+ - (results.packages | length) >= 1
+
+ - name: Install vim without cache
+ community.general.apk:
+ name: vim
+ state: present
+ no_cache: true
+ register: results
+
+ - name: Ensure vim was installed without cache
+ ansible.builtin.assert:
+ that:
+ - results is changed
+
+ - name: Install vim again without cache
+ community.general.apk:
+ name: vim
+ state: present
+ no_cache: true
+ register: results
+
+ - name: Ensure vim was not installed again without cache
+ ansible.builtin.assert:
+ that:
+ - results is not changed
+ - (results.packages | default([]) | length) == 0
+
+ - name: Ensure a bunch of packages aren't installed
+ community.general.apk:
+ name:
+ - less
+ - nano
+ - vim
+ state: absent
+
+ - name: Install a bunch of packages
+ community.general.apk:
+ name:
+ - less
+ - nano
+ - vim
+ state: present
+ register: results
+
+ - name: Ensure a bunch of packages were installed
+ ansible.builtin.assert:
+ that:
+ - results is changed
+ - (results.packages | length) >= 3
+
+ - name: Install a bunch of packages again
+ community.general.apk:
+ name:
+ - less
+ - nano
+ - vim
+ state: present
+ register: results
+
+ - name: Ensure a bunch of packages were not installed again
+ ansible.builtin.assert:
+ that:
+ - results is not changed
+ - (results.packages | default([]) | length) == 0
+
+ - name: Ensure a bunch of packages are not installed
+ community.general.apk:
+ name:
+ - less
+ - nano
+ - vim
+ state: absent
+ register: results
+
+ - name: Ensure a bunch of packages were uninstalled
+ ansible.builtin.assert:
+ that:
+ - results is changed
+ - (results.packages | length) >= 3
+
+ - name: Install a bunch of packages without cache
+ community.general.apk:
+ name:
+ - less
+ - nano
+ - vim
+ state: present
+ no_cache: true
+ register: results
+
+ - name: Ensure a bunch of packages were installed without cache
+ ansible.builtin.assert:
+ that:
+ - results is changed
+
+ - name: Install a bunch of packages again without cache
+ community.general.apk:
+ name:
+ - less
+ - nano
+ - vim
+ state: present
+ no_cache: true
+ register: results
+
+ - name: Ensure a bunch of packages were not installed again without cache
+ ansible.builtin.assert:
+ that:
+ - results is not changed
+ - (results.packages | default([]) | length) == 0
diff --git a/ansible_collections/community/general/tests/integration/targets/archive/tests/core.yml b/ansible_collections/community/general/tests/integration/targets/archive/tests/core.yml
index 1c4f4d1aa..21b07038f 100644
--- a/ansible_collections/community/general/tests/integration/targets/archive/tests/core.yml
+++ b/ansible_collections/community/general/tests/integration/targets/archive/tests/core.yml
@@ -29,7 +29,7 @@
that:
- archive_no_options is changed
- "archive_no_options.dest_state == 'archive'"
- - "{{ archive_no_options.archived | length }} == 3"
+ - "archive_no_options.archived | length == 3"
- name: Remove the archive - no options ({{ format }})
file:
@@ -54,7 +54,7 @@
that:
- archive_file_options_stat is not changed
- "archive_file_options.mode == '0600'"
- - "{{ archive_file_options.archived | length }} == 3"
+ - "archive_file_options.archived | length == 3"
- name: Remove the archive - file options ({{ format }})
file:
@@ -146,7 +146,7 @@
assert:
that:
- archive_path_list is changed
- - "{{ archive_path_list.archived | length }} == 3"
+ - "archive_path_list.archived | length == 3"
- name: Remove archive - path list ({{ format }})
file:
@@ -168,8 +168,8 @@
that:
- archive_missing_paths is changed
- "archive_missing_paths.dest_state == 'incomplete'"
- - "'{{ remote_tmp_dir }}/dne.txt' in archive_missing_paths.missing"
- - "'{{ remote_tmp_dir }}/foo.txt' not in archive_missing_paths.missing"
+ - "(remote_tmp_dir ~ '/dne.txt') in archive_missing_paths.missing"
+ - "(remote_tmp_dir ~ '/foo.txt') not in archive_missing_paths.missing"
- name: Remove archive - missing paths ({{ format }})
file:
diff --git a/ansible_collections/community/general/tests/integration/targets/archive/tests/remove.yml b/ansible_collections/community/general/tests/integration/targets/archive/tests/remove.yml
index 8f0b8cff8..a7e151d25 100644
--- a/ansible_collections/community/general/tests/integration/targets/archive/tests/remove.yml
+++ b/ansible_collections/community/general/tests/integration/targets/archive/tests/remove.yml
@@ -20,21 +20,28 @@
assert:
that:
- archive_remove_source_files is changed
- - "{{ archive_remove_source_files.archived | length }} == 3"
+ - "archive_remove_source_files.archived | length == 3"
- name: Remove Archive - remove source files ({{ format }})
file:
path: "{{ remote_tmp_dir }}/archive_remove_source_files.{{ format }}"
state: absent
-- name: Assert that source files were removed - remove source files ({{ format }})
- assert:
- that:
- - "'{{ remote_tmp_dir }}/{{ item }}' is not exists"
+- name: Remove source files in check mode ({{ format }})
+ file:
+ path: "{{ remote_tmp_dir }}/{{ item }}"
+ state: absent
+ check_mode: true
with_items:
- foo.txt
- bar.txt
- empty.txt
+ register: remove_files
+
+- name: Assert that source files were removed - remove source files ({{ format }})
+ assert:
+ that:
+ - remove_files is not changed
- name: Copy source files - remove source directory ({{ format }})
copy:
@@ -76,17 +83,24 @@
assert:
that:
- archive_remove_source_directory is changed
- - "{{ archive_remove_source_directory.archived | length }} == 3"
+ - "archive_remove_source_directory.archived | length == 3"
- name: Remove archive - remove source directory ({{ format }})
file:
path: "{{ remote_tmp_dir }}/archive_remove_source_directory.{{ format }}"
state: absent
+- name: Remove source source directory in check mode ({{ format }})
+ file:
+ path: "{{ remote_tmp_dir }}/tmpdir"
+ state: absent
+ check_mode: true
+ register: remove_dir
+
- name: Verify source directory was removed - remove source directory ({{ format }})
assert:
that:
- - "'{{ remote_tmp_dir }}/tmpdir' is not exists"
+ - remove_dir is not changed
- name: Create temporary directory - remove source excluding path ({{ format }})
file:
@@ -120,7 +134,7 @@
assert:
that:
- archive_remove_source_excluding_path is changed
- - "{{ archive_remove_source_excluding_path.archived | length }} == 2"
+ - "archive_remove_source_excluding_path.archived | length == 2"
- name: Remove archive - remove source excluding path ({{ format }})
file:
diff --git a/ansible_collections/community/general/tests/integration/targets/btrfs_subvolume/aliases b/ansible_collections/community/general/tests/integration/targets/btrfs_subvolume/aliases
index 914c36ad3..f5b6800db 100644
--- a/ansible_collections/community/general/tests/integration/targets/btrfs_subvolume/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/btrfs_subvolume/aliases
@@ -1,4 +1,4 @@
-# Copyright (c) Ansible Projec
+# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
diff --git a/ansible_collections/community/general/tests/integration/targets/callback_default_without_diff/aliases b/ansible_collections/community/general/tests/integration/targets/callback_default_without_diff/aliases
new file mode 100644
index 000000000..3e2dd244c
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/callback_default_without_diff/aliases
@@ -0,0 +1,6 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+azp/posix/3
+needs/target/callback
diff --git a/ansible_collections/community/general/tests/integration/targets/callback_default_without_diff/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/callback_default_without_diff/tasks/main.yml
new file mode 100644
index 000000000..5fc656e84
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/callback_default_without_diff/tasks/main.yml
@@ -0,0 +1,65 @@
+---
+####################################################################
+# WARNING: These are designed specifically for Ansible tests #
+# and should not be used as examples of how to write Ansible roles #
+####################################################################
+
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- block:
+ - name: Create temporary file
+ tempfile:
+ register: tempfile
+
+ - name: Run tests
+ include_role:
+ name: callback
+ vars:
+ tests:
+ - name: Basic file diff
+ environment:
+ ANSIBLE_NOCOLOR: 'true'
+ ANSIBLE_FORCE_COLOR: 'false'
+ ANSIBLE_DIFF_ALWAYS: 'true'
+ ANSIBLE_PYTHON_INTERPRETER: "{{ ansible_python_interpreter }}"
+ ANSIBLE_STDOUT_CALLBACK: community.general.default_without_diff
+ playbook: |
+ - hosts: testhost
+ gather_facts: true
+ tasks:
+ - name: Create file
+ copy:
+ dest: "{{ tempfile.path }}"
+ content: |
+ Foo bar
+
+ - name: Modify file
+ copy:
+ dest: "{{ tempfile.path }}"
+ content: |
+ Foo bar
+ Bar baz bam!
+ expected_output: [
+ "",
+ "PLAY [testhost] ****************************************************************",
+ "",
+ "TASK [Gathering Facts] *********************************************************",
+ "ok: [testhost]",
+ "",
+ "TASK [Create file] *************************************************************",
+ "changed: [testhost]",
+ "",
+ "TASK [Modify file] *************************************************************",
+ "changed: [testhost]",
+ "",
+ "PLAY RECAP *********************************************************************",
+ "testhost : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 ",
+ ]
+
+ always:
+ - name: Clean up temp file
+ file:
+ path: "{{ tempfile.path }}"
+ state: absent
diff --git a/ansible_collections/community/general/tests/integration/targets/cargo/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/cargo/tasks/main.yml
index bb22e27c0..29f27c3fd 100644
--- a/ansible_collections/community/general/tests/integration/targets/cargo/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/cargo/tasks/main.yml
@@ -18,3 +18,5 @@
- import_tasks: test_version.yml
environment: "{{ cargo_environment }}"
when: has_cargo | default(false)
+- import_tasks: test_rustup_cargo.yml
+ when: rustup_cargo_bin | default(false)
diff --git a/ansible_collections/community/general/tests/integration/targets/cargo/tasks/setup.yml b/ansible_collections/community/general/tests/integration/targets/cargo/tasks/setup.yml
index 232658ab4..7eec97ac4 100644
--- a/ansible_collections/community/general/tests/integration/targets/cargo/tasks/setup.yml
+++ b/ansible_collections/community/general/tests/integration/targets/cargo/tasks/setup.yml
@@ -26,3 +26,17 @@
has_cargo: true
when:
- ansible_system == 'FreeBSD' and ansible_distribution_version is version('13.0', '>')
+
+- block:
+ - name: Download rustup
+ get_url:
+ url: https://sh.rustup.rs
+ dest: /tmp/sh.rustup.rs
+ mode: "0750"
+ force: true
+ - name: Install rustup cargo
+ command: /tmp/sh.rustup.rs -y
+ - set_fact:
+ rustup_cargo_bin: "{{ lookup('env', 'HOME') }}/.cargo/bin/cargo"
+ when:
+ - ansible_distribution != 'CentOS' or ansible_distribution_version is version('7.0', '>=')
diff --git a/ansible_collections/community/general/tests/integration/targets/cargo/tasks/test_rustup_cargo.yml b/ansible_collections/community/general/tests/integration/targets/cargo/tasks/test_rustup_cargo.yml
new file mode 100644
index 000000000..ec2cf6e6d
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/cargo/tasks/test_rustup_cargo.yml
@@ -0,0 +1,23 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+- name: Install application helloworld
+ community.general.cargo:
+ executable: "{{ rustup_cargo_bin }}"
+ name: helloworld
+ register: rustup_install_absent_helloworld
+
+- name: Uninstall application helloworld
+ community.general.cargo:
+ executable: "{{ rustup_cargo_bin }}"
+ state: absent
+ name: helloworld
+ register: rustup_uninstall_present_helloworld
+
+- name: Check assertions helloworld
+ assert:
+ that:
+ - rustup_install_absent_helloworld is changed
+ - rustup_uninstall_present_helloworld is changed
diff --git a/ansible_collections/community/general/tests/integration/targets/cloud_init_data_facts/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/cloud_init_data_facts/tasks/main.yml
index 40e762d68..2b67b5c17 100644
--- a/ansible_collections/community/general/tests/integration/targets/cloud_init_data_facts/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/cloud_init_data_facts/tasks/main.yml
@@ -8,6 +8,14 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
+- name: Help debugging
+ debug:
+ msg: >-
+ distribution={{ ansible_distribution }},
+ distribution major version={{ ansible_distribution_major_version }},
+ os_family={{ ansible_os_family }},
+ Python version={{ ansible_python.version.major }}
+
- name: test cloud-init
# TODO: check for a workaround
# install 'cloud-init'' failed: dpkg-divert: error: `diversion of /etc/init/ureadahead.conf
@@ -15,10 +23,11 @@
# /etc/init/ureadahead.conf to /etc/init/ureadahead.conf.distrib
# https://bugs.launchpad.net/ubuntu/+source/ureadahead/+bug/997838
# Will also have to skip on OpenSUSE when running on Python 2 on newer Leap versions
- # (!= 42 and >= 15) ascloud-init will install the Python 3 package, breaking our build on py2.
+ # (!= 42 and >= 15) as cloud-init will install the Python 3 package, breaking our build on py2.
when:
- not (ansible_distribution == "Ubuntu" and ansible_distribution_major_version|int == 14)
- not (ansible_os_family == "Suse" and ansible_distribution_major_version|int != 42 and ansible_python.version.major != 3)
+ - not (ansible_os_family == "Suse" and ansible_distribution_major_version|int == 15)
- not (ansible_distribution == "CentOS" and ansible_distribution_major_version|int == 8) # TODO: cannot start service
- not (ansible_distribution == 'Archlinux') # TODO: package seems to be broken, cannot be downloaded from mirrors?
- not (ansible_distribution == 'Alpine') # TODO: not sure what's wrong here, the module doesn't return what the tests expect
diff --git a/ansible_collections/community/general/tests/integration/targets/cmd_runner/action_plugins/_unsafe_assert.py b/ansible_collections/community/general/tests/integration/targets/cmd_runner/action_plugins/_unsafe_assert.py
new file mode 100644
index 000000000..498e8258d
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/cmd_runner/action_plugins/_unsafe_assert.py
@@ -0,0 +1,56 @@
+# Copyright 2012, Dag Wieers <dag@wieers.com>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+from ansible.errors import AnsibleError
+from ansible.playbook.conditional import Conditional
+from ansible.plugins.action import ActionBase
+
+
+class ActionModule(ActionBase):
+ ''' Fail with custom message '''
+
+ _requires_connection = False
+
+ _VALID_ARGS = frozenset(('msg', 'that'))
+
+ def _make_safe(self, text):
+ # A simple str(text) won't do it since AnsibleUnsafeText is clever :-)
+ return ''.join(chr(ord(x)) for x in text)
+
+ def run(self, tmp=None, task_vars=None):
+ if task_vars is None:
+ task_vars = dict()
+
+ result = super(ActionModule, self).run(tmp, task_vars)
+ del tmp # tmp no longer has any effect
+
+ if 'that' not in self._task.args:
+ raise AnsibleError('conditional required in "that" string')
+
+ fail_msg = 'Assertion failed'
+ success_msg = 'All assertions passed'
+
+ thats = self._task.args['that']
+
+ cond = Conditional(loader=self._loader)
+ result['_ansible_verbose_always'] = True
+
+ for that in thats:
+ cond.when = [str(self._make_safe(that))]
+ test_result = cond.evaluate_conditional(templar=self._templar, all_vars=task_vars)
+ if not test_result:
+ result['failed'] = True
+ result['evaluated_to'] = test_result
+ result['assertion'] = that
+
+ result['msg'] = fail_msg
+
+ return result
+
+ result['changed'] = False
+ result['msg'] = success_msg
+ return result
diff --git a/ansible_collections/community/general/tests/integration/targets/cmd_runner/library/cmd_echo.py b/ansible_collections/community/general/tests/integration/targets/cmd_runner/library/cmd_echo.py
index cd8766264..ec0beb98e 100644
--- a/ansible_collections/community/general/tests/integration/targets/cmd_runner/library/cmd_echo.py
+++ b/ansible_collections/community/general/tests/integration/targets/cmd_runner/library/cmd_echo.py
@@ -21,11 +21,14 @@ from ansible_collections.community.general.plugins.module_utils.cmd_runner impor
def main():
module = AnsibleModule(
argument_spec=dict(
+ cmd=dict(type="str", default="echo"),
+ path_prefix=dict(type="str"),
arg_formats=dict(type="dict", default={}),
arg_order=dict(type="raw", required=True),
arg_values=dict(type="dict", default={}),
check_mode_skip=dict(type="bool", default=False),
aa=dict(type="raw"),
+ tt=dict(),
),
supports_check_mode=True,
)
@@ -40,7 +43,7 @@ def main():
arg_formats[arg] = func(*args)
- runner = CmdRunner(module, ['echo', '--'], arg_formats=arg_formats)
+ runner = CmdRunner(module, [module.params["cmd"], '--'], arg_formats=arg_formats, path_prefix=module.params["path_prefix"])
with runner.context(p['arg_order'], check_mode_skip=p['check_mode_skip']) as ctx:
result = ctx.run(**p['arg_values'])
diff --git a/ansible_collections/community/general/tests/integration/targets/cmd_runner/meta/main.yml b/ansible_collections/community/general/tests/integration/targets/cmd_runner/meta/main.yml
new file mode 100644
index 000000000..982de6eb0
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/cmd_runner/meta/main.yml
@@ -0,0 +1,7 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+dependencies:
+ - setup_remote_tmp_dir
diff --git a/ansible_collections/community/general/tests/integration/targets/cmd_runner/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/cmd_runner/tasks/main.yml
index 36ab039f0..e955c5d3d 100644
--- a/ansible_collections/community/general/tests/integration/targets/cmd_runner/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/cmd_runner/tasks/main.yml
@@ -6,3 +6,4 @@
ansible.builtin.include_tasks:
file: test_cmd_echo.yml
loop: "{{ cmd_echo_tests }}"
+ when: item.condition | default(true) | bool
diff --git a/ansible_collections/community/general/tests/integration/targets/cmd_runner/tasks/test_cmd_echo.yml b/ansible_collections/community/general/tests/integration/targets/cmd_runner/tasks/test_cmd_echo.yml
index 1c2caf2b5..a2a9fb8b7 100644
--- a/ansible_collections/community/general/tests/integration/targets/cmd_runner/tasks/test_cmd_echo.yml
+++ b/ansible_collections/community/general/tests/integration/targets/cmd_runner/tasks/test_cmd_echo.yml
@@ -3,17 +3,27 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
-- name: test cmd_echo [{{ item.name }}]
+- name: create copy of /bin/echo ({{ item.name }})
+ ansible.builtin.copy:
+ src: /bin/echo
+ dest: "{{ item.copy_to }}/echo"
+ mode: "0755"
+ remote_src: true
+ when: item.copy_to is defined
+
+- name: test cmd_echo module ({{ item.name }})
cmd_echo:
- arg_formats: "{{ item.arg_formats|default(omit) }}"
+ cmd: "{{ item.cmd | default(omit) }}"
+ path_prefix: "{{ item.path_prefix | default(omit) }}"
+ arg_formats: "{{ item.arg_formats | default(omit) }}"
arg_order: "{{ item.arg_order }}"
- arg_values: "{{ item.arg_values|default(omit) }}"
- check_mode_skip: "{{ item.check_mode_skip|default(omit) }}"
- aa: "{{ item.aa|default(omit) }}"
+ arg_values: "{{ item.arg_values | default(omit) }}"
+ check_mode_skip: "{{ item.check_mode_skip | default(omit) }}"
+ aa: "{{ item.aa | default(omit) }}"
register: test_result
- check_mode: "{{ item.check_mode|default(omit) }}"
- ignore_errors: "{{ item.expect_error|default(omit) }}"
+ check_mode: "{{ item.check_mode | default(omit) }}"
+ ignore_errors: "{{ item.expect_error | default(omit) }}"
-- name: check results [{{ item.name }}]
- assert:
+- name: check results ({{ item.name }})
+ _unsafe_assert:
that: "{{ item.assertions }}"
diff --git a/ansible_collections/community/general/tests/integration/targets/cmd_runner/vars/main.yml b/ansible_collections/community/general/tests/integration/targets/cmd_runner/vars/main.yml
index 7f0027d49..f9a715338 100644
--- a/ansible_collections/community/general/tests/integration/targets/cmd_runner/vars/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/cmd_runner/vars/main.yml
@@ -121,3 +121,142 @@ cmd_echo_tests:
- test_result.rc == None
- test_result.out == None
- test_result.err == None
+
+ - name: set aa and tt value
+ arg_formats:
+ aa:
+ func: as_opt_eq_val
+ args: [--answer]
+ tt:
+ func: as_opt_val
+ args: [--tt-arg]
+ arg_order: 'aa tt'
+ arg_values:
+ tt: potatoes
+ aa: 11
+ assertions:
+ - test_result.rc == 0
+ - test_result.out == "-- --answer=11 --tt-arg potatoes\n"
+ - test_result.err == ""
+
+ - name: use cmd echo
+ cmd: echo
+ arg_formats:
+ aa:
+ func: as_opt_eq_val
+ args: [--answer]
+ tt:
+ func: as_opt_val
+ args: [--tt-arg]
+ arg_order: 'aa tt'
+ arg_values:
+ tt: potatoes
+ aa: 11
+ assertions:
+ - test_result.rc == 0
+ - test_result.out == "-- --answer=11 --tt-arg potatoes\n"
+ - test_result.err == ""
+
+ - name: use cmd /bin/echo
+ cmd: /bin/echo
+ arg_formats:
+ aa:
+ func: as_opt_eq_val
+ args: [--answer]
+ tt:
+ func: as_opt_val
+ args: [--tt-arg]
+ arg_order: 'aa tt'
+ arg_values:
+ tt: potatoes
+ aa: 11
+ assertions:
+ - test_result.rc == 0
+ - test_result.out == "-- --answer=11 --tt-arg potatoes\n"
+ - test_result.err == ""
+
+ # this will not be in the regular set of paths get_bin_path() searches
+ - name: use cmd {{ remote_tmp_dir }}/echo
+ condition: >
+ {{
+ ansible_distribution != "MacOSX" and
+ not (ansible_distribution == "CentOS" and ansible_distribution_major_version is version('7.0', '<'))
+ }}
+ copy_to: "{{ remote_tmp_dir }}"
+ cmd: "{{ remote_tmp_dir }}/echo"
+ arg_formats:
+ aa:
+ func: as_opt_eq_val
+ args: [--answer]
+ tt:
+ func: as_opt_val
+ args: [--tt-arg]
+ arg_order: 'aa tt'
+ arg_values:
+ tt: potatoes
+ aa: 11
+ assertions:
+ - test_result.rc == 0
+ - test_result.out == "-- --answer=11 --tt-arg potatoes\n"
+ - test_result.err == ""
+
+ - name: use cmd echo with path_prefix {{ remote_tmp_dir }}
+ cmd: echo
+ condition: >
+ {{
+ ansible_distribution != "MacOSX" and
+ not (ansible_distribution == "CentOS" and ansible_distribution_major_version is version('7.0', '<'))
+ }}
+ copy_to: "{{ remote_tmp_dir }}"
+ path_prefix: "{{ remote_tmp_dir }}"
+ arg_formats:
+ aa:
+ func: as_opt_eq_val
+ args: [--answer]
+ tt:
+ func: as_opt_val
+ args: [--tt-arg]
+ arg_order: 'aa tt'
+ arg_values:
+ tt: potatoes
+ aa: 11
+ assertions:
+ - test_result.rc == 0
+ - test_result.out == "-- --answer=11 --tt-arg potatoes\n"
+ - test_result.err == ""
+
+ - name: use cmd never-existed
+ cmd: never-existed
+ arg_formats:
+ aa:
+ func: as_opt_eq_val
+ args: [--answer]
+ tt:
+ func: as_opt_val
+ args: [--tt-arg]
+ arg_order: 'aa tt'
+ arg_values:
+ tt: potatoes
+ aa: 11
+ expect_error: true
+ assertions:
+ - >
+ "Failed to find required executable" in test_result.msg
+
+ - name: use cmd /usr/bin/never-existed
+ cmd: /usr/bin/never-existed
+ arg_formats:
+ aa:
+ func: as_opt_eq_val
+ args: [--answer]
+ tt:
+ func: as_opt_val
+ args: [--tt-arg]
+ arg_order: 'aa tt'
+ arg_values:
+ tt: potatoes
+ aa: 11
+ expect_error: true
+ assertions:
+ - >
+ "No such file or directory" in test_result.msg
diff --git a/ansible_collections/community/general/tests/integration/targets/connection_incus/aliases b/ansible_collections/community/general/tests/integration/targets/connection_incus/aliases
new file mode 100644
index 000000000..5a0c47032
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/connection_incus/aliases
@@ -0,0 +1,6 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+non_local
+unsupported
diff --git a/ansible_collections/community/general/tests/integration/targets/connection_incus/runme.sh b/ansible_collections/community/general/tests/integration/targets/connection_incus/runme.sh
new file mode 100755
index 000000000..9f31da64d
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/connection_incus/runme.sh
@@ -0,0 +1,21 @@
+#!/usr/bin/env bash
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+set -eux
+
+# Connection tests for POSIX platforms use this script by linking to it from the appropriate 'connection_' target dir.
+# The name of the inventory group to test is extracted from the directory name following the 'connection_' prefix.
+
+group=$(python -c \
+ "from os import path; print(path.basename(path.abspath(path.dirname('$0'))).replace('connection_', ''))")
+
+cd ../connection
+
+INVENTORY="../connection_${group}/test_connection.inventory" ./test.sh \
+ -e target_hosts="${group}" \
+ -e action_prefix= \
+ -e local_tmp=/tmp/ansible-local \
+ -e remote_tmp=/tmp/ansible-remote \
+ "$@"
diff --git a/ansible_collections/community/general/tests/integration/targets/connection_incus/test_connection.inventory b/ansible_collections/community/general/tests/integration/targets/connection_incus/test_connection.inventory
new file mode 100644
index 000000000..84b69faf7
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/connection_incus/test_connection.inventory
@@ -0,0 +1,11 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+[incus]
+incus-pipelining ansible_ssh_pipelining=true
+incus-no-pipelining ansible_ssh_pipelining=false
+[incus:vars]
+ansible_host=ubuntu-2204
+ansible_connection=community.general.incus
+ansible_python_interpreter=python3
diff --git a/ansible_collections/community/general/tests/integration/targets/consul/tasks/consul_auth_method.yml b/ansible_collections/community/general/tests/integration/targets/consul/tasks/consul_auth_method.yml
new file mode 100644
index 000000000..611d67309
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/consul/tasks/consul_auth_method.yml
@@ -0,0 +1,74 @@
+---
+# Copyright (c) 2024, Florian Apolloner (@apollo13)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Create an auth method
+ community.general.consul_auth_method:
+ name: test
+ type: jwt
+ config:
+ jwt_validation_pubkeys:
+ - |
+ -----BEGIN PUBLIC KEY-----
+ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu1SU1LfVLPHCozMxH2Mo
+ 4lgOEePzNm0tRgeLezV6ffAt0gunVTLw7onLRnrq0/IzW7yWR7QkrmBL7jTKEn5u
+ +qKhbwKfBstIs+bMY2Zkp18gnTxKLxoS2tFczGkPLPgizskuemMghRniWaoLcyeh
+ kd3qqGElvW/VDL5AaWTg0nLVkjRo9z+40RQzuVaE8AkAFmxZzow3x+VJYKdjykkJ
+ 0iT9wCS0DRTXu269V264Vf/3jvredZiKRkgwlL9xNAwxXFg0x/XFw005UWVRIkdg
+ cKWTjpBP2dPwVZ4WWC+9aGVd+Gyn1o0CLelf4rEjGoXbAAEgAqeGUxrcIlbjXfbc
+ mwIDAQAB
+ -----END PUBLIC KEY-----
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.auth_method.Type == 'jwt'
+ - result.operation == 'create'
+
+- name: Update auth method
+ community.general.consul_auth_method:
+ name: test
+ max_token_ttl: 30m80s
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.auth_method.Type == 'jwt'
+ - result.operation == 'update'
+
+- name: Update auth method (noop)
+ community.general.consul_auth_method:
+ name: test
+ max_token_ttl: 30m80s
+ register: result
+
+- assert:
+ that:
+ - result is not changed
+ - result.auth_method.Type == 'jwt'
+ - result.operation is not defined
+
+- name: Delete auth method
+ community.general.consul_auth_method:
+ name: test
+ state: absent
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.operation == 'remove'
+
+- name: Delete auth method (noop)
+ community.general.consul_auth_method:
+ name: test
+ state: absent
+ register: result
+
+- assert:
+ that:
+ - result is not changed
+ - result.operation is not defined
diff --git a/ansible_collections/community/general/tests/integration/targets/consul/tasks/consul_binding_rule.yml b/ansible_collections/community/general/tests/integration/targets/consul/tasks/consul_binding_rule.yml
new file mode 100644
index 000000000..218daf982
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/consul/tasks/consul_binding_rule.yml
@@ -0,0 +1,73 @@
+---
+# Copyright (c) 2024, Florian Apolloner (@apollo13)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Create an auth method
+ community.general.consul_auth_method:
+ name: test
+ type: jwt
+ config:
+ jwt_validation_pubkeys:
+ - |
+ -----BEGIN PUBLIC KEY-----
+ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu1SU1LfVLPHCozMxH2Mo
+ 4lgOEePzNm0tRgeLezV6ffAt0gunVTLw7onLRnrq0/IzW7yWR7QkrmBL7jTKEn5u
+ +qKhbwKfBstIs+bMY2Zkp18gnTxKLxoS2tFczGkPLPgizskuemMghRniWaoLcyeh
+ kd3qqGElvW/VDL5AaWTg0nLVkjRo9z+40RQzuVaE8AkAFmxZzow3x+VJYKdjykkJ
+ 0iT9wCS0DRTXu269V264Vf/3jvredZiKRkgwlL9xNAwxXFg0x/XFw005UWVRIkdg
+ cKWTjpBP2dPwVZ4WWC+9aGVd+Gyn1o0CLelf4rEjGoXbAAEgAqeGUxrcIlbjXfbc
+ mwIDAQAB
+ -----END PUBLIC KEY-----
+
+- name: Create a binding rule
+ community.general.consul_binding_rule:
+ name: test-binding
+ description: my description
+ auth_method: test
+ bind_type: service
+ bind_name: yolo
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.binding_rule.AuthMethod == 'test'
+ - result.binding.Description == 'test-binding: my description'
+ - result.operation == 'create'
+
+- name: Update a binding rule
+ community.general.consul_binding_rule:
+ name: test-binding
+ auth_method: test
+ bind_name: yolo2
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.binding.Description == 'test-binding: my description'
+ - result.operation == 'update'
+
+- name: Update a binding rule (noop)
+ community.general.consul_binding_rule:
+ name: test-binding
+ auth_method: test
+ register: result
+
+- assert:
+ that:
+ - result is not changed
+ - result.binding.Description == 'test-binding: my description'
+ - result.operation is not defined
+
+- name: Delete a binding rule
+ community.general.consul_binding_rule:
+ name: test-binding
+ auth_method: test
+ state: absent
+ register: result
+- assert:
+ that:
+ - result is changed
+ - result.operation == 'remove' \ No newline at end of file
diff --git a/ansible_collections/community/general/tests/integration/targets/consul/tasks/consul_general.yml b/ansible_collections/community/general/tests/integration/targets/consul/tasks/consul_general.yml
new file mode 100644
index 000000000..2fc28efc2
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/consul/tasks/consul_general.yml
@@ -0,0 +1,76 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: ensure unknown scheme fails
+ consul_session:
+ state: info
+ id: dummy
+ scheme: non_existent
+ token: "{{ consul_management_token }}"
+ register: result
+ ignore_errors: true
+
+- assert:
+ that:
+ - result is failed
+
+- name: ensure SSL certificate is checked
+ consul_session:
+ state: info
+ id: dummy
+ port: 8501
+ scheme: https
+ token: "{{ consul_management_token }}"
+ register: result
+ ignore_errors: true
+
+- name: previous task should fail since certificate is not known
+ assert:
+ that:
+ - result is failed
+ - "'certificate verify failed' in result.msg"
+
+- name: ensure SSL certificate isn't checked when validate_certs is disabled
+ consul_session:
+ state: info
+ id: dummy
+ port: 8501
+ scheme: https
+ token: "{{ consul_management_token }}"
+ validate_certs: false
+ register: result
+
+- name: previous task should succeed since certificate isn't checked
+ assert:
+ that:
+ - result is changed
+
+- name: ensure a secure connection is possible
+ consul_session:
+ state: info
+ id: dummy
+ port: 8501
+ scheme: https
+ token: "{{ consul_management_token }}"
+ ca_path: '{{ remote_dir }}/cert.pem'
+ register: result
+
+- assert:
+ that:
+ - result is changed
+
+- name: ensure connection errors are handled properly
+ consul_session:
+ state: info
+ id: dummy
+ token: "{{ consul_management_token }}"
+ port: 1234
+ register: result
+ ignore_errors: true
+
+- assert:
+ that:
+ - result is failed
+ - result.msg.startswith('Could not connect to consul agent at localhost:1234, error was')
diff --git a/ansible_collections/community/general/tests/integration/targets/consul/tasks/consul_kv.yml b/ansible_collections/community/general/tests/integration/targets/consul/tasks/consul_kv.yml
new file mode 100644
index 000000000..6cca73137
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/consul/tasks/consul_kv.yml
@@ -0,0 +1,57 @@
+---
+# Copyright (c) 2024, Florian Apolloner (@apollo13)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Create a key
+ consul_kv:
+ key: somekey
+ value: somevalue
+ token: "{{ consul_management_token }}"
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.data.Value == 'somevalue'
+
+#- name: Test the lookup
+# assert:
+# that:
+# - lookup('community.general.consul_kv', 'somekey', token=consul_management_token) == 'somevalue'
+
+- name: Update a key with the same data
+ consul_kv:
+ key: somekey
+ value: somevalue
+ token: "{{ consul_management_token }}"
+ register: result
+
+- assert:
+ that:
+ - result is not changed
+ - result.data.Value == 'somevalue'
+
+- name: Remove a key from the store
+ consul_kv:
+ key: somekey
+ state: absent
+ token: "{{ consul_management_token }}"
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.data.Value == 'somevalue'
+
+- name: Remove a non-existant key from the store
+ consul_kv:
+ key: somekey
+ state: absent
+ token: "{{ consul_management_token }}"
+ register: result
+
+- assert:
+ that:
+ - result is not changed
+ - not result.data \ No newline at end of file
diff --git a/ansible_collections/community/general/tests/integration/targets/consul/tasks/consul_policy.yml b/ansible_collections/community/general/tests/integration/targets/consul/tasks/consul_policy.yml
new file mode 100644
index 000000000..336324f03
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/consul/tasks/consul_policy.yml
@@ -0,0 +1,72 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Create a policy with rules
+ consul_policy:
+ name: foo-access
+ rules: |
+ key "foo" {
+ policy = "read"
+ }
+ key "private/foo" {
+ policy = "deny"
+ }
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.policy.Name == 'foo-access'
+ - result.operation == 'create'
+
+- name: Update the rules associated to a policy
+ consul_policy:
+ name: foo-access
+ rules: |
+ key "foo" {
+ policy = "read"
+ }
+ key "private/foo" {
+ policy = "deny"
+ }
+ event "bbq" {
+ policy = "write"
+ }
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.operation == 'update'
+
+- name: Update reports not changed when updating again without changes
+ consul_policy:
+ name: foo-access
+ rules: |
+ key "foo" {
+ policy = "read"
+ }
+ key "private/foo" {
+ policy = "deny"
+ }
+ event "bbq" {
+ policy = "write"
+ }
+ register: result
+
+- assert:
+ that:
+ - result is not changed
+ - result.operation is not defined
+
+- name: Remove a policy
+ consul_policy:
+ name: foo-access
+ state: absent
+ register: result
+- assert:
+ that:
+ - result is changed
+ - result.operation == 'remove' \ No newline at end of file
diff --git a/ansible_collections/community/general/tests/integration/targets/consul/tasks/consul_role.yml b/ansible_collections/community/general/tests/integration/targets/consul/tasks/consul_role.yml
new file mode 100644
index 000000000..9b0504e0b
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/consul/tasks/consul_role.yml
@@ -0,0 +1,194 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Create a policy with rules
+ consul_policy:
+ name: foo-access-for-role
+ rules: |
+ key "foo" {
+ policy = "read"
+ }
+ key "private/foo" {
+ policy = "deny"
+ }
+ register: policy_result
+
+- name: Create another policy with rules
+ consul_policy:
+ name: bar-access-for-role
+ rules: |
+ key "bar" {
+ policy = "read"
+ }
+ key "private/bar" {
+ policy = "deny"
+ }
+ register: policy_result
+
+- name: Create a role with policy
+ consul_role:
+ name: foo-role-with-policy
+ policies:
+ - name: "foo-access-for-role"
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.role.Name == 'foo-role-with-policy'
+ - result.operation == 'create'
+
+- name: Update policy description, in check mode
+ consul_role:
+ name: foo-role-with-policy
+ description: "Testing updating description"
+ check_mode: yes
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.role.Description == "Testing updating description"
+ - result.role.Policies.0.Name == 'foo-access-for-role'
+ - result.operation == 'update'
+
+- name: Update policy to add the description
+ consul_role:
+ name: foo-role-with-policy
+ description: "Role for testing policies"
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.role.Description == "Role for testing policies"
+ - result.role.Policies.0.Name == 'foo-access-for-role'
+ - result.operation == 'update'
+
+- name: Update the role with another policy, also testing leaving description blank
+ consul_role:
+ name: foo-role-with-policy
+ policies:
+ - name: "foo-access-for-role"
+ - name: "bar-access-for-role"
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.role.Policies.0.Name == 'foo-access-for-role'
+ - result.role.Policies.1.Name == 'bar-access-for-role'
+ - result.role.Description == "Role for testing policies"
+ - result.operation == 'update'
+
+- name: Create a role with service identity
+ consul_role:
+ name: role-with-service-identity
+ service_identities:
+ - name: web
+ datacenters:
+ - dc1
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.role.ServiceIdentities.0.ServiceName == "web"
+ - result.role.ServiceIdentities.0.Datacenters.0 == "dc1"
+
+- name: Update the role with service identity in check mode
+ consul_role:
+ name: role-with-service-identity
+ service_identities:
+ - name: web
+ datacenters:
+ - dc2
+ register: result
+ check_mode: yes
+
+- assert:
+ that:
+ - result is changed
+ - result.role.ServiceIdentities.0.ServiceName == "web"
+ - result.role.ServiceIdentities.0.Datacenters.0 == "dc2"
+
+- name: Update the role with service identity to add a policy, leaving the service id unchanged
+ consul_role:
+ name: role-with-service-identity
+ policies:
+ - name: "foo-access-for-role"
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.role.ServiceIdentities.0.ServiceName == "web"
+ - result.role.ServiceIdentities.0.Datacenters.0 == "dc1"
+ - result.role.Policies.0.Name == 'foo-access-for-role'
+
+- name: Update the role with service identity to remove the policies
+ consul_role:
+ name: role-with-service-identity
+ policies: []
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.role.ServiceIdentities.0.ServiceName == "web"
+ - result.role.ServiceIdentities.0.Datacenters.0 == "dc1"
+ - result.role.Policies is not defined
+
+- name: Update the role with service identity to remove the node identities, in check mode
+ consul_role:
+ name: role-with-service-identity
+ node_identities: []
+ register: result
+ check_mode: yes
+
+- assert:
+ that:
+ - result is changed
+ - result.role.ServiceIdentities.0.ServiceName == "web"
+ - result.role.ServiceIdentities.0.Datacenters.0 == "dc1"
+ - result.role.Policies is not defined
+ - result.role.NodeIdentities == [] # in check mode the cleared field is returned as an empty array
+
+- name: Update the role with service identity to remove the service identities
+ consul_role:
+ name: role-with-service-identity
+ service_identities: []
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.role.ServiceIdentities is not defined # in normal mode the dictionary is removed from the result
+ - result.role.Policies is not defined
+
+- name: Create a role with node identity
+ consul_role:
+ name: role-with-node-identity
+ node_identities:
+ - name: node-1
+ datacenter: dc2
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.role.NodeIdentities.0.NodeName == "node-1"
+ - result.role.NodeIdentities.0.Datacenter == "dc2"
+
+- name: Remove the last role
+ consul_role:
+ name: role-with-node-identity
+ state: absent
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.operation == 'remove' \ No newline at end of file
diff --git a/ansible_collections/community/general/tests/integration/targets/consul/tasks/consul_session.yml b/ansible_collections/community/general/tests/integration/targets/consul/tasks/consul_session.yml
index 543668964..7f852a36d 100644
--- a/ansible_collections/community/general/tests/integration/targets/consul/tasks/consul_session.yml
+++ b/ansible_collections/community/general/tests/integration/targets/consul/tasks/consul_session.yml
@@ -52,7 +52,7 @@
- name: ensure session was created
assert:
that:
- - test_session_found|default(False)
+ - test_session_found|default(false)
- name: fetch info about a session
consul_session:
@@ -75,61 +75,6 @@
that:
- result is failed
-- name: ensure unknown scheme fails
- consul_session:
- state: info
- id: '{{ session_id }}'
- scheme: non_existent
- register: result
- ignore_errors: true
-
-- assert:
- that:
- - result is failed
-
-- name: ensure SSL certificate is checked
- consul_session:
- state: info
- id: '{{ session_id }}'
- port: 8501
- scheme: https
- register: result
- ignore_errors: true
-
-- name: previous task should fail since certificate is not known
- assert:
- that:
- - result is failed
- - "'certificate verify failed' in result.msg"
-
-- name: ensure SSL certificate isn't checked when validate_certs is disabled
- consul_session:
- state: info
- id: '{{ session_id }}'
- port: 8501
- scheme: https
- validate_certs: false
- register: result
-
-- name: previous task should succeed since certificate isn't checked
- assert:
- that:
- - result is changed
-
-- name: ensure a secure connection is possible
- consul_session:
- state: info
- id: '{{ session_id }}'
- port: 8501
- scheme: https
- environment:
- REQUESTS_CA_BUNDLE: '{{ remote_dir }}/cert.pem'
- register: result
-
-- assert:
- that:
- - result is changed
-
- name: delete a session
consul_session:
state: absent
diff --git a/ansible_collections/community/general/tests/integration/targets/consul/tasks/consul_token.yml b/ansible_collections/community/general/tests/integration/targets/consul/tasks/consul_token.yml
new file mode 100644
index 000000000..9b3679ef1
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/consul/tasks/consul_token.yml
@@ -0,0 +1,88 @@
+---
+# Copyright (c) 2024, Florian Apolloner (@apollo13)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Create a policy with rules
+ community.general.consul_policy:
+ name: "{{ item }}"
+ rules: |
+ key "foo" {
+ policy = "read"
+ }
+ loop:
+ - foo-access
+ - foo-access2
+
+- name: Create token without accessor
+ community.general.consul_token:
+ state: present
+ register: simple_create_result
+
+- assert:
+ that:
+ - simple_create_result is changed
+ - simple_create_result.token.AccessorID
+ - simple_create_result.operation == 'create'
+
+- name: Create token
+ community.general.consul_token:
+ state: present
+ accessor_id: 07a7de84-c9c7-448a-99cc-beaf682efd21
+ service_identities:
+ - service_name: test
+ datacenters: [test1, test2]
+ node_identities:
+ - node_name: test
+ datacenter: test
+ policies:
+ - name: foo-access
+ - name: foo-access2
+ expiration_ttl: 1h
+ register: create_result
+
+- assert:
+ that:
+ - create_result is changed
+ - create_result.token.AccessorID == "07a7de84-c9c7-448a-99cc-beaf682efd21"
+ - create_result.operation == 'create'
+
+- name: Update token
+ community.general.consul_token:
+ state: present
+ accessor_id: 07a7de84-c9c7-448a-99cc-beaf682efd21
+ description: Testing
+ policies:
+ - id: "{{ create_result.token.Policies[-1].ID }}"
+ service_identities: []
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.operation == 'update'
+
+- name: Update token (noop)
+ community.general.consul_token:
+ state: present
+ accessor_id: 07a7de84-c9c7-448a-99cc-beaf682efd21
+ policies:
+ - id: "{{ create_result.token.Policies[-1].ID }}"
+ register: result
+
+- assert:
+ that:
+ - result is not changed
+ - result.operation is not defined
+
+- name: Remove token
+ community.general.consul_token:
+ state: absent
+ accessor_id: 07a7de84-c9c7-448a-99cc-beaf682efd21
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - not result.token
+ - result.operation == 'remove'
diff --git a/ansible_collections/community/general/tests/integration/targets/consul/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/consul/tasks/main.yml
index a2b63ac95..6fef2b998 100644
--- a/ansible_collections/community/general/tests/integration/targets/consul/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/consul/tasks/main.yml
@@ -10,8 +10,8 @@
- name: Install Consul and test
vars:
- consul_version: 1.5.0
- consul_uri: https://s3.amazonaws.com/ansible-ci-files/test/integration/targets/consul/consul_{{ consul_version }}_{{ ansible_system | lower }}_{{ consul_arch }}.zip
+ consul_version: 1.13.2
+ consul_uri: https://releases.hashicorp.com/consul/{{ consul_version }}/consul_{{ consul_version }}_{{ ansible_system | lower }}_{{ consul_arch }}.zip
consul_cmd: '{{ remote_tmp_dir }}/consul'
block:
- name: Install requests<2.20 (CentOS/RHEL 6)
@@ -76,14 +76,32 @@
dest: '{{ remote_tmp_dir }}/consul_config.hcl'
- name: Start Consul (dev mode enabled)
shell: nohup {{ consul_cmd }} agent -dev -config-file {{ remote_tmp_dir }}/consul_config.hcl </dev/null >/dev/null 2>&1 &
+ - name: Bootstrap ACL
+ consul_acl_bootstrap:
+ register: consul_bootstrap_result
+ - set_fact:
+ consul_management_token: '{{ consul_bootstrap_result.result.SecretID }}'
- name: Create some data
- command: '{{ consul_cmd }} kv put data/value{{ item }} foo{{ item }}'
+ command: '{{ consul_cmd }} kv put -token={{consul_management_token}} data/value{{ item }} foo{{ item }}'
loop:
- 1
- 2
- 3
- - import_tasks: consul_session.yml
+ - import_tasks: consul_general.yml
+ - import_tasks: consul_kv.yml
+
+ - block:
+ - import_tasks: consul_session.yml
+ - import_tasks: consul_policy.yml
+ - import_tasks: consul_role.yml
+ - import_tasks: consul_token.yml
+ - import_tasks: consul_auth_method.yml
+ - import_tasks: consul_binding_rule.yml
+ module_defaults:
+ group/community.general.consul:
+ token: "{{ consul_management_token }}"
+
always:
- name: Kill consul process
shell: kill $(cat {{ remote_tmp_dir }}/consul.pid)
- ignore_errors: true
+ ignore_errors: true \ No newline at end of file
diff --git a/ansible_collections/community/general/tests/integration/targets/consul/templates/consul_config.hcl.j2 b/ansible_collections/community/general/tests/integration/targets/consul/templates/consul_config.hcl.j2
index 96da5d664..91bfb08ae 100644
--- a/ansible_collections/community/general/tests/integration/targets/consul/templates/consul_config.hcl.j2
+++ b/ansible_collections/community/general/tests/integration/targets/consul/templates/consul_config.hcl.j2
@@ -12,3 +12,8 @@ ports {
}
key_file = "{{ remote_dir }}/privatekey.pem"
cert_file = "{{ remote_dir }}/cert.pem"
+acl {
+ enabled = true
+ default_policy = "deny"
+ down_policy = "extend-cache"
+}
diff --git a/ansible_collections/community/general/tests/integration/targets/copr/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/copr/tasks/main.yml
index 0e4651724..0d6637811 100644
--- a/ansible_collections/community/general/tests/integration/targets/copr/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/copr/tasks/main.yml
@@ -10,12 +10,6 @@
ansible_distribution == 'Fedora'
or (ansible_os_family == 'RedHat' and ansible_distribution != 'Fedora'
and ansible_distribution_major_version | int >= 8)
- # The copr module imports dnf which is only available for the system Python
- # interpreter.
- - >
- not (ansible_distribution == 'CentOS' and
- ansible_distribution_major_version | int == 8 and not
- ansible_python_version.startswith('3.6'))
block:
- debug: var=copr_chroot
- name: enable copr project
diff --git a/ansible_collections/community/general/tests/integration/targets/deploy_helper/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/deploy_helper/tasks/main.yml
index fdd8bd87b..9bd5f4150 100644
--- a/ansible_collections/community/general/tests/integration/targets/deploy_helper/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/deploy_helper/tasks/main.yml
@@ -17,25 +17,25 @@
assert:
that:
- "'project_path' in deploy_helper"
- - "deploy_helper.current_path == '{{ deploy_helper.project_path }}/current'"
- - "deploy_helper.releases_path == '{{ deploy_helper.project_path }}/releases'"
- - "deploy_helper.shared_path == '{{ deploy_helper.project_path }}/shared'"
+ - "deploy_helper.current_path == deploy_helper.project_path ~ '/current'"
+ - "deploy_helper.releases_path == deploy_helper.project_path ~ '/releases'"
+ - "deploy_helper.shared_path == deploy_helper.project_path ~ '/shared'"
- "deploy_helper.unfinished_filename == 'DEPLOY_UNFINISHED'"
- "'previous_release' in deploy_helper"
- "'previous_release_path' in deploy_helper"
- "'new_release' in deploy_helper"
- "'new_release_path' in deploy_helper"
- - "deploy_helper.new_release_path == '{{ deploy_helper.releases_path }}/{{ deploy_helper.new_release }}'"
+ - "deploy_helper.new_release_path == deploy_helper.releases_path ~ '/' ~ deploy_helper.new_release"
- name: State=query with relative overridden paths
deploy_helper: path={{ deploy_helper_test_root }} current_path=CURRENT_PATH releases_path=RELEASES_PATH shared_path=SHARED_PATH state=query
- name: Assert State=query with relative overridden paths
assert:
that:
- - "deploy_helper.current_path == '{{ deploy_helper.project_path }}/CURRENT_PATH'"
- - "deploy_helper.releases_path == '{{ deploy_helper.project_path }}/RELEASES_PATH'"
- - "deploy_helper.shared_path == '{{ deploy_helper.project_path }}/SHARED_PATH'"
- - "deploy_helper.new_release_path == '{{ deploy_helper.releases_path }}/{{ deploy_helper.new_release}}'"
+ - "deploy_helper.current_path == deploy_helper.project_path ~ '/CURRENT_PATH'"
+ - "deploy_helper.releases_path == deploy_helper.project_path ~ '/RELEASES_PATH'"
+ - "deploy_helper.shared_path == deploy_helper.project_path ~ '/SHARED_PATH'"
+ - "deploy_helper.new_release_path == deploy_helper.releases_path ~ '/' ~ deploy_helper.new_release"
- name: State=query with absolute overridden paths
deploy_helper: path={{ deploy_helper_test_root }} current_path=/CURRENT_PATH releases_path=/RELEASES_PATH shared_path=/SHARED_PATH state=query
@@ -45,7 +45,7 @@
- "deploy_helper.current_path == '/CURRENT_PATH'"
- "deploy_helper.releases_path == '/RELEASES_PATH'"
- "deploy_helper.shared_path == '/SHARED_PATH'"
- - "deploy_helper.new_release_path == '{{ deploy_helper.releases_path }}/{{ deploy_helper.new_release}}'"
+ - "deploy_helper.new_release_path == deploy_helper.releases_path ~ '/' ~ deploy_helper.new_release"
- name: State=query with overridden unfinished_filename
deploy_helper: path={{ deploy_helper_test_root }} unfinished_filename=UNFINISHED_DEPLOY state=query
diff --git a/ansible_collections/community/general/tests/integration/targets/django_manage/aliases b/ansible_collections/community/general/tests/integration/targets/django_manage/aliases
index 98aed9e9d..979054916 100644
--- a/ansible_collections/community/general/tests/integration/targets/django_manage/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/django_manage/aliases
@@ -11,5 +11,10 @@ skip/rhel8.2
skip/rhel8.3
skip/rhel8.4
skip/rhel8.5
+skip/rhel8.6
+skip/rhel8.7
+skip/rhel8.8
skip/rhel9.0
skip/rhel9.1
+skip/rhel9.2
+skip/rhel9.3
diff --git a/ansible_collections/community/general/tests/integration/targets/ejabberd_user/aliases b/ansible_collections/community/general/tests/integration/targets/ejabberd_user/aliases
new file mode 100644
index 000000000..11c37f6bb
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/ejabberd_user/aliases
@@ -0,0 +1,11 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+azp/posix/3
+skip/osx
+skip/macos
+skip/freebsd
+skip/alpine
+skip/rhel
+destructive
diff --git a/ansible_collections/community/general/tests/integration/targets/ejabberd_user/handlers/main.yml b/ansible_collections/community/general/tests/integration/targets/ejabberd_user/handlers/main.yml
new file mode 100644
index 000000000..16eed4733
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/ejabberd_user/handlers/main.yml
@@ -0,0 +1,9 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+---
+- name: Remove ejabberd
+ ansible.builtin.package:
+ name: ejabberd
+ state: absent
diff --git a/ansible_collections/community/general/tests/integration/targets/ejabberd_user/meta/main.yml b/ansible_collections/community/general/tests/integration/targets/ejabberd_user/meta/main.yml
new file mode 100644
index 000000000..2fcd152f9
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/ejabberd_user/meta/main.yml
@@ -0,0 +1,7 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+dependencies:
+ - setup_pkg_mgr
diff --git a/ansible_collections/community/general/tests/integration/targets/ejabberd_user/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/ejabberd_user/tasks/main.yml
new file mode 100644
index 000000000..33e07b785
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/ejabberd_user/tasks/main.yml
@@ -0,0 +1,122 @@
+---
+####################################################################
+# WARNING: These are designed specifically for Ansible tests #
+# and should not be used as examples of how to write Ansible roles #
+####################################################################
+
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Bail out if not supported
+ ansible.builtin.meta: end_play
+ when: ansible_distribution in ('Alpine', 'openSUSE Leap', 'CentOS', 'Fedora')
+
+
+- name: Remove ejabberd
+ ansible.builtin.package:
+ name: ejabberd
+ state: absent
+
+- name: Create user without ejabberdctl installed
+ community.general.ejabberd_user:
+ host: localhost
+ username: alice
+ password: pa$$w0rd
+ state: present
+ register: user_no_ejabberdctl
+ ignore_errors: true
+
+- name: Install ejabberd
+ ansible.builtin.package:
+ name: ejabberd
+ state: present
+ notify: Remove ejabberd
+
+- name: Make runnable on Arch
+ community.general.ini_file:
+ path: /usr/lib/systemd/system/ejabberd.service
+ section: Service
+ option: "{{ item }}"
+ state: absent
+ loop:
+ - PrivateDevices
+ - AmbientCapabilities
+ when: ansible_distribution == 'Archlinux'
+
+- name: Make installable on Arch
+ systemd:
+ daemon_reload: true
+ when: ansible_distribution == 'Archlinux'
+
+- ansible.builtin.service:
+ name: ejabberd
+ state: started
+
+- name: Create user alice (check)
+ community.general.ejabberd_user:
+ host: localhost
+ username: alice
+ password: pa$$w0rd
+ state: present
+ check_mode: true
+ register: user_alice_check
+
+- name: Create user alice
+ community.general.ejabberd_user:
+ host: localhost
+ username: alice
+ password: pa$$w0rd
+ state: present
+ register: user_alice
+
+- name: Create user alice (idempotency)
+ community.general.ejabberd_user:
+ host: localhost
+ username: alice
+ password: pa$$w0rd
+ state: present
+ register: user_alice_idempot
+
+- name: Create user alice (change password)
+ community.general.ejabberd_user:
+ host: localhost
+ username: alice
+ password: different_pa$$w0rd
+ state: present
+ register: user_alice_chgpw
+
+- name: Remove user alice (check)
+ community.general.ejabberd_user:
+ host: localhost
+ username: alice
+ state: absent
+ register: remove_alice_check
+ check_mode: true
+
+- name: Remove user alice
+ community.general.ejabberd_user:
+ host: localhost
+ username: alice
+ state: absent
+ register: remove_alice
+
+- name: Remove user alice (idempotency)
+ community.general.ejabberd_user:
+ host: localhost
+ username: alice
+ state: absent
+ register: remove_alice_idempot
+
+- name: Assertions
+ ansible.builtin.assert:
+ that:
+ - user_no_ejabberdctl is failed
+ - "'Failed to find required executable' in user_no_ejabberdctl.msg"
+ - user_alice_check is changed
+ - user_alice is changed
+ - user_alice_idempot is not changed
+ - user_alice_chgpw is changed
+ - remove_alice_check is changed
+ - remove_alice is changed
+ - remove_alice_idempot is not changed
diff --git a/ansible_collections/community/general/tests/integration/targets/etcd3/aliases b/ansible_collections/community/general/tests/integration/targets/etcd3/aliases
index 264446580..78b1fff07 100644
--- a/ansible_collections/community/general/tests/integration/targets/etcd3/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/etcd3/aliases
@@ -8,5 +8,4 @@ skip/aix
skip/osx
skip/macos
skip/freebsd
-skip/python2.6 # installing etcd3 python module will fail on python < 2.7
disabled # see https://github.com/ansible-collections/community.general/issues/322
diff --git a/ansible_collections/community/general/tests/integration/targets/filesize/tasks/sparse.yml b/ansible_collections/community/general/tests/integration/targets/filesize/tasks/sparse.yml
index 79145b6e2..348a1eea1 100644
--- a/ansible_collections/community/general/tests/integration/targets/filesize/tasks/sparse.yml
+++ b/ansible_collections/community/general/tests/integration/targets/filesize/tasks/sparse.yml
@@ -5,10 +5,10 @@
# Test module with sparse files
-- name: Create a huge sparse file of 4TB (check mode)
+- name: Create a huge sparse file of 2TB (check mode)
community.general.filesize:
path: "{{ filesize_testfile }}"
- size: 4TB
+ size: 2TB
sparse: true
register: filesize_test_sparse_01
check_mode: true
@@ -20,10 +20,10 @@
register: filesize_stat_sparse_01
-- name: Create a huge sparse file of 4TB
+- name: Create a huge sparse file of 2TB
community.general.filesize:
path: "{{ filesize_testfile }}"
- size: 4TB
+ size: 2TB
sparse: true
register: filesize_test_sparse_02
@@ -34,34 +34,34 @@
register: filesize_stat_sparse_02
-- name: Create a huge sparse file of 4TB (4000GB) (check mode, idempotency)
+- name: Create a huge sparse file of 2TB (2000GB) (check mode, idempotency)
community.general.filesize:
path: "{{ filesize_testfile }}"
- size: 4000GB
+ size: 2000GB
sparse: true
register: filesize_test_sparse_03
check_mode: true
-- name: Create a huge sparse file of 4TB (4000GB) (idempotency)
+- name: Create a huge sparse file of 2TB (2000GB) (idempotency)
community.general.filesize:
path: "{{ filesize_testfile }}"
- size: 4000GB
+ size: 2000GB
sparse: true
register: filesize_test_sparse_04
-- name: Create a huge sparse file of 4TB (4000000 × 1MB) (check mode, idempotency)
+- name: Create a huge sparse file of 2TB (2000000 × 1MB) (check mode, idempotency)
community.general.filesize:
path: "{{ filesize_testfile }}"
- size: 4000000
+ size: 2000000
blocksize: 1MB
sparse: true
register: filesize_test_sparse_05
check_mode: true
-- name: Create a huge sparse file of 4TB (4000000 × 1MB) (idempotency)
+- name: Create a huge sparse file of 2TB (2000000 × 1MB) (idempotency)
community.general.filesize:
path: "{{ filesize_testfile }}"
- size: 4000000
+ size: 2000000
blocksize: 1MB
sparse: true
register: filesize_test_sparse_06
@@ -89,15 +89,15 @@
- filesize_test_sparse_05.cmd is undefined
- filesize_test_sparse_06.cmd is undefined
- - filesize_test_sparse_01.filesize.bytes == 4*1000**4
- - filesize_test_sparse_02.filesize.bytes == 4*1000**4
- - filesize_test_sparse_03.filesize.bytes == 4*1000**4
- - filesize_test_sparse_04.filesize.bytes == 4*1000**4
- - filesize_test_sparse_05.filesize.bytes == 4*1000**4
- - filesize_test_sparse_06.filesize.bytes == 4*1000**4
+ - filesize_test_sparse_01.filesize.bytes == 2*1000**4
+ - filesize_test_sparse_02.filesize.bytes == 2*1000**4
+ - filesize_test_sparse_03.filesize.bytes == 2*1000**4
+ - filesize_test_sparse_04.filesize.bytes == 2*1000**4
+ - filesize_test_sparse_05.filesize.bytes == 2*1000**4
+ - filesize_test_sparse_06.filesize.bytes == 2*1000**4
- - filesize_test_sparse_01.size_diff == 4*1000**4
- - filesize_test_sparse_02.size_diff == 4*1000**4
+ - filesize_test_sparse_01.size_diff == 2*1000**4
+ - filesize_test_sparse_02.size_diff == 2*1000**4
- filesize_test_sparse_03.size_diff == 0
- filesize_test_sparse_04.size_diff == 0
- filesize_test_sparse_05.size_diff == 0
@@ -106,24 +106,24 @@
- filesize_test_sparse_01.state is undefined
- filesize_test_sparse_02.state in ["file"]
- filesize_test_sparse_01.size is undefined
- - filesize_test_sparse_02.size == 4*1000**4
- - filesize_test_sparse_03.size == 4*1000**4
- - filesize_test_sparse_04.size == 4*1000**4
- - filesize_test_sparse_05.size == 4*1000**4
- - filesize_test_sparse_06.size == 4*1000**4
+ - filesize_test_sparse_02.size == 2*1000**4
+ - filesize_test_sparse_03.size == 2*1000**4
+ - filesize_test_sparse_04.size == 2*1000**4
+ - filesize_test_sparse_05.size == 2*1000**4
+ - filesize_test_sparse_06.size == 2*1000**4
- not filesize_stat_sparse_01.stat.exists
- filesize_stat_sparse_02.stat.exists
- filesize_stat_sparse_02.stat.isreg
- - filesize_stat_sparse_02.stat.size == 4*1000**4
- - filesize_stat_sparse_06.stat.size == 4*1000**4
+ - filesize_stat_sparse_02.stat.size == 2*1000**4
+ - filesize_stat_sparse_06.stat.size == 2*1000**4
-- name: Change sparse file size to 4TiB (check mode)
+- name: Change sparse file size to 2TiB (check mode)
community.general.filesize:
path: "{{ filesize_testfile }}"
- size: 4TiB
+ size: 2TiB
sparse: true
register: filesize_test_sparse_11
check_mode: true
@@ -135,10 +135,10 @@
register: filesize_stat_sparse_11
-- name: Change sparse file size to 4TiB
+- name: Change sparse file size to 2TiB
community.general.filesize:
path: "{{ filesize_testfile }}"
- size: 4TiB
+ size: 2TiB
sparse: true
register: filesize_test_sparse_12
@@ -149,18 +149,18 @@
register: filesize_stat_sparse_12
-- name: Change sparse file size to 4TiB (4096GiB) (check mode, idempotency)
+- name: Change sparse file size to 2TiB (2048GiB) (check mode, idempotency)
community.general.filesize:
path: "{{ filesize_testfile }}"
- size: 4096GiB
+ size: 2048GiB
sparse: true
register: filesize_test_sparse_13
check_mode: true
-- name: Change sparse file size to 4TiB (4096GiB) (idempotency)
+- name: Change sparse file size to 2TiB (2048GiB) (idempotency)
community.general.filesize:
path: "{{ filesize_testfile }}"
- size: 4096GiB
+ size: 2048GiB
sparse: true
register: filesize_test_sparse_14
@@ -183,26 +183,26 @@
- filesize_test_sparse_13.cmd is undefined
- filesize_test_sparse_14.cmd is undefined
- - filesize_test_sparse_11.size_diff == 398046511104
- - filesize_test_sparse_12.size_diff == 398046511104
+ - filesize_test_sparse_11.size_diff == 199023255552
+ - filesize_test_sparse_12.size_diff == 199023255552
- filesize_test_sparse_13.size_diff == 0
- filesize_test_sparse_14.size_diff == 0
- - filesize_test_sparse_11.size == 4000000000000
- - filesize_test_sparse_12.size == 4398046511104
- - filesize_test_sparse_13.size == 4398046511104
- - filesize_test_sparse_14.size == 4398046511104
+ - filesize_test_sparse_11.size == 2000000000000
+ - filesize_test_sparse_12.size == 2199023255552
+ - filesize_test_sparse_13.size == 2199023255552
+ - filesize_test_sparse_14.size == 2199023255552
- - filesize_stat_sparse_11.stat.size == 4000000000000
- - filesize_stat_sparse_12.stat.size == 4398046511104
- - filesize_stat_sparse_14.stat.size == 4398046511104
+ - filesize_stat_sparse_11.stat.size == 2000000000000
+ - filesize_stat_sparse_12.stat.size == 2199023255552
+ - filesize_stat_sparse_14.stat.size == 2199023255552
-- name: Change sparse file size to 4.321TB (check mode)
+- name: Change sparse file size to 2.321TB (check mode)
community.general.filesize:
path: "{{ filesize_testfile }}"
- size: 4.321TB
+ size: 2.321TB
sparse: true
register: filesize_test_sparse_21
check_mode: true
@@ -214,10 +214,10 @@
register: filesize_stat_sparse_21
-- name: Change sparse file size to 4.321TB
+- name: Change sparse file size to 2.321TB
community.general.filesize:
path: "{{ filesize_testfile }}"
- size: 4.321TB
+ size: 2.321TB
sparse: true
register: filesize_test_sparse_22
@@ -228,19 +228,19 @@
register: filesize_stat_sparse_22
-- name: Change sparse file size to 4321×1GB (check mode, idempotency)
+- name: Change sparse file size to 2321×1GB (check mode, idempotency)
community.general.filesize:
path: "{{ filesize_testfile }}"
- size: 4321
+ size: 2321
blocksize: 1GB
sparse: true
register: filesize_test_sparse_23
check_mode: true
-- name: Change sparse file size to 4321×1GB (idempotency)
+- name: Change sparse file size to 2321×1GB (idempotency)
community.general.filesize:
path: "{{ filesize_testfile }}"
- size: 4321
+ size: 2321
blocksize: 1GB
sparse: true
register: filesize_test_sparse_24
@@ -264,19 +264,19 @@
- filesize_test_sparse_23.cmd is undefined
- filesize_test_sparse_24.cmd is undefined
- - filesize_test_sparse_21.size_diff == 4321*1000**3 - 4*1024**4
- - filesize_test_sparse_22.size_diff == 4321*1000**3 - 4*1024**4
+ - filesize_test_sparse_21.size_diff == 2321*1000**3 - 2*1024**4
+ - filesize_test_sparse_22.size_diff == 2321*1000**3 - 2*1024**4
- filesize_test_sparse_23.size_diff == 0
- filesize_test_sparse_24.size_diff == 0
- - filesize_test_sparse_21.size == 4398046511104
- - filesize_test_sparse_22.size == 4321000000000
- - filesize_test_sparse_23.size == 4321000000000
- - filesize_test_sparse_24.size == 4321000000000
+ - filesize_test_sparse_21.size == 2199023255552
+ - filesize_test_sparse_22.size == 2321000000000
+ - filesize_test_sparse_23.size == 2321000000000
+ - filesize_test_sparse_24.size == 2321000000000
- - filesize_stat_sparse_21.stat.size == 4398046511104
- - filesize_stat_sparse_22.stat.size == 4321000000000
- - filesize_stat_sparse_24.stat.size == 4321000000000
+ - filesize_stat_sparse_21.stat.size == 2199023255552
+ - filesize_stat_sparse_22.stat.size == 2321000000000
+ - filesize_stat_sparse_24.stat.size == 2321000000000
diff --git a/ansible_collections/community/general/tests/integration/targets/filesystem/defaults/main.yml b/ansible_collections/community/general/tests/integration/targets/filesystem/defaults/main.yml
index 0448d8602..ec446d241 100644
--- a/ansible_collections/community/general/tests/integration/targets/filesystem/defaults/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/filesystem/defaults/main.yml
@@ -11,23 +11,23 @@ tested_filesystems:
# - XFS: 20Mo
# - Btrfs: 150Mo (50Mo when "--metadata single" is used and 100Mb when on newer Fedora versions)
# - f2fs:
- # - 1.2.0 requires at leat 116Mo
+ # - 1.2.0 requires at least 116Mo
# - 1.7.0 requires at least 30Mo
# - 1.10.0 requires at least 38Mo
# - resizefs asserts when initial fs is smaller than 60Mo and seems to require 1.10.0
- ext4: {fssize: 10, grow: true}
- ext4dev: {fssize: 10, grow: true}
- ext3: {fssize: 10, grow: true}
- ext2: {fssize: 10, grow: true}
- xfs: {fssize: 300, grow: false} # grow requires a mounted filesystem
- btrfs: {fssize: 150, grow: false} # grow requires a mounted filesystem
- reiserfs: {fssize: 33, grow: false} # grow not implemented
- vfat: {fssize: 20, grow: true}
- ocfs2: {fssize: '{{ ocfs2_fssize }}', grow: false} # grow not implemented
- f2fs: {fssize: '{{ f2fs_fssize|default(60) }}', grow: 'f2fs_version is version("1.10.0", ">=")'}
- lvm: {fssize: 20, grow: true}
- swap: {fssize: 10, grow: false} # grow not implemented
- ufs: {fssize: 10, grow: true}
+ ext4: {fssize: 10, grow: true, new_uuid: 'random'}
+ ext4dev: {fssize: 10, grow: true, new_uuid: 'random'}
+ ext3: {fssize: 10, grow: true, new_uuid: 'random'}
+ ext2: {fssize: 10, grow: true, new_uuid: 'random'}
+ xfs: {fssize: 300, grow: false, new_uuid: 'generate'} # grow requires a mounted filesystem
+ btrfs: {fssize: 150, grow: false, new_uuid: null} # grow requires a mounted filesystem
+ reiserfs: {fssize: 33, grow: false, new_uuid: null} # grow not implemented
+ vfat: {fssize: 20, grow: true, new_uuid: null}
+ ocfs2: {fssize: '{{ ocfs2_fssize }}', grow: false, new_uuid: null} # grow not implemented
+ f2fs: {fssize: '{{ f2fs_fssize|default(60) }}', grow: 'f2fs_version is version("1.10.0", ">=")', new_uuid: null}
+ lvm: {fssize: 20, grow: true, new_uuid: 'something'}
+ swap: {fssize: 10, grow: false, new_uuid: null} # grow not implemented
+ ufs: {fssize: 10, grow: true, new_uuid: null}
get_uuid_any: "blkid -c /dev/null -o value -s UUID {{ dev }}"
diff --git a/ansible_collections/community/general/tests/integration/targets/filesystem/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/filesystem/tasks/main.yml
index 0ff0f2309..0c15c2155 100644
--- a/ansible_collections/community/general/tests/integration/targets/filesystem/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/filesystem/tasks/main.yml
@@ -29,6 +29,7 @@
fstype: '{{ item.0.key }}'
fssize: '{{ item.0.value.fssize }}'
grow: '{{ item.0.value.grow }}'
+ new_uuid: '{{ item.0.value.new_uuid }}'
action: '{{ item.1 }}'
when:
# FreeBSD limited support
@@ -83,7 +84,7 @@
# TODO: something seems to be broken on Alpine
- 'not (ansible_distribution == "Alpine")'
- loop: "{{ query('dict', tested_filesystems)|product(['create_fs', 'overwrite_another_fs', 'remove_fs'])|list }}"
+ loop: "{{ query('dict', tested_filesystems)|product(['create_fs', 'reset_fs_uuid', 'overwrite_another_fs', 'remove_fs', 'set_fs_uuid_on_creation', 'set_fs_uuid_on_creation_with_opts'])|list }}"
# With FreeBSD extended support (util-linux is not available before 12.2)
diff --git a/ansible_collections/community/general/tests/integration/targets/filesystem/tasks/reset_fs_uuid.yml b/ansible_collections/community/general/tests/integration/targets/filesystem/tasks/reset_fs_uuid.yml
new file mode 100644
index 000000000..77dad2203
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/filesystem/tasks/reset_fs_uuid.yml
@@ -0,0 +1,59 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# Skip UUID reset tests for FreeBSD due to "xfs_admin: only 'rewrite' supported on V5 fs"
+- when:
+ - new_uuid | default(False)
+ - not (ansible_system == "FreeBSD" and fstype == "xfs")
+ block:
+ - name: "Create filesystem ({{ fstype }})"
+ community.general.filesystem:
+ dev: '{{ dev }}'
+ fstype: '{{ fstype }}'
+ register: fs_result
+
+ - name: "Get UUID of created filesystem"
+ ansible.builtin.shell:
+ cmd: "{{ get_uuid_cmd }}"
+ changed_when: false
+ register: uuid
+
+ - name: "Reset filesystem ({{ fstype }}) UUID"
+ community.general.filesystem:
+ dev: '{{ dev }}'
+ fstype: '{{ fstype }}'
+ uuid: "{{ new_uuid }}"
+ register: fs_resetuuid_result
+
+ - name: "Get UUID of the filesystem"
+ ansible.builtin.shell:
+ cmd: "{{ get_uuid_cmd }}"
+ changed_when: false
+ register: uuid2
+
+ - name: "Assert that filesystem UUID is changed"
+ ansible.builtin.assert:
+ that:
+ - 'fs_resetuuid_result is changed'
+ - 'fs_resetuuid_result is success'
+ - 'uuid.stdout != uuid2.stdout'
+
+ - when:
+ - (grow | bool and (fstype != "vfat" or resize_vfat)) or
+ (fstype == "xfs" and ansible_system == "Linux" and
+ ansible_distribution not in ["CentOS", "Ubuntu"])
+ block:
+ - name: "Reset filesystem ({{ fstype }}) UUID and resizefs"
+ ignore_errors: true
+ community.general.filesystem:
+ dev: '{{ dev }}'
+ fstype: '{{ fstype }}'
+ uuid: "{{ new_uuid }}"
+ resizefs: true
+ register: fs_resetuuid_and_resizefs_result
+
+ - name: "Assert that filesystem UUID reset and resizefs failed"
+ ansible.builtin.assert:
+ that: fs_resetuuid_and_resizefs_result is failed
diff --git a/ansible_collections/community/general/tests/integration/targets/filesystem/tasks/set_fs_uuid_on_creation.yml b/ansible_collections/community/general/tests/integration/targets/filesystem/tasks/set_fs_uuid_on_creation.yml
new file mode 100644
index 000000000..f52c44d65
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/filesystem/tasks/set_fs_uuid_on_creation.yml
@@ -0,0 +1,44 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: "Generate a random UUID"
+ ansible.builtin.set_fact:
+ random_uuid: '{{ "first_random_uuid" | ansible.builtin.to_uuid }}'
+
+# Skip UUID set at creation tests for FreeBSD due to "xfs_admin: only 'rewrite' supported on V5 fs"
+- when:
+ - new_uuid | default(False)
+ - not (ansible_system == "FreeBSD" and fstype == "xfs")
+ block:
+ - name: "Create filesystem ({{ fstype }}) with UUID"
+ community.general.filesystem:
+ dev: '{{ dev }}'
+ fstype: '{{ fstype }}'
+ uuid: '{{ random_uuid }}'
+ register: fs_result
+
+ - name: "Get UUID of the created filesystem"
+ ansible.builtin.shell:
+ cmd: "{{ get_uuid_cmd }}"
+ changed_when: false
+ register: uuid
+
+ - name: "Assert that filesystem UUID is the random UUID set on creation"
+ ansible.builtin.assert:
+ that: (random_uuid | replace('-','')) == ( uuid.stdout | replace('-',''))
+
+- when: not (new_uuid | default(False))
+ block:
+ - name: "Create filesystem ({{ fstype }}) without UUID support"
+ ignore_errors: true
+ community.general.filesystem:
+ dev: '{{ dev }}'
+ fstype: '{{ fstype }}'
+ uuid: '{{ random_uuid }}'
+ register: fs_result
+
+ - name: "Assert that filesystem creation failed"
+ ansible.builtin.assert:
+ that: fs_result is failed
diff --git a/ansible_collections/community/general/tests/integration/targets/filesystem/tasks/set_fs_uuid_on_creation_with_opts.yml b/ansible_collections/community/general/tests/integration/targets/filesystem/tasks/set_fs_uuid_on_creation_with_opts.yml
new file mode 100644
index 000000000..fc73e57ee
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/filesystem/tasks/set_fs_uuid_on_creation_with_opts.yml
@@ -0,0 +1,33 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# UUID set at creation with opts for XFS is not supported
+- when:
+ - new_uuid | default(False)
+ - fstype != "xfs"
+ block:
+
+ - name: "Generate random UUIDs"
+ ansible.builtin.set_fact:
+ random_uuid: '{{ "first_random_uuid" | ansible.builtin.to_uuid }}'
+ random_uuid2: '{{ "second_random_uuid" | ansible.builtin.to_uuid }}'
+
+ - name: "Create filesystem ({{ fstype }}) with fix UUID as opt"
+ community.general.filesystem:
+ dev: '{{ dev }}'
+ fstype: '{{ fstype }}'
+ opts: "{{ ((fstype == 'lvm') | ansible.builtin.ternary('--norestorefile --uuid ', '-U ')) + random_uuid2 }}"
+ uuid: '{{ random_uuid }}'
+ register: fs_result2
+
+ - name: "Get UUID of the created filesystem"
+ ansible.builtin.shell:
+ cmd: "{{ get_uuid_cmd }}"
+ changed_when: false
+ register: uuid2
+
+ - name: "Assert that filesystem UUID is the one set on creation with opt"
+ ansible.builtin.assert:
+ that: (random_uuid2 | replace('-','')) == ( uuid2.stdout | replace('-',''))
diff --git a/ansible_collections/community/general/tests/integration/targets/filter_counter/aliases b/ansible_collections/community/general/tests/integration/targets/filter_counter/aliases
index bc9b4bc99..12d1d6617 100644
--- a/ansible_collections/community/general/tests/integration/targets/filter_counter/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/filter_counter/aliases
@@ -3,4 +3,3 @@
# SPDX-License-Identifier: GPL-3.0-or-later
azp/posix/2
-skip/python2.6 # filters are controller only, and we no longer support Python 2.6 on the controller
diff --git a/ansible_collections/community/general/tests/integration/targets/filter_dict/aliases b/ansible_collections/community/general/tests/integration/targets/filter_dict/aliases
index e8051e042..343f119da 100644
--- a/ansible_collections/community/general/tests/integration/targets/filter_dict/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/filter_dict/aliases
@@ -3,4 +3,3 @@
# SPDX-License-Identifier: GPL-3.0-or-later
azp/posix/3
-skip/python2.6 # filters are controller only, and we no longer support Python 2.6 on the controller
diff --git a/ansible_collections/community/general/tests/integration/targets/filter_dict_kv/aliases b/ansible_collections/community/general/tests/integration/targets/filter_dict_kv/aliases
index bc9b4bc99..12d1d6617 100644
--- a/ansible_collections/community/general/tests/integration/targets/filter_dict_kv/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/filter_dict_kv/aliases
@@ -3,4 +3,3 @@
# SPDX-License-Identifier: GPL-3.0-or-later
azp/posix/2
-skip/python2.6 # filters are controller only, and we no longer support Python 2.6 on the controller
diff --git a/ansible_collections/community/general/tests/integration/targets/filter_from_csv/aliases b/ansible_collections/community/general/tests/integration/targets/filter_from_csv/aliases
index bc9b4bc99..12d1d6617 100644
--- a/ansible_collections/community/general/tests/integration/targets/filter_from_csv/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/filter_from_csv/aliases
@@ -3,4 +3,3 @@
# SPDX-License-Identifier: GPL-3.0-or-later
azp/posix/2
-skip/python2.6 # filters are controller only, and we no longer support Python 2.6 on the controller
diff --git a/ansible_collections/community/general/tests/integration/targets/filter_from_ini/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/filter_from_ini/tasks/main.yml
new file mode 100644
index 000000000..a2eca36a6
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/filter_from_ini/tasks/main.yml
@@ -0,0 +1,60 @@
+---
+# Copyright (c) 2023, Steffen Scheib <steffen@scheib.me>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: 'Define ini_test_dict'
+ ansible.builtin.set_fact:
+ ini_test_dict:
+ section_name:
+ key_name: 'key value'
+
+ another_section:
+ connection: 'ssh'
+
+- name: 'Write INI file that reflects ini_test_dict to {{ ini_test_file }}'
+ ansible.builtin.copy:
+ dest: '{{ ini_test_file }}'
+ content: |
+ [section_name]
+ key_name=key value
+
+ [another_section]
+ connection=ssh
+
+- name: 'Slurp the test file: {{ ini_test_file }}'
+ ansible.builtin.slurp:
+ src: '{{ ini_test_file }}'
+ register: 'ini_file_content'
+
+- name: >-
+ Ensure defined ini_test_dict is the same when retrieved
+ from {{ ini_test_file }}
+ ansible.builtin.assert:
+ that:
+ - 'ini_file_content.content | b64decode | community.general.from_ini ==
+ ini_test_dict'
+
+- name: 'Create a file that is not INI formatted: {{ ini_bad_file }}'
+ ansible.builtin.copy:
+ dest: '{{ ini_bad_file }}'
+ content: |
+ Testing a not INI formatted file.
+
+- name: 'Slurp the file that is not INI formatted: {{ ini_bad_file }}'
+ ansible.builtin.slurp:
+ src: '{{ ini_bad_file }}'
+ register: 'ini_bad_file_content'
+
+- name: 'Try parsing the bad file with from_ini: {{ ini_bad_file }}'
+ ansible.builtin.debug:
+ var: ini_bad_file_content | b64decode | community.general.from_ini
+ register: 'ini_bad_file_debug'
+ ignore_errors: true
+
+- name: 'Ensure from_ini raised the correct exception'
+ ansible.builtin.assert:
+ that:
+ - "'from_ini failed to parse given string' in ini_bad_file_debug.msg"
+ - "'File contains no section headers' in ini_bad_file_debug.msg"
+...
diff --git a/ansible_collections/community/general/tests/integration/targets/filter_from_ini/vars/main.yml b/ansible_collections/community/general/tests/integration/targets/filter_from_ini/vars/main.yml
new file mode 100644
index 000000000..8c4d79327
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/filter_from_ini/vars/main.yml
@@ -0,0 +1,8 @@
+---
+# Copyright (c) 2023, Steffen Scheib <steffen@scheib.me>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+ini_test_file: '/tmp/test.ini'
+ini_bad_file: '/tmp/bad.file'
+...
diff --git a/ansible_collections/community/general/tests/integration/targets/filter_groupby_as_dict/aliases b/ansible_collections/community/general/tests/integration/targets/filter_groupby_as_dict/aliases
index e8051e042..343f119da 100644
--- a/ansible_collections/community/general/tests/integration/targets/filter_groupby_as_dict/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/filter_groupby_as_dict/aliases
@@ -3,4 +3,3 @@
# SPDX-License-Identifier: GPL-3.0-or-later
azp/posix/3
-skip/python2.6 # filters are controller only, and we no longer support Python 2.6 on the controller
diff --git a/ansible_collections/community/general/tests/integration/targets/filter_hashids/aliases b/ansible_collections/community/general/tests/integration/targets/filter_hashids/aliases
index bc9b4bc99..12d1d6617 100644
--- a/ansible_collections/community/general/tests/integration/targets/filter_hashids/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/filter_hashids/aliases
@@ -3,4 +3,3 @@
# SPDX-License-Identifier: GPL-3.0-or-later
azp/posix/2
-skip/python2.6 # filters are controller only, and we no longer support Python 2.6 on the controller
diff --git a/ansible_collections/community/general/tests/integration/targets/filter_jc/aliases b/ansible_collections/community/general/tests/integration/targets/filter_jc/aliases
index 0e799090e..4e1151566 100644
--- a/ansible_collections/community/general/tests/integration/targets/filter_jc/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/filter_jc/aliases
@@ -3,5 +3,6 @@
# SPDX-License-Identifier: GPL-3.0-or-later
azp/posix/2
-skip/python2.6 # filters are controller only, and we no longer support Python 2.6 on the controller
skip/python2.7 # jc only supports python3.x
+skip/freebsd13.3 # FIXME - ruyaml compilation fails
+skip/freebsd14.0 # FIXME - ruyaml compilation fails
diff --git a/ansible_collections/community/general/tests/integration/targets/filter_json_query/aliases b/ansible_collections/community/general/tests/integration/targets/filter_json_query/aliases
index cee9abd2c..dadd9f37a 100644
--- a/ansible_collections/community/general/tests/integration/targets/filter_json_query/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/filter_json_query/aliases
@@ -3,5 +3,4 @@
# SPDX-License-Identifier: GPL-3.0-or-later
azp/posix/2
-skip/python2.6 # filters are controller only, and we no longer support Python 2.6 on the controller
skip/aix
diff --git a/ansible_collections/community/general/tests/integration/targets/filter_lists/aliases b/ansible_collections/community/general/tests/integration/targets/filter_lists/aliases
new file mode 100644
index 000000000..12d1d6617
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/filter_lists/aliases
@@ -0,0 +1,5 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+azp/posix/2
diff --git a/ansible_collections/community/general/tests/integration/targets/filter_lists/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/filter_lists/tasks/main.yml
new file mode 100644
index 000000000..a146e1293
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/filter_lists/tasks/main.yml
@@ -0,0 +1,64 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Test predictive list union
+ ansible.builtin.assert:
+ that:
+ - 'list1 | community.general.lists_union(list2, list3) == [1, 2, 5, 3, 4, 10, 11, 99, 101]'
+ - '[list1, list2, list3] | community.general.lists_union(flatten=True) == [1, 2, 5, 3, 4, 10, 11, 99, 101]'
+ - '[1, 2, 3] | community.general.lists_union([4, 5, 6]) == [1, 2, 3, 4, 5, 6]'
+ - '[1, 2, 3] | community.general.lists_union([3, 4, 5, 6]) == [1, 2, 3, 4, 5, 6]'
+ - '[1, 2, 3] | community.general.lists_union([3, 2, 1]) == [1, 2, 3]'
+ - '["a", "A", "b"] | community.general.lists_union(["B", "c", "C"]) == ["a", "A", "b", "B", "c", "C"]'
+ - '["a", "A", "b"] | community.general.lists_union(["b", "B", "c", "C"]) == ["a", "A", "b", "B", "c", "C"]'
+ - '["a", "A", "b"] | community.general.lists_union(["b", "A", "a"]) == ["a", "A", "b"]'
+ - '[["a"]] | community.general.lists_union([["b"], ["a"]]) == [["a"], ["b"]]'
+ - '[["a"]] | community.general.lists_union([["b"]], ["a"]) == [["a"], ["b"], "a"]'
+ - '[["a"]] | community.general.lists_union(["b"], ["a"]) == [["a"], "b", "a"]'
+
+- name: Test predictive list intersection
+ ansible.builtin.assert:
+ that:
+ - 'list1 | community.general.lists_intersect(list2, list3) == [1, 2, 5, 4]'
+ - '[list1, list2, list3] | community.general.lists_intersect(flatten=True) == [1, 2, 5, 4]'
+ - '[1, 2, 3] | community.general.lists_intersect([4, 5, 6]) == []'
+ - '[1, 2, 3] | community.general.lists_intersect([3, 4, 5, 6]) == [3]'
+ - '[1, 2, 3] | community.general.lists_intersect([3, 2, 1]) == [1, 2, 3]'
+ - '["a", "A", "b"] | community.general.lists_intersect(["B", "c", "C"]) == []'
+ - '["a", "A", "b"] | community.general.lists_intersect(["b", "B", "c", "C"]) == ["b"]'
+ - '["a", "A", "b"] | community.general.lists_intersect(["b", "A", "a"]) == ["a", "A", "b"]'
+ - '[["a"]] | community.general.lists_intersect([["b"], ["a"]]) == [["a"]]'
+ - '[["a"]] | community.general.lists_intersect([["b"]], ["a"]) == []'
+ - '[["a"]] | community.general.lists_intersect(["b"], ["a"]) == []'
+
+- name: Test predictive list difference
+ ansible.builtin.assert:
+ that:
+ - 'list1 | community.general.lists_difference(list2, list3) == []'
+ - '[list1, list2, list3] | community.general.lists_difference(flatten=True) == []'
+ - '[1, 2, 3] | community.general.lists_difference([4, 5, 6]) == [1, 2, 3]'
+ - '[1, 2, 3] | community.general.lists_difference([3, 4, 5, 6]) == [1, 2]'
+ - '[1, 2, 3] | community.general.lists_difference([3, 2, 1]) == []'
+ - '["a", "A", "b"] | community.general.lists_difference(["B", "c", "C"]) == ["a", "A", "b"]'
+ - '["a", "A", "b"] | community.general.lists_difference(["b", "B", "c", "C"]) == ["a", "A"]'
+ - '["a", "A", "b"] | community.general.lists_difference(["b", "A", "a"]) == []'
+ - '[["a"]] | community.general.lists_difference([["b"], ["a"]]) == []'
+ - '[["a"]] | community.general.lists_difference([["b"]], ["a"]) == [["a"]]'
+ - '[["a"]] | community.general.lists_difference(["b"], ["a"]) == [["a"]]'
+
+- name: Test predictive list symmetric difference
+ ansible.builtin.assert:
+ that:
+ - 'list1 | community.general.lists_symmetric_difference(list2, list3) == [11, 1, 2, 4, 5, 101]'
+ - '[list1, list2, list3] | community.general.lists_symmetric_difference(flatten=True) == [11, 1, 2, 4, 5, 101]'
+ - '[1, 2, 3] | community.general.lists_symmetric_difference([4, 5, 6]) == [1, 2, 3, 4, 5, 6]'
+ - '[1, 2, 3] | community.general.lists_symmetric_difference([3, 4, 5, 6]) == [1, 2, 4, 5, 6]'
+ - '[1, 2, 3] | community.general.lists_symmetric_difference([3, 2, 1]) == []'
+ - '["a", "A", "b"] | community.general.lists_symmetric_difference(["B", "c", "C"]) == ["a", "A", "b", "B", "c", "C"]'
+ - '["a", "A", "b"] | community.general.lists_symmetric_difference(["b", "B", "c", "C"]) == ["a", "A", "B", "c", "C"]'
+ - '["a", "A", "b"] | community.general.lists_symmetric_difference(["b", "A", "a"]) == []'
+ - '[["a"]] | community.general.lists_symmetric_difference([["b"], ["a"]]) == [["b"]]'
+ - '[["a"]] | community.general.lists_symmetric_difference([["b"]], ["a"]) == [["a"], ["b"], "a"]'
+ - '[["a"]] | community.general.lists_symmetric_difference(["b"], ["a"]) == [["a"], "b", "a"]'
diff --git a/ansible_collections/community/general/tests/integration/targets/filter_lists/vars/main.yml b/ansible_collections/community/general/tests/integration/targets/filter_lists/vars/main.yml
new file mode 100644
index 000000000..a67af1dad
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/filter_lists/vars/main.yml
@@ -0,0 +1,8 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+list1: [1, 2, 5, 3, 4, 10]
+list2: [1, 2, 3, 4, 5, 11, 99]
+list3: [1, 2, 4, 5, 10, 99, 101]
diff --git a/ansible_collections/community/general/tests/integration/targets/filter_lists_mergeby/aliases b/ansible_collections/community/general/tests/integration/targets/filter_lists_mergeby/aliases
index bc9b4bc99..12d1d6617 100644
--- a/ansible_collections/community/general/tests/integration/targets/filter_lists_mergeby/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/filter_lists_mergeby/aliases
@@ -3,4 +3,3 @@
# SPDX-License-Identifier: GPL-3.0-or-later
azp/posix/2
-skip/python2.6 # filters are controller only, and we no longer support Python 2.6 on the controller
diff --git a/ansible_collections/community/general/tests/integration/targets/filter_path_join_shim/aliases b/ansible_collections/community/general/tests/integration/targets/filter_path_join_shim/aliases
index 51baa3d7a..afda346c4 100644
--- a/ansible_collections/community/general/tests/integration/targets/filter_path_join_shim/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/filter_path_join_shim/aliases
@@ -3,4 +3,3 @@
# SPDX-License-Identifier: GPL-3.0-or-later
azp/posix/1
-skip/python2.6 # filters are controller only, and we no longer support Python 2.6 on the controller
diff --git a/ansible_collections/community/general/tests/integration/targets/filter_random_mac/aliases b/ansible_collections/community/general/tests/integration/targets/filter_random_mac/aliases
index cee9abd2c..dadd9f37a 100644
--- a/ansible_collections/community/general/tests/integration/targets/filter_random_mac/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/filter_random_mac/aliases
@@ -3,5 +3,4 @@
# SPDX-License-Identifier: GPL-3.0-or-later
azp/posix/2
-skip/python2.6 # filters are controller only, and we no longer support Python 2.6 on the controller
skip/aix
diff --git a/ansible_collections/community/general/tests/integration/targets/filter_time/aliases b/ansible_collections/community/general/tests/integration/targets/filter_time/aliases
index bc9b4bc99..12d1d6617 100644
--- a/ansible_collections/community/general/tests/integration/targets/filter_time/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/filter_time/aliases
@@ -3,4 +3,3 @@
# SPDX-License-Identifier: GPL-3.0-or-later
azp/posix/2
-skip/python2.6 # filters are controller only, and we no longer support Python 2.6 on the controller
diff --git a/ansible_collections/community/general/tests/integration/targets/filter_to_ini/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/filter_to_ini/tasks/main.yml
new file mode 100644
index 000000000..877d4471d
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/filter_to_ini/tasks/main.yml
@@ -0,0 +1,58 @@
+---
+# Copyright (c) 2023, Steffen Scheib <steffen@scheib.me>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: >-
+ Write INI file that reflects using to_ini to {{ ini_test_file_filter }}
+ ansible.builtin.copy:
+ dest: '{{ ini_test_file_filter }}'
+ content: '{{ ini_test_dict | community.general.to_ini }}'
+ vars:
+ ini_test_dict:
+ section_name:
+ key_name: 'key value'
+
+ another_section:
+ connection: 'ssh'
+
+- name: 'Write INI file manually to {{ ini_test_file }}'
+ ansible.builtin.copy:
+ dest: '{{ ini_test_file }}'
+ content: |
+ [section_name]
+ key_name = key value
+
+ [another_section]
+ connection = ssh
+
+- name: 'Slurp the manually created test file: {{ ini_test_file }}'
+ ansible.builtin.slurp:
+ src: '{{ ini_test_file }}'
+ register: 'ini_file_content'
+
+- name: 'Slurp the test file created with to_ini: {{ ini_test_file_filter }}'
+ ansible.builtin.slurp:
+ src: '{{ ini_test_file_filter }}'
+ register: 'ini_file_filter_content'
+
+- name: >-
+ Ensure the manually created test file and the test file created with
+ to_ini are identical
+ ansible.builtin.assert:
+ that:
+ - 'ini_file_content.content | b64decode ==
+ ini_file_filter_content.content | b64decode'
+
+- name: 'Try to convert an empty dictionary with to_ini'
+ ansible.builtin.debug:
+ msg: '{{ {} | community.general.to_ini }}'
+ register: 'ini_empty_dict'
+ ignore_errors: true
+
+- name: 'Ensure the correct exception was raised'
+ ansible.builtin.assert:
+ that:
+ - "'to_ini received an empty dict. An empty dict cannot be converted.' in
+ ini_empty_dict.msg"
+...
diff --git a/ansible_collections/community/general/tests/integration/targets/filter_to_ini/vars/main.yml b/ansible_collections/community/general/tests/integration/targets/filter_to_ini/vars/main.yml
new file mode 100644
index 000000000..9c950726b
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/filter_to_ini/vars/main.yml
@@ -0,0 +1,8 @@
+---
+# Copyright (c) 2023, Steffen Scheib <steffen@scheib.me>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+ini_test_file: '/tmp/test.ini'
+ini_test_file_filter: '/tmp/test_filter.ini'
+...
diff --git a/ansible_collections/community/general/tests/integration/targets/filter_unicode_normalize/aliases b/ansible_collections/community/general/tests/integration/targets/filter_unicode_normalize/aliases
index bc9b4bc99..12d1d6617 100644
--- a/ansible_collections/community/general/tests/integration/targets/filter_unicode_normalize/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/filter_unicode_normalize/aliases
@@ -3,4 +3,3 @@
# SPDX-License-Identifier: GPL-3.0-or-later
azp/posix/2
-skip/python2.6 # filters are controller only, and we no longer support Python 2.6 on the controller
diff --git a/ansible_collections/community/general/tests/integration/targets/filter_version_sort/aliases b/ansible_collections/community/general/tests/integration/targets/filter_version_sort/aliases
index bc9b4bc99..12d1d6617 100644
--- a/ansible_collections/community/general/tests/integration/targets/filter_version_sort/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/filter_version_sort/aliases
@@ -3,4 +3,3 @@
# SPDX-License-Identifier: GPL-3.0-or-later
azp/posix/2
-skip/python2.6 # filters are controller only, and we no longer support Python 2.6 on the controller
diff --git a/ansible_collections/community/general/tests/integration/targets/gem/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/gem/tasks/main.yml
index 362c126bf..2d615304f 100644
--- a/ansible_collections/community/general/tests/integration/targets/gem/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/gem/tasks/main.yml
@@ -109,7 +109,7 @@
- current_gems.stdout is not search('gist\s+\([0-9.]+\)')
when: ansible_user_uid == 0
- # Check cutom gem directory
+ # Check custom gem directory
- name: Install gem in a custom directory with incorrect options
gem:
name: gist
diff --git a/ansible_collections/community/general/tests/integration/targets/git_config/files/gitconfig b/ansible_collections/community/general/tests/integration/targets/git_config/files/gitconfig
index 92eeb7eb9..29d3e8a0e 100644
--- a/ansible_collections/community/general/tests/integration/targets/git_config/files/gitconfig
+++ b/ansible_collections/community/general/tests/integration/targets/git_config/files/gitconfig
@@ -4,3 +4,8 @@
[http]
proxy = foo
+
+[push]
+pushoption = merge_request.create
+pushoption = merge_request.draft
+pushoption = merge_request.target=foobar
diff --git a/ansible_collections/community/general/tests/integration/targets/git_config/tasks/get_set_state_present_file.yml b/ansible_collections/community/general/tests/integration/targets/git_config/tasks/get_set_state_present_file.yml
index a61ffcc68..c410bfe18 100644
--- a/ansible_collections/community/general/tests/integration/targets/git_config/tasks/get_set_state_present_file.yml
+++ b/ansible_collections/community/general/tests/integration/targets/git_config/tasks/get_set_state_present_file.yml
@@ -30,3 +30,4 @@
- set_result.diff.after == option_value + "\n"
- get_result is not changed
- get_result.config_value == option_value
+... \ No newline at end of file
diff --git a/ansible_collections/community/general/tests/integration/targets/git_config/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/git_config/tasks/main.yml
index 4dc72824c..5fddaf764 100644
--- a/ansible_collections/community/general/tests/integration/targets/git_config/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/git_config/tasks/main.yml
@@ -13,6 +13,7 @@
import_tasks: setup.yml
- block:
+ - import_tasks: set_value.yml
# testing parameters exclusion: state and list_all
- import_tasks: exclusion_state_list-all.yml
# testing get/set option without state
@@ -31,5 +32,7 @@
- import_tasks: unset_check_mode.yml
# testing for case in issue #1776
- import_tasks: set_value_with_tilde.yml
+ - import_tasks: set_multi_value.yml
+ - import_tasks: unset_multi_value.yml
when: git_installed is succeeded and git_version.stdout is version(git_version_supporting_includes, ">=")
...
diff --git a/ansible_collections/community/general/tests/integration/targets/git_config/tasks/set_multi_value.yml b/ansible_collections/community/general/tests/integration/targets/git_config/tasks/set_multi_value.yml
new file mode 100644
index 000000000..8d2710b76
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/git_config/tasks/set_multi_value.yml
@@ -0,0 +1,79 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- import_tasks: setup_no_value.yml
+
+- name: setting value
+ git_config:
+ name: push.pushoption
+ add_mode: add
+ value: "{{ item }}"
+ state: present
+ scope: global
+ loop:
+ - 'merge_request.create'
+ - 'merge_request.draft'
+ - 'merge_request.target=foobar'
+ register: set_result1
+
+- name: setting value
+ git_config:
+ name: push.pushoption
+ add_mode: add
+ value: "{{ item }}"
+ state: present
+ scope: global
+ loop:
+ - 'merge_request.create'
+ - 'merge_request.draft'
+ - 'merge_request.target=foobar'
+ register: set_result2
+
+- name: getting the multi-value
+ git_config:
+ name: push.pushoption
+ scope: global
+ register: get_single_result
+
+- name: getting all values for the single option
+ git_config_info:
+ name: push.pushoption
+ scope: global
+ register: get_all_result
+
+- name: replace-all values
+ git_config:
+ name: push.pushoption
+ add_mode: replace-all
+ value: merge_request.create
+ state: present
+ scope: global
+ register: set_result3
+
+- name: assert set changed and value is correct
+ assert:
+ that:
+ - set_result1.results[0] is changed
+ - set_result1.results[1] is changed
+ - set_result1.results[2] is changed
+ - set_result2.results[0] is not changed
+ - set_result2.results[1] is not changed
+ - set_result2.results[2] is not changed
+ - set_result3 is changed
+ - get_single_result.config_value == 'merge_request.create'
+ - 'get_all_result.config_values == {"push.pushoption": ["merge_request.create", "merge_request.draft", "merge_request.target=foobar"]}'
+
+- name: assert the diffs are also right
+ assert:
+ that:
+ - set_result1.results[0].diff.before == "\n"
+ - set_result1.results[0].diff.after == "merge_request.create\n"
+ - set_result1.results[1].diff.before == "merge_request.create\n"
+ - set_result1.results[1].diff.after == ["merge_request.create", "merge_request.draft"]
+ - set_result1.results[2].diff.before == ["merge_request.create", "merge_request.draft"]
+ - set_result1.results[2].diff.after == ["merge_request.create", "merge_request.draft", "merge_request.target=foobar"]
+ - set_result3.diff.before == ["merge_request.create", "merge_request.draft", "merge_request.target=foobar"]
+ - set_result3.diff.after == "merge_request.create\n"
+...
diff --git a/ansible_collections/community/general/tests/integration/targets/git_config/tasks/set_value.yml b/ansible_collections/community/general/tests/integration/targets/git_config/tasks/set_value.yml
new file mode 100644
index 000000000..774e3136a
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/git_config/tasks/set_value.yml
@@ -0,0 +1,39 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- import_tasks: setup_no_value.yml
+
+- name: setting value
+ git_config:
+ name: core.name
+ value: foo
+ scope: global
+ register: set_result1
+
+- name: setting another value for same name
+ git_config:
+ name: core.name
+ value: bar
+ scope: global
+ register: set_result2
+
+- name: getting value
+ git_config:
+ name: core.name
+ scope: global
+ register: get_result
+
+- name: assert set changed and value is correct
+ assert:
+ that:
+ - set_result1 is changed
+ - set_result2 is changed
+ - get_result is not changed
+ - get_result.config_value == 'bar'
+ - set_result1.diff.before == "\n"
+ - set_result1.diff.after == "foo\n"
+ - set_result2.diff.before == "foo\n"
+ - set_result2.diff.after == "bar\n"
+...
diff --git a/ansible_collections/community/general/tests/integration/targets/git_config/tasks/set_value_with_tilde.yml b/ansible_collections/community/general/tests/integration/targets/git_config/tasks/set_value_with_tilde.yml
index f78e709bd..3ca9023aa 100644
--- a/ansible_collections/community/general/tests/integration/targets/git_config/tasks/set_value_with_tilde.yml
+++ b/ansible_collections/community/general/tests/integration/targets/git_config/tasks/set_value_with_tilde.yml
@@ -11,7 +11,7 @@
value: '~/foo/bar'
state: present
scope: global
- register: set_result
+ register: set_result1
- name: setting value again
git_config:
@@ -30,7 +30,7 @@
- name: assert set changed and value is correct
assert:
that:
- - set_result is changed
+ - set_result1 is changed
- set_result2 is not changed
- get_result is not changed
- get_result.config_value == '~/foo/bar'
diff --git a/ansible_collections/community/general/tests/integration/targets/git_config/tasks/unset_multi_value.yml b/ansible_collections/community/general/tests/integration/targets/git_config/tasks/unset_multi_value.yml
new file mode 100644
index 000000000..4cb9dee49
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/git_config/tasks/unset_multi_value.yml
@@ -0,0 +1,28 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- import_tasks: setup_value.yml
+
+- name: unsetting "push.pushoption"
+ git_config:
+ name: push.pushoption
+ scope: global
+ state: absent
+ register: unset_result
+
+- name: getting all pushoptions values
+ git_config_info:
+ name: push.pushoption
+ scope: global
+ register: get_all_result
+
+- name: assert unsetting muti-values
+ assert:
+ that:
+ - unset_result is changed
+ - 'get_all_result.config_values == {"push.pushoption": []}'
+ - unset_result.diff.before == ["merge_request.create", "merge_request.draft", "merge_request.target=foobar"]
+ - unset_result.diff.after == "\n"
+...
diff --git a/ansible_collections/community/general/tests/integration/targets/git_config_info/aliases b/ansible_collections/community/general/tests/integration/targets/git_config_info/aliases
new file mode 100644
index 000000000..7b8c653de
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/git_config_info/aliases
@@ -0,0 +1,7 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+azp/posix/3
+skip/aix
+destructive
diff --git a/ansible_collections/community/general/tests/integration/targets/git_config_info/files/gitconfig b/ansible_collections/community/general/tests/integration/targets/git_config_info/files/gitconfig
new file mode 100644
index 000000000..d0590b3f8
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/git_config_info/files/gitconfig
@@ -0,0 +1,11 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+[credential "https://some.com"]
+ username = yolo
+[user]
+ name = foobar
+[push]
+ pushoption = merge_request.create
+ pushoption = merge_request.draft
diff --git a/ansible_collections/community/general/tests/integration/targets/git_config_info/meta/main.yml b/ansible_collections/community/general/tests/integration/targets/git_config_info/meta/main.yml
new file mode 100644
index 000000000..982de6eb0
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/git_config_info/meta/main.yml
@@ -0,0 +1,7 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+dependencies:
+ - setup_remote_tmp_dir
diff --git a/ansible_collections/community/general/tests/integration/targets/git_config_info/tasks/error_handling.yml b/ansible_collections/community/general/tests/integration/targets/git_config_info/tasks/error_handling.yml
new file mode 100644
index 000000000..1b84fee50
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/git_config_info/tasks/error_handling.yml
@@ -0,0 +1,26 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- import_tasks: "setup_file.yml"
+
+- name: getting all system configs
+ git_config_info:
+ scope: system
+ register: get_result1
+
+- name: getting all system configs for a key
+ git_config_info:
+ name: user.name
+ scope: system
+ register: get_result2
+
+- name: assert value is correct
+ assert:
+ that:
+ - get_result1.config_value == ""
+ - 'get_result1.config_values == {}'
+ - get_result2.config_value == ""
+ - 'get_result2.config_values == {"user.name": []}'
+...
diff --git a/ansible_collections/community/general/tests/integration/targets/git_config_info/tasks/get_all_values.yml b/ansible_collections/community/general/tests/integration/targets/git_config_info/tasks/get_all_values.yml
new file mode 100644
index 000000000..301051a42
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/git_config_info/tasks/get_all_values.yml
@@ -0,0 +1,19 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- include_tasks: "{{ item.import_file }}"
+
+- name: getting all values (as list) for a file config
+ git_config_info:
+ scope: "{{ item.git_scope }}"
+ path: "{{ item.git_file | default(omit) }}"
+ register: get_result
+
+- name: assert value is correct
+ assert:
+ that:
+ - get_result.config_value == ""
+ - 'get_result.config_values == {"credential.https://some.com.username": ["yolo"], "user.name": ["foobar"], "push.pushoption": ["merge_request.create", "merge_request.draft"]}'
+...
diff --git a/ansible_collections/community/general/tests/integration/targets/git_config_info/tasks/get_multi_value.yml b/ansible_collections/community/general/tests/integration/targets/git_config_info/tasks/get_multi_value.yml
new file mode 100644
index 000000000..14fa2800c
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/git_config_info/tasks/get_multi_value.yml
@@ -0,0 +1,20 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- include_tasks: "{{ item.import_file }}"
+
+- name: getting only a single value (as string) from an option with multiple values in the git config file
+ git_config_info:
+ name: push.pushoption
+ scope: "{{ item.git_scope }}"
+ path: "{{ item.git_file | default(omit) }}"
+ register: get_result
+
+- name: assert value is correct
+ assert:
+ that:
+ - get_result.config_value == "merge_request.create"
+ - 'get_result.config_values == {"push.pushoption": ["merge_request.create", "merge_request.draft"]}'
+...
diff --git a/ansible_collections/community/general/tests/integration/targets/git_config_info/tasks/get_simple_value.yml b/ansible_collections/community/general/tests/integration/targets/git_config_info/tasks/get_simple_value.yml
new file mode 100644
index 000000000..83cd19a0b
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/git_config_info/tasks/get_simple_value.yml
@@ -0,0 +1,38 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- include_tasks: "{{ item.import_file }}"
+
+- name: getting simple file value1
+ git_config_info:
+ name: user.name
+ scope: "{{ item.git_scope }}"
+ path: "{{ item.git_file | default(omit) }}"
+ register: get_result1
+
+- name: getting simple file value2
+ git_config_info:
+ name: "credential.https://some.com.username"
+ scope: "{{ item.git_scope }}"
+ path: "{{ item.git_file | default(omit) }}"
+ register: get_result2
+
+- name: getting not existing value
+ git_config_info:
+ name: "user.email"
+ scope: "{{ item.git_scope }}"
+ path: "{{ item.git_file | default(omit) }}"
+ register: get_result3
+
+- name: assert value is correct
+ assert:
+ that:
+ - get_result1.config_value == "foobar"
+ - 'get_result1.config_values == {"user.name": ["foobar"]}'
+ - get_result2.config_value == "yolo"
+ - 'get_result2.config_values == {"credential.https://some.com.username": ["yolo"]}'
+ - get_result3.config_value == ""
+ - 'get_result3.config_values == {"user.email": []}'
+...
diff --git a/ansible_collections/community/general/tests/integration/targets/git_config_info/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/git_config_info/tasks/main.yml
new file mode 100644
index 000000000..993238805
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/git_config_info/tasks/main.yml
@@ -0,0 +1,33 @@
+---
+####################################################################
+# WARNING: These are designed specifically for Ansible tests #
+# and should not be used as examples of how to write Ansible roles #
+####################################################################
+
+# test code for the git_config_info module
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: setup
+ import_tasks: setup.yml
+
+- block:
+ - include_tasks: get_simple_value.yml
+ loop:
+ - { import_file: setup_global.yml, git_scope: 'global' }
+ - { import_file: setup_file.yml, git_scope: 'file', git_file: "{{ remote_tmp_dir }}/gitconfig_file" }
+
+ - include_tasks: get_multi_value.yml
+ loop:
+ - { import_file: setup_global.yml, git_scope: 'global' }
+ - { import_file: setup_file.yml, git_scope: 'file', git_file: "{{ remote_tmp_dir }}/gitconfig_file" }
+
+ - include_tasks: get_all_values.yml
+ loop:
+ - { import_file: setup_global.yml, git_scope: 'global' }
+ - { import_file: setup_file.yml, git_scope: 'file', git_file: "{{ remote_tmp_dir }}/gitconfig_file" }
+
+ - include_tasks: error_handling.yml
+ when: git_installed is succeeded and git_version.stdout is version(git_version_supporting_includes, ">=")
+...
diff --git a/ansible_collections/community/general/tests/integration/targets/git_config_info/tasks/setup.yml b/ansible_collections/community/general/tests/integration/targets/git_config_info/tasks/setup.yml
new file mode 100644
index 000000000..6e5516da5
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/git_config_info/tasks/setup.yml
@@ -0,0 +1,15 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: verify that git is installed so this test can continue
+ command: which git
+ register: git_installed
+ ignore_errors: true
+
+- name: get git version, only newer than {{git_version_supporting_includes}} has includes option
+ shell: "git --version | grep 'git version' | sed 's/git version //'"
+ register: git_version
+ ignore_errors: true
+...
diff --git a/ansible_collections/community/general/tests/integration/targets/git_config_info/tasks/setup_file.yml b/ansible_collections/community/general/tests/integration/targets/git_config_info/tasks/setup_file.yml
new file mode 100644
index 000000000..854b10997
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/git_config_info/tasks/setup_file.yml
@@ -0,0 +1,16 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# ------
+# set up : set gitconfig with value
+- name: delete global config
+ file:
+ path: ~/.gitconfig
+ state: absent
+
+- name: set up file config
+ copy:
+ src: gitconfig
+ dest: "{{ remote_tmp_dir }}/gitconfig_file"
diff --git a/ansible_collections/community/general/tests/integration/targets/git_config_info/tasks/setup_global.yml b/ansible_collections/community/general/tests/integration/targets/git_config_info/tasks/setup_global.yml
new file mode 100644
index 000000000..a9e045a57
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/git_config_info/tasks/setup_global.yml
@@ -0,0 +1,16 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# ------
+# set up : set gitconfig with value
+- name: delete file config
+ file:
+ path: "{{ remote_tmp_dir }}/gitconfig_file"
+ state: absent
+
+- name: setup global config
+ copy:
+ src: gitconfig
+ dest: ~/.gitconfig
diff --git a/ansible_collections/community/general/tests/integration/targets/git_config_info/vars/main.yml b/ansible_collections/community/general/tests/integration/targets/git_config_info/vars/main.yml
new file mode 100644
index 000000000..55c3d1738
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/git_config_info/vars/main.yml
@@ -0,0 +1,7 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+git_version_supporting_includes: 1.7.10
+...
diff --git a/ansible_collections/community/general/tests/integration/targets/gitlab_group_access_token/aliases b/ansible_collections/community/general/tests/integration/targets/gitlab_group_access_token/aliases
new file mode 100644
index 000000000..fc0e157c9
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/gitlab_group_access_token/aliases
@@ -0,0 +1,7 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+azp/posix/1
+gitlab/ci
+disabled
diff --git a/ansible_collections/community/general/tests/integration/targets/gitlab_group_access_token/defaults/main.yml b/ansible_collections/community/general/tests/integration/targets/gitlab_group_access_token/defaults/main.yml
new file mode 100644
index 000000000..1b0dab289
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/gitlab_group_access_token/defaults/main.yml
@@ -0,0 +1,15 @@
+---
+####################################################################
+# WARNING: These are designed specifically for Ansible tests #
+# and should not be used as examples of how to write Ansible roles #
+####################################################################
+
+# Copyright (c) 2024, Zoran Krleza <zoran.krleza@true-north.hr>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+gitlab_api_token:
+gitlab_api_url:
+gitlab_validate_certs: false
+gitlab_group_name:
+gitlab_token_name:
diff --git a/ansible_collections/community/general/tests/integration/targets/gitlab_group_access_token/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/gitlab_group_access_token/tasks/main.yml
new file mode 100644
index 000000000..4e6234238
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/gitlab_group_access_token/tasks/main.yml
@@ -0,0 +1,221 @@
+---
+####################################################################
+# WARNING: These are designed specifically for Ansible tests #
+# and should not be used as examples of how to write Ansible roles #
+####################################################################
+
+# Copyright (c) 2024, Zoran Krleza <zoran.krleza@true-north.hr>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Install required libs
+ pip:
+ name: python-gitlab
+ state: present
+
+- block:
+ - name: Try to create access token in nonexisting group
+ community.general.gitlab_group_access_token:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_api_url }}"
+ validate_certs: "{{ gitlab_validate_certs }}"
+ group: "some_nonexisting_group"
+ name: "{{ gitlab_token_name }}"
+ state: present
+ expires_at: '2025-01-01'
+ access_level: developer
+ scopes:
+ - api
+ - read_api
+ register: create_pfail_token_status
+ always:
+ - name: Assert that token creation in nonexisting group failed
+ assert:
+ that:
+ - create_pfail_token_status is failed
+ ignore_errors: true
+
+- block:
+ - name: Try to create access token with nonvalid expires_at
+ community.general.gitlab_group_access_token:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_api_url }}"
+ validate_certs: "{{ gitlab_validate_certs }}"
+ group: "some_nonexisting_group"
+ name: "{{ gitlab_token_name }}"
+ state: present
+ expires_at: '2025-13-01'
+ access_level: developer
+ scopes:
+ - api
+ - read_api
+ register: create_efail_token_status
+ always:
+ - name: Assert that token creation with invalid expires_at failed
+ assert:
+ that:
+ - create_efail_token_status is failed
+ ignore_errors: true
+
+- name: Create access token
+ community.general.gitlab_group_access_token:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_api_url }}"
+ validate_certs: "{{ gitlab_validate_certs }}"
+ group: "{{ gitlab_group_name }}"
+ name: "{{ gitlab_token_name }}"
+ state: present
+ expires_at: '2024-12-31'
+ access_level: developer
+ scopes:
+ - api
+ - read_api
+ register: create_token_status
+- name: Assert that token creation with valid arguments is successfull
+ assert:
+ that:
+ - create_token_status is changed
+ - create_token_status.access_token.token is defined
+
+- name: Check existing access token recreate=never (default)
+ community.general.gitlab_group_access_token:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_api_url }}"
+ validate_certs: "{{ gitlab_validate_certs }}"
+ group: "{{ gitlab_group_name }}"
+ name: "{{ gitlab_token_name }}"
+ state: present
+ expires_at: '2024-12-31'
+ access_level: developer
+ scopes:
+ - api
+ - read_api
+ register: check_token_status
+- name: Assert that token creation without changes and recreate=never succeeds with status not changed
+ assert:
+ that:
+ - check_token_status is not changed
+ - check_token_status.access_token.token is not defined
+
+- name: Check existing access token with recreate=state_change
+ community.general.gitlab_group_access_token:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_api_url }}"
+ validate_certs: "{{ gitlab_validate_certs }}"
+ group: "{{ gitlab_group_name }}"
+ name: "{{ gitlab_token_name }}"
+ state: present
+ expires_at: '2024-12-31'
+ access_level: developer
+ scopes:
+ - api
+ - read_api
+ recreate: state_change
+ register: check_recreate_token_status
+- name: Assert that token creation without changes and recreate=state_change succeeds with status not changed
+ assert:
+ that:
+ - check_recreate_token_status is not changed
+ - check_recreate_token_status.access_token.token is not defined
+
+- block:
+ - name: Try to change existing access token with recreate=never
+ community.general.gitlab_group_access_token:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_api_url }}"
+ validate_certs: "{{ gitlab_validate_certs }}"
+ group: "{{ gitlab_group_name }}"
+ name: "{{ gitlab_token_name }}"
+ state: present
+ expires_at: '2025-01-01'
+ access_level: developer
+ scopes:
+ - api
+ - read_api
+ register: change_token_status
+ always:
+ - name: Assert that token change with recreate=never fails
+ assert:
+ that:
+ - change_token_status is failed
+ ignore_errors: true
+
+- name: Try to change existing access token with recreate=state_change
+ community.general.gitlab_group_access_token:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_api_url }}"
+ validate_certs: "{{ gitlab_validate_certs }}"
+ group: "{{ gitlab_group_name }}"
+ name: "{{ gitlab_token_name }}"
+ state: present
+ expires_at: '2025-01-01'
+ access_level: developer
+ scopes:
+ - api
+ - read_api
+ recreate: state_change
+ register: change_recreate_token_status
+- name: Assert that token change with recreate=state_change succeeds
+ assert:
+ that:
+ - change_recreate_token_status is changed
+ - change_recreate_token_status.access_token.token is defined
+
+- name: Try to change existing access token with recreate=always
+ community.general.gitlab_group_access_token:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_api_url }}"
+ validate_certs: "{{ gitlab_validate_certs }}"
+ group: "{{ gitlab_group_name }}"
+ name: "{{ gitlab_token_name }}"
+ state: present
+ expires_at: '2025-01-01'
+ access_level: developer
+ scopes:
+ - api
+ - read_api
+ recreate: always
+ register: change_recreate1_token_status
+- name: Assert that token change with recreate=always succeeds
+ assert:
+ that:
+ - change_recreate1_token_status is changed
+ - change_recreate1_token_status.access_token.token is defined
+
+- name: Revoke access token
+ community.general.gitlab_group_access_token:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_api_url }}"
+ validate_certs: "{{ gitlab_validate_certs }}"
+ group: "{{ gitlab_group_name }}"
+ name: "{{ gitlab_token_name }}"
+ state: absent
+ expires_at: '2024-12-31'
+ access_level: developer
+ scopes:
+ - api
+ - read_api
+ register: revoke_token_status
+- name: Assert that token revocation succeeds
+ assert:
+ that:
+ - revoke_token_status is changed
+
+- name: Revoke nonexisting access token
+ community.general.gitlab_group_access_token:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_api_url }}"
+ validate_certs: "{{ gitlab_validate_certs }}"
+ group: "{{ gitlab_group_name }}"
+ name: "{{ gitlab_token_name }}"
+ state: absent
+ expires_at: '2024-12-31'
+ access_level: developer
+ scopes:
+ - api
+ - read_api
+ register: revoke_token_status
+- name: Assert that token revocation succeeds with status not changed
+ assert:
+ that:
+ - revoke_token_status is not changed \ No newline at end of file
diff --git a/ansible_collections/community/general/tests/integration/targets/gitlab_instance_variable/aliases b/ansible_collections/community/general/tests/integration/targets/gitlab_instance_variable/aliases
new file mode 100644
index 000000000..bd1f02444
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/gitlab_instance_variable/aliases
@@ -0,0 +1,5 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+unsupported
diff --git a/ansible_collections/community/general/tests/integration/targets/gitlab_instance_variable/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/gitlab_instance_variable/tasks/main.yml
new file mode 100644
index 000000000..94a81698b
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/gitlab_instance_variable/tasks/main.yml
@@ -0,0 +1,606 @@
+---
+####################################################################
+# WARNING: These are designed specifically for Ansible tests #
+# and should not be used as examples of how to write Ansible roles #
+####################################################################
+
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Install required libs
+ pip:
+ name: python-gitlab
+ state: present
+
+- name: purge all variables for check_mode test
+ gitlab_instance_variable:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_login_token }}"
+ purge: true
+
+- name: add a variable value in check_mode
+ gitlab_instance_variable:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_login_token }}"
+ variables:
+ - name: ACCESS_KEY_ID
+ value: checkmode
+ check_mode: true
+ register: gitlab_instance_variable_state
+
+- name: check_mode state must be changed
+ assert:
+ that:
+ - gitlab_instance_variable_state is changed
+
+- name: apply add value from check_mode test
+ gitlab_instance_variable:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_login_token }}"
+ variables:
+ - name: ACCESS_KEY_ID
+ value: checkmode
+ register: gitlab_instance_variable_state
+
+- name: state must be changed
+ assert:
+ that:
+ - gitlab_instance_variable_state is changed
+
+- name: apply same value again again
+ gitlab_instance_variable:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_login_token }}"
+ variables:
+ - name: ACCESS_KEY_ID
+ value: checkmode
+ register: gitlab_instance_variable_state
+
+- name: state must be not changed
+ assert:
+ that:
+ - gitlab_instance_variable_state is not changed
+
+- name: change protected attribute
+ gitlab_instance_variable:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_login_token }}"
+ variables:
+ - name: ACCESS_KEY_ID
+ value: checkmode
+ protected: true
+ register: gitlab_instance_variable_state
+
+- name: state must be changed
+ assert:
+ that:
+ - gitlab_instance_variable_state is changed
+
+- name: revert protected attribute
+ gitlab_instance_variable:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_login_token }}"
+ variables:
+ - name: ACCESS_KEY_ID
+ value: checkmode
+ protected: false
+ register: gitlab_instance_variable_state
+
+- name: state must be changed
+ assert:
+ that:
+ - gitlab_instance_variable_state is changed
+
+- name: change masked attribute
+ gitlab_instance_variable:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_login_token }}"
+ variables:
+ - name: ACCESS_KEY_ID
+ value: checkmode
+ masked: true
+ register: gitlab_instance_variable_state
+
+- name: state must be changed
+ assert:
+ that:
+ - gitlab_instance_variable_state is changed
+
+- name: revert masked attribute by not mention it
+ gitlab_instance_variable:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_login_token }}"
+ variables:
+ - name: ACCESS_KEY_ID
+ value: checkmode
+ masked: false
+ register: gitlab_instance_variable_state
+
+- name: state must be changed
+ assert:
+ that:
+ - gitlab_instance_variable_state is changed
+
+- name: revert again masked attribute by not mention it (idempotent)
+ gitlab_instance_variable:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_login_token }}"
+ variables:
+ - name: ACCESS_KEY_ID
+ value: checkmode
+ register: gitlab_instance_variable_state
+
+- name: state must be not changed
+ assert:
+ that:
+ - gitlab_instance_variable_state is not changed
+
+- name: set all attributes
+ gitlab_instance_variable:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_login_token }}"
+ variables:
+ - name: ACCESS_KEY_ID
+ value: checkmode
+ masked: true
+ protected: true
+ variable_type: env_var
+ register: gitlab_instance_variable_state
+
+- name: state must be changed
+ assert:
+ that:
+ - gitlab_instance_variable_state is changed
+
+- name: set again all attributes (idempotent)
+ gitlab_instance_variable:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_login_token }}"
+ variables:
+ - name: ACCESS_KEY_ID
+ value: checkmode
+ masked: true
+ protected: true
+ variable_type: env_var
+ register: gitlab_instance_variable_state
+
+- name: state must not be changed
+ assert:
+ that:
+ - gitlab_instance_variable_state is not changed
+
+- name: revert both (masked and protected) attribute
+ gitlab_instance_variable:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_login_token }}"
+ variables:
+ - name: ACCESS_KEY_ID
+ value: checkmode
+ protected: false
+ register: gitlab_instance_variable_state
+
+- name: state must be changed
+ assert:
+ that:
+ - gitlab_instance_variable_state is changed
+
+- name: change a variable value in check_mode again
+ gitlab_instance_variable:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_login_token }}"
+ variables:
+ - name: ACCESS_KEY_ID
+ value: checkmode
+ check_mode: true
+ register: gitlab_instance_variable_state
+
+- name: check_mode state must not be changed
+ assert:
+ that:
+ - gitlab_instance_variable_state is not changed
+
+- name: apply again the value change from check_mode test
+ gitlab_instance_variable:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_login_token }}"
+ variables:
+ - name: ACCESS_KEY_ID
+ value: checkmode
+ register: gitlab_instance_variable_state
+
+- name: state must not be changed
+ assert:
+ that:
+ - gitlab_instance_variable_state is not changed
+
+- name: purge all variables again
+ gitlab_instance_variable:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_login_token }}"
+ purge: true
+
+- name: set two test variables
+ gitlab_instance_variable:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_login_token }}"
+ variables:
+ - name: ACCESS_KEY_ID
+ value: abc123
+ - name: SECRET_ACCESS_KEY
+ value: 321cba
+ register: gitlab_instance_variable_state
+
+- name: set two test variables state must be changed
+ assert:
+ that:
+ - gitlab_instance_variable_state is changed
+ - gitlab_instance_variable_state.instance_variable.added|length == 2
+ - gitlab_instance_variable_state.instance_variable.untouched|length == 0
+ - gitlab_instance_variable_state.instance_variable.removed|length == 0
+ - gitlab_instance_variable_state.instance_variable.updated|length == 0
+
+- name: re-set two test variables
+ gitlab_instance_variable:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_login_token }}"
+ variables:
+ - name: ACCESS_KEY_ID
+ value: abc123
+ - name: SECRET_ACCESS_KEY
+ value: 321cba
+ register: gitlab_instance_variable_state
+
+- name: re-set two test variables state must not be changed
+ assert:
+ that:
+ - gitlab_instance_variable_state is not changed
+ - gitlab_instance_variable_state.instance_variable.added|length == 0
+ - gitlab_instance_variable_state.instance_variable.untouched|length == 2
+ - gitlab_instance_variable_state.instance_variable.removed|length == 0
+ - gitlab_instance_variable_state.instance_variable.updated|length == 0
+
+- name: edit one variable
+ gitlab_instance_variable:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_login_token }}"
+ variables:
+ - name: ACCESS_KEY_ID
+ value: changed
+ purge: false
+ register: gitlab_instance_variable_state
+
+- name: edit one variable state must be changed
+ assert:
+ that:
+ - gitlab_instance_variable_state.changed
+ - gitlab_instance_variable_state.instance_variable.added|length == 0
+ - gitlab_instance_variable_state.instance_variable.untouched|length == 1
+ - gitlab_instance_variable_state.instance_variable.removed|length == 0
+ - gitlab_instance_variable_state.instance_variable.updated|length == 1
+ - gitlab_instance_variable_state.instance_variable.updated[0] == "ACCESS_KEY_ID"
+
+- name: append one variable
+ gitlab_instance_variable:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_login_token }}"
+ variables:
+ - name: some
+ value: value
+ purge: false
+ register: gitlab_instance_variable_state
+
+- name: append one variable state must be changed
+ assert:
+ that:
+ - gitlab_instance_variable_state.changed
+ - gitlab_instance_variable_state.instance_variable.added|length == 1
+ - gitlab_instance_variable_state.instance_variable.untouched|length == 2
+ - gitlab_instance_variable_state.instance_variable.removed|length == 0
+ - gitlab_instance_variable_state.instance_variable.updated|length == 0
+ - gitlab_instance_variable_state.instance_variable.added[0] == "some"
+
+- name: re-set all variables
+ gitlab_instance_variable:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_login_token }}"
+ variables:
+ - name: ACCESS_KEY_ID
+ value: changed
+ - name: SECRET_ACCESS_KEY
+ value: 321cba
+ - name: some
+ value: value
+ register: gitlab_instance_variable_state
+
+- name: re-set all variables state must not be changed
+ assert:
+ that:
+ - not gitlab_instance_variable_state.changed
+ - gitlab_instance_variable_state.instance_variable.added|length == 0
+ - gitlab_instance_variable_state.instance_variable.untouched|length == 3
+ - gitlab_instance_variable_state.instance_variable.removed|length == 0
+ - gitlab_instance_variable_state.instance_variable.updated|length == 0
+
+- name: set one variables and purge all others
+ gitlab_instance_variable:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_login_token }}"
+ variables:
+ - name: some
+ value: value
+ purge: true
+ register: gitlab_instance_variable_state
+
+- name: set one variables and purge all others state must be changed
+ assert:
+ that:
+ - gitlab_instance_variable_state.changed
+ - gitlab_instance_variable_state.instance_variable.added|length == 0
+ - gitlab_instance_variable_state.instance_variable.untouched|length == 1
+ - gitlab_instance_variable_state.instance_variable.removed|length == 2
+ - gitlab_instance_variable_state.instance_variable.updated|length == 0
+
+- name: only one variable is left
+ gitlab_instance_variable:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_login_token }}"
+ variables:
+ - name: some
+ value: value
+ purge: false
+ register: gitlab_instance_variable_state
+
+- name: only one variable is left state must not be changed
+ assert:
+ that:
+ - not gitlab_instance_variable_state.changed
+ - gitlab_instance_variable_state.instance_variable.added|length == 0
+ - gitlab_instance_variable_state.instance_variable.untouched|length == 1
+ - gitlab_instance_variable_state.instance_variable.removed|length == 0
+ - gitlab_instance_variable_state.instance_variable.updated|length == 0
+ - gitlab_instance_variable_state.instance_variable.untouched[0] == "some"
+
+- name: test integer values
+ gitlab_instance_variable:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_login_token }}"
+ variables:
+ - name: some
+ value: 42
+ purge: false
+ register: gitlab_instance_variable_state
+
+- name: only one variable is left state must be changed
+ assert:
+ that:
+ - gitlab_instance_variable_state.changed
+ - gitlab_instance_variable_state.instance_variable.added|length == 0
+ - gitlab_instance_variable_state.instance_variable.untouched|length == 0
+ - gitlab_instance_variable_state.instance_variable.removed|length == 0
+ - gitlab_instance_variable_state.instance_variable.updated|length == 1
+
+- name: test float values
+ gitlab_instance_variable:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_login_token }}"
+ variables:
+ - name: some
+ value: 42.23
+ purge: false
+ register: gitlab_instance_variable_state
+
+- name: only one variable is left state must be changed
+ assert:
+ that:
+ - gitlab_instance_variable_state.changed
+ - gitlab_instance_variable_state.instance_variable.added|length == 0
+ - gitlab_instance_variable_state.instance_variable.untouched|length == 0
+ - gitlab_instance_variable_state.instance_variable.removed|length == 0
+ - gitlab_instance_variable_state.instance_variable.updated|length == 1
+
+- name: delete the last left variable
+ gitlab_instance_variable:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_login_token }}"
+ state: absent
+ variables:
+ - name: some
+ register: gitlab_instance_variable_state
+
+- name: no variable is left state must be changed
+ assert:
+ that:
+ - gitlab_instance_variable_state.changed
+ - gitlab_instance_variable_state.instance_variable.added|length == 0
+ - gitlab_instance_variable_state.instance_variable.untouched|length == 0
+ - gitlab_instance_variable_state.instance_variable.removed|length == 1
+ - gitlab_instance_variable_state.instance_variable.updated|length == 0
+ - gitlab_instance_variable_state.instance_variable.removed[0] == "some"
+
+- name: add one variable with variable_type file
+ gitlab_instance_variable:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_login_token }}"
+ variables:
+ - name: my_test_var
+ value: my_test_value
+ variable_type: file
+ purge: false
+ register: gitlab_instance_variable_state
+
+- name: append one variable state must be changed
+ assert:
+ that:
+ - gitlab_instance_variable_state.changed
+ - gitlab_instance_variable_state.instance_variable.added|length == 1
+ - gitlab_instance_variable_state.instance_variable.untouched|length == 0
+ - gitlab_instance_variable_state.instance_variable.removed|length == 0
+ - gitlab_instance_variable_state.instance_variable.updated|length == 0
+ # VALUE_SPECIFIED_IN_NO_LOG_PARAMETER
+ #- gitlab_instance_variable_state.instance_variable.added[0] == "my_test_var"
+
+- name: change variable_type attribute
+ gitlab_instance_variable:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_login_token }}"
+ variables:
+ - name: my_test_var
+ value: my_test_value
+ variable_type: env_var
+ register: gitlab_instance_variable_state
+
+- name: state must be changed
+ assert:
+ that:
+ - gitlab_instance_variable_state is changed
+
+- name: revert variable_type attribute
+ gitlab_instance_variable:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_login_token }}"
+ variables:
+ - name: my_test_var
+ value: my_test_value
+ variable_type: file
+ register: gitlab_instance_variable_state
+
+- name: state must be changed
+ assert:
+ that:
+ - gitlab_instance_variable_state is changed
+
+- name: delete the variable_type file variable
+ gitlab_instance_variable:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_login_token }}"
+ state: absent
+ variables:
+ - name: my_test_var
+ register: gitlab_instance_variable_state
+
+- name: no variable is left state must be changed
+ assert:
+ that:
+ - gitlab_instance_variable_state.changed
+ - gitlab_instance_variable_state.instance_variable.added|length == 0
+ - gitlab_instance_variable_state.instance_variable.untouched|length == 0
+ - gitlab_instance_variable_state.instance_variable.removed|length == 1
+ - gitlab_instance_variable_state.instance_variable.updated|length == 0
+ - gitlab_instance_variable_state.instance_variable.removed[0] == "my_test_var"
+
+- name: set complete page and purge existing ones
+ gitlab_instance_variable:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_login_token }}"
+ variables:
+ - name: page1_var01
+ value: value
+ - name: page1_var02
+ value: value
+ - name: page1_var03
+ value: value
+ - name: page1_var04
+ value: value
+ - name: page1_var05
+ value: value
+ - name: page1_var06
+ value: value
+ - name: page1_var07
+ value: value
+ - name: page1_var08
+ value: value
+ - name: page1_var09
+ value: value
+ - name: page1_var10
+ value: value
+ - name: page1_var11
+ value: value
+ - name: page1_var12
+ value: value
+ - name: page1_var13
+ value: value
+ - name: page1_var14
+ value: value
+ - name: page1_var15
+ value: value
+ - name: page1_var16
+ value: value
+ - name: page1_var17
+ value: value
+ - name: page1_var18
+ value: value
+ - name: page1_var19
+ value: value
+ - name: page1_var20
+ value: value
+ purge: true
+ register: gitlab_instance_variable_state
+
+- name: complete page added state must be changed
+ assert:
+ that:
+ - gitlab_instance_variable_state is changed
+ - gitlab_instance_variable_state.instance_variable.added|length == 20
+ - gitlab_instance_variable_state.instance_variable.untouched|length == 0
+
+- name: check that no variables are left
+ gitlab_instance_variable:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_login_token }}"
+ purge: true
+ register: gitlab_instance_variable_state
+
+- name: check that no variables are untouched state must be changed
+ assert:
+ that:
+ - gitlab_instance_variable_state.changed
+ - gitlab_instance_variable_state.instance_variable.added|length == 0
+ - gitlab_instance_variable_state.instance_variable.untouched|length == 0
+ - gitlab_instance_variable_state.instance_variable.removed|length == 20
+ - gitlab_instance_variable_state.instance_variable.updated|length == 0
+
+- name: throw error when state is present but no value is given
+ gitlab_instance_variable:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_login_token }}"
+ variables:
+ - name: no_value
+ register: gitlab_instance_variable_state
+ ignore_errors: true
+
+- name: verify fail
+ assert:
+ that:
+ - gitlab_instance_variable_state.failed
+ - gitlab_instance_variable_state is not changed
+
+- name: set a new variable to delete it later
+ gitlab_instance_variable:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_login_token }}"
+ purge: true
+ variables:
+ - name: delete_me
+ value: ansible
+ register: gitlab_instance_variable_state
+
+- name: verify the change
+ assert:
+ that:
+ - gitlab_instance_variable_state.changed
+
+- name: delete variable without referencing its value
+ gitlab_instance_variable:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_login_token }}"
+ state: absent
+ variables:
+ - name: delete_me
+ register: gitlab_instance_variable_state
+
+- name: verify deletion
+ assert:
+ that:
+ - gitlab_instance_variable_state.changed
+ - gitlab_instance_variable_state.instance_variable.removed|length == 1
diff --git a/ansible_collections/community/general/tests/integration/targets/gitlab_issue/aliases b/ansible_collections/community/general/tests/integration/targets/gitlab_issue/aliases
new file mode 100644
index 000000000..4f4e3dcc9
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/gitlab_issue/aliases
@@ -0,0 +1,6 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+gitlab/ci
+disabled
diff --git a/ansible_collections/community/general/tests/integration/targets/gitlab_issue/defaults/main.yml b/ansible_collections/community/general/tests/integration/targets/gitlab_issue/defaults/main.yml
new file mode 100644
index 000000000..f94530fbf
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/gitlab_issue/defaults/main.yml
@@ -0,0 +1,15 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+gitlab_branch: ansible_test_branch
+gitlab_project_name: ansible_test_project
+gitlab_project_group: ansible_test_group
+gitlab_host: ansible_test_host
+gitlab_api_token: ansible_test_api_token
+gitlab_labels: ansible_test_label
+gitlab_milestone_search: ansible_test_milestone_search
+gitlab_milestone_group_id: ansible_test_milestone_group_id
+gitlab_assignee_ids: ansible_test_assignee_ids
+gitlab_description_path: ansible_test_description_path \ No newline at end of file
diff --git a/ansible_collections/community/general/tests/integration/targets/gitlab_issue/files/description.md b/ansible_collections/community/general/tests/integration/targets/gitlab_issue/files/description.md
new file mode 100644
index 000000000..f0ff12a77
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/gitlab_issue/files/description.md
@@ -0,0 +1,9 @@
+<!--
+Copyright (c) Ansible Project
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
+-->
+
+### Description
+
+Issue test description \ No newline at end of file
diff --git a/ansible_collections/community/general/tests/integration/targets/gitlab_issue/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/gitlab_issue/tasks/main.yml
new file mode 100644
index 000000000..af1416c3d
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/gitlab_issue/tasks/main.yml
@@ -0,0 +1,150 @@
+---
+####################################################################
+# WARNING: These are designed specifically for Ansible tests #
+# and should not be used as examples of how to write Ansible roles #
+####################################################################
+
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Install required libs
+ pip:
+ name: python-gitlab
+ state: present
+
+- block:
+ - name: Create {{ gitlab_project_name }} project
+ gitlab_project:
+ api_url: "{{ gitlab_host }}"
+ validate_certs: true
+ api_token: "{{ gitlab_api_token }}"
+ name: "{{ gitlab_project_name }}"
+ group: "{{ gitlab_project_group }}"
+ default_branch: "{{ gitlab_branch }}"
+ initialize_with_readme: true
+ state: present
+
+ - name: Create Issue
+ gitlab_issue:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_host }}"
+ description: "Test description"
+ project: "{{ gitlab_project_group }}/{{ gitlab_project_name }}"
+ state: present
+ title: "Ansible test issue"
+ register: gitlab_issue_create
+
+ - name: Test Issue Created
+ assert:
+ that:
+ - gitlab_issue_create is changed
+
+ - name: Create Issue ( Idempotency test )
+ gitlab_issue:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_host }}"
+ description: "Test description"
+ project: "{{ gitlab_project_group }}/{{ gitlab_project_name }}"
+ state: present
+ title: "Ansible test issue"
+ register: gitlab_issue_create_idempotence
+
+ - name: Test Create Issue is Idempotent
+ assert:
+ that:
+ - gitlab_issue_create_idempotence is not changed
+
+ - name: Update Issue Test ( Additions )
+ gitlab_issue:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_host }}"
+ assignee_ids: "{{ gitlab_assignee_ids }}"
+ description_path: "{{ gitlab_description_path }}"
+ labels: "{{ gitlab_labels }}"
+ milestone_search: "{{ gitlab_milestone_search }}"
+ milestone_group_id: "{{ gitlab_milestone_group_id }}"
+ project: "{{ gitlab_project_group }}/{{ gitlab_project_name }}"
+ state: present
+ title: "Ansible test issue"
+ register: gitlab_issue_update_additions
+
+ - name: Test Issue Updated ( Additions )
+ assert:
+ that:
+ - gitlab_issue_update_additions.issue.labels[0] == "{{ gitlab_labels[0] }}"
+ - gitlab_issue_update_additions.issue.assignees[0].username == "{{ gitlab_assignee_ids[0] }}"
+ - "'### Description\n\nIssue test description' in gitlab_issue_update_additions.issue.description"
+ - gitlab_issue_update_additions.issue.milestone.title == "{{ gitlab_milestone_search }}"
+
+ - name: Update Issue Test ( Persistence )
+ gitlab_issue:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_host }}"
+ description_path: "{{ gitlab_description_path }}"
+ milestone_search: "{{ gitlab_milestone_search }}"
+ milestone_group_id: "{{ gitlab_milestone_group_id }}"
+ project: "{{ gitlab_project_group }}/{{ gitlab_project_name }}"
+ state: present
+ title: "Ansible test issue"
+ register: gitlab_issue_update_persistence
+
+ - name: Test issue Not Updated ( Persistence )
+ assert:
+ that:
+ - gitlab_issue_update_persistence.issue.labels[0] == "{{ gitlab_labels[0] }}"
+ - gitlab_issue_update_persistence.issue.assignees[0].username == "{{ gitlab_assignee_ids[0] }}"
+
+ - name: Update Issue Test ( Removals )
+ gitlab_issue:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_host }}"
+ assignee_ids: []
+ description_path: "{{ gitlab_description_path }}"
+ labels: []
+ milestone_search: ""
+ milestone_group_id: ""
+ project: "{{ gitlab_project_group }}/{{ gitlab_project_name }}"
+ state: present
+ title: "Ansible test issue"
+ register: gitlab_issue_update_removal
+
+ - name: Test issue updated
+ assert:
+ that:
+ - gitlab_issue_update_removal.issue.labels == []
+ - gitlab_issue_update_removal.issue.assignees == []
+ - gitlab_issue_update_removal.issue.milestone == None
+
+ - name: Delete Issue
+ gitlab_issue:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_api_token }}"
+ project: "{{ gitlab_project_group }}/{{ gitlab_project_name }}"
+ title: "Ansible test issue"
+ state: absent
+ register: gitlab_issue_delete
+
+ - name: Test issue is deleted
+ assert:
+ that:
+ - gitlab_issue_delete is changed
+
+ always:
+ - name: Delete Issue
+ gitlab_issue:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_api_token }}"
+ project: "{{ gitlab_project_group }}/{{ gitlab_project_name }}"
+ title: "Ansible test issue"
+ state_filter: "opened"
+ state: absent
+ register: gitlab_issue_delete
+ - name: Clean up {{ gitlab_project_name }}
+ gitlab_project:
+ api_url: "{{ gitlab_host }}"
+ validate_certs: false
+ api_token: "{{ gitlab_api_token }}"
+ name: "{{ gitlab_project_name }}"
+ group: "{{ gitlab_project_group }}"
+ state: absent
diff --git a/ansible_collections/community/general/tests/integration/targets/gitlab_label/README.md b/ansible_collections/community/general/tests/integration/targets/gitlab_label/README.md
new file mode 100644
index 000000000..e27cb74c8
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/gitlab_label/README.md
@@ -0,0 +1,19 @@
+<!--
+Copyright (c) Ansible Project
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
+-->
+
+# Gitlab integration tests
+
+1. to run integration tests locally, I've setup a podman pod with both gitlab-ee image and the testing image
+2. gitlab's related information were taken from [here](https://docs.gitlab.com/ee/install/docker.html), about the variable it needs (hostname, ports, volumes); volumes were pre-made before launching the image
+3. image that run integration tests is started with `podman run --rm -it --pod <pod_name> --name <image_name> --network=host --volume <path_to_git_repo>/ansible_community/community.general:<container_path_to>/workspace/ansible_collections/community/general quay.io/ansible/azure-pipelines-test-container:4.0.1`
+4. into the testing image, run
+```sh
+pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check
+cd <container_path_to>/workspace/ansible_collections/community/general
+ansible-test integration gitlab_label -vvv
+```
+
+While debugging with `q` package, open a second terminal and run `podman exec -it <image_name> /bin/bash` and inside it do `tail -f /tmp/q` .
diff --git a/ansible_collections/community/general/tests/integration/targets/gitlab_label/aliases b/ansible_collections/community/general/tests/integration/targets/gitlab_label/aliases
new file mode 100644
index 000000000..4f4e3dcc9
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/gitlab_label/aliases
@@ -0,0 +1,6 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+gitlab/ci
+disabled
diff --git a/ansible_collections/community/general/tests/integration/targets/gitlab_label/defaults/main.yml b/ansible_collections/community/general/tests/integration/targets/gitlab_label/defaults/main.yml
new file mode 100644
index 000000000..315cbd77f
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/gitlab_label/defaults/main.yml
@@ -0,0 +1,17 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+gitlab_project_name: ansible_test_project
+gitlab_host: ansible_test_host
+gitlab_api_token: ansible_test_api_token
+gitlab_project_group: ansible_test_group
+gitlab_branch: ansible_test_branch
+gitlab_first_label: ansible_test_label
+gitlab_first_label_color: "#112233"
+gitlab_first_label_description: "label description"
+gitlab_first_label_priority: 10
+gitlab_second_label: ansible_test_second_label
+gitlab_second_label_color: "#445566"
+gitlab_second_label_new_name: ansible_test_second_label_new_name \ No newline at end of file
diff --git a/ansible_collections/community/general/tests/integration/targets/gitlab_label/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/gitlab_label/tasks/main.yml
new file mode 100644
index 000000000..880b72ceb
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/gitlab_label/tasks/main.yml
@@ -0,0 +1,463 @@
+---
+####################################################################
+# WARNING: These are designed specifically for Ansible tests #
+# and should not be used as examples of how to write Ansible roles #
+####################################################################
+
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Install required libs
+ pip:
+ name: python-gitlab
+ state: present
+
+- block:
+###
+### Group label
+###
+
+ - name: Create {{ gitlab_project_group }}
+ gitlab_group:
+ api_url: "{{ gitlab_host }}"
+ validate_certs: true
+ api_token: "{{ gitlab_api_token }}"
+ name: "{{ gitlab_project_group }}"
+ state: present
+
+ - name: Purge all group labels for check_mode test
+ gitlab_label:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_api_token }}"
+ group: "{{ gitlab_project_group }}"
+ purge: true
+
+ - name: Group label - Add a label in check_mode
+ gitlab_label:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_host }}"
+ group: "{{ gitlab_project_group }}"
+ labels:
+ - name: "{{ gitlab_second_label }}"
+ color: "{{ gitlab_second_label_color }}"
+ check_mode: true
+ register: gitlab_group_label_state
+
+ - name: Group label - Check_mode state must be changed
+ assert:
+ that:
+ - gitlab_group_label_state is changed
+
+ - name: Group label - Create label {{ gitlab_first_label }} and {{ gitlab_second_label }}
+ gitlab_label:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_host }}"
+ group: "{{ gitlab_project_group }}"
+ labels:
+ - name: "{{ gitlab_first_label }}"
+ color: "{{ gitlab_first_label_color }}"
+ description: "{{ gitlab_first_label_description }}"
+ priority: "{{ gitlab_first_label_priority }}"
+ - name: "{{ gitlab_second_label }}"
+ color: "{{ gitlab_second_label_color }}"
+ state: present
+ register: gitlab_group_label_create
+
+ - name: Group label - Test Label Created
+ assert:
+ that:
+ - gitlab_group_label_create is changed
+ - gitlab_group_label_create.labels.added|length == 2
+ - gitlab_group_label_create.labels.untouched|length == 0
+ - gitlab_group_label_create.labels.removed|length == 0
+ - gitlab_group_label_create.labels.updated|length == 0
+ - gitlab_group_label_create.labels.added[0] == "{{ gitlab_first_label }}"
+ - gitlab_group_label_create.labels.added[1] == "{{ gitlab_second_label }}"
+
+ - name: Group label - Create Label ( Idempotency test )
+ gitlab_label:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_host }}"
+ group: "{{ gitlab_project_group }}"
+ labels:
+ - name: "{{ gitlab_first_label }}"
+ color: "{{ gitlab_first_label_color }}"
+ description: "{{ gitlab_first_label_description }}"
+ priority: "{{ gitlab_first_label_priority }}"
+ state: present
+ register: gitlab_group_label_create_idempotence
+
+ - name: Group label - Test Create Label is Idempotent
+ assert:
+ that:
+ - gitlab_group_label_create_idempotence is not changed
+
+ - name: Group label - Update Label {{ gitlab_first_label }} changing color
+ gitlab_label:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_host }}"
+ group: "{{ gitlab_project_group }}"
+ labels:
+ - name: "{{ gitlab_first_label }}"
+ color: "{{ gitlab_second_label_color }}"
+ state: present
+ register: gitlab_group_label_update
+
+ - name: Group label - Test Label Updated
+ assert:
+ that:
+ - gitlab_group_label_update.labels.added|length == 0
+ - gitlab_group_label_update.labels.untouched|length == 0
+ - gitlab_group_label_update.labels.removed|length == 0
+ - gitlab_group_label_update.labels.updated|length == 1
+ - gitlab_group_label_update.labels.updated[0] == "{{ gitlab_first_label }}"
+
+ - name: Group label - Change label {{ gitlab_second_label }} name to {{ gitlab_second_label_new_name }}
+ gitlab_label:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_host }}"
+ group: "{{ gitlab_project_group }}"
+ labels:
+ - name: "{{ gitlab_second_label }}"
+ new_name: "{{ gitlab_second_label_new_name }}"
+ state: present
+ register: gitlab_group_label_new_name
+
+ - name: Group label - Test Label name changed
+ assert:
+ that:
+ - gitlab_group_label_new_name.labels.added|length == 0
+ - gitlab_group_label_new_name.labels.untouched|length == 0
+ - gitlab_group_label_new_name.labels.removed|length == 0
+ - gitlab_group_label_new_name.labels.updated|length == 1
+ - gitlab_group_label_new_name.labels.updated[0] == "{{ gitlab_second_label }}"
+
+ - name: Group label - Change label name back to {{ gitlab_second_label }}
+ gitlab_label:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_host }}"
+ group: "{{ gitlab_project_group }}"
+ labels:
+ - name: "{{ gitlab_second_label_new_name }}"
+ new_name: "{{ gitlab_second_label }}"
+ state: present
+ register: gitlab_group_label_orig_name
+
+ - name: Group label - Test Label name changed back
+ assert:
+ that:
+ - gitlab_group_label_orig_name.labels.added|length == 0
+ - gitlab_group_label_orig_name.labels.untouched|length == 0
+ - gitlab_group_label_orig_name.labels.removed|length == 0
+ - gitlab_group_label_orig_name.labels.updated|length == 1
+ - gitlab_group_label_orig_name.labels.updated[0] == "{{ gitlab_second_label_new_name }}"
+
+ - name: Group label - Update Label Test ( Additions )
+ gitlab_label:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_host }}"
+ group: "{{ gitlab_project_group }}"
+ labels:
+ - name: "{{ gitlab_second_label }}"
+ description: "{{ gitlab_first_label_description }}"
+ priority: "{{ gitlab_first_label_priority }}"
+ state: present
+ register: gitlab_group_label_update_additions
+
+ - name: Group label - Test Label Updated ( Additions )
+ assert:
+ that:
+ - gitlab_group_label_update_additions.labels.added|length == 0
+ - gitlab_group_label_update_additions.labels.untouched|length == 0
+ - gitlab_group_label_update_additions.labels.removed|length == 0
+ - gitlab_group_label_update_additions.labels.updated|length == 1
+ - gitlab_group_label_update_additions.labels.updated[0] == "{{ gitlab_second_label }}"
+
+ - name: Group label - Delete Label {{ gitlab_second_label }}
+ gitlab_label:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_host }}"
+ group: "{{ gitlab_project_group }}"
+ labels:
+ - name: "{{ gitlab_second_label }}"
+ state: absent
+ register: gitlab_group_label_delete
+
+ - name: Group label - Test label is deleted
+ assert:
+ that:
+ - gitlab_group_label_delete is changed
+ - gitlab_group_label_delete.labels.added|length == 0
+ - gitlab_group_label_delete.labels.untouched|length == 0
+ - gitlab_group_label_delete.labels.removed|length == 1
+ - gitlab_group_label_delete.labels.updated|length == 0
+ - gitlab_group_label_delete.labels.removed[0] == "{{ gitlab_second_label }}"
+
+ - name: Group label - Create label {{ gitlab_second_label }} again purging the other
+ gitlab_label:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_host }}"
+ group: "{{ gitlab_project_group }}"
+ purge: true
+ labels:
+ - name: "{{ gitlab_second_label }}"
+ color: "{{ gitlab_second_label_color }}"
+ state: present
+ register: gitlab_group_label_create_purging
+
+ - name: Group label - Test Label Created again
+ assert:
+ that:
+ - gitlab_group_label_create_purging is changed
+ - gitlab_group_label_create_purging.labels.added|length == 1
+ - gitlab_group_label_create_purging.labels.untouched|length == 0
+ - gitlab_group_label_create_purging.labels.removed|length == 1
+ - gitlab_group_label_create_purging.labels.updated|length == 0
+ - gitlab_group_label_create_purging.labels.added[0] == "{{ gitlab_second_label }}"
+ - gitlab_group_label_create_purging.labels.removed[0] == "{{ gitlab_first_label }}"
+
+###
+### Project label
+###
+
+ - name: Create {{ gitlab_project_name }}
+ gitlab_project:
+ api_url: "{{ gitlab_host }}"
+ validate_certs: true
+ api_token: "{{ gitlab_api_token }}"
+ name: "{{ gitlab_project_name }}"
+ group: "{{ gitlab_project_group }}"
+ default_branch: "{{ gitlab_branch }}"
+ initialize_with_readme: true
+ state: present
+
+ - name: Purge all labels for check_mode test
+ gitlab_label:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_api_token }}"
+ project: "{{ gitlab_project_group }}/{{ gitlab_project_name }}"
+ purge: true
+
+ - name: Add a label in check_mode
+ gitlab_label:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_host }}"
+ project: "{{ gitlab_project_group }}/{{ gitlab_project_name }}"
+ labels:
+ - name: "{{ gitlab_second_label }}"
+ color: "{{ gitlab_second_label_color }}"
+ check_mode: true
+ register: gitlab_first_label_state
+
+ - name: Check_mode state must be changed
+ assert:
+ that:
+ - gitlab_first_label_state is changed
+
+ - name: Create label {{ gitlab_first_label }} and {{ gitlab_second_label }}
+ gitlab_label:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_host }}"
+ project: "{{ gitlab_project_group }}/{{ gitlab_project_name }}"
+ labels:
+ - name: "{{ gitlab_first_label }}"
+ color: "{{ gitlab_first_label_color }}"
+ description: "{{ gitlab_first_label_description }}"
+ priority: "{{ gitlab_first_label_priority }}"
+ - name: "{{ gitlab_second_label }}"
+ color: "{{ gitlab_second_label_color }}"
+ state: present
+ register: gitlab_first_label_create
+
+ - name: Test Label Created
+ assert:
+ that:
+ - gitlab_first_label_create is changed
+ - gitlab_first_label_create.labels.added|length == 2
+ - gitlab_first_label_create.labels.untouched|length == 0
+ - gitlab_first_label_create.labels.removed|length == 0
+ - gitlab_first_label_create.labels.updated|length == 0
+ - gitlab_first_label_create.labels.added[0] == "{{ gitlab_first_label }}"
+ - gitlab_first_label_create.labels.added[1] == "{{ gitlab_second_label }}"
+
+ - name: Create Label ( Idempotency test )
+ gitlab_label:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_host }}"
+ project: "{{ gitlab_project_group }}/{{ gitlab_project_name }}"
+ labels:
+ - name: "{{ gitlab_first_label }}"
+ color: "{{ gitlab_first_label_color }}"
+ description: "{{ gitlab_first_label_description }}"
+ priority: "{{ gitlab_first_label_priority }}"
+ state: present
+ register: gitlab_first_label_create_idempotence
+
+ - name: Test Create Label is Idempotent
+ assert:
+ that:
+ - gitlab_first_label_create_idempotence is not changed
+
+ - name: Update Label {{ gitlab_first_label }} changing color
+ gitlab_label:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_host }}"
+ project: "{{ gitlab_project_group }}/{{ gitlab_project_name }}"
+ labels:
+ - name: "{{ gitlab_first_label }}"
+ color: "{{ gitlab_second_label_color }}"
+ state: present
+ register: gitlab_first_label_update
+
+ - name: Test Label Updated
+ assert:
+ that:
+ - gitlab_first_label_update.labels.added|length == 0
+ - gitlab_first_label_update.labels.untouched|length == 0
+ - gitlab_first_label_update.labels.removed|length == 0
+ - gitlab_first_label_update.labels.updated|length == 1
+ - gitlab_first_label_update.labels.updated[0] == "{{ gitlab_first_label }}"
+
+ - name: Change label {{ gitlab_second_label }} name to {{ gitlab_second_label_new_name }}
+ gitlab_label:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_host }}"
+ project: "{{ gitlab_project_group }}/{{ gitlab_project_name }}"
+ labels:
+ - name: "{{ gitlab_second_label }}"
+ new_name: "{{ gitlab_second_label_new_name }}"
+ state: present
+ register: gitlab_first_label_new_name
+
+ - name: Test Label name changed
+ assert:
+ that:
+ - gitlab_first_label_new_name.labels.added|length == 0
+ - gitlab_first_label_new_name.labels.untouched|length == 0
+ - gitlab_first_label_new_name.labels.removed|length == 0
+ - gitlab_first_label_new_name.labels.updated|length == 1
+ - gitlab_first_label_new_name.labels.updated[0] == "{{ gitlab_second_label }}"
+
+ - name: Change label name back to {{ gitlab_second_label }}
+ gitlab_label:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_host }}"
+ project: "{{ gitlab_project_group }}/{{ gitlab_project_name }}"
+ labels:
+ - name: "{{ gitlab_second_label_new_name }}"
+ new_name: "{{ gitlab_second_label }}"
+ state: present
+ register: gitlab_first_label_orig_name
+
+ - name: Test Label name changed back
+ assert:
+ that:
+ - gitlab_first_label_orig_name.labels.added|length == 0
+ - gitlab_first_label_orig_name.labels.untouched|length == 0
+ - gitlab_first_label_orig_name.labels.removed|length == 0
+ - gitlab_first_label_orig_name.labels.updated|length == 1
+ - gitlab_first_label_orig_name.labels.updated[0] == "{{ gitlab_second_label_new_name }}"
+
+ - name: Update Label Test ( Additions )
+ gitlab_label:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_host }}"
+ project: "{{ gitlab_project_group }}/{{ gitlab_project_name }}"
+ labels:
+ - name: "{{ gitlab_second_label }}"
+ description: "{{ gitlab_first_label_description }}"
+ priority: "{{ gitlab_first_label_priority }}"
+ state: present
+ register: gitlab_first_label_update_additions
+
+ - name: Test Label Updated ( Additions )
+ assert:
+ that:
+ - gitlab_first_label_update_additions.labels.added|length == 0
+ - gitlab_first_label_update_additions.labels.untouched|length == 0
+ - gitlab_first_label_update_additions.labels.removed|length == 0
+ - gitlab_first_label_update_additions.labels.updated|length == 1
+ - gitlab_first_label_update_additions.labels.updated[0] == "{{ gitlab_second_label }}"
+
+ - name: Delete Label {{ gitlab_second_label }}
+ gitlab_label:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_host }}"
+ project: "{{ gitlab_project_group }}/{{ gitlab_project_name }}"
+ labels:
+ - name: "{{ gitlab_second_label }}"
+ state: absent
+ register: gitlab_first_label_delete
+
+ - name: Test label is deleted
+ assert:
+ that:
+ - gitlab_first_label_delete is changed
+ - gitlab_first_label_delete.labels.added|length == 0
+ - gitlab_first_label_delete.labels.untouched|length == 0
+ - gitlab_first_label_delete.labels.removed|length == 1
+ - gitlab_first_label_delete.labels.updated|length == 0
+ - gitlab_first_label_delete.labels.removed[0] == "{{ gitlab_second_label }}"
+
+ - name: Create label {{ gitlab_second_label }} again purging the other
+ gitlab_label:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_host }}"
+ project: "{{ gitlab_project_group }}/{{ gitlab_project_name }}"
+ purge: true
+ labels:
+ - name: "{{ gitlab_second_label }}"
+ color: "{{ gitlab_second_label_color }}"
+ state: present
+ register: gitlab_first_label_create_purging
+
+ - name: Test Label Created again
+ assert:
+ that:
+ - gitlab_first_label_create_purging is changed
+ - gitlab_first_label_create_purging.labels.added|length == 1
+ - gitlab_first_label_create_purging.labels.untouched|length == 0
+ - gitlab_first_label_create_purging.labels.removed|length == 1
+ - gitlab_first_label_create_purging.labels.updated|length == 0
+ - gitlab_first_label_create_purging.labels.added[0] == "{{ gitlab_second_label }}"
+ - gitlab_first_label_create_purging.labels.removed[0] == "{{ gitlab_first_label }}"
+
+ always:
+ - name: Delete Labels
+ gitlab_label:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_host }}"
+ project: "{{ gitlab_project_group }}/{{ gitlab_project_name }}"
+ purge: true
+ labels:
+ - name: "{{ gitlab_first_label }}"
+ - name: "{{ gitlab_second_label }}"
+ state: absent
+ register: gitlab_first_label_always_delete
+
+ - name: Test label are deleted
+ assert:
+ that:
+ - gitlab_first_label_always_delete is changed
+ - gitlab_first_label_always_delete.labels.added|length == 0
+ - gitlab_first_label_always_delete.labels.untouched|length == 0
+ - gitlab_first_label_always_delete.labels.removed|length > 0
+ - gitlab_first_label_always_delete.labels.updated|length == 0
+
+ - name: Clean up {{ gitlab_project_name }}
+ gitlab_project:
+ api_url: "{{ gitlab_host }}"
+ validate_certs: false
+ api_token: "{{ gitlab_api_token }}"
+ name: "{{ gitlab_project_name }}"
+ group: "{{ gitlab_project_group }}"
+ state: absent
+
+ - name: Clean up {{ gitlab_project_group }}
+ gitlab_group:
+ api_url: "{{ gitlab_host }}"
+ validate_certs: true
+ api_token: "{{ gitlab_api_token }}"
+ name: "{{ gitlab_project_group }}"
+ state: absent \ No newline at end of file
diff --git a/ansible_collections/community/general/tests/integration/targets/gitlab_merge_request/aliases b/ansible_collections/community/general/tests/integration/targets/gitlab_merge_request/aliases
new file mode 100644
index 000000000..4f4e3dcc9
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/gitlab_merge_request/aliases
@@ -0,0 +1,6 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+gitlab/ci
+disabled
diff --git a/ansible_collections/community/general/tests/integration/targets/gitlab_merge_request/defaults/main.yml b/ansible_collections/community/general/tests/integration/targets/gitlab_merge_request/defaults/main.yml
new file mode 100644
index 000000000..eb27b0b68
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/gitlab_merge_request/defaults/main.yml
@@ -0,0 +1,14 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+gitlab_source_branch: ansible_test_source_branch
+gitlab_target_branch: ansible_test_target_project
+gitlab_project_name: ansible_test_project
+gitlab_project_group: ansible_test_group
+gitlab_host: ansible_test_host
+gitlab_api_token: ansible_test_api_token
+gitlab_labels: ansible_test_label
+gitlab_assignee_ids: ansible_test_assignee_ids
+gitlab_description_path: ansible_test_description_path \ No newline at end of file
diff --git a/ansible_collections/community/general/tests/integration/targets/gitlab_merge_request/files/description.md b/ansible_collections/community/general/tests/integration/targets/gitlab_merge_request/files/description.md
new file mode 100644
index 000000000..3f662eff8
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/gitlab_merge_request/files/description.md
@@ -0,0 +1,9 @@
+<!--
+Copyright (c) Ansible Project
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
+-->
+
+### Description
+
+Merge Request test description \ No newline at end of file
diff --git a/ansible_collections/community/general/tests/integration/targets/gitlab_merge_request/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/gitlab_merge_request/tasks/main.yml
new file mode 100644
index 000000000..18da900a2
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/gitlab_merge_request/tasks/main.yml
@@ -0,0 +1,129 @@
+---
+####################################################################
+# WARNING: These are designed specifically for Ansible tests #
+# and should not be used as examples of how to write Ansible roles #
+####################################################################
+
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Install required libs
+ pip:
+ name: python-gitlab
+ state: present
+
+- block:
+ - name: Create {{ gitlab_project_name }}
+ gitlab_project:
+ api_url: "{{ gitlab_host }}"
+ validate_certs: true
+ api_token: "{{ gitlab_api_token }}"
+ name: "{{ gitlab_project_name }}"
+ group: "{{ gitlab_project_group }}"
+ default_branch: "{{ gitlab_target_branch }}"
+ initialize_with_readme: true
+ state: present
+
+ - name: Create branch {{ gitlab_source_branch }}
+ gitlab_branch:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_api_token }}"
+ project: "{{ gitlab_project_group }}/{{ gitlab_project_name }}"
+ branch: "{{ gitlab_source_branch }}"
+ ref_branch: "{{ gitlab_target_branch }}"
+ state: present
+
+ - name: Create Merge Request
+ gitlab_merge_request:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_api_token }}"
+ project: "{{ gitlab_project_group }}/{{ gitlab_project_name }}"
+ source_branch: "{{gitlab_source_branch}}"
+ target_branch: "{{gitlab_target_branch}}"
+ title: "Ansible test merge request"
+ description: "Test description"
+ labels: ""
+ state_filter: "opened"
+ assignee_ids: ""
+ reviewer_ids: ""
+ remove_source_branch: True
+ state: present
+ register: gitlab_merge_request_create
+
+ - name: Test Merge Request Created
+ assert:
+ that:
+ - gitlab_merge_request_create is changed
+
+ - name: Create Merge Request ( Idempotency test )
+ gitlab_merge_request:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_api_token }}"
+ project: "{{ gitlab_project_group }}/{{ gitlab_project_name }}"
+ source_branch: "{{gitlab_source_branch}}"
+ target_branch: "{{gitlab_target_branch}}"
+ title: "Ansible test merge request"
+ description: "Test description"
+ labels: ""
+ state_filter: "opened"
+ assignee_ids: ""
+ reviewer_ids: ""
+ remove_source_branch: True
+ state: present
+ register: gitlab_merge_request_create_idempotence
+
+ - name: Test module is idempotent
+ assert:
+ that:
+ - gitlab_merge_request_create_idempotence is not changed
+
+ - name: Update Merge Request Test
+ gitlab_merge_request:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_api_token }}"
+ project: "{{ gitlab_project_group }}/{{ gitlab_project_name }}"
+ source_branch: "{{gitlab_source_branch}}"
+ target_branch: "{{gitlab_target_branch}}"
+ title: "Ansible test merge request"
+ description_path: "{{gitlab_description_path}}"
+ labels: "{{ gitlab_labels }}"
+ state_filter: "opened"
+ assignee_ids: "{{ gitlab_assignee_ids }}"
+ reviewer_ids: ""
+ remove_source_branch: True
+ state: present
+ register: gitlab_merge_request_udpate
+
+ - name: Test merge request updated
+ assert:
+ that:
+ - gitlab_merge_request_udpate.mr.labels[0] == "{{ gitlab_labels }}"
+ - gitlab_merge_request_udpate.mr.assignees[0].username == "{{ gitlab_assignee_ids }}"
+ - "'### Description\n\nMerge Request test description' in gitlab_merge_request_udpate.mr.description"
+
+ - name: Delete Merge Request
+ gitlab_merge_request:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_api_token }}"
+ project: "{{ gitlab_project_group }}/{{ gitlab_project_name }}"
+ source_branch: "{{gitlab_source_branch}}"
+ target_branch: "{{gitlab_target_branch}}"
+ title: "Ansible test merge request"
+ state: absent
+ register: gitlab_merge_request_delete
+
+ - name: Test merge request is deleted
+ assert:
+ that:
+ - gitlab_merge_request_delete is changed
+
+ always:
+ - name: Clean up {{ gitlab_project_name }}
+ gitlab_project:
+ api_url: "{{ gitlab_host }}"
+ validate_certs: false
+ api_token: "{{ gitlab_api_token }}"
+ name: "{{ gitlab_project_name }}"
+ group: "{{ gitlab_project_group }}"
+ state: absent
diff --git a/ansible_collections/community/general/tests/integration/targets/gitlab_milestone/README.md b/ansible_collections/community/general/tests/integration/targets/gitlab_milestone/README.md
new file mode 100644
index 000000000..95bb3410b
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/gitlab_milestone/README.md
@@ -0,0 +1,19 @@
+<!--
+Copyright (c) Ansible Project
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
+-->
+
+# Gitlab integration tests
+
+1. to run integration tests locally, I've setup a podman pod with both gitlab-ee image and the testing image
+2. gitlab's related information were taken from [here](https://docs.gitlab.com/ee/install/docker.html), about the variable it needs (hostname, ports, volumes); volumes were pre-made before launching the image
+3. image that run integration tests is started with `podman run --rm -it --pod <pod_name> --name <image_name> --network=host --volume <path_to_git_repo>/ansible_community/community.general:<container_path_to>/workspace/ansible_collections/community/general quay.io/ansible/azure-pipelines-test-container:4.0.1`
+4. into the testing image, run
+```sh
+pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check
+cd <container_path_to>/workspace/ansible_collections/community/general
+ansible-test integration gitlab_milestone -vvv
+```
+
+While debugging with `q` package, open a second terminal and run `podman exec -it <image_name> /bin/bash` and inside it do `tail -f /tmp/q` .
diff --git a/ansible_collections/community/general/tests/integration/targets/gitlab_milestone/aliases b/ansible_collections/community/general/tests/integration/targets/gitlab_milestone/aliases
new file mode 100644
index 000000000..1d485e509
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/gitlab_milestone/aliases
@@ -0,0 +1,6 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+gitlab/ci
+disabled \ No newline at end of file
diff --git a/ansible_collections/community/general/tests/integration/targets/gitlab_milestone/defaults/main.yml b/ansible_collections/community/general/tests/integration/targets/gitlab_milestone/defaults/main.yml
new file mode 100644
index 000000000..d11001295
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/gitlab_milestone/defaults/main.yml
@@ -0,0 +1,18 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+gitlab_project_name: ansible_test_project
+gitlab_host: ansible_test_host
+gitlab_api_token: ansible_test_api_token
+gitlab_project_group: ansible_test_group
+gitlab_branch: ansible_test_branch
+gitlab_first_milestone: ansible_test_milestone
+gitlab_first_milestone_description: "milestone description"
+gitlab_first_milestone_start_date: "2024-01-01"
+gitlab_first_milestone_due_date: "2024-12-31"
+gitlab_first_milestone_new_start_date: "2024-05-01"
+gitlab_first_milestone_new_due_date: "2024-10-31"
+gitlab_second_milestone: ansible_test_second_milestone
+gitlab_second_milestone_description: "new milestone"
diff --git a/ansible_collections/community/general/tests/integration/targets/gitlab_milestone/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/gitlab_milestone/tasks/main.yml
new file mode 100644
index 000000000..ce78c2eef
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/gitlab_milestone/tasks/main.yml
@@ -0,0 +1,388 @@
+---
+####################################################################
+# WARNING: These are designed specifically for Ansible tests #
+# and should not be used as examples of how to write Ansible roles #
+####################################################################
+
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Install required libs
+ pip:
+ name: python-gitlab
+ state: present
+
+- block:
+###
+### Group milestone
+###
+ - name: Create {{ gitlab_project_group }}
+ gitlab_group:
+ api_url: "{{ gitlab_host }}"
+ validate_certs: true
+ api_token: "{{ gitlab_api_token }}"
+ name: "{{ gitlab_project_group }}"
+ state: present
+
+ - name: Purge all group milestones for check_mode test
+ gitlab_milestone:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_api_token }}"
+ group: "{{ gitlab_project_group }}"
+ purge: true
+
+ - name: Group milestone - Add a milestone in check_mode
+ gitlab_milestone:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_host }}"
+ group: "{{ gitlab_project_group }}"
+ milestones:
+ - title: "{{ gitlab_second_milestone }}"
+ check_mode: true
+ register: gitlab_group_milestone_state
+
+ - name: Group milestone - Check_mode state must be changed
+ assert:
+ that:
+ - gitlab_group_milestone_state is changed
+
+ - name: Purge all group milestones for project milestone test - cannot exist with same name
+ gitlab_milestone:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_api_token }}"
+ group: "{{ gitlab_project_group }}"
+ purge: true
+ register: gitlab_group_milestone_purged
+
+ - name: Group milestone - Create milestone {{ gitlab_first_milestone }} and {{ gitlab_second_milestone }}
+ gitlab_milestone:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_host }}"
+ group: "{{ gitlab_project_group }}"
+ milestones:
+ - title: "{{ gitlab_first_milestone }}"
+ start_date: "{{ gitlab_first_milestone_start_date }}"
+ due_date: "{{ gitlab_first_milestone_due_date }}"
+ - title: "{{ gitlab_second_milestone }}"
+ state: present
+ register: gitlab_group_milestone_create
+
+ - name: Group milestone - Test milestone Created
+ assert:
+ that:
+ - gitlab_group_milestone_create is changed
+ - gitlab_group_milestone_create.milestones.added|length == 2
+ - gitlab_group_milestone_create.milestones.untouched|length == 0
+ - gitlab_group_milestone_create.milestones.removed|length == 0
+ - gitlab_group_milestone_create.milestones.updated|length == 0
+ - gitlab_group_milestone_create.milestones.added[0] == "{{ gitlab_first_milestone }}"
+ - gitlab_group_milestone_create.milestones.added[1] == "{{ gitlab_second_milestone }}"
+
+ - name: Group milestone - Create milestone ( Idempotency test )
+ gitlab_milestone:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_host }}"
+ group: "{{ gitlab_project_group }}"
+ milestones:
+ - title: "{{ gitlab_first_milestone }}"
+ start_date: "{{ gitlab_first_milestone_start_date }}"
+ due_date: "{{ gitlab_first_milestone_due_date }}"
+ state: present
+ register: gitlab_group_milestone_create_idempotence
+
+ - name: Group milestone - Test Create milestone is Idempotent
+ assert:
+ that:
+ - gitlab_group_milestone_create_idempotence is not changed
+
+ - name: Group milestone - Update milestone {{ gitlab_first_milestone }} changing dates
+ gitlab_milestone:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_host }}"
+ group: "{{ gitlab_project_group }}"
+ milestones:
+ - title: "{{ gitlab_first_milestone }}"
+ start_date: "{{ gitlab_first_milestone_new_start_date }}"
+ due_date: "{{ gitlab_first_milestone_new_due_date }}"
+ state: present
+ register: gitlab_group_milestone_update
+
+ - name: Group milestone - Test milestone Updated
+ assert:
+ that:
+ - gitlab_group_milestone_update.milestones.added|length == 0
+ - gitlab_group_milestone_update.milestones.untouched|length == 0
+ - gitlab_group_milestone_update.milestones.removed|length == 0
+ - gitlab_group_milestone_update.milestones.updated|length == 1
+ - gitlab_group_milestone_update.milestones.updated[0] == "{{ gitlab_first_milestone }}"
+
+ - name: Group milestone - Update milestone Test ( Additions )
+ gitlab_milestone:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_host }}"
+ group: "{{ gitlab_project_group }}"
+ milestones:
+ - title: "{{ gitlab_second_milestone }}"
+ description: "{{ gitlab_first_milestone_description }}"
+ state: present
+ register: gitlab_group_milestone_update_additions
+
+ - name: Group milestone - Test milestone Updated ( Additions )
+ assert:
+ that:
+ - gitlab_group_milestone_update_additions.milestones.added|length == 0
+ - gitlab_group_milestone_update_additions.milestones.untouched|length == 0
+ - gitlab_group_milestone_update_additions.milestones.removed|length == 0
+ - gitlab_group_milestone_update_additions.milestones.updated|length == 1
+ - gitlab_group_milestone_update_additions.milestones.updated[0] == "{{ gitlab_second_milestone }}"
+
+ - name: Group milestone - Delete milestone {{ gitlab_second_milestone }}
+ gitlab_milestone:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_host }}"
+ group: "{{ gitlab_project_group }}"
+ milestones:
+ - title: "{{ gitlab_second_milestone }}"
+ state: absent
+ register: gitlab_group_milestone_delete
+
+ - name: Group milestone - Test milestone is deleted
+ assert:
+ that:
+ - gitlab_group_milestone_delete is changed
+ - gitlab_group_milestone_delete.milestones.added|length == 0
+ - gitlab_group_milestone_delete.milestones.untouched|length == 0
+ - gitlab_group_milestone_delete.milestones.removed|length == 1
+ - gitlab_group_milestone_delete.milestones.updated|length == 0
+ - gitlab_group_milestone_delete.milestones.removed[0] == "{{ gitlab_second_milestone }}"
+
+ - name: Group milestone - Create group milestone {{ gitlab_second_milestone }} again purging the other
+ gitlab_milestone:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_host }}"
+ group: "{{ gitlab_project_group }}"
+ purge: true
+ milestones:
+ - title: "{{ gitlab_second_milestone }}"
+ state: present
+ register: gitlab_group_milestone_create_purging
+
+ - name: Group milestone - Test milestone Created again
+ assert:
+ that:
+ - gitlab_group_milestone_create_purging is changed
+ - gitlab_group_milestone_create_purging.milestones.added|length == 1
+ - gitlab_group_milestone_create_purging.milestones.untouched|length == 0
+ - gitlab_group_milestone_create_purging.milestones.removed|length == 1
+ - gitlab_group_milestone_create_purging.milestones.updated|length == 0
+ - gitlab_group_milestone_create_purging.milestones.added[0] == "{{ gitlab_second_milestone }}"
+ - gitlab_group_milestone_create_purging.milestones.removed[0] == "{{ gitlab_first_milestone }}"
+
+###
+### Project milestone
+###
+ - name: Purge all group milestones for project milestone test - cannot exist with same name
+ gitlab_milestone:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_api_token }}"
+ group: "{{ gitlab_project_group }}"
+ purge: true
+ register: gitlab_group_milestone_purged
+
+ - name: Create {{ gitlab_project_name }}
+ gitlab_project:
+ api_url: "{{ gitlab_host }}"
+ validate_certs: true
+ api_token: "{{ gitlab_api_token }}"
+ name: "{{ gitlab_project_name }}"
+ group: "{{ gitlab_project_group }}"
+ default_branch: "{{ gitlab_branch }}"
+ initialize_with_readme: true
+ state: present
+
+ - name: Purge all milestones for check_mode test
+ gitlab_milestone:
+ api_url: "{{ gitlab_host }}"
+ api_token: "{{ gitlab_api_token }}"
+ project: "{{ gitlab_project_group }}/{{ gitlab_project_name }}"
+ purge: true
+
+ - name: Add a milestone in check_mode
+ gitlab_milestone:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_host }}"
+ project: "{{ gitlab_project_group }}/{{ gitlab_project_name }}"
+ milestones:
+ - title: "{{ gitlab_second_milestone }}"
+ description: "{{ gitlab_second_milestone_description }}"
+ check_mode: true
+ register: gitlab_first_milestone_state
+
+ - name: Check_mode state must be changed
+ assert:
+ that:
+ - gitlab_first_milestone_state is changed
+
+ - name: Create milestone {{ gitlab_first_milestone }} and {{ gitlab_second_milestone }}
+ gitlab_milestone:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_host }}"
+ project: "{{ gitlab_project_group }}/{{ gitlab_project_name }}"
+ milestones:
+ - title: "{{ gitlab_first_milestone }}"
+ start_date: "{{ gitlab_first_milestone_start_date }}"
+ due_date: "{{ gitlab_first_milestone_due_date }}"
+ - title: "{{ gitlab_second_milestone }}"
+ state: present
+ register: gitlab_milestones_create
+
+ - name: Test milestone Created
+ assert:
+ that:
+ - gitlab_milestones_create is changed
+ - gitlab_milestones_create.milestones.added|length == 2
+ - gitlab_milestones_create.milestones.untouched|length == 0
+ - gitlab_milestones_create.milestones.removed|length == 0
+ - gitlab_milestones_create.milestones.updated|length == 0
+ - gitlab_milestones_create.milestones.added[0] == "{{ gitlab_first_milestone }}"
+ - gitlab_milestones_create.milestones.added[1] == "{{ gitlab_second_milestone }}"
+
+ - name: Create milestone ( Idempotency test )
+ gitlab_milestone:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_host }}"
+ project: "{{ gitlab_project_group }}/{{ gitlab_project_name }}"
+ milestones:
+ - title: "{{ gitlab_first_milestone }}"
+ start_date: "{{ gitlab_first_milestone_start_date }}"
+ due_date: "{{ gitlab_first_milestone_due_date }}"
+ state: present
+ register: gitlab_first_milestone_create_idempotence
+
+ - name: Test Create milestone is Idempotent
+ assert:
+ that:
+ - gitlab_first_milestone_create_idempotence is not changed
+
+ - name: Update milestone {{ gitlab_first_milestone }} changing dates
+ gitlab_milestone:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_host }}"
+ project: "{{ gitlab_project_group }}/{{ gitlab_project_name }}"
+ milestones:
+ - title: "{{ gitlab_first_milestone }}"
+ start_date: "{{ gitlab_first_milestone_new_start_date }}"
+ due_date: "{{ gitlab_first_milestone_new_due_date }}"
+ state: present
+ register: gitlab_first_milestone_update
+
+ - name: Test milestone Updated
+ assert:
+ that:
+ - gitlab_first_milestone_update.milestones.added|length == 0
+ - gitlab_first_milestone_update.milestones.untouched|length == 0
+ - gitlab_first_milestone_update.milestones.removed|length == 0
+ - gitlab_first_milestone_update.milestones.updated|length == 1
+ - gitlab_first_milestone_update.milestones.updated[0] == "{{ gitlab_first_milestone }}"
+
+ - name: Update milestone Test ( Additions )
+ gitlab_milestone:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_host }}"
+ project: "{{ gitlab_project_group }}/{{ gitlab_project_name }}"
+ milestones:
+ - title: "{{ gitlab_second_milestone }}"
+ description: "{{ gitlab_second_milestone_description }}"
+ state: present
+ register: gitlab_first_milestone_update_additions
+
+ - name: Test milestone Updated ( Additions )
+ assert:
+ that:
+ - gitlab_first_milestone_update_additions.milestones.added|length == 0
+ - gitlab_first_milestone_update_additions.milestones.untouched|length == 0
+ - gitlab_first_milestone_update_additions.milestones.removed|length == 0
+ - gitlab_first_milestone_update_additions.milestones.updated|length == 1
+ - gitlab_first_milestone_update_additions.milestones.updated[0] == "{{ gitlab_second_milestone }}"
+
+ - name: Delete milestone {{ gitlab_second_milestone }}
+ gitlab_milestone:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_host }}"
+ project: "{{ gitlab_project_group }}/{{ gitlab_project_name }}"
+ milestones:
+ - title: "{{ gitlab_second_milestone }}"
+ state: absent
+ register: gitlab_first_milestone_delete
+
+ - name: Test milestone is deleted
+ assert:
+ that:
+ - gitlab_first_milestone_delete is changed
+ - gitlab_first_milestone_delete.milestones.added|length == 0
+ - gitlab_first_milestone_delete.milestones.untouched|length == 0
+ - gitlab_first_milestone_delete.milestones.removed|length == 1
+ - gitlab_first_milestone_delete.milestones.updated|length == 0
+ - gitlab_first_milestone_delete.milestones.removed[0] == "{{ gitlab_second_milestone }}"
+
+ - name: Create milestone {{ gitlab_second_milestone }} again purging the other
+ gitlab_milestone:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_host }}"
+ project: "{{ gitlab_project_group }}/{{ gitlab_project_name }}"
+ purge: true
+ milestones:
+ - title: "{{ gitlab_second_milestone }}"
+ state: present
+ register: gitlab_first_milestone_create_purging
+
+ - name: Test milestone Created again
+ assert:
+ that:
+ - gitlab_first_milestone_create_purging is changed
+ - gitlab_first_milestone_create_purging.milestones.added|length == 1
+ - gitlab_first_milestone_create_purging.milestones.untouched|length == 0
+ - gitlab_first_milestone_create_purging.milestones.removed|length == 1
+ - gitlab_first_milestone_create_purging.milestones.updated|length == 0
+ - gitlab_first_milestone_create_purging.milestones.added[0] == "{{ gitlab_second_milestone }}"
+ - gitlab_first_milestone_create_purging.milestones.removed[0] == "{{ gitlab_first_milestone }}"
+
+ always:
+ - name: Delete milestones
+ gitlab_milestone:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_host }}"
+ project: "{{ gitlab_project_group }}/{{ gitlab_project_name }}"
+ purge: true
+ milestones:
+ - title: "{{ gitlab_first_milestone }}"
+ - title: "{{ gitlab_second_milestone }}"
+ state: absent
+ register: gitlab_first_milestone_always_delete
+
+ - name: Test milestone are deleted
+ assert:
+ that:
+ - gitlab_first_milestone_always_delete is changed
+ - gitlab_first_milestone_always_delete.milestones.added|length == 0
+ - gitlab_first_milestone_always_delete.milestones.untouched|length == 0
+ - gitlab_first_milestone_always_delete.milestones.removed|length > 0
+ - gitlab_first_milestone_always_delete.milestones.updated|length == 0
+
+ - name: Clean up {{ gitlab_project_name }}
+ gitlab_project:
+ api_url: "{{ gitlab_host }}"
+ validate_certs: false
+ api_token: "{{ gitlab_api_token }}"
+ name: "{{ gitlab_project_name }}"
+ group: "{{ gitlab_project_group }}"
+ state: absent
+
+ - name: Clean up {{ gitlab_project_group }}
+ gitlab_group:
+ api_url: "{{ gitlab_host }}"
+ validate_certs: true
+ api_token: "{{ gitlab_api_token }}"
+ name: "{{ gitlab_project_group }}"
+ state: absent \ No newline at end of file
diff --git a/ansible_collections/community/general/tests/integration/targets/gitlab_project_access_token/aliases b/ansible_collections/community/general/tests/integration/targets/gitlab_project_access_token/aliases
new file mode 100644
index 000000000..fc0e157c9
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/gitlab_project_access_token/aliases
@@ -0,0 +1,7 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+azp/posix/1
+gitlab/ci
+disabled
diff --git a/ansible_collections/community/general/tests/integration/targets/gitlab_project_access_token/defaults/main.yml b/ansible_collections/community/general/tests/integration/targets/gitlab_project_access_token/defaults/main.yml
new file mode 100644
index 000000000..579584d62
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/gitlab_project_access_token/defaults/main.yml
@@ -0,0 +1,15 @@
+---
+####################################################################
+# WARNING: These are designed specifically for Ansible tests #
+# and should not be used as examples of how to write Ansible roles #
+####################################################################
+
+# Copyright (c) 2024, Zoran Krleza <zoran.krleza@true-north.hr>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+gitlab_api_token:
+gitlab_api_url:
+gitlab_validate_certs: false
+gitlab_project_name:
+gitlab_token_name:
diff --git a/ansible_collections/community/general/tests/integration/targets/gitlab_project_access_token/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/gitlab_project_access_token/tasks/main.yml
new file mode 100644
index 000000000..c3125d740
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/gitlab_project_access_token/tasks/main.yml
@@ -0,0 +1,221 @@
+---
+####################################################################
+# WARNING: These are designed specifically for Ansible tests #
+# and should not be used as examples of how to write Ansible roles #
+####################################################################
+
+# Copyright (c) 2024, Zoran Krleza <zoran.krleza@true-north.hr>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Install required libs
+ pip:
+ name: python-gitlab
+ state: present
+
+- block:
+ - name: Try to create access token in nonexisting project
+ community.general.gitlab_project_access_token:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_api_url }}"
+ validate_certs: "{{ gitlab_validate_certs }}"
+ project: "some_nonexisting_project"
+ name: "{{ gitlab_token_name }}"
+ state: present
+ expires_at: '2025-01-01'
+ access_level: developer
+ scopes:
+ - api
+ - read_api
+ register: create_pfail_token_status
+ always:
+ - name: Assert that token creation in nonexisting project failed
+ assert:
+ that:
+ - create_pfail_token_status is failed
+ ignore_errors: true
+
+- block:
+ - name: Try to create access token with nonvalid expires_at
+ community.general.gitlab_project_access_token:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_api_url }}"
+ validate_certs: "{{ gitlab_validate_certs }}"
+ project: "some_nonexisting_project"
+ name: "{{ gitlab_token_name }}"
+ state: present
+ expires_at: '2025-13-01'
+ access_level: developer
+ scopes:
+ - api
+ - read_api
+ register: create_efail_token_status
+ always:
+ - name: Assert that token creation with invalid expires_at failed
+ assert:
+ that:
+ - create_efail_token_status is failed
+ ignore_errors: true
+
+- name: Create access token
+ community.general.gitlab_project_access_token:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_api_url }}"
+ validate_certs: "{{ gitlab_validate_certs }}"
+ project: "{{ gitlab_project_name }}"
+ name: "{{ gitlab_token_name }}"
+ state: present
+ expires_at: '2024-12-31'
+ access_level: developer
+ scopes:
+ - api
+ - read_api
+ register: create_token_status
+- name: Assert that token creation with valid arguments is successfull
+ assert:
+ that:
+ - create_token_status is changed
+ - create_token_status.access_token.token is defined
+
+- name: Check existing access token recreate=never (default)
+ community.general.gitlab_project_access_token:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_api_url }}"
+ validate_certs: "{{ gitlab_validate_certs }}"
+ project: "{{ gitlab_project_name }}"
+ name: "{{ gitlab_token_name }}"
+ state: present
+ expires_at: '2024-12-31'
+ access_level: developer
+ scopes:
+ - api
+ - read_api
+ register: check_token_status
+- name: Assert that token creation without changes and recreate=never succeeds with status not changed
+ assert:
+ that:
+ - check_token_status is not changed
+ - check_token_status.access_token.token is not defined
+
+- name: Check existing access token with recreate=state_change
+ community.general.gitlab_project_access_token:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_api_url }}"
+ validate_certs: "{{ gitlab_validate_certs }}"
+ project: "{{ gitlab_project_name }}"
+ name: "{{ gitlab_token_name }}"
+ state: present
+ expires_at: '2024-12-31'
+ access_level: developer
+ scopes:
+ - api
+ - read_api
+ recreate: state_change
+ register: check_recreate_token_status
+- name: Assert that token creation without changes and recreate=state_change succeeds with status not changed
+ assert:
+ that:
+ - check_recreate_token_status is not changed
+ - check_recreate_token_status.access_token.token is not defined
+
+- block:
+ - name: Try to change existing access token with recreate=never
+ community.general.gitlab_project_access_token:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_api_url }}"
+ validate_certs: "{{ gitlab_validate_certs }}"
+ project: "{{ gitlab_project_name }}"
+ name: "{{ gitlab_token_name }}"
+ state: present
+ expires_at: '2025-01-01'
+ access_level: developer
+ scopes:
+ - api
+ - read_api
+ register: change_token_status
+ always:
+ - name: Assert that token change with recreate=never fails
+ assert:
+ that:
+ - change_token_status is failed
+ ignore_errors: true
+
+- name: Try to change existing access token with recreate=state_change
+ community.general.gitlab_project_access_token:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_api_url }}"
+ validate_certs: "{{ gitlab_validate_certs }}"
+ project: "{{ gitlab_project_name }}"
+ name: "{{ gitlab_token_name }}"
+ state: present
+ expires_at: '2025-01-01'
+ access_level: developer
+ scopes:
+ - api
+ - read_api
+ recreate: state_change
+ register: change_recreate_token_status
+- name: Assert that token change with recreate=state_change succeeds
+ assert:
+ that:
+ - change_recreate_token_status is changed
+ - change_recreate_token_status.access_token.token is defined
+
+- name: Try to change existing access token with recreate=always
+ community.general.gitlab_project_access_token:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_api_url }}"
+ validate_certs: "{{ gitlab_validate_certs }}"
+ project: "{{ gitlab_project_name }}"
+ name: "{{ gitlab_token_name }}"
+ state: present
+ expires_at: '2025-01-01'
+ access_level: developer
+ scopes:
+ - api
+ - read_api
+ recreate: always
+ register: change_recreate1_token_status
+- name: Assert that token change with recreate=always succeeds
+ assert:
+ that:
+ - change_recreate1_token_status is changed
+ - change_recreate1_token_status.access_token.token is defined
+
+- name: Revoke access token
+ community.general.gitlab_project_access_token:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_api_url }}"
+ validate_certs: "{{ gitlab_validate_certs }}"
+ project: "{{ gitlab_project_name }}"
+ name: "{{ gitlab_token_name }}"
+ state: absent
+ expires_at: '2024-12-31'
+ access_level: developer
+ scopes:
+ - api
+ - read_api
+ register: revoke_token_status
+- name: Assert that token revocation succeeds
+ assert:
+ that:
+ - revoke_token_status is changed
+
+- name: Revoke nonexisting access token
+ community.general.gitlab_project_access_token:
+ api_token: "{{ gitlab_api_token }}"
+ api_url: "{{ gitlab_api_url }}"
+ validate_certs: "{{ gitlab_validate_certs }}"
+ project: "{{ gitlab_project_name }}"
+ name: "{{ gitlab_token_name }}"
+ state: absent
+ expires_at: '2024-12-31'
+ access_level: developer
+ scopes:
+ - api
+ - read_api
+ register: revoke_token_status
+- name: Assert that token revocation succeeds with status not changed
+ assert:
+ that:
+ - revoke_token_status is not changed \ No newline at end of file
diff --git a/ansible_collections/community/general/tests/integration/targets/homebrew/aliases b/ansible_collections/community/general/tests/integration/targets/homebrew/aliases
index 11bb9a086..bd478505d 100644
--- a/ansible_collections/community/general/tests/integration/targets/homebrew/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/homebrew/aliases
@@ -7,4 +7,3 @@ skip/aix
skip/freebsd
skip/rhel
skip/docker
-skip/python2.6
diff --git a/ansible_collections/community/general/tests/integration/targets/homebrew/tasks/casks.yml b/ansible_collections/community/general/tests/integration/targets/homebrew/tasks/casks.yml
new file mode 100644
index 000000000..42d3515bf
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/homebrew/tasks/casks.yml
@@ -0,0 +1,99 @@
+---
+####################################################################
+# WARNING: These are designed specifically for Ansible tests #
+# and should not be used as examples of how to write Ansible roles #
+####################################################################
+
+# Test code for the homebrew module.
+# Copyright (c) 2020, Abhijeet Kasurde <akasurde@redhat.com>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Find brew binary
+ command: which brew
+ register: brew_which
+ when: ansible_distribution in ['MacOSX']
+
+- name: Get owner of brew binary
+ stat:
+ path: "{{ brew_which.stdout }}"
+ register: brew_stat
+ when: ansible_distribution in ['MacOSX']
+
+#- name: Use ignored-pinned option while upgrading all
+# homebrew:
+# upgrade_all: true
+# upgrade_options: ignore-pinned
+# become: true
+# become_user: "{{ brew_stat.stat.pw_name }}"
+# register: upgrade_option_result
+# environment:
+# HOMEBREW_NO_AUTO_UPDATE: True
+
+#- assert:
+# that:
+# - upgrade_option_result.changed
+
+- vars:
+ package_name: kitty
+
+ block:
+ - name: Make sure {{ package_name }} package is not installed
+ homebrew:
+ name: "{{ package_name }}"
+ state: absent
+ update_homebrew: false
+ become: true
+ become_user: "{{ brew_stat.stat.pw_name }}"
+
+ - name: Install {{ package_name }} package using homebrew
+ homebrew:
+ name: "{{ package_name }}"
+ state: present
+ update_homebrew: false
+ become: true
+ become_user: "{{ brew_stat.stat.pw_name }}"
+ register: package_result
+
+ - assert:
+ that:
+ - package_result.changed
+
+ - name: Again install {{ package_name }} package using homebrew
+ homebrew:
+ name: "{{ package_name }}"
+ state: present
+ update_homebrew: false
+ become: true
+ become_user: "{{ brew_stat.stat.pw_name }}"
+ register: package_result
+
+ - assert:
+ that:
+ - not package_result.changed
+
+ - name: Uninstall {{ package_name }} package using homebrew
+ homebrew:
+ name: "{{ package_name }}"
+ state: absent
+ update_homebrew: false
+ become: true
+ become_user: "{{ brew_stat.stat.pw_name }}"
+ register: package_result
+
+ - assert:
+ that:
+ - package_result.changed
+
+ - name: Again uninstall {{ package_name }} package using homebrew
+ homebrew:
+ name: "{{ package_name }}"
+ state: absent
+ update_homebrew: false
+ become: true
+ become_user: "{{ brew_stat.stat.pw_name }}"
+ register: package_result
+
+ - assert:
+ that:
+ - not package_result.changed
diff --git a/ansible_collections/community/general/tests/integration/targets/homebrew/tasks/formulae.yml b/ansible_collections/community/general/tests/integration/targets/homebrew/tasks/formulae.yml
new file mode 100644
index 000000000..1db3ef1a6
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/homebrew/tasks/formulae.yml
@@ -0,0 +1,99 @@
+---
+####################################################################
+# WARNING: These are designed specifically for Ansible tests #
+# and should not be used as examples of how to write Ansible roles #
+####################################################################
+
+# Test code for the homebrew module.
+# Copyright (c) 2020, Abhijeet Kasurde <akasurde@redhat.com>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Find brew binary
+ command: which brew
+ register: brew_which
+ when: ansible_distribution in ['MacOSX']
+
+- name: Get owner of brew binary
+ stat:
+ path: "{{ brew_which.stdout }}"
+ register: brew_stat
+ when: ansible_distribution in ['MacOSX']
+
+#- name: Use ignored-pinned option while upgrading all
+# homebrew:
+# upgrade_all: true
+# upgrade_options: ignore-pinned
+# become: true
+# become_user: "{{ brew_stat.stat.pw_name }}"
+# register: upgrade_option_result
+# environment:
+# HOMEBREW_NO_AUTO_UPDATE: True
+
+#- assert:
+# that:
+# - upgrade_option_result.changed
+
+- vars:
+ package_name: gnu-tar
+
+ block:
+ - name: Make sure {{ package_name }} package is not installed
+ homebrew:
+ name: "{{ package_name }}"
+ state: absent
+ update_homebrew: false
+ become: true
+ become_user: "{{ brew_stat.stat.pw_name }}"
+
+ - name: Install {{ package_name }} package using homebrew
+ homebrew:
+ name: "{{ package_name }}"
+ state: present
+ update_homebrew: false
+ become: true
+ become_user: "{{ brew_stat.stat.pw_name }}"
+ register: package_result
+
+ - assert:
+ that:
+ - package_result.changed
+
+ - name: Again install {{ package_name }} package using homebrew
+ homebrew:
+ name: "{{ package_name }}"
+ state: present
+ update_homebrew: false
+ become: true
+ become_user: "{{ brew_stat.stat.pw_name }}"
+ register: package_result
+
+ - assert:
+ that:
+ - not package_result.changed
+
+ - name: Uninstall {{ package_name }} package using homebrew
+ homebrew:
+ name: "{{ package_name }}"
+ state: absent
+ update_homebrew: false
+ become: true
+ become_user: "{{ brew_stat.stat.pw_name }}"
+ register: package_result
+
+ - assert:
+ that:
+ - package_result.changed
+
+ - name: Again uninstall {{ package_name }} package using homebrew
+ homebrew:
+ name: "{{ package_name }}"
+ state: absent
+ update_homebrew: false
+ become: true
+ become_user: "{{ brew_stat.stat.pw_name }}"
+ register: package_result
+
+ - assert:
+ that:
+ - not package_result.changed
diff --git a/ansible_collections/community/general/tests/integration/targets/homebrew/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/homebrew/tasks/main.yml
index 1db3ef1a6..f5479917e 100644
--- a/ansible_collections/community/general/tests/integration/targets/homebrew/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/homebrew/tasks/main.yml
@@ -9,91 +9,9 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
-- name: Find brew binary
- command: which brew
- register: brew_which
- when: ansible_distribution in ['MacOSX']
-
-- name: Get owner of brew binary
- stat:
- path: "{{ brew_which.stdout }}"
- register: brew_stat
- when: ansible_distribution in ['MacOSX']
-
-#- name: Use ignored-pinned option while upgrading all
-# homebrew:
-# upgrade_all: true
-# upgrade_options: ignore-pinned
-# become: true
-# become_user: "{{ brew_stat.stat.pw_name }}"
-# register: upgrade_option_result
-# environment:
-# HOMEBREW_NO_AUTO_UPDATE: True
-
-#- assert:
-# that:
-# - upgrade_option_result.changed
-
-- vars:
- package_name: gnu-tar
-
+- block:
+ - include_tasks: 'formulae.yml'
+
+- when: ansible_distribution in ['MacOSX']
block:
- - name: Make sure {{ package_name }} package is not installed
- homebrew:
- name: "{{ package_name }}"
- state: absent
- update_homebrew: false
- become: true
- become_user: "{{ brew_stat.stat.pw_name }}"
-
- - name: Install {{ package_name }} package using homebrew
- homebrew:
- name: "{{ package_name }}"
- state: present
- update_homebrew: false
- become: true
- become_user: "{{ brew_stat.stat.pw_name }}"
- register: package_result
-
- - assert:
- that:
- - package_result.changed
-
- - name: Again install {{ package_name }} package using homebrew
- homebrew:
- name: "{{ package_name }}"
- state: present
- update_homebrew: false
- become: true
- become_user: "{{ brew_stat.stat.pw_name }}"
- register: package_result
-
- - assert:
- that:
- - not package_result.changed
-
- - name: Uninstall {{ package_name }} package using homebrew
- homebrew:
- name: "{{ package_name }}"
- state: absent
- update_homebrew: false
- become: true
- become_user: "{{ brew_stat.stat.pw_name }}"
- register: package_result
-
- - assert:
- that:
- - package_result.changed
-
- - name: Again uninstall {{ package_name }} package using homebrew
- homebrew:
- name: "{{ package_name }}"
- state: absent
- update_homebrew: false
- become: true
- become_user: "{{ brew_stat.stat.pw_name }}"
- register: package_result
-
- - assert:
- that:
- - not package_result.changed
+ - include_tasks: 'casks.yml'
diff --git a/ansible_collections/community/general/tests/integration/targets/homebrew_cask/aliases b/ansible_collections/community/general/tests/integration/targets/homebrew_cask/aliases
index 11bb9a086..bd478505d 100644
--- a/ansible_collections/community/general/tests/integration/targets/homebrew_cask/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/homebrew_cask/aliases
@@ -7,4 +7,3 @@ skip/aix
skip/freebsd
skip/rhel
skip/docker
-skip/python2.6
diff --git a/ansible_collections/community/general/tests/integration/targets/homectl/aliases b/ansible_collections/community/general/tests/integration/targets/homectl/aliases
index b87db2e43..ea9b44230 100644
--- a/ansible_collections/community/general/tests/integration/targets/homectl/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/homectl/aliases
@@ -9,3 +9,5 @@ skip/osx
skip/macos
skip/rhel9.0 # See https://www.reddit.com/r/Fedora/comments/si7nzk/homectl/
skip/rhel9.1 # See https://www.reddit.com/r/Fedora/comments/si7nzk/homectl/
+skip/rhel9.2 # See https://www.reddit.com/r/Fedora/comments/si7nzk/homectl/
+skip/rhel9.3 # See https://www.reddit.com/r/Fedora/comments/si7nzk/homectl/
diff --git a/ansible_collections/community/general/tests/integration/targets/htpasswd/aliases b/ansible_collections/community/general/tests/integration/targets/htpasswd/aliases
new file mode 100644
index 000000000..e3339b210
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/htpasswd/aliases
@@ -0,0 +1,7 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+azp/posix/2
+destructive
+needs/root
diff --git a/ansible_collections/community/general/tests/integration/targets/htpasswd/handlers/main.yml b/ansible_collections/community/general/tests/integration/targets/htpasswd/handlers/main.yml
new file mode 100644
index 000000000..6befa0cd3
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/htpasswd/handlers/main.yml
@@ -0,0 +1,9 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: remove passlib
+ ansible.builtin.pip:
+ name: passlib
+ state: absent
diff --git a/ansible_collections/community/general/tests/integration/targets/htpasswd/meta/main.yml b/ansible_collections/community/general/tests/integration/targets/htpasswd/meta/main.yml
new file mode 100644
index 000000000..982de6eb0
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/htpasswd/meta/main.yml
@@ -0,0 +1,7 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+dependencies:
+ - setup_remote_tmp_dir
diff --git a/ansible_collections/community/general/tests/integration/targets/htpasswd/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/htpasswd/tasks/main.yml
new file mode 100644
index 000000000..7b5dc3c51
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/htpasswd/tasks/main.yml
@@ -0,0 +1,83 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: install passlib
+ ansible.builtin.pip:
+ name: passlib
+ notify: remove passlib
+
+- name: add bob (check mode)
+ community.general.htpasswd:
+ path: "{{ htpasswd_path }}"
+ name: bob
+ password: c00lbob
+ check_mode: true
+ register: add_bob_check
+
+- name: add bob
+ community.general.htpasswd:
+ path: "{{ htpasswd_path }}"
+ name: bob
+ password: c00lbob
+ register: add_bob
+
+- name: add bob (idempotency)
+ community.general.htpasswd:
+ path: "{{ htpasswd_path }}"
+ name: bob
+ password: c00lbob
+ register: add_bob_idempot
+
+- name: add bob new password
+ community.general.htpasswd:
+ path: "{{ htpasswd_path }}"
+ name: bob
+ password: SUPERsecret
+ register: add_bob_newpw
+
+- name: add bob new password (idempotency)
+ community.general.htpasswd:
+ path: "{{ htpasswd_path }}"
+ name: bob
+ password: SUPERsecret
+ register: add_bob_newpw_idempot
+
+- name: test add bob assertions
+ ansible.builtin.assert:
+ that:
+ - add_bob_check is changed
+ - add_bob is changed
+ - add_bob_idempot is not changed
+ - add_bob_newpw is changed
+ - add_bob_newpw_idempot is not changed
+
+- name: remove bob (check mode)
+ community.general.htpasswd:
+ path: "{{ htpasswd_path }}"
+ name: bob
+ state: absent
+ check_mode: true
+ register: del_bob_check
+
+- name: remove bob
+ community.general.htpasswd:
+ path: "{{ htpasswd_path }}"
+ name: bob
+ state: absent
+ register: del_bob
+
+- name: remove bob (idempotency)
+ community.general.htpasswd:
+ path: "{{ htpasswd_path }}"
+ name: bob
+ state: absent
+ register: del_bob_idempot
+
+- name: test remove bob assertions
+ ansible.builtin.assert:
+ that:
+ - del_bob_check is changed
+ - del_bob is changed
+ - del_bob_idempot is not changed
diff --git a/ansible_collections/community/general/tests/integration/targets/htpasswd/vars/main.yml b/ansible_collections/community/general/tests/integration/targets/htpasswd/vars/main.yml
new file mode 100644
index 000000000..ff81959c4
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/htpasswd/vars/main.yml
@@ -0,0 +1,6 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+htpasswd_path: "{{ remote_tmp_dir }}/dot_htpasswd"
diff --git a/ansible_collections/community/general/tests/integration/targets/ini_file/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/ini_file/tasks/main.yml
index 11c5bf3b2..0ed3c2817 100644
--- a/ansible_collections/community/general/tests/integration/targets/ini_file/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/ini_file/tasks/main.yml
@@ -38,3 +38,15 @@
- name: include tasks to test regressions
include_tasks: tests/03-encoding.yml
+
+ - name: include tasks to test symlink handling
+ include_tasks: tests/04-symlink.yml
+
+ - name: include tasks to test ignore_spaces
+ include_tasks: tests/05-ignore_spaces.yml
+
+ - name: include tasks to test modify_inactive_option
+ include_tasks: tests/06-modify_inactive_option.yml
+
+ - name: include tasks to test optional spaces in section headings
+ include_tasks: tests/07-section_name_spaces.yml
diff --git a/ansible_collections/community/general/tests/integration/targets/ini_file/tasks/tests/00-basic.yml b/ansible_collections/community/general/tests/integration/targets/ini_file/tasks/tests/00-basic.yml
index c619e937a..f36fd54c5 100644
--- a/ansible_collections/community/general/tests/integration/targets/ini_file/tasks/tests/00-basic.yml
+++ b/ansible_collections/community/general/tests/integration/targets/ini_file/tasks/tests/00-basic.yml
@@ -3,7 +3,7 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
-## basiscs
+## basics
- name: test-basic 1 - specify both "value" and "values" and fail
ini_file:
@@ -39,4 +39,4 @@
that:
- result_basic_2 is not changed
- result_basic_2 is failed
- - result_basic_2.msg == "Destination {{ non_existing_file }} does not exist!"
+ - result_basic_2.msg == "Destination " ~ non_existing_file ~ " does not exist!"
diff --git a/ansible_collections/community/general/tests/integration/targets/ini_file/tasks/tests/04-symlink.yml b/ansible_collections/community/general/tests/integration/targets/ini_file/tasks/tests/04-symlink.yml
new file mode 100644
index 000000000..7e83a010d
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/ini_file/tasks/tests/04-symlink.yml
@@ -0,0 +1,59 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- block: &prepare
+ - name: Create the final file
+ ansible.builtin.copy:
+ content: |
+ [main]
+ foo=BAR
+ dest: "{{ remote_tmp_dir }}/my_original_file.ini"
+ - name: Clean up symlink.ini
+ ansible.builtin.file:
+ path: "{{ remote_tmp_dir }}/symlink.ini"
+ state: absent
+ - name: Create a symbolic link
+ ansible.builtin.file:
+ src: my_original_file.ini
+ dest: "{{ remote_tmp_dir }}/symlink.ini"
+ state: link
+
+- name: Set the proxy key on the symlink which will be converted as a file
+ community.general.ini_file:
+ path: "{{ remote_tmp_dir }}/symlink.ini"
+ section: main
+ option: proxy
+ value: 'http://proxy.myorg.org:3128'
+- name: Set the proxy key on the final file that is still unchanged
+ community.general.ini_file:
+ path: "{{ remote_tmp_dir }}/my_original_file.ini"
+ section: main
+ option: proxy
+ value: 'http://proxy.myorg.org:3128'
+ register: result
+- ansible.builtin.assert:
+ that:
+ - result is changed
+
+# With follow
+- block: *prepare
+- name: Set the proxy key on the symlink which will be preserved
+ community.general.ini_file:
+ path: "{{ remote_tmp_dir }}/symlink.ini"
+ section: main
+ option: proxy
+ value: 'http://proxy.myorg.org:3128'
+ follow: true
+ register: result
+- name: Set the proxy key on the target directly that was changed in the previous step
+ community.general.ini_file:
+ path: "{{ remote_tmp_dir }}/my_original_file.ini"
+ section: main
+ option: proxy
+ value: 'http://proxy.myorg.org:3128'
+ register: result
+- ansible.builtin.assert:
+ that:
+ - "not (result is changed)"
diff --git a/ansible_collections/community/general/tests/integration/targets/ini_file/tasks/tests/05-ignore_spaces.yml b/ansible_collections/community/general/tests/integration/targets/ini_file/tasks/tests/05-ignore_spaces.yml
new file mode 100644
index 000000000..3c4b068fb
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/ini_file/tasks/tests/05-ignore_spaces.yml
@@ -0,0 +1,123 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+## testing ignore_spaces option
+
+- name: test-ignore_spaces 1 (commented line updated) - create test file
+ copy:
+ dest: "{{ output_file }}"
+ content: "[foo]\n; bar=baz\n"
+
+- name: test-ignore_spaces 1 - set new value
+ ini_file:
+ path: "{{ output_file }}"
+ section: foo
+ option: bar
+ value: frelt
+ ignore_spaces: true
+ register: result
+
+- name: test-ignore_spaces 1 - read content from output file
+ slurp:
+ src: "{{ output_file }}"
+ register: output_content
+
+- name: test-ignore_spaces 1 - verify results
+ vars:
+ actual_content: "{{ output_content.content | b64decode }}"
+ expected_content: "[foo]\nbar = frelt\n"
+ assert:
+ that:
+ - actual_content == expected_content
+ - result is changed
+ - result.msg == 'option changed'
+
+- name: test-ignore_spaces 2 (uncommented line updated) - create test file
+ copy:
+ dest: "{{ output_file }}"
+ content: "[foo]\nbar=baz\n"
+
+- name: test-ignore_spaces 2 - set new value
+ ini_file:
+ path: "{{ output_file }}"
+ section: foo
+ option: bar
+ value: frelt
+ ignore_spaces: true
+ register: result
+
+- name: test-ignore_spaces 2 - read content from output file
+ slurp:
+ src: "{{ output_file }}"
+ register: output_content
+
+- name: test-ignore_spaces 2 - verify results
+ vars:
+ actual_content: "{{ output_content.content | b64decode }}"
+ expected_content: "[foo]\nbar = frelt\n"
+ assert:
+ that:
+ - actual_content == expected_content
+ - result is changed
+ - result.msg == 'option changed'
+
+- name: test-ignore_spaces 3 (spaces on top of no spaces) - create test file
+ copy:
+ dest: "{{ output_file }}"
+ content: "[foo]\nbar=baz\n"
+
+- name: test-ignore_spaces 3 - try to set value
+ ini_file:
+ path: "{{ output_file }}"
+ section: foo
+ option: bar
+ value: baz
+ ignore_spaces: true
+ register: result
+
+- name: test-ignore_spaces 3 - read content from output file
+ slurp:
+ src: "{{ output_file }}"
+ register: output_content
+
+- name: test-ignore_spaces 3 - verify results
+ vars:
+ actual_content: "{{ output_content.content | b64decode }}"
+ expected_content: "[foo]\nbar=baz\n"
+ assert:
+ that:
+ - actual_content == expected_content
+ - result is not changed
+ - result.msg == "OK"
+
+- name: test-ignore_spaces 4 (no spaces on top of spaces) - create test file
+ copy:
+ dest: "{{ output_file }}"
+ content: "[foo]\nbar = baz\n"
+
+- name: test-ignore_spaces 4 - try to set value
+ ini_file:
+ path: "{{ output_file }}"
+ section: foo
+ option: bar
+ value: baz
+ ignore_spaces: true
+ no_extra_spaces: true
+ register: result
+
+- name: test-ignore_spaces 4 - read content from output file
+ slurp:
+ src: "{{ output_file }}"
+ register: output_content
+
+- name: test-ignore_spaces 4 - verify results
+ vars:
+ actual_content: "{{ output_content.content | b64decode }}"
+ expected_content: "[foo]\nbar = baz\n"
+ assert:
+ that:
+ - actual_content == expected_content
+ - result is not changed
+ - result.msg == "OK"
diff --git a/ansible_collections/community/general/tests/integration/targets/ini_file/tasks/tests/06-modify_inactive_option.yml b/ansible_collections/community/general/tests/integration/targets/ini_file/tasks/tests/06-modify_inactive_option.yml
new file mode 100644
index 000000000..2d1d04928
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/ini_file/tasks/tests/06-modify_inactive_option.yml
@@ -0,0 +1,123 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+## testing modify_inactive_option option
+
+- name: test-modify_inactive_option 1 - create test file
+ copy:
+ content: |
+
+ [section1]
+ # Uncomment the line below to enable foo
+ # foo = bar
+
+ dest: "{{ output_file }}"
+
+- name: test-modify_inactive_option 1 - set value for foo with modify_inactive_option set to true
+ ini_file:
+ path: "{{ output_file }}"
+ section: section1
+ option: foo
+ value: bar
+ modify_inactive_option: true
+ register: result1
+
+- name: test-modify_inactive_option 1 - read content from output file
+ slurp:
+ src: "{{ output_file }}"
+ register: output_content
+
+- name: test-modify_inactive_option 1 - set expected content and get current ini file content
+ set_fact:
+ expected1: |
+
+ [section1]
+ # Uncomment the line below to enable foo
+ foo = bar
+
+ content1: "{{ output_content.content | b64decode }}"
+
+- name: test-modify_inactive_option 1 - assert 'changed' is true, content is OK and option changed
+ assert:
+ that:
+ - result1 is changed
+ - result1.msg == 'option changed'
+ - content1 == expected1
+
+
+- name: test-modify_inactive_option 2 - create test file
+ copy:
+ content: |
+
+ [section1]
+ # Uncomment the line below to enable foo
+ # foo = bar
+
+ dest: "{{ output_file }}"
+
+- name: test-modify_inactive_option 2 - set value for foo with modify_inactive_option set to false
+ ini_file:
+ path: "{{ output_file }}"
+ section: section1
+ option: foo
+ value: bar
+ modify_inactive_option: false
+ register: result2
+
+- name: test-modify_inactive_option 2 - read content from output file
+ slurp:
+ src: "{{ output_file }}"
+ register: output_content
+
+- name: test-modify_inactive_option 2 - set expected content and get current ini file content
+ set_fact:
+ expected2: |
+
+ [section1]
+ foo = bar
+ # Uncomment the line below to enable foo
+ # foo = bar
+
+ content2: "{{ output_content.content | b64decode }}"
+
+- name: test-modify_inactive_option 2 - assert 'changed' is true and content is OK and option added
+ assert:
+ that:
+ - result2 is changed
+ - result2.msg == 'option added'
+ - content2 == expected2
+
+
+- name: test-modify_inactive_option 3 - remove foo=bar with modify_inactive_option set to true to ensure it doesn't have effect for removal
+ ini_file:
+ path: "{{ output_file }}"
+ section: section1
+ option: foo
+ value: bar
+ modify_inactive_option: true
+ state: absent
+ register: result3
+
+- name: test-modify_inactive_option 3 - read content from output file
+ slurp:
+ src: "{{ output_file }}"
+ register: output_content
+
+- name: test-modify_inactive_option 3 - set expected content and get current ini file content
+ set_fact:
+ expected3: |
+
+ [section1]
+ # Uncomment the line below to enable foo
+ # foo = bar
+
+ content3: "{{ output_content.content | b64decode }}"
+
+- name: test-modify_inactive_option 3 - assert 'changed' is true and content is OK and active option removed
+ assert:
+ that:
+ - result3 is changed
+ - result3.msg == 'option changed'
+ - content3 == expected3 \ No newline at end of file
diff --git a/ansible_collections/community/general/tests/integration/targets/ini_file/tasks/tests/07-section_name_spaces.yml b/ansible_collections/community/general/tests/integration/targets/ini_file/tasks/tests/07-section_name_spaces.yml
new file mode 100644
index 000000000..6cdcfef40
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/ini_file/tasks/tests/07-section_name_spaces.yml
@@ -0,0 +1,103 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+## testing support for optional spaces between brackets and section names
+
+- name: Test-section_name_spaces 1 (does legacy workaround still work) - create test file
+ ansible.builtin.copy: # noqa risky-file-permissions
+ dest: "{{ output_file }}"
+ content: |
+ [ foo ]
+ ; bar=baz
+
+- name: Test-section_name_spaces 1 - update with optional spaces specified
+ community.general.ini_file: # noqa risky-file-permissions
+ path: "{{ output_file }}"
+ section: ' foo '
+ option: bar
+ value: frelt
+ register: result
+
+- name: Test-section_name_spaces 1 - read content from output file
+ ansible.builtin.slurp:
+ src: "{{ output_file }}"
+ register: output_content
+
+- name: Test-section_name_spaces 1 - verify results
+ vars:
+ actual_content: "{{ output_content.content | b64decode }}"
+ expected_content: |
+ [ foo ]
+ bar = frelt
+ ansible.builtin.assert:
+ that:
+ - actual_content == expected_content
+ - result is changed
+ - result.msg == 'option changed'
+
+
+- name: Test-section_name_spaces 2 (optional spaces omitted) - create test file
+ ansible.builtin.copy: # noqa risky-file-permissions
+ dest: "{{ output_file }}"
+ content: |
+ [ foo ]
+ bar=baz"
+
+- name: Test-section_name_spaces 2 - update without optional spaces
+ community.general.ini_file: # noqa risky-file-permissions
+ path: "{{ output_file }}"
+ section: foo
+ option: bar
+ value: frelt
+ ignore_spaces: true
+ register: result
+
+- name: Test-section_name_spaces 2 - read content from output file
+ ansible.builtin.slurp:
+ src: "{{ output_file }}"
+ register: output_content
+
+- name: Test-section_name_spaces 2 - verify results
+ vars:
+ actual_content: "{{ output_content.content | b64decode }}"
+ expected_content: "[ foo ]\nbar = frelt\n"
+ ansible.builtin.assert:
+ that:
+ - actual_content == expected_content
+ - result is changed
+ - result.msg == 'option changed'
+
+
+- name: Test-section_name_spaces 3 (legacy workaround when not required) - create test file
+ ansible.builtin.copy: # noqa risky-file-permissions
+ dest: "{{ output_file }}"
+ content: |
+ [foo]
+ ; bar=baz
+
+- name: Test-section_name_spaces 3 - update with optional spaces specified
+ community.general.ini_file: # noqa risky-file-permissions
+ path: "{{ output_file }}"
+ section: ' foo '
+ option: bar
+ value: frelt
+ register: result
+
+- name: Test-section_name_spaces 3 - read content from output file
+ ansible.builtin.slurp:
+ src: "{{ output_file }}"
+ register: output_content
+
+- name: Test-section_name_spaces 3 - verify results
+ vars:
+ actual_content: "{{ output_content.content | b64decode }}"
+ expected_content: |
+ [foo]
+ bar = frelt
+ ansible.builtin.assert:
+ that:
+ - actual_content == expected_content
+ - result is changed
+ - result.msg == 'option changed'
diff --git a/ansible_collections/community/general/tests/integration/targets/interfaces_file/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/interfaces_file/tasks/main.yml
index 918a32331..18af12f5a 100644
--- a/ansible_collections/community/general/tests/integration/targets/interfaces_file/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/interfaces_file/tasks/main.yml
@@ -7,6 +7,7 @@
set_fact:
interfaces_testfile: '{{ remote_tmp_dir }}/interfaces'
interfaces_testfile_3841: '{{ remote_tmp_dir }}/interfaces_3841'
+ interfaces_testfile_7610: '{{ remote_tmp_dir }}/interfaces_7610'
- name: Copy interfaces file
copy:
@@ -65,3 +66,60 @@
that:
- ifile_3841_a is changed
- ifile_3841_b is not changed
+
+- name: 7610 - create file
+ copy:
+ dest: '{{ interfaces_testfile_7610 }}'
+ content: |
+ iface ens3 inet dhcp
+ iface ens3 inet6 auto
+
+- name: 7610 - modify file
+ interfaces_file:
+ dest: '{{ interfaces_testfile_7610 }}'
+ iface: ens3
+ address_family: "inet6"
+ option: "{{ item.option }}"
+ value: "{{ item.value }}"
+ loop:
+ - option: "method"
+ value: "static"
+ - option: "address"
+ value: "1:2::3/48"
+
+- name: 7610 - read file
+ slurp:
+ src: '{{ interfaces_testfile_7610 }}'
+ register: content_7610
+
+- name: 7610 - check assertions
+ assert:
+ that:
+ - content_7610.content | b64decode == expected_content
+ vars:
+ expected_content: |
+ iface ens3 inet dhcp
+ iface ens3 inet6 static
+ address 1:2::3/48
+
+- name: 7610 - modify file again
+ interfaces_file:
+ dest: '{{ interfaces_testfile_7610 }}'
+ iface: ens3
+ option: method
+ value: foobar
+
+- name: 7610 - read file
+ slurp:
+ src: '{{ interfaces_testfile_7610 }}'
+ register: content_7610
+
+- name: 7610 - check assertions
+ assert:
+ that:
+ - content_7610.content | b64decode == expected_content
+ vars:
+ expected_content: |
+ iface ens3 inet foobar
+ iface ens3 inet6 foobar
+ address 1:2::3/48
diff --git a/ansible_collections/community/general/tests/integration/targets/iptables_state/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/iptables_state/tasks/main.yml
index a74e74df4..d55007067 100644
--- a/ansible_collections/community/general/tests/integration/targets/iptables_state/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/iptables_state/tasks/main.yml
@@ -29,6 +29,12 @@
when:
- xtables_lock is undefined
+ - name: include tasks to test partial restore files
+ include_tasks: tests/02-partial-restore.yml
+ when:
+ - xtables_lock is undefined
+
+
- name: include tasks to test rollbacks
include_tasks: tests/10-rollback.yml
when:
diff --git a/ansible_collections/community/general/tests/integration/targets/iptables_state/tasks/tests/02-partial-restore.yml b/ansible_collections/community/general/tests/integration/targets/iptables_state/tasks/tests/02-partial-restore.yml
new file mode 100644
index 000000000..6da4814af
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/iptables_state/tasks/tests/02-partial-restore.yml
@@ -0,0 +1,66 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: "Create initial rule set to use"
+ copy:
+ dest: "{{ iptables_tests }}"
+ content: |
+ *filter
+ :INPUT ACCEPT [0:0]
+ :FORWARD ACCEPT [0:0]
+ :OUTPUT ACCEPT [0:0]
+ -A INPUT -m state --state NEW,ESTABLISHED -j ACCEPT
+ COMMIT
+ *nat
+ :PREROUTING ACCEPT [151:17304]
+ :INPUT ACCEPT [151:17304]
+ :OUTPUT ACCEPT [151:17304]
+ :POSTROUTING ACCEPT [151:17304]
+ -A POSTROUTING -o eth0 -j MASQUERADE
+ COMMIT
+
+- name: "Restore initial state"
+ iptables_state:
+ path: "{{ iptables_tests }}"
+ state: restored
+ async: "{{ ansible_timeout }}"
+ poll: 0
+
+- name: "Create partial ruleset only specifying input"
+ copy:
+ dest: "{{ iptables_tests }}"
+ content: |
+ *filter
+ :INPUT ACCEPT [0:0]
+ :FORWARD ACCEPT [0:0]
+ :OUTPUT ACCEPT [0:0]
+ -A INPUT -m state --state NEW,ESTABLISHED -j ACCEPT
+ COMMIT
+
+- name: "Check restoring partial state"
+ iptables_state:
+ path: "{{ iptables_tests }}"
+ state: restored
+ check_mode: true
+ register: iptables_state
+
+
+- name: "assert that no changes are detected in check mode"
+ assert:
+ that:
+ - iptables_state is not changed
+
+- name: "Restore partial state"
+ iptables_state:
+ path: "{{ iptables_tests }}"
+ state: restored
+ register: iptables_state
+ async: "{{ ansible_timeout }}"
+ poll: 0
+
+- name: "assert that no changes are made"
+ assert:
+ that:
+ - iptables_state is not changed \ No newline at end of file
diff --git a/ansible_collections/community/general/tests/integration/targets/iso_create/aliases b/ansible_collections/community/general/tests/integration/targets/iso_create/aliases
index 4fb0bec81..73bf1b2d1 100644
--- a/ansible_collections/community/general/tests/integration/targets/iso_create/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/iso_create/aliases
@@ -5,4 +5,3 @@
azp/posix/1
destructive
skip/aix
-skip/python2.6
diff --git a/ansible_collections/community/general/tests/integration/targets/iso_customize/aliases b/ansible_collections/community/general/tests/integration/targets/iso_customize/aliases
index 54a0f1a04..394289c08 100644
--- a/ansible_collections/community/general/tests/integration/targets/iso_customize/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/iso_customize/aliases
@@ -8,6 +8,5 @@ destructive
skip/aix
skip/freebsd
skip/alpine
-skip/python2.6
skip/docker
needs/root
diff --git a/ansible_collections/community/general/tests/integration/targets/iso_customize/tasks/iso_customize_exception.yml b/ansible_collections/community/general/tests/integration/targets/iso_customize/tasks/iso_customize_exception.yml
index b2130bb6b..715f2fd38 100644
--- a/ansible_collections/community/general/tests/integration/targets/iso_customize/tasks/iso_customize_exception.yml
+++ b/ansible_collections/community/general/tests/integration/targets/iso_customize/tasks/iso_customize_exception.yml
@@ -59,7 +59,7 @@
failed_when: customized_result.msg.find("does not exist") == -1
# Test: filenames with whitespaces
-# We report error: the user should be reponsible for the it
+# We report error: the user should be responsible for the it
- name: "Testcase: filenames with whitespaces"
community.general.iso_customize:
src_iso: "{{ test_dir }}/test.iso"
diff --git a/ansible_collections/community/general/tests/integration/targets/iso_extract/aliases b/ansible_collections/community/general/tests/integration/targets/iso_extract/aliases
index 33041456a..5ddca1ecb 100644
--- a/ansible_collections/community/general/tests/integration/targets/iso_extract/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/iso_extract/aliases
@@ -9,5 +9,9 @@ skip/aix
skip/osx # FIXME
skip/rhel9.0 # FIXME
skip/rhel9.1 # FIXME
+skip/rhel9.2 # FIXME
+skip/rhel9.3 # FIXME
skip/freebsd12.4 # FIXME
skip/freebsd13.2 # FIXME
+skip/freebsd13.3 # FIXME
+skip/freebsd14.0 # FIXME
diff --git a/ansible_collections/community/general/tests/integration/targets/java_cert/aliases b/ansible_collections/community/general/tests/integration/targets/java_cert/aliases
index 573cb189b..0d8271ff7 100644
--- a/ansible_collections/community/general/tests/integration/targets/java_cert/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/java_cert/aliases
@@ -9,3 +9,4 @@ skip/osx
skip/macos
skip/freebsd
needs/root
+skip/rhel # FIXME: keytool seems to be broken on newer RHELs
diff --git a/ansible_collections/community/general/tests/integration/targets/java_cert/files/setupSSLServer.py b/ansible_collections/community/general/tests/integration/targets/java_cert/files/setupSSLServer.py
index 4b0a42185..b5a333b47 100644
--- a/ansible_collections/community/general/tests/integration/targets/java_cert/files/setupSSLServer.py
+++ b/ansible_collections/community/general/tests/integration/targets/java_cert/files/setupSSLServer.py
@@ -18,7 +18,14 @@ except ModuleNotFoundError:
from http.server import HTTPServer, SimpleHTTPRequestHandler
httpd = HTTPServer(('localhost', port), SimpleHTTPRequestHandler)
-httpd.socket = ssl.wrap_socket(httpd.socket, server_side=True,
- certfile=os.path.join(root_dir, 'cert.pem'),
- keyfile=os.path.join(root_dir, 'key.pem'))
+try:
+ httpd.socket = ssl.wrap_socket(httpd.socket, server_side=True,
+ certfile=os.path.join(root_dir, 'cert.pem'),
+ keyfile=os.path.join(root_dir, 'key.pem'))
+except AttributeError:
+ # Python 3.12 or newer:
+ context = ssl.create_default_context(purpose=ssl.Purpose.CLIENT_AUTH)
+ context.load_cert_chain(certfile=os.path.join(root_dir, 'cert.pem'),
+ keyfile=os.path.join(root_dir, 'key.pem'))
+ httpd.socket = context.wrap_socket(httpd.socket)
httpd.handle_request()
diff --git a/ansible_collections/community/general/tests/integration/targets/java_cert/tasks/state_change.yml b/ansible_collections/community/general/tests/integration/targets/java_cert/tasks/state_change.yml
index e135a60a3..f2898ddc2 100644
--- a/ansible_collections/community/general/tests/integration/targets/java_cert/tasks/state_change.yml
+++ b/ansible_collections/community/general/tests/integration/targets/java_cert/tasks/state_change.yml
@@ -181,7 +181,7 @@
- result_x509_changed is changed
- name: |
- We also want to make sure that the status doesnt change if we import the same cert
+ We also want to make sure that the status does not change if we import the same cert
community.general.java_cert:
cert_alias: test_cert
cert_path: "{{ test_cert2_path }}"
diff --git a/ansible_collections/community/general/tests/integration/targets/java_keystore/aliases b/ansible_collections/community/general/tests/integration/targets/java_keystore/aliases
index 573cb189b..0d8271ff7 100644
--- a/ansible_collections/community/general/tests/integration/targets/java_keystore/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/java_keystore/aliases
@@ -9,3 +9,4 @@ skip/osx
skip/macos
skip/freebsd
needs/root
+skip/rhel # FIXME: keytool seems to be broken on newer RHELs
diff --git a/ansible_collections/community/general/tests/integration/targets/kernel_blacklist/aliases b/ansible_collections/community/general/tests/integration/targets/kernel_blacklist/aliases
index afda346c4..b85ae6419 100644
--- a/ansible_collections/community/general/tests/integration/targets/kernel_blacklist/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/kernel_blacklist/aliases
@@ -3,3 +3,7 @@
# SPDX-License-Identifier: GPL-3.0-or-later
azp/posix/1
+skip/aix
+skip/freebsd
+skip/osx
+skip/macos
diff --git a/ansible_collections/community/general/tests/integration/targets/kernel_blacklist/handlers/main.yml b/ansible_collections/community/general/tests/integration/targets/kernel_blacklist/handlers/main.yml
new file mode 100644
index 000000000..814c9c51a
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/kernel_blacklist/handlers/main.yml
@@ -0,0 +1,10 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Remove modprobe.d
+ ansible.builtin.file:
+ path: /etc/modprobe.d
+ state: absent
+ \ No newline at end of file
diff --git a/ansible_collections/community/general/tests/integration/targets/kernel_blacklist/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/kernel_blacklist/tasks/main.yml
index e169d5479..48cd38a93 100644
--- a/ansible_collections/community/general/tests/integration/targets/kernel_blacklist/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/kernel_blacklist/tasks/main.yml
@@ -36,25 +36,37 @@
path: '{{ bl_file }}'
register: stat_test_1
+- name: show bl_test_1
+ ansible.builtin.debug:
+ var: bl_test_1_depr_msgs
+ vars:
+ bl_test_1_depr_msgs: "{{ (bl_test_1.deprecations | default([])) | map(attribute='msg') }}"
+ # q('ansible.builtin.subelements', bl_test_1, 'deprecations', {'skip_missing': True}) }}"
+
- name: assert file is unchanged
assert:
that:
- - bl_test_1 is not changed
- - bl_test_1a is not changed
- - orig_stat.stat.size == stat_test_1.stat.size
- - orig_stat.stat.checksum == stat_test_1.stat.checksum
- - orig_stat.stat.mtime == stat_test_1.stat.mtime
- - stat_test_1.stat.checksum == expected_content | checksum
+ - bl_test_1 is not changed
+ - bl_test_1a is not changed
+ - orig_stat.stat.size == stat_test_1.stat.size
+ - orig_stat.stat.checksum == stat_test_1.stat.checksum
+ - orig_stat.stat.mtime == stat_test_1.stat.mtime
+ - stat_test_1.stat.checksum == expected_content | checksum
vars:
expected_content: |
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
- # SPDX-{{ '' }}License-Identifier: GPL-3.0-or-later
+ # SPDX{{ '' }}-License-Identifier: GPL-3.0-or-later
blacklist aaaa
blacklist bbbb
blacklist cccc
+- name: test deprecation
+ assert:
+ that:
+ - "'deprecations' not in bl_test_1 or (ansible_version.major == 2 and ansible_version.minor == 12)"
+
- name: add new item to list
community.general.kernel_blacklist:
blacklist_file: '{{ bl_file }}'
@@ -70,13 +82,13 @@
- name: assert element is added
assert:
that:
- - bl_test_2 is changed
- - slurp_test_2.content|b64decode == content
+ - bl_test_2 is changed
+ - slurp_test_2.content|b64decode == content
vars:
content: |
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
- # SPDX-{{ '' }}License-Identifier: GPL-3.0-or-later
+ # SPDX{{ '' }}-License-Identifier: GPL-3.0-or-later
blacklist aaaa
blacklist bbbb
@@ -95,17 +107,49 @@
src: '{{ bl_file }}'
register: slurp_test_3
-- name: assert element is added
+- name: assert element is removed
assert:
that:
- - bl_test_3 is changed
- - slurp_test_3.content|b64decode == content
+ - bl_test_3 is changed
+ - slurp_test_3.content|b64decode == content
vars:
content: |
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
- # SPDX-{{ '' }}License-Identifier: GPL-3.0-or-later
+ # SPDX{{ '' }}-License-Identifier: GPL-3.0-or-later
blacklist aaaa
blacklist cccc
blacklist dddd
+
+############################################################################################################################################
+#
+# Issue 7362
+#
+
+- name: Create /etc/modprobe.d
+ ansible.builtin.file:
+ path: /etc/modprobe.d
+ state: directory
+ mode: '0755'
+ owner: root
+ group: root
+ notify: Remove modprobe.d
+
+- name: Create cls_rsvp file
+ ansible.builtin.copy:
+ dest: /etc/modprobe.d/cls_rsvp-blacklist.conf
+ content: |
+ blacklist cls_rsvp
+ mode: '0644'
+
+- name: Block potentially affected (and unused) modules (7362)
+ community.general.kernel_blacklist:
+ name: "{{ line_item }}"
+ state: present
+ blacklist_file: "/etc/modprobe.d/{{ line_item }}-blacklist.conf"
+ with_items:
+ - cifs
+ - cls_rsvp
+ loop_control:
+ loop_var: line_item
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_authz_authorization_scope/readme.adoc b/ansible_collections/community/general/tests/integration/targets/keycloak_authz_authorization_scope/readme.adoc
index 1941e54ef..8e052920c 100644
--- a/ansible_collections/community/general/tests/integration/targets/keycloak_authz_authorization_scope/readme.adoc
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_authz_authorization_scope/readme.adoc
@@ -20,7 +20,7 @@ docker run --name mykeycloak -p 8080:8080 -e KC_HTTP_RELATIVE_PATH=/auth -e KEYC
This test suite can run against a fresh unconfigured server instance
(no preconfiguration required) and cleans up after itself (undoes all
-its config changes) as long as it runs through completly. While its active
+its config changes) as long as it runs through completely. While its active
it changes the server configuration in the following ways:
* creating, modifying and deleting some keycloak groups
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/aliases b/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/aliases
new file mode 100644
index 000000000..bd1f02444
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/aliases
@@ -0,0 +1,5 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+unsupported
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/policy/Containerfile b/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/policy/Containerfile
new file mode 100644
index 000000000..3303066da
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/policy/Containerfile
@@ -0,0 +1,4 @@
+FROM quay.io/keycloak/keycloak:20.0.2
+
+COPY policy.jar /opt/keycloak/providers/
+RUN /opt/keycloak/bin/kc.sh build
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/policy/Containerfile.license b/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/policy/Containerfile.license
new file mode 100644
index 000000000..a1390a69e
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/policy/Containerfile.license
@@ -0,0 +1,3 @@
+Copyright (c) Ansible Project
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/policy/META-INF/keycloak-scripts.json b/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/policy/META-INF/keycloak-scripts.json
new file mode 100644
index 000000000..9370c16cb
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/policy/META-INF/keycloak-scripts.json
@@ -0,0 +1,14 @@
+{
+ "policies": [
+ {
+ "name": "MyPolicy1",
+ "fileName": "policy-1.js",
+ "description": "My Policy 1"
+ },
+ {
+ "name": "MyPolicy2",
+ "fileName": "policy-2.js",
+ "description": "My Policy 2"
+ }
+ ]
+}
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/policy/META-INF/keycloak-scripts.json.license b/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/policy/META-INF/keycloak-scripts.json.license
new file mode 100644
index 000000000..a1390a69e
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/policy/META-INF/keycloak-scripts.json.license
@@ -0,0 +1,3 @@
+Copyright (c) Ansible Project
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/policy/build-policy.sh b/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/policy/build-policy.sh
new file mode 100755
index 000000000..eeca22f7e
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/policy/build-policy.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+zip -r policy.jar META-INF/keycloak-scripts.json policy-1.js policy-2.js
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/policy/build-policy.sh.license b/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/policy/build-policy.sh.license
new file mode 100644
index 000000000..a1390a69e
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/policy/build-policy.sh.license
@@ -0,0 +1,3 @@
+Copyright (c) Ansible Project
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/policy/policy-1.js b/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/policy/policy-1.js
new file mode 100644
index 000000000..fa42b0719
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/policy/policy-1.js
@@ -0,0 +1 @@
+$evaluation.grant();
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/policy/policy-1.js.license b/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/policy/policy-1.js.license
new file mode 100644
index 000000000..a1390a69e
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/policy/policy-1.js.license
@@ -0,0 +1,3 @@
+Copyright (c) Ansible Project
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/policy/policy-2.js b/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/policy/policy-2.js
new file mode 100644
index 000000000..fa42b0719
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/policy/policy-2.js
@@ -0,0 +1 @@
+$evaluation.grant();
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/policy/policy-2.js.license b/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/policy/policy-2.js.license
new file mode 100644
index 000000000..a1390a69e
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/policy/policy-2.js.license
@@ -0,0 +1,3 @@
+Copyright (c) Ansible Project
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/readme.adoc b/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/readme.adoc
new file mode 100644
index 000000000..cc014158f
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/readme.adoc
@@ -0,0 +1,27 @@
+// Copyright (c) Ansible Project
+// GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+To be able to run these integration tests a keycloak server must be
+reachable under a specific url with a specific admin user and password.
+The exact values expected for these parameters can be found in
+'vars/main.yml' file. A vanilla Keycloak server will not be sufficient:
+you will need to deploy a custom JAR file with two policies:
+
+* _MyPolicy1:_ policy-1.js
+* _MyPolicy2:_ policy-2.js
+
+To create a customized Keycloak test instance running on Podman first
+install the "zip" command, go to the policy subdirectory and then do
+
+[source,shell]
+----
+./build-policy.sh
+podman build --tag keycloak_authz_custom_policy_test:1.0.0 .
+podman rm mykeycloak && podman run --name mykeycloak -p 8080:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=password -e KC_HTTP_RELATIVE_PATH=/auth localhost/keycloak_authz_custom_policy_test:1.0.0 start-dev
+----
+
+This process probably also work with Docker just by replacing _podman_ with
+_docker_. Modify the FROM argument in Containerfile to change Keycloak version
+to test against. Quarkus versions of Keycloak should work - older versions
+will not.
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/tasks/main.yml
new file mode 100644
index 000000000..b22d75121
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/tasks/main.yml
@@ -0,0 +1,168 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+- name: Remove keycloak client to avoid failures from previous failed runs
+ community.general.keycloak_client:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ realm: "{{ realm }}"
+ client_id: "{{ client_id }}"
+ state: absent
+
+- name: Create keycloak client with authorization services enabled
+ community.general.keycloak_client:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ realm: "{{ realm }}"
+ client_id: "{{ client_id }}"
+ state: present
+ enabled: true
+ public_client: false
+ service_accounts_enabled: true
+ authorization_services_enabled: true
+
+- name: Create first custom policy (check_mode)
+ community.general.keycloak_authz_custom_policy:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ name: FirstCustomPolicy
+ state: present
+ policy_type: script-policy-1.js
+ realm: "{{ realm }}"
+ client_id: "{{ client_id }}"
+ check_mode: true
+ register: result
+
+- name: Assert that first custom policy was not created
+ assert:
+ that:
+ - result is changed
+ - result.end_state != {}
+ - result.end_state.name == "FirstCustomPolicy"
+ - result.end_state.type == "script-policy-1.js"
+ - result.msg == 'Would create custom policy FirstCustomPolicy'
+
+- name: Create first custom policy
+ community.general.keycloak_authz_custom_policy:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ name: FirstCustomPolicy
+ state: present
+ policy_type: script-policy-1.js
+ realm: "{{ realm }}"
+ client_id: "{{ client_id }}"
+ register: result
+
+- name: Assert that first custom policy was created
+ assert:
+ that:
+ - result is changed
+ - result.end_state != {}
+ - result.end_state.name == "FirstCustomPolicy"
+ - result.end_state.type == "script-policy-1.js"
+ - result.msg == 'Custom policy FirstCustomPolicy created'
+
+- name: Attempt to update first custom policy (not possible)
+ community.general.keycloak_authz_custom_policy:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ name: FirstCustomPolicy
+ state: present
+ policy_type: script-policy-2.js
+ realm: "{{ realm }}"
+ client_id: "{{ client_id }}"
+ register: result
+
+- name: Assert that first custom policy was not modified
+ assert:
+ that:
+ - result is not changed
+ - result.end_state != {}
+ - result.end_state.name == "FirstCustomPolicy"
+ - result.end_state.type == "script-policy-2.js"
+ - result.msg == 'Custom policy FirstCustomPolicy already exists'
+
+# Ensure that we can create multiple instances of the custom policy
+- name: Create second instance of the custom policy
+ community.general.keycloak_authz_custom_policy:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ name: SecondCustomPolicy
+ state: present
+ policy_type: script-policy-1.js
+ realm: "{{ realm }}"
+ client_id: "{{ client_id }}"
+ register: result
+
+- name: Assert that second instance of the custom policy was created
+ assert:
+ that:
+ - result is changed
+ - result.end_state != {}
+ - result.end_state.name == "SecondCustomPolicy"
+ - result.end_state.type == "script-policy-1.js"
+ - result.msg == 'Custom policy SecondCustomPolicy created'
+
+- name: Remove second instance of the custom policy (check_mode)
+ community.general.keycloak_authz_custom_policy:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ name: SecondCustomPolicy
+ state: absent
+ policy_type: script-policy-1.js
+ realm: "{{ realm }}"
+ client_id: "{{ client_id }}"
+ check_mode: true
+ register: result
+
+- name: Assert that second custom policy was not removed
+ assert:
+ that:
+ - result is changed
+ - result.end_state == {}
+ - result.msg == 'Would remove custom policy SecondCustomPolicy'
+
+- name: Remove second instance of the custom policy
+ community.general.keycloak_authz_custom_policy:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ name: SecondCustomPolicy
+ state: absent
+ policy_type: script-policy-1.js
+ realm: "{{ realm }}"
+ client_id: "{{ client_id }}"
+ register: result
+
+- name: Assert that second custom policy was removed
+ assert:
+ that:
+ - result is changed
+ - result.end_state == {}
+ - result.msg == 'Custom policy SecondCustomPolicy removed'
+
+- name: Remove keycloak client
+ community.general.keycloak_client:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ realm: "{{ realm }}"
+ client_id: "{{ client_id }}"
+ state: absent
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/vars/main.yml b/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/vars/main.yml
new file mode 100644
index 000000000..c1d5fc983
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_authz_custom_policy/vars/main.yml
@@ -0,0 +1,11 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+url: http://localhost:8080/auth
+admin_realm: master
+admin_user: admin
+admin_password: password
+realm: master
+client_id: authz
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_authz_permission/aliases b/ansible_collections/community/general/tests/integration/targets/keycloak_authz_permission/aliases
new file mode 100644
index 000000000..e1f8d6b4b
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_authz_permission/aliases
@@ -0,0 +1,6 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+unsupported
+keycloak_authz_permission_info
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_authz_permission/readme.adoc b/ansible_collections/community/general/tests/integration/targets/keycloak_authz_permission/readme.adoc
new file mode 100644
index 000000000..8e052920c
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_authz_permission/readme.adoc
@@ -0,0 +1,27 @@
+// Copyright (c) Ansible Project
+// GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+To be able to run these integration tests a keycloak server must be
+reachable under a specific url with a specific admin user and password.
+The exact values expected for these parameters can be found in
+'vars/main.yml' file. A simple way to do this is to use the official
+keycloak docker images like this:
+
+----
+docker run --name mykeycloak -p 8080:8080 -e KC_HTTP_RELATIVE_PATH=<url-path> -e KEYCLOAK_ADMIN=<admin_user> -e KEYCLOAK_ADMIN_PASSWORD=<admin_password> quay.io/keycloak/keycloak:20.0.2 start-dev
+----
+
+Example with concrete values inserted:
+
+----
+docker run --name mykeycloak -p 8080:8080 -e KC_HTTP_RELATIVE_PATH=/auth -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=password quay.io/keycloak/keycloak:20.0.2 start-dev
+----
+
+This test suite can run against a fresh unconfigured server instance
+(no preconfiguration required) and cleans up after itself (undoes all
+its config changes) as long as it runs through completely. While its active
+it changes the server configuration in the following ways:
+
+ * creating, modifying and deleting some keycloak groups
+
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_authz_permission/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/keycloak_authz_permission/tasks/main.yml
new file mode 100644
index 000000000..16cb6806f
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_authz_permission/tasks/main.yml
@@ -0,0 +1,567 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+- name: Remove keycloak client to avoid failures from previous failed runs
+ community.general.keycloak_client:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ realm: "{{ realm }}"
+ client_id: "{{ client_id }}"
+ state: absent
+
+- name: Create keycloak client with authorization services enabled
+ community.general.keycloak_client:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ realm: "{{ realm }}"
+ client_id: "{{ client_id }}"
+ state: present
+ enabled: true
+ public_client: false
+ service_accounts_enabled: true
+ authorization_services_enabled: true
+
+- name: Create file:create authorization scope
+ community.general.keycloak_authz_authorization_scope:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ state: present
+ name: "file:create"
+ display_name: "File create"
+ icon_uri: "http://localhost/icon.png"
+ client_id: "{{ client_id }}"
+ realm: "{{ realm }}"
+ register: result
+
+- name: Create file:delete authorization scope
+ community.general.keycloak_authz_authorization_scope:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ state: present
+ name: "file:delete"
+ display_name: "File delete"
+ icon_uri: "http://localhost/icon.png"
+ client_id: "{{ client_id }}"
+ realm: "{{ realm }}"
+ register: result
+
+- name: Create permission without type (test for failure)
+ community.general.keycloak_authz_permission:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ state: present
+ name: "ScopePermission"
+ description: "Scope permission"
+ client_id: "{{ client_id }}"
+ realm: "{{ realm }}"
+ register: result
+ failed_when: result.msg.find('missing required arguments') == -1
+
+- name: Create scope permission without scopes (test for failure)
+ community.general.keycloak_authz_permission:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ state: present
+ name: "ScopePermission"
+ description: "Scope permission"
+ permission_type: scope
+ client_id: "{{ client_id }}"
+ realm: "{{ realm }}"
+ register: result
+ failed_when: result.msg.find('Scopes need to defined when permission type is set to scope!') == -1
+
+- name: Create scope permission with multiple resources (test for failure)
+ community.general.keycloak_authz_permission:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ state: present
+ name: "ScopePermission"
+ description: "Scope permission"
+ resources:
+ - "Default Resource"
+ - "Other Resource"
+ permission_type: scope
+ scopes:
+ - "file:delete"
+ client_id: "{{ client_id }}"
+ realm: "{{ realm }}"
+ register: result
+ failed_when: result.msg.find('Only one resource can be defined for a scope permission!') == -1
+
+- name: Create scope permission with invalid policy name (test for failure)
+ community.general.keycloak_authz_permission:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ state: present
+ name: "ScopePermission"
+ description: "Scope permission"
+ permission_type: scope
+ scopes:
+ - "file:delete"
+ policies:
+ - "Missing Policy"
+ client_id: "{{ client_id }}"
+ realm: "{{ realm }}"
+ register: result
+ failed_when: result.msg.find('Unable to find authorization policy with name') == -1
+
+- name: Create scope permission
+ community.general.keycloak_authz_permission:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ state: present
+ name: "ScopePermission"
+ description: "Scope permission"
+ permission_type: scope
+ scopes:
+ - "file:delete"
+ policies:
+ - "Default Policy"
+ client_id: "{{ client_id }}"
+ realm: "{{ realm }}"
+ register: result
+
+- name: Assert that scope permission was created
+ assert:
+ that:
+ - result is changed
+ - result.end_state != {}
+ - result.end_state.name == "ScopePermission"
+ - result.end_state.description == "Scope permission"
+ - result.end_state.type == "scope"
+ - result.end_state.resources == []
+ - result.end_state.policies|length == 1
+ - result.end_state.scopes|length == 1
+
+- name: Query state
+ community.general.keycloak_authz_permission_info:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ name: "ScopePermission"
+ client_id: "{{ client_id }}"
+ realm: "{{ realm }}"
+ register: result
+
+- name: Assert that queried state matches desired end state
+ assert:
+ that:
+ - result.queried_state.name == "ScopePermission"
+ - result.queried_state.description == "Scope permission"
+
+- name: Create scope permission (test for idempotency)
+ community.general.keycloak_authz_permission:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ state: present
+ name: "ScopePermission"
+ description: "Scope permission"
+ permission_type: scope
+ scopes:
+ - "file:delete"
+ policies:
+ - "Default Policy"
+ client_id: "{{ client_id }}"
+ realm: "{{ realm }}"
+ register: result
+
+- name: Assert that nothing changed
+ assert:
+ that:
+ - result.end_state != {}
+ - result.end_state.name == "ScopePermission"
+ - result.end_state.description == "Scope permission"
+ - result.end_state.type == "scope"
+ - result.end_state.resources == []
+ - result.end_state.policies|length == 1
+ - result.end_state.scopes|length == 1
+
+- name: Query state
+ community.general.keycloak_authz_permission_info:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ name: "ScopePermission"
+ client_id: "{{ client_id }}"
+ realm: "{{ realm }}"
+ register: result
+
+- name: Assert that queried state matches desired end state
+ assert:
+ that:
+ - result.queried_state.name == "ScopePermission"
+ - result.queried_state.description == "Scope permission"
+
+- name: Update scope permission
+ community.general.keycloak_authz_permission:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ state: present
+ name: "ScopePermission"
+ description: "Scope permission changed"
+ permission_type: scope
+ decision_strategy: 'AFFIRMATIVE'
+ scopes:
+ - "file:create"
+ - "file:delete"
+ policies: []
+ client_id: "{{ client_id }}"
+ realm: "{{ realm }}"
+ register: result
+
+- name: Assert that scope permission was updated correctly
+ assert:
+ that:
+ - result.changed == True
+ - result.end_state != {}
+ - result.end_state.scopes|length == 2
+ - result.end_state.policies == []
+ - result.end_state.resources == []
+ - result.end_state.name == "ScopePermission"
+ - result.end_state.description == "Scope permission changed"
+
+- name: Query state
+ community.general.keycloak_authz_permission_info:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ name: "ScopePermission"
+ client_id: "{{ client_id }}"
+ realm: "{{ realm }}"
+ register: result
+
+- name: Assert that queried state matches desired end state
+ assert:
+ that:
+ - result.queried_state.name == "ScopePermission"
+ - result.queried_state.description == "Scope permission changed"
+
+- name: Update scope permission (test for idempotency)
+ community.general.keycloak_authz_permission:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ state: present
+ name: "ScopePermission"
+ description: "Scope permission changed"
+ permission_type: scope
+ decision_strategy: 'AFFIRMATIVE'
+ scopes:
+ - "file:create"
+ - "file:delete"
+ policies: []
+ client_id: "{{ client_id }}"
+ realm: "{{ realm }}"
+ register: result
+
+- name: Assert that nothing changed
+ assert:
+ that:
+ - result.changed == True
+ - result.end_state != {}
+ - result.end_state.scopes|length == 2
+ - result.end_state.policies == []
+ - result.end_state.resources == []
+ - result.end_state.name == "ScopePermission"
+ - result.end_state.description == "Scope permission changed"
+
+- name: Query state
+ community.general.keycloak_authz_permission_info:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ name: "ScopePermission"
+ client_id: "{{ client_id }}"
+ realm: "{{ realm }}"
+ register: result
+
+- name: Assert that queried state matches desired end state
+ assert:
+ that:
+ - result.queried_state.name == "ScopePermission"
+ - result.queried_state.description == "Scope permission changed"
+
+- name: Remove scope permission
+ community.general.keycloak_authz_permission:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ state: absent
+ name: "ScopePermission"
+ permission_type: scope
+ client_id: "{{ client_id }}"
+ realm: "{{ realm }}"
+ register: result
+
+- name: Assert that scope permission was removed
+ assert:
+ that:
+ - result is changed
+ - result.end_state == {}
+
+- name: Remove scope permission (test for idempotency)
+ community.general.keycloak_authz_permission:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ state: absent
+ name: "ScopePermission"
+ permission_type: scope
+ client_id: "{{ client_id }}"
+ realm: "{{ realm }}"
+ register: result
+
+- name: Assert that nothing has changed
+ assert:
+ that:
+ - result is not changed
+ - result.end_state == {}
+
+- name: Create resource permission without resources (test for failure)
+ community.general.keycloak_authz_permission:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ state: present
+ name: "ResourcePermission"
+ description: "Resource permission"
+ permission_type: resource
+ policies:
+ - "Default Policy"
+ client_id: "{{ client_id }}"
+ realm: "{{ realm }}"
+ register: result
+ failed_when: result.msg.find('A resource need to defined when permission type is set to resource!') == -1
+
+- name: Create resource permission with scopes (test for failure)
+ community.general.keycloak_authz_permission:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ state: present
+ name: "ResourcePermission"
+ description: "Resource permission"
+ permission_type: resource
+ resources:
+ - "Default Resource"
+ policies:
+ - "Default Policy"
+ scopes:
+ - "file:delete"
+ client_id: "{{ client_id }}"
+ realm: "{{ realm }}"
+ register: result
+ failed_when: result.msg.find('Scopes cannot be defined when permission type is set to resource!') == -1
+
+- name: Create resource permission
+ community.general.keycloak_authz_permission:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ state: present
+ name: "ResourcePermission"
+ description: "Resource permission"
+ resources:
+ - "Default Resource"
+ permission_type: resource
+ policies:
+ - "Default Policy"
+ client_id: "{{ client_id }}"
+ realm: "{{ realm }}"
+ register: result
+
+- name: Assert that resource permission was created
+ assert:
+ that:
+ - result is changed
+ - result.end_state != {}
+ - result.end_state.policies|length == 1
+ - result.end_state.resources|length == 1
+ - result.end_state.name == "ResourcePermission"
+ - result.end_state.description == "Resource permission"
+
+- name: Query state
+ community.general.keycloak_authz_permission_info:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ name: "ResourcePermission"
+ client_id: "{{ client_id }}"
+ realm: "{{ realm }}"
+ register: result
+
+- name: Assert that queried state matches desired end state
+ assert:
+ that:
+ - result.queried_state.name == "ResourcePermission"
+ - result.queried_state.description == "Resource permission"
+
+- name: Create resource permission (test for idempotency)
+ community.general.keycloak_authz_permission:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ state: present
+ name: "ResourcePermission"
+ description: "Resource permission"
+ resources:
+ - "Default Resource"
+ permission_type: resource
+ policies:
+ - "Default Policy"
+ client_id: "{{ client_id }}"
+ realm: "{{ realm }}"
+ register: result
+
+- name: Assert that nothing has changed
+ assert:
+ that:
+ - result.end_state != {}
+ - result.end_state.policies|length == 1
+ - result.end_state.resources|length == 1
+ - result.end_state.name == "ResourcePermission"
+ - result.end_state.description == "Resource permission"
+
+- name: Query state
+ community.general.keycloak_authz_permission_info:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ name: "ResourcePermission"
+ client_id: "{{ client_id }}"
+ realm: "{{ realm }}"
+ register: result
+
+- name: Assert that queried state matches desired end state
+ assert:
+ that:
+ - result.queried_state.name == "ResourcePermission"
+ - result.queried_state.description == "Resource permission"
+
+- name: Update resource permission
+ community.general.keycloak_authz_permission:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ state: present
+ name: "ResourcePermission"
+ description: "Resource permission changed"
+ resources:
+ - "Default Resource"
+ permission_type: resource
+ policies: []
+ client_id: "{{ client_id }}"
+ realm: "{{ realm }}"
+ register: result
+
+- name: Assert that resource permission was updated correctly
+ assert:
+ that:
+ - result.changed == True
+ - result.end_state != {}
+ - result.end_state.policies == []
+ - result.end_state.resources|length == 1
+ - result.end_state.name == "ResourcePermission"
+ - result.end_state.description == "Resource permission changed"
+
+- name: Query state
+ community.general.keycloak_authz_permission_info:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ name: "ResourcePermission"
+ client_id: "{{ client_id }}"
+ realm: "{{ realm }}"
+ register: result
+
+- name: Assert that queried state matches desired end state
+ assert:
+ that:
+ - result.queried_state.name == "ResourcePermission"
+ - result.queried_state.description == "Resource permission changed"
+
+- name: Remove resource permission
+ community.general.keycloak_authz_permission:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ state: absent
+ name: "ResourcePermission"
+ permission_type: resource
+ client_id: "{{ client_id }}"
+ realm: "{{ realm }}"
+ register: result
+
+- name: Assert that resource permission was removed
+ assert:
+ that:
+ - result is changed
+ - result.end_state == {}
+
+- name: Remove resource permission (test for idempotency)
+ community.general.keycloak_authz_permission:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ state: absent
+ name: "ResourcePermission"
+ permission_type: resource
+ client_id: "{{ client_id }}"
+ realm: "{{ realm }}"
+ register: result
+
+- name: Assert that nothing has changed
+ assert:
+ that:
+ - result is not changed
+ - result.end_state == {}
+
+- name: Remove keycloak client
+ community.general.keycloak_client:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ realm: "{{ realm }}"
+ client_id: "{{ client_id }}"
+ state: absent
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_authz_permission/vars/main.yml b/ansible_collections/community/general/tests/integration/targets/keycloak_authz_permission/vars/main.yml
new file mode 100644
index 000000000..c1d5fc983
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_authz_permission/vars/main.yml
@@ -0,0 +1,11 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+url: http://localhost:8080/auth
+admin_realm: master
+admin_user: admin
+admin_password: password
+realm: master
+client_id: authz
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_client/README.md b/ansible_collections/community/general/tests/integration/targets/keycloak_client/README.md
index d8bcc08ec..f2b1012aa 100644
--- a/ansible_collections/community/general/tests/integration/targets/keycloak_client/README.md
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_client/README.md
@@ -4,14 +4,16 @@ GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://w
SPDX-License-Identifier: GPL-3.0-or-later
-->
-The integration test can be performed as follows:
+# Running keycloak_client module integration test
-```
-# 1. Start docker-compose:
-docker-compose -f tests/integration/targets/keycloak_client/docker-compose.yml stop
-docker-compose -f tests/integration/targets/keycloak_client/docker-compose.yml rm -f -v
-docker-compose -f tests/integration/targets/keycloak_client/docker-compose.yml up -d
+To run Keycloak client module's integration test, start a keycloak server using Docker:
-# 2. Run the integration tests:
-ansible-test integration keycloak_client --allow-unsupported -v
-```
+ docker run -d --rm --name mykeycloak -p 8080:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=password quay.io/keycloak/keycloak:latest start-dev --http-relative-path /auth
+
+Run the integration tests:
+
+ ansible-test integration -v keycloak_client --allow-unsupported --docker fedora35 --docker-network host
+
+Cleanup:
+
+ docker stop mykeycloak
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_client/docker-compose.yml b/ansible_collections/community/general/tests/integration/targets/keycloak_client/docker-compose.yml
deleted file mode 100644
index 5e14e9aac..000000000
--- a/ansible_collections/community/general/tests/integration/targets/keycloak_client/docker-compose.yml
+++ /dev/null
@@ -1,31 +0,0 @@
----
-# Copyright (c) Ansible Project
-# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
-# SPDX-License-Identifier: GPL-3.0-or-later
-
-version: '3.4'
-
-services:
- postgres:
- image: postgres:9.6
- restart: always
- environment:
- POSTGRES_USER: postgres
- POSTGRES_DB: postgres
- POSTGRES_PASSWORD: postgres
-
- keycloak:
- image: jboss/keycloak:12.0.4
- ports:
- - 8080:8080
-
- environment:
- DB_VENDOR: postgres
- DB_ADDR: postgres
- DB_DATABASE: postgres
- DB_USER: postgres
- DB_SCHEMA: public
- DB_PASSWORD: postgres
-
- KEYCLOAK_USER: admin
- KEYCLOAK_PASSWORD: password
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_client/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/keycloak_client/tasks/main.yml
index 513d5836b..5e7c7fae3 100644
--- a/ansible_collections/community/general/tests/integration/targets/keycloak_client/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_client/tasks/main.yml
@@ -2,58 +2,78 @@
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
+- name: Wait for Keycloak
+ uri:
+ url: "{{ url }}/admin/"
+ status_code: 200
+ validate_certs: no
+ register: result
+ until: result.status == 200
+ retries: 10
+ delay: 10
- name: Delete realm
- community.general.keycloak_realm: "{{ auth_args | combine(call_args) }}"
- vars:
- call_args:
- id: "{{ realm }}"
- realm: "{{ realm }}"
- state: absent
+ community.general.keycloak_realm:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ id: "{{ realm }}"
+ realm: "{{ realm }}"
+ state: absent
- name: Create realm
- community.general.keycloak_realm: "{{ auth_args | combine(call_args) }}"
- vars:
- call_args:
- id: "{{ realm }}"
- realm: "{{ realm }}"
- state: present
+ community.general.keycloak_realm:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ id: "{{ realm }}"
+ realm: "{{ realm }}"
+ state: present
- name: Desire client
- community.general.keycloak_client: "{{ auth_args | combine(call_args) }}"
- vars:
- call_args:
- realm: "{{ realm }}"
- client_id: "{{ client_id }}"
- state: present
- redirect_uris: '{{redirect_uris1}}'
- attributes: '{{client_attributes1}}'
- protocol_mappers: '{{protocol_mappers1}}'
+ community.general.keycloak_client:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ realm: "{{ realm }}"
+ client_id: "{{ client_id }}"
+ state: present
+ redirect_uris: '{{redirect_uris1}}'
+ attributes: '{{client_attributes1}}'
+ protocol_mappers: '{{protocol_mappers1}}'
register: desire_client_not_present
- name: Desire client again with same props
- community.general.keycloak_client: "{{ auth_args | combine(call_args) }}"
- vars:
- call_args:
- realm: "{{ realm }}"
- client_id: "{{ client_id }}"
- state: present
- redirect_uris: '{{redirect_uris1}}'
- attributes: '{{client_attributes1}}'
- protocol_mappers: '{{protocol_mappers1}}'
+ community.general.keycloak_client:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ realm: "{{ realm }}"
+ client_id: "{{ client_id }}"
+ state: present
+ redirect_uris: '{{redirect_uris1}}'
+ attributes: '{{client_attributes1}}'
+ protocol_mappers: '{{protocol_mappers1}}'
register: desire_client_when_present_and_same
- name: Check client again with same props
- community.general.keycloak_client: "{{ auth_args | combine(call_args) }}"
+ community.general.keycloak_client:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ realm: "{{ realm }}"
+ client_id: "{{ client_id }}"
+ state: present
+ redirect_uris: '{{redirect_uris1}}'
+ attributes: '{{client_attributes1}}'
+ protocol_mappers: '{{protocol_mappers1}}'
+ authorization_services_enabled: False
check_mode: true
- vars:
- call_args:
- realm: "{{ realm }}"
- client_id: "{{ client_id }}"
- state: present
- redirect_uris: '{{redirect_uris1}}'
- attributes: '{{client_attributes1}}'
- protocol_mappers: '{{protocol_mappers1}}'
register: check_client_when_present_and_same
- name: Assert changes not detected in last two tasks (desire when same, and check)
@@ -61,3 +81,25 @@
that:
- desire_client_when_present_and_same is not changed
- check_client_when_present_and_same is not changed
+
+- name: Check client again with changed props
+ community.general.keycloak_client:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ realm: "{{ realm }}"
+ client_id: "{{ client_id }}"
+ state: present
+ redirect_uris: '{{redirect_uris1}}'
+ attributes: '{{client_attributes1}}'
+ protocol_mappers: '{{protocol_mappers1}}'
+ authorization_services_enabled: False
+ service_accounts_enabled: True
+ check_mode: true
+ register: check_client_when_present_and_changed
+
+- name: Assert changes detected in last tasks
+ assert:
+ that:
+ - check_client_when_present_and_changed is changed
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_client/vars/main.yml b/ansible_collections/community/general/tests/integration/targets/keycloak_client/vars/main.yml
index 53ba35fca..498f93e70 100644
--- a/ansible_collections/community/general/tests/integration/targets/keycloak_client/vars/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_client/vars/main.yml
@@ -24,7 +24,7 @@ redirect_uris1:
- "http://example.b.com/"
- "http://example.a.com/"
-client_attributes1: {"backchannel.logout.session.required": true, "backchannel.logout.revoke.offline.tokens": false}
+client_attributes1: {"backchannel.logout.session.required": true, "backchannel.logout.revoke.offline.tokens": false, "client.secret.creation.time": 0}
protocol_mappers1:
- name: 'email'
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_component_info/README.md b/ansible_collections/community/general/tests/integration/targets/keycloak_component_info/README.md
new file mode 100644
index 000000000..cf4f222b0
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_component_info/README.md
@@ -0,0 +1,20 @@
+<!--
+Copyright (c) Ansible Project
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
+-->
+# Running keycloak_component_info module integration test
+
+To run Keycloak component info module's integration test, start a keycloak server using Docker:
+
+ docker run -d --rm --name myldap -p 389:389 minkwe/389ds:latest
+ docker run -d --rm --name mykeycloak --link myldap:ldap.example.com -p 8080:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=password quay.io/keycloak/keycloak:latest start-dev --http-relative-path /auth
+
+Run integration tests:
+ ansible-test integration -v keycloak_component_info --allow-unsupported --docker fedora35 --docker-network host
+
+Cleanup:
+
+ docker stop myldap mykeycloak
+
+
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_component_info/aliases b/ansible_collections/community/general/tests/integration/targets/keycloak_component_info/aliases
new file mode 100644
index 000000000..bd1f02444
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_component_info/aliases
@@ -0,0 +1,5 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+unsupported
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_component_info/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/keycloak_component_info/tasks/main.yml
new file mode 100644
index 000000000..c0ca5600f
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_component_info/tasks/main.yml
@@ -0,0 +1,266 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+- name: Wait for Keycloak
+ uri:
+ url: "{{ url }}/admin/"
+ status_code: 200
+ validate_certs: no
+ register: result
+ until: result.status == 200
+ retries: 10
+ delay: 10
+
+- name: Delete realm if exists
+ community.general.keycloak_realm:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ realm: "{{ realm }}"
+ state: absent
+
+- name: Create realm
+ community.general.keycloak_realm:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ id: "{{ realm }}"
+ realm: "{{ realm }}"
+ state: present
+
+- name: Retrive ldap info when absent
+ community.general.keycloak_component_info:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ name: "{{ federation }}"
+ provider_type: "org.keycloak.storage.UserStorageProvider"
+ realm: "{{ realm }}"
+ register: result
+
+- name: Assert ldap is missing
+ assert:
+ that:
+ - result is not changed
+ - result.components | length == 0
+
+- name: Create new user federation
+ community.general.keycloak_user_federation:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ realm: "{{ realm }}"
+ name: "{{ federation }}"
+ state: present
+ provider_id: ldap
+ provider_type: org.keycloak.storage.UserStorageProvider
+ config:
+ enabled: true
+ priority: 0
+ fullSyncPeriod: -1
+ changedSyncPeriod: -1
+ cachePolicy: DEFAULT
+ batchSizeForSync: 1000
+ editMode: READ_ONLY
+ importEnabled: true
+ syncRegistrations: false
+ vendor: other
+ usernameLDAPAttribute: uid
+ rdnLDAPAttribute: uid
+ uuidLDAPAttribute: entryUUID
+ userObjectClasses: "inetOrgPerson, organizationalPerson"
+ connectionUrl: "ldap://ldap.example.com"
+ usersDn: "ou=Users,dc=example,dc=com"
+ authType: simple
+ bindDn: cn=directory reader
+ bindCredential: secret
+ searchScope: 1
+ validatePasswordPolicy: false
+ trustEmail: false
+ useTruststoreSpi: "ldapsOnly"
+ connectionPooling: true
+ pagination: true
+ allowKerberosAuthentication: false
+ useKerberosForPasswordAuthentication: false
+ debug: false
+
+- name: Retrive ldap info
+ community.general.keycloak_component_info:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ name: "{{ federation }}"
+ provider_type: "org.keycloak.storage.UserStorageProvider"
+ realm: "{{ realm }}"
+ register: result
+
+- name: Assert ldap exists
+ assert:
+ that:
+ - result is not changed
+ - result.components | length == 1
+ - result.components[0].name == federation
+
+- name: Save ldap id
+ set_fact:
+ myLdapId: "{{ result.components[0].id }}"
+
+- name: Retrive ldap subcomponents info
+ community.general.keycloak_component_info:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ realm: "{{ realm }}"
+ parent_id: "{{ myLdapId }}"
+ register: result
+
+- name: Assert components exists
+ assert:
+ that:
+ - result is not changed
+ - result.components | length > 0
+
+- name: Retrive ldap subcomponents filter by name
+ community.general.keycloak_component_info:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ realm: "{{ realm }}"
+ parent_id: "{{ myLdapId }}"
+ name: "email"
+ register: result
+
+- name: Assert sub component with name "email" exists
+ assert:
+ that:
+ - result is not changed
+ - result.components | length == 1
+ - result.components[0].name == "email"
+
+- name: Retrive ldap subcomponents filter by type
+ community.general.keycloak_component_info:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ realm: "{{ realm }}"
+ parent_id: "{{ myLdapId }}"
+ provider_type: "org.keycloak.storage.ldap.mappers.LDAPStorageMapper"
+ register: result
+
+- name: Assert ldap sub components filter by type
+ assert:
+ that:
+ - result is not changed
+ - result.components | length > 0
+ - result.components[0].providerType == "org.keycloak.storage.ldap.mappers.LDAPStorageMapper"
+
+- name: Retrive key info when absent
+ community.general.keycloak_component_info:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ name: "{{ realm_key_name }}"
+ provider_type: "org.keycloak.keys.KeyProvider"
+ realm: "{{ realm }}"
+ register: result
+
+- name: Assert key is missing
+ assert:
+ that:
+ - result is not changed
+ - result.components | length == 0
+
+- name: Create custom realm key
+ community.general.keycloak_realm_key:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ name: "{{ realm_key_name }}"
+ state: present
+ parent_id: "{{ realm }}"
+ config:
+ private_key: "{{ realm_private_key }}"
+ certificate: ""
+ enabled: true
+ active: true
+ priority: 150
+ register: result
+
+- name: Retrive key info
+ community.general.keycloak_component_info:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ name: "{{ realm_key_name }}"
+ provider_type: "org.keycloak.keys.KeyProvider"
+ realm: "{{ realm }}"
+ register: result
+
+- name: Assert key exists
+ assert:
+ that:
+ - result is not changed
+ - result.components | length == 1
+
+- name: Retrive all realm components
+ community.general.keycloak_component_info:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ realm: "{{ realm }}"
+ register: result
+
+- name: Assert key exists
+ assert:
+ that:
+ - result is not changed
+ - result.components | length > 0
+
+- name: Retrive all ldap in realm
+ community.general.keycloak_component_info:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ realm: "{{ realm }}"
+ provider_type: "org.keycloak.storage.UserStorageProvider"
+ register: result
+
+- name: Assert key exists
+ assert:
+ that:
+ - result is not changed
+ - result.components | length == 1
+ - result.components[0].providerType == "org.keycloak.storage.UserStorageProvider"
+ - result.components[0].name == "myldap"
+
+- name: Retrive component by name only
+ community.general.keycloak_component_info:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ realm: "{{ realm }}"
+ name: "{{ realm_key_name }}"
+ register: result
+
+- name: Assert key exists
+ assert:
+ that:
+ - result is not changed
+ - result.components | length == 1
+ - result.components[0].providerType == "org.keycloak.keys.KeyProvider"
+ - result.components[0].name == realm_key_name
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_component_info/vars/main.yml b/ansible_collections/community/general/tests/integration/targets/keycloak_component_info/vars/main.yml
new file mode 100644
index 000000000..7f18d8459
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_component_info/vars/main.yml
@@ -0,0 +1,19 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+url: http://localhost:8080/auth
+admin_realm: master
+admin_user: admin
+admin_password: password
+realm: myrealm
+
+federation: myldap
+
+
+realm_key_name: testkey
+realm_private_key: |
+ -----BEGIN PRIVATE KEY-----
+ MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC9Mi7IKXPhqGiWGwgEYEXnqc8nytG1pHbC6QYZe1gUa43jDtGYQln36It02BGw4e5XydCUj+M26X2sH+kKaV+KHEnJtcEqdAuVX1QaDVzeiOoo1/B9HC8By6NZBsOSdxpat3EvilQ+R7NP9yi53J08+vfeZSEGyPmKV1me7nJnRh3/zcRsOi92GTsBd7gApKfP8sorDjY8m9NRuPLwleK2nh/aRvj1yK8x3UAqUIbOCVaE39bSN6VUTFK2Q/+MX3vF0Zugsk7PKKmfqcEW6wj7dtSElbX4uhrfTkGMmwIWdIiLDNRA/jVRvGxUB1SyMy6kmMC8jC2QGWpZgfkSKtHlAgMBAAECggEACWkSVh7ntmjtwM+Z47vVJkt2NBS8vxPt206DYOeXbzaVUV6mkrP0LSZKL3bi1GE8fW3am9UXWF8fQt04dm3c1G4JRojtkXrBq72Y3Y3eGWyGdx8chWCOPwDdwFsbhbC6ZRo8PUDcZVekJd1Vj38XbBXQl+WAUcnTzauAF+1kz9mhJq1gpglIbB+8l7VjMXwXeaGWJQ5OL/MSsq7r3P1elVjHwprFBM7HHA5+RTu/KY/GcEutgm5uwTRqRZNC1IBXAQtBO7HQJbuLqDPTQ3RRCPEur8R+0dk5bF+8IyzQ8Bh+Dhuou9xzfS/A7lV6L/CZSpv4Bvq1H3Uxk+orXf2Q2QKBgQDBOf1nSJB0VgQdIcdtgVpVgQ2SyWAd+N8Qk7QsyVQf9f7ZqiFLejWJbaaeY9WtfZ01D8tgHJfPqsO1/Jux255mtkyk2K2c6dav1Lsd4l+iPfidsDJNWkcd59nQqwC9BLjzWK/J4rO20apm34abLaZ9oVk8Mgz8VWJWOxTgCr+COQKBgQD6qP1lm6rzlCSIEz9eCuGPkQkVo+NIP437e3i+sxtkLlMgnmfzSwSJdVF8AKH3gXi3NyWjfBVYeAZEkm1kHF8IWOiK4U1y95Vx3uud3NX4SC+cjePc+pDPQJiz9L+zq9I6WFZWmm7n/9heTxu/l0vxI4FHaBmt95BMwLJNkzbdDQKBgCHGwUUMqjOr1YxCG1pJAkFwDa9bBDI5DsUXDKfHia0Mkz/5PVi0RCeBw15slS1+h7x+xk5GsULb1to5Df5JJadOtpcaST7koWKbDRpsN8tkidEGu8RJw6S2opyXR8nCyZHALvpbZo7Ol7rj1+PIVxIe4jpjhWGWi1oHed6wAkoBAoGAJx2F5XxEUhx1EvMF+XPzPQciBsl7Z0PbsTnUXtXuWVTNThLKH/I99AFlxNcIb2o530VwzzFG13Zra/n5rhyrS88sArgj8OPn40wpMopKraL+Iw0VWN+VB3KKIdL4s14FwWsVlhAlbHjFV/o6V0yR4kBrJSx+jWJLl16etHJbpmUCgYBUWCQwcT1aw9XHWJXiNYTnQSYg88hgGYhts1qSzhfu+n1t2BlAlxM0gu2+gez21mM8uiYsqbU2OZeG2U4as6kdai8Q4tzNQt2f1r3ZewJN/QHrkx6FT94PNa0w4ILiQ9Eu7xssaHcYjHyrI1NlbMKypVy6waDG2ajLOFAVeHGpOg==
+ -----END PRIVATE KEY-----
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_group/readme.adoc b/ansible_collections/community/general/tests/integration/targets/keycloak_group/readme.adoc
index 1941e54ef..8e052920c 100644
--- a/ansible_collections/community/general/tests/integration/targets/keycloak_group/readme.adoc
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_group/readme.adoc
@@ -20,7 +20,7 @@ docker run --name mykeycloak -p 8080:8080 -e KC_HTTP_RELATIVE_PATH=/auth -e KEYC
This test suite can run against a fresh unconfigured server instance
(no preconfiguration required) and cleans up after itself (undoes all
-its config changes) as long as it runs through completly. While its active
+its config changes) as long as it runs through completely. While its active
it changes the server configuration in the following ways:
* creating, modifying and deleting some keycloak groups
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_group_rolemapping/README.md b/ansible_collections/community/general/tests/integration/targets/keycloak_group_rolemapping/README.md
new file mode 100644
index 000000000..db58acb7b
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_group_rolemapping/README.md
@@ -0,0 +1,21 @@
+<!--
+Copyright (c) Ansible Project
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
+-->
+
+# `keycloak_group_rolemapping` Integration Tests
+
+## Test Server
+
+Prepare a development server, tested with Keycloak versions tagged 22.0 and 23.0:
+
+```sh
+docker run -p 8080:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=password --rm quay.io/keycloak/keycloak:22.0 start-dev
+```
+
+## Run Tests
+
+```sh
+ansible localhost --module-name include_role --args name=keycloak_group_rolemapping
+```
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_group_rolemapping/aliases b/ansible_collections/community/general/tests/integration/targets/keycloak_group_rolemapping/aliases
new file mode 100644
index 000000000..9e2cd0dc4
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_group_rolemapping/aliases
@@ -0,0 +1,4 @@
+# Copyright (c) 2023, Alexander Groß (@agross)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+unsupported
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_group_rolemapping/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/keycloak_group_rolemapping/tasks/main.yml
new file mode 100644
index 000000000..f1e6371e2
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_group_rolemapping/tasks/main.yml
@@ -0,0 +1,160 @@
+# Copyright (c) 2023, Alexander Groß (@agross)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Create realm
+ community.general.keycloak_realm:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+
+ id: "{{ realm }}"
+ realm: "{{ realm }}"
+ state: present
+
+- name: Create realm roles
+ community.general.keycloak_role:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+
+ realm: "{{ realm }}"
+ name: "{{ item }}"
+ state: present
+ loop:
+ - "{{ role_1 }}"
+ - "{{ role_2 }}"
+
+- name: Create group
+ community.general.keycloak_group:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+
+ realm: "{{ realm }}"
+ name: "{{ group }}"
+ state: present
+
+- name: Map realm roles to group
+ community.general.keycloak_realm_rolemapping:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+
+ realm: "{{ realm }}"
+ group_name: "{{ group }}"
+ roles:
+ - name: "{{ role_1 }}"
+ - name: "{{ role_2 }}"
+ state: present
+ register: result
+
+- name: Assert realm roles are assigned to group
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.end_state | count == 2
+
+- name: Map realm roles to group again (idempotency)
+ community.general.keycloak_realm_rolemapping:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+
+ realm: "{{ realm }}"
+ group_name: "{{ group }}"
+ roles:
+ - name: "{{ role_1 }}"
+ - name: "{{ role_2 }}"
+ state: present
+ register: result
+
+- name: Assert realm roles stay assigned to group
+ ansible.builtin.assert:
+ that:
+ - result is not changed
+
+- name: Unmap realm role 1 from group
+ community.general.keycloak_realm_rolemapping:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+
+ realm: "{{ realm }}"
+ group_name: "{{ group }}"
+ roles:
+ - name: "{{ role_1 }}"
+ state: absent
+ register: result
+
+- name: Assert realm role 1 is unassigned from group
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.end_state | count == 1
+ - result.end_state[0] == role_2
+
+- name: Unmap realm role 1 from group again (idempotency)
+ community.general.keycloak_realm_rolemapping:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+
+ realm: "{{ realm }}"
+ group_name: "{{ group }}"
+ roles:
+ - name: "{{ role_1 }}"
+ state: absent
+ register: result
+
+- name: Assert realm role 1 stays unassigned from group
+ ansible.builtin.assert:
+ that:
+ - result is not changed
+
+- name: Unmap realm role 2 from group
+ community.general.keycloak_realm_rolemapping:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+
+ realm: "{{ realm }}"
+ group_name: "{{ group }}"
+ roles:
+ - name: "{{ role_2 }}"
+ state: absent
+ register: result
+
+- name: Assert no realm roles are assigned to group
+ ansible.builtin.assert:
+ that:
+ - result is changed
+ - result.end_state | count == 0
+
+- name: Unmap realm role 2 from group again (idempotency)
+ community.general.keycloak_realm_rolemapping:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+
+ realm: "{{ realm }}"
+ group_name: "{{ group }}"
+ roles:
+ - name: "{{ role_2 }}"
+ state: absent
+ register: result
+
+- name: Assert no realm roles are assigned to group
+ ansible.builtin.assert:
+ that:
+ - result is not changed
+ - result.end_state | count == 0
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_group_rolemapping/vars/main.yml b/ansible_collections/community/general/tests/integration/targets/keycloak_group_rolemapping/vars/main.yml
new file mode 100644
index 000000000..0848499e7
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_group_rolemapping/vars/main.yml
@@ -0,0 +1,15 @@
+---
+# Copyright (c) 2023, Alexander Groß (@agross)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+url: http://localhost:8080
+admin_realm: master
+admin_user: admin
+admin_password: password
+realm: myrealm
+
+role_1: myrole-1
+role_2: myrole-2
+
+group: mygroup
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_identity_provider/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/keycloak_identity_provider/tasks/main.yml
index 79ba33049..afad9740e 100644
--- a/ansible_collections/community/general/tests/integration/targets/keycloak_identity_provider/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_identity_provider/tasks/main.yml
@@ -35,14 +35,14 @@
syncMode: FORCE
mappers:
- name: "first_name"
- identityProviderAlias: "oidc-idp"
+ identityProviderAlias: "{{ idp }}"
identityProviderMapper: "oidc-user-attribute-idp-mapper"
config:
claim: "first_name"
user.attribute: "first_name"
syncMode: "INHERIT"
- name: "last_name"
- identityProviderAlias: "oidc-idp"
+ identityProviderAlias: "{{ idp }}"
identityProviderMapper: "oidc-user-attribute-idp-mapper"
config:
claim: "last_name"
@@ -84,14 +84,14 @@
syncMode: FORCE
mappers:
- name: "first_name"
- identityProviderAlias: "oidc-idp"
+ identityProviderAlias: "{{ idp }}"
identityProviderMapper: "oidc-user-attribute-idp-mapper"
config:
claim: "first_name"
user.attribute: "first_name"
syncMode: "INHERIT"
- name: "last_name"
- identityProviderAlias: "oidc-idp"
+ identityProviderAlias: "{{ idp }}"
identityProviderMapper: "oidc-user-attribute-idp-mapper"
config:
claim: "last_name"
@@ -109,7 +109,7 @@
that:
- result is not changed
-- name: Update existing identity provider (with change)
+- name: Update existing identity provider (with change, no mapper change)
community.general.keycloak_identity_provider:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
@@ -132,6 +132,109 @@
- result.existing.enabled == true
- result.end_state.enabled == false
+- name: Update existing identity provider (delete mapper)
+ community.general.keycloak_identity_provider:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ realm: "{{ realm }}"
+ alias: "{{ idp }}"
+ state: present
+ mappers:
+ - name: "first_name"
+ identityProviderAlias: "{{ idp }}"
+ identityProviderMapper: "oidc-user-attribute-idp-mapper"
+ config:
+ claim: "first_name"
+ user.attribute: "first_name"
+ syncMode: "INHERIT"
+ register: result
+
+- name: Debug
+ debug:
+ var: result
+
+- name: Assert identity provider updated
+ assert:
+ that:
+ - result is changed
+ - result.existing.mappers | length == 2
+ - result.end_state.mappers | length == 1
+ - result.end_state.mappers[0].name == "first_name"
+
+- name: Update existing identity provider (add mapper)
+ community.general.keycloak_identity_provider:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ realm: "{{ realm }}"
+ alias: "{{ idp }}"
+ state: present
+ mappers:
+ - name: "last_name"
+ identityProviderAlias: "{{ idp }}"
+ identityProviderMapper: "oidc-user-attribute-idp-mapper"
+ config:
+ claim: "last_name"
+ user.attribute: "last_name"
+ syncMode: "INHERIT"
+ - name: "first_name"
+ identityProviderAlias: "{{ idp }}"
+ identityProviderMapper: "oidc-user-attribute-idp-mapper"
+ config:
+ claim: "first_name"
+ user.attribute: "first_name"
+ syncMode: "INHERIT"
+ register: result
+
+- name: Debug
+ debug:
+ var: result
+
+- name: Assert identity provider updated
+ assert:
+ that:
+ - result is changed
+ - result.existing.mappers | length == 1
+ - result.end_state.mappers | length == 2
+
+- name: Update existing identity provider (no change, test mapper idempotency)
+ community.general.keycloak_identity_provider:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ realm: "{{ realm }}"
+ alias: "{{ idp }}"
+ state: present
+ mappers:
+ - name: "last_name"
+ identityProviderAlias: "{{ idp }}"
+ identityProviderMapper: "oidc-user-attribute-idp-mapper"
+ config:
+ claim: "last_name"
+ user.attribute: "last_name"
+ syncMode: "INHERIT"
+ - name: "first_name"
+ identityProviderAlias: "{{ idp }}"
+ identityProviderMapper: "oidc-user-attribute-idp-mapper"
+ config:
+ claim: "first_name"
+ user.attribute: "first_name"
+ syncMode: "INHERIT"
+ register: result
+
+- name: Debug
+ debug:
+ var: result
+
+- name: Assert identity provider updated
+ assert:
+ that:
+ - result is not changed
+
- name: Delete existing identity provider
community.general.keycloak_identity_provider:
auth_keycloak_url: "{{ url }}"
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_realm_key/aliases b/ansible_collections/community/general/tests/integration/targets/keycloak_realm_key/aliases
new file mode 100644
index 000000000..bd1f02444
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_realm_key/aliases
@@ -0,0 +1,5 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+unsupported
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_realm_key/readme.adoc b/ansible_collections/community/general/tests/integration/targets/keycloak_realm_key/readme.adoc
new file mode 100644
index 000000000..8e052920c
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_realm_key/readme.adoc
@@ -0,0 +1,27 @@
+// Copyright (c) Ansible Project
+// GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+To be able to run these integration tests a keycloak server must be
+reachable under a specific url with a specific admin user and password.
+The exact values expected for these parameters can be found in
+'vars/main.yml' file. A simple way to do this is to use the official
+keycloak docker images like this:
+
+----
+docker run --name mykeycloak -p 8080:8080 -e KC_HTTP_RELATIVE_PATH=<url-path> -e KEYCLOAK_ADMIN=<admin_user> -e KEYCLOAK_ADMIN_PASSWORD=<admin_password> quay.io/keycloak/keycloak:20.0.2 start-dev
+----
+
+Example with concrete values inserted:
+
+----
+docker run --name mykeycloak -p 8080:8080 -e KC_HTTP_RELATIVE_PATH=/auth -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=password quay.io/keycloak/keycloak:20.0.2 start-dev
+----
+
+This test suite can run against a fresh unconfigured server instance
+(no preconfiguration required) and cleans up after itself (undoes all
+its config changes) as long as it runs through completely. While its active
+it changes the server configuration in the following ways:
+
+ * creating, modifying and deleting some keycloak groups
+
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_realm_key/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/keycloak_realm_key/tasks/main.yml
new file mode 100644
index 000000000..c02950600
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_realm_key/tasks/main.yml
@@ -0,0 +1,373 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+- name: Remove Keycloak test realm to avoid failures from previous failed runs
+ community.general.keycloak_realm:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ realm: "{{ realm }}"
+ id: "{{ realm }}"
+ state: absent
+
+- name: Create Keycloak test realm
+ community.general.keycloak_realm:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ realm: "{{ realm }}"
+ id: "{{ realm }}"
+ state: present
+
+- name: Create custom realm key (check mode)
+ community.general.keycloak_realm_key:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ name: testkey
+ state: present
+ parent_id: "{{ realm }}"
+ config:
+ private_key: "{{ realm_private_key }}"
+ certificate: ""
+ enabled: true
+ active: true
+ priority: 150
+ check_mode: true
+ register: result
+
+- name: Assert that nothing has changed
+ assert:
+ that:
+ - result is changed
+ - result.end_state != {}
+ - result.end_state.name == "testkey"
+ - result.end_state.parentId == "realm_key_test"
+ - result.end_state.providerId == "rsa"
+ - result.end_state.providerType == "org.keycloak.keys.KeyProvider"
+ - result.end_state.config.active == ["true"]
+ - result.end_state.config.enabled == ["true"]
+ - result.end_state.config.algorithm == ["RS256"]
+ - result.end_state.config.priority == ["150"]
+ - result.msg == "Realm key testkey would be created"
+
+- name: Create custom realm key
+ community.general.keycloak_realm_key:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ name: testkey
+ state: present
+ parent_id: "{{ realm }}"
+ config:
+ private_key: "{{ realm_private_key }}"
+ certificate: ""
+ enabled: true
+ active: true
+ priority: 150
+ diff: true
+ register: result
+
+- name: Assert that realm key was created
+ assert:
+ that:
+ - result is changed
+ - result.end_state != {}
+ - result.end_state.name == "testkey"
+ - result.end_state.parentId == "realm_key_test"
+ - result.end_state.providerId == "rsa"
+ - result.end_state.providerType == "org.keycloak.keys.KeyProvider"
+ - result.end_state.config.active == ["true"]
+ - result.end_state.config.enabled == ["true"]
+ - result.end_state.config.algorithm == ["RS256"]
+ - result.end_state.config.priority == ["150"]
+ - result.msg == "Realm key testkey created"
+
+- name: Create custom realm key (test for idempotency)
+ community.general.keycloak_realm_key:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ name: testkey
+ state: present
+ parent_id: "{{ realm }}"
+ config:
+ private_key: "{{ realm_private_key }}"
+ certificate: ""
+ enabled: true
+ active: true
+ priority: 150
+ register: result
+
+- name: Assert that nothing has changed
+ assert:
+ that:
+ - result is not changed
+ - result.end_state != {}
+ - result.end_state.name == "testkey"
+ - result.end_state.parentId == "realm_key_test"
+ - result.end_state.providerId == "rsa"
+ - result.end_state.providerType == "org.keycloak.keys.KeyProvider"
+ - result.end_state.config.active == ["true"]
+ - result.end_state.config.enabled == ["true"]
+ - result.end_state.config.algorithm == ["RS256"]
+ - result.end_state.config.priority == ["150"]
+ - result.msg == "Realm key testkey was in sync"
+
+- name: Update custom realm key (check mode)
+ community.general.keycloak_realm_key:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ name: testkey
+ state: present
+ parent_id: "{{ realm }}"
+ config:
+ private_key: "{{ realm_private_key }}"
+ certificate: ""
+ enabled: true
+ active: true
+ priority: 140
+ check_mode: true
+ register: result
+
+- name: Assert that nothing has changed
+ assert:
+ that:
+ - result is changed
+ - result.end_state != {}
+ - result.end_state.name == "testkey"
+ - result.end_state.parentId == "realm_key_test"
+ - result.end_state.providerId == "rsa"
+ - result.end_state.providerType == "org.keycloak.keys.KeyProvider"
+ - result.end_state.config.active == ["true"]
+ - result.end_state.config.enabled == ["true"]
+ - result.end_state.config.algorithm == ["RS256"]
+ - result.end_state.config.priority == ["140"]
+ - result.msg == "Realm key testkey would be changed: config.priority ['150'] -> ['140']"
+
+- name: Update custom realm key
+ community.general.keycloak_realm_key:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ name: testkey
+ state: present
+ parent_id: "{{ realm }}"
+ config:
+ private_key: "{{ realm_private_key }}"
+ certificate: ""
+ enabled: true
+ active: true
+ priority: 140
+ diff: true
+ register: result
+
+- name: Assert that realm key was updated
+ assert:
+ that:
+ - result is changed
+ - result.end_state != {}
+ - result.end_state.name == "testkey"
+ - result.end_state.parentId == "realm_key_test"
+ - result.end_state.providerId == "rsa"
+ - result.end_state.providerType == "org.keycloak.keys.KeyProvider"
+ - result.end_state.config.active == ["true"]
+ - result.end_state.config.enabled == ["true"]
+ - result.end_state.config.algorithm == ["RS256"]
+ - result.end_state.config.priority == ["140"]
+ - result.msg == "Realm key testkey changed: config.priority ['150'] -> ['140']"
+
+- name: Update custom realm key (test for idempotency)
+ community.general.keycloak_realm_key:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ name: testkey
+ state: present
+ parent_id: "{{ realm }}"
+ config:
+ private_key: "{{ realm_private_key }}"
+ certificate: ""
+ enabled: true
+ active: true
+ priority: 140
+ register: result
+
+- name: Assert that nothing has changed
+ assert:
+ that:
+ - result is not changed
+ - result.end_state != {}
+ - result.end_state.name == "testkey"
+ - result.end_state.parentId == "realm_key_test"
+ - result.end_state.providerId == "rsa"
+ - result.end_state.providerType == "org.keycloak.keys.KeyProvider"
+ - result.end_state.config.active == ["true"]
+ - result.end_state.config.enabled == ["true"]
+ - result.end_state.config.algorithm == ["RS256"]
+ - result.end_state.config.priority == ["140"]
+ - result.msg == "Realm key testkey was in sync"
+
+- name: Force update custom realm key
+ community.general.keycloak_realm_key:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ name: testkey
+ force: true
+ state: present
+ parent_id: "{{ realm }}"
+ config:
+ private_key: "{{ realm_private_key_2 }}"
+ certificate: ""
+ enabled: true
+ active: true
+ priority: 140
+ register: result
+
+- name: Assert that forced update ran correctly
+ assert:
+ that:
+ - result is changed
+ - result.end_state != {}
+ - result.end_state.name == "testkey"
+ - result.end_state.parentId == "realm_key_test"
+ - result.end_state.providerId == "rsa"
+ - result.end_state.providerType == "org.keycloak.keys.KeyProvider"
+ - result.end_state.config.active == ["true"]
+ - result.end_state.config.enabled == ["true"]
+ - result.end_state.config.algorithm == ["RS256"]
+ - result.end_state.config.priority == ["140"]
+ - result.msg == "Realm key testkey was forcibly updated"
+
+- name: Remove custom realm key
+ community.general.keycloak_realm_key:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ name: testkey
+ state: absent
+ parent_id: "{{ realm }}"
+ config:
+ private_key: "{{ realm_private_key }}"
+ certificate: ""
+ priority: 140
+ diff: true
+ register: result
+
+- name: Assert that realm key was deleted
+ assert:
+ that:
+ - result is changed
+ - result.end_state == {}
+ - result.msg == "Realm key testkey deleted"
+
+- name: Remove custom realm key (test for idempotency)
+ community.general.keycloak_realm_key:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ name: testkey
+ state: absent
+ parent_id: "{{ realm }}"
+ config:
+ private_key: "{{ realm_private_key }}"
+ certificate: ""
+ priority: 140
+ register: result
+
+- name: Assert that nothing has changed
+ assert:
+ that:
+ - result is not changed
+ - result.end_state == {}
+ - result.msg == "Realm key testkey not present"
+
+- name: Create custom realm key with a custom certificate
+ community.general.keycloak_realm_key:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ name: testkey_with_certificate
+ state: present
+ parent_id: "{{ realm }}"
+ config:
+ private_key: "{{ realm_private_key }}"
+ certificate: "{{ realm_certificate }}"
+ enabled: true
+ active: true
+ priority: 150
+ diff: true
+ register: result
+
+- name: Assert that realm key with custom certificate was created
+ assert:
+ that:
+ - result is changed
+ - result.end_state != {}
+ - result.end_state.name == "testkey_with_certificate"
+ - result.end_state.parentId == "realm_key_test"
+ - result.end_state.providerId == "rsa"
+ - result.end_state.providerType == "org.keycloak.keys.KeyProvider"
+ - result.end_state.config.active == ["true"]
+ - result.end_state.config.enabled == ["true"]
+ - result.end_state.config.algorithm == ["RS256"]
+ - result.end_state.config.priority == ["150"]
+ - result.msg == "Realm key testkey_with_certificate created"
+
+- name: Attempt to change the private key and the certificate
+ community.general.keycloak_realm_key:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ name: testkey_with_certificate
+ state: present
+ parent_id: "{{ realm }}"
+ config:
+ private_key: "a different private key string"
+ certificate: "a different certificate string"
+ enabled: true
+ active: true
+ priority: 150
+ diff: true
+ register: result
+
+- name: Assert that nothing has changed
+ assert:
+ that:
+ - result is not changed
+ - result.end_state != {}
+ - result.end_state.name == "testkey_with_certificate"
+ - result.end_state.parentId == "realm_key_test"
+ - result.end_state.providerId == "rsa"
+ - result.end_state.providerType == "org.keycloak.keys.KeyProvider"
+ - result.end_state.config.active == ["true"]
+ - result.end_state.config.enabled == ["true"]
+ - result.end_state.config.algorithm == ["RS256"]
+ - result.end_state.config.priority == ["150"]
+ - result.msg == "Realm key testkey_with_certificate was in sync"
+
+- name: Remove Keycloak test realm
+ community.general.keycloak_realm:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ realm: "{{ realm }}"
+ id: "{{ realm }}"
+ state: absent
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_realm_key/vars/main.yml b/ansible_collections/community/general/tests/integration/targets/keycloak_realm_key/vars/main.yml
new file mode 100644
index 000000000..d39cf8f73
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_realm_key/vars/main.yml
@@ -0,0 +1,48 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+url: http://localhost:8080/auth
+admin_realm: master
+admin_user: admin
+admin_password: password
+realm: realm_key_test
+realm_private_key_name: testkey
+realm_private_key: |
+ -----BEGIN PRIVATE KEY-----
+ MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC9Mi7IKXPhqGiWGwgEYEXnqc8nytG1pHbC6QYZe1gUa43jDtGYQln36It02BGw4e5XydCUj+M26X2sH+kKaV+KHEnJtcEqdAuVX1QaDVzeiOoo1/B9HC8By6NZBsOSdxpat3EvilQ+R7NP9yi53J08+vfeZSEGyPmKV1me7nJnRh3/zcRsOi92GTsBd7gApKfP8sorDjY8m9NRuPLwleK2nh/aRvj1yK8x3UAqUIbOCVaE39bSN6VUTFK2Q/+MX3vF0Zugsk7PKKmfqcEW6wj7dtSElbX4uhrfTkGMmwIWdIiLDNRA/jVRvGxUB1SyMy6kmMC8jC2QGWpZgfkSKtHlAgMBAAECggEACWkSVh7ntmjtwM+Z47vVJkt2NBS8vxPt206DYOeXbzaVUV6mkrP0LSZKL3bi1GE8fW3am9UXWF8fQt04dm3c1G4JRojtkXrBq72Y3Y3eGWyGdx8chWCOPwDdwFsbhbC6ZRo8PUDcZVekJd1Vj38XbBXQl+WAUcnTzauAF+1kz9mhJq1gpglIbB+8l7VjMXwXeaGWJQ5OL/MSsq7r3P1elVjHwprFBM7HHA5+RTu/KY/GcEutgm5uwTRqRZNC1IBXAQtBO7HQJbuLqDPTQ3RRCPEur8R+0dk5bF+8IyzQ8Bh+Dhuou9xzfS/A7lV6L/CZSpv4Bvq1H3Uxk+orXf2Q2QKBgQDBOf1nSJB0VgQdIcdtgVpVgQ2SyWAd+N8Qk7QsyVQf9f7ZqiFLejWJbaaeY9WtfZ01D8tgHJfPqsO1/Jux255mtkyk2K2c6dav1Lsd4l+iPfidsDJNWkcd59nQqwC9BLjzWK/J4rO20apm34abLaZ9oVk8Mgz8VWJWOxTgCr+COQKBgQD6qP1lm6rzlCSIEz9eCuGPkQkVo+NIP437e3i+sxtkLlMgnmfzSwSJdVF8AKH3gXi3NyWjfBVYeAZEkm1kHF8IWOiK4U1y95Vx3uud3NX4SC+cjePc+pDPQJiz9L+zq9I6WFZWmm7n/9heTxu/l0vxI4FHaBmt95BMwLJNkzbdDQKBgCHGwUUMqjOr1YxCG1pJAkFwDa9bBDI5DsUXDKfHia0Mkz/5PVi0RCeBw15slS1+h7x+xk5GsULb1to5Df5JJadOtpcaST7koWKbDRpsN8tkidEGu8RJw6S2opyXR8nCyZHALvpbZo7Ol7rj1+PIVxIe4jpjhWGWi1oHed6wAkoBAoGAJx2F5XxEUhx1EvMF+XPzPQciBsl7Z0PbsTnUXtXuWVTNThLKH/I99AFlxNcIb2o530VwzzFG13Zra/n5rhyrS88sArgj8OPn40wpMopKraL+Iw0VWN+VB3KKIdL4s14FwWsVlhAlbHjFV/o6V0yR4kBrJSx+jWJLl16etHJbpmUCgYBUWCQwcT1aw9XHWJXiNYTnQSYg88hgGYhts1qSzhfu+n1t2BlAlxM0gu2+gez21mM8uiYsqbU2OZeG2U4as6kdai8Q4tzNQt2f1r3ZewJN/QHrkx6FT94PNa0w4ILiQ9Eu7xssaHcYjHyrI1NlbMKypVy6waDG2ajLOFAVeHGpOg==
+ -----END PRIVATE KEY-----
+realm_certificate: |
+ -----BEGIN CERTIFICATE-----
+ MIIDQDCCAiigAwIBAgIUMfPlHWcZn6xfeSjfbhgmt4yy6mMwDQYJKoZIhvcNAQELBQAwQjELMAkGA1UEBhMCWFgxFTATBgNVBAcMDERlZmF1bHQgQ2l0eTEcMBoGA1UECgwTRGVmYXVsdCBDb21wYW55IEx0ZDAeFw0yMzA4MTgxMTU5MDFaFw0zMzA4MTUxMTU5MDFaMEIxCzAJBgNVBAYTAlhYMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0RlZmF1bHQgQ29tcGFueSBMdGQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9Mi7IKXPhqGiWGwgEYEXnqc8nytG1pHbC6QYZe1gUa43jDtGYQln36It02BGw4e5XydCUj+M26X2sH+kKaV+KHEnJtcEqdAuVX1QaDVzeiOoo1/B9HC8By6NZBsOSdxpat3EvilQ+R7NP9yi53J08+vfeZSEGyPmKV1me7nJnRh3/zcRsOi92GTsBd7gApKfP8sorDjY8m9NRuPLwleK2nh/aRvj1yK8x3UAqUIbOCVaE39bSN6VUTFK2Q/+MX3vF0Zugsk7PKKmfqcEW6wj7dtSElbX4uhrfTkGMmwIWdIiLDNRA/jVRvGxUB1SyMy6kmMC8jC2QGWpZgfkSKtHlAgMBAAGjLjAsMAsGA1UdDwQEAwIEkDAdBgNVHQ4EFgQUcZirWRV5EzRhanUVSQ9rmAavVbEwDQYJKoZIhvcNAQELBQADggEBAIt2aFr/sxvtZfDc+Nb9tgspBuoX8f9Gf9mrS6dTdvdqSMHQrcoejSEEAZNljdSpKAhnhyR3+uCIev++WS4tixZoooQ8aYxDGNIwyry51GNEK7LKXVRmkbZFODidRuYZ1XWQORaJoaXWplaPaNtLvUr1swachz36K4n8/UIi109w/addajOHFbFGAzUmGRR4saMZPGrQCaNFje7G1o5wb/mQD1L+Jfk81Id5/F6NFBsSEIi+/O7Xs7fOWuab6cdfwI7zQQclEo55WQkLXefFLn+Ju0Ftgl023awpNEE4pjl6jD5VSEOkQ+I2sxGvymgjz7Av4zPOD/Lr05lRnMxf8dA=
+ -----END CERTIFICATE-----
+realm_private_key_2: |
+ -----BEGIN PRIVATE KEY-----
+ MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCyQ5FKuqbnWEtt
+ KI0FHKFvd+G/RyEI2ow29Ytjs3fZ7/gMYfXozHLLJl3jgCOvSf9Ta55arL0XnCCf
+ RKQb0vpgMmOTQw++A1UmNXe8atTczZMRiHMHFdLhXUvUKthcMGOrTH8xegCnm0bG
+ rZwimjQDog/kROMAN78Uv8SD1lMpGBxPr2DWXNl4kRF670m/jC0cM7SeDGCCKVF5
+ SEh6rMDgI62AxKnbtxuAbF9SOO/6kTsYv5+dc8wxDEb0aaT1jC1CLhjAVmjc6vO7
+ WHE0LLas+ARs4ghMONLN6VdOkJxBuEtlLqM3M+/viD1TRftZCeLarYLWdEsg8Yz9
+ Ufb0oawzAgMBAAECggEARqPDxWsljHNOoFj7WNU5m6RTzqpvCsUf3v96Vu3dRn1z
+ O+Ttv2yU6K+xcN9sRJ/8D6CLxb7Bx8NUoghfR69ZDBmrn8VpTZCgg12Yrw9efojw
+ CHibrGkXgbqou9CmoBGEzXKozIBeFgzQBRby0jts9SuZRImPspxkmeJMCzo5BgUg
+ ksNibaWikvUJYMgFc7PdXEvxhCKcWTTGC3fxJwpRxXkqKsYDa3JhdhloH8hHqynm
+ o7WEXeGAn4UV7C1tg3OdTciHn/ONMRItPcyonwk19meZTvsEub6ZsNjVg/5oJVBr
+ WG8vPZBi1VzAMayDXxDOnEAKW5eJXRSNX1vZ7EQTEQKBgQDXg5pSp9hVdVZc+eN/
+ Ab/1NMMdgrQdbyTeB9esjLiwNuXysQm/KaG8gTkLpiKVvJ8R7SOcxb9Y5Gt9Y5Ej
+ eu943V4zLDIzNt/ST4bXGW/gQ84zkMBdhKz9hKA5tartVjI1ycznjpDbgn/jAYPI
+ 8VXGmjID2oDIJ7P+dLD8lMBDvQKBgQDTwIyimy+4EwFUuuppfWArXRsqsWUScGWD
+ +06xbc+Ld92LJBvakvSTdDNnS/PlYGl/fJjqQ4wq5UPREJYCi3UW9I5jtfsIg8Pl
+ oCnIhEYkn8xPZ7X8grU4emkM6QAPhstCDlXE6t0T202TpYVYjtEEDRQu4rKAbJ0h
+ gqSh5Ge2rwKBgEjrx6jWEBYCaOF20ComTmxKmQaANi+Lbt8NqkVBLDC7spymmJSt
+ IoOk+cdeRG+D7hLjuVwPcQpD57b6nJ5zt1mfFYOdHbNEiwEfVZGskrVAXCIIhX5f
+ KSVy3cAJHzfFJaIbkRB8pbkQc/M8jPnN5ucXP3scUNzoyjd8BnLAZjnFAoGAWwwY
+ rDYTz48EbH0uG4uYFS0kaDf8YHBJhfVBgdLYgXxZmuE8xL+ZP+mfzJOA3CiXVASr
+ 71Z551vKzBLYnWF/SA6BRuhRdvjI+2vha2FMk6TOAXpzao59AzrG/pEUwJhRvyZQ
+ xKnDwyzxb0GlU02dG6PQANTisYuCCI2W4jFGUusCgYB72p5o5uBr7qrFMTdMMxxe
+ f/9Go/9QBR/uNYk3D/rWj0F/bXGbiYMddNMD4v3XE24NL4ZvBJn0Po64Tuz5+wtu
+ 5ICKc6ED1l55MPsKdegVMpXGIFRjZt2TtCk4FE68m5QJpT1IIK7I9jv0+FGKjFYa
+ ukdTEghu13cANd8eKpxBsQ==
+ -----END PRIVATE KEY-----
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_role/README.md b/ansible_collections/community/general/tests/integration/targets/keycloak_role/README.md
new file mode 100644
index 000000000..ccb4c8ffa
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_role/README.md
@@ -0,0 +1,20 @@
+<!--
+Copyright (c) Ansible Project
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
+-->
+# Running keycloak_user module integration test
+
+To run Keycloak user module's integration test, start a keycloak server using Docker or Podman:
+
+ podman|docker run -d --rm --name mykeycloak -p 8080:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=password quay.io/keycloak/keycloak:latest start-dev --http-relative-path /auth
+
+Source Ansible env-setup from ansible github repository
+
+Run integration tests:
+
+ ansible-test integration keycloak_role --python 3.10 --allow-unsupported
+
+Cleanup:
+
+ podman|docker stop mykeycloak
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_role/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/keycloak_role/tasks/main.yml
index 61b62629a..c649b8680 100644
--- a/ansible_collections/community/general/tests/integration/targets/keycloak_role/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_role/tasks/main.yml
@@ -248,3 +248,236 @@
that:
- result is not changed
- result.end_state == {}
+
+- name: Create realm role with composites
+ community.general.keycloak_role:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ name: "{{ keycloak_role_name }}"
+ realm: "{{ realm }}"
+ description: "{{ keycloak_role_description }}"
+ composite: "{{ keycloak_role_composite }}"
+ composites: "{{ keycloak_role_composites }}"
+ state: present
+ register: result
+
+- name: Debug
+ debug:
+ var: result
+
+- name: Assert realm role is created with composites
+ assert:
+ that:
+ - result is changed
+ - result.end_state.composites | length == 3
+
+- name: Change realm role with composites no change
+ community.general.keycloak_role:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ name: "{{ keycloak_role_name }}"
+ realm: "{{ realm }}"
+ description: "{{ keycloak_role_description }}"
+ composite: "{{ keycloak_role_composite }}"
+ composites: "{{ keycloak_role_composites }}"
+ state: present
+ register: result
+
+- name: Debug
+ debug:
+ var: result
+
+- name: Assert realm role with composites have not changed
+ assert:
+ that:
+ - result is not changed
+ - result.end_state.composites | length == 3
+
+- name: Remove composite from realm role with composites
+ community.general.keycloak_role:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ name: "{{ keycloak_role_name }}"
+ realm: "{{ realm }}"
+ description: "{{ keycloak_role_description }}"
+ composite: "{{ keycloak_role_composite }}"
+ composites: "{{ keycloak_role_composites_with_absent }}"
+ state: present
+ register: result
+
+- name: Debug
+ debug:
+ var: result
+
+- name: Assert composite was removed from realm role with composites
+ assert:
+ that:
+ - result is changed
+ - result.end_state.composites | length == 2
+
+- name: Delete realm role with composites
+ community.general.keycloak_role:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ realm: "{{ realm }}"
+ name: "{{ keycloak_role_name }}"
+ state: absent
+ register: result
+
+- name: Debug
+ debug:
+ var: result
+
+- name: Assert realm role deleted
+ assert:
+ that:
+ - result is changed
+ - result.end_state == {}
+
+- name: Delete absent realm role with composites
+ community.general.keycloak_role:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ realm: "{{ realm }}"
+ name: "{{ keycloak_role_name }}"
+ state: absent
+ register: result
+
+- name: Debug
+ debug:
+ var: result
+
+- name: Assert not changed and realm role absent
+ assert:
+ that:
+ - result is not changed
+ - result.end_state == {}
+
+- name: Create client role with composites
+ community.general.keycloak_role:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ name: "{{ keycloak_role_name }}"
+ client_id: "{{ client_id }}"
+ realm: "{{ realm }}"
+ description: "{{ keycloak_role_description }}"
+ composite: "{{ keycloak_role_composite }}"
+ composites: "{{ keycloak_role_composites }}"
+ state: present
+ register: result
+
+- name: Debug
+ debug:
+ var: result
+
+- name: Assert client role is created with composites
+ assert:
+ that:
+ - result is changed
+ - result.end_state.composites | length == 3
+
+- name: Change client role with composites no change
+ community.general.keycloak_role:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ name: "{{ keycloak_role_name }}"
+ client_id: "{{ client_id }}"
+ realm: "{{ realm }}"
+ description: "{{ keycloak_role_description }}"
+ composite: "{{ keycloak_role_composite }}"
+ composites: "{{ keycloak_role_composites }}"
+ state: present
+ register: result
+
+- name: Debug
+ debug:
+ var: result
+
+- name: Assert client role with composites have not changed
+ assert:
+ that:
+ - result is not changed
+ - result.end_state.composites | length == 3
+
+- name: Remove composite from client role with composites
+ community.general.keycloak_role:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ name: "{{ keycloak_role_name }}"
+ client_id: "{{ client_id }}"
+ realm: "{{ realm }}"
+ description: "{{ keycloak_role_description }}"
+ composite: "{{ keycloak_role_composite }}"
+ composites: "{{ keycloak_role_composites_with_absent }}"
+ state: present
+ register: result
+
+- name: Debug
+ debug:
+ var: result
+
+- name: Assert composite was removed from client role with composites
+ assert:
+ that:
+ - result is changed
+ - result.end_state.composites | length == 2
+
+- name: Delete client role with composites
+ community.general.keycloak_role:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ realm: "{{ realm }}"
+ name: "{{ keycloak_role_name }}"
+ client_id: "{{ client_id }}"
+ state: absent
+ register: result
+
+- name: Debug
+ debug:
+ var: result
+
+- name: Assert client role deleted
+ assert:
+ that:
+ - result is changed
+ - result.end_state == {}
+
+- name: Delete absent client role with composites
+ community.general.keycloak_role:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ realm: "{{ realm }}"
+ name: "{{ keycloak_role_name }}"
+ client_id: "{{ client_id }}"
+ state: absent
+ register: result
+
+- name: Debug
+ debug:
+ var: result
+
+- name: Assert not changed and client role absent
+ assert:
+ that:
+ - result is not changed
+ - result.end_state == {} \ No newline at end of file
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_role/vars/main.yml b/ansible_collections/community/general/tests/integration/targets/keycloak_role/vars/main.yml
index b003311e0..0af55dfc5 100644
--- a/ansible_collections/community/general/tests/integration/targets/keycloak_role/vars/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_role/vars/main.yml
@@ -12,3 +12,30 @@ client_id: myclient
role: myrole
description_1: desc 1
description_2: desc 2
+
+keycloak_role_name: test
+keycloak_role_description: test
+keycloak_role_composite: true
+keycloak_role_composites:
+ - name: view-clients
+ client_id: "realm-management"
+ state: present
+ - name: query-clients
+ client_id: "realm-management"
+ state: present
+ - name: offline_access
+ state: present
+keycloak_client_id: test-client
+keycloak_client_name: test-client
+keycloak_client_description: This is a client for testing purpose
+role_state: present
+
+keycloak_role_composites_with_absent:
+ - name: view-clients
+ client_id: "realm-management"
+ state: present
+ - name: query-clients
+ client_id: "realm-management"
+ state: present
+ - name: offline_access
+ state: absent \ No newline at end of file
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_user/README.md b/ansible_collections/community/general/tests/integration/targets/keycloak_user/README.md
new file mode 100644
index 000000000..07ecc3f83
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_user/README.md
@@ -0,0 +1,21 @@
+<!--
+Copyright (c) Ansible Project
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
+-->
+# Running keycloak_user module integration test
+
+To run Keycloak user module's integration test, start a keycloak server using Docker or Podman:
+
+ podman|docker run -d --rm --name mykeycloak -p 8080:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=password quay.io/keycloak/keycloak:latest start-dev --http-relative-path /auth
+
+Source Ansible env-setup from ansible github repository
+
+Run integration tests:
+
+ ansible-test integration keycloak_user --python 3.10 --allow-unsupported
+
+Cleanup:
+
+ podman|docker stop mykeycloak
+
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_user/aliases b/ansible_collections/community/general/tests/integration/targets/keycloak_user/aliases
new file mode 100644
index 000000000..0abc6a467
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_user/aliases
@@ -0,0 +1,4 @@
+# Copyright (c) 2023, INSPQ Philippe Gauthier (@elfelip)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+unsupported
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_user/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/keycloak_user/tasks/main.yml
new file mode 100644
index 000000000..0f1fe152d
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_user/tasks/main.yml
@@ -0,0 +1,114 @@
+# Copyright (c) 2022, Dušan Marković (@bratwurzt)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Create realm
+ community.general.keycloak_realm:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ id: "{{ realm }}"
+ realm: "{{ realm }}"
+ state: present
+
+- name: Create new realm role
+ community.general.keycloak_role:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ realm: "{{ realm }}"
+ name: "{{ role }}"
+ description: "{{ description_1 }}"
+ state: present
+
+- name: Create client
+ community.general.keycloak_client:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ realm: "{{ realm }}"
+ client_id: "{{ client_id }}"
+ service_accounts_enabled: true
+ state: present
+ register: client
+
+
+- name: Create new client role
+ community.general.keycloak_role:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ realm: "{{ realm }}"
+ client_id: "{{ client_id }}"
+ name: "{{ keycloak_client_role }}"
+ description: "{{ description_1 }}"
+ state: present
+
+- name: Create new groups
+ community.general.keycloak_group:
+ auth_keycloak_url: "{{ url }}"
+ auth_realm: "{{ admin_realm }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ realm: "{{ realm }}"
+ name: "{{ item.name }}"
+ state: present
+ with_items: "{{ keycloak_user_groups }}"
+
+- name: Create user
+ community.general.keycloak_user:
+ auth_keycloak_url: "{{ url }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ auth_realm: "{{ admin_realm }}"
+ username: "{{ keycloak_username }}"
+ realm: "{{ realm }}"
+ first_name: Ceciestes
+ last_name: Untestes
+ email: ceciestuntestes@test.com
+ groups: "{{ keycloak_user_groups }}"
+ attributes: "{{ keycloak_user_attributes }}"
+ state: present
+ register: create_result
+
+- name: debug
+ debug:
+ var: create_result
+
+- name: Assert user is created
+ assert:
+ that:
+ - create_result.changed
+ - create_result.end_state.username == 'test'
+ - create_result.end_state.attributes | length == 3
+ - create_result.end_state.groups | length == 2
+
+- name: Delete User
+ community.general.keycloak_user:
+ auth_keycloak_url: "{{ url }}"
+ auth_username: "{{ admin_user }}"
+ auth_password: "{{ admin_password }}"
+ auth_realm: "{{ admin_realm }}"
+ username: "{{ keycloak_username }}"
+ realm: "{{ realm }}"
+ first_name: Ceciestes
+ last_name: Untestes
+ email: ceciestuntestes@test.com
+ groups: "{{ keycloak_user_groups }}"
+ attributes: "{{ keycloak_user_attributes }}"
+ state: absent
+ register: delete_result
+
+- name: debug
+ debug:
+ var: delete_result
+
+- name: Assert user is deleted
+ assert:
+ that:
+ - delete_result.changed
+ - delete_result.end_state | length == 0
diff --git a/ansible_collections/community/general/tests/integration/targets/keycloak_user/vars/main.yml b/ansible_collections/community/general/tests/integration/targets/keycloak_user/vars/main.yml
new file mode 100644
index 000000000..9962aba54
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/keycloak_user/vars/main.yml
@@ -0,0 +1,46 @@
+---
+# Copyright (c) 2022, Dušan Marković (@bratwurzt)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+url: http://localhost:8080/auth
+admin_realm: master
+admin_user: admin
+admin_password: password
+realm: myrealm
+client_id: myclient
+role: myrole
+description_1: desc 1
+description_2: desc 2
+
+keycloak_username: test
+keycloak_service_account_client_id: "{{ client_id }}"
+keycloak_user_realm_roles:
+ - name: offline_access
+ - name: "{{ role }}"
+keycloak_client_role: test
+keycloak_user_client_roles:
+ - client_id: "{{ client_id }}"
+ roles:
+ - name: "{{ keycloak_client_role }}"
+ - client_id: "{{ realm }}-realm"
+ roles:
+ - name: view-users
+ - name: query-users
+keycloak_user_attributes:
+ - name: attr1
+ values:
+ - value1s
+ state: present
+ - name: attr2
+ values:
+ - value2s
+ state: present
+ - name: attr3
+ values:
+ - value3s
+ state: present
+keycloak_user_groups:
+ - name: test
+ state: present
+ - name: test2
diff --git a/ansible_collections/community/general/tests/integration/targets/ldap_search/tasks/tests/auth.yml b/ansible_collections/community/general/tests/integration/targets/ldap_search/tasks/tests/auth.yml
new file mode 100644
index 000000000..a8c7a13ee
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/ldap_search/tasks/tests/auth.yml
@@ -0,0 +1,47 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- debug:
+ msg: Running tests/auth.yml
+
+####################################################################
+## Search ##########################################################
+####################################################################
+- name: Test simple search for password authenticated user
+ ldap_search:
+ dn: "ou=users,dc=example,dc=com"
+ scope: "onelevel"
+ filter: "(uid=ldaptest)"
+ bind_dn: "uid=ldaptest,ou=users,dc=example,dc=com"
+ bind_pw: "test1pass!"
+ ignore_errors: true
+ register: output
+
+- name: assert that test LDAP user can read its password
+ assert:
+ that:
+ - output is not failed
+ - output.results | length == 1
+ - output.results.0.userPassword is defined
+
+- name: Test simple search for cert authenticated user
+ ldap_search:
+ dn: "ou=users,dc=example,dc=com"
+ server_uri: "ldap://localhost/"
+ start_tls: true
+ ca_path: /usr/local/share/ca-certificates/ca.crt
+ scope: "onelevel"
+ filter: "(uid=ldaptest)"
+ client_cert: "/root/user.crt"
+ client_key: "/root/user.key"
+ ignore_errors: true
+ register: output
+
+- name: assert that test LDAP user can read its password
+ assert:
+ that:
+ - output is not failed
+ - output.results | length == 1
+ - output.results.0.userPassword is defined
diff --git a/ansible_collections/community/general/tests/integration/targets/ldap_search/tasks/tests/basic.yml b/ansible_collections/community/general/tests/integration/targets/ldap_search/tasks/tests/basic.yml
index 36d245d39..11e5d6562 100644
--- a/ansible_collections/community/general/tests/integration/targets/ldap_search/tasks/tests/basic.yml
+++ b/ansible_collections/community/general/tests/integration/targets/ldap_search/tasks/tests/basic.yml
@@ -23,3 +23,17 @@
- output is not failed
- output.results | length == 1
- output.results.0.displayName == "LDAP Test"
+
+- name: Test simple search for a user with no results
+ ldap_search:
+ dn: "ou=users,dc=example,dc=com"
+ scope: "onelevel"
+ filter: "(uid=nonexistent)"
+ ignore_errors: true
+ register: output
+
+- name: assert that the output is empty
+ assert:
+ that:
+ - output is not failed
+ - output.results | length == 0
diff --git a/ansible_collections/community/general/tests/integration/targets/ldap_search/tasks/tests/pages.yml b/ansible_collections/community/general/tests/integration/targets/ldap_search/tasks/tests/pages.yml
new file mode 100644
index 000000000..32575854b
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/ldap_search/tasks/tests/pages.yml
@@ -0,0 +1,24 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- debug:
+ msg: Running tests/pages.yml
+
+####################################################################
+## Search ##########################################################
+####################################################################
+- name: Test paged search for all users
+ ldap_search:
+ dn: "ou=users,dc=example,dc=com"
+ scope: "onelevel"
+ page_size: 1
+ ignore_errors: true
+ register: output
+
+- name: assert that the right number of results are returned
+ assert:
+ that:
+ - output is not failed
+ - output.results | length == 2
diff --git a/ansible_collections/community/general/tests/integration/targets/ldap_search/tasks/tests/schema.yml b/ansible_collections/community/general/tests/integration/targets/ldap_search/tasks/tests/schema.yml
new file mode 100644
index 000000000..892eac3cb
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/ldap_search/tasks/tests/schema.yml
@@ -0,0 +1,25 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- debug:
+ msg: Running tests/schema.yml
+
+####################################################################
+## Search ##########################################################
+####################################################################
+- name: Test for ldap schema output
+ ldap_search:
+ dn: "ou=users,dc=example,dc=com"
+ scope: "onelevel"
+ schema: true
+ ignore_errors: true
+ register: output
+
+- name: Assert that the schema output is correct
+ assert:
+ that:
+ - output is not failed
+ - output.results | length >= 1
+ - "{{ 'displayName' in output.results.0.attrs }}"
diff --git a/ansible_collections/community/general/tests/integration/targets/listen_ports_facts/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/listen_ports_facts/tasks/main.yml
index 70649f505..0e583e7a1 100644
--- a/ansible_collections/community/general/tests/integration/targets/listen_ports_facts/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/listen_ports_facts/tasks/main.yml
@@ -13,7 +13,7 @@
ansible.builtin.package:
name:
- net-tools
- - netcat
+ - netcat-openbsd
state: latest
when: ansible_os_family == "Debian"
diff --git a/ansible_collections/community/general/tests/integration/targets/locale_gen/aliases b/ansible_collections/community/general/tests/integration/targets/locale_gen/aliases
index f7f4063f6..a5d3e27f9 100644
--- a/ansible_collections/community/general/tests/integration/targets/locale_gen/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/locale_gen/aliases
@@ -6,3 +6,5 @@ azp/posix/3
destructive
needs/root
skip/aix
+skip/freebsd
+skip/macos
diff --git a/ansible_collections/community/general/tests/integration/targets/locale_gen/tasks/basic.yml b/ansible_collections/community/general/tests/integration/targets/locale_gen/tasks/basic.yml
new file mode 100644
index 000000000..8718e0be8
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/locale_gen/tasks/basic.yml
@@ -0,0 +1,102 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Is the locale we're going to test against installed? {{ locale_basic.localegen }}
+ command: locale -a
+ register: initial_state
+ ignore_errors: true
+
+- name: Make sure the locale is not installed {{ locale_basic.localegen }}
+ locale_gen:
+ name: "{{ locale_basic.localegen }}"
+ state: absent
+
+- name: Is the locale present? {{ locale_basic.localegen }}
+ command: locale -a
+ register: cleaned
+ ignore_errors: true
+
+- name: Make sure the locale is not present {{ locale_basic.localegen }}
+ assert:
+ that:
+ - locale_basic.skip_removal or locale_basic.locales | intersect(cleaned.stdout_lines) == []
+
+- name: Install the locale {{ locale_basic.localegen }}
+ locale_gen:
+ name: "{{ locale_basic.localegen }}"
+ state: present
+ register: output_present
+
+- name: Is the locale present? {{ locale_basic.localegen }}
+ command: locale -a
+ register: post_check_output_present
+ ignore_errors: true
+
+- name: Make sure the locale is present and we say we installed it {{ locale_basic.localegen }}
+ assert:
+ that:
+ - locale_basic.locales | intersect(post_check_output_present.stdout_lines) != []
+ - locale_basic.skip_removal or output_present is changed
+
+- name: Install the locale a second time {{ locale_basic.localegen }}
+ locale_gen:
+ name: "{{ locale_basic.localegen }}"
+ state: present
+ register: output_present_idempotent
+
+- name: Is the locale present? {{ locale_basic.localegen }}
+ command: locale -a
+ register: post_check_output_present_idempotent
+ ignore_errors: true
+
+- name: Make sure the locale is present and we reported no change {{ locale_basic.localegen }}
+ assert:
+ that:
+ - locale_basic.locales | intersect(post_check_output_present_idempotent.stdout_lines) != []
+ - output_present_idempotent is not changed
+
+- name: Removals
+ when: locale_basic.skip_removal is false
+ block:
+ - name: Remove the locale {{ locale_basic.localegen }}
+ locale_gen:
+ name: "{{ locale_basic.localegen }}"
+ state: absent
+ register: output_absent
+
+ - name: Is the locale present? {{ locale_basic.localegen }}
+ command: locale -a
+ register: post_check_output_absent
+ ignore_errors: true
+
+ - name: Make sure the locale is absent and we reported a change {{ locale_basic.localegen }}
+ assert:
+ that:
+ - locale_basic.locales | intersect(post_check_output_absent.stdout_lines) == []
+ - output_absent is changed
+
+ - name: Remove the locale a second time {{ locale_basic.localegen }}
+ locale_gen:
+ name: "{{ locale_basic.localegen }}"
+ state: absent
+ register: output_absent_idempotent
+
+ - name: Is the locale present? {{ locale_basic.localegen }}
+ command: locale -a
+ register: post_check_output_absent_idempotent
+ ignore_errors: true
+
+ - name: Make sure the locale is absent and we reported no change {{ locale_basic.localegen }}
+ assert:
+ that:
+ - locale_basic.locales | intersect(post_check_output_absent_idempotent.stdout_lines) == []
+ - output_absent_idempotent is not changed
+
+# Cleanup
+- name: Reinstall the locale we tested against if it was initially installed {{ locale_basic.localegen }}
+ locale_gen:
+ name: "{{ locale_basic.localegen }}"
+ state: present
+ when: locale_basic.locales | intersect(initial_state.stdout_lines) != []
diff --git a/ansible_collections/community/general/tests/integration/targets/locale_gen/tasks/locale_gen.yml b/ansible_collections/community/general/tests/integration/targets/locale_gen/tasks/locale_gen.yml
deleted file mode 100644
index c6bdcc046..000000000
--- a/ansible_collections/community/general/tests/integration/targets/locale_gen/tasks/locale_gen.yml
+++ /dev/null
@@ -1,99 +0,0 @@
----
-# Copyright (c) Ansible Project
-# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
-# SPDX-License-Identifier: GPL-3.0-or-later
-
-- name: Is the locale we're going to test against installed?
- shell: locale -a | grep pt_BR
- register: initial_state
- ignore_errors: true
-
-- name: Make sure the locale is not installed
- locale_gen:
- name: pt_BR
- state: absent
-
-- name: Is the locale present?
- shell: locale -a | grep pt_BR
- register: cleaned
- ignore_errors: true
-
-- name: Make sure the locale is not present
- assert:
- that:
- - "cleaned.rc == 1"
-
-- name: Install the locale
- locale_gen:
- name: pt_BR
- state: present
- register: output
-
-- name: Is the locale present?
- shell: locale -a | grep pt_BR
- register: post_check_output
- ignore_errors: true
-
-- name: Make sure the locale is present and we say we installed it
- assert:
- that:
- - "post_check_output.rc == 0"
- - "output.changed"
-
-- name: Install the locale a second time
- locale_gen:
- name: pt_BR
- state: present
- register: output
-
-- name: Is the locale present?
- shell: locale -a | grep pt_BR
- register: post_check_output
- ignore_errors: true
-
-- name: Make sure the locale is present and we reported no change
- assert:
- that:
- - "post_check_output.rc == 0"
- - "not output.changed"
-
-- name: Remove the locale
- locale_gen:
- name: pt_BR
- state: absent
- register: output
-
-- name: Is the locale present?
- shell: locale -a | grep pt_BR
- register: post_check_output
- ignore_errors: true
-
-- name: Make sure the locale is absent and we reported a change
- assert:
- that:
- - "post_check_output.rc == 1"
- - "output.changed"
-
-- name: Remove the locale a second time
- locale_gen:
- name: pt_BR
- state: absent
- register: output
-
-- name: Is the locale present?
- shell: locale -a | grep pt_BR
- register: post_check_output
- ignore_errors: true
-
-- name: Make sure the locale is absent and we reported no change
- assert:
- that:
- - "post_check_output.rc == 1"
- - "not output.changed"
-
-# Cleanup
-- name: Reinstall the locale we tested against if it was initially installed
- locale_gen:
- name: pt_BR
- state: present
- when: initial_state.rc == 0
diff --git a/ansible_collections/community/general/tests/integration/targets/locale_gen/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/locale_gen/tasks/main.yml
index de3e673be..2d9dfcee0 100644
--- a/ansible_collections/community/general/tests/integration/targets/locale_gen/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/locale_gen/tasks/main.yml
@@ -8,5 +8,11 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
-- include_tasks: 'locale_gen.yml'
- when: ansible_distribution in ('Ubuntu', 'Debian')
+- name: Bail out if not supported
+ ansible.builtin.meta: end_play
+ when: ansible_distribution not in ('Ubuntu', 'Debian')
+
+- include_tasks: basic.yml
+ loop: "{{ locale_list_basic }}"
+ loop_control:
+ loop_var: locale_basic
diff --git a/ansible_collections/community/general/tests/integration/targets/locale_gen/vars/main.yml b/ansible_collections/community/general/tests/integration/targets/locale_gen/vars/main.yml
new file mode 100644
index 000000000..44327ddd3
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/locale_gen/vars/main.yml
@@ -0,0 +1,17 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# locale_basic: pt_BR
+
+locale_list_basic:
+ - localegen: pt_BR
+ locales: [pt_BR]
+ skip_removal: false
+ - localegen: C.UTF-8
+ locales: [C.utf8, C.UTF-8]
+ skip_removal: true
+ - localegen: eo
+ locales: [eo]
+ skip_removal: false
diff --git a/ansible_collections/community/general/tests/integration/targets/lookup_cartesian/aliases b/ansible_collections/community/general/tests/integration/targets/lookup_cartesian/aliases
index 2bdcc0113..5e6585203 100644
--- a/ansible_collections/community/general/tests/integration/targets/lookup_cartesian/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/lookup_cartesian/aliases
@@ -4,4 +4,3 @@
azp/posix/1
skip/aix
-skip/python2.6 # lookups are controller only, and we no longer support Python 2.6 on the controller
diff --git a/ansible_collections/community/general/tests/integration/targets/lookup_dependent/aliases b/ansible_collections/community/general/tests/integration/targets/lookup_dependent/aliases
index 26ad5c244..12d1d6617 100644
--- a/ansible_collections/community/general/tests/integration/targets/lookup_dependent/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/lookup_dependent/aliases
@@ -3,4 +3,3 @@
# SPDX-License-Identifier: GPL-3.0-or-later
azp/posix/2
-skip/python2.6 # lookups are controller only, and we no longer support Python 2.6 on the controller
diff --git a/ansible_collections/community/general/tests/integration/targets/lookup_dig/aliases b/ansible_collections/community/general/tests/integration/targets/lookup_dig/aliases
index eb449a9cf..afda346c4 100644
--- a/ansible_collections/community/general/tests/integration/targets/lookup_dig/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/lookup_dig/aliases
@@ -3,4 +3,3 @@
# SPDX-License-Identifier: GPL-3.0-or-later
azp/posix/1
-skip/python2.6 # lookups are controller only, and we no longer support Python 2.6 on the controller
diff --git a/ansible_collections/community/general/tests/integration/targets/lookup_etcd3/aliases b/ansible_collections/community/general/tests/integration/targets/lookup_etcd3/aliases
index b9f3395f7..de1f51cb5 100644
--- a/ansible_collections/community/general/tests/integration/targets/lookup_etcd3/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/lookup_etcd3/aliases
@@ -10,5 +10,4 @@ skip/aix
skip/osx
skip/macos
skip/freebsd
-skip/python2.6 # lookups are controller only, and we no longer support Python 2.6 on the controller
disabled # see https://github.com/ansible-collections/community.general/issues/322
diff --git a/ansible_collections/community/general/tests/integration/targets/lookup_flattened/aliases b/ansible_collections/community/general/tests/integration/targets/lookup_flattened/aliases
index 0ac9bad98..dadd9f37a 100644
--- a/ansible_collections/community/general/tests/integration/targets/lookup_flattened/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/lookup_flattened/aliases
@@ -4,4 +4,3 @@
azp/posix/2
skip/aix
-skip/python2.6 # lookups are controller only, and we no longer support Python 2.6 on the controller
diff --git a/ansible_collections/community/general/tests/integration/targets/lookup_lmdb_kv/aliases b/ansible_collections/community/general/tests/integration/targets/lookup_lmdb_kv/aliases
index 66632fb4a..9c7febe24 100644
--- a/ansible_collections/community/general/tests/integration/targets/lookup_lmdb_kv/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/lookup_lmdb_kv/aliases
@@ -5,4 +5,3 @@
azp/posix/2
destructive
skip/aix
-skip/python2.6 # lookups are controller only, and we no longer support Python 2.6 on the controller
diff --git a/ansible_collections/community/general/tests/integration/targets/lookup_merge_variables/aliases b/ansible_collections/community/general/tests/integration/targets/lookup_merge_variables/aliases
index eb449a9cf..afda346c4 100644
--- a/ansible_collections/community/general/tests/integration/targets/lookup_merge_variables/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/lookup_merge_variables/aliases
@@ -3,4 +3,3 @@
# SPDX-License-Identifier: GPL-3.0-or-later
azp/posix/1
-skip/python2.6 # lookups are controller only, and we no longer support Python 2.6 on the controller
diff --git a/ansible_collections/community/general/tests/integration/targets/lookup_merge_variables/runme.sh b/ansible_collections/community/general/tests/integration/targets/lookup_merge_variables/runme.sh
index 52a38f4a5..4e66476be 100755
--- a/ansible_collections/community/general/tests/integration/targets/lookup_merge_variables/runme.sh
+++ b/ansible_collections/community/general/tests/integration/targets/lookup_merge_variables/runme.sh
@@ -11,3 +11,6 @@ ANSIBLE_LOG_PATH=/tmp/ansible-test-merge-variables \
ANSIBLE_LOG_PATH=/tmp/ansible-test-merge-variables \
ANSIBLE_MERGE_VARIABLES_PATTERN_TYPE=suffix \
ansible-playbook test_with_env.yml "$@"
+
+ANSIBLE_LOG_PATH=/tmp/ansible-test-merge-variables \
+ ansible-playbook -i test_inventory_all_hosts.yml test_all_hosts.yml "$@"
diff --git a/ansible_collections/community/general/tests/integration/targets/lookup_merge_variables/test_all_hosts.yml b/ansible_collections/community/general/tests/integration/targets/lookup_merge_variables/test_all_hosts.yml
new file mode 100644
index 000000000..3070087bb
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/lookup_merge_variables/test_all_hosts.yml
@@ -0,0 +1,64 @@
+---
+# Copyright (c) 2020, Thales Netherlands
+# Copyright (c) 2021, Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Test merge_variables lookup plugin (multiple hosts)
+ hosts: host0
+ gather_facts: false
+ tasks:
+ - name: Test merge dicts via all group
+ delegate_to: localhost
+ vars:
+ merged_dict: "{{ lookup('community.general.merge_variables', '__merge_dict_ex', pattern_type='suffix', groups=['all']) }}"
+ block:
+ - name: Test merge dicts via all group - Print the merged dict
+ ansible.builtin.debug:
+ msg: "{{ merged_dict }}"
+
+ - name: Test merge dicts via all group - Validate that the dict is complete
+ ansible.builtin.assert:
+ that:
+ - "(merged_dict.keys() | list | length) == 4"
+ - "'item1' in merged_dict"
+ - "'item2' in merged_dict"
+ - "'item3' in merged_dict"
+ - "'list_item' in merged_dict"
+ - "merged_dict.list_item | length == 3"
+ - name: Test merge dicts via two of three groups
+ delegate_to: localhost
+ vars:
+ merged_dict: "{{ lookup('community.general.merge_variables', '__merge_dict_in', pattern_type='suffix', groups=['dummy1', 'dummy2']) }}"
+ block:
+ - name: Test merge dicts via two of three groups - Print the merged dict
+ ansible.builtin.debug:
+ msg: "{{ merged_dict }}"
+
+ - name: Test merge dicts via two of three groups - Validate that the dict is complete
+ ansible.builtin.assert:
+ that:
+ - "(merged_dict.keys() | list | length) == 3"
+ - "'item1' in merged_dict"
+ - "'item2' in merged_dict"
+ - "'list_item' in merged_dict"
+ - "merged_dict.list_item | length == 2"
+ - name: Test merge dicts via two of three groups with inital value
+ delegate_to: localhost
+ vars:
+ initial_dict:
+ initial: initial_value
+ merged_dict: "{{ lookup('community.general.merge_variables', '__merge_dict_in', initial_value=initial_dict, pattern_type='suffix', groups=['dummy1', 'dummy2']) }}"
+ block:
+ - name: Test merge dicts via two of three groups with inital value - Print the merged dict
+ ansible.builtin.debug:
+ msg: "{{ merged_dict }}"
+
+ - name: Test merge dicts via two of three groups with inital value - Validate that the dict is complete
+ ansible.builtin.assert:
+ that:
+ - "(merged_dict.keys() | list | length) == 4"
+ - "'item1' in merged_dict"
+ - "'item2' in merged_dict"
+ - "'list_item' in merged_dict"
+ - "merged_dict.list_item | length == 2"
diff --git a/ansible_collections/community/general/tests/integration/targets/lookup_merge_variables/test_inventory_all_hosts.yml b/ansible_collections/community/general/tests/integration/targets/lookup_merge_variables/test_inventory_all_hosts.yml
new file mode 100644
index 000000000..edf5a9e46
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/lookup_merge_variables/test_inventory_all_hosts.yml
@@ -0,0 +1,52 @@
+---
+# Copyright (c) 2020, Thales Netherlands
+# Copyright (c) 2021, Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+all:
+ hosts:
+ host0:
+ host1:
+ testdict1__merge_dict_ex:
+ item1: value1
+ list_item:
+ - test1
+
+ testdict2__merge_dict_ex:
+ item2: value2
+ list_item:
+ - test2
+
+ testdict__merge_dict_in:
+ item1: value1
+ list_item:
+ - test1
+ host2:
+ testdict3__merge_dict_ex:
+ item3: value3
+ list_item:
+ - test3
+
+ testdict__merge_dict_in:
+ item2: value2
+ list_item:
+ - test2
+
+ host3:
+ testdict__merge_dict_in:
+ item3: value3
+ list_item:
+ - test3
+
+dummy1:
+ hosts:
+ host1:
+
+dummy2:
+ hosts:
+ host2:
+
+dummy3:
+ hosts:
+ host3:
diff --git a/ansible_collections/community/general/tests/integration/targets/lookup_passwordstore/aliases b/ansible_collections/community/general/tests/integration/targets/lookup_passwordstore/aliases
index 0d4c5af3b..f02225028 100644
--- a/ansible_collections/community/general/tests/integration/targets/lookup_passwordstore/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/lookup_passwordstore/aliases
@@ -6,6 +6,5 @@ azp/posix/1
destructive
skip/aix
skip/rhel
-skip/python2.6 # lookups are controller only, and we no longer support Python 2.6 on the controller
skip/osx # FIXME https://github.com/ansible-collections/community.general/issues/2978
skip/macos # FIXME https://github.com/ansible-collections/community.general/issues/2978
diff --git a/ansible_collections/community/general/tests/integration/targets/lookup_random_pet/aliases b/ansible_collections/community/general/tests/integration/targets/lookup_random_pet/aliases
index 0ac9bad98..dadd9f37a 100644
--- a/ansible_collections/community/general/tests/integration/targets/lookup_random_pet/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/lookup_random_pet/aliases
@@ -4,4 +4,3 @@
azp/posix/2
skip/aix
-skip/python2.6 # lookups are controller only, and we no longer support Python 2.6 on the controller
diff --git a/ansible_collections/community/general/tests/integration/targets/lookup_random_string/aliases b/ansible_collections/community/general/tests/integration/targets/lookup_random_string/aliases
index 0ac9bad98..dadd9f37a 100644
--- a/ansible_collections/community/general/tests/integration/targets/lookup_random_string/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/lookup_random_string/aliases
@@ -4,4 +4,3 @@
azp/posix/2
skip/aix
-skip/python2.6 # lookups are controller only, and we no longer support Python 2.6 on the controller
diff --git a/ansible_collections/community/general/tests/integration/targets/lookup_random_words/aliases b/ansible_collections/community/general/tests/integration/targets/lookup_random_words/aliases
index 0ac9bad98..dadd9f37a 100644
--- a/ansible_collections/community/general/tests/integration/targets/lookup_random_words/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/lookup_random_words/aliases
@@ -4,4 +4,3 @@
azp/posix/2
skip/aix
-skip/python2.6 # lookups are controller only, and we no longer support Python 2.6 on the controller
diff --git a/ansible_collections/community/general/tests/integration/targets/lvg/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/lvg/tasks/main.yml
index e14c48c3f..15af2d08c 100644
--- a/ansible_collections/community/general/tests/integration/targets/lvg/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/lvg/tasks/main.yml
@@ -18,10 +18,20 @@
block:
- import_tasks: setup.yml
+ - import_tasks: setup_missing_pv.yml
+
- import_tasks: test_indempotency.yml
- import_tasks: test_grow_reduce.yml
- import_tasks: test_pvresize.yml
+
+ - import_tasks: test_active_change.yml
+
+ - import_tasks: test_active_create.yml
+
+ - import_tasks: test_uuid_reset.yml
always:
- import_tasks: teardown.yml
+
+ - import_tasks: teardown_missing_pv.yml
diff --git a/ansible_collections/community/general/tests/integration/targets/lvg/tasks/setup.yml b/ansible_collections/community/general/tests/integration/targets/lvg/tasks/setup.yml
index 3984b9fc3..45209c6a6 100644
--- a/ansible_collections/community/general/tests/integration/targets/lvg/tasks/setup.yml
+++ b/ansible_collections/community/general/tests/integration/targets/lvg/tasks/setup.yml
@@ -4,8 +4,8 @@
# SPDX-License-Identifier: GPL-3.0-or-later
- name: "Create files to use as a disk devices"
- command: "dd if=/dev/zero of={{ remote_tmp_dir }}/img{{ item }} bs=1M count=10"
- with_sequence: 'count=2'
+ command: "dd if=/dev/zero of={{ remote_tmp_dir }}/img{{ item }} bs=1M count=36"
+ with_sequence: 'count=4'
- name: "Show next free loop device"
command: "losetup -f"
@@ -21,7 +21,23 @@
- name: "Create loop device for file"
command: "losetup -f {{ remote_tmp_dir }}/img2"
+- name: "Show next free loop device"
+ command: "losetup -f"
+ register: loop_device3
+
+- name: "Create loop device for file"
+ command: "losetup -f {{ remote_tmp_dir }}/img3"
+
+- name: "Show next free loop device"
+ command: "losetup -f"
+ register: loop_device4
+
+- name: "Create loop device for file"
+ command: "losetup -f {{ remote_tmp_dir }}/img4"
+
- name: "Affect name on disk to work on"
set_fact:
loop_device1: "{{ loop_device1.stdout }}"
loop_device2: "{{ loop_device2.stdout }}"
+ loop_device3: "{{ loop_device3.stdout }}"
+ loop_device4: "{{ loop_device4.stdout }}"
diff --git a/ansible_collections/community/general/tests/integration/targets/lvg/tasks/setup_missing_pv.yml b/ansible_collections/community/general/tests/integration/targets/lvg/tasks/setup_missing_pv.yml
new file mode 100644
index 000000000..863ef8757
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/lvg/tasks/setup_missing_pv.yml
@@ -0,0 +1,18 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: "Prepare VG for missing PV"
+ lvg:
+ vg: vg_with_missing_pv
+ pvs:
+ - "{{ loop_device3 }}"
+ - "{{ loop_device4 }}"
+
+- name: Save loop_device4 pvid
+ shell: "pvs -ouuid --noheadings {{ loop_device4 }} | xargs -n1 | tr -d '-'"
+ register: loop_device4_pvid_result
+
+- name: Detach loop_device4
+ command: "losetup -d {{ loop_device4 }}"
diff --git a/ansible_collections/community/general/tests/integration/targets/lvg/tasks/teardown.yml b/ansible_collections/community/general/tests/integration/targets/lvg/tasks/teardown.yml
index de4957321..2d147dee0 100644
--- a/ansible_collections/community/general/tests/integration/targets/lvg/tasks/teardown.yml
+++ b/ansible_collections/community/general/tests/integration/targets/lvg/tasks/teardown.yml
@@ -6,13 +6,25 @@
- name: Remove test volume group
lvg:
vg: testvg
+ force: true
state: absent
+- name: Remove LVM devices
+ loop:
+ - "{{ loop_device1 | default('') }}"
+ - "{{ loop_device2 | default('') }}"
+ - "{{ loop_device3 | default('') }}"
+ when:
+ - item|length > 0
+ command: "lvmdevices --deldev {{ item }}"
+ ignore_errors: true
+
- name: Detach loop devices
command: "losetup -d {{ item }}"
loop:
- "{{ loop_device1 | default('') }}"
- "{{ loop_device2 | default('') }}"
+ - "{{ loop_device3 | default('') }}"
when:
- item != ''
@@ -20,4 +32,4 @@
file:
path: "{{ remote_tmp_dir }}/img{{ item }}"
state: absent
- with_sequence: 'count=2'
+ with_sequence: 'count=4'
diff --git a/ansible_collections/community/general/tests/integration/targets/lvg/tasks/teardown_missing_pv.yml b/ansible_collections/community/general/tests/integration/targets/lvg/tasks/teardown_missing_pv.yml
new file mode 100644
index 000000000..4cff68003
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/lvg/tasks/teardown_missing_pv.yml
@@ -0,0 +1,8 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Remove loop_device4 LVM device
+ command: "lvmdevices --delpvid {{ loop_device4_pvid_result.stdout }}"
+ ignore_errors: true
diff --git a/ansible_collections/community/general/tests/integration/targets/lvg/tasks/test_active_change.yml b/ansible_collections/community/general/tests/integration/targets/lvg/tasks/test_active_change.yml
new file mode 100644
index 000000000..7df52683f
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/lvg/tasks/test_active_change.yml
@@ -0,0 +1,163 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Create volume group on disk device
+ lvg:
+ vg: testvg
+ pvs: "{{ loop_device1 }}"
+
+- name: Create logical volumes on volume group
+ loop:
+ - lv1
+ - lv2
+ lvol:
+ vg: testvg
+ lv: "{{ item }}"
+ size: 2m
+
+- name: Create snapshot volumes of origin logical volumes
+ loop:
+ - lv1
+ - lv2
+ lvol:
+ vg: testvg
+ lv: "{{ item }}"
+ snapshot: "{{ item }}_snap"
+ size: 50%ORIGIN
+
+- name: Collect all lv active status in testvg
+ shell: vgs -olv_active --noheadings testvg | xargs -n1
+ register: initial_lv_status_result
+
+- name: Assert all lv in testvg are active
+ loop: "{{ initial_lv_status_result.stdout_lines }}"
+ assert:
+ that:
+ - "'active' == item"
+
+- name: Deactivate volume group
+ lvg:
+ state: inactive
+ vg: testvg
+ register: vg_deactivate_result
+
+- name: Collect all lv active status in testvg
+ shell: vgs -olv_active --noheadings testvg | xargs -n1
+ register: deactivated_lv_status_result
+
+- name: Do all assertions to verify expected results
+ assert:
+ that:
+ - vg_deactivate_result is changed
+ - "'active' not in deactivated_lv_status_result.stdout"
+
+- name: Deactivate volume group again to verify idempotence
+ lvg:
+ state: inactive
+ vg: testvg
+ register: repeated_vg_deactivate_result
+
+- name: Verify vg deactivation idempontency
+ assert:
+ that:
+ - repeated_vg_deactivate_result is not changed
+
+- name: Activate volume group in check mode
+ lvg:
+ state: active
+ vg: testvg
+ register: check_mode_vg_activate_result
+ check_mode: true
+
+- name: Collect all lv active status in testvg
+ shell: vgs -olv_active --noheadings testvg | xargs -n1
+ register: check_mode_activate_lv_status_result
+
+- name: Verify VG activation in check mode changed without activating LVs
+ assert:
+ that:
+ - check_mode_vg_activate_result is changed
+ - "'active' not in check_mode_activate_lv_status_result.stdout"
+
+- name: Activate volume group
+ lvg:
+ state: active
+ vg: testvg
+ register: vg_activate_result
+
+- name: Collect all lv active status in testvg
+ shell: vgs -olv_active --noheadings testvg | xargs -n1
+ register: activate_lv_status_result
+
+- name: Verify vg activation
+ assert:
+ that:
+ - vg_activate_result is changed
+
+- name: Assert all lv in testvg are active
+ loop: "{{ activate_lv_status_result.stdout_lines }}"
+ assert:
+ that:
+ - "'active' == item"
+
+- name: Activate volume group again to verify idempontency
+ lvg:
+ state: active
+ vg: testvg
+ register: repeated_vg_activate_result
+
+- name: Verify vg activation idempontency
+ assert:
+ that:
+ - repeated_vg_activate_result is not changed
+
+- name: Deactivate lv2 in testvg
+ lvol:
+ vg: testvg
+ lv: lv2
+ active: false
+
+- name: Activate volume group again to verify partially activated vg activation
+ lvg:
+ state: active
+ vg: testvg
+ register: partial_vg_activate_result
+
+- name: Verify partially activated vg activation
+ assert:
+ that:
+ - partial_vg_activate_result is changed
+
+- name: Collect all lv active status in testvg
+ shell: vgs -olv_active --noheadings testvg | xargs -n1
+ register: activate_partial_lv_status_result
+
+- name: Assert all lv in testvg are active
+ loop: "{{ activate_partial_lv_status_result.stdout_lines }}"
+ assert:
+ that:
+ - "'active' == item"
+
+- name: Deactivate volume group in check mode
+ lvg:
+ state: inactive
+ vg: testvg
+ register: check_mode_vg_deactivate_result
+ check_mode: true
+
+- name: Collect all lv active status in testvg
+ shell: vgs -olv_active --noheadings testvg | xargs -n1
+ register: check_mode_deactivate_lv_status_result
+
+- name: Verify check mode vg deactivation changed
+ assert:
+ that:
+ - check_mode_vg_deactivate_result is changed
+
+- name: Assert all lv in testvg are still active
+ loop: "{{ check_mode_deactivate_lv_status_result.stdout_lines }}"
+ assert:
+ that:
+ - "'active' == item"
diff --git a/ansible_collections/community/general/tests/integration/targets/lvg/tasks/test_active_create.yml b/ansible_collections/community/general/tests/integration/targets/lvg/tasks/test_active_create.yml
new file mode 100644
index 000000000..7ac1ffedd
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/lvg/tasks/test_active_create.yml
@@ -0,0 +1,71 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Collect vgcreate help
+ command: "vgcreate --help"
+ register: vgcreate_help_result
+
+- when: "'--setautoactivation' in vgcreate_help_result.stdout"
+ block:
+ - name: Create autoactivated volume group on disk device
+ lvg:
+ state: active
+ vg: vg_autoact_test
+ pvs: "{{ loop_device2 }}"
+
+ - name: Collect vg autoactivation status for vg_autoact_test
+ shell: vgs -oautoactivation --noheadings vg_autoact_test | xargs -n1
+ register: active_vg_autoact_status_result
+
+ - name: Assert vg autoactivation is set for vg_autoact_test
+ assert:
+ that: "'enabled' == active_vg_autoact_status_result.stdout"
+
+ - name: Remove vg_autoact_test for the next test
+ lvg:
+ state: absent
+ vg: vg_autoact_test
+ force: true
+
+ - name: Create auttoactivation disabled volume group on disk device
+ lvg:
+ state: inactive
+ vg: vg_autoact_test
+ pvs: "{{ loop_device2 }}"
+
+ - name: Collect vg autoactivation status for vg_autoact_test
+ shell: vgs -oautoactivation --noheadings vg_autoact_test | xargs -n1
+ register: inactive_vg_autoact_status_result
+
+ - name: Assert vg autoactivation disabled for vg_autoact_test
+ assert:
+ that: "inactive_vg_autoact_status_result.stdout | length == 0"
+
+ - name: Remove vg_autoact_test for the next test
+ lvg:
+ state: absent
+ vg: vg_autoact_test
+ force: true
+
+ - name: Create auttoactivation disabled by option volume group on disk device
+ lvg:
+ state: active
+ vg: vg_autoact_test
+ vg_options: "--setautoactivation n"
+ pvs: "{{ loop_device2 }}"
+
+ - name: Collect vg autoactivation status for vg_autoact_test
+ shell: vgs -oautoactivation --noheadings vg_autoact_test | xargs -n1
+ register: inactive_by_option_vg_autoact_status_result
+
+ - name: Assert vg autoactivation disabled by option for vg_autoact_test
+ assert:
+ that: "inactive_by_option_vg_autoact_status_result.stdout | length == 0"
+ always:
+ - name: Cleanup vg_autoact_test
+ lvg:
+ state: absent
+ vg: vg_autoact_test
+ force: true
diff --git a/ansible_collections/community/general/tests/integration/targets/lvg/tasks/test_pvresize.yml b/ansible_collections/community/general/tests/integration/targets/lvg/tasks/test_pvresize.yml
index f15add91c..3f3b9dbdd 100644
--- a/ansible_collections/community/general/tests/integration/targets/lvg/tasks/test_pvresize.yml
+++ b/ansible_collections/community/general/tests/integration/targets/lvg/tasks/test_pvresize.yml
@@ -12,10 +12,10 @@
shell: vgs -v testvg -o pv_size --noheading --units b | xargs
register: cmd_result
-- name: Assert the testvg size is 8388608B
+- name: Assert the testvg size is 33554432B
assert:
that:
- - "'8388608B' == cmd_result.stdout"
+ - "'33554432B' == cmd_result.stdout"
- name: Increases size in file
command: "dd if=/dev/zero bs=8MiB count=1 of={{ remote_tmp_dir }}/img1 conv=notrunc oflag=append"
@@ -38,10 +38,10 @@
shell: vgs -v testvg -o pv_size --noheading --units b | xargs
register: cmd_result
-- name: Assert the testvg size is still 8388608B
+- name: Assert the testvg size is still 33554432B
assert:
that:
- - "'8388608B' == cmd_result.stdout"
+ - "'33554432B' == cmd_result.stdout"
- name: "Reruns lvg with pvresize:yes and check_mode:yes"
lvg:
@@ -60,10 +60,10 @@
shell: vgs -v testvg -o pv_size --noheading --units b | xargs
register: cmd_result
-- name: Assert the testvg size is still 8388608B
+- name: Assert the testvg size is still 33554432B
assert:
that:
- - "'8388608B' == cmd_result.stdout"
+ - "'33554432B' == cmd_result.stdout"
- name: "Reruns lvg with pvresize:yes"
lvg:
@@ -75,7 +75,7 @@
shell: vgs -v testvg -o pv_size --noheading --units b | xargs
register: cmd_result
-- name: Assert the testvg size is now 16777216B
+- name: Assert the testvg size is now 41943040B
assert:
that:
- - "'16777216B' == cmd_result.stdout"
+ - "'41943040B' == cmd_result.stdout"
diff --git a/ansible_collections/community/general/tests/integration/targets/lvg/tasks/test_uuid_reset.yml b/ansible_collections/community/general/tests/integration/targets/lvg/tasks/test_uuid_reset.yml
new file mode 100644
index 000000000..8de50ace5
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/lvg/tasks/test_uuid_reset.yml
@@ -0,0 +1,107 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Create volume group on disk device
+ lvg:
+ vg: testvg
+ pvs: "{{ loop_device1 }}"
+
+- name: Save testvg uuid
+ shell: vgs -ouuid --noheadings testvg | xargs -n1
+ register: orig_vg_uuid_cmd_result
+
+- name: Save pv uuid
+ shell: "pvs -ouuid --noheadings {{ loop_device1 }} | xargs -n1"
+ register: orig_pv_uuid_cmd_result
+
+- name: Deactivate and reset vg/pv uuid
+ lvg:
+ state: inactive
+ vg: testvg
+ pvs: "{{ loop_device1 }}"
+ reset_vg_uuid: true
+ reset_pv_uuid: true
+ register: vg_uuid_reset
+
+- name: Save testvg uuid
+ shell: vgs -ouuid --noheadings testvg | xargs -n1
+ register: new_vg_uuid_cmd_result
+
+- name: Save pv uuid
+ shell: "pvs -ouuid --noheadings {{ loop_device1 }} | xargs -n1"
+ register: new_pv_uuid_cmd_result
+
+- name: Do all assertions to verify expected results
+ assert:
+ that:
+ - vg_uuid_reset is changed
+ - orig_vg_uuid_cmd_result.stdout != new_vg_uuid_cmd_result.stdout
+ - orig_pv_uuid_cmd_result.stdout != new_pv_uuid_cmd_result.stdout
+
+- name: Reset vg uuid again to verify non-idempotence
+ lvg:
+ vg: testvg
+ reset_vg_uuid: true
+ register: repeat_vg_uuid_reset
+
+- name: Reset pv uuid again to verify non-idempotence
+ lvg:
+ vg: testvg
+ reset_pv_uuid: true
+ pvs: "{{ loop_device1 }}"
+ register: repeat_pv_uuid_reset
+
+- name: Save testvg uuid
+ shell: vgs -ouuid --noheadings testvg | xargs -n1
+ register: repeat_vg_uuid_cmd_result
+
+- name: Save pv uuid
+ shell: "pvs -ouuid --noheadings {{ loop_device1 }} | xargs -n1"
+ register: repeat_pv_uuid_cmd_result
+
+- name: Do all assertions to verify expected results
+ assert:
+ that:
+ - repeat_vg_uuid_reset is changed
+ - repeat_pv_uuid_reset is changed
+ - new_vg_uuid_cmd_result.stdout != repeat_vg_uuid_cmd_result.stdout
+ - new_pv_uuid_cmd_result.stdout != repeat_pv_uuid_cmd_result.stdout
+
+- name: Reset vg uuid in check mode
+ lvg:
+ vg: testvg
+ reset_vg_uuid: true
+ register: check_mode_vg_uuid_reset
+ check_mode: true
+
+- name: Reset pv uuid in check mode
+ lvg:
+ vg: testvg
+ reset_pv_uuid: true
+ pvs: "{{ loop_device1 }}"
+ register: check_mode_pv_uuid_reset
+ check_mode: true
+
+- name: Save testvg uuid
+ shell: vgs -ouuid --noheadings testvg | xargs -n1
+ register: check_mode_vg_uuid_cmd_result
+
+- name: Save pv uuid
+ shell: "pvs -ouuid --noheadings {{ loop_device1 }} | xargs -n1"
+ register: check_mode_pv_uuid_cmd_result
+
+- name: Do all assertions to verify expected results
+ assert:
+ that:
+ - check_mode_vg_uuid_reset is changed
+ - check_mode_pv_uuid_reset is changed
+ - check_mode_vg_uuid_cmd_result.stdout == repeat_vg_uuid_cmd_result.stdout
+ - check_mode_pv_uuid_cmd_result.stdout == repeat_pv_uuid_cmd_result.stdout
+
+- name: Activate volume group
+ lvg:
+ state: active
+ vg: testvg
+ register: vg_activate
diff --git a/ansible_collections/community/general/tests/integration/targets/lvg_rename/aliases b/ansible_collections/community/general/tests/integration/targets/lvg_rename/aliases
new file mode 100644
index 000000000..64d439099
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/lvg_rename/aliases
@@ -0,0 +1,13 @@
+# Copyright (c) Contributors to the Ansible project
+# Based on the integraton test for the lvg module
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+azp/posix/1
+azp/posix/vm
+destructive
+needs/privileged
+skip/aix
+skip/freebsd
+skip/osx
+skip/macos
diff --git a/ansible_collections/community/general/tests/integration/targets/lvg_rename/meta/main.yml b/ansible_collections/community/general/tests/integration/targets/lvg_rename/meta/main.yml
new file mode 100644
index 000000000..90c5d5cb8
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/lvg_rename/meta/main.yml
@@ -0,0 +1,9 @@
+---
+# Copyright (c) Ansible Project
+# Based on the integraton test for the lvg module
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+dependencies:
+ - setup_pkg_mgr
+ - setup_remote_tmp_dir
diff --git a/ansible_collections/community/general/tests/integration/targets/lvg_rename/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/lvg_rename/tasks/main.yml
new file mode 100644
index 000000000..18dd6f1ba
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/lvg_rename/tasks/main.yml
@@ -0,0 +1,25 @@
+---
+####################################################################
+# WARNING: These are designed specifically for Ansible tests #
+# and should not be used as examples of how to write Ansible roles #
+####################################################################
+
+# Copyright (c) Contributors to the Ansible project
+# Based on the integraton test for the lvg module
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Install required packages (Linux)
+ when: ansible_system == 'Linux'
+ ansible.builtin.package:
+ name: lvm2
+ state: present
+
+- name: Test lvg_rename module
+ block:
+ - import_tasks: setup.yml
+
+ - import_tasks: test.yml
+
+ always:
+ - import_tasks: teardown.yml
diff --git a/ansible_collections/community/general/tests/integration/targets/lvg_rename/tasks/setup.yml b/ansible_collections/community/general/tests/integration/targets/lvg_rename/tasks/setup.yml
new file mode 100644
index 000000000..01721e42d
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/lvg_rename/tasks/setup.yml
@@ -0,0 +1,50 @@
+---
+# Copyright (c) Contributors to the Ansible project
+# Based on the integraton test for the lvg module
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Create files to use as disk devices
+ with_sequence: 'count=2'
+ ansible.builtin.command:
+ cmd: "dd if=/dev/zero of={{ remote_tmp_dir }}/img{{ item }} bs=1M count=10"
+ creates: "{{ remote_tmp_dir }}/img{{ item }}"
+
+- name: Show next free loop device
+ ansible.builtin.command:
+ cmd: "losetup -f"
+ changed_when: false
+ register: loop_device1
+
+- name: "Create loop device for file {{ remote_tmp_dir }}/img1"
+ ansible.builtin.command:
+ cmd: "losetup -f {{ remote_tmp_dir }}/img1"
+ changed_when: true
+
+- name: Show next free loop device
+ ansible.builtin.command:
+ cmd: "losetup -f"
+ changed_when: false
+ register: loop_device2
+
+- name: "Create loop device for file {{ remote_tmp_dir }}/img2"
+ ansible.builtin.command:
+ cmd: "losetup -f {{ remote_tmp_dir }}/img2"
+ changed_when: true
+
+- name: Affect name on disk to work on
+ ansible.builtin.set_fact:
+ loop_device1: "{{ loop_device1.stdout }}"
+ loop_device2: "{{ loop_device2.stdout }}"
+
+- name: "Create test volume group testvg on {{ loop_device1 }}"
+ community.general.lvg:
+ vg: "testvg"
+ state: present
+ pvs: "{{ loop_device1 }}"
+
+- name: "Create test volume group testvg2 on {{ loop_device2 }}"
+ community.general.lvg:
+ vg: "testvg2"
+ state: present
+ pvs: "{{ loop_device2 }}"
diff --git a/ansible_collections/community/general/tests/integration/targets/lvg_rename/tasks/teardown.yml b/ansible_collections/community/general/tests/integration/targets/lvg_rename/tasks/teardown.yml
new file mode 100644
index 000000000..71c33d56d
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/lvg_rename/tasks/teardown.yml
@@ -0,0 +1,46 @@
+---
+# Copyright (c) Contributors to the Ansible project
+# Based on the integraton test for the lvg module
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Collect test volume groups
+ ansible.builtin.command:
+ cmd: "pvs --noheadings -ovg_name {{ loop_device1 | default('') }} {{ loop_device2 | default('') }}"
+ register: test_vgs_output
+ changed_when: false
+
+- name: Remove test volume groups
+ loop: "{{ test_vgs_output.stdout_lines }}"
+ loop_control:
+ label: "{{ item | trim }}"
+ community.general.lvg:
+ vg: "{{ item | trim }}"
+ state: absent
+
+- name: Remove lvmdevices
+ loop:
+ - "{{ loop_device1 | default('') }}"
+ - "{{ loop_device2 | default('') }}"
+ when:
+ - item | length > 0
+ ansible.builtin.command:
+ cmd: "lvmdevices --deldev {{ item }}"
+ failed_when: false
+ changed_when: true
+
+- name: Detach loop devices
+ loop:
+ - "{{ loop_device1 | default('') }}"
+ - "{{ loop_device2 | default('') }}"
+ when:
+ - item | length > 0
+ ansible.builtin.command:
+ cmd: "losetup -d {{ item }}"
+ changed_when: true
+
+- name: Remove device files
+ with_sequence: 'count=2'
+ ansible.builtin.file:
+ path: "{{ remote_tmp_dir }}/img{{ item }}"
+ state: absent
diff --git a/ansible_collections/community/general/tests/integration/targets/lvg_rename/tasks/test.yml b/ansible_collections/community/general/tests/integration/targets/lvg_rename/tasks/test.yml
new file mode 100644
index 000000000..ab62b679b
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/lvg_rename/tasks/test.yml
@@ -0,0 +1,105 @@
+---
+# Copyright (c) Contributors to the Ansible project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Rename a VG in check mode
+ community.general.lvg_rename:
+ vg: testvg
+ vg_new: testvg_renamed
+ check_mode: true
+ register: check_mode_vg_rename
+
+- name: Check if testvg still exists
+ ansible.builtin.command:
+ cmd: vgs testvg
+ changed_when: false
+
+- name: Assert that renaming a VG is changed - check mode
+ assert:
+ that:
+ - check_mode_vg_rename is changed
+
+- name: Rename testvg to testvg_renamed
+ community.general.lvg_rename:
+ vg: testvg
+ vg_new: testvg_renamed
+ register: vg_renamed
+
+- name: Assert that renaming a VG is changed
+ assert:
+ that:
+ - vg_renamed is changed
+
+- name: Check if testvg does not exists
+ ansible.builtin.command:
+ cmd: vgs testvg
+ register: check_testvg_existence_result
+ failed_when: check_testvg_existence_result.rc == 0
+ changed_when: false
+
+- name: Check if testvg_renamed exists
+ ansible.builtin.command:
+ cmd: vgs testvg_renamed
+ changed_when: false
+
+- name: Rename testvg to testvg_renamed again for testing idempotency - check mode
+ community.general.lvg_rename:
+ vg: testvg
+ vg_new: testvg_renamed
+ check_mode: true
+ register: check_mode_vg_renamed_again
+
+- name: Rename testvg to testvg_renamed again for testing idempotency
+ community.general.lvg_rename:
+ vg: testvg
+ vg_new: testvg_renamed
+ register: vg_renamed_again
+
+- name: Assert that renaming a VG again is not changed
+ assert:
+ that:
+ - check_mode_vg_renamed_again is not changed
+ - vg_renamed_again is not changed
+
+- name: Rename a non-existing VG - check mode
+ community.general.lvg_rename:
+ vg: testvg
+ vg_new: testvg_ne
+ check_mode: true
+ ignore_errors: true
+ register: check_mode_ne_vg_rename
+
+- name: Rename a non-existing VG
+ community.general.lvg_rename:
+ vg: testvg
+ vg_new: testvg_ne
+ ignore_errors: true
+ register: ne_vg_rename
+
+- name: Assert that renaming a no-existing VG failed
+ assert:
+ that:
+ - check_mode_ne_vg_rename is failed
+ - ne_vg_rename is failed
+
+- name: Rename testvg_renamed to the existing testvg2 name - check mode
+ community.general.lvg_rename:
+ vg: testvg_renamed
+ vg_new: testvg2
+ check_mode: true
+ ignore_errors: true
+ register: check_mode_vg_rename_collision
+
+- name: Rename testvg_renamed to the existing testvg2 name
+ community.general.lvg_rename:
+ vg: testvg_renamed
+ vg_new: testvg2
+ ignore_errors: true
+ register: vg_rename_collision
+
+- name: Assert that renaming to an existing VG name failed
+ assert:
+ that:
+ - check_mode_vg_rename_collision is failed
+ - vg_rename_collision is failed
diff --git a/ansible_collections/community/general/tests/integration/targets/lvol/aliases b/ansible_collections/community/general/tests/integration/targets/lvol/aliases
new file mode 100644
index 000000000..3b92ba75c
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/lvol/aliases
@@ -0,0 +1,12 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+azp/posix/1
+azp/posix/vm
+destructive
+needs/privileged
+skip/aix
+skip/freebsd
+skip/osx
+skip/macos
diff --git a/ansible_collections/community/general/tests/integration/targets/lvol/meta/main.yml b/ansible_collections/community/general/tests/integration/targets/lvol/meta/main.yml
new file mode 100644
index 000000000..ca1915e05
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/lvol/meta/main.yml
@@ -0,0 +1,8 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+dependencies:
+ - setup_pkg_mgr
+ - setup_remote_tmp_dir
diff --git a/ansible_collections/community/general/tests/integration/targets/lvol/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/lvol/tasks/main.yml
new file mode 100644
index 000000000..0e3bfa1a3
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/lvol/tasks/main.yml
@@ -0,0 +1,24 @@
+---
+####################################################################
+# WARNING: These are designed specifically for Ansible tests #
+# and should not be used as examples of how to write Ansible roles #
+####################################################################
+
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Install required packages (Linux)
+ package:
+ name: lvm2
+ state: present
+ when: ansible_system == 'Linux'
+
+- name: Test lvol module
+ block:
+ - import_tasks: setup.yml
+
+ - import_tasks: test_pvs.yml
+
+ always:
+ - import_tasks: teardown.yml
diff --git a/ansible_collections/community/general/tests/integration/targets/lvol/tasks/setup.yml b/ansible_collections/community/general/tests/integration/targets/lvol/tasks/setup.yml
new file mode 100644
index 000000000..195c50111
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/lvol/tasks/setup.yml
@@ -0,0 +1,57 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: "Create files to use as a disk devices"
+ command: "dd if=/dev/zero of={{ remote_tmp_dir }}/img{{ item }} bs=1M count=36"
+ with_sequence: 'count=4'
+
+- name: "Show next free loop device"
+ command: "losetup -f"
+ register: loop_device1
+
+- name: "Create loop device for file"
+ command: "losetup -f {{ remote_tmp_dir }}/img1"
+
+- name: "Show next free loop device"
+ command: "losetup -f"
+ register: loop_device2
+
+- name: "Create loop device for file"
+ command: "losetup -f {{ remote_tmp_dir }}/img2"
+
+- name: "Show next free loop device"
+ command: "losetup -f"
+ register: loop_device3
+
+- name: "Create loop device for file"
+ command: "losetup -f {{ remote_tmp_dir }}/img3"
+
+- name: "Show next free loop device"
+ command: "losetup -f"
+ register: loop_device4
+
+- name: "Create loop device for file"
+ command: "losetup -f {{ remote_tmp_dir }}/img4"
+
+- name: "Set loop device names"
+ set_fact:
+ loop_device1: "{{ loop_device1.stdout }}"
+ loop_device2: "{{ loop_device2.stdout }}"
+ loop_device3: "{{ loop_device3.stdout }}"
+ loop_device4: "{{ loop_device4.stdout }}"
+
+- name: Create testvg1 volume group on disk devices
+ lvg:
+ vg: testvg1
+ pvs:
+ - "{{ loop_device1 }}"
+ - "{{ loop_device2 }}"
+
+- name: Create testvg2 volume group on disk devices
+ lvg:
+ vg: testvg2
+ pvs:
+ - "{{ loop_device3 }}"
+ - "{{ loop_device4 }}"
diff --git a/ansible_collections/community/general/tests/integration/targets/lvol/tasks/teardown.yml b/ansible_collections/community/general/tests/integration/targets/lvol/tasks/teardown.yml
new file mode 100644
index 000000000..a8080f874
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/lvol/tasks/teardown.yml
@@ -0,0 +1,40 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Remove test volume groups
+ loop:
+ - testvg1
+ - testvg2
+ lvg:
+ vg: "{{ item }}"
+ force: true
+ state: absent
+
+- name: Remove LVM devices
+ loop:
+ - "{{ loop_device1 | default('') }}"
+ - "{{ loop_device2 | default('') }}"
+ - "{{ loop_device3 | default('') }}"
+ - "{{ loop_device4 | default('') }}"
+ when:
+ - item|length > 0
+ command: "lvmdevices --deldev {{ item }}"
+ ignore_errors: true
+
+- name: Detach loop devices
+ command: "losetup -d {{ item }}"
+ loop:
+ - "{{ loop_device1 | default('') }}"
+ - "{{ loop_device2 | default('') }}"
+ - "{{ loop_device3 | default('') }}"
+ - "{{ loop_device4 | default('') }}"
+ when:
+ - item != ''
+
+- name: Remove device files
+ file:
+ path: "{{ remote_tmp_dir }}/img{{ item }}"
+ state: absent
+ with_sequence: 'count=4'
diff --git a/ansible_collections/community/general/tests/integration/targets/lvol/tasks/test_pvs.yml b/ansible_collections/community/general/tests/integration/targets/lvol/tasks/test_pvs.yml
new file mode 100644
index 000000000..c1cd3d1a8
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/lvol/tasks/test_pvs.yml
@@ -0,0 +1,64 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Create logical volume (testlv1) with pvs set as comma separated string
+ lvol:
+ vg: testvg1
+ lv: testlv1
+ size: 50%PVS
+ pvs: "{{ loop_device1 }},{{ loop_device2 }}"
+ register: css_pvs_create_testlv1_result
+
+- name: Assert logical volume (testlv1) created with pvs set as comma separated string
+ assert:
+ that:
+ - css_pvs_create_testlv1_result is success
+ - css_pvs_create_testlv1_result is changed
+
+- name: Create logical volume (testlv1) with pvs set as list
+ lvol:
+ vg: testvg1
+ lv: testlv1
+ size: 50%PVS
+ pvs:
+ - "{{ loop_device1 }}"
+ - "{{ loop_device2 }}"
+ register: list_pvs_create_testlv1_result
+
+- name: Assert logical volume (testlv1) creation idempotency with pvs set as list on second execution
+ assert:
+ that:
+ - list_pvs_create_testlv1_result is success
+ - list_pvs_create_testlv1_result is not changed
+
+- name: Create logical volume (testlv2) with pvs set as list
+ lvol:
+ vg: testvg2
+ lv: testlv2
+ size: 50%PVS
+ pvs:
+ - "{{ loop_device3 }}"
+ - "{{ loop_device4 }}"
+ register: list_pvs_create_testlv2_result
+
+- name: Assert logical volume (testlv2) created with pvs set as list
+ assert:
+ that:
+ - list_pvs_create_testlv2_result is success
+ - list_pvs_create_testlv2_result is changed
+
+- name: Create logical volume (testlv2) with pvs set as comma separated string
+ lvol:
+ vg: testvg2
+ lv: testlv2
+ size: 50%PVS
+ pvs: "{{ loop_device3 }},{{ loop_device4 }}"
+ register: css_pvs_create_testlv2_result
+
+- name: Assert logical volume (testlv2) creation idempotency with pvs set as comma separated string on second execution
+ assert:
+ that:
+ - css_pvs_create_testlv2_result is success
+ - css_pvs_create_testlv2_result is not changed
diff --git a/ansible_collections/community/general/tests/integration/targets/mail/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/mail/tasks/main.yml
index 4f3f90a51..83c242ad2 100644
--- a/ansible_collections/community/general/tests/integration/targets/mail/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/mail/tasks/main.yml
@@ -10,96 +10,101 @@
# TODO: Our current implementation does not handle SMTP authentication
-# NOTE: If the system does not support smtpd-tls (python 2.6 and older) we do basic tests
-- name: Attempt to install smtpd-tls
- pip:
- name: smtpd-tls
- state: present
- ignore_errors: true
- register: smtpd_tls
+- when:
+ # TODO: https://github.com/ansible-collections/community.general/issues/4656
+ - ansible_python.version.major != 3 or ansible_python.version.minor < 12
+ block:
-- name: Install test smtpserver
- copy:
- src: '{{ item }}'
- dest: '{{ remote_tmp_dir }}/{{ item }}'
- loop:
- - smtpserver.py
- - smtpserver.crt
- - smtpserver.key
+ # NOTE: If the system does not support smtpd-tls (python 2.6 and older) we do basic tests
+ - name: Attempt to install smtpd-tls
+ pip:
+ name: smtpd-tls
+ state: present
+ ignore_errors: true
+ register: smtpd_tls
-# FIXME: Verify the mail after it was send would be nice
-# This would require either dumping the content, or registering async task output
-- name: Start test smtpserver
- shell: '{{ ansible_python.executable }} {{ remote_tmp_dir }}/smtpserver.py 10025:10465'
- async: 45
- poll: 0
- register: smtpserver
+ - name: Install test smtpserver
+ copy:
+ src: '{{ item }}'
+ dest: '{{ remote_tmp_dir }}/{{ item }}'
+ loop:
+ - smtpserver.py
+ - smtpserver.crt
+ - smtpserver.key
-- name: Send a basic test-mail
- mail:
- port: 10025
- subject: Test mail 1 (smtp)
- secure: never
+ # FIXME: Verify the mail after it was send would be nice
+ # This would require either dumping the content, or registering async task output
+ - name: Start test smtpserver
+ shell: '{{ ansible_python.executable }} {{ remote_tmp_dir }}/smtpserver.py 10025:10465'
+ async: 45
+ poll: 0
+ register: smtpserver
-- name: Send a test-mail with body and specific recipient
- mail:
- port: 10025
- from: ansible@localhost
- to: root@localhost
- subject: Test mail 2 (smtp + body)
- body: Test body 2
- secure: never
+ - name: Send a basic test-mail
+ mail:
+ port: 10025
+ subject: Test mail 1 (smtp)
+ secure: never
-- name: Send a test-mail with attachment
- mail:
- port: 10025
- from: ansible@localhost
- to: root@localhost
- subject: Test mail 3 (smtp + body + attachment)
- body: Test body 3
- attach: /etc/group
- secure: never
+ - name: Send a test-mail with body and specific recipient
+ mail:
+ port: 10025
+ from: ansible@localhost
+ to: root@localhost
+ subject: Test mail 2 (smtp + body)
+ body: Test body 2
+ secure: never
-# NOTE: This might fail if smtpd-tls is missing or python 2.7.8 or older is used
-- name: Send a test-mail using starttls
- mail:
- port: 10025
- from: ansible@localhost
- to: root@localhost
- subject: Test mail 4 (smtp + starttls + body + attachment)
- body: Test body 4
- attach: /etc/group
- secure: starttls
- ignore_errors: true
- register: starttls_support
+ - name: Send a test-mail with attachment
+ mail:
+ port: 10025
+ from: ansible@localhost
+ to: root@localhost
+ subject: Test mail 3 (smtp + body + attachment)
+ body: Test body 3
+ attach: /etc/group
+ secure: never
-# NOTE: This might fail if smtpd-tls is missing or python 2.7.8 or older is used
-- name: Send a test-mail using TLS
- mail:
- port: 10465
- from: ansible@localhost
- to: root@localhost
- subject: Test mail 5 (smtp + tls + body + attachment)
- body: Test body 5
- attach: /etc/group
- secure: always
- ignore_errors: true
- register: tls_support
+ # NOTE: This might fail if smtpd-tls is missing or python 2.7.8 or older is used
+ - name: Send a test-mail using starttls
+ mail:
+ port: 10025
+ from: ansible@localhost
+ to: root@localhost
+ subject: Test mail 4 (smtp + starttls + body + attachment)
+ body: Test body 4
+ attach: /etc/group
+ secure: starttls
+ ignore_errors: true
+ register: starttls_support
-- fail:
- msg: Sending mail using starttls failed.
- when: smtpd_tls is succeeded and starttls_support is failed and tls_support is succeeded
+ # NOTE: This might fail if smtpd-tls is missing or python 2.7.8 or older is used
+ - name: Send a test-mail using TLS
+ mail:
+ port: 10465
+ from: ansible@localhost
+ to: root@localhost
+ subject: Test mail 5 (smtp + tls + body + attachment)
+ body: Test body 5
+ attach: /etc/group
+ secure: always
+ ignore_errors: true
+ register: tls_support
-- fail:
- msg: Send mail using TLS failed.
- when: smtpd_tls is succeeded and tls_support is failed and starttls_support is succeeded
+ - fail:
+ msg: Sending mail using starttls failed.
+ when: smtpd_tls is succeeded and starttls_support is failed and tls_support is succeeded
-- name: Send a test-mail with body, specific recipient and specific ehlohost
- mail:
- port: 10025
- ehlohost: some.domain.tld
- from: ansible@localhost
- to: root@localhost
- subject: Test mail 6 (smtp + body + ehlohost)
- body: Test body 6
- secure: never
+ - fail:
+ msg: Send mail using TLS failed.
+ when: smtpd_tls is succeeded and tls_support is failed and starttls_support is succeeded
+
+ - name: Send a test-mail with body, specific recipient and specific ehlohost
+ mail:
+ port: 10025
+ ehlohost: some.domain.tld
+ from: ansible@localhost
+ to: root@localhost
+ subject: Test mail 6 (smtp + body + ehlohost)
+ body: Test body 6
+ secure: never
diff --git a/ansible_collections/community/general/tests/integration/targets/mas/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/mas/tasks/main.yml
index f659160dc..839620779 100644
--- a/ansible_collections/community/general/tests/integration/targets/mas/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/mas/tasks/main.yml
@@ -117,7 +117,7 @@
that:
- install_status.stat.exists == true
-- name: Unistall Rested
+- name: Uninstall Rested
mas:
id: 421879749
state: absent
diff --git a/ansible_collections/community/general/tests/integration/targets/monit/aliases b/ansible_collections/community/general/tests/integration/targets/monit/aliases
index ca39d1353..c78104339 100644
--- a/ansible_collections/community/general/tests/integration/targets/monit/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/monit/aliases
@@ -9,6 +9,5 @@ skip/osx
skip/macos
skip/freebsd
skip/aix
-skip/python2.6 # python-daemon package used in integration tests requires >=2.7
skip/rhel # FIXME
unstable # TODO: the tests fail a lot; 'unstable' only requires them to pass when the module itself has been modified
diff --git a/ansible_collections/community/general/tests/integration/targets/mssql_script/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/mssql_script/tasks/main.yml
index 6fa4d3501..481522216 100644
--- a/ansible_collections/community/general/tests/integration/targets/mssql_script/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/mssql_script/tasks/main.yml
@@ -49,6 +49,19 @@
login_port: "{{ mssql_port }}"
script: "SELECT 1"
+- name: Execute a malformed query
+ community.general.mssql_script:
+ login_user: "{{ mssql_login_user }}"
+ login_password: "{{ mssql_login_password }}"
+ login_host: "{{ mssql_host }}"
+ login_port: "{{ mssql_port }}"
+ script: "SELCT 1"
+ failed_when: false
+ register: bad_query
+- assert:
+ that:
+ - bad_query.error.startswith('ProgrammingError')
+
- name: two batches with default output
community.general.mssql_script:
login_user: "{{ mssql_login_user }}"
@@ -135,6 +148,30 @@
- result_batches_dict.query_results_dict[0][0] | length == 1 # one row in first select
- result_batches_dict.query_results_dict[0][0][0]['b0s0'] == 'Batch 0 - Select 0' # column 'b0s0' of first row
+- name: Multiple batches with no resultsets and mixed-case GO
+ community.general.mssql_script:
+ login_user: "{{ mssql_login_user }}"
+ login_password: "{{ mssql_login_password }}"
+ login_host: "{{ mssql_host }}"
+ login_port: "{{ mssql_port }}"
+ script: |
+ CREATE TABLE #integration56yH2 (c1 VARCHAR(10), c2 VARCHAR(10))
+ Go
+ INSERT INTO #integration56yH2 VALUES ('C1_VALUE1', 'C2_VALUE1')
+ gO
+ UPDATE #integration56yH2 SET c2 = 'C2_VALUE2' WHERE c1 = 'C1_VALUE1'
+ go
+ SELECT * from #integration56yH2
+ GO
+ DROP TABLE #integration56yH2
+ register: empty_batches
+- assert:
+ that:
+ - empty_batches.query_results | length == 5 # five batch results
+ - empty_batches.query_results[3][0] | length == 1 # one row in select
+ - empty_batches.query_results[3][0][0] | length == 2 # two columns in row
+ - empty_batches.query_results[3][0][0][1] == 'C2_VALUE2' # value has been updated
+
- name: Stored procedure may return multiple result sets
community.general.mssql_script:
login_user: "{{ mssql_login_user }}"
diff --git a/ansible_collections/community/general/tests/integration/targets/nomad/aliases b/ansible_collections/community/general/tests/integration/targets/nomad/aliases
index ad2435c82..5886d4799 100644
--- a/ansible_collections/community/general/tests/integration/targets/nomad/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/nomad/aliases
@@ -8,3 +8,4 @@ destructive
skip/aix
skip/centos6
skip/freebsd
+disabled # TODO
diff --git a/ansible_collections/community/general/tests/integration/targets/npm/tasks/test.yml b/ansible_collections/community/general/tests/integration/targets/npm/tasks/test.yml
index c8e83f602..0ab8a98d2 100644
--- a/ansible_collections/community/general/tests/integration/targets/npm/tasks/test.yml
+++ b/ansible_collections/community/general/tests/integration/targets/npm/tasks/test.yml
@@ -12,10 +12,10 @@
# sample: node-v8.2.0-linux-x64.tar.xz
node_path: '{{ remote_dir }}/{{ nodejs_path }}/bin'
package: 'iconv-lite'
+ environment:
+ PATH: '{{ node_path }}:{{ ansible_env.PATH }}'
block:
- shell: npm --version
- environment:
- PATH: '{{ node_path }}:{{ ansible_env.PATH }}'
register: npm_version
- debug:
@@ -24,11 +24,8 @@
- name: 'Install simple package without dependency'
npm:
path: '{{ remote_dir }}'
- executable: '{{ node_path }}/npm'
state: present
name: '{{ package }}'
- environment:
- PATH: '{{ node_path }}:{{ ansible_env.PATH }}'
register: npm_install
- assert:
@@ -39,11 +36,8 @@
- name: 'Reinstall simple package without dependency'
npm:
path: '{{ remote_dir }}'
- executable: '{{ node_path }}/npm'
state: present
name: '{{ package }}'
- environment:
- PATH: '{{ node_path }}:{{ ansible_env.PATH }}'
register: npm_reinstall
- name: Check there is no change
@@ -60,11 +54,8 @@
- name: 'reinstall simple package'
npm:
path: '{{ remote_dir }}'
- executable: '{{ node_path }}/npm'
state: present
name: '{{ package }}'
- environment:
- PATH: '{{ node_path }}:{{ ansible_env.PATH }}'
register: npm_fix_install
- name: Check result is changed and successful
diff --git a/ansible_collections/community/general/tests/integration/targets/odbc/aliases b/ansible_collections/community/general/tests/integration/targets/odbc/aliases
index e8465c50e..91a616725 100644
--- a/ansible_collections/community/general/tests/integration/targets/odbc/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/odbc/aliases
@@ -9,4 +9,6 @@ skip/macos
skip/rhel8.0
skip/rhel9.0
skip/rhel9.1
+skip/rhel9.2
+skip/rhel9.3
skip/freebsd
diff --git a/ansible_collections/community/general/tests/integration/targets/odbc/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/odbc/tasks/main.yml
index ce55ea8aa..af5f57cb2 100644
--- a/ansible_collections/community/general/tests/integration/targets/odbc/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/odbc/tasks/main.yml
@@ -10,6 +10,7 @@
- when:
- ansible_os_family != 'Archlinux' # TODO install driver from AUR: https://aur.archlinux.org/packages/psqlodbc
+ - ansible_os_family != 'RedHat' or ansible_distribution_major_version != '7' # CentOS 7 stopped working
block:
#
diff --git a/ansible_collections/community/general/tests/integration/targets/one_host/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/one_host/tasks/main.yml
index ffd5ac04c..3b2c1cedf 100644
--- a/ansible_collections/community/general/tests/integration/targets/one_host/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/one_host/tasks/main.yml
@@ -9,7 +9,7 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
-# ENVIRONENT PREPARACTION
+# ENVIRONMENT PREPARACTION
- set_fact: test_number= 0
diff --git a/ansible_collections/community/general/tests/integration/targets/osx_defaults/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/osx_defaults/tasks/main.yml
index f7bcb8944..3ca3180f0 100644
--- a/ansible_collections/community/general/tests/integration/targets/osx_defaults/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/osx_defaults/tasks/main.yml
@@ -21,7 +21,7 @@
- name: Test if state and value are required together
assert:
that:
- - "'following are missing: value' in '{{ missing_value['msg'] }}'"
+ - "'following are missing: value' in missing_value['msg']"
- name: Change value of AppleMeasurementUnits to centimeter in check_mode
osx_defaults:
@@ -194,7 +194,7 @@
register: test_data_types
- assert:
- that: "{{ item.changed }}"
+ that: "item is changed"
with_items: "{{ test_data_types.results }}"
- name: Use different data types and delete them
@@ -208,7 +208,7 @@
register: test_data_types
- assert:
- that: "{{ item.changed }}"
+ that: "item is changed"
with_items: "{{ test_data_types.results }}"
diff --git a/ansible_collections/community/general/tests/integration/targets/pacman/handlers/main.yml b/ansible_collections/community/general/tests/integration/targets/pacman/handlers/main.yml
new file mode 100644
index 000000000..484482bba
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/pacman/handlers/main.yml
@@ -0,0 +1,23 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Remove user yaybuilder
+ ansible.builtin.user:
+ name: yaybuilder
+ state: absent
+
+- name: Remove yay
+ ansible.builtin.package:
+ name: yay
+ state: absent
+
+- name: Remove packages for yay-become
+ ansible.builtin.package:
+ name:
+ - base-devel
+ - yay
+ - git
+ - nmap
+ state: absent
diff --git a/ansible_collections/community/general/tests/integration/targets/pacman/tasks/locally_installed_package.yml b/ansible_collections/community/general/tests/integration/targets/pacman/tasks/locally_installed_package.yml
index a5f183236..f67950c75 100644
--- a/ansible_collections/community/general/tests/integration/targets/pacman/tasks/locally_installed_package.yml
+++ b/ansible_collections/community/general/tests/integration/targets/pacman/tasks/locally_installed_package.yml
@@ -7,11 +7,12 @@
package_name: ansible-test-foo
username: ansible-regular-user
block:
- - name: Install fakeroot
+ - name: Install dependencies
pacman:
state: present
name:
- fakeroot
+ - debugedit
- name: Create user
user:
diff --git a/ansible_collections/community/general/tests/integration/targets/pacman/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/pacman/tasks/main.yml
index 12d28a2d3..1f6001a66 100644
--- a/ansible_collections/community/general/tests/integration/targets/pacman/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/pacman/tasks/main.yml
@@ -17,3 +17,4 @@
- include_tasks: 'update_cache.yml'
- include_tasks: 'locally_installed_package.yml'
- include_tasks: 'reason.yml'
+ - include_tasks: 'yay-become.yml'
diff --git a/ansible_collections/community/general/tests/integration/targets/pacman/tasks/remove_nosave.yml b/ansible_collections/community/general/tests/integration/targets/pacman/tasks/remove_nosave.yml
index 2271ebc03..a410775c2 100644
--- a/ansible_collections/community/general/tests/integration/targets/pacman/tasks/remove_nosave.yml
+++ b/ansible_collections/community/general/tests/integration/targets/pacman/tasks/remove_nosave.yml
@@ -4,13 +4,14 @@
# SPDX-License-Identifier: GPL-3.0-or-later
- vars:
- package_name: xinetd
- config_file: /etc/xinetd.conf
+ package_name: mdadm
+ config_file: /etc/mdadm.conf
block:
- name: Make sure that {{ package_name }} is not installed
pacman:
name: '{{ package_name }}'
state: absent
+
- name: Make sure {{config_file}}.pacsave file doesn't exist
file:
path: '{{config_file}}.pacsave'
@@ -32,6 +33,7 @@
pacman:
name: '{{ package_name }}'
state: absent
+
- name: Make sure {{config_file}}.pacsave exists
stat:
path: '{{config_file}}.pacsave'
diff --git a/ansible_collections/community/general/tests/integration/targets/pacman/tasks/yay-become.yml b/ansible_collections/community/general/tests/integration/targets/pacman/tasks/yay-become.yml
new file mode 100644
index 000000000..95698d5ce
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/pacman/tasks/yay-become.yml
@@ -0,0 +1,66 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# This is more convoluted that one might expect, because:
+# - yay is not available or installation in ArchLinux (as it is in Manjaro - issue 6184 reports using it)
+# - to install yay in ArchLinux requires building the package
+# - makepkg cannot be run as root, but the user running it must have sudo to install the resulting package
+
+- name: create user
+ ansible.builtin.user:
+ name: yaybuilder
+ state: present
+ notify: Remove user yaybuilder
+
+- name: grant sudo powers to builder
+ community.general.sudoers:
+ name: yaybuilder
+ user: yaybuilder
+ commands: ALL
+ nopassword: true
+
+- name: Install base packages
+ ansible.builtin.package:
+ name:
+ - base-devel
+ - git
+ - go
+ state: present
+ notify: Remove packages for yay-become
+
+- name: Hack permissions for the remote_tmp_dir
+ ansible.builtin.file:
+ path: "{{ remote_tmp_dir }}"
+ mode: '0777'
+
+- name: Create temp directory for builder
+ ansible.builtin.file:
+ path: "{{ remote_tmp_dir }}/builder"
+ owner: yaybuilder
+ state: directory
+ mode: '0755'
+
+- name: clone yay git repo
+ become: true
+ become_user: yaybuilder
+ ansible.builtin.git:
+ repo: https://aur.archlinux.org/yay.git
+ dest: "{{ remote_tmp_dir }}/builder/yay"
+ depth: 1
+
+- name: make package
+ become: true
+ become_user: yaybuilder
+ ansible.builtin.command:
+ chdir: "{{ remote_tmp_dir }}/builder/yay"
+ cmd: makepkg -si --noconfirm
+ notify: Remove yay
+
+- name: Install nmap
+ community.general.pacman:
+ name: nmap
+ state: present
+ executable: yay
+ extra_args: --builddir /var/cache/yay
diff --git a/ansible_collections/community/general/tests/integration/targets/pids/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/pids/tasks/main.yml
index 2ba7f3754..c8feaacf3 100644
--- a/ansible_collections/community/general/tests/integration/targets/pids/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/pids/tasks/main.yml
@@ -45,7 +45,7 @@
- name: Copy templated helper script
template:
- src: obtainpid.sh
+ src: obtainpid.sh.j2
dest: "{{ remote_tmp_dir }}/obtainpid.sh"
mode: 0755
diff --git a/ansible_collections/community/general/tests/integration/targets/pids/templates/obtainpid.sh b/ansible_collections/community/general/tests/integration/targets/pids/templates/obtainpid.sh.j2
index ecbf56aab..ecbf56aab 100644
--- a/ansible_collections/community/general/tests/integration/targets/pids/templates/obtainpid.sh
+++ b/ansible_collections/community/general/tests/integration/targets/pids/templates/obtainpid.sh.j2
diff --git a/ansible_collections/community/general/tests/integration/targets/pipx/aliases b/ansible_collections/community/general/tests/integration/targets/pipx/aliases
index 9f87ec348..66e6e1a3e 100644
--- a/ansible_collections/community/general/tests/integration/targets/pipx/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/pipx/aliases
@@ -6,3 +6,4 @@ azp/posix/2
destructive
skip/python2
skip/python3.5
+disabled # TODO
diff --git a/ansible_collections/community/general/tests/integration/targets/pipx/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/pipx/tasks/main.yml
index 567405ec4..7eb0f11a6 100644
--- a/ansible_collections/community/general/tests/integration/targets/pipx/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/pipx/tasks/main.yml
@@ -314,3 +314,28 @@
that:
- install_tox_sitewide is changed
- usrlocaltox.stat.exists
+
+##############################################################################
+# Test for issue 7497
+- name: ensure application pyinstaller is uninstalled
+ community.general.pipx:
+ name: pyinstaller
+ state: absent
+
+- name: Install Python Package pyinstaller
+ community.general.pipx:
+ name: pyinstaller
+ state: present
+ system_site_packages: true
+ pip_args: "--no-cache-dir"
+ register: install_pyinstaller
+
+- name: cleanup pyinstaller
+ community.general.pipx:
+ name: pyinstaller
+ state: absent
+
+- name: check assertions
+ assert:
+ that:
+ - install_pyinstaller is changed
diff --git a/ansible_collections/community/general/tests/integration/targets/pipx_info/aliases b/ansible_collections/community/general/tests/integration/targets/pipx_info/aliases
index a28278bbc..e262b485a 100644
--- a/ansible_collections/community/general/tests/integration/targets/pipx_info/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/pipx_info/aliases
@@ -6,3 +6,4 @@ azp/posix/3
destructive
skip/python2
skip/python3.5
+disabled # TODO
diff --git a/ansible_collections/community/general/tests/integration/targets/pkgng/tasks/freebsd.yml b/ansible_collections/community/general/tests/integration/targets/pkgng/tasks/freebsd.yml
index 0c8001899..9d4ecf8bb 100644
--- a/ansible_collections/community/general/tests/integration/targets/pkgng/tasks/freebsd.yml
+++ b/ansible_collections/community/general/tests/integration/targets/pkgng/tasks/freebsd.yml
@@ -515,11 +515,18 @@
# NOTE: FreeBSD 13.2 fails to update the package catalogue for unknown reasons (someone with FreeBSD
# knowledge has to take a look)
#
+ # NOTE: FreeBSD 13.3 fails to update the package catalogue for unknown reasons (someone with FreeBSD
+ # knowledge has to take a look)
+ #
+ # NOTE: FreeBSD 14.0 fails to update the package catalogue for unknown reasons (someone with FreeBSD
+ # knowledge has to take a look)
+ #
# See also
# https://github.com/ansible-collections/community.general/issues/5795
when: >-
(ansible_distribution_version is version('12.01', '>=') and ansible_distribution_version is version('12.3', '<'))
- or ansible_distribution_version is version('13.3', '>=')
+ or (ansible_distribution_version is version('13.4', '>=') and ansible_distribution_version is version('14.0', '<'))
+ or ansible_distribution_version is version('14.1', '>=')
block:
- name: Setup testjail
include_tasks: setup-testjail.yml
diff --git a/ansible_collections/community/general/tests/integration/targets/pnpm/aliases b/ansible_collections/community/general/tests/integration/targets/pnpm/aliases
new file mode 100644
index 000000000..afeb1a6ee
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/pnpm/aliases
@@ -0,0 +1,8 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+azp/posix/2
+destructive
+skip/macos
+skip/freebsd
diff --git a/ansible_collections/community/general/tests/integration/targets/pnpm/meta/main.yml b/ansible_collections/community/general/tests/integration/targets/pnpm/meta/main.yml
new file mode 100644
index 000000000..6147ad33e
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/pnpm/meta/main.yml
@@ -0,0 +1,9 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+dependencies:
+ - setup_pkg_mgr
+ - setup_gnutar
+ - setup_remote_tmp_dir
diff --git a/ansible_collections/community/general/tests/integration/targets/pnpm/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/pnpm/tasks/main.yml
new file mode 100644
index 000000000..10f42618f
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/pnpm/tasks/main.yml
@@ -0,0 +1,27 @@
+---
+####################################################################
+# WARNING: These are designed specifically for Ansible tests #
+# and should not be used as examples of how to write Ansible roles #
+####################################################################
+
+# test code for the pnpm module
+# Copyright (c) 2023 Aritra Sen <aretrosen@proton.me>
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# -------------------------------------------------------------
+# Setup steps
+
+- name: Run tests on OSes
+ ansible.builtin.include_tasks: run.yml
+ vars:
+ ansible_system_os: "{{ ansible_system | lower }}"
+ nodejs_version: "{{ item.node_version }}"
+ nodejs_path: "node-v{{ nodejs_version }}-{{ ansible_system_os }}-x{{ ansible_userspace_bits }}"
+ pnpm_version: "{{ item.pnpm_version }}"
+ pnpm_path: "pnpm-{{ 'macos' if ansible_system_os == 'darwin' else 'linuxstatic' }}-x{{ ansible_userspace_bits }}"
+ with_items:
+ - { node_version: 16.20.0, pnpm_version: 8.7.0 }
+ when:
+ - not(ansible_distribution == 'Alpine') and not(ansible_distribution == 'CentOS' and ansible_distribution_major_version == '6')
diff --git a/ansible_collections/community/general/tests/integration/targets/pnpm/tasks/run.yml b/ansible_collections/community/general/tests/integration/targets/pnpm/tasks/run.yml
new file mode 100644
index 000000000..66f5eb622
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/pnpm/tasks/run.yml
@@ -0,0 +1,322 @@
+---
+# Copyright (c) 2023 Aritra Sen <aretrosen@proton.me>
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Download nodejs
+ ansible.builtin.unarchive:
+ src: "https://nodejs.org/dist/v{{ nodejs_version }}/{{ nodejs_path }}.tar.gz"
+ dest: "{{ remote_tmp_dir }}"
+ remote_src: true
+ creates: "{{ remote_tmp_dir }}/{{ nodejs_path }}.tar.gz"
+
+- name: Create a temporary directory for pnpm binary
+ ansible.builtin.tempfile:
+ state: directory
+ register: tmp_dir
+
+- name: Download pnpm binary to the temporary directory
+ ansible.builtin.get_url:
+ url: "https://github.com/pnpm/pnpm/releases/download/v{{ pnpm_version }}/{{ pnpm_path }}"
+ dest: "{{ tmp_dir.path }}/pnpm"
+ mode: "755"
+
+- name: Setting up pnpm via command
+ ansible.builtin.command: "{{ tmp_dir.path }}/pnpm setup --force"
+ environment:
+ PNPM_HOME: "{{ ansible_env.HOME }}/.local/share/pnpm"
+ SHELL: /bin/sh
+ ENV: "{{ ansible_env.HOME }}/.shrc"
+
+- name: Remove the temporary directory
+ ansible.builtin.file:
+ path: "{{ tmp_dir.path }}"
+ state: absent
+
+- name: Remove any previous Nodejs modules
+ ansible.builtin.file:
+ path: "{{ remote_tmp_dir }}/node_modules"
+ state: absent
+
+- name: CI tests to run
+ vars:
+ node_bin_path: "{{ remote_tmp_dir }}/{{ nodejs_path }}/bin"
+ pnpm_bin_path: "{{ ansible_env.HOME }}/.local/share/pnpm"
+ package: "tailwindcss"
+ environment:
+ PATH: "{{ node_bin_path }}:{{ ansible_env.PATH }}"
+
+ block:
+ - name: Create dummy package.json
+ ansible.builtin.template:
+ src: package.j2
+ dest: "{{ remote_tmp_dir }}/package.json"
+ mode: "644"
+
+ - name: Install reading-time package via package.json
+ pnpm:
+ path: "{{ remote_tmp_dir }}"
+ executable: "{{ pnpm_bin_path }}/pnpm"
+ state: present
+ environment:
+ PATH: "{{ node_bin_path }}:{{ ansible_env.PATH }}"
+
+ - name: Install the same package from package.json again
+ pnpm:
+ path: "{{ remote_tmp_dir }}"
+ executable: "{{ pnpm_bin_path }}/pnpm"
+ name: "reading-time"
+ state: present
+ environment:
+ PATH: "{{ node_bin_path }}:{{ ansible_env.PATH }}"
+ register: pnpm_install
+
+ - name: Assert that result is not changed
+ ansible.builtin.assert:
+ that:
+ - not (pnpm_install is changed)
+
+ - name: Install all packages in check mode
+ pnpm:
+ path: "{{ remote_tmp_dir }}"
+ executable: "{{ pnpm_bin_path }}/pnpm"
+ state: present
+ environment:
+ PATH: "{{ node_bin_path }}:{{ ansible_env.PATH }}"
+ check_mode: true
+ register: pnpm_install_check
+
+ - name: Verify test pnpm global installation in check mode
+ ansible.builtin.assert:
+ that:
+ - pnpm_install_check.err is defined
+ - pnpm_install_check.out is defined
+ - pnpm_install_check.err is none
+ - pnpm_install_check.out is none
+
+ - name: Install package without dependency
+ pnpm:
+ path: "{{ remote_tmp_dir }}"
+ executable: "{{ pnpm_bin_path }}/pnpm"
+ state: present
+ name: "{{ package }}"
+ environment:
+ PATH: "{{ node_bin_path }}:{{ ansible_env.PATH }}"
+ register: pnpm_install
+
+ - name: Assert that result is changed and successful
+ ansible.builtin.assert:
+ that:
+ - pnpm_install is success
+ - pnpm_install is changed
+
+ - name: Reinstall package without dependency
+ pnpm:
+ path: "{{ remote_tmp_dir }}"
+ executable: "{{ pnpm_bin_path }}/pnpm"
+ state: present
+ name: "{{ package }}"
+ environment:
+ PATH: "{{ node_bin_path }}:{{ ansible_env.PATH }}"
+ register: pnpm_reinstall
+
+ - name: Assert that there is no change
+ ansible.builtin.assert:
+ that:
+ - pnpm_reinstall is success
+ - not (pnpm_reinstall is changed)
+
+ - name: Reinstall package
+ pnpm:
+ path: "{{ remote_tmp_dir }}"
+ executable: "{{ pnpm_bin_path }}/pnpm"
+ state: latest
+ name: "{{ package }}"
+ environment:
+ PATH: "{{ node_bin_path }}:{{ ansible_env.PATH }}"
+ register: pnpm_fix_install
+
+ - name: Assert that result is changed and successful
+ ansible.builtin.assert:
+ that:
+ - pnpm_fix_install is success
+ - pnpm_fix_install is not changed
+
+ - name: Install package with version, without executable path
+ pnpm:
+ name: "{{ package }}"
+ version: 0.1.3
+ path: "{{ remote_tmp_dir }}"
+ state: present
+ environment:
+ PATH: "{{ pnpm_bin_path }}:{{ node_bin_path }}:{{ ansible_env.PATH }}"
+ register: pnpm_install
+
+ - name: Assert that package with version is installed
+ ansible.builtin.assert:
+ that:
+ - pnpm_install is success
+ - pnpm_install is changed
+
+ - name: Reinstall package with version, without explicit executable path
+ pnpm:
+ name: "{{ package }}"
+ version: 0.1.3
+ path: "{{ remote_tmp_dir }}"
+ state: present
+ environment:
+ PATH: "{{ pnpm_bin_path }}:{{ node_bin_path }}:{{ ansible_env.PATH }}"
+ register: pnpm_reinstall
+
+ - name: Assert that there is no change
+ ansible.builtin.assert:
+ that:
+ - pnpm_reinstall is success
+ - not (pnpm_reinstall is changed)
+
+ - name: Update package, without executable path
+ pnpm:
+ name: "{{ package }}"
+ path: "{{ remote_tmp_dir }}"
+ state: latest
+ environment:
+ PATH: "{{ pnpm_bin_path }}:{{ node_bin_path }}:{{ ansible_env.PATH }}"
+ register: pnpm_update
+
+ - name: Assert that result is changed and successful
+ ansible.builtin.assert:
+ that:
+ - pnpm_update is success
+ - pnpm_update is changed
+
+ - name: Remove package, without executable path
+ pnpm:
+ name: "{{ package }}"
+ path: "{{ remote_tmp_dir }}"
+ state: absent
+ environment:
+ PATH: "{{ pnpm_bin_path }}:{{ node_bin_path }}:{{ ansible_env.PATH }}"
+ register: pnpm_absent
+
+ - name: Assert that result is changed and successful
+ ansible.builtin.assert:
+ that:
+ - pnpm_absent is success
+ - pnpm_absent is changed
+
+ - name: Install package with version and alias, without executable path
+ pnpm:
+ name: "{{ package }}"
+ alias: tailwind-1
+ version: 0.1.3
+ path: "{{ remote_tmp_dir }}"
+ state: present
+ environment:
+ PATH: "{{ pnpm_bin_path }}:{{ node_bin_path }}:{{ ansible_env.PATH }}"
+ register: pnpm_install
+
+ - name: Assert that package with version and alias is installed
+ ansible.builtin.assert:
+ that:
+ - pnpm_install is success
+ - pnpm_install is changed
+
+ - name: Reinstall package with version and alias, without explicit executable path
+ pnpm:
+ name: "{{ package }}"
+ alias: tailwind-1
+ version: 0.1.3
+ path: "{{ remote_tmp_dir }}"
+ state: present
+ environment:
+ PATH: "{{ pnpm_bin_path }}:{{ node_bin_path }}:{{ ansible_env.PATH }}"
+ register: pnpm_reinstall
+
+ - name: Assert that there is no change
+ ansible.builtin.assert:
+ that:
+ - pnpm_reinstall is success
+ - not (pnpm_reinstall is changed)
+
+ - name: Remove package with alias, without executable path
+ pnpm:
+ name: tailwindcss
+ alias: tailwind-1
+ path: "{{ remote_tmp_dir }}"
+ state: absent
+ environment:
+ PATH: "{{ pnpm_bin_path }}:{{ node_bin_path }}:{{ ansible_env.PATH }}"
+ register: pnpm_absent
+
+ - name: Assert that result is changed and successful
+ ansible.builtin.assert:
+ that:
+ - pnpm_absent is success
+ - pnpm_absent is changed
+
+ - name: Install package without dependency globally
+ pnpm:
+ name: "{{ package }}"
+ executable: "{{ pnpm_bin_path }}/pnpm"
+ state: present
+ global: true
+ environment:
+ PATH: "{{ pnpm_bin_path }}:{{ node_bin_path }}:{{ ansible_env.PATH }}"
+ PNPM_HOME: "{{ pnpm_bin_path }}"
+ register: pnpm_install
+
+ - name: Assert that result is changed and successful
+ ansible.builtin.assert:
+ that:
+ - pnpm_install is success
+ - pnpm_install is changed
+
+ - name: Reinstall package globally, without explicit executable path
+ pnpm:
+ name: "{{ package }}"
+ state: present
+ global: true
+ environment:
+ PATH: "{{ pnpm_bin_path }}:{{ node_bin_path }}:{{ ansible_env.PATH }}"
+ PNPM_HOME: "{{ pnpm_bin_path }}"
+ register: pnpm_reinstall
+
+ - name: Assert that there is no change
+ ansible.builtin.assert:
+ that:
+ - pnpm_reinstall is success
+ - not (pnpm_reinstall is changed)
+
+ - name: Updating package globally, without explicit executable path
+ pnpm:
+ name: "{{ package }}"
+ state: latest
+ global: true
+ environment:
+ PATH: "{{ pnpm_bin_path }}:{{ node_bin_path }}:{{ ansible_env.PATH }}"
+ PNPM_HOME: "{{ pnpm_bin_path }}"
+ register: pnpm_reinstall
+
+ - name: Assert that there is no change
+ ansible.builtin.assert:
+ that:
+ - pnpm_reinstall is success
+ - pnpm_reinstall is not changed
+
+ - name: Remove package without dependency globally
+ pnpm:
+ name: "{{ package }}"
+ executable: "{{ pnpm_bin_path }}/pnpm"
+ global: true
+ state: absent
+ environment:
+ PATH: "{{ pnpm_bin_path }}:{{ node_bin_path }}:{{ ansible_env.PATH }}"
+ PNPM_HOME: "{{ pnpm_bin_path }}"
+ register: pnpm_absent
+
+ - name: Assert that result is changed and successful
+ ansible.builtin.assert:
+ that:
+ - pnpm_absent is success
+ - pnpm_absent is changed
diff --git a/ansible_collections/community/general/tests/integration/targets/pnpm/templates/package.j2 b/ansible_collections/community/general/tests/integration/targets/pnpm/templates/package.j2
new file mode 100644
index 000000000..429ea9bee
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/pnpm/templates/package.j2
@@ -0,0 +1,13 @@
+{#
+Copyright (c) Ansible Project
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
+#}
+{
+ "name": "ansible-pnpm-testing",
+ "version": "1.0.0",
+ "license": "MIT",
+ "dependencies": {
+ "reading-time": "^1.5.0"
+ }
+}
diff --git a/ansible_collections/community/general/tests/integration/targets/proxmox/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/proxmox/tasks/main.yml
index 22d7fcd29..1b529d111 100644
--- a/ansible_collections/community/general/tests/integration/targets/proxmox/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/proxmox/tasks/main.yml
@@ -129,6 +129,25 @@
- results_storage.proxmox_storages|length == 1
- results_storage.proxmox_storages[0].storage == "{{ storage }}"
+- name: List content on storage
+ proxmox_storage_contents_info:
+ api_host: "{{ api_host }}"
+ api_user: "{{ user }}@{{ domain }}"
+ api_password: "{{ api_password | default(omit) }}"
+ api_token_id: "{{ api_token_id | default(omit) }}"
+ api_token_secret: "{{ api_token_secret | default(omit) }}"
+ validate_certs: "{{ validate_certs }}"
+ storage: "{{ storage }}"
+ node: "{{ node }}"
+ content: images
+ register: results_list_storage
+
+- assert:
+ that:
+ - results_storage is not changed
+ - results_storage.proxmox_storage_content is defined
+ - results_storage.proxmox_storage_content |length == 1
+
- name: VM creation
tags: [ 'create' ]
block:
@@ -577,3 +596,20 @@
- results_kvm_destroy is changed
- results_kvm_destroy.vmid == {{ vmid }}
- results_kvm_destroy.msg == "VM {{ vmid }} removed"
+
+- name: Retrieve information about nodes
+ proxmox_node_info:
+ api_host: "{{ api_host }}"
+ api_user: "{{ user }}@{{ domain }}"
+ api_password: "{{ api_password | default(omit) }}"
+ api_token_id: "{{ api_token_id | default(omit) }}"
+ api_token_secret: "{{ api_token_secret | default(omit) }}"
+ validate_certs: "{{ validate_certs }}"
+ register: results
+
+- assert:
+ that:
+ - results is not changed
+ - results.proxmox_nodes is defined
+ - results.proxmox_nodes|length >= 1
+ - results.proxmox_nodes[0].type == 'node'
diff --git a/ansible_collections/community/general/tests/integration/targets/proxmox_pool/aliases b/ansible_collections/community/general/tests/integration/targets/proxmox_pool/aliases
new file mode 100644
index 000000000..525dcd332
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/proxmox_pool/aliases
@@ -0,0 +1,7 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+unsupported
+proxmox_pool
+proxmox_pool_member
diff --git a/ansible_collections/community/general/tests/integration/targets/proxmox_pool/defaults/main.yml b/ansible_collections/community/general/tests/integration/targets/proxmox_pool/defaults/main.yml
new file mode 100644
index 000000000..5a518ac73
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/proxmox_pool/defaults/main.yml
@@ -0,0 +1,7 @@
+# Copyright (c) 2023, Sergei Antipov <greendayonfire at gmail.com>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+poolid: test
+member: local
+member_type: storage
diff --git a/ansible_collections/community/general/tests/integration/targets/proxmox_pool/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/proxmox_pool/tasks/main.yml
new file mode 100644
index 000000000..2b22960f2
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/proxmox_pool/tasks/main.yml
@@ -0,0 +1,220 @@
+####################################################################
+# WARNING: These are designed specifically for Ansible tests #
+# and should not be used as examples of how to write Ansible roles #
+####################################################################
+
+# Copyright (c) 2023, Sergei Antipov <greendayonfire at gmail.com>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Proxmox VE pool and pool membership management
+ tags: ["pool"]
+ block:
+ - name: Make sure poolid parameter is not missing
+ proxmox_pool:
+ api_host: "{{ api_host }}"
+ api_user: "{{ user }}@{{ domain }}"
+ api_password: "{{ api_password | default(omit) }}"
+ api_token_id: "{{ api_token_id | default(omit) }}"
+ api_token_secret: "{{ api_token_secret | default(omit) }}"
+ validate_certs: "{{ validate_certs }}"
+ ignore_errors: true
+ register: result
+
+ - assert:
+ that:
+ - result is failed
+ - "'missing required arguments: poolid' in result.msg"
+
+ - name: Create pool (Check)
+ proxmox_pool:
+ api_host: "{{ api_host }}"
+ api_user: "{{ user }}@{{ domain }}"
+ api_password: "{{ api_password | default(omit) }}"
+ api_token_id: "{{ api_token_id | default(omit) }}"
+ api_token_secret: "{{ api_token_secret | default(omit) }}"
+ validate_certs: "{{ validate_certs }}"
+ poolid: "{{ poolid }}"
+ check_mode: true
+ register: result
+
+ - assert:
+ that:
+ - result is changed
+ - result is success
+
+ - name: Create pool
+ proxmox_pool:
+ api_host: "{{ api_host }}"
+ api_user: "{{ user }}@{{ domain }}"
+ api_password: "{{ api_password | default(omit) }}"
+ api_token_id: "{{ api_token_id | default(omit) }}"
+ api_token_secret: "{{ api_token_secret | default(omit) }}"
+ validate_certs: "{{ validate_certs }}"
+ poolid: "{{ poolid }}"
+ register: result
+
+ - assert:
+ that:
+ - result is changed
+ - result is success
+ - result.poolid == "{{ poolid }}"
+
+ - name: Delete pool (Check)
+ proxmox_pool:
+ api_host: "{{ api_host }}"
+ api_user: "{{ user }}@{{ domain }}"
+ api_password: "{{ api_password | default(omit) }}"
+ api_token_id: "{{ api_token_id | default(omit) }}"
+ api_token_secret: "{{ api_token_secret | default(omit) }}"
+ validate_certs: "{{ validate_certs }}"
+ poolid: "{{ poolid }}"
+ state: absent
+ check_mode: true
+ register: result
+
+ - assert:
+ that:
+ - result is changed
+ - result is success
+
+ - name: Delete non-existing pool should do nothing
+ proxmox_pool:
+ api_host: "{{ api_host }}"
+ api_user: "{{ user }}@{{ domain }}"
+ api_password: "{{ api_password | default(omit) }}"
+ api_token_id: "{{ api_token_id | default(omit) }}"
+ api_token_secret: "{{ api_token_secret | default(omit) }}"
+ validate_certs: "{{ validate_certs }}"
+ poolid: "non-existing-poolid"
+ state: absent
+ register: result
+
+ - assert:
+ that:
+ - result is not changed
+ - result is success
+
+ - name: Deletion of non-empty pool fails
+ block:
+ - name: Add storage into pool
+ proxmox_pool_member:
+ api_host: "{{ api_host }}"
+ api_user: "{{ user }}@{{ domain }}"
+ api_password: "{{ api_password | default(omit) }}"
+ api_token_id: "{{ api_token_id | default(omit) }}"
+ api_token_secret: "{{ api_token_secret | default(omit) }}"
+ validate_certs: "{{ validate_certs }}"
+ poolid: "{{ poolid }}"
+ member: "{{ member }}"
+ type: "{{ member_type }}"
+ diff: true
+ register: result
+
+ - assert:
+ that:
+ - result is changed
+ - result is success
+ - "'{{ member }}' in result.diff.after.members"
+
+ - name: Add non-existing storage into pool should fail
+ proxmox_pool_member:
+ api_host: "{{ api_host }}"
+ api_user: "{{ user }}@{{ domain }}"
+ api_password: "{{ api_password | default(omit) }}"
+ api_token_id: "{{ api_token_id | default(omit) }}"
+ api_token_secret: "{{ api_token_secret | default(omit) }}"
+ validate_certs: "{{ validate_certs }}"
+ poolid: "{{ poolid }}"
+ member: "non-existing-storage"
+ type: "{{ member_type }}"
+ ignore_errors: true
+ register: result
+
+ - assert:
+ that:
+ - result is failed
+ - "'Storage non-existing-storage doesn\\'t exist in the cluster' in result.msg"
+
+ - name: Delete non-empty pool
+ proxmox_pool:
+ api_host: "{{ api_host }}"
+ api_user: "{{ user }}@{{ domain }}"
+ api_password: "{{ api_password | default(omit) }}"
+ api_token_id: "{{ api_token_id | default(omit) }}"
+ api_token_secret: "{{ api_token_secret | default(omit) }}"
+ validate_certs: "{{ validate_certs }}"
+ poolid: "{{ poolid }}"
+ state: absent
+ ignore_errors: true
+ register: result
+
+ - assert:
+ that:
+ - result is failed
+ - "'Please remove members from pool first.' in result.msg"
+
+ - name: Delete storage from the pool
+ proxmox_pool_member:
+ api_host: "{{ api_host }}"
+ api_user: "{{ user }}@{{ domain }}"
+ api_password: "{{ api_password | default(omit) }}"
+ api_token_id: "{{ api_token_id | default(omit) }}"
+ api_token_secret: "{{ api_token_secret | default(omit) }}"
+ validate_certs: "{{ validate_certs }}"
+ poolid: "{{ poolid }}"
+ member: "{{ member }}"
+ type: "{{ member_type }}"
+ state: absent
+ register: result
+
+ - assert:
+ that:
+ - result is success
+ - result is changed
+
+ rescue:
+ - name: Delete storage from the pool if it is added
+ proxmox_pool_member:
+ api_host: "{{ api_host }}"
+ api_user: "{{ user }}@{{ domain }}"
+ api_password: "{{ api_password | default(omit) }}"
+ api_token_id: "{{ api_token_id | default(omit) }}"
+ api_token_secret: "{{ api_token_secret | default(omit) }}"
+ validate_certs: "{{ validate_certs }}"
+ poolid: "{{ poolid }}"
+ member: "{{ member }}"
+ type: "{{ member_type }}"
+ state: absent
+ ignore_errors: true
+
+ - name: Delete pool
+ proxmox_pool:
+ api_host: "{{ api_host }}"
+ api_user: "{{ user }}@{{ domain }}"
+ api_password: "{{ api_password | default(omit) }}"
+ api_token_id: "{{ api_token_id | default(omit) }}"
+ api_token_secret: "{{ api_token_secret | default(omit) }}"
+ validate_certs: "{{ validate_certs }}"
+ poolid: "{{ poolid }}"
+ state: absent
+ register: result
+
+ - assert:
+ that:
+ - result is changed
+ - result is success
+ - result.poolid == "{{ poolid }}"
+
+ rescue:
+ - name: Delete test pool if it is created
+ proxmox_pool:
+ api_host: "{{ api_host }}"
+ api_user: "{{ user }}@{{ domain }}"
+ api_password: "{{ api_password | default(omit) }}"
+ api_token_id: "{{ api_token_id | default(omit) }}"
+ api_token_secret: "{{ api_token_secret | default(omit) }}"
+ validate_certs: "{{ validate_certs }}"
+ poolid: "{{ poolid }}"
+ state: absent
+ ignore_errors: true
diff --git a/ansible_collections/community/general/tests/integration/targets/proxmox_template/aliases b/ansible_collections/community/general/tests/integration/targets/proxmox_template/aliases
new file mode 100644
index 000000000..5d9af8101
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/proxmox_template/aliases
@@ -0,0 +1,6 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+unsupported
+proxmox_template
diff --git a/ansible_collections/community/general/tests/integration/targets/proxmox_template/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/proxmox_template/tasks/main.yml
new file mode 100644
index 000000000..2d1187e89
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/proxmox_template/tasks/main.yml
@@ -0,0 +1,136 @@
+####################################################################
+# WARNING: These are designed specifically for Ansible tests #
+# and should not be used as examples of how to write Ansible roles #
+####################################################################
+
+# Copyright (c) 2023, Sergei Antipov <greendayonfire at gmail.com>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Proxmox VE virtual machines templates management
+ tags: ['template']
+ vars:
+ filename: /tmp/dummy.iso
+ block:
+ - name: Create dummy ISO file
+ ansible.builtin.command:
+ cmd: 'truncate -s 300M {{ filename }}'
+
+ - name: Delete requests_toolbelt module if it is installed
+ ansible.builtin.pip:
+ name: requests_toolbelt
+ state: absent
+
+ - name: Install latest proxmoxer
+ ansible.builtin.pip:
+ name: proxmoxer
+ state: latest
+
+ - name: Upload ISO as template to Proxmox VE cluster should fail
+ proxmox_template:
+ api_host: '{{ api_host }}'
+ api_user: '{{ user }}@{{ domain }}'
+ api_password: '{{ api_password | default(omit) }}'
+ api_token_id: '{{ api_token_id | default(omit) }}'
+ api_token_secret: '{{ api_token_secret | default(omit) }}'
+ validate_certs: '{{ validate_certs }}'
+ node: '{{ node }}'
+ src: '{{ filename }}'
+ content_type: iso
+ force: true
+ register: result
+ ignore_errors: true
+
+ - assert:
+ that:
+ - result is failed
+ - result.msg is match('\'requests_toolbelt\' module is required to upload files larger than 256MB')
+
+ - name: Install old (1.1.2) version of proxmoxer
+ ansible.builtin.pip:
+ name: proxmoxer==1.1.1
+ state: present
+
+ - name: Upload ISO as template to Proxmox VE cluster should be successful
+ proxmox_template:
+ api_host: '{{ api_host }}'
+ api_user: '{{ user }}@{{ domain }}'
+ api_password: '{{ api_password | default(omit) }}'
+ api_token_id: '{{ api_token_id | default(omit) }}'
+ api_token_secret: '{{ api_token_secret | default(omit) }}'
+ validate_certs: '{{ validate_certs }}'
+ node: '{{ node }}'
+ src: '{{ filename }}'
+ content_type: iso
+ force: true
+ register: result
+
+ - assert:
+ that:
+ - result is changed
+ - result is success
+ - result.msg is match('template with volid=local:iso/dummy.iso uploaded')
+
+ - name: Install latest proxmoxer
+ ansible.builtin.pip:
+ name: proxmoxer
+ state: latest
+
+ - name: Make smaller dummy file
+ ansible.builtin.command:
+ cmd: 'truncate -s 128M {{ filename }}'
+
+ - name: Upload ISO as template to Proxmox VE cluster should be successful
+ proxmox_template:
+ api_host: '{{ api_host }}'
+ api_user: '{{ user }}@{{ domain }}'
+ api_password: '{{ api_password | default(omit) }}'
+ api_token_id: '{{ api_token_id | default(omit) }}'
+ api_token_secret: '{{ api_token_secret | default(omit) }}'
+ validate_certs: '{{ validate_certs }}'
+ node: '{{ node }}'
+ src: '{{ filename }}'
+ content_type: iso
+ force: true
+ register: result
+
+ - assert:
+ that:
+ - result is changed
+ - result is success
+ - result.msg is match('template with volid=local:iso/dummy.iso uploaded')
+
+ - name: Install requests_toolbelt
+ ansible.builtin.pip:
+ name: requests_toolbelt
+ state: present
+
+ - name: Make big dummy file
+ ansible.builtin.command:
+ cmd: 'truncate -s 300M {{ filename }}'
+
+ - name: Upload ISO as template to Proxmox VE cluster should be successful
+ proxmox_template:
+ api_host: '{{ api_host }}'
+ api_user: '{{ user }}@{{ domain }}'
+ api_password: '{{ api_password | default(omit) }}'
+ api_token_id: '{{ api_token_id | default(omit) }}'
+ api_token_secret: '{{ api_token_secret | default(omit) }}'
+ validate_certs: '{{ validate_certs }}'
+ node: '{{ node }}'
+ src: '{{ filename }}'
+ content_type: iso
+ force: true
+ register: result
+
+ - assert:
+ that:
+ - result is changed
+ - result is success
+ - result.msg is match('template with volid=local:iso/dummy.iso uploaded')
+
+ always:
+ - name: Delete ISO file from host
+ ansible.builtin.file:
+ path: '{{ filename }}'
+ state: absent
diff --git a/ansible_collections/community/general/tests/integration/targets/scaleway_compute/tasks/pagination.yml b/ansible_collections/community/general/tests/integration/targets/scaleway_compute/tasks/pagination.yml
index 5a674b801..b2429e39f 100644
--- a/ansible_collections/community/general/tests/integration/targets/scaleway_compute/tasks/pagination.yml
+++ b/ansible_collections/community/general/tests/integration/targets/scaleway_compute/tasks/pagination.yml
@@ -23,7 +23,7 @@
commercial_type: '{{ scaleway_commerial_type }}'
wait: true
-- name: Get server informations of the first page
+- name: Get server information of the first page
scaleway_server_info:
region: par1
query_parameters:
@@ -37,7 +37,7 @@
that:
- first_page is success
-- name: Get server informations of the second page
+- name: Get server information of the second page
scaleway_server_info:
region: par1
query_parameters:
diff --git a/ansible_collections/community/general/tests/integration/targets/scaleway_container_registry/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/scaleway_container_registry/tasks/main.yml
index 91cea20f3..84d733a10 100644
--- a/ansible_collections/community/general/tests/integration/targets/scaleway_container_registry/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/scaleway_container_registry/tasks/main.yml
@@ -159,7 +159,7 @@
- cr_deletion_task is success
- cr_deletion_task is changed
-- name: Delete container regitry (Confirmation)
+- name: Delete container registry (Confirmation)
community.general.scaleway_container_registry:
state: absent
name: '{{ name }}'
diff --git a/ansible_collections/community/general/tests/integration/targets/scaleway_image_info/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/scaleway_image_info/tasks/main.yml
index 2cdf34fdd..3dfe20f37 100644
--- a/ansible_collections/community/general/tests/integration/targets/scaleway_image_info/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/scaleway_image_info/tasks/main.yml
@@ -8,7 +8,7 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
-- name: Get image informations and register it in a variable
+- name: Get image information and register it in a variable
scaleway_image_info:
region: par1
register: images
@@ -22,7 +22,7 @@
that:
- images is success
-- name: Get image informations from ams1 and register it in a variable
+- name: Get image information from ams1 and register it in a variable
scaleway_image_info:
region: ams1
register: images_ams1
diff --git a/ansible_collections/community/general/tests/integration/targets/scaleway_ip_info/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/scaleway_ip_info/tasks/main.yml
index b560b5658..6aad9b52e 100644
--- a/ansible_collections/community/general/tests/integration/targets/scaleway_ip_info/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/scaleway_ip_info/tasks/main.yml
@@ -8,7 +8,7 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
-- name: Get ip informations and register it in a variable
+- name: Get ip information and register it in a variable
scaleway_ip_info:
region: par1
register: ips
@@ -22,7 +22,7 @@
that:
- ips is success
-- name: Get ip informations and register it in a variable
+- name: Get ip information and register it in a variable
scaleway_ip_info:
region: ams1
register: ips_ams1
diff --git a/ansible_collections/community/general/tests/integration/targets/scaleway_organization_info/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/scaleway_organization_info/tasks/main.yml
index 7326ca226..247a4012b 100644
--- a/ansible_collections/community/general/tests/integration/targets/scaleway_organization_info/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/scaleway_organization_info/tasks/main.yml
@@ -8,7 +8,7 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
-- name: Get organization informations and register it in a variable
+- name: Get organization information and register it in a variable
scaleway_organization_info:
register: organizations
diff --git a/ansible_collections/community/general/tests/integration/targets/scaleway_security_group_info/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/scaleway_security_group_info/tasks/main.yml
index 8029a1e9a..608d76409 100644
--- a/ansible_collections/community/general/tests/integration/targets/scaleway_security_group_info/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/scaleway_security_group_info/tasks/main.yml
@@ -8,7 +8,7 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
-- name: Get security group informations and register it in a variable
+- name: Get security group information and register it in a variable
scaleway_security_group_info:
region: par1
register: security_groups
@@ -22,7 +22,7 @@
that:
- security_groups is success
-- name: Get security group informations and register it in a variable (AMS1)
+- name: Get security group information and register it in a variable (AMS1)
scaleway_security_group_info:
region: ams1
register: ams1_security_groups
diff --git a/ansible_collections/community/general/tests/integration/targets/scaleway_server_info/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/scaleway_server_info/tasks/main.yml
index 7274e8a85..516b2df0e 100644
--- a/ansible_collections/community/general/tests/integration/targets/scaleway_server_info/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/scaleway_server_info/tasks/main.yml
@@ -8,7 +8,7 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
-- name: Get server informations and register it in a variable
+- name: Get server information and register it in a variable
scaleway_server_info:
region: par1
register: servers
@@ -22,7 +22,7 @@
that:
- servers is success
-- name: Get server informations and register it in a variable
+- name: Get server information and register it in a variable
scaleway_server_info:
region: ams1
register: ams1_servers
diff --git a/ansible_collections/community/general/tests/integration/targets/scaleway_snapshot_info/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/scaleway_snapshot_info/tasks/main.yml
index 44f15d515..f80a9ced1 100644
--- a/ansible_collections/community/general/tests/integration/targets/scaleway_snapshot_info/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/scaleway_snapshot_info/tasks/main.yml
@@ -8,7 +8,7 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
-- name: Get snapshot informations and register it in a variable
+- name: Get snapshot information and register it in a variable
scaleway_snapshot_info:
region: par1
register: snapshots
@@ -22,7 +22,7 @@
that:
- snapshots is success
-- name: Get snapshot informations and register it in a variable (AMS1)
+- name: Get snapshot information and register it in a variable (AMS1)
scaleway_snapshot_info:
region: ams1
register: ams1_snapshots
diff --git a/ansible_collections/community/general/tests/integration/targets/scaleway_volume_info/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/scaleway_volume_info/tasks/main.yml
index 45995a54c..2202e6bf9 100644
--- a/ansible_collections/community/general/tests/integration/targets/scaleway_volume_info/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/scaleway_volume_info/tasks/main.yml
@@ -8,7 +8,7 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
-- name: Get volume informations and register it in a variable
+- name: Get volume information and register it in a variable
scaleway_volume_info:
region: par1
register: volumes
@@ -22,7 +22,7 @@
that:
- volumes is success
-- name: Get volume informations and register it in a variable (AMS1)
+- name: Get volume information and register it in a variable (AMS1)
scaleway_volume_info:
region: ams1
register: ams1_volumes
diff --git a/ansible_collections/community/general/tests/integration/targets/setup_docker/handlers/main.yml b/ansible_collections/community/general/tests/integration/targets/setup_docker/handlers/main.yml
index 283496714..52e13e3c4 100644
--- a/ansible_collections/community/general/tests/integration/targets/setup_docker/handlers/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/setup_docker/handlers/main.yml
@@ -3,17 +3,29 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
+- name: Remove python requests
+ ansible.builtin.pip:
+ name:
+ - requests
+ state: absent
+
+- name: Stop docker service
+ become: true
+ ansible.builtin.service:
+ name: docker
+ state: stopped
+
- name: Remove Docker packages
- package:
+ ansible.builtin.package:
name: "{{ docker_packages }}"
state: absent
- name: "D-Fedora : Remove repository"
- file:
+ ansible.builtin.file:
path: /etc/yum.repos.d/docker-ce.repo
state: absent
- name: "D-Fedora : Remove dnf-plugins-core"
- package:
+ ansible.builtin.package:
name: dnf-plugins-core
state: absent
diff --git a/ansible_collections/community/general/tests/integration/targets/setup_docker/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/setup_docker/tasks/main.yml
index 4f41da31a..19bc7aa8c 100644
--- a/ansible_collections/community/general/tests/integration/targets/setup_docker/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/setup_docker/tasks/main.yml
@@ -41,6 +41,7 @@
ansible.builtin.service:
name: docker
state: started
+ notify: Stop docker service
- name: Cheat on the docker socket permissions
become: true
@@ -53,3 +54,4 @@
name:
- requests
state: present
+ notify: Remove python requests
diff --git a/ansible_collections/community/general/tests/integration/targets/setup_etcd3/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/setup_etcd3/tasks/main.yml
index fe6b9cd02..1da52e225 100644
--- a/ansible_collections/community/general/tests/integration/targets/setup_etcd3/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/setup_etcd3/tasks/main.yml
@@ -50,7 +50,7 @@
state: present
# Check if re-installing etcd3 is required
- - name: Check if etcd3ctl exists for re-use.
+ - name: Check if etcd3ctl exists for reuse.
shell: "ETCDCTL_API=3 {{ etcd3_path }}/etcdctl --endpoints=localhost:2379 get foo"
args:
executable: /bin/bash
diff --git a/ansible_collections/community/general/tests/integration/targets/setup_java_keytool/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/setup_java_keytool/tasks/main.yml
index 2ab57d59d..9f156425d 100644
--- a/ansible_collections/community/general/tests/integration/targets/setup_java_keytool/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/setup_java_keytool/tasks/main.yml
@@ -16,11 +16,19 @@
}}
- name: Include OS-specific variables
- include_vars: '{{ ansible_os_family }}.yml'
+ include_vars: '{{ lookup("first_found", params) }}'
+ vars:
+ params:
+ files:
+ - '{{ ansible_distribution }}-{{ ansible_distribution_version }}.yml'
+ - '{{ ansible_distribution }}-{{ ansible_distribution_major_version }}.yml'
+ - '{{ ansible_os_family }}.yml'
+ paths:
+ - '{{ role_path }}/vars'
when: has_java_keytool
- name: Install keytool
package:
- name: '{{ keytool_package_name }}'
+ name: '{{ keytool_package_names }}'
become: true
when: has_java_keytool
diff --git a/ansible_collections/community/general/tests/integration/targets/setup_java_keytool/vars/Alpine.yml b/ansible_collections/community/general/tests/integration/targets/setup_java_keytool/vars/Alpine.yml
index 4ff75ae8c..c314c80ba 100644
--- a/ansible_collections/community/general/tests/integration/targets/setup_java_keytool/vars/Alpine.yml
+++ b/ansible_collections/community/general/tests/integration/targets/setup_java_keytool/vars/Alpine.yml
@@ -3,4 +3,5 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
-keytool_package_name: openjdk11-jre-headless
+keytool_package_names:
+ - openjdk11-jre-headless
diff --git a/ansible_collections/community/general/tests/integration/targets/setup_java_keytool/vars/Archlinux.yml b/ansible_collections/community/general/tests/integration/targets/setup_java_keytool/vars/Archlinux.yml
index 9e29065b3..b342911b6 100644
--- a/ansible_collections/community/general/tests/integration/targets/setup_java_keytool/vars/Archlinux.yml
+++ b/ansible_collections/community/general/tests/integration/targets/setup_java_keytool/vars/Archlinux.yml
@@ -3,4 +3,5 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
-keytool_package_name: jre11-openjdk-headless
+keytool_package_names:
+ - jre11-openjdk-headless
diff --git a/ansible_collections/community/general/tests/integration/targets/setup_java_keytool/vars/Debian-12.yml b/ansible_collections/community/general/tests/integration/targets/setup_java_keytool/vars/Debian-12.yml
new file mode 100644
index 000000000..17f8a53d0
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/setup_java_keytool/vars/Debian-12.yml
@@ -0,0 +1,8 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+keytool_package_names:
+ - ca-certificates-java
+ - openjdk-17-jre-headless
diff --git a/ansible_collections/community/general/tests/integration/targets/setup_java_keytool/vars/Debian.yml b/ansible_collections/community/general/tests/integration/targets/setup_java_keytool/vars/Debian.yml
index 30ae5cd04..cb5551a58 100644
--- a/ansible_collections/community/general/tests/integration/targets/setup_java_keytool/vars/Debian.yml
+++ b/ansible_collections/community/general/tests/integration/targets/setup_java_keytool/vars/Debian.yml
@@ -3,4 +3,5 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
-keytool_package_name: ca-certificates-java
+keytool_package_names:
+ - ca-certificates-java
diff --git a/ansible_collections/community/general/tests/integration/targets/setup_java_keytool/vars/RedHat.yml b/ansible_collections/community/general/tests/integration/targets/setup_java_keytool/vars/RedHat.yml
index c200091f8..8f4126e5d 100644
--- a/ansible_collections/community/general/tests/integration/targets/setup_java_keytool/vars/RedHat.yml
+++ b/ansible_collections/community/general/tests/integration/targets/setup_java_keytool/vars/RedHat.yml
@@ -3,4 +3,5 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
-keytool_package_name: java-11-openjdk-headless
+keytool_package_names:
+ - java-11-openjdk-headless
diff --git a/ansible_collections/community/general/tests/integration/targets/setup_java_keytool/vars/Suse.yml b/ansible_collections/community/general/tests/integration/targets/setup_java_keytool/vars/Suse.yml
index c200091f8..8f4126e5d 100644
--- a/ansible_collections/community/general/tests/integration/targets/setup_java_keytool/vars/Suse.yml
+++ b/ansible_collections/community/general/tests/integration/targets/setup_java_keytool/vars/Suse.yml
@@ -3,4 +3,5 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
-keytool_package_name: java-11-openjdk-headless
+keytool_package_names:
+ - java-11-openjdk-headless
diff --git a/ansible_collections/community/general/tests/integration/targets/setup_openldap/files/cert_cnconfig.ldif b/ansible_collections/community/general/tests/integration/targets/setup_openldap/files/cert_cnconfig.ldif
new file mode 100644
index 000000000..fc97e5f5c
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/setup_openldap/files/cert_cnconfig.ldif
@@ -0,0 +1,15 @@
+dn: cn=config
+add: olcTLSCACertificateFile
+olcTLSCACertificateFile: /usr/local/share/ca-certificates/ca.crt
+-
+add: olcTLSCertificateFile
+olcTLSCertificateFile: /etc/ldap/localhost.crt
+-
+add: olcTLSCertificateKeyFile
+olcTLSCertificateKeyFile: /etc/ldap/localhost.key
+-
+add: olcAuthzRegexp
+olcAuthzRegexp: {0}"UID=([^,]*)" uid=$1,ou=users,dc=example,dc=com
+-
+add: olcTLSVerifyClient
+olcTLSVerifyClient: allow
diff --git a/ansible_collections/community/general/tests/integration/targets/setup_openldap/files/cert_cnconfig.ldif.license b/ansible_collections/community/general/tests/integration/targets/setup_openldap/files/cert_cnconfig.ldif.license
new file mode 100644
index 000000000..edff8c768
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/setup_openldap/files/cert_cnconfig.ldif.license
@@ -0,0 +1,3 @@
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
+SPDX-FileCopyrightText: Ansible Project
diff --git a/ansible_collections/community/general/tests/integration/targets/setup_openldap/files/initial_config.ldif b/ansible_collections/community/general/tests/integration/targets/setup_openldap/files/initial_config.ldif
index 8f8c537bd..cb21f2cfd 100644
--- a/ansible_collections/community/general/tests/integration/targets/setup_openldap/files/initial_config.ldif
+++ b/ansible_collections/community/general/tests/integration/targets/setup_openldap/files/initial_config.ldif
@@ -18,5 +18,24 @@ homeDirectory: /home/ldaptest
cn: LDAP Test
gecos: LDAP Test
displayName: LDAP Test
+userPassword: test1pass!
mail: ldap.test@example.com
sn: Test
+
+dn: uid=second,ou=users,dc=example,dc=com
+uid: second
+uidNumber: 1112
+gidNUmber: 102
+objectClass: top
+objectClass: posixAccount
+objectClass: shadowAccount
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+loginShell: /bin/sh
+homeDirectory: /home/second
+cn: Second Test
+gecos: Second Test
+displayName: Second Test
+mail: second.test@example.com
+sn: Test
diff --git a/ansible_collections/community/general/tests/integration/targets/setup_openldap/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/setup_openldap/tasks/main.yml
index 25077de16..00f8f6a10 100644
--- a/ansible_collections/community/general/tests/integration/targets/setup_openldap/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/setup_openldap/tasks/main.yml
@@ -44,6 +44,22 @@
cmd: "export DEBIAN_FRONTEND=noninteractive; cat /root/debconf-slapd.conf | debconf-set-selections; dpkg-reconfigure -f noninteractive slapd"
creates: "/root/slapd_configured"
+ - name: Enable secure ldap
+ lineinfile:
+ path: /etc/default/slapd
+ regexp: "^SLAPD_SERVICES"
+ line: 'SLAPD_SERVICES="ldap:/// ldaps:/// ldapi:///"'
+
+ - name: Create certificates
+ shell: |
+ openssl req -x509 -batch -sha256 -days 1825 -newkey rsa:2048 -nodes -keyout /root/ca.key -out /usr/local/share/ca-certificates/ca.crt
+ openssl req -batch -sha256 -days 365 -newkey rsa:2048 -subj "/CN=$(hostname)" -addext "subjectAltName = DNS:localhost" -nodes -keyout /etc/ldap/localhost.key -out /etc/ldap/localhost.csr
+ openssl x509 -req -CA /usr/local/share/ca-certificates/ca.crt -CAkey /root/ca.key -CAcreateserial -in /etc/ldap/localhost.csr -out /etc/ldap/localhost.crt
+ chgrp openldap /etc/ldap/localhost.key
+ chmod 0640 /etc/ldap/localhost.key
+ openssl req -batch -sha256 -days 365 -newkey rsa:2048 -subj "/UID=ldaptest" -nodes -keyout /root/user.key -out /root/user.csr
+ openssl x509 -req -CA /usr/local/share/ca-certificates/ca.crt -CAkey /root/ca.key -CAcreateserial -in /root/user.csr -out /root/user.crt
+
- name: Start OpenLDAP service
become: true
service:
@@ -61,10 +77,14 @@
mode: '0644'
loop:
- rootpw_cnconfig.ldif
+ - cert_cnconfig.ldif
- initial_config.ldif
- name: Configure admin password for cn=config
- shell: "ldapmodify -Y EXTERNAL -H ldapi:/// -f /tmp/rootpw_cnconfig.ldif"
+ shell: "ldapmodify -Y EXTERNAL -H ldapi:/// -f /tmp/{{ item }}"
+ loop:
+ - rootpw_cnconfig.ldif
+ - cert_cnconfig.ldif
- name: Add initial config
become: true
diff --git a/ansible_collections/community/general/tests/integration/targets/setup_pkg_mgr/tasks/archlinux.yml b/ansible_collections/community/general/tests/integration/targets/setup_pkg_mgr/tasks/archlinux.yml
index fc75f84df..f471cc19a 100644
--- a/ansible_collections/community/general/tests/integration/targets/setup_pkg_mgr/tasks/archlinux.yml
+++ b/ansible_collections/community/general/tests/integration/targets/setup_pkg_mgr/tasks/archlinux.yml
@@ -21,3 +21,8 @@
update_cache: true
upgrade: true
when: archlinux_upgrade_tag is changed
+
+- name: Remove EXTERNALLY-MANAGED file
+ file:
+ path: /usr/lib/python{{ ansible_python.version.major }}.{{ ansible_python.version.minor }}/EXTERNALLY-MANAGED
+ state: absent
diff --git a/ansible_collections/community/general/tests/integration/targets/setup_postgresql_db/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/setup_postgresql_db/tasks/main.yml
index 3dac4a098..99668ebc9 100644
--- a/ansible_collections/community/general/tests/integration/targets/setup_postgresql_db/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/setup_postgresql_db/tasks/main.yml
@@ -127,6 +127,32 @@
seconds: 5
when: ansible_os_family == 'Suse'
+- name: Make installable on Arch
+ community.general.ini_file:
+ path: /usr/lib/systemd/system/postgresql.service
+ section: Service
+ option: "{{ item }}"
+ state: absent
+ loop:
+ - PrivateTmp
+ - ProtectHome
+ - ProtectSystem
+ - NoNewPrivileges
+ - ProtectControlGroups
+ - ProtectKernelModules
+ - ProtectKernelTunables
+ - PrivateDevices
+ - RestrictAddressFamilies
+ - RestrictNamespaces
+ - RestrictRealtime
+ - SystemCallArchitectures
+ when: ansible_distribution == 'Archlinux'
+
+- name: Make installable on Arch
+ systemd:
+ daemon_reload: true
+ when: ansible_distribution == 'Archlinux'
+
- name: Initialize postgres (Suse)
service: name=postgresql state=started
when: ansible_os_family == 'Suse'
diff --git a/ansible_collections/community/general/tests/integration/targets/setup_postgresql_db/vars/Debian-12-py3.yml b/ansible_collections/community/general/tests/integration/targets/setup_postgresql_db/vars/Debian-12-py3.yml
new file mode 100644
index 000000000..c92240237
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/setup_postgresql_db/vars/Debian-12-py3.yml
@@ -0,0 +1,13 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+postgresql_packages:
+ - "postgresql"
+ - "postgresql-common"
+ - "python3-psycopg2"
+
+pg_hba_location: "/etc/postgresql/15/main/pg_hba.conf"
+pg_dir: "/var/lib/postgresql/15/main"
+pg_ver: 15
diff --git a/ansible_collections/community/general/tests/integration/targets/setup_snap/tasks/D-RedHat-9.2.yml b/ansible_collections/community/general/tests/integration/targets/setup_snap/tasks/D-RedHat-9.2.yml
new file mode 100644
index 000000000..5bbfaff12
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/setup_snap/tasks/D-RedHat-9.2.yml
@@ -0,0 +1,6 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# Do nothing
diff --git a/ansible_collections/community/general/tests/integration/targets/setup_snap/tasks/D-RedHat-9.3.yml b/ansible_collections/community/general/tests/integration/targets/setup_snap/tasks/D-RedHat-9.3.yml
new file mode 100644
index 000000000..5bbfaff12
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/setup_snap/tasks/D-RedHat-9.3.yml
@@ -0,0 +1,6 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# Do nothing
diff --git a/ansible_collections/community/general/tests/integration/targets/setup_tls/files/ca_certificate.pem b/ansible_collections/community/general/tests/integration/targets/setup_tls/files/ca_certificate.pem
index 130e0a2da..a438d9266 100644
--- a/ansible_collections/community/general/tests/integration/targets/setup_tls/files/ca_certificate.pem
+++ b/ansible_collections/community/general/tests/integration/targets/setup_tls/files/ca_certificate.pem
@@ -1,7 +1,3 @@
-# Copyright (c) Ansible Project
-# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
-# SPDX-License-Identifier: GPL-3.0-or-later
-
-----BEGIN CERTIFICATE-----
MIIDAjCCAeqgAwIBAgIJANguFROhaWocMA0GCSqGSIb3DQEBCwUAMDExIDAeBgNV
BAMMF1RMU0dlblNlbGZTaWduZWR0Um9vdENBMQ0wCwYDVQQHDAQkJCQkMB4XDTE5
diff --git a/ansible_collections/community/general/tests/integration/targets/setup_tls/files/ca_certificate.pem.license b/ansible_collections/community/general/tests/integration/targets/setup_tls/files/ca_certificate.pem.license
new file mode 100644
index 000000000..a1390a69e
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/setup_tls/files/ca_certificate.pem.license
@@ -0,0 +1,3 @@
+Copyright (c) Ansible Project
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
diff --git a/ansible_collections/community/general/tests/integration/targets/setup_tls/files/ca_key.pem b/ansible_collections/community/general/tests/integration/targets/setup_tls/files/ca_key.pem
index d9dc5ca0f..0a950eda0 100644
--- a/ansible_collections/community/general/tests/integration/targets/setup_tls/files/ca_key.pem
+++ b/ansible_collections/community/general/tests/integration/targets/setup_tls/files/ca_key.pem
@@ -1,7 +1,3 @@
-# Copyright (c) Ansible Project
-# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
-# SPDX-License-Identifier: GPL-3.0-or-later
-
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDqVt84czSxWnWW
4Ng6hmKE3NarbLsycwtjrYBokV7Kk7Mp7PrBbYF05FOgSdJLvL6grlRSQK2VPsXd
diff --git a/ansible_collections/community/general/tests/integration/targets/setup_tls/files/ca_key.pem.license b/ansible_collections/community/general/tests/integration/targets/setup_tls/files/ca_key.pem.license
new file mode 100644
index 000000000..a1390a69e
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/setup_tls/files/ca_key.pem.license
@@ -0,0 +1,3 @@
+Copyright (c) Ansible Project
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
diff --git a/ansible_collections/community/general/tests/integration/targets/setup_tls/files/client_certificate.pem b/ansible_collections/community/general/tests/integration/targets/setup_tls/files/client_certificate.pem
index 9e956e6b0..501d83897 100644
--- a/ansible_collections/community/general/tests/integration/targets/setup_tls/files/client_certificate.pem
+++ b/ansible_collections/community/general/tests/integration/targets/setup_tls/files/client_certificate.pem
@@ -1,7 +1,3 @@
-# Copyright (c) Ansible Project
-# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
-# SPDX-License-Identifier: GPL-3.0-or-later
-
-----BEGIN CERTIFICATE-----
MIIDRjCCAi6gAwIBAgIBAjANBgkqhkiG9w0BAQsFADAxMSAwHgYDVQQDDBdUTFNH
ZW5TZWxmU2lnbmVkdFJvb3RDQTENMAsGA1UEBwwEJCQkJDAeFw0xOTAxMTEwODMz
diff --git a/ansible_collections/community/general/tests/integration/targets/setup_tls/files/client_certificate.pem.license b/ansible_collections/community/general/tests/integration/targets/setup_tls/files/client_certificate.pem.license
new file mode 100644
index 000000000..a1390a69e
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/setup_tls/files/client_certificate.pem.license
@@ -0,0 +1,3 @@
+Copyright (c) Ansible Project
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
diff --git a/ansible_collections/community/general/tests/integration/targets/setup_tls/files/client_key.pem b/ansible_collections/community/general/tests/integration/targets/setup_tls/files/client_key.pem
index 3848ad7cf..850260a87 100644
--- a/ansible_collections/community/general/tests/integration/targets/setup_tls/files/client_key.pem
+++ b/ansible_collections/community/general/tests/integration/targets/setup_tls/files/client_key.pem
@@ -1,7 +1,3 @@
-# Copyright (c) Ansible Project
-# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
-# SPDX-License-Identifier: GPL-3.0-or-later
-
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAqDPjkNxwpwlAAM/Shhk8FgfYUG1HwGV5v7LZW9v7jgKd6zcM
QJQrP4IspgRxOiLupqytNOlZ/mfYm6iKw9i7gjsXLtucvIKKhutk4HT+bGvcEfuf
diff --git a/ansible_collections/community/general/tests/integration/targets/setup_tls/files/client_key.pem.license b/ansible_collections/community/general/tests/integration/targets/setup_tls/files/client_key.pem.license
new file mode 100644
index 000000000..a1390a69e
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/setup_tls/files/client_key.pem.license
@@ -0,0 +1,3 @@
+Copyright (c) Ansible Project
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
diff --git a/ansible_collections/community/general/tests/integration/targets/setup_tls/files/server_certificate.pem b/ansible_collections/community/general/tests/integration/targets/setup_tls/files/server_certificate.pem
index b714ddbfb..4a0ebc6ec 100644
--- a/ansible_collections/community/general/tests/integration/targets/setup_tls/files/server_certificate.pem
+++ b/ansible_collections/community/general/tests/integration/targets/setup_tls/files/server_certificate.pem
@@ -1,7 +1,3 @@
-# Copyright (c) Ansible Project
-# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
-# SPDX-License-Identifier: GPL-3.0-or-later
-
-----BEGIN CERTIFICATE-----
MIIDRjCCAi6gAwIBAgIBATANBgkqhkiG9w0BAQsFADAxMSAwHgYDVQQDDBdUTFNH
ZW5TZWxmU2lnbmVkdFJvb3RDQTENMAsGA1UEBwwEJCQkJDAeFw0xOTAxMTEwODMz
diff --git a/ansible_collections/community/general/tests/integration/targets/setup_tls/files/server_certificate.pem.license b/ansible_collections/community/general/tests/integration/targets/setup_tls/files/server_certificate.pem.license
new file mode 100644
index 000000000..a1390a69e
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/setup_tls/files/server_certificate.pem.license
@@ -0,0 +1,3 @@
+Copyright (c) Ansible Project
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
diff --git a/ansible_collections/community/general/tests/integration/targets/setup_tls/files/server_key.pem b/ansible_collections/community/general/tests/integration/targets/setup_tls/files/server_key.pem
index ec0134993..c79ab6480 100644
--- a/ansible_collections/community/general/tests/integration/targets/setup_tls/files/server_key.pem
+++ b/ansible_collections/community/general/tests/integration/targets/setup_tls/files/server_key.pem
@@ -1,7 +1,3 @@
-# Copyright (c) Ansible Project
-# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
-# SPDX-License-Identifier: GPL-3.0-or-later
-
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAyMBKx8AHrEQX3fR4mZJgd1WIdvHNUJBPSPJ2MhySl9mQVIQM
yvofNAZHEySfeNuualsgAh/8JeeF3v6HxVBaxmuL89Ks+FJC/yiNDhsNvGOKpyna
diff --git a/ansible_collections/community/general/tests/integration/targets/setup_tls/files/server_key.pem.license b/ansible_collections/community/general/tests/integration/targets/setup_tls/files/server_key.pem.license
new file mode 100644
index 000000000..a1390a69e
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/setup_tls/files/server_key.pem.license
@@ -0,0 +1,3 @@
+Copyright (c) Ansible Project
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
diff --git a/ansible_collections/community/general/tests/integration/targets/shutdown/aliases b/ansible_collections/community/general/tests/integration/targets/shutdown/aliases
index afda346c4..428e8289d 100644
--- a/ansible_collections/community/general/tests/integration/targets/shutdown/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/shutdown/aliases
@@ -3,3 +3,4 @@
# SPDX-License-Identifier: GPL-3.0-or-later
azp/posix/1
+destructive
diff --git a/ansible_collections/community/general/tests/integration/targets/shutdown/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/shutdown/tasks/main.yml
index dadeb6269..2c9bc6bd6 100644
--- a/ansible_collections/community/general/tests/integration/targets/shutdown/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/shutdown/tasks/main.yml
@@ -7,13 +7,7 @@
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
-
-- name: Install systemd-sysv on Ubuntu 18 and Debian
- apt:
- name: systemd-sysv
- state: present
- when: (ansible_distribution == 'Ubuntu' and ansible_distribution_major_version is version('18', '>=')) or (ansible_distribution == 'Debian')
- register: systemd_sysv_install
+#
- name: Execute shutdown with custom message and delay
community.general.shutdown:
@@ -34,29 +28,44 @@
- '"Custom Message" in shutdown_result["shutdown_command"]'
- '"Shut down initiated by Ansible" in shutdown_result_minus["shutdown_command"]'
- '"Custom Message" not in shutdown_result_minus["shutdown_command"]'
- when: ansible_os_family not in ['Alpine', 'AIX']
+ when:
+ - 'ansible_os_family not in ["Alpine", "AIX"]'
+ - '"systemctl" not in shutdown_result["shutdown_command"]'
+ - '"systemctl" not in shutdown_result_minus["shutdown_command"]'
-- name: Verify shutdown command is present except Alpine, VMKernel
+- name: Verify shutdown command is present except Alpine or AIX or systemd
assert:
that: '"shutdown" in shutdown_result["shutdown_command"]'
- when: ansible_os_family != 'Alpine' and ansible_system != 'VMKernel'
+ when:
+ - "ansible_os_family != 'Alpine'"
+ - "ansible_system != 'VMKernel'"
+ - '"systemctl" not in shutdown_result["shutdown_command"]'
-- name: Verify shutdown command is present in Alpine
+- name: Verify shutdown command is present in Alpine except systemd
assert:
that: '"poweroff" in shutdown_result["shutdown_command"]'
- when: ansible_os_family == 'Alpine'
+ when:
+ - "ansible_os_family == 'Alpine'"
+ - '"systemctl" not in shutdown_result["shutdown_command"]'
-- name: Verify shutdown command is present in VMKernel
+
+- name: Verify shutdown command is present in VMKernel except systemd
assert:
that: '"halt" in shutdown_result["shutdown_command"]'
- when: ansible_system == 'VMKernel'
+ when:
+ - "ansible_system == 'VMKernel'"
+ - '"systemctl" not in shutdown_result["shutdown_command"]'
-- name: Verify shutdown delay is present in minutes in Linux
+- name: Verify shutdown delay is present in minutes in Linux except systemd
assert:
that:
- '"-h 1" in shutdown_result["shutdown_command"]'
- '"-h 0" in shutdown_result_minus["shutdown_command"]'
- when: ansible_system == 'Linux' and ansible_os_family != 'Alpine'
+ when:
+ - "ansible_system == 'Linux'"
+ - "ansible_os_family != 'Alpine'"
+ - '"systemctl" not in shutdown_result["shutdown_command"]'
+ - '"systemctl" not in shutdown_result_minus["shutdown_command"]'
- name: Verify shutdown delay is present in minutes in Void, MacOSX, OpenBSD
assert:
@@ -68,8 +77,8 @@
- name: Verify shutdown delay is present in seconds in FreeBSD
assert:
that:
- - '"-h +100s" in shutdown_result["shutdown_command"]'
- - '"-h +0s" in shutdown_result_minus["shutdown_command"]'
+ - '"-p +100s" in shutdown_result["shutdown_command"]'
+ - '"-p +0s" in shutdown_result_minus["shutdown_command"]'
when: ansible_system == 'FreeBSD'
- name: Verify shutdown delay is present in seconds in Solaris, SunOS
@@ -86,8 +95,30 @@
- '"-d 0" in shutdown_result_minus["shutdown_command"]'
when: ansible_system == 'VMKernel'
-- name: Remove systemd-sysv in ubuntu 18 in case it has been installed in test
+- name: Ensure that systemd-sysv is absent in Ubuntu 18 and Debian
apt:
- name: systemd-sysv
+ name: sytemd-sysv
state: absent
- when: systemd_sysv_install is changed
+ when: (ansible_distribution == 'Ubuntu' and ansible_distribution_major_version is version('18', '>=')) or (ansible_distribution == 'Debian')
+ register: systemd_sysv_install
+
+- name: Gather package facts
+ package_facts:
+ manager: apt
+ when: (ansible_distribution == 'Ubuntu' and ansible_distribution_major_version is version('18', '>=')) or (ansible_distribution == 'Debian')
+
+- name: Execute shutdown if no systemd-sysv
+ community.general.shutdown:
+ register: shutdown_result
+ check_mode: true
+ when:
+ - "(ansible_distribution == 'Ubuntu' and ansible_distribution_major_version is version('18', '>=')) or (ansible_distribution == 'Debian')"
+ - '"systemd-sysv" not in ansible_facts.packages'
+
+- name: Install systemd_sysv in case it has been removed in test
+ apt:
+ name: systemd-sysv
+ state: present
+ when:
+ - "(ansible_distribution == 'Ubuntu' and ansible_distribution_major_version is version('18', '>=')) or (ansible_distribution == 'Debian')"
+ - "systemd_sysv_install is changed"
diff --git a/ansible_collections/community/general/tests/integration/targets/snap/meta/main.yml b/ansible_collections/community/general/tests/integration/targets/snap/meta/main.yml
index f36427f71..5c4a48a41 100644
--- a/ansible_collections/community/general/tests/integration/targets/snap/meta/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/snap/meta/main.yml
@@ -5,3 +5,4 @@
dependencies:
- setup_snap
+ - setup_remote_tmp_dir
diff --git a/ansible_collections/community/general/tests/integration/targets/snap/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/snap/tasks/main.yml
index 0f24e69f3..2a683617a 100644
--- a/ansible_collections/community/general/tests/integration/targets/snap/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/snap/tasks/main.yml
@@ -8,236 +8,18 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
-- name: Has-snap block
+- name: Has-snap include
when: has_snap
block:
- - name: Make sure package is not installed (hello-world)
- community.general.snap:
- name: hello-world
- state: absent
-
- - name: Install package (hello-world) (check mode)
- community.general.snap:
- name: hello-world
- state: present
- register: install_check
- check_mode: true
-
- - name: Install package (hello-world)
- community.general.snap:
- name: hello-world
- state: present
- register: install
-
- - name: Install package again (hello-world) (check mode)
- community.general.snap:
- name: hello-world
- state: present
- register: install_again_check
- check_mode: true
-
- - name: Install package again (hello-world)
- community.general.snap:
- name: hello-world
- state: present
- register: install_again
-
- - name: Assert package has been installed just once (hello-world)
- assert:
- that:
- - install is changed
- - install_check is changed
- - install_again is not changed
- - install_again_check is not changed
-
- - name: Check package has been installed correctly (hello-world)
- command: hello-world
- environment:
- PATH: /snap/bin/
-
- - name: Remove package (hello-world) (check mode)
- community.general.snap:
- name: hello-world
- state: absent
- register: remove_check
- check_mode: true
-
- - name: Remove package (hello-world)
- community.general.snap:
- name: hello-world
- state: absent
- register: remove
-
- - name: Remove package again (hello-world) (check mode)
- community.general.snap:
- name: hello-world
- state: absent
- register: remove_again_check
- check_mode: true
-
- - name: Remove package again (hello-world)
- community.general.snap:
- name: hello-world
- state: absent
- register: remove_again
-
- - name: Assert package has been removed just once (hello-world)
- assert:
- that:
- - remove is changed
- - remove_check is changed
- - remove_again is not changed
- - remove_again_check is not changed
-
- - name: Make sure package from classic snap is not installed (nvim)
- community.general.snap:
- name: nvim
- state: absent
-
- - name: Install package from classic snap (nvim)
- community.general.snap:
- name: nvim
- state: present
- classic: true
- register: classic_install
-
- # testing classic idempotency
- - name: Install package from classic snap again (nvim)
- community.general.snap:
- name: nvim
- state: present
- classic: true
- register: classic_install_again
-
- - name: Assert package has been installed just once (nvim)
- assert:
- that:
- - classic_install is changed
- - classic_install_again is not changed
-
- # this is just testing if a package which has been installed
- # with true classic can be removed without setting classic to true
- - name: Remove package from classic snap without setting classic to true (nvim)
- community.general.snap:
- name: nvim
- state: absent
- register: classic_remove_without_true_classic
-
- - name: Remove package from classic snap with setting classic to true (nvim)
- community.general.snap:
- name: nvim
- state: absent
- classic: true
- register: classic_remove_with_true_classic
-
- - name: Assert package has been removed without setting classic to true (nvim)
- assert:
- that:
- - classic_remove_without_true_classic is changed
- - classic_remove_with_true_classic is not changed
-
-
- - name: Make sure package is not installed (uhttpd)
- community.general.snap:
- name: uhttpd
- state: absent
-
- - name: Install package (uhttpd)
- community.general.snap:
- name: uhttpd
- state: present
- register: install
-
- - name: Install package (uhttpd)
- community.general.snap:
- name: uhttpd
- state: present
- options:
- - "listening-port=8080"
- register: install_with_option
-
- - name: Install package again with option (uhttpd)
- community.general.snap:
- name: uhttpd
- state: present
- options:
- - "listening-port=8080"
- register: install_with_option_again
-
- - name: Install package again with different options (uhttpd)
- community.general.snap:
- name: uhttpd
- state: present
- options:
- - "listening-port=8088"
- - "document-root-dir=/tmp"
- register: install_with_option_changed
-
- - name: Remove package (uhttpd)
- community.general.snap:
- name: uhttpd
- state: absent
- register: remove
-
- - name: Assert package has been installed with options just once and only changed options trigger a change (uhttpd)
- assert:
- that:
- - install is changed
- - install_with_option is changed
- - "install_with_option.options_changed[0] == 'uhttpd:listening-port=8080'"
- - install_with_option_again is not changed
- - install_with_option_changed is changed
- - "'uhttpd:listening-port=8088' in install_with_option_changed.options_changed"
- - "'uhttpd:document-root-dir=/tmp' in install_with_option_changed.options_changed"
- - "'uhttpd:listening-port=8080' not in install_with_option_changed.options_changed"
- - remove is changed
-
- - name: Install two packages at the same time
- community.general.snap:
- name:
- - hello-world
- - uhttpd
- state: present
- register: install_two
-
- - name: Install two packages at the same time (again)
- community.general.snap:
- name:
- - hello-world
- - uhttpd
- state: present
- register: install_two_again
-
- - name: Remove packages (hello-world & uhttpd)
- community.general.snap:
- name:
- - hello-world
- - uhttpd
- state: absent
- register: install_two_remove
-
- - name: Remove packages again (hello-world & uhttpd)
- community.general.snap:
- name:
- - hello-world
- - uhttpd
- state: absent
- register: install_two_remove_again
-
- - name: Assert installation of two packages
- assert:
- that:
- - install_two is changed
- - "'hello-world' in install_two.snaps_installed"
- - "'uhttpd' in install_two.snaps_installed"
- - install_two.snaps_removed is not defined
- - install_two_again is not changed
- - install_two_again.snaps_installed is not defined
- - install_two_again.snaps_removed is not defined
- - install_two_remove is changed
- - install_two_again.snaps_installed is not defined
- - "'hello-world' in install_two_remove.snaps_removed"
- - "'uhttpd' in install_two_remove.snaps_removed"
- - install_two_remove_again is not changed
- - install_two_remove_again.snaps_installed is not defined
- - install_two_remove_again.snaps_removed is not defined
+ - name: Include test
+ ansible.builtin.include_tasks: test.yml
+ # TODO: Find better package to install from a channel - microk8s installation takes multiple minutes, and even removal takes one minute!
+ # - name: Include test_channel
+ # ansible.builtin.include_tasks: test_channel.yml
+ # TODO: Find bettter package to download and install from sources - cider 1.6.0 takes over 35 seconds to install
+ # - name: Include test_dangerous
+ # ansible.builtin.include_tasks: test_dangerous.yml
+ - name: Include test_3dash
+ ansible.builtin.include_tasks: test_3dash.yml
+ - name: Include test_empty_list
+ ansible.builtin.include_tasks: test_empty_list.yml
diff --git a/ansible_collections/community/general/tests/integration/targets/snap/tasks/test.yml b/ansible_collections/community/general/tests/integration/targets/snap/tasks/test.yml
new file mode 100644
index 000000000..3a77704b3
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/snap/tasks/test.yml
@@ -0,0 +1,235 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Make sure package is not installed (hello-world)
+ community.general.snap:
+ name: hello-world
+ state: absent
+
+- name: Install package (hello-world) (check mode)
+ community.general.snap:
+ name: hello-world
+ state: present
+ register: install_check
+ check_mode: true
+
+- name: Install package (hello-world)
+ community.general.snap:
+ name: hello-world
+ state: present
+ register: install
+
+- name: Install package again (hello-world) (check mode)
+ community.general.snap:
+ name: hello-world
+ state: present
+ register: install_again_check
+ check_mode: true
+
+- name: Install package again (hello-world)
+ community.general.snap:
+ name: hello-world
+ state: present
+ register: install_again
+
+- name: Assert package has been installed just once (hello-world)
+ assert:
+ that:
+ - install is changed
+ - install_check is changed
+ - install_again is not changed
+ - install_again_check is not changed
+
+- name: Check package has been installed correctly (hello-world)
+ command: hello-world
+ environment:
+ PATH: /snap/bin/
+
+- name: Remove package (hello-world) (check mode)
+ community.general.snap:
+ name: hello-world
+ state: absent
+ register: remove_check
+ check_mode: true
+
+- name: Remove package (hello-world)
+ community.general.snap:
+ name: hello-world
+ state: absent
+ register: remove
+
+- name: Remove package again (hello-world) (check mode)
+ community.general.snap:
+ name: hello-world
+ state: absent
+ register: remove_again_check
+ check_mode: true
+
+- name: Remove package again (hello-world)
+ community.general.snap:
+ name: hello-world
+ state: absent
+ register: remove_again
+
+- name: Assert package has been removed just once (hello-world)
+ assert:
+ that:
+ - remove is changed
+ - remove_check is changed
+ - remove_again is not changed
+ - remove_again_check is not changed
+
+- name: Make sure package from classic snap is not installed (nvim)
+ community.general.snap:
+ name: nvim
+ state: absent
+
+- name: Install package from classic snap (nvim)
+ community.general.snap:
+ name: nvim
+ state: present
+ classic: true
+ register: classic_install
+
+# testing classic idempotency
+- name: Install package from classic snap again (nvim)
+ community.general.snap:
+ name: nvim
+ state: present
+ classic: true
+ register: classic_install_again
+
+- name: Assert package has been installed just once (nvim)
+ assert:
+ that:
+ - classic_install is changed
+ - classic_install_again is not changed
+
+# this is just testing if a package which has been installed
+# with true classic can be removed without setting classic to true
+- name: Remove package from classic snap without setting classic to true (nvim)
+ community.general.snap:
+ name: nvim
+ state: absent
+ register: classic_remove_without_true_classic
+
+- name: Remove package from classic snap with setting classic to true (nvim)
+ community.general.snap:
+ name: nvim
+ state: absent
+ classic: true
+ register: classic_remove_with_true_classic
+
+- name: Assert package has been removed without setting classic to true (nvim)
+ assert:
+ that:
+ - classic_remove_without_true_classic is changed
+ - classic_remove_with_true_classic is not changed
+
+
+- name: Make sure package is not installed (uhttpd)
+ community.general.snap:
+ name: uhttpd
+ state: absent
+
+- name: Install package (uhttpd)
+ community.general.snap:
+ name: uhttpd
+ state: present
+ register: install
+
+- name: Install package (uhttpd)
+ community.general.snap:
+ name: uhttpd
+ state: present
+ options:
+ - "listening-port=8080"
+ register: install_with_option
+
+- name: Install package again with option (uhttpd)
+ community.general.snap:
+ name: uhttpd
+ state: present
+ options:
+ - "listening-port=8080"
+ register: install_with_option_again
+
+- name: Install package again with different options (uhttpd)
+ community.general.snap:
+ name: uhttpd
+ state: present
+ options:
+ - "listening-port=8088"
+ - "document-root-dir=/tmp"
+ register: install_with_option_changed
+
+- name: Remove package (uhttpd)
+ community.general.snap:
+ name: uhttpd
+ state: absent
+ register: remove
+
+- name: Assert package has been installed with options just once and only changed options trigger a change (uhttpd)
+ assert:
+ that:
+ - install is changed
+ - install_with_option is changed
+ - "install_with_option.options_changed[0] == 'uhttpd:listening-port=8080'"
+ - install_with_option_again is not changed
+ - install_with_option_changed is changed
+ - "'uhttpd:listening-port=8088' in install_with_option_changed.options_changed"
+ - "'uhttpd:document-root-dir=/tmp' in install_with_option_changed.options_changed"
+ - "'uhttpd:listening-port=8080' not in install_with_option_changed.options_changed"
+ - remove is changed
+
+- name: Install two packages at the same time
+ community.general.snap:
+ name:
+ - hello-world
+ - uhttpd
+ state: present
+ register: install_two
+
+- name: Install two packages at the same time (again)
+ community.general.snap:
+ name:
+ - hello-world
+ - uhttpd
+ state: present
+ register: install_two_again
+
+- name: Remove packages (hello-world & uhttpd)
+ community.general.snap:
+ name:
+ - hello-world
+ - uhttpd
+ state: absent
+ register: install_two_remove
+
+- name: Remove packages again (hello-world & uhttpd)
+ community.general.snap:
+ name:
+ - hello-world
+ - uhttpd
+ state: absent
+ register: install_two_remove_again
+
+- name: Assert installation of two packages
+ assert:
+ that:
+ - install_two is changed
+ - "'hello-world' in install_two.snaps_installed"
+ - "'uhttpd' in install_two.snaps_installed"
+ - install_two.snaps_removed is not defined
+ - install_two_again is not changed
+ - install_two_again.snaps_installed is not defined
+ - install_two_again.snaps_removed is not defined
+ - install_two_remove is changed
+ - install_two_again.snaps_installed is not defined
+ - "'hello-world' in install_two_remove.snaps_removed"
+ - "'uhttpd' in install_two_remove.snaps_removed"
+ - install_two_remove_again is not changed
+ - install_two_remove_again.snaps_installed is not defined
+ - install_two_remove_again.snaps_removed is not defined
diff --git a/ansible_collections/community/general/tests/integration/targets/snap/tasks/test_3dash.yml b/ansible_collections/community/general/tests/integration/targets/snap/tasks/test_3dash.yml
new file mode 100644
index 000000000..4d39c0a48
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/snap/tasks/test_3dash.yml
@@ -0,0 +1,31 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Make sure packages are not installed (3 dashes)
+ community.general.snap:
+ name:
+ - bw
+ - shellcheck
+ state: absent
+
+- name: Install package with 3 dashes in description (check)
+ community.general.snap:
+ name:
+ - bw
+ - shellcheck
+ state: present
+ check_mode: true
+ register: install_3dash_check
+
+- name: Remove packages (3 dashes)
+ community.general.snap:
+ name:
+ - bw
+ - shellcheck
+ state: absent
+
+- assert:
+ that:
+ - install_3dash_check is changed
diff --git a/ansible_collections/community/general/tests/integration/targets/snap/tasks/test_channel.yml b/ansible_collections/community/general/tests/integration/targets/snap/tasks/test_channel.yml
new file mode 100644
index 000000000..e9eb19c89
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/snap/tasks/test_channel.yml
@@ -0,0 +1,81 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# NOTE This is currently disabled for performance reasons!
+
+- name: Make sure package is not installed (microk8s)
+ community.general.snap:
+ name: microk8s
+ state: absent
+
+# Test for https://github.com/ansible-collections/community.general/issues/1606
+- name: Install package (microk8s)
+ community.general.snap:
+ name: microk8s
+ classic: true
+ state: present
+ register: install_microk8s
+
+- name: Install package with channel (microk8s)
+ community.general.snap:
+ name: microk8s
+ classic: true
+ channel: 1.20/stable
+ state: present
+ register: install_microk8s_chan
+
+- name: Install package with channel (microk8s) again
+ community.general.snap:
+ name: microk8s
+ classic: true
+ channel: 1.20/stable
+ state: present
+ register: install_microk8s_chan_again
+
+- name: Remove package (microk8s)
+ community.general.snap:
+ name: microk8s
+ state: absent
+ register: remove_microk8s
+
+- assert:
+ that:
+ - install_microk8s is changed
+ - install_microk8s_chan is changed
+ - install_microk8s_chan_again is not changed
+ - remove_microk8s is changed
+
+- name: Install package (shellcheck)
+ community.general.snap:
+ name: shellcheck
+ state: present
+ register: install_shellcheck
+
+- name: Install package with channel (shellcheck)
+ community.general.snap:
+ name: shellcheck
+ channel: edge
+ state: present
+ register: install_shellcheck_chan
+
+- name: Install package with channel (shellcheck) again
+ community.general.snap:
+ name: shellcheck
+ channel: edge
+ state: present
+ register: install_shellcheck_chan_again
+
+- name: Remove package (shellcheck)
+ community.general.snap:
+ name: shellcheck
+ state: absent
+ register: remove_shellcheck
+
+- assert:
+ that:
+ - install_shellcheck is changed
+ - install_shellcheck_chan is changed
+ - install_shellcheck_chan_again is not changed
+ - remove_shellcheck is changed
diff --git a/ansible_collections/community/general/tests/integration/targets/snap/tasks/test_dangerous.yml b/ansible_collections/community/general/tests/integration/targets/snap/tasks/test_dangerous.yml
new file mode 100644
index 000000000..8fe4edee0
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/snap/tasks/test_dangerous.yml
@@ -0,0 +1,53 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# NOTE This is currently disabled for performance reasons!
+
+- name: Make sure package is not installed (cider)
+ community.general.snap:
+ name: cider
+ state: absent
+
+- name: Download cider snap
+ ansible.builtin.get_url:
+ url: https://github.com/ciderapp/cider-releases/releases/download/v1.6.0/cider_1.6.0_amd64.snap
+ dest: "{{ remote_tmp_dir }}/cider_1.6.0_amd64.snap"
+ mode: "0644"
+
+# Test for https://github.com/ansible-collections/community.general/issues/5715
+- name: Install package from file (check)
+ community.general.snap:
+ name: "{{ remote_tmp_dir }}/cider_1.6.0_amd64.snap"
+ dangerous: true
+ state: present
+ check_mode: true
+ register: install_dangerous_check
+
+- name: Install package from file
+ community.general.snap:
+ name: "{{ remote_tmp_dir }}/cider_1.6.0_amd64.snap"
+ dangerous: true
+ state: present
+ register: install_dangerous
+
+- name: Install package from file
+ community.general.snap:
+ name: "{{ remote_tmp_dir }}/cider_1.6.0_amd64.snap"
+ dangerous: true
+ state: present
+ register: install_dangerous_idempot
+
+- name: Remove package
+ community.general.snap:
+ name: cider
+ state: absent
+ register: remove_dangerous
+
+- assert:
+ that:
+ - install_dangerous_check is changed
+ - install_dangerous is changed
+ - install_dangerous_idempot is not changed
+ - remove_dangerous is changed
diff --git a/ansible_collections/community/general/tests/integration/targets/snap/tasks/test_empty_list.yml b/ansible_collections/community/general/tests/integration/targets/snap/tasks/test_empty_list.yml
new file mode 100644
index 000000000..bea73cb5e
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/snap/tasks/test_empty_list.yml
@@ -0,0 +1,14 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Empty list present
+ community.general.snap:
+ name: []
+ state: present
+
+- name: Empty list absent
+ community.general.snap:
+ name: []
+ state: absent
diff --git a/ansible_collections/community/general/tests/integration/targets/ssh_config/aliases b/ansible_collections/community/general/tests/integration/targets/ssh_config/aliases
index 6011128da..2c5cf3237 100644
--- a/ansible_collections/community/general/tests/integration/targets/ssh_config/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/ssh_config/aliases
@@ -4,6 +4,5 @@
azp/posix/2
destructive
-skip/python2.6 # stromssh only supports python3
skip/python2.7 # stromssh only supports python3
skip/freebsd # stromssh installation fails on freebsd
diff --git a/ansible_collections/community/general/tests/integration/targets/ssh_config/tasks/options.yml b/ansible_collections/community/general/tests/integration/targets/ssh_config/tasks/options.yml
index 406de6831..f88f99081 100644
--- a/ansible_collections/community/general/tests/integration/targets/ssh_config/tasks/options.yml
+++ b/ansible_collections/community/general/tests/integration/targets/ssh_config/tasks/options.yml
@@ -15,7 +15,12 @@
host: "options.example.com"
proxycommand: "ssh jumphost.example.com -W %h:%p"
forward_agent: true
+ add_keys_to_agent: true
host_key_algorithms: "+ssh-rsa"
+ identities_only: true
+ controlmaster: "auto"
+ controlpath: "~/.ssh/sockets/%r@%h-%p"
+ controlpersist: yes
state: present
register: options_add
check_mode: true
@@ -33,7 +38,7 @@
src: "{{ ssh_config_test }}"
register: slurp_ssh_config
-- name: "Options - Verify that nothign was added to {{ ssh_config_test }} during change mode"
+- name: "Options - Verify that nothing was added to {{ ssh_config_test }} during change mode"
assert:
that:
- "'options.example.com' not in slurp_ssh_config['content'] | b64decode"
@@ -44,7 +49,12 @@
host: "options.example.com"
proxycommand: "ssh jumphost.example.com -W %h:%p"
forward_agent: true
+ add_keys_to_agent: true
host_key_algorithms: "+ssh-rsa"
+ identities_only: true
+ controlmaster: "auto"
+ controlpath: "~/.ssh/sockets/%r@%h-%p"
+ controlpersist: yes
state: present
register: options_add
@@ -62,7 +72,12 @@
host: "options.example.com"
proxycommand: "ssh jumphost.example.com -W %h:%p"
forward_agent: true
+ add_keys_to_agent: true
host_key_algorithms: "+ssh-rsa"
+ identities_only: true
+ controlmaster: "auto"
+ controlpath: "~/.ssh/sockets/%r@%h-%p"
+ controlpersist: yes
state: present
register: options_add_again
@@ -84,7 +99,12 @@
that:
- "'proxycommand ssh jumphost.example.com -W %h:%p' in slurp_ssh_config['content'] | b64decode"
- "'forwardagent yes' in slurp_ssh_config['content'] | b64decode"
+ - "'addkeystoagent yes' in slurp_ssh_config['content'] | b64decode"
- "'hostkeyalgorithms +ssh-rsa' in slurp_ssh_config['content'] | b64decode"
+ - "'identitiesonly yes' in slurp_ssh_config['content'] | b64decode"
+ - "'controlmaster auto' in slurp_ssh_config['content'] | b64decode"
+ - "'controlpath ~/.ssh/sockets/%r@%h-%p' in slurp_ssh_config['content'] | b64decode"
+ - "'controlpersist yes' in slurp_ssh_config['content'] | b64decode"
- name: Options - Update host
community.general.ssh_config:
@@ -92,7 +112,12 @@
host: "options.example.com"
proxycommand: "ssh new-jumphost.example.com -W %h:%p"
forward_agent: false
+ add_keys_to_agent: false
host_key_algorithms: "+ssh-ed25519"
+ identities_only: false
+ controlmaster: no
+ controlpath: "~/.ssh/new-sockets/%r@%h-%p"
+ controlpersist: "600"
state: present
register: options_update
@@ -112,7 +137,12 @@
host: "options.example.com"
proxycommand: "ssh new-jumphost.example.com -W %h:%p"
forward_agent: false
+ add_keys_to_agent: false
host_key_algorithms: "+ssh-ed25519"
+ identities_only: false
+ controlmaster: no
+ controlpath: "~/.ssh/new-sockets/%r@%h-%p"
+ controlpersist: "600"
state: present
register: options_update
@@ -135,7 +165,12 @@
that:
- "'proxycommand ssh new-jumphost.example.com -W %h:%p' in slurp_ssh_config['content'] | b64decode"
- "'forwardagent no' in slurp_ssh_config['content'] | b64decode"
+ - "'addkeystoagent no' in slurp_ssh_config['content'] | b64decode"
- "'hostkeyalgorithms +ssh-ed25519' in slurp_ssh_config['content'] | b64decode"
+ - "'identitiesonly no' in slurp_ssh_config['content'] | b64decode"
+ - "'controlmaster no' in slurp_ssh_config['content'] | b64decode"
+ - "'controlpath ~/.ssh/new-sockets/%r@%h-%p' in slurp_ssh_config['content'] | b64decode"
+ - "'controlpersist 600' in slurp_ssh_config['content'] | b64decode"
- name: Options - Ensure no update in case option exist in ssh_config file but wasn't defined in playbook
community.general.ssh_config:
@@ -163,7 +198,12 @@
that:
- "'proxycommand ssh new-jumphost.example.com -W %h:%p' in slurp_ssh_config['content'] | b64decode"
- "'forwardagent no' in slurp_ssh_config['content'] | b64decode"
+ - "'addkeystoagent no' in slurp_ssh_config['content'] | b64decode"
- "'hostkeyalgorithms +ssh-ed25519' in slurp_ssh_config['content'] | b64decode"
+ - "'identitiesonly no' in slurp_ssh_config['content'] | b64decode"
+ - "'controlmaster no' in slurp_ssh_config['content'] | b64decode"
+ - "'controlpath ~/.ssh/new-sockets/%r@%h-%p' in slurp_ssh_config['content'] | b64decode"
+ - "'controlpersist 600' in slurp_ssh_config['content'] | b64decode"
- name: Debug
debug:
@@ -209,7 +249,12 @@
that:
- "'proxycommand ssh new-jumphost.example.com -W %h:%p' not in slurp_ssh_config['content'] | b64decode"
- "'forwardagent no' not in slurp_ssh_config['content'] | b64decode"
+ - "'addkeystoagent no' not in slurp_ssh_config['content'] | b64decode"
- "'hostkeyalgorithms +ssh-ed25519' not in slurp_ssh_config['content'] | b64decode"
+ - "'identitiesonly no' not in slurp_ssh_config['content'] | b64decode"
+ - "'controlmaster auto' not in slurp_ssh_config['content'] | b64decode"
+ - "'controlpath ~/.ssh/sockets/%r@%h-%p' not in slurp_ssh_config['content'] | b64decode"
+ - "'controlpersist yes' not in slurp_ssh_config['content'] | b64decode"
# Proxycommand and ProxyJump are mutually exclusive.
# Reset ssh_config before testing options with proxyjump
@@ -225,7 +270,12 @@
host: "options.example.com"
proxyjump: "jumphost.example.com"
forward_agent: true
+ add_keys_to_agent: true
host_key_algorithms: "+ssh-rsa"
+ identities_only: true
+ controlmaster: "auto"
+ controlpath: "~/.ssh/sockets/%r@%h-%p"
+ controlpersist: yes
state: present
register: options_add
check_mode: true
@@ -243,7 +293,7 @@
src: "{{ ssh_config_test }}"
register: slurp_ssh_config
-- name: "Options - Verify that nothign was added to {{ ssh_config_test }} during change mode"
+- name: "Options - Verify that nothing was added to {{ ssh_config_test }} during change mode"
assert:
that:
- "'options.example.com' not in slurp_ssh_config['content'] | b64decode"
@@ -254,7 +304,12 @@
host: "options.example.com"
proxyjump: "jumphost.example.com"
forward_agent: true
+ add_keys_to_agent: true
host_key_algorithms: "+ssh-rsa"
+ identities_only: true
+ controlmaster: "auto"
+ controlpath: "~/.ssh/sockets/%r@%h-%p"
+ controlpersist: yes
state: present
register: options_add
@@ -272,7 +327,12 @@
host: "options.example.com"
proxyjump: "jumphost.example.com"
forward_agent: true
+ add_keys_to_agent: true
host_key_algorithms: "+ssh-rsa"
+ identities_only: true
+ controlmaster: "auto"
+ controlpath: "~/.ssh/sockets/%r@%h-%p"
+ controlpersist: yes
state: present
register: options_add_again
@@ -294,7 +354,12 @@
that:
- "'proxyjump jumphost.example.com' in slurp_ssh_config['content'] | b64decode"
- "'forwardagent yes' in slurp_ssh_config['content'] | b64decode"
+ - "'addkeystoagent yes' in slurp_ssh_config['content'] | b64decode"
- "'hostkeyalgorithms +ssh-rsa' in slurp_ssh_config['content'] | b64decode"
+ - "'identitiesonly yes' in slurp_ssh_config['content'] | b64decode"
+ - "'controlmaster auto' in slurp_ssh_config['content'] | b64decode"
+ - "'controlpath ~/.ssh/sockets/%r@%h-%p' in slurp_ssh_config['content'] | b64decode"
+ - "'controlpersist yes' in slurp_ssh_config['content'] | b64decode"
- name: Options - Update host
community.general.ssh_config:
@@ -302,7 +367,12 @@
host: "options.example.com"
proxyjump: "new-jumphost.example.com"
forward_agent: false
+ add_keys_to_agent: false
host_key_algorithms: "+ssh-ed25519"
+ identities_only: false
+ controlmaster: no
+ controlpath: "~/.ssh/new-sockets/%r@%h-%p"
+ controlpersist: "600"
state: present
register: options_update
@@ -322,7 +392,12 @@
host: "options.example.com"
proxyjump: "new-jumphost.example.com"
forward_agent: false
+ add_keys_to_agent: false
host_key_algorithms: "+ssh-ed25519"
+ identities_only: false
+ controlmaster: no
+ controlpath: "~/.ssh/new-sockets/%r@%h-%p"
+ controlpersist: "600"
state: present
register: options_update
@@ -345,7 +420,12 @@
that:
- "'proxyjump new-jumphost.example.com' in slurp_ssh_config['content'] | b64decode"
- "'forwardagent no' in slurp_ssh_config['content'] | b64decode"
+ - "'addkeystoagent no' in slurp_ssh_config['content'] | b64decode"
- "'hostkeyalgorithms +ssh-ed25519' in slurp_ssh_config['content'] | b64decode"
+ - "'identitiesonly no' in slurp_ssh_config['content'] | b64decode"
+ - "'controlmaster no' in slurp_ssh_config['content'] | b64decode"
+ - "'controlpath ~/.ssh/new-sockets/%r@%h-%p' in slurp_ssh_config['content'] | b64decode"
+ - "'controlpersist 600' in slurp_ssh_config['content'] | b64decode"
- name: Options - Ensure no update in case option exist in ssh_config file but wasn't defined in playbook
community.general.ssh_config:
@@ -373,7 +453,12 @@
that:
- "'proxyjump new-jumphost.example.com' in slurp_ssh_config['content'] | b64decode"
- "'forwardagent no' in slurp_ssh_config['content'] | b64decode"
+ - "'addkeystoagent no' in slurp_ssh_config['content'] | b64decode"
- "'hostkeyalgorithms +ssh-ed25519' in slurp_ssh_config['content'] | b64decode"
+ - "'identitiesonly no' in slurp_ssh_config['content'] | b64decode"
+ - "'controlmaster no' in slurp_ssh_config['content'] | b64decode"
+ - "'controlpath ~/.ssh/new-sockets/%r@%h-%p' in slurp_ssh_config['content'] | b64decode"
+ - "'controlpersist 600' in slurp_ssh_config['content'] | b64decode"
- name: Debug
debug:
@@ -419,4 +504,9 @@
that:
- "'proxyjump new-jumphost.example.com' not in slurp_ssh_config['content'] | b64decode"
- "'forwardagent no' not in slurp_ssh_config['content'] | b64decode"
+ - "'addkeystoagent no' not in slurp_ssh_config['content'] | b64decode"
- "'hostkeyalgorithms +ssh-ed25519' not in slurp_ssh_config['content'] | b64decode"
+ - "'identitiesonly no' not in slurp_ssh_config['content'] | b64decode"
+ - "'controlmaster auto' not in slurp_ssh_config['content'] | b64decode"
+ - "'controlpath ~/.ssh/sockets/%r@%h-%p' not in slurp_ssh_config['content'] | b64decode"
+ - "'controlpersist yes' not in slurp_ssh_config['content'] | b64decode"
diff --git a/ansible_collections/community/general/tests/integration/targets/sudoers/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/sudoers/tasks/main.yml
index dd62025d5..36397f41a 100644
--- a/ansible_collections/community/general/tests/integration/targets/sudoers/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/sudoers/tasks/main.yml
@@ -159,6 +159,20 @@
src: "{{ sudoers_path }}/my-sudo-rule-8"
register: rule_8_contents
+- name: Create rule with noexec parameters
+ community.general.sudoers:
+ name: my-sudo-rule-9
+ state: present
+ user: alice
+ commands: /usr/local/bin/command
+ noexec: true
+ register: rule_9
+
+- name: Grab contents of my-sudo-rule-9
+ ansible.builtin.slurp:
+ src: "{{ sudoers_path }}/my-sudo-rule-9"
+ register: rule_9_contents
+
- name: Revoke rule 1
community.general.sudoers:
name: my-sudo-rule-1
@@ -257,6 +271,7 @@
- "rule_6_contents['content'] | b64decode == 'alice ALL=(bob)NOPASSWD: /usr/local/bin/command\n'"
- "rule_7_contents['content'] | b64decode == 'alice host-1=NOPASSWD: /usr/local/bin/command\n'"
- "rule_8_contents['content'] | b64decode == 'alice ALL=NOPASSWD:SETENV: /usr/local/bin/command\n'"
+ - "rule_9_contents['content'] | b64decode == 'alice ALL=NOEXEC:NOPASSWD: /usr/local/bin/command\n'"
- name: Check revocation stat
ansible.builtin.assert:
diff --git a/ansible_collections/community/general/tests/integration/targets/sysrc/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/sysrc/tasks/main.yml
index 2c45c3b1c..ace38202f 100644
--- a/ansible_collections/community/general/tests/integration/targets/sysrc/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/sysrc/tasks/main.yml
@@ -140,11 +140,11 @@
- name: Test within jail
#
# NOTE: currently fails with FreeBSD 12 with minor version less than 4
- # NOTE: currently fails with FreeBSD 13 with minor version less than 1
+ # NOTE: currently fails with FreeBSD 13 with minor version less than 2
#
when: >-
ansible_distribution_version is version('12.4', '>=') and ansible_distribution_version is version('13', '<')
- or ansible_distribution_version is version('13.1', '>=')
+ or ansible_distribution_version is version('13.2', '>=')
block:
- name: Setup testjail
include_tasks: setup-testjail.yml
diff --git a/ansible_collections/community/general/tests/integration/targets/terraform/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/terraform/tasks/main.yml
index 1c66990be..d04757d8e 100644
--- a/ansible_collections/community/general/tests/integration/targets/terraform/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/terraform/tasks/main.yml
@@ -63,5 +63,5 @@
loop_control:
index_var: provider_index
-- name: Test Complex Varibles
+- name: Test Complex Variables
ansible.builtin.include_tasks: complex_variables.yml
diff --git a/ansible_collections/community/general/tests/integration/targets/test_fqdn_valid/aliases b/ansible_collections/community/general/tests/integration/targets/test_fqdn_valid/aliases
new file mode 100644
index 000000000..12d1d6617
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/test_fqdn_valid/aliases
@@ -0,0 +1,5 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+azp/posix/2
diff --git a/ansible_collections/community/dns/tests/integration/targets/wait_for_txt/runme.sh b/ansible_collections/community/general/tests/integration/targets/test_fqdn_valid/runme.sh
index 9265e7ee1..cd97ac949 100755
--- a/ansible_collections/community/dns/tests/integration/targets/wait_for_txt/runme.sh
+++ b/ansible_collections/community/general/tests/integration/targets/test_fqdn_valid/runme.sh
@@ -5,12 +5,11 @@
set -eux
-export ANSIBLE_TEST_PREFER_VENV=1 # see https://github.com/ansible/ansible/pull/73000#issuecomment-757012395; can be removed once Ansible 2.9 and ansible-base 2.10 support has been dropped
source virtualenv.sh
# Requirements have to be installed prior to running ansible-playbook
# because plugins and requirements are loaded before the task runs
-pip install dnspython
+pip install fqdn
ANSIBLE_ROLES_PATH=../ ansible-playbook runme.yml "$@"
diff --git a/ansible_collections/community/dns/tests/integration/targets/wait_for_txt/runme.yml b/ansible_collections/community/general/tests/integration/targets/test_fqdn_valid/runme.yml
index bcecb88e9..37f965b28 100644
--- a/ansible_collections/community/dns/tests/integration/targets/wait_for_txt/runme.yml
+++ b/ansible_collections/community/general/tests/integration/targets/test_fqdn_valid/runme.yml
@@ -5,4 +5,4 @@
- hosts: localhost
roles:
- - { role: wait_for_txt }
+ - {role: test_fqdn_valid}
diff --git a/ansible_collections/community/general/tests/integration/targets/test_fqdn_valid/tasks/fqdn_valid_1.yml b/ansible_collections/community/general/tests/integration/targets/test_fqdn_valid/tasks/fqdn_valid_1.yml
new file mode 100644
index 000000000..36cfffad0
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/test_fqdn_valid/tasks/fqdn_valid_1.yml
@@ -0,0 +1,58 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Debug ansible_version
+ ansible.builtin.debug:
+ var: ansible_version
+ when: debug_test|d(false)|bool
+ tags: t0
+
+- name: 1. Test valid hostnames. Default options.
+ block:
+ - name: "1. Default min_labels=1, allow_underscores=False"
+ ansible.builtin.debug:
+ msg: "hosts_invalid: {{ hosts_invalid }}"
+ when: debug_test|d(false)|bool
+ - name: Assert
+ ansible.builtin.assert:
+ that: hosts_invalid|difference(result)|length == 0
+ vars:
+ hosts_valid: "{{ names1|select('community.general.fqdn_valid') }}"
+ hosts_invalid: "{{ names1|difference(hosts_valid) }}"
+ result: [-rv.example.com, -rv, s_v]
+ tags: t1
+
+- name: 2. Test valid hostnames. allow_underscores=True
+ block:
+ - name: "2. allow_underscores=True, default min_labels=1"
+ ansible.builtin.debug:
+ msg: "hosts_invalid: {{ hosts_invalid }}"
+ when: debug_test|d(false)|bool
+ - name: Assert
+ ansible.builtin.assert:
+ that: hosts_invalid|difference(result)|length == 0
+ vars:
+ hosts_valid: "{{ names2|select('community.general.fqdn_valid',
+ allow_underscores=True) }}"
+ hosts_invalid: "{{ names2|difference(hosts_valid) }}"
+ result: [-rv]
+ tags: t2
+
+- name: 3. Test valid hostnames. min_labels=2, allow_underscores=True
+ block:
+ - name: "3. allow_underscores=True, min_labels=2"
+ ansible.builtin.debug:
+ msg: "hosts_invalid: {{ hosts_invalid }}"
+ when: debug_test|d(false)|bool
+ - name: Assert
+ ansible.builtin.assert:
+ that: hosts_invalid|difference(result)|length == 0
+ vars:
+ hosts_valid: "{{ names3|select('community.general.fqdn_valid',
+ min_labels=2,
+ allow_underscores=True) }}"
+ hosts_invalid: "{{ names3|difference(hosts_valid) }}"
+ result: [9rv, s_v-.x.y]
+ tags: t3
diff --git a/ansible_collections/community/general/tests/integration/targets/test_fqdn_valid/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/test_fqdn_valid/tasks/main.yml
new file mode 100644
index 000000000..3bb62555a
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/test_fqdn_valid/tasks/main.yml
@@ -0,0 +1,7 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Test fqdn_valid
+ ansible.builtin.import_tasks: fqdn_valid_1.yml
diff --git a/ansible_collections/community/general/tests/integration/targets/test_fqdn_valid/vars/main.yml b/ansible_collections/community/general/tests/integration/targets/test_fqdn_valid/vars/main.yml
new file mode 100644
index 000000000..ba0a0eb08
--- /dev/null
+++ b/ansible_collections/community/general/tests/integration/targets/test_fqdn_valid/vars/main.yml
@@ -0,0 +1,15 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+names1:
+ - srv.example.com
+ - 9rv.example.com
+ - -rv.example.com
+ - srv
+ - 9rv
+ - -rv
+ - s_v
+names2: [9rv, -rv, s_v]
+names3: [9rv, srv.x, s_v.x.y, s_v-.x.y]
diff --git a/ansible_collections/community/general/tests/integration/targets/timezone/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/timezone/tasks/main.yml
index 3644eeafa..721341592 100644
--- a/ansible_collections/community/general/tests/integration/targets/timezone/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/timezone/tasks/main.yml
@@ -77,6 +77,7 @@
when:
- ansible_facts.distribution ~ ansible_facts.distribution_major_version not in ['Fedora31', 'Fedora32']
- not (ansible_os_family == 'Alpine') # TODO
+ - not (ansible_distribution == 'Archlinux') # TODO
block:
- name: set timezone to Etc/UTC
timezone:
@@ -93,4 +94,4 @@
- name: Restore original system timezone - {{ original_timezone.diff.before.name }}
timezone:
name: "{{ original_timezone.diff.before.name }}"
- when: original_timezone is changed
+ when: original_timezone is changed and original_timezone.diff.before.name != 'n/a'
diff --git a/ansible_collections/community/general/tests/integration/targets/ufw/aliases b/ansible_collections/community/general/tests/integration/targets/ufw/aliases
index 2ef1a4133..209a1153e 100644
--- a/ansible_collections/community/general/tests/integration/targets/ufw/aliases
+++ b/ansible_collections/community/general/tests/integration/targets/ufw/aliases
@@ -11,6 +11,8 @@ skip/freebsd
skip/rhel8.0 # FIXME
skip/rhel9.0 # FIXME
skip/rhel9.1 # FIXME
+skip/rhel9.2 # FIXME
+skip/rhel9.3 # FIXME
skip/docker
needs/root
needs/target/setup_epel
diff --git a/ansible_collections/community/general/tests/integration/targets/xml/tasks/main.yml b/ansible_collections/community/general/tests/integration/targets/xml/tasks/main.yml
index fe46b3ae5..8235f1a6b 100644
--- a/ansible_collections/community/general/tests/integration/targets/xml/tasks/main.yml
+++ b/ansible_collections/community/general/tests/integration/targets/xml/tasks/main.yml
@@ -14,6 +14,15 @@
state: present
when: ansible_os_family == "FreeBSD"
+- name: Install requirements (RHEL 8)
+ package:
+ name:
+ - libxml2-devel
+ - libxslt-devel
+ - python3-lxml
+ state: present
+ when: ansible_distribution == "RedHat" and ansible_distribution_major_version == "8"
+
# Needed for MacOSX !
- name: Install lxml
pip:
diff --git a/ansible_collections/community/general/tests/sanity/extra/botmeta.py b/ansible_collections/community/general/tests/sanity/extra/botmeta.py
index 3b6c34834..459d3ba14 100755
--- a/ansible_collections/community/general/tests/sanity/extra/botmeta.py
+++ b/ansible_collections/community/general/tests/sanity/extra/botmeta.py
@@ -18,6 +18,10 @@ from voluptuous.humanize import humanize_error
IGNORE_NO_MAINTAINERS = [
+ 'docs/docsite/rst/filter_guide.rst',
+ 'docs/docsite/rst/filter_guide_abstract_informations.rst',
+ 'docs/docsite/rst/filter_guide_paths.rst',
+ 'docs/docsite/rst/filter_guide_selecting_json_data.rst',
'plugins/cache/memcached.py',
'plugins/cache/redis.py',
'plugins/callback/cgroup_memory_recap.py',
@@ -197,7 +201,7 @@ def main():
# Scan all files
unmatched = set(files)
- for dirs in ('plugins', 'tests', 'changelogs'):
+ for dirs in ('docs/docsite/rst', 'plugins', 'tests', 'changelogs'):
for dirpath, dirnames, filenames in os.walk(dirs):
for file in sorted(filenames):
if file.endswith('.pyc'):
diff --git a/ansible_collections/community/general/tests/sanity/extra/extra-docs.py b/ansible_collections/community/general/tests/sanity/extra/extra-docs.py
index c636beb08..251e6d70f 100755
--- a/ansible_collections/community/general/tests/sanity/extra/extra-docs.py
+++ b/ansible_collections/community/general/tests/sanity/extra/extra-docs.py
@@ -17,7 +17,7 @@ def main():
suffix = ':{env}'.format(env=env["ANSIBLE_COLLECTIONS_PATH"]) if 'ANSIBLE_COLLECTIONS_PATH' in env else ''
env['ANSIBLE_COLLECTIONS_PATH'] = '{root}{suffix}'.format(root=os.path.dirname(os.path.dirname(os.path.dirname(os.getcwd()))), suffix=suffix)
p = subprocess.run(
- ['antsibull-docs', 'lint-collection-docs', '--plugin-docs', '--disallow-semantic-markup', '--skip-rstcheck', '.'],
+ ['antsibull-docs', 'lint-collection-docs', '--plugin-docs', '--skip-rstcheck', '.'],
env=env,
check=False,
)
diff --git a/ansible_collections/community/general/tests/sanity/ignore-2.11.txt b/ansible_collections/community/general/tests/sanity/ignore-2.11.txt
deleted file mode 100644
index f2c30270c..000000000
--- a/ansible_collections/community/general/tests/sanity/ignore-2.11.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-.azure-pipelines/scripts/publish-codecov.py compile-2.6!skip # Uses Python 3.6+ syntax
-.azure-pipelines/scripts/publish-codecov.py compile-2.7!skip # Uses Python 3.6+ syntax
-.azure-pipelines/scripts/publish-codecov.py compile-3.5!skip # Uses Python 3.6+ syntax
-.azure-pipelines/scripts/publish-codecov.py future-import-boilerplate
-.azure-pipelines/scripts/publish-codecov.py metaclass-boilerplate
-.azure-pipelines/scripts/publish-codecov.py replace-urlopen
-plugins/modules/consul.py validate-modules:doc-missing-type
-plugins/modules/consul.py validate-modules:undocumented-parameter
-plugins/modules/consul_session.py validate-modules:parameter-state-invalid-choice
-plugins/modules/gconftool2.py validate-modules:parameter-state-invalid-choice # state=get - removed in 8.0.0
-plugins/modules/iptables_state.py validate-modules:undocumented-parameter # params _back and _timeout used by action plugin
-plugins/modules/lxc_container.py validate-modules:use-run-command-not-popen
-plugins/modules/manageiq_policies.py validate-modules:parameter-state-invalid-choice # state=list - removed in 8.0.0
-plugins/modules/manageiq_provider.py validate-modules:doc-choices-do-not-match-spec # missing docs on suboptions
-plugins/modules/manageiq_provider.py validate-modules:doc-missing-type # missing docs on suboptions
-plugins/modules/manageiq_provider.py validate-modules:parameter-type-not-in-doc # missing docs on suboptions
-plugins/modules/manageiq_provider.py validate-modules:undocumented-parameter # missing docs on suboptions
-plugins/modules/manageiq_tags.py validate-modules:parameter-state-invalid-choice
-plugins/modules/osx_defaults.py validate-modules:parameter-state-invalid-choice
-plugins/modules/parted.py validate-modules:parameter-state-invalid-choice
-plugins/modules/puppet.py validate-modules:parameter-invalid # invalid alias - removed in 7.0.0
-plugins/modules/rax_files_objects.py use-argspec-type-path
-plugins/modules/rax_files.py validate-modules:parameter-state-invalid-choice
-plugins/modules/rax.py use-argspec-type-path # fix needed
-plugins/modules/rhevm.py validate-modules:parameter-state-invalid-choice
-plugins/modules/xfconf.py validate-modules:return-syntax-error
-tests/integration/targets/django_manage/files/base_test/simple_project/p1/manage.py compile-2.6 # django generated code
-tests/integration/targets/django_manage/files/base_test/simple_project/p1/manage.py compile-2.7 # django generated code
diff --git a/ansible_collections/community/general/tests/sanity/ignore-2.12.txt b/ansible_collections/community/general/tests/sanity/ignore-2.12.txt
deleted file mode 100644
index a8e04ff30..000000000
--- a/ansible_collections/community/general/tests/sanity/ignore-2.12.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-.azure-pipelines/scripts/publish-codecov.py replace-urlopen
-plugins/modules/consul.py validate-modules:doc-missing-type
-plugins/modules/consul.py validate-modules:undocumented-parameter
-plugins/modules/consul_session.py validate-modules:parameter-state-invalid-choice
-plugins/modules/gconftool2.py validate-modules:parameter-state-invalid-choice # state=get - removed in 8.0.0
-plugins/modules/iptables_state.py validate-modules:undocumented-parameter # params _back and _timeout used by action plugin
-plugins/modules/lxc_container.py validate-modules:use-run-command-not-popen
-plugins/modules/manageiq_policies.py validate-modules:parameter-state-invalid-choice # state=list - removed in 8.0.0
-plugins/modules/manageiq_provider.py validate-modules:doc-choices-do-not-match-spec # missing docs on suboptions
-plugins/modules/manageiq_provider.py validate-modules:doc-missing-type # missing docs on suboptions
-plugins/modules/manageiq_provider.py validate-modules:parameter-type-not-in-doc # missing docs on suboptions
-plugins/modules/manageiq_provider.py validate-modules:undocumented-parameter # missing docs on suboptions
-plugins/modules/manageiq_tags.py validate-modules:parameter-state-invalid-choice
-plugins/modules/osx_defaults.py validate-modules:parameter-state-invalid-choice
-plugins/modules/parted.py validate-modules:parameter-state-invalid-choice
-plugins/modules/puppet.py validate-modules:parameter-invalid # invalid alias - removed in 7.0.0
-plugins/modules/rax_files_objects.py use-argspec-type-path
-plugins/modules/rax_files.py validate-modules:parameter-state-invalid-choice
-plugins/modules/rax.py use-argspec-type-path # fix needed
-plugins/modules/rhevm.py validate-modules:parameter-state-invalid-choice
-plugins/modules/xfconf.py validate-modules:return-syntax-error
diff --git a/ansible_collections/community/general/tests/sanity/ignore-2.13.txt b/ansible_collections/community/general/tests/sanity/ignore-2.13.txt
index a8e04ff30..0665ddc1a 100644
--- a/ansible_collections/community/general/tests/sanity/ignore-2.13.txt
+++ b/ansible_collections/community/general/tests/sanity/ignore-2.13.txt
@@ -1,21 +1,15 @@
.azure-pipelines/scripts/publish-codecov.py replace-urlopen
-plugins/modules/consul.py validate-modules:doc-missing-type
-plugins/modules/consul.py validate-modules:undocumented-parameter
+plugins/lookup/etcd.py validate-modules:invalid-documentation
+plugins/lookup/etcd3.py validate-modules:invalid-documentation
plugins/modules/consul_session.py validate-modules:parameter-state-invalid-choice
-plugins/modules/gconftool2.py validate-modules:parameter-state-invalid-choice # state=get - removed in 8.0.0
plugins/modules/iptables_state.py validate-modules:undocumented-parameter # params _back and _timeout used by action plugin
plugins/modules/lxc_container.py validate-modules:use-run-command-not-popen
-plugins/modules/manageiq_policies.py validate-modules:parameter-state-invalid-choice # state=list - removed in 8.0.0
-plugins/modules/manageiq_provider.py validate-modules:doc-choices-do-not-match-spec # missing docs on suboptions
-plugins/modules/manageiq_provider.py validate-modules:doc-missing-type # missing docs on suboptions
-plugins/modules/manageiq_provider.py validate-modules:parameter-type-not-in-doc # missing docs on suboptions
-plugins/modules/manageiq_provider.py validate-modules:undocumented-parameter # missing docs on suboptions
-plugins/modules/manageiq_tags.py validate-modules:parameter-state-invalid-choice
plugins/modules/osx_defaults.py validate-modules:parameter-state-invalid-choice
plugins/modules/parted.py validate-modules:parameter-state-invalid-choice
-plugins/modules/puppet.py validate-modules:parameter-invalid # invalid alias - removed in 7.0.0
-plugins/modules/rax_files_objects.py use-argspec-type-path
-plugins/modules/rax_files.py validate-modules:parameter-state-invalid-choice
-plugins/modules/rax.py use-argspec-type-path # fix needed
+plugins/modules/rax_files_objects.py use-argspec-type-path # module deprecated - removed in 9.0.0
+plugins/modules/rax_files.py validate-modules:parameter-state-invalid-choice # module deprecated - removed in 9.0.0
+plugins/modules/rax.py use-argspec-type-path # module deprecated - removed in 9.0.0
+plugins/modules/read_csv.py validate-modules:invalid-documentation
plugins/modules/rhevm.py validate-modules:parameter-state-invalid-choice
plugins/modules/xfconf.py validate-modules:return-syntax-error
+tests/unit/plugins/modules/test_gio_mime.yaml no-smart-quotes
diff --git a/ansible_collections/community/general/tests/sanity/ignore-2.14.txt b/ansible_collections/community/general/tests/sanity/ignore-2.14.txt
index 7e00143a6..fed147e44 100644
--- a/ansible_collections/community/general/tests/sanity/ignore-2.14.txt
+++ b/ansible_collections/community/general/tests/sanity/ignore-2.14.txt
@@ -1,23 +1,17 @@
.azure-pipelines/scripts/publish-codecov.py replace-urlopen
-plugins/modules/consul.py validate-modules:doc-missing-type
-plugins/modules/consul.py validate-modules:undocumented-parameter
+plugins/lookup/etcd.py validate-modules:invalid-documentation
+plugins/lookup/etcd3.py validate-modules:invalid-documentation
plugins/modules/consul_session.py validate-modules:parameter-state-invalid-choice
-plugins/modules/gconftool2.py validate-modules:parameter-state-invalid-choice # state=get - removed in 8.0.0
plugins/modules/homectl.py import-3.11 # Uses deprecated stdlib library 'crypt'
plugins/modules/iptables_state.py validate-modules:undocumented-parameter # params _back and _timeout used by action plugin
plugins/modules/lxc_container.py validate-modules:use-run-command-not-popen
-plugins/modules/manageiq_policies.py validate-modules:parameter-state-invalid-choice # state=list - removed in 8.0.0
-plugins/modules/manageiq_provider.py validate-modules:doc-choices-do-not-match-spec # missing docs on suboptions
-plugins/modules/manageiq_provider.py validate-modules:doc-missing-type # missing docs on suboptions
-plugins/modules/manageiq_provider.py validate-modules:parameter-type-not-in-doc # missing docs on suboptions
-plugins/modules/manageiq_provider.py validate-modules:undocumented-parameter # missing docs on suboptions
-plugins/modules/manageiq_tags.py validate-modules:parameter-state-invalid-choice
plugins/modules/osx_defaults.py validate-modules:parameter-state-invalid-choice
plugins/modules/parted.py validate-modules:parameter-state-invalid-choice
-plugins/modules/puppet.py validate-modules:parameter-invalid # invalid alias - removed in 7.0.0
-plugins/modules/rax_files_objects.py use-argspec-type-path
-plugins/modules/rax_files.py validate-modules:parameter-state-invalid-choice
-plugins/modules/rax.py use-argspec-type-path # fix needed
+plugins/modules/rax_files_objects.py use-argspec-type-path # module deprecated - removed in 9.0.0
+plugins/modules/rax_files.py validate-modules:parameter-state-invalid-choice # module deprecated - removed in 9.0.0
+plugins/modules/rax.py use-argspec-type-path # module deprecated - removed in 9.0.0
+plugins/modules/read_csv.py validate-modules:invalid-documentation
plugins/modules/rhevm.py validate-modules:parameter-state-invalid-choice
plugins/modules/udm_user.py import-3.11 # Uses deprecated stdlib library 'crypt'
plugins/modules/xfconf.py validate-modules:return-syntax-error
+tests/unit/plugins/modules/test_gio_mime.yaml no-smart-quotes
diff --git a/ansible_collections/community/general/tests/sanity/ignore-2.15.txt b/ansible_collections/community/general/tests/sanity/ignore-2.15.txt
index 7e00143a6..d4c92c4d9 100644
--- a/ansible_collections/community/general/tests/sanity/ignore-2.15.txt
+++ b/ansible_collections/community/general/tests/sanity/ignore-2.15.txt
@@ -1,23 +1,14 @@
.azure-pipelines/scripts/publish-codecov.py replace-urlopen
-plugins/modules/consul.py validate-modules:doc-missing-type
-plugins/modules/consul.py validate-modules:undocumented-parameter
plugins/modules/consul_session.py validate-modules:parameter-state-invalid-choice
-plugins/modules/gconftool2.py validate-modules:parameter-state-invalid-choice # state=get - removed in 8.0.0
plugins/modules/homectl.py import-3.11 # Uses deprecated stdlib library 'crypt'
plugins/modules/iptables_state.py validate-modules:undocumented-parameter # params _back and _timeout used by action plugin
plugins/modules/lxc_container.py validate-modules:use-run-command-not-popen
-plugins/modules/manageiq_policies.py validate-modules:parameter-state-invalid-choice # state=list - removed in 8.0.0
-plugins/modules/manageiq_provider.py validate-modules:doc-choices-do-not-match-spec # missing docs on suboptions
-plugins/modules/manageiq_provider.py validate-modules:doc-missing-type # missing docs on suboptions
-plugins/modules/manageiq_provider.py validate-modules:parameter-type-not-in-doc # missing docs on suboptions
-plugins/modules/manageiq_provider.py validate-modules:undocumented-parameter # missing docs on suboptions
-plugins/modules/manageiq_tags.py validate-modules:parameter-state-invalid-choice
plugins/modules/osx_defaults.py validate-modules:parameter-state-invalid-choice
plugins/modules/parted.py validate-modules:parameter-state-invalid-choice
-plugins/modules/puppet.py validate-modules:parameter-invalid # invalid alias - removed in 7.0.0
-plugins/modules/rax_files_objects.py use-argspec-type-path
-plugins/modules/rax_files.py validate-modules:parameter-state-invalid-choice
-plugins/modules/rax.py use-argspec-type-path # fix needed
+plugins/modules/rax_files_objects.py use-argspec-type-path # module deprecated - removed in 9.0.0
+plugins/modules/rax_files.py validate-modules:parameter-state-invalid-choice # module deprecated - removed in 9.0.0
+plugins/modules/rax.py use-argspec-type-path # module deprecated - removed in 9.0.0
plugins/modules/rhevm.py validate-modules:parameter-state-invalid-choice
plugins/modules/udm_user.py import-3.11 # Uses deprecated stdlib library 'crypt'
plugins/modules/xfconf.py validate-modules:return-syntax-error
+tests/unit/plugins/modules/test_gio_mime.yaml no-smart-quotes
diff --git a/ansible_collections/community/general/tests/sanity/ignore-2.16.txt b/ansible_collections/community/general/tests/sanity/ignore-2.16.txt
index 5fa3d90ba..397c6d986 100644
--- a/ansible_collections/community/general/tests/sanity/ignore-2.16.txt
+++ b/ansible_collections/community/general/tests/sanity/ignore-2.16.txt
@@ -1,23 +1,15 @@
-.azure-pipelines/scripts/publish-codecov.py replace-urlopen
-plugins/modules/consul.py validate-modules:doc-missing-type
-plugins/modules/consul.py validate-modules:undocumented-parameter
plugins/modules/consul_session.py validate-modules:parameter-state-invalid-choice
-plugins/modules/gconftool2.py validate-modules:parameter-state-invalid-choice # state=get - removed in 8.0.0
plugins/modules/homectl.py import-3.11 # Uses deprecated stdlib library 'crypt'
+plugins/modules/homectl.py import-3.12 # Uses deprecated stdlib library 'crypt'
plugins/modules/iptables_state.py validate-modules:undocumented-parameter # params _back and _timeout used by action plugin
plugins/modules/lxc_container.py validate-modules:use-run-command-not-popen
-plugins/modules/manageiq_policies.py validate-modules:parameter-state-invalid-choice # state=list - removed in 8.0.0
-plugins/modules/manageiq_provider.py validate-modules:doc-choices-do-not-match-spec # missing docs on suboptions
-plugins/modules/manageiq_provider.py validate-modules:doc-missing-type # missing docs on suboptions
-plugins/modules/manageiq_provider.py validate-modules:parameter-type-not-in-doc # missing docs on suboptions
-plugins/modules/manageiq_provider.py validate-modules:undocumented-parameter # missing docs on suboptions
-plugins/modules/manageiq_tags.py validate-modules:parameter-state-invalid-choice # state=list - removed in 8.0.0
plugins/modules/osx_defaults.py validate-modules:parameter-state-invalid-choice
plugins/modules/parted.py validate-modules:parameter-state-invalid-choice
-plugins/modules/puppet.py validate-modules:parameter-invalid # invalid alias - removed in 7.0.0
plugins/modules/rax_files_objects.py use-argspec-type-path # module deprecated - removed in 9.0.0
plugins/modules/rax_files.py validate-modules:parameter-state-invalid-choice # module deprecated - removed in 9.0.0
plugins/modules/rax.py use-argspec-type-path # module deprecated - removed in 9.0.0
plugins/modules/rhevm.py validate-modules:parameter-state-invalid-choice
plugins/modules/udm_user.py import-3.11 # Uses deprecated stdlib library 'crypt'
+plugins/modules/udm_user.py import-3.12 # Uses deprecated stdlib library 'crypt'
plugins/modules/xfconf.py validate-modules:return-syntax-error
+tests/unit/plugins/modules/test_gio_mime.yaml no-smart-quotes
diff --git a/ansible_collections/community/general/tests/sanity/ignore-2.17.txt b/ansible_collections/community/general/tests/sanity/ignore-2.17.txt
new file mode 100644
index 000000000..d75aaeac2
--- /dev/null
+++ b/ansible_collections/community/general/tests/sanity/ignore-2.17.txt
@@ -0,0 +1,17 @@
+plugins/modules/consul_session.py validate-modules:parameter-state-invalid-choice
+plugins/modules/homectl.py import-3.11 # Uses deprecated stdlib library 'crypt'
+plugins/modules/homectl.py import-3.12 # Uses deprecated stdlib library 'crypt'
+plugins/modules/iptables_state.py validate-modules:undocumented-parameter # params _back and _timeout used by action plugin
+plugins/modules/lxc_container.py validate-modules:use-run-command-not-popen
+plugins/modules/osx_defaults.py validate-modules:parameter-state-invalid-choice
+plugins/modules/parted.py validate-modules:parameter-state-invalid-choice
+plugins/modules/rax_files_objects.py use-argspec-type-path # module deprecated - removed in 9.0.0
+plugins/modules/rax_files.py validate-modules:parameter-state-invalid-choice # module deprecated - removed in 9.0.0
+plugins/modules/rax.py use-argspec-type-path # module deprecated - removed in 9.0.0
+plugins/modules/rhevm.py validate-modules:parameter-state-invalid-choice
+plugins/modules/udm_user.py import-3.11 # Uses deprecated stdlib library 'crypt'
+plugins/modules/udm_user.py import-3.12 # Uses deprecated stdlib library 'crypt'
+plugins/modules/xfconf.py validate-modules:return-syntax-error
+plugins/module_utils/univention_umc.py pylint:use-yield-from # suggested construct does not work with Python 2
+tests/unit/compat/mock.py pylint:use-yield-from # suggested construct does not work with Python 2
+tests/unit/plugins/modules/test_gio_mime.yaml no-smart-quotes
diff --git a/ansible_collections/community/general/tests/sanity/ignore-2.17.txt.license b/ansible_collections/community/general/tests/sanity/ignore-2.17.txt.license
new file mode 100644
index 000000000..edff8c768
--- /dev/null
+++ b/ansible_collections/community/general/tests/sanity/ignore-2.17.txt.license
@@ -0,0 +1,3 @@
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
+SPDX-FileCopyrightText: Ansible Project
diff --git a/ansible_collections/community/general/tests/unit/mock/loader.py b/ansible_collections/community/general/tests/unit/mock/loader.py
index 948f4eecd..f7aff17c3 100644
--- a/ansible_collections/community/general/tests/unit/mock/loader.py
+++ b/ansible_collections/community/general/tests/unit/mock/loader.py
@@ -17,7 +17,7 @@ class DictDataLoader(DataLoader):
def __init__(self, file_mapping=None):
file_mapping = {} if file_mapping is None else file_mapping
- assert type(file_mapping) == dict
+ assert isinstance(file_mapping, dict)
super(DictDataLoader, self).__init__()
diff --git a/ansible_collections/community/general/tests/unit/plugins/become/helper.py b/ansible_collections/community/general/tests/unit/plugins/become/helper.py
index 9949e1bef..d2a7df97f 100644
--- a/ansible_collections/community/general/tests/unit/plugins/become/helper.py
+++ b/ansible_collections/community/general/tests/unit/plugins/become/helper.py
@@ -12,7 +12,7 @@ from ansible.plugins.loader import become_loader, get_shell_plugin
def call_become_plugin(task, var_options, cmd, executable=None):
- """Helper function to call become plugin simiarly on how Ansible itself handles this."""
+ """Helper function to call become plugin similarly on how Ansible itself handles this."""
plugin = become_loader.get(task['become_method'])
plugin.set_options(task_keys=task, var_options=var_options)
shell = get_shell_plugin(executable=executable)
diff --git a/ansible_collections/community/general/tests/unit/plugins/callback/test_loganalytics.py b/ansible_collections/community/general/tests/unit/plugins/callback/test_loganalytics.py
index f9fef3c5d..17932ed5f 100644
--- a/ansible_collections/community/general/tests/unit/plugins/callback/test_loganalytics.py
+++ b/ansible_collections/community/general/tests/unit/plugins/callback/test_loganalytics.py
@@ -12,6 +12,7 @@ from ansible_collections.community.general.plugins.callback.loganalytics import
from datetime import datetime
import json
+import sys
class TestAzureLogAnalytics(unittest.TestCase):
@@ -27,6 +28,10 @@ class TestAzureLogAnalytics(unittest.TestCase):
self.mock_host = Mock('MockHost')
self.mock_host.name = 'myhost'
+ # Add backward compatibility
+ if sys.version_info < (3, 2):
+ self.assertRegex = self.assertRegexpMatches
+
@patch('ansible_collections.community.general.plugins.callback.loganalytics.datetime')
@patch('ansible_collections.community.general.plugins.callback.loganalytics.open_url')
def test_overall(self, open_url_mock, mock_datetime):
@@ -62,5 +67,5 @@ class TestAzureLogAnalytics(unittest.TestCase):
args, kwargs = open_url_mock.call_args
headers = kwargs['headers']
- self.assertRegexpMatches(headers['Authorization'], r'^SharedKey 01234567-0123-0123-0123-01234567890a:.*=$')
+ self.assertRegex(headers['Authorization'], r'^SharedKey 01234567-0123-0123-0123-01234567890a:.*=$')
self.assertEqual(headers['Log-Type'], 'ansible_playbook')
diff --git a/ansible_collections/community/general/tests/unit/plugins/connection/test_lxc.py b/ansible_collections/community/general/tests/unit/plugins/connection/test_lxc.py
index 8733a92e0..bebd42772 100644
--- a/ansible_collections/community/general/tests/unit/plugins/connection/test_lxc.py
+++ b/ansible_collections/community/general/tests/unit/plugins/connection/test_lxc.py
@@ -6,20 +6,138 @@
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
+import pytest
+import sys
+
from io import StringIO
-from ansible_collections.community.general.tests.unit.compat import unittest
-from ansible_collections.community.general.plugins.connection import lxc
+from ansible.errors import AnsibleError
from ansible.playbook.play_context import PlayContext
+from ansible.plugins.loader import connection_loader
+from ansible_collections.community.general.tests.unit.compat import mock
+
+
+@pytest.fixture(autouse=True)
+def lxc(request):
+ """Fixture to import/load the lxc plugin module.
+
+ The fixture parameter is used to determine the presence of liblxc.
+ When true (default), a mocked liblxc module is injected. If False,
+ no liblxc will be present.
+ """
+ liblxc_present = getattr(request, 'param', True)
+
+ class ContainerMock():
+ # dict of container name to its state
+ _container_states = {}
+
+ def __init__(self, name):
+ super(ContainerMock, self).__init__()
+ self.name = name
+
+ @property
+ def state(self):
+ return ContainerMock._container_states.get(self.name, 'STARTED')
+
+ liblxc_module_mock = mock.MagicMock()
+ liblxc_module_mock.Container = ContainerMock
+
+ with mock.patch.dict('sys.modules'):
+ if liblxc_present:
+ sys.modules['lxc'] = liblxc_module_mock
+ elif 'lxc' in sys.modules:
+ del sys.modules['lxc']
+
+ from ansible_collections.community.general.plugins.connection import lxc as lxc_plugin_module
+
+ assert lxc_plugin_module.HAS_LIBLXC == liblxc_present
+ assert bool(getattr(lxc_plugin_module, '_lxc', None)) == liblxc_present
+
+ yield lxc_plugin_module
+
+
+class TestLXCConnectionClass():
+
+ @pytest.mark.parametrize('lxc', [True, False], indirect=True)
+ def test_lxc_connection_module(self, lxc):
+ """Test that a connection can be created with the plugin."""
+ play_context = PlayContext()
+ in_stream = StringIO()
+ conn = connection_loader.get('lxc', play_context, in_stream)
+ assert conn
+ assert isinstance(conn, lxc.Connection)
-class TestLXCConnectionClass(unittest.TestCase):
+ @pytest.mark.parametrize('lxc', [False], indirect=True)
+ def test_lxc_connection_liblxc_error(self, lxc):
+ """Test that on connect an error is thrown if liblxc is not present."""
+ play_context = PlayContext()
+ in_stream = StringIO()
+ conn = connection_loader.get('lxc', play_context, in_stream)
+
+ with pytest.raises(AnsibleError, match='lxc python bindings are not installed'):
+ conn._connect()
- def test_lxc_connection_module(self):
+ def test_remote_addr_option(self):
+ """Test that the remote_addr option is used"""
play_context = PlayContext()
- play_context.prompt = (
- '[sudo via ansible, key=ouzmdnewuhucvuaabtjmweasarviygqq] password: '
- )
in_stream = StringIO()
+ conn = connection_loader.get('lxc', play_context, in_stream)
+
+ container_name = 'my-container'
+ conn.set_option('remote_addr', container_name)
+ assert conn.get_option('remote_addr') == container_name
+
+ conn._connect()
+ assert conn.container_name == container_name
+
+ def test_error_when_stopped(self, lxc):
+ """Test that on connect an error is thrown if the container is stopped."""
+ play_context = PlayContext()
+ in_stream = StringIO()
+ conn = connection_loader.get('lxc', play_context, in_stream)
+ conn.set_option('remote_addr', 'my-container')
+
+ lxc._lxc.Container._container_states['my-container'] = 'STOPPED'
+
+ with pytest.raises(AnsibleError, match='my-container is not running'):
+ conn._connect()
+
+ def test_container_name_change(self):
+ """Test connect method reconnects when remote_addr changes"""
+ play_context = PlayContext()
+ in_stream = StringIO()
+ conn = connection_loader.get('lxc', play_context, in_stream)
+
+ # setting the option does nothing
+ container1_name = 'my-container'
+ conn.set_option('remote_addr', container1_name)
+ assert conn.container_name is None
+ assert conn.container is None
+
+ # first call initializes the connection
+ conn._connect()
+ assert conn.container_name is container1_name
+ assert conn.container is not None
+ assert conn.container.name == container1_name
+ container1 = conn.container
+
+ # second call is basically a no-op
+ conn._connect()
+ assert conn.container_name is container1_name
+ assert conn.container is container1
+ assert conn.container.name == container1_name
+
+ # setting the option does again nothing
+ container2_name = 'my-other-container'
+ conn.set_option('remote_addr', container2_name)
+ assert conn.container_name == container1_name
+ assert conn.container is container1
+ assert conn.container.name == container1_name
- self.assertIsInstance(lxc.Connection(play_context, in_stream), lxc.Connection)
+ # first call with a different remote_addr changes the connection
+ conn._connect()
+ assert conn.container_name == container2_name
+ assert conn.container is not None
+ assert conn.container is not container1
+ assert conn.container.name == container2_name
diff --git a/ansible_collections/community/general/tests/unit/plugins/inventory/test_icinga2.py b/ansible_collections/community/general/tests/unit/plugins/inventory/test_icinga2.py
index e3928b0db..859f29d3b 100644
--- a/ansible_collections/community/general/tests/unit/plugins/inventory/test_icinga2.py
+++ b/ansible_collections/community/general/tests/unit/plugins/inventory/test_icinga2.py
@@ -86,6 +86,8 @@ def get_option(option):
return {}
elif option == 'strict':
return False
+ elif option == 'group_by_hostgroups':
+ return True
else:
return None
@@ -96,6 +98,7 @@ def test_populate(inventory, mocker):
inventory.icinga2_password = 'password'
inventory.icinga2_url = 'https://localhost:5665' + '/v1'
inventory.inventory_attr = "address"
+ inventory.group_by_hostgroups = True
# bypass authentication and API fetch calls
inventory._check_api = mocker.MagicMock(side_effect=check_api)
diff --git a/ansible_collections/community/general/tests/unit/plugins/inventory/test_linode.py b/ansible_collections/community/general/tests/unit/plugins/inventory/test_linode.py
index a4f556761..0f239f2dd 100644
--- a/ansible_collections/community/general/tests/unit/plugins/inventory/test_linode.py
+++ b/ansible_collections/community/general/tests/unit/plugins/inventory/test_linode.py
@@ -37,11 +37,25 @@ def test_missing_access_token_lookup(inventory):
assert 'Could not retrieve Linode access token' in error_message
-def test_verify_file(tmp_path, inventory):
+def test_verify_file_yml(tmp_path, inventory):
file = tmp_path / "foobar.linode.yml"
file.touch()
assert inventory.verify_file(str(file)) is True
+def test_verify_file_yaml(tmp_path, inventory):
+ file = tmp_path / "foobar.linode.yaml"
+ file.touch()
+ assert inventory.verify_file(str(file)) is True
+
+
+def test_verify_file_bad_config_yml(inventory):
+ assert inventory.verify_file("foobar.linode.yml") is False
+
+
+def test_verify_file_bad_config_yaml(inventory):
+ assert inventory.verify_file("foobar.linode.yaml") is False
+
+
def test_verify_file_bad_config(inventory):
- assert inventory.verify_file('foobar.linode.yml') is False
+ assert inventory.verify_file("foobar.wrongcloud.yml") is False
diff --git a/ansible_collections/community/general/tests/unit/plugins/inventory/test_proxmox.py b/ansible_collections/community/general/tests/unit/plugins/inventory/test_proxmox.py
index 13832c938..ea6c84bcd 100644
--- a/ansible_collections/community/general/tests/unit/plugins/inventory/test_proxmox.py
+++ b/ansible_collections/community/general/tests/unit/plugins/inventory/test_proxmox.py
@@ -646,13 +646,15 @@ def test_populate(inventory, mocker):
inventory.group_prefix = 'proxmox_'
inventory.facts_prefix = 'proxmox_'
inventory.strict = False
+ inventory.exclude_nodes = False
opts = {
'group_prefix': 'proxmox_',
'facts_prefix': 'proxmox_',
'want_facts': True,
'want_proxmox_nodes_ansible_host': True,
- 'qemu_extended_statuses': True
+ 'qemu_extended_statuses': True,
+ 'exclude_nodes': False
}
# bypass authentication and API fetch calls
@@ -723,13 +725,15 @@ def test_populate_missing_qemu_extended_groups(inventory, mocker):
inventory.group_prefix = 'proxmox_'
inventory.facts_prefix = 'proxmox_'
inventory.strict = False
+ inventory.exclude_nodes = False
opts = {
'group_prefix': 'proxmox_',
'facts_prefix': 'proxmox_',
'want_facts': True,
'want_proxmox_nodes_ansible_host': True,
- 'qemu_extended_statuses': False
+ 'qemu_extended_statuses': False,
+ 'exclude_nodes': False
}
# bypass authentication and API fetch calls
@@ -743,3 +747,40 @@ def test_populate_missing_qemu_extended_groups(inventory, mocker):
# make sure that ['prelaunch', 'paused'] are not in the group list
for group in ['paused', 'prelaunch']:
assert ('%sall_%s' % (inventory.group_prefix, group)) not in inventory.inventory.groups
+
+
+def test_populate_exclude_nodes(inventory, mocker):
+ # module settings
+ inventory.proxmox_user = 'root@pam'
+ inventory.proxmox_password = 'password'
+ inventory.proxmox_url = 'https://localhost:8006'
+ inventory.group_prefix = 'proxmox_'
+ inventory.facts_prefix = 'proxmox_'
+ inventory.strict = False
+ inventory.exclude_nodes = True
+
+ opts = {
+ 'group_prefix': 'proxmox_',
+ 'facts_prefix': 'proxmox_',
+ 'want_facts': True,
+ 'want_proxmox_nodes_ansible_host': True,
+ 'qemu_extended_statuses': False,
+ 'exclude_nodes': True
+ }
+
+ # bypass authentication and API fetch calls
+ inventory._get_auth = mocker.MagicMock(side_effect=get_auth)
+ inventory._get_json = mocker.MagicMock(side_effect=get_json)
+ inventory._get_vm_snapshots = mocker.MagicMock(side_effect=get_vm_snapshots)
+ inventory.get_option = mocker.MagicMock(side_effect=get_option(opts))
+ inventory._can_add_host = mocker.MagicMock(return_value=True)
+ inventory._populate()
+
+ # make sure that nodes are not in the inventory
+ for node in ['testnode', 'testnode2']:
+ assert node not in inventory.inventory.hosts
+ # make sure that nodes group is absent
+ assert ('%s_nodes' % (inventory.group_prefix)) not in inventory.inventory.groups
+ # make sure that nodes are not in the "ungrouped" group
+ for node in ['testnode', 'testnode2']:
+ assert node not in inventory.inventory.get_groups_dict()["ungrouped"]
diff --git a/ansible_collections/community/general/tests/unit/plugins/lookup/onepassword_conftest.py b/ansible_collections/community/general/tests/unit/plugins/lookup/conftest.py
index 18afae1a3..d4ae42ab8 100644
--- a/ansible_collections/community/general/tests/unit/plugins/lookup/onepassword_conftest.py
+++ b/ansible_collections/community/general/tests/unit/plugins/lookup/conftest.py
@@ -10,17 +10,11 @@ import pytest
from ansible_collections.community.general.plugins.lookup.onepassword import OnePass
-OP_VERSION_FIXTURES = [
- "opv1",
- "opv2"
-]
-
-
@pytest.fixture
def fake_op(mocker):
def _fake_op(version):
mocker.patch("ansible_collections.community.general.plugins.lookup.onepassword.OnePassCLIBase.get_current_version", return_value=version)
- op = OnePass(None, None, None, None, None)
+ op = OnePass()
op._config._config_file_path = "/home/jin/.op/config"
mocker.patch.object(op._cli, "_run")
diff --git a/ansible_collections/community/general/tests/unit/plugins/lookup/onepassword_common.py b/ansible_collections/community/general/tests/unit/plugins/lookup/onepassword_common.py
index 092979225..bf0cc35c1 100644
--- a/ansible_collections/community/general/tests/unit/plugins/lookup/onepassword_common.py
+++ b/ansible_collections/community/general/tests/unit/plugins/lookup/onepassword_common.py
@@ -81,5 +81,215 @@ MOCK_ENTRIES = {
"expected": ["first value"],
"output": load_file("v2_out_03.json")
},
+ {
+ # Request data from an omitted value (label lookup, no section)
+ "vault_name": "Test Vault",
+ "queries": ["Omitted values"],
+ "kwargs": {
+ "field": "label-without-value",
+ },
+ "expected": [""],
+ "output": load_file("v2_out_04.json")
+ },
+ {
+ # Request data from an omitted value (id lookup, no section)
+ "vault_name": "Test Vault",
+ "queries": ["Omitted values"],
+ "kwargs": {
+ "field": "67890q7mspf4x6zrlw3qejn7m",
+ },
+ "expected": [""],
+ "output": load_file("v2_out_04.json")
+ },
+ {
+ # Request data from an omitted value (label lookup, with section)
+ "vault_name": "Test Vault",
+ "queries": ["Omitted values"],
+ "kwargs": {
+ "field": "section-label-without-value",
+ "section": "Section-Without-Values"
+ },
+ "expected": [""],
+ "output": load_file("v2_out_04.json")
+ },
+ {
+ # Request data from an omitted value (id lookup, with section)
+ "vault_name": "Test Vault",
+ "queries": ["Omitted values"],
+ "kwargs": {
+ "field": "123345q7mspf4x6zrlw3qejn7m",
+ "section": "section-without-values",
+ },
+ "expected": [""],
+ "output": load_file("v2_out_04.json")
+ },
+ {
+ # Query item without section by lowercase id (case matching)
+ "vault_name": "Test Vault",
+ "queries": ["LabelCasing"],
+ "kwargs": {
+ "field": "lowercaseid",
+ },
+ "expected": ["lowercaseid"],
+ "output": load_file("v2_out_05.json")
+ },
+ {
+ # Query item without section by lowercase id (case not matching)
+ "vault_name": "Test Vault",
+ "queries": ["LabelCasing"],
+ "kwargs": {
+ "field": "LOWERCASEID",
+ },
+ "expected": ["lowercaseid"],
+ "output": load_file("v2_out_05.json")
+ },
+ {
+ # Query item without section by lowercase label (case matching)
+ "vault_name": "Test Vault",
+ "queries": ["LabelCasing"],
+ "kwargs": {
+ "field": "lowercaselabel",
+ },
+ "expected": ["lowercaselabel"],
+ "output": load_file("v2_out_05.json")
+ },
+ {
+ # Query item without section by lowercase label (case not matching)
+ "vault_name": "Test Vault",
+ "queries": ["LabelCasing"],
+ "kwargs": {
+ "field": "LOWERCASELABEL",
+ },
+ "expected": ["lowercaselabel"],
+ "output": load_file("v2_out_05.json")
+ },
+ {
+ # Query item without section by mixed case id (case matching)
+ "vault_name": "Test Vault",
+ "queries": ["LabelCasing"],
+ "kwargs": {
+ "field": "MiXeDcAsEiD",
+ },
+ "expected": ["mixedcaseid"],
+ "output": load_file("v2_out_05.json")
+ },
+ {
+ # Query item without section by mixed case id (case not matching)
+ "vault_name": "Test Vault",
+ "queries": ["LabelCasing"],
+ "kwargs": {
+ "field": "mixedcaseid",
+ },
+ "expected": ["mixedcaseid"],
+ "output": load_file("v2_out_05.json")
+ },
+ {
+ # Query item without section by mixed case label (case matching)
+ "vault_name": "Test Vault",
+ "queries": ["LabelCasing"],
+ "kwargs": {
+ "field": "MiXeDcAsElAbEl",
+ },
+ "expected": ["mixedcaselabel"],
+ "output": load_file("v2_out_05.json")
+ },
+ {
+ # Query item without section by mixed case label (case not matching)
+ "vault_name": "Test Vault",
+ "queries": ["LabelCasing"],
+ "kwargs": {
+ "field": "mixedcaselabel",
+ },
+ "expected": ["mixedcaselabel"],
+ "output": load_file("v2_out_05.json")
+ },
+ {
+ # Query item with section by lowercase id (case matching)
+ "vault_name": "Test Vault",
+ "queries": ["LabelCasing"],
+ "kwargs": {
+ "field": "sectionlowercaseid",
+ "section": "section-with-values",
+ },
+ "expected": ["sectionlowercaseid"],
+ "output": load_file("v2_out_05.json")
+ },
+ {
+ # Query item with section by lowercase id (case not matching)
+ "vault_name": "Test Vault",
+ "queries": ["LabelCasing"],
+ "kwargs": {
+ "field": "SECTIONLOWERCASEID",
+ "section": "section-with-values",
+ },
+ "expected": ["sectionlowercaseid"],
+ "output": load_file("v2_out_05.json")
+ },
+ {
+ # Query item with section by lowercase label (case matching)
+ "vault_name": "Test Vault",
+ "queries": ["LabelCasing"],
+ "kwargs": {
+ "field": "sectionlowercaselabel",
+ "section": "section-with-values",
+ },
+ "expected": ["sectionlowercaselabel"],
+ "output": load_file("v2_out_05.json")
+ },
+ {
+ # Query item with section by lowercase label (case not matching)
+ "vault_name": "Test Vault",
+ "queries": ["LabelCasing"],
+ "kwargs": {
+ "field": "SECTIONLOWERCASELABEL",
+ "section": "section-with-values",
+ },
+ "expected": ["sectionlowercaselabel"],
+ "output": load_file("v2_out_05.json")
+ },
+ {
+ # Query item with section by lowercase id (case matching)
+ "vault_name": "Test Vault",
+ "queries": ["LabelCasing"],
+ "kwargs": {
+ "field": "SeCtIoNmIxEdCaSeId",
+ "section": "section-with-values",
+ },
+ "expected": ["sectionmixedcaseid"],
+ "output": load_file("v2_out_05.json")
+ },
+ {
+ # Query item with section by lowercase id (case not matching)
+ "vault_name": "Test Vault",
+ "queries": ["LabelCasing"],
+ "kwargs": {
+ "field": "sectionmixedcaseid",
+ "section": "section-with-values",
+ },
+ "expected": ["sectionmixedcaseid"],
+ "output": load_file("v2_out_05.json")
+ },
+ {
+ # Query item with section by lowercase label (case matching)
+ "vault_name": "Test Vault",
+ "queries": ["LabelCasing"],
+ "kwargs": {
+ "field": "SeCtIoNmIxEdCaSeLaBeL",
+ "section": "section-with-values",
+ },
+ "expected": ["sectionmixedcaselabel"],
+ "output": load_file("v2_out_05.json")
+ },
+ {
+ # Query item with section by lowercase label (case not matching)
+ "vault_name": "Test Vault",
+ "queries": ["LabelCasing"],
+ "kwargs": {
+ "field": "sectionmixedcaselabel",
+ "section": "section-with-values",
+ },
+ "expected": ["sectionmixedcaselabel"],
+ "output": load_file("v2_out_05.json")
+ },
],
}
diff --git a/ansible_collections/community/general/tests/unit/plugins/lookup/onepassword_fixtures/v2_out_01.json b/ansible_collections/community/general/tests/unit/plugins/lookup/onepassword_fixtures/v2_out_01.json
index 7ef0bb0c2..0ace5c825 100644
--- a/ansible_collections/community/general/tests/unit/plugins/lookup/onepassword_fixtures/v2_out_01.json
+++ b/ansible_collections/community/general/tests/unit/plugins/lookup/onepassword_fixtures/v2_out_01.json
@@ -13,10 +13,10 @@
"additional_information": "Jan 18, 2015, 08:13:38",
"fields": [
{
- "id": "password",
+ "id": "Password",
"type": "CONCEALED",
"purpose": "PASSWORD",
- "label": "password",
+ "label": "Password",
"value": "OctoberPoppyNuttyDraperySabbath",
"reference": "op://Test Vault/Authy Backup/password",
"password_details": {
diff --git a/ansible_collections/community/general/tests/unit/plugins/lookup/onepassword_fixtures/v2_out_04.json b/ansible_collections/community/general/tests/unit/plugins/lookup/onepassword_fixtures/v2_out_04.json
new file mode 100644
index 000000000..13b6cc2aa
--- /dev/null
+++ b/ansible_collections/community/general/tests/unit/plugins/lookup/onepassword_fixtures/v2_out_04.json
@@ -0,0 +1,67 @@
+{
+ "id": "bgqegp3xcxnpfkb45olwigpkpi",
+ "title": "OmittedValues",
+ "version": 1,
+ "vault": {
+ "id": "stpebbaccrq72xulgouxsk4p7y",
+ "name": "Private"
+ },
+ "category": "LOGIN",
+ "last_edited_by": "WOUTERRUYBH7BFPHMZ2KKGL6AU",
+ "created_at": "2023-09-12T08:30:07Z",
+ "updated_at": "2023-09-12T08:30:07Z",
+ "additional_information": "fluxility",
+ "sections": [
+ {
+ "id": "7osqcvd43i75teocdzbb6d7mie",
+ "label": "section-without-values"
+ }
+ ],
+ "fields": [
+ {
+ "id": "username",
+ "type": "STRING",
+ "purpose": "USERNAME",
+ "label": "username",
+ "value": "fluxility",
+ "reference": "op://Testcase/OmittedValues/username"
+ },
+ {
+ "id": "password",
+ "type": "CONCEALED",
+ "purpose": "PASSWORD",
+ "label": "password",
+ "value": "j89Dyb7psat*hkbkyLUQyq@GR.a-g2pQH_V_xtMhrn37rQ_2uRYoRiozj6TjWVLy2pbfEvjnse",
+ "entropy": 427.01202392578125,
+ "reference": "op://Testcase/OmittedValues/password",
+ "password_details": {
+ "entropy": 427,
+ "generated": true,
+ "strength": "FANTASTIC"
+ }
+ },
+ {
+ "id": "notesPlain",
+ "type": "STRING",
+ "purpose": "NOTES",
+ "label": "notesPlain",
+ "reference": "op://Testcase/OmittedValues/notesPlain"
+ },
+ {
+ "id": "67890q7mspf4x6zrlw3qejn7m",
+ "type": "URL",
+ "label": "label-without-value",
+ "reference": "op://01202392578125/OmittedValues/section-without-values/section-without-value"
+ },
+ {
+ "id": "123345q7mspf4x6zrlw3qejn7m",
+ "section": {
+ "id": "6hbtca5yrlmoptgy3nw74222",
+ "label": "section-without-values"
+ },
+ "type": "URL",
+ "label": "section-label-without-value",
+ "reference": "op://01202392578125/OmittedValues/section-without-values/section-without-value"
+ }
+ ]
+}
diff --git a/ansible_collections/community/general/tests/unit/plugins/lookup/onepassword_fixtures/v2_out_04.json.license b/ansible_collections/community/general/tests/unit/plugins/lookup/onepassword_fixtures/v2_out_04.json.license
new file mode 100644
index 000000000..969b956c2
--- /dev/null
+++ b/ansible_collections/community/general/tests/unit/plugins/lookup/onepassword_fixtures/v2_out_04.json.license
@@ -0,0 +1,3 @@
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
+SPDX-FileCopyrightText: 2022, Ansible Project
diff --git a/ansible_collections/community/general/tests/unit/plugins/lookup/onepassword_fixtures/v2_out_05.json b/ansible_collections/community/general/tests/unit/plugins/lookup/onepassword_fixtures/v2_out_05.json
new file mode 100644
index 000000000..f925476e1
--- /dev/null
+++ b/ansible_collections/community/general/tests/unit/plugins/lookup/onepassword_fixtures/v2_out_05.json
@@ -0,0 +1,102 @@
+{
+ "id": "bgqegp3xcxnpfkb45olwigpkpi",
+ "title": "LabelCasing",
+ "version": 1,
+ "vault": {
+ "id": "stpebbaccrq72xulgouxsk4p7y",
+ "name": "Private"
+ },
+ "category": "LOGIN",
+ "last_edited_by": "WOUTERRUYBH7BFPHMZ2KKGL6AU",
+ "created_at": "2023-09-12T08:30:07Z",
+ "updated_at": "2023-09-12T08:30:07Z",
+ "additional_information": "fluxility",
+ "sections": [
+ {
+ "id": "7osqcvd43i75teocdzbb6d7mie",
+ "label": "section-with-values"
+ }
+ ],
+ "fields": [
+ {
+ "id": "lowercaseid",
+ "type": "STRING",
+ "purpose": "USERNAME",
+ "label": "label0",
+ "value": "lowercaseid",
+ "reference": "op://Testcase/LabelCasing/lowercase"
+ },
+ {
+ "id": "MiXeDcAsEiD",
+ "type": "STRING",
+ "purpose": "USERNAME",
+ "label": "label1",
+ "value": "mixedcaseid",
+ "reference": "op://Testcase/LabelCasing/lowercase"
+ },
+ {
+ "id": "id1",
+ "type": "STRING",
+ "purpose": "USERNAME",
+ "label": "lowercaselabel",
+ "value": "lowercaselabel",
+ "reference": "op://Testcase/LabelCasing/lowercase"
+ },
+ {
+ "id": "id2",
+ "type": "STRING",
+ "purpose": "USERNAME",
+ "label": "MiXeDcAsElAbEl",
+ "value": "mixedcaselabel",
+ "reference": "op://Testcase/LabelCasing/lowercase"
+ },
+ {
+ "id": "sectionlowercaseid",
+ "type": "STRING",
+ "purpose": "USERNAME",
+ "label": "label2",
+ "value": "sectionlowercaseid",
+ "reference": "op://Testcase/LabelCasing/lowercase",
+ "section": {
+ "id": "7osqcvd43i75teocdzbb6d7mie",
+ "label": "section-with-values"
+ }
+ },
+ {
+ "id": "SeCtIoNmIxEdCaSeId",
+ "type": "STRING",
+ "purpose": "USERNAME",
+ "label": "label3",
+ "value": "sectionmixedcaseid",
+ "reference": "op://Testcase/LabelCasing/lowercase",
+ "section": {
+ "id": "7osqcvd43i75teocdzbb6d7mie",
+ "label": "section-with-values"
+ }
+ },
+ {
+ "id": "id3",
+ "type": "STRING",
+ "purpose": "USERNAME",
+ "label": "sectionlowercaselabel",
+ "value": "sectionlowercaselabel",
+ "reference": "op://Testcase/LabelCasing/lowercase",
+ "section": {
+ "id": "7osqcvd43i75teocdzbb6d7mie",
+ "label": "section-with-values"
+ }
+ },
+ {
+ "id": "id2",
+ "type": "STRING",
+ "purpose": "USERNAME",
+ "label": "SeCtIoNmIxEdCaSeLaBeL",
+ "value": "sectionmixedcaselabel",
+ "reference": "op://Testcase/LabelCasing/lowercase",
+ "section": {
+ "id": "7osqcvd43i75teocdzbb6d7mie",
+ "label": "section-with-values"
+ }
+ }
+ ]
+}
diff --git a/ansible_collections/community/general/tests/unit/plugins/lookup/onepassword_fixtures/v2_out_05.json.license b/ansible_collections/community/general/tests/unit/plugins/lookup/onepassword_fixtures/v2_out_05.json.license
new file mode 100644
index 000000000..969b956c2
--- /dev/null
+++ b/ansible_collections/community/general/tests/unit/plugins/lookup/onepassword_fixtures/v2_out_05.json.license
@@ -0,0 +1,3 @@
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
+SPDX-FileCopyrightText: 2022, Ansible Project
diff --git a/ansible_collections/community/general/tests/unit/plugins/lookup/test_bitwarden.py b/ansible_collections/community/general/tests/unit/plugins/lookup/test_bitwarden.py
index d45263965..9270dd44e 100644
--- a/ansible_collections/community/general/tests/unit/plugins/lookup/test_bitwarden.py
+++ b/ansible_collections/community/general/tests/unit/plugins/lookup/test_bitwarden.py
@@ -14,10 +14,13 @@ from ansible.module_utils import six
from ansible.plugins.loader import lookup_loader
from ansible_collections.community.general.plugins.lookup.bitwarden import Bitwarden
+MOCK_COLLECTION_ID = "3b12a9da-7c49-40b8-ad33-aede017a7ead"
MOCK_RECORDS = [
{
- "collectionIds": [],
+ "collectionIds": [
+ MOCK_COLLECTION_ID
+ ],
"deletedDate": None,
"favorite": False,
"fields": [
@@ -65,7 +68,9 @@ MOCK_RECORDS = [
"type": 1
},
{
- "collectionIds": [],
+ "collectionIds": [
+ MOCK_COLLECTION_ID
+ ],
"deletedDate": None,
"favorite": False,
"folderId": None,
@@ -85,7 +90,9 @@ MOCK_RECORDS = [
"type": 1
},
{
- "collectionIds": [],
+ "collectionIds": [
+ MOCK_COLLECTION_ID
+ ],
"deletedDate": None,
"favorite": False,
"folderId": None,
@@ -111,7 +118,10 @@ class MockBitwarden(Bitwarden):
unlocked = True
- def _get_matches(self, search_value, search_field="name", collection_id=None):
+ def _get_matches(self, search_value=None, search_field="name", collection_id=None):
+ if not search_value and collection_id:
+ return list(filter(lambda record: collection_id in record['collectionIds'], MOCK_RECORDS))
+
return list(filter(lambda record: record[search_field] == search_value, MOCK_RECORDS))
@@ -156,5 +166,32 @@ class TestLookupModule(unittest.TestCase):
def test_bitwarden_plugin_unlocked(self):
record = MOCK_RECORDS[0]
record_name = record['name']
- with self.assertRaises(AnsibleError):
+ with self.assertRaises(AnsibleError) as raised_error:
self.lookup.run([record_name], field='password')
+
+ self.assertEqual("Bitwarden Vault locked. Run 'bw unlock'.", str(raised_error.exception))
+
+ def test_bitwarden_plugin_without_session_option(self):
+ mock_bitwarden = MockBitwarden()
+ with patch("ansible_collections.community.general.plugins.lookup.bitwarden._bitwarden", mock_bitwarden):
+ record = MOCK_RECORDS[0]
+ record_name = record['name']
+ session = 'session'
+
+ self.lookup.run([record_name], field=None)
+ self.assertIsNone(mock_bitwarden.session)
+
+ def test_bitwarden_plugin_session_option(self):
+ mock_bitwarden = MockBitwarden()
+ with patch("ansible_collections.community.general.plugins.lookup.bitwarden._bitwarden", mock_bitwarden):
+ record = MOCK_RECORDS[0]
+ record_name = record['name']
+ session = 'session'
+
+ self.lookup.run([record_name], field=None, bw_session=session)
+ self.assertEqual(mock_bitwarden.session, session)
+
+ @patch('ansible_collections.community.general.plugins.lookup.bitwarden._bitwarden', new=MockBitwarden())
+ def test_bitwarden_plugin_full_collection(self):
+ # Try to retrieve the full records of the given collection.
+ self.assertEqual(MOCK_RECORDS, self.lookup.run(None, collection_id=MOCK_COLLECTION_ID)[0])
diff --git a/ansible_collections/community/general/tests/unit/plugins/lookup/test_bitwarden_secrets_manager.py b/ansible_collections/community/general/tests/unit/plugins/lookup/test_bitwarden_secrets_manager.py
new file mode 100644
index 000000000..aaeaf79ea
--- /dev/null
+++ b/ansible_collections/community/general/tests/unit/plugins/lookup/test_bitwarden_secrets_manager.py
@@ -0,0 +1,83 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2023, jantari (https://github.com/jantari)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import (absolute_import, division, print_function)
+
+__metaclass__ = type
+
+import json
+from ansible_collections.community.general.tests.unit.compat import unittest
+from ansible_collections.community.general.tests.unit.compat.mock import patch
+
+from ansible.errors import AnsibleLookupError
+from ansible.plugins.loader import lookup_loader
+from ansible_collections.community.general.plugins.lookup.bitwarden_secrets_manager import BitwardenSecretsManager
+
+
+MOCK_SECRETS = [
+ {
+ "object": "secret",
+ "id": "ababc4a8-c242-4e54-bceb-77d17cdf2e07",
+ "organizationId": "3c33066c-a0bf-4e70-9a3c-24cda6aaddd5",
+ "projectId": "81869439-bfe5-442f-8b4e-b172e68b0ab2",
+ "key": "TEST_SECRET",
+ "value": "1234supersecret5678",
+ "note": "A test secret to use when developing the ansible bitwarden_secrets_manager lookup plugin",
+ "creationDate": "2023-04-23T13:13:37.7507017Z",
+ "revisionDate": "2023-04-23T13:13:37.7507017Z"
+ },
+ {
+ "object": "secret",
+ "id": "d4b7c8fa-fc95-40d7-a13c-6e186ee69d53",
+ "organizationId": "3c33066c-a0bf-4e70-9a3c-24cda6aaddd5",
+ "projectId": "81869439-bfe5-442f-8b4e-b172e68b0ab2",
+ "key": "TEST_SECRET_2",
+ "value": "abcd_such_secret_very_important_efgh",
+ "note": "notes go here",
+ "creationDate": "2023-04-23T13:26:44.0392906Z",
+ "revisionDate": "2023-04-23T13:26:44.0392906Z"
+ }
+]
+
+
+class MockBitwardenSecretsManager(BitwardenSecretsManager):
+
+ def _run(self, args, stdin=None):
+ # secret_id is the last argument passed to the bws CLI
+ secret_id = args[-1]
+ rc = 1
+ out = ""
+ err = ""
+ found_secrets = list(filter(lambda record: record["id"] == secret_id, MOCK_SECRETS))
+
+ if len(found_secrets) == 0:
+ err = "simulated bws CLI error: 404 no secret with such id"
+ elif len(found_secrets) == 1:
+ rc = 0
+ # The real bws CLI will only ever return one secret / json object for the "get secret <secret-id>" command
+ out = json.dumps(found_secrets[0])
+ else:
+ # This should never happen unless there's an error in the test MOCK_SECRETS.
+ # The real Bitwarden Secrets Manager assigns each secret a unique ID.
+ raise ValueError("More than 1 secret found with id: '{0}'. Impossible!".format(secret_id))
+
+ return out, err, rc
+
+
+class TestLookupModule(unittest.TestCase):
+
+ def setUp(self):
+ self.lookup = lookup_loader.get('community.general.bitwarden_secrets_manager')
+
+ @patch('ansible_collections.community.general.plugins.lookup.bitwarden_secrets_manager._bitwarden_secrets_manager', new=MockBitwardenSecretsManager())
+ def test_bitwarden_secrets_manager(self):
+ # Getting a secret by its id should return the full secret info
+ self.assertEqual([MOCK_SECRETS[0]], self.lookup.run(['ababc4a8-c242-4e54-bceb-77d17cdf2e07'], bws_access_token='123'))
+
+ @patch('ansible_collections.community.general.plugins.lookup.bitwarden_secrets_manager._bitwarden_secrets_manager', new=MockBitwardenSecretsManager())
+ def test_bitwarden_secrets_manager_no_match(self):
+ # Getting a nonexistent secret id throws exception
+ with self.assertRaises(AnsibleLookupError):
+ self.lookup.run(['nonexistant_id'], bws_access_token='123')
diff --git a/ansible_collections/community/general/tests/unit/plugins/lookup/test_github_app_access_token.py b/ansible_collections/community/general/tests/unit/plugins/lookup/test_github_app_access_token.py
new file mode 100644
index 000000000..4bf9c7e70
--- /dev/null
+++ b/ansible_collections/community/general/tests/unit/plugins/lookup/test_github_app_access_token.py
@@ -0,0 +1,52 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2023, Poh Wei Sheng <weisheng-p@hotmail.sg>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+import json
+
+from ansible_collections.community.general.tests.unit.compat import unittest
+from ansible_collections.community.general.tests.unit.compat.mock import (
+ patch,
+ MagicMock,
+ mock_open
+)
+from ansible.plugins.loader import lookup_loader
+
+
+class MockJWT(MagicMock):
+ def encode(self, payload, key, alg):
+ return 'Foobar'
+
+
+class MockResponse(MagicMock):
+ response_token = 'Bar'
+
+ def read(self):
+ return json.dumps({
+ "token": self.response_token,
+ }).encode('utf-8')
+
+
+class TestLookupModule(unittest.TestCase):
+
+ def test_get_token(self):
+ with patch.multiple("ansible_collections.community.general.plugins.lookup.github_app_access_token",
+ open=mock_open(read_data="foo_bar"),
+ open_url=MagicMock(return_value=MockResponse()),
+ jwk_from_pem=MagicMock(return_value='private_key'),
+ jwt_instance=MockJWT(),
+ HAS_JWT=True):
+ lookup = lookup_loader.get('community.general.github_app_access_token')
+ self.assertListEqual(
+ [MockResponse.response_token],
+ lookup.run(
+ [],
+ key_path="key",
+ app_id="app_id",
+ installation_id="installation_id",
+ token_expiry=600
+ )
+ )
diff --git a/ansible_collections/community/general/tests/unit/plugins/lookup/test_merge_variables.py b/ansible_collections/community/general/tests/unit/plugins/lookup/test_merge_variables.py
index 5085797b3..66cb2f08b 100644
--- a/ansible_collections/community/general/tests/unit/plugins/lookup/test_merge_variables.py
+++ b/ansible_collections/community/general/tests/unit/plugins/lookup/test_merge_variables.py
@@ -24,7 +24,7 @@ class TestMergeVariablesLookup(unittest.TestCase):
self.merge_vars_lookup = merge_variables.LookupModule(loader=self.loader, templar=self.templar)
@patch.object(AnsiblePlugin, 'set_options')
- @patch.object(AnsiblePlugin, 'get_option', side_effect=[None, 'ignore', 'suffix'])
+ @patch.object(AnsiblePlugin, 'get_option', side_effect=[None, 'ignore', 'suffix', None])
@patch.object(Templar, 'template', side_effect=[['item1'], ['item3']])
def test_merge_list(self, mock_set_options, mock_get_option, mock_template):
results = self.merge_vars_lookup.run(['__merge_list'], {
@@ -36,7 +36,7 @@ class TestMergeVariablesLookup(unittest.TestCase):
self.assertEqual(results, [['item1', 'item3']])
@patch.object(AnsiblePlugin, 'set_options')
- @patch.object(AnsiblePlugin, 'get_option', side_effect=[['initial_item'], 'ignore', 'suffix'])
+ @patch.object(AnsiblePlugin, 'get_option', side_effect=[['initial_item'], 'ignore', 'suffix', None])
@patch.object(Templar, 'template', side_effect=[['item1'], ['item3']])
def test_merge_list_with_initial_value(self, mock_set_options, mock_get_option, mock_template):
results = self.merge_vars_lookup.run(['__merge_list'], {
@@ -48,7 +48,7 @@ class TestMergeVariablesLookup(unittest.TestCase):
self.assertEqual(results, [['initial_item', 'item1', 'item3']])
@patch.object(AnsiblePlugin, 'set_options')
- @patch.object(AnsiblePlugin, 'get_option', side_effect=[None, 'ignore', 'suffix'])
+ @patch.object(AnsiblePlugin, 'get_option', side_effect=[None, 'ignore', 'suffix', None])
@patch.object(Templar, 'template', side_effect=[{'item1': 'test', 'list_item': ['test1']},
{'item2': 'test', 'list_item': ['test2']}])
def test_merge_dict(self, mock_set_options, mock_get_option, mock_template):
@@ -73,7 +73,7 @@ class TestMergeVariablesLookup(unittest.TestCase):
@patch.object(AnsiblePlugin, 'set_options')
@patch.object(AnsiblePlugin, 'get_option', side_effect=[{'initial_item': 'random value', 'list_item': ['test0']},
- 'ignore', 'suffix'])
+ 'ignore', 'suffix', None])
@patch.object(Templar, 'template', side_effect=[{'item1': 'test', 'list_item': ['test1']},
{'item2': 'test', 'list_item': ['test2']}])
def test_merge_dict_with_initial_value(self, mock_set_options, mock_get_option, mock_template):
@@ -98,7 +98,7 @@ class TestMergeVariablesLookup(unittest.TestCase):
])
@patch.object(AnsiblePlugin, 'set_options')
- @patch.object(AnsiblePlugin, 'get_option', side_effect=[None, 'warn', 'suffix'])
+ @patch.object(AnsiblePlugin, 'get_option', side_effect=[None, 'warn', 'suffix', None])
@patch.object(Templar, 'template', side_effect=[{'item': 'value1'}, {'item': 'value2'}])
@patch.object(Display, 'warning')
def test_merge_dict_non_unique_warning(self, mock_set_options, mock_get_option, mock_template, mock_display):
@@ -111,7 +111,7 @@ class TestMergeVariablesLookup(unittest.TestCase):
self.assertEqual(results, [{'item': 'value2'}])
@patch.object(AnsiblePlugin, 'set_options')
- @patch.object(AnsiblePlugin, 'get_option', side_effect=[None, 'error', 'suffix'])
+ @patch.object(AnsiblePlugin, 'get_option', side_effect=[None, 'error', 'suffix', None])
@patch.object(Templar, 'template', side_effect=[{'item': 'value1'}, {'item': 'value2'}])
def test_merge_dict_non_unique_error(self, mock_set_options, mock_get_option, mock_template):
with self.assertRaises(AnsibleError):
@@ -121,7 +121,7 @@ class TestMergeVariablesLookup(unittest.TestCase):
})
@patch.object(AnsiblePlugin, 'set_options')
- @patch.object(AnsiblePlugin, 'get_option', side_effect=[None, 'ignore', 'suffix'])
+ @patch.object(AnsiblePlugin, 'get_option', side_effect=[None, 'ignore', 'suffix', None])
@patch.object(Templar, 'template', side_effect=[{'item1': 'test', 'list_item': ['test1']},
['item2', 'item3']])
def test_merge_list_and_dict(self, mock_set_options, mock_get_option, mock_template):
@@ -133,3 +133,150 @@ class TestMergeVariablesLookup(unittest.TestCase):
},
'testdict__merge_var': ['item2', 'item3']
})
+
+ @patch.object(AnsiblePlugin, 'set_options')
+ @patch.object(AnsiblePlugin, 'get_option', side_effect=[None, 'ignore', 'suffix', ['all']])
+ @patch.object(Templar, 'template', side_effect=[
+ {'var': [{'item1': 'value1', 'item2': 'value2'}]},
+ {'var': [{'item5': 'value5', 'item6': 'value6'}]},
+ ])
+ def test_merge_dict_group_all(self, mock_set_options, mock_get_option, mock_template):
+ results = self.merge_vars_lookup.run(['__merge_var'], {
+ 'inventory_hostname': 'host1',
+ 'hostvars': {
+ 'host1': {
+ 'group_names': ['dummy1'],
+ 'inventory_hostname': 'host1',
+ '1testlist__merge_var': {
+ 'var': [{'item1': 'value1', 'item2': 'value2'}]
+ }
+ },
+ 'host2': {
+ 'group_names': ['dummy1'],
+ 'inventory_hostname': 'host2',
+ '2otherlist__merge_var': {
+ 'var': [{'item5': 'value5', 'item6': 'value6'}]
+ }
+ }
+ }
+ })
+
+ self.assertEqual(results, [
+ {'var': [
+ {'item1': 'value1', 'item2': 'value2'},
+ {'item5': 'value5', 'item6': 'value6'}
+ ]}
+ ])
+
+ @patch.object(AnsiblePlugin, 'set_options')
+ @patch.object(AnsiblePlugin, 'get_option', side_effect=[None, 'ignore', 'suffix', ['dummy1']])
+ @patch.object(Templar, 'template', side_effect=[
+ {'var': [{'item1': 'value1', 'item2': 'value2'}]},
+ {'var': [{'item5': 'value5', 'item6': 'value6'}]},
+ ])
+ def test_merge_dict_group_single(self, mock_set_options, mock_get_option, mock_template):
+ results = self.merge_vars_lookup.run(['__merge_var'], {
+ 'inventory_hostname': 'host1',
+ 'hostvars': {
+ 'host1': {
+ 'group_names': ['dummy1'],
+ 'inventory_hostname': 'host1',
+ '1testlist__merge_var': {
+ 'var': [{'item1': 'value1', 'item2': 'value2'}]
+ }
+ },
+ 'host2': {
+ 'group_names': ['dummy1'],
+ 'inventory_hostname': 'host2',
+ '2otherlist__merge_var': {
+ 'var': [{'item5': 'value5', 'item6': 'value6'}]
+ }
+ },
+ 'host3': {
+ 'group_names': ['dummy2'],
+ 'inventory_hostname': 'host3',
+ '3otherlist__merge_var': {
+ 'var': [{'item3': 'value3', 'item4': 'value4'}]
+ }
+ }
+ }
+ })
+
+ self.assertEqual(results, [
+ {'var': [
+ {'item1': 'value1', 'item2': 'value2'},
+ {'item5': 'value5', 'item6': 'value6'}
+ ]}
+ ])
+
+ @patch.object(AnsiblePlugin, 'set_options')
+ @patch.object(AnsiblePlugin, 'get_option', side_effect=[None, 'ignore', 'suffix', ['dummy1', 'dummy2']])
+ @patch.object(Templar, 'template', side_effect=[
+ {'var': [{'item1': 'value1', 'item2': 'value2'}]},
+ {'var': [{'item5': 'value5', 'item6': 'value6'}]},
+ ])
+ def test_merge_dict_group_multiple(self, mock_set_options, mock_get_option, mock_template):
+ results = self.merge_vars_lookup.run(['__merge_var'], {
+ 'inventory_hostname': 'host1',
+ 'hostvars': {
+ 'host1': {
+ 'group_names': ['dummy1'],
+ 'inventory_hostname': 'host1',
+ '1testlist__merge_var': {
+ 'var': [{'item1': 'value1', 'item2': 'value2'}]
+ }
+ },
+ 'host2': {
+ 'group_names': ['dummy2'],
+ 'inventory_hostname': 'host2',
+ '2otherlist__merge_var': {
+ 'var': [{'item5': 'value5', 'item6': 'value6'}]
+ }
+ },
+ 'host3': {
+ 'group_names': ['dummy3'],
+ 'inventory_hostname': 'host3',
+ '3otherlist__merge_var': {
+ 'var': [{'item3': 'value3', 'item4': 'value4'}]
+ }
+ }
+ }
+ })
+
+ self.assertEqual(results, [
+ {'var': [
+ {'item1': 'value1', 'item2': 'value2'},
+ {'item5': 'value5', 'item6': 'value6'}
+ ]}
+ ])
+
+ @patch.object(AnsiblePlugin, 'set_options')
+ @patch.object(AnsiblePlugin, 'get_option', side_effect=[None, 'ignore', 'suffix', ['dummy1', 'dummy2']])
+ @patch.object(Templar, 'template', side_effect=[
+ ['item1'],
+ ['item5'],
+ ])
+ def test_merge_list_group_multiple(self, mock_set_options, mock_get_option, mock_template):
+ print()
+ results = self.merge_vars_lookup.run(['__merge_var'], {
+ 'inventory_hostname': 'host1',
+ 'hostvars': {
+ 'host1': {
+ 'group_names': ['dummy1'],
+ 'inventory_hostname': 'host1',
+ '1testlist__merge_var': ['item1']
+ },
+ 'host2': {
+ 'group_names': ['dummy2'],
+ 'inventory_hostname': 'host2',
+ '2otherlist__merge_var': ['item5']
+ },
+ 'host3': {
+ 'group_names': ['dummy3'],
+ 'inventory_hostname': 'host3',
+ '3otherlist__merge_var': ['item3']
+ }
+ }
+ })
+
+ self.assertEqual(results, [['item1', 'item5']])
diff --git a/ansible_collections/community/general/tests/unit/plugins/lookup/test_onepassword.py b/ansible_collections/community/general/tests/unit/plugins/lookup/test_onepassword.py
index ab7f3def2..dc00e5703 100644
--- a/ansible_collections/community/general/tests/unit/plugins/lookup/test_onepassword.py
+++ b/ansible_collections/community/general/tests/unit/plugins/lookup/test_onepassword.py
@@ -10,15 +10,9 @@ import itertools
import json
import pytest
-from .onepassword_conftest import ( # noqa: F401, pylint: disable=unused-import
- OP_VERSION_FIXTURES,
- fake_op,
- opv1,
- opv2,
-)
from .onepassword_common import MOCK_ENTRIES
-from ansible.errors import AnsibleLookupError
+from ansible.errors import AnsibleLookupError, AnsibleOptionsError
from ansible.plugins.loader import lookup_loader
from ansible_collections.community.general.plugins.lookup.onepassword import (
OnePassCLIv1,
@@ -26,6 +20,12 @@ from ansible_collections.community.general.plugins.lookup.onepassword import (
)
+OP_VERSION_FIXTURES = [
+ "opv1",
+ "opv2"
+]
+
+
@pytest.mark.parametrize(
("args", "rc", "expected_call_args", "expected_call_kwargs", "expected"),
(
@@ -82,6 +82,12 @@ def test_assert_logged_in_v2(mocker, args, out, expected_call_args, expected_cal
assert result == expected
+def test_assert_logged_in_v2_connect():
+ op_cli = OnePassCLIv2(connect_host="http://localhost:8080", connect_token="foobar")
+ result = op_cli.assert_logged_in()
+ assert result
+
+
def test_full_signin_v2(mocker):
mocker.patch.object(OnePassCLIv2, "_run", return_value=[0, "", ""])
@@ -264,5 +270,50 @@ def test_signin(op_fixture, request):
op = request.getfixturevalue(op_fixture)
op._cli.master_password = "master_pass"
op._cli.signin()
- print(op._cli.version)
op._cli._run.assert_called_once_with(['signin', '--raw'], command_input=b"master_pass")
+
+
+def test_op_doc(mocker):
+ document_contents = "Document Contents\n"
+
+ mocker.patch("ansible_collections.community.general.plugins.lookup.onepassword.OnePass.assert_logged_in", return_value=True)
+ mocker.patch("ansible_collections.community.general.plugins.lookup.onepassword.OnePassCLIBase._run", return_value=(0, document_contents, ""))
+
+ op_lookup = lookup_loader.get("community.general.onepassword_doc")
+ result = op_lookup.run(["Private key doc"])
+
+ assert result == [document_contents]
+
+
+@pytest.mark.parametrize(
+ ("plugin", "connect_host", "connect_token"),
+ [
+ (plugin, connect_host, connect_token)
+ for plugin in ("community.general.onepassword", "community.general.onepassword_raw")
+ for (connect_host, connect_token) in
+ (
+ ("http://localhost", None),
+ (None, "foobar"),
+ )
+ ]
+)
+def test_op_connect_partial_args(plugin, connect_host, connect_token, mocker):
+ op_lookup = lookup_loader.get(plugin)
+
+ mocker.patch("ansible_collections.community.general.plugins.lookup.onepassword.OnePass._get_cli_class", OnePassCLIv2)
+
+ with pytest.raises(AnsibleOptionsError):
+ op_lookup.run("login", vault_name="test vault", connect_host=connect_host, connect_token=connect_token)
+
+
+@pytest.mark.parametrize(
+ ("kwargs"),
+ (
+ {"connect_host": "http://localhost", "connect_token": "foobar"},
+ {"service_account_token": "foobar"},
+ )
+)
+def test_opv1_unsupported_features(kwargs):
+ op_cli = OnePassCLIv1(**kwargs)
+ with pytest.raises(AnsibleLookupError):
+ op_cli.full_signin()
diff --git a/ansible_collections/community/general/tests/unit/plugins/module_utils/hwc/test_hwc_utils.py b/ansible_collections/community/general/tests/unit/plugins/module_utils/hwc/test_hwc_utils.py
index 1344496b1..9b0be0bb4 100644
--- a/ansible_collections/community/general/tests/unit/plugins/module_utils/hwc/test_hwc_utils.py
+++ b/ansible_collections/community/general/tests/unit/plugins/module_utils/hwc/test_hwc_utils.py
@@ -6,11 +6,20 @@
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
+import sys
+
from ansible_collections.community.general.tests.unit.compat import unittest
from ansible_collections.community.general.plugins.module_utils.hwc_utils import (HwcModuleException, navigate_value)
class HwcUtilsTestCase(unittest.TestCase):
+ def setUp(self):
+ super(HwcUtilsTestCase, self).setUp()
+
+ # Add backward compatibility
+ if sys.version_info < (3, 0):
+ self.assertRaisesRegex = self.assertRaisesRegexp
+
def test_navigate_value(self):
value = {
'foo': {
@@ -29,12 +38,12 @@ class HwcUtilsTestCase(unittest.TestCase):
{"foo.quiet.trees": 1}),
1)
- self.assertRaisesRegexp(HwcModuleException,
- r".* key\(q\) is not exist in dict",
- navigate_value, value, ["foo", "q", "tree"])
+ self.assertRaisesRegex(HwcModuleException,
+ r".* key\(q\) is not exist in dict",
+ navigate_value, value, ["foo", "q", "tree"])
- self.assertRaisesRegexp(HwcModuleException,
- r".* the index is out of list",
- navigate_value, value,
- ["foo", "quiet", "trees"],
- {"foo.quiet.trees": 2})
+ self.assertRaisesRegex(HwcModuleException,
+ r".* the index is out of list",
+ navigate_value, value,
+ ["foo", "quiet", "trees"],
+ {"foo.quiet.trees": 2})
diff --git a/ansible_collections/community/general/tests/unit/plugins/module_utils/test_cmd_runner.py b/ansible_collections/community/general/tests/unit/plugins/module_utils/test_cmd_runner.py
index 7cec215a7..86576e8ce 100644
--- a/ansible_collections/community/general/tests/unit/plugins/module_utils/test_cmd_runner.py
+++ b/ansible_collections/community/general/tests/unit/plugins/module_utils/test_cmd_runner.py
@@ -11,44 +11,44 @@ from sys import version_info
import pytest
from ansible_collections.community.general.tests.unit.compat.mock import MagicMock, PropertyMock
-from ansible_collections.community.general.plugins.module_utils.cmd_runner import CmdRunner, fmt
+from ansible_collections.community.general.plugins.module_utils.cmd_runner import CmdRunner, cmd_runner_fmt
TC_FORMATS = dict(
- simple_boolean__true=(fmt.as_bool, ("--superflag",), True, ["--superflag"]),
- simple_boolean__false=(fmt.as_bool, ("--superflag",), False, []),
- simple_boolean__none=(fmt.as_bool, ("--superflag",), None, []),
- simple_boolean_both__true=(fmt.as_bool, ("--superflag", "--falseflag"), True, ["--superflag"]),
- simple_boolean_both__false=(fmt.as_bool, ("--superflag", "--falseflag"), False, ["--falseflag"]),
- simple_boolean_both__none=(fmt.as_bool, ("--superflag", "--falseflag"), None, ["--falseflag"]),
- simple_boolean_both__none_ig=(fmt.as_bool, ("--superflag", "--falseflag", True), None, []),
- simple_boolean_not__true=(fmt.as_bool_not, ("--superflag",), True, []),
- simple_boolean_not__false=(fmt.as_bool_not, ("--superflag",), False, ["--superflag"]),
- simple_boolean_not__none=(fmt.as_bool_not, ("--superflag",), None, ["--superflag"]),
- simple_optval__str=(fmt.as_optval, ("-t",), "potatoes", ["-tpotatoes"]),
- simple_optval__int=(fmt.as_optval, ("-t",), 42, ["-t42"]),
- simple_opt_val__str=(fmt.as_opt_val, ("-t",), "potatoes", ["-t", "potatoes"]),
- simple_opt_val__int=(fmt.as_opt_val, ("-t",), 42, ["-t", "42"]),
- simple_opt_eq_val__str=(fmt.as_opt_eq_val, ("--food",), "potatoes", ["--food=potatoes"]),
- simple_opt_eq_val__int=(fmt.as_opt_eq_val, ("--answer",), 42, ["--answer=42"]),
- simple_list_potato=(fmt.as_list, (), "literal_potato", ["literal_potato"]),
- simple_list_42=(fmt.as_list, (), 42, ["42"]),
- simple_map=(fmt.as_map, ({'a': 1, 'b': 2, 'c': 3},), 'b', ["2"]),
- simple_default_type__list=(fmt.as_default_type, ("list",), [1, 2, 3, 5, 8], ["--1", "--2", "--3", "--5", "--8"]),
- simple_default_type__bool_true=(fmt.as_default_type, ("bool", "what"), True, ["--what"]),
- simple_default_type__bool_false=(fmt.as_default_type, ("bool", "what"), False, []),
- simple_default_type__potato=(fmt.as_default_type, ("any-other-type", "potato"), "42", ["--potato", "42"]),
- simple_fixed_true=(fmt.as_fixed, [("--always-here", "--forever")], True, ["--always-here", "--forever"]),
- simple_fixed_false=(fmt.as_fixed, [("--always-here", "--forever")], False, ["--always-here", "--forever"]),
- simple_fixed_none=(fmt.as_fixed, [("--always-here", "--forever")], None, ["--always-here", "--forever"]),
- simple_fixed_str=(fmt.as_fixed, [("--always-here", "--forever")], "something", ["--always-here", "--forever"]),
+ simple_boolean__true=(cmd_runner_fmt.as_bool, ("--superflag",), True, ["--superflag"]),
+ simple_boolean__false=(cmd_runner_fmt.as_bool, ("--superflag",), False, []),
+ simple_boolean__none=(cmd_runner_fmt.as_bool, ("--superflag",), None, []),
+ simple_boolean_both__true=(cmd_runner_fmt.as_bool, ("--superflag", "--falseflag"), True, ["--superflag"]),
+ simple_boolean_both__false=(cmd_runner_fmt.as_bool, ("--superflag", "--falseflag"), False, ["--falseflag"]),
+ simple_boolean_both__none=(cmd_runner_fmt.as_bool, ("--superflag", "--falseflag"), None, ["--falseflag"]),
+ simple_boolean_both__none_ig=(cmd_runner_fmt.as_bool, ("--superflag", "--falseflag", True), None, []),
+ simple_boolean_not__true=(cmd_runner_fmt.as_bool_not, ("--superflag",), True, []),
+ simple_boolean_not__false=(cmd_runner_fmt.as_bool_not, ("--superflag",), False, ["--superflag"]),
+ simple_boolean_not__none=(cmd_runner_fmt.as_bool_not, ("--superflag",), None, ["--superflag"]),
+ simple_optval__str=(cmd_runner_fmt.as_optval, ("-t",), "potatoes", ["-tpotatoes"]),
+ simple_optval__int=(cmd_runner_fmt.as_optval, ("-t",), 42, ["-t42"]),
+ simple_opt_val__str=(cmd_runner_fmt.as_opt_val, ("-t",), "potatoes", ["-t", "potatoes"]),
+ simple_opt_val__int=(cmd_runner_fmt.as_opt_val, ("-t",), 42, ["-t", "42"]),
+ simple_opt_eq_val__str=(cmd_runner_fmt.as_opt_eq_val, ("--food",), "potatoes", ["--food=potatoes"]),
+ simple_opt_eq_val__int=(cmd_runner_fmt.as_opt_eq_val, ("--answer",), 42, ["--answer=42"]),
+ simple_list_potato=(cmd_runner_fmt.as_list, (), "literal_potato", ["literal_potato"]),
+ simple_list_42=(cmd_runner_fmt.as_list, (), 42, ["42"]),
+ simple_map=(cmd_runner_fmt.as_map, ({'a': 1, 'b': 2, 'c': 3},), 'b', ["2"]),
+ simple_default_type__list=(cmd_runner_fmt.as_default_type, ("list",), [1, 2, 3, 5, 8], ["--1", "--2", "--3", "--5", "--8"]),
+ simple_default_type__bool_true=(cmd_runner_fmt.as_default_type, ("bool", "what"), True, ["--what"]),
+ simple_default_type__bool_false=(cmd_runner_fmt.as_default_type, ("bool", "what"), False, []),
+ simple_default_type__potato=(cmd_runner_fmt.as_default_type, ("any-other-type", "potato"), "42", ["--potato", "42"]),
+ simple_fixed_true=(cmd_runner_fmt.as_fixed, [("--always-here", "--forever")], True, ["--always-here", "--forever"]),
+ simple_fixed_false=(cmd_runner_fmt.as_fixed, [("--always-here", "--forever")], False, ["--always-here", "--forever"]),
+ simple_fixed_none=(cmd_runner_fmt.as_fixed, [("--always-here", "--forever")], None, ["--always-here", "--forever"]),
+ simple_fixed_str=(cmd_runner_fmt.as_fixed, [("--always-here", "--forever")], "something", ["--always-here", "--forever"]),
)
if tuple(version_info) >= (3, 1):
from collections import OrderedDict
# needs OrderedDict to provide a consistent key order
TC_FORMATS["simple_default_type__dict"] = ( # type: ignore
- fmt.as_default_type,
+ cmd_runner_fmt.as_default_type,
("dict",),
OrderedDict((('a', 1), ('b', 2))),
["--a=1", "--b=2"]
@@ -76,11 +76,11 @@ TC_RUNNER = dict(
# param1=dict(
# type="int",
# value=11,
- # fmt_func=fmt.as_opt_eq_val,
+ # fmt_func=cmd_runner_fmt.as_opt_eq_val,
# fmt_arg="--answer",
# ),
# param2=dict(
- # fmt_func=fmt.as_bool,
+ # fmt_func=cmd_runner_fmt.as_bool,
# fmt_arg="--bb-here",
# )
# ),
@@ -119,8 +119,8 @@ TC_RUNNER = dict(
aa_bb=(
dict(
args_bundle=dict(
- aa=dict(type="int", value=11, fmt_func=fmt.as_opt_eq_val, fmt_arg="--answer"),
- bb=dict(fmt_func=fmt.as_bool, fmt_arg="--bb-here"),
+ aa=dict(type="int", value=11, fmt_func=cmd_runner_fmt.as_opt_eq_val, fmt_arg="--answer"),
+ bb=dict(fmt_func=cmd_runner_fmt.as_bool, fmt_arg="--bb-here"),
),
runner_init_args=dict(),
runner_ctx_args=dict(args_order=['aa', 'bb']),
@@ -137,8 +137,8 @@ TC_RUNNER = dict(
aa_bb_default_order=(
dict(
args_bundle=dict(
- aa=dict(type="int", value=11, fmt_func=fmt.as_opt_eq_val, fmt_arg="--answer"),
- bb=dict(fmt_func=fmt.as_bool, fmt_arg="--bb-here"),
+ aa=dict(type="int", value=11, fmt_func=cmd_runner_fmt.as_opt_eq_val, fmt_arg="--answer"),
+ bb=dict(fmt_func=cmd_runner_fmt.as_bool, fmt_arg="--bb-here"),
),
runner_init_args=dict(default_args_order=['bb', 'aa']),
runner_ctx_args=dict(),
@@ -155,8 +155,8 @@ TC_RUNNER = dict(
aa_bb_default_order_args_order=(
dict(
args_bundle=dict(
- aa=dict(type="int", value=11, fmt_func=fmt.as_opt_eq_val, fmt_arg="--answer"),
- bb=dict(fmt_func=fmt.as_bool, fmt_arg="--bb-here"),
+ aa=dict(type="int", value=11, fmt_func=cmd_runner_fmt.as_opt_eq_val, fmt_arg="--answer"),
+ bb=dict(fmt_func=cmd_runner_fmt.as_bool, fmt_arg="--bb-here"),
),
runner_init_args=dict(default_args_order=['bb', 'aa']),
runner_ctx_args=dict(args_order=['aa', 'bb']),
@@ -173,8 +173,8 @@ TC_RUNNER = dict(
aa_bb_dup_in_args_order=(
dict(
args_bundle=dict(
- aa=dict(type="int", value=11, fmt_func=fmt.as_opt_eq_val, fmt_arg="--answer"),
- bb=dict(fmt_func=fmt.as_bool, fmt_arg="--bb-here"),
+ aa=dict(type="int", value=11, fmt_func=cmd_runner_fmt.as_opt_eq_val, fmt_arg="--answer"),
+ bb=dict(fmt_func=cmd_runner_fmt.as_bool, fmt_arg="--bb-here"),
),
runner_init_args=dict(),
runner_ctx_args=dict(args_order=['aa', 'bb', 'aa']),
@@ -189,8 +189,8 @@ TC_RUNNER = dict(
aa_bb_process_output=(
dict(
args_bundle=dict(
- aa=dict(type="int", value=11, fmt_func=fmt.as_opt_eq_val, fmt_arg="--answer"),
- bb=dict(fmt_func=fmt.as_bool, fmt_arg="--bb-here"),
+ aa=dict(type="int", value=11, fmt_func=cmd_runner_fmt.as_opt_eq_val, fmt_arg="--answer"),
+ bb=dict(fmt_func=cmd_runner_fmt.as_bool, fmt_arg="--bb-here"),
),
runner_init_args=dict(default_args_order=['bb', 'aa']),
runner_ctx_args=dict(
@@ -209,8 +209,8 @@ TC_RUNNER = dict(
aa_bb_ignore_none_with_none=(
dict(
args_bundle=dict(
- aa=dict(type="int", value=49, fmt_func=fmt.as_opt_eq_val, fmt_arg="--answer"),
- bb=dict(fmt_func=fmt.as_bool, fmt_arg="--bb-here"),
+ aa=dict(type="int", value=49, fmt_func=cmd_runner_fmt.as_opt_eq_val, fmt_arg="--answer"),
+ bb=dict(fmt_func=cmd_runner_fmt.as_bool, fmt_arg="--bb-here"),
),
runner_init_args=dict(default_args_order=['bb', 'aa']),
runner_ctx_args=dict(
@@ -228,8 +228,8 @@ TC_RUNNER = dict(
aa_bb_ignore_not_none_with_none=(
dict(
args_bundle=dict(
- aa=dict(type="int", value=49, fmt_func=fmt.as_opt_eq_val, fmt_arg="--answer"),
- bb=dict(fmt_func=fmt.as_bool, fmt_arg="--bb-here"),
+ aa=dict(type="int", value=49, fmt_func=cmd_runner_fmt.as_opt_eq_val, fmt_arg="--answer"),
+ bb=dict(fmt_func=cmd_runner_fmt.as_bool, fmt_arg="--bb-here"),
),
runner_init_args=dict(default_args_order=['bb', 'aa']),
runner_ctx_args=dict(
@@ -247,8 +247,8 @@ TC_RUNNER = dict(
aa_bb_fixed=(
dict(
args_bundle=dict(
- aa=dict(type="int", value=11, fmt_func=fmt.as_opt_eq_val, fmt_arg="--answer"),
- bb=dict(fmt_func=fmt.as_fixed, fmt_arg=["fixed", "args"]),
+ aa=dict(type="int", value=11, fmt_func=cmd_runner_fmt.as_opt_eq_val, fmt_arg="--answer"),
+ bb=dict(fmt_func=cmd_runner_fmt.as_fixed, fmt_arg=["fixed", "args"]),
),
runner_init_args=dict(),
runner_ctx_args=dict(args_order=['aa', 'bb']),
@@ -265,8 +265,8 @@ TC_RUNNER = dict(
aa_bb_map=(
dict(
args_bundle=dict(
- aa=dict(type="int", value=11, fmt_func=fmt.as_opt_eq_val, fmt_arg="--answer"),
- bb=dict(fmt_func=fmt.as_map, fmt_arg={"v1": 111, "v2": 222}),
+ aa=dict(type="int", value=11, fmt_func=cmd_runner_fmt.as_opt_eq_val, fmt_arg="--answer"),
+ bb=dict(fmt_func=cmd_runner_fmt.as_map, fmt_arg={"v1": 111, "v2": 222}),
),
runner_init_args=dict(),
runner_ctx_args=dict(args_order=['aa', 'bb']),
@@ -283,8 +283,8 @@ TC_RUNNER = dict(
aa_bb_map_default=(
dict(
args_bundle=dict(
- aa=dict(type="int", value=11, fmt_func=fmt.as_opt_eq_val, fmt_arg="--answer"),
- bb=dict(fmt_func=fmt.as_map, fmt_arg={"v1": 111, "v2": 222}),
+ aa=dict(type="int", value=11, fmt_func=cmd_runner_fmt.as_opt_eq_val, fmt_arg="--answer"),
+ bb=dict(fmt_func=cmd_runner_fmt.as_map, fmt_arg={"v1": 111, "v2": 222}),
),
runner_init_args=dict(),
runner_ctx_args=dict(args_order=['aa', 'bb']),
diff --git a/ansible_collections/community/general/tests/unit/plugins/module_utils/test_module_helper.py b/ansible_collections/community/general/tests/unit/plugins/module_utils/test_module_helper.py
index 3d8a4b654..b2cd58690 100644
--- a/ansible_collections/community/general/tests/unit/plugins/module_utils/test_module_helper.py
+++ b/ansible_collections/community/general/tests/unit/plugins/module_utils/test_module_helper.py
@@ -10,88 +10,10 @@ __metaclass__ = type
import pytest
from ansible_collections.community.general.plugins.module_utils.module_helper import (
- ArgFormat, DependencyCtxMgr, VarMeta, VarDict, cause_changes
+ DependencyCtxMgr, VarMeta, VarDict, cause_changes
)
-def single_lambda_2star(x, y, z):
- return ["piggies=[{0},{1},{2}]".format(x, y, z)]
-
-
-ARG_FORMATS = dict(
- simple_boolean_true=("--superflag", ArgFormat.BOOLEAN, 0,
- True, ["--superflag"]),
- simple_boolean_false=("--superflag", ArgFormat.BOOLEAN, 0,
- False, []),
- simple_boolean_none=("--superflag", ArgFormat.BOOLEAN, 0,
- None, []),
- simple_boolean_not_true=("--superflag", ArgFormat.BOOLEAN_NOT, 0,
- True, []),
- simple_boolean_not_false=("--superflag", ArgFormat.BOOLEAN_NOT, 0,
- False, ["--superflag"]),
- simple_boolean_not_none=("--superflag", ArgFormat.BOOLEAN_NOT, 0,
- None, ["--superflag"]),
- single_printf=("--param=%s", ArgFormat.PRINTF, 0,
- "potatoes", ["--param=potatoes"]),
- single_printf_no_substitution=("--param", ArgFormat.PRINTF, 0,
- "potatoes", ["--param"]),
- single_printf_none=("--param=%s", ArgFormat.PRINTF, 0,
- None, []),
- multiple_printf=(["--param", "free-%s"], ArgFormat.PRINTF, 0,
- "potatoes", ["--param", "free-potatoes"]),
- single_format=("--param={0}", ArgFormat.FORMAT, 0,
- "potatoes", ["--param=potatoes"]),
- single_format_none=("--param={0}", ArgFormat.FORMAT, 0,
- None, []),
- single_format_no_substitution=("--param", ArgFormat.FORMAT, 0,
- "potatoes", ["--param"]),
- multiple_format=(["--param", "free-{0}"], ArgFormat.FORMAT, 0,
- "potatoes", ["--param", "free-potatoes"]),
- multiple_format_none=(["--param", "free-{0}"], ArgFormat.FORMAT, 0,
- None, []),
- single_lambda_0star=((lambda v: ["piggies=[{0},{1},{2}]".format(v[0], v[1], v[2])]), None, 0,
- ['a', 'b', 'c'], ["piggies=[a,b,c]"]),
- single_lambda_0star_none=((lambda v: ["piggies=[{0},{1},{2}]".format(v[0], v[1], v[2])]), None, 0,
- None, []),
- single_lambda_1star=((lambda a, b, c: ["piggies=[{0},{1},{2}]".format(a, b, c)]), None, 1,
- ['a', 'b', 'c'], ["piggies=[a,b,c]"]),
- single_lambda_1star_none=((lambda a, b, c: ["piggies=[{0},{1},{2}]".format(a, b, c)]), None, 1,
- None, []),
- single_lambda_2star=(single_lambda_2star, None, 2,
- dict(z='c', x='a', y='b'), ["piggies=[a,b,c]"]),
- single_lambda_2star_none=(single_lambda_2star, None, 2,
- None, []),
-)
-ARG_FORMATS_IDS = sorted(ARG_FORMATS.keys())
-
-
-@pytest.mark.parametrize('fmt, style, stars, value, expected',
- (ARG_FORMATS[tc] for tc in ARG_FORMATS_IDS),
- ids=ARG_FORMATS_IDS)
-def test_arg_format(fmt, style, stars, value, expected):
- af = ArgFormat('name', fmt, style, stars)
- actual = af.to_text(value)
- print("formatted string = {0}".format(actual))
- assert actual == expected, "actual = {0}".format(actual)
-
-
-ARG_FORMATS_FAIL = dict(
- int_fmt=(3, None, 0, "", [""]),
- bool_fmt=(True, None, 0, "", [""]),
-)
-ARG_FORMATS_FAIL_IDS = sorted(ARG_FORMATS_FAIL.keys())
-
-
-@pytest.mark.parametrize('fmt, style, stars, value, expected',
- (ARG_FORMATS_FAIL[tc] for tc in ARG_FORMATS_FAIL_IDS),
- ids=ARG_FORMATS_FAIL_IDS)
-def test_arg_format_fail(fmt, style, stars, value, expected):
- with pytest.raises(TypeError):
- af = ArgFormat('name', fmt, style, stars)
- actual = af.to_text(value)
- print("formatted string = {0}".format(actual))
-
-
def test_dependency_ctxmgr():
ctx = DependencyCtxMgr("POTATOES", "Potatoes must be installed")
with ctx:
diff --git a/ansible_collections/community/general/tests/unit/plugins/module_utils/test_vardict.py b/ansible_collections/community/general/tests/unit/plugins/module_utils/test_vardict.py
new file mode 100644
index 000000000..01d710b44
--- /dev/null
+++ b/ansible_collections/community/general/tests/unit/plugins/module_utils/test_vardict.py
@@ -0,0 +1,134 @@
+# -*- coding: utf-8 -*-
+# (c) 2023, Alexei Znamensky <russoz@gmail.com>
+# Copyright (c) 2023 Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+
+from ansible_collections.community.general.plugins.module_utils.vardict import VarDict
+
+
+def test_var_simple():
+ vd = VarDict()
+ vd["a"] = 123
+
+ var = vd._var("a")
+ assert var.output is True
+ assert var.diff is False
+ assert var.change is False
+ assert var.fact is False
+ assert var.initial_value == 123
+ assert var.value == 123
+
+ vd.a = 456
+ assert var.output is True
+ assert var.diff is False
+ assert var.change is False
+ assert var.fact is False
+ assert var.initial_value == 123
+ assert var.value == 456
+
+
+def test_var_diff_scalar():
+ vd = VarDict()
+ vd.set("aa", 123, diff=True)
+
+ var = vd._var("aa")
+ assert var.output is True
+ assert var.diff is True
+ assert var.change is True
+ assert var.fact is False
+ assert var.initial_value == 123
+ assert var.value == 123
+ assert vd.diff() is None
+
+ vd.aa = 456
+ assert var.output is True
+ assert var.diff is True
+ assert var.change is True
+ assert var.fact is False
+ assert var.initial_value == 123
+ assert var.value == 456
+ assert vd.diff() == {"before": {"aa": 123}, "after": {"aa": 456}}, "actual={0}".format(vd.diff())
+
+
+def test_var_diff_dict():
+ val_before = dict(x=0, y=10, z=10)
+ val_after = dict(x=0, y=30, z=10)
+
+ vd = VarDict()
+ vd.set("dd", val_before, diff=True)
+
+ var = vd._var("dd")
+ assert var.output is True
+ assert var.diff is True
+ assert var.change is True
+ assert var.fact is False
+ assert var.initial_value == val_before
+ assert var.value == val_before
+ assert vd.diff() is None
+
+ vd.dd = val_after
+ assert var.output is True
+ assert var.diff is True
+ assert var.change is True
+ assert var.fact is False
+ assert var.initial_value == val_before
+ assert var.value == val_after
+ assert vd.diff() == {"before": {"dd": val_before}, "after": {"dd": val_after}}, "actual={0}".format(vd.diff())
+
+ vd.set("aa", 123, diff=True)
+ vd.aa = 456
+ assert vd.diff() == {"before": {"aa": 123, "dd": val_before}, "after": {"aa": 456, "dd": val_after}}, "actual={0}".format(vd.diff())
+
+
+def test_vardict_set_meta():
+ vd = VarDict()
+ vd["jj"] = 123
+
+ var = vd._var("jj")
+ assert var.output is True
+ assert var.diff is False
+ assert var.change is False
+ assert var.fact is False
+ assert var.initial_value == 123
+ assert var.value == 123
+
+ vd.set_meta("jj", diff=True)
+ assert var.diff is True
+ assert var.change is True
+
+ vd.set_meta("jj", diff=False)
+ assert var.diff is False
+ assert var.change is False
+
+ vd.set_meta("jj", change=False)
+ vd.set_meta("jj", diff=True)
+ assert var.diff is True
+ assert var.change is False
+
+
+def test_vardict_change():
+ vd = VarDict()
+ vd.set("xx", 123, change=True)
+ vd.set("yy", 456, change=True)
+ vd.set("zz", 789, change=True)
+
+ vd.xx = 123
+ vd.yy = 456
+ assert vd.has_changed is False
+ vd.xx = 12345
+ assert vd.has_changed is True
+
+
+def test_vardict_dict():
+ vd = VarDict()
+ vd.set("xx", 123)
+ vd.set("yy", 456)
+ vd.set("zz", 789)
+
+ assert vd.as_dict() == {"xx": 123, "yy": 456, "zz": 789}
+ assert vd.get_meta("xx") == {"output": True, "change": False, "diff": False, "fact": False, "verbosity": 0}
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/gitlab.py b/ansible_collections/community/general/tests/unit/plugins/modules/gitlab.py
index c64d99fff..7a52dc355 100644
--- a/ansible_collections/community/general/tests/unit/plugins/modules/gitlab.py
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/gitlab.py
@@ -284,6 +284,36 @@ def resp_delete_group(url, request):
return response(204, content, headers, None, 5, request)
+@urlmatch(scheme="http", netloc="localhost", path="/api/v4/groups/1/access_tokens", method="get")
+def resp_list_group_access_tokens(url, request):
+ headers = {'content-type': 'application/json'}
+ content = ('[{"user_id" : 1, "scopes" : ["api"], "name" : "token1", "expires_at" : "2021-01-31",'
+ '"id" : 1, "active" : false, "created_at" : "2021-01-20T22:11:48.151Z", "revoked" : true,'
+ '"access_level": 40},{"user_id" : 2, "scopes" : ["api"], "name" : "token2", "expires_at" : "2021-02-31",'
+ '"id" : 2, "active" : true, "created_at" : "2021-02-20T22:11:48.151Z", "revoked" : false,'
+ '"access_level": 40}]')
+ content = content.encode("utf-8")
+ return response(200, content, headers, None, 5, request)
+
+
+@urlmatch(scheme="http", netloc="localhost", path="/api/v4/groups/1/access_tokens", method="post")
+def resp_create_group_access_tokens(url, request):
+ headers = {'content-type': 'application/json'}
+ content = ('{"user_id" : 1, "scopes" : ["api"], "name" : "token1", "expires_at" : "2021-01-31",'
+ '"id" : 1, "active" : false, "created_at" : "2021-01-20T22:11:48.151Z", "revoked" : true,'
+ '"access_level": 40, "token": "Der423FErcdv35qEEWc"}')
+ content = content.encode("utf-8")
+ return response(201, content, headers, None, 5, request)
+
+
+@urlmatch(scheme="http", netloc="localhost", path="/api/v4/groups/1/access_tokens/1", method="delete")
+def resp_revoke_group_access_tokens(url, request):
+ headers = {'content-type': 'application/json'}
+ content = ('')
+ content = content.encode("utf-8")
+ return response(204, content, headers, None, 5, request)
+
+
'''
GROUP MEMBER API
'''
@@ -534,6 +564,36 @@ def resp_delete_protected_branch(url, request):
return response(204, content, headers, None, 5, request)
+@urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects/1/access_tokens", method="get")
+def resp_list_project_access_tokens(url, request):
+ headers = {'content-type': 'application/json'}
+ content = ('[{"user_id" : 1, "scopes" : ["api"], "name" : "token1", "expires_at" : "2021-01-31",'
+ '"id" : 1, "active" : false, "created_at" : "2021-01-20T22:11:48.151Z", "revoked" : true,'
+ '"access_level": 40},{"user_id" : 2, "scopes" : ["api"], "name" : "token2", "expires_at" : "2021-02-31",'
+ '"id" : 2, "active" : true, "created_at" : "2021-02-20T22:11:48.151Z", "revoked" : false,'
+ '"access_level": 40}]')
+ content = content.encode("utf-8")
+ return response(200, content, headers, None, 5, request)
+
+
+@urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects/1/access_tokens", method="post")
+def resp_create_project_access_tokens(url, request):
+ headers = {'content-type': 'application/json'}
+ content = ('{"user_id" : 1, "scopes" : ["api"], "name" : "token1", "expires_at" : "2021-01-31",'
+ '"id" : 1, "active" : false, "created_at" : "2021-01-20T22:11:48.151Z", "revoked" : true,'
+ '"access_level": 40, "token": "Der423FErcdv35qEEWc"}')
+ content = content.encode("utf-8")
+ return response(201, content, headers, None, 5, request)
+
+
+@urlmatch(scheme="http", netloc="localhost", path="/api/v4/projects/1/access_tokens/1", method="delete")
+def resp_revoke_project_access_tokens(url, request):
+ headers = {'content-type': 'application/json'}
+ content = ('')
+ content = content.encode("utf-8")
+ return response(204, content, headers, None, 5, request)
+
+
'''
HOOK API
'''
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/helper.py b/ansible_collections/community/general/tests/unit/plugins/modules/helper.py
new file mode 100644
index 000000000..a7322bf4d
--- /dev/null
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/helper.py
@@ -0,0 +1,181 @@
+# Copyright (c) Ansible project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import sys
+import json
+from collections import namedtuple
+from itertools import chain, repeat
+
+import pytest
+import yaml
+
+
+ModuleTestCase = namedtuple("ModuleTestCase", ["id", "input", "output", "run_command_calls", "flags"])
+RunCmdCall = namedtuple("RunCmdCall", ["command", "environ", "rc", "out", "err"])
+
+
+class _BaseContext(object):
+ def __init__(self, helper, testcase, mocker, capfd):
+ self.helper = helper
+ self.testcase = testcase
+ self.mocker = mocker
+ self.capfd = capfd
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ return False
+
+ def _run(self):
+ with pytest.raises(SystemExit):
+ self.helper.module_main()
+
+ out, err = self.capfd.readouterr()
+ results = json.loads(out)
+
+ self.check_results(results)
+
+ def test_flags(self, flag=None):
+ flags = self.testcase.flags
+ if flag:
+ flags = flags.get(flag)
+ return flags
+
+ def run(self):
+ func = self._run
+
+ test_flags = self.test_flags()
+ if test_flags.get("skip"):
+ pytest.skip()
+ if test_flags.get("xfail"):
+ pytest.xfail()
+
+ func()
+
+ def check_results(self, results):
+ print("testcase =\n%s" % str(self.testcase))
+ print("results =\n%s" % results)
+ if 'exception' in results:
+ print("exception = \n%s" % results["exception"])
+
+ for test_result in self.testcase.output:
+ assert results[test_result] == self.testcase.output[test_result], \
+ "'{0}': '{1}' != '{2}'".format(test_result, results[test_result], self.testcase.output[test_result])
+
+
+class _RunCmdContext(_BaseContext):
+ def __init__(self, *args, **kwargs):
+ super(_RunCmdContext, self).__init__(*args, **kwargs)
+ self.run_cmd_calls = self.testcase.run_command_calls
+ self.mock_run_cmd = self._make_mock_run_cmd()
+
+ def _make_mock_run_cmd(self):
+ call_results = [(x.rc, x.out, x.err) for x in self.run_cmd_calls]
+ error_call_results = (123,
+ "OUT: testcase has not enough run_command calls",
+ "ERR: testcase has not enough run_command calls")
+ mock_run_command = self.mocker.patch('ansible.module_utils.basic.AnsibleModule.run_command',
+ side_effect=chain(call_results, repeat(error_call_results)))
+ return mock_run_command
+
+ def check_results(self, results):
+ super(_RunCmdContext, self).check_results(results)
+ call_args_list = [(item[0][0], item[1]) for item in self.mock_run_cmd.call_args_list]
+ expected_call_args_list = [(item.command, item.environ) for item in self.run_cmd_calls]
+ print("call args list =\n%s" % call_args_list)
+ print("expected args list =\n%s" % expected_call_args_list)
+
+ assert self.mock_run_cmd.call_count == len(self.run_cmd_calls), "{0} != {1}".format(self.mock_run_cmd.call_count, len(self.run_cmd_calls))
+ if self.mock_run_cmd.call_count:
+ assert call_args_list == expected_call_args_list
+
+
+class Helper(object):
+ @staticmethod
+ def from_list(module_main, list_):
+ helper = Helper(module_main, test_cases=list_)
+ return helper
+
+ @staticmethod
+ def from_file(module_main, filename):
+ with open(filename, "r") as test_cases:
+ helper = Helper(module_main, test_cases=test_cases)
+ return helper
+
+ @staticmethod
+ def from_module(module, test_module_name):
+ basename = module.__name__.split(".")[-1]
+ test_spec = "tests/unit/plugins/modules/test_{0}.yaml".format(basename)
+ helper = Helper.from_file(module.main, test_spec)
+
+ setattr(sys.modules[test_module_name], "patch_bin", helper.cmd_fixture)
+ setattr(sys.modules[test_module_name], "test_module", helper.test_module)
+
+ def __init__(self, module_main, test_cases):
+ self.module_main = module_main
+ self._test_cases = test_cases
+ if isinstance(test_cases, (list, tuple)):
+ self.testcases = test_cases
+ else:
+ self.testcases = self._make_test_cases()
+
+ @property
+ def cmd_fixture(self):
+ @pytest.fixture
+ def patch_bin(mocker):
+ def mockie(self, path, *args, **kwargs):
+ return "/testbin/{0}".format(path)
+ mocker.patch('ansible.module_utils.basic.AnsibleModule.get_bin_path', mockie)
+
+ return patch_bin
+
+ def _make_test_cases(self):
+ test_cases = yaml.safe_load(self._test_cases)
+
+ results = []
+ for tc in test_cases:
+ for tc_param in ["input", "output", "flags"]:
+ if not tc.get(tc_param):
+ tc[tc_param] = {}
+ if tc.get("run_command_calls"):
+ tc["run_command_calls"] = [RunCmdCall(**r) for r in tc["run_command_calls"]]
+ else:
+ tc["run_command_calls"] = []
+ results.append(ModuleTestCase(**tc))
+
+ return results
+
+ @property
+ def testcases_params(self):
+ return [[x.input, x] for x in self.testcases]
+
+ @property
+ def testcases_ids(self):
+ return [item.id for item in self.testcases]
+
+ def __call__(self, *args, **kwargs):
+ return _RunCmdContext(self, *args, **kwargs)
+
+ @property
+ def test_module(self):
+ helper = self
+
+ @pytest.mark.parametrize('patch_ansible_module, testcase',
+ helper.testcases_params, ids=helper.testcases_ids,
+ indirect=['patch_ansible_module'])
+ @pytest.mark.usefixtures('patch_ansible_module')
+ def _test_module(mocker, capfd, patch_bin, testcase):
+ """
+ Run unit tests for test cases listed in TEST_CASES
+ """
+
+ with helper(testcase, mocker, capfd) as testcase_context:
+ testcase_context.run()
+
+ return _test_module
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_cpanm.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_cpanm.py
index 5367a1fab..4eecf000f 100644
--- a/ansible_collections/community/general/tests/unit/plugins/modules/test_cpanm.py
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_cpanm.py
@@ -12,282 +12,9 @@
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
-import json
from ansible_collections.community.general.plugins.modules import cpanm
+from .helper import Helper
-import pytest
-TESTED_MODULE = cpanm.__name__
-
-
-@pytest.fixture
-def patch_cpanm(mocker):
- """
- Function used for mocking some parts of redhat_subscription module
- """
- mocker.patch('ansible.module_utils.basic.AnsibleModule.get_bin_path',
- return_value='/testbin/cpanm')
-
-
-TEST_CASES = [
- [
- {'name': 'Dancer'},
- {
- 'id': 'install_dancer_compatibility',
- 'run_command.calls': [
- (
- ['/testbin/cpanm', '-le', 'use Dancer;'],
- {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
- (2, '', 'error, not installed',), # output rc, out, err
- ),
- (
- ['/testbin/cpanm', 'Dancer'],
- {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': True},
- (0, '', '',), # output rc, out, err
- ),
- ],
- 'changed': True,
- }
- ],
- [
- {'name': 'Dancer'},
- {
- 'id': 'install_dancer_already_installed_compatibility',
- 'run_command.calls': [
- (
- ['/testbin/cpanm', '-le', 'use Dancer;'],
- {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
- (0, '', '',), # output rc, out, err
- ),
- ],
- 'changed': False,
- }
- ],
- [
- {'name': 'Dancer', 'mode': 'new'},
- {
- 'id': 'install_dancer',
- 'run_command.calls': [(
- ['/testbin/cpanm', 'Dancer'],
- {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': True},
- (0, '', '',), # output rc, out, err
- )],
- 'changed': True,
- }
- ],
- [
- {'name': 'MIYAGAWA/Plack-0.99_05.tar.gz'},
- {
- 'id': 'install_distribution_file_compatibility',
- 'run_command.calls': [(
- ['/testbin/cpanm', 'MIYAGAWA/Plack-0.99_05.tar.gz'],
- {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': True},
- (0, '', '',), # output rc, out, err
- )],
- 'changed': True,
- }
- ],
- [
- {'name': 'MIYAGAWA/Plack-0.99_05.tar.gz', 'mode': 'new'},
- {
- 'id': 'install_distribution_file',
- 'run_command.calls': [(
- ['/testbin/cpanm', 'MIYAGAWA/Plack-0.99_05.tar.gz'],
- {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': True},
- (0, '', '',), # output rc, out, err
- )],
- 'changed': True,
- }
- ],
- [
- {'name': 'Dancer', 'locallib': '/srv/webapps/my_app/extlib', 'mode': 'new'},
- {
- 'id': 'install_into_locallib',
- 'run_command.calls': [(
- ['/testbin/cpanm', '--local-lib', '/srv/webapps/my_app/extlib', 'Dancer'],
- {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': True},
- (0, '', '',), # output rc, out, err
- )],
- 'changed': True,
- }
- ],
- [
- {'from_path': '/srv/webapps/my_app/src/', 'mode': 'new'},
- {
- 'id': 'install_from_local_directory',
- 'run_command.calls': [(
- ['/testbin/cpanm', '/srv/webapps/my_app/src/'],
- {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': True},
- (0, '', '',), # output rc, out, err
- )],
- 'changed': True,
- }
- ],
- [
- {'name': 'Dancer', 'locallib': '/srv/webapps/my_app/extlib', 'notest': True, 'mode': 'new'},
- {
- 'id': 'install_into_locallib_no_unit_testing',
- 'run_command.calls': [(
- ['/testbin/cpanm', '--notest', '--local-lib', '/srv/webapps/my_app/extlib', 'Dancer'],
- {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': True},
- (0, '', '',), # output rc, out, err
- )],
- 'changed': True,
- }
- ],
- [
- {'name': 'Dancer', 'mirror': 'http://cpan.cpantesters.org/', 'mode': 'new'},
- {
- 'id': 'install_from_mirror',
- 'run_command.calls': [(
- ['/testbin/cpanm', '--mirror', 'http://cpan.cpantesters.org/', 'Dancer'],
- {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': True},
- (0, '', '',), # output rc, out, err
- )],
- 'changed': True,
- }
- ],
- [
- {'name': 'Dancer', 'system_lib': True, 'mode': 'new'},
- {
- 'id': 'install_into_system_lib',
- 'run_command.calls': [],
- 'changed': False,
- 'failed': True,
- }
- ],
- [
- {'name': 'Dancer', 'version': '1.0', 'mode': 'new'},
- {
- 'id': 'install_minversion_implicit',
- 'run_command.calls': [(
- ['/testbin/cpanm', 'Dancer~1.0'],
- {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': True},
- (0, '', '',), # output rc, out, err
- )],
- 'changed': True,
- }
- ],
- [
- {'name': 'Dancer', 'version': '~1.5', 'mode': 'new'},
- {
- 'id': 'install_minversion_explicit',
- 'run_command.calls': [(
- ['/testbin/cpanm', 'Dancer~1.5'],
- {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': True},
- (0, '', '',), # output rc, out, err
- )],
- 'changed': True,
- }
- ],
- [
- {'name': 'Dancer', 'version': '@1.7', 'mode': 'new'},
- {
- 'id': 'install_specific_version',
- 'run_command.calls': [(
- ['/testbin/cpanm', 'Dancer@1.7'],
- {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': True},
- (0, '', '',), # output rc, out, err
- )],
- 'changed': True,
- 'failed': False,
- }
- ],
- [
- {'name': 'MIYAGAWA/Plack-0.99_05.tar.gz', 'version': '@1.7', 'mode': 'new'},
- {
- 'id': 'install_specific_version_from_file_error',
- 'run_command.calls': [],
- 'changed': False,
- 'failed': True,
- 'msg': "parameter 'version' must not be used when installing from a file",
- }
- ],
- [
- {'from_path': '~/', 'version': '@1.7', 'mode': 'new'},
- {
- 'id': 'install_specific_version_from_directory_error',
- 'run_command.calls': [],
- 'changed': False,
- 'failed': True,
- 'msg': "parameter 'version' must not be used when installing from a directory",
- }
- ],
- [
- {'name': 'git://github.com/plack/Plack.git', 'version': '@1.7', 'mode': 'new'},
- {
- 'id': 'install_specific_version_from_git_url_explicit',
- 'run_command.calls': [(
- ['/testbin/cpanm', 'git://github.com/plack/Plack.git@1.7'],
- {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': True},
- (0, '', '',), # output rc, out, err
- )],
- 'changed': True,
- 'failed': False,
- }
- ],
- [
- {'name': 'git://github.com/plack/Plack.git', 'version': '2.5', 'mode': 'new'},
- {
- 'id': 'install_specific_version_from_git_url_implicit',
- 'run_command.calls': [(
- ['/testbin/cpanm', 'git://github.com/plack/Plack.git@2.5'],
- {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': True},
- (0, '', '',), # output rc, out, err
- )],
- 'changed': True,
- 'failed': False,
- }
- ],
- [
- {'name': 'git://github.com/plack/Plack.git', 'version': '~2.5', 'mode': 'new'},
- {
- 'id': 'install_version_operator_from_git_url_error',
- 'run_command.calls': [],
- 'changed': False,
- 'failed': True,
- 'msg': "operator '~' not allowed in version parameter when installing from git repository",
- }
- ],
-]
-TEST_CASES_IDS = [item[1]['id'] for item in TEST_CASES]
-
-
-@pytest.mark.parametrize('patch_ansible_module, testcase',
- TEST_CASES,
- ids=TEST_CASES_IDS,
- indirect=['patch_ansible_module'])
-@pytest.mark.usefixtures('patch_ansible_module')
-def test_cpanm(mocker, capfd, patch_cpanm, testcase):
- """
- Run unit tests for test cases listen in TEST_CASES
- """
-
- # Mock function used for running commands first
- call_results = [item[2] for item in testcase['run_command.calls']]
- mock_run_command = mocker.patch(
- 'ansible_collections.community.general.plugins.module_utils.module_helper.AnsibleModule.run_command',
- side_effect=call_results)
-
- # Try to run test case
- with pytest.raises(SystemExit):
- cpanm.main()
-
- out, err = capfd.readouterr()
- results = json.loads(out)
- print("results =\n%s" % results)
-
- assert mock_run_command.call_count == len(testcase['run_command.calls'])
- if mock_run_command.call_count:
- call_args_list = [(item[0][0], item[1]) for item in mock_run_command.call_args_list]
- expected_call_args_list = [(item[0], item[1]) for item in testcase['run_command.calls']]
- print("call args list =\n%s" % call_args_list)
- print("expected args list =\n%s" % expected_call_args_list)
- assert call_args_list == expected_call_args_list
-
- assert results.get('changed', False) == testcase['changed']
- if 'failed' in testcase:
- assert results.get('failed', False) == testcase['failed']
- if 'msg' in testcase:
- assert results.get('msg', '') == testcase['msg']
+Helper.from_module(cpanm, __name__)
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_cpanm.yaml b/ansible_collections/community/general/tests/unit/plugins/modules/test_cpanm.yaml
new file mode 100644
index 000000000..3ed718d48
--- /dev/null
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_cpanm.yaml
@@ -0,0 +1,220 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) Alexei Znamensky (russoz@gmail.com)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+---
+- id: install_dancer_compatibility
+ input:
+ name: Dancer
+ output:
+ changed: true
+ run_command_calls:
+ - command: [/testbin/perl, -le, 'use Dancer;']
+ environ: &env-def-false {environ_update: {LANGUAGE: C, LC_ALL: C}, check_rc: false}
+ rc: 2
+ out: ""
+ err: "error, not installed"
+ - command: [/testbin/cpanm, Dancer]
+ environ: &env-def-true {environ_update: {LANGUAGE: C, LC_ALL: C}, check_rc: true}
+ rc: 0
+ out: ""
+ err: ""
+- id: install_dancer_already_installed_compatibility
+ input:
+ name: Dancer
+ output:
+ changed: false
+ run_command_calls:
+ - command: [/testbin/perl, -le, 'use Dancer;']
+ environ: *env-def-false
+ rc: 0
+ out: ""
+ err: ""
+- id: install_dancer
+ input:
+ name: Dancer
+ mode: new
+ output:
+ changed: true
+ run_command_calls:
+ - command: [/testbin/cpanm, Dancer]
+ environ: *env-def-true
+ rc: 0
+ out: ""
+ err: ""
+- id: install_distribution_file_compatibility
+ input:
+ name: MIYAGAWA/Plack-0.99_05.tar.gz
+ output:
+ changed: true
+ run_command_calls:
+ - command: [/testbin/cpanm, MIYAGAWA/Plack-0.99_05.tar.gz]
+ environ: *env-def-true
+ rc: 0
+ out: ""
+ err: ""
+- id: install_distribution_file
+ input:
+ name: MIYAGAWA/Plack-0.99_05.tar.gz
+ mode: new
+ output:
+ changed: true
+ run_command_calls:
+ - command: [/testbin/cpanm, MIYAGAWA/Plack-0.99_05.tar.gz]
+ environ: *env-def-true
+ rc: 0
+ out: ""
+ err: ""
+- id: install_into_locallib
+ input:
+ name: Dancer
+ mode: new
+ locallib: /srv/webapps/my_app/extlib
+ output:
+ changed: true
+ run_command_calls:
+ - command: [/testbin/cpanm, --local-lib, /srv/webapps/my_app/extlib, Dancer]
+ environ: *env-def-true
+ rc: 0
+ out: ""
+ err: ""
+- id: install_from_local_directory
+ input:
+ from_path: /srv/webapps/my_app/src/
+ mode: new
+ output:
+ changed: true
+ run_command_calls:
+ - command: [/testbin/cpanm, /srv/webapps/my_app/src/]
+ environ: *env-def-true
+ rc: 0
+ out: ""
+ err: ""
+- id: install_into_locallib_no_unit_testing
+ input:
+ name: Dancer
+ notest: true
+ mode: new
+ locallib: /srv/webapps/my_app/extlib
+ output:
+ changed: true
+ run_command_calls:
+ - command: [/testbin/cpanm, --notest, --local-lib, /srv/webapps/my_app/extlib, Dancer]
+ environ: *env-def-true
+ rc: 0
+ out: ""
+ err: ""
+- id: install_from_mirror
+ input:
+ name: Dancer
+ mode: new
+ mirror: "http://cpan.cpantesters.org/"
+ output:
+ changed: true
+ run_command_calls:
+ - command: [/testbin/cpanm, --mirror, "http://cpan.cpantesters.org/", Dancer]
+ environ: *env-def-true
+ rc: 0
+ out: ""
+ err: ""
+- id: install_into_system_lib
+ input:
+ name: Dancer
+ mode: new
+ system_lib: true
+ output:
+ failed: true
+ run_command_calls: []
+- id: install_minversion_implicit
+ input:
+ name: Dancer
+ mode: new
+ version: "1.0"
+ output:
+ changed: true
+ run_command_calls:
+ - command: [/testbin/cpanm, Dancer~1.0]
+ environ: *env-def-true
+ rc: 0
+ out: ""
+ err: ""
+- id: install_minversion_explicit
+ input:
+ name: Dancer
+ mode: new
+ version: "~1.5"
+ output:
+ changed: true
+ run_command_calls:
+ - command: [/testbin/cpanm, Dancer~1.5]
+ environ: *env-def-true
+ rc: 0
+ out: ""
+ err: ""
+- id: install_specific_version
+ input:
+ name: Dancer
+ mode: new
+ version: "@1.7"
+ output:
+ changed: true
+ run_command_calls:
+ - command: [/testbin/cpanm, Dancer@1.7]
+ environ: *env-def-true
+ rc: 0
+ out: ""
+ err: ""
+- id: install_specific_version_from_file_error
+ input:
+ name: MIYAGAWA/Plack-0.99_05.tar.gz
+ mode: new
+ version: "@1.7"
+ output:
+ failed: true
+ msg: parameter 'version' must not be used when installing from a file
+ run_command_calls: []
+- id: install_specific_version_from_directory_error
+ input:
+ from_path: ~/
+ mode: new
+ version: "@1.7"
+ output:
+ failed: true
+ msg: parameter 'version' must not be used when installing from a directory
+ run_command_calls: []
+- id: install_specific_version_from_git_url_explicit
+ input:
+ name: "git://github.com/plack/Plack.git"
+ mode: new
+ version: "@1.7"
+ output:
+ changed: true
+ run_command_calls:
+ - command: [/testbin/cpanm, "git://github.com/plack/Plack.git@1.7"]
+ environ: *env-def-true
+ rc: 0
+ out: ""
+ err: ""
+- id: install_specific_version_from_git_url_implicit
+ input:
+ name: "git://github.com/plack/Plack.git"
+ mode: new
+ version: "2.5"
+ output:
+ changed: true
+ run_command_calls:
+ - command: [/testbin/cpanm, "git://github.com/plack/Plack.git@2.5"]
+ environ: *env-def-true
+ rc: 0
+ out: ""
+ err: ""
+- id: install_version_operator_from_git_url_error
+ input:
+ name: "git://github.com/plack/Plack.git"
+ mode: new
+ version: "~2.5"
+ output:
+ failed: true
+ msg: operator '~' not allowed in version parameter when installing from git repository
+ run_command_calls: []
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_dnf_config_manager.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_dnf_config_manager.py
new file mode 100644
index 000000000..90bffe436
--- /dev/null
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_dnf_config_manager.py
@@ -0,0 +1,402 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2023, Andrew Hyatt <andy@hyatt.xyz>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+from __future__ import (absolute_import, division, print_function)
+
+__metaclass__ = type
+
+from ansible_collections.community.general.tests.unit.compat.mock import patch, call
+from ansible_collections.community.general.plugins.modules import dnf_config_manager as dnf_config_manager_module
+from ansible_collections.community.general.tests.unit.plugins.modules.utils import AnsibleExitJson, AnsibleFailJson, \
+ ModuleTestCase, set_module_args
+
+# Return value on all-default arguments
+mock_repolist_crb_enabled = """Loaded plugins: builddep, changelog, config-manager, copr, debug, debuginfo-install
+DNF version: 4.14.0
+cachedir: /var/cache/dnf
+Last metadata expiration check: 1:20:49 ago on Fri 22 Dec 2023 06:05:13 PM UTC.
+Repo-id : appstream
+Repo-name : AlmaLinux 9 - AppStream
+Repo-status : enabled
+Repo-revision : 1703240474
+Repo-updated : Fri 22 Dec 2023 10:21:14 AM UTC
+Repo-pkgs : 5,897
+Repo-available-pkgs: 5,728
+Repo-size : 9.5 G
+Repo-mirrors : https://mirrors.almalinux.org/mirrorlist/9/appstream
+Repo-baseurl : http://mirror.cogentco.com/pub/linux/almalinux/9.3/AppStream/x86_64/os/ (9 more)
+Repo-expire : 86,400 second(s) (last: Fri 22 Dec 2023 06:05:11 PM UTC)
+Repo-filename : /etc/yum.repos.d/almalinux-appstream.repo
+
+Repo-id : appstream-debuginfo
+Repo-name : AlmaLinux 9 - AppStream - Debug
+Repo-status : disabled
+Repo-mirrors : https://mirrors.almalinux.org/mirrorlist/9/appstream-debug
+Repo-expire : 86,400 second(s) (last: unknown)
+Repo-filename : /etc/yum.repos.d/almalinux-appstream.repo
+
+Repo-id : appstream-source
+Repo-name : AlmaLinux 9 - AppStream - Source
+Repo-status : disabled
+Repo-mirrors : https://mirrors.almalinux.org/mirrorlist/9/appstream-source
+Repo-expire : 86,400 second(s) (last: unknown)
+Repo-filename : /etc/yum.repos.d/almalinux-appstream.repo
+
+Repo-id : baseos
+Repo-name : AlmaLinux 9 - BaseOS
+Repo-status : enabled
+Repo-revision : 1703240561
+Repo-updated : Fri 22 Dec 2023 10:22:41 AM UTC
+Repo-pkgs : 1,244
+Repo-available-pkgs: 1,244
+Repo-size : 1.3 G
+Repo-mirrors : https://mirrors.almalinux.org/mirrorlist/9/baseos
+Repo-baseurl : http://mirror.cogentco.com/pub/linux/almalinux/9.3/BaseOS/x86_64/os/ (9 more)
+Repo-expire : 86,400 second(s) (last: Fri 22 Dec 2023 06:05:11 PM UTC)
+Repo-filename : /etc/yum.repos.d/almalinux-baseos.repo
+
+Repo-id : baseos-debuginfo
+Repo-name : AlmaLinux 9 - BaseOS - Debug
+Repo-status : disabled
+Repo-mirrors : https://mirrors.almalinux.org/mirrorlist/9/baseos-debug
+Repo-expire : 86,400 second(s) (last: unknown)
+Repo-filename : /etc/yum.repos.d/almalinux-baseos.repo
+
+Repo-id : baseos-source
+Repo-name : AlmaLinux 9 - BaseOS - Source
+Repo-status : disabled
+Repo-mirrors : https://mirrors.almalinux.org/mirrorlist/9/baseos-source
+Repo-expire : 86,400 second(s) (last: unknown)
+Repo-filename : /etc/yum.repos.d/almalinux-baseos.repo
+
+Repo-id : copr:copr.fedorainfracloud.org:uriesk:dracut-crypt-ssh
+Repo-name : Copr repo for dracut-crypt-ssh owned by uriesk
+Repo-status : enabled
+Repo-revision : 1698291016
+Repo-updated : Thu 26 Oct 2023 03:30:16 AM UTC
+Repo-pkgs : 4
+Repo-available-pkgs: 4
+Repo-size : 102 k
+Repo-baseurl : https://download.copr.fedorainfracloud.org/results/uriesk/dracut-crypt-ssh/epel-9-x86_64/
+Repo-expire : 172,800 second(s) (last: Fri 22 Dec 2023 06:05:10 PM UTC)
+Repo-filename : /etc/yum.repos.d/_copr:copr.fedorainfracloud.org:uriesk:dracut-crypt-ssh.repo
+
+Repo-id : crb
+Repo-name : AlmaLinux 9 - CRB
+Repo-status : enabled
+Repo-revision : 1703240590
+Repo-updated : Fri 22 Dec 2023 10:23:10 AM UTC
+Repo-pkgs : 1,730
+Repo-available-pkgs: 1,727
+Repo-size : 13 G
+Repo-mirrors : https://mirrors.almalinux.org/mirrorlist/9/crb
+Repo-baseurl : http://mirror.cogentco.com/pub/linux/almalinux/9.3/CRB/x86_64/os/ (9 more)
+Repo-expire : 86,400 second(s) (last: Fri 22 Dec 2023 06:05:11 PM UTC)
+Repo-filename : /etc/yum.repos.d/almalinux-crb.repo
+
+Repo-id : rpmfusion-nonfree-updates
+Repo-name : RPM Fusion for EL 9 - Nonfree - Updates
+Repo-status : enabled
+Repo-revision : 1703248251
+Repo-tags : binary-x86_64
+Repo-updated : Fri 22 Dec 2023 12:30:53 PM UTC
+Repo-pkgs : 65
+Repo-available-pkgs: 65
+Repo-size : 944 M
+Repo-metalink : http://mirrors.rpmfusion.org/metalink?repo=nonfree-el-updates-released-9&arch=x86_64
+ Updated : Fri 22 Dec 2023 06:05:13 PM UTC
+Repo-baseurl : http://uvermont.mm.fcix.net/rpmfusion/nonfree/el/updates/9/x86_64/ (33 more)
+Repo-expire : 172,800 second(s) (last: Fri 22 Dec 2023 06:05:13 PM UTC)
+Repo-filename : /etc/yum.repos.d/rpmfusion-nonfree-updates.repo
+Total packages: 28,170
+"""
+
+mock_repolist_crb_disabled = """Loaded plugins: builddep, changelog, config-manager, copr, debug, debuginfo-install
+DNF version: 4.14.0
+cachedir: /var/cache/dnf
+Last metadata expiration check: 1:20:49 ago on Fri 22 Dec 2023 06:05:13 PM UTC.
+Repo-id : appstream
+Repo-name : AlmaLinux 9 - AppStream
+Repo-status : enabled
+Repo-revision : 1703240474
+Repo-updated : Fri 22 Dec 2023 10:21:14 AM UTC
+Repo-pkgs : 5,897
+Repo-available-pkgs: 5,728
+Repo-size : 9.5 G
+Repo-mirrors : https://mirrors.almalinux.org/mirrorlist/9/appstream
+Repo-baseurl : http://mirror.cogentco.com/pub/linux/almalinux/9.3/AppStream/x86_64/os/ (9 more)
+Repo-expire : 86,400 second(s) (last: Fri 22 Dec 2023 06:05:11 PM UTC)
+Repo-filename : /etc/yum.repos.d/almalinux-appstream.repo
+
+Repo-id : appstream-debuginfo
+Repo-name : AlmaLinux 9 - AppStream - Debug
+Repo-status : disabled
+Repo-mirrors : https://mirrors.almalinux.org/mirrorlist/9/appstream-debug
+Repo-expire : 86,400 second(s) (last: unknown)
+Repo-filename : /etc/yum.repos.d/almalinux-appstream.repo
+
+Repo-id : appstream-source
+Repo-name : AlmaLinux 9 - AppStream - Source
+Repo-status : disabled
+Repo-mirrors : https://mirrors.almalinux.org/mirrorlist/9/appstream-source
+Repo-expire : 86,400 second(s) (last: unknown)
+Repo-filename : /etc/yum.repos.d/almalinux-appstream.repo
+
+Repo-id : baseos
+Repo-name : AlmaLinux 9 - BaseOS
+Repo-status : enabled
+Repo-revision : 1703240561
+Repo-updated : Fri 22 Dec 2023 10:22:41 AM UTC
+Repo-pkgs : 1,244
+Repo-available-pkgs: 1,244
+Repo-size : 1.3 G
+Repo-mirrors : https://mirrors.almalinux.org/mirrorlist/9/baseos
+Repo-baseurl : http://mirror.cogentco.com/pub/linux/almalinux/9.3/BaseOS/x86_64/os/ (9 more)
+Repo-expire : 86,400 second(s) (last: Fri 22 Dec 2023 06:05:11 PM UTC)
+Repo-filename : /etc/yum.repos.d/almalinux-baseos.repo
+
+Repo-id : baseos-debuginfo
+Repo-name : AlmaLinux 9 - BaseOS - Debug
+Repo-status : disabled
+Repo-mirrors : https://mirrors.almalinux.org/mirrorlist/9/baseos-debug
+Repo-expire : 86,400 second(s) (last: unknown)
+Repo-filename : /etc/yum.repos.d/almalinux-baseos.repo
+
+Repo-id : baseos-source
+Repo-name : AlmaLinux 9 - BaseOS - Source
+Repo-status : disabled
+Repo-mirrors : https://mirrors.almalinux.org/mirrorlist/9/baseos-source
+Repo-expire : 86,400 second(s) (last: unknown)
+Repo-filename : /etc/yum.repos.d/almalinux-baseos.repo
+
+Repo-id : copr:copr.fedorainfracloud.org:uriesk:dracut-crypt-ssh
+Repo-name : Copr repo for dracut-crypt-ssh owned by uriesk
+Repo-status : enabled
+Repo-revision : 1698291016
+Repo-updated : Thu 26 Oct 2023 03:30:16 AM UTC
+Repo-pkgs : 4
+Repo-available-pkgs: 4
+Repo-size : 102 k
+Repo-baseurl : https://download.copr.fedorainfracloud.org/results/uriesk/dracut-crypt-ssh/epel-9-x86_64/
+Repo-expire : 172,800 second(s) (last: Fri 22 Dec 2023 06:05:10 PM UTC)
+Repo-filename : /etc/yum.repos.d/_copr:copr.fedorainfracloud.org:uriesk:dracut-crypt-ssh.repo
+
+Repo-id : crb
+Repo-name : AlmaLinux 9 - CRB
+Repo-status : disabled
+Repo-revision : 1703240590
+Repo-updated : Fri 22 Dec 2023 10:23:10 AM UTC
+Repo-pkgs : 1,730
+Repo-available-pkgs: 1,727
+Repo-size : 13 G
+Repo-mirrors : https://mirrors.almalinux.org/mirrorlist/9/crb
+Repo-baseurl : http://mirror.cogentco.com/pub/linux/almalinux/9.3/CRB/x86_64/os/ (9 more)
+Repo-expire : 86,400 second(s) (last: Fri 22 Dec 2023 06:05:11 PM UTC)
+Repo-filename : /etc/yum.repos.d/almalinux-crb.repo
+
+Repo-id : rpmfusion-nonfree-updates
+Repo-name : RPM Fusion for EL 9 - Nonfree - Updates
+Repo-status : enabled
+Repo-revision : 1703248251
+Repo-tags : binary-x86_64
+Repo-updated : Fri 22 Dec 2023 12:30:53 PM UTC
+Repo-pkgs : 65
+Repo-available-pkgs: 65
+Repo-size : 944 M
+Repo-metalink : http://mirrors.rpmfusion.org/metalink?repo=nonfree-el-updates-released-9&arch=x86_64
+ Updated : Fri 22 Dec 2023 06:05:13 PM UTC
+Repo-baseurl : http://uvermont.mm.fcix.net/rpmfusion/nonfree/el/updates/9/x86_64/ (33 more)
+Repo-expire : 172,800 second(s) (last: Fri 22 Dec 2023 06:05:13 PM UTC)
+Repo-filename : /etc/yum.repos.d/rpmfusion-nonfree-updates.repo
+Total packages: 28,170
+"""
+
+mock_repolist_no_status = """Repo-id : appstream-debuginfo
+Repo-name : AlmaLinux 9 - AppStream - Debug
+Repo-mirrors : https://mirrors.almalinux.org/mirrorlist/9/appstream-debug
+Repo-expire : 86,400 second(s) (last: unknown)
+Repo-filename : /etc/yum.repos.d/almalinux-appstream.repo
+
+Repo-id : appstream-source
+Repo-name : AlmaLinux 9 - AppStream - Source
+Repo-status : disabled
+Repo-mirrors : https://mirrors.almalinux.org/mirrorlist/9/appstream-source
+Repo-expire : 86,400 second(s) (last: unknown)
+Repo-filename : /etc/yum.repos.d/almalinux-appstream.repo
+"""
+
+mock_repolist_status_before_id = """
+Repo-id : appstream-debuginfo
+Repo-status : disabled
+Repo-status : disabled
+"""
+
+expected_repo_states_crb_enabled = {'disabled': ['appstream-debuginfo',
+ 'appstream-source',
+ 'baseos-debuginfo',
+ 'baseos-source'],
+ 'enabled': ['appstream',
+ 'baseos',
+ 'copr:copr.fedorainfracloud.org:uriesk:dracut-crypt-ssh',
+ 'crb',
+ 'rpmfusion-nonfree-updates']}
+
+expected_repo_states_crb_disabled = {'disabled': ['appstream-debuginfo',
+ 'appstream-source',
+ 'baseos-debuginfo',
+ 'baseos-source',
+ 'crb'],
+ 'enabled': ['appstream',
+ 'baseos',
+ 'copr:copr.fedorainfracloud.org:uriesk:dracut-crypt-ssh',
+ 'rpmfusion-nonfree-updates']}
+
+call_get_repo_states = call(['/usr/bin/dnf', 'repolist', '--all', '--verbose'], check_rc=True)
+call_disable_crb = call(['/usr/bin/dnf', 'config-manager', '--set-disabled', 'crb'], check_rc=True)
+call_enable_crb = call(['/usr/bin/dnf', 'config-manager', '--set-enabled', 'crb'], check_rc=True)
+
+
+class TestDNFConfigManager(ModuleTestCase):
+ def setUp(self):
+ super(TestDNFConfigManager, self).setUp()
+ self.mock_run_command = (patch('ansible.module_utils.basic.AnsibleModule.run_command'))
+ self.run_command = self.mock_run_command.start()
+ self.mock_path_exists = (patch('os.path.exists'))
+ self.path_exists = self.mock_path_exists.start()
+ self.path_exists.return_value = True
+ self.module = dnf_config_manager_module
+
+ def tearDown(self):
+ super(TestDNFConfigManager, self).tearDown()
+ self.mock_run_command.stop()
+ self.mock_path_exists.stop()
+
+ def set_command_mock(self, execute_return=(0, '', ''), execute_side_effect=None):
+ self.run_command.reset_mock()
+ self.run_command.return_value = execute_return
+ self.run_command.side_effect = execute_side_effect
+
+ def execute_module(self, failed=False, changed=False):
+ if failed:
+ result = self.failed()
+ self.assertTrue(result['failed'])
+ else:
+ result = self.changed(changed)
+ self.assertEqual(result['changed'], changed)
+
+ return result
+
+ def failed(self):
+ with self.assertRaises(AnsibleFailJson) as exc:
+ self.module.main()
+
+ result = exc.exception.args[0]
+ self.assertTrue(result['failed'])
+ return result
+
+ def changed(self, changed=False):
+ with self.assertRaises(AnsibleExitJson) as exc:
+ self.module.main()
+
+ result = exc.exception.args[0]
+ self.assertEqual(result['changed'], changed)
+ return result
+
+ def test_get_repo_states(self):
+ set_module_args({})
+ self.set_command_mock(execute_return=(0, mock_repolist_crb_enabled, ''))
+ result = self.execute_module(changed=False)
+ self.assertEqual(result['repo_states_pre'], expected_repo_states_crb_enabled)
+ self.assertEqual(result['repo_states_post'], expected_repo_states_crb_enabled)
+ self.assertEqual(result['changed_repos'], [])
+ self.run_command.assert_has_calls(calls=[call_get_repo_states, call_get_repo_states], any_order=False)
+
+ def test_enable_disabled_repo(self):
+ set_module_args({
+ 'name': ['crb'],
+ 'state': 'enabled'
+ })
+ side_effects = [(0, mock_repolist_crb_disabled, ''), (0, '', ''), (0, mock_repolist_crb_enabled, '')]
+ self.set_command_mock(execute_side_effect=side_effects)
+ result = self.execute_module(changed=True)
+ self.assertEqual(result['repo_states_pre'], expected_repo_states_crb_disabled)
+ self.assertEqual(result['repo_states_post'], expected_repo_states_crb_enabled)
+ self.assertEqual(result['changed_repos'], ['crb'])
+ expected_calls = [call_get_repo_states, call_enable_crb, call_get_repo_states]
+ self.run_command.assert_has_calls(calls=expected_calls, any_order=False)
+
+ def test_enable_disabled_repo_check_mode(self):
+ set_module_args({
+ 'name': ['crb'],
+ 'state': 'enabled',
+ '_ansible_check_mode': True
+ })
+ side_effects = [(0, mock_repolist_crb_disabled, ''), (0, mock_repolist_crb_disabled, '')]
+ self.set_command_mock(execute_side_effect=side_effects)
+ result = self.execute_module(changed=True)
+ self.assertEqual(result['changed_repos'], ['crb'])
+ self.run_command.assert_has_calls(calls=[call_get_repo_states], any_order=False)
+
+ def test_disable_enabled_repo(self):
+ set_module_args({
+ 'name': ['crb'],
+ 'state': 'disabled'
+ })
+ side_effects = [(0, mock_repolist_crb_enabled, ''), (0, '', ''), (0, mock_repolist_crb_disabled, '')]
+ self.set_command_mock(execute_side_effect=side_effects)
+ result = self.execute_module(changed=True)
+ self.assertEqual(result['repo_states_pre'], expected_repo_states_crb_enabled)
+ self.assertEqual(result['repo_states_post'], expected_repo_states_crb_disabled)
+ self.assertEqual(result['changed_repos'], ['crb'])
+ expected_calls = [call_get_repo_states, call_disable_crb, call_get_repo_states]
+ self.run_command.assert_has_calls(calls=expected_calls, any_order=False)
+
+ def test_crb_already_enabled(self):
+ set_module_args({
+ 'name': ['crb'],
+ 'state': 'enabled'
+ })
+ side_effects = [(0, mock_repolist_crb_enabled, ''), (0, mock_repolist_crb_enabled, '')]
+ self.set_command_mock(execute_side_effect=side_effects)
+ result = self.execute_module(changed=False)
+ self.assertEqual(result['repo_states_pre'], expected_repo_states_crb_enabled)
+ self.assertEqual(result['repo_states_post'], expected_repo_states_crb_enabled)
+ self.assertEqual(result['changed_repos'], [])
+ self.run_command.assert_has_calls(calls=[call_get_repo_states, call_get_repo_states], any_order=False)
+
+ def test_get_repo_states_fail_no_status(self):
+ set_module_args({})
+ self.set_command_mock(execute_return=(0, mock_repolist_no_status, ''))
+ result = self.execute_module(failed=True)
+ self.assertEqual(result['msg'], 'dnf repolist parse failure: parsed another repo id before next status')
+ self.run_command.assert_has_calls(calls=[call_get_repo_states], any_order=False)
+
+ def test_get_repo_states_fail_status_before_id(self):
+ set_module_args({})
+ self.set_command_mock(execute_return=(0, mock_repolist_status_before_id, ''))
+ result = self.execute_module(failed=True)
+ self.assertEqual(result['msg'], 'dnf repolist parse failure: parsed status before repo id')
+ self.run_command.assert_has_calls(calls=[call_get_repo_states], any_order=False)
+
+ def test_failed__unknown_repo_id(self):
+ set_module_args({
+ 'name': ['fake']
+ })
+ self.set_command_mock(execute_return=(0, mock_repolist_crb_disabled, ''))
+ result = self.execute_module(failed=True)
+ self.assertEqual(result['msg'], "did not find repo with ID 'fake' in dnf repolist --all --verbose")
+ self.run_command.assert_has_calls(calls=[call_get_repo_states], any_order=False)
+
+ def test_failed_state_change_ineffective(self):
+ set_module_args({
+ 'name': ['crb'],
+ 'state': 'enabled'
+ })
+ side_effects = [(0, mock_repolist_crb_disabled, ''), (0, '', ''), (0, mock_repolist_crb_disabled, '')]
+ self.set_command_mock(execute_side_effect=side_effects)
+ result = self.execute_module(failed=True)
+ self.assertEqual(result['msg'], "dnf config-manager failed to make 'crb' enabled")
+ expected_calls = [call_get_repo_states, call_enable_crb, call_get_repo_states]
+ self.run_command.assert_has_calls(calls=expected_calls, any_order=False)
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_dnsimple.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_dnsimple.py
index 95a78818d..d5578252d 100644
--- a/ansible_collections/community/general/tests/unit/plugins/modules/test_dnsimple.py
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_dnsimple.py
@@ -45,7 +45,7 @@ class TestDNSimple(ModuleTestCase):
def test_account_token(self, mock_whoami):
mock_whoami.return_value.data.account = 42
ds = self.module.DNSimpleV2('fake', 'fake', True, self.module)
- self.assertEquals(ds.account, 42)
+ self.assertEqual(ds.account, 42)
@patch('dnsimple.service.Accounts.list_accounts')
@patch('dnsimple.service.Identity.whoami')
@@ -61,4 +61,4 @@ class TestDNSimple(ModuleTestCase):
mock_accounts.return_value.data = [42]
mock_whoami.return_value.data.account = None
ds = self.module.DNSimpleV2('fake', 'fake', True, self.module)
- self.assertEquals(ds.account, 42)
+ self.assertEqual(ds.account, 42)
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_dnsimple_info.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_dnsimple_info.py
index 5806ec772..08c5296c8 100644
--- a/ansible_collections/community/general/tests/unit/plugins/modules/test_dnsimple_info.py
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_dnsimple_info.py
@@ -89,7 +89,7 @@ class TestDNSimple_Info(ModuleTestCase):
result = exc_info.exception.args[0]
# nothing should change
self.assertFalse(result['changed'])
- # we should return at least one item with mathing domain
+ # we should return at least one item with matching domain
assert result['dnsimple_records_info'][0]['name'] == name
@with_httmock(records_resp)
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_facter_facts.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_facter_facts.py
new file mode 100644
index 000000000..227d8cd15
--- /dev/null
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_facter_facts.py
@@ -0,0 +1,14 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) Alexei Znamensky (russoz@gmail.com)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+
+from ansible_collections.community.general.plugins.modules import facter_facts
+from .helper import Helper
+
+
+Helper.from_module(facter_facts, __name__)
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_facter_facts.yaml b/ansible_collections/community/general/tests/unit/plugins/modules/test_facter_facts.yaml
new file mode 100644
index 000000000..c287fdcfd
--- /dev/null
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_facter_facts.yaml
@@ -0,0 +1,40 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) Alexei Znamensky (russoz@gmail.com)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+---
+- id: simple run
+ output:
+ ansible_facts:
+ facter:
+ a: 1
+ b: 2
+ c: 3
+ run_command_calls:
+ - command: [/testbin/facter, --json]
+ environ: &env-def {check_rc: true}
+ rc: 0
+ out: >
+ { "a": 1, "b": 2, "c": 3 }
+ err: ""
+- id: with args
+ input:
+ arguments:
+ - -p
+ - system_uptime
+ - timezone
+ - is_virtual
+ output:
+ ansible_facts:
+ facter:
+ a: 1
+ b: 2
+ c: 3
+ run_command_calls:
+ - command: [/testbin/facter, --json, -p, system_uptime, timezone, is_virtual]
+ environ: *env-def
+ rc: 0
+ out: >
+ { "a": 1, "b": 2, "c": 3 }
+ err: ""
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_gconftool2.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_gconftool2.py
index f01f15ef8..9608016e5 100644
--- a/ansible_collections/community/general/tests/unit/plugins/modules/test_gconftool2.py
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_gconftool2.py
@@ -6,111 +6,9 @@
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
-import json
from ansible_collections.community.general.plugins.modules import gconftool2
+from .helper import Helper
-import pytest
-TESTED_MODULE = gconftool2.__name__
-
-
-@pytest.fixture
-def patch_gconftool2(mocker):
- """
- Function used for mocking some parts of redhat_subscription module
- """
- mocker.patch('ansible_collections.community.general.plugins.module_utils.mh.module_helper.AnsibleModule.get_bin_path',
- return_value='/testbin/gconftool-2')
-
-
-TEST_CASES = [
- [
- {'state': 'get', 'key': '/desktop/gnome/background/picture_filename'},
- {
- 'id': 'test_simple_element_get',
- 'run_command.calls': [
- (
- ['/testbin/gconftool-2', '--get', '/desktop/gnome/background/picture_filename'],
- {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': True},
- (0, '100\n', '',),
- ),
- ],
- 'new_value': '100',
- }
- ],
- [
- {'state': 'get', 'key': '/desktop/gnome/background/picture_filename'},
- {
- 'id': 'test_simple_element_get_not_found',
- 'run_command.calls': [
- (
- ['/testbin/gconftool-2', '--get', '/desktop/gnome/background/picture_filename'],
- {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': True},
- (0, '', "No value set for `/desktop/gnome/background/picture_filename'\n",),
- ),
- ],
- 'new_value': None,
- }
- ],
- [
- {'state': 'present', 'key': '/desktop/gnome/background/picture_filename', 'value': '200', 'value_type': 'int'},
- {
- 'id': 'test_simple_element_set',
- 'run_command.calls': [
- (
- ['/testbin/gconftool-2', '--get', '/desktop/gnome/background/picture_filename'],
- {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': True},
- (0, '100\n', '',),
- ),
- (
- ['/testbin/gconftool-2', '--type', 'int', '--set', '/desktop/gnome/background/picture_filename', '200'],
- {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': True},
- (0, '200\n', '',),
- ),
- ],
- 'new_value': '200',
- }
- ],
-]
-TEST_CASES_IDS = [item[1]['id'] for item in TEST_CASES]
-
-
-@pytest.mark.parametrize('patch_ansible_module, testcase',
- TEST_CASES,
- ids=TEST_CASES_IDS,
- indirect=['patch_ansible_module'])
-@pytest.mark.usefixtures('patch_ansible_module')
-def test_gconftool2(mocker, capfd, patch_gconftool2, testcase):
- """
- Run unit tests for test cases listen in TEST_CASES
- """
-
- # Mock function used for running commands first
- call_results = [item[2] for item in testcase['run_command.calls']]
- mock_run_command = mocker.patch(
- 'ansible_collections.community.general.plugins.module_utils.mh.module_helper.AnsibleModule.run_command',
- side_effect=call_results)
-
- # Try to run test case
- with pytest.raises(SystemExit):
- gconftool2.main()
-
- out, err = capfd.readouterr()
- results = json.loads(out)
- print("testcase =\n%s" % testcase)
- print("results =\n%s" % results)
-
- for conditional_test_result in ('value',):
- if conditional_test_result in testcase:
- assert conditional_test_result in results, "'{0}' not found in {1}".format(conditional_test_result, results)
- assert results[conditional_test_result] == testcase[conditional_test_result], \
- "'{0}': '{1}' != '{2}'".format(conditional_test_result, results[conditional_test_result], testcase[conditional_test_result])
-
- assert mock_run_command.call_count == len(testcase['run_command.calls'])
- if mock_run_command.call_count:
- call_args_list = [(item[0][0], item[1]) for item in mock_run_command.call_args_list]
- expected_call_args_list = [(item[0], item[1]) for item in testcase['run_command.calls']]
- print("call args list =\n%s" % call_args_list)
- print("expected args list =\n%s" % expected_call_args_list)
- assert call_args_list == expected_call_args_list
+Helper.from_module(gconftool2, __name__)
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_gconftool2.yaml b/ansible_collections/community/general/tests/unit/plugins/modules/test_gconftool2.yaml
new file mode 100644
index 000000000..5114dc45f
--- /dev/null
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_gconftool2.yaml
@@ -0,0 +1,117 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) Alexei Znamensky (russoz@gmail.com)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+---
+- id: test_simple_element_set
+ input:
+ state: present
+ key: /desktop/gnome/background/picture_filename
+ value: 200
+ value_type: int
+ output:
+ new_value: '200'
+ changed: true
+ run_command_calls:
+ - command: [/testbin/gconftool-2, --get, /desktop/gnome/background/picture_filename]
+ environ: &env-def {environ_update: {LANGUAGE: C, LC_ALL: C}, check_rc: true}
+ rc: 0
+ out: "100\n"
+ err: ""
+ - command: [/testbin/gconftool-2, --type, int, --set, /desktop/gnome/background/picture_filename, "200"]
+ environ: *env-def
+ rc: 0
+ out: ""
+ err: ""
+ - command: [/testbin/gconftool-2, --get, /desktop/gnome/background/picture_filename]
+ environ: *env-def
+ rc: 0
+ out: "200\n"
+ err: ""
+- id: test_simple_element_set_idempotency_int
+ input:
+ state: present
+ key: /desktop/gnome/background/picture_filename
+ value: 200
+ value_type: int
+ output:
+ new_value: '200'
+ changed: false
+ run_command_calls:
+ - command: [/testbin/gconftool-2, --get, /desktop/gnome/background/picture_filename]
+ environ: *env-def
+ rc: 0
+ out: "200\n"
+ err: ""
+ - command: [/testbin/gconftool-2, --type, int, --set, /desktop/gnome/background/picture_filename, "200"]
+ environ: *env-def
+ rc: 0
+ out: ""
+ err: ""
+ - command: [/testbin/gconftool-2, --get, /desktop/gnome/background/picture_filename]
+ environ: *env-def
+ rc: 0
+ out: "200\n"
+ err: ""
+- id: test_simple_element_set_idempotency_bool
+ input:
+ state: present
+ key: /apps/gnome_settings_daemon/screensaver/start_screensaver
+ value: false
+ value_type: bool
+ output:
+ new_value: 'false'
+ changed: false
+ run_command_calls:
+ - command: [/testbin/gconftool-2, --get, /apps/gnome_settings_daemon/screensaver/start_screensaver]
+ environ: *env-def
+ rc: 0
+ out: "false\n"
+ err: ""
+ - command: [/testbin/gconftool-2, --type, bool, --set, /apps/gnome_settings_daemon/screensaver/start_screensaver, "False"]
+ environ: *env-def
+ rc: 0
+ out: ""
+ err: ""
+ - command: [/testbin/gconftool-2, --get, /apps/gnome_settings_daemon/screensaver/start_screensaver]
+ environ: *env-def
+ rc: 0
+ out: "false\n"
+ err: ""
+- id: test_simple_element_unset
+ input:
+ state: absent
+ key: /desktop/gnome/background/picture_filename
+ output:
+ new_value: null
+ changed: true
+ run_command_calls:
+ - command: [/testbin/gconftool-2, --get, /desktop/gnome/background/picture_filename]
+ environ: *env-def
+ rc: 0
+ out: "200\n"
+ err: ""
+ - command: [/testbin/gconftool-2, --unset, /desktop/gnome/background/picture_filename]
+ environ: *env-def
+ rc: 0
+ out: ""
+ err: ""
+- id: test_simple_element_unset_idempotency
+ input:
+ state: absent
+ key: /apps/gnome_settings_daemon/screensaver/start_screensaver
+ output:
+ new_value: null
+ changed: false
+ run_command_calls:
+ - command: [/testbin/gconftool-2, --get, /apps/gnome_settings_daemon/screensaver/start_screensaver]
+ environ: *env-def
+ rc: 0
+ out: ""
+ err: ""
+ - command: [/testbin/gconftool-2, --unset, /apps/gnome_settings_daemon/screensaver/start_screensaver]
+ environ: *env-def
+ rc: 0
+ out: ""
+ err: ""
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_gconftool2_info.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_gconftool2_info.py
index 352af6bb0..54676a12d 100644
--- a/ansible_collections/community/general/tests/unit/plugins/modules/test_gconftool2_info.py
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_gconftool2_info.py
@@ -6,98 +6,9 @@
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
-import json
from ansible_collections.community.general.plugins.modules import gconftool2_info
+from .helper import Helper
-import pytest
-TESTED_MODULE = gconftool2_info.__name__
-
-
-@pytest.fixture
-def patch_gconftool2_info(mocker):
- """
- Function used for mocking some parts of redhat_subscription module
- """
- mocker.patch('ansible_collections.community.general.plugins.module_utils.mh.module_helper.AnsibleModule.get_bin_path',
- return_value='/testbin/gconftool-2')
-
-
-TEST_CASES = [
- [
- {'key': '/desktop/gnome/background/picture_filename'},
- {
- 'id': 'test_simple_element_get',
- 'run_command.calls': [
- (
- # Calling of following command will be asserted
- ['/testbin/gconftool-2', '--get', '/desktop/gnome/background/picture_filename'],
- # Was return code checked?
- {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': True},
- # Mock of returned code, stdout and stderr
- (0, '100\n', '',),
- ),
- ],
- 'value': '100',
- }
- ],
- [
- {'key': '/desktop/gnome/background/picture_filename'},
- {
- 'id': 'test_simple_element_get_not_found',
- 'run_command.calls': [
- (
- # Calling of following command will be asserted
- ['/testbin/gconftool-2', '--get', '/desktop/gnome/background/picture_filename'],
- # Was return code checked?
- {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': True},
- # Mock of returned code, stdout and stderr
- (0, '', "No value set for `/desktop/gnome/background/picture_filename'\n",),
- ),
- ],
- 'value': None,
- }
- ],
-]
-TEST_CASES_IDS = [item[1]['id'] for item in TEST_CASES]
-
-
-@pytest.mark.parametrize('patch_ansible_module, testcase',
- TEST_CASES,
- ids=TEST_CASES_IDS,
- indirect=['patch_ansible_module'])
-@pytest.mark.usefixtures('patch_ansible_module')
-def test_gconftool2_info(mocker, capfd, patch_gconftool2_info, testcase):
- """
- Run unit tests for test cases listen in TEST_CASES
- """
-
- # Mock function used for running commands first
- call_results = [item[2] for item in testcase['run_command.calls']]
- mock_run_command = mocker.patch(
- 'ansible_collections.community.general.plugins.module_utils.mh.module_helper.AnsibleModule.run_command',
- side_effect=call_results)
-
- # Try to run test case
- with pytest.raises(SystemExit):
- gconftool2_info.main()
-
- out, err = capfd.readouterr()
- results = json.loads(out)
- print("testcase =\n%s" % testcase)
- print("results =\n%s" % results)
-
- for conditional_test_result in ('value',):
- if conditional_test_result in testcase:
- assert conditional_test_result in results, "'{0}' not found in {1}".format(conditional_test_result, results)
- assert results[conditional_test_result] == testcase[conditional_test_result], \
- "'{0}': '{1}' != '{2}'".format(conditional_test_result, results[conditional_test_result], testcase[conditional_test_result])
-
- assert mock_run_command.call_count == len(testcase['run_command.calls'])
- if mock_run_command.call_count:
- call_args_list = [(item[0][0], item[1]) for item in mock_run_command.call_args_list]
- expected_call_args_list = [(item[0], item[1]) for item in testcase['run_command.calls']]
- print("call args list =\n%s" % call_args_list)
- print("expected args list =\n%s" % expected_call_args_list)
- assert call_args_list == expected_call_args_list
+Helper.from_module(gconftool2_info, __name__)
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_gconftool2_info.yaml b/ansible_collections/community/general/tests/unit/plugins/modules/test_gconftool2_info.yaml
new file mode 100644
index 000000000..eb8bef750
--- /dev/null
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_gconftool2_info.yaml
@@ -0,0 +1,28 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) Alexei Znamensky (russoz@gmail.com)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+---
+- id: test_simple_element_get
+ input:
+ key: /desktop/gnome/background/picture_filename
+ output:
+ value: '100'
+ run_command_calls:
+ - command: [/testbin/gconftool-2, --get, /desktop/gnome/background/picture_filename]
+ environ: &env-def {environ_update: {LANGUAGE: C, LC_ALL: C}, check_rc: true}
+ rc: 0
+ out: "100\n"
+ err: ""
+- id: test_simple_element_get_not_found
+ input:
+ key: /desktop/gnome/background/picture_filename
+ output:
+ value: null
+ run_command_calls:
+ - command: [/testbin/gconftool-2, --get, /desktop/gnome/background/picture_filename]
+ environ: *env-def
+ rc: 0
+ out: ""
+ err: "No value set for `/desktop/gnome/background/picture_filename'\n"
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_gem.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_gem.py
index 92578e062..10c03e537 100644
--- a/ansible_collections/community/general/tests/unit/plugins/modules/test_gem.py
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_gem.py
@@ -69,7 +69,7 @@ class TestGem(ModuleTestCase):
assert result['msg'] == "install_dir requires user_install=false"
def test_passes_install_dir_to_gem(self):
- # XXX: This test is extremely fragile, and makes assuptions about the module code, and how
+ # XXX: This test is extremely fragile, and makes assumptions about the module code, and how
# functions are run.
# If you start modifying the code of the module, you might need to modify what this
# test mocks. The only thing that matters is the assertion that this 'gem install' is
diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/authentication/conftest.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_gio_mime.py
index bf577a2d0..f2402ac35 100644
--- a/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/authentication/conftest.py
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_gio_mime.py
@@ -1,10 +1,14 @@
# -*- coding: utf-8 -*-
-# Copyright (c) 2022 Brian Scholer (@briantist)
+# Copyright (c) Alexei Znamensky (russoz@gmail.com)
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
-# pylint: disable=wildcard-import,unused-wildcard-import
-from ...module_utils.authentication.conftest import *
+
+from ansible_collections.community.general.plugins.modules import gio_mime
+from .helper import Helper
+
+
+Helper.from_module(gio_mime, __name__)
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_gio_mime.yaml b/ansible_collections/community/general/tests/unit/plugins/modules/test_gio_mime.yaml
new file mode 100644
index 000000000..d9e47a60e
--- /dev/null
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_gio_mime.yaml
@@ -0,0 +1,70 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) Alexei Znamensky (russoz@gmail.com)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+---
+- id: test_set_handler
+ input:
+ handler: google-chrome.desktop
+ mime_type: x-scheme-handler/http
+ output:
+ handler: google-chrome.desktop
+ changed: true
+ run_command_calls:
+ - command: [/testbin/gio, mime, x-scheme-handler/http]
+ environ: &env-def {environ_update: {LANGUAGE: C, LC_ALL: C}, check_rc: true}
+ rc: 0
+ out: ""
+ err: >
+ No default applications for “x-scheme-handler/http”
+ - command: [/testbin/gio, mime, x-scheme-handler/http, google-chrome.desktop]
+ environ: *env-def
+ rc: 0
+ out: "Set google-chrome.desktop as the default for x-scheme-handler/http\n"
+ err: ""
+- id: test_set_handler_check
+ input:
+ handler: google-chrome.desktop
+ mime_type: x-scheme-handler/http
+ output:
+ handler: google-chrome.desktop
+ changed: true
+ flags:
+ skip: test helper does not support check mode yet
+ run_command_calls:
+ - command: [/testbin/gio, mime, x-scheme-handler/http]
+ environ: *env-def
+ rc: 0
+ out: ""
+ err: >
+ No default applications for “x-scheme-handler/http”
+ - command: [/testbin/gio, mime, x-scheme-handler/http, google-chrome.desktop]
+ environ: *env-def
+ rc: 0
+ out: "Set google-chrome.desktop as the default for x-scheme-handler/http\n"
+ err: ""
+- id: test_set_handler_idempot
+ input:
+ handler: google-chrome.desktop
+ mime_type: x-scheme-handler/http
+ output:
+ handler: google-chrome.desktop
+ changed: false
+ run_command_calls:
+ - command: [/testbin/gio, mime, x-scheme-handler/http]
+ environ: *env-def
+ rc: 0
+ out: |
+ Default application for “x-scheme-handler/https”: google-chrome.desktop
+ Registered applications:
+ brave-browser.desktop
+ firefox.desktop
+ google-chrome.desktop
+ firefox_firefox.desktop
+ Recommended applications:
+ brave-browser.desktop
+ firefox.desktop
+ google-chrome.desktop
+ firefox_firefox.desktop
+ err: ""
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_gitlab_group_access_token.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_gitlab_group_access_token.py
new file mode 100644
index 000000000..06af94820
--- /dev/null
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_gitlab_group_access_token.py
@@ -0,0 +1,107 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2023, Zoran Krleza (zoran.krleza@true-north.hr)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import pytest
+import gitlab
+
+from ansible_collections.community.general.plugins.modules.gitlab_group_access_token import GitLabGroupAccessToken
+
+# python-gitlab 3.1+ is needed for python-gitlab access tokens api
+PYTHON_GITLAB_MINIMAL_VERSION = (3, 1)
+
+
+def python_gitlab_version_match_requirement():
+ return tuple(map(int, gitlab.__version__.split('.'))) >= PYTHON_GITLAB_MINIMAL_VERSION
+
+
+def _dummy(x):
+ """Dummy function. Only used as a placeholder for toplevel definitions when the test is going
+ to be skipped anyway"""
+ return x
+
+
+pytestmark = []
+try:
+ from .gitlab import (GitlabModuleTestCase,
+ resp_get_user,
+ resp_get_group,
+ resp_list_group_access_tokens,
+ resp_create_group_access_tokens,
+ resp_revoke_group_access_tokens)
+
+except ImportError:
+ pytestmark.append(pytest.mark.skip("Could not load gitlab module required for testing"))
+ # Need to set these to something so that we don't fail when parsing
+ GitlabModuleTestCase = object
+ resp_list_group_access_tokens = _dummy
+ resp_create_group_access_tokens = _dummy
+ resp_revoke_group_access_tokens = _dummy
+ resp_get_user = _dummy
+ resp_get_group = _dummy
+
+# Unit tests requirements
+try:
+ from httmock import with_httmock # noqa
+except ImportError:
+ pytestmark.append(pytest.mark.skip("Could not load httmock module required for testing"))
+ with_httmock = _dummy
+
+
+class TestGitlabGroupAccessToken(GitlabModuleTestCase):
+ @with_httmock(resp_get_user)
+ def setUp(self):
+ super(TestGitlabGroupAccessToken, self).setUp()
+ if not python_gitlab_version_match_requirement():
+ self.skipTest("python-gitlab %s+ is needed for gitlab_group_access_token" % ",".join(map(str, PYTHON_GITLAB_MINIMAL_VERSION)))
+
+ self.moduleUtil = GitLabGroupAccessToken(module=self.mock_module, gitlab_instance=self.gitlab_instance)
+
+ @with_httmock(resp_get_group)
+ @with_httmock(resp_list_group_access_tokens)
+ def test_find_access_token(self):
+ group = self.gitlab_instance.groups.get(1)
+ self.assertIsNotNone(group)
+
+ rvalue = self.moduleUtil.find_access_token(group, "token1")
+ self.assertEqual(rvalue, False)
+ self.assertIsNotNone(self.moduleUtil.access_token_object)
+
+ @with_httmock(resp_get_group)
+ @with_httmock(resp_list_group_access_tokens)
+ def test_find_access_token_negative(self):
+ groups = self.gitlab_instance.groups.get(1)
+ self.assertIsNotNone(groups)
+
+ rvalue = self.moduleUtil.find_access_token(groups, "nonexisting")
+ self.assertEqual(rvalue, False)
+ self.assertIsNone(self.moduleUtil.access_token_object)
+
+ @with_httmock(resp_get_group)
+ @with_httmock(resp_create_group_access_tokens)
+ def test_create_access_token(self):
+ groups = self.gitlab_instance.groups.get(1)
+ self.assertIsNotNone(groups)
+
+ rvalue = self.moduleUtil.create_access_token(groups, {'name': "tokenXYZ", 'scopes': ["api"], 'access_level': 20, 'expires_at': "2024-12-31"})
+ self.assertEqual(rvalue, True)
+ self.assertIsNotNone(self.moduleUtil.access_token_object)
+
+ @with_httmock(resp_get_group)
+ @with_httmock(resp_list_group_access_tokens)
+ @with_httmock(resp_revoke_group_access_tokens)
+ def test_revoke_access_token(self):
+ groups = self.gitlab_instance.groups.get(1)
+ self.assertIsNotNone(groups)
+
+ rvalue = self.moduleUtil.find_access_token(groups, "token1")
+ self.assertEqual(rvalue, False)
+ self.assertIsNotNone(self.moduleUtil.access_token_object)
+
+ rvalue = self.moduleUtil.revoke_access_token()
+ self.assertEqual(rvalue, True)
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_gitlab_project_access_token.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_gitlab_project_access_token.py
new file mode 100644
index 000000000..ebc324b88
--- /dev/null
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_gitlab_project_access_token.py
@@ -0,0 +1,107 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2023, Zoran Krleza (zoran.krleza@true-north.hr)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import pytest
+import gitlab
+
+from ansible_collections.community.general.plugins.modules.gitlab_project_access_token import GitLabProjectAccessToken
+
+# python-gitlab 3.1+ is needed for python-gitlab access tokens api
+PYTHON_GITLAB_MINIMAL_VERSION = (3, 1)
+
+
+def python_gitlab_version_match_requirement():
+ return tuple(map(int, gitlab.__version__.split('.'))) >= PYTHON_GITLAB_MINIMAL_VERSION
+
+
+def _dummy(x):
+ """Dummy function. Only used as a placeholder for toplevel definitions when the test is going
+ to be skipped anyway"""
+ return x
+
+
+pytestmark = []
+try:
+ from .gitlab import (GitlabModuleTestCase,
+ resp_get_user,
+ resp_get_project,
+ resp_list_project_access_tokens,
+ resp_create_project_access_tokens,
+ resp_revoke_project_access_tokens)
+
+except ImportError:
+ pytestmark.append(pytest.mark.skip("Could not load gitlab module required for testing"))
+ # Need to set these to something so that we don't fail when parsing
+ GitlabModuleTestCase = object
+ resp_list_project_access_tokens = _dummy
+ resp_create_project_access_tokens = _dummy
+ resp_revoke_project_access_tokens = _dummy
+ resp_get_user = _dummy
+ resp_get_project = _dummy
+
+# Unit tests requirements
+try:
+ from httmock import with_httmock # noqa
+except ImportError:
+ pytestmark.append(pytest.mark.skip("Could not load httmock module required for testing"))
+ with_httmock = _dummy
+
+
+class TestGitlabProjectAccessToken(GitlabModuleTestCase):
+ @with_httmock(resp_get_user)
+ def setUp(self):
+ super(TestGitlabProjectAccessToken, self).setUp()
+ if not python_gitlab_version_match_requirement():
+ self.skipTest("python-gitlab %s+ is needed for gitlab_project_access_token" % ",".join(map(str, PYTHON_GITLAB_MINIMAL_VERSION)))
+
+ self.moduleUtil = GitLabProjectAccessToken(module=self.mock_module, gitlab_instance=self.gitlab_instance)
+
+ @with_httmock(resp_get_project)
+ @with_httmock(resp_list_project_access_tokens)
+ def test_find_access_token(self):
+ project = self.gitlab_instance.projects.get(1)
+ self.assertIsNotNone(project)
+
+ rvalue = self.moduleUtil.find_access_token(project, "token1")
+ self.assertEqual(rvalue, False)
+ self.assertIsNotNone(self.moduleUtil.access_token_object)
+
+ @with_httmock(resp_get_project)
+ @with_httmock(resp_list_project_access_tokens)
+ def test_find_access_token_negative(self):
+ project = self.gitlab_instance.projects.get(1)
+ self.assertIsNotNone(project)
+
+ rvalue = self.moduleUtil.find_access_token(project, "nonexisting")
+ self.assertEqual(rvalue, False)
+ self.assertIsNone(self.moduleUtil.access_token_object)
+
+ @with_httmock(resp_get_project)
+ @with_httmock(resp_create_project_access_tokens)
+ def test_create_access_token(self):
+ project = self.gitlab_instance.projects.get(1)
+ self.assertIsNotNone(project)
+
+ rvalue = self.moduleUtil.create_access_token(project, {'name': "tokenXYZ", 'scopes': ["api"], 'access_level': 20, 'expires_at': "2024-12-31"})
+ self.assertEqual(rvalue, True)
+ self.assertIsNotNone(self.moduleUtil.access_token_object)
+
+ @with_httmock(resp_get_project)
+ @with_httmock(resp_list_project_access_tokens)
+ @with_httmock(resp_revoke_project_access_tokens)
+ def test_revoke_access_token(self):
+ project = self.gitlab_instance.projects.get(1)
+ self.assertIsNotNone(project)
+
+ rvalue = self.moduleUtil.find_access_token(project, "token1")
+ self.assertEqual(rvalue, False)
+ self.assertIsNotNone(self.moduleUtil.access_token_object)
+
+ rvalue = self.moduleUtil.revoke_access_token()
+ self.assertEqual(rvalue, True)
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_hana_query.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_hana_query.py
deleted file mode 100644
index db06e4cef..000000000
--- a/ansible_collections/community/general/tests/unit/plugins/modules/test_hana_query.py
+++ /dev/null
@@ -1,103 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright (c) 2021, Rainer Leber (@rainerleber) <rainerleber@gmail.com>
-# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
-# SPDX-License-Identifier: GPL-3.0-or-later
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-from ansible_collections.community.general.plugins.modules import hana_query
-from ansible_collections.community.general.tests.unit.plugins.modules.utils import (
- AnsibleExitJson,
- AnsibleFailJson,
- ModuleTestCase,
- set_module_args,
-)
-from ansible_collections.community.general.tests.unit.compat.mock import patch
-from ansible.module_utils import basic
-
-
-def get_bin_path(*args, **kwargs):
- """Function to return path of hdbsql"""
- return "/usr/sap/HDB/HDB01/exe/hdbsql"
-
-
-class Testhana_query(ModuleTestCase):
- """Main class for testing hana_query module."""
-
- def setUp(self):
- """Setup."""
- super(Testhana_query, self).setUp()
- self.module = hana_query
- self.mock_get_bin_path = patch.object(basic.AnsibleModule, 'get_bin_path', get_bin_path)
- self.mock_get_bin_path.start()
- self.addCleanup(self.mock_get_bin_path.stop) # ensure that the patching is 'undone'
-
- def tearDown(self):
- """Teardown."""
- super(Testhana_query, self).tearDown()
-
- def test_without_required_parameters(self):
- """Failure must occurs when all parameters are missing."""
- with self.assertRaises(AnsibleFailJson):
- set_module_args({})
- self.module.main()
-
- def test_hana_query(self):
- """Check that result is processed."""
- set_module_args({
- 'sid': "HDB",
- 'instance': "01",
- 'encrypted': False,
- 'host': "localhost",
- 'user': "SYSTEM",
- 'password': "1234Qwer",
- 'database': "HDB",
- 'query': "SELECT * FROM users;"
- })
- with patch.object(basic.AnsibleModule, 'run_command') as run_command:
- run_command.return_value = 0, 'username,name\n testuser,test user \n myuser, my user \n', ''
- with self.assertRaises(AnsibleExitJson) as result:
- hana_query.main()
- self.assertEqual(result.exception.args[0]['query_result'], [[
- {'username': 'testuser', 'name': 'test user'},
- {'username': 'myuser', 'name': 'my user'},
- ]])
- self.assertEqual(run_command.call_count, 1)
-
- def test_hana_userstore_query(self):
- """Check that result is processed with userstore."""
- set_module_args({
- 'sid': "HDB",
- 'instance': "01",
- 'encrypted': False,
- 'host': "localhost",
- 'user': "SYSTEM",
- 'userstore': True,
- 'database': "HDB",
- 'query': "SELECT * FROM users;"
- })
- with patch.object(basic.AnsibleModule, 'run_command') as run_command:
- run_command.return_value = 0, 'username,name\n testuser,test user \n myuser, my user \n', ''
- with self.assertRaises(AnsibleExitJson) as result:
- hana_query.main()
- self.assertEqual(result.exception.args[0]['query_result'], [[
- {'username': 'testuser', 'name': 'test user'},
- {'username': 'myuser', 'name': 'my user'},
- ]])
- self.assertEqual(run_command.call_count, 1)
-
- def test_hana_failed_no_passwd(self):
- """Check that result is failed with no password."""
- with self.assertRaises(AnsibleFailJson):
- set_module_args({
- 'sid': "HDB",
- 'instance': "01",
- 'encrypted': False,
- 'host': "localhost",
- 'user': "SYSTEM",
- 'database': "HDB",
- 'query': "SELECT * FROM users;"
- })
- self.module.main()
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_ini_file.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_ini_file.py
new file mode 100644
index 000000000..a65a9c326
--- /dev/null
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_ini_file.py
@@ -0,0 +1,51 @@
+# Copyright (c) 2023 Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or
+# https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+from ansible_collections.community.general.plugins.modules import ini_file
+
+
+def do_test(option, ignore_spaces, newline, before, expected_after,
+ expected_changed, expected_msg):
+ section_lines = [before]
+ changed_lines = [0]
+ changed, msg = ini_file.update_section_line(
+ option, None, section_lines, 0, changed_lines, ignore_spaces,
+ newline, None)
+ assert section_lines[0] == expected_after
+ assert changed == expected_changed
+ assert changed_lines[0] == 1
+ assert msg == expected_msg
+
+
+def test_ignore_spaces_comment():
+ oldline = ';foobar=baz'
+ newline = 'foobar = baz'
+ do_test('foobar', True, newline, oldline, newline, True, 'option changed')
+
+
+def test_ignore_spaces_changed():
+ oldline = 'foobar=baz'
+ newline = 'foobar = freeble'
+ do_test('foobar', True, newline, oldline, newline, True, 'option changed')
+
+
+def test_ignore_spaces_unchanged():
+ oldline = 'foobar=baz'
+ newline = 'foobar = baz'
+ do_test('foobar', True, newline, oldline, oldline, False, None)
+
+
+def test_no_ignore_spaces_changed():
+ oldline = 'foobar=baz'
+ newline = 'foobar = baz'
+ do_test('foobar', False, newline, oldline, newline, True, 'option changed')
+
+
+def test_no_ignore_spaces_unchanged():
+ newline = 'foobar=baz'
+ do_test('foobar', False, newline, newline, newline, False, None)
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_ipa_otptoken.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_ipa_otptoken.py
index c06e19c3b..23911e5a5 100644
--- a/ansible_collections/community/general/tests/unit/plugins/modules/test_ipa_otptoken.py
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_ipa_otptoken.py
@@ -104,7 +104,7 @@ class TestIPAOTPToken(ModuleTestCase):
{
'method': 'otptoken_add',
'name': 'NewToken1',
- 'item': {'ipatokendisabled': 'FALSE',
+ 'item': {'ipatokendisabled': False,
'all': True}
}
)
@@ -130,7 +130,7 @@ class TestIPAOTPToken(ModuleTestCase):
{
'method': 'otptoken_add',
'name': 'NewToken1',
- 'item': {'ipatokendisabled': 'FALSE',
+ 'item': {'ipatokendisabled': False,
'all': True}
}
)
@@ -176,7 +176,7 @@ class TestIPAOTPToken(ModuleTestCase):
'ipatokenotpkey': 'KRSXG5CTMVRXEZLUGE======',
'description': 'Test description',
'ipatokenowner': 'pinky',
- 'ipatokendisabled': 'FALSE',
+ 'ipatokendisabled': False,
'ipatokennotbefore': '20200101010101Z',
'ipatokennotafter': '20900101010101Z',
'ipatokenvendor': 'Acme',
@@ -220,7 +220,7 @@ class TestIPAOTPToken(ModuleTestCase):
'ipatokenotpkey': [{'__base64__': 'VGVzdFNlY3JldDE='}],
'description': ['Test description'],
'ipatokenowner': ['pinky'],
- 'ipatokendisabled': ['FALSE'],
+ 'ipatokendisabled': [False],
'ipatokennotbefore': ['20200101010101Z'],
'ipatokennotafter': ['20900101010101Z'],
'ipatokenvendor': ['Acme'],
@@ -271,7 +271,7 @@ class TestIPAOTPToken(ModuleTestCase):
'ipatokenotpkey': [{'__base64__': 'VGVzdFNlY3JldDE='}],
'description': ['Test description'],
'ipatokenowner': ['pinky'],
- 'ipatokendisabled': ['FALSE'],
+ 'ipatokendisabled': [False],
'ipatokennotbefore': ['20200101010101Z'],
'ipatokennotafter': ['20900101010101Z'],
'ipatokenvendor': ['Acme'],
@@ -296,7 +296,7 @@ class TestIPAOTPToken(ModuleTestCase):
'name': 'NewToken1',
'item': {'description': 'Test description',
'ipatokenowner': 'brain',
- 'ipatokendisabled': 'FALSE',
+ 'ipatokendisabled': False,
'ipatokennotbefore': '20200101010101Z',
'ipatokennotafter': '20900101010101Z',
'ipatokenvendor': 'Acme',
@@ -335,7 +335,7 @@ class TestIPAOTPToken(ModuleTestCase):
'ipatokenotpkey': [{'__base64__': 'VGVzdFNlY3JldDE='}],
'description': ['Test description'],
'ipatokenowner': ['pinky'],
- 'ipatokendisabled': ['FALSE'],
+ 'ipatokendisabled': [False],
'ipatokennotbefore': ['20200101010101Z'],
'ipatokennotafter': ['20900101010101Z'],
'ipatokenvendor': ['Acme'],
@@ -360,7 +360,7 @@ class TestIPAOTPToken(ModuleTestCase):
'name': 'NewToken1',
'item': {'description': 'New Test description',
'ipatokenowner': 'pinky',
- 'ipatokendisabled': 'TRUE',
+ 'ipatokendisabled': True,
'ipatokennotbefore': '20200101010102Z',
'ipatokennotafter': '20900101010102Z',
'ipatokenvendor': 'NewAcme',
@@ -384,7 +384,7 @@ class TestIPAOTPToken(ModuleTestCase):
'ipatokenotpkey': [{'__base64__': 'KRSXG5CTMVRXEZLUGE======'}],
'description': ['Test description'],
'ipatokenowner': ['pinky'],
- 'ipatokendisabled': ['FALSE'],
+ 'ipatokendisabled': [False],
'ipatokennotbefore': ['20200101010101Z'],
'ipatokennotafter': ['20900101010101Z'],
'ipatokenvendor': ['Acme'],
@@ -425,7 +425,7 @@ class TestIPAOTPToken(ModuleTestCase):
'ipatokenotpkey': [{'__base64__': 'KRSXG5CTMVRXEZLUGE======'}],
'description': ['Test description'],
'ipatokenowner': ['pinky'],
- 'ipatokendisabled': ['FALSE'],
+ 'ipatokendisabled': [False],
'ipatokennotbefore': ['20200101010101Z'],
'ipatokennotafter': ['20900101010101Z'],
'ipatokenvendor': ['Acme'],
@@ -448,7 +448,7 @@ class TestIPAOTPToken(ModuleTestCase):
{
'method': 'otptoken_mod',
'name': 'NewToken1',
- 'item': {'ipatokendisabled': 'TRUE',
+ 'item': {'ipatokendisabled': True,
'all': True}
}
)
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_ipa_pwpolicy.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_ipa_pwpolicy.py
index b45c566fc..538f61e9a 100644
--- a/ansible_collections/community/general/tests/unit/plugins/modules/test_ipa_pwpolicy.py
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_ipa_pwpolicy.py
@@ -100,7 +100,12 @@ class TestIPAPwPolicy(ModuleTestCase):
'minlength': '16',
'maxfailcount': '6',
'failinterval': '60',
- 'lockouttime': '600'
+ 'lockouttime': '600',
+ 'gracelimit': 3,
+ 'maxrepeat': 3,
+ 'maxsequence': 3,
+ 'dictcheck': True,
+ 'usercheck': True,
}
return_value = {}
mock_calls = (
@@ -124,7 +129,12 @@ class TestIPAPwPolicy(ModuleTestCase):
'krbpwdminlength': '16',
'krbpwdmaxfailure': '6',
'krbpwdfailurecountinterval': '60',
- 'krbpwdlockoutduration': '600'
+ 'krbpwdlockoutduration': '600',
+ 'passwordgracelimit': '3',
+ 'ipapwdmaxrepeat': '3',
+ 'ipapwdmaxsequence': '3',
+ 'ipapwddictcheck': True,
+ 'ipapwdusercheck': True,
}
}
)
@@ -145,7 +155,12 @@ class TestIPAPwPolicy(ModuleTestCase):
'minlength': '16',
'maxfailcount': '6',
'failinterval': '60',
- 'lockouttime': '600'
+ 'lockouttime': '600',
+ 'gracelimit': 3,
+ 'maxrepeat': 3,
+ 'maxsequence': 3,
+ 'dictcheck': True,
+ 'usercheck': True,
}
return_value = {}
mock_calls = (
@@ -169,7 +184,12 @@ class TestIPAPwPolicy(ModuleTestCase):
'krbpwdminlength': '16',
'krbpwdmaxfailure': '6',
'krbpwdfailurecountinterval': '60',
- 'krbpwdlockoutduration': '600'
+ 'krbpwdlockoutduration': '600',
+ 'passwordgracelimit': '3',
+ 'ipapwdmaxrepeat': '3',
+ 'ipapwdmaxsequence': '3',
+ 'ipapwddictcheck': True,
+ 'ipapwdusercheck': True,
}
}
)
@@ -190,7 +210,12 @@ class TestIPAPwPolicy(ModuleTestCase):
'minlength': '12',
'maxfailcount': '8',
'failinterval': '60',
- 'lockouttime': '600'
+ 'lockouttime': '600',
+ 'gracelimit': 3,
+ 'maxrepeat': 3,
+ 'maxsequence': 3,
+ 'dictcheck': True,
+ 'usercheck': True,
}
return_value = {
'cn': ['sysops'],
@@ -203,6 +228,11 @@ class TestIPAPwPolicy(ModuleTestCase):
'krbpwdmaxfailure': ['6'],
'krbpwdfailurecountinterval': ['60'],
'krbpwdlockoutduration': ['600'],
+ 'passwordgracelimit': ['3'],
+ 'ipapwdmaxrepeat': ['3'],
+ 'ipapwdmaxsequence': ['3'],
+ 'ipapwddictcheck': [True],
+ 'ipapwdusercheck': [True],
'dn': 'cn=sysops,cn=EXAMPLE.COM,cn=kerberos,dc=example,dc=com',
'objectclass': ['top', 'nscontainer', 'krbpwdpolicy']
}
@@ -227,7 +257,12 @@ class TestIPAPwPolicy(ModuleTestCase):
'krbpwdminlength': '12',
'krbpwdmaxfailure': '8',
'krbpwdfailurecountinterval': '60',
- 'krbpwdlockoutduration': '600'
+ 'krbpwdlockoutduration': '600',
+ 'passwordgracelimit': '3',
+ 'ipapwdmaxrepeat': '3',
+ 'ipapwdmaxsequence': '3',
+ 'ipapwddictcheck': True,
+ 'ipapwdusercheck': True,
}
}
)
@@ -248,7 +283,12 @@ class TestIPAPwPolicy(ModuleTestCase):
'minlength': '16',
'maxfailcount': '6',
'failinterval': '60',
- 'lockouttime': '600'
+ 'lockouttime': '600',
+ 'gracelimit': 3,
+ 'maxrepeat': 3,
+ 'maxsequence': 3,
+ 'dictcheck': True,
+ 'usercheck': True,
}
return_value = {
'cn': ['sysops'],
@@ -281,7 +321,12 @@ class TestIPAPwPolicy(ModuleTestCase):
'krbpwdminlength': '16',
'krbpwdmaxfailure': '6',
'krbpwdfailurecountinterval': '60',
- 'krbpwdlockoutduration': '600'
+ 'krbpwdlockoutduration': '600',
+ 'passwordgracelimit': '3',
+ 'ipapwdmaxrepeat': '3',
+ 'ipapwdmaxsequence': '3',
+ 'ipapwddictcheck': True,
+ 'ipapwdusercheck': True,
}
}
)
@@ -342,7 +387,12 @@ class TestIPAPwPolicy(ModuleTestCase):
'minlength': '16',
'maxfailcount': '6',
'failinterval': '60',
- 'lockouttime': '600'
+ 'lockouttime': '600',
+ 'gracelimit': 3,
+ 'maxrepeat': 3,
+ 'maxsequence': 3,
+ 'dictcheck': True,
+ 'usercheck': True,
}
return_value = {
'cn': ['admins'],
@@ -355,6 +405,11 @@ class TestIPAPwPolicy(ModuleTestCase):
'krbpwdmaxfailure': ['6'],
'krbpwdfailurecountinterval': ['60'],
'krbpwdlockoutduration': ['600'],
+ 'passwordgracelimit': ['3'],
+ 'ipapwdmaxrepeat': ['3'],
+ 'ipapwdmaxsequence': ['3'],
+ 'ipapwddictcheck': [True],
+ 'ipapwdusercheck': [True],
'dn': 'cn=admins,cn=EXAMPLE.COM,cn=kerberos,dc=example,dc=com',
'objectclass': ['top', 'nscontainer', 'krbpwdpolicy']
}
@@ -409,7 +464,12 @@ class TestIPAPwPolicy(ModuleTestCase):
'minlength': '12',
'maxfailcount': '8',
'failinterval': '60',
- 'lockouttime': '600'
+ 'lockouttime': '600',
+ 'gracelimit': 3,
+ 'maxrepeat': 3,
+ 'maxsequence': 3,
+ 'dictcheck': True,
+ 'usercheck': True,
}
return_value = {
'cn': ['global_policy'],
@@ -420,6 +480,11 @@ class TestIPAPwPolicy(ModuleTestCase):
'krbpwdmaxfailure': ['6'],
'krbpwdfailurecountinterval': ['60'],
'krbpwdlockoutduration': ['600'],
+ 'passwordgracelimit': ['3'],
+ 'ipapwdmaxrepeat': ['3'],
+ 'ipapwdmaxsequence': ['3'],
+ 'ipapwddictcheck': [True],
+ 'ipapwdusercheck': [True],
'dn': 'cn=global_policy,cn=EXAMPLE.COM,cn=kerberos,dc=example,dc=com',
'objectclass': ['top', 'nscontainer', 'krbpwdpolicy']
}
@@ -443,7 +508,12 @@ class TestIPAPwPolicy(ModuleTestCase):
'krbpwdminlength': '12',
'krbpwdmaxfailure': '8',
'krbpwdfailurecountinterval': '60',
- 'krbpwdlockoutduration': '600'
+ 'krbpwdlockoutduration': '600',
+ 'passwordgracelimit': '3',
+ 'ipapwdmaxrepeat': '3',
+ 'ipapwdmaxsequence': '3',
+ 'ipapwddictcheck': True,
+ 'ipapwdusercheck': True,
}
}
)
@@ -461,7 +531,12 @@ class TestIPAPwPolicy(ModuleTestCase):
'minlength': '16',
'maxfailcount': '6',
'failinterval': '60',
- 'lockouttime': '600'
+ 'lockouttime': '600',
+ 'gracelimit': 3,
+ 'maxrepeat': 3,
+ 'maxsequence': 3,
+ 'dictcheck': True,
+ 'usercheck': True,
}
return_value = {
'cn': ['global_policy'],
@@ -473,6 +548,11 @@ class TestIPAPwPolicy(ModuleTestCase):
'krbpwdmaxfailure': ['6'],
'krbpwdfailurecountinterval': ['60'],
'krbpwdlockoutduration': ['600'],
+ 'passwordgracelimit': ['3'],
+ 'ipapwdmaxrepeat': ['3'],
+ 'ipapwdmaxsequence': ['3'],
+ 'ipapwddictcheck': [True],
+ 'ipapwdusercheck': [True],
'dn': 'cn=global_policy,cn=EXAMPLE.COM,cn=kerberos,dc=example,dc=com',
'objectclass': ['top', 'nscontainer', 'krbpwdpolicy']
}
@@ -504,7 +584,12 @@ class TestIPAPwPolicy(ModuleTestCase):
'minlength': '16',
'maxfailcount': '6',
'failinterval': '60',
- 'lockouttime': '600'
+ 'lockouttime': '600',
+ 'gracelimit': 3,
+ 'maxrepeat': 3,
+ 'maxsequence': 3,
+ 'dictcheck': True,
+ 'usercheck': True,
}
return_value = {}
mock_calls = [
@@ -535,7 +620,12 @@ class TestIPAPwPolicy(ModuleTestCase):
'minlength': '12',
'maxfailcount': '8',
'failinterval': '60',
- 'lockouttime': '600'
+ 'lockouttime': '600',
+ 'gracelimit': 3,
+ 'maxrepeat': 3,
+ 'maxsequence': 3,
+ 'dictcheck': True,
+ 'usercheck': True,
}
return_value = {
'cn': ['sysops'],
@@ -548,6 +638,11 @@ class TestIPAPwPolicy(ModuleTestCase):
'krbpwdmaxfailure': ['6'],
'krbpwdfailurecountinterval': ['60'],
'krbpwdlockoutduration': ['600'],
+ 'passwordgracelimit': ['3'],
+ 'ipapwdmaxrepeat': ['3'],
+ 'ipapwdmaxsequence': ['3'],
+ 'ipapwddictcheck': [True],
+ 'ipapwdusercheck': [True],
'dn': 'cn=sysops,cn=EXAMPLE.COM,cn=kerberos,dc=example,dc=com',
'objectclass': ['top', 'nscontainer', 'krbpwdpolicy']
}
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_ipbase.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_ipbase.py
new file mode 100644
index 000000000..8106889da
--- /dev/null
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_ipbase.py
@@ -0,0 +1,187 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) Ansible project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import json
+
+from ansible_collections.community.general.plugins.modules.ipbase_info import IpbaseInfo
+from ansible_collections.community.general.tests.unit.compat import unittest
+from ansible_collections.community.general.tests.unit.compat.mock import Mock
+
+
+IPBASE_DATA = {
+ "response": b"""
+{
+ "data": {
+ "ip": "1.1.1.1",
+ "hostname": "one.one.one.one",
+ "type": "v4",
+ "range_type": {
+ "type": "PUBLIC",
+ "description": "Public address"
+ },
+ "connection": {
+ "asn": 13335,
+ "organization": "Cloudflare, Inc.",
+ "isp": "APNIC Research and Development",
+ "range": "1.1.1.1/32"
+ },
+ "location": {
+ "geonames_id": 5332870,
+ "latitude": 34.053611755371094,
+ "longitude": -118.24549865722656,
+ "zip": "90012",
+ "continent": {
+ "code": "NA",
+ "name": "North America",
+ "name_translated": "North America"
+ },
+ "country": {
+ "alpha2": "US",
+ "alpha3": "USA",
+ "calling_codes": [
+ "+1"
+ ],
+ "currencies": [
+ {
+ "symbol": "$",
+ "name": "US Dollar",
+ "symbol_native": "$",
+ "decimal_digits": 2,
+ "rounding": 0,
+ "code": "USD",
+ "name_plural": "US dollars"
+ }
+ ],
+ "emoji": "...",
+ "ioc": "USA",
+ "languages": [
+ {
+ "name": "English",
+ "name_native": "English"
+ }
+ ],
+ "name": "United States",
+ "name_translated": "United States",
+ "timezones": [
+ "America/New_York",
+ "America/Detroit",
+ "America/Kentucky/Louisville",
+ "America/Kentucky/Monticello",
+ "America/Indiana/Indianapolis",
+ "America/Indiana/Vincennes",
+ "America/Indiana/Winamac",
+ "America/Indiana/Marengo",
+ "America/Indiana/Petersburg",
+ "America/Indiana/Vevay",
+ "America/Chicago",
+ "America/Indiana/Tell_City",
+ "America/Indiana/Knox",
+ "America/Menominee",
+ "America/North_Dakota/Center",
+ "America/North_Dakota/New_Salem",
+ "America/North_Dakota/Beulah",
+ "America/Denver",
+ "America/Boise",
+ "America/Phoenix",
+ "America/Los_Angeles",
+ "America/Anchorage",
+ "America/Juneau",
+ "America/Sitka",
+ "America/Metlakatla",
+ "America/Yakutat",
+ "America/Nome",
+ "America/Adak",
+ "Pacific/Honolulu"
+ ],
+ "is_in_european_union": false,
+ "fips": "US",
+ "geonames_id": 6252001,
+ "hasc_id": "US",
+ "wikidata_id": "Q30"
+ },
+ "city": {
+ "fips": "644000",
+ "alpha2": null,
+ "geonames_id": 5368753,
+ "hasc_id": null,
+ "wikidata_id": "Q65",
+ "name": "Los Angeles",
+ "name_translated": "Los Angeles"
+ },
+ "region": {
+ "fips": "US06",
+ "alpha2": "US-CA",
+ "geonames_id": 5332921,
+ "hasc_id": "US.CA",
+ "wikidata_id": "Q99",
+ "name": "California",
+ "name_translated": "California"
+ }
+ },
+ "tlds": [
+ ".us"
+ ],
+ "timezone": {
+ "id": "America/Los_Angeles",
+ "current_time": "2023-05-04T04:30:28-07:00",
+ "code": "PDT",
+ "is_daylight_saving": true,
+ "gmt_offset": -25200
+ },
+ "security": {
+ "is_anonymous": false,
+ "is_datacenter": false,
+ "is_vpn": false,
+ "is_bot": false,
+ "is_abuser": true,
+ "is_known_attacker": true,
+ "is_proxy": false,
+ "is_spam": false,
+ "is_tor": false,
+ "is_icloud_relay": false,
+ "threat_score": 100
+ },
+ "domains": {
+ "count": 10943,
+ "domains": [
+ "eliwise.academy",
+ "accountingprose.academy",
+ "pistola.academy",
+ "1and1-test-ntlds-fr.accountant",
+ "omnergy.africa"
+ ]
+ }
+ }
+}
+"""
+}
+
+
+class TestIpbase(unittest.TestCase):
+ def test_info(self,):
+ "test the json data extraction"
+
+ params = {
+ "ip": "1.1.1.1",
+ "apikey": "aaa",
+ "hostname": True,
+ "language": "de",
+ }
+ module = Mock()
+ module.params = params
+
+ data = json.loads(IPBASE_DATA['response'].decode("utf-8"))
+
+ IpbaseInfo._get_url_data = Mock()
+ IpbaseInfo._get_url_data.return_value = data
+ jenkins_plugin = IpbaseInfo(module)
+
+ json_data = jenkins_plugin.info()
+
+ self.maxDiff = None
+ self.assertDictEqual(json_data, data)
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_jenkins_build.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_jenkins_build.py
index 44c6307ac..d9013a018 100644
--- a/ansible_collections/community/general/tests/unit/plugins/modules/test_jenkins_build.py
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_jenkins_build.py
@@ -75,6 +75,11 @@ class JenkinsMock():
def get_build_info(self, name, build_number):
if name == "host-delete":
raise jenkins.JenkinsException("job {0} number {1} does not exist".format(name, build_number))
+ elif name == "create-detached":
+ return {
+ "building": True,
+ "result": None
+ }
return {
"building": True,
"result": "SUCCESS"
@@ -222,3 +227,38 @@ class TestJenkinsBuild(unittest.TestCase):
"token": "xyz"
})
jenkins_build.main()
+
+ @patch('ansible_collections.community.general.plugins.modules.jenkins_build.test_dependencies')
+ @patch('ansible_collections.community.general.plugins.modules.jenkins_build.JenkinsBuild.get_jenkins_connection')
+ @patch('ansible_collections.community.general.plugins.modules.jenkins_build.JenkinsBuild.get_build_status')
+ def test_module_create_build_without_detach(self, build_status, jenkins_connection, test_deps):
+ test_deps.return_value = None
+ jenkins_connection.return_value = JenkinsMock()
+ build_status.return_value = JenkinsBuildMock().get_build_status()
+
+ with self.assertRaises(AnsibleExitJson) as return_json:
+ set_module_args({
+ "name": "create-detached",
+ "user": "abc",
+ "token": "xyz"
+ })
+ jenkins_build.main()
+
+ self.assertFalse(return_json.exception.args[0]['changed'])
+
+ @patch('ansible_collections.community.general.plugins.modules.jenkins_build.test_dependencies')
+ @patch('ansible_collections.community.general.plugins.modules.jenkins_build.JenkinsBuild.get_jenkins_connection')
+ def test_module_create_build_detached(self, jenkins_connection, test_deps):
+ test_deps.return_value = None
+ jenkins_connection.return_value = JenkinsMock()
+
+ with self.assertRaises(AnsibleExitJson) as return_json:
+ set_module_args({
+ "name": "create-detached",
+ "user": "abc",
+ "token": "xyz",
+ "detach": True
+ })
+ jenkins_build.main()
+
+ self.assertTrue(return_json.exception.args[0]['changed'])
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_jenkins_build_info.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_jenkins_build_info.py
new file mode 100644
index 000000000..b5d4126fe
--- /dev/null
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_jenkins_build_info.py
@@ -0,0 +1,180 @@
+# Copyright (c) Ansible project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+from ansible_collections.community.general.tests.unit.compat import unittest
+from ansible_collections.community.general.tests.unit.compat.mock import patch
+from ansible.module_utils import basic
+from ansible.module_utils.common.text.converters import to_bytes
+from ansible_collections.community.general.plugins.modules import jenkins_build_info
+
+import json
+
+
+def set_module_args(args):
+ """prepare arguments so that they will be picked up during module creation"""
+ args = json.dumps({'ANSIBLE_MODULE_ARGS': args})
+ basic._ANSIBLE_ARGS = to_bytes(args)
+
+
+class AnsibleExitJson(Exception):
+ """Exception class to be raised by module.exit_json and caught by the test case"""
+ pass
+
+
+class AnsibleFailJson(Exception):
+ """Exception class to be raised by module.fail_json and caught by the test case"""
+ pass
+
+
+def exit_json(*args, **kwargs):
+ """function to patch over exit_json; package return data into an exception"""
+ if 'changed' not in kwargs:
+ kwargs['changed'] = False
+ raise AnsibleExitJson(kwargs)
+
+
+def fail_json(*args, **kwargs):
+ """function to patch over fail_json; package return data into an exception"""
+ kwargs['failed'] = True
+ raise AnsibleFailJson(kwargs)
+
+
+class jenkins:
+ class JenkinsException(Exception):
+ pass
+
+
+class JenkinsBuildMock():
+ def __init__(self, name, build_number=None):
+ self.name = name
+ self.build_number = build_number
+
+ def get_build_status(self):
+ try:
+ instance = JenkinsMock()
+ response = JenkinsMock.get_build_info(instance, self.name, self.build_number)
+ return response
+ except jenkins.JenkinsException:
+ response = {}
+ response["result"] = "ABSENT"
+ return response
+ except Exception as e:
+ fail_json(msg='Unable to fetch build information, {0}'.format(e))
+
+
+class JenkinsMock():
+
+ def get_build_info(self, name, build_number):
+ if name == "job-absent":
+ raise jenkins.JenkinsException()
+
+ return {
+ "result": "SUCCESS",
+ "build_info": {}
+ }
+
+ def get_job_info(self, name):
+ if name == "job-absent":
+ raise jenkins.JenkinsException()
+
+ return {
+ "lastBuild": {
+ "number": 123
+ }
+ }
+
+
+class TestJenkinsBuildInfo(unittest.TestCase):
+
+ def setUp(self):
+ self.mock_module_helper = patch.multiple(basic.AnsibleModule,
+ exit_json=exit_json,
+ fail_json=fail_json)
+ self.mock_module_helper.start()
+ self.addCleanup(self.mock_module_helper.stop)
+
+ @patch('ansible_collections.community.general.plugins.modules.jenkins_build_info.test_dependencies')
+ def test_module_fail_when_required_args_missing(self, test_deps):
+ test_deps.return_value = None
+ with self.assertRaises(AnsibleFailJson):
+ set_module_args({})
+ jenkins_build_info.main()
+
+ @patch('ansible_collections.community.general.plugins.modules.jenkins_build_info.test_dependencies')
+ @patch('ansible_collections.community.general.plugins.modules.jenkins_build_info.JenkinsBuildInfo.get_jenkins_connection')
+ def test_module_get_build_info(self, jenkins_connection, test_deps):
+ test_deps.return_value = None
+ jenkins_connection.return_value = JenkinsMock()
+
+ with self.assertRaises(AnsibleExitJson) as return_json:
+ set_module_args({
+ "name": "job-present",
+ "user": "abc",
+ "token": "xyz",
+ "build_number": 30
+ })
+ jenkins_build_info.main()
+
+ self.assertFalse(return_json.exception.args[0]["changed"])
+
+ @patch('ansible_collections.community.general.plugins.modules.jenkins_build_info.test_dependencies')
+ @patch('ansible_collections.community.general.plugins.modules.jenkins_build_info.JenkinsBuildInfo.get_jenkins_connection')
+ @patch('ansible_collections.community.general.plugins.modules.jenkins_build_info.JenkinsBuildInfo.get_build_status')
+ def test_module_get_build_info_if_build_does_not_exist(self, build_status, jenkins_connection, test_deps):
+ test_deps.return_value = None
+ jenkins_connection.return_value = JenkinsMock()
+ build_status.return_value = JenkinsBuildMock("job-absent", 30).get_build_status()
+
+ with self.assertRaises(AnsibleExitJson) as return_json:
+ set_module_args({
+ "name": "job-absent",
+ "user": "abc",
+ "token": "xyz",
+ "build_number": 30
+ })
+ jenkins_build_info.main()
+
+ self.assertFalse(return_json.exception.args[0]['changed'])
+ self.assertTrue(return_json.exception.args[0]['failed'])
+ self.assertEqual("ABSENT", return_json.exception.args[0]['build_info']['result'])
+
+ @patch('ansible_collections.community.general.plugins.modules.jenkins_build_info.test_dependencies')
+ @patch('ansible_collections.community.general.plugins.modules.jenkins_build_info.JenkinsBuildInfo.get_jenkins_connection')
+ def test_module_get_build_info_get_last_build(self, jenkins_connection, test_deps):
+ test_deps.return_value = None
+ jenkins_connection.return_value = JenkinsMock()
+
+ with self.assertRaises(AnsibleExitJson) as return_json:
+ set_module_args({
+ "name": "job-present",
+ "user": "abc",
+ "token": "xyz"
+ })
+ jenkins_build_info.main()
+
+ self.assertFalse(return_json.exception.args[0]['changed'])
+ self.assertEqual("SUCCESS", return_json.exception.args[0]['build_info']['result'])
+
+ @patch('ansible_collections.community.general.plugins.modules.jenkins_build_info.test_dependencies')
+ @patch('ansible_collections.community.general.plugins.modules.jenkins_build_info.JenkinsBuildInfo.get_jenkins_connection')
+ @patch('ansible_collections.community.general.plugins.modules.jenkins_build_info.JenkinsBuildInfo.get_build_status')
+ def test_module_get_build_info_if_job_does_not_exist(self, build_status, jenkins_connection, test_deps):
+ test_deps.return_value = None
+ jenkins_connection.return_value = JenkinsMock()
+ build_status.return_value = JenkinsBuildMock("job-absent").get_build_status()
+
+ with self.assertRaises(AnsibleExitJson) as return_json:
+ set_module_args({
+ "name": "job-absent",
+ "user": "abc",
+ "token": "xyz"
+ })
+ jenkins_build_info.main()
+
+ self.assertFalse(return_json.exception.args[0]['changed'])
+ self.assertTrue(return_json.exception.args[0]['failed'])
+ self.assertEqual("ABSENT", return_json.exception.args[0]['build_info']['result'])
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_keycloak_authentication_required_actions.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_keycloak_authentication_required_actions.py
new file mode 100644
index 000000000..2adc3a896
--- /dev/null
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_keycloak_authentication_required_actions.py
@@ -0,0 +1,835 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2021, Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+from contextlib import contextmanager
+
+from ansible_collections.community.general.tests.unit.compat import unittest
+from ansible_collections.community.general.tests.unit.compat.mock import patch
+from ansible_collections.community.general.tests.unit.plugins.modules.utils import AnsibleExitJson, ModuleTestCase, set_module_args
+
+from ansible_collections.community.general.plugins.modules import keycloak_authentication_required_actions
+
+from itertools import count
+
+from ansible.module_utils.six import StringIO
+
+
+@contextmanager
+def patch_keycloak_api(
+ get_required_actions=None,
+ register_required_action=None,
+ update_required_action=None,
+ delete_required_action=None,
+):
+ """
+ Mock context manager for patching the methods in PwPolicyIPAClient that contact the IPA server
+
+ Patches the `login` and `_post_json` methods
+
+ Keyword arguments are passed to the mock object that patches `_post_json`
+
+ No arguments are passed to the mock object that patches `login` because no tests require it
+
+ Example::
+
+ with patch_ipa(return_value={}) as (mock_login, mock_post):
+ ...
+ """
+
+ obj = keycloak_authentication_required_actions.KeycloakAPI
+ with patch.object(
+ obj,
+ 'get_required_actions',
+ side_effect=get_required_actions
+ ) as mock_get_required_actions:
+ with patch.object(
+ obj,
+ 'register_required_action',
+ side_effect=register_required_action
+ ) as mock_register_required_action:
+ with patch.object(
+ obj,
+ 'update_required_action',
+ side_effect=update_required_action
+ ) as mock_update_required_action:
+ with patch.object(
+ obj,
+ 'delete_required_action',
+ side_effect=delete_required_action
+ ) as mock_delete_required_action:
+ yield (
+ mock_get_required_actions,
+ mock_register_required_action,
+ mock_update_required_action,
+ mock_delete_required_action,
+ )
+
+
+def get_response(object_with_future_response, method, get_id_call_count):
+ if callable(object_with_future_response):
+ return object_with_future_response()
+ if isinstance(object_with_future_response, dict):
+ return get_response(
+ object_with_future_response[method], method, get_id_call_count)
+ if isinstance(object_with_future_response, list):
+ call_number = next(get_id_call_count)
+ return get_response(
+ object_with_future_response[call_number], method, get_id_call_count)
+ return object_with_future_response
+
+
+def build_mocked_request(get_id_user_count, response_dict):
+ def _mocked_requests(*args, **kwargs):
+ url = args[0]
+ method = kwargs['method']
+ future_response = response_dict.get(url, None)
+ return get_response(future_response, method, get_id_user_count)
+ return _mocked_requests
+
+
+def create_wrapper(text_as_string):
+ """Allow to mock many times a call to one address.
+ Without this function, the StringIO is empty for the second call.
+ """
+ def _create_wrapper():
+ return StringIO(text_as_string)
+ return _create_wrapper
+
+
+def mock_good_connection():
+ token_response = {
+ 'http://keycloak.url/auth/realms/master/protocol/openid-connect/token': create_wrapper('{"access_token": "alongtoken"}'), }
+ return patch(
+ 'ansible_collections.community.general.plugins.module_utils.identity.keycloak.keycloak.open_url',
+ side_effect=build_mocked_request(count(), token_response),
+ autospec=True
+ )
+
+
+class TestKeycloakAuthentication(ModuleTestCase):
+ def setUp(self):
+ super(TestKeycloakAuthentication, self).setUp()
+ self.module = keycloak_authentication_required_actions
+
+ def test_register_required_action(self):
+ """Register a new authentication required action."""
+
+ module_args = {
+ 'auth_client_id': 'admin-cli',
+ 'auth_keycloak_url': 'http://keycloak.url/auth',
+ 'auth_password': 'admin',
+ 'auth_realm': 'master',
+ 'auth_username': 'admin',
+ 'realm': 'master',
+ 'required_actions': [
+ {
+ 'alias': 'test-provider-id',
+ 'name': 'Test provider ID',
+ 'providerId': 'test-provider-id',
+ },
+ {
+ 'alias': 'test-provider-id',
+ 'name': 'Test provider ID (DUPLICATE ALIAS)',
+ 'providerId': 'test-provider-id',
+ },
+ {
+ 'alias': 'test-provider-id',
+ 'name': 'Test provider ID (DIFFERENT PROVIDER ID)',
+ 'providerId': 'test-provider-id-diff',
+ },
+ ],
+ 'state': 'present',
+ }
+
+ return_value_required_actions = [
+ [
+ {
+ 'alias': 'CONFIGURE_TOTP',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': True,
+ 'name': 'Configure OTP',
+ 'priority': 10,
+ 'providerId': 'CONFIGURE_TOTP'
+ },
+ {
+ 'alias': 'TERMS_AND_CONDITIONS',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': True,
+ 'name': 'Terms and conditions',
+ 'priority': 20,
+ 'providerId': 'TERMS_AND_CONDITIONS'
+ },
+ {
+ 'alias': 'UPDATE_PASSWORD',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': True,
+ 'name': 'Update Password',
+ 'priority': 30,
+ 'providerId': 'UPDATE_PASSWORD'
+ },
+ {
+ 'alias': 'UPDATE_PROFILE',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': True,
+ 'name': 'Update Profile',
+ 'priority': 40,
+ 'providerId': 'UPDATE_PROFILE'
+ },
+ {
+ 'alias': 'VERIFY_EMAIL',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': True,
+ 'name': 'Verify Email',
+ 'priority': 50,
+ 'providerId': 'VERIFY_EMAIL'
+ },
+ {
+ 'alias': 'delete_account',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': False,
+ 'name': 'Delete Account',
+ 'priority': 60,
+ 'providerId': 'delete_account'
+ },
+ {
+ 'alias': 'webauthn-register',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': True,
+ 'name': 'Webauthn Register',
+ 'priority': 70,
+ 'providerId': 'webauthn-register'
+ },
+ {
+ 'alias': 'webauthn-register-passwordless',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': True,
+ 'name': 'Webauthn Register Passwordless',
+ 'priority': 80,
+ 'providerId': 'webauthn-register-passwordless'
+ },
+ {
+ 'alias': 'update_user_locale',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': True,
+ 'name': 'Update User Locale',
+ 'priority': 1000,
+ 'providerId': 'update_user_locale'
+ }
+ ],
+ ]
+
+ changed = True
+
+ set_module_args(module_args)
+
+ # Run the module
+ with mock_good_connection():
+ with patch_keycloak_api(
+ get_required_actions=return_value_required_actions,
+ ) as (
+ mock_get_required_actions,
+ mock_register_required_action,
+ mock_update_required_action,
+ mock_delete_required_action,
+ ):
+ with self.assertRaises(AnsibleExitJson) as exec_info:
+ self.module.main()
+
+ # Verify number of call on each mock
+ self.assertEqual(len(mock_get_required_actions.mock_calls), 1)
+ self.assertEqual(len(mock_update_required_action.mock_calls), 1)
+ self.assertEqual(len(mock_register_required_action.mock_calls), 1)
+ self.assertEqual(len(mock_delete_required_action.mock_calls), 0)
+
+ # Verify that the module's changed status matches what is expected
+ self.assertIs(exec_info.exception.args[0]['changed'], changed)
+
+ def test_register_required_action_idempotency(self):
+ """Register an already existing new authentication required action again."""
+
+ module_args = {
+ 'auth_client_id': 'admin-cli',
+ 'auth_keycloak_url': 'http://keycloak.url/auth',
+ 'auth_password': 'admin',
+ 'auth_realm': 'master',
+ 'auth_username': 'admin',
+ 'realm': 'master',
+ 'required_actions': [
+ {
+ 'alias': 'test-provider-id',
+ 'name': 'Test provider ID',
+ 'providerId': 'test-provider-id',
+ },
+ {
+ 'alias': 'test-provider-id',
+ 'name': 'Test provider ID (DUPLICATE ALIAS)',
+ 'providerId': 'test-provider-id',
+ },
+ {
+ 'alias': 'test-provider-id',
+ 'name': 'Test provider ID (DIFFERENT PROVIDER ID)',
+ 'providerId': 'test-provider-id-diff',
+ },
+ ],
+ 'state': 'present',
+ }
+
+ return_value_required_actions = [
+ [
+ {
+ 'alias': 'CONFIGURE_TOTP',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': True,
+ 'name': 'Configure OTP',
+ 'priority': 10,
+ 'providerId': 'CONFIGURE_TOTP'
+ },
+ {
+ 'alias': 'TERMS_AND_CONDITIONS',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': True,
+ 'name': 'Terms and conditions',
+ 'priority': 20,
+ 'providerId': 'TERMS_AND_CONDITIONS'
+ },
+ {
+ 'alias': 'UPDATE_PASSWORD',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': True,
+ 'name': 'Update Password',
+ 'priority': 30,
+ 'providerId': 'UPDATE_PASSWORD'
+ },
+ {
+ 'alias': 'UPDATE_PROFILE',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': True,
+ 'name': 'Update Profile',
+ 'priority': 40,
+ 'providerId': 'UPDATE_PROFILE'
+ },
+ {
+ 'alias': 'VERIFY_EMAIL',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': True,
+ 'name': 'Verify Email',
+ 'priority': 50,
+ 'providerId': 'VERIFY_EMAIL'
+ },
+ {
+ 'alias': 'delete_account',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': False,
+ 'name': 'Delete Account',
+ 'priority': 60,
+ 'providerId': 'delete_account'
+ },
+ {
+ 'alias': 'webauthn-register',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': True,
+ 'name': 'Webauthn Register',
+ 'priority': 70,
+ 'providerId': 'webauthn-register'
+ },
+ {
+ 'alias': 'webauthn-register-passwordless',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': True,
+ 'name': 'Webauthn Register Passwordless',
+ 'priority': 80,
+ 'providerId': 'webauthn-register-passwordless'
+ },
+ {
+ 'alias': 'test-provider-id',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': False,
+ 'name': 'Test provider ID',
+ 'priority': 90,
+ 'providerId': 'test-provider-id'
+ },
+ {
+ 'alias': 'update_user_locale',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': True,
+ 'name': 'Update User Locale',
+ 'priority': 1000,
+ 'providerId': 'update_user_locale'
+ }
+ ],
+ ]
+
+ changed = False
+
+ set_module_args(module_args)
+
+ # Run the module
+ with mock_good_connection():
+ with patch_keycloak_api(
+ get_required_actions=return_value_required_actions,
+ ) as (
+ mock_get_required_actions,
+ mock_register_required_action,
+ mock_update_required_action,
+ mock_delete_required_action,
+ ):
+ with self.assertRaises(AnsibleExitJson) as exec_info:
+ self.module.main()
+
+ # Verify number of call on each mock
+ self.assertEqual(len(mock_get_required_actions.mock_calls), 1)
+ self.assertEqual(len(mock_update_required_action.mock_calls), 0)
+ self.assertEqual(len(mock_register_required_action.mock_calls), 0)
+ self.assertEqual(len(mock_delete_required_action.mock_calls), 0)
+
+ # Verify that the module's changed status matches what is expected
+ self.assertIs(exec_info.exception.args[0]['changed'], changed)
+
+ def test_update_required_actions(self):
+ """Update an authentication required action."""
+
+ module_args = {
+ 'auth_client_id': 'admin-cli',
+ 'auth_keycloak_url': 'http://keycloak.url/auth',
+ 'auth_password': 'admin',
+ 'auth_realm': 'master',
+ 'auth_username': 'admin',
+ 'realm': 'master',
+ 'required_actions': [
+ {
+ 'alias': 'test-provider-id',
+ 'name': 'Test provider ID UPDATED',
+ 'providerId': 'test-provider-id',
+ },
+ {
+ 'alias': 'test-provider-id',
+ 'name': 'Test provider ID UPDATED (DUPLICATE ALIAS)',
+ 'providerId': 'test-provider-id',
+ },
+ {
+ 'alias': 'test-provider-id',
+ 'name': 'Test provider ID UPDATED (DIFFERENT PROVIDER ID)',
+ 'providerId': 'test-provider-id-diff',
+ },
+ ],
+ 'state': 'present',
+ }
+
+ return_value_required_actions = [
+ [
+ {
+ 'alias': 'CONFIGURE_TOTP',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': True,
+ 'name': 'Configure OTP',
+ 'priority': 10,
+ 'providerId': 'CONFIGURE_TOTP'
+ },
+ {
+ 'alias': 'TERMS_AND_CONDITIONS',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': True,
+ 'name': 'Terms and conditions',
+ 'priority': 20,
+ 'providerId': 'TERMS_AND_CONDITIONS'
+ },
+ {
+ 'alias': 'UPDATE_PASSWORD',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': True,
+ 'name': 'Update Password',
+ 'priority': 30,
+ 'providerId': 'UPDATE_PASSWORD'
+ },
+ {
+ 'alias': 'UPDATE_PROFILE',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': True,
+ 'name': 'Update Profile',
+ 'priority': 40,
+ 'providerId': 'UPDATE_PROFILE'
+ },
+ {
+ 'alias': 'VERIFY_EMAIL',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': True,
+ 'name': 'Verify Email',
+ 'priority': 50,
+ 'providerId': 'VERIFY_EMAIL'
+ },
+ {
+ 'alias': 'delete_account',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': False,
+ 'name': 'Delete Account',
+ 'priority': 60,
+ 'providerId': 'delete_account'
+ },
+ {
+ 'alias': 'webauthn-register',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': True,
+ 'name': 'Webauthn Register',
+ 'priority': 70,
+ 'providerId': 'webauthn-register'
+ },
+ {
+ 'alias': 'webauthn-register-passwordless',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': True,
+ 'name': 'Webauthn Register Passwordless',
+ 'priority': 80,
+ 'providerId': 'webauthn-register-passwordless'
+ },
+ {
+ 'alias': 'test-provider-id',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': False,
+ 'name': 'Test provider ID',
+ 'priority': 90,
+ 'providerId': 'test-provider-id'
+ },
+ {
+ 'alias': 'update_user_locale',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': True,
+ 'name': 'Update User Locale',
+ 'priority': 1000,
+ 'providerId': 'update_user_locale'
+ }
+ ],
+ ]
+
+ changed = True
+
+ set_module_args(module_args)
+
+ # Run the module
+ with mock_good_connection():
+ with patch_keycloak_api(
+ get_required_actions=return_value_required_actions,
+ ) as (
+ mock_get_required_actions,
+ mock_register_required_action,
+ mock_update_required_action,
+ mock_delete_required_action,
+ ):
+ with self.assertRaises(AnsibleExitJson) as exec_info:
+ self.module.main()
+
+ # Verify number of call on each mock
+ self.assertEqual(len(mock_get_required_actions.mock_calls), 1)
+ self.assertEqual(len(mock_update_required_action.mock_calls), 1)
+ self.assertEqual(len(mock_register_required_action.mock_calls), 0)
+ self.assertEqual(len(mock_delete_required_action.mock_calls), 0)
+
+ # Verify that the module's changed status matches what is expected
+ self.assertIs(exec_info.exception.args[0]['changed'], changed)
+
+ def test_delete_required_action(self):
+ """Delete a registered authentication required action."""
+
+ module_args = {
+ 'auth_client_id': 'admin-cli',
+ 'auth_keycloak_url': 'http://keycloak.url/auth',
+ 'auth_password': 'admin',
+ 'auth_realm': 'master',
+ 'auth_username': 'admin',
+ 'realm': 'master',
+ 'required_actions': [
+ {
+ 'alias': 'test-provider-id',
+ },
+ ],
+ 'state': 'absent',
+ }
+
+ return_value_required_actions = [
+ [
+ {
+ 'alias': 'CONFIGURE_TOTP',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': True,
+ 'name': 'Configure OTP',
+ 'priority': 10,
+ 'providerId': 'CONFIGURE_TOTP'
+ },
+ {
+ 'alias': 'TERMS_AND_CONDITIONS',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': True,
+ 'name': 'Terms and conditions',
+ 'priority': 20,
+ 'providerId': 'TERMS_AND_CONDITIONS'
+ },
+ {
+ 'alias': 'UPDATE_PASSWORD',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': True,
+ 'name': 'Update Password',
+ 'priority': 30,
+ 'providerId': 'UPDATE_PASSWORD'
+ },
+ {
+ 'alias': 'UPDATE_PROFILE',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': True,
+ 'name': 'Update Profile',
+ 'priority': 40,
+ 'providerId': 'UPDATE_PROFILE'
+ },
+ {
+ 'alias': 'VERIFY_EMAIL',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': True,
+ 'name': 'Verify Email',
+ 'priority': 50,
+ 'providerId': 'VERIFY_EMAIL'
+ },
+ {
+ 'alias': 'delete_account',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': False,
+ 'name': 'Delete Account',
+ 'priority': 60,
+ 'providerId': 'delete_account'
+ },
+ {
+ 'alias': 'webauthn-register',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': True,
+ 'name': 'Webauthn Register',
+ 'priority': 70,
+ 'providerId': 'webauthn-register'
+ },
+ {
+ 'alias': 'webauthn-register-passwordless',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': True,
+ 'name': 'Webauthn Register Passwordless',
+ 'priority': 80,
+ 'providerId': 'webauthn-register-passwordless'
+ },
+ {
+ 'alias': 'test-provider-id',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': False,
+ 'name': 'Test provider ID',
+ 'priority': 90,
+ 'providerId': 'test-provider-id'
+ },
+ {
+ 'alias': 'update_user_locale',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': True,
+ 'name': 'Update User Locale',
+ 'priority': 1000,
+ 'providerId': 'update_user_locale'
+ }
+ ],
+ ]
+
+ changed = True
+
+ set_module_args(module_args)
+
+ # Run the module
+ with mock_good_connection():
+ with patch_keycloak_api(
+ get_required_actions=return_value_required_actions,
+ ) as (
+ mock_get_required_actions,
+ mock_register_required_action,
+ mock_update_required_action,
+ mock_delete_required_action,
+ ):
+ with self.assertRaises(AnsibleExitJson) as exec_info:
+ self.module.main()
+
+ # Verify number of call on each mock
+ self.assertEqual(len(mock_get_required_actions.mock_calls), 1)
+ self.assertEqual(len(mock_update_required_action.mock_calls), 0)
+ self.assertEqual(len(mock_register_required_action.mock_calls), 0)
+ self.assertEqual(len(mock_delete_required_action.mock_calls), 1)
+
+ # Verify that the module's changed status matches what is expected
+ self.assertIs(exec_info.exception.args[0]['changed'], changed)
+
+ def test_delete_required_action_idempotency(self):
+ """Delete an already deleted authentication required action."""
+
+ module_args = {
+ 'auth_client_id': 'admin-cli',
+ 'auth_keycloak_url': 'http://keycloak.url/auth',
+ 'auth_password': 'admin',
+ 'auth_realm': 'master',
+ 'auth_username': 'admin',
+ 'realm': 'master',
+ 'required_actions': [
+ {
+ 'alias': 'test-provider-id',
+ },
+ ],
+ 'state': 'absent',
+ }
+
+ return_value_required_actions = [
+ [
+ {
+ 'alias': 'CONFIGURE_TOTP',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': True,
+ 'name': 'Configure OTP',
+ 'priority': 10,
+ 'providerId': 'CONFIGURE_TOTP'
+ },
+ {
+ 'alias': 'TERMS_AND_CONDITIONS',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': True,
+ 'name': 'Terms and conditions',
+ 'priority': 20,
+ 'providerId': 'TERMS_AND_CONDITIONS'
+ },
+ {
+ 'alias': 'UPDATE_PASSWORD',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': True,
+ 'name': 'Update Password',
+ 'priority': 30,
+ 'providerId': 'UPDATE_PASSWORD'
+ },
+ {
+ 'alias': 'UPDATE_PROFILE',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': True,
+ 'name': 'Update Profile',
+ 'priority': 40,
+ 'providerId': 'UPDATE_PROFILE'
+ },
+ {
+ 'alias': 'VERIFY_EMAIL',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': True,
+ 'name': 'Verify Email',
+ 'priority': 50,
+ 'providerId': 'VERIFY_EMAIL'
+ },
+ {
+ 'alias': 'delete_account',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': False,
+ 'name': 'Delete Account',
+ 'priority': 60,
+ 'providerId': 'delete_account'
+ },
+ {
+ 'alias': 'webauthn-register',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': True,
+ 'name': 'Webauthn Register',
+ 'priority': 70,
+ 'providerId': 'webauthn-register'
+ },
+ {
+ 'alias': 'webauthn-register-passwordless',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': True,
+ 'name': 'Webauthn Register Passwordless',
+ 'priority': 80,
+ 'providerId': 'webauthn-register-passwordless'
+ },
+ {
+ 'alias': 'update_user_locale',
+ 'config': {},
+ 'defaultAction': False,
+ 'enabled': True,
+ 'name': 'Update User Locale',
+ 'priority': 1000,
+ 'providerId': 'update_user_locale'
+ }
+ ],
+ ]
+
+ changed = False
+
+ set_module_args(module_args)
+
+ # Run the module
+ with mock_good_connection():
+ with patch_keycloak_api(
+ get_required_actions=return_value_required_actions,
+ ) as (
+ mock_get_required_actions,
+ mock_register_required_action,
+ mock_update_required_action,
+ mock_delete_required_action,
+ ):
+ with self.assertRaises(AnsibleExitJson) as exec_info:
+ self.module.main()
+
+ # Verify number of call on each mock
+ self.assertEqual(len(mock_get_required_actions.mock_calls), 1)
+ self.assertEqual(len(mock_update_required_action.mock_calls), 0)
+ self.assertEqual(len(mock_register_required_action.mock_calls), 0)
+ self.assertEqual(len(mock_delete_required_action.mock_calls), 0)
+
+ # Verify that the module's changed status matches what is expected
+ self.assertIs(exec_info.exception.args[0]['changed'], changed)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_keycloak_client_rolemapping.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_keycloak_client_rolemapping.py
index 58c8b9548..359e6304e 100644
--- a/ansible_collections/community/general/tests/unit/plugins/modules/test_keycloak_client_rolemapping.py
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_keycloak_client_rolemapping.py
@@ -120,6 +120,11 @@ class TestKeycloakRealm(ModuleTestCase):
'state': 'present',
'client_id': 'test_client',
'group_name': 'test_group',
+ 'parents': [
+ {
+ 'name': 'parent_group'
+ }
+ ],
'roles': [
{
'name': 'test_role1',
@@ -139,7 +144,7 @@ class TestKeycloakRealm(ModuleTestCase):
"clientRoles": "{}",
"id": "92f2400e-0ecb-4185-8950-12dcef616c2b",
"name": "test_group",
- "path": "/test_group",
+ "path": "/parent_group/test_group",
"realmRoles": "[]",
"subGroups": "[]"
}]
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_keycloak_role.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_keycloak_role.py
index c48c9771a..cc2f6e716 100644
--- a/ansible_collections/community/general/tests/unit/plugins/modules/test_keycloak_role.py
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_keycloak_role.py
@@ -21,7 +21,9 @@ from ansible.module_utils.six import StringIO
@contextmanager
-def patch_keycloak_api(get_realm_role, create_realm_role=None, update_realm_role=None, delete_realm_role=None):
+def patch_keycloak_api(get_realm_role=None, create_realm_role=None, update_realm_role=None, delete_realm_role=None,
+ get_client_role=None, create_client_role=None, update_client_role=None, delete_client_role=None,
+ get_client_by_id=None, get_role_composites=None):
"""Mock context manager for patching the methods in PwPolicyIPAClient that contact the IPA server
Patches the `login` and `_post_json` methods
@@ -41,7 +43,15 @@ def patch_keycloak_api(get_realm_role, create_realm_role=None, update_realm_role
with patch.object(obj, 'create_realm_role', side_effect=create_realm_role) as mock_create_realm_role:
with patch.object(obj, 'update_realm_role', side_effect=update_realm_role) as mock_update_realm_role:
with patch.object(obj, 'delete_realm_role', side_effect=delete_realm_role) as mock_delete_realm_role:
- yield mock_get_realm_role, mock_create_realm_role, mock_update_realm_role, mock_delete_realm_role
+ with patch.object(obj, 'get_client_role', side_effect=get_client_role) as mock_get_client_role:
+ with patch.object(obj, 'create_client_role', side_effect=create_client_role) as mock_create_client_role:
+ with patch.object(obj, 'update_client_role', side_effect=update_client_role) as mock_update_client_role:
+ with patch.object(obj, 'delete_client_role', side_effect=delete_client_role) as mock_delete_client_role:
+ with patch.object(obj, 'get_client_by_id', side_effect=get_client_by_id) as mock_get_client_by_id:
+ with patch.object(obj, 'get_role_composites', side_effect=get_role_composites) as mock_get_role_composites:
+ yield mock_get_realm_role, mock_create_realm_role, mock_update_realm_role, mock_delete_realm_role, \
+ mock_get_client_role, mock_create_client_role, mock_update_client_role, mock_delete_client_role, \
+ mock_get_client_by_id, mock_get_role_composites
def get_response(object_with_future_response, method, get_id_call_count):
@@ -125,7 +135,9 @@ class TestKeycloakRealmRole(ModuleTestCase):
with mock_good_connection():
with patch_keycloak_api(get_realm_role=return_value_absent, create_realm_role=return_value_created) \
- as (mock_get_realm_role, mock_create_realm_role, mock_update_realm_role, mock_delete_realm_role):
+ as (mock_get_realm_role, mock_create_realm_role, mock_update_realm_role, mock_delete_realm_role,
+ mock_get_client_role, mock_create_client_role, mock_update_client_role, mock_delete_client_role,
+ mock_get_client_by_client_id, mock_get_role_composites):
with self.assertRaises(AnsibleExitJson) as exec_info:
self.module.main()
@@ -179,7 +191,9 @@ class TestKeycloakRealmRole(ModuleTestCase):
with mock_good_connection():
with patch_keycloak_api(get_realm_role=return_value_present, update_realm_role=return_value_updated) \
- as (mock_get_realm_role, mock_create_realm_role, mock_update_realm_role, mock_delete_realm_role):
+ as (mock_get_realm_role, mock_create_realm_role, mock_update_realm_role, mock_delete_realm_role,
+ mock_get_client_role, mock_create_client_role, mock_update_client_role, mock_delete_client_role,
+ mock_get_client_by_client_id, mock_get_role_composites):
with self.assertRaises(AnsibleExitJson) as exec_info:
self.module.main()
@@ -233,7 +247,9 @@ class TestKeycloakRealmRole(ModuleTestCase):
with mock_good_connection():
with patch_keycloak_api(get_realm_role=return_value_present, update_realm_role=return_value_updated) \
- as (mock_get_realm_role, mock_create_realm_role, mock_update_realm_role, mock_delete_realm_role):
+ as (mock_get_realm_role, mock_create_realm_role, mock_update_realm_role, mock_delete_realm_role,
+ mock_get_client_role, mock_create_client_role, mock_update_client_role, mock_delete_client_role,
+ mock_get_client_by_client_id, mock_get_role_composites):
with self.assertRaises(AnsibleExitJson) as exec_info:
self.module.main()
@@ -244,6 +260,140 @@ class TestKeycloakRealmRole(ModuleTestCase):
# Verify that the module's changed status matches what is expected
self.assertIs(exec_info.exception.args[0]['changed'], changed)
+ def test_create_with_composites_when_present_no_change(self):
+ """Update without change a realm role"""
+
+ module_args = {
+ 'auth_keycloak_url': 'http://keycloak.url/auth',
+ 'auth_password': 'admin',
+ 'auth_realm': 'master',
+ 'auth_username': 'admin',
+ 'auth_client_id': 'admin-cli',
+ 'validate_certs': True,
+ 'realm': 'realm-name',
+ 'name': 'role-name',
+ 'description': 'role-description',
+ 'composite': True,
+ 'composites': [
+ {
+ 'client_id': 'client_1',
+ 'name': 'client-role1'
+ },
+ {
+ 'name': 'realm-role-1'
+ }
+ ]
+
+ }
+ return_value_present = [
+ {
+ "attributes": {},
+ "clientRole": False,
+ "composite": True,
+ "containerId": "realm-name",
+ "description": "role-description",
+ "id": "90f1cdb6-be88-496e-89c6-da1fb6bc6966",
+ "name": "role-name",
+ },
+ {
+ "attributes": {},
+ "clientRole": False,
+ "composite": True,
+ "containerId": "realm-name",
+ "description": "role-description",
+ "id": "90f1cdb6-be88-496e-89c6-da1fb6bc6966",
+ "name": "role-name",
+ }
+ ]
+ return_value_updated = [None]
+ return_get_role_composites = [
+ [
+ {
+ 'clientRole': True,
+ 'containerId': 'c4367fac-f427-11ed-8e2f-aff070d20f0e',
+ 'name': 'client-role1'
+ },
+ {
+ 'clientRole': False,
+ 'containerId': 'realm-name',
+ 'name': 'realm-role-1'
+ }
+ ]
+ ]
+ return_get_client_by_client_id = [
+ {
+ "id": "de152444-f126-4a7a-8273-4ee1544133ad",
+ "clientId": "client_1",
+ "name": "client_1",
+ "description": "client_1",
+ "surrogateAuthRequired": False,
+ "enabled": True,
+ "alwaysDisplayInConsole": False,
+ "clientAuthenticatorType": "client-secret",
+ "redirectUris": [
+ "http://localhost:8080/*",
+ ],
+ "webOrigins": [
+ "*"
+ ],
+ "notBefore": 0,
+ "bearerOnly": False,
+ "consentRequired": False,
+ "standardFlowEnabled": True,
+ "implicitFlowEnabled": False,
+ "directAccessGrantsEnabled": False,
+ "serviceAccountsEnabled": False,
+ "publicClient": False,
+ "frontchannelLogout": False,
+ "protocol": "openid-connect",
+ "attributes": {
+ "backchannel.logout.session.required": "true",
+ "backchannel.logout.revoke.offline.tokens": "false"
+ },
+ "authenticationFlowBindingOverrides": {},
+ "fullScopeAllowed": True,
+ "nodeReRegistrationTimeout": -1,
+ "defaultClientScopes": [
+ "web-origins",
+ "acr",
+ "profile",
+ "roles",
+ "email"
+ ],
+ "optionalClientScopes": [
+ "address",
+ "phone",
+ "offline_access",
+ "microprofile-jwt"
+ ]
+ }
+ ]
+
+ changed = False
+
+ set_module_args(module_args)
+
+ # Run the module
+
+ with mock_good_connection():
+ with patch_keycloak_api(get_realm_role=return_value_present, update_realm_role=return_value_updated,
+ get_client_by_id=return_get_client_by_client_id,
+ get_role_composites=return_get_role_composites) \
+ as (mock_get_realm_role, mock_create_realm_role, mock_update_realm_role, mock_delete_realm_role,
+ mock_get_client_role, mock_create_client_role, mock_update_client_role, mock_delete_client_role,
+ mock_get_client_by_client_id, mock_get_role_composites):
+ with self.assertRaises(AnsibleExitJson) as exec_info:
+ self.module.main()
+
+ self.assertEqual(len(mock_get_realm_role.mock_calls), 1)
+ self.assertEqual(len(mock_create_realm_role.mock_calls), 0)
+ self.assertEqual(len(mock_update_realm_role.mock_calls), 0)
+ self.assertEqual(len(mock_get_client_by_client_id.mock_calls), 1)
+ self.assertEqual(len(mock_get_role_composites.mock_calls), 1)
+
+ # Verify that the module's changed status matches what is expected
+ self.assertIs(exec_info.exception.args[0]['changed'], changed)
+
def test_delete_when_absent(self):
"""Remove an absent realm role"""
@@ -268,7 +418,9 @@ class TestKeycloakRealmRole(ModuleTestCase):
with mock_good_connection():
with patch_keycloak_api(get_realm_role=return_value_absent, delete_realm_role=return_value_deleted) \
- as (mock_get_realm_role, mock_create_realm_role, mock_update_realm_role, mock_delete_realm_role):
+ as (mock_get_realm_role, mock_create_realm_role, mock_update_realm_role, mock_delete_realm_role,
+ mock_get_client_role, mock_create_client_role, mock_update_client_role, mock_delete_client_role,
+ mock_get_client_by_client_id, mock_get_role_composites):
with self.assertRaises(AnsibleExitJson) as exec_info:
self.module.main()
@@ -312,7 +464,9 @@ class TestKeycloakRealmRole(ModuleTestCase):
with mock_good_connection():
with patch_keycloak_api(get_realm_role=return_value_absent, delete_realm_role=return_value_deleted) \
- as (mock_get_realm_role, mock_create_realm_role, mock_update_realm_role, mock_delete_realm_role):
+ as (mock_get_realm_role, mock_create_realm_role, mock_update_realm_role, mock_delete_realm_role,
+ mock_get_client_role, mock_create_client_role, mock_update_client_role, mock_delete_client_role,
+ mock_get_client_by_client_id, mock_get_role_composites):
with self.assertRaises(AnsibleExitJson) as exec_info:
self.module.main()
@@ -323,5 +477,207 @@ class TestKeycloakRealmRole(ModuleTestCase):
self.assertIs(exec_info.exception.args[0]['changed'], changed)
+class TestKeycloakClientRole(ModuleTestCase):
+ def setUp(self):
+ super(TestKeycloakClientRole, self).setUp()
+ self.module = keycloak_role
+
+ def test_create_client_role_with_composites_when_absent(self):
+ """Update with change a realm role"""
+
+ module_args = {
+ 'auth_keycloak_url': 'http://keycloak.url/auth',
+ 'auth_password': 'admin',
+ 'auth_realm': 'master',
+ 'auth_username': 'admin',
+ 'auth_client_id': 'admin-cli',
+ 'validate_certs': True,
+ 'realm': 'realm-name',
+ 'client_id': 'client-name',
+ 'name': 'role-name',
+ 'description': 'role-description',
+ 'composite': True,
+ 'composites': [
+ {
+ 'client_id': 'client_1',
+ 'name': 'client-role1'
+ },
+ {
+ 'name': 'realm-role-1'
+ }
+ ]
+ }
+ return_get_client_role = [
+ None,
+ {
+ "attributes": {},
+ "clientRole": True,
+ "composite": True,
+ "composites": [
+ {
+ 'client': {
+ 'client1': ['client-role1']
+ }
+ },
+ {
+ 'realm': ['realm-role-1']
+ }
+ ],
+ "containerId": "9ae25ec2-f40a-11ed-9261-b3bacf720f69",
+ "description": "role-description",
+ "id": "90f1cdb6-be88-496e-89c6-da1fb6bc6966",
+ "name": "role-name",
+ }
+ ]
+ changed = True
+
+ set_module_args(module_args)
+
+ # Run the module
+
+ with mock_good_connection():
+ with patch_keycloak_api(get_client_role=return_get_client_role) \
+ as (mock_get_realm_role, mock_create_realm_role, mock_update_realm_role, mock_delete_realm_role,
+ mock_get_client_role, mock_create_client_role, mock_update_client_role, mock_delete_client_role,
+ mock_get_client_by_client_id, mock_get_role_composites):
+ with self.assertRaises(AnsibleExitJson) as exec_info:
+ self.module.main()
+
+ self.assertEqual(len(mock_get_realm_role.mock_calls), 0)
+ self.assertEqual(len(mock_create_realm_role.mock_calls), 0)
+ self.assertEqual(len(mock_update_realm_role.mock_calls), 0)
+ self.assertEqual(len(mock_get_client_role.mock_calls), 2)
+ self.assertEqual(len(mock_create_client_role.mock_calls), 1)
+ self.assertEqual(len(mock_update_client_role.mock_calls), 0)
+
+ # Verify that the module's changed status matches what is expected
+ self.assertIs(exec_info.exception.args[0]['changed'], changed)
+
+ def test_create_client_role_with_composites_when_present_no_change(self):
+ """Update with change a realm role"""
+
+ module_args = {
+ 'auth_keycloak_url': 'http://keycloak.url/auth',
+ 'auth_password': 'admin',
+ 'auth_realm': 'master',
+ 'auth_username': 'admin',
+ 'auth_client_id': 'admin-cli',
+ 'validate_certs': True,
+ 'realm': 'realm-name',
+ 'client_id': 'client-name',
+ 'name': 'role-name',
+ 'description': 'role-description',
+ 'composite': True,
+ 'composites': [
+ {
+ 'client_id': 'client_1',
+ 'name': 'client-role1'
+ },
+ {
+ 'name': 'realm-role-1'
+ }
+ ]
+ }
+ return_get_client_role = [
+ {
+ "attributes": {},
+ "clientRole": True,
+ "composite": True,
+ "containerId": "9ae25ec2-f40a-11ed-9261-b3bacf720f69",
+ "description": "role-description",
+ "id": "90f1cdb6-be88-496e-89c6-da1fb6bc6966",
+ "name": "role-name",
+ }
+ ]
+ return_get_role_composites = [
+ [
+ {
+ 'clientRole': True,
+ 'containerId': 'c4367fac-f427-11ed-8e2f-aff070d20f0e',
+ 'name': 'client-role1'
+ },
+ {
+ 'clientRole': False,
+ 'containerId': 'realm-name',
+ 'name': 'realm-role-1'
+ }
+ ]
+ ]
+ return_get_client_by_client_id = [
+ {
+ "id": "de152444-f126-4a7a-8273-4ee1544133ad",
+ "clientId": "client_1",
+ "name": "client_1",
+ "description": "client_1",
+ "surrogateAuthRequired": False,
+ "enabled": True,
+ "alwaysDisplayInConsole": False,
+ "clientAuthenticatorType": "client-secret",
+ "redirectUris": [
+ "http://localhost:8080/*",
+ ],
+ "webOrigins": [
+ "*"
+ ],
+ "notBefore": 0,
+ "bearerOnly": False,
+ "consentRequired": False,
+ "standardFlowEnabled": True,
+ "implicitFlowEnabled": False,
+ "directAccessGrantsEnabled": False,
+ "serviceAccountsEnabled": False,
+ "publicClient": False,
+ "frontchannelLogout": False,
+ "protocol": "openid-connect",
+ "attributes": {
+ "backchannel.logout.session.required": "true",
+ "backchannel.logout.revoke.offline.tokens": "false"
+ },
+ "authenticationFlowBindingOverrides": {},
+ "fullScopeAllowed": True,
+ "nodeReRegistrationTimeout": -1,
+ "defaultClientScopes": [
+ "web-origins",
+ "acr",
+ "profile",
+ "roles",
+ "email"
+ ],
+ "optionalClientScopes": [
+ "address",
+ "phone",
+ "offline_access",
+ "microprofile-jwt"
+ ]
+ }
+ ]
+ changed = False
+
+ set_module_args(module_args)
+
+ # Run the module
+
+ with mock_good_connection():
+ with patch_keycloak_api(get_client_role=return_get_client_role, get_client_by_id=return_get_client_by_client_id,
+ get_role_composites=return_get_role_composites) \
+ as (mock_get_realm_role, mock_create_realm_role, mock_update_realm_role, mock_delete_realm_role,
+ mock_get_client_role, mock_create_client_role, mock_update_client_role, mock_delete_client_role,
+ mock_get_client_by_client_id, mock_get_role_composites):
+ with self.assertRaises(AnsibleExitJson) as exec_info:
+ self.module.main()
+
+ self.assertEqual(len(mock_get_realm_role.mock_calls), 0)
+ self.assertEqual(len(mock_create_realm_role.mock_calls), 0)
+ self.assertEqual(len(mock_update_realm_role.mock_calls), 0)
+ self.assertEqual(len(mock_get_client_role.mock_calls), 1)
+ self.assertEqual(len(mock_create_client_role.mock_calls), 0)
+ self.assertEqual(len(mock_update_client_role.mock_calls), 0)
+ self.assertEqual(len(mock_get_client_by_client_id.mock_calls), 1)
+ self.assertEqual(len(mock_get_role_composites.mock_calls), 1)
+
+ # Verify that the module's changed status matches what is expected
+ self.assertIs(exec_info.exception.args[0]['changed'], changed)
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_keycloak_user.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_keycloak_user.py
new file mode 100644
index 000000000..26bc33d82
--- /dev/null
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_keycloak_user.py
@@ -0,0 +1,354 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2021, Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+from contextlib import contextmanager
+
+from ansible_collections.community.general.tests.unit.compat import unittest
+from ansible_collections.community.general.tests.unit.compat.mock import patch
+from ansible_collections.community.general.tests.unit.plugins.modules.utils import AnsibleExitJson, ModuleTestCase, set_module_args
+
+from ansible_collections.community.general.plugins.modules import keycloak_user
+
+from itertools import count
+
+from ansible.module_utils.six import StringIO
+
+
+@contextmanager
+def patch_keycloak_api(get_user_by_username=None,
+ create_user=None,
+ update_user_groups_membership=None,
+ get_user_groups=None,
+ delete_user=None,
+ update_user=None):
+ """Mock context manager for patching the methods in KeycloakAPI that contact the Keycloak server
+
+ Patches the `get_user_by_username` and `create_user` methods
+
+ """
+
+ obj = keycloak_user.KeycloakAPI
+ with patch.object(obj, 'get_user_by_username', side_effect=get_user_by_username) as mock_get_user_by_username:
+ with patch.object(obj, 'create_user', side_effect=create_user) as mock_create_user:
+ with patch.object(obj, 'update_user_groups_membership', side_effect=update_user_groups_membership) as mock_update_user_groups_membership:
+ with patch.object(obj, 'get_user_groups', side_effect=get_user_groups) as mock_get_user_groups:
+ with patch.object(obj, 'delete_user', side_effect=delete_user) as mock_delete_user:
+ with patch.object(obj, 'update_user', side_effect=update_user) as mock_update_user:
+ yield mock_get_user_by_username, mock_create_user, mock_update_user_groups_membership, \
+ mock_get_user_groups, mock_delete_user, mock_update_user
+
+
+def get_response(object_with_future_response, method, get_id_call_count):
+ if callable(object_with_future_response):
+ return object_with_future_response()
+ if isinstance(object_with_future_response, dict):
+ return get_response(
+ object_with_future_response[method], method, get_id_call_count)
+ if isinstance(object_with_future_response, list):
+ call_number = next(get_id_call_count)
+ return get_response(
+ object_with_future_response[call_number], method, get_id_call_count)
+ return object_with_future_response
+
+
+def build_mocked_request(get_id_user_count, response_dict):
+ def _mocked_requests(*args, **kwargs):
+ url = args[0]
+ method = kwargs['method']
+ future_response = response_dict.get(url, None)
+ return get_response(future_response, method, get_id_user_count)
+
+ return _mocked_requests
+
+
+def create_wrapper(text_as_string):
+ """Allow to mock many times a call to one address.
+ Without this function, the StringIO is empty for the second call.
+ """
+
+ def _create_wrapper():
+ return StringIO(text_as_string)
+
+ return _create_wrapper
+
+
+def mock_good_connection():
+ token_response = {
+ 'http://keycloak.url/auth/realms/master/protocol/openid-connect/token': create_wrapper(
+ '{"access_token": "alongtoken"}'), }
+ return patch(
+ 'ansible_collections.community.general.plugins.module_utils.identity.keycloak.keycloak.open_url',
+ side_effect=build_mocked_request(count(), token_response),
+ autospec=True
+ )
+
+
+class TestKeycloakUser(ModuleTestCase):
+ def setUp(self):
+ super(TestKeycloakUser, self).setUp()
+ self.module = keycloak_user
+
+ def test_add_new_user(self):
+ """Add a new user"""
+
+ module_args = {
+ 'auth_keycloak_url': 'https: // auth.example.com / auth',
+ 'token': '{{ access_token }}',
+ 'state': 'present',
+ 'realm': 'master',
+ 'username': 'test',
+ 'groups': []
+ }
+ return_value_get_user_by_username = [None]
+ return_value_update_user_groups_membership = [False]
+ return_get_user_groups = [[]]
+ return_create_user = [{'id': '123eqwdawer24qwdqw4'}]
+ return_delete_user = None
+ return_update_user = None
+ changed = True
+
+ set_module_args(module_args)
+
+ # Run the module
+
+ with mock_good_connection():
+ with patch_keycloak_api(get_user_by_username=return_value_get_user_by_username,
+ create_user=return_create_user,
+ update_user_groups_membership=return_value_update_user_groups_membership,
+ get_user_groups=return_get_user_groups,
+ update_user=return_update_user,
+ delete_user=return_delete_user) \
+ as (mock_get_user_by_username,
+ mock_create_user,
+ mock_update_user_groups_membership,
+ mock_get_user_groups,
+ mock_delete_user,
+ mock_update_user):
+ with self.assertRaises(AnsibleExitJson) as exec_info:
+ self.module.main()
+
+ self.assertEqual(mock_get_user_by_username.call_count, 1)
+ self.assertEqual(mock_create_user.call_count, 1)
+ self.assertEqual(mock_update_user_groups_membership.call_count, 1)
+ self.assertEqual(mock_get_user_groups.call_count, 1)
+ self.assertEqual(mock_update_user.call_count, 0)
+ self.assertEqual(mock_delete_user.call_count, 0)
+
+ # Verify that the module's changed status matches what is expected
+ self.assertIs(exec_info.exception.args[0]['changed'], changed)
+
+ def test_add_exiting_user_no_change(self):
+ """Add a new user"""
+
+ module_args = {
+ 'auth_keycloak_url': 'https: // auth.example.com / auth',
+ 'token': '{{ access_token }}',
+ 'state': 'present',
+ 'realm': 'master',
+ 'username': 'test',
+ 'groups': []
+ }
+ return_value_get_user_by_username = [
+ {
+ 'id': '123eqwdawer24qwdqw4',
+ 'username': 'test',
+ 'groups': [],
+ 'enabled': True,
+ 'emailVerified': False,
+ 'disableableCredentialTypes': [],
+ 'requiredActions': [],
+ 'credentials': [],
+ 'federatedIdentities': [],
+ 'clientConsents': []
+ }
+ ]
+ return_value_update_user_groups_membership = [False]
+ return_get_user_groups = [[]]
+ return_create_user = None
+ return_delete_user = None
+ return_update_user = None
+ changed = False
+
+ set_module_args(module_args)
+
+ # Run the module
+
+ with mock_good_connection():
+ with patch_keycloak_api(get_user_by_username=return_value_get_user_by_username,
+ create_user=return_create_user,
+ update_user_groups_membership=return_value_update_user_groups_membership,
+ get_user_groups=return_get_user_groups,
+ update_user=return_update_user,
+ delete_user=return_delete_user) \
+ as (mock_get_user_by_username,
+ mock_create_user,
+ mock_update_user_groups_membership,
+ mock_get_user_groups,
+ mock_delete_user,
+ mock_update_user):
+ with self.assertRaises(AnsibleExitJson) as exec_info:
+ self.module.main()
+
+ self.assertEqual(mock_get_user_by_username.call_count, 1)
+ self.assertEqual(mock_create_user.call_count, 0)
+ self.assertEqual(mock_update_user_groups_membership.call_count, 1)
+ self.assertEqual(mock_get_user_groups.call_count, 1)
+ self.assertEqual(mock_update_user.call_count, 0)
+ self.assertEqual(mock_delete_user.call_count, 0)
+
+ # Verify that the module's changed status matches what is expected
+ self.assertIs(exec_info.exception.args[0]['changed'], changed)
+
+ def test_update_user_with_group_changes(self):
+ """Update groups for a user"""
+
+ module_args = {
+ 'auth_keycloak_url': 'https: // auth.example.com / auth',
+ 'token': '{{ access_token }}',
+ 'state': 'present',
+ 'realm': 'master',
+ 'username': 'test',
+ 'first_name': 'test',
+ 'last_name': 'user',
+ 'groups': [{
+ 'name': 'group1',
+ 'state': 'present'
+ }]
+ }
+ return_value_get_user_by_username = [
+ {
+ 'id': '123eqwdawer24qwdqw4',
+ 'username': 'test',
+ 'groups': [],
+ 'enabled': True,
+ 'emailVerified': False,
+ 'disableableCredentialTypes': [],
+ 'requiredActions': [],
+ 'credentials': [],
+ 'federatedIdentities': [],
+ 'clientConsents': []
+ }
+ ]
+ return_value_update_user_groups_membership = [True]
+ return_get_user_groups = [['group1']]
+ return_create_user = None
+ return_delete_user = None
+ return_update_user = [
+ {
+ 'id': '123eqwdawer24qwdqw4',
+ 'username': 'test',
+ 'first_name': 'test',
+ 'last_name': 'user',
+ 'enabled': True,
+ 'emailVerified': False,
+ 'disableableCredentialTypes': [],
+ 'requiredActions': [],
+ 'credentials': [],
+ 'federatedIdentities': [],
+ 'clientConsents': []
+ }
+ ]
+ changed = True
+
+ set_module_args(module_args)
+
+ # Run the module
+
+ with mock_good_connection():
+ with patch_keycloak_api(get_user_by_username=return_value_get_user_by_username,
+ create_user=return_create_user,
+ update_user_groups_membership=return_value_update_user_groups_membership,
+ get_user_groups=return_get_user_groups,
+ update_user=return_update_user,
+ delete_user=return_delete_user) \
+ as (mock_get_user_by_username,
+ mock_create_user,
+ mock_update_user_groups_membership,
+ mock_get_user_groups,
+ mock_delete_user,
+ mock_update_user):
+ with self.assertRaises(AnsibleExitJson) as exec_info:
+ self.module.main()
+
+ self.assertEqual(mock_get_user_by_username.call_count, 1)
+ self.assertEqual(mock_create_user.call_count, 0)
+ self.assertEqual(mock_update_user_groups_membership.call_count, 1)
+ self.assertEqual(mock_get_user_groups.call_count, 1)
+ self.assertEqual(mock_update_user.call_count, 1)
+ self.assertEqual(mock_delete_user.call_count, 0)
+
+ # Verify that the module's changed status matches what is expected
+ self.assertIs(exec_info.exception.args[0]['changed'], changed)
+
+ def test_delete_user(self):
+ """Delete a user"""
+
+ module_args = {
+ 'auth_keycloak_url': 'https: // auth.example.com / auth',
+ 'token': '{{ access_token }}',
+ 'state': 'absent',
+ 'realm': 'master',
+ 'username': 'test',
+ 'groups': []
+ }
+ return_value_get_user_by_username = [
+ {
+ 'id': '123eqwdawer24qwdqw4',
+ 'username': 'test',
+ 'groups': [],
+ 'enabled': True,
+ 'emailVerified': False,
+ 'disableableCredentialTypes': [],
+ 'requiredActions': [],
+ 'credentials': [],
+ 'federatedIdentities': [],
+ 'clientConsents': []
+ }
+ ]
+ return_value_update_user_groups_membership = None
+ return_get_user_groups = None
+ return_create_user = None
+ return_delete_user = None
+ return_update_user = None
+ changed = True
+
+ set_module_args(module_args)
+
+ # Run the module
+
+ with mock_good_connection():
+ with patch_keycloak_api(get_user_by_username=return_value_get_user_by_username,
+ create_user=return_create_user,
+ update_user_groups_membership=return_value_update_user_groups_membership,
+ get_user_groups=return_get_user_groups,
+ update_user=return_update_user,
+ delete_user=return_delete_user) \
+ as (mock_get_user_by_username,
+ mock_create_user,
+ mock_update_user_groups_membership,
+ mock_get_user_groups,
+ mock_delete_user,
+ mock_update_user):
+ with self.assertRaises(AnsibleExitJson) as exec_info:
+ self.module.main()
+
+ self.assertEqual(mock_get_user_by_username.call_count, 1)
+ self.assertEqual(mock_create_user.call_count, 0)
+ self.assertEqual(mock_update_user_groups_membership.call_count, 0)
+ self.assertEqual(mock_get_user_groups.call_count, 0)
+ self.assertEqual(mock_update_user.call_count, 0)
+ self.assertEqual(mock_delete_user.call_count, 1)
+
+ # Verify that the module's changed status matches what is expected
+ self.assertIs(exec_info.exception.args[0]['changed'], changed)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_keycloak_user_federation.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_keycloak_user_federation.py
index 8d3dcaa23..523ef9f21 100644
--- a/ansible_collections/community/general/tests/unit/plugins/modules/test_keycloak_user_federation.py
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_keycloak_user_federation.py
@@ -326,6 +326,7 @@ class TestKeycloakUserFederation(ModuleTestCase):
'connectionPooling': True,
'pagination': True,
'allowKerberosAuthentication': False,
+ 'krbPrincipalAttribute': 'krbPrincipalName',
'debug': False,
'useKerberosForPasswordAuthentication': False,
},
@@ -374,6 +375,9 @@ class TestKeycloakUserFederation(ModuleTestCase):
"enabled": [
"true"
],
+ "krbPrincipalAttribute": [
+ "krb5PrincipalName"
+ ],
"usernameLDAPAttribute": [
"uid"
],
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_lvg_rename.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_lvg_rename.py
new file mode 100644
index 000000000..0f2fcb7fa
--- /dev/null
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_lvg_rename.py
@@ -0,0 +1,160 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) Contributors to the Ansible project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+from ansible_collections.community.general.plugins.modules import lvg_rename
+from ansible_collections.community.general.tests.unit.compat.mock import patch
+from ansible_collections.community.general.tests.unit.plugins.modules.utils import (
+ AnsibleFailJson, AnsibleExitJson, ModuleTestCase, set_module_args)
+
+
+VGS_OUTPUT = '''\
+vg_data_testhost1;XKZ5gn-YhWY-NlrT-QCFN-qmMG-VGT9-7uOmex
+vg_sys_testhost2;xgy2SJ-YlYd-fde2-e3oG-zdXL-0xGf-ihqG2H
+'''
+
+
+class TestLvgRename(ModuleTestCase):
+ """Tests for lvg_rename internals"""
+ module = lvg_rename
+ module_path = 'ansible_collections.community.general.plugins.modules.lvg_rename'
+
+ def setUp(self):
+ """Prepare mocks for module testing"""
+ super(TestLvgRename, self).setUp()
+
+ self.mock_run_responses = {}
+
+ patched_module_get_bin_path = patch('%s.AnsibleModule.get_bin_path' % (self.module_path))
+ self.mock_module_get_bin_path = patched_module_get_bin_path.start()
+ self.mock_module_get_bin_path.return_value = '/mocpath'
+ self.addCleanup(patched_module_get_bin_path.stop)
+
+ patched_module_run_command = patch('%s.AnsibleModule.run_command' % (self.module_path))
+ self.mock_module_run_command = patched_module_run_command.start()
+ self.addCleanup(patched_module_run_command.stop)
+
+ def test_vg_not_found_by_name(self):
+ """When the VG by the specified by vg name not found, the module should exit with error"""
+ failed = True
+ self.mock_module_run_command.side_effect = [(0, VGS_OUTPUT, '')]
+ expected_msg = 'Both current (vg_missing) and new (vg_data_testhost2) VG are missing.'
+
+ module_args = {
+ 'vg': 'vg_missing',
+ 'vg_new': 'vg_data_testhost2',
+ }
+ set_module_args(args=module_args)
+
+ with self.assertRaises(AnsibleFailJson) as result:
+ self.module.main()
+
+ self.assertEqual(len(self.mock_module_run_command.mock_calls), 1)
+ self.assertIs(result.exception.args[0]['failed'], failed)
+ self.assertEqual(result.exception.args[0]['msg'], expected_msg)
+
+ def test_vg_not_found_by_uuid(self):
+ """When the VG by the specified vg UUID not found, the module should exit with error"""
+ failed = True
+ self.mock_module_run_command.side_effect = [(0, VGS_OUTPUT, '')]
+ expected_msg = 'Both current (Yfj4YG-c8nI-z7w5-B7Fw-i2eM-HqlF-ApFVp0) and new (vg_data_testhost2) VG are missing.'
+
+ module_args = {
+ 'vg': 'Yfj4YG-c8nI-z7w5-B7Fw-i2eM-HqlF-ApFVp0',
+ 'vg_new': 'vg_data_testhost2',
+ }
+ set_module_args(args=module_args)
+
+ with self.assertRaises(AnsibleFailJson) as result:
+ self.module.main()
+
+ self.assertEqual(len(self.mock_module_run_command.mock_calls), 1)
+ self.assertIs(result.exception.args[0]['failed'], failed)
+ self.assertEqual(result.exception.args[0]['msg'], expected_msg)
+
+ def test_vg_and_vg_new_both_exists(self):
+ """When a VG found for both vg and vg_new options, the module should exit with error"""
+ failed = True
+ self.mock_module_run_command.side_effect = [(0, VGS_OUTPUT, '')]
+ expected_msg = 'The new VG name (vg_sys_testhost2) is already in use.'
+
+ module_args = {
+ 'vg': 'vg_data_testhost1',
+ 'vg_new': 'vg_sys_testhost2',
+ }
+ set_module_args(args=module_args)
+
+ with self.assertRaises(AnsibleFailJson) as result:
+ self.module.main()
+
+ self.assertEqual(len(self.mock_module_run_command.mock_calls), 1)
+ self.assertIs(result.exception.args[0]['failed'], failed)
+ self.assertEqual(result.exception.args[0]['msg'], expected_msg)
+
+ def test_vg_needs_renaming(self):
+ """When the VG found for vg option and there is no VG for vg_new option,
+ the module should call vgrename"""
+ changed = True
+ self.mock_module_run_command.side_effect = [
+ (0, VGS_OUTPUT, ''),
+ (0, ' Volume group "vg_data_testhost1" successfully renamed to "vg_data_testhost2"', '')
+ ]
+ expected_msg = ' Volume group "vg_data_testhost1" successfully renamed to "vg_data_testhost2"'
+
+ module_args = {
+ 'vg': '/dev/vg_data_testhost1',
+ 'vg_new': 'vg_data_testhost2',
+ }
+ set_module_args(args=module_args)
+
+ with self.assertRaises(AnsibleExitJson) as result:
+ self.module.main()
+
+ self.assertEqual(len(self.mock_module_run_command.mock_calls), 2)
+ self.assertIs(result.exception.args[0]['changed'], changed)
+ self.assertEqual(result.exception.args[0]['msg'], expected_msg)
+
+ def test_vg_needs_renaming_in_check_mode(self):
+ """When running in check mode and the VG found for vg option and there is no VG for vg_new option,
+ the module should not call vgrename"""
+ changed = True
+ self.mock_module_run_command.side_effect = [(0, VGS_OUTPUT, '')]
+ expected_msg = 'Running in check mode. The module would rename VG /dev/vg_data_testhost1 to vg_data_testhost2.'
+
+ module_args = {
+ 'vg': '/dev/vg_data_testhost1',
+ 'vg_new': 'vg_data_testhost2',
+ '_ansible_check_mode': True,
+ }
+ set_module_args(args=module_args)
+
+ with self.assertRaises(AnsibleExitJson) as result:
+ self.module.main()
+
+ self.assertEqual(len(self.mock_module_run_command.mock_calls), 1)
+ self.assertIs(result.exception.args[0]['changed'], changed)
+ self.assertEqual(result.exception.args[0]['msg'], expected_msg)
+
+ def test_vg_needs_no_renaming(self):
+ """When the VG not found for vg option and the VG found for vg_new option,
+ the module should not call vgrename"""
+ changed = False
+ self.mock_module_run_command.side_effect = [(0, VGS_OUTPUT, '')]
+ expected_msg = 'The new VG (vg_data_testhost1) already exists, nothing to do.'
+
+ module_args = {
+ 'vg': 'vg_data_testhostX',
+ 'vg_new': 'vg_data_testhost1',
+ }
+ set_module_args(args=module_args)
+
+ with self.assertRaises(AnsibleExitJson) as result:
+ self.module.main()
+
+ self.assertEqual(len(self.mock_module_run_command.mock_calls), 1)
+ self.assertIs(result.exception.args[0]['changed'], changed)
+ self.assertEqual(result.exception.args[0]['msg'], expected_msg)
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_modprobe.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_modprobe.py
index 18695695a..2ad083151 100644
--- a/ansible_collections/community/general/tests/unit/plugins/modules/test_modprobe.py
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_modprobe.py
@@ -152,7 +152,7 @@ class TestUnloadModule(ModuleTestCase):
class TestModuleIsLoadedPersistently(ModuleTestCase):
def setUp(self):
if (sys.version_info[0] == 3 and sys.version_info[1] < 7) or (sys.version_info[0] == 2 and sys.version_info[1] < 7):
- self.skipTest('open_mock doesnt support readline in earlier python versions')
+ self.skipTest("open_mock doesn't support readline in earlier python versions")
super(TestModuleIsLoadedPersistently, self).setUp()
@@ -230,7 +230,7 @@ class TestModuleIsLoadedPersistently(ModuleTestCase):
class TestPermanentParams(ModuleTestCase):
def setUp(self):
if (sys.version_info[0] == 3 and sys.version_info[1] < 7) or (sys.version_info[0] == 2 and sys.version_info[1] < 7):
- self.skipTest('open_mock doesnt support readline in earlier python versions')
+ self.skipTest("open_mock doesn't support readline in earlier python versions")
super(TestPermanentParams, self).setUp()
self.mock_get_bin_path = patch('ansible.module_utils.basic.AnsibleModule.get_bin_path')
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_nmcli.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_nmcli.py
index efd8284a3..8c9c007ac 100644
--- a/ansible_collections/community/general/tests/unit/plugins/modules/test_nmcli.py
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_nmcli.py
@@ -118,6 +118,12 @@ TESTCASE_CONNECTION = [
'state': 'absent',
'_ansible_check_mode': True,
},
+ {
+ 'type': 'loopback',
+ 'conn_name': 'non_existent_nw_device',
+ 'state': 'absent',
+ '_ansible_check_mode': True,
+ },
]
TESTCASE_GENERIC = [
@@ -262,6 +268,25 @@ ipv4.routes: { ip = 192.168.200.0/24, nh = 192.168.1.
ipv4.route-metric: 10
"""
+TESTCASE_ETHERNET_MOD_IPV4_INT_WITH_ROUTE_AND_METRIC_CLEAR = [
+ {
+ 'type': 'ethernet',
+ 'conn_name': 'non_existent_nw_device',
+ 'routes4': [],
+ 'state': 'present',
+ '_ansible_check_mode': False,
+ '_ansible_diff': True,
+ },
+ {
+ 'type': 'ethernet',
+ 'conn_name': 'non_existent_nw_device',
+ 'routes4_extended': [],
+ 'state': 'present',
+ '_ansible_check_mode': False,
+ '_ansible_diff': True,
+ },
+]
+
TESTCASE_ETHERNET_MOD_IPV6_INT_WITH_ROUTE_AND_METRIC = [
{
'type': 'ethernet',
@@ -453,6 +478,38 @@ ipv6.ignore-auto-dns: no
ipv6.ignore-auto-routes: no
"""
+TESTCASE_GENERIC_DNS4_OPTIONS = [
+ {
+ 'type': 'generic',
+ 'conn_name': 'non_existent_nw_device',
+ 'ifname': 'generic_non_existant',
+ 'ip4': '10.10.10.10/24',
+ 'gw4': '10.10.10.1',
+ 'state': 'present',
+ 'dns4_options': [],
+ 'dns6_options': [],
+ '_ansible_check_mode': False,
+ }
+]
+
+TESTCASE_GENERIC_DNS4_OPTIONS_SHOW_OUTPUT = """\
+connection.id: non_existent_nw_device
+connection.interface-name: generic_non_existant
+connection.autoconnect: yes
+ipv4.method: manual
+ipv4.addresses: 10.10.10.10/24
+ipv4.gateway: 10.10.10.1
+ipv4.ignore-auto-dns: no
+ipv4.ignore-auto-routes: no
+ipv4.never-default: no
+ipv4.dns-options: --
+ipv4.may-fail: yes
+ipv6.dns-options: --
+ipv6.method: auto
+ipv6.ignore-auto-dns: no
+ipv6.ignore-auto-routes: no
+"""
+
TESTCASE_GENERIC_ZONE = [
{
'type': 'generic',
@@ -569,6 +626,7 @@ TESTCASE_BRIDGE_SLAVE = [
'type': 'bridge-slave',
'conn_name': 'non_existent_nw_device',
'ifname': 'br0_non_existant',
+ 'hairpin': True,
'path_cost': 100,
'state': 'present',
'_ansible_check_mode': False,
@@ -892,6 +950,28 @@ TESTCASE_ETHERNET_STATIC = [
}
]
+TESTCASE_LOOPBACK = [
+ {
+ 'type': 'loopback',
+ 'conn_name': 'lo',
+ 'ifname': 'lo',
+ 'ip4': '127.0.0.1/8',
+ 'state': 'present',
+ '_ansible_check_mode': False,
+ }
+]
+
+TESTCASE_LOOPBACK_MODIFY = [
+ {
+ 'type': 'loopback',
+ 'conn_name': 'lo',
+ 'ifname': 'lo',
+ 'ip4': ['127.0.0.1/8', '127.0.0.2/8'],
+ 'state': 'present',
+ '_ansible_check_mode': False,
+ }
+]
+
TESTCASE_ETHERNET_STATIC_SHOW_OUTPUT = """\
connection.id: non_existent_nw_device
connection.interface-name: ethernet_non_existant
@@ -910,6 +990,21 @@ ipv6.ignore-auto-dns: no
ipv6.ignore-auto-routes: no
"""
+TESTCASE_LOOPBACK_SHOW_OUTPUT = """\
+connection.id: lo
+connection.interface-name: lo
+connection.autoconnect: yes
+ipv4.method: manual
+ipv4.addresses: 127.0.0.1/8
+ipv4.ignore-auto-dns: no
+ipv4.ignore-auto-routes: no
+ipv4.never-default: no
+ipv4.may-fail: yes
+ipv6.method: manual
+ipv6.ignore-auto-dns: no
+ipv6.ignore-auto-routes: no
+"""
+
TESTCASE_ETHERNET_STATIC_MULTIPLE_IP4_ADDRESSES = [
{
'type': 'ethernet',
@@ -1393,7 +1488,8 @@ ipv4.may-fail: yes
ipv6.method: auto
ipv6.ignore-auto-dns: no
ipv6.ignore-auto-routes: no
-infiniband.transport-mode datagram
+infiniband.mtu: auto
+infiniband.transport-mode: datagram
"""
TESTCASE_INFINIBAND_STATIC_MODIFY_TRANSPORT_MODE = [
@@ -1514,6 +1610,13 @@ def mocked_generic_connection_dns_search_unchanged(mocker):
@pytest.fixture
+def mocked_generic_connection_dns_options_unchanged(mocker):
+ mocker_set(mocker,
+ connection_exists=True,
+ execute_return=(0, TESTCASE_GENERIC_DNS4_OPTIONS_SHOW_OUTPUT, ""))
+
+
+@pytest.fixture
def mocked_generic_connection_zone_unchanged(mocker):
mocker_set(mocker,
connection_exists=True,
@@ -1672,6 +1775,17 @@ def mocked_ethernet_connection_with_ipv4_static_address_static_route_metric_modi
@pytest.fixture
+def mocked_ethernet_connection_with_ipv4_static_address_static_route_metric_clear(mocker):
+ mocker_set(mocker,
+ connection_exists=True,
+ execute_return=None,
+ execute_side_effect=(
+ (0, TESTCASE_ETHERNET_MOD_IPV4_INT_WITH_ROUTE_AND_METRIC_SHOW_OUTPUT, ""),
+ (0, "", ""),
+ ))
+
+
+@pytest.fixture
def mocked_ethernet_connection_with_ipv6_static_address_static_route_metric_modify(mocker):
mocker_set(mocker,
connection_exists=True,
@@ -1875,6 +1989,24 @@ def mocked_generic_connection_diff_check(mocker):
execute_return=(0, TESTCASE_GENERIC_SHOW_OUTPUT, ""))
+@pytest.fixture
+def mocked_loopback_connection_unchanged(mocker):
+ mocker_set(mocker,
+ connection_exists=True,
+ execute_return=(0, TESTCASE_LOOPBACK_SHOW_OUTPUT, ""))
+
+
+@pytest.fixture
+def mocked_loopback_connection_modify(mocker):
+ mocker_set(mocker,
+ connection_exists=True,
+ execute_return=None,
+ execute_side_effect=(
+ (0, TESTCASE_LOOPBACK_SHOW_OUTPUT, ""),
+ (0, "", ""),
+ ))
+
+
@pytest.mark.parametrize('patch_ansible_module', TESTCASE_BOND, indirect=['patch_ansible_module'])
def test_bond_connection_create(mocked_generic_connection_create, capfd):
"""
@@ -2066,6 +2198,62 @@ def test_generic_connection_dns_search_unchanged(mocked_generic_connection_dns_s
assert not results['changed']
+@pytest.mark.parametrize('patch_ansible_module', TESTCASE_GENERIC_DNS4_OPTIONS, indirect=['patch_ansible_module'])
+def test_generic_connection_create_dns_options(mocked_generic_connection_create, capfd):
+ """
+ Test : Generic connection created with dns options
+ """
+ with pytest.raises(SystemExit):
+ nmcli.main()
+
+ assert nmcli.Nmcli.execute_command.call_count == 1
+ arg_list = nmcli.Nmcli.execute_command.call_args_list
+ args, kwargs = arg_list[0]
+
+ assert 'ipv4.dns-options' in args[0]
+ assert 'ipv6.dns-options' in args[0]
+
+ out, err = capfd.readouterr()
+ results = json.loads(out)
+ assert not results.get('failed')
+ assert results['changed']
+
+
+@pytest.mark.parametrize('patch_ansible_module', TESTCASE_GENERIC_DNS4_OPTIONS, indirect=['patch_ansible_module'])
+def test_generic_connection_modify_dns_options(mocked_generic_connection_create, capfd):
+ """
+ Test : Generic connection modified with dns options
+ """
+ with pytest.raises(SystemExit):
+ nmcli.main()
+
+ assert nmcli.Nmcli.execute_command.call_count == 1
+ arg_list = nmcli.Nmcli.execute_command.call_args_list
+ args, kwargs = arg_list[0]
+
+ assert 'ipv4.dns-options' in args[0]
+ assert 'ipv6.dns-options' in args[0]
+
+ out, err = capfd.readouterr()
+ results = json.loads(out)
+ assert not results.get('failed')
+ assert results['changed']
+
+
+@pytest.mark.parametrize('patch_ansible_module', TESTCASE_GENERIC_DNS4_OPTIONS, indirect=['patch_ansible_module'])
+def test_generic_connection_dns_options_unchanged(mocked_generic_connection_dns_options_unchanged, capfd):
+ """
+ Test : Generic connection with dns options unchanged
+ """
+ with pytest.raises(SystemExit):
+ nmcli.main()
+
+ out, err = capfd.readouterr()
+ results = json.loads(out)
+ assert not results.get('failed')
+ assert not results['changed']
+
+
@pytest.mark.parametrize('patch_ansible_module', TESTCASE_CONNECTION, indirect=['patch_ansible_module'])
def test_dns4_none(mocked_connection_exists, capfd):
"""
@@ -2991,6 +3179,38 @@ def test_ethernet_connection_static_ipv4_address_static_route_with_metric_modify
assert not results.get('failed')
+@pytest.mark.parametrize('patch_ansible_module', TESTCASE_ETHERNET_MOD_IPV4_INT_WITH_ROUTE_AND_METRIC_CLEAR, indirect=['patch_ansible_module'])
+def test_ethernet_connection_static_ipv4_address_static_route_with_metric_clear(
+ mocked_ethernet_connection_with_ipv4_static_address_static_route_metric_clear, capfd):
+ """
+ Test : Modify ethernet connection with static IPv4 address and static route
+ """
+ with pytest.raises(SystemExit):
+ nmcli.main()
+
+ arg_list = nmcli.Nmcli.execute_command.call_args_list
+ add_args, add_kw = arg_list[1]
+
+ assert add_args[0][0] == '/usr/bin/nmcli'
+ assert add_args[0][1] == 'con'
+ assert add_args[0][2] == 'modify'
+ assert add_args[0][3] == 'non_existent_nw_device'
+
+ add_args_text = list(map(to_text, add_args[0]))
+
+ for param in ['ipv4.routes', '']:
+ assert param in add_args_text
+
+ out, err = capfd.readouterr()
+ results = json.loads(out)
+
+ assert 'ipv4.routes' in results['diff']['before']
+ assert 'ipv4.routes' in results['diff']['after']
+
+ assert results.get('changed') is True
+ assert not results.get('failed')
+
+
@pytest.mark.parametrize('patch_ansible_module', TESTCASE_ETHERNET_ADD_IPV6_INT_WITH_ROUTE, indirect=['patch_ansible_module'])
def test_ethernet_connection_static_ipv6_address_static_route_create(mocked_ethernet_connection_with_ipv6_static_address_static_route_create, capfd):
"""
@@ -4032,6 +4252,7 @@ def test_bond_connection_unchanged(mocked_generic_connection_diff_check, capfd):
state=dict(type='str', required=True, choices=['absent', 'present']),
conn_name=dict(type='str', required=True),
master=dict(type='str'),
+ slave_type=dict(type=str, choices=['bond', 'bridge', 'team']),
ifname=dict(type='str'),
type=dict(type='str',
choices=[
@@ -4077,6 +4298,7 @@ def test_bond_connection_unchanged(mocked_generic_connection_diff_check, capfd):
never_default4=dict(type='bool', default=False),
dns4=dict(type='list', elements='str'),
dns4_search=dict(type='list', elements='str'),
+ dns4_options=dict(type='list', elements='str'),
dns4_ignore_auto=dict(type='bool', default=False),
method4=dict(type='str', choices=['auto', 'link-local', 'manual', 'shared', 'disabled']),
may_fail4=dict(type='bool', default=True),
@@ -4086,6 +4308,7 @@ def test_bond_connection_unchanged(mocked_generic_connection_diff_check, capfd):
gw6_ignore_auto=dict(type='bool', default=False),
dns6=dict(type='list', elements='str'),
dns6_search=dict(type='list', elements='str'),
+ dns6_options=dict(type='list', elements='str'),
dns6_ignore_auto=dict(type='bool', default=False),
routes6=dict(type='list', elements='str'),
routes6_extended=dict(type='list',
@@ -4259,3 +4482,366 @@ def test_macvlan_mod(mocked_generic_connection_modify, capfd):
results = json.loads(out)
assert not results.get('failed')
assert results['changed']
+
+
+TESTCASE_SLAVE_TYPE_BRIDGE_CONNECTION = [
+ {
+ 'type': 'ethernet',
+ 'conn_name': 'fake_conn',
+ 'ifname': 'fake_eth0',
+ 'state': 'present',
+ 'slave_type': 'bridge',
+ 'master': 'fake_br0',
+ '_ansible_check_mode': False,
+ }
+]
+
+
+TESTCASE_SLAVE_TYPE_BRIDGE_CONNECTION_SHOW_OUTPUT = """\
+connection.id: fake_conn
+connection.type: 802-3-ethernet
+connection.interface-name: fake_eth0
+connection.autoconnect: yes
+connection.master: --
+connection.slave-type: --
+802-3-ethernet.mtu: auto
+"""
+
+
+TESTCASE_SLAVE_TYPE_BRIDGE_CONNECTION_UNCHANGED_SHOW_OUTPUT = """\
+connection.id: fake_conn
+connection.type: 802-3-ethernet
+connection.interface-name: fake_eth0
+connection.autoconnect: yes
+connection.master: fake_br0
+connection.slave-type: bridge
+802-3-ethernet.mtu: auto
+"""
+
+
+@pytest.fixture
+def mocked_slave_type_bridge_create(mocker):
+ mocker_set(mocker,
+ execute_return=None,
+ execute_side_effect=(
+ (0, TESTCASE_SLAVE_TYPE_BRIDGE_CONNECTION_SHOW_OUTPUT, ""),
+ (0, "", ""),
+ ))
+
+
+@pytest.mark.parametrize('patch_ansible_module', TESTCASE_SLAVE_TYPE_BRIDGE_CONNECTION, indirect=['patch_ansible_module'])
+def test_create_slave_type_bridge(mocked_slave_type_bridge_create, capfd):
+ """
+ Test : slave for bridge created
+ """
+
+ with pytest.raises(SystemExit):
+ nmcli.main()
+
+ assert nmcli.Nmcli.execute_command.call_count == 1
+ arg_list = nmcli.Nmcli.execute_command.call_args_list
+ args, kwargs = arg_list[0]
+
+ assert args[0][0] == '/usr/bin/nmcli'
+ assert args[0][1] == 'con'
+ assert args[0][2] == 'add'
+ assert args[0][3] == 'type'
+ assert args[0][4] == 'ethernet'
+ assert args[0][5] == 'con-name'
+ assert args[0][6] == 'fake_conn'
+ con_master_index = args[0].index('connection.master')
+ slave_type_index = args[0].index('connection.slave-type')
+ assert args[0][con_master_index + 1] == 'fake_br0'
+ assert args[0][slave_type_index + 1] == 'bridge'
+
+ out, err = capfd.readouterr()
+ results = json.loads(out)
+ assert not results.get('failed')
+ assert results['changed']
+
+
+@pytest.fixture
+def mocked_create_slave_type_bridge_unchanged(mocker):
+ mocker_set(mocker,
+ connection_exists=True,
+ execute_return=(0, TESTCASE_SLAVE_TYPE_BRIDGE_CONNECTION_UNCHANGED_SHOW_OUTPUT, ""))
+
+
+@pytest.mark.parametrize('patch_ansible_module', TESTCASE_SLAVE_TYPE_BRIDGE_CONNECTION, indirect=['patch_ansible_module'])
+def test_slave_type_bridge_unchanged(mocked_create_slave_type_bridge_unchanged, capfd):
+ """
+ Test : Existent slave for bridge unchanged
+ """
+ with pytest.raises(SystemExit):
+ nmcli.main()
+
+ out, err = capfd.readouterr()
+ results = json.loads(out)
+ assert not results.get('failed')
+ assert not results['changed']
+
+
+TESTCASE_SLAVE_TYPE_BOND_CONNECTION = [
+ {
+ 'type': 'ethernet',
+ 'conn_name': 'fake_conn',
+ 'ifname': 'fake_eth0',
+ 'state': 'present',
+ 'slave_type': 'bond',
+ 'master': 'fake_bond0',
+ '_ansible_check_mode': False,
+ }
+]
+
+
+TESTCASE_SLAVE_TYPE_BOND_CONNECTION_SHOW_OUTPUT = """\
+connection.id: fake_conn
+connection.type: 802-3-ethernet
+connection.interface-name: fake_eth0
+connection.autoconnect: yes
+connection.master: --
+connection.slave-type: --
+802-3-ethernet.mtu: auto
+"""
+
+
+TESTCASE_SLAVE_TYPE_BOND_CONNECTION_UNCHANGED_SHOW_OUTPUT = """\
+connection.id: fake_conn
+connection.type: 802-3-ethernet
+connection.interface-name: fake_eth0
+connection.autoconnect: yes
+connection.master: fake_bond0
+connection.slave-type: bond
+802-3-ethernet.mtu: auto
+"""
+
+
+@pytest.fixture
+def mocked_slave_type_bond_create(mocker):
+ mocker_set(mocker,
+ execute_return=None,
+ execute_side_effect=(
+ (0, TESTCASE_SLAVE_TYPE_BOND_CONNECTION_SHOW_OUTPUT, ""),
+ (0, "", ""),
+ ))
+
+
+@pytest.mark.parametrize('patch_ansible_module', TESTCASE_SLAVE_TYPE_BOND_CONNECTION, indirect=['patch_ansible_module'])
+def test_create_slave_type_bond(mocked_slave_type_bond_create, capfd):
+ """
+ Test : slave for bond created
+ """
+
+ with pytest.raises(SystemExit):
+ nmcli.main()
+
+ assert nmcli.Nmcli.execute_command.call_count == 1
+ arg_list = nmcli.Nmcli.execute_command.call_args_list
+ args, kwargs = arg_list[0]
+
+ assert args[0][0] == '/usr/bin/nmcli'
+ assert args[0][1] == 'con'
+ assert args[0][2] == 'add'
+ assert args[0][3] == 'type'
+ assert args[0][4] == 'ethernet'
+ assert args[0][5] == 'con-name'
+ assert args[0][6] == 'fake_conn'
+ con_master_index = args[0].index('connection.master')
+ slave_type_index = args[0].index('connection.slave-type')
+ assert args[0][con_master_index + 1] == 'fake_bond0'
+ assert args[0][slave_type_index + 1] == 'bond'
+
+ out, err = capfd.readouterr()
+ results = json.loads(out)
+ assert not results.get('failed')
+ assert results['changed']
+
+
+@pytest.fixture
+def mocked_create_slave_type_bond_unchanged(mocker):
+ mocker_set(mocker,
+ connection_exists=True,
+ execute_return=(0, TESTCASE_SLAVE_TYPE_BOND_CONNECTION_UNCHANGED_SHOW_OUTPUT, ""))
+
+
+@pytest.mark.parametrize('patch_ansible_module', TESTCASE_SLAVE_TYPE_BOND_CONNECTION, indirect=['patch_ansible_module'])
+def test_slave_type_bond_unchanged(mocked_create_slave_type_bond_unchanged, capfd):
+ """
+ Test : Existent slave for bridge unchanged
+ """
+ with pytest.raises(SystemExit):
+ nmcli.main()
+
+ out, err = capfd.readouterr()
+ results = json.loads(out)
+ assert not results.get('failed')
+ assert not results['changed']
+
+
+TESTCASE_SLAVE_TYPE_TEAM_CONNECTION = [
+ {
+ 'type': 'ethernet',
+ 'conn_name': 'fake_conn',
+ 'ifname': 'fake_eth0',
+ 'state': 'present',
+ 'slave_type': 'team',
+ 'master': 'fake_team0',
+ '_ansible_check_mode': False,
+ }
+]
+
+
+TESTCASE_SLAVE_TYPE_TEAM_CONNECTION_SHOW_OUTPUT = """\
+connection.id: fake_conn
+connection.type: 802-3-ethernet
+connection.interface-name: fake_eth0
+connection.autoconnect: yes
+connection.master: --
+connection.slave-type: --
+802-3-ethernet.mtu: auto
+"""
+
+
+TESTCASE_SLAVE_TYPE_TEAM_CONNECTION_UNCHANGED_SHOW_OUTPUT = """\
+connection.id: fake_conn
+connection.type: 802-3-ethernet
+connection.interface-name: fake_eth0
+connection.autoconnect: yes
+connection.master: fake_team0
+connection.slave-type: team
+802-3-ethernet.mtu: auto
+"""
+
+
+@pytest.fixture
+def mocked_slave_type_team_create(mocker):
+ mocker_set(mocker,
+ execute_return=None,
+ execute_side_effect=(
+ (0, TESTCASE_SLAVE_TYPE_TEAM_CONNECTION_SHOW_OUTPUT, ""),
+ (0, "", ""),
+ ))
+
+
+@pytest.mark.parametrize('patch_ansible_module', TESTCASE_SLAVE_TYPE_TEAM_CONNECTION, indirect=['patch_ansible_module'])
+def test_create_slave_type_team(mocked_slave_type_team_create, capfd):
+ """
+ Test : slave for bond created
+ """
+
+ with pytest.raises(SystemExit):
+ nmcli.main()
+
+ assert nmcli.Nmcli.execute_command.call_count == 1
+ arg_list = nmcli.Nmcli.execute_command.call_args_list
+ args, kwargs = arg_list[0]
+
+ assert args[0][0] == '/usr/bin/nmcli'
+ assert args[0][1] == 'con'
+ assert args[0][2] == 'add'
+ assert args[0][3] == 'type'
+ assert args[0][4] == 'ethernet'
+ assert args[0][5] == 'con-name'
+ assert args[0][6] == 'fake_conn'
+ con_master_index = args[0].index('connection.master')
+ slave_type_index = args[0].index('connection.slave-type')
+ assert args[0][con_master_index + 1] == 'fake_team0'
+ assert args[0][slave_type_index + 1] == 'team'
+
+ out, err = capfd.readouterr()
+ results = json.loads(out)
+ assert not results.get('failed')
+ assert results['changed']
+
+
+@pytest.fixture
+def mocked_create_slave_type_team_unchanged(mocker):
+ mocker_set(mocker,
+ connection_exists=True,
+ execute_return=(0, TESTCASE_SLAVE_TYPE_TEAM_CONNECTION_UNCHANGED_SHOW_OUTPUT, ""))
+
+
+@pytest.mark.parametrize('patch_ansible_module', TESTCASE_SLAVE_TYPE_TEAM_CONNECTION, indirect=['patch_ansible_module'])
+def test_slave_type_team_unchanged(mocked_create_slave_type_team_unchanged, capfd):
+ """
+ Test : Existent slave for bridge unchanged
+ """
+ with pytest.raises(SystemExit):
+ nmcli.main()
+
+ out, err = capfd.readouterr()
+ results = json.loads(out)
+ assert not results.get('failed')
+ assert not results['changed']
+
+
+@pytest.mark.parametrize('patch_ansible_module', TESTCASE_LOOPBACK, indirect=['patch_ansible_module'])
+def test_create_loopback(mocked_generic_connection_create, capfd):
+ """
+ Test : Create loopback connection
+ """
+
+ with pytest.raises(SystemExit):
+ nmcli.main()
+
+ assert nmcli.Nmcli.execute_command.call_count == 1
+ arg_list = nmcli.Nmcli.execute_command.call_args_list
+ add_args, add_kw = arg_list[0]
+
+ assert add_args[0][0] == '/usr/bin/nmcli'
+ assert add_args[0][1] == 'con'
+ assert add_args[0][2] == 'add'
+ assert add_args[0][3] == 'type'
+ assert add_args[0][4] == 'loopback'
+ assert add_args[0][5] == 'con-name'
+ assert add_args[0][6] == 'lo'
+
+ add_args_text = list(map(to_text, add_args[0]))
+ for param in ['connection.interface-name', 'lo',
+ 'ipv4.addresses', '127.0.0.1/8']:
+ assert param in add_args_text
+
+ out, err = capfd.readouterr()
+ results = json.loads(out)
+ assert not results.get('failed')
+ assert results['changed']
+
+
+@pytest.mark.parametrize('patch_ansible_module', TESTCASE_LOOPBACK, indirect=['patch_ansible_module'])
+def test_unchanged_loopback(mocked_loopback_connection_unchanged, capfd):
+ """
+ Test : loopback connection unchanged
+ """
+ with pytest.raises(SystemExit):
+ nmcli.main()
+
+ out, err = capfd.readouterr()
+ results = json.loads(out)
+ assert not results.get('failed')
+ assert not results['changed']
+
+
+@pytest.mark.parametrize('patch_ansible_module', TESTCASE_LOOPBACK_MODIFY, indirect=['patch_ansible_module'])
+def test_add_second_ip4_address_to_loopback_connection(mocked_loopback_connection_modify, capfd):
+ """
+ Test : Modify loopback connection
+ """
+ with pytest.raises(SystemExit):
+ nmcli.main()
+
+ assert nmcli.Nmcli.execute_command.call_count == 2
+ arg_list = nmcli.Nmcli.execute_command.call_args_list
+ args, kwargs = arg_list[1]
+
+ assert args[0][0] == '/usr/bin/nmcli'
+ assert args[0][1] == 'con'
+ assert args[0][2] == 'modify'
+ assert args[0][3] == 'lo'
+
+ for param in ['ipv4.addresses', '127.0.0.1/8,127.0.0.2/8']:
+ assert param in args[0]
+
+ out, err = capfd.readouterr()
+ results = json.loads(out)
+ assert not results.get('failed')
+ assert results['changed']
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_nomad_token.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_nomad_token.py
new file mode 100644
index 000000000..48f060f8b
--- /dev/null
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_nomad_token.py
@@ -0,0 +1,222 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2021, Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+import nomad
+from ansible_collections.community.general.plugins.modules import nomad_token
+from ansible_collections.community.general.tests.unit.compat.mock import patch
+from ansible_collections.community.general.tests.unit.plugins.modules.utils import AnsibleExitJson, AnsibleFailJson, \
+ ModuleTestCase, \
+ set_module_args
+
+
+def mock_acl_get_tokens(empty_list=False):
+ response_object = []
+
+ if not empty_list:
+ response_object = [
+ {
+ 'AccessorID': 'bac2b162-2a63-efa2-4e68-55d79dcb7721',
+ 'Name': 'Bootstrap Token', 'Type': 'management',
+ 'Policies': None, 'Roles': None, 'Global': True,
+ 'Hash': 'BUJ3BerTfrqFVm1P+vZr1gz9ubOkd+JAvYjNAJyaU9Y=',
+ 'CreateTime': '2023-11-12T18:44:39.740562185Z',
+ 'ExpirationTime': None,
+ 'CreateIndex': 9,
+ 'ModifyIndex': 9
+ },
+ {
+ 'AccessorID': '0d01c55f-8d63-f832-04ff-1866d4eb594e',
+ 'Name': 'devs',
+ 'Type': 'client', 'Policies': ['readonly'],
+ 'Roles': None,
+ 'Global': True,
+ 'Hash': 'eSn8H8RVqh8As8WQNnC2vlBRqXy6DECogc5umzX0P30=',
+ 'CreateTime': '2023-11-12T18:48:34.248857001Z',
+ 'ExpirationTime': None,
+ 'CreateIndex': 14,
+ 'ModifyIndex': 836
+ }
+ ]
+
+ return response_object
+
+
+def mock_acl_generate_bootstrap():
+ response_object = {
+ 'AccessorID': '0d01c55f-8d63-f832-04ff-1866d4eb594e',
+ 'Name': 'Bootstrap Token',
+ 'Type': 'management',
+ 'Policies': None,
+ 'Roles': None,
+ 'Global': True,
+ 'Hash': 'BUJ3BerTfrqFVm1P+vZr1gz9ubOkd+JAvYjNAJyaU9Y=',
+ 'CreateTime': '2023-11-12T18:48:34.248857001Z',
+ 'ExpirationTime': None,
+ 'ExpirationTTL': '',
+ 'CreateIndex': 14,
+ 'ModifyIndex': 836,
+ 'SecretID': 'd539a03d-337a-8504-6d12-000f861337bc'
+ }
+ return response_object
+
+
+def mock_acl_create_update_token():
+ response_object = {
+ 'AccessorID': '0d01c55f-8d63-f832-04ff-1866d4eb594e',
+ 'Name': 'dev',
+ 'Type': 'client',
+ 'Policies': ['readonly'],
+ 'Roles': None,
+ 'Global': True,
+ 'Hash': 'eSn8H8RVqh8As8WQNnC2vlBRqXy6DECogc5umzX0P30=',
+ 'CreateTime': '2023-11-12T18:48:34.248857001Z',
+ 'ExpirationTime': None,
+ 'ExpirationTTL': '',
+ 'CreateIndex': 14,
+ 'ModifyIndex': 836,
+ 'SecretID': 'd539a03d-337a-8504-6d12-000f861337bc'
+ }
+
+ return response_object
+
+
+def mock_acl_delete_token():
+ return {}
+
+
+class TestNomadTokenModule(ModuleTestCase):
+
+ def setUp(self):
+ super(TestNomadTokenModule, self).setUp()
+ self.module = nomad_token
+
+ def tearDown(self):
+ super(TestNomadTokenModule, self).tearDown()
+
+ def test_should_fail_without_parameters(self):
+ with self.assertRaises(AnsibleFailJson):
+ set_module_args({})
+ self.module.main()
+
+ def test_should_create_token_type_client(self):
+ module_args = {
+ 'host': 'localhost',
+ 'name': 'Dev token',
+ 'token_type': 'client',
+ 'state': 'present'
+ }
+
+ set_module_args(module_args)
+ with patch.object(nomad.api.acl.Acl, 'get_tokens', return_value=mock_acl_get_tokens()) as mock_get_tokens:
+ with patch.object(nomad.api.acl.Acl, 'create_token', return_value=mock_acl_create_update_token()) as \
+ mock_create_update_token:
+ with self.assertRaises(AnsibleExitJson):
+ self.module.main()
+
+ self.assertIs(mock_get_tokens.call_count, 1)
+ self.assertIs(mock_create_update_token.call_count, 1)
+
+ def test_should_create_token_type_bootstrap(self):
+ module_args = {
+ 'host': 'localhost',
+ 'token_type': 'bootstrap',
+ 'state': 'present'
+ }
+
+ set_module_args(module_args)
+
+ with patch.object(nomad.api.acl.Acl, 'get_tokens') as mock_get_tokens:
+ with patch.object(nomad.api.Acl, 'generate_bootstrap') as mock_generate_bootstrap:
+ mock_get_tokens.return_value = mock_acl_get_tokens(empty_list=True)
+ mock_generate_bootstrap.return_value = mock_acl_generate_bootstrap()
+
+ with self.assertRaises(AnsibleExitJson):
+ self.module.main()
+
+ self.assertIs(mock_get_tokens.call_count, 1)
+ self.assertIs(mock_generate_bootstrap.call_count, 1)
+
+ def test_should_fail_delete_without_name_parameter(self):
+ module_args = {
+ 'host': 'localhost',
+ 'state': 'absent'
+ }
+
+ set_module_args(module_args)
+ with patch.object(nomad.api.acl.Acl, 'get_tokens') as mock_get_tokens:
+ with patch.object(nomad.api.acl.Acl, 'delete_token') as mock_delete_token:
+ mock_get_tokens.return_value = mock_acl_get_tokens()
+ mock_delete_token.return_value = mock_acl_delete_token()
+
+ with self.assertRaises(AnsibleFailJson):
+ self.module.main()
+
+ def test_should_fail_delete_bootstrap_token(self):
+ module_args = {
+ 'host': 'localhost',
+ 'token_type': 'boostrap',
+ 'state': 'absent'
+ }
+
+ set_module_args(module_args)
+
+ with self.assertRaises(AnsibleFailJson):
+ self.module.main()
+
+ def test_should_fail_delete_boostrap_token_by_name(self):
+ module_args = {
+ 'host': 'localhost',
+ 'name': 'Bootstrap Token',
+ 'state': 'absent'
+ }
+
+ set_module_args(module_args)
+
+ with self.assertRaises(AnsibleFailJson):
+ self.module.main()
+
+ def test_should_delete_client_token(self):
+ module_args = {
+ 'host': 'localhost',
+ 'name': 'devs',
+ 'state': 'absent'
+ }
+
+ set_module_args(module_args)
+
+ with patch.object(nomad.api.acl.Acl, 'get_tokens') as mock_get_tokens:
+ with patch.object(nomad.api.acl.Acl, 'delete_token') as mock_delete_token:
+ mock_get_tokens.return_value = mock_acl_get_tokens()
+ mock_delete_token.return_value = mock_acl_delete_token()
+
+ with self.assertRaises(AnsibleExitJson):
+ self.module.main()
+
+ self.assertIs(mock_delete_token.call_count, 1)
+
+ def test_should_update_client_token(self):
+ module_args = {
+ 'host': 'localhost',
+ 'name': 'devs',
+ 'token_type': 'client',
+ 'state': 'present'
+ }
+
+ set_module_args(module_args)
+
+ with patch.object(nomad.api.acl.Acl, 'get_tokens') as mock_get_tokens:
+ with patch.object(nomad.api.acl.Acl, 'update_token') as mock_create_update_token:
+ mock_get_tokens.return_value = mock_acl_get_tokens()
+ mock_create_update_token.return_value = mock_acl_create_update_token()
+
+ with self.assertRaises(AnsibleExitJson):
+ self.module.main()
+ self.assertIs(mock_get_tokens.call_count, 1)
+ self.assertIs(mock_create_update_token.call_count, 1)
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_npm.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_npm.py
index f5d312775..cc4d65172 100644
--- a/ansible_collections/community/general/tests/unit/plugins/modules/test_npm.py
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_npm.py
@@ -48,8 +48,8 @@ class NPMModuleTestCase(ModuleTestCase):
self.assertTrue(result['changed'])
self.module_main_command.assert_has_calls([
- call(['/testbin/npm', 'list', '--json', '--long', '--global'], check_rc=False, cwd=None),
- call(['/testbin/npm', 'install', '--global', 'coffee-script'], check_rc=True, cwd=None),
+ call(['/testbin/npm', 'list', '--json', '--long', '--global'], check_rc=False, cwd=None, environ_update={'LANGUAGE': 'C', 'LC_ALL': 'C'}),
+ call(['/testbin/npm', 'install', '--global', 'coffee-script'], check_rc=True, cwd=None, environ_update={'LANGUAGE': 'C', 'LC_ALL': 'C'}),
])
def test_present_missing(self):
@@ -67,8 +67,8 @@ class NPMModuleTestCase(ModuleTestCase):
self.assertTrue(result['changed'])
self.module_main_command.assert_has_calls([
- call(['/testbin/npm', 'list', '--json', '--long', '--global'], check_rc=False, cwd=None),
- call(['/testbin/npm', 'install', '--global', 'coffee-script'], check_rc=True, cwd=None),
+ call(['/testbin/npm', 'list', '--json', '--long', '--global'], check_rc=False, cwd=None, environ_update={'LANGUAGE': 'C', 'LC_ALL': 'C'}),
+ call(['/testbin/npm', 'install', '--global', 'coffee-script'], check_rc=True, cwd=None, environ_update={'LANGUAGE': 'C', 'LC_ALL': 'C'}),
])
def test_present_version(self):
@@ -87,8 +87,8 @@ class NPMModuleTestCase(ModuleTestCase):
self.assertTrue(result['changed'])
self.module_main_command.assert_has_calls([
- call(['/testbin/npm', 'list', '--json', '--long', '--global'], check_rc=False, cwd=None),
- call(['/testbin/npm', 'install', '--global', 'coffee-script@2.5.1'], check_rc=True, cwd=None),
+ call(['/testbin/npm', 'list', '--json', '--long', '--global'], check_rc=False, cwd=None, environ_update={'LANGUAGE': 'C', 'LC_ALL': 'C'}),
+ call(['/testbin/npm', 'install', '--global', 'coffee-script@2.5.1'], check_rc=True, cwd=None, environ_update={'LANGUAGE': 'C', 'LC_ALL': 'C'}),
])
def test_present_version_update(self):
@@ -107,8 +107,8 @@ class NPMModuleTestCase(ModuleTestCase):
self.assertTrue(result['changed'])
self.module_main_command.assert_has_calls([
- call(['/testbin/npm', 'list', '--json', '--long', '--global'], check_rc=False, cwd=None),
- call(['/testbin/npm', 'install', '--global', 'coffee-script@2.5.1'], check_rc=True, cwd=None),
+ call(['/testbin/npm', 'list', '--json', '--long', '--global'], check_rc=False, cwd=None, environ_update={'LANGUAGE': 'C', 'LC_ALL': 'C'}),
+ call(['/testbin/npm', 'install', '--global', 'coffee-script@2.5.1'], check_rc=True, cwd=None, environ_update={'LANGUAGE': 'C', 'LC_ALL': 'C'}),
])
def test_present_version_exists(self):
@@ -127,7 +127,7 @@ class NPMModuleTestCase(ModuleTestCase):
self.assertFalse(result['changed'])
self.module_main_command.assert_has_calls([
- call(['/testbin/npm', 'list', '--json', '--long', '--global'], check_rc=False, cwd=None),
+ call(['/testbin/npm', 'list', '--json', '--long', '--global'], check_rc=False, cwd=None, environ_update={'LANGUAGE': 'C', 'LC_ALL': 'C'}),
])
def test_absent(self):
@@ -145,8 +145,8 @@ class NPMModuleTestCase(ModuleTestCase):
self.assertTrue(result['changed'])
self.module_main_command.assert_has_calls([
- call(['/testbin/npm', 'list', '--json', '--long', '--global'], check_rc=False, cwd=None),
- call(['/testbin/npm', 'uninstall', '--global', 'coffee-script'], check_rc=True, cwd=None),
+ call(['/testbin/npm', 'list', '--json', '--long', '--global'], check_rc=False, cwd=None, environ_update={'LANGUAGE': 'C', 'LC_ALL': 'C'}),
+ call(['/testbin/npm', 'uninstall', '--global', 'coffee-script'], check_rc=True, cwd=None, environ_update={'LANGUAGE': 'C', 'LC_ALL': 'C'}),
])
def test_absent_version(self):
@@ -165,8 +165,8 @@ class NPMModuleTestCase(ModuleTestCase):
self.assertTrue(result['changed'])
self.module_main_command.assert_has_calls([
- call(['/testbin/npm', 'list', '--json', '--long', '--global'], check_rc=False, cwd=None),
- call(['/testbin/npm', 'uninstall', '--global', 'coffee-script'], check_rc=True, cwd=None),
+ call(['/testbin/npm', 'list', '--json', '--long', '--global'], check_rc=False, cwd=None, environ_update={'LANGUAGE': 'C', 'LC_ALL': 'C'}),
+ call(['/testbin/npm', 'uninstall', '--global', 'coffee-script'], check_rc=True, cwd=None, environ_update={'LANGUAGE': 'C', 'LC_ALL': 'C'}),
])
def test_absent_version_different(self):
@@ -185,8 +185,8 @@ class NPMModuleTestCase(ModuleTestCase):
self.assertTrue(result['changed'])
self.module_main_command.assert_has_calls([
- call(['/testbin/npm', 'list', '--json', '--long', '--global'], check_rc=False, cwd=None),
- call(['/testbin/npm', 'uninstall', '--global', 'coffee-script'], check_rc=True, cwd=None),
+ call(['/testbin/npm', 'list', '--json', '--long', '--global'], check_rc=False, cwd=None, environ_update={'LANGUAGE': 'C', 'LC_ALL': 'C'}),
+ call(['/testbin/npm', 'uninstall', '--global', 'coffee-script'], check_rc=True, cwd=None, environ_update={'LANGUAGE': 'C', 'LC_ALL': 'C'}),
])
def test_present_package_json(self):
@@ -203,7 +203,7 @@ class NPMModuleTestCase(ModuleTestCase):
self.assertTrue(result['changed'])
self.module_main_command.assert_has_calls([
- call(['/testbin/npm', 'install', '--global'], check_rc=True, cwd=None),
+ call(['/testbin/npm', 'install', '--global'], check_rc=True, cwd=None, environ_update={'LANGUAGE': 'C', 'LC_ALL': 'C'}),
])
def test_present_package_json_production(self):
@@ -221,7 +221,7 @@ class NPMModuleTestCase(ModuleTestCase):
self.assertTrue(result['changed'])
self.module_main_command.assert_has_calls([
- call(['/testbin/npm', 'install', '--global', '--production'], check_rc=True, cwd=None),
+ call(['/testbin/npm', 'install', '--global', '--production'], check_rc=True, cwd=None, environ_update={'LANGUAGE': 'C', 'LC_ALL': 'C'}),
])
def test_present_package_json_ci(self):
@@ -239,7 +239,7 @@ class NPMModuleTestCase(ModuleTestCase):
self.assertTrue(result['changed'])
self.module_main_command.assert_has_calls([
- call(['/testbin/npm', 'ci', '--global'], check_rc=True, cwd=None),
+ call(['/testbin/npm', 'ci', '--global'], check_rc=True, cwd=None, environ_update={'LANGUAGE': 'C', 'LC_ALL': 'C'}),
])
def test_present_package_json_ci_production(self):
@@ -258,5 +258,5 @@ class NPMModuleTestCase(ModuleTestCase):
self.assertTrue(result['changed'])
self.module_main_command.assert_has_calls([
- call(['/testbin/npm', 'ci', '--global', '--production'], check_rc=True, cwd=None),
+ call(['/testbin/npm', 'ci', '--global', '--production'], check_rc=True, cwd=None, environ_update={'LANGUAGE': 'C', 'LC_ALL': 'C'}),
])
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_opkg.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_opkg.py
index 8e52368ff..c42025959 100644
--- a/ansible_collections/community/general/tests/unit/plugins/modules/test_opkg.py
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_opkg.py
@@ -6,236 +6,9 @@
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
-import json
-from collections import namedtuple
from ansible_collections.community.general.plugins.modules import opkg
+from .helper import Helper
-import pytest
-TESTED_MODULE = opkg.__name__
-
-
-ModuleTestCase = namedtuple("ModuleTestCase", ["id", "input", "output", "run_command_calls"])
-RunCmdCall = namedtuple("RunCmdCall", ["command", "environ", "rc", "out", "err"])
-
-
-@pytest.fixture
-def patch_opkg(mocker):
- mocker.patch('ansible.module_utils.basic.AnsibleModule.get_bin_path', return_value='/testbin/opkg')
-
-
-TEST_CASES = [
- ModuleTestCase(
- id="install_zlibdev",
- input={"name": "zlib-dev", "state": "present"},
- output={
- "msg": "installed 1 package(s)"
- },
- run_command_calls=[
- RunCmdCall(
- command=["/testbin/opkg", "list-installed", "zlib-dev"],
- environ={'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
- rc=0,
- out="",
- err="",
- ),
- RunCmdCall(
- command=["/testbin/opkg", "install", "zlib-dev"],
- environ={'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
- rc=0,
- out=(
- "Installing zlib-dev (1.2.11-6) to root..."
- "Downloading https://downloads.openwrt.org/releases/22.03.0/packages/mips_24kc/base/zlib-dev_1.2.11-6_mips_24kc.ipk"
- "Installing zlib (1.2.11-6) to root..."
- "Downloading https://downloads.openwrt.org/releases/22.03.0/packages/mips_24kc/base/zlib_1.2.11-6_mips_24kc.ipk"
- "Configuring zlib."
- "Configuring zlib-dev."
- ),
- err="",
- ),
- RunCmdCall(
- command=["/testbin/opkg", "list-installed", "zlib-dev"],
- environ={'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
- rc=0,
- out="zlib-dev - 1.2.11-6\n",
- err="",
- ),
- ],
- ),
- ModuleTestCase(
- id="install_zlibdev_present",
- input={"name": "zlib-dev", "state": "present"},
- output={
- "msg": "package(s) already present"
- },
- run_command_calls=[
- RunCmdCall(
- command=["/testbin/opkg", "list-installed", "zlib-dev"],
- environ={'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
- rc=0,
- out="zlib-dev - 1.2.11-6\n",
- err="",
- ),
- ],
- ),
- ModuleTestCase(
- id="install_zlibdev_force_reinstall",
- input={"name": "zlib-dev", "state": "present", "force": "reinstall"},
- output={
- "msg": "installed 1 package(s)"
- },
- run_command_calls=[
- RunCmdCall(
- command=["/testbin/opkg", "list-installed", "zlib-dev"],
- environ={'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
- rc=0,
- out="zlib-dev - 1.2.11-6\n",
- err="",
- ),
- RunCmdCall(
- command=["/testbin/opkg", "install", "--force-reinstall", "zlib-dev"],
- environ={'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
- rc=0,
- out=(
- "Installing zlib-dev (1.2.11-6) to root...\n"
- "Downloading https://downloads.openwrt.org/releases/22.03.0/packages/mips_24kc/base/zlib-dev_1.2.11-6_mips_24kc.ipk\n"
- "Configuring zlib-dev.\n"
- ),
- err="",
- ),
- RunCmdCall(
- command=["/testbin/opkg", "list-installed", "zlib-dev"],
- environ={'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
- rc=0,
- out="zlib-dev - 1.2.11-6\n",
- err="",
- ),
- ],
- ),
- ModuleTestCase(
- id="install_zlibdev_with_version",
- input={"name": "zlib-dev=1.2.11-6", "state": "present"},
- output={
- "msg": "installed 1 package(s)"
- },
- run_command_calls=[
- RunCmdCall(
- command=["/testbin/opkg", "list-installed", "zlib-dev"],
- environ={'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
- rc=0,
- out="",
- err="",
- ),
- RunCmdCall(
- command=["/testbin/opkg", "install", "zlib-dev=1.2.11-6"],
- environ={'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
- rc=0,
- out=(
- "Installing zlib-dev (1.2.11-6) to root..."
- "Downloading https://downloads.openwrt.org/releases/22.03.0/packages/mips_24kc/base/zlib-dev_1.2.11-6_mips_24kc.ipk"
- "Installing zlib (1.2.11-6) to root..."
- "Downloading https://downloads.openwrt.org/releases/22.03.0/packages/mips_24kc/base/zlib_1.2.11-6_mips_24kc.ipk"
- "Configuring zlib."
- "Configuring zlib-dev."
- ),
- err="",
- ),
- RunCmdCall(
- command=["/testbin/opkg", "list-installed", "zlib-dev"],
- environ={'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
- rc=0,
- out="zlib-dev - 1.2.11-6 \n", # This output has the extra space at the end, to satisfy the behaviour of Yocto/OpenEmbedded's opkg
- err="",
- ),
- ],
- ),
- ModuleTestCase(
- id="install_vim_updatecache",
- input={"name": "vim-fuller", "state": "present", "update_cache": True},
- output={
- "msg": "installed 1 package(s)"
- },
- run_command_calls=[
- RunCmdCall(
- command=["/testbin/opkg", "update"],
- environ={'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
- rc=0,
- out="",
- err="",
- ),
- RunCmdCall(
- command=["/testbin/opkg", "list-installed", "vim-fuller"],
- environ={'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
- rc=0,
- out="",
- err="",
- ),
- RunCmdCall(
- command=["/testbin/opkg", "install", "vim-fuller"],
- environ={'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
- rc=0,
- out=(
- "Multiple packages (libgcc1 and libgcc1) providing same name marked HOLD or PREFER. Using latest.\n"
- "Installing vim-fuller (9.0-1) to root...\n"
- "Downloading https://downloads.openwrt.org/snapshots/packages/x86_64/packages/vim-fuller_9.0-1_x86_64.ipk\n"
- "Installing terminfo (6.4-2) to root...\n"
- "Downloading https://downloads.openwrt.org/snapshots/packages/x86_64/base/terminfo_6.4-2_x86_64.ipk\n"
- "Installing libncurses6 (6.4-2) to root...\n"
- "Downloading https://downloads.openwrt.org/snapshots/packages/x86_64/base/libncurses6_6.4-2_x86_64.ipk\n"
- "Configuring terminfo.\n"
- "Configuring libncurses6.\n"
- "Configuring vim-fuller.\n"
- ),
- err="",
- ),
- RunCmdCall(
- command=["/testbin/opkg", "list-installed", "vim-fuller"],
- environ={'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
- rc=0,
- out="vim-fuller - 9.0-1 \n", # This output has the extra space at the end, to satisfy the behaviour of Yocto/OpenEmbedded's opkg
- err="",
- ),
- ],
- ),
-]
-TEST_CASES_IDS = [item.id for item in TEST_CASES]
-
-
-@pytest.mark.parametrize('patch_ansible_module, testcase',
- [[x.input, x] for x in TEST_CASES],
- ids=TEST_CASES_IDS,
- indirect=['patch_ansible_module'])
-@pytest.mark.usefixtures('patch_ansible_module')
-def test_opkg(mocker, capfd, patch_opkg, testcase):
- """
- Run unit tests for test cases listen in TEST_CASES
- """
-
- run_cmd_calls = testcase.run_command_calls
-
- # Mock function used for running commands first
- call_results = [(x.rc, x.out, x.err) for x in run_cmd_calls]
- mock_run_command = mocker.patch('ansible.module_utils.basic.AnsibleModule.run_command', side_effect=call_results)
-
- # Try to run test case
- with pytest.raises(SystemExit):
- opkg.main()
-
- out, err = capfd.readouterr()
- results = json.loads(out)
- print("testcase =\n%s" % str(testcase))
- print("results =\n%s" % results)
-
- for test_result in testcase.output:
- assert results[test_result] == testcase.output[test_result], \
- "'{0}': '{1}' != '{2}'".format(test_result, results[test_result], testcase.output[test_result])
-
- call_args_list = [(item[0][0], item[1]) for item in mock_run_command.call_args_list]
- expected_call_args_list = [(item.command, item.environ) for item in run_cmd_calls]
- print("call args list =\n%s" % call_args_list)
- print("expected args list =\n%s" % expected_call_args_list)
-
- assert mock_run_command.call_count == len(run_cmd_calls)
- if mock_run_command.call_count:
- assert call_args_list == expected_call_args_list
+Helper.from_module(opkg, __name__)
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_opkg.yaml b/ansible_collections/community/general/tests/unit/plugins/modules/test_opkg.yaml
new file mode 100644
index 000000000..6e227dea2
--- /dev/null
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_opkg.yaml
@@ -0,0 +1,142 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) Alexei Znamensky (russoz@gmail.com)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+---
+- id: install_zlibdev
+ input:
+ name: zlib-dev
+ state: present
+ output:
+ msg: installed 1 package(s)
+ run_command_calls:
+ - command: [/testbin/opkg, list-installed, zlib-dev]
+ environ: &env-def {environ_update: {LANGUAGE: C, LC_ALL: C}, check_rc: false}
+ rc: 0
+ out: ""
+ err: ""
+ - command: [/testbin/opkg, install, zlib-dev]
+ environ: *env-def
+ rc: 0
+ out: |
+ Installing zlib-dev (1.2.11-6) to root...
+ Downloading https://downloads.openwrt.org/releases/22.03.0/packages/mips_24kc/base/zlib-dev_1.2.11-6_mips_24kc.ipk
+ Installing zlib (1.2.11-6) to root...
+ Downloading https://downloads.openwrt.org/releases/22.03.0/packages/mips_24kc/base/zlib_1.2.11-6_mips_24kc.ipk
+ Configuring zlib.
+ Configuring zlib-dev.
+ err: ""
+ - command: [/testbin/opkg, list-installed, zlib-dev]
+ environ: *env-def
+ rc: 0
+ out: |
+ zlib-dev - 1.2.11-6
+ err: ""
+- id: install_zlibdev_present
+ input:
+ name: zlib-dev
+ state: present
+ output:
+ msg: package(s) already present
+ run_command_calls:
+ - command: [/testbin/opkg, list-installed, zlib-dev]
+ environ: *env-def
+ rc: 0
+ out: |
+ zlib-dev - 1.2.11-6
+ err: ""
+- id: install_zlibdev_force_reinstall
+ input:
+ name: zlib-dev
+ state: present
+ force: reinstall
+ output:
+ msg: installed 1 package(s)
+ run_command_calls:
+ - command: [/testbin/opkg, list-installed, zlib-dev]
+ environ: *env-def
+ rc: 0
+ out: |
+ zlib-dev - 1.2.11-6
+ err: ""
+ - command: [/testbin/opkg, install, --force-reinstall, zlib-dev]
+ environ: *env-def
+ rc: 0
+ out: |
+ Installing zlib-dev (1.2.11-6) to root...
+ Downloading https://downloads.openwrt.org/releases/22.03.0/packages/mips_24kc/base/zlib-dev_1.2.11-6_mips_24kc.ipk
+ Configuring zlib-dev.
+ err: ""
+ - command: [/testbin/opkg, list-installed, zlib-dev]
+ environ: *env-def
+ rc: 0
+ out: |
+ zlib-dev - 1.2.11-6
+ err: ""
+- id: install_zlibdev_with_version
+ input:
+ name: zlib-dev=1.2.11-6
+ state: present
+ output:
+ msg: installed 1 package(s)
+ run_command_calls:
+ - command: [/testbin/opkg, list-installed, zlib-dev]
+ environ: *env-def
+ rc: 0
+ out: ""
+ err: ""
+ - command: [/testbin/opkg, install, zlib-dev=1.2.11-6]
+ environ: *env-def
+ rc: 0
+ out: |
+ Installing zlib-dev (1.2.11-6) to root...
+ Downloading https://downloads.openwrt.org/releases/22.03.0/packages/mips_24kc/base/zlib-dev_1.2.11-6_mips_24kc.ipk
+ Installing zlib (1.2.11-6) to root...
+ Downloading https://downloads.openwrt.org/releases/22.03.0/packages/mips_24kc/base/zlib_1.2.11-6_mips_24kc.ipk
+ Configuring zlib.
+ Configuring zlib-dev.
+ err: ""
+ - command: [/testbin/opkg, list-installed, zlib-dev]
+ environ: *env-def
+ rc: 0
+ out: "zlib-dev - 1.2.11-6 \n" # This output has the extra space at the end, to satisfy the behaviour of Yocto/OpenEmbedded's opkg
+ err: ""
+- id: install_vim_updatecache
+ input:
+ name: vim-fuller
+ state: present
+ update_cache: true
+ output:
+ msg: installed 1 package(s)
+ run_command_calls:
+ - command: [/testbin/opkg, update]
+ environ: *env-def
+ rc: 0
+ out: ""
+ err: ""
+ - command: [/testbin/opkg, list-installed, vim-fuller]
+ environ: *env-def
+ rc: 0
+ out: ""
+ err: ""
+ - command: [/testbin/opkg, install, vim-fuller]
+ environ: *env-def
+ rc: 0
+ out: |
+ Multiple packages (libgcc1 and libgcc1) providing same name marked HOLD or PREFER. Using latest.
+ Installing vim-fuller (9.0-1) to root...
+ Downloading https://downloads.openwrt.org/snapshots/packages/x86_64/packages/vim-fuller_9.0-1_x86_64.ipk
+ Installing terminfo (6.4-2) to root...
+ Downloading https://downloads.openwrt.org/snapshots/packages/x86_64/base/terminfo_6.4-2_x86_64.ipk
+ Installing libncurses6 (6.4-2) to root...
+ Downloading https://downloads.openwrt.org/snapshots/packages/x86_64/base/libncurses6_6.4-2_x86_64.ipk
+ Configuring terminfo.
+ Configuring libncurses6.
+ Configuring vim-fuller.
+ err: ""
+ - command: [/testbin/opkg, list-installed, vim-fuller]
+ environ: *env-def
+ rc: 0
+ out: "vim-fuller - 9.0-1 \n" # This output has the extra space at the end, to satisfy the behaviour of Yocto/OpenEmbedded's opkg
+ err: ""
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_pagerduty.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_pagerduty.py
index d363804bc..75987d3df 100644
--- a/ansible_collections/community/general/tests/unit/plugins/modules/test_pagerduty.py
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_pagerduty.py
@@ -20,9 +20,9 @@ class PagerDutyTest(unittest.TestCase):
return object(), {'status': 200}
def _assert_ongoing_window_with_v1_compatible_header(self, module, url, headers, data=None, method=None):
- self.assertDictContainsSubset(
- {'Accept': 'application/vnd.pagerduty+json;version=2'},
- headers,
+ self.assertEqual(
+ 'application/vnd.pagerduty+json;version=2',
+ headers.get('Accept'),
'Accept:application/vnd.pagerduty+json;version=2 HTTP header not found'
)
return object(), {'status': 200}
@@ -36,17 +36,17 @@ class PagerDutyTest(unittest.TestCase):
return object(), {'status': 201}
def _assert_create_a_maintenance_window_from_header(self, module, url, headers, data=None, method=None):
- self.assertDictContainsSubset(
- {'From': 'requester_id'},
- headers,
+ self.assertEqual(
+ 'requester_id',
+ headers.get('From'),
'From:requester_id HTTP header not found'
)
return object(), {'status': 201}
def _assert_create_window_with_v1_compatible_header(self, module, url, headers, data=None, method=None):
- self.assertDictContainsSubset(
- {'Accept': 'application/vnd.pagerduty+json;version=2'},
- headers,
+ self.assertEqual(
+ 'application/vnd.pagerduty+json;version=2',
+ headers.get('Accept'),
'Accept:application/vnd.pagerduty+json;version=2 HTTP header not found'
)
return object(), {'status': 201}
@@ -54,9 +54,9 @@ class PagerDutyTest(unittest.TestCase):
def _assert_create_window_payload(self, module, url, headers, data=None, method=None):
payload = json.loads(data)
window_data = payload['maintenance_window']
- self.assertTrue('start_time' in window_data, '"start_time" is requiered attribute')
- self.assertTrue('end_time' in window_data, '"end_time" is requiered attribute')
- self.assertTrue('services' in window_data, '"services" is requiered attribute')
+ self.assertTrue('start_time' in window_data, '"start_time" is required attribute')
+ self.assertTrue('end_time' in window_data, '"end_time" is required attribute')
+ self.assertTrue('services' in window_data, '"services" is required attribute')
return object(), {'status': 201}
def _assert_create_window_single_service(self, module, url, headers, data=None, method=None):
@@ -89,9 +89,9 @@ class PagerDutyTest(unittest.TestCase):
return object(), {'status': 204}
def _assert_absent_window_with_v1_compatible_header(self, module, url, headers, method=None):
- self.assertDictContainsSubset(
- {'Accept': 'application/vnd.pagerduty+json;version=2'},
- headers,
+ self.assertEqual(
+ 'application/vnd.pagerduty+json;version=2',
+ headers.get('Accept'),
'Accept:application/vnd.pagerduty+json;version=2 HTTP header not found'
)
return object(), {'status': 204}
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_pagerduty_alert.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_pagerduty_alert.py
index 3df992b42..7a1e951a2 100644
--- a/ansible_collections/community/general/tests/unit/plugins/modules/test_pagerduty_alert.py
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_pagerduty_alert.py
@@ -7,6 +7,10 @@ __metaclass__ = type
from ansible_collections.community.general.tests.unit.compat import unittest
from ansible_collections.community.general.plugins.modules import pagerduty_alert
+import json
+import pytest
+from ansible_collections.community.general.tests.unit.compat.mock import patch
+from ansible_collections.community.general.tests.unit.plugins.modules.utils import AnsibleExitJson, AnsibleFailJson, ModuleTestCase, set_module_args
class PagerDutyAlertsTest(unittest.TestCase):
@@ -18,9 +22,9 @@ class PagerDutyAlertsTest(unittest.TestCase):
return Response(), {'status': 200}
def _assert_compatibility_header(self, module, url, method, headers):
- self.assertDictContainsSubset(
- {'Accept': 'application/vnd.pagerduty+json;version=2'},
- headers,
+ self.assertEqual(
+ 'application/vnd.pagerduty+json;version=2',
+ headers.get('Accept'),
'Accept:application/vnd.pagerduty+json;version=2 HTTP header not found'
)
return Response(), {'status': 200}
@@ -44,3 +48,106 @@ class PagerDutyAlertsTest(unittest.TestCase):
class Response(object):
def read(self):
return '{"incidents":[{"id": "incident_id", "status": "triggered"}]}'
+
+
+class TestPagerDutyAlertModule(ModuleTestCase):
+ def setUp(self):
+ super(TestPagerDutyAlertModule, self).setUp()
+ self.module = pagerduty_alert
+
+ def tearDown(self):
+ super(TestPagerDutyAlertModule, self).tearDown()
+
+ @pytest.fixture
+ def fetch_url_mock(self, mocker):
+ return mocker.patch('ansible.module_utils.monitoring.pagerduty_change.fetch_url')
+
+ def test_module_fail_when_required_args_missing(self):
+ with self.assertRaises(AnsibleFailJson):
+ set_module_args({})
+ self.module.main()
+
+ def test_ensure_alert_created_with_minimal_data(self):
+ set_module_args({
+ 'state': 'triggered',
+ 'api_version': 'v2',
+ 'integration_key': 'test',
+ 'source': 'My Ansible Script',
+ 'desc': 'Description for alert'
+ })
+
+ with patch.object(pagerduty_alert, 'fetch_url') as fetch_url_mock:
+ fetch_url_mock.return_value = (Response(), {"status": 202})
+ with self.assertRaises(AnsibleExitJson):
+ self.module.main()
+
+ assert fetch_url_mock.call_count == 1
+ url = fetch_url_mock.call_args[0][1]
+ json_data = fetch_url_mock.call_args[1]['data']
+ data = json.loads(json_data)
+
+ assert url == 'https://events.pagerduty.com/v2/enqueue'
+ assert data['routing_key'] == 'test'
+ assert data['event_action'] == 'trigger'
+ assert data['payload']['summary'] == 'Description for alert'
+ assert data['payload']['source'] == 'My Ansible Script'
+ assert data['payload']['severity'] == 'critical'
+ assert data['payload']['timestamp'] is not None
+
+ def test_ensure_alert_created_with_full_data(self):
+ set_module_args({
+ 'api_version': 'v2',
+ 'component': 'mysql',
+ 'custom_details': {'environment': 'production', 'notes': 'this is a test note'},
+ 'desc': 'Description for alert',
+ 'incident_class': 'ping failure',
+ 'integration_key': 'test',
+ 'link_url': 'https://pagerduty.com',
+ 'link_text': 'PagerDuty',
+ 'state': 'triggered',
+ 'source': 'My Ansible Script',
+ })
+
+ with patch.object(pagerduty_alert, 'fetch_url') as fetch_url_mock:
+ fetch_url_mock.return_value = (Response(), {"status": 202})
+ with self.assertRaises(AnsibleExitJson):
+ self.module.main()
+
+ assert fetch_url_mock.call_count == 1
+ url = fetch_url_mock.call_args[0][1]
+ json_data = fetch_url_mock.call_args[1]['data']
+ data = json.loads(json_data)
+
+ assert url == 'https://events.pagerduty.com/v2/enqueue'
+ assert data['routing_key'] == 'test'
+ assert data['payload']['summary'] == 'Description for alert'
+ assert data['payload']['source'] == 'My Ansible Script'
+ assert data['payload']['class'] == 'ping failure'
+ assert data['payload']['component'] == 'mysql'
+ assert data['payload']['custom_details']['environment'] == 'production'
+ assert data['payload']['custom_details']['notes'] == 'this is a test note'
+ assert data['links'][0]['href'] == 'https://pagerduty.com'
+ assert data['links'][0]['text'] == 'PagerDuty'
+
+ def test_ensure_alert_acknowledged(self):
+ set_module_args({
+ 'state': 'acknowledged',
+ 'api_version': 'v2',
+ 'integration_key': 'test',
+ 'incident_key': 'incident_test_id',
+ })
+
+ with patch.object(pagerduty_alert, 'fetch_url') as fetch_url_mock:
+ fetch_url_mock.return_value = (Response(), {"status": 202})
+ with self.assertRaises(AnsibleExitJson):
+ self.module.main()
+
+ assert fetch_url_mock.call_count == 1
+ url = fetch_url_mock.call_args[0][1]
+ json_data = fetch_url_mock.call_args[1]['data']
+ data = json.loads(json_data)
+
+ assert url == 'https://events.pagerduty.com/v2/enqueue'
+ assert data['routing_key'] == 'test'
+ assert data['event_action'] == 'acknowledge'
+ assert data['dedup_key'] == 'incident_test_id'
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_pkgin.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_pkgin.py
index d73911e0c..dea5a05b5 100644
--- a/ansible_collections/community/general/tests/unit/plugins/modules/test_pkgin.py
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_pkgin.py
@@ -30,7 +30,7 @@ class TestPkginQueryPackage(unittest.TestCase):
command_result = pkgin.query_package(mock_module, package)
# then
- self.assertEquals(command_result, pkgin.PackageState.PRESENT)
+ self.assertEqual(command_result, pkgin.PackageState.PRESENT)
@mock.patch('ansible_collections.community.general.plugins.modules.pkgin.AnsibleModule')
def test_package_with_version_is_present(self, mock_module):
@@ -46,7 +46,7 @@ class TestPkginQueryPackage(unittest.TestCase):
command_result = pkgin.query_package(mock_module, package)
# then
- self.assertEquals(command_result, pkgin.PackageState.PRESENT)
+ self.assertEqual(command_result, pkgin.PackageState.PRESENT)
@mock.patch('ansible_collections.community.general.plugins.modules.pkgin.AnsibleModule')
def test_package_found_but_not_installed(self, mock_module):
@@ -62,7 +62,7 @@ class TestPkginQueryPackage(unittest.TestCase):
command_result = pkgin.query_package(mock_module, package)
# then
- self.assertEquals(command_result, pkgin.PackageState.NOT_INSTALLED)
+ self.assertEqual(command_result, pkgin.PackageState.NOT_INSTALLED)
@mock.patch('ansible_collections.community.general.plugins.modules.pkgin.AnsibleModule')
def test_package_found_outdated(self, mock_module):
@@ -78,7 +78,7 @@ class TestPkginQueryPackage(unittest.TestCase):
command_result = pkgin.query_package(mock_module, package)
# then
- self.assertEquals(command_result, pkgin.PackageState.OUTDATED)
+ self.assertEqual(command_result, pkgin.PackageState.OUTDATED)
@mock.patch('ansible_collections.community.general.plugins.modules.pkgin.AnsibleModule')
def test_package_with_version_found_outdated(self, mock_module):
@@ -94,7 +94,7 @@ class TestPkginQueryPackage(unittest.TestCase):
command_result = pkgin.query_package(mock_module, package)
# then
- self.assertEquals(command_result, pkgin.PackageState.OUTDATED)
+ self.assertEqual(command_result, pkgin.PackageState.OUTDATED)
@mock.patch('ansible_collections.community.general.plugins.modules.pkgin.AnsibleModule')
def test_package_not_found(self, mock_module):
@@ -110,7 +110,7 @@ class TestPkginQueryPackage(unittest.TestCase):
command_result = pkgin.query_package(mock_module, package)
# then
- self.assertEquals(command_result, pkgin.PackageState.NOT_FOUND)
+ self.assertEqual(command_result, pkgin.PackageState.NOT_FOUND)
@mock.patch('ansible_collections.community.general.plugins.modules.pkgin.AnsibleModule')
def test_with_parseable_flag_supported_package_is_present(self, mock_module):
@@ -126,7 +126,7 @@ class TestPkginQueryPackage(unittest.TestCase):
command_result = pkgin.query_package(mock_module, package)
# then
- self.assertEquals(command_result, pkgin.PackageState.PRESENT)
+ self.assertEqual(command_result, pkgin.PackageState.PRESENT)
@mock.patch('ansible_collections.community.general.plugins.modules.pkgin.AnsibleModule')
def test_with_parseable_flag_not_supported_package_is_present(self, mock_module):
@@ -142,4 +142,4 @@ class TestPkginQueryPackage(unittest.TestCase):
command_result = pkgin.query_package(mock_module, package)
# then
- self.assertEquals(command_result, pkgin.PackageState.PRESENT)
+ self.assertEqual(command_result, pkgin.PackageState.PRESENT)
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_proxmox_kvm.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_proxmox_kvm.py
index 531185102..4e2cf032c 100644
--- a/ansible_collections/community/general/tests/unit/plugins/modules/test_proxmox_kvm.py
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_proxmox_kvm.py
@@ -4,17 +4,165 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
-from ansible_collections.community.general.plugins.modules.proxmox_kvm import parse_dev, parse_mac
+import sys
+
+import pytest
+
+proxmoxer = pytest.importorskip("proxmoxer")
+mandatory_py_version = pytest.mark.skipif(
+ sys.version_info < (2, 7),
+ reason="The proxmoxer dependency requires python2.7 or higher",
+)
+
+from ansible_collections.community.general.plugins.modules import proxmox_kvm
+from ansible_collections.community.general.tests.unit.compat.mock import (
+ patch,
+ DEFAULT,
+)
+from ansible_collections.community.general.tests.unit.plugins.modules.utils import (
+ AnsibleExitJson,
+ AnsibleFailJson,
+ ModuleTestCase,
+ set_module_args,
+)
+import ansible_collections.community.general.plugins.module_utils.proxmox as proxmox_utils
+
+
+class TestProxmoxKvmModule(ModuleTestCase):
+ def setUp(self):
+ super(TestProxmoxKvmModule, self).setUp()
+ proxmox_utils.HAS_PROXMOXER = True
+ self.module = proxmox_kvm
+ self.connect_mock = patch(
+ "ansible_collections.community.general.plugins.module_utils.proxmox.ProxmoxAnsible._connect"
+ ).start()
+ self.get_node_mock = patch.object(
+ proxmox_utils.ProxmoxAnsible, "get_node"
+ ).start()
+ self.get_vm_mock = patch.object(proxmox_utils.ProxmoxAnsible, "get_vm").start()
+ self.create_vm_mock = patch.object(
+ proxmox_kvm.ProxmoxKvmAnsible, "create_vm"
+ ).start()
+
+ def tearDown(self):
+ self.create_vm_mock.stop()
+ self.get_vm_mock.stop()
+ self.get_node_mock.stop()
+ self.connect_mock.stop()
+ super(TestProxmoxKvmModule, self).tearDown()
+
+ def test_module_fail_when_required_args_missing(self):
+ with self.assertRaises(AnsibleFailJson):
+ set_module_args({})
+ self.module.main()
+
+ def test_module_exits_unchaged_when_provided_vmid_exists(self):
+ set_module_args(
+ {
+ "api_host": "host",
+ "api_user": "user",
+ "api_password": "password",
+ "vmid": "100",
+ "node": "pve",
+ }
+ )
+ self.get_vm_mock.return_value = [{"vmid": "100"}]
+ with pytest.raises(AnsibleExitJson) as exc_info:
+ self.module.main()
+
+ assert self.get_vm_mock.call_count == 1
+ result = exc_info.value.args[0]
+ assert result["changed"] is False
+ assert result["msg"] == "VM with vmid <100> already exists"
+
+ def test_vm_created_when_vmid_not_exist_but_name_already_exist(self):
+ set_module_args(
+ {
+ "api_host": "host",
+ "api_user": "user",
+ "api_password": "password",
+ "vmid": "100",
+ "name": "existing.vm.local",
+ "node": "pve",
+ }
+ )
+ self.get_vm_mock.return_value = None
+ with pytest.raises(AnsibleExitJson) as exc_info:
+ self.module.main()
+
+ assert self.get_vm_mock.call_count == 1
+ assert self.get_node_mock.call_count == 1
+ result = exc_info.value.args[0]
+ assert result["changed"] is True
+ assert result["msg"] == "VM existing.vm.local with vmid 100 deployed"
+
+ def test_vm_not_created_when_name_already_exist_and_vmid_not_set(self):
+ set_module_args(
+ {
+ "api_host": "host",
+ "api_user": "user",
+ "api_password": "password",
+ "name": "existing.vm.local",
+ "node": "pve",
+ }
+ )
+ with patch.object(proxmox_utils.ProxmoxAnsible, "get_vmid") as get_vmid_mock:
+ get_vmid_mock.return_value = {
+ "vmid": 100,
+ "name": "existing.vm.local",
+ }
+ with pytest.raises(AnsibleExitJson) as exc_info:
+ self.module.main()
+
+ assert get_vmid_mock.call_count == 1
+ result = exc_info.value.args[0]
+ assert result["changed"] is False
+ def test_vm_created_when_name_doesnt_exist_and_vmid_not_set(self):
+ set_module_args(
+ {
+ "api_host": "host",
+ "api_user": "user",
+ "api_password": "password",
+ "name": "existing.vm.local",
+ "node": "pve",
+ }
+ )
+ self.get_vm_mock.return_value = None
+ with patch.multiple(
+ proxmox_utils.ProxmoxAnsible, get_vmid=DEFAULT, get_nextvmid=DEFAULT
+ ) as utils_mock:
+ utils_mock["get_vmid"].return_value = None
+ utils_mock["get_nextvmid"].return_value = 101
+ with pytest.raises(AnsibleExitJson) as exc_info:
+ self.module.main()
-def test_parse_mac():
- assert parse_mac('virtio=00:11:22:AA:BB:CC,bridge=vmbr0,firewall=1') == '00:11:22:AA:BB:CC'
+ assert utils_mock["get_vmid"].call_count == 1
+ assert utils_mock["get_nextvmid"].call_count == 1
+ result = exc_info.value.args[0]
+ assert result["changed"] is True
+ assert result["msg"] == "VM existing.vm.local with vmid 101 deployed"
+ def test_parse_mac(self):
+ assert (
+ proxmox_kvm.parse_mac("virtio=00:11:22:AA:BB:CC,bridge=vmbr0,firewall=1")
+ == "00:11:22:AA:BB:CC"
+ )
-def test_parse_dev():
- assert parse_dev('local-lvm:vm-1000-disk-0,format=qcow2') == 'local-lvm:vm-1000-disk-0'
- assert parse_dev('local-lvm:vm-101-disk-1,size=8G') == 'local-lvm:vm-101-disk-1'
- assert parse_dev('local-zfs:vm-1001-disk-0') == 'local-zfs:vm-1001-disk-0'
+ def test_parse_dev(self):
+ assert (
+ proxmox_kvm.parse_dev("local-lvm:vm-1000-disk-0,format=qcow2")
+ == "local-lvm:vm-1000-disk-0"
+ )
+ assert (
+ proxmox_kvm.parse_dev("local-lvm:vm-101-disk-1,size=8G")
+ == "local-lvm:vm-101-disk-1"
+ )
+ assert (
+ proxmox_kvm.parse_dev("local-zfs:vm-1001-disk-0")
+ == "local-zfs:vm-1001-disk-0"
+ )
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_proxmox_snap.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_proxmox_snap.py
index 4bdcaa8b7..545fcd1f5 100644
--- a/ansible_collections/community/general/tests/unit/plugins/modules/test_proxmox_snap.py
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_proxmox_snap.py
@@ -7,8 +7,16 @@ from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import json
+import sys
+
import pytest
+proxmoxer = pytest.importorskip('proxmoxer')
+mandatory_py_version = pytest.mark.skipif(
+ sys.version_info < (2, 7),
+ reason='The proxmoxer dependency requires python2.7 or higher'
+)
+
from ansible_collections.community.general.tests.unit.compat.mock import MagicMock, patch
from ansible_collections.community.general.plugins.modules import proxmox_snap
import ansible_collections.community.general.plugins.module_utils.proxmox as proxmox_utils
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_proxmox_storage_contents_info.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_proxmox_storage_contents_info.py
new file mode 100644
index 000000000..df2625dba
--- /dev/null
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_proxmox_storage_contents_info.py
@@ -0,0 +1,90 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2023, Julian Vanden Broeck <julian.vandenbroeck at dalibo.com>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+import pytest
+
+proxmoxer = pytest.importorskip("proxmoxer")
+
+from ansible_collections.community.general.plugins.modules import proxmox_storage_contents_info
+from ansible_collections.community.general.tests.unit.compat.mock import patch
+from ansible_collections.community.general.tests.unit.plugins.modules.utils import (
+ AnsibleExitJson,
+ AnsibleFailJson,
+ ModuleTestCase,
+ set_module_args,
+)
+import ansible_collections.community.general.plugins.module_utils.proxmox as proxmox_utils
+
+NODE1 = "pve"
+RAW_LIST_OUTPUT = [
+ {
+ "content": "backup",
+ "ctime": 1702528474,
+ "format": "pbs-vm",
+ "size": 273804166061,
+ "subtype": "qemu",
+ "vmid": 931,
+ "volid": "datastore:backup/vm/931/2023-12-14T04:34:34Z",
+ },
+ {
+ "content": "backup",
+ "ctime": 1702582560,
+ "format": "pbs-vm",
+ "size": 273804166059,
+ "subtype": "qemu",
+ "vmid": 931,
+ "volid": "datastore:backup/vm/931/2023-12-14T19:36:00Z",
+ },
+]
+
+
+def get_module_args(node, storage, content="all", vmid=None):
+ return {
+ "api_host": "host",
+ "api_user": "user",
+ "api_password": "password",
+ "node": node,
+ "storage": storage,
+ "content": content,
+ "vmid": vmid,
+ }
+
+
+class TestProxmoxStorageContentsInfo(ModuleTestCase):
+ def setUp(self):
+ super(TestProxmoxStorageContentsInfo, self).setUp()
+ proxmox_utils.HAS_PROXMOXER = True
+ self.module = proxmox_storage_contents_info
+ self.connect_mock = patch(
+ "ansible_collections.community.general.plugins.module_utils.proxmox.ProxmoxAnsible._connect",
+ ).start()
+ self.connect_mock.return_value.nodes.return_value.storage.return_value.content.return_value.get.return_value = (
+ RAW_LIST_OUTPUT
+ )
+ self.connect_mock.return_value.nodes.get.return_value = [{"node": NODE1}]
+
+ def tearDown(self):
+ self.connect_mock.stop()
+ super(TestProxmoxStorageContentsInfo, self).tearDown()
+
+ def test_module_fail_when_required_args_missing(self):
+ with pytest.raises(AnsibleFailJson) as exc_info:
+ set_module_args({})
+ self.module.main()
+
+ def test_storage_contents_info(self):
+ with pytest.raises(AnsibleExitJson) as exc_info:
+ set_module_args(get_module_args(node=NODE1, storage="datastore"))
+ expected_output = {}
+ self.module.main()
+
+ result = exc_info.value.args[0]
+ assert not result["changed"]
+ assert result["proxmox_storage_content"] == RAW_LIST_OUTPUT
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_proxmox_tasks_info.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_proxmox_tasks_info.py
index 0d1b5a7bf..5c228655b 100644
--- a/ansible_collections/community/general/tests/unit/plugins/modules/test_proxmox_tasks_info.py
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_proxmox_tasks_info.py
@@ -10,8 +10,16 @@
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
-import pytest
import json
+import sys
+
+import pytest
+
+proxmoxer = pytest.importorskip('proxmoxer')
+mandatory_py_version = pytest.mark.skipif(
+ sys.version_info < (2, 7),
+ reason='The proxmoxer dependency requires python2.7 or higher'
+)
from ansible_collections.community.general.plugins.modules import proxmox_tasks_info
import ansible_collections.community.general.plugins.module_utils.proxmox as proxmox_utils
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_proxmox_template.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_proxmox_template.py
new file mode 100644
index 000000000..dc09a44b3
--- /dev/null
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_proxmox_template.py
@@ -0,0 +1,66 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2023, Sergei Antipov <greendayonfire at gmail.com>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+import os
+import sys
+
+import pytest
+
+proxmoxer = pytest.importorskip('proxmoxer')
+mandatory_py_version = pytest.mark.skipif(
+ sys.version_info < (2, 7),
+ reason='The proxmoxer dependency requires python2.7 or higher'
+)
+
+from ansible_collections.community.general.plugins.modules import proxmox_template
+from ansible_collections.community.general.tests.unit.compat.mock import patch, Mock
+from ansible_collections.community.general.tests.unit.plugins.modules.utils import (
+ AnsibleFailJson,
+ ModuleTestCase,
+ set_module_args,
+)
+import ansible_collections.community.general.plugins.module_utils.proxmox as proxmox_utils
+
+
+class TestProxmoxTemplateModule(ModuleTestCase):
+ def setUp(self):
+ super(TestProxmoxTemplateModule, self).setUp()
+ proxmox_utils.HAS_PROXMOXER = True
+ self.module = proxmox_template
+ self.connect_mock = patch(
+ "ansible_collections.community.general.plugins.module_utils.proxmox.ProxmoxAnsible._connect"
+ )
+ self.connect_mock.start()
+
+ def tearDown(self):
+ self.connect_mock.stop()
+ super(TestProxmoxTemplateModule, self).tearDown()
+
+ @patch("os.stat")
+ @patch.multiple(os.path, exists=Mock(return_value=True), isfile=Mock(return_value=True))
+ def test_module_fail_when_toolbelt_not_installed_and_file_size_is_big(self, mock_stat):
+ self.module.HAS_REQUESTS_TOOLBELT = False
+ mock_stat.return_value.st_size = 268435460
+ set_module_args(
+ {
+ "api_host": "host",
+ "api_user": "user",
+ "api_password": "password",
+ "node": "pve",
+ "src": "/tmp/mock.iso",
+ "content_type": "iso"
+ }
+ )
+ with pytest.raises(AnsibleFailJson) as exc_info:
+ self.module.main()
+
+ result = exc_info.value.args[0]
+ assert result["failed"] is True
+ assert result["msg"] == "'requests_toolbelt' module is required to upload files larger than 256MB"
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_proxmox_vm_info.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_proxmox_vm_info.py
new file mode 100644
index 000000000..94bbbc948
--- /dev/null
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_proxmox_vm_info.py
@@ -0,0 +1,714 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2023, Sergei Antipov <greendayonfire at gmail.com>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+import sys
+
+import pytest
+
+proxmoxer = pytest.importorskip("proxmoxer")
+mandatory_py_version = pytest.mark.skipif(
+ sys.version_info < (2, 7),
+ reason="The proxmoxer dependency requires python2.7 or higher",
+)
+
+from ansible_collections.community.general.plugins.modules import proxmox_vm_info
+from ansible_collections.community.general.tests.unit.compat.mock import patch
+from ansible_collections.community.general.tests.unit.plugins.modules.utils import (
+ AnsibleExitJson,
+ AnsibleFailJson,
+ ModuleTestCase,
+ set_module_args,
+)
+import ansible_collections.community.general.plugins.module_utils.proxmox as proxmox_utils
+
+NODE1 = "pve"
+NODE2 = "pve2"
+RAW_CLUSTER_OUTPUT = [
+ {
+ "cpu": 0.174069059487628,
+ "disk": 0,
+ "diskread": 6656,
+ "diskwrite": 0,
+ "id": "qemu/100",
+ "maxcpu": 1,
+ "maxdisk": 34359738368,
+ "maxmem": 4294967296,
+ "mem": 35304543,
+ "name": "pxe.home.arpa",
+ "netin": 416956,
+ "netout": 17330,
+ "node": NODE1,
+ "status": "running",
+ "template": 0,
+ "type": "qemu",
+ "uptime": 669,
+ "vmid": 100,
+ },
+ {
+ "cpu": 0,
+ "disk": 0,
+ "diskread": 0,
+ "diskwrite": 0,
+ "id": "qemu/101",
+ "maxcpu": 1,
+ "maxdisk": 0,
+ "maxmem": 536870912,
+ "mem": 0,
+ "name": "test1",
+ "netin": 0,
+ "netout": 0,
+ "node": NODE2,
+ "pool": "pool1",
+ "status": "stopped",
+ "template": 0,
+ "type": "qemu",
+ "uptime": 0,
+ "vmid": 101,
+ },
+ {
+ "cpu": 0,
+ "disk": 352190464,
+ "diskread": 0,
+ "diskwrite": 0,
+ "id": "lxc/102",
+ "maxcpu": 2,
+ "maxdisk": 10737418240,
+ "maxmem": 536870912,
+ "mem": 28192768,
+ "name": "test-lxc.home.arpa",
+ "netin": 102757,
+ "netout": 446,
+ "node": NODE1,
+ "status": "running",
+ "template": 0,
+ "type": "lxc",
+ "uptime": 161,
+ "vmid": 102,
+ },
+ {
+ "cpu": 0,
+ "disk": 0,
+ "diskread": 0,
+ "diskwrite": 0,
+ "id": "lxc/103",
+ "maxcpu": 2,
+ "maxdisk": 10737418240,
+ "maxmem": 536870912,
+ "mem": 0,
+ "name": "test1-lxc.home.arpa",
+ "netin": 0,
+ "netout": 0,
+ "node": NODE2,
+ "pool": "pool1",
+ "status": "stopped",
+ "template": 0,
+ "type": "lxc",
+ "uptime": 0,
+ "vmid": 103,
+ },
+ {
+ "cpu": 0,
+ "disk": 0,
+ "diskread": 0,
+ "diskwrite": 0,
+ "id": "lxc/104",
+ "maxcpu": 2,
+ "maxdisk": 10737418240,
+ "maxmem": 536870912,
+ "mem": 0,
+ "name": "test-lxc.home.arpa",
+ "netin": 0,
+ "netout": 0,
+ "node": NODE2,
+ "pool": "pool1",
+ "status": "stopped",
+ "template": 0,
+ "type": "lxc",
+ "uptime": 0,
+ "vmid": 104,
+ },
+ {
+ "cpu": 0,
+ "disk": 0,
+ "diskread": 0,
+ "diskwrite": 0,
+ "id": "lxc/105",
+ "maxcpu": 2,
+ "maxdisk": 10737418240,
+ "maxmem": 536870912,
+ "mem": 0,
+ "name": "",
+ "netin": 0,
+ "netout": 0,
+ "node": NODE2,
+ "pool": "pool1",
+ "status": "stopped",
+ "template": 0,
+ "type": "lxc",
+ "uptime": 0,
+ "vmid": 105,
+ },
+]
+RAW_LXC_OUTPUT = [
+ {
+ "cpu": 0,
+ "cpus": 2,
+ "disk": 0,
+ "diskread": 0,
+ "diskwrite": 0,
+ "maxdisk": 10737418240,
+ "maxmem": 536870912,
+ "maxswap": 536870912,
+ "mem": 0,
+ "name": "test1-lxc.home.arpa",
+ "netin": 0,
+ "netout": 0,
+ "status": "stopped",
+ "swap": 0,
+ "type": "lxc",
+ "uptime": 0,
+ "vmid": "103",
+ },
+ {
+ "cpu": 0,
+ "cpus": 2,
+ "disk": 352190464,
+ "diskread": 0,
+ "diskwrite": 0,
+ "maxdisk": 10737418240,
+ "maxmem": 536870912,
+ "maxswap": 536870912,
+ "mem": 28192768,
+ "name": "test-lxc.home.arpa",
+ "netin": 102757,
+ "netout": 446,
+ "pid": 4076752,
+ "status": "running",
+ "swap": 0,
+ "type": "lxc",
+ "uptime": 161,
+ "vmid": "102",
+ },
+ {
+ "cpu": 0,
+ "cpus": 2,
+ "disk": 0,
+ "diskread": 0,
+ "diskwrite": 0,
+ "maxdisk": 10737418240,
+ "maxmem": 536870912,
+ "maxswap": 536870912,
+ "mem": 0,
+ "name": "test-lxc.home.arpa",
+ "netin": 0,
+ "netout": 0,
+ "status": "stopped",
+ "swap": 0,
+ "type": "lxc",
+ "uptime": 0,
+ "vmid": "104",
+ },
+ {
+ "cpu": 0,
+ "cpus": 2,
+ "disk": 0,
+ "diskread": 0,
+ "diskwrite": 0,
+ "maxdisk": 10737418240,
+ "maxmem": 536870912,
+ "maxswap": 536870912,
+ "mem": 0,
+ "name": "",
+ "netin": 0,
+ "netout": 0,
+ "status": "stopped",
+ "swap": 0,
+ "type": "lxc",
+ "uptime": 0,
+ "vmid": "105",
+ },
+]
+RAW_QEMU_OUTPUT = [
+ {
+ "cpu": 0,
+ "cpus": 1,
+ "disk": 0,
+ "diskread": 0,
+ "diskwrite": 0,
+ "maxdisk": 0,
+ "maxmem": 536870912,
+ "mem": 0,
+ "name": "test1",
+ "netin": 0,
+ "netout": 0,
+ "status": "stopped",
+ "uptime": 0,
+ "vmid": 101,
+ },
+ {
+ "cpu": 0.174069059487628,
+ "cpus": 1,
+ "disk": 0,
+ "diskread": 6656,
+ "diskwrite": 0,
+ "maxdisk": 34359738368,
+ "maxmem": 4294967296,
+ "mem": 35304543,
+ "name": "pxe.home.arpa",
+ "netin": 416956,
+ "netout": 17330,
+ "pid": 4076688,
+ "status": "running",
+ "uptime": 669,
+ "vmid": 100,
+ },
+]
+EXPECTED_VMS_OUTPUT = [
+ {
+ "cpu": 0.174069059487628,
+ "cpus": 1,
+ "disk": 0,
+ "diskread": 6656,
+ "diskwrite": 0,
+ "id": "qemu/100",
+ "maxcpu": 1,
+ "maxdisk": 34359738368,
+ "maxmem": 4294967296,
+ "mem": 35304543,
+ "name": "pxe.home.arpa",
+ "netin": 416956,
+ "netout": 17330,
+ "node": NODE1,
+ "pid": 4076688,
+ "status": "running",
+ "template": False,
+ "type": "qemu",
+ "uptime": 669,
+ "vmid": 100,
+ },
+ {
+ "cpu": 0,
+ "cpus": 1,
+ "disk": 0,
+ "diskread": 0,
+ "diskwrite": 0,
+ "id": "qemu/101",
+ "maxcpu": 1,
+ "maxdisk": 0,
+ "maxmem": 536870912,
+ "mem": 0,
+ "name": "test1",
+ "netin": 0,
+ "netout": 0,
+ "node": NODE2,
+ "pool": "pool1",
+ "status": "stopped",
+ "template": False,
+ "type": "qemu",
+ "uptime": 0,
+ "vmid": 101,
+ },
+ {
+ "cpu": 0,
+ "cpus": 2,
+ "disk": 352190464,
+ "diskread": 0,
+ "diskwrite": 0,
+ "id": "lxc/102",
+ "maxcpu": 2,
+ "maxdisk": 10737418240,
+ "maxmem": 536870912,
+ "maxswap": 536870912,
+ "mem": 28192768,
+ "name": "test-lxc.home.arpa",
+ "netin": 102757,
+ "netout": 446,
+ "node": NODE1,
+ "pid": 4076752,
+ "status": "running",
+ "swap": 0,
+ "template": False,
+ "type": "lxc",
+ "uptime": 161,
+ "vmid": 102,
+ },
+ {
+ "cpu": 0,
+ "cpus": 2,
+ "disk": 0,
+ "diskread": 0,
+ "diskwrite": 0,
+ "id": "lxc/103",
+ "maxcpu": 2,
+ "maxdisk": 10737418240,
+ "maxmem": 536870912,
+ "maxswap": 536870912,
+ "mem": 0,
+ "name": "test1-lxc.home.arpa",
+ "netin": 0,
+ "netout": 0,
+ "node": NODE2,
+ "pool": "pool1",
+ "status": "stopped",
+ "swap": 0,
+ "template": False,
+ "type": "lxc",
+ "uptime": 0,
+ "vmid": 103,
+ },
+ {
+ "cpu": 0,
+ "cpus": 2,
+ "disk": 0,
+ "diskread": 0,
+ "diskwrite": 0,
+ "id": "lxc/104",
+ "maxcpu": 2,
+ "maxdisk": 10737418240,
+ "maxmem": 536870912,
+ "maxswap": 536870912,
+ "mem": 0,
+ "name": "test-lxc.home.arpa",
+ "netin": 0,
+ "netout": 0,
+ "node": NODE2,
+ "pool": "pool1",
+ "status": "stopped",
+ "swap": 0,
+ "template": False,
+ "type": "lxc",
+ "uptime": 0,
+ "vmid": 104,
+ },
+ {
+ "cpu": 0,
+ "cpus": 2,
+ "disk": 0,
+ "diskread": 0,
+ "diskwrite": 0,
+ "id": "lxc/105",
+ "maxcpu": 2,
+ "maxdisk": 10737418240,
+ "maxmem": 536870912,
+ "maxswap": 536870912,
+ "mem": 0,
+ "name": "",
+ "netin": 0,
+ "netout": 0,
+ "node": NODE2,
+ "pool": "pool1",
+ "status": "stopped",
+ "swap": 0,
+ "template": False,
+ "type": "lxc",
+ "uptime": 0,
+ "vmid": 105,
+ },
+]
+
+
+def get_module_args(type="all", node=None, vmid=None, name=None, config="none"):
+ return {
+ "api_host": "host",
+ "api_user": "user",
+ "api_password": "password",
+ "node": node,
+ "type": type,
+ "vmid": vmid,
+ "name": name,
+ "config": config,
+ }
+
+
+class TestProxmoxVmInfoModule(ModuleTestCase):
+ def setUp(self):
+ super(TestProxmoxVmInfoModule, self).setUp()
+ proxmox_utils.HAS_PROXMOXER = True
+ self.module = proxmox_vm_info
+ self.connect_mock = patch(
+ "ansible_collections.community.general.plugins.module_utils.proxmox.ProxmoxAnsible._connect",
+ ).start()
+ self.connect_mock.return_value.nodes.return_value.lxc.return_value.get.return_value = (
+ RAW_LXC_OUTPUT
+ )
+ self.connect_mock.return_value.nodes.return_value.qemu.return_value.get.return_value = (
+ RAW_QEMU_OUTPUT
+ )
+ self.connect_mock.return_value.cluster.return_value.resources.return_value.get.return_value = (
+ RAW_CLUSTER_OUTPUT
+ )
+ self.connect_mock.return_value.nodes.get.return_value = [{"node": NODE1}]
+
+ def tearDown(self):
+ self.connect_mock.stop()
+ super(TestProxmoxVmInfoModule, self).tearDown()
+
+ def test_module_fail_when_required_args_missing(self):
+ with pytest.raises(AnsibleFailJson) as exc_info:
+ set_module_args({})
+ self.module.main()
+
+ result = exc_info.value.args[0]
+ assert result["msg"] == "missing required arguments: api_host, api_user"
+
+ def test_get_lxc_vms_information(self):
+ with pytest.raises(AnsibleExitJson) as exc_info:
+ set_module_args(get_module_args(type="lxc"))
+ expected_output = [vm for vm in EXPECTED_VMS_OUTPUT if vm["type"] == "lxc"]
+ self.module.main()
+
+ result = exc_info.value.args[0]
+ assert result["changed"] is False
+ assert result["proxmox_vms"] == expected_output
+
+ def test_get_qemu_vms_information(self):
+ with pytest.raises(AnsibleExitJson) as exc_info:
+ set_module_args(get_module_args(type="qemu"))
+ expected_output = [vm for vm in EXPECTED_VMS_OUTPUT if vm["type"] == "qemu"]
+ self.module.main()
+
+ result = exc_info.value.args[0]
+ assert result["proxmox_vms"] == expected_output
+
+ def test_get_all_vms_information(self):
+ with pytest.raises(AnsibleExitJson) as exc_info:
+ set_module_args(get_module_args())
+ self.module.main()
+
+ result = exc_info.value.args[0]
+ assert result["proxmox_vms"] == EXPECTED_VMS_OUTPUT
+
+ def test_vmid_is_converted_to_int(self):
+ with pytest.raises(AnsibleExitJson) as exc_info:
+ set_module_args(get_module_args(type="lxc"))
+ self.module.main()
+
+ result = exc_info.value.args[0]
+ assert isinstance(result["proxmox_vms"][0]["vmid"], int)
+
+ def test_get_specific_lxc_vm_information(self):
+ with pytest.raises(AnsibleExitJson) as exc_info:
+ vmid = 102
+ expected_output = [
+ vm
+ for vm in EXPECTED_VMS_OUTPUT
+ if vm["vmid"] == vmid and vm["type"] == "lxc"
+ ]
+ set_module_args(get_module_args(type="lxc", vmid=vmid))
+ self.module.main()
+
+ result = exc_info.value.args[0]
+ assert result["proxmox_vms"] == expected_output
+ assert len(result["proxmox_vms"]) == 1
+
+ def test_get_specific_qemu_vm_information(self):
+ with pytest.raises(AnsibleExitJson) as exc_info:
+ vmid = 100
+ expected_output = [
+ vm
+ for vm in EXPECTED_VMS_OUTPUT
+ if vm["vmid"] == vmid and vm["type"] == "qemu"
+ ]
+ set_module_args(get_module_args(type="qemu", vmid=vmid))
+ self.module.main()
+
+ result = exc_info.value.args[0]
+ assert result["proxmox_vms"] == expected_output
+ assert len(result["proxmox_vms"]) == 1
+
+ def test_get_specific_vm_information(self):
+ with pytest.raises(AnsibleExitJson) as exc_info:
+ vmid = 100
+ expected_output = [vm for vm in EXPECTED_VMS_OUTPUT if vm["vmid"] == vmid]
+ set_module_args(get_module_args(type="all", vmid=vmid))
+ self.module.main()
+
+ result = exc_info.value.args[0]
+ assert result["proxmox_vms"] == expected_output
+ assert len(result["proxmox_vms"]) == 1
+
+ def test_get_specific_vm_information_by_using_name(self):
+ name = "test1-lxc.home.arpa"
+ self.connect_mock.return_value.cluster.resources.get.return_value = [
+ {"name": name, "vmid": "103"}
+ ]
+
+ with pytest.raises(AnsibleExitJson) as exc_info:
+ expected_output = [vm for vm in EXPECTED_VMS_OUTPUT if vm["name"] == name]
+ set_module_args(get_module_args(type="all", name=name))
+ self.module.main()
+
+ result = exc_info.value.args[0]
+ assert result["proxmox_vms"] == expected_output
+ assert len(result["proxmox_vms"]) == 1
+
+ def test_get_multiple_vms_with_the_same_name(self):
+ name = "test-lxc.home.arpa"
+ self.connect_mock.return_value.cluster.resources.get.return_value = [
+ {"name": name, "vmid": "102"},
+ {"name": name, "vmid": "104"},
+ ]
+
+ with pytest.raises(AnsibleExitJson) as exc_info:
+ expected_output = [vm for vm in EXPECTED_VMS_OUTPUT if vm["name"] == name]
+ set_module_args(get_module_args(type="all", name=name))
+ self.module.main()
+
+ result = exc_info.value.args[0]
+ assert result["proxmox_vms"] == expected_output
+ assert len(result["proxmox_vms"]) == 2
+
+ def test_get_vm_with_an_empty_name(self):
+ name = ""
+ self.connect_mock.return_value.cluster.resources.get.return_value = [
+ {"name": name, "vmid": "105"},
+ ]
+
+ with pytest.raises(AnsibleExitJson) as exc_info:
+ expected_output = [vm for vm in EXPECTED_VMS_OUTPUT if vm["name"] == name]
+ set_module_args(get_module_args(type="all", name=name))
+ self.module.main()
+
+ result = exc_info.value.args[0]
+ assert result["proxmox_vms"] == expected_output
+ assert len(result["proxmox_vms"]) == 1
+
+ def test_get_all_lxc_vms_from_specific_node(self):
+ with pytest.raises(AnsibleExitJson) as exc_info:
+ expected_output = [
+ vm
+ for vm in EXPECTED_VMS_OUTPUT
+ if vm["node"] == NODE1 and vm["type"] == "lxc"
+ ]
+ set_module_args(get_module_args(type="lxc", node=NODE1))
+ self.module.main()
+
+ result = exc_info.value.args[0]
+ assert result["proxmox_vms"] == expected_output
+ assert len(result["proxmox_vms"]) == 1
+
+ def test_get_all_qemu_vms_from_specific_node(self):
+ with pytest.raises(AnsibleExitJson) as exc_info:
+ expected_output = [
+ vm
+ for vm in EXPECTED_VMS_OUTPUT
+ if vm["node"] == NODE1 and vm["type"] == "qemu"
+ ]
+ set_module_args(get_module_args(type="qemu", node=NODE1))
+ self.module.main()
+
+ result = exc_info.value.args[0]
+ assert result["proxmox_vms"] == expected_output
+ assert len(result["proxmox_vms"]) == 1
+
+ def test_get_all_vms_from_specific_node(self):
+ with pytest.raises(AnsibleExitJson) as exc_info:
+ expected_output = [vm for vm in EXPECTED_VMS_OUTPUT if vm["node"] == NODE1]
+ set_module_args(get_module_args(node=NODE1))
+ self.module.main()
+
+ result = exc_info.value.args[0]
+ assert result["proxmox_vms"] == expected_output
+ assert len(result["proxmox_vms"]) == 2
+
+ def test_module_returns_empty_list_when_vm_does_not_exist(self):
+ with pytest.raises(AnsibleExitJson) as exc_info:
+ vmid = 200
+ set_module_args(get_module_args(type="all", vmid=vmid))
+ self.module.main()
+
+ result = exc_info.value.args[0]
+ assert result["proxmox_vms"] == []
+
+ def test_module_fail_when_qemu_request_fails(self):
+ self.connect_mock.return_value.nodes.return_value.qemu.return_value.get.side_effect = IOError(
+ "Some mocked connection error."
+ )
+ with pytest.raises(AnsibleFailJson) as exc_info:
+ set_module_args(get_module_args(type="qemu"))
+ self.module.main()
+
+ result = exc_info.value.args[0]
+ assert "Failed to retrieve QEMU VMs information:" in result["msg"]
+
+ def test_module_fail_when_lxc_request_fails(self):
+ self.connect_mock.return_value.nodes.return_value.lxc.return_value.get.side_effect = IOError(
+ "Some mocked connection error."
+ )
+ with pytest.raises(AnsibleFailJson) as exc_info:
+ set_module_args(get_module_args(type="lxc"))
+ self.module.main()
+
+ result = exc_info.value.args[0]
+ assert "Failed to retrieve LXC VMs information:" in result["msg"]
+
+ def test_module_fail_when_cluster_resources_request_fails(self):
+ self.connect_mock.return_value.cluster.return_value.resources.return_value.get.side_effect = IOError(
+ "Some mocked connection error."
+ )
+ with pytest.raises(AnsibleFailJson) as exc_info:
+ set_module_args(get_module_args())
+ self.module.main()
+
+ result = exc_info.value.args[0]
+ assert (
+ "Failed to retrieve VMs information from cluster resources:"
+ in result["msg"]
+ )
+
+ def test_module_fail_when_node_does_not_exist(self):
+ with pytest.raises(AnsibleFailJson) as exc_info:
+ set_module_args(get_module_args(type="all", node="NODE3"))
+ self.module.main()
+
+ result = exc_info.value.args[0]
+ assert result["msg"] == "Node NODE3 doesn't exist in PVE cluster"
+
+ def test_call_to_get_vmid_is_not_used_when_vmid_provided(self):
+ with patch(
+ "ansible_collections.community.general.plugins.module_utils.proxmox.ProxmoxAnsible.get_vmid"
+ ) as get_vmid_mock:
+ with pytest.raises(AnsibleExitJson):
+ vmid = 100
+ set_module_args(
+ get_module_args(type="all", vmid=vmid, name="something")
+ )
+ self.module.main()
+
+ assert get_vmid_mock.call_count == 0
+
+ def test_config_returned_when_specified_qemu_vm_with_config(self):
+ config_vm_value = {
+ 'scsi0': 'local-lvm:vm-101-disk-0,iothread=1,size=32G',
+ 'net0': 'virtio=4E:79:9F:A8:EE:E4,bridge=vmbr0,firewall=1',
+ 'scsihw': 'virtio-scsi-single',
+ 'cores': 1,
+ 'name': 'test1',
+ 'ostype': 'l26',
+ 'boot': 'order=scsi0;ide2;net0',
+ 'memory': 2048,
+ 'sockets': 1,
+ }
+ (self.connect_mock.return_value.nodes.return_value.qemu.return_value.
+ config.return_value.get.return_value) = config_vm_value
+
+ with pytest.raises(AnsibleExitJson) as exc_info:
+ vmid = 101
+ set_module_args(get_module_args(
+ type="qemu",
+ vmid=vmid,
+ config="current",
+ ))
+ expected_output = [vm for vm in EXPECTED_VMS_OUTPUT if vm["vmid"] == vmid]
+ expected_output[0]["config"] = config_vm_value
+ self.module.main()
+
+ result = exc_info.value.args[0]
+ assert result["proxmox_vms"] == expected_output
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_puppet.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_puppet.py
index f62523e7f..57f88ada1 100644
--- a/ansible_collections/community/general/tests/unit/plugins/modules/test_puppet.py
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_puppet.py
@@ -12,216 +12,9 @@
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
-import json
-from collections import namedtuple
from ansible_collections.community.general.plugins.modules import puppet
+from .helper import Helper
-import pytest
-TESTED_MODULE = puppet.__name__
-
-
-ModuleTestCase = namedtuple("ModuleTestCase", ["id", "input", "output", "run_command_calls"])
-RunCmdCall = namedtuple("RunCmdCall", ["command", "environ", "rc", "out", "err"])
-
-
-@pytest.fixture
-def patch_get_bin_path(mocker):
- """
- Function used for mocking AnsibleModule.get_bin_path
- """
- def mockie(self, path, *args, **kwargs):
- return "/testbin/{0}".format(path)
- mocker.patch("ansible.module_utils.basic.AnsibleModule.get_bin_path", mockie)
-
-
-TEST_CASES = [
- ModuleTestCase(
- id="puppet_agent_plain",
- input={},
- output=dict(changed=False),
- run_command_calls=[
- RunCmdCall(
- command=["/testbin/puppet", "config", "print", "agent_disabled_lockfile"],
- environ={'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
- rc=0,
- out="blah, anything",
- err="",
- ),
- RunCmdCall(
- command=[
- "/testbin/timeout", "-s", "9", "30m", "/testbin/puppet", "agent", "--onetime", "--no-daemonize",
- "--no-usecacheonfailure", "--no-splay", "--detailed-exitcodes", "--verbose", "--color", "0"
- ],
- environ={'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
- rc=0,
- out="",
- err="",
- ),
- ]
- ),
- ModuleTestCase(
- id="puppet_agent_certname",
- input={"certname": "potatobox"},
- output=dict(changed=False),
- run_command_calls=[
- RunCmdCall(
- command=["/testbin/puppet", "config", "print", "agent_disabled_lockfile"],
- environ={'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
- rc=0,
- out="blah, anything",
- err="",
- ),
- RunCmdCall(
- command=[
- "/testbin/timeout", "-s", "9", "30m", "/testbin/puppet", "agent", "--onetime", "--no-daemonize",
- "--no-usecacheonfailure", "--no-splay", "--detailed-exitcodes", "--verbose", "--color", "0", "--certname=potatobox"
- ],
- environ={'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
- rc=0,
- out="",
- err="",
- ),
- ]
- ),
- ModuleTestCase(
- id="puppet_agent_tags_abc",
- input={"tags": ["a", "b", "c"]},
- output=dict(changed=False),
- run_command_calls=[
- RunCmdCall(
- command=["/testbin/puppet", "config", "print", "agent_disabled_lockfile"],
- environ={'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
- rc=0,
- out="blah, anything",
- err="",
- ),
- RunCmdCall(
- command=[
- "/testbin/timeout", "-s", "9", "30m", "/testbin/puppet", "agent", "--onetime", "--no-daemonize",
- "--no-usecacheonfailure", "--no-splay", "--detailed-exitcodes", "--verbose", "--color", "0", "--tags", "a,b,c"
- ],
- environ={'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
- rc=0,
- out="",
- err="",
- ),
- ]
- ),
- ModuleTestCase(
- id="puppet_agent_skip_tags_def",
- input={"skip_tags": ["d", "e", "f"]},
- output=dict(changed=False),
- run_command_calls=[
- RunCmdCall(
- command=["/testbin/puppet", "config", "print", "agent_disabled_lockfile"],
- environ={'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
- rc=0,
- out="blah, anything",
- err="",
- ),
- RunCmdCall(
- command=[
- "/testbin/timeout", "-s", "9", "30m", "/testbin/puppet", "agent", "--onetime", "--no-daemonize",
- "--no-usecacheonfailure", "--no-splay", "--detailed-exitcodes", "--verbose", "--color", "0", "--skip_tags", "d,e,f"
- ],
- environ={'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
- rc=0,
- out="",
- err="",
- ),
- ]
- ),
- ModuleTestCase(
- id="puppet_agent_noop_false",
- input={"noop": False},
- output=dict(changed=False),
- run_command_calls=[
- RunCmdCall(
- command=["/testbin/puppet", "config", "print", "agent_disabled_lockfile"],
- environ={'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
- rc=0,
- out="blah, anything",
- err="",
- ),
- RunCmdCall(
- command=[
- "/testbin/timeout", "-s", "9", "30m", "/testbin/puppet", "agent", "--onetime", "--no-daemonize",
- "--no-usecacheonfailure", "--no-splay", "--detailed-exitcodes", "--verbose", "--color", "0", "--no-noop"
- ],
- environ={'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
- rc=0,
- out="",
- err="",
- ),
- ]
- ),
- ModuleTestCase(
- id="puppet_agent_noop_true",
- input={"noop": True},
- output=dict(changed=False),
- run_command_calls=[
- RunCmdCall(
- command=["/testbin/puppet", "config", "print", "agent_disabled_lockfile"],
- environ={'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
- rc=0,
- out="blah, anything",
- err="",
- ),
- RunCmdCall(
- command=[
- "/testbin/timeout", "-s", "9", "30m", "/testbin/puppet", "agent", "--onetime", "--no-daemonize",
- "--no-usecacheonfailure", "--no-splay", "--detailed-exitcodes", "--verbose", "--color", "0", "--noop"
- ],
- environ={'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
- rc=0,
- out="",
- err="",
- ),
- ]
- ),
-]
-TEST_CASES_IDS = [item.id for item in TEST_CASES]
-
-
-@pytest.mark.parametrize("patch_ansible_module, testcase",
- [[x.input, x] for x in TEST_CASES],
- ids=TEST_CASES_IDS,
- indirect=["patch_ansible_module"])
-@pytest.mark.usefixtures("patch_ansible_module")
-def test_puppet(mocker, capfd, patch_get_bin_path, testcase):
- """
- Run unit tests for test cases listen in TEST_CASES
- """
-
- run_cmd_calls = testcase.run_command_calls
-
- # Mock function used for running commands first
- call_results = [(x.rc, x.out, x.err) for x in run_cmd_calls]
- mock_run_command = mocker.patch(
- "ansible.module_utils.basic.AnsibleModule.run_command",
- side_effect=call_results)
-
- # Try to run test case
- with pytest.raises(SystemExit):
- puppet.main()
-
- out, err = capfd.readouterr()
- results = json.loads(out)
- print("testcase =\n%s" % str(testcase))
- print("results =\n%s" % results)
-
- assert mock_run_command.call_count == len(run_cmd_calls)
- if mock_run_command.call_count:
- call_args_list = [(item[0][0], item[1]) for item in mock_run_command.call_args_list]
- expected_call_args_list = [(item.command, item.environ) for item in run_cmd_calls]
- print("call args list =\n%s" % call_args_list)
- print("expected args list =\n%s" % expected_call_args_list)
- assert call_args_list == expected_call_args_list
-
- assert results.get("changed", False) == testcase.output["changed"]
- if "failed" in testcase:
- assert results.get("failed", False) == testcase.output["failed"]
- if "msg" in testcase:
- assert results.get("msg", "") == testcase.output["msg"]
+Helper.from_module(puppet, __name__)
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_puppet.yaml b/ansible_collections/community/general/tests/unit/plugins/modules/test_puppet.yaml
new file mode 100644
index 000000000..308be9797
--- /dev/null
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_puppet.yaml
@@ -0,0 +1,192 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) Alexei Znamensky (russoz@gmail.com)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+---
+- id: puppet_agent_plain
+ input: {}
+ output:
+ changed: false
+ run_command_calls:
+ - command: [/testbin/puppet, config, print, agent_disabled_lockfile]
+ environ: &env-def {environ_update: {LANGUAGE: C, LC_ALL: C}, check_rc: false}
+ rc: 0
+ out: "blah, anything"
+ err: ""
+ - command:
+ - /testbin/timeout
+ - -s
+ - "9"
+ - 30m
+ - /testbin/puppet
+ - agent
+ - --onetime
+ - --no-daemonize
+ - --no-usecacheonfailure
+ - --no-splay
+ - --detailed-exitcodes
+ - --verbose
+ - --color
+ - "0"
+ environ: *env-def
+ rc: 0
+ out: ""
+ err: ""
+- id: puppet_agent_certname
+ input:
+ certname: potatobox
+ output:
+ changed: false
+ run_command_calls:
+ - command: [/testbin/puppet, config, print, agent_disabled_lockfile]
+ environ: *env-def
+ rc: 0
+ out: "blah, anything"
+ err: ""
+ - command:
+ - /testbin/timeout
+ - -s
+ - "9"
+ - 30m
+ - /testbin/puppet
+ - agent
+ - --onetime
+ - --no-daemonize
+ - --no-usecacheonfailure
+ - --no-splay
+ - --detailed-exitcodes
+ - --verbose
+ - --color
+ - "0"
+ - --certname=potatobox
+ environ: *env-def
+ rc: 0
+ out: ""
+ err: ""
+- id: puppet_agent_tags_abc
+ input:
+ tags: [a, b, c]
+ output:
+ changed: false
+ run_command_calls:
+ - command: [/testbin/puppet, config, print, agent_disabled_lockfile]
+ environ: *env-def
+ rc: 0
+ out: "blah, anything"
+ err: ""
+ - command:
+ - /testbin/timeout
+ - -s
+ - "9"
+ - 30m
+ - /testbin/puppet
+ - agent
+ - --onetime
+ - --no-daemonize
+ - --no-usecacheonfailure
+ - --no-splay
+ - --detailed-exitcodes
+ - --verbose
+ - --color
+ - "0"
+ - --tags
+ - a,b,c
+ environ: *env-def
+ rc: 0
+ out: ""
+ err: ""
+- id: puppet_agent_skip_tags_def
+ input:
+ skip_tags: [d, e, f]
+ output:
+ changed: false
+ run_command_calls:
+ - command: [/testbin/puppet, config, print, agent_disabled_lockfile]
+ environ: *env-def
+ rc: 0
+ out: "blah, anything"
+ err: ""
+ - command:
+ - /testbin/timeout
+ - -s
+ - "9"
+ - 30m
+ - /testbin/puppet
+ - agent
+ - --onetime
+ - --no-daemonize
+ - --no-usecacheonfailure
+ - --no-splay
+ - --detailed-exitcodes
+ - --verbose
+ - --color
+ - "0"
+ - --skip_tags
+ - d,e,f
+ environ: *env-def
+ rc: 0
+ out: ""
+ err: ""
+- id: puppet_agent_noop_false
+ input:
+ noop: false
+ output:
+ changed: false
+ run_command_calls:
+ - command: [/testbin/puppet, config, print, agent_disabled_lockfile]
+ environ: *env-def
+ rc: 0
+ out: "blah, anything"
+ err: ""
+ - command:
+ - /testbin/timeout
+ - -s
+ - "9"
+ - 30m
+ - /testbin/puppet
+ - agent
+ - --onetime
+ - --no-daemonize
+ - --no-usecacheonfailure
+ - --no-splay
+ - --detailed-exitcodes
+ - --verbose
+ - --color
+ - "0"
+ - --no-noop
+ environ: *env-def
+ rc: 0
+ out: ""
+ err: ""
+- id: puppet_agent_noop_true
+ input:
+ noop: true
+ output:
+ changed: false
+ run_command_calls:
+ - command: [/testbin/puppet, config, print, agent_disabled_lockfile]
+ environ: *env-def
+ rc: 0
+ out: "blah, anything"
+ err: ""
+ - command:
+ - /testbin/timeout
+ - -s
+ - "9"
+ - 30m
+ - /testbin/puppet
+ - agent
+ - --onetime
+ - --no-daemonize
+ - --no-usecacheonfailure
+ - --no-splay
+ - --detailed-exitcodes
+ - --verbose
+ - --color
+ - "0"
+ - --noop
+ environ: *env-def
+ rc: 0
+ out: ""
+ err: ""
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_redhat_subscription.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_redhat_subscription.py
index 4bf272916..9473d0d46 100644
--- a/ansible_collections/community/general/tests/unit/plugins/modules/test_redhat_subscription.py
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_redhat_subscription.py
@@ -22,13 +22,15 @@ def patch_redhat_subscription(mocker):
"""
Function used for mocking some parts of redhat_subscription module
"""
- mocker.patch('ansible_collections.community.general.plugins.modules.redhat_subscription.RegistrationBase.REDHAT_REPO')
+ mocker.patch('ansible_collections.community.general.plugins.modules.redhat_subscription.Rhsm.REDHAT_REPO')
mocker.patch('ansible_collections.community.general.plugins.modules.redhat_subscription.isfile', return_value=False)
mocker.patch('ansible_collections.community.general.plugins.modules.redhat_subscription.unlink', return_value=True)
mocker.patch('ansible_collections.community.general.plugins.modules.redhat_subscription.AnsibleModule.get_bin_path',
return_value='/testbin/subscription-manager')
mocker.patch('ansible_collections.community.general.plugins.modules.redhat_subscription.Rhsm._can_connect_to_dbus',
return_value=False)
+ mocker.patch('ansible_collections.community.general.plugins.modules.redhat_subscription.Rhsm._has_dbus_interface',
+ return_value=False)
mocker.patch('ansible_collections.community.general.plugins.modules.redhat_subscription.getuid',
return_value=0)
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_redis_info.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_redis_info.py
index 8b30a2316..cdc78680e 100644
--- a/ansible_collections/community/general/tests/unit/plugins/modules/test_redis_info.py
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_redis_info.py
@@ -50,7 +50,12 @@ class TestRedisInfoModule(ModuleTestCase):
set_module_args({})
self.module.main()
self.assertEqual(redis_client.call_count, 1)
- self.assertEqual(redis_client.call_args, ({'host': 'localhost', 'port': 6379, 'password': None},))
+ self.assertEqual(redis_client.call_args, ({'host': 'localhost',
+ 'port': 6379,
+ 'password': None,
+ 'ssl': False,
+ 'ssl_ca_certs': None,
+ 'ssl_cert_reqs': 'required'},))
self.assertEqual(result.exception.args[0]['info']['redis_version'], '999.999.999')
def test_with_parameters(self):
@@ -64,7 +69,34 @@ class TestRedisInfoModule(ModuleTestCase):
})
self.module.main()
self.assertEqual(redis_client.call_count, 1)
- self.assertEqual(redis_client.call_args, ({'host': 'test', 'port': 1234, 'password': 'PASS'},))
+ self.assertEqual(redis_client.call_args, ({'host': 'test',
+ 'port': 1234,
+ 'password': 'PASS',
+ 'ssl': False,
+ 'ssl_ca_certs': None,
+ 'ssl_cert_reqs': 'required'},))
+ self.assertEqual(result.exception.args[0]['info']['redis_version'], '999.999.999')
+
+ def test_with_tls_parameters(self):
+ """Test with tls parameters"""
+ with self.patch_redis_client(side_effect=FakeRedisClient) as redis_client:
+ with self.assertRaises(AnsibleExitJson) as result:
+ set_module_args({
+ 'login_host': 'test',
+ 'login_port': 1234,
+ 'login_password': 'PASS',
+ 'tls': True,
+ 'ca_certs': '/etc/ssl/ca.pem',
+ 'validate_certs': False
+ })
+ self.module.main()
+ self.assertEqual(redis_client.call_count, 1)
+ self.assertEqual(redis_client.call_args, ({'host': 'test',
+ 'port': 1234,
+ 'password': 'PASS',
+ 'ssl': True,
+ 'ssl_ca_certs': '/etc/ssl/ca.pem',
+ 'ssl_cert_reqs': None},))
self.assertEqual(result.exception.args[0]['info']['redis_version'], '999.999.999')
def test_with_fail_client(self):
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_rhsm_release.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_rhsm_release.py
index c5696962b..e8b2db6fd 100644
--- a/ansible_collections/community/general/tests/unit/plugins/modules/test_rhsm_release.py
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_rhsm_release.py
@@ -14,6 +14,8 @@ from ansible_collections.community.general.tests.unit.plugins.modules.utils impo
class RhsmRepositoryReleaseModuleTestCase(ModuleTestCase):
module = rhsm_release
+ SUBMAN_KWARGS = dict(check_rc=True, expand_user_and_vars=False)
+
def setUp(self):
super(RhsmRepositoryReleaseModuleTestCase, self).setUp()
@@ -63,8 +65,8 @@ class RhsmRepositoryReleaseModuleTestCase(ModuleTestCase):
self.assertTrue(result['changed'])
self.assertEqual('7.5', result['current_release'])
self.module_main_command.assert_has_calls([
- call('/testbin/subscription-manager release --show', check_rc=True),
- call('/testbin/subscription-manager release --set 7.5', check_rc=True),
+ call(['/testbin/subscription-manager', 'release', '--show'], **self.SUBMAN_KWARGS),
+ call(['/testbin/subscription-manager', 'release', '--set', '7.5'], **self.SUBMAN_KWARGS),
])
def test_release_set_idempotent(self):
@@ -81,7 +83,7 @@ class RhsmRepositoryReleaseModuleTestCase(ModuleTestCase):
self.assertFalse(result['changed'])
self.assertEqual('7.5', result['current_release'])
self.module_main_command.assert_has_calls([
- call('/testbin/subscription-manager release --show', check_rc=True),
+ call(['/testbin/subscription-manager', 'release', '--show'], **self.SUBMAN_KWARGS),
])
def test_release_unset(self):
@@ -100,8 +102,8 @@ class RhsmRepositoryReleaseModuleTestCase(ModuleTestCase):
self.assertTrue(result['changed'])
self.assertIsNone(result['current_release'])
self.module_main_command.assert_has_calls([
- call('/testbin/subscription-manager release --show', check_rc=True),
- call('/testbin/subscription-manager release --unset', check_rc=True),
+ call(['/testbin/subscription-manager', 'release', '--show'], **self.SUBMAN_KWARGS),
+ call(['/testbin/subscription-manager', 'release', '--unset'], **self.SUBMAN_KWARGS),
])
def test_release_unset_idempotent(self):
@@ -118,7 +120,7 @@ class RhsmRepositoryReleaseModuleTestCase(ModuleTestCase):
self.assertFalse(result['changed'])
self.assertIsNone(result['current_release'])
self.module_main_command.assert_has_calls([
- call('/testbin/subscription-manager release --show', check_rc=True),
+ call(['/testbin/subscription-manager', 'release', '--show'], **self.SUBMAN_KWARGS),
])
def test_release_insane(self):
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_rhsm_repository.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_rhsm_repository.py
new file mode 100644
index 000000000..e822c7e84
--- /dev/null
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_rhsm_repository.py
@@ -0,0 +1,833 @@
+# -*- coding: utf-8 -*-
+# Author: Pino Toscano (ptoscano@redhat.com)
+# Largely adapted from test_rhsm_repository by
+# Jiri Hnidek (jhnidek@redhat.com)
+#
+# Copyright (c) Pino Toscano (ptoscano@redhat.com)
+# Copyright (c) Jiri Hnidek (jhnidek@redhat.com)
+#
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import copy
+import fnmatch
+import itertools
+import json
+
+from ansible.module_utils import basic
+from ansible_collections.community.general.plugins.modules import rhsm_repository
+
+import pytest
+
+TESTED_MODULE = rhsm_repository.__name__
+
+
+@pytest.fixture
+def patch_rhsm_repository(mocker):
+ """
+ Function used for mocking some parts of rhsm_repository module
+ """
+ mocker.patch('ansible_collections.community.general.plugins.modules.rhsm_repository.AnsibleModule.get_bin_path',
+ return_value='/testbin/subscription-manager')
+ mocker.patch('ansible_collections.community.general.plugins.modules.rhsm_repository.os.getuid',
+ return_value=0)
+
+
+class Repos(object):
+ """
+ Helper class to represent a list of repositories
+
+ Each repository is an object with few properties.
+ """
+
+ _SUBMAN_OUT_HEADER = """+----------------------------------------------------------+
+ Available Repositories in /etc/yum.repos.d/redhat.repo
++----------------------------------------------------------+
+"""
+ _SUBMAN_OUT_ENTRY = """Repo ID: %s
+Repo Name: %s
+Repo URL: %s
+Enabled: %s
+
+"""
+
+ def __init__(self, repos):
+ self.repos = repos
+
+ def to_subman_list_output(self):
+ """
+ Return a string mimicking the output of `subscription-manager repos --list`
+ """
+ out = self._SUBMAN_OUT_HEADER
+ for repo in self.repos:
+ out += self._SUBMAN_OUT_ENTRY % (
+ repo["id"],
+ repo["name"],
+ repo["url"],
+ "1" if repo["enabled"] else "0",
+ )
+
+ return out
+
+ def copy(self):
+ """
+ Clone the object; used to do changes (enable(), disable()) without
+ affecting the original object.
+ """
+ return copy.deepcopy(self)
+
+ def _set_status(self, repo_id, status):
+ for repo in self.repos:
+ if fnmatch.fnmatch(repo['id'], repo_id):
+ repo['enabled'] = status
+
+ def enable(self, repo_ids):
+ """
+ Enable the specified IDs.
+
+ 'repo_ids' can be either a string or a list of strings representing
+ an ID (wildcard included).
+
+ Returns the same object, so calls to this can be chained.
+ """
+ if not isinstance(repo_ids, list):
+ repo_ids = [repo_ids]
+ for repo_id in repo_ids:
+ self._set_status(repo_id, True)
+ return self
+
+ def disable(self, repo_ids):
+ """
+ Disable the specified IDs.
+
+ 'repo_ids' can be either a string or a list of strings representing
+ an ID (wildcard included).
+
+ Returns the same object, so calls to this can be chained.
+ """
+ if not isinstance(repo_ids, list):
+ repo_ids = [repo_ids]
+ for repo_id in repo_ids:
+ self._set_status(repo_id, False)
+ return self
+
+ def _filter_by_status(self, filter, status):
+ return [
+ repo['id']
+ for repo in self.repos
+ if repo['enabled'] == status and fnmatch.fnmatch(repo['id'], filter)
+ ]
+
+ def ids_enabled(self, filter='*'):
+ """
+ Get a list with the enabled repositories.
+
+ 'filter' is a wildcard expression.
+ """
+ return self._filter_by_status(filter, True)
+
+ def ids_disabled(self, filter='*'):
+ """
+ Get a list with the disabled repositories.
+
+ 'filter' is a wildcard expression.
+ """
+ return self._filter_by_status(filter, False)
+
+ def to_list(self):
+ """
+ Get the list of repositories.
+ """
+ return self.repos
+
+
+def flatten(iter_of_iters):
+ return list(itertools.chain.from_iterable(iter_of_iters))
+
+
+# List with test repositories, directly from the Candlepin test data.
+REPOS_LIST = [
+ {
+ "id": "never-enabled-content-801",
+ "name": "never-enabled-content-801",
+ "url": "https://candlepin.local/foo/path/never_enabled/801-100",
+ "enabled": False,
+ },
+ {
+ "id": "never-enabled-content-100000000000060",
+ "name": "never-enabled-content-100000000000060",
+ "url": "https://candlepin.local/foo/path/never_enabled/100000000000060-100",
+ "enabled": False,
+ },
+ {
+ "id": "awesomeos-x86_64-1000000000000023",
+ "name": "awesomeos-x86_64-1000000000000023",
+ "url": "https://candlepin.local/path/to/awesomeos/x86_64/1000000000000023-11124",
+ "enabled": False,
+ },
+ {
+ "id": "awesomeos-ppc64-100000000000011",
+ "name": "awesomeos-ppc64-100000000000011",
+ "url": "https://candlepin.local/path/to/awesomeos/ppc64/100000000000011-11126",
+ "enabled": False,
+ },
+ {
+ "id": "awesomeos-99000",
+ "name": "awesomeos-99000",
+ "url": "https://candlepin.local/path/to/generic/awesomeos/99000-11113",
+ "enabled": True,
+ },
+ {
+ "id": "content-label-27060",
+ "name": "content-27060",
+ "url": "https://candlepin.local/foo/path/common/27060-1111",
+ "enabled": True,
+ },
+ {
+ "id": "content-label-no-gpg-32060",
+ "name": "content-nogpg-32060",
+ "url": "https://candlepin.local/foo/path/no_gpg/32060-234",
+ "enabled": False,
+ },
+ {
+ "id": "awesomeos-1000000000000023",
+ "name": "awesomeos-1000000000000023",
+ "url": "https://candlepin.local/path/to/generic/awesomeos/1000000000000023-11113",
+ "enabled": False,
+ },
+ {
+ "id": "awesomeos-x86-100000000000020",
+ "name": "awesomeos-x86-100000000000020",
+ "url": "https://candlepin.local/path/to/awesomeos/x86/100000000000020-11120",
+ "enabled": False,
+ },
+ {
+ "id": "awesomeos-x86_64-99000",
+ "name": "awesomeos-x86_64-99000",
+ "url": "https://candlepin.local/path/to/awesomeos/x86_64/99000-11124",
+ "enabled": True,
+ },
+ {
+ "id": "awesomeos-s390x-99000",
+ "name": "awesomeos-s390x-99000",
+ "url": "https://candlepin.local/path/to/awesomeos/s390x/99000-11121",
+ "enabled": False,
+ },
+ {
+ "id": "awesomeos-modifier-37080",
+ "name": "awesomeos-modifier-37080",
+ "url": "https://candlepin.local/example.com/awesomeos-modifier/37080-1112",
+ "enabled": False,
+ },
+ {
+ "id": "awesomeos-i686-99000",
+ "name": "awesomeos-i686-99000",
+ "url": "https://candlepin.local/path/to/awesomeos/i686/99000-11123",
+ "enabled": False,
+ },
+ {
+ "id": "fake-content-38072",
+ "name": "fake-content-38072",
+ "url": "https://candlepin.local/path/to/fake-content/38072-3902",
+ "enabled": True,
+ },
+]
+
+
+# A static object with the list of repositories, used as reference to query
+# the repositories, and create (by copy()) new Repos objects.
+REPOS = Repos(REPOS_LIST)
+
+# The mock string for the output of `subscription-manager repos --list`.
+REPOS_LIST_OUTPUT = REPOS.to_subman_list_output()
+
+# MUST match what's in the Rhsm class in the module.
+SUBMAN_KWARGS = {
+ 'environ_update': dict(LANG='C', LC_ALL='C', LC_MESSAGES='C'),
+ 'expand_user_and_vars': False,
+ 'use_unsafe_shell': False,
+}
+
+
+TEST_CASES = [
+ # enable a disabled repository
+ [
+ {
+ 'name': 'awesomeos-1000000000000023',
+ },
+ {
+ 'id': 'test_enable_single',
+ 'run_command.calls': [
+ (
+ [
+ '/testbin/subscription-manager',
+ 'repos',
+ '--list',
+ ],
+ SUBMAN_KWARGS,
+ (0, REPOS_LIST_OUTPUT, '')
+ ),
+ (
+ [
+ '/testbin/subscription-manager',
+ 'repos',
+ '--enable',
+ 'awesomeos-1000000000000023',
+ ],
+ SUBMAN_KWARGS,
+ (0, '', '')
+ ),
+ ],
+ 'changed': True,
+ 'repositories': REPOS.copy().enable('awesomeos-1000000000000023'),
+ }
+ ],
+ # enable an already enabled repository
+ [
+ {
+ 'name': 'fake-content-38072',
+ },
+ {
+ 'id': 'test_enable_already_enabled',
+ 'run_command.calls': [
+ (
+ [
+ '/testbin/subscription-manager',
+ 'repos',
+ '--list',
+ ],
+ SUBMAN_KWARGS,
+ (0, REPOS_LIST_OUTPUT, '')
+ ),
+ ],
+ 'changed': False,
+ 'repositories': REPOS.copy(),
+ }
+ ],
+ # enable two disabled repositories
+ [
+ {
+ 'name': ['awesomeos-1000000000000023', 'content-label-no-gpg-32060'],
+ },
+ {
+ 'id': 'test_enable_multiple',
+ 'run_command.calls': [
+ (
+ [
+ '/testbin/subscription-manager',
+ 'repos',
+ '--list',
+ ],
+ SUBMAN_KWARGS,
+ (0, REPOS_LIST_OUTPUT, '')
+ ),
+ (
+ [
+ '/testbin/subscription-manager',
+ 'repos',
+ '--enable',
+ 'awesomeos-1000000000000023',
+ '--enable',
+ 'content-label-no-gpg-32060',
+ ],
+ SUBMAN_KWARGS,
+ (0, '', '')
+ ),
+ ],
+ 'changed': True,
+ 'repositories': REPOS.copy().enable('awesomeos-1000000000000023').enable('content-label-no-gpg-32060'),
+ }
+ ],
+ # enable two repositories, one disabled and one already enabled
+ [
+ {
+ 'name': ['awesomeos-1000000000000023', 'fake-content-38072'],
+ },
+ {
+ 'id': 'test_enable_multiple_mixed',
+ 'run_command.calls': [
+ (
+ [
+ '/testbin/subscription-manager',
+ 'repos',
+ '--list',
+ ],
+ SUBMAN_KWARGS,
+ (0, REPOS_LIST_OUTPUT, '')
+ ),
+ (
+ [
+ '/testbin/subscription-manager',
+ 'repos',
+ '--enable',
+ 'awesomeos-1000000000000023',
+ '--enable',
+ 'fake-content-38072',
+ ],
+ SUBMAN_KWARGS,
+ (0, '', '')
+ ),
+ ],
+ 'changed': True,
+ 'repositories': REPOS.copy().enable('awesomeos-1000000000000023'),
+ }
+ ],
+ # purge everything but never-enabled-content-801 (disabled)
+ [
+ {
+ 'name': 'never-enabled-content-801',
+ 'purge': True,
+ },
+ {
+ 'id': 'test_purge_everything_but_one_disabled',
+ 'run_command.calls': [
+ (
+ [
+ '/testbin/subscription-manager',
+ 'repos',
+ '--list',
+ ],
+ SUBMAN_KWARGS,
+ (0, REPOS_LIST_OUTPUT, '')
+ ),
+ (
+ [
+ '/testbin/subscription-manager',
+ 'repos',
+ '--enable',
+ 'never-enabled-content-801',
+ ] + flatten([['--disable', i] for i in REPOS.ids_enabled() if i != 'never-enabled-content-801']),
+ SUBMAN_KWARGS,
+ (0, '', '')
+ ),
+ ],
+ 'changed': True,
+ 'repositories': REPOS.copy().disable('*').enable('never-enabled-content-801'),
+ }
+ ],
+ # purge everything but awesomeos-99000 (already enabled)
+ [
+ {
+ 'name': 'awesomeos-99000',
+ 'purge': True,
+ },
+ {
+ 'id': 'test_purge_everything_but_one_enabled',
+ 'run_command.calls': [
+ (
+ [
+ '/testbin/subscription-manager',
+ 'repos',
+ '--list',
+ ],
+ SUBMAN_KWARGS,
+ (0, REPOS_LIST_OUTPUT, '')
+ ),
+ (
+ [
+ '/testbin/subscription-manager',
+ 'repos',
+ '--enable',
+ 'awesomeos-99000',
+ '--disable',
+ 'content-label-27060',
+ '--disable',
+ 'awesomeos-x86_64-99000',
+ '--disable',
+ 'fake-content-38072',
+ ],
+ SUBMAN_KWARGS,
+ (0, '', '')
+ ),
+ ],
+ 'changed': True,
+ 'repositories': REPOS.copy().disable('*').enable('awesomeos-99000'),
+ }
+ ],
+ # enable everything, then purge everything but content-label-27060
+ [
+ {
+ 'name': 'content-label-27060',
+ 'purge': True,
+ },
+ {
+ 'id': 'test_enable_everything_purge_everything_but_one_enabled',
+ 'run_command.calls': [
+ (
+ [
+ '/testbin/subscription-manager',
+ 'repos',
+ '--list',
+ ],
+ SUBMAN_KWARGS,
+ (0, REPOS.copy().enable('*').to_subman_list_output(), '')
+ ),
+ (
+ [
+ '/testbin/subscription-manager',
+ 'repos',
+ '--enable',
+ 'content-label-27060',
+ '--disable',
+ 'never-enabled-content-801',
+ '--disable',
+ 'never-enabled-content-100000000000060',
+ '--disable',
+ 'awesomeos-x86_64-1000000000000023',
+ '--disable',
+ 'awesomeos-ppc64-100000000000011',
+ '--disable',
+ 'awesomeos-99000',
+ '--disable',
+ 'content-label-no-gpg-32060',
+ '--disable',
+ 'awesomeos-1000000000000023',
+ '--disable',
+ 'awesomeos-x86-100000000000020',
+ '--disable',
+ 'awesomeos-x86_64-99000',
+ '--disable',
+ 'awesomeos-s390x-99000',
+ '--disable',
+ 'awesomeos-modifier-37080',
+ '--disable',
+ 'awesomeos-i686-99000',
+ '--disable',
+ 'fake-content-38072',
+ ],
+ SUBMAN_KWARGS,
+ (0, '', '')
+ ),
+ ],
+ 'changed': True,
+ 'repositories': REPOS.copy().disable('*').enable('content-label-27060'),
+ }
+ ],
+ # enable all awesomeos-*
+ [
+ {
+ 'name': 'awesomeos-*',
+ },
+ {
+ 'id': 'test_enable_all_awesomeos_star',
+ 'run_command.calls': [
+ (
+ [
+ '/testbin/subscription-manager',
+ 'repos',
+ '--list',
+ ],
+ SUBMAN_KWARGS,
+ (0, REPOS_LIST_OUTPUT, '')
+ ),
+ (
+ [
+ '/testbin/subscription-manager',
+ 'repos',
+ '--enable',
+ 'awesomeos-x86_64-1000000000000023',
+ '--enable',
+ 'awesomeos-ppc64-100000000000011',
+ '--enable',
+ 'awesomeos-99000',
+ '--enable',
+ 'awesomeos-1000000000000023',
+ '--enable',
+ 'awesomeos-x86-100000000000020',
+ '--enable',
+ 'awesomeos-x86_64-99000',
+ '--enable',
+ 'awesomeos-s390x-99000',
+ '--enable',
+ 'awesomeos-modifier-37080',
+ '--enable',
+ 'awesomeos-i686-99000',
+ ],
+ SUBMAN_KWARGS,
+ (0, '', '')
+ ),
+ ],
+ 'changed': True,
+ 'repositories': REPOS.copy().enable('awesomeos-*'),
+ }
+ ],
+ # purge everything but awesomeos-*
+ [
+ {
+ 'name': REPOS.ids_enabled('awesomeos-*'),
+ 'purge': True,
+ },
+ {
+ 'id': 'test_purge_everything_but_awesomeos_list',
+ 'run_command.calls': [
+ (
+ [
+ '/testbin/subscription-manager',
+ 'repos',
+ '--list',
+ ],
+ SUBMAN_KWARGS,
+ (0, REPOS_LIST_OUTPUT, '')
+ ),
+ (
+ [
+ '/testbin/subscription-manager',
+ 'repos',
+ '--enable',
+ 'awesomeos-99000',
+ '--enable',
+ 'awesomeos-x86_64-99000',
+ '--disable',
+ 'content-label-27060',
+ '--disable',
+ 'fake-content-38072',
+ ],
+ SUBMAN_KWARGS,
+ (0, '', '')
+ ),
+ ],
+ 'changed': True,
+ 'repositories': REPOS.copy().disable('*').enable(REPOS.ids_enabled('awesomeos-*')),
+ }
+ ],
+ # enable a repository that does not exist
+ [
+ {
+ 'name': 'repo-that-does-not-exist',
+ },
+ {
+ 'id': 'test_enable_nonexisting',
+ 'run_command.calls': [
+ (
+ [
+ '/testbin/subscription-manager',
+ 'repos',
+ '--list',
+ ],
+ SUBMAN_KWARGS,
+ (0, REPOS_LIST_OUTPUT, '')
+ ),
+ ],
+ 'failed': True,
+ 'msg': 'repo-that-does-not-exist is not a valid repository ID',
+ }
+ ],
+ # disable an enabled repository
+ [
+ {
+ 'name': 'awesomeos-99000',
+ 'state': 'disabled',
+ },
+ {
+ 'id': 'test_disable_single',
+ 'run_command.calls': [
+ (
+ [
+ '/testbin/subscription-manager',
+ 'repos',
+ '--list',
+ ],
+ SUBMAN_KWARGS,
+ (0, REPOS_LIST_OUTPUT, '')
+ ),
+ (
+ [
+ '/testbin/subscription-manager',
+ 'repos',
+ '--disable',
+ 'awesomeos-99000',
+ ],
+ SUBMAN_KWARGS,
+ (0, '', '')
+ ),
+ ],
+ 'changed': True,
+ 'repositories': REPOS.copy().disable('awesomeos-99000'),
+ }
+ ],
+ # disable an enabled repository (using state=absent)
+ [
+ {
+ 'name': 'awesomeos-99000',
+ 'state': 'absent',
+ },
+ {
+ 'id': 'test_disable_single_using_absent',
+ 'run_command.calls': [
+ (
+ [
+ '/testbin/subscription-manager',
+ 'repos',
+ '--list',
+ ],
+ SUBMAN_KWARGS,
+ (0, REPOS_LIST_OUTPUT, '')
+ ),
+ (
+ [
+ '/testbin/subscription-manager',
+ 'repos',
+ '--disable',
+ 'awesomeos-99000',
+ ],
+ SUBMAN_KWARGS,
+ (0, '', '')
+ ),
+ ],
+ 'changed': True,
+ 'repositories': REPOS.copy().disable('awesomeos-99000'),
+ }
+ ],
+ # disable an already disabled repository
+ [
+ {
+ 'name': 'never-enabled-content-801',
+ 'state': 'disabled',
+ },
+ {
+ 'id': 'test_disable_already_disabled',
+ 'run_command.calls': [
+ (
+ [
+ '/testbin/subscription-manager',
+ 'repos',
+ '--list',
+ ],
+ SUBMAN_KWARGS,
+ (0, REPOS_LIST_OUTPUT, '')
+ ),
+ ],
+ 'changed': False,
+ 'repositories': REPOS.copy(),
+ }
+ ],
+ # disable an already disabled repository, and purge
+ [
+ {
+ 'name': 'never-enabled-content-801',
+ 'state': 'disabled',
+ 'purge': True,
+ },
+ {
+ 'id': 'test_disable_already_disabled_and_purge',
+ 'run_command.calls': [
+ (
+ [
+ '/testbin/subscription-manager',
+ 'repos',
+ '--list',
+ ],
+ SUBMAN_KWARGS,
+ (0, REPOS_LIST_OUTPUT, '')
+ ),
+ (
+ [
+ '/testbin/subscription-manager',
+ 'repos',
+ ] + flatten([['--disable', i] for i in REPOS.ids_enabled()]),
+ SUBMAN_KWARGS,
+ (0, '', '')
+ ),
+ ],
+ 'changed': True,
+ 'repositories': REPOS.copy().disable('*'),
+ }
+ ],
+ # disable an enabled repository, and purge
+ [
+ {
+ 'name': 'awesomeos-99000',
+ 'state': 'disabled',
+ 'purge': True,
+ },
+ {
+ 'id': 'test_disable_single_and_purge',
+ 'run_command.calls': [
+ (
+ [
+ '/testbin/subscription-manager',
+ 'repos',
+ '--list',
+ ],
+ SUBMAN_KWARGS,
+ (0, REPOS_LIST_OUTPUT, '')
+ ),
+ (
+ [
+ '/testbin/subscription-manager',
+ 'repos',
+ ] + flatten([['--disable', i] for i in REPOS.ids_enabled()]),
+ SUBMAN_KWARGS,
+ (0, '', '')
+ ),
+ ],
+ 'changed': True,
+ 'repositories': REPOS.copy().disable('*'),
+ }
+ ],
+ # disable a repository that does not exist
+ [
+ {
+ 'name': 'repo-that-does-not-exist',
+ 'state': 'disabled',
+ },
+ {
+ 'id': 'test_disable_nonexisting',
+ 'run_command.calls': [
+ (
+ [
+ '/testbin/subscription-manager',
+ 'repos',
+ '--list',
+ ],
+ SUBMAN_KWARGS,
+ (0, REPOS_LIST_OUTPUT, '')
+ ),
+ ],
+ 'failed': True,
+ 'msg': 'repo-that-does-not-exist is not a valid repository ID',
+ }
+ ],
+]
+
+
+TEST_CASES_IDS = [item[1]['id'] for item in TEST_CASES]
+
+
+@pytest.mark.parametrize('patch_ansible_module, testcase', TEST_CASES, ids=TEST_CASES_IDS, indirect=['patch_ansible_module'])
+@pytest.mark.usefixtures('patch_ansible_module')
+def test_rhsm_repository(mocker, capfd, patch_rhsm_repository, testcase):
+ """
+ Run unit tests for test cases listen in TEST_CASES
+ """
+
+ # Mock function used for running commands first
+ call_results = [item[2] for item in testcase['run_command.calls']]
+ mock_run_command = mocker.patch.object(
+ basic.AnsibleModule,
+ 'run_command',
+ side_effect=call_results)
+
+ # Try to run test case
+ with pytest.raises(SystemExit):
+ rhsm_repository.main()
+
+ out, err = capfd.readouterr()
+ results = json.loads(out)
+
+ if 'failed' in testcase:
+ assert results['failed'] == testcase['failed']
+ assert results['msg'] == testcase['msg']
+ else:
+ assert 'changed' in results
+ assert results['changed'] == testcase['changed']
+ assert results['repositories'] == testcase['repositories'].to_list()
+
+ assert basic.AnsibleModule.run_command.call_count == len(testcase['run_command.calls'])
+ # FIXME ideally we need also to compare the actual calls with the expected
+ # ones; the problem is that the module uses a dict to collect the repositories
+ # to enable and disable, so the order of the --enable/--disable parameters to
+ # `subscription-manager repos` is not stable
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_sap_task_list_execute.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_sap_task_list_execute.py
deleted file mode 100644
index 34c97c4a8..000000000
--- a/ansible_collections/community/general/tests/unit/plugins/modules/test_sap_task_list_execute.py
+++ /dev/null
@@ -1,91 +0,0 @@
-# Copyright (c) Ansible project
-# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
-# SPDX-License-Identifier: GPL-3.0-or-later
-
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import sys
-from ansible_collections.community.general.tests.unit.compat.mock import patch, MagicMock
-from ansible_collections.community.general.tests.unit.plugins.modules.utils import AnsibleExitJson, AnsibleFailJson, ModuleTestCase, set_module_args
-
-sys.modules['pyrfc'] = MagicMock()
-sys.modules['pyrfc.Connection'] = MagicMock()
-sys.modules['xmltodict'] = MagicMock()
-sys.modules['xmltodict.parse'] = MagicMock()
-
-from ansible_collections.community.general.plugins.modules import sap_task_list_execute
-
-
-class TestSAPRfcModule(ModuleTestCase):
-
- def setUp(self):
- super(TestSAPRfcModule, self).setUp()
- self.module = sap_task_list_execute
-
- def tearDown(self):
- super(TestSAPRfcModule, self).tearDown()
-
- def define_rfc_connect(self, mocker):
- return mocker.patch(self.module.call_rfc_method)
-
- def test_without_required_parameters(self):
- """Failure must occurs when all parameters are missing"""
- with self.assertRaises(AnsibleFailJson):
- set_module_args({})
- self.module.main()
-
- def test_error_no_task_list(self):
- """tests fail to exec task list"""
-
- set_module_args({
- "conn_username": "DDIC",
- "conn_password": "Test1234",
- "host": "10.1.8.9",
- "task_to_execute": "SAP_BASIS_SSL_CHECK"
- })
-
- with patch.object(self.module, 'Connection') as conn:
- conn.return_value = ''
- with self.assertRaises(AnsibleFailJson) as result:
- self.module.main()
- self.assertEqual(result.exception.args[0]['msg'], 'The task list does not exsist.')
-
- def test_success(self):
- """test execute task list success"""
-
- set_module_args({
- "conn_username": "DDIC",
- "conn_password": "Test1234",
- "host": "10.1.8.9",
- "task_to_execute": "SAP_BASIS_SSL_CHECK"
- })
- with patch.object(self.module, 'xml_to_dict') as XML:
- XML.return_value = {'item': [{'TASK': {'CHECK_STATUS_DESCR': 'Check successfully',
- 'STATUS_DESCR': 'Executed successfully', 'TASKNAME': 'CL_STCT_CHECK_SEC_CRYPTO',
- 'LNR': '1', 'DESCRIPTION': 'Check SAP Cryptographic Library', 'DOCU_EXIST': 'X',
- 'LOG_EXIST': 'X', 'ACTION_SKIP': None, 'ACTION_UNSKIP': None, 'ACTION_CONFIRM': None,
- 'ACTION_MAINTAIN': None}}]}
-
- with self.assertRaises(AnsibleExitJson) as result:
- sap_task_list_execute.main()
- self.assertEqual(result.exception.args[0]['out'], {'item': [{'TASK': {'CHECK_STATUS_DESCR': 'Check successfully',
- 'STATUS_DESCR': 'Executed successfully', 'TASKNAME': 'CL_STCT_CHECK_SEC_CRYPTO',
- 'LNR': '1', 'DESCRIPTION': 'Check SAP Cryptographic Library', 'DOCU_EXIST': 'X',
- 'LOG_EXIST': 'X', 'ACTION_SKIP': None, 'ACTION_UNSKIP': None,
- 'ACTION_CONFIRM': None, 'ACTION_MAINTAIN': None}}]})
-
- def test_success_no_log(self):
- """test execute task list success without logs"""
-
- set_module_args({
- "conn_username": "DDIC",
- "conn_password": "Test1234",
- "host": "10.1.8.9",
- "task_to_execute": "SAP_BASIS_SSL_CHECK"
- })
- with patch.object(self.module, 'xml_to_dict') as XML:
- XML.return_value = "No logs available."
- with self.assertRaises(AnsibleExitJson) as result:
- sap_task_list_execute.main()
- self.assertEqual(result.exception.args[0]['out'], 'No logs available.')
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_sapcar_extract.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_sapcar_extract.py
deleted file mode 100644
index bec9cf886..000000000
--- a/ansible_collections/community/general/tests/unit/plugins/modules/test_sapcar_extract.py
+++ /dev/null
@@ -1,54 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright (c) 2021, Rainer Leber (@rainerleber) <rainerleber@gmail.com>
-# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
-# SPDX-License-Identifier: GPL-3.0-or-later
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-from ansible_collections.community.general.plugins.modules import sapcar_extract
-from ansible_collections.community.general.tests.unit.plugins.modules.utils import AnsibleExitJson, AnsibleFailJson, ModuleTestCase, set_module_args
-from ansible_collections.community.general.tests.unit.compat.mock import patch
-from ansible.module_utils import basic
-
-
-def get_bin_path(*args, **kwargs):
- """Function to return path of SAPCAR"""
- return "/tmp/sapcar"
-
-
-class Testsapcar_extract(ModuleTestCase):
- """Main class for testing sapcar_extract module."""
-
- def setUp(self):
- """Setup."""
- super(Testsapcar_extract, self).setUp()
- self.module = sapcar_extract
- self.mock_get_bin_path = patch.object(basic.AnsibleModule, 'get_bin_path', get_bin_path)
- self.mock_get_bin_path.start()
- self.addCleanup(self.mock_get_bin_path.stop) # ensure that the patching is 'undone'
-
- def tearDown(self):
- """Teardown."""
- super(Testsapcar_extract, self).tearDown()
-
- def test_without_required_parameters(self):
- """Failure must occurs when all parameters are missing."""
- with self.assertRaises(AnsibleFailJson):
- set_module_args({})
- self.module.main()
-
- def test_sapcar_extract(self):
- """Check that result is changed."""
- set_module_args({
- 'path': "/tmp/HANA_CLIENT_REV2_00_053_00_LINUX_X86_64.SAR",
- 'dest': "/tmp/test2",
- 'binary_path': "/tmp/sapcar"
- })
- with patch.object(basic.AnsibleModule, 'run_command') as run_command:
- run_command.return_value = 0, '', '' # successful execution, no output
- with self.assertRaises(AnsibleExitJson) as result:
- sapcar_extract.main()
- self.assertTrue(result.exception.args[0]['changed'])
- self.assertEqual(run_command.call_count, 1)
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_simpleinit_msb.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_simpleinit_msb.py
new file mode 100644
index 000000000..d97e9b5f2
--- /dev/null
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_simpleinit_msb.py
@@ -0,0 +1,200 @@
+# Copyright (c) 2023 Vlad Glagolev <scm@vaygr.net>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+
+from ansible_collections.community.general.tests.unit.compat.mock import patch
+from ansible_collections.community.general.tests.unit.plugins.modules.utils import AnsibleFailJson, ModuleTestCase, set_module_args
+
+from ansible_collections.community.general.plugins.modules.simpleinit_msb import SimpleinitMSB, build_module
+
+
+_TELINIT_LIST = """
+RUNLEVEL SCRIPT
+2 smgl-suspend-single
+3 crond
+3 fuse
+3 network
+3 nscd
+3 smgl-default-remote-fs
+3 smgl-misc
+3 sshd
+DEV coldplug
+DEV devices
+DEV udevd
+S hostname.sh
+S hwclock.sh
+S keymap.sh
+S modutils
+S mountall.sh
+S mountroot.sh
+S single
+S smgl-default-crypt-fs
+S smgl-metalog
+S smgl-sysctl
+S sysstat
+"""
+
+_TELINIT_LIST_ENABLED = """
+smgl-suspend-single
+crond
+fuse
+network
+nscd
+smgl-default-remote-fs
+smgl-misc
+sshd
+coldplug
+devices
+udevd
+hostname.sh
+hwclock.sh
+keymap.sh
+modutils
+mountall.sh
+mountroot.sh
+single
+smgl-default-crypt-fs
+smgl-metalog
+smgl-sysctl
+"""
+
+_TELINIT_LIST_DISABLED = """
+sysstat
+"""
+
+_TELINIT_ALREADY_ENABLED = """
+Service smgl-suspend-single already enabled.
+"""
+
+_TELINIT_ALREADY_DISABLED = """
+Service smgl-suspend-single already disabled.
+"""
+
+_TELINIT_STATUS_RUNNING = """
+sshd is running with Process ID(s) 8510 8508 2195
+"""
+
+_TELINIT_STATUS_RUNNING_NOT = """
+/sbin/metalog is not running
+"""
+
+
+class TestSimpleinitMSB(ModuleTestCase):
+
+ def setUp(self):
+ super(TestSimpleinitMSB, self).setUp()
+
+ def tearDown(self):
+ super(TestSimpleinitMSB, self).tearDown()
+
+ def init_module(self, args):
+ set_module_args(args)
+
+ return SimpleinitMSB(build_module())
+
+ @patch('os.path.exists', return_value=True)
+ @patch('ansible.module_utils.basic.AnsibleModule.get_bin_path', return_value="/sbin/telinit")
+ def test_get_service_tools(self, *args, **kwargs):
+ simpleinit_msb = self.init_module({
+ 'name': 'smgl-suspend-single',
+ 'state': 'running',
+ })
+
+ simpleinit_msb.get_service_tools()
+
+ self.assertEqual(simpleinit_msb.telinit_cmd, "/sbin/telinit")
+
+ @patch('ansible_collections.community.general.plugins.modules.simpleinit_msb.SimpleinitMSB.execute_command')
+ def test_service_exists(self, execute_command):
+ simpleinit_msb = self.init_module({
+ 'name': 'smgl-suspend-single',
+ 'state': 'running',
+ })
+
+ execute_command.return_value = (0, _TELINIT_LIST, "")
+
+ simpleinit_msb.service_exists()
+
+ @patch('ansible_collections.community.general.plugins.modules.simpleinit_msb.SimpleinitMSB.execute_command')
+ def test_service_exists_not(self, execute_command):
+ simpleinit_msb = self.init_module({
+ 'name': 'ntp',
+ 'state': 'running',
+ })
+
+ execute_command.return_value = (0, _TELINIT_LIST, "")
+
+ with self.assertRaises(AnsibleFailJson) as context:
+ simpleinit_msb.service_exists()
+
+ self.assertEqual("telinit could not find the requested service: ntp", context.exception.args[0]["msg"])
+
+ @patch('ansible_collections.community.general.plugins.modules.simpleinit_msb.SimpleinitMSB.service_exists')
+ @patch('ansible_collections.community.general.plugins.modules.simpleinit_msb.SimpleinitMSB.execute_command')
+ def test_check_service_enabled(self, execute_command, service_exists):
+ simpleinit_msb = self.init_module({
+ 'name': 'nscd',
+ 'state': 'running',
+ 'enabled': 'true',
+ })
+
+ service_exists.return_value = True
+ execute_command.return_value = (0, _TELINIT_LIST_ENABLED, "")
+
+ self.assertTrue(simpleinit_msb.service_enabled())
+
+ # Race condition check
+ with patch('ansible_collections.community.general.plugins.modules.simpleinit_msb.SimpleinitMSB.service_enabled', return_value=False):
+ execute_command.return_value = (0, "", _TELINIT_ALREADY_ENABLED)
+
+ simpleinit_msb.service_enable()
+
+ self.assertFalse(simpleinit_msb.changed)
+
+ @patch('ansible_collections.community.general.plugins.modules.simpleinit_msb.SimpleinitMSB.service_exists')
+ @patch('ansible_collections.community.general.plugins.modules.simpleinit_msb.SimpleinitMSB.execute_command')
+ def test_check_service_disabled(self, execute_command, service_exists):
+ simpleinit_msb = self.init_module({
+ 'name': 'sysstat',
+ 'state': 'stopped',
+ 'enabled': 'false',
+ })
+
+ service_exists.return_value = True
+ execute_command.return_value = (0, _TELINIT_LIST_DISABLED, "")
+
+ self.assertFalse(simpleinit_msb.service_enabled())
+
+ # Race condition check
+ with patch('ansible_collections.community.general.plugins.modules.simpleinit_msb.SimpleinitMSB.service_enabled', return_value=True):
+ execute_command.return_value = (0, "", _TELINIT_ALREADY_DISABLED)
+
+ simpleinit_msb.service_enable()
+
+ self.assertFalse(simpleinit_msb.changed)
+
+ @patch('ansible_collections.community.general.plugins.modules.simpleinit_msb.SimpleinitMSB.service_control')
+ def test_check_service_running(self, service_control):
+ simpleinit_msb = self.init_module({
+ 'name': 'sshd',
+ 'state': 'running',
+ })
+
+ service_control.return_value = (0, _TELINIT_STATUS_RUNNING, "")
+
+ self.assertFalse(simpleinit_msb.get_service_status())
+
+ @patch('ansible_collections.community.general.plugins.modules.simpleinit_msb.SimpleinitMSB.service_control')
+ def test_check_service_running_not(self, service_control):
+ simpleinit_msb = self.init_module({
+ 'name': 'smgl-metalog',
+ 'state': 'running',
+ })
+
+ service_control.return_value = (0, _TELINIT_STATUS_RUNNING_NOT, "")
+
+ self.assertFalse(simpleinit_msb.get_service_status())
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_slack.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_slack.py
index ab4405baa..52ac9b7f3 100644
--- a/ansible_collections/community/general/tests/unit/plugins/modules/test_slack.py
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_slack.py
@@ -105,7 +105,7 @@ class TestSlackModule(ModuleTestCase):
self.module.main()
self.assertTrue(fetch_url_mock.call_count, 1)
- self.assertEquals(fetch_url_mock.call_args[1]['url'], "https://slack.com/api/chat.postMessage")
+ self.assertEqual(fetch_url_mock.call_args[1]['url'], "https://slack.com/api/chat.postMessage")
def test_edit_message(self):
set_module_args({
@@ -125,9 +125,9 @@ class TestSlackModule(ModuleTestCase):
self.module.main()
self.assertTrue(fetch_url_mock.call_count, 2)
- self.assertEquals(fetch_url_mock.call_args[1]['url'], "https://slack.com/api/chat.update")
+ self.assertEqual(fetch_url_mock.call_args[1]['url'], "https://slack.com/api/chat.update")
call_data = json.loads(fetch_url_mock.call_args[1]['data'])
- self.assertEquals(call_data['ts'], "12345")
+ self.assertEqual(call_data['ts'], "12345")
def test_message_with_blocks(self):
"""tests sending a message with blocks"""
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_snap.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_snap.py
new file mode 100644
index 000000000..480f637b6
--- /dev/null
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_snap.py
@@ -0,0 +1,474 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) Alexei Znamensky (russoz@gmail.com)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+from .helper import Helper, ModuleTestCase, RunCmdCall
+from ansible_collections.community.general.plugins.modules import snap
+
+
+issue_6803_status_out = """Name Version Rev Tracking Publisher Notes
+core20 20220826 1623 latest/stable canonical** base
+lxd 5.6-794016a 23680 latest/stable/… canonical** -
+snapd 2.57.4 17336 latest/stable canonical** snapd
+"""
+
+issue_6803_microk8s_out = (
+ "\rEnsure prerequisites for \"microk8s\" are available /"
+ "\rDownload snap \"microk8s\" (5372) from channel \"1.27/stable\" "
+ "\rDownload snap \"microk8s\" (5372) from channel \"1.27/stable\" \\"
+ "\rDownload snap \"microk8s\" (5372) from channel \"1.27/stable\" "
+ "\rDownload snap \"microk8s\" (5372) from channel \"1.27/stable\" /\u001b[?25"
+ "\r\u001b[7m\u001b[0mDownload snap \"microk8s\" (5372) from channel \"1.27/stable\" 0% 0B/s ages"
+ "\r\u001b[7m\u001b[0mDownload snap \"microk8s\" (5372) from channel \"1.27/stable\" 0% 0B/s ages"
+ "\r\u001b[7m\u001b[0mDownload snap \"microk8s\" (5372) from channel \"1.27/stable\" 0% 0B/s ages"
+ "\r\u001b[7m\u001b[0mDownload snap \"microk8s\" (5372) from channel \"1.27/stable\" 0% 880kB/s 3m21"
+ "\r\u001b[7m\u001b[0mDownload snap \"microk8s\" (5372) from channel \"1.27/stable\" 1% 2.82MB/s 1m02"
+ "\r\u001b[7mD\u001b[0mownload snap \"microk8s\" (5372) from channel \"1.27/stable\" 2% 4.71MB/s 37.0"
+ "\r\u001b[7mDo\u001b[0mwnload snap \"microk8s\" (5372) from channel \"1.27/stable\" 4% 9.09MB/s 18.8"
+ "\r\u001b[7mDown\u001b[0mload snap \"microk8s\" (5372) from channel \"1.27/stable\" 6% 12.4MB/s 13.5"
+ "\r\u001b[7mDownl\u001b[0moad snap \"microk8s\" (5372) from channel \"1.27/stable\" 7% 14.5MB/s 11.3"
+ "\r\u001b[7mDownloa\u001b[0md snap \"microk8s\" (5372) from channel \"1.27/stable\" 9% 15.9MB/s 10.1"
+ "\r\u001b[7mDownload \u001b[0msnap \"microk8s\" (5372) from channel \"1.27/stable\" 11% 18.0MB/s 8.75"
+ "\r\u001b[7mDownload s\u001b[0mnap \"microk8s\" (5372) from channel \"1.27/stable\" 13% 19.4MB/s 7.91"
+ "\r\u001b[7mDownload sn\u001b[0map \"microk8s\" (5372) from channel \"1.27/stable\" 15% 20.1MB/s 7.50"
+ "\r\u001b[7mDownload snap\u001b[0m \"microk8s\" (5372) from channel \"1.27/stable\" 17% 20.9MB/s 7.05"
+ "\r\u001b[7mDownload snap \"\u001b[0mmicrok8s\" (5372) from channel \"1.27/stable\" 19% 22.1MB/s 6.50"
+ "\r\u001b[7mDownload snap \"m\u001b[0microk8s\" (5372) from channel \"1.27/stable\" 21% 22.9MB/s 6.11"
+ "\r\u001b[7mDownload snap \"mic\u001b[0mrok8s\" (5372) from channel \"1.27/stable\" 23% 23.2MB/s 5.90"
+ "\r\u001b[7mDownload snap \"micr\u001b[0mok8s\" (5372) from channel \"1.27/stable\" 25% 23.9MB/s 5.58"
+ "\r\u001b[7mDownload snap \"microk\u001b[0m8s\" (5372) from channel \"1.27/stable\" 27% 24.5MB/s 5.30"
+ "\r\u001b[7mDownload snap \"microk8\u001b[0ms\" (5372) from channel \"1.27/stable\" 29% 24.9MB/s 5.09"
+ "\r\u001b[7mDownload snap \"microk8s\"\u001b[0m (5372) from channel \"1.27/stable\" 31% 25.4MB/s 4.85"
+ "\r\u001b[7mDownload snap \"microk8s\" (\u001b[0m5372) from channel \"1.27/stable\" 33% 25.8MB/s 4.63"
+ "\r\u001b[7mDownload snap \"microk8s\" (5\u001b[0m372) from channel \"1.27/stable\" 35% 26.2MB/s 4.42"
+ "\r\u001b[7mDownload snap \"microk8s\" (53\u001b[0m72) from channel \"1.27/stable\" 36% 26.3MB/s 4.30"
+ "\r\u001b[7mDownload snap \"microk8s\" (5372\u001b[0m) from channel \"1.27/stable\" 38% 26.7MB/s 4.10"
+ "\r\u001b[7mDownload snap \"microk8s\" (5372) \u001b[0mfrom channel \"1.27/stable\" 40% 26.9MB/s 3.95"
+ "\r\u001b[7mDownload snap \"microk8s\" (5372) f\u001b[0mrom channel \"1.27/stable\" 42% 27.2MB/s 3.77"
+ "\r\u001b[7mDownload snap \"microk8s\" (5372) fro\u001b[0mm channel \"1.27/stable\" 44% 27.4MB/s 3.63"
+ "\r\u001b[7mDownload snap \"microk8s\" (5372) from\u001b[0m channel \"1.27/stable\" 46% 27.8MB/s 3.44"
+ "\r\u001b[7mDownload snap \"microk8s\" (5372) from c\u001b[0mhannel \"1.27/stable\" 48% 27.9MB/s 3.31"
+ "\r\u001b[7mDownload snap \"microk8s\" (5372) from cha\u001b[0mnnel \"1.27/stable\" 50% 28.1MB/s 3.15"
+ "\r\u001b[7mDownload snap \"microk8s\" (5372) from chan\u001b[0mnel \"1.27/stable\" 52% 28.3MB/s 3.02"
+ "\r\u001b[7mDownload snap \"microk8s\" (5372) from channe\u001b[0ml \"1.27/stable\" 54% 28.5MB/s 2.87"
+ "\r\u001b[7mDownload snap \"microk8s\" (5372) from channel\u001b[0m \"1.27/stable\" 56% 28.6MB/s 2.75"
+ "\r\u001b[7mDownload snap \"microk8s\" (5372) from channel \u001b[0m\"1.27/stable\" 57% 28.7MB/s 2.63"
+ "\r\u001b[7mDownload snap \"microk8s\" (5372) from channel \"1\u001b[0m.27/stable\" 60% 28.9MB/s 2.47"
+ "\r\u001b[7mDownload snap \"microk8s\" (5372) from channel \"1.2\u001b[0m7/stable\" 62% 29.0MB/s 2.35"
+ "\r\u001b[7mDownload snap \"microk8s\" (5372) from channel \"1.27\u001b[0m/stable\" 63% 29.1MB/s 2.23"
+ "\r\u001b[7mDownload snap \"microk8s\" (5372) from channel \"1.27/s\u001b[0mtable\" 65% 29.2MB/s 2.10"
+ "\r\u001b[7mDownload snap \"microk8s\" (5372) from channel \"1.27/st\u001b[0mable\" 67% 29.4MB/s 1.97"
+ "\r\u001b[7mDownload snap \"microk8s\" (5372) from channel \"1.27/stab\u001b[0mle\" 69% 29.5MB/s 1.85"
+ "\r\u001b[7mDownload snap \"microk8s\" (5372) from channel \"1.27/stabl\u001b[0me\" 71% 29.5MB/s 1.74"
+ "\r\u001b[7mDownload snap \"microk8s\" (5372) from channel \"1.27/stable\"\u001b[0m 73% 29.7MB/s 1.59"
+ "\r\u001b[7mDownload snap \"microk8s\" (5372) from channel \"1.27/stable\" \u001b[0m 75% 29.8MB/s 1.48"
+ "\r\u001b[7mDownload snap \"microk8s\" (5372) from channel \"1.27/stable\" \u001b[0m 77% 29.8MB/s 1.37"
+ "\r\u001b[7mDownload snap \"microk8s\" (5372) from channel \"1.27/stable\" 7\u001b[0m9% 29.9MB/s 1.26"
+ "\r\u001b[7mDownload snap \"microk8s\" (5372) from channel \"1.27/stable\" 81\u001b[0m% 30.0MB/s 1.14"
+ "\r\u001b[7mDownload snap \"microk8s\" (5372) from channel \"1.27/stable\" 83% \u001b[0m30.1MB/s 1.01"
+ "\r\u001b[7mDownload snap \"microk8s\" (5372) from channel \"1.27/stable\" 84% 3\u001b[0m0.1MB/s 919m"
+ "\r\u001b[7mDownload snap \"microk8s\" (5372) from channel \"1.27/stable\" 86% 30.\u001b[0m1MB/s 810m"
+ "\r\u001b[7mDownload snap \"microk8s\" (5372) from channel \"1.27/stable\" 88% 30.2\u001b[0mMB/s 676m"
+ "\r\u001b[7mDownload snap \"microk8s\" (5372) from channel \"1.27/stable\" 91% 30.3MB\u001b[0m/s 555m"
+ "\r\u001b[7mDownload snap \"microk8s\" (5372) from channel \"1.27/stable\" 93% 30.4MB/s\u001b[0m 436m"
+ "\r\u001b[7mDownload snap \"microk8s\" (5372) from channel \"1.27/stable\" 95% 30.5MB/s \u001b[0m317m"
+ "\r\u001b[7mDownload snap \"microk8s\" (5372) from channel \"1.27/stable\" 96% 30.5MB/s 21\u001b[0m1m"
+ "\r\u001b[7mDownload snap \"microk8s\" (5372) from channel \"1.27/stable\" 98% 30.5MB/s 117\u001b[0mm"
+ "\r\u001b[7mDownload snap \"microk8s\" (5372) from channel \"1.27/stable\" 100% 30.5MB/s 11m\u001b[0m"
+ "\r\u001b[7mDownload snap \"microk8s\" (5372) from channel \"1.27/stable\" 100% 30.0MB/s 0.0ns\u001b[0"
+ "\rFetch and check assertions for snap \"microk8s\" (5372) "
+ "\rMount snap \"microk8s\" (5372) \\"
+ "\rMount snap \"microk8s\" (5372) "
+ "\rMount snap \"microk8s\" (5372) "
+ "\rMount snap \"microk8s\" (5372) "
+ "\rSetup snap \"microk8s\" (5372) security profiles \\"
+ "\rSetup snap \"microk8s\" (5372) security profiles "
+ "\rSetup snap \"microk8s\" (5372) security profiles "
+ "\rSetup snap \"microk8s\" (5372) security profiles "
+ "\rSetup snap \"microk8s\" (5372) security profiles \\"
+ "\rSetup snap \"microk8s\" (5372) security profiles "
+ "\rSetup snap \"microk8s\" (5372) security profiles "
+ "\rSetup snap \"microk8s\" (5372) security profiles "
+ "\rSetup snap \"microk8s\" (5372) security profiles \\"
+ "\rSetup snap \"microk8s\" (5372) security profiles "
+ "\rSetup snap \"microk8s\" (5372) security profiles "
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present \\"
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present \\"
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present \\"
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present \\"
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present \\"
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present \\"
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present \\"
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present \\"
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present \\"
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present \\"
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present \\"
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present \\"
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present \\"
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present \\"
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rRun install hook of \"microk8s\" snap if present "
+ "\rStart snap \"microk8s\" (5372) services \\"
+ "\rStart snap \"microk8s\" (5372) services "
+ "\rStart snap \"microk8s\" (5372) services "
+ "\rStart snap \"microk8s\" (5372) services "
+ "\rStart snap \"microk8s\" (5372) services \\"
+ "\rStart snap \"microk8s\" (5372) services "
+ "\rStart snap \"microk8s\" (5372) services "
+ "\rStart snap \"microk8s\" (5372) services "
+ "\rStart snap \"microk8s\" (5372) services \\"
+ "\rStart snap \"microk8s\" (5372) services "
+ "\rStart snap \"microk8s\" (5372) services "
+ "\rStart snap \"microk8s\" (5372) services "
+ "\rStart snap \"microk8s\" (5372) services \\"
+ "\rStart snap \"microk8s\" (5372) services "
+ "\rStart snap \"microk8s\" (5372) services "
+ "\rStart snap \"microk8s\" (5372) services "
+ "\rStart snap \"microk8s\" (5372) services \\"
+ "\rRun configure hook of \"microk8s\" snap if present "
+ "\rRun configure hook of \"microk8s\" snap if present "
+ "\rRun configure hook of \"microk8s\" snap if present "
+ "\rRun configure hook of \"microk8s\" snap if present \\"
+ "\rRun configure hook of \"microk8s\" snap if present "
+ "\rRun configure hook of \"microk8s\" snap if present "
+ "\rRun configure hook of \"microk8s\" snap if present "
+ "\rRun configure hook of \"microk8s\" snap if present \\"
+ "\rRun configure hook of \"microk8s\" snap if present "
+ "\rRun configure hook of \"microk8s\" snap if present "
+ "\rRun configure hook of \"microk8s\" snap if present "
+ "\rRun configure hook of \"microk8s\" snap if present \\"
+ "\rRun configure hook of \"microk8s\" snap if present "
+ "\rRun configure hook of \"microk8s\" snap if present "
+ "\rRun configure hook of \"microk8s\" snap if present "
+ "\rRun configure hook of \"microk8s\" snap if present \\"
+ "\rRun configure hook of \"microk8s\" snap if present "
+ "\rRun configure hook of \"microk8s\" snap if present "
+ "\rRun configure hook of \"microk8s\" snap if present "
+ "\rRun configure hook of \"microk8s\" snap if present \\"
+ "\rRun configure hook of \"microk8s\" snap if present "
+ "\rRun service command \"restart\" for services [\"daemon-apiserver-proxy\"] of snap \""
+ "\r\u001b[0m\u001b[?25h\u001b[Kmicrok8s (1.27/stable) v1.27.2 from Canonical** installed\n"
+)
+
+issue_6803_kubectl_out = (
+ "\rEnsure prerequisites for \"kubectl\" are available /"
+ "\rDownload snap \"kubectl\" (5372) from channel \"1.27/stable\" "
+ "\rDownload snap \"kubectl\" (5372) from channel \"1.27/stable\" \\"
+ "\rDownload snap \"kubectl\" (5372) from channel \"1.27/stable\" "
+ "\rDownload snap \"kubectl\" (5372) from channel \"1.27/stable\" /\u001b[?25"
+ "\r\u001b[7m\u001b[0mDownload snap \"kubectl\" (5372) from channel \"1.27/stable\" 0% 0B/s ages"
+ "\r\u001b[7m\u001b[0mDownload snap \"kubectl\" (5372) from channel \"1.27/stable\" 0% 0B/s ages"
+ "\r\u001b[7m\u001b[0mDownload snap \"kubectl\" (5372) from channel \"1.27/stable\" 0% 0B/s ages"
+ "\r\u001b[7m\u001b[0mDownload snap \"kubectl\" (5372) from channel \"1.27/stable\" 0% 880kB/s 3m21"
+ "\r\u001b[7m\u001b[0mDownload snap \"kubectl\" (5372) from channel \"1.27/stable\" 1% 2.82MB/s 1m02"
+ "\r\u001b[7mD\u001b[0mownload snap \"kubectl\" (5372) from channel \"1.27/stable\" 2% 4.71MB/s 37.0"
+ "\r\u001b[7mDo\u001b[0mwnload snap \"kubectl\" (5372) from channel \"1.27/stable\" 4% 9.09MB/s 18.8"
+ "\r\u001b[7mDown\u001b[0mload snap \"kubectl\" (5372) from channel \"1.27/stable\" 6% 12.4MB/s 13.5"
+ "\r\u001b[7mDownl\u001b[0moad snap \"kubectl\" (5372) from channel \"1.27/stable\" 7% 14.5MB/s 11.3"
+ "\r\u001b[7mDownloa\u001b[0md snap \"kubectl\" (5372) from channel \"1.27/stable\" 9% 15.9MB/s 10.1"
+ "\r\u001b[7mDownload \u001b[0msnap \"kubectl\" (5372) from channel \"1.27/stable\" 11% 18.0MB/s 8.75"
+ "\r\u001b[7mDownload s\u001b[0mnap \"kubectl\" (5372) from channel \"1.27/stable\" 13% 19.4MB/s 7.91"
+ "\r\u001b[7mDownload sn\u001b[0map \"kubectl\" (5372) from channel \"1.27/stable\" 15% 20.1MB/s 7.50"
+ "\r\u001b[7mDownload snap\u001b[0m \"kubectl\" (5372) from channel \"1.27/stable\" 17% 20.9MB/s 7.05"
+ "\r\u001b[7mDownload snap \"\u001b[0mkubectl\" (5372) from channel \"1.27/stable\" 19% 22.1MB/s 6.50"
+ "\r\u001b[7mDownload snap \"m\u001b[0kubectl\" (5372) from channel \"1.27/stable\" 21% 22.9MB/s 6.11"
+ "\r\u001b[7mDownload snap \"mic\u001b[0mrok8s\" (5372) from channel \"1.27/stable\" 23% 23.2MB/s 5.90"
+ "\r\u001b[7mDownload snap \"micr\u001b[0mok8s\" (5372) from channel \"1.27/stable\" 25% 23.9MB/s 5.58"
+ "\r\u001b[7mDownload snap \"microk\u001b[0m8s\" (5372) from channel \"1.27/stable\" 27% 24.5MB/s 5.30"
+ "\r\u001b[7mDownload snap \"microk8\u001b[0ms\" (5372) from channel \"1.27/stable\" 29% 24.9MB/s 5.09"
+ "\r\u001b[7mDownload snap \"kubectl\"\u001b[0m (5372) from channel \"1.27/stable\" 31% 25.4MB/s 4.85"
+ "\r\u001b[7mDownload snap \"kubectl\" (\u001b[0m5372) from channel \"1.27/stable\" 33% 25.8MB/s 4.63"
+ "\r\u001b[7mDownload snap \"kubectl\" (5\u001b[0m372) from channel \"1.27/stable\" 35% 26.2MB/s 4.42"
+ "\r\u001b[7mDownload snap \"kubectl\" (53\u001b[0m72) from channel \"1.27/stable\" 36% 26.3MB/s 4.30"
+ "\r\u001b[7mDownload snap \"kubectl\" (5372\u001b[0m) from channel \"1.27/stable\" 38% 26.7MB/s 4.10"
+ "\r\u001b[7mDownload snap \"kubectl\" (5372) \u001b[0mfrom channel \"1.27/stable\" 40% 26.9MB/s 3.95"
+ "\r\u001b[7mDownload snap \"kubectl\" (5372) f\u001b[0mrom channel \"1.27/stable\" 42% 27.2MB/s 3.77"
+ "\r\u001b[7mDownload snap \"kubectl\" (5372) fro\u001b[0mm channel \"1.27/stable\" 44% 27.4MB/s 3.63"
+ "\r\u001b[7mDownload snap \"kubectl\" (5372) from\u001b[0m channel \"1.27/stable\" 46% 27.8MB/s 3.44"
+ "\r\u001b[7mDownload snap \"kubectl\" (5372) from c\u001b[0mhannel \"1.27/stable\" 48% 27.9MB/s 3.31"
+ "\r\u001b[7mDownload snap \"kubectl\" (5372) from cha\u001b[0mnnel \"1.27/stable\" 50% 28.1MB/s 3.15"
+ "\r\u001b[7mDownload snap \"kubectl\" (5372) from chan\u001b[0mnel \"1.27/stable\" 52% 28.3MB/s 3.02"
+ "\r\u001b[7mDownload snap \"kubectl\" (5372) from channe\u001b[0ml \"1.27/stable\" 54% 28.5MB/s 2.87"
+ "\r\u001b[7mDownload snap \"kubectl\" (5372) from channel\u001b[0m \"1.27/stable\" 56% 28.6MB/s 2.75"
+ "\r\u001b[7mDownload snap \"kubectl\" (5372) from channel \u001b[0m\"1.27/stable\" 57% 28.7MB/s 2.63"
+ "\r\u001b[7mDownload snap \"kubectl\" (5372) from channel \"1\u001b[0m.27/stable\" 60% 28.9MB/s 2.47"
+ "\r\u001b[7mDownload snap \"kubectl\" (5372) from channel \"1.2\u001b[0m7/stable\" 62% 29.0MB/s 2.35"
+ "\r\u001b[7mDownload snap \"kubectl\" (5372) from channel \"1.27\u001b[0m/stable\" 63% 29.1MB/s 2.23"
+ "\r\u001b[7mDownload snap \"kubectl\" (5372) from channel \"1.27/s\u001b[0mtable\" 65% 29.2MB/s 2.10"
+ "\r\u001b[7mDownload snap \"kubectl\" (5372) from channel \"1.27/st\u001b[0mable\" 67% 29.4MB/s 1.97"
+ "\r\u001b[7mDownload snap \"kubectl\" (5372) from channel \"1.27/stab\u001b[0mle\" 69% 29.5MB/s 1.85"
+ "\r\u001b[7mDownload snap \"kubectl\" (5372) from channel \"1.27/stabl\u001b[0me\" 71% 29.5MB/s 1.74"
+ "\r\u001b[7mDownload snap \"kubectl\" (5372) from channel \"1.27/stable\"\u001b[0m 73% 29.7MB/s 1.59"
+ "\r\u001b[7mDownload snap \"kubectl\" (5372) from channel \"1.27/stable\" \u001b[0m 75% 29.8MB/s 1.48"
+ "\r\u001b[7mDownload snap \"kubectl\" (5372) from channel \"1.27/stable\" \u001b[0m 77% 29.8MB/s 1.37"
+ "\r\u001b[7mDownload snap \"kubectl\" (5372) from channel \"1.27/stable\" 7\u001b[0m9% 29.9MB/s 1.26"
+ "\r\u001b[7mDownload snap \"kubectl\" (5372) from channel \"1.27/stable\" 81\u001b[0m% 30.0MB/s 1.14"
+ "\r\u001b[7mDownload snap \"kubectl\" (5372) from channel \"1.27/stable\" 83% \u001b[0m30.1MB/s 1.01"
+ "\r\u001b[7mDownload snap \"kubectl\" (5372) from channel \"1.27/stable\" 84% 3\u001b[0m0.1MB/s 919m"
+ "\r\u001b[7mDownload snap \"kubectl\" (5372) from channel \"1.27/stable\" 86% 30.\u001b[0m1MB/s 810m"
+ "\r\u001b[7mDownload snap \"kubectl\" (5372) from channel \"1.27/stable\" 88% 30.2\u001b[0mMB/s 676m"
+ "\r\u001b[7mDownload snap \"kubectl\" (5372) from channel \"1.27/stable\" 91% 30.3MB\u001b[0m/s 555m"
+ "\r\u001b[7mDownload snap \"kubectl\" (5372) from channel \"1.27/stable\" 93% 30.4MB/s\u001b[0m 436m"
+ "\r\u001b[7mDownload snap \"kubectl\" (5372) from channel \"1.27/stable\" 95% 30.5MB/s \u001b[0m317m"
+ "\r\u001b[7mDownload snap \"kubectl\" (5372) from channel \"1.27/stable\" 96% 30.5MB/s 21\u001b[0m1m"
+ "\r\u001b[7mDownload snap \"kubectl\" (5372) from channel \"1.27/stable\" 98% 30.5MB/s 117\u001b[0mm"
+ "\r\u001b[7mDownload snap \"kubectl\" (5372) from channel \"1.27/stable\" 100% 30.5MB/s 11m\u001b[0m"
+ "\r\u001b[7mDownload snap \"kubectl\" (5372) from channel \"1.27/stable\" 100% 30.0MB/s 0.0ns\u001b[0"
+ "\rFetch and check assertions for snap \"kubectl\" (5372) "
+ "\rMount snap \"kubectl\" (5372) \\"
+ "\rMount snap \"kubectl\" (5372) "
+ "\rMount snap \"kubectl\" (5372) "
+ "\rMount snap \"kubectl\" (5372) "
+ "\rSetup snap \"kubectl\" (5372) security profiles \\"
+ "\rSetup snap \"kubectl\" (5372) security profiles "
+ "\rSetup snap \"kubectl\" (5372) security profiles "
+ "\rSetup snap \"kubectl\" (5372) security profiles "
+ "\rSetup snap \"kubectl\" (5372) security profiles \\"
+ "\rSetup snap \"kubectl\" (5372) security profiles "
+ "\rSetup snap \"kubectl\" (5372) security profiles "
+ "\rSetup snap \"kubectl\" (5372) security profiles "
+ "\rSetup snap \"kubectl\" (5372) security profiles \\"
+ "\rSetup snap \"kubectl\" (5372) security profiles "
+ "\rSetup snap \"kubectl\" (5372) security profiles "
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present \\"
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present \\"
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present \\"
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present \\"
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present \\"
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present \\"
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present \\"
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present \\"
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present \\"
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present \\"
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present \\"
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present \\"
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present \\"
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present \\"
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rRun install hook of \"kubectl\" snap if present "
+ "\rStart snap \"kubectl\" (5372) services \\"
+ "\rStart snap \"kubectl\" (5372) services "
+ "\rStart snap \"kubectl\" (5372) services "
+ "\rStart snap \"kubectl\" (5372) services "
+ "\rStart snap \"kubectl\" (5372) services \\"
+ "\rStart snap \"kubectl\" (5372) services "
+ "\rStart snap \"kubectl\" (5372) services "
+ "\rStart snap \"kubectl\" (5372) services "
+ "\rStart snap \"kubectl\" (5372) services \\"
+ "\rStart snap \"kubectl\" (5372) services "
+ "\rStart snap \"kubectl\" (5372) services "
+ "\rStart snap \"kubectl\" (5372) services "
+ "\rStart snap \"kubectl\" (5372) services \\"
+ "\rStart snap \"kubectl\" (5372) services "
+ "\rStart snap \"kubectl\" (5372) services "
+ "\rStart snap \"kubectl\" (5372) services "
+ "\rStart snap \"kubectl\" (5372) services \\"
+ "\rRun configure hook of \"kubectl\" snap if present "
+ "\rRun configure hook of \"kubectl\" snap if present "
+ "\rRun configure hook of \"kubectl\" snap if present "
+ "\rRun configure hook of \"kubectl\" snap if present \\"
+ "\rRun configure hook of \"kubectl\" snap if present "
+ "\rRun configure hook of \"kubectl\" snap if present "
+ "\rRun configure hook of \"kubectl\" snap if present "
+ "\rRun configure hook of \"kubectl\" snap if present \\"
+ "\rRun configure hook of \"kubectl\" snap if present "
+ "\rRun configure hook of \"kubectl\" snap if present "
+ "\rRun configure hook of \"kubectl\" snap if present "
+ "\rRun configure hook of \"kubectl\" snap if present \\"
+ "\rRun configure hook of \"kubectl\" snap if present "
+ "\rRun configure hook of \"kubectl\" snap if present "
+ "\rRun configure hook of \"kubectl\" snap if present "
+ "\rRun configure hook of \"kubectl\" snap if present \\"
+ "\rRun configure hook of \"kubectl\" snap if present "
+ "\rRun configure hook of \"kubectl\" snap if present "
+ "\rRun configure hook of \"kubectl\" snap if present "
+ "\rRun configure hook of \"kubectl\" snap if present \\"
+ "\rRun configure hook of \"kubectl\" snap if present "
+ "\rRun service command \"restart\" for services [\"daemon-apiserver-proxy\"] of snap \""
+ "\r\u001b[0m\u001b[?25h\u001b[Kkubectl (1.27/stable) v1.27.2 from Canonical** installed\n"
+)
+
+TEST_CASES = [
+ ModuleTestCase(
+ id="simple case",
+ input={"name": ["hello-world"]},
+ output=dict(changed=True, snaps_installed=["hello-world"]),
+ flags={},
+ run_command_calls=[
+ RunCmdCall(
+ command=['/testbin/snap', 'info', 'hello-world'],
+ environ={'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
+ rc=0,
+ out='name: hello-world\n',
+ err="",
+ ),
+ RunCmdCall(
+ command=['/testbin/snap', 'list'],
+ environ={'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
+ rc=0,
+ out="",
+ err="",
+ ),
+ RunCmdCall(
+ command=['/testbin/snap', 'install', 'hello-world'],
+ environ={'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
+ rc=0,
+ out="hello-world (12345/stable) v12345 from Canonical** installed\n",
+ err="",
+ ),
+ RunCmdCall(
+ command=['/testbin/snap', 'list'],
+ environ={'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
+ rc=0,
+ out=(
+ "Name Version Rev Tracking Publisher Notes"
+ "core20 20220826 1623 latest/stable canonical** base"
+ "lxd 5.6-794016a 23680 latest/stable/… canonical** -"
+ "hello-world 5.6-794016a 23680 latest/stable/… canonical** -"
+ "snapd 2.57.4 17336 latest/stable canonical** snapd"
+ ""),
+ err="",
+ ),
+ ]
+ ),
+ ModuleTestCase(
+ id="issue_6803",
+ input={"name": ["microk8s", "kubectl"], "classic": True},
+ output=dict(changed=True, snaps_installed=["microk8s", "kubectl"]),
+ flags={},
+ run_command_calls=[
+ RunCmdCall(
+ command=['/testbin/snap', 'info', 'microk8s', 'kubectl'],
+ environ={'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
+ rc=0,
+ out='name: microk8s\n---\nname: kubectl\n',
+ err="",
+ ),
+ RunCmdCall(
+ command=['/testbin/snap', 'list'],
+ environ={'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
+ rc=0,
+ out=issue_6803_status_out,
+ err="",
+ ),
+ RunCmdCall(
+ command=['/testbin/snap', 'install', '--classic', 'microk8s'],
+ environ={'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
+ rc=0,
+ out=issue_6803_microk8s_out,
+ err="",
+ ),
+ RunCmdCall(
+ command=['/testbin/snap', 'install', '--classic', 'kubectl'],
+ environ={'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
+ rc=0,
+ out=issue_6803_kubectl_out,
+ err="",
+ ),
+ RunCmdCall(
+ command=['/testbin/snap', 'list'],
+ environ={'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
+ rc=0,
+ out=(
+ "Name Version Rev Tracking Publisher Notes"
+ "core20 20220826 1623 latest/stable canonical** base"
+ "lxd 5.6-794016a 23680 latest/stable/… canonical** -"
+ "microk8s 5.6-794016a 23680 latest/stable/… canonical** -"
+ "kubectl 5.6-794016a 23680 latest/stable/… canonical** -"
+ "snapd 2.57.4 17336 latest/stable canonical** snapd"
+ ""),
+ err="",
+ ),
+ ]
+ ),
+]
+
+helper = Helper.from_list(snap.main, TEST_CASES)
+patch_bin = helper.cmd_fixture
+test_module = helper.test_module
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_usb_facts.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_usb_facts.py
new file mode 100644
index 000000000..084433492
--- /dev/null
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_usb_facts.py
@@ -0,0 +1,105 @@
+# Copyright (c) Ansible project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import json
+
+from ansible_collections.community.general.tests.unit.compat import mock
+from ansible_collections.community.general.tests.unit.compat import unittest
+from ansible.module_utils import basic
+from ansible.module_utils.common.text.converters import to_bytes
+from ansible_collections.community.general.plugins.modules import usb_facts
+
+
+def set_module_args(args):
+ """prepare arguments so that they will be picked up during module creation"""
+ args = json.dumps({'ANSIBLE_MODULE_ARGS': args})
+ basic._ANSIBLE_ARGS = to_bytes(args)
+
+
+class AnsibleExitJson(Exception):
+ """Exception class to be raised by module.exit_json and caught by the test case"""
+ pass
+
+
+class AnsibleFailJson(Exception):
+ """Exception class to be raised by module.fail_json and caught by the test case"""
+ pass
+
+
+def exit_json(*args, **kwargs):
+ """function to patch over exit_json; package return data into an exception"""
+ if 'changed' not in kwargs:
+ kwargs['changed'] = False
+ raise AnsibleExitJson(kwargs)
+
+
+def fail_json(*args, **kwargs):
+ """function to patch over fail_json; package return data into an exception"""
+ kwargs['failed'] = True
+ raise AnsibleFailJson(kwargs)
+
+
+def get_bin_path(self, arg, required=False):
+ """Mock AnsibleModule.get_bin_path"""
+ if arg == 'lsusb':
+ return '/usr/bin/lsusb'
+ else:
+ if required:
+ fail_json(msg='%r not found !' % arg)
+
+
+class TestUsbFacts(unittest.TestCase):
+
+ def setUp(self):
+ self.mock_module_helper = mock.patch.multiple(basic.AnsibleModule,
+ exit_json=exit_json,
+ fail_json=fail_json,
+ get_bin_path=get_bin_path)
+ self.mock_module_helper.start()
+ self.addCleanup(self.mock_module_helper.stop)
+ self.testing_data = [
+ {
+ "input": "Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub",
+ "bus": "001",
+ "device": "001",
+ "id": "1d6b:0002",
+ "name": "Linux Foundation 2.0 root hub"
+ },
+ {
+ "input": "Bus 003 Device 002: ID 8087:8008 Intel Corp. Integrated Rate Matching Hub",
+ "bus": "003",
+ "device": "002",
+ "id": "8087:8008",
+ "name": "Intel Corp. Integrated Rate Matching Hub"
+ }
+ ]
+ self.output_fields = ["bus", "device", "id", "name"]
+
+ def test_parsing_single_line(self):
+ for data in self.testing_data:
+ with mock.patch.object(basic.AnsibleModule, 'run_command') as mock_run_command:
+ command_output = data["input"]
+ mock_run_command.return_value = 0, command_output, None
+ with self.assertRaises(AnsibleExitJson) as result:
+ set_module_args({})
+ usb_facts.main()
+ for output_field in self.output_fields:
+ self.assertEqual(result.exception.args[0]["ansible_facts"]["usb_devices"][0][output_field], data[output_field])
+
+ def test_parsing_multiple_lines(self):
+ input = ""
+ for data in self.testing_data:
+ input += ("%s\n" % data["input"])
+ with mock.patch.object(basic.AnsibleModule, 'run_command') as mock_run_command:
+ mock_run_command.return_value = 0, input, None
+ with self.assertRaises(AnsibleExitJson) as result:
+ set_module_args({})
+ usb_facts.main()
+ for index in range(0, len(self.testing_data)):
+ for output_field in self.output_fields:
+ self.assertEqual(result.exception.args[0]["ansible_facts"]["usb_devices"][index][output_field],
+ self.testing_data[index][output_field])
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_xfconf.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_xfconf.py
index c979fd8d2..fbc2dae5f 100644
--- a/ansible_collections/community/general/tests/unit/plugins/modules/test_xfconf.py
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_xfconf.py
@@ -12,301 +12,9 @@
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
-import json
from ansible_collections.community.general.plugins.modules import xfconf
+from .helper import Helper
-import pytest
-TESTED_MODULE = xfconf.__name__
-
-
-@pytest.fixture
-def patch_xfconf(mocker):
- """
- Function used for mocking some parts of redhat_subscription module
- """
- mocker.patch('ansible_collections.community.general.plugins.module_utils.mh.module_helper.AnsibleModule.get_bin_path',
- return_value='/testbin/xfconf-query')
-
-
-@pytest.mark.parametrize('patch_ansible_module', [{}], indirect=['patch_ansible_module'])
-@pytest.mark.usefixtures('patch_ansible_module')
-def test_without_required_parameters(capfd, patch_xfconf):
- """
- Failure must occurs when all parameters are missing
- """
- with pytest.raises(SystemExit):
- xfconf.main()
- out, err = capfd.readouterr()
- results = json.loads(out)
- assert results['failed']
- assert 'missing required arguments' in results['msg']
-
-
-TEST_CASES = [
- [
- {
- 'channel': 'xfwm4',
- 'property': '/general/inactive_opacity',
- 'state': 'present',
- 'value_type': 'int',
- 'value': 90,
- },
- {
- 'id': 'test_property_set_property',
- 'run_command.calls': [
- (
- # Calling of following command will be asserted
- ['/testbin/xfconf-query', '--channel', 'xfwm4', '--property', '/general/inactive_opacity'],
- # Was return code checked?
- {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
- # Mock of returned code, stdout and stderr
- (0, '100\n', '',),
- ),
- (
- # Calling of following command will be asserted
- ['/testbin/xfconf-query', '--channel', 'xfwm4', '--property', '/general/inactive_opacity',
- '--create', '--type', 'int', '--set', '90'],
- # Was return code checked?
- {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
- # Mock of returned code, stdout and stderr
- (0, '', '',),
- ),
- ],
- 'changed': True,
- 'previous_value': '100',
- 'value_type': 'int',
- 'value': '90',
- },
- ],
- [
- {
- 'channel': 'xfwm4',
- 'property': '/general/inactive_opacity',
- 'state': 'present',
- 'value_type': 'int',
- 'value': 90,
- },
- {
- 'id': 'test_property_set_property_same_value',
- 'run_command.calls': [
- (
- # Calling of following command will be asserted
- ['/testbin/xfconf-query', '--channel', 'xfwm4', '--property', '/general/inactive_opacity'],
- # Was return code checked?
- {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
- # Mock of returned code, stdout and stderr
- (0, '90\n', '',),
- ),
- (
- # Calling of following command will be asserted
- ['/testbin/xfconf-query', '--channel', 'xfwm4', '--property', '/general/inactive_opacity',
- '--create', '--type', 'int', '--set', '90'],
- # Was return code checked?
- {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
- # Mock of returned code, stdout and stderr
- (0, '', '',),
- ),
- ],
- 'changed': False,
- 'previous_value': '90',
- 'value_type': 'int',
- 'value': '90',
- },
- ],
- [
- {
- 'channel': 'xfce4-session',
- 'property': '/general/SaveOnExit',
- 'state': 'present',
- 'value_type': 'bool',
- 'value': False,
- },
- {
- 'id': 'test_property_set_property_bool_false',
- 'run_command.calls': [
- (
- # Calling of following command will be asserted
- ['/testbin/xfconf-query', '--channel', 'xfce4-session', '--property', '/general/SaveOnExit'],
- # Was return code checked?
- {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
- # Mock of returned code, stdout and stderr
- (0, 'true\n', '',),
- ),
- (
- # Calling of following command will be asserted
- ['/testbin/xfconf-query', '--channel', 'xfce4-session', '--property', '/general/SaveOnExit',
- '--create', '--type', 'bool', '--set', 'false'],
- # Was return code checked?
- {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
- # Mock of returned code, stdout and stderr
- (0, 'false\n', '',),
- ),
- ],
- 'changed': True,
- 'previous_value': 'true',
- 'value_type': 'bool',
- 'value': 'False',
- },
- ],
- [
- {
- 'channel': 'xfwm4',
- 'property': '/general/workspace_names',
- 'state': 'present',
- 'value_type': 'string',
- 'value': ['A', 'B', 'C'],
- },
- {
- 'id': 'test_property_set_array',
- 'run_command.calls': [
- (
- # Calling of following command will be asserted
- ['/testbin/xfconf-query', '--channel', 'xfwm4', '--property', '/general/workspace_names'],
- # Was return code checked?
- {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
- # Mock of returned code, stdout and stderr
- (0, 'Value is an array with 3 items:\n\nMain\nWork\nTmp\n', '',),
- ),
- (
- # Calling of following command will be asserted
- ['/testbin/xfconf-query', '--channel', 'xfwm4', '--property', '/general/workspace_names',
- '--create', '--force-array', '--type', 'string', '--set', 'A', '--type', 'string', '--set', 'B',
- '--type', 'string', '--set', 'C'],
- # Was return code checked?
- {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
- # Mock of returned code, stdout and stderr
- (0, '', '',),
- ),
- ],
- 'changed': True,
- 'previous_value': ['Main', 'Work', 'Tmp'],
- 'value_type': ['str', 'str', 'str'],
- 'value': ['A', 'B', 'C'],
- },
- ],
- [
- {
- 'channel': 'xfwm4',
- 'property': '/general/workspace_names',
- 'state': 'present',
- 'value_type': 'string',
- 'value': ['A', 'B', 'C'],
- },
- {
- 'id': 'test_property_set_array_to_same_value',
- 'run_command.calls': [
- (
- # Calling of following command will be asserted
- ['/testbin/xfconf-query', '--channel', 'xfwm4', '--property', '/general/workspace_names'],
- # Was return code checked?
- {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
- # Mock of returned code, stdout and stderr
- (0, 'Value is an array with 3 items:\n\nA\nB\nC\n', '',),
- ),
- (
- # Calling of following command will be asserted
- ['/testbin/xfconf-query', '--channel', 'xfwm4', '--property', '/general/workspace_names',
- '--create', '--force-array', '--type', 'string', '--set', 'A', '--type', 'string', '--set', 'B',
- '--type', 'string', '--set', 'C'],
- # Was return code checked?
- {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
- # Mock of returned code, stdout and stderr
- (0, '', '',),
- ),
- ],
- 'changed': False,
- 'previous_value': ['A', 'B', 'C'],
- 'value_type': ['str', 'str', 'str'],
- 'value': ['A', 'B', 'C'],
- },
- ],
- [
- {
- 'channel': 'xfwm4',
- 'property': '/general/workspace_names',
- 'state': 'absent',
- },
- {
- 'id': 'test_property_reset_value',
- 'run_command.calls': [
- (
- # Calling of following command will be asserted
- ['/testbin/xfconf-query', '--channel', 'xfwm4', '--property', '/general/workspace_names'],
- # Was return code checked?
- {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
- # Mock of returned code, stdout and stderr
- (0, 'Value is an array with 3 items:\n\nA\nB\nC\n', '',),
- ),
- (
- # Calling of following command will be asserted
- ['/testbin/xfconf-query', '--channel', 'xfwm4', '--property', '/general/workspace_names',
- '--reset'],
- # Was return code checked?
- {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': False},
- # Mock of returned code, stdout and stderr
- (0, '', '',),
- ),
- ],
- 'changed': True,
- 'previous_value': ['A', 'B', 'C'],
- 'value_type': None,
- 'value': None,
- },
- ],
-]
-TEST_CASES_IDS = [item[1]['id'] for item in TEST_CASES]
-
-
-@pytest.mark.parametrize('patch_ansible_module, testcase',
- TEST_CASES,
- ids=TEST_CASES_IDS,
- indirect=['patch_ansible_module'])
-@pytest.mark.usefixtures('patch_ansible_module')
-def test_xfconf(mocker, capfd, patch_xfconf, testcase):
- """
- Run unit tests for test cases listen in TEST_CASES
- """
-
- # Mock function used for running commands first
- call_results = [item[2] for item in testcase['run_command.calls']]
- mock_run_command = mocker.patch(
- 'ansible.module_utils.basic.AnsibleModule.run_command',
- side_effect=call_results)
-
- # Try to run test case
- with pytest.raises(SystemExit):
- xfconf.main()
-
- out, err = capfd.readouterr()
- results = json.loads(out)
- print("testcase =\n%s" % testcase)
- print("results =\n%s" % results)
-
- assert 'changed' in results
- assert results['changed'] == testcase['changed']
-
- for test_result in ('channel', 'property'):
- assert test_result in results, "'{0}' not found in {1}".format(test_result, results)
- assert results[test_result] == results['invocation']['module_args'][test_result], \
- "'{0}': '{1}' != '{2}'".format(test_result, results[test_result], results['invocation']['module_args'][test_result])
-
- assert mock_run_command.call_count == len(testcase['run_command.calls'])
- if mock_run_command.call_count:
- call_args_list = [(item[0][0], item[1]) for item in mock_run_command.call_args_list]
- expected_call_args_list = [(item[0], item[1]) for item in testcase['run_command.calls']]
- print("call args list =\n%s" % call_args_list)
- print("expected args list =\n%s" % expected_call_args_list)
- assert call_args_list == expected_call_args_list
-
- expected_cmd, dummy, expected_res = testcase['run_command.calls'][-1]
- assert results['cmd'] == expected_cmd
- assert results['stdout'] == expected_res[1]
- assert results['stderr'] == expected_res[2]
-
- for conditional_test_result in ('msg', 'value', 'previous_value'):
- if conditional_test_result in testcase:
- assert conditional_test_result in results, "'{0}' not found in {1}".format(conditional_test_result, results)
- assert results[conditional_test_result] == testcase[conditional_test_result], \
- "'{0}': '{1}' != '{2}'".format(conditional_test_result, results[conditional_test_result], testcase[conditional_test_result])
+Helper.from_module(xfconf, __name__)
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_xfconf.yaml b/ansible_collections/community/general/tests/unit/plugins/modules/test_xfconf.yaml
new file mode 100644
index 000000000..908154df2
--- /dev/null
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_xfconf.yaml
@@ -0,0 +1,185 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) Alexei Znamensky (russoz@gmail.com)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+---
+- id: test_missing_input
+ input: {}
+ output:
+ failed: true
+ msg: "missing required arguments: channel, property"
+- id: test_property_set_property
+ input:
+ channel: xfwm4
+ property: /general/inactive_opacity
+ state: present
+ value_type: int
+ value: 90
+ output:
+ changed: true
+ previous_value: '100'
+ type: int
+ value: '90'
+ run_command_calls:
+ - command: [/testbin/xfconf-query, --channel, xfwm4, --property, /general/inactive_opacity]
+ environ: &env-def {environ_update: {LANGUAGE: C, LC_ALL: C}, check_rc: false}
+ rc: 0
+ out: "100\n"
+ err: ""
+ - command: [/testbin/xfconf-query, --channel, xfwm4, --property, /general/inactive_opacity, --create, --type, int, --set, '90']
+ environ: *env-def
+ rc: 0
+ out: ""
+ err: ""
+- id: test_property_set_property_same_value
+ input:
+ channel: xfwm4
+ property: /general/inactive_opacity
+ state: present
+ value_type: int
+ value: 90
+ output:
+ changed: false
+ previous_value: '90'
+ type: int
+ value: '90'
+ run_command_calls:
+ - command: [/testbin/xfconf-query, --channel, xfwm4, --property, /general/inactive_opacity]
+ environ: *env-def
+ rc: 0
+ out: "90\n"
+ err: ""
+ - command: [/testbin/xfconf-query, --channel, xfwm4, --property, /general/inactive_opacity, --create, --type, int, --set, '90']
+ environ: *env-def
+ rc: 0
+ out: ""
+ err: ""
+- id: test_property_set_property_bool_false
+ input:
+ channel: xfce4-session
+ property: /general/SaveOnExit
+ state: present
+ value_type: bool
+ value: False
+ output:
+ changed: true
+ previous_value: 'true'
+ type: bool
+ value: 'False'
+ run_command_calls:
+ - command: [/testbin/xfconf-query, --channel, xfce4-session, --property, /general/SaveOnExit]
+ environ: *env-def
+ rc: 0
+ out: "true\n"
+ err: ""
+ - command: [/testbin/xfconf-query, --channel, xfce4-session, --property, /general/SaveOnExit, --create, --type, bool, --set, 'false']
+ environ: *env-def
+ rc: 0
+ out: "false\n"
+ err: ""
+- id: test_property_set_array
+ input:
+ channel: xfwm4
+ property: /general/workspace_names
+ state: present
+ value_type: string
+ value: [A, B, C]
+ output:
+ changed: true
+ previous_value: [Main, Work, Tmp]
+ type: [string, string, string]
+ value: [A, B, C]
+ run_command_calls:
+ - command: [/testbin/xfconf-query, --channel, xfwm4, --property, /general/workspace_names]
+ environ: *env-def
+ rc: 0
+ out: "Value is an array with 3 items:\n\nMain\nWork\nTmp\n"
+ err: ""
+ - command:
+ - /testbin/xfconf-query
+ - --channel
+ - xfwm4
+ - --property
+ - /general/workspace_names
+ - --create
+ - --force-array
+ - --type
+ - string
+ - --set
+ - A
+ - --type
+ - string
+ - --set
+ - B
+ - --type
+ - string
+ - --set
+ - C
+ environ: *env-def
+ rc: 0
+ out: ""
+ err: ""
+- id: test_property_set_array_to_same_value
+ input:
+ channel: xfwm4
+ property: /general/workspace_names
+ state: present
+ value_type: string
+ value: [A, B, C]
+ output:
+ changed: false
+ previous_value: [A, B, C]
+ type: [string, string, string]
+ value: [A, B, C]
+ run_command_calls:
+ - command: [/testbin/xfconf-query, --channel, xfwm4, --property, /general/workspace_names]
+ environ: *env-def
+ rc: 0
+ out: "Value is an array with 3 items:\n\nA\nB\nC\n"
+ err: ""
+ - command:
+ - /testbin/xfconf-query
+ - --channel
+ - xfwm4
+ - --property
+ - /general/workspace_names
+ - --create
+ - --force-array
+ - --type
+ - string
+ - --set
+ - A
+ - --type
+ - string
+ - --set
+ - B
+ - --type
+ - string
+ - --set
+ - C
+ environ: *env-def
+ rc: 0
+ out: ""
+ err: ""
+- id: test_property_reset_value
+ input:
+ channel: xfwm4
+ property: /general/workspace_names
+ state: absent
+ output:
+ changed: true
+ previous_value: [A, B, C]
+ type: null
+ value: null
+ run_command_calls:
+ - command: [/testbin/xfconf-query, --channel, xfwm4, --property, /general/workspace_names]
+ environ: *env-def
+ rc: 0
+ out: "Value is an array with 3 items:\n\nA\nB\nC\n"
+ err: ""
+ - command: [/testbin/xfconf-query, --channel, xfwm4, --property, /general/workspace_names, --reset]
+ environ: *env-def
+ rc: 0
+ out: ""
+ err: ""
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_xfconf_info.py b/ansible_collections/community/general/tests/unit/plugins/modules/test_xfconf_info.py
index dfcd4f33a..67c63dda0 100644
--- a/ansible_collections/community/general/tests/unit/plugins/modules/test_xfconf_info.py
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_xfconf_info.py
@@ -5,168 +5,9 @@
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
-import json
from ansible_collections.community.general.plugins.modules import xfconf_info
+from .helper import Helper
-import pytest
-TESTED_MODULE = xfconf_info.__name__
-
-
-@pytest.fixture
-def patch_xfconf_info(mocker):
- """
- Function used for mocking some parts of redhat_subscription module
- """
- mocker.patch('ansible_collections.community.general.plugins.module_utils.mh.module_helper.AnsibleModule.get_bin_path',
- return_value='/testbin/xfconf-query')
-
-
-TEST_CASES = [
- [
- {'channel': 'xfwm4', 'property': '/general/inactive_opacity'},
- {
- 'id': 'test_simple_property_get',
- 'run_command.calls': [
- (
- # Calling of following command will be asserted
- ['/testbin/xfconf-query', '--channel', 'xfwm4', '--property', '/general/inactive_opacity'],
- # Was return code checked?
- {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': True},
- # Mock of returned code, stdout and stderr
- (0, '100\n', '',),
- ),
- ],
- 'is_array': False,
- 'value': '100',
- }
- ],
- [
- {'channel': 'xfwm4', 'property': '/general/i_dont_exist'},
- {
- 'id': 'test_simple_property_get_nonexistent',
- 'run_command.calls': [
- (
- # Calling of following command will be asserted
- ['/testbin/xfconf-query', '--channel', 'xfwm4', '--property', '/general/i_dont_exist'],
- # Was return code checked?
- {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': True},
- # Mock of returned code, stdout and stderr
- (1, '', 'Property "/general/i_dont_exist" does not exist on channel "xfwm4".\n',),
- ),
- ],
- 'is_array': False,
- }
- ],
- [
- {'property': '/general/i_dont_exist'},
- {
- 'id': 'test_property_no_channel',
- 'run_command.calls': [],
- }
- ],
- [
- {'channel': 'xfwm4', 'property': '/general/workspace_names'},
- {
- 'id': 'test_property_get_array',
- 'run_command.calls': [
- (
- # Calling of following command will be asserted
- ['/testbin/xfconf-query', '--channel', 'xfwm4', '--property', '/general/workspace_names'],
- # Was return code checked?
- {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': True},
- # Mock of returned code, stdout and stderr
- (0, 'Value is an array with 3 items:\n\nMain\nWork\nTmp\n', '',),
- ),
- ],
- 'is_array': True,
- 'value_array': ['Main', 'Work', 'Tmp'],
- },
- ],
- [
- {},
- {
- 'id': 'get_channels',
- 'run_command.calls': [
- (
- # Calling of following command will be asserted
- ['/testbin/xfconf-query', '--list'],
- # Was return code checked?
- {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': True},
- # Mock of returned code, stdout and stderr
- (0, 'Channels:\n a\n b\n c\n', '',),
- ),
- ],
- 'is_array': False,
- 'channels': ['a', 'b', 'c'],
- },
- ],
- [
- {'channel': 'xfwm4'},
- {
- 'id': 'get_properties',
- 'run_command.calls': [
- (
- # Calling of following command will be asserted
- ['/testbin/xfconf-query', '--list', '--channel', 'xfwm4'],
- # Was return code checked?
- {'environ_update': {'LANGUAGE': 'C', 'LC_ALL': 'C'}, 'check_rc': True},
- # Mock of returned code, stdout and stderr
- (0, '/general/wrap_cycle\n/general/wrap_layout\n/general/wrap_resistance\n/general/wrap_windows\n'
- '/general/wrap_workspaces\n/general/zoom_desktop\n', '',),
- ),
- ],
- 'is_array': False,
- 'properties': [
- '/general/wrap_cycle',
- '/general/wrap_layout',
- '/general/wrap_resistance',
- '/general/wrap_windows',
- '/general/wrap_workspaces',
- '/general/zoom_desktop',
- ],
- },
- ],
-]
-TEST_CASES_IDS = [item[1]['id'] for item in TEST_CASES]
-
-
-@pytest.mark.parametrize('patch_ansible_module, testcase',
- TEST_CASES,
- ids=TEST_CASES_IDS,
- indirect=['patch_ansible_module'])
-@pytest.mark.usefixtures('patch_ansible_module')
-def test_xfconf_info(mocker, capfd, patch_xfconf_info, testcase):
- """
- Run unit tests for test cases listen in TEST_CASES
- """
-
- # Mock function used for running commands first
- call_results = [item[2] for item in testcase['run_command.calls']]
- mock_run_command = mocker.patch(
- 'ansible_collections.community.general.plugins.module_utils.mh.module_helper.AnsibleModule.run_command',
- side_effect=call_results)
-
- # Try to run test case
- with pytest.raises(SystemExit):
- xfconf_info.main()
-
- out, err = capfd.readouterr()
- results = json.loads(out)
- print("testcase =\n%s" % testcase)
- print("results =\n%s" % results)
-
- for conditional_test_result in ('value_array', 'value', 'is_array', 'properties', 'channels'):
- if conditional_test_result in testcase:
- assert conditional_test_result in results, "'{0}' not found in {1}".format(conditional_test_result, results)
- assert results[conditional_test_result] == testcase[conditional_test_result], \
- "'{0}': '{1}' != '{2}'".format(conditional_test_result, results[conditional_test_result], testcase[conditional_test_result])
-
- assert mock_run_command.call_count == len(testcase['run_command.calls'])
- if mock_run_command.call_count:
- call_args_list = [(item[0][0], item[1]) for item in mock_run_command.call_args_list]
- expected_call_args_list = [(item[0], item[1]) for item in testcase['run_command.calls']]
- print("call args list =\n%s" % call_args_list)
- print("expected args list =\n%s" % expected_call_args_list)
- assert call_args_list == expected_call_args_list
+Helper.from_module(xfconf_info, __name__)
diff --git a/ansible_collections/community/general/tests/unit/plugins/modules/test_xfconf_info.yaml b/ansible_collections/community/general/tests/unit/plugins/modules/test_xfconf_info.yaml
new file mode 100644
index 000000000..519a87fdb
--- /dev/null
+++ b/ansible_collections/community/general/tests/unit/plugins/modules/test_xfconf_info.yaml
@@ -0,0 +1,83 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) Alexei Znamensky (russoz@gmail.com)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+---
+- id: test_simple_property_get
+ input:
+ channel: xfwm4
+ property: /general/inactive_opacity
+ output:
+ value: '100'
+ is_array: false
+ run_command_calls:
+ - command: [/testbin/xfconf-query, --channel, xfwm4, --property, /general/inactive_opacity]
+ environ: &env-def {environ_update: {LANGUAGE: C, LC_ALL: C}, check_rc: true}
+ rc: 0
+ out: "100\n"
+ err: ""
+- id: test_simple_property_get_nonexistent
+ input:
+ channel: xfwm4
+ property: /general/i_dont_exist
+ output: {}
+ run_command_calls:
+ - command: [/testbin/xfconf-query, --channel, xfwm4, --property, /general/i_dont_exist]
+ environ: *env-def
+ rc: 1
+ out: ""
+ err: 'Property "/general/i_dont_exist" does not exist on channel "xfwm4".\n'
+- id: test_property_no_channel
+ input:
+ property: /general/i_dont_exist
+ output:
+ failed: true
+ msg: "missing parameter(s) required by 'property': channel"
+ run_command_calls: []
+- id: test_property_get_array
+ input:
+ channel: xfwm4
+ property: /general/workspace_names
+ output:
+ is_array: true
+ value_array: [Main, Work, Tmp]
+ run_command_calls:
+ - command: [/testbin/xfconf-query, --channel, xfwm4, --property, /general/workspace_names]
+ environ: *env-def
+ rc: 0
+ out: "Value is an array with 3 items:\n\nMain\nWork\nTmp\n"
+ err: ""
+- id: get_channels
+ input: {}
+ output:
+ channels: [a, b, c]
+ run_command_calls:
+ - command: [/testbin/xfconf-query, --list]
+ environ: *env-def
+ rc: 0
+ out: "Channels:\n a\n b\n c\n"
+ err: ""
+- id: get_properties
+ input:
+ channel: xfwm4
+ output:
+ properties:
+ - /general/wrap_cycle
+ - /general/wrap_layout
+ - /general/wrap_resistance
+ - /general/wrap_windows
+ - /general/wrap_workspaces
+ - /general/zoom_desktop
+ run_command_calls:
+ - command: [/testbin/xfconf-query, --list, --channel, xfwm4]
+ environ: *env-def
+ rc: 0
+ out: |
+ /general/wrap_cycle
+ /general/wrap_layout
+ /general/wrap_resistance
+ /general/wrap_windows
+ /general/wrap_workspaces
+ /general/zoom_desktop
+ err: ""
diff --git a/ansible_collections/community/general/tests/unit/requirements.txt b/ansible_collections/community/general/tests/unit/requirements.txt
index 0aa7c1fc9..218fe4567 100644
--- a/ansible_collections/community/general/tests/unit/requirements.txt
+++ b/ansible_collections/community/general/tests/unit/requirements.txt
@@ -6,10 +6,12 @@ unittest2 ; python_version < '2.7'
importlib ; python_version < '2.7'
# requirement for the memcached cache plugin
-python-memcached
+python-memcached < 1.60 ; python_version < '3.6'
+python-memcached ; python_version >= '3.6'
# requirement for the redis cache plugin
redis
+async-timeout ; python_version == '3.11'
# requirement for the linode module
linode-python # APIv3
@@ -43,4 +45,12 @@ dataclasses ; python_version == '3.6'
elastic-apm ; python_version >= '3.6'
# requirements for scaleway modules
-passlib[argon2] \ No newline at end of file
+passlib[argon2]
+
+# requirements for the proxmox modules
+proxmoxer < 2.0.0 ; python_version >= '2.7' and python_version <= '3.6'
+proxmoxer ; python_version > '3.6'
+
+#requirements for nomad_token modules
+python-nomad < 2.0.0 ; python_version <= '3.6'
+python-nomad >= 2.0.0 ; python_version >= '3.7'
diff --git a/ansible_collections/community/general/tests/utils/constraints.txt b/ansible_collections/community/general/tests/utils/constraints.txt
index 4fb5276e2..c4d0312d8 100644
--- a/ansible_collections/community/general/tests/utils/constraints.txt
+++ b/ansible_collections/community/general/tests/utils/constraints.txt
@@ -19,7 +19,7 @@ wheel < 0.30.0 ; python_version < '2.7' # wheel 0.30.0 and later require python
yamllint != 1.8.0, < 1.14.0 ; python_version < '2.7' # yamllint 1.8.0 and 1.14.0+ require python 2.7+
pycrypto >= 2.6 # Need features found in 2.6 and greater
ncclient >= 0.5.2 # Need features added in 0.5.2 and greater
-idna < 2.6, >= 2.5 # linode requires idna < 2.9, >= 2.5, requests requires idna < 2.6, but cryptography will cause the latest version to be installed instead
+# idna < 2.6, >= 2.5 # linode requires idna < 2.9, >= 2.5, requests requires idna < 2.6, but cryptography will cause the latest version to be installed instead
paramiko < 2.4.0 ; python_version < '2.7' # paramiko 2.4.0 drops support for python 2.6
python-nomad < 2.0.0 ; python_version <= '3.7' # python-nomad 2.0.0 needs Python 3.7+
pytest < 3.3.0 ; python_version < '2.7' # pytest 3.3.0 drops support for python 2.6
diff --git a/ansible_collections/community/general/tests/utils/shippable/shippable.sh b/ansible_collections/community/general/tests/utils/shippable/shippable.sh
index e98680438..e288cca1c 100755
--- a/ansible_collections/community/general/tests/utils/shippable/shippable.sh
+++ b/ansible_collections/community/general/tests/utils/shippable/shippable.sh
@@ -65,16 +65,7 @@ else
retry pip install "https://github.com/ansible/ansible/archive/stable-${ansible_version}.tar.gz" --disable-pip-version-check
fi
-if [ "${SHIPPABLE_BUILD_ID:-}" ]; then
- export ANSIBLE_COLLECTIONS_PATHS="${HOME}/.ansible"
- SHIPPABLE_RESULT_DIR="$(pwd)/shippable"
- TEST_DIR="${ANSIBLE_COLLECTIONS_PATHS}/ansible_collections/community/general"
- mkdir -p "${TEST_DIR}"
- cp -aT "${SHIPPABLE_BUILD_DIR}" "${TEST_DIR}"
- cd "${TEST_DIR}"
-else
- export ANSIBLE_COLLECTIONS_PATHS="${PWD}/../../../"
-fi
+export ANSIBLE_COLLECTIONS_PATHS="${PWD}/../../../"
if [ "${test}" == "sanity/extra" ]; then
retry pip install junit-xml --disable-pip-version-check
diff --git a/ansible_collections/community/google/.github/workflows/ansible-test.yml b/ansible_collections/community/google/.github/workflows/ansible-test.yml
deleted file mode 100644
index 652b774ac..000000000
--- a/ansible_collections/community/google/.github/workflows/ansible-test.yml
+++ /dev/null
@@ -1,110 +0,0 @@
-# README FIRST
-# 1. replace "NAMESPACE" and "COLLECTION_NAME" with the correct name in the env section (e.g. with 'community' and 'mycollection')
-# 2. If you don't have unit tests remove that section
-# 3. If your collection depends on other collections ensure they are installed, see "Install collection dependencies"
-# If you need help please ask in #ansible-devel on Freenode IRC
-
-name: CI
-on:
- # Run CI against all pushes (direct commits, also merged PRs), Pull Requests
- push:
- pull_request:
- schedule:
- - cron: '0 6 * * *'
-env:
- NAMESPACE: community
- COLLECTION_NAME: google
-
-jobs:
-
-###
-# Sanity tests (REQUIRED)
-#
-# https://docs.ansible.com/ansible/latest/dev_guide/testing_sanity.html
-
- sanity:
- name: Sanity (Ⓐ${{ matrix.ansible }})
- strategy:
- matrix:
- ansible:
- # It's important that Sanity is tested against all stable-X.Y branches
- # Testing against `devel` may fail as new tests are added.
- # - stable-2.9 # Only if your collection supports Ansible 2.9
- - stable-2.10
- - devel
- runs-on: ubuntu-latest
- steps:
-
- # ansible-test requires the collection to be in a directory in the form
- # .../ansible_collections/${{env.NAMESPACE}}/${{env.COLLECTION_NAME}}/
-
- - name: Check out code
- uses: actions/checkout@v2
- with:
- path: ansible_collections/${{env.NAMESPACE}}/${{env.COLLECTION_NAME}}
-
- - name: Set up Python
- uses: actions/setup-python@v2
- with:
- # it is just required to run that once as "ansible-test sanity" in the docker image
- # will run on all python versions it supports.
- python-version: 3.8
-
- # Install the head of the given branch (devel, stable-2.10)
- - name: Install ansible-base (${{ matrix.ansible }})
- run: pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz --disable-pip-version-check
-
- # run ansible-test sanity inside of Docker.
- # The docker container has all the pinned dependencies that are required
- # and all python versions ansible supports.
- - name: Run sanity tests
- run: ansible-test sanity --docker -v --color
- working-directory: ./ansible_collections/${{env.NAMESPACE}}/${{env.COLLECTION_NAME}}
-
-###
-# Unit tests (OPTIONAL)
-#
-# https://docs.ansible.com/ansible/latest/dev_guide/testing_units.html
-
- units:
- runs-on: ubuntu-latest
- name: Units (Ⓐ${{ matrix.ansible }})
- strategy:
- # As soon as the first unit test fails, cancel the others to free up the CI queue
- fail-fast: true
- matrix:
- ansible:
- # - stable-2.9 # Only if your collection supports Ansible 2.9
- - stable-2.10
- - devel
-
- steps:
- - name: Check out code
- uses: actions/checkout@v2
- with:
- path: ansible_collections/${{env.NAMESPACE}}/${{env.COLLECTION_NAME}}
-
- - name: Set up Python
- uses: actions/setup-python@v2
- with:
- # it is just required to run that once as "ansible-test units" in the docker image
- # will run on all python versions it supports.
- python-version: 3.8
-
- - name: Install ansible-base (${{ matrix.ansible }})
- run: pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz --disable-pip-version-check
-
- # Run the unit tests
- - name: Run unit test
- run: ansible-test units -v --color --docker --coverage
- working-directory: ./ansible_collections/${{env.NAMESPACE}}/${{env.COLLECTION_NAME}}
-
- # ansible-test support producing code coverage date
- - name: Generate coverage report
- run: ansible-test coverage xml -v --requirements --group-by command --group-by version
- working-directory: ./ansible_collections/${{env.NAMESPACE}}/${{env.COLLECTION_NAME}}
-
- # See the reports at https://codecov.io/gh/GITHUBORG/REPONAME
- - uses: codecov/codecov-action@v1
- with:
- fail_ci_if_error: false
diff --git a/ansible_collections/community/google/CHANGELOG.rst b/ansible_collections/community/google/CHANGELOG.rst
deleted file mode 100644
index 8e33c3d75..000000000
--- a/ansible_collections/community/google/CHANGELOG.rst
+++ /dev/null
@@ -1,23 +0,0 @@
-==============================
-community.google Release Notes
-==============================
-
-.. contents:: Topics
-
-
-v1.0.0
-======
-
-Release Summary
----------------
-
-This is the first stable release version of community.google.
-
-v0.1.0
-======
-
-Release Summary
----------------
-
-This is the first pre-release version of community.google after migrating from community.general.
-
diff --git a/ansible_collections/community/google/FILES.json b/ansible_collections/community/google/FILES.json
deleted file mode 100644
index ff7fa022a..000000000
--- a/ansible_collections/community/google/FILES.json
+++ /dev/null
@@ -1,418 +0,0 @@
-{
- "files": [
- {
- "name": ".",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "LICENSE",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "3972dc9744f6499f0f9b2dbf76696f2ae7ad8af9b23dde66d6af86c9dfb36986",
- "format": 1
- },
- {
- "name": "README.md",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "42d8f0ee470ee5760bc195e06fb35ba0d4cf1d2f0663ee1f866d997cb0159bdc",
- "format": 1
- },
- {
- "name": "scripts",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "scripts/inventory",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "scripts/inventory/gce.ini",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "925cfa8728fa00c71d851d13203fc6c9bfe87f96c0528029a0e909a602a0004c",
- "format": 1
- },
- {
- "name": "scripts/inventory/gce.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "e2fd208cca342e3e91d6711bd781bc2658715bf4201fa7d190be8d5ad35dc423",
- "format": 1
- },
- {
- "name": "tests",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/unit",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/unit/requirements.txt",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "b8bc332492969db761f788580155f30f1f57382a5f952cf1a9c920b627843d6f",
- "format": 1
- },
- {
- "name": "tests/unit/plugins",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/unit/plugins/module_utils",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/unit/plugins/module_utils/test_utils.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "19432d0cf6054eff46a50aa1cd9300a3e6bfe1ea118a9906096312daf7ee58aa",
- "format": 1
- },
- {
- "name": "tests/unit/plugins/module_utils/__init__.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
- "format": 1
- },
- {
- "name": "tests/unit/plugins/module_utils/test_auth.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "7f0279cfc003046e5f8e05851e12a8ef2b55d3770dcf9d585376afc5e6477b67",
- "format": 1
- },
- {
- "name": "tests/unit/plugins/modules",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/unit/plugins/modules/test_gce_tag.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "f66f884d5d9a5f4ae7b34ece88d47071e2598a29915b5950e8c957986c80ed10",
- "format": 1
- },
- {
- "name": "tests/unit/plugins/modules/__init__.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
- "format": 1
- },
- {
- "name": "tests/unit/compat",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/unit/compat/mock.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "0af958450cf6de3fbafe94b1111eae8ba5a8dbe1d785ffbb9df81f26e4946d99",
- "format": 1
- },
- {
- "name": "tests/unit/compat/unittest.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "5401a046e5ce71fa19b6d905abd0f9bdf816c0c635f7bdda6730b3ef06e67096",
- "format": 1
- },
- {
- "name": "tests/unit/compat/__init__.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
- "format": 1
- },
- {
- "name": "tests/sanity",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/sanity/ignore-2.11.txt",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "513d336e4fec3987f8bb1946f889e91126eae6e661e64359ecec85e69c00f23c",
- "format": 1
- },
- {
- "name": "tests/sanity/ignore-2.9.txt",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "9914221531e94c75983a9624dcaf8914fc459ba8d0e261ce1462135f300b5617",
- "format": 1
- },
- {
- "name": "tests/sanity/ignore-2.10.txt",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "513d336e4fec3987f8bb1946f889e91126eae6e661e64359ecec85e69c00f23c",
- "format": 1
- },
- {
- "name": "plugins",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "plugins/module_utils",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "plugins/module_utils/gcp.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "a85bdf5808a57d1860fd128e8bf93be1ec8009022d0a0e8fdc1af3732c2e8a9e",
- "format": 1
- },
- {
- "name": "plugins/module_utils/gce.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "282fc5e4c59582e8ea24ecb406ec7e5f14953a8d305002fbacda680811628d32",
- "format": 1
- },
- {
- "name": "plugins/doc_fragments",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "plugins/doc_fragments/_gcp.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "31581014875f54e52e1ece32efe3b581b175c7bec2d939571d892daf2302219d",
- "format": 1
- },
- {
- "name": "plugins/modules",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "plugins/modules/gc_storage.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "6390536b4af26888d58eea69390ed7590c637e83aa7fe278da7a776267517416",
- "format": 1
- },
- {
- "name": "plugins/modules/gce_net.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "7346ffb330fd4a4aca1937a1bdc9647e117c02e2dd701b72f1e46859107e0fb5",
- "format": 1
- },
- {
- "name": "plugins/modules/gcpubsub.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "04636fac7225cdd6a5ca34ea471ad19749c14afc17ec6642c58b66f688d9205a",
- "format": 1
- },
- {
- "name": "plugins/modules/gce_img.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "ac082df31a9c7bc156c0698c4175e5f593bad90f634f27b60653542de122e12d",
- "format": 1
- },
- {
- "name": "plugins/modules/gce_tag.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "fe08d5ac7faee9f7a8033b19ab4dccc5c76c46a4524c83a935dd89856bcd4c01",
- "format": 1
- },
- {
- "name": "plugins/modules/gce_instance_template.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "536e39871eba316c2264690c0ff26a2732b2be8f31215a03bd65d36dc7638480",
- "format": 1
- },
- {
- "name": "plugins/modules/gce_snapshot.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "db83ddf7998f915e702851bfa122817a0d99f2e60c257f1899f639b2186faa49",
- "format": 1
- },
- {
- "name": "plugins/modules/gce_pd.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "0d3cb555bf6b2095751eb4d5a984c9eab8bcbe6e6073c33749d15a80e976b3eb",
- "format": 1
- },
- {
- "name": "plugins/modules/gce_eip.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "cc2585ec223fdbac121d7ba6e711e5bdbb574102d63779d17b429b7630fa3771",
- "format": 1
- },
- {
- "name": "plugins/modules/gce_mig.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "4dd037f1fd3a58af68217a4d213cde47dd835730e09fe840ab2b0aa4a6df6a2e",
- "format": 1
- },
- {
- "name": "plugins/modules/gce_labels.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "419e6fc92f59717da395a4d70c778d18475940431517071e8c1ed051d3694bc4",
- "format": 1
- },
- {
- "name": "plugins/modules/gcpubsub_info.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "9ef79767bdeee07d33aefe342ab4298f5d38c091ed5c58f6872d550d3b0f1f92",
- "format": 1
- },
- {
- "name": "plugins/modules/gce_lb.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "54de796b84bf1308d370b1c015b0e968d48e0f821e7ae382a63b0f61ff4d87f2",
- "format": 1
- },
- {
- "name": "plugins/lookup",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "plugins/lookup/gcp_storage_file.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "969de4dedeb2b6be2f3fe6c6072bdc4481f4b2e427e72eac03eb6c5359634a2b",
- "format": 1
- },
- {
- "name": "changelogs",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "changelogs/fragments",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "changelogs/fragments/.keep",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
- "format": 1
- },
- {
- "name": "changelogs/changelog.yaml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "48a6a9e80e1629dbccaaa278f83493de9b19ca26a4334e7b114adc86f014332f",
- "format": 1
- },
- {
- "name": "changelogs/config.yaml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "d18c3fb08d51d89b581031b5079624a86306457a85ba48938c27152e38881fe9",
- "format": 1
- },
- {
- "name": "meta",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "meta/runtime.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "3b0634ab394e8ced5d60b2532bfa8ed14cec4c7d4739c9e0277c760c5543c0e1",
- "format": 1
- },
- {
- "name": "CHANGELOG.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "1f5a70b361b5f1a356efddb0abde59de7d80197b7302859dd7155c7ad4e43b64",
- "format": 1
- },
- {
- "name": ".github",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": ".github/workflows",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": ".github/workflows/ansible-test.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "57d072bb0337cf78a96fd4e2ee58f0e8d57e21da29bd9642adfbaed25556549c",
- "format": 1
- }
- ],
- "format": 1
-} \ No newline at end of file
diff --git a/ansible_collections/community/google/MANIFEST.json b/ansible_collections/community/google/MANIFEST.json
deleted file mode 100644
index aab8d0781..000000000
--- a/ansible_collections/community/google/MANIFEST.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "collection_info": {
- "namespace": "community",
- "name": "google",
- "version": "1.0.0",
- "authors": [
- "Google"
- ],
- "readme": "README.md",
- "tags": [
- "google",
- "gce",
- "gcp"
- ],
- "description": "Google Cloud Platform community collection",
- "license": [],
- "license_file": "LICENSE",
- "dependencies": {},
- "repository": "https://github.com/ansible-collections/community.google",
- "documentation": null,
- "homepage": "https://github.com/ansible-collections/community.google",
- "issues": "https://github.com/ansible-collections/community.google/issues"
- },
- "file_manifest_file": {
- "name": "FILES.json",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "6dfe9e97ce5637373663dd885af32c1deb5c10352c3440296526b3b4fe5d401c",
- "format": 1
- },
- "format": 1
-} \ No newline at end of file
diff --git a/ansible_collections/community/google/README.md b/ansible_collections/community/google/README.md
deleted file mode 100644
index 27122af06..000000000
--- a/ansible_collections/community/google/README.md
+++ /dev/null
@@ -1,38 +0,0 @@
-# community.google Ansible collection
-[![CI](https://github.com/ansible-collections/community.google/workflows/CI/badge.svg?event=push)](https://github.com/ansible-collections/community.google/actions) [![Codecov](https://img.shields.io/codecov/c/github/ansible-collections/community.google)](https://codecov.io/gh/ansible-collections/community.google)
-
-## External requirements
-
-- boto
-- libcloud
-- google-auth
-
-## Included content
-
-See: https://docs.ansible.com/ansible/latest/collections/community/google/
-
-## Using this collection
-
-See [Ansible Using collections](https://docs.ansible.com/ansible/latest/user_guide/collections_using.html) for more details.
-
-## Release notes
-
-See the [changelog](https://github.com/ansible-collections/community.google/tree/main/CHANGELOG.rst).
-
-## More information
-
-<!-- List out where the user can find additional information, such as working group meeting times, slack/IRC channels, or documentation for the product this collection automates. At a minimum, link to: -->
-
-- [Ansible Collection overview](https://github.com/ansible-collections/overview)
-- [Ansible User guide](https://docs.ansible.com/ansible/latest/user_guide/index.html)
-- [Ansible Developer guide](https://docs.ansible.com/ansible/latest/dev_guide/index.html)
-- [Ansible Collections Checklist](https://github.com/ansible-collections/overview/blob/master/collection_requirements.rst)
-- [Ansible Community code of conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html)
-- [The Bullhorn (the Ansible Contributor newsletter)](https://us19.campaign-archive.com/home/?u=56d874e027110e35dea0e03c1&id=d6635f5420)
-- [Changes impacting Contributors](https://github.com/ansible-collections/overview/issues/45)
-
-## Licensing
-
-GNU General Public License v3.0 or later.
-
-See [LICENSE](https://www.gnu.org/licenses/gpl-3.0.txt) to see the full text.
diff --git a/ansible_collections/community/google/changelogs/changelog.yaml b/ansible_collections/community/google/changelogs/changelog.yaml
deleted file mode 100644
index 13fbdc44d..000000000
--- a/ansible_collections/community/google/changelogs/changelog.yaml
+++ /dev/null
@@ -1,17 +0,0 @@
-ancestor: null
-releases:
- 0.1.0:
- changes:
- release_summary: 'This is the first pre-release version of community.google
- after migrating from community.general.
-
- '
- fragments:
- - 0.1.0.yml
- release_date: '2020-11-30'
- 1.0.0:
- changes:
- release_summary: This is the first stable release version of community.google.
- fragments:
- - 1.0.0.yaml
- release_date: '2020-12-22'
diff --git a/ansible_collections/community/google/changelogs/config.yaml b/ansible_collections/community/google/changelogs/config.yaml
deleted file mode 100644
index 038e5eb48..000000000
--- a/ansible_collections/community/google/changelogs/config.yaml
+++ /dev/null
@@ -1,29 +0,0 @@
-changelog_filename_template: ../CHANGELOG.rst
-changelog_filename_version_depth: 0
-changes_file: changelog.yaml
-changes_format: combined
-keep_fragments: false
-mention_ancestor: true
-new_plugins_after_name: removed_features
-notesdir: fragments
-prelude_section_name: release_summary
-prelude_section_title: Release Summary
-sections:
-- - major_changes
- - Major Changes
-- - minor_changes
- - Minor Changes
-- - breaking_changes
- - Breaking Changes / Porting Guide
-- - deprecated_features
- - Deprecated Features
-- - removed_features
- - Removed Features (previously deprecated)
-- - security_fixes
- - Security Fixes
-- - bugfixes
- - Bugfixes
-- - known_issues
- - Known Issues
-title: community.google
-trivial_section_name: trivial
diff --git a/ansible_collections/community/google/changelogs/fragments/.keep b/ansible_collections/community/google/changelogs/fragments/.keep
deleted file mode 100644
index e69de29bb..000000000
--- a/ansible_collections/community/google/changelogs/fragments/.keep
+++ /dev/null
diff --git a/ansible_collections/community/google/meta/runtime.yml b/ansible_collections/community/google/meta/runtime.yml
deleted file mode 100644
index a9d40b8b5..000000000
--- a/ansible_collections/community/google/meta/runtime.yml
+++ /dev/null
@@ -1,9 +0,0 @@
----
-requires_ansible: '>=2.9.10'
-plugin_routing:
- modules:
- gcpubsub_facts:
- redirect: community.google.gcpubsub_info
- deprecation:
- removal_version: 2.0.0
- warning_text: Use community.google.gcpubsub_info instead.
diff --git a/ansible_collections/community/google/plugins/doc_fragments/_gcp.py b/ansible_collections/community/google/plugins/doc_fragments/_gcp.py
deleted file mode 100644
index 068725436..000000000
--- a/ansible_collections/community/google/plugins/doc_fragments/_gcp.py
+++ /dev/null
@@ -1,62 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright: (c) 2018, Google Inc.
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-class ModuleDocFragment(object):
- # GCP doc fragment.
- DOCUMENTATION = r'''
-options:
- project:
- description:
- - The Google Cloud Platform project to use.
- type: str
- auth_kind:
- description:
- - The type of credential used.
- type: str
- required: true
- choices: [ application, machineaccount, serviceaccount ]
- service_account_contents:
- description:
- - The contents of a Service Account JSON file, either in a dictionary or as a JSON string that represents it.
- type: jsonarg
- service_account_file:
- description:
- - The path of a Service Account JSON file if serviceaccount is selected as type.
- type: path
- service_account_email:
- description:
- - An optional service account email address if machineaccount is selected
- and the user does not wish to use the default email.
- type: str
- scopes:
- description:
- - Array of scopes to be used.
- type: list
- elements: str
- env_type:
- description:
- - Specifies which Ansible environment you're running this module within.
- - This should not be set unless you know what you're doing.
- - This only alters the User Agent string for any API requests.
- type: str
-notes:
- - for authentication, you can set service_account_file using the
- c(gcp_service_account_file) env variable.
- - for authentication, you can set service_account_contents using the
- c(GCP_SERVICE_ACCOUNT_CONTENTS) env variable.
- - For authentication, you can set service_account_email using the
- C(GCP_SERVICE_ACCOUNT_EMAIL) env variable.
- - For authentication, you can set auth_kind using the C(GCP_AUTH_KIND) env
- variable.
- - For authentication, you can set scopes using the C(GCP_SCOPES) env variable.
- - Environment variables values will only be used if the playbook values are
- not set.
- - The I(service_account_email) and I(service_account_file) options are
- mutually exclusive.
-'''
diff --git a/ansible_collections/community/google/plugins/lookup/gcp_storage_file.py b/ansible_collections/community/google/plugins/lookup/gcp_storage_file.py
deleted file mode 100644
index ae58c5c59..000000000
--- a/ansible_collections/community/google/plugins/lookup/gcp_storage_file.py
+++ /dev/null
@@ -1,156 +0,0 @@
-# (c) 2019, Eric Anderson <eric.sysmin@gmail.com>
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-DOCUMENTATION = '''
-lookup: gcp_storage_file
-description:
- - This lookup returns the contents from a file residing on Google Cloud Storage
-short_description: Return GC Storage content
-author: Eric Anderson (!UNKNOWN) <eanderson@avinetworks.com>
-requirements:
- - python >= 2.6
- - requests >= 2.18.4
- - google-auth >= 1.3.0
-options:
- src:
- description:
- - Source location of file (may be local machine or cloud depending on action).
- required: false
- bucket:
- description:
- - The name of the bucket.
- required: false
-extends_documentation_fragment:
-- community.google._gcp
-
-'''
-
-EXAMPLES = '''
-- ansible.builtin.debug:
- msg: |
- the value of foo.txt is {{ lookup('community.google.gcp_storage_file',
- bucket='gcp-bucket', src='mydir/foo.txt', project='project-name',
- auth_kind='serviceaccount', service_account_file='/tmp/myserviceaccountfile.json') }}
-'''
-
-RETURN = '''
-_raw:
- description:
- - base64 encoded file content
- type: list
- elements: str
-'''
-
-import base64
-import json
-import mimetypes
-import os
-from ansible.errors import AnsibleError
-from ansible.plugins.lookup import LookupBase
-from ansible.utils.display import Display
-
-try:
- import requests
- HAS_REQUESTS = True
-except ImportError:
- HAS_REQUESTS = False
-
-try:
- from ansible_collections.google.cloud.plugins.module_utils.gcp_utils import navigate_hash, GcpSession
- HAS_GOOGLE_CLOUD_COLLECTION = True
-except ImportError:
- HAS_GOOGLE_CLOUD_COLLECTION = False
-
-
-display = Display()
-
-
-class GcpMockModule(object):
- def __init__(self, params):
- self.params = params
-
- def fail_json(self, *args, **kwargs):
- raise AnsibleError(kwargs['msg'])
-
- def raise_for_status(self, response):
- try:
- response.raise_for_status()
- except getattr(requests.exceptions, 'RequestException'):
- self.fail_json(msg="GCP returned error: %s" % response.json())
-
-
-class GcpFileLookup():
- def get_file_contents(self, module):
- auth = GcpSession(module, 'storage')
- data = auth.get(self.media_link(module))
- return base64.b64encode(data.content.rstrip())
-
- def fetch_resource(self, module, link, allow_not_found=True):
- auth = GcpSession(module, 'storage')
- return self.return_if_object(module, auth.get(link), allow_not_found)
-
- def self_link(self, module):
- return "https://www.googleapis.com/storage/v1/b/{bucket}/o/{src}".format(**module.params)
-
- def media_link(self, module):
- return "https://www.googleapis.com/storage/v1/b/{bucket}/o/{src}?alt=media".format(**module.params)
-
- def return_if_object(self, module, response, allow_not_found=False):
- # If not found, return nothing.
- if allow_not_found and response.status_code == 404:
- return None
- # If no content, return nothing.
- if response.status_code == 204:
- return None
- try:
- module.raise_for_status(response)
- result = response.json()
- except getattr(json.decoder, 'JSONDecodeError', ValueError) as inst:
- raise AnsibleError("Invalid JSON response with error: %s" % inst)
- if navigate_hash(result, ['error', 'errors']):
- raise AnsibleError(navigate_hash(result, ['error', 'errors']))
- return result
-
- def object_headers(self, module):
- return {
- "name": module.params['src'],
- "Content-Type": mimetypes.guess_type(module.params['src'])[0],
- "Content-Length": str(os.path.getsize(module.params['src'])),
- }
-
- def run(self, terms, variables=None, **kwargs):
- params = {
- 'bucket': kwargs.get('bucket', None),
- 'src': kwargs.get('src', None),
- 'projects': kwargs.get('projects', None),
- 'scopes': kwargs.get('scopes', None),
- 'zones': kwargs.get('zones', None),
- 'auth_kind': kwargs.get('auth_kind', None),
- 'service_account_file': kwargs.get('service_account_file', None),
- 'service_account_email': kwargs.get('service_account_email', None),
- }
-
- if not params['scopes']:
- params['scopes'] = ['https://www.googleapis.com/auth/devstorage.full_control']
-
- fake_module = GcpMockModule(params)
-
- # Check if files exist.
- remote_object = self.fetch_resource(fake_module, self.self_link(fake_module))
- if not remote_object:
- raise AnsibleError("File does not exist in bucket")
-
- result = self.get_file_contents(fake_module)
- return [result]
-
-
-class LookupModule(LookupBase):
- def run(self, terms, variables=None, **kwargs):
- if not HAS_GOOGLE_CLOUD_COLLECTION:
- raise AnsibleError("community.google.gcp_storage_file needs a supported version of the google.cloud collection installed")
- if not HAS_REQUESTS:
- raise AnsibleError("community.google.gcp_storage_file needs requests installed. Use `pip install requests` to install it")
- return GcpFileLookup().run(terms, variables=variables, **kwargs)
diff --git a/ansible_collections/community/google/plugins/module_utils/gce.py b/ansible_collections/community/google/plugins/module_utils/gce.py
deleted file mode 100644
index 7698e3c5e..000000000
--- a/ansible_collections/community/google/plugins/module_utils/gce.py
+++ /dev/null
@@ -1,39 +0,0 @@
-# This code is part of Ansible, but is an independent component.
-# This particular file snippet, and this file snippet only, is BSD licensed.
-# Modules you write using this snippet, which is embedded dynamically by Ansible
-# still belong to the author of the module, and may assign their own license
-# to the complete work.
-#
-# Copyright (c), Franck Cuny <franck.cuny@gmail.com>, 2014
-#
-# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
-
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-try:
- from libcloud.compute.types import Provider
- from libcloud.compute.providers import get_driver
- HAS_LIBCLOUD_BASE = True
-except ImportError:
- HAS_LIBCLOUD_BASE = False
-
-from ansible_collections.community.google.plugins.module_utils.gcp import gcp_connect
-from ansible_collections.community.google.plugins.module_utils.gcp import unexpected_error_msg as gcp_error
-
-USER_AGENT_PRODUCT = "Ansible-gce"
-USER_AGENT_VERSION = "v1"
-
-
-def gce_connect(module, provider=None):
- """Return a GCP connection for Google Compute Engine."""
- if not HAS_LIBCLOUD_BASE:
- module.fail_json(msg='libcloud must be installed to use this module')
- provider = provider or Provider.GCE
-
- return gcp_connect(module, provider, get_driver, USER_AGENT_PRODUCT, USER_AGENT_VERSION)
-
-
-def unexpected_error_msg(error):
- """Create an error string based on passed in error."""
- return gcp_error(error)
diff --git a/ansible_collections/community/google/plugins/module_utils/gcp.py b/ansible_collections/community/google/plugins/module_utils/gcp.py
deleted file mode 100644
index a034f3b6c..000000000
--- a/ansible_collections/community/google/plugins/module_utils/gcp.py
+++ /dev/null
@@ -1,799 +0,0 @@
-# This code is part of Ansible, but is an independent component.
-# This particular file snippet, and this file snippet only, is BSD licensed.
-# Modules you write using this snippet, which is embedded dynamically by Ansible
-# still belong to the author of the module, and may assign their own license
-# to the complete work.
-#
-# Copyright (c), Franck Cuny <franck.cuny@gmail.com>, 2014
-#
-# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
-
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import json
-import os
-import time
-import traceback
-from distutils.version import LooseVersion
-
-# libcloud
-try:
- import libcloud
- HAS_LIBCLOUD_BASE = True
-except ImportError:
- HAS_LIBCLOUD_BASE = False
-
-# google-auth
-try:
- import google.auth
- from google.oauth2 import service_account
- HAS_GOOGLE_AUTH = True
-except ImportError:
- HAS_GOOGLE_AUTH = False
-
-# google-python-api
-try:
- import google_auth_httplib2
- from httplib2 import Http
- from googleapiclient.http import set_user_agent
- from googleapiclient.errors import HttpError
- from apiclient.discovery import build
- HAS_GOOGLE_API_LIB = True
-except ImportError:
- HAS_GOOGLE_API_LIB = False
-
-
-import ansible.module_utils.six.moves.urllib.parse as urlparse
-
-GCP_DEFAULT_SCOPES = ['https://www.googleapis.com/auth/cloud-platform']
-
-
-def _get_gcp_ansible_credentials(module):
- """Helper to fetch creds from AnsibleModule object."""
- service_account_email = module.params.get('service_account_email', None)
- # Note: pem_file is discouraged and will be deprecated
- credentials_file = module.params.get('pem_file', None) or module.params.get(
- 'credentials_file', None)
- project_id = module.params.get('project_id', None)
-
- return (service_account_email, credentials_file, project_id)
-
-
-def _get_gcp_environ_var(var_name, default_value):
- """Wrapper around os.environ.get call."""
- return os.environ.get(
- var_name, default_value)
-
-
-def _get_gcp_environment_credentials(service_account_email, credentials_file, project_id):
- """Helper to look in environment variables for credentials."""
- # If any of the values are not given as parameters, check the appropriate
- # environment variables.
- if not service_account_email:
- service_account_email = _get_gcp_environ_var('GCE_EMAIL', None)
- if not credentials_file:
- credentials_file = _get_gcp_environ_var(
- 'GCE_CREDENTIALS_FILE_PATH', None) or _get_gcp_environ_var(
- 'GOOGLE_APPLICATION_CREDENTIALS', None) or _get_gcp_environ_var(
- 'GCE_PEM_FILE_PATH', None)
- if not project_id:
- project_id = _get_gcp_environ_var('GCE_PROJECT', None) or _get_gcp_environ_var(
- 'GOOGLE_CLOUD_PROJECT', None)
- return (service_account_email, credentials_file, project_id)
-
-
-def _get_gcp_credentials(module, require_valid_json=True, check_libcloud=False):
- """
- Obtain GCP credentials by trying various methods.
-
- There are 3 ways to specify GCP credentials:
- 1. Specify via Ansible module parameters (recommended).
- 2. Specify via environment variables. Two sets of env vars are available:
- a) GOOGLE_CLOUD_PROJECT, GOOGLE_CREDENTIALS_APPLICATION (preferred)
- b) GCE_PROJECT, GCE_CREDENTIAL_FILE_PATH, GCE_EMAIL (legacy, not recommended; req'd if
- using p12 key)
- 3. Specify via libcloud secrets.py file (deprecated).
-
- There are 3 helper functions to assist in the above.
-
- Regardless of method, the user also has the option of specifying a JSON
- file or a p12 file as the credentials file. JSON is strongly recommended and
- p12 will be removed in the future.
-
- Additionally, flags may be set to require valid json and check the libcloud
- version.
-
- AnsibleModule.fail_json is called only if the project_id cannot be found.
-
- :param module: initialized Ansible module object
- :type module: `class AnsibleModule`
-
- :param require_valid_json: If true, require credentials to be valid JSON. Default is True.
- :type require_valid_json: ``bool``
-
- :params check_libcloud: If true, check the libcloud version available to see if
- JSON creds are supported.
- :type check_libcloud: ``bool``
-
- :return: {'service_account_email': service_account_email,
- 'credentials_file': credentials_file,
- 'project_id': project_id}
- :rtype: ``dict``
- """
- (service_account_email,
- credentials_file,
- project_id) = _get_gcp_ansible_credentials(module)
-
- # If any of the values are not given as parameters, check the appropriate
- # environment variables.
- (service_account_email,
- credentials_file,
- project_id) = _get_gcp_environment_credentials(service_account_email,
- credentials_file, project_id)
-
- if credentials_file is None or project_id is None or service_account_email is None:
- if check_libcloud is True:
- if project_id is None:
- # TODO(supertom): this message is legacy and integration tests
- # depend on it.
- module.fail_json(msg='Missing GCE connection parameters in libcloud '
- 'secrets file.')
- else:
- if project_id is None:
- module.fail_json(msg=('GCP connection error: unable to determine project (%s) or '
- 'credentials file (%s)' % (project_id, credentials_file)))
- # Set these fields to empty strings if they are None
- # consumers of this will make the distinction between an empty string
- # and None.
- if credentials_file is None:
- credentials_file = ''
- if service_account_email is None:
- service_account_email = ''
-
- # ensure the credentials file is found and is in the proper format.
- if credentials_file:
- _validate_credentials_file(module, credentials_file,
- require_valid_json=require_valid_json,
- check_libcloud=check_libcloud)
-
- return {'service_account_email': service_account_email,
- 'credentials_file': credentials_file,
- 'project_id': project_id}
-
-
-def _validate_credentials_file(module, credentials_file, require_valid_json=True, check_libcloud=False):
- """
- Check for valid credentials file.
-
- Optionally check for JSON format and if libcloud supports JSON.
-
- :param module: initialized Ansible module object
- :type module: `class AnsibleModule`
-
- :param credentials_file: path to file on disk
- :type credentials_file: ``str``. Complete path to file on disk.
-
- :param require_valid_json: This argument is ignored as of Ansible 2.7.
- :type require_valid_json: ``bool``
-
- :params check_libcloud: If true, check the libcloud version available to see if
- JSON creds are supported.
- :type check_libcloud: ``bool``
-
- :returns: True
- :rtype: ``bool``
- """
- try:
- # Try to read credentials as JSON
- with open(credentials_file) as credentials:
- json.loads(credentials.read())
- # If the credentials are proper JSON and we do not have the minimum
- # required libcloud version, bail out and return a descriptive
- # error
- if check_libcloud and LooseVersion(libcloud.__version__) < '0.17.0':
- module.fail_json(msg='Using JSON credentials but libcloud minimum version not met. '
- 'Upgrade to libcloud>=0.17.0.')
- return True
- except IOError as e:
- module.fail_json(msg='GCP Credentials File %s not found.' %
- credentials_file, changed=False)
- return False
- except ValueError as e:
- module.fail_json(
- msg='Non-JSON credentials file provided. Please generate a new JSON key from the Google Cloud console',
- changed=False)
-
-
-def gcp_connect(module, provider, get_driver, user_agent_product, user_agent_version):
- """Return a Google libcloud driver connection."""
- if not HAS_LIBCLOUD_BASE:
- module.fail_json(msg='libcloud must be installed to use this module')
-
- creds = _get_gcp_credentials(module,
- require_valid_json=False,
- check_libcloud=True)
- try:
- gcp = get_driver(provider)(creds['service_account_email'], creds['credentials_file'],
- datacenter=module.params.get('zone', None),
- project=creds['project_id'])
- gcp.connection.user_agent_append("%s/%s" % (
- user_agent_product, user_agent_version))
- except (RuntimeError, ValueError) as e:
- module.fail_json(msg=str(e), changed=False)
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
-
- return gcp
-
-
-def get_google_cloud_credentials(module, scopes=None):
- """
- Get credentials object for use with Google Cloud client.
-
- Attempts to obtain credentials by calling _get_gcp_credentials. If those are
- not present will attempt to connect via Application Default Credentials.
-
- To connect via libcloud, don't use this function, use gcp_connect instead. For
- Google Python API Client, see get_google_api_auth for how to connect.
-
- For more information on Google's client library options for Python, see:
- U(https://cloud.google.com/apis/docs/client-libraries-explained#google_api_client_libraries)
-
- Google Cloud example:
- creds, params = get_google_cloud_credentials(module, scopes, user_agent_product, user_agent_version)
- pubsub_client = pubsub.Client(project=params['project_id'], credentials=creds)
- pubsub_client.user_agent = 'ansible-pubsub-0.1'
- ...
-
- :param module: initialized Ansible module object
- :type module: `class AnsibleModule`
-
- :param scopes: list of scopes
- :type module: ``list`` of URIs
-
- :returns: A tuple containing (google authorized) credentials object and
- params dict {'service_account_email': '...', 'credentials_file': '...', 'project_id': ...}
- :rtype: ``tuple``
- """
- scopes = [] if scopes is None else scopes
-
- if not HAS_GOOGLE_AUTH:
- module.fail_json(msg='Please install google-auth.')
-
- conn_params = _get_gcp_credentials(module,
- require_valid_json=True,
- check_libcloud=False)
- try:
- if conn_params['credentials_file']:
- credentials = service_account.Credentials.from_service_account_file(
- conn_params['credentials_file'])
- if scopes:
- credentials = credentials.with_scopes(scopes)
- else:
- (credentials, project_id) = google.auth.default(
- scopes=scopes)
- if project_id is not None:
- conn_params['project_id'] = project_id
-
- return (credentials, conn_params)
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
- return (None, None)
-
-
-def get_google_api_auth(module, scopes=None, user_agent_product='ansible-python-api', user_agent_version='NA'):
- """
- Authentication for use with google-python-api-client.
-
- Function calls get_google_cloud_credentials, which attempts to assemble the credentials
- from various locations. Next it attempts to authenticate with Google.
-
- This function returns an httplib2 (compatible) object that can be provided to the Google Python API client.
-
- For libcloud, don't use this function, use gcp_connect instead. For Google Cloud, See
- get_google_cloud_credentials for how to connect.
-
- For more information on Google's client library options for Python, see:
- U(https://cloud.google.com/apis/docs/client-libraries-explained#google_api_client_libraries)
-
- Google API example:
- http_auth, conn_params = get_google_api_auth(module, scopes, user_agent_product, user_agent_version)
- service = build('myservice', 'v1', http=http_auth)
- ...
-
- :param module: initialized Ansible module object
- :type module: `class AnsibleModule`
-
- :param scopes: list of scopes
- :type scopes: ``list`` of URIs
-
- :param user_agent_product: User agent product. eg: 'ansible-python-api'
- :type user_agent_product: ``str``
-
- :param user_agent_version: Version string to append to product. eg: 'NA' or '0.1'
- :type user_agent_version: ``str``
-
- :returns: A tuple containing (google authorized) httplib2 request object and a
- params dict {'service_account_email': '...', 'credentials_file': '...', 'project_id': ...}
- :rtype: ``tuple``
- """
- scopes = [] if scopes is None else scopes
-
- if not HAS_GOOGLE_API_LIB:
- module.fail_json(msg="Please install google-api-python-client library")
- if not scopes:
- scopes = GCP_DEFAULT_SCOPES
- try:
- (credentials, conn_params) = get_google_cloud_credentials(module, scopes)
- http = set_user_agent(Http(), '%s-%s' %
- (user_agent_product, user_agent_version))
- http_auth = google_auth_httplib2.AuthorizedHttp(credentials, http=http)
-
- return (http_auth, conn_params)
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
- return (None, None)
-
-
-def get_google_api_client(module, service, user_agent_product, user_agent_version,
- scopes=None, api_version='v1'):
- """
- Get the discovery-based python client. Use when a cloud client is not available.
-
- client = get_google_api_client(module, 'compute', user_agent_product=USER_AGENT_PRODUCT,
- user_agent_version=USER_AGENT_VERSION)
-
- :returns: A tuple containing the authorized client to the specified service and a
- params dict {'service_account_email': '...', 'credentials_file': '...', 'project_id': ...}
- :rtype: ``tuple``
- """
- if not scopes:
- scopes = GCP_DEFAULT_SCOPES
-
- http_auth, conn_params = get_google_api_auth(module, scopes=scopes,
- user_agent_product=user_agent_product,
- user_agent_version=user_agent_version)
- client = build(service, api_version, http=http_auth)
-
- return (client, conn_params)
-
-
-def check_min_pkg_version(pkg_name, minimum_version):
- """Minimum required version is >= installed version."""
- from pkg_resources import get_distribution
- try:
- installed_version = get_distribution(pkg_name).version
- return LooseVersion(installed_version) >= minimum_version
- except Exception as e:
- return False
-
-
-def unexpected_error_msg(error):
- """Create an error string based on passed in error."""
- return 'Unexpected response: (%s). Detail: %s' % (str(error), traceback.format_exc())
-
-
-def get_valid_location(module, driver, location, location_type='zone'):
- if location_type == 'zone':
- l = driver.ex_get_zone(location)
- else:
- l = driver.ex_get_region(location)
- if l is None:
- link = 'https://cloud.google.com/compute/docs/regions-zones/regions-zones#available'
- module.fail_json(msg=('%s %s is invalid. Please see the list of '
- 'available %s at %s' % (
- location_type, location, location_type, link)),
- changed=False)
- return l
-
-
-def check_params(params, field_list):
- """
- Helper to validate params.
-
- Use this in function definitions if they require specific fields
- to be present.
-
- :param params: structure that contains the fields
- :type params: ``dict``
-
- :param field_list: list of dict representing the fields
- [{'name': str, 'required': True/False', 'type': cls}]
- :type field_list: ``list`` of ``dict``
-
- :return True or raises ValueError
- :rtype: ``bool`` or `class:ValueError`
- """
- for d in field_list:
- if not d['name'] in params:
- if 'required' in d and d['required'] is True:
- raise ValueError(("%s is required and must be of type: %s" %
- (d['name'], str(d['type']))))
- else:
- if not isinstance(params[d['name']], d['type']):
- raise ValueError(("%s must be of type: %s. %s (%s) provided." % (
- d['name'], str(d['type']), params[d['name']],
- type(params[d['name']]))))
- if 'values' in d:
- if params[d['name']] not in d['values']:
- raise ValueError(("%s must be one of: %s" % (
- d['name'], ','.join(d['values']))))
- if isinstance(params[d['name']], int):
- if 'min' in d:
- if params[d['name']] < d['min']:
- raise ValueError(("%s must be greater than or equal to: %s" % (
- d['name'], d['min'])))
- if 'max' in d:
- if params[d['name']] > d['max']:
- raise ValueError("%s must be less than or equal to: %s" % (
- d['name'], d['max']))
- return True
-
-
-class GCPUtils(object):
- """
- Helper utilities for GCP.
- """
-
- @staticmethod
- def underscore_to_camel(txt):
- return txt.split('_')[0] + ''.join(x.capitalize() or '_' for x in txt.split('_')[1:])
-
- @staticmethod
- def remove_non_gcp_params(params):
- """
- Remove params if found.
- """
- params_to_remove = ['state']
- for p in params_to_remove:
- if p in params:
- del params[p]
-
- return params
-
- @staticmethod
- def params_to_gcp_dict(params, resource_name=None):
- """
- Recursively convert ansible params to GCP Params.
-
- Keys are converted from snake to camelCase
- ex: default_service to defaultService
-
- Handles lists, dicts and strings
-
- special provision for the resource name
- """
- if not isinstance(params, dict):
- return params
- gcp_dict = {}
- params = GCPUtils.remove_non_gcp_params(params)
- for k, v in params.items():
- gcp_key = GCPUtils.underscore_to_camel(k)
- if isinstance(v, dict):
- retval = GCPUtils.params_to_gcp_dict(v)
- gcp_dict[gcp_key] = retval
- elif isinstance(v, list):
- gcp_dict[gcp_key] = [GCPUtils.params_to_gcp_dict(x) for x in v]
- else:
- if resource_name and k == resource_name:
- gcp_dict['name'] = v
- else:
- gcp_dict[gcp_key] = v
- return gcp_dict
-
- @staticmethod
- def execute_api_client_req(req, client=None, raw=True,
- operation_timeout=180, poll_interval=5,
- raise_404=True):
- """
- General python api client interaction function.
-
- For use with google-api-python-client, or clients created
- with get_google_api_client function
- Not for use with Google Cloud client libraries
-
- For long-running operations, we make an immediate query and then
- sleep poll_interval before re-querying. After the request is done
- we rebuild the request with a get method and return the result.
-
- """
- try:
- resp = req.execute()
-
- if not resp:
- return None
-
- if raw:
- return resp
-
- if resp['kind'] == 'compute#operation':
- resp = GCPUtils.execute_api_client_operation_req(req, resp,
- client,
- operation_timeout,
- poll_interval)
-
- if 'items' in resp:
- return resp['items']
-
- return resp
- except HttpError as h:
- # Note: 404s can be generated (incorrectly) for dependent
- # resources not existing. We let the caller determine if
- # they want 404s raised for their invocation.
- if h.resp.status == 404 and not raise_404:
- return None
- else:
- raise
- except Exception:
- raise
-
- @staticmethod
- def execute_api_client_operation_req(orig_req, op_resp, client,
- operation_timeout=180, poll_interval=5):
- """
- Poll an operation for a result.
- """
- parsed_url = GCPUtils.parse_gcp_url(orig_req.uri)
- project_id = parsed_url['project']
- resource_name = GCPUtils.get_gcp_resource_from_methodId(
- orig_req.methodId)
- resource = GCPUtils.build_resource_from_name(client, resource_name)
-
- start_time = time.time()
-
- complete = False
- attempts = 1
- while not complete:
- if start_time + operation_timeout >= time.time():
- op_req = client.globalOperations().get(
- project=project_id, operation=op_resp['name'])
- op_resp = op_req.execute()
- if op_resp['status'] != 'DONE':
- time.sleep(poll_interval)
- attempts += 1
- else:
- complete = True
- if op_resp['operationType'] == 'delete':
- # don't wait for the delete
- return True
- elif op_resp['operationType'] in ['insert', 'update', 'patch']:
- # TODO(supertom): Isolate 'build-new-request' stuff.
- resource_name_singular = GCPUtils.get_entity_name_from_resource_name(
- resource_name)
- if op_resp['operationType'] == 'insert' or 'entity_name' not in parsed_url:
- parsed_url['entity_name'] = GCPUtils.parse_gcp_url(op_resp['targetLink'])[
- 'entity_name']
- args = {'project': project_id,
- resource_name_singular: parsed_url['entity_name']}
- new_req = resource.get(**args)
- resp = new_req.execute()
- return resp
- else:
- # assuming multiple entities, do a list call.
- new_req = resource.list(project=project_id)
- resp = new_req.execute()
- return resp
- else:
- # operation didn't complete on time.
- raise GCPOperationTimeoutError("Operation timed out: %s" % (
- op_resp['targetLink']))
-
- @staticmethod
- def build_resource_from_name(client, resource_name):
- try:
- method = getattr(client, resource_name)
- return method()
- except AttributeError:
- raise NotImplementedError('%s is not an attribute of %s' % (resource_name,
- client))
-
- @staticmethod
- def get_gcp_resource_from_methodId(methodId):
- try:
- parts = methodId.split('.')
- if len(parts) != 3:
- return None
- else:
- return parts[1]
- except AttributeError:
- return None
-
- @staticmethod
- def get_entity_name_from_resource_name(resource_name):
- if not resource_name:
- return None
-
- try:
- # Chop off global or region prefixes
- if resource_name.startswith('global'):
- resource_name = resource_name.replace('global', '')
- elif resource_name.startswith('regional'):
- resource_name = resource_name.replace('region', '')
-
- # ensure we have a lower case first letter
- resource_name = resource_name[0].lower() + resource_name[1:]
-
- if resource_name[-3:] == 'ies':
- return resource_name.replace(
- resource_name[-3:], 'y')
- if resource_name[-1] == 's':
- return resource_name[:-1]
-
- return resource_name
-
- except AttributeError:
- return None
-
- @staticmethod
- def parse_gcp_url(url):
- """
- Parse GCP urls and return dict of parts.
-
- Supported URL structures:
- /SERVICE/VERSION/'projects'/PROJECT_ID/RESOURCE
- /SERVICE/VERSION/'projects'/PROJECT_ID/RESOURCE/ENTITY_NAME
- /SERVICE/VERSION/'projects'/PROJECT_ID/RESOURCE/ENTITY_NAME/METHOD_NAME
- /SERVICE/VERSION/'projects'/PROJECT_ID/'global'/RESOURCE
- /SERVICE/VERSION/'projects'/PROJECT_ID/'global'/RESOURCE/ENTITY_NAME
- /SERVICE/VERSION/'projects'/PROJECT_ID/'global'/RESOURCE/ENTITY_NAME/METHOD_NAME
- /SERVICE/VERSION/'projects'/PROJECT_ID/LOCATION_TYPE/LOCATION/RESOURCE
- /SERVICE/VERSION/'projects'/PROJECT_ID/LOCATION_TYPE/LOCATION/RESOURCE/ENTITY_NAME
- /SERVICE/VERSION/'projects'/PROJECT_ID/LOCATION_TYPE/LOCATION/RESOURCE/ENTITY_NAME/METHOD_NAME
-
- :param url: GCP-generated URL, such as a selflink or resource location.
- :type url: ``str``
-
- :return: dictionary of parts. Includes stanard components of urlparse, plus
- GCP-specific 'service', 'api_version', 'project' and
- 'resource_name' keys. Optionally, 'zone', 'region', 'entity_name'
- and 'method_name', if applicable.
- :rtype: ``dict``
- """
-
- p = urlparse.urlparse(url)
- if not p:
- return None
- else:
- # we add extra items such as
- # zone, region and resource_name
- url_parts = {}
- url_parts['scheme'] = p.scheme
- url_parts['host'] = p.netloc
- url_parts['path'] = p.path
- if p.path.find('/') == 0:
- url_parts['path'] = p.path[1:]
- url_parts['params'] = p.params
- url_parts['fragment'] = p.fragment
- url_parts['query'] = p.query
- url_parts['project'] = None
- url_parts['service'] = None
- url_parts['api_version'] = None
-
- path_parts = url_parts['path'].split('/')
- url_parts['service'] = path_parts[0]
- url_parts['api_version'] = path_parts[1]
- if path_parts[2] == 'projects':
- url_parts['project'] = path_parts[3]
- else:
- # invalid URL
- raise GCPInvalidURLError('unable to parse: %s' % url)
-
- if 'global' in path_parts:
- url_parts['global'] = True
- idx = path_parts.index('global')
- if len(path_parts) - idx == 4:
- # we have a resource, entity and method_name
- url_parts['resource_name'] = path_parts[idx + 1]
- url_parts['entity_name'] = path_parts[idx + 2]
- url_parts['method_name'] = path_parts[idx + 3]
-
- if len(path_parts) - idx == 3:
- # we have a resource and entity
- url_parts['resource_name'] = path_parts[idx + 1]
- url_parts['entity_name'] = path_parts[idx + 2]
-
- if len(path_parts) - idx == 2:
- url_parts['resource_name'] = path_parts[idx + 1]
-
- if len(path_parts) - idx < 2:
- # invalid URL
- raise GCPInvalidURLError('unable to parse: %s' % url)
-
- elif 'regions' in path_parts or 'zones' in path_parts:
- idx = -1
- if 'regions' in path_parts:
- idx = path_parts.index('regions')
- url_parts['region'] = path_parts[idx + 1]
- else:
- idx = path_parts.index('zones')
- url_parts['zone'] = path_parts[idx + 1]
-
- if len(path_parts) - idx == 5:
- # we have a resource, entity and method_name
- url_parts['resource_name'] = path_parts[idx + 2]
- url_parts['entity_name'] = path_parts[idx + 3]
- url_parts['method_name'] = path_parts[idx + 4]
-
- if len(path_parts) - idx == 4:
- # we have a resource and entity
- url_parts['resource_name'] = path_parts[idx + 2]
- url_parts['entity_name'] = path_parts[idx + 3]
-
- if len(path_parts) - idx == 3:
- url_parts['resource_name'] = path_parts[idx + 2]
-
- if len(path_parts) - idx < 3:
- # invalid URL
- raise GCPInvalidURLError('unable to parse: %s' % url)
-
- else:
- # no location in URL.
- idx = path_parts.index('projects')
- if len(path_parts) - idx == 5:
- # we have a resource, entity and method_name
- url_parts['resource_name'] = path_parts[idx + 2]
- url_parts['entity_name'] = path_parts[idx + 3]
- url_parts['method_name'] = path_parts[idx + 4]
-
- if len(path_parts) - idx == 4:
- # we have a resource and entity
- url_parts['resource_name'] = path_parts[idx + 2]
- url_parts['entity_name'] = path_parts[idx + 3]
-
- if len(path_parts) - idx == 3:
- url_parts['resource_name'] = path_parts[idx + 2]
-
- if len(path_parts) - idx < 3:
- # invalid URL
- raise GCPInvalidURLError('unable to parse: %s' % url)
-
- return url_parts
-
- @staticmethod
- def build_googleapi_url(project, api_version='v1', service='compute'):
- return 'https://www.googleapis.com/%s/%s/projects/%s' % (service, api_version, project)
-
- @staticmethod
- def filter_gcp_fields(params, excluded_fields=None):
- new_params = {}
- if not excluded_fields:
- excluded_fields = ['creationTimestamp', 'id', 'kind',
- 'selfLink', 'fingerprint', 'description']
-
- if isinstance(params, list):
- new_params = [GCPUtils.filter_gcp_fields(
- x, excluded_fields) for x in params]
- elif isinstance(params, dict):
- for k in params.keys():
- if k not in excluded_fields:
- new_params[k] = GCPUtils.filter_gcp_fields(
- params[k], excluded_fields)
- else:
- new_params = params
-
- return new_params
-
- @staticmethod
- def are_params_equal(p1, p2):
- """
- Check if two params dicts are equal.
- TODO(supertom): need a way to filter out URLs, or they need to be built
- """
- filtered_p1 = GCPUtils.filter_gcp_fields(p1)
- filtered_p2 = GCPUtils.filter_gcp_fields(p2)
- if filtered_p1 != filtered_p2:
- return False
- return True
-
-
-class GCPError(Exception):
- pass
-
-
-class GCPOperationTimeoutError(GCPError):
- pass
-
-
-class GCPInvalidURLError(GCPError):
- pass
diff --git a/ansible_collections/community/google/plugins/modules/gc_storage.py b/ansible_collections/community/google/plugins/modules/gc_storage.py
deleted file mode 100644
index 8344c251e..000000000
--- a/ansible_collections/community/google/plugins/modules/gc_storage.py
+++ /dev/null
@@ -1,497 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright: Ansible Project
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
----
-module: gc_storage
-short_description: This module manages objects/buckets in Google Cloud Storage.
-description:
- - This module allows users to manage their objects/buckets in Google Cloud Storage. It allows upload and download operations and can set some
- canned permissions. It also allows retrieval of URLs for objects for use in playbooks, and retrieval of string contents of objects. This module
- requires setting the default project in GCS prior to playbook usage. See U(https://developers.google.com/storage/docs/reference/v1/apiversion1) for
- information about setting the default project.
-
-options:
- bucket:
- type: str
- description:
- - Bucket name.
- required: true
- object:
- type: path
- description:
- - Keyname of the object inside the bucket. Can be also be used to create "virtual directories" (see examples).
- src:
- type: str
- description:
- - The source file path when performing a PUT operation.
- dest:
- type: path
- description:
- - The destination file path when downloading an object/key with a GET operation.
- overwrite:
- description:
- - Forces an overwrite either locally on the filesystem or remotely with the object/key. Used with PUT and GET operations.
- type: bool
- default: 'yes'
- aliases: [ 'force' ]
- permission:
- type: str
- description:
- - This option let's the user set the canned permissions on the object/bucket that are created. The permissions that can be set are 'private',
- 'public-read', 'authenticated-read'.
- default: private
- choices: ['private', 'public-read', 'authenticated-read']
- headers:
- type: dict
- description:
- - Headers to attach to object.
- default: {}
- expiration:
- type: int
- default: 600
- description:
- - Time limit (in seconds) for the URL generated and returned by GCA when performing a mode=put or mode=get_url operation. This url is only
- available when public-read is the acl for the object.
- aliases: [expiry]
- mode:
- type: str
- description:
- - Switches the module behaviour between upload, download, get_url (return download url) , get_str (download object as string), create (bucket) and
- delete (bucket).
- required: true
- choices: [ 'get', 'put', 'get_url', 'get_str', 'delete', 'create' ]
- gs_secret_key:
- type: str
- description:
- - GS secret key. If not set then the value of the GS_SECRET_ACCESS_KEY environment variable is used.
- required: true
- gs_access_key:
- type: str
- description:
- - GS access key. If not set then the value of the GS_ACCESS_KEY_ID environment variable is used.
- required: true
- region:
- type: str
- description:
- - The gs region to use. If not defined then the value 'US' will be used. See U(https://cloud.google.com/storage/docs/bucket-locations)
- default: 'US'
- versioning:
- description:
- - Whether versioning is enabled or disabled (note that once versioning is enabled, it can only be suspended)
- type: bool
- default: false
-
-requirements:
- - "python >= 2.6"
- - "boto >= 2.9"
-
-author:
-- Benno Joy (@bennojoy)
-- Lukas Beumer (@Nitaco)
-
-'''
-
-EXAMPLES = '''
-- name: Upload some content
- community.google.gc_storage:
- bucket: mybucket
- object: key.txt
- src: /usr/local/myfile.txt
- mode: put
- permission: public-read
-
-- name: Upload some headers
- community.google.gc_storage:
- bucket: mybucket
- object: key.txt
- src: /usr/local/myfile.txt
- headers: '{"Content-Encoding": "gzip"}'
-
-- name: Download some content
- community.google.gc_storage:
- bucket: mybucket
- object: key.txt
- dest: /usr/local/myfile.txt
- mode: get
-
-- name: Download an object as a string to use else where in your playbook
- community.google.gc_storage:
- bucket: mybucket
- object: key.txt
- mode: get_str
-
-- name: Create an empty bucket
- community.google.gc_storage:
- bucket: mybucket
- mode: create
-
-- name: Create a bucket with key as directory
- community.google.gc_storage:
- bucket: mybucket
- object: /my/directory/path
- mode: create
-
-- name: Delete a bucket and all contents
- community.google.gc_storage:
- bucket: mybucket
- mode: delete
-
-- name: Create a bucket with versioning enabled
- community.google.gc_storage:
- bucket: "mybucket"
- versioning: yes
- mode: create
-
-- name: Create a bucket located in the eu
- community.google.gc_storage:
- bucket: "mybucket"
- region: "europe-west3"
- mode: create
-
-'''
-
-import os
-
-try:
- import boto
- HAS_BOTO = True
-except ImportError:
- HAS_BOTO = False
-
-from ansible.module_utils.basic import AnsibleModule
-
-
-def grant_check(module, gs, obj):
- try:
- acp = obj.get_acl()
- if module.params.get('permission') == 'public-read':
- grant = [x for x in acp.entries.entry_list if x.scope.type == 'AllUsers']
- if not grant:
- obj.set_acl('public-read')
- module.exit_json(changed=True, result="The objects permission as been set to public-read")
- if module.params.get('permission') == 'authenticated-read':
- grant = [x for x in acp.entries.entry_list if x.scope.type == 'AllAuthenticatedUsers']
- if not grant:
- obj.set_acl('authenticated-read')
- module.exit_json(changed=True, result="The objects permission as been set to authenticated-read")
- except gs.provider.storage_response_error as e:
- module.fail_json(msg=str(e))
- return True
-
-
-def key_check(module, gs, bucket, obj):
- try:
- bucket = gs.lookup(bucket)
- key_check = bucket.get_key(obj)
- except gs.provider.storage_response_error as e:
- module.fail_json(msg=str(e))
- if key_check:
- grant_check(module, gs, key_check)
- return True
- else:
- return False
-
-
-def keysum(module, gs, bucket, obj):
- bucket = gs.lookup(bucket)
- key_check = bucket.get_key(obj)
- if not key_check:
- return None
- md5_remote = key_check.etag[1:-1]
- etag_multipart = '-' in md5_remote # Check for multipart, etag is not md5
- if etag_multipart is True:
- module.fail_json(msg="Files uploaded with multipart of gs are not supported with checksum, unable to compute checksum.")
- return md5_remote
-
-
-def bucket_check(module, gs, bucket):
- try:
- result = gs.lookup(bucket)
- except gs.provider.storage_response_error as e:
- module.fail_json(msg=str(e))
- if result:
- grant_check(module, gs, result)
- return True
- else:
- return False
-
-
-def create_bucket(module, gs, bucket):
- try:
- bucket = gs.create_bucket(bucket, transform_headers(module.params.get('headers')), module.params.get('region'))
- bucket.set_acl(module.params.get('permission'))
- bucket.configure_versioning(module.params.get('versioning'))
- except gs.provider.storage_response_error as e:
- module.fail_json(msg=str(e))
- if bucket:
- return True
-
-
-def delete_bucket(module, gs, bucket):
- try:
- bucket = gs.lookup(bucket)
- bucket_contents = bucket.list()
- for key in bucket_contents:
- bucket.delete_key(key.name)
- bucket.delete()
- return True
- except gs.provider.storage_response_error as e:
- module.fail_json(msg=str(e))
-
-
-def delete_key(module, gs, bucket, obj):
- try:
- bucket = gs.lookup(bucket)
- bucket.delete_key(obj)
- module.exit_json(msg="Object deleted from bucket ", changed=True)
- except gs.provider.storage_response_error as e:
- module.fail_json(msg=str(e))
-
-
-def create_dirkey(module, gs, bucket, obj):
- try:
- bucket = gs.lookup(bucket)
- key = bucket.new_key(obj)
- key.set_contents_from_string('')
- module.exit_json(msg="Virtual directory %s created in bucket %s" % (obj, bucket.name), changed=True)
- except gs.provider.storage_response_error as e:
- module.fail_json(msg=str(e))
-
-
-def path_check(path):
- if os.path.exists(path):
- return True
- else:
- return False
-
-
-def transform_headers(headers):
- """
- Boto url-encodes values unless we convert the value to `str`, so doing
- this prevents 'max-age=100000' from being converted to "max-age%3D100000".
-
- :param headers: Headers to convert
- :type headers: dict
- :rtype: dict
-
- """
-
- for key, value in headers.items():
- headers[key] = str(value)
- return headers
-
-
-def upload_gsfile(module, gs, bucket, obj, src, expiry):
- try:
- bucket = gs.lookup(bucket)
- key = bucket.new_key(obj)
- key.set_contents_from_filename(
- filename=src,
- headers=transform_headers(module.params.get('headers'))
- )
- key.set_acl(module.params.get('permission'))
- url = key.generate_url(expiry)
- module.exit_json(msg="PUT operation complete", url=url, changed=True)
- except gs.provider.storage_copy_error as e:
- module.fail_json(msg=str(e))
-
-
-def download_gsfile(module, gs, bucket, obj, dest):
- try:
- bucket = gs.lookup(bucket)
- key = bucket.lookup(obj)
- key.get_contents_to_filename(dest)
- module.exit_json(msg="GET operation complete", changed=True)
- except gs.provider.storage_copy_error as e:
- module.fail_json(msg=str(e))
-
-
-def download_gsstr(module, gs, bucket, obj):
- try:
- bucket = gs.lookup(bucket)
- key = bucket.lookup(obj)
- contents = key.get_contents_as_string()
- module.exit_json(msg="GET operation complete", contents=contents, changed=True)
- except gs.provider.storage_copy_error as e:
- module.fail_json(msg=str(e))
-
-
-def get_download_url(module, gs, bucket, obj, expiry):
- try:
- bucket = gs.lookup(bucket)
- key = bucket.lookup(obj)
- url = key.generate_url(expiry)
- module.exit_json(msg="Download url:", url=url, expiration=expiry, changed=True)
- except gs.provider.storage_response_error as e:
- module.fail_json(msg=str(e))
-
-
-def handle_get(module, gs, bucket, obj, overwrite, dest):
- md5_remote = keysum(module, gs, bucket, obj)
- md5_local = module.md5(dest)
- if md5_local == md5_remote:
- module.exit_json(changed=False)
- if md5_local != md5_remote and not overwrite:
- module.exit_json(msg="WARNING: Checksums do not match. Use overwrite parameter to force download.", failed=True)
- else:
- download_gsfile(module, gs, bucket, obj, dest)
-
-
-def handle_put(module, gs, bucket, obj, overwrite, src, expiration):
- # Lets check to see if bucket exists to get ground truth.
- bucket_rc = bucket_check(module, gs, bucket)
- key_rc = key_check(module, gs, bucket, obj)
-
- # Lets check key state. Does it exist and if it does, compute the etag md5sum.
- if bucket_rc and key_rc:
- md5_remote = keysum(module, gs, bucket, obj)
- md5_local = module.md5(src)
- if md5_local == md5_remote:
- module.exit_json(msg="Local and remote object are identical", changed=False)
- if md5_local != md5_remote and not overwrite:
- module.exit_json(msg="WARNING: Checksums do not match. Use overwrite parameter to force upload.", failed=True)
- else:
- upload_gsfile(module, gs, bucket, obj, src, expiration)
-
- if not bucket_rc:
- create_bucket(module, gs, bucket)
- upload_gsfile(module, gs, bucket, obj, src, expiration)
-
- # If bucket exists but key doesn't, just upload.
- if bucket_rc and not key_rc:
- upload_gsfile(module, gs, bucket, obj, src, expiration)
-
-
-def handle_delete(module, gs, bucket, obj):
- if bucket and not obj:
- if bucket_check(module, gs, bucket):
- module.exit_json(msg="Bucket %s and all keys have been deleted." % bucket, changed=delete_bucket(module, gs, bucket))
- else:
- module.exit_json(msg="Bucket does not exist.", changed=False)
- if bucket and obj:
- if bucket_check(module, gs, bucket):
- if key_check(module, gs, bucket, obj):
- module.exit_json(msg="Object has been deleted.", changed=delete_key(module, gs, bucket, obj))
- else:
- module.exit_json(msg="Object does not exist.", changed=False)
- else:
- module.exit_json(msg="Bucket does not exist.", changed=False)
- else:
- module.fail_json(msg="Bucket or Bucket & object parameter is required.", failed=True)
-
-
-def handle_create(module, gs, bucket, obj):
- if bucket and not obj:
- if bucket_check(module, gs, bucket):
- module.exit_json(msg="Bucket already exists.", changed=False)
- else:
- module.exit_json(msg="Bucket created successfully", changed=create_bucket(module, gs, bucket))
- if bucket and obj:
- if obj.endswith('/'):
- dirobj = obj
- else:
- dirobj = obj + "/"
-
- if bucket_check(module, gs, bucket):
- if key_check(module, gs, bucket, dirobj):
- module.exit_json(msg="Bucket %s and key %s already exists." % (bucket, obj), changed=False)
- else:
- create_dirkey(module, gs, bucket, dirobj)
- else:
- create_bucket(module, gs, bucket)
- create_dirkey(module, gs, bucket, dirobj)
-
-
-def main():
- module = AnsibleModule(
- argument_spec=dict(
- bucket=dict(required=True),
- object=dict(default=None, type='path'),
- src=dict(default=None),
- dest=dict(default=None, type='path'),
- expiration=dict(type='int', default=600, aliases=['expiry']),
- mode=dict(choices=['get', 'put', 'delete', 'create', 'get_url', 'get_str'], required=True),
- permission=dict(choices=['private', 'public-read', 'authenticated-read'], default='private'),
- headers=dict(type='dict', default={}),
- gs_secret_key=dict(no_log=True, required=True),
- gs_access_key=dict(required=True),
- overwrite=dict(default=True, type='bool', aliases=['force']),
- region=dict(default='US', type='str'),
- versioning=dict(default=False, type='bool')
- ),
- )
-
- if not HAS_BOTO:
- module.fail_json(msg='`boto` 2.9+ is required for this module. Try: pip install `boto` --upgrade')
-
- bucket = module.params.get('bucket')
- obj = module.params.get('object')
- src = module.params.get('src')
- dest = module.params.get('dest')
- mode = module.params.get('mode')
- expiry = module.params.get('expiration')
- gs_secret_key = module.params.get('gs_secret_key')
- gs_access_key = module.params.get('gs_access_key')
- overwrite = module.params.get('overwrite')
-
- if mode == 'put':
- if not src or not object:
- module.fail_json(msg="When using PUT, src, bucket, object are mandatory parameters")
- if mode == 'get':
- if not dest or not object:
- module.fail_json(msg="When using GET, dest, bucket, object are mandatory parameters")
-
- try:
- gs = boto.connect_gs(gs_access_key, gs_secret_key)
- except boto.exception.NoAuthHandlerFound as e:
- module.fail_json(msg=str(e))
-
- if mode == 'get':
- if not bucket_check(module, gs, bucket) or not key_check(module, gs, bucket, obj):
- module.fail_json(msg="Target bucket/key cannot be found", failed=True)
- if not path_check(dest):
- download_gsfile(module, gs, bucket, obj, dest)
- else:
- handle_get(module, gs, bucket, obj, overwrite, dest)
-
- if mode == 'put':
- if not path_check(src):
- module.fail_json(msg="Local object for PUT does not exist", failed=True)
- handle_put(module, gs, bucket, obj, overwrite, src, expiry)
-
- # Support for deleting an object if we have both params.
- if mode == 'delete':
- handle_delete(module, gs, bucket, obj)
-
- if mode == 'create':
- handle_create(module, gs, bucket, obj)
-
- if mode == 'get_url':
- if bucket and obj:
- if bucket_check(module, gs, bucket) and key_check(module, gs, bucket, obj):
- get_download_url(module, gs, bucket, obj, expiry)
- else:
- module.fail_json(msg="Key/Bucket does not exist", failed=True)
- else:
- module.fail_json(msg="Bucket and Object parameters must be set", failed=True)
-
- # --------------------------- Get the String contents of an Object -------------------------
- if mode == 'get_str':
- if bucket and obj:
- if bucket_check(module, gs, bucket) and key_check(module, gs, bucket, obj):
- download_gsstr(module, gs, bucket, obj)
- else:
- module.fail_json(msg="Key/Bucket does not exist", failed=True)
- else:
- module.fail_json(msg="Bucket and Object parameters must be set", failed=True)
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/google/plugins/modules/gce_eip.py b/ansible_collections/community/google/plugins/modules/gce_eip.py
deleted file mode 100644
index a9ad45e4d..000000000
--- a/ansible_collections/community/google/plugins/modules/gce_eip.py
+++ /dev/null
@@ -1,247 +0,0 @@
-#!/usr/bin/python
-# Copyright 2017 Google Inc.
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
-module: gce_eip
-short_description: Create or Destroy Global or Regional External IP addresses.
-description:
- - Create (reserve) or Destroy (release) Regional or Global IP Addresses. See
- U(https://cloud.google.com/compute/docs/configure-instance-ip-addresses#reserve_new_static) for more on reserving static addresses.
-requirements:
- - "python >= 2.6"
- - "apache-libcloud >= 0.19.0"
-notes:
- - Global addresses can only be used with Global Forwarding Rules.
-author:
- - "Tom Melendez (@supertom) <tom@supertom.com>"
-options:
- name:
- type: str
- description:
- - Name of Address.
- required: true
- region:
- type: str
- description:
- - Region to create the address in. Set to 'global' to create a global address.
- required: true
- state:
- type: str
- description: The state the address should be in. C(present) or C(absent) are the only valid options.
- default: present
- required: false
- choices: [present, absent]
- project_id:
- type: str
- description:
- - The Google Cloud Platform project ID to use.
- pem_file:
- type: path
- description:
- - The path to the PEM file associated with the service account email.
- - This option is deprecated and may be removed in a future release. Use I(credentials_file) instead.
- credentials_file:
- type: path
- description:
- - The path to the JSON file associated with the service account email.
- service_account_email:
- type: str
- description:
- - service account email
- service_account_permissions:
- type: list
- description:
- - service account permissions
-'''
-
-EXAMPLES = '''
-- name: Create a Global external IP address
- community.google.gce_eip:
- service_account_email: "{{ service_account_email }}"
- credentials_file: "{{ credentials_file }}"
- project_id: "{{ project_id }}"
- name: my-global-ip
- region: global
- state: present
-
-- name: Create a Regional external IP address
- community.google.gce_eip:
- service_account_email: "{{ service_account_email }}"
- credentials_file: "{{ credentials_file }}"
- project_id: "{{ project_id }}"
- name: my-global-ip
- region: us-east1
- state: present
-'''
-
-RETURN = '''
-address:
- description: IP address being operated on
- returned: always
- type: str
- sample: "35.186.222.233"
-name:
- description: name of the address being operated on
- returned: always
- type: str
- sample: "my-address"
-region:
- description: Which region an address belongs.
- returned: always
- type: str
- sample: "global"
-'''
-
-USER_AGENT_VERSION = 'v1'
-USER_AGENT_PRODUCT = 'Ansible-gce_eip'
-
-try:
- from ast import literal_eval
- HAS_PYTHON26 = True
-except ImportError:
- HAS_PYTHON26 = False
-
-try:
- import libcloud
- from libcloud.compute.types import Provider
- from libcloud.compute.providers import get_driver
- from libcloud.common.google import GoogleBaseError, QuotaExceededError, \
- ResourceExistsError, ResourceInUseError, ResourceNotFoundError
- from libcloud.compute.drivers.gce import GCEAddress
- _ = Provider.GCE
- HAS_LIBCLOUD = True
-except ImportError:
- HAS_LIBCLOUD = False
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible_collections.community.google.plugins.module_utils.gcp import gcp_connect
-
-
-def get_address(gce, name, region):
- """
- Get an Address from GCE.
-
- :param gce: An initialized GCE driver object.
- :type gce: :class: `GCENodeDriver`
-
- :param name: Name of the Address.
- :type name: ``str``
-
- :return: A GCEAddress object or None.
- :rtype: :class: `GCEAddress` or None
- """
- try:
- return gce.ex_get_address(name=name, region=region)
-
- except ResourceNotFoundError:
- return None
-
-
-def create_address(gce, params):
- """
- Create a new Address.
-
- :param gce: An initialized GCE driver object.
- :type gce: :class: `GCENodeDriver`
-
- :param params: Dictionary of parameters needed by the module.
- :type params: ``dict``
-
- :return: Tuple with changed status and address.
- :rtype: tuple in the format of (bool, str)
- """
- changed = False
- return_data = []
-
- address = gce.ex_create_address(
- name=params['name'], region=params['region'])
-
- if address:
- changed = True
- return_data = address.address
-
- return (changed, return_data)
-
-
-def delete_address(address):
- """
- Delete an Address.
-
- :param gce: An initialized GCE driver object.
- :type gce: :class: `GCENodeDriver`
-
- :param params: Dictionary of parameters needed by the module.
- :type params: ``dict``
-
- :return: Tuple with changed status and address.
- :rtype: tuple in the format of (bool, str)
- """
- changed = False
- return_data = []
- if address.destroy():
- changed = True
- return_data = address.address
- return (changed, return_data)
-
-
-def main():
- module = AnsibleModule(argument_spec=dict(
- name=dict(required=True),
- state=dict(choices=['absent', 'present'], default='present'),
- region=dict(required=True),
- service_account_email=dict(),
- service_account_permissions=dict(type='list'),
- pem_file=dict(type='path'),
- credentials_file=dict(type='path'),
- project_id=dict(), ), )
-
- if not HAS_PYTHON26:
- module.fail_json(
- msg="GCE module requires python's 'ast' module, python v2.6+")
- if not HAS_LIBCLOUD:
- module.fail_json(
- msg='libcloud with GCE support (+0.19) required for this module.')
-
- gce = gcp_connect(module, Provider.GCE, get_driver,
- USER_AGENT_PRODUCT, USER_AGENT_VERSION)
-
- params = {}
- params['state'] = module.params.get('state')
- params['name'] = module.params.get('name')
- params['region'] = module.params.get('region')
-
- changed = False
- json_output = {'state': params['state']}
- address = get_address(gce, params['name'], region=params['region'])
-
- if params['state'] == 'absent':
- if not address:
- # Doesn't exist in GCE, and state==absent.
- changed = False
- module.fail_json(
- msg="Cannot delete unknown address: %s" %
- (params['name']))
- else:
- # Delete
- (changed, json_output['address']) = delete_address(address)
- else:
- if not address:
- # Create
- (changed, json_output['address']) = create_address(gce,
- params)
- else:
- changed = False
- json_output['address'] = address.address
-
- json_output['changed'] = changed
- json_output.update(params)
- module.exit_json(**json_output)
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/google/plugins/modules/gce_img.py b/ansible_collections/community/google/plugins/modules/gce_img.py
deleted file mode 100644
index 9e53e1e23..000000000
--- a/ansible_collections/community/google/plugins/modules/gce_img.py
+++ /dev/null
@@ -1,211 +0,0 @@
-#!/usr/bin/python
-# Copyright 2015 Google Inc. All Rights Reserved.
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-"""An Ansible module to utilize GCE image resources."""
-
-DOCUMENTATION = '''
----
-module: gce_img
-short_description: utilize GCE image resources
-description:
- - This module can create and delete GCE private images from gzipped
- compressed tarball containing raw disk data or from existing detached
- disks in any zone. U(https://cloud.google.com/compute/docs/images)
-options:
- name:
- type: str
- description:
- - the name of the image to create or delete
- required: true
- description:
- type: str
- description:
- - an optional description
- family:
- type: str
- description:
- - an optional family name
- source:
- type: str
- description:
- - the source disk or the Google Cloud Storage URI to create the image from
- state:
- type: str
- description:
- - desired state of the image
- default: "present"
- choices: ["present", "absent"]
- zone:
- type: str
- description:
- - the zone of the disk specified by source
- default: "us-central1-a"
- timeout:
- type: int
- description:
- - timeout for the operation
- default: 180
- service_account_email:
- type: str
- description:
- - service account email
- pem_file:
- type: path
- description:
- - path to the pem file associated with the service account email
- project_id:
- type: str
- description:
- - your GCE project ID
-requirements:
- - "python >= 2.6"
- - "apache-libcloud"
-author: "Tom Melendez (@supertom)"
-'''
-
-EXAMPLES = '''
-- name: Create an image named test-image from the disk 'test-disk' in zone us-central1-a
- community.google.gce_img:
- name: test-image
- source: test-disk
- zone: us-central1-a
- state: present
-
-- name: Create an image named test-image from a tarball in Google Cloud Storage
- community.google.gce_img:
- name: test-image
- source: https://storage.googleapis.com/bucket/path/to/image.tgz
-
-- name: Alternatively use the gs scheme
- community.google.gce_img:
- name: test-image
- source: gs://bucket/path/to/image.tgz
-
-- name: Delete an image named test-image
- community.google.gce_img:
- name: test-image
- state: absent
-'''
-
-
-try:
- import libcloud
- from libcloud.compute.types import Provider
- from libcloud.compute.providers import get_driver
- from libcloud.common.google import GoogleBaseError
- from libcloud.common.google import ResourceExistsError
- from libcloud.common.google import ResourceNotFoundError
- _ = Provider.GCE
- has_libcloud = True
-except ImportError:
- has_libcloud = False
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible_collections.community.google.plugins.module_utils.gce import gce_connect
-
-
-GCS_URI = 'https://storage.googleapis.com/'
-
-
-def create_image(gce, name, module):
- """Create an image with the specified name."""
- source = module.params.get('source')
- zone = module.params.get('zone')
- desc = module.params.get('description')
- timeout = module.params.get('timeout')
- family = module.params.get('family')
-
- if not source:
- module.fail_json(msg='Must supply a source', changed=False)
-
- if source.startswith(GCS_URI):
- # source is a Google Cloud Storage URI
- volume = source
- elif source.startswith('gs://'):
- # libcloud only accepts https URI.
- volume = source.replace('gs://', GCS_URI)
- else:
- try:
- volume = gce.ex_get_volume(source, zone)
- except ResourceNotFoundError:
- module.fail_json(msg='Disk %s not found in zone %s' % (source, zone),
- changed=False)
- except GoogleBaseError as e:
- module.fail_json(msg=str(e), changed=False)
-
- gce_extra_args = {}
- if family is not None:
- gce_extra_args['family'] = family
-
- old_timeout = gce.connection.timeout
- try:
- gce.connection.timeout = timeout
- gce.ex_create_image(name, volume, desc, use_existing=False, **gce_extra_args)
- return True
- except ResourceExistsError:
- return False
- except GoogleBaseError as e:
- module.fail_json(msg=str(e), changed=False)
- finally:
- gce.connection.timeout = old_timeout
-
-
-def delete_image(gce, name, module):
- """Delete a specific image resource by name."""
- try:
- gce.ex_delete_image(name)
- return True
- except ResourceNotFoundError:
- return False
- except GoogleBaseError as e:
- module.fail_json(msg=str(e), changed=False)
-
-
-def main():
- module = AnsibleModule(
- argument_spec=dict(
- name=dict(required=True),
- family=dict(),
- description=dict(),
- source=dict(),
- state=dict(default='present', choices=['present', 'absent']),
- zone=dict(default='us-central1-a'),
- service_account_email=dict(),
- pem_file=dict(type='path'),
- project_id=dict(),
- timeout=dict(type='int', default=180)
- )
- )
-
- if not has_libcloud:
- module.fail_json(msg='libcloud with GCE support is required.')
-
- gce = gce_connect(module)
-
- name = module.params.get('name')
- state = module.params.get('state')
- family = module.params.get('family')
- changed = False
-
- if family is not None and hasattr(libcloud, '__version__') and libcloud.__version__ <= '0.20.1':
- module.fail_json(msg="Apache Libcloud 1.0.0+ is required to use 'family' option",
- changed=False)
-
- # user wants to create an image.
- if state == 'present':
- changed = create_image(gce, name, module)
-
- # user wants to delete the image.
- if state == 'absent':
- changed = delete_image(gce, name, module)
-
- module.exit_json(changed=changed, name=name)
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/google/plugins/modules/gce_instance_template.py b/ansible_collections/community/google/plugins/modules/gce_instance_template.py
deleted file mode 100644
index ec436b422..000000000
--- a/ansible_collections/community/google/plugins/modules/gce_instance_template.py
+++ /dev/null
@@ -1,605 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# Copyright: Ansible Project
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
----
-module: gce_instance_template
-short_description: create or destroy instance templates of Compute Engine of GCP.
-description:
- - Creates or destroy Google instance templates
- of Compute Engine of Google Cloud Platform.
-options:
- state:
- type: str
- description:
- - The desired state for the instance template.
- default: "present"
- choices: ["present", "absent"]
- name:
- type: str
- description:
- - The name of the GCE instance template.
- required: True
- aliases: [base_name]
- size:
- type: str
- description:
- - The desired machine type for the instance template.
- default: "f1-micro"
- source:
- type: str
- description:
- - A source disk to attach to the instance.
- Cannot specify both I(image) and I(source).
- image:
- type: str
- description:
- - The image to use to create the instance.
- Cannot specify both both I(image) and I(source).
- image_family:
- type: str
- description:
- - The image family to use to create the instance.
- If I(image) has been used I(image_family) is ignored.
- Cannot specify both I(image) and I(source).
- default: debian-8
- disk_type:
- type: str
- description:
- - Specify a C(pd-standard) disk or C(pd-ssd) for an SSD disk.
- choices:
- - pd-standard
- - pd-ssd
- default: pd-standard
- disk_auto_delete:
- description:
- - Indicate that the boot disk should be
- deleted when the Node is deleted.
- default: true
- type: bool
- network:
- type: str
- description:
- - The network to associate with the instance.
- default: "default"
- subnetwork:
- type: str
- description:
- - The Subnetwork resource name for this instance.
- can_ip_forward:
- description:
- - Set to C(yes) to allow instance to
- send/receive non-matching src/dst packets.
- type: bool
- default: 'no'
- external_ip:
- type: str
- description:
- - The external IP address to use.
- If C(ephemeral), a new non-static address will be
- used. If C(None), then no external address will
- be used. To use an existing static IP address
- specify address name.
- default: "ephemeral"
- service_account_email:
- type: str
- description:
- - service account email
- service_account_permissions:
- type: list
- description:
- - service account permissions (see
- U(https://cloud.google.com/sdk/gcloud/reference/compute/instances/create),
- --scopes section for detailed information)
- - >
- Available choices are:
- C(bigquery), C(cloud-platform), C(compute-ro), C(compute-rw),
- C(useraccounts-ro), C(useraccounts-rw), C(datastore), C(logging-write),
- C(monitoring), C(sql-admin), C(storage-full), C(storage-ro),
- C(storage-rw), C(taskqueue), C(userinfo-email).
- automatic_restart:
- description:
- - Defines whether the instance should be
- automatically restarted when it is
- terminated by Compute Engine.
- type: bool
- preemptible:
- description:
- - Defines whether the instance is preemptible.
- type: bool
- tags:
- type: list
- description:
- - a comma-separated list of tags to associate with the instance
- metadata:
- description:
- - a hash/dictionary of custom data for the instance;
- '{"key":"value", ...}'
- description:
- type: str
- description:
- - description of instance template
- disks:
- type: list
- description:
- - a list of persistent disks to attach to the instance; a string value
- gives the name of the disk; alternatively, a dictionary value can
- define 'name' and 'mode' ('READ_ONLY' or 'READ_WRITE'). The first entry
- will be the boot disk (which must be READ_WRITE).
- nic_gce_struct:
- type: list
- description:
- - Support passing in the GCE-specific
- formatted networkInterfaces[] structure.
- disks_gce_struct:
- type: list
- description:
- - Support passing in the GCE-specific
- formatted formatted disks[] structure. Case sensitive.
- see U(https://cloud.google.com/compute/docs/reference/latest/instanceTemplates#resource) for detailed information
- project_id:
- type: str
- description:
- - your GCE project ID
- pem_file:
- type: path
- description:
- - path to the pem file associated with the service account email
- This option is deprecated. Use 'credentials_file'.
- credentials_file:
- type: path
- description:
- - path to the JSON file associated with the service account email
- subnetwork_region:
- type: str
- description:
- - Region that subnetwork resides in. (Required for subnetwork to successfully complete)
-requirements:
- - "python >= 2.6"
- - "apache-libcloud >= 0.13.3, >= 0.17.0 if using JSON credentials,
- >= 0.20.0 if using preemptible option"
-notes:
- - JSON credentials strongly preferred.
-author: "Gwenael Pellen (@GwenaelPellenArkeup) <gwenael.pellen@arkeup.com>"
-'''
-
-EXAMPLES = '''
-# Usage
-- name: Create instance template named foo
- community.google.gce_instance_template:
- name: foo
- size: n1-standard-1
- image_family: ubuntu-1604-lts
- state: present
- project_id: "your-project-name"
- credentials_file: "/path/to/your-key.json"
- service_account_email: "your-sa@your-project-name.iam.gserviceaccount.com"
-
-# Example Playbook
-- name: Compute Engine Instance Template Examples
- hosts: localhost
- vars:
- service_account_email: "your-sa@your-project-name.iam.gserviceaccount.com"
- credentials_file: "/path/to/your-key.json"
- project_id: "your-project-name"
- tasks:
- - name: Create instance template
- community.google.gce_instance_template:
- name: my-test-instance-template
- size: n1-standard-1
- image_family: ubuntu-1604-lts
- state: present
- project_id: "{{ project_id }}"
- credentials_file: "{{ credentials_file }}"
- service_account_email: "{{ service_account_email }}"
- - name: Delete instance template
- community.google.gce_instance_template:
- name: my-test-instance-template
- size: n1-standard-1
- image_family: ubuntu-1604-lts
- state: absent
- project_id: "{{ project_id }}"
- credentials_file: "{{ credentials_file }}"
- service_account_email: "{{ service_account_email }}"
-
-# Example playbook using disks_gce_struct
-- name: Compute Engine Instance Template Examples
- hosts: localhost
- vars:
- service_account_email: "your-sa@your-project-name.iam.gserviceaccount.com"
- credentials_file: "/path/to/your-key.json"
- project_id: "your-project-name"
- tasks:
- - name: Create instance template
- community.google.gce_instance_template:
- name: foo
- size: n1-standard-1
- state: present
- project_id: "{{ project_id }}"
- credentials_file: "{{ credentials_file }}"
- service_account_email: "{{ service_account_email }}"
- disks_gce_struct:
- - device_name: /dev/sda
- boot: true
- autoDelete: true
- initializeParams:
- diskSizeGb: 30
- diskType: pd-ssd
- sourceImage: projects/debian-cloud/global/images/family/debian-8
-
-'''
-
-RETURN = '''
-'''
-
-import traceback
-try:
- from ast import literal_eval
- HAS_PYTHON26 = True
-except ImportError:
- HAS_PYTHON26 = False
-
-try:
- import libcloud
- from libcloud.compute.types import Provider
- from libcloud.compute.providers import get_driver
- from libcloud.common.google import GoogleBaseError, QuotaExceededError, \
- ResourceExistsError, ResourceInUseError, ResourceNotFoundError
- from libcloud.compute.drivers.gce import GCEAddress
- _ = Provider.GCE
- HAS_LIBCLOUD = True
-except ImportError:
- HAS_LIBCLOUD = False
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible_collections.community.google.plugins.module_utils.gce import gce_connect
-from ansible.module_utils._text import to_native
-
-
-def get_info(inst):
- """Retrieves instance template information
- """
- return({
- 'name': inst.name,
- 'extra': inst.extra,
- })
-
-
-def create_instance_template(module, gce):
- """Create an instance template
- module : AnsibleModule object
- gce: authenticated GCE libcloud driver
- Returns:
- instance template information
- """
- # get info from module
- name = module.params.get('name')
- size = module.params.get('size')
- source = module.params.get('source')
- image = module.params.get('image')
- image_family = module.params.get('image_family')
- disk_type = module.params.get('disk_type')
- disk_auto_delete = module.params.get('disk_auto_delete')
- network = module.params.get('network')
- subnetwork = module.params.get('subnetwork')
- subnetwork_region = module.params.get('subnetwork_region')
- can_ip_forward = module.params.get('can_ip_forward')
- external_ip = module.params.get('external_ip')
- service_account_permissions = module.params.get(
- 'service_account_permissions')
- service_account_email = module.params.get('service_account_email')
- on_host_maintenance = module.params.get('on_host_maintenance')
- automatic_restart = module.params.get('automatic_restart')
- preemptible = module.params.get('preemptible')
- tags = module.params.get('tags')
- metadata = module.params.get('metadata')
- description = module.params.get('description')
- disks_gce_struct = module.params.get('disks_gce_struct')
- changed = False
-
- # args of ex_create_instancetemplate
- gce_args = dict(
- name="instance",
- size="f1-micro",
- source=None,
- image=None,
- disk_type='pd-standard',
- disk_auto_delete=True,
- network='default',
- subnetwork=None,
- can_ip_forward=None,
- external_ip='ephemeral',
- service_accounts=None,
- on_host_maintenance=None,
- automatic_restart=None,
- preemptible=None,
- tags=None,
- metadata=None,
- description=None,
- disks_gce_struct=None,
- nic_gce_struct=None
- )
-
- gce_args['name'] = name
- gce_args['size'] = size
-
- if source is not None:
- gce_args['source'] = source
-
- if image:
- gce_args['image'] = image
- else:
- if image_family:
- image = gce.ex_get_image_from_family(image_family)
- gce_args['image'] = image
- else:
- gce_args['image'] = "debian-8"
-
- gce_args['disk_type'] = disk_type
- gce_args['disk_auto_delete'] = disk_auto_delete
-
- gce_network = gce.ex_get_network(network)
- gce_args['network'] = gce_network
-
- if subnetwork is not None:
- gce_args['subnetwork'] = gce.ex_get_subnetwork(subnetwork, region=subnetwork_region)
-
- if can_ip_forward is not None:
- gce_args['can_ip_forward'] = can_ip_forward
-
- if external_ip == "ephemeral":
- instance_external_ip = external_ip
- elif external_ip == "none":
- instance_external_ip = None
- else:
- try:
- instance_external_ip = gce.ex_get_address(external_ip)
- except GoogleBaseError as err:
- # external_ip is name ?
- instance_external_ip = external_ip
- gce_args['external_ip'] = instance_external_ip
-
- ex_sa_perms = []
- bad_perms = []
- if service_account_permissions:
- for perm in service_account_permissions:
- if perm not in gce.SA_SCOPES_MAP:
- bad_perms.append(perm)
- if len(bad_perms) > 0:
- module.fail_json(msg='bad permissions: %s' % str(bad_perms))
- if service_account_email is not None:
- ex_sa_perms.append({'email': str(service_account_email)})
- else:
- ex_sa_perms.append({'email': "default"})
- ex_sa_perms[0]['scopes'] = service_account_permissions
- gce_args['service_accounts'] = ex_sa_perms
-
- if on_host_maintenance is not None:
- gce_args['on_host_maintenance'] = on_host_maintenance
-
- if automatic_restart is not None:
- gce_args['automatic_restart'] = automatic_restart
-
- if preemptible is not None:
- gce_args['preemptible'] = preemptible
-
- if tags is not None:
- gce_args['tags'] = tags
-
- if disks_gce_struct is not None:
- gce_args['disks_gce_struct'] = disks_gce_struct
-
- # Try to convert the user's metadata value into the format expected
- # by GCE. First try to ensure user has proper quoting of a
- # dictionary-like syntax using 'literal_eval', then convert the python
- # dict into a python list of 'key' / 'value' dicts. Should end up
- # with:
- # [ {'key': key1, 'value': value1}, {'key': key2, 'value': value2}, ...]
- if metadata:
- if isinstance(metadata, dict):
- md = metadata
- else:
- try:
- md = literal_eval(str(metadata))
- if not isinstance(md, dict):
- raise ValueError('metadata must be a dict')
- except ValueError as e:
- module.fail_json(msg='bad metadata: %s' % str(e))
- except SyntaxError as e:
- module.fail_json(msg='bad metadata syntax')
-
- if hasattr(libcloud, '__version__') and libcloud.__version__ < '0.15':
- items = []
- for k, v in md.items():
- items.append({"key": k, "value": v})
- metadata = {'items': items}
- else:
- metadata = md
- gce_args['metadata'] = metadata
-
- if description is not None:
- gce_args['description'] = description
-
- instance = None
- try:
- instance = gce.ex_get_instancetemplate(name)
- except ResourceNotFoundError:
- try:
- instance = gce.ex_create_instancetemplate(**gce_args)
- changed = True
- except GoogleBaseError as err:
- module.fail_json(
- msg='Unexpected error attempting to create instance {0}, error: {1}'
- .format(
- instance,
- err.value
- )
- )
-
- if instance:
- json_data = get_info(instance)
- else:
- module.fail_json(msg="no instance template!")
-
- return (changed, json_data, name)
-
-
-def delete_instance_template(module, gce):
- """ Delete instance template.
- module : AnsibleModule object
- gce: authenticated GCE libcloud driver
- Returns:
- instance template information
- """
- name = module.params.get('name')
- current_state = "absent"
- changed = False
-
- # get instance template
- instance = None
- try:
- instance = gce.ex_get_instancetemplate(name)
- current_state = "present"
- except GoogleBaseError as e:
- json_data = dict(msg='instance template not exists: %s' % to_native(e),
- exception=traceback.format_exc())
-
- if current_state == "present":
- rc = instance.destroy()
- if rc:
- changed = True
- else:
- module.fail_json(
- msg='instance template destroy failed'
- )
-
- json_data = {}
- return (changed, json_data, name)
-
-
-def module_controller(module, gce):
- ''' Control module state parameter.
- module : AnsibleModule object
- gce: authenticated GCE libcloud driver
- Returns:
- nothing
- Exit:
- AnsibleModule object exit with json data.
- '''
- json_output = dict()
- state = module.params.get("state")
- if state == "present":
- (changed, output, name) = create_instance_template(module, gce)
- json_output['changed'] = changed
- json_output['msg'] = output
- elif state == "absent":
- (changed, output, name) = delete_instance_template(module, gce)
- json_output['changed'] = changed
- json_output['msg'] = output
-
- module.exit_json(**json_output)
-
-
-def check_if_system_state_would_be_changed(module, gce):
- ''' check_if_system_state_would_be_changed !
- module : AnsibleModule object
- gce: authenticated GCE libcloud driver
- Returns:
- system_state changed
- '''
- changed = False
- current_state = "absent"
-
- state = module.params.get("state")
- name = module.params.get("name")
-
- try:
- gce.ex_get_instancetemplate(name)
- current_state = "present"
- except GoogleBaseError as e:
- module.fail_json(msg='GCE get instancetemplate problem: %s' % to_native(e),
- exception=traceback.format_exc())
-
- if current_state != state:
- changed = True
-
- if current_state == "absent":
- if changed:
- output = 'instance template {0} will be created'.format(name)
- else:
- output = 'nothing to do for instance template {0} '.format(name)
- if current_state == "present":
- if changed:
- output = 'instance template {0} will be destroyed'.format(name)
- else:
- output = 'nothing to do for instance template {0} '.format(name)
-
- return (changed, output)
-
-
-def main():
- module = AnsibleModule(
- argument_spec=dict(
- state=dict(choices=['present', 'absent'], default='present'),
- name=dict(required=True, aliases=['base_name']),
- size=dict(default='f1-micro'),
- source=dict(),
- image=dict(),
- image_family=dict(default='debian-8'),
- disk_type=dict(choices=['pd-standard', 'pd-ssd'], default='pd-standard', type='str'),
- disk_auto_delete=dict(type='bool', default=True),
- network=dict(default='default'),
- subnetwork=dict(),
- can_ip_forward=dict(type='bool', default=False),
- external_ip=dict(default='ephemeral'),
- service_account_email=dict(),
- service_account_permissions=dict(type='list'),
- automatic_restart=dict(type='bool', default=None),
- preemptible=dict(type='bool', default=None),
- tags=dict(type='list'),
- metadata=dict(),
- description=dict(),
- disks=dict(type='list'),
- nic_gce_struct=dict(type='list'),
- project_id=dict(),
- pem_file=dict(type='path'),
- credentials_file=dict(type='path'),
- subnetwork_region=dict(),
- disks_gce_struct=dict(type='list')
- ),
- mutually_exclusive=[['source', 'image']],
- required_one_of=[['image', 'image_family']],
- supports_check_mode=True
- )
-
- if not HAS_PYTHON26:
- module.fail_json(
- msg="GCE module requires python's 'ast' module, python v2.6+")
- if not HAS_LIBCLOUD:
- module.fail_json(
- msg='libcloud with GCE support (0.17.0+) required for this module')
-
- try:
- gce = gce_connect(module)
- except GoogleBaseError as e:
- module.fail_json(msg='GCE Connection failed %s' % to_native(e), exception=traceback.format_exc())
-
- if module.check_mode:
- (changed, output) = check_if_system_state_would_be_changed(module, gce)
- module.exit_json(
- changed=changed,
- msg=output
- )
- else:
- module_controller(module, gce)
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/google/plugins/modules/gce_labels.py b/ansible_collections/community/google/plugins/modules/gce_labels.py
deleted file mode 100644
index 3eed2df2f..000000000
--- a/ansible_collections/community/google/plugins/modules/gce_labels.py
+++ /dev/null
@@ -1,350 +0,0 @@
-#!/usr/bin/python
-# Copyright 2017 Google Inc.
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
----
-module: gce_labels
-short_description: Create, Update or Destroy GCE Labels.
-description:
- - Create, Update or Destroy GCE Labels on instances, disks, snapshots, etc.
- When specifying the GCE resource, users may specify the full URL for
- the resource (its 'self_link'), or the individual parameters of the
- resource (type, location, name). Examples for the two options can be
- seen in the documentation.
- See U(https://cloud.google.com/compute/docs/label-or-tag-resources) for
- more information about GCE Labels. Labels are gradually being added to
- more GCE resources, so this module will need to be updated as new
- resources are added to the GCE (v1) API.
-requirements:
- - 'python >= 2.6'
- - 'google-api-python-client >= 1.6.2'
- - 'google-auth >= 1.0.0'
- - 'google-auth-httplib2 >= 0.0.2'
-notes:
- - Labels support resources such as instances, disks, images, etc. See
- U(https://cloud.google.com/compute/docs/labeling-resources) for the list
- of resources available in the GCE v1 API (not alpha or beta).
-author:
- - 'Eric Johnson (@erjohnso) <erjohnso@google.com>'
-options:
- labels:
- type: dict
- description:
- - A list of labels (key/value pairs) to add or remove for the resource.
- required: false
- resource_url:
- type: str
- description:
- - The 'self_link' for the resource (instance, disk, snapshot, etc)
- required: false
- resource_type:
- type: str
- description:
- - The type of resource (instances, disks, snapshots, images)
- required: false
- resource_location:
- type: str
- description:
- - The location of resource (global, us-central1-f, etc.)
- required: false
- resource_name:
- type: str
- description:
- - The name of resource.
- required: false
- state:
- type: str
- description: The state the labels should be in. C(present) or C(absent) are the only valid options.
- default: present
- required: false
- choices: [present, absent]
- project_id:
- type: str
- description:
- - The Google Cloud Platform project ID to use.
- pem_file:
- type: str
- description:
- - The path to the PEM file associated with the service account email.
- - This option is deprecated and may be removed in a future release. Use I(credentials_file) instead.
- credentials_file:
- type: str
- description:
- - The path to the JSON file associated with the service account email.
- service_account_email:
- type: str
- description:
- - service account email
- service_account_permissions:
- type: list
- description:
- - service account email
-'''
-
-EXAMPLES = '''
-- name: Add labels on an existing instance (using resource_url)
- community.google.gce_labels:
- service_account_email: "{{ service_account_email }}"
- credentials_file: "{{ credentials_file }}"
- project_id: "{{ project_id }}"
- labels:
- webserver-frontend: homepage
- environment: test
- experiment-name: kennedy
- resource_url: https://www.googleapis.com/compute/beta/projects/myproject/zones/us-central1-f/instances/example-instance
- state: present
-- name: Add labels on an image (using resource params)
- community.google.gce_labels:
- service_account_email: "{{ service_account_email }}"
- credentials_file: "{{ credentials_file }}"
- project_id: "{{ project_id }}"
- labels:
- webserver-frontend: homepage
- environment: test
- experiment-name: kennedy
- resource_type: images
- resource_location: global
- resource_name: my-custom-image
- state: present
-- name: Remove specified labels from the GCE instance
- community.google.gce_labels:
- service_account_email: "{{ service_account_email }}"
- credentials_file: "{{ credentials_file }}"
- project_id: "{{ project_id }}"
- labels:
- environment: prod
- experiment-name: kennedy
- resource_url: https://www.googleapis.com/compute/beta/projects/myproject/zones/us-central1-f/instances/example-instance
- state: absent
-'''
-
-RETURN = '''
-labels:
- description: List of labels that exist on the resource.
- returned: Always.
- type: dict
- sample: [ { 'webserver-frontend': 'homepage', 'environment': 'test', 'environment-name': 'kennedy' } ]
-resource_url:
- description: The 'self_link' of the GCE resource.
- returned: Always.
- type: str
- sample: 'https://www.googleapis.com/compute/beta/projects/myproject/zones/us-central1-f/instances/example-instance'
-resource_type:
- description: The type of the GCE resource.
- returned: Always.
- type: str
- sample: instances
-resource_location:
- description: The location of the GCE resource.
- returned: Always.
- type: str
- sample: us-central1-f
-resource_name:
- description: The name of the GCE resource.
- returned: Always.
- type: str
- sample: my-happy-little-instance
-state:
- description: state of the labels
- returned: Always.
- type: str
- sample: present
-'''
-
-try:
- from ast import literal_eval
- HAS_PYTHON26 = True
-except ImportError:
- HAS_PYTHON26 = False
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible_collections.community.google.plugins.module_utils.gcp import check_params, get_google_api_client, GCPUtils
-
-
-UA_PRODUCT = 'ansible-gce_labels'
-UA_VERSION = '0.0.1'
-GCE_API_VERSION = 'v1'
-
-# TODO(all): As Labels are added to more GCE resources, this list will need to
-# be updated (along with some code changes below). The list can *only* include
-# resources from the 'v1' GCE API and will *not* work with 'beta' or 'alpha'.
-KNOWN_RESOURCES = ['instances', 'disks', 'snapshots', 'images']
-
-
-def _fetch_resource(client, module):
- params = module.params
- if params['resource_url']:
- if not params['resource_url'].startswith('https://www.googleapis.com/compute'):
- module.fail_json(
- msg='Invalid self_link url: %s' % params['resource_url'])
- else:
- parts = params['resource_url'].split('/')[8:]
- if len(parts) == 2:
- resource_type, resource_name = parts
- resource_location = 'global'
- else:
- resource_location, resource_type, resource_name = parts
- else:
- if not params['resource_type'] or not params['resource_location'] \
- or not params['resource_name']:
- module.fail_json(msg='Missing required resource params.')
- resource_type = params['resource_type'].lower()
- resource_name = params['resource_name'].lower()
- resource_location = params['resource_location'].lower()
-
- if resource_type not in KNOWN_RESOURCES:
- module.fail_json(msg='Unsupported resource_type: %s' % resource_type)
-
- # TODO(all): See the comment above for KNOWN_RESOURCES. As labels are
- # added to the v1 GCE API for more resources, some minor code work will
- # need to be added here.
- if resource_type == 'instances':
- resource = client.instances().get(project=params['project_id'],
- zone=resource_location,
- instance=resource_name).execute()
- elif resource_type == 'disks':
- resource = client.disks().get(project=params['project_id'],
- zone=resource_location,
- disk=resource_name).execute()
- elif resource_type == 'snapshots':
- resource = client.snapshots().get(project=params['project_id'],
- snapshot=resource_name).execute()
- elif resource_type == 'images':
- resource = client.images().get(project=params['project_id'],
- image=resource_name).execute()
- else:
- module.fail_json(msg='Unsupported resource type: %s' % resource_type)
-
- return resource.get('labelFingerprint', ''), {
- 'resource_name': resource.get('name'),
- 'resource_url': resource.get('selfLink'),
- 'resource_type': resource_type,
- 'resource_location': resource_location,
- 'labels': resource.get('labels', {})
- }
-
-
-def _set_labels(client, new_labels, module, ri, fingerprint):
- params = module.params
- result = err = None
- labels = {
- 'labels': new_labels,
- 'labelFingerprint': fingerprint
- }
-
- # TODO(all): See the comment above for KNOWN_RESOURCES. As labels are
- # added to the v1 GCE API for more resources, some minor code work will
- # need to be added here.
- if ri['resource_type'] == 'instances':
- req = client.instances().setLabels(project=params['project_id'],
- instance=ri['resource_name'],
- zone=ri['resource_location'],
- body=labels)
- elif ri['resource_type'] == 'disks':
- req = client.disks().setLabels(project=params['project_id'],
- zone=ri['resource_location'],
- resource=ri['resource_name'],
- body=labels)
- elif ri['resource_type'] == 'snapshots':
- req = client.snapshots().setLabels(project=params['project_id'],
- resource=ri['resource_name'],
- body=labels)
- elif ri['resource_type'] == 'images':
- req = client.images().setLabels(project=params['project_id'],
- resource=ri['resource_name'],
- body=labels)
- else:
- module.fail_json(msg='Unsupported resource type: %s' % ri['resource_type'])
-
- # TODO(erjohnso): Once Labels goes GA, we'll be able to use the GCPUtils
- # method to poll for the async request/operation to complete before
- # returning. However, during 'beta', we are in an odd state where
- # API requests must be sent to the 'compute/beta' API, but the python
- # client library only allows for *Operations.get() requests to be
- # sent to 'compute/v1' API. The response operation is in the 'beta'
- # API-scope, but the client library cannot find the operation (404).
- # result = GCPUtils.execute_api_client_req(req, client=client, raw=False)
- # return result, err
- result = req.execute()
- return True, err
-
-
-def main():
- module = AnsibleModule(
- argument_spec=dict(
- state=dict(choices=['absent', 'present'], default='present'),
- service_account_email=dict(),
- service_account_permissions=dict(type='list'),
- pem_file=dict(),
- credentials_file=dict(),
- labels=dict(required=False, type='dict', default={}),
- resource_url=dict(required=False, type='str'),
- resource_name=dict(required=False, type='str'),
- resource_location=dict(required=False, type='str'),
- resource_type=dict(required=False, type='str'),
- project_id=dict()
- ),
- required_together=[
- ['resource_name', 'resource_location', 'resource_type']
- ],
- mutually_exclusive=[
- ['resource_url', 'resource_name'],
- ['resource_url', 'resource_location'],
- ['resource_url', 'resource_type']
- ]
- )
-
- if not HAS_PYTHON26:
- module.fail_json(
- msg="GCE module requires python's 'ast' module, python v2.6+")
-
- client, cparams = get_google_api_client(module, 'compute',
- user_agent_product=UA_PRODUCT,
- user_agent_version=UA_VERSION,
- api_version=GCE_API_VERSION)
-
- # Get current resource info including labelFingerprint
- fingerprint, resource_info = _fetch_resource(client, module)
- new_labels = resource_info['labels'].copy()
-
- update_needed = False
- if module.params['state'] == 'absent':
- for k, v in module.params['labels'].items():
- if k in new_labels:
- if new_labels[k] == v:
- update_needed = True
- new_labels.pop(k, None)
- else:
- module.fail_json(msg="Could not remove unmatched label pair '%s':'%s'" % (k, v))
- else:
- for k, v in module.params['labels'].items():
- if k not in new_labels:
- update_needed = True
- new_labels[k] = v
-
- changed = False
- json_output = {'state': module.params['state']}
- if update_needed:
- changed, err = _set_labels(client, new_labels, module, resource_info,
- fingerprint)
- json_output['changed'] = changed
-
- # TODO(erjohnso): probably want to re-fetch the resource to return the
- # new labelFingerprint, check that desired labels match updated labels.
- # BUT! Will need to wait for setLabels() to hit v1 API so we can use the
- # GCPUtils feature to poll for the operation to be complete. For now,
- # we'll just update the output with what we have from the original
- # state of the resource.
- json_output.update(resource_info)
- json_output.update(module.params)
-
- module.exit_json(**json_output)
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/google/plugins/modules/gce_lb.py b/ansible_collections/community/google/plugins/modules/gce_lb.py
deleted file mode 100644
index ff29b56de..000000000
--- a/ansible_collections/community/google/plugins/modules/gce_lb.py
+++ /dev/null
@@ -1,310 +0,0 @@
-#!/usr/bin/python
-# Copyright 2013 Google Inc.
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
----
-module: gce_lb
-short_description: create/destroy GCE load-balancer resources
-description:
- - This module can create and destroy Google Compute Engine C(loadbalancer)
- and C(httphealthcheck) resources. The primary LB resource is the
- C(load_balancer) resource and the health check parameters are all
- prefixed with I(httphealthcheck).
- The full documentation for Google Compute Engine load balancing is at
- U(https://developers.google.com/compute/docs/load-balancing/). However,
- the ansible module simplifies the configuration by following the
- libcloud model.
- Full install/configuration instructions for the gce* modules can
- be found in the comments of ansible/test/gce_tests.py.
-options:
- httphealthcheck_name:
- type: str
- description:
- - the name identifier for the HTTP health check
- httphealthcheck_port:
- type: int
- description:
- - the TCP port to use for HTTP health checking
- default: 80
- httphealthcheck_path:
- type: str
- description:
- - the url path to use for HTTP health checking
- default: "/"
- httphealthcheck_interval:
- type: int
- description:
- - the duration in seconds between each health check request
- default: 5
- httphealthcheck_timeout:
- type: int
- description:
- - the timeout in seconds before a request is considered a failed check
- default: 5
- httphealthcheck_unhealthy_count:
- type: int
- description:
- - number of consecutive failed checks before marking a node unhealthy
- default: 2
- httphealthcheck_healthy_count:
- type: int
- description:
- - number of consecutive successful checks before marking a node healthy
- default: 2
- httphealthcheck_host:
- type: str
- description:
- - host header to pass through on HTTP check requests
- name:
- type: str
- description:
- - name of the load-balancer resource
- protocol:
- type: str
- description:
- - the protocol used for the load-balancer packet forwarding, tcp or udp
- - "the available choices are: C(tcp) or C(udp)."
- default: "tcp"
- region:
- type: str
- description:
- - the GCE region where the load-balancer is defined
- external_ip:
- type: str
- description:
- - the external static IPv4 (or auto-assigned) address for the LB
- port_range:
- type: str
- description:
- - the port (range) to forward, e.g. 80 or 8000-8888 defaults to all ports
- members:
- type: list
- description:
- - a list of zone/nodename pairs, e.g ['us-central1-a/www-a', ...]
- state:
- type: str
- description:
- - desired state of the LB
- - "the available choices are: C(active), C(present), C(absent), C(deleted)."
- default: "present"
- service_account_email:
- type: str
- description:
- - service account email
- pem_file:
- type: path
- description:
- - path to the pem file associated with the service account email
- This option is deprecated. Use 'credentials_file'.
- credentials_file:
- type: path
- description:
- - path to the JSON file associated with the service account email
- project_id:
- type: str
- description:
- - your GCE project ID
-
-requirements:
- - "python >= 2.6"
- - "apache-libcloud >= 0.13.3, >= 0.17.0 if using JSON credentials"
-author: "Eric Johnson (@erjohnso) <erjohnso@google.com>"
-'''
-
-EXAMPLES = '''
-- name: Simple example of creating a new LB, adding members, and a health check
- local_action:
- module: gce_lb
- name: testlb
- region: us-central1
- members: ["us-central1-a/www-a", "us-central1-b/www-b"]
- httphealthcheck_name: hc
- httphealthcheck_port: 80
- httphealthcheck_path: "/up"
-'''
-
-try:
- from libcloud.compute.types import Provider
- from libcloud.compute.providers import get_driver
- from libcloud.loadbalancer.types import Provider as Provider_lb
- from libcloud.loadbalancer.providers import get_driver as get_driver_lb
- from libcloud.common.google import GoogleBaseError, QuotaExceededError, ResourceExistsError, ResourceNotFoundError
-
- _ = Provider.GCE
- HAS_LIBCLOUD = True
-except ImportError:
- HAS_LIBCLOUD = False
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible_collections.community.google.plugins.module_utils.gce import USER_AGENT_PRODUCT, USER_AGENT_VERSION, gce_connect, unexpected_error_msg
-
-
-def main():
- module = AnsibleModule(
- argument_spec=dict(
- httphealthcheck_name=dict(),
- httphealthcheck_port=dict(default=80, type='int'),
- httphealthcheck_path=dict(default='/'),
- httphealthcheck_interval=dict(default=5, type='int'),
- httphealthcheck_timeout=dict(default=5, type='int'),
- httphealthcheck_unhealthy_count=dict(default=2, type='int'),
- httphealthcheck_healthy_count=dict(default=2, type='int'),
- httphealthcheck_host=dict(),
- name=dict(),
- protocol=dict(default='tcp'),
- region=dict(),
- external_ip=dict(),
- port_range=dict(),
- members=dict(type='list'),
- state=dict(default='present'),
- service_account_email=dict(),
- pem_file=dict(type='path'),
- credentials_file=dict(type='path'),
- project_id=dict(),
- )
- )
-
- if not HAS_LIBCLOUD:
- module.fail_json(msg='libcloud with GCE support (0.13.3+) required for this module.')
-
- gce = gce_connect(module)
-
- httphealthcheck_name = module.params.get('httphealthcheck_name')
- httphealthcheck_port = module.params.get('httphealthcheck_port')
- httphealthcheck_path = module.params.get('httphealthcheck_path')
- httphealthcheck_interval = module.params.get('httphealthcheck_interval')
- httphealthcheck_timeout = module.params.get('httphealthcheck_timeout')
- httphealthcheck_unhealthy_count = module.params.get('httphealthcheck_unhealthy_count')
- httphealthcheck_healthy_count = module.params.get('httphealthcheck_healthy_count')
- httphealthcheck_host = module.params.get('httphealthcheck_host')
- name = module.params.get('name')
- protocol = module.params.get('protocol')
- region = module.params.get('region')
- external_ip = module.params.get('external_ip')
- port_range = module.params.get('port_range')
- members = module.params.get('members')
- state = module.params.get('state')
-
- try:
- gcelb = get_driver_lb(Provider_lb.GCE)(gce_driver=gce)
- gcelb.connection.user_agent_append("%s/%s" % (
- USER_AGENT_PRODUCT, USER_AGENT_VERSION))
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
-
- changed = False
- json_output = {'name': name, 'state': state}
-
- if not name and not httphealthcheck_name:
- module.fail_json(msg='Nothing to do, please specify a "name" ' + 'or "httphealthcheck_name" parameter', changed=False)
-
- if state in ['active', 'present']:
- # first, create the httphealthcheck if requested
- hc = None
- if httphealthcheck_name:
- json_output['httphealthcheck_name'] = httphealthcheck_name
- try:
- hc = gcelb.ex_create_healthcheck(httphealthcheck_name,
- host=httphealthcheck_host, path=httphealthcheck_path,
- port=httphealthcheck_port,
- interval=httphealthcheck_interval,
- timeout=httphealthcheck_timeout,
- unhealthy_threshold=httphealthcheck_unhealthy_count,
- healthy_threshold=httphealthcheck_healthy_count)
- changed = True
- except ResourceExistsError:
- hc = gce.ex_get_healthcheck(httphealthcheck_name)
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
-
- if hc is not None:
- json_output['httphealthcheck_host'] = hc.extra['host']
- json_output['httphealthcheck_path'] = hc.path
- json_output['httphealthcheck_port'] = hc.port
- json_output['httphealthcheck_interval'] = hc.interval
- json_output['httphealthcheck_timeout'] = hc.timeout
- json_output['httphealthcheck_unhealthy_count'] = hc.unhealthy_threshold
- json_output['httphealthcheck_healthy_count'] = hc.healthy_threshold
-
- # create the forwarding rule (and target pool under the hood)
- lb = None
- if name:
- if not region:
- module.fail_json(msg='Missing required region name',
- changed=False)
- nodes = []
- output_nodes = []
- json_output['name'] = name
- # members is a python list of 'zone/inst' strings
- if members:
- for node in members:
- try:
- zone, node_name = node.split('/')
- nodes.append(gce.ex_get_node(node_name, zone))
- output_nodes.append(node)
- except Exception:
- # skip nodes that are badly formatted or don't exist
- pass
- try:
- if hc is not None:
- lb = gcelb.create_balancer(name, port_range, protocol,
- None, nodes, ex_region=region, ex_healthchecks=[hc],
- ex_address=external_ip)
- else:
- lb = gcelb.create_balancer(name, port_range, protocol,
- None, nodes, ex_region=region, ex_address=external_ip)
- changed = True
- except ResourceExistsError:
- lb = gcelb.get_balancer(name)
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
-
- if lb is not None:
- json_output['members'] = output_nodes
- json_output['protocol'] = protocol
- json_output['region'] = region
- json_output['external_ip'] = lb.ip
- json_output['port_range'] = lb.port
- hc_names = []
- if 'healthchecks' in lb.extra:
- for hc in lb.extra['healthchecks']:
- hc_names.append(hc.name)
- json_output['httphealthchecks'] = hc_names
-
- if state in ['absent', 'deleted']:
- # first, delete the load balancer (forwarding rule and target pool)
- # if specified.
- if name:
- json_output['name'] = name
- try:
- lb = gcelb.get_balancer(name)
- gcelb.destroy_balancer(lb)
- changed = True
- except ResourceNotFoundError:
- pass
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
-
- # destroy the health check if specified
- if httphealthcheck_name:
- json_output['httphealthcheck_name'] = httphealthcheck_name
- try:
- hc = gce.ex_get_healthcheck(httphealthcheck_name)
- gce.ex_destroy_healthcheck(hc)
- changed = True
- except ResourceNotFoundError:
- pass
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
-
- json_output['changed'] = changed
- module.exit_json(**json_output)
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/google/plugins/modules/gce_mig.py b/ansible_collections/community/google/plugins/modules/gce_mig.py
deleted file mode 100644
index fd47167f9..000000000
--- a/ansible_collections/community/google/plugins/modules/gce_mig.py
+++ /dev/null
@@ -1,904 +0,0 @@
-#!/usr/bin/python
-# Copyright 2016 Google Inc.
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
----
-module: gce_mig
-short_description: Create, Update or Destroy a Managed Instance Group (MIG).
-description:
- - Create, Update or Destroy a Managed Instance Group (MIG). See
- U(https://cloud.google.com/compute/docs/instance-groups) for an overview.
- Full install/configuration instructions for the gce* modules can
- be found in the comments of ansible/test/gce_tests.py.
-requirements:
- - "python >= 2.6"
- - "apache-libcloud >= 1.2.0"
-notes:
- - Resizing and Recreating VM are also supported.
- - An existing instance template is required in order to create a
- Managed Instance Group.
-author:
- - "Tom Melendez (@supertom) <tom@supertom.com>"
-options:
- name:
- type: str
- description:
- - Name of the Managed Instance Group.
- required: true
- template:
- type: str
- description:
- - Instance Template to be used in creating the VMs. See
- U(https://cloud.google.com/compute/docs/instance-templates) to learn more
- about Instance Templates. Required for creating MIGs.
- size:
- type: int
- description:
- - Size of Managed Instance Group. If MIG already exists, it will be
- resized to the number provided here. Required for creating MIGs.
- service_account_email:
- type: str
- description:
- - service account email
- service_account_permissions:
- type: list
- description:
- - service account permissions
- pem_file:
- type: path
- description:
- - path to the pem file associated with the service account email
- This option is deprecated. Use 'credentials_file'.
- credentials_file:
- type: path
- description:
- - Path to the JSON file associated with the service account email
- project_id:
- type: str
- description:
- - GCE project ID
- state:
- type: str
- description:
- - desired state of the resource
- default: "present"
- choices: ["absent", "present"]
- zone:
- type: str
- description:
- - The GCE zone to use for this Managed Instance Group.
- required: true
- autoscaling:
- type: dict
- description:
- - A dictionary of configuration for the autoscaler. 'enabled (bool)', 'name (str)'
- and policy.max_instances (int) are required fields if autoscaling is used. See
- U(https://cloud.google.com/compute/docs/reference/beta/autoscalers) for more information
- on Autoscaling.
- named_ports:
- type: list
- description:
- - Define named ports that backend services can forward data to. Format is a a list of
- name:port dictionaries.
- recreate_instances:
- type: bool
- default: no
- description:
- - Recreate MIG instances.
-'''
-
-EXAMPLES = '''
-# Following playbook creates, rebuilds instances, resizes and then deletes a MIG.
-# Notes:
-# - Two valid Instance Templates must exist in your GCE project in order to run
-# this playbook. Change the fields to match the templates used in your
-# project.
-# - The use of the 'pause' module is not required, it is just for convenience.
-- name: Managed Instance Group Example
- hosts: localhost
- gather_facts: False
- tasks:
- - name: Create MIG
- community.google.gce_mig:
- name: ansible-mig-example
- zone: us-central1-c
- state: present
- size: 1
- template: my-instance-template-1
- named_ports:
- - name: http
- port: 80
- - name: foobar
- port: 82
-
- - name: Pause for 30 seconds
- ansible.builtin.pause:
- seconds: 30
-
- - name: Recreate MIG Instances with Instance Template change.
- community.google.gce_mig:
- name: ansible-mig-example
- zone: us-central1-c
- state: present
- template: my-instance-template-2-small
- recreate_instances: yes
-
- - name: Pause for 30 seconds
- ansible.builtin.pause:
- seconds: 30
-
- - name: Resize MIG
- community.google.gce_mig:
- name: ansible-mig-example
- zone: us-central1-c
- state: present
- size: 3
-
- - name: Update MIG with Autoscaler
- community.google.gce_mig:
- name: ansible-mig-example
- zone: us-central1-c
- state: present
- size: 3
- template: my-instance-template-2-small
- recreate_instances: yes
- autoscaling:
- enabled: yes
- name: my-autoscaler
- policy:
- min_instances: 2
- max_instances: 5
- cool_down_period: 37
- cpu_utilization:
- target: .39
- load_balancing_utilization:
- target: 0.4
-
- - name: Pause for 30 seconds
- ansible.builtin.pause:
- seconds: 30
-
- - name: Delete MIG
- community.google.gce_mig:
- name: ansible-mig-example
- zone: us-central1-c
- state: absent
- autoscaling:
- enabled: no
- name: my-autoscaler
-'''
-RETURN = '''
-zone:
- description: Zone in which to launch MIG.
- returned: always
- type: str
- sample: "us-central1-b"
-
-template:
- description: Instance Template to use for VMs. Must exist prior to using with MIG.
- returned: changed
- type: str
- sample: "my-instance-template"
-
-name:
- description: Name of the Managed Instance Group.
- returned: changed
- type: str
- sample: "my-managed-instance-group"
-
-named_ports:
- description: list of named ports acted upon
- returned: when named_ports are initially set or updated
- type: list
- sample: [{ "name": "http", "port": 80 }, { "name": "foo", "port": 82 }]
-
-size:
- description: Number of VMs in Managed Instance Group.
- returned: changed
- type: int
- sample: 4
-
-created_instances:
- description: Names of instances created.
- returned: When instances are created.
- type: list
- sample: ["ansible-mig-new-0k4y", "ansible-mig-new-0zk5", "ansible-mig-new-kp68"]
-
-deleted_instances:
- description: Names of instances deleted.
- returned: When instances are deleted.
- type: list
- sample: ["ansible-mig-new-0k4y", "ansible-mig-new-0zk5", "ansible-mig-new-kp68"]
-
-resize_created_instances:
- description: Names of instances created during resizing.
- returned: When a resize results in the creation of instances.
- type: list
- sample: ["ansible-mig-new-0k4y", "ansible-mig-new-0zk5", "ansible-mig-new-kp68"]
-
-resize_deleted_instances:
- description: Names of instances deleted during resizing.
- returned: When a resize results in the deletion of instances.
- type: list
- sample: ["ansible-mig-new-0k4y", "ansible-mig-new-0zk5", "ansible-mig-new-kp68"]
-
-recreated_instances:
- description: Names of instances recreated.
- returned: When instances are recreated.
- type: list
- sample: ["ansible-mig-new-0k4y", "ansible-mig-new-0zk5", "ansible-mig-new-kp68"]
-
-created_autoscaler:
- description: True if Autoscaler was attempted and created. False otherwise.
- returned: When the creation of an Autoscaler was attempted.
- type: bool
- sample: true
-
-updated_autoscaler:
- description: True if an Autoscaler update was attempted and succeeded.
- False returned if update failed.
- returned: When the update of an Autoscaler was attempted.
- type: bool
- sample: true
-
-deleted_autoscaler:
- description: True if an Autoscaler delete attempted and succeeded.
- False returned if delete failed.
- returned: When the delete of an Autoscaler was attempted.
- type: bool
- sample: true
-
-set_named_ports:
- description: True if the named_ports have been set
- returned: named_ports have been set
- type: bool
- sample: true
-
-updated_named_ports:
- description: True if the named_ports have been updated
- returned: named_ports have been updated
- type: bool
- sample: true
-'''
-
-try:
- from ast import literal_eval
- HAS_PYTHON26 = True
-except ImportError:
- HAS_PYTHON26 = False
-
-try:
- import libcloud
- from libcloud.compute.types import Provider
- from libcloud.compute.providers import get_driver
- from libcloud.common.google import GoogleBaseError, QuotaExceededError, \
- ResourceExistsError, ResourceInUseError, ResourceNotFoundError
- from libcloud.compute.drivers.gce import GCEAddress
- _ = Provider.GCE
- HAS_LIBCLOUD = True
-except ImportError:
- HAS_LIBCLOUD = False
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible_collections.community.google.plugins.module_utils.gce import gce_connect
-
-
-def _check_params(params, field_list):
- """
- Helper to validate params.
-
- Use this in function definitions if they require specific fields
- to be present.
-
- :param params: structure that contains the fields
- :type params: ``dict``
-
- :param field_list: list of dict representing the fields
- [{'name': str, 'required': True/False', 'type': cls}]
- :type field_list: ``list`` of ``dict``
-
- :return True, exits otherwise
- :rtype: ``bool``
- """
- for d in field_list:
- if not d['name'] in params:
- if d['required'] is True:
- return (False, "%s is required and must be of type: %s" %
- (d['name'], str(d['type'])))
- else:
- if not isinstance(params[d['name']], d['type']):
- return (False,
- "%s must be of type: %s" % (d['name'], str(d['type'])))
-
- return (True, '')
-
-
-def _validate_autoscaling_params(params):
- """
- Validate that the minimum configuration is present for autoscaling.
-
- :param params: Ansible dictionary containing autoscaling configuration
- It is expected that autoscaling config will be found at the
- key 'autoscaling'.
- :type params: ``dict``
-
- :return: Tuple containing a boolean and a string. True if autoscaler
- is valid, False otherwise, plus str for message.
- :rtype: ``(``bool``, ``str``)``
- """
- if not params['autoscaling']:
- # It's optional, so if not set at all, it's valid.
- return (True, '')
- if not isinstance(params['autoscaling'], dict):
- return (False,
- 'autoscaling: configuration expected to be a dictionary.')
-
- # check first-level required fields
- as_req_fields = [
- {'name': 'name', 'required': True, 'type': str},
- {'name': 'enabled', 'required': True, 'type': bool},
- {'name': 'policy', 'required': True, 'type': dict}
- ] # yapf: disable
-
- (as_req_valid, as_req_msg) = _check_params(params['autoscaling'],
- as_req_fields)
- if not as_req_valid:
- return (False, as_req_msg)
-
- # check policy configuration
- as_policy_fields = [
- {'name': 'max_instances', 'required': True, 'type': int},
- {'name': 'min_instances', 'required': False, 'type': int},
- {'name': 'cool_down_period', 'required': False, 'type': int}
- ] # yapf: disable
-
- (as_policy_valid, as_policy_msg) = _check_params(
- params['autoscaling']['policy'], as_policy_fields)
- if not as_policy_valid:
- return (False, as_policy_msg)
-
- # TODO(supertom): check utilization fields
-
- return (True, '')
-
-
-def _validate_named_port_params(params):
- """
- Validate the named ports parameters
-
- :param params: Ansible dictionary containing named_ports configuration
- It is expected that autoscaling config will be found at the
- key 'named_ports'. That key should contain a list of
- {name : port} dictionaries.
- :type params: ``dict``
-
- :return: Tuple containing a boolean and a string. True if params
- are valid, False otherwise, plus str for message.
- :rtype: ``(``bool``, ``str``)``
- """
- if not params['named_ports']:
- # It's optional, so if not set at all, it's valid.
- return (True, '')
- if not isinstance(params['named_ports'], list):
- return (False, 'named_ports: expected list of name:port dictionaries.')
- req_fields = [
- {'name': 'name', 'required': True, 'type': str},
- {'name': 'port', 'required': True, 'type': int}
- ] # yapf: disable
-
- for np in params['named_ports']:
- (valid_named_ports, np_msg) = _check_params(np, req_fields)
- if not valid_named_ports:
- return (False, np_msg)
-
- return (True, '')
-
-
-def _get_instance_list(mig, field='name', filter_list=None):
- """
- Helper to grab field from instances response.
-
- :param mig: Managed Instance Group Object from libcloud.
- :type mig: :class: `GCEInstanceGroupManager`
-
- :param field: Field name in list_managed_instances response. Defaults
- to 'name'.
- :type field: ``str``
-
- :param filter_list: list of 'currentAction' strings to filter on. Only
- items that match a currentAction in this list will
- be returned. Default is "['NONE']".
- :type filter_list: ``list`` of ``str``
-
- :return: List of strings from list_managed_instances response.
- :rtype: ``list``
- """
- filter_list = ['NONE'] if filter_list is None else filter_list
-
- return [x[field] for x in mig.list_managed_instances()
- if x['currentAction'] in filter_list]
-
-
-def _gen_gce_as_policy(as_params):
- """
- Take Autoscaler params and generate GCE-compatible policy.
-
- :param as_params: Dictionary in Ansible-playbook format
- containing policy arguments.
- :type as_params: ``dict``
-
- :return: GCE-compatible policy dictionary
- :rtype: ``dict``
- """
- asp_data = {}
- asp_data['maxNumReplicas'] = as_params['max_instances']
- if 'min_instances' in as_params:
- asp_data['minNumReplicas'] = as_params['min_instances']
- if 'cool_down_period' in as_params:
- asp_data['coolDownPeriodSec'] = as_params['cool_down_period']
- if 'cpu_utilization' in as_params and 'target' in as_params[
- 'cpu_utilization']:
- asp_data['cpuUtilization'] = {'utilizationTarget':
- as_params['cpu_utilization']['target']}
- if 'load_balancing_utilization' in as_params and 'target' in as_params[
- 'load_balancing_utilization']:
- asp_data['loadBalancingUtilization'] = {
- 'utilizationTarget':
- as_params['load_balancing_utilization']['target']
- }
-
- return asp_data
-
-
-def create_autoscaler(gce, mig, params):
- """
- Create a new Autoscaler for a MIG.
-
- :param gce: An initialized GCE driver object.
- :type gce: :class: `GCENodeDriver`
-
- :param mig: An initialized GCEInstanceGroupManager.
- :type mig: :class: `GCEInstanceGroupManager`
-
- :param params: Dictionary of autoscaling parameters.
- :type params: ``dict``
-
- :return: Tuple with changed stats.
- :rtype: tuple in the format of (bool, list)
- """
- changed = False
- as_policy = _gen_gce_as_policy(params['policy'])
- autoscaler = gce.ex_create_autoscaler(name=params['name'], zone=mig.zone,
- instance_group=mig, policy=as_policy)
- if autoscaler:
- changed = True
- return changed
-
-
-def update_autoscaler(gce, autoscaler, params):
- """
- Update an Autoscaler.
-
- Takes an existing Autoscaler object, and updates it with
- the supplied params before calling libcloud's update method.
-
- :param gce: An initialized GCE driver object.
- :type gce: :class: `GCENodeDriver`
-
- :param autoscaler: An initialized GCEAutoscaler.
- :type autoscaler: :class: `GCEAutoscaler`
-
- :param params: Dictionary of autoscaling parameters.
- :type params: ``dict``
-
- :return: True if changes, False otherwise.
- :rtype: ``bool``
- """
- as_policy = _gen_gce_as_policy(params['policy'])
- if autoscaler.policy != as_policy:
- autoscaler.policy = as_policy
- autoscaler = gce.ex_update_autoscaler(autoscaler)
- if autoscaler:
- return True
- return False
-
-
-def delete_autoscaler(autoscaler):
- """
- Delete an Autoscaler. Does not affect MIG.
-
- :param mig: Managed Instance Group Object from Libcloud.
- :type mig: :class: `GCEInstanceGroupManager`
-
- :return: Tuple with changed stats and a list of affected instances.
- :rtype: tuple in the format of (bool, list)
- """
- changed = False
- if autoscaler.destroy():
- changed = True
- return changed
-
-
-def get_autoscaler(gce, name, zone):
- """
- Get an Autoscaler from GCE.
-
- If the Autoscaler is not found, None is found.
-
- :param gce: An initialized GCE driver object.
- :type gce: :class: `GCENodeDriver`
-
- :param name: Name of the Autoscaler.
- :type name: ``str``
-
- :param zone: Zone that the Autoscaler is located in.
- :type zone: ``str``
-
- :return: A GCEAutoscaler object or None.
- :rtype: :class: `GCEAutoscaler` or None
- """
- try:
- # Does the Autoscaler already exist?
- return gce.ex_get_autoscaler(name, zone)
-
- except ResourceNotFoundError:
- return None
-
-
-def create_mig(gce, params):
- """
- Create a new Managed Instance Group.
-
- :param gce: An initialized GCE driver object.
- :type gce: :class: `GCENodeDriver`
-
- :param params: Dictionary of parameters needed by the module.
- :type params: ``dict``
-
- :return: Tuple with changed stats and a list of affected instances.
- :rtype: tuple in the format of (bool, list)
- """
-
- changed = False
- return_data = []
- actions_filter = ['CREATING']
-
- mig = gce.ex_create_instancegroupmanager(
- name=params['name'], size=params['size'], template=params['template'],
- zone=params['zone'])
-
- if mig:
- changed = True
- return_data = _get_instance_list(mig, filter_list=actions_filter)
-
- return (changed, return_data)
-
-
-def delete_mig(mig):
- """
- Delete a Managed Instance Group. All VMs in that MIG are also deleted."
-
- :param mig: Managed Instance Group Object from Libcloud.
- :type mig: :class: `GCEInstanceGroupManager`
-
- :return: Tuple with changed stats and a list of affected instances.
- :rtype: tuple in the format of (bool, list)
- """
- changed = False
- return_data = []
- actions_filter = ['NONE', 'CREATING', 'RECREATING', 'DELETING',
- 'ABANDONING', 'RESTARTING', 'REFRESHING']
- instance_names = _get_instance_list(mig, filter_list=actions_filter)
- if mig.destroy():
- changed = True
- return_data = instance_names
-
- return (changed, return_data)
-
-
-def recreate_instances_in_mig(mig):
- """
- Recreate the instances for a Managed Instance Group.
-
- :param mig: Managed Instance Group Object from libcloud.
- :type mig: :class: `GCEInstanceGroupManager`
-
- :return: Tuple with changed stats and a list of affected instances.
- :rtype: tuple in the format of (bool, list)
- """
- changed = False
- return_data = []
- actions_filter = ['RECREATING']
-
- if mig.recreate_instances():
- changed = True
- return_data = _get_instance_list(mig, filter_list=actions_filter)
-
- return (changed, return_data)
-
-
-def resize_mig(mig, size):
- """
- Resize a Managed Instance Group.
-
- Based on the size provided, GCE will automatically create and delete
- VMs as needed.
-
- :param mig: Managed Instance Group Object from libcloud.
- :type mig: :class: `GCEInstanceGroupManager`
-
- :return: Tuple with changed stats and a list of affected instances.
- :rtype: tuple in the format of (bool, list)
- """
- changed = False
- return_data = []
- actions_filter = ['CREATING', 'DELETING']
-
- if mig.resize(size):
- changed = True
- return_data = _get_instance_list(mig, filter_list=actions_filter)
-
- return (changed, return_data)
-
-
-def get_mig(gce, name, zone):
- """
- Get a Managed Instance Group from GCE.
-
- If the MIG is not found, None is found.
-
- :param gce: An initialized GCE driver object.
- :type gce: :class: `GCENodeDriver`
-
- :param name: Name of the Managed Instance Group.
- :type name: ``str``
-
- :param zone: Zone that the Managed Instance Group is located in.
- :type zone: ``str``
-
- :return: A GCEInstanceGroupManager object or None.
- :rtype: :class: `GCEInstanceGroupManager` or None
- """
- try:
- # Does the MIG already exist?
- return gce.ex_get_instancegroupmanager(name=name, zone=zone)
-
- except ResourceNotFoundError:
- return None
-
-
-def update_named_ports(mig, named_ports):
- """
- Set the named ports on a Managed Instance Group.
-
- Sort the existing named ports and new. If different, update.
- This also implicitly allows for the removal of named_por
-
- :param mig: Managed Instance Group Object from libcloud.
- :type mig: :class: `GCEInstanceGroupManager`
-
- :param named_ports: list of dictionaries in the format of {'name': port}
- :type named_ports: ``list`` of ``dict``
-
- :return: True if successful
- :rtype: ``bool``
- """
- changed = False
- existing_ports = []
- new_ports = []
- if hasattr(mig.instance_group, 'named_ports'):
- existing_ports = sorted(mig.instance_group.named_ports,
- key=lambda x: x['name'])
- if named_ports is not None:
- new_ports = sorted(named_ports, key=lambda x: x['name'])
-
- if existing_ports != new_ports:
- if mig.instance_group.set_named_ports(named_ports):
- changed = True
-
- return changed
-
-
-def main():
- module = AnsibleModule(argument_spec=dict(
- name=dict(required=True),
- template=dict(),
- recreate_instances=dict(type='bool', default=False),
- # Do not set a default size here. For Create and some update
- # operations, it is required and should be explicitly set.
- # Below, we set it to the existing value if it has not been set.
- size=dict(type='int'),
- state=dict(choices=['absent', 'present'], default='present'),
- zone=dict(required=True),
- autoscaling=dict(type='dict', default=None),
- named_ports=dict(type='list', default=None),
- service_account_email=dict(),
- service_account_permissions=dict(type='list'),
- pem_file=dict(type='path'),
- credentials_file=dict(type='path'),
- project_id=dict(), ), )
-
- if not HAS_PYTHON26:
- module.fail_json(
- msg="GCE module requires python's 'ast' module, python v2.6+")
- if not HAS_LIBCLOUD:
- module.fail_json(
- msg='libcloud with GCE Managed Instance Group support (1.2+) required for this module.')
-
- gce = gce_connect(module)
- if not hasattr(gce, 'ex_create_instancegroupmanager'):
- module.fail_json(
- msg='libcloud with GCE Managed Instance Group support (1.2+) required for this module.',
- changed=False)
-
- params = {}
- params['state'] = module.params.get('state')
- params['zone'] = module.params.get('zone')
- params['name'] = module.params.get('name')
- params['size'] = module.params.get('size')
- params['template'] = module.params.get('template')
- params['recreate_instances'] = module.params.get('recreate_instances')
- params['autoscaling'] = module.params.get('autoscaling', None)
- params['named_ports'] = module.params.get('named_ports', None)
-
- (valid_autoscaling, as_msg) = _validate_autoscaling_params(params)
- if not valid_autoscaling:
- module.fail_json(msg=as_msg, changed=False)
-
- if params['named_ports'] is not None and not hasattr(
- gce, 'ex_instancegroup_set_named_ports'):
- module.fail_json(
- msg="Apache Libcloud 1.3.0+ is required to use 'named_ports' option",
- changed=False)
-
- (valid_named_ports, np_msg) = _validate_named_port_params(params)
- if not valid_named_ports:
- module.fail_json(msg=np_msg, changed=False)
-
- changed = False
- json_output = {'state': params['state'], 'zone': params['zone']}
- mig = get_mig(gce, params['name'], params['zone'])
-
- if not mig:
- if params['state'] == 'absent':
- # Doesn't exist in GCE, and state==absent.
- changed = False
- module.fail_json(
- msg="Cannot delete unknown managed instance group: %s" %
- (params['name']))
- else:
- # Create MIG
- req_create_fields = [
- {'name': 'template', 'required': True, 'type': str},
- {'name': 'size', 'required': True, 'type': int}
- ] # yapf: disable
-
- (valid_create_fields, valid_create_msg) = _check_params(
- params, req_create_fields)
- if not valid_create_fields:
- module.fail_json(msg=valid_create_msg, changed=False)
-
- (changed, json_output['created_instances']) = create_mig(gce,
- params)
- if params['autoscaling'] and params['autoscaling'][
- 'enabled'] is True:
- # Fetch newly-created MIG and create Autoscaler for it.
- mig = get_mig(gce, params['name'], params['zone'])
- if not mig:
- module.fail_json(
- msg='Unable to fetch created MIG %s to create \
- autoscaler in zone: %s' % (
- params['name'], params['zone']), changed=False)
-
- if not create_autoscaler(gce, mig, params['autoscaling']):
- module.fail_json(
- msg='Unable to fetch MIG %s to create autoscaler \
- in zone: %s' % (params['name'], params['zone']),
- changed=False)
-
- json_output['created_autoscaler'] = True
- # Add named ports if available
- if params['named_ports']:
- mig = get_mig(gce, params['name'], params['zone'])
- if not mig:
- module.fail_json(
- msg='Unable to fetch created MIG %s to create \
- autoscaler in zone: %s' % (
- params['name'], params['zone']), changed=False)
- json_output['set_named_ports'] = update_named_ports(
- mig, params['named_ports'])
- if json_output['set_named_ports']:
- json_output['named_ports'] = params['named_ports']
-
- elif params['state'] == 'absent':
- # Delete MIG
-
- # First, check and remove the autoscaler, if present.
- # Note: multiple autoscalers can be associated to a single MIG. We
- # only handle the one that is named, but we might want to think about this.
- if params['autoscaling']:
- autoscaler = get_autoscaler(gce, params['autoscaling']['name'],
- params['zone'])
- if not autoscaler:
- module.fail_json(msg='Unable to fetch autoscaler %s to delete \
- in zone: %s' % (params['autoscaling']['name'], params['zone']),
- changed=False)
-
- changed = delete_autoscaler(autoscaler)
- json_output['deleted_autoscaler'] = changed
-
- # Now, delete the MIG.
- (changed, json_output['deleted_instances']) = delete_mig(mig)
-
- else:
- # Update MIG
-
- # If we're going to update a MIG, we need a size and template values.
- # If not specified, we use the values from the existing MIG.
- if not params['size']:
- params['size'] = mig.size
-
- if not params['template']:
- params['template'] = mig.template.name
-
- if params['template'] != mig.template.name:
- # Update Instance Template.
- new_template = gce.ex_get_instancetemplate(params['template'])
- mig.set_instancetemplate(new_template)
- json_output['updated_instancetemplate'] = True
- changed = True
- if params['recreate_instances'] is True:
- # Recreate Instances.
- (changed, json_output['recreated_instances']
- ) = recreate_instances_in_mig(mig)
-
- if params['size'] != mig.size:
- # Resize MIG.
- keystr = 'created' if params['size'] > mig.size else 'deleted'
- (changed, json_output['resize_%s_instances' %
- (keystr)]) = resize_mig(mig, params['size'])
-
- # Update Autoscaler
- if params['autoscaling']:
- autoscaler = get_autoscaler(gce, params['autoscaling']['name'],
- params['zone'])
- if not autoscaler:
- # Try to create autoscaler.
- # Note: this isn't perfect, if the autoscaler name has changed
- # we wouldn't know that here.
- if not create_autoscaler(gce, mig, params['autoscaling']):
- module.fail_json(
- msg='Unable to create autoscaler %s for existing MIG %s\
- in zone: %s' % (params['autoscaling']['name'],
- params['name'], params['zone']),
- changed=False)
- json_output['created_autoscaler'] = True
- changed = True
- else:
- if params['autoscaling']['enabled'] is False:
- # Delete autoscaler
- changed = delete_autoscaler(autoscaler)
- json_output['delete_autoscaler'] = changed
- else:
- # Update policy, etc.
- changed = update_autoscaler(gce, autoscaler,
- params['autoscaling'])
- json_output['updated_autoscaler'] = changed
- named_ports = params['named_ports'] or []
- json_output['updated_named_ports'] = update_named_ports(mig,
- named_ports)
- if json_output['updated_named_ports']:
- json_output['named_ports'] = named_ports
-
- json_output['changed'] = changed
- json_output.update(params)
- module.exit_json(**json_output)
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/google/plugins/modules/gce_net.py b/ansible_collections/community/google/plugins/modules/gce_net.py
deleted file mode 100644
index 48395f2a9..000000000
--- a/ansible_collections/community/google/plugins/modules/gce_net.py
+++ /dev/null
@@ -1,511 +0,0 @@
-#!/usr/bin/python
-# Copyright 2013 Google Inc.
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
----
-module: gce_net
-short_description: create/destroy GCE networks and firewall rules
-description:
- - This module can create and destroy Google Compute Engine networks and
- firewall rules U(https://cloud.google.com/compute/docs/networking).
- The I(name) parameter is reserved for referencing a network while the
- I(fwname) parameter is used to reference firewall rules.
- IPv4 Address ranges must be specified using the CIDR
- U(http://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing) format.
- Full install/configuration instructions for the gce* modules can
- be found in the comments of ansible/test/gce_tests.py.
-options:
- allowed:
- type: str
- description:
- - the protocol:ports to allow (I(tcp:80) or I(tcp:80,443) or I(tcp:80-800;udp:1-25))
- this parameter is mandatory when creating or updating a firewall rule
- ipv4_range:
- type: str
- description:
- - the IPv4 address range in CIDR notation for the network
- this parameter is not mandatory when you specified existing network in name parameter,
- but when you create new network, this parameter is mandatory
- fwname:
- type: str
- description:
- - name of the firewall rule
- name:
- type: str
- description:
- - name of the network
- src_range:
- type: list
- description:
- - the source IPv4 address range in CIDR notation
- default: []
- src_tags:
- type: list
- description:
- - the source instance tags for creating a firewall rule
- default: []
- target_tags:
- type: list
- description:
- - the target instance tags for creating a firewall rule
- default: []
- state:
- type: str
- description:
- - desired state of the network or firewall
- - "Available choices are: C(active), C(present), C(absent), C(deleted)."
- default: "present"
- service_account_email:
- type: str
- description:
- - service account email
- pem_file:
- type: path
- description:
- - path to the pem file associated with the service account email
- This option is deprecated. Use C(credentials_file).
- credentials_file:
- type: path
- description:
- - path to the JSON file associated with the service account email
- project_id:
- type: str
- description:
- - your GCE project ID
- mode:
- type: str
- description:
- - network mode for Google Cloud
- C(legacy) indicates a network with an IP address range;
- C(auto) automatically generates subnetworks in different regions;
- C(custom) uses networks to group subnets of user specified IP address ranges
- https://cloud.google.com/compute/docs/networking#network_types
- default: "legacy"
- choices: ["legacy", "auto", "custom"]
- subnet_name:
- type: str
- description:
- - name of subnet to create
- subnet_region:
- type: str
- description:
- - region of subnet to create
- subnet_desc:
- type: str
- description:
- - description of subnet to create
-
-requirements:
- - "python >= 2.6"
- - "apache-libcloud >= 0.13.3, >= 0.17.0 if using JSON credentials"
-author: "Eric Johnson (@erjohnso) <erjohnso@google.com>, Tom Melendez (@supertom) <supertom@google.com>"
-'''
-
-EXAMPLES = '''
-# Create a 'legacy' Network
-- name: Create Legacy Network
- community.google.gce_net:
- name: legacynet
- ipv4_range: '10.24.17.0/24'
- mode: legacy
- state: present
-
-# Create an 'auto' Network
-- name: Create Auto Network
- community.google.gce_net:
- name: autonet
- mode: auto
- state: present
-
-# Create a 'custom' Network
-- name: Create Custom Network
- community.google.gce_net:
- name: customnet
- mode: custom
- subnet_name: "customsubnet"
- subnet_region: us-east1
- ipv4_range: '10.240.16.0/24'
- state: "present"
-
-# Create Firewall Rule with Source Tags
-- name: Create Firewall Rule w/Source Tags
- community.google.gce_net:
- name: default
- fwname: "my-firewall-rule"
- allowed: tcp:80
- state: "present"
- src_tags: "foo,bar"
-
-# Create Firewall Rule with Source Range
-- name: Create Firewall Rule w/Source Range
- community.google.gce_net:
- name: default
- fwname: "my-firewall-rule"
- allowed: tcp:80
- state: "present"
- src_range: ['10.1.1.1/32']
-
-# Create Custom Subnetwork
-- name: Create Custom Subnetwork
- community.google.gce_net:
- name: privatenet
- mode: custom
- subnet_name: subnet_example
- subnet_region: us-central1
- ipv4_range: '10.0.0.0/16'
-'''
-
-RETURN = '''
-allowed:
- description: Rules (ports and protocols) specified by this firewall rule.
- returned: When specified
- type: str
- sample: "tcp:80;icmp"
-
-fwname:
- description: Name of the firewall rule.
- returned: When specified
- type: str
- sample: "my-fwname"
-
-ipv4_range:
- description: IPv4 range of the specified network or subnetwork.
- returned: when specified or when a subnetwork is created
- type: str
- sample: "10.0.0.0/16"
-
-name:
- description: Name of the network.
- returned: always
- type: str
- sample: "my-network"
-
-src_range:
- description: IP address blocks a firewall rule applies to.
- returned: when specified
- type: list
- sample: [ '10.1.1.12/8' ]
-
-src_tags:
- description: Instance Tags firewall rule applies to.
- returned: when specified while creating a firewall rule
- type: list
- sample: [ 'foo', 'bar' ]
-
-state:
- description: State of the item operated on.
- returned: always
- type: str
- sample: "present"
-
-subnet_name:
- description: Name of the subnetwork.
- returned: when specified or when a subnetwork is created
- type: str
- sample: "my-subnetwork"
-
-subnet_region:
- description: Region of the specified subnet.
- returned: when specified or when a subnetwork is created
- type: str
- sample: "us-east1"
-
-target_tags:
- description: Instance Tags with these tags receive traffic allowed by firewall rule.
- returned: when specified while creating a firewall rule
- type: list
- sample: [ 'foo', 'bar' ]
-'''
-try:
- from libcloud.compute.types import Provider
- from libcloud.compute.providers import get_driver
- from libcloud.common.google import GoogleBaseError, QuotaExceededError, ResourceExistsError, ResourceNotFoundError
- _ = Provider.GCE
- HAS_LIBCLOUD = True
-except ImportError:
- HAS_LIBCLOUD = False
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible_collections.community.google.plugins.module_utils.gce import gce_connect, unexpected_error_msg
-
-
-def format_allowed_section(allowed):
- """Format each section of the allowed list"""
- if allowed.count(":") == 0:
- protocol = allowed
- ports = []
- elif allowed.count(":") == 1:
- protocol, ports = allowed.split(":")
- else:
- return []
- if ports.count(","):
- ports = ports.split(",")
- elif ports:
- ports = [ports]
- return_val = {"IPProtocol": protocol}
- if ports:
- return_val["ports"] = ports
- return return_val
-
-
-def format_allowed(allowed):
- """Format the 'allowed' value so that it is GCE compatible."""
- return_value = []
- if allowed.count(";") == 0:
- return [format_allowed_section(allowed)]
- else:
- sections = allowed.split(";")
- for section in sections:
- return_value.append(format_allowed_section(section))
- return return_value
-
-
-def sorted_allowed_list(allowed_list):
- """Sort allowed_list (output of format_allowed) by protocol and port."""
- # sort by protocol
- allowed_by_protocol = sorted(allowed_list, key=lambda x: x['IPProtocol'])
- # sort the ports list
- return sorted(allowed_by_protocol, key=lambda y: sorted(y.get('ports', [])))
-
-
-def main():
- module = AnsibleModule(
- argument_spec=dict(
- allowed=dict(),
- ipv4_range=dict(),
- fwname=dict(),
- name=dict(),
- src_range=dict(default=[], type='list'),
- src_tags=dict(default=[], type='list'),
- target_tags=dict(default=[], type='list'),
- state=dict(default='present'),
- service_account_email=dict(),
- pem_file=dict(type='path'),
- credentials_file=dict(type='path'),
- project_id=dict(),
- mode=dict(default='legacy', choices=['legacy', 'auto', 'custom']),
- subnet_name=dict(),
- subnet_region=dict(),
- subnet_desc=dict(),
- )
- )
-
- if not HAS_LIBCLOUD:
- module.fail_json(msg='libcloud with GCE support (0.17.0+) required for this module')
-
- gce = gce_connect(module)
-
- allowed = module.params.get('allowed')
- ipv4_range = module.params.get('ipv4_range')
- fwname = module.params.get('fwname')
- name = module.params.get('name')
- src_range = module.params.get('src_range')
- src_tags = module.params.get('src_tags')
- target_tags = module.params.get('target_tags')
- state = module.params.get('state')
- mode = module.params.get('mode')
- subnet_name = module.params.get('subnet_name')
- subnet_region = module.params.get('subnet_region')
- subnet_desc = module.params.get('subnet_desc')
-
- changed = False
- json_output = {'state': state}
-
- if state in ['active', 'present']:
- network = None
- subnet = None
- try:
- network = gce.ex_get_network(name)
- json_output['name'] = name
- if mode == 'legacy':
- json_output['ipv4_range'] = network.cidr
- if network and mode == 'custom' and subnet_name:
- if not hasattr(gce, 'ex_get_subnetwork'):
- module.fail_json(msg="Update libcloud to a more recent version (>1.0) that supports network 'mode' parameter", changed=False)
-
- subnet = gce.ex_get_subnetwork(subnet_name, region=subnet_region)
- json_output['subnet_name'] = subnet_name
- json_output['ipv4_range'] = subnet.cidr
- except ResourceNotFoundError:
- pass
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
-
- # user wants to create a new network that doesn't yet exist
- if name and not network:
- if not ipv4_range and mode != 'auto':
- module.fail_json(msg="Network '" + name + "' is not found. To create network in legacy or custom mode, 'ipv4_range' parameter is required",
- changed=False)
- args = [ipv4_range if mode == 'legacy' else None]
- kwargs = {}
- if mode != 'legacy':
- kwargs['mode'] = mode
-
- try:
- network = gce.ex_create_network(name, *args, **kwargs)
- json_output['name'] = name
- json_output['ipv4_range'] = ipv4_range
- changed = True
- except TypeError:
- module.fail_json(msg="Update libcloud to a more recent version (>1.0) that supports network 'mode' parameter", changed=False)
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
-
- if (subnet_name or ipv4_range) and not subnet and mode == 'custom':
- if not hasattr(gce, 'ex_create_subnetwork'):
- module.fail_json(msg='Update libcloud to a more recent version (>1.0) that supports subnetwork creation', changed=changed)
- if not subnet_name or not ipv4_range or not subnet_region:
- module.fail_json(msg="subnet_name, ipv4_range, and subnet_region required for custom mode", changed=changed)
-
- try:
- subnet = gce.ex_create_subnetwork(subnet_name, cidr=ipv4_range, network=name, region=subnet_region, description=subnet_desc)
- json_output['subnet_name'] = subnet_name
- json_output['ipv4_range'] = ipv4_range
- changed = True
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=changed)
-
- if fwname:
- # user creating a firewall rule
- if not allowed and not src_range and not src_tags:
- if changed and network:
- module.fail_json(
- msg="Network created, but missing required " + "firewall rule parameter(s)", changed=True)
- module.fail_json(
- msg="Missing required firewall rule parameter(s)",
- changed=False)
-
- allowed_list = format_allowed(allowed)
-
- # Fetch existing rule and if it exists, compare attributes
- # update if attributes changed. Create if doesn't exist.
- try:
- fw_changed = False
- fw = gce.ex_get_firewall(fwname)
-
- # If old and new attributes are different, we update the firewall rule.
- # This implicitly lets us clear out attributes as well.
- # allowed_list is required and must not be None for firewall rules.
- if allowed_list and (sorted_allowed_list(allowed_list) != sorted_allowed_list(fw.allowed)):
- fw.allowed = allowed_list
- fw_changed = True
-
- # source_ranges might not be set in the project; cast it to an empty list
- fw.source_ranges = fw.source_ranges or []
-
- # If these attributes are lists, we sort them first, then compare.
- # Otherwise, we update if they differ.
- if fw.source_ranges != src_range:
- if isinstance(src_range, list):
- if sorted(fw.source_ranges) != sorted(src_range):
- fw.source_ranges = src_range
- fw_changed = True
- else:
- fw.source_ranges = src_range
- fw_changed = True
-
- # source_tags might not be set in the project; cast it to an empty list
- fw.source_tags = fw.source_tags or []
-
- if fw.source_tags != src_tags:
- if isinstance(src_tags, list):
- if sorted(fw.source_tags) != sorted(src_tags):
- fw.source_tags = src_tags
- fw_changed = True
- else:
- fw.source_tags = src_tags
- fw_changed = True
-
- # target_tags might not be set in the project; cast it to an empty list
- fw.target_tags = fw.target_tags or []
-
- if fw.target_tags != target_tags:
- if isinstance(target_tags, list):
- if sorted(fw.target_tags) != sorted(target_tags):
- fw.target_tags = target_tags
- fw_changed = True
- else:
- fw.target_tags = target_tags
- fw_changed = True
-
- if fw_changed is True:
- try:
- gce.ex_update_firewall(fw)
- changed = True
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
-
- # Firewall rule not found so we try to create it.
- except ResourceNotFoundError:
- try:
- gce.ex_create_firewall(fwname, allowed_list, network=name,
- source_ranges=src_range, source_tags=src_tags, target_tags=target_tags)
- changed = True
-
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
-
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
-
- json_output['fwname'] = fwname
- json_output['allowed'] = allowed
- json_output['src_range'] = src_range
- json_output['src_tags'] = src_tags
- json_output['target_tags'] = target_tags
-
- if state in ['absent', 'deleted']:
- if fwname:
- json_output['fwname'] = fwname
- fw = None
- try:
- fw = gce.ex_get_firewall(fwname)
- except ResourceNotFoundError:
- pass
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
- if fw:
- gce.ex_destroy_firewall(fw)
- changed = True
- elif subnet_name:
- if not hasattr(gce, 'ex_get_subnetwork') or not hasattr(gce, 'ex_destroy_subnetwork'):
- module.fail_json(msg='Update libcloud to a more recent version (>1.0) that supports subnetwork creation', changed=changed)
- json_output['name'] = subnet_name
- subnet = None
- try:
- subnet = gce.ex_get_subnetwork(subnet_name, region=subnet_region)
- except ResourceNotFoundError:
- pass
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
- if subnet:
- gce.ex_destroy_subnetwork(subnet)
- changed = True
- elif name:
- json_output['name'] = name
- network = None
- try:
- network = gce.ex_get_network(name)
-
- except ResourceNotFoundError:
- pass
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
- if network:
- try:
- gce.ex_destroy_network(network)
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
- changed = True
-
- json_output['changed'] = changed
- module.exit_json(**json_output)
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/google/plugins/modules/gce_pd.py b/ansible_collections/community/google/plugins/modules/gce_pd.py
deleted file mode 100644
index 0e3093d8b..000000000
--- a/ansible_collections/community/google/plugins/modules/gce_pd.py
+++ /dev/null
@@ -1,293 +0,0 @@
-#!/usr/bin/python
-# Copyright 2013 Google Inc.
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
----
-module: gce_pd
-short_description: utilize GCE persistent disk resources
-description:
- - This module can create and destroy unformatted GCE persistent disks
- U(https://developers.google.com/compute/docs/disks#persistentdisks).
- It also supports attaching and detaching disks from running instances.
- Full install/configuration instructions for the gce* modules can
- be found in the comments of ansible/test/gce_tests.py.
-options:
- detach_only:
- description:
- - do not destroy the disk, merely detach it from an instance
- type: bool
- instance_name:
- type: str
- description:
- - instance name if you wish to attach or detach the disk
- mode:
- type: str
- description:
- - GCE mount mode of disk, READ_ONLY (default) or READ_WRITE
- default: "READ_ONLY"
- choices: ["READ_WRITE", "READ_ONLY"]
- name:
- type: str
- description:
- - name of the disk
- required: true
- size_gb:
- type: str
- description:
- - whole integer size of disk (in GB) to create, default is 10 GB
- default: "10"
- image:
- type: str
- description:
- - the source image to use for the disk
- snapshot:
- type: str
- description:
- - the source snapshot to use for the disk
- state:
- type: str
- description:
- - desired state of the persistent disk
- - "Available choices are: C(active), C(present), C(absent), C(deleted)."
- default: "present"
- zone:
- type: str
- description:
- - zone in which to create the disk
- default: "us-central1-b"
- service_account_email:
- type: str
- description:
- - service account email
- pem_file:
- type: path
- description:
- - path to the pem file associated with the service account email
- This option is deprecated. Use 'credentials_file'.
- credentials_file:
- type: path
- description:
- - path to the JSON file associated with the service account email
- project_id:
- type: str
- description:
- - your GCE project ID
- disk_type:
- type: str
- description:
- - Specify a C(pd-standard) disk or C(pd-ssd) for an SSD disk.
- default: "pd-standard"
- delete_on_termination:
- description:
- - If C(yes), deletes the volume when instance is terminated
- type: bool
- image_family:
- type: str
- description:
- - The image family to use to create the instance.
- If I(image) has been used I(image_family) is ignored.
- Cannot specify both I(image) and I(source).
- external_projects:
- type: list
- description:
- - A list of other projects (accessible with the provisioning credentials)
- to be searched for the image.
-
-requirements:
- - "python >= 2.6"
- - "apache-libcloud >= 0.13.3, >= 0.17.0 if using JSON credentials"
-author: "Eric Johnson (@erjohnso) <erjohnso@google.com>"
-'''
-
-EXAMPLES = '''
-- name: Simple attachment action to an existing instance
- local_action:
- module: gce_pd
- instance_name: notlocalhost
- size_gb: 5
- name: pd
-'''
-
-try:
- from libcloud.compute.types import Provider
- from libcloud.compute.providers import get_driver
- from libcloud.common.google import GoogleBaseError, QuotaExceededError, ResourceExistsError, ResourceNotFoundError, ResourceInUseError
- _ = Provider.GCE
- HAS_LIBCLOUD = True
-except ImportError:
- HAS_LIBCLOUD = False
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible_collections.community.google.plugins.module_utils.gce import gce_connect, unexpected_error_msg
-
-
-def main():
- module = AnsibleModule(
- argument_spec=dict(
- delete_on_termination=dict(type='bool'),
- detach_only=dict(type='bool'),
- instance_name=dict(),
- mode=dict(default='READ_ONLY', choices=['READ_WRITE', 'READ_ONLY']),
- name=dict(required=True),
- size_gb=dict(default=10),
- disk_type=dict(default='pd-standard'),
- image=dict(),
- image_family=dict(),
- external_projects=dict(type='list'),
- snapshot=dict(),
- state=dict(default='present'),
- zone=dict(default='us-central1-b'),
- service_account_email=dict(),
- pem_file=dict(type='path'),
- credentials_file=dict(type='path'),
- project_id=dict(),
- )
- )
- if not HAS_LIBCLOUD:
- module.fail_json(msg='libcloud with GCE support (0.17.0+) is required for this module')
-
- gce = gce_connect(module)
-
- delete_on_termination = module.params.get('delete_on_termination')
- detach_only = module.params.get('detach_only')
- instance_name = module.params.get('instance_name')
- mode = module.params.get('mode')
- name = module.params.get('name')
- size_gb = module.params.get('size_gb')
- disk_type = module.params.get('disk_type')
- image = module.params.get('image')
- image_family = module.params.get('image_family')
- external_projects = module.params.get('external_projects')
- snapshot = module.params.get('snapshot')
- state = module.params.get('state')
- zone = module.params.get('zone')
-
- if delete_on_termination and not instance_name:
- module.fail_json(
- msg='Must specify an instance name when requesting delete on termination',
- changed=False)
-
- if detach_only and not instance_name:
- module.fail_json(
- msg='Must specify an instance name when detaching a disk',
- changed=False)
-
- disk = inst = None
- changed = is_attached = False
-
- json_output = {'name': name, 'zone': zone, 'state': state, 'disk_type': disk_type}
- if detach_only:
- json_output['detach_only'] = True
- json_output['detached_from_instance'] = instance_name
-
- if instance_name:
- # user wants to attach/detach from an existing instance
- try:
- inst = gce.ex_get_node(instance_name, zone)
- # is the disk attached?
- for d in inst.extra['disks']:
- if d['deviceName'] == name:
- is_attached = True
- json_output['attached_mode'] = d['mode']
- json_output['attached_to_instance'] = inst.name
- except Exception:
- pass
-
- # find disk if it already exists
- try:
- disk = gce.ex_get_volume(name)
- json_output['size_gb'] = int(disk.size)
- except ResourceNotFoundError:
- pass
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
-
- # user wants a disk to exist. If "instance_name" is supplied the user
- # also wants it attached
- if state in ['active', 'present']:
-
- if not size_gb:
- module.fail_json(msg="Must supply a size_gb", changed=False)
- try:
- size_gb = int(round(float(size_gb)))
- if size_gb < 1:
- raise Exception
- except Exception:
- module.fail_json(msg="Must supply a size_gb larger than 1 GB",
- changed=False)
-
- if instance_name and inst is None:
- module.fail_json(msg='Instance %s does not exist in zone %s' % (
- instance_name, zone), changed=False)
-
- if not disk:
- if image is not None and snapshot is not None:
- module.fail_json(
- msg='Cannot give both image (%s) and snapshot (%s)' % (
- image, snapshot), changed=False)
- lc_image = None
- lc_snapshot = None
- if image_family is not None:
- lc_image = gce.ex_get_image_from_family(image_family, ex_project_list=external_projects)
- elif image is not None:
- lc_image = gce.ex_get_image(image, ex_project_list=external_projects)
- elif snapshot is not None:
- lc_snapshot = gce.ex_get_snapshot(snapshot)
- try:
- disk = gce.create_volume(
- size_gb, name, location=zone, image=lc_image,
- snapshot=lc_snapshot, ex_disk_type=disk_type)
- except ResourceExistsError:
- pass
- except QuotaExceededError:
- module.fail_json(msg='Requested disk size exceeds quota',
- changed=False)
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
- json_output['size_gb'] = size_gb
- if image is not None:
- json_output['image'] = image
- if snapshot is not None:
- json_output['snapshot'] = snapshot
- changed = True
- if inst and not is_attached:
- try:
- gce.attach_volume(inst, disk, device=name, ex_mode=mode,
- ex_auto_delete=delete_on_termination)
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
- json_output['attached_to_instance'] = inst.name
- json_output['attached_mode'] = mode
- if delete_on_termination:
- json_output['delete_on_termination'] = True
- changed = True
-
- # user wants to delete a disk (or perhaps just detach it).
- if state in ['absent', 'deleted'] and disk:
-
- if inst and is_attached:
- try:
- gce.detach_volume(disk, ex_node=inst)
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
- changed = True
- if not detach_only:
- try:
- gce.destroy_volume(disk)
- except ResourceInUseError as e:
- module.fail_json(msg=str(e.value), changed=False)
- except Exception as e:
- module.fail_json(msg=unexpected_error_msg(e), changed=False)
- changed = True
-
- json_output['changed'] = changed
- module.exit_json(**json_output)
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/google/plugins/modules/gce_snapshot.py b/ansible_collections/community/google/plugins/modules/gce_snapshot.py
deleted file mode 100644
index 6723f4648..000000000
--- a/ansible_collections/community/google/plugins/modules/gce_snapshot.py
+++ /dev/null
@@ -1,225 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: Ansible Project
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
----
-module: gce_snapshot
-short_description: Create or destroy snapshots for GCE storage volumes
-description:
- - Manages snapshots for GCE instances. This module manages snapshots for
- the storage volumes of a GCE compute instance. If there are multiple
- volumes, each snapshot will be prepended with the disk name
-options:
- instance_name:
- type: str
- description:
- - The GCE instance to snapshot
- required: True
- snapshot_name:
- type: str
- description:
- - The name of the snapshot to manage
- required: True
- disks:
- type: list
- description:
- - A list of disks to create snapshots for. If none is provided,
- all of the volumes will have snapshots created.
- required: False
- state:
- type: str
- description:
- - Whether a snapshot should be C(present) or C(absent)
- required: false
- default: present
- choices: [present, absent]
- service_account_email:
- type: str
- description:
- - GCP service account email for the project where the instance resides
- credentials_file:
- type: path
- description:
- - The path to the credentials file associated with the service account
- project_id:
- type: str
- description:
- - The GCP project ID to use
-requirements:
- - "python >= 2.6"
- - "apache-libcloud >= 0.19.0"
-author: Rob Wagner (@robwagner33)
-'''
-
-EXAMPLES = '''
-- name: Create gce snapshot
- community.google.gce_snapshot:
- instance_name: example-instance
- snapshot_name: example-snapshot
- state: present
- service_account_email: project_name@appspot.gserviceaccount.com
- credentials_file: /path/to/credentials
- project_id: project_name
- delegate_to: localhost
-
-- name: Delete gce snapshot
- community.google.gce_snapshot:
- instance_name: example-instance
- snapshot_name: example-snapshot
- state: absent
- service_account_email: project_name@appspot.gserviceaccount.com
- credentials_file: /path/to/credentials
- project_id: project_name
- delegate_to: localhost
-
-# This example creates snapshots for only two of the available disks as
-# disk0-example-snapshot and disk1-example-snapshot
-- name: Create snapshots of specific disks
- community.google.gce_snapshot:
- instance_name: example-instance
- snapshot_name: example-snapshot
- state: present
- disks:
- - disk0
- - disk1
- service_account_email: project_name@appspot.gserviceaccount.com
- credentials_file: /path/to/credentials
- project_id: project_name
- delegate_to: localhost
-'''
-
-RETURN = '''
-snapshots_created:
- description: List of newly created snapshots
- returned: When snapshots are created
- type: list
- sample: "[disk0-example-snapshot, disk1-example-snapshot]"
-
-snapshots_deleted:
- description: List of destroyed snapshots
- returned: When snapshots are deleted
- type: list
- sample: "[disk0-example-snapshot, disk1-example-snapshot]"
-
-snapshots_existing:
- description: List of snapshots that already existed (no-op)
- returned: When snapshots were already present
- type: list
- sample: "[disk0-example-snapshot, disk1-example-snapshot]"
-
-snapshots_absent:
- description: List of snapshots that were already absent (no-op)
- returned: When snapshots were already absent
- type: list
- sample: "[disk0-example-snapshot, disk1-example-snapshot]"
-'''
-
-try:
- from libcloud.compute.types import Provider
- _ = Provider.GCE
- HAS_LIBCLOUD = True
-except ImportError:
- HAS_LIBCLOUD = False
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible_collections.community.google.plugins.module_utils.gce import gce_connect
-
-
-def find_snapshot(volume, name):
- '''
- Check if there is a snapshot already created with the given name for
- the passed in volume.
-
- Args:
- volume: A gce StorageVolume object to manage
- name: The name of the snapshot to look for
-
- Returns:
- The VolumeSnapshot object if one is found
- '''
- found_snapshot = None
- snapshots = volume.list_snapshots()
- for snapshot in snapshots:
- if name == snapshot.name:
- found_snapshot = snapshot
- return found_snapshot
-
-
-def main():
- module = AnsibleModule(
- argument_spec=dict(
- instance_name=dict(required=True),
- snapshot_name=dict(required=True),
- state=dict(choices=['present', 'absent'], default='present'),
- disks=dict(default=None, type='list'),
- service_account_email=dict(type='str'),
- credentials_file=dict(type='path'),
- project_id=dict(type='str')
- )
- )
-
- if not HAS_LIBCLOUD:
- module.fail_json(msg='libcloud with GCE support (0.19.0+) is required for this module')
-
- gce = gce_connect(module)
-
- instance_name = module.params.get('instance_name')
- snapshot_name = module.params.get('snapshot_name')
- disks = module.params.get('disks')
- state = module.params.get('state')
-
- json_output = dict(
- changed=False,
- snapshots_created=[],
- snapshots_deleted=[],
- snapshots_existing=[],
- snapshots_absent=[]
- )
-
- snapshot = None
-
- instance = gce.ex_get_node(instance_name, 'all')
- instance_disks = instance.extra['disks']
-
- for instance_disk in instance_disks:
- disk_snapshot_name = snapshot_name
- disk_info = gce._get_components_from_path(instance_disk['source'])
- device_name = disk_info['name']
- device_zone = disk_info['zone']
- if disks is None or device_name in disks:
- volume_obj = gce.ex_get_volume(device_name, device_zone)
-
- # If we have more than one disk to snapshot, prepend the disk name
- if len(instance_disks) > 1:
- disk_snapshot_name = device_name + "-" + disk_snapshot_name
-
- snapshot = find_snapshot(volume_obj, disk_snapshot_name)
-
- if snapshot and state == 'present':
- json_output['snapshots_existing'].append(disk_snapshot_name)
-
- elif snapshot and state == 'absent':
- snapshot.destroy()
- json_output['changed'] = True
- json_output['snapshots_deleted'].append(disk_snapshot_name)
-
- elif not snapshot and state == 'present':
- volume_obj.snapshot(disk_snapshot_name)
- json_output['changed'] = True
- json_output['snapshots_created'].append(disk_snapshot_name)
-
- elif not snapshot and state == 'absent':
- json_output['snapshots_absent'].append(disk_snapshot_name)
-
- module.exit_json(**json_output)
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/google/plugins/modules/gce_tag.py b/ansible_collections/community/google/plugins/modules/gce_tag.py
deleted file mode 100644
index 4af318632..000000000
--- a/ansible_collections/community/google/plugins/modules/gce_tag.py
+++ /dev/null
@@ -1,218 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# Copyright: (c) 2017, Ansible Project
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-DOCUMENTATION = '''
----
-module: gce_tag
-short_description: add or remove tag(s) to/from GCE instances
-description:
- - This module can add or remove tags U(https://cloud.google.com/compute/docs/label-or-tag-resources#tags)
- to/from GCE instances. Use 'instance_pattern' to update multiple instances in a specify zone.
-options:
- instance_name:
- type: str
- description:
- - The name of the GCE instance to add/remove tags.
- - Required if C(instance_pattern) is not specified.
- instance_pattern:
- type: str
- description:
- - The pattern of GCE instance names to match for adding/removing tags. Full-Python regex is supported.
- See U(https://docs.python.org/2/library/re.html) for details.
- - If C(instance_name) is not specified, this field is required.
- tags:
- type: list
- description:
- - Comma-separated list of tags to add or remove.
- required: yes
- state:
- type: str
- description:
- - Desired state of the tags.
- choices: [ absent, present ]
- default: present
- zone:
- type: str
- description:
- - The zone of the disk specified by source.
- default: us-central1-a
- service_account_email:
- type: str
- description:
- - Service account email.
- pem_file:
- type: path
- description:
- - Path to the PEM file associated with the service account email.
- project_id:
- type: str
- description:
- - Your GCE project ID.
-requirements:
- - python >= 2.6
- - apache-libcloud >= 0.17.0
-notes:
- - Either I(instance_name) or I(instance_pattern) is required.
-author:
- - Do Hoang Khiem (@dohoangkhiem) <(dohoangkhiem@gmail.com>
- - Tom Melendez (@supertom)
-'''
-
-EXAMPLES = '''
-- name: Add tags to instance
- community.google.gce_tag:
- instance_name: staging-server
- tags: http-server,https-server,staging
- zone: us-central1-a
- state: present
-
-- name: Remove tags from instance in default zone (us-central1-a)
- community.google.gce_tag:
- instance_name: test-server
- tags: foo,bar
- state: absent
-
-- name: Add tags to instances in zone that match pattern
- community.google.gce_tag:
- instance_pattern: test-server-*
- tags: foo,bar
- zone: us-central1-a
- state: present
-'''
-
-import re
-import traceback
-
-try:
- from libcloud.compute.types import Provider
- from libcloud.compute.providers import get_driver
- from libcloud.common.google import GoogleBaseError, QuotaExceededError, \
- ResourceExistsError, ResourceNotFoundError, InvalidRequestError
-
- _ = Provider.GCE
- HAS_LIBCLOUD = True
-except ImportError:
- HAS_LIBCLOUD = False
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible_collections.community.google.plugins.module_utils.gce import gce_connect
-
-
-def _union_items(baselist, comparelist):
- """Combine two lists, removing duplicates."""
- return list(set(baselist) | set(comparelist))
-
-
-def _intersect_items(baselist, comparelist):
- """Return matching items in both lists."""
- return list(set(baselist) & set(comparelist))
-
-
-def _get_changed_items(baselist, comparelist):
- """Return changed items as they relate to baselist."""
- return list(set(baselist) & set(set(baselist) ^ set(comparelist)))
-
-
-def modify_tags(gce, module, node, tags, state='present'):
- """Modify tags on an instance."""
-
- existing_tags = node.extra['tags']
- tags = [x.lower() for x in tags]
- tags_changed = []
-
- if state == 'absent':
- # tags changed are any that intersect
- tags_changed = _intersect_items(existing_tags, tags)
- if not tags_changed:
- return False, None
- # update instance with tags in existing tags that weren't specified
- node_tags = _get_changed_items(existing_tags, tags)
- else:
- # tags changed are any that in the new list that weren't in existing
- tags_changed = _get_changed_items(tags, existing_tags)
- if not tags_changed:
- return False, None
- # update instance with the combined list
- node_tags = _union_items(existing_tags, tags)
-
- try:
- gce.ex_set_node_tags(node, node_tags)
- return True, tags_changed
- except (GoogleBaseError, InvalidRequestError) as e:
- module.fail_json(msg=str(e), changed=False)
-
-
-def main():
- module = AnsibleModule(
- argument_spec=dict(
- instance_name=dict(type='str'),
- instance_pattern=dict(type='str'),
- tags=dict(type='list', required=True),
- state=dict(type='str', default='present', choices=['absent', 'present']),
- zone=dict(type='str', default='us-central1-a'),
- service_account_email=dict(type='str'),
- pem_file=dict(type='path'),
- project_id=dict(type='str'),
- ),
- mutually_exclusive=[
- ['instance_name', 'instance_pattern']
- ],
- required_one_of=[
- ['instance_name', 'instance_pattern']
- ],
- )
-
- instance_name = module.params.get('instance_name')
- instance_pattern = module.params.get('instance_pattern')
- state = module.params.get('state')
- tags = module.params.get('tags')
- zone = module.params.get('zone')
- changed = False
-
- if not HAS_LIBCLOUD:
- module.fail_json(msg='libcloud with GCE support (0.17.0+) required for this module')
-
- gce = gce_connect(module)
-
- # Create list of nodes to operate on
- matching_nodes = []
- try:
- if instance_pattern:
- instances = gce.list_nodes(ex_zone=zone)
- # no instances in zone
- if not instances:
- module.exit_json(changed=False, tags=tags, zone=zone, instances_updated=[])
- try:
- # Python regex fully supported: https://docs.python.org/2/library/re.html
- p = re.compile(instance_pattern)
- matching_nodes = [i for i in instances if p.search(i.name) is not None]
- except re.error as e:
- module.fail_json(msg='Regex error for pattern %s: %s' % (instance_pattern, e), changed=False)
- else:
- matching_nodes = [gce.ex_get_node(instance_name, zone=zone)]
- except ResourceNotFoundError:
- module.fail_json(msg='Instance %s not found in zone %s' % (instance_name, zone), changed=False)
- except GoogleBaseError as e:
- module.fail_json(msg=str(e), changed=False, exception=traceback.format_exc())
-
- # Tag nodes
- instance_pattern_matches = []
- tags_changed = []
- for node in matching_nodes:
- changed, tags_changed = modify_tags(gce, module, node, tags, state)
- if changed:
- instance_pattern_matches.append({'instance_name': node.name, 'tags_changed': tags_changed})
- if instance_pattern:
- module.exit_json(changed=changed, instance_pattern=instance_pattern, tags=tags_changed, zone=zone, instances_updated=instance_pattern_matches)
- else:
- module.exit_json(changed=changed, instance_name=instance_name, tags=tags_changed, zone=zone)
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/google/plugins/modules/gcpubsub.py b/ansible_collections/community/google/plugins/modules/gcpubsub.py
deleted file mode 100644
index 2d9230c8f..000000000
--- a/ansible_collections/community/google/plugins/modules/gcpubsub.py
+++ /dev/null
@@ -1,349 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# Copyright: (c) 2016, Google Inc.
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-DOCUMENTATION = '''
----
-module: gcpubsub
-short_description: Create and Delete Topics/Subscriptions, Publish and pull messages on PubSub
-description:
- - Create and Delete Topics/Subscriptions, Publish and pull messages on PubSub.
- See U(https://cloud.google.com/pubsub/docs) for an overview.
-requirements:
- - google-auth >= 0.5.0
- - google-cloud-pubsub >= 0.22.0
-notes:
- - Subscription pull happens before publish. You cannot publish and pull in the same task.
-author:
- - Tom Melendez (@supertom) <tom@supertom.com>
-options:
- topic:
- type: str
- description:
- - GCP pubsub topic name.
- - Only the name, not the full path, is required.
- required: yes
- subscription:
- type: dict
- description:
- - Dictionary containing a subscription name associated with a topic (required), along with optional ack_deadline, push_endpoint and pull.
- For pulling from a subscription, message_ack (bool), max_messages (int) and return_immediate are available as subfields.
- See subfields name, push_endpoint and ack_deadline for more information.
- suboptions:
- name:
- description:
- - Subfield of subscription. Required if subscription is specified. See examples.
- ack_deadline:
- description:
- - Subfield of subscription. Not required. Default deadline for subscriptions to ACK the message before it is resent. See examples.
- pull:
- description:
- - Subfield of subscription. Not required. If specified, messages will be retrieved from topic via the
- provided subscription name. max_messages (int; default None; max number of messages to pull),
- message_ack (bool; default False; acknowledge the message) and return_immediately
- (bool; default True, don't wait for messages to appear). If the messages are acknowledged,
- changed is set to True, otherwise, changed is False.
- push_endpoint:
- description:
- - Subfield of subscription. Not required. If specified, message will be sent to an endpoint.
- See U(https://cloud.google.com/pubsub/docs/advanced#push_endpoints) for more information.
- publish:
- type: list
- description:
- - List of dictionaries describing messages and attributes to be published. Dictionary is in message(str):attributes(dict) format.
- Only message is required.
- state:
- type: str
- description:
- - State of the topic or queue.
- - Applies to the most granular resource.
- - If subscription isspecified we remove it.
- - If only topic is specified, that is what is removed.
- - NOTE - A topic can be removed without first removing the subscription.
- choices: [ absent, present ]
- default: present
- project_id:
- type: str
- description:
- - your GCE project ID
- credentials_file:
- type: str
- description:
- - path to the JSON file associated with the service account email
- service_account_email:
- type: str
- description:
- - service account email
-'''
-
-EXAMPLES = '''
-# (Message will be pushed; there is no check to see if the message was pushed before
-- name: Create a topic and publish a message to it
- community.google.gcpubsub:
- topic: ansible-topic-example
- state: present
-
-# Subscriptions associated with topic are not deleted.
-- name: Delete Topic
- community.google.gcpubsub:
- topic: ansible-topic-example
- state: absent
-
-# Setting absent will keep the messages from being sent
-- name: Publish multiple messages, with attributes (key:value available with the message)
- community.google.gcpubsub:
- topic: '{{ topic_name }}'
- state: present
- publish:
- - message: this is message 1
- attributes:
- mykey1: myvalue
- mykey2: myvalu2
- mykey3: myvalue3
- - message: this is message 2
- attributes:
- server: prod
- sla: "99.9999"
- owner: fred
-
-- name: Create Subscription (pull)
- community.google.gcpubsub:
- topic: ansible-topic-example
- subscription:
- - name: mysub
- state: present
-
-# pull is default, ack_deadline is not required
-- name: Create Subscription with ack_deadline and push endpoint
- community.google.gcpubsub:
- topic: ansible-topic-example
- subscription:
- - name: mysub
- ack_deadline: "60"
- push_endpoint: http://pushendpoint.example.com
- state: present
-
-# Setting push_endpoint to "None" converts subscription to pull.
-- name: Subscription change from push to pull
- community.google.gcpubsub:
- topic: ansible-topic-example
- subscription:
- name: mysub
- push_endpoint: "None"
-
-### Topic will not be deleted
-- name: Delete subscription
- community.google.gcpubsub:
- topic: ansible-topic-example
- subscription:
- - name: mysub
- state: absent
-
-# only pull keyword is required.
-- name: Pull messages from subscription
- community.google.gcpubsub:
- topic: ansible-topic-example
- subscription:
- name: ansible-topic-example-sub
- pull:
- message_ack: yes
- max_messages: "100"
-'''
-
-RETURN = '''
-publish:
- description: List of dictionaries describing messages and attributes to be published. Dictionary is in message(str):attributes(dict) format.
- Only message is required.
- returned: Only when specified
- type: list
- sample: "publish: ['message': 'my message', attributes: {'key1': 'value1'}]"
-
-pulled_messages:
- description: list of dictionaries containing message info. Fields are ack_id, attributes, data, message_id.
- returned: Only when subscription.pull is specified
- type: list
- sample: [{ "ack_id": "XkASTCcYREl...","attributes": {"key1": "val1",...}, "data": "this is message 1", "message_id": "49107464153705"},..]
-
-state:
- description: The state of the topic or subscription. Value will be either 'absent' or 'present'.
- returned: Always
- type: str
- sample: "present"
-
-subscription:
- description: Name of subscription.
- returned: When subscription fields are specified
- type: str
- sample: "mysubscription"
-
-topic:
- description: Name of topic.
- returned: Always
- type: str
- sample: "mytopic"
-'''
-
-try:
- from ast import literal_eval
- HAS_PYTHON26 = True
-except ImportError:
- HAS_PYTHON26 = False
-
-try:
- from google.cloud import pubsub
- HAS_GOOGLE_CLOUD_PUBSUB = True
-except ImportError as e:
- HAS_GOOGLE_CLOUD_PUBSUB = False
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible_collections.community.google.plugins.module_utils.gcp import check_min_pkg_version, get_google_cloud_credentials
-
-
-CLOUD_CLIENT = 'google-cloud-pubsub'
-CLOUD_CLIENT_MINIMUM_VERSION = '0.22.0'
-CLOUD_CLIENT_USER_AGENT = 'ansible-pubsub-0.1'
-
-
-def publish_messages(message_list, topic):
- with topic.batch() as batch:
- for message in message_list:
- msg = message['message']
- attrs = {}
- if 'attributes' in message:
- attrs = message['attributes']
- batch.publish(bytes(msg), **attrs)
- return True
-
-
-def pull_messages(pull_params, sub):
- """
- :rtype: tuple (output, changed)
- """
- changed = False
- max_messages = pull_params.get('max_messages', None)
- message_ack = pull_params.get('message_ack', 'no')
- return_immediately = pull_params.get('return_immediately', False)
-
- output = []
- pulled = sub.pull(return_immediately=return_immediately, max_messages=max_messages)
-
- for ack_id, msg in pulled:
- msg_dict = {'message_id': msg.message_id,
- 'attributes': msg.attributes,
- 'data': msg.data,
- 'ack_id': ack_id}
- output.append(msg_dict)
-
- if message_ack:
- ack_ids = [m['ack_id'] for m in output]
- if ack_ids:
- sub.acknowledge(ack_ids)
- changed = True
- return (output, changed)
-
-
-def main():
-
- module = AnsibleModule(
- argument_spec=dict(
- topic=dict(type='str', required=True),
- state=dict(type='str', default='present', choices=['absent', 'present']),
- publish=dict(type='list'),
- subscription=dict(type='dict'),
- service_account_email=dict(type='str'),
- credentials_file=dict(type='str'),
- project_id=dict(type='str'),
- ),
- )
-
- if not HAS_PYTHON26:
- module.fail_json(
- msg="GCE module requires python's 'ast' module, python v2.6+")
-
- if not HAS_GOOGLE_CLOUD_PUBSUB:
- module.fail_json(msg="Please install google-cloud-pubsub library.")
-
- if not check_min_pkg_version(CLOUD_CLIENT, CLOUD_CLIENT_MINIMUM_VERSION):
- module.fail_json(msg="Please install %s client version %s" % (CLOUD_CLIENT, CLOUD_CLIENT_MINIMUM_VERSION))
-
- mod_params = {}
- mod_params['publish'] = module.params.get('publish')
- mod_params['state'] = module.params.get('state')
- mod_params['topic'] = module.params.get('topic')
- mod_params['subscription'] = module.params.get('subscription')
-
- creds, params = get_google_cloud_credentials(module)
- pubsub_client = pubsub.Client(project=params['project_id'], credentials=creds, use_gax=False)
- pubsub_client.user_agent = CLOUD_CLIENT_USER_AGENT
-
- changed = False
- json_output = {}
-
- t = None
- if mod_params['topic']:
- t = pubsub_client.topic(mod_params['topic'])
- s = None
- if mod_params['subscription']:
- # Note: default ack deadline cannot be changed without deleting/recreating subscription
- s = t.subscription(mod_params['subscription']['name'],
- ack_deadline=mod_params['subscription'].get('ack_deadline', None),
- push_endpoint=mod_params['subscription'].get('push_endpoint', None))
-
- if mod_params['state'] == 'absent':
- # Remove the most granular resource. If subscription is specified
- # we remove it. If only topic is specified, that is what is removed.
- # Note that a topic can be removed without first removing the subscription.
- # TODO(supertom): Enhancement: Provide an option to only delete a topic
- # if there are no subscriptions associated with it (which the API does not support).
- if s is not None:
- if s.exists():
- s.delete()
- changed = True
- else:
- if t.exists():
- t.delete()
- changed = True
- elif mod_params['state'] == 'present':
- if not t.exists():
- t.create()
- changed = True
- if s:
- if not s.exists():
- s.create()
- s.reload()
- changed = True
- else:
- # Subscription operations
- # TODO(supertom): if more 'update' operations arise, turn this into a function.
- s.reload()
- push_endpoint = mod_params['subscription'].get('push_endpoint', None)
- if push_endpoint is not None:
- if push_endpoint != s.push_endpoint:
- if push_endpoint == 'None':
- push_endpoint = None
- s.modify_push_configuration(push_endpoint=push_endpoint)
- s.reload()
- changed = push_endpoint == s.push_endpoint
-
- if 'pull' in mod_params['subscription']:
- if s.push_endpoint is not None:
- module.fail_json(msg="Cannot pull messages, push_endpoint is configured.")
- (json_output['pulled_messages'], changed) = pull_messages(
- mod_params['subscription']['pull'], s)
-
- # publish messages to the topic
- if mod_params['publish'] and len(mod_params['publish']) > 0:
- changed = publish_messages(mod_params['publish'], t)
-
- json_output['changed'] = changed
- json_output.update(mod_params)
- module.exit_json(**json_output)
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/google/plugins/modules/gcpubsub_info.py b/ansible_collections/community/google/plugins/modules/gcpubsub_info.py
deleted file mode 100644
index 1feac1e03..000000000
--- a/ansible_collections/community/google/plugins/modules/gcpubsub_info.py
+++ /dev/null
@@ -1,164 +0,0 @@
-#!/usr/bin/python
-# Copyright 2016 Google Inc.
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
----
-module: gcpubsub_info
-short_description: List Topics/Subscriptions and Messages from Google PubSub.
-description:
- - List Topics/Subscriptions from Google PubSub. Use the gcpubsub module for
- topic/subscription management.
- See U(https://cloud.google.com/pubsub/docs) for an overview.
- - This module was called C(gcpubsub_facts) before Ansible 2.9. The usage did not change.
-requirements:
- - "python >= 2.6"
- - "google-auth >= 0.5.0"
- - "google-cloud-pubsub >= 0.22.0"
-notes:
- - list state enables user to list topics or subscriptions in the project. See examples for details.
-author:
- - "Tom Melendez (@supertom) <tom@supertom.com>"
-options:
- topic:
- type: str
- description:
- - GCP pubsub topic name. Only the name, not the full path, is required.
- required: False
- view:
- type: str
- description:
- - Choices are 'topics' or 'subscriptions'
- choices: [topics, subscriptions]
- default: topics
- state:
- type: str
- description:
- - list is the only valid option.
- required: False
- choices: [list]
- default: list
- project_id:
- type: str
- description:
- - your GCE project ID
- credentials_file:
- type: str
- description:
- - path to the JSON file associated with the service account email
- service_account_email:
- type: str
- description:
- - service account email
-'''
-
-EXAMPLES = '''
-- name: List all Topics in a project
- community.google.gcpubsub_info:
- view: topics
- state: list
-
-- name: List all Subscriptions in a project
- community.google.gcpubsub_info:
- view: subscriptions
- state: list
-
-- name: List all Subscriptions for a Topic in a project
- community.google.gcpubsub_info:
- view: subscriptions
- topic: my-topic
- state: list
-'''
-
-RETURN = '''
-subscriptions:
- description: List of subscriptions.
- returned: When view is set to subscriptions.
- type: list
- sample: ["mysubscription", "mysubscription2"]
-topic:
- description: Name of topic. Used to filter subscriptions.
- returned: Always
- type: str
- sample: "mytopic"
-topics:
- description: List of topics.
- returned: When view is set to topics.
- type: list
- sample: ["mytopic", "mytopic2"]
-'''
-
-try:
- from ast import literal_eval
- HAS_PYTHON26 = True
-except ImportError:
- HAS_PYTHON26 = False
-
-try:
- from google.cloud import pubsub
- HAS_GOOGLE_CLOUD_PUBSUB = True
-except ImportError as e:
- HAS_GOOGLE_CLOUD_PUBSUB = False
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible_collections.community.google.plugins.module_utils.gcp import check_min_pkg_version, get_google_cloud_credentials
-
-
-def list_func(data, member='name'):
- """Used for state=list."""
- return [getattr(x, member) for x in data]
-
-
-def main():
- module = AnsibleModule(argument_spec=dict(
- view=dict(choices=['topics', 'subscriptions'], default='topics'),
- topic=dict(required=False),
- state=dict(choices=['list'], default='list'),
- service_account_email=dict(),
- credentials_file=dict(),
- project_id=dict(), ),)
- if module._name in ('gcpubsub_facts', 'community.google.gcpubsub_facts'):
- module.deprecate("The 'gcpubsub_facts' module has been renamed to 'gcpubsub_info'",
- version='3.0.0', collection_name='community.google') # was Ansible 2.13
-
- if not HAS_PYTHON26:
- module.fail_json(
- msg="GCE module requires python's 'ast' module, python v2.6+")
-
- if not HAS_GOOGLE_CLOUD_PUBSUB:
- module.fail_json(msg="Please install google-cloud-pubsub library.")
-
- CLIENT_MINIMUM_VERSION = '0.22.0'
- if not check_min_pkg_version('google-cloud-pubsub', CLIENT_MINIMUM_VERSION):
- module.fail_json(msg="Please install google-cloud-pubsub library version %s" % CLIENT_MINIMUM_VERSION)
-
- mod_params = {}
- mod_params['state'] = module.params.get('state')
- mod_params['topic'] = module.params.get('topic')
- mod_params['view'] = module.params.get('view')
-
- creds, params = get_google_cloud_credentials(module)
- pubsub_client = pubsub.Client(project=params['project_id'], credentials=creds, use_gax=False)
- pubsub_client.user_agent = 'ansible-pubsub-0.1'
-
- json_output = {}
- if mod_params['view'] == 'topics':
- json_output['topics'] = list_func(pubsub_client.list_topics())
- elif mod_params['view'] == 'subscriptions':
- if mod_params['topic']:
- t = pubsub_client.topic(mod_params['topic'])
- json_output['subscriptions'] = list_func(t.list_subscriptions())
- else:
- json_output['subscriptions'] = list_func(pubsub_client.list_subscriptions())
-
- json_output['changed'] = False
- json_output.update(mod_params)
- module.exit_json(**json_output)
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/google/scripts/inventory/gce.ini b/ansible_collections/community/google/scripts/inventory/gce.ini
deleted file mode 100644
index af27a9c4a..000000000
--- a/ansible_collections/community/google/scripts/inventory/gce.ini
+++ /dev/null
@@ -1,76 +0,0 @@
-# Copyright 2013 Google Inc.
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-
-# The GCE inventory script has the following dependencies:
-# 1. A valid Google Cloud Platform account with Google Compute Engine
-# enabled. See https://cloud.google.com
-# 2. An OAuth2 Service Account flow should be enabled. This will generate
-# a private key file that the inventory script will use for API request
-# authorization. See https://developers.google.com/accounts/docs/OAuth2
-# 3. Convert the private key from PKCS12 to PEM format
-# $ openssl pkcs12 -in pkey.pkcs12 -passin pass:notasecret \
-# > -nodes -nocerts | openssl rsa -out pkey.pem
-# 4. The libcloud (>=0.13.3) python libray. See http://libcloud.apache.org
-#
-# (See ansible/test/gce_tests.py comments for full install instructions)
-#
-# Author: Eric Johnson <erjohnso@google.com>
-# Contributors: John Roach <johnroach1985@gmail.com>
-
-[gce]
-# GCE Service Account configuration information can be stored in the
-# libcloud 'secrets.py' file. Ideally, the 'secrets.py' file will already
-# exist in your PYTHONPATH and be picked up automatically with an import
-# statement in the inventory script. However, you can specify an absolute
-# path to the secrets.py file with 'libcloud_secrets' parameter.
-# This option will be deprecated in a future release.
-libcloud_secrets =
-
-# If you are not going to use a 'secrets.py' file, you can set the necessary
-# authorization parameters here.
-# You can add multiple gce projects to by using a comma separated list. Make
-# sure that the service account used has permissions on said projects.
-gce_service_account_email_address =
-gce_service_account_pem_file_path =
-gce_project_id =
-gce_zone =
-
-# Filter inventory based on state. Leave undefined to return instances regardless of state.
-# example: Uncomment to only return inventory in the running or provisioning state
-#instance_states = RUNNING,PROVISIONING
-
-# Filter inventory based on instance tags. Leave undefined to return instances regardless of tags.
-# example: Uncomment to only return inventory with the http-server or https-server tag
-#instance_tags = http-server,https-server
-
-
-[inventory]
-# The 'inventory_ip_type' parameter specifies whether 'ansible_ssh_host' should
-# contain the instance internal or external address. Values may be either
-# 'internal' or 'external'. If 'external' is specified but no external instance
-# address exists, the internal address will be used.
-# The INVENTORY_IP_TYPE environment variable will override this value.
-inventory_ip_type =
-
-[cache]
-# directory in which cache should be created
-cache_path = ~/.ansible/tmp
-
-# The number of seconds a cache file is considered valid. After this many
-# seconds, a new API call will be made, and the cache file will be updated.
-# To disable the cache, set this value to 0
-cache_max_age = 300
diff --git a/ansible_collections/community/google/scripts/inventory/gce.py b/ansible_collections/community/google/scripts/inventory/gce.py
deleted file mode 100644
index 05a93f483..000000000
--- a/ansible_collections/community/google/scripts/inventory/gce.py
+++ /dev/null
@@ -1,524 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright: (c) 2013, Google Inc.
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-'''
-GCE external inventory script
-=================================
-
-Generates inventory that Ansible can understand by making API requests
-Google Compute Engine via the libcloud library. Full install/configuration
-instructions for the gce* modules can be found in the comments of
-ansible/test/gce_tests.py.
-
-When run against a specific host, this script returns the following variables
-based on the data obtained from the libcloud Node object:
- - gce_uuid
- - gce_id
- - gce_image
- - gce_machine_type
- - gce_private_ip
- - gce_public_ip
- - gce_name
- - gce_description
- - gce_status
- - gce_zone
- - gce_tags
- - gce_metadata
- - gce_network
- - gce_subnetwork
-
-When run in --list mode, instances are grouped by the following categories:
- - zone:
- zone group name examples are us-central1-b, europe-west1-a, etc.
- - instance tags:
- An entry is created for each tag. For example, if you have two instances
- with a common tag called 'foo', they will both be grouped together under
- the 'tag_foo' name.
- - network name:
- the name of the network is appended to 'network_' (e.g. the 'default'
- network will result in a group named 'network_default')
- - machine type
- types follow a pattern like n1-standard-4, g1-small, etc.
- - running status:
- group name prefixed with 'status_' (e.g. status_running, status_stopped,..)
- - image:
- when using an ephemeral/scratch disk, this will be set to the image name
- used when creating the instance (e.g. debian-7-wheezy-v20130816). when
- your instance was created with a root persistent disk it will be set to
- 'persistent_disk' since there is no current way to determine the image.
-
-Examples:
- Execute uname on all instances in the us-central1-a zone
- $ ansible -i gce.py us-central1-a -m shell -a "/bin/uname -a"
-
- Use the GCE inventory script to print out instance specific information
- $ contrib/inventory/gce.py --host my_instance
-
-Author: Eric Johnson <erjohnso@google.com>
-Contributors: Matt Hite <mhite@hotmail.com>, Tom Melendez <supertom@google.com>,
- John Roach <johnroach1985@gmail.com>
-Version: 0.0.4
-'''
-
-try:
- import pkg_resources
-except ImportError:
- # Use pkg_resources to find the correct versions of libraries and set
- # sys.path appropriately when there are multiversion installs. We don't
- # fail here as there is code that better expresses the errors where the
- # library is used.
- pass
-
-USER_AGENT_PRODUCT = "Ansible-gce_inventory_plugin"
-USER_AGENT_VERSION = "v2"
-
-import sys
-import os
-import argparse
-
-from time import time
-
-from ansible.module_utils.six.moves import configparser
-
-import logging
-logging.getLogger('libcloud.common.google').addHandler(logging.NullHandler())
-
-import json
-
-try:
- from libcloud.compute.types import Provider
- from libcloud.compute.providers import get_driver
- _ = Provider.GCE
-except Exception:
- sys.exit("GCE inventory script requires libcloud >= 0.13")
-
-
-class CloudInventoryCache(object):
- def __init__(self, cache_name='ansible-cloud-cache', cache_path='/tmp',
- cache_max_age=300):
- cache_dir = os.path.expanduser(cache_path)
- if not os.path.exists(cache_dir):
- os.makedirs(cache_dir)
- self.cache_path_cache = os.path.join(cache_dir, cache_name)
-
- self.cache_max_age = cache_max_age
-
- def is_valid(self, max_age=None):
- ''' Determines if the cache files have expired, or if it is still valid '''
-
- if max_age is None:
- max_age = self.cache_max_age
-
- if os.path.isfile(self.cache_path_cache):
- mod_time = os.path.getmtime(self.cache_path_cache)
- current_time = time()
- if (mod_time + max_age) > current_time:
- return True
-
- return False
-
- def get_all_data_from_cache(self, filename=''):
- ''' Reads the JSON inventory from the cache file. Returns Python dictionary. '''
-
- data = ''
- if not filename:
- filename = self.cache_path_cache
- with open(filename, 'r') as cache:
- data = cache.read()
- return json.loads(data)
-
- def write_to_cache(self, data, filename=''):
- ''' Writes data to file as JSON. Returns True. '''
- if not filename:
- filename = self.cache_path_cache
- json_data = json.dumps(data)
- with open(filename, 'w') as cache:
- cache.write(json_data)
- return True
-
-
-class GceInventory(object):
- def __init__(self):
- # Cache object
- self.cache = None
- # dictionary containing inventory read from disk
- self.inventory = {}
-
- # Read settings and parse CLI arguments
- self.parse_cli_args()
- self.config = self.get_config()
- self.drivers = self.get_gce_drivers()
- self.ip_type = self.get_inventory_options()
- if self.ip_type:
- self.ip_type = self.ip_type.lower()
-
- # Cache management
- start_inventory_time = time()
- cache_used = False
- if self.args.refresh_cache or not self.cache.is_valid():
- self.do_api_calls_update_cache()
- else:
- self.load_inventory_from_cache()
- cache_used = True
- self.inventory['_meta']['stats'] = {'use_cache': True}
- self.inventory['_meta']['stats'] = {
- 'inventory_load_time': time() - start_inventory_time,
- 'cache_used': cache_used
- }
-
- # Just display data for specific host
- if self.args.host:
- print(self.json_format_dict(
- self.inventory['_meta']['hostvars'][self.args.host],
- pretty=self.args.pretty))
- else:
- # Otherwise, assume user wants all instances grouped
- zones = self.parse_env_zones()
- print(self.json_format_dict(self.inventory,
- pretty=self.args.pretty))
- sys.exit(0)
-
- def get_config(self):
- """
- Reads the settings from the gce.ini file.
-
- Populates a ConfigParser object with defaults and
- attempts to read an .ini-style configuration from the filename
- specified in GCE_INI_PATH. If the environment variable is
- not present, the filename defaults to gce.ini in the current
- working directory.
- """
- gce_ini_default_path = os.path.join(
- os.path.dirname(os.path.realpath(__file__)), "gce.ini")
- gce_ini_path = os.environ.get('GCE_INI_PATH', gce_ini_default_path)
-
- # Create a ConfigParser.
- # This provides empty defaults to each key, so that environment
- # variable configuration (as opposed to INI configuration) is able
- # to work.
- config = configparser.ConfigParser(defaults={
- 'gce_service_account_email_address': '',
- 'gce_service_account_pem_file_path': '',
- 'gce_project_id': '',
- 'gce_zone': '',
- 'libcloud_secrets': '',
- 'instance_tags': '',
- 'inventory_ip_type': '',
- 'cache_path': '~/.ansible/tmp',
- 'cache_max_age': '300'
- })
- if 'gce' not in config.sections():
- config.add_section('gce')
- if 'inventory' not in config.sections():
- config.add_section('inventory')
- if 'cache' not in config.sections():
- config.add_section('cache')
-
- config.read(gce_ini_path)
-
- #########
- # Section added for processing ini settings
- #########
-
- # Set the instance_states filter based on config file options
- self.instance_states = []
- if config.has_option('gce', 'instance_states'):
- states = config.get('gce', 'instance_states')
- # Ignore if instance_states is an empty string.
- if states:
- self.instance_states = states.split(',')
-
- # Set the instance_tags filter, env var overrides config from file
- # and cli param overrides all
- if self.args.instance_tags:
- self.instance_tags = self.args.instance_tags
- else:
- self.instance_tags = os.environ.get(
- 'GCE_INSTANCE_TAGS', config.get('gce', 'instance_tags'))
- if self.instance_tags:
- self.instance_tags = self.instance_tags.split(',')
-
- # Caching
- cache_path = config.get('cache', 'cache_path')
- cache_max_age = config.getint('cache', 'cache_max_age')
- # TOOD(supertom): support project-specific caches
- cache_name = 'ansible-gce.cache'
- self.cache = CloudInventoryCache(cache_path=cache_path,
- cache_max_age=cache_max_age,
- cache_name=cache_name)
- return config
-
- def get_inventory_options(self):
- """Determine inventory options. Environment variables always
- take precedence over configuration files."""
- ip_type = self.config.get('inventory', 'inventory_ip_type')
- # If the appropriate environment variables are set, they override
- # other configuration
- ip_type = os.environ.get('INVENTORY_IP_TYPE', ip_type)
- return ip_type
-
- def get_gce_drivers(self):
- """Determine the GCE authorization settings and return a list of
- libcloud drivers.
- """
- # Attempt to get GCE params from a configuration file, if one
- # exists.
- secrets_path = self.config.get('gce', 'libcloud_secrets')
- secrets_found = False
-
- try:
- import secrets
- args = list(secrets.GCE_PARAMS)
- kwargs = secrets.GCE_KEYWORD_PARAMS
- secrets_found = True
- except Exception:
- pass
-
- if not secrets_found and secrets_path:
- if not secrets_path.endswith('secrets.py'):
- err = "Must specify libcloud secrets file as "
- err += "/absolute/path/to/secrets.py"
- sys.exit(err)
- sys.path.append(os.path.dirname(secrets_path))
- try:
- import secrets
- args = list(getattr(secrets, 'GCE_PARAMS', []))
- kwargs = getattr(secrets, 'GCE_KEYWORD_PARAMS', {})
- secrets_found = True
- except Exception:
- pass
-
- if not secrets_found:
- args = [
- self.config.get('gce', 'gce_service_account_email_address'),
- self.config.get('gce', 'gce_service_account_pem_file_path')
- ]
- kwargs = {'project': self.config.get('gce', 'gce_project_id'),
- 'datacenter': self.config.get('gce', 'gce_zone')}
-
- # If the appropriate environment variables are set, they override
- # other configuration; process those into our args and kwargs.
- args[0] = os.environ.get('GCE_EMAIL', args[0])
- args[1] = os.environ.get('GCE_PEM_FILE_PATH', args[1])
- args[1] = os.environ.get('GCE_CREDENTIALS_FILE_PATH', args[1])
-
- kwargs['project'] = os.environ.get('GCE_PROJECT', kwargs['project'])
- kwargs['datacenter'] = os.environ.get('GCE_ZONE', kwargs['datacenter'])
-
- gce_drivers = []
- projects = kwargs['project'].split(',')
- for project in projects:
- kwargs['project'] = project
- gce = get_driver(Provider.GCE)(*args, **kwargs)
- gce.connection.user_agent_append(
- '%s/%s' % (USER_AGENT_PRODUCT, USER_AGENT_VERSION),
- )
- gce_drivers.append(gce)
- return gce_drivers
-
- def parse_env_zones(self):
- '''returns a list of comma separated zones parsed from the GCE_ZONE environment variable.
- If provided, this will be used to filter the results of the grouped_instances call'''
- import csv
- reader = csv.reader([os.environ.get('GCE_ZONE', "")], skipinitialspace=True)
- zones = [r for r in reader]
- return [z for z in zones[0]]
-
- def parse_cli_args(self):
- ''' Command line argument processing '''
-
- parser = argparse.ArgumentParser(
- description='Produce an Ansible Inventory file based on GCE')
- parser.add_argument('--list', action='store_true', default=True,
- help='List instances (default: True)')
- parser.add_argument('--host', action='store',
- help='Get all information about an instance')
- parser.add_argument('--instance-tags', action='store',
- help='Only include instances with this tags, separated by comma')
- parser.add_argument('--pretty', action='store_true', default=False,
- help='Pretty format (default: False)')
- parser.add_argument(
- '--refresh-cache', action='store_true', default=False,
- help='Force refresh of cache by making API requests (default: False - use cache files)')
- self.args = parser.parse_args()
-
- def node_to_dict(self, inst):
- md = {}
-
- if inst is None:
- return {}
-
- if 'items' in inst.extra['metadata']:
- for entry in inst.extra['metadata']['items']:
- md[entry['key']] = entry['value']
-
- net = inst.extra['networkInterfaces'][0]['network'].split('/')[-1]
- subnet = None
- if 'subnetwork' in inst.extra['networkInterfaces'][0]:
- subnet = inst.extra['networkInterfaces'][0]['subnetwork'].split('/')[-1]
- # default to exernal IP unless user has specified they prefer internal
- if self.ip_type == 'internal':
- ssh_host = inst.private_ips[0]
- else:
- ssh_host = inst.public_ips[0] if len(inst.public_ips) >= 1 else inst.private_ips[0]
-
- return {
- 'gce_uuid': inst.uuid,
- 'gce_id': inst.id,
- 'gce_image': inst.image,
- 'gce_machine_type': inst.size,
- 'gce_private_ip': inst.private_ips[0],
- 'gce_public_ip': inst.public_ips[0] if len(inst.public_ips) >= 1 else None,
- 'gce_name': inst.name,
- 'gce_description': inst.extra['description'],
- 'gce_status': inst.extra['status'],
- 'gce_zone': inst.extra['zone'].name,
- 'gce_tags': inst.extra['tags'],
- 'gce_metadata': md,
- 'gce_network': net,
- 'gce_subnetwork': subnet,
- # Hosts don't have a public name, so we add an IP
- 'ansible_ssh_host': ssh_host
- }
-
- def load_inventory_from_cache(self):
- ''' Loads inventory from JSON on disk. '''
-
- try:
- self.inventory = self.cache.get_all_data_from_cache()
- hosts = self.inventory['_meta']['hostvars']
- except Exception as e:
- print(
- "Invalid inventory file %s. Please rebuild with -refresh-cache option."
- % (self.cache.cache_path_cache))
- raise
-
- def do_api_calls_update_cache(self):
- ''' Do API calls and save data in cache. '''
- zones = self.parse_env_zones()
- data = self.group_instances(zones)
- self.cache.write_to_cache(data)
- self.inventory = data
-
- def list_nodes(self):
- all_nodes = []
- params, more_results = {'maxResults': 500}, True
- while more_results:
- for driver in self.drivers:
- driver.connection.gce_params = params
- all_nodes.extend(driver.list_nodes())
- more_results = 'pageToken' in params
- return all_nodes
-
- def group_instances(self, zones=None):
- '''Group all instances'''
- groups = {}
- meta = {}
- meta["hostvars"] = {}
-
- for node in self.list_nodes():
-
- # This check filters on the desired instance states defined in the
- # config file with the instance_states config option.
- #
- # If the instance_states list is _empty_ then _ALL_ states are returned.
- #
- # If the instance_states list is _populated_ then check the current
- # state against the instance_states list
- if self.instance_states and not node.extra['status'] in self.instance_states:
- continue
-
- # This check filters on the desired instance tags defined in the
- # config file with the instance_tags config option, env var GCE_INSTANCE_TAGS,
- # or as the cli param --instance-tags.
- #
- # If the instance_tags list is _empty_ then _ALL_ instances are returned.
- #
- # If the instance_tags list is _populated_ then check the current
- # instance tags against the instance_tags list. If the instance has
- # at least one tag from the instance_tags list, it is returned.
- if self.instance_tags and not set(self.instance_tags) & set(node.extra['tags']):
- continue
-
- name = node.name
-
- meta["hostvars"][name] = self.node_to_dict(node)
-
- zone = node.extra['zone'].name
-
- # To avoid making multiple requests per zone
- # we list all nodes and then filter the results
- if zones and zone not in zones:
- continue
-
- if zone in groups:
- groups[zone].append(name)
- else:
- groups[zone] = [name]
-
- tags = node.extra['tags']
- for t in tags:
- if t.startswith('group-'):
- tag = t[6:]
- else:
- tag = 'tag_%s' % t
- if tag in groups:
- groups[tag].append(name)
- else:
- groups[tag] = [name]
-
- net = node.extra['networkInterfaces'][0]['network'].split('/')[-1]
- net = 'network_%s' % net
- if net in groups:
- groups[net].append(name)
- else:
- groups[net] = [name]
-
- machine_type = node.size
- if machine_type in groups:
- groups[machine_type].append(name)
- else:
- groups[machine_type] = [name]
-
- image = node.image or 'persistent_disk'
- if image in groups:
- groups[image].append(name)
- else:
- groups[image] = [name]
-
- status = node.extra['status']
- stat = 'status_%s' % status.lower()
- if stat in groups:
- groups[stat].append(name)
- else:
- groups[stat] = [name]
-
- for private_ip in node.private_ips:
- groups[private_ip] = [name]
-
- if len(node.public_ips) >= 1:
- for public_ip in node.public_ips:
- groups[public_ip] = [name]
-
- groups["_meta"] = meta
-
- return groups
-
- def json_format_dict(self, data, pretty=False):
- ''' Converts a dict to a JSON object and dumps it as a formatted
- string '''
-
- if pretty:
- return json.dumps(data, sort_keys=True, indent=2)
- else:
- return json.dumps(data)
-
-
-# Run the script
-if __name__ == '__main__':
- GceInventory()
diff --git a/ansible_collections/community/google/tests/sanity/ignore-2.10.txt b/ansible_collections/community/google/tests/sanity/ignore-2.10.txt
deleted file mode 100644
index c233efa5e..000000000
--- a/ansible_collections/community/google/tests/sanity/ignore-2.10.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-plugins/modules/gce_eip.py pylint:blacklisted-name
-plugins/modules/gce_eip.py validate-modules:parameter-list-no-elements
-plugins/modules/gce_img.py pylint:blacklisted-name
-plugins/modules/gce_instance_template.py pylint:blacklisted-name
-plugins/modules/gce_instance_template.py validate-modules:doc-missing-type
-plugins/modules/gce_instance_template.py validate-modules:parameter-list-no-elements
-plugins/modules/gce_labels.py validate-modules:parameter-list-no-elements
-plugins/modules/gce_lb.py pylint:blacklisted-name
-plugins/modules/gce_lb.py validate-modules:parameter-list-no-elements
-plugins/modules/gce_mig.py pylint:blacklisted-name
-plugins/modules/gce_mig.py validate-modules:parameter-list-no-elements
-plugins/modules/gce_net.py pylint:blacklisted-name
-plugins/modules/gce_net.py validate-modules:parameter-list-no-elements
-plugins/modules/gce_pd.py pylint:blacklisted-name
-plugins/modules/gce_pd.py validate-modules:parameter-list-no-elements
-plugins/modules/gce_snapshot.py pylint:blacklisted-name
-plugins/modules/gce_snapshot.py validate-modules:parameter-list-no-elements
-plugins/modules/gce_tag.py pylint:blacklisted-name
-plugins/modules/gce_tag.py validate-modules:parameter-list-no-elements
-plugins/modules/gcpubsub.py validate-modules:parameter-list-no-elements
-plugins/modules/gcpubsub_info.py validate-modules:parameter-state-invalid-choice
-scripts/inventory/gce.py pylint:blacklisted-name
diff --git a/ansible_collections/community/google/tests/sanity/ignore-2.11.txt b/ansible_collections/community/google/tests/sanity/ignore-2.11.txt
deleted file mode 100644
index c233efa5e..000000000
--- a/ansible_collections/community/google/tests/sanity/ignore-2.11.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-plugins/modules/gce_eip.py pylint:blacklisted-name
-plugins/modules/gce_eip.py validate-modules:parameter-list-no-elements
-plugins/modules/gce_img.py pylint:blacklisted-name
-plugins/modules/gce_instance_template.py pylint:blacklisted-name
-plugins/modules/gce_instance_template.py validate-modules:doc-missing-type
-plugins/modules/gce_instance_template.py validate-modules:parameter-list-no-elements
-plugins/modules/gce_labels.py validate-modules:parameter-list-no-elements
-plugins/modules/gce_lb.py pylint:blacklisted-name
-plugins/modules/gce_lb.py validate-modules:parameter-list-no-elements
-plugins/modules/gce_mig.py pylint:blacklisted-name
-plugins/modules/gce_mig.py validate-modules:parameter-list-no-elements
-plugins/modules/gce_net.py pylint:blacklisted-name
-plugins/modules/gce_net.py validate-modules:parameter-list-no-elements
-plugins/modules/gce_pd.py pylint:blacklisted-name
-plugins/modules/gce_pd.py validate-modules:parameter-list-no-elements
-plugins/modules/gce_snapshot.py pylint:blacklisted-name
-plugins/modules/gce_snapshot.py validate-modules:parameter-list-no-elements
-plugins/modules/gce_tag.py pylint:blacklisted-name
-plugins/modules/gce_tag.py validate-modules:parameter-list-no-elements
-plugins/modules/gcpubsub.py validate-modules:parameter-list-no-elements
-plugins/modules/gcpubsub_info.py validate-modules:parameter-state-invalid-choice
-scripts/inventory/gce.py pylint:blacklisted-name
diff --git a/ansible_collections/community/google/tests/sanity/ignore-2.9.txt b/ansible_collections/community/google/tests/sanity/ignore-2.9.txt
deleted file mode 100644
index f2dffaa46..000000000
--- a/ansible_collections/community/google/tests/sanity/ignore-2.9.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-plugins/modules/gce_eip.py pylint:blacklisted-name
-plugins/modules/gce_img.py pylint:blacklisted-name
-plugins/modules/gce_instance_template.py pylint:blacklisted-name
-plugins/modules/gce_instance_template.py validate-modules:doc-missing-type
-plugins/modules/gce_lb.py pylint:blacklisted-name
-plugins/modules/gce_mig.py pylint:blacklisted-name
-plugins/modules/gce_net.py pylint:blacklisted-name
-plugins/modules/gce_pd.py pylint:blacklisted-name
-plugins/modules/gce_snapshot.py pylint:blacklisted-name
-plugins/modules/gce_tag.py pylint:blacklisted-name
-scripts/inventory/gce.py pylint:blacklisted-name
diff --git a/ansible_collections/community/google/tests/unit/compat/mock.py b/ansible_collections/community/google/tests/unit/compat/mock.py
deleted file mode 100644
index 0972cd2e8..000000000
--- a/ansible_collections/community/google/tests/unit/compat/mock.py
+++ /dev/null
@@ -1,122 +0,0 @@
-# (c) 2014, Toshio Kuratomi <tkuratomi@ansible.com>
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-'''
-Compat module for Python3.x's unittest.mock module
-'''
-import sys
-
-# Python 2.7
-
-# Note: Could use the pypi mock library on python3.x as well as python2.x. It
-# is the same as the python3 stdlib mock library
-
-try:
- # Allow wildcard import because we really do want to import all of mock's
- # symbols into this compat shim
- # pylint: disable=wildcard-import,unused-wildcard-import
- from unittest.mock import *
-except ImportError:
- # Python 2
- # pylint: disable=wildcard-import,unused-wildcard-import
- try:
- from mock import *
- except ImportError:
- print('You need the mock library installed on python2.x to run tests')
-
-
-# Prior to 3.4.4, mock_open cannot handle binary read_data
-if sys.version_info >= (3,) and sys.version_info < (3, 4, 4):
- file_spec = None
-
- def _iterate_read_data(read_data):
- # Helper for mock_open:
- # Retrieve lines from read_data via a generator so that separate calls to
- # readline, read, and readlines are properly interleaved
- sep = b'\n' if isinstance(read_data, bytes) else '\n'
- data_as_list = [l + sep for l in read_data.split(sep)]
-
- if data_as_list[-1] == sep:
- # If the last line ended in a newline, the list comprehension will have an
- # extra entry that's just a newline. Remove this.
- data_as_list = data_as_list[:-1]
- else:
- # If there wasn't an extra newline by itself, then the file being
- # emulated doesn't have a newline to end the last line remove the
- # newline that our naive format() added
- data_as_list[-1] = data_as_list[-1][:-1]
-
- for line in data_as_list:
- yield line
-
- def mock_open(mock=None, read_data=''):
- """
- A helper function to create a mock to replace the use of `open`. It works
- for `open` called directly or used as a context manager.
-
- The `mock` argument is the mock object to configure. If `None` (the
- default) then a `MagicMock` will be created for you, with the API limited
- to methods or attributes available on standard file handles.
-
- `read_data` is a string for the `read` methoddline`, and `readlines` of the
- file handle to return. This is an empty string by default.
- """
- def _readlines_side_effect(*args, **kwargs):
- if handle.readlines.return_value is not None:
- return handle.readlines.return_value
- return list(_data)
-
- def _read_side_effect(*args, **kwargs):
- if handle.read.return_value is not None:
- return handle.read.return_value
- return type(read_data)().join(_data)
-
- def _readline_side_effect():
- if handle.readline.return_value is not None:
- while True:
- yield handle.readline.return_value
- for line in _data:
- yield line
-
- global file_spec
- if file_spec is None:
- import _io
- file_spec = list(set(dir(_io.TextIOWrapper)).union(set(dir(_io.BytesIO))))
-
- if mock is None:
- mock = MagicMock(name='open', spec=open)
-
- handle = MagicMock(spec=file_spec)
- handle.__enter__.return_value = handle
-
- _data = _iterate_read_data(read_data)
-
- handle.write.return_value = None
- handle.read.return_value = None
- handle.readline.return_value = None
- handle.readlines.return_value = None
-
- handle.read.side_effect = _read_side_effect
- handle.readline.side_effect = _readline_side_effect()
- handle.readlines.side_effect = _readlines_side_effect
-
- mock.return_value = handle
- return mock
diff --git a/ansible_collections/community/google/tests/unit/compat/unittest.py b/ansible_collections/community/google/tests/unit/compat/unittest.py
deleted file mode 100644
index 98f08ad6a..000000000
--- a/ansible_collections/community/google/tests/unit/compat/unittest.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# (c) 2014, Toshio Kuratomi <tkuratomi@ansible.com>
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-'''
-Compat module for Python2.7's unittest module
-'''
-
-import sys
-
-# Allow wildcard import because we really do want to import all of
-# unittests's symbols into this compat shim
-# pylint: disable=wildcard-import,unused-wildcard-import
-if sys.version_info < (2, 7):
- try:
- # Need unittest2 on python2.6
- from unittest2 import *
- except ImportError:
- print('You need unittest2 installed on python2.6.x to run tests')
-else:
- from unittest import *
diff --git a/ansible_collections/community/google/tests/unit/plugins/module_utils/__init__.py b/ansible_collections/community/google/tests/unit/plugins/module_utils/__init__.py
deleted file mode 100644
index e69de29bb..000000000
--- a/ansible_collections/community/google/tests/unit/plugins/module_utils/__init__.py
+++ /dev/null
diff --git a/ansible_collections/community/google/tests/unit/plugins/module_utils/test_auth.py b/ansible_collections/community/google/tests/unit/plugins/module_utils/test_auth.py
deleted file mode 100644
index 845234ff7..000000000
--- a/ansible_collections/community/google/tests/unit/plugins/module_utils/test_auth.py
+++ /dev/null
@@ -1,162 +0,0 @@
-# -*- coding: utf-8 -*-
-# (c) 2016, Tom Melendez (@supertom) <tom@supertom.com>
-#
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import os
-
-import pytest
-
-from ansible_collections.community.google.tests.unit.compat import mock, unittest
-from ansible_collections.community.google.plugins.module_utils.gcp import (_get_gcp_ansible_credentials, _get_gcp_credentials, _get_gcp_environ_var,
- _get_gcp_environment_credentials,
- _validate_credentials_file)
-
-# Fake data/function used for testing
-fake_env_data = {'GCE_EMAIL': 'gce-email'}
-
-
-def fake_get_gcp_environ_var(var_name, default_value):
- if var_name not in fake_env_data:
- return default_value
- else:
- return fake_env_data[var_name]
-
-# Fake AnsibleModule for use in tests
-
-
-class FakeModule(object):
- class Params():
- data = {}
-
- def get(self, key, alt=None):
- if key in self.data:
- return self.data[key]
- else:
- return alt
-
- def __init__(self, data=None):
- data = {} if data is None else data
-
- self.params = FakeModule.Params()
- self.params.data = data
-
- def fail_json(self, **kwargs):
- raise ValueError("fail_json")
-
- def deprecate(self, **kwargs):
- return None
-
-
-class GCPAuthTestCase(unittest.TestCase):
- """Tests to verify different Auth mechanisms."""
-
- def setup_method(self, method):
- global fake_env_data
- fake_env_data = {'GCE_EMAIL': 'gce-email'}
-
- def test_get_gcp_ansible_credentials(self):
- input_data = {'service_account_email': 'mysa',
- 'credentials_file': 'path-to-file.json',
- 'project_id': 'my-cool-project'}
-
- module = FakeModule(input_data)
- actual = _get_gcp_ansible_credentials(module)
- expected = tuple(input_data.values())
- self.assertEqual(sorted(expected), sorted(actual))
-
- def test_get_gcp_environ_var(self):
- # Chose not to mock this so we could really verify that it
- # works as expected.
- existing_var_name = 'gcp_ansible_auth_test_54321'
- non_existing_var_name = 'doesnt_exist_gcp_ansible_auth_test_12345'
- os.environ[existing_var_name] = 'foobar'
- self.assertEqual('foobar', _get_gcp_environ_var(
- existing_var_name, None))
- del os.environ[existing_var_name]
- self.assertEqual('default_value', _get_gcp_environ_var(
- non_existing_var_name, 'default_value'))
-
- def test_validate_credentials_file(self):
- # TODO(supertom): Only dealing with p12 here, check the other states
- # of this function
- module = FakeModule()
- with mock.patch('ansible_collections.community.google.plugins.module_utils.gcp.open',
- mock.mock_open(read_data='foobar'), create=True):
- # pem condition, warning is suppressed with the return_value
- credentials_file = '/foopath/pem.pem'
- with self.assertRaises(ValueError):
- _validate_credentials_file(module,
- credentials_file=credentials_file,
- require_valid_json=False,
- check_libcloud=False)
-
- @mock.patch('ansible_collections.community.google.plugins.module_utils.gcp._get_gcp_environ_var',
- side_effect=fake_get_gcp_environ_var)
- def test_get_gcp_environment_credentials(self, mockobj):
- global fake_env_data
-
- actual = _get_gcp_environment_credentials(None, None, None)
- expected = tuple(['gce-email', None, None])
- self.assertEqual(expected, actual)
-
- fake_env_data = {'GCE_PEM_FILE_PATH': '/path/to/pem.pem'}
- expected = tuple([None, '/path/to/pem.pem', None])
- actual = _get_gcp_environment_credentials(None, None, None)
- self.assertEqual(expected, actual)
-
- # pem and creds are set, expect creds
- fake_env_data = {'GCE_PEM_FILE_PATH': '/path/to/pem.pem',
- 'GCE_CREDENTIALS_FILE_PATH': '/path/to/creds.json'}
- expected = tuple([None, '/path/to/creds.json', None])
- actual = _get_gcp_environment_credentials(None, None, None)
- self.assertEqual(expected, actual)
-
- # expect GOOGLE_APPLICATION_CREDENTIALS over PEM
- fake_env_data = {'GCE_PEM_FILE_PATH': '/path/to/pem.pem',
- 'GOOGLE_APPLICATION_CREDENTIALS': '/path/to/appcreds.json'}
- expected = tuple([None, '/path/to/appcreds.json', None])
- actual = _get_gcp_environment_credentials(None, None, None)
- self.assertEqual(expected, actual)
-
- # project tests
- fake_env_data = {'GCE_PROJECT': 'my-project'}
- expected = tuple([None, None, 'my-project'])
- actual = _get_gcp_environment_credentials(None, None, None)
- self.assertEqual(expected, actual)
-
- fake_env_data = {'GOOGLE_CLOUD_PROJECT': 'my-cloud-project'}
- expected = tuple([None, None, 'my-cloud-project'])
- actual = _get_gcp_environment_credentials(None, None, None)
- self.assertEqual(expected, actual)
-
- # data passed in, picking up project id only
- fake_env_data = {'GOOGLE_CLOUD_PROJECT': 'my-project'}
- expected = tuple(['my-sa-email', '/path/to/creds.json', 'my-project'])
- actual = _get_gcp_environment_credentials(
- 'my-sa-email', '/path/to/creds.json', None)
- self.assertEqual(expected, actual)
-
- @mock.patch('ansible_collections.community.google.plugins.module_utils.gcp._get_gcp_environ_var',
- side_effect=fake_get_gcp_environ_var)
- def test_get_gcp_credentials(self, mockobj):
- global fake_env_data
-
- fake_env_data = {}
- module = FakeModule()
- module.params.data = {}
- # Nothing is set, calls fail_json
- with pytest.raises(ValueError):
- _get_gcp_credentials(module)
-
- # project_id (only) is set from Ansible params.
- module.params.data['project_id'] = 'my-project'
- actual = _get_gcp_credentials(
- module, require_valid_json=True, check_libcloud=False)
- expected = {'service_account_email': '',
- 'project_id': 'my-project',
- 'credentials_file': ''}
- self.assertEqual(expected, actual)
diff --git a/ansible_collections/community/google/tests/unit/plugins/module_utils/test_utils.py b/ansible_collections/community/google/tests/unit/plugins/module_utils/test_utils.py
deleted file mode 100644
index 7098f705d..000000000
--- a/ansible_collections/community/google/tests/unit/plugins/module_utils/test_utils.py
+++ /dev/null
@@ -1,361 +0,0 @@
-# -*- coding: utf-8 -*-
-# (c) 2016, Tom Melendez <tom@supertom.com>
-#
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-from ansible_collections.community.google.tests.unit.compat import mock, unittest
-from ansible_collections.community.google.plugins.module_utils.gcp import check_min_pkg_version, GCPUtils, GCPInvalidURLError
-
-
-def build_distribution(version):
- obj = mock.MagicMock()
- obj.version = '0.5.0'
- return obj
-
-
-class GCPUtilsTestCase(unittest.TestCase):
- params_dict = {
- 'url_map_name': 'foo_url_map_name',
- 'description': 'foo_url_map description',
- 'host_rules': [
- {
- 'description': 'host rules description',
- 'hosts': [
- 'www.example.com',
- 'www2.example.com'
- ],
- 'path_matcher': 'host_rules_path_matcher'
- }
- ],
- 'path_matchers': [
- {
- 'name': 'path_matcher_one',
- 'description': 'path matcher one',
- 'defaultService': 'bes-pathmatcher-one-default',
- 'pathRules': [
- {
- 'service': 'my-one-bes',
- 'paths': [
- '/',
- '/aboutus'
- ]
- }
- ]
- },
- {
- 'name': 'path_matcher_two',
- 'description': 'path matcher two',
- 'defaultService': 'bes-pathmatcher-two-default',
- 'pathRules': [
- {
- 'service': 'my-two-bes',
- 'paths': [
- '/webapp',
- '/graphs'
- ]
- }
- ]
- }
- ]
- }
-
- @mock.patch("pkg_resources.get_distribution", side_effect=build_distribution)
- def test_check_minimum_pkg_version(self, mockobj):
- self.assertTrue(check_min_pkg_version('foobar', '0.4.0'))
- self.assertTrue(check_min_pkg_version('foobar', '0.5.0'))
- self.assertFalse(check_min_pkg_version('foobar', '0.6.0'))
-
- def test_parse_gcp_url(self):
- # region, resource, entity, method
- input_url = 'https://www.googleapis.com/compute/v1/projects/myproject/regions/us-east1/instanceGroupManagers/my-mig/recreateInstances'
- actual = GCPUtils.parse_gcp_url(input_url)
- self.assertEqual('compute', actual['service'])
- self.assertEqual('v1', actual['api_version'])
- self.assertEqual('myproject', actual['project'])
- self.assertEqual('us-east1', actual['region'])
- self.assertEqual('instanceGroupManagers', actual['resource_name'])
- self.assertEqual('my-mig', actual['entity_name'])
- self.assertEqual('recreateInstances', actual['method_name'])
-
- # zone, resource, entity, method
- input_url = 'https://www.googleapis.com/compute/v1/projects/myproject/zones/us-east1-c/instanceGroupManagers/my-mig/recreateInstances'
- actual = GCPUtils.parse_gcp_url(input_url)
- self.assertEqual('compute', actual['service'])
- self.assertEqual('v1', actual['api_version'])
- self.assertEqual('myproject', actual['project'])
- self.assertEqual('us-east1-c', actual['zone'])
- self.assertEqual('instanceGroupManagers', actual['resource_name'])
- self.assertEqual('my-mig', actual['entity_name'])
- self.assertEqual('recreateInstances', actual['method_name'])
-
- # global, resource
- input_url = 'https://www.googleapis.com/compute/v1/projects/myproject/global/urlMaps'
- actual = GCPUtils.parse_gcp_url(input_url)
- self.assertEqual('compute', actual['service'])
- self.assertEqual('v1', actual['api_version'])
- self.assertEqual('myproject', actual['project'])
- self.assertTrue('global' in actual)
- self.assertTrue(actual['global'])
- self.assertEqual('urlMaps', actual['resource_name'])
-
- # global, resource, entity
- input_url = 'https://www.googleapis.com/compute/v1/projects/myproject/global/urlMaps/my-url-map'
- actual = GCPUtils.parse_gcp_url(input_url)
- self.assertEqual('myproject', actual['project'])
- self.assertTrue('global' in actual)
- self.assertTrue(actual['global'])
- self.assertEqual('v1', actual['api_version'])
- self.assertEqual('compute', actual['service'])
-
- # global URL, resource, entity, method_name
- input_url = 'https://www.googleapis.com/compute/v1/projects/myproject/global/backendServices/mybackendservice/getHealth'
- actual = GCPUtils.parse_gcp_url(input_url)
- self.assertEqual('compute', actual['service'])
- self.assertEqual('v1', actual['api_version'])
- self.assertEqual('myproject', actual['project'])
- self.assertTrue('global' in actual)
- self.assertTrue(actual['global'])
- self.assertEqual('backendServices', actual['resource_name'])
- self.assertEqual('mybackendservice', actual['entity_name'])
- self.assertEqual('getHealth', actual['method_name'])
-
- # no location in URL
- input_url = 'https://www.googleapis.com/compute/v1/projects/myproject/targetHttpProxies/mytargetproxy/setUrlMap'
- actual = GCPUtils.parse_gcp_url(input_url)
- self.assertEqual('compute', actual['service'])
- self.assertEqual('v1', actual['api_version'])
- self.assertEqual('myproject', actual['project'])
- self.assertFalse('global' in actual)
- self.assertEqual('targetHttpProxies', actual['resource_name'])
- self.assertEqual('mytargetproxy', actual['entity_name'])
- self.assertEqual('setUrlMap', actual['method_name'])
-
- input_url = 'https://www.googleapis.com/compute/v1/projects/myproject/targetHttpProxies/mytargetproxy'
- actual = GCPUtils.parse_gcp_url(input_url)
- self.assertEqual('compute', actual['service'])
- self.assertEqual('v1', actual['api_version'])
- self.assertEqual('myproject', actual['project'])
- self.assertFalse('global' in actual)
- self.assertEqual('targetHttpProxies', actual['resource_name'])
- self.assertEqual('mytargetproxy', actual['entity_name'])
-
- input_url = 'https://www.googleapis.com/compute/v1/projects/myproject/targetHttpProxies'
- actual = GCPUtils.parse_gcp_url(input_url)
- self.assertEqual('compute', actual['service'])
- self.assertEqual('v1', actual['api_version'])
- self.assertEqual('myproject', actual['project'])
- self.assertFalse('global' in actual)
- self.assertEqual('targetHttpProxies', actual['resource_name'])
-
- # test exceptions
- no_projects_input_url = 'https://www.googleapis.com/compute/v1/not-projects/myproject/global/backendServices/mybackendservice/getHealth'
- no_resource_input_url = 'https://www.googleapis.com/compute/v1/not-projects/myproject/global'
-
- no_resource_no_loc_input_url = 'https://www.googleapis.com/compute/v1/not-projects/myproject'
-
- with self.assertRaises(GCPInvalidURLError) as cm:
- GCPUtils.parse_gcp_url(no_projects_input_url)
- self.assertTrue(cm.exception, GCPInvalidURLError)
-
- with self.assertRaises(GCPInvalidURLError) as cm:
- GCPUtils.parse_gcp_url(no_resource_input_url)
- self.assertTrue(cm.exception, GCPInvalidURLError)
-
- with self.assertRaises(GCPInvalidURLError) as cm:
- GCPUtils.parse_gcp_url(no_resource_no_loc_input_url)
- self.assertTrue(cm.exception, GCPInvalidURLError)
-
- def test_params_to_gcp_dict(self):
-
- expected = {
- 'description': 'foo_url_map description',
- 'hostRules': [
- {
- 'description': 'host rules description',
- 'hosts': [
- 'www.example.com',
- 'www2.example.com'
- ],
- 'pathMatcher': 'host_rules_path_matcher'
- }
- ],
- 'name': 'foo_url_map_name',
- 'pathMatchers': [
- {
- 'defaultService': 'bes-pathmatcher-one-default',
- 'description': 'path matcher one',
- 'name': 'path_matcher_one',
- 'pathRules': [
- {
- 'paths': [
- '/',
- '/aboutus'
- ],
- 'service': 'my-one-bes'
- }
- ]
- },
- {
- 'defaultService': 'bes-pathmatcher-two-default',
- 'description': 'path matcher two',
- 'name': 'path_matcher_two',
- 'pathRules': [
- {
- 'paths': [
- '/webapp',
- '/graphs'
- ],
- 'service': 'my-two-bes'
- }
- ]
- }
- ]
- }
-
- actual = GCPUtils.params_to_gcp_dict(self.params_dict, 'url_map_name')
- self.assertEqual(expected, actual)
-
- def test_get_gcp_resource_from_methodId(self):
- input_data = 'compute.urlMaps.list'
- actual = GCPUtils.get_gcp_resource_from_methodId(input_data)
- self.assertEqual('urlMaps', actual)
- input_data = None
- actual = GCPUtils.get_gcp_resource_from_methodId(input_data)
- self.assertFalse(actual)
- input_data = 666
- actual = GCPUtils.get_gcp_resource_from_methodId(input_data)
- self.assertFalse(actual)
-
- def test_get_entity_name_from_resource_name(self):
- input_data = 'urlMaps'
- actual = GCPUtils.get_entity_name_from_resource_name(input_data)
- self.assertEqual('urlMap', actual)
- input_data = 'targetHttpProxies'
- actual = GCPUtils.get_entity_name_from_resource_name(input_data)
- self.assertEqual('targetHttpProxy', actual)
- input_data = 'globalForwardingRules'
- actual = GCPUtils.get_entity_name_from_resource_name(input_data)
- self.assertEqual('forwardingRule', actual)
- input_data = ''
- actual = GCPUtils.get_entity_name_from_resource_name(input_data)
- self.assertEqual(None, actual)
- input_data = 666
- actual = GCPUtils.get_entity_name_from_resource_name(input_data)
- self.assertEqual(None, actual)
-
- def test_are_params_equal(self):
- params1 = {'one': 1}
- params2 = {'one': 1}
- actual = GCPUtils.are_params_equal(params1, params2)
- self.assertTrue(actual)
-
- params1 = {'one': 1}
- params2 = {'two': 2}
- actual = GCPUtils.are_params_equal(params1, params2)
- self.assertFalse(actual)
-
- params1 = {'three': 3, 'two': 2, 'one': 1}
- params2 = {'one': 1, 'two': 2, 'three': 3}
- actual = GCPUtils.are_params_equal(params1, params2)
- self.assertTrue(actual)
-
- params1 = {
- "creationTimestamp": "2017-04-21T11:19:20.718-07:00",
- "defaultService": "https://www.googleapis.com/compute/v1/projects/myproject/global/backendServices/default-backend-service",
- "description": "",
- "fingerprint": "ickr_pwlZPU=",
- "hostRules": [
- {
- "description": "",
- "hosts": [
- "*."
- ],
- "pathMatcher": "path-matcher-one"
- }
- ],
- "id": "8566395781175047111",
- "kind": "compute#urlMap",
- "name": "newtesturlmap-foo",
- "pathMatchers": [
- {
- "defaultService": "https://www.googleapis.com/compute/v1/projects/myproject/global/backendServices/bes-pathmatcher-one-default",
- "description": "path matcher one",
- "name": "path-matcher-one",
- "pathRules": [
- {
- "paths": [
- "/data",
- "/aboutus"
- ],
- "service": "https://www.googleapis.com/compute/v1/projects/myproject/global/backendServices/my-one-bes"
- }
- ]
- }
- ],
- "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/global/urlMaps/newtesturlmap-foo"
- }
- params2 = {
- "defaultService": "https://www.googleapis.com/compute/v1/projects/myproject/global/backendServices/default-backend-service",
- "hostRules": [
- {
- "description": "",
- "hosts": [
- "*."
- ],
- "pathMatcher": "path-matcher-one"
- }
- ],
- "name": "newtesturlmap-foo",
- "pathMatchers": [
- {
- "defaultService": "https://www.googleapis.com/compute/v1/projects/myproject/global/backendServices/bes-pathmatcher-one-default",
- "description": "path matcher one",
- "name": "path-matcher-one",
- "pathRules": [
- {
- "paths": [
- "/data",
- "/aboutus"
- ],
- "service": "https://www.googleapis.com/compute/v1/projects/myproject/global/backendServices/my-one-bes"
- }
- ]
- }
- ],
- }
-
- # params1 has exclude fields, params2 doesn't. Should be equal
- actual = GCPUtils.are_params_equal(params1, params2)
- self.assertTrue(actual)
-
- def test_filter_gcp_fields(self):
- input_data = {
- u'kind': u'compute#httpsHealthCheck',
- u'description': u'',
- u'timeoutSec': 5,
- u'checkIntervalSec': 5,
- u'port': 443,
- u'healthyThreshold': 2,
- u'host': u'',
- u'requestPath': u'/',
- u'unhealthyThreshold': 2,
- u'creationTimestamp': u'2017-05-16T15:09:36.546-07:00',
- u'id': u'8727093129334146639',
- u'selfLink': u'https://www.googleapis.com/compute/v1/projects/myproject/global/httpsHealthChecks/myhealthcheck',
- u'name': u'myhealthcheck'}
-
- expected = {
- 'name': 'myhealthcheck',
- 'checkIntervalSec': 5,
- 'port': 443,
- 'unhealthyThreshold': 2,
- 'healthyThreshold': 2,
- 'host': '',
- 'timeoutSec': 5,
- 'requestPath': '/'}
-
- actual = GCPUtils.filter_gcp_fields(input_data)
- self.assertEqual(expected, actual)
diff --git a/ansible_collections/community/google/tests/unit/plugins/modules/__init__.py b/ansible_collections/community/google/tests/unit/plugins/modules/__init__.py
deleted file mode 100644
index e69de29bb..000000000
--- a/ansible_collections/community/google/tests/unit/plugins/modules/__init__.py
+++ /dev/null
diff --git a/ansible_collections/community/google/tests/unit/plugins/modules/test_gce_tag.py b/ansible_collections/community/google/tests/unit/plugins/modules/test_gce_tag.py
deleted file mode 100644
index 3a06f18d2..000000000
--- a/ansible_collections/community/google/tests/unit/plugins/modules/test_gce_tag.py
+++ /dev/null
@@ -1,66 +0,0 @@
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import unittest
-
-from ansible_collections.community.google.plugins.modules.gce_tag import _get_changed_items, _intersect_items, _union_items
-
-
-class TestGCETag(unittest.TestCase):
- """Unit tests for gce_tag module."""
-
- def test_union_items(self):
- """
- Combine items in both lists
- removing duplicates.
- """
- listA = [1, 2, 3, 4, 5, 8, 9]
- listB = [1, 2, 3, 4, 5, 6, 7]
- want = [1, 2, 3, 4, 5, 6, 7, 8, 9]
- got = _union_items(listA, listB)
- self.assertEqual(want, got)
-
- def test_intersect_items(self):
- """
- All unique items from either list.
- """
- listA = [1, 2, 3, 4, 5, 8, 9]
- listB = [1, 2, 3, 4, 5, 6, 7]
- want = [1, 2, 3, 4, 5]
- got = _intersect_items(listA, listB)
- self.assertEqual(want, got)
-
- # tags removed
- new_tags = ['one', 'two']
- existing_tags = ['two']
- want = ['two'] # only remove the tag that was present
- got = _intersect_items(existing_tags, new_tags)
- self.assertEqual(want, got)
-
- def test_get_changed_items(self):
- """
- All the items from left list that don't match
- any item from the right list.
- """
- listA = [1, 2, 3, 4, 5, 8, 9]
- listB = [1, 2, 3, 4, 5, 6, 7]
- want = [8, 9]
- got = _get_changed_items(listA, listB)
- self.assertEqual(want, got)
-
- # simulate new tags added
- tags_to_add = ['one', 'two']
- existing_tags = ['two']
- want = ['one']
- got = _get_changed_items(tags_to_add, existing_tags)
- self.assertEqual(want, got)
-
- # simulate removing tags
- # specifying one tag on right that doesn't exist
- tags_to_remove = ['one', 'two']
- existing_tags = ['two', 'three']
- want = ['three']
- got = _get_changed_items(existing_tags, tags_to_remove)
- self.assertEqual(want, got)
diff --git a/ansible_collections/community/google/tests/unit/requirements.txt b/ansible_collections/community/google/tests/unit/requirements.txt
deleted file mode 100644
index 16494a447..000000000
--- a/ansible_collections/community/google/tests/unit/requirements.txt
+++ /dev/null
@@ -1 +0,0 @@
-unittest2 ; python_version < '2.7' \ No newline at end of file
diff --git a/ansible_collections/community/grafana/.all-contributorsrc b/ansible_collections/community/grafana/.all-contributorsrc
index 878f911bf..f1a1cb6dc 100644
--- a/ansible_collections/community/grafana/.all-contributorsrc
+++ b/ansible_collections/community/grafana/.all-contributorsrc
@@ -177,6 +177,26 @@
"contributions": [
"bug"
]
+ },
+ {
+ "login": "amenzhinsky",
+ "name": "Aliaksandr Mianzhynski",
+ "avatar_url": "https://avatars.githubusercontent.com/u/1308953?v=4",
+ "profile": "https://github.com/amenzhinsky",
+ "contributions": [
+ "code",
+ "test"
+ ]
+ },
+ {
+ "login": "Nemental",
+ "name": "Moritz",
+ "avatar_url": "https://avatars.githubusercontent.com/u/15136847?v=4",
+ "profile": "https://nemental.de",
+ "contributions": [
+ "bug",
+ "code"
+ ]
}
],
"contributorsPerLine": 7,
@@ -185,5 +205,6 @@
"repoType": "github",
"repoHost": "https://github.com",
"skipCi": true,
- "commitConvention": "angular"
+ "commitConvention": "angular",
+ "commitType": "docs"
}
diff --git a/ansible_collections/community/grafana/.config/ansible-lint.yml b/ansible_collections/community/grafana/.config/ansible-lint.yml
new file mode 100644
index 000000000..81424ef79
--- /dev/null
+++ b/ansible_collections/community/grafana/.config/ansible-lint.yml
@@ -0,0 +1,5 @@
+---
+exclude_paths:
+ - .github/
+ - tests/
+ - changelogs/
diff --git a/ansible_collections/community/grafana/.config/yamllint/config b/ansible_collections/community/grafana/.config/yamllint/config
new file mode 100644
index 000000000..e907140bf
--- /dev/null
+++ b/ansible_collections/community/grafana/.config/yamllint/config
@@ -0,0 +1,2 @@
+---
+extends: default
diff --git a/ansible_collections/community/grafana/.github/CODEOWNERS b/ansible_collections/community/grafana/.github/CODEOWNERS
index 3035cfbbd..2cc403628 100644
--- a/ansible_collections/community/grafana/.github/CODEOWNERS
+++ b/ansible_collections/community/grafana/.github/CODEOWNERS
@@ -1,13 +1,9 @@
.github
# Repo maintainers, and goverance team (like Anisble's @ansible-commit-external)
-* @rrey @seuf @gundalow-collections/community-goverance-team
+* @rrey @seuf
# or possibly, we may want to define teams at the org level.
-# * @gundalow-collections/grafana-maintainers
# Example of maintainer of just a single plugin
#grafana/plugins/modules/grafana_plugin.py @someone-else
-
-
-.github/ @gundalow
diff --git a/ansible_collections/community/grafana/.github/workflows/ansible-test.yml b/ansible_collections/community/grafana/.github/workflows/ansible-test.yml
index e8f2cd6b3..a5717781f 100644
--- a/ansible_collections/community/grafana/.github/workflows/ansible-test.yml
+++ b/ansible_collections/community/grafana/.github/workflows/ansible-test.yml
@@ -12,8 +12,8 @@ jobs:
timeout-minutes: 30
strategy:
matrix:
- python_version: ["3.9"]
- ansible_version: ["stable-2.13", "stable-2.14", "devel"]
+ python_version: ["3.10"]
+ ansible_version: ["stable-2.15", "stable-2.16", "devel"]
steps:
- name: Perform testing
uses: ansible-community/ansible-test-gh-action@release/v1
@@ -29,8 +29,8 @@ jobs:
timeout-minutes: 30
strategy:
matrix:
- python_version: ["3.9"]
- ansible_version: ["stable-2.13", "stable-2.14", "devel"]
+ python_version: ["3.10"]
+ ansible_version: ["stable-2.15", "stable-2.16", "devel"]
steps:
- name: Perform testing
uses: ansible-community/ansible-test-gh-action@release/v1
@@ -45,9 +45,9 @@ jobs:
strategy:
fail-fast: false
matrix:
- grafana_version: ["9.2.6", "8.5.15", "7.5.16"]
- ansible_version: ["stable-2.13", "stable-2.14", "devel"]
- python_version: ["3.9"]
+ grafana_version: ["9.5.14", "8.5.27", "10.2.2"]
+ ansible_version: ["stable-2.15", "stable-2.16", "devel"]
+ python_version: ["3.10"]
services:
grafana:
image: grafana/grafana:${{ matrix.grafana_version }}
@@ -58,3 +58,37 @@ jobs:
ansible-core-version: ${{ matrix.ansible_version }}
target-python-version: ${{ matrix.python_version }}
testing-type: integration
+
+ molecule:
+ runs-on: ubuntu-latest
+ env:
+ PY_COLORS: 1
+ ANSIBLE_FORCE_COLOR: 1
+ strategy:
+ fail-fast: false
+ matrix:
+ grafana_version: ["9.5.14", "8.5.27", "10.2.2"]
+ ansible_version: ["stable-2.15", "stable-2.16", "devel"]
+ python_version: ["3.10"]
+ services:
+ grafana:
+ image: grafana/grafana:${{ matrix.grafana_version }}
+ ports: ["3000:3000"]
+ steps:
+ - name: Checkout repo
+ uses: actions/checkout@v4
+
+ - name: Set up Python
+ uses: actions/setup-python@v5
+ with:
+ python-version: ${{ matrix.python_version }}
+
+ - name: Install dependencies
+ run: |
+ python -m pip install --no-cache-dir --upgrade pip
+ pip install "git+https://github.com/ansible/ansible@${{ matrix.ansible_version }}" molecule molecule-docker
+
+ - name: Test with molecule
+ run: |
+ molecule --version
+ molecule test
diff --git a/ansible_collections/community/grafana/.github/workflows/lint.yml b/ansible_collections/community/grafana/.github/workflows/lint.yml
new file mode 100644
index 000000000..26216d89b
--- /dev/null
+++ b/ansible_collections/community/grafana/.github/workflows/lint.yml
@@ -0,0 +1,36 @@
+name: Lint
+
+on:
+ push:
+ branches:
+ - main
+ pull_request:
+
+jobs:
+ python:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Get changed files
+ id: changed-files
+ uses: tj-actions/changed-files@v41
+ with:
+ files: "**/*.py"
+
+ - if: ${{ steps.changed-files.outputs.all_changed_files != '' }}
+ uses: psf/black@stable
+ with:
+ src: ${{ steps.changed-files.outputs.all_changed_files }}
+
+ - if: ${{ steps.changed-files.outputs.all_changed_files != '' }}
+ uses: chartboost/ruff-action@v1
+ with:
+ src: ${{ steps.changed-files.outputs.all_changed_files }}
+ ansible:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Run ansible-lint
+ uses: ansible/ansible-lint@main
diff --git a/ansible_collections/community/grafana/.gitignore b/ansible_collections/community/grafana/.gitignore
index 9f11b755a..2483976dc 100644
--- a/ansible_collections/community/grafana/.gitignore
+++ b/ansible_collections/community/grafana/.gitignore
@@ -1 +1,2 @@
.idea/
+__pycache__/
diff --git a/ansible_collections/community/grafana/CHANGELOG.rst b/ansible_collections/community/grafana/CHANGELOG.rst
index 426f3cdf5..8a40ac18f 100644
--- a/ansible_collections/community/grafana/CHANGELOG.rst
+++ b/ansible_collections/community/grafana/CHANGELOG.rst
@@ -5,6 +5,71 @@ Grafana Collection Release Notes
.. contents:: Topics
+v1.8.0
+======
+
+Minor Changes
+-------------
+
+- Manage `grafana_folder` for organizations
+- Merged ansible role telekom-mms/ansible-role-grafana into ansible-collections/community.grafana
+- added `community.grafana.notification_channel` to role
+- grafana_dashboard - add check_mode support
+
+Bugfixes
+--------
+
+- test: replace deprecated `TestCase.assertEquals` to support Python 3.12
+
+v1.7.0
+======
+
+Minor Changes
+-------------
+
+- Add Quickwit search engine datasource (https://quickwit.io).
+- Add parameter `org_name` to `grafana_dashboard`
+- Add parameter `org_name` to `grafana_datasource`
+- Add parameter `org_name` to `grafana_organization_user`
+- Add support for Grafana Tempo datasource type (https://grafana.com/docs/grafana/latest/datasources/tempo/)
+- default to true/false in docs and code
+
+Bugfixes
+--------
+
+- Add `grafana_organiazion_user` to `action_groups.grafana`
+- Fixed orgId handling in diff comparison for `grafana_datasource` if using org_name
+
+v1.6.1
+======
+
+Minor Changes
+-------------
+
+- Bump version of Python used in tests to 3.10
+- Enable datasource option `time_interval` for prometheus
+- Fix documentation url for Ansible doc website
+- Now testing against Grafana 9.5.13, 8.5.27, 10.2.0
+
+Bugfixes
+--------
+
+- Fix error with datasources configured without basicAuth
+- grafana_folder, fix an issue during delete (starting Grafana 9.3)
+
+v1.6.0
+======
+
+Minor Changes
+-------------
+
+- Add `grafana_organization_user` module
+
+New Modules
+-----------
+
+- community.grafana.grafana_organization_user - Manage Grafana Organization Users.
+
v1.5.4
======
diff --git a/ansible_collections/community/grafana/FILES.json b/ansible_collections/community/grafana/FILES.json
index 4dc1e3d44..be95fa2bc 100644
--- a/ansible_collections/community/grafana/FILES.json
+++ b/ansible_collections/community/grafana/FILES.json
@@ -8,6 +8,34 @@
"format": 1
},
{
+ "name": ".config",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": ".config/yamllint",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": ".config/yamllint/config",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "b5910022dcb8c8295c99271d1c55ad728bb9ea20ae873c18aa2df97b8befae92",
+ "format": 1
+ },
+ {
+ "name": ".config/ansible-lint.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "dbf92afa23eaa6ef3d4461829dc8a7d3f8f14caab53e5a74d4070720c721b8af",
+ "format": 1
+ },
+ {
"name": ".github",
"ftype": "dir",
"chksum_type": null,
@@ -25,7 +53,7 @@
"name": ".github/workflows/ansible-test.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "105c6c1fb8b82644fddd6c6eaa59b21ab581662ff4a673483ee05f16cf44a48a",
+ "chksum_sha256": "e3e774ec33a3dc2a5ea1da40931ab5e6b96d3b67e57454fc867f9009cbc9797f",
"format": 1
},
{
@@ -43,6 +71,13 @@
"format": 1
},
{
+ "name": ".github/workflows/lint.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "405ea441af55f0770ae8d90ed355e34e31cef75a3b70dddd558a013df24e3b5d",
+ "format": 1
+ },
+ {
"name": ".github/workflows/rebase.yml",
"ftype": "file",
"chksum_type": "sha256",
@@ -53,7 +88,7 @@
"name": ".github/CODEOWNERS",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "27ba6e53b61251034d894049f866e4e15f9946b605b91756597e2a4727beef98",
+ "chksum_sha256": "81b8c5a2958345d497da521973b94f9c50210535765d8a4cb713d51468e5fb58",
"format": 1
},
{
@@ -225,6 +260,13 @@
"format": 1
},
{
+ "name": "changelogs/fragments/238_checkmode.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "7111820e7939b5645f6ebd20cdc03b166f0e8df983808c964334f4449d2fe73c",
+ "format": 1
+ },
+ {
"name": "changelogs/fragments/239_keyerror_grafana_url.yml",
"ftype": "file",
"chksum_type": "sha256",
@@ -232,6 +274,13 @@
"format": 1
},
{
+ "name": "changelogs/fragments/242_add_grafana_organization_user_module.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "8c86a0c996a356a2884ab70ef4fadfa58c7e504a26f055bc0926f8065de1f556",
+ "format": 1
+ },
+ {
"name": "changelogs/fragments/248_ds_update_error_grafana_9.yml",
"ftype": "file",
"chksum_type": "sha256",
@@ -267,6 +316,13 @@
"format": 1
},
{
+ "name": "changelogs/fragments/285_fix_doc.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "eed5d4709bb9447344c7ca0d8fe47ca3ecb3641697b1e18de865e7ee6b0ec9eb",
+ "format": 1
+ },
+ {
"name": "changelogs/fragments/288_get_actual_org_encode.yml",
"ftype": "file",
"chksum_type": "sha256",
@@ -274,6 +330,146 @@
"format": 1
},
{
+ "name": "changelogs/fragments/294-bump-grafana-version.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "91f1f5dd43943a5955f18df300a3497c0d89c9fd54ee8ddb8fbbd881262aa10f",
+ "format": 1
+ },
+ {
+ "name": "changelogs/fragments/300_datasource_prometheus_time_interval.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f8b238f88f025de74c456235a2a04283d22233da36e33d4c8887bdca56d0fcd0",
+ "format": 1
+ },
+ {
+ "name": "changelogs/fragments/308_datasource_quickwit.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "da003c09e654cf46ca2de33f32782fdd30f19f5d3196d7d8b3258ff6804565d7",
+ "format": 1
+ },
+ {
+ "name": "changelogs/fragments/311_dashboard_check_mode.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0601ccd2ae0421c355e6183110c64df7243f93e1376f07cf593be5ff4a9f4470",
+ "format": 1
+ },
+ {
+ "name": "changelogs/fragments/318-org_users_by_org_name.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "23c95e1b4d10f2a89dfb8a2857af543b08361ac54e831919c46f30a03f749301",
+ "format": 1
+ },
+ {
+ "name": "changelogs/fragments/321-action-groups-org-users.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f559e5db8e8b85da1b937996024f5f0c23324d40ea6ee5d7fc5c419aa71ebb95",
+ "format": 1
+ },
+ {
+ "name": "changelogs/fragments/324_formatting.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "25665f818c24b36058bcaa706604440967276be1296a2bdc6037271519505e04",
+ "format": 1
+ },
+ {
+ "name": "changelogs/fragments/325_linting.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "af5aec2049dfeae982e2d47daa44e6e84a5f800092b4b818fa8d2a569afbe511",
+ "format": 1
+ },
+ {
+ "name": "changelogs/fragments/325_true_false.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "14a107d144554667832aec72c86f83c5a0fecb31c8645daec3c6933906633459",
+ "format": 1
+ },
+ {
+ "name": "changelogs/fragments/331-dashboard-by-org-name.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "57095fa0bcf6aea3b7f2b79565d3d4f71d01c9d3735ee7044041217c518c4439",
+ "format": 1
+ },
+ {
+ "name": "changelogs/fragments/332-datasource-by-org-name.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "31ad79d93624848dc7b4a30c79938200b94a809ae84df411e7afb993b32529bc",
+ "format": 1
+ },
+ {
+ "name": "changelogs/fragments/335-add-datasource-type-tempo.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "da3c13510502e83b46b7ddc8fffe7d007ec76b4586f311d59c9e7dc33e424754",
+ "format": 1
+ },
+ {
+ "name": "changelogs/fragments/339-lint-black.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "60ede1111ab7b74ab1f933bfe06df23bbcc2fed7fe1cd60270095d6ab315572f",
+ "format": 1
+ },
+ {
+ "name": "changelogs/fragments/341-lint-ruff.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c1549e022f201f9e5dc7d984a84a38a10bce720f12b046abfcaeab24ddfd27b8",
+ "format": 1
+ },
+ {
+ "name": "changelogs/fragments/342-ruff-findings.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ce61f53984c913b4c8f7bbc099938fce8aed19d566422e530b427d7685b797fa",
+ "format": 1
+ },
+ {
+ "name": "changelogs/fragments/343-telekom-mms-role.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "bfe2053658fe18ffcefbb8b3d7f739281ae24693c16d36b13189229994d3e07c",
+ "format": 1
+ },
+ {
+ "name": "changelogs/fragments/345-datasource-compare-diff-orgid.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "4698e5052edfce0dc51171d390bb7070e8a70bd3181475e6d8f1f90abe7695db",
+ "format": 1
+ },
+ {
+ "name": "changelogs/fragments/347-folder-for-orgs.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "55a59bceab13dfa96e7a63a0a9b0912ecf9248ae8a9037ffff49ecc78a716ad9",
+ "format": 1
+ },
+ {
+ "name": "changelogs/fragments/349-role-notification-channel.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e46d6a7d7175a33ba08ce335b4fc839164afd9d49ea788bc71777e4aee3ec4fb",
+ "format": 1
+ },
+ {
+ "name": "changelogs/fragments/350-python3.12.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "38410fc78c051c85a770d57487c0e44afcfb7788cc23dc675b47018c31ca2be0",
+ "format": 1
+ },
+ {
"name": "changelogs/fragments/add-units-datasource.yml",
"ftype": "file",
"chksum_type": "sha256",
@@ -302,6 +498,13 @@
"format": 1
},
{
+ "name": "changelogs/fragments/fix-316.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "599f961644d8b43f3f8d1c291b4ff1db8c09834d8c493560b91e030f7f2dfb7d",
+ "format": 1
+ },
+ {
"name": "changelogs/fragments/fix_slashes_in_datasources.yml",
"ftype": "file",
"chksum_type": "sha256",
@@ -340,7 +543,7 @@
"name": "changelogs/changelog.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "672317831941badc24b8b2b99f256386289e6774791ad54e107bd1a20cab4e0b",
+ "chksum_sha256": "641de48bd2e1d3ab8daeace7b522413299bd4d2521204d1f707e8c23bb445480",
"format": 1
},
{
@@ -375,14 +578,14 @@
"name": "hacking/find_grafana_versions.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f208e226d9f51971c45afd07149e2f9b6a6b583b35abde56c75bacba9961e84d",
+ "chksum_sha256": "39acc81ec9733183bbb4eeae0c10c3aeecdeedd1ffc2dabcc675b84e16565f3e",
"format": 1
},
{
"name": "hacking/requirements.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f68f48b3014372d3e3859aac2030508871fb7f8cd29a5e5b51be92674a192570",
+ "chksum_sha256": "1d277ef3981a3e49b02912a0f03fe1ab563539d7e4e1b5c1e6404a57b19d883f",
"format": 1
},
{
@@ -396,7 +599,42 @@
"name": "meta/runtime.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ad30b0b10736f60b92a231e7f825472184755320479821a6486acbc6b502b4f0",
+ "chksum_sha256": "6872a5ea5042e0a7a43f2b60fe6c02a24e3e76b25deb50a46567df781345e41b",
+ "format": 1
+ },
+ {
+ "name": "molecule",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "molecule/default",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "molecule/default/converge.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c1e0e02c807ceafdf7bd707e0def1e9d2118e6389af9af44dc832dfc0483dab9",
+ "format": 1
+ },
+ {
+ "name": "molecule/default/molecule.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "93fdbc0ddeba791f7c430b0838ef87de49feb9b0662b8b2f1502b5a949e1c301",
+ "format": 1
+ },
+ {
+ "name": "molecule/default/test_dashboard.json",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ce0f583b94ead7ef7e0ae7e696dc87fefb2ba70106b2fda6cf072f17f8d1a136",
"format": 1
},
{
@@ -424,7 +662,7 @@
"name": "plugins/callback/grafana_annotations.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fac40baac9edab0ff30d12f63ee7d13f29f1dd4777d65f3a3a80d04cffb5a2e2",
+ "chksum_sha256": "2f0a1b0cdb40b90e44dd5c23bba4f65773a163cc92ca26263ca20de5a702e8e0",
"format": 1
},
{
@@ -445,14 +683,14 @@
"name": "plugins/doc_fragments/api_key.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bb4e6492b954294664aa87ac44bd12ffa42e59ddfcedd693e5a486b42c352dc1",
+ "chksum_sha256": "624cdc3b10d6a2bbdf9cd7d58fa47281658aa8b1377e702a8ecc6ca1f43bf630",
"format": 1
},
{
"name": "plugins/doc_fragments/basic_auth.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fff91970e34eca089abc8275b82957c07acd78889db684281be97252a5b6d27b",
+ "chksum_sha256": "4e16ce6e91408d53d9b482bfdfc1fd5919801aeaa00830e2703bae467fcc3a3d",
"format": 1
},
{
@@ -473,7 +711,7 @@
"name": "plugins/lookup/grafana_dashboard.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a2329d0c45e452ae9c63ed39a921de5aa7b073be4b405eccfde4abdae6603055",
+ "chksum_sha256": "7483dabbd84c95d3cd603e2d9d905b51f00e9f6ab4974164f31387c3ee63535d",
"format": 1
},
{
@@ -487,7 +725,7 @@
"name": "plugins/module_utils/base.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f3a2355da8ff10f76b0a5886d5915556efd87942a640d9f31fb84fe09b4e35c5",
+ "chksum_sha256": "edc463e8bea58732fd5a43b11c31c86b06ca5f5f5af1c81e4c0e1cc8a00ee59c",
"format": 1
},
{
@@ -508,56 +746,126 @@
"name": "plugins/modules/grafana_dashboard.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a941cd951e30bc40d8e50b5f94b6fce724e52c427043a45da3490c7d19b69710",
+ "chksum_sha256": "4f0fa0bd616646667b30cc6373a3983b802704396d0cba184173244b13820b7e",
"format": 1
},
{
"name": "plugins/modules/grafana_datasource.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7da547912f54e294da3ba2bd529a1541e7837e6d59f9657b32af1c842cb13eee",
+ "chksum_sha256": "23081add13f2aba994b4cddb264972d219bee823ac1e4f454931d5a6a374bd94",
"format": 1
},
{
"name": "plugins/modules/grafana_folder.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3f8b5ff973317b96b2df44d557b4541e3f8878f31c3ac9524e670900a4d94c23",
+ "chksum_sha256": "0690d114c97f3cfabc115b17b1e90c9304737d6681085473f7321365797be9b8",
"format": 1
},
{
"name": "plugins/modules/grafana_notification_channel.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f33607a8e2ab8b641f23e37c13c191d4b536d7f17a0e53167491341f0953ba36",
+ "chksum_sha256": "abfa2ecf38dfa35cfcf4ee3256a0f2f21fb33134669041c613c64522c27511a4",
"format": 1
},
{
"name": "plugins/modules/grafana_organization.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0770da78a9c0c20ecd893ffff6c949757b3d56e69512c074c097af210de62a95",
+ "chksum_sha256": "e3007e6f1b18309adf4c2d591cdf8fe7ff7095e16cb8f712d6118e353e74c4fb",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/grafana_organization_user.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "805358f94bc8d54afb5ceeba18f1539ace43f713c02175441d195837aa96da2e",
"format": 1
},
{
"name": "plugins/modules/grafana_plugin.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d655afaca63400ea116ea4a2f0629b3c9a614e363a3bc587bdfe40404b13865f",
+ "chksum_sha256": "fb0ee164a2936bc35381cf79026b6725c7a1df139e71d58989f8912432043c00",
"format": 1
},
{
"name": "plugins/modules/grafana_team.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "59d95c0432cdc854f7d9176e37c9c0ee0676c27678bbac5a467b762f4985a50e",
+ "chksum_sha256": "1f455f7615dcc33a7612b2dd6e881dbc90d37fadc02bcd1c9b8edcf3c80cc1f5",
"format": 1
},
{
"name": "plugins/modules/grafana_user.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "74081babe6e887d9701f85ad6cfba434d534480b84d8eca89c47c587b7f4400b",
+ "chksum_sha256": "0b1c4c363f47bcdda8f909005816a7f9a87c691050d5123e0b2f3ad2da7cbaed",
+ "format": 1
+ },
+ {
+ "name": "roles",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "roles/grafana",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "roles/grafana/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "roles/grafana/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ee6026b2dd62777a731f2214949124f45d73309102123cad31ad55489a90ca45",
+ "format": 1
+ },
+ {
+ "name": "roles/grafana/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "roles/grafana/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "192ef2ac687cd5594febffbc0ab6f3d184cceed34dc66c11ff217db19f4ccfc2",
+ "format": 1
+ },
+ {
+ "name": "roles/grafana/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "roles/grafana/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0de2cd11feb7e45f3427d063c3123024f94401bc5c1b48eaecea9716efcc03d5",
+ "format": 1
+ },
+ {
+ "name": "roles/grafana/README.md",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ab4f69856777b7b0c208c3c3d06a9771c98f81a729618dc94df80ea981b1b6ab",
"format": 1
},
{
@@ -599,7 +907,7 @@
"name": "tests/integration/targets/grafana_dashboard/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1abe5b960f170fe88ae3643d49bb82030dec115a22324db1664f6b52dfc874a8",
+ "chksum_sha256": "3080ff0153745941649566c421bdd85715c4174dc651656a241aef27be424ae7",
"format": 1
},
{
@@ -624,52 +932,59 @@
"format": 1
},
{
+ "name": "tests/integration/targets/grafana_dashboard/tasks/dashboard-by-org-name.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "a43bbb6de9a723b95b69c7c51663f1b4601a58353ca226b63a1df474b800590a",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/grafana_dashboard/tasks/dashboard-export.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5f6af8316c89f6a61b424540b5779682e9a411052b63c94d3d411a926a38cc1a",
+ "chksum_sha256": "6a1fc18ba64dd7e8f1aa7ca2633608e2932e34147acbf2974e8d882ac0087189",
"format": 1
},
{
"name": "tests/integration/targets/grafana_dashboard/tasks/dashboard-folder-destination.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "621fd78f70b4381fc4a346b59f8c71886a74283d439debe973e6a90677322ae1",
+ "chksum_sha256": "23e068c4c5a4d2e77166bc442aa40d61678a09f5923e392bc9ed45be961cd238",
"format": 1
},
{
- "name": "tests/integration/targets/grafana_dashboard/tasks/dashboard-from-file.yml",
+ "name": "tests/integration/targets/grafana_dashboard/tasks/dashboard-from-file-export.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4987b17b353b126c059e60e83ea081eacd83b149d6aeed0ab9d34c013322d574",
+ "chksum_sha256": "3d80e67a2a60f491578a45be9cce19178a9fb675c2fd04932c353d984db9591d",
"format": 1
},
{
"name": "tests/integration/targets/grafana_dashboard/tasks/dashboard-from-id.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f679381b8db000fb5bf0e1166fd78196a63efc8c0bba4a8917ae02f85e54c295",
+ "chksum_sha256": "d2b528f99db43d1a36c10aedcfca5cf98dd3c34c0087a3d5a0c12ac43871efd1",
"format": 1
},
{
"name": "tests/integration/targets/grafana_dashboard/tasks/dashboard-from-url.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "468c55bbc58254f1e956f8b6eaf318b863e88270f9741a05fd63643d18ced748",
+ "chksum_sha256": "d1bb246bb41e3b47171953bb4194988ae57015b462208287b5e678e157197776",
"format": 1
},
{
"name": "tests/integration/targets/grafana_dashboard/tasks/delete-dashboard.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "abaf3c4b643d2f893fd05849de8ee8f15ed14ae74a24cb9b252db54c64415478",
+ "chksum_sha256": "7544b7ea2374965a6b14ef47c517058ecc614ed2ce388ed96c7301670b4d2a3e",
"format": 1
},
{
"name": "tests/integration/targets/grafana_dashboard/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "83298bca7c6ae5f5467168e5c75dbf34497d458f81258935c1b929126b984916",
+ "chksum_sha256": "9ac539607fab1744739465d19d35eb69337d367f4834f5b260a9f83ccb34a225",
"format": 1
},
{
@@ -680,6 +995,20 @@
"format": 1
},
{
+ "name": "tests/integration/targets/grafana_dashboard/runme.sh",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "b9aa6c8dadef0b4ce9cb08a05d0cf6c40f882d04f9e698bff795b26896e8853c",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/grafana_dashboard/site.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f30cb92dff7bcfa3c7b92ea0fb4d0cd62d2704f282f9a74bd68a5ba3ac34b142",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/grafana_datasource",
"ftype": "dir",
"chksum_type": null,
@@ -697,7 +1026,7 @@
"name": "tests/integration/targets/grafana_datasource/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1abe5b960f170fe88ae3643d49bb82030dec115a22324db1664f6b52dfc874a8",
+ "chksum_sha256": "d7d3a06f224d1576e39fcc2083e33261f30e3ceac18506f17772d8bcb72315c2",
"format": 1
},
{
@@ -711,91 +1040,105 @@
"name": "tests/integration/targets/grafana_datasource/tasks/azure.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "19ee9ae9eb2a07401743f0cbe9618c10765b9fe008070344676e9c49aa385a14",
+ "chksum_sha256": "e7ebd714ea8613e5bdfb5ed632526f6435978dfe164e2358cb4d9fa000f7cf65",
"format": 1
},
{
"name": "tests/integration/targets/grafana_datasource/tasks/cloudwatch.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "464c12422283a217c8075285d2ea2c05b005b864ea4437c551701925ff44d7b7",
+ "chksum_sha256": "d3acce4b415027eebf9cef909e2b351fdcf6fadc8fc441da205db041a595010b",
"format": 1
},
{
"name": "tests/integration/targets/grafana_datasource/tasks/elastic.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1635d2de6380a9ee458af3ca590f5640b22381bb12417f6bf4dfbdeebc2f4757",
+ "chksum_sha256": "69fba433ef869f3bb1916f2036a43985af48d21118f08e969f6020532a963d43",
"format": 1
},
{
"name": "tests/integration/targets/grafana_datasource/tasks/errors.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a0d109a1c3408a51bde3d5cf753990c46176d8372164b7e4a2f681dae3920352",
+ "chksum_sha256": "10fac33e0d5bb44d834579e719c498e4e0eb91535625881bb8cb027dc778c39a",
"format": 1
},
{
"name": "tests/integration/targets/grafana_datasource/tasks/influx.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2ce76fc18d2405a0ac4964cac4b6aa2a6685788c98bc42a1b2de3ac8e907e02b",
+ "chksum_sha256": "7852e7f6e7cb6bd5359a29766fa1810faead04e5760536dc5812fafdf32c7e67",
"format": 1
},
{
"name": "tests/integration/targets/grafana_datasource/tasks/issues.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "432147d3f437fb0438de8e13581d6c878ef9f74c4fdf8c2c343be2772003608d",
+ "chksum_sha256": "4ea6ef2c0ff7ab17d4f454b0aca0429dba3bed373b9e7e9f45679354bbb197b6",
"format": 1
},
{
"name": "tests/integration/targets/grafana_datasource/tasks/loki.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9a4b7278d0b86f6a140f618fae5ca135078c4e2c6f45c5c9ce1d392e5bc51e00",
+ "chksum_sha256": "7f6a14c7eb76ee8c8846955ff98bd71c082b741dc1d67b5c7e0f2dd188eea8de",
"format": 1
},
{
"name": "tests/integration/targets/grafana_datasource/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "721d230780309d65c7e436717d0c5097886a4d8952c51b4a3b60ee6191f37a8f",
+ "chksum_sha256": "713a162941560a20ecadd97bd185b09e8a0073451286554ead9c7a8deb71b08f",
"format": 1
},
{
"name": "tests/integration/targets/grafana_datasource/tasks/postgres.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "705a43192be5211f28a87f6b4123859b98fe8b286ba340a3baf0cc6331afcd99",
+ "chksum_sha256": "4ed316aab332c0dfcc005213ef28087ea49ed011c0a73bdd0e5f8481e9403de4",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/grafana_datasource/tasks/quickwit.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "3a2adf0e3207fe51808c044312d537f11321cf0b685eb4f1e01f1dfdafad54e9",
"format": 1
},
{
"name": "tests/integration/targets/grafana_datasource/tasks/redis.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "95b32572dabe963cc378c6256b442febb157a41aac8a88b7dfe8aee9010a4bb2",
+ "chksum_sha256": "18869fb58bfbd29d666c02c18a25050fdd87fb6efe6f3945c7d472ab00addc22",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/grafana_datasource/tasks/tempo.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "d9626fb7988f6c16a407d15d0397a4a2fee1b4a25ec1e8c256441afcdcfdbfa4",
"format": 1
},
{
"name": "tests/integration/targets/grafana_datasource/tasks/thruk.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "305abe7c14283b27645b7cf40e6e72f37d7c981cf4ec8802624534cbd566bee6",
+ "chksum_sha256": "40964d1ada4844b2896d15e8d6291fcc3cce2de461e23d6a484271ecbe01bea4",
"format": 1
},
{
"name": "tests/integration/targets/grafana_datasource/tasks/uid.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "08990e1b6427c88c54e19eb5bb1ecf7982e82225398dc99df095a8a8d757290b",
+ "chksum_sha256": "3cd162f42bd87ed70b42a7f1eec4465f46470f959e1995d4da16ba7c985cbab5",
"format": 1
},
{
"name": "tests/integration/targets/grafana_datasource/tasks/zabbix.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c6a9c292a023c3da296ac2bd326b90c376b2302e07ce94808172313891421f36",
+ "chksum_sha256": "c2871a04f46eea697114ace8a8ed977e35db18617b6d7d605895d8dc42231d70",
"format": 1
},
{
@@ -806,6 +1149,20 @@
"format": 1
},
{
+ "name": "tests/integration/targets/grafana_datasource/runme.sh",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "b9aa6c8dadef0b4ce9cb08a05d0cf6c40f882d04f9e698bff795b26896e8853c",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/grafana_datasource/site.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "16d7e16475eb96288139560e75d3f538a276ce843d42c922b73bcbdb3061129e",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/grafana_folder",
"ftype": "dir",
"chksum_type": null,
@@ -823,7 +1180,7 @@
"name": "tests/integration/targets/grafana_folder/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1abe5b960f170fe88ae3643d49bb82030dec115a22324db1664f6b52dfc874a8",
+ "chksum_sha256": "d7d3a06f224d1576e39fcc2083e33261f30e3ceac18506f17772d8bcb72315c2",
"format": 1
},
{
@@ -834,10 +1191,38 @@
"format": 1
},
{
+ "name": "tests/integration/targets/grafana_folder/tasks/create-delete.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "122f5e9db2674a05c1ee476e946dae3a04e3cd321665c7db71b2cba315097d20",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/grafana_folder/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "47bc05ebcddd2fe27fa914c732be64a7c2c6378578d5c8cb6429d73f25d355f5",
+ "chksum_sha256": "ff5d04e49ad1db4a7020371f3aac554a0f92221b317cd8dba41aade14495a32d",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/grafana_folder/tasks/org.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f334b190c923087495214249c3d63199bfdbd9c16b92f3402ab0bbdd4baceee7",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/grafana_folder/runme.sh",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f93043b637d08213e98b76e867cf233123d527d183441230d495fd192ebb0ebe",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/grafana_folder/site.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "826699299c1afe13404ece8b0ba37677617244fa6d31479b94ef8fceb86ba40a",
"format": 1
},
{
@@ -858,7 +1243,7 @@
"name": "tests/integration/targets/grafana_notification_channel/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1abe5b960f170fe88ae3643d49bb82030dec115a22324db1664f6b52dfc874a8",
+ "chksum_sha256": "d7d3a06f224d1576e39fcc2083e33261f30e3ceac18506f17772d8bcb72315c2",
"format": 1
},
{
@@ -872,133 +1257,147 @@
"name": "tests/integration/targets/grafana_notification_channel/tasks/dingding.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "20be703a675310b8986c39720a30cbca5697519aeee1036d735af61608a66cc8",
+ "chksum_sha256": "71fe4171eff7055caae552fd9baf97bf09ddbab7ea9f4d30ad0329fd0ee57ba5",
"format": 1
},
{
"name": "tests/integration/targets/grafana_notification_channel/tasks/discord.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a24f0816c122f278575acf3269028c027d7056350213d5bf79d7e32a87cabb92",
+ "chksum_sha256": "783aedab3656a22446c4d7d66cb73b9098a0a417501618314e8ee016c7f823e7",
"format": 1
},
{
"name": "tests/integration/targets/grafana_notification_channel/tasks/email.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "70de3340f20f09e20f1a9f6bcb9cdc71133e9d3ca5299a56e29ded8941402c4e",
+ "chksum_sha256": "bae730db1d3ae0f9c48b620910e22e084fbb2cd78435cded44d08aab03c49017",
"format": 1
},
{
"name": "tests/integration/targets/grafana_notification_channel/tasks/googlechat.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a8fc0c11896c5831c6295818e9a2142b51906a1d3b32ca2865f8323be48d8dfe",
+ "chksum_sha256": "ed076cea03274dc08b91cfe11440f7d9ed56991192ec8e4ce5fc6aead9932d50",
"format": 1
},
{
"name": "tests/integration/targets/grafana_notification_channel/tasks/hipchat.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fbe650e907a7327d069f72b0077cd563cb7016cbf6d51703bf5f463c7e22488b",
+ "chksum_sha256": "974a0df2c6fbc614f3cb0110a72437744b528d057fcd07065754e1f0d075f572",
"format": 1
},
{
"name": "tests/integration/targets/grafana_notification_channel/tasks/kafka.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "eb784a102669f4f2d087ae644c63f7f2e09e60363b47acea59ccce9299b3ed78",
+ "chksum_sha256": "d911f680a1dab3c7c6ca24062b07daa650c14cf95d41bb4b3b5f1a03f82bea8e",
"format": 1
},
{
"name": "tests/integration/targets/grafana_notification_channel/tasks/line.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a997b83ad729061f48299a94c609db3eab3f315f4febc86d3e97bc06c0263fec",
+ "chksum_sha256": "0793dcafac5c6baadd8f807f5738b0f43c1043fcaf5461548608a3f788144900",
"format": 1
},
{
"name": "tests/integration/targets/grafana_notification_channel/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "603d4be7ff5a3e2685e3e0c2bc51a526222d29c20f63a4b7d301110566a4f765",
+ "chksum_sha256": "3928211b941d3ec67d73d44122519b76364772a9ab79c731a8b5e5f22e46078b",
"format": 1
},
{
"name": "tests/integration/targets/grafana_notification_channel/tasks/opsgenie.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0a3eb750d61a5a3d26434f25b09681a5ac3b27f94bb6d72eb2879e4a5157194d",
+ "chksum_sha256": "10a080ac4ab19d1c2ab7e2c1e1558acb7e11a3e75ae3c7ed3f90f56ef9425fef",
"format": 1
},
{
"name": "tests/integration/targets/grafana_notification_channel/tasks/pagerduty.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d781b916d195e780653185c46aae0cf5007dbc9c92920cd380203164c7512d4e",
+ "chksum_sha256": "5988e630d581c1c2d715e5f617104c8e8ecabb8ecc2c85d18491b3ba16e7ff8c",
"format": 1
},
{
"name": "tests/integration/targets/grafana_notification_channel/tasks/prometheus.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d893bb8c7f3cddacce404325ce903c5f91d1760ebf17b123a9e2ec58b9d262c6",
+ "chksum_sha256": "abf6e31f7f4485b1b1821e178cd90063572726958c26e724ccc2f0417d8b5999",
"format": 1
},
{
"name": "tests/integration/targets/grafana_notification_channel/tasks/pushover.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1f7313a53d5d3e38de3f79fe1c89be297eac4ffe366cb88872b989354f3beb6a",
+ "chksum_sha256": "afaf52cddb757eb1a5ad988e5ac07638269d9e8669136db07f6d909d7b9f74f9",
"format": 1
},
{
"name": "tests/integration/targets/grafana_notification_channel/tasks/sensu.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "542998ba92afda7d9e84204f4792be3f094059fe3b3aa85ec4f8cd8ca8e1f7f5",
+ "chksum_sha256": "cfa23b2fdd7f2aa998f568177dc029a92c10b00492a6dcb9c575d8aaf06af9a4",
"format": 1
},
{
"name": "tests/integration/targets/grafana_notification_channel/tasks/slack-and-beyond.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5e07153d379c3ed98207b7a9cab4e291962ecf2b493c78e430bb187ad77b3553",
+ "chksum_sha256": "8666a93b31846da1f4eef2e632a1e9c1d62dc765691733647b828229dd16f2f4",
"format": 1
},
{
"name": "tests/integration/targets/grafana_notification_channel/tasks/teams.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9cf484e386db1b5f0b39a97e419127c0c23ef016a8cdf307a46f1a43b6d13b50",
+ "chksum_sha256": "b95ee61e08caf11be5917c421e82feab4e108c5bd05d7eca2804e0bf3dfa69dd",
"format": 1
},
{
"name": "tests/integration/targets/grafana_notification_channel/tasks/telegram.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "881e193e76bc7c63213ccc4d29e9e91831618760edfa33b4d80381799d5684b4",
+ "chksum_sha256": "5ef4e24ceb5a814dde62620e98f3d47cd748fa0800ff5db398aa4a8726ee3b4f",
"format": 1
},
{
"name": "tests/integration/targets/grafana_notification_channel/tasks/threema.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ab5586f7f1be5494b306bc7db62bd147f76f8d9c2269d3109b4d20ea7ca27e5b",
+ "chksum_sha256": "dc35cc7b06bd8f2c4194ccad905bb3aa66053c8f30b2fa6c67626a798710b096",
"format": 1
},
{
"name": "tests/integration/targets/grafana_notification_channel/tasks/victorops.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6676ea8941ac8758a8b7b68c0d620a02fba4aa46a3208a6143dac3c23a4359c0",
+ "chksum_sha256": "2da1bc74d6e1dc2ecfbf2625c9228a13e72015a37a646baa65343fe0dd4f57b1",
"format": 1
},
{
"name": "tests/integration/targets/grafana_notification_channel/tasks/webhook.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7c9625e9e31301fc7ffa49c384b211f2d68fba895f8358eafd403403de023acc",
+ "chksum_sha256": "ab506c8c1fc656f62b8bfa34d5ac877086ce6918b7282e22f5d2c0d88cd97475",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/grafana_notification_channel/runme.sh",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "b9aa6c8dadef0b4ce9cb08a05d0cf6c40f882d04f9e698bff795b26896e8853c",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/grafana_notification_channel/site.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6b38ec20b7346f0bd7ad39edb98487a6c123d3e0c5a86671ab5f81bc6f77d30c",
"format": 1
},
{
@@ -1019,7 +1418,7 @@
"name": "tests/integration/targets/grafana_organization/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5a300746bed6ecd05371181b97507a46472e5379002f23590c6d3a38b576be68",
+ "chksum_sha256": "3080ff0153745941649566c421bdd85715c4174dc651656a241aef27be424ae7",
"format": 1
},
{
@@ -1033,7 +1432,70 @@
"name": "tests/integration/targets/grafana_organization/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "49205778d4eacf15c53b6b0e69f3f78c02cb758d235a64636523c82fec9a26e0",
+ "chksum_sha256": "5fe8af2ef9401defb8f328e0a24b4184bf1e3309aa8be51c983b34edaa85f234",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/grafana_organization/runme.sh",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f93043b637d08213e98b76e867cf233123d527d183441230d495fd192ebb0ebe",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/grafana_organization/site.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "b29bfe7832b74990a2f2a34f268d16946dca7a1fce852b4ef6c29106ffdc510f",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/grafana_organization_user",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/grafana_organization_user/defaults",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/grafana_organization_user/defaults/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "3080ff0153745941649566c421bdd85715c4174dc651656a241aef27be424ae7",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/grafana_organization_user/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/grafana_organization_user/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "4886c04060faeb0617ab4637269d4ba52279e36169cc508e6231ea63773a38b9",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/grafana_organization_user/runme.sh",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f93043b637d08213e98b76e867cf233123d527d183441230d495fd192ebb0ebe",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/grafana_organization_user/site.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ff14af15f86f7b705bbc2505639b15edbd8124af4653a8ae12681ea05ac766fd",
"format": 1
},
{
@@ -1054,7 +1516,7 @@
"name": "tests/integration/targets/grafana_team/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1abe5b960f170fe88ae3643d49bb82030dec115a22324db1664f6b52dfc874a8",
+ "chksum_sha256": "d7d3a06f224d1576e39fcc2083e33261f30e3ceac18506f17772d8bcb72315c2",
"format": 1
},
{
@@ -1068,14 +1530,28 @@
"name": "tests/integration/targets/grafana_team/tasks/create_user.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1c95f96aaaf709c403a815f6bee8ffe0e1a0acf4bf860b04b84fdeb1e2640d70",
+ "chksum_sha256": "4d64425f6cc9da06d28a9ca5332b1056b01d65396a5a59f8f0d7c592f6f028b3",
"format": 1
},
{
"name": "tests/integration/targets/grafana_team/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "849f63851576fe7d459f0e69380fbf6915606bbdebf3836d36301d594ddde9e7",
+ "chksum_sha256": "3a251b9f1794ca36ff3d9025145ad0f639082d3185772115fdac6eeda2fab8b2",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/grafana_team/runme.sh",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "b9aa6c8dadef0b4ce9cb08a05d0cf6c40f882d04f9e698bff795b26896e8853c",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/grafana_team/site.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e729b0be1c515ad93b175d7f024bae9232365faaa68a4506b47967447dfa7e65",
"format": 1
},
{
@@ -1096,7 +1572,7 @@
"name": "tests/integration/targets/grafana_user/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5a300746bed6ecd05371181b97507a46472e5379002f23590c6d3a38b576be68",
+ "chksum_sha256": "3080ff0153745941649566c421bdd85715c4174dc651656a241aef27be424ae7",
"format": 1
},
{
@@ -1110,7 +1586,21 @@
"name": "tests/integration/targets/grafana_user/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "dee06bc10461e6607b56babd7767b70336a3469ba2fcbc687a3f430b4b89e42c",
+ "chksum_sha256": "b87f7be9298d38992197ddba80c4a9049a314604867772780040e53f6a1a2368",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/grafana_user/runme.sh",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f93043b637d08213e98b76e867cf233123d527d183441230d495fd192ebb0ebe",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/grafana_user/site.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e19f63916db02291f7340bcfbaadde68e2063c98ebd570151e51b2590ba55006",
"format": 1
},
{
@@ -1163,6 +1653,20 @@
"format": 1
},
{
+ "name": "tests/sanity/ignore-2.16.txt",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0908af1f4e86722688b3f158cfa9cc81c931ef40c0a166c398f47a4af69a93f9",
+ "format": 1
+ },
+ {
+ "name": "tests/sanity/ignore-2.17.txt",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0908af1f4e86722688b3f158cfa9cc81c931ef40c0a166c398f47a4af69a93f9",
+ "format": 1
+ },
+ {
"name": "tests/sanity/ignore-2.9.txt",
"ftype": "file",
"chksum_type": "sha256",
@@ -1201,7 +1705,7 @@
"name": "tests/unit/modules/grafana/grafana_datasource/test_grafana_datasource.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a2e07e9ebe4ff689cf3a7a6f17fe7a15bb498787d3f34b2b04e8c6a60faec054",
+ "chksum_sha256": "f7163648b75242c0acbfe2b3cd911ae3119107bfe9578019443fe887b0f6dbf9",
"format": 1
},
{
@@ -1215,7 +1719,7 @@
"name": "tests/unit/modules/grafana/grafana_plugin/test_grafana_plugin.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c7b7015b793f75de5c19cd95772a8aaa170eca6e508a305755f61ae11495e4f1",
+ "chksum_sha256": "ada20cb8aef9852aee7b79afddd78f144f813c9df55baf3b8adc1b3863a8e9db",
"format": 1
},
{
@@ -1229,7 +1733,7 @@
"name": "tests/unit/modules/grafana/grafana_team/test_grafana_team.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "96116b92002f89708a978cf54ba9209234bc65622b82ea37f67b942a8d19b849",
+ "chksum_sha256": "53ca8d47d277ebe320b112ccc59a91e6cd0eae6194eecc1991b8e08977fa2c96",
"format": 1
},
{
@@ -1243,7 +1747,7 @@
"name": "tests/unit/modules/grafana/grafana_user/test_grafana_user.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ebe4eca4179be5a9780ef606dbd01da1e8512df914b9d576a256a9f0b72c66bb",
+ "chksum_sha256": "02409b123e54c08c9c5e3ce8bdd0213464c00659490873e07cbfbfdc2cec7c7c",
"format": 1
},
{
@@ -1254,24 +1758,31 @@
"format": 1
},
{
+ "name": "tests/requirements.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "697e4332a08c9c12c77188df7cf1e687151c9d77e61a3b08f879a825d869f6b4",
+ "format": 1
+ },
+ {
"name": ".all-contributorsrc",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2ef91cc790e39c200094615d52b2d5a7efcddf6ec2f95d1324a5664b8ed5f35b",
+ "chksum_sha256": "00fabf54b7d76fb7d88baea1a20fcfb7e5f3b3a11532d9b8bc474a063bc98a8c",
"format": 1
},
{
"name": ".gitignore",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0a44bd2b8e7c35cfad385b8f440c3ec6ebcf8bd10248cf5925d2ceacc92f8078",
+ "chksum_sha256": "b42461ab9570bb951c6614a223aab90b258464234d72e53bfb3853ec69006c5e",
"format": 1
},
{
"name": "CHANGELOG.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4840bdb66ca2d031a29df53e3a2e7f9bf3da209fb1fb6ef9a4c6284e6791c56b",
+ "chksum_sha256": "e20df0ad2408ce9c311cf3bf18c99b2362c6eee388db48286b13be28ecedd8db",
"format": 1
},
{
@@ -1285,14 +1796,21 @@
"name": "README.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5b3523fbf8ffe4c3f7f503f6e63c294c33d0d074588d9e1f278b035676c34336",
+ "chksum_sha256": "8e93c6a3ce656865252643666a94835e98d904107d7a678f0a74774445f91125",
"format": 1
},
{
"name": "codecov.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4b37d1d2f2d4ddf5ad85e350ea6e0b6c18b1d09de82807847a230883a19abde4",
+ "chksum_sha256": "187229d57b799f65a9da46cafe34a880c14240022bdbb9b8d447a85de31aa02c",
+ "format": 1
+ },
+ {
+ "name": "ruff.toml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9b50c21301c083a2c248259c891bed4403e917cc268ffc236f652e73e2869c15",
"format": 1
}
],
diff --git a/ansible_collections/community/grafana/MANIFEST.json b/ansible_collections/community/grafana/MANIFEST.json
index e1c676340..71f9afdc1 100644
--- a/ansible_collections/community/grafana/MANIFEST.json
+++ b/ansible_collections/community/grafana/MANIFEST.json
@@ -2,7 +2,7 @@
"collection_info": {
"namespace": "community",
"name": "grafana",
- "version": "1.5.4",
+ "version": "1.8.0",
"authors": [
"R\u00e9mi REY (@rrey)",
"Thierry Sall\u00e9 (@seuf)"
@@ -25,7 +25,7 @@
"name": "FILES.json",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "035021ce8ce32b6ab7857a4f7acf48a7911b14c718c7f9625ead4d097e51788d",
+ "chksum_sha256": "98a10c2378e1ad46d7031d895c557d33af10809314832b9e3af5c2e607099e0b",
"format": 1
},
"format": 1
diff --git a/ansible_collections/community/grafana/README.md b/ansible_collections/community/grafana/README.md
index bf416426d..6d23f1b96 100644
--- a/ansible_collections/community/grafana/README.md
+++ b/ansible_collections/community/grafana/README.md
@@ -3,7 +3,7 @@
![](https://github.com/ansible-collections/grafana/workflows/CI/badge.svg?branch=master)
[![Codecov](https://img.shields.io/codecov/c/github/ansible-collections/community.grafana)](https://codecov.io/gh/ansible-collections/community.grafana)
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
-[![All Contributors](https://img.shields.io/badge/all_contributors-18-orange.svg?style=flat-square)](#contributors-)
+[![All Contributors](https://img.shields.io/badge/all_contributors-20-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->
This repo hosts the `community.grafana` Ansible Collection.
@@ -27,6 +27,7 @@ Click on the name of a plugin or module to view that content's documentation:
- [grafana_folder](https://docs.ansible.com/ansible/latest/collections/community/grafana/grafana_folder_module.html)
- [grafana_notification_channel](https://docs.ansible.com/ansible/latest/collections/community/grafana/grafana_notification_channel_module.html)
- [grafana_organization](https://docs.ansible.com/ansible/latest/collections/community/grafana/grafana_organization_module.html)
+ - [grafana_organization_user](https://docs.ansible.com/ansible/latest/collections/community/grafana/grafana_organization_user_module.html)
- [grafana_plugin](https://docs.ansible.com/ansible/latest/collections/community/grafana/grafana_plugin_module.html)
- [grafana_team](https://docs.ansible.com/ansible/latest/collections/community/grafana/grafana_team_module.html)
- [grafana_user](https://docs.ansible.com/ansible/latest/collections/community/grafana/grafana_user_module.html)
@@ -36,7 +37,7 @@ Click on the name of a plugin or module to view that content's documentation:
We aim at keeping the last 3 Major versions of Grafana tested.
This collection is currently testing the modules against following versions of Grafana:
```
-grafana_version: ["9.2.6", "8.5.15", "7.5.16"]
+grafana_version: ["9.5.14", "8.5.27", "10.2.2"]
```
## Installation and Usage
@@ -66,12 +67,9 @@ You can either call modules by their Fully Qualified Collection Namespace (FQCN)
gather_facts: false
connection: local
- collections:
- - community.grafana
-
tasks:
- name: Ensure Influxdb datasource exists.
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: "datasource-influxdb"
grafana_url: "https://grafana.company.com"
grafana_user: "admin"
@@ -92,13 +90,11 @@ In your playbooks, you can set [module defaults](https://github.com/ansible/ansi
```yaml
+---
- hosts: localhost
gather_facts: false
connection: local
- collections:
- - community.grafana
-
module_defaults:
group/community.grafana.grafana:
grafana_url: "https://grafana.company.com"
@@ -107,7 +103,7 @@ In your playbooks, you can set [module defaults](https://github.com/ansible/ansi
tasks:
- name: Ensure Influxdb datasource exists.
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: "datasource-influxdb"
org_id: "1"
ds_type: "influxdb"
@@ -117,7 +113,7 @@ In your playbooks, you can set [module defaults](https://github.com/ansible/ansi
tls_ca_cert: "/etc/ssl/certs/ca.pem"
- name: Create or update a Grafana user
- grafana_user:
+ community.grafana.grafana_user:
name: "Bruce Wayne"
email: "batman@gotham.city"
login: "batman"
@@ -184,6 +180,7 @@ Any contribution is welcome and we only ask contributors to:
* Provide *at least* integration tests for any contribution.
* The Pull Request *MUST* contain a changelog fragment. See [Ansible documentation](https://docs.ansible.com/ansible/latest/community/development_process.html#creating-a-changelog-fragment) about fragments.
* Create an issue for any significant contribution that would change a large portion of the code base.
+* Use [ruff](https://github.com/astral-sh/ruff) to lint and [black](https://github.com/psf/black) to format your changes on python code.
## Contributors ✨
@@ -195,28 +192,30 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
<table>
<tbody>
<tr>
- <td align="center"><a href="https://github.com/gundalow"><img src="https://avatars1.githubusercontent.com/u/940557?v=4?s=100" width="100px;" alt="John R Barker"/><br /><sub><b>John R Barker</b></sub></a><br /><a href="#infra-gundalow" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="https://github.com/ansible-collections/community.grafana/commits?author=gundalow" title="Tests">⚠️</a> <a href="https://github.com/ansible-collections/community.grafana/commits?author=gundalow" title="Code">💻</a></td>
- <td align="center"><a href="https://github.com/rrey"><img src="https://avatars1.githubusercontent.com/u/2752379?v=4?s=100" width="100px;" alt="Rémi REY"/><br /><sub><b>Rémi REY</b></sub></a><br /><a href="https://github.com/ansible-collections/community.grafana/commits?author=rrey" title="Tests">⚠️</a> <a href="https://github.com/ansible-collections/community.grafana/commits?author=rrey" title="Documentation">📖</a> <a href="https://github.com/ansible-collections/community.grafana/commits?author=rrey" title="Code">💻</a></td>
- <td align="center"><a href="https://aperogeek.fr"><img src="https://avatars1.githubusercontent.com/u/1336359?v=4?s=100" width="100px;" alt="Thierry Sallé"/><br /><sub><b>Thierry Sallé</b></sub></a><br /><a href="https://github.com/ansible-collections/community.grafana/commits?author=seuf" title="Code">💻</a> <a href="https://github.com/ansible-collections/community.grafana/commits?author=seuf" title="Tests">⚠️</a></td>
- <td align="center"><a href="http://antoine.tanzil.li"><img src="https://avatars0.githubusercontent.com/u/1068018?v=4?s=100" width="100px;" alt="Antoine"/><br /><sub><b>Antoine</b></sub></a><br /><a href="https://github.com/ansible-collections/community.grafana/commits?author=Tailzip" title="Code">💻</a> <a href="https://github.com/ansible-collections/community.grafana/commits?author=Tailzip" title="Tests">⚠️</a></td>
- <td align="center"><a href="https://github.com/pomverte"><img src="https://avatars0.githubusercontent.com/u/695230?v=4?s=100" width="100px;" alt="hvle"/><br /><sub><b>hvle</b></sub></a><br /><a href="https://github.com/ansible-collections/community.grafana/commits?author=pomverte" title="Code">💻</a> <a href="https://github.com/ansible-collections/community.grafana/commits?author=pomverte" title="Tests">⚠️</a></td>
- <td align="center"><a href="https://github.com/jual"><img src="https://avatars2.githubusercontent.com/u/4416541?v=4?s=100" width="100px;" alt="jual"/><br /><sub><b>jual</b></sub></a><br /><a href="https://github.com/ansible-collections/community.grafana/commits?author=jual" title="Code">💻</a> <a href="https://github.com/ansible-collections/community.grafana/commits?author=jual" title="Tests">⚠️</a></td>
- <td align="center"><a href="https://github.com/MCyprien"><img src="https://avatars2.githubusercontent.com/u/11160859?v=4?s=100" width="100px;" alt="MCyprien"/><br /><sub><b>MCyprien</b></sub></a><br /><a href="https://github.com/ansible-collections/community.grafana/commits?author=MCyprien" title="Code">💻</a> <a href="https://github.com/ansible-collections/community.grafana/commits?author=MCyprien" title="Tests">⚠️</a></td>
+ <td align="center" valign="top" width="14.28%"><a href="https://github.com/gundalow"><img src="https://avatars1.githubusercontent.com/u/940557?v=4?s=100" width="100px;" alt="John R Barker"/><br /><sub><b>John R Barker</b></sub></a><br /><a href="#infra-gundalow" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="https://github.com/ansible-collections/community.grafana/commits?author=gundalow" title="Tests">⚠️</a> <a href="https://github.com/ansible-collections/community.grafana/commits?author=gundalow" title="Code">💻</a></td>
+ <td align="center" valign="top" width="14.28%"><a href="https://github.com/rrey"><img src="https://avatars1.githubusercontent.com/u/2752379?v=4?s=100" width="100px;" alt="Rémi REY"/><br /><sub><b>Rémi REY</b></sub></a><br /><a href="https://github.com/ansible-collections/community.grafana/commits?author=rrey" title="Tests">⚠️</a> <a href="https://github.com/ansible-collections/community.grafana/commits?author=rrey" title="Documentation">📖</a> <a href="https://github.com/ansible-collections/community.grafana/commits?author=rrey" title="Code">💻</a></td>
+ <td align="center" valign="top" width="14.28%"><a href="https://aperogeek.fr"><img src="https://avatars1.githubusercontent.com/u/1336359?v=4?s=100" width="100px;" alt="Thierry Sallé"/><br /><sub><b>Thierry Sallé</b></sub></a><br /><a href="https://github.com/ansible-collections/community.grafana/commits?author=seuf" title="Code">💻</a> <a href="https://github.com/ansible-collections/community.grafana/commits?author=seuf" title="Tests">⚠️</a></td>
+ <td align="center" valign="top" width="14.28%"><a href="http://antoine.tanzil.li"><img src="https://avatars0.githubusercontent.com/u/1068018?v=4?s=100" width="100px;" alt="Antoine"/><br /><sub><b>Antoine</b></sub></a><br /><a href="https://github.com/ansible-collections/community.grafana/commits?author=Tailzip" title="Code">💻</a> <a href="https://github.com/ansible-collections/community.grafana/commits?author=Tailzip" title="Tests">⚠️</a></td>
+ <td align="center" valign="top" width="14.28%"><a href="https://github.com/pomverte"><img src="https://avatars0.githubusercontent.com/u/695230?v=4?s=100" width="100px;" alt="hvle"/><br /><sub><b>hvle</b></sub></a><br /><a href="https://github.com/ansible-collections/community.grafana/commits?author=pomverte" title="Code">💻</a> <a href="https://github.com/ansible-collections/community.grafana/commits?author=pomverte" title="Tests">⚠️</a></td>
+ <td align="center" valign="top" width="14.28%"><a href="https://github.com/jual"><img src="https://avatars2.githubusercontent.com/u/4416541?v=4?s=100" width="100px;" alt="jual"/><br /><sub><b>jual</b></sub></a><br /><a href="https://github.com/ansible-collections/community.grafana/commits?author=jual" title="Code">💻</a> <a href="https://github.com/ansible-collections/community.grafana/commits?author=jual" title="Tests">⚠️</a></td>
+ <td align="center" valign="top" width="14.28%"><a href="https://github.com/MCyprien"><img src="https://avatars2.githubusercontent.com/u/11160859?v=4?s=100" width="100px;" alt="MCyprien"/><br /><sub><b>MCyprien</b></sub></a><br /><a href="https://github.com/ansible-collections/community.grafana/commits?author=MCyprien" title="Code">💻</a> <a href="https://github.com/ansible-collections/community.grafana/commits?author=MCyprien" title="Tests">⚠️</a></td>
</tr>
<tr>
- <td align="center"><a href="https://twitter.com/RealRockaut"><img src="https://avatars0.githubusercontent.com/u/453368?v=4?s=100" width="100px;" alt="Markus Fischbacher"/><br /><sub><b>Markus Fischbacher</b></sub></a><br /><a href="https://github.com/ansible-collections/community.grafana/commits?author=rockaut" title="Code">💻</a></td>
- <td align="center"><a href="https://github.com/rverchere"><img src="https://avatars3.githubusercontent.com/u/232433?v=4?s=100" width="100px;" alt="Remi Verchere"/><br /><sub><b>Remi Verchere</b></sub></a><br /><a href="https://github.com/ansible-collections/community.grafana/commits?author=rverchere" title="Code">💻</a></td>
- <td align="center"><a href="http://akasurde.github.io"><img src="https://avatars1.githubusercontent.com/u/633765?v=4?s=100" width="100px;" alt="Abhijeet Kasurde"/><br /><sub><b>Abhijeet Kasurde</b></sub></a><br /><a href="https://github.com/ansible-collections/community.grafana/commits?author=Akasurde" title="Documentation">📖</a> <a href="https://github.com/ansible-collections/community.grafana/commits?author=Akasurde" title="Tests">⚠️</a></td>
- <td align="center"><a href="https://github.com/martinwangjian"><img src="https://avatars2.githubusercontent.com/u/1770277?v=4?s=100" width="100px;" alt="martinwangjian"/><br /><sub><b>martinwangjian</b></sub></a><br /><a href="https://github.com/ansible-collections/community.grafana/commits?author=martinwangjian" title="Code">💻</a></td>
- <td align="center"><a href="https://github.com/CWollinger"><img src="https://avatars2.githubusercontent.com/u/11299733?v=4?s=100" width="100px;" alt="cwollinger"/><br /><sub><b>cwollinger</b></sub></a><br /><a href="https://github.com/ansible-collections/community.grafana/commits?author=cwollinger" title="Code">💻</a></td>
- <td align="center"><a href="https://github.com/Andersson007"><img src="https://avatars3.githubusercontent.com/u/34477873?v=4?s=100" width="100px;" alt="Andrew Klychkov"/><br /><sub><b>Andrew Klychkov</b></sub></a><br /><a href="https://github.com/ansible-collections/community.grafana/commits?author=Andersson007" title="Code">💻</a></td>
- <td align="center"><a href="https://github.com/vnea"><img src="https://avatars.githubusercontent.com/u/10775422?v=4?s=100" width="100px;" alt="Victor"/><br /><sub><b>Victor</b></sub></a><br /><a href="https://github.com/ansible-collections/community.grafana/commits?author=vnea" title="Code">💻</a></td>
+ <td align="center" valign="top" width="14.28%"><a href="https://twitter.com/RealRockaut"><img src="https://avatars0.githubusercontent.com/u/453368?v=4?s=100" width="100px;" alt="Markus Fischbacher"/><br /><sub><b>Markus Fischbacher</b></sub></a><br /><a href="https://github.com/ansible-collections/community.grafana/commits?author=rockaut" title="Code">💻</a></td>
+ <td align="center" valign="top" width="14.28%"><a href="https://github.com/rverchere"><img src="https://avatars3.githubusercontent.com/u/232433?v=4?s=100" width="100px;" alt="Remi Verchere"/><br /><sub><b>Remi Verchere</b></sub></a><br /><a href="https://github.com/ansible-collections/community.grafana/commits?author=rverchere" title="Code">💻</a></td>
+ <td align="center" valign="top" width="14.28%"><a href="http://akasurde.github.io"><img src="https://avatars1.githubusercontent.com/u/633765?v=4?s=100" width="100px;" alt="Abhijeet Kasurde"/><br /><sub><b>Abhijeet Kasurde</b></sub></a><br /><a href="https://github.com/ansible-collections/community.grafana/commits?author=Akasurde" title="Documentation">📖</a> <a href="https://github.com/ansible-collections/community.grafana/commits?author=Akasurde" title="Tests">⚠️</a></td>
+ <td align="center" valign="top" width="14.28%"><a href="https://github.com/martinwangjian"><img src="https://avatars2.githubusercontent.com/u/1770277?v=4?s=100" width="100px;" alt="martinwangjian"/><br /><sub><b>martinwangjian</b></sub></a><br /><a href="https://github.com/ansible-collections/community.grafana/commits?author=martinwangjian" title="Code">💻</a></td>
+ <td align="center" valign="top" width="14.28%"><a href="https://github.com/CWollinger"><img src="https://avatars2.githubusercontent.com/u/11299733?v=4?s=100" width="100px;" alt="cwollinger"/><br /><sub><b>cwollinger</b></sub></a><br /><a href="https://github.com/ansible-collections/community.grafana/commits?author=cwollinger" title="Code">💻</a></td>
+ <td align="center" valign="top" width="14.28%"><a href="https://github.com/Andersson007"><img src="https://avatars3.githubusercontent.com/u/34477873?v=4?s=100" width="100px;" alt="Andrew Klychkov"/><br /><sub><b>Andrew Klychkov</b></sub></a><br /><a href="https://github.com/ansible-collections/community.grafana/commits?author=Andersson007" title="Code">💻</a></td>
+ <td align="center" valign="top" width="14.28%"><a href="https://github.com/vnea"><img src="https://avatars.githubusercontent.com/u/10775422?v=4?s=100" width="100px;" alt="Victor"/><br /><sub><b>Victor</b></sub></a><br /><a href="https://github.com/ansible-collections/community.grafana/commits?author=vnea" title="Code">💻</a></td>
</tr>
<tr>
- <td align="center"><a href="https://github.com/paytroff"><img src="https://avatars.githubusercontent.com/u/93038288?v=4?s=100" width="100px;" alt="paytroff"/><br /><sub><b>paytroff</b></sub></a><br /><a href="https://github.com/ansible-collections/community.grafana/commits?author=paytroff" title="Code">💻</a> <a href="https://github.com/ansible-collections/community.grafana/commits?author=paytroff" title="Tests">⚠️</a></td>
- <td align="center"><a href="https://github.com/jseiser"><img src="https://avatars.githubusercontent.com/u/4855527?v=4?s=100" width="100px;" alt="Justin Seiser"/><br /><sub><b>Justin Seiser</b></sub></a><br /><a href="https://github.com/ansible-collections/community.grafana/commits?author=jseiser" title="Code">💻</a></td>
- <td align="center"><a href="https://github.com/prndrbr"><img src="https://avatars.githubusercontent.com/u/96344856?v=4?s=100" width="100px;" alt="Pierre"/><br /><sub><b>Pierre</b></sub></a><br /><a href="https://github.com/ansible-collections/community.grafana/issues?q=author%3Aprndrbr" title="Bug reports">🐛</a></td>
- <td align="center"><a href="https://github.com/miksonx"><img src="https://avatars.githubusercontent.com/u/5308184?v=4?s=100" width="100px;" alt="MiksonX"/><br /><sub><b>MiksonX</b></sub></a><br /><a href="https://github.com/ansible-collections/community.grafana/issues?q=author%3Amiksonx" title="Bug reports">🐛</a></td>
+ <td align="center" valign="top" width="14.28%"><a href="https://github.com/paytroff"><img src="https://avatars.githubusercontent.com/u/93038288?v=4?s=100" width="100px;" alt="paytroff"/><br /><sub><b>paytroff</b></sub></a><br /><a href="https://github.com/ansible-collections/community.grafana/commits?author=paytroff" title="Code">💻</a> <a href="https://github.com/ansible-collections/community.grafana/commits?author=paytroff" title="Tests">⚠️</a></td>
+ <td align="center" valign="top" width="14.28%"><a href="https://github.com/jseiser"><img src="https://avatars.githubusercontent.com/u/4855527?v=4?s=100" width="100px;" alt="Justin Seiser"/><br /><sub><b>Justin Seiser</b></sub></a><br /><a href="https://github.com/ansible-collections/community.grafana/commits?author=jseiser" title="Code">💻</a></td>
+ <td align="center" valign="top" width="14.28%"><a href="https://github.com/prndrbr"><img src="https://avatars.githubusercontent.com/u/96344856?v=4?s=100" width="100px;" alt="Pierre"/><br /><sub><b>Pierre</b></sub></a><br /><a href="https://github.com/ansible-collections/community.grafana/issues?q=author%3Aprndrbr" title="Bug reports">🐛</a></td>
+ <td align="center" valign="top" width="14.28%"><a href="https://github.com/miksonx"><img src="https://avatars.githubusercontent.com/u/5308184?v=4?s=100" width="100px;" alt="MiksonX"/><br /><sub><b>MiksonX</b></sub></a><br /><a href="https://github.com/ansible-collections/community.grafana/issues?q=author%3Amiksonx" title="Bug reports">🐛</a></td>
+ <td align="center" valign="top" width="14.28%"><a href="https://github.com/amenzhinsky"><img src="https://avatars.githubusercontent.com/u/1308953?v=4?s=100" width="100px;" alt="Aliaksandr Mianzhynski"/><br /><sub><b>Aliaksandr Mianzhynski</b></sub></a><br /><a href="https://github.com/ansible-collections/community.grafana/commits?author=amenzhinsky" title="Code">💻</a> <a href="https://github.com/ansible-collections/community.grafana/commits?author=amenzhinsky" title="Tests">⚠️</a></td>
+ <td align="center" valign="top" width="14.28%"><a href="https://nemental.de"><img src="https://avatars.githubusercontent.com/u/15136847?v=4?s=100" width="100px;" alt="Moritz"/><br /><sub><b>Moritz</b></sub></a><br /><a href="https://github.com/ansible-collections/community.grafana/issues?q=author%3ANemental" title="Bug reports">🐛</a> <a href="https://github.com/ansible-collections/community.grafana/commits?author=Nemental" title="Code">💻</a></td>
</tr>
</tbody>
</table>
diff --git a/ansible_collections/community/grafana/changelogs/changelog.yaml b/ansible_collections/community/grafana/changelogs/changelog.yaml
index 6166fe7a3..465b42bc3 100644
--- a/ansible_collections/community/grafana/changelogs/changelog.yaml
+++ b/ansible_collections/community/grafana/changelogs/changelog.yaml
@@ -207,3 +207,75 @@ releases:
- 277-gha-ansible-test-versions.yml
- 288_get_actual_org_encode.yml
release_date: '2023-02-07'
+ 1.6.0:
+ changes:
+ minor_changes:
+ - Add `grafana_organization_user` module
+ fragments:
+ - 242_add_grafana_organization_user_module.yml
+ modules:
+ - description: Manage Grafana Organization Users.
+ name: grafana_organization_user
+ namespace: ''
+ release_date: '2023-02-19'
+ 1.6.1:
+ changes:
+ bugfixes:
+ - Fix error with datasources configured without basicAuth
+ - grafana_folder, fix an issue during delete (starting Grafana 9.3)
+ minor_changes:
+ - Bump version of Python used in tests to 3.10
+ - Enable datasource option `time_interval` for prometheus
+ - Fix documentation url for Ansible doc website
+ - Now testing against Grafana 9.5.13, 8.5.27, 10.2.0
+ fragments:
+ - 285_fix_doc.yml
+ - 294-bump-grafana-version.yml
+ - 300_datasource_prometheus_time_interval.yml
+ - fix-316.yml
+ release_date: '2023-11-05'
+ 1.7.0:
+ changes:
+ bugfixes:
+ - Add `grafana_organiazion_user` to `action_groups.grafana`
+ - Fixed orgId handling in diff comparison for `grafana_datasource` if using
+ org_name
+ minor_changes:
+ - Add Quickwit search engine datasource (https://quickwit.io).
+ - Add parameter `org_name` to `grafana_dashboard`
+ - Add parameter `org_name` to `grafana_datasource`
+ - Add parameter `org_name` to `grafana_organization_user`
+ - Add support for Grafana Tempo datasource type (https://grafana.com/docs/grafana/latest/datasources/tempo/)
+ - default to true/false in docs and code
+ fragments:
+ - 238_checkmode.yml
+ - 308_datasource_quickwit.yml
+ - 318-org_users_by_org_name.yml
+ - 321-action-groups-org-users.yml
+ - 324_formatting.yml
+ - 325_linting.yml
+ - 325_true_false.yml
+ - 331-dashboard-by-org-name.yml
+ - 332-datasource-by-org-name.yml
+ - 335-add-datasource-type-tempo.yml
+ - 339-lint-black.yml
+ - 341-lint-ruff.yml
+ - 342-ruff-findings.yml
+ - 345-datasource-compare-diff-orgid.yml
+ release_date: '2024-01-17'
+ 1.8.0:
+ changes:
+ bugfixes:
+ - 'test: replace deprecated `TestCase.assertEquals` to support Python 3.12'
+ minor_changes:
+ - Manage `grafana_folder` for organizations
+ - Merged ansible role telekom-mms/ansible-role-grafana into ansible-collections/community.grafana
+ - added `community.grafana.notification_channel` to role
+ - grafana_dashboard - add check_mode support
+ fragments:
+ - 311_dashboard_check_mode.yml
+ - 343-telekom-mms-role.yml
+ - 347-folder-for-orgs.yml
+ - 349-role-notification-channel.yml
+ - 350-python3.12.yml
+ release_date: '2024-02-21'
diff --git a/ansible_collections/community/grafana/changelogs/fragments/238_checkmode.yml b/ansible_collections/community/grafana/changelogs/fragments/238_checkmode.yml
new file mode 100644
index 000000000..81785b52d
--- /dev/null
+++ b/ansible_collections/community/grafana/changelogs/fragments/238_checkmode.yml
@@ -0,0 +1,2 @@
+trivial:
+ - run integration tests in check-mode.
diff --git a/ansible_collections/community/grafana/changelogs/fragments/242_add_grafana_organization_user_module.yml b/ansible_collections/community/grafana/changelogs/fragments/242_add_grafana_organization_user_module.yml
new file mode 100644
index 000000000..2296df462
--- /dev/null
+++ b/ansible_collections/community/grafana/changelogs/fragments/242_add_grafana_organization_user_module.yml
@@ -0,0 +1,2 @@
+minor_changes:
+ - Add `grafana_organization_user` module
diff --git a/ansible_collections/community/grafana/changelogs/fragments/285_fix_doc.yml b/ansible_collections/community/grafana/changelogs/fragments/285_fix_doc.yml
new file mode 100644
index 000000000..74db5e2c7
--- /dev/null
+++ b/ansible_collections/community/grafana/changelogs/fragments/285_fix_doc.yml
@@ -0,0 +1,6 @@
+---
+
+minor_changes:
+ - Fix documentation url for Ansible doc website
+
+...
diff --git a/ansible_collections/community/grafana/changelogs/fragments/294-bump-grafana-version.yml b/ansible_collections/community/grafana/changelogs/fragments/294-bump-grafana-version.yml
new file mode 100644
index 000000000..7149cfe0f
--- /dev/null
+++ b/ansible_collections/community/grafana/changelogs/fragments/294-bump-grafana-version.yml
@@ -0,0 +1,5 @@
+minor_changes:
+ - Bump version of Python used in tests to 3.10
+ - Now testing against Grafana 9.5.13, 8.5.27, 10.2.0
+bugfixes:
+ - grafana_folder, fix an issue during delete (starting Grafana 9.3)
diff --git a/ansible_collections/community/grafana/changelogs/fragments/300_datasource_prometheus_time_interval.yml b/ansible_collections/community/grafana/changelogs/fragments/300_datasource_prometheus_time_interval.yml
new file mode 100644
index 000000000..970797f76
--- /dev/null
+++ b/ansible_collections/community/grafana/changelogs/fragments/300_datasource_prometheus_time_interval.yml
@@ -0,0 +1,2 @@
+minor_changes:
+ - Enable datasource option `time_interval` for prometheus
diff --git a/ansible_collections/community/grafana/changelogs/fragments/308_datasource_quickwit.yml b/ansible_collections/community/grafana/changelogs/fragments/308_datasource_quickwit.yml
new file mode 100644
index 000000000..d91a13082
--- /dev/null
+++ b/ansible_collections/community/grafana/changelogs/fragments/308_datasource_quickwit.yml
@@ -0,0 +1,2 @@
+minor_changes:
+ - Add Quickwit search engine datasource (https://quickwit.io).
diff --git a/ansible_collections/community/grafana/changelogs/fragments/311_dashboard_check_mode.yml b/ansible_collections/community/grafana/changelogs/fragments/311_dashboard_check_mode.yml
new file mode 100644
index 000000000..394edad9b
--- /dev/null
+++ b/ansible_collections/community/grafana/changelogs/fragments/311_dashboard_check_mode.yml
@@ -0,0 +1,5 @@
+minor_changes:
+ - grafana_dashboard - add check_mode support
+
+trivial:
+ - Refactor tests for `grafana_dashboard`
diff --git a/ansible_collections/community/grafana/changelogs/fragments/318-org_users_by_org_name.yml b/ansible_collections/community/grafana/changelogs/fragments/318-org_users_by_org_name.yml
new file mode 100644
index 000000000..ef8d4959e
--- /dev/null
+++ b/ansible_collections/community/grafana/changelogs/fragments/318-org_users_by_org_name.yml
@@ -0,0 +1,7 @@
+---
+
+minor_changes:
+ - Add parameter `org_name` to `grafana_organization_user`
+
+trivial:
+ - Add tests for new `grafana_organization_user`-parameter `org_name`
diff --git a/ansible_collections/community/grafana/changelogs/fragments/321-action-groups-org-users.yml b/ansible_collections/community/grafana/changelogs/fragments/321-action-groups-org-users.yml
new file mode 100644
index 000000000..d62f076bf
--- /dev/null
+++ b/ansible_collections/community/grafana/changelogs/fragments/321-action-groups-org-users.yml
@@ -0,0 +1,4 @@
+---
+
+bugfixes:
+ - Add `grafana_organiazion_user` to `action_groups.grafana`
diff --git a/ansible_collections/community/grafana/changelogs/fragments/324_formatting.yml b/ansible_collections/community/grafana/changelogs/fragments/324_formatting.yml
new file mode 100644
index 000000000..db7b9609d
--- /dev/null
+++ b/ansible_collections/community/grafana/changelogs/fragments/324_formatting.yml
@@ -0,0 +1,2 @@
+trivial:
+ - Format with black, remove unused variables
diff --git a/ansible_collections/community/grafana/changelogs/fragments/325_linting.yml b/ansible_collections/community/grafana/changelogs/fragments/325_linting.yml
new file mode 100644
index 000000000..cfeff8a52
--- /dev/null
+++ b/ansible_collections/community/grafana/changelogs/fragments/325_linting.yml
@@ -0,0 +1,2 @@
+trivial:
+ - fix linting with ansible-lint write.
diff --git a/ansible_collections/community/grafana/changelogs/fragments/325_true_false.yml b/ansible_collections/community/grafana/changelogs/fragments/325_true_false.yml
new file mode 100644
index 000000000..c192d086f
--- /dev/null
+++ b/ansible_collections/community/grafana/changelogs/fragments/325_true_false.yml
@@ -0,0 +1,2 @@
+minor_changes:
+- default to true/false in docs and code
diff --git a/ansible_collections/community/grafana/changelogs/fragments/331-dashboard-by-org-name.yml b/ansible_collections/community/grafana/changelogs/fragments/331-dashboard-by-org-name.yml
new file mode 100644
index 000000000..576c8c143
--- /dev/null
+++ b/ansible_collections/community/grafana/changelogs/fragments/331-dashboard-by-org-name.yml
@@ -0,0 +1,8 @@
+---
+
+minor_changes:
+ - Add parameter `org_name` to `grafana_dashboard`
+
+trivial:
+ - Add tests for new `grafana_dashboard`-parameter `org_name`
+ - Refactor tests for `grafana_dashboard`
diff --git a/ansible_collections/community/grafana/changelogs/fragments/332-datasource-by-org-name.yml b/ansible_collections/community/grafana/changelogs/fragments/332-datasource-by-org-name.yml
new file mode 100644
index 000000000..0c8e265df
--- /dev/null
+++ b/ansible_collections/community/grafana/changelogs/fragments/332-datasource-by-org-name.yml
@@ -0,0 +1,4 @@
+---
+
+minor_changes:
+ - Add parameter `org_name` to `grafana_datasource`
diff --git a/ansible_collections/community/grafana/changelogs/fragments/335-add-datasource-type-tempo.yml b/ansible_collections/community/grafana/changelogs/fragments/335-add-datasource-type-tempo.yml
new file mode 100644
index 000000000..18d34a0aa
--- /dev/null
+++ b/ansible_collections/community/grafana/changelogs/fragments/335-add-datasource-type-tempo.yml
@@ -0,0 +1,2 @@
+minor_changes:
+ - Add support for Grafana Tempo datasource type (https://grafana.com/docs/grafana/latest/datasources/tempo/) \ No newline at end of file
diff --git a/ansible_collections/community/grafana/changelogs/fragments/339-lint-black.yml b/ansible_collections/community/grafana/changelogs/fragments/339-lint-black.yml
new file mode 100644
index 000000000..2a37ca851
--- /dev/null
+++ b/ansible_collections/community/grafana/changelogs/fragments/339-lint-black.yml
@@ -0,0 +1,3 @@
+---
+trivial:
+ - added python black linting action
diff --git a/ansible_collections/community/grafana/changelogs/fragments/341-lint-ruff.yml b/ansible_collections/community/grafana/changelogs/fragments/341-lint-ruff.yml
new file mode 100644
index 000000000..e5cfd5b49
--- /dev/null
+++ b/ansible_collections/community/grafana/changelogs/fragments/341-lint-ruff.yml
@@ -0,0 +1,3 @@
+---
+trivial:
+ - added python ruff linting action
diff --git a/ansible_collections/community/grafana/changelogs/fragments/342-ruff-findings.yml b/ansible_collections/community/grafana/changelogs/fragments/342-ruff-findings.yml
new file mode 100644
index 000000000..79c7ab220
--- /dev/null
+++ b/ansible_collections/community/grafana/changelogs/fragments/342-ruff-findings.yml
@@ -0,0 +1,2 @@
+trivial:
+ - fixed ruff python formatter findings
diff --git a/ansible_collections/community/grafana/changelogs/fragments/343-telekom-mms-role.yml b/ansible_collections/community/grafana/changelogs/fragments/343-telekom-mms-role.yml
new file mode 100644
index 000000000..07da942ca
--- /dev/null
+++ b/ansible_collections/community/grafana/changelogs/fragments/343-telekom-mms-role.yml
@@ -0,0 +1,2 @@
+minor_changes:
+ - Merged ansible role telekom-mms/ansible-role-grafana into ansible-collections/community.grafana
diff --git a/ansible_collections/community/grafana/changelogs/fragments/345-datasource-compare-diff-orgid.yml b/ansible_collections/community/grafana/changelogs/fragments/345-datasource-compare-diff-orgid.yml
new file mode 100644
index 000000000..11c211417
--- /dev/null
+++ b/ansible_collections/community/grafana/changelogs/fragments/345-datasource-compare-diff-orgid.yml
@@ -0,0 +1,3 @@
+---
+bugfixes:
+ - Fixed orgId handling in diff comparison for `grafana_datasource` if using org_name
diff --git a/ansible_collections/community/grafana/changelogs/fragments/347-folder-for-orgs.yml b/ansible_collections/community/grafana/changelogs/fragments/347-folder-for-orgs.yml
new file mode 100644
index 000000000..c37990eb4
--- /dev/null
+++ b/ansible_collections/community/grafana/changelogs/fragments/347-folder-for-orgs.yml
@@ -0,0 +1,7 @@
+---
+
+minor_changes:
+ - Manage `grafana_folder` for organizations
+
+trivial:
+ - Fixed syntax for code in some docs
diff --git a/ansible_collections/community/grafana/changelogs/fragments/349-role-notification-channel.yml b/ansible_collections/community/grafana/changelogs/fragments/349-role-notification-channel.yml
new file mode 100644
index 000000000..f2428c3a6
--- /dev/null
+++ b/ansible_collections/community/grafana/changelogs/fragments/349-role-notification-channel.yml
@@ -0,0 +1,4 @@
+---
+
+minor_changes:
+ - added `community.grafana.notification_channel` to role
diff --git a/ansible_collections/community/grafana/changelogs/fragments/350-python3.12.yml b/ansible_collections/community/grafana/changelogs/fragments/350-python3.12.yml
new file mode 100644
index 000000000..21b7cc760
--- /dev/null
+++ b/ansible_collections/community/grafana/changelogs/fragments/350-python3.12.yml
@@ -0,0 +1,3 @@
+---
+bugfixes:
+ - "test: replace deprecated `TestCase.assertEquals` to support Python 3.12"
diff --git a/ansible_collections/community/grafana/changelogs/fragments/fix-316.yml b/ansible_collections/community/grafana/changelogs/fragments/fix-316.yml
new file mode 100644
index 000000000..4569d4456
--- /dev/null
+++ b/ansible_collections/community/grafana/changelogs/fragments/fix-316.yml
@@ -0,0 +1,2 @@
+bugfixes:
+ - Fix error with datasources configured without basicAuth \ No newline at end of file
diff --git a/ansible_collections/community/grafana/codecov.yml b/ansible_collections/community/grafana/codecov.yml
index c01a21d4a..d376ab571 100644
--- a/ansible_collections/community/grafana/codecov.yml
+++ b/ansible_collections/community/grafana/codecov.yml
@@ -3,4 +3,4 @@ coverage:
round: down
range: "70...100"
fixes:
- - "/ansible_collections/community/grafana/::"
+ - "/ansible_collections/community/grafana/::"
diff --git a/ansible_collections/community/grafana/hacking/find_grafana_versions.py b/ansible_collections/community/grafana/hacking/find_grafana_versions.py
index 06625a2d5..b31fc530a 100644
--- a/ansible_collections/community/grafana/hacking/find_grafana_versions.py
+++ b/ansible_collections/community/grafana/hacking/find_grafana_versions.py
@@ -7,11 +7,14 @@ import requests
def get_by_major(version):
if version.startswith("v"):
version = version[1:]
- return (version[0], version, int(version.replace('.', '')))
+ return (version[0], version, int(version.replace(".", "")))
def get_grafana_releases():
- r = requests.get('https://api.github.com/repos/grafana/grafana/releases?per_page=50', headers={"Accept": "application/vnd.github.v3+json"})
+ r = requests.get(
+ "https://api.github.com/repos/grafana/grafana/releases?per_page=50",
+ headers={"Accept": "application/vnd.github.v3+json"},
+ )
if r.status_code != 200:
raise Exception("Failed to get releases from GitHub")
return r.json()
diff --git a/ansible_collections/community/grafana/hacking/requirements.txt b/ansible_collections/community/grafana/hacking/requirements.txt
index ced51d094..2c24336eb 100644
--- a/ansible_collections/community/grafana/hacking/requirements.txt
+++ b/ansible_collections/community/grafana/hacking/requirements.txt
@@ -1 +1 @@
-requests==2.28.0
+requests==2.31.0
diff --git a/ansible_collections/community/grafana/meta/runtime.yml b/ansible_collections/community/grafana/meta/runtime.yml
index 8d9b13a42..15f5554fc 100644
--- a/ansible_collections/community/grafana/meta/runtime.yml
+++ b/ansible_collections/community/grafana/meta/runtime.yml
@@ -1,12 +1,13 @@
---
-requires_ansible: '>=2.9.0'
+requires_ansible: ">=2.14.0"
action_groups:
grafana:
- - grafana_dashboard
- - grafana_datasource
- - grafana_folder
- - grafana_notification_channel
- - grafana_organization
- - grafana_plugin
- - grafana_team
- - grafana_user
+ - grafana_dashboard
+ - grafana_datasource
+ - grafana_folder
+ - grafana_notification_channel
+ - grafana_organization
+ - grafana_organization_user
+ - grafana_plugin
+ - grafana_team
+ - grafana_user
diff --git a/ansible_collections/community/grafana/molecule/default/converge.yml b/ansible_collections/community/grafana/molecule/default/converge.yml
new file mode 100644
index 000000000..b1e1cf20b
--- /dev/null
+++ b/ansible_collections/community/grafana/molecule/default/converge.yml
@@ -0,0 +1,48 @@
+---
+- name: Converge
+ hosts: localhost
+ environment:
+ http_proxy: "{{ lookup('env', 'HTTP_PROXY') | default(omit) }}"
+ https_proxy: "{{ lookup('env', 'HTTPS_PROXY') | default(omit) }}"
+ no_proxy: "{{ lookup('env', 'NO_PROXY') | default(omit) }}"
+
+ vars:
+ grafana_url: http://localhost:3000
+ grafana_username: admin
+ grafana_password: admin
+
+ grafana_organizations:
+ - name: my_org
+
+ grafana_datasources:
+ - name: Loki
+ ds_type: loki
+ ds_url: http://127.0.0.1:3100
+ tls_skip_verify: true
+
+ grafana_folders:
+ - name: my_service
+ - name: other_service
+
+ grafana_teams:
+ - name: my_team
+ email: myteam@example.de
+
+ grafana_users:
+ - name: Test User
+ login: testuser
+ password: supersecure!123
+ email: testuser@example.de
+
+ grafana_organization_users:
+ - login: testuser
+ org_id: 1
+ - login: testuser
+ org_name: my_org
+
+ grafana_dashboards:
+ - folder: my_service
+ path: test_dashboard.json
+ overwrite: true
+
+ roles: [{role: community.grafana.grafana}]
diff --git a/ansible_collections/community/grafana/molecule/default/molecule.yml b/ansible_collections/community/grafana/molecule/default/molecule.yml
new file mode 100644
index 000000000..ab4613bcb
--- /dev/null
+++ b/ansible_collections/community/grafana/molecule/default/molecule.yml
@@ -0,0 +1,21 @@
+---
+dependency:
+ name: galaxy
+driver:
+ name: docker
+platforms:
+ - name: instance
+ image: rndmh3ro/docker-debian12-ansible:latest
+ command: ${MOLECULE_DOCKER_COMMAND:-/lib/systemd/systemd}
+ env:
+ container: docker
+ pre_build_image: true
+ platform: amd64
+provisioner:
+ name: ansible
+ config_options:
+ defaults:
+ interpreter_python: auto_silent
+ callback_whitelist: profile_tasks, timer, yaml
+verifier:
+ name: ansible
diff --git a/ansible_collections/community/grafana/molecule/default/test_dashboard.json b/ansible_collections/community/grafana/molecule/default/test_dashboard.json
new file mode 100644
index 000000000..b95184512
--- /dev/null
+++ b/ansible_collections/community/grafana/molecule/default/test_dashboard.json
@@ -0,0 +1,126 @@
+{
+ "annotations": {
+ "list": [
+ {
+ "builtIn": 1,
+ "datasource": "-- Grafana --",
+ "enable": true,
+ "hide": true,
+ "iconColor": "rgba(0, 211, 255, 1)",
+ "name": "Annotations & Alerts",
+ "target": {
+ "limit": 100,
+ "matchAny": false,
+ "tags": [],
+ "type": "dashboard"
+ },
+ "type": "dashboard"
+ }
+ ]
+ },
+ "editable": true,
+ "fiscalYearStartMonth": 0,
+ "graphTooltip": 0,
+ "id": 3,
+ "links": [],
+ "liveNow": false,
+ "panels": [
+ {
+ "datasource": {
+ "type": "loki"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 0,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "auto",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green"
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ }
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 8,
+ "w": 12,
+ "x": 0,
+ "y": 0
+ },
+ "options": {
+ "legend": {
+ "calcs": [],
+ "displayMode": "list",
+ "placement": "bottom"
+ },
+ "tooltip": {
+ "mode": "single"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "loki"
+ },
+ "refId": "A"
+ }
+ ],
+ "title": "Panel Title",
+ "type": "timeseries"
+ }
+ ],
+ "refresh": "",
+ "schemaVersion": 33,
+ "style": "dark",
+ "tags": [],
+ "templating": {
+ "list": []
+ },
+ "time": {
+ "from": "now-6h",
+ "to": "now"
+ },
+ "timepicker": {},
+ "timezone": "",
+ "title": "New dashboard",
+ "uid": "ES5apb27k",
+ "version": 1,
+ "weekStart": ""
+}
diff --git a/ansible_collections/community/grafana/plugins/callback/grafana_annotations.py b/ansible_collections/community/grafana/plugins/callback/grafana_annotations.py
index 04555eae0..6030b0c8b 100644
--- a/ansible_collections/community/grafana/plugins/callback/grafana_annotations.py
+++ b/ansible_collections/community/grafana/plugins/callback/grafana_annotations.py
@@ -14,10 +14,11 @@
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
-DOCUMENTATION = '''
+DOCUMENTATION = """
name: grafana_annotations
type: notification
short_description: send ansible events as annotations on charts to grafana over http api.
@@ -29,7 +30,7 @@ DOCUMENTATION = '''
options:
grafana_url:
description: Grafana annotations api URL
- required: True
+ required: true
env:
- name: GRAFANA_URL
ini:
@@ -45,7 +46,7 @@ DOCUMENTATION = '''
key: validate_grafana_certs
- section: callback_grafana_annotations
key: validate_certs
- default: True
+ default: true
type: bool
aliases: [ validate_grafana_certs ]
http_agent:
@@ -104,7 +105,7 @@ DOCUMENTATION = '''
default: []
type: list
elements: integer
-'''
+"""
import json
import socket
@@ -148,7 +149,7 @@ Result:
def to_millis(dt):
- return int(dt.strftime('%s')) * 1000
+ return int(dt.strftime("%s")) * 1000
class CallbackModule(CallbackBase):
@@ -161,15 +162,14 @@ class CallbackModule(CallbackBase):
"""
CALLBACK_VERSION = 2.0
- CALLBACK_TYPE = 'aggregate'
- CALLBACK_NAME = 'community.grafana.grafana_annotations'
+ CALLBACK_TYPE = "aggregate"
+ CALLBACK_NAME = "community.grafana.grafana_annotations"
CALLBACK_NEEDS_WHITELIST = True
def __init__(self, display=None):
-
super(CallbackModule, self).__init__(display=display)
- self.headers = {'Content-Type': 'application/json'}
+ self.headers = {"Content-Type": "application/json"}
self.force_basic_auth = False
self.hostname = socket.gethostname()
self.username = getpass.getuser()
@@ -177,38 +177,42 @@ class CallbackModule(CallbackBase):
self.errors = 0
def set_options(self, task_keys=None, var_options=None, direct=None):
-
- super(CallbackModule, self).set_options(task_keys=task_keys, var_options=var_options, direct=direct)
-
- self.grafana_api_key = self.get_option('grafana_api_key')
- self.grafana_url = self.get_option('grafana_url')
- self.validate_grafana_certs = self.get_option('validate_certs')
- self.http_agent = self.get_option('http_agent')
- self.grafana_user = self.get_option('grafana_user')
- self.grafana_password = self.get_option('grafana_password')
- self.dashboard_id = self.get_option('grafana_dashboard_id')
- self.panel_ids = self.get_option('grafana_panel_ids')
+ super(CallbackModule, self).set_options(
+ task_keys=task_keys, var_options=var_options, direct=direct
+ )
+
+ self.grafana_api_key = self.get_option("grafana_api_key")
+ self.grafana_url = self.get_option("grafana_url")
+ self.validate_grafana_certs = self.get_option("validate_certs")
+ self.http_agent = self.get_option("http_agent")
+ self.grafana_user = self.get_option("grafana_user")
+ self.grafana_password = self.get_option("grafana_password")
+ self.dashboard_id = self.get_option("grafana_dashboard_id")
+ self.panel_ids = self.get_option("grafana_panel_ids")
if self.grafana_api_key:
- self.headers['Authorization'] = "Bearer %s" % self.grafana_api_key
+ self.headers["Authorization"] = "Bearer %s" % self.grafana_api_key
else:
self.force_basic_auth = True
if self.grafana_url is None:
self.disabled = True
- self._display.warning('Grafana URL was not provided. The '
- 'Grafana URL can be provided using '
- 'the `GRAFANA_URL` environment variable.')
- self._display.debug('Grafana URL: %s' % self.grafana_url)
+ self._display.warning(
+ "Grafana URL was not provided. The "
+ "Grafana URL can be provided using "
+ "the `GRAFANA_URL` environment variable."
+ )
+ self._display.debug("Grafana URL: %s" % self.grafana_url)
def v2_playbook_on_start(self, playbook):
self.playbook = playbook._file_name
- text = PLAYBOOK_START_TXT.format(playbook=self.playbook, hostname=self.hostname,
- username=self.username)
+ text = PLAYBOOK_START_TXT.format(
+ playbook=self.playbook, hostname=self.hostname, username=self.username
+ )
data = {
- 'time': to_millis(self.start_time),
- 'text': text,
- 'tags': ['ansible', 'ansible_event_start', self.playbook, self.hostname]
+ "time": to_millis(self.start_time),
+ "text": text,
+ "tags": ["ansible", "ansible_event_start", self.playbook, self.hostname],
}
self._send_annotation(data)
@@ -223,30 +227,39 @@ class CallbackModule(CallbackBase):
if self.errors == 0:
status = "OK"
- text = PLAYBOOK_STATS_TXT.format(playbook=self.playbook, hostname=self.hostname,
- duration=duration.total_seconds(),
- status=status, username=self.username,
- summary=json.dumps(summarize_stat))
+ text = PLAYBOOK_STATS_TXT.format(
+ playbook=self.playbook,
+ hostname=self.hostname,
+ duration=duration.total_seconds(),
+ status=status,
+ username=self.username,
+ summary=json.dumps(summarize_stat),
+ )
data = {
- 'time': to_millis(self.start_time),
- 'timeEnd': to_millis(end_time),
- 'isRegion': True,
- 'text': text,
- 'tags': ['ansible', 'ansible_report', self.playbook, self.hostname]
+ "time": to_millis(self.start_time),
+ "timeEnd": to_millis(end_time),
+ "isRegion": True,
+ "text": text,
+ "tags": ["ansible", "ansible_report", self.playbook, self.hostname],
}
self._send_annotations(data)
def v2_runner_on_failed(self, result, ignore_errors=False, **kwargs):
- text = PLAYBOOK_ERROR_TXT.format(playbook=self.playbook, hostname=self.hostname,
- username=self.username, task=result._task,
- host=result._host.name, result=self._dump_results(result._result))
+ text = PLAYBOOK_ERROR_TXT.format(
+ playbook=self.playbook,
+ hostname=self.hostname,
+ username=self.username,
+ task=result._task,
+ host=result._host.name,
+ result=self._dump_results(result._result),
+ )
if ignore_errors:
return
data = {
- 'time': to_millis(datetime.now()),
- 'text': text,
- 'tags': ['ansible', 'ansible_event_failure', self.playbook, self.hostname]
+ "time": to_millis(datetime.now()),
+ "text": text,
+ "tags": ["ansible", "ansible_event_failure", self.playbook, self.hostname],
}
self.errors += 1
self._send_annotations(data)
@@ -263,10 +276,16 @@ class CallbackModule(CallbackBase):
def _send_annotation(self, annotation):
try:
- open_url(self.grafana_url, data=json.dumps(annotation), headers=self.headers,
- method="POST",
- validate_certs=self.validate_grafana_certs,
- url_username=self.grafana_user, url_password=self.grafana_password,
- http_agent=self.http_agent, force_basic_auth=self.force_basic_auth)
+ open_url(
+ self.grafana_url,
+ data=json.dumps(annotation),
+ headers=self.headers,
+ method="POST",
+ validate_certs=self.validate_grafana_certs,
+ url_username=self.grafana_user,
+ url_password=self.grafana_password,
+ http_agent=self.http_agent,
+ force_basic_auth=self.force_basic_auth,
+ )
except Exception as e:
- self._display.error(u'Could not submit message to Grafana: %s' % to_text(e))
+ self._display.error("Could not submit message to Grafana: %s" % to_text(e))
diff --git a/ansible_collections/community/grafana/plugins/doc_fragments/api_key.py b/ansible_collections/community/grafana/plugins/doc_fragments/api_key.py
index ffea714e5..94fdb57a2 100644
--- a/ansible_collections/community/grafana/plugins/doc_fragments/api_key.py
+++ b/ansible_collections/community/grafana/plugins/doc_fragments/api_key.py
@@ -2,17 +2,16 @@
# Copyright: (c) 2019, Rémi REY (@rrey)
# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import, division, print_function
__metaclass__ = type
class ModuleDocFragment(object):
-
- DOCUMENTATION = r'''options:
+ DOCUMENTATION = r"""options:
grafana_api_key:
description:
- The Grafana API key.
- If set, C(url_username) and C(url_password) will be ignored.
type: str
- '''
+ """
diff --git a/ansible_collections/community/grafana/plugins/doc_fragments/basic_auth.py b/ansible_collections/community/grafana/plugins/doc_fragments/basic_auth.py
index 8c41acdbe..5a8aec541 100644
--- a/ansible_collections/community/grafana/plugins/doc_fragments/basic_auth.py
+++ b/ansible_collections/community/grafana/plugins/doc_fragments/basic_auth.py
@@ -2,14 +2,13 @@
# Copyright: (c) 2019, Rémi REY (@rrey)
# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import, division, print_function
__metaclass__ = type
class ModuleDocFragment(object):
-
- DOCUMENTATION = r'''options:
+ DOCUMENTATION = r"""options:
url:
description:
- The Grafana URL.
@@ -30,9 +29,9 @@ class ModuleDocFragment(object):
aliases: [ grafana_password ]
use_proxy:
description:
- - If C(no), it will not use a proxy, even if one is defined in an environment variable on the target hosts.
+ - If C(false), it will not use a proxy, even if one is defined in an environment variable on the target hosts.
type: bool
- default: yes
+ default: true
client_cert:
description:
- PEM formatted certificate chain file to be used for SSL client authentication.
@@ -45,8 +44,8 @@ class ModuleDocFragment(object):
type: path
validate_certs:
description:
- - If C(no), SSL certificates will not be validated.
- - This should only set to C(no) used on personally controlled sites using self-signed certificates.
+ - If C(false), SSL certificates will not be validated.
+ - This should only set to C(false) used on personally controlled sites using self-signed certificates.
type: bool
- default: yes
- '''
+ default: true
+ """
diff --git a/ansible_collections/community/grafana/plugins/lookup/grafana_dashboard.py b/ansible_collections/community/grafana/plugins/lookup/grafana_dashboard.py
index ff288a1f3..c7fa31574 100644
--- a/ansible_collections/community/grafana/plugins/lookup/grafana_dashboard.py
+++ b/ansible_collections/community/grafana/plugins/lookup/grafana_dashboard.py
@@ -1,9 +1,10 @@
# (c) 2018 Ansible Project
# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
-DOCUMENTATION = '''
+DOCUMENTATION = """
name: grafana_dashboard
author: Thierry Salle (@seuf)
short_description: list or search grafana dashboards
@@ -40,7 +41,7 @@ options:
description: optional filter for dashboard search.
env:
- name: GRAFANA_DASHBOARD_SEARCH
-'''
+"""
EXAMPLES = """
- name: get project foo grafana dashboards
@@ -64,30 +65,30 @@ from ansible.utils.display import Display
display = Display()
-ANSIBLE_GRAFANA_URL = 'http://127.0.0.1:3000'
+ANSIBLE_GRAFANA_URL = "http://127.0.0.1:3000"
ANSIBLE_GRAFANA_API_KEY = None
-ANSIBLE_GRAFANA_USER = 'admin'
-ANSIBLE_GRAFANA_PASSWORD = 'admin'
+ANSIBLE_GRAFANA_USER = "admin"
+ANSIBLE_GRAFANA_PASSWORD = "admin"
ANSIBLE_GRAFANA_ORG_ID = 1
ANSIBLE_GRAFANA_DASHBOARD_SEARCH = None
-if os.getenv('GRAFANA_URL') is not None:
- ANSIBLE_GRAFANA_URL = os.environ['GRAFANA_URL']
+if os.getenv("GRAFANA_URL") is not None:
+ ANSIBLE_GRAFANA_URL = os.environ["GRAFANA_URL"]
-if os.getenv('GRAFANA_API_KEY') is not None:
- ANSIBLE_GRAFANA_API_KEY = os.environ['GRAFANA_API_KEY']
+if os.getenv("GRAFANA_API_KEY") is not None:
+ ANSIBLE_GRAFANA_API_KEY = os.environ["GRAFANA_API_KEY"]
-if os.getenv('GRAFANA_USER') is not None:
- ANSIBLE_GRAFANA_USER = os.environ['GRAFANA_USER']
+if os.getenv("GRAFANA_USER") is not None:
+ ANSIBLE_GRAFANA_USER = os.environ["GRAFANA_USER"]
-if os.getenv('GRAFANA_PASSWORD') is not None:
- ANSIBLE_GRAFANA_PASSWORD = os.environ['GRAFANA_PASSWORD']
+if os.getenv("GRAFANA_PASSWORD") is not None:
+ ANSIBLE_GRAFANA_PASSWORD = os.environ["GRAFANA_PASSWORD"]
-if os.getenv('GRAFANA_ORG_ID') is not None:
- ANSIBLE_GRAFANA_ORG_ID = os.environ['GRAFANA_ORG_ID']
+if os.getenv("GRAFANA_ORG_ID") is not None:
+ ANSIBLE_GRAFANA_ORG_ID = os.environ["GRAFANA_ORG_ID"]
-if os.getenv('GRAFANA_DASHBOARD_SEARCH') is not None:
- ANSIBLE_GRAFANA_DASHBOARD_SEARCH = os.environ['GRAFANA_DASHBOARD_SEARCH']
+if os.getenv("GRAFANA_DASHBOARD_SEARCH") is not None:
+ ANSIBLE_GRAFANA_DASHBOARD_SEARCH = os.environ["GRAFANA_DASHBOARD_SEARCH"]
class GrafanaAPIException(Exception):
@@ -96,35 +97,47 @@ class GrafanaAPIException(Exception):
class GrafanaAPI:
def __init__(self, **kwargs):
- self.grafana_url = kwargs.get('grafana_url', ANSIBLE_GRAFANA_URL)
- self.grafana_api_key = kwargs.get('grafana_api_key', ANSIBLE_GRAFANA_API_KEY)
- self.grafana_user = kwargs.get('grafana_user', ANSIBLE_GRAFANA_USER)
- self.grafana_password = kwargs.get('grafana_password', ANSIBLE_GRAFANA_PASSWORD)
- self.grafana_org_id = kwargs.get('grafana_org_id', ANSIBLE_GRAFANA_ORG_ID)
- self.search = kwargs.get('search', ANSIBLE_GRAFANA_DASHBOARD_SEARCH)
+ self.grafana_url = kwargs.get("grafana_url", ANSIBLE_GRAFANA_URL)
+ self.grafana_api_key = kwargs.get("grafana_api_key", ANSIBLE_GRAFANA_API_KEY)
+ self.grafana_user = kwargs.get("grafana_user", ANSIBLE_GRAFANA_USER)
+ self.grafana_password = kwargs.get("grafana_password", ANSIBLE_GRAFANA_PASSWORD)
+ self.grafana_org_id = kwargs.get("grafana_org_id", ANSIBLE_GRAFANA_ORG_ID)
+ self.search = kwargs.get("search", ANSIBLE_GRAFANA_DASHBOARD_SEARCH)
def grafana_switch_organisation(self, headers):
try:
- r = open_url('%s/api/user/using/%s' % (self.grafana_url, self.grafana_org_id), headers=headers, method='POST')
+ r = open_url(
+ "%s/api/user/using/%s" % (self.grafana_url, self.grafana_org_id),
+ headers=headers,
+ method="POST",
+ )
except HTTPError as e:
- raise GrafanaAPIException('Unable to switch to organization %s : %s' % (self.grafana_org_id, to_native(e)))
+ raise GrafanaAPIException(
+ "Unable to switch to organization %s : %s"
+ % (self.grafana_org_id, to_native(e))
+ )
if r.getcode() != 200:
- raise GrafanaAPIException('Unable to switch to organization %s : %s' % (self.grafana_org_id, str(r.getcode())))
+ raise GrafanaAPIException(
+ "Unable to switch to organization %s : %s"
+ % (self.grafana_org_id, str(r.getcode()))
+ )
def grafana_headers(self):
- headers = {'content-type': 'application/json; charset=utf8'}
+ headers = {"content-type": "application/json; charset=utf8"}
if self.grafana_api_key:
api_key = self.grafana_api_key
if len(api_key) % 4 == 2:
display.deprecated(
"Passing a mangled version of the API key to the grafana_dashboard lookup is no longer necessary and should not be done.",
"2.0.0",
- collection_name='community.grafana',
+ collection_name="community.grafana",
)
- api_key += '=='
- headers['Authorization'] = "Bearer %s" % api_key
+ api_key += "=="
+ headers["Authorization"] = "Bearer %s" % api_key
else:
- headers['Authorization'] = basic_auth_header(self.grafana_user, self.grafana_password)
+ headers["Authorization"] = basic_auth_header(
+ self.grafana_user, self.grafana_password
+ )
self.grafana_switch_organisation(headers)
return headers
@@ -136,35 +149,44 @@ class GrafanaAPI:
dashboard_list = []
try:
if self.search:
- r = open_url('%s/api/search?query=%s' % (self.grafana_url, self.search), headers=headers, method='GET')
+ r = open_url(
+ "%s/api/search?query=%s" % (self.grafana_url, self.search),
+ headers=headers,
+ method="GET",
+ )
else:
- r = open_url('%s/api/search/' % self.grafana_url, headers=headers, method='GET')
+ r = open_url(
+ "%s/api/search/" % self.grafana_url, headers=headers, method="GET"
+ )
except HTTPError as e:
- raise GrafanaAPIException('Unable to search dashboards : %s' % to_native(e))
+ raise GrafanaAPIException("Unable to search dashboards : %s" % to_native(e))
if r.getcode() == 200:
try:
dashboard_list = json.loads(r.read())
except Exception as e:
- raise GrafanaAPIException('Unable to parse json list %s' % to_native(e))
+ raise GrafanaAPIException("Unable to parse json list %s" % to_native(e))
else:
- raise GrafanaAPIException('Unable to list grafana dashboards : %s' % str(r.getcode()))
+ raise GrafanaAPIException(
+ "Unable to list grafana dashboards : %s" % str(r.getcode())
+ )
return dashboard_list
class LookupModule(LookupBase):
-
def run(self, terms, variables=None, **kwargs):
-
- grafana_args = terms[0].split(' ')
+ grafana_args = terms[0].split(" ")
grafana_dict = {}
ret = []
for param in grafana_args:
try:
- key, value = param.split('=', 1)
+ key, value = param.split("=", 1)
except ValueError:
- raise AnsibleError("grafana_dashboard lookup plugin needs key=value pairs, but received %s" % terms)
+ raise AnsibleError(
+ "grafana_dashboard lookup plugin needs key=value pairs, but received %s"
+ % terms
+ )
grafana_dict[key] = value
grafana = GrafanaAPI(**grafana_dict)
diff --git a/ansible_collections/community/grafana/plugins/module_utils/base.py b/ansible_collections/community/grafana/plugins/module_utils/base.py
index 3a0174bbd..7d51601d8 100644
--- a/ansible_collections/community/grafana/plugins/module_utils/base.py
+++ b/ansible_collections/community/grafana/plugins/module_utils/base.py
@@ -16,7 +16,7 @@
#
# Copyright: (c) 2019, Rémi REY (@rrey)
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import, division, print_function
from ansible.module_utils.urls import url_argument_spec
__metaclass__ = type
@@ -29,26 +29,26 @@ def clean_url(url):
def grafana_argument_spec():
argument_spec = url_argument_spec()
- del argument_spec['force']
- del argument_spec['force_basic_auth']
- del argument_spec['http_agent']
+ del argument_spec["force"]
+ del argument_spec["force_basic_auth"]
+ del argument_spec["http_agent"]
# Avoid sanity error with devel
if "use_gssapi" in argument_spec:
- del argument_spec['use_gssapi']
+ del argument_spec["use_gssapi"]
argument_spec.update(
- state=dict(choices=['present', 'absent'], default='present'),
- url=dict(aliases=['grafana_url'], type='str', required=True),
- grafana_api_key=dict(type='str', no_log=True),
- url_username=dict(aliases=['grafana_user'], default='admin'),
- url_password=dict(aliases=['grafana_password'], default='admin', no_log=True),
+ state=dict(choices=["present", "absent"], default="present"),
+ url=dict(aliases=["grafana_url"], type="str", required=True),
+ grafana_api_key=dict(type="str", no_log=True),
+ url_username=dict(aliases=["grafana_user"], default="admin"),
+ url_password=dict(aliases=["grafana_password"], default="admin", no_log=True),
)
return argument_spec
def grafana_required_together():
- return [['url_username', 'url_password']]
+ return [["url_username", "url_password"]]
def grafana_mutually_exclusive():
- return [['url_username', 'grafana_api_key']]
+ return [["url_username", "grafana_api_key"]]
diff --git a/ansible_collections/community/grafana/plugins/modules/grafana_dashboard.py b/ansible_collections/community/grafana/plugins/modules/grafana_dashboard.py
index 99801d494..77a5a7565 100644
--- a/ansible_collections/community/grafana/plugins/modules/grafana_dashboard.py
+++ b/ansible_collections/community/grafana/plugins/modules/grafana_dashboard.py
@@ -6,7 +6,7 @@
from __future__ import absolute_import, division, print_function
-DOCUMENTATION = '''
+DOCUMENTATION = """
---
module: grafana_dashboard
author:
@@ -18,10 +18,17 @@ description:
options:
org_id:
description:
- - The Grafana Organisation ID where the dashboard will be imported / exported.
- - Not used when I(grafana_api_key) is set, because the grafana_api_key only belongs to one organisation..
+ - The Grafana organization ID where the dashboard will be imported / exported / deleted.
+ - Not used when I(grafana_api_key) is set, because the grafana_api_key only belongs to one organization.
+ - Mutually exclusive with C(org_name).
default: 1
type: int
+ org_name:
+ description:
+ - The Grafana organization name where the dashboard will be imported / exported / deleted.
+ - Not used when I(grafana_api_key) is set, because the grafana_api_key only belongs to one organization.
+ - Mutually exclusive with C(org_id).
+ type: str
folder:
description:
- The Grafana folder where this dashboard will be imported to.
@@ -58,7 +65,7 @@ options:
description:
- Override existing dashboard when state is present.
type: bool
- default: 'no'
+ default: false
dashboard_id:
description:
- Public Grafana.com dashboard id to import
@@ -80,55 +87,52 @@ options:
extends_documentation_fragment:
- community.grafana.basic_auth
- community.grafana.api_key
-'''
-
-EXAMPLES = '''
-- hosts: localhost
- connection: local
- tasks:
- - name: Import Grafana dashboard foo
- community.grafana.grafana_dashboard:
- grafana_url: http://grafana.company.com
- grafana_api_key: "{{ grafana_api_key }}"
- state: present
- commit_message: Updated by ansible
- overwrite: yes
- path: /path/to/dashboards/foo.json
-
- - name: Import Grafana dashboard Zabbix
- community.grafana.grafana_dashboard:
- grafana_url: http://grafana.company.com
- grafana_api_key: "{{ grafana_api_key }}"
- folder: zabbix
- dashboard_id: 6098
- dashbord_revision: 1
-
- - name: Import Grafana dashboard zabbix
- community.grafana.grafana_dashboard:
- grafana_url: http://grafana.company.com
- grafana_api_key: "{{ grafana_api_key }}"
- folder: public
- dashboard_url: https://grafana.com/api/dashboards/6098/revisions/1/download
-
- - name: Export dashboard
- community.grafana.grafana_dashboard:
- grafana_url: http://grafana.company.com
- grafana_user: "admin"
- grafana_password: "{{ grafana_password }}"
- org_id: 1
- state: export
- uid: "000000653"
- path: "/path/to/dashboards/000000653.json"
-'''
-
-RETURN = '''
+"""
+
+EXAMPLES = """
+- name: Import Grafana dashboard foo
+ community.grafana.grafana_dashboard:
+ grafana_url: http://grafana.company.com
+ grafana_api_key: "{{ grafana_api_key }}"
+ state: present
+ commit_message: Updated by ansible
+ overwrite: true
+ path: /path/to/dashboards/foo.json
+
+- name: Import Grafana dashboard Zabbix
+ community.grafana.grafana_dashboard:
+ grafana_url: http://grafana.company.com
+ grafana_api_key: "{{ grafana_api_key }}"
+ folder: zabbix
+ dashboard_id: 6098
+ dashboard_revision: 1
+
+- name: Import Grafana dashboard zabbix
+ community.grafana.grafana_dashboard:
+ grafana_url: http://grafana.company.com
+ grafana_api_key: "{{ grafana_api_key }}"
+ folder: public
+ dashboard_url: https://grafana.com/api/dashboards/6098/revisions/1/download
+
+- name: Export dashboard
+ community.grafana.grafana_dashboard:
+ grafana_url: http://grafana.company.com
+ grafana_user: "admin"
+ grafana_password: "{{ grafana_password }}"
+ org_id: 1
+ state: export
+ uid: "000000653"
+ path: "/path/to/dashboards/000000653.json"
+"""
+
+RETURN = """
---
uid:
description: uid or slug of the created / deleted / exported dashboard.
returned: success
type: str
sample: 000000063
-'''
+"""
import json
from ansible.module_utils.basic import AnsibleModule
@@ -136,7 +140,10 @@ from ansible.module_utils.urls import fetch_url
from ansible.module_utils.six.moves.urllib.parse import urlencode
from ansible.module_utils._text import to_native
from ansible.module_utils._text import to_text
-from ansible_collections.community.grafana.plugins.module_utils.base import grafana_argument_spec, clean_url
+from ansible_collections.community.grafana.plugins.module_utils.base import (
+ grafana_argument_spec,
+ clean_url,
+)
__metaclass__ = type
@@ -157,56 +164,91 @@ class GrafanaDeleteException(Exception):
pass
-def grafana_switch_organisation(module, grafana_url, org_id, headers):
- r, info = fetch_url(module, '%s/api/user/using/%s' % (grafana_url, org_id), headers=headers, method='POST')
- if info['status'] != 200:
- raise GrafanaAPIException('Unable to switch to organization %s : %s' % (org_id, info))
+def grafana_organization_id_by_name(module, grafana_url, org_name, headers):
+ r, info = fetch_url(
+ module, "%s/api/user/orgs" % grafana_url, headers=headers, method="GET"
+ )
+ if info["status"] != 200:
+ raise GrafanaAPIException("Unable to retrieve users organizations: %s" % info)
+ organizations = json.loads(to_text(r.read()))
+ for org in organizations:
+ if org["name"] == org_name:
+ return org["orgId"]
+
+ raise GrafanaAPIException(
+ "Current user isn't member of organization: %s" % org_name
+ )
+
+
+def grafana_switch_organization(module, grafana_url, org_id, headers):
+ r, info = fetch_url(
+ module,
+ "%s/api/user/using/%s" % (grafana_url, org_id),
+ headers=headers,
+ method="POST",
+ )
+ if info["status"] != 200:
+ raise GrafanaAPIException(
+ "Unable to switch to organization %s : %s" % (org_id, info)
+ )
def grafana_headers(module, data):
- headers = {'content-type': 'application/json; charset=utf8'}
- if 'grafana_api_key' in data and data['grafana_api_key']:
- headers['Authorization'] = "Bearer %s" % data['grafana_api_key']
+ headers = {"content-type": "application/json; charset=utf8"}
+ if "grafana_api_key" in data and data["grafana_api_key"]:
+ headers["Authorization"] = "Bearer %s" % data["grafana_api_key"]
else:
- module.params['force_basic_auth'] = True
- grafana_switch_organisation(module, data['url'], data['org_id'], headers)
+ module.params["force_basic_auth"] = True
+ if module.params["org_name"]:
+ org_name = module.params["org_name"]
+ data["org_id"] = grafana_organization_id_by_name(
+ module, data["url"], org_name, headers
+ )
+ grafana_switch_organization(module, data["url"], data["org_id"], headers)
return headers
def get_grafana_version(module, grafana_url, headers):
grafana_version = None
- r, info = fetch_url(module, '%s/api/frontend/settings' % grafana_url, headers=headers, method='GET')
- if info['status'] == 200:
+ r, info = fetch_url(
+ module, "%s/api/frontend/settings" % grafana_url, headers=headers, method="GET"
+ )
+ if info["status"] == 200:
try:
settings = json.loads(to_text(r.read()))
- grafana_version = settings['buildInfo']['version'].split('.')[0]
- except UnicodeError as e:
- raise GrafanaAPIException('Unable to decode version string to Unicode')
+ grafana_version = settings["buildInfo"]["version"].split(".")[0]
+ except UnicodeError:
+ raise GrafanaAPIException("Unable to decode version string to Unicode")
except Exception as e:
raise GrafanaAPIException(e)
else:
- raise GrafanaAPIException('Unable to get grafana version : %s' % info)
+ raise GrafanaAPIException("Unable to get grafana version: %s" % info)
return int(grafana_version)
def grafana_folder_exists(module, grafana_url, folder_name, headers):
# the 'General' folder is a special case, it's ID is always '0'
- if folder_name == 'General':
+ if folder_name == "General":
return True, 0
try:
- r, info = fetch_url(module, '%s/api/folders' % grafana_url, headers=headers, method='GET')
+ r, info = fetch_url(
+ module, "%s/api/folders" % grafana_url, headers=headers, method="GET"
+ )
- if info['status'] != 200:
- raise GrafanaAPIException("Unable to query Grafana API for folders (name: %s): %d" % (folder_name, info['status']))
+ if info["status"] != 200:
+ raise GrafanaAPIException(
+ "Unable to query Grafana API for folders (name: %s): %d"
+ % (folder_name, info["status"])
+ )
folders = json.loads(r.read())
for folder in folders:
- if folder['title'] == folder_name:
- return True, folder['id']
+ if folder["title"] == folder_name:
+ return True, folder["id"]
except Exception as e:
raise GrafanaAPIException(e)
@@ -219,73 +261,73 @@ def grafana_dashboard_exists(module, grafana_url, uid, headers):
grafana_version = get_grafana_version(module, grafana_url, headers)
if grafana_version >= 5:
- uri = '%s/api/dashboards/uid/%s' % (grafana_url, uid)
+ uri = "%s/api/dashboards/uid/%s" % (grafana_url, uid)
else:
- uri = '%s/api/dashboards/db/%s' % (grafana_url, uid)
+ uri = "%s/api/dashboards/db/%s" % (grafana_url, uid)
- r, info = fetch_url(module, uri, headers=headers, method='GET')
+ r, info = fetch_url(module, uri, headers=headers, method="GET")
- if info['status'] == 200:
+ if info["status"] == 200:
dashboard_exists = True
try:
dashboard = json.loads(r.read())
except Exception as e:
raise GrafanaAPIException(e)
- elif info['status'] == 404:
+ elif info["status"] == 404:
dashboard_exists = False
else:
- raise GrafanaAPIException('Unable to get dashboard %s : %s' % (uid, info))
+ raise GrafanaAPIException("Unable to get dashboard %s : %s" % (uid, info))
return dashboard_exists, dashboard
def grafana_dashboard_search(module, grafana_url, folder_id, title, headers):
-
# search by title
- uri = '%s/api/search?%s' % (grafana_url, urlencode({
- 'folderIds': folder_id,
- 'query': title,
- 'type': 'dash-db'
- }))
- r, info = fetch_url(module, uri, headers=headers, method='GET')
-
- if info['status'] == 200:
+ uri = "%s/api/search?%s" % (
+ grafana_url,
+ urlencode({"folderIds": folder_id, "query": title, "type": "dash-db"}),
+ )
+ r, info = fetch_url(module, uri, headers=headers, method="GET")
+
+ if info["status"] == 200:
try:
dashboards = json.loads(r.read())
for d in dashboards:
- if d['title'] == title:
- return grafana_dashboard_exists(module, grafana_url, d['uid'], headers)
+ if d["title"] == title:
+ return grafana_dashboard_exists(
+ module, grafana_url, d["uid"], headers
+ )
except Exception as e:
raise GrafanaAPIException(e)
else:
- raise GrafanaAPIException('Unable to search dashboard %s : %s' % (title, info))
+ raise GrafanaAPIException("Unable to search dashboard %s : %s" % (title, info))
return False, None
# for comparison, we sometimes need to ignore a few keys
-def grafana_dashboard_changed(payload, dashboard):
+def is_grafana_dashboard_changed(payload, dashboard):
# you don't need to set the version, but '0' is incremented to '1' by Grafana's API
- if 'version' in payload['dashboard']:
- del payload['dashboard']['version']
- if 'version' in dashboard['dashboard']:
- del dashboard['dashboard']['version']
+ if "version" in payload["dashboard"]:
+ del payload["dashboard"]["version"]
+ if "version" in dashboard["dashboard"]:
+ del dashboard["dashboard"]["version"]
# remove meta key if exists for compare
- if 'meta' in dashboard:
- del dashboard['meta']
- if 'meta' in payload:
- del payload['meta']
+ if "meta" in dashboard:
+ del dashboard["meta"]
+ if "meta" in payload:
+ del payload["meta"]
# if folderId is not provided in dashboard, set default folderId
- if 'folderId' not in dashboard:
- dashboard['folderId'] = 0
+ if "folderId" not in dashboard:
+ dashboard["folderId"] = 0
# Ignore dashboard ids since real identifier is uuid
- if 'id' in dashboard['dashboard']:
- del dashboard['dashboard']['id']
- if 'id' in payload['dashboard']:
- del payload['dashboard']['id']
+ if "id" in dashboard["dashboard"]:
+ del dashboard["dashboard"]["id"]
+ if "id" in payload["dashboard"]:
+ del payload["dashboard"]["id"]
if payload == dashboard:
return False
@@ -293,43 +335,48 @@ def grafana_dashboard_changed(payload, dashboard):
def grafana_create_dashboard(module, data):
-
# define data payload for grafana API
payload = {}
- if data.get('dashboard_id'):
- data['path'] = "https://grafana.com/api/dashboards/%s/revisions/%s/download" % (data['dashboard_id'], data['dashboard_revision'])
- if data['path'].startswith('http'):
- r, info = fetch_url(module, data['path'])
- if info['status'] != 200:
- raise GrafanaAPIException('Unable to download grafana dashboard from url %s : %s' % (data['path'], info))
+ if data.get("dashboard_id"):
+ data["path"] = "https://grafana.com/api/dashboards/%s/revisions/%s/download" % (
+ data["dashboard_id"],
+ data["dashboard_revision"],
+ )
+ if data["path"].startswith("http"):
+ r, info = fetch_url(module, data["path"])
+ if info["status"] != 200:
+ raise GrafanaAPIException(
+ "Unable to download grafana dashboard from url %s : %s"
+ % (data["path"], info)
+ )
payload = json.loads(r.read())
else:
try:
- with open(data['path'], 'r', encoding="utf-8") as json_file:
+ with open(data["path"], "r", encoding="utf-8") as json_file:
payload = json.load(json_file)
except Exception as e:
raise GrafanaAPIException("Can't load json file %s" % to_native(e))
# Check that the dashboard JSON is nested under the 'dashboard' key
- if 'dashboard' not in payload:
- payload = {'dashboard': payload}
+ if "dashboard" not in payload:
+ payload = {"dashboard": payload}
# define http header
headers = grafana_headers(module, data)
- grafana_version = get_grafana_version(module, data['url'], headers)
+ grafana_version = get_grafana_version(module, data["url"], headers)
if grafana_version < 5:
- if data.get('slug'):
- uid = data['slug']
- elif 'meta' in payload and 'slug' in payload['meta']:
- uid = payload['meta']['slug']
+ if data.get("slug"):
+ uid = data["slug"]
+ elif "meta" in payload and "slug" in payload["meta"]:
+ uid = payload["meta"]["slug"]
else:
- raise GrafanaMalformedJson('No slug found in json. Needed with grafana < 5')
+ raise GrafanaMalformedJson("No slug found in json. Needed with grafana < 5")
else:
- if data.get('uid'):
- uid = data['uid']
- elif 'uid' in payload['dashboard']:
- uid = payload['dashboard']['uid']
+ if data.get("uid"):
+ uid = data["uid"]
+ elif "uid" in payload["dashboard"]:
+ uid = payload["dashboard"]["uid"]
else:
uid = None
@@ -338,148 +385,223 @@ def grafana_create_dashboard(module, data):
# test if the folder exists
folder_exists = False
if grafana_version >= 5:
- folder_exists, folder_id = grafana_folder_exists(module, data['url'], data['folder'], headers)
+ folder_exists, folder_id = grafana_folder_exists(
+ module, data["url"], data["folder"], headers
+ )
if folder_exists is False:
- raise GrafanaAPIException("Dashboard folder '%s' does not exist." % data['folder'])
+ raise GrafanaAPIException(
+ "Dashboard folder '%s' does not exist." % data["folder"]
+ )
- payload['folderId'] = folder_id
+ payload["folderId"] = folder_id
# test if dashboard already exists
if uid:
dashboard_exists, dashboard = grafana_dashboard_exists(
- module, data['url'], uid, headers=headers)
+ module, data["url"], uid, headers=headers
+ )
else:
dashboard_exists, dashboard = grafana_dashboard_search(
- module, data['url'], folder_id, payload['dashboard']['title'], headers=headers)
+ module,
+ data["url"],
+ folder_id,
+ payload["dashboard"]["title"],
+ headers=headers,
+ )
if dashboard_exists is True:
- if grafana_dashboard_changed(payload, dashboard):
+ grafana_dashboard_changed = is_grafana_dashboard_changed(payload, dashboard)
+
+ if grafana_dashboard_changed:
+ if module.check_mode:
+ module.exit_json(
+ uid=uid,
+ failed=False,
+ changed=True,
+ msg="Dashboard %s will be updated" % payload["dashboard"]["title"],
+ )
# update
- if 'overwrite' in data and data['overwrite']:
- payload['overwrite'] = True
- if 'commit_message' in data and data['commit_message']:
- payload['message'] = data['commit_message']
-
- r, info = fetch_url(module, '%s/api/dashboards/db' % data['url'],
- data=json.dumps(payload), headers=headers, method='POST')
- if info['status'] == 200:
+ if "overwrite" in data and data["overwrite"]:
+ payload["overwrite"] = True
+ if "commit_message" in data and data["commit_message"]:
+ payload["message"] = data["commit_message"]
+
+ r, info = fetch_url(
+ module,
+ "%s/api/dashboards/db" % data["url"],
+ data=json.dumps(payload),
+ headers=headers,
+ method="POST",
+ )
+ if info["status"] == 200:
if grafana_version >= 5:
try:
dashboard = json.loads(r.read())
- uid = dashboard['uid']
+ uid = dashboard["uid"]
except Exception as e:
raise GrafanaAPIException(e)
- result['uid'] = uid
- result['msg'] = "Dashboard %s updated" % payload['dashboard']['title']
- result['changed'] = True
+ result["uid"] = uid
+ result["msg"] = "Dashboard %s updated" % payload["dashboard"]["title"]
+ result["changed"] = True
else:
- body = json.loads(info['body'])
- raise GrafanaAPIException('Unable to update the dashboard %s : %s (HTTP: %d)' %
- (uid, body['message'], info['status']))
+ body = json.loads(info["body"])
+ raise GrafanaAPIException(
+ "Unable to update the dashboard %s : %s (HTTP: %d)"
+ % (uid, body["message"], info["status"])
+ )
else:
# unchanged
- result['uid'] = uid
- result['msg'] = "Dashboard %s unchanged." % payload['dashboard']['title']
- result['changed'] = False
+ result["uid"] = uid
+ result["msg"] = "Dashboard %s unchanged." % payload["dashboard"]["title"]
+ result["changed"] = False
else:
+ if module.check_mode:
+ module.exit_json(
+ failed=False,
+ changed=True,
+ msg="Dashboard %s will be created" % payload["dashboard"]["title"],
+ )
+
# Ensure there is no id in payload
- if 'id' in payload['dashboard']:
- del payload['dashboard']['id']
-
- r, info = fetch_url(module, '%s/api/dashboards/db' % data['url'],
- data=json.dumps(payload), headers=headers, method='POST')
- if info['status'] == 200:
- result['msg'] = "Dashboard %s created" % payload['dashboard']['title']
- result['changed'] = True
+ if "id" in payload["dashboard"]:
+ del payload["dashboard"]["id"]
+
+ r, info = fetch_url(
+ module,
+ "%s/api/dashboards/db" % data["url"],
+ data=json.dumps(payload),
+ headers=headers,
+ method="POST",
+ )
+ if info["status"] == 200:
+ result["msg"] = "Dashboard %s created" % payload["dashboard"]["title"]
+ result["changed"] = True
if grafana_version >= 5:
try:
dashboard = json.loads(r.read())
- uid = dashboard['uid']
+ uid = dashboard["uid"]
except Exception as e:
raise GrafanaAPIException(e)
- result['uid'] = uid
+ result["uid"] = uid
else:
- raise GrafanaAPIException('Unable to create the new dashboard %s : %s - %s. (headers : %s)' %
- (payload['dashboard']['title'], info['status'], info, headers))
+ raise GrafanaAPIException(
+ "Unable to create the new dashboard %s : %s - %s. (headers : %s)"
+ % (payload["dashboard"]["title"], info["status"], info, headers)
+ )
return result
def grafana_delete_dashboard(module, data):
-
# define http headers
headers = grafana_headers(module, data)
- grafana_version = get_grafana_version(module, data['url'], headers)
+ grafana_version = get_grafana_version(module, data["url"], headers)
if grafana_version < 5:
- if data.get('slug'):
- uid = data['slug']
+ if data.get("slug"):
+ uid = data["slug"]
else:
- raise GrafanaMalformedJson('No slug parameter. Needed with grafana < 5')
+ raise GrafanaMalformedJson("No slug parameter. Needed with grafana < 5")
else:
- if data.get('uid'):
- uid = data['uid']
+ if data.get("uid"):
+ uid = data["uid"]
else:
- raise GrafanaDeleteException('No uid specified %s')
+ raise GrafanaDeleteException("No uid specified %s")
# test if dashboard already exists
- dashboard_exists, dashboard = grafana_dashboard_exists(module, data['url'], uid, headers=headers)
+ dashboard_exists, dashboard = grafana_dashboard_exists(
+ module, data["url"], uid, headers=headers
+ )
result = {}
if dashboard_exists is True:
+ if module.check_mode:
+ module.exit_json(
+ uid=uid,
+ failed=False,
+ changed=True,
+ msg="Dashboard %s will be deleted" % uid,
+ )
+
# delete
if grafana_version < 5:
- r, info = fetch_url(module, '%s/api/dashboards/db/%s' % (data['url'], uid), headers=headers, method='DELETE')
+ r, info = fetch_url(
+ module,
+ "%s/api/dashboards/db/%s" % (data["url"], uid),
+ headers=headers,
+ method="DELETE",
+ )
else:
- r, info = fetch_url(module, '%s/api/dashboards/uid/%s' % (data['url'], uid), headers=headers, method='DELETE')
- if info['status'] == 200:
- result['msg'] = "Dashboard %s deleted" % uid
- result['changed'] = True
- result['uid'] = uid
+ r, info = fetch_url(
+ module,
+ "%s/api/dashboards/uid/%s" % (data["url"], uid),
+ headers=headers,
+ method="DELETE",
+ )
+ if info["status"] == 200:
+ result["msg"] = "Dashboard %s deleted" % uid
+ result["changed"] = True
+ result["uid"] = uid
else:
- raise GrafanaAPIException('Unable to update the dashboard %s : %s' % (uid, info))
+ raise GrafanaAPIException(
+ "Unable to update the dashboard %s : %s" % (uid, info)
+ )
else:
# dashboard does not exist, do nothing
- result = {'msg': "Dashboard %s does not exist." % uid,
- 'changed': False,
- 'uid': uid}
+ result = {
+ "msg": "Dashboard %s does not exist." % uid,
+ "changed": False,
+ "uid": uid,
+ }
return result
def grafana_export_dashboard(module, data):
-
# define http headers
headers = grafana_headers(module, data)
- grafana_version = get_grafana_version(module, data['url'], headers)
+ grafana_version = get_grafana_version(module, data["url"], headers)
if grafana_version < 5:
- if data.get('slug'):
- uid = data['slug']
+ if data.get("slug"):
+ uid = data["slug"]
else:
- raise GrafanaMalformedJson('No slug parameter. Needed with grafana < 5')
+ raise GrafanaMalformedJson("No slug parameter. Needed with grafana < 5")
else:
- if data.get('uid'):
- uid = data['uid']
+ if data.get("uid"):
+ uid = data["uid"]
else:
- raise GrafanaExportException('No uid specified')
+ raise GrafanaExportException("No uid specified")
# test if dashboard already exists
- dashboard_exists, dashboard = grafana_dashboard_exists(module, data['url'], uid, headers=headers)
+ dashboard_exists, dashboard = grafana_dashboard_exists(
+ module, data["url"], uid, headers=headers
+ )
if dashboard_exists is True:
+ if module.check_mode:
+ module.exit_json(
+ uid=uid,
+ failed=False,
+ changed=True,
+ msg="Dashboard %s will be exported to %s" % (uid, data["path"]),
+ )
try:
- with open(data['path'], 'w', encoding="utf-8") as f:
+ with open(data["path"], "w", encoding="utf-8") as f:
f.write(json.dumps(dashboard, indent=2))
except Exception as e:
raise GrafanaExportException("Can't write json file : %s" % to_native(e))
- result = {'msg': "Dashboard %s exported to %s" % (uid, data['path']),
- 'uid': uid,
- 'changed': True}
+ result = {
+ "msg": "Dashboard %s exported to %s" % (uid, data["path"]),
+ "uid": uid,
+ "changed": True,
+ }
else:
- result = {'msg': "Dashboard %s does not exist." % uid,
- 'uid': uid,
- 'changed': False}
+ result = {
+ "msg": "Dashboard %s does not exist." % uid,
+ "uid": uid,
+ "changed": False,
+ }
return result
@@ -488,72 +610,75 @@ def main():
# use the predefined argument spec for url
argument_spec = grafana_argument_spec()
argument_spec.update(
- state=dict(choices=['present', 'absent', 'export'], default='present'),
- org_id=dict(default=1, type='int'),
- folder=dict(type='str', default='General'),
- uid=dict(type='str'),
- slug=dict(type='str'),
- path=dict(aliases=['dashboard_url'], type='str'),
- dashboard_id=dict(type='str'),
- dashboard_revision=dict(type='str', default='1'),
- overwrite=dict(type='bool', default=False),
- commit_message=dict(type='str', aliases=['message'],
- deprecated_aliases=[dict(name='message',
- version='2.0.0', collection_name="community.grafana")]),
+ state=dict(choices=["present", "absent", "export"], default="present"),
+ org_id=dict(default=1, type="int"),
+ org_name=dict(type="str"),
+ folder=dict(type="str", default="General"),
+ uid=dict(type="str"),
+ slug=dict(type="str"),
+ path=dict(aliases=["dashboard_url"], type="str"),
+ dashboard_id=dict(type="str"),
+ dashboard_revision=dict(type="str", default="1"),
+ overwrite=dict(type="bool", default=False),
+ commit_message=dict(
+ type="str",
+ aliases=["message"],
+ deprecated_aliases=[
+ dict(
+ name="message", version="2.0.0", collection_name="community.grafana"
+ )
+ ],
+ ),
)
module = AnsibleModule(
argument_spec=argument_spec,
- supports_check_mode=False,
+ supports_check_mode=True,
required_if=[
- ['state', 'export', ['path']],
+ ["state", "export", ["path"]],
+ ],
+ required_together=[["url_username", "url_password", "org_id"]],
+ mutually_exclusive=[
+ ["url_username", "grafana_api_key"],
+ ["uid", "slug"],
+ ["path", "dashboard_id"],
+ ["org_id", "org_name"],
],
- required_together=[['url_username', 'url_password', 'org_id']],
- mutually_exclusive=[['url_username', 'grafana_api_key'], ['uid', 'slug'], ['path', 'dashboard_id']],
)
module.params["url"] = clean_url(module.params["url"])
- if 'message' in module.params:
- module.fail_json(msg="'message' is reserved keyword, please change this parameter to 'commit_message'")
+ if "message" in module.params:
+ module.fail_json(
+ msg="'message' is reserved keyword, please change this parameter to 'commit_message'"
+ )
try:
- if module.params['state'] == 'present':
+ if module.params["state"] == "present":
result = grafana_create_dashboard(module, module.params)
- elif module.params['state'] == 'absent':
+ elif module.params["state"] == "absent":
result = grafana_delete_dashboard(module, module.params)
else:
result = grafana_export_dashboard(module, module.params)
except GrafanaAPIException as e:
- module.fail_json(
- failed=True,
- msg="error : %s" % to_native(e)
- )
+ module.fail_json(failed=True, msg="error : %s" % to_native(e))
return
except GrafanaMalformedJson as e:
- module.fail_json(
- failed=True,
- msg="error : %s" % to_native(e)
- )
+ module.fail_json(failed=True, msg="error : %s" % to_native(e))
return
except GrafanaDeleteException as e:
module.fail_json(
- failed=True,
- msg="error : Can't delete dashboard : %s" % to_native(e)
+ failed=True, msg="error : Can't delete dashboard : %s" % to_native(e)
)
return
except GrafanaExportException as e:
module.fail_json(
- failed=True,
- msg="error : Can't export dashboard : %s" % to_native(e)
+ failed=True, msg="error : Can't export dashboard : %s" % to_native(e)
)
return
- module.exit_json(
- failed=False,
- **result
- )
+ module.exit_json(failed=False, **result)
return
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/grafana/plugins/modules/grafana_datasource.py b/ansible_collections/community/grafana/plugins/modules/grafana_datasource.py
index 6346038f4..29cdbea7c 100644
--- a/ansible_collections/community/grafana/plugins/modules/grafana_datasource.py
+++ b/ansible_collections/community/grafana/plugins/modules/grafana_datasource.py
@@ -5,9 +5,10 @@
# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
-DOCUMENTATION = '''
+DOCUMENTATION = """
module: grafana_datasource
author:
- Thierry Sallé (@seuf)
@@ -46,6 +47,8 @@ options:
- camptocamp-prometheus-alertmanager-datasource
- loki
- redis-datasource
+ - tempo
+ - quickwit-quickwit-datasource
type: str
ds_url:
description:
@@ -67,15 +70,18 @@ options:
(index name), C(mysql) or C(postgres).
required: false
type: str
+ default: ''
user:
description:
- The datasource login user for influxdb datasources.
type: str
+ default: ''
password:
description:
- The datasource password.
- Stored as secure data, see C(enforce_secure_data) and notes!
type: str
+ default: ''
basic_auth_user:
description:
- The datasource basic auth user.
@@ -83,7 +89,7 @@ options:
type: str
basic_auth_password:
description:
- - The datasource basic auth password, when C(basic auth) is C(yes).
+ - The datasource basic auth password, when C(basic auth) is C(true).
- Stored as secure data, see C(enforce_secure_data) and notes!
type: str
with_credentials:
@@ -91,7 +97,7 @@ options:
- Whether credentials such as cookies or auth headers should be sent with cross-site
requests.
type: bool
- default: 'no'
+ default: false
tls_client_cert:
description:
- The client TLS certificate.
@@ -120,14 +126,22 @@ options:
description:
- Make this datasource the default one.
type: bool
- default: 'no'
+ default: false
org_id:
description:
- - Grafana Organisation ID in which the datasource should be created.
+ - Grafana organization ID in which the datasource should be created.
- Not used when C(grafana_api_key) is set, because the C(grafana_api_key) only
- belong to one organisation.
+ belongs to one organization.
+ - Mutually exclusive with C(org_name).
default: 1
type: int
+ org_name:
+ description:
+ - Grafana organization name in which the datasource should be created.
+ - Not used when C(grafana_api_key) is set, because the C(grafana_api_key) only
+ belongs to one organization.
+ - Mutually exclusive with C(org_id).
+ type: str
state:
description:
- Status of the datasource
@@ -166,7 +180,7 @@ options:
default: '@timestamp'
time_interval:
description:
- - Minimum group by interval for C(influxdb) or C(elasticsearch) datasources.
+ - Minimum group by interval for C(influxdb), C(elasticsearch) or C(prometheus) datasources.
- for example C(>10s).
type: str
interval:
@@ -180,6 +194,7 @@ options:
- Monthly
- Yearly
type: str
+ default: ''
tsdb_version:
description:
- The opentsdb version.
@@ -213,7 +228,7 @@ options:
description:
- Use trends or not for zabbix datasource type.
type: bool
- default: False
+ default: false
aws_auth_type:
description:
- Type for AWS authentication for CloudWatch datasource type (authType of grafana
@@ -280,7 +295,6 @@ options:
aws_custom_metrics_namespaces:
description:
- Namespaces of Custom Metrics for CloudWatch datasource type
- default: ''
required: false
type: str
azure_cloud:
@@ -350,9 +364,9 @@ notes:
data will not be updated after initial creation! To force the secure data update you have to set I(enforce_secure_data=True).
- Hint, with the C(enforce_secure_data) always reporting changed=True, you might just do one Task updating the datasource without
any secure data and make a separate playbook/task also changing the secure data. This way it will not break any workflow.
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = """
---
- name: Create elasticsearch datasource
community.grafana.grafana_datasource:
@@ -460,9 +474,9 @@ EXAMPLES = '''
additional_secure_json_data:
httpHeaderValue1: "Bearer ihavenogroot"
enforce_secure_data: true
-'''
+"""
-RETURN = '''
+RETURN = """
---
datasource:
description: datasource created/updated by module
@@ -488,13 +502,13 @@ datasource:
"user": "",
"password": "",
"withCredentials": false }
-'''
+"""
import json
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.six.moves.urllib.parse import quote
-from ansible.module_utils.urls import fetch_url, url_argument_spec, basic_auth_header
+from ansible.module_utils.urls import fetch_url, basic_auth_header
from ansible_collections.community.grafana.plugins.module_utils import base
@@ -506,175 +520,191 @@ ES_VERSION_MAPPING = {
def compare_datasources(new, current, compareSecureData=True):
- if new['uid'] is None:
- del current['uid']
- del new['uid']
- del current['typeLogoUrl']
- del current['id']
- if 'version' in current:
- del current['version']
- if 'readOnly' in current:
- del current['readOnly']
- if current['basicAuth'] is False:
- del current['basicAuthUser']
- if 'password' in current:
- del current['password']
- if 'basicAuthPassword' in current:
- del current['basicAuthPassword']
+ if new["uid"] is None:
+ del current["uid"]
+ del new["uid"]
+ del current["typeLogoUrl"]
+ del current["id"]
+ if "version" in current:
+ del current["version"]
+ if "readOnly" in current:
+ del current["readOnly"]
+ if current["basicAuth"] is False:
+ if "basicAuthUser" in current:
+ del current["basicAuthUser"]
+ if "password" in current:
+ del current["password"]
+ if "basicAuthPassword" in current:
+ del current["basicAuthPassword"]
# check if secureJsonData should be compared
if not compareSecureData:
# if we should ignore it just drop alltogether
- new.pop('secureJsonData', None)
- new.pop('secureJsonFields', None)
- current.pop('secureJsonData', None)
- current.pop('secureJsonFields', None)
+ new.pop("secureJsonData", None)
+ new.pop("secureJsonFields", None)
+ current.pop("secureJsonData", None)
+ current.pop("secureJsonFields", None)
else:
# handle secureJsonData/secureJsonFields, some current facts:
# - secureJsonFields is reporting each field set as true
# - secureJsonFields once set cant be removed (DS has to be deleted)
- if not new.get('secureJsonData'):
+ if not new.get("secureJsonData"):
# secureJsonData is not provided so just remove both for comparision
- new.pop('secureJsonData', None)
- current.pop('secureJsonFields', None)
+ new.pop("secureJsonData", None)
+ current.pop("secureJsonFields", None)
else:
# we have some secure data so just "rename" secureJsonFields for comparison as it will change anyhow everytime
- current['secureJsonData'] = current.pop('secureJsonFields')
+ current["secureJsonData"] = current.pop("secureJsonFields")
return dict(before=current, after=new)
-def get_datasource_payload(data):
+def get_datasource_payload(data, org_id=None):
payload = {
- 'orgId': data['org_id'],
- 'name': data['name'],
- 'uid': data['uid'],
- 'type': data['ds_type'],
- 'access': data['access'],
- 'url': data['ds_url'],
- 'database': data['database'],
- 'withCredentials': data['with_credentials'],
- 'isDefault': data['is_default'],
- 'user': data['user'],
- 'jsonData': data['additional_json_data'],
- 'secureJsonData': data['additional_secure_json_data']
+ "orgId": data["org_id"] if org_id is None else org_id,
+ "name": data["name"],
+ "uid": data["uid"],
+ "type": data["ds_type"],
+ "access": data["access"],
+ "url": data["ds_url"],
+ "database": data["database"],
+ "withCredentials": data["with_credentials"],
+ "isDefault": data["is_default"],
+ "user": data["user"],
+ "jsonData": data["additional_json_data"],
+ "secureJsonData": data["additional_secure_json_data"],
}
- json_data = payload['jsonData']
- secure_json_data = payload['secureJsonData']
+ json_data = payload["jsonData"]
+ secure_json_data = payload["secureJsonData"]
# define password
- if data.get('password'):
- secure_json_data['password'] = data['password']
+ if data.get("password"):
+ secure_json_data["password"] = data["password"]
# define basic auth
- if 'basic_auth_user' in data and data['basic_auth_user'] and 'basic_auth_password' in data and data['basic_auth_password']:
- payload['basicAuth'] = True
- payload['basicAuthUser'] = data['basic_auth_user']
- secure_json_data['basicAuthPassword'] = data['basic_auth_password']
+ if (
+ "basic_auth_user" in data
+ and data["basic_auth_user"]
+ and "basic_auth_password" in data
+ and data["basic_auth_password"]
+ ):
+ payload["basicAuth"] = True
+ payload["basicAuthUser"] = data["basic_auth_user"]
+ secure_json_data["basicAuthPassword"] = data["basic_auth_password"]
else:
- payload['basicAuth'] = False
+ payload["basicAuth"] = False
# define tls auth
- if data.get('tls_client_cert') and data.get('tls_client_key'):
- json_data['tlsAuth'] = True
- if data.get('tls_ca_cert'):
- secure_json_data['tlsCACert'] = data['tls_ca_cert']
- secure_json_data['tlsClientCert'] = data['tls_client_cert']
- secure_json_data['tlsClientKey'] = data['tls_client_key']
- json_data['tlsAuthWithCACert'] = True
+ if data.get("tls_client_cert") and data.get("tls_client_key"):
+ json_data["tlsAuth"] = True
+ if data.get("tls_ca_cert"):
+ secure_json_data["tlsCACert"] = data["tls_ca_cert"]
+ secure_json_data["tlsClientCert"] = data["tls_client_cert"]
+ secure_json_data["tlsClientKey"] = data["tls_client_key"]
+ json_data["tlsAuthWithCACert"] = True
else:
- secure_json_data['tlsClientCert'] = data['tls_client_cert']
- secure_json_data['tlsClientKey'] = data['tls_client_key']
+ secure_json_data["tlsClientCert"] = data["tls_client_cert"]
+ secure_json_data["tlsClientKey"] = data["tls_client_key"]
else:
- json_data['tlsAuth'] = False
- json_data['tlsAuthWithCACert'] = False
- if data.get('tls_ca_cert'):
- json_data['tlsAuthWithCACert'] = True
- secure_json_data['tlsCACert'] = data['tls_ca_cert']
+ json_data["tlsAuth"] = False
+ json_data["tlsAuthWithCACert"] = False
+ if data.get("tls_ca_cert"):
+ json_data["tlsAuthWithCACert"] = True
+ secure_json_data["tlsCACert"] = data["tls_ca_cert"]
- if data.get('tls_skip_verify'):
- json_data['tlsSkipVerify'] = True
+ if data.get("tls_skip_verify"):
+ json_data["tlsSkipVerify"] = True
# datasource type related parameters
- if data['ds_type'] == 'elasticsearch':
-
- json_data['maxConcurrentShardRequests'] = data['max_concurrent_shard_requests']
- json_data['timeField'] = data['time_field']
- if data.get('interval'):
- json_data['interval'] = data['interval']
+ if data["ds_type"] == "elasticsearch":
+ json_data["maxConcurrentShardRequests"] = data["max_concurrent_shard_requests"]
+ json_data["timeField"] = data["time_field"]
+ if data.get("interval"):
+ json_data["interval"] = data["interval"]
# Handle changes in es_version format in Grafana < 8.x which used to
# be integers and is now semver format
try:
- es_version = int(data['es_version'])
+ es_version = int(data["es_version"])
if es_version < 56:
- json_data.pop('maxConcurrentShardRequests')
+ json_data.pop("maxConcurrentShardRequests")
except ValueError:
# Retrieve the Semver format expected by API
- es_version = ES_VERSION_MAPPING.get(data['es_version'])
- json_data['esVersion'] = es_version
+ es_version = ES_VERSION_MAPPING.get(data["es_version"])
+ json_data["esVersion"] = es_version
- if data['ds_type'] == 'elasticsearch' or data['ds_type'] == 'influxdb':
- if data.get('time_interval'):
- json_data['timeInterval'] = data['time_interval']
+ if data["ds_type"] in ["elasticsearch", "influxdb", "prometheus"]:
+ if data.get("time_interval"):
+ json_data["timeInterval"] = data["time_interval"]
- if data['ds_type'] == 'opentsdb':
- json_data['tsdbVersion'] = data['tsdb_version']
- if data['tsdb_resolution'] == 'second':
- json_data['tsdbResolution'] = 1
+ if data["ds_type"] == "opentsdb":
+ json_data["tsdbVersion"] = data["tsdb_version"]
+ if data["tsdb_resolution"] == "second":
+ json_data["tsdbResolution"] = 1
else:
- json_data['tsdbResolution'] = 2
-
- if data['ds_type'] == 'postgres':
- json_data['sslmode'] = data['sslmode']
-
- if data['ds_type'] == 'alexanderzobnin-zabbix-datasource':
- if data.get('trends'):
- json_data['trends'] = True
- json_data['username'] = data['zabbix_user']
- json_data['password'] = data['zabbix_password']
-
- if data['ds_type'] == 'grafana-azure-monitor-datasource':
- json_data['tenantId'] = data['azure_tenant']
- json_data['clientId'] = data['azure_client']
- json_data['cloudName'] = data['azure_cloud']
- json_data['clientsecret'] = 'clientsecret'
- if data.get('azure_secret'):
- secure_json_data['clientSecret'] = data['azure_secret']
-
- if data['ds_type'] == 'cloudwatch':
- if data.get('aws_credentials_profile'):
- payload['database'] = data.get('aws_credentials_profile')
-
- json_data['authType'] = data['aws_auth_type']
- json_data['defaultRegion'] = data['aws_default_region']
-
- if data.get('aws_custom_metrics_namespaces'):
- json_data['customMetricsNamespaces'] = data.get('aws_custom_metrics_namespaces')
- if data.get('aws_assume_role_arn'):
- json_data['assumeRoleArn'] = data.get('aws_assume_role_arn')
- if data.get('aws_access_key') and data.get('aws_secret_key'):
- secure_json_data['accessKey'] = data.get('aws_access_key')
- secure_json_data['secretKey'] = data.get('aws_secret_key')
-
- payload['jsonData'] = json_data
- payload['secureJsonData'] = secure_json_data
+ json_data["tsdbResolution"] = 2
+
+ if data["ds_type"] == "postgres":
+ json_data["sslmode"] = data["sslmode"]
+
+ if data["ds_type"] == "alexanderzobnin-zabbix-datasource":
+ if data.get("trends"):
+ json_data["trends"] = True
+ json_data["username"] = data["zabbix_user"]
+ json_data["password"] = data["zabbix_password"]
+
+ if data["ds_type"] == "grafana-azure-monitor-datasource":
+ json_data["tenantId"] = data["azure_tenant"]
+ json_data["clientId"] = data["azure_client"]
+ json_data["cloudName"] = data["azure_cloud"]
+ json_data["clientsecret"] = "clientsecret"
+ if data.get("azure_secret"):
+ secure_json_data["clientSecret"] = data["azure_secret"]
+
+ if data["ds_type"] == "cloudwatch":
+ if data.get("aws_credentials_profile"):
+ payload["database"] = data.get("aws_credentials_profile")
+
+ json_data["authType"] = data["aws_auth_type"]
+ json_data["defaultRegion"] = data["aws_default_region"]
+
+ if data.get("aws_custom_metrics_namespaces"):
+ json_data["customMetricsNamespaces"] = data.get(
+ "aws_custom_metrics_namespaces"
+ )
+ if data.get("aws_assume_role_arn"):
+ json_data["assumeRoleArn"] = data.get("aws_assume_role_arn")
+ if data.get("aws_access_key") and data.get("aws_secret_key"):
+ secure_json_data["accessKey"] = data.get("aws_access_key")
+ secure_json_data["secretKey"] = data.get("aws_secret_key")
+
+ payload["jsonData"] = json_data
+ payload["secureJsonData"] = secure_json_data
return payload
class GrafanaInterface(object):
-
def __init__(self, module):
self._module = module
self.grafana_url = base.clean_url(module.params.get("url"))
+ self.org_id = None
# {{{ Authentication header
self.headers = {"Content-Type": "application/json"}
- if module.params.get('grafana_api_key', None):
- self.headers["Authorization"] = "Bearer %s" % module.params['grafana_api_key']
+ if module.params.get("grafana_api_key", None):
+ self.headers["Authorization"] = (
+ "Bearer %s" % module.params["grafana_api_key"]
+ )
else:
- self.headers["Authorization"] = basic_auth_header(module.params['url_username'], module.params['url_password'])
- self.switch_organisation(module.params['org_id'])
+ self.headers["Authorization"] = basic_auth_header(
+ module.params["url_username"], module.params["url_password"]
+ )
+ self.org_id = (
+ self.organization_by_name(module.params["org_name"])
+ if module.params["org_name"]
+ else module.params["org_id"]
+ )
+ self.switch_organization(self.org_id)
# }}}
def _send_request(self, url, data=None, headers=None, method="GET"):
@@ -684,125 +714,200 @@ class GrafanaInterface(object):
headers = []
full_url = "{grafana_url}{path}".format(grafana_url=self.grafana_url, path=url)
- resp, info = fetch_url(self._module, full_url, data=data, headers=headers, method=method)
+ resp, info = fetch_url(
+ self._module, full_url, data=data, headers=headers, method=method
+ )
status_code = info["status"]
if status_code == 404:
return None
elif status_code == 401:
- self._module.fail_json(failed=True, msg="Unauthorized to perform action '%s' on '%s'" % (method, full_url))
+ self._module.fail_json(
+ failed=True,
+ msg="Unauthorized to perform action '%s' on '%s'" % (method, full_url),
+ )
elif status_code == 403:
self._module.fail_json(failed=True, msg="Permission Denied")
elif status_code == 200:
return self._module.from_json(resp.read())
- self._module.fail_json(failed=True, msg="Grafana API answered with HTTP %d for url %s and data %s" % (status_code, url, data))
+ self._module.fail_json(
+ failed=True,
+ msg="Grafana API answered with HTTP %d for url %s and data %s"
+ % (status_code, url, data),
+ )
- def switch_organisation(self, org_id):
+ def switch_organization(self, org_id):
url = "/api/user/using/%d" % org_id
- response = self._send_request(url, headers=self.headers, method='POST')
+ self._send_request(url, headers=self.headers, method="POST")
+
+ def organization_by_name(self, org_name):
+ url = "/api/user/orgs"
+ organizations = self._send_request(url, headers=self.headers, method="GET")
+ orga = next((org for org in organizations if org["name"] == org_name))
+ if orga:
+ return orga["orgId"]
+
+ return self._module.fail_json(
+ failed=True, msg="Current user isn't member of organization: %s" % org_name
+ )
def datasource_by_name(self, name):
- datasource_exists = False
- ds = {}
- url = "/api/datasources/name/%s" % quote(name, safe='')
- return self._send_request(url, headers=self.headers, method='GET')
+ url = "/api/datasources/name/%s" % quote(name, safe="")
+ return self._send_request(url, headers=self.headers, method="GET")
def delete_datasource(self, name):
- url = "/api/datasources/name/%s" % quote(name, safe='')
- self._send_request(url, headers=self.headers, method='DELETE')
+ url = "/api/datasources/name/%s" % quote(name, safe="")
+ self._send_request(url, headers=self.headers, method="DELETE")
def update_datasource(self, ds_id, data):
url = "/api/datasources/%d" % ds_id
- self._send_request(url, data=data, headers=self.headers, method='PUT')
+ self._send_request(url, data=data, headers=self.headers, method="PUT")
def create_datasource(self, data):
url = "/api/datasources"
- self._send_request(url, data=data, headers=self.headers, method='POST')
+ self._send_request(url, data=data, headers=self.headers, method="POST")
def setup_module_object():
argument_spec = base.grafana_argument_spec()
argument_spec.update(
- name=dict(required=True, type='str'),
- uid=dict(type='str'),
- ds_type=dict(choices=['graphite',
- 'prometheus',
- 'elasticsearch',
- 'influxdb',
- 'opentsdb',
- 'mysql',
- 'postgres',
- 'cloudwatch',
- 'alexanderzobnin-zabbix-datasource',
- 'grafana-azure-monitor-datasource',
- 'camptocamp-prometheus-alertmanager-datasource',
- 'sni-thruk-datasource',
- 'redis-datasource',
- 'loki']),
- ds_url=dict(type='str'),
- access=dict(default='proxy', choices=['proxy', 'direct']),
- database=dict(type='str', default=""),
- user=dict(default='', type='str'),
- password=dict(default='', no_log=True, type='str'),
- basic_auth_user=dict(type='str'),
- basic_auth_password=dict(type='str', no_log=True),
- with_credentials=dict(default=False, type='bool'),
- tls_client_cert=dict(type='str', no_log=True),
- tls_client_key=dict(type='str', no_log=True),
- tls_ca_cert=dict(type='str', no_log=True),
- tls_skip_verify=dict(type='bool', default=False),
- is_default=dict(default=False, type='bool'),
- org_id=dict(default=1, type='int'),
- es_version=dict(type='str', default="7.10+", choices=["2", "5", "56", "60",
- "70", "7.7+", "7.10+",
- "8.0+"]),
- max_concurrent_shard_requests=dict(type='int', default=256),
- time_field=dict(default='@timestamp', type='str'),
- time_interval=dict(type='str'),
- interval=dict(type='str', choices=['', 'Hourly', 'Daily', 'Weekly', 'Monthly', 'Yearly'], default=''),
- tsdb_version=dict(type='int', default=1, choices=[1, 2, 3]),
- tsdb_resolution=dict(type='str', default='second', choices=['second', 'millisecond']),
- sslmode=dict(default='disable', choices=['disable', 'require', 'verify-ca', 'verify-full']),
- trends=dict(default=False, type='bool'),
- aws_auth_type=dict(default='keys', choices=['keys', 'credentials', 'arn', 'default']),
- aws_default_region=dict(default='us-east-1', choices=['ap-northeast-1', 'ap-northeast-2', 'ap-southeast-1', 'ap-southeast-2', 'ap-south-1',
- 'ca-central-1',
- 'cn-north-1', 'cn-northwest-1',
- 'eu-central-1', 'eu-west-1', 'eu-west-2', 'eu-west-3',
- 'sa-east-1',
- 'us-east-1', 'us-east-2', 'us-gov-west-1', 'us-west-1', 'us-west-2']),
- aws_access_key=dict(default='', no_log=True, type='str'),
- aws_secret_key=dict(default='', no_log=True, type='str'),
- aws_credentials_profile=dict(default='', type='str'),
- aws_assume_role_arn=dict(default='', type='str'),
- aws_custom_metrics_namespaces=dict(type='str'),
- azure_cloud=dict(type='str', default='azuremonitor', choices=['azuremonitor', 'chinaazuremonitor', 'govazuremonitor', 'germanyazuremonitor']),
- azure_tenant=dict(type='str'),
- azure_client=dict(type='str'),
- azure_secret=dict(type='str', no_log=True),
- zabbix_user=dict(type='str'),
- zabbix_password=dict(type='str', no_log=True),
- additional_json_data=dict(type='dict', default={}, required=False),
- additional_secure_json_data=dict(type='dict', default={}, required=False),
- enforce_secure_data=dict(type='bool', default=False, required=False)
+ name=dict(required=True, type="str"),
+ uid=dict(type="str"),
+ ds_type=dict(
+ choices=[
+ "graphite",
+ "prometheus",
+ "elasticsearch",
+ "influxdb",
+ "opentsdb",
+ "mysql",
+ "postgres",
+ "cloudwatch",
+ "alexanderzobnin-zabbix-datasource",
+ "grafana-azure-monitor-datasource",
+ "camptocamp-prometheus-alertmanager-datasource",
+ "sni-thruk-datasource",
+ "redis-datasource",
+ "loki",
+ "tempo",
+ "quickwit-quickwit-datasource",
+ ]
+ ),
+ ds_url=dict(type="str"),
+ access=dict(default="proxy", choices=["proxy", "direct"]),
+ database=dict(type="str", default=""),
+ user=dict(default="", type="str"),
+ password=dict(default="", no_log=True, type="str"),
+ basic_auth_user=dict(type="str"),
+ basic_auth_password=dict(type="str", no_log=True),
+ with_credentials=dict(default=False, type="bool"),
+ tls_client_cert=dict(type="str", no_log=True),
+ tls_client_key=dict(type="str", no_log=True),
+ tls_ca_cert=dict(type="str", no_log=True),
+ tls_skip_verify=dict(type="bool", default=False),
+ is_default=dict(default=False, type="bool"),
+ org_id=dict(default=1, type="int"),
+ org_name=dict(type="str"),
+ es_version=dict(
+ type="str",
+ default="7.10+",
+ choices=["2", "5", "56", "60", "70", "7.7+", "7.10+", "8.0+"],
+ ),
+ max_concurrent_shard_requests=dict(type="int", default=256),
+ time_field=dict(default="@timestamp", type="str"),
+ time_interval=dict(type="str"),
+ interval=dict(
+ type="str",
+ choices=["", "Hourly", "Daily", "Weekly", "Monthly", "Yearly"],
+ default="",
+ ),
+ tsdb_version=dict(type="int", default=1, choices=[1, 2, 3]),
+ tsdb_resolution=dict(
+ type="str", default="second", choices=["second", "millisecond"]
+ ),
+ sslmode=dict(
+ default="disable",
+ choices=["disable", "require", "verify-ca", "verify-full"],
+ ),
+ trends=dict(default=False, type="bool"),
+ aws_auth_type=dict(
+ default="keys", choices=["keys", "credentials", "arn", "default"]
+ ),
+ aws_default_region=dict(
+ default="us-east-1",
+ choices=[
+ "ap-northeast-1",
+ "ap-northeast-2",
+ "ap-southeast-1",
+ "ap-southeast-2",
+ "ap-south-1",
+ "ca-central-1",
+ "cn-north-1",
+ "cn-northwest-1",
+ "eu-central-1",
+ "eu-west-1",
+ "eu-west-2",
+ "eu-west-3",
+ "sa-east-1",
+ "us-east-1",
+ "us-east-2",
+ "us-gov-west-1",
+ "us-west-1",
+ "us-west-2",
+ ],
+ ),
+ aws_access_key=dict(default="", no_log=True, type="str"),
+ aws_secret_key=dict(default="", no_log=True, type="str"),
+ aws_credentials_profile=dict(default="", type="str"),
+ aws_assume_role_arn=dict(default="", type="str"),
+ aws_custom_metrics_namespaces=dict(type="str"),
+ azure_cloud=dict(
+ type="str",
+ default="azuremonitor",
+ choices=[
+ "azuremonitor",
+ "chinaazuremonitor",
+ "govazuremonitor",
+ "germanyazuremonitor",
+ ],
+ ),
+ azure_tenant=dict(type="str"),
+ azure_client=dict(type="str"),
+ azure_secret=dict(type="str", no_log=True),
+ zabbix_user=dict(type="str"),
+ zabbix_password=dict(type="str", no_log=True),
+ additional_json_data=dict(type="dict", default={}, required=False),
+ additional_secure_json_data=dict(type="dict", default={}, required=False),
+ enforce_secure_data=dict(type="bool", default=False, required=False),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=False,
- required_together=[['url_username', 'url_password', 'org_id'], ['tls_client_cert', 'tls_client_key']],
- mutually_exclusive=[['url_username', 'grafana_api_key'], ['tls_ca_cert', 'tls_skip_verify']],
+ required_together=[
+ ["url_username", "url_password", "org_id"],
+ ["tls_client_cert", "tls_client_key"],
+ ],
+ mutually_exclusive=[
+ ["url_username", "grafana_api_key"],
+ ["tls_ca_cert", "tls_skip_verify"],
+ ["org_id", "org_name"],
+ ],
required_if=[
- ['state', 'present', ['ds_type', 'ds_url']],
- ['ds_type', 'opentsdb', ['tsdb_version', 'tsdb_resolution']],
- ['ds_type', 'influxdb', ['database']],
- ['ds_type', 'elasticsearch', ['database', 'es_version', 'time_field', 'interval']],
- ['ds_type', 'mysql', ['database']],
- ['ds_type', 'postgres', ['database', 'sslmode']],
- ['ds_type', 'cloudwatch', ['aws_auth_type', 'aws_default_region']],
- ['es_version', "56", ['max_concurrent_shard_requests']],
- ['es_version', "60", ['max_concurrent_shard_requests']],
- ['es_version', "70", ['max_concurrent_shard_requests']]
+ ["state", "present", ["ds_type", "ds_url"]],
+ ["ds_type", "opentsdb", ["tsdb_version", "tsdb_resolution"]],
+ ["ds_type", "influxdb", ["database"]],
+ [
+ "ds_type",
+ "elasticsearch",
+ ["database", "es_version", "time_field", "interval"],
+ ],
+ ["ds_type", "mysql", ["database"]],
+ ["ds_type", "postgres", ["database", "sslmode"]],
+ ["ds_type", "cloudwatch", ["aws_auth_type", "aws_default_region"]],
+ ["es_version", "56", ["max_concurrent_shard_requests"]],
+ ["es_version", "60", ["max_concurrent_shard_requests"]],
+ ["es_version", "70", ["max_concurrent_shard_requests"]],
],
)
return module
@@ -811,35 +916,52 @@ def setup_module_object():
def main():
module = setup_module_object()
- state = module.params['state']
- name = module.params['name']
- enforce_secure_data = module.params['enforce_secure_data']
+ state = module.params["state"]
+ name = module.params["name"]
+ enforce_secure_data = module.params["enforce_secure_data"]
grafana_iface = GrafanaInterface(module)
ds = grafana_iface.datasource_by_name(name)
- if state == 'present':
- payload = get_datasource_payload(module.params)
+ if state == "present":
+ payload = get_datasource_payload(module.params, grafana_iface.org_id)
if ds is None:
grafana_iface.create_datasource(payload)
ds = grafana_iface.datasource_by_name(name)
- module.exit_json(changed=True, datasource=ds, msg='Datasource %s created' % name)
+ module.exit_json(
+ changed=True, datasource=ds, msg="Datasource %s created" % name
+ )
else:
diff = compare_datasources(payload.copy(), ds.copy(), enforce_secure_data)
- if diff.get('before') == diff.get('after'):
- module.exit_json(changed=False, datasource=ds, msg='Datasource %s unchanged' % name)
- grafana_iface.update_datasource(ds.get('id'), payload)
+ if diff.get("before") == diff.get("after"):
+ module.exit_json(
+ changed=False, datasource=ds, msg="Datasource %s unchanged" % name
+ )
+ grafana_iface.update_datasource(ds.get("id"), payload)
ds = grafana_iface.datasource_by_name(name)
- if diff.get('before') == diff.get('after'):
- module.exit_json(changed=False, datasource=ds, msg='Datasource %s unchanged' % name)
-
- module.exit_json(changed=True, diff=diff, datasource=ds, msg='Datasource %s updated' % name)
+ if diff.get("before") == diff.get("after"):
+ module.exit_json(
+ changed=False, datasource=ds, msg="Datasource %s unchanged" % name
+ )
+
+ module.exit_json(
+ changed=True,
+ diff=diff,
+ datasource=ds,
+ msg="Datasource %s updated" % name,
+ )
else:
if ds is None:
- module.exit_json(changed=False, datasource=None, msg='Datasource %s does not exist.' % name)
+ module.exit_json(
+ changed=False,
+ datasource=None,
+ msg="Datasource %s does not exist." % name,
+ )
grafana_iface.delete_datasource(name)
- module.exit_json(changed=True, datasource=None, msg='Datasource %s deleted.' % name)
+ module.exit_json(
+ changed=True, datasource=None, msg="Datasource %s deleted." % name
+ )
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/grafana/plugins/modules/grafana_folder.py b/ansible_collections/community/grafana/plugins/modules/grafana_folder.py
index d39e56e41..73c437dbb 100644
--- a/ansible_collections/community/grafana/plugins/modules/grafana_folder.py
+++ b/ansible_collections/community/grafana/plugins/modules/grafana_folder.py
@@ -19,7 +19,7 @@
from __future__ import absolute_import, division, print_function
-DOCUMENTATION = '''
+DOCUMENTATION = """
---
module: grafana_folder
author:
@@ -44,20 +44,35 @@ options:
default: present
type: str
choices: ["present", "absent"]
+ org_id:
+ description:
+ - Grafana organization ID in which the datasource should be created.
+ - Not used when C(grafana_api_key) is set, because the C(grafana_api_key) only
+ belongs to one organization.
+ - Mutually exclusive with C(org_name).
+ default: 1
+ type: int
+ org_name:
+ description:
+ - Grafana organization name in which the datasource should be created.
+ - Not used when C(grafana_api_key) is set, because the C(grafana_api_key) only
+ belongs to one organization.
+ - Mutually exclusive with C(org_id).
+ type: str
skip_version_check:
description:
- Skip Grafana version check and try to reach api endpoint anyway.
- - This parameter can be useful if you enabled `hide_version` in grafana.ini
+ - This parameter can be useful if you enabled C(hide_version) in grafana.ini
required: False
type: bool
- default: False
+ default: false
version_added: "1.2.0"
extends_documentation_fragment:
- community.grafana.basic_auth
- community.grafana.api_key
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = """
---
- name: Create a folder
community.grafana.grafana_folder:
@@ -72,9 +87,9 @@ EXAMPLES = '''
grafana_api_key: "{{ some_api_token_value }}"
title: "grafana_working_group"
state: absent
-'''
+"""
-RETURN = '''
+RETURN = """
---
folder:
description: Information about the Folder
@@ -159,7 +174,7 @@ folder:
type: int
sample:
- 1
-'''
+"""
import json
@@ -177,24 +192,36 @@ class GrafanaError(Exception):
class GrafanaFolderInterface(object):
-
def __init__(self, module):
self._module = module
+ self.grafana_url = base.clean_url(module.params.get("url"))
+ self.org_id = None
# {{{ Authentication header
self.headers = {"Content-Type": "application/json"}
- if module.params.get('grafana_api_key', None):
- self.headers["Authorization"] = "Bearer %s" % module.params['grafana_api_key']
+ if module.params.get("grafana_api_key", None):
+ self.headers["Authorization"] = (
+ "Bearer %s" % module.params["grafana_api_key"]
+ )
else:
- self.headers["Authorization"] = basic_auth_header(module.params['url_username'], module.params['url_password'])
+ self.headers["Authorization"] = basic_auth_header(
+ module.params["url_username"], module.params["url_password"]
+ )
+ self.org_id = (
+ self.organization_by_name(module.params["org_name"])
+ if module.params["org_name"]
+ else module.params["org_id"]
+ )
+ self.switch_organization(self.org_id)
# }}}
- self.grafana_url = base.clean_url(module.params.get("url"))
if module.params.get("skip_version_check") is False:
try:
grafana_version = self.get_version()
except GrafanaError as e:
self._module.fail_json(failed=True, msg=to_text(e))
if grafana_version["major"] < 5:
- self._module.fail_json(failed=True, msg="Folders API is available starting Grafana v5")
+ self._module.fail_json(
+ failed=True, msg="Folders API is available starting Grafana v5"
+ )
def _send_request(self, url, data=None, headers=None, method="GET"):
if data is not None:
@@ -203,24 +230,51 @@ class GrafanaFolderInterface(object):
headers = []
full_url = "{grafana_url}{path}".format(grafana_url=self.grafana_url, path=url)
- resp, info = fetch_url(self._module, full_url, data=data, headers=headers, method=method)
+ resp, info = fetch_url(
+ self._module, full_url, data=data, headers=headers, method=method
+ )
status_code = info["status"]
if status_code == 404:
return None
elif status_code == 401:
- self._module.fail_json(failed=True, msg="Unauthorized to perform action '%s' on '%s'" % (method, full_url))
+ self._module.fail_json(
+ failed=True,
+ msg="Unauthorized to perform action '%s' on '%s'" % (method, full_url),
+ )
elif status_code == 403:
self._module.fail_json(failed=True, msg="Permission Denied")
elif status_code == 412:
- error_msg = resp.read()['message']
+ error_msg = resp.read()["message"]
self._module.fail_json(failed=True, msg=error_msg)
elif status_code == 200:
- return self._module.from_json(resp.read())
- self._module.fail_json(failed=True, msg="Grafana Folders API answered with HTTP %d" % status_code)
+ # XXX: Grafana folders endpoint stopped sending back json in response for delete operations
+ # see https://github.com/grafana/grafana/issues/77673
+ response = resp.read() or "{}"
+ return self._module.from_json(response)
+ self._module.fail_json(
+ failed=True, msg="Grafana Folders API answered with HTTP %d" % status_code
+ )
+
+ def switch_organization(self, org_id):
+ url = "/api/user/using/%d" % org_id
+ self._send_request(url, headers=self.headers, method="POST")
+
+ def organization_by_name(self, org_name):
+ url = "/api/user/orgs"
+ organizations = self._send_request(url, headers=self.headers, method="GET")
+ orga = next((org for org in organizations if org["name"] == org_name))
+ if orga:
+ return orga["orgId"]
+
+ self._module.fail_json(
+ failed=True, msg="Current user isn't member of organization: %s" % org_name
+ )
def get_version(self):
url = "/api/health"
- response = self._send_request(url, data=None, headers=self.headers, method="GET")
+ response = self._send_request(
+ url, data=None, headers=self.headers, method="GET"
+ )
version = response.get("version")
if version is not None:
major, minor, rev = version.split(".")
@@ -230,7 +284,9 @@ class GrafanaFolderInterface(object):
def create_folder(self, title):
url = "/api/folders"
folder = dict(title=title)
- response = self._send_request(url, data=folder, headers=self.headers, method="POST")
+ response = self._send_request(
+ url, data=folder, headers=self.headers, method="POST"
+ )
return response
def get_folder(self, title):
@@ -247,34 +303,33 @@ class GrafanaFolderInterface(object):
return response
-def setup_module_object():
+def main():
+ argument_spec = base.grafana_argument_spec()
+ argument_spec.update(
+ name=dict(type="str", aliases=["title"], required=True),
+ state=dict(type="str", default="present", choices=["present", "absent"]),
+ skip_version_check=dict(type="bool", default=False),
+ org_id=dict(default=1, type="int"),
+ org_name=dict(type="str"),
+ )
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=False,
- required_together=base.grafana_required_together(),
- mutually_exclusive=base.grafana_mutually_exclusive(),
+ required_together=base.grafana_required_together()
+ + [["url_username", "url_password", "org_id"]],
+ mutually_exclusive=base.grafana_mutually_exclusive()
+ + [
+ ["org_id", "org_name"],
+ ],
)
- return module
-
-
-argument_spec = base.grafana_argument_spec()
-argument_spec.update(
- name=dict(type='str', aliases=['title'], required=True),
- state=dict(type='str', default='present', choices=['present', 'absent']),
- skip_version_check=dict(type='bool', default=False),
-)
-
-
-def main():
-
- module = setup_module_object()
- state = module.params['state']
- title = module.params['name']
+ state = module.params["state"]
+ title = module.params["name"]
+ module.params["url"] = base.clean_url(module.params["url"])
grafana_iface = GrafanaFolderInterface(module)
changed = False
- if state == 'present':
+ if state == "present":
folder = grafana_iface.get_folder(title)
if folder is None:
grafana_iface.create_folder(title)
@@ -282,7 +337,7 @@ def main():
changed = True
folder = grafana_iface.get_folder(title)
module.exit_json(changed=changed, folder=folder)
- elif state == 'absent':
+ elif state == "absent":
folder = grafana_iface.get_folder(title)
if folder is None:
module.exit_json(changed=False, message="No folder found")
@@ -290,5 +345,5 @@ def main():
module.exit_json(changed=True, message=result)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/grafana/plugins/modules/grafana_notification_channel.py b/ansible_collections/community/grafana/plugins/modules/grafana_notification_channel.py
index eb808fa1b..30b5b1124 100644
--- a/ansible_collections/community/grafana/plugins/modules/grafana_notification_channel.py
+++ b/ansible_collections/community/grafana/plugins/modules/grafana_notification_channel.py
@@ -16,9 +16,10 @@
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
-DOCUMENTATION = '''
+DOCUMENTATION = """
---
module: grafana_notification_channel
notes:
@@ -82,17 +83,17 @@ options:
- Required when I(state) is C(present).
is_default:
type: bool
- default: 'no'
+ default: false
description:
- Use this channel for all alerts.
include_image:
type: bool
- default: 'no'
+ default: false
description:
- Capture a visualization image and attach it to notifications.
disable_resolve_message:
type: bool
- default: 'no'
+ default: false
description:
- Disable the resolve message.
reminder_frequency:
@@ -368,10 +369,10 @@ options:
extends_documentation_fragment:
- community.grafana.basic_auth
- community.grafana.api_key
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = """
- name: Create slack notification channel
register: result
grafana_notification_channel:
@@ -391,9 +392,9 @@ EXAMPLES = '''
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password}}"
-'''
+"""
-RETURN = '''
+RETURN = """
notification_channel:
description: Notification channel created or updated by the module.
returned: changed
@@ -416,14 +417,17 @@ notification_channel:
"uid": "slack-oops",
"updated": "2020-11-10T21:10:19.675308112+03:00"
}
-'''
+"""
import json
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.urls import fetch_url
from ansible.module_utils._text import to_text
-from ansible_collections.community.grafana.plugins.module_utils.base import grafana_argument_spec, clean_url
+from ansible_collections.community.grafana.plugins.module_utils.base import (
+ grafana_argument_spec,
+ clean_url,
+)
from ansible.module_utils.urls import basic_auth_header
@@ -432,412 +436,448 @@ class GrafanaAPIException(Exception):
def dingding_channel_payload(data, payload):
- payload['settings']['url'] = data['dingding_url']
- if data.get('dingding_message_type'):
- payload['settings']['msgType'] = {
- 'link': 'link',
- 'action_card': 'actionCard',
- }[data['dingding_message_type']]
+ payload["settings"]["url"] = data["dingding_url"]
+ if data.get("dingding_message_type"):
+ payload["settings"]["msgType"] = {
+ "link": "link",
+ "action_card": "actionCard",
+ }[data["dingding_message_type"]]
def discord_channel_payload(data, payload):
- payload['settings']['url'] = data['discord_url']
- if data.get('discord_message_content'):
- payload['settings']['content'] = data['discord_message_content']
+ payload["settings"]["url"] = data["discord_url"]
+ if data.get("discord_message_content"):
+ payload["settings"]["content"] = data["discord_message_content"]
def email_channel_payload(data, payload):
- payload['settings']['addresses'] = ';'.join(data['email_addresses'])
- if data.get('email_single'):
- payload['settings']['singleEmail'] = data['email_single']
+ payload["settings"]["addresses"] = ";".join(data["email_addresses"])
+ if data.get("email_single"):
+ payload["settings"]["singleEmail"] = data["email_single"]
def hipchat_channel_payload(data, payload):
- payload['settings']['url'] = data['hipchat_url']
- if data.get('hipchat_api_key'):
- payload['settings']['apiKey'] = data['hipchat_api_key']
- if data.get('hipchat_room_id'):
- payload['settings']['roomid'] = data['hipchat_room_id']
+ payload["settings"]["url"] = data["hipchat_url"]
+ if data.get("hipchat_api_key"):
+ payload["settings"]["apiKey"] = data["hipchat_api_key"]
+ if data.get("hipchat_room_id"):
+ payload["settings"]["roomid"] = data["hipchat_room_id"]
def pagerduty_channel_payload(data, payload):
- payload['settings']['integrationKey'] = data['pagerduty_integration_key']
- if data.get('pagerduty_severity'):
- payload['settings']['severity'] = data['pagerduty_severity']
- if data.get('pagerduty_auto_resolve'):
- payload['settings']['autoResolve'] = data['pagerduty_auto_resolve']
- if data.get('pagerduty_message_in_details'):
- payload['settings']['messageInDetails'] = data['pagerduty_message_in_details']
+ payload["settings"]["integrationKey"] = data["pagerduty_integration_key"]
+ if data.get("pagerduty_severity"):
+ payload["settings"]["severity"] = data["pagerduty_severity"]
+ if data.get("pagerduty_auto_resolve"):
+ payload["settings"]["autoResolve"] = data["pagerduty_auto_resolve"]
+ if data.get("pagerduty_message_in_details"):
+ payload["settings"]["messageInDetails"] = data["pagerduty_message_in_details"]
def prometheus_channel_payload(data, payload):
- payload['type'] = 'prometheus-alertmanager'
- payload['settings']['url'] = data['prometheus_url']
- if data.get('prometheus_username'):
- payload['settings']['basicAuthUser'] = data['prometheus_username']
- if data.get('prometheus_password'):
- payload['settings']['basicAuthPassword'] = data['prometheus_password']
+ payload["type"] = "prometheus-alertmanager"
+ payload["settings"]["url"] = data["prometheus_url"]
+ if data.get("prometheus_username"):
+ payload["settings"]["basicAuthUser"] = data["prometheus_username"]
+ if data.get("prometheus_password"):
+ payload["settings"]["basicAuthPassword"] = data["prometheus_password"]
def pushover_channel_payload(data, payload):
- payload['settings']['apiToken'] = data['pushover_api_token']
- payload['settings']['userKey'] = data['pushover_user_key']
- if data.get('pushover_devices'):
- payload['settings']['device'] = ';'.join(data['pushover_devices'])
- if data.get('pushover_priority'):
- payload['settings']['priority'] = {
- 'emergency': '2',
- 'high': '1',
- 'normal': '0',
- 'low': '-1',
- 'lowest': '-2'
- }[data['pushover_priority']]
- if data.get('pushover_retry'):
- payload['settings']['retry'] = str(data['pushover_retry'])
- if data.get('pushover_expire'):
- payload['settings']['expire'] = str(data['pushover_expire'])
- if data.get('pushover_alert_sound'):
- payload['settings']['sound'] = data['pushover_alert_sound']
- if data.get('pushover_ok_sound'):
- payload['settings']['okSound'] = data['pushover_ok_sound']
+ payload["settings"]["apiToken"] = data["pushover_api_token"]
+ payload["settings"]["userKey"] = data["pushover_user_key"]
+ if data.get("pushover_devices"):
+ payload["settings"]["device"] = ";".join(data["pushover_devices"])
+ if data.get("pushover_priority"):
+ payload["settings"]["priority"] = {
+ "emergency": "2",
+ "high": "1",
+ "normal": "0",
+ "low": "-1",
+ "lowest": "-2",
+ }[data["pushover_priority"]]
+ if data.get("pushover_retry"):
+ payload["settings"]["retry"] = str(data["pushover_retry"])
+ if data.get("pushover_expire"):
+ payload["settings"]["expire"] = str(data["pushover_expire"])
+ if data.get("pushover_alert_sound"):
+ payload["settings"]["sound"] = data["pushover_alert_sound"]
+ if data.get("pushover_ok_sound"):
+ payload["settings"]["okSound"] = data["pushover_ok_sound"]
def sensu_channel_payload(data, payload):
- payload['settings']['url'] = data['sensu_url']
- if data.get('sensu_source'):
- payload['settings']['source'] = data['sensu_source']
- if data.get('sensu_handler'):
- payload['settings']['handler'] = data['sensu_handler']
- if data.get('sensu_username'):
- payload['settings']['username'] = data['sensu_username']
- if data.get('sensu_password'):
- payload['settings']['password'] = data['sensu_password']
+ payload["settings"]["url"] = data["sensu_url"]
+ if data.get("sensu_source"):
+ payload["settings"]["source"] = data["sensu_source"]
+ if data.get("sensu_handler"):
+ payload["settings"]["handler"] = data["sensu_handler"]
+ if data.get("sensu_username"):
+ payload["settings"]["username"] = data["sensu_username"]
+ if data.get("sensu_password"):
+ payload["settings"]["password"] = data["sensu_password"]
def slack_channel_payload(data, payload):
- payload['settings']['url'] = data['slack_url']
- if data.get('slack_recipient'):
- payload['settings']['recipient'] = data['slack_recipient']
- if data.get('slack_username'):
- payload['settings']['username'] = data['slack_username']
- if data.get('slack_icon_emoji'):
- payload['settings']['iconEmoji'] = data['slack_icon_emoji']
- if data.get('slack_icon_url'):
- payload['settings']['iconUrl'] = data['slack_icon_url']
- if data.get('slack_mention_users'):
- payload['settings']['mentionUsers'] = ','.join(data['slack_mention_users'])
- if data.get('slack_mention_groups'):
- payload['settings']['mentionGroups'] = ','.join(data['slack_mention_groups'])
- if data.get('slack_mention_channel'):
- payload['settings']['mentionChannel'] = data['slack_mention_channel']
- if data.get('slack_token'):
- payload['settings']['token'] = data['slack_token']
+ payload["settings"]["url"] = data["slack_url"]
+ if data.get("slack_recipient"):
+ payload["settings"]["recipient"] = data["slack_recipient"]
+ if data.get("slack_username"):
+ payload["settings"]["username"] = data["slack_username"]
+ if data.get("slack_icon_emoji"):
+ payload["settings"]["iconEmoji"] = data["slack_icon_emoji"]
+ if data.get("slack_icon_url"):
+ payload["settings"]["iconUrl"] = data["slack_icon_url"]
+ if data.get("slack_mention_users"):
+ payload["settings"]["mentionUsers"] = ",".join(data["slack_mention_users"])
+ if data.get("slack_mention_groups"):
+ payload["settings"]["mentionGroups"] = ",".join(data["slack_mention_groups"])
+ if data.get("slack_mention_channel"):
+ payload["settings"]["mentionChannel"] = data["slack_mention_channel"]
+ if data.get("slack_token"):
+ payload["settings"]["token"] = data["slack_token"]
def webhook_channel_payload(data, payload):
- payload['settings']['url'] = data['webhook_url']
- if data.get('webhook_http_method'):
- payload['settings']['httpMethod'] = data['webhook_http_method']
- if data.get('webhook_username'):
- payload['settings']['username'] = data['webhook_username']
- if data.get('webhook_password'):
- payload['settings']['password'] = data['webhook_password']
+ payload["settings"]["url"] = data["webhook_url"]
+ if data.get("webhook_http_method"):
+ payload["settings"]["httpMethod"] = data["webhook_http_method"]
+ if data.get("webhook_username"):
+ payload["settings"]["username"] = data["webhook_username"]
+ if data.get("webhook_password"):
+ payload["settings"]["password"] = data["webhook_password"]
def grafana_notification_channel_payload(data):
payload = {
- 'uid': data['uid'],
- 'name': data['name'],
- 'type': data['type'],
- 'isDefault': data['is_default'],
- 'disableResolveMessage': data['disable_resolve_message'],
- 'settings': {
- 'uploadImage': data['include_image']
- }
+ "uid": data["uid"],
+ "name": data["name"],
+ "type": data["type"],
+ "isDefault": data["is_default"],
+ "disableResolveMessage": data["disable_resolve_message"],
+ "settings": {"uploadImage": data["include_image"]},
}
- if data.get('reminder_frequency'):
- payload['sendReminder'] = True
- payload['frequency'] = data['reminder_frequency']
+ if data.get("reminder_frequency"):
+ payload["sendReminder"] = True
+ payload["frequency"] = data["reminder_frequency"]
- if data['type'] == 'dingding':
+ if data["type"] == "dingding":
dingding_channel_payload(data, payload)
- elif data['type'] == 'discord':
+ elif data["type"] == "discord":
discord_channel_payload(data, payload)
- elif data['type'] == 'email':
+ elif data["type"] == "email":
email_channel_payload(data, payload)
- elif data['type'] == 'googlechat':
- payload['settings']['url'] = data['googlechat_url']
- elif data['type'] == 'hipchat':
+ elif data["type"] == "googlechat":
+ payload["settings"]["url"] = data["googlechat_url"]
+ elif data["type"] == "hipchat":
hipchat_channel_payload(data, payload)
- elif data['type'] == 'kafka':
- payload['settings']['kafkaRestProxy'] = data['kafka_url']
- payload['settings']['kafkaTopic'] = data['kafka_topic']
- elif data['type'] == 'line':
- payload['settings']['token'] = data['line_token']
- elif data['type'] == 'teams':
- payload['settings']['url'] = data['teams_url']
- elif data['type'] == 'opsgenie':
- payload['settings']['apiUrl'] = data['opsgenie_url']
- payload['settings']['apiKey'] = data['opsgenie_api_key']
- elif data['type'] == 'pagerduty':
+ elif data["type"] == "kafka":
+ payload["settings"]["kafkaRestProxy"] = data["kafka_url"]
+ payload["settings"]["kafkaTopic"] = data["kafka_topic"]
+ elif data["type"] == "line":
+ payload["settings"]["token"] = data["line_token"]
+ elif data["type"] == "teams":
+ payload["settings"]["url"] = data["teams_url"]
+ elif data["type"] == "opsgenie":
+ payload["settings"]["apiUrl"] = data["opsgenie_url"]
+ payload["settings"]["apiKey"] = data["opsgenie_api_key"]
+ elif data["type"] == "pagerduty":
pagerduty_channel_payload(data, payload)
- elif data['type'] == 'prometheus':
+ elif data["type"] == "prometheus":
prometheus_channel_payload(data, payload)
- elif data['type'] == 'pushover':
+ elif data["type"] == "pushover":
pushover_channel_payload(data, payload)
- elif data['type'] == 'sensu':
+ elif data["type"] == "sensu":
sensu_channel_payload(data, payload)
- elif data['type'] == 'slack':
+ elif data["type"] == "slack":
slack_channel_payload(data, payload)
- elif data['type'] == 'telegram':
- payload['settings']['bottoken'] = data['telegram_bot_token']
- payload['settings']['chatid'] = data['telegram_chat_id']
- elif data['type'] == 'threema':
- payload['settings']['gateway_id'] = data['threema_gateway_id']
- payload['settings']['recipient_id'] = data['threema_recipient_id']
- payload['settings']['api_secret'] = data['threema_api_secret']
- elif data['type'] == 'victorops':
- payload['settings']['url'] = data['victorops_url']
- if data.get('victorops_auto_resolve'):
- payload['settings']['autoResolve'] = data['victorops_auto_resolve']
- elif data['type'] == 'webhook':
+ elif data["type"] == "telegram":
+ payload["settings"]["bottoken"] = data["telegram_bot_token"]
+ payload["settings"]["chatid"] = data["telegram_chat_id"]
+ elif data["type"] == "threema":
+ payload["settings"]["gateway_id"] = data["threema_gateway_id"]
+ payload["settings"]["recipient_id"] = data["threema_recipient_id"]
+ payload["settings"]["api_secret"] = data["threema_api_secret"]
+ elif data["type"] == "victorops":
+ payload["settings"]["url"] = data["victorops_url"]
+ if data.get("victorops_auto_resolve"):
+ payload["settings"]["autoResolve"] = data["victorops_auto_resolve"]
+ elif data["type"] == "webhook":
webhook_channel_payload(data, payload)
return payload
class GrafanaNotificationChannelInterface(object):
-
def __init__(self, module):
self._module = module
# {{{ Authentication header
self.headers = {"Content-Type": "application/json"}
- if module.params.get('grafana_api_key', None):
- self.headers["Authorization"] = "Bearer %s" % module.params['grafana_api_key']
+ if module.params.get("grafana_api_key", None):
+ self.headers["Authorization"] = (
+ "Bearer %s" % module.params["grafana_api_key"]
+ )
else:
- self.headers["Authorization"] = basic_auth_header(module.params['url_username'], module.params['url_password'])
+ self.headers["Authorization"] = basic_auth_header(
+ module.params["url_username"], module.params["url_password"]
+ )
# }}}
self.grafana_url = clean_url(module.params.get("url"))
def grafana_switch_organisation(self, grafana_url, org_id):
- r, info = fetch_url(self._module, '%s/api/user/using/%s' % (grafana_url, org_id),
- headers=self.headers, method='POST')
- if info['status'] != 200:
- raise GrafanaAPIException('Unable to switch to organization %s : %s' %
- (org_id, info))
+ r, info = fetch_url(
+ self._module,
+ "%s/api/user/using/%s" % (grafana_url, org_id),
+ headers=self.headers,
+ method="POST",
+ )
+ if info["status"] != 200:
+ raise GrafanaAPIException(
+ "Unable to switch to organization %s : %s" % (org_id, info)
+ )
def grafana_create_notification_channel(self, data, payload):
- r, info = fetch_url(self._module, '%s/api/alert-notifications' % data['url'],
- data=json.dumps(payload), headers=self.headers, method='POST')
- if info['status'] == 200:
+ r, info = fetch_url(
+ self._module,
+ "%s/api/alert-notifications" % data["url"],
+ data=json.dumps(payload),
+ headers=self.headers,
+ method="POST",
+ )
+ if info["status"] == 200:
return {
- 'state': 'present',
- 'changed': True,
- 'channel': json.loads(to_text(r.read())),
+ "state": "present",
+ "changed": True,
+ "channel": json.loads(to_text(r.read())),
}
else:
- raise GrafanaAPIException("Unable to create notification channel: %s" % info)
+ raise GrafanaAPIException(
+ "Unable to create notification channel: %s" % info
+ )
def grafana_update_notification_channel(self, data, payload, before):
- r, info = fetch_url(self._module, '%s/api/alert-notifications/uid/%s' %
- (data['url'], data['uid']),
- data=json.dumps(payload), headers=self.headers, method='PUT')
- if info['status'] == 200:
- del before['created']
- del before['updated']
+ r, info = fetch_url(
+ self._module,
+ "%s/api/alert-notifications/uid/%s" % (data["url"], data["uid"]),
+ data=json.dumps(payload),
+ headers=self.headers,
+ method="PUT",
+ )
+ if info["status"] == 200:
+ del before["created"]
+ del before["updated"]
channel = json.loads(to_text(r.read()))
after = channel.copy()
- del after['created']
- del after['updated']
+ del after["created"]
+ del after["updated"]
if before == after:
return {
- 'changed': False,
- 'channel': channel,
+ "changed": False,
+ "channel": channel,
}
else:
return {
- 'changed': True,
- 'diff': {
- 'before': before,
- 'after': after,
+ "changed": True,
+ "diff": {
+ "before": before,
+ "after": after,
},
- 'channel': channel,
+ "channel": channel,
}
else:
- raise GrafanaAPIException("Unable to update notification channel %s : %s" %
- (data['uid'], info))
+ raise GrafanaAPIException(
+ "Unable to update notification channel %s : %s" % (data["uid"], info)
+ )
def grafana_create_or_update_notification_channel(self, data):
payload = grafana_notification_channel_payload(data)
- r, info = fetch_url(self._module, '%s/api/alert-notifications/uid/%s' %
- (data['url'], data['uid']), headers=self.headers)
- if info['status'] == 200:
+ r, info = fetch_url(
+ self._module,
+ "%s/api/alert-notifications/uid/%s" % (data["url"], data["uid"]),
+ headers=self.headers,
+ )
+ if info["status"] == 200:
before = json.loads(to_text(r.read()))
return self.grafana_update_notification_channel(data, payload, before)
- elif info['status'] == 404:
+ elif info["status"] == 404:
return self.grafana_create_notification_channel(data, payload)
else:
- raise GrafanaAPIException("Unable to get notification channel %s : %s" %
- (data['uid'], info))
+ raise GrafanaAPIException(
+ "Unable to get notification channel %s : %s" % (data["uid"], info)
+ )
def grafana_delete_notification_channel(self, data):
- r, info = fetch_url(self._module, '%s/api/alert-notifications/uid/%s' %
- (data['url'], data['uid']),
- headers=self.headers, method='DELETE')
- if info['status'] == 200:
- return {
- 'state': 'absent',
- 'changed': True
- }
- elif info['status'] == 404:
- return {
- 'changed': False
- }
+ r, info = fetch_url(
+ self._module,
+ "%s/api/alert-notifications/uid/%s" % (data["url"], data["uid"]),
+ headers=self.headers,
+ method="DELETE",
+ )
+ if info["status"] == 200:
+ return {"state": "absent", "changed": True}
+ elif info["status"] == 404:
+ return {"changed": False}
else:
- raise GrafanaAPIException("Unable to delete notification channel %s : %s" %
- (data['uid'], info))
+ raise GrafanaAPIException(
+ "Unable to delete notification channel %s : %s" % (data["uid"], info)
+ )
def main():
argument_spec = grafana_argument_spec()
argument_spec.update(
- org_id=dict(type='int', default=1),
- uid=dict(type='str'),
- name=dict(type='str'),
- type=dict(type='str',
- choices=['dingding', 'discord', 'email', 'googlechat', 'hipchat',
- 'kafka', 'line', 'teams', 'opsgenie', 'pagerduty',
- 'prometheus', 'pushover', 'sensu', 'slack', 'telegram',
- 'threema', 'victorops', 'webhook']),
- is_default=dict(type='bool', default=False),
- include_image=dict(type='bool', default=False),
- disable_resolve_message=dict(type='bool', default=False),
- reminder_frequency=dict(type='str'),
-
- dingding_url=dict(type='str'),
- dingding_message_type=dict(type='list', elements='str',
- choices=['link', 'action_card']),
-
- discord_url=dict(type='str'),
- discord_message_content=dict(type='str'),
-
- email_addresses=dict(type='list', elements='str'),
- email_single=dict(type='bool'),
-
- googlechat_url=dict(type='str'),
-
- hipchat_url=dict(type='str'),
- hipchat_api_key=dict(type='str', no_log=True),
- hipchat_room_id=dict(type='str'),
-
- kafka_url=dict(type='str'),
- kafka_topic=dict(type='str'),
-
- line_token=dict(type='str', no_log=True),
-
- teams_url=dict(type='str'),
-
- opsgenie_url=dict(type='str'),
- opsgenie_api_key=dict(type='str', no_log=True),
- opsgenie_auto_close=dict(type='bool'),
- opsgenie_override_priority=dict(type='bool'),
-
- pagerduty_integration_key=dict(type='str', no_log=True),
- pagerduty_severity=dict(type='list', elements='str',
- choices=['critical', 'error', 'warning', 'info']),
- pagerduty_auto_resolve=dict(type='bool'),
- pagerduty_message_in_details=dict(type='bool'),
-
- prometheus_url=dict(type='str'),
- prometheus_username=dict(type='str'),
- prometheus_password=dict(type='str', no_log=True),
-
- pushover_api_token=dict(type='str', no_log=True),
- pushover_user_key=dict(type='str', no_log=True),
- pushover_devices=dict(type='list', elements='str'),
- pushover_priority=dict(type='list', elements='str',
- choices=['emergency', 'high', 'normal', 'low', 'lowest']),
- pushover_retry=dict(type='int'), # TODO: only when priority==emergency
- pushover_expire=dict(type='int'), # TODO: only when priority==emergency
- pushover_alert_sound=dict(type='str'), # TODO: add sound choices
- pushover_ok_sound=dict(type='str'), # TODO: add sound choices
-
- sensu_url=dict(type='str'),
- sensu_source=dict(type='str'),
- sensu_handler=dict(type='str'),
- sensu_username=dict(type='str'),
- sensu_password=dict(type='str', no_log=True),
-
- slack_url=dict(type='str', no_log=True),
- slack_recipient=dict(type='str'),
- slack_username=dict(type='str'),
- slack_icon_emoji=dict(type='str'),
- slack_icon_url=dict(type='str'),
- slack_mention_users=dict(type='list', elements='str'),
- slack_mention_groups=dict(type='list', elements='str'),
- slack_mention_channel=dict(type='list', elements='str',
- choices=['here', 'channel']),
- slack_token=dict(type='str', no_log=True),
-
- telegram_bot_token=dict(type='str', no_log=True),
- telegram_chat_id=dict(type='str'),
-
- threema_gateway_id=dict(type='str'),
- threema_recipient_id=dict(type='str'),
- threema_api_secret=dict(type='str', no_log=True),
-
- victorops_url=dict(type='str'),
- victorops_auto_resolve=dict(type='bool'),
-
- webhook_url=dict(type='str'),
- webhook_username=dict(type='str'),
- webhook_password=dict(type='str', no_log=True),
- webhook_http_method=dict(type='list', elements='str', choices=['POST', 'PUT'])
+ org_id=dict(type="int", default=1),
+ uid=dict(type="str"),
+ name=dict(type="str"),
+ type=dict(
+ type="str",
+ choices=[
+ "dingding",
+ "discord",
+ "email",
+ "googlechat",
+ "hipchat",
+ "kafka",
+ "line",
+ "teams",
+ "opsgenie",
+ "pagerduty",
+ "prometheus",
+ "pushover",
+ "sensu",
+ "slack",
+ "telegram",
+ "threema",
+ "victorops",
+ "webhook",
+ ],
+ ),
+ is_default=dict(type="bool", default=False),
+ include_image=dict(type="bool", default=False),
+ disable_resolve_message=dict(type="bool", default=False),
+ reminder_frequency=dict(type="str"),
+ dingding_url=dict(type="str"),
+ dingding_message_type=dict(
+ type="list", elements="str", choices=["link", "action_card"]
+ ),
+ discord_url=dict(type="str"),
+ discord_message_content=dict(type="str"),
+ email_addresses=dict(type="list", elements="str"),
+ email_single=dict(type="bool"),
+ googlechat_url=dict(type="str"),
+ hipchat_url=dict(type="str"),
+ hipchat_api_key=dict(type="str", no_log=True),
+ hipchat_room_id=dict(type="str"),
+ kafka_url=dict(type="str"),
+ kafka_topic=dict(type="str"),
+ line_token=dict(type="str", no_log=True),
+ teams_url=dict(type="str"),
+ opsgenie_url=dict(type="str"),
+ opsgenie_api_key=dict(type="str", no_log=True),
+ opsgenie_auto_close=dict(type="bool"),
+ opsgenie_override_priority=dict(type="bool"),
+ pagerduty_integration_key=dict(type="str", no_log=True),
+ pagerduty_severity=dict(
+ type="list",
+ elements="str",
+ choices=["critical", "error", "warning", "info"],
+ ),
+ pagerduty_auto_resolve=dict(type="bool"),
+ pagerduty_message_in_details=dict(type="bool"),
+ prometheus_url=dict(type="str"),
+ prometheus_username=dict(type="str"),
+ prometheus_password=dict(type="str", no_log=True),
+ pushover_api_token=dict(type="str", no_log=True),
+ pushover_user_key=dict(type="str", no_log=True),
+ pushover_devices=dict(type="list", elements="str"),
+ pushover_priority=dict(
+ type="list",
+ elements="str",
+ choices=["emergency", "high", "normal", "low", "lowest"],
+ ),
+ pushover_retry=dict(type="int"), # TODO: only when priority==emergency
+ pushover_expire=dict(type="int"), # TODO: only when priority==emergency
+ pushover_alert_sound=dict(type="str"), # TODO: add sound choices
+ pushover_ok_sound=dict(type="str"), # TODO: add sound choices
+ sensu_url=dict(type="str"),
+ sensu_source=dict(type="str"),
+ sensu_handler=dict(type="str"),
+ sensu_username=dict(type="str"),
+ sensu_password=dict(type="str", no_log=True),
+ slack_url=dict(type="str", no_log=True),
+ slack_recipient=dict(type="str"),
+ slack_username=dict(type="str"),
+ slack_icon_emoji=dict(type="str"),
+ slack_icon_url=dict(type="str"),
+ slack_mention_users=dict(type="list", elements="str"),
+ slack_mention_groups=dict(type="list", elements="str"),
+ slack_mention_channel=dict(
+ type="list", elements="str", choices=["here", "channel"]
+ ),
+ slack_token=dict(type="str", no_log=True),
+ telegram_bot_token=dict(type="str", no_log=True),
+ telegram_chat_id=dict(type="str"),
+ threema_gateway_id=dict(type="str"),
+ threema_recipient_id=dict(type="str"),
+ threema_api_secret=dict(type="str", no_log=True),
+ victorops_url=dict(type="str"),
+ victorops_auto_resolve=dict(type="bool"),
+ webhook_url=dict(type="str"),
+ webhook_username=dict(type="str"),
+ webhook_password=dict(type="str", no_log=True),
+ webhook_http_method=dict(type="list", elements="str", choices=["POST", "PUT"]),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=False,
- required_together=[['url_username', 'url_password', 'org_id'],
- ['prometheus_username', 'prometheus_password'],
- ['sensu_username', 'sensu_password']],
- mutually_exclusive=[['url_username', 'grafana_api_key']],
+ required_together=[
+ ["url_username", "url_password", "org_id"],
+ ["prometheus_username", "prometheus_password"],
+ ["sensu_username", "sensu_password"],
+ ],
+ mutually_exclusive=[["url_username", "grafana_api_key"]],
required_if=[
- ['state', 'present', ['name', 'type']],
- ['type', 'dingding', ['dingding_url']],
- ['type', 'discord', ['discord_url']],
- ['type', 'email', ['email_addresses']],
- ['type', 'googlechat', ['googlechat_url']],
- ['type', 'hipchat', ['hipchat_url']],
- ['type', 'kafka', ['kafka_url', 'kafka_topic']],
- ['type', 'line', ['line_token']],
- ['type', 'teams', ['teams_url']],
- ['type', 'opsgenie', ['opsgenie_url', 'opsgenie_api_key']],
- ['type', 'pagerduty', ['pagerduty_integration_key']],
- ['type', 'prometheus', ['prometheus_url']],
- ['type', 'pushover', ['pushover_api_token', 'pushover_user_key']],
- ['type', 'sensu', ['sensu_url']],
- ['type', 'slack', ['slack_url']],
- ['type', 'telegram', ['telegram_bot_token', 'telegram_chat_id']],
- ['type', 'threema', ['threema_gateway_id', 'threema_recipient_id',
- 'threema_api_secret']],
- ['type', 'victorops', ['victorops_url']],
- ['type', 'webhook', ['webhook_url']]
- ]
+ ["state", "present", ["name", "type"]],
+ ["type", "dingding", ["dingding_url"]],
+ ["type", "discord", ["discord_url"]],
+ ["type", "email", ["email_addresses"]],
+ ["type", "googlechat", ["googlechat_url"]],
+ ["type", "hipchat", ["hipchat_url"]],
+ ["type", "kafka", ["kafka_url", "kafka_topic"]],
+ ["type", "line", ["line_token"]],
+ ["type", "teams", ["teams_url"]],
+ ["type", "opsgenie", ["opsgenie_url", "opsgenie_api_key"]],
+ ["type", "pagerduty", ["pagerduty_integration_key"]],
+ ["type", "prometheus", ["prometheus_url"]],
+ ["type", "pushover", ["pushover_api_token", "pushover_user_key"]],
+ ["type", "sensu", ["sensu_url"]],
+ ["type", "slack", ["slack_url"]],
+ ["type", "telegram", ["telegram_bot_token", "telegram_chat_id"]],
+ [
+ "type",
+ "threema",
+ ["threema_gateway_id", "threema_recipient_id", "threema_api_secret"],
+ ],
+ ["type", "victorops", ["victorops_url"]],
+ ["type", "webhook", ["webhook_url"]],
+ ],
)
module.params["url"] = clean_url(module.params["url"])
alert_channel_iface = GrafanaNotificationChannelInterface(module)
- if module.params['state'] == 'present':
- result = alert_channel_iface.grafana_create_or_update_notification_channel(module.params)
+ if module.params["state"] == "present":
+ result = alert_channel_iface.grafana_create_or_update_notification_channel(
+ module.params
+ )
module.exit_json(failed=False, **result)
else:
result = alert_channel_iface.grafana_delete_notification_channel(module.params)
module.exit_json(failed=False, **result)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/grafana/plugins/modules/grafana_organization.py b/ansible_collections/community/grafana/plugins/modules/grafana_organization.py
index 7fad4c876..7bddcb3f4 100644
--- a/ansible_collections/community/grafana/plugins/modules/grafana_organization.py
+++ b/ansible_collections/community/grafana/plugins/modules/grafana_organization.py
@@ -19,7 +19,7 @@
from __future__ import absolute_import, division, print_function
-DOCUMENTATION = '''
+DOCUMENTATION = """
---
module: grafana_organization
author:
@@ -43,9 +43,9 @@ options:
choices: ["present", "absent"]
extends_documentation_fragment:
- community.grafana.basic_auth
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = """
---
- name: Create a Grafana organization
community.grafana.grafana_organization:
@@ -62,9 +62,9 @@ EXAMPLES = '''
url_password: changeme
name: orgtest
state: absent
-'''
+"""
-RETURN = '''
+RETURN = """
---
org:
description: Information about the organization
@@ -94,7 +94,7 @@ org:
country: ""
state: ""
zipCode: ""
-'''
+"""
import json
@@ -107,12 +107,13 @@ __metaclass__ = type
class GrafanaOrgInterface(object):
-
def __init__(self, module):
self._module = module
# {{{ Authentication header
self.headers = {"Content-Type": "application/json"}
- self.headers["Authorization"] = basic_auth_header(module.params['url_username'], module.params['url_password'])
+ self.headers["Authorization"] = basic_auth_header(
+ module.params["url_username"], module.params["url_password"]
+ )
# }}}
self.grafana_url = base.clean_url(module.params.get("url"))
@@ -123,20 +124,35 @@ class GrafanaOrgInterface(object):
headers = []
full_url = "{grafana_url}{path}".format(grafana_url=self.grafana_url, path=url)
- resp, info = fetch_url(self._module, full_url, data=data, headers=headers, method=method)
+ resp, info = fetch_url(
+ self._module, full_url, data=data, headers=headers, method=method
+ )
status_code = info["status"]
if status_code == 404:
return None
elif status_code == 401:
- self._module.fail_json(failed=True, msg="Unauthorized to perform action '%s' on '%s' header: %s" % (method, full_url, self.headers))
+ self._module.fail_json(
+ failed=True,
+ msg="Unauthorized to perform action '%s' on '%s' header: %s"
+ % (method, full_url, self.headers),
+ )
elif status_code == 403:
self._module.fail_json(failed=True, msg="Permission Denied")
elif status_code == 200:
return self._module.from_json(resp.read())
if resp is None:
- self._module.fail_json(failed=True, msg="Cannot connect to API Grafana %s" % info['msg'], status=status_code, url=info['url'])
+ self._module.fail_json(
+ failed=True,
+ msg="Cannot connect to API Grafana %s" % info["msg"],
+ status=status_code,
+ url=info["url"],
+ )
else:
- self._module.fail_json(failed=True, msg="Grafana Org API answered with HTTP %d" % status_code, body=self._module.from_json(resp.read()))
+ self._module.fail_json(
+ failed=True,
+ msg="Grafana Org API answered with HTTP %d" % status_code,
+ body=self._module.from_json(resp.read()),
+ )
def get_actual_org(self, name):
# https://grafana.com/docs/grafana/latest/http_api/org/#get-organization-by-name
@@ -160,40 +176,48 @@ def setup_module_object():
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=False,
- required_together=base.grafana_required_together()
+ required_together=base.grafana_required_together(),
)
return module
argument_spec = base.grafana_argument_spec()
argument_spec.update(
- state=dict(choices=['present', 'absent'], default='present'),
- name=dict(type='str', required=True),
+ state=dict(choices=["present", "absent"], default="present"),
+ name=dict(type="str", required=True),
)
-argument_spec.pop('grafana_api_key')
+argument_spec.pop("grafana_api_key")
def main():
module = setup_module_object()
- state = module.params['state']
- name = module.params['name']
+ state = module.params["state"]
+ name = module.params["name"]
grafana_iface = GrafanaOrgInterface(module)
# search org by name
actual_org = grafana_iface.get_actual_org(name)
- if state == 'present':
+ if state == "present":
has_changed = False
if actual_org is None:
# create new org
actual_org = grafana_iface.create_org(name)
has_changed = True
- module.exit_json(changed=has_changed, msg='Organization %s created.' % name, org=actual_org)
+ module.exit_json(
+ changed=has_changed,
+ msg="Organization %s created." % name,
+ org=actual_org,
+ )
else:
- module.exit_json(changed=has_changed, msg='Organization %s already created.' % name, org=actual_org)
+ module.exit_json(
+ changed=has_changed,
+ msg="Organization %s already created." % name,
+ org=actual_org,
+ )
- elif state == 'absent':
+ elif state == "absent":
if actual_org is None:
module.exit_json(msg="No org found, nothing to do")
# delete org
@@ -201,5 +225,5 @@ def main():
module.exit_json(changed=True, msg=result.get("message"))
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/grafana/plugins/modules/grafana_organization_user.py b/ansible_collections/community/grafana/plugins/modules/grafana_organization_user.py
new file mode 100644
index 000000000..11171f38f
--- /dev/null
+++ b/ansible_collections/community/grafana/plugins/modules/grafana_organization_user.py
@@ -0,0 +1,294 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright: (c) 2021
+
+from __future__ import absolute_import, division, print_function
+
+DOCUMENTATION = """
+---
+module: grafana_organization_user
+author:
+ - Aliaksandr Mianzhynski (@amenzhinsky)
+version_added: "1.6.0"
+short_description: Manage Grafana Organization Users.
+description:
+ - Add or remove users or change their roles in Grafana organizations through org API.
+ - The user has to exist before using this module. See U(https://docs.ansible.com/ansible/latest/collections/community/grafana/grafana_user_module.html).
+options:
+ login:
+ type: str
+ required: True
+ description:
+ - Username or email.
+ role:
+ type: str
+ choices:
+ - viewer
+ - editor
+ - admin
+ default: viewer
+ description:
+ - User's role in the organization.
+ state:
+ type: str
+ default: present
+ choices:
+ - present
+ - absent
+ description:
+ - Status of a user's organization membership.
+ org_id:
+ type: int
+ default: 1
+ description:
+ - Organization ID.
+ - Mutually exclusive with C(org_name).
+ org_name:
+ type: str
+ description:
+ - Organization name.
+ - Mutually exclusive with C(org_id).
+
+extends_documentation_fragment:
+ - community.grafana.basic_auth
+"""
+
+EXAMPLES = """
+---
+- name: Add user to organization
+ community.grafana.grafana_organization_user:
+ url: "{{ grafana_url }}"
+ url_username: "{{ grafana_username }}"
+ url_password: "{{ grafana_password }}"
+ login: john
+ role: admin
+
+- name: Remove user from organization
+ community.grafana.grafana_organization_user:
+ url: "{{ grafana_url }}"
+ url_username: "{{ grafana_username }}"
+ url_password: "{{ grafana_password }}"
+ login: john
+ state: absent
+"""
+
+RETURN = """
+---
+user:
+ description: Information about the organization user
+ returned: when state present
+ type: complex
+ contains:
+ email:
+ description: The User email address
+ returned: always
+ type: str
+ sample:
+ - "foo.bar@example.com"
+ login:
+ description: The User login
+ returned: always
+ type: str
+ sample:
+ - "batman"
+ name:
+ description: The User name (same as login)
+ returned: always
+ type: str
+ sample:
+ - "batman"
+ orgId:
+ description: The organization id that the team is part of.
+ returned: always
+ type: int
+ sample:
+ - 1
+ role:
+ description: The user role in the organization
+ returned: always
+ type: str
+ choices:
+ - Viewer
+ - Editor
+ - Admin
+ sample:
+ - Viewer
+"""
+
+
+import json
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.urls import fetch_url
+from ansible.module_utils._text import to_text
+from ansible_collections.community.grafana.plugins.module_utils.base import (
+ grafana_argument_spec,
+ clean_url,
+)
+from ansible.module_utils.urls import basic_auth_header
+
+__metaclass__ = type
+
+
+class GrafanaAPIException(Exception):
+ pass
+
+
+class GrafanaOrganizationUserInterface(object):
+ def __init__(self, module):
+ self._module = module
+ # {{{ Authentication header
+ self.headers = {"Content-Type": "application/json"}
+ self.headers["Authorization"] = basic_auth_header(
+ module.params["url_username"], module.params["url_password"]
+ )
+ # }}}
+ self.grafana_url = clean_url(module.params.get("url"))
+
+ def _api_call(self, method, path, payload):
+ data = None
+ if payload:
+ data = json.dumps(payload)
+ return fetch_url(
+ self._module,
+ self.grafana_url + "/api/" + path,
+ headers=self.headers,
+ method=method,
+ data=data,
+ )
+
+ def _organization_by_name(self, org_name):
+ r, info = self._api_call("GET", "orgs/name/%s" % org_name, None)
+ if info["status"] != 200:
+ raise GrafanaAPIException("Unable to retrieve organization: %s" % info)
+ return json.loads(to_text(r.read()))
+
+ def _organization_users(self, org_id):
+ r, info = self._api_call("GET", "orgs/%d/users" % org_id, None)
+ if info["status"] != 200:
+ raise GrafanaAPIException(
+ "Unable to retrieve organization users: %s" % info
+ )
+ return json.loads(to_text(r.read()))
+
+ def _create_organization_user(self, org_id, login, role):
+ return self._api_call(
+ "POST",
+ "orgs/%d/users" % org_id,
+ {
+ "loginOrEmail": login,
+ "role": role,
+ },
+ )
+
+ def _update_organization_user_role(self, org_id, user_id, role):
+ return self._api_call(
+ "PATCH",
+ "orgs/%d/users/%s" % (org_id, user_id),
+ {
+ "role": role,
+ },
+ )
+
+ def _remove_organization_user(self, org_id, user_id):
+ return self._api_call("DELETE", "orgs/%d/users/%s" % (org_id, user_id), None)
+
+ def _organization_user_by_login(self, org_id, login):
+ for user in self._organization_users(org_id):
+ if login in (user["login"], user["email"]):
+ return user
+
+ def create_or_update_user(self, org_id, login, role):
+ r, info = self._create_organization_user(org_id, login, role)
+ if info["status"] == 200:
+ return {
+ "state": "present",
+ "changed": True,
+ "user": self._organization_user_by_login(org_id, login),
+ }
+ if info["status"] == 409: # already member
+ user = self._organization_user_by_login(org_id, login)
+ if not user:
+ raise Exception("[BUG] User not found in organization")
+
+ if user["role"] == role:
+ return {"changed": False}
+
+ r, info = self._update_organization_user_role(org_id, user["userId"], role)
+ if info["status"] == 200:
+ return {
+ "changed": True,
+ "user": self._organization_user_by_login(org_id, login),
+ }
+ else:
+ raise GrafanaAPIException(
+ "Unable to update organization user: %s" % info
+ )
+ else:
+ raise GrafanaAPIException("Unable to add user to organization: %s" % info)
+
+ def remove_user(self, org_id, login):
+ user = self._organization_user_by_login(org_id, login)
+ if not user:
+ return {"changed": False}
+
+ r, info = self._remove_organization_user(org_id, user["userId"])
+ if info["status"] == 200:
+ return {"state": "absent", "changed": True}
+ else:
+ raise GrafanaAPIException("Unable to delete organization user: %s" % info)
+
+
+def main():
+ argument_spec = grafana_argument_spec()
+ argument_spec.pop("grafana_api_key")
+ argument_spec.update(
+ org_id=dict(type="int", default=1),
+ org_name=dict(type="str"),
+ login=dict(type="str", required=True),
+ role=dict(type="str", choices=["viewer", "editor", "admin"], default="viewer"),
+ )
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=False,
+ mutually_exclusive=[
+ ("org_id", "org_name"),
+ ],
+ required_if=[
+ ["state", "present", ["role"]],
+ ],
+ )
+
+ org_id = module.params["org_id"]
+ login = module.params["login"]
+ iface = GrafanaOrganizationUserInterface(module)
+ if module.params["org_name"]:
+ org_name = module.params["org_name"]
+ organization = iface._organization_by_name(org_name)
+ org_id = organization["id"]
+ if module.params["state"] == "present":
+ role = module.params["role"].capitalize()
+ result = iface.create_or_update_user(org_id, login, role)
+ module.exit_json(failed=False, **result)
+ else:
+ result = iface.remove_user(org_id, login)
+ module.exit_json(failed=False, **result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/grafana/plugins/modules/grafana_plugin.py b/ansible_collections/community/grafana/plugins/modules/grafana_plugin.py
index 7fd418760..c510f02ba 100644
--- a/ansible_collections/community/grafana/plugins/modules/grafana_plugin.py
+++ b/ansible_collections/community/grafana/plugins/modules/grafana_plugin.py
@@ -6,7 +6,7 @@
from __future__ import absolute_import, division, print_function
-DOCUMENTATION = '''module: grafana_plugin
+DOCUMENTATION = """module: grafana_plugin
author:
- Thierry Sallé (@seuf)
short_description: Manage Grafana plugins via grafana-cli
@@ -50,26 +50,26 @@ options:
validate_certs:
description:
- Boolean variable to include --insecure while installing pluging
- default: False
+ default: false
type: bool
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = """
---
- name: Install/update Grafana piechart panel plugin
community.grafana.grafana_plugin:
name: grafana-piechart-panel
version: latest
state: present
-'''
+"""
-RETURN = '''
+RETURN = """
---
version:
description: version of the installed/removed/updated plugin.
type: str
returned: always
-'''
+"""
import os
from ansible.module_utils.basic import AnsibleModule
@@ -82,18 +82,18 @@ class GrafanaCliException(Exception):
def parse_version(string):
- name, version = string.split('@')
+ name, version = string.split("@")
return name.strip(), version.strip()
def grafana_cli_bin(params):
- '''
+ """
Get the grafana-cli binary path with global options.
Raise a GrafanaCliException if the grafana-cli is not present or not in PATH
:param params: ansible module params. Used to fill grafana-cli global params.
- '''
- program = 'grafana-cli'
+ """
+ program = "grafana-cli"
grafana_cli = None
def is_exe(fpath):
@@ -112,50 +112,57 @@ def grafana_cli_bin(params):
break
if grafana_cli is None:
- raise GrafanaCliException('grafana-cli binary is not present or not in PATH')
+ raise GrafanaCliException("grafana-cli binary is not present or not in PATH")
else:
- if 'grafana_plugin_url' in params and params['grafana_plugin_url']:
- grafana_cli = '{0} {1} {2}'.format(grafana_cli, '--pluginUrl', params['grafana_plugin_url'])
- if 'grafana_plugins_dir' in params and params['grafana_plugins_dir']:
- grafana_cli = '{0} {1} {2}'.format(grafana_cli, '--pluginsDir', params['grafana_plugins_dir'])
- if 'grafana_repo' in params and params['grafana_repo']:
- grafana_cli = '{0} {1} {2}'.format(grafana_cli, '--repo', params['grafana_repo'])
- if 'validate_certs' in params and params['validate_certs'] is False:
- grafana_cli = '{0} {1}'.format(grafana_cli, '--insecure')
-
- return '{0} {1}'.format(grafana_cli, 'plugins')
+ if "grafana_plugin_url" in params and params["grafana_plugin_url"]:
+ grafana_cli = "{0} {1} {2}".format(
+ grafana_cli, "--pluginUrl", params["grafana_plugin_url"]
+ )
+ if "grafana_plugins_dir" in params and params["grafana_plugins_dir"]:
+ grafana_cli = "{0} {1} {2}".format(
+ grafana_cli, "--pluginsDir", params["grafana_plugins_dir"]
+ )
+ if "grafana_repo" in params and params["grafana_repo"]:
+ grafana_cli = "{0} {1} {2}".format(
+ grafana_cli, "--repo", params["grafana_repo"]
+ )
+ if "validate_certs" in params and params["validate_certs"] is False:
+ grafana_cli = "{0} {1}".format(grafana_cli, "--insecure")
+
+ return "{0} {1}".format(grafana_cli, "plugins")
def get_grafana_plugin_version(module, params):
- '''
+ """
Fetch grafana installed plugin version. Return None if plugin is not installed.
:param module: ansible module object. used to run system commands.
:param params: ansible module params.
- '''
+ """
grafana_cli = grafana_cli_bin(params)
- rc, stdout, stderr = module.run_command('{0} ls'.format(grafana_cli))
+ rc, stdout, stderr = module.run_command("{0} ls".format(grafana_cli))
stdout_lines = stdout.split("\n")
for line in stdout_lines:
- if line.find(' @ ') != -1:
+ if line.find(" @ ") != -1:
line = line.rstrip()
plugin_name, plugin_version = parse_version(line)
- if plugin_name == params['name']:
+ if plugin_name == params["name"]:
return plugin_version
return None
def get_grafana_plugin_version_latest(module, params):
- '''
+ """
Fetch the latest version available from grafana-cli.
Return the newest version number or None not found.
:param module: ansible module object. used to run system commands.
:param params: ansible module params.
- '''
+ """
grafana_cli = grafana_cli_bin(params)
- rc, stdout, stderr = module.run_command('{0} list-versions {1}'.format(grafana_cli,
- params['name']))
+ rc, stdout, stderr = module.run_command(
+ "{0} list-versions {1}".format(grafana_cli, params["name"])
+ )
stdout_lines = stdout.split("\n")
if stdout_lines[0]:
return stdout_lines[0].rstrip()
@@ -163,108 +170,126 @@ def get_grafana_plugin_version_latest(module, params):
def grafana_plugin(module, params):
- '''
+ """
Install update or remove grafana plugin
:param module: ansible module object. used to run system commands.
:param params: ansible module params.
- '''
+ """
grafana_cli = grafana_cli_bin(params)
- if params['state'] == 'present':
+ if params["state"] == "present":
grafana_plugin_version = get_grafana_plugin_version(module, params)
if grafana_plugin_version is not None:
- if 'version' in params and params['version']:
- if params['version'] == grafana_plugin_version:
- return {'msg': 'Grafana plugin already installed',
- 'changed': False,
- 'version': grafana_plugin_version}
+ if "version" in params and params["version"]:
+ if params["version"] == grafana_plugin_version:
+ return {
+ "msg": "Grafana plugin already installed",
+ "changed": False,
+ "version": grafana_plugin_version,
+ }
else:
- if params['version'] == 'latest' or params['version'] is None:
- latest_version = get_grafana_plugin_version_latest(module, params)
+ if params["version"] == "latest" or params["version"] is None:
+ latest_version = get_grafana_plugin_version_latest(
+ module, params
+ )
if latest_version == grafana_plugin_version:
- return {'msg': 'Grafana plugin already installed',
- 'changed': False,
- 'version': grafana_plugin_version}
- cmd = '{0} update {1}'.format(grafana_cli, params['name'])
+ return {
+ "msg": "Grafana plugin already installed",
+ "changed": False,
+ "version": grafana_plugin_version,
+ }
+ cmd = "{0} update {1}".format(grafana_cli, params["name"])
else:
- cmd = '{0} install {1} {2}'.format(grafana_cli, params['name'], params['version'])
+ cmd = "{0} install {1} {2}".format(
+ grafana_cli, params["name"], params["version"]
+ )
else:
- return {'msg': 'Grafana plugin already installed',
- 'changed': False,
- 'version': grafana_plugin_version}
+ return {
+ "msg": "Grafana plugin already installed",
+ "changed": False,
+ "version": grafana_plugin_version,
+ }
else:
- if 'version' in params:
- if params['version'] == 'latest' or params['version'] is None:
- cmd = '{0} install {1}'.format(grafana_cli, params['name'])
+ if "version" in params:
+ if params["version"] == "latest" or params["version"] is None:
+ cmd = "{0} install {1}".format(grafana_cli, params["name"])
else:
- cmd = '{0} install {1} {2}'.format(grafana_cli, params['name'], params['version'])
+ cmd = "{0} install {1} {2}".format(
+ grafana_cli, params["name"], params["version"]
+ )
else:
- cmd = '{0} install {1}'.format(grafana_cli, params['name'])
+ cmd = "{0} install {1}".format(grafana_cli, params["name"])
else:
- cmd = '{0} uninstall {1}'.format(grafana_cli, params['name'])
+ cmd = "{0} uninstall {1}".format(grafana_cli, params["name"])
rc, stdout, stderr = module.run_command(cmd)
if rc == 0:
stdout_lines = stdout.split("\n")
for line in stdout_lines:
- if line.find(params['name']):
- if line.find(' @ ') != -1:
+ if line.find(params["name"]):
+ if line.find(" @ ") != -1:
line = line.rstrip()
plugin_name, plugin_version = parse_version(line)
else:
plugin_version = None
- if params['state'] == 'present':
- return {'msg': 'Grafana plugin {0} installed : {1}'.format(params['name'], cmd),
- 'changed': True,
- 'version': plugin_version}
+ if params["state"] == "present":
+ return {
+ "msg": "Grafana plugin {0} installed : {1}".format(
+ params["name"], cmd
+ ),
+ "changed": True,
+ "version": plugin_version,
+ }
else:
- return {'msg': 'Grafana plugin {0} uninstalled : {1}'.format(params['name'], cmd),
- 'changed': True}
+ return {
+ "msg": "Grafana plugin {0} uninstalled : {1}".format(
+ params["name"], cmd
+ ),
+ "changed": True,
+ }
else:
- if params['state'] == 'absent' and stdout.find("plugin does not exist"):
- return {'msg': 'Grafana plugin {0} already uninstalled : {1}'.format(params['name'], cmd), 'changed': False}
- raise GrafanaCliException("'{0}' execution returned an error : [{1}] {2} {3}".format(cmd, rc, stdout, stderr))
+ if params["state"] == "absent" and stdout.find("plugin does not exist"):
+ return {
+ "msg": "Grafana plugin {0} already uninstalled : {1}".format(
+ params["name"], cmd
+ ),
+ "changed": False,
+ }
+ raise GrafanaCliException(
+ "'{0}' execution returned an error : [{1}] {2} {3}".format(
+ cmd, rc, stdout, stderr
+ )
+ )
def main():
module = AnsibleModule(
argument_spec=dict(
- name=dict(required=True,
- type='str'),
- version=dict(type='str'),
- grafana_plugins_dir=dict(type='str'),
- grafana_repo=dict(type='str'),
- grafana_plugin_url=dict(type='str'),
- validate_certs=dict(type='bool', default=False),
- state=dict(choices=['present', 'absent'],
- default='present')
+ name=dict(required=True, type="str"),
+ version=dict(type="str"),
+ grafana_plugins_dir=dict(type="str"),
+ grafana_repo=dict(type="str"),
+ grafana_plugin_url=dict(type="str"),
+ validate_certs=dict(type="bool", default=False),
+ state=dict(choices=["present", "absent"], default="present"),
),
- supports_check_mode=False
+ supports_check_mode=False,
)
try:
result = grafana_plugin(module, module.params)
except GrafanaCliException as e:
- module.fail_json(
- failed=True,
- msg="{0}".format(e)
- )
+ module.fail_json(failed=True, msg="{0}".format(e))
return
except Exception as e:
- module.fail_json(
- failed=True,
- msg="{0} : {1} ".format(type(e), e)
- )
+ module.fail_json(failed=True, msg="{0} : {1} ".format(type(e), e))
return
- module.exit_json(
- failed=False,
- **result
- )
+ module.exit_json(failed=False, **result)
return
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/grafana/plugins/modules/grafana_team.py b/ansible_collections/community/grafana/plugins/modules/grafana_team.py
index 7f8de8457..76dc70a62 100644
--- a/ansible_collections/community/grafana/plugins/modules/grafana_team.py
+++ b/ansible_collections/community/grafana/plugins/modules/grafana_team.py
@@ -19,7 +19,7 @@
from __future__ import absolute_import, division, print_function
-DOCUMENTATION = '''
+DOCUMENTATION = """
---
module: grafana_team
author:
@@ -59,22 +59,22 @@ options:
description:
- Delete the members not found in the C(members) parameters from the
- list of members found on the Team.
- default: False
+ default: false
type: bool
skip_version_check:
description:
- Skip Grafana version check and try to reach api endpoint anyway.
- - This parameter can be useful if you enabled `hide_version` in grafana.ini
+ - This parameter can be useful if you enabled C(hide_version) in grafana.ini
required: False
type: bool
- default: False
+ default: false
version_added: "1.2.0"
extends_documentation_fragment:
- community.grafana.basic_auth
- community.grafana.api_key
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = """
---
- name: Create a team
community.grafana.grafana_team:
@@ -104,7 +104,7 @@ EXAMPLES = '''
members:
- john.doe@example.com
- jane.doe@example.com
- enforce_members: yes
+ enforce_members: true
state: present
- name: Delete a team
@@ -114,9 +114,9 @@ EXAMPLES = '''
name: "grafana_working_group"
email: "foo.bar@example.com"
state: absent
-'''
+"""
-RETURN = '''
+RETURN = """
---
team:
description: Information about the Team
@@ -165,7 +165,7 @@ team:
type: int
sample:
- 1
-'''
+"""
import json
@@ -183,15 +183,18 @@ class GrafanaError(Exception):
class GrafanaTeamInterface(object):
-
def __init__(self, module):
self._module = module
# {{{ Authentication header
self.headers = {"Content-Type": "application/json"}
- if module.params.get('grafana_api_key', None):
- self.headers["Authorization"] = "Bearer %s" % module.params['grafana_api_key']
+ if module.params.get("grafana_api_key", None):
+ self.headers["Authorization"] = (
+ "Bearer %s" % module.params["grafana_api_key"]
+ )
else:
- self.headers["Authorization"] = basic_auth_header(module.params['url_username'], module.params['url_password'])
+ self.headers["Authorization"] = basic_auth_header(
+ module.params["url_username"], module.params["url_password"]
+ )
# }}}
self.grafana_url = base.clean_url(module.params.get("url"))
if module.params.get("skip_version_check") is False:
@@ -200,7 +203,9 @@ class GrafanaTeamInterface(object):
except GrafanaError as e:
self._module.fail_json(failed=True, msg=to_text(e))
if grafana_version["major"] < 5:
- self._module.fail_json(failed=True, msg="Teams API is available starting Grafana v5")
+ self._module.fail_json(
+ failed=True, msg="Teams API is available starting Grafana v5"
+ )
def _send_request(self, url, data=None, headers=None, method="GET"):
if data is not None:
@@ -209,23 +214,32 @@ class GrafanaTeamInterface(object):
headers = []
full_url = "{grafana_url}{path}".format(grafana_url=self.grafana_url, path=url)
- resp, info = fetch_url(self._module, full_url, data=data, headers=headers, method=method)
+ resp, info = fetch_url(
+ self._module, full_url, data=data, headers=headers, method=method
+ )
status_code = info["status"]
if status_code == 404:
return None
elif status_code == 401:
- self._module.fail_json(failed=True, msg="Unauthorized to perform action '%s' on '%s'" % (method, full_url))
+ self._module.fail_json(
+ failed=True,
+ msg="Unauthorized to perform action '%s' on '%s'" % (method, full_url),
+ )
elif status_code == 403:
self._module.fail_json(failed=True, msg="Permission Denied")
elif status_code == 409:
self._module.fail_json(failed=True, msg="Team name is taken")
elif status_code == 200:
return self._module.from_json(resp.read())
- self._module.fail_json(failed=True, msg="Grafana Teams API answered with HTTP %d" % status_code)
+ self._module.fail_json(
+ failed=True, msg="Grafana Teams API answered with HTTP %d" % status_code
+ )
def get_version(self):
url = "/api/health"
- response = self._send_request(url, data=None, headers=self.headers, method="GET")
+ response = self._send_request(
+ url, data=None, headers=self.headers, method="GET"
+ )
version = response.get("version")
if version is not None:
major, minor, rev = version.split(".")
@@ -235,7 +249,9 @@ class GrafanaTeamInterface(object):
def create_team(self, name, email):
url = "/api/teams"
team = dict(email=email, name=name)
- response = self._send_request(url, data=team, headers=self.headers, method="POST")
+ response = self._send_request(
+ url, data=team, headers=self.headers, method="POST"
+ )
return response
def get_team(self, name):
@@ -251,7 +267,9 @@ class GrafanaTeamInterface(object):
def update_team(self, team_id, name, email):
url = "/api/teams/{team_id}".format(team_id=team_id)
team = dict(email=email, name=name)
- response = self._send_request(url, data=team, headers=self.headers, method="PUT")
+ response = self._send_request(
+ url, data=team, headers=self.headers, method="PUT"
+ )
return response
def delete_team(self, team_id):
@@ -272,7 +290,9 @@ class GrafanaTeamInterface(object):
def delete_team_member(self, team_id, email):
user_id = self.get_user_id_from_mail(email)
- url = "/api/teams/{team_id}/members/{user_id}".format(team_id=team_id, user_id=user_id)
+ url = "/api/teams/{team_id}/members/{user_id}".format(
+ team_id=team_id, user_id=user_id
+ )
self._send_request(url, headers=self.headers, method="DELETE")
def get_user_id_from_mail(self, email):
@@ -295,27 +315,26 @@ def setup_module_object():
argument_spec = base.grafana_argument_spec()
argument_spec.update(
- name=dict(type='str', required=True),
- email=dict(type='str', required=True),
- members=dict(type='list', elements='str', required=False),
- enforce_members=dict(type='bool', default=False),
- skip_version_check=dict(type='bool', default=False),
+ name=dict(type="str", required=True),
+ email=dict(type="str", required=True),
+ members=dict(type="list", elements="str", required=False),
+ enforce_members=dict(type="bool", default=False),
+ skip_version_check=dict(type="bool", default=False),
)
def main():
-
module = setup_module_object()
- state = module.params['state']
- name = module.params['name']
- email = module.params['email']
- members = module.params['members']
- enforce_members = module.params['enforce_members']
+ state = module.params["state"]
+ name = module.params["name"]
+ email = module.params["email"]
+ members = module.params["members"]
+ enforce_members = module.params["enforce_members"]
grafana_iface = GrafanaTeamInterface(module)
changed = False
- if state == 'present':
+ if state == "present":
team = grafana_iface.get_team(name)
if team is None:
grafana_iface.create_team(name, email)
@@ -332,9 +351,9 @@ def main():
grafana_iface.delete_team_member(team.get("id"), member)
changed = True
team = grafana_iface.get_team(name)
- team['members'] = grafana_iface.get_team_members(team.get("id"))
+ team["members"] = grafana_iface.get_team_members(team.get("id"))
module.exit_json(failed=False, changed=changed, team=team)
- elif state == 'absent':
+ elif state == "absent":
team = grafana_iface.get_team(name)
if team is None:
module.exit_json(failed=False, changed=False, message="No team found")
@@ -353,5 +372,5 @@ def diff_members(target, current):
return diff
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/grafana/plugins/modules/grafana_user.py b/ansible_collections/community/grafana/plugins/modules/grafana_user.py
index 3247b534a..6e99718ac 100644
--- a/ansible_collections/community/grafana/plugins/modules/grafana_user.py
+++ b/ansible_collections/community/grafana/plugins/modules/grafana_user.py
@@ -19,7 +19,7 @@
from __future__ import absolute_import, division, print_function
-DOCUMENTATION = '''
+DOCUMENTATION = """
---
module: grafana_user
author:
@@ -68,13 +68,13 @@ options:
type: str
choices: ["present", "absent"]
notes:
-- Unlike other modules from the collection, this module does not support `grafana_api_key` authentication type. The Grafana API endpoint for users management
+- Unlike other modules from the collection, this module does not support C(grafana_api_key) authentication type. The Grafana API endpoint for users management
requires basic auth and admin privileges.
extends_documentation_fragment:
- community.grafana.basic_auth
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = """
---
- name: Create or update a Grafana user
community.grafana.grafana_user:
@@ -95,9 +95,9 @@ EXAMPLES = '''
url_password: changeme
login: batman
state: absent
-'''
+"""
-RETURN = '''
+RETURN = """
---
user:
description: Information about the User
@@ -152,7 +152,7 @@ user:
type: bool
sample:
- false
-'''
+"""
import json
@@ -165,12 +165,13 @@ __metaclass__ = type
class GrafanaUserInterface(object):
-
def __init__(self, module):
self._module = module
# {{{ Authentication header
self.headers = {"Content-Type": "application/json"}
- self.headers["Authorization"] = basic_auth_header(module.params['url_username'], module.params['url_password'])
+ self.headers["Authorization"] = basic_auth_header(
+ module.params["url_username"], module.params["url_password"]
+ )
# }}}
self.grafana_url = base.clean_url(module.params.get("url"))
@@ -181,22 +182,34 @@ class GrafanaUserInterface(object):
headers = []
full_url = "{grafana_url}{path}".format(grafana_url=self.grafana_url, path=url)
- resp, info = fetch_url(self._module, full_url, data=data, headers=headers, method=method)
+ resp, info = fetch_url(
+ self._module, full_url, data=data, headers=headers, method=method
+ )
status_code = info["status"]
if status_code == 404:
return None
elif status_code == 401:
- self._module.fail_json(failed=True, msg="Unauthorized to perform action '%s' on '%s' header: %s" % (method, full_url, self.headers))
+ self._module.fail_json(
+ failed=True,
+ msg="Unauthorized to perform action '%s' on '%s' header: %s"
+ % (method, full_url, self.headers),
+ )
elif status_code == 403:
self._module.fail_json(failed=True, msg="Permission Denied")
elif status_code == 200:
return self._module.from_json(resp.read())
- self._module.fail_json(failed=True, msg="Grafana Users API answered with HTTP %d" % status_code, body=self._module.from_json(resp.read()))
+ self._module.fail_json(
+ failed=True,
+ msg="Grafana Users API answered with HTTP %d" % status_code,
+ body=self._module.from_json(resp.read()),
+ )
def create_user(self, name, email, login, password):
# https://grafana.com/docs/http_api/admin/#global-users
if not password:
- self._module.fail_json(failed=True, msg="missing required arguments: password")
+ self._module.fail_json(
+ failed=True, msg="missing required arguments: password"
+ )
url = "/api/admin/users"
user = dict(name=name, email=email, login=login, password=password)
self._send_request(url, data=user, headers=self.headers, method="POST")
@@ -218,7 +231,9 @@ class GrafanaUserInterface(object):
# https://grafana.com/docs/http_api/admin/#permissions
url = "/api/admin/users/{user_id}/permissions".format(user_id=user_id)
permissions = dict(isGrafanaAdmin=is_admin)
- return self._send_request(url, data=permissions, headers=self.headers, method="PUT")
+ return self._send_request(
+ url, data=permissions, headers=self.headers, method="PUT"
+ )
def delete_user(self, user_id):
# https://grafana.com/docs/http_api/admin/#delete-global-user
@@ -232,7 +247,7 @@ def is_user_update_required(target_user, email, name, login, is_admin):
email=target_user.get("email"),
name=target_user.get("name"),
login=target_user.get("login"),
- is_admin=target_user.get("isGrafanaAdmin")
+ is_admin=target_user.get("isGrafanaAdmin"),
)
param_dict = dict(email=email, name=name, login=login, is_admin=is_admin)
return target_user_dict != param_dict
@@ -243,44 +258,46 @@ def setup_module_object():
argument_spec=argument_spec,
supports_check_mode=False,
required_if=[
- ['state', 'present', ['name', 'email']],
+ ["state", "present", ["name", "email"]],
],
- required_together=base.grafana_required_together()
+ required_together=base.grafana_required_together(),
)
return module
argument_spec = base.grafana_argument_spec()
argument_spec.update(
- state=dict(choices=['present', 'absent'], default='present'),
- name=dict(type='str', required=False),
- email=dict(type='str', required=False),
- login=dict(type='str', required=True),
- password=dict(type='str', required=False, no_log=True),
- is_admin=dict(type='bool', default=False),
+ state=dict(choices=["present", "absent"], default="present"),
+ name=dict(type="str", required=False),
+ email=dict(type="str", required=False),
+ login=dict(type="str", required=True),
+ password=dict(type="str", required=False, no_log=True),
+ is_admin=dict(type="bool", default=False),
)
-argument_spec.pop('grafana_api_key')
+argument_spec.pop("grafana_api_key")
def main():
module = setup_module_object()
- state = module.params['state']
- name = module.params['name']
- email = module.params['email']
- login = module.params['login']
- password = module.params['password']
- is_admin = module.params['is_admin']
+ state = module.params["state"]
+ name = module.params["name"]
+ email = module.params["email"]
+ login = module.params["login"]
+ password = module.params["password"]
+ is_admin = module.params["is_admin"]
grafana_iface = GrafanaUserInterface(module)
# search user by login
actual_grafana_user = grafana_iface.get_user_from_login(login)
- if state == 'present':
+ if state == "present":
has_changed = False
if actual_grafana_user is None:
# create new user
- actual_grafana_user = grafana_iface.create_user(name, email, login, password)
+ actual_grafana_user = grafana_iface.create_user(
+ name, email, login, password
+ )
has_changed = True
if is_user_update_required(actual_grafana_user, email, name, login, is_admin):
@@ -288,17 +305,19 @@ def main():
actual_grafana_user_id = actual_grafana_user.get("id")
if is_admin != actual_grafana_user.get("isGrafanaAdmin"):
grafana_iface.update_user_permissions(actual_grafana_user_id, is_admin)
- actual_grafana_user = grafana_iface.update_user(actual_grafana_user_id, email, name, login)
+ actual_grafana_user = grafana_iface.update_user(
+ actual_grafana_user_id, email, name, login
+ )
has_changed = True
module.exit_json(changed=has_changed, user=actual_grafana_user)
- elif state == 'absent':
+ elif state == "absent":
if actual_grafana_user is None:
module.exit_json(message="No user found, nothing to do")
result = grafana_iface.delete_user(actual_grafana_user.get("id"))
module.exit_json(changed=True, message=result.get("message"))
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/grafana/roles/grafana/README.md b/ansible_collections/community/grafana/roles/grafana/README.md
new file mode 100644
index 000000000..f46434edf
--- /dev/null
+++ b/ansible_collections/community/grafana/roles/grafana/README.md
@@ -0,0 +1,190 @@
+# Grafana Role for Ansible Collection Community.Grafana
+
+Configure Grafana organizations, dashboards, folders, datasources, teams and users.
+
+## Role Variables
+
+| Variable | Required | Default |
+| ---------------- | -------- | ------- |
+| grafana_url | yes |
+| grafana_username | yes |
+| grafana_password | yes |
+| [**grafana_users**](https://docs.ansible.com/ansible/latest/collections/community/grafana/grafana_user_module.html) |
+| email | no |
+| is_admin | no |
+| login | yes |
+| name | yes |
+| password | no |
+| state | no |
+| [**grafana_organizations**](https://docs.ansible.com/ansible/latest/collections/community/grafana/grafana_organization_module.html) |
+| name | yes |
+| state | no |
+| [**grafana_teams**](https://docs.ansible.com/ansible/latest/collections/community/grafana/grafana_team_module.html) |
+| email | yes |
+| enforce_members | no |
+| members | no |
+| name | yes |
+| skip_version_check | no |
+| state | no |
+| [**grafana_datasources**](https://docs.ansible.com/ansible/latest/collections/community/grafana/grafana_datasource_module.html) |
+| access | no |
+| additional_json_data | no |
+| additional_secure_json_data | no |
+| aws_access_key | no |
+| aws_assume_role_arn | no |
+| aws_auth_type | no |
+| aws_credentials_profile | no |
+| aws_custom_metrics_namespaces | no |
+| aws_default_region | no |
+| aws_secret_key | no |
+| azure_client | no |
+| azure_cloud | no |
+| azure_secret | no |
+| azure_tenant | no |
+| basic_auth_password | no |
+| basic_auth_user | no |
+| database | no |
+| ds_type | no |
+| ds_url | no |
+| enforce_secure_data | no |
+| es_version | no |
+| interval | no |
+| is_default | no |
+| max_concurrent_shard_requests | no |
+| name | yes |
+| org_id | no |
+| org_name | no |
+| password | no |
+| sslmode | no |
+| state | no |
+| time_field | no |
+| time_interval | no |
+| tls_ca_cert | no |
+| tls_client_cert | no |
+| tls_client_key | no |
+| tls_skip_verify | no |
+| trends | no |
+| tsdb_resolution | no |
+| tsdb_version | no |
+| uid | no |
+| user | no |
+| with_credentials | no |
+| zabbix_password | no |
+| zabbix_user | no |
+| [**grafana_folders**](https://docs.ansible.com/ansible/latest/collections/community/grafana/grafana_folder_module.html) |
+| name | yes |
+| skip_version_check | no |
+| state | no |
+| org_id | no |
+| org_name | no |
+| [**grafana_dashboards**](https://docs.ansible.com/ansible/latest/collections/community/grafana/grafana_dashboard_module.html) |
+| commit_message | no |
+| dashboard_id | no |
+| dashboard_revision | no |
+| folder | no |
+| org_id | no |
+| org_name | no |
+| overwrite | no |
+| path | no |
+| slug | no |
+| state | no |
+| uid | no |
+| [**grafana_organization_users**](https://docs.ansible.com/ansible/latest/collections/community/grafana/grafana_organization_user_module.html) |
+| login | yes |
+| org_id | no |
+| org_name | no |
+| role | no |
+| state | no |
+| [**grafana_notification_channel**](https://docs.ansible.com/ansible/latest/collections/community/grafana/grafana_notification_channel_module.html) |
+| dingding_message_type | no |
+| dingding_url | no |
+| disable_resolve_message | no |
+| discord_message_content | no |
+| discord_url | no |
+| email_addresses | no |
+| email_single | no |
+| googlechat_url | no |
+| hipchat_api_key | no |
+| hipchat_room_id | no |
+| hipchat_url | no |
+| include_image | no |
+| is_default | no |
+| kafka_topic | no |
+| kafka_url | no |
+| line_token | no |
+| name | yes |
+| opsgenie_api_key | no |
+| opsgenie_auto_close | no |
+| opsgenie_override_priority | no |
+| opsgenie_url | no |
+| org_id | no |
+| pagerduty_auto_resolve | no |
+| pagerduty_integration_key | no |
+| pagerduty_message_in_details | no |
+| pagerduty_severity | no |
+| prometheus_password | no |
+| prometheus_url | no |
+| prometheus_username | no |
+| pushover_alert_sound | no |
+| pushover_api_token | no |
+| pushover_devices | no |
+| pushover_expire | no |
+| pushover_ok_sound | no |
+| pushover_priority | no |
+| pushover_retry | no |
+| pushover_user_key | no |
+| reminder_frequency | no |
+| sensu_handler | no |
+| sensu_password | no |
+| sensu_source | no |
+| sensu_url | no |
+| sensu_username | no |
+| slack_icon_emoji | no |
+| slack_icon_url | no |
+| slack_mention_channel | no |
+| slack_mention_groups | no |
+| slack_mention_users | no |
+| slack_recipient | no |
+| slack_token | no |
+| slack_url | no |
+| slack_username | no |
+| state | no |
+| teams_url | no |
+| telegram_bot_token | no |
+| telegram_chat_id | no |
+| threema_api_secret | no |
+| threema_gateway_id | no |
+| threema_recipient_id | no |
+| type | yes |
+| uid | no |
+| victorops_auto_resolve | no |
+| victorops_url | no |
+| webhook_http_method | no |
+| webhook_password | no |
+| webhook_url | no |
+| webhook_username | no |
+
+## Example Playbook
+
+```yaml
+---
+- hosts: localhost
+ gather_facts: false
+
+ vars:
+ grafana_url: "https://monitoring.example.com"
+ grafana_username: "api-user"
+ grafana_password: "******"
+
+ grafana_datasources:
+ - name: "Loki"
+ ds_type: "loki"
+ ds_url: "http://127.0.0.1:3100"
+ tls_skip_verify: yes
+ grafana_folders:
+ - name: my_service
+ - name: other_service
+
+ roles:
+ - role: community.grafana.grafana
+```
diff --git a/ansible_collections/community/grafana/roles/grafana/defaults/main.yml b/ansible_collections/community/grafana/roles/grafana/defaults/main.yml
new file mode 100644
index 000000000..6a84370d3
--- /dev/null
+++ b/ansible_collections/community/grafana/roles/grafana/defaults/main.yml
@@ -0,0 +1,9 @@
+---
+grafana_organizations: []
+grafana_organization_users: []
+grafana_users: []
+grafana_teams: []
+grafana_datasources: []
+grafana_folders: []
+grafana_dashboards: []
+grafana_notification_channels: []
diff --git a/ansible_collections/community/grafana/roles/grafana/meta/main.yml b/ansible_collections/community/grafana/roles/grafana/meta/main.yml
new file mode 100644
index 000000000..47d4af5b7
--- /dev/null
+++ b/ansible_collections/community/grafana/roles/grafana/meta/main.yml
@@ -0,0 +1,14 @@
+---
+galaxy_info:
+ role_name: grafana
+ author: community
+ description: Configure Grafana organizations, dashboards, folders, datasources, teams and users
+ license: GPLv3
+ min_ansible_version: "2.14"
+ galaxy_tags: [grafana, monitoring]
+ platforms:
+ - {name: EL, versions: [all]}
+ - {name: Fedora, versions: [all]}
+ - {name: Amazon, versions: [all]}
+ - {name: Debian, versions: [all]}
+ - {name: Ubuntu, versions: [all]}
diff --git a/ansible_collections/community/grafana/roles/grafana/tasks/main.yml b/ansible_collections/community/grafana/roles/grafana/tasks/main.yml
new file mode 100644
index 000000000..82bbc633d
--- /dev/null
+++ b/ansible_collections/community/grafana/roles/grafana/tasks/main.yml
@@ -0,0 +1,203 @@
+---
+- name: Group tasks for authentication parameters
+ module_defaults:
+ group/community.grafana.grafana:
+ url: "{{ grafana_url }}"
+ url_username: "{{ grafana_username }}"
+ url_password: "{{ grafana_password }}"
+ use_proxy: "{{ grafana_use_proxy | default(omit) }}"
+ validate_certs: "{{ grafana_validate_certs | default(omit) }}"
+ block:
+ - name: Manage organization # noqa: args[module]
+ community.grafana.grafana_organization:
+ name: "{{ organization.name }}"
+ state: "{{ organization.state | default(omit) }}"
+ loop: "{{ grafana_organizations }}"
+ loop_control: {loop_var: organization}
+ tags: organization
+
+ - name: Manage notification channel
+ community.grafana.grafana_notification_channel:
+ dingding_message_type: "{{ notification_channel.dingding_message_type | default(omit) }}"
+ dingding_url: "{{ notification_channel.dingding_url | default(omit) }}"
+ disable_resolve_message: "{{ notification_channel.disable_resolve_message | default(omit) }}"
+ discord_message_content: "{{ notification_channel.discord_message_content | default(omit) }}"
+ discord_url: "{{ notification_channel.discord_url | default(omit) }}"
+ email_addresses: "{{ notification_channel.email_addresses | default(omit) }}"
+ email_single: "{{ notification_channel.email_single | default(omit) }}"
+ googlechat_url: "{{ notification_channel.googlechat_url | default(omit) }}"
+ hipchat_api_key: "{{ notification_channel.hipchat_api_key | default(omit) }}"
+ hipchat_room_id: "{{ notification_channel.hipchat_room_id | default(omit) }}"
+ hipchat_url: "{{ notification_channel.hipchat_url | default(omit) }}"
+ include_image: "{{ notification_channel.include_image | default(omit) }}"
+ is_default: "{{ notification_channel.is_default | default(omit) }}"
+ kafka_topic: "{{ notification_channel.kafka_topic | default(omit) }}"
+ kafka_url: "{{ notification_channel.kafka_url | default(omit) }}"
+ line_token: "{{ notification_channel.line_token | default(omit) }}"
+ name: "{{ notification_channel.name }}"
+ opsgenie_api_key: "{{ notification_channel.opsgenie_api_key | default(omit) }}"
+ opsgenie_auto_close: "{{ notification_channel.opsgenie_auto_close | default(omit) }}"
+ opsgenie_override_priority: "{{ notification_channel.opsgenie_override_priority | default(omit) }}"
+ opsgenie_url: "{{ notification_channel.opsgenie_url | default(omit) }}"
+ org_id: "{{ notification_channel.org_id | default(omit) }}"
+ pagerduty_auto_resolve: "{{ notification_channel.pagerduty_auto_resolve | default(omit) }}"
+ pagerduty_integration_key: "{{ notification_channel.pagerduty_integration_key | default(omit) }}"
+ pagerduty_message_in_details: "{{ notification_channel.pagerduty_message_in_details | default(omit) }}"
+ pagerduty_severity: "{{ notification_channel.pagerduty_severity | default(omit) }}"
+ prometheus_password: "{{ notification_channel.prometheus_password | default(omit) }}"
+ prometheus_url: "{{ notification_channel.prometheus_url | default(omit) }}"
+ prometheus_username: "{{ notification_channel.prometheus_username | default(omit) }}"
+ pushover_alert_sound: "{{ notification_channel.pushover_alert_sound | default(omit) }}"
+ pushover_api_token: "{{ notification_channel.pushover_api_token | default(omit) }}"
+ pushover_devices: "{{ notification_channel.pushover_devices | default(omit) }}"
+ pushover_expire: "{{ notification_channel.pushover_expire | default(omit) }}"
+ pushover_ok_sound: "{{ notification_channel.pushover_ok_sound | default(omit) }}"
+ pushover_priority: "{{ notification_channel.pushover_priority | default(omit) }}"
+ pushover_retry: "{{ notification_channel.pushover_retry | default(omit) }}"
+ pushover_user_key: "{{ notification_channel.pushover_user_key | default(omit) }}"
+ reminder_frequency: "{{ notification_channel.reminder_frequency | default(omit) }}"
+ sensu_handler: "{{ notification_channel.sensu_handler | default(omit) }}"
+ sensu_password: "{{ notification_channel.sensu_password | default(omit) }}"
+ sensu_source: "{{ notification_channel.sensu_source | default(omit) }}"
+ sensu_url: "{{ notification_channel.sensu_url | default(omit) }}"
+ sensu_username: "{{ notification_channel.sensu_username | default(omit) }}"
+ slack_icon_emoji: "{{ notification_channel.slack_icon_emoji | default(omit) }}"
+ slack_icon_url: "{{ notification_channel.slack_icon_url | default(omit) }}"
+ slack_mention_channel: "{{ notification_channel.slack_mention_channel | default(omit) }}"
+ slack_mention_groups: "{{ notification_channel.slack_mention_groups | default(omit) }}"
+ slack_mention_users: "{{ notification_channel.slack_mention_users | default(omit) }}"
+ slack_recipient: "{{ notification_channel.slack_recipient | default(omit) }}"
+ slack_token: "{{ notification_channel.slack_token | default(omit) }}"
+ slack_url: "{{ notification_channel.slack_url | default(omit) }}"
+ slack_username: "{{ notification_channel.slack_username | default(omit) }}"
+ state: "{{ notification_channel.state | default(omit) }}"
+ teams_url: "{{ notification_channel.teams_url | default(omit) }}"
+ telegram_bot_token: "{{ notification_channel.telegram_bot_token | default(omit) }}"
+ telegram_chat_id: "{{ notification_channel.telegram_chat_id | default(omit) }}"
+ threema_api_secret: "{{ notification_channel.threema_api_secret | default(omit) }}"
+ threema_gateway_id: "{{ notification_channel.threema_gateway_id | default(omit) }}"
+ threema_recipient_id: "{{ notification_channel.threema_recipient_id | default(omit) }}"
+ type: "{{ notification_channel.type }}"
+ uid: "{{ notification_channel.uid | default(omit) }}"
+ victorops_auto_resolve: "{{ notification_channel.victorops_auto_resolve | default(omit) }}"
+ victorops_url: "{{ notification_channel.victorops_url | default(omit) }}"
+ webhook_http_method: "{{ notification_channel.webhook_http_method | default(omit) }}"
+ webhook_password: "{{ notification_channel.webhook_password | default(omit) }}"
+ webhook_url: "{{ notification_channel.webhook_url | default(omit) }}"
+ webhook_username: "{{ notification_channel.webhook_username | default(omit) }}"
+ loop: "{{ grafana_notification_channels }}"
+ loop_control: {loop_var: notification_channel}
+ tags: notification_channel
+
+ - name: Manage datasource
+ community.grafana.grafana_datasource:
+ access: "{{ datasource.access | default(omit) }}"
+ additional_json_data: "{{ datasource.additional_json_data | default(omit) }}"
+ additional_secure_json_data: "{{ datasource.additional_secure_json_data | default(omit) }}"
+ aws_access_key: "{{ datasource.aws_access_key | default(omit) }}"
+ aws_assume_role_arn: "{{ datasource.aws_assume_role_arn | default(omit) }}"
+ aws_auth_type: "{{ datasource.aws_auth_type | default(omit) }}"
+ aws_credentials_profile: "{{ datasource.aws_credentials_profile | default(omit) }}"
+ aws_custom_metrics_namespaces: "{{ datasource.aws_custom_metrics_namespaces | default(omit) }}"
+ aws_default_region: "{{ datasource.aws_default_region | default(omit) }}"
+ aws_secret_key: "{{ datasource.aws_secret_key | default(omit) }}"
+ azure_client: "{{ datasource.azure_client | default(omit) }}"
+ azure_cloud: "{{ datasource.azure_cloud | default(omit) }}"
+ azure_secret: "{{ datasource.azure_secret | default(omit) }}"
+ azure_tenant: "{{ datasource.azure_tenant | default(omit) }}"
+ basic_auth_password: "{{ datasource.basic_auth_password | default(omit) }}"
+ basic_auth_user: "{{ datasource.basic_auth_user | default(omit) }}"
+ database: "{{ datasource.database | default(omit) }}"
+ ds_type: "{{ datasource.ds_type | default(omit) }}"
+ ds_url: "{{ datasource.ds_url | default(omit) }}"
+ enforce_secure_data: "{{ datasource.enforce_secure_data | default(omit) }}"
+ es_version: "{{ datasource.es_version | default(omit) }}"
+ interval: "{{ datasource.interval | default(omit) }}"
+ is_default: "{{ datasource.is_default | default(omit) }}"
+ max_concurrent_shard_requests: "{{ datasource.max_concurrent_shard_requests | default(omit) }}"
+ name: "{{ datasource.name }}"
+ org_id: "{{ datasource.org_id | default(omit) }}"
+ org_name: "{{ datasource.org_name | default(omit) }}"
+ password: "{{ datasource.password | default(omit) }}"
+ sslmode: "{{ datasource.sslmode | default(omit) }}"
+ state: "{{ datasource.state | default(omit) }}"
+ time_field: "{{ datasource.time_field | default(omit) }}"
+ time_interval: "{{ datasource.time_interval | default(omit) }}"
+ tls_ca_cert: "{{ datasource.tls_ca_cert | default(omit) }}"
+ tls_client_cert: "{{ datasource.tls_client_cert | default(omit) }}"
+ tls_client_key: "{{ datasource.tls_client_key | default(omit) }}"
+ tls_skip_verify: "{{ datasource.tls_skip_verify | default(omit) }}"
+ trends: "{{ datasource.trends | default(omit) }}"
+ tsdb_resolution: "{{ datasource.tsdb_resolution | default(omit) }}"
+ tsdb_version: "{{ datasource.tsdb_version | default(omit) }}"
+ uid: "{{ datasource.uid | default(omit) }}"
+ user: "{{ datasource.user | default(omit) }}"
+ with_credentials: "{{ datasource.with_credentials | default(omit) }}"
+ zabbix_password: "{{ datasource.zabbix_password | default(omit) }}"
+ zabbix_user: "{{ datasource.zabbix_user | default(omit) }}"
+ loop: "{{ grafana_datasources }}"
+ loop_control: {loop_var: datasource}
+ tags: datasource
+
+ - name: Manage folder # noqa: args[module]
+ community.grafana.grafana_folder:
+ name: "{{ folder.name }}"
+ skip_version_check: "{{ folder.skip_version_check | default(omit) }}"
+ state: "{{ folder.state | default(omit) }}"
+ org_id: "{{ folder.org_id | default(omit) }}"
+ org_name: "{{ folder.org_name | default(omit) }}"
+ loop: "{{ grafana_folders }}"
+ loop_control: {loop_var: folder}
+ tags: folder
+
+ - name: Manage team # noqa: args[module]
+ community.grafana.grafana_team:
+ email: "{{ team.email }}"
+ enforce_members: "{{ team.enforce_members | default(omit) }}"
+ members: "{{ team.members | default(omit) }}"
+ name: "{{ team.name }}"
+ skip_version_check: "{{ team.skip_version_check | default(omit) }}"
+ state: "{{ team.state | default(omit) }}"
+ loop: "{{ grafana_teams }}"
+ loop_control: {loop_var: team}
+ tags: team
+
+ - name: Manage user # noqa: args[module]
+ community.grafana.grafana_user:
+ email: "{{ user.email | default(omit) }}"
+ is_admin: "{{ user.is_admin | default(omit) }}"
+ login: "{{ user.login }}"
+ name: "{{ user.name }}"
+ password: "{{ user.password | default(omit) }}"
+ state: "{{ user.state | default(omit) }}"
+ loop: "{{ grafana_users }}"
+ loop_control: {loop_var: user}
+ tags: user
+
+ - name: Manage organization users
+ community.grafana.grafana_organization_user:
+ login: "{{ organization_user.login }}"
+ org_id: "{{ organization_user.org_id | default(omit) }}"
+ org_name: "{{ organization_user.org_name | default(omit) }}"
+ role: "{{ organization_user.role | default(omit) }}"
+ state: "{{ organization_user.state | default(omit) }}"
+ loop: "{{ grafana_organization_users }}"
+ loop_control: {loop_var: organization_user}
+ tags: organization_user
+
+ - name: Manage dashboard
+ community.grafana.grafana_dashboard:
+ commit_message: "{{ dashboard.commit_message | default(omit) }}"
+ dashboard_id: "{{ dashboard.dashboard_id | default(omit) }}"
+ dashboard_revision: "{{ dashboard.dashboard_revision | default(omit) }}"
+ folder: "{{ dashboard.folder | default(omit) }}"
+ org_id: "{{ dashboard.org_id | default(omit) }}"
+ org_name: "{{ dashboard.org_name | default(omit) }}"
+ overwrite: "{{ dashboard.overwrite | default(omit) }}"
+ path: "{{ dashboard.path | default(omit) }}"
+ slug: "{{ dashboard.slug | default(omit) }}"
+ state: "{{ dashboard.state | default(omit) }}"
+ uid: "{{ dashboard.uid | default(omit) }}"
+ loop: "{{ grafana_dashboards }}"
+ loop_control: {loop_var: dashboard}
+ tags: [dashboard, molecule-idempotence-notest]
diff --git a/ansible_collections/community/grafana/ruff.toml b/ansible_collections/community/grafana/ruff.toml
new file mode 100644
index 000000000..ef486c58f
--- /dev/null
+++ b/ansible_collections/community/grafana/ruff.toml
@@ -0,0 +1 @@
+ignore = ["E402"]
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/defaults/main.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/defaults/main.yml
index 8b9c9348a..3edac8598 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/defaults/main.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/defaults/main.yml
@@ -1,7 +1,4 @@
---
-
-grafana_url: "http://grafana:3000/"
-grafana_username: "admin"
-grafana_password: "admin"
-
-...
+grafana_url: http://grafana:3000/
+grafana_username: admin
+grafana_password: admin
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/runme.sh b/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/runme.sh
new file mode 100755
index 000000000..867afb0d3
--- /dev/null
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/runme.sh
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+
+set -eux
+
+ansible-playbook site.yml
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/site.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/site.yml
new file mode 100644
index 000000000..c32364ef0
--- /dev/null
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/site.yml
@@ -0,0 +1,6 @@
+---
+- name: Run tests for grafana_dashboard
+ hosts: localhost
+ tasks:
+ - ansible.builtin.include_role:
+ name: ../../grafana_dashboard
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/dashboard-by-org-name.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/dashboard-by-org-name.yml
new file mode 100644
index 000000000..a493eb0f8
--- /dev/null
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/dashboard-by-org-name.yml
@@ -0,0 +1,84 @@
+---
+- module_defaults:
+ community.grafana.grafana_dashboard:
+ org_name: Main Org.
+ block:
+ - name: Create Dashboard from file by org_name | check mode | dashboard does not exist
+ community.grafana.grafana_dashboard:
+ grafana_url: "{{ grafana_url }}"
+ grafana_user: "{{ grafana_username }}"
+ grafana_password: "{{ grafana_password }}"
+ state: present
+ commit_message: Updated by ansible
+ path: /tmp/dashboard.json
+ overwrite: true
+ check_mode: true
+ register: dbo_result1
+ - ansible.builtin.assert:
+ that:
+ - dbo_result1.failed == false
+ - dbo_result1.changed == true
+ - dbo_result1.uid is not defined
+ - dbo_result1.msg == 'Dashboard test will be created'
+
+ - name: Create Dashboard from file by org_name | run mode | dashboard does not exist
+ community.grafana.grafana_dashboard:
+ grafana_url: "{{ grafana_url }}"
+ grafana_user: "{{ grafana_username }}"
+ grafana_password: "{{ grafana_password }}"
+ state: present
+ commit_message: Updated by ansible
+ path: /tmp/dashboard.json
+ overwrite: true
+ check_mode: false
+ register: dbo_result2
+ - ansible.builtin.assert:
+ that:
+ - dbo_result2.failed == false
+ - dbo_result2.changed == true
+ - dbo_result2.uid is defined
+ - dbo_result2.uid | type_debug == "AnsibleUnsafeText"
+ - dbo_result2.msg == 'Dashboard test created'
+
+ - name: Create Dashboard from file by org_name | check mode | dashboard exists
+ community.grafana.grafana_dashboard:
+ grafana_url: "{{ grafana_url }}"
+ grafana_user: "{{ grafana_username }}"
+ grafana_password: "{{ grafana_password }}"
+ state: present
+ commit_message: Updated by ansible
+ path: /tmp/dashboard.json
+ overwrite: true
+ check_mode: true
+ register: dbo_result3
+ - ansible.builtin.assert:
+ that:
+ - dbo_result3.failed == false
+ - dbo_result3.changed == false
+ - dbo_result3.uid is defined
+ - dbo_result3.uid | type_debug == "AnsibleUnsafeText"
+ - dbo_result3.msg == 'Dashboard test unchanged.'
+
+ - name: Create Dashboard from file by org_name | run mode | dashboard exists
+ community.grafana.grafana_dashboard:
+ grafana_url: "{{ grafana_url }}"
+ grafana_user: "{{ grafana_username }}"
+ grafana_password: "{{ grafana_password }}"
+ state: present
+ commit_message: Updated by ansible
+ path: /tmp/dashboard.json
+ overwrite: true
+ check_mode: false
+ register: dbo_result4
+ - ansible.builtin.assert:
+ that:
+ - dbo_result4.failed == false
+ - dbo_result4.changed == false
+ - dbo_result4.uid is defined
+ - dbo_result4.uid | type_debug == "AnsibleUnsafeText"
+ - dbo_result4.msg == 'Dashboard test unchanged.'
+
+ - ansible.builtin.include_tasks:
+ file: delete-dashboard.yml
+ vars:
+ uid_to_delete: '{{ dbo_result4.uid }}'
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/dashboard-export.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/dashboard-export.yml
index 04b17f727..bb4f30e10 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/dashboard-export.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/dashboard-export.yml
@@ -1,33 +1,93 @@
---
-- set_fact:
- dashboard_uid: "{{ result.uid }}"
+- name: Export Dashboard | check mode | uid does not exist
+ community.grafana.grafana_dashboard:
+ grafana_url: "{{ grafana_url }}"
+ grafana_user: "{{ grafana_username }}"
+ grafana_password: "{{ grafana_password }}"
+ state: export
+ path: /tmp/dashboard_export.json
+ overwrite: true
+ uid: "090909090"
+ check_mode: true
+ ignore_errors: true
+ register: de_result1
+- ansible.builtin.assert:
+ that:
+ - de_result1.failed == false
+ - de_result1.changed == false
+ - de_result1.uid is defined
+ - de_result1.uid | type_debug == "AnsibleUnsafeText"
+ - de_result1.uid == "090909090"
+ - de_result1.msg == 'Dashboard ' ~ de_result1.uid ~ ' does not exist.'
-- name: Check export grafana dashboard to file
- grafana_dashboard:
+- name: Export Dashboard | run mode | uid does not exist
+ community.grafana.grafana_dashboard:
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
state: export
- path: /tmp/dashboard.json
+ path: /tmp/dashboard_export.json
overwrite: true
- uid: "{{ dashboard_uid }}"
- register: result
+ uid: "090909090"
+ check_mode: false
+ ignore_errors: true
+ register: de_result2
+- ansible.builtin.assert:
+ that:
+ - de_result2.failed == false
+ - de_result2.changed == false
+ - de_result2.uid is defined
+ - de_result2.uid | type_debug == "AnsibleUnsafeText"
+ - de_result2.uid == "090909090"
+ - de_result2.msg == 'Dashboard ' ~ de_result2.uid ~ ' does not exist.'
-- debug:
- var: result
+- name: Export Dashboard | check mode | uid exists
+ community.grafana.grafana_dashboard:
+ grafana_url: "{{ grafana_url }}"
+ grafana_user: "{{ grafana_username }}"
+ grafana_password: "{{ grafana_password }}"
+ state: export
+ path: /tmp/dashboard_export.json
+ overwrite: true
+ uid: "{{ uid_to_export }}"
+ check_mode: true
+ register: de_result3
+- ansible.builtin.assert:
+ that:
+ - de_result3.failed == false
+ - de_result3.changed == true
+ - de_result3.uid is defined
+ - de_result3.uid | type_debug == "AnsibleUnsafeText"
+ - de_result3.uid == uid_to_export
+ - de_result3.msg == 'Dashboard ' ~ de_result3.uid ~ ' will be exported to /tmp/dashboard_export.json'
-- assert:
+- name: Export Dashboard | run mode | uid exists
+ community.grafana.grafana_dashboard:
+ grafana_url: "{{ grafana_url }}"
+ grafana_user: "{{ grafana_username }}"
+ grafana_password: "{{ grafana_password }}"
+ state: export
+ path: /tmp/dashboard_export.json
+ overwrite: true
+ uid: "{{ uid_to_export }}"
+ check_mode: false
+ register: de_result4
+- ansible.builtin.assert:
that:
- - "result.changed == true"
- - "result.msg == 'Dashboard {{ dashboard_uid }} exported to /tmp/dashboard.json'"
+ - de_result4.failed == false
+ - de_result4.changed == true
+ - de_result4.uid is defined
+ - de_result4.uid | type_debug == "AnsibleUnsafeText"
+ - de_result4.uid == uid_to_export
+ - de_result4.msg == 'Dashboard ' ~ de_result4.uid ~ ' exported to /tmp/dashboard_export.json'
-- name: Load /tmp/dashboard.json or fail if missing
- set_fact:
- exported_dashboard_lines: "{{ lookup('file', '/tmp/dashboard.json').splitlines() }}"
+- name: Export Dashboard | Load /tmp/dashboard_export.json or fail if missing
+ ansible.builtin.set_fact:
+ exported_dashboard_lines: "{{ lookup('file', '/tmp/dashboard_export.json').splitlines() }}"
-- name: Assert that exported dashboard contains formatted JSON
- assert:
+- name: Export Dashboard | Assert that exported dashboard contains formatted JSON
+ ansible.builtin.assert:
that:
- - "exported_dashboard_lines | length >= 2"
- - "exported_dashboard_lines[0] == '{'"
- - "exported_dashboard_lines[-1] == '}'"
+ - exported_dashboard_lines | length >= 2
+ - exported_dashboard_lines[0] == '{'
+ - exported_dashboard_lines[-1] == '}'
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/dashboard-folder-destination.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/dashboard-folder-destination.yml
index f4f3d9f4d..4704002f5 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/dashboard-folder-destination.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/dashboard-folder-destination.yml
@@ -1,33 +1,38 @@
---
-- name: copy dashboard file
- copy:
- src: "files/dashboard.json"
- dest: "/tmp/dashboard.json"
-
-- block:
- - name: Check import grafana dashboard from file to unknown folder fails
- grafana_dashboard:
- grafana_url: "{{ grafana_url }}"
- grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password }}"
- state: present
- commit_message: Updated by ansible
- path: /tmp/dashboard.json
- overwrite: true
- folder: inexistent
- register: result
- ignore_errors: true
-
-- debug:
- var: result
-
-- set_fact:
- # XXX: Too many quotes of different types to do inline.
- # I did not manage to find a good way of having it inline.
- expected_error: "error : Dashboard folder 'inexistent' does not exist."
+- name: Create Dashboard from file | check mode | folder does not exist
+ community.grafana.grafana_dashboard:
+ grafana_url: "{{ grafana_url }}"
+ grafana_user: "{{ grafana_username }}"
+ grafana_password: "{{ grafana_password }}"
+ state: present
+ commit_message: Updated by ansible
+ path: /tmp/dashboard.json
+ overwrite: true
+ folder: inexistent
+ check_mode: true
+ register: dfff_result1
+ ignore_errors: true
+- ansible.builtin.assert:
+ that:
+ - dfff_result1.failed == true
+ - dfff_result1.changed == false
+ - "dfff_result1.msg == 'error : Dashboard folder \\'inexistent\\' does not exist.'"
-- assert:
+- name: Create Dashboard from file | run mode | folder does not exist
+ community.grafana.grafana_dashboard:
+ grafana_url: "{{ grafana_url }}"
+ grafana_user: "{{ grafana_username }}"
+ grafana_password: "{{ grafana_password }}"
+ state: present
+ commit_message: Updated by ansible
+ path: /tmp/dashboard.json
+ overwrite: true
+ folder: inexistent
+ check_mode: false
+ register: dfff_result2
+ ignore_errors: true
+- ansible.builtin.assert:
that:
- - "result.changed == false"
- - "result.failed == true"
- - "result.msg == expected_error"
+ - dfff_result2.failed == true
+ - dfff_result2.changed == false
+ - "dfff_result2.msg == 'error : Dashboard folder \\'inexistent\\' does not exist.'"
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/dashboard-from-file-export.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/dashboard-from-file-export.yml
new file mode 100644
index 000000000..3d0019c5d
--- /dev/null
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/dashboard-from-file-export.yml
@@ -0,0 +1,90 @@
+---
+- name: Create Dashboard from file | Copy dashboard file
+ ansible.builtin.copy:
+ src: files/dashboard.json
+ dest: /tmp/dashboard.json
+
+- name: Create Dashboard from file | check mode | dashboard does not exist
+ community.grafana.grafana_dashboard:
+ grafana_url: "{{ grafana_url }}"
+ grafana_user: "{{ grafana_username }}"
+ grafana_password: "{{ grafana_password }}"
+ state: present
+ commit_message: Updated by ansible
+ path: /tmp/dashboard.json
+ overwrite: true
+ check_mode: true
+ register: dff_result1
+- ansible.builtin.assert:
+ that:
+ - dff_result1.failed == false
+ - dff_result1.changed == true
+ - dff_result1.uid is not defined
+ - dff_result1.msg == 'Dashboard test will be created'
+
+- name: Create Dashboard from file | run mode | dashboard does not exist
+ community.grafana.grafana_dashboard:
+ grafana_url: "{{ grafana_url }}"
+ grafana_user: "{{ grafana_username }}"
+ grafana_password: "{{ grafana_password }}"
+ state: present
+ commit_message: Updated by ansible
+ path: /tmp/dashboard.json
+ overwrite: true
+ check_mode: false
+ register: dff_result2
+- ansible.builtin.assert:
+ that:
+ - dff_result2.failed == false
+ - dff_result2.changed == true
+ - dff_result2.uid is defined
+ - dff_result2.uid | type_debug == "AnsibleUnsafeText"
+ - dff_result2.msg == 'Dashboard test created'
+
+- name: Create Dashboard from file | check mode | dashboard exists
+ community.grafana.grafana_dashboard:
+ grafana_url: "{{ grafana_url }}"
+ grafana_user: "{{ grafana_username }}"
+ grafana_password: "{{ grafana_password }}"
+ state: present
+ commit_message: Updated by ansible
+ path: /tmp/dashboard.json
+ overwrite: true
+ check_mode: true
+ register: dff_result3
+- ansible.builtin.assert:
+ that:
+ - dff_result3.failed == false
+ - dff_result3.changed == false
+ - dff_result3.uid is defined
+ - dff_result3.uid | type_debug == "AnsibleUnsafeText"
+ - dff_result3.msg == 'Dashboard test unchanged.'
+
+- name: Create Dashboard from file | run mode | dashboard exists
+ community.grafana.grafana_dashboard:
+ grafana_url: "{{ grafana_url }}"
+ grafana_user: "{{ grafana_username }}"
+ grafana_password: "{{ grafana_password }}"
+ state: present
+ commit_message: Updated by ansible
+ path: /tmp/dashboard.json
+ overwrite: true
+ check_mode: false
+ register: dff_result4
+- ansible.builtin.assert:
+ that:
+ - dff_result4.failed == false
+ - dff_result4.changed == false
+ - dff_result4.uid is defined
+ - dff_result4.uid | type_debug == "AnsibleUnsafeText"
+ - dff_result4.msg == 'Dashboard test unchanged.'
+
+- ansible.builtin.include_tasks:
+ file: dashboard-export.yml
+ vars:
+ uid_to_export: '{{ dff_result4.uid }}'
+
+- ansible.builtin.include_tasks:
+ file: delete-dashboard.yml
+ vars:
+ uid_to_delete: '{{ dff_result4.uid }}'
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/dashboard-from-file.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/dashboard-from-file.yml
deleted file mode 100644
index 93df1666a..000000000
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/dashboard-from-file.yml
+++ /dev/null
@@ -1,44 +0,0 @@
----
-- name: copy dashboard file
- copy:
- src: "files/dashboard.json"
- dest: "/tmp/dashboard.json"
-
-
-- name: Check import grafana dashboard from file
- grafana_dashboard:
- grafana_url: "{{ grafana_url }}"
- grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password }}"
- state: present
- commit_message: Updated by ansible
- path: /tmp/dashboard.json
- overwrite: true
- register: result
-
-- debug:
- var: result
-
-- assert:
- that:
- - "result.changed == true"
- - "result.msg == 'Dashboard test created'"
-
-- name: Check import grafana dashboard from file idempotency
- grafana_dashboard:
- grafana_url: "{{ grafana_url }}"
- grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password }}"
- state: present
- commit_message: Updated by ansible
- path: /tmp/dashboard.json
- overwrite: true
- register: result
-
-- debug:
- var: result
-
-- assert:
- that:
- - "result.changed == false"
- - "result.msg == 'Dashboard test unchanged.'"
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/dashboard-from-id.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/dashboard-from-id.yml
index 3b81ebf71..4de7b4675 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/dashboard-from-id.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/dashboard-from-id.yml
@@ -1,6 +1,6 @@
---
-- name: Check import grafana dashboard from id
- grafana_dashboard:
+- name: Create Dashboard from ID | check mode | dashboard does not exist
+ community.grafana.grafana_dashboard:
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
@@ -9,18 +9,17 @@
dashboard_id: "6098"
dashboard_revision: "1"
overwrite: true
- register: result
-
-- debug:
- var: result
-
-- assert:
+ check_mode: true
+ register: dfi_result1
+- ansible.builtin.assert:
that:
- - "result.changed == true"
- - "result.msg == 'Dashboard Zabbix Host Status created'"
+ - dfi_result1.failed == false
+ - dfi_result1.changed == true
+ - dfi_result1.uid is not defined
+ - dfi_result1.msg == 'Dashboard Zabbix Host Status will be created'
-- name: Check import grafana dashboard from id idempotency
- grafana_dashboard:
+- name: Create Dashboard from ID | run mode | dashboard does not exist
+ community.grafana.grafana_dashboard:
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
@@ -29,12 +28,57 @@
dashboard_id: "6098"
dashboard_revision: "1"
overwrite: true
- register: result
+ check_mode: false
+ register: dfi_result2
+- ansible.builtin.assert:
+ that:
+ - dfi_result2.failed == false
+ - dfi_result2.changed == true
+ - dfi_result2.uid is defined
+ - dfi_result2.uid | type_debug == "AnsibleUnsafeText"
+ - dfi_result2.msg == 'Dashboard Zabbix Host Status created'
-- debug:
- var: result
+- name: Create Dashboard from ID | check mode | dashboard exists
+ community.grafana.grafana_dashboard:
+ grafana_url: "{{ grafana_url }}"
+ grafana_user: "{{ grafana_username }}"
+ grafana_password: "{{ grafana_password }}"
+ state: present
+ commit_message: Updated by ansible
+ dashboard_id: "6098"
+ dashboard_revision: "1"
+ overwrite: true
+ check_mode: true
+ register: dfi_result3
+- ansible.builtin.assert:
+ that:
+ - dfi_result3.failed == false
+ - dfi_result3.changed == false
+ - dfi_result3.uid is defined
+ - dfi_result3.uid | type_debug == "AnsibleUnsafeText"
+ - dfi_result3.msg == 'Dashboard Zabbix Host Status unchanged.'
-- assert:
+- name: Create Dashboard from ID | run mode | dashboard exists
+ community.grafana.grafana_dashboard:
+ grafana_url: "{{ grafana_url }}"
+ grafana_user: "{{ grafana_username }}"
+ grafana_password: "{{ grafana_password }}"
+ state: present
+ commit_message: Updated by ansible
+ dashboard_id: "6098"
+ dashboard_revision: "1"
+ overwrite: true
+ check_mode: false
+ register: dfi_result4
+- ansible.builtin.assert:
that:
- - "result.changed == false"
- - "result.msg == 'Dashboard Zabbix Host Status unchanged.'"
+ - dfi_result4.failed == false
+ - dfi_result4.changed == false
+ - dfi_result4.uid is defined
+ - dfi_result4.uid | type_debug == "AnsibleUnsafeText"
+ - dfi_result4.msg == 'Dashboard Zabbix Host Status unchanged.'
+
+- ansible.builtin.include_tasks:
+ file: delete-dashboard.yml
+ vars:
+ uid_to_delete: '{{ dfi_result4.uid }}'
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/dashboard-from-url.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/dashboard-from-url.yml
index 5146fc9a0..abdeacfd0 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/dashboard-from-url.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/dashboard-from-url.yml
@@ -1,7 +1,6 @@
---
-
-- name: Check import grafana dashboard from url
- grafana_dashboard:
+- name: Create Dashboard from URL | check mode | dashboard does not exist
+ community.grafana.grafana_dashboard:
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
@@ -9,18 +8,17 @@
commit_message: Updated by ansible
dashboard_url: https://grafana.com/api/dashboards/6098/revisions/1/download
overwrite: true
- register: result
-
-- debug:
- var: result
-
-- assert:
+ check_mode: true
+ register: dfu_result1
+- ansible.builtin.assert:
that:
- - "result.changed == true"
- - "result.msg == 'Dashboard Zabbix Host Status created'"
+ - dfu_result1.failed == false
+ - dfu_result1.changed == true
+ - dfu_result1.uid is not defined
+ - dfu_result1.msg == 'Dashboard Zabbix Host Status will be created'
-- name: Check import grafana dashboard from url idempotency
- grafana_dashboard:
+- name: Create Dashboard from URL | run mode | dashboard does not exist
+ community.grafana.grafana_dashboard:
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
@@ -28,12 +26,55 @@
commit_message: Updated by ansible
dashboard_url: https://grafana.com/api/dashboards/6098/revisions/1/download
overwrite: true
- register: result
+ check_mode: false
+ register: dfu_result2
+- ansible.builtin.assert:
+ that:
+ - dfu_result2.failed == false
+ - dfu_result2.changed == true
+ - dfu_result2.uid is defined
+ - dfu_result2.uid | type_debug == "AnsibleUnsafeText"
+ - dfu_result2.msg == 'Dashboard Zabbix Host Status created'
-- debug:
- var: result
+- name: Create Dashboard from URL | check mode | dashboard exists
+ community.grafana.grafana_dashboard:
+ grafana_url: "{{ grafana_url }}"
+ grafana_user: "{{ grafana_username }}"
+ grafana_password: "{{ grafana_password }}"
+ state: present
+ commit_message: Updated by ansible
+ dashboard_url: https://grafana.com/api/dashboards/6098/revisions/1/download
+ overwrite: true
+ check_mode: true
+ register: dfu_result3
+- ansible.builtin.assert:
+ that:
+ - dfu_result3.failed == false
+ - dfu_result3.changed == false
+ - dfu_result3.uid is defined
+ - dfu_result3.uid | type_debug == "AnsibleUnsafeText"
+ - dfu_result3.msg == 'Dashboard Zabbix Host Status unchanged.'
-- assert:
+- name: Create Dashboard from URL | run mode | dashboard exists
+ community.grafana.grafana_dashboard:
+ grafana_url: "{{ grafana_url }}"
+ grafana_user: "{{ grafana_username }}"
+ grafana_password: "{{ grafana_password }}"
+ state: present
+ commit_message: Updated by ansible
+ dashboard_url: https://grafana.com/api/dashboards/6098/revisions/1/download
+ overwrite: true
+ check_mode: false
+ register: dfu_result4
+- ansible.builtin.assert:
that:
- - "result.changed == false"
- - "result.msg == 'Dashboard Zabbix Host Status unchanged.'"
+ - dfu_result4.failed == false
+ - dfu_result4.changed == false
+ - dfu_result4.uid is defined
+ - dfu_result4.uid | type_debug == "AnsibleUnsafeText"
+ - dfu_result4.msg == 'Dashboard Zabbix Host Status unchanged.'
+
+- ansible.builtin.include_tasks:
+ file: delete-dashboard.yml
+ vars:
+ uid_to_delete: '{{ dfu_result4.uid }}' \ No newline at end of file
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/delete-dashboard.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/delete-dashboard.yml
index 2013324fb..b2d27fdc8 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/delete-dashboard.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/delete-dashboard.yml
@@ -1,16 +1,60 @@
-- name: Check delete dashboard is working
- grafana_dashboard:
+---
+- name: Delete dashboard | check mode | dashboard exists
+ community.grafana.grafana_dashboard:
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
state: absent
- uid: "{{ result.uid }}"
- register: result
+ uid: "{{ uid_to_delete }}"
+ check_mode: true
+ register: dd_result1
+- ansible.builtin.assert:
+ that:
+ - dd_result1.failed == false
+ - dd_result1.changed == true
+ - dd_result1.msg == 'Dashboard ' ~ dd_result1.uid ~ ' will be deleted'
+
+- name: Delete dashboard | run mode | dashboard exists
+ community.grafana.grafana_dashboard:
+ grafana_url: "{{ grafana_url }}"
+ grafana_user: "{{ grafana_username }}"
+ grafana_password: "{{ grafana_password }}"
+ state: absent
+ uid: "{{ uid_to_delete }}"
+ check_mode: false
+ register: dd_result2
+- ansible.builtin.assert:
+ that:
+ - dd_result2.failed == false
+ - dd_result2.changed == true
+ - dd_result2.msg == 'Dashboard ' ~ dd_result2.uid ~ ' deleted'
-- debug:
- var: result
+- name: Delete dashboard | check mode | dashboard does not exist
+ community.grafana.grafana_dashboard:
+ grafana_url: "{{ grafana_url }}"
+ grafana_user: "{{ grafana_username }}"
+ grafana_password: "{{ grafana_password }}"
+ state: absent
+ uid: "{{ uid_to_delete }}"
+ check_mode: true
+ register: dd_result1
+- ansible.builtin.assert:
+ that:
+ - dd_result1.failed == false
+ - dd_result1.changed == false
+ - dd_result1.msg == 'Dashboard ' ~ dd_result1.uid ~ ' does not exist.'
-- assert:
+- name: Delete dashboard | run mode | dashboard does not exist
+ community.grafana.grafana_dashboard:
+ grafana_url: "{{ grafana_url }}"
+ grafana_user: "{{ grafana_username }}"
+ grafana_password: "{{ grafana_password }}"
+ state: absent
+ uid: "{{ uid_to_delete }}"
+ check_mode: false
+ register: dd_result2
+- ansible.builtin.assert:
that:
- - "result.changed == true"
- - "result.msg == 'Dashboard {{ result.uid }} deleted'"
+ - dd_result2.failed == false
+ - dd_result2.changed == false
+ - dd_result2.msg == 'Dashboard ' ~ dd_result2.uid ~ ' does not exist.' \ No newline at end of file
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/main.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/main.yml
index 4d9138fcf..86e756e95 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/main.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_dashboard/tasks/main.yml
@@ -1,7 +1,20 @@
-- block:
- - include: dashboard-from-url.yml
- - include: delete-dashboard.yml
- - include: dashboard-from-id.yml
- - include: dashboard-from-file.yml
- - include: dashboard-export.yml
- - include: dashboard-folder-destination.yml
+---
+- name: Create dashboard from url
+ ansible.builtin.include_tasks:
+ file: dashboard-from-url.yml
+
+- name: Create dashboard from id
+ ansible.builtin.include_tasks:
+ file: dashboard-from-id.yml
+
+- name: Create dashboard from file and export
+ ansible.builtin.include_tasks:
+ file: dashboard-from-file-export.yml
+
+- name: Create dashboard from file by org_name
+ ansible.builtin.include_tasks:
+ file: dashboard-by-org-name.yml
+
+- name: Create dashboard from file in non existing folder
+ ansible.builtin.include_tasks:
+ file: dashboard-folder-destination.yml
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/defaults/main.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/defaults/main.yml
index 8b9c9348a..4abf9bb43 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/defaults/main.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/defaults/main.yml
@@ -1,7 +1,5 @@
---
-grafana_url: "http://grafana:3000/"
-grafana_username: "admin"
-grafana_password: "admin"
-
-...
+grafana_url: http://grafana:3000/
+grafana_username: admin
+grafana_password: admin
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/runme.sh b/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/runme.sh
new file mode 100755
index 000000000..867afb0d3
--- /dev/null
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/runme.sh
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+
+set -eux
+
+ansible-playbook site.yml
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/site.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/site.yml
new file mode 100644
index 000000000..c8374dcdd
--- /dev/null
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/site.yml
@@ -0,0 +1,6 @@
+---
+- name: Run tests for grafana_datasource
+ hosts: localhost
+ tasks:
+ - ansible.builtin.include_role:
+ name: ../../grafana_datasource
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/azure.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/azure.yml
index a96691893..0dbd94963 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/azure.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/azure.yml
@@ -1,11 +1,12 @@
+---
- name: Create azure datasource
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-azure
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
- org_id: '1'
+ grafana_password: "{{ grafana_password }}"
+ org_id: "1"
ds_type: grafana-azure-monitor-datasource
ds_url: http://example.com
azure_client: client1
@@ -13,38 +14,38 @@
azure_secret: secret1
azure_cloud: azuremonitor
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - result.changed
- - "result.msg == 'Datasource datasource-azure created'"
- - result.datasource.access == 'proxy'
- - result.datasource.basicAuth == false
- - result.datasource.database == ''
- - result.datasource.isDefault == false
- - result.datasource.jsonData.clientId == 'client1'
- - result.datasource.jsonData.cloudName == 'azuremonitor'
- - result.datasource.jsonData.tenantId == 'tenant1'
- - result.datasource.jsonData.tlsAuth == false
- - result.datasource.jsonData.tlsAuthWithCACert == false
- - result.datasource.name == 'datasource-azure'
- - result.datasource.orgId == 1
- - ('password' not in result.datasource) or (result.datasource.password == '')
- - result.datasource.type == 'grafana-azure-monitor-datasource'
- - result.datasource.url == 'http://example.com'
- - result.datasource.user == ''
- - result.datasource.withCredentials == false
+ - result.changed
+ - result.msg == 'Datasource datasource-azure created'
+ - result.datasource.access == 'proxy'
+ - result.datasource.basicAuth == false
+ - result.datasource.database == ''
+ - result.datasource.isDefault == false
+ - result.datasource.jsonData.clientId == 'client1'
+ - result.datasource.jsonData.cloudName == 'azuremonitor'
+ - result.datasource.jsonData.tenantId == 'tenant1'
+ - result.datasource.jsonData.tlsAuth == false
+ - result.datasource.jsonData.tlsAuthWithCACert == false
+ - result.datasource.name == 'datasource-azure'
+ - result.datasource.orgId == 1
+ - ('password' not in result.datasource) or (result.datasource.password == '')
+ - result.datasource.type == 'grafana-azure-monitor-datasource'
+ - result.datasource.url == 'http://example.com'
+ - result.datasource.user == ''
+ - result.datasource.withCredentials == false
- name: Check azure datasource creation idempotency
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-azure
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
- org_id: '1'
+ grafana_password: "{{ grafana_password }}"
+ org_id: "1"
ds_type: grafana-azure-monitor-datasource
ds_url: http://example.com
azure_client: client1
@@ -52,37 +53,37 @@
azure_secret: secret1
azure_cloud: azuremonitor
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - not result.changed
- - result.datasource.access == 'proxy'
- - result.datasource.basicAuth == false
- - result.datasource.database == ''
- - result.datasource.isDefault == false
- - result.datasource.jsonData.clientId == 'client1'
- - result.datasource.jsonData.cloudName == 'azuremonitor'
- - result.datasource.jsonData.tenantId == 'tenant1'
- - result.datasource.jsonData.tlsAuth == false
- - result.datasource.jsonData.tlsAuthWithCACert == false
- - result.datasource.name == 'datasource-azure'
- - result.datasource.orgId == 1
- - ('password' not in result.datasource) or (result.datasource.password == '')
- - result.datasource.type == 'grafana-azure-monitor-datasource'
- - result.datasource.url == 'http://example.com'
- - result.datasource.user == ''
- - result.datasource.withCredentials == false
+ - not result.changed
+ - result.datasource.access == 'proxy'
+ - result.datasource.basicAuth == false
+ - result.datasource.database == ''
+ - result.datasource.isDefault == false
+ - result.datasource.jsonData.clientId == 'client1'
+ - result.datasource.jsonData.cloudName == 'azuremonitor'
+ - result.datasource.jsonData.tenantId == 'tenant1'
+ - result.datasource.jsonData.tlsAuth == false
+ - result.datasource.jsonData.tlsAuthWithCACert == false
+ - result.datasource.name == 'datasource-azure'
+ - result.datasource.orgId == 1
+ - ('password' not in result.datasource) or (result.datasource.password == '')
+ - result.datasource.type == 'grafana-azure-monitor-datasource'
+ - result.datasource.url == 'http://example.com'
+ - result.datasource.user == ''
+ - result.datasource.withCredentials == false
- name: Delete azure datasource
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-azure
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
- org_id: '1'
+ grafana_password: "{{ grafana_password }}"
+ org_id: "1"
ds_type: grafana-azure-monitor-datasource
ds_url: http://example.com
azure_client: client1
@@ -91,22 +92,22 @@
azure_cloud: azuremonitor
state: absent
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - result.changed
- - "result.msg == 'Datasource datasource-azure deleted.'"
+ - result.changed
+ - result.msg == 'Datasource datasource-azure deleted.'
- name: Delete azure datasource (idempotency)
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-azure
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
- org_id: '1'
+ grafana_password: "{{ grafana_password }}"
+ org_id: "1"
ds_type: grafana-azure-monitor-datasource
ds_url: http://example.com
azure_client: client1
@@ -115,9 +116,9 @@
azure_cloud: azuremonitor
state: absent
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - not result.changed
+ - not result.changed
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/cloudwatch.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/cloudwatch.yml
index 50268ea8f..79408b68b 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/cloudwatch.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/cloudwatch.yml
@@ -1,11 +1,12 @@
+---
- name: Create cloudwatch datasource
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-cloudwatch
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
- org_id: '1'
+ grafana_password: "{{ grafana_password }}"
+ org_id: "1"
ds_type: cloudwatch
ds_url: http://monitoring.us-west-1.amazonaws.com
aws_auth_type: keys
@@ -14,38 +15,38 @@
aws_secret_key: mel10n
aws_custom_metrics_namespaces: n1,n2
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - result.changed
- - "result.msg == 'Datasource datasource-cloudwatch created'"
- - result.datasource.access == 'proxy'
- - result.datasource.basicAuth == false
- - result.datasource.database == ''
- - result.datasource.isDefault == false
- - result.datasource.jsonData.authType == 'keys'
- - result.datasource.jsonData.customMetricsNamespaces == 'n1,n2'
- - result.datasource.jsonData.defaultRegion == 'us-west-1'
- - result.datasource.jsonData.tlsAuth == false
- - result.datasource.jsonData.tlsAuthWithCACert == false
- - result.datasource.name == 'datasource-cloudwatch'
- - result.datasource.orgId == 1
- - ('password' not in result.datasource) or (result.datasource.password == '')
- - result.datasource.type == 'cloudwatch'
- - result.datasource.url == 'http://monitoring.us-west-1.amazonaws.com'
- - result.datasource.user == ''
- - result.datasource.withCredentials == false
+ - result.changed
+ - result.msg == 'Datasource datasource-cloudwatch created'
+ - result.datasource.access == 'proxy'
+ - result.datasource.basicAuth == false
+ - result.datasource.database == ''
+ - result.datasource.isDefault == false
+ - result.datasource.jsonData.authType == 'keys'
+ - result.datasource.jsonData.customMetricsNamespaces == 'n1,n2'
+ - result.datasource.jsonData.defaultRegion == 'us-west-1'
+ - result.datasource.jsonData.tlsAuth == false
+ - result.datasource.jsonData.tlsAuthWithCACert == false
+ - result.datasource.name == 'datasource-cloudwatch'
+ - result.datasource.orgId == 1
+ - ('password' not in result.datasource) or (result.datasource.password == '')
+ - result.datasource.type == 'cloudwatch'
+ - result.datasource.url == 'http://monitoring.us-west-1.amazonaws.com'
+ - result.datasource.user == ''
+ - result.datasource.withCredentials == false
- name: Check cloudwatch datasource creation idempotency
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-cloudwatch
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
- org_id: '1'
+ org_id: "1"
ds_type: cloudwatch
ds_url: http://monitoring.us-west-1.amazonaws.com
aws_auth_type: keys
@@ -54,58 +55,58 @@
aws_secret_key: mel10n
aws_custom_metrics_namespaces: n1,n2
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - not result.changed
- - result.datasource.access == 'proxy'
- - result.datasource.basicAuth == false
- - result.datasource.database == ''
- - result.datasource.isDefault == false
- - result.datasource.jsonData.authType == 'keys'
- - result.datasource.jsonData.customMetricsNamespaces == 'n1,n2'
- - result.datasource.jsonData.defaultRegion == 'us-west-1'
- - result.datasource.jsonData.tlsAuth == false
- - result.datasource.jsonData.tlsAuthWithCACert == false
- - result.datasource.name == 'datasource-cloudwatch'
- - result.datasource.orgId == 1
- - ('password' not in result.datasource) or (result.datasource.password == '')
- - result.datasource.type == 'cloudwatch'
- - result.datasource.url == 'http://monitoring.us-west-1.amazonaws.com'
- - result.datasource.user == ''
- - result.datasource.withCredentials == false
+ - not result.changed
+ - result.datasource.access == 'proxy'
+ - result.datasource.basicAuth == false
+ - result.datasource.database == ''
+ - result.datasource.isDefault == false
+ - result.datasource.jsonData.authType == 'keys'
+ - result.datasource.jsonData.customMetricsNamespaces == 'n1,n2'
+ - result.datasource.jsonData.defaultRegion == 'us-west-1'
+ - result.datasource.jsonData.tlsAuth == false
+ - result.datasource.jsonData.tlsAuthWithCACert == false
+ - result.datasource.name == 'datasource-cloudwatch'
+ - result.datasource.orgId == 1
+ - ('password' not in result.datasource) or (result.datasource.password == '')
+ - result.datasource.type == 'cloudwatch'
+ - result.datasource.url == 'http://monitoring.us-west-1.amazonaws.com'
+ - result.datasource.user == ''
+ - result.datasource.withCredentials == false
- name: Delete cloudwatch datasource
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-cloudwatch
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
state: absent
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - result.changed
- - "result.msg == 'Datasource datasource-cloudwatch deleted.'"
+ - result.changed
+ - result.msg == 'Datasource datasource-cloudwatch deleted.'
- name: Delete cloudwatch datasource (idempotency)
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-cloudwatch
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
state: absent
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - not result.changed
+ - not result.changed
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/elastic.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/elastic.yml
index 73b258426..ff05b93f5 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/elastic.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/elastic.yml
@@ -1,313 +1,313 @@
---
- name: Create elasticsearch datasource with legacy elasticsearch format
register: result
- grafana_datasource:
- name: "datasource/elasticLegacy"
- uid: "myuid"
+ community.grafana.grafana_datasource:
+ name: datasource/elasticLegacy
+ uid: myuid
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
- org_id: '1'
+ org_id: "1"
ds_type: elasticsearch
ds_url: https://elastic.company.com:9200
- database: '[logstash_]YYYY.MM.DD'
+ database: "[logstash_]YYYY.MM.DD"
basic_auth_user: grafana
- basic_auth_password: '******'
- time_field: '@timestamp'
+ basic_auth_password: "******"
+ time_field: "@timestamp"
time_interval: 1m
interval: Daily
es_version: 56
max_concurrent_shard_requests: 42
tls_ca_cert: /etc/ssl/certs/ca.pem
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - result.changed
- - result.datasource.basicAuth
- - result.datasource.basicAuthUser == 'grafana'
- - result.datasource.access == 'proxy'
- - result.datasource.database == '[logstash_]YYYY.MM.DD'
- - not result.datasource.isDefault
- - result.datasource.jsonData.esVersion == 56
- - result.datasource.jsonData.interval == 'Daily'
- - result.datasource.jsonData.maxConcurrentShardRequests == 42
- - result.datasource.jsonData.timeField == '@timestamp'
- - not result.datasource.jsonData.tlsAuth
- - result.datasource.jsonData.tlsAuthWithCACert
- - result.datasource.name == 'datasource/elasticLegacy'
- - result.datasource.orgId == 1
- - ('password' not in result.datasource) or (result.datasource.password == '')
- - result.datasource.type == 'elasticsearch'
- - result.datasource.url == 'https://elastic.company.com:9200'
- - result.datasource.user == ''
- - not result.datasource.withCredentials
- - "result.msg == 'Datasource datasource/elasticLegacy created'"
+ - result.changed
+ - result.datasource.basicAuth
+ - result.datasource.basicAuthUser == 'grafana'
+ - result.datasource.access == 'proxy'
+ - result.datasource.database == '[logstash_]YYYY.MM.DD'
+ - not result.datasource.isDefault
+ - result.datasource.jsonData.esVersion == 56
+ - result.datasource.jsonData.interval == 'Daily'
+ - result.datasource.jsonData.maxConcurrentShardRequests == 42
+ - result.datasource.jsonData.timeField == '@timestamp'
+ - not result.datasource.jsonData.tlsAuth
+ - result.datasource.jsonData.tlsAuthWithCACert
+ - result.datasource.name == 'datasource/elasticLegacy'
+ - result.datasource.orgId == 1
+ - ('password' not in result.datasource) or (result.datasource.password == '')
+ - result.datasource.type == 'elasticsearch'
+ - result.datasource.url == 'https://elastic.company.com:9200'
+ - result.datasource.user == ''
+ - not result.datasource.withCredentials
+ - result.msg == 'Datasource datasource/elasticLegacy created'
- name: Create elasticsearch datasource with new elsaticsearch version format
register: result
- grafana_datasource:
- name: "datasource/elastic"
+ community.grafana.grafana_datasource:
+ name: datasource/elastic
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
- org_id: '1'
+ org_id: "1"
ds_type: elasticsearch
ds_url: https://elastic.company.com:9200
- database: '[logstash_]YYYY.MM.DD'
+ database: "[logstash_]YYYY.MM.DD"
basic_auth_user: grafana
- basic_auth_password: '******'
- time_field: '@timestamp'
+ basic_auth_password: "******"
+ time_field: "@timestamp"
time_interval: 1m
interval: Daily
- es_version: "7.10+"
+ es_version: 7.10+
max_concurrent_shard_requests: 42
tls_ca_cert: /etc/ssl/certs/ca.pem
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - result.changed
- - result.datasource.basicAuth
- - result.datasource.basicAuthUser == 'grafana'
- - result.datasource.access == 'proxy'
- - result.datasource.database == '[logstash_]YYYY.MM.DD'
- - not result.datasource.isDefault
- - result.datasource.jsonData.esVersion == "7.10.0"
- - result.datasource.jsonData.interval == 'Daily'
- - result.datasource.jsonData.maxConcurrentShardRequests == 42
- - result.datasource.jsonData.timeField == '@timestamp'
- - not result.datasource.jsonData.tlsAuth
- - result.datasource.jsonData.tlsAuthWithCACert
- - result.datasource.name == 'datasource/elastic'
- - result.datasource.orgId == 1
- - ('password' not in result.datasource) or (result.datasource.password == '')
- - result.datasource.type == 'elasticsearch'
- - result.datasource.url == 'https://elastic.company.com:9200'
- - result.datasource.user == ''
- - not result.datasource.withCredentials
- - "result.msg == 'Datasource datasource/elastic created'"
+ - result.changed
+ - result.datasource.basicAuth
+ - result.datasource.basicAuthUser == 'grafana'
+ - result.datasource.access == 'proxy'
+ - result.datasource.database == '[logstash_]YYYY.MM.DD'
+ - not result.datasource.isDefault
+ - result.datasource.jsonData.esVersion == "7.10.0"
+ - result.datasource.jsonData.interval == 'Daily'
+ - result.datasource.jsonData.maxConcurrentShardRequests == 42
+ - result.datasource.jsonData.timeField == '@timestamp'
+ - not result.datasource.jsonData.tlsAuth
+ - result.datasource.jsonData.tlsAuthWithCACert
+ - result.datasource.name == 'datasource/elastic'
+ - result.datasource.orgId == 1
+ - ('password' not in result.datasource) or (result.datasource.password == '')
+ - result.datasource.type == 'elasticsearch'
+ - result.datasource.url == 'https://elastic.company.com:9200'
+ - result.datasource.user == ''
+ - not result.datasource.withCredentials
+ - result.msg == 'Datasource datasource/elastic created'
- name: Check elasticsearch datasource creation idempotency
register: result
- grafana_datasource:
- name: "datasource/elastic"
+ community.grafana.grafana_datasource:
+ name: datasource/elastic
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
- org_id: '1'
+ org_id: "1"
ds_type: elasticsearch
ds_url: https://elastic.company.com:9200
- database: '[logstash_]YYYY.MM.DD'
+ database: "[logstash_]YYYY.MM.DD"
basic_auth_user: grafana
- basic_auth_password: '******'
- time_field: '@timestamp'
+ basic_auth_password: "******"
+ time_field: "@timestamp"
time_interval: 1m
interval: Daily
- es_version: "7.10+"
+ es_version: 7.10+
max_concurrent_shard_requests: 42
tls_ca_cert: /etc/ssl/certs/ca.pem
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - not result.changed
- - result.datasource.basicAuth
- - result.datasource.basicAuthUser == 'grafana'
- - result.datasource.access == 'proxy'
- - result.datasource.database == '[logstash_]YYYY.MM.DD'
- - not result.datasource.isDefault
- - result.datasource.jsonData.esVersion == '7.10.0'
- - result.datasource.jsonData.interval == 'Daily'
- - result.datasource.jsonData.maxConcurrentShardRequests == 42
- - result.datasource.jsonData.timeField == '@timestamp'
- - not result.datasource.jsonData.tlsAuth
- - result.datasource.jsonData.tlsAuthWithCACert
- - result.datasource.name == 'datasource/elastic'
- - result.datasource.orgId == 1
- - ('password' not in result.datasource) or (result.datasource.password == '')
- - result.datasource.type == 'elasticsearch'
- - result.datasource.url == 'https://elastic.company.com:9200'
- - result.datasource.user == ''
- - not result.datasource.withCredentials
+ - not result.changed
+ - result.datasource.basicAuth
+ - result.datasource.basicAuthUser == 'grafana'
+ - result.datasource.access == 'proxy'
+ - result.datasource.database == '[logstash_]YYYY.MM.DD'
+ - not result.datasource.isDefault
+ - result.datasource.jsonData.esVersion == '7.10.0'
+ - result.datasource.jsonData.interval == 'Daily'
+ - result.datasource.jsonData.maxConcurrentShardRequests == 42
+ - result.datasource.jsonData.timeField == '@timestamp'
+ - not result.datasource.jsonData.tlsAuth
+ - result.datasource.jsonData.tlsAuthWithCACert
+ - result.datasource.name == 'datasource/elastic'
+ - result.datasource.orgId == 1
+ - ('password' not in result.datasource) or (result.datasource.password == '')
+ - result.datasource.type == 'elasticsearch'
+ - result.datasource.url == 'https://elastic.company.com:9200'
+ - result.datasource.user == ''
+ - not result.datasource.withCredentials
-- name: update elasticsearch datasource creation
+- name: Update elasticsearch datasource creation
register: result
- grafana_datasource:
- name: "datasource/elastic"
+ community.grafana.grafana_datasource:
+ name: datasource/elastic
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
- org_id: '1'
+ org_id: "1"
ds_type: elasticsearch
ds_url: https://elastic.example.com:9200
- database: '[logstash_]YYYY.MM.DD'
+ database: "[logstash_]YYYY.MM.DD"
basic_auth_user: grafana
- basic_auth_password: '******'
- time_field: '@timestamp'
+ basic_auth_password: "******"
+ time_field: "@timestamp"
time_interval: 1m
interval: Daily
- es_version: "7.10+"
+ es_version: 7.10+
max_concurrent_shard_requests: 42
tls_ca_cert: /etc/ssl/certs/ca.pem
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - result.changed
- - result.datasource.basicAuth
- - result.datasource.basicAuthUser == 'grafana'
- - result.datasource.access == 'proxy'
- - result.datasource.database == '[logstash_]YYYY.MM.DD'
- - not result.datasource.isDefault
- - result.datasource.jsonData.esVersion == '7.10.0'
- - result.datasource.jsonData.interval == 'Daily'
- - result.datasource.jsonData.maxConcurrentShardRequests == 42
- - result.datasource.jsonData.timeField == '@timestamp'
- - not result.datasource.jsonData.tlsAuth
- - result.datasource.jsonData.tlsAuthWithCACert
- - result.datasource.name == 'datasource/elastic'
- - result.datasource.orgId == 1
- - ('password' not in result.datasource) or (result.datasource.password == '')
- - result.datasource.type == 'elasticsearch'
- - result.datasource.url == 'https://elastic.example.com:9200'
- - result.datasource.user == ''
- - not result.datasource.withCredentials
+ - result.changed
+ - result.datasource.basicAuth
+ - result.datasource.basicAuthUser == 'grafana'
+ - result.datasource.access == 'proxy'
+ - result.datasource.database == '[logstash_]YYYY.MM.DD'
+ - not result.datasource.isDefault
+ - result.datasource.jsonData.esVersion == '7.10.0'
+ - result.datasource.jsonData.interval == 'Daily'
+ - result.datasource.jsonData.maxConcurrentShardRequests == 42
+ - result.datasource.jsonData.timeField == '@timestamp'
+ - not result.datasource.jsonData.tlsAuth
+ - result.datasource.jsonData.tlsAuthWithCACert
+ - result.datasource.name == 'datasource/elastic'
+ - result.datasource.orgId == 1
+ - ('password' not in result.datasource) or (result.datasource.password == '')
+ - result.datasource.type == 'elasticsearch'
+ - result.datasource.url == 'https://elastic.example.com:9200'
+ - result.datasource.user == ''
+ - not result.datasource.withCredentials
-- name: update elasticsearch datasource (ignoring secureJsonData)
+- name: Update elasticsearch datasource (ignoring secureJsonData)
register: result
- grafana_datasource:
- name: "datasource/elastic"
+ community.grafana.grafana_datasource:
+ name: datasource/elastic
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
- org_id: '1'
+ org_id: "1"
ds_type: elasticsearch
ds_url: https://elastic.example.com:9200
- database: '[logstash_]YYYY.MM.DD'
+ database: "[logstash_]YYYY.MM.DD"
basic_auth_user: grafana
- basic_auth_password: '******'
- time_field: '@timestamp'
+ basic_auth_password: "******"
+ time_field: "@timestamp"
time_interval: 1m
interval: Daily
- es_version: "7.10+"
+ es_version: 7.10+
max_concurrent_shard_requests: 42
tls_ca_cert: /etc/ssl/certs/ca.pem
enforce_secure_data: false
additional_json_data:
- nonSecureTest: "nonsecure"
+ nonSecureTest: nonsecure
additional_secure_json_data:
- secureTest: "secure"
+ secureTest: secure
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - result.changed
- - result.datasource.basicAuth
- - result.datasource.basicAuthUser == 'grafana'
- - result.datasource.access == 'proxy'
- - result.datasource.database == '[logstash_]YYYY.MM.DD'
- - not result.datasource.isDefault
- - result.datasource.jsonData.esVersion == '7.10.0'
- - result.datasource.jsonData.interval == 'Daily'
- - result.datasource.jsonData.maxConcurrentShardRequests == 42
- - result.datasource.jsonData.timeField == '@timestamp'
- - not result.datasource.jsonData.tlsAuth
- - result.datasource.jsonData.tlsAuthWithCACert
- - result.datasource.name == 'datasource/elastic'
- - result.datasource.orgId == 1
- - ('password' not in result.datasource) or (result.datasource.password == '')
- - result.datasource.type == 'elasticsearch'
- - result.datasource.url == 'https://elastic.example.com:9200'
- - result.datasource.user == ''
- - not result.datasource.withCredentials
- - result.datasource.jsonData.nonSecureTest == 'nonsecure'
+ - result.changed
+ - result.datasource.basicAuth
+ - result.datasource.basicAuthUser == 'grafana'
+ - result.datasource.access == 'proxy'
+ - result.datasource.database == '[logstash_]YYYY.MM.DD'
+ - not result.datasource.isDefault
+ - result.datasource.jsonData.esVersion == '7.10.0'
+ - result.datasource.jsonData.interval == 'Daily'
+ - result.datasource.jsonData.maxConcurrentShardRequests == 42
+ - result.datasource.jsonData.timeField == '@timestamp'
+ - not result.datasource.jsonData.tlsAuth
+ - result.datasource.jsonData.tlsAuthWithCACert
+ - result.datasource.name == 'datasource/elastic'
+ - result.datasource.orgId == 1
+ - ('password' not in result.datasource) or (result.datasource.password == '')
+ - result.datasource.type == 'elasticsearch'
+ - result.datasource.url == 'https://elastic.example.com:9200'
+ - result.datasource.user == ''
+ - not result.datasource.withCredentials
+ - result.datasource.jsonData.nonSecureTest == 'nonsecure'
-- name: update elasticsearch datasource (including secureJsonData)
+- name: Update elasticsearch datasource (including secureJsonData)
register: result
- grafana_datasource:
- name: "datasource/elastic"
+ community.grafana.grafana_datasource:
+ name: datasource/elastic
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
- org_id: '1'
+ org_id: "1"
ds_type: elasticsearch
ds_url: https://elastic.example.com:9200
- database: '[logstash_]YYYY.MM.DD'
+ database: "[logstash_]YYYY.MM.DD"
basic_auth_user: grafana
- basic_auth_password: '******'
- time_field: '@timestamp'
+ basic_auth_password: "******"
+ time_field: "@timestamp"
time_interval: 1m
interval: Daily
- es_version: "7.10+"
+ es_version: 7.10+
max_concurrent_shard_requests: 42
tls_ca_cert: /etc/ssl/certs/ca.pem
enforce_secure_data: true
additional_json_data:
- nonSecureTest: "nonsecure"
+ nonSecureTest: nonsecure
additional_secure_json_data:
- secureTest: "secure"
+ secureTest: secure
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - result.changed
- - result.datasource.basicAuth
- - result.datasource.basicAuthUser == 'grafana'
- - result.datasource.access == 'proxy'
- - result.datasource.database == '[logstash_]YYYY.MM.DD'
- - not result.datasource.isDefault
- - result.datasource.jsonData.esVersion == '7.10.0'
- - result.datasource.jsonData.interval == 'Daily'
- - result.datasource.jsonData.maxConcurrentShardRequests == 42
- - result.datasource.jsonData.timeField == '@timestamp'
- - not result.datasource.jsonData.tlsAuth
- - result.datasource.jsonData.tlsAuthWithCACert
- - result.datasource.name == 'datasource/elastic'
- - result.datasource.orgId == 1
- - ('password' not in result.datasource) or (result.datasource.password == '')
- - result.datasource.type == 'elasticsearch'
- - result.datasource.url == 'https://elastic.example.com:9200'
- - result.datasource.user == ''
- - not result.datasource.withCredentials
- - result.datasource.jsonData.nonSecureTest == 'nonsecure'
- - result.datasource.secureJsonFields.secureTest == true
- - result.diff.after.secureJsonData is defined
+ - result.changed
+ - result.datasource.basicAuth
+ - result.datasource.basicAuthUser == 'grafana'
+ - result.datasource.access == 'proxy'
+ - result.datasource.database == '[logstash_]YYYY.MM.DD'
+ - not result.datasource.isDefault
+ - result.datasource.jsonData.esVersion == '7.10.0'
+ - result.datasource.jsonData.interval == 'Daily'
+ - result.datasource.jsonData.maxConcurrentShardRequests == 42
+ - result.datasource.jsonData.timeField == '@timestamp'
+ - not result.datasource.jsonData.tlsAuth
+ - result.datasource.jsonData.tlsAuthWithCACert
+ - result.datasource.name == 'datasource/elastic'
+ - result.datasource.orgId == 1
+ - ('password' not in result.datasource) or (result.datasource.password == '')
+ - result.datasource.type == 'elasticsearch'
+ - result.datasource.url == 'https://elastic.example.com:9200'
+ - result.datasource.user == ''
+ - not result.datasource.withCredentials
+ - result.datasource.jsonData.nonSecureTest == 'nonsecure'
+ - result.datasource.secureJsonFields.secureTest == true
+ - result.diff.after.secureJsonData is defined
- name: Delete elasticsearch datasource
register: result
- grafana_datasource:
- name: "datasource/elastic"
+ community.grafana.grafana_datasource:
+ name: datasource/elastic
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
state: absent
-- assert:
+- ansible.builtin.assert:
that:
- - result.changed
+ - result.changed
- name: Delete elasticsearch datasource (idempotency)
register: result
- grafana_datasource:
- name: "datasource/elastic"
+ community.grafana.grafana_datasource:
+ name: datasource/elastic
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
state: absent
-- assert:
+- ansible.builtin.assert:
that:
- - not result.changed
+ - not result.changed
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/errors.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/errors.yml
index 731a19d8f..779b4724d 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/errors.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/errors.yml
@@ -1,18 +1,18 @@
---
- name: Create datasource without `ds_type` and `ds_url` (expect failure)
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-postgres
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
ignore_errors: true
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - not result.changed
- - result.failed
- - "result.msg == 'state is present but all of the following are missing: ds_type, ds_url'"
+ - not result.changed
+ - result.failed
+ - "result.msg == 'state is present but all of the following are missing: ds_type, ds_url'"
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/influx.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/influx.yml
index da61833f6..7952bec6b 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/influx.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/influx.yml
@@ -1,88 +1,89 @@
+---
- name: Create influxdb datasource
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-influxdb
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
- org_id: '1'
+ org_id: "1"
ds_type: influxdb
ds_url: https://influx.company.com:8086
database: telegraf
- time_interval: '>10s'
+ time_interval: ">10s"
tls_ca_cert: /etc/ssl/certs/ca.pem
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - result.changed
- - "result.msg == 'Datasource datasource-influxdb created'"
+ - result.changed
+ - result.msg == 'Datasource datasource-influxdb created'
- name: Check influxdb datasource creation idempotency
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-influxdb
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
- org_id: '1'
+ org_id: "1"
ds_type: influxdb
ds_url: https://influx.company.com:8086
database: telegraf
- time_interval: '>10s'
+ time_interval: ">10s"
tls_ca_cert: /etc/ssl/certs/ca.pem
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - not result.changed
- - result.datasource.basicAuth == false
- - result.datasource.access == 'proxy'
- - result.datasource.database == 'telegraf'
- - result.datasource.isDefault == false
- - result.datasource.jsonData.timeInterval == '>10s'
- - result.datasource.jsonData.tlsAuth == false
- - result.datasource.jsonData.tlsAuthWithCACert
- - result.datasource.name == 'datasource-influxdb'
- - result.datasource.orgId == 1
- - ('password' not in result.datasource) or (result.datasource.password == '')
- - result.datasource.type == 'influxdb'
- - result.datasource.url == 'https://influx.company.com:8086'
- - result.datasource.user == ''
- - result.datasource.withCredentials == false
+ - not result.changed
+ - result.datasource.basicAuth == false
+ - result.datasource.access == 'proxy'
+ - result.datasource.database == 'telegraf'
+ - result.datasource.isDefault == false
+ - result.datasource.jsonData.timeInterval == '>10s'
+ - result.datasource.jsonData.tlsAuth == false
+ - result.datasource.jsonData.tlsAuthWithCACert
+ - result.datasource.name == 'datasource-influxdb'
+ - result.datasource.orgId == 1
+ - ('password' not in result.datasource) or (result.datasource.password == '')
+ - result.datasource.type == 'influxdb'
+ - result.datasource.url == 'https://influx.company.com:8086'
+ - result.datasource.user == ''
+ - result.datasource.withCredentials == false
- name: Delete influxdb datasource
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-influxdb
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
state: absent
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - result.changed
+ - result.changed
- name: Delete influxdb datasource (idempotency)
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-influxdb
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
state: absent
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - not result.changed
+ - not result.changed
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/issues.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/issues.yml
index f80677d8d..3b4df5a71 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/issues.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/issues.yml
@@ -1,46 +1,43 @@
---
-
-- name: test datasource name with slash
+- name: Test datasource name with slash
register: result
- grafana_datasource:
- name: "datasource/elastic"
+ community.grafana.grafana_datasource:
+ name: datasource/elastic
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
- org_id: '1'
+ org_id: "1"
ds_type: elasticsearch
ds_url: https://elastic.company.com:9200
- database: '[logstash_]YYYY.MM.DD'
+ database: "[logstash_]YYYY.MM.DD"
basic_auth_user: grafana
- basic_auth_password: '******'
- time_field: '@timestamp'
+ basic_auth_password: "******"
+ time_field: "@timestamp"
time_interval: 1m
interval: Daily
es_version: 56
max_concurrent_shard_requests: 42
tls_ca_cert: /etc/ssl/certs/ca.pem
-- assert:
+- ansible.builtin.assert:
that:
- - result.changed
- - result.datasource.basicAuth
- - result.datasource.basicAuthUser == 'grafana'
- - result.datasource.access == 'proxy'
- - result.datasource.database == '[logstash_]YYYY.MM.DD'
- - not result.datasource.isDefault
- - result.datasource.jsonData.esVersion == 56
- - result.datasource.jsonData.interval == 'Daily'
- - result.datasource.jsonData.maxConcurrentShardRequests == 42
- - result.datasource.jsonData.timeField == '@timestamp'
- - not result.datasource.jsonData.tlsAuth
- - not result.datasource.jsonData.tlsAuthWithCACert
- - result.datasource.name == 'datasource/elastic'
- - result.datasource.orgId == 1
- - ('password' not in result.datasource) or (result.datasource.password == '')
- - result.datasource.type == 'elasticsearch'
- - result.datasource.url == 'https://elastic.company.com:9200'
- - result.datasource.user == ''
- - not result.datasource.withCredentials
- - "result.msg == 'Datasource datasource/elastic created'"
-
-...
+ - result.changed
+ - result.datasource.basicAuth
+ - result.datasource.basicAuthUser == 'grafana'
+ - result.datasource.access == 'proxy'
+ - result.datasource.database == '[logstash_]YYYY.MM.DD'
+ - not result.datasource.isDefault
+ - result.datasource.jsonData.esVersion == 56
+ - result.datasource.jsonData.interval == 'Daily'
+ - result.datasource.jsonData.maxConcurrentShardRequests == 42
+ - result.datasource.jsonData.timeField == '@timestamp'
+ - not result.datasource.jsonData.tlsAuth
+ - not result.datasource.jsonData.tlsAuthWithCACert
+ - result.datasource.name == 'datasource/elastic'
+ - result.datasource.orgId == 1
+ - ('password' not in result.datasource) or (result.datasource.password == '')
+ - result.datasource.type == 'elasticsearch'
+ - result.datasource.url == 'https://elastic.company.com:9200'
+ - result.datasource.user == ''
+ - not result.datasource.withCredentials
+ - result.msg == 'Datasource datasource/elastic created'
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/loki.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/loki.yml
index 68eca9802..a501b99d2 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/loki.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/loki.yml
@@ -1,82 +1,83 @@
+---
- name: Create loki datasource
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-loki
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
- org_id: '1'
+ grafana_password: "{{ grafana_password }}"
+ org_id: "1"
ds_type: loki
ds_url: https://loki.company.com:3100
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - result.changed
- - "result.msg == 'Datasource datasource-loki created'"
+ - result.changed
+ - result.msg == 'Datasource datasource-loki created'
- name: Check loki datasource creation idempotency
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-loki
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
- org_id: '1'
+ org_id: "1"
ds_type: loki
ds_url: https://loki.company.com:3100
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - not result.changed
- - result.datasource.basicAuth == false
- - result.datasource.access == 'proxy'
- - result.datasource.database == ''
- - result.datasource.isDefault == false
- - result.datasource.jsonData.tlsAuth == false
- - result.datasource.jsonData.tlsAuthWithCACert == false
- - result.datasource.name == 'datasource-loki'
- - result.datasource.orgId == 1
- - ('password' not in result.datasource) or (result.datasource.password == '')
- - result.datasource.type == 'loki'
- - result.datasource.url == 'https://loki.company.com:3100'
- - result.datasource.user == ''
- - result.datasource.withCredentials == false
+ - not result.changed
+ - result.datasource.basicAuth == false
+ - result.datasource.access == 'proxy'
+ - result.datasource.database == ''
+ - result.datasource.isDefault == false
+ - result.datasource.jsonData.tlsAuth == false
+ - result.datasource.jsonData.tlsAuthWithCACert == false
+ - result.datasource.name == 'datasource-loki'
+ - result.datasource.orgId == 1
+ - ('password' not in result.datasource) or (result.datasource.password == '')
+ - result.datasource.type == 'loki'
+ - result.datasource.url == 'https://loki.company.com:3100'
+ - result.datasource.user == ''
+ - result.datasource.withCredentials == false
- name: Delete loki datasource
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-loki
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
state: absent
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - result.changed
- - "result.msg == 'Datasource datasource-loki deleted.'"
+ - result.changed
+ - result.msg == 'Datasource datasource-loki deleted.'
- name: Delete loki datasource (idempotency)
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-loki
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
state: absent
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - not result.changed
+ - not result.changed
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/main.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/main.yml
index b5798e9a8..0b3ea4cd6 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/main.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/main.yml
@@ -1,16 +1,24 @@
---
-
- block:
- - include: errors.yml
- - include: elastic.yml
- - include: influx.yml
- - include: postgres.yml
- - include: cloudwatch.yml
- - include: thruk.yml
- - include: loki.yml
- - include: zabbix.yml
- - include: redis.yml
- - include: azure.yml
- - include: uid.yml
-
-...
+ - ansible.builtin.include_tasks:
+ file: errors.yml
+ - ansible.builtin.include_tasks:
+ file: elastic.yml
+ - ansible.builtin.include_tasks:
+ file: influx.yml
+ - ansible.builtin.include_tasks:
+ file: postgres.yml
+ - ansible.builtin.include_tasks:
+ file: cloudwatch.yml
+ - ansible.builtin.include_tasks:
+ file: thruk.yml
+ - ansible.builtin.include_tasks:
+ file: loki.yml
+ - ansible.builtin.include_tasks:
+ file: zabbix.yml
+ - ansible.builtin.include_tasks:
+ file: redis.yml
+ - ansible.builtin.include_tasks:
+ file: azure.yml
+ - ansible.builtin.include_tasks:
+ file: uid.yml
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/postgres.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/postgres.yml
index 80221f012..b07bc752b 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/postgres.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/postgres.yml
@@ -1,11 +1,12 @@
+---
- name: Create postgres datasource
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-postgres
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
- org_id: '1'
+ org_id: "1"
ds_type: postgres
ds_url: postgres.company.com:5432
database: db
@@ -15,22 +16,22 @@
additional_json_data:
timescaledb: true
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - result.changed
- - "result.msg == 'Datasource datasource-postgres created'"
+ - result.changed
+ - result.msg == 'Datasource datasource-postgres created'
- name: Check postgres datasource creation idempotency
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-postgres
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
- org_id: '1'
+ org_id: "1"
ds_type: postgres
ds_url: postgres.company.com:5432
database: db
@@ -40,54 +41,54 @@
additional_json_data:
timescaledb: true
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - not result.changed
- - result.datasource.basicAuth == false
- - result.datasource.database == 'db'
- - result.datasource.isDefault == false
- - result.datasource.jsonData.sslmode == 'verify-full'
- - result.datasource.jsonData.tlsAuth == false
- - result.datasource.jsonData.tlsAuthWithCACert == false
- - result.datasource.jsonData.timescaledb == true
- - result.datasource.name == 'datasource-postgres'
- - result.datasource.orgId == 1
- - result.datasource.type == 'postgres'
- - result.datasource.url == 'postgres.company.com:5432'
- - result.datasource.user == 'postgres'
- - result.datasource.withCredentials == false
+ - not result.changed
+ - result.datasource.basicAuth == false
+ - result.datasource.database == 'db'
+ - result.datasource.isDefault == false
+ - result.datasource.jsonData.sslmode == 'verify-full'
+ - result.datasource.jsonData.tlsAuth == false
+ - result.datasource.jsonData.tlsAuthWithCACert == false
+ - result.datasource.jsonData.timescaledb == true
+ - result.datasource.name == 'datasource-postgres'
+ - result.datasource.orgId == 1
+ - result.datasource.type == 'postgres'
+ - result.datasource.url == 'postgres.company.com:5432'
+ - result.datasource.user == 'postgres'
+ - result.datasource.withCredentials == false
- name: Delete postgres datasource
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-postgres
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
state: absent
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - result.changed
+ - result.changed
- name: Delete postgres datasource
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-postgres
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
state: absent
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - not result.changed
+ - not result.changed
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/quickwit.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/quickwit.yml
new file mode 100644
index 000000000..8221dcb42
--- /dev/null
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/quickwit.yml
@@ -0,0 +1,137 @@
+---
+- name: Create Quickwit datasource
+ register: result
+ community.grafana.grafana_datasource:
+ name: Quickwit
+ grafana_url: "{{ grafana_url }}"
+ grafana_user: "{{ grafana_username }}"
+ grafana_password: "{{ grafana_password }}"
+ org_id: "1"
+ ds_type: quickwit-quickwit-datasource
+ ds_url: http://localhost:7280/api/v1
+ additional_json_data:
+ index: hdfs-logs
+ timeField: timestamp
+ timeOutputFormat: unix_timestamp_secs
+ logMessageField: body
+ logLevelField: severity_text
+
+- ansible.builtin.debug:
+ var: result
+
+- ansible.builtin.assert:
+ that:
+ - result.changed
+ - result.datasource.access == 'proxy'
+ - not result.datasource.isDefault
+ - result.datasource.database == ''
+ - result.datasource.name == 'Quickwit'
+ - result.datasource.orgId == 1
+ - result.datasource.type == 'quickwit-quickwit-datasource'
+ - result.datasource.url == 'http://localhost:7280/api/v1'
+ - result.msg == 'Datasource Quickwit created'
+ - result.datasource.jsonData.index == 'hdfs-logs'
+ - result.datasource.jsonData.timeField == 'timestamp'
+ - result.datasource.jsonData.timeOutputFormat == 'unix_timestamp_secs'
+ - result.datasource.jsonData.logMessageField == 'body'
+ - result.datasource.jsonData.logLevelField == 'severity_text'
+
+- name: Check Quickwit datasource creation (idempotency)
+ register: result
+ community.grafana.grafana_datasource:
+ name: Quickwit
+ grafana_url: "{{ grafana_url }}"
+ grafana_user: "{{ grafana_username }}"
+ grafana_password: "{{ grafana_password }}"
+ org_id: "1"
+ ds_type: quickwit-quickwit-datasource
+ ds_url: http://localhost:7280/api/v1
+ additional_json_data:
+ index: hdfs-logs
+ timeField: timestamp
+ timeOutputFormat: unix_timestamp_secs
+ logMessageField: body
+ logLevelField: severity_text
+
+- ansible.builtin.debug:
+ var: result
+
+- ansible.builtin.assert:
+ that:
+ - not result.changed
+ - result.datasource.access == 'proxy'
+ - not result.datasource.isDefault
+ - result.datasource.database == ''
+ - result.datasource.name == 'Quickwit'
+ - result.datasource.orgId == 1
+ - result.datasource.type == 'quickwit-quickwit-datasource'
+ - result.datasource.url == 'http://localhost:7280/api/v1'
+ - result.msg == 'Datasource Quickwit created'
+ - result.datasource.jsonData.index == 'hdfs-logs'
+ - result.datasource.jsonData.timeField == 'timestamp'
+ - result.datasource.jsonData.timeOutputFormat == 'unix_timestamp_secs'
+ - result.datasource.jsonData.logMessageField == 'body'
+ - result.datasource.jsonData.logLevelField == 'severity_text'
+
+- name: Update Quickwit datasource
+ register: result
+ community.grafana.grafana_datasource:
+ name: Quickwit
+ grafana_url: "{{ grafana_url }}"
+ grafana_user: "{{ grafana_username }}"
+ grafana_password: "{{ grafana_password }}"
+ org_id: "1"
+ ds_type: quickwit-quickwit-datasource
+ ds_url: http://quickwit-url:7280/api/v1
+ additional_json_data:
+ index: hdfs-logs
+ timeField: timestamp
+ timeOutputFormat: unix_timestamp_millis
+ logMessageField: body
+ logLevelField: severity_text
+
+- ansible.builtin.debug:
+ var: result
+
+- ansible.builtin.assert:
+ that:
+ - result.changed
+ - result.datasource.access == 'proxy'
+ - not result.datasource.isDefault
+ - result.datasource.database == ''
+ - result.datasource.name == 'Quickwit'
+ - result.datasource.orgId == 1
+ - result.datasource.type == 'quickwit-quickwit-datasource'
+ - result.datasource.url == 'http://quickwit-url:7280/api/v1'
+ - result.msg == 'Datasource Quickwit created'
+ - result.datasource.jsonData.index == 'hdfs-logs'
+ - result.datasource.jsonData.timeField == 'timestamp'
+ - result.datasource.jsonData.timeOutputFormat == 'unix_timestamp_millis'
+ - result.datasource.jsonData.logMessageField == 'body'
+ - result.datasource.jsonData.logLevelField == 'severity_text'
+
+- name: Delete Quickwit datasource
+ register: result
+ community.grafana.grafana_datasource:
+ name: Quickwit
+ grafana_url: "{{ grafana_url }}"
+ grafana_user: "{{ grafana_username }}"
+ grafana_password: "{{ grafana_password }}"
+ state: absent
+
+- ansible.builtin.assert:
+ that:
+ - result.changed
+
+- name: Delete Quickwit datasource (idempotency)
+ register: result
+ community.grafana.grafana_datasource:
+ name: Quickwit
+ grafana_url: "{{ grafana_url }}"
+ grafana_user: "{{ grafana_username }}"
+ grafana_password: "{{ grafana_password }}"
+ state: absent
+
+- ansible.builtin.assert:
+ that:
+ - not result.changed
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/redis.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/redis.yml
index 933695354..dc39be64e 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/redis.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/redis.yml
@@ -1,101 +1,102 @@
+---
- name: Create redis datasource
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-redis
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
- org_id: '1'
+ org_id: "1"
ds_type: redis-datasource
ds_url: https://redis.company.com:6379
time_interval: 1m
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - result.changed
- - result.datasource.access == 'proxy'
- - not result.datasource.isDefault
- - result.datasource.name == 'datasource-redis'
- - result.datasource.orgId == 1
- - result.datasource.type == 'redis-datasource'
- - result.datasource.url == 'https://redis.company.com:6379'
- - "result.msg == 'Datasource datasource-redis created'"
+ - result.changed
+ - result.datasource.access == 'proxy'
+ - not result.datasource.isDefault
+ - result.datasource.name == 'datasource-redis'
+ - result.datasource.orgId == 1
+ - result.datasource.type == 'redis-datasource'
+ - result.datasource.url == 'https://redis.company.com:6379'
+ - result.msg == 'Datasource datasource-redis created'
- name: Check redis-datasource datasource creation idempotency
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-redis
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
- org_id: '1'
+ org_id: "1"
ds_type: redis-datasource
ds_url: https://redis.company.com:6379
time_interval: 1m
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - not result.changed
- - result.datasource.access == 'proxy'
- - not result.datasource.isDefault
- - result.datasource.name == 'datasource-redis'
- - result.datasource.orgId == 1
- - result.datasource.type == 'redis-datasource'
- - result.datasource.url == 'https://redis.company.com:6379'
+ - not result.changed
+ - result.datasource.access == 'proxy'
+ - not result.datasource.isDefault
+ - result.datasource.name == 'datasource-redis'
+ - result.datasource.orgId == 1
+ - result.datasource.type == 'redis-datasource'
+ - result.datasource.url == 'https://redis.company.com:6379'
-- name: update redis-datasource datasource creation
+- name: Update redis-datasource datasource creation
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-redis
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
- org_id: '1'
+ org_id: "1"
ds_type: redis-datasource
ds_url: https://redisnew.company.com:6379
time_interval: 1m
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - result.changed
- - result.datasource.access == 'proxy'
- - not result.datasource.isDefault
- - result.datasource.name == 'datasource-redis'
- - result.datasource.orgId == 1
- - result.datasource.type == 'redis-datasource'
- - result.datasource.url == 'https://redisnew.company.com:6379'
+ - result.changed
+ - result.datasource.access == 'proxy'
+ - not result.datasource.isDefault
+ - result.datasource.name == 'datasource-redis'
+ - result.datasource.orgId == 1
+ - result.datasource.type == 'redis-datasource'
+ - result.datasource.url == 'https://redisnew.company.com:6379'
-- name: Delete redis-datasource datasource
+- name: Delete redis-datasource datasource
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-redis
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
state: absent
-- assert:
+- ansible.builtin.assert:
that:
- - result.changed
+ - result.changed
- name: Delete redis-datasource datasource (idempotency)
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-redis
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
state: absent
-- assert:
+- ansible.builtin.assert:
that:
- - not result.changed
+ - not result.changed
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/tempo.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/tempo.yml
new file mode 100644
index 000000000..51ab52513
--- /dev/null
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/tempo.yml
@@ -0,0 +1,79 @@
+---
+- name: Create tempo datasource
+ register: result
+ community.grafana.grafana_datasource:
+ name: datasource-tempo
+ grafana_url: "{{ grafana_url }}"
+ grafana_user: "{{ grafana_username }}"
+ grafana_password: "{{ grafana_password }}"
+ org_id: "1"
+ ds_type: tempo
+ ds_url: tempo.company.com:3100
+
+- ansible.builtin.debug:
+ var: result
+
+- ansible.builtin.assert:
+ that:
+ - result.changed
+ - result.msg == 'Datasource datasource-tempo created'
+
+- name: Check tempo datasource creation idempotency
+ register: result
+ community.grafana.grafana_datasource:
+ name: datasource-tempo
+ grafana_url: "{{ grafana_url }}"
+ grafana_user: "{{ grafana_username }}"
+ grafana_password: "{{ grafana_password }}"
+ org_id: "1"
+ ds_type: tempo
+ ds_url: tempo.company.com:3100
+
+- ansible.builtin.debug:
+ var: result
+
+- ansible.builtin.assert:
+ that:
+ - not result.changed
+ - result.datasource.basicAuth == false
+ - result.datasource.isDefault == false
+ - result.datasource.jsonData.tlsAuth == false
+ - result.datasource.jsonData.tlsAuthWithCACert == false
+ - result.datasource.secureJsonFields.httpHeaderValue1 == true
+ - result.datasource.name == 'datasource-tempo'
+ - result.datasource.orgId == 1
+ - result.datasource.type == 'tempo'
+ - result.datasource.url == 'tempo.company.com:3100'
+ - result.datasource.withCredentials == false
+
+- name: Delete tempo datasource
+ register: result
+ community.grafana.grafana_datasource:
+ name: datasource-tempo
+ grafana_url: "{{ grafana_url }}"
+ grafana_user: "{{ grafana_username }}"
+ grafana_password: "{{ grafana_password }}"
+ state: absent
+
+- ansible.builtin.debug:
+ var: result
+
+- ansible.builtin.assert:
+ that:
+ - result.changed
+
+- name: Delete tempo datasource
+ register: result
+ community.grafana.grafana_datasource:
+ name: datasource-tempo
+ grafana_url: "{{ grafana_url }}"
+ grafana_user: "{{ grafana_username }}"
+ grafana_password: "{{ grafana_password }}"
+ state: absent
+
+- ansible.builtin.debug:
+ var: result
+
+- ansible.builtin.assert:
+ that:
+ - not result.changed
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/thruk.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/thruk.yml
index 3ecc92d94..74f7c4dfa 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/thruk.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/thruk.yml
@@ -1,78 +1,79 @@
+---
- name: Create thruk datasource
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-thruk
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
org_id: "1"
ds_type: sni-thruk-datasource
- ds_url: "https://thruk.company.com/sitename/thruk"
- tls_skip_verify: yes
- validate_certs: no
+ ds_url: https://thruk.company.com/sitename/thruk
+ tls_skip_verify: true
+ validate_certs: false
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - result.changed
- - "result.msg == 'Datasource datasource-thruk created'"
+ - result.changed
+ - result.msg == 'Datasource datasource-thruk created'
- name: Check thruk datasource creation idempotency
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-thruk
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
- org_id: '1'
+ org_id: "1"
ds_type: sni-thruk-datasource
- ds_url: "https://thruk.company.com/sitename/thruk"
- tls_skip_verify: yes
- validate_certs: no
+ ds_url: https://thruk.company.com/sitename/thruk
+ tls_skip_verify: true
+ validate_certs: false
-- assert:
+- ansible.builtin.assert:
that:
- - not result.changed
- - result.datasource.basicAuth == false
- - result.datasource.access == 'proxy'
- - result.datasource.isDefault == false
- - result.datasource.jsonData.tlsAuth == false
- - result.datasource.jsonData.tlsAuthWithCACert == false
- - result.datasource.name == 'datasource-thruk'
- - result.datasource.orgId == 1
- - ('password' not in result.datasource) or (result.datasource.password == '')
- - result.datasource.type == 'sni-thruk-datasource'
- - result.datasource.url == 'https://thruk.company.com/sitename/thruk'
- - result.datasource.user == ''
- - result.datasource.withCredentials == false
+ - not result.changed
+ - result.datasource.basicAuth == false
+ - result.datasource.access == 'proxy'
+ - result.datasource.isDefault == false
+ - result.datasource.jsonData.tlsAuth == false
+ - result.datasource.jsonData.tlsAuthWithCACert == false
+ - result.datasource.name == 'datasource-thruk'
+ - result.datasource.orgId == 1
+ - ('password' not in result.datasource) or (result.datasource.password == '')
+ - result.datasource.type == 'sni-thruk-datasource'
+ - result.datasource.url == 'https://thruk.company.com/sitename/thruk'
+ - result.datasource.user == ''
+ - result.datasource.withCredentials == false
- name: Delete thruk datasource
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-thruk
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
state: absent
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - result.changed
+ - result.changed
- name: Delete thruk datasource (idempotency)
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-thruk
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
state: absent
-- assert:
+- ansible.builtin.assert:
that:
- - not result.changed
+ - not result.changed
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/uid.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/uid.yml
index 71102a074..7a472b42f 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/uid.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/uid.yml
@@ -1,253 +1,254 @@
+---
- name: Create datasource with uid
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-with-uid
uid: uid1
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
- org_id: '1'
+ org_id: "1"
ds_type: prometheus
ds_url: https://prometheus.company.com:8086
- basic_auth_user: "admin"
- basic_auth_password: "admin"
- validate_certs: False
- is_default: no
+ basic_auth_user: admin
+ basic_auth_password: admin
+ validate_certs: false
+ is_default: false
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - result.changed
- - "result.msg == 'Datasource datasource-with-uid created'"
+ - result.changed
+ - result.msg == 'Datasource datasource-with-uid created'
- name: Create datasource without uid
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-without-uid
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
- org_id: '1'
+ org_id: "1"
ds_type: prometheus
ds_url: https://prometheus.company.com:8086
- basic_auth_user: "admin"
- basic_auth_password: "admin"
- validate_certs: False
- is_default: no
+ basic_auth_user: admin
+ basic_auth_password: admin
+ validate_certs: false
+ is_default: false
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - result.changed
- - "result.msg == 'Datasource datasource-without-uid created'"
+ - result.changed
+ - result.msg == 'Datasource datasource-without-uid created'
- name: Check datasource creation idempotency with uid
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-with-uid
uid: uid1
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
- org_id: '1'
+ org_id: "1"
ds_type: prometheus
ds_url: https://prometheus.company.com:8086
- basic_auth_user: "admin"
- basic_auth_password: "admin"
- validate_certs: False
- is_default: no
+ basic_auth_user: admin
+ basic_auth_password: admin
+ validate_certs: false
+ is_default: false
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - not result.changed
- - result.datasource.access == 'proxy'
- - result.datasource.isDefault == false
- - result.datasource.jsonData.tlsAuth == false
- - result.datasource.name == 'datasource-with-uid'
- - result.datasource.uid == 'uid1'
- - result.datasource.orgId == 1
- - ('password' not in result.datasource) or (result.datasource.password == '')
- - result.datasource.type == 'prometheus'
- - result.datasource.url == 'https://prometheus.company.com:8086'
- - result.datasource.user == ''
- - result.datasource.withCredentials == false
+ - not result.changed
+ - result.datasource.access == 'proxy'
+ - result.datasource.isDefault == false
+ - result.datasource.jsonData.tlsAuth == false
+ - result.datasource.name == 'datasource-with-uid'
+ - result.datasource.uid == 'uid1'
+ - result.datasource.orgId == 1
+ - ('password' not in result.datasource) or (result.datasource.password == '')
+ - result.datasource.type == 'prometheus'
+ - result.datasource.url == 'https://prometheus.company.com:8086'
+ - result.datasource.user == ''
+ - result.datasource.withCredentials == false
- name: Check datasource creation idempotency without uid
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-without-uid
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
- org_id: '1'
+ org_id: "1"
ds_type: prometheus
ds_url: https://prometheus.company.com:8086
- basic_auth_user: "admin"
- basic_auth_password: "admin"
- validate_certs: False
- is_default: no
+ basic_auth_user: admin
+ basic_auth_password: admin
+ validate_certs: false
+ is_default: false
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - not result.changed
- - result.datasource.access == 'proxy'
- - result.datasource.isDefault == false
- - result.datasource.jsonData.tlsAuth == false
- - result.datasource.name == 'datasource-without-uid'
- - result.datasource.uid
- - result.datasource.orgId == 1
- - ('password' not in result.datasource) or (result.datasource.password == '')
- - result.datasource.type == 'prometheus'
- - result.datasource.url == 'https://prometheus.company.com:8086'
- - result.datasource.user == ''
- - result.datasource.withCredentials == false
+ - not result.changed
+ - result.datasource.access == 'proxy'
+ - result.datasource.isDefault == false
+ - result.datasource.jsonData.tlsAuth == false
+ - result.datasource.name == 'datasource-without-uid'
+ - result.datasource.uid
+ - result.datasource.orgId == 1
+ - ('password' not in result.datasource) or (result.datasource.password == '')
+ - result.datasource.type == 'prometheus'
+ - result.datasource.url == 'https://prometheus.company.com:8086'
+ - result.datasource.user == ''
+ - result.datasource.withCredentials == false
- name: Set uid for datasource with random uid
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-without-uid
uid: uid3
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
- org_id: '1'
+ org_id: "1"
ds_type: prometheus
ds_url: https://prometheus.company.com:8086
- basic_auth_user: "admin"
- basic_auth_password: "admin"
- validate_certs: False
- is_default: no
+ basic_auth_user: admin
+ basic_auth_password: admin
+ validate_certs: false
+ is_default: false
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - result.changed
- - result.datasource.access == 'proxy'
- - result.datasource.isDefault == false
- - result.datasource.jsonData.tlsAuth == false
- - result.datasource.name == 'datasource-without-uid'
- - result.datasource.uid == 'uid3'
- - result.datasource.orgId == 1
- - ('password' not in result.datasource) or (result.datasource.password == '')
- - result.datasource.type == 'prometheus'
- - result.datasource.url == 'https://prometheus.company.com:8086'
- - result.datasource.user == ''
- - result.datasource.withCredentials == false
+ - result.changed
+ - result.datasource.access == 'proxy'
+ - result.datasource.isDefault == false
+ - result.datasource.jsonData.tlsAuth == false
+ - result.datasource.name == 'datasource-without-uid'
+ - result.datasource.uid == 'uid3'
+ - result.datasource.orgId == 1
+ - ('password' not in result.datasource) or (result.datasource.password == '')
+ - result.datasource.type == 'prometheus'
+ - result.datasource.url == 'https://prometheus.company.com:8086'
+ - result.datasource.user == ''
+ - result.datasource.withCredentials == false
- name: Change uid for datasource
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-with-uid
uid: uid2
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
- org_id: '1'
+ org_id: "1"
ds_type: prometheus
ds_url: https://prometheus.company.com:8086
- basic_auth_user: "admin"
- basic_auth_password: "admin"
- validate_certs: False
- is_default: no
+ basic_auth_user: admin
+ basic_auth_password: admin
+ validate_certs: false
+ is_default: false
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - result.changed
- - result.datasource.access == 'proxy'
- - result.datasource.isDefault == false
- - result.datasource.jsonData.tlsAuth == false
- - result.datasource.name == 'datasource-with-uid'
- - result.datasource.uid == 'uid2'
- - result.datasource.orgId == 1
- - ('password' not in result.datasource) or (result.datasource.password == '')
- - result.datasource.type == 'prometheus'
- - result.datasource.url == 'https://prometheus.company.com:8086'
- - result.datasource.user == ''
- - result.datasource.withCredentials == false
+ - result.changed
+ - result.datasource.access == 'proxy'
+ - result.datasource.isDefault == false
+ - result.datasource.jsonData.tlsAuth == false
+ - result.datasource.name == 'datasource-with-uid'
+ - result.datasource.uid == 'uid2'
+ - result.datasource.orgId == 1
+ - ('password' not in result.datasource) or (result.datasource.password == '')
+ - result.datasource.type == 'prometheus'
+ - result.datasource.url == 'https://prometheus.company.com:8086'
+ - result.datasource.user == ''
+ - result.datasource.withCredentials == false
- name: Delete datasource-with-uid
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-with-uid
uid: uid1
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
- org_id: '1'
+ org_id: "1"
ds_type: prometheus
ds_url: https://prometheus.company.com:8086
- basic_auth_user: "admin"
- basic_auth_password: "admin"
- validate_certs: False
- is_default: no
+ basic_auth_user: admin
+ basic_auth_password: admin
+ validate_certs: false
+ is_default: false
state: absent
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - result.changed
+ - result.changed
- name: Delete datasource-without-uid
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-without-uid
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
- org_id: '1'
+ org_id: "1"
ds_type: prometheus
ds_url: https://prometheus.company.com:8086
- basic_auth_user: "admin"
- basic_auth_password: "admin"
- validate_certs: False
- is_default: no
+ basic_auth_user: admin
+ basic_auth_password: admin
+ validate_certs: false
+ is_default: false
state: absent
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - result.changed
+ - result.changed
- name: Delete datasource-with-uid (idempotency)
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-with-uid
uid: uid1
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
- org_id: '1'
+ org_id: "1"
ds_type: prometheus
ds_url: https://prometheus.company.com:8086
- basic_auth_user: "admin"
- basic_auth_password: "admin"
- validate_certs: False
- is_default: no
+ basic_auth_user: admin
+ basic_auth_password: admin
+ validate_certs: false
+ is_default: false
state: absent
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - not result.changed
+ - not result.changed
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/zabbix.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/zabbix.yml
index c8a8236bf..d238efb3e 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/zabbix.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_datasource/tasks/zabbix.yml
@@ -1,114 +1,115 @@
+---
- name: Create zabbix datasource
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-zabbix
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
- org_id: '1'
+ org_id: "1"
ds_type: alexanderzobnin-zabbix-datasource
ds_url: https://zabbix.company.com
zabbix_user: grafana
- zabbix_password: '******'
+ zabbix_password: "******"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - result.changed
- - not result.datasource.isDefault
- - result.datasource.jsonData.username == 'grafana'
- - result.datasource.name == 'datasource-zabbix'
- - result.datasource.orgId == 1
- - ('password' not in result.datasource) or (result.datasource.password == '')
- - result.datasource.type == 'alexanderzobnin-zabbix-datasource'
- - result.datasource.url == 'https://zabbix.company.com'
- - result.datasource.user == ''
- - not result.datasource.withCredentials
- - "result.msg == 'Datasource datasource-zabbix created'"
+ - result.changed
+ - not result.datasource.isDefault
+ - result.datasource.jsonData.username == 'grafana'
+ - result.datasource.name == 'datasource-zabbix'
+ - result.datasource.orgId == 1
+ - ('password' not in result.datasource) or (result.datasource.password == '')
+ - result.datasource.type == 'alexanderzobnin-zabbix-datasource'
+ - result.datasource.url == 'https://zabbix.company.com'
+ - result.datasource.user == ''
+ - not result.datasource.withCredentials
+ - result.msg == 'Datasource datasource-zabbix created'
- name: Create zabbix datasource (idempotency)
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-zabbix
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
- org_id: '1'
+ org_id: "1"
ds_type: alexanderzobnin-zabbix-datasource
ds_url: https://zabbix.company.com
zabbix_user: grafana
- zabbix_password: '******'
+ zabbix_password: "******"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - not result.changed
- - not result.datasource.isDefault
- - result.datasource.jsonData.username == 'grafana'
- - result.datasource.name == 'datasource-zabbix'
- - result.datasource.orgId == 1
- - ('password' not in result.datasource) or (result.datasource.password == '')
- - result.datasource.type == 'alexanderzobnin-zabbix-datasource'
- - result.datasource.url == 'https://zabbix.company.com'
- - result.datasource.user == ''
- - not result.datasource.withCredentials
+ - not result.changed
+ - not result.datasource.isDefault
+ - result.datasource.jsonData.username == 'grafana'
+ - result.datasource.name == 'datasource-zabbix'
+ - result.datasource.orgId == 1
+ - ('password' not in result.datasource) or (result.datasource.password == '')
+ - result.datasource.type == 'alexanderzobnin-zabbix-datasource'
+ - result.datasource.url == 'https://zabbix.company.com'
+ - result.datasource.user == ''
+ - not result.datasource.withCredentials
- name: Update zabbix datasource
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-zabbix
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
- org_id: '1'
+ org_id: "1"
ds_type: alexanderzobnin-zabbix-datasource
ds_url: https://zabbix.example.com
zabbix_user: grafana
- zabbix_password: '******'
+ zabbix_password: "******"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - result.changed
- - not result.datasource.isDefault
- - result.datasource.jsonData.username == 'grafana'
- - result.datasource.name == 'datasource-zabbix'
- - result.datasource.orgId == 1
- - ('password' not in result.datasource) or (result.datasource.password == '')
- - result.datasource.type == 'alexanderzobnin-zabbix-datasource'
- - result.datasource.url == 'https://zabbix.example.com'
- - result.datasource.user == ''
- - not result.datasource.withCredentials
- - "result.msg == 'Datasource datasource-zabbix updated'"
+ - result.changed
+ - not result.datasource.isDefault
+ - result.datasource.jsonData.username == 'grafana'
+ - result.datasource.name == 'datasource-zabbix'
+ - result.datasource.orgId == 1
+ - ('password' not in result.datasource) or (result.datasource.password == '')
+ - result.datasource.type == 'alexanderzobnin-zabbix-datasource'
+ - result.datasource.url == 'https://zabbix.example.com'
+ - result.datasource.user == ''
+ - not result.datasource.withCredentials
+ - result.msg == 'Datasource datasource-zabbix updated'
- name: Delete zabbix datasource
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-zabbix
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
state: absent
-- assert:
+- ansible.builtin.assert:
that:
- - result.changed
+ - result.changed
- name: Delete zabbix datasource (idempotency)
register: result
- grafana_datasource:
+ community.grafana.grafana_datasource:
name: datasource-zabbix
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
grafana_password: "{{ grafana_password }}"
state: absent
-- assert:
+- ansible.builtin.assert:
that:
- - not result.changed
+ - not result.changed
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_folder/defaults/main.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_folder/defaults/main.yml
index 8b9c9348a..4abf9bb43 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_folder/defaults/main.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_folder/defaults/main.yml
@@ -1,7 +1,5 @@
---
-grafana_url: "http://grafana:3000/"
-grafana_username: "admin"
-grafana_password: "admin"
-
-...
+grafana_url: http://grafana:3000/
+grafana_username: admin
+grafana_password: admin
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_folder/runme.sh b/ansible_collections/community/grafana/tests/integration/targets/grafana_folder/runme.sh
new file mode 100755
index 000000000..9daa487db
--- /dev/null
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_folder/runme.sh
@@ -0,0 +1,6 @@
+#!/usr/bin/env bash
+
+set -eux
+
+ansible-playbook site.yml --check
+ansible-playbook site.yml
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_folder/site.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_folder/site.yml
new file mode 100644
index 000000000..2041400ea
--- /dev/null
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_folder/site.yml
@@ -0,0 +1,6 @@
+---
+- name: Run tests for grafana_folder
+ hosts: localhost
+ tasks:
+ - ansible.builtin.include_role:
+ name: ../../grafana_folder
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_folder/tasks/create-delete.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_folder/tasks/create-delete.yml
new file mode 100644
index 000000000..c818c2ef1
--- /dev/null
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_folder/tasks/create-delete.yml
@@ -0,0 +1,58 @@
+---
+- name: Create a Folder
+ community.grafana.grafana_folder:
+ url: "{{ grafana_url }}"
+ url_username: "{{ grafana_username }}"
+ url_password: "{{ grafana_password }}"
+ title: grafana_working_group
+ state: present
+ register: result
+
+- ansible.builtin.assert:
+ that:
+ - result.changed == true
+ - result.folder.title == 'grafana_working_group'
+ when: not ansible_check_mode
+
+- name: Test folder creation idempotency
+ community.grafana.grafana_folder:
+ url: "{{ grafana_url }}"
+ url_username: "{{ grafana_username }}"
+ url_password: "{{ grafana_password }}"
+ title: grafana_working_group
+ state: present
+ register: result
+
+- ansible.builtin.assert:
+ that:
+ - result.changed == false
+ - result.folder.title == 'grafana_working_group'
+ when: not ansible_check_mode
+
+- name: Delete a Folder
+ community.grafana.grafana_folder:
+ url: "{{ grafana_url }}"
+ url_username: "{{ grafana_username }}"
+ url_password: "{{ grafana_password }}"
+ title: grafana_working_group
+ state: absent
+ register: result
+
+- ansible.builtin.assert:
+ that:
+ - result.changed == true
+ when: not ansible_check_mode
+
+- name: Test folder deletion idempotency
+ community.grafana.grafana_folder:
+ url: "{{ grafana_url }}"
+ url_username: "{{ grafana_username }}"
+ url_password: "{{ grafana_password }}"
+ title: grafana_working_group
+ state: absent
+ register: result
+
+- ansible.builtin.assert:
+ that:
+ - result.changed == false
+ when: not ansible_check_mode
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_folder/tasks/main.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_folder/tasks/main.yml
index c6a520560..0ac91f375 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_folder/tasks/main.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_folder/tasks/main.yml
@@ -1,55 +1,6 @@
---
+- name: Folder creation and deletion
+ ansible.builtin.include_tasks: create-delete.yml
-- name: Create a Folder
- grafana_folder:
- url: "{{ grafana_url }}"
- url_username: "{{ grafana_username }}"
- url_password: "{{ grafana_password }}"
- title: "grafana_working_group"
- state: present
- register: result
-
-- assert:
- that:
- - "result.changed == true"
- - "result.folder.title == 'grafana_working_group'"
-
-- name: Test folder creation idempotency
- grafana_folder:
- url: "{{ grafana_url }}"
- url_username: "{{ grafana_username }}"
- url_password: "{{ grafana_password }}"
- title: "grafana_working_group"
- state: present
- register: result
-
-- assert:
- that:
- - "result.changed == false"
- - "result.folder.title == 'grafana_working_group'"
-
-- name: Delete a Folder
- grafana_folder:
- url: "{{ grafana_url }}"
- url_username: "{{ grafana_username }}"
- url_password: "{{ grafana_password }}"
- title: "grafana_working_group"
- state: absent
- register: result
-
-- assert:
- that:
- - "result.changed == true"
-
-- name: Test folder deletion idempotency
- grafana_folder:
- url: "{{ grafana_url }}"
- url_username: "{{ grafana_username }}"
- url_password: "{{ grafana_password }}"
- title: "grafana_working_group"
- state: absent
- register: result
-
-- assert:
- that:
- - "result.changed == false"
+- name: Folder creation and deletion for organization
+ ansible.builtin.include_tasks: org.yml
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_folder/tasks/org.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_folder/tasks/org.yml
new file mode 100644
index 000000000..f30d48c14
--- /dev/null
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_folder/tasks/org.yml
@@ -0,0 +1,7 @@
+---
+- module_defaults:
+ community.grafana.grafana_folder:
+ org_name: Main Org.
+ block:
+ - name: Folder creation and deletion
+ ansible.builtin.include_tasks: create-delete.yml
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/defaults/main.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/defaults/main.yml
index 8b9c9348a..4abf9bb43 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/defaults/main.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/defaults/main.yml
@@ -1,7 +1,5 @@
---
-grafana_url: "http://grafana:3000/"
-grafana_username: "admin"
-grafana_password: "admin"
-
-...
+grafana_url: http://grafana:3000/
+grafana_username: admin
+grafana_password: admin
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/runme.sh b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/runme.sh
new file mode 100755
index 000000000..867afb0d3
--- /dev/null
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/runme.sh
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+
+set -eux
+
+ansible-playbook site.yml
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/site.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/site.yml
new file mode 100644
index 000000000..e20f44e32
--- /dev/null
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/site.yml
@@ -0,0 +1,6 @@
+---
+- name: Run tests for grafana_notification_channel
+ hosts: localhost
+ tasks:
+ - ansible.builtin.include_role:
+ name: ../../grafana_notification_channel
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/dingding.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/dingding.yml
index 7279e313b..80d2f07d8 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/dingding.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/dingding.yml
@@ -1,19 +1,19 @@
---
- name: Create dingding notification channel
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: dingding
name: dingding
type: dingding
dingding_url: https://example.org
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- result.changed == True
- result.channel.name == "dingding"
@@ -22,19 +22,19 @@
- name: Create dingding notification channel (idempotency)
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: dingding
name: dingding
type: dingding
dingding_url: https://example.org
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- result.changed == False
- result.channel.name == "dingding"
@@ -43,32 +43,32 @@
- name: Delete dingding notification channel
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: dingding
state: absent
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- result.changed == True
- name: Delete dingding notification channel (idempotency)
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: dingding
state: absent
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- result.changed == False
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/discord.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/discord.yml
index 29cfece70..30c70d63e 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/discord.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/discord.yml
@@ -1,19 +1,19 @@
---
- name: Create discord notification channel
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: discord
name: discord
type: discord
discord_url: https://example.org
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- result.changed == True
- result.channel.name == "discord"
@@ -22,19 +22,19 @@
- name: Create discord notification channel (idempotency)
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: discord
name: discord
type: discord
discord_url: https://example.org
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- result.changed == False
- result.channel.name == "discord"
@@ -43,32 +43,32 @@
- name: Delete discord notification channel
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: discord
state: absent
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- result.changed == True
- name: Delete discord notification channel (idempotency)
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: discord
state: absent
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- result.changed == False
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/email.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/email.yml
index 85a236c9e..29e188755 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/email.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/email.yml
@@ -1,7 +1,7 @@
---
- name: Create email notification channel
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: email
name: email
type: email
@@ -10,21 +10,21 @@
- bar@example.org
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == True"
+ - result.changed == True
- result.channel.name == "email"
- result.channel.type == "email"
- result.channel.uid == "email"
- name: Create email notification channel (idempotency)
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: email
name: email
type: email
@@ -33,47 +33,47 @@
- bar@example.org
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == False"
+ - result.changed == False
- result.channel.name == "email"
- result.channel.type == "email"
- result.channel.uid == "email"
- name: Delete discord notification channel
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: email
state: absent
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == True"
- - "result.state == 'absent'"
+ - result.changed == True
+ - result.state == 'absent'
- name: Delete discord notification channel (idempotency)
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: email
state: absent
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == False"
+ - result.changed == False
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/googlechat.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/googlechat.yml
index abc7db644..8acdf0a68 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/googlechat.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/googlechat.yml
@@ -1,74 +1,74 @@
---
- name: Create googlechat notification channel
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: googlechat
name: googlechat
type: googlechat
googlechat_url: https://example.org
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == True"
+ - result.changed == True
- result.channel.name == "googlechat"
- result.channel.uid == "googlechat"
- result.channel.type == "googlechat"
- name: Create googlechat notification channel (idempotency)
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: googlechat
name: googlechat
type: googlechat
googlechat_url: https://example.org
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == False"
+ - result.changed == False
- result.channel.name == "googlechat"
- result.channel.uid == "googlechat"
- result.channel.type == "googlechat"
- name: Delete googlechat notification channel
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: googlechat
state: absent
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == True"
+ - result.changed == True
- name: Delete googlechat notification channel (idempotency)
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: googlechat
state: absent
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == False"
+ - result.changed == False
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/hipchat.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/hipchat.yml
index 4a9ec1704..6423cafc8 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/hipchat.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/hipchat.yml
@@ -1,74 +1,74 @@
---
- name: Create hipchat notification channel
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: hipchat
name: hipchat
type: hipchat
hipchat_url: https://example.org
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == True"
+ - result.changed == True
- result.channel.name == "hipchat"
- result.channel.type == "hipchat"
- result.channel.uid == "hipchat"
- name: Create hipchat notification channel (idempotency)
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: hipchat
name: hipchat
type: hipchat
hipchat_url: https://example.org
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == False"
+ - result.changed == False
- result.channel.name == "hipchat"
- result.channel.type == "hipchat"
- result.channel.uid == "hipchat"
- name: Delete hipchat notification channel
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: hipchat
state: absent
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == True"
+ - result.changed == True
- name: Delete hipchat notification channel (idempotency)
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: hipchat
state: absent
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == False"
+ - result.changed == False
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/kafka.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/kafka.yml
index ffc208acb..d8ec9cad3 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/kafka.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/kafka.yml
@@ -1,7 +1,7 @@
---
- name: Create kafka notification channel
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: kafka
name: kafka
type: kafka
@@ -9,21 +9,21 @@
kafka_topic: test
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == True"
+ - result.changed == True
- result.channel.name == "kafka"
- result.channel.uid == "kafka"
- result.channel.type == "kafka"
- name: Create kafka notification channel (idempotentcy)
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: kafka
name: kafka
type: kafka
@@ -31,46 +31,46 @@
kafka_topic: test
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == False"
+ - result.changed == False
- result.channel.name == "kafka"
- result.channel.uid == "kafka"
- result.channel.type == "kafka"
- name: Delete kafka notification channel
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: kafka
state: absent
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == True"
+ - result.changed == True
- name: Delete kafka notification channel (idempotency)
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: kafka
state: absent
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == False"
+ - result.changed == False
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/line.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/line.yml
index 83a1863ba..dde928c3e 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/line.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/line.yml
@@ -1,74 +1,74 @@
---
- name: Create line notification channel
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: line
name: line
type: line
line_token: xxx
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == True"
+ - result.changed == True
- result.channel.uid == "line"
- result.channel.name == "line"
- result.channel.type == "line"
- name: Create line notification channel (idempotency)
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: line
name: line
type: line
line_token: xxx
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == False"
+ - result.changed == False
- result.channel.uid == "line"
- result.channel.name == "line"
- result.channel.type == "line"
- name: Delete line notification channel
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: line
state: absent
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == True"
+ - result.changed == True
- name: Delete line notification channel (idempotency)
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: line
state: absent
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == False"
+ - result.changed == False
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/main.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/main.yml
index ada6338c7..af0b2f861 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/main.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/main.yml
@@ -1,20 +1,34 @@
---
- block:
- - include: dingding.yml
- - include: discord.yml
- - include: email.yml
- - include: googlechat.yml
- - include: hipchat.yml
- - include: kafka.yml
-# - include: line.yml
- - include: teams.yml
- - include: opsgenie.yml
- - include: pagerduty.yml
- - include: prometheus.yml
- - include: pushover.yml
- - include: sensu.yml
- - include: slack-and-beyond.yml
- - include: telegram.yml
-# - include: threema.yml
- - include: victorops.yml
- - include: webhook.yml
+ - ansible.builtin.include_tasks:
+ file: dingding.yml
+ - ansible.builtin.include_tasks:
+ file: discord.yml
+ - ansible.builtin.include_tasks:
+ file: email.yml
+ - ansible.builtin.include_tasks:
+ file: googlechat.yml
+ - ansible.builtin.include_tasks:
+ file: hipchat.yml
+ - ansible.builtin.include_tasks:
+ file: kafka.yml
+ - ansible.builtin.include_tasks:
+ file: teams.yml
+ - ansible.builtin.include_tasks:
+ file: opsgenie.yml
+ - ansible.builtin.include_tasks:
+ file: pagerduty.yml
+ - ansible.builtin.include_tasks:
+ file: prometheus.yml
+ - ansible.builtin.include_tasks:
+ file: pushover.yml
+ - ansible.builtin.include_tasks:
+ file: sensu.yml
+ - ansible.builtin.include_tasks:
+ file: slack-and-beyond.yml
+ - ansible.builtin.include_tasks:
+ file: telegram.yml
+ - ansible.builtin.include_tasks:
+ file: victorops.yml
+ - ansible.builtin.include_tasks:
+ file: webhook.yml
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/opsgenie.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/opsgenie.yml
index f871fe719..cd1048b86 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/opsgenie.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/opsgenie.yml
@@ -1,7 +1,7 @@
---
- name: Create opsgenie notification channel
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: opsgenie
name: opsgenie
type: opsgenie
@@ -9,21 +9,21 @@
opsgenie_api_key: xxx
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == True"
+ - result.changed == True
- result.channel.name == "opsgenie"
- result.channel.type == "opsgenie"
- result.channel.uid == "opsgenie"
- name: Create opsgenie notification channel (idempotency)
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: opsgenie
name: opsgenie
type: opsgenie
@@ -31,47 +31,47 @@
opsgenie_api_key: xxx
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == False"
+ - result.changed == False
- result.channel.name == "opsgenie"
- result.channel.type == "opsgenie"
- result.channel.uid == "opsgenie"
- name: Delete opsgenie notification channel
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: opsgenie
state: absent
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == True"
- - "result.state == 'absent'"
+ - result.changed == True
+ - result.state == 'absent'
- name: Delete opsgenie notification channel (idempotency)
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: opsgenie
state: absent
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == False"
+ - result.changed == False
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/pagerduty.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/pagerduty.yml
index a8fa940b0..40fd00468 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/pagerduty.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/pagerduty.yml
@@ -1,74 +1,74 @@
---
- name: Create pagerduty notification channel
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: pagerduty
name: pagerduty
type: pagerduty
pagerduty_integration_key: xxx
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == True"
+ - result.changed == True
- result.channel.name == "pagerduty"
- result.channel.type == "pagerduty"
- result.channel.uid == "pagerduty"
- name: Create pagerduty notification channel (idempotency)
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: pagerduty
name: pagerduty
type: pagerduty
pagerduty_integration_key: xxx
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == False"
+ - result.changed == False
- result.channel.name == "pagerduty"
- result.channel.type == "pagerduty"
- result.channel.uid == "pagerduty"
- name: Delete pagerduty notification channel
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: pagerduty
state: absent
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == True"
+ - result.changed == True
- name: Delete pagerduty notification channel (idempotency)
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: pagerduty
state: absent
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == False"
+ - result.changed == False
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/prometheus.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/prometheus.yml
index 40810eaf3..c85d26f2e 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/prometheus.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/prometheus.yml
@@ -1,74 +1,74 @@
---
- name: Create prometheus notification channel
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: prometheus
name: prometheus
type: prometheus
prometheus_url: https://example.org
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == True"
+ - result.changed == True
- result.channel.name == "prometheus"
- result.channel.uid == "prometheus"
- result.channel.type == "prometheus-alertmanager"
- name: Create prometheus notification channel (idempotency)
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: prometheus
name: prometheus
type: prometheus
prometheus_url: https://example.org
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == False"
+ - result.changed == False
- result.channel.name == "prometheus"
- result.channel.uid == "prometheus"
- result.channel.type == "prometheus-alertmanager"
- name: Delete prometheus notification channel
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: prometheus
state: absent
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == True"
+ - result.changed == True
- name: Delete prometheus notification channel (idempotency)
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: prometheus
state: absent
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == False"
+ - result.changed == False
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/pushover.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/pushover.yml
index 894bd71e6..ee7b9bea4 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/pushover.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/pushover.yml
@@ -1,7 +1,7 @@
---
- name: Create pushover notification channel
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: pushover
name: pushover
type: pushover
@@ -9,21 +9,21 @@
pushover_user_key: yyy
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == True"
+ - result.changed == True
- result.channel.name == "pushover"
- result.channel.uid == "pushover"
- result.channel.type == "pushover"
- name: Create pushover notification channel (idempotency)
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: pushover
name: pushover
type: pushover
@@ -31,46 +31,46 @@
pushover_user_key: yyy
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == False"
+ - result.changed == False
- result.channel.name == "pushover"
- result.channel.uid == "pushover"
- result.channel.type == "pushover"
- name: Delete pushover notification channel
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: pushover
state: absent
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == True"
+ - result.changed == True
- name: Delete pushover notification channel (idempotency)
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: pushover
state: absent
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == False"
+ - result.changed == False
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/sensu.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/sensu.yml
index 01619b719..a46ef1d0a 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/sensu.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/sensu.yml
@@ -1,74 +1,74 @@
---
- name: Create sensu notification channel
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: sensu
name: sensu
type: sensu
sensu_url: https://example.org
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == True"
+ - result.changed == True
- result.channel.name == "sensu"
- result.channel.type == "sensu"
- result.channel.uid == "sensu"
- name: Create sensu notification channel
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: sensu
name: sensu
type: sensu
sensu_url: https://example.org
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == False"
+ - result.changed == False
- result.channel.name == "sensu"
- result.channel.type == "sensu"
- result.channel.uid == "sensu"
- name: Delete sensu notification channel
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: sensu
state: absent
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == True"
+ - result.changed == True
- name: Delete sensu notification channel (idempotency)
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: sensu
state: absent
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == False"
+ - result.changed == False
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/slack-and-beyond.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/slack-and-beyond.yml
index 0748c8bdb..1cbab6d5c 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/slack-and-beyond.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/slack-and-beyond.yml
@@ -1,110 +1,110 @@
---
- name: Create slack notification channel
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: slack
name: slack
type: slack
slack_url: https://hooks.slack.com/services/xxx/yyy/zzz
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == True"
+ - result.changed == True
- result.channel.name == "slack"
- result.channel.type == "slack"
- result.channel.uid == "slack"
- name: Create slack notification channel
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: slack
name: slack
type: slack
slack_url: https://hooks.slack.com/services/xxx/yyy/zzz
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == False"
+ - result.changed == False
- result.channel.name == "slack"
- result.channel.type == "slack"
- result.channel.uid == "slack"
- name: Check slack notification channel idempotency
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: slack
name: slack
type: slack
slack_url: https://hooks.slack.com/services/xxx/yyy/zzz
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == False"
+ - result.changed == False
- name: Update slack notification channel
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: slack
name: slack
type: slack
slack_url: https://hooks.slack.com/services/xxx/yyy/fff
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == True"
+ - result.changed == True
- name: Delete slack notification channel
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
state: absent
uid: slack
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == True"
+ - result.changed == True
- name: Delete slack notification channel (idempotency)
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
state: absent
uid: slack
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == False"
+ - result.changed == False
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/teams.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/teams.yml
index cfc44aef3..d9c7471c5 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/teams.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/teams.yml
@@ -1,74 +1,74 @@
---
- name: Create teams notification channel
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: teams
name: teams
type: teams
teams_url: https://example.org
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == True"
+ - result.changed == True
- result.channel.name == "teams"
- result.channel.uid == "teams"
- result.channel.type == "teams"
- name: Create teams notification channel (idempotency)
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: teams
name: teams
type: teams
teams_url: https://example.org
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == False"
+ - result.changed == False
- result.channel.name == "teams"
- result.channel.uid == "teams"
- result.channel.type == "teams"
- name: Delete teams notification channel
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: teams
state: absent
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == True"
+ - result.changed == True
- name: Delete teams notification channel (idempotency)
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: teams
state: absent
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == False"
+ - result.changed == False
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/telegram.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/telegram.yml
index 98a7a3c6d..38e27ef57 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/telegram.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/telegram.yml
@@ -1,7 +1,7 @@
---
- name: Create telegram notification channel
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: telegram
name: telegram
type: telegram
@@ -9,21 +9,21 @@
telegram_chat_id: yyy
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == True"
+ - result.changed == True
- result.channel.name == "telegram"
- result.channel.type == "telegram"
- result.channel.uid == "telegram"
- name: Create telegram notification channel
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: telegram
name: telegram
type: telegram
@@ -31,46 +31,46 @@
telegram_chat_id: yyy
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == False"
+ - result.changed == False
- result.channel.name == "telegram"
- result.channel.type == "telegram"
- result.channel.uid == "telegram"
- name: Delete telegram notification channel
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: telegram
state: absent
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == True"
+ - result.changed == True
- name: Delete telegram notification channel (idempotency)
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: telegram
state: absent
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == False"
+ - result.changed == False
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/threema.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/threema.yml
index 7858b6977..c61eae316 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/threema.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/threema.yml
@@ -1,7 +1,7 @@
---
- name: Create threema notification channel
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: threema
name: threema
type: threema
@@ -10,21 +10,21 @@
threema_api_secret: zzz
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == True"
+ - result.changed == True
- result.channel.name == "threema"
- result.channel.type == "threema"
- result.channel.uid == "threema"
- name: Create threema notification channel (idempotency)
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: threema
name: threema
type: threema
@@ -33,46 +33,46 @@
threema_api_secret: zzz
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == True"
+ - result.changed == True
- result.channel.name == "threema"
- result.channel.type == "threema"
- result.channel.uid == "threema"
- name: Delete threema notification channel
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: threema
state: absent
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == True"
+ - result.changed == True
- name: Delete threema notification channel (idempotency)
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: threema
state: absent
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == False"
+ - result.changed == False
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/victorops.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/victorops.yml
index 3779e813a..e21679132 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/victorops.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/victorops.yml
@@ -1,74 +1,74 @@
---
- name: Create victorops notification channel
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: victorops
name: victorops
type: victorops
victorops_url: https://example.org
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == True"
+ - result.changed == True
- result.channel.name == "victorops"
- result.channel.type == "victorops"
- result.channel.uid == "victorops"
- name: Create victorops notification channel (idempotency)
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: victorops
name: victorops
type: victorops
victorops_url: https://example.org
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == False"
+ - result.changed == False
- result.channel.name == "victorops"
- result.channel.type == "victorops"
- result.channel.uid == "victorops"
- name: Delete victorops notification channel
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: victorops
state: absent
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == True"
+ - result.changed == True
- name: Delete victorops notification channel (idempotency)
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: victorops
state: absent
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == False"
+ - result.changed == False
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/webhook.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/webhook.yml
index c9efd9193..5a00878f9 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/webhook.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_notification_channel/tasks/webhook.yml
@@ -1,74 +1,74 @@
---
- name: Create webhook notification channel
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: webhook
name: webhook
type: webhook
webhook_url: https://example.org
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == True"
+ - result.changed == True
- result.channel.name == "webhook"
- result.channel.uid == "webhook"
- result.channel.type == "webhook"
- name: Create webhook notification channel (idempotency)
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: webhook
name: webhook
type: webhook
webhook_url: https://example.org
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == False"
+ - result.changed == False
- result.channel.name == "webhook"
- result.channel.uid == "webhook"
- result.channel.type == "webhook"
- name: Delete webhook notification channel
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: webhook
state: absent
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == True"
+ - result.changed == True
- name: Delete webhook notification channel (idempotency)
register: result
- grafana_notification_channel:
+ community.grafana.grafana_notification_channel:
uid: webhook
state: absent
grafana_url: "{{ grafana_url }}"
grafana_user: "{{ grafana_username }}"
- grafana_password: "{{ grafana_password}}"
+ grafana_password: "{{ grafana_password }}"
-- debug:
+- ansible.builtin.debug:
var: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == False"
+ - result.changed == False
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_organization/defaults/main.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_organization/defaults/main.yml
index 7bb77ea3f..3edac8598 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_organization/defaults/main.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_organization/defaults/main.yml
@@ -1,4 +1,4 @@
---
-grafana_url: "http://grafana:3000/"
-grafana_username: "admin"
-grafana_password: "admin"
+grafana_url: http://grafana:3000/
+grafana_username: admin
+grafana_password: admin
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_organization/runme.sh b/ansible_collections/community/grafana/tests/integration/targets/grafana_organization/runme.sh
new file mode 100755
index 000000000..9daa487db
--- /dev/null
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_organization/runme.sh
@@ -0,0 +1,6 @@
+#!/usr/bin/env bash
+
+set -eux
+
+ansible-playbook site.yml --check
+ansible-playbook site.yml
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_organization/site.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_organization/site.yml
new file mode 100644
index 000000000..e2e4900bd
--- /dev/null
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_organization/site.yml
@@ -0,0 +1,6 @@
+---
+- name: Run tests for grafana_organization
+ hosts: localhost
+ tasks:
+ - ansible.builtin.include_role:
+ name: ../../grafana_organization
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_organization/tasks/main.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_organization/tasks/main.yml
index f8ccdf3bf..936b147cb 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_organization/tasks/main.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_organization/tasks/main.yml
@@ -1,5 +1,4 @@
---
-
- name: Create a Grafana organization
community.grafana.grafana_organization:
url: "{{ grafana_url }}"
@@ -8,13 +7,15 @@
name: orgtest
state: present
register: result
-- assert:
+
+- ansible.builtin.assert:
that:
- - "result.changed == true"
- - "result.failed == false"
- - "result.org.name == 'orgtest'"
+ - result.changed == true
+ - result.failed == false
+ - result.org.name == 'orgtest'
+ when: not ansible_check_mode
-- name: check idempotency Grafana organization
+- name: Check idempotency Grafana organization
community.grafana.grafana_organization:
url: "{{ grafana_url }}"
url_username: "{{ grafana_username }}"
@@ -22,11 +23,13 @@
name: orgtest
state: present
register: result
-- assert:
+
+- ansible.builtin.assert:
that:
- - "result.changed == false"
- - "result.failed == false"
- - "result.org.name == 'orgtest'"
+ - result.changed == false
+ - result.failed == false
+ - result.org.name == 'orgtest'
+ when: not ansible_check_mode
- name: Delete a Grafana organization
community.grafana.grafana_organization:
@@ -36,13 +39,15 @@
name: orgtest
state: absent
register: result
-- assert:
+
+- ansible.builtin.assert:
that:
- - "result.changed == true"
- - "result.failed == false"
- - "result.msg |length > 0"
+ - result.changed == true
+ - result.failed == false
+ - result.msg |length > 0
+ when: not ansible_check_mode
-- name: check idempotency delete a Grafana organization
+- name: Check idempotency delete a Grafana organization
community.grafana.grafana_organization:
url: "{{ grafana_url }}"
url_username: "{{ grafana_username }}"
@@ -50,8 +55,10 @@
name: orgtest
state: absent
register: result
-- assert:
+
+- ansible.builtin.assert:
that:
- - "result.changed == false"
- - "result.failed == false"
- - "result.msg == 'No org found, nothing to do'"
+ - result.changed == false
+ - result.failed == false
+ - result.msg == 'No org found, nothing to do'
+ when: not ansible_check_mode
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_organization_user/defaults/main.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_organization_user/defaults/main.yml
new file mode 100644
index 000000000..3edac8598
--- /dev/null
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_organization_user/defaults/main.yml
@@ -0,0 +1,4 @@
+---
+grafana_url: http://grafana:3000/
+grafana_username: admin
+grafana_password: admin
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_organization_user/runme.sh b/ansible_collections/community/grafana/tests/integration/targets/grafana_organization_user/runme.sh
new file mode 100755
index 000000000..9daa487db
--- /dev/null
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_organization_user/runme.sh
@@ -0,0 +1,6 @@
+#!/usr/bin/env bash
+
+set -eux
+
+ansible-playbook site.yml --check
+ansible-playbook site.yml
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_organization_user/site.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_organization_user/site.yml
new file mode 100644
index 000000000..80e5ea916
--- /dev/null
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_organization_user/site.yml
@@ -0,0 +1,6 @@
+---
+- name: Run tests for grafana_organization_user
+ hosts: localhost
+ tasks:
+ - ansible.builtin.include_role:
+ name: ../../grafana_organization_user
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_organization_user/tasks/main.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_organization_user/tasks/main.yml
new file mode 100644
index 000000000..73b0482ac
--- /dev/null
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_organization_user/tasks/main.yml
@@ -0,0 +1,172 @@
+---
+- name: Create test user (default org 1)
+ community.grafana.grafana_user:
+ url: "{{ grafana_url }}"
+ url_username: "{{ grafana_username }}"
+ url_password: "{{ grafana_password }}"
+ name: orgtest
+ email: orgtest@example.com
+ login: orgtest
+ password: userpassword
+ state: present
+ register: result
+
+- name: Remove user from organization (default org 1)
+ community.grafana.grafana_organization_user:
+ url: "{{ grafana_url }}"
+ url_username: "{{ grafana_username }}"
+ url_password: "{{ grafana_password }}"
+ login: orgtest
+ state: absent
+ register: result
+- ansible.builtin.assert:
+ that:
+ - result.failed == false
+ - result.changed == true
+ when: not ansible_check_mode
+
+- name: Check idempotency on user removal from org
+ community.grafana.grafana_organization_user:
+ url: "{{ grafana_url }}"
+ url_username: "{{ grafana_username }}"
+ url_password: "{{ grafana_password }}"
+ login: orgtest
+ state: absent
+ register: result
+- ansible.builtin.assert:
+ that:
+ - result.failed == false
+ - result.changed == false
+ when: not ansible_check_mode
+
+- name: Add user to organization
+ community.grafana.grafana_organization_user:
+ url: "{{ grafana_url }}"
+ url_username: "{{ grafana_username }}"
+ url_password: "{{ grafana_password }}"
+ login: orgtest
+ role: viewer
+ state: present
+ register: result
+- ansible.builtin.assert:
+ that:
+ - result.failed == false
+ - result.changed == true
+ - result.user.orgId == 1
+ - result.user.role == 'Viewer'
+ when: not ansible_check_mode
+
+- name: Update existing user role
+ community.grafana.grafana_organization_user:
+ url: "{{ grafana_url }}"
+ url_username: "{{ grafana_username }}"
+ url_password: "{{ grafana_password }}"
+ login: orgtest
+ role: editor
+ state: present
+ register: result
+- ansible.builtin.assert:
+ that:
+ - result.failed == false
+ - result.changed == true
+ - result.user.orgId == 1
+ - result.user.role == 'Editor'
+ when: not ansible_check_mode
+
+- name: Check idempotency on user update
+ community.grafana.grafana_organization_user:
+ url: "{{ grafana_url }}"
+ url_username: "{{ grafana_username }}"
+ url_password: "{{ grafana_password }}"
+ login: orgtest
+ role: editor
+ state: present
+ register: result
+- ansible.builtin.assert:
+ that:
+ - result.failed == false
+ - result.changed == false
+ when: not ansible_check_mode
+
+- name: Create a new organization
+ community.grafana.grafana_organization:
+ url: "{{ grafana_url }}"
+ url_username: "{{ grafana_username }}"
+ url_password: "{{ grafana_password }}"
+ name: neworgtest
+ state: present
+ register: org
+
+- name: Add user to the new organization by org_id
+ community.grafana.grafana_organization_user:
+ url: "{{ grafana_url }}"
+ url_username: "{{ grafana_username }}"
+ url_password: "{{ grafana_password }}"
+ org_id: "{{ org.org.id }}"
+ login: orgtest
+ role: admin
+ state: present
+ register: result
+ when: not ansible_check_mode
+
+- ansible.builtin.assert:
+ that:
+ - result.failed == false
+ - result.changed == true
+ - result.user.orgId == org.org.id
+ - result.user.role == 'Admin'
+ when: not ansible_check_mode
+
+- name: Remove user from new organization by org_id
+ community.grafana.grafana_organization_user:
+ url: "{{ grafana_url }}"
+ url_username: "{{ grafana_username }}"
+ url_password: "{{ grafana_password }}"
+ org_id: "{{ org.org.id }}"
+ login: orgtest
+ state: absent
+ register: result
+ when: not ansible_check_mode
+
+- ansible.builtin.assert:
+ that:
+ - result.failed == false
+ - result.changed == true
+ when: not ansible_check_mode
+
+- name: Add user to the new organization by org_name
+ community.grafana.grafana_organization_user:
+ url: "{{ grafana_url }}"
+ url_username: "{{ grafana_username }}"
+ url_password: "{{ grafana_password }}"
+ org_name: "{{ org.org.name }}"
+ login: orgtest
+ role: admin
+ state: present
+ register: result
+ when: not ansible_check_mode
+
+- ansible.builtin.assert:
+ that:
+ - result.failed == false
+ - result.changed == true
+ - result.user.orgId == org.org.id
+ - result.user.role == 'Admin'
+ when: not ansible_check_mode
+
+- name: Remove user from new organization by org_name
+ community.grafana.grafana_organization_user:
+ url: "{{ grafana_url }}"
+ url_username: "{{ grafana_username }}"
+ url_password: "{{ grafana_password }}"
+ org_name: "{{ org.org.name }}"
+ login: orgtest
+ state: absent
+ register: result
+ when: not ansible_check_mode
+
+- ansible.builtin.assert:
+ that:
+ - result.failed == false
+ - result.changed == true
+ when: not ansible_check_mode
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_team/defaults/main.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_team/defaults/main.yml
index 8b9c9348a..4abf9bb43 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_team/defaults/main.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_team/defaults/main.yml
@@ -1,7 +1,5 @@
---
-grafana_url: "http://grafana:3000/"
-grafana_username: "admin"
-grafana_password: "admin"
-
-...
+grafana_url: http://grafana:3000/
+grafana_username: admin
+grafana_password: admin
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_team/runme.sh b/ansible_collections/community/grafana/tests/integration/targets/grafana_team/runme.sh
new file mode 100755
index 000000000..867afb0d3
--- /dev/null
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_team/runme.sh
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+
+set -eux
+
+ansible-playbook site.yml
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_team/site.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_team/site.yml
new file mode 100644
index 000000000..c8a618891
--- /dev/null
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_team/site.yml
@@ -0,0 +1,6 @@
+---
+- name: Run tests for grafana_team
+ hosts: localhost
+ tasks:
+ - ansible.builtin.include_role:
+ name: ../../grafana_team
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_team/tasks/create_user.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_team/tasks/create_user.yml
index 6971d07b6..9641e7185 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_team/tasks/create_user.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_team/tasks/create_user.yml
@@ -1,29 +1,30 @@
+---
- name: Create John Doe for tests purpose through uri module
- uri:
+ ansible.builtin.uri:
url: "{{ grafana_url }}api/admin/users"
method: POST
user: "{{ grafana_username }}"
password: "{{ grafana_password }}"
- force_basic_auth: yes
+ force_basic_auth: true
body:
- name: "John"
- email: "john+doe@example.com"
- login: "john"
- password: "userpassword"
+ name: John
+ email: john+doe@example.com
+ login: john
+ password: userpassword
body_format: json
status_code: 200
- name: Create Jane Doe for tests purpose through uri module
- uri:
+ ansible.builtin.uri:
url: "{{ grafana_url }}api/admin/users"
method: POST
user: "{{ grafana_username }}"
password: "{{ grafana_password }}"
- force_basic_auth: yes
+ force_basic_auth: true
body:
- name: "Jane"
- email: "jane.doe@example.com"
- login: "jane"
- password: "userpassword"
+ name: Jane
+ email: jane.doe@example.com
+ login: jane
+ password: userpassword
body_format: json
status_code: 200
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_team/tasks/main.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_team/tasks/main.yml
index 2d74581b7..d43eb8286 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_team/tasks/main.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_team/tasks/main.yml
@@ -1,187 +1,198 @@
---
-
- name: Create a Team
- grafana_team:
- url: "{{ grafana_url }}"
- url_username: "{{ grafana_username }}"
- url_password: "{{ grafana_password }}"
- name: "grafana_working_group"
- email: "foo.bar@example.com"
- state: present
+ community.grafana.grafana_team:
+ url: "{{ grafana_url }}"
+ url_username: "{{ grafana_username }}"
+ url_password: "{{ grafana_password }}"
+ name: grafana working group
+ email: foo.bar@example.com
+ state: present
+ skip_version_check: true
register: result
-- set_fact:
+- ansible.builtin.set_fact:
# From Grafana 9.0.0, the API user automatically becomes a member of the team
auto_member: "{{ result.team.memberCount == 1 }}"
-- set_fact:
+- ansible.builtin.set_fact:
expected_members: "{{ auto_member | ternary(['********@localhost'], []) }}"
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == true"
- - "result.team.name == 'grafana_working_group'"
- - "result.team.email == 'foo.bar@example.com'"
- - "result.team.memberCount == (expected_members|length)"
- - "result.team.members == expected_members"
+ - result.changed == true
+ - result.team.name == 'grafana working group'
+ - result.team.email == 'foo.bar@example.com'
+ - result.team.memberCount == (expected_members|length)
+ - result.team.members == expected_members
+ when: not ansible_check_mode
- name: Check idempotency on team creation
- grafana_team:
- url: "{{ grafana_url }}"
- url_username: "{{ grafana_username }}"
- url_password: "{{ grafana_password }}"
- name: "grafana_working_group"
- email: "foo.bar@example.com"
- state: present
+ community.grafana.grafana_team:
+ url: "{{ grafana_url }}"
+ url_username: "{{ grafana_username }}"
+ url_password: "{{ grafana_password }}"
+ name: grafana working group
+ email: foo.bar@example.com
+ state: present
register: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == false"
- - "result.team.name == 'grafana_working_group'"
- - "result.team.email == 'foo.bar@example.com'"
- - "result.team.memberCount == (expected_members|length)"
- - "result.team.members == expected_members"
+ - result.changed == false
+ - result.team.name == 'grafana working group'
+ - result.team.email == 'foo.bar@example.com'
+ - result.team.memberCount == (expected_members|length)
+ - result.team.members == expected_members
+ when: not ansible_check_mode
- name: Check a team can be deleted
- grafana_team:
- url: "{{ grafana_url }}"
- url_username: "{{ grafana_username }}"
- url_password: "{{ grafana_password }}"
- name: "grafana_working_group"
- email: "foo.bar@example.com"
- state: absent
+ community.grafana.grafana_team:
+ url: "{{ grafana_url }}"
+ url_username: "{{ grafana_username }}"
+ url_password: "{{ grafana_password }}"
+ name: grafana working group
+ email: foo.bar@example.com
+ state: absent
register: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == true"
- - "result.message == 'Team deleted'"
+ - result.changed == true
+ - result.message == 'Team deleted'
+ when: not ansible_check_mode
- name: Check idempotency on team deletion
- grafana_team:
- url: "{{ grafana_url }}"
- url_username: "{{ grafana_username }}"
- url_password: "{{ grafana_password }}"
- name: "grafana_working_group"
- email: "foo.bar@example.com"
- state: absent
+ community.grafana.grafana_team:
+ url: "{{ grafana_url }}"
+ url_username: "{{ grafana_username }}"
+ url_password: "{{ grafana_password }}"
+ name: grafana working group
+ email: foo.bar@example.com
+ state: absent
register: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == false"
- - "result.message == 'No team found'"
+ - result.changed == false
+ - result.message == 'No team found'
+ when: not ansible_check_mode
- name: Create users for tests purpose
- import_tasks: create_user.yml
+ ansible.builtin.import_tasks:
+ file: create_user.yml
- name: Create a Team with members
- grafana_team:
- url: "{{ grafana_url }}"
- url_username: "{{ grafana_username }}"
- url_password: "{{ grafana_password }}"
- name: "grafana_working_group"
- email: "foo.bar@example.com"
- members:
- - "john+doe@example.com"
- - "jane.doe@example.com"
- state: present
+ community.grafana.grafana_team:
+ url: "{{ grafana_url }}"
+ url_username: "{{ grafana_username }}"
+ url_password: "{{ grafana_password }}"
+ name: grafana working group
+ email: foo.bar@example.com
+ members:
+ - john+doe@example.com
+ - jane.doe@example.com
+ state: present
register: result
-- set_fact:
- expected_members: "{{ auto_member | ternary(['********@localhost', 'jane.doe@example.com', 'john+doe@example.com'], ['jane.doe@example.com', 'john+doe@example.com']) }}"
+- ansible.builtin.set_fact:
+ expected_members: "{{ auto_member | ternary(['********@localhost', 'jane.doe@example.com', 'john+doe@example.com'], ['jane.doe@example.com', 'john+doe@example.com'])
+ }}"
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == true"
- - "result.team.name == 'grafana_working_group'"
- - "result.team.email == 'foo.bar@example.com'"
- - "result.team.memberCount == (expected_members|length)"
- - "result.team.members == expected_members"
+ - result.changed == true
+ - result.team.name == 'grafana working group'
+ - result.team.email == 'foo.bar@example.com'
+ - result.team.memberCount == (expected_members|length)
+ - result.team.members == expected_members
+ when: not ansible_check_mode
- name: Ensure a Team exists with member not enforced
- grafana_team:
- url: "{{ grafana_url }}"
- url_username: "{{ grafana_username }}"
- url_password: "{{ grafana_password }}"
- name: "grafana_working_group"
- email: "foo.bar@example.com"
- members:
- - "john+doe@example.com"
- state: present
+ community.grafana.grafana_team:
+ url: "{{ grafana_url }}"
+ url_username: "{{ grafana_username }}"
+ url_password: "{{ grafana_password }}"
+ name: grafana working group
+ email: foo.bar@example.com
+ members:
+ - john+doe@example.com
+ state: present
register: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == false"
- - "result.team.name == 'grafana_working_group'"
- - "result.team.email == 'foo.bar@example.com'"
- - "result.team.memberCount == (expected_members|length)"
- - "result.team.members == expected_members"
-
-- set_fact:
+ - result.changed == false
+ - result.team.name == 'grafana working group'
+ - result.team.email == 'foo.bar@example.com'
+ - result.team.memberCount == (expected_members|length)
+ - result.team.members == expected_members
+ when: not ansible_check_mode
+
+- ansible.builtin.set_fact:
enforced_members: "{{ auto_member | ternary(['admin@localhost', 'john+doe@example.com'], ['john+doe@example.com']) }}"
expected_members: "{{ auto_member | ternary(['********@localhost', 'john+doe@example.com'], ['john+doe@example.com']) }}"
- name: Ensure a Team exists with member enforced
- grafana_team:
- url: "{{ grafana_url }}"
- url_username: "{{ grafana_username }}"
- url_password: "{{ grafana_password }}"
- name: "grafana_working_group"
- email: "foo.bar@example.com"
- members: "{{ enforced_members }}"
- enforce_members: true
- state: present
+ community.grafana.grafana_team:
+ url: "{{ grafana_url }}"
+ url_username: "{{ grafana_username }}"
+ url_password: "{{ grafana_password }}"
+ name: grafana working group
+ email: foo.bar@example.com
+ members: "{{ enforced_members }}"
+ enforce_members: true
+ state: present
register: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == true"
- - "result.team.name == 'grafana_working_group'"
- - "result.team.email == 'foo.bar@example.com'"
- - "result.team.memberCount == (expected_members|length)"
- - "result.team.members == expected_members"
+ - result.changed == true
+ - result.team.name == 'grafana working group'
+ - result.team.email == 'foo.bar@example.com'
+ - result.team.memberCount == (expected_members|length)
+ - result.team.members == expected_members
- name: Ensure a Team exists with members omitted
- grafana_team:
- url: "{{ grafana_url }}"
- url_username: "{{ grafana_username }}"
- url_password: "{{ grafana_password }}"
- name: "grafana_working_group"
- email: "foo.bar@example.com"
- state: present
+ community.grafana.grafana_team:
+ url: "{{ grafana_url }}"
+ url_username: "{{ grafana_username }}"
+ url_password: "{{ grafana_password }}"
+ name: grafana working group
+ email: foo.bar@example.com
+ state: present
register: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == false"
- - "result.team.name == 'grafana_working_group'"
- - "result.team.email == 'foo.bar@example.com'"
- - "result.team.memberCount == (expected_members|length)"
- - "result.team.members == expected_members"
+ - result.changed == false
+ - result.team.name == 'grafana working group'
+ - result.team.email == 'foo.bar@example.com'
+ - result.team.memberCount == (expected_members|length)
+ - result.team.members == expected_members
+ when: not ansible_check_mode
- name: Add new member to existing Team
- grafana_team:
- url: "{{ grafana_url }}"
- url_username: "{{ grafana_username }}"
- url_password: "{{ grafana_password }}"
- name: "grafana_working_group"
- email: "foo.bar@example.com"
- members:
- - "john+doe@example.com"
- - "jane.doe@example.com"
- state: present
+ community.grafana.grafana_team:
+ url: "{{ grafana_url }}"
+ url_username: "{{ grafana_username }}"
+ url_password: "{{ grafana_password }}"
+ name: grafana working group
+ email: foo.bar@example.com
+ members:
+ - john+doe@example.com
+ - jane.doe@example.com
+ state: present
register: result
-- set_fact:
- expected_members: "{{ auto_member | ternary(['********@localhost', 'jane.doe@example.com', 'john+doe@example.com'], ['jane.doe@example.com', 'john+doe@example.com']) }}"
+- ansible.builtin.set_fact:
+ expected_members: "{{ auto_member | ternary(['********@localhost', 'jane.doe@example.com', 'john+doe@example.com'], ['jane.doe@example.com', 'john+doe@example.com'])
+ }}"
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == true"
- - "result.team.name == 'grafana_working_group'"
- - "result.team.email == 'foo.bar@example.com'"
- - "result.team.memberCount == (expected_members|length)"
- - "result.team.members == expected_members"
+ - result.changed == true
+ - result.team.name == 'grafana working group'
+ - result.team.email == 'foo.bar@example.com'
+ - result.team.memberCount == (expected_members|length)
+ - result.team.members == expected_members
+ when: not ansible_check_mode
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_user/defaults/main.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_user/defaults/main.yml
index 7bb77ea3f..3edac8598 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_user/defaults/main.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_user/defaults/main.yml
@@ -1,4 +1,4 @@
---
-grafana_url: "http://grafana:3000/"
-grafana_username: "admin"
-grafana_password: "admin"
+grafana_url: http://grafana:3000/
+grafana_username: admin
+grafana_password: admin
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_user/runme.sh b/ansible_collections/community/grafana/tests/integration/targets/grafana_user/runme.sh
new file mode 100755
index 000000000..9daa487db
--- /dev/null
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_user/runme.sh
@@ -0,0 +1,6 @@
+#!/usr/bin/env bash
+
+set -eux
+
+ansible-playbook site.yml --check
+ansible-playbook site.yml
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_user/site.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_user/site.yml
new file mode 100644
index 000000000..b080803f8
--- /dev/null
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_user/site.yml
@@ -0,0 +1,6 @@
+---
+- name: Run tests for grafana_user
+ hosts: localhost
+ tasks:
+ - ansible.builtin.include_role:
+ name: ../../grafana_user
diff --git a/ansible_collections/community/grafana/tests/integration/targets/grafana_user/tasks/main.yml b/ansible_collections/community/grafana/tests/integration/targets/grafana_user/tasks/main.yml
index c62801653..83a3891e1 100644
--- a/ansible_collections/community/grafana/tests/integration/targets/grafana_user/tasks/main.yml
+++ b/ansible_collections/community/grafana/tests/integration/targets/grafana_user/tasks/main.yml
@@ -1,237 +1,251 @@
---
- name: Create new admin
- grafana_user:
+ community.grafana.grafana_user:
url: "{{ grafana_url }}"
url_username: "{{ grafana_username }}"
url_password: "{{ grafana_password }}"
- name: "Harley Quinn"
+ name: Harley Quinn
email: harley.quinn@gotham.city
login: harley
password: Wy3ta6ob6M3wHELv58MPfqOe126RTnWpcYfEhyJm
is_admin: true
state: present
register: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == true"
- - "result.failed == false"
- - "result.user.name == 'Harley Quinn'"
- - "result.user.email == 'harley.quinn@gotham.city'"
- - "result.user.isGrafanaAdmin == true"
+ - result.changed == true
+ - result.failed == false
+ - result.user.name == 'Harley Quinn'
+ - result.user.email == 'harley.quinn@gotham.city'
+ - result.user.isGrafanaAdmin == true
+ when: not ansible_check_mode
- name: Check idempotency on admin creation
- grafana_user:
+ community.grafana.grafana_user:
url: "{{ grafana_url }}"
url_username: "{{ grafana_username }}"
url_password: "{{ grafana_password }}"
- name: "Harley Quinn"
+ name: Harley Quinn
email: harley.quinn@gotham.city
login: harley
password: Wy3ta6ob6M3wHELv58MPfqOe126RTnWpcYfEhyJm
is_admin: true
state: present
register: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == false"
- - "result.user.name == 'Harley Quinn'"
- - "result.user.email == 'harley.quinn@gotham.city'"
- - "result.user.isGrafanaAdmin == true"
+ - result.changed == false
+ - result.user.name == 'Harley Quinn'
+ - result.user.email == 'harley.quinn@gotham.city'
+ - result.user.isGrafanaAdmin == true
+ when: not ansible_check_mode
- name: Check user creation with Grafana API
- uri:
+ ansible.builtin.uri:
url: "{{ grafana_url }}api/users/lookup?loginOrEmail=harley"
user: "{{ grafana_username }}"
password: "{{ grafana_password }}"
- force_basic_auth: yes
+ force_basic_auth: true
status_code: 200
headers:
Accept: application/json
Content-Type: application/json
register: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.json.name == 'Harley Quinn'"
- - "result.json.email == 'harley.quinn@gotham.city'"
- - "result.json.isGrafanaAdmin == true"
+ - result.json.name == 'Harley Quinn'
+ - result.json.email == 'harley.quinn@gotham.city'
+ - result.json.isGrafanaAdmin == true
+ when: not ansible_check_mode
- name: Create a Grafana user without password (expect failure)
- grafana_user:
+ community.grafana.grafana_user:
url: "{{ grafana_url }}"
url_username: "{{ grafana_username }}"
url_password: "{{ grafana_password }}"
- name: "Bruce Wayne"
+ name: Bruce Wayne
email: batman@gotham.city
login: batman
state: present
register: result
- ignore_errors: yes
-- assert:
+ ignore_errors: true
+- ansible.builtin.assert:
that:
- - "result.changed == false"
- - "result.failed == true"
+ - result.changed == false
+ - result.failed == true
- "result.msg == 'missing required arguments: password'"
+ when: not ansible_check_mode
- name: Create a Grafana user
- grafana_user:
+ community.grafana.grafana_user:
url: "{{ grafana_url }}"
url_username: "{{ grafana_username }}"
url_password: "{{ grafana_password }}"
- name: "Bruce Wayne"
+ name: Bruce Wayne
email: batman@gotham.city
login: batman
password: robin
state: present
register: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == true"
- - "result.user.name == 'Bruce Wayne'"
- - "result.user.email == 'batman@gotham.city'"
- - "result.user.isGrafanaAdmin == false"
+ - result.changed == true
+ - result.user.name == 'Bruce Wayne'
+ - result.user.email == 'batman@gotham.city'
+ - result.user.isGrafanaAdmin == false
+ when: not ansible_check_mode
- name: Check idempotency on user creation (password not requiered)
- grafana_user:
+ community.grafana.grafana_user:
url: "{{ grafana_url }}"
url_username: "{{ grafana_username }}"
url_password: "{{ grafana_password }}"
- name: "Bruce Wayne"
+ name: Bruce Wayne
email: batman@gotham.city
login: batman
state: present
register: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == false"
- - "result.user.name == 'Bruce Wayne'"
- - "result.user.email == 'batman@gotham.city'"
- - "result.user.isGrafanaAdmin == false"
+ - result.changed == false
+ - result.user.name == 'Bruce Wayne'
+ - result.user.email == 'batman@gotham.city'
+ - result.user.isGrafanaAdmin == false
+ when: not ansible_check_mode
- name: Check user creation with Grafana API
- uri:
+ ansible.builtin.uri:
url: "{{ grafana_url }}api/users/lookup?loginOrEmail=batman"
user: "{{ grafana_username }}"
password: "{{ grafana_password }}"
- force_basic_auth: yes
+ force_basic_auth: true
status_code: 200
headers:
Accept: application/json
Content-Type: application/json
register: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.json.name == 'Bruce Wayne'"
- - "result.json.email == 'batman@gotham.city'"
- - "result.json.isGrafanaAdmin == false"
+ - result.json.name == 'Bruce Wayne'
+ - result.json.email == 'batman@gotham.city'
+ - result.json.isGrafanaAdmin == false
+ when: not ansible_check_mode
- name: Update Grafana user
- grafana_user:
+ community.grafana.grafana_user:
url: "{{ grafana_url }}"
url_username: "{{ grafana_username }}"
url_password: "{{ grafana_password }}"
- name: "The Dark Knight"
+ name: The Dark Knight
email: thedarkknight@gotham.city
login: batman
password: robin
is_admin: true
state: present
register: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == true"
- - "result.user.name == 'The Dark Knight'"
- - "result.user.email == 'thedarkknight@gotham.city'"
- - "result.user.isGrafanaAdmin == true"
+ - result.changed == true
+ - result.user.name == 'The Dark Knight'
+ - result.user.email == 'thedarkknight@gotham.city'
+ - result.user.isGrafanaAdmin == true
+ when: not ansible_check_mode
- name: Check user update with Grafana API
- uri:
+ ansible.builtin.uri:
url: "{{ grafana_url }}api/users/lookup?loginOrEmail=batman"
user: "{{ grafana_username }}"
password: "{{ grafana_password }}"
- force_basic_auth: yes
+ force_basic_auth: true
status_code: 200
headers:
Accept: application/json
Content-Type: application/json
register: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.json.name == 'The Dark Knight'"
- - "result.json.email == 'thedarkknight@gotham.city'"
- - "result.json.isGrafanaAdmin == true"
+ - result.json.name == 'The Dark Knight'
+ - result.json.email == 'thedarkknight@gotham.city'
+ - result.json.isGrafanaAdmin == true
+ when: not ansible_check_mode
- name: Delete a Grafana user
- grafana_user:
+ community.grafana.grafana_user:
url: "{{ grafana_url }}"
url_username: "{{ grafana_username }}"
url_password: "{{ grafana_password }}"
login: batman
state: absent
register: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == true"
- - "result.message == 'User deleted'"
+ - result.changed == true
+ - result.message == 'User deleted'
+ when: not ansible_check_mode
- name: Check idempotency on user deletion
- grafana_user:
+ community.grafana.grafana_user:
url: "{{ grafana_url }}"
url_username: "{{ grafana_username }}"
url_password: "{{ grafana_password }}"
login: batman
state: absent
register: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == false"
- - "result.message == 'No user found, nothing to do'"
+ - result.changed == false
+ - result.message == 'No user found, nothing to do'
+ when: not ansible_check_mode
- name: Check user deletion with Grafana API (expect 404 Not Found)
- uri:
+ ansible.builtin.uri:
url: "{{ grafana_url }}api/users/lookup?loginOrEmail=batman"
user: "{{ grafana_username }}"
password: "{{ grafana_password }}"
- force_basic_auth: yes
+ force_basic_auth: true
status_code: 404
headers:
Accept: application/json
Content-Type: application/json
register: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.json.message | lower == 'user not found'"
+ - result.json.message | lower == 'user not found'
+ when: not ansible_check_mode
- name: Create a Grafana user with character encoding
- grafana_user:
+ community.grafana.grafana_user:
url: "{{ grafana_url }}"
url_username: "{{ grafana_username }}"
url_password: "{{ grafana_password }}"
- name: "Bruce Wayne"
+ name: Bruce Wayne
email: bruce+wayne@gotham.city
login: bruce+wayne@gotham.city
password: robin
state: present
register: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == true"
- - "result.user.name == 'Bruce Wayne'"
- - "result.user.email == 'bruce+wayne@gotham.city'"
- - "result.user.isGrafanaAdmin == false"
+ - result.changed == true
+ - result.user.name == 'Bruce Wayne'
+ - result.user.email == 'bruce+wayne@gotham.city'
+ - result.user.isGrafanaAdmin == false
+ when: not ansible_check_mode
- name: Check idempotency on user creation (password not requiered)
- grafana_user:
+ community.grafana.grafana_user:
url: "{{ grafana_url }}"
url_username: "{{ grafana_username }}"
url_password: "{{ grafana_password }}"
- name: "Bruce Wayne"
+ name: Bruce Wayne
email: bruce+wayne@gotham.city
login: bruce+wayne@gotham.city
state: present
register: result
-- assert:
+- ansible.builtin.assert:
that:
- - "result.changed == false"
- - "result.user.name == 'Bruce Wayne'"
- - "result.user.email == 'bruce+wayne@gotham.city'"
- - "result.user.isGrafanaAdmin == false"
+ - result.changed == false
+ - result.user.name == 'Bruce Wayne'
+ - result.user.email == 'bruce+wayne@gotham.city'
+ - result.user.isGrafanaAdmin == false
+ when: not ansible_check_mode
diff --git a/ansible_collections/community/grafana/tests/requirements.yml b/ansible_collections/community/grafana/tests/requirements.yml
new file mode 100644
index 000000000..b9d14e2c3
--- /dev/null
+++ b/ansible_collections/community/grafana/tests/requirements.yml
@@ -0,0 +1,3 @@
+collections:
+ - name: community.grafana
+ version: 1.5.3
diff --git a/ansible_collections/community/grafana/tests/sanity/ignore-2.16.txt b/ansible_collections/community/grafana/tests/sanity/ignore-2.16.txt
new file mode 100644
index 000000000..5c82494f9
--- /dev/null
+++ b/ansible_collections/community/grafana/tests/sanity/ignore-2.16.txt
@@ -0,0 +1,4 @@
+plugins/modules/grafana_dashboard.py validate-modules:invalid-argument-name
+tests/unit/modules/grafana/grafana_plugin/test_grafana_plugin.py pep8:W291
+hacking/check_fragment.sh shebang
+hacking/find_grafana_versions.py shebang
diff --git a/ansible_collections/community/grafana/tests/sanity/ignore-2.17.txt b/ansible_collections/community/grafana/tests/sanity/ignore-2.17.txt
new file mode 100644
index 000000000..5c82494f9
--- /dev/null
+++ b/ansible_collections/community/grafana/tests/sanity/ignore-2.17.txt
@@ -0,0 +1,4 @@
+plugins/modules/grafana_dashboard.py validate-modules:invalid-argument-name
+tests/unit/modules/grafana/grafana_plugin/test_grafana_plugin.py pep8:W291
+hacking/check_fragment.sh shebang
+hacking/find_grafana_versions.py shebang
diff --git a/ansible_collections/community/grafana/tests/unit/modules/grafana/grafana_datasource/test_grafana_datasource.py b/ansible_collections/community/grafana/tests/unit/modules/grafana/grafana_datasource/test_grafana_datasource.py
index d2fba0fe1..ff8e4f242 100644
--- a/ansible_collections/community/grafana/tests/unit/modules/grafana/grafana_datasource/test_grafana_datasource.py
+++ b/ansible_collections/community/grafana/tests/unit/modules/grafana/grafana_datasource/test_grafana_datasource.py
@@ -1,7 +1,7 @@
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import, division, print_function
from unittest import TestCase
-from unittest.mock import call, patch, MagicMock
+from unittest.mock import patch
from ansible_collections.community.grafana.plugins.modules import grafana_datasource
from ansible.module_utils._text import to_bytes
from ansible.module_utils import basic
@@ -13,200 +13,207 @@ __metaclass__ = type
def set_module_args(args):
"""prepare arguments so that they will be picked up during module creation"""
- args = json.dumps({'ANSIBLE_MODULE_ARGS': args})
+ args = json.dumps({"ANSIBLE_MODULE_ARGS": args})
basic._ANSIBLE_ARGS = to_bytes(args)
def exit_json(*args, **kwargs):
"""function to patch over exit_json; package return data into an exception"""
- if 'changed' not in kwargs:
- kwargs['changed'] = False
+ if "changed" not in kwargs:
+ kwargs["changed"] = False
raise AnsibleExitJson(kwargs)
def fail_json(*args, **kwargs):
"""function to patch over fail_json; package return data into an exception"""
- kwargs['failed'] = True
+ kwargs["failed"] = True
raise AnsibleFailJson(kwargs)
class AnsibleExitJson(Exception):
"""Exception class to be raised by module.exit_json and caught by the test case"""
+
pass
class AnsibleFailJson(Exception):
"""Exception class to be raised by module.fail_json and caught by the test case"""
+
pass
class GrafanaDatasource(TestCase):
-
def setUp(self):
self.authorization = basic_auth_header("admin", "admin")
- self.mock_module_helper = patch.multiple(basic.AnsibleModule,
- exit_json=exit_json,
- fail_json=fail_json)
+ self.mock_module_helper = patch.multiple(
+ basic.AnsibleModule, exit_json=exit_json, fail_json=fail_json
+ )
self.mock_module_helper.start()
self.addCleanup(self.mock_module_helper.stop)
def test_payload_prometheus(self):
expected_payload = {
- 'access': 'proxy',
- 'basicAuth': False,
- 'database': '',
- 'isDefault': False,
- 'jsonData': {
- 'tlsAuth': False,
- 'tlsAuthWithCACert': False,
- 'tlsSkipVerify': True
+ "access": "proxy",
+ "basicAuth": False,
+ "database": "",
+ "isDefault": False,
+ "jsonData": {
+ "tlsAuth": False,
+ "tlsAuthWithCACert": False,
+ "tlsSkipVerify": True,
},
- 'name': 'openshift_prometheus',
- 'uid': 'xyz123',
- 'orgId': 1,
- 'secureJsonData': {},
- 'type': 'prometheus',
- 'url': 'https://openshift-monitoring.company.com',
- 'user': '',
- 'withCredentials': False
+ "name": "openshift_prometheus",
+ "uid": "xyz123",
+ "orgId": 1,
+ "secureJsonData": {},
+ "type": "prometheus",
+ "url": "https://openshift-monitoring.company.com",
+ "user": "",
+ "withCredentials": False,
}
- set_module_args({
- 'url': 'https://grafana.example.com',
- 'url_username': 'admin',
- 'url_password': 'admin',
- 'name': 'openshift_prometheus',
- 'uid': 'xyz123',
- 'ds_type': 'prometheus',
- 'ds_url': 'https://openshift-monitoring.company.com',
- 'access': 'proxy',
- 'tls_skip_verify': 'true',
- })
+ set_module_args(
+ {
+ "url": "https://grafana.example.com",
+ "url_username": "admin",
+ "url_password": "admin",
+ "name": "openshift_prometheus",
+ "uid": "xyz123",
+ "ds_type": "prometheus",
+ "ds_url": "https://openshift-monitoring.company.com",
+ "access": "proxy",
+ "tls_skip_verify": "true",
+ }
+ )
module = grafana_datasource.setup_module_object()
payload = grafana_datasource.get_datasource_payload(module.params)
self.assertEqual(payload, expected_payload)
def test_payload_prometheus_with_basic_auth(self):
expected_payload = {
- 'access': 'proxy',
- 'basicAuth': True,
- 'basicAuthUser': 'admin',
- 'database': '',
- 'isDefault': False,
- 'jsonData': {
- 'tlsAuth': False,
- 'tlsAuthWithCACert': False,
- 'tlsSkipVerify': True
+ "access": "proxy",
+ "basicAuth": True,
+ "basicAuthUser": "admin",
+ "database": "",
+ "isDefault": False,
+ "jsonData": {
+ "tlsAuth": False,
+ "tlsAuthWithCACert": False,
+ "tlsSkipVerify": True,
},
- 'name': 'openshift_prometheus',
- 'uid': 'xyz123',
- 'orgId': 1,
- 'secureJsonData': {'basicAuthPassword': 'admin'},
- 'type': 'prometheus',
- 'url': 'https://openshift-monitoring.company.com',
- 'user': '',
- 'withCredentials': False
+ "name": "openshift_prometheus",
+ "uid": "xyz123",
+ "orgId": 1,
+ "secureJsonData": {"basicAuthPassword": "admin"},
+ "type": "prometheus",
+ "url": "https://openshift-monitoring.company.com",
+ "user": "",
+ "withCredentials": False,
}
- set_module_args({
- 'url': 'https://grafana.example.com',
- 'url_username': 'admin',
- 'url_password': 'admin',
- 'name': 'openshift_prometheus',
- 'uid': 'xyz123',
- 'ds_type': 'prometheus',
- 'ds_url': 'https://openshift-monitoring.company.com',
- 'access': 'proxy',
- 'basic_auth_user': 'admin',
- 'basic_auth_password': 'admin',
- 'tls_skip_verify': 'true',
- })
+ set_module_args(
+ {
+ "url": "https://grafana.example.com",
+ "url_username": "admin",
+ "url_password": "admin",
+ "name": "openshift_prometheus",
+ "uid": "xyz123",
+ "ds_type": "prometheus",
+ "ds_url": "https://openshift-monitoring.company.com",
+ "access": "proxy",
+ "basic_auth_user": "admin",
+ "basic_auth_password": "admin",
+ "tls_skip_verify": "true",
+ }
+ )
module = grafana_datasource.setup_module_object()
payload = grafana_datasource.get_datasource_payload(module.params)
self.assertEqual(payload, expected_payload)
def test_payload_influxdb(self):
expected_payload = {
- 'access': 'proxy',
- 'basicAuth': False,
- 'database': 'telegraf',
- 'isDefault': False,
- 'jsonData': {
- 'timeInterval': '>10s',
- 'tlsAuth': False,
- 'tlsAuthWithCACert': True
- },
- 'name': 'datasource-influxdb',
- 'uid': 'xyz123',
- 'orgId': 1,
- 'secureJsonData': {
- 'tlsCACert': '/etc/ssl/certs/ca.pem'
+ "access": "proxy",
+ "basicAuth": False,
+ "database": "telegraf",
+ "isDefault": False,
+ "jsonData": {
+ "timeInterval": ">10s",
+ "tlsAuth": False,
+ "tlsAuthWithCACert": True,
},
- 'type': 'influxdb',
- 'url': 'https://influx.company.com:8086',
- 'user': '',
- 'withCredentials': False
+ "name": "datasource-influxdb",
+ "uid": "xyz123",
+ "orgId": 1,
+ "secureJsonData": {"tlsCACert": "/etc/ssl/certs/ca.pem"},
+ "type": "influxdb",
+ "url": "https://influx.company.com:8086",
+ "user": "",
+ "withCredentials": False,
}
- set_module_args({
- 'url': 'https://grafana.example.com',
- 'url_username': 'admin',
- 'url_password': 'admin',
- 'name': 'datasource-influxdb',
- 'uid': 'xyz123',
- 'ds_type': 'influxdb',
- 'ds_url': 'https://influx.company.com:8086',
- 'database': 'telegraf',
- 'time_interval': '>10s',
- 'tls_ca_cert': '/etc/ssl/certs/ca.pem'
- })
+ set_module_args(
+ {
+ "url": "https://grafana.example.com",
+ "url_username": "admin",
+ "url_password": "admin",
+ "name": "datasource-influxdb",
+ "uid": "xyz123",
+ "ds_type": "influxdb",
+ "ds_url": "https://influx.company.com:8086",
+ "database": "telegraf",
+ "time_interval": ">10s",
+ "tls_ca_cert": "/etc/ssl/certs/ca.pem",
+ }
+ )
module = grafana_datasource.setup_module_object()
payload = grafana_datasource.get_datasource_payload(module.params)
self.assertEqual(payload, expected_payload)
def test_payload_elastic(self):
expected_payload = {
- 'access': 'proxy',
- 'basicAuth': True,
- 'basicAuthUser': 'grafana',
- 'database': '[logstash_]YYYY.MM.DD',
- 'isDefault': False,
- 'jsonData': {
- 'esVersion': 56,
- 'interval': 'Daily',
- 'maxConcurrentShardRequests': 42,
- 'timeField': '@timestamp',
- 'timeInterval': '1m',
- 'tlsAuth': False,
- 'tlsAuthWithCACert': True
+ "access": "proxy",
+ "basicAuth": True,
+ "basicAuthUser": "grafana",
+ "database": "[logstash_]YYYY.MM.DD",
+ "isDefault": False,
+ "jsonData": {
+ "esVersion": 56,
+ "interval": "Daily",
+ "maxConcurrentShardRequests": 42,
+ "timeField": "@timestamp",
+ "timeInterval": "1m",
+ "tlsAuth": False,
+ "tlsAuthWithCACert": True,
},
- 'name': 'datasource-elastic',
- 'uid': 'xyz123',
- 'orgId': 1,
- 'secureJsonData': {
- 'basicAuthPassword': 'grafana',
- 'tlsCACert': '/etc/ssl/certs/ca.pem'
+ "name": "datasource-elastic",
+ "uid": "xyz123",
+ "orgId": 1,
+ "secureJsonData": {
+ "basicAuthPassword": "grafana",
+ "tlsCACert": "/etc/ssl/certs/ca.pem",
},
- 'type': 'elasticsearch',
- 'url': 'https://elastic.company.com:9200',
- 'user': '',
- 'withCredentials': False
+ "type": "elasticsearch",
+ "url": "https://elastic.company.com:9200",
+ "user": "",
+ "withCredentials": False,
}
- set_module_args({
- 'url': 'https://grafana.example.com',
- 'url_username': 'admin',
- 'url_password': 'admin',
- 'name': 'datasource-elastic',
- 'uid': 'xyz123',
- 'ds_type': 'elasticsearch',
- 'ds_url': 'https://elastic.company.com:9200',
- 'database': '[logstash_]YYYY.MM.DD',
- 'basic_auth_user': 'grafana',
- 'basic_auth_password': 'grafana',
- 'time_field': '@timestamp',
- 'time_interval': '1m',
- 'interval': 'Daily',
- 'es_version': 56,
- 'max_concurrent_shard_requests': 42,
- 'tls_ca_cert': '/etc/ssl/certs/ca.pem'
- })
+ set_module_args(
+ {
+ "url": "https://grafana.example.com",
+ "url_username": "admin",
+ "url_password": "admin",
+ "name": "datasource-elastic",
+ "uid": "xyz123",
+ "ds_type": "elasticsearch",
+ "ds_url": "https://elastic.company.com:9200",
+ "database": "[logstash_]YYYY.MM.DD",
+ "basic_auth_user": "grafana",
+ "basic_auth_password": "grafana",
+ "time_field": "@timestamp",
+ "time_interval": "1m",
+ "interval": "Daily",
+ "es_version": 56,
+ "max_concurrent_shard_requests": 42,
+ "tls_ca_cert": "/etc/ssl/certs/ca.pem",
+ }
+ )
module = grafana_datasource.setup_module_object()
payload = grafana_datasource.get_datasource_payload(module.params)
self.assertEqual(payload, expected_payload)
diff --git a/ansible_collections/community/grafana/tests/unit/modules/grafana/grafana_plugin/test_grafana_plugin.py b/ansible_collections/community/grafana/tests/unit/modules/grafana/grafana_plugin/test_grafana_plugin.py
index b3b025c4e..ec691a467 100644
--- a/ansible_collections/community/grafana/tests/unit/modules/grafana/grafana_plugin/test_grafana_plugin.py
+++ b/ansible_collections/community/grafana/tests/unit/modules/grafana/grafana_plugin/test_grafana_plugin.py
@@ -1,4 +1,4 @@
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import, division, print_function
from unittest import TestCase
from unittest.mock import patch, MagicMock
@@ -53,14 +53,13 @@ Error: ✗ plugin does not exist
class GrafanaPlugin(TestCase):
-
- @patch('ansible_collections.community.grafana.plugins.modules.grafana_plugin.grafana_cli_bin')
+ @patch(
+ "ansible_collections.community.grafana.plugins.modules.grafana_plugin.grafana_cli_bin"
+ )
def test_plugin_install_zip(self, mock_grafana_cli_bin):
mock_grafana_cli_bin.return_value = "grafana-cli plugins"
- params = {
- "name": "alexanderzobnin-zabbix-app"
- }
+ params = {"name": "alexanderzobnin-zabbix-app"}
module = MagicMock()
module.run_command.return_value = run_command_install_zip()
@@ -68,13 +67,13 @@ class GrafanaPlugin(TestCase):
result = grafana_plugin.get_grafana_plugin_version(module, params)
self.assertEqual(result, None)
- @patch('ansible_collections.community.grafana.plugins.modules.grafana_plugin.grafana_cli_bin')
+ @patch(
+ "ansible_collections.community.grafana.plugins.modules.grafana_plugin.grafana_cli_bin"
+ )
def test_plugin_ls(self, mock_grafana_cli_bin):
mock_grafana_cli_bin.return_value = "grafana-cli plugins"
- params = {
- "name": "alexanderzobnin-zabbix-app"
- }
+ params = {"name": "alexanderzobnin-zabbix-app"}
module = MagicMock()
module.run_command.return_value = run_command_ls()
@@ -82,13 +81,13 @@ class GrafanaPlugin(TestCase):
result = grafana_plugin.get_grafana_plugin_version(module, params)
self.assertEqual(result, "3.10.5")
- @patch('ansible_collections.community.grafana.plugins.modules.grafana_plugin.grafana_cli_bin')
+ @patch(
+ "ansible_collections.community.grafana.plugins.modules.grafana_plugin.grafana_cli_bin"
+ )
def test_plugin_uninstall(self, mock_grafana_cli_bin):
mock_grafana_cli_bin.return_value = "grafana-cli plugins"
- params = {
- "name": "alexanderzobnin-zabbix-app"
- }
+ params = {"name": "alexanderzobnin-zabbix-app"}
module = MagicMock()
module.run_command.return_value = run_command_uninstall()
@@ -96,13 +95,13 @@ class GrafanaPlugin(TestCase):
result = grafana_plugin.get_grafana_plugin_version(module, params)
self.assertEqual(result, None)
- @patch('ansible_collections.community.grafana.plugins.modules.grafana_plugin.grafana_cli_bin')
+ @patch(
+ "ansible_collections.community.grafana.plugins.modules.grafana_plugin.grafana_cli_bin"
+ )
def test_plugin_uninstall_again(self, mock_grafana_cli_bin):
mock_grafana_cli_bin.return_value = "grafana-cli plugins"
- params = {
- "name": "alexanderzobnin-zabbix-app"
- }
+ params = {"name": "alexanderzobnin-zabbix-app"}
module = MagicMock()
module.run_command.return_value = run_command_uninstall_again()
diff --git a/ansible_collections/community/grafana/tests/unit/modules/grafana/grafana_team/test_grafana_team.py b/ansible_collections/community/grafana/tests/unit/modules/grafana/grafana_team/test_grafana_team.py
index c59953afa..8efba998b 100644
--- a/ansible_collections/community/grafana/tests/unit/modules/grafana/grafana_team/test_grafana_team.py
+++ b/ansible_collections/community/grafana/tests/unit/modules/grafana/grafana_team/test_grafana_team.py
@@ -1,7 +1,7 @@
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import, division, print_function
from unittest import TestCase
-from unittest.mock import patch, MagicMock
+from unittest.mock import patch
from ansible_collections.community.grafana.plugins.modules import grafana_team
from ansible.module_utils._text import to_bytes
from ansible.module_utils import basic
@@ -21,30 +21,32 @@ class MockedReponse(object):
def exit_json(*args, **kwargs):
"""function to patch over exit_json; package return data into an exception"""
- if 'changed' not in kwargs:
- kwargs['changed'] = False
+ if "changed" not in kwargs:
+ kwargs["changed"] = False
raise AnsibleExitJson(kwargs)
def fail_json(*args, **kwargs):
"""function to patch over fail_json; package return data into an exception"""
- kwargs['failed'] = True
+ kwargs["failed"] = True
raise AnsibleFailJson(kwargs)
class AnsibleExitJson(Exception):
"""Exception class to be raised by module.exit_json and caught by the test case"""
+
pass
class AnsibleFailJson(Exception):
"""Exception class to be raised by module.fail_json and caught by the test case"""
+
pass
def set_module_args(args):
"""prepare arguments so that they will be picked up during module creation"""
- args = json.dumps({'ANSIBLE_MODULE_ARGS': args})
+ args = json.dumps({"ANSIBLE_MODULE_ARGS": args})
basic._ANSIBLE_ARGS = to_bytes(args)
@@ -65,7 +67,10 @@ def get_low_version_resp():
def team_exists_resp():
- server_response = json.dumps({"totalCount": 1, "teams": [{"name": "MyTestTeam", "email": "email@test.com"}]}, sort_keys=True)
+ server_response = json.dumps(
+ {"totalCount": 1, "teams": [{"name": "MyTestTeam", "email": "email@test.com"}]},
+ sort_keys=True,
+ )
return (MockedReponse(server_response), {"status": 200})
@@ -90,21 +95,26 @@ def team_deleted_resp():
def team_members_resp():
- server_response = json.dumps([{
- "orgId": 1,
- "teamId": 2,
- "userId": 3,
- "email": "user1@email.com",
- "login": "user1",
- "avatarUrl": r"\/avatar\/1b3c32f6386b0185c40d359cdc733a79"
- }, {
- "orgId": 1,
- "teamId": 2,
- "userId": 2,
- "email": "user2@email.com",
- "login": "user2",
- "avatarUrl": r"\/avatar\/cad3c68da76e45d10269e8ef02f8e73e"
- }])
+ server_response = json.dumps(
+ [
+ {
+ "orgId": 1,
+ "teamId": 2,
+ "userId": 3,
+ "email": "user1@email.com",
+ "login": "user1",
+ "avatarUrl": r"\/avatar\/1b3c32f6386b0185c40d359cdc733a79",
+ },
+ {
+ "orgId": 1,
+ "teamId": 2,
+ "userId": 2,
+ "email": "user2@email.com",
+ "login": "user2",
+ "avatarUrl": r"\/avatar\/cad3c68da76e45d10269e8ef02f8e73e",
+ },
+ ]
+ )
return (MockedReponse(server_response), {"status": 200})
@@ -124,12 +134,11 @@ def delete_team_member_resp():
class GrafanaTeamsTest(TestCase):
-
def setUp(self):
self.authorization = basic_auth_header("admin", "admin")
- self.mock_module_helper = patch.multiple(basic.AnsibleModule,
- exit_json=exit_json,
- fail_json=fail_json)
+ self.mock_module_helper = patch.multiple(
+ basic.AnsibleModule, exit_json=exit_json, fail_json=fail_json
+ )
self.mock_module_helper.start()
self.addCleanup(self.mock_module_helper.stop)
@@ -139,112 +148,148 @@ class GrafanaTeamsTest(TestCase):
with self.assertRaises(AnsibleFailJson) as result:
grafana_team.main()
- err, arg_list = result.exception.args[0]['msg'].split(':')
- missing_args = [item.strip() for item in arg_list.split(',')]
- self.assertEqual(err, 'missing required arguments')
+ err, arg_list = result.exception.args[0]["msg"].split(":")
+ self.assertEqual(err, "missing required arguments")
self.assertEqual(arg_list, ["name", "email", "url"])
def test_module_setup_fails_without_name(self):
- set_module_args({
- 'email': 'email@test.com',
- 'url': 'http://grafana.example.com'
- })
+ set_module_args(
+ {"email": "email@test.com", "url": "http://grafana.example.com"}
+ )
with self.assertRaises(AnsibleFailJson) as result:
grafana_team.main()
- self.assertEqual(result.exception.args[0]['msg'], 'missing required arguments: name')
+ self.assertEqual(
+ result.exception.args[0]["msg"], "missing required arguments: name"
+ )
def test_module_setup_fails_without_email(self):
- set_module_args({
- 'name': 'MyTestTeam',
- 'url': 'http://grafana.example.com'
- })
+ set_module_args({"name": "MyTestTeam", "url": "http://grafana.example.com"})
with self.assertRaises(AnsibleFailJson) as result:
grafana_team.main()
- self.assertEqual(result.exception.args[0]['msg'], 'missing required arguments: email')
+ self.assertEqual(
+ result.exception.args[0]["msg"], "missing required arguments: email"
+ )
def test_module_setup_fails_without_url(self):
- set_module_args({
- 'name': 'MyTestTeam',
- 'email': 'email@test.com',
- })
+ set_module_args(
+ {
+ "name": "MyTestTeam",
+ "email": "email@test.com",
+ }
+ )
with self.assertRaises(AnsibleFailJson) as result:
grafana_team.main()
- self.assertEqual(result.exception.args[0]['msg'], 'missing required arguments: url')
+ self.assertEqual(
+ result.exception.args[0]["msg"], "missing required arguments: url"
+ )
def test_module_setup_fails_with_mutually_exclusive_auth_methods(self):
- set_module_args({
- 'name': 'MyTestTeam',
- 'email': 'email@test.com',
- 'url': 'http://grafana.example.com',
- 'grafana_user': 'admin',
- 'grafana_api_key': 'random_api_key',
- })
+ set_module_args(
+ {
+ "name": "MyTestTeam",
+ "email": "email@test.com",
+ "url": "http://grafana.example.com",
+ "grafana_user": "admin",
+ "grafana_api_key": "random_api_key",
+ }
+ )
with self.assertRaises(AnsibleFailJson) as result:
grafana_team.main()
- self.assertEqual(result.exception.args[0]['msg'], 'parameters are mutually exclusive: url_username|grafana_api_key')
-
- @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.GrafanaTeamInterface.get_version')
+ self.assertEqual(
+ result.exception.args[0]["msg"],
+ "parameters are mutually exclusive: url_username|grafana_api_key",
+ )
+
+ @patch(
+ "ansible_collections.community.grafana.plugins.modules.grafana_team.GrafanaTeamInterface.get_version"
+ )
def test_module_fails_with_low_grafana_version(self, mock_get_version):
- set_module_args({
- 'name': 'MyTestTeam',
- 'email': 'email@test.com',
- 'url': 'http://grafana.example.com',
- 'grafana_user': 'admin',
- 'grafana_password': 'admin',
- })
+ set_module_args(
+ {
+ "name": "MyTestTeam",
+ "email": "email@test.com",
+ "url": "http://grafana.example.com",
+ "grafana_user": "admin",
+ "grafana_password": "admin",
+ }
+ )
- module = grafana_team.setup_module_object()
mock_get_version.return_value = get_low_version_resp()
with self.assertRaises(AnsibleFailJson) as result:
grafana_team.main()
- self.assertEqual(result.exception.args[0]['msg'], 'Teams API is available starting Grafana v5')
-
- @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.GrafanaTeamInterface.get_version')
- @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.fetch_url')
- def test_module_failure_with_unauthorized_resp(self, mock_fetch_url, mock_get_version):
- set_module_args({
- 'name': 'MyTestTeam',
- 'email': 'email@test.com',
- 'url': 'http://grafana.example.com',
- })
- module = grafana_team.setup_module_object()
+ self.assertEqual(
+ result.exception.args[0]["msg"],
+ "Teams API is available starting Grafana v5",
+ )
+
+ @patch(
+ "ansible_collections.community.grafana.plugins.modules.grafana_team.GrafanaTeamInterface.get_version"
+ )
+ @patch(
+ "ansible_collections.community.grafana.plugins.modules.grafana_team.fetch_url"
+ )
+ def test_module_failure_with_unauthorized_resp(
+ self, mock_fetch_url, mock_get_version
+ ):
+ set_module_args(
+ {
+ "name": "MyTestTeam",
+ "email": "email@test.com",
+ "url": "http://grafana.example.com",
+ }
+ )
mock_fetch_url.return_value = unauthorized_resp()
mock_get_version.return_value = get_version_resp()
with self.assertRaises(AnsibleFailJson) as result:
grafana_team.main()
- self.assertTrue(result.exception.args[0]['msg'].startswith('Unauthorized to perform action'))
-
- @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.GrafanaTeamInterface.get_version')
- @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.fetch_url')
- def test_module_failure_with_permission_denied_resp(self, mock_fetch_url, mock_get_version):
- set_module_args({
- 'name': 'MyTestTeam',
- 'email': 'email@test.com',
- 'url': 'http://grafana.example.com',
- })
- module = grafana_team.setup_module_object()
+ self.assertTrue(
+ result.exception.args[0]["msg"].startswith("Unauthorized to perform action")
+ )
+
+ @patch(
+ "ansible_collections.community.grafana.plugins.modules.grafana_team.GrafanaTeamInterface.get_version"
+ )
+ @patch(
+ "ansible_collections.community.grafana.plugins.modules.grafana_team.fetch_url"
+ )
+ def test_module_failure_with_permission_denied_resp(
+ self, mock_fetch_url, mock_get_version
+ ):
+ set_module_args(
+ {
+ "name": "MyTestTeam",
+ "email": "email@test.com",
+ "url": "http://grafana.example.com",
+ }
+ )
mock_fetch_url.return_value = permission_denied_resp()
mock_get_version.return_value = get_version_resp()
with self.assertRaises(AnsibleFailJson) as result:
grafana_team.main()
- self.assertTrue(result.exception.args[0]['msg'].startswith('Permission Denied'))
-
- @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.GrafanaTeamInterface.get_version')
- @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.fetch_url')
+ self.assertTrue(result.exception.args[0]["msg"].startswith("Permission Denied"))
+
+ @patch(
+ "ansible_collections.community.grafana.plugins.modules.grafana_team.GrafanaTeamInterface.get_version"
+ )
+ @patch(
+ "ansible_collections.community.grafana.plugins.modules.grafana_team.fetch_url"
+ )
def test_get_team_method_with_existing_team(self, mock_fetch_url, mock_get_version):
- set_module_args({
- 'state': 'present',
- 'name': 'MyTestTeam',
- 'email': 'email@test.com',
- 'url': 'http://grafana.example.com'
- })
+ set_module_args(
+ {
+ "state": "present",
+ "name": "MyTestTeam",
+ "email": "email@test.com",
+ "url": "http://grafana.example.com",
+ }
+ )
module = grafana_team.setup_module_object()
mock_fetch_url.return_value = team_exists_resp()
mock_get_version.return_value = get_version_resp()
@@ -252,21 +297,34 @@ class GrafanaTeamsTest(TestCase):
grafana_iface = grafana_team.GrafanaTeamInterface(module)
res = grafana_iface.get_team("MyTestTeam")
mock_fetch_url.assert_called_once_with(
- module, 'http://grafana.example.com/api/teams/search?name=MyTestTeam',
+ module,
+ "http://grafana.example.com/api/teams/search?name=MyTestTeam",
data=None,
- headers={'Content-Type': 'application/json', 'Authorization': self.authorization},
- method='GET')
- self.assertEquals(res, {"email": "email@test.com", "name": "MyTestTeam"})
-
- @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.GrafanaTeamInterface.get_version')
- @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.fetch_url')
- def test_get_team_method_with_non_existing_team(self, mock_fetch_url, mock_get_version):
- set_module_args({
- 'state': 'present',
- 'name': 'MyTestTeam',
- 'email': 'email@test.com',
- 'url': 'http://grafana.example.com'
- })
+ headers={
+ "Content-Type": "application/json",
+ "Authorization": self.authorization,
+ },
+ method="GET",
+ )
+ self.assertEqual(res, {"email": "email@test.com", "name": "MyTestTeam"})
+
+ @patch(
+ "ansible_collections.community.grafana.plugins.modules.grafana_team.GrafanaTeamInterface.get_version"
+ )
+ @patch(
+ "ansible_collections.community.grafana.plugins.modules.grafana_team.fetch_url"
+ )
+ def test_get_team_method_with_non_existing_team(
+ self, mock_fetch_url, mock_get_version
+ ):
+ set_module_args(
+ {
+ "state": "present",
+ "name": "MyTestTeam",
+ "email": "email@test.com",
+ "url": "http://grafana.example.com",
+ }
+ )
module = grafana_team.setup_module_object()
mock_fetch_url.return_value = team_not_found_resp()
mock_get_version.return_value = get_version_resp()
@@ -274,21 +332,32 @@ class GrafanaTeamsTest(TestCase):
grafana_iface = grafana_team.GrafanaTeamInterface(module)
res = grafana_iface.get_team("MyTestTeam")
mock_fetch_url.assert_called_once_with(
- module, 'http://grafana.example.com/api/teams/search?name=MyTestTeam',
+ module,
+ "http://grafana.example.com/api/teams/search?name=MyTestTeam",
data=None,
- headers={'Content-Type': 'application/json', 'Authorization': self.authorization},
- method='GET')
- self.assertEquals(res, None)
-
- @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.GrafanaTeamInterface.get_version')
- @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.fetch_url')
+ headers={
+ "Content-Type": "application/json",
+ "Authorization": self.authorization,
+ },
+ method="GET",
+ )
+ self.assertEqual(res, None)
+
+ @patch(
+ "ansible_collections.community.grafana.plugins.modules.grafana_team.GrafanaTeamInterface.get_version"
+ )
+ @patch(
+ "ansible_collections.community.grafana.plugins.modules.grafana_team.fetch_url"
+ )
def test_create_team_method(self, mock_fetch_url, mock_get_version):
- set_module_args({
- 'state': 'present',
- 'name': 'MyTestTeam',
- 'email': 'email@test.com',
- 'url': 'http://grafana.example.com'
- })
+ set_module_args(
+ {
+ "state": "present",
+ "name": "MyTestTeam",
+ "email": "email@test.com",
+ "url": "http://grafana.example.com",
+ }
+ )
module = grafana_team.setup_module_object()
mock_fetch_url.return_value = team_created_resp()
mock_get_version.return_value = get_version_resp()
@@ -297,21 +366,34 @@ class GrafanaTeamsTest(TestCase):
res = grafana_iface.create_team("MyTestTeam", "email@test.com")
mock_fetch_url.assert_called_once_with(
- module, 'http://grafana.example.com/api/teams',
- data=json.dumps({"email": "email@test.com", "name": "MyTestTeam"}, sort_keys=True),
- headers={'Content-Type': 'application/json', 'Authorization': self.authorization},
- method='POST')
- self.assertEquals(res, {"message": "Team created", "teamId": 2})
-
- @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.GrafanaTeamInterface.get_version')
- @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.fetch_url')
+ module,
+ "http://grafana.example.com/api/teams",
+ data=json.dumps(
+ {"email": "email@test.com", "name": "MyTestTeam"}, sort_keys=True
+ ),
+ headers={
+ "Content-Type": "application/json",
+ "Authorization": self.authorization,
+ },
+ method="POST",
+ )
+ self.assertEqual(res, {"message": "Team created", "teamId": 2})
+
+ @patch(
+ "ansible_collections.community.grafana.plugins.modules.grafana_team.GrafanaTeamInterface.get_version"
+ )
+ @patch(
+ "ansible_collections.community.grafana.plugins.modules.grafana_team.fetch_url"
+ )
def test_update_team_method(self, mock_fetch_url, mock_get_version):
- set_module_args({
- 'state': 'present',
- 'name': 'MyTestTeam',
- 'email': 'email@test.com',
- 'url': 'http://grafana.example.com'
- })
+ set_module_args(
+ {
+ "state": "present",
+ "name": "MyTestTeam",
+ "email": "email@test.com",
+ "url": "http://grafana.example.com",
+ }
+ )
module = grafana_team.setup_module_object()
mock_fetch_url.return_value = team_updated_resp()
mock_get_version.return_value = get_version_resp()
@@ -319,21 +401,34 @@ class GrafanaTeamsTest(TestCase):
grafana_iface = grafana_team.GrafanaTeamInterface(module)
res = grafana_iface.update_team(2, "MyTestTeam", "email@test.com")
mock_fetch_url.assert_called_once_with(
- module, 'http://grafana.example.com/api/teams/2',
- data=json.dumps({"email": "email@test.com", "name": "MyTestTeam"}, sort_keys=True),
- headers={'Content-Type': 'application/json', 'Authorization': self.authorization},
- method='PUT')
- self.assertEquals(res, {"message": "Team updated"})
-
- @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.GrafanaTeamInterface.get_version')
- @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.fetch_url')
+ module,
+ "http://grafana.example.com/api/teams/2",
+ data=json.dumps(
+ {"email": "email@test.com", "name": "MyTestTeam"}, sort_keys=True
+ ),
+ headers={
+ "Content-Type": "application/json",
+ "Authorization": self.authorization,
+ },
+ method="PUT",
+ )
+ self.assertEqual(res, {"message": "Team updated"})
+
+ @patch(
+ "ansible_collections.community.grafana.plugins.modules.grafana_team.GrafanaTeamInterface.get_version"
+ )
+ @patch(
+ "ansible_collections.community.grafana.plugins.modules.grafana_team.fetch_url"
+ )
def test_delete_team_method(self, mock_fetch_url, mock_get_version):
- set_module_args({
- 'state': 'absent',
- 'name': 'MyTestTeam',
- 'email': 'email@test.com',
- 'url': 'http://grafana.example.com'
- })
+ set_module_args(
+ {
+ "state": "absent",
+ "name": "MyTestTeam",
+ "email": "email@test.com",
+ "url": "http://grafana.example.com",
+ }
+ )
module = grafana_team.setup_module_object()
mock_fetch_url.return_value = team_deleted_resp()
mock_get_version.return_value = get_version_resp()
@@ -341,21 +436,32 @@ class GrafanaTeamsTest(TestCase):
grafana_iface = grafana_team.GrafanaTeamInterface(module)
res = grafana_iface.delete_team(2)
mock_fetch_url.assert_called_once_with(
- module, 'http://grafana.example.com/api/teams/2',
+ module,
+ "http://grafana.example.com/api/teams/2",
data=None,
- headers={'Content-Type': 'application/json', 'Authorization': self.authorization},
- method='DELETE')
- self.assertEquals(res, {"message": "Team deleted"})
-
- @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.GrafanaTeamInterface.get_version')
- @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.fetch_url')
+ headers={
+ "Content-Type": "application/json",
+ "Authorization": self.authorization,
+ },
+ method="DELETE",
+ )
+ self.assertEqual(res, {"message": "Team deleted"})
+
+ @patch(
+ "ansible_collections.community.grafana.plugins.modules.grafana_team.GrafanaTeamInterface.get_version"
+ )
+ @patch(
+ "ansible_collections.community.grafana.plugins.modules.grafana_team.fetch_url"
+ )
def test_get_team_members_method(self, mock_fetch_url, mock_get_version):
- set_module_args({
- 'state': 'present',
- 'name': 'MyTestTeam',
- 'email': 'email@test.com',
- 'url': 'http://grafana.example.com'
- })
+ set_module_args(
+ {
+ "state": "present",
+ "name": "MyTestTeam",
+ "email": "email@test.com",
+ "url": "http://grafana.example.com",
+ }
+ )
module = grafana_team.setup_module_object()
mock_fetch_url.return_value = team_members_resp()
mock_get_version.return_value = get_version_resp()
@@ -363,21 +469,34 @@ class GrafanaTeamsTest(TestCase):
grafana_iface = grafana_team.GrafanaTeamInterface(module)
res = grafana_iface.get_team_members(2)
mock_fetch_url.assert_called_once_with(
- module, 'http://grafana.example.com/api/teams/2/members',
+ module,
+ "http://grafana.example.com/api/teams/2/members",
data=None,
- headers={'Content-Type': 'application/json', 'Authorization': self.authorization},
- method='GET')
- self.assertEquals(res, ["user1@email.com", "user2@email.com"])
-
- @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.GrafanaTeamInterface.get_version')
- @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.fetch_url')
- def test_get_team_members_method_no_members_returned(self, mock_fetch_url, mock_get_version):
- set_module_args({
- 'state': 'present',
- 'name': 'MyTestTeam',
- 'email': 'email@test.com',
- 'url': 'http://grafana.example.com'
- })
+ headers={
+ "Content-Type": "application/json",
+ "Authorization": self.authorization,
+ },
+ method="GET",
+ )
+ self.assertEqual(res, ["user1@email.com", "user2@email.com"])
+
+ @patch(
+ "ansible_collections.community.grafana.plugins.modules.grafana_team.GrafanaTeamInterface.get_version"
+ )
+ @patch(
+ "ansible_collections.community.grafana.plugins.modules.grafana_team.fetch_url"
+ )
+ def test_get_team_members_method_no_members_returned(
+ self, mock_fetch_url, mock_get_version
+ ):
+ set_module_args(
+ {
+ "state": "present",
+ "name": "MyTestTeam",
+ "email": "email@test.com",
+ "url": "http://grafana.example.com",
+ }
+ )
module = grafana_team.setup_module_object()
mock_fetch_url.return_value = team_members_no_members_resp()
mock_get_version.return_value = get_version_resp()
@@ -385,63 +504,96 @@ class GrafanaTeamsTest(TestCase):
grafana_iface = grafana_team.GrafanaTeamInterface(module)
res = grafana_iface.get_team_members(2)
mock_fetch_url.assert_called_once_with(
- module, 'http://grafana.example.com/api/teams/2/members',
+ module,
+ "http://grafana.example.com/api/teams/2/members",
data=None,
- headers={'Content-Type': 'application/json', 'Authorization': self.authorization},
- method='GET')
- self.assertEquals(res, [])
-
- @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.GrafanaTeamInterface.get_version')
- @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.fetch_url')
+ headers={
+ "Content-Type": "application/json",
+ "Authorization": self.authorization,
+ },
+ method="GET",
+ )
+ self.assertEqual(res, [])
+
+ @patch(
+ "ansible_collections.community.grafana.plugins.modules.grafana_team.GrafanaTeamInterface.get_version"
+ )
+ @patch(
+ "ansible_collections.community.grafana.plugins.modules.grafana_team.fetch_url"
+ )
def test_add_team_member_method(self, mock_fetch_url, mock_get_version):
- set_module_args({
- 'state': 'present',
- 'name': 'MyTestTeam',
- 'email': 'email@test.com',
- 'url': 'http://grafana.example.com'
- })
+ set_module_args(
+ {
+ "state": "present",
+ "name": "MyTestTeam",
+ "email": "email@test.com",
+ "url": "http://grafana.example.com",
+ }
+ )
module = grafana_team.setup_module_object()
mock_fetch_url.return_value = add_team_member_resp()
mock_get_version.return_value = get_version_resp()
grafana_iface = grafana_team.GrafanaTeamInterface(module)
- with patch.object(grafana_team.GrafanaTeamInterface, 'get_user_id_from_mail') as mock_get_user_id_from_mail:
+ with patch.object(
+ grafana_team.GrafanaTeamInterface, "get_user_id_from_mail"
+ ) as mock_get_user_id_from_mail:
mock_get_user_id_from_mail.return_value = 42
res = grafana_iface.add_team_member(2, "another@test.com")
mock_fetch_url.assert_called_once_with(
- module, 'http://grafana.example.com/api/teams/2/members',
- data=json.dumps({'userId': 42}),
- headers={'Content-Type': 'application/json', 'Authorization': self.authorization},
- method='POST')
- self.assertEquals(res, None)
-
- @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.GrafanaTeamInterface.get_version')
- @patch('ansible_collections.community.grafana.plugins.modules.grafana_team.fetch_url')
+ module,
+ "http://grafana.example.com/api/teams/2/members",
+ data=json.dumps({"userId": 42}),
+ headers={
+ "Content-Type": "application/json",
+ "Authorization": self.authorization,
+ },
+ method="POST",
+ )
+ self.assertEqual(res, None)
+
+ @patch(
+ "ansible_collections.community.grafana.plugins.modules.grafana_team.GrafanaTeamInterface.get_version"
+ )
+ @patch(
+ "ansible_collections.community.grafana.plugins.modules.grafana_team.fetch_url"
+ )
def test_delete_team_member_method(self, mock_fetch_url, mock_get_version):
- set_module_args({
- 'state': 'present',
- 'name': 'MyTestTeam',
- 'email': 'email@test.com',
- 'url': 'http://grafana.example.com'
- })
+ set_module_args(
+ {
+ "state": "present",
+ "name": "MyTestTeam",
+ "email": "email@test.com",
+ "url": "http://grafana.example.com",
+ }
+ )
module = grafana_team.setup_module_object()
mock_fetch_url.return_value = delete_team_member_resp()
mock_get_version.return_value = get_version_resp()
grafana_iface = grafana_team.GrafanaTeamInterface(module)
- with patch.object(grafana_team.GrafanaTeamInterface, 'get_user_id_from_mail') as mock_get_user_id_from_mail:
+ with patch.object(
+ grafana_team.GrafanaTeamInterface, "get_user_id_from_mail"
+ ) as mock_get_user_id_from_mail:
mock_get_user_id_from_mail.return_value = 42
res = grafana_iface.delete_team_member(2, "another@test.com")
mock_fetch_url.assert_called_once_with(
- module, 'http://grafana.example.com/api/teams/2/members/42',
+ module,
+ "http://grafana.example.com/api/teams/2/members/42",
data=None,
- headers={'Content-Type': 'application/json', 'Authorization': self.authorization},
- method='DELETE')
- self.assertEquals(res, None)
+ headers={
+ "Content-Type": "application/json",
+ "Authorization": self.authorization,
+ },
+ method="DELETE",
+ )
+ self.assertEqual(res, None)
def test_diff_members_function(self):
list1 = ["foo@example.com", "bar@example.com"]
list2 = ["bar@example.com", "random@example.com"]
res = grafana_team.diff_members(list1, list2)
- self.assertEquals(res, {"to_del": ["random@example.com"], "to_add": ["foo@example.com"]})
+ self.assertEqual(
+ res, {"to_del": ["random@example.com"], "to_add": ["foo@example.com"]}
+ )
diff --git a/ansible_collections/community/grafana/tests/unit/modules/grafana/grafana_user/test_grafana_user.py b/ansible_collections/community/grafana/tests/unit/modules/grafana/grafana_user/test_grafana_user.py
index 925c01655..09d0dce05 100644
--- a/ansible_collections/community/grafana/tests/unit/modules/grafana/grafana_user/test_grafana_user.py
+++ b/ansible_collections/community/grafana/tests/unit/modules/grafana/grafana_user/test_grafana_user.py
@@ -1,7 +1,7 @@
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import, division, print_function
from unittest import TestCase
-from unittest.mock import call, patch, MagicMock
+from unittest.mock import call, patch
from ansible_collections.community.grafana.plugins.modules import grafana_user
from ansible.module_utils._text import to_bytes
from ansible.module_utils import basic
@@ -21,30 +21,32 @@ class MockedReponse(object):
def exit_json(*args, **kwargs):
"""function to patch over exit_json; package return data into an exception"""
- if 'changed' not in kwargs:
- kwargs['changed'] = False
+ if "changed" not in kwargs:
+ kwargs["changed"] = False
raise AnsibleExitJson(kwargs)
def fail_json(*args, **kwargs):
"""function to patch over fail_json; package return data into an exception"""
- kwargs['failed'] = True
+ kwargs["failed"] = True
raise AnsibleFailJson(kwargs)
class AnsibleExitJson(Exception):
"""Exception class to be raised by module.exit_json and caught by the test case"""
+
pass
class AnsibleFailJson(Exception):
"""Exception class to be raised by module.fail_json and caught by the test case"""
+
pass
def set_module_args(args):
"""prepare arguments so that they will be picked up during module creation"""
- args = json.dumps({'ANSIBLE_MODULE_ARGS': args})
+ args = json.dumps({"ANSIBLE_MODULE_ARGS": args})
basic._ANSIBLE_ARGS = to_bytes(args)
@@ -59,75 +61,94 @@ def user_already_exists_resp():
def user_created_resp():
- server_response = json.dumps({
- "id": 2,
- "email": "robin@gotham.com",
- "name": "Robin",
- "login": "adrobinmin",
- "theme": "light",
- "orgId": 1,
- "isGrafanaAdmin": False,
- "isDisabled": False,
- "isExternal": False,
- "authLabels": None,
- "updatedAt": "2019-09-25T14:44:37+01:00",
- "createdAt": "2019-09-25T14:44:37+01:00"
- }, sort_keys=True)
+ server_response = json.dumps(
+ {
+ "id": 2,
+ "email": "robin@gotham.com",
+ "name": "Robin",
+ "login": "adrobinmin",
+ "theme": "light",
+ "orgId": 1,
+ "isGrafanaAdmin": False,
+ "isDisabled": False,
+ "isExternal": False,
+ "authLabels": None,
+ "updatedAt": "2019-09-25T14:44:37+01:00",
+ "createdAt": "2019-09-25T14:44:37+01:00",
+ },
+ sort_keys=True,
+ )
return (MockedReponse(server_response), {"status": 200})
class GrafanaUserTest(TestCase):
-
def setUp(self):
self.authorization = basic_auth_header("admin", "changeme")
- self.mock_module_helper = patch.multiple(basic.AnsibleModule,
- exit_json=exit_json,
- fail_json=fail_json)
+ self.mock_module_helper = patch.multiple(
+ basic.AnsibleModule, exit_json=exit_json, fail_json=fail_json
+ )
self.mock_module_helper.start()
self.addCleanup(self.mock_module_helper.stop)
# create an already existing user
- @patch('ansible_collections.community.grafana.plugins.modules.grafana_user.fetch_url')
+ @patch(
+ "ansible_collections.community.grafana.plugins.modules.grafana_user.fetch_url"
+ )
def test_create_user_existing_user(self, mock_fetch_url):
- set_module_args({
- 'url': 'https://grafana.example.com',
- 'url_username': 'admin',
- 'url_password': 'changeme',
- 'name': 'Joker',
- 'email': 'joker@gotham.com',
- 'login': 'joker',
- 'password': 'oups',
- 'state': 'present'
- })
+ set_module_args(
+ {
+ "url": "https://grafana.example.com",
+ "url_username": "admin",
+ "url_password": "changeme",
+ "name": "Joker",
+ "email": "joker@gotham.com",
+ "login": "joker",
+ "password": "oups",
+ "state": "present",
+ }
+ )
module = grafana_user.setup_module_object()
mock_fetch_url.return_value = user_already_exists_resp()
grafana_iface = grafana_user.GrafanaUserInterface(module)
with self.assertRaises(AnsibleFailJson):
- grafana_iface.create_user(
- 'Joker', 'joker@gotham.com', 'joker', 'oups')
+ grafana_iface.create_user("Joker", "joker@gotham.com", "joker", "oups")
mock_fetch_url.assert_called_once_with(
module,
- 'https://grafana.example.com/api/admin/users',
- data=json.dumps({'name': 'Joker', 'email': 'joker@gotham.com',
- 'login': 'joker', 'password': 'oups'}, sort_keys=True),
- headers={'Content-Type': 'application/json',
- 'Authorization': self.authorization},
- method='POST')
+ "https://grafana.example.com/api/admin/users",
+ data=json.dumps(
+ {
+ "name": "Joker",
+ "email": "joker@gotham.com",
+ "login": "joker",
+ "password": "oups",
+ },
+ sort_keys=True,
+ ),
+ headers={
+ "Content-Type": "application/json",
+ "Authorization": self.authorization,
+ },
+ method="POST",
+ )
# create a new user
- @patch('ansible_collections.community.grafana.plugins.modules.grafana_user.fetch_url')
+ @patch(
+ "ansible_collections.community.grafana.plugins.modules.grafana_user.fetch_url"
+ )
def test_create_user_new_user(self, mock_fetch_url):
- set_module_args({
- 'url': 'https://grafana.example.com',
- 'url_username': 'admin',
- 'url_password': 'changeme',
- 'name': 'Robin',
- 'email': 'robin@gotham.com',
- 'login': 'robin',
- 'password': 'oups',
- 'state': 'present'
- })
+ set_module_args(
+ {
+ "url": "https://grafana.example.com",
+ "url_username": "admin",
+ "url_password": "changeme",
+ "name": "Robin",
+ "email": "robin@gotham.com",
+ "login": "robin",
+ "password": "oups",
+ "state": "present",
+ }
+ )
module = grafana_user.setup_module_object()
mock_fetch_url.return_value = user_created_resp()
@@ -136,54 +157,71 @@ class GrafanaUserTest(TestCase):
# first call to create user
call(
module,
- 'https://grafana.example.com/api/admin/users',
- data=json.dumps({'name': 'Robin', 'email': 'robin@gotham.com',
- 'login': 'robin', 'password': 'oups'}, sort_keys=True),
- headers={'Content-Type': 'application/json',
- 'Authorization': self.authorization},
- method='POST'),
-
+ "https://grafana.example.com/api/admin/users",
+ data=json.dumps(
+ {
+ "name": "Robin",
+ "email": "robin@gotham.com",
+ "login": "robin",
+ "password": "oups",
+ },
+ sort_keys=True,
+ ),
+ headers={
+ "Content-Type": "application/json",
+ "Authorization": self.authorization,
+ },
+ method="POST",
+ ),
# second call to return created user
call(
module,
- 'https://grafana.example.com/api/users/lookup?loginOrEmail=robin',
+ "https://grafana.example.com/api/users/lookup?loginOrEmail=robin",
data=None,
- headers={'Content-Type': 'application/json',
- 'Authorization': self.authorization},
- method='GET'),
+ headers={
+ "Content-Type": "application/json",
+ "Authorization": self.authorization,
+ },
+ method="GET",
+ ),
]
grafana_iface = grafana_user.GrafanaUserInterface(module)
- result = grafana_iface.create_user(
- 'Robin', 'robin@gotham.com', 'robin', 'oups')
-
- mock_fetch_url.assert_has_calls(
- expected_fetch_url_calls, any_order=False)
-
- self.assertEquals(result, {
- "id": 2,
- "email": "robin@gotham.com",
- "name": "Robin",
- "login": "adrobinmin",
- "theme": "light",
- "orgId": 1,
- "isGrafanaAdmin": False,
- "isDisabled": False,
- "isExternal": False,
- "authLabels": None,
- "updatedAt": "2019-09-25T14:44:37+01:00",
- "createdAt": "2019-09-25T14:44:37+01:00"
- })
-
- @patch('ansible_collections.community.grafana.plugins.modules.grafana_user.fetch_url')
+ result = grafana_iface.create_user("Robin", "robin@gotham.com", "robin", "oups")
+
+ mock_fetch_url.assert_has_calls(expected_fetch_url_calls, any_order=False)
+
+ self.assertEqual(
+ result,
+ {
+ "id": 2,
+ "email": "robin@gotham.com",
+ "name": "Robin",
+ "login": "adrobinmin",
+ "theme": "light",
+ "orgId": 1,
+ "isGrafanaAdmin": False,
+ "isDisabled": False,
+ "isExternal": False,
+ "authLabels": None,
+ "updatedAt": "2019-09-25T14:44:37+01:00",
+ "createdAt": "2019-09-25T14:44:37+01:00",
+ },
+ )
+
+ @patch(
+ "ansible_collections.community.grafana.plugins.modules.grafana_user.fetch_url"
+ )
def test_delete_user(self, mock_fetch_url):
- set_module_args({
- 'url': 'https://grafana.example.com',
- 'url_username': 'admin',
- 'url_password': 'changeme',
- 'login': 'batman',
- 'state': 'absent'
- })
+ set_module_args(
+ {
+ "url": "https://grafana.example.com",
+ "url_username": "admin",
+ "url_password": "changeme",
+ "login": "batman",
+ "state": "absent",
+ }
+ )
module = grafana_user.setup_module_object()
mock_fetch_url.return_value = user_deleted_resp()
@@ -192,9 +230,12 @@ class GrafanaUserTest(TestCase):
result = grafana_iface.delete_user(user_id)
mock_fetch_url.assert_called_once_with(
module,
- 'https://grafana.example.com/api/admin/users/42',
+ "https://grafana.example.com/api/admin/users/42",
data=None,
- headers={'Content-Type': 'application/json',
- 'Authorization': self.authorization},
- method='DELETE')
- self.assertEquals(result, {"message": "User deleted"})
+ headers={
+ "Content-Type": "application/json",
+ "Authorization": self.authorization,
+ },
+ method="DELETE",
+ )
+ self.assertEqual(result, {"message": "User deleted"})
diff --git a/ansible_collections/community/hashi_vault/.github/actions/docker-image-versions/action.yml b/ansible_collections/community/hashi_vault/.github/actions/docker-image-versions/action.yml
index 766067df7..d2503deaa 100644
--- a/ansible_collections/community/hashi_vault/.github/actions/docker-image-versions/action.yml
+++ b/ansible_collections/community/hashi_vault/.github/actions/docker-image-versions/action.yml
@@ -8,8 +8,7 @@ outputs:
inputs:
image:
description: The docker image name.
- required: false
- default: vault
+ required: true
num_major_versions:
description: Number of unique major versions to return.
required: false
diff --git a/ansible_collections/community/hashi_vault/.github/actions/docker-image-versions/versions.py b/ansible_collections/community/hashi_vault/.github/actions/docker-image-versions/versions.py
index 9d7fcea2d..d73680f8c 100755
--- a/ansible_collections/community/hashi_vault/.github/actions/docker-image-versions/versions.py
+++ b/ansible_collections/community/hashi_vault/.github/actions/docker-image-versions/versions.py
@@ -21,7 +21,7 @@ from warnings import warn
from packaging import version
-TAG_URI = 'https://registry.hub.docker.com/v2/repositories/library/%s/tags?page_size=1024'
+TAG_URI = 'https://registry.hub.docker.com/v2/repositories/%s/%s/tags?page_size=1024'
class WarningRetry(Retry):
@@ -49,7 +49,7 @@ def main(argv):
for opt, arg in opts:
if opt == '--image':
- image = arg
+ image = image_name = arg
elif opt == '--num_major_versions':
num_major_versions = int(arg)
elif opt == '--num_minor_versions':
@@ -64,7 +64,12 @@ def main(argv):
if image is None:
raise ValueError('image must be supplied.')
- tag_url = TAG_URI % image
+ if '/' in image:
+ org, image_name = image.split('/')
+ else:
+ org = 'library'
+
+ tag_url = TAG_URI % (org, image_name)
sess = requests.Session()
retry = WarningRetry(total=5, backoff_factor=0.2, respect_retry_after_header=False)
@@ -112,7 +117,7 @@ def main(argv):
keep.append(str(ver))
- with open(os.environ['GITHUB_OUTPUT'], 'a') as f:
+ with open(os.environ.get('GITHUB_OUTPUT', '/dev/stdout'), 'a') as f:
f.write('versions=')
json.dump(keep, f)
diff --git a/ansible_collections/community/hashi_vault/.github/dependabot.yml b/ansible_collections/community/hashi_vault/.github/dependabot.yml
new file mode 100644
index 000000000..969b36fe0
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/.github/dependabot.yml
@@ -0,0 +1,9 @@
+---
+# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
+
+version: 2
+updates:
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "weekly"
diff --git a/ansible_collections/community/hashi_vault/.github/workflows/ansible-builder.yml b/ansible_collections/community/hashi_vault/.github/workflows/ansible-builder.yml
index 10aeb5c2d..a3a849c46 100644
--- a/ansible_collections/community/hashi_vault/.github/workflows/ansible-builder.yml
+++ b/ansible_collections/community/hashi_vault/.github/workflows/ansible-builder.yml
@@ -24,14 +24,15 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
+ show-progress: false
path: ansible_collections/${{ env.NAMESPACE }}/${{ env.COLLECTION_NAME }}
- name: Set up Python
- uses: actions/setup-python@v4
+ uses: actions/setup-python@v5
with:
- python-version: 3.9
+ python-version: 3.11
- name: Install ansible-builder
run: pip install ansible-builder
diff --git a/ansible_collections/community/hashi_vault/.github/workflows/ansible-test.yml b/ansible_collections/community/hashi_vault/.github/workflows/ansible-test.yml
index 25857dadb..b1b079817 100644
--- a/ansible_collections/community/hashi_vault/.github/workflows/ansible-test.yml
+++ b/ansible_collections/community/hashi_vault/.github/workflows/ansible-test.yml
@@ -2,6 +2,8 @@ name: CI
on:
# Run CI against all pushes (direct commits, also merged PRs), Pull Requests
push:
+ branches-ignore:
+ - 'dependabot/**'
paths-ignore:
- 'docs/**'
- '.github/workflows/_shared-*'
@@ -31,17 +33,16 @@ jobs:
name: Sanity (Ⓐ${{ matrix.ansible }})
runs-on: ${{ matrix.runner }}
strategy:
+ fail-fast: false
matrix:
runner:
- ubuntu-latest
test_container:
- default
ansible:
- - stable-2.11
- - stable-2.12
- - stable-2.13
- stable-2.14
- stable-2.15
+ - stable-2.16
- devel
steps:
@@ -55,22 +56,23 @@ jobs:
TEST_INVOCATION="sanity --docker ${{ matrix.test_container }} -v --color ${{ github.event_name != 'schedule' && '--coverage' || '' }}"
- name: Check out code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
+ show-progress: false
path: ${{ env.COLLECTION_PATH }}
- name: Link to .github # easier access to local actions
run: ln -s "${COLLECTION_PATH}/.github" .github
- name: Set up Python
- uses: actions/setup-python@v4
+ uses: actions/setup-python@v5
with:
# it is just required to run that once as "ansible-test sanity" in the docker image
# will run on all python versions it supports.
- python-version: 3.9
+ python-version: '3.11'
# Install the head of the given branch (devel, stable-2.14)
- - name: Install ansible-base (${{ matrix.ansible }})
+ - name: Install ansible-core (${{ matrix.ansible }})
run: pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz --disable-pip-version-check
- name: Pull Ansible test images
@@ -95,7 +97,7 @@ jobs:
- name: Upload ${{ github.job }} coverage reports
if: ${{ github.event_name != 'schedule' }}
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: coverage=${{ github.job }}=ansible_${{ matrix.ansible }}=data
path: ${{ env.COLLECTION_PATH }}/tests/output/reports/
@@ -107,19 +109,16 @@ jobs:
runs-on: ${{ matrix.runner }}
name: Units (Ⓐ${{ matrix.ansible }})
strategy:
- # As soon as the first unit test fails, cancel the others to free up the CI queue
- fail-fast: true
+ fail-fast: false
matrix:
runner:
- ubuntu-latest
test_container:
- default
ansible:
- - stable-2.11
- - stable-2.12
- - stable-2.13
- stable-2.14
- stable-2.15
+ - stable-2.16
- devel
steps:
@@ -131,21 +130,22 @@ jobs:
TEST_INVOCATION="units --color --docker ${{ matrix.test_container }} ${{ github.event_name != 'schedule' && '--coverage' || '' }}"
- name: Check out code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
+ show-progress: false
path: ${{ env.COLLECTION_PATH }}
- name: Link to .github # easier access to local actions
run: ln -s "${COLLECTION_PATH}/.github" .github
- name: Set up Python
- uses: actions/setup-python@v4
+ uses: actions/setup-python@v5
with:
# it is just required to run that once as "ansible-test units" in the docker image
# will run on all python versions it supports.
- python-version: 3.9
+ python-version: '3.11'
- - name: Install ansible-base (${{ matrix.ansible }})
+ - name: Install ansible-core (${{ matrix.ansible }})
run: pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz --disable-pip-version-check
- name: Pull Ansible test images
@@ -168,7 +168,7 @@ jobs:
- name: Upload ${{ github.job }} coverage reports
if: ${{ github.event_name != 'schedule' }}
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: coverage=${{ github.job }}=ansible_${{ matrix.ansible }}=data
path: ${{ env.COLLECTION_PATH }}/tests/output/reports/
@@ -182,7 +182,7 @@ jobs:
integration:
runs-on: ${{ matrix.runner }}
- name: I (Ⓐ${{ matrix.ansible }}+py${{ matrix.python }})
+ name: I (Ⓐ${{ matrix.ansible }}+py${{ matrix.python }}+V[-${{ matrix.vault_minus }}])
strategy:
fail-fast: false
matrix:
@@ -190,12 +190,13 @@ jobs:
- ubuntu-latest
test_container:
- default
+ vault_minus:
+ - 0
+ - 1
ansible:
- - stable-2.11
- - stable-2.12
- - stable-2.13
- stable-2.14
- stable-2.15
+ - stable-2.16
- devel
python:
- '3.6'
@@ -204,29 +205,36 @@ jobs:
- '3.9'
- '3.10'
- '3.11'
+ - '3.12'
exclude:
# https://docs.ansible.com/ansible/devel/installation_guide/intro_installation.html#control-node-requirements
# https://docs.ansible.com/ansible/devel/reference_appendices/release_and_maintenance.html#ansible-core-support-matrix
- - ansible: 'stable-2.11'
- python: '3.10'
- - ansible: 'stable-2.11'
- python: '3.11'
- - ansible: 'stable-2.12'
- python: '3.11'
- - ansible: 'stable-2.13'
- python: '3.11'
- - ansible: 'stable-2.15'
+ - ansible: 'devel'
python: '3.6'
- - ansible: 'stable-2.15'
+ - ansible: 'devel'
python: '3.7'
- - ansible: 'stable-2.15'
+ - ansible: 'devel'
python: '3.8'
- ansible: 'devel'
+ python: '3.9'
+ - ansible: 'stable-2.16'
python: '3.6'
- - ansible: 'devel'
+ - ansible: 'stable-2.16'
python: '3.7'
- - ansible: 'devel'
+ - ansible: 'stable-2.16'
+ python: '3.8'
+ - ansible: 'stable-2.16'
+ python: '3.9'
+ - ansible: 'stable-2.15'
+ python: '3.6'
+ - ansible: 'stable-2.15'
+ python: '3.7'
+ - ansible: 'stable-2.15'
+ python: '3.12'
+ - ansible: 'stable-2.15'
python: '3.8'
+ - ansible: 'stable-2.14'
+ python: '3.12'
steps:
- name: Initialize env vars
@@ -239,29 +247,36 @@ jobs:
TEST_INVOCATION="integration -v --color --retry-on-error --continue-on-error --python ${{ matrix.python }} --docker ${{ matrix.test_container }} ${{ github.event_name != 'schedule' && '--coverage' || '' }} --docker-network hashi_vault_default"
- name: Check out code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
+ show-progress: false
path: ${{ env.COLLECTION_PATH }}
- name: Link to .github # easier access to local actions
run: ln -s "${COLLECTION_PATH}/.github" .github
- name: Set up Python
- uses: actions/setup-python@v4
+ uses: actions/setup-python@v5
with:
- python-version: 3.9
+ python-version: '3.11'
- name: Get Vault versions
id: vault_versions
uses: ./.github/actions/docker-image-versions
with:
+ image: hashicorp/vault
num_major_versions: 1
num_minor_versions: 2
num_micro_versions: 1
- - name: Install ansible-base (${{ matrix.ansible }})
+ - name: Install ansible-core (${{ matrix.ansible }})
run: pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz --disable-pip-version-check
+ - name: Install community.postgresql
+ uses: ./.github/actions/collection-via-git
+ with:
+ collection: community.postgresql
+
- name: Pull Ansible test images
timeout-minutes: 5
continue-on-error: true
@@ -270,23 +285,10 @@ jobs:
working-directory: ${{ env.COLLECTION_PATH }}
ansible-test-invocation: ${{ env.TEST_INVOCATION }}
- - name: Set Vault Version (older)
+ - name: Set Vault Version
uses: briantist/ezenv@v1
with:
- env: VAULT_VERSION=${{ fromJSON(steps.vault_versions.outputs.versions)[1] }}
-
- - name: Prepare docker dependencies (Vault ${{ env.VAULT_VERSION }})
- run: ./setup.sh -e vault_version=${VAULT_VERSION}
- working-directory: ${{ env.COLLECTION_INTEGRATION_TARGETS }}/setup_localenv_gha
-
- - name: Run integration test (Vault ${{ env.VAULT_VERSION }})
- run: ansible-test ${{ env.TEST_INVOCATION }}
- working-directory: ${{ env.COLLECTION_PATH }}
-
- - name: Set Vault Version (newer)
- uses: briantist/ezenv@v1
- with:
- env: VAULT_VERSION=${{ fromJSON(steps.vault_versions.outputs.versions)[0] }}
+ env: VAULT_VERSION=${{ fromJSON(steps.vault_versions.outputs.versions)[matrix.vault_minus] }}
- name: Prepare docker dependencies (Vault ${{ env.VAULT_VERSION }})
run: ./setup.sh -e vault_version=${VAULT_VERSION}
@@ -304,9 +306,9 @@ jobs:
- name: Upload ${{ github.job }} coverage reports
if: ${{ github.event_name != 'schedule' }}
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
- name: coverage=${{ github.job }}=ansible_${{ matrix.ansible }}=${{ matrix.python }}=data
+ name: coverage=${{ github.job }}=ansible_${{ matrix.ansible }}=${{ matrix.python }}=vault_minus_${{ matrix.vault_minus }}=data
path: ${{ env.COLLECTION_PATH }}/tests/output/reports/
if-no-files-found: error
retention-days: 1
@@ -318,14 +320,22 @@ jobs:
fail-fast: false
matrix:
ansible:
- - stable-2.15
+ - stable-2.16
- devel
+ delete_canaries:
+ - true
+ - false
python:
- - 3.9
+ - '3.12'
runner:
- ubuntu-latest
test_container:
- default
+ exclude:
+ - ansible: devel
+ delete_canaries: false
+ - ansible: stable-2.16
+ delete_canaries: true
steps:
- name: Initialize env vars
@@ -338,19 +348,20 @@ jobs:
DOCKER_TEST_INVOCATION="integration -v --color --retry-on-error --continue-on-error --controller docker:${{ matrix.test_container }},python=${{ matrix.python }} ${{ github.event_name != 'schedule' && '--coverage' || '' }}"
- name: Check out code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
+ show-progress: false
path: ${{ env.COLLECTION_PATH }}
- name: Link to .github # easier access to local actions
run: ln -s "${COLLECTION_PATH}/.github" .github
- name: Set up Python
- uses: actions/setup-python@v4
+ uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python }}
- - name: Install ansible-base (${{ matrix.ansible }})
+ - name: Install ansible-core (${{ matrix.ansible }})
run: pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz --disable-pip-version-check
- name: Install community.crypto
@@ -363,6 +374,11 @@ jobs:
with:
collection: community.docker
+ - name: Install community.postgresql
+ uses: ./.github/actions/collection-via-git
+ with:
+ collection: community.postgresql
+
- name: Pull Ansible test images
timeout-minutes: 5
continue-on-error: true
@@ -374,6 +390,10 @@ jobs:
- name: localenv_docker - setup
run: |
pwd
+ pip install --upgrade pip setuptools build wheel
+ pip install "Cython<3.0" "pyyaml<6" --no-build-isolation
+ # ^ https://github.com/yaml/pyyaml/issues/601
+ # ^ https://github.com/docker/compose/issues/10836
pip install -r files/requirements/requirements.txt -c files/requirements/constraints.txt
./setup.sh
working-directory: ${{ env.COLLECTION_INTEGRATION_TARGETS }}/setup_localenv_docker
@@ -383,13 +403,9 @@ jobs:
ansible-test ${{ env.DOCKER_TEST_INVOCATION }} --docker-network hashi_vault_default
working-directory: ${{ env.COLLECTION_PATH }}
- - name: Run integration again (ensure tests do not break against still-running containers)
- run: |
- ansible-test ${{ env.DOCKER_TEST_INVOCATION }} --docker-network hashi_vault_default
- working-directory: ${{ env.COLLECTION_PATH }}
-
#TODO add capability in the Ansible side once vault_list and vault_delete exist
- - name: Run a third time, but delete Vault's cubbyhole contents first
+ - name: Delete Vault's cubbyhole contents (ensure test setup is idempotent)
+ if: matrix.delete_canaries
working-directory: ${{ env.COLLECTION_PATH }}
env:
VAULT_TOKEN: 47542cbc-6bf8-4fba-8eda-02e0a0d29a0a
@@ -398,8 +414,11 @@ jobs:
echo 'vault list cubbyhole \
| tail -n +3 \
| xargs -I{} -n 1 vault delete cubbyhole/{}' \
- | docker run --rm --network hashi_vault_default -e VAULT_TOKEN -e VAULT_ADDR -i vault sh
+ | docker run --rm --network hashi_vault_default -e VAULT_TOKEN -e VAULT_ADDR -i hashicorp/vault sh
+ - name: Run integration again (ensure tests do not break against still-running containers)
+ working-directory: ${{ env.COLLECTION_PATH }}
+ run: |
ansible-test ${{ env.DOCKER_TEST_INVOCATION }} --docker-network hashi_vault_default
# ansible-test support producing code coverage data
@@ -410,7 +429,7 @@ jobs:
- name: Upload ${{ github.job }} coverage reports
if: ${{ github.event_name != 'schedule' }}
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: coverage=${{ github.job }}=${{ matrix.runner }}=ansible_${{ matrix.ansible }}=${{ matrix.python }}=data
path: ${{ env.COLLECTION_PATH }}/tests/output/reports/
@@ -430,31 +449,15 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
+ with:
+ show-progress: false
- name: Download artifacts
- uses: actions/download-artifact@v3
+ uses: actions/download-artifact@v4
with:
path: ./cov
- # Before Ansible 2.12, units always used a "target" of "units", and we don't want a flag of "target_units".
- # After 2.12, target can be "controller" or "module_utils" and we'll preserve them for now.
- # If we decide that those targets are not helpful, we can simplify processing by removing this run block
- # and just having two ansible-codecov calls, one for units (that excludes target) and one for integration.
- # That change would also make integration processing faster because we can hardcode the integration flag as an additional flag.
- - name: Move Ansible pre-2.12 units
- run: |
- mkdir ./cov-units-pre2.12
- mv ./cov/coverage=units=ansible_stable-2.11=data ./cov-units-pre2.12
-
- - name: Upload Ansible pre-2.12 unit coverage reports to Codecov
- uses: ./.github/actions/ansible-codecov
- with:
- directory: ./cov-units-pre2.12
- additional-flags: units
- file-flag-pattern: coverage=units=units={env_%}.xml
- directory-flag-pattern: =ansible_{ansible-%}=
-
# See the reports at https://codecov.io/gh/ansible-collections/community.hashi_vault
- name: Upload coverage reports to Codecov
uses: ./.github/actions/ansible-codecov
diff --git a/ansible_collections/community/hashi_vault/.github/workflows/github-release.yml b/ansible_collections/community/hashi_vault/.github/workflows/github-release.yml
index 6fce7d2e6..4a2a2418e 100644
--- a/ansible_collections/community/hashi_vault/.github/workflows/github-release.yml
+++ b/ansible_collections/community/hashi_vault/.github/workflows/github-release.yml
@@ -15,18 +15,20 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
+ with:
+ show-progress: false
- name: Set up Python
- uses: actions/setup-python@v4
+ uses: actions/setup-python@v5
with:
- python-version: 3.9
+ python-version: 3.12
- name: Install PyYaml
- run: pip install pyyaml
+ run: pip install pyyaml ansible-core
- name: Validate version is published to Galaxy
- run: curl --head -s -f -o /dev/null https://galaxy.ansible.com/download/community-hashi_vault-${{ github.event.inputs.version }}.tar.gz
+ run: ansible-galaxy collection download -vvv -p /tmp 'community.hashi_vault:==${{ github.event.inputs.version }}'
- name: Build release description
shell: python
diff --git a/ansible_collections/community/hashi_vault/CHANGELOG.md b/ansible_collections/community/hashi_vault/CHANGELOG.md
new file mode 100644
index 000000000..87ac6d4e0
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/CHANGELOG.md
@@ -0,0 +1,828 @@
+# community\.hashi\_vault Release Notes
+
+**Topics**
+
+- <a href="#v6-2-0">v6\.2\.0</a>
+ - <a href="#release-summary">Release Summary</a>
+ - <a href="#minor-changes">Minor Changes</a>
+ - <a href="#new-modules">New Modules</a>
+- <a href="#v6-1-0">v6\.1\.0</a>
+ - <a href="#release-summary-1">Release Summary</a>
+ - <a href="#major-changes">Major Changes</a>
+- <a href="#v6-0-0">v6\.0\.0</a>
+ - <a href="#release-summary-2">Release Summary</a>
+ - <a href="#breaking-changes--porting-guide">Breaking Changes / Porting Guide</a>
+ - <a href="#removed-features-previously-deprecated">Removed Features \(previously deprecated\)</a>
+- <a href="#v5-0-1">v5\.0\.1</a>
+ - <a href="#release-summary-3">Release Summary</a>
+ - <a href="#bugfixes">Bugfixes</a>
+- <a href="#v5-0-0">v5\.0\.0</a>
+ - <a href="#release-summary-4">Release Summary</a>
+ - <a href="#breaking-changes--porting-guide-1">Breaking Changes / Porting Guide</a>
+- <a href="#v4-2-1">v4\.2\.1</a>
+ - <a href="#release-summary-5">Release Summary</a>
+- <a href="#v4-2-0">v4\.2\.0</a>
+ - <a href="#release-summary-6">Release Summary</a>
+ - <a href="#deprecated-features">Deprecated Features</a>
+ - <a href="#bugfixes-1">Bugfixes</a>
+ - <a href="#new-modules-1">New Modules</a>
+- <a href="#v4-1-0">v4\.1\.0</a>
+ - <a href="#release-summary-7">Release Summary</a>
+ - <a href="#deprecated-features-1">Deprecated Features</a>
+ - <a href="#new-plugins">New Plugins</a>
+ - <a href="#lookup">Lookup</a>
+ - <a href="#new-modules-2">New Modules</a>
+- <a href="#v4-0-0">v4\.0\.0</a>
+ - <a href="#release-summary-8">Release Summary</a>
+ - <a href="#minor-changes-1">Minor Changes</a>
+ - <a href="#breaking-changes--porting-guide-2">Breaking Changes / Porting Guide</a>
+- <a href="#v3-4-0">v3\.4\.0</a>
+ - <a href="#release-summary-9">Release Summary</a>
+ - <a href="#minor-changes-2">Minor Changes</a>
+ - <a href="#bugfixes-2">Bugfixes</a>
+ - <a href="#new-modules-3">New Modules</a>
+- <a href="#v3-3-1">v3\.3\.1</a>
+ - <a href="#release-summary-10">Release Summary</a>
+- <a href="#v3-3-0">v3\.3\.0</a>
+ - <a href="#release-summary-11">Release Summary</a>
+ - <a href="#minor-changes-3">Minor Changes</a>
+- <a href="#v3-2-0">v3\.2\.0</a>
+ - <a href="#release-summary-12">Release Summary</a>
+ - <a href="#minor-changes-4">Minor Changes</a>
+ - <a href="#bugfixes-3">Bugfixes</a>
+- <a href="#v3-1-0">v3\.1\.0</a>
+ - <a href="#release-summary-13">Release Summary</a>
+ - <a href="#deprecated-features-2">Deprecated Features</a>
+ - <a href="#bugfixes-4">Bugfixes</a>
+- <a href="#v3-0-0">v3\.0\.0</a>
+ - <a href="#release-summary-14">Release Summary</a>
+ - <a href="#deprecated-features-3">Deprecated Features</a>
+ - <a href="#removed-features-previously-deprecated-1">Removed Features \(previously deprecated\)</a>
+- <a href="#v2-5-0">v2\.5\.0</a>
+ - <a href="#release-summary-15">Release Summary</a>
+ - <a href="#minor-changes-5">Minor Changes</a>
+ - <a href="#deprecated-features-4">Deprecated Features</a>
+ - <a href="#new-plugins-1">New Plugins</a>
+ - <a href="#lookup-1">Lookup</a>
+ - <a href="#new-modules-4">New Modules</a>
+- <a href="#v2-4-0">v2\.4\.0</a>
+ - <a href="#release-summary-16">Release Summary</a>
+ - <a href="#new-plugins-2">New Plugins</a>
+ - <a href="#lookup-2">Lookup</a>
+ - <a href="#new-modules-5">New Modules</a>
+- <a href="#v2-3-0">v2\.3\.0</a>
+ - <a href="#release-summary-17">Release Summary</a>
+ - <a href="#new-plugins-3">New Plugins</a>
+ - <a href="#lookup-3">Lookup</a>
+ - <a href="#new-modules-6">New Modules</a>
+- <a href="#v2-2-0">v2\.2\.0</a>
+ - <a href="#release-summary-18">Release Summary</a>
+ - <a href="#minor-changes-6">Minor Changes</a>
+ - <a href="#new-plugins-4">New Plugins</a>
+ - <a href="#filter">Filter</a>
+ - <a href="#lookup-4">Lookup</a>
+ - <a href="#new-modules-7">New Modules</a>
+- <a href="#v2-1-0">v2\.1\.0</a>
+ - <a href="#release-summary-19">Release Summary</a>
+ - <a href="#deprecated-features-5">Deprecated Features</a>
+ - <a href="#removed-features-previously-deprecated-2">Removed Features \(previously deprecated\)</a>
+- <a href="#v2-0-0">v2\.0\.0</a>
+ - <a href="#release-summary-20">Release Summary</a>
+ - <a href="#breaking-changes--porting-guide-3">Breaking Changes / Porting Guide</a>
+ - <a href="#removed-features-previously-deprecated-3">Removed Features \(previously deprecated\)</a>
+- <a href="#v1-5-0">v1\.5\.0</a>
+ - <a href="#release-summary-21">Release Summary</a>
+ - <a href="#minor-changes-7">Minor Changes</a>
+- <a href="#v1-4-1">v1\.4\.1</a>
+ - <a href="#release-summary-22">Release Summary</a>
+ - <a href="#bugfixes-5">Bugfixes</a>
+- <a href="#v1-4-0">v1\.4\.0</a>
+ - <a href="#release-summary-23">Release Summary</a>
+ - <a href="#minor-changes-8">Minor Changes</a>
+ - <a href="#deprecated-features-6">Deprecated Features</a>
+ - <a href="#bugfixes-6">Bugfixes</a>
+ - <a href="#new-plugins-5">New Plugins</a>
+ - <a href="#lookup-5">Lookup</a>
+ - <a href="#new-modules-8">New Modules</a>
+- <a href="#v1-3-2">v1\.3\.2</a>
+ - <a href="#release-summary-24">Release Summary</a>
+ - <a href="#minor-changes-9">Minor Changes</a>
+ - <a href="#deprecated-features-7">Deprecated Features</a>
+- <a href="#v1-3-1">v1\.3\.1</a>
+ - <a href="#release-summary-25">Release Summary</a>
+- <a href="#v1-3-0">v1\.3\.0</a>
+ - <a href="#release-summary-26">Release Summary</a>
+ - <a href="#minor-changes-10">Minor Changes</a>
+- <a href="#v1-2-0">v1\.2\.0</a>
+ - <a href="#release-summary-27">Release Summary</a>
+ - <a href="#minor-changes-11">Minor Changes</a>
+ - <a href="#deprecated-features-8">Deprecated Features</a>
+- <a href="#v1-1-3">v1\.1\.3</a>
+ - <a href="#release-summary-28">Release Summary</a>
+ - <a href="#bugfixes-7">Bugfixes</a>
+- <a href="#v1-1-2">v1\.1\.2</a>
+ - <a href="#release-summary-29">Release Summary</a>
+- <a href="#v1-1-1">v1\.1\.1</a>
+ - <a href="#release-summary-30">Release Summary</a>
+ - <a href="#bugfixes-8">Bugfixes</a>
+- <a href="#v1-1-0">v1\.1\.0</a>
+ - <a href="#release-summary-31">Release Summary</a>
+ - <a href="#minor-changes-12">Minor Changes</a>
+- <a href="#v1-0-0">v1\.0\.0</a>
+ - <a href="#release-summary-32">Release Summary</a>
+ - <a href="#breaking-changes--porting-guide-4">Breaking Changes / Porting Guide</a>
+- <a href="#v0-2-0">v0\.2\.0</a>
+ - <a href="#release-summary-33">Release Summary</a>
+ - <a href="#minor-changes-13">Minor Changes</a>
+ - <a href="#deprecated-features-9">Deprecated Features</a>
+ - <a href="#bugfixes-9">Bugfixes</a>
+- <a href="#v0-1-0">v0\.1\.0</a>
+ - <a href="#release-summary-34">Release Summary</a>
+
+<a id="v6-2-0"></a>
+## v6\.2\.0
+
+<a id="release-summary"></a>
+### Release Summary
+
+This release contains a dozen\+ new modules for working with Vault\'s database secrets engine and some new <code>vars</code> entries for specifying public and private keys in <code>cert</code> auth\.
+
+<a id="minor-changes"></a>
+### Minor Changes
+
+* cert auth \- add option to set the <code>cert\_auth\_public\_key</code> and <code>cert\_auth\_private\_key</code> parameters using the variables <code>ansible\_hashi\_vault\_cert\_auth\_public\_key</code> and <code>ansible\_hashi\_vault\_cert\_auth\_private\_key</code> \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/428](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/428)\)\.
+
+<a id="new-modules"></a>
+### New Modules
+
+* vault\_database\_connection\_configure \- Configures the database engine
+* vault\_database\_connection\_delete \- Delete a Database Connection
+* vault\_database\_connection\_read \- Returns the configuration settings for a O\(connection\_name\)
+* vault\_database\_connection\_reset \- Closes a O\(connection\_name\) and its underlying plugin and restarts it with the configuration stored
+* vault\_database\_connections\_list \- Returns a list of available connections
+* vault\_database\_role\_create \- Creates or updates a \(dynamic\) role definition
+* vault\_database\_role\_delete \- Delete a role definition
+* vault\_database\_role\_read \- Queries a dynamic role definition
+* vault\_database\_roles\_list \- Returns a list of available \(dynamic\) roles
+* vault\_database\_rotate\_root\_credentials \- Rotates the root credentials stored for the database connection\. This user must have permissions to update its own password\.
+* vault\_database\_static\_role\_create \- Create or update a static role
+* vault\_database\_static\_role\_get\_credentials \- Returns the current credentials based on the named static role
+* vault\_database\_static\_role\_read \- Queries a static role definition
+* vault\_database\_static\_role\_rotate\_credentials \- Trigger the credential rotation for a static role
+* vault\_database\_static\_roles\_list \- Returns a list of available static roles
+
+<a id="v6-1-0"></a>
+## v6\.1\.0
+
+<a id="release-summary-1"></a>
+### Release Summary
+
+This release addresses some breaking changes in core that were backported\.
+
+<a id="major-changes"></a>
+### Major Changes
+
+* requirements \- the <code>requests</code> package which is required by <code>hvac</code> now has a more restrictive range for this collection in certain use cases due to breaking security changes in <code>ansible\-core</code> that were backported \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/416](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/416)\)\.
+
+<a id="v6-0-0"></a>
+## v6\.0\.0
+
+<a id="release-summary-2"></a>
+### Release Summary
+
+This major version of the collection has no functional changes from the previous version\, however the minimum versions of <code>hvac</code> and <code>ansible\-core</code> have been raised\. While the collection may still work with those earlier versions\, future changes will not test against them\.
+
+<a id="breaking-changes--porting-guide"></a>
+### Breaking Changes / Porting Guide
+
+* The minimum required version of <code>hvac</code> is now <code>1\.2\.1</code> \([https\://docs\.ansible\.com/ansible/devel/collections/community/hashi\_vault/docsite/user\_guide\.html\#hvac\-version\-specifics](https\://docs\.ansible\.com/ansible/devel/collections/community/hashi\_vault/docsite/user\_guide\.html\#hvac\-version\-specifics)\)\.
+
+<a id="removed-features-previously-deprecated"></a>
+### Removed Features \(previously deprecated\)
+
+* The minimum supported version of <code>ansible\-core</code> is now <code>2\.14</code>\, support for <code>2\.13</code> has been dropped \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/403](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/403)\)\.
+
+<a id="v5-0-1"></a>
+## v5\.0\.1
+
+<a id="release-summary-3"></a>
+### Release Summary
+
+This release fixes a bug in <code>vault\_write</code> ahead of the collection\'s next major release\.
+
+<a id="bugfixes"></a>
+### Bugfixes
+
+* vault\_write \- the <code>vault\_write</code> lookup and module were not able to write data containing keys named <code>path</code> or <code>wrap\_ttl</code> due to a bug in the <code>hvac</code> library\. These plugins have now been updated to take advantage of fixes in <code>hvac\>\=1\.2</code> to address this \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/389](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/389)\)\.
+
+<a id="v5-0-0"></a>
+## v5\.0\.0
+
+<a id="release-summary-4"></a>
+### Release Summary
+
+This version makes some relatively minor but technically breaking changes\. Support for <code>ansible\-core</code> versions <code>2\.11</code> and <code>2\.12</code> have been dropped\, and there is now a minimum supported version of <code>hvac</code> which will be updated over time\. A warning in the <code>hashi\_vault</code> lookup on duplicate option specifications in the term string has been changed to a fatal error\.
+
+<a id="breaking-changes--porting-guide-1"></a>
+### Breaking Changes / Porting Guide
+
+* Support for <code>ansible\-core</code> 2\.11 and 2\.12 has been removed \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/340](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/340)\)\.
+* The minimum version of <code>hvac</code> for <code>community\.hashi\_vault</code> is now <code>1\.1\.0</code> \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/324](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/324)\)\.
+* hashi\_vault lookup \- duplicate option entries in the term string now raises an exception instead of a warning \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/356](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/356)\)\.
+
+<a id="v4-2-1"></a>
+## v4\.2\.1
+
+<a id="release-summary-5"></a>
+### Release Summary
+
+This patch version updates the documentation for the <code>vault\_kv2\_write</code> module\. There are no functional changes\.
+
+<a id="v4-2-0"></a>
+## v4\.2\.0
+
+<a id="release-summary-6"></a>
+### Release Summary
+
+This release contains a new module for KVv2 writes\, and a new warning for duplicated term string options in the <code>hashi\_vault</code> lookup\.
+
+<a id="deprecated-features"></a>
+### Deprecated Features
+
+* hashi\_vault lookup \- in <code>v5\.0\.0</code> duplicate term string options will raise an exception instead of showing a warning \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/356](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/356)\)\.
+
+<a id="bugfixes-1"></a>
+### Bugfixes
+
+* hashi\_vault lookup \- a term string with duplicate options would silently use the last value\. The lookup now shows a warning on option duplication \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/349](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/349)\)\.
+
+<a id="new-modules-1"></a>
+### New Modules
+
+* vault\_kv2\_write \- Perform a write operation against a KVv2 secret in HashiCorp Vault
+
+<a id="v4-1-0"></a>
+## v4\.1\.0
+
+<a id="release-summary-7"></a>
+### Release Summary
+
+This release brings new generic <code>vault\_list</code> plugins from a new contributor\!
+There are also some deprecation notices for the next major version\, and some updates to documentation attributes\.
+
+<a id="deprecated-features-1"></a>
+### Deprecated Features
+
+* ansible\-core \- support for <code>ansible\-core</code> versions <code>2\.11</code> and <code>2\.12</code> will be dropped in collection version <code>5\.0\.0</code>\, making <code>2\.13</code> the minimum supported version of <code>ansible\-core</code> \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/340](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/340)\)\.
+* hvac \- the minimum version of <code>hvac</code> to be supported in collection version <code>5\.0\.0</code> will be at least <code>1\.0\.2</code>\; this minimum may be raised before <code>5\.0\.0</code> is released\, so please subscribe to the linked issue and look out for new notices in the changelog \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/324](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/324)\)\.
+
+<a id="new-plugins"></a>
+### New Plugins
+
+<a id="lookup"></a>
+#### Lookup
+
+* vault\_list \- Perform a list operation against HashiCorp Vault
+
+<a id="new-modules-2"></a>
+### New Modules
+
+* vault\_list \- Perform a list operation against HashiCorp Vault
+
+<a id="v4-0-0"></a>
+## v4\.0\.0
+
+<a id="release-summary-8"></a>
+### Release Summary
+
+The next major version of the collection includes previously announced breaking changes to some default values\, and improvements to module documentation with attributes that describe the use of action groups and check mode support\.
+
+<a id="minor-changes-1"></a>
+### Minor Changes
+
+* modules \- all modules now document their action group and support for check mode in their attributes documentation \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/197](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/197)\)\.
+
+<a id="breaking-changes--porting-guide-2"></a>
+### Breaking Changes / Porting Guide
+
+* auth \- the default value for <code>token\_validate</code> has changed from <code>true</code> to <code>false</code>\, as previously announced \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/248](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/248)\)\.
+* vault\_kv2\_get lookup \- as previously announced\, the default value for <code>engine\_mount\_point</code> in the <code>vault\_kv2\_get</code> lookup has changed from <code>kv</code> to <code>secret</code> \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/279](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/279)\)\.
+
+<a id="v3-4-0"></a>
+## v3\.4\.0
+
+<a id="release-summary-9"></a>
+### Release Summary
+
+This release includes a new module\, fixes \(another\) <code>requests</code> header issue\, and updates some inaccurate documentation\.
+This is the last planned release before v4\.0\.0\.
+
+<a id="minor-changes-2"></a>
+### Minor Changes
+
+* vault\_pki\_generate\_certificate \- the documentation has been updated to match the argspec for the default values of options <code>alt\_names</code>\, <code>ip\_sans</code>\, <code>other\_sans</code>\, and <code>uri\_sans</code> \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/318](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/318)\)\.
+
+<a id="bugfixes-2"></a>
+### Bugfixes
+
+* connection options \- the <code>namespace</code> connection option will be forced into a string to ensure cmpatibility with recent <code>requests</code> versions \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/309](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/309)\)\.
+
+<a id="new-modules-3"></a>
+### New Modules
+
+* vault\_kv2\_delete \- Delete one or more versions of a secret from HashiCorp Vault\'s KV version 2 secret store
+
+<a id="v3-3-1"></a>
+## v3\.3\.1
+
+<a id="release-summary-10"></a>
+### Release Summary
+
+No functional changes in this release\, this provides updated filter documentation for the public docsite\.
+
+<a id="v3-3-0"></a>
+## v3\.3\.0
+
+<a id="release-summary-11"></a>
+### Release Summary
+
+With the release of <code>hvac</code> version <code>1\.0\.0</code>\, we needed to update <code>vault\_token\_create</code>\'s support for orphan tokens\.
+The collection\'s changelog is now viewable in the Ansible documentation site\.
+
+<a id="minor-changes-3"></a>
+### Minor Changes
+
+* vault\_token\_create \- creation or orphan tokens uses <code>hvac</code>\'s new v1 method for creating orphans\, or falls back to the v0 method if needed \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/301](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/301)\)\.
+
+<a id="v3-2-0"></a>
+## v3\.2\.0
+
+<a id="release-summary-12"></a>
+### Release Summary
+
+This release brings support for the <code>azure</code> auth method\, adds <code>412</code> to the default list of HTTP status codes to be retried\, and fixes a bug that causes failures in token auth with <code>requests\>\=2\.28\.0</code>\.
+
+<a id="minor-changes-4"></a>
+### Minor Changes
+
+* community\.hashi\_vault collection \- add support for <code>azure</code> auth method\, for Azure service principal\, managed identity\, or plain JWT access token \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/293](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/293)\)\.
+* community\.hashi\_vault retries \- [HTTP status code 412](https\://www\.vaultproject\.io/api\-docs\#412) has been added to the default list of codes to be retried\, for the new [Server Side Consistent Token feature](https\://www\.vaultproject\.io/docs/faq/ssct\#q\-is\-there\-anything\-else\-i\-need\-to\-consider\-to\-achieve\-consistency\-besides\-upgrading\-to\-vault\-1\-10) in Vault Enterprise \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/290](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/290)\)\.
+
+<a id="bugfixes-3"></a>
+### Bugfixes
+
+* community\.hashi\_vault plugins \- tokens will be cast to a string type before being sent to <code>hvac</code> to prevent errors in <code>requests</code> when values are <code>AnsibleUnsafe</code> \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/289](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/289)\)\.
+* modules \- fix a \"variable used before assignment\" that cannot be reached but causes sanity test failures \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/296](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/296)\)\.
+
+<a id="v3-1-0"></a>
+## v3\.1\.0
+
+<a id="release-summary-13"></a>
+### Release Summary
+
+A default value that was set incorrectly will be corrected in <code>4\.0\.0</code>\.
+A deprecation warning will be shown until then if the value is not specified explicitly\.
+This version also includes some fixes and improvements to the licensing in the collection\, which does not affect any functionality\.
+
+<a id="deprecated-features-2"></a>
+### Deprecated Features
+
+* vault\_kv2\_get lookup \- the <code>engine\_mount\_point option</code> in the <code>vault\_kv2\_get</code> lookup only will change its default from <code>kv</code> to <code>secret</code> in community\.hashi\_vault version 4\.0\.0 \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/279](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/279)\)\.
+
+<a id="bugfixes-4"></a>
+### Bugfixes
+
+* Add SPDX license headers to individual files \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/282](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/282)\)\.
+* Add missing <code>BSD\-2\-Clause\.txt</code> file for BSD licensed content \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/275](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/275)\)\.
+* Use the correct GPL license for plugin\_utils \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/276](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/276)\)\.
+
+<a id="v3-0-0"></a>
+## v3\.0\.0
+
+<a id="release-summary-14"></a>
+### Release Summary
+
+Version 3\.0\.0 of <code>community\.hashi\_vault</code> drops support for Ansible 2\.9 and ansible\-base 2\.10\.
+Several deprecated features have been removed\. See the changelog for the full list\.
+
+<a id="deprecated-features-3"></a>
+### Deprecated Features
+
+* token\_validate options \- the shared auth option <code>token\_validate</code> will change its default from <code>true</code> to <code>false</code> in community\.hashi\_vault version 4\.0\.0\. The <code>vault\_login</code> lookup and module will keep the default value of <code>true</code> \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/248](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/248)\)\.
+
+<a id="removed-features-previously-deprecated-1"></a>
+### Removed Features \(previously deprecated\)
+
+* aws\_iam auth \- the deprecated alias <code>aws\_iam\_login</code> for the <code>aws\_iam</code> value of the <code>auth\_method</code> option has been removed \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/194](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/194)\)\.
+* community\.hashi\_vault collection \- support for Ansible 2\.9 and ansible\-base 2\.10 has been removed \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/189](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/189)\)\.
+* hashi\_vault lookup \- the deprecated <code>\[lookup\_hashi\_vault\]</code> INI config section has been removed in favor of the collection\-wide <code>\[hashi\_vault\_collection\]</code> section \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/179](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/179)\)\.
+
+<a id="v2-5-0"></a>
+## v2\.5\.0
+
+<a id="release-summary-15"></a>
+### Release Summary
+
+This release finally contains dedicated KV plugins and modules\, and an exciting new lookup to help use plugin values in module calls\.
+With that\, we also have a guide in the collection docsite for migrating away from the <code>hashi\_vault</code> lookup toward dedicated content\.
+We are also announcing that the <code>token\_validate</code> option will change its default value in version 4\.0\.0\.
+This is the last planned release before 3\.0\.0\. See the porting guide for breaking changes and removed features in the next version\.
+
+<a id="minor-changes-5"></a>
+### Minor Changes
+
+* vault\_login module \& lookup \- no friendly error message was given when <code>hvac</code> was missing \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/257](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/257)\)\.
+* vault\_pki\_certificate \- add <code>vault\_pki\_certificate</code> to the <code>community\.hashi\_vault\.vault</code> action group \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/251](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/251)\)\.
+* vault\_read module \& lookup \- no friendly error message was given when <code>hvac</code> was missing \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/257](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/257)\)\.
+* vault\_token\_create \- add <code>vault\_token\_create</code> to the <code>community\.hashi\_vault\.vault</code> action group \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/251](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/251)\)\.
+* vault\_token\_create module \& lookup \- no friendly error message was given when <code>hvac</code> was missing \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/257](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/257)\)\.
+* vault\_write \- add <code>vault\_write</code> to the <code>community\.hashi\_vault\.vault</code> action group \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/251](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/251)\)\.
+
+<a id="deprecated-features-4"></a>
+### Deprecated Features
+
+* token\_validate options \- the shared auth option <code>token\_validate</code> will change its default from <code>True</code> to <code>False</code> in community\.hashi\_vault version 4\.0\.0\. The <code>vault\_login</code> lookup and module will keep the default value of <code>True</code> \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/248](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/248)\)\.
+
+<a id="new-plugins-1"></a>
+### New Plugins
+
+<a id="lookup-1"></a>
+#### Lookup
+
+* vault\_ansible\_settings \- Returns plugin settings \(options\)
+* vault\_kv1\_get \- Get a secret from HashiCorp Vault\'s KV version 1 secret store
+* vault\_kv2\_get \- Get a secret from HashiCorp Vault\'s KV version 2 secret store
+
+<a id="new-modules-4"></a>
+### New Modules
+
+* vault\_kv1\_get \- Get a secret from HashiCorp Vault\'s KV version 1 secret store
+* vault\_kv2\_get \- Get a secret from HashiCorp Vault\'s KV version 2 secret store
+
+<a id="v2-4-0"></a>
+## v2\.4\.0
+
+<a id="release-summary-16"></a>
+### Release Summary
+
+Our first content for writing to Vault is now live\.
+
+<a id="new-plugins-2"></a>
+### New Plugins
+
+<a id="lookup-2"></a>
+#### Lookup
+
+* vault\_write \- Perform a write operation against HashiCorp Vault
+
+<a id="new-modules-5"></a>
+### New Modules
+
+* vault\_write \- Perform a write operation against HashiCorp Vault
+
+<a id="v2-3-0"></a>
+## v2\.3\.0
+
+<a id="release-summary-17"></a>
+### Release Summary
+
+This release contains new plugins and modules for creating tokens and for generating certificates with Vault\'s PKI secrets engine\.
+
+<a id="new-plugins-3"></a>
+### New Plugins
+
+<a id="lookup-3"></a>
+#### Lookup
+
+* vault\_token\_create \- Create a HashiCorp Vault token
+
+<a id="new-modules-6"></a>
+### New Modules
+
+* vault\_pki\_generate\_certificate \- Generates a new set of credentials \(private key and certificate\) using HashiCorp Vault PKI
+* vault\_token\_create \- Create a HashiCorp Vault token
+
+<a id="v2-2-0"></a>
+## v2\.2\.0
+
+<a id="release-summary-18"></a>
+### Release Summary
+
+This release contains a new lookup/module combo for logging in to Vault\, and includes our first filter plugin\.
+
+<a id="minor-changes-6"></a>
+### Minor Changes
+
+* The Filter guide has been added to the collection\'s docsite\.
+
+<a id="new-plugins-4"></a>
+### New Plugins
+
+<a id="filter"></a>
+#### Filter
+
+* vault\_login\_token \- Extracts the client token from a Vault login response
+
+<a id="lookup-4"></a>
+#### Lookup
+
+* vault\_login \- Perform a login operation against HashiCorp Vault
+
+<a id="new-modules-7"></a>
+### New Modules
+
+* vault\_login \- Perform a login operation against HashiCorp Vault
+
+<a id="v2-1-0"></a>
+## v2\.1\.0
+
+<a id="release-summary-19"></a>
+### Release Summary
+
+The most important change in this release is renaming the <code>aws\_iam\_login</code> auth method to <code>aws\_iam</code> and deprecating the old name\. This release also announces the deprecation of Ansible 2\.9 and ansible\-base 2\.10 support in 3\.0\.0\.
+
+<a id="deprecated-features-5"></a>
+### Deprecated Features
+
+* Support for Ansible 2\.9 and ansible\-base 2\.10 is deprecated\, and will be removed in the next major release \(community\.hashi\_vault 3\.0\.0\) next spring \([https\://github\.com/ansible\-community/community\-topics/issues/50](https\://github\.com/ansible\-community/community\-topics/issues/50)\, [https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/189](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/189)\)\.
+* aws\_iam\_login auth method \- the <code>aws\_iam\_login</code> method has been renamed to <code>aws\_iam</code>\. The old name will be removed in collection version <code>3\.0\.0</code>\. Until then both names will work\, and a warning will be displayed when using the old name \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/193](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/193)\)\.
+
+<a id="removed-features-previously-deprecated-2"></a>
+### Removed Features \(previously deprecated\)
+
+* the \"legacy\" integration test setup has been removed\; this does not affect end users and is only relevant to contributors \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/191](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/191)\)\.
+
+<a id="v2-0-0"></a>
+## v2\.0\.0
+
+<a id="release-summary-20"></a>
+### Release Summary
+
+Version 2\.0\.0 of the collection drops support for Python 2 \& Python 3\.5\, making Python 3\.6 the minimum supported version\.
+Some deprecated features and settings have been removed as well\.
+
+<a id="breaking-changes--porting-guide-3"></a>
+### Breaking Changes / Porting Guide
+
+* connection options \- there is no longer a default value for the <code>url</code> option \(the Vault address\)\, so a value must be supplied \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/83](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/83)\)\.
+
+<a id="removed-features-previously-deprecated-3"></a>
+### Removed Features \(previously deprecated\)
+
+* drop support for Python 2 and Python 3\.5 \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/81](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/81)\)\.
+* support for the following deprecated environment variables has been removed\: <code>VAULT\_AUTH\_METHOD</code>\, <code>VAULT\_TOKEN\_PATH</code>\, <code>VAULT\_TOKEN\_FILE</code>\, <code>VAULT\_ROLE\_ID</code>\, <code>VAULT\_SECRET\_ID</code> \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/173](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/173)\)\.
+
+<a id="v1-5-0"></a>
+## v1\.5\.0
+
+<a id="release-summary-21"></a>
+### Release Summary
+
+This release includes a new action group for use with <code>module\_defaults</code>\, and additional ways of specifying the <code>mount\_point</code> option for plugins\.
+This will be the last <code>1\.x</code> release\.
+
+<a id="minor-changes-7"></a>
+### Minor Changes
+
+* add the <code>community\.hashi\_vault\.vault</code> action group \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/172](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/172)\)\.
+* auth methods \- Add support for configuring the <code>mount\_point</code> auth method option in plugins via the <code>ANSIBLE\_HASHI\_VAULT\_MOUNT\_POINT</code> environment variable\, <code>ansible\_hashi\_vault\_mount\_point</code> ansible variable\, or <code>mount\_point</code> INI section \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/171](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/171)\)\.
+
+<a id="v1-4-1"></a>
+## v1\.4\.1
+
+<a id="release-summary-22"></a>
+### Release Summary
+
+This release contains a bugfix for <code>aws\_iam\_login</code> authentication\.
+
+<a id="bugfixes-5"></a>
+### Bugfixes
+
+* aws\_iam\_login auth method \- fix incorrect use of <code>boto3</code>/<code>botocore</code> that prevented proper loading of AWS IAM role credentials \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/167](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/167)\)\.
+
+<a id="v1-4-0"></a>
+## v1\.4\.0
+
+<a id="release-summary-23"></a>
+### Release Summary
+
+This release includes bugfixes\, a new auth method \(<code>cert</code>\)\, and the first new content since the collection\'s formation\, the <code>vault\_read</code> module and lookup plugin\.
+We\'re also announcing the deprecation of the <code>\[lookup\_hashi\_vault\]</code> INI section \(which will continue working up until its removal only for the <code>hashi\_vault</code> lookup\)\, to be replaced by the <code>\[hashi\_vault\_collection\]</code> section that will apply to all plugins in the collection\.
+
+<a id="minor-changes-8"></a>
+### Minor Changes
+
+* community\.hashi\_vault collection \- add cert auth method \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/159](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/159)\)\.
+
+<a id="deprecated-features-6"></a>
+### Deprecated Features
+
+* lookup hashi\_vault \- the <code>\[lookup\_hashi\_vault\]</code> section in the <code>ansible\.cfg</code> file is deprecated and will be removed in collection version <code>3\.0\.0</code>\. Instead\, the section <code>\[hashi\_vault\_collection\]</code> can be used\, which will apply to all plugins in the collection going forward \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/144](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/144)\)\.
+
+<a id="bugfixes-6"></a>
+### Bugfixes
+
+* aws\_iam\_login auth \- the <code>aws\_security\_token</code> option was not used\, causing assumed role credentials to fail \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/160](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/160)\)\.
+* hashi\_vault collection \- a fallback import supporting the <code>retries</code> option for <code>urllib3</code> via <code>requests\.packages\.urllib3</code> was not correctly formed \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/116](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/116)\)\.
+* hashi\_vault collection \- unhandled exception with <code>token</code> auth when <code>token\_file</code> exists but is a directory \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/152](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/152)\)\.
+
+<a id="new-plugins-5"></a>
+### New Plugins
+
+<a id="lookup-5"></a>
+#### Lookup
+
+* vault\_read \- Perform a read operation against HashiCorp Vault
+
+<a id="new-modules-8"></a>
+### New Modules
+
+* vault\_read \- Perform a read operation against HashiCorp Vault
+
+<a id="v1-3-2"></a>
+## v1\.3\.2
+
+<a id="release-summary-24"></a>
+### Release Summary
+
+This release adds requirements detection support for Ansible Execution Environments\. It also updates and adds new guides in our [collection docsite](https\://docs\.ansible\.com/ansible/devel/collections/community/hashi\_vault)\.
+This release also announces the dropping of Python 3\.5 support in version <code>2\.0\.0</code> of the collection\, alongside the previous announcement dropping Python 2\.x in <code>2\.0\.0</code>\.
+
+<a id="minor-changes-9"></a>
+### Minor Changes
+
+* hashi\_vault collection \- add <code>execution\-environment\.yml</code> and a python requirements file to better support <code>ansible\-builder</code> \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/105](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/105)\)\.
+
+<a id="deprecated-features-7"></a>
+### Deprecated Features
+
+* hashi\_vault collection \- support for Python 3\.5 will be dropped in version <code>2\.0\.0</code> of <code>community\.hashi\_vault</code> \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/81](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/81)\)\.
+
+<a id="v1-3-1"></a>
+## v1\.3\.1
+
+<a id="release-summary-25"></a>
+### Release Summary
+
+This release fixes an error in the documentation\. No functionality is changed so it\'s not necessary to upgrade from <code>1\.3\.0</code>\.
+
+<a id="v1-3-0"></a>
+## v1\.3\.0
+
+<a id="release-summary-26"></a>
+### Release Summary
+
+This release adds two connection\-based options for controlling timeouts and retrying failed Vault requests\.
+
+<a id="minor-changes-10"></a>
+### Minor Changes
+
+* hashi\_vault lookup \- add <code>retries</code> and <code>retry\_action</code> to enable built\-in retry on failure \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/71](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/71)\)\.
+* hashi\_vault lookup \- add <code>timeout</code> option to control connection timeouts \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/100](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/100)\)\.
+
+<a id="v1-2-0"></a>
+## v1\.2\.0
+
+<a id="release-summary-27"></a>
+### Release Summary
+
+This release brings several new ways of accessing options\, like using Ansible vars\, and addng new environment variables and INI config entries\.
+A special <code>none</code> auth type is also added\, for working with certain Vault Agent configurations\.
+This release also announces the deprecation of Python 2 support in version <code>2\.0\.0</code> of the collection\.
+
+<a id="minor-changes-11"></a>
+### Minor Changes
+
+* hashi\_vault lookup \- add <code>ANSIBLE\_HASHI\_VAULT\_CA\_CERT</code> env var \(with <code>VAULT\_CACERT</code> low\-precedence fallback\) for <code>ca\_cert</code> option \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/97](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/97)\)\.
+* hashi\_vault lookup \- add <code>ANSIBLE\_HASHI\_VAULT\_PASSWORD</code> env var and <code>ansible\_hashi\_vault\_password</code> ansible var for <code>password</code> option \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/96](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/96)\)\.
+* hashi\_vault lookup \- add <code>ANSIBLE\_HASHI\_VAULT\_USERNAME</code> env var and <code>ansible\_hashi\_vault\_username</code> ansible var for <code>username</code> option \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/96](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/96)\)\.
+* hashi\_vault lookup \- add <code>ansible\_hashi\_vault\_auth\_method</code> Ansible vars entry to the <code>proxies</code> option \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/86](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/86)\)\.
+* hashi\_vault lookup \- add <code>ansible\_hashi\_vault\_ca\_cert</code> ansible var for <code>ca\_cert</code> option \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/97](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/97)\)\.
+* hashi\_vault lookup \- add <code>ansible\_hashi\_vault\_namespace</code> Ansible vars entry to the <code>namespace</code> option \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/86](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/86)\)\.
+* hashi\_vault lookup \- add <code>ansible\_hashi\_vault\_proxies</code> Ansible vars entry to the <code>proxies</code> option \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/86](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/86)\)\.
+* hashi\_vault lookup \- add <code>ansible\_hashi\_vault\_role\_id</code> Ansible vars entry to the <code>proxies</code> option \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/86](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/86)\)\.
+* hashi\_vault lookup \- add <code>ansible\_hashi\_vault\_secret\_id</code> Ansible vars entry to the <code>proxies</code> option \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/86](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/86)\)\.
+* hashi\_vault lookup \- add <code>ansible\_hashi\_vault\_token\_file</code> Ansible vars entry to the <code>token\_file</code> option \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/95](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/95)\)\.
+* hashi\_vault lookup \- add <code>ansible\_hashi\_vault\_token\_path</code> Ansible vars entry to the <code>token\_path</code> option \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/95](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/95)\)\.
+* hashi\_vault lookup \- add <code>ansible\_hashi\_vault\_token\_validate</code> Ansible vars entry to the <code>proxies</code> option \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/86](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/86)\)\.
+* hashi\_vault lookup \- add <code>ansible\_hashi\_vault\_token</code> Ansible vars entry to the <code>proxies</code> option \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/86](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/86)\)\.
+* hashi\_vault lookup \- add <code>ansible\_hashi\_vault\_url</code> and <code>ansible\_hashi\_vault\_addr</code> Ansible vars entries to the <code>url</code> option \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/86](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/86)\)\.
+* hashi\_vault lookup \- add <code>ansible\_hashi\_vault\_validate\_certs</code> Ansible vars entry to the <code>validate\_certs</code> option \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/95](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/95)\)\.
+* hashi\_vault lookup \- add <code>ca\_cert</code> INI config file key <code>ca\_cert</code> option \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/97](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/97)\)\.
+* hashi\_vault lookup \- add <code>none</code> auth type which allows for passive auth via a Vault agent \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/80](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/80)\)\.
+
+<a id="deprecated-features-8"></a>
+### Deprecated Features
+
+* hashi\_vault collection \- support for Python 2 will be dropped in version <code>2\.0\.0</code> of <code>community\.hashi\_vault</code> \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/81](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/81)\)\.
+
+<a id="v1-1-3"></a>
+## v1\.1\.3
+
+<a id="release-summary-28"></a>
+### Release Summary
+
+This release fixes a bug with <code>userpass</code> authentication and <code>hvac</code> versions 0\.9\.6 and higher\.
+
+<a id="bugfixes-7"></a>
+### Bugfixes
+
+* hashi\_vault \- userpass authentication did not work with hvac 0\.9\.6 or higher \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/68](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/68)\)\.
+
+<a id="v1-1-2"></a>
+## v1\.1\.2
+
+<a id="release-summary-29"></a>
+### Release Summary
+
+This release contains the same functionality as 1\.1\.1\. The only change is to mark some code as internal to the collection\. If you are already using 1\.1\.1 as an end user you do not need to update\.
+
+<a id="v1-1-1"></a>
+## v1\.1\.1
+
+<a id="release-summary-30"></a>
+### Release Summary
+
+This bugfix release restores the use of the <code>VAULT\_ADDR</code> environment variable for setting the <code>url</code> option\.
+See the PR linked from the changelog entry for details and workarounds if you cannot upgrade\.
+
+<a id="bugfixes-8"></a>
+### Bugfixes
+
+* hashi\_vault \- restore use of <code>VAULT\_ADDR</code> environment variable as a low preference env var \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/61](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/61)\)\.
+
+<a id="v1-1-0"></a>
+## v1\.1\.0
+
+<a id="release-summary-31"></a>
+### Release Summary
+
+This release contains a new <code>proxies</code> option for the <code>hashi\_vault</code> lookup\.
+
+<a id="minor-changes-12"></a>
+### Minor Changes
+
+* hashi\_vault \- add <code>proxies</code> option \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/50](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/50)\)\.
+
+<a id="v1-0-0"></a>
+## v1\.0\.0
+
+<a id="release-summary-32"></a>
+### Release Summary
+
+Our first major release contains a single breaking change that will affect only a small subset of users\. No functionality is removed\. See the details in the changelog to determine if you\'re affected and if so how to transition to remediate\.
+
+<a id="breaking-changes--porting-guide-4"></a>
+### Breaking Changes / Porting Guide
+
+* hashi\_vault \- the <code>VAULT\_ADDR</code> environment variable is now checked last for the <code>url</code> parameter\. For details on which use cases are impacted\, see \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/8](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/8)\)\.
+
+<a id="v0-2-0"></a>
+## v0\.2\.0
+
+<a id="release-summary-33"></a>
+### Release Summary
+
+Several backwards\-compatible bugfixes and enhancements in this release\.
+Some environment variables are deprecated and have standardized replacements\.
+
+<a id="minor-changes-13"></a>
+### Minor Changes
+
+* Add optional <code>aws\_iam\_server\_id</code> parameter as the value for <code>X\-Vault\-AWS\-IAM\-Server\-ID</code> header \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/27](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/27)\)\.
+* hashi\_vault \- <code>ANSIBLE\_HASHI\_VAULT\_ADDR</code> environment variable added for option <code>url</code> \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/8](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/8)\)\.
+* hashi\_vault \- <code>ANSIBLE\_HASHI\_VAULT\_AUTH\_METHOD</code> environment variable added for option <code>auth\_method</code> \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/17](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/17)\)\.
+* hashi\_vault \- <code>ANSIBLE\_HASHI\_VAULT\_ROLE\_ID</code> environment variable added for option <code>role\_id</code> \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/20](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/20)\)\.
+* hashi\_vault \- <code>ANSIBLE\_HASHI\_VAULT\_SECRET\_ID</code> environment variable added for option <code>secret\_id</code> \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/20](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/20)\)\.
+* hashi\_vault \- <code>ANSIBLE\_HASHI\_VAULT\_TOKEN\_FILE</code> environment variable added for option <code>token\_file</code> \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/15](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/15)\)\.
+* hashi\_vault \- <code>ANSIBLE\_HASHI\_VAULT\_TOKEN\_PATH</code> environment variable added for option <code>token\_path</code> \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/15](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/15)\)\.
+* hashi\_vault \- <code>namespace</code> parameter can be specified in INI or via env vars <code>ANSIBLE\_HASHI\_VAULT\_NAMESPACE</code> \(new\) and <code>VAULT\_NAMESPACE</code> \(lower preference\) \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/14](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/14)\)\.
+* hashi\_vault \- <code>token</code> parameter can now be specified via <code>ANSIBLE\_HASHI\_VAULT\_TOKEN</code> as well as via <code>VAULT\_TOKEN</code> \(the latter with lower preference\) \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/16](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/16)\)\.
+* hashi\_vault \- add <code>token\_validate</code> option to control token validation \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/24](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/24)\)\.
+* hashi\_vault \- uses new AppRole method in hvac 0\.10\.6 with fallback to deprecated method with warning \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/33](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/33)\)\.
+
+<a id="deprecated-features-9"></a>
+### Deprecated Features
+
+* hashi\_vault \- <code>VAULT\_ADDR</code> environment variable for option <code>url</code> will have its precedence lowered in 1\.0\.0\; use <code>ANSIBLE\_HASHI\_VAULT\_ADDR</code> to intentionally override a config value \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/8](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/8)\)\.
+* hashi\_vault \- <code>VAULT\_AUTH\_METHOD</code> environment variable for option <code>auth\_method</code> will be removed in 2\.0\.0\, use <code>ANSIBLE\_HASHI\_VAULT\_AUTH\_METHOD</code> instead \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/17](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/17)\)\.
+* hashi\_vault \- <code>VAULT\_ROLE\_ID</code> environment variable for option <code>role\_id</code> will be removed in 2\.0\.0\, use <code>ANSIBLE\_HASHI\_VAULT\_ROLE\_ID</code> instead \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/20](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/20)\)\.
+* hashi\_vault \- <code>VAULT\_SECRET\_ID</code> environment variable for option <code>secret\_id</code> will be removed in 2\.0\.0\, use <code>ANSIBLE\_HASHI\_VAULT\_SECRET\_ID</code> instead \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/20](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/20)\)\.
+* hashi\_vault \- <code>VAULT\_TOKEN\_FILE</code> environment variable for option <code>token\_file</code> will be removed in 2\.0\.0\, use <code>ANSIBLE\_HASHI\_VAULT\_TOKEN\_FILE</code> instead \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/15](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/15)\)\.
+* hashi\_vault \- <code>VAULT\_TOKEN\_PATH</code> environment variable for option <code>token\_path</code> will be removed in 2\.0\.0\, use <code>ANSIBLE\_HASHI\_VAULT\_TOKEN\_PATH</code> instead \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/15](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/15)\)\.
+
+<a id="bugfixes-9"></a>
+### Bugfixes
+
+* hashi\_vault \- <code>mount\_point</code> parameter did not work with <code>aws\_iam\_login</code> auth method \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/7](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/7)\)
+* hashi\_vault \- fallback logic for handling deprecated style of auth in hvac was not implemented correctly \([https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/33](https\://github\.com/ansible\-collections/community\.hashi\_vault/pull/33)\)\.
+* hashi\_vault \- parameter <code>mount\_point</code> does not work with JWT auth \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/29](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/29)\)\.
+* hashi\_vault \- tokens without <code>lookup\-self</code> ability can\'t be used because of validation \([https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/18](https\://github\.com/ansible\-collections/community\.hashi\_vault/issues/18)\)\.
+
+<a id="v0-1-0"></a>
+## v0\.1\.0
+
+<a id="release-summary-34"></a>
+### Release Summary
+
+Our first release matches the <code>hashi\_vault</code> lookup functionality provided by <code>community\.general</code> version <code>1\.3\.0</code>\.
diff --git a/ansible_collections/community/hashi_vault/CHANGELOG.rst b/ansible_collections/community/hashi_vault/CHANGELOG.rst
index 5223d4a97..4362dc7f0 100644
--- a/ansible_collections/community/hashi_vault/CHANGELOG.rst
+++ b/ansible_collections/community/hashi_vault/CHANGELOG.rst
@@ -1,9 +1,99 @@
-===================================
-community.hashi_vault Release Notes
-===================================
+====================================
+community.hashi\_vault Release Notes
+====================================
.. contents:: Topics
+v6.2.0
+======
+
+Release Summary
+---------------
+
+This release contains a dozen+ new modules for working with Vault's database secrets engine and some new ``vars`` entries for specifying public and private keys in ``cert`` auth.
+
+Minor Changes
+-------------
+
+- cert auth - add option to set the ``cert_auth_public_key`` and ``cert_auth_private_key`` parameters using the variables ``ansible_hashi_vault_cert_auth_public_key`` and ``ansible_hashi_vault_cert_auth_private_key`` (https://github.com/ansible-collections/community.hashi_vault/issues/428).
+
+New Modules
+-----------
+
+- vault_database_connection_configure - Configures the database engine
+- vault_database_connection_delete - Delete a Database Connection
+- vault_database_connection_read - Returns the configuration settings for a O(connection_name)
+- vault_database_connection_reset - Closes a O(connection_name) and its underlying plugin and restarts it with the configuration stored
+- vault_database_connections_list - Returns a list of available connections
+- vault_database_role_create - Creates or updates a (dynamic) role definition
+- vault_database_role_delete - Delete a role definition
+- vault_database_role_read - Queries a dynamic role definition
+- vault_database_roles_list - Returns a list of available (dynamic) roles
+- vault_database_rotate_root_credentials - Rotates the root credentials stored for the database connection. This user must have permissions to update its own password.
+- vault_database_static_role_create - Create or update a static role
+- vault_database_static_role_get_credentials - Returns the current credentials based on the named static role
+- vault_database_static_role_read - Queries a static role definition
+- vault_database_static_role_rotate_credentials - Trigger the credential rotation for a static role
+- vault_database_static_roles_list - Returns a list of available static roles
+
+v6.1.0
+======
+
+Release Summary
+---------------
+
+This release addresses some breaking changes in core that were backported.
+
+Major Changes
+-------------
+
+- requirements - the ``requests`` package which is required by ``hvac`` now has a more restrictive range for this collection in certain use cases due to breaking security changes in ``ansible-core`` that were backported (https://github.com/ansible-collections/community.hashi_vault/pull/416).
+
+v6.0.0
+======
+
+Release Summary
+---------------
+
+This major version of the collection has no functional changes from the previous version, however the minimum versions of ``hvac`` and ``ansible-core`` have been raised. While the collection may still work with those earlier versions, future changes will not test against them.
+
+Breaking Changes / Porting Guide
+--------------------------------
+
+- The minimum required version of ``hvac`` is now ``1.2.1`` (https://docs.ansible.com/ansible/devel/collections/community/hashi_vault/docsite/user_guide.html#hvac-version-specifics).
+
+Removed Features (previously deprecated)
+----------------------------------------
+
+- The minimum supported version of ``ansible-core`` is now ``2.14``, support for ``2.13`` has been dropped (https://github.com/ansible-collections/community.hashi_vault/pull/403).
+
+v5.0.1
+======
+
+Release Summary
+---------------
+
+This release fixes a bug in ``vault_write`` ahead of the collection's next major release.
+
+Bugfixes
+--------
+
+- vault_write - the ``vault_write`` lookup and module were not able to write data containing keys named ``path`` or ``wrap_ttl`` due to a bug in the ``hvac`` library. These plugins have now been updated to take advantage of fixes in ``hvac>=1.2`` to address this (https://github.com/ansible-collections/community.hashi_vault/issues/389).
+
+v5.0.0
+======
+
+Release Summary
+---------------
+
+This version makes some relatively minor but technically breaking changes. Support for ``ansible-core`` versions ``2.11`` and ``2.12`` have been dropped, and there is now a minimum supported version of ``hvac`` which will be updated over time. A warning in the ``hashi_vault`` lookup on duplicate option specifications in the term string has been changed to a fatal error.
+
+Breaking Changes / Porting Guide
+--------------------------------
+
+- Support for ``ansible-core`` 2.11 and 2.12 has been removed (https://github.com/ansible-collections/community.hashi_vault/issues/340).
+- The minimum version of ``hvac`` for ``community.hashi_vault`` is now ``1.1.0`` (https://github.com/ansible-collections/community.hashi_vault/issues/324).
+- hashi_vault lookup - duplicate option entries in the term string now raises an exception instead of a warning (https://github.com/ansible-collections/community.hashi_vault/issues/356).
v4.2.1
======
@@ -601,4 +691,3 @@ Release Summary
---------------
Our first release matches the ``hashi_vault`` lookup functionality provided by ``community.general`` version ``1.3.0``.
-
diff --git a/ansible_collections/community/hashi_vault/FILES.json b/ansible_collections/community/hashi_vault/FILES.json
index a64ed5bf0..504a3d407 100644
--- a/ansible_collections/community/hashi_vault/FILES.json
+++ b/ansible_collections/community/hashi_vault/FILES.json
@@ -67,7 +67,7 @@
"name": ".github/actions/docker-image-versions/action.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "84f0cc9401479ea5de42f11f78b581b9e230a0676bbc6e79f2672f1a72f47912",
+ "chksum_sha256": "ed473f398e597fd8b0a9d7c8417ce59a2e1d3184b7adc3d92bed87caae970cf8",
"format": 1
},
{
@@ -81,7 +81,7 @@
"name": ".github/actions/docker-image-versions/versions.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "959b408cc5a5c6a8276906db11846cc1b5a0b73ff5761036cbfa92b410e73eee",
+ "chksum_sha256": "5002feb4c7cc3aebfc5e7e7a2eecd3f05bd75c0a151342f61eb1e49ef7dba2df",
"format": 1
},
{
@@ -109,14 +109,14 @@
"name": ".github/workflows/ansible-builder.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "09b7434235b6c0eafa5ec2649fcb3f7121917e9f18723ca0af3c239d1bc644c7",
+ "chksum_sha256": "60e927ce638ba122eb6524e00a8c85c83d8f49572e3a85bfbf1529901a90652e",
"format": 1
},
{
"name": ".github/workflows/ansible-test.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "442c8de42766184549bbc6e8f1687a80b488e71f7072d3aee57d9851c296b4d3",
+ "chksum_sha256": "f58b5fd09fea3c4f0bdf17685f636a3f0e56535c0c89a72ba130a42aa0363539",
"format": 1
},
{
@@ -137,7 +137,14 @@
"name": ".github/workflows/github-release.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cebad181da6db6c618d2e698942a868e8e4ef90ad977465ebf2396ae2947d4b7",
+ "chksum_sha256": "52d9ec1fe024e9fc8f646e9fb9afc25788c61caf9ee772bc683a890cf6c19dbd",
+ "format": 1
+ },
+ {
+ "name": ".github/dependabot.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6e34ab713019e08cae0c4c50295b17c904ee6f0c7ed1e8cf8d08213cb2772142",
"format": 1
},
{
@@ -186,14 +193,14 @@
"name": "changelogs/changelog.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a854ea29e391bde2c6bcd8c45e7081d746daff404d3f4221af5f43c7e320a142",
+ "chksum_sha256": "42eccc5898ab651d29158d22b590a0638259d6de081adda969b0bae8e6ede1fc",
"format": 1
},
{
"name": "changelogs/config.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "630354cc2146c9705841870850c9a5b3b8f61775452e45f056f3a5f84c6e5f20",
+ "chksum_sha256": "9453f4ca84464e45eb811ed5a71bb973a59ea6cc906f0e851a774a055e31f0d8",
"format": 1
},
{
@@ -221,7 +228,7 @@
"name": "docs/docsite/rst/CHANGELOG.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "79bab511c63a4f5ffdffbf0deb76f4b6aed0db672e46dc34413030f308cbba4a",
+ "chksum_sha256": "9b52d95bfa031a3b374b7a519ea045b63a7ee696cf74af9d6bf70039a5ef4816",
"format": 1
},
{
@@ -270,7 +277,7 @@
"name": "docs/docsite/rst/user_guide.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0cd48bf54449f41af3ccf83fec27be2554b3774b4bc76d7a7755a856b24b3244",
+ "chksum_sha256": "9b4394996585d6f8c236d6729c7721a785a6f69a462d31673491548d13debade",
"format": 1
},
{
@@ -354,7 +361,7 @@
"name": "meta/ee-requirements.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "21886d56af804293670e040b8dd722757ec0247cee26caec659e667991efc556",
+ "chksum_sha256": "59961a1cc5447ff1ad70a7d2d415543e1e8e17f7e242b10e1e2a792abfbe5d2b",
"format": 1
},
{
@@ -368,7 +375,7 @@
"name": "meta/runtime.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "94f270496ec3a6415ee18ae1e586e8038b1b3f43d4b03eef6d5ba764259a0724",
+ "chksum_sha256": "62ad2fcfb7ad737b4038c9e73025c96640f371bc9cdd08c8b429a53397748683",
"format": 1
},
{
@@ -396,7 +403,7 @@
"name": "plugins/doc_fragments/auth.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d983c9c2ffec0153202c74cb4d003562e2d3272e75920097bcd0dee4bf08cc12",
+ "chksum_sha256": "2f0f0a8c928449d457d100c90a60fc5c284bcd86eaa31d24062188303aea8fec",
"format": 1
},
{
@@ -459,7 +466,7 @@
"name": "plugins/lookup/hashi_vault.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1f9913f0e357c356b80860ddc23e77d435fe7bbd33caa5b907fddb42aff365b2",
+ "chksum_sha256": "fc1e9d356b44254568ecb59bc2f617c1d87122f7af2853bd0e1744a228a739f0",
"format": 1
},
{
@@ -508,14 +515,14 @@
"name": "plugins/lookup/vault_token_create.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9c208d252553cf150234f240d5898c40521627fe9f8db60330cae1fed7b7cd65",
+ "chksum_sha256": "9c1841d0c54c7fc2de3b2024e14dc28e1cbde3a7f932390f6d54699cc09980b8",
"format": 1
},
{
"name": "plugins/lookup/vault_write.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d8fd10b5075f0bdc34e8b1ea0f7707acc1e198bd2d7e5acf22033ad39646564e",
+ "chksum_sha256": "5e12bc31541e63c459eb7a84419759823eb04cdfcc2f5795bac2a749649e8500",
"format": 1
},
{
@@ -578,7 +585,7 @@
"name": "plugins/module_utils/_auth_method_token.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f88bf860fbb14a5163dd30f0e03b629e4c7b8b83acfdb24f3783d8cc93a867c3",
+ "chksum_sha256": "5131dceee53f54144c2fd4c9965d165b8773df9a6ee9c04935fde99f0686623d",
"format": 1
},
{
@@ -599,14 +606,14 @@
"name": "plugins/module_utils/_connection_options.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1c30d05a0fb24f6fa0d22f8837620101366b8fa761e89dcd7828d429537031e3",
+ "chksum_sha256": "d7a219f8af7237d09429f4aacda1539adb2c300f5d39aba9ca96956b0e20d08b",
"format": 1
},
{
"name": "plugins/module_utils/_hashi_vault_common.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5ab33ef2f123fce48c13ea200a22ee06a45c565cdc147e4403f879ef585ff725",
+ "chksum_sha256": "e5785f7c5ea98d8a899908ba96353c3e667a7c591ac93bf0ed96f96491594d36",
"format": 1
},
{
@@ -624,6 +631,111 @@
"format": 1
},
{
+ "name": "plugins/modules/vault_database_connection_configure.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "09785e357b9fb8b2c1200ca2b99179b754a1f6e7faff983f3266f8d7301c9e39",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/vault_database_connection_delete.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "02a090ab539e27374c76c084e3ff9bb24a0fc5e30636a3368059ae24a3fd3ff8",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/vault_database_connection_read.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "719567425b8da7eb28bcb4ca7034df09d590b935c4704a774fa70498ac9cfc8c",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/vault_database_connection_reset.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6336e36134104d48498ab30023e631617b51e2cdebb1028246c13a9f18b81d54",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/vault_database_connections_list.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "61ac9eb1f1da102140ba6e115a53deb71f1919f23704da27e5a230a9968a1c97",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/vault_database_role_create.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "cb7b14e64b789feb1e493b0a2401cc4cde7c155ed105ac483d0164c1f3f0a99c",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/vault_database_role_delete.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "95c294c9cfacc0fb31e2d3db558161ecc1062a0b66bff2cbb809687609fbf4fc",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/vault_database_role_read.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "2ccb57f6d005b02a0afb90aaa5bea494eee9c7c36e7b8c62bd9878d997561a6f",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/vault_database_roles_list.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "bdb86ab286581c84af4d5d06cb72bfd566be38c7b750c20599d00099549b193d",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/vault_database_rotate_root_credentials.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "d8b0a1de9116f4af09767079a0731dd58134c6733f3a12445ed61e47cdb1572f",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/vault_database_static_role_create.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "15504a6219ca74129bdffcc05fa77d58d0dcfc76a5cbb9a4bdafced8a27a454f",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/vault_database_static_role_get_credentials.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "8a89ccbc40df8450ffa3cd1b0f2a75c2269e73f3a7648cd4d54aadb5986932b2",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/vault_database_static_role_read.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ffbb4b47d7cfb2d8a523850e1191e8510b3c89449f8979e72b0ff59d9710b935",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/vault_database_static_role_rotate_credentials.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ef159236af51471ef9150f262778d8fd9e971554e282a0eb956fd8662765537f",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/vault_database_static_roles_list.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c76eefd9c2345648c5e333b3d006e3d2b85a8deded214d6d19ce2afbef06a7ef",
+ "format": 1
+ },
+ {
"name": "plugins/modules/vault_kv1_get.py",
"ftype": "file",
"chksum_type": "sha256",
@@ -690,7 +802,7 @@
"name": "plugins/modules/vault_write.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c17d015dff130769b05357cb3496b2b32acdbc4f1b4f84d2f0b24f31bfd51ae6",
+ "chksum_sha256": "ef53b13f68730379e4c1c662e8ca1a2acafd196f97b009e3ccc8e27a5975184a",
"format": 1
},
{
@@ -704,7 +816,7 @@
"name": "plugins/plugin_utils/_hashi_vault_lookup_base.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8bacb7aeaf9aefb8a7b750c70c8a01a5d3970a326711c1579deaeff4de3fbd9e",
+ "chksum_sha256": "980e337f86c244b851f8c7d78c7728185904fb4f7f49bc04a688d8dcbea7b9ca",
"format": 1
},
{
@@ -788,21 +900,21 @@
"name": "tests/integration/targets/auth_approle/tasks/approle_test_controller.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "db2c8d9bffe8900e52fca26547274879ea6f0f9082aa63a0fa5afbf061951b30",
+ "chksum_sha256": "6652903cfaf08fd637f3d54cfa1438b9844f537dea99a6098cc1e7b432b9a441",
"format": 1
},
{
"name": "tests/integration/targets/auth_approle/tasks/approle_test_target.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1901a0c244201493787e3a9b4191d7de38f3d78fb4119a25f71f61e6386bf8c1",
+ "chksum_sha256": "349fce896f65460b122adebbd9a7684084c3bcde6a0966d49493f82a657eb0c0",
"format": 1
},
{
"name": "tests/integration/targets/auth_approle/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e6afe86da906899d4cbb718e4ceee48d3fd935a77cc5503b69add5cf940bb9ef",
+ "chksum_sha256": "a20931f5d629f3689e5cccbc7f8e663c21fec701ab967fd16c0de4d2afa05c8f",
"format": 1
},
{
@@ -865,14 +977,14 @@
"name": "tests/integration/targets/auth_aws_iam/tasks/aws_iam_test_target.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "91cb21963bca9ecfa4ecd1dc21fec09685e95e9df8d702057cc390295f7422c0",
+ "chksum_sha256": "bb9f349ede884884ae6ffdb1059019d3ff391574afd956abd75153e66572888b",
"format": 1
},
{
"name": "tests/integration/targets/auth_aws_iam/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9f8e209e859c00c8caf7898bb8fb2d35ddf6866c8e0074ce2c58d39296439f02",
+ "chksum_sha256": "e3836386fd357e44042bb492c90d43bf7ed676cc29528af72d80f23c244af426",
"format": 1
},
{
@@ -935,14 +1047,14 @@
"name": "tests/integration/targets/auth_azure/tasks/azure_test_target.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "da5435958d587f7bb1eb774b6bda26390ea05c0a1c0a4ba57c9e7fd824f2ffda",
+ "chksum_sha256": "d35ddc8bb68b74eaeecefabea6c57425bc2fac10df55dd784671bf1711fb4e90",
"format": 1
},
{
"name": "tests/integration/targets/auth_azure/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "03882c949782ad0a1cbe23a0be8b849d7c6b85f7b5700b756c379fb7d2800cff",
+ "chksum_sha256": "52ec210f89111e200e34c28486fb3ff5800aff1188b9b061c633fc4d0f9421e2",
"format": 1
},
{
@@ -1047,14 +1159,14 @@
"name": "tests/integration/targets/auth_cert/tasks/cert_test_target.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "94bd3b77ebd5c339f00b7a68e9221bdadc48fe00d217e50e3042c50743f6d63f",
+ "chksum_sha256": "3a1043a944c79adde84f9c2e3d556853438085f34d1468b04e394d42539857a7",
"format": 1
},
{
"name": "tests/integration/targets/auth_cert/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ee0782baf3cc65d16b1159db751f29d817968fc6fe705ed541259afd3f58c618",
+ "chksum_sha256": "1fbe3a23da9c63df523935d1d6d7aabaeec21da75db2a3279934d3eb318c549c",
"format": 1
},
{
@@ -1159,14 +1271,14 @@
"name": "tests/integration/targets/auth_jwt/tasks/jwt_test_target.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1b1eba5701d38b6eff7de7547d24420d7d81ac86827c0aca044b5e41e14fade8",
+ "chksum_sha256": "c5265a06d2e60d8f52a4af2dcb791d2aa22d24d0c9049e8a8fe80b053759fadd",
"format": 1
},
{
"name": "tests/integration/targets/auth_jwt/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "00aca2ae191aa626d9818d9f279a30e8ccf1172f31f77c683fe5ffaccd4deb40",
+ "chksum_sha256": "b7fd3e0d2fbbd3767878ac8aeec211ff7bbfe86a64d0240fac3157adccb113d9",
"format": 1
},
{
@@ -1229,14 +1341,14 @@
"name": "tests/integration/targets/auth_ldap/tasks/ldap_test_target.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "270f5d3f7ff671ea2f20a55dfd424b431aa133bff57dff5e98c556ee379bda63",
+ "chksum_sha256": "7d3946d44231b95d46278feeb5444731e8c0711622e25e48950e0d6bcb5d46ca",
"format": 1
},
{
"name": "tests/integration/targets/auth_ldap/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5506a054b0000d291b243fdd6e3e2445377c21c3cc678cdcad1885e9921aa2f6",
+ "chksum_sha256": "35994f3f0d55754d16342bc38845369bc04de16c9455acfb057f4c6c4e07c07c",
"format": 1
},
{
@@ -1362,21 +1474,21 @@
"name": "tests/integration/targets/auth_token/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6b0806626ea64468831efbb27c86078a7a43e94a82dcb77aef645851f67bff96",
+ "chksum_sha256": "946757960cb259566d15cc02cfd209bef9c4a63da7468e6c4a4ad25af3bb9d3d",
"format": 1
},
{
"name": "tests/integration/targets/auth_token/tasks/token_test_controller.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e135196c8e082e36f18cd35ea6e736a7d6c6c0f67f7298122c896ec4ed171353",
+ "chksum_sha256": "b7ca6f715fe4daf1c5586904074ba60952dc3ddd85fe49409ddd7bcc02d34f00",
"format": 1
},
{
"name": "tests/integration/targets/auth_token/tasks/token_test_target.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c11eea8eba17a551373c684c7625da1e28d1f8e9072eb09bbfff48b57e2a35ed",
+ "chksum_sha256": "f53a1ab468d52899229a15ecee9fcb71bf635d0705042f909ededf92f0bda11e",
"format": 1
},
{
@@ -1432,7 +1544,7 @@
"name": "tests/integration/targets/auth_userpass/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "37c1144beac57279d2f79c9a49c2c37f8227e4f77203bf12bce1e59eeaf255a1",
+ "chksum_sha256": "5f5eb68962d2263743736024b160cdf50be12906c13c66e72476de70aad23f5f",
"format": 1
},
{
@@ -1453,7 +1565,7 @@
"name": "tests/integration/targets/auth_userpass/tasks/userpass_test_target.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a80bb0f3842e9ada72841ec1677e0a12703634e5d65d18a71c2f7ddcc595e30a",
+ "chksum_sha256": "ecbbc0696c4bb5e2238d6d1388e40781de62bccf1d924888cf0f1dacebdf3ebe",
"format": 1
},
{
@@ -1509,7 +1621,7 @@
"name": "tests/integration/targets/connection_options/tasks/controller.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "330ca6d4711e5e35f0b4045d6140127b7835e8d0b3e87cf66c3b98e88346b043",
+ "chksum_sha256": "13872e8fc01d9a542965bb1bfb4a7bc788bf751e6390afc069d39b30b530fd3a",
"format": 1
},
{
@@ -1523,7 +1635,7 @@
"name": "tests/integration/targets/connection_options/tasks/target.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "34a316f8f3fada71ca60d476144e2b29fb6c6eb285a21468e1a8b3405abab115",
+ "chksum_sha256": "c37bdfecd80f27a2783c57e771cfdb269a9f486539e39c97f4a40631d6dae868",
"format": 1
},
{
@@ -1600,7 +1712,7 @@
"name": "tests/integration/targets/lookup_hashi_vault/tasks/lookup_test.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "763927dee00e08efaeb2f61c3f876294a97e9d6277be53351e211974937b8b2a",
+ "chksum_sha256": "4d53516153a79579ee12390baa5a7a5586b73f2895d2798a3f74afc7f708406b",
"format": 1
},
{
@@ -2048,7 +2160,7 @@
"name": "tests/integration/targets/lookup_vault_write/tasks/lookup_vault_write_test.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cf8dcda9a6613838dbf5d38d55eb7d26a8de4c405a4a254c01d2e1863c8a30a9",
+ "chksum_sha256": "28cdd9d16d48d749b670df94e969a66541d075d3f4e106bc1c9a2acebea51ba5",
"format": 1
},
{
@@ -2066,6 +2178,853 @@
"format": 1
},
{
+ "name": "tests/integration/targets/module_vault_database_connection_configure",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_connection_configure/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_connection_configure/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c975bcab7c4c1f062c6454a2006e70ff60617e236d85f1f22adc672622e1b32a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_connection_configure/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_connection_configure/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "732804da077147062d10c0e3260bfddd70caab5eb0c86e71f75d6c9a83cb7d15",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_connection_configure/tasks/module_vault_database_connection_configure_setup.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f132da412f3037b2d20ed77ced34c54b25e0f45fac918279b5444161f4ec00c2",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_connection_configure/tasks/module_vault_database_connection_configure_test.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "8a93b17aebe03af788005293758f8edeed48dea3b7f2ed10a4e78978599b077d",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_connection_configure/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fd716828fe3bf18b1f328708f5a49d15d2a07354307aa642833ac8c1f1221b8c",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_connection_delete",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_connection_delete/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_connection_delete/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c975bcab7c4c1f062c6454a2006e70ff60617e236d85f1f22adc672622e1b32a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_connection_delete/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_connection_delete/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0c84c2923b51da9074523b92997311f516a6b0c68caa3f48cf440e22f855f602",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_connection_delete/tasks/module_vault_database_connection_delete_setup.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "00541579a7143cc99bfcbc2df6b528554a3fdddb48ba1547b4f2fae2b471cd6f",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_connection_delete/tasks/module_vault_database_connection_delete_test.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "aa8a1fead1fff90e5972b47d0f8bbdf1401351e758815a5bd39fe677e1e78ad9",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_connection_delete/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fd716828fe3bf18b1f328708f5a49d15d2a07354307aa642833ac8c1f1221b8c",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_connection_read",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_connection_read/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_connection_read/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c975bcab7c4c1f062c6454a2006e70ff60617e236d85f1f22adc672622e1b32a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_connection_read/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_connection_read/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "b55fc52d80a32bd15f2fa96b86bba5e1f7b7f835eb71d82826a7a2fd3027f6a3",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_connection_read/tasks/module_vault_database_connection_read_setup.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "682277687903170a100924daba0c38acdad3e2603450270e881fc7fadacd9a4b",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_connection_read/tasks/module_vault_database_connection_read_test.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "7c3b8185b7475ce1ea8ae9a4418cf70721e8a21009b011190c89a47598ef73d0",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_connection_read/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fd716828fe3bf18b1f328708f5a49d15d2a07354307aa642833ac8c1f1221b8c",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_connection_reset",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_connection_reset/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_connection_reset/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c975bcab7c4c1f062c6454a2006e70ff60617e236d85f1f22adc672622e1b32a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_connection_reset/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_connection_reset/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "061020558d2ad687e4a211905b162222302001a9502ec8a26569a77c9c2f4856",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_connection_reset/tasks/module_vault_database_connection_reset_setup.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f132da412f3037b2d20ed77ced34c54b25e0f45fac918279b5444161f4ec00c2",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_connection_reset/tasks/module_vault_database_connection_reset_test.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "8ed2ec14914b9632684928e2b2c0e6a4a0214d9bd0a2d4cdc6ce6c12f26b020a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_connection_reset/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fd716828fe3bf18b1f328708f5a49d15d2a07354307aa642833ac8c1f1221b8c",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_connections_list",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_connections_list/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_connections_list/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c975bcab7c4c1f062c6454a2006e70ff60617e236d85f1f22adc672622e1b32a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_connections_list/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_connections_list/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "3281e06eeef48bde62a10941ce28d734f475c588d3e7ff77ee4d894bb8709989",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_connections_list/tasks/module_vault_database_connection_list_setup.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "682277687903170a100924daba0c38acdad3e2603450270e881fc7fadacd9a4b",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_connections_list/tasks/module_vault_database_connection_list_test.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fbdcd876556d4d40b8276d1f9f1f5276e160180f7f60a99f10359a276010f1b5",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_connections_list/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fd716828fe3bf18b1f328708f5a49d15d2a07354307aa642833ac8c1f1221b8c",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_role_create",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_role_create/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_role_create/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c975bcab7c4c1f062c6454a2006e70ff60617e236d85f1f22adc672622e1b32a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_role_create/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_role_create/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "121019ed78fec8ed9aed738f3b3f2def55991536dc1a7baf6d62f176f6e1626d",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_role_create/tasks/module_vault_database_role_create_setup.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9e2ad35c9d730c9f37b404934fad90b1bfcff67347f3c449bf78e6bba214381c",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_role_create/tasks/module_vault_database_role_create_test.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "40a8641647a29d2965c13a2d331780d89384c80d4a209a4de441c7f4d8368bd8",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_role_create/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fd716828fe3bf18b1f328708f5a49d15d2a07354307aa642833ac8c1f1221b8c",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_role_delete",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_role_delete/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_role_delete/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c975bcab7c4c1f062c6454a2006e70ff60617e236d85f1f22adc672622e1b32a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_role_delete/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_role_delete/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "70703bfa3463815edc4d0967793fefe37a72dab1c3245af3f56d8e244114b8d7",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_role_delete/tasks/module_vault_database_role_delete_setup.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "5dfd1b35f4d521e5dd5e849451669db9ce7f44670e2ff91105282b2e7a59279a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_role_delete/tasks/module_vault_database_role_delete_test.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "119e9785255c90e923506cc8e0b9e276d50115eb90167c66c26c7714d58a7e4f",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_role_delete/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fd716828fe3bf18b1f328708f5a49d15d2a07354307aa642833ac8c1f1221b8c",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_role_read",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_role_read/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_role_read/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c975bcab7c4c1f062c6454a2006e70ff60617e236d85f1f22adc672622e1b32a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_role_read/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_role_read/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "454bbf70f3e1da0a05b95c6acc9561514474144eed982d7a52764f325edaed51",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_role_read/tasks/module_vault_database_role_read_setup.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "682277687903170a100924daba0c38acdad3e2603450270e881fc7fadacd9a4b",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_role_read/tasks/module_vault_database_role_read_test.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "19798f8d2a693c9109206301a56a0ea0a5df681e141dbd0647af4d7f88f24b94",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_role_read/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fd716828fe3bf18b1f328708f5a49d15d2a07354307aa642833ac8c1f1221b8c",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_roles_list",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_roles_list/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_roles_list/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c975bcab7c4c1f062c6454a2006e70ff60617e236d85f1f22adc672622e1b32a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_roles_list/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_roles_list/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "3f3530c36c4f487f55b454349b72ab9fc04958ae3117ea40b4b6aed8661ed19c",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_roles_list/tasks/module_vault_database_roles_list_setup.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "682277687903170a100924daba0c38acdad3e2603450270e881fc7fadacd9a4b",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_roles_list/tasks/module_vault_database_roles_list_test.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "4b4a64ba29c5b2d1e9f1b8a94d44f8d2c9f75a17f4d99bd868ab66cc31a7cfb7",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_roles_list/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fd716828fe3bf18b1f328708f5a49d15d2a07354307aa642833ac8c1f1221b8c",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_rotate_root_creds",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_rotate_root_creds/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_rotate_root_creds/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c975bcab7c4c1f062c6454a2006e70ff60617e236d85f1f22adc672622e1b32a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_rotate_root_creds/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_rotate_root_creds/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c810c6573a56b0f3e75d50095d9aede661faae86d10baca9689b97018cd8e9eb",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_rotate_root_creds/tasks/module_vault_db_rotate_root_creds_cleanup.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e5a5899f1dd9fffc20f1eae8176fb6271008da40308e9d8d7de641d7d0fbc248",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_rotate_root_creds/tasks/module_vault_db_rotate_root_creds_setup.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c5f28493506637d1575dd435a5cac4392bfa793a4c1f0b09d44182ca21671819",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_rotate_root_creds/tasks/module_vault_db_rotate_root_creds_test.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e6e0975b9bffccf9c3f1ee819ee0f2482f1bdf9ddccfd386bacbcf3157a09cc6",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_rotate_root_creds/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fd716828fe3bf18b1f328708f5a49d15d2a07354307aa642833ac8c1f1221b8c",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_static_role_create",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_static_role_create/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_static_role_create/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c975bcab7c4c1f062c6454a2006e70ff60617e236d85f1f22adc672622e1b32a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_static_role_create/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_static_role_create/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "04b41c2b6d52b73e539f227d5860f2a2d0839d8a4263404aef861c634cddd9f7",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_static_role_create/tasks/module_vault_database_static_role_create_setup.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9e2ad35c9d730c9f37b404934fad90b1bfcff67347f3c449bf78e6bba214381c",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_static_role_create/tasks/module_vault_database_static_role_create_test.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "1299f12449f5c2978e936212d539000aae16bbd1dd9a889fdcca027e312b3abe",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_static_role_create/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fd716828fe3bf18b1f328708f5a49d15d2a07354307aa642833ac8c1f1221b8c",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_static_role_get_creds",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_static_role_get_creds/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_static_role_get_creds/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c975bcab7c4c1f062c6454a2006e70ff60617e236d85f1f22adc672622e1b32a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_static_role_get_creds/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_static_role_get_creds/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "5b5bc39e5d80cdeb750f6f44017ea22574d4659be6829118b976a193565cb2ed",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_static_role_get_creds/tasks/module_vault_database_static_role_get_credentials_setup.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "371e13dca6e5ffdb1e7daae3a995c5bc666fb61da3d3ae7bd1424f9314821595",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_static_role_get_creds/tasks/module_vault_database_static_role_get_credentials_test.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "645bac53117a5a61655dd99faf04297d6d531ca279aebca771c6321885d395ee",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_static_role_get_creds/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fd716828fe3bf18b1f328708f5a49d15d2a07354307aa642833ac8c1f1221b8c",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_static_role_read",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_static_role_read/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_static_role_read/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c975bcab7c4c1f062c6454a2006e70ff60617e236d85f1f22adc672622e1b32a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_static_role_read/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_static_role_read/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "7969c6a9f5447fae5e780d5df7c18f32ce1a33c1d1829e16c0c7a7fecead88b2",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_static_role_read/tasks/module_vault_database_static_role_read_setup.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "682277687903170a100924daba0c38acdad3e2603450270e881fc7fadacd9a4b",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_static_role_read/tasks/module_vault_database_static_role_read_test.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "41bcf98396b6ad272d5915faa64fb376ce41c2289c0fb92f65a94127339309aa",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_static_role_read/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fd716828fe3bf18b1f328708f5a49d15d2a07354307aa642833ac8c1f1221b8c",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_static_role_rotate_creds",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_static_role_rotate_creds/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_static_role_rotate_creds/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c975bcab7c4c1f062c6454a2006e70ff60617e236d85f1f22adc672622e1b32a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_static_role_rotate_creds/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_static_role_rotate_creds/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6ac85c42e2b88b0279543724956b144113d13ba1a3ad868fc0049cc53b66b6f8",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_static_role_rotate_creds/tasks/module_vault_db_static_role_rotate_creds_setup.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "5c0bbfcabe4cf92041f3b192a02d98b24c26ec51a543f7570556d31ba3c6dbcd",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_static_role_rotate_creds/tasks/module_vault_db_static_role_rotate_creds_test.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "712cd5d4150769cd5f3327038feb7dc04802e5e11f844ba2083356bb785e07d5",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_static_role_rotate_creds/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fd716828fe3bf18b1f328708f5a49d15d2a07354307aa642833ac8c1f1221b8c",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_static_roles_list",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_static_roles_list/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_static_roles_list/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c975bcab7c4c1f062c6454a2006e70ff60617e236d85f1f22adc672622e1b32a",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_static_roles_list/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_static_roles_list/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "b524e4c9b61fc3985a5081122446de5f372d0949fa08efc851048b5b4bb50b62",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_static_roles_list/tasks/module_vault_database_static_roles_list_setup.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "682277687903170a100924daba0c38acdad3e2603450270e881fc7fadacd9a4b",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_static_roles_list/tasks/module_vault_database_static_roles_list_test.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "5d4627309166e68d3b2c5ef27e63e56a62ce82634b5d924c692cd1ff9ef5ab45",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/module_vault_database_static_roles_list/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fd716828fe3bf18b1f328708f5a49d15d2a07354307aa642833ac8c1f1221b8c",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/module_vault_kv1_get",
"ftype": "dir",
"chksum_type": null,
@@ -2405,7 +3364,7 @@
"name": "tests/integration/targets/module_vault_login/tasks/module_vault_login_test.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8c301ddad3eaf8cbcce282450509b8f97373a9eaba0f303b75bdbffa31632a7e",
+ "chksum_sha256": "85463950dfa98475033d097b0d582e1706bd660b9c51f7886d1ccef0e2e95de1",
"format": 1
},
{
@@ -2629,7 +3588,7 @@
"name": "tests/integration/targets/module_vault_write/tasks/module_vault_write_test.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2c77fe22b6a2c80eab637289cd32027d3893ecab8f9e9deee8551234a3ded4ae",
+ "chksum_sha256": "6ecab83cd951b6761b5dccde4a65b40027269afff7ed8113b7d08172765a1c7c",
"format": 1
},
{
@@ -2720,7 +3679,7 @@
"name": "tests/integration/targets/setup_localenv_docker/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e9186a70864ebe946235117d244026dff8de74ffc6185f470c947fc83aa7e046",
+ "chksum_sha256": "2d962f207d5f4bcdd85730c077130c86f81d08f8a35ff6bbe2e56ad68be33a43",
"format": 1
},
{
@@ -2755,7 +3714,7 @@
"name": "tests/integration/targets/setup_localenv_docker/files/playbooks/vault_docker.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "db75d75550fcb5334f8161ae8b591f145c6604a093247e9149f723bf26682abb",
+ "chksum_sha256": "0c247bf4edd24eb1c7bef49da03d59df376b5946196d58e0bf47c5003003cc4a",
"format": 1
},
{
@@ -2769,14 +3728,14 @@
"name": "tests/integration/targets/setup_localenv_docker/files/requirements/constraints.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "521caee2728da71f6f8c804ee6a125081b38ac1b07b0acb48d790eeeca722eeb",
+ "chksum_sha256": "3d00767b7ce6a17528778206e8a1a3888e8bf966f88c6dbb03608aa1d9e11f11",
"format": 1
},
{
"name": "tests/integration/targets/setup_localenv_docker/files/requirements/requirements.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e2af5fc6f791738b66b031c46731e8de0976265f02dc51901174af1f1be3b4e3",
+ "chksum_sha256": "cdc9c91d9afdb3a25f281299e50d7fb1456820f5cee294569135487c358ff57d",
"format": 1
},
{
@@ -2787,6 +3746,20 @@
"format": 1
},
{
+ "name": "tests/integration/targets/setup_localenv_docker/files/sql",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_localenv_docker/files/sql/init.sql",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "7855191e0bc7cb4a363a426e22f00cbe4d2a6714b871682345552abfa8c36ccf",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/setup_localenv_docker/tasks",
"ftype": "dir",
"chksum_type": null,
@@ -2804,7 +3777,7 @@
"name": "tests/integration/targets/setup_localenv_docker/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5847657fe7ab224b6a780b62359a725f4dd8978c9fbde213bb6dd124d648ab19",
+ "chksum_sha256": "f53f3dc1f2059e3f97c1504c118d806f8a91940f2a5d8f09058df5ae8486d177",
"format": 1
},
{
@@ -2895,7 +3868,7 @@
"name": "tests/integration/targets/setup_localenv_docker/templates/docker-compose.yml.j2",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4ee4aded02dc766e59599c22e977f266fee2a4e238b5c9cb5b7ccfbd31e089e3",
+ "chksum_sha256": "d76a1634d00bf21830d5970775f048cd62735552fff1b21990d5be789043f76e",
"format": 1
},
{
@@ -2930,7 +3903,7 @@
"name": "tests/integration/targets/setup_localenv_docker/vars/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ba1d50adc2585030809325a0102576dbb5cb1c5f4c1613bf5f1f4a2ce0bd6cc8",
+ "chksum_sha256": "91655f9dc152ab9aa50cb99bfd12aacb8a277f4d4ccd70f9509912d4c63e9ecf",
"format": 1
},
{
@@ -3021,7 +3994,7 @@
"name": "tests/integration/targets/setup_localenv_gha/files/playbooks/gha.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e3f4b18483da6eadf64e5ed8193d89ba648daa2ac67c61df156e7dbd9a166496",
+ "chksum_sha256": "41fc6c71d3aa6682059d9ea3a7f5a9cf8c84347f202564bcc2ddaebc912e0be1",
"format": 1
},
{
@@ -3151,6 +4124,76 @@
"format": 1
},
{
+ "name": "tests/integration/targets/setup_vault_configure_database",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_vault_configure_database/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_vault_configure_database/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "4711f4181ed51d1fd3c0912702e2e28b8429485a3ded3bbe8088b873a6ff3888",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_vault_configure_database/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_vault_configure_database/tasks/configure.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "7053ed5006ed1da7dc410b149a6fef66099c4e5803d765db4446d21704aef050",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_vault_configure_database/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "40e459dac64ec618436d308ce3400a37b057267fbd082cc8c4cd7aea973c9eed",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_vault_configure_database/vars",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_vault_configure_database/vars/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "14de609ddcffdb33a72f72ea45908d7edbbaf0194e014163691d200ea603f917",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_vault_configure_database/README.md",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "b5e48fce153278864264b27fc2162a6bbd8c789413b592a8ae4349014ee72bd6",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_vault_configure_database/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0584bb783019be77fe15aba5347fba524b641155594286366214a4647662c8e8",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/setup_vault_configure_engine_pki",
"ftype": "dir",
"chksum_type": null,
@@ -3403,6 +4446,13 @@
"format": 1
},
{
+ "name": "tests/integration/constraints.txt",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9dec7a581a697549468372acb1cc3a37b2cbe897ea2902878f9565f3f8b7b3fb",
+ "format": 1
+ },
+ {
"name": "tests/integration/integration.cfg",
"ftype": "file",
"chksum_type": "sha256",
@@ -3420,7 +4470,7 @@
"name": "tests/integration/requirements.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b46f66680eea1291c232bd2e08db3258aa94ad4a3c5a26750203dc71046810f5",
+ "chksum_sha256": "caddf55f1b596b08d58b6ecf106f4321f79dacdb648d69e953184d01cd4b1755",
"format": 1
},
{
@@ -3508,6 +4558,55 @@
"format": 1
},
{
+ "name": "tests/unit/fixtures/database_connection_read_response.json",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "24151ee2d877ce7ccc16b66b163eb1622c23db0b5f0002f9ddde733619b2ec27",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/fixtures/database_connections_list_response.json",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "7f6a94dc085560e91281059c1147f9851f1a75cbb514f63e668ddc31fc5cfb52",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/fixtures/database_role_read_response.json",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "108ccdc116d131ecf87dc1aebe268693a1b3bd6b625e0769c7eb83b02e421d41",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/fixtures/database_roles_list_response.json",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "08260f3a5167cec132d0162089498a7c64bec0f2f16d08d2f2fb368a4372e746",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/fixtures/database_static_role_get_credentials_response.json",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f4c847fd41e6b6419aed4e205675dcc547b073e0015ec52ac2ccaebbf041e86d",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/fixtures/database_static_role_read_response.json",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e815b6dc328429cf0d0e353098c100c7cc35da83fdc7e761c5373a982e7905c3",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/fixtures/database_static_roles_list_response.json",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0fd331d4f627e6ac97986890a6445543d71b2c71fe23120203fe3428766b1fac",
+ "format": 1
+ },
+ {
"name": "tests/unit/fixtures/jwt_login_response.json",
"ftype": "file",
"chksum_type": "sha256",
@@ -3686,14 +4785,14 @@
"name": "tests/unit/plugins/lookup/test_vault_token_create.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "da6e62da0beabc991cebc40e063f861b6b46f98ef501d4c28f17ee7e68e34b05",
+ "chksum_sha256": "2008e24f5096b3454cce19aed8b877c33f4a8bc1c2dc4a3908653395cd409d79",
"format": 1
},
{
"name": "tests/unit/plugins/lookup/test_vault_write.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "db7a4a050e4c80b9ef058ed9c28e06ff7f7c94d0d6fac535455d270e69cd06ed",
+ "chksum_sha256": "c2b5ee98baadba6e5a9520e95aacb899c01b4d989cc48453c340be0a1de2d9f3",
"format": 1
},
{
@@ -3728,14 +4827,14 @@
"name": "tests/unit/plugins/module_utils/authentication/test_auth_aws_iam.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "47a0b6f5339479ccf7ba86344478bb936d468e7cac20fdabe8ea84248d4f086c",
+ "chksum_sha256": "5cd756c453da81d4dcb408139567b86a047175b88045ee112a4f958887c50b34",
"format": 1
},
{
"name": "tests/unit/plugins/module_utils/authentication/test_auth_azure.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e7874e069e88a75c257fb80cf612bf78316ace21e892289ad59981907906dd77",
+ "chksum_sha256": "651237f3b447adaabcb1dff9a7540a4125b07b012d04c54afc841e578c4c6743",
"format": 1
},
{
@@ -3770,7 +4869,7 @@
"name": "tests/unit/plugins/module_utils/authentication/test_auth_token.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "abac6adc2d23f2368700edac95f9734153379ce62837cacf277653024b7b63b4",
+ "chksum_sha256": "1576d74d9304af6c7dbc8494c34a605b2001484f3904830f1d08f789ff83edd7",
"format": 1
},
{
@@ -3784,7 +4883,7 @@
"name": "tests/unit/plugins/module_utils/authentication/test_hashi_vault_auth_method_base.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0c0861f123a4cf0f291f857035d04754b6a547e79e47b1a406e48b4022f3b44b",
+ "chksum_sha256": "49d1a2b3df3afdda4957428e1ade75ecfd7ebeedc481139538a80749e2181ba3",
"format": 1
},
{
@@ -3812,21 +4911,21 @@
"name": "tests/unit/plugins/module_utils/option_adapter/test_hashi_vault_option_adapter.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "df8f8ddc9ecf159214128c2987b6186805af8ea631cd855169a702db8617e767",
+ "chksum_sha256": "8025136869c598fdb79ca350e2f64d5448279240d33a047d69661074b5f7175d",
"format": 1
},
{
"name": "tests/unit/plugins/module_utils/test_hashi_vault_connection_options.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d40bcd481379315d4362afb0cc0e3b735b024ec5c85fb54055b05374da52fcd6",
+ "chksum_sha256": "75521ab23dcd91023b82da4290ecf99a9eb7dc082ed35a1b053a4619fe64fdc6",
"format": 1
},
{
"name": "tests/unit/plugins/module_utils/test_hashi_vault_helper.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "02ca0e5fb0d77d7de7a86b1fe7ce9bce5f3d33a71bf64c1785376f50200aee89",
+ "chksum_sha256": "db9944713d7c7b70d1689b59b73f8ed7dfea644146ed89c0bf88df6722cdc8d4",
"format": 1
},
{
@@ -3851,6 +4950,111 @@
"format": 1
},
{
+ "name": "tests/unit/plugins/modules/test_vault_database_connection_configure.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0ac8a71b1858d9fb93c468a09fc34fdd745f397caee36a7cf83bbbccfe75cbdf",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/modules/test_vault_database_connection_delete.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "3e09ebd72533c3ff547e707a3cac4b2b65605531fc207f65d548be227c54a231",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/modules/test_vault_database_connection_read.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "41f2b86409b0fe614883b206c72dbc9900833227bcb3a6dfc4220b77856ad10d",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/modules/test_vault_database_connection_reset.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "2961c5f24715e8009b268a4027b05fb13953b98f4219afa2e5397d0cfe2d2794",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/modules/test_vault_database_connections_list.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fee63fc3547e48ac51e25c5beffd5899b079d0a151413673b86d8a84a0ec57fb",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/modules/test_vault_database_role_create.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "4209c5095e09cde98a54b510f64438d7e40aa8a0fff0ef5ba0b978ee39a11fd3",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/modules/test_vault_database_role_delete.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "33ebdbf3d606fa48d7e89579ce2013dc563f7dd66ce5d05e4e5972ea018fb85e",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/modules/test_vault_database_role_read.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c4a9922cfed0444dacf22f8383eb077c17b164b10d51ee4b8e8e0723e5098b85",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/modules/test_vault_database_roles_list.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "a52538e72f73d420862c2bc516a4675faf5a6f092fde520305b6c2f80f9619b5",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/modules/test_vault_database_rotate_root_credentials.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "4ae5b4d20fb6e2dba90a2a7c7a3d65f2ae3497cf46ee490abb6a5476940d9107",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/modules/test_vault_database_static_role_create.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "87b0a60aa3c09c6ec167741cc9724b69dc30a2a3f63c205b5425d36febdc631a",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/modules/test_vault_database_static_role_get_credentials.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6f5cb1b8f6fead7f89e9af378e8a63dd561c8958aed5a33f47b8bcf7ac840e8a",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/modules/test_vault_database_static_role_read.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "aa6a6e0b26dbcac35e01d04a53c1c338fcc366ef6127bef49264a35f8dcb2741",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/modules/test_vault_database_static_role_rotate_credentials.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0905fe00c51129d07a2cdfbb76ccee7774187626bdc504aee58da2785f373082",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/modules/test_vault_database_static_roles_list.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "535af7025507c0fcc1b9ee82597a53b2f6e5c4c0f9ecaa69c10761403d6640c5",
+ "format": 1
+ },
+ {
"name": "tests/unit/plugins/modules/test_vault_kv1_get.py",
"ftype": "file",
"chksum_type": "sha256",
@@ -3896,7 +5100,7 @@
"name": "tests/unit/plugins/modules/test_vault_pki_generate_certificate.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2c7ffc3b60b172c704c2947bfd212c92ea2a2e4bef1b71a3967c3e022c9879e6",
+ "chksum_sha256": "bc53c528710a271501e8e3905ba94de223f958420754202f9d4ace391a019253",
"format": 1
},
{
@@ -3917,7 +5121,7 @@
"name": "tests/unit/plugins/modules/test_vault_write.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b723e07376ec9c56bd5070e0be49c19d6e6542aa46b9b4e3491170bb1af6ce4c",
+ "chksum_sha256": "0a716b13c406579c7d26cb283658ea53299fbfe34920b7d12ab73e4e7d41cac6",
"format": 1
},
{
@@ -3928,27 +5132,6 @@
"format": 1
},
{
- "name": "tests/unit/plugins/plugin_utils/authentication",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/unit/plugins/plugin_utils/authentication/conftest.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "7eaacca9465aa4ab541a88254fe6700ece427d3e9fd832c2733bfd71e30c6899",
- "format": 1
- },
- {
- "name": "tests/unit/plugins/plugin_utils/authentication/test_auth_token.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "b48581be86aa632e7580301a0d3d62d06219b3d24b44a94b6c4ca73e23e6f1fc",
- "format": 1
- },
- {
"name": "tests/unit/plugins/plugin_utils/base",
"ftype": "dir",
"chksum_type": null,
@@ -3959,7 +5142,7 @@
"name": "tests/unit/plugins/plugin_utils/base/test_hashi_vault_lookup_base.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b38f37e9cb846e77a00e6b1dcf63db09ffde02460e02ec278317e091a950dd42",
+ "chksum_sha256": "ec0bccac48afd69d21644d3d2631f9617e7a604a72158473b26f011d48250c9e",
"format": 1
},
{
@@ -3980,77 +5163,63 @@
"name": "tests/unit/plugins/plugin_utils/option_adapter/conftest.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "692431478c133aedf9e66f939cb63ecc7fc66a58191ace5569759a3af40ed5c5",
+ "chksum_sha256": "2dd268286c9a921018df05152f8f6332f20279ab3ff25c731c8e34d22e676295",
"format": 1
},
{
"name": "tests/unit/plugins/plugin_utils/option_adapter/test_hashi_vault_option_adapter.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "525504b9d635e74afe7e24efbb2431e9cd77ceb6b27b1ba1ebf2da92c8ac5901",
+ "chksum_sha256": "75c3eb27a1c78605461bba291dd5db145043c981845c4163f9b54b7259cced88",
"format": 1
},
{
- "name": "tests/unit/plugins/plugin_utils/test_hashi_vault_common_stringify.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "30a555505f23377a8850ec84ad5df84a192dd24ba5774fb473fa67f97dac381b",
- "format": 1
- },
- {
- "name": "tests/unit/plugins/plugin_utils/test_hashi_vault_helper.py",
+ "name": "tests/unit/conftest.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "14488b16acbb0cf0d991a84f4fe1805fb0ac5f0cfa4529cf1b57b7b448adc907",
+ "chksum_sha256": "da4017d6bcb97a9184ce968d216eaa62aac641ded86df8fd710fd6287357f7cd",
"format": 1
},
{
- "name": "tests/unit/conftest.py",
+ "name": "tests/unit/constraints.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e29931074c13b6d08f944adba9ce6fbaf0e2b8585a9bceeac51cde6c99ab83e1",
+ "chksum_sha256": "9dec7a581a697549468372acb1cc3a37b2cbe897ea2902878f9565f3f8b7b3fb",
"format": 1
},
{
"name": "tests/unit/requirements.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1a7e15b893287335a87621a5738d46855524ee40b7e54c7af18fa567c85f30a5",
- "format": 1
- },
- {
- "name": "tests/utils",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
+ "chksum_sha256": "18ae2786efc33af15a4f09d215cd4758daf61dd8c992154131afadf95ace170a",
"format": 1
},
{
- "name": "tests/utils/constraints.txt",
+ "name": "tests/config.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6587434a23557810c3378386918925a2bc372399682483bb1ee0c33001a30544",
+ "chksum_sha256": "f5174fec8c0d86b9970fd83767ffc181f4d6ef25aaad4a1f12f9d73ad38a23de",
"format": 1
},
{
- "name": "tests/config.yml",
+ "name": ".git-blame-ignore-revs",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f5174fec8c0d86b9970fd83767ffc181f4d6ef25aaad4a1f12f9d73ad38a23de",
+ "chksum_sha256": "559c96731959d3d5e516775f2e4329064991505ffefb2f3c84d3b1f814270f90",
"format": 1
},
{
- "name": ".git-blame-ignore-revs",
+ "name": "CHANGELOG.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "559c96731959d3d5e516775f2e4329064991505ffefb2f3c84d3b1f814270f90",
+ "chksum_sha256": "7dbbb4c968b1d53ad5661e79a364f341e728da0d61ac1bdc868bf7136cd6e634",
"format": 1
},
{
"name": "CHANGELOG.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "79bab511c63a4f5ffdffbf0deb76f4b6aed0db672e46dc34413030f308cbba4a",
+ "chksum_sha256": "9b52d95bfa031a3b374b7a519ea045b63a7ee696cf74af9d6bf70039a5ef4816",
"format": 1
},
{
@@ -4064,7 +5233,7 @@
"name": "README.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "44caa26d837f0ae09a1f6d7f97fca696d26261ea4d94d6d30ccf58bb37864ae3",
+ "chksum_sha256": "4561d2cec8f8ffd034351f3fba6d2788640b034df96805aeda0b67db9a408127",
"format": 1
},
{
diff --git a/ansible_collections/community/hashi_vault/MANIFEST.json b/ansible_collections/community/hashi_vault/MANIFEST.json
index 3845b05b1..2524a07c4 100644
--- a/ansible_collections/community/hashi_vault/MANIFEST.json
+++ b/ansible_collections/community/hashi_vault/MANIFEST.json
@@ -2,7 +2,7 @@
"collection_info": {
"namespace": "community",
"name": "hashi_vault",
- "version": "4.2.1",
+ "version": "6.2.0",
"authors": [
"Julie Davila (@juliedavila) <julie(at)davila.io>",
"Brian Scholer (@briantist)"
@@ -32,7 +32,7 @@
"name": "FILES.json",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a3546d2747fa04f54d5d67aee79aeb8d80598df269a6f484ba9ff2a0fc3895e1",
+ "chksum_sha256": "eafb51e763722dc3571899bd632595bc4c449ed0a39e9b8d707b5f6f03caf521",
"format": 1
},
"format": 1
diff --git a/ansible_collections/community/hashi_vault/README.md b/ansible_collections/community/hashi_vault/README.md
index c8cf2b82c..d80337060 100644
--- a/ansible_collections/community/hashi_vault/README.md
+++ b/ansible_collections/community/hashi_vault/README.md
@@ -12,17 +12,16 @@ Browsing the [**devel** collection documentation](https://docs.ansible.com/ansib
We also separately publish [**latest commit** collection documentation](https://ansible-collections.github.io/community.hashi_vault/branch/main/) which shows docs for the _latest commit in the `main` branch_.
If you use the Ansible package and don't update collections independently, use **latest**, if you install or update this collection directly from Galaxy, use **devel**. If you are looking to contribute, use **latest commit**.
+
## Tested with Ansible
-* 2.11
-* 2.12
-* 2.13
-* 2.14
-* 2.15
-* devel (latest development commit)
+Please refer to the [`ansible-core` support matrix](https://docs.ansible.com/ansible/devel/reference_appendices/release_and_maintenance.html#ansible-core-support-matrix) to see which versions of `ansible-core` are still supported or end-of-life.
+
+Generally, we release a new major version of this collection a little before the release of a new `ansible-core` version, which is around every 6 months. In that release, we will update the CI matrix to drop the core versions that are about to go EoL, and add in new core versions if they have not been added already.
+
+We also regularly test against the [`devel` branch](https://github.com/ansible/ansible/tree/devel) (latest development commit).
See [the CI configuration](https://github.com/ansible-collections/community.hashi_vault/blob/main/.github/workflows/ansible-test.yml) for the most accurate testing information.
-<!-- List the versions of Ansible the collection has been tested with. Must match what is in galaxy.yml. -->
## Tested with Vault
@@ -47,6 +46,7 @@ Currently we support and test against Python versions:
* 3.9
* 3.10
* 3.11
+* 3.12
Note that for controller-side plugins, only the Python versions supported by the Ansible controller are supported (for example, you cannot use Python 3.7 with Ansible core 2.12).
diff --git a/ansible_collections/community/hashi_vault/changelogs/changelog.yaml b/ansible_collections/community/hashi_vault/changelogs/changelog.yaml
index cd982ec0e..0018040ff 100644
--- a/ansible_collections/community/hashi_vault/changelogs/changelog.yaml
+++ b/ansible_collections/community/hashi_vault/changelogs/changelog.yaml
@@ -644,3 +644,124 @@ releases:
fragments:
- 4.2.1.yml
release_date: '2023-04-27'
+ 5.0.0:
+ changes:
+ breaking_changes:
+ - Support for ``ansible-core`` 2.11 and 2.12 has been removed (https://github.com/ansible-collections/community.hashi_vault/issues/340).
+ - The minimum version of ``hvac`` for ``community.hashi_vault`` is now ``1.1.0``
+ (https://github.com/ansible-collections/community.hashi_vault/issues/324).
+ - hashi_vault lookup - duplicate option entries in the term string now raises
+ an exception instead of a warning (https://github.com/ansible-collections/community.hashi_vault/issues/356).
+ release_summary: This version makes some relatively minor but technically breaking
+ changes. Support for ``ansible-core`` versions ``2.11`` and ``2.12`` have
+ been dropped, and there is now a minimum supported version of ``hvac`` which
+ will be updated over time. A warning in the ``hashi_vault`` lookup on duplicate
+ option specifications in the term string has been changed to a fatal error.
+ fragments:
+ - 324-minimum-hvac-version.yml
+ - 340-drop-core-211-212.yml
+ - 356-duplicate-term-options.yml
+ - 5.0.0.yml
+ release_date: '2023-05-11'
+ 5.0.1:
+ changes:
+ bugfixes:
+ - vault_write - the ``vault_write`` lookup and module were not able to write
+ data containing keys named ``path`` or ``wrap_ttl`` due to a bug in the ``hvac``
+ library. These plugins have now been updated to take advantage of fixes in
+ ``hvac>=1.2`` to address this (https://github.com/ansible-collections/community.hashi_vault/issues/389).
+ release_summary: This release fixes a bug in ``vault_write`` ahead of the collection's
+ next major release.
+ fragments:
+ - 381-localenv_docker.yml
+ - 404-vault_write-spicy-keys.yml
+ - 5.0.1.yml
+ release_date: '2023-11-05'
+ 6.0.0:
+ changes:
+ breaking_changes:
+ - The minimum required version of ``hvac`` is now ``1.2.1`` (https://docs.ansible.com/ansible/devel/collections/community/hashi_vault/docsite/user_guide.html#hvac-version-specifics).
+ release_summary: This major version of the collection has no functional changes
+ from the previous version, however the minimum versions of ``hvac`` and ``ansible-core``
+ have been raised. While the collection may still work with those earlier versions,
+ future changes will not test against them.
+ removed_features:
+ - The minimum supported version of ``ansible-core`` is now ``2.14``, support
+ for ``2.13`` has been dropped (https://github.com/ansible-collections/community.hashi_vault/pull/403).
+ fragments:
+ - 403-core-vault-python.yml
+ - 6.0.0.yml
+ release_date: '2023-11-05'
+ 6.1.0:
+ changes:
+ major_changes:
+ - requirements - the ``requests`` package which is required by ``hvac`` now
+ has a more restrictive range for this collection in certain use cases due
+ to breaking security changes in ``ansible-core`` that were backported (https://github.com/ansible-collections/community.hashi_vault/pull/416).
+ release_summary: This release addresses some breaking changes in core that were
+ backported.
+ fragments:
+ - 416-core-changes.yml
+ - 6.1.0.yml
+ release_date: '2024-01-02'
+ 6.2.0:
+ changes:
+ minor_changes:
+ - cert auth - add option to set the ``cert_auth_public_key`` and ``cert_auth_private_key``
+ parameters using the variables ``ansible_hashi_vault_cert_auth_public_key``
+ and ``ansible_hashi_vault_cert_auth_private_key`` (https://github.com/ansible-collections/community.hashi_vault/issues/428).
+ release_summary: This release contains a dozen+ new modules for working with
+ Vault's database secrets engine and some new ``vars`` entries for specifying
+ public and private keys in ``cert`` auth.
+ fragments:
+ - 429-add-cert-auth-variables.yml
+ - 6.2.0.yml
+ modules:
+ - description: Configures the database engine
+ name: vault_database_connection_configure
+ namespace: ''
+ - description: Delete a Database Connection
+ name: vault_database_connection_delete
+ namespace: ''
+ - description: Returns the configuration settings for a O(connection_name)
+ name: vault_database_connection_read
+ namespace: ''
+ - description: Closes a O(connection_name) and its underlying plugin and restarts
+ it with the configuration stored
+ name: vault_database_connection_reset
+ namespace: ''
+ - description: Returns a list of available connections
+ name: vault_database_connections_list
+ namespace: ''
+ - description: Creates or updates a (dynamic) role definition
+ name: vault_database_role_create
+ namespace: ''
+ - description: Delete a role definition
+ name: vault_database_role_delete
+ namespace: ''
+ - description: Queries a dynamic role definition
+ name: vault_database_role_read
+ namespace: ''
+ - description: Returns a list of available (dynamic) roles
+ name: vault_database_roles_list
+ namespace: ''
+ - description: Rotates the root credentials stored for the database connection.
+ This user must have permissions to update its own password.
+ name: vault_database_rotate_root_credentials
+ namespace: ''
+ - description: Create or update a static role
+ name: vault_database_static_role_create
+ namespace: ''
+ - description: Returns the current credentials based on the named static role
+ name: vault_database_static_role_get_credentials
+ namespace: ''
+ - description: Queries a static role definition
+ name: vault_database_static_role_read
+ namespace: ''
+ - description: Trigger the credential rotation for a static role
+ name: vault_database_static_role_rotate_credentials
+ namespace: ''
+ - description: Returns a list of available static roles
+ name: vault_database_static_roles_list
+ namespace: ''
+ release_date: '2024-03-19'
diff --git a/ansible_collections/community/hashi_vault/changelogs/config.yaml b/ansible_collections/community/hashi_vault/changelogs/config.yaml
index f7f950db0..2eaf842ca 100644
--- a/ansible_collections/community/hashi_vault/changelogs/config.yaml
+++ b/ansible_collections/community/hashi_vault/changelogs/config.yaml
@@ -27,3 +27,4 @@ sections:
- Known Issues
title: community.hashi_vault
trivial_section_name: trivial
+output_formats: [rst, md]
diff --git a/ansible_collections/community/hashi_vault/docs/docsite/rst/CHANGELOG.rst b/ansible_collections/community/hashi_vault/docs/docsite/rst/CHANGELOG.rst
index 5223d4a97..4362dc7f0 100644
--- a/ansible_collections/community/hashi_vault/docs/docsite/rst/CHANGELOG.rst
+++ b/ansible_collections/community/hashi_vault/docs/docsite/rst/CHANGELOG.rst
@@ -1,9 +1,99 @@
-===================================
-community.hashi_vault Release Notes
-===================================
+====================================
+community.hashi\_vault Release Notes
+====================================
.. contents:: Topics
+v6.2.0
+======
+
+Release Summary
+---------------
+
+This release contains a dozen+ new modules for working with Vault's database secrets engine and some new ``vars`` entries for specifying public and private keys in ``cert`` auth.
+
+Minor Changes
+-------------
+
+- cert auth - add option to set the ``cert_auth_public_key`` and ``cert_auth_private_key`` parameters using the variables ``ansible_hashi_vault_cert_auth_public_key`` and ``ansible_hashi_vault_cert_auth_private_key`` (https://github.com/ansible-collections/community.hashi_vault/issues/428).
+
+New Modules
+-----------
+
+- vault_database_connection_configure - Configures the database engine
+- vault_database_connection_delete - Delete a Database Connection
+- vault_database_connection_read - Returns the configuration settings for a O(connection_name)
+- vault_database_connection_reset - Closes a O(connection_name) and its underlying plugin and restarts it with the configuration stored
+- vault_database_connections_list - Returns a list of available connections
+- vault_database_role_create - Creates or updates a (dynamic) role definition
+- vault_database_role_delete - Delete a role definition
+- vault_database_role_read - Queries a dynamic role definition
+- vault_database_roles_list - Returns a list of available (dynamic) roles
+- vault_database_rotate_root_credentials - Rotates the root credentials stored for the database connection. This user must have permissions to update its own password.
+- vault_database_static_role_create - Create or update a static role
+- vault_database_static_role_get_credentials - Returns the current credentials based on the named static role
+- vault_database_static_role_read - Queries a static role definition
+- vault_database_static_role_rotate_credentials - Trigger the credential rotation for a static role
+- vault_database_static_roles_list - Returns a list of available static roles
+
+v6.1.0
+======
+
+Release Summary
+---------------
+
+This release addresses some breaking changes in core that were backported.
+
+Major Changes
+-------------
+
+- requirements - the ``requests`` package which is required by ``hvac`` now has a more restrictive range for this collection in certain use cases due to breaking security changes in ``ansible-core`` that were backported (https://github.com/ansible-collections/community.hashi_vault/pull/416).
+
+v6.0.0
+======
+
+Release Summary
+---------------
+
+This major version of the collection has no functional changes from the previous version, however the minimum versions of ``hvac`` and ``ansible-core`` have been raised. While the collection may still work with those earlier versions, future changes will not test against them.
+
+Breaking Changes / Porting Guide
+--------------------------------
+
+- The minimum required version of ``hvac`` is now ``1.2.1`` (https://docs.ansible.com/ansible/devel/collections/community/hashi_vault/docsite/user_guide.html#hvac-version-specifics).
+
+Removed Features (previously deprecated)
+----------------------------------------
+
+- The minimum supported version of ``ansible-core`` is now ``2.14``, support for ``2.13`` has been dropped (https://github.com/ansible-collections/community.hashi_vault/pull/403).
+
+v5.0.1
+======
+
+Release Summary
+---------------
+
+This release fixes a bug in ``vault_write`` ahead of the collection's next major release.
+
+Bugfixes
+--------
+
+- vault_write - the ``vault_write`` lookup and module were not able to write data containing keys named ``path`` or ``wrap_ttl`` due to a bug in the ``hvac`` library. These plugins have now been updated to take advantage of fixes in ``hvac>=1.2`` to address this (https://github.com/ansible-collections/community.hashi_vault/issues/389).
+
+v5.0.0
+======
+
+Release Summary
+---------------
+
+This version makes some relatively minor but technically breaking changes. Support for ``ansible-core`` versions ``2.11`` and ``2.12`` have been dropped, and there is now a minimum supported version of ``hvac`` which will be updated over time. A warning in the ``hashi_vault`` lookup on duplicate option specifications in the term string has been changed to a fatal error.
+
+Breaking Changes / Porting Guide
+--------------------------------
+
+- Support for ``ansible-core`` 2.11 and 2.12 has been removed (https://github.com/ansible-collections/community.hashi_vault/issues/340).
+- The minimum version of ``hvac`` for ``community.hashi_vault`` is now ``1.1.0`` (https://github.com/ansible-collections/community.hashi_vault/issues/324).
+- hashi_vault lookup - duplicate option entries in the term string now raises an exception instead of a warning (https://github.com/ansible-collections/community.hashi_vault/issues/356).
v4.2.1
======
@@ -601,4 +691,3 @@ Release Summary
---------------
Our first release matches the ``hashi_vault`` lookup functionality provided by ``community.general`` version ``1.3.0``.
-
diff --git a/ansible_collections/community/hashi_vault/docs/docsite/rst/user_guide.rst b/ansible_collections/community/hashi_vault/docs/docsite/rst/user_guide.rst
index a3f417800..badf7f8da 100644
--- a/ansible_collections/community/hashi_vault/docs/docsite/rst/user_guide.rst
+++ b/ansible_collections/community/hashi_vault/docs/docsite/rst/user_guide.rst
@@ -29,19 +29,18 @@ The content in ``community.hashi_vault`` requires the `hvac <https://hvac.readth
``hvac`` version specifics
--------------------------
-In general, we recommend using the latest version of ``hvac`` that is supported for your given Python version because that is what we test against. Where possible we will try to list version-specific restrictions here, but this list may not be exhaustive.
+In general, we recommend using the latest version of ``hvac`` that is supported for your given Python version because that is what we test against.
-* ``hvac`` 0.7.0+ (for Azure auth and namespace support)
-* ``hvac`` 0.9.6+ (to avoid most deprecation warnings)
-* ``hvac`` 0.10.5+ (for JWT auth)
-* ``hvac`` 0.10.6+ (to avoid deprecation warning for AppRole)
-* ``hvac`` 0.10.12+ (for cert auth)
+As of ``community.hashi_vault`` version ``5.0.0`` we are setting a minimum supported version of ``hvac``.
+
+**The current required minimum** ``hvac`` **version is** ``1.2.1``.
Other requirements
------------------
* ``boto3`` (only if loading credentials from a boto session, for example using an AWS profile or IAM role credentials)
* ``azure-identity`` (only if using a service principal or managed identity)
+* ``requests`` — with ``requests>=2.28,<2.29``, setting certain options (``token``, ``namespace``) to values that come from lookups will raise an exception, do to Ansible's marking of the values as "unsafe" for templating. We recommend using ``requests>=2.29``, which won't work with Python 3.6.
Retrying failed requests
========================
diff --git a/ansible_collections/community/hashi_vault/meta/ee-requirements.txt b/ansible_collections/community/hashi_vault/meta/ee-requirements.txt
index 53393fd3e..457af229b 100644
--- a/ansible_collections/community/hashi_vault/meta/ee-requirements.txt
+++ b/ansible_collections/community/hashi_vault/meta/ee-requirements.txt
@@ -1,6 +1,6 @@
# ansible-builder doesn't seem to properly handle "; python_version" type of constraints
# requirements here are assuming python 3.6 or higher
-hvac >=0.10.6
+hvac >= 1.2.1
urllib3 >= 1.15
boto3 # these are only needed if inferring AWS credentials or
diff --git a/ansible_collections/community/hashi_vault/meta/runtime.yml b/ansible_collections/community/hashi_vault/meta/runtime.yml
index 02b09ecd2..9ed765c82 100644
--- a/ansible_collections/community/hashi_vault/meta/runtime.yml
+++ b/ansible_collections/community/hashi_vault/meta/runtime.yml
@@ -1,8 +1,22 @@
---
-requires_ansible: '>=2.11.0'
+requires_ansible: '>=2.14.0'
action_groups:
# let's keep this in alphabetical order
vault:
+ - vault_database_connection_configure
+ - vault_database_connection_delete
+ - vault_database_connection_read
+ - vault_database_connection_reset
+ - vault_database_connections_list
+ - vault_database_role_create
+ - vault_database_role_delete
+ - vault_database_roles_list
+ - vault_database_rotate_root_credentials
+ - vault_database_static_role_create
+ - vault_database_static_role_get_credentials
+ - vault_database_static_role_read
+ - vault_database_static_role_rotate_credentials
+ - vault_database_static_roles_list
- vault_kv1_get
- vault_kv2_delete
- vault_kv2_get
diff --git a/ansible_collections/community/hashi_vault/plugins/doc_fragments/auth.py b/ansible_collections/community/hashi_vault/plugins/doc_fragments/auth.py
index 8c6bd8760..623029037 100644
--- a/ansible_collections/community/hashi_vault/plugins/doc_fragments/auth.py
+++ b/ansible_collections/community/hashi_vault/plugins/doc_fragments/auth.py
@@ -296,12 +296,18 @@ class ModuleDocFragment(object):
cert_auth_public_key:
env:
- name: ANSIBLE_HASHI_VAULT_CERT_AUTH_PUBLIC_KEY
+ vars:
+ - name: ansible_hashi_vault_cert_auth_public_key
+ version_added: 6.2.0
ini:
- section: hashi_vault_collection
key: cert_auth_public_key
cert_auth_private_key:
env:
- name: ANSIBLE_HASHI_VAULT_CERT_AUTH_PRIVATE_KEY
+ vars:
+ - name: ansible_hashi_vault_cert_auth_private_key
+ version_added: 6.2.0
ini:
- section: hashi_vault_collection
key: cert_auth_private_key
diff --git a/ansible_collections/community/hashi_vault/plugins/lookup/hashi_vault.py b/ansible_collections/community/hashi_vault/plugins/lookup/hashi_vault.py
index 1ea9b2c90..9fab815ba 100644
--- a/ansible_collections/community/hashi_vault/plugins/lookup/hashi_vault.py
+++ b/ansible_collections/community/hashi_vault/plugins/lookup/hashi_vault.py
@@ -305,13 +305,14 @@ class LookupModule(HashiVaultLookupBase):
field = s_f[1]
else:
field = None
- self.set_option('secret_field', field)
+
+ self._secret_field = field
def get(self):
'''gets a secret. should always return a list'''
+ field = self._secret_field
secret = self.get_option('secret')
- field = self.get_option('secret_field')
return_as = self.get_option('return_format')
try:
diff --git a/ansible_collections/community/hashi_vault/plugins/lookup/vault_token_create.py b/ansible_collections/community/hashi_vault/plugins/lookup/vault_token_create.py
index 520288897..284f681d9 100644
--- a/ansible_collections/community/hashi_vault/plugins/lookup/vault_token_create.py
+++ b/ansible_collections/community/hashi_vault/plugins/lookup/vault_token_create.py
@@ -29,7 +29,7 @@ DOCUMENTATION = """
it may be more useful to set I(changed_when=false) if you are doing idempotency checks against the target system.
- In check mode, this module will not create a token, and will instead return a basic structure with an empty token.
However, this may not be useful if the token is required for follow on tasks.
- It may be better to use this module with I(check_mode=no) in order to have a valid token that can be used.
+ It may be better to use this module with I(check_mode=false) in order to have a valid token that can be used.
extends_documentation_fragment:
- community.hashi_vault.connection
- community.hashi_vault.connection.plugins
diff --git a/ansible_collections/community/hashi_vault/plugins/lookup/vault_write.py b/ansible_collections/community/hashi_vault/plugins/lookup/vault_write.py
index 6864c76fb..a8c056a73 100644
--- a/ansible_collections/community/hashi_vault/plugins/lookup/vault_write.py
+++ b/ansible_collections/community/hashi_vault/plugins/lookup/vault_write.py
@@ -43,7 +43,9 @@ DOCUMENTATION = """
type: str
required: true
data:
- description: A dictionary to be serialized to JSON and then sent as the request body.
+ description:
+ - A dictionary to be serialized to JSON and then sent as the request body.
+ - If the dictionary contains keys named C(path) or C(wrap_ttl), the call will fail with C(hvac<1.2).
type: dict
required: false
default: {}
@@ -122,8 +124,8 @@ from ansible.utils.display import Display
from ansible.module_utils.six import raise_from
-from ansible_collections.community.hashi_vault.plugins.plugin_utils._hashi_vault_lookup_base import HashiVaultLookupBase
-from ansible_collections.community.hashi_vault.plugins.module_utils._hashi_vault_common import HashiVaultValueError
+from ..plugin_utils._hashi_vault_lookup_base import HashiVaultLookupBase
+from ..module_utils._hashi_vault_common import HashiVaultValueError
display = Display()
@@ -164,7 +166,16 @@ class LookupModule(HashiVaultLookupBase):
for term in terms:
try:
- response = client.write(path=term, wrap_ttl=wrap_ttl, **data)
+ try:
+ # TODO: write_data will eventually turn back into write
+ # see: https://github.com/hvac/hvac/issues/1034
+ response = client.write_data(path=term, wrap_ttl=wrap_ttl, data=data)
+ except AttributeError as e:
+ # https://github.com/ansible-collections/community.hashi_vault/issues/389
+ if "path" in data or "wrap_ttl" in data:
+ raise_from(AnsibleError("To use 'path' or 'wrap_ttl' as data keys, use hvac >= 1.2"), e)
+ else:
+ response = client.write(path=term, wrap_ttl=wrap_ttl, **data)
except hvac.exceptions.Forbidden as e:
raise_from(AnsibleError("Forbidden: Permission Denied to path '%s'." % term), e)
except hvac.exceptions.InvalidPath as e:
diff --git a/ansible_collections/community/hashi_vault/plugins/module_utils/_auth_method_token.py b/ansible_collections/community/hashi_vault/plugins/module_utils/_auth_method_token.py
index 3b66b1937..2d95b67c3 100644
--- a/ansible_collections/community/hashi_vault/plugins/module_utils/_auth_method_token.py
+++ b/ansible_collections/community/hashi_vault/plugins/module_utils/_auth_method_token.py
@@ -81,7 +81,7 @@ class HashiVaultAuthMethodToken(HashiVaultAuthMethodBase):
raise HashiVaultValueError("No Vault Token specified or discovered.")
def authenticate(self, client, use_token=True, lookup_self=False):
- token = self._stringify(self._options.get_option('token'))
+ token = self._options.get_option('token')
validate = self._options.get_option_default('token_validate')
response = None
diff --git a/ansible_collections/community/hashi_vault/plugins/module_utils/_connection_options.py b/ansible_collections/community/hashi_vault/plugins/module_utils/_connection_options.py
index f570479d0..726a9a4f8 100644
--- a/ansible_collections/community/hashi_vault/plugins/module_utils/_connection_options.py
+++ b/ansible_collections/community/hashi_vault/plugins/module_utils/_connection_options.py
@@ -100,11 +100,11 @@ class HashiVaultConnectionOptions(HashiVaultOptionGroupBase):
# validate_certs is only used to optionally change the value of ca_cert
def _filter(k, v):
- return v is not None and k != 'validate_certs'
+ return v is not None and k not in ('validate_certs', 'ca_cert')
# our transformed ca_cert value will become the verify parameter for the hvac client
hvopts = self._options.get_filtered_options(_filter, *self.OPTIONS)
- hvopts['verify'] = hvopts.pop('ca_cert')
+ hvopts['verify'] = self._conopt_verify
retry_action = hvopts.pop('retry_action')
if 'retries' in hvopts:
@@ -255,6 +255,6 @@ class HashiVaultConnectionOptions(HashiVaultOptionGroupBase):
validate_certs = True
if not (validate_certs and ca_cert):
- self._options.set_option('ca_cert', validate_certs)
+ self._conopt_verify = validate_certs
else:
- self._options.set_option('ca_cert', to_text(ca_cert, errors='surrogate_or_strict'))
+ self._conopt_verify = to_text(ca_cert, errors='surrogate_or_strict')
diff --git a/ansible_collections/community/hashi_vault/plugins/module_utils/_hashi_vault_common.py b/ansible_collections/community/hashi_vault/plugins/module_utils/_hashi_vault_common.py
index b39431c05..471022e1f 100644
--- a/ansible_collections/community/hashi_vault/plugins/module_utils/_hashi_vault_common.py
+++ b/ansible_collections/community/hashi_vault/plugins/module_utils/_hashi_vault_common.py
@@ -25,54 +25,18 @@ except ImportError:
HAS_HVAC = False
-def _stringify(input):
- '''
- This method is primarily used to Un-Unsafe values that come from Ansible.
- We want to remove the Unsafe context so that libraries don't get confused
- by the values.
- '''
-
- # Since this is a module_util, and will be used by both plugins and modules,
- # we cannot import the AnsibleUnsafe* types, because they are controller-only.
- # However, they subclass the native types, so we can check for that.
-
- # bytes is the only consistent type to check against in both py2 and py3
- if isinstance(input, bytes):
- # seems redundant, but this will give us a regular bytes object even
- # when the input is AnsibleUnsafeBytes
- return bytes(input)
- else:
- # instead of checking for py2 vs. py3 to cast to str or unicode,
- # let's get the type from the literal.
- return type(u'')(input)
-
-
class HashiVaultValueError(ValueError):
'''Use in common code to raise an Exception that can be turned into AnsibleError or used to fail_json()'''
class HashiVaultHelper():
-
- STRINGIFY_CANDIDATES = set([
- 'token', # Token will end up in a header, requests requires headers to be str or bytes,
- # and newer versions of requests stopped converting automatically. Because our
- # token could have been passed in from a previous lookup call, it could be one
- # of the AnsibleUnsafe types instead, causing a failure. Tokens should always
- # be strings, so we will convert them.
- 'namespace', # namespace is also set in a header
- ])
-
def __init__(self):
# TODO move hvac checking here?
pass
- @staticmethod
- def _stringify(input):
- return _stringify(input)
-
def get_vault_client(
self,
- hashi_vault_logout_inferred_token=True, hashi_vault_revoke_on_logout=False, hashi_vault_stringify_args=True,
+ hashi_vault_logout_inferred_token=True, hashi_vault_revoke_on_logout=False,
**kwargs
):
'''
@@ -84,16 +48,8 @@ class HashiVaultHelper():
:param hashi_vault_revoke_on_logout: if True revokes any current token on logout. Only used if a logout is performed. Not recommended.
:type hashi_vault_revoke_on_logout: bool
-
- :param hashi_vault_stringify_args: if True converts a specific set of defined kwargs to a string type.
- :type hashi_vault_stringify_args: bool
'''
- if hashi_vault_stringify_args:
- for key in kwargs.keys():
- if key in self.STRINGIFY_CANDIDATES:
- kwargs[key] = self._stringify(kwargs[key])
-
client = hvac.Client(**kwargs)
# logout to prevent accidental use of inferred tokens
@@ -296,7 +252,3 @@ class HashiVaultAuthMethodBase(HashiVaultOptionGroupBase):
def deprecate(self, message, version=None, date=None, collection_name=None):
self._deprecator(message, version=version, date=date, collection_name=collection_name)
-
- @staticmethod
- def _stringify(input):
- return _stringify(input)
diff --git a/ansible_collections/community/hashi_vault/plugins/modules/vault_database_connection_configure.py b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_connection_configure.py
new file mode 100644
index 000000000..035f2c4f5
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_connection_configure.py
@@ -0,0 +1,193 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# (c) 2024, Martin Chmielewski (@M4rt1nCh)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+DOCUMENTATION = r"""
+module: vault_database_connection_configure
+version_added: 6.2.0
+author:
+ - Martin Chmielewski (@M4rt1nCh)
+short_description: Configures the database engine
+requirements:
+ - C(hvac) (L(Python library,https://hvac.readthedocs.io/en/stable/overview.html))
+ - For detailed requirements, see R(the collection requirements page,ansible_collections.community.hashi_vault.docsite.user_guide.requirements).
+description:
+ - Creates a L(new database connection for a database secrets engine,https://hvac.readthedocs.io/en/stable/usage/secrets_engines/database.html#configuration),
+ identified by its O(engine_mount_point) in HashiCorp Vault.
+notes:
+ - The database needs to be created and available to connect before you can configure the database secrets engine using the above configure method.
+ - This module always reports C(changed) status because it cannot guarantee idempotence.
+ - Use C(changed_when) to control that in cases where the operation is known to not change state.
+attributes:
+ check_mode:
+ support: partial
+ details:
+ - In check mode, a sample response will be returned, but the create / update will not be performed in Hashicorp Vault.
+extends_documentation_fragment:
+ - community.hashi_vault.attributes
+ - community.hashi_vault.attributes.action_group
+ - community.hashi_vault.connection
+ - community.hashi_vault.auth
+ - community.hashi_vault.engine_mount
+options:
+ connection_name:
+ description: Name of the database connection.
+ type: str
+ required: True
+ plugin_name:
+ description: Plugin name used to connect to the database
+ type: str
+ required: True
+ allowed_roles:
+ description: Allowed roles
+ type: list
+ elements: str
+ required: True
+ connection_url:
+ description: Connection URL to the database
+ type: str
+ required: True
+ connection_username:
+ description: Username to connect to the database
+ type: str
+ required: True
+ connection_password:
+ description: Password to connect to the database
+ type: str
+ required: True
+"""
+
+EXAMPLES = r"""
+- name: Create a new Database Connection with the default mount point
+ community.hashi_vault.vault_database_connection_configure:
+ url: https://vault:8201
+ auth_method: userpass
+ username: '{{ user }}'
+ password: '{{ passwd }}'
+ connection_name: MyName
+ plugin_name: postgresql-database-plugin
+ connection_url: postgresql://{{'{{username}}'}}:{{'{{password}}'}}@postgres:5432/postgres?sslmode=disable
+ connection_username: SomeUser
+ connection_password: SomePass
+ register: result
+
+- name: Display the result of the operation
+ ansible.builtin.debug:
+ msg: "{{ result }}"
+
+
+- name: Create a new Database Connection with a custom mount point
+ community.hashi_vault.vault_database_connection_configure:
+ url: https://vault:8201
+ auth_method: userpass
+ username: '{{ user }}'
+ password: '{{ passwd }}'
+ engine_mount_point: db1
+ connection_name: MyName
+ plugin_name: postgresql-database-plugin
+ connection_url: postgresql://{{'{{username}}'}}:{{'{{password}}'}}@postgres:5432/postgres?sslmode=disable
+ connection_username: SomeUser
+ connection_password: SomePass
+ register: result
+
+- name: Display the result of the operation
+ ansible.builtin.debug:
+ msg: "{{ result }}"
+"""
+
+RETURN = r""""""
+
+import traceback
+
+from ansible.module_utils._text import to_native
+from ansible.module_utils.basic import missing_required_lib
+
+from ..module_utils._hashi_vault_module import HashiVaultModule
+from ..module_utils._hashi_vault_common import HashiVaultValueError
+
+try:
+ import hvac
+except ImportError:
+ HAS_HVAC = False
+ HVAC_IMPORT_ERROR = traceback.format_exc()
+else:
+ HVAC_IMPORT_ERROR = None
+ HAS_HVAC = True
+
+
+def run_module():
+ argspec = HashiVaultModule.generate_argspec(
+ engine_mount_point=dict(type="str", required=False),
+ plugin_name=dict(type="str", required=True),
+ allowed_roles=dict(type="list", required=True, elements="str"),
+ connection_name=dict(type="str", required=True),
+ connection_url=dict(type="str", required=True),
+ connection_username=dict(type="str", required=True),
+ connection_password=dict(type="str", required=True, no_log=True),
+ )
+
+ module = HashiVaultModule(argument_spec=argspec, supports_check_mode=True)
+
+ if not HAS_HVAC:
+ module.fail_json(msg=missing_required_lib("hvac"), exception=HVAC_IMPORT_ERROR)
+
+ if module.check_mode is True:
+ module.exit_json(changed=True)
+
+ parameters = {}
+ engine_mount_point = module.params.get("engine_mount_point", None)
+ if engine_mount_point is not None:
+ parameters["mount_point"] = engine_mount_point
+ parameters["plugin_name"] = module.params.get("plugin_name")
+ parameters["allowed_roles"] = module.params.get("allowed_roles")
+ parameters["connection_url"] = module.params.get("connection_url")
+ parameters["name"] = module.params.get("connection_name")
+ parameters["username"] = module.params.get("connection_username")
+ parameters["password"] = module.params.get("connection_password")
+
+ module.connection_options.process_connection_options()
+ client_args = module.connection_options.get_hvac_connection_options()
+ client = module.helper.get_vault_client(**client_args)
+
+ try:
+ module.authenticator.validate()
+ module.authenticator.authenticate(client)
+ except (NotImplementedError, HashiVaultValueError) as e:
+ module.fail_json(msg=to_native(e), exception=traceback.format_exc())
+
+ try:
+ client.secrets.database.configure(**parameters)
+ except hvac.exceptions.Forbidden as e:
+ module.fail_json(
+ msg="Forbidden: Permission Denied to path ['%s']." % engine_mount_point
+ or "database",
+ exception=traceback.format_exc(),
+ )
+ except hvac.exceptions.InvalidPath as e:
+ module.fail_json(
+ msg="Invalid or missing path ['%s/config/%s']."
+ % (engine_mount_point or "database", parameters["name"]),
+ exception=traceback.format_exc(),
+ )
+ except hvac.exceptions.InvalidRequest as e:
+ module.fail_json(
+ msg="Error creating database connection ['%s/config/%s']. Please analyze the traceback for further details."
+ % (engine_mount_point or "database", parameters["name"]),
+ exception=traceback.format_exc(),
+ )
+ else:
+ module.exit_json(changed=True)
+
+
+def main():
+ run_module()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/hashi_vault/plugins/modules/vault_database_connection_delete.py b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_connection_delete.py
new file mode 100644
index 000000000..4579d15f8
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_connection_delete.py
@@ -0,0 +1,146 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# (c) 2024, Martin Chmielewski (@M4rt1nCh)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+DOCUMENTATION = r"""
+module: vault_database_connection_delete
+version_added: 6.2.0
+author:
+ - Martin Chmielewski (@M4rt1nCh)
+short_description: Delete a Database Connection
+requirements:
+ - C(hvac) (L(Python library,https://hvac.readthedocs.io/en/stable/overview.html))
+ - For detailed requirements, see R(the collection requirements page,ansible_collections.community.hashi_vault.docsite.user_guide.requirements).
+description:
+ - Deletes a L(Database Connection,https://hvac.readthedocs.io/en/stable/usage/secrets_engines/database.html#delete-connection),
+ identified by its O(connection_name) from HashiCorp Vault.
+notes:
+ - This module always reports C(changed) status because it cannot guarantee idempotence.
+ - Use C(changed_when) to control that in cases where the operation is known to not change state.
+attributes:
+ check_mode:
+ support: partial
+ details:
+ - In check mode, a sample response will be returned, but the deletion will not be performed in Hashicorp Vault.
+extends_documentation_fragment:
+ - community.hashi_vault.attributes
+ - community.hashi_vault.attributes.action_group
+ - community.hashi_vault.connection
+ - community.hashi_vault.auth
+ - community.hashi_vault.engine_mount
+options:
+ connection_name:
+ description: The connection name to be deleted.
+ type: str
+ required: True
+"""
+
+EXAMPLES = r"""
+- name: Delete a Database Connection with the default mount point
+ community.hashi_vault.vault_database_connection_delete:
+ url: https://vault:8201
+ auth_method: userpass
+ username: '{{ user }}'
+ password: '{{ passwd }}'
+ connection_name: SomeName
+ register: result
+
+- name: Display the result of the operation
+ ansible.builtin.debug:
+ msg: "{{ result }}"
+
+- name: Delete a Database Connection with a custom mount point
+ community.hashi_vault.vault_database_connection_delete:
+ url: https://vault:8201
+ auth_method: userpass
+ username: '{{ user }}'
+ password: '{{ passwd }}'
+ engine_mount_point: db1
+ connection_name: SomeName
+ register: result
+
+- name: Display the result of the operation
+ ansible.builtin.debug:
+ msg: "{{ result }}"
+"""
+
+RETURN = r""""""
+
+import traceback
+
+from ansible.module_utils._text import to_native
+from ansible.module_utils.basic import missing_required_lib
+
+from ..module_utils._hashi_vault_module import HashiVaultModule
+from ..module_utils._hashi_vault_common import HashiVaultValueError
+
+try:
+ import hvac
+except ImportError:
+ HAS_HVAC = False
+ HVAC_IMPORT_ERROR = traceback.format_exc()
+else:
+ HVAC_IMPORT_ERROR = None
+ HAS_HVAC = True
+
+
+def run_module():
+ argspec = HashiVaultModule.generate_argspec(
+ engine_mount_point=dict(type="str", required=False),
+ connection_name=dict(type="str", required=True),
+ )
+
+ module = HashiVaultModule(argument_spec=argspec, supports_check_mode=True)
+
+ if not HAS_HVAC:
+ module.fail_json(msg=missing_required_lib("hvac"), exception=HVAC_IMPORT_ERROR)
+
+ if module.check_mode is True:
+ module.exit_json(changed=True)
+
+ parameters = {}
+ engine_mount_point = module.params.get("engine_mount_point", None)
+ if engine_mount_point is not None:
+ parameters["mount_point"] = engine_mount_point
+ parameters["name"] = module.params.get("connection_name")
+
+ module.connection_options.process_connection_options()
+ client_args = module.connection_options.get_hvac_connection_options()
+ client = module.helper.get_vault_client(**client_args)
+
+ try:
+ module.authenticator.validate()
+ module.authenticator.authenticate(client)
+ except (NotImplementedError, HashiVaultValueError) as e:
+ module.fail_json(msg=to_native(e), exception=traceback.format_exc())
+
+ try:
+ client.secrets.database.delete_connection(**parameters)
+ except hvac.exceptions.Forbidden as e:
+ module.fail_json(
+ msg="Forbidden: Permission Denied to path ['%s']." % engine_mount_point
+ or "database",
+ exception=traceback.format_exc(),
+ )
+ except hvac.exceptions.InvalidPath as e:
+ module.fail_json(
+ msg="Invalid or missing path ['%s/config/%s']."
+ % (engine_mount_point or "database", parameters["name"]),
+ exception=traceback.format_exc(),
+ )
+ else:
+ module.exit_json(changed=True)
+
+
+def main():
+ run_module()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/hashi_vault/plugins/modules/vault_database_connection_read.py b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_connection_read.py
new file mode 100644
index 000000000..4d4fdb0f5
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_connection_read.py
@@ -0,0 +1,162 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# (c) 2024, Martin Chmielewski (@M4rt1nCh)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+DOCUMENTATION = r"""
+module: vault_database_connection_read
+version_added: 6.2.0
+author:
+ - Martin Chmielewski (@M4rt1nCh)
+short_description: Returns the configuration settings for a O(connection_name)
+requirements:
+ - C(hvac) (L(Python library,https://hvac.readthedocs.io/en/stable/overview.html))
+ - For detailed requirements, see R(the collection requirements page,ansible_collections.community.hashi_vault.docsite.user_guide.requirements).
+description:
+ - L(Reads a Database Connection,https://hvac.readthedocs.io/en/stable/usage/secrets_engines/database.html#read-configuration),
+ identified by its O(connection_name) from Hashcorp Vault.
+notes:
+ - This module always reports C(changed) as False as it is a read operation that doesn't modify data.
+ - Use C(changed_when) to control that in cases where the operation is known to not change state.
+extends_documentation_fragment:
+ - community.hashi_vault.attributes
+ - community.hashi_vault.attributes.action_group
+ - community.hashi_vault.attributes.check_mode_read_only
+ - community.hashi_vault.connection
+ - community.hashi_vault.auth
+ - community.hashi_vault.engine_mount
+options:
+ connection_name:
+ description: The connection name to be read.
+ type: str
+ required: True
+"""
+
+EXAMPLES = r"""
+- name: Read a Database Connection with the default mount point
+ community.hashi_vault.vault_database_connection_read:
+ url: https://vault:8201
+ auth_method: userpass
+ username: '{{ user }}'
+ password: '{{ passwd }}'
+ connection_name: SomeName
+ register: result
+
+- name: Display the result of the operation
+ ansible.builtin.debug:
+ msg: "{{ result }}"
+
+- name: Read a Database Connection with a custom mount point
+ community.hashi_vault.vault_database_connection_read:
+ url: https://vault:8201
+ auth_method: userpass
+ username: '{{ user }}'
+ password: '{{ passwd }}'
+ engine_mount_point: db1
+ register: result
+
+- name: Display the result of the operation
+ ansible.builtin.debug:
+ msg: "{{ result }}"
+"""
+
+RETURN = r"""
+data: &data
+ description: The C(data) field of the RV(raw) result. This can also be accessed via RV(raw.data).
+ returned: success
+ type: dict
+ sample: &data_sample
+ allowed_roles: []
+ connection_details:
+ connection_url: "postgresql://{{username}}:{{password}}@postgres:5432/postgres?sslmode=disable"
+ username: "UserName"
+ password_policy": ""
+ plugin_name": "postgresql-database-plugin"
+ plugin_version": ""
+ root_credentials_rotate_statements": []
+raw:
+ description: The raw result of the operation
+ returned: success
+ type: dict
+ contains:
+ data: *data
+ sample:
+ auth: null,
+ data: *data_sample
+"""
+
+import traceback
+
+from ansible.module_utils._text import to_native
+from ansible.module_utils.basic import missing_required_lib
+
+from ..module_utils._hashi_vault_module import HashiVaultModule
+from ..module_utils._hashi_vault_common import HashiVaultValueError
+
+try:
+ import hvac
+except ImportError:
+ HAS_HVAC = False
+ HVAC_IMPORT_ERROR = traceback.format_exc()
+else:
+ HVAC_IMPORT_ERROR = None
+ HAS_HVAC = True
+
+
+def run_module():
+ argspec = HashiVaultModule.generate_argspec(
+ engine_mount_point=dict(type="str", required=False),
+ connection_name=dict(type="str", required=True),
+ )
+
+ module = HashiVaultModule(argument_spec=argspec, supports_check_mode=True)
+
+ if not HAS_HVAC:
+ module.fail_json(msg=missing_required_lib("hvac"), exception=HVAC_IMPORT_ERROR)
+
+ parameters = {}
+ engine_mount_point = module.params.get("engine_mount_point", None)
+ if engine_mount_point is not None:
+ parameters["mount_point"] = engine_mount_point
+ parameters["name"] = module.params.get("connection_name")
+
+ module.connection_options.process_connection_options()
+ client_args = module.connection_options.get_hvac_connection_options()
+ client = module.helper.get_vault_client(**client_args)
+
+ try:
+ module.authenticator.validate()
+ module.authenticator.authenticate(client)
+ except (NotImplementedError, HashiVaultValueError) as e:
+ module.fail_json(msg=to_native(e), exception=traceback.format_exc())
+
+ try:
+ raw = client.secrets.database.read_connection(**parameters)
+ except hvac.exceptions.Forbidden as e:
+ module.fail_json(
+ msg="Forbidden: Permission Denied to path ['%s']." % engine_mount_point
+ or "database",
+ exception=traceback.format_exc(),
+ )
+ except hvac.exceptions.InvalidPath as e:
+ module.fail_json(
+ msg="Invalid or missing path ['%s/config/%s']."
+ % (engine_mount_point or "database", parameters["name"]),
+ exception=traceback.format_exc(),
+ )
+
+ data = raw["data"]
+ module.exit_json(raw=raw, data=data, changed=False)
+
+
+def main():
+ run_module()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/hashi_vault/plugins/modules/vault_database_connection_reset.py b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_connection_reset.py
new file mode 100644
index 000000000..858fdfc7f
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_connection_reset.py
@@ -0,0 +1,145 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# (c) 2024, Martin Chmielewski (@M4rt1nCh)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+DOCUMENTATION = r"""
+module: vault_database_connection_reset
+version_added: 6.2.0
+author:
+ - Martin Chmielewski (@M4rt1nCh)
+short_description: Closes a O(connection_name) and its underlying plugin and restarts it with the configuration stored
+requirements:
+ - C(hvac) (L(Python library,https://hvac.readthedocs.io/en/stable/overview.html))
+ - For detailed requirements, see R(the collection requirements page,ansible_collections.community.hashi_vault.docsite.user_guide.requirements).
+description:
+ - L(Resets a Database Connection,https://hvac.readthedocs.io/en/stable/usage/secrets_engines/database.html#reset-connection).
+notes:
+ - This module always reports C(changed) status because it cannot guarantee idempotence.
+ - Use C(changed_when) to control that in cases where the operation is known to not change state.
+attributes:
+ check_mode:
+ support: partial
+ details:
+ - In check mode, a sample response will be returned, but the reset will not be performed in Hashicorp Vault.
+extends_documentation_fragment:
+ - community.hashi_vault.attributes
+ - community.hashi_vault.attributes.action_group
+ - community.hashi_vault.connection
+ - community.hashi_vault.auth
+ - community.hashi_vault.engine_mount
+options:
+ connection_name:
+ description: The connection name to be resetted.
+ type: str
+ required: True
+"""
+
+EXAMPLES = r"""
+- name: Reset a Database Connection with the default mount point
+ community.hashi_vault.vault_database_connection_reset:
+ url: https://vault:8201
+ auth_method: userpass
+ username: '{{ user }}'
+ password: '{{ passwd }}'
+ connection_name: SomeName
+ register: result
+
+- name: Display the result of the operation
+ ansible.builtin.debug:
+ msg: "{{ result }}"
+
+- name: Reset a Database Connection with a custom mount point
+ community.hashi_vault.vault_database_connection_reset:
+ url: https://vault:8201
+ auth_method: userpass
+ username: '{{ user }}'
+ password: '{{ passwd }}'
+ engine_mount_point: db1
+ connection_name: SomeName
+ register: result
+
+- name: Display the result of the operation
+ ansible.builtin.debug:
+ msg: "{{ result }}"
+"""
+
+RETURN = r""""""
+
+import traceback
+
+from ansible.module_utils._text import to_native
+from ansible.module_utils.basic import missing_required_lib
+
+from ..module_utils._hashi_vault_module import HashiVaultModule
+from ..module_utils._hashi_vault_common import HashiVaultValueError
+
+try:
+ import hvac
+except ImportError:
+ HAS_HVAC = False
+ HVAC_IMPORT_ERROR = traceback.format_exc()
+else:
+ HVAC_IMPORT_ERROR = None
+ HAS_HVAC = True
+
+
+def run_module():
+ argspec = HashiVaultModule.generate_argspec(
+ engine_mount_point=dict(type="str", required=False),
+ connection_name=dict(type="str", required=True),
+ )
+
+ module = HashiVaultModule(argument_spec=argspec, supports_check_mode=True)
+
+ if not HAS_HVAC:
+ module.fail_json(msg=missing_required_lib("hvac"), exception=HVAC_IMPORT_ERROR)
+
+ if module.check_mode is True:
+ module.exit_json(changed=True)
+
+ parameters = {}
+ engine_mount_point = module.params.get("engine_mount_point", None)
+ if engine_mount_point is not None:
+ parameters["mount_point"] = engine_mount_point
+ parameters["name"] = module.params.get("connection_name")
+
+ module.connection_options.process_connection_options()
+ client_args = module.connection_options.get_hvac_connection_options()
+ client = module.helper.get_vault_client(**client_args)
+
+ try:
+ module.authenticator.validate()
+ module.authenticator.authenticate(client)
+ except (NotImplementedError, HashiVaultValueError) as e:
+ module.fail_json(msg=to_native(e), exception=traceback.format_exc())
+
+ try:
+ client.secrets.database.reset_connection(**parameters)
+ except hvac.exceptions.Forbidden as e:
+ module.fail_json(
+ msg="Forbidden: Permission Denied to path ['%s']." % engine_mount_point
+ or "database",
+ exception=traceback.format_exc(),
+ )
+ except hvac.exceptions.InvalidPath as e:
+ module.fail_json(
+ msg="Invalid or missing path ['%s/reset/%s']."
+ % (engine_mount_point or "database", parameters["name"]),
+ exception=traceback.format_exc(),
+ )
+ else:
+ module.exit_json(changed=True)
+
+
+def main():
+ run_module()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/hashi_vault/plugins/modules/vault_database_connections_list.py b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_connections_list.py
new file mode 100644
index 000000000..f570947d5
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_connections_list.py
@@ -0,0 +1,176 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# (c) 2024, Martin Chmielewski (@M4rt1nCh)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+DOCUMENTATION = r"""
+module: vault_database_connections_list
+version_added: 6.2.0
+author:
+ - Martin Chmielewski (@M4rt1nCh)
+short_description: Returns a list of available connections
+requirements:
+ - C(hvac) (L(Python library,https://hvac.readthedocs.io/en/stable/overview.html))
+ - For detailed requirements, see R(the collection requirements page,ansible_collections.community.hashi_vault.docsite.user_guide.requirements).
+description:
+ - L(List Database Connections,https://hvac.readthedocs.io/en/stable/usage/secrets_engines/database.html#list-connections).
+notes:
+ - This module always reports C(changed) as False as it is a read operation that doesn't modify data.
+ - Use C(changed_when) to control that in cases where the operation is known to not change state.
+extends_documentation_fragment:
+ - community.hashi_vault.attributes
+ - community.hashi_vault.attributes.action_group
+ - community.hashi_vault.attributes.check_mode_read_only
+ - community.hashi_vault.connection
+ - community.hashi_vault.auth
+ - community.hashi_vault.engine_mount
+"""
+
+EXAMPLES = r"""
+- name: List Database Connections with the default mount point
+ community.hashi_vault.vault_database_connections_list:
+ url: https://vault:8201
+ auth_method: userpass
+ username: '{{ user }}'
+ password: '{{ passwd }}'
+ register: result
+
+- name: Display the result of the operation
+ ansible.builtin.debug:
+ msg: "{{ result }}"
+
+- name: List Database Connections with a custom mount point
+ community.hashi_vault.vault_database_connections_list:
+ url: https://vault:8201
+ auth_method: userpass
+ username: '{{ user }}'
+ password: '{{ passwd }}'
+ engine_mount_point: db1
+ register: result
+
+- name: Display the result of the operation
+ ansible.builtin.debug:
+ msg: "{{ result }}"
+"""
+
+RETURN = r"""
+data:
+ description: The C(data) field of raw result. This can also be accessed via RV(raw.data).
+ returned: success
+ type: dict
+ contains: &data_contains
+ keys:
+ description: The list of database connections.
+ returned: success
+ type: list
+ elements: str
+ sample: &sample_connections ["role1", "role2", "role3"]
+ sample:
+ keys: *sample_connections
+connections:
+ description: The list of database connections or en empty list. This can also be accessed via RV(data.keys) or RV(raw.data.keys).
+ returned: success
+ type: list
+ elements: str
+ sample: *sample_connections
+raw:
+ description: The raw result of the operation.
+ returned: success
+ type: dict
+ contains:
+ data:
+ description: The data field of the API response.
+ returned: success
+ type: dict
+ contains: *data_contains
+ sample:
+ auth: null
+ data:
+ keys: *sample_connections
+ lease_duration": 0
+ lease_id: ""
+ renewable: false
+ request_id: "123456"
+ warnings: null
+ wrap_info: null
+"""
+
+import traceback
+
+from ansible.module_utils._text import to_native
+from ansible.module_utils.basic import missing_required_lib
+
+from ..module_utils._hashi_vault_module import HashiVaultModule
+from ..module_utils._hashi_vault_common import HashiVaultValueError
+
+try:
+ import hvac
+except ImportError:
+ HAS_HVAC = False
+ HVAC_IMPORT_ERROR = traceback.format_exc()
+else:
+ HVAC_IMPORT_ERROR = None
+ HAS_HVAC = True
+
+
+def run_module():
+ argspec = HashiVaultModule.generate_argspec(
+ engine_mount_point=dict(type="str", required=False),
+ )
+
+ module = HashiVaultModule(argument_spec=argspec, supports_check_mode=True)
+
+ if not HAS_HVAC:
+ module.fail_json(msg=missing_required_lib("hvac"), exception=HVAC_IMPORT_ERROR)
+
+ parameters = {}
+ engine_mount_point = module.params.get("engine_mount_point", None)
+ if engine_mount_point is not None:
+ parameters["mount_point"] = engine_mount_point
+
+ module.connection_options.process_connection_options()
+ client_args = module.connection_options.get_hvac_connection_options()
+ client = module.helper.get_vault_client(**client_args)
+
+ try:
+ module.authenticator.validate()
+ module.authenticator.authenticate(client)
+ except (NotImplementedError, HashiVaultValueError) as e:
+ module.fail_json(msg=to_native(e), exception=traceback.format_exc())
+
+ try:
+ raw = client.secrets.database.list_connections(**parameters)
+ except hvac.exceptions.Forbidden as e:
+ module.fail_json(
+ msg="Forbidden: Permission Denied to path ['%s']." % engine_mount_point
+ or "database",
+ exception=traceback.format_exc(),
+ )
+ except hvac.exceptions.InvalidPath as e:
+ module.fail_json(
+ msg="Invalid or missing path ['%s/config']."
+ % (engine_mount_point or "database"),
+ exception=traceback.format_exc(),
+ )
+
+ data = raw.get("data", {"keys": []})
+ connections = data["keys"]
+ module.exit_json(
+ raw=raw,
+ connections=connections,
+ data=data,
+ changed=False,
+ )
+
+
+def main():
+ run_module()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/hashi_vault/plugins/modules/vault_database_role_create.py b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_role_create.py
new file mode 100644
index 000000000..c005e27e7
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_role_create.py
@@ -0,0 +1,207 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# (c) 2024, Martin Chmielewski (@M4rt1nCh)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+DOCUMENTATION = r"""
+module: vault_database_role_create
+version_added: 6.2.0
+author:
+ - Martin Chmielewski (@M4rt1nCh)
+short_description: Creates or updates a (dynamic) role definition
+requirements:
+ - C(hvac) (L(Python library,https://hvac.readthedocs.io/en/stable/overview.html))
+ - For detailed requirements, see R(the collection requirements page,ansible_collections.community.hashi_vault.docsite.user_guide.requirements).
+description:
+ - L(Creates or updates a dynamic role definition,https://hvac.readthedocs.io/en/stable/usage/secrets_engines/database.html#create-static-role).
+notes:
+ - This module always reports C(changed) status because it cannot guarantee idempotence.
+ - Use C(changed_when) to control that in cases where the operation is known to not change state.
+attributes:
+ check_mode:
+ support: partial
+ details:
+ - In check mode, a sample response will be returned, but the role creation will not be performed in Hashicorp Vault.
+extends_documentation_fragment:
+ - community.hashi_vault.attributes
+ - community.hashi_vault.attributes.action_group
+ - community.hashi_vault.connection
+ - community.hashi_vault.auth
+ - community.hashi_vault.engine_mount
+options:
+ connection_name:
+ description: The connection name under which the role should be created.
+ type: str
+ required: True
+ role_name:
+ description: The name of the role that should be created.
+ type: str
+ required: True
+ creation_statements:
+ description: Specifies the database statements executed to create and configure a user.
+ type: list
+ required: True
+ elements: str
+ revocation_statements:
+ description: Specifies the database statements to be executed to revoke a user.
+ type: list
+ required: False
+ elements: str
+ rollback_statements:
+ description: Specifies the database statements to be executed to rollback a create operation in the event of an error.
+ type: list
+ required: False
+ elements: str
+ renew_statements:
+ description: Specifies the database statements to be executed to renew a user
+ type: list
+ required: False
+ elements: str
+ default_ttl:
+ description: Default TTL for the role.
+ type: int
+ required: False
+ default: 3600
+ max_ttl:
+ description: Max TTL for the role.
+ type: int
+ required: False
+ default: 86400
+"""
+
+EXAMPLES = r"""
+- name: Generate creation statement
+ ansible.builtin.set_fact:
+ creation_statements = [
+ "CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}';",
+ "GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";"
+ ]
+
+- name: Create / update Role with the default mount point
+ community.hashi_vault.vault_database_role_create:
+ url: https://vault:8201
+ auth_method: userpass
+ username: '{{ user }}'
+ password: '{{ passwd }}'
+ connection_name: SomeConnection
+ role_name: SomeRole
+ db_username: '{{ db_username}}'
+ creation_statements: '{{ creation_statements }}'
+ register: result
+
+- name: Display the result of the operation
+ ansible.builtin.debug:
+ msg: "{{ result }}"
+
+- name: Create / update Role with a custom mount point
+ community.hashi_vault.vault_database_role_create:
+ url: https://vault:8201
+ auth_method: userpass
+ username: '{{ user }}'
+ password: '{{ passwd }}'
+ engine_mount_point: db1
+ connection_name: SomeConnection
+ role_name: SomeRole
+ db_username: '{{ db_username}}'
+ creation_statements: '{{ creation_statements }}'
+ register: result
+
+- name: Display the result of the operation
+ ansible.builtin.debug:
+ msg: "{{ result }}"
+"""
+
+RETURN = r""""""
+
+import traceback
+
+from ansible.module_utils._text import to_native
+from ansible.module_utils.basic import missing_required_lib
+
+from ..module_utils._hashi_vault_module import HashiVaultModule
+from ..module_utils._hashi_vault_common import HashiVaultValueError
+
+try:
+ import hvac
+except ImportError:
+ HAS_HVAC = False
+ HVAC_IMPORT_ERROR = traceback.format_exc()
+else:
+ HVAC_IMPORT_ERROR = None
+ HAS_HVAC = True
+
+
+def run_module():
+ argspec = HashiVaultModule.generate_argspec(
+ engine_mount_point=dict(type="str", required=False),
+ connection_name=dict(type="str", required=True),
+ role_name=dict(type="str", required=True),
+ creation_statements=dict(type="list", required=True, elements="str"),
+ revocation_statements=dict(type="list", required=False, elements="str"),
+ rollback_statements=dict(type="list", required=False, elements="str"),
+ renew_statements=dict(type="list", required=False, elements="str"),
+ default_ttl=dict(type="int", required=False, default=3600),
+ max_ttl=dict(type="int", required=False, default=86400),
+ )
+
+ module = HashiVaultModule(argument_spec=argspec, supports_check_mode=True)
+
+ if not HAS_HVAC:
+ module.fail_json(msg=missing_required_lib("hvac"), exception=HVAC_IMPORT_ERROR)
+
+ if module.check_mode is True:
+ module.exit_json(changed=True)
+
+ parameters = {
+ "name": module.params.get("role_name"),
+ "db_name": module.params.get("connection_name"),
+ "creation_statements": module.params.get("creation_statements"),
+ "revocation_statements": module.params.get("revocation_statements"),
+ "rollback_statements": module.params.get("rollback_statements"),
+ "renew_statements": module.params.get("renew_statements"),
+ "default_ttl": module.params.get("default_ttl"),
+ "max_ttl": module.params.get("max_ttl"),
+ }
+ engine_mount_point = module.params.get("engine_mount_point", None)
+ if engine_mount_point is not None:
+ parameters["mount_point"] = engine_mount_point
+
+ module.connection_options.process_connection_options()
+ client_args = module.connection_options.get_hvac_connection_options()
+ client = module.helper.get_vault_client(**client_args)
+
+ try:
+ module.authenticator.validate()
+ module.authenticator.authenticate(client)
+ except (NotImplementedError, HashiVaultValueError) as e:
+ module.fail_json(msg=to_native(e), exception=traceback.format_exc())
+
+ try:
+ client.secrets.database.create_role(**parameters)
+ except hvac.exceptions.Forbidden as e:
+ module.fail_json(
+ msg="Forbidden: Permission Denied to path ['%s']." % engine_mount_point
+ or "database",
+ exception=traceback.format_exc(),
+ )
+ except hvac.exceptions.InvalidPath as e:
+ module.fail_json(
+ msg="Invalid or missing path ['%s/roles/%s']."
+ % (engine_mount_point or "database", parameters["name"]),
+ exception=traceback.format_exc(),
+ )
+ else:
+ module.exit_json(changed=True)
+
+
+def main():
+ run_module()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/hashi_vault/plugins/modules/vault_database_role_delete.py b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_role_delete.py
new file mode 100644
index 000000000..7f20e3bba
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_role_delete.py
@@ -0,0 +1,146 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# (c) 2024, Martin Chmielewski (@M4rt1nCh)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+DOCUMENTATION = r"""
+module: vault_database_role_delete
+version_added: 6.2.0
+author:
+ - Martin Chmielewski (@M4rt1nCh)
+short_description: Delete a role definition
+requirements:
+ - C(hvac) (L(Python library,https://hvac.readthedocs.io/en/stable/overview.html))
+ - For detailed requirements, see R(the collection requirements page,ansible_collections.community.hashi_vault.docsite.user_guide.requirements).
+description:
+ - L(Delete a role definition,https://hvac.readthedocs.io/en/stable/usage/secrets_engines/database.html#delete-a-role).
+notes:
+ - Applies to both static and dynamic roles.
+ - This module always reports C(changed) status because it cannot guarantee idempotence.
+ - Use C(changed_when) to control that in cases where the operation is known to not change state.
+attributes:
+ check_mode:
+ support: partial
+ details:
+ - In check mode, a sample response will be returned, but the deletion will not be performed in Hashicorp Vault.
+extends_documentation_fragment:
+ - community.hashi_vault.attributes
+ - community.hashi_vault.attributes.action_group
+ - community.hashi_vault.connection
+ - community.hashi_vault.auth
+ - community.hashi_vault.engine_mount
+options:
+ role_name:
+ description: The name of the role to rotate credentials for.
+ type: str
+ required: True
+"""
+
+EXAMPLES = r"""
+- name: Delete a Role with the default mount point
+ community.hashi_vault.vault_database_role_delete:
+ url: https://vault:8201
+ auth_method: userpass
+ username: '{{ user }}'
+ password: '{{ passwd }}'
+ role_name: SomeRole
+ register: result
+
+- name: Display the result of the operation
+ ansible.builtin.debug:
+ msg: "{{ result }}"
+
+- name: Delete a Role with a custom mount point
+ community.hashi_vault.vault_database_role_delete:
+ url: https://vault:8201
+ auth_method: userpass
+ username: '{{ user }}'
+ password: '{{ passwd }}'
+ engine_mount_path: db1
+ role_name: SomeRole
+ register: result
+
+- name: Display the result of the operation
+ ansible.builtin.debug:
+ msg: "{{ result }}"
+"""
+
+RETURN = r""""""
+
+import traceback
+
+from ansible.module_utils._text import to_native
+from ansible.module_utils.basic import missing_required_lib
+
+from ..module_utils._hashi_vault_module import HashiVaultModule
+from ..module_utils._hashi_vault_common import HashiVaultValueError
+
+try:
+ import hvac
+except ImportError:
+ HAS_HVAC = False
+ HVAC_IMPORT_ERROR = traceback.format_exc()
+else:
+ HVAC_IMPORT_ERROR = None
+ HAS_HVAC = True
+
+
+def run_module():
+ argspec = HashiVaultModule.generate_argspec(
+ engine_mount_point=dict(type="str", required=False),
+ role_name=dict(type="str", required=True),
+ )
+
+ module = HashiVaultModule(argument_spec=argspec, supports_check_mode=True)
+
+ if not HAS_HVAC:
+ module.fail_json(msg=missing_required_lib("hvac"), exception=HVAC_IMPORT_ERROR)
+
+ if module.check_mode is True:
+ module.exit_json(changed=True)
+
+ parameters = {}
+ engine_mount_point = module.params.get("engine_mount_point", None)
+ if engine_mount_point is not None:
+ parameters["mount_point"] = engine_mount_point
+ parameters["name"] = module.params.get("role_name")
+
+ module.connection_options.process_connection_options()
+ client_args = module.connection_options.get_hvac_connection_options()
+ client = module.helper.get_vault_client(**client_args)
+
+ try:
+ module.authenticator.validate()
+ module.authenticator.authenticate(client)
+ except (NotImplementedError, HashiVaultValueError) as e:
+ module.fail_json(msg=to_native(e), exception=traceback.format_exc())
+
+ try:
+ client.secrets.database.delete_role(**parameters)
+ except hvac.exceptions.Forbidden as e:
+ module.fail_json(
+ msg="Forbidden: Permission Denied to path ['%s']." % engine_mount_point
+ or "database",
+ exception=traceback.format_exc(),
+ )
+ except hvac.exceptions.InvalidPath as e:
+ module.fail_json(
+ msg="Invalid or missing path ['%s/roles/%s']."
+ % (engine_mount_point or "database", parameters["name"]),
+ exception=traceback.format_exc(),
+ )
+ else:
+ module.exit_json(changed=True)
+
+
+def main():
+ run_module()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/hashi_vault/plugins/modules/vault_database_role_read.py b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_role_read.py
new file mode 100644
index 000000000..68157dce1
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_role_read.py
@@ -0,0 +1,175 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# (c) 2024, Martin Chmielewski (@M4rt1nCh)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+DOCUMENTATION = r"""
+module: vault_database_role_read
+version_added: 6.2.0
+author:
+ - Martin Chmielewski (@M4rt1nCh)
+short_description: Queries a dynamic role definition
+requirements:
+ - C(hvac) (L(Python library,https://hvac.readthedocs.io/en/stable/overview.html))
+ - For detailed requirements, see R(the collection requirements page,ansible_collections.community.hashi_vault.docsite.user_guide.requirements).
+description:
+ - L(Queries a role definition,L(reads a static role,https://hvac.readthedocs.io/en/stable/usage/secrets_engines/database.html#read-a-role),
+ identified by its O(role_name).
+notes:
+ - This module always reports C(changed) as False as it is a read operation that doesn't modify data.
+ - Use C(changed_when) to control that in cases where the operation is known to not change state.
+extends_documentation_fragment:
+ - community.hashi_vault.attributes
+ - community.hashi_vault.attributes.action_group
+ - community.hashi_vault.attributes.check_mode_read_only
+ - community.hashi_vault.connection
+ - community.hashi_vault.auth
+ - community.hashi_vault.engine_mount
+options:
+ role_name:
+ description: The role name to be read from Hashicorp Vault.
+ type: str
+ required: True
+"""
+
+EXAMPLES = r"""
+- name: Read Role with a default mount point
+ community.hashi_vault.vault_database_role_read:
+ url: https://vault:8201
+ auth_method: userpass
+ username: '{{ user }}'
+ password: '{{ passwd }}'
+ role_name: SomeRole
+ register: result
+
+- name: Display the result of the operation
+ ansible.builtin.debug:
+ msg: "{{ result }}"
+
+- name: Read Static Role with a custom moint point
+ community.hashi_vault.vault_database_role_read:
+ url: https://vault:8201
+ auth_method: userpass
+ username: '{{ user }}'
+ password: '{{ passwd }}'
+ engine_mount_point: db1
+ role_name: SomeRole
+ register: result
+
+- name: Display the result of the operation
+ ansible.builtin.debug:
+ msg: "{{ result }}"
+
+"""
+
+RETURN = r"""
+data: &data
+ description: The C(data) field of raw result. This can also be accessed via RV(raw.data).
+ returned: success
+ type: dict
+ sample: &data_sample
+ creation_statements: [
+ "CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}';",
+ "GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";"
+ ]
+ credential_type: "password"
+ db_name: "database"
+ default_ttl: 3600
+ max_ttl: 86400
+ renew_statements: []
+ revocation_statements: []
+ rollback_statements: []
+raw:
+ description: The raw result of the operation.
+ returned: success
+ type: dict
+ contains:
+ data: *data
+ sample:
+ auth: null
+ data: *data_sample
+ username: "SomeUser"
+ lease_duration": 0
+ lease_id: ""
+ renewable: false
+ request_id: "123456"
+ warnings: null
+ wrap_info: null
+"""
+
+import traceback
+
+from ansible.module_utils._text import to_native
+from ansible.module_utils.basic import missing_required_lib
+
+from ..module_utils._hashi_vault_module import HashiVaultModule
+from ..module_utils._hashi_vault_common import HashiVaultValueError
+
+try:
+ import hvac
+except ImportError:
+ HAS_HVAC = False
+ HVAC_IMPORT_ERROR = traceback.format_exc()
+else:
+ HVAC_IMPORT_ERROR = None
+ HAS_HVAC = True
+
+
+def run_module():
+ argspec = HashiVaultModule.generate_argspec(
+ engine_mount_point=dict(type="str", required=False),
+ role_name=dict(type="str", required=True),
+ )
+
+ module = HashiVaultModule(argument_spec=argspec, supports_check_mode=True)
+
+ if not HAS_HVAC:
+ module.fail_json(msg=missing_required_lib("hvac"), exception=HVAC_IMPORT_ERROR)
+
+ parameters = {}
+ engine_mount_point = module.params.get("engine_mount_point", None)
+ if engine_mount_point is not None:
+ parameters["mount_point"] = engine_mount_point
+ parameters["name"] = module.params.get("role_name")
+
+ module.connection_options.process_connection_options()
+ client_args = module.connection_options.get_hvac_connection_options()
+ client = module.helper.get_vault_client(**client_args)
+
+ try:
+ module.authenticator.validate()
+ module.authenticator.authenticate(client)
+ except (NotImplementedError, HashiVaultValueError) as e:
+ module.fail_json(msg=to_native(e), exception=traceback.format_exc())
+
+ try:
+ raw = client.secrets.database.read_role(**parameters)
+ except hvac.exceptions.Forbidden as e:
+ module.fail_json(
+ msg="Forbidden: Permission Denied to path ['%s']." % engine_mount_point
+ or "database",
+ exception=traceback.format_exc(),
+ )
+ except hvac.exceptions.InvalidPath as e:
+ module.fail_json(
+ msg="Invalid or missing path ['%s/roles/%s']."
+ % (engine_mount_point or "database", parameters["name"]),
+ exception=traceback.format_exc(),
+ )
+
+ data = raw["data"]
+
+ module.exit_json(data=data, raw=raw, changed=False)
+
+
+def main():
+ run_module()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/hashi_vault/plugins/modules/vault_database_roles_list.py b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_roles_list.py
new file mode 100644
index 000000000..a0dc7e472
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_roles_list.py
@@ -0,0 +1,173 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# (c) 2024, Martin Chmielewski (@M4rt1nCh)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+DOCUMENTATION = r"""
+module: vault_database_roles_list
+version_added: 6.2.0
+author:
+ - Martin Chmielewski (@M4rt1nCh)
+short_description: Returns a list of available (dynamic) roles
+requirements:
+ - C(hvac) (L(Python library,https://hvac.readthedocs.io/en/stable/overview.html))
+ - For detailed requirements, see R(the collection requirements page,ansible_collections.community.hashi_vault.docsite.user_guide.requirements).
+description:
+ - Returns a list of available (dynamic) roles.
+notes:
+ - This API returns a member named C(keys).
+ - In Ansible, accessing RV(data.keys) or RV(raw.data.keys) will not work because the dict object contains a method named C(keys).
+ - Instead, use RV(roles) to access the list of roles, or use the syntax C(data["keys"]) or C(raw.data["keys"]) to access the list via dict member.
+extends_documentation_fragment:
+ - community.hashi_vault.attributes
+ - community.hashi_vault.attributes.action_group
+ - community.hashi_vault.attributes.check_mode_read_only
+ - community.hashi_vault.connection
+ - community.hashi_vault.auth
+ - community.hashi_vault.engine_mount
+"""
+
+EXAMPLES = r"""
+- name: List all roles with the default mount point
+ community.hashi_vault.vault_database_roles_list:
+ url: https://vault:8201
+ auth_method: userpass
+ username: '{{ user }}'
+ password: '{{ passwd }}'
+ register: result
+
+- name: Display the result of the operation
+ ansible.builtin.debug:
+ msg: "{{ result }}"
+
+- name: List all roles with a custom mount point
+ community.hashi_vault.vault_database_roles_list:
+ url: https://vault:8201
+ auth_method: userpass
+ username: '{{ user }}'
+ password: '{{ passwd }}'
+ engine_mount_point: db1
+ register: result
+
+- name: Display the result of the operation
+ ansible.builtin.debug:
+ msg: "{{ result }}"
+"""
+
+RETURN = r"""
+data:
+ description: The C(data) field of raw result. This can also be accessed via RV(raw.data).
+ returned: success
+ type: dict
+ contains: &data_contains
+ keys:
+ description: The list of dynamic role names.
+ returned: success
+ type: list
+ elements: str
+ sample: &sample_roles ["dyn_role1", "dyn_role2", "dyn_role3"]
+ sample:
+ keys: *sample_roles
+roles:
+ description: The list of dynamic roles or en empty list. This can also be accessed via RV(data.keys) or RV(raw.data.keys).
+ returned: success
+ type: list
+ elements: str
+ sample: *sample_roles
+raw:
+ description: The raw result of the operation.
+ returned: success
+ type: dict
+ contains:
+ data:
+ description: The data field of the API response.
+ returned: success
+ type: dict
+ contains: *data_contains
+ sample:
+ auth: null
+ data:
+ keys: *sample_roles
+ username: "SomeUser"
+ lease_duration": 0
+ lease_id: ""
+ renewable: false
+ request_id: "123456"
+ warnings: null
+ wrap_info: null
+"""
+
+import traceback
+
+from ansible.module_utils._text import to_native
+from ansible.module_utils.basic import missing_required_lib
+
+from ..module_utils._hashi_vault_module import HashiVaultModule
+from ..module_utils._hashi_vault_common import HashiVaultValueError
+
+try:
+ import hvac
+except ImportError:
+ HAS_HVAC = False
+ HVAC_IMPORT_ERROR = traceback.format_exc()
+else:
+ HVAC_IMPORT_ERROR = None
+ HAS_HVAC = True
+
+
+def run_module():
+ argspec = HashiVaultModule.generate_argspec(
+ engine_mount_point=dict(type="str", required=False),
+ )
+
+ module = HashiVaultModule(argument_spec=argspec, supports_check_mode=True)
+
+ if not HAS_HVAC:
+ module.fail_json(msg=missing_required_lib("hvac"), exception=HVAC_IMPORT_ERROR)
+ parameters = {}
+ engine_mount_point = module.params.get("engine_mount_point", None)
+ if engine_mount_point is not None:
+ parameters["mount_point"] = engine_mount_point
+
+ module.connection_options.process_connection_options()
+ client_args = module.connection_options.get_hvac_connection_options()
+ client = module.helper.get_vault_client(**client_args)
+
+ try:
+ module.authenticator.validate()
+ module.authenticator.authenticate(client)
+ except (NotImplementedError, HashiVaultValueError) as e:
+ module.fail_json(msg=to_native(e), exception=traceback.format_exc())
+
+ try:
+ raw = client.secrets.database.list_roles(**parameters)
+ except hvac.exceptions.Forbidden as e:
+ module.fail_json(
+ msg="Forbidden: Permission Denied to path ['%s']." % engine_mount_point
+ or "database",
+ exception=traceback.format_exc(),
+ )
+ except hvac.exceptions.InvalidPath as e:
+ module.fail_json(
+ msg="Invalid or missing path ['%s/roles']."
+ % (engine_mount_point or "database"),
+ exception=traceback.format_exc(),
+ )
+
+ data = raw.get("data", {"keys": []})
+ roles = data["keys"]
+
+ module.exit_json(data=data, roles=roles, raw=raw, changed=False)
+
+
+def main():
+ run_module()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/hashi_vault/plugins/modules/vault_database_rotate_root_credentials.py b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_rotate_root_credentials.py
new file mode 100644
index 000000000..f5b58de1e
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_rotate_root_credentials.py
@@ -0,0 +1,150 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# (c) 2024, Martin Chmielewski (@M4rt1nCh)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+DOCUMENTATION = r"""
+module: vault_database_rotate_root_credentials
+version_added: 6.2.0
+author:
+ - Martin Chmielewski (@M4rt1nCh)
+short_description: Rotates the root credentials stored for the database connection. This user must have permissions to update its own password.
+requirements:
+ - C(hvac) (L(Python library,https://hvac.readthedocs.io/en/stable/overview.html)) >= 2.0.0
+ - For detailed requirements, see R(the collection requirements page,ansible_collections.community.hashi_vault.docsite.user_guide.requirements).
+description:
+ - Trigger L(root credential rotation,https://hvac.readthedocs.io/en/stable/usage/secrets_engines/database.html#rotate-root-credentials)
+ of a Database Connection identified by its O(connection_name).
+notes:
+ - This module always reports C(changed) status because it cannot guarantee idempotence.
+ - Use C(changed_when) to control that in cases where the operation is known to not change state.
+attributes:
+ check_mode:
+ support: partial
+ details:
+ - In check mode, a sample response will be returned, but the credential rotation will not be performed in Hashicorp Vault.
+extends_documentation_fragment:
+ - community.hashi_vault.attributes
+ - community.hashi_vault.attributes.action_group
+ - community.hashi_vault.connection
+ - community.hashi_vault.auth
+ - community.hashi_vault.engine_mount
+options:
+ connection_name:
+ description: The connection name where the root credential rotation should be triggered.
+ type: str
+ required: True
+"""
+
+EXAMPLES = r"""
+- name: Trigger root credentiaL rotation with the default mount point
+ community.hashi_vault.vault_database_rotate_root_credentials:
+ url: https://vault:8201
+ auth_method: userpass
+ username: '{{ user }}'
+ password: '{{ passwd }}'
+ connection_name: SomeName
+ register: result
+
+- name: Display the result of the operation
+ ansible.builtin.debug:
+ msg: "{{ result }}"
+
+- name: Trigger root credential rotation with the default mount point
+ community.hashi_vault.vault_database_rotate_root_credentials:
+ url: https://vault:8201
+ auth_method: userpass
+ username: '{{ user }}'
+ password: '{{ passwd }}'
+ engine_mount_point: db1
+ connection_name: SomeName
+ register: result
+
+- name: Display the result of the operation
+ ansible.builtin.debug:
+ msg: "{{ result }}"
+"""
+
+RETURN = r""""""
+
+import traceback
+
+from ansible.module_utils._text import to_native
+from ansible.module_utils.basic import missing_required_lib
+
+from ..module_utils._hashi_vault_module import HashiVaultModule
+from ..module_utils._hashi_vault_common import HashiVaultValueError
+
+try:
+ import hvac
+except ImportError:
+ HAS_HVAC = False
+ HVAC_IMPORT_ERROR = traceback.format_exc()
+else:
+ HVAC_IMPORT_ERROR = None
+ HAS_HVAC = True
+
+
+def run_module():
+ argspec = HashiVaultModule.generate_argspec(
+ engine_mount_point=dict(type="str", required=False),
+ connection_name=dict(type="str", required=True),
+ )
+
+ module = HashiVaultModule(argument_spec=argspec, supports_check_mode=True)
+
+ if not HAS_HVAC:
+ module.fail_json(msg=missing_required_lib("hvac"), exception=HVAC_IMPORT_ERROR)
+
+ if module.check_mode is True:
+ module.exit_json(changed=True)
+
+ parameters = {}
+ engine_mount_point = module.params.get("engine_mount_point", None)
+ if engine_mount_point is not None:
+ parameters["mount_point"] = engine_mount_point
+ parameters["name"] = module.params.get("connection_name")
+
+ module.connection_options.process_connection_options()
+ client_args = module.connection_options.get_hvac_connection_options()
+ client = module.helper.get_vault_client(**client_args)
+
+ try:
+ module.authenticator.validate()
+ module.authenticator.authenticate(client)
+ except (NotImplementedError, HashiVaultValueError) as e:
+ module.fail_json(msg=to_native(e), exception=traceback.format_exc())
+
+ try:
+ client.secrets.database.rotate_root_credentials(**parameters)
+ except AttributeError as e:
+ module.fail_json(
+ msg="hvac>=2.0.0 is required", exception=traceback.format_exc()
+ )
+ except hvac.exceptions.Forbidden as e:
+ module.fail_json(
+ msg="Forbidden: Permission Denied to path ['%s']." % engine_mount_point
+ or "database",
+ exception=traceback.format_exc(),
+ )
+ except hvac.exceptions.InvalidPath as e:
+ module.fail_json(
+ msg="Invalid or missing path ['%s/rotate-root/%s']"
+ % (engine_mount_point or "database", parameters["name"]),
+ exception=traceback.format_exc(),
+ )
+ else:
+ module.exit_json(changed=True)
+
+
+def main():
+ run_module()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/hashi_vault/plugins/modules/vault_database_static_role_create.py b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_static_role_create.py
new file mode 100644
index 000000000..5dd57ccae
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_static_role_create.py
@@ -0,0 +1,188 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# (c) 2024, Martin Chmielewski (@M4rt1nCh)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+DOCUMENTATION = r"""
+module: vault_database_static_role_create
+version_added: 6.2.0
+author:
+ - Martin Chmielewski (@M4rt1nCh)
+short_description: Create or update a static role
+requirements:
+ - C(hvac) (L(Python library,https://hvac.readthedocs.io/en/stable/overview.html))
+ - For detailed requirements, see R(the collection requirements page,ansible_collections.community.hashi_vault.docsite.user_guide.requirements).
+description:
+ - L(Creates a new or updates an existing static role,https://hvac.readthedocs.io/en/stable/usage/secrets_engines/database.html#create-static-role).
+notes:
+ - This module always reports C(changed) status because it cannot guarantee idempotence.
+ - Use C(changed_when) to control that in cases where the operation is known to not change state.
+attributes:
+ check_mode:
+ support: partial
+ details:
+ - In check mode, a sample response will be returned, but the role creation will not be performed in Hashicorp Vault.
+extends_documentation_fragment:
+ - community.hashi_vault.attributes
+ - community.hashi_vault.attributes.action_group
+ - community.hashi_vault.connection
+ - community.hashi_vault.auth
+ - community.hashi_vault.engine_mount
+options:
+ connection_name:
+ description: The connection name under which the role should be created.
+ type: str
+ required: True
+ role_name:
+ description: The name of the role that should be created.
+ type: str
+ required: True
+ db_username:
+ description: The database username - Note that the user must exist in the target database!
+ type: str
+ required: True
+ rotation_statements:
+ description: SQL statements to rotate the password for the given O(db_username)
+ type: list
+ required: True
+ elements: str
+ rotation_period:
+ description: Password rotation period in seconds (defaults to 24hs)
+ type: int
+ required: False
+ default: 86400
+"""
+
+EXAMPLES = r"""
+- name: Generate rotation statement
+ ansible.builtin.set_fact:
+ rotation_statements = ["ALTER USER \"{{name}}\" WITH PASSWORD '{{password}}';"]
+
+- name: Create / update Static Role with the default mount point
+ community.hashi_vault.vault_database_static_role_create:
+ url: https://vault:8201
+ auth_method: userpass
+ username: '{{ user }}'
+ password: '{{ passwd }}'
+ connection_name: SomeConnection
+ role_name: SomeRole
+ db_username: '{{ db_username}}'
+ rotation_statements: '{{ rotation_statements }}'
+ register: response
+
+- name: Display the result of the operation
+ ansible.builtin.debug:
+ msg: "{{ result }}"
+
+- name: Create / update Static Role with a custom mount point
+ community.hashi_vault.vault_database_static_role_create:
+ url: https://vault:8201
+ auth_method: userpass
+ username: '{{ user }}'
+ password: '{{ passwd }}'
+ engine_mount_point: db1
+ connection_name: SomeConnection
+ role_name: SomeRole
+ db_username: '{{ db_username}}'
+ rotation_statements: '{{ rotation_statements }}'
+ register: response
+
+- name: Display the result of the operation
+ ansible.builtin.debug:
+ msg: "{{ result }}"
+"""
+
+RETURN = r""""""
+
+import traceback
+
+from ansible.module_utils._text import to_native
+from ansible.module_utils.basic import missing_required_lib
+
+from ..module_utils._hashi_vault_module import HashiVaultModule
+from ..module_utils._hashi_vault_common import HashiVaultValueError
+
+try:
+ import hvac
+except ImportError:
+ HAS_HVAC = False
+ HVAC_IMPORT_ERROR = traceback.format_exc()
+else:
+ HVAC_IMPORT_ERROR = None
+ HAS_HVAC = True
+
+
+def run_module():
+ argspec = HashiVaultModule.generate_argspec(
+ engine_mount_point=dict(type="str", required=False),
+ connection_name=dict(type="str", required=True),
+ role_name=dict(type="str", required=True),
+ db_username=dict(type="str", required=True),
+ rotation_statements=dict(type="list", required=True, elements="str"),
+ rotation_period=dict(type="int", required=False, default=86400),
+ )
+
+ module = HashiVaultModule(argument_spec=argspec, supports_check_mode=True)
+
+ if not HAS_HVAC:
+ module.fail_json(msg=missing_required_lib("hvac"), exception=HVAC_IMPORT_ERROR)
+
+ if module.check_mode is True:
+ module.exit_json(changed=True)
+
+ parameters = {}
+ engine_mount_point = module.params.get("engine_mount_point", None)
+ if engine_mount_point is not None:
+ parameters["mount_point"] = engine_mount_point
+ parameters["db_name"] = module.params.get("connection_name")
+ parameters["name"] = module.params.get("role_name")
+ parameters["username"] = module.params.get("db_username")
+ parameters["rotation_statements"] = module.params.get("rotation_statements")
+ rotation_period = module.params.get("rotation_period", None)
+ parameters["rotation_period"] = rotation_period
+
+ module.connection_options.process_connection_options()
+ client_args = module.connection_options.get_hvac_connection_options()
+ client = module.helper.get_vault_client(**client_args)
+
+ try:
+ module.authenticator.validate()
+ module.authenticator.authenticate(client)
+ except (NotImplementedError, HashiVaultValueError) as e:
+ module.fail_json(msg=to_native(e), exception=traceback.format_exc())
+
+ try:
+ client.secrets.database.create_static_role(**parameters)
+ except hvac.exceptions.Forbidden as e:
+ module.fail_json(
+ msg="Forbidden: Permission Denied to path ['%s']." % engine_mount_point
+ or "database",
+ exception=traceback.format_exc(),
+ )
+ except hvac.exceptions.InvalidPath as e:
+ module.fail_json(
+ msg="Invalid or missing path ['%s/static-roles/%s']."
+ % (engine_mount_point or "database", parameters["name"]),
+ exception=traceback.format_exc(),
+ )
+ except hvac.exceptions.InvalidRequest as e:
+ module.fail_json(
+ msg="Cannot update static role ['%s/static-roles/%s']. Please verify that the user exists on the database."
+ % (engine_mount_point or "database", parameters["name"]),
+ exception=traceback.format_exc(),
+ )
+ else:
+ module.exit_json(changed=True)
+
+
+def main():
+ run_module()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/hashi_vault/plugins/modules/vault_database_static_role_get_credentials.py b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_static_role_get_credentials.py
new file mode 100644
index 000000000..a8a5cc9cc
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_static_role_get_credentials.py
@@ -0,0 +1,167 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# (c) 2024, Martin Chmielewski (@M4rt1nCh)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+DOCUMENTATION = r"""
+module: vault_database_static_role_get_credentials
+version_added: 6.2.0
+author:
+ - Martin Chmielewski (@M4rt1nCh)
+short_description: Returns the current credentials based on the named static role
+requirements:
+ - C(hvac) (L(Python library,https://hvac.readthedocs.io/en/stable/overview.html))
+ - For detailed requirements, see R(the collection requirements page,ansible_collections.community.hashi_vault.docsite.user_guide.requirements).
+description:
+ - Returns the
+ L(current credentials based of the named static role,https://hvac.readthedocs.io/en/stable/usage/secrets_engines/database.html#get-static-credentials),
+ identified by its O(role_name).
+notes:
+ - This module always reports C(changed) as False as it is a read operation that doesn't modify data.
+ - Use C(changed_when) to control that in cases where the operation is known to not change state.
+extends_documentation_fragment:
+ - community.hashi_vault.attributes
+ - community.hashi_vault.attributes.action_group
+ - community.hashi_vault.attributes.check_mode_read_only
+ - community.hashi_vault.connection
+ - community.hashi_vault.auth
+ - community.hashi_vault.engine_mount
+options:
+ role_name:
+ description: The role name from which the credentials should be retrieved.
+ type: str
+ required: True
+"""
+
+EXAMPLES = r"""
+- name: Returns the current credentials based on the named static role with the default mount point
+ community.hashi_vault.vault_database_static_role_read:
+ url: https://vault:8201
+ auth_method: userpass
+ username: '{{ user }}'
+ password: '{{ passwd }}'
+ role_name: SomeRole
+ register: result
+
+- name: Display the result of the operation
+ ansible.builtin.debug:
+ msg: "{{ result }}"
+
+- name: Returns the current credentials based on the named static role with a custom mount point
+ community.hashi_vault.vault_database_static_role_read:
+ url: https://vault:8201
+ auth_method: userpass
+ username: '{{ user }}'
+ password: '{{ passwd }}'
+ engine_mount_point: db1
+ role_name: SomeRole
+ register: result
+
+- name: Display the result of the operation
+ ansible.builtin.debug:
+ msg: "{{ result }}"
+"""
+
+RETURN = r"""
+data: &data
+ description: The C(data) field of raw result. This can also be accessed via RV(raw.data).
+ returned: success
+ type: dict
+ sample: &data_sample
+ last_vault_rotation": "2024-01-01T09:00:00+01:00"
+ password": "Th3_$3cr3t_P@ss!"
+ rotation_period": 86400
+ ttl": 123456
+ username: "SomeUser"
+raw:
+ description: The raw result of the operation.
+ returned: success
+ type: dict
+ contains:
+ data: *data
+ sample:
+ auth: null,
+ data: *data_sample
+ lease_duration: 0
+ lease_id: ""
+ renewable: false
+ request_id: "123456"
+ warnings: null,
+ wrap_info: null
+"""
+
+import traceback
+
+from ansible.module_utils._text import to_native
+from ansible.module_utils.basic import missing_required_lib
+
+from ..module_utils._hashi_vault_module import HashiVaultModule
+from ..module_utils._hashi_vault_common import HashiVaultValueError
+
+try:
+ import hvac
+except ImportError:
+ HAS_HVAC = False
+ HVAC_IMPORT_ERROR = traceback.format_exc()
+else:
+ HVAC_IMPORT_ERROR = None
+ HAS_HVAC = True
+
+
+def run_module():
+ argspec = HashiVaultModule.generate_argspec(
+ engine_mount_point=dict(type="str", required=False),
+ role_name=dict(type="str", required=True),
+ )
+
+ module = HashiVaultModule(argument_spec=argspec, supports_check_mode=True)
+
+ if not HAS_HVAC:
+ module.fail_json(msg=missing_required_lib("hvac"), exception=HVAC_IMPORT_ERROR)
+
+ parameters = {}
+ engine_mount_point = module.params.get("engine_mount_point", None)
+ if engine_mount_point is not None:
+ parameters["mount_point"] = engine_mount_point
+ parameters["name"] = module.params.get("role_name")
+
+ module.connection_options.process_connection_options()
+ client_args = module.connection_options.get_hvac_connection_options()
+ client = module.helper.get_vault_client(**client_args)
+
+ try:
+ module.authenticator.validate()
+ module.authenticator.authenticate(client)
+ except (NotImplementedError, HashiVaultValueError) as e:
+ module.fail_json(msg=to_native(e), exception=traceback.format_exc())
+
+ try:
+ raw = client.secrets.database.get_static_credentials(**parameters)
+ except hvac.exceptions.Forbidden as e:
+ module.fail_json(
+ msg="Forbidden: Permission Denied to path ['%s']." % engine_mount_point,
+ exception=traceback.format_exc(),
+ )
+ except hvac.exceptions.InvalidPath as e:
+ module.fail_json(
+ msg="Invalid or missing path ['%s/static-creds/%s']"
+ % (engine_mount_point or "database", parameters["name"]),
+ exception=traceback.format_exc(),
+ )
+
+ data = raw["data"]
+
+ module.exit_json(data=data, raw=raw, changed=False)
+
+
+def main():
+ run_module()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/hashi_vault/plugins/modules/vault_database_static_role_read.py b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_static_role_read.py
new file mode 100644
index 000000000..f2ad972b6
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_static_role_read.py
@@ -0,0 +1,171 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# (c) 2024, Martin Chmielewski (@M4rt1nCh)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+DOCUMENTATION = r"""
+module: vault_database_static_role_read
+version_added: 6.2.0
+author:
+ - Martin Chmielewski (@M4rt1nCh)
+short_description: Queries a static role definition
+requirements:
+ - C(hvac) (L(Python library,https://hvac.readthedocs.io/en/stable/overview.html))
+ - For detailed requirements, see R(the collection requirements page,ansible_collections.community.hashi_vault.docsite.user_guide.requirements).
+description:
+ - L(Queries a static role definition,L(reads a static role,https://hvac.readthedocs.io/en/stable/usage/secrets_engines/database.html#read-static-role),
+ - identified by its O(role_name)
+notes:
+ - This module always reports C(changed) as False as it is a read operation that doesn't modify data.
+ - Use C(changed_when) to control that in cases where the operation is known to not change state.
+extends_documentation_fragment:
+ - community.hashi_vault.attributes
+ - community.hashi_vault.attributes.action_group
+ - community.hashi_vault.attributes.check_mode_read_only
+ - community.hashi_vault.connection
+ - community.hashi_vault.auth
+ - community.hashi_vault.engine_mount
+options:
+ role_name:
+ description: The role name to be read from Hashicorp Vault.
+ type: str
+ required: True
+"""
+
+EXAMPLES = r"""
+- name: Read Static Role with a default mount point
+ community.hashi_vault.vault_database_static_role_read:
+ url: https://vault:8201
+ auth_method: userpass
+ username: '{{ user }}'
+ password: '{{ passwd }}'
+ role_name: SomeRole
+ register: result
+
+- name: Display the result of the operation
+ ansible.builtin.debug:
+ msg: "{{ result }}"
+
+- name: Read Static Role with a custom moint point
+ community.hashi_vault.vault_database_static_role_read:
+ url: https://vault:8201
+ auth_method: userpass
+ username: '{{ user }}'
+ password: '{{ passwd }}'
+ engine_mount_point: db1
+ role_name: SomeRole
+ register: result
+
+- name: Display the result of the operation
+ ansible.builtin.debug:
+ msg: "{{ result }}"
+
+"""
+
+RETURN = r"""
+data: &data
+ description: The C(data) field of raw result. This can also be accessed via RV(raw.data).
+ returned: success
+ type: dict
+ sample: &data_sample
+ credential_type: "password"
+ db_name: "SomeConnection"
+ last_vault_rotation": "2024-01-01T09:00:00 +01:00"
+ rotation_period": 86400
+ rotation_statements": [
+ "ALTER USER \"{{name}}\" WITH PASSWORD '{{password}}';"
+ ]
+raw:
+ description: The raw result of the operation.
+ returned: success
+ type: dict
+ contains:
+ data: *data
+ sample:
+ auth: null
+ data: *data_sample
+ username: "SomeUser"
+ lease_duration": 0
+ lease_id: ""
+ renewable: false
+ request_id: "123456"
+ warnings: null
+ wrap_info: null
+"""
+
+import traceback
+
+from ansible.module_utils._text import to_native
+from ansible.module_utils.basic import missing_required_lib
+
+from ..module_utils._hashi_vault_module import HashiVaultModule
+from ..module_utils._hashi_vault_common import HashiVaultValueError
+
+try:
+ import hvac
+except ImportError:
+ HAS_HVAC = False
+ HVAC_IMPORT_ERROR = traceback.format_exc()
+else:
+ HVAC_IMPORT_ERROR = None
+ HAS_HVAC = True
+
+
+def run_module():
+ argspec = HashiVaultModule.generate_argspec(
+ engine_mount_point=dict(type="str", required=False),
+ role_name=dict(type="str", required=True),
+ )
+
+ module = HashiVaultModule(argument_spec=argspec, supports_check_mode=True)
+
+ if not HAS_HVAC:
+ module.fail_json(msg=missing_required_lib("hvac"), exception=HVAC_IMPORT_ERROR)
+
+ parameters = {}
+ engine_mount_point = module.params.get("engine_mount_point", None)
+ if engine_mount_point is not None:
+ parameters["mount_point"] = engine_mount_point
+ parameters["name"] = module.params.get("role_name")
+
+ module.connection_options.process_connection_options()
+ client_args = module.connection_options.get_hvac_connection_options()
+ client = module.helper.get_vault_client(**client_args)
+
+ try:
+ module.authenticator.validate()
+ module.authenticator.authenticate(client)
+ except (NotImplementedError, HashiVaultValueError) as e:
+ module.fail_json(msg=to_native(e), exception=traceback.format_exc())
+
+ try:
+ raw = client.secrets.database.read_static_role(**parameters)
+ except hvac.exceptions.Forbidden as e:
+ module.fail_json(
+ msg="Forbidden: Permission Denied to path ['%s']." % engine_mount_point
+ or "database",
+ exception=traceback.format_exc(),
+ )
+ except hvac.exceptions.InvalidPath as e:
+ module.fail_json(
+ msg="Invalid or missing path ['%s/static-roles/%s']."
+ % (engine_mount_point or "database", parameters["name"]),
+ exception=traceback.format_exc(),
+ )
+
+ data = raw["data"]
+
+ module.exit_json(data=data, raw=raw, changed=False)
+
+
+def main():
+ run_module()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/hashi_vault/plugins/modules/vault_database_static_role_rotate_credentials.py b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_static_role_rotate_credentials.py
new file mode 100644
index 000000000..660725b0b
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_static_role_rotate_credentials.py
@@ -0,0 +1,152 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# (c) 2024, Martin Chmielewski (@M4rt1nCh)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+DOCUMENTATION = r"""
+module: vault_database_static_role_rotate_credentials
+version_added: 6.2.0
+author:
+ - Martin Chmielewski (@M4rt1nCh)
+short_description: Trigger the credential rotation for a static role
+requirements:
+ - C(hvac) (L(Python library,https://hvac.readthedocs.io/en/stable/overview.html)) >= 2.0.0
+ - For detailed requirements, see R(the collection requirements page,ansible_collections.community.hashi_vault.docsite.user_guide.requirements).
+description:
+ - This endpoint is used to
+ - L(rotate the Static Role credentials,https://hvac.readthedocs.io/en/stable/usage/secrets_engines/database.html#rotate-static-role-credentials)
+ - stored for a given role name. While Static Roles are rotated automatically by Vault at configured rotation periods,
+ - users can use this endpoint to manually trigger a rotation to change the stored password and reset the TTL of the Static Role's password.
+notes:
+ - This module always reports C(changed) status because it cannot guarantee idempotence.
+ - Use C(changed_when) to control that in cases where the operation is known to not change state.
+attributes:
+ check_mode:
+ support: partial
+ details:
+ - In check mode, a sample response will be returned, but the credential rotation will not be performed in Hashicorp Vault.
+extends_documentation_fragment:
+ - community.hashi_vault.attributes
+ - community.hashi_vault.attributes.action_group
+ - community.hashi_vault.connection
+ - community.hashi_vault.auth
+ - community.hashi_vault.engine_mount
+options:
+ role_name:
+ description: The name of the role to rotate credentials for.
+ type: str
+ required: True
+"""
+
+EXAMPLES = r"""
+- name: Rotate credentials of a static role with the default mount point
+ community.hashi_vault.vault_database_static_role_rotate_credentials:
+ url: https://vault:8201
+ auth_method: userpass
+ username: '{{ user }}'
+ password: '{{ passwd }}'
+ role_name: SomeRole
+ register: result
+
+- name: Display the result of the operation
+ ansible.builtin.debug:
+ msg: "{{ result }}"
+
+- name: Rotate credentials of a static role with a custom mount point
+ community.hashi_vault.vault_database_static_role_rotate_credentials:
+ url: https://vault:8201
+ auth_method: userpass
+ username: '{{ user }}'
+ password: '{{ passwd }}'
+ engine_mount_point: db1
+ role_name: SomeRole
+ register: result
+
+- name: Display the result of the operation
+ ansible.builtin.debug:
+ msg: "{{ result }}"
+"""
+
+RETURN = r""""""
+
+import traceback
+
+from ansible.module_utils._text import to_native
+from ansible.module_utils.basic import missing_required_lib
+
+from ..module_utils._hashi_vault_module import HashiVaultModule
+from ..module_utils._hashi_vault_common import HashiVaultValueError
+
+try:
+ import hvac
+except ImportError:
+ HAS_HVAC = False
+ HVAC_IMPORT_ERROR = traceback.format_exc()
+else:
+ HVAC_IMPORT_ERROR = None
+ HAS_HVAC = True
+
+
+def run_module():
+ argspec = HashiVaultModule.generate_argspec(
+ engine_mount_point=dict(type="str", required=False),
+ role_name=dict(type="str", required=True),
+ )
+
+ module = HashiVaultModule(argument_spec=argspec, supports_check_mode=True)
+
+ if not HAS_HVAC:
+ module.fail_json(msg=missing_required_lib("hvac"), exception=HVAC_IMPORT_ERROR)
+
+ if module.check_mode is True:
+ module.exit_json(changed=True)
+
+ parameters = {}
+ engine_mount_point = module.params.get("engine_mount_point", None)
+ if engine_mount_point is not None:
+ parameters["mount_point"] = engine_mount_point
+ parameters["name"] = module.params.get("role_name")
+
+ module.connection_options.process_connection_options()
+ client_args = module.connection_options.get_hvac_connection_options()
+ client = module.helper.get_vault_client(**client_args)
+
+ try:
+ module.authenticator.validate()
+ module.authenticator.authenticate(client)
+ except (NotImplementedError, HashiVaultValueError) as e:
+ module.fail_json(msg=to_native(e), exception=traceback.format_exc())
+
+ try:
+ raw = client.secrets.database.rotate_static_role_credentials(**parameters)
+ except AttributeError as e:
+ module.fail_json(
+ msg="hvac>=2.0.0 is required", exception=traceback.format_exc()
+ )
+ except hvac.exceptions.Forbidden as e:
+ module.fail_json(
+ msg="Forbidden: Permission Denied to path ['%s']." % engine_mount_point
+ or "database",
+ exception=traceback.format_exc(),
+ )
+ except hvac.exceptions.InvalidPath as e:
+ module.fail_json(
+ msg="Invalid or missing path ['%s/rotate-role/%s']."
+ % (engine_mount_point or "database", parameters["name"]),
+ exception=traceback.format_exc(),
+ )
+ else:
+ module.exit_json(changed=True)
+
+
+def main():
+ run_module()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/hashi_vault/plugins/modules/vault_database_static_roles_list.py b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_static_roles_list.py
new file mode 100644
index 000000000..36a35337e
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/plugins/modules/vault_database_static_roles_list.py
@@ -0,0 +1,174 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# (c) 2024, Martin Chmielewski (@M4rt1nCh)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+DOCUMENTATION = r"""
+module: vault_database_static_roles_list
+version_added: 6.2.0
+author:
+ - Martin Chmielewski (@M4rt1nCh)
+short_description: Returns a list of available static roles
+requirements:
+ - C(hvac) (L(Python library,https://hvac.readthedocs.io/en/stable/overview.html))
+ - For detailed requirements, see R(the collection requirements page,ansible_collections.community.hashi_vault.docsite.user_guide.requirements).
+description:
+ - L(Returns a list of available static roles,https://hvac.readthedocs.io/en/stable/usage/secrets_engines/database.html#list-static-roles).
+extends_documentation_fragment:
+ - community.hashi_vault.attributes
+ - community.hashi_vault.attributes.action_group
+ - community.hashi_vault.attributes.check_mode_read_only
+ - community.hashi_vault.connection
+ - community.hashi_vault.auth
+ - community.hashi_vault.engine_mount
+notes:
+ - This API returns a member named C(keys).
+ - In Ansible, accessing RV(data.keys) or RV(raw.data.keys) will not work because the dict object contains a method named C(keys).
+ - Instead, use RV(roles) to access the list of roles, or use the syntax C(data["keys"]) or C(raw.data["keys"]) to access the list via dict member.
+"""
+
+EXAMPLES = r"""
+- name: List static roles with the default mount point
+ community.hashi_vault.vault_database_static_roles_list:
+ url: https://vault:8201
+ auth_method: userpass
+ username: '{{ user }}'
+ password: '{{ passwd }}'
+ register: response
+
+- name: Display the result of the operation
+ ansible.builtin.debug:
+ msg: "{{ response }}"
+
+- name: List static roles with a custom mount point
+ community.hashi_vault.vault_database_static_roles_list:
+ url: https://vault:8201
+ auth_method: userpass
+ username: '{{ user }}'
+ password: '{{ passwd }}'
+ engine_mount_point: db1
+ register: response
+
+- name: Display the result of the operation
+ ansible.builtin.debug:
+ msg: "{{ response }}"
+"""
+
+RETURN = r"""
+data:
+ description: The C(data) field of raw result. This can also be accessed via RV(raw.data).
+ returned: success
+ type: dict
+ contains: &data_contains
+ keys:
+ description: The list of role names.
+ returned: success
+ type: list
+ elements: str
+ sample: &sample_roles ["role1", "role2", "role3"]
+ sample:
+ keys: *sample_roles
+roles:
+ description: The list of roles or en empty list. This can also be accessed via RV(data.keys) or RV(raw.data.keys).
+ returned: success
+ type: list
+ elements: str
+ sample: *sample_roles
+raw:
+ description: The raw result of the operation.
+ returned: success
+ type: dict
+ contains:
+ data:
+ description: The data field of the API response.
+ returned: success
+ type: dict
+ contains: *data_contains
+ sample:
+ auth: null
+ data:
+ keys: *sample_roles
+ username: "SomeUser"
+ lease_duration": 0
+ lease_id: ""
+ renewable: false
+ request_id: "123456"
+ warnings: null
+ wrap_info: null
+"""
+
+import traceback
+
+from ansible.module_utils._text import to_native
+from ansible.module_utils.basic import missing_required_lib
+
+from ..module_utils._hashi_vault_module import HashiVaultModule
+from ..module_utils._hashi_vault_common import HashiVaultValueError
+
+try:
+ import hvac
+except ImportError:
+ HAS_HVAC = False
+ HVAC_IMPORT_ERROR = traceback.format_exc()
+else:
+ HVAC_IMPORT_ERROR = None
+ HAS_HVAC = True
+
+
+def run_module():
+ argspec = HashiVaultModule.generate_argspec(
+ engine_mount_point=dict(type="str", required=False),
+ )
+
+ module = HashiVaultModule(argument_spec=argspec, supports_check_mode=True)
+
+ if not HAS_HVAC:
+ module.fail_json(msg=missing_required_lib("hvac"), exception=HVAC_IMPORT_ERROR)
+
+ parameters = {}
+ engine_mount_point = module.params.get("engine_mount_point", None)
+ if engine_mount_point is not None:
+ parameters["mount_point"] = engine_mount_point
+
+ module.connection_options.process_connection_options()
+ client_args = module.connection_options.get_hvac_connection_options()
+ client = module.helper.get_vault_client(**client_args)
+
+ try:
+ module.authenticator.validate()
+ module.authenticator.authenticate(client)
+ except (NotImplementedError, HashiVaultValueError) as e:
+ module.fail_json(msg=to_native(e), exception=traceback.format_exc())
+
+ try:
+ raw = client.secrets.database.list_static_roles(**parameters)
+ except hvac.exceptions.Forbidden as e:
+ module.fail_json(
+ msg="Forbidden: Permission Denied to path ['%s']." % engine_mount_point
+ or "database",
+ exception=traceback.format_exc(),
+ )
+ except hvac.exceptions.InvalidPath as e:
+ module.fail_json(
+ msg="Invalid or missing path ['%s/static-roles']."
+ % (engine_mount_point or "database"),
+ exception=traceback.format_exc(),
+ )
+
+ data = raw.get("data", {"keys": []})
+ roles = data["keys"]
+
+ module.exit_json(data=data, roles=roles, raw=raw, changed=False)
+
+
+def main():
+ run_module()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/hashi_vault/plugins/modules/vault_write.py b/ansible_collections/community/hashi_vault/plugins/modules/vault_write.py
index 35c7fcb60..76cf4f8e9 100644
--- a/ansible_collections/community/hashi_vault/plugins/modules/vault_write.py
+++ b/ansible_collections/community/hashi_vault/plugins/modules/vault_write.py
@@ -46,7 +46,9 @@ DOCUMENTATION = """
type: str
required: True
data:
- description: A dictionary to be serialized to JSON and then sent as the request body.
+ description:
+ - A dictionary to be serialized to JSON and then sent as the request body.
+ - If the dictionary contains keys named C(path) or C(wrap_ttl), the call will fail with C(hvac<1.2).
type: dict
required: false
default: {}
@@ -108,8 +110,8 @@ import traceback
from ansible.module_utils._text import to_native
from ansible.module_utils.basic import missing_required_lib
-from ansible_collections.community.hashi_vault.plugins.module_utils._hashi_vault_module import HashiVaultModule
-from ansible_collections.community.hashi_vault.plugins.module_utils._hashi_vault_common import HashiVaultValueError
+from ..module_utils._hashi_vault_module import HashiVaultModule
+from ..module_utils._hashi_vault_common import HashiVaultValueError
try:
import hvac
@@ -157,7 +159,16 @@ def run_module():
if module.check_mode:
response = {}
else:
- response = client.write(path=path, wrap_ttl=wrap_ttl, **data)
+ try:
+ # TODO: write_data will eventually turn back into write
+ # see: https://github.com/hvac/hvac/issues/1034
+ response = client.write_data(path=path, wrap_ttl=wrap_ttl, data=data)
+ except AttributeError:
+ # https://github.com/ansible-collections/community.hashi_vault/issues/389
+ if "path" in data or "wrap_ttl" in data:
+ module.fail_json("To use 'path' or 'wrap_ttl' as data keys, use hvac >= 1.2")
+ else:
+ response = client.write(path=path, wrap_ttl=wrap_ttl, **data)
except hvac.exceptions.Forbidden:
module.fail_json(msg="Forbidden: Permission Denied to path '%s'." % path, exception=traceback.format_exc())
except hvac.exceptions.InvalidPath:
diff --git a/ansible_collections/community/hashi_vault/plugins/plugin_utils/_hashi_vault_lookup_base.py b/ansible_collections/community/hashi_vault/plugins/plugin_utils/_hashi_vault_lookup_base.py
index 7a878cbb4..acc7a1b08 100644
--- a/ansible_collections/community/hashi_vault/plugins/plugin_utils/_hashi_vault_lookup_base.py
+++ b/ansible_collections/community/hashi_vault/plugins/plugin_utils/_hashi_vault_lookup_base.py
@@ -12,7 +12,7 @@
from __future__ import absolute_import, division, print_function
__metaclass__ = type
-from ansible.errors import AnsibleError
+from ansible.errors import AnsibleError, AnsibleOptionsError
from ansible.plugins.lookup import LookupBase
from ansible.utils.display import Display
@@ -43,11 +43,8 @@ class HashiVaultLookupBase(HashiVaultPlugin, LookupBase):
raise AnsibleError("%s lookup plugin needs key=value pairs, but received %s" % (plugin_name, term))
if key in param_dict:
- removed_in = '5.0.0'
msg = "Duplicate key '%s' in the term string '%s'." % (key, term)
- display.deprecated(msg + "\nIn version %s of the collection, this will raise an exception." % (removed_in, ), removed_in)
- # TODO: v5.0.0: remove deprecation message, uncomment: https://github.com/ansible-collections/community.hashi_vault/pull/350
- # raise AnsibleOptionsError(msg)
+ raise AnsibleOptionsError(msg)
param_dict[key] = value
diff --git a/ansible_collections/community/hashi_vault/tests/utils/constraints.txt b/ansible_collections/community/hashi_vault/tests/integration/constraints.txt
index f0efeb2e8..f347921c3 100644
--- a/ansible_collections/community/hashi_vault/tests/utils/constraints.txt
+++ b/ansible_collections/community/hashi_vault/tests/integration/constraints.txt
@@ -52,11 +52,13 @@ typed-ast == 1.4.0 # 1.4.0 is required to compile on Python 3.8
wrapt == 1.11.1
# hvac
-hvac >= 0.10.6, != 0.10.12, != 0.10.13, < 1.0.0 ; python_version == '2.7' # bugs in 0.10.12 and 0.10.13 prevent it from working in Python 2
-hvac >= 0.10.6, < 1.0.0 ; python_version == '3.5' # py3.5 support will be dropped in 1.0.0
-hvac >= 0.10.6 ; python_version >= '3.6'
+hvac >= 1.2.1 ; python_version >= '3.6'
# urllib3
# these should be satisfied naturally by the requests versions required by hvac anyway
urllib3 >= 1.15 ; python_version >= '3.6' # we need raise_on_status for retry support to raise the correct exceptions https://github.com/urllib3/urllib3/blob/main/CHANGES.rst#115-2016-04-06
-urllib3 >= 1.15, <2.0.0 ; python_version < '3.6' # https://urllib3.readthedocs.io/en/latest/v2-roadmap.html#optimized-for-python-3-6
+
+# requests
+# https://github.com/psf/requests/pull/6356
+requests >= 2.29 ; python_version >= '3.7'
+requests < 2.28 ; python_version < '3.7'
diff --git a/ansible_collections/community/hashi_vault/tests/integration/requirements.txt b/ansible_collections/community/hashi_vault/tests/integration/requirements.txt
index 033733f7c..c3a5354f0 100644
--- a/ansible_collections/community/hashi_vault/tests/integration/requirements.txt
+++ b/ansible_collections/community/hashi_vault/tests/integration/requirements.txt
@@ -1,16 +1,4 @@
-# the collection supports python 3.6 and higher, however the constraints for
-# earlier python versions are still needed for Ansible < 2.12 which doesn't
-# support tests/config.yml, so that unit tests (which will be skipped) won't
-# choke on installing requirements.
-
-hvac >= 0.10.6, != 0.10.12, != 0.10.13, < 1.0.0 ; python_version == '2.7' # bugs in 0.10.12 and 0.10.13 prevent it from working in Python 2
-hvac >= 0.10.6, < 1.0.0 ; python_version == '3.5' # py3.5 support will be dropped in 1.0.0
-hvac >= 0.10.6 ; python_version >= '3.6'
-
-# these should be satisfied naturally by the requests versions required by hvac anyway
-urllib3 >= 1.15 ; python_version >= '3.6' # we need raise_on_status for retry support to raise the correct exceptions https://github.com/urllib3/urllib3/blob/main/CHANGES.rst#115-2016-04-06
-urllib3 >= 1.15, <2.0.0 ; python_version < '3.6' # https://urllib3.readthedocs.io/en/latest/v2-roadmap.html#optimized-for-python-3-6
-
-# azure-identity 1.7.0 depends on cryptography 2.5 which drops python 2.6 support
-azure-identity < 1.7.0; python_version < '2.7'
-azure-identity; python_version >= '2.7'
+hvac
+urllib3
+azure-identity
+psycopg[binary,pool]
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_approle/tasks/approle_test_controller.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_approle/tasks/approle_test_controller.yml
index 8cf331b1d..48b5117f7 100644
--- a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_approle/tasks/approle_test_controller.yml
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_approle/tasks/approle_test_controller.yml
@@ -52,4 +52,4 @@
fail_msg: "An invalid secret ID somehow did not cause a failure."
that:
- (response is failed) == use_secret_id
- - not use_secret_id or response.msg is search('invalid secret id')
+ - not use_secret_id or response.msg is search('(?i)invalid (?:role or )?secret id')
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_approle/tasks/approle_test_target.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_approle/tasks/approle_test_target.yml
index 1f5796957..387195af9 100644
--- a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_approle/tasks/approle_test_target.yml
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_approle/tasks/approle_test_target.yml
@@ -40,10 +40,10 @@
register: response
vault_test_auth:
secret_id: fake
- want_exception: yes
+ want_exception: true
- assert:
fail_msg: "An invalid secret ID somehow did not cause a failure."
that:
- (response.inner is failed) == use_secret_id
- - not use_secret_id or response.msg is search('invalid secret id')
+ - not use_secret_id or response.msg is search('(?i)invalid (?:role or )?secret id')
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_approle/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_approle/tasks/main.yml
index 79dfd38d7..5d31a32c3 100644
--- a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_approle/tasks/main.yml
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_approle/tasks/main.yml
@@ -49,4 +49,4 @@
use_secret_id: '{{ item[0][1] == secret_id_role }}'
module_defaults:
assert:
- quiet: yes
+ quiet: true
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_aws_iam/tasks/aws_iam_test_target.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_aws_iam/tasks/aws_iam_test_target.yml
index 0f4267f13..1e905afc9 100644
--- a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_aws_iam/tasks/aws_iam_test_target.yml
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_aws_iam/tasks/aws_iam_test_target.yml
@@ -29,7 +29,7 @@
register: response
vault_test_auth:
role_id: fail-me-role
- want_exception: yes
+ want_exception: true
- assert:
fail_msg: "An invalid request somehow did not cause a failure."
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_aws_iam/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_aws_iam/tasks/main.yml
index 50c57e5c6..b7598105c 100644
--- a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_aws_iam/tasks/main.yml
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_aws_iam/tasks/main.yml
@@ -20,4 +20,4 @@
this_path: '{{ item[0] }}'
module_defaults:
assert:
- quiet: yes
+ quiet: true
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_azure/tasks/azure_test_target.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_azure/tasks/azure_test_target.yml
index 0c637c706..3c2ff255a 100644
--- a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_azure/tasks/azure_test_target.yml
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_azure/tasks/azure_test_target.yml
@@ -32,7 +32,7 @@
register: response
vault_test_auth:
role_id: fail-me-role
- want_exception: yes
+ want_exception: true
- assert:
fail_msg: "An invalid request somehow did not cause a failure."
@@ -43,7 +43,7 @@
- name: Failure expected when role_id is not given
register: response
vault_test_auth:
- want_exception: yes
+ want_exception: true
- assert:
fail_msg: |
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_azure/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_azure/tasks/main.yml
index 95bde76e5..860f9bb18 100644
--- a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_azure/tasks/main.yml
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_azure/tasks/main.yml
@@ -23,4 +23,4 @@
this_path: '{{ item[0] }}'
module_defaults:
assert:
- quiet: yes
+ quiet: true
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_cert/tasks/cert_test_target.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_cert/tasks/cert_test_target.yml
index 897a2e1d3..e92b6c73a 100644
--- a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_cert/tasks/cert_test_target.yml
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_cert/tasks/cert_test_target.yml
@@ -30,7 +30,7 @@
vault_test_auth:
cert_auth_public_key: "{{ invalid_auth_cert_cert }}"
cert_auth_private_key: "{{ invalid_auth_cert_key }}"
- want_exception: yes
+ want_exception: true
register: response
- assert:
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_cert/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_cert/tasks/main.yml
index 7ac78b17f..fff6cf07d 100644
--- a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_cert/tasks/main.yml
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_cert/tasks/main.yml
@@ -48,7 +48,7 @@
this_path: '{{ item }}'
module_defaults:
assert:
- quiet: yes
+ quiet: true
- name: Run cert tests (target)
loop: '{{ auth_paths }}'
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_jwt/tasks/jwt_test_target.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_jwt/tasks/jwt_test_target.yml
index 25110f8fe..456cd2adc 100644
--- a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_jwt/tasks/jwt_test_target.yml
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_jwt/tasks/jwt_test_target.yml
@@ -30,7 +30,7 @@
register: response
vault_test_auth:
jwt: '{{ jwt_invalid }}'
- want_exception: yes
+ want_exception: true
- assert:
fail_msg: "An invalid JWT somehow did not cause a failure."
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_jwt/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_jwt/tasks/main.yml
index 1bef30955..1eb0d1ed2 100644
--- a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_jwt/tasks/main.yml
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_jwt/tasks/main.yml
@@ -47,7 +47,7 @@
this_path: '{{ item }}'
module_defaults:
assert:
- quiet: yes
+ quiet: true
- name: Run JWT tests (target)
loop: '{{ auth_paths }}'
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_ldap/tasks/ldap_test_target.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_ldap/tasks/ldap_test_target.yml
index 663f9065e..372dd7ea6 100644
--- a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_ldap/tasks/ldap_test_target.yml
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_ldap/tasks/ldap_test_target.yml
@@ -28,7 +28,7 @@
register: response
vault_test_auth:
username: fail-me-username
- want_exception: yes
+ want_exception: true
- assert:
fail_msg: "An invalid request somehow did not cause a failure."
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_ldap/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_ldap/tasks/main.yml
index 1e561648e..01dbb225c 100644
--- a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_ldap/tasks/main.yml
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_ldap/tasks/main.yml
@@ -20,4 +20,4 @@
this_path: '{{ item[0] }}'
module_defaults:
assert:
- quiet: yes
+ quiet: true
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_token/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_token/tasks/main.yml
index 768b8ac8c..b2949bb06 100644
--- a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_token/tasks/main.yml
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_token/tasks/main.yml
@@ -26,9 +26,9 @@
- import_tasks: token_test_target.yml
module_defaults:
assert:
- quiet: yes
+ quiet: true
- import_tasks: token_test_controller.yml
module_defaults:
assert:
- quiet: yes
+ quiet: true
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_token/tasks/token_test_controller.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_token/tasks/token_test_controller.yml
index 137c747ce..258d8d798 100644
--- a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_token/tasks/token_test_controller.yml
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_token/tasks/token_test_controller.yml
@@ -56,7 +56,7 @@
token: '{{ response.login.auth.client_token }}'
path: '{{ secret }}'
register: secret_data
- ignore_errors: yes
+ ignore_errors: true
- assert:
that:
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_token/tasks/token_test_target.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_token/tasks/token_test_target.yml
index cbfa30f70..235d2a7b3 100644
--- a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_token/tasks/token_test_target.yml
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_token/tasks/token_test_target.yml
@@ -54,7 +54,7 @@
token: '{{ response.login.auth.client_token }}'
path: '{{ secret }}'
register: secret_data
- ignore_errors: yes
+ ignore_errors: true
- assert:
that:
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_userpass/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_userpass/tasks/main.yml
index 39d6373f4..055c55e1d 100644
--- a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_userpass/tasks/main.yml
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_userpass/tasks/main.yml
@@ -47,4 +47,4 @@
this_path: '{{ item[0] }}'
module_defaults:
assert:
- quiet: yes
+ quiet: true
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_userpass/tasks/userpass_test_target.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_userpass/tasks/userpass_test_target.yml
index a502ba573..1d23e79a2 100644
--- a/ansible_collections/community/hashi_vault/tests/integration/targets/auth_userpass/tasks/userpass_test_target.yml
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/auth_userpass/tasks/userpass_test_target.yml
@@ -28,7 +28,7 @@
register: response
vault_test_auth:
password: fake
- want_exception: yes
+ want_exception: true
- assert:
fail_msg: "An invalid password somehow did not cause a failure."
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/connection_options/tasks/controller.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/connection_options/tasks/controller.yml
index f9c44fefe..cbd0150b5 100644
--- a/ansible_collections/community/hashi_vault/tests/integration/targets/connection_options/tasks/controller.yml
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/connection_options/tasks/controller.yml
@@ -2,7 +2,7 @@
- name: Connection Tests
module_defaults:
assert:
- quiet: yes
+ quiet: true
vars:
# we don't set kwargs: {} here because of https://github.com/ansible/ansible/issues/75286
test_cmd: &test
@@ -37,14 +37,14 @@
- name: test HTTP with wrong proxy
<<: *test
vars:
- vault_test_connection_want_exception: yes
+ vault_test_connection_want_exception: true
ansible_hashi_vault_proxies: http://127.0.0.1:4567
ansible_hashi_vault_retries: 2
- assert:
that:
- result is failed
- - result.msg is search('Cannot connect to proxy')
+ - result.msg is search('(?:Cannot|Unable to) connect to proxy')
- result.retries == 2
- name: HTTPS connection
@@ -67,8 +67,8 @@
- name: test HTTPS with cert validation
<<: *test
vars:
- vault_test_connection_want_args: yes
- vault_test_connection_want_exception: yes
+ vault_test_connection_want_args: true
+ vault_test_connection_want_exception: true
- <<: *assert
@@ -85,13 +85,13 @@
- name: test HTTPS with wrong proxy & cert validation
<<: *test
vars:
- vault_test_connection_want_exception: yes
- ansible_hashi_vault_validate_certs: yes
+ vault_test_connection_want_exception: true
+ ansible_hashi_vault_validate_certs: true
ansible_hashi_vault_proxies: http://127.0.0.1:4567
ansible_hashi_vault_retries: 2
- assert:
that:
- result is failed
- - result.msg is search('Cannot connect to proxy')
+ - result.msg is search('(?:Cannot|Unable to) connect to proxy')
- result.retries == 2
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/connection_options/tasks/target.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/connection_options/tasks/target.yml
index 7fb854b8d..45f9403da 100644
--- a/ansible_collections/community/hashi_vault/tests/integration/targets/connection_options/tasks/target.yml
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/connection_options/tasks/target.yml
@@ -2,7 +2,7 @@
- name: Connection Tests
module_defaults:
assert:
- quiet: yes
+ quiet: true
vars:
assert_cmd: &assert
assert:
@@ -30,14 +30,14 @@
- name: test HTTP with wrong proxy
register: result
vault_test_connection:
- want_exception: yes
+ want_exception: true
proxies: http://127.0.0.1:4567
retries: 2
- assert:
that:
- result.inner is failed
- - result.msg is search('Cannot connect to proxy')
+ - result.msg is search('(?:Cannot|Unable to) connect to proxy')
- result.retries == 2
- name: HTTPS connection
@@ -57,7 +57,7 @@
- name: test HTTPS with cert validation
register: result
vault_test_connection:
- want_args: yes
+ want_args: true
- <<: *assert
@@ -72,13 +72,13 @@
- name: test HTTPS with wrong proxy & cert validation
register: result
vault_test_connection:
- want_exception: yes
- validate_certs: yes
+ want_exception: true
+ validate_certs: true
proxies: http://127.0.0.1:4567
retries: 2
- assert:
that:
- result.inner is failed
- - result.msg is search('Cannot connect to proxy')
+ - result.msg is search('(?:Cannot|Unable to) connect to proxy')
- result.retries == 2
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/lookup_hashi_vault/tasks/lookup_test.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/lookup_hashi_vault/tasks/lookup_test.yml
index 21306ee9f..f9cf9674c 100644
--- a/ansible_collections/community/hashi_vault/tests/integration/targets/lookup_hashi_vault/tasks/lookup_test.yml
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/lookup_hashi_vault/tasks/lookup_test.yml
@@ -92,21 +92,20 @@
- test_inexistent.msg is search("doesn't seem to exist")
fail_msg: "Expected failure but got success or wrong failure message."
- # TODO: v5.0.0 - uncomment below: https://github.com/ansible-collections/community.hashi_vault/pull/350
- # - name: Failure expected when duplicate terms are used in the term string
- # vars:
- # duplicate_terms: >-
- # {{
- # lookup('community.hashi_vault.hashi_vault',
- # vault_kv2_api_path ~ '/secrets secret=' ~ vault_kv2_api_path ~ '/secret2',
- # **kwargs)
- # }}
- # ansible.builtin.debug:
- # msg: 'Failure is expected ({{ duplicate_terms }})'
- # register: test_duplicate
- # ignore_errors: true
+ - name: Failure expected when duplicate terms are used in the term string
+ vars:
+ duplicate_terms: >-
+ {{
+ lookup('community.hashi_vault.hashi_vault',
+ vault_kv2_api_path ~ '/secrets secret=' ~ vault_kv2_api_path ~ '/secret2',
+ **kwargs)
+ }}
+ ansible.builtin.debug:
+ msg: 'Failure is expected ({{ duplicate_terms }})'
+ register: test_duplicate
+ ignore_errors: true
- # - assert:
- # that:
- # - test_duplicate is failed
- # - test_duplicate.msg is search("^Duplicate key 'secret' in term string")
+ - assert:
+ that:
+ - test_duplicate is failed
+ - test_duplicate.msg is search("Duplicate key 'secret' in the term string")
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/lookup_vault_write/tasks/lookup_vault_write_test.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/lookup_vault_write/tasks/lookup_vault_write_test.yml
index 33dc245f9..e43c04708 100644
--- a/ansible_collections/community/hashi_vault/tests/integration/targets/lookup_vault_write/tasks/lookup_vault_write_test.yml
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/lookup_vault_write/tasks/lookup_vault_write_test.yml
@@ -11,6 +11,9 @@
test_data:
a: 1
b: two
+ # https://github.com/ansible-collections/community.hashi_vault/issues/389
+ path: path_value
+ wrap_ttl: wrap_ttl_value
block:
- name: Write data to the cubbyhole
vars:
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_configure/aliases b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_configure/aliases
new file mode 100644
index 000000000..7636a9a65
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_configure/aliases
@@ -0,0 +1 @@
+context/target
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_configure/meta/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_configure/meta/main.yml
new file mode 100644
index 000000000..e867490b0
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_configure/meta/main.yml
@@ -0,0 +1,4 @@
+---
+dependencies:
+ - setup_vault_test_plugins
+ - setup_vault_configure_database
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_configure/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_configure/tasks/main.yml
new file mode 100644
index 000000000..2c929267f
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_configure/tasks/main.yml
@@ -0,0 +1,3 @@
+---
+- import_tasks: module_vault_database_connection_configure_setup.yml
+- import_tasks: module_vault_database_connection_configure_test.yml
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_configure/tasks/module_vault_database_connection_configure_setup.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_configure/tasks/module_vault_database_connection_configure_setup.yml
new file mode 100644
index 000000000..f43f5d09e
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_configure/tasks/module_vault_database_connection_configure_setup.yml
@@ -0,0 +1,9 @@
+---
+- name: Configuration tasks
+ module_defaults:
+ vault_ci_token_create: '{{ vault_plugins_module_defaults_common }}'
+ block:
+ - name: Create a test non-root token
+ vault_ci_token_create:
+ policies: [policy-database-all]
+ register: user_token_cmd
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_configure/tasks/module_vault_database_connection_configure_test.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_configure/tasks/module_vault_database_connection_configure_test.yml
new file mode 100644
index 000000000..903425cdb
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_configure/tasks/module_vault_database_connection_configure_test.yml
@@ -0,0 +1,192 @@
+---
+- name: Var block
+ vars:
+ user_token: "{{ user_token_cmd.result.auth.client_token }}"
+ module_defaults:
+ community.hashi_vault.vault_database_connection_configure: &defaults
+ url: "{{ vault_test_server_http }}"
+ auth_method: token
+ token: "{{ user_token }}"
+ token_validate: true
+ block:
+ - name: Test database connection configure [check mode]
+ register: db_connection_configure
+ check_mode: true
+ ignore_errors: true
+ community.hashi_vault.vault_database_connection_configure:
+ engine_mount_point: DOES NOT MATTER
+ connection_name: DOES NOT MATTER
+ plugin_name: DOES NOT MATTER
+ allowed_roles: DOES NOT MATTER
+ connection_url: DOES NOT MATTER
+ connection_username: DOES NOT MATTER
+ connection_password: DOES NOT MATTER
+
+ - name: Check [check mode]
+ ansible.builtin.assert: &success
+ that:
+ - db_connection_configure is changed
+
+ - name: Test database connection configure (explicit mount - invalid, plugin_name, connection_url, connection_user, connection_password)
+ register: db_connection_configure
+ ignore_errors: true
+ community.hashi_vault.vault_database_connection_configure:
+ engine_mount_point: NOT REAL
+ connection_name: con1-postgres
+ plugin_name: postgresql-database-plugin
+ allowed_roles: "*"
+ connection_url: "postgresql://{{ '{{username}}' }}:{{ '{{password}}' }}@postgres:5432/hcvault?sslmode=disable"
+ connection_username: con1
+ connection_password: con1
+
+ - name: Check (explicit mount - invalid, plugin_name, connection_url, connection_user, connection_password)
+ ansible.builtin.assert: &failure_invalid_mount
+ that:
+ - db_connection_configure is failed
+ - db_connection_configure.msg is search('Permission Denied')
+
+ - name: Test database connection configure (explicit mount, plugin_name - invalid, connection_url, connection_user, connection_password)
+ register: db_connection_configure
+ ignore_errors: true
+ community.hashi_vault.vault_database_connection_configure:
+ engine_mount_point: database
+ connection_name: con1-postgres
+ plugin_name: NOT REAL
+ allowed_roles: "*"
+ connection_url: "postgresql://{{ '{{username}}' }}:{{ '{{password}}' }}@postgres:5432/hcvault?sslmode=disable"
+ connection_username: con1
+ connection_password: con1
+
+ - name: Check (explicit mount, plugin_name - invalid, connection_url, connection_user, connection_password)
+ ansible.builtin.assert: &failure_invalid_request
+ that:
+ - db_connection_configure is failed
+ - db_connection_configure.msg is search('Error creating database connection')
+
+ - name: Test database connection configure (explicit mount, plugin_name, connection_url - invalid, connection_user, connection_password)
+ register: db_connection_configure
+ ignore_errors: true
+ community.hashi_vault.vault_database_connection_configure:
+ engine_mount_point: database
+ connection_name: con1-postgres
+ plugin_name: postgresql-database-plugin
+ allowed_roles: "*"
+ connection_url: postgresql://{{ '{{username}}' }}:{{ '{{password}}' }}@NOT_REAL:5432/hcvault?sslmode=disable
+ connection_username: con1
+ connection_password: con1
+
+ - name: Check (explicit mount, plugin_name, connection_url - invalid, connection_user, connection_password)
+ ansible.builtin.assert: *failure_invalid_request
+
+ - name: Test database connection configure (explicit mount, plugin_name, connection_url, connection_user - invalid, connection_password)
+ register: db_connection_configure
+ ignore_errors: true
+ community.hashi_vault.vault_database_connection_configure:
+ engine_mount_point: database
+ connection_name: con1-postgres
+ plugin_name: postgresql-database-plugin
+ allowed_roles: "*"
+ connection_url: postgresql://{{ '{{username}}' }}:{{ '{{password}}' }}@postgres:5432/hcvault?sslmode=disable
+ connection_username: NOT REAL
+ connection_password: con1
+
+ - name: Check (explicit mount, plugin_name, connection_url, connection_user - invalid, connection_password)
+ ansible.builtin.assert: *failure_invalid_request
+
+ - name: Test database connection configure (explicit mount, plugin_name, connection_url, connection_user, connection_password - invalid)
+ register: db_connection_configure
+ ignore_errors: true
+ community.hashi_vault.vault_database_connection_configure:
+ engine_mount_point: database
+ connection_name: con1-postgres
+ plugin_name: postgresql-database-plugin
+ allowed_roles: "*"
+ connection_url: postgresql://{{ '{{username}}' }}:{{ '{{password}}' }}@postgres:5432/hcvault?sslmode=disable
+ connection_username: con1
+ connection_password: NOT REAL
+
+ - name: Check (explicit mount, plugin_name, connection_url, connection_user, connection_password)
+ ansible.builtin.assert: *failure_invalid_request
+
+ - name: Test database connection configure (explicit mount, plugin_name, connection_url, connection_user, connection_password - invalid)
+ register: db_connection_configure
+ community.hashi_vault.vault_database_connection_configure:
+ engine_mount_point: database
+ connection_name: con1-postgres
+ plugin_name: postgresql-database-plugin
+ allowed_roles: "*"
+ connection_url: postgresql://{{ '{{username}}' }}:{{ '{{password}}' }}@postgres:5432/hcvault?sslmode=disable
+ connection_username: con1
+ connection_password: con1
+
+ - name: Check (explicit mount, plugin_name, connection_url, connection_user, connection_password)
+ ansible.builtin.assert: *success
+
+ - name: Test database connection configure (default mount, plugin_name - invalid, connection_url, connection_user, connection_password)
+ register: db_connection_configure
+ ignore_errors: true
+ community.hashi_vault.vault_database_connection_configure:
+ connection_name: con1-postgres
+ plugin_name: NOT REAL
+ allowed_roles: "*"
+ connection_url: "postgresql://{{ '{{username}}' }}:{{ '{{password}}' }}@postgres:5432/hcvault?sslmode=disable"
+ connection_username: con1
+ connection_password: con1
+
+ - name: Check (default mount, plugin_name - invalid, connection_url, connection_user, connection_password)
+ ansible.builtin.assert: *failure_invalid_request
+
+ - name: Test database connection configure (default mount, plugin_name, connection_url - invalid, connection_user, connection_password)
+ register: db_connection_configure
+ ignore_errors: true
+ community.hashi_vault.vault_database_connection_configure:
+ connection_name: con1-postgres
+ plugin_name: postgresql-database-plugin
+ allowed_roles: "*"
+ connection_url: postgresql://{{ '{{username}}' }}:{{ '{{password}}' }}@NOT_REAL:5432/hcvault?sslmode=disable
+ connection_username: con1
+ connection_password: con1
+
+ - name: Check (default mount, plugin_name, connection_url - invalid, connection_user, connection_password)
+ ansible.builtin.assert: *failure_invalid_request
+
+ - name: Test database connection configure (default mount, plugin_name, connection_url, connection_user - invalid, connection_password)
+ register: db_connection_configure
+ ignore_errors: true
+ community.hashi_vault.vault_database_connection_configure:
+ connection_name: con1-postgres
+ plugin_name: postgresql-database-plugin
+ allowed_roles: "*"
+ connection_url: postgresql://{{ '{{username}}' }}:{{ '{{password}}' }}@postgres:5432/hcvault?sslmode=disable
+ connection_username: NOT REAL
+ connection_password: con1
+
+ - name: Check (default mount, plugin_name, connection_url, connection_user - invalid, connection_password)
+ ansible.builtin.assert: *failure_invalid_request
+
+ - name: Test database connection configure (default mount, plugin_name, connection_url, connection_user, connection_password - invalid)
+ register: db_connection_configure
+ ignore_errors: true
+ community.hashi_vault.vault_database_connection_configure:
+ connection_name: con1-postgres
+ plugin_name: postgresql-database-plugin
+ allowed_roles: "*"
+ connection_url: postgresql://{{ '{{username}}' }}:{{ '{{password}}' }}@postgres:5432/hcvault?sslmode=disable
+ connection_username: con1
+ connection_password: NOT REAL
+
+ - name: Check (default mount, plugin_name, connection_url, connection_user, connection_password - invalid)
+ ansible.builtin.assert: *failure_invalid_request
+
+ - name: Test database connection configure (default mount, plugin_name, connection_url, connection_user, connection_password - invalid)
+ register: db_connection_configure
+ community.hashi_vault.vault_database_connection_configure:
+ connection_name: con1-postgres
+ plugin_name: postgresql-database-plugin
+ allowed_roles: "*"
+ connection_url: postgresql://{{ '{{username}}' }}:{{ '{{password}}' }}@postgres:5432/hcvault?sslmode=disable
+ connection_username: con1
+ connection_password: con1
+
+ - name: Check (default mount, plugin_name, connection_url, connection_user, connection_password)
+ ansible.builtin.assert: *success
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_delete/aliases b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_delete/aliases
new file mode 100644
index 000000000..7636a9a65
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_delete/aliases
@@ -0,0 +1 @@
+context/target
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_delete/meta/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_delete/meta/main.yml
new file mode 100644
index 000000000..e867490b0
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_delete/meta/main.yml
@@ -0,0 +1,4 @@
+---
+dependencies:
+ - setup_vault_test_plugins
+ - setup_vault_configure_database
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_delete/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_delete/tasks/main.yml
new file mode 100644
index 000000000..210fb0ba9
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_delete/tasks/main.yml
@@ -0,0 +1,3 @@
+---
+- import_tasks: module_vault_database_connection_delete_setup.yml
+- import_tasks: module_vault_database_connection_delete_test.yml
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_delete/tasks/module_vault_database_connection_delete_setup.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_delete/tasks/module_vault_database_connection_delete_setup.yml
new file mode 100644
index 000000000..ca5219b07
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_delete/tasks/module_vault_database_connection_delete_setup.yml
@@ -0,0 +1,36 @@
+---
+- name: Configuration tasks
+ module_defaults:
+ vault_ci_token_create: "{{ vault_plugins_module_defaults_common }}"
+ vault_ci_enable_engine: "{{ vault_plugins_module_defaults_common }}"
+ vault_ci_read: "{{ vault_plugins_module_defaults_common }}"
+ vault_ci_write: "{{ vault_plugins_module_defaults_common }}"
+ vault_ci_policy_put: "{{ vault_plugins_module_defaults_common }}"
+ vars:
+ connection_names: ["test-connection-delete-1", "test-connection-delete-2"]
+ usernames: ["con2", "con2"]
+ passwords: ["con2", "con2"]
+ block:
+ - name: Create a test non-root token
+ vault_ci_token_create:
+ policies: [policy-database-all]
+ register: user_token_cmd
+
+ - name: Define database connection data
+ ansible.builtin.set_fact:
+ db_sample_data: "{{ db_sample_data | default([]) + [ {'connection_name': item.0, 'username': item.1, 'password': item.2 } ] }}"
+ with_together:
+ - "{{ connection_names }}"
+ - "{{ usernames }}"
+ - "{{ passwords }}"
+
+ - name: Create database connections that can be deleted in the following test
+ vault_ci_write:
+ path: "database/config/{{ item.connection_name }}"
+ data:
+ plugin_name: "{{ vault_database_plugin_name }}"
+ connection_url: "{{ vault_database_connection_url }}"
+ allowed_roles: "*"
+ username: "{{ item.username }}"
+ password: "{{ item.password }}"
+ loop: "{{ db_sample_data }}"
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_delete/tasks/module_vault_database_connection_delete_test.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_delete/tasks/module_vault_database_connection_delete_test.yml
new file mode 100644
index 000000000..7d51d6e8f
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_delete/tasks/module_vault_database_connection_delete_test.yml
@@ -0,0 +1,84 @@
+---
+- name: Var block
+ vars:
+ user_token: "{{ user_token_cmd.result.auth.client_token }}"
+ module_defaults:
+ community.hashi_vault.vault_database_connection_delete: &defaults
+ url: "{{ vault_test_server_http }}"
+ auth_method: token
+ token: "{{ user_token }}"
+ token_validate: true
+ timeout: 5
+ block:
+ - name: Test database connection delete (explicit mount, connection_name) [check mode]
+ register: db_connection_delete
+ check_mode: true
+ community.hashi_vault.vault_database_connection_delete:
+ engine_mount_point: database
+ connection_name: test-delete-connection-1
+
+ - name: Check (explicit mount) [check mode]
+ ansible.builtin.assert: &success
+ that:
+ - db_connection_delete is changed
+
+ - name: Test database connection delete (explicit mount - invalid, connection_name)
+ register: db_connection_delete
+ ignore_errors: true
+ community.hashi_vault.vault_database_connection_delete:
+ engine_mount_point: NOT REAL
+ connection_name: test-connection-delete-1
+
+ - name: Check (explicit mount - invalid)
+ ansible.builtin.assert: &failure_bad_mount
+ that:
+ - db_connection_delete is failed
+ - db_connection_delete.msg is search('Permission Denied')
+
+ - name: Test database connection delete (explicit mount, connection_name - invalid)
+ register: db_connection_delete
+ ignore_errors: true
+ community.hashi_vault.vault_database_connection_delete:
+ engine_mount_point: database
+ connection_name: NOT REAL
+
+ - name: Check (explicit mount, connection_name - invalid)
+ ansible.builtin.assert: &failure_invalid_path
+ that:
+ - db_connection_delete is failed
+ - db_connection_delete.msg is search('Invalid or missing path')
+
+ - name: Test database connection delete (explicit mount)
+ register: db_connection_delete
+ community.hashi_vault.vault_database_connection_delete:
+ engine_mount_point: database
+ connection_name: test-connection-delete-1
+
+ - name: Check (explicit mount)
+ ansible.builtin.assert: *success
+
+ - name: Test database connection delete (default mount, connection_name) [check mode]
+ register: db_connection_delete
+ check_mode: true
+ community.hashi_vault.vault_database_connection_delete:
+ connection_name: test-connection-delete-2
+
+ - name: Check (explicit mount, connection_name) [check mode]
+ ansible.builtin.assert: *success
+
+ - name: Test database connection delete (default mount, connection_name - invalid)
+ register: db_connection_delete
+ ignore_errors: true
+ community.hashi_vault.vault_database_connection_delete:
+ connection_name: NOT REAL
+
+ - name: Check (default mount, connection_name - invalid)
+ ansible.builtin.assert: *failure_invalid_path
+
+ - name: Test database connection delete (default mount)
+ register: db_connection_delete
+ community.hashi_vault.vault_database_connection_delete:
+ connection_name: test-connection-delete-2
+
+ - name: Check (default mount)
+ ansible.builtin.assert: *success
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_read/aliases b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_read/aliases
new file mode 100644
index 000000000..7636a9a65
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_read/aliases
@@ -0,0 +1 @@
+context/target
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_read/meta/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_read/meta/main.yml
new file mode 100644
index 000000000..e867490b0
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_read/meta/main.yml
@@ -0,0 +1,4 @@
+---
+dependencies:
+ - setup_vault_test_plugins
+ - setup_vault_configure_database
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_read/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_read/tasks/main.yml
new file mode 100644
index 000000000..dd4afd076
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_read/tasks/main.yml
@@ -0,0 +1,3 @@
+---
+- import_tasks: module_vault_database_connection_read_setup.yml
+- import_tasks: module_vault_database_connection_read_test.yml
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_read/tasks/module_vault_database_connection_read_setup.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_read/tasks/module_vault_database_connection_read_setup.yml
new file mode 100644
index 000000000..cd1b09dc7
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_read/tasks/module_vault_database_connection_read_setup.yml
@@ -0,0 +1,9 @@
+---
+- name: Configuration tasks
+ module_defaults:
+ vault_ci_token_create: '{{ vault_plugins_module_defaults_common }}'
+ block:
+ - name: Create a test non-root token
+ vault_ci_token_create:
+ policies: [base-policy-database]
+ register: user_token_cmd
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_read/tasks/module_vault_database_connection_read_test.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_read/tasks/module_vault_database_connection_read_test.yml
new file mode 100644
index 000000000..329f6b94d
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_read/tasks/module_vault_database_connection_read_test.yml
@@ -0,0 +1,134 @@
+---
+- name: Var block
+ vars:
+ user_token: "{{ user_token_cmd.result.auth.client_token }}"
+ module_defaults:
+ community.hashi_vault.vault_database_connection_read: &defaults
+ url: "{{ vault_test_server_http }}"
+ auth_method: token
+ token: "{{ user_token }}"
+ token_validate: true
+ timeout: 5
+ block:
+ - name: Test read database connection (explicit mount - invalid, connection_name) [check mode]
+ register: db_connection
+ check_mode: true
+ ignore_errors: true
+ community.hashi_vault.vault_database_connection_read:
+ engine_mount_point: NOT REAL
+ connection_name: my-postgresql-database
+
+ - name: Check (explicit mount - invalid, connection_name) [check mode]
+ ansible.builtin.assert: &failure_bad_mount
+ that:
+ - db_connection is failed
+ - db_connection.msg is search('Permission Denied')
+
+ - name: Test read database connection (explicit mount, connection_name - invalid) [check mode]
+ register: db_connection
+ check_mode: true
+ ignore_errors: true
+ community.hashi_vault.vault_database_connection_read:
+ engine_mount_point: database
+ connection_name: NOT_REAL
+
+ - name: Check (explicit mount, connection_name - invalid) [check mode]
+ ansible.builtin.assert: &failure_invalid_path
+ that:
+ - db_connection is failed
+ - db_connection.msg is search('Invalid or missing path')
+
+ - name: Test read database connection (explicit mount, connection_name) [check mode]
+ register: db_connection
+ check_mode: true
+ community.hashi_vault.vault_database_connection_read:
+ engine_mount_point: database
+ connection_name: my-postgresql-database
+
+ - name: Check (explicit mount) [check mode]
+ ansible.builtin.assert: &success
+ that:
+ - db_connection is defined
+ - "'data' in db_connection"
+ - "'raw' in db_connection"
+ - db_connection["data"]["plugin_name"] == 'postgresql-database-plugin'
+ - db_connection["data"]["connection_details"]["username"] == 'postgres'
+ - "'allowed_roles' in db_connection['data']"
+ - "'password_policy' in db_connection['data']"
+ - "'root_credentials_rotate_statements' in db_connection['data']"
+
+ - name: Test read database connection (explicit mount, connection_name invalid) [check mode]
+ register: db_connection
+ check_mode: true
+ ignore_errors: true
+ community.hashi_vault.vault_database_connection_read:
+ engine_mount_point: database
+ connection_name: NOT REAL
+
+ - name: Check (explicit mount, connection_name invalid) [check mode]
+ ansible.builtin.assert: *failure_invalid_path
+
+ - name: Test read database connection (explicit mount, connection_name)
+ register: db_connection
+ community.hashi_vault.vault_database_connection_read:
+ engine_mount_point: database
+ connection_name: my-postgresql-database
+
+ - name: Check (explicit mount, connection_name)
+ ansible.builtin.assert: *success
+
+ - name: Test read database connection (explicit mount - invalid, connection_name)
+ register: db_connection
+ ignore_errors: true
+ community.hashi_vault.vault_database_connection_read:
+ engine_mount_point: NOT REAL
+ connection_name: my-postgresql-database
+
+ - name: Check (explicit mount - invalid, connection_name)
+ ansible.builtin.assert: *failure_bad_mount
+
+ - name: Test read database connection (explicit mount, connection_name - invalid)
+ register: db_connection
+ ignore_errors: true
+ community.hashi_vault.vault_database_connection_read:
+ engine_mount_point: database
+ connection_name: NOT REAL
+
+ - name: Check (explicit mount, connection_name - invalid)
+ ansible.builtin.assert: *failure_invalid_path
+
+ - name: Test read database connection (default mount) [check mode]
+ register: db_connection
+ check_mode: true
+ community.hashi_vault.vault_database_connection_read:
+ connection_name: my-postgresql-database
+
+ - name: Check (default mount) [check mode]
+ ansible.builtin.assert: *success
+
+ - name: Test read database connection (default mount, connection_name - invalid) [check mode]
+ register: db_connection
+ check_mode: true
+ ignore_errors: true
+ community.hashi_vault.vault_database_connection_read:
+ connection_name: NOT REAL
+
+ - name: Check (default mount, connection_name - invalid) [check mode]
+ ansible.builtin.assert: *failure_invalid_path
+
+ - name: Test read database connection (default mount, connection_name)
+ register: db_connection
+ community.hashi_vault.vault_database_connection_read:
+ connection_name: my-postgresql-database
+
+ - name: Check (76default mount, connection_name)
+ ansible.builtin.assert: *success
+
+ - name: Test read database connection (default mount, connection_name - invalid)
+ register: db_connection
+ ignore_errors: true
+ community.hashi_vault.vault_database_connection_read:
+ connection_name: NOT REAL
+
+ - name: Check (default mount, connection_name - invalid)
+ ansible.builtin.assert: *failure_invalid_path
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_reset/aliases b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_reset/aliases
new file mode 100644
index 000000000..7636a9a65
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_reset/aliases
@@ -0,0 +1 @@
+context/target
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_reset/meta/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_reset/meta/main.yml
new file mode 100644
index 000000000..e867490b0
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_reset/meta/main.yml
@@ -0,0 +1,4 @@
+---
+dependencies:
+ - setup_vault_test_plugins
+ - setup_vault_configure_database
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_reset/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_reset/tasks/main.yml
new file mode 100644
index 000000000..4e52e7602
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_reset/tasks/main.yml
@@ -0,0 +1,3 @@
+---
+- import_tasks: module_vault_database_connection_reset_setup.yml
+- import_tasks: module_vault_database_connection_reset_test.yml
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_reset/tasks/module_vault_database_connection_reset_setup.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_reset/tasks/module_vault_database_connection_reset_setup.yml
new file mode 100644
index 000000000..f43f5d09e
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_reset/tasks/module_vault_database_connection_reset_setup.yml
@@ -0,0 +1,9 @@
+---
+- name: Configuration tasks
+ module_defaults:
+ vault_ci_token_create: '{{ vault_plugins_module_defaults_common }}'
+ block:
+ - name: Create a test non-root token
+ vault_ci_token_create:
+ policies: [policy-database-all]
+ register: user_token_cmd
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_reset/tasks/module_vault_database_connection_reset_test.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_reset/tasks/module_vault_database_connection_reset_test.yml
new file mode 100644
index 000000000..ce05750bc
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connection_reset/tasks/module_vault_database_connection_reset_test.yml
@@ -0,0 +1,84 @@
+---
+- name: Var block
+ vars:
+ user_token: "{{ user_token_cmd.result.auth.client_token }}"
+ module_defaults:
+ community.hashi_vault.vault_database_connection_reset: &defaults
+ url: "{{ vault_test_server_http }}"
+ auth_method: token
+ token: "{{ user_token }}"
+ token_validate: true
+ timeout: 5
+ block:
+ - name: Test database connection reset (explicit mount) [check mode]
+ register: db_connection_reset
+ check_mode: true
+ community.hashi_vault.vault_database_connection_reset:
+ engine_mount_point: database
+ connection_name: "{{ vault_database_connection_name }}"
+
+ - name: Check (explicit mount) [check mode]
+ ansible.builtin.assert: &success
+ that:
+ - db_connection_reset is changed
+
+ - name: Test database connection reset (explicit mount - invalid, connection_name)
+ register: db_connection_reset
+ ignore_errors: true
+ community.hashi_vault.vault_database_connection_reset:
+ engine_mount_point: NOT REAL
+ connection_name: "{{ vault_database_connection_name }}"
+
+ - name: Check (explicit mount - invalid)
+ ansible.builtin.assert: &failure_bad_mount
+ that:
+ - db_connection_reset is failed
+ - db_connection_reset.msg is search('Permission Denied')
+
+ - name: Test database connection reset (explicit mount, connection_name - invalid)
+ register: db_connection_reset
+ ignore_errors: true
+ community.hashi_vault.vault_database_connection_reset:
+ engine_mount_point: database
+ connection_name: NOT REAL
+
+ - name: Check (explicit mount, connection_name - invalid)
+ ansible.builtin.assert: &failure_invalid_path
+ that:
+ - db_connection_reset is failed
+ - db_connection_reset.msg is search('Invalid or missing path')
+
+ - name: Test database connection reset (explicit mount, connection_name)
+ register: db_connection_reset
+ community.hashi_vault.vault_database_connection_reset:
+ engine_mount_point: database
+ connection_name: "{{ vault_database_connection_name }}"
+
+ - name: Check (explicit mount)
+ ansible.builtin.assert: *success
+
+ - name: Test database connection reset (default mount) [check mode]
+ register: db_connection_reset
+ check_mode: true
+ community.hashi_vault.vault_database_connection_reset:
+ connection_name: "{{ vault_database_connection_name }}"
+
+ - name: Check (explicit mount, connection_name) [check mode]
+ ansible.builtin.assert: *success
+
+ - name: Test database connection reset (default mount, connection_name - invalid)
+ register: db_connection_reset
+ ignore_errors: true
+ community.hashi_vault.vault_database_connection_reset:
+ connection_name: NOT REAL
+
+ - name: Check (default mount, connection_name - invalid)
+ ansible.builtin.assert: *failure_invalid_path
+
+ - name: Test database connection reset (default mount)
+ register: db_connection_reset
+ community.hashi_vault.vault_database_connection_reset:
+ connection_name: "{{ vault_database_connection_name }}"
+
+ - name: Check (default mount)
+ ansible.builtin.assert: *success
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connections_list/aliases b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connections_list/aliases
new file mode 100644
index 000000000..7636a9a65
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connections_list/aliases
@@ -0,0 +1 @@
+context/target
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connections_list/meta/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connections_list/meta/main.yml
new file mode 100644
index 000000000..e867490b0
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connections_list/meta/main.yml
@@ -0,0 +1,4 @@
+---
+dependencies:
+ - setup_vault_test_plugins
+ - setup_vault_configure_database
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connections_list/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connections_list/tasks/main.yml
new file mode 100644
index 000000000..4d51ae24a
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connections_list/tasks/main.yml
@@ -0,0 +1,3 @@
+---
+- import_tasks: module_vault_database_connection_list_setup.yml
+- import_tasks: module_vault_database_connection_list_test.yml
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connections_list/tasks/module_vault_database_connection_list_setup.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connections_list/tasks/module_vault_database_connection_list_setup.yml
new file mode 100644
index 000000000..cd1b09dc7
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connections_list/tasks/module_vault_database_connection_list_setup.yml
@@ -0,0 +1,9 @@
+---
+- name: Configuration tasks
+ module_defaults:
+ vault_ci_token_create: '{{ vault_plugins_module_defaults_common }}'
+ block:
+ - name: Create a test non-root token
+ vault_ci_token_create:
+ policies: [base-policy-database]
+ register: user_token_cmd
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connections_list/tasks/module_vault_database_connection_list_test.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connections_list/tasks/module_vault_database_connection_list_test.yml
new file mode 100644
index 000000000..c57890457
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_connections_list/tasks/module_vault_database_connection_list_test.yml
@@ -0,0 +1,72 @@
+---
+- name: Var block
+ vars:
+ user_token: "{{ user_token_cmd.result.auth.client_token }}"
+ module_defaults:
+ community.hashi_vault.vault_database_connections_list: &defaults
+ url: "{{ vault_test_server_http }}"
+ auth_method: token
+ token: "{{ user_token }}"
+ token_validate: true
+ timeout: 5
+ block:
+ - name: Test list database connections (explicit mount - invalid) [check mode]
+ register: db_connections
+ check_mode: true
+ ignore_errors: true
+ community.hashi_vault.vault_database_connections_list:
+ engine_mount_point: NOT REAL
+
+ - name: Check (explicit mount - invalid) [check mode]
+ ansible.builtin.assert: &failure_bad_mount
+ that:
+ - db_connections is failed
+ - db_connections.msg is search('Permission Denied')
+
+ - name: Test list database connections (explicit mount - invalid)
+ register: db_connections
+ ignore_errors: true
+ community.hashi_vault.vault_database_connections_list:
+ engine_mount_point: NOT REAL
+
+ - name: Check (explicit mount - invalid) [check mode]
+ ansible.builtin.assert: *failure_bad_mount
+
+ - name: Test list database connections (explicit mount) [check mode]
+ register: db_connections
+ check_mode: true
+ community.hashi_vault.vault_database_connections_list:
+ engine_mount_point: database
+
+ - name: Check (explicit mount) [check mode]
+ ansible.builtin.assert: &success
+ that:
+ - db_connections is defined
+ - "'data' in db_connections"
+ - "'raw' in db_connections"
+ - "'connections' in db_connections"
+ - "'keys' in db_connections['data']"
+ - "'my-postgresql-database' in db_connections['data']['keys']"
+
+ - name: Test list database connections (explicit mount)
+ register: db_connections
+ community.hashi_vault.vault_database_connections_list:
+ engine_mount_point: database
+
+ - name: Check (explicit mount)
+ ansible.builtin.assert: *success
+
+ - name: Test list database connections (default mount) [check mode]
+ check_mode: true
+ register: db_connections
+ community.hashi_vault.vault_database_connections_list:
+
+ - name: Check (default mount) [check mode]
+ ansible.builtin.assert: *success
+
+ - name: Test list database connections (default mount)
+ register: db_connections
+ community.hashi_vault.vault_database_connections_list:
+
+ - name: Check (default mount)
+ ansible.builtin.assert: *success
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_create/aliases b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_create/aliases
new file mode 100644
index 000000000..7636a9a65
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_create/aliases
@@ -0,0 +1 @@
+context/target
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_create/meta/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_create/meta/main.yml
new file mode 100644
index 000000000..e867490b0
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_create/meta/main.yml
@@ -0,0 +1,4 @@
+---
+dependencies:
+ - setup_vault_test_plugins
+ - setup_vault_configure_database
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_create/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_create/tasks/main.yml
new file mode 100644
index 000000000..88f896f5a
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_create/tasks/main.yml
@@ -0,0 +1,3 @@
+---
+- import_tasks: module_vault_database_role_create_setup.yml
+- import_tasks: module_vault_database_role_create_test.yml
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_create/tasks/module_vault_database_role_create_setup.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_create/tasks/module_vault_database_role_create_setup.yml
new file mode 100644
index 000000000..7abb3ceb2
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_create/tasks/module_vault_database_role_create_setup.yml
@@ -0,0 +1,13 @@
+---
+- name: Configuration tasks
+ module_defaults:
+ vault_ci_token_create: '{{ vault_plugins_module_defaults_common }}'
+ vault_ci_enable_engine: '{{ vault_plugins_module_defaults_common }}'
+ vault_ci_read: '{{ vault_plugins_module_defaults_common }}'
+ vault_ci_write: '{{ vault_plugins_module_defaults_common }}'
+ vault_ci_policy_put: '{{ vault_plugins_module_defaults_common }}'
+ block:
+ - name: Create a test non-root token
+ vault_ci_token_create:
+ policies: [policy-database-all]
+ register: user_token_cmd
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_create/tasks/module_vault_database_role_create_test.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_create/tasks/module_vault_database_role_create_test.yml
new file mode 100644
index 000000000..f82109ec1
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_create/tasks/module_vault_database_role_create_test.yml
@@ -0,0 +1,92 @@
+---
+- name: Var block
+ vars:
+ user_token: "{{ user_token_cmd.result.auth.client_token }}"
+ module_defaults:
+ community.hashi_vault.vault_database_role_create: &defaults
+ url: "{{ vault_test_server_http }}"
+ auth_method: token
+ token: "{{ user_token }}"
+ token_validate: true
+ timeout: 5
+ block:
+ - name: Test database create role [check mode]
+ register: db_create_role
+ check_mode: true
+ community.hashi_vault.vault_database_role_create:
+ engine_mount_point: Does Not Matter
+ connection_name: Does Not Matter
+ creation_statements:
+ - Does Not Matter
+ role_name: Does Not Matter
+
+ - name: Check [check mode]
+ ansible.builtin.assert: &success
+ that:
+ - db_create_role is changed
+
+ - name: Test database create role (explicit mount point - invalid, connection_name)
+ register: db_create_role
+ ignore_errors: true
+ community.hashi_vault.vault_database_role_create:
+ engine_mount_point: NOT REAL
+ connection_name: "{{ vault_database_connection_name }}"
+ creation_statements:
+ - "{{ vault_database_dynamic_user_sql }}"
+ role_name: dynamic_role_read
+
+ - name: Check (explicit mount point - invalid, connection_name)
+ ansible.builtin.assert: &failure_bad_mount
+ that:
+ - db_create_role is failed
+ - db_create_role.msg is search('Permission Denied')
+
+ - name: Test database create role (explicit mount point, connection_name - invalid)
+ register: db_create_role
+ ignore_errors: true
+ community.hashi_vault.vault_database_role_create:
+ engine_mount_point: database
+ connection_name: nonono
+ creation_statements:
+ - "{{ vault_database_dynamic_user_sql }}"
+ role_name: dynamic_role_read_invalid_1
+
+ # Note that this statement will be successful and a dynamic role will be added, although the connection name is not existing
+ - name: Check (explicit mount point, connection_name - invalid)
+ ansible.builtin.assert: *success
+
+ - name: Test database create role (explicit mount point, connection_name)
+ register: db_create_role
+ community.hashi_vault.vault_database_role_create:
+ engine_mount_point: database
+ connection_name: "{{ vault_database_connection_name }}"
+ creation_statements:
+ - "{{ vault_database_dynamic_user_sql }}"
+ role_name: dynamic_role_read_1
+
+ - name: Check (explicit mount point)
+ ansible.builtin.assert: *success
+
+ - name: Test database create role (default mount point, connection_name - invalid)
+ register: db_create_role
+ ignore_errors: true
+ community.hashi_vault.vault_database_role_create:
+ connection_name: NOT REAL
+ creation_statements:
+ - "{{ vault_database_dynamic_user_sql }}"
+ role_name: dynamic_role_read_invalid_2
+
+ # Note that this statement will be successful and a dynamic role will be added, although the connection name is not existing
+ - name: Check (default mount point, connection_name - invalid)
+ ansible.builtin.assert: *success
+
+ - name: Test database create role (default mount point, connection_name)
+ register: db_create_role
+ community.hashi_vault.vault_database_role_create:
+ connection_name: "{{ vault_database_connection_name }}"
+ creation_statements:
+ - "{{ vault_database_dynamic_user_sql }}"
+ role_name: dynamic_role_read_2
+
+ - name: Check (explicit mount point)
+ ansible.builtin.assert: *success
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_delete/aliases b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_delete/aliases
new file mode 100644
index 000000000..7636a9a65
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_delete/aliases
@@ -0,0 +1 @@
+context/target
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_delete/meta/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_delete/meta/main.yml
new file mode 100644
index 000000000..e867490b0
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_delete/meta/main.yml
@@ -0,0 +1,4 @@
+---
+dependencies:
+ - setup_vault_test_plugins
+ - setup_vault_configure_database
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_delete/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_delete/tasks/main.yml
new file mode 100644
index 000000000..5d0a50d2a
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_delete/tasks/main.yml
@@ -0,0 +1,3 @@
+---
+- import_tasks: module_vault_database_role_delete_setup.yml
+- import_tasks: module_vault_database_role_delete_test.yml
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_delete/tasks/module_vault_database_role_delete_setup.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_delete/tasks/module_vault_database_role_delete_setup.yml
new file mode 100644
index 000000000..c6d0e2e90
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_delete/tasks/module_vault_database_role_delete_setup.yml
@@ -0,0 +1,34 @@
+---
+- name: Configuration tasks
+ module_defaults:
+ vault_ci_token_create: "{{ vault_plugins_module_defaults_common }}"
+ vault_ci_enable_engine: "{{ vault_plugins_module_defaults_common }}"
+ vault_ci_read: "{{ vault_plugins_module_defaults_common }}"
+ vault_ci_write: "{{ vault_plugins_module_defaults_common }}"
+ vault_ci_policy_put: "{{ vault_plugins_module_defaults_common }}"
+ block:
+ - name: Create a test non-root token
+ vault_ci_token_create:
+ policies: [policy-database-all]
+ register: user_token_cmd
+
+ - name: Set roles to be deleted
+ ansible.builtin.set_fact:
+ static_role_name: role5
+ dynamic_role_name: dynamic_role
+
+ - name: Create a static role
+ vault_ci_write:
+ path: "database/static-roles/{{ static_role_name }}"
+ data:
+ db_name: "{{ vault_database_connection_name }}"
+ username: "{{ static_role_name }}"
+
+ - name: Create a readonly dynamic role
+ vault_ci_write:
+ path: "database/roles/{{ dynamic_role_name }}"
+ data:
+ db_name: "{{ vault_database_connection_name }}"
+ creation_statements: "{{ vault_database_dynamic_user_sql }}"
+ default_ttl: 1h
+ max_ttl: 24h
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_delete/tasks/module_vault_database_role_delete_test.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_delete/tasks/module_vault_database_role_delete_test.yml
new file mode 100644
index 000000000..e7e869158
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_delete/tasks/module_vault_database_role_delete_test.yml
@@ -0,0 +1,75 @@
+---
+- name: Var block
+ vars:
+ user_token: "{{ user_token_cmd.result.auth.client_token }}"
+ module_defaults:
+ community.hashi_vault.vault_database_role_delete: &defaults
+ url: "{{ vault_test_server_http }}"
+ auth_method: token
+ token: "{{ user_token }}"
+ token_validate: true
+ timeout: 5
+ block:
+ - name: Test database static role delete [check mode]
+ register: db_role_delete
+ check_mode: true
+ community.hashi_vault.vault_database_role_delete:
+ engine_mount_point: DOES NOT MATTER
+ role_name: DOES NOT MATTER
+
+ - name: Check [check mode]
+ ansible.builtin.assert: &success
+ that:
+ - db_role_delete is changed
+
+ - name: Test database role delete (explicit mount - invalid, role_name)
+ register: db_role_delete
+ ignore_errors: true
+ community.hashi_vault.vault_database_role_delete:
+ engine_mount_point: NOT REAL
+ role_name: "{{ static_role_name }}"
+
+ - name: Check (explicit mount - invalid, role_name)
+ ansible.builtin.assert: &failure_bad_mount
+ that:
+ - db_role_delete is failed
+ - db_role_delete.msg is search('Permission Denied')
+
+ - name: Test database role delete (explicit mount, role_name - invalid)
+ register: db_role_delete
+ ignore_errors: true
+ community.hashi_vault.vault_database_role_delete:
+ engine_mount_point: database
+ role_name: NOT REAL
+
+ - name: Check (explicit mount - invalid, role_name)
+ ansible.builtin.assert: &failure_invalid_path
+ that:
+ - db_role_delete is failed
+ - db_role_delete.msg is search('Invalid or missing path')
+
+ - name: Test database role delete (explicit mount, role_name)
+ register: db_role_delete
+ community.hashi_vault.vault_database_role_delete:
+ engine_mount_point: database
+ role_name: "{{ static_role_name }}"
+
+ - name: Check (explicit mount, role_name)
+ ansible.builtin.assert: *success
+
+ - name: Test database role delete (default mount, role_name - invalid)
+ register: db_role_delete
+ ignore_errors: true
+ community.hashi_vault.vault_database_role_delete:
+ role_name: NOT REAL
+
+ - name: Check (explicit mount - invalid, role_name)
+ ansible.builtin.assert: *failure_invalid_path
+
+ - name: Test database role delete (default mount, role_name)
+ register: db_role_delete
+ community.hashi_vault.vault_database_role_delete:
+ role_name: "{{ dynamic_role_name }}"
+
+ - name: Check (default mount, role_name)
+ ansible.builtin.assert: *success
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_read/aliases b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_read/aliases
new file mode 100644
index 000000000..7636a9a65
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_read/aliases
@@ -0,0 +1 @@
+context/target
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_read/meta/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_read/meta/main.yml
new file mode 100644
index 000000000..e867490b0
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_read/meta/main.yml
@@ -0,0 +1,4 @@
+---
+dependencies:
+ - setup_vault_test_plugins
+ - setup_vault_configure_database
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_read/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_read/tasks/main.yml
new file mode 100644
index 000000000..a601b07a3
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_read/tasks/main.yml
@@ -0,0 +1,3 @@
+---
+- import_tasks: module_vault_database_role_read_setup.yml
+- import_tasks: module_vault_database_role_read_test.yml
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_read/tasks/module_vault_database_role_read_setup.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_read/tasks/module_vault_database_role_read_setup.yml
new file mode 100644
index 000000000..cd1b09dc7
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_read/tasks/module_vault_database_role_read_setup.yml
@@ -0,0 +1,9 @@
+---
+- name: Configuration tasks
+ module_defaults:
+ vault_ci_token_create: '{{ vault_plugins_module_defaults_common }}'
+ block:
+ - name: Create a test non-root token
+ vault_ci_token_create:
+ policies: [base-policy-database]
+ register: user_token_cmd
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_read/tasks/module_vault_database_role_read_test.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_read/tasks/module_vault_database_role_read_test.yml
new file mode 100644
index 000000000..1e2d687ad
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_role_read/tasks/module_vault_database_role_read_test.yml
@@ -0,0 +1,126 @@
+---
+- name: Var block
+ vars:
+ user_token: "{{ user_token_cmd.result.auth.client_token }}"
+ module_defaults:
+ community.hashi_vault.vault_database_role_read: &defaults
+ url: "{{ vault_test_server_http }}"
+ auth_method: token
+ token: "{{ user_token }}"
+ token_validate: true
+ timeout: 5
+ block:
+ - name: Test read database role (explicit mount - invalid, role_name) [check mode]
+ register: db_role_read
+ check_mode: true
+ ignore_errors: true
+ community.hashi_vault.vault_database_role_read:
+ engine_mount_point: NOT REAL
+ role_name: readonly
+
+ - name: Check (explicit mount - invalid) [check mode]
+ ansible.builtin.assert: &failure_bad_mount
+ that:
+ - db_role_read is failed
+ - db_role_read.msg is search('Permission Denied')
+
+ - name: Test read database role (explicit mount, role_name - invalid) [check mode]
+ register: db_role_read
+ check_mode: true
+ ignore_errors: true
+ community.hashi_vault.vault_database_role_read:
+ engine_mount_point: database
+ role_name: NOT REAL
+
+ - name: Check (explicit mount - invalid) [check mode]
+ ansible.builtin.assert: &failure_invalid_path
+ that:
+ - db_role_read is failed
+ - db_role_read.msg is search('Invalid or missing path')
+
+ - name: Test read database role (explicit mount, role_name) [check mode]
+ register: db_role_read
+ check_mode: true
+ community.hashi_vault.vault_database_role_read:
+ engine_mount_point: database
+ role_name: readonly
+
+ - name: Check (explicit mount, role_name) [check mode]
+ ansible.builtin.assert: &success
+ that:
+ - db_role_read is defined
+ - "'data' in db_role_read"
+ - "'raw' in db_role_read"
+ - "'creation_statements' in db_role_read['data']"
+ - "'credential_type' in db_role_read['data']"
+ - "'db_name' in db_role_read['data']"
+ - "'default_ttl' in db_role_read['data']"
+ - "'max_ttl' in db_role_read['data']"
+ - "'renew_statements' in db_role_read['data']"
+ - "'revocation_statements' in db_role_read['data']"
+ - "'rollback_statements' in db_role_read['data']"
+
+ - name: Test read database role (explicit mount - invalid, role_name)
+ register: db_role_read
+ ignore_errors: true
+ community.hashi_vault.vault_database_role_read:
+ engine_mount_point: NOT REAL
+ role_name: readonly
+
+ - name: Check (explicit mount - invalid)
+ ansible.builtin.assert: *failure_bad_mount
+
+ - name: Test read database role (explicit mount, role_name - invalid)
+ register: db_role_read
+ ignore_errors: true
+ community.hashi_vault.vault_database_role_read:
+ engine_mount_point: database
+ role_name: NOT REAL
+
+ - name: Check (explicit mount - invalid)
+ ansible.builtin.assert: *failure_invalid_path
+
+ - name: Test read database role (explicit mount, role_name)
+ register: db_role_read
+ community.hashi_vault.vault_database_role_read:
+ engine_mount_point: database
+ role_name: readonly
+
+ - name: Check (explicit mount, role_name)
+ ansible.builtin.assert: *success
+
+ - name: Test read database role (default mount, role_name - invalid) [check mode]
+ register: db_role_read
+ check_mode: true
+ ignore_errors: true
+ community.hashi_vault.vault_database_role_read:
+ role_name: NOT REAL
+
+ - name: Check (default mount - invalid) [check mode]
+ ansible.builtin.assert: *failure_invalid_path
+
+ - name: Test read database role (default mount, role_name) [check mode]
+ register: db_role_read
+ check_mode: true
+ community.hashi_vault.vault_database_role_read:
+ role_name: readonly
+
+ - name: Check (default mount, role_name) [check mode]
+ ansible.builtin.assert: *success
+
+ - name: Test read database role (default mount, role_name - invalid)
+ register: db_role_read
+ ignore_errors: true
+ community.hashi_vault.vault_database_role_read:
+ role_name: NOT REAL
+
+ - name: Check (default mount - invalid)
+ ansible.builtin.assert: *failure_invalid_path
+
+ - name: Test read database role (default mount, role_name)
+ register: db_role_read
+ community.hashi_vault.vault_database_role_read:
+ role_name: readonly
+
+ - name: Check (default mount, role_name)
+ ansible.builtin.assert: *success
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_roles_list/aliases b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_roles_list/aliases
new file mode 100644
index 000000000..7636a9a65
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_roles_list/aliases
@@ -0,0 +1 @@
+context/target
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_roles_list/meta/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_roles_list/meta/main.yml
new file mode 100644
index 000000000..e867490b0
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_roles_list/meta/main.yml
@@ -0,0 +1,4 @@
+---
+dependencies:
+ - setup_vault_test_plugins
+ - setup_vault_configure_database
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_roles_list/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_roles_list/tasks/main.yml
new file mode 100644
index 000000000..420aa1b76
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_roles_list/tasks/main.yml
@@ -0,0 +1,3 @@
+---
+- import_tasks: module_vault_database_roles_list_setup.yml
+- import_tasks: module_vault_database_roles_list_test.yml
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_roles_list/tasks/module_vault_database_roles_list_setup.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_roles_list/tasks/module_vault_database_roles_list_setup.yml
new file mode 100644
index 000000000..cd1b09dc7
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_roles_list/tasks/module_vault_database_roles_list_setup.yml
@@ -0,0 +1,9 @@
+---
+- name: Configuration tasks
+ module_defaults:
+ vault_ci_token_create: '{{ vault_plugins_module_defaults_common }}'
+ block:
+ - name: Create a test non-root token
+ vault_ci_token_create:
+ policies: [base-policy-database]
+ register: user_token_cmd
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_roles_list/tasks/module_vault_database_roles_list_test.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_roles_list/tasks/module_vault_database_roles_list_test.yml
new file mode 100644
index 000000000..b49c06ade
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_roles_list/tasks/module_vault_database_roles_list_test.yml
@@ -0,0 +1,65 @@
+---
+- name: Var block
+ vars:
+ user_token: "{{ user_token_cmd.result.auth.client_token }}"
+ expected_role: readonly
+ module_defaults:
+ community.hashi_vault.vault_database_roles_list: &defaults
+ url: "{{ vault_test_server_http }}"
+ auth_method: token
+ token: "{{ user_token }}"
+ token_validate: true
+ timeout: 5
+ block:
+ - name: Test list database dynamic roles (explicit mount - invalid) [check mode]
+ register: db_roles_list
+ check_mode: true
+ ignore_errors: true
+ community.hashi_vault.vault_database_roles_list:
+ engine_mount_point: NOT REAL
+
+ - name: Check (explicit mount - invalid) [check mode]
+ ansible.builtin.assert: &failure_bad_mount
+ that:
+ - db_roles_list is failed
+ - db_roles_list.msg is search('Permission Denied')
+
+ - name: Test list database dynamic roles (explicit mount) [check mode]
+ register: db_roles_list
+ check_mode: true
+ community.hashi_vault.vault_database_roles_list:
+ engine_mount_point: database
+
+ - name: Check (explicit mount) [check mode]
+ ansible.builtin.assert: &success
+ that:
+ - db_roles_list is defined
+ - "'data' in db_roles_list"
+ - "'raw' in db_roles_list"
+ - "'keys' in db_roles_list['data']"
+ - "'roles' in db_roles_list"
+ - db_roles_list.roles == db_roles_list.data['keys']
+ - expected_role in db_roles_list.roles
+
+ - name: Test list database dynamic roles (explicit mount)
+ register: db_roles_list
+ community.hashi_vault.vault_database_roles_list:
+ engine_mount_point: database
+
+ - name: Check (explicit mount)
+ ansible.builtin.assert: *success
+
+ - name: Test list database dynamic roles (default mount) [check mode]
+ register: db_roles_list
+ check_mode: true
+ community.hashi_vault.vault_database_roles_list:
+
+ - name: Check (default mount) [check mode]
+ ansible.builtin.assert: *success
+
+ - name: Test list database dynamic roles (default mount)
+ register: db_roles_list
+ community.hashi_vault.vault_database_roles_list:
+
+ - name: Check (default mount)
+ ansible.builtin.assert: *success
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/aliases b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/aliases
new file mode 100644
index 000000000..7636a9a65
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/aliases
@@ -0,0 +1 @@
+context/target
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/meta/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/meta/main.yml
new file mode 100644
index 000000000..e867490b0
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/meta/main.yml
@@ -0,0 +1,4 @@
+---
+dependencies:
+ - setup_vault_test_plugins
+ - setup_vault_configure_database
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/tasks/main.yml
new file mode 100644
index 000000000..7b05ed1af
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/tasks/main.yml
@@ -0,0 +1,10 @@
+---
+- name: Get python minor version
+ ansible.builtin.set_fact:
+ python_interpreter_minor: "{{ ansible_python_version | split('.') }}"
+
+- when: python_interpreter_minor[1] | int > 6
+ block:
+ - import_tasks: module_vault_db_rotate_root_creds_setup.yml
+ - import_tasks: module_vault_db_rotate_root_creds_test.yml
+ - import_tasks: module_vault_db_rotate_root_creds_cleanup.yml
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/tasks/module_vault_db_rotate_root_creds_cleanup.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/tasks/module_vault_db_rotate_root_creds_cleanup.yml
new file mode 100644
index 000000000..e360aee6a
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/tasks/module_vault_db_rotate_root_creds_cleanup.yml
@@ -0,0 +1,12 @@
+---
+- name: Drop users in PostgreSQL
+ community.postgresql.postgresql_user:
+ db: "{{ vault_postgres_db }}"
+ name: "{{ item.username }}"
+ password: "{{ item.password }}"
+ login_user: "{{ vault_postgres_user }}"
+ login_password: "{{ vault_postgres_password }}"
+ port: "{{ vault_postgres_port }}"
+ login_host: "{{ vault_postgres_host }}"
+ state: absent
+ loop: "{{ users_to_create }}"
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/tasks/module_vault_db_rotate_root_creds_setup.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/tasks/module_vault_db_rotate_root_creds_setup.yml
new file mode 100644
index 000000000..7f1eaee87
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/tasks/module_vault_db_rotate_root_creds_setup.yml
@@ -0,0 +1,46 @@
+---
+- name: Configuration tasks
+ vars:
+ users_to_create:
+ - { "username": "usr_to_rotate1", "password": "SuperSecret" }
+ - { "username": "usr_to_rotate2", "password": "SuperSecret" }
+ module_defaults:
+ vault_ci_token_create: "{{ vault_plugins_module_defaults_common }}"
+ vault_ci_enable_engine: "{{ vault_plugins_module_defaults_common }}"
+ vault_ci_read: "{{ vault_plugins_module_defaults_common }}"
+ vault_ci_write: "{{ vault_plugins_module_defaults_common }}"
+ vault_ci_policy_put: "{{ vault_plugins_module_defaults_common }}"
+ block:
+ - name: Create a test non-root token
+ vault_ci_token_create:
+ policies: [policy-database-all]
+ register: user_token_cmd
+
+ - name: Set facts
+ ansible.builtin.set_fact:
+ users_to_create:
+ - { "username": "usr_to_rotate1", "password": "SuperSecret" }
+ - { "username": "usr_to_rotate2", "password": "SuperSecret" }
+
+ - name: Create a new user in PostgreSQL
+ community.postgresql.postgresql_user:
+ db: "{{ vault_postgres_db }}"
+ name: "{{ item.username }}"
+ password: "{{ item.password }}"
+ login_user: "{{ vault_postgres_user }}"
+ login_password: "{{ vault_postgres_password }}"
+ port: "{{ vault_postgres_port }}"
+ login_host: "{{ vault_postgres_host }}"
+ role_attr_flags: SUPERUSER
+ loop: "{{ users_to_create }}"
+
+ - name: Create the Database Connection
+ vault_ci_write:
+ path: "database/config/{{ item.username }}"
+ data:
+ plugin_name: "{{ vault_database_plugin_name }}"
+ connection_url: "{{ vault_database_connection_url }}"
+ allowed_roles: "*"
+ username: "{{ item.username }}"
+ password: "{{ item.password }}"
+ loop: "{{ users_to_create }}"
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/tasks/module_vault_db_rotate_root_creds_test.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/tasks/module_vault_db_rotate_root_creds_test.yml
new file mode 100644
index 000000000..50498e824
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_rotate_root_creds/tasks/module_vault_db_rotate_root_creds_test.yml
@@ -0,0 +1,132 @@
+---
+- name: Var block
+ vars:
+ user_token: "{{ user_token_cmd.result.auth.client_token }}"
+ module_defaults:
+ vault_ci_read: "{{ vault_plugins_module_defaults_common }}"
+ community.hashi_vault.vault_database_rotate_root_credentials: &defaults
+ url: "{{ vault_test_server_http }}"
+ auth_method: token
+ token: "{{ user_token }}"
+ token_validate: true
+ timeout: 5
+ block:
+ - name: Test rotate root credentials [check mode]
+ register: rotate_credentials
+ check_mode: true
+ community.hashi_vault.vault_database_rotate_root_credentials:
+ engine_mount_point: DOES NOT MATTER
+ connection_name: DOES NOT MATTER
+
+ - name: Check [check mode]
+ ansible.builtin.assert: &success
+ that:
+ - rotate_credentials is changed
+
+ - name: Test rotate root credentials (explicit mount - invalid, connection_name)
+ register: rotate_credentials
+ ignore_errors: true
+ community.hashi_vault.vault_database_rotate_root_credentials:
+ engine_mount_point: NOT REAL
+ connection_name: "{{ users_to_create[0].username }}"
+
+ - name: Check (explicit mount - invalid, connection_name)
+ ansible.builtin.assert: &failure_bad_mount
+ that:
+ - rotate_credentials is failed
+ - rotate_credentials.msg is search('Permission Denied')
+
+ - name: Test rotate root credentials (explicit mount, connection_name - invalid)
+ register: rotate_credentials
+ ignore_errors: true
+ community.hashi_vault.vault_database_rotate_root_credentials:
+ engine_mount_point: database
+ connection_name: NOT REAL
+
+ - name: Check (explicit mount, connection_name - invalid)
+ ansible.builtin.assert: &failure_invalid_path
+ that:
+ - rotate_credentials is failed
+ - rotate_credentials.msg is search('Invalid or missing path')
+
+ - name: Login before root credential rotation with user {{ users_to_create[0].username }}
+ community.postgresql.postgresql_ping:
+ db: "{{ vault_postgres_db }}"
+ login_user: "{{ users_to_create[0].username }}"
+ login_password: "{{ users_to_create[0].password }}"
+ port: "{{ vault_postgres_port }}"
+ login_host: "{{ vault_postgres_host }}"
+ register: login_result_before
+
+ - name: Check db login before root credential rotation
+ ansible.builtin.assert: &login_before
+ that:
+ - login_result_before is defined
+ - login_result_before.is_available
+ - login_result_before.conn_err_msg | length == 0
+
+ - name: Test rotate root credentials (explicit_mount, connection_name)
+ register: rotate_credentials
+ community.hashi_vault.vault_database_rotate_root_credentials:
+ engine_mount_point: database
+ connection_name: "{{ users_to_create[0].username }}"
+
+ - name: Check (explicit_mount, connection_name)
+ ansible.builtin.assert: *success
+
+ - name: Try to login with the old password for user {{ users_to_create[0].username }}
+ community.postgresql.postgresql_ping:
+ db: "{{ vault_postgres_db }}"
+ login_user: "{{ users_to_create[0].username }}"
+ login_password: "{{ users_to_create[0].password }}"
+ port: "{{ vault_postgres_port }}"
+ login_host: "{{ vault_postgres_host }}"
+ register: login_result_after
+
+ - name: Ensure that password was rotated
+ ansible.builtin.assert: &login_failed
+ that:
+ - login_result_after is defined
+ - not login_result_after.is_available
+ - login_result_after.conn_err_msg | length > 0
+
+ - name: Test rotate root credentials (default mount, connection_name - invalid)
+ register: rotate_credentials
+ ignore_errors: true
+ community.hashi_vault.vault_database_rotate_root_credentials:
+ connection_name: NOT REAL
+
+ - name: Check (explicit mount, connection_name - invalid)
+ ansible.builtin.assert: *failure_invalid_path
+
+ - name: Login before root credential rotation with user {{ users_to_create[1].username }}
+ community.postgresql.postgresql_ping:
+ db: "{{ vault_postgres_db }}"
+ login_user: "{{ users_to_create[1].username }}"
+ login_password: "{{ users_to_create[1].password }}"
+ port: "{{ vault_postgres_port }}"
+ login_host: "{{ vault_postgres_host }}"
+ register: login_result_before
+
+ - name: Check db login before root credential rotation
+ ansible.builtin.assert: *login_before
+
+ - name: Test rotate root credentials (default, connection_name)
+ register: rotate_credentials
+ community.hashi_vault.vault_database_rotate_root_credentials:
+ connection_name: "{{ users_to_create[1].username }}"
+
+ - name: Check (explicit_mount, connection_name)
+ ansible.builtin.assert: *success
+
+ - name: Try to login with the old password for user {{ users_to_create[1].username }}
+ community.postgresql.postgresql_ping:
+ db: "{{ vault_postgres_db }}"
+ login_user: "{{ users_to_create[1].username }}"
+ login_password: "{{ users_to_create[1].password }}"
+ port: "{{ vault_postgres_port }}"
+ login_host: "{{ vault_postgres_host }}"
+ register: login_result_after
+
+ - name: Ensure that password was rotated
+ ansible.builtin.assert: *login_failed
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_create/aliases b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_create/aliases
new file mode 100644
index 000000000..7636a9a65
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_create/aliases
@@ -0,0 +1 @@
+context/target
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_create/meta/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_create/meta/main.yml
new file mode 100644
index 000000000..e867490b0
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_create/meta/main.yml
@@ -0,0 +1,4 @@
+---
+dependencies:
+ - setup_vault_test_plugins
+ - setup_vault_configure_database
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_create/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_create/tasks/main.yml
new file mode 100644
index 000000000..7a49731f3
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_create/tasks/main.yml
@@ -0,0 +1,3 @@
+---
+- import_tasks: module_vault_database_static_role_create_setup.yml
+- import_tasks: module_vault_database_static_role_create_test.yml
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_create/tasks/module_vault_database_static_role_create_setup.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_create/tasks/module_vault_database_static_role_create_setup.yml
new file mode 100644
index 000000000..7abb3ceb2
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_create/tasks/module_vault_database_static_role_create_setup.yml
@@ -0,0 +1,13 @@
+---
+- name: Configuration tasks
+ module_defaults:
+ vault_ci_token_create: '{{ vault_plugins_module_defaults_common }}'
+ vault_ci_enable_engine: '{{ vault_plugins_module_defaults_common }}'
+ vault_ci_read: '{{ vault_plugins_module_defaults_common }}'
+ vault_ci_write: '{{ vault_plugins_module_defaults_common }}'
+ vault_ci_policy_put: '{{ vault_plugins_module_defaults_common }}'
+ block:
+ - name: Create a test non-root token
+ vault_ci_token_create:
+ policies: [policy-database-all]
+ register: user_token_cmd
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_create/tasks/module_vault_database_static_role_create_test.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_create/tasks/module_vault_database_static_role_create_test.yml
new file mode 100644
index 000000000..07bc1ac08
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_create/tasks/module_vault_database_static_role_create_test.yml
@@ -0,0 +1,130 @@
+---
+- name: Var block
+ vars:
+ user_token: "{{ user_token_cmd.result.auth.client_token }}"
+ rotation_statements:
+ - 'ALTER USER {{ "{{name}}" }} WITH PASSWORD {{ ''{{password}}'' }};'
+ module_defaults:
+ community.hashi_vault.vault_database_static_role_create: &defaults
+ url: "{{ vault_test_server_http }}"
+ auth_method: token
+ token: "{{ user_token }}"
+ token_validate: true
+ timeout: 5
+ block:
+ - name: Test database create static role [check mode]
+ register: db_create_static_role
+ check_mode: true
+ community.hashi_vault.vault_database_static_role_create:
+ engine_mount_point: Does Not Matter
+ connection_name: Does Not Matter
+ rotation_statements:
+ - Does Not Matter
+ role_name: Does Not Matter
+ db_username: Does Not Matter
+
+ - name: Check [check mode]
+ ansible.builtin.assert: &success
+ that:
+ - db_create_static_role is changed
+
+ - name: Test database create static role (explicit mount point - invalid, connection_name, db_username)
+ register: db_create_static_role
+ ignore_errors: true
+ community.hashi_vault.vault_database_static_role_create:
+ engine_mount_point: NOT REAL
+ connection_name: "{{ vault_database_connection_name }}"
+ rotation_statements:
+ - "{{ rotation_statements }}"
+ db_username: role3
+ role_name: role3
+
+ - name: Check (explicit mount point - invalid, connection_name)
+ ansible.builtin.assert: &failure_bad_mount
+ that:
+ - db_create_static_role is failed
+ - db_create_static_role.msg is search('Permission Denied')
+
+ - name: Test database create static role (explicit mount point, connection_name - invalid, db_username)
+ register: db_create_static_role
+ ignore_errors: true
+ community.hashi_vault.vault_database_static_role_create:
+ engine_mount_point: database
+ connection_name: NOT REAL
+ rotation_statements:
+ - "{{ rotation_statements }}"
+ db_username: role3
+ role_name: role3
+
+ # Note that this statement will be successful and a dynamic role will be added, although the connection name is not existing
+ - name: Check (explicit mount point, connection_name - invalid)
+ ansible.builtin.assert: *success
+
+ - name: Test database create static role (explicit mount point, connection_name, db_username - invalid)
+ register: db_create_static_role
+ ignore_errors: true
+ community.hashi_vault.vault_database_static_role_create:
+ engine_mount_point: database
+ connection_name: "{{ vault_database_connection_name }}"
+ rotation_statements:
+ - "{{ rotation_statements }}"
+ db_username: NOT REAL
+ role_name: role3
+
+ - name: Check (explicit mount point, connection_name, db_username - invalid)
+ ansible.builtin.assert: &failure_invalid_request
+ that:
+ - db_create_static_role is failed
+ - db_create_static_role.msg is search('Cannot update static role')
+
+ - name: Test database create static role (explicit mount point, connection_name, db_username)
+ register: db_create_static_role
+ community.hashi_vault.vault_database_static_role_create:
+ engine_mount_point: database
+ connection_name: "{{ vault_database_connection_name }}"
+ rotation_statements:
+ - "{{ rotation_statements }}"
+ db_username: role3
+ role_name: role3
+
+ - name: Check (explicit mount point, connection_name, db_username)
+ ansible.builtin.assert: *success
+
+ - name: Test database create static role (default mount point, connection_name - invalid, db_username)
+ register: db_create_static_role
+ ignore_errors: true
+ community.hashi_vault.vault_database_static_role_create:
+ connection_name: NOT REAL
+ rotation_statements:
+ - "{{ rotation_statements }}"
+ db_username: role3
+ role_name: role3
+
+ # Note that this statement will be successful and a dynamic role will be added, although the connection name is not existing
+ - name: Check (default mount point, connection_name - invalid, db_username)
+ ansible.builtin.assert: *success
+
+ - name: Test database create static role (default mount point, connection_name, db_username - invalid)
+ register: db_create_static_role
+ ignore_errors: true
+ community.hashi_vault.vault_database_static_role_create:
+ connection_name: NOT REAL
+ rotation_statements:
+ - "{{ rotation_statements }}"
+ db_username: NOT REAL
+ role_name: role3
+
+ - name: Check (default mount point, connection_name, db_username - invalid)
+ ansible.builtin.assert: *failure_invalid_request
+
+ - name: Test database create static role (default mount point, connection_name, db_username)
+ register: db_create_static_role
+ community.hashi_vault.vault_database_static_role_create:
+ connection_name: "{{ vault_database_connection_name }}"
+ rotation_statements:
+ - "{{ rotation_statements }}"
+ role_name: role3
+ db_username: role3
+
+ - name: Check (default mount point, connection_name, db_username)
+ ansible.builtin.assert: *success
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_get_creds/aliases b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_get_creds/aliases
new file mode 100644
index 000000000..7636a9a65
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_get_creds/aliases
@@ -0,0 +1 @@
+context/target
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_get_creds/meta/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_get_creds/meta/main.yml
new file mode 100644
index 000000000..e867490b0
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_get_creds/meta/main.yml
@@ -0,0 +1,4 @@
+---
+dependencies:
+ - setup_vault_test_plugins
+ - setup_vault_configure_database
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_get_creds/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_get_creds/tasks/main.yml
new file mode 100644
index 000000000..3116a06a3
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_get_creds/tasks/main.yml
@@ -0,0 +1,3 @@
+---
+- import_tasks: module_vault_database_static_role_get_credentials_setup.yml
+- import_tasks: module_vault_database_static_role_get_credentials_test.yml
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_get_creds/tasks/module_vault_database_static_role_get_credentials_setup.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_get_creds/tasks/module_vault_database_static_role_get_credentials_setup.yml
new file mode 100644
index 000000000..c843258fa
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_get_creds/tasks/module_vault_database_static_role_get_credentials_setup.yml
@@ -0,0 +1,13 @@
+---
+- name: Configuration tasks
+ module_defaults:
+ vault_ci_token_create: '{{ vault_plugins_module_defaults_common }}'
+ vault_ci_enable_engine: '{{ vault_plugins_module_defaults_common }}'
+ vault_ci_read: '{{ vault_plugins_module_defaults_common }}'
+ vault_ci_write: '{{ vault_plugins_module_defaults_common }}'
+ vault_ci_policy_put: '{{ vault_plugins_module_defaults_common }}'
+ block:
+ - name: Create a test non-root token
+ vault_ci_token_create:
+ policies: [base-policy-database]
+ register: user_token_cmd
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_get_creds/tasks/module_vault_database_static_role_get_credentials_test.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_get_creds/tasks/module_vault_database_static_role_get_credentials_test.yml
new file mode 100644
index 000000000..7ee1bd7bc
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_get_creds/tasks/module_vault_database_static_role_get_credentials_test.yml
@@ -0,0 +1,114 @@
+---
+- name: Var block
+ vars:
+ user_token: "{{ user_token_cmd.result.auth.client_token }}"
+ module_defaults:
+ community.hashi_vault.vault_database_static_role_get_credentials: &defaults
+ url: "{{ vault_test_server_http }}"
+ auth_method: token
+ token: "{{ user_token }}"
+ token_validate: true
+ timeout: 5
+ block:
+ - name: Test database get credentials of static role (explicit mount - invalid, role_name) [check mode]
+ register: db_static_role
+ check_mode: true
+ ignore_errors: true
+ community.hashi_vault.vault_database_static_role_get_credentials:
+ engine_mount_point: NOT REAL
+ role_name: role1
+
+ - name: Check (explicit mount - invalid, role_name) [check_mode]
+ ansible.builtin.assert: &failure_bad_mount
+ that:
+ - db_static_role is failed
+ - db_static_role.msg is search('Permission Denied')
+
+ - name: Test database get credentials of static role (explicit mount, role_name - invalid) [check mode]
+ register: db_static_role
+ check_mode: true
+ ignore_errors: true
+ community.hashi_vault.vault_database_static_role_get_credentials:
+ engine_mount_point: database
+ role_name: NOT REAL
+
+ - name: Check (explicit mount, role_name - invalid) [check_mode]
+ ansible.builtin.assert: &failure_invalid_path
+ that:
+ - db_static_role is failed
+ - db_static_role.msg is search('Invalid or missing path')
+
+ - name: Test database get credentials of static role (explicit mount, role_name) [check mode]
+ register: db_static_role
+ check_mode: true
+ community.hashi_vault.vault_database_static_role_get_credentials:
+ engine_mount_point: database
+ role_name: role1
+
+ - name: Check (explicit mount, role_name) [check_mode]
+ ansible.builtin.assert: &success
+ that:
+ - db_static_role is defined
+ - "'data' in db_static_role"
+ - "'password' in db_static_role['data']"
+ - "'rotation_period' in db_static_role['data']"
+ - "'ttl' in db_static_role['data']"
+ - "'last_vault_rotation' in db_static_role['data']"
+ - "'raw' in db_static_role"
+
+ - name: Test database get credentials of static role (explicit mount - invalid, role_name)
+ register: db_static_role
+ ignore_errors: true
+ community.hashi_vault.vault_database_static_role_get_credentials:
+ engine_mount_point: NOT REAL
+ role_name: role1
+
+ - name: Check (explicit mount - invalid, role_name)
+ ansible.builtin.assert: *failure_bad_mount
+
+ - name: Test database get credentials of static role (explicit mount, role_name - invalid)
+ register: db_static_role
+ ignore_errors: true
+ community.hashi_vault.vault_database_static_role_get_credentials:
+ engine_mount_point: database
+ role_name: NOT REAL
+
+ - name: Check (explicit mount, role_name - invalid)
+ ansible.builtin.assert: *failure_invalid_path
+
+ - name: Test database get credentials of static role (explicit mount, role_name)
+ register: db_static_role
+ community.hashi_vault.vault_database_static_role_get_credentials:
+ engine_mount_point: database
+ role_name: role1
+
+ - name: Check (explicit mount, role_name)
+ ansible.builtin.assert: *success
+
+ - name: Test database get credentials of static role (default mount, role_name - invalid) [check mode]
+ register: db_static_role
+ check_mode: true
+ ignore_errors: true
+ community.hashi_vault.vault_database_static_role_get_credentials:
+ role_name: NOT REAL
+
+ - name: Check (default mount, role_name - invalid) [check mode]
+ ansible.builtin.assert: *failure_invalid_path
+
+ - name: Test database get credentials of static role (default mount, role_name - invalid)
+ register: db_static_role
+ ignore_errors: true
+ community.hashi_vault.vault_database_static_role_get_credentials:
+ role_name: NOT REAL
+
+ - name: Check (default mount, role_name - invalid)
+ ansible.builtin.assert: *failure_invalid_path
+
+ - name: Test database get credentials of static role (default mount, role_name)
+ register: db_static_role
+ ignore_errors: true
+ community.hashi_vault.vault_database_static_role_get_credentials:
+ role_name: role1
+
+ - name: Check (default mount, role_name)
+ ansible.builtin.assert: *success
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_read/aliases b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_read/aliases
new file mode 100644
index 000000000..7636a9a65
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_read/aliases
@@ -0,0 +1 @@
+context/target
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_read/meta/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_read/meta/main.yml
new file mode 100644
index 000000000..e867490b0
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_read/meta/main.yml
@@ -0,0 +1,4 @@
+---
+dependencies:
+ - setup_vault_test_plugins
+ - setup_vault_configure_database
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_read/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_read/tasks/main.yml
new file mode 100644
index 000000000..44e2405ee
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_read/tasks/main.yml
@@ -0,0 +1,3 @@
+---
+- import_tasks: module_vault_database_static_role_read_setup.yml
+- import_tasks: module_vault_database_static_role_read_test.yml
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_read/tasks/module_vault_database_static_role_read_setup.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_read/tasks/module_vault_database_static_role_read_setup.yml
new file mode 100644
index 000000000..cd1b09dc7
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_read/tasks/module_vault_database_static_role_read_setup.yml
@@ -0,0 +1,9 @@
+---
+- name: Configuration tasks
+ module_defaults:
+ vault_ci_token_create: '{{ vault_plugins_module_defaults_common }}'
+ block:
+ - name: Create a test non-root token
+ vault_ci_token_create:
+ policies: [base-policy-database]
+ register: user_token_cmd
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_read/tasks/module_vault_database_static_role_read_test.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_read/tasks/module_vault_database_static_role_read_test.yml
new file mode 100644
index 000000000..c8cc77423
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_read/tasks/module_vault_database_static_role_read_test.yml
@@ -0,0 +1,123 @@
+---
+- name: Var block
+ vars:
+ user_token: "{{ user_token_cmd.result.auth.client_token }}"
+ module_defaults:
+ community.hashi_vault.vault_database_static_role_read: &defaults
+ url: "{{ vault_test_server_http }}"
+ auth_method: token
+ token: "{{ user_token }}"
+ token_validate: true
+ timeout: 5
+ block:
+ - name: Test read database role (explicit mount - invalid, role_name) [check mode]
+ register: db_static_role_read
+ check_mode: true
+ ignore_errors: true
+ community.hashi_vault.vault_database_static_role_read:
+ engine_mount_point: NOT REAL
+ role_name: role2
+
+ - name: Check (explicit mount - invalid) [check mode]
+ ansible.builtin.assert: &failure_bad_mount
+ that:
+ - db_static_role_read is failed
+ - db_static_role_read.msg is search('Permission Denied')
+
+ - name: Test read database role (explicit mount, role_name - invalid) [check mode]
+ register: db_static_role_read
+ check_mode: true
+ ignore_errors: true
+ community.hashi_vault.vault_database_static_role_read:
+ engine_mount_point: database
+ role_name: NOT REAL
+
+ - name: Check (explicit mount - invalid) [check mode]
+ ansible.builtin.assert: &failure_invalid_path
+ that:
+ - db_static_role_read is failed
+ - db_static_role_read.msg is search('Invalid or missing path')
+
+ - name: Test read database role (explicit mount, role_name) [check mode]
+ register: db_static_role_read
+ check_mode: true
+ community.hashi_vault.vault_database_static_role_read:
+ engine_mount_point: database
+ role_name: role2
+
+ - name: Check (explicit mount, role_name) [check mode]
+ ansible.builtin.assert: &success
+ that:
+ - db_static_role_read is defined
+ - "'data' in db_static_role_read"
+ - "'raw' in db_static_role_read"
+ - "'credential_type' in db_static_role_read['data']"
+ - "'db_name' in db_static_role_read['data']"
+ - "'last_vault_rotation' in db_static_role_read['data']"
+ - "'rotation_period' in db_static_role_read['data']"
+ - "'rotation_statements' in db_static_role_read['data']"
+
+ - name: Test read database role (explicit mount - invalid, role_name)
+ register: db_static_role_read
+ ignore_errors: true
+ community.hashi_vault.vault_database_static_role_read:
+ engine_mount_point: NOT REAL
+ role_name: role2
+
+ - name: Check (explicit mount - invalid)
+ ansible.builtin.assert: *failure_bad_mount
+
+ - name: Test read database role (explicit mount, role_name - invalid)
+ register: db_static_role_read
+ ignore_errors: true
+ community.hashi_vault.vault_database_static_role_read:
+ engine_mount_point: database
+ role_name: NOT REAL
+
+ - name: Check (explicit mount - invalid)
+ ansible.builtin.assert: *failure_invalid_path
+
+ - name: Test read database role (explicit mount, role_name)
+ register: db_static_role_read
+ community.hashi_vault.vault_database_static_role_read:
+ engine_mount_point: database
+ role_name: role2
+
+ - name: Check (explicit mount, role_name)
+ ansible.builtin.assert: *success
+
+ - name: Test read database role (default mount, role_name - invalid) [check mode]
+ register: db_static_role_read
+ check_mode: true
+ ignore_errors: true
+ community.hashi_vault.vault_database_static_role_read:
+ role_name: NOT REAL
+
+ - name: Check (default mount - invalid) [check mode]
+ ansible.builtin.assert: *failure_invalid_path
+
+ - name: Test read database role (default mount, role_name) [check mode]
+ register: db_static_role_read
+ check_mode: true
+ community.hashi_vault.vault_database_static_role_read:
+ role_name: role2
+
+ - name: Check (default mount, role_name) [check mode]
+ ansible.builtin.assert: *success
+
+ - name: Test read database role (default mount, role_name - invalid)
+ register: db_static_role_read
+ ignore_errors: true
+ community.hashi_vault.vault_database_static_role_read:
+ role_name: NOT REAL
+
+ - name: Check (default mount - invalid)
+ ansible.builtin.assert: *failure_invalid_path
+
+ - name: Test read database role (default mount, role_name)
+ register: db_static_role_read
+ community.hashi_vault.vault_database_static_role_read:
+ role_name: role2
+
+ - name: Check (default mount, role_name)
+ ansible.builtin.assert: *success
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_rotate_creds/aliases b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_rotate_creds/aliases
new file mode 100644
index 000000000..7636a9a65
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_rotate_creds/aliases
@@ -0,0 +1 @@
+context/target
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_rotate_creds/meta/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_rotate_creds/meta/main.yml
new file mode 100644
index 000000000..e867490b0
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_rotate_creds/meta/main.yml
@@ -0,0 +1,4 @@
+---
+dependencies:
+ - setup_vault_test_plugins
+ - setup_vault_configure_database
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_rotate_creds/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_rotate_creds/tasks/main.yml
new file mode 100644
index 000000000..b1c2e1029
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_rotate_creds/tasks/main.yml
@@ -0,0 +1,8 @@
+---
+- ansible.builtin.set_fact:
+ python_interpreter_minor: "{{ ansible_python_version | split('.') }}"
+
+- when: python_interpreter_minor[1] | int > 6
+ block:
+ - import_tasks: module_vault_db_static_role_rotate_creds_setup.yml
+ - import_tasks: module_vault_db_static_role_rotate_creds_test.yml
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_rotate_creds/tasks/module_vault_db_static_role_rotate_creds_setup.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_rotate_creds/tasks/module_vault_db_static_role_rotate_creds_setup.yml
new file mode 100644
index 000000000..3e650be6b
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_rotate_creds/tasks/module_vault_db_static_role_rotate_creds_setup.yml
@@ -0,0 +1,23 @@
+---
+- name: Configuration tasks
+ module_defaults:
+ vault_ci_token_create: "{{ vault_plugins_module_defaults_common }}"
+ vault_ci_enable_engine: "{{ vault_plugins_module_defaults_common }}"
+ vault_ci_read: "{{ vault_plugins_module_defaults_common }}"
+ vault_ci_write: "{{ vault_plugins_module_defaults_common }}"
+ vault_ci_policy_put: "{{ vault_plugins_module_defaults_common }}"
+ block:
+ - name: Create a test non-root token
+ vault_ci_token_create:
+ policies: [policy-database-all]
+ register: user_token_cmd
+
+ - name: Set roles data
+ ansible.builtin.set_fact:
+ roles_to_rotate: ["role4", "role5"]
+
+ - name: Read users
+ vault_ci_read:
+ path: "database/static-creds/{{ item }}"
+ register: roles_data_before
+ loop: "{{ roles_to_rotate }}"
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_rotate_creds/tasks/module_vault_db_static_role_rotate_creds_test.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_rotate_creds/tasks/module_vault_db_static_role_rotate_creds_test.yml
new file mode 100644
index 000000000..caee65e9c
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_role_rotate_creds/tasks/module_vault_db_static_role_rotate_creds_test.yml
@@ -0,0 +1,120 @@
+---
+- name: Var block
+ vars:
+ user_token: "{{ user_token_cmd.result.auth.client_token }}"
+ module_defaults:
+ vault_ci_read: "{{ vault_plugins_module_defaults_common }}"
+ community.hashi_vault.vault_database_static_role_rotate_credentials:
+ &defaults
+ url: "{{ vault_test_server_http }}"
+ auth_method: token
+ token: "{{ user_token }}"
+ token_validate: true
+ timeout: 5
+ block:
+ - name: Test for python >= 3.8
+ when: python_interpreter_minor[1] | int > 7
+ block:
+ - name: Test rotate credential for a static role (explicit mount) [check mode]
+ register: rotate_credentials
+ check_mode: true
+ community.hashi_vault.vault_database_static_role_rotate_credentials:
+ engine_mount_point: database
+ role_name: "{{ roles_to_rotate[0] }}"
+
+ - name: Check (explicit mount) [check mode]
+ ansible.builtin.assert: &success
+ that:
+ - rotate_credentials is changed
+
+ - name: Test rotate credential for a static role (explicit mount - invalid, role_name)
+ register: rotate_credentials
+ ignore_errors: true
+ community.hashi_vault.vault_database_static_role_rotate_credentials:
+ engine_mount_point: NOT REAL
+ role_name: "{{ roles_to_rotate[0] }}"
+
+ - name: Check (explicit mount - invalid, role_name)
+ ansible.builtin.assert: &failure_bad_mount
+ that:
+ - rotate_credentials is failed
+ - rotate_credentials.msg is search('Permission Denied')
+
+ - name: Test rotate credential for a static role (explicit mount, role_name - invalid)
+ register: rotate_credentials
+ ignore_errors: true
+ community.hashi_vault.vault_database_static_role_rotate_credentials:
+ engine_mount_point: database
+ role_name: NOT REAL
+
+ - name: Check (explicit mount, role_name - invalid)
+ ansible.builtin.assert: &failure_invalid_path
+ that:
+ - rotate_credentials is failed
+ - rotate_credentials.msg is search('Invalid or missing path')
+
+ - name: Test rotate credential for a static role (explicit mount, role_name)
+ register: rotate_credentials
+ ignore_errors: true
+ community.hashi_vault.vault_database_static_role_rotate_credentials:
+ engine_mount_point: database
+ role_name: "{{ roles_to_rotate[0] }}"
+
+ - name: Check (explicit mount, role_name)
+ ansible.builtin.assert: *success
+
+ - name: Read user
+ vault_ci_read:
+ path: "database/static-creds/{{ roles_to_rotate[0] }}"
+ register: role_data_after
+
+ - name: Check that passwords were rotated for "{{ roles_data_before[0] }}"
+ ansible.builtin.assert:
+ that:
+ - roles_data_before.results[0].result.data.password != role_data_after.result.data.password
+ - roles_data_before.results[0].result.data.ttl < role_data_after.result.data.ttl
+
+ - name: Test rotate credential for a static role (default mount, role_name - invalid)
+ register: rotate_credentials
+ ignore_errors: true
+ community.hashi_vault.vault_database_static_role_rotate_credentials:
+ role_name: NOT REAL
+
+ - name: Check (default mount, role_name - invalid)
+ ansible.builtin.assert: *failure_invalid_path
+
+ - name: Test rotate credential for a static role (default mount, role_name)
+ register: rotate_credentials
+ ignore_errors: true
+ community.hashi_vault.vault_database_static_role_rotate_credentials:
+ engine_mount_point: database
+ role_name: "{{ roles_to_rotate[1] }}"
+
+ - name: Check (explicit mount, role_name)
+ ansible.builtin.assert: *success
+
+ - name: Read user
+ vault_ci_read:
+ path: "database/static-creds/{{ roles_to_rotate[1] }}"
+ register: role_data_after
+
+ - name: Check
+ ansible.builtin.assert:
+ that:
+ - roles_data_before.results[1].result.data.password != role_data_after.result.data.password
+ - roles_data_before.results[1].result.data.ttl < role_data_after.result.data.ttl
+
+ - name: Test for python < 3.8
+ when: python_interpreter_minor[1] | int <= 7
+ block:
+ - name: Test rotate credential for a static role [python < 3.8]
+ register: rotate_credentials
+ community.hashi_vault.vault_database_static_role_rotate_credentials:
+ engine_mount_point: database
+ role_name: "{{ role_name_to_rotate }}"
+ ignore_errors: true
+
+ - name: Check python < 3.8
+ ansible.builtin.assert:
+ that:
+ - rotate_credentials is failed
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_roles_list/aliases b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_roles_list/aliases
new file mode 100644
index 000000000..7636a9a65
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_roles_list/aliases
@@ -0,0 +1 @@
+context/target
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_roles_list/meta/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_roles_list/meta/main.yml
new file mode 100644
index 000000000..e867490b0
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_roles_list/meta/main.yml
@@ -0,0 +1,4 @@
+---
+dependencies:
+ - setup_vault_test_plugins
+ - setup_vault_configure_database
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_roles_list/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_roles_list/tasks/main.yml
new file mode 100644
index 000000000..ab6b5c5bc
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_roles_list/tasks/main.yml
@@ -0,0 +1,3 @@
+---
+- import_tasks: module_vault_database_static_roles_list_setup.yml
+- import_tasks: module_vault_database_static_roles_list_test.yml
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_roles_list/tasks/module_vault_database_static_roles_list_setup.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_roles_list/tasks/module_vault_database_static_roles_list_setup.yml
new file mode 100644
index 000000000..cd1b09dc7
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_roles_list/tasks/module_vault_database_static_roles_list_setup.yml
@@ -0,0 +1,9 @@
+---
+- name: Configuration tasks
+ module_defaults:
+ vault_ci_token_create: '{{ vault_plugins_module_defaults_common }}'
+ block:
+ - name: Create a test non-root token
+ vault_ci_token_create:
+ policies: [base-policy-database]
+ register: user_token_cmd
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_roles_list/tasks/module_vault_database_static_roles_list_test.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_roles_list/tasks/module_vault_database_static_roles_list_test.yml
new file mode 100644
index 000000000..31aa86814
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_database_static_roles_list/tasks/module_vault_database_static_roles_list_test.yml
@@ -0,0 +1,91 @@
+---
+- name: Var block
+ vars:
+ user_token: "{{ user_token_cmd.result.auth.client_token }}"
+ expected_roles:
+ - role1
+ - role2
+ - role3
+ - role4
+ - role5
+
+ module_defaults:
+ community.hashi_vault.vault_database_static_roles_list: &defaults
+ url: "{{ vault_test_server_http }}"
+ auth_method: token
+ token: "{{ user_token }}"
+ token_validate: true
+ timeout: 5
+ block:
+ - name: Test list database static roles (explicit mount - invalid) [check mode]
+ register: db_static_roles
+ check_mode: true
+ ignore_errors: true
+ community.hashi_vault.vault_database_static_roles_list:
+ engine_mount_point: NOT REAL
+
+ - name: Check (explicit mount - invalid) [check mode]
+ ansible.builtin.assert: &failure_bad_mount
+ that:
+ - db_static_roles is failed
+ - db_static_roles.msg is search('Permission Denied')
+
+ - name: Test list database static roles (explicit mount) [check mode]
+ register: db_static_roles
+ check_mode: true
+ community.hashi_vault.vault_database_static_roles_list:
+ engine_mount_point: database
+
+ - name: Check (explicit mount) [check mode]
+ ansible.builtin.assert: &success
+ that:
+ - db_static_roles is defined
+ - db_static_roles is not changed
+ - "'raw' in db_static_roles"
+ - "'data' in db_static_roles"
+ - db_static_roles.data == db_static_roles.raw.data
+ - "'keys' in db_static_roles['data']"
+ - "'roles' in db_static_roles"
+ - db_static_roles.roles == db_static_roles.data['keys']
+ - db_static_roles.roles == expected_roles
+
+ - name: Test list database static roles (explicit mount - invalid)
+ register: db_static_roles
+ ignore_errors: true
+ community.hashi_vault.vault_database_static_roles_list:
+ engine_mount_point: NOT REAL
+
+ - name: Check
+ ansible.builtin.assert: *failure_bad_mount
+
+ - name: Test list database static roles (explicit mount) [check mode]
+ register: db_static_roles
+ check_mode: true
+ community.hashi_vault.vault_database_static_roles_list:
+ engine_mount_point: database
+
+ - name: Check (explicit mount) [check mode]
+ ansible.builtin.assert: *success
+
+ - name: Test list database static roles (explicit mount)
+ register: db_static_roles
+ community.hashi_vault.vault_database_static_roles_list:
+ engine_mount_point: database
+
+ - name: Check (explicit mount)
+ ansible.builtin.assert: *success
+
+ - name: Test list database static roles (default mount) [check mode]
+ register: db_static_roles
+ check_mode: true
+ community.hashi_vault.vault_database_static_roles_list:
+
+ - name: Check (default mount) [check mode]
+ ansible.builtin.assert: *success
+
+ - name: Test list database static roles (default mount)
+ register: db_static_roles
+ community.hashi_vault.vault_database_static_roles_list:
+
+ - name: Check (default mount)
+ ansible.builtin.assert: *success
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_login/tasks/module_vault_login_test.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_login/tasks/module_vault_login_test.yml
index be8e3acff..124099566 100644
--- a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_login/tasks/module_vault_login_test.yml
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_login/tasks/module_vault_login_test.yml
@@ -39,7 +39,7 @@
- name: Try a login in check mode
register: result
community.hashi_vault.vault_login:
- check_mode: yes
+ check_mode: true
- assert:
that:
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_write/tasks/module_vault_write_test.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_write/tasks/module_vault_write_test.yml
index 244b8e29a..b9824b91f 100644
--- a/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_write/tasks/module_vault_write_test.yml
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/module_vault_write/tasks/module_vault_write_test.yml
@@ -20,6 +20,9 @@
data:
a: 1
b: two
+ # https://github.com/ansible-collections/community.hashi_vault/issues/389
+ path: path_value
+ wrap_ttl: wrap_ttl_value
- assert:
that:
@@ -42,6 +45,9 @@
data:
a: 1
b: two
+ # https://github.com/ansible-collections/community.hashi_vault/issues/389
+ path: path_value
+ wrap_ttl: wrap_ttl_value
- assert:
that:
@@ -57,7 +63,13 @@
that:
- "'result' in result"
- "'data' in result.result"
- - "result.result.data == {'a': 1, 'b': 'two'}"
+ - >
+ result.result.data == {
+ 'a': 1,
+ 'b': 'two',
+ 'path': 'path_value',
+ 'wrap_ttl': 'wrap_ttl_value',
+ }
- name: Write data to an endpoint that returns data and test wrapping
register: result
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/defaults/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/defaults/main.yml
index d17c895f9..8f6095be1 100644
--- a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/defaults/main.yml
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/defaults/main.yml
@@ -13,18 +13,30 @@ docker_compose_project_name: hashi_vault
vault_port_http: 8200
vault_port_https: 8300
vault_container_name: vault
+vault_container_image: hashicorp/vault
vault_target_name: '{{ vault_container_name }}'
proxy_port: 8888
proxy_container_name: tinyproxy
+proxy_container_image: monokal/tinyproxy
proxy_target_name: '{{ proxy_container_name }}'
mmock_server_port: 8900
mmock_console_port: 8901
mmock_container_name: mmock
+mmock_container_image: jordimartin/mmock
mmock_target_name: '{{ mmock_container_name }}'
mmock_config_path: '{{ output_dir }}/mmock_config'
+postgres_container_name: postgres
+postgres_container_image: postgres
+postgres_target_name: '{{ postgres_container_name }}'
+postgres_config_path: '{{ output_dir }}/postgres'
+postgres_sql_port: 5432
+postgres_db_name: hcvault
+postgres_db_user: postgres
+postgres_db_password: postgres
+
output_dir: '{{ role_path }}/files/.output'
docker_compose_output: '{{ output_dir }}/{{ docker_compose_project_name }}'
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/files/playbooks/vault_docker.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/files/playbooks/vault_docker.yml
index 6f6ae5ab9..18ff09ddc 100644
--- a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/files/playbooks/vault_docker.yml
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/files/playbooks/vault_docker.yml
@@ -1,5 +1,5 @@
---
- hosts: localhost
- gather_facts: no
+ gather_facts: false
roles:
- setup_localenv_docker
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/files/requirements/constraints.txt b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/files/requirements/constraints.txt
index 16f5a6645..66daa618e 100644
--- a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/files/requirements/constraints.txt
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/files/requirements/constraints.txt
@@ -1,2 +1,3 @@
-docker >= 5.0.0 ; python_version >= '3.6'
-docker < 5.0.0 ; python_version == '2.7'
+# https://github.com/docker/docker-py/issues/3194#issuecomment-1849016391
+# Must use docker SDK for Python < 7
+docker >= 5.0.0,<7 ; python_version >= '3.6'
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/files/requirements/requirements.txt b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/files/requirements/requirements.txt
index de536a9e5..52fdd0170 100644
--- a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/files/requirements/requirements.txt
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/files/requirements/requirements.txt
@@ -1,3 +1,2 @@
docker
docker-compose
-six # https://github.com/ansible-collections/community.docker/issues/171
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/files/sql/init.sql b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/files/sql/init.sql
new file mode 100644
index 000000000..2e9e73054
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/files/sql/init.sql
@@ -0,0 +1,16 @@
+-- Create users to manage database connections
+CREATE USER con1 WITH PASSWORD 'con1';
+CREATE USER con2 WITH PASSWORD 'con2';
+CREATE USER con3 WITH PASSWORD 'con3';
+CREATE USER con4 WITH PASSWORD 'con4';
+CREATE USER con5 WITH PASSWORD 'con5';
+
+-- Create another user to manage credential rotation
+-- CREATE USER usr_to_rotate with PASSWORD 'SuperSecret' SUPERUSER;
+
+-- Create users to manage static roles
+CREATE USER role1;
+CREATE USER role2;
+CREATE USER role3;
+CREATE USER role4;
+CREATE USER role5;
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/tasks/main.yml
index 90223f1e4..967497a26 100644
--- a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/tasks/main.yml
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/tasks/main.yml
@@ -7,6 +7,7 @@
- '{{ docker_compose_output }}'
- '{{ vault_config_output }}'
- '{{ mmock_config_path }}'
+ - '{{ postgres_config_path }}'
- name: "Create the docker-compose definition"
template:
@@ -21,19 +22,19 @@
- name: "Check if cert already exists"
stat:
path: '{{ vault_cert_file }}'
- follow: yes
- get_attributes: no
- get_checksum: no
- get_mime: no
+ follow: true
+ get_attributes: false
+ get_checksum: false
+ get_mime: false
register: cert_status
- name: "Check if key already exists"
stat:
path: '{{ vault_key_file }}'
- follow: yes
- get_attributes: no
- get_checksum: no
- get_mime: no
+ follow: true
+ get_attributes: false
+ get_checksum: false
+ get_mime: false
register: key_status
- name: "Generate certs"
@@ -60,11 +61,17 @@
src: '{{ item }}'
dest: '{{ mmock_config_path }}/{{ dest_name }}'
-- include_tasks: docker.yml
- when: docker_compose != 'none'
-
- name: "Template integration_config"
template:
src: integration_config.yml.j2
dest: '{{ output_dir }}/integration_config.yml'
- force: yes
+ force: true
+
+- name: "Copy postgres init.sql script"
+ copy:
+ src: files/sql/init.sql
+ dest: "{{ postgres_config_path }}/init.sql"
+ force: true
+
+- include_tasks: docker.yml
+ when: docker_compose != 'none'
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/templates/docker-compose.yml.j2 b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/templates/docker-compose.yml.j2
index 365532c4c..6696a6dd0 100644
--- a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/templates/docker-compose.yml.j2
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/templates/docker-compose.yml.j2
@@ -3,7 +3,7 @@
version: '3'
services:
vault:
- image: 'vault:{{ vault_version }}'
+ image: '{{ vault_container_image }}:{{ vault_version }}'
container_name: '{{ vault_container_name }}'
ports:
- '{{ vault_port_http }}:{{ vault_port_http }}'
@@ -14,13 +14,13 @@ services:
VAULT_DEV_ROOT_TOKEN_ID: '{{ vault_dev_root_token_id }}'
SKIP_CHOWN: 1
tinyproxy:
- image: 'monokal/tinyproxy'
+ image: '{{ proxy_container_image }}'
container_name: '{{ proxy_container_name }}'
ports:
- '{{ proxy_port }}:{{ proxy_port }}'
command: ANY
mmock:
- image: jordimartin/mmock
+ image: '{{ mmock_container_image }}'
container_name: '{{ mmock_container_name }}'
ports:
- '{{ mmock_server_port }}:{{ mmock_server_port }}'
@@ -30,3 +30,14 @@ services:
command: >-
-console-port {{ mmock_console_port }}
-server-port {{ mmock_server_port }}
+ postgres:
+ image: '{{ postgres_container_image }}'
+ container_name: '{{ postgres_container_name }}'
+ environment:
+ POSTGRES_DB: '{{ postgres_db_name }}'
+ POSTGRES_PASSWORD: '{{ postgres_db_password }}'
+ POSTGRES_USER: '{{ postgres_db_user }}'
+ ports:
+ - '{{ postgres_sql_port }}:{{ postgres_sql_port }}'
+ volumes:
+ - '{{ postgres_config_path}}/init.sql:/docker-entrypoint-initdb.d/init.sql'
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/vars/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/vars/main.yml
index fd0a0c36b..dc36fdae5 100644
--- a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/vars/main.yml
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_docker/vars/main.yml
@@ -7,3 +7,8 @@ integration_config:
vault_proxy_server: 'http://{{ proxy_target_name }}:{{ proxy_port }}'
vault_cert_content: "{{ lookup('file', vault_cert_file) }}"
vault_mmock_server_http: 'http://{{ mmock_target_name }}:{{ mmock_server_port }}'
+ vault_postgres_host: '{{ postgres_container_name }}'
+ vault_postgres_port: '{{ postgres_sql_port }}'
+ vault_postgres_db: '{{ postgres_db_name }}'
+ vault_postgres_user: '{{ postgres_db_user }}'
+ vault_postgres_password: '{{ postgres_db_password }}'
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_gha/files/playbooks/gha.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_gha/files/playbooks/gha.yml
index aea370d3f..57b27677b 100644
--- a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_gha/files/playbooks/gha.yml
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_localenv_gha/files/playbooks/gha.yml
@@ -1,5 +1,5 @@
---
- hosts: localhost
- gather_facts: no
+ gather_facts: false
roles:
- setup_localenv_gha
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/README.md b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/README.md
new file mode 100644
index 000000000..2d948a957
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/README.md
@@ -0,0 +1,2 @@
+# `setup_vault_configure_database`
+Performs configuration of the database engine in Vault.
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/aliases b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/aliases
new file mode 100644
index 000000000..4b3a017fd
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/aliases
@@ -0,0 +1,2 @@
+hidden
+needs/target/setup_vault_test_plugins
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/meta/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/meta/main.yml
new file mode 100644
index 000000000..290705e5e
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - setup_vault_test_plugins
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/tasks/configure.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/tasks/configure.yml
new file mode 100644
index 000000000..5640870ce
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/tasks/configure.yml
@@ -0,0 +1,48 @@
+---
+- name: Create database secrets engine
+ vault_ci_enable_engine:
+ backend_type: database
+
+- name: Create a database connection
+ vault_ci_write:
+ path: "/{{ vault_database_engine_mount_point }}/config/{{ vault_database_connection_name }}"
+ data:
+ plugin_name: "{{ vault_database_plugin_name }}"
+ connection_url: "{{ vault_database_connection_url }}"
+ allowed_roles: "*"
+ username: "{{ vault_database_connection_user }}"
+ password: "{{ vault_database_connection_password }}"
+
+- name: Create some static roles
+ vault_ci_write:
+ path: "{{ vault_database_engine_mount_point }}/static-roles/role{{ item }}"
+ data:
+ db_name: "{{ vault_database_connection_name }}"
+ username: "role{{ item }}"
+ rotation_period: 24h
+ loop: [1, 2, 3, 4, 5]
+
+- name: Create a readonly dynamic role
+ vault_ci_write:
+ path: "{{ vault_database_engine_mount_point }}/roles/readonly"
+ data:
+ db_name: "{{ vault_database_connection_name }}"
+ creation_statements: "{{ vault_database_dynamic_user_sql }}"
+ default_ttl: 1h
+ max_ttl: 24h
+
+- name: Create a database base policy
+ vault_ci_policy_put:
+ name: base-policy-database
+ policy: "{{ vault_base_policy_db }}"
+
+- name: Create a database all policy
+ vault_ci_policy_put:
+ name: policy-database-all
+ policy: "{{ vault_policy_db_all }}"
+
+- name: Write Canary
+ vault_ci_write:
+ path: "{{ vault_configure_engine_database_canary.path }}"
+ data:
+ value: "{{ vault_configure_engine_database_canary.value }}"
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/tasks/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/tasks/main.yml
new file mode 100644
index 000000000..f6a343251
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/tasks/main.yml
@@ -0,0 +1,17 @@
+---
+- name: Configuration tasks
+ module_defaults:
+ vault_ci_enable_engine: '{{ vault_plugins_module_defaults_common }}'
+ vault_ci_read: '{{ vault_plugins_module_defaults_common }}'
+ vault_ci_write: '{{ vault_plugins_module_defaults_common }}'
+ vault_ci_policy_put: '{{ vault_plugins_module_defaults_common }}'
+ vault_ci_token_create: '{{ vault_plugins_module_defaults_common }}'
+ block:
+ - name: Canary for Vault Database engine setup
+ vault_ci_read:
+ path: '{{ vault_configure_engine_database_canary.path }}'
+ register: canary
+
+ - name: Configure Vault Database engine basic setup
+ include_tasks: configure.yml
+ when: canary.result is none
diff --git a/ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/vars/main.yml b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/vars/main.yml
new file mode 100644
index 000000000..4086901e7
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/integration/targets/setup_vault_configure_database/vars/main.yml
@@ -0,0 +1,27 @@
+---
+vault_configure_engine_database_canary:
+ path: cubbyhole/configure_engine_database
+ value: complete # value does not matter
+
+vault_database_engine_mount_point: database
+vault_database_connection_name: my-postgresql-database
+vault_database_db_name: hcvault
+vault_database_connection_url: "postgresql://{{ '{{username}}' }}:{{ '{{password}}' }}@postgres:5432/{{ vault_database_db_name }}?sslmode=disable"
+vault_database_plugin_name: postgresql-database-plugin
+vault_database_connection_user: postgres
+vault_database_connection_password: postgres
+
+vault_database_dynamic_user_sql: |
+ CREATE ROLE {{ "{{name}}" }} WITH LOGIN PASSWORD {{ '{{password}}' }} VALID UNTIL {{ '{{expiration}}' }} INHERIT;
+ GRANT ro TO {{ "{{name}}" }};
+
+vault_base_policy_db: |
+ path "{{ vault_database_engine_mount_point }}/*" {
+ capabilities = ["read", "list"]
+ }
+
+vault_policy_db_all: |
+ {{ vault_base_policy_db }}
+ path "{{ vault_database_engine_mount_point }}/*" {
+ capabilities = ["create", "update", "patch", "delete"]
+ }
diff --git a/ansible_collections/community/hashi_vault/tests/unit/conftest.py b/ansible_collections/community/hashi_vault/tests/unit/conftest.py
index 862e93cf6..7b07c1b1e 100644
--- a/ansible_collections/community/hashi_vault/tests/unit/conftest.py
+++ b/ansible_collections/community/hashi_vault/tests/unit/conftest.py
@@ -78,5 +78,15 @@ def patch_get_vault_client(vault_client):
def requests_unparseable_response():
r = mock.MagicMock()
r.json.side_effect = json.JSONDecodeError
+ return r
+
+# https://github.com/hvac/hvac/issues/797
+@pytest.fixture
+def empty_response(requests_unparseable_response):
+ r = requests_unparseable_response
+ r.status_code = 204
+ r._content = b""
+ r.content = b""
+ r.text = ""
return r
diff --git a/ansible_collections/community/hashi_vault/tests/unit/constraints.txt b/ansible_collections/community/hashi_vault/tests/unit/constraints.txt
new file mode 100644
index 000000000..f347921c3
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/unit/constraints.txt
@@ -0,0 +1,64 @@
+coverage >= 4.2, < 5.0.0, != 4.3.2 ; python_version <= '3.7' # features in 4.2+ required, avoid known bug in 4.3.2 on python 2.6, coverage 5.0+ incompatible
+coverage >= 4.5.4, < 5.0.0 ; python_version > '3.7' # coverage had a bug in < 4.5.4 that would cause unit tests to hang in Python 3.8, coverage 5.0+ incompatible
+cryptography < 2.2 ; python_version < '2.7' # cryptography 2.2 drops support for python 2.6
+deepdiff < 4.0.0 ; python_version < '3' # deepdiff 4.0.0 and later require python 3
+jinja2 < 2.11 ; python_version < '2.7' # jinja2 2.11 and later require python 2.7 or later
+urllib3 < 1.24 ; python_version < '2.7' # urllib3 1.24 and later require python 2.7 or later
+pywinrm >= 0.3.0 # message encryption support
+sphinx < 1.6 ; python_version < '2.7' # sphinx 1.6 and later require python 2.7 or later
+sphinx < 1.8 ; python_version >= '2.7' # sphinx 1.8 and later are currently incompatible with rstcheck 3.3
+pygments >= 2.4.0 # Pygments 2.4.0 includes bugfixes for YAML and YAML+Jinja lexers
+wheel < 0.30.0 ; python_version < '2.7' # wheel 0.30.0 and later require python 2.7 or later
+yamllint != 1.8.0, < 1.14.0 ; python_version < '2.7' # yamllint 1.8.0 and 1.14.0+ require python 2.7+
+pycrypto >= 2.6 # Need features found in 2.6 and greater
+ncclient >= 0.5.2 # Need features added in 0.5.2 and greater
+idna < 2.6, >= 2.5 # linode requires idna < 2.9, >= 2.5, requests requires idna < 2.6, but cryptography will cause the latest version to be installed instead
+paramiko < 2.4.0 ; python_version < '2.7' # paramiko 2.4.0 drops support for python 2.6
+pytest < 3.3.0 ; python_version < '2.7' # pytest 3.3.0 drops support for python 2.6
+pytest < 5.0.0 ; python_version == '2.7' # pytest 5.0.0 and later will no longer support python 2.7
+pytest-forked < 1.0.2 ; python_version < '2.7' # pytest-forked 1.0.2 and later require python 2.7 or later
+pytest-forked >= 1.0.2 ; python_version >= '2.7' # pytest-forked before 1.0.2 does not work with pytest 4.2.0+ (which requires python 2.7+)
+ntlm-auth >= 1.3.0 # message encryption support using cryptography
+requests < 2.20.0 ; python_version < '2.7' # requests 2.20.0 drops support for python 2.6
+requests-ntlm >= 1.1.0 # message encryption support
+requests-credssp >= 0.1.0 # message encryption support
+voluptuous >= 0.11.0 # Schema recursion via Self
+openshift >= 0.6.2, < 0.9.0 # merge_type support
+virtualenv < 16.0.0 ; python_version < '2.7' # virtualenv 16.0.0 and later require python 2.7 or later
+pathspec < 0.6.0 ; python_version < '2.7' # pathspec 0.6.0 and later require python 2.7 or later
+pyopenssl < 18.0.0 ; python_version < '2.7' # pyOpenSSL 18.0.0 and later require python 2.7 or later
+pyfmg == 0.6.1 # newer versions do not pass current unit tests
+pyyaml < 5.1 ; python_version < '2.7' # pyyaml 5.1 and later require python 2.7 or later
+pycparser < 2.19 ; python_version < '2.7' # pycparser 2.19 and later require python 2.7 or later
+mock >= 2.0.0 # needed for features backported from Python 3.6 unittest.mock (assert_called, assert_called_once...)
+pytest-mock >= 1.4.0 # needed for mock_use_standalone_module pytest option
+xmltodict < 0.12.0 ; python_version < '2.7' # xmltodict 0.12.0 and later require python 2.7 or later
+lxml < 4.3.0 ; python_version < '2.7' # lxml 4.3.0 and later require python 2.7 or later
+pyvmomi < 6.0.0 ; python_version < '2.7' # pyvmomi 6.0.0 and later require python 2.7 or later
+pyone == 1.1.9 # newer versions do not pass current integration tests
+boto3 < 1.11 ; python_version < '2.7' # boto3 1.11 drops Python 2.6 support
+botocore >= 1.10.0, < 1.14 ; python_version < '2.7' # adds support for the following AWS services: secretsmanager, fms, and acm-pca; botocore 1.14 drops Python 2.6 support
+botocore >= 1.10.0 ; python_version >= '2.7' # adds support for the following AWS services: secretsmanager, fms, and acm-pca
+setuptools < 45 ; python_version <= '2.7' # setuptools 45 and later require python 3.5 or later
+cffi >= 1.14.2, != 1.14.3 # Yanked version which older versions of pip will still install:
+
+# freeze pylint and its requirements for consistent test results
+astroid == 2.2.5
+isort == 4.3.15
+lazy-object-proxy == 1.3.1
+mccabe == 0.6.1
+pylint == 2.3.1
+typed-ast == 1.4.0 # 1.4.0 is required to compile on Python 3.8
+wrapt == 1.11.1
+
+# hvac
+hvac >= 1.2.1 ; python_version >= '3.6'
+
+# urllib3
+# these should be satisfied naturally by the requests versions required by hvac anyway
+urllib3 >= 1.15 ; python_version >= '3.6' # we need raise_on_status for retry support to raise the correct exceptions https://github.com/urllib3/urllib3/blob/main/CHANGES.rst#115-2016-04-06
+
+# requests
+# https://github.com/psf/requests/pull/6356
+requests >= 2.29 ; python_version >= '3.7'
+requests < 2.28 ; python_version < '3.7'
diff --git a/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_connection_read_response.json b/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_connection_read_response.json
new file mode 100644
index 000000000..36c4429a8
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_connection_read_response.json
@@ -0,0 +1,20 @@
+{
+ "auth": null,
+ "data": {
+ "allowed_roles": [],
+ "connection_details": {
+ "connection_url": "postgresql://{{username}}:{{password}}@postgres:5432/postgres?sslmode=disable",
+ "username": "UserName"
+ },
+ "password_policy": "",
+ "plugin_name": "postgresql-database-plugin",
+ "plugin_version": "",
+ "root_credentials_rotate_statements": []
+ },
+ "lease_duration": 0,
+ "lease_id": "",
+ "renewable": false,
+ "request_id": "91909ec0-cd89-489c-a7cf-2a82d2258b4d",
+ "warnings": null,
+ "wrap_info": null
+}
diff --git a/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_connections_list_response.json b/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_connections_list_response.json
new file mode 100644
index 000000000..c5abad4ce
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_connections_list_response.json
@@ -0,0 +1,21 @@
+{
+ "auth": null,
+ "data": {
+ "keys": [
+ "con1",
+ "con2",
+ "con3"
+ ]
+ },
+ "connections": [
+ "con1",
+ "con2",
+ "con3"
+ ],
+ "lease_duration": 0,
+ "lease_id": "",
+ "renewable": false,
+ "request_id": "91909ec0-cd89-489c-a7cf-2a82d2258b4d",
+ "warnings": null,
+ "wrap_info": null
+}
diff --git a/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_role_read_response.json b/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_role_read_response.json
new file mode 100644
index 000000000..c840ad1cb
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_role_read_response.json
@@ -0,0 +1,22 @@
+{
+ "auth": null,
+ "data": {
+ "creation_statements": [
+ "CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}';",
+ "GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";"
+ ],
+ "credential_type": "password",
+ "db_name": "SomeConnection",
+ "default_ttl": 3600,
+ "max_ttl": 86400,
+ "renew_statements": [],
+ "revocation_statements": [],
+ "rollback_statements": []
+ },
+ "lease_duration": 0,
+ "lease_id": "",
+ "renewable": false,
+ "request_id": "91909ec0-cd89-489c-a7cf-2a82d2258b4d",
+ "warnings": null,
+ "wrap_info": null
+}
diff --git a/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_roles_list_response.json b/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_roles_list_response.json
new file mode 100644
index 000000000..00062fa20
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_roles_list_response.json
@@ -0,0 +1,21 @@
+{
+ "auth": null,
+ "data": {
+ "keys": [
+ "dyn_role1",
+ "dyn_role2",
+ "dyn_role3"
+ ]
+ },
+ "roles": [
+ "dyn_role1",
+ "dyn_role2",
+ "dyn_role3"
+ ],
+ "lease_duration": 0,
+ "lease_id": "",
+ "renewable": false,
+ "request_id": "91909ec0-cd89-489c-a7cf-2a82d2258b4d",
+ "warnings": null,
+ "wrap_info": null
+}
diff --git a/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_static_role_get_credentials_response.json b/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_static_role_get_credentials_response.json
new file mode 100644
index 000000000..34e901a12
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_static_role_get_credentials_response.json
@@ -0,0 +1,25 @@
+{
+ "data": {
+ "last_vault_rotation": "2024-01-01T09:00:00+01:00",
+ "password": "Th3_$3cr3t_P@ss!",
+ "rotation_period": 86400,
+ "ttl": 123456,
+ "username": "SomeUser"
+ },
+ "raw": {
+ "auth": null,
+ "data": {
+ "last_vault_rotation": "2024-01-01T09:00:00+01:00",
+ "password": "Th3_$3cr3t_P@ss!",
+ "rotation_period": 86400,
+ "ttl": 123456,
+ "username": "SomeUser"
+ },
+ "lease_duration": 0,
+ "lease_id": "",
+ "renewable": false,
+ "request_id": "91909ec0-cd89-489c-a7cf-2a82d2258b4d",
+ "warnings": null,
+ "wrap_info": null
+ }
+}
diff --git a/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_static_role_read_response.json b/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_static_role_read_response.json
new file mode 100644
index 000000000..cd4cbdc63
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_static_role_read_response.json
@@ -0,0 +1,18 @@
+{
+ "auth": null,
+ "data": {
+ "credential_type": "password",
+ "db_name": "SomeConnection",
+ "last_vault_rotation": "2024-01-01T09:00:00 +01:00",
+ "rotation_period": 86400,
+ "rotation_statements": [
+ "ALTER USER \"{{name}}\" WITH PASSWORD '{{password}}';"
+ ]
+ },
+ "lease_duration": 0,
+ "lease_id": "",
+ "renewable": false,
+ "request_id": "91909ec0-cd89-489c-a7cf-2a82d2258b4d",
+ "warnings": null,
+ "wrap_info": null
+}
diff --git a/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_static_roles_list_response.json b/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_static_roles_list_response.json
new file mode 100644
index 000000000..be8700112
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/unit/fixtures/database_static_roles_list_response.json
@@ -0,0 +1,21 @@
+{
+ "auth": null,
+ "data": {
+ "keys": [
+ "role1",
+ "role2",
+ "role3"
+ ]
+ },
+ "roles": [
+ "role1",
+ "role2",
+ "role3"
+ ],
+ "lease_duration": 0,
+ "lease_id": "",
+ "renewable": false,
+ "request_id": "91909ec0-cd89-489c-a7cf-2a82d2258b4d",
+ "warnings": null,
+ "wrap_info": null
+}
diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/lookup/test_vault_token_create.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/lookup/test_vault_token_create.py
index 05a74f8b4..37404d9a2 100644
--- a/ansible_collections/community/hashi_vault/tests/unit/plugins/lookup/test_vault_token_create.py
+++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/lookup/test_vault_token_create.py
@@ -6,7 +6,6 @@
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
-import sys
import pytest
from ansible.plugins.loader import lookup_loader
@@ -150,11 +149,7 @@ class TestVaultTokenCreateLookup(object):
"lookup result did not match expected result:\nlookup: %r\nexpected: %r" % (result, token_create_response)
)
- if sys.version_info < (3, 8):
- # TODO: remove when python < 3.8 is dropped
- assert pass_thru_options.items() <= client.auth.token.create.call_args[1].items()
- else:
- assert pass_thru_options.items() <= client.auth.token.create.call_args.kwargs.items()
+ assert pass_thru_options.items() <= client.auth.token.create.call_args.kwargs.items()
def test_vault_token_create_orphan_options(
self, vault_token_create_lookup, authenticator, minimal_vars, pass_thru_options, orphan_option_translation, token_create_response
@@ -175,11 +170,7 @@ class TestVaultTokenCreateLookup(object):
"lookup result did not match expected result:\nlookup: %r\nexpected: %r" % (result, token_create_response)
)
- if sys.version_info < (3, 8):
- # TODO: remove when python < 3.8 is dropped
- call_kwargs = client.auth.token.create_orphan.call_args[1]
- else:
- call_kwargs = client.auth.token.create_orphan.call_args.kwargs
+ call_kwargs = client.auth.token.create_orphan.call_args.kwargs
for name, orphan in orphan_option_translation.items():
assert name not in call_kwargs, (
diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/lookup/test_vault_write.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/lookup/test_vault_write.py
index c3c325228..eaac0ff08 100644
--- a/ansible_collections/community/hashi_vault/tests/unit/plugins/lookup/test_vault_write.py
+++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/lookup/test_vault_write.py
@@ -68,18 +68,18 @@ class TestVaultWriteLookup(object):
def test_vault_write_return_data(self, vault_write_lookup, minimal_vars, approle_secret_id_write_response, vault_client, paths, data, wrap_ttl):
client = vault_client
- expected_calls = [mock.call(path=p, wrap_ttl=wrap_ttl, **data) for p in paths]
+ expected_calls = [mock.call(path=p, wrap_ttl=wrap_ttl, data=data) for p in paths]
- def _fake_write(path, wrap_ttl, **data):
+ def _fake_write(path, wrap_ttl, data=None):
r = approle_secret_id_write_response.copy()
r.update({'path': path})
return r
- client.write = mock.Mock(wraps=_fake_write)
+ client.write_data = mock.Mock(wraps=_fake_write)
response = vault_write_lookup.run(terms=paths, variables=minimal_vars, wrap_ttl=wrap_ttl, data=data)
- client.write.assert_has_calls(expected_calls)
+ client.write_data.assert_has_calls(expected_calls)
assert len(response) == len(paths), "%i paths processed but got %i responses" % (len(paths), len(response))
@@ -96,7 +96,7 @@ class TestVaultWriteLookup(object):
requests_unparseable_response.status_code = 204
- client.write.return_value = requests_unparseable_response
+ client.write_data.return_value = requests_unparseable_response
response = vault_write_lookup.run(terms=['fake'], variables=minimal_vars)
@@ -108,7 +108,7 @@ class TestVaultWriteLookup(object):
requests_unparseable_response.status_code = 200
requests_unparseable_response.content = '﷽'
- client.write.return_value = requests_unparseable_response
+ client.write_data.return_value = requests_unparseable_response
with mock.patch('ansible_collections.community.hashi_vault.plugins.lookup.vault_write.display.warning') as warning:
response = vault_write_lookup.run(terms=['fake'], variables=minimal_vars)
@@ -127,7 +127,40 @@ class TestVaultWriteLookup(object):
def test_vault_write_exceptions(self, vault_write_lookup, minimal_vars, vault_client, exc):
client = vault_client
- client.write.side_effect = exc[0]
+ client.write_data.side_effect = exc[0]
with pytest.raises(AnsibleError, match=exc[1]):
vault_write_lookup.run(terms=['fake'], variables=minimal_vars)
+
+ @pytest.mark.parametrize(
+ 'data',
+ [
+ {"path": mock.sentinel.path_value},
+ {"wrap_ttl": mock.sentinel.wrap_ttl_value},
+ {"path": mock.sentinel.data_value, "wrap_ttl": mock.sentinel.write_ttl_value},
+ ],
+ )
+ def test_vault_write_data_fallback_bad_params(self, vault_write_lookup, minimal_vars, vault_client, data):
+ client = vault_client
+ client.mock_add_spec(['write'])
+
+ with pytest.raises(AnsibleError, match=r"To use 'path' or 'wrap_ttl' as data keys, use hvac >= 1\.2"):
+ vault_write_lookup.run(terms=['fake'], variables=minimal_vars, data=data)
+
+ client.write.assert_not_called()
+
+ @pytest.mark.parametrize(
+ 'data',
+ [
+ {"item1": mock.sentinel.item1_value},
+ {"item2": mock.sentinel.item2_value},
+ {"item1": mock.sentinel.item1_value, "item2": mock.sentinel.item2_value},
+ ],
+ )
+ def test_vault_write_data_fallback_write(self, vault_write_lookup, minimal_vars, vault_client, data):
+ client = vault_client
+ client.mock_add_spec(['write'])
+
+ vault_write_lookup.run(terms=['fake'], variables=minimal_vars, data=data)
+
+ client.write.assert_called_once_with(path='fake', wrap_ttl=None, **data)
diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/authentication/test_auth_aws_iam.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/authentication/test_auth_aws_iam.py
index 678146b92..ac867dcd6 100644
--- a/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/authentication/test_auth_aws_iam.py
+++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/authentication/test_auth_aws_iam.py
@@ -163,7 +163,7 @@ class TestAuthAwsIam(object):
params = auth_aws_iam._auth_aws_iam_login_params
- assert boto3.session.Session.called_once_with(profile_name=profile)
+ boto3.session.Session.assert_called_once_with(profile_name=profile)
assert params['access_key'] == aws_access_key
assert params['secret_key'] == aws_secret_key
diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/authentication/test_auth_azure.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/authentication/test_auth_azure.py
index 747a432df..f0aabd78a 100644
--- a/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/authentication/test_auth_azure.py
+++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/authentication/test_auth_azure.py
@@ -157,10 +157,10 @@ class TestAuthAzure(object):
credential.get_token.return_value.token = jwt
auth_azure.validate()
- assert mocked_credential_class.called_once_with(
+ mocked_credential_class.assert_called_once_with(
azure_tenant_id, azure_client_id, azure_client_secret
)
- assert credential.get_token.called_once_with(
+ credential.get_token.assert_called_once_with(
'https://management.azure.com//.default'
)
@@ -194,8 +194,8 @@ class TestAuthAzure(object):
credential.get_token.return_value.token = jwt
auth_azure.validate()
- assert mocked_credential_class.called_once_with(azure_client_id)
- assert credential.get_token.called_once_with(
+ mocked_credential_class.assert_called_once_with(client_id=azure_client_id)
+ credential.get_token.assert_called_once_with(
'https://management.azure.com//.default'
)
@@ -215,8 +215,8 @@ class TestAuthAzure(object):
credential.get_token.return_value.token = jwt
auth_azure.validate()
- assert mocked_credential_class.called_once_with()
- assert credential.get_token.called_once_with(
+ mocked_credential_class.assert_called_once_with()
+ credential.get_token.assert_called_once_with(
'https://management.azure.com//.default'
)
diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/authentication/test_auth_token.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/authentication/test_auth_token.py
index d8a13435b..5003082a5 100644
--- a/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/authentication/test_auth_token.py
+++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/authentication/test_auth_token.py
@@ -11,11 +11,7 @@ import pytest
from ......tests.unit.compat import mock
-try:
- import hvac
-except ImportError:
- # python 2.6, which isn't supported anyway
- hvac = mock.MagicMock()
+import hvac
from ......plugins.module_utils._auth_method_token import (
HashiVaultAuthMethodToken,
diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/authentication/test_hashi_vault_auth_method_base.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/authentication/test_hashi_vault_auth_method_base.py
index 828cbdefc..36dfbcec0 100644
--- a/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/authentication/test_hashi_vault_auth_method_base.py
+++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/authentication/test_hashi_vault_auth_method_base.py
@@ -8,13 +8,10 @@ __metaclass__ = type
import pytest
-from ansible_collections.community.hashi_vault.tests.unit.compat import mock
-
-from ansible_collections.community.hashi_vault.plugins.module_utils._hashi_vault_common import (
+from ......plugins.module_utils._hashi_vault_common import (
HashiVaultAuthMethodBase,
HashiVaultOptionGroupBase,
HashiVaultValueError,
- _stringify,
)
@@ -75,12 +72,3 @@ class TestHashiVaultAuthMethodBase(object):
auth_base.deprecate(msg, version, date, collection_name)
deprecator.assert_called_once_with(msg, version=version, date=date, collection_name=collection_name)
-
- def test_has_stringify(self, auth_base):
- v = 'X'
- wrapper = mock.Mock(wraps=_stringify)
- with mock.patch('ansible_collections.community.hashi_vault.plugins.module_utils._hashi_vault_common._stringify', wrapper):
- r = auth_base._stringify(v)
-
- wrapper.assert_called_once_with(v)
- assert r == v
diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/option_adapter/test_hashi_vault_option_adapter.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/option_adapter/test_hashi_vault_option_adapter.py
index d3e205d68..9226de003 100644
--- a/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/option_adapter/test_hashi_vault_option_adapter.py
+++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/option_adapter/test_hashi_vault_option_adapter.py
@@ -8,7 +8,7 @@ __metaclass__ = type
import pytest
-from ansible_collections.community.hashi_vault.plugins.module_utils._hashi_vault_common import HashiVaultOptionAdapter
+from ......plugins.module_utils._hashi_vault_common import HashiVaultOptionAdapter
SAMPLE_DICT = {
@@ -103,18 +103,32 @@ class TestHashiVaultOptionAdapter(object):
def test_has_option(self, adapter, option, expected):
assert adapter.has_option(option) == expected
- @pytest.mark.parametrize('value', ['__VALUE'])
- @pytest.mark.parametrize('option', (SAMPLE_KEYS + MISSING_KEYS))
- def test_set_option(self, adapter, option, value, sample_dict):
+ @pytest.mark.parametrize('option', SAMPLE_KEYS)
+ def test_set_option_existing(self, adapter, option, sample_dict):
+ value = type(sample_dict.get(option, ""))()
adapter.set_option(option, value)
-
# first check the underlying data, then ensure the adapter refelcts the change too
assert sample_dict[option] == value
assert adapter.get_option(option) == value
+ @pytest.mark.parametrize('option', MISSING_KEYS)
+ def test_set_option_missing(self, request, adapter, option, sample_dict):
+ value = MARKER
+
+ for mark in request.node.own_markers:
+ if mark.name == 'option_adapter_raise_on_missing':
+ from ansible.errors import AnsibleError
+ with pytest.raises(AnsibleError, match=rf"^Requested entry.*?setting: {option}.*?was not defined in configuration"):
+ adapter.set_option(option, value)
+ break
+ else:
+ adapter.set_option(option, value)
+ assert sample_dict[option] == value
+ assert adapter.get_option(option) == value
+
@pytest.mark.parametrize('default', [MARKER])
- @pytest.mark.parametrize('option,expected', [(o, SAMPLE_DICT[o]) for o in SAMPLE_KEYS] + [(o, MARKER) for o in MISSING_KEYS])
- def test_set_option_default(self, adapter, option, default, expected, sample_dict):
+ @pytest.mark.parametrize('option,expected', [(o, SAMPLE_DICT[o]) for o in SAMPLE_KEYS])
+ def test_set_option_default_existing(self, adapter, option, default, expected, sample_dict):
value = adapter.set_option_default(option, default)
# check return data, underlying data structure, and adapter retrieval
@@ -122,25 +136,47 @@ class TestHashiVaultOptionAdapter(object):
assert sample_dict[option] == expected
assert adapter.get_option(option) == expected
- @pytest.mark.parametrize('options', [[SAMPLE_KEYS[0], MISSING_KEYS[0]]])
- def test_set_options(self, adapter, options, sample_dict):
- update = dict([(o, '__VALUE_%i' % i) for i, o in enumerate(options)])
+ @pytest.mark.parametrize('default', [MARKER])
+ @pytest.mark.parametrize('option,expected', [(o, MARKER) for o in MISSING_KEYS])
+ def test_set_option_default_missing(self, request, adapter, option, default, expected, sample_dict):
+ for mark in request.node.own_markers:
+ if mark.name == 'option_adapter_raise_on_missing':
+ from ansible.errors import AnsibleError
+ with pytest.raises(AnsibleError, match=rf"^Requested entry.*?setting: {option}.*?was not defined in configuration"):
+ adapter.set_option_default(option, default)
+ break
+ else:
+ value = adapter.set_option_default(option, default)
+ # check return data, underlying data structure, and adapter retrieval
+ assert value == expected
+ assert sample_dict[option] == expected
+ assert adapter.get_option(option) == expected
- adapter.set_options(**update)
+ @pytest.mark.parametrize('options', [[SAMPLE_KEYS[0], MISSING_KEYS[0]]])
+ def test_set_options(self, request, adapter, options, sample_dict):
+ update = dict([(o, type(sample_dict.get(o, ""))(i)) for i, o in enumerate(options)])
+
+ for mark in request.node.own_markers:
+ if mark.name == 'option_adapter_raise_on_missing':
+ from ansible.errors import AnsibleError
+ with pytest.raises(AnsibleError, match=r"^Requested entry.*?setting:.*?was not defined in configuration"):
+ adapter.set_options(**update)
+ break
+ else:
+ adapter.set_options(**update)
+ for k in MISSING_KEYS:
+ if k in update:
+ assert sample_dict[k] == update[k]
+ assert adapter.get_option(k) == update[k]
+ else:
+ assert k not in sample_dict
+ assert not adapter.has_option(k)
for k in SAMPLE_KEYS:
expected = update[k] if k in update else SAMPLE_DICT[k]
assert sample_dict[k] == expected
assert adapter.get_option(k) == expected
- for k in MISSING_KEYS:
- if k in update:
- assert sample_dict[k] == update[k]
- assert adapter.get_option(k) == update[k]
- else:
- assert k not in sample_dict
- assert not adapter.has_option(k)
-
@pytest.mark.parametrize('options', [[SAMPLE_KEYS[0], MISSING_KEYS[0]]])
def test_get_options_mixed(self, adapter, options):
with pytest.raises(KeyError):
diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/test_hashi_vault_connection_options.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/test_hashi_vault_connection_options.py
index 8766388e9..6a45b9859 100644
--- a/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/test_hashi_vault_connection_options.py
+++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/test_hashi_vault_connection_options.py
@@ -101,7 +101,7 @@ class TestHashiVaultConnectionOptions(object):
with mock.patch.dict(os.environ, envpatch):
connection_options._boolean_or_cacert()
- assert predefined_options['ca_cert'] == expected
+ assert connection_options._conopt_verify == expected
# _process_option_proxies
# proxies can be specified as a dictionary where key is protocol/scheme
@@ -248,7 +248,7 @@ class TestHashiVaultConnectionOptions(object):
# these should always be returned
assert 'url' in opts and opts['url'] == predefined_options['url']
- assert 'verify' in opts and opts['verify'] == predefined_options['ca_cert']
+ assert 'verify' in opts and opts['verify'] == connection_options._conopt_verify
# these are optional
assert 'proxies' not in opts or opts['proxies'] == predefined_options['proxies']
diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/test_hashi_vault_helper.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/test_hashi_vault_helper.py
index 6a5c6002b..14db5d1c8 100644
--- a/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/test_hashi_vault_helper.py
+++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/module_utils/test_hashi_vault_helper.py
@@ -12,7 +12,6 @@ import pytest
from .....tests.unit.compat import mock
from .....plugins.module_utils._hashi_vault_common import (
HashiVaultHelper,
- _stringify,
)
@@ -48,12 +47,3 @@ class TestHashiVaultHelper(object):
client = hashi_vault_helper.get_vault_client(hashi_vault_logout_inferred_token=True)
assert client.token is None
-
- def test_has_stringify(self, hashi_vault_helper):
- v = 'X'
- wrapper = mock.Mock(wraps=_stringify)
- with mock.patch('ansible_collections.community.hashi_vault.plugins.module_utils._hashi_vault_common._stringify', wrapper):
- r = hashi_vault_helper._stringify(v)
-
- wrapper.assert_called_once_with(v)
- assert r == v, '%r != %r' % (r, v)
diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_connection_configure.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_connection_configure.py
new file mode 100644
index 000000000..17a4e063e
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_connection_configure.py
@@ -0,0 +1,195 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2024 Brian Scholer (@briantist)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+import pytest
+import re
+import json
+
+from ansible.module_utils.basic import missing_required_lib
+
+from ...compat import mock
+from .....plugins.modules import vault_database_connection_configure
+from .....plugins.module_utils._hashi_vault_common import HashiVaultValueError
+
+
+hvac = pytest.importorskip("hvac")
+
+
+pytestmark = pytest.mark.usefixtures(
+ "patch_ansible_module",
+ "patch_authenticator",
+ "patch_get_vault_client",
+)
+
+
+def _connection_options():
+ return {
+ "auth_method": "token",
+ "url": "http://myvault",
+ "token": "beep-boop",
+ }
+
+
+def _sample_options():
+ return {
+ "engine_mount_point": "dbmount",
+ }
+
+
+def _sample_connection():
+ return {
+ "connection_name": "foo",
+ "plugin_name": "bar",
+ "allowed_roles": [
+ "baz",
+ ],
+ "connection_url": "postgresql://{{'{{username}}'}}:{{'{{password}}'}}@postgres:5432/postgres?sslmode=disable",
+ "connection_username": "SomeUser",
+ "connection_password": "SomePass",
+ }
+
+
+def _combined_options(**kwargs):
+ opt = _connection_options()
+ opt.update(_sample_options())
+ opt.update(_sample_connection())
+ opt.update(kwargs)
+ return opt
+
+
+class TestModuleVaultDatabaseConnectionConfigure:
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ @pytest.mark.parametrize(
+ "exc",
+ [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")],
+ )
+ def test_vault_database_connection_configure_authentication_error(
+ self, authenticator, exc, capfd
+ ):
+ authenticator.authenticate.side_effect = exc
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_connection_configure.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == "throwaway msg", "result: %r" % result
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ @pytest.mark.parametrize(
+ "exc",
+ [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")],
+ )
+ def test_vault_database_connection_configure_auth_validation_error(
+ self, authenticator, exc, capfd
+ ):
+ authenticator.validate.side_effect = exc
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_connection_configure.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == "throwaway msg"
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ def test_vault_database_connection_configure_no_hvac(self, capfd):
+ with mock.patch.multiple(
+ vault_database_connection_configure,
+ HAS_HVAC=False,
+ HVAC_IMPORT_ERROR=None,
+ create=True,
+ ):
+ with pytest.raises(SystemExit) as e:
+ vault_database_connection_configure.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == missing_required_lib("hvac")
+
+ @pytest.mark.parametrize(
+ "exc",
+ [
+ (
+ hvac.exceptions.Forbidden,
+ "",
+ r"^Forbidden: Permission Denied to path \['([^']+)'\]",
+ ),
+ (
+ hvac.exceptions.InvalidPath,
+ "",
+ r"^Invalid or missing path \['([^']+)/config/([^']+)'\]",
+ ),
+ ],
+ )
+ @pytest.mark.parametrize(
+ "patch_ansible_module",
+ [[_combined_options(), "engine_mount_point"]],
+ indirect=True,
+ )
+ @pytest.mark.parametrize("opt_engine_mount_point", ["path/1", "second/path"])
+ def test_vault_database_connection_configure_vault_exception(
+ self, vault_client, exc, opt_engine_mount_point, capfd
+ ):
+
+ client = vault_client
+ client.secrets.database.configure.side_effect = exc[0](exc[1])
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_connection_configure.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ match = re.search(exc[2], result["msg"])
+ assert match is not None, "result: %r\ndid not match: %s" % (result, exc[2])
+
+ assert opt_engine_mount_point == match.group(1)
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ def test_vault_database_connection_configure_success(
+ self, patch_ansible_module, empty_response, vault_client, capfd
+ ):
+ client = vault_client
+ client.secrets.database.configure.return_value = empty_response
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_connection_configure.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code == 0, "result: %r" % (result,)
+
+ client.secrets.database.configure.assert_called_once_with(
+ mount_point=patch_ansible_module["engine_mount_point"],
+ name=patch_ansible_module["connection_name"],
+ plugin_name=patch_ansible_module["plugin_name"],
+ allowed_roles=patch_ansible_module["allowed_roles"],
+ connection_url=patch_ansible_module["connection_url"],
+ username=patch_ansible_module["connection_username"],
+ password=patch_ansible_module["connection_password"],
+ )
+
+ assert result["changed"] is True
diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_connection_delete.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_connection_delete.py
new file mode 100644
index 000000000..5a24f85fa
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_connection_delete.py
@@ -0,0 +1,181 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2024 Brian Scholer (@briantist)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+import pytest
+import re
+import json
+
+from ansible.module_utils.basic import missing_required_lib
+
+from ...compat import mock
+from .....plugins.modules import vault_database_connection_delete
+from .....plugins.module_utils._hashi_vault_common import HashiVaultValueError
+
+
+hvac = pytest.importorskip("hvac")
+
+
+pytestmark = pytest.mark.usefixtures(
+ "patch_ansible_module",
+ "patch_authenticator",
+ "patch_get_vault_client",
+)
+
+
+def _connection_options():
+ return {
+ "auth_method": "token",
+ "url": "http://myvault",
+ "token": "beep-boop",
+ }
+
+
+def _sample_options():
+ return {
+ "engine_mount_point": "dbmount",
+ }
+
+
+def _sample_connection():
+ return {"connection_name": "foo"}
+
+
+def _combined_options(**kwargs):
+ opt = _connection_options()
+ opt.update(_sample_options())
+ opt.update(_sample_connection())
+ opt.update(kwargs)
+ return opt
+
+
+class TestModuleVaultDatabaseConnectionDelete:
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ @pytest.mark.parametrize(
+ "exc",
+ [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")],
+ )
+ def test_vault_database_connection_delete_authentication_error(
+ self, authenticator, exc, capfd
+ ):
+ authenticator.authenticate.side_effect = exc
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_connection_delete.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == "throwaway msg", "result: %r" % result
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ @pytest.mark.parametrize(
+ "exc",
+ [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")],
+ )
+ def test_vault_database_connection_delete_auth_validation_error(
+ self, authenticator, exc, capfd
+ ):
+ authenticator.validate.side_effect = exc
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_connection_delete.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == "throwaway msg"
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ def test_vault_database_connection_delete_success(
+ self, patch_ansible_module, empty_response, vault_client, capfd
+ ):
+ client = vault_client
+ client.secrets.database.delete_connection.return_value = empty_response
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_connection_delete.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code == 0, "result: %r" % (result,)
+
+ client.secrets.database.delete_connection.assert_called_once_with(
+ mount_point=patch_ansible_module["engine_mount_point"],
+ name=patch_ansible_module["connection_name"],
+ )
+
+ assert result["changed"] is True
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ def test_vault_database_connection_delete_no_hvac(self, capfd):
+ with mock.patch.multiple(
+ vault_database_connection_delete,
+ HAS_HVAC=False,
+ HVAC_IMPORT_ERROR=None,
+ create=True,
+ ):
+ with pytest.raises(SystemExit) as e:
+ vault_database_connection_delete.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == missing_required_lib("hvac")
+
+ @pytest.mark.parametrize(
+ "exc",
+ [
+ (
+ hvac.exceptions.Forbidden,
+ "",
+ r"^Forbidden: Permission Denied to path \['([^']+)'\]",
+ ),
+ (
+ hvac.exceptions.InvalidPath,
+ "",
+ r"^Invalid or missing path \['([^']+)/config/([^']+)'\]",
+ ),
+ ],
+ )
+ @pytest.mark.parametrize(
+ "patch_ansible_module",
+ [[_combined_options(), "engine_mount_point"]],
+ indirect=True,
+ )
+ @pytest.mark.parametrize("opt_engine_mount_point", ["path/1", "second/path"])
+ def test_vault_database_connection_delete_vault_exception(
+ self, vault_client, exc, opt_engine_mount_point, capfd
+ ):
+
+ client = vault_client
+ client.secrets.database.delete_connection.side_effect = exc[0](exc[1])
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_connection_delete.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ match = re.search(exc[2], result["msg"])
+ assert match is not None, "result: %r\ndid not match: %s" % (result, exc[2])
+
+ assert opt_engine_mount_point == match.group(1)
diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_connection_read.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_connection_read.py
new file mode 100644
index 000000000..062ff7689
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_connection_read.py
@@ -0,0 +1,200 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2024 Brian Scholer (@briantist)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+import pytest
+import re
+import json
+
+from ansible.module_utils.basic import missing_required_lib
+
+from ...compat import mock
+from .....plugins.modules import vault_database_connection_read
+from .....plugins.module_utils._hashi_vault_common import HashiVaultValueError
+
+
+hvac = pytest.importorskip("hvac")
+
+
+pytestmark = pytest.mark.usefixtures(
+ "patch_ansible_module",
+ "patch_authenticator",
+ "patch_get_vault_client",
+)
+
+
+def _connection_options():
+ return {
+ "auth_method": "token",
+ "url": "http://myvault",
+ "token": "beep-boop",
+ }
+
+
+def _sample_options():
+ return {
+ "engine_mount_point": "dbmount",
+ }
+
+
+def _sample_connection():
+ return {"connection_name": "foo"}
+
+
+def _combined_options(**kwargs):
+ opt = _connection_options()
+ opt.update(_sample_options())
+ opt.update(_sample_connection())
+ opt.update(kwargs)
+ return opt
+
+
+@pytest.fixture
+def list_response(fixture_loader):
+ return fixture_loader("database_connection_read_response.json")
+
+
+class TestModuleVaultDatabaseConnectionRead:
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ @pytest.mark.parametrize(
+ "exc",
+ [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")],
+ )
+ def test_vault_database_connection_read_authentication_error(
+ self, authenticator, exc, capfd
+ ):
+ authenticator.authenticate.side_effect = exc
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_connection_read.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == "throwaway msg", "result: %r" % result
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ @pytest.mark.parametrize(
+ "exc",
+ [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")],
+ )
+ def test_vault_database_connection_read_auth_validation_error(
+ self, authenticator, exc, capfd
+ ):
+ authenticator.validate.side_effect = exc
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_connection_read.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == "throwaway msg"
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ def test_vault_database_connection_read_return_data(
+ self, patch_ansible_module, list_response, vault_client, capfd
+ ):
+ client = vault_client
+ client.secrets.database.read_connection.return_value = list_response.copy()
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_connection_read.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code == 0, "result: %r" % (result,)
+
+ client.secrets.database.read_connection.assert_called_once_with(
+ mount_point=patch_ansible_module["engine_mount_point"],
+ name=patch_ansible_module["connection_name"],
+ )
+
+ raw = list_response.copy()
+ data = raw["data"]
+
+ assert (
+ result["raw"] == raw
+ ), "module result did not match expected result:\nexpected: %r\ngot: %r" % (
+ list_response,
+ result,
+ )
+ assert (
+ result["data"] == data
+ ), "module result did not match expected result:\nexpected: %r\ngot: %r" % (
+ list_response,
+ result,
+ )
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ def test_vault_database_connection_read_no_hvac(self, capfd):
+ with mock.patch.multiple(
+ vault_database_connection_read,
+ HAS_HVAC=False,
+ HVAC_IMPORT_ERROR=None,
+ create=True,
+ ):
+ with pytest.raises(SystemExit) as e:
+ vault_database_connection_read.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == missing_required_lib("hvac")
+
+ @pytest.mark.parametrize(
+ "exc",
+ [
+ (
+ hvac.exceptions.Forbidden,
+ "",
+ r"^Forbidden: Permission Denied to path \['([^']+)'\]",
+ ),
+ (
+ hvac.exceptions.InvalidPath,
+ "",
+ r"^Invalid or missing path \['([^']+)/config/([^']+)'\]",
+ ),
+ ],
+ )
+ @pytest.mark.parametrize(
+ "patch_ansible_module",
+ [[_combined_options(), "engine_mount_point"]],
+ indirect=True,
+ )
+ @pytest.mark.parametrize("opt_engine_mount_point", ["path/1", "second/path"])
+ def test_vault_database_connection_read_vault_exception(
+ self, vault_client, exc, opt_engine_mount_point, capfd
+ ):
+
+ client = vault_client
+ client.secrets.database.read_connection.side_effect = exc[0](exc[1])
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_connection_read.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ match = re.search(exc[2], result["msg"])
+ assert match is not None, "result: %r\ndid not match: %s" % (result, exc[2])
+
+ assert opt_engine_mount_point == match.group(1)
diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_connection_reset.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_connection_reset.py
new file mode 100644
index 000000000..bddb858fd
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_connection_reset.py
@@ -0,0 +1,181 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2024 Brian Scholer (@briantist)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+import pytest
+import re
+import json
+
+from ansible.module_utils.basic import missing_required_lib
+
+from ...compat import mock
+from .....plugins.modules import vault_database_connection_reset
+from .....plugins.module_utils._hashi_vault_common import HashiVaultValueError
+
+
+hvac = pytest.importorskip("hvac")
+
+
+pytestmark = pytest.mark.usefixtures(
+ "patch_ansible_module",
+ "patch_authenticator",
+ "patch_get_vault_client",
+)
+
+
+def _connection_options():
+ return {
+ "auth_method": "token",
+ "url": "http://myvault",
+ "token": "beep-boop",
+ }
+
+
+def _sample_options():
+ return {
+ "engine_mount_point": "dbmount",
+ }
+
+
+def _sample_connection():
+ return {"connection_name": "foo"}
+
+
+def _combined_options(**kwargs):
+ opt = _connection_options()
+ opt.update(_sample_options())
+ opt.update(_sample_connection())
+ opt.update(kwargs)
+ return opt
+
+
+class TestModuleVaultDatabaseConnectionReset:
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ @pytest.mark.parametrize(
+ "exc",
+ [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")],
+ )
+ def test_vault_database_connection_reset_authentication_error(
+ self, authenticator, exc, capfd
+ ):
+ authenticator.authenticate.side_effect = exc
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_connection_reset.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == "throwaway msg", "result: %r" % result
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ @pytest.mark.parametrize(
+ "exc",
+ [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")],
+ )
+ def test_vault_database_connection_reset_auth_validation_error(
+ self, authenticator, exc, capfd
+ ):
+ authenticator.validate.side_effect = exc
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_connection_reset.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == "throwaway msg"
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ def test_vault_database_connection_reset_success(
+ self, patch_ansible_module, empty_response, vault_client, capfd
+ ):
+ client = vault_client
+ client.secrets.database.reset_connection.return_value = empty_response
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_connection_reset.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code == 0, "result: %r" % (result,)
+
+ client.secrets.database.reset_connection.assert_called_once_with(
+ mount_point=patch_ansible_module["engine_mount_point"],
+ name=patch_ansible_module["connection_name"],
+ )
+
+ assert result["changed"] is True
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ def test_vault_database_connection_reset_no_hvac(self, capfd):
+ with mock.patch.multiple(
+ vault_database_connection_reset,
+ HAS_HVAC=False,
+ HVAC_IMPORT_ERROR=None,
+ create=True,
+ ):
+ with pytest.raises(SystemExit) as e:
+ vault_database_connection_reset.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == missing_required_lib("hvac")
+
+ @pytest.mark.parametrize(
+ "exc",
+ [
+ (
+ hvac.exceptions.Forbidden,
+ "",
+ r"^Forbidden: Permission Denied to path \['([^']+)'\]",
+ ),
+ (
+ hvac.exceptions.InvalidPath,
+ "",
+ r"^Invalid or missing path \['([^']+)/reset/([^']+)'\]",
+ ),
+ ],
+ )
+ @pytest.mark.parametrize(
+ "patch_ansible_module",
+ [[_combined_options(), "engine_mount_point"]],
+ indirect=True,
+ )
+ @pytest.mark.parametrize("opt_engine_mount_point", ["path/1", "second/path"])
+ def test_vault_database_connection_reset_vault_exception(
+ self, vault_client, exc, opt_engine_mount_point, capfd
+ ):
+
+ client = vault_client
+ client.secrets.database.reset_connection.side_effect = exc[0](exc[1])
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_connection_reset.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ match = re.search(exc[2], result["msg"])
+ assert match is not None, "result: %r\ndid not match: %s" % (result, exc[2])
+
+ assert opt_engine_mount_point == match.group(1)
diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_connections_list.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_connections_list.py
new file mode 100644
index 000000000..057adc6f6
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_connections_list.py
@@ -0,0 +1,228 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2024 Martin Chmielewski (@M4rt1nCh)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+import pytest
+import re
+import json
+
+from ansible.module_utils.basic import missing_required_lib
+
+from ...compat import mock
+from .....plugins.modules import vault_database_connections_list
+from .....plugins.module_utils._hashi_vault_common import HashiVaultValueError
+
+
+hvac = pytest.importorskip("hvac")
+
+
+pytestmark = pytest.mark.usefixtures(
+ "patch_ansible_module",
+ "patch_authenticator",
+ "patch_get_vault_client",
+)
+
+
+def _connection_options():
+ return {
+ "auth_method": "token",
+ "url": "http://myvault",
+ "token": "beep-boop",
+ }
+
+
+def _sample_options():
+ return {
+ "engine_mount_point": "dbmount",
+ }
+
+
+def _combined_options(**kwargs):
+ opt = _connection_options()
+ opt.update(_sample_options())
+ opt.update(kwargs)
+ return opt
+
+
+@pytest.fixture
+def list_response(fixture_loader):
+ return fixture_loader("database_connections_list_response.json")
+
+
+class TestModuleVaultDatabaseConnectionsList:
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ @pytest.mark.parametrize(
+ "exc",
+ [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")],
+ )
+ def test_vault_database_connections_list_authentication_error(
+ self, authenticator, exc, capfd
+ ):
+ authenticator.authenticate.side_effect = exc
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_connections_list.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == "throwaway msg", "result: %r" % result
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ @pytest.mark.parametrize(
+ "exc",
+ [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")],
+ )
+ def test_vault_database_connections_list_auth_validation_error(
+ self, authenticator, exc, capfd
+ ):
+ authenticator.validate.side_effect = exc
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_connections_list.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == "throwaway msg"
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ def test_vault_database_connections_list_return_data(
+ self, patch_ansible_module, list_response, vault_client, capfd
+ ):
+ client = vault_client
+ client.secrets.database.list_connections.return_value = list_response.copy()
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_connections_list.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code == 0, "result: %r" % (result,)
+
+ client.secrets.database.list_connections.assert_called_once_with(
+ mount_point=patch_ansible_module["engine_mount_point"]
+ )
+
+ raw = list_response.copy()
+ data = raw["data"]
+ roles = data["keys"]
+
+ assert (
+ result["raw"] == raw
+ ), "module result did not match expected result:\nexpected: %r\ngot: %r" % (
+ list_response,
+ result,
+ )
+ assert (
+ result["data"] == data
+ ), "module result did not match expected result:\nexpected: %r\ngot: %r" % (
+ list_response,
+ result,
+ )
+ assert (
+ result["connections"] == roles
+ ), "module result did not match expected result:\nexpected: %r\ngot: %r" % (
+ list_response,
+ result,
+ )
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ def test_vault_database_connections_list_no_data(
+ self, patch_ansible_module, vault_client, capfd
+ ):
+ client = vault_client
+ raw = {"errors": []}
+ client.secrets.database.list_connections.return_value = raw
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_connections_list.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code == 0, "result: %r" % (result,)
+
+ client.secrets.database.list_connections.assert_called_once_with(
+ mount_point=patch_ansible_module["engine_mount_point"]
+ )
+
+ empty_data = {"keys": []}
+ assert result["raw"] == raw
+ assert result["data"] == empty_data
+ assert result["connections"] == empty_data["keys"]
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ def test_vault_database_connections_list_no_hvac(self, capfd):
+ with mock.patch.multiple(
+ vault_database_connections_list,
+ HAS_HVAC=False,
+ HVAC_IMPORT_ERROR=None,
+ create=True,
+ ):
+ with pytest.raises(SystemExit) as e:
+ vault_database_connections_list.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == missing_required_lib("hvac")
+
+ @pytest.mark.parametrize(
+ "exc",
+ [
+ (
+ hvac.exceptions.Forbidden,
+ "",
+ r"^Forbidden: Permission Denied to path \['([^']+)'\]",
+ ),
+ (
+ hvac.exceptions.InvalidPath,
+ "",
+ r"^Invalid or missing path \['([^']+)/config'\]",
+ ),
+ ],
+ )
+ @pytest.mark.parametrize(
+ "patch_ansible_module",
+ [[_combined_options(), "engine_mount_point"]],
+ indirect=True,
+ )
+ @pytest.mark.parametrize("opt_engine_mount_point", ["path/1", "second/path"])
+ def test_vault_database_connections_list_vault_exception(
+ self, vault_client, exc, opt_engine_mount_point, capfd
+ ):
+
+ client = vault_client
+ client.secrets.database.list_connections.side_effect = exc[0](exc[1])
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_connections_list.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ match = re.search(exc[2], result["msg"])
+ assert match is not None, "result: %r\ndid not match: %s" % (result, exc[2])
+
+ assert opt_engine_mount_point == match.group(1)
diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_role_create.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_role_create.py
new file mode 100644
index 000000000..f8c752a00
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_role_create.py
@@ -0,0 +1,197 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2024 Brian Scholer (@briantist)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+import pytest
+import re
+import json
+
+from ansible.module_utils.basic import missing_required_lib
+
+from ...compat import mock
+from .....plugins.modules import vault_database_role_create
+from .....plugins.module_utils._hashi_vault_common import HashiVaultValueError
+
+
+hvac = pytest.importorskip("hvac")
+
+
+pytestmark = pytest.mark.usefixtures(
+ "patch_ansible_module",
+ "patch_authenticator",
+ "patch_get_vault_client",
+)
+
+
+def _connection_options():
+ return {
+ "auth_method": "token",
+ "url": "http://myvault",
+ "token": "beep-boop",
+ }
+
+
+def _sample_options():
+ return {
+ "engine_mount_point": "dbmount",
+ }
+
+
+def _sample_role():
+ return {
+ "role_name": "foo",
+ "connection_name": "bar",
+ "creation_statements": [
+ "CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}';",
+ 'GRANT SELECT ON ALL TABLES IN SCHEMA public TO "{{name}}";',
+ ],
+ "default_ttl": 3600,
+ "max_ttl": 86400,
+ }
+
+
+def _combined_options(**kwargs):
+ opt = _connection_options()
+ opt.update(_sample_options())
+ opt.update(_sample_role())
+ opt.update(kwargs)
+ return opt
+
+
+class TestModuleVaultDatabaseRoleCreate:
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ @pytest.mark.parametrize(
+ "exc",
+ [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")],
+ )
+ def test_vault_database_role_create_authentication_error(
+ self, authenticator, exc, capfd
+ ):
+ authenticator.authenticate.side_effect = exc
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_role_create.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == "throwaway msg", "result: %r" % result
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ @pytest.mark.parametrize(
+ "exc",
+ [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")],
+ )
+ def test_vault_database_role_create_auth_validation_error(
+ self, authenticator, exc, capfd
+ ):
+ authenticator.validate.side_effect = exc
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_role_create.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == "throwaway msg"
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ def test_vault_database_role_create_success(
+ self, patch_ansible_module, empty_response, vault_client, capfd
+ ):
+ client = vault_client
+ client.secrets.database.create_role.return_value = empty_response
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_role_create.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code == 0, "result: %r" % (result,)
+
+ client.secrets.database.create_role.assert_called_once_with(
+ name=patch_ansible_module["role_name"],
+ db_name=patch_ansible_module["connection_name"],
+ creation_statements=patch_ansible_module["creation_statements"],
+ revocation_statements=patch_ansible_module.get("revocation_statements"),
+ rollback_statements=patch_ansible_module.get("rollback_statements"),
+ renew_statements=patch_ansible_module.get("renew_statements"),
+ default_ttl=patch_ansible_module["default_ttl"],
+ max_ttl=patch_ansible_module["max_ttl"],
+ mount_point=patch_ansible_module["engine_mount_point"],
+ )
+
+ assert result["changed"] is True
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ def test_vault_database_role_create_no_hvac(self, capfd):
+ with mock.patch.multiple(
+ vault_database_role_create,
+ HAS_HVAC=False,
+ HVAC_IMPORT_ERROR=None,
+ create=True,
+ ):
+ with pytest.raises(SystemExit) as e:
+ vault_database_role_create.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == missing_required_lib("hvac")
+
+ @pytest.mark.parametrize(
+ "exc",
+ [
+ (
+ hvac.exceptions.Forbidden,
+ "",
+ r"^Forbidden: Permission Denied to path \['([^']+)'\]",
+ ),
+ (
+ hvac.exceptions.InvalidPath,
+ "",
+ r"^Invalid or missing path \['([^']+)/roles/([^']+)'\]",
+ ),
+ ],
+ )
+ @pytest.mark.parametrize(
+ "patch_ansible_module",
+ [[_combined_options(), "engine_mount_point"]],
+ indirect=True,
+ )
+ @pytest.mark.parametrize("opt_engine_mount_point", ["path/1", "second/path"])
+ def test_vault_database_role_create_vault_exception(
+ self, vault_client, exc, opt_engine_mount_point, capfd
+ ):
+
+ client = vault_client
+ client.secrets.database.create_role.side_effect = exc[0](exc[1])
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_role_create.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ match = re.search(exc[2], result["msg"])
+ assert match is not None, "result: %r\ndid not match: %s" % (result, exc[2])
+
+ assert opt_engine_mount_point == match.group(1)
diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_role_delete.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_role_delete.py
new file mode 100644
index 000000000..e0b254bd1
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_role_delete.py
@@ -0,0 +1,180 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2024 Brian Scholer (@briantist)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+import pytest
+import re
+import json
+
+from ansible.module_utils.basic import missing_required_lib
+
+from ...compat import mock
+from .....plugins.modules import vault_database_role_delete
+from .....plugins.module_utils._hashi_vault_common import HashiVaultValueError
+
+
+hvac = pytest.importorskip("hvac")
+
+pytestmark = pytest.mark.usefixtures(
+ "patch_ansible_module",
+ "patch_authenticator",
+ "patch_get_vault_client",
+)
+
+
+def _connection_options():
+ return {
+ "auth_method": "token",
+ "url": "http://myvault",
+ "token": "beep-boop",
+ }
+
+
+def _sample_options():
+ return {
+ "engine_mount_point": "dbmount",
+ }
+
+
+def _sample_role():
+ return {"role_name": "foo"}
+
+
+def _combined_options(**kwargs):
+ opt = _connection_options()
+ opt.update(_sample_options())
+ opt.update(_sample_role())
+ opt.update(kwargs)
+ return opt
+
+
+class TestModuleVaultDatabaseRoleDelete:
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ @pytest.mark.parametrize(
+ "exc",
+ [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")],
+ )
+ def test_vault_database_role_delete_authentication_error(
+ self, authenticator, exc, capfd
+ ):
+ authenticator.authenticate.side_effect = exc
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_role_delete.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == "throwaway msg", "result: %r" % result
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ @pytest.mark.parametrize(
+ "exc",
+ [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")],
+ )
+ def test_vault_database_role_delete_auth_validation_error(
+ self, authenticator, exc, capfd
+ ):
+ authenticator.validate.side_effect = exc
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_role_delete.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == "throwaway msg"
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ def test_vault_database_role_delete_success(
+ self, patch_ansible_module, empty_response, vault_client, capfd
+ ):
+ client = vault_client
+ client.secrets.database.delete_role.return_value = empty_response
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_role_delete.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code == 0, "result: %r" % (result,)
+
+ client.secrets.database.delete_role.assert_called_once_with(
+ mount_point=patch_ansible_module["engine_mount_point"],
+ name=patch_ansible_module["role_name"],
+ )
+
+ assert result["changed"] is True
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ def test_vault_database_role_delete_no_hvac(self, capfd):
+ with mock.patch.multiple(
+ vault_database_role_delete,
+ HAS_HVAC=False,
+ HVAC_IMPORT_ERROR=None,
+ create=True,
+ ):
+ with pytest.raises(SystemExit) as e:
+ vault_database_role_delete.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == missing_required_lib("hvac")
+
+ @pytest.mark.parametrize(
+ "exc",
+ [
+ (
+ hvac.exceptions.Forbidden,
+ "",
+ r"^Forbidden: Permission Denied to path \['([^']+)'\]",
+ ),
+ (
+ hvac.exceptions.InvalidPath,
+ "",
+ r"^Invalid or missing path \['([^']+)/roles/([^']+)'\]",
+ ),
+ ],
+ )
+ @pytest.mark.parametrize(
+ "patch_ansible_module",
+ [[_combined_options(), "engine_mount_point"]],
+ indirect=True,
+ )
+ @pytest.mark.parametrize("opt_engine_mount_point", ["path/1", "second/path"])
+ def test_vault_database_role_delete_vault_exception(
+ self, vault_client, exc, opt_engine_mount_point, capfd
+ ):
+
+ client = vault_client
+ client.secrets.database.delete_role.side_effect = exc[0](exc[1])
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_role_delete.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ match = re.search(exc[2], result["msg"])
+ assert match is not None, "result: %r\ndid not match: %s" % (result, exc[2])
+
+ assert opt_engine_mount_point == match.group(1)
diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_role_read.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_role_read.py
new file mode 100644
index 000000000..9dfcd4117
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_role_read.py
@@ -0,0 +1,200 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2024 Brian Scholer (@briantist)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+import pytest
+import re
+import json
+
+from ansible.module_utils.basic import missing_required_lib
+
+from ...compat import mock
+from .....plugins.modules import vault_database_role_read
+from .....plugins.module_utils._hashi_vault_common import HashiVaultValueError
+
+
+hvac = pytest.importorskip("hvac")
+
+
+pytestmark = pytest.mark.usefixtures(
+ "patch_ansible_module",
+ "patch_authenticator",
+ "patch_get_vault_client",
+)
+
+
+def _connection_options():
+ return {
+ "auth_method": "token",
+ "url": "http://myvault",
+ "token": "beep-boop",
+ }
+
+
+def _sample_options():
+ return {
+ "engine_mount_point": "dbmount",
+ }
+
+
+def _sample_role():
+ return {"role_name": "foo"}
+
+
+def _combined_options(**kwargs):
+ opt = _connection_options()
+ opt.update(_sample_options())
+ opt.update(_sample_role())
+ opt.update(kwargs)
+ return opt
+
+
+@pytest.fixture
+def list_response(fixture_loader):
+ return fixture_loader("database_role_read_response.json")
+
+
+class TestModuleVaultDatabaseRoleRead:
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ @pytest.mark.parametrize(
+ "exc",
+ [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")],
+ )
+ def test_vault_database_role_read_authentication_error(
+ self, authenticator, exc, capfd
+ ):
+ authenticator.authenticate.side_effect = exc
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_role_read.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == "throwaway msg", "result: %r" % result
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ @pytest.mark.parametrize(
+ "exc",
+ [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")],
+ )
+ def test_vault_database_role_read_auth_validation_error(
+ self, authenticator, exc, capfd
+ ):
+ authenticator.validate.side_effect = exc
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_role_read.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == "throwaway msg"
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ def test_vault_database_role_read_return_data(
+ self, patch_ansible_module, list_response, vault_client, capfd
+ ):
+ client = vault_client
+ client.secrets.database.read_role.return_value = list_response.copy()
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_role_read.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code == 0, "result: %r" % (result,)
+
+ client.secrets.database.read_role.assert_called_once_with(
+ mount_point=patch_ansible_module["engine_mount_point"],
+ name=patch_ansible_module["role_name"],
+ )
+
+ raw = list_response.copy()
+ data = raw["data"]
+
+ assert (
+ result["raw"] == raw
+ ), "module result did not match expected result:\nexpected: %r\ngot: %r" % (
+ list_response,
+ result,
+ )
+ assert (
+ result["data"] == data
+ ), "module result did not match expected result:\nexpected: %r\ngot: %r" % (
+ list_response,
+ result,
+ )
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ def test_vault_database_role_read_no_hvac(self, capfd):
+ with mock.patch.multiple(
+ vault_database_role_read,
+ HAS_HVAC=False,
+ HVAC_IMPORT_ERROR=None,
+ create=True,
+ ):
+ with pytest.raises(SystemExit) as e:
+ vault_database_role_read.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == missing_required_lib("hvac")
+
+ @pytest.mark.parametrize(
+ "exc",
+ [
+ (
+ hvac.exceptions.Forbidden,
+ "",
+ r"^Forbidden: Permission Denied to path \['([^']+)'\]",
+ ),
+ (
+ hvac.exceptions.InvalidPath,
+ "",
+ r"^Invalid or missing path \['([^']+)/roles/([^']+)'\]",
+ ),
+ ],
+ )
+ @pytest.mark.parametrize(
+ "patch_ansible_module",
+ [[_combined_options(), "engine_mount_point"]],
+ indirect=True,
+ )
+ @pytest.mark.parametrize("opt_engine_mount_point", ["path/1", "second/path"])
+ def test_vault_database_role_read_vault_exception(
+ self, vault_client, exc, opt_engine_mount_point, capfd
+ ):
+
+ client = vault_client
+ client.secrets.database.read_role.side_effect = exc[0](exc[1])
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_role_read.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ match = re.search(exc[2], result["msg"])
+ assert match is not None, "result: %r\ndid not match: %s" % (result, exc[2])
+
+ assert opt_engine_mount_point == match.group(1)
diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_roles_list.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_roles_list.py
new file mode 100644
index 000000000..bcfadb062
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_roles_list.py
@@ -0,0 +1,228 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2024 Martin Chmielewski (@M4rt1nCh)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+import pytest
+import re
+import json
+
+from ansible.module_utils.basic import missing_required_lib
+
+from ...compat import mock
+from .....plugins.modules import vault_database_roles_list
+from .....plugins.module_utils._hashi_vault_common import HashiVaultValueError
+
+
+hvac = pytest.importorskip("hvac")
+
+
+pytestmark = pytest.mark.usefixtures(
+ "patch_ansible_module",
+ "patch_authenticator",
+ "patch_get_vault_client",
+)
+
+
+def _connection_options():
+ return {
+ "auth_method": "token",
+ "url": "http://myvault",
+ "token": "beep-boop",
+ }
+
+
+def _sample_options():
+ return {
+ "engine_mount_point": "dbmount",
+ }
+
+
+def _combined_options(**kwargs):
+ opt = _connection_options()
+ opt.update(_sample_options())
+ opt.update(kwargs)
+ return opt
+
+
+@pytest.fixture
+def list_response(fixture_loader):
+ return fixture_loader("database_roles_list_response.json")
+
+
+class TestModuleVaultDatabaseRolesList:
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ @pytest.mark.parametrize(
+ "exc",
+ [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")],
+ )
+ def test_vault_database_roles_list_authentication_error(
+ self, authenticator, exc, capfd
+ ):
+ authenticator.authenticate.side_effect = exc
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_roles_list.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == "throwaway msg", "result: %r" % result
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ @pytest.mark.parametrize(
+ "exc",
+ [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")],
+ )
+ def test_vault_database_roles_list_auth_validation_error(
+ self, authenticator, exc, capfd
+ ):
+ authenticator.validate.side_effect = exc
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_roles_list.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == "throwaway msg"
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ def test_vault_database_roles_list_return_data(
+ self, patch_ansible_module, list_response, vault_client, capfd
+ ):
+ client = vault_client
+ client.secrets.database.list_roles.return_value = list_response.copy()
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_roles_list.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code == 0, "result: %r" % (result,)
+
+ client.secrets.database.list_roles.assert_called_once_with(
+ mount_point=patch_ansible_module["engine_mount_point"]
+ )
+
+ raw = list_response.copy()
+ data = raw["data"]
+ roles = data["keys"]
+
+ assert (
+ result["raw"] == raw
+ ), "module result did not match expected result:\nexpected: %r\ngot: %r" % (
+ list_response,
+ result,
+ )
+ assert (
+ result["data"] == data
+ ), "module result did not match expected result:\nexpected: %r\ngot: %r" % (
+ list_response,
+ result,
+ )
+ assert (
+ result["roles"] == roles
+ ), "module result did not match expected result:\nexpected: %r\ngot: %r" % (
+ list_response,
+ result,
+ )
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ def test_vault_database_roles_list_no_data(
+ self, patch_ansible_module, vault_client, capfd
+ ):
+ client = vault_client
+ raw = {"errors": []}
+ client.secrets.database.list_roles.return_value = raw
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_roles_list.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code == 0, "result: %r" % (result,)
+
+ client.secrets.database.list_roles.assert_called_once_with(
+ mount_point=patch_ansible_module["engine_mount_point"]
+ )
+
+ empty_data = {"keys": []}
+ assert result["raw"] == raw
+ assert result["data"] == empty_data
+ assert result["roles"] == empty_data["keys"]
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ def test_vault_database_roles_list_no_hvac(self, capfd):
+ with mock.patch.multiple(
+ vault_database_roles_list,
+ HAS_HVAC=False,
+ HVAC_IMPORT_ERROR=None,
+ create=True,
+ ):
+ with pytest.raises(SystemExit) as e:
+ vault_database_roles_list.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == missing_required_lib("hvac")
+
+ @pytest.mark.parametrize(
+ "exc",
+ [
+ (
+ hvac.exceptions.Forbidden,
+ "",
+ r"^Forbidden: Permission Denied to path \['([^']+)'\]",
+ ),
+ (
+ hvac.exceptions.InvalidPath,
+ "",
+ r"^Invalid or missing path \['([^']+)/roles'\]",
+ ),
+ ],
+ )
+ @pytest.mark.parametrize(
+ "patch_ansible_module",
+ [[_combined_options(), "engine_mount_point"]],
+ indirect=True,
+ )
+ @pytest.mark.parametrize("opt_engine_mount_point", ["path/1", "second/path"])
+ def test_vault_database_roles_list_vault_exception(
+ self, vault_client, exc, opt_engine_mount_point, capfd
+ ):
+
+ client = vault_client
+ client.secrets.database.list_roles.side_effect = exc[0](exc[1])
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_roles_list.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ match = re.search(exc[2], result["msg"])
+ assert match is not None, "result: %r\ndid not match: %s" % (result, exc[2])
+
+ assert opt_engine_mount_point == match.group(1)
diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_rotate_root_credentials.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_rotate_root_credentials.py
new file mode 100644
index 000000000..1b22aaa0c
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_rotate_root_credentials.py
@@ -0,0 +1,197 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2024 Brian Scholer (@briantist)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+import pytest
+import re
+import json
+
+from ansible.module_utils.basic import missing_required_lib
+
+from ...compat import mock
+from .....plugins.modules import vault_database_rotate_root_credentials
+from .....plugins.module_utils._hashi_vault_common import HashiVaultValueError
+
+
+hvac = pytest.importorskip("hvac")
+
+
+pytestmark = pytest.mark.usefixtures(
+ "patch_ansible_module",
+ "patch_authenticator",
+ "patch_get_vault_client",
+)
+
+
+def _connection_options():
+ return {
+ "auth_method": "token",
+ "url": "http://myvault",
+ "token": "beep-boop",
+ }
+
+
+def _sample_options():
+ return {
+ "engine_mount_point": "dbmount",
+ }
+
+
+def _sample_connection():
+ return {"connection_name": "foo"}
+
+
+def _combined_options(**kwargs):
+ opt = _connection_options()
+ opt.update(_sample_options())
+ opt.update(_sample_connection())
+ opt.update(kwargs)
+ return opt
+
+
+class TestModuleVaultDatabaseRotateRootCredentials:
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ @pytest.mark.parametrize(
+ "exc",
+ [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")],
+ )
+ def test_vault_database_rotate_root_credentials_authentication_error(
+ self, authenticator, exc, capfd
+ ):
+ authenticator.authenticate.side_effect = exc
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_rotate_root_credentials.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == "throwaway msg", "result: %r" % result
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ @pytest.mark.parametrize(
+ "exc",
+ [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")],
+ )
+ def test_vault_database_rotate_root_credentials_auth_validation_error(
+ self, authenticator, exc, capfd
+ ):
+ authenticator.validate.side_effect = exc
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_rotate_root_credentials.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == "throwaway msg"
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ def test_vault_database_rotate_root_credentials_success(
+ self, patch_ansible_module, empty_response, vault_client, capfd
+ ):
+ client = vault_client
+ client.secrets.database.rotate_root_credentials.return_value = empty_response
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_rotate_root_credentials.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code == 0, "result: %r" % (result,)
+
+ client.secrets.database.rotate_root_credentials.assert_called_once_with(
+ mount_point=patch_ansible_module["engine_mount_point"],
+ name=patch_ansible_module["connection_name"],
+ )
+
+ assert result["changed"] is True
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ def test_vault_database_rotate_root_credentials_no_hvac(self, capfd):
+ with mock.patch.multiple(
+ vault_database_rotate_root_credentials,
+ HAS_HVAC=False,
+ HVAC_IMPORT_ERROR=None,
+ create=True,
+ ):
+ with pytest.raises(SystemExit) as e:
+ vault_database_rotate_root_credentials.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == missing_required_lib("hvac")
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ def test_vault_database_rotate_root_credentials_old_hvac(self, vault_client, capfd):
+ client = vault_client
+ client.secrets.database.rotate_root_credentials.side_effect = AttributeError
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_rotate_root_credentials.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == "hvac>=2.0.0 is required"
+
+ @pytest.mark.parametrize(
+ "exc",
+ [
+ (
+ hvac.exceptions.Forbidden,
+ "",
+ r"^Forbidden: Permission Denied to path \['([^']+)'\]",
+ ),
+ (
+ hvac.exceptions.InvalidPath,
+ "",
+ r"^Invalid or missing path \['([^']+)/rotate-root/([^']+)'\]",
+ ),
+ ],
+ )
+ @pytest.mark.parametrize(
+ "patch_ansible_module",
+ [[_combined_options(), "engine_mount_point"]],
+ indirect=True,
+ )
+ @pytest.mark.parametrize("opt_engine_mount_point", ["path/1", "second/path"])
+ def test_vault_database_rotate_root_credentials_vault_exception(
+ self, vault_client, exc, opt_engine_mount_point, capfd
+ ):
+
+ client = vault_client
+ client.secrets.database.rotate_root_credentials.side_effect = exc[0](exc[1])
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_rotate_root_credentials.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ match = re.search(exc[2], result["msg"])
+ assert match is not None, "result: %r\ndid not match: %s" % (result, exc[2])
+
+ assert opt_engine_mount_point == match.group(1)
diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_static_role_create.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_static_role_create.py
new file mode 100644
index 000000000..eab22477b
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_static_role_create.py
@@ -0,0 +1,192 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2024 Brian Scholer (@briantist)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+import pytest
+import re
+import json
+
+from ansible.module_utils.basic import missing_required_lib
+
+from ...compat import mock
+from .....plugins.modules import vault_database_static_role_create
+from .....plugins.module_utils._hashi_vault_common import HashiVaultValueError
+
+
+hvac = pytest.importorskip("hvac")
+
+pytestmark = pytest.mark.usefixtures(
+ "patch_ansible_module",
+ "patch_authenticator",
+ "patch_get_vault_client",
+)
+
+
+def _connection_options():
+ return {
+ "auth_method": "token",
+ "url": "http://myvault",
+ "token": "beep-boop",
+ }
+
+
+def _sample_options():
+ return {
+ "engine_mount_point": "dbmount",
+ }
+
+
+def _sample_role():
+ return {
+ "role_name": "foo",
+ "connection_name": "bar",
+ "db_username": "baz",
+ "rotation_statements": [
+ "ALTER USER \"{{name}}\" WITH PASSWORD '{{password}}';"
+ ],
+ "rotation_period": 86400,
+ }
+
+
+def _combined_options(**kwargs):
+ opt = _connection_options()
+ opt.update(_sample_options())
+ opt.update(_sample_role())
+ opt.update(kwargs)
+ return opt
+
+
+class TestModuleVaultDatabaseStaticRoleCreate:
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ @pytest.mark.parametrize(
+ "exc",
+ [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")],
+ )
+ def test_vault_database_static_role_create_authentication_error(
+ self, authenticator, exc, capfd
+ ):
+ authenticator.authenticate.side_effect = exc
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_static_role_create.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == "throwaway msg", "result: %r" % result
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ @pytest.mark.parametrize(
+ "exc",
+ [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")],
+ )
+ def test_vault_database_static_role_create_auth_validation_error(
+ self, authenticator, exc, capfd
+ ):
+ authenticator.validate.side_effect = exc
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_static_role_create.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == "throwaway msg"
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ def test_vault_database_static_role_create_success(
+ self, patch_ansible_module, empty_response, vault_client, capfd
+ ):
+ client = vault_client
+ client.secrets.database.create_static_role.return_value = empty_response
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_static_role_create.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code == 0, "result: %r" % (result,)
+
+ client.secrets.database.create_static_role.assert_called_once_with(
+ mount_point=patch_ansible_module["engine_mount_point"],
+ name=patch_ansible_module["role_name"],
+ db_name=patch_ansible_module["connection_name"],
+ username=patch_ansible_module["db_username"],
+ rotation_statements=patch_ansible_module["rotation_statements"],
+ rotation_period=patch_ansible_module["rotation_period"],
+ )
+
+ assert result["changed"] is True
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ def test_vault_database_static_role_create_no_hvac(self, capfd):
+ with mock.patch.multiple(
+ vault_database_static_role_create,
+ HAS_HVAC=False,
+ HVAC_IMPORT_ERROR=None,
+ create=True,
+ ):
+ with pytest.raises(SystemExit) as e:
+ vault_database_static_role_create.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == missing_required_lib("hvac")
+
+ @pytest.mark.parametrize(
+ "exc",
+ [
+ (
+ hvac.exceptions.Forbidden,
+ "",
+ r"^Forbidden: Permission Denied to path \['([^']+)'\]",
+ ),
+ (
+ hvac.exceptions.InvalidPath,
+ "",
+ r"^Invalid or missing path \['([^']+)/static-roles/([^']+)'\]",
+ ),
+ ],
+ )
+ @pytest.mark.parametrize(
+ "patch_ansible_module",
+ [[_combined_options(), "engine_mount_point"]],
+ indirect=True,
+ )
+ @pytest.mark.parametrize("opt_engine_mount_point", ["path/1", "second/path"])
+ def test_vault_database_static_role_create_vault_exception(
+ self, vault_client, exc, opt_engine_mount_point, capfd
+ ):
+
+ client = vault_client
+ client.secrets.database.create_static_role.side_effect = exc[0](exc[1])
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_static_role_create.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ match = re.search(exc[2], result["msg"])
+ assert match is not None, "result: %r\ndid not match: %s" % (result, exc[2])
+
+ assert opt_engine_mount_point == match.group(1)
diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_static_role_get_credentials.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_static_role_get_credentials.py
new file mode 100644
index 000000000..b15364ab6
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_static_role_get_credentials.py
@@ -0,0 +1,202 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2024 Brian Scholer (@briantist)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+import pytest
+import re
+import json
+
+from ansible.module_utils.basic import missing_required_lib
+
+from ...compat import mock
+from .....plugins.modules import vault_database_static_role_get_credentials
+from .....plugins.module_utils._hashi_vault_common import HashiVaultValueError
+
+
+hvac = pytest.importorskip("hvac")
+
+
+pytestmark = pytest.mark.usefixtures(
+ "patch_ansible_module",
+ "patch_authenticator",
+ "patch_get_vault_client",
+)
+
+
+def _connection_options():
+ return {
+ "auth_method": "token",
+ "url": "http://myvault",
+ "token": "beep-boop",
+ }
+
+
+def _sample_options():
+ return {
+ "engine_mount_point": "dbmount",
+ }
+
+
+def _sample_role():
+ return {"role_name": "foo"}
+
+
+def _combined_options(**kwargs):
+ opt = _connection_options()
+ opt.update(_sample_options())
+ opt.update(_sample_role())
+ opt.update(kwargs)
+ return opt
+
+
+@pytest.fixture
+def list_response(fixture_loader):
+ return fixture_loader("database_static_role_get_credentials_response.json")
+
+
+class TestModuleVaultDatabaseStaticRoleGetCredentials:
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ @pytest.mark.parametrize(
+ "exc",
+ [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")],
+ )
+ def test_vault_database_static_role_get_credentials_authentication_error(
+ self, authenticator, exc, capfd
+ ):
+ authenticator.authenticate.side_effect = exc
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_static_role_get_credentials.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == "throwaway msg", "result: %r" % result
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ @pytest.mark.parametrize(
+ "exc",
+ [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")],
+ )
+ def test_vault_database_static_role_get_credentials_auth_validation_error(
+ self, authenticator, exc, capfd
+ ):
+ authenticator.validate.side_effect = exc
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_static_role_get_credentials.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == "throwaway msg"
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ def test_vault_database_static_role_get_credentials_return_data(
+ self, patch_ansible_module, list_response, vault_client, capfd
+ ):
+ client = vault_client
+ client.secrets.database.get_static_credentials.return_value = (
+ list_response.copy()
+ )
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_static_role_get_credentials.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code == 0, "result: %r" % (result,)
+
+ client.secrets.database.get_static_credentials.assert_called_once_with(
+ mount_point=patch_ansible_module["engine_mount_point"],
+ name=patch_ansible_module["role_name"],
+ )
+
+ raw = list_response.copy()
+ data = raw["data"]
+
+ assert (
+ result["raw"] == raw
+ ), "module result did not match expected result:\nexpected: %r\ngot: %r" % (
+ list_response,
+ result,
+ )
+ assert (
+ result["data"] == data
+ ), "module result did not match expected result:\nexpected: %r\ngot: %r" % (
+ list_response,
+ result,
+ )
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ def test_vault_database_static_role_get_credentials_no_hvac(self, capfd):
+ with mock.patch.multiple(
+ vault_database_static_role_get_credentials,
+ HAS_HVAC=False,
+ HVAC_IMPORT_ERROR=None,
+ create=True,
+ ):
+ with pytest.raises(SystemExit) as e:
+ vault_database_static_role_get_credentials.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == missing_required_lib("hvac")
+
+ @pytest.mark.parametrize(
+ "exc",
+ [
+ (
+ hvac.exceptions.Forbidden,
+ "",
+ r"^Forbidden: Permission Denied to path \['([^']+)'\]",
+ ),
+ (
+ hvac.exceptions.InvalidPath,
+ "",
+ r"^Invalid or missing path \['([^']+)/static-creds/([^']+)'\]",
+ ),
+ ],
+ )
+ @pytest.mark.parametrize(
+ "patch_ansible_module",
+ [[_combined_options(), "engine_mount_point"]],
+ indirect=True,
+ )
+ @pytest.mark.parametrize("opt_engine_mount_point", ["path/1", "second/path"])
+ def test_vault_database_static_role_get_credentials_vault_exception(
+ self, vault_client, exc, opt_engine_mount_point, capfd
+ ):
+
+ client = vault_client
+ client.secrets.database.get_static_credentials.side_effect = exc[0](exc[1])
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_static_role_get_credentials.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ match = re.search(exc[2], result["msg"])
+ assert match is not None, "result: %r\ndid not match: %s" % (result, exc[2])
+
+ assert opt_engine_mount_point == match.group(1)
diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_static_role_read.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_static_role_read.py
new file mode 100644
index 000000000..6a0b087b4
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_static_role_read.py
@@ -0,0 +1,200 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2024 Brian Scholer (@briantist)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+import pytest
+import re
+import json
+
+from ansible.module_utils.basic import missing_required_lib
+
+from ...compat import mock
+from .....plugins.modules import vault_database_static_role_read
+from .....plugins.module_utils._hashi_vault_common import HashiVaultValueError
+
+
+hvac = pytest.importorskip("hvac")
+
+
+pytestmark = pytest.mark.usefixtures(
+ "patch_ansible_module",
+ "patch_authenticator",
+ "patch_get_vault_client",
+)
+
+
+def _connection_options():
+ return {
+ "auth_method": "token",
+ "url": "http://myvault",
+ "token": "beep-boop",
+ }
+
+
+def _sample_options():
+ return {
+ "engine_mount_point": "dbmount",
+ }
+
+
+def _sample_role():
+ return {"role_name": "foo"}
+
+
+def _combined_options(**kwargs):
+ opt = _connection_options()
+ opt.update(_sample_options())
+ opt.update(_sample_role())
+ opt.update(kwargs)
+ return opt
+
+
+@pytest.fixture
+def list_response(fixture_loader):
+ return fixture_loader("database_static_role_read_response.json")
+
+
+class TestModuleVaultDatabaseStaticRoleRead:
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ @pytest.mark.parametrize(
+ "exc",
+ [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")],
+ )
+ def test_vault_database_static_role_read_authentication_error(
+ self, authenticator, exc, capfd
+ ):
+ authenticator.authenticate.side_effect = exc
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_static_role_read.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == "throwaway msg", "result: %r" % result
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ @pytest.mark.parametrize(
+ "exc",
+ [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")],
+ )
+ def test_vault_database_static_role_read_auth_validation_error(
+ self, authenticator, exc, capfd
+ ):
+ authenticator.validate.side_effect = exc
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_static_role_read.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == "throwaway msg"
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ def test_vault_database_static_role_read_return_data(
+ self, patch_ansible_module, list_response, vault_client, capfd
+ ):
+ client = vault_client
+ client.secrets.database.read_static_role.return_value = list_response.copy()
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_static_role_read.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code == 0, "result: %r" % (result,)
+
+ client.secrets.database.read_static_role.assert_called_once_with(
+ mount_point=patch_ansible_module["engine_mount_point"],
+ name=patch_ansible_module["role_name"],
+ )
+
+ raw = list_response.copy()
+ data = raw["data"]
+
+ assert (
+ result["raw"] == raw
+ ), "module result did not match expected result:\nexpected: %r\ngot: %r" % (
+ list_response,
+ result,
+ )
+ assert (
+ result["data"] == data
+ ), "module result did not match expected result:\nexpected: %r\ngot: %r" % (
+ list_response,
+ result,
+ )
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ def test_vault_database_static_role_read_no_hvac(self, capfd):
+ with mock.patch.multiple(
+ vault_database_static_role_read,
+ HAS_HVAC=False,
+ HVAC_IMPORT_ERROR=None,
+ create=True,
+ ):
+ with pytest.raises(SystemExit) as e:
+ vault_database_static_role_read.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == missing_required_lib("hvac")
+
+ @pytest.mark.parametrize(
+ "exc",
+ [
+ (
+ hvac.exceptions.Forbidden,
+ "",
+ r"^Forbidden: Permission Denied to path \['([^']+)'\]",
+ ),
+ (
+ hvac.exceptions.InvalidPath,
+ "",
+ r"^Invalid or missing path \['([^']+)/static-roles/([^']+)'\]",
+ ),
+ ],
+ )
+ @pytest.mark.parametrize(
+ "patch_ansible_module",
+ [[_combined_options(), "engine_mount_point"]],
+ indirect=True,
+ )
+ @pytest.mark.parametrize("opt_engine_mount_point", ["path/1", "second/path"])
+ def test_vault_database_static_role_read_vault_exception(
+ self, vault_client, exc, opt_engine_mount_point, capfd
+ ):
+
+ client = vault_client
+ client.secrets.database.read_static_role.side_effect = exc[0](exc[1])
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_static_role_read.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ match = re.search(exc[2], result["msg"])
+ assert match is not None, "result: %r\ndid not match: %s" % (result, exc[2])
+
+ assert opt_engine_mount_point == match.group(1)
diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_static_role_rotate_credentials.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_static_role_rotate_credentials.py
new file mode 100644
index 000000000..b6e266755
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_static_role_rotate_credentials.py
@@ -0,0 +1,199 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2024 Brian Scholer (@briantist)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+import pytest
+import re
+import json
+
+from ansible.module_utils.basic import missing_required_lib
+
+from ...compat import mock
+from .....plugins.modules import vault_database_static_role_rotate_credentials
+from .....plugins.module_utils._hashi_vault_common import HashiVaultValueError
+
+
+hvac = pytest.importorskip("hvac")
+
+
+pytestmark = pytest.mark.usefixtures(
+ "patch_ansible_module",
+ "patch_authenticator",
+ "patch_get_vault_client",
+)
+
+
+def _connection_options():
+ return {
+ "auth_method": "token",
+ "url": "http://myvault",
+ "token": "beep-boop",
+ }
+
+
+def _sample_options():
+ return {
+ "engine_mount_point": "dbmount",
+ }
+
+
+def _sample_role():
+ return {"role_name": "foo"}
+
+
+def _combined_options(**kwargs):
+ opt = _connection_options()
+ opt.update(_sample_options())
+ opt.update(_sample_role())
+ opt.update(kwargs)
+ return opt
+
+
+class TestModuleVaultDatabaseStaticRoleRotateCredentials:
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ @pytest.mark.parametrize(
+ "exc",
+ [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")],
+ )
+ def test_vault_database_static_role_rotate_credentials_authentication_error(
+ self, authenticator, exc, capfd
+ ):
+ authenticator.authenticate.side_effect = exc
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_static_role_rotate_credentials.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == "throwaway msg", "result: %r" % result
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ @pytest.mark.parametrize(
+ "exc",
+ [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")],
+ )
+ def test_vault_database_static_role_rotate_credentials_auth_validation_error(
+ self, authenticator, exc, capfd
+ ):
+ authenticator.validate.side_effect = exc
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_static_role_rotate_credentials.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == "throwaway msg"
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ def test_vault_database_static_role_rotate_credentials_success(
+ self, patch_ansible_module, empty_response, vault_client, capfd
+ ):
+ client = vault_client
+ client.secrets.database.rotate_static_role_credentials.return_value = empty_response
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_static_role_rotate_credentials.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code == 0, "result: %r" % (result,)
+
+ client.secrets.database.rotate_static_role_credentials.assert_called_once_with(
+ mount_point=patch_ansible_module["engine_mount_point"],
+ name=patch_ansible_module["role_name"],
+ )
+
+ assert result["changed"] is True
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ def test_vault_database_static_role_rotate_credentials_no_hvac(self, capfd):
+ with mock.patch.multiple(
+ vault_database_static_role_rotate_credentials,
+ HAS_HVAC=False,
+ HVAC_IMPORT_ERROR=None,
+ create=True,
+ ):
+ with pytest.raises(SystemExit) as e:
+ vault_database_static_role_rotate_credentials.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == missing_required_lib("hvac")
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ def test_vault_database_static_role_rotate_credentials_old_hvac(self, vault_client, capfd):
+ client = vault_client
+ client.secrets.database.rotate_static_role_credentials.side_effect = AttributeError
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_static_role_rotate_credentials.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == "hvac>=2.0.0 is required"
+
+ @pytest.mark.parametrize(
+ "exc",
+ [
+ (
+ hvac.exceptions.Forbidden,
+ "",
+ r"^Forbidden: Permission Denied to path \['([^']+)'\]",
+ ),
+ (
+ hvac.exceptions.InvalidPath,
+ "",
+ r"^Invalid or missing path \['([^']+)/rotate-role/([^']+)'\]",
+ ),
+ ],
+ )
+ @pytest.mark.parametrize(
+ "patch_ansible_module",
+ [[_combined_options(), "engine_mount_point"]],
+ indirect=True,
+ )
+ @pytest.mark.parametrize("opt_engine_mount_point", ["path/1", "second/path"])
+ def test_vault_database_static_role_rotate_credentials_vault_exception(
+ self, vault_client, exc, opt_engine_mount_point, capfd
+ ):
+
+ client = vault_client
+ client.secrets.database.rotate_static_role_credentials.side_effect = exc[0](
+ exc[1]
+ )
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_static_role_rotate_credentials.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ match = re.search(exc[2], result["msg"])
+ assert match is not None, "result: %r\ndid not match: %s" % (result, exc[2])
+
+ assert opt_engine_mount_point == match.group(1)
diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_static_roles_list.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_static_roles_list.py
new file mode 100644
index 000000000..7a028e76d
--- /dev/null
+++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_database_static_roles_list.py
@@ -0,0 +1,228 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2024 Brian Scholer (@briantist)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+import pytest
+import re
+import json
+
+from ansible.module_utils.basic import missing_required_lib
+
+from ...compat import mock
+from .....plugins.modules import vault_database_static_roles_list
+from .....plugins.module_utils._hashi_vault_common import HashiVaultValueError
+
+
+hvac = pytest.importorskip("hvac")
+
+
+pytestmark = pytest.mark.usefixtures(
+ "patch_ansible_module",
+ "patch_authenticator",
+ "patch_get_vault_client",
+)
+
+
+def _connection_options():
+ return {
+ "auth_method": "token",
+ "url": "http://myvault",
+ "token": "beep-boop",
+ }
+
+
+def _sample_options():
+ return {
+ "engine_mount_point": "dbmount",
+ }
+
+
+def _combined_options(**kwargs):
+ opt = _connection_options()
+ opt.update(_sample_options())
+ opt.update(kwargs)
+ return opt
+
+
+@pytest.fixture
+def list_response(fixture_loader):
+ return fixture_loader("database_static_roles_list_response.json")
+
+
+class TestModuleVaultDatabaseStaticRolesList:
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ @pytest.mark.parametrize(
+ "exc",
+ [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")],
+ )
+ def test_vault_database_static_roles_list_authentication_error(
+ self, authenticator, exc, capfd
+ ):
+ authenticator.authenticate.side_effect = exc
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_static_roles_list.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == "throwaway msg", "result: %r" % result
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ @pytest.mark.parametrize(
+ "exc",
+ [HashiVaultValueError("throwaway msg"), NotImplementedError("throwaway msg")],
+ )
+ def test_vault_database_static_roles_list_auth_validation_error(
+ self, authenticator, exc, capfd
+ ):
+ authenticator.validate.side_effect = exc
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_static_roles_list.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == "throwaway msg"
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ def test_vault_database_static_roles_list_return_data(
+ self, patch_ansible_module, list_response, vault_client, capfd
+ ):
+ client = vault_client
+ client.secrets.database.list_static_roles.return_value = list_response.copy()
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_static_roles_list.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code == 0, "result: %r" % (result,)
+
+ client.secrets.database.list_static_roles.assert_called_once_with(
+ mount_point=patch_ansible_module["engine_mount_point"]
+ )
+
+ raw = list_response.copy()
+ data = raw["data"]
+ roles = data["keys"]
+
+ assert (
+ result["raw"] == raw
+ ), "module result did not match expected result:\nexpected: %r\ngot: %r" % (
+ list_response,
+ result,
+ )
+ assert (
+ result["data"] == data
+ ), "module result did not match expected result:\nexpected: %r\ngot: %r" % (
+ list_response,
+ result,
+ )
+ assert (
+ result["roles"] == roles
+ ), "module result did not match expected result:\nexpected: %r\ngot: %r" % (
+ list_response,
+ result,
+ )
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ def test_vault_database_static_roles_list_no_data(
+ self, patch_ansible_module, vault_client, capfd
+ ):
+ client = vault_client
+ raw = {"errors": []}
+ client.secrets.database.list_static_roles.return_value = raw
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_static_roles_list.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code == 0, "result: %r" % (result,)
+
+ client.secrets.database.list_static_roles.assert_called_once_with(
+ mount_point=patch_ansible_module["engine_mount_point"]
+ )
+
+ empty_data = {"keys": []}
+ assert result["raw"] == raw
+ assert result["data"] == empty_data
+ assert result["roles"] == empty_data["keys"]
+
+ @pytest.mark.parametrize(
+ "patch_ansible_module", [_combined_options()], indirect=True
+ )
+ def test_vault_database_static_roles_list_no_hvac(self, capfd):
+ with mock.patch.multiple(
+ vault_database_static_roles_list,
+ HAS_HVAC=False,
+ HVAC_IMPORT_ERROR=None,
+ create=True,
+ ):
+ with pytest.raises(SystemExit) as e:
+ vault_database_static_roles_list.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert result["msg"] == missing_required_lib("hvac")
+
+ @pytest.mark.parametrize(
+ "exc",
+ [
+ (
+ hvac.exceptions.Forbidden,
+ "",
+ r"^Forbidden: Permission Denied to path \['([^']+)'\]",
+ ),
+ (
+ hvac.exceptions.InvalidPath,
+ "",
+ r"^Invalid or missing path \['([^']+)/static-roles'\]",
+ ),
+ ],
+ )
+ @pytest.mark.parametrize(
+ "patch_ansible_module",
+ [[_combined_options(), "engine_mount_point"]],
+ indirect=True,
+ )
+ @pytest.mark.parametrize("opt_engine_mount_point", ["path/1", "second/path"])
+ def test_vault_database_static_roles_list_vault_exception(
+ self, vault_client, exc, opt_engine_mount_point, capfd
+ ):
+
+ client = vault_client
+ client.secrets.database.list_static_roles.side_effect = exc[0](exc[1])
+
+ with pytest.raises(SystemExit) as e:
+ vault_database_static_roles_list.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ match = re.search(exc[2], result["msg"])
+ assert match is not None, "result: %r\ndid not match: %s" % (result, exc[2])
+
+ assert opt_engine_mount_point == match.group(1)
diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_pki_generate_certificate.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_pki_generate_certificate.py
index 29bba2165..c5374b537 100644
--- a/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_pki_generate_certificate.py
+++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_pki_generate_certificate.py
@@ -71,7 +71,7 @@ def translated_options(sample_options):
if k in toplevel:
opt[toplevel[k]] = v
else:
- if type(v) is list:
+ if isinstance(v, list):
val = ','.join(v)
else:
val = v
diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_write.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_write.py
index afe877e8d..59d2e38a1 100644
--- a/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_write.py
+++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/modules/test_vault_write.py
@@ -88,7 +88,7 @@ class TestModuleVaultWrite():
@pytest.mark.parametrize('patch_ansible_module', [[_combined_options(), 'data', 'wrap_ttl']], indirect=True)
def test_vault_write_return_data(self, patch_ansible_module, approle_secret_id_write_response, vault_client, opt_wrap_ttl, opt_data, capfd):
client = vault_client
- client.write.return_value = approle_secret_id_write_response
+ client.write_data.return_value = approle_secret_id_write_response
with pytest.raises(SystemExit) as e:
vault_write.main()
@@ -98,7 +98,7 @@ class TestModuleVaultWrite():
assert e.value.code == 0, "result: %r" % (result,)
- client.write.assert_called_once_with(path=patch_ansible_module['path'], wrap_ttl=opt_wrap_ttl, **opt_data)
+ client.write_data.assert_called_once_with(path=patch_ansible_module['path'], wrap_ttl=opt_wrap_ttl, data=opt_data)
assert result['data'] == approle_secret_id_write_response, (
"module result did not match expected result:\nmodule: %r\nexpected: %r" % (result['data'], approle_secret_id_write_response)
@@ -110,7 +110,7 @@ class TestModuleVaultWrite():
requests_unparseable_response.status_code = 204
- client.write.return_value = requests_unparseable_response
+ client.write_data.return_value = requests_unparseable_response
with pytest.raises(SystemExit) as e:
vault_write.main()
@@ -129,7 +129,7 @@ class TestModuleVaultWrite():
requests_unparseable_response.status_code = 200
requests_unparseable_response.content = '﷽'
- client.write.return_value = requests_unparseable_response
+ client.write_data.return_value = requests_unparseable_response
with pytest.raises(SystemExit) as e:
vault_write.main()
@@ -166,7 +166,7 @@ class TestModuleVaultWrite():
def test_vault_write_vault_exception(self, vault_client, exc, capfd):
client = vault_client
- client.write.side_effect = exc[0]
+ client.write_data.side_effect = exc[0]
with pytest.raises(SystemExit) as e:
vault_write.main()
@@ -176,3 +176,51 @@ class TestModuleVaultWrite():
assert e.value.code != 0, "result: %r" % (result,)
assert re.search(exc[1], result['msg']) is not None
+
+ @pytest.mark.parametrize(
+ 'opt_data',
+ [
+ {"path": 'path_value'},
+ {"wrap_ttl": 'wrap_ttl_value'},
+ {"path": 'data_value', "wrap_ttl": 'write_ttl_value'},
+ ],
+ )
+ @pytest.mark.parametrize('patch_ansible_module', [[_combined_options(), 'data']], indirect=True)
+ def test_vault_write_data_fallback_bad_params(self, vault_client, opt_data, capfd):
+ client = vault_client
+ client.mock_add_spec(['write'])
+
+ with pytest.raises(SystemExit) as e:
+ vault_write.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code != 0, "result: %r" % (result,)
+ assert re.search(r"To use 'path' or 'wrap_ttl' as data keys, use hvac >= 1\.2", result['msg']) is not None
+
+ client.write.assert_not_called()
+
+ @pytest.mark.parametrize(
+ 'opt_data',
+ [
+ {"item1": 'item1_value'},
+ {"item2": 'item2_value'},
+ {"item1": 'item1_value', "item2": 'item2_value'},
+ ],
+ )
+ @pytest.mark.parametrize('patch_ansible_module', [[_combined_options(), 'data']], indirect=True)
+ def test_vault_write_data_fallback_write(self, vault_client, opt_data, patch_ansible_module, approle_secret_id_write_response, capfd):
+ client = vault_client
+ client.mock_add_spec(['write'])
+ client.write.return_value = approle_secret_id_write_response
+
+ with pytest.raises(SystemExit) as e:
+ vault_write.main()
+
+ out, err = capfd.readouterr()
+ result = json.loads(out)
+
+ assert e.value.code == 0, "result: %r" % (result,)
+
+ client.write.assert_called_once_with(path=patch_ansible_module['path'], wrap_ttl=None, **opt_data)
diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/authentication/test_auth_token.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/authentication/test_auth_token.py
deleted file mode 100644
index 3dbc4c7fc..000000000
--- a/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/authentication/test_auth_token.py
+++ /dev/null
@@ -1,54 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2022 Brian Scholer (@briantist)
-# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
-# SPDX-License-Identifier: GPL-3.0-or-later
-
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import pytest
-
-from ansible.utils.unsafe_proxy import AnsibleUnsafe, AnsibleUnsafeBytes, AnsibleUnsafeText
-
-from ansible_collections.community.hashi_vault.tests.unit.compat import mock
-
-from ansible_collections.community.hashi_vault.plugins.module_utils._auth_method_token import (
- HashiVaultAuthMethodToken,
-)
-
-
-@pytest.fixture
-def option_dict():
- return {
- 'auth_method': 'fake',
- 'token': None,
- 'token_path': None,
- 'token_file': '.vault-token',
- 'token_validate': True,
- }
-
-
-@pytest.fixture(params=[AnsibleUnsafeBytes(b'ub_opaque'), AnsibleUnsafeText(u'ut_opaque'), b'b_opaque', u't_opaque'])
-def stringy(request):
- return request.param
-
-
-@pytest.fixture
-def auth_token(adapter, warner, deprecator):
- return HashiVaultAuthMethodToken(adapter, warner, deprecator)
-
-
-class TestAuthToken(object):
- def test_auth_token_unsafes(self, auth_token, client, adapter, stringy):
- adapter.set_option('token', stringy)
- adapter.set_option('token_validate', False)
-
- wrapper = mock.Mock(wraps=auth_token._stringify)
-
- with mock.patch.object(auth_token, '_stringify', wrapper):
- response = auth_token.authenticate(client, use_token=True, lookup_self=False)
-
- assert isinstance(response['auth']['client_token'], (bytes, type(u''))), repr(response['auth']['client_token'])
- assert isinstance(client.token, (bytes, type(u''))), repr(client.token)
- assert not isinstance(response['auth']['client_token'], AnsibleUnsafe), repr(response['auth']['client_token'])
- assert not isinstance(client.token, AnsibleUnsafe), repr(client.token)
diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/base/test_hashi_vault_lookup_base.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/base/test_hashi_vault_lookup_base.py
index 620583b41..aa71687b4 100644
--- a/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/base/test_hashi_vault_lookup_base.py
+++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/base/test_hashi_vault_lookup_base.py
@@ -8,10 +8,11 @@ __metaclass__ = type
import pytest
-from ansible.errors import AnsibleError
+from re import escape as re_escape
+
+from ansible.errors import AnsibleError, AnsibleOptionsError
from ansible.plugins.lookup import LookupBase
-from ....compat import mock
from ......plugins.plugin_utils._hashi_vault_plugin import HashiVaultPlugin
from ......plugins.plugin_utils._hashi_vault_lookup_base import HashiVaultLookupBase
@@ -72,7 +73,6 @@ class TestHashiVaultLookupBase(object):
with pytest.raises(TypeError):
parsed = hashi_vault_lookup_module.parse_kev_term('key1=value1', first_unqualified='fake')
- # TODO: v5.0.0 - should raise not warn: https://github.com/ansible-collections/community.hashi_vault/pull/350
@pytest.mark.parametrize('term', [
'one secret=two a=1 b=2',
'a=1 secret=one b=2 secret=two',
@@ -80,10 +80,10 @@ class TestHashiVaultLookupBase(object):
])
def test_parse_kev_term_duplicate_option(self, term, hashi_vault_lookup_module):
dup_key = 'secret'
- removed_in = '5.0.0'
- expected_template = "Duplicate key '%s' in the term string '%s'.\nIn version %s of the collection, this will raise an exception."
- expected_msg = expected_template % (dup_key, term, removed_in)
+ expected_template = "Duplicate key '%s' in the term string '%s'."
+ expected_msg = expected_template % (dup_key, term)
+ expected_re = re_escape(expected_msg)
+ expected_match = "^%s$" % (expected_re,)
- with mock.patch('ansible_collections.community.hashi_vault.plugins.plugin_utils._hashi_vault_lookup_base.display') as display:
+ with pytest.raises(AnsibleOptionsError, match=expected_match):
hashi_vault_lookup_module.parse_kev_term(term, plugin_name='fake', first_unqualified=dup_key)
- display.deprecated.assert_called_once_with(expected_msg, removed_in)
diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/option_adapter/conftest.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/option_adapter/conftest.py
index 5c1aa7ed6..dd292cf10 100644
--- a/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/option_adapter/conftest.py
+++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/option_adapter/conftest.py
@@ -15,18 +15,33 @@ __metaclass__ = type
import pytest
+from packaging import version
+from ansible.release import __version__ as ansible_version
from ansible.plugins import AnsiblePlugin
-from ansible_collections.community.hashi_vault.plugins.module_utils._hashi_vault_common import HashiVaultOptionAdapter
+from ......plugins.module_utils._hashi_vault_common import HashiVaultOptionAdapter
-class FakePlugin(AnsiblePlugin):
- _load_name = 'community.hashi_vault.fake'
+ver = version.parse(ansible_version)
+cutoff = version.parse('2.17')
+option_adapter_from_plugin_marks = pytest.mark.option_adapter_raise_on_missing if ver.release >= cutoff.release else []
+# https://github.com/ansible-collections/community.hashi_vault/issues/417
+
+
+def _generate_options(opts: dict) -> dict:
+ return {k: {"type": type(v).__name__} if v is not None else {} for k, v in opts.items()}
@pytest.fixture
def ansible_plugin(sample_dict):
- plugin = FakePlugin()
+ optdef = _generate_options(opts=sample_dict)
+
+ class LookupModule(AnsiblePlugin):
+ _load_name = 'community.hashi_vault.fake'
+
+ import ansible.constants as C
+ C.config.initialize_plugin_configuration_definitions("lookup", LookupModule._load_name, optdef)
+ plugin = LookupModule()
plugin._options = sample_dict
return plugin
@@ -39,7 +54,11 @@ def adapter_from_ansible_plugin(ansible_plugin):
return _create_adapter_from_ansible_plugin
-@pytest.fixture(params=['dict', 'dict_defaults', 'ansible_plugin'])
+@pytest.fixture(params=[
+ 'dict',
+ 'dict_defaults',
+ pytest.param('ansible_plugin', marks=option_adapter_from_plugin_marks),
+])
def adapter(request, adapter_from_dict, adapter_from_dict_defaults, adapter_from_ansible_plugin):
return {
'dict': adapter_from_dict,
diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/option_adapter/test_hashi_vault_option_adapter.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/option_adapter/test_hashi_vault_option_adapter.py
index e78feec17..2d6d16ae7 100644
--- a/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/option_adapter/test_hashi_vault_option_adapter.py
+++ b/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/option_adapter/test_hashi_vault_option_adapter.py
@@ -12,4 +12,4 @@ __metaclass__ = type
# So we really do want to import * and so we disable lint failure on wildcard imports.
#
# pylint: disable=wildcard-import,unused-wildcard-import
-from ansible_collections.community.hashi_vault.tests.unit.plugins.module_utils.option_adapter.test_hashi_vault_option_adapter import *
+from ...module_utils.option_adapter.test_hashi_vault_option_adapter import *
diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/test_hashi_vault_common_stringify.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/test_hashi_vault_common_stringify.py
deleted file mode 100644
index 1fcd3fd5e..000000000
--- a/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/test_hashi_vault_common_stringify.py
+++ /dev/null
@@ -1,48 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2022 Brian Scholer (@briantist)
-# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
-# SPDX-License-Identifier: GPL-3.0-or-later
-
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import pytest
-
-from ansible.utils.unsafe_proxy import AnsibleUnsafe, AnsibleUnsafeBytes, AnsibleUnsafeText
-
-from ansible_collections.community.hashi_vault.plugins.module_utils._hashi_vault_common import _stringify
-
-
-@pytest.fixture
-def uvalue():
- return u'fake123'
-
-
-@pytest.fixture
-def bvalue():
- return b'fake456'
-
-
-class TestHashiVaultCommonStringify(object):
- @pytest.mark.parametrize('unsafe', [True, False])
- def test_stringify_bytes(self, unsafe, bvalue):
- token = bvalue
- if unsafe:
- token = AnsibleUnsafeBytes(token)
-
- r = _stringify(token)
-
- assert isinstance(r, bytes)
- assert not isinstance(r, AnsibleUnsafe)
-
- @pytest.mark.parametrize('unsafe', [True, False])
- def test_stringify_unicode(self, unsafe, uvalue):
- token = uvalue
- utype = type(token)
- if unsafe:
- token = AnsibleUnsafeText(token)
-
- r = _stringify(token)
-
- assert isinstance(r, utype)
- assert not isinstance(r, AnsibleUnsafe)
diff --git a/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/test_hashi_vault_helper.py b/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/test_hashi_vault_helper.py
deleted file mode 100644
index e71e625c0..000000000
--- a/ansible_collections/community/hashi_vault/tests/unit/plugins/plugin_utils/test_hashi_vault_helper.py
+++ /dev/null
@@ -1,58 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2022 Brian Scholer (@briantist)
-# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
-# SPDX-License-Identifier: GPL-3.0-or-later
-
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import pytest
-
-from ansible.utils.unsafe_proxy import AnsibleUnsafeBytes, AnsibleUnsafeText
-
-from ansible_collections.community.hashi_vault.tests.unit.compat import mock
-from ansible_collections.community.hashi_vault.plugins.module_utils._hashi_vault_common import HashiVaultHelper
-
-
-@pytest.fixture
-def hashi_vault_helper():
- return HashiVaultHelper()
-
-
-@pytest.fixture
-def expected_stringify_candidates():
- return set([
- 'token',
- 'namespace',
- ])
-
-
-class TestHashiVaultHelper(object):
- def test_expected_stringify_candidates(self, hashi_vault_helper, expected_stringify_candidates):
- # If we add more candidates to the set without updating the tests,
- # this will help us catch that. The purpose is not to simply update
- # the set in the fixture, but to also add specific tests where appropriate.
- assert hashi_vault_helper.STRINGIFY_CANDIDATES == expected_stringify_candidates, '%r' % (
- hashi_vault_helper.STRINGIFY_CANDIDATES ^ expected_stringify_candidates
- )
-
- @pytest.mark.parametrize('input', [b'one', u'two', AnsibleUnsafeBytes(b'three'), AnsibleUnsafeText(u'four')])
- @pytest.mark.parametrize('stringify', [True, False])
- def test_get_vault_client_stringify(self, hashi_vault_helper, expected_stringify_candidates, input, stringify):
- kwargs = {
- '__no_candidate': AnsibleUnsafeText(u'value'),
- }
- expected_calls = []
- for k in expected_stringify_candidates:
- v = '%s_%s' % (k, input)
- kwargs[k] = v
- if stringify:
- expected_calls.append(mock.call(v))
-
- wrapper = mock.Mock(wraps=hashi_vault_helper._stringify)
- with mock.patch('hvac.Client'):
- with mock.patch.object(hashi_vault_helper, '_stringify', wrapper):
- hashi_vault_helper.get_vault_client(hashi_vault_stringify_args=stringify, **kwargs)
-
- assert wrapper.call_count == len(expected_calls)
- wrapper.assert_has_calls(expected_calls)
diff --git a/ansible_collections/community/hashi_vault/tests/unit/requirements.txt b/ansible_collections/community/hashi_vault/tests/unit/requirements.txt
index d8844e35b..af9366e75 100644
--- a/ansible_collections/community/hashi_vault/tests/unit/requirements.txt
+++ b/ansible_collections/community/hashi_vault/tests/unit/requirements.txt
@@ -1,15 +1,3 @@
-# the collection supports python 3.6 and higher, however the constraints for
-# earlier python versions are still needed for Ansible < 2.12 which doesn't
-# support tests/config.yml, so that unit tests (which will be skipped) won't
-# choke on installing requirements.
-hvac >= 0.10.6, != 0.10.12, != 0.10.13, < 1.0.0 ; python_version == '2.7' # bugs in 0.10.12 and 0.10.13 prevent it from working in Python 2
-hvac >= 0.10.6, < 1.0.0 ; python_version == '3.5' # py3.5 support will be dropped in 1.0.0
-hvac >= 0.10.6 ; python_version >= '3.6'
-
-# these should be satisfied naturally by the requests versions required by hvac anyway
-urllib3 >= 1.15 ; python_version >= '3.6' # we need raise_on_status for retry support to raise the correct exceptions https://github.com/urllib3/urllib3/blob/main/CHANGES.rst#115-2016-04-06
-urllib3 >= 1.15, <2.0.0 ; python_version < '3.6' # https://urllib3.readthedocs.io/en/latest/v2-roadmap.html#optimized-for-python-3-6
-
-# azure-identity 1.7.0 depends on cryptography 2.5 which drops python 2.6 support
-azure-identity < 1.7.0; python_version < '2.7'
-azure-identity; python_version >= '2.7'
+hvac
+urllib3
+azure-identity
diff --git a/ansible_collections/community/hrobot/.github/workflows/ansible-test.yml b/ansible_collections/community/hrobot/.github/workflows/ansible-test.yml
index 10a685f4c..1e66b7d29 100644
--- a/ansible_collections/community/hrobot/.github/workflows/ansible-test.yml
+++ b/ansible_collections/community/hrobot/.github/workflows/ansible-test.yml
@@ -32,6 +32,8 @@ jobs:
- stable-2.12
- stable-2.13
- stable-2.14
+ - stable-2.15
+ - stable-2.16
- devel
# Ansible-test on various stable branches does not yet work well with cgroups v2.
# Since ubuntu-latest now uses Ubuntu 22.04, we need to fall back to the ubuntu-20.04
@@ -71,6 +73,8 @@ jobs:
- stable-2.12
- stable-2.13
- stable-2.14
+ - stable-2.15
+ - stable-2.16
- devel
steps:
diff --git a/ansible_collections/community/hrobot/.github/workflows/ee.yml b/ansible_collections/community/hrobot/.github/workflows/ee.yml
index 04787e8ed..c4e751a79 100644
--- a/ansible_collections/community/hrobot/.github/workflows/ee.yml
+++ b/ansible_collections/community/hrobot/.github/workflows/ee.yml
@@ -22,25 +22,73 @@ env:
jobs:
build:
- name: Build and test EE (Ⓐ${{ matrix.runner_tag }})
+ name: Build and test EE (${{ matrix.name }})
strategy:
+ fail-fast: false
matrix:
- runner_tag:
- - devel
- - stable-2.12-latest
- - stable-2.11-latest
- - stable-2.9-latest
+ name:
+ - ''
+ ansible_core:
+ - ''
+ ansible_runner:
+ - ''
+ base_image:
+ - ''
+ pre_base:
+ - ''
+ extra_vars:
+ - ''
+ other_deps:
+ - ''
+ exclude:
+ - ansible_core: ''
+ include:
+ - name: ansible-core devel @ RHEL UBI 9
+ ansible_core: https://github.com/ansible/ansible/archive/devel.tar.gz
+ ansible_runner: ansible-runner
+ other_deps: |2
+ python_interpreter:
+ package_system: python3.11 python3.11-pip python3.11-wheel python3.11-cryptography
+ python_path: "/usr/bin/python3.11"
+ base_image: docker.io/redhat/ubi9:latest
+ pre_base: '"#"'
+ - name: ansible-core 2.15 @ Rocky Linux 9
+ ansible_core: https://github.com/ansible/ansible/archive/stable-2.15.tar.gz
+ ansible_runner: ansible-runner
+ base_image: quay.io/rockylinux/rockylinux:9
+ pre_base: '"#"'
+ - name: ansible-core 2.14 @ CentOS Stream 9
+ ansible_core: https://github.com/ansible/ansible/archive/stable-2.14.tar.gz
+ ansible_runner: ansible-runner
+ base_image: quay.io/centos/centos:stream9
+ pre_base: '"#"'
+ - name: ansible-core 2.13 @ RHEL UBI 8
+ ansible_core: https://github.com/ansible/ansible/archive/stable-2.13.tar.gz
+ ansible_runner: ansible-runner
+ other_deps: |2
+ python_interpreter:
+ package_system: python39 python39-pip python39-wheel python39-cryptography
+ base_image: docker.io/redhat/ubi8:latest
+ pre_base: '"#"'
+ - name: ansible-core 2.12 @ CentOS Stream 8
+ ansible_core: https://github.com/ansible/ansible/archive/stable-2.12.tar.gz
+ ansible_runner: ansible-runner
+ other_deps: |2
+ python_interpreter:
+ package_system: python39 python39-pip python39-wheel python39-cryptography
+ base_image: quay.io/centos/centos:stream8
+ pre_base: '"#"'
runs-on: ubuntu-latest
steps:
- name: Check out code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
path: ansible_collections/${{ env.NAMESPACE }}/${{ env.COLLECTION_NAME }}
- name: Set up Python
- uses: actions/setup-python@v4
+ uses: actions/setup-python@v5
with:
- python-version: '3.10'
+ python-version: '3.11'
- name: Install ansible-builder and ansible-navigator
run: pip install ansible-builder ansible-navigator
@@ -74,11 +122,26 @@ jobs:
# EE config
cat > execution-environment.yml <<EOF
---
- version: 1
- build_arg_defaults:
- EE_BASE_IMAGE: 'quay.io/ansible/ansible-runner:${{ matrix.runner_tag }}'
+ version: 3
dependencies:
+ ansible_core:
+ package_pip: ${{ matrix.ansible_core }}
+ ansible_runner:
+ package_pip: ${{ matrix.ansible_runner }}
galaxy: requirements.yml
+ ${{ matrix.other_deps }}
+
+ images:
+ base_image:
+ name: ${{ matrix.base_image }}
+
+ additional_build_files:
+ - src: ${COLLECTION_FILENAME}
+ dest: src
+
+ additional_build_steps:
+ prepend_base:
+ - ${{ matrix.pre_base }}
EOF
echo "::group::execution-environment.yml"
cat execution-environment.yml
@@ -88,26 +151,29 @@ jobs:
cat > requirements.yml <<EOF
---
collections:
- - name: ${COLLECTION_FILENAME}
+ - name: src/${COLLECTION_FILENAME}
type: file
EOF
echo "::group::requirements.yml"
cat requirements.yml
echo "::endgroup::"
- - name: Build image based on ${{ matrix.runner_tag }}
+ - name: Build image based on ${{ matrix.base_image }}
run: |
- mkdir -p context/_build/
- cp "${{ env.NAMESPACE }}-${{ env.COLLECTION_NAME }}"-*.tar.gz context/_build/
- ansible-builder build -v 3 -t test-ee:latest --container-runtime=podman
+ ansible-builder build --verbosity 3 --tag test-ee:latest --container-runtime docker
+
+ - name: Show images
+ run: docker image ls
- name: Run basic tests
run: >
ansible-navigator run
--mode stdout
+ --container-engine docker
--pull-policy never
--set-environment-variable ANSIBLE_PRIVATE_ROLE_VARS=true
--execution-environment-image test-ee:latest
-v
all.yml
+ ${{ matrix.extra_vars }}
working-directory: ansible_collections/${{ env.NAMESPACE }}/${{ env.COLLECTION_NAME }}/tests/ee
diff --git a/ansible_collections/community/hrobot/.github/workflows/extra-tests.yml b/ansible_collections/community/hrobot/.github/workflows/extra-tests.yml
index e00d93822..ee8964c3f 100644
--- a/ansible_collections/community/hrobot/.github/workflows/extra-tests.yml
+++ b/ansible_collections/community/hrobot/.github/workflows/extra-tests.yml
@@ -26,14 +26,14 @@ jobs:
steps:
- name: Check out code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
path: ansible_collections/${{env.NAMESPACE}}/${{env.COLLECTION_NAME}}
- name: Set up Python
- uses: actions/setup-python@v4
+ uses: actions/setup-python@v5
with:
- python-version: '3.10'
+ python-version: '3.11'
- name: Install ansible-core
run: pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check
diff --git a/ansible_collections/community/hrobot/.github/workflows/import-galaxy.yml b/ansible_collections/community/hrobot/.github/workflows/import-galaxy.yml
index 8a5d43177..0c0ee402a 100644
--- a/ansible_collections/community/hrobot/.github/workflows/import-galaxy.yml
+++ b/ansible_collections/community/hrobot/.github/workflows/import-galaxy.yml
@@ -4,7 +4,7 @@
# SPDX-License-Identifier: GPL-3.0-or-later
name: import-galaxy
-on:
+'on':
# Run CI against all pushes (direct commits, also merged PRs) to main, and all Pull Requests
push:
branches:
@@ -12,77 +12,9 @@ on:
- stable-*
pull_request:
-env:
- # Adjust this to your collection
- NAMESPACE: community
- COLLECTION_NAME: hrobot
-
jobs:
- build-collection:
- name: Build collection artifact
- runs-on: ubuntu-latest
- steps:
- - name: Check out code
- uses: actions/checkout@v3
- with:
- path: ./checkout
-
- - name: Set up Python
- uses: actions/setup-python@v4
- with:
- python-version: '3.10'
-
- - name: Install ansible-core
- run: pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check
-
- - name: Make sure galaxy.yml has version entry
- run: >-
- python -c
- 'import yaml ;
- f = open("galaxy.yml", "rb") ;
- data = yaml.safe_load(f) ;
- f.close() ;
- data["version"] = data.get("version") or "0.0.1" ;
- f = open("galaxy.yml", "wb") ;
- f.write(yaml.dump(data).encode("utf-8")) ;
- f.close() ;
- '
- working-directory: ./checkout
-
- - name: Build collection
- run: ansible-galaxy collection build
- working-directory: ./checkout
-
- - name: Copy artifact into subdirectory
- run: mkdir ./artifact && mv ./checkout/${{ env.NAMESPACE }}-${{ env.COLLECTION_NAME }}-*.tar.gz ./artifact
-
- - name: Upload artifact
- uses: actions/upload-artifact@v3
- with:
- name: ${{ env.NAMESPACE }}-${{ env.COLLECTION_NAME }}-${{ github.sha }}
- path: ./artifact/
-
import-galaxy:
- name: Import artifact with Galaxy importer
- runs-on: ubuntu-latest
- needs:
- - build-collection
- steps:
- - name: Set up Python
- uses: actions/setup-python@v4
- with:
- python-version: '3.10'
-
- - name: Install ansible-core
- run: pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check
-
- - name: Install galaxy-importer
- run: pip install galaxy-importer --disable-pip-version-check
-
- - name: Download artifact
- uses: actions/download-artifact@v3
- with:
- name: ${{ env.NAMESPACE }}-${{ env.COLLECTION_NAME }}-${{ github.sha }}
-
- - name: Run Galaxy importer
- run: python -m galaxy_importer.main ${{ env.NAMESPACE }}-${{ env.COLLECTION_NAME }}-*.tar.gz
+ permissions:
+ contents: read
+ name: Test to import built collection artifact with Galaxy importer
+ uses: ansible-community/github-action-test-galaxy-import/.github/workflows/test-galaxy-import.yml@main
diff --git a/ansible_collections/community/hrobot/.github/workflows/reuse.yml b/ansible_collections/community/hrobot/.github/workflows/reuse.yml
index 06a3fa455..51d9ac2fb 100644
--- a/ansible_collections/community/hrobot/.github/workflows/reuse.yml
+++ b/ansible_collections/community/hrobot/.github/workflows/reuse.yml
@@ -21,12 +21,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- - name: Install dependencies
- run: |
- pip install reuse
-
- - name: Check REUSE compliance
- run: |
- reuse lint
+ - name: REUSE Compliance Check
+ uses: fsfe/reuse-action@v3
diff --git a/ansible_collections/community/hrobot/CHANGELOG.md b/ansible_collections/community/hrobot/CHANGELOG.md
new file mode 100644
index 000000000..d09d85be0
--- /dev/null
+++ b/ansible_collections/community/hrobot/CHANGELOG.md
@@ -0,0 +1,358 @@
+# Community Hetzner Robot Collection Release Notes
+
+**Topics**
+
+- <a href="#v1-9-1">v1\.9\.1</a>
+ - <a href="#release-summary">Release Summary</a>
+ - <a href="#security-fixes">Security Fixes</a>
+- <a href="#v1-9-0">v1\.9\.0</a>
+ - <a href="#release-summary-1">Release Summary</a>
+ - <a href="#minor-changes">Minor Changes</a>
+ - <a href="#deprecated-features">Deprecated Features</a>
+- <a href="#v1-8-2">v1\.8\.2</a>
+ - <a href="#release-summary-2">Release Summary</a>
+ - <a href="#bugfixes">Bugfixes</a>
+- <a href="#v1-8-1">v1\.8\.1</a>
+ - <a href="#release-summary-3">Release Summary</a>
+ - <a href="#known-issues">Known Issues</a>
+- <a href="#v1-8-0">v1\.8\.0</a>
+ - <a href="#release-summary-4">Release Summary</a>
+ - <a href="#major-changes">Major Changes</a>
+ - <a href="#minor-changes-1">Minor Changes</a>
+- <a href="#v1-7-0">v1\.7\.0</a>
+ - <a href="#release-summary-5">Release Summary</a>
+ - <a href="#new-modules">New Modules</a>
+- <a href="#v1-6-0">v1\.6\.0</a>
+ - <a href="#release-summary-6">Release Summary</a>
+ - <a href="#minor-changes-2">Minor Changes</a>
+- <a href="#v1-5-2">v1\.5\.2</a>
+ - <a href="#release-summary-7">Release Summary</a>
+ - <a href="#minor-changes-3">Minor Changes</a>
+- <a href="#v1-5-1">v1\.5\.1</a>
+ - <a href="#release-summary-8">Release Summary</a>
+- <a href="#v1-5-0">v1\.5\.0</a>
+ - <a href="#release-summary-9">Release Summary</a>
+ - <a href="#minor-changes-4">Minor Changes</a>
+- <a href="#v1-4-0">v1\.4\.0</a>
+ - <a href="#release-summary-10">Release Summary</a>
+ - <a href="#minor-changes-5">Minor Changes</a>
+- <a href="#v1-3-1">v1\.3\.1</a>
+ - <a href="#release-summary-11">Release Summary</a>
+ - <a href="#bugfixes-1">Bugfixes</a>
+- <a href="#v1-3-0">v1\.3\.0</a>
+ - <a href="#release-summary-12">Release Summary</a>
+ - <a href="#minor-changes-6">Minor Changes</a>
+ - <a href="#bugfixes-2">Bugfixes</a>
+- <a href="#v1-2-3">v1\.2\.3</a>
+ - <a href="#release-summary-13">Release Summary</a>
+- <a href="#v1-2-2">v1\.2\.2</a>
+ - <a href="#release-summary-14">Release Summary</a>
+ - <a href="#bugfixes-3">Bugfixes</a>
+- <a href="#v1-2-1">v1\.2\.1</a>
+ - <a href="#release-summary-15">Release Summary</a>
+ - <a href="#minor-changes-7">Minor Changes</a>
+- <a href="#v1-2-0">v1\.2\.0</a>
+ - <a href="#release-summary-16">Release Summary</a>
+ - <a href="#minor-changes-8">Minor Changes</a>
+ - <a href="#new-modules-1">New Modules</a>
+- <a href="#v1-1-1">v1\.1\.1</a>
+ - <a href="#release-summary-17">Release Summary</a>
+ - <a href="#bugfixes-4">Bugfixes</a>
+- <a href="#v1-1-0">v1\.1\.0</a>
+ - <a href="#release-summary-18">Release Summary</a>
+ - <a href="#new-plugins">New Plugins</a>
+ - <a href="#inventory">Inventory</a>
+- <a href="#v1-0-0">v1\.0\.0</a>
+ - <a href="#release-summary-19">Release Summary</a>
+ - <a href="#breaking-changes--porting-guide">Breaking Changes / Porting Guide</a>
+
+<a id="v1-9-1"></a>
+## v1\.9\.1
+
+<a id="release-summary"></a>
+### Release Summary
+
+Bugfix release\.
+
+<a id="security-fixes"></a>
+### Security Fixes
+
+* robot inventory plugin \- make sure all data received from the Hetzner robot service server is marked as unsafe\, so remote code execution by obtaining texts that can be evaluated as templates is not possible \([https\://www\.die\-welt\.net/2024/03/remote\-code\-execution\-in\-ansible\-dynamic\-inventory\-plugins/](https\://www\.die\-welt\.net/2024/03/remote\-code\-execution\-in\-ansible\-dynamic\-inventory\-plugins/)\, [https\://github\.com/ansible\-collections/community\.hrobot/pull/99](https\://github\.com/ansible\-collections/community\.hrobot/pull/99)\)\.
+
+<a id="v1-9-0"></a>
+## v1\.9\.0
+
+<a id="release-summary-1"></a>
+### Release Summary
+
+Feature and maintenance release\.
+
+<a id="minor-changes"></a>
+### Minor Changes
+
+* robot inventory plugin \- the <code>filters</code> option has been renamed to <code>simple\_filters</code>\. The old name still works until community\.hrobot 2\.0\.0\. Then it will change to allow more complex filtering with the <code>community\.library\_inventory\_filtering\_v1</code> collection\'s functionality \([https\://github\.com/ansible\-collections/community\.hrobot/pull/94](https\://github\.com/ansible\-collections/community\.hrobot/pull/94)\)\.
+
+<a id="deprecated-features"></a>
+### Deprecated Features
+
+* robot inventory plugin \- the <code>filters</code> option has been renamed to <code>simple\_filters</code>\. The old name will stop working in community\.hrobot 2\.0\.0 \([https\://github\.com/ansible\-collections/community\.hrobot/pull/94](https\://github\.com/ansible\-collections/community\.hrobot/pull/94)\)\.
+
+<a id="v1-8-2"></a>
+## v1\.8\.2
+
+<a id="release-summary-2"></a>
+### Release Summary
+
+Maintenance release with updated documentation\.
+
+<a id="bugfixes"></a>
+### Bugfixes
+
+* Show more information \(if available\) from error messages \([https\://github\.com/ansible\-collections/community\.hrobot/pull/89](https\://github\.com/ansible\-collections/community\.hrobot/pull/89)\)\.
+
+<a id="v1-8-1"></a>
+## v1\.8\.1
+
+<a id="release-summary-3"></a>
+### Release Summary
+
+Maintenance release with updated documentation\.
+
+From this version on\, community\.hrobot is using the new [Ansible semantic markup](https\://docs\.ansible\.com/ansible/devel/dev\_guide/developing\_modules\_documenting\.html\#semantic\-markup\-within\-module\-documentation)
+in its documentation\. If you look at documentation with the ansible\-doc CLI tool
+from ansible\-core before 2\.15\, please note that it does not render the markup
+correctly\. You should be still able to read it in most cases\, but you need
+ansible\-core 2\.15 or later to see it as it is intended\. Alternatively you can
+look at [the devel docsite](https\://docs\.ansible\.com/ansible/devel/collections/community/hrobot/)
+for the rendered HTML version of the documentation of the latest release\.
+
+<a id="known-issues"></a>
+### Known Issues
+
+* Ansible markup will show up in raw form on ansible\-doc text output for ansible\-core before 2\.15\. If you have trouble deciphering the documentation markup\, please upgrade to ansible\-core 2\.15 \(or newer\)\, or read the HTML documentation on [https\://docs\.ansible\.com/ansible/devel/collections/community/hrobot/](https\://docs\.ansible\.com/ansible/devel/collections/community/hrobot/)\.
+
+<a id="v1-8-0"></a>
+## v1\.8\.0
+
+<a id="release-summary-4"></a>
+### Release Summary
+
+Feature release for the Hetzner firewall changes\.
+
+<a id="major-changes"></a>
+### Major Changes
+
+* firewall \- Hetzner added output rules support to the firewall\. This change unfortunately means that using old versions of the firewall module will always set the output rule list to empty\, thus disallowing the server to send out packets \([https\://github\.com/ansible\-collections/community\.hrobot/issues/75](https\://github\.com/ansible\-collections/community\.hrobot/issues/75)\, [https\://github\.com/ansible\-collections/community\.hrobot/pull/76](https\://github\.com/ansible\-collections/community\.hrobot/pull/76)\)\.
+
+<a id="minor-changes-1"></a>
+### Minor Changes
+
+* firewall\, firewall\_info \- add <code>filter\_ipv6</code> and <code>rules\.output</code> output to support the new IPv6 filtering and output rules features \([https\://github\.com/ansible\-collections/community\.hrobot/issues/75](https\://github\.com/ansible\-collections/community\.hrobot/issues/75)\, [https\://github\.com/ansible\-collections/community\.hrobot/pull/76](https\://github\.com/ansible\-collections/community\.hrobot/pull/76)\)\.
+* firewall\, firewall\_info \- add <code>server\_number</code> option that can be used instead of <code>server\_ip</code> to identify the server\. Hetzner deprecated configuring the firewall by <code>server\_ip</code>\, so using <code>server\_ip</code> will stop at some point in the future \([https\://github\.com/ansible\-collections/community\.hrobot/pull/77](https\://github\.com/ansible\-collections/community\.hrobot/pull/77)\)\.
+
+<a id="v1-7-0"></a>
+## v1\.7\.0
+
+<a id="release-summary-5"></a>
+### Release Summary
+
+Feature release\.
+
+<a id="new-modules"></a>
+### New Modules
+
+* community\.hrobot\.v\_switch \- Manage Hetzner\'s vSwitch
+
+<a id="v1-6-0"></a>
+## v1\.6\.0
+
+<a id="release-summary-6"></a>
+### Release Summary
+
+Feature release with improved documentation\.
+
+<a id="minor-changes-2"></a>
+### Minor Changes
+
+* Added a <code>community\.hrobot\.robot</code> module defaults group / action group\. Use with <code>group/community\.hrobot\.robot</code> to provide options for all Hetzner Robot modules \([https\://github\.com/ansible\-collections/community\.hrobot/pull/65](https\://github\.com/ansible\-collections/community\.hrobot/pull/65)\)\.
+
+<a id="v1-5-2"></a>
+## v1\.5\.2
+
+<a id="release-summary-7"></a>
+### Release Summary
+
+Maintenance release with a documentation improvement\.
+
+<a id="minor-changes-3"></a>
+### Minor Changes
+
+* The collection repository conforms to the [REUSE specification](https\://reuse\.software/spec/) except for the changelog fragments \([https\://github\.com/ansible\-collections/community\.hrobot/pull/60](https\://github\.com/ansible\-collections/community\.hrobot/pull/60)\)\.
+
+<a id="v1-5-1"></a>
+## v1\.5\.1
+
+<a id="release-summary-8"></a>
+### Release Summary
+
+Maintenance release with small documentation fixes\.
+
+<a id="v1-5-0"></a>
+## v1\.5\.0
+
+<a id="release-summary-9"></a>
+### Release Summary
+
+Maintenance release changing the way licenses are declared\. No functional changes\.
+
+<a id="minor-changes-4"></a>
+### Minor Changes
+
+* All software licenses are now in the <code>LICENSES/</code> directory of the collection root\. Moreover\, <code>SPDX\-License\-Identifier\:</code> is used to declare the applicable license for every file that is not automatically generated \([https\://github\.com/ansible\-collections/community\.hrobot/pull/52](https\://github\.com/ansible\-collections/community\.hrobot/pull/52)\)\.
+
+<a id="v1-4-0"></a>
+## v1\.4\.0
+
+<a id="release-summary-10"></a>
+### Release Summary
+
+Feature release\.
+
+<a id="minor-changes-5"></a>
+### Minor Changes
+
+* robot inventory plugin \- allow to template <code>hetzner\_user</code> and <code>hetzner\_password</code> \([https\://github\.com/ansible\-collections/community\.hrobot/pull/49](https\://github\.com/ansible\-collections/community\.hrobot/pull/49)\)\.
+
+<a id="v1-3-1"></a>
+## v1\.3\.1
+
+<a id="release-summary-11"></a>
+### Release Summary
+
+Maintenance release\.
+
+<a id="bugfixes-1"></a>
+### Bugfixes
+
+* Include <code>simplified\_bsd\.txt</code> license file for the <code>robot</code> and <code>failover</code> module utils\.
+
+<a id="v1-3-0"></a>
+## v1\.3\.0
+
+<a id="release-summary-12"></a>
+### Release Summary
+
+Feature and bugfix release\.
+
+<a id="minor-changes-6"></a>
+### Minor Changes
+
+* Prepare collection for inclusion in an Execution Environment by declaring its dependencies \([https\://github\.com/ansible\-collections/community\.hrobot/pull/45](https\://github\.com/ansible\-collections/community\.hrobot/pull/45)\)\.
+
+<a id="bugfixes-2"></a>
+### Bugfixes
+
+* robot inventory plugin \- do not crash if a server neither has name or primary IP set\. Instead\, fall back to using the server\'s number as the name\. This can happen if unnamed rack reservations show up in your server list \([https\://github\.com/ansible\-collections/community\.hrobot/issues/40](https\://github\.com/ansible\-collections/community\.hrobot/issues/40)\, [https\://github\.com/ansible\-collections/community\.hrobot/pull/47](https\://github\.com/ansible\-collections/community\.hrobot/pull/47)\)\.
+
+<a id="v1-2-3"></a>
+## v1\.2\.3
+
+<a id="release-summary-13"></a>
+### Release Summary
+
+Docs update release\.
+
+<a id="v1-2-2"></a>
+## v1\.2\.2
+
+<a id="release-summary-14"></a>
+### Release Summary
+
+Bugfix release\.
+
+<a id="bugfixes-3"></a>
+### Bugfixes
+
+* boot \- fix incorrect handling of SSH authorized keys \([https\://github\.com/ansible\-collections/community\.hrobot/issues/32](https\://github\.com/ansible\-collections/community\.hrobot/issues/32)\, [https\://github\.com/ansible\-collections/community\.hrobot/pull/33](https\://github\.com/ansible\-collections/community\.hrobot/pull/33)\)\.
+
+<a id="v1-2-1"></a>
+## v1\.2\.1
+
+<a id="release-summary-15"></a>
+### Release Summary
+
+Maintenance release\.
+
+<a id="minor-changes-7"></a>
+### Minor Changes
+
+* Generic module HTTP support code \- fix usage of <code>fetch\_url</code> with changes in latest ansible\-core <code>devel</code> branch \([https\://github\.com/ansible\-collections/community\.hrobot/pull/30](https\://github\.com/ansible\-collections/community\.hrobot/pull/30)\)\.
+
+<a id="v1-2-0"></a>
+## v1\.2\.0
+
+<a id="release-summary-16"></a>
+### Release Summary
+
+Feature release with multiple new modules\.
+
+<a id="minor-changes-8"></a>
+### Minor Changes
+
+* Avoid internal ansible\-core module\_utils in favor of equivalent public API available since at least Ansible 2\.9 \([https\://github\.com/ansible\-collections/community\.hrobot/pull/18](https\://github\.com/ansible\-collections/community\.hrobot/pull/18)\)\.
+* firewall \- rename option <code>whitelist\_hos</code> to <code>allowlist\_hos</code>\, keep old name as alias \([https\://github\.com/ansible\-collections/community\.hrobot/pull/15](https\://github\.com/ansible\-collections/community\.hrobot/pull/15)\)\.
+* firewall\, firewall\_info \- add return value <code>allowlist\_hos</code>\, which contains the same value as <code>whitelist\_hos</code>\. The old name <code>whitelist\_hos</code> will be removed eventually \([https\://github\.com/ansible\-collections/community\.hrobot/pull/15](https\://github\.com/ansible\-collections/community\.hrobot/pull/15)\)\.
+* robot module utils \- add <code>allow\_empty\_result</code> parameter to <code>plugin\_open\_url\_json</code> and <code>fetch\_url\_json</code> \([https\://github\.com/ansible\-collections/community\.hrobot/pull/16](https\://github\.com/ansible\-collections/community\.hrobot/pull/16)\)\.
+
+<a id="new-modules-1"></a>
+### New Modules
+
+* community\.hrobot\.boot \- Set boot configuration
+* community\.hrobot\.reset \- Reset a dedicated server
+* community\.hrobot\.reverse\_dns \- Set or remove reverse DNS entry for IP
+* community\.hrobot\.server \- Update server information
+* community\.hrobot\.server\_info \- Query information on one or more servers
+* community\.hrobot\.ssh\_key \- Add\, remove or update SSH key
+* community\.hrobot\.ssh\_key\_info \- Query information on SSH keys
+
+<a id="v1-1-1"></a>
+## v1\.1\.1
+
+<a id="release-summary-17"></a>
+### Release Summary
+
+Bugfix release which reduces the number of HTTPS queries for the modules and plugins\.
+
+<a id="bugfixes-4"></a>
+### Bugfixes
+
+* robot \- force HTTP basic authentication to reduce number of HTTPS requests \([https\://github\.com/ansible\-collections/community\.hrobot/pull/9](https\://github\.com/ansible\-collections/community\.hrobot/pull/9)\)\.
+
+<a id="v1-1-0"></a>
+## v1\.1\.0
+
+<a id="release-summary-18"></a>
+### Release Summary
+
+Release with a new inventory plugin\.
+
+<a id="new-plugins"></a>
+### New Plugins
+
+<a id="inventory"></a>
+#### Inventory
+
+* community\.hrobot\.robot \- Hetzner Robot inventory source
+
+<a id="v1-0-0"></a>
+## v1\.0\.0
+
+<a id="release-summary-19"></a>
+### Release Summary
+
+The <code>community\.hrobot</code> continues the work on the Hetzner Robot modules from their state in <code>community\.general</code> 1\.2\.0\. The changes listed here are thus relative to the modules <code>community\.general\.hetzner\_\*</code>\.
+
+<a id="breaking-changes--porting-guide"></a>
+### Breaking Changes / Porting Guide
+
+* firewall \- now requires the [ipaddress](https\://pypi\.org/project/ipaddress/) library \([https\://github\.com/ansible\-collections/community\.hrobot/pull/2](https\://github\.com/ansible\-collections/community\.hrobot/pull/2)\)\.
diff --git a/ansible_collections/community/hrobot/CHANGELOG.md.license b/ansible_collections/community/hrobot/CHANGELOG.md.license
new file mode 100644
index 000000000..edff8c768
--- /dev/null
+++ b/ansible_collections/community/hrobot/CHANGELOG.md.license
@@ -0,0 +1,3 @@
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
+SPDX-FileCopyrightText: Ansible Project
diff --git a/ansible_collections/community/hrobot/CHANGELOG.rst b/ansible_collections/community/hrobot/CHANGELOG.rst
index 9b7559cbf..847d3dbda 100644
--- a/ansible_collections/community/hrobot/CHANGELOG.rst
+++ b/ansible_collections/community/hrobot/CHANGELOG.rst
@@ -4,6 +4,71 @@ Community Hetzner Robot Collection Release Notes
.. contents:: Topics
+v1.9.1
+======
+
+Release Summary
+---------------
+
+Bugfix release.
+
+Security Fixes
+--------------
+
+- robot inventory plugin - make sure all data received from the Hetzner robot service server is marked as unsafe, so remote code execution by obtaining texts that can be evaluated as templates is not possible (https://www.die-welt.net/2024/03/remote-code-execution-in-ansible-dynamic-inventory-plugins/, https://github.com/ansible-collections/community.hrobot/pull/99).
+
+v1.9.0
+======
+
+Release Summary
+---------------
+
+Feature and maintenance release.
+
+Minor Changes
+-------------
+
+- robot inventory plugin - the ``filters`` option has been renamed to ``simple_filters``. The old name still works until community.hrobot 2.0.0. Then it will change to allow more complex filtering with the ``community.library_inventory_filtering_v1`` collection's functionality (https://github.com/ansible-collections/community.hrobot/pull/94).
+
+Deprecated Features
+-------------------
+
+- robot inventory plugin - the ``filters`` option has been renamed to ``simple_filters``. The old name will stop working in community.hrobot 2.0.0 (https://github.com/ansible-collections/community.hrobot/pull/94).
+
+v1.8.2
+======
+
+Release Summary
+---------------
+
+Maintenance release with updated documentation.
+
+Bugfixes
+--------
+
+- Show more information (if available) from error messages (https://github.com/ansible-collections/community.hrobot/pull/89).
+
+v1.8.1
+======
+
+Release Summary
+---------------
+
+Maintenance release with updated documentation.
+
+From this version on, community.hrobot is using the new `Ansible semantic markup
+<https://docs.ansible.com/ansible/devel/dev_guide/developing_modules_documenting.html#semantic-markup-within-module-documentation>`__
+in its documentation. If you look at documentation with the ansible-doc CLI tool
+from ansible-core before 2.15, please note that it does not render the markup
+correctly. You should be still able to read it in most cases, but you need
+ansible-core 2.15 or later to see it as it is intended. Alternatively you can
+look at `the devel docsite <https://docs.ansible.com/ansible/devel/collections/community/hrobot/>`__
+for the rendered HTML version of the documentation of the latest release.
+
+Known Issues
+------------
+
+- Ansible markup will show up in raw form on ansible-doc text output for ansible-core before 2.15. If you have trouble deciphering the documentation markup, please upgrade to ansible-core 2.15 (or newer), or read the HTML documentation on https://docs.ansible.com/ansible/devel/collections/community/hrobot/.
v1.8.0
======
@@ -226,7 +291,6 @@ Release Summary
The ``community.hrobot`` continues the work on the Hetzner Robot modules from their state in ``community.general`` 1.2.0. The changes listed here are thus relative to the modules ``community.general.hetzner_*``.
-
Breaking Changes / Porting Guide
--------------------------------
diff --git a/ansible_collections/community/hrobot/FILES.json b/ansible_collections/community/hrobot/FILES.json
index 9576b95d8..54c28f1e6 100644
--- a/ansible_collections/community/hrobot/FILES.json
+++ b/ansible_collections/community/hrobot/FILES.json
@@ -25,7 +25,7 @@
"name": ".github/workflows/ansible-test.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3a0024831cf7cc7a832b0478ae964e70e3713af496ce78904f1c820b3878507c",
+ "chksum_sha256": "b221558d1b9e91f2f1b3087eca7455efea6016a313388315d94c748a736f6d0c",
"format": 1
},
{
@@ -46,28 +46,28 @@
"name": ".github/workflows/ee.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2ec44891b83956d4816fef844f14e692e56dcd9f46b96aa55dcfa838f1290181",
+ "chksum_sha256": "03c5a4a0a65ebe7d5b9683d95f2752cdbbcac4d4b8cca513d4332d80dd1c79c2",
"format": 1
},
{
"name": ".github/workflows/extra-tests.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1dddc4fefe3721d4daf55419948d65be8f05579a015b37e4229fbb1475ae3958",
+ "chksum_sha256": "3d4972a65972c0091b7343e287eba10382716e29fd184091b1f8b4df4892fe44",
"format": 1
},
{
"name": ".github/workflows/import-galaxy.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "220b0bab6530dfbbe6031eb7d7e569b20af32cfcb82b4bfa8d3e08e7450d9b89",
+ "chksum_sha256": "739c36223d6e0e6ccc98907c43cba53296e7b1ccd64a2d995c2ff21df4ab25a5",
"format": 1
},
{
"name": ".github/workflows/reuse.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c9cc8b1cebfde4ee00c680356325d514c3ee3fa792e04cc6f5d74740fbfd61b4",
+ "chksum_sha256": "bc2800b679cfe401b8c7a7188a8669f2717425390947fd0dba6477797d2dc614",
"format": 1
},
{
@@ -137,7 +137,7 @@
"name": "changelogs/changelog.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3a3089a66ec4db61793fea71c17024c3aeef4e89818d70ea3d15a67bb2b7a1a9",
+ "chksum_sha256": "7bb1dd839047930188a470f49ab846872b8b5fed15a0ad79f2a4f6badc7ca08f",
"format": 1
},
{
@@ -151,7 +151,7 @@
"name": "changelogs/config.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "34aff4539b48607175563a83f71ec1c66ee23a2e94906915fe3ac3d89a4d68ef",
+ "chksum_sha256": "a7b8fa9406e8d12b8783432c8dcbec5e940b502649eb8d4c1bbc18bcac0c7ede",
"format": 1
},
{
@@ -235,7 +235,7 @@
"name": "plugins/inventory/robot.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f012c1189cc2df209e97e7dd5fa8d2502f192abeb922d7dff3d4918fe3f9ca83",
+ "chksum_sha256": "08386e031100da8e3ae8d8a76fdf511b71ebce6d5b9648dc24f32784ee497fda",
"format": 1
},
{
@@ -256,7 +256,7 @@
"name": "plugins/module_utils/robot.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "dcfd4d5f6854cc2c82f9239d05c0625fdcf38b18b67b4cab8ecdf391afdb6e9e",
+ "chksum_sha256": "61fd87bec43eae7bc08f2414c51b4f479ebca17d7e0be5d9d337c75392dd6bf0",
"format": 1
},
{
@@ -270,70 +270,70 @@
"name": "plugins/modules/boot.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f9f0adbcd0ce63cebde36f20795961d5c678465b764bd037900cf3c14fb540a7",
+ "chksum_sha256": "6e602be89c58a047b8b0874a462e950340f1ae5c0066876efc3c6826f9fd1464",
"format": 1
},
{
"name": "plugins/modules/failover_ip.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c22701e1a41409a583dc8d9bc8f3aee0c5caf61711d1796729c571ce6baf68bc",
+ "chksum_sha256": "73945727cd5ebb8330f0089d7ac6c429b457863fffc0fbfb3fd3309041b23c4c",
"format": 1
},
{
"name": "plugins/modules/failover_ip_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a732a481bf7bd2d7956e2b7c73b58e4631dff3a491a38cea47aafa7fc87d70b3",
+ "chksum_sha256": "6876f306910f6b3339eb45482bba2563789b92a529f026e174e1d35f4bf6e39d",
"format": 1
},
{
"name": "plugins/modules/firewall.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8fd6d3567e7077bd4f94c40be87e6519f5e3fe24dcb60559b3c28c133fe1d0e5",
+ "chksum_sha256": "91a1096959175c8a038b4baeadd13cea05f852579f7f09542f653136bd9f9b6e",
"format": 1
},
{
"name": "plugins/modules/firewall_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2492c517ba7e4440913d7760f1cb47b33fe5dbc41ae6e738d08986b0eacdcbce",
+ "chksum_sha256": "c4b7b4012cda86c3ad336c148ceafead1454c3a8de2325372dbb3ba797ca8024",
"format": 1
},
{
"name": "plugins/modules/reset.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c326bd880106c020c0a923b9b2239e5fa7ca02f92df5a2100aef8fd8a2ea83ef",
+ "chksum_sha256": "e6a78514fec243ac08dbdb9f258b297b9e10dd3374b98941694e9ef67008c22a",
"format": 1
},
{
"name": "plugins/modules/reverse_dns.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "64521ba301cc273f59deb696ab80d8529f3297d9e1dc8d2470926f45ff114c7b",
+ "chksum_sha256": "5a976d175cc922ecb5cc04d2c076a84794b5c8033369870ff648344fa2c6c4e9",
"format": 1
},
{
"name": "plugins/modules/server.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2448b78e391940eb6fb4a955c1d24f5e54a1f519d24dc3e60b30efb4cca916f2",
+ "chksum_sha256": "7d2fa319fa2ed98d511daab1f576d46d551b4785d3a9e18a7d44d95b43234934",
"format": 1
},
{
"name": "plugins/modules/server_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "08f5cb04db19a18ca3ec6fc3cfb01adf6f174dc94c4befb826f854ac0fab42d7",
+ "chksum_sha256": "057ee56dbd104fb5bd2031ebef68c6c93cf378342029cab26e4c671d9346716c",
"format": 1
},
{
"name": "plugins/modules/ssh_key.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "56d3a5ef901a3c692d6f5f3dc7a07da8a384fdfefb1d7ad7bcde0e7cae0092ae",
+ "chksum_sha256": "8df71f0d30ffbfc928851111c023ee1c2907194a73e1f9abf2b485c09dcaa823",
"format": 1
},
{
@@ -347,7 +347,7 @@
"name": "plugins/modules/v_switch.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0769c7829fc91038fb4b7ea446d3a5f3fafc3a3d0ec4c6085158d8ae741fe053",
+ "chksum_sha256": "bfd0a37f238dead342b88bcce0ea8f6d1e45819d6e1e1335f1cfef450529828d",
"format": 1
},
{
@@ -431,7 +431,7 @@
"name": "tests/sanity/extra/extra-docs.json",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "63af024dcda47dda7e3cead05953d33c858853d2adc046efb47af28a6a0dc96b",
+ "chksum_sha256": "6c7fbc8a07fa803ce062387232eb0d0198a311f5347493f06c19a07aa45a9bf6",
"format": 1
},
{
@@ -445,7 +445,7 @@
"name": "tests/sanity/extra/extra-docs.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "00ae2a5eeec7f3a621074473ee4d0d16f763c67e1c6c1b2f4b7dcd3ca171262c",
+ "chksum_sha256": "c52e316daf1292bbb063be19429fd1f06e02bce3c9d4622a8dfc61fa3af06688",
"format": 1
},
{
@@ -582,6 +582,34 @@
"format": 1
},
{
+ "name": "tests/sanity/ignore-2.16.txt",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "5264853edb2c6ff138f5496111c1e758a3a54b61e82d96c0072cb9429fb31c6e",
+ "format": 1
+ },
+ {
+ "name": "tests/sanity/ignore-2.16.txt.license",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6eb915239f9f35407fa68fdc41ed6522f1fdcce11badbdcd6057548023179ac1",
+ "format": 1
+ },
+ {
+ "name": "tests/sanity/ignore-2.17.txt",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "5264853edb2c6ff138f5496111c1e758a3a54b61e82d96c0072cb9429fb31c6e",
+ "format": 1
+ },
+ {
+ "name": "tests/sanity/ignore-2.17.txt.license",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6eb915239f9f35407fa68fdc41ed6522f1fdcce11badbdcd6057548023179ac1",
+ "format": 1
+ },
+ {
"name": "tests/sanity/ignore-2.9.txt",
"ftype": "file",
"chksum_type": "sha256",
@@ -620,7 +648,7 @@
"name": "tests/unit/plugins/inventory/test_robot.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1e7aebcb567bfb2c8dd055e5ea6ccb4cb175b4e7df992868e0ef0df2b47cbaf1",
+ "chksum_sha256": "673ffae43e3a3584719643a42bbdd33321b2b8331629a9d069793c3925d21c35",
"format": 1
},
{
@@ -634,14 +662,14 @@
"name": "tests/unit/plugins/module_utils/test_failover.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "19106763b057e212a13597775a82f939f5b6959b317e93fe3188a64284d8797f",
+ "chksum_sha256": "d6072cde4dbaef7af6400d9e417c7e647607628826c732dbc1b16f53f2e46f6c",
"format": 1
},
{
"name": "tests/unit/plugins/module_utils/test_robot.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c8ccfce1d5a536b29c4ce5ab7529e75dc893e4d15f66032fc7b6fa9c6af4e1f0",
+ "chksum_sha256": "20bb76b45cfd9c002089324c941f9ed34e48635781b30c3a808ce3892bbfae03",
"format": 1
},
{
@@ -743,6 +771,13 @@
"format": 1
},
{
+ "name": "tests/unit/requirements.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "999b6bb4a4234b1f38abb63cbd57d40af2d93bcff2260ab088e09157a055abaf",
+ "format": 1
+ },
+ {
"name": "tests/config.yml",
"ftype": "file",
"chksum_type": "sha256",
@@ -750,17 +785,24 @@
"format": 1
},
{
- "name": "tests/requirements.yml",
+ "name": "CHANGELOG.md",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "2c4facb0c77d486fd61f1ea78cd2bee7c6cf833fc4dd328b57a9a440efe43db3",
+ "format": 1
+ },
+ {
+ "name": "CHANGELOG.md.license",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d556aaf12dcf49749ad88e27cb3b2c9995de47c1eccde8b73de744b21ca218cc",
+ "chksum_sha256": "6eb915239f9f35407fa68fdc41ed6522f1fdcce11badbdcd6057548023179ac1",
"format": 1
},
{
"name": "CHANGELOG.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "240999c1e8b017228a03f0c6fb48e35a637e650fa4fb022fdc2c35d480ba7615",
+ "chksum_sha256": "ca10d6a2a30e1165b9325897d7c6335ff8b3a50859742e2e4333070df0e6c38f",
"format": 1
},
{
@@ -781,7 +823,7 @@
"name": "README.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7ffc02a04b50194cf13c5b6b54372e3e29939dafc7efe965ca5193d27f64b6ea",
+ "chksum_sha256": "b26ea8090f24cde8afb282f7779abf6ce363edbf65068631c38984c5ed51ba70",
"format": 1
},
{
diff --git a/ansible_collections/community/hrobot/MANIFEST.json b/ansible_collections/community/hrobot/MANIFEST.json
index 74cd2a6f1..5fd6295d8 100644
--- a/ansible_collections/community/hrobot/MANIFEST.json
+++ b/ansible_collections/community/hrobot/MANIFEST.json
@@ -2,7 +2,7 @@
"collection_info": {
"namespace": "community",
"name": "hrobot",
- "version": "1.8.0",
+ "version": "1.9.1",
"authors": [
"Felix Fontein (github.com/felixfontein)"
],
@@ -30,7 +30,7 @@
"name": "FILES.json",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1d5553b60ed857cfc979fd52b7531a8135bec6bde395b4ec3e1356daa2fab3bb",
+ "chksum_sha256": "cada2fa56571e4857ace197d0dd1c09e665fdd718cea048c0327ba8ef3447245",
"format": 1
},
"format": 1
diff --git a/ansible_collections/community/hrobot/README.md b/ansible_collections/community/hrobot/README.md
index 2f78a9aef..44ee9ddcd 100644
--- a/ansible_collections/community/hrobot/README.md
+++ b/ansible_collections/community/hrobot/README.md
@@ -15,7 +15,7 @@ Please note that this collection does **not** support Windows targets.
## Tested with Ansible
-Tested with the current Ansible 2.9, ansible-base 2.10, ansible-core 2.11, ansible-core 2.12, ansible-core 2.13, and ansible-core 2.14 releases and the current development version of ansible-core. Ansible versions before 2.9.10 are not supported.
+Tested with the current Ansible 2.9, ansible-base 2.10, ansible-core 2.11, ansible-core 2.12, ansible-core 2.13, ansible-core 2.14, ansible-core 2.15, and ansible-core 2.16 releases and the current development version of ansible-core. Ansible versions before 2.9.10 are not supported.
## External requirements
@@ -37,7 +37,7 @@ If you use the Ansible package and do not update collections independently, use
- `community.hrobot.failover_ip_info` module
- `community.hrobot.firewall` module
- `community.hrobot.firewall_info` module
-- `community.hrobot.hrobot` inventory plugin
+- `community.hrobot.robot` inventory plugin
You can find [documentation for the modules and plugins in this collection here](https://docs.ansible.com/ansible/devel/collections/community/hrobot/).
@@ -64,7 +64,7 @@ You can find more information in the [developer guide for collections](https://d
## Release notes
-See the [changelog](https://github.com/ansible-collections/community.hrobot/tree/main/CHANGELOG.rst).
+See the [changelog](https://github.com/ansible-collections/community.hrobot/tree/main/CHANGELOG.md).
## More information
diff --git a/ansible_collections/community/hrobot/changelogs/changelog.yaml b/ansible_collections/community/hrobot/changelogs/changelog.yaml
index 94785155c..ff49e627a 100644
--- a/ansible_collections/community/hrobot/changelogs/changelog.yaml
+++ b/ansible_collections/community/hrobot/changelogs/changelog.yaml
@@ -210,3 +210,73 @@ releases:
- 76-firewall-ipv6-output.yml
- 77-firewall-server_number.yml
release_date: '2023-03-15'
+ 1.8.1:
+ changes:
+ known_issues:
+ - Ansible markup will show up in raw form on ansible-doc text output for ansible-core
+ before 2.15. If you have trouble deciphering the documentation markup, please
+ upgrade to ansible-core 2.15 (or newer), or read the HTML documentation on
+ https://docs.ansible.com/ansible/devel/collections/community/hrobot/.
+ release_summary: 'Maintenance release with updated documentation.
+
+
+ From this version on, community.hrobot is using the new `Ansible semantic
+ markup
+
+ <https://docs.ansible.com/ansible/devel/dev_guide/developing_modules_documenting.html#semantic-markup-within-module-documentation>`__
+
+ in its documentation. If you look at documentation with the ansible-doc CLI
+ tool
+
+ from ansible-core before 2.15, please note that it does not render the markup
+
+ correctly. You should be still able to read it in most cases, but you need
+
+ ansible-core 2.15 or later to see it as it is intended. Alternatively you
+ can
+
+ look at `the devel docsite <https://docs.ansible.com/ansible/devel/collections/community/hrobot/>`__
+
+ for the rendered HTML version of the documentation of the latest release.
+
+ '
+ fragments:
+ - 1.8.1.yml
+ - semantic-markup.yml
+ release_date: '2023-06-27'
+ 1.8.2:
+ changes:
+ bugfixes:
+ - Show more information (if available) from error messages (https://github.com/ansible-collections/community.hrobot/pull/89).
+ release_summary: Maintenance release with updated documentation.
+ fragments:
+ - 1.8.2.yml
+ - 89-firewall.yml
+ release_date: '2023-11-11'
+ 1.9.0:
+ changes:
+ deprecated_features:
+ - robot inventory plugin - the ``filters`` option has been renamed to ``simple_filters``.
+ The old name will stop working in community.hrobot 2.0.0 (https://github.com/ansible-collections/community.hrobot/pull/94).
+ minor_changes:
+ - robot inventory plugin - the ``filters`` option has been renamed to ``simple_filters``.
+ The old name still works until community.hrobot 2.0.0. Then it will change
+ to allow more complex filtering with the ``community.library_inventory_filtering_v1``
+ collection's functionality (https://github.com/ansible-collections/community.hrobot/pull/94).
+ release_summary: Feature and maintenance release.
+ fragments:
+ - 1.9.0.yml
+ - 94-inventory-filters.yml
+ release_date: '2024-01-21'
+ 1.9.1:
+ changes:
+ release_summary: Bugfix release.
+ security_fixes:
+ - robot inventory plugin - make sure all data received from the Hetzner robot
+ service server is marked as unsafe, so remote code execution by obtaining
+ texts that can be evaluated as templates is not possible (https://www.die-welt.net/2024/03/remote-code-execution-in-ansible-dynamic-inventory-plugins/,
+ https://github.com/ansible-collections/community.hrobot/pull/99).
+ fragments:
+ - 1.9.1.yml
+ - inventory-rce.yml
+ release_date: '2024-03-16'
diff --git a/ansible_collections/community/hrobot/changelogs/config.yaml b/ansible_collections/community/hrobot/changelogs/config.yaml
index 4d6ee1a9b..ed2ab2a71 100644
--- a/ansible_collections/community/hrobot/changelogs/config.yaml
+++ b/ansible_collections/community/hrobot/changelogs/config.yaml
@@ -11,6 +11,9 @@ keep_fragments: false
mention_ancestor: true
new_plugins_after_name: removed_features
notesdir: fragments
+output_formats:
+- rst
+- md
prelude_section_name: release_summary
prelude_section_title: Release Summary
sections:
diff --git a/ansible_collections/community/hrobot/plugins/inventory/robot.py b/ansible_collections/community/hrobot/plugins/inventory/robot.py
index 1d5af4537..19a2f1aa4 100644
--- a/ansible_collections/community/hrobot/plugins/inventory/robot.py
+++ b/ansible_collections/community/hrobot/plugins/inventory/robot.py
@@ -26,7 +26,7 @@ DOCUMENTATION = r"""
- ansible.builtin.inventory_cache
- community.hrobot.robot
notes:
- - The I(hetzner_user) and I(hetzner_password) options can be templated.
+ - The O(hetzner_user) and O(hetzner_password) options can be templated.
options:
plugin:
description: Token that ensures this is a source file for the plugin.
@@ -38,13 +38,17 @@ DOCUMENTATION = r"""
hetzner_password:
env:
- name: HROBOT_API_PASSWORD
- filters:
+ simple_filters:
description:
- A dictionary of filter value pairs.
- Available filters are listed here are keys of server like C(status) or C(server_ip).
- See U(https://robot.your-server.de/doc/webservice/en.html#get-server) for all values that can be used.
+ - This option has been renamed from O(filters) to O(simple_filters) in community.hrobot 1.9.0.
+ The old name can still be used until community.hrobot 2.0.0.
type: dict
default: {}
+ aliases:
+ - filters
"""
EXAMPLES = r"""
@@ -63,7 +67,7 @@ hetzner_password: '{{ (lookup("community.sops.sops", "keys/hetzner.sops.yaml") |
# Example using constructed features to create groups
plugin: community.hrobot.robot
-filters:
+simple_filters:
status: ready
traffic: unlimited
# keyed_groups may be used to create custom groups
@@ -81,6 +85,7 @@ from ansible.errors import AnsibleError
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable, Cacheable
from ansible.template import Templar
from ansible.utils.display import Display
+from ansible.utils.unsafe_proxy import wrap_var as make_unsafe
from ansible_collections.community.hrobot.plugins.module_utils.robot import (
BASE_URL,
@@ -109,10 +114,18 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
def parse(self, inventory, loader, path, cache=True):
super(InventoryModule, self).parse(inventory, loader, path)
servers = {}
- config = self._read_config_data(path)
+ orig_config = self._read_config_data(path)
self.load_cache_plugin()
cache_key = self.get_cache_key(path)
+ if 'filters' in orig_config:
+ display.deprecated(
+ 'The `filters` option of the community.hrobot.robot inventory plugin has been renamed to `simple_filters`. '
+ 'The old name will stop working in community.hrobot 2.0.0.',
+ collection_name='community.hrobot',
+ version='2.0.0',
+ )
+
self.templar = Templar(loader=loader)
# cache may be True or False at this point to indicate if the inventory is being refreshed
@@ -143,7 +156,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
self.populate(servers)
def populate(self, servers):
- filters = self.get_option('filters')
+ filters = self.get_option('simple_filters')
strict = self.get_option('strict')
server_lists = []
for server in servers:
@@ -162,9 +175,9 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
self.inventory.add_host(server_name)
server_lists.append(server_name)
if 'server_ip' in s:
- self.inventory.set_variable(server_name, 'ansible_host', s['server_ip'])
+ self.inventory.set_variable(server_name, 'ansible_host', make_unsafe(s['server_ip']))
for hostvar, hostval in s.items():
- self.inventory.set_variable(server_name, "{0}_{1}".format('hrobot', hostvar), hostval)
+ self.inventory.set_variable(server_name, "{0}_{1}".format('hrobot', hostvar), make_unsafe(hostval))
# Composed variables
server_vars = self.inventory.get_host(server_name).get_vars()
diff --git a/ansible_collections/community/hrobot/plugins/module_utils/robot.py b/ansible_collections/community/hrobot/plugins/module_utils/robot.py
index 034a3fc48..f01409083 100644
--- a/ansible_collections/community/hrobot/plugins/module_utils/robot.py
+++ b/ansible_collections/community/hrobot/plugins/module_utils/robot.py
@@ -8,6 +8,7 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type
+from ansible.module_utils.common.text.converters import to_native
from ansible.module_utils.six import PY3
from ansible.module_utils.six.moves.urllib.error import HTTPError
from ansible.module_utils.urls import fetch_url, open_url
@@ -33,6 +34,30 @@ def get_x_www_form_urlenconded_dict_from_list(key, values):
return dict(('{key}[{index}]'.format(key=key, index=i), x) for i, x in enumerate(values))
+def _format_list(obj):
+ if not isinstance(obj, (list, tuple)):
+ return to_native(obj)
+ return [_format_list(e) for e in obj]
+
+
+def format_error_msg(error):
+ # Reference: https://robot.hetzner.com/doc/webservice/en.html#errors
+ msg = 'Request failed: {0} {1} ({2})'.format(
+ error['status'],
+ error['code'],
+ error['message'],
+ )
+ if error.get('missing'):
+ msg += '. Missing input parameters: {0}'.format(_format_list(error['missing']))
+ if error.get('invalid'):
+ msg += '. Invalid input parameters: {0}'.format(_format_list(error['invalid']))
+ if error.get('max_request') is not None:
+ msg += '. Maximum allowed requests: {0}'.format(error['max_request'])
+ if error.get('interval') is not None:
+ msg += '. Time interval in seconds: {0}'.format(error['interval'])
+ return msg
+
+
class PluginException(Exception):
def __init__(self, message):
super(PluginException, self).__init__(message)
@@ -85,11 +110,7 @@ def plugin_open_url_json(plugin, url, method='GET', timeout=10, data=None, heade
if accept_errors:
if result['error']['code'] in accept_errors:
return result, result['error']['code']
- raise PluginException('Request failed: {0} {1} ({2})'.format(
- result['error']['status'],
- result['error']['code'],
- result['error']['message']
- ))
+ raise PluginException(format_error_msg(result['error']))
return result, None
except ValueError:
raise PluginException('Cannot decode content retrieved from {0}'.format(url))
@@ -125,11 +146,7 @@ def fetch_url_json(module, url, method='GET', timeout=10, data=None, headers=Non
if accept_errors:
if result['error']['code'] in accept_errors:
return result, result['error']['code']
- module.fail_json(msg='Request failed: {0} {1} ({2})'.format(
- result['error']['status'],
- result['error']['code'],
- result['error']['message']
- ))
+ module.fail_json(msg=format_error_msg(result['error']), error=result['error'])
return result, None
except ValueError:
module.fail_json(msg='Cannot decode content retrieved from {0}'.format(url))
diff --git a/ansible_collections/community/hrobot/plugins/modules/boot.py b/ansible_collections/community/hrobot/plugins/modules/boot.py
index 64917d9b8..bcf6f3c47 100644
--- a/ansible_collections/community/hrobot/plugins/modules/boot.py
+++ b/ansible_collections/community/hrobot/plugins/modules/boot.py
@@ -46,31 +46,31 @@ options:
description:
- If this option is provided, all special boot configurations are removed and
the installed operating system will be booted up next (assuming it is bootable).
- - Precisely one of I(regular_boot), I(rescue), I(install_linux), I(install_vnc),
- I(install_windows), I(install_plesk), and I(install_cpanel) must be provided.
+ - Precisely one of O(regular_boot), O(rescue), O(install_linux), O(install_vnc),
+ O(install_windows), O(install_plesk), and O(install_cpanel) must be provided.
type: bool
choices:
- true
rescue:
description:
- If this option is provided, the rescue system will be activated for the next boot.
- - Precisely one of I(regular_boot), I(rescue), I(install_linux), I(install_vnc),
- I(install_windows), I(install_plesk), and I(install_cpanel) must be provided.
+ - Precisely one of O(regular_boot), O(rescue), O(install_linux), O(install_vnc),
+ O(install_windows), O(install_plesk), and O(install_cpanel) must be provided.
type: dict
suboptions:
os:
description:
- The operating system to use for the rescue system. Possible choices can
change over time.
- - Currently, C(linux), C(linuxold), C(freebsd), C(freebsdold), C(freebsdax),
- C(freebsdbetaax), C(vkvm), and C(vkvmold) seem to be available.
+ - Currently, V(linux), V(linuxold), V(freebsd), V(freebsdold), V(freebsdax),
+ V(freebsdbetaax), V(vkvm), and V(vkvmold) seem to be available.
type: str
required: true
arch:
description:
- The architecture to use for the rescue system.
- Not all architectures are available for all operating systems.
- - Defaults to C(64).
+ - Defaults to V(64).
type: int
choices:
- 32
@@ -87,8 +87,8 @@ options:
install_linux:
description:
- If this option is provided, a Linux system install will be activated for the next boot.
- - Precisely one of I(regular_boot), I(rescue), I(install_linux), I(install_vnc),
- I(install_windows), I(install_plesk), and I(install_cpanel) must be provided.
+ - Precisely one of O(regular_boot), O(rescue), O(install_linux), O(install_vnc),
+ O(install_windows), O(install_plesk), and O(install_cpanel) must be provided.
type: dict
suboptions:
dist:
@@ -100,7 +100,7 @@ options:
description:
- The architecture to use for the install.
- Not all architectures are available for all distributions.
- - Defaults to C(64).
+ - Defaults to V(64).
type: int
choices:
- 32
@@ -122,8 +122,8 @@ options:
install_vnc:
description:
- If this option is provided, a VNC installation will be activated for the next boot.
- - Precisely one of I(regular_boot), I(rescue), I(install_linux), I(install_vnc),
- I(install_windows), I(install_plesk), and I(install_cpanel) must be provided.
+ - Precisely one of O(regular_boot), O(rescue), O(install_linux), O(install_vnc),
+ O(install_windows), O(install_plesk), and O(install_cpanel) must be provided.
type: dict
suboptions:
dist:
@@ -135,7 +135,7 @@ options:
description:
- The architecture to use for the install.
- Not all architectures are available for all distributions.
- - Defaults to C(64).
+ - Defaults to V(64).
type: int
choices:
- 32
@@ -148,8 +148,8 @@ options:
install_windows:
description:
- If this option is provided, a Windows installation will be activated for the next boot.
- - Precisely one of I(regular_boot), I(rescue), I(install_linux), I(install_vnc),
- I(install_windows), I(install_plesk), and I(install_cpanel) must be provided.
+ - Precisely one of O(regular_boot), O(rescue), O(install_linux), O(install_vnc),
+ O(install_windows), O(install_plesk), and O(install_cpanel) must be provided.
type: dict
suboptions:
lang:
@@ -160,8 +160,8 @@ options:
install_plesk:
description:
- If this option is provided, a Plesk installation will be activated for the next boot.
- - Precisely one of I(regular_boot), I(rescue), I(install_linux), I(install_vnc),
- I(install_windows), I(install_plesk), and I(install_cpanel) must be provided.
+ - Precisely one of O(regular_boot), O(rescue), O(install_linux), O(install_vnc),
+ O(install_windows), O(install_plesk), and O(install_cpanel) must be provided.
type: dict
suboptions:
dist:
@@ -173,7 +173,7 @@ options:
description:
- The architecture to use for the install.
- Not all architectures are available for all distributions.
- - Defaults to C(64).
+ - Defaults to V(64).
type: int
choices:
- 32
@@ -191,8 +191,8 @@ options:
install_cpanel:
description:
- If this option is provided, a cPanel installation will be activated for the next boot.
- - Precisely one of I(regular_boot), I(rescue), I(install_linux), I(install_vnc),
- I(install_windows), I(install_plesk), and I(install_cpanel) must be provided.
+ - Precisely one of O(regular_boot), O(rescue), O(install_linux), O(install_vnc),
+ O(install_windows), O(install_plesk), and O(install_cpanel) must be provided.
type: dict
suboptions:
dist:
@@ -204,7 +204,7 @@ options:
description:
- The architecture to use for the install.
- Not all architectures are available for all distributions.
- - Defaults to C(64).
+ - Defaults to V(64).
type: int
choices:
- 32
@@ -266,7 +266,7 @@ password:
- The root password for the active boot configuration, if available.
- For non-rescue boot configurations, it is avised to change the root password
as soon as possible.
- returned: success and if a boot configuration other than C(regular_boot) is active
+ returned: success and if RV(configuration_type) is not V(regular_boot)
type: str
'''
diff --git a/ansible_collections/community/hrobot/plugins/modules/failover_ip.py b/ansible_collections/community/hrobot/plugins/modules/failover_ip.py
index da2da356a..e5d0fdae7 100644
--- a/ansible_collections/community/hrobot/plugins/modules/failover_ip.py
+++ b/ansible_collections/community/hrobot/plugins/modules/failover_ip.py
@@ -44,7 +44,7 @@ options:
state:
description:
- Defines whether the IP will be routed or not.
- - If set to C(routed), I(value) must be specified.
+ - If set to V(routed), O(value) must be specified.
type: str
choices:
- routed
@@ -53,7 +53,7 @@ options:
value:
description:
- The new value for the failover IP address.
- - Required when setting I(state) to C(routed).
+ - Required when setting O(state) to V(routed).
type: str
timeout:
description:
@@ -85,12 +85,12 @@ RETURN = r'''
value:
description:
- The value of the failover IP.
- - Will be C(none) if the IP is unrouted.
+ - Will be V(none) if the IP is unrouted.
returned: success
type: str
state:
description:
- - Will be C(routed) or C(unrouted).
+ - Will be V(routed) or V(unrouted).
returned: success
type: str
'''
diff --git a/ansible_collections/community/hrobot/plugins/modules/failover_ip_info.py b/ansible_collections/community/hrobot/plugins/modules/failover_ip_info.py
index b656b0499..1db0d1b2c 100644
--- a/ansible_collections/community/hrobot/plugins/modules/failover_ip_info.py
+++ b/ansible_collections/community/hrobot/plugins/modules/failover_ip_info.py
@@ -59,12 +59,12 @@ RETURN = r'''
value:
description:
- The value of the failover IP.
- - Will be C(none) if the IP is unrouted.
+ - Will be V(none) if the IP is unrouted.
returned: success
type: str
state:
description:
- - Will be C(routed) or C(unrouted).
+ - Will be V(routed) or V(unrouted).
returned: success
type: str
failover_ip:
diff --git a/ansible_collections/community/hrobot/plugins/modules/firewall.py b/ansible_collections/community/hrobot/plugins/modules/firewall.py
index 2677a1186..8f158eaa6 100644
--- a/ansible_collections/community/hrobot/plugins/modules/firewall.py
+++ b/ansible_collections/community/hrobot/plugins/modules/firewall.py
@@ -44,14 +44,14 @@ options:
server_ip:
description:
- The server's main IP address.
- - Exactly one of I(server_ip) and I(server_number) must be specified.
+ - Exactly one of O(server_ip) and O(server_number) must be specified.
- Note that Hetzner deprecated identifying the server's firewall by the server's main IP.
- Using this option can thus stop working at any time in the future. Use I(server_number) instead.
+ Using this option can thus stop working at any time in the future. Use O(server_number) instead.
type: str
server_number:
description:
- The server's number.
- - Exactly one of I(server_ip) and I(server_number) must be specified.
+ - Exactly one of O(server_ip) and O(server_number) must be specified.
type: int
version_added: 1.8.0
filter_ipv6:
@@ -69,7 +69,7 @@ options:
state:
description:
- Status of the firewall.
- - Firewall is active if state is C(present), and disabled if state is C(absent).
+ - Firewall is active if state is V(present), and disabled if state is V(absent).
type: str
default: present
choices: [ present, absent ]
@@ -93,11 +93,14 @@ options:
name:
description:
- Name of the firewall rule.
+ - Note that Hetzner restricts the characters that can be used for rule names. At the moment, only
+ letters C(a-z), C(A-Z), space, and the symbols C(.), C(-), C(+), C(_), and C(@) are allowed.
type: str
ip_version:
description:
- Internet protocol version.
- - Leave away to filter both protocols. Note that in that case, none of I(dst_ip), I(src_ip), or I(protocol) can be specified.
+ - Leave away to filter both protocols. Note that in that case, none of O(rules.input[].dst_ip),
+ O(rules.input[].src_ip), or O(rules.input[].protocol) can be specified.
type: str
dst_ip:
description:
@@ -124,8 +127,8 @@ options:
tcp_flags:
description:
- TCP flags or logical combination of flags.
- - Flags supported by Hetzner are C(syn), C(fin), C(rst), C(psh) and C(urg).
- - They can be combined with C(|) (logical or) and C(&) (logical and).
+ - Flags supported by Hetzner are V(syn), V(fin), V(rst), V(psh) and V(urg).
+ - They can be combined with V(|) (logical or) and V(&) (logical and).
- See L(the documentation,https://wiki.hetzner.de/index.php/Robot_Firewall/en#Parameter)
for more information.
type: str
@@ -145,11 +148,14 @@ options:
name:
description:
- Name of the firewall rule.
+ - Note that Hetzner restricts the characters that can be used for rule names. At the moment, only
+ letters C(a-z), C(A-Z), space, and the symbols C(.), C(-), C(+), C(_), and C(@) are allowed.
type: str
ip_version:
description:
- Internet protocol version.
- - Leave away to filter both protocols. Note that in that case, none of I(dst_ip), I(src_ip), or I(protocol) can be specified.
+ - Leave away to filter both protocols. Note that in that case, none of O(rules.output[].dst_ip),
+ O(rules.output[].src_ip), or O(rules.output[].protocol) can be specified.
type: str
dst_ip:
description:
@@ -176,8 +182,8 @@ options:
tcp_flags:
description:
- TCP flags or logical combination of flags.
- - Flags supported by Hetzner are C(syn), C(fin), C(rst), C(psh) and C(urg).
- - They can be combined with C(|) (logical or) and C(&) (logical and).
+ - Flags supported by Hetzner are V(syn), V(fin), V(rst), V(psh) and V(urg).
+ - They can be combined with V(|) (logical or) and V(&) (logical and).
- See L(the documentation,https://wiki.hetzner.de/index.php/Robot_Firewall/en#Parameter)
for more information.
type: str
@@ -230,7 +236,8 @@ EXAMPLES = r'''
allowlist_hos: true
rules:
input:
- - name: Allow ICMP protocol, so you can ping your server
+ - name: Allow ICMP protocol
+ # This is needed so you can ping your server
ip_version: ipv4
protocol: icmp
action: accept
@@ -241,7 +248,8 @@ EXAMPLES = r'''
dst_port: '32768-65535'
tcp_flags: ack
action: accept
- - name: Allow everything to ports 20-23 from 4.3.2.1/24 (IPv4 only)
+ - name: Allow restricted access from some known IPv4 addresses
+ # Allow everything to ports 20-23 from 4.3.2.1/24 (IPv4 only)
ip_version: ipv4
src_ip: 4.3.2.1/24
dst_port: '20-23'
@@ -270,7 +278,7 @@ firewall:
port:
description:
- Switch port of firewall.
- - C(main) or C(kvm).
+ - V(main) or V(kvm).
type: str
sample: main
server_ip:
@@ -286,9 +294,9 @@ firewall:
status:
description:
- Status of the firewall.
- - C(active) or C(disabled).
- - Will be C(in process) if the firewall is currently updated, and
- I(wait_for_configured) is set to C(false) or I(timeout) to a too small value.
+ - V(active) or V(disabled).
+ - Will be V(in process) if the firewall is currently updated, and
+ O(wait_for_configured) is set to V(false) or O(timeout) to a too small value.
type: str
sample: active
allowlist_hos:
@@ -300,7 +308,7 @@ firewall:
whitelist_hos:
description:
- Whether Hetzner services have access.
- - Old name of return value C(allowlist_hos), will be removed eventually.
+ - Old name of return value V(allowlist_hos), will be removed eventually.
type: bool
sample: true
rules:
@@ -360,7 +368,7 @@ firewall:
action:
description:
- Action if rule matches.
- - C(accept) or C(discard).
+ - V(accept) or V(discard).
type: str
sample: accept
choices:
@@ -418,7 +426,7 @@ firewall:
action:
description:
- Action if rule matches.
- - C(accept) or C(discard).
+ - V(accept) or V(discard).
type: str
sample: accept
choices:
diff --git a/ansible_collections/community/hrobot/plugins/modules/firewall_info.py b/ansible_collections/community/hrobot/plugins/modules/firewall_info.py
index 49f98ab64..f72e253d7 100644
--- a/ansible_collections/community/hrobot/plugins/modules/firewall_info.py
+++ b/ansible_collections/community/hrobot/plugins/modules/firewall_info.py
@@ -37,14 +37,14 @@ options:
server_ip:
description:
- The server's main IP address.
- - Exactly one of I(server_ip) and I(server_number) must be specified.
+ - Exactly one of O(server_ip) and O(server_number) must be specified.
- Note that Hetzner deprecated identifying the server's firewall by the server's main IP.
- Using this option can thus stop working at any time in the future. Use I(server_number) instead.
+ Using this option can thus stop working at any time in the future. Use O(server_number) instead.
type: str
server_number:
description:
- The server's number.
- - Exactly one of I(server_ip) and I(server_number) must be specified.
+ - Exactly one of O(server_ip) and O(server_number) must be specified.
type: int
version_added: 1.8.0
wait_for_configured:
@@ -94,7 +94,7 @@ firewall:
port:
description:
- Switch port of firewall.
- - C(main) or C(kvm).
+ - V(main) or V(kvm).
type: str
sample: main
filter_ipv6:
@@ -115,9 +115,9 @@ firewall:
status:
description:
- Status of the firewall.
- - C(active) or C(disabled).
- - Will be C(in process) if the firewall is currently updated, and
- I(wait_for_configured) is set to C(false) or I(timeout) to a too small value.
+ - V(active) or V(disabled).
+ - Will be V(in process) if the firewall is currently updated, and
+ O(wait_for_configured) is set to V(false) or O(timeout) to a too small value.
type: str
sample: active
allowlist_hos:
@@ -129,7 +129,7 @@ firewall:
whitelist_hos:
description:
- Whether Hetzner services have access.
- - Old name of return value C(allowlist_hos), will be removed eventually.
+ - Old name of return value V(allowlist_hos), will be removed eventually.
type: bool
sample: true
rules:
@@ -189,7 +189,7 @@ firewall:
action:
description:
- Action if rule matches.
- - C(accept) or C(discard).
+ - V(accept) or V(discard).
type: str
sample: accept
choices:
@@ -247,7 +247,7 @@ firewall:
action:
description:
- Action if rule matches.
- - C(accept) or C(discard).
+ - V(accept) or V(discard).
type: str
sample: accept
choices:
diff --git a/ansible_collections/community/hrobot/plugins/modules/reset.py b/ansible_collections/community/hrobot/plugins/modules/reset.py
index d367936e0..eaeaa5853 100644
--- a/ansible_collections/community/hrobot/plugins/modules/reset.py
+++ b/ansible_collections/community/hrobot/plugins/modules/reset.py
@@ -40,11 +40,11 @@ options:
reset_type:
description:
- How to reset the server.
- - C(software) is a software reset. This should be similar to pressing Ctrl+Alt+Del on the keyboard.
- - C(power) is a hardware reset similar to pressing the Power button. An ACPI signal is sent, and if the
+ - V(software) is a software reset. This should be similar to pressing Ctrl+Alt+Del on the keyboard.
+ - V(power) is a hardware reset similar to pressing the Power button. An ACPI signal is sent, and if the
server is configured correctly, this will trigger a regular shutdown.
- - C(hardware) is a hardware reset similar to pressing the Restart button. The power is cycled for the server.
- - C(manual) is a manual reset. This requests a technician to manually do the shutdown while looking at the
+ - V(hardware) is a hardware reset similar to pressing the Restart button. The power is cycled for the server.
+ - V(manual) is a manual reset. This requests a technician to manually do the shutdown while looking at the
screen output. B(Be careful) and only use this when really necessary!
- Note that not every server supports every reset method!
type: str
diff --git a/ansible_collections/community/hrobot/plugins/modules/reverse_dns.py b/ansible_collections/community/hrobot/plugins/modules/reverse_dns.py
index 200489217..f3a914679 100644
--- a/ansible_collections/community/hrobot/plugins/modules/reverse_dns.py
+++ b/ansible_collections/community/hrobot/plugins/modules/reverse_dns.py
@@ -44,7 +44,7 @@ options:
required: true
state:
description:
- - Whether to set or update (C(present)) or delete (C(absent)) the reverse DNS entry for I(ip).
+ - Whether to set or update (V(present)) or delete (V(absent)) the reverse DNS entry for O(ip).
type: str
default: present
choices:
@@ -52,8 +52,8 @@ options:
- absent
value:
description:
- - The reverse DNS entry for I(ip).
- - Required if I(state=present).
+ - The reverse DNS entry for O(ip).
+ - Required if O(state=present).
type: str
'''
diff --git a/ansible_collections/community/hrobot/plugins/modules/server.py b/ansible_collections/community/hrobot/plugins/modules/server.py
index 2a24986e3..d32320af6 100644
--- a/ansible_collections/community/hrobot/plugins/modules/server.py
+++ b/ansible_collections/community/hrobot/plugins/modules/server.py
@@ -100,7 +100,7 @@ server:
traffic:
description:
- Free traffic quota.
- - C(unlimited) in case of unlimited traffic.
+ - V(unlimited) in case of unlimited traffic.
type: str
sample: 5 TB
returned: success
diff --git a/ansible_collections/community/hrobot/plugins/modules/server_info.py b/ansible_collections/community/hrobot/plugins/modules/server_info.py
index b3f6da11d..eed9f2289 100644
--- a/ansible_collections/community/hrobot/plugins/modules/server_info.py
+++ b/ansible_collections/community/hrobot/plugins/modules/server_info.py
@@ -40,9 +40,9 @@ options:
full_info:
description:
- Whether to provide full information for every server.
- - Setting this to C(true) requires one REST call per server,
+ - Setting this to V(true) requires one REST call per server,
which is slow and reduces your rate limit. Use with care.
- - When I(server_number) is specified, this option is set to C(true).
+ - When O(server_number) is specified, this option is set to V(true).
type: bool
default: false
'''
@@ -113,7 +113,7 @@ servers:
traffic:
description:
- Free traffic quota.
- - C(unlimited) in case of unlimited traffic.
+ - V(unlimited) in case of unlimited traffic.
type: str
sample: 5 TB
returned: success
@@ -171,55 +171,55 @@ servers:
- Whether the server can be automatically reset.
type: bool
sample: true
- returned: when I(full_info=true)
+ returned: when O(full_info=true)
rescue:
description:
- Whether the rescue system is available.
type: bool
sample: false
- returned: when I(full_info=true)
+ returned: when O(full_info=true)
vnc:
description:
- Flag of VNC installation availability.
type: bool
sample: true
- returned: when I(full_info=true)
+ returned: when O(full_info=true)
windows:
description:
- Flag of Windows installation availability.
type: bool
sample: true
- returned: when I(full_info=true)
+ returned: when O(full_info=true)
plesk:
description:
- Flag of Plesk installation availability.
type: bool
sample: true
- returned: when I(full_info=true)
+ returned: when O(full_info=true)
cpanel:
description:
- Flag of cPanel installation availability.
type: bool
sample: true
- returned: when I(full_info=true)
+ returned: when O(full_info=true)
wol:
description:
- Flag of Wake On Lan availability.
type: bool
sample: true
- returned: when I(full_info=true)
+ returned: when O(full_info=true)
hot_swap:
description:
- Flag of Hot Swap availability.
type: bool
sample: true
- returned: when I(full_info=true)
+ returned: when O(full_info=true)
linked_storagebox:
description:
- Linked Storage Box ID.
type: int
sample: 12345
- returned: when I(full_info=true)
+ returned: when O(full_info=true)
'''
from ansible.module_utils.basic import AnsibleModule
diff --git a/ansible_collections/community/hrobot/plugins/modules/ssh_key.py b/ansible_collections/community/hrobot/plugins/modules/ssh_key.py
index 2353514b9..e2064592c 100644
--- a/ansible_collections/community/hrobot/plugins/modules/ssh_key.py
+++ b/ansible_collections/community/hrobot/plugins/modules/ssh_key.py
@@ -38,9 +38,9 @@ options:
state:
description:
- Whether to make sure a public SSH key is present or absent.
- - C(present) makes sure that the SSH key is available, and
- potentially updates names for existing SHS public keys.
- - C(absent) makes sure that the SSH key is not available.
+ - V(present) makes sure that the SSH key is available, and
+ potentially updates names for existing SSH public keys.
+ - V(absent) makes sure that the SSH key is not available.
The fingerprint or public key data is used for matching the
key.
required: true
@@ -51,19 +51,19 @@ options:
name:
description:
- The public key's name.
- - Required if I(state=present), and ignored if I(state=absent).
+ - Required if O(state=present), and ignored if O(state=absent).
type: str
fingerprint:
description:
- The MD5 fingerprint of the public SSH key to remove.
- - One of I(public_key) and I(fingerprint) are required if I(state=absent).
+ - One of O(public_key) and O(fingerprint) are required if O(state=absent).
type: str
public_key:
description:
- The public key data in OpenSSH format.
- - "Example: C(ssh-rsa AAAAB3NzaC1yc+...)"
- - One of I(public_key) and I(fingerprint) are required if I(state=absent).
- - Required if I(state=present).
+ - "Example: V(ssh-rsa AAAAB3NzaC1yc+...)"
+ - One of O(public_key) and O(fingerprint) are required if O(state=absent).
+ - Required if O(state=present).
type: str
'''
diff --git a/ansible_collections/community/hrobot/plugins/modules/v_switch.py b/ansible_collections/community/hrobot/plugins/modules/v_switch.py
index 6035392a4..f4ab27a11 100644
--- a/ansible_collections/community/hrobot/plugins/modules/v_switch.py
+++ b/ansible_collections/community/hrobot/plugins/modules/v_switch.py
@@ -51,9 +51,9 @@ options:
state:
description:
- State of the vSwitch.
- - vSwitch is created if state is C(present), and deleted if state is C(absent).
- - C(absent) just cancels the vSwitch at the end of the current day.
- - When cancelling, you have to specify I(servers=[]) if you want to actively remove the servers in the vSwitch.
+ - vSwitch is created if state is V(present), and deleted if state is V(absent).
+ - V(absent) just cancels the vSwitch at the end of the current day.
+ - When cancelling, you have to specify O(servers=[]) if you want to actively remove the servers in the vSwitch.
type: str
default: present
choices: [ present, absent ]
diff --git a/ansible_collections/community/hrobot/tests/sanity/extra/extra-docs.json b/ansible_collections/community/hrobot/tests/sanity/extra/extra-docs.json
index c2e612e5f..9a28d174f 100644
--- a/ansible_collections/community/hrobot/tests/sanity/extra/extra-docs.json
+++ b/ansible_collections/community/hrobot/tests/sanity/extra/extra-docs.json
@@ -1,10 +1,13 @@
{
"include_symlinks": false,
"prefixes": [
- "docs/docsite/"
+ "docs/docsite/",
+ "plugins/",
+ "roles/"
],
"output": "path-line-column-message",
"requirements": [
+ "ansible-core",
"antsibull-docs"
]
}
diff --git a/ansible_collections/community/hrobot/tests/sanity/extra/extra-docs.py b/ansible_collections/community/hrobot/tests/sanity/extra/extra-docs.py
index 673104923..251e6d70f 100755
--- a/ansible_collections/community/hrobot/tests/sanity/extra/extra-docs.py
+++ b/ansible_collections/community/hrobot/tests/sanity/extra/extra-docs.py
@@ -13,9 +13,14 @@ import subprocess
def main():
"""Main entry point."""
- if not os.path.isdir(os.path.join('docs', 'docsite')):
- return
- p = subprocess.run(['antsibull-docs', 'lint-collection-docs', '.'], check=False)
+ env = os.environ.copy()
+ suffix = ':{env}'.format(env=env["ANSIBLE_COLLECTIONS_PATH"]) if 'ANSIBLE_COLLECTIONS_PATH' in env else ''
+ env['ANSIBLE_COLLECTIONS_PATH'] = '{root}{suffix}'.format(root=os.path.dirname(os.path.dirname(os.path.dirname(os.getcwd()))), suffix=suffix)
+ p = subprocess.run(
+ ['antsibull-docs', 'lint-collection-docs', '--plugin-docs', '--skip-rstcheck', '.'],
+ env=env,
+ check=False,
+ )
if p.returncode not in (0, 3):
print('{0}:0:0: unexpected return code {1}'.format(sys.argv[0], p.returncode))
diff --git a/ansible_collections/community/hrobot/tests/sanity/ignore-2.16.txt b/ansible_collections/community/hrobot/tests/sanity/ignore-2.16.txt
new file mode 100644
index 000000000..0d9329fad
--- /dev/null
+++ b/ansible_collections/community/hrobot/tests/sanity/ignore-2.16.txt
@@ -0,0 +1 @@
+tests/ee/roles/smoke/library/smoke_ipaddress.py shebang
diff --git a/ansible_collections/community/hrobot/tests/sanity/ignore-2.16.txt.license b/ansible_collections/community/hrobot/tests/sanity/ignore-2.16.txt.license
new file mode 100644
index 000000000..edff8c768
--- /dev/null
+++ b/ansible_collections/community/hrobot/tests/sanity/ignore-2.16.txt.license
@@ -0,0 +1,3 @@
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
+SPDX-FileCopyrightText: Ansible Project
diff --git a/ansible_collections/community/hrobot/tests/sanity/ignore-2.17.txt b/ansible_collections/community/hrobot/tests/sanity/ignore-2.17.txt
new file mode 100644
index 000000000..0d9329fad
--- /dev/null
+++ b/ansible_collections/community/hrobot/tests/sanity/ignore-2.17.txt
@@ -0,0 +1 @@
+tests/ee/roles/smoke/library/smoke_ipaddress.py shebang
diff --git a/ansible_collections/community/hrobot/tests/sanity/ignore-2.17.txt.license b/ansible_collections/community/hrobot/tests/sanity/ignore-2.17.txt.license
new file mode 100644
index 000000000..edff8c768
--- /dev/null
+++ b/ansible_collections/community/hrobot/tests/sanity/ignore-2.17.txt.license
@@ -0,0 +1,3 @@
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
+SPDX-FileCopyrightText: Ansible Project
diff --git a/ansible_collections/community/hrobot/tests/unit/plugins/inventory/test_robot.py b/ansible_collections/community/hrobot/tests/unit/plugins/inventory/test_robot.py
index 31d6adae0..d5514aee5 100644
--- a/ansible_collections/community/hrobot/tests/unit/plugins/inventory/test_robot.py
+++ b/ansible_collections/community/hrobot/tests/unit/plugins/inventory/test_robot.py
@@ -17,6 +17,7 @@ from ansible.inventory.data import InventoryData
from ansible.inventory.manager import InventoryManager
from ansible.module_utils.common.text.converters import to_native
from ansible.template import Templar
+from ansible.utils.unsafe_proxy import AnsibleUnsafe
from ansible_collections.community.internal_test_tools.tests.unit.mock.path import mock_unfrackpath_noop
from ansible_collections.community.internal_test_tools.tests.unit.mock.loader import DictDataLoader
@@ -60,7 +61,7 @@ def inventory():
def get_option(option):
- if option == 'filters':
+ if option == 'simple_filters':
return {}
if option == 'hetzner_user':
return 'test'
@@ -159,7 +160,7 @@ def test_inventory_file_simple(mocker):
plugin: community.hrobot.robot
hetzner_user: test
hetzner_password: hunter2
- filters:
+ simple_filters:
dc: foo
""")}
im = InventoryManager(loader=DictDataLoader(inventory_file), sources=inventory_filename)
@@ -216,7 +217,7 @@ def test_inventory_file_simple_2(mocker):
plugin: community.hrobot.robot
hetzner_user: '{{ "test" }}'
hetzner_password: '{{ "hunter2" }}'
- filters:
+ simple_filters:
dc: foo
""")}
im = InventoryManager(loader=DictDataLoader(inventory_file), sources=inventory_filename)
@@ -260,7 +261,7 @@ def test_inventory_file_fail(mocker, error_result):
plugin: community.hrobot.robot
hetzner_user: test
hetzner_password: hunter2
- filters:
+ simple_filters:
dc: foo
""")}
im = InventoryManager(loader=DictDataLoader(inventory_file), sources=inventory_filename)
@@ -359,3 +360,56 @@ def test_inventory_file_collision(mocker):
assert len(im._inventory.groups['ungrouped'].hosts) == 1
assert len(im._inventory.groups['all'].hosts) == 0
# TODO: check for warning
+
+
+def test_unsafe(inventory, mocker):
+ open_url = OpenUrlProxy([
+ OpenUrlCall('GET', 200)
+ .result_json([
+ {
+ 'server': {
+ 'server_ip': '1.2.3.4',
+ 'dc': 'abc',
+ },
+ },
+ {
+ 'server': {
+ 'server_ip': '1.2.3.5',
+ 'server_name': 'foo',
+ 'dc': 'EVALU{{ "" }}ATED',
+ },
+ },
+ ])
+ .expect_url('{0}/server'.format(BASE_URL)),
+ ])
+ mocker.patch('ansible_collections.community.hrobot.plugins.module_utils.robot.open_url', open_url)
+
+ inventory.get_option = mocker.MagicMock(side_effect=get_option)
+ inventory.populate(inventory.get_servers())
+
+ open_url.assert_is_done()
+
+ host_1 = inventory.inventory.get_host('1.2.3.4')
+ host_2 = inventory.inventory.get_host('foo')
+
+ host_1_vars = host_1.get_vars()
+ host_2_vars = host_2.get_vars()
+
+ assert host_1_vars['ansible_host'] == '1.2.3.4'
+ assert host_1_vars['hrobot_server_ip'] == '1.2.3.4'
+ assert host_1_vars['hrobot_dc'] == 'abc'
+
+ assert host_2_vars['ansible_host'] == '1.2.3.5'
+ assert host_2_vars['hrobot_server_ip'] == '1.2.3.5'
+ assert host_2_vars['hrobot_server_name'] == 'foo'
+ assert host_2_vars['hrobot_dc'] == 'EVALU{{ "" }}ATED'
+
+ # Make sure everything is unsafe
+ assert isinstance(host_1_vars['ansible_host'], AnsibleUnsafe)
+ assert isinstance(host_1_vars['hrobot_server_ip'], AnsibleUnsafe)
+ assert isinstance(host_1_vars['hrobot_dc'], AnsibleUnsafe)
+
+ assert isinstance(host_2_vars['ansible_host'], AnsibleUnsafe)
+ assert isinstance(host_2_vars['hrobot_server_ip'], AnsibleUnsafe)
+ assert isinstance(host_2_vars['hrobot_server_name'], AnsibleUnsafe)
+ assert isinstance(host_2_vars['hrobot_dc'], AnsibleUnsafe)
diff --git a/ansible_collections/community/hrobot/tests/unit/plugins/module_utils/test_failover.py b/ansible_collections/community/hrobot/tests/unit/plugins/module_utils/test_failover.py
index 56cd02944..dc1a3911d 100644
--- a/ansible_collections/community/hrobot/tests/unit/plugins/module_utils/test_failover.py
+++ b/ansible_collections/community/hrobot/tests/unit/plugins/module_utils/test_failover.py
@@ -67,14 +67,22 @@ GET_FAILOVER_FAIL = [
),
)).encode('utf-8'),
)),
- 'Request failed: 400 foo (bar)'
+ 'Request failed: 400 foo (bar)',
+ {
+ 'error': {
+ 'code': 'foo',
+ 'status': 400,
+ 'message': 'bar',
+ },
+ },
),
(
'1.2.3.4',
(None, dict(
body='{"foo": "bar"}'.encode('utf-8'),
)),
- 'Cannot interpret result: {"foo": "bar"}'
+ 'Cannot interpret result: {"foo": "bar"}',
+ {},
),
]
@@ -87,16 +95,16 @@ def test_get_failover_record(monkeypatch, ip, return_value, result, record):
assert failover.get_failover_record(module, ip) == record
-@pytest.mark.parametrize("ip, return_value, result", GET_FAILOVER_FAIL)
-def test_get_failover_record_fail(monkeypatch, ip, return_value, result):
+@pytest.mark.parametrize("ip, return_value, fail_msg, fail_kwargs", GET_FAILOVER_FAIL)
+def test_get_failover_record_fail(monkeypatch, ip, return_value, fail_msg, fail_kwargs):
module = get_module_mock()
robot.fetch_url = MagicMock(return_value=copy.deepcopy(return_value))
with pytest.raises(ModuleFailException) as exc:
failover.get_failover_record(module, ip)
- assert exc.value.fail_msg == result
- assert exc.value.fail_kwargs == dict()
+ assert exc.value.fail_msg == fail_msg
+ assert exc.value.fail_kwargs == fail_kwargs
@pytest.mark.parametrize("ip, return_value, result, record", GET_FAILOVER_SUCCESS)
@@ -107,16 +115,16 @@ def test_get_failover(monkeypatch, ip, return_value, result, record):
assert failover.get_failover(module, ip) == result
-@pytest.mark.parametrize("ip, return_value, result", GET_FAILOVER_FAIL)
-def test_get_failover_fail(monkeypatch, ip, return_value, result):
+@pytest.mark.parametrize("ip, return_value, fail_msg, fail_kwargs", GET_FAILOVER_FAIL)
+def test_get_failover_fail(monkeypatch, ip, return_value, fail_msg, fail_kwargs):
module = get_module_mock()
robot.fetch_url = MagicMock(return_value=copy.deepcopy(return_value))
with pytest.raises(ModuleFailException) as exc:
failover.get_failover(module, ip)
- assert exc.value.fail_msg == result
- assert exc.value.fail_kwargs == dict()
+ assert exc.value.fail_msg == fail_msg
+ assert exc.value.fail_kwargs == fail_kwargs
# ########################################################################################
@@ -164,7 +172,14 @@ SET_FAILOVER_FAIL = [
),
)).encode('utf-8'),
)),
- 'Request failed: 400 foo (bar)'
+ 'Request failed: 400 foo (bar)',
+ {
+ 'error': {
+ 'code': 'foo',
+ 'status': 400,
+ 'message': 'bar',
+ },
+ },
),
]
@@ -177,13 +192,13 @@ def test_set_failover(monkeypatch, ip, value, return_value, result):
assert failover.set_failover(module, ip, value) == result
-@pytest.mark.parametrize("ip, value, return_value, result", SET_FAILOVER_FAIL)
-def test_set_failover_fail(monkeypatch, ip, value, return_value, result):
+@pytest.mark.parametrize("ip, value, return_value, fail_msg, fail_kwargs", SET_FAILOVER_FAIL)
+def test_set_failover_fail(monkeypatch, ip, value, return_value, fail_msg, fail_kwargs):
module = get_module_mock()
robot.fetch_url = MagicMock(return_value=copy.deepcopy(return_value))
with pytest.raises(ModuleFailException) as exc:
failover.set_failover(module, ip, value)
- assert exc.value.fail_msg == result
- assert exc.value.fail_kwargs == dict()
+ assert exc.value.fail_msg == fail_msg
+ assert exc.value.fail_kwargs == fail_kwargs
diff --git a/ansible_collections/community/hrobot/tests/unit/plugins/module_utils/test_robot.py b/ansible_collections/community/hrobot/tests/unit/plugins/module_utils/test_robot.py
index b53049e8b..8f5c5cd67 100644
--- a/ansible_collections/community/hrobot/tests/unit/plugins/module_utils/test_robot.py
+++ b/ansible_collections/community/hrobot/tests/unit/plugins/module_utils/test_robot.py
@@ -80,7 +80,14 @@ FETCH_URL_JSON_FAIL = [
)).encode('utf-8'),
)),
None,
- 'Request failed: 400 foo (bar)'
+ 'Request failed: 400 foo (bar)',
+ {
+ 'error': {
+ 'code': "foo",
+ 'status': 400,
+ 'message': "bar",
+ },
+ },
),
(
(None, dict(
@@ -89,21 +96,67 @@ FETCH_URL_JSON_FAIL = [
code="foo",
status=400,
message="bar",
+ missing=None,
+ invalid=None,
+ max_request=None,
+ interval=None,
),
)).encode('utf-8'),
)),
['bar'],
- 'Request failed: 400 foo (bar)'
+ 'Request failed: 400 foo (bar)',
+ {
+ 'error': {
+ 'code': "foo",
+ 'status': 400,
+ 'message': "bar",
+ 'missing': None,
+ 'invalid': None,
+ 'max_request': None,
+ 'interval': None,
+ },
+ },
+ ),
+ (
+ (None, dict(
+ body=json.dumps(dict(
+ error=dict(
+ code="foo",
+ status=400,
+ message="bar",
+ missing=["foo"],
+ invalid=["bar"],
+ max_request=0,
+ interval=0,
+ ),
+ )).encode('utf-8'),
+ )),
+ None,
+ "Request failed: 400 foo (bar). Missing input parameters: ['foo']. Invalid input"
+ " parameters: ['bar']. Maximum allowed requests: 0. Time interval in seconds: 0",
+ {
+ 'error': {
+ 'code': "foo",
+ 'status': 400,
+ 'message': "bar",
+ 'missing': ["foo"],
+ 'invalid': ["bar"],
+ 'max_request': 0,
+ 'interval': 0,
+ },
+ },
),
(
(None, dict(body='{this is not json}'.encode('utf-8'))),
[],
- 'Cannot decode content retrieved from https://foo/bar'
+ 'Cannot decode content retrieved from https://foo/bar',
+ {},
),
(
(None, dict(status=400)),
[],
- 'Cannot retrieve content from https://foo/bar, HTTP status code 400'
+ 'Cannot retrieve content from https://foo/bar, HTTP status code 400',
+ {},
),
]
@@ -116,16 +169,18 @@ def test_fetch_url_json(monkeypatch, return_value, accept_errors, result):
assert robot.fetch_url_json(module, 'https://foo/bar', accept_errors=accept_errors) == result
-@pytest.mark.parametrize("return_value, accept_errors, result", FETCH_URL_JSON_FAIL)
-def test_fetch_url_json_fail(monkeypatch, return_value, accept_errors, result):
+@pytest.mark.parametrize("return_value, accept_errors, fail_msg, fail_kwargs", FETCH_URL_JSON_FAIL)
+def test_fetch_url_json_fail(monkeypatch, return_value, accept_errors, fail_msg, fail_kwargs):
module = get_module_mock()
robot.fetch_url = MagicMock(return_value=return_value)
with pytest.raises(ModuleFailException) as exc:
robot.fetch_url_json(module, 'https://foo/bar', accept_errors=accept_errors)
- assert exc.value.fail_msg == result
- assert exc.value.fail_kwargs == dict()
+ print(exc.value.fail_msg)
+ print(exc.value.fail_kwargs)
+ assert exc.value.fail_msg == fail_msg
+ assert exc.value.fail_kwargs == fail_kwargs
def test_fetch_url_json_empty(monkeypatch):
@@ -139,6 +194,8 @@ def test_fetch_url_json_empty(monkeypatch):
with pytest.raises(ModuleFailException) as exc:
robot.fetch_url_json(module, 'https://foo/bar', allow_empty_result=True)
+ print(exc.value.fail_msg)
+ print(exc.value.fail_kwargs)
assert exc.value.fail_msg == 'Cannot retrieve content from https://foo/bar, HTTP status code 400'
assert exc.value.fail_kwargs == dict()
@@ -153,8 +210,8 @@ def test_plugin_open_url_json(monkeypatch, return_value, accept_errors, result):
assert robot.plugin_open_url_json(plugin, 'https://foo/bar', accept_errors=accept_errors) == result
-@pytest.mark.parametrize("return_value, accept_errors, result", FETCH_URL_JSON_FAIL)
-def test_plugin_open_url_json_fail(monkeypatch, return_value, accept_errors, result):
+@pytest.mark.parametrize("return_value, accept_errors, fail_msg, fail_kwargs", FETCH_URL_JSON_FAIL)
+def test_plugin_open_url_json_fail(monkeypatch, return_value, accept_errors, fail_msg, fail_kwargs):
response = MagicMock()
response.read = MagicMock(return_value=return_value[1].get('body', ''))
robot.open_url = MagicMock(side_effect=robot.HTTPError('https://foo/bar', 400, 'Error!', {}, response))
@@ -163,7 +220,8 @@ def test_plugin_open_url_json_fail(monkeypatch, return_value, accept_errors, res
with pytest.raises(robot.PluginException) as exc:
robot.plugin_open_url_json(plugin, 'https://foo/bar', accept_errors=accept_errors)
- assert exc.value.error_message == result
+ print(exc.value.error_message)
+ assert exc.value.error_message == fail_msg
def test_plugin_open_url_json_fail_other(monkeypatch):
diff --git a/ansible_collections/community/hrobot/tests/requirements.yml b/ansible_collections/community/hrobot/tests/unit/requirements.yml
index dde980c10..586a6a1b3 100644
--- a/ansible_collections/community/hrobot/tests/requirements.yml
+++ b/ansible_collections/community/hrobot/tests/unit/requirements.yml
@@ -3,5 +3,5 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
-unit_tests_dependencies:
+collections:
- community.internal_test_tools
diff --git a/ansible_collections/community/library_inventory_filtering_v1/.github/dependabot.yml b/ansible_collections/community/library_inventory_filtering_v1/.github/dependabot.yml
new file mode 100644
index 000000000..2f4ff900d
--- /dev/null
+++ b/ansible_collections/community/library_inventory_filtering_v1/.github/dependabot.yml
@@ -0,0 +1,11 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+version: 2
+updates:
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "weekly"
diff --git a/ansible_collections/community/library_inventory_filtering_v1/.github/workflows/ansible-test.yml b/ansible_collections/community/library_inventory_filtering_v1/.github/workflows/ansible-test.yml
new file mode 100644
index 000000000..ff4cd6afd
--- /dev/null
+++ b/ansible_collections/community/library_inventory_filtering_v1/.github/workflows/ansible-test.yml
@@ -0,0 +1,87 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# For the comprehensive list of the inputs supported by the ansible-community/ansible-test-gh-action GitHub Action, see
+# https://github.com/marketplace/actions/ansible-test
+
+name: CI
+on:
+ # Run CI against all pushes (direct commits, also merged PRs), Pull Requests
+ push:
+ branches:
+ - stable-*
+ pull_request:
+ # Run CI once per day (at 04:45 UTC)
+ schedule:
+ - cron: '45 4 * * *'
+
+jobs:
+ sanity:
+ name: Sanity (Ⓐ${{ matrix.ansible }})
+ strategy:
+ matrix:
+ ansible:
+ # It's important that Sanity is tested against all stable-X.Y branches
+ # Testing against `devel` may fail as new tests are added.
+ - stable-2.9
+ - stable-2.10
+ - stable-2.11
+ - stable-2.12
+ - stable-2.13
+ - stable-2.14
+ - stable-2.15
+ - stable-2.16
+ - devel
+ # Ansible-test on various stable branches does not yet work well with cgroups v2.
+ # Since ubuntu-latest now uses Ubuntu 22.04, we need to fall back to the ubuntu-20.04
+ # image for these stable branches. The list of branches where this is necessary will
+ # shrink over time, check out https://github.com/ansible-collections/news-for-maintainers/issues/28
+ # for the latest list.
+ runs-on: >-
+ ${{ contains(fromJson(
+ '["stable-2.9", "stable-2.10", "stable-2.11"]'
+ ), matrix.ansible) && 'ubuntu-20.04' || 'ubuntu-latest' }}
+ steps:
+ - name: Perform sanity testing
+ uses: felixfontein/ansible-test-gh-action@main
+ with:
+ ansible-core-version: ${{ matrix.ansible }}
+ testing-type: sanity
+
+ units:
+ # Ansible-test on various stable branches does not yet work well with cgroups v2.
+ # Since ubuntu-latest now uses Ubuntu 22.04, we need to fall back to the ubuntu-20.04
+ # image for these stable branches. The list of branches where this is necessary will
+ # shrink over time, check out https://github.com/ansible-collections/news-for-maintainers/issues/28
+ # for the latest list.
+ runs-on: >-
+ ${{ contains(fromJson(
+ '["stable-2.9", "stable-2.10", "stable-2.11"]'
+ ), matrix.ansible) && 'ubuntu-20.04' || 'ubuntu-latest' }}
+ name: Units (Ⓐ${{ matrix.ansible }})
+ strategy:
+ # As soon as the first unit test fails, cancel the others to free up the CI queue
+ fail-fast: true
+ matrix:
+ ansible:
+ - stable-2.9
+ - stable-2.10
+ - stable-2.11
+ - stable-2.12
+ - stable-2.13
+ - stable-2.14
+ - stable-2.15
+ - stable-2.16
+ - devel
+
+ steps:
+ - name: Perform unit testing against Ansible version ${{ matrix.ansible }}
+ uses: felixfontein/ansible-test-gh-action@main
+ with:
+ ansible-core-version: ${{ matrix.ansible }}
+ testing-type: units
+ # NOTE: we're installing with git to work around Galaxy being a huge PITA (https://github.com/ansible/galaxy/issues/2429)
+ pre-test-cmd: >-
+ git clone --depth=1 --single-branch https://github.com/ansible-collections/community.internal_test_tools.git ../../community/internal_test_tools
diff --git a/ansible_collections/community/library_inventory_filtering_v1/.github/workflows/extra-tests.yml b/ansible_collections/community/library_inventory_filtering_v1/.github/workflows/extra-tests.yml
new file mode 100644
index 000000000..8352f7f32
--- /dev/null
+++ b/ansible_collections/community/library_inventory_filtering_v1/.github/workflows/extra-tests.yml
@@ -0,0 +1,47 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+name: extra-tests
+on:
+ # Run CI against all pushes (direct commits, also merged PRs), Pull Requests
+ push:
+ branches:
+ - stable-*
+ pull_request:
+ # Run CI once per day (at 04:45 UTC)
+ # This ensures that even if there haven't been commits that we are still testing against latest version of ansible-test for each ansible-base version
+ schedule:
+ - cron: '45 4 * * *'
+env:
+ NAMESPACE: community
+ COLLECTION_NAME: library_inventory_filtering_v1
+
+jobs:
+ extra-sanity:
+ name: Extra Sanity
+ runs-on: ubuntu-latest
+ steps:
+
+ - name: Check out code
+ uses: actions/checkout@v4
+ with:
+ path: ansible_collections/${{env.NAMESPACE}}/${{env.COLLECTION_NAME}}
+
+ - name: Set up Python
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.11'
+
+ - name: Install ansible-core
+ run: pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check
+
+ - name: Install collection dependencies
+ run: git clone --depth=1 --single-branch https://github.com/ansible-collections/community.internal_test_tools.git ./ansible_collections/community/internal_test_tools
+ # NOTE: we're installing with git to work around Galaxy being a huge PITA (https://github.com/ansible/galaxy/issues/2429)
+ # run: ansible-galaxy collection install community.internal_test_tools -p .
+
+ - name: Run sanity tests
+ run: ../../community/internal_test_tools/tools/run.py --color
+ working-directory: ./ansible_collections/${{env.NAMESPACE}}/${{env.COLLECTION_NAME}}
diff --git a/ansible_collections/community/library_inventory_filtering_v1/.github/workflows/import-galaxy.yml b/ansible_collections/community/library_inventory_filtering_v1/.github/workflows/import-galaxy.yml
new file mode 100644
index 000000000..45dcfafe0
--- /dev/null
+++ b/ansible_collections/community/library_inventory_filtering_v1/.github/workflows/import-galaxy.yml
@@ -0,0 +1,87 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+name: import-galaxy
+on:
+ # Run CI against all pushes (direct commits, also merged PRs) to main, and all Pull Requests
+ push:
+ branches:
+ - stable-*
+ pull_request:
+
+env:
+ # Adjust this to your collection
+ NAMESPACE: community
+ COLLECTION_NAME: library_inventory_filtering_v1
+
+jobs:
+ build-collection:
+ name: Build collection artifact
+ runs-on: ubuntu-latest
+ steps:
+ - name: Check out code
+ uses: actions/checkout@v4
+ with:
+ path: ./checkout
+
+ - name: Set up Python
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.11'
+
+ - name: Install ansible-core
+ run: pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check
+
+ - name: Make sure galaxy.yml has version entry
+ run: >-
+ python -c
+ 'import yaml ;
+ f = open("galaxy.yml", "rb") ;
+ data = yaml.safe_load(f) ;
+ f.close() ;
+ data["version"] = data.get("version") or "0.0.1" ;
+ f = open("galaxy.yml", "wb") ;
+ f.write(yaml.dump(data).encode("utf-8")) ;
+ f.close() ;
+ '
+ working-directory: ./checkout
+
+ - name: Build collection
+ run: ansible-galaxy collection build
+ working-directory: ./checkout
+
+ - name: Copy artifact into subdirectory
+ run: mkdir ./artifact && mv ./checkout/${{ env.NAMESPACE }}-${{ env.COLLECTION_NAME }}-*.tar.gz ./artifact
+
+ - name: Upload artifact
+ uses: actions/upload-artifact@v4
+ with:
+ name: ${{ env.NAMESPACE }}-${{ env.COLLECTION_NAME }}-${{ github.sha }}
+ path: ./artifact/
+
+ import-galaxy:
+ name: Import artifact with Galaxy importer
+ runs-on: ubuntu-latest
+ needs:
+ - build-collection
+ steps:
+ - name: Set up Python
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.11'
+
+ - name: Install ansible-core
+ run: pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check
+
+ - name: Install galaxy-importer
+ run: pip install galaxy-importer --disable-pip-version-check
+
+ - name: Download artifact
+ uses: actions/download-artifact@v4
+ with:
+ name: ${{ env.NAMESPACE }}-${{ env.COLLECTION_NAME }}-${{ github.sha }}
+
+ - name: Run Galaxy importer
+ run: python -m galaxy_importer.main ${{ env.NAMESPACE }}-${{ env.COLLECTION_NAME }}-*.tar.gz
diff --git a/ansible_collections/community/library_inventory_filtering_v1/.github/workflows/reuse.yml b/ansible_collections/community/library_inventory_filtering_v1/.github/workflows/reuse.yml
new file mode 100644
index 000000000..8785d624c
--- /dev/null
+++ b/ansible_collections/community/library_inventory_filtering_v1/.github/workflows/reuse.yml
@@ -0,0 +1,32 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+name: Verify REUSE
+
+on:
+ push:
+ branches:
+ - stable-*
+ pull_request:
+ # Run CI once per day (at 04:45 UTC)
+ schedule:
+ - cron: '45 4 * * *'
+
+jobs:
+ check:
+ permissions:
+ contents: read
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Install dependencies
+ run: |
+ pip install reuse
+
+ - name: Check REUSE compliance
+ run: |
+ reuse lint
diff --git a/ansible_collections/community/library_inventory_filtering_v1/.reuse/dep5 b/ansible_collections/community/library_inventory_filtering_v1/.reuse/dep5
new file mode 100644
index 000000000..0c3745ebf
--- /dev/null
+++ b/ansible_collections/community/library_inventory_filtering_v1/.reuse/dep5
@@ -0,0 +1,5 @@
+Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+
+Files: changelogs/fragments/*
+Copyright: Ansible Project
+License: GPL-3.0-or-later
diff --git a/ansible_collections/community/library_inventory_filtering_v1/CHANGELOG.rst b/ansible_collections/community/library_inventory_filtering_v1/CHANGELOG.rst
new file mode 100644
index 000000000..9f655c4cf
--- /dev/null
+++ b/ansible_collections/community/library_inventory_filtering_v1/CHANGELOG.rst
@@ -0,0 +1,22 @@
+==============================================================
+Community Inventory Filtering Library Collection Release Notes
+==============================================================
+
+.. contents:: Topics
+
+
+v1.0.0
+======
+
+Release Summary
+---------------
+
+First production ready release.
+
+v0.1.0
+======
+
+Release Summary
+---------------
+
+Initial test release.
diff --git a/ansible_collections/community/library_inventory_filtering_v1/CHANGELOG.rst.license b/ansible_collections/community/library_inventory_filtering_v1/CHANGELOG.rst.license
new file mode 100644
index 000000000..edff8c768
--- /dev/null
+++ b/ansible_collections/community/library_inventory_filtering_v1/CHANGELOG.rst.license
@@ -0,0 +1,3 @@
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
+SPDX-FileCopyrightText: Ansible Project
diff --git a/ansible_collections/community/fortios/LICENSE b/ansible_collections/community/library_inventory_filtering_v1/COPYING
index f288702d2..f288702d2 100644
--- a/ansible_collections/community/fortios/LICENSE
+++ b/ansible_collections/community/library_inventory_filtering_v1/COPYING
diff --git a/ansible_collections/community/library_inventory_filtering_v1/FILES.json b/ansible_collections/community/library_inventory_filtering_v1/FILES.json
new file mode 100644
index 000000000..f89f629d5
--- /dev/null
+++ b/ansible_collections/community/library_inventory_filtering_v1/FILES.json
@@ -0,0 +1,355 @@
+{
+ "files": [
+ {
+ "name": ".",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": ".github",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": ".github/workflows",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": ".github/workflows/ansible-test.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "29df556b00de431af2c7824813c09ceff4dc440903465c18b382e423cfdb04b8",
+ "format": 1
+ },
+ {
+ "name": ".github/workflows/extra-tests.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "34a58525f32c964e97de3b09619f3c2e540f1521db85f29679d3af6e1e689e89",
+ "format": 1
+ },
+ {
+ "name": ".github/workflows/import-galaxy.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "bf7394f8711a28c66c2a0b199e18c11d25d181cc827a2f7d0a0372a9f16ec0a9",
+ "format": 1
+ },
+ {
+ "name": ".github/workflows/reuse.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "5430af9a962c589c971154eb0dbd19a3f3a8b9eb870cb6c2d5e3896a5e962dac",
+ "format": 1
+ },
+ {
+ "name": ".github/dependabot.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f314f2fce46d346ef9559fdeae3a55ce6d799bab45a255092446c31e17e6874d",
+ "format": 1
+ },
+ {
+ "name": ".reuse",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": ".reuse/dep5",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9d8cb20d72d7e81aaf2e7f0ddce7eacdb3d47a890541717d7fae08a6cab7ebed",
+ "format": 1
+ },
+ {
+ "name": "LICENSES",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "LICENSES/GPL-3.0-or-later.txt",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "3972dc9744f6499f0f9b2dbf76696f2ae7ad8af9b23dde66d6af86c9dfb36986",
+ "format": 1
+ },
+ {
+ "name": "changelogs",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "changelogs/fragments",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "changelogs/fragments/.keep",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ "format": 1
+ },
+ {
+ "name": "changelogs/changelog.yaml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "77a81c4d67042178df11c3235affa25a4c80e9140a6cab05eb8382750f9b5abd",
+ "format": 1
+ },
+ {
+ "name": "changelogs/changelog.yaml.license",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6eb915239f9f35407fa68fdc41ed6522f1fdcce11badbdcd6057548023179ac1",
+ "format": 1
+ },
+ {
+ "name": "changelogs/config.yaml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e9f261ba6cc36a9d2639e0a51701fd8dd7e8c2ce7ae226380fb53da97a81a9cd",
+ "format": 1
+ },
+ {
+ "name": "meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "meta/runtime.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "4ed63a88ab6b7c15fc1ba0c16d2accb77b3305fff800731770f40609a7593393",
+ "format": 1
+ },
+ {
+ "name": "plugins",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "plugins/doc_fragments",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "plugins/doc_fragments/inventory_filter.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "2ab92d32537a93231ac4c6d9acb96537c5bb8638841c134613c664a5222acaee",
+ "format": 1
+ },
+ {
+ "name": "plugins/plugin_utils",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "plugins/plugin_utils/inventory_filter.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ba30f4d33b81c74a18cab8cbce209c84833789b81867b0e1be01d687472e03bb",
+ "format": 1
+ },
+ {
+ "name": "tests",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/sanity",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/sanity/extra",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/sanity/extra/extra-docs.json",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6c7fbc8a07fa803ce062387232eb0d0198a311f5347493f06c19a07aa45a9bf6",
+ "format": 1
+ },
+ {
+ "name": "tests/sanity/extra/extra-docs.json.license",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6eb915239f9f35407fa68fdc41ed6522f1fdcce11badbdcd6057548023179ac1",
+ "format": 1
+ },
+ {
+ "name": "tests/sanity/extra/extra-docs.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c52e316daf1292bbb063be19429fd1f06e02bce3c9d4622a8dfc61fa3af06688",
+ "format": 1
+ },
+ {
+ "name": "tests/sanity/extra/licenses.json",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "8c111eb62fa6f1b6c8a1260e9ff06c8b76ef8244428c6289969d79678093618f",
+ "format": 1
+ },
+ {
+ "name": "tests/sanity/extra/licenses.json.license",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6eb915239f9f35407fa68fdc41ed6522f1fdcce11badbdcd6057548023179ac1",
+ "format": 1
+ },
+ {
+ "name": "tests/sanity/extra/licenses.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ff502f0707adf15a57b2fc48842fc47d154bfbd3aeadf4c0c05e96b0589c3cd4",
+ "format": 1
+ },
+ {
+ "name": "tests/sanity/extra/licenses.py.license",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "88f745b5d91e1371369c207e3392877af6f3e1de48fbaca63a728d4dcf79e03c",
+ "format": 1
+ },
+ {
+ "name": "tests/sanity/extra/no-unwanted-files.json",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "a3d3b17f699b042958c7cd845a9d685bc935d83062e0bcf077f2c7200e2c0bac",
+ "format": 1
+ },
+ {
+ "name": "tests/sanity/extra/no-unwanted-files.json.license",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6eb915239f9f35407fa68fdc41ed6522f1fdcce11badbdcd6057548023179ac1",
+ "format": 1
+ },
+ {
+ "name": "tests/sanity/extra/no-unwanted-files.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "416fdc4ddd0ad89ddad54bcacc8bf5790d3a9610f7c059167123046849f0ade9",
+ "format": 1
+ },
+ {
+ "name": "tests/unit",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/plugin_utils",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/unit/plugins/plugin_utils/test_inventory_filter.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "7cd8dcd9c83396681e88db981df8505debf3df6f5ea383f19d5f4886b8eac6ef",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/requirements.txt",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "dbf3688bcda2816222b33ee535d6513ddc5c7814bcf91d9aefb85911b49f344d",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/requirements.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "999b6bb4a4234b1f38abb63cbd57d40af2d93bcff2260ab088e09157a055abaf",
+ "format": 1
+ },
+ {
+ "name": "tests/config.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "498d46cf08b5abb09880088fa8fd142315f7f775e94cdc7d41364ed20fc2cd65",
+ "format": 1
+ },
+ {
+ "name": "CHANGELOG.rst",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "48a7116aab933a579b4972ff4646af4a5a37a5059d168f10e50df8054e7951f1",
+ "format": 1
+ },
+ {
+ "name": "CHANGELOG.rst.license",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6eb915239f9f35407fa68fdc41ed6522f1fdcce11badbdcd6057548023179ac1",
+ "format": 1
+ },
+ {
+ "name": "COPYING",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "3972dc9744f6499f0f9b2dbf76696f2ae7ad8af9b23dde66d6af86c9dfb36986",
+ "format": 1
+ },
+ {
+ "name": "README.md",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "b81d36f2d772b7384f5ecc75329982c5cb5812c8532acc9c3f07effff53eb430",
+ "format": 1
+ },
+ {
+ "name": "codecov.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fccd5fc7ac924bcb9b7269c4ecd7c0fa7f25ed9fa1a88ced6f06f933a4f9b391",
+ "format": 1
+ }
+ ],
+ "format": 1
+} \ No newline at end of file
diff --git a/ansible_collections/community/google/LICENSE b/ansible_collections/community/library_inventory_filtering_v1/LICENSES/GPL-3.0-or-later.txt
index f288702d2..f288702d2 100644
--- a/ansible_collections/community/google/LICENSE
+++ b/ansible_collections/community/library_inventory_filtering_v1/LICENSES/GPL-3.0-or-later.txt
diff --git a/ansible_collections/community/library_inventory_filtering_v1/MANIFEST.json b/ansible_collections/community/library_inventory_filtering_v1/MANIFEST.json
new file mode 100644
index 000000000..eb2881bcc
--- /dev/null
+++ b/ansible_collections/community/library_inventory_filtering_v1/MANIFEST.json
@@ -0,0 +1,33 @@
+{
+ "collection_info": {
+ "namespace": "community",
+ "name": "library_inventory_filtering_v1",
+ "version": "1.0.0",
+ "authors": [
+ "Felix Fontein (github.com/felixfontein)"
+ ],
+ "readme": "README.md",
+ "tags": [
+ "inventory",
+ "filtering"
+ ],
+ "description": "Library for inventory plugins in other collections that allows to filter hosts in a generic way.",
+ "license": [
+ "GPL-3.0-or-later"
+ ],
+ "license_file": null,
+ "dependencies": {},
+ "repository": "https://github.com/ansible-collections/community.library_inventory_filtering",
+ "documentation": null,
+ "homepage": "https://github.com/ansible-collections/community.library_inventory_filtering",
+ "issues": "https://github.com/ansible-collections/community.library_inventory_filtering/issues"
+ },
+ "file_manifest_file": {
+ "name": "FILES.json",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9e2fea3417b34954669efe0b692abee7364e520719a215937bd30b3484b546e3",
+ "format": 1
+ },
+ "format": 1
+} \ No newline at end of file
diff --git a/ansible_collections/community/library_inventory_filtering_v1/README.md b/ansible_collections/community/library_inventory_filtering_v1/README.md
new file mode 100644
index 000000000..88299bbbb
--- /dev/null
+++ b/ansible_collections/community/library_inventory_filtering_v1/README.md
@@ -0,0 +1,52 @@
+<!--
+Copyright (c) Ansible Project
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
+-->
+
+# Community Inventory Filtering Library Collection
+[![CI](https://github.com/ansible-collections/community.library_inventory_filtering/workflows/CI/badge.svg?event=push)](https://github.com/ansible-collections/community.library_inventory_filtering/actions) [![Codecov](https://img.shields.io/codecov/c/github/ansible-collections/community.library_inventory_filtering)](https://codecov.io/gh/ansible-collections/community.library_inventory_filtering)
+
+This repository contains the `community.library_inventory_filtering_v1` Ansible Collection. The collection includes helpers for use with other collections, that allow inventory plugins to offer common filtering functionality.
+
+## Tested with Ansible
+
+Tested with the current Ansible 2.9, ansible-base 2.10, ansible-core 2.11, ansible-core 2.12, ansible-core 2.13, ansible-core 2.14, ansible-core 2.15, and ansible-core 2.16 releases and the current development version of ansible-core. Ansible versions before 2.9.10 are not supported.
+
+## Included content
+
+- `inventory_filter` docs fragment and plugin utils.
+
+## Using this collection
+
+Usually this collection is installed as a dependency of another collection. You do not need to install it explicitly.
+
+See [Ansible Using collections](https://docs.ansible.com/ansible/latest/user_guide/collections_using.html) for general instructions on how to use collections.
+
+## Contributing to this collection
+
+If you want to develop new content for this collection or improve what is already here, the easiest way to work on the collection is to clone it into one of the configured [`COLLECTIONS_PATH`](https://docs.ansible.com/ansible/latest/reference_appendices/config.html#collections-paths), and work on it there.
+
+You can find more information in the [developer guide for collections](https://docs.ansible.com/ansible/devel/dev_guide/developing_collections.html#contributing-to-collections), and in the [Ansible Community Guide](https://docs.ansible.com/ansible/latest/community/index.html).
+
+## Release notes
+
+See the [changelog](https://github.com/ansible-collections/community.library_inventory_filtering/tree/stable-1/CHANGELOG.rst).
+
+## More information
+
+- [Ansible Collection overview](https://github.com/ansible-collections/overview)
+- [Ansible User guide](https://docs.ansible.com/ansible/latest/user_guide/index.html)
+- [Ansible Developer guide](https://docs.ansible.com/ansible/latest/dev_guide/index.html)
+- [Ansible Collections Checklist](https://github.com/ansible-collections/overview/blob/master/collection_requirements.rst)
+- [Ansible Community code of conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html)
+- [The Bullhorn (the Ansible Contributor newsletter)](https://us19.campaign-archive.com/home/?u=56d874e027110e35dea0e03c1&id=d6635f5420)
+- [Changes impacting Contributors](https://github.com/ansible-collections/overview/issues/45)
+
+## Licensing
+
+This collection is primarily licensed and distributed as a whole under the GNU General Public License v3.0 or later.
+
+See [LICENSES/GPL-3.0-or-later.txt](https://github.com/ansible-collections/community.library_inventory_filtering/blob/stable-1/COPYING) for the full text.
+
+All files have a machine readable `SDPX-License-Identifier:` comment denoting its respective license(s) or an equivalent entry in an accompanying `.license` file. Only changelog fragments (which will not be part of a release) are covered by a blanket statement in `.reuse/dep5`. This conforms to the [REUSE specification](https://reuse.software/spec/).
diff --git a/ansible_collections/community/library_inventory_filtering_v1/changelogs/changelog.yaml b/ansible_collections/community/library_inventory_filtering_v1/changelogs/changelog.yaml
new file mode 100644
index 000000000..dc48b112a
--- /dev/null
+++ b/ansible_collections/community/library_inventory_filtering_v1/changelogs/changelog.yaml
@@ -0,0 +1,14 @@
+ancestor: null
+releases:
+ 0.1.0:
+ changes:
+ release_summary: Initial test release.
+ fragments:
+ - 0.1.0.yml
+ release_date: '2023-12-07'
+ 1.0.0:
+ changes:
+ release_summary: First production ready release.
+ fragments:
+ - 1.0.0.yml
+ release_date: '2023-12-28'
diff --git a/ansible_collections/community/library_inventory_filtering_v1/changelogs/changelog.yaml.license b/ansible_collections/community/library_inventory_filtering_v1/changelogs/changelog.yaml.license
new file mode 100644
index 000000000..edff8c768
--- /dev/null
+++ b/ansible_collections/community/library_inventory_filtering_v1/changelogs/changelog.yaml.license
@@ -0,0 +1,3 @@
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
+SPDX-FileCopyrightText: Ansible Project
diff --git a/ansible_collections/community/skydive/changelogs/config.yaml b/ansible_collections/community/library_inventory_filtering_v1/changelogs/config.yaml
index 92d466964..a64e83dc6 100644
--- a/ansible_collections/community/skydive/changelogs/config.yaml
+++ b/ansible_collections/community/library_inventory_filtering_v1/changelogs/config.yaml
@@ -1,8 +1,12 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
changelog_filename_template: ../CHANGELOG.rst
changelog_filename_version_depth: 0
changes_file: changelog.yaml
changes_format: combined
-ignore_other_fragment_extensions: true
keep_fragments: false
mention_ancestor: true
new_plugins_after_name: removed_features
@@ -26,6 +30,6 @@ sections:
- Bugfixes
- - known_issues
- Known Issues
-title: Skydive
+title: Community Inventory Filtering Library Collection
trivial_section_name: trivial
use_fqcn: true
diff --git a/ansible_collections/community/fortios/changelogs/fragments/.keep b/ansible_collections/community/library_inventory_filtering_v1/changelogs/fragments/.keep
index e69de29bb..e69de29bb 100644
--- a/ansible_collections/community/fortios/changelogs/fragments/.keep
+++ b/ansible_collections/community/library_inventory_filtering_v1/changelogs/fragments/.keep
diff --git a/ansible_collections/community/library_inventory_filtering_v1/codecov.yml b/ansible_collections/community/library_inventory_filtering_v1/codecov.yml
new file mode 100644
index 000000000..200063a85
--- /dev/null
+++ b/ansible_collections/community/library_inventory_filtering_v1/codecov.yml
@@ -0,0 +1,7 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+fixes:
+ - "ansible_collections/community/library_inventory_filtering_v1/::"
diff --git a/ansible_collections/community/library_inventory_filtering_v1/meta/runtime.yml b/ansible_collections/community/library_inventory_filtering_v1/meta/runtime.yml
new file mode 100644
index 000000000..d642fb895
--- /dev/null
+++ b/ansible_collections/community/library_inventory_filtering_v1/meta/runtime.yml
@@ -0,0 +1,6 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+requires_ansible: '>=2.9.10'
diff --git a/ansible_collections/community/library_inventory_filtering_v1/plugins/doc_fragments/inventory_filter.py b/ansible_collections/community/library_inventory_filtering_v1/plugins/doc_fragments/inventory_filter.py
new file mode 100644
index 000000000..64ce2fa5f
--- /dev/null
+++ b/ansible_collections/community/library_inventory_filtering_v1/plugins/doc_fragments/inventory_filter.py
@@ -0,0 +1,36 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+
+class ModuleDocFragment(object):
+
+ # Docker doc fragment
+ DOCUMENTATION = r'''
+options:
+ filters:
+ description:
+ - A list of include/exclude filters that allows to select/deselect hosts for this inventory.
+ - Filters are processed sequentially until the first filter where O(filters[].exclude) or
+ O(filters[].include) matches is found. In case O(filters[].exclude) matches, the host is
+ excluded, and in case O(filters[].include) matches, the host is included. In case no filter
+ matches, the host is included.
+ type: list
+ elements: dict
+ suboptions:
+ exclude:
+ description:
+ - A Jinja2 condition. If it matches for a host, that host is B(excluded).
+ - Exactly one of O(filters[].exclude) and O(filters[].include) can be specified.
+ type: str
+ include:
+ description:
+ - A Jinja2 condition. If it matches for a host, that host is B(included).
+ - Exactly one of O(filters[].exclude) and O(filters[].include) can be specified.
+ type: str
+'''
diff --git a/ansible_collections/community/library_inventory_filtering_v1/plugins/plugin_utils/inventory_filter.py b/ansible_collections/community/library_inventory_filtering_v1/plugins/plugin_utils/inventory_filter.py
new file mode 100644
index 000000000..460dc208e
--- /dev/null
+++ b/ansible_collections/community/library_inventory_filtering_v1/plugins/plugin_utils/inventory_filter.py
@@ -0,0 +1,91 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+from ansible.errors import AnsibleError, AnsibleParserError
+from ansible.module_utils.common._collections_compat import Mapping
+from ansible.module_utils.common.text.converters import to_native
+from ansible.module_utils.parsing.convert_bool import boolean
+from ansible.module_utils.six import string_types
+
+
+_ALLOWED_KEYS = ('include', 'exclude')
+
+
+def parse_filters(filters):
+ """
+ Parse get_option('filter') and return normalized version to be fed into filter_host().
+ """
+ result = []
+ if filters is None:
+ return result
+ for index, filter in enumerate(filters):
+ if not isinstance(filter, Mapping):
+ raise AnsibleError('filter[{index}] must be a dictionary'.format(
+ index=index + 1,
+ ))
+ if len(filter) != 1:
+ raise AnsibleError('filter[{index}] must have exactly one key-value pair'.format(
+ index=index + 1,
+ ))
+ key, value = list(filter.items())[0]
+ if key not in _ALLOWED_KEYS:
+ raise AnsibleError('filter[{index}] must have a {allowed_keys} key, not "{key}"'.format(
+ index=index + 1,
+ key=key,
+ allowed_keys=' or '.join('"{key}"'.format(key=key) for key in _ALLOWED_KEYS),
+ ))
+ if not isinstance(value, (string_types, bool)):
+ raise AnsibleError('filter[{index}].{key} must be a string, not {value_type}'.format(
+ index=index + 1,
+ key=key,
+ value_type=type(value),
+ ))
+ result.append(filter)
+ return result
+
+
+def filter_host(inventory_plugin, host, host_vars, filters):
+ """
+ Determine whether a host should be accepted (``True``) or not (``False``).
+ """
+ vars = {
+ 'inventory_hostname': host,
+ }
+ if host_vars:
+ vars.update(host_vars)
+
+ def evaluate(condition):
+ if isinstance(condition, bool):
+ return condition
+ conditional = "{%% if %s %%} True {%% else %%} False {%% endif %%}" % condition
+ templar = inventory_plugin.templar
+ old_vars = templar.available_variables
+ try:
+ templar.available_variables = vars
+ return boolean(templar.template(conditional))
+ except Exception as e:
+ raise AnsibleParserError("Could not evaluate filter condition {condition!r} for host {host}: {err}".format(
+ host=host,
+ condition=condition,
+ err=to_native(e),
+ ))
+ finally:
+ templar.available_variables = old_vars
+
+ for filter in filters:
+ if 'include' in filter:
+ expr = filter['include']
+ if evaluate(expr):
+ return True
+ if 'exclude' in filter:
+ expr = filter['exclude']
+ if evaluate(expr):
+ return False
+
+ return True
diff --git a/ansible_collections/community/library_inventory_filtering_v1/tests/config.yml b/ansible_collections/community/library_inventory_filtering_v1/tests/config.yml
new file mode 100644
index 000000000..38590f2e4
--- /dev/null
+++ b/ansible_collections/community/library_inventory_filtering_v1/tests/config.yml
@@ -0,0 +1,9 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# See template for more information:
+# https://github.com/ansible/ansible/blob/devel/test/lib/ansible_test/config/config.yml
+modules:
+ python_requires: default
diff --git a/ansible_collections/community/library_inventory_filtering_v1/tests/sanity/extra/extra-docs.json b/ansible_collections/community/library_inventory_filtering_v1/tests/sanity/extra/extra-docs.json
new file mode 100644
index 000000000..9a28d174f
--- /dev/null
+++ b/ansible_collections/community/library_inventory_filtering_v1/tests/sanity/extra/extra-docs.json
@@ -0,0 +1,13 @@
+{
+ "include_symlinks": false,
+ "prefixes": [
+ "docs/docsite/",
+ "plugins/",
+ "roles/"
+ ],
+ "output": "path-line-column-message",
+ "requirements": [
+ "ansible-core",
+ "antsibull-docs"
+ ]
+}
diff --git a/ansible_collections/community/library_inventory_filtering_v1/tests/sanity/extra/extra-docs.json.license b/ansible_collections/community/library_inventory_filtering_v1/tests/sanity/extra/extra-docs.json.license
new file mode 100644
index 000000000..edff8c768
--- /dev/null
+++ b/ansible_collections/community/library_inventory_filtering_v1/tests/sanity/extra/extra-docs.json.license
@@ -0,0 +1,3 @@
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
+SPDX-FileCopyrightText: Ansible Project
diff --git a/ansible_collections/community/library_inventory_filtering_v1/tests/sanity/extra/extra-docs.py b/ansible_collections/community/library_inventory_filtering_v1/tests/sanity/extra/extra-docs.py
new file mode 100755
index 000000000..251e6d70f
--- /dev/null
+++ b/ansible_collections/community/library_inventory_filtering_v1/tests/sanity/extra/extra-docs.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+"""Check extra collection docs with antsibull-docs."""
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import os
+import sys
+import subprocess
+
+
+def main():
+ """Main entry point."""
+ env = os.environ.copy()
+ suffix = ':{env}'.format(env=env["ANSIBLE_COLLECTIONS_PATH"]) if 'ANSIBLE_COLLECTIONS_PATH' in env else ''
+ env['ANSIBLE_COLLECTIONS_PATH'] = '{root}{suffix}'.format(root=os.path.dirname(os.path.dirname(os.path.dirname(os.getcwd()))), suffix=suffix)
+ p = subprocess.run(
+ ['antsibull-docs', 'lint-collection-docs', '--plugin-docs', '--skip-rstcheck', '.'],
+ env=env,
+ check=False,
+ )
+ if p.returncode not in (0, 3):
+ print('{0}:0:0: unexpected return code {1}'.format(sys.argv[0], p.returncode))
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/library_inventory_filtering_v1/tests/sanity/extra/licenses.json b/ansible_collections/community/library_inventory_filtering_v1/tests/sanity/extra/licenses.json
new file mode 100644
index 000000000..50e47ca88
--- /dev/null
+++ b/ansible_collections/community/library_inventory_filtering_v1/tests/sanity/extra/licenses.json
@@ -0,0 +1,4 @@
+{
+ "include_symlinks": false,
+ "output": "path-message"
+}
diff --git a/ansible_collections/community/library_inventory_filtering_v1/tests/sanity/extra/licenses.json.license b/ansible_collections/community/library_inventory_filtering_v1/tests/sanity/extra/licenses.json.license
new file mode 100644
index 000000000..edff8c768
--- /dev/null
+++ b/ansible_collections/community/library_inventory_filtering_v1/tests/sanity/extra/licenses.json.license
@@ -0,0 +1,3 @@
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
+SPDX-FileCopyrightText: Ansible Project
diff --git a/ansible_collections/community/library_inventory_filtering_v1/tests/sanity/extra/licenses.py b/ansible_collections/community/library_inventory_filtering_v1/tests/sanity/extra/licenses.py
new file mode 100755
index 000000000..80eb795ef
--- /dev/null
+++ b/ansible_collections/community/library_inventory_filtering_v1/tests/sanity/extra/licenses.py
@@ -0,0 +1,110 @@
+#!/usr/bin/env python
+# Copyright (c) 2022, Felix Fontein <felix@fontein.de>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+"""Prevent files without a correct license identifier from being added to the source tree."""
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import os
+import glob
+import sys
+
+
+def format_license_list(licenses):
+ if not licenses:
+ return '(empty)'
+ return ', '.join(['"%s"' % license for license in licenses])
+
+
+def find_licenses(filename, relax=False):
+ spdx_license_identifiers = []
+ other_license_identifiers = []
+ has_copyright = False
+ try:
+ with open(filename, 'r', encoding='utf-8') as f:
+ for line in f:
+ line = line.rstrip()
+ if 'Copyright ' in line:
+ has_copyright = True
+ if 'Copyright: ' in line:
+ print('%s: found copyright line with "Copyright:". Please remove the colon.' % (filename, ))
+ if 'SPDX-FileCopyrightText: ' in line:
+ has_copyright = True
+ idx = line.find('SPDX-License-Identifier: ')
+ if idx >= 0:
+ lic_id = line[idx + len('SPDX-License-Identifier: '):]
+ spdx_license_identifiers.extend(lic_id.split(' OR '))
+ if 'GNU General Public License' in line:
+ if 'v3.0+' in line:
+ other_license_identifiers.append('GPL-3.0-or-later')
+ if 'version 3 or later' in line:
+ other_license_identifiers.append('GPL-3.0-or-later')
+ if 'Simplified BSD License' in line:
+ other_license_identifiers.append('BSD-2-Clause')
+ if 'Apache License 2.0' in line:
+ other_license_identifiers.append('Apache-2.0')
+ if 'PSF License' in line or 'Python-2.0' in line:
+ other_license_identifiers.append('PSF-2.0')
+ if 'MIT License' in line:
+ other_license_identifiers.append('MIT')
+ except Exception as exc:
+ print('%s: error while processing file: %s' % (filename, exc))
+ if len(set(spdx_license_identifiers)) < len(spdx_license_identifiers):
+ print('%s: found identical SPDX-License-Identifier values' % (filename, ))
+ if other_license_identifiers and set(other_license_identifiers) != set(spdx_license_identifiers):
+ print('%s: SPDX-License-Identifier yielded the license list %s, while manual guessing yielded the license list %s' % (
+ filename, format_license_list(spdx_license_identifiers), format_license_list(other_license_identifiers)))
+ if not has_copyright and not relax:
+ print('%s: found no copyright notice' % (filename, ))
+ return sorted(spdx_license_identifiers)
+
+
+def main():
+ """Main entry point."""
+ paths = sys.argv[1:] or sys.stdin.read().splitlines()
+
+ # The following paths are allowed to have no license identifier
+ no_comments_allowed = [
+ 'changelogs/fragments/*.yml',
+ 'changelogs/fragments/*.yaml',
+ ]
+
+ # These files are completely ignored
+ ignore_paths = [
+ '.ansible-test-timeout.json',
+ '.reuse/dep5',
+ 'LICENSES/*.txt',
+ 'COPYING',
+ ]
+
+ no_comments_allowed = [fn for pattern in no_comments_allowed for fn in glob.glob(pattern)]
+ ignore_paths = [fn for pattern in ignore_paths for fn in glob.glob(pattern)]
+
+ valid_licenses = [license_file[len('LICENSES/'):-len('.txt')] for license_file in glob.glob('LICENSES/*.txt')]
+
+ for path in paths:
+ if path.startswith('./'):
+ path = path[2:]
+ if path in ignore_paths or path.startswith('tests/output/'):
+ continue
+ if os.stat(path).st_size == 0:
+ continue
+ if not path.endswith('.license') and os.path.exists(path + '.license'):
+ path = path + '.license'
+ valid_licenses_for_path = valid_licenses
+ if path.startswith('plugins/') and not path.startswith(('plugins/modules/', 'plugins/module_utils/')):
+ valid_licenses_for_path = [license for license in valid_licenses if license == 'GPL-3.0-or-later']
+ licenses = find_licenses(path, relax=path in no_comments_allowed)
+ if not licenses:
+ if path not in no_comments_allowed:
+ print('%s: must have at least one license' % (path, ))
+ else:
+ for license in licenses:
+ if license not in valid_licenses_for_path:
+ print('%s: found not allowed license "%s", must be one of %s' % (
+ path, license, format_license_list(valid_licenses_for_path)))
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/library_inventory_filtering_v1/tests/sanity/extra/licenses.py.license b/ansible_collections/community/library_inventory_filtering_v1/tests/sanity/extra/licenses.py.license
new file mode 100644
index 000000000..6c4958feb
--- /dev/null
+++ b/ansible_collections/community/library_inventory_filtering_v1/tests/sanity/extra/licenses.py.license
@@ -0,0 +1,3 @@
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
+SPDX-FileCopyrightText: 2022, Felix Fontein <felix@fontein.de>
diff --git a/ansible_collections/community/library_inventory_filtering_v1/tests/sanity/extra/no-unwanted-files.json b/ansible_collections/community/library_inventory_filtering_v1/tests/sanity/extra/no-unwanted-files.json
new file mode 100644
index 000000000..c789a7fd3
--- /dev/null
+++ b/ansible_collections/community/library_inventory_filtering_v1/tests/sanity/extra/no-unwanted-files.json
@@ -0,0 +1,7 @@
+{
+ "include_symlinks": true,
+ "prefixes": [
+ "plugins/"
+ ],
+ "output": "path-message"
+}
diff --git a/ansible_collections/community/library_inventory_filtering_v1/tests/sanity/extra/no-unwanted-files.json.license b/ansible_collections/community/library_inventory_filtering_v1/tests/sanity/extra/no-unwanted-files.json.license
new file mode 100644
index 000000000..edff8c768
--- /dev/null
+++ b/ansible_collections/community/library_inventory_filtering_v1/tests/sanity/extra/no-unwanted-files.json.license
@@ -0,0 +1,3 @@
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
+SPDX-FileCopyrightText: Ansible Project
diff --git a/ansible_collections/community/library_inventory_filtering_v1/tests/sanity/extra/no-unwanted-files.py b/ansible_collections/community/library_inventory_filtering_v1/tests/sanity/extra/no-unwanted-files.py
new file mode 100755
index 000000000..51444ab75
--- /dev/null
+++ b/ansible_collections/community/library_inventory_filtering_v1/tests/sanity/extra/no-unwanted-files.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+"""Prevent unwanted files from being added to the source tree."""
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import os
+import sys
+
+
+def main():
+ """Main entry point."""
+ paths = sys.argv[1:] or sys.stdin.read().splitlines()
+
+ allowed_extensions = (
+ '.cs',
+ '.ps1',
+ '.psm1',
+ '.py',
+ )
+
+ skip_paths = set([
+ ])
+
+ skip_directories = (
+ )
+
+ for path in paths:
+ if path in skip_paths:
+ continue
+
+ if any(path.startswith(skip_directory) for skip_directory in skip_directories):
+ continue
+
+ ext = os.path.splitext(path)[1]
+
+ if ext not in allowed_extensions:
+ print('%s: extension must be one of: %s' % (path, ', '.join(allowed_extensions)))
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/library_inventory_filtering_v1/tests/unit/plugins/plugin_utils/test_inventory_filter.py b/ansible_collections/community/library_inventory_filtering_v1/tests/unit/plugins/plugin_utils/test_inventory_filter.py
new file mode 100644
index 000000000..5d354f05e
--- /dev/null
+++ b/ansible_collections/community/library_inventory_filtering_v1/tests/unit/plugins/plugin_utils/test_inventory_filter.py
@@ -0,0 +1,114 @@
+# Copyright (c), Felix Fontein <felix@fontein.de>, 2023
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+
+import pytest
+
+from ansible.errors import AnsibleError, AnsibleParserError
+from ansible.template import Templar
+
+from mock import MagicMock
+from ansible_collections.community.internal_test_tools.tests.unit.mock.loader import DictDataLoader
+
+from .....plugins.plugin_utils.inventory_filter import parse_filters, filter_host
+
+
+@pytest.fixture(scope='module')
+def inventory():
+ r = MagicMock()
+ r.templar = Templar(loader=DictDataLoader({}))
+ return r
+
+
+@pytest.mark.parametrize('input', [
+ None,
+ [],
+ [{'include': 'foo'}],
+ [{'include': True}],
+ [{'exclude': 'foo'}],
+ [{'exclude': False}],
+])
+def test_parse_success(input):
+ result = parse_filters(input)
+ print(result)
+ assert result == (input or [])
+
+
+@pytest.mark.parametrize('input, output', [
+ (
+ [23],
+ ('filter[1] must be a dictionary', ),
+ ),
+ (
+ [{}],
+ ('filter[1] must have exactly one key-value pair', ),
+ ),
+ (
+ [{'a': 'b', 'c': 'd'}],
+ ('filter[1] must have exactly one key-value pair', ),
+ ),
+ (
+ [{'foo': 'bar'}],
+ ('filter[1] must have a "include" or "exclude" key, not "foo"', ),
+ ),
+ (
+ [{'include': 23}],
+ (
+ "filter[1].include must be a string, not <class 'int'>",
+ "filter[1].include must be a string, not <type 'int'>",
+ ),
+ ),
+])
+def test_parse_errors(input, output):
+ with pytest.raises(AnsibleError) as exc:
+ parse_filters(input)
+
+ print(exc.value.args[0])
+ assert exc.value.args[0] in output
+
+
+@pytest.mark.parametrize('host, host_vars, filters, result', [
+ (
+ 'example.com',
+ {},
+ [],
+ True,
+ ),
+ (
+ 'example.com',
+ {'foo': 'bar'},
+ [{'include': 'inventory_hostname == "example.com"'}, {'exclude': 'true'}],
+ True,
+ ),
+ (
+ 'example.com',
+ {},
+ [{'include': 'inventory_hostname == "foo.com"'}, {'exclude': 'false'}, {'exclude': True}],
+ False,
+ ),
+])
+def test_filter_success(inventory, host, host_vars, filters, result):
+ assert filter_host(inventory, host, host_vars, filters) == result
+
+
+@pytest.mark.parametrize('host, host_vars, filters, result', [
+ (
+ 'example.com',
+ {},
+ [{'include': 'foobar'}],
+ (
+ "Could not evaluate filter condition 'foobar' for host example.com: 'foobar' is undefined",
+ "Could not evaluate filter condition 'foobar' for host example.com: 'foobar' is undefined. 'foobar' is undefined",
+ ),
+ ),
+])
+def test_filter_errors(inventory, host, host_vars, filters, result):
+ with pytest.raises(AnsibleParserError) as exc:
+ filter_host(inventory, host, host_vars, filters)
+
+ print(exc.value.args[0])
+ assert exc.value.args[0] in result
diff --git a/ansible_collections/community/library_inventory_filtering_v1/tests/unit/requirements.txt b/ansible_collections/community/library_inventory_filtering_v1/tests/unit/requirements.txt
new file mode 100644
index 000000000..4e4af39b1
--- /dev/null
+++ b/ansible_collections/community/library_inventory_filtering_v1/tests/unit/requirements.txt
@@ -0,0 +1,6 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+unittest2 ; python_version < '2.7'
+importlib ; python_version < '2.7'
diff --git a/ansible_collections/community/library_inventory_filtering_v1/tests/unit/requirements.yml b/ansible_collections/community/library_inventory_filtering_v1/tests/unit/requirements.yml
new file mode 100644
index 000000000..586a6a1b3
--- /dev/null
+++ b/ansible_collections/community/library_inventory_filtering_v1/tests/unit/requirements.yml
@@ -0,0 +1,7 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+collections:
+- community.internal_test_tools
diff --git a/ansible_collections/community/libvirt/.azure-pipelines/azure-pipelines.yml b/ansible_collections/community/libvirt/.azure-pipelines/azure-pipelines.yml
index f6912428a..71bab55d2 100644
--- a/ansible_collections/community/libvirt/.azure-pipelines/azure-pipelines.yml
+++ b/ansible_collections/community/libvirt/.azure-pipelines/azure-pipelines.yml
@@ -36,7 +36,7 @@ variables:
resources:
containers:
- container: default
- image: quay.io/ansible/azure-pipelines-test-container:3.0.0
+ image: quay.io/ansible/azure-pipelines-test-container:4.0.1
pool: Standard
@@ -56,65 +56,66 @@ stages:
- name: Units
test: 'devel/units/1'
- - stage: Ansible_2_13
- displayName: Sanity & Units 2.13
+ - stage: Ansible_2_16
+ displayName: Sanity & Units 2.16
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
targets:
- name: Sanity
- test: '2.13/sanity/1'
+ test: '2.16/sanity/1'
- name: Units
- test: '2.13/units/1'
+ test: '2.16/units/1'
- - stage: Ansible_2_12
- displayName: Sanity & Units 2.12
+ - stage: Ansible_2_15
+ displayName: Sanity & Units 2.15
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
targets:
- name: Sanity
- test: '2.12/sanity/1'
+ test: '2.15/sanity/1'
- name: Units
- test: '2.12/units/1'
+ test: '2.15/units/1'
- - stage: Ansible_2_11
- displayName: Sanity & Units 2.11
+ - stage: Ansible_2_14
+ displayName: Sanity & Units 2.14
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
targets:
- name: Sanity
- test: '2.11/sanity/1'
+ test: '2.14/sanity/1'
- name: Units
- test: '2.11/units/1'
+ test: '2.14/units/1'
- - stage: Ansible_2_10
- displayName: Sanity & Units 2.10
+ - stage: Ansible_2_13
+ displayName: Sanity & Units 2.13
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
targets:
- name: Sanity
- test: '2.10/sanity/1'
+ test: '2.13/sanity/1'
- name: Units
- test: '2.10/units/1'
+ test: '2.13/units/1'
- - stage: Ansible_2_9
- displayName: Sanity & Units 2.9
+ - stage: Ansible_2_12
+ displayName: Sanity & Units 2.12
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
targets:
- name: Sanity
- test: '2.9/sanity/1'
+ test: '2.12/sanity/1'
- name: Units
- test: '2.9/units/1'
+ test: '2.12/units/1'
+
### Docker
- stage: Docker_devel
displayName: Docker devel
@@ -126,10 +127,8 @@ stages:
targets:
- name: CentOS 7
test: centos7
- - name: Fedora 35
- test: fedora35
- - name: Fedora 36
- test: fedora36
+ - name: Fedora 38
+ test: fedora38
- name: openSUSE 15 py3
test: opensuse15
- name: Ubuntu 20.04
@@ -137,124 +136,104 @@ stages:
- name: Ubuntu 22.04
test: ubuntu2204
- - stage: Docker_2_13
- displayName: Docker 2.13
+ - stage: Docker_2_16
+ displayName: Docker 2.16
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
- testFormat: 2.13/linux/{0}/1
+ testFormat: 2.16/linux/{0}/1
targets:
- name: CentOS 7
test: centos7
- - name: Fedora 34
- test: fedora34
- - name: openSUSE 15 py2
- test: opensuse15py2
+ - name: Fedora 38
+ test: fedora38
- name: openSUSE 15 py3
test: opensuse15
- - name: Ubuntu 18.04
- test: ubuntu1804
- name: Ubuntu 20.04
test: ubuntu2004
+ - name: Ubuntu 22.04
+ test: ubuntu2204
- - stage: Docker_2_12
- displayName: Docker 2.12
+ - stage: Docker_2_15
+ displayName: Docker 2.15
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
- testFormat: 2.12/linux/{0}/1
+ testFormat: 2.15/linux/{0}/1
targets:
- name: CentOS 7
test: centos7
- - name: Fedora 33
- test: fedora33
- - name: Fedora 34
- test: fedora34
- - name: openSUSE 15 py2
- test: opensuse15py2
+ - name: Fedora 37
+ test: fedora37
- name: openSUSE 15 py3
test: opensuse15
- - name: Ubuntu 18.04
- test: ubuntu1804
- name: Ubuntu 20.04
test: ubuntu2004
- - stage: Docker_2_11
- displayName: Docker 2.11
+ - stage: Docker_2_14
+ displayName: Docker 2.14
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
- testFormat: 2.11/linux/{0}/1
+ testFormat: 2.14/linux/{0}/1
targets:
- - name: CentOS 6
- test: centos6
- name: CentOS 7
test: centos7
- - name: Fedora 32
- test: fedora32
- - name: Fedora 33
- test: fedora33
- - name: openSUSE 15 py2
- test: opensuse15py2
+ - name: Fedora 36
+ test: fedora36
- name: openSUSE 15 py3
test: opensuse15
- - name: Ubuntu 18.04
- test: ubuntu1804
- name: Ubuntu 20.04
test: ubuntu2004
- - stage: Docker_2_10
- displayName: Docker 2.10
+ - stage: Docker_2_13
+ displayName: Docker 2.13
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
- testFormat: 2.10/linux/{0}/1
+ testFormat: 2.13/linux/{0}/1
targets:
- - name: CentOS 6
- test: centos6
- name: CentOS 7
test: centos7
- - name: Fedora 31
- test: fedora31
- - name: Fedora 32
- test: fedora32
+ - name: Fedora 34
+ test: fedora34
+ - name: Fedora 35
+ test: fedora35
- name: openSUSE 15 py2
test: opensuse15py2
- name: openSUSE 15 py3
test: opensuse15
- - name: Ubuntu 16.04
- test: ubuntu1604
- name: Ubuntu 18.04
test: ubuntu1804
+ - name: Ubuntu 20.04
+ test: ubuntu2004
- - stage: Docker_2_9
- displayName: Docker 2.9
+ - stage: Docker_2_12
+ displayName: Docker 2.12
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
- testFormat: 2.9/linux/{0}/1
+ testFormat: 2.12/linux/{0}/1
targets:
- - name: CentOS 6
- test: centos6
- name: CentOS 7
test: centos7
- - name: Fedora 31
- test: fedora31
- - name: Fedora 32
- test: fedora32
+ - name: Fedora 33
+ test: fedora33
+ - name: Fedora 34
+ test: fedora34
- name: openSUSE 15 py2
test: opensuse15py2
- name: openSUSE 15 py3
test: opensuse15
- - name: Ubuntu 16.04
- test: ubuntu1604
- name: Ubuntu 18.04
test: ubuntu1804
+ - name: Ubuntu 20.04
+ test: ubuntu2004
### Remote
- stage: Remote_devel
@@ -267,12 +246,57 @@ stages:
targets:
- name: RHEL 7.9
test: rhel/7.9
- - name: RHEL 8.6
- test: rhel/8.6
+ - name: RHEL 8.8
+ test: rhel/8.8
+ - name: RHEL 9.2
+ test: rhel/9.2
+ - name: FreeBSD 13.2
+ test: freebsd/13.2
+
+ - stage: Remote_2_16
+ displayName: Remote 2.16
+ dependsOn: []
+ jobs:
+ - template: templates/matrix.yml
+ parameters:
+ testFormat: '2.16/{0}/1'
+ targets:
+ - name: RHEL 7.9
+ test: rhel/7.9
+ - name: RHEL 8.8
+ test: rhel/8.8
+ - name: RHEL 9.2
+ test: rhel/9.2
+ - name: FreeBSD 13.2
+ test: freebsd/13.2
+
+ - stage: Remote_2_15
+ displayName: Remote 2.15
+ dependsOn: []
+ jobs:
+ - template: templates/matrix.yml
+ parameters:
+ testFormat: '2.15/{0}/1'
+ targets:
+ - name: RHEL 9.1
+ test: rhel/9.1
+ - name: RHEL 8.7
+ test: rhel/8.7
+ - name: FreeBSD 13.1
+ test: freebsd/13.1
+
+ - stage: Remote_2_14
+ displayName: Remote 2.14
+ dependsOn: []
+ jobs:
+ - template: templates/matrix.yml
+ parameters:
+ testFormat: '2.14/{0}/1'
+ targets:
- name: RHEL 9.0
test: rhel/9.0
- - name: FreeBSD 12.3
- test: freebsd/12.3
+ - name: RHEL 8.6
+ test: rhel/8.6
- name: FreeBSD 13.1
test: freebsd/13.1
@@ -286,8 +310,8 @@ stages:
targets:
- name: RHEL 8.5
test: rhel/8.5
- - name: FreeBSD 13.0
- test: freebsd/13.0
+ - name: FreeBSD 13.1
+ test: freebsd/13.1
- stage: Remote_2_12
displayName: Remote 2.12
@@ -306,77 +330,26 @@ stages:
- name: FreeBSD 13.0
test: freebsd/13.0
- - stage: Remote_2_11
- displayName: Remote 2.11
- dependsOn: []
- jobs:
- - template: templates/matrix.yml
- parameters:
- testFormat: '2.11/{0}/1'
- targets:
- - name: RHEL 7.9
- test: rhel/7.9
- - name: RHEL 8.3
- test: rhel/8.3
- - name: FreeBSD 11.4
- test: freebsd/11.4
- - name: FreeBSD 12.2
- test: freebsd/12.2
-
- - stage: Remote_2_10
- displayName: Remote 2.10
- dependsOn: []
- jobs:
- - template: templates/matrix.yml
- parameters:
- testFormat: '2.10/{0}/1'
- targets:
- - name: RHEL 7.8
- test: rhel/7.8
- - name: RHEL 8.2
- test: rhel/8.2
- - name: FreeBSD 11.1
- test: freebsd/11.1
- - name: FreeBSD 12.1
- test: freebsd/12.1
-
- - stage: Remote_2_9
- displayName: Remote 2.9
- dependsOn: []
- jobs:
- - template: templates/matrix.yml
- parameters:
- testFormat: '2.9/{0}/1'
- targets:
- - name: RHEL 7.8
- test: rhel/7.8
- - name: RHEL 8.2
- test: rhel/8.2
- - name: FreeBSD 11.1
- test: freebsd/11.1
- - name: FreeBSD 12.1
- test: freebsd/12.1
-
- stage: Summary
condition: succeededOrFailed()
dependsOn:
- Ansible_devel
+ - Ansible_2_16
+ - Ansible_2_15
+ - Ansible_2_14
- Ansible_2_13
- Ansible_2_12
- - Ansible_2_11
- - Ansible_2_10
- - Ansible_2_9
- Docker_devel
+ - Docker_2_16
+ - Docker_2_15
+ - Docker_2_14
- Docker_2_13
- Docker_2_12
- - Docker_2_11
- - Docker_2_10
- - Docker_2_9
- Remote_devel
+ - Remote_2_16
+ - Remote_2_15
+ - Remote_2_14
- Remote_2_13
- Remote_2_12
- - Remote_2_11
- - Remote_2_10
- - Remote_2_9
jobs:
- template: templates/coverage.yml
diff --git a/ansible_collections/community/libvirt/CHANGELOG.rst b/ansible_collections/community/libvirt/CHANGELOG.rst
index 0452a4685..23ea5e554 100644
--- a/ansible_collections/community/libvirt/CHANGELOG.rst
+++ b/ansible_collections/community/libvirt/CHANGELOG.rst
@@ -5,6 +5,31 @@ Community.Libvirt Release Notes
.. contents:: Topics
+v1.3.0
+======
+
+Release Summary
+---------------
+
+This is a new release of the ``community.libvirt`` collection.
+This changelog contains all changes to the modules and plugins in this collection
+that have been made after the previous release.
+
+Minor Changes
+-------------
+
+- virt - add `mutate_flags` parameter to enable XML mutation (add UUID, MAC addresses from existing domain) (https://github.com/ansible-collections/community.libvirt/pull/142/).
+- virt - support ``--diff`` for ``define`` command (https://github.com/ansible-collections/community.libvirt/pull/142/).
+
+Bugfixes
+--------
+
+- libvirt_qemu - connection plugin threw a warning about an improperly configured remote target. Fix adds `inventory_hostname` to `options.remote_addr.vars` (https://github.com/ansible-collections/community.libvirt/pull/147).
+- libvirt_qemu - fix encoding errors on Windows guests for non-ASCII return values (https://github.com/ansible-collections/community.libvirt/pull/157)
+- virt - fix virt module to undefine a domain with nvram, managed_save, snapshot_metadata or checkpoints_metadata (https://github.com/ansible-collections/community.libvirt/issues/40).
+- virt_pool - replace discouraged function ``listAllVolumes`` with ``listAllVolumes`` to fix potential race conditions (https://github.com/ansible-collections/community.libvirt/pull/135).
+- virt_pool - replace discouraged functions ``listStoragePools`` and ``listDefinedStoragePools`` with ``listAllStoragePools`` to fix potential race conditions (https://github.com/ansible-collections/community.libvirt/pull/134).
+
v1.2.0
======
diff --git a/ansible_collections/community/libvirt/CONTRIBUTING.md b/ansible_collections/community/libvirt/CONTRIBUTING.md
index edcfe55bc..70cd5557e 100644
--- a/ansible_collections/community/libvirt/CONTRIBUTING.md
+++ b/ansible_collections/community/libvirt/CONTRIBUTING.md
@@ -1,3 +1,5 @@
# Contributing
-Refer to the [Ansible Contributing guidelines](https://github.com/ansible/community-docs/blob/main/contributing.rst) to learn how to contribute to this collection.
+Refer to the [Ansible Contributing guidelines](https://docs.ansible.com/ansible/devel/community/index.html) to learn how to contribute to this collection.
+
+Refer to the [review checklist](https://docs.ansible.com/ansible/devel/community/collection_contributors/collection_reviewing.html) when triaging issues or reviewing PRs.
diff --git a/ansible_collections/community/libvirt/FILES.json b/ansible_collections/community/libvirt/FILES.json
index f41264643..66c2b67eb 100644
--- a/ansible_collections/community/libvirt/FILES.json
+++ b/ansible_collections/community/libvirt/FILES.json
@@ -109,7 +109,7 @@
"name": ".azure-pipelines/azure-pipelines.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a549b47cd670d92e56c58995ee2854f176baccf8bbb7bc7a064829bae78034c2",
+ "chksum_sha256": "235743eb1257d9b918cb046c756557e2f7b262cb6b0e3ef63fc9fb3af48df454",
"format": 1
},
{
@@ -123,7 +123,7 @@
"name": "changelogs/changelog.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4a77c0ce3b56db83490dbc6c9a159f7e65b9952b08ed66f7eb9c4e090c1fabe3",
+ "chksum_sha256": "e5e062c16c66fc3bb41f11b732b92b0e631198816c975805636088ae79c9cae8",
"format": 1
},
{
@@ -172,7 +172,7 @@
"name": "plugins/connection/libvirt_qemu.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fe6ca9c7dc6e723ac2ac1f720b78767ef3ba6663ecf3bfca03d1a62bb6d4d202",
+ "chksum_sha256": "fb6c4f88d7568d223a55839789ee576b4de55d47ca83bdcb056ffadfe465a144",
"format": 1
},
{
@@ -200,7 +200,7 @@
"name": "plugins/doc_fragments/virt.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d0b7a491bad2786203fe8111137a7d2cfb0853499dcb16bbef34e3ee170935bd",
+ "chksum_sha256": "63c76e4bef4bedacafba97e075c96eafefdaa4f04f92f9abc112a8236fa36593",
"format": 1
},
{
@@ -221,7 +221,7 @@
"name": "plugins/inventory/libvirt.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "71b0387fc55fca79ad138058e8105465e2f2c1a7f8d3ad0c48251232132cbedd",
+ "chksum_sha256": "b20e409ad3494b68427147d677b83f819b6a6ac9e061c7dd931662aee75c08d6",
"format": 1
},
{
@@ -235,21 +235,21 @@
"name": "plugins/modules/virt.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e23a3804a7fef3b08708ef89b61d70d155b5da55c77cf77ce084d4320452d6f9",
+ "chksum_sha256": "7ea10809743250129360305f892f3c3b263a6b006552380f2dfd594228072164",
"format": 1
},
{
"name": "plugins/modules/virt_net.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1f5f65ec1c7fb458f33d22c06b5157ff251f72b01a5b5f2d9d6620447f0a9fb8",
+ "chksum_sha256": "2eb089b25132eb862d502a375ed9727646de76eb245a8ab3c0a68b92ae30d9ef",
"format": 1
},
{
"name": "plugins/modules/virt_pool.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5ab52e7d19324c40a072eb2172bb7f3995621da95872fa090e714e420e64dffa",
+ "chksum_sha256": "f6614a835ce63252b9f969c1dca5bff6114246c98ffeef4da452f6e2ed7226b9",
"format": 1
},
{
@@ -645,45 +645,45 @@
"format": 1
},
{
- "name": "tests/sanity/ignore-2.10.txt",
+ "name": "tests/sanity/ignore-2.12.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3dbe66b16a396e94940e595e59436b4b2ff9163e53e7d33904839d5b51f1e572",
+ "chksum_sha256": "a70097a1274b645cb1981448b0b17069dfe2bdfedcec83cf6ea12c9a2d9092c1",
"format": 1
},
{
- "name": "tests/sanity/ignore-2.11.txt",
+ "name": "tests/sanity/ignore-2.13.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3dbe66b16a396e94940e595e59436b4b2ff9163e53e7d33904839d5b51f1e572",
+ "chksum_sha256": "a70097a1274b645cb1981448b0b17069dfe2bdfedcec83cf6ea12c9a2d9092c1",
"format": 1
},
{
- "name": "tests/sanity/ignore-2.12.txt",
+ "name": "tests/sanity/ignore-2.14.txt",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "a70097a1274b645cb1981448b0b17069dfe2bdfedcec83cf6ea12c9a2d9092c1",
"format": 1
},
{
- "name": "tests/sanity/ignore-2.13.txt",
+ "name": "tests/sanity/ignore-2.15.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a70097a1274b645cb1981448b0b17069dfe2bdfedcec83cf6ea12c9a2d9092c1",
+ "chksum_sha256": "30b40efd581721fa90731bfe2ea3bb9fdbaba3ffcedf13366b5379b1fd244042",
"format": 1
},
{
- "name": "tests/sanity/ignore-2.14.txt",
+ "name": "tests/sanity/ignore-2.16.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a70097a1274b645cb1981448b0b17069dfe2bdfedcec83cf6ea12c9a2d9092c1",
+ "chksum_sha256": "03d3b402bb612840b82adb62a100dd4e2dbc82ca4189ab7c3d88694aa6979fff",
"format": 1
},
{
- "name": "tests/sanity/ignore-2.9.txt",
+ "name": "tests/sanity/ignore-2.17.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3dbe66b16a396e94940e595e59436b4b2ff9163e53e7d33904839d5b51f1e572",
+ "chksum_sha256": "03d3b402bb612840b82adb62a100dd4e2dbc82ca4189ab7c3d88694aa6979fff",
"format": 1
},
{
@@ -746,7 +746,7 @@
"name": "tests/unit/mock/loader.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cfe3480f0eae6d3723ee62d01d00a0e9f58fcdc082ea1d8e4836157c56d4fa95",
+ "chksum_sha256": "aec7750aabec8f519349a0b0899efbcc4ceadb57ade3201914debe347f4b26a5",
"format": 1
},
{
@@ -865,7 +865,7 @@
"name": "tests/utils/shippable/check_matrix.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4855ba1cb515a6b3a51e3ac26e00c34d853866d8a67ced189f8f733526ae3d8a",
+ "chksum_sha256": "475c5515e7951b5e204c17a33f053964f245d5bb08d55ec46eee4e6314ade53d",
"format": 1
},
{
@@ -935,14 +935,14 @@
"name": "CHANGELOG.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6a5ac5751344499d6238ee7dce91c1b787ca62b388cdc2b2d40c5179bf53874b",
+ "chksum_sha256": "9fea037270c0db73ae6f11c9450f43534cb6448f7c0fac01cae01bcb745b669c",
"format": 1
},
{
"name": "CONTRIBUTING.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "537598e3a4b1c7e00d763177f92a0b2a66b0c02747dd47f847bc6a03bcb50cc0",
+ "chksum_sha256": "b0c50cf3715d59964a341dc651a6f626322209ef9fa8c0d03047d3a2b2e420a4",
"format": 1
},
{
@@ -974,13 +974,6 @@
"format": 1
},
{
- "name": "REVIEW_CHECKLIST.md",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "91ad4aff2cc14b98f81fbe2d90609c5a69ed96b6d836387a9c697c1112e603c0",
- "format": 1
- },
- {
"name": "shippable.yml",
"ftype": "file",
"chksum_type": "sha256",
diff --git a/ansible_collections/community/libvirt/MANIFEST.json b/ansible_collections/community/libvirt/MANIFEST.json
index 6f9a9f4eb..4f494c826 100644
--- a/ansible_collections/community/libvirt/MANIFEST.json
+++ b/ansible_collections/community/libvirt/MANIFEST.json
@@ -2,7 +2,7 @@
"collection_info": {
"namespace": "community",
"name": "libvirt",
- "version": "1.2.0",
+ "version": "1.3.0",
"authors": [
"Ansible (https://github.com/ansible)",
"community.libvirt"
@@ -26,7 +26,7 @@
"name": "FILES.json",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "37ac18f37cae0fd2deb7d11e81c71b9c5d7a68b4a040ccd07c31976f563357ff",
+ "chksum_sha256": "5209c6a915eee7b459e3bd0275469132b95ac29a0e0a283e41605ccba0c93a87",
"format": 1
},
"format": 1
diff --git a/ansible_collections/community/libvirt/REVIEW_CHECKLIST.md b/ansible_collections/community/libvirt/REVIEW_CHECKLIST.md
deleted file mode 100644
index 9dccf7ef1..000000000
--- a/ansible_collections/community/libvirt/REVIEW_CHECKLIST.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# Review Checklist
-
-Refer to the [Collection review checklist](https://github.com/ansible/community-docs/blob/main/review_checklist.rst).
diff --git a/ansible_collections/community/libvirt/changelogs/changelog.yaml b/ansible_collections/community/libvirt/changelogs/changelog.yaml
index 62a1b1a9e..4770781b6 100644
--- a/ansible_collections/community/libvirt/changelogs/changelog.yaml
+++ b/ansible_collections/community/libvirt/changelogs/changelog.yaml
@@ -83,3 +83,35 @@ releases:
- 117_find_vms_update_calls.yml
- virt_pool_no_path.yml
release_date: '2022-08-04'
+ 1.3.0:
+ changes:
+ bugfixes:
+ - libvirt_qemu - connection plugin threw a warning about an improperly configured
+ remote target. Fix adds `inventory_hostname` to `options.remote_addr.vars`
+ (https://github.com/ansible-collections/community.libvirt/pull/147).
+ - libvirt_qemu - fix encoding errors on Windows guests for non-ASCII return
+ values (https://github.com/ansible-collections/community.libvirt/pull/157)
+ - virt - fix virt module to undefine a domain with nvram, managed_save, snapshot_metadata
+ or checkpoints_metadata (https://github.com/ansible-collections/community.libvirt/issues/40).
+ - virt_pool - replace discouraged function ``listAllVolumes`` with ``listAllVolumes``
+ to fix potential race conditions (https://github.com/ansible-collections/community.libvirt/pull/135).
+ - virt_pool - replace discouraged functions ``listStoragePools`` and ``listDefinedStoragePools``
+ with ``listAllStoragePools`` to fix potential race conditions (https://github.com/ansible-collections/community.libvirt/pull/134).
+ minor_changes:
+ - virt - add `mutate_flags` parameter to enable XML mutation (add UUID, MAC
+ addresses from existing domain) (https://github.com/ansible-collections/community.libvirt/pull/142/).
+ - virt - support ``--diff`` for ``define`` command (https://github.com/ansible-collections/community.libvirt/pull/142/).
+ release_summary: 'This is a new release of the ``community.libvirt`` collection.
+
+ This changelog contains all changes to the modules and plugins in this collection
+
+ that have been made after the previous release.'
+ fragments:
+ - 1.3.0.yml
+ - 134_virt_pool_replace_functions_listStoragePools.yml
+ - 135_virt_pool_replace_function_listVolumes.yml
+ - 136_fix_undefine_nvram.yml
+ - 142_virt_define_improvements.yml
+ - 147_fix_qemu_remote_target_warning.yml
+ - 156_fix_windows_encoding.yml
+ release_date: '2023-09-19'
diff --git a/ansible_collections/community/libvirt/plugins/connection/libvirt_qemu.py b/ansible_collections/community/libvirt/plugins/connection/libvirt_qemu.py
index 220c02283..c9ed52fab 100644
--- a/ansible_collections/community/libvirt/plugins/connection/libvirt_qemu.py
+++ b/ansible_collections/community/libvirt/plugins/connection/libvirt_qemu.py
@@ -29,6 +29,7 @@ options:
default: inventory_hostname
vars:
- name: ansible_host
+ - name: inventory_hostname
executable:
description:
- Shell to use for execution inside container.
@@ -57,7 +58,6 @@ except ImportError as imp_exc:
else:
LIBVIRT_IMPORT_ERROR = None
-from ansible import constants as C
from ansible.errors import AnsibleError, AnsibleConnectionFailure, AnsibleFileNotFound
from ansible.module_utils._text import to_bytes, to_native, to_text
from ansible.module_utils.six import raise_from
@@ -65,7 +65,7 @@ from ansible.plugins.connection import ConnectionBase, BUFSIZE
from ansible.plugins.shell.powershell import _parse_clixml
from ansible.utils.display import Display
from functools import partial
-from os.path import exists, getsize
+from os.path import exists
display = Display()
@@ -160,6 +160,10 @@ class Connection(ConnectionBase):
# prompt that will not occur
sudoable = False
+ # Make sure our first command is to set the console encoding to
+ # utf-8, this must be done via chcp to get utf-8 (65001)
+ cmd = ' '.join(["chcp.com", "65001", self._shell._SHELL_REDIRECT_ALLNULL, self._shell._SHELL_AND, cmd])
+
# Generate powershell commands
cmd_args_list = self._shell._encode_script(cmd, as_list=True, strict_mode=False, preserve_rc=False)
diff --git a/ansible_collections/community/libvirt/plugins/doc_fragments/virt.py b/ansible_collections/community/libvirt/plugins/doc_fragments/virt.py
index a607299bf..6e4ec35a1 100644
--- a/ansible_collections/community/libvirt/plugins/doc_fragments/virt.py
+++ b/ansible_collections/community/libvirt/plugins/doc_fragments/virt.py
@@ -65,3 +65,24 @@ options:
- Must be raw XML content using C(lookup). XML cannot be reference to a file.
type: str
"""
+
+ OPTIONS_MUTATE_FLAGS = r"""
+options:
+ mutate_flags:
+ description:
+ - For each mutate_flag, we will modify the given XML in some way
+ - ADD_UUID will add an existing domain's UUID to the xml if it's missing
+ - ADD_MAC_ADDRESSES will look up interfaces in the existing domain with a
+ matching alias and copy the MAC address over. The matching interface
+ doesn't need to be of the same type or source network.
+ - ADD_MAC_ADDRESSES_FUZZY will try to match incoming interfaces with
+ interfaces of the existing domain sharing the same type and source
+ network/device. It may not always result in the expected outcome,
+ particularly if a domain has multiple interface attached to the same
+ host device and only some of those devices have <mac>s.
+ Use caution, do some testing for your particular use-case!
+ choices: [ ADD_UUID, ADD_MAC_ADDRESSES, ADD_MAC_ADDRESSES_FUZZY ]
+ type: list
+ elements: str
+ default: ['ADD_UUID']
+ """
diff --git a/ansible_collections/community/libvirt/plugins/inventory/libvirt.py b/ansible_collections/community/libvirt/plugins/inventory/libvirt.py
index 903870cc0..d0cd62f8a 100644
--- a/ansible_collections/community/libvirt/plugins/inventory/libvirt.py
+++ b/ansible_collections/community/libvirt/plugins/inventory/libvirt.py
@@ -160,6 +160,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
)
# This needs the guest powered on, 'qemu-guest-agent' installed and the org.qemu.guest_agent.0 channel configured.
+ domain_guestInfo = ''
try:
# type==0 returns all types (users, os, timezone, hostname, filesystem, disks, interfaces)
domain_guestInfo = domain.guestInfo(types=0)
@@ -173,6 +174,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
)
# This needs the guest powered on, 'qemu-guest-agent' installed and the org.qemu.guest_agent.0 channel configured.
+ domain_interfaceAddresses = ''
try:
domain_interfaceAddresses = domain.interfaceAddresses(source=libvirt.VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_AGENT)
except libvirt.libvirtError as e:
diff --git a/ansible_collections/community/libvirt/plugins/modules/virt.py b/ansible_collections/community/libvirt/plugins/modules/virt.py
index bbc2add06..529e6cd47 100644
--- a/ansible_collections/community/libvirt/plugins/modules/virt.py
+++ b/ansible_collections/community/libvirt/plugins/modules/virt.py
@@ -16,6 +16,29 @@ module: virt
short_description: Manages virtual machines supported by libvirt
description:
- Manages virtual machines supported by I(libvirt).
+options:
+ flags:
+ choices: [ 'managed_save', 'snapshots_metadata', 'nvram', 'keep_nvram', 'checkpoints_metadata']
+ description:
+ - Pass additional parameters.
+ - Currently only implemented with command C(undefine).
+ Specify which metadata should be removed with C(undefine).
+ Useful option to be able to C(undefine) guests with UEFI nvram.
+ C(nvram) and C(keep_nvram) are conflicting and mutually exclusive.
+ Consider option C(force) if all related metadata should be removed.
+ type: list
+ elements: str
+ force:
+ description:
+ - Enforce an action.
+ - Currently only implemented with command C(undefine).
+ This option can be used instead of providing all C(flags).
+ If C(true), C(undefine) removes also any related nvram or other metadata, if existing.
+ If C(false) or not set, C(undefine) executes only if there is no nvram or other metadata existing.
+ Otherwise the task fails and the guest is kept defined without change.
+ C(true) and option C(flags) should not be provided together. In this case
+ C(undefine) ignores C(true), considers only C(flags) and issues a warning.
+ type: bool
extends_documentation_fragment:
- community.libvirt.virt.options_uri
- community.libvirt.virt.options_xml
@@ -23,6 +46,7 @@ extends_documentation_fragment:
- community.libvirt.virt.options_autostart
- community.libvirt.virt.options_state
- community.libvirt.virt.options_command
+ - community.libvirt.virt.options_mutate_flags
- community.libvirt.requirements
author:
- Ansible Core Team
@@ -58,14 +82,38 @@ EXAMPLES = '''
- name: Set autostart for a VM
community.libvirt.virt:
name: foo
- autostart: yes
+ autostart: true
# Defining a VM and making is autostart with host. VM will be off after this task
- name: Define vm from xml and set autostart
community.libvirt.virt:
command: define
xml: "{{ lookup('template', 'vm_template.xml.j2') }}"
- autostart: yes
+ autostart: true
+
+# Undefine VM only, if it has no existing nvram or other metadata
+- name: Undefine qemu VM
+ community.libvirt.virt:
+ name: foo
+
+# Undefine VM and force remove all of its related metadata (nvram, snapshots, etc.)
+- name: "Undefine qemu VM with force"
+ community.libvirt.virt:
+ name: foo
+ force: true
+
+# Undefine VM and remove all of its specified metadata specified
+# Result would the same as with force=true
+- name: Undefine qemu VM with list of flags
+ community.libvirt.virt:
+ name: foo
+ flags: managed_save, snapshots_metadata, nvram, checkpoints_metadata
+
+# Undefine VM, but keep its nvram
+- name: Undefine qemu VM and keep its nvram
+ community.libvirt.virt:
+ name: foo
+ flags: keep_nvram
# Listing VMs
- name: List all VMs
@@ -108,7 +156,12 @@ except ImportError:
else:
HAS_VIRT = True
-import re
+try:
+ from lxml import etree
+except ImportError:
+ HAS_XML = False
+else:
+ HAS_XML = True
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_native
@@ -134,6 +187,19 @@ VIRT_STATE_NAME_MAP = {
6: 'crashed',
}
+ENTRY_UNDEFINE_FLAGS_MAP = {
+ 'managed_save': 1,
+ 'snapshots_metadata': 2,
+ 'nvram': 4,
+ 'keep_nvram': 8,
+ 'checkpoints_metadata': 16,
+}
+
+MUTATE_FLAGS = ['ADD_UUID', 'ADD_MAC_ADDRESSES', 'ADD_MAC_ADDRESSES_FUZZY']
+
+ALL_FLAGS = []
+ALL_FLAGS.extend(ENTRY_UNDEFINE_FLAGS_MAP.keys())
+
class VMNotFound(Exception):
pass
@@ -198,8 +264,8 @@ class LibvirtConnection(object):
def destroy(self, vmid):
return self.find_vm(vmid).destroy()
- def undefine(self, vmid):
- return self.find_vm(vmid).undefine()
+ def undefine(self, vmid, flag):
+ return self.find_vm(vmid).undefineFlags(flag)
def get_status2(self, vm):
state = vm.info()[0]
@@ -367,11 +433,11 @@ class Virt(object):
self.__get_conn()
return self.conn.destroy(vmid)
- def undefine(self, vmid):
+ def undefine(self, vmid, flag):
""" Stop a domain, and then wipe it from the face of the earth. (delete disk/config file) """
self.__get_conn()
- return self.conn.undefine(vmid)
+ return self.conn.undefine(vmid, flag)
def status(self, vmid):
"""
@@ -413,14 +479,210 @@ class Virt(object):
return self.conn.define_from_xml(xml)
+# A dict of interface types (found in their `type` attribute) to the
+# corresponding "source" attribute name of their <source> elements
+# user networks don't have a <source> element
+#
+# We do not support fuzzy matching against any interface types
+# not defined here
+INTERFACE_SOURCE_ATTRS = {
+ 'network': 'network',
+ 'bridge': 'bridge',
+ 'direct': 'dev',
+ 'user': None,
+}
+
+
+def handle_define(module, v):
+ ''' handle `command: define` '''
+ xml = module.params.get('xml', None)
+ guest = module.params.get('name', None)
+ autostart = module.params.get('autostart', None)
+ mutate_flags = module.params.get('mutate_flags', [])
+
+ if not xml:
+ module.fail_json(msg="define requires 'xml' argument")
+ try:
+ incoming_xml = etree.fromstring(xml)
+ except etree.XMLSyntaxError:
+ # TODO: provide info from parser
+ module.fail_json(msg="given XML is invalid")
+
+ # We'll support supplying the domain's name either from 'name' parameter or xml
+ #
+ # But we will fail if both are defined and not equal.
+ domain_name = incoming_xml.findtext("./name")
+ if domain_name is not None:
+ if guest is not None and domain_name != guest:
+ module.fail_json("given 'name' parameter does not match name in XML")
+ else:
+ if guest is None:
+ module.fail_json("missing 'name' parameter and no name provided in XML")
+ domain_name = guest
+ # since there's no <name> in the xml, we'll add it
+ etree.SubElement(incoming_xml, 'name').text = domain_name
+
+ if domain_name == '':
+ module.fail_json(msg="domain name cannot be an empty string")
+
+ res = dict()
+
+ # From libvirt docs (https://libvirt.org/html/libvirt-libvirt-domain.html#virDomainDefineXML):
+ # -- A previous definition for this domain with the same UUID and name would
+ # be overridden if it already exists.
+ #
+ # If a domain is defined without a <uuid>, libvirt will generate one for it.
+ # If an attempt is made to re-define the same xml (with the same <name> and
+ # no <uuid>), libvirt will complain with the following error:
+ #
+ # operation failed: domain '<name>' already exists with <uuid>
+ #
+ # If a domain with a similiar <name> but different <uuid> is defined,
+ # libvirt complains with the same error. However, if a domain is defined
+ # with the same <name> and <uuid> as an existing domain, then libvirt will
+ # update the domain with the new definition (automatically handling
+ # addition/removal of devices. some changes may require a boot).
+ try:
+ existing_domain = v.get_vm(domain_name)
+ existing_xml_raw = existing_domain.XMLDesc(libvirt.VIR_DOMAIN_XML_INACTIVE)
+ existing_xml = etree.fromstring(existing_xml_raw)
+ except VMNotFound:
+ existing_domain = None
+ existing_xml_raw = None
+ existing_xml = None
+
+ if existing_domain is not None:
+ # we are updating a domain's definition
+
+ incoming_uuid = incoming_xml.findtext('./uuid')
+ existing_uuid = existing_domain.UUIDString()
+
+ if incoming_uuid is not None and incoming_uuid != existing_uuid:
+ # A user should not try defining a domain with the same name but
+ # different UUID
+ module.fail_json(msg="attempting to re-define domain %s/%s with a different UUID: %s" % (
+ domain_name, existing_uuid, incoming_uuid
+ ))
+ else:
+ if 'ADD_UUID' in mutate_flags and incoming_uuid is None:
+ # Users will often want to define their domains without an explicit
+ # UUID, instead giving them a unique name - so we support bringing
+ # over the UUID from the existing domain
+ etree.SubElement(incoming_xml, 'uuid').text = existing_uuid
+
+ existing_devices = existing_xml.find('./devices')
+
+ if 'ADD_MAC_ADDRESSES' in mutate_flags:
+ for interface in incoming_xml.xpath('./devices/interface[not(mac) and alias]'):
+ search_alias = interface.find('alias').get('name')
+ xpath = "./interface[alias[@name='%s']]" % search_alias
+ try:
+ matched_interface = existing_devices.xpath(xpath)[0]
+ existing_devices.remove(matched_interface)
+ etree.SubElement(interface, 'mac', {
+ 'address': matched_interface.find('mac').get('address')
+ })
+ except IndexError:
+ module.warn("Could not match interface %i of incoming XML by alias %s." % (
+ interface.getparent().index(interface) + 1, search_alias
+ ))
+
+ if 'ADD_MAC_ADDRESSES_FUZZY' in mutate_flags:
+ # the counts of interfaces of a similar type/source
+ # key'd with tuple of (type, source)
+ similar_interface_counts = {}
+
+ def get_interface_count(_type, source=None):
+ key = (_type, source if _type != "user" else None)
+ if key not in similar_interface_counts:
+ similar_interface_counts[key] = 1
+ else:
+ similar_interface_counts[key] += 1
+ return similar_interface_counts[key]
+
+ # iterate user-defined interfaces
+ for interface in incoming_xml.xpath('./devices/interface'):
+ _type = interface.get('type')
+
+ if interface.find('mac') is not None and interface.find('alias') is not None:
+ continue
+
+ if _type not in INTERFACE_SOURCE_ATTRS:
+ module.warn("Skipping fuzzy MAC matching for interface %i of incoming XML: unsupported interface type '%s'." % (
+ interface.getparent().index(interface) + 1, _type
+ ))
+ continue
+
+ source_attr = INTERFACE_SOURCE_ATTRS[_type]
+ source = interface.find('source').get(source_attr) if source_attr else None
+ similar_count = get_interface_count(_type, source)
+
+ if interface.find('mac') is not None:
+ # we want to count these, but not try to change their MAC address
+ continue
+
+ if source:
+ xpath = "./interface[@type='%s' and source[@%s='%s']]" % (
+ _type, source_attr, source)
+ else:
+ xpath = "./interface[@type = '%s']" % source_attr
+
+ matching_interfaces = existing_devices.xpath(xpath)
+ try:
+ matched_interface = matching_interfaces[similar_count - 1]
+ etree.SubElement(interface, 'mac', {
+ 'address': matched_interface.find('./mac').get('address'),
+ })
+ except IndexError:
+ module.warn("Could not fuzzy match interface %i of incoming XML." % (
+ interface.getparent().index(interface) + 1
+ ))
+
+ try:
+ domain_xml = etree.tostring(incoming_xml).decode()
+
+ # TODO: support check mode
+ domain = v.define(domain_xml)
+
+ if existing_domain is not None:
+ # In this case, we may have updated the definition or it might be the same.
+ # We compare the domain's previous xml with its new state and diff
+ # the changes. This allows users to fix their xml if it results in
+ # non-idempotent behaviour (e.g. libvirt mutates it each time)
+ new_xml = domain.XMLDesc(libvirt.VIR_DOMAIN_XML_INACTIVE)
+ if existing_xml_raw != new_xml:
+ res.update({
+ 'changed': True,
+ 'change_reason': 'domain definition changed',
+ 'diff': {
+ 'before': existing_xml_raw,
+ 'after': new_xml
+ }
+ })
+ else:
+ # there was no existing XML, so this is a newly created domain
+ res.update({'changed': True, 'created': domain.name()})
+
+ except libvirtError as e:
+ module.fail_json(msg='libvirtError: %s' % e.get_error_message())
+ except Exception as e:
+ module.fail_json(msg='an unknown error occured: %s' % e)
+
+ if autostart is not None and v.autostart(domain_name, autostart):
+ res.update({'changed': True, 'change_reason': 'autostart'})
+
+ return res
+
+
def core(module):
state = module.params.get('state', None)
autostart = module.params.get('autostart', None)
guest = module.params.get('name', None)
command = module.params.get('command', None)
+ force = module.params.get('force', None)
+ flags = module.params.get('flags', None)
uri = module.params.get('uri', None)
- xml = module.params.get('xml', None)
v = Virt(uri, module)
res = dict()
@@ -473,46 +735,34 @@ def core(module):
if command:
if command in VM_COMMANDS:
if command == 'define':
- if not xml:
- module.fail_json(msg="define requires xml argument")
- if guest:
- # there might be a mismatch between quest 'name' in the module and in the xml
- module.warn("'xml' is given - ignoring 'name'")
- try:
- domain_name = re.search('<name>(.*)</name>', xml).groups()[0]
- except AttributeError:
- module.fail_json(msg="Could not find domain 'name' in xml")
-
- # From libvirt docs (https://libvirt.org/html/libvirt-libvirt-domain.html#virDomainDefineXML):
- # -- A previous definition for this domain would be overridden if it already exists.
- #
- # In real world testing with libvirt versions 1.2.17-13, 2.0.0-10 and 3.9.0-14
- # on qemu and lxc domains results in:
- # operation failed: domain '<name>' already exists with <uuid>
- #
- # In case a domain would be indeed overwritten, we should protect idempotency:
- try:
- existing_domain_xml = v.get_vm(domain_name).XMLDesc(
- libvirt.VIR_DOMAIN_XML_INACTIVE
- )
- except VMNotFound:
- existing_domain_xml = None
- try:
- domain = v.define(xml)
- if existing_domain_xml:
- # if we are here, then libvirt redefined existing domain as the doc promised
- if existing_domain_xml != domain.XMLDesc(libvirt.VIR_DOMAIN_XML_INACTIVE):
- res = {'changed': True, 'change_reason': 'config changed'}
- else:
- res = {'changed': True, 'created': domain.name()}
- except libvirtError as e:
- if e.get_error_code() != 9: # 9 means 'domain already exists' error
- module.fail_json(msg='libvirtError: %s' % e.get_error_message())
- if autostart is not None and v.autostart(domain_name, autostart):
- res = {'changed': True, 'change_reason': 'autostart'}
+ res.update(handle_define(module, v))
elif not guest:
module.fail_json(msg="%s requires 1 argument: guest" % command)
+
+ elif command == 'undefine':
+ # Use the undefine function with flag to also handle various metadata.
+ # This is especially important for UEFI enabled guests with nvram.
+ # Provide flag as an integer of all desired bits, see 'ENTRY_UNDEFINE_FLAGS_MAP'.
+ # Integer 23 takes care of all cases (23 = 1 + 2 + 4 + 16).
+ flag = 0
+ if flags is not None:
+ if force is True:
+ module.warn("Ignoring 'force', because 'flags' are provided.")
+ nv = ['nvram', 'keep_nvram']
+ # Check mutually exclusive flags
+ if set(nv) <= set(flags):
+ raise ValueError("Flags '%s' are mutually exclusive" % "' and '".join(nv))
+ for item in flags:
+ # Get and add flag integer from mapping, otherwise 0.
+ flag += ENTRY_UNDEFINE_FLAGS_MAP.get(item, 0)
+ elif force is True:
+ flag = 23
+ # Finally, execute with flag
+ res = getattr(v, command)(guest, flag)
+ if not isinstance(res, dict):
+ res = {command: res}
+
else:
res = getattr(v, command)(guest)
if not isinstance(res, dict):
@@ -539,13 +789,23 @@ def main():
state=dict(type='str', choices=['destroyed', 'paused', 'running', 'shutdown']),
autostart=dict(type='bool'),
command=dict(type='str', choices=ALL_COMMANDS),
+ flags=dict(type='list', elements='str', choices=ALL_FLAGS),
+ force=dict(type='bool'),
uri=dict(type='str', default='qemu:///system'),
xml=dict(type='str'),
+ mutate_flags=dict(type='list', elements='str', choices=MUTATE_FLAGS, default=['ADD_UUID']),
),
)
if not HAS_VIRT:
- module.fail_json(msg='The `libvirt` module is not importable. Check the requirements.')
+ module.fail_json(
+ msg='The `libvirt` module is not importable. Check the requirements.'
+ )
+
+ if not HAS_XML:
+ module.fail_json(
+ msg='The `lxml` module is not importable. Check the requirements.'
+ )
rc = VIRT_SUCCESS
try:
diff --git a/ansible_collections/community/libvirt/plugins/modules/virt_net.py b/ansible_collections/community/libvirt/plugins/modules/virt_net.py
index 7492cac79..de8418a6f 100644
--- a/ansible_collections/community/libvirt/plugins/modules/virt_net.py
+++ b/ansible_collections/community/libvirt/plugins/modules/virt_net.py
@@ -109,12 +109,12 @@ EXAMPLES = '''
- name: Ensure that a given network will be started at boot
community.libvirt.virt_net:
- autostart: yes
+ autostart: true
name: br_nat
- name: Disable autostart for a given network
community.libvirt.virt_net:
- autostart: no
+ autostart: false
name: br_nat
- name: Add a new host in the dhcp pool
diff --git a/ansible_collections/community/libvirt/plugins/modules/virt_pool.py b/ansible_collections/community/libvirt/plugins/modules/virt_pool.py
index 70145c617..3b0117333 100644
--- a/ansible_collections/community/libvirt/plugins/modules/virt_pool.py
+++ b/ansible_collections/community/libvirt/plugins/modules/virt_pool.py
@@ -124,12 +124,12 @@ EXAMPLES = '''
- name: Ensure that a given pool will be started at boot
community.libvirt.virt_pool:
- autostart: yes
+ autostart: true
name: vms
- name: Disable autostart for a given pool
community.libvirt.virt_pool:
- autostart: no
+ autostart: false
name: vms
'''
@@ -222,17 +222,8 @@ class LibvirtConnection(object):
def find_entry(self, entryid):
# entryid = -1 returns a list of everything
- results = []
-
- # Get active entries
- for name in self.conn.listStoragePools():
- entry = self.conn.storagePoolLookupByName(name)
- results.append(entry)
-
- # Get inactive entries
- for name in self.conn.listDefinedStoragePools():
- entry = self.conn.storagePoolLookupByName(name)
- results.append(entry)
+ # Get all entries
+ results = self.conn.listAllStoragePools()
if entryid == -1:
return results
@@ -296,7 +287,7 @@ class LibvirtConnection(object):
return self.find_entry(entryid).numOfVolumes()
def get_volume_names(self, entryid):
- return self.find_entry(entryid).listVolumes()
+ return self.find_entry(entryid).listAllVolumes()
def get_devices(self, entryid):
xml = etree.fromstring(self.find_entry(entryid).XMLDesc(0))
@@ -506,7 +497,7 @@ class VirtStoragePool(object):
results[entry]["volume_count"] = self.conn.get_volume_count(entry)
results[entry]["volumes"] = list()
for volume in self.conn.get_volume_names(entry):
- results[entry]["volumes"].append(volume)
+ results[entry]["volumes"].append(volume.name())
else:
results[entry]["volume_count"] = -1
diff --git a/ansible_collections/community/libvirt/tests/sanity/ignore-2.10.txt b/ansible_collections/community/libvirt/tests/sanity/ignore-2.10.txt
deleted file mode 100644
index f6584fe11..000000000
--- a/ansible_collections/community/libvirt/tests/sanity/ignore-2.10.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-tests/unit/mock/path.py future-import-boilerplate
-tests/unit/mock/path.py metaclass-boilerplate
-tests/unit/mock/yaml_helper.py future-import-boilerplate
-tests/unit/mock/yaml_helper.py metaclass-boilerplate
-tests/unit/modules/cloud/misc/virt_net/conftest.py future-import-boilerplate
-tests/unit/modules/cloud/misc/virt_net/conftest.py metaclass-boilerplate
-tests/unit/modules/cloud/misc/virt_net/test_virt_net.py future-import-boilerplate
-tests/unit/modules/cloud/misc/virt_net/test_virt_net.py metaclass-boilerplate
-tests/utils/shippable/timing.py shebang
-tests/utils/shippable/check_matrix.py replace-urlopen
diff --git a/ansible_collections/community/libvirt/tests/sanity/ignore-2.11.txt b/ansible_collections/community/libvirt/tests/sanity/ignore-2.11.txt
deleted file mode 100644
index f6584fe11..000000000
--- a/ansible_collections/community/libvirt/tests/sanity/ignore-2.11.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-tests/unit/mock/path.py future-import-boilerplate
-tests/unit/mock/path.py metaclass-boilerplate
-tests/unit/mock/yaml_helper.py future-import-boilerplate
-tests/unit/mock/yaml_helper.py metaclass-boilerplate
-tests/unit/modules/cloud/misc/virt_net/conftest.py future-import-boilerplate
-tests/unit/modules/cloud/misc/virt_net/conftest.py metaclass-boilerplate
-tests/unit/modules/cloud/misc/virt_net/test_virt_net.py future-import-boilerplate
-tests/unit/modules/cloud/misc/virt_net/test_virt_net.py metaclass-boilerplate
-tests/utils/shippable/timing.py shebang
-tests/utils/shippable/check_matrix.py replace-urlopen
diff --git a/ansible_collections/community/libvirt/tests/sanity/ignore-2.15.txt b/ansible_collections/community/libvirt/tests/sanity/ignore-2.15.txt
new file mode 100644
index 000000000..889e71429
--- /dev/null
+++ b/ansible_collections/community/libvirt/tests/sanity/ignore-2.15.txt
@@ -0,0 +1,3 @@
+tests/utils/shippable/timing.py shebang
+tests/utils/shippable/check_matrix.py replace-urlopen
+tests/unit/compat/builtins.py pylint:unused-import
diff --git a/ansible_collections/community/libvirt/tests/sanity/ignore-2.16.txt b/ansible_collections/community/libvirt/tests/sanity/ignore-2.16.txt
new file mode 100644
index 000000000..3eb3aa615
--- /dev/null
+++ b/ansible_collections/community/libvirt/tests/sanity/ignore-2.16.txt
@@ -0,0 +1,2 @@
+tests/utils/shippable/timing.py shebang
+tests/unit/compat/builtins.py pylint:unused-import
diff --git a/ansible_collections/community/libvirt/tests/sanity/ignore-2.17.txt b/ansible_collections/community/libvirt/tests/sanity/ignore-2.17.txt
new file mode 100644
index 000000000..3eb3aa615
--- /dev/null
+++ b/ansible_collections/community/libvirt/tests/sanity/ignore-2.17.txt
@@ -0,0 +1,2 @@
+tests/utils/shippable/timing.py shebang
+tests/unit/compat/builtins.py pylint:unused-import
diff --git a/ansible_collections/community/libvirt/tests/sanity/ignore-2.9.txt b/ansible_collections/community/libvirt/tests/sanity/ignore-2.9.txt
deleted file mode 100644
index f6584fe11..000000000
--- a/ansible_collections/community/libvirt/tests/sanity/ignore-2.9.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-tests/unit/mock/path.py future-import-boilerplate
-tests/unit/mock/path.py metaclass-boilerplate
-tests/unit/mock/yaml_helper.py future-import-boilerplate
-tests/unit/mock/yaml_helper.py metaclass-boilerplate
-tests/unit/modules/cloud/misc/virt_net/conftest.py future-import-boilerplate
-tests/unit/modules/cloud/misc/virt_net/conftest.py metaclass-boilerplate
-tests/unit/modules/cloud/misc/virt_net/test_virt_net.py future-import-boilerplate
-tests/unit/modules/cloud/misc/virt_net/test_virt_net.py metaclass-boilerplate
-tests/utils/shippable/timing.py shebang
-tests/utils/shippable/check_matrix.py replace-urlopen
diff --git a/ansible_collections/community/libvirt/tests/unit/mock/loader.py b/ansible_collections/community/libvirt/tests/unit/mock/loader.py
index 00a584127..e5eb8b411 100644
--- a/ansible_collections/community/libvirt/tests/unit/mock/loader.py
+++ b/ansible_collections/community/libvirt/tests/unit/mock/loader.py
@@ -30,7 +30,7 @@ class DictDataLoader(DataLoader):
def __init__(self, file_mapping=None):
file_mapping = {} if file_mapping is None else file_mapping
- assert type(file_mapping) == dict
+ assert type(file_mapping) is dict
super(DictDataLoader, self).__init__()
diff --git a/ansible_collections/community/libvirt/tests/utils/shippable/check_matrix.py b/ansible_collections/community/libvirt/tests/utils/shippable/check_matrix.py
index 567181fc0..e670ed51d 100755
--- a/ansible_collections/community/libvirt/tests/utils/shippable/check_matrix.py
+++ b/ansible_collections/community/libvirt/tests/utils/shippable/check_matrix.py
@@ -10,8 +10,6 @@ import re
import sys
import time
-from ansible.module_utils.urls import open_url
-
try:
from typing import NoReturn
except ImportError:
diff --git a/ansible_collections/community/mongodb/.github/workflows/ansible-test.yml b/ansible_collections/community/mongodb/.github/workflows/ansible-test.yml
index 6a8d52bd1..f64d5881c 100644
--- a/ansible_collections/community/mongodb/.github/workflows/ansible-test.yml
+++ b/ansible_collections/community/mongodb/.github/workflows/ansible-test.yml
@@ -18,20 +18,23 @@ jobs:
ansible_version:
- devel
- stable-2.13
+ - stable-2.14
+ - stable-2.15
+ - stable-2.16
steps:
- name: Check out code
- uses: actions/checkout@v2
+ uses: actions/checkout@v4
with:
path: ansible_collections/community/mongodb
- - name: Set up Python 3.9
- uses: actions/setup-python@v4
+ - name: Set up Python 3.10
+ uses: actions/setup-python@v5
with:
- python-version: 3.9
+ python-version: "3.10"
- name: Install ansible-base (${{ matrix.ansible_version }})
- uses: nick-invision/retry@v2
+ uses: nick-invision/retry@v3
with:
timeout_minutes: 3
max_attempts: 3
@@ -50,40 +53,43 @@ jobs:
ansible_version:
- devel
- stable-2.13
+ - stable-2.14
+ - stable-2.15
+ - stable-2.16
steps:
- name: Check out code
- uses: actions/checkout@v2
+ uses: actions/checkout@v4
with:
path: ansible_collections/community/mongodb
- - name: Set up Python 3.9
- uses: actions/setup-python@v4
+ - name: Set up Python 3.10
+ uses: actions/setup-python@v5
with:
- python-version: 3.9
+ python-version: "3.10"
- name: Install ansible-base (${{ matrix.ansible_version }})
- uses: nick-invision/retry@v2
+ uses: nick-invision/retry@v3
with:
timeout_minutes: 3
max_attempts: 3
command: pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible_version }}.tar.gz --disable-pip-version-check
- name: Install mongodb
- uses: nick-invision/retry@v2
+ uses: nick-invision/retry@v3
with:
timeout_minutes: 3
max_attempts: 3
command: sudo apt-get install -y mongodb-org
- name: Install dateutil
- uses: nick-invision/retry@v2
+ uses: nick-invision/retry@v3
with:
timeout_minutes: 3
max_attempts: 3
command: pip install python-dateutil
- name: Install python libs
- uses: nick-invision/retry@v2
+ uses: nick-invision/retry@v3
with:
timeout_minutes: 3
max_attempts: 3
@@ -97,12 +103,12 @@ jobs:
run: mlaunch --single --port 27999
- name: Run unit tests
- run: ansible-test units -v --color --python 3.9 --coverage
+ run: ansible-test units -v --color --python 3.10 --coverage
- name: Generate coverage report.
run: ansible-test coverage xml -v --requirements --group-by command --group-by version
- - uses: codecov/codecov-action@v1
+ - uses: codecov/codecov-action@v3
with:
fail_ci_if_error: false
@@ -120,7 +126,7 @@ jobs:
steps:
- name: Check out code
- uses: actions/checkout@v2
+ uses: actions/checkout@v4
with:
path: ansible_collections/community/mongodb
@@ -144,64 +150,53 @@ jobs:
strategy:
matrix:
mongodb_version:
- - "5.0"
- "6.0"
+ - "7.0"
mongodb_module: ${{ fromJson(needs.integration_matrix.outputs.matrix) }}
versions:
- #- python_version: "2.7"
- # ansible_version: "stable-2.10"
- # docker_image: "centos7"
- #- python_version: "2.7"
- # ansible_version: "stable-2.11"
- # docker_image: "centos7"
- - python_version: "3.6"
- ansible_version: "stable-2.10"
- docker_image: "ubuntu1804"
- - python_version: "3.6"
- ansible_version: "stable-2.11"
- docker_image: "ubuntu1804"
- - python_version: "3.8"
- ansible_version: "stable-2.12"
- docker_image: "default"
- python_version: "3.8"
ansible_version: "stable-2.13"
docker_image: "default"
- python_version: "3.9"
ansible_version: "stable-2.14"
docker_image: "default"
- # Fedora 33 should be possible after this is fixed
- # https://jira.mongodb.org/browse/MONGOSH-941
- #- python_version: "3.9"
- # ansible_version: "devel"
- # docker_image: "fedora33"
+ - python_version: "3.10"
+ ansible_version: "stable-2.15"
+ docker_image: "default"
+ - python_version: "3.10"
+ ansible_version: "stable-2.16"
+ docker_image: "default"
+ - python_version: "3.10"
+ ansible_version: "devel"
+ docker_image: "default"
steps:
- name: Check out code
- uses: actions/checkout@v2
+ uses: actions/checkout@v4
with:
path: ansible_collections/community/mongodb
- name: Set up Python ${{ matrix.versions.python_version }}
- uses: actions/setup-python@v4
+ uses: actions/setup-python@v5
with:
python-version: ${{ matrix.versions.python_version }}
- name: Install ansible-base (${{ matrix.versions.ansible_version }})
- uses: nick-invision/retry@v2
+ uses: nick-invision/retry@v3
with:
timeout_minutes: 3
max_attempts: 3
command: pip install https://github.com/ansible/ansible/archive/${{ matrix.versions.ansible_version }}.tar.gz --disable-pip-version-check
- name: Install community.general
- uses: nick-invision/retry@v2
+ uses: nick-invision/retry@v3
with:
timeout_minutes: 3
max_attempts: 3
command: ansible-galaxy collection install 'community.general' -p ansible_collections/
- name: Install community.crypto
- uses: nick-invision/retry@v2
+ uses: nick-invision/retry@v3
with:
timeout_minutes: 3
max_attempts: 3
@@ -214,4 +209,4 @@ jobs:
run: ansible-test integration --docker ${{ matrix.versions.docker_image }} -v --color --retry-on-error --python ${{ matrix.versions.python_version }} --continue-on-error --diff --coverage ${{ matrix.mongodb_module }}
- name: Upload Coverage data
- run: tests/coverage.sh \ No newline at end of file
+ run: tests/coverage.sh
diff --git a/ansible_collections/community/mongodb/.github/workflows/mongodb-cache.yml b/ansible_collections/community/mongodb/.github/workflows/mongodb-cache.yml
index 992646c28..757b72256 100644
--- a/ansible_collections/community/mongodb/.github/workflows/mongodb-cache.yml
+++ b/ansible_collections/community/mongodb/.github/workflows/mongodb-cache.yml
@@ -17,33 +17,31 @@ jobs:
strategy:
matrix:
versions:
- - ansible_version: "stable-2.10"
- python_version: "3.6"
- - ansible_version: "stable-2.11"
- python_version: "3.6"
- - ansible_version: "stable-2.12"
- python_version: "3.9"
- ansible_version: "stable-2.13"
- python_version: "3.8"
- - ansible_version: "stable-2.14"
python_version: "3.9"
+ - ansible_version: "stable-2.14"
+ python_version: "3.10"
+ - ansible_version: "stable-2.15"
+ python_version: "3.11"
+ - ansible_version: "stable-2.16"
+ python_version: "3.11"
- ansible_version: "devel"
- python_version: "3.9"
+ python_version: "3.11"
steps:
- name: Check out code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
path: ansible_collections/community/mongodb
- name: Set up Python ${{ matrix.versions.python_version }}
- uses: actions/setup-python@v4
+ uses: actions/setup-python@v5
with:
python-version: ${{ matrix.versions.python_version }}
- name: Install ansible-base (${{ matrix.versions.ansible_version }})
- uses: nick-invision/retry@v2
+ uses: nick-invision/retry@v3
with:
timeout_minutes: 3
max_attempts: 3
@@ -68,7 +66,7 @@ jobs:
-v mongocache:/data/db mongo:latest
- name: Install mongodb-org-shell
- uses: nick-invision/retry@v2
+ uses: nick-invision/retry@v3
with:
timeout_minutes: 3
max_attempts: 3
@@ -86,18 +84,18 @@ jobs:
echo "nopymongo=$output" >> $GITHUB_OUTPUT
- name: Test cache handling of missing pymongo
- uses: nick-invision/assert-action@v1
+ uses: nick-invision/assert-action@v2
with:
expected: "The 'pymongo' python module is required for the mongodb fact cache"
actual: ${{ steps.no-pymongo.outputs.nopymongo }}
comparison: contains
- name: Install pymongo
- uses: nick-invision/retry@v2
+ uses: nick-invision/retry@v3
with:
timeout_minutes: 3
max_attempts: 3
- command: pip install pymongo==3.12.2
+ command: pip install pymongo
- name: Run ansible to generate the mongodb cache
run: ansible localhost -m setup
@@ -113,7 +111,7 @@ jobs:
echo "mongo=$output" >> $GITHUB_OUTPUT
- name: Test that we have something that looks like a cache record
- uses: nick-invision/assert-action@v1
+ uses: nick-invision/assert-action@v2
with:
expected: ansible_processor_count
actual: ${{ steps.mongo1.outputs.mongo }}
@@ -130,14 +128,14 @@ jobs:
echo "mongo=$output" >> $GITHUB_OUTPUT
- name: Test that we don't have an index called ttl
- uses: nick-invision/assert-action@v1
+ uses: nick-invision/assert-action@v2
with:
expected: ttl
actual: ${{ steps.mongo2.outputs.mongo }}
comparison: notContains
- name: Test that we have good output from getindexes
- uses: nick-invision/assert-action@v1
+ uses: nick-invision/assert-action@v2
with:
expected: "_id_"
actual: ${{ steps.mongo2.outputs.mongo }}
@@ -157,7 +155,7 @@ jobs:
echo "mongo=$output" >> $GITHUB_OUTPUT
- name: Test that we have something that looks like a cache record
- uses: nick-invision/assert-action@v1
+ uses: nick-invision/assert-action@v2
with:
expected: ansible_processor_count
actual: ${{ steps.mongo3.outputs.mongo }}
@@ -174,14 +172,14 @@ jobs:
echo "mongo=$output" >> $GITHUB_OUTPUT
- name: Test that we don't have an index called ttl
- uses: nick-invision/assert-action@v1
+ uses: nick-invision/assert-action@v2
with:
expected: ttl
actual: ${{ steps.mongo4.outputs.mongo }}
comparison: notContains
- name: Test that we have good output from getindexes
- uses: nick-invision/assert-action@v1
+ uses: nick-invision/assert-action@v2
with:
expected: "_id_"
actual: ${{ steps.mongo4.outputs.mongo }}
@@ -203,7 +201,7 @@ jobs:
echo "mongo=$output" >> $GITHUB_OUTPUT
- name: Test that we have something that looks like a cache record
- uses: nick-invision/assert-action@v1
+ uses: nick-invision/assert-action@v2
with:
expected: ansible_processor_count
actual: ${{ steps.mongo5.outputs.mongo }}
@@ -220,7 +218,7 @@ jobs:
echo "mongo=$output" >> $GITHUB_OUTPUT
- name: Test that we do have an index called ttl
- uses: nick-invision/assert-action@v1
+ uses: nick-invision/assert-action@v2
with:
expected: ttl
actual: ${{ steps.mongo6.outputs.mongo }}
@@ -242,7 +240,7 @@ jobs:
echo "mongo=$output" >> $GITHUB_OUTPUT
- name: Test that we have something that looks like a cache record
- uses: nick-invision/assert-action@v1
+ uses: nick-invision/assert-action@v2
with:
expected: ansible_processor_count
actual: ${{ steps.mongo7.outputs.mongo }}
@@ -259,7 +257,7 @@ jobs:
echo "mongo=$output" >> $GITHUB_OUTPUT
- name: Test that we do have an index called ttl
- uses: nick-invision/assert-action@v1
+ uses: nick-invision/assert-action@v2
with:
expected: ttl
actual: ${{ steps.mongo8.outputs.mongo }}
@@ -281,7 +279,7 @@ jobs:
echo "mongo=$output" >> $GITHUB_OUTPUT
- name: Test that we have something that looks like a cache record
- uses: nick-invision/assert-action@v1
+ uses: nick-invision/assert-action@v2
with:
expected: ansible_processor_count
actual: ${{ steps.mongo9.outputs.mongo }}
@@ -298,14 +296,14 @@ jobs:
echo "mongo=$output" >> $GITHUB_OUTPUT
- name: Test that we don't have an index called ttl
- uses: nick-invision/assert-action@v1
+ uses: nick-invision/assert-action@v2
with:
expected: ttl
actual: ${{ steps.mongo10.outputs.mongo }}
comparison: notContains
- name: Test that we have good output from getindexes
- uses: nick-invision/assert-action@v1
+ uses: nick-invision/assert-action@v2
with:
expected: "_id_"
actual: ${{ steps.mongo10.outputs.mongo }}
diff --git a/ansible_collections/community/mongodb/.github/workflows/publish_collection.yml b/ansible_collections/community/mongodb/.github/workflows/publish_collection.yml
index a16dcd55d..c928a4809 100644
--- a/ansible_collections/community/mongodb/.github/workflows/publish_collection.yml
+++ b/ansible_collections/community/mongodb/.github/workflows/publish_collection.yml
@@ -14,14 +14,14 @@ jobs:
steps:
- name: Check out code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
path: ansible_collections/community/mongodb
- - name: Set up Python 3.9
- uses: actions/setup-python@v4
+ - name: Set up Python 3.10
+ uses: actions/setup-python@v5
with:
- python-version: 3.9
+ python-version: "3.10"
- name: Install ansible-base (devel)
run: pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check
@@ -40,7 +40,7 @@ jobs:
# Moving the tag leaves an orphan artifact. Just changing the artifact doesn't move the tag.
- name: Delete latest tag and release
- uses: dev-drprasad/delete-tag-and-release@v0.2.1
+ uses: dev-drprasad/delete-tag-and-release@v1.0.1
with:
delete_release: true
tag_name: latest
diff --git a/ansible_collections/community/mongodb/.github/workflows/test-roles.yml b/ansible_collections/community/mongodb/.github/workflows/test-roles.yml
index 2529bfc10..5aa01e2cc 100644
--- a/ansible_collections/community/mongodb/.github/workflows/test-roles.yml
+++ b/ansible_collections/community/mongodb/.github/workflows/test-roles.yml
@@ -17,7 +17,7 @@ jobs:
steps:
- name: Check out code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
path: ansible_collections/community/mongodb
@@ -42,17 +42,17 @@ jobs:
strategy:
matrix:
python_version:
- - "3.6"
+ - "3.10"
mongodb_role: ${{ fromJson(needs.roles_matrix.outputs.matrix) }}
steps:
- name: Check out code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
path: ansible_collections/community/mongodb
- name: Set up Python ${{ matrix.test_scenario.python_version }}
- uses: actions/setup-python@v4
+ uses: actions/setup-python@v5
with:
python-version: ${{ matrix.test_scenario.python_version }}
diff --git a/ansible_collections/community/mongodb/.github/workflows/x509.yml b/ansible_collections/community/mongodb/.github/workflows/x509.yml
index bd6fd561c..59070b07f 100644
--- a/ansible_collections/community/mongodb/.github/workflows/x509.yml
+++ b/ansible_collections/community/mongodb/.github/workflows/x509.yml
@@ -13,7 +13,7 @@ jobs:
steps:
- name: Check out code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
path: ansible_collections/community/mongodb
@@ -104,13 +104,13 @@ jobs:
--authenticationDatabase '$external' \
--eval "db.adminCommand('listDatabases')"
- - name: Set up Python 3.9
- uses: actions/setup-python@v4
+ - name: Set up Python 3.10
+ uses: actions/setup-python@v5
with:
- python-version: "3.9"
+ python-version: "3.10"
- name: Install ansible-base devel
- uses: nick-invision/retry@v2
+ uses: nick-invision/retry@v3
with:
timeout_minutes: 3
max_attempts: 3
@@ -129,7 +129,7 @@ jobs:
working-directory: ansible_collections/community/mongodb
- name: Install pymongo
- uses: nick-invision/retry@v2.8.2
+ uses: nick-invision/retry@v3
with:
timeout_minutes: 3
max_attempts: 3
diff --git a/ansible_collections/community/mongodb/CHANGELOG.rst b/ansible_collections/community/mongodb/CHANGELOG.rst
index 2c898bd5d..88b4b7fe4 100644
--- a/ansible_collections/community/mongodb/CHANGELOG.rst
+++ b/ansible_collections/community/mongodb/CHANGELOG.rst
@@ -4,6 +4,108 @@ Community.MongoDB Release Notes
.. contents:: Topics
+v1.7.2:
+=========
+
+Release Summary
+----------------
+
+This release is a maintenance release.
+
+Bug Fixes
+----------
+
+- 638 - mongodb_replicaset - Allow module to update replicaset horizons.
+
+v1.7.1:
+=========
+
+Release Summary
+----------------
+
+This release is a maintenance release.
+
+Bug Fixes
+----------
+
+- 631 - cache/mongodb.py - Support pymongo 4.0+. This plugin no longer support pymongo 3.12.*.
+
+v1.7.0:
+=========
+
+Release Summary
+----------------
+
+This release is a maintenance release.
+
+Minor Changes
+--------------
+
+- 622 - mongodb_mongod - Allow systemd configuration override.
+- 620 - mongodb_common - Use SSL constants in shared connection code.
+- 609 - mongodb_mongod, mongodb_mongos, mongodb_config - support for allowConnectionsWithoutCertificates.
+- 605 - mongodb_mongod, mongodb_mongos, mongodb_config - support for security.disabledProtocols.
+
+Bug Fixes
+----------
+
+- 614 - mongodb_replicaset - Count voting members based on the sum of "votes" and using a comprehension list.
+- 611 - mongodb_role - lambda function changed to support non-existing keys.
+
+Modules
+---------
+
+- 612 - mongodb_atlas_cluster - Manage database clusters in Atlas (#612).
+- 612 - mongodb_atlas_ldap_user - Manage ldap users in Atlas (#612).
+- 612 - mongodb_atlas_user - Manage database users in Atlas (#612).
+- 612 - mongodb_atlas_whitelist - Manage IP whitelists in Atlas (#612).
+
+v1.6.3:
+========
+
+Release Summary
+---------------
+
+This release is a maintenance release.
+
+Minor Changes
+--------------
+
+- 600 - Remove delete module from README.md.
+- 601 - mongodb_install - Fix issue with specific_mongodb_version on RedHat OS family.
+
+v1.6.2:
+========
+
+Release Summary
+---------------
+
+This release is a maintenance release.
+
+Minor Changes
+--------------
+
+- 583 - mongodb_linux - Add vars for RedHat 9 to role.
+- 586 - mongodb_auth - Add ssl vars to role.
+- 589 - mongodb_linux - Adds vars to better handle ntp package installation and handling.
+- 588 - mongodb_linux - Default ntp system to systemd-timesyncd for Debian12.
+- 593 - mongodb_linux - Add vm.max_map_count = 128000 sysctl config.
+- 597 - mongodb_monitoring - Module has been deleted as Free Monitoring service has been stopped.
+- 595 - mongodb_linux - Improvements to transparent_hugepage handling.
+
+v1.6.1:
+========
+
+Release Summary
+---------------
+
+This release is a maintenance release.
+
+Minor Changes
+--------------
+
+- 578 - mongodb_role - More robust comparison of user roles.
+
v1.6.0:
========
@@ -16,7 +118,7 @@ Minor Changes
--------------
- 569 - All pymongo modules - Better support for MongoDB Atlas.
-- 568 - Minor documentation updates.
+- 568 - Minor documentation updates.
v1.5.2
=======
@@ -131,7 +233,7 @@ Major Changes
---------------
- 470 - Removes depreciated distutils package and require Pymongo 3.12+ and MongoDB 4+
- Adds a new parameter strict_compatibility (default true).
+ Adds a new parameter strict_compatibility (default true).
Set to false to disable Pymongo and MongoDB requirements.
v1.3.4
@@ -165,8 +267,8 @@ Bug Fixes
Minor Changes
---------------
-- 450 - mongodb_replicaset. Introduce cluster_cmd parameter. Can be set to isMaster or hello.
- Hello is the default. isMaster is useful for older versions of MongoDB.
+- 450 - mongodb_replicaset. Introduce cluster_cmd parameter. Can be set to isMaster or hello.
+ Hello is the default. isMaster is useful for older versions of MongoDB.
See [db.hello()](https://www.mongodb.com/docs/manual/reference/method/db.hello/) for more.
v1.3.2
diff --git a/ansible_collections/community/mongodb/FILES.json b/ansible_collections/community/mongodb/FILES.json
index 3350b5fe3..ff9223131 100644
--- a/ansible_collections/community/mongodb/FILES.json
+++ b/ansible_collections/community/mongodb/FILES.json
@@ -25,21 +25,21 @@
"name": ".github/workflows/ansible-test.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "893b57c4cbb866c079d790a6018f660ee8f178ee105a8e46b2d93f1e5106bb1f",
+ "chksum_sha256": "73b933669a573ce6fa027dff9223cbbed48d4d31e0b61cf54c503f3eec46816a",
"format": 1
},
{
"name": ".github/workflows/mongodb-cache.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3b6e9e5c1b98e1db58c3c3327bb10ce1c59cd24dbc716d253f2d75bd30ab06d4",
+ "chksum_sha256": "a501aa0916837a4abfbd5f910662f525be0833be53d3d46a0c98973659ba21f2",
"format": 1
},
{
"name": ".github/workflows/publish_collection.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5dc1ef6a5c6cdf0ce4d49e520df15cefc0b8f9732f9cde850c8f82d674a247b2",
+ "chksum_sha256": "e938fc2ffec98aa434184ee4f7f7a293def84daaadf116289b38226e0a00426a",
"format": 1
},
{
@@ -53,14 +53,14 @@
"name": ".github/workflows/test-roles.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d3b655c70d9d1d8f93a6e18a36c04735ef41c9cf67c5db5c82fa5a8d51a5ac3a",
+ "chksum_sha256": "fcb80d477c82b079fbf7fc1bb3b099bb913d4961c699026bc2b78e8064cb58e6",
"format": 1
},
{
"name": ".github/workflows/x509.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e0f9df03ae321bb23feeec7ee9b0de71d915fa27667aa3f88cb52a82d1ea07a8",
+ "chksum_sha256": "da22d7aa6893fdf4134f886f828344437bbdab96808ad7617f36775f619d480f",
"format": 1
},
{
@@ -95,7 +95,7 @@
"name": "changelogs/changelog.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a2b8248a625db8ee7b0564011caa76e5cca57d319a6465f327b2151bfac26a47",
+ "chksum_sha256": "62026cfdee0d726808baf3b46212cb3b1d0668bf8f156898c11b3017f45c67e4",
"format": 1
},
{
@@ -151,7 +151,7 @@
"name": "plugins/cache/mongodb.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "dd0e0964cdbeb66487c9dd39feeee0f408221f0060988df7afc8ee9b5c17b9bd",
+ "chksum_sha256": "aedbdc6afc85b4d5ed39ce822c4573b7a7de0742ea6ec43e5e7e1f6bcfb12905",
"format": 1
},
{
@@ -162,6 +162,13 @@
"format": 1
},
{
+ "name": "plugins/doc_fragments/atlas_options.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c28b5eaeb1b089c9b66a2ad64ba7467f7836f86d6948ca9e5aed684304873b2a",
+ "format": 1
+ },
+ {
"name": "plugins/doc_fragments/login_options.py",
"ftype": "file",
"chksum_type": "sha256",
@@ -211,10 +218,17 @@
"format": 1
},
{
+ "name": "plugins/module_utils/mongodb_atlas.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e63bf87e1f6f35859e306fbd7070c70c1d5406ab3a30c51923cc6fe0d338779a",
+ "format": 1
+ },
+ {
"name": "plugins/module_utils/mongodb_common.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "31ee1df028aaf5f6807866807dd9bbb584318af5bd640c924daf3b4ad76dfc48",
+ "chksum_sha256": "a46ecf4ee936b461cabe289496e425a9fd2d454df7c083580e7e65c96c45092d",
"format": 1
},
{
@@ -239,10 +253,38 @@
"format": 1
},
{
+ "name": "plugins/modules/mongodb_atlas_cluster.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "41da55ac3e6fbeeb8ad3c056e37e1bf3116b6b75b82dbbcd279af10f9228d247",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/mongodb_atlas_ldap_user.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "2c424fd746b2a531c811fc9d4ba6126e42b6433db87998beae2ac725392cf3c9",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/mongodb_atlas_user.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "fc1f272d0d97322664633458de27c9fcbc0011696052421bc2bb58d7fb06744b",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/mongodb_atlas_whitelist.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "066c44e0ed09fb61e4a0b66416a644121eb7eb5556c9a1895ae8305f49f4ffcf",
+ "format": 1
+ },
+ {
"name": "plugins/modules/mongodb_balancer.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a634f2ab69e027cd9876a36937c808b1ab551707739aa4bf87c88f5bbeffc635",
+ "chksum_sha256": "dd4263c776a24763b3811a2a343dcb555a53f135e452216417b8018d970e26c7",
"format": 1
},
{
@@ -267,13 +309,6 @@
"format": 1
},
{
- "name": "plugins/modules/mongodb_monitoring.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "928eca8ce08b54251c708fb88749f1f5a75aa26e7f1c84fbe31983f43ab4fe4e",
- "format": 1
- },
- {
"name": "plugins/modules/mongodb_oplog.py",
"ftype": "file",
"chksum_type": "sha256",
@@ -291,14 +326,14 @@
"name": "plugins/modules/mongodb_replicaset.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "044d8ef48ba89fd5809b673990776acfa573c9b2a27890d7d6cddd17f2afc50f",
+ "chksum_sha256": "c26ca9213dc53361cf320db30d7e478d4107da0ca89b2b2a72c5e50d17352db0",
"format": 1
},
{
"name": "plugins/modules/mongodb_role.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "53bf6881a8d8dae4abf3d94cd238b24eb13c4ae39420495e57f25c799ba1fba6",
+ "chksum_sha256": "2fd82f46ba80720492007a2505e4aca8a5053a71dba2b27a9f1cead7cc33d57d",
"format": 1
},
{
@@ -361,7 +396,7 @@
"name": "plugins/modules/mongodb_user.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "dc53094a237fcc6941306d9bc48d30097c8f3e8b50cbb122d841e2140f16af4d",
+ "chksum_sha256": "3d4cd46206b60f69ed168e84ec54e151a32c1c4a18c1c2989d19a6e9e98924a7",
"format": 1
},
{
@@ -389,7 +424,7 @@
"name": "roles/mongodb_auth/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "770aaa7a7e1aa715295ce515ebcc381e0ddf088bb88df068626d5f023e577b9a",
+ "chksum_sha256": "b6135635aa61d2f294bf69a1b7308495d1b82be79bc7ce2f514ae9e0c4f693f5",
"format": 1
},
{
@@ -445,14 +480,14 @@
"name": "roles/mongodb_auth/molecule/default/molecule.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "189c4239601a31224b5b0e5c2555d3824f8db7faa50bd5b3286db59f9762a919",
+ "chksum_sha256": "7277bbdc4e39e8b2fea6947c097402c58b19ddf3c55362b9de63eee36c6d94e2",
"format": 1
},
{
"name": "roles/mongodb_auth/molecule/default/playbook.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "90376e78d3e52f87ea244a0da77ce40456dac6455a49eeb1e3f6b6edfc8c47bd",
+ "chksum_sha256": "52ca66d02d0aa4bbed51e46564a5be8f3a973a5efa1fb58adaf76c636ac209cc",
"format": 1
},
{
@@ -515,14 +550,14 @@
"name": "roles/mongodb_auth/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4dfaf85065ad9d25d59e58ff7aca52d1f7a02caac905e434921eecb6387c2bb4",
+ "chksum_sha256": "d053cc9984165bbdfab92bcbb59e988d5766b2f9fbc9acc3df95a403f398abdb",
"format": 1
},
{
"name": "roles/mongodb_auth/tasks/mongodb_auth_user.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "327d37e2ce96949fa0401129c3609fe8f8c93fa7075cad4115f2465117a7e947",
+ "chksum_sha256": "d27869371e43dceadffe0295ab9ee06e3161dc94fa598ed8776e559d9f916c82",
"format": 1
},
{
@@ -599,7 +634,7 @@
"name": "roles/mongodb_config/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b02f09d1c97cb479f785d03f12474d9fc599049d74ae1374063960250ab94948",
+ "chksum_sha256": "75bcad9b2efe940df6365fe5051866d218383c609fdb60ebfcc95b7de083220a",
"format": 1
},
{
@@ -662,21 +697,21 @@
"name": "roles/mongodb_config/molecule/custom_db_path/tests/test_default.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6785ea2c0ef42b1c74098c66a58e79496172b9150c3a6f840da39becf1e65f92",
+ "chksum_sha256": "9043f00bfad88d3f198692b80b762ca41af5db6d2f57f72915a2d74c3d4f853c",
"format": 1
},
{
"name": "roles/mongodb_config/molecule/custom_db_path/molecule.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7a81696b0bba4ff65dc6d7f89d16d2c7daa6368b5e84ff4772fbf31210bb1c3c",
+ "chksum_sha256": "7ed5994c9bef0b2e46cf6bae21af9a82a7366b3a8dc85605c217f6941166c3c5",
"format": 1
},
{
"name": "roles/mongodb_config/molecule/custom_db_path/playbook.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ab3364344b36e00fcad9d5e00be1aa6c15ea629d619a8e87308d38416045891c",
+ "chksum_sha256": "96f0c0737e5155e74c3221fe8140e6fed8829c88b8e7f67e53bd64d4bc8b5efe",
"format": 1
},
{
@@ -711,21 +746,21 @@
"name": "roles/mongodb_config/molecule/default/tests/test_default.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "76c4a4583bbd511453521974072f30d98268c9061ac35d85edf3846d4544da69",
+ "chksum_sha256": "d58ff4a841a0c923e98e0e4c2f5f2c4c72e32eb8879b743e48e9de1f0227124a",
"format": 1
},
{
"name": "roles/mongodb_config/molecule/default/molecule.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7a81696b0bba4ff65dc6d7f89d16d2c7daa6368b5e84ff4772fbf31210bb1c3c",
+ "chksum_sha256": "7ed5994c9bef0b2e46cf6bae21af9a82a7366b3a8dc85605c217f6941166c3c5",
"format": 1
},
{
"name": "roles/mongodb_config/molecule/default/playbook.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4d583abdcf01781aa7067708340991b1ce76a927d4a0c3f20f0f728d19e2d50f",
+ "chksum_sha256": "23267a579fc73f82b2e15f3b7652d25f2a44fdc8bf2c374ad21be9ef90426eb8",
"format": 1
},
{
@@ -802,7 +837,7 @@
"name": "roles/mongodb_config/templates/configsrv.conf.j2",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c6ef3f0bde18b5678d91f4a04538d10957dfc5cfb6e51131675268e6905869af",
+ "chksum_sha256": "24094caecb4f6c83858bf5d854b0c2e3b3a9c6daed896e592eb937b0f963d5ef",
"format": 1
},
{
@@ -851,7 +886,7 @@
"name": "roles/mongodb_config/README.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ccf4c86dd5e1a6e1998fbb59d506b5473f94a58caecac46568f167033f12c183",
+ "chksum_sha256": "1a927b09d12cc908ac710a0d3fa72671be0f50e4930e185db510bdd8f2d1c8c4",
"format": 1
},
{
@@ -872,7 +907,7 @@
"name": "roles/mongodb_install/files/lock_mongodb_packages.sh",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "89582cbb311785ffd3e39029a6f03678267cb1e84995b7260ed41bcc3a508e83",
+ "chksum_sha256": "463061abc6bebbcbad2e3d4a111c4d813494a8504e73d24c66335850e148430c",
"format": 1
},
{
@@ -928,7 +963,7 @@
"name": "roles/mongodb_install/molecule/default/molecule.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e1d96e0e5e9e889366a75d87c73f5408954d1bcfab2e1253c6e070f4d6da1509",
+ "chksum_sha256": "704539b8afef5b03179bfebc38ca69b4017f863b86821af66866c6138d6b7965",
"format": 1
},
{
@@ -939,6 +974,13 @@
"format": 1
},
{
+ "name": "roles/mongodb_install/molecule/default/prepare.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "716aa1020826da54c85e96d853b6f075d293f3b85163f1e59083e6a77de03f6b",
+ "format": 1
+ },
+ {
"name": "roles/mongodb_install/molecule/mongodb_hold_packages",
"ftype": "dir",
"chksum_type": null,
@@ -963,14 +1005,14 @@
"name": "roles/mongodb_install/molecule/mongodb_hold_packages/tests/test_default.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6e073162dffc65ded4fb9afefc297a091c7210f97072044c905b09502944147b",
+ "chksum_sha256": "fe77ad84ef37f1e94aea2dc559de730eb76792fd6f2e6162b055dd5a07eea0a1",
"format": 1
},
{
"name": "roles/mongodb_install/molecule/mongodb_hold_packages/molecule.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1415aa365827c25bd2eb92c2ed0b7fc5d994211d1ace12939d9edf3108238029",
+ "chksum_sha256": "52aaa6252e224662deeae462f1196eb36627d457c368c97b1921fa358f511da1",
"format": 1
},
{
@@ -984,7 +1026,7 @@
"name": "roles/mongodb_install/molecule/mongodb_hold_packages/prepare.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "33e0317ed95fb8f1c1c1731829ab5face9b8a4b462508ca98b7f0f60d2fd081c",
+ "chksum_sha256": "39b7a0f9bc99a5ed5e6780cddaf721d86d5ebdba3b816331e0477bdc74ab2834",
"format": 1
},
{
@@ -1012,14 +1054,14 @@
"name": "roles/mongodb_install/molecule/mongodb_nohold_packages/tests/test_default.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3a2b47c9b82958b1a9e6f02b2deae73bc3cf7c1d7a3b71677bb44014ee9495d1",
+ "chksum_sha256": "55316179446793619e8f84077feb30a7f196c2d745696845435df26c35dbe821",
"format": 1
},
{
"name": "roles/mongodb_install/molecule/mongodb_nohold_packages/molecule.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1415aa365827c25bd2eb92c2ed0b7fc5d994211d1ace12939d9edf3108238029",
+ "chksum_sha256": "52aaa6252e224662deeae462f1196eb36627d457c368c97b1921fa358f511da1",
"format": 1
},
{
@@ -1033,7 +1075,7 @@
"name": "roles/mongodb_install/molecule/mongodb_nohold_packages/prepare.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "86d57bedf4f40ab8b4bb0e3c2ff7dd13460c59bb717b75f40c66127fdf04fc19",
+ "chksum_sha256": "39b7a0f9bc99a5ed5e6780cddaf721d86d5ebdba3b816331e0477bdc74ab2834",
"format": 1
},
{
@@ -1068,7 +1110,7 @@
"name": "roles/mongodb_install/molecule/specific_mongodb_version/molecule.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1357cdc063266cba2791e9aff653754beaeac0ccb4cc9c14e57f276efb073a85",
+ "chksum_sha256": "f00fe8ebc792b3ed29f11cf1a6a6ea2a812da05c42381c3159992b16e29a43e9",
"format": 1
},
{
@@ -1079,6 +1121,13 @@
"format": 1
},
{
+ "name": "roles/mongodb_install/molecule/specific_mongodb_version/prepare.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "716aa1020826da54c85e96d853b6f075d293f3b85163f1e59083e6a77de03f6b",
+ "format": 1
+ },
+ {
"name": "roles/mongodb_install/molecule/virtualbox",
"ftype": "dir",
"chksum_type": null,
@@ -1131,7 +1180,7 @@
"name": "roles/mongodb_install/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "96fc2a8682910071e99da627660d51e23b3810c8527f9417e7676bc19d041db7",
+ "chksum_sha256": "7e697265fdb1056041aa09706fbd1692a788d642f9e854c8e4f48feca59dc15b",
"format": 1
},
{
@@ -1166,7 +1215,7 @@
"name": "roles/mongodb_linux/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8c1cb3f8cb7c88e5f9b94e95c798303831bd6d28cee2b24b42e1b8b5c3c77fc7",
+ "chksum_sha256": "d86ecaec3b0c92ecd4838d5d23c78facb542ec49032799451ba4e4faafccc63c",
"format": 1
},
{
@@ -1180,7 +1229,7 @@
"name": "roles/mongodb_linux/files/thp-disable.service",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1b9f839d1dbbb918acd201e94fe3a9bb9ddaafdbf9398059f8fb0817ecd823c3",
+ "chksum_sha256": "8b7ce5d74e14d3efe593ed64d94376f5320183f9f522b407cbad53a72bbb5439",
"format": 1
},
{
@@ -1236,7 +1285,7 @@
"name": "roles/mongodb_linux/molecule/default/molecule.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b231dbfcbc1932c974c1a82df6cc5e5b32dce3b2168bae77781e8c5f0a706d6b",
+ "chksum_sha256": "fe17f301302d20fdd6df13667cc160c5f0305b639eaddc00203da9b988185241",
"format": 1
},
{
@@ -1299,7 +1348,7 @@
"name": "roles/mongodb_linux/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c3eea6e9a70b6f26b80927d4e7b32ed555d1b3c823aeabca4d9e4827eb82d98f",
+ "chksum_sha256": "6fced29f74e80b9e274f5ec26398f1a7f58ff53b0b89c049fcfbffb18d9c812f",
"format": 1
},
{
@@ -1310,6 +1359,13 @@
"format": 1
},
{
+ "name": "roles/mongodb_linux/vars/Debian-12.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "3755aba3d3662eb7a5db022eeee52e58af7498f7cd2a11f56f0affac09cffb9f",
+ "format": 1
+ },
+ {
"name": "roles/mongodb_linux/vars/Debian.yml",
"ftype": "file",
"chksum_type": "sha256",
@@ -1331,6 +1387,13 @@
"format": 1
},
{
+ "name": "roles/mongodb_linux/vars/RedHat-9.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "a2f3697e1cadee2ccd84ff99e8c57788bca914a28e7fd3826c580fa8ad1f6ba0",
+ "format": 1
+ },
+ {
"name": "roles/mongodb_linux/vars/RedHat.yml",
"ftype": "file",
"chksum_type": "sha256",
@@ -1355,7 +1418,7 @@
"name": "roles/mongodb_linux/README.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "63c1aafaf9e96e1b5af474e2ae294424374cd0ddc0f2b9168ee423bf577a38eb",
+ "chksum_sha256": "f5aa2b290ead1c5bc566f8090cf8158f709b391d6c505a06c79792f2f3013e13",
"format": 1
},
{
@@ -1376,7 +1439,7 @@
"name": "roles/mongodb_mongod/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3fd9448c9f2e71d1392c3204ce01532404b663397b8a38dd475a3b908a8a06d7",
+ "chksum_sha256": "9393e6e14e1beae42490926c6a614768816c3755f880f6a01e0524386358a0b0",
"format": 1
},
{
@@ -1390,7 +1453,7 @@
"name": "roles/mongodb_mongod/handlers/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "662a28d9c1fd7469e827f9c7cba697264223ccddf694c130d05123e531078b1b",
+ "chksum_sha256": "3e6b2158c8e1234c3ae1f3014245b0484006a532a8aca06f93b07dc83e411447",
"format": 1
},
{
@@ -1439,21 +1502,21 @@
"name": "roles/mongodb_mongod/molecule/custom_db_path/tests/test_default.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a1329ddc753d95bb5b6a419239dd11b04458d311b7c887383209fca998d2e7e1",
+ "chksum_sha256": "114708df31e1ae006de36e6da5855dc27e2364ed5d59fcd479c5df011568bb4a",
"format": 1
},
{
"name": "roles/mongodb_mongod/molecule/custom_db_path/molecule.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a755fd15a10b01e97988e46729fa0778559f1ae60113cb225d5b9888ae5830ac",
+ "chksum_sha256": "b0f6a68a3bc235970237258b0e194ed94fae205efebe453a6c9f20addd5a5ce0",
"format": 1
},
{
"name": "roles/mongodb_mongod/molecule/custom_db_path/playbook.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f00bd99f8c6f8a3846cc888ed647c62bd78e1f80919a27b4d7c7760d81b81bd3",
+ "chksum_sha256": "255483b7cc0083dc8dfd74a643d66773878ed4424a5d2c2a58f0e549c8921b81",
"format": 1
},
{
@@ -1488,21 +1551,21 @@
"name": "roles/mongodb_mongod/molecule/default/tests/test_default.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "17805508cb475efa6ef5db20800b4a5a579c821d410bae36a35bd146ca6fa3e1",
+ "chksum_sha256": "2cc045495253d0c39609fa814d0911454c25a829c98e6038a7791cf54723cc71",
"format": 1
},
{
"name": "roles/mongodb_mongod/molecule/default/molecule.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "994424e997851f791720fba34b6b65eb6afbc38c82d0dee086fcd7078275a9e6",
+ "chksum_sha256": "e1b801f8421f73a84b91e8eb1b091e3edc7b169ac8f245d2f0da97b0d35b7d71",
"format": 1
},
{
"name": "roles/mongodb_mongod/molecule/default/playbook.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "63a19a9b4f08c1266695faaba9e54dbedd28e3dcc8c6787e64766ba8bb417761",
+ "chksum_sha256": "192e372a1908bcf0ec54b8c52eb459db79529fe098210c07b42363c62f52443a",
"format": 1
},
{
@@ -1537,21 +1600,21 @@
"name": "roles/mongodb_mongod/molecule/multiple_bind_ip/tests/test_default.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ecc1e7f77b43b5e6a46e171a9a2bf2b63ffa4d83f38ef1a721f10ccf8f4bb7a8",
+ "chksum_sha256": "4bcab44a1f135f5a657ed3149112fd3321a6a63591ef60a5669fa690da892b31",
"format": 1
},
{
"name": "roles/mongodb_mongod/molecule/multiple_bind_ip/molecule.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7e577d75e184d4b8f9a43b00e9dacc2f228a308a1bd6c19a5eb2692856e53ec8",
+ "chksum_sha256": "4bd4d98c03f8cd3c6d8ce974474df1a038b73cbf0e0c1da9aa0090ae531ef0a4",
"format": 1
},
{
"name": "roles/mongodb_mongod/molecule/multiple_bind_ip/playbook.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b51c6a694115163ce2b6812c3c520723a8f7c45dd5b779172d12ad7fa5635edc",
+ "chksum_sha256": "a746b663a752a435a6490632389476a1f502e138886c66fff49cccdc1e068f9e",
"format": 1
},
{
@@ -1611,10 +1674,17 @@
"format": 1
},
{
+ "name": "roles/mongodb_mongod/tasks/logrotate.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "118a6c4770ac2a3880516cbb8b4cf84bb8e03bf0500a3736f8bc1928312d7c35",
+ "format": 1
+ },
+ {
"name": "roles/mongodb_mongod/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "52dbf388253cdfc09243b8f3de0ca28f274a82c89e325ab18bbd8aafb5b743a8",
+ "chksum_sha256": "e14ef77e6676c1e39f5be07eeb2392027fb4fb88676c608deb75607e23823018",
"format": 1
},
{
@@ -1628,7 +1698,14 @@
"name": "roles/mongodb_mongod/templates/mongod.conf.j2",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "13f379130e1e18bbc1e0819207beeb4f26d4a52b192fa75de3f125db0390862c",
+ "chksum_sha256": "7640c7f81cf31e93dc02bb1e1b5099ddc1f9b555e5109190f2c252fed81f4b43",
+ "format": 1
+ },
+ {
+ "name": "roles/mongodb_mongod/templates/mongodb.logrotate.j2",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "21ad67a4b7659d49e8d7d0c4533c02b84f1e5d233c427034eaebe0458897096b",
"format": 1
},
{
@@ -1677,7 +1754,7 @@
"name": "roles/mongodb_mongod/README.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4d0e53aee8b83c06980a6350923a8a0e1c6d55e9a48409c21e5c3a0a9a587571",
+ "chksum_sha256": "b1476365276bea045940d237a5aabeec55bb9b33c084e4eb11f898e19a137066",
"format": 1
},
{
@@ -1698,7 +1775,7 @@
"name": "roles/mongodb_mongos/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "01ab55998e3208feebf702cb0e3ffc97cf4f603e5086e994054f2735ba3078bf",
+ "chksum_sha256": "688a38955cb3af4ad91934f5dc605591b9ea7b4ff4409d52c6d467d353ac42e1",
"format": 1
},
{
@@ -1768,21 +1845,21 @@
"name": "roles/mongodb_mongos/molecule/default/molecule.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "702b696ccd89d34c943a966e4185e2473eb9a0f1621411584c08499f16c55a93",
+ "chksum_sha256": "0a092e14ce32979f4898440305e2b6deb139b6e1111d1a2e4931c031cf5d409d",
"format": 1
},
{
"name": "roles/mongodb_mongos/molecule/default/playbook.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "89c6e68e43761ba1c1561cb77854e7e79b32726ee4f03d1d7f7e185ca0bf8883",
+ "chksum_sha256": "531b36ee51c7dbce56828f34f361a11cdbe8be1ab3467886e19c95afd592ad67",
"format": 1
},
{
"name": "roles/mongodb_mongos/molecule/default/prepare.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "158c7741dc6b3aab715292c41dcf01fabbebf01638c97446589ab877ffe22491",
+ "chksum_sha256": "e00402f4e6a834f23823890627199c922e4a9de4f4a7a94cd872e915036afbd2",
"format": 1
},
{
@@ -1852,7 +1929,7 @@
"name": "roles/mongodb_mongos/templates/mongos.conf.j2",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3dca1de18243e57265866cd9b9b851dac3a1941fdf8da97e93d1c57643108d5f",
+ "chksum_sha256": "fbd7af556a9778eeccce3b0b345a8d2644eae92224393eb17522d9241673d7a7",
"format": 1
},
{
@@ -1908,7 +1985,7 @@
"name": "roles/mongodb_mongos/README.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a13f2fab8aceb7e147ee8f691e050bc65bbf3f6f44495ce6217d567adcf58dd1",
+ "chksum_sha256": "46b03a9992c095fd3813f0aeb108042f0dca6d3034e95347a65b15ef3474ff0e",
"format": 1
},
{
@@ -1985,7 +2062,7 @@
"name": "roles/mongodb_repository/molecule/default/molecule.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "05560652ed31d566d085a225e2b5aeb50c66c54f9c943982fc7ecad4fd0cf4bf",
+ "chksum_sha256": "6e6d921129d528fcd553ea213e652cf3a37c3fe6fe95b57b470fa12ada407a84",
"format": 1
},
{
@@ -2146,7 +2223,7 @@
"name": "roles/mongodb_selinux/molecule/default/molecule.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "90f021d6adf7fe29b9140e6137c0c6c8afa0bdbdfbcb82014f4286d3d0ecf139",
+ "chksum_sha256": "d0b2f513f9d181359b54313f3542e9056262309f68f3dd8cd93eecaad6fbd746",
"format": 1
},
{
@@ -2293,7 +2370,7 @@
"name": "CHANGELOG.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "17b50804c5b444656c29da757e68b4f9769a5a8eba9af7bdc772527943fccb05",
+ "chksum_sha256": "c81479be70033bb9abe13501e9c3eef37936cb74ea74bbfea1d83d9e685c2917",
"format": 1
},
{
@@ -2307,7 +2384,7 @@
"name": "README.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3308be37a3b35aec4053a63147f24db66db009ab48f6c73c9eb976dcc2b4fa94",
+ "chksum_sha256": "30119dbbd021221c84f7447cee3fd266408933a599e51affa2fab12db835bd87",
"format": 1
},
{
diff --git a/ansible_collections/community/mongodb/MANIFEST.json b/ansible_collections/community/mongodb/MANIFEST.json
index 4e225b112..8ae826436 100644
--- a/ansible_collections/community/mongodb/MANIFEST.json
+++ b/ansible_collections/community/mongodb/MANIFEST.json
@@ -2,7 +2,7 @@
"collection_info": {
"namespace": "community",
"name": "mongodb",
- "version": "1.6.0",
+ "version": "1.7.2",
"authors": [
"Ansible (https://github.com/ansible)",
"Rhys Campbell (https://github.com/rhysmeister)",
@@ -11,7 +11,8 @@
"Elliott Foster (http://fourkitchens.com)",
"Loic Blot (http://www.infopro-digital.com/)",
"Matt Martz (https://github.com/sivel)",
- "Jacob Floyd (https://github.com/cognifloyd)"
+ "Jacob Floyd (https://github.com/cognifloyd)",
+ "Martin Schurz (https://github.com/schurzi)"
],
"readme": "README.md",
"tags": [
@@ -35,7 +36,7 @@
"name": "FILES.json",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "088440e2e1049c54446ad93e2ba9288528fd68f0451484b75ffbbbd6f0528e24",
+ "chksum_sha256": "4d1c58600e395dade74dad0a4e8ad949bda341bf224312202dcff67516a0a16e",
"format": 1
},
"format": 1
diff --git a/ansible_collections/community/mongodb/README.md b/ansible_collections/community/mongodb/README.md
index cd86c4322..caadf1e93 100644
--- a/ansible_collections/community/mongodb/README.md
+++ b/ansible_collections/community/mongodb/README.md
@@ -1,10 +1,8 @@
# MongoDB Version and PyMongoDB Version Compatibility
-- This collection is tested against the most recent two minor MongoDB releases, currently 5.0.X and 6.0.X.
-- ~This collection is tested against PyMongo version 3.12.X and latest.~ PyMongo 3.12.X dropped on 11.04.2023. Now PyMongo latest only.
-- This collection will not run against any MongoDB version lower than 4.0. You can set *strict_compatibility* to false to override this behaviour but don't expect 100% success. It might be a better approach to use an older release of this collection (1.3.4 or earlier) if you're using an old MongoDB version (3.6 or earlier).
+- This collection is tested against the most recent two minor MongoDB releases, currently 6.0.X and 7.0.X.
+- PyMongo 3.12.X dropped on 11.04.2023. Now PyMongo latest only.
- Compatibility may be maintained for older software versions but is not guaranteed. Please upgrade your PyMongo driver version if you encounter difficulties with older versions.
-- ~Support for PyMongo versions less than 4.X will be dropped in the future.~ [Drop support for pymongo < 4.0?](https://github.com/ansible-collections/community.mongodb/issues/457) - Support for Pymongo < 4.0 now dropped from collection version 1.5.0
# Mongodb Collection
|Category|Status|
@@ -12,10 +10,6 @@
|Github CI|![CI](https://github.com/ansible-collections/community.mongodb/workflows/CI/badge.svg)|
|Codecov|[![Codecov](https://img.shields.io/codecov/c/github/ansible-collections/community.mongodb)](https://codecov.io/gh/ansible-collections/community.mongodb)|
|CI Roles|![CI_roles](https://github.com/ansible-collections/community.mongodb/workflows/CI_roles/badge.svg)|
-|AutomatingMongoDBWithAnsible|[![CI-basic](https://github.com/rhysmeister/AutomatingMongoDBWithAnsible/actions/workflows/CI-basic.yml/badge.svg)](https://github.com/rhysmeister/AutomatingMongoDBWithAnsible/actions/workflows/CI-basic.yml)|
-|AutomatingMongoDBWithAnsible|[![CI-etc](https://github.com/rhysmeister/AutomatingMongoDBWithAnsible/actions/workflows/CI-etc.yml/badge.svg)](https://github.com/rhysmeister/AutomatingMongoDBWithAnsible/actions/workflows/CI-etc.yml)|
-|AutomatingMongoDBWithAnsible|[![CI-resync](https://github.com/rhysmeister/AutomatingMongoDBWithAnsible/actions/workflows/CI-resync.yml/badge.svg)](https://github.com/rhysmeister/AutomatingMongoDBWithAnsible/actions/workflows/CI-resync.yml)|
-|AutomatingMongoDBWithAnsible|[![CI-upgrade-downgrade](https://github.com/rhysmeister/AutomatingMongoDBWithAnsible/actions/workflows/CI-upgrade-downgrade.yml/badge.svg)](https://github.com/rhysmeister/AutomatingMongoDBWithAnsible/actions/workflows/CI-upgrade-downgrade.yml)|
|Latest Build|![Build & Publish Collection](https://github.com/ansible-collections/community.mongodb/workflows/Build%20&%20Publish%20Collection/badge.svg)|
This collection called `mongodb` aims at providing all Ansible modules allowing to interact with MongoDB.
@@ -58,7 +52,6 @@ These modules are for any MongoDB cluster (standalone, replicaset, or sharded):
- `community.mongodb.mongodb_index`: Creates or drops indexes on MongoDB collections.
- `community.mongodb.mongodb_info`: Gather information about MongoDB instance.
-- `community.mongodb.mongodb_monitoring`: Manages the [free monitoring](https://docs.mongodb.com/manual/administration/free-monitoring/) feature.
- `community.mongodb.mongodb_oplog`: [Resizes](https://docs.mongodb.com/manual/tutorial/change-oplog-size) the MongoDB oplog (MongoDB 3.6+ only).
- `community.mongodb.mongodb_parameter`: Change an administrative parameter on a MongoDB server.
- `community.mongodb.mongodb_role`: Manage [MongoDB Roles](https://www.mongodb.com/docs/upcoming/tutorial/manage-users-and-roles/).
@@ -81,6 +74,12 @@ These modules are only useful for sharded MongoDB clusters:
- `community.mongodb.mongodb_shard_tag`: Manage Shard Tags.
- `community.mongodb.mongodb_shard_zone`: Manage Shard Zones.
+These modules are only useful for MongoDB Atlas clusters:
+
+- `community.mongodb.mongodb_atlas_cluster`: Manage MongoDB clusters in Atlas.
+- `community.mongodb.mongodb_atlas_ldap_user`: Manage LDAP users in Atlas.
+- `community.mongodb.mongodb_atlas_user`: Manage users in Atlas.
+- `community.mongodb.mongodb_atlas_whitelist`: Manage IP whitelists in Atlas.
## community.mongodb Role Tags
@@ -111,6 +110,14 @@ These tags apply to the specific roles as indicated.
|mongodb_auth|admin_user|Tasks that work with the MongoDB Administrator user.|
|mongodb_auth|app_user|Tasks that work with MongoDB app users.|
+## Usage Examples
+
+The following links provide various examples for how the community.mongodb roles and modules can be used in real projects.
+
+* https://github.com/rhysmeister/AutomatingMongoDBWithAnsible (no longer maintained)
+* https://github.com/superset1/Ansible_role_mongodb
+* https://github.com/ansible-collections/community.mongodb/tree/master/roles/ROLENAME/molecule (replace ROLENAME, some full examples that we use in our testing)
+
## Running the integration and unit tests
* Requirements
@@ -133,14 +140,6 @@ mkdir -p git/ansible_collections/community
cd git/ansible_collections/community
```
-# Usage Examples
-
-The following links provide various exampels for how the community.mongodb roles and modules can be used in real projects.
-
-* https://github.com/rhysmeister/AutomatingMongoDBWithAnsible (no longer maintained)
-* https://github.com/superset1/Ansible_role_mongodb
-* https://github.com/ansible-collections/community.mongodb/tree/master/roles/ROLENAME/molecule (replace ROLENAME, some full examples that we use in our testing)
-
* Clone the required projects.
```bash
diff --git a/ansible_collections/community/mongodb/changelogs/changelog.yaml b/ansible_collections/community/mongodb/changelogs/changelog.yaml
index 7ad33ab5c..7f608d606 100644
--- a/ansible_collections/community/mongodb/changelogs/changelog.yaml
+++ b/ansible_collections/community/mongodb/changelogs/changelog.yaml
@@ -199,8 +199,8 @@ releases:
- 440 - Fix incorrect alias ssl_crlfile.
- 450 - Fix issues with mongodb_replicaset connecting with the pymongo 4.0.X driver.
minor_changes:
- - 450 - mongodb_replicaset. Introduce cluster_cmd parameter. Can be set to isMaster or hello.
- hello is the default. isMaster is useful for older versions of MongoDB.
+ - 450 - mongodb_replicaset. Introduce cluster_cmd parameter. Can be set to isMaster or hello.
+ hello is the default. isMaster is useful for older versions of MongoDB.
See [db.hello()](https://www.mongodb.com/docs/manual/reference/method/db.hello/) for more.
1.3.4:
release_summary: |
@@ -212,7 +212,7 @@ releases:
This release is a maintenance release. Pymongo versions 3.12.* or 4.* are now required. MongoDB version 4+ are also required but can be overriden if desired.
major_changes:
- 470 - Removes depreciated distutils package and require Pymongo 3.12+ and MongoDB 4+
- Adds a new parameter strict_compatibility (default true).
+ Adds a new parameter strict_compatibility (default true).
Set to false to disable Pymongo and MongoDB requirements.
1.4.1:
release_summary: |
@@ -247,7 +247,7 @@ releases:
- 540 mongodb_replicaset - replicaset member priority updates.
- 488 mongodb_info - Better handling of json data types.
modules:
- - description:
+ - description:
- Manage MongoDB User Roles (#530).
name: mongodb_role
namespace: community
@@ -269,4 +269,64 @@ releases:
This release is a maintenance release.
minor_changes:
- 569 - All pymongo modules - Better support for MongoDB Atlas.
- - 568 - Minor documentation updates. \ No newline at end of file
+ - 568 - Minor documentation updates.
+ 1.6.1:
+ release_summary: |
+ This release is a maintenance release.
+ minor_changes:
+ - 578 - mongodb_role - More robust comparison of user roles.
+ 1.6.2:
+ release_summary: |
+ This release is a maintenance release.
+ minor_changes:
+ - 583 - mongodb_linux - Add vars for RedHat 9 to role.
+ - 586 - mongodb_auth - Add ssl vars to role.
+ - 589 - mongodb_linux - Adds vars to better handle ntp package installation and handling.
+ - 588 - mongodb_linux - Default ntp system to systemd-timesyncd for Debian12.
+ - 593 - mongodb_linux - Add vm.max_map_count = 128000 sysctl config.
+ - 597 - mongodb_monitoring - Module has been deleted as Free Monitoring service has been stopped.
+ - 595 - mongodb_linux - Improvements to transparent_hugepage handling.
+ 1.6.3:
+ release_summary: |
+ This release is a maintenance release.
+ minor_changes:
+ - 600 - Remove delete module from README.md.
+ - 601 - mongodb_install - Fix issue with specific_mongodb_version on RedHat OS family.
+ 1.7.0:
+ release_summary: |
+ This release is a maintenance release.
+ minor_changes:
+ - 622 - mongodb_mongod - Allow systemd configuration override.
+ - 620 - mongodb_common - Use SSL constants in shared connection code.
+ - 609 - mongodb_mongod, mongodb_mongos, mongodb_config - support for allowConnectionsWithoutCertificates.
+ - 605 - mongodb_mongod, mongodb_mongos, mongodb_config - support for security.disabledProtocols.
+ bugfixes:
+ - 614 - mongodb_replicaset - Count voting members based on the sum of "votes" and using a comprehension list.
+ - 611 - mongodb_role - lambda function changed to support non-existing keys.
+ modules:
+ - description:
+ - Manage database clusters in Atlas (#612)
+ name: mongodb_atlas_cluster
+ namespace: community
+ - description:
+ - Manage LDAP users in Atlas (#612)
+ name: mongodb_atlas_ldap_user
+ namespace: community
+ - description:
+ - Manage database users in Atlas (#612)
+ name: mongodb_atlas_user
+ namespace: community
+ - description:
+ - Manage IP whitelists in Atlas (#612)
+ name: mongodb_atlas_whitelist
+ namespace: community
+ 1.7.1:
+ release_summary: |
+ This release is a maintenance release.
+ bugfixes:
+ - 631 - cache/mongodb.py - Support pymongo 4.0+. This plugin no longer support pymongo 3.12.*.
+ 1.7.2:
+ release_summary: |
+ This release is a maintenance release.
+ bugfixes:
+ - 638 - mongodb_replicaset - Allow module to update replicaset horizons.
diff --git a/ansible_collections/community/mongodb/plugins/cache/mongodb.py b/ansible_collections/community/mongodb/plugins/cache/mongodb.py
index b51b7b293..0fa7a2cd8 100644
--- a/ansible_collections/community/mongodb/plugins/cache/mongodb.py
+++ b/ansible_collections/community/mongodb/plugins/cache/mongodb.py
@@ -182,7 +182,7 @@ class CacheModule(BaseCacheModule):
def contains(self, key):
with self._collection() as collection:
- return bool(collection.count({'_id': self._make_key(key)}))
+ return bool(collection.count_documents({'_id': self._make_key(key)}))
def delete(self, key):
del self._cache[key]
diff --git a/ansible_collections/community/mongodb/plugins/doc_fragments/atlas_options.py b/ansible_collections/community/mongodb/plugins/doc_fragments/atlas_options.py
new file mode 100644
index 000000000..dfdee3325
--- /dev/null
+++ b/ansible_collections/community/mongodb/plugins/doc_fragments/atlas_options.py
@@ -0,0 +1,54 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2021 T-Systems MMS
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+#
+# This module is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this software. If not, see <http://www.gnu.org/licenses/>.
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+class ModuleDocFragment(object):
+ # Documentation for global options that are always the same
+ DOCUMENTATION = r'''
+options:
+ api_username:
+ description:
+ - The username for use in authentication with the Atlas API.
+ - Can use API users and tokens (public key is username)
+ type: str
+ required: True
+ aliases: [apiUsername]
+ api_password:
+ description:
+ - The password for use in authentication with the Atlas API.
+ - Can use API users and tokens (private key is password)
+ type: str
+ required: True
+ aliases: [apiPassword]
+ group_id:
+ description:
+ - Unique identifier for the Atlas project.
+ type: str
+ required: True
+ aliases: [groupId]
+ state:
+ description:
+ - State of the ressource.
+ choices: [ "present", "absent" ]
+ default: present
+ type: str
+'''
diff --git a/ansible_collections/community/mongodb/plugins/module_utils/mongodb_atlas.py b/ansible_collections/community/mongodb/plugins/module_utils/mongodb_atlas.py
new file mode 100644
index 000000000..a32f3e1de
--- /dev/null
+++ b/ansible_collections/community/mongodb/plugins/module_utils/mongodb_atlas.py
@@ -0,0 +1,220 @@
+# -*- coding: utf-8 -*-
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+import json
+from collections import defaultdict
+
+from ansible.module_utils.urls import fetch_url
+
+try:
+ from urllib import quote
+except ImportError:
+ # noinspection PyCompatibility, PyUnresolvedReferences
+ from urllib.parse import (
+ quote,
+ ) # pylint: disable=locally-disabled, import-error, no-name-in-module
+
+
+class AtlasAPIObject:
+ module = None
+
+ def __init__(
+ self, module, object_name, group_id, path, data, data_is_array=False
+ ):
+ self.module = module
+ self.path = path
+ self.data = data
+ self.group_id = group_id
+ self.object_name = object_name
+ self.data_is_array = data_is_array
+
+ self.module.params["url_username"] = self.module.params["api_username"]
+ self.module.params["url_password"] = self.module.params["api_password"]
+
+ def call_url(self, path, data="", method="GET"):
+ headers = {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ }
+
+ if self.data_is_array and data != "":
+ data = "[" + data + "]"
+
+ url = (
+ "https://cloud.mongodb.com/api/atlas/v1.0/groups/"
+ + self.group_id
+ + path
+ )
+ rsp, info = fetch_url(
+ module=self.module,
+ url=url,
+ data=data,
+ headers=headers,
+ method=method,
+ )
+
+ content = ""
+ error = ""
+ if rsp and info["status"] not in (204, 404):
+ content = json.loads(rsp.read())
+ if info["status"] >= 400:
+ try:
+ content = json.loads(info["body"])
+ error = content["reason"]
+ if "detail" in content:
+ error += ". Detail: " + content["detail"]
+ except ValueError:
+ error = info["msg"]
+ if info["status"] < 0:
+ error = info["msg"]
+ return {"code": info["status"], "data": content, "error": error}
+
+ def exists(self):
+ additional_path = ""
+ if self.path == "/databaseUsers":
+ additional_path = "/admin"
+ ret = self.call_url(
+ path=self.path
+ + additional_path
+ + "/"
+ + quote(self.data[self.object_name], "")
+ )
+ if ret["code"] == 200:
+ return True
+ return False
+
+ def create(self):
+ ret = self.call_url(
+ path=self.path,
+ data=self.module.jsonify(self.data),
+ method="POST",
+ )
+ return ret
+
+ def delete(self):
+ additional_path = ""
+ if self.path == "/databaseUsers":
+ additional_path = "/admin"
+ ret = self.call_url(
+ path=self.path
+ + additional_path
+ + "/"
+ + quote(self.data[self.object_name], ""),
+ method="DELETE",
+ )
+ return ret
+
+ def modify(self):
+ additional_path = ""
+ if self.path == "/databaseUsers":
+ additional_path = "/admin"
+ ret = self.call_url(
+ path=self.path
+ + additional_path
+ + "/"
+ + quote(self.data[self.object_name], ""),
+ data=self.module.jsonify(self.data),
+ method="PATCH",
+ )
+ return ret
+
+ def diff(self):
+ additional_path = ""
+ if self.path == "/databaseUsers":
+ additional_path = "/admin"
+ ret = self.call_url(
+ path=self.path
+ + additional_path
+ + "/"
+ + quote(self.data[self.object_name], ""),
+ method="GET",
+ )
+
+ data_from_atlas = json.loads(self.module.jsonify(ret["data"]))
+ data_from_task = json.loads(self.module.jsonify(self.data))
+
+ diff = defaultdict(dict)
+ for key, value in data_from_atlas.items():
+ if key in data_from_task.keys() and value != data_from_task[key]:
+ diff["before"][key] = "{val}".format(val=value)
+ diff["after"][key] = "{val}".format(val=data_from_task[key])
+ return diff
+
+ def update(self, state):
+ changed = False
+ diff_result = {"before": "", "after": ""}
+ if self.exists():
+ diff_result.update({"before": "state: present\n"})
+ if state == "absent":
+ if self.module.check_mode:
+ diff_result.update({"after": "state: absent\n"})
+ self.module.exit_json(
+ changed=True,
+ object_name=self.data[self.object_name],
+ diff=diff_result,
+ )
+ else:
+ try:
+ ret = self.delete()
+ if ret["code"] == 204 or ret["code"] == 202:
+ changed = True
+ diff_result.update({"after": "state: absent\n"})
+ else:
+ self.module.fail_json(
+ msg="bad return code while deleting: %d. Error message: %s"
+ % (ret["code"], ret["error"])
+ )
+ except Exception as e:
+ self.module.fail_json(
+ msg="exception when deleting: " + str(e)
+ )
+
+ else:
+ diff_result.update(self.diff())
+ if self.module.check_mode:
+ if diff_result["after"] != "":
+ changed = True
+ self.module.exit_json(
+ changed=changed,
+ object_name=self.data[self.object_name],
+ data=self.data,
+ diff=diff_result,
+ )
+ if diff_result["after"] != "":
+ if self.path == "/whitelist":
+ ret = self.create()
+ else:
+ ret = self.modify()
+ if ret["code"] == 200 or ret["code"] == 201:
+ changed = True
+ else:
+ self.module.fail_json(
+ msg="bad return code while modifying: %d. Error message: %s"
+ % (ret["code"], ret["error"])
+ )
+
+ else:
+ diff_result.update({"before": "state: absent\n"})
+ if state == "present":
+ if self.module.check_mode:
+ changed = True
+ diff_result.update({"after": "state: created\n"})
+ else:
+ try:
+ ret = self.create()
+ if ret["code"] == 201:
+ changed = True
+ diff_result.update({"after": "state: created\n"})
+ else:
+ self.module.fail_json(
+ msg="bad return code while creating: %d. Error message: %s"
+ % (ret["code"], ret["error"])
+ )
+ except Exception as e:
+ self.module.fail_json(
+ msg="exception while creating: " + str(e)
+ )
+ return changed, diff_result
diff --git a/ansible_collections/community/mongodb/plugins/module_utils/mongodb_common.py b/ansible_collections/community/mongodb/plugins/module_utils/mongodb_common.py
index e1ab27293..2a748b96f 100644
--- a/ansible_collections/community/mongodb/plugins/module_utils/mongodb_common.py
+++ b/ansible_collections/community/mongodb/plugins/module_utils/mongodb_common.py
@@ -168,9 +168,9 @@ def rename_ssl_option_for_pymongo4(connection_options):
when the driver use is >= PyMongo 4
"""
if int(PyMongoVersion[0]) >= 4:
- if connection_options.get('ssl_cert_reqs', None) == 'CERT_NONE':
- connection_options['tlsAllowInvalidCertificates'] = False
- elif connection_options.get('ssl_cert_reqs', None) == 'CERT_REQUIRED':
+ if connection_options.get('ssl_cert_reqs', None) in ('CERT_NONE', ssl_lib.CERT_NONE):
+ connection_options['tlsAllowInvalidCertificates'] = True
+ elif connection_options.get('ssl_cert_reqs', None) in ('CERT_REQUIRED', ssl_lib.CERT_REQUIRED):
connection_options['tlsAllowInvalidCertificates'] = False
connection_options.pop('ssl_cert_reqs', None)
if connection_options.get('ssl_ca_certs', None) is not None:
@@ -395,6 +395,7 @@ def member_dicts_different(conf, member_config):
"hidden": False,
"priority": {"nonarbiter": 1.0, "arbiter": 0},
"tags": {},
+ "horizons": {},
"secondardDelaySecs": 0,
"votes": 1
}
diff --git a/ansible_collections/community/mongodb/plugins/modules/mongodb_atlas_cluster.py b/ansible_collections/community/mongodb/plugins/modules/mongodb_atlas_cluster.py
new file mode 100644
index 000000000..e8aa6e43f
--- /dev/null
+++ b/ansible_collections/community/mongodb/plugins/modules/mongodb_atlas_cluster.py
@@ -0,0 +1,238 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2020 T-Systems MMS
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+#
+# This module is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this software. If not, see <http://www.gnu.org/licenses/>.
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+DOCUMENTATION = '''
+---
+module: mongodb_atlas_cluster
+short_description: Manage database clusters in Atlas
+description:
+ - The clusters module provides access to your cluster configurations.
+ - The module lets you create, edit and delete clusters.
+ - L(API Documentation,https://docs.atlas.mongodb.com/reference/api/clusters/)
+author: "Martin Schurz (@schurzi)"
+extends_documentation_fragment: community.mongodb.atlas_options
+options:
+ name:
+ description:
+ - Name of the cluster as it appears in Atlas. Once the cluster is created, its name cannot be changed.
+ type: str
+ required: True
+ mongo_db_major_version:
+ description:
+ - Version of the cluster to deploy.
+ - Atlas always deploys the cluster with the latest stable release of the specified version.
+ - You can upgrade to a newer version of MongoDB when you modify a cluster.
+ choices: [ "4.2", "4.4", "5.0", "6.0", "7.0" ]
+ type: str
+ aliases: [ "mongoDBMajorVersion" ]
+ cluster_type:
+ description:
+ - Type of the cluster that you want to create.
+ choices: [ "REPLICASET", "SHARDED" ]
+ default: "REPLICASET"
+ type: str
+ aliases: [ "clusterType" ]
+ replication_factor:
+ description:
+ - Number of replica set members. Each member keeps a copy of your databases, providing high availability and data redundancy.
+ choices: [ 3, 5, 7 ]
+ default: 3
+ type: int
+ aliases: [ "replicationFactor" ]
+ auto_scaling:
+ description:
+ - Configure your cluster to automatically scale its storage and cluster tier.
+ suboptions:
+ disk_gb_enabled:
+ type: bool
+ description:
+ - Specifies whether disk auto-scaling is enabled. The default is true.
+ aliases: [ "diskGBEnabled" ]
+ required: False
+ type: dict
+ aliases: [ "autoScaling" ]
+ provider_settings:
+ description:
+ - Configuration for the provisioned servers on which MongoDB runs.
+ - The available options are specific to the cloud service provider.
+ suboptions:
+ provider_name:
+ required: True
+ type: str
+ description:
+ - Cloud service provider on which the servers are provisioned.
+ aliases: [ "providerName" ]
+ region_name:
+ required: True
+ type: str
+ description:
+ - Physical location of your MongoDB cluster.
+ aliases: [ "regionName" ]
+ instance_size_name:
+ required: True
+ type: str
+ description:
+ - Atlas provides different cluster tiers, each with a default storage capacity and RAM size.
+ - The cluster you select is used for all the data-bearing servers in your cluster tier.
+ aliases: [ "instanceSizeName" ]
+ required: True
+ type: dict
+ aliases: [ "providerSettings" ]
+ disk_size_gb:
+ description:
+ - Capacity, in gigabytes, of the host's root volume. Increase this number to add capacity,
+ up to a maximum possible value of 4096 (i.e., 4 TB). This value must be a positive integer.
+ type: int
+ aliases: [ "diskSizeGB" ]
+ provider_backup_enabled:
+ description:
+ - Flag that indicates if the cluster uses Cloud Backups for backups.
+ type: bool
+ aliases: [ "providerBackupEnabled" ]
+ pit_enabled:
+ description:
+ - Flag that indicates the cluster uses continuous cloud backups.
+ type: bool
+ aliases: [ "pitEnabled" ]
+'''
+
+EXAMPLES = '''
+ - name: test cluster
+ community.mongodb.mongodb_atlas_cluster:
+ api_username: "API_user"
+ api_password: "API_passwort_or_token"
+ group_id: "GROUP_ID"
+ name: "testcluster"
+ mongo_db_major_version: "4.0"
+ cluster_type: "REPLICASET"
+ provider_settings:
+ provider_name: "GCP"
+ region_name: "EUROPE_WEST_3"
+ instance_size_name: "M10"
+...
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.community.mongodb.plugins.module_utils.mongodb_atlas import (
+ AtlasAPIObject,
+)
+
+
+# ===========================================
+# Module execution.
+#
+def main():
+ # add our own arguments
+ argument_spec = dict(
+ state=dict(default="present", choices=["absent", "present"]),
+ api_username=dict(required=True, aliases=['apiUsername']),
+ api_password=dict(required=True, no_log=True, aliases=['apiPassword']),
+ group_id=dict(required=True, aliases=['groupId']),
+ name=dict(required=True),
+ mongo_db_major_version=dict(
+ choices=["4.2", "4.4", "5.0", "6.0", "7.0"],
+ aliases=["mongoDBMajorVersion"]
+ ),
+ cluster_type=dict(
+ default="REPLICASET", choices=["REPLICASET", "SHARDED"],
+ aliases=["clusterType"]
+ ),
+ replication_factor=dict(default=3, type="int", choices=[3, 5, 7], aliases=["replicationFactor"]),
+ auto_scaling=dict(
+ type="dict",
+ options=dict(
+ disk_gb_enabled=dict(type="bool", aliases=["diskGBEnabled"]),
+ ),
+ aliases=["autoScaling"]
+ ),
+ provider_settings=dict(
+ type="dict",
+ required=True,
+ options=dict(
+ provider_name=dict(required=True, aliases=["providerName"]),
+ region_name=dict(required=True, aliases=["regionName"]),
+ instance_size_name=dict(required=True, aliases=["instanceSizeName"]),
+ ),
+ aliases=["providerSettings"]
+ ),
+ disk_size_gb=dict(type="int", aliases=["diskSizeGB"]),
+ provider_backup_enabled=dict(type="bool", aliases=["providerBackupEnabled"]),
+ pit_enabled=dict(type="bool", aliases=["pitEnabled"]),
+ )
+
+ # Define the main module
+ module = AnsibleModule(
+ argument_spec=argument_spec, supports_check_mode=True
+ )
+
+ data = {
+ "name": module.params["name"],
+ "clusterType": module.params["cluster_type"],
+ "replicationFactor": module.params["replication_factor"],
+ "providerSettings": {
+ "providerName": module.params["provider_settings"]["provider_name"],
+ "regionName": module.params["provider_settings"]["region_name"],
+ "instanceSizeName": module.params["provider_settings"]["instance_size_name"],
+ }
+ }
+
+ # handle optional options
+ optional_vars = {
+ "mongo_db_major_version": "mongoDBMajorVersion",
+ "auto_scaling": "autoScaling",
+ "disk_size_gb": "diskSizeGB",
+ "provider_backup_enabled": "providerBackupEnabled",
+ "pit_enabled": "pitEnabled",
+ }
+
+ for key in optional_vars:
+ if module.params[key] is not None:
+ if key == "auto_scaling":
+ data.update({optional_vars[key]: {"diskGBEnabled": module.params[key]["disk_gb_enabled"]}})
+ else:
+ data.update({optional_vars[key]: module.params[key]})
+
+ try:
+ atlas = AtlasAPIObject(
+ module=module,
+ path="/clusters",
+ object_name="name",
+ group_id=module.params["group_id"],
+ data=data,
+ )
+ except Exception as e:
+ module.fail_json(
+ msg="unable to connect to Atlas API. Exception message: %s" % e
+ )
+
+ changed, diff = atlas.update(module.params["state"])
+ module.exit_json(
+ changed=changed,
+ data=atlas.data,
+ diff=diff,
+ )
+
+
+# import module snippets
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/mongodb/plugins/modules/mongodb_atlas_ldap_user.py b/ansible_collections/community/mongodb/plugins/modules/mongodb_atlas_ldap_user.py
new file mode 100644
index 000000000..e816a264c
--- /dev/null
+++ b/ansible_collections/community/mongodb/plugins/modules/mongodb_atlas_ldap_user.py
@@ -0,0 +1,165 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2020 T-Systems MMS
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+#
+# This module is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this software. If not, see <http://www.gnu.org/licenses/>.
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+DOCUMENTATION = '''
+---
+module: mongodb_atlas_ldap_user
+short_description: Manage LDAP users in Atlas
+description:
+ - The mongodb_atlas_ldap_user module lets you create LDAP groups on the admin database by mapping LDAP groups to MongoDB roles on your Atlas databases.
+ - Each user or group has a set of roles that provide access to the project's databases.
+ - L(API Documentation,https://docs.atlas.mongodb.com/security-ldaps/)
+author: "Martin Schurz (@schurzi) / Derek Giri"
+extends_documentation_fragment: community.mongodb.atlas_options
+options:
+ database_name:
+ description:
+ - Database against which Atlas authenticates the user.
+ choices: ["admin", "$external"]
+ default: "admin"
+ type: str
+ aliases: [ "databaseName" ]
+ ldap_auth_type:
+ description:
+ - Type of LDAP authorization for the user i.e. USER or GROUP
+ choices: ["GROUP", "USER"]
+ default: "GROUP"
+ type: str
+ aliases: [ "ldapAuthType" ]
+ username:
+ description:
+ - Username for authenticating to MongoDB.
+ required: true
+ type: str
+ roles:
+ description:
+ - Array of this user's roles and the databases / collections on which the roles apply.
+ - A role must include folliwing elements
+ suboptions:
+ database_name:
+ required: true
+ type: str
+ description:
+ - Database on which the user has the specified role.
+ - A role on the admin database can include privileges that apply to the other databases.
+ aliases: [ "databaseName" ]
+ role_name:
+ required: true
+ type: str
+ description:
+ - Name of the role. This value can either be a built-in role or a custom role.
+ aliases: ["roleName" ]
+ required: true
+ type: list
+ elements: dict
+'''
+
+EXAMPLES = '''
+ - name: LDAP Group or Username
+ community.mongodb.mongodb_atlas_ldap_user:
+ api_username: "API_user"
+ api_password: "API_passwort_or_token"
+ atlas_ldap_user: "USER DN or GROUP DN"
+ group_id: "GROUP_ID"
+ database_name: "admin"
+ username: my_app_user
+ roles:
+ - database_name: private_info
+ role_name: read
+ - database_name: public_info
+ role_name: readWrite
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.community.mongodb.plugins.module_utils.mongodb_atlas import (
+ AtlasAPIObject,
+)
+
+
+# ===========================================
+# Module execution.
+#
+def main():
+ # add our own arguments
+ argument_spec = dict(
+ state=dict(default="present", choices=["absent", "present"]),
+ api_username=dict(required=True, aliases=['apiUsername']),
+ api_password=dict(required=True, no_log=True, aliases=['apiPassword']),
+ group_id=dict(required=True, aliases=['groupId']),
+ ldap_auth_type=dict(default="GROUP", choices=["GROUP", "USER"], aliases=["ldapAuthType"]),
+ database_name=dict(default="admin", choices=["admin", "$external"], aliases=["databaseName"]),
+ username=dict(required=True),
+ roles=dict(
+ required=True,
+ type="list",
+ elements="dict",
+ options=dict(
+ database_name=dict(required=True, aliases=["databaseName"]),
+ role_name=dict(required=True, aliases=["roleName"]),
+ ),
+ ),
+ )
+
+ # Define the main module
+ module = AnsibleModule(
+ argument_spec=argument_spec, supports_check_mode=True
+ )
+
+ data = {
+ "databaseName": module.params["database_name"],
+ "ldapAuthType": module.params["ldap_auth_type"],
+ "username": module.params["username"],
+ "roles": [],
+ }
+
+ # remap keys to API format
+ for role in module.params.get("roles"):
+ data["roles"].append({
+ "databaseName": role.get("database_name"),
+ "roleName": role.get("role_name")
+ })
+
+ try:
+ atlas = AtlasAPIObject(
+ module=module,
+ path="/databaseUsers",
+ object_name="username",
+ group_id=module.params["group_id"],
+ data=data,
+ )
+ except Exception as e:
+ module.fail_json(
+ msg="unable to connect to Atlas API. Exception message: %s" % e
+ )
+
+ changed, diff = atlas.update(module.params["state"])
+ module.exit_json(
+ changed=changed,
+ data=atlas.data,
+ diff=diff,
+ )
+
+
+# import module snippets
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/mongodb/plugins/modules/mongodb_atlas_user.py b/ansible_collections/community/mongodb/plugins/modules/mongodb_atlas_user.py
new file mode 100644
index 000000000..ac8427b03
--- /dev/null
+++ b/ansible_collections/community/mongodb/plugins/modules/mongodb_atlas_user.py
@@ -0,0 +1,196 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2020 T-Systems MMS
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+#
+# This module is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this software. If not, see <http://www.gnu.org/licenses/>.
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+DOCUMENTATION = '''
+---
+module: mongodb_atlas_user
+short_description: Manage database users in Atlas
+description:
+ - The mongodb_atlas_user module lets you create, modify and delete the database users in your cluster.
+ - Each user has a set of roles that provide access to the project's databases.
+ - A user's roles apply to all the clusters in the project
+ - if two clusters have a products database and a user has a role granting read access on the products database,
+ - the user has that access on both clusters.
+ - L(API Documentation,https://docs.atlas.mongodb.com/reference/api/database-users/)
+author: "Martin Schurz (@schurzi)"
+extends_documentation_fragment: community.mongodb.atlas_options
+options:
+ database_name:
+ description:
+ - Database against which Atlas authenticates the user.
+ choices: ["admin", "$external"]
+ default: "admin"
+ type: str
+ aliases: [ "databaseName" ]
+ username:
+ description:
+ - Username for authenticating to MongoDB.
+ required: true
+ type: str
+ password:
+ description:
+ - User's password.
+ required: true
+ type: str
+ roles:
+ description:
+ - Array of this user's roles and the databases / collections on which the roles apply.
+ - A role must include following elements
+ suboptions:
+ database_name:
+ required: true
+ type: str
+ description:
+ - Database on which the user has the specified role.
+ - A role on the admin database can include privileges that apply to the other databases.
+ aliases: [ "databaseName" ]
+ role_name:
+ required: true
+ type: str
+ description:
+ - Name of the role. This value can either be a built-in role or a custom role.
+ aliases: [ "roleName" ]
+ required: true
+ type: list
+ elements: dict
+ scopes:
+ description:
+ - List of clusters and Atlas Data Lakes that this user can access.
+ - Atlas grants database users access to all resources by default.
+ suboptions:
+ name:
+ required: true
+ type: str
+ description:
+ - Name of the cluster or Atlas Data Lake that the database user can access.
+ type:
+ type: str
+ choices: ["CLUSTER", "DATA_LAKE"]
+ default: "CLUSTER"
+ description:
+ - Type of resource that the database user can access.
+ required: false
+ default: []
+ type: list
+ elements: dict
+'''
+
+EXAMPLES = '''
+ - name: test user
+ community.mongodb.mongodb_atlas_user:
+ api_username: "API_user"
+ api_password: "API_passwort_or_token"
+ group_id: "GROUP_ID"
+ username: my_app_user
+ password: SuperSecret!
+ roles:
+ - database_name: private_info
+ role_name: read
+ - database_name: public_info
+ role_name: readWrite
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.community.mongodb.plugins.module_utils.mongodb_atlas import (
+ AtlasAPIObject,
+)
+
+
+# ===========================================
+# Module execution.
+#
+def main():
+ # add our own arguments
+ argument_spec = dict(
+ state=dict(default="present", choices=["absent", "present"]),
+ api_username=dict(required=True, aliases=['apiUsername']),
+ api_password=dict(required=True, no_log=True, aliases=['apiPassword']),
+ group_id=dict(required=True, aliases=['groupId']),
+ database_name=dict(default="admin", choices=["admin", "$external"], aliases=["databaseName"]),
+ username=dict(required=True),
+ password=dict(required=True, no_log=True),
+ roles=dict(
+ required=True,
+ type="list",
+ elements="dict",
+ options=dict(
+ database_name=dict(required=True, aliases=["databaseName"]),
+ role_name=dict(required=True, aliases=["roleName"]),
+ ),
+ ),
+ scopes=dict(
+ required=False,
+ type="list",
+ elements="dict",
+ options=dict(
+ name=dict(required=True),
+ type=dict(default="CLUSTER", choices=["CLUSTER", "DATA_LAKE"]),
+ ),
+ default=[],
+ ),
+ )
+
+ # Define the main module
+ module = AnsibleModule(
+ argument_spec=argument_spec, supports_check_mode=True
+ )
+
+ data = {
+ "databaseName": module.params["database_name"],
+ "username": module.params["username"],
+ "password": module.params["password"],
+ "roles": [],
+ "scopes": module.params["scopes"],
+ }
+
+ # remap keys to API format
+ for role in module.params.get("roles"):
+ data["roles"].append({
+ "databaseName": role.get("database_name"),
+ "roleName": role.get("role_name")
+ })
+
+ try:
+ atlas = AtlasAPIObject(
+ module=module,
+ path="/databaseUsers",
+ object_name="username",
+ group_id=module.params["group_id"],
+ data=data,
+ )
+ except Exception as e:
+ module.fail_json(
+ msg="unable to connect to Atlas API. Exception message: %s" % e
+ )
+
+ changed, diff = atlas.update(module.params["state"])
+ module.exit_json(
+ changed=changed,
+ data=atlas.data,
+ diff=diff,
+ )
+
+
+# import module snippets
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/mongodb/plugins/modules/mongodb_atlas_whitelist.py b/ansible_collections/community/mongodb/plugins/modules/mongodb_atlas_whitelist.py
new file mode 100644
index 000000000..5354321a6
--- /dev/null
+++ b/ansible_collections/community/mongodb/plugins/modules/mongodb_atlas_whitelist.py
@@ -0,0 +1,111 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2020 T-Systems MMS
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+#
+# This module is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this software. If not, see <http://www.gnu.org/licenses/>.
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+DOCUMENTATION = '''
+---
+module: mongodb_atlas_whitelist
+short_description: Manage IP whitelists in Atlas
+description:
+ - The mongodb_atlas_whitelist module manages a Atlas project's IP whitelist.
+ - L(API Documentation,https://docs.atlas.mongodb.com/reference/api/whitelist/)
+author: "Martin Schurz (@schurzi)"
+extends_documentation_fragment: community.mongodb.atlas_options
+options:
+ cidr_block:
+ description:
+ - Whitelist entry in Classless Inter-Domain Routing (CIDR) notation.
+ type: str
+ required: True
+ aliases: [ "cidrBlock" ]
+ comment:
+ description:
+ - Optional Comment associated with the whitelist entry.
+ type: str
+ default: "created by Ansible"
+'''
+
+EXAMPLES = '''
+ - name: test whitelist
+ community.mongodb.mongodb_atlas_whitelist:
+ api_username: "API_user"
+ api_password: "API_passwort_or_token"
+ group_id: "GROUP_ID"
+ cidr_block: "192.168.0.0/24"
+ comment: "test"
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.community.mongodb.plugins.module_utils.mongodb_atlas import (
+ AtlasAPIObject,
+)
+
+
+# ===========================================
+# Module execution.
+#
+def main():
+ # add our own arguments
+ argument_spec = dict(
+ state=dict(default="present", choices=["absent", "present"]),
+ api_username=dict(required=True, aliases=['apiUsername']),
+ api_password=dict(required=True, no_log=True, aliases=['apiPassword']),
+ group_id=dict(required=True, aliases=['groupId']),
+ cidr_block=dict(required=True, aliases=["cidrBlock"]),
+ comment=dict(default="created by Ansible"),
+ )
+
+ # Define the main module
+ module = AnsibleModule(
+ argument_spec=argument_spec, supports_check_mode=True
+ )
+
+ data = {
+ "cidrBlock": module.params["cidr_block"],
+ "comment": module.params["comment"],
+ }
+
+ try:
+ atlas = AtlasAPIObject(
+ module=module,
+ path="/whitelist",
+ object_name="cidrBlock",
+ group_id=module.params["group_id"],
+ data=data,
+ data_is_array=True,
+ )
+ except Exception as e:
+ module.fail_json(
+ msg="unable to connect to Atlas API. Exception message: %s" % e
+ )
+
+ changed, diff = atlas.update(module.params["state"])
+ module.exit_json(
+ changed=changed,
+ data=atlas.data,
+ diff=diff,
+ )
+
+
+# import module snippets
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/mongodb/plugins/modules/mongodb_balancer.py b/ansible_collections/community/mongodb/plugins/modules/mongodb_balancer.py
index 0e9b33a34..77ce37ed0 100644
--- a/ansible_collections/community/mongodb/plugins/modules/mongodb_balancer.py
+++ b/ansible_collections/community/mongodb/plugins/modules/mongodb_balancer.py
@@ -29,6 +29,8 @@ options:
autosplit:
description:
- Disable or enable the autosplit flag in the config.settings collection.
+ - From MongoDB 6.1 automatic chunk splitting is not performed so this parameter is not valid in this and later versions. See more see [enableAutoSplit](https://www.mongodb.com/docs/manual/reference/method/sh.enableAutoSplit/). # noqa: E501
+ - This parameter is deprecated and will be removed in a future release.
required: false
type: bool
chunksize:
diff --git a/ansible_collections/community/mongodb/plugins/modules/mongodb_monitoring.py b/ansible_collections/community/mongodb/plugins/modules/mongodb_monitoring.py
deleted file mode 100644
index d399a9907..000000000
--- a/ansible_collections/community/mongodb/plugins/modules/mongodb_monitoring.py
+++ /dev/null
@@ -1,197 +0,0 @@
-#!/usr/bin/python
-
-# Copyright: (c) 2021, Rhys Campbell rhyscampbell@blueiwn.ch
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
----
-module: mongodb_monitoring
-short_description: Manages the free monitoring feature.
-description:
- - Manages the free monitoring feature.
- - Optionally return the monitoring url.
-author: Rhys Campbell (@rhysmeister)
-version_added: "1.3.0"
-
-extends_documentation_fragment:
- - community.mongodb.login_options
- - community.mongodb.ssl_options
-
-options:
- state:
- description: Manage the free monitoring feature.
- type: str
- choices:
- - "started"
- - "stopped"
- default: "started"
- return_url:
- description: When true return the monitoring url if available.
- type: bool
- default: false
-
-notes:
-- Requires the pymongo Python package on the remote host, version 2.4.2+. This
- can be installed using pip or the OS package manager. @see U(http://api.mongodb.org/python/current/installation.html)
-requirements:
- - pymongo
-'''
-
-EXAMPLES = r'''
-- name: Enable monitoring
- community.mongodb.mongodb_monitoring:
- state: "started"
-
-- name: Disable monitoring
- community.mongodb.mongodb_monitoring:
- state: "stopped"
-
-- name: Enable monitoring and return the monitoring url
- community.mongodb_monitoring:
- state: "started"
- return_url: "yes"
-'''
-
-RETURN = r'''
-changed:
- description: Whether the monitoring status changed.
- returned: success
- type: bool
-msg:
- description: A short description of what happened.
- returned: success
- type: str
-failed:
- description: If something went wrong
- returned: failed
- type: bool
-url:
- description: The MongoDB instance Monitoring url.
- returned: When requested and available.
- type: str
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-from ansible_collections.community.mongodb.plugins.module_utils.mongodb_common import (
- missing_required_lib,
- mongodb_common_argument_spec,
- PYMONGO_IMP_ERR,
- pymongo_found,
- mongo_auth,
- get_mongodb_client,
-)
-
-has_ordereddict = False
-try:
- from collections import OrderedDict
- has_ordereddict = True
-except ImportError as excep:
- try:
- from ordereddict import OrderedDict
- has_ordereddict = True
- except ImportError as excep:
- pass
-
-
-def stop_monitoring(client):
- '''
- Stops MongoDB Free Monitoring
- '''
- cmd_doc = OrderedDict([('setFreeMonitoring', 1),
- ('action', 'disable')])
- client['admin'].command(cmd_doc)
-
-
-def start_monitoring(client):
- '''
- Stops MongoDB Free Monitoring
- '''
- cmd_doc = OrderedDict([('setFreeMonitoring', 1),
- ('action', 'enable')])
- client['admin'].command(cmd_doc)
-
-
-def get_monitoring_status(client):
- '''
- Gets the state of MongoDB Monitoring.
- N.B. If Monitoring has never been enabled the
- free_monitoring record in admin.system.version
- will not yet exist.
- '''
- monitoring_state = None
- url = None
- result = client["admin"]['system.version'].find_one({"_id": "free_monitoring"})
- if not result:
- monitoring_state = "stopped"
- else:
- url = result["informationalURL"]
- if result["state"] == "enabled":
- monitoring_state = "started"
- else:
- monitoring_state = "stopped"
- return monitoring_state, url
-
-
-def main():
- argument_spec = mongodb_common_argument_spec()
- argument_spec.update(
- state=dict(type='str', default='started', choices=['started', 'stopped']),
- return_url=dict(type='bool', default=False)
- )
-
- module = AnsibleModule(
- argument_spec=argument_spec,
- supports_check_mode=True,
- required_together=[['login_user', 'login_password']],
- )
-
- if not has_ordereddict:
- module.fail_json(msg='Cannot import OrderedDict class. You can probably install with: pip install ordereddict')
-
- if not pymongo_found:
- module.fail_json(msg=missing_required_lib('pymongo'),
- exception=PYMONGO_IMP_ERR)
-
- state = module.params['state']
- return_url = module.params['return_url']
-
- try:
- client = get_mongodb_client(module, directConnection=True)
- client = mongo_auth(module, client, directConnection=True)
- except Exception as e:
- module.fail_json(msg='Unable to connect to database: %s' % to_native(e))
-
- current_monitoring_state, url = get_monitoring_status(client)
- result = {}
- if state == "started":
- if current_monitoring_state == "started":
- result['changed'] = False
- result['msg'] = "Free monitoring is already started"
- else:
- if module.check_mode is False:
- start_monitoring(client)
- result['changed'] = True
- result['msg'] = "Free monitoring has been started"
- else:
- if current_monitoring_state == "started":
- if module.check_mode is False:
- stop_monitoring(client)
- result['changed'] = True
- result['msg'] = "Free monitoring has been stopped"
- else:
- result['changed'] = False
- result['msg'] = "Free monitoring is already stopped"
-
- if return_url and url:
- result['url'] = url
-
- module.exit_json(**result)
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/mongodb/plugins/modules/mongodb_replicaset.py b/ansible_collections/community/mongodb/plugins/modules/mongodb_replicaset.py
index d0baf661e..d6cdaae26 100644
--- a/ansible_collections/community/mongodb/plugins/modules/mongodb_replicaset.py
+++ b/ansible_collections/community/mongodb/plugins/modules/mongodb_replicaset.py
@@ -554,8 +554,11 @@ def main():
debug = module.params['debug']
cluster_cmd = module.params['cluster_cmd']
+ # Count voting members
+ voting_members = sum([1 if not isinstance(m, dict) or m.get("votes", 1) == 1 else 0 for m in members])
+
if validate and reconfigure is False:
- if len(members) <= 2 or len(members) % 2 == 0:
+ if len(members) <= 2 or voting_members % 2 == 0:
module.fail_json(msg="MongoDB Replicaset validation failed. Invalid number of replicaset members.")
if arbiter_at_index is not None and len(members) - 1 < arbiter_at_index:
module.fail_json(msg="MongoDB Replicaset validation failed. Invalid arbiter index.")
diff --git a/ansible_collections/community/mongodb/plugins/modules/mongodb_role.py b/ansible_collections/community/mongodb/plugins/modules/mongodb_role.py
index 012f553a0..23f653c32 100644
--- a/ansible_collections/community/mongodb/plugins/modules/mongodb_role.py
+++ b/ansible_collections/community/mongodb/plugins/modules/mongodb_role.py
@@ -303,8 +303,8 @@ def check_if_role_changed(client, role, db_name, privileges, authenticationRestr
'roles' not in role_dict and roles != []):
changed = True
elif ('authenticationRestrictions' in role_dict and
- sorted(reformat_authenticationRestrictions, key=lambda x: (x['clientSource'], x['serverAddress'])) !=
- sorted(authenticationRestrictions, key=lambda x: (x['clientSource'], x['serverAddress'])) or
+ sorted(reformat_authenticationRestrictions, key=lambda x: (x.get('clientSource', ''), x.get('serverAddress', ''))) !=
+ sorted(authenticationRestrictions, key=lambda x: (x.get('clientSource', ''), x.get('serverAddress', ''))) or
'authenticationRestrictions' not in role_dict and authenticationRestrictions != []):
changed = True
else:
diff --git a/ansible_collections/community/mongodb/plugins/modules/mongodb_user.py b/ansible_collections/community/mongodb/plugins/modules/mongodb_user.py
index eab0d186c..fee4c48c1 100644
--- a/ansible_collections/community/mongodb/plugins/modules/mongodb_user.py
+++ b/ansible_collections/community/mongodb/plugins/modules/mongodb_user.py
@@ -189,7 +189,6 @@ user:
import os
import traceback
-from operator import itemgetter
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
@@ -307,7 +306,7 @@ def check_if_roles_changed(uinfo, roles, db_name):
roles_as_list_of_dict = make_sure_roles_are_a_list_of_dict(roles, db_name)
uinfo_roles = uinfo.get('roles', [])
- if sorted(roles_as_list_of_dict, key=itemgetter('db')) == sorted(uinfo_roles, key=itemgetter('db')):
+ if sorted(roles_as_list_of_dict, key=lambda roles: sorted(roles.items())) == sorted(uinfo_roles, key=lambda roles: sorted(roles.items())):
return False
return True
diff --git a/ansible_collections/community/mongodb/roles/mongodb_auth/defaults/main.yml b/ansible_collections/community/mongodb/roles/mongodb_auth/defaults/main.yml
index c34225a2a..59049bde2 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_auth/defaults/main.yml
+++ b/ansible_collections/community/mongodb/roles/mongodb_auth/defaults/main.yml
@@ -26,3 +26,5 @@ mongodb_users: []
# Setting this to yes will result in 'changed' on every run, even if the password is the same.
# See the comment in tasks/main.yml for more details.
mongodb_force_update_password: no
+
+mongodb_use_tls: false \ No newline at end of file
diff --git a/ansible_collections/community/mongodb/roles/mongodb_auth/molecule/default/molecule.yml b/ansible_collections/community/mongodb/roles/mongodb_auth/molecule/default/molecule.yml
index 8b614fb6a..dfb11aac4 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_auth/molecule/default/molecule.yml
+++ b/ansible_collections/community/mongodb/roles/mongodb_auth/molecule/default/molecule.yml
@@ -15,8 +15,8 @@ platforms:
privileged: True
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup:ro
- - name: ubuntu_18
- image: ubuntu:18.04
+ - name: ubuntu_22_04
+ image: ubuntu:22.04
command: /sbin/init
privileged: True
- name: ubuntu_22
diff --git a/ansible_collections/community/mongodb/roles/mongodb_auth/molecule/default/playbook.yml b/ansible_collections/community/mongodb/roles/mongodb_auth/molecule/default/playbook.yml
index 46c4e8e2e..efbb70469 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_auth/molecule/default/playbook.yml
+++ b/ansible_collections/community/mongodb/roles/mongodb_auth/molecule/default/playbook.yml
@@ -9,7 +9,7 @@
# initially disable authorization on some hosts
hosts_with_auth_disabled:
- - ubuntu_18
+ - ubuntu_22_04
- ubuntu_22
# add some users for some of the hosts
@@ -52,6 +52,17 @@
include_role:
name: mongodb_auth
+ - name: Determine openssl version
+ command: openssl version
+ changed_when: false
+ register: openssl
+
+ - name: Set mongosh package version
+ set_fact:
+ mongosh_package: "{{ 'mongodb-mongosh-shared-openssl3' if openssl.stdout.startswith('OpenSSL 3') else 'mongodb-mongosh-shared-openssl11' }}"
+ when: mongosh_package is not defined
+
- name: Install MongoDB Shell
package:
- name: mongodb-mongosh
+ name:
+ - "{{ mongosh_package }}"
diff --git a/ansible_collections/community/mongodb/roles/mongodb_auth/tasks/main.yml b/ansible_collections/community/mongodb/roles/mongodb_auth/tasks/main.yml
index d3775a1b7..eff6e4f31 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_auth/tasks/main.yml
+++ b/ansible_collections/community/mongodb/roles/mongodb_auth/tasks/main.yml
@@ -94,6 +94,8 @@
database: admin
roles: "{{ mongodb_admin_roles }}"
+ ssl: "{{ mongodb_use_tls }}"
+ ssl_ca_certs: "{{ mongodb_certificate_ca_file if mongodb_use_tls else omit }}"
login_host: localhost
login_port: "{{ mongod_port | string }}" # silence implicit int->str conversion warning
create_for_localhost_exception: /root/mongodb_admin.success
diff --git a/ansible_collections/community/mongodb/roles/mongodb_auth/tasks/mongodb_auth_user.yml b/ansible_collections/community/mongodb/roles/mongodb_auth/tasks/mongodb_auth_user.yml
index e21dec073..5c0c930ba 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_auth/tasks/mongodb_auth_user.yml
+++ b/ansible_collections/community/mongodb/roles/mongodb_auth/tasks/mongodb_auth_user.yml
@@ -18,6 +18,8 @@
database: "{{ _mongodb_user.db }}"
roles: "{{ _mongodb_user.roles|default('readWrite') }}"
+ ssl: "{{ mongodb_use_tls }}"
+ ssl_ca_certs: "{{ mongodb_certificate_ca_file if mongodb_use_tls else omit }}"
login_host: localhost
login_port: "{{ mongod_port | string }}" # silence implicit int->str conversion warning
login_user: "{{ mongodb_admin_user }}"
diff --git a/ansible_collections/community/mongodb/roles/mongodb_config/README.md b/ansible_collections/community/mongodb/roles/mongodb_config/README.md
index 4ab33efcb..b5cd560a5 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_config/README.md
+++ b/ansible_collections/community/mongodb/roles/mongodb_config/README.md
@@ -6,25 +6,27 @@ A simple role to aid in setting up a CSRS Config Server Replicaset for a MongoDB
Role Variables
--------------
-* `config_port`: The port used by the mongos process. Default 27019.
-* `mongod_service`: The name of the mongod service. Default mongod.
-* `mongodb_user`: The Linux OS user for MongoDB. Default mongod.
-* `mongodb_group`: The Linux OS user group for MongoDB. Default mongod.
-* `pid_file`: The pid file for mongos. Default /run/mongodb/mongos.pid.
-* `log_path`: Path of the log file. Default /var/log/mongodb/mongod.log.
-* `bind_ip`: The IP address mongod will bind to. Default 0.0.0.0.
-* `bind_ip_all`: Have mongod bind to all IP addresses instead of specifying `bind_ip`. Default false.
-* `config_repl_set_name`: The replicaset name for the config servers. Default cfg.
-* `authorization`: Enable authorization. Default enabled.
+* `config_port`: The port used by the mongos process. Default `27019`.
+* `mongod_service`: The name of the mongod service. Default `mongod`.
+* `mongodb_user`: The Linux OS user for MongoDB. Default `mongod`.
+* `mongodb_group`: The Linux OS user group for MongoDB. Default `mongod`.
+* `pid_file`: The pid file for mongos. Default `/run/mongodb/mongos.pid`.
+* `log_path`: Path of the log file. Default `/var/log/mongodb/mongod.log`.
+* `bind_ip`: The IP address mongod will bind to. Default `0.0.0.0`.
+* `bind_ip_all`: Have mongod bind to all IP addresses instead of specifying `bind_ip`. Default `false`.
+* `config_repl_set_name`: The replicaset name for the config servers. Default `cfg`.
+* `authorization`: Enable authorization. Default `enabled`.
* `openssl_keyfile_content`: The kexfile content that MongoDB uses to authenticate within a replicaset. Generate with cmd: openssl rand -base64 756.
-* `openssl_keyfile_path`: Put the openssl_keyfile at this path. Default: /etc/keyfile
-* `mongod_package`: The name of the mongod installation package. Default mongodb-org-server.
-replicaset: When enabled add a replication section to the configuration. Default true.
+* `openssl_keyfile_path`: Put the openssl_keyfile at this path. Default: `/etc/keyfile`.
+* `mongod_package`: The name of the mongod installation package. Default `mongodb-org-server`.
+replicaset: When enabled add a replication section to the configuration. Default `true`.
* `net_compressors`: If this is set, this sets `net.compression.compressors` in mongod.conf.
-* `mongod_config_template`: If defined allows to override path to mongod config template with custom configuration. Default "mongod.conf.j2"
+* `mongod_config_template`: If defined allows to override path to mongod config template with custom configuration. Default `mongod.conf.j2`.
* `skip_restart`: If set to `true` will skip restarting mongod service when config file or the keyfile content changes. Default `true`.
* `db_path`: Path to database data location. Default `/var/lib/mongodb` on Debian based distributions, `/var/lib/mongo` for others.
-* `mongodb_use_tls`: Wether to use tls. Default false.
+* `mongodb_use_tls`: Whether to use tls. Default `false`.
+* `mongodb_disabled_tls_protocols`: The tls protocols to be disabled. Leave blank to let MongoDB decide which protocols to allow according to the ones available on the system; check the [official docs](https://www.mongodb.com/docs/v6.0/reference/configuration-options/#mongodb-setting-net.tls.disabledProtocols) for details. Default "".
+* `mongodb_allow_connections_without_certificates`: When enabled allows to bypass the certificate validation for clients that do not present a certificate, if a certificate is provided it _must_ be valid. Default `false`.
* `mongodb_certificate_key_file`: Path to the PEM-file containing the certficate and private key.
* `mongodb_certificate_ca_file`: Path to the CA-file.
diff --git a/ansible_collections/community/mongodb/roles/mongodb_config/defaults/main.yml b/ansible_collections/community/mongodb/roles/mongodb_config/defaults/main.yml
index 0460a8bd6..916d06725 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_config/defaults/main.yml
+++ b/ansible_collections/community/mongodb/roles/mongodb_config/defaults/main.yml
@@ -32,3 +32,5 @@ mongod_config_template: "configsrv.conf.j2"
skip_restart: true
db_path: "{{ '/var/lib/mongodb' if ansible_os_family == 'Debian' else '/var/lib/mongo' if ansible_os_family == 'RedHat' else '/var/lib/mongo' }}"
mongodb_use_tls: false
+mongodb_disabled_tls_protocols: ""
+mongodb_allow_connections_without_certificates: false
diff --git a/ansible_collections/community/mongodb/roles/mongodb_config/molecule/custom_db_path/molecule.yml b/ansible_collections/community/mongodb/roles/mongodb_config/molecule/custom_db_path/molecule.yml
index 3dc8132e1..e9d686e54 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_config/molecule/custom_db_path/molecule.yml
+++ b/ansible_collections/community/mongodb/roles/mongodb_config/molecule/custom_db_path/molecule.yml
@@ -19,9 +19,9 @@ platforms:
networks:
- name: "mymongo"
network_mode: "mymongo"
- - name: ubuntu_18
- hostname: ubuntu_18
- image: ubuntu:18.04
+ - name: ubuntu_22_04
+ hostname: ubuntu_22_04
+ image: ubuntu:22.04
command: /sbin/init
privileged: True
networks:
diff --git a/ansible_collections/community/mongodb/roles/mongodb_config/molecule/custom_db_path/playbook.yml b/ansible_collections/community/mongodb/roles/mongodb_config/molecule/custom_db_path/playbook.yml
index eceb73444..bf89e498d 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_config/molecule/custom_db_path/playbook.yml
+++ b/ansible_collections/community/mongodb/roles/mongodb_config/molecule/custom_db_path/playbook.yml
@@ -15,9 +15,20 @@
name: "{{ 'pymongo==3.12.*' if ansible_python_version[0:3] | float < 3.6 else 'pymongo' }}"
when: ansible_hostname == "fedora"
+ - name: Determine openssl version
+ command: openssl version
+ changed_when: false
+ register: openssl
+
+ - name: Set mongosh package version
+ set_fact:
+ mongosh_package: "{{ 'mongodb-mongosh-shared-openssl3' if openssl.stdout.startswith('OpenSSL 3') else 'mongodb-mongosh-shared-openssl11' }}"
+ when: mongosh_package is not defined
+
- name: Install MongoDB Shell
package:
- name: mongodb-mongosh
+ name:
+ - "{{ mongosh_package }}"
- name: Init config server replicaset
community.mongodb.mongodb_replicaset:
@@ -28,7 +39,7 @@
members:
- almalinux_8:27019
- fedora:27019
- - ubuntu_18:27019
+ - ubuntu_22_04:27019
- debian_bullseye:27019
- ubuntu_22:27019
when: ansible_hostname == "fedora"
diff --git a/ansible_collections/community/mongodb/roles/mongodb_config/molecule/custom_db_path/tests/test_default.py b/ansible_collections/community/mongodb/roles/mongodb_config/molecule/custom_db_path/tests/test_default.py
index 99a541fd1..823197ea5 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_config/molecule/custom_db_path/tests/test_default.py
+++ b/ansible_collections/community/mongodb/roles/mongodb_config/molecule/custom_db_path/tests/test_default.py
@@ -60,7 +60,7 @@ def test_mongod_replicaset(host):
assert "cfg" in r.stdout
assert "almalinux_8:{0}".format(port) in r.stdout
assert "fedora:{0}".format(port) in r.stdout
- assert "ubuntu_18:{0}".format(port) in r.stdout
+ assert "ubuntu_22_04:{0}".format(port) in r.stdout
assert "ubuntu_22:{0}".format(port) in r.stdout
assert "debian_bullseye:{0}".format(port) in r.stdout
diff --git a/ansible_collections/community/mongodb/roles/mongodb_config/molecule/default/molecule.yml b/ansible_collections/community/mongodb/roles/mongodb_config/molecule/default/molecule.yml
index 3dc8132e1..e9d686e54 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_config/molecule/default/molecule.yml
+++ b/ansible_collections/community/mongodb/roles/mongodb_config/molecule/default/molecule.yml
@@ -19,9 +19,9 @@ platforms:
networks:
- name: "mymongo"
network_mode: "mymongo"
- - name: ubuntu_18
- hostname: ubuntu_18
- image: ubuntu:18.04
+ - name: ubuntu_22_04
+ hostname: ubuntu_22_04
+ image: ubuntu:22.04
command: /sbin/init
privileged: True
networks:
diff --git a/ansible_collections/community/mongodb/roles/mongodb_config/molecule/default/playbook.yml b/ansible_collections/community/mongodb/roles/mongodb_config/molecule/default/playbook.yml
index 42c89bad2..4f9d6ce29 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_config/molecule/default/playbook.yml
+++ b/ansible_collections/community/mongodb/roles/mongodb_config/molecule/default/playbook.yml
@@ -13,9 +13,20 @@
name: "{{ 'pymongo==3.12.*' if ansible_python_version[0:3] | float < 3.6 else 'pymongo' }}"
when: ansible_hostname == "fedora"
+ - name: Determine openssl version
+ command: openssl version
+ changed_when: false
+ register: openssl
+
+ - name: Set mongosh package version
+ set_fact:
+ mongosh_package: "{{ 'mongodb-mongosh-shared-openssl3' if openssl.stdout.startswith('OpenSSL 3') else 'mongodb-mongosh-shared-openssl11' }}"
+ when: mongosh_package is not defined
+
- name: Install MongoDB Shell
package:
- name: mongodb-mongosh
+ name:
+ - "{{ mongosh_package }}"
- name: Init config server replicaset
community.mongodb.mongodb_replicaset:
@@ -26,7 +37,7 @@
members:
- almalinux_8:27019
- fedora:27019
- - ubuntu_18:27019
+ - ubuntu_22_04:27019
- debian_bullseye:27019
- ubuntu_22:27019
when: ansible_hostname == "fedora"
diff --git a/ansible_collections/community/mongodb/roles/mongodb_config/molecule/default/tests/test_default.py b/ansible_collections/community/mongodb/roles/mongodb_config/molecule/default/tests/test_default.py
index fe7aecf16..89b86c207 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_config/molecule/default/tests/test_default.py
+++ b/ansible_collections/community/mongodb/roles/mongodb_config/molecule/default/tests/test_default.py
@@ -60,7 +60,7 @@ def test_mongod_replicaset(host):
assert "cfg" in r.stdout
assert "almalinux_8:{0}".format(port) in r.stdout
assert "fedora:{0}".format(port) in r.stdout
- assert "ubuntu_18:{0}".format(port) in r.stdout
+ assert "ubuntu_22_04:{0}".format(port) in r.stdout
assert "ubuntu_22:{0}".format(port) in r.stdout
assert "debian_bullseye:{0}".format(port) in r.stdout
diff --git a/ansible_collections/community/mongodb/roles/mongodb_config/templates/configsrv.conf.j2 b/ansible_collections/community/mongodb/roles/mongodb_config/templates/configsrv.conf.j2
index afb06f641..192b3cbae 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_config/templates/configsrv.conf.j2
+++ b/ansible_collections/community/mongodb/roles/mongodb_config/templates/configsrv.conf.j2
@@ -41,6 +41,12 @@ net:
mode: requireTLS
certificateKeyFile: {{ mongodb_certificate_key_file }}
CAFile: {{ mongodb_certificate_ca_file }}
+{% if mongodb_disabled_tls_protocols != "" %}
+ disabledProtocols: {{ mongodb_disabled_tls_protocols }}
+{% endif %}
+{% if mongodb_allow_connections_without_certificates %}
+ allowConnectionsWithoutCertificates: true
+{% endif %}
{% endif %}
{% if authorization == "enabled" %}
diff --git a/ansible_collections/community/mongodb/roles/mongodb_install/files/lock_mongodb_packages.sh b/ansible_collections/community/mongodb/roles/mongodb_install/files/lock_mongodb_packages.sh
index 0c3e8e6f5..bbfff55c8 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_install/files/lock_mongodb_packages.sh
+++ b/ansible_collections/community/mongodb/roles/mongodb_install/files/lock_mongodb_packages.sh
@@ -8,13 +8,19 @@ HOLD="$1";
PACKAGE_NAME="mongodb-org*"
if [[ "$HOLD" == "HOLD" ]]; then
- if command -v yum &> /dev/null; then
+ if command -v dnf &> /dev/null; then
+ dnf install "dnf-command(versionlock)"
+ dnf versionlock "$PACKAGE_NAME" && touch /root/mongo_version_lock.success;
+ elif command -v yum &> /dev/null; then
yum versionlock "$PACKAGE_NAME" && touch /root/mongo_version_lock.success;
elif command -v apt-mark &> /dev/null; then
apt-mark hold "$PACKAGE_NAME" && touch /root/mongo_version_lock.success;
fi;
elif [[ "$HOLD" == "NOHOLD" ]]; then
- if command -v yum &> /dev/null; then
+ if command -v dnf &> /dev/null; then
+ dnf install "dnf-command(versionlock)"
+ dnf versionlock delete "$PACKAGE_NAME" || true && rm -rf /root/mongo_version_lock.success;
+ elif command -v yum &> /dev/null; then
yum versionlock delete "$PACKAGE_NAME" || true && rm -rf /root/mongo_version_lock.success;
elif command -v apt-mark &> /dev/null; then
apt-mark unhold "$PACKAGE_NAME" && rm -rf /root/mongo_version_lock.success;
diff --git a/ansible_collections/community/mongodb/roles/mongodb_install/molecule/default/molecule.yml b/ansible_collections/community/mongodb/roles/mongodb_install/molecule/default/molecule.yml
index 5258056e7..aab979c46 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_install/molecule/default/molecule.yml
+++ b/ansible_collections/community/mongodb/roles/mongodb_install/molecule/default/molecule.yml
@@ -11,8 +11,8 @@ lint:
platforms:
- name: almalinux_8
image: almalinux:8
- - name: ubuntu_18
- image: ubuntu:18.04
+ - name: ubuntu_22_04
+ image: ubuntu:22.04
privileged: yes
command: "/sbin/init"
- name: ubuntu_22
diff --git a/ansible_collections/community/mongodb/roles/mongodb_install/molecule/default/prepare.yml b/ansible_collections/community/mongodb/roles/mongodb_install/molecule/default/prepare.yml
new file mode 100644
index 000000000..1eec53a5c
--- /dev/null
+++ b/ansible_collections/community/mongodb/roles/mongodb_install/molecule/default/prepare.yml
@@ -0,0 +1,10 @@
+---
+- name: Prepare
+ hosts: all
+ become: yes
+
+ tasks:
+
+ - name: Install openssl
+ package:
+ name: "openssl" \ No newline at end of file
diff --git a/ansible_collections/community/mongodb/roles/mongodb_install/molecule/mongodb_hold_packages/molecule.yml b/ansible_collections/community/mongodb/roles/mongodb_install/molecule/mongodb_hold_packages/molecule.yml
index 4266ee65b..2767eee61 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_install/molecule/mongodb_hold_packages/molecule.yml
+++ b/ansible_collections/community/mongodb/roles/mongodb_install/molecule/mongodb_hold_packages/molecule.yml
@@ -13,8 +13,8 @@ platforms:
image: almalinux:8
- name: fedora
image: fedora:37
- - name: ubuntu_18
- image: ubuntu:18.04
+ - name: ubuntu_22_04
+ image: ubuntu:22.04
- name: ubuntu_22
image: ubuntu:22.04
- name: debian_bullseye
diff --git a/ansible_collections/community/mongodb/roles/mongodb_install/molecule/mongodb_hold_packages/prepare.yml b/ansible_collections/community/mongodb/roles/mongodb_install/molecule/mongodb_hold_packages/prepare.yml
index 8a94ca7eb..bcc16f3f1 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_install/molecule/mongodb_hold_packages/prepare.yml
+++ b/ansible_collections/community/mongodb/roles/mongodb_install/molecule/mongodb_hold_packages/prepare.yml
@@ -10,3 +10,7 @@
name: yum-plugin-versionlock
state: present
when: ansible_facts.os_family == "RedHat"
+
+ - name: Install openssl
+ package:
+ name: "openssl" \ No newline at end of file
diff --git a/ansible_collections/community/mongodb/roles/mongodb_install/molecule/mongodb_hold_packages/tests/test_default.py b/ansible_collections/community/mongodb/roles/mongodb_install/molecule/mongodb_hold_packages/tests/test_default.py
index 381a5823a..72893a0aa 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_install/molecule/mongodb_hold_packages/tests/test_default.py
+++ b/ansible_collections/community/mongodb/roles/mongodb_install/molecule/mongodb_hold_packages/tests/test_default.py
@@ -17,8 +17,6 @@ def test_mongodb_packages_not_installed(host):
assert p.is_installed
p = host.package("mongodb-org-server")
assert p.is_installed
- p = host.package("mongodb-mongosh")
- assert p.is_installed
p = host.package("mongodb-org-mongos")
assert p.is_installed
p = host.package("mongodb-org-tools")
diff --git a/ansible_collections/community/mongodb/roles/mongodb_install/molecule/mongodb_nohold_packages/molecule.yml b/ansible_collections/community/mongodb/roles/mongodb_install/molecule/mongodb_nohold_packages/molecule.yml
index 4266ee65b..2767eee61 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_install/molecule/mongodb_nohold_packages/molecule.yml
+++ b/ansible_collections/community/mongodb/roles/mongodb_install/molecule/mongodb_nohold_packages/molecule.yml
@@ -13,8 +13,8 @@ platforms:
image: almalinux:8
- name: fedora
image: fedora:37
- - name: ubuntu_18
- image: ubuntu:18.04
+ - name: ubuntu_22_04
+ image: ubuntu:22.04
- name: ubuntu_22
image: ubuntu:22.04
- name: debian_bullseye
diff --git a/ansible_collections/community/mongodb/roles/mongodb_install/molecule/mongodb_nohold_packages/prepare.yml b/ansible_collections/community/mongodb/roles/mongodb_install/molecule/mongodb_nohold_packages/prepare.yml
index 325651e03..bcc16f3f1 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_install/molecule/mongodb_nohold_packages/prepare.yml
+++ b/ansible_collections/community/mongodb/roles/mongodb_install/molecule/mongodb_nohold_packages/prepare.yml
@@ -9,4 +9,8 @@
yum:
name: yum-plugin-versionlock
state: present
- when: ansible_facts.os_family == "RedHat" \ No newline at end of file
+ when: ansible_facts.os_family == "RedHat"
+
+ - name: Install openssl
+ package:
+ name: "openssl" \ No newline at end of file
diff --git a/ansible_collections/community/mongodb/roles/mongodb_install/molecule/mongodb_nohold_packages/tests/test_default.py b/ansible_collections/community/mongodb/roles/mongodb_install/molecule/mongodb_nohold_packages/tests/test_default.py
index cd1fc5f79..2fc340c43 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_install/molecule/mongodb_nohold_packages/tests/test_default.py
+++ b/ansible_collections/community/mongodb/roles/mongodb_install/molecule/mongodb_nohold_packages/tests/test_default.py
@@ -17,8 +17,6 @@ def test_mongodb_packages_installed(host):
assert p.is_installed
p = host.package("mongodb-org-server")
assert p.is_installed
- p = host.package("mongodb-mongosh")
- assert p.is_installed
p = host.package("mongodb-org-mongos")
assert p.is_installed
p = host.package("mongodb-org-tools")
diff --git a/ansible_collections/community/mongodb/roles/mongodb_install/molecule/specific_mongodb_version/molecule.yml b/ansible_collections/community/mongodb/roles/mongodb_install/molecule/specific_mongodb_version/molecule.yml
index 3fdeb9123..6ee9a3814 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_install/molecule/specific_mongodb_version/molecule.yml
+++ b/ansible_collections/community/mongodb/roles/mongodb_install/molecule/specific_mongodb_version/molecule.yml
@@ -9,14 +9,14 @@ lint:
config-data:
line-length: disable
platforms:
- #- name: almalinux_8
- # image: almalinux:8 yum seems broken for wildcard/version install for AL8
+ - name: almalinux_8
+ image: almalinux:8
#- name: fedora
# image: fedora:37 ditto
- - name: centos7
- image: centos:7 # Just here while the above two are broken
- - name: ubuntu_18
- image: ubuntu:18.04
+ #- name: centos7
+ # image: centos:7 # Just here while the above two are broken
+ - name: ubuntu_22_04
+ image: ubuntu:22.04
- name: ubuntu_22
image: ubuntu:22.04
- name: debian_bullseye
diff --git a/ansible_collections/community/mongodb/roles/mongodb_install/molecule/specific_mongodb_version/prepare.yml b/ansible_collections/community/mongodb/roles/mongodb_install/molecule/specific_mongodb_version/prepare.yml
new file mode 100644
index 000000000..1eec53a5c
--- /dev/null
+++ b/ansible_collections/community/mongodb/roles/mongodb_install/molecule/specific_mongodb_version/prepare.yml
@@ -0,0 +1,10 @@
+---
+- name: Prepare
+ hosts: all
+ become: yes
+
+ tasks:
+
+ - name: Install openssl
+ package:
+ name: "openssl" \ No newline at end of file
diff --git a/ansible_collections/community/mongodb/roles/mongodb_install/tasks/main.yml b/ansible_collections/community/mongodb/roles/mongodb_install/tasks/main.yml
index d43174fd3..02b71f82d 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_install/tasks/main.yml
+++ b/ansible_collections/community/mongodb/roles/mongodb_install/tasks/main.yml
@@ -1,8 +1,23 @@
---
+- name: Determine openssl version
+ command: openssl version
+ changed_when: false
+ register: openssl
+
+- name: Set mongosh package version
+ set_fact:
+ mongosh_package: "{{ 'mongodb-mongosh-shared-openssl3' if openssl.stdout.startswith('OpenSSL 3') else 'mongodb-mongosh-shared-openssl11' }}"
+ when: mongosh_package is not defined
+
# tasks file for mongodb_install
- name: Install MongoDB Packages
package:
- name: mongodb-org
+ name:
+ - "mongodb-org"
+ - "mongodb-org-server"
+ - "{{ mongosh_package }}" # variablized due to tls issue
+ - "mongodb-org-mongos"
+ - "mongodb-org-tools"
state: present
when: specific_mongodb_version is not defined
register: _pkg
@@ -15,7 +30,12 @@
- name: Install MongoDB Packages (Specific version)
package:
- name: "mongodb-org*{{ specific_mongodb_version }}"
+ name:
+ - "mongodb-org-{{ specific_mongodb_version }}"
+ - "mongodb-org-server-{{ specific_mongodb_version }}"
+ - "{{ mongosh_package }}" # variablized due to tls issue
+ - "mongodb-org-mongos-{{ specific_mongodb_version }}"
+ - "mongodb-org-tools-{{ specific_mongodb_version }}"
state: present
when:
- specific_mongodb_version is defined
@@ -37,7 +57,7 @@
name:
- "mongodb-org={{ specific_mongodb_version }}"
- "mongodb-org-server={{ specific_mongodb_version }}"
- - "mongodb-mongosh" # mongosh package uses a new versioning number schema
+ - "{{ mongosh_package }}" # variablized due to tls issue
- "mongodb-org-mongos={{ specific_mongodb_version }}"
- "mongodb-org-tools={{ specific_mongodb_version }}"
state: present
diff --git a/ansible_collections/community/mongodb/roles/mongodb_linux/README.md b/ansible_collections/community/mongodb/roles/mongodb_linux/README.md
index 7cc37be47..5a948d5c9 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_linux/README.md
+++ b/ansible_collections/community/mongodb/roles/mongodb_linux/README.md
@@ -17,8 +17,9 @@ Role Variables
--------------
swappiness: OS swappiness value. Default "1".
-ntp_package: Name of ntp package. Default ntp.
-ntp_service: Name of ntp service. Default ntpd.
+mongodb_ntp_package: Name of ntp package. Default depends on OS-specific vars.
+mongodb_ntp_service: Name of ntp service. Default depends on OS-specific vars.
+mongodb_gnu_c_lib: Name of the GNU C lib. Default depends on OS-specific vars.
* On RedHat 8 and higher systems ntp_package and ntp_service are set to chrony and chronyd respectively.
diff --git a/ansible_collections/community/mongodb/roles/mongodb_linux/defaults/main.yml b/ansible_collections/community/mongodb/roles/mongodb_linux/defaults/main.yml
index 7b2a0a68b..14659e137 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_linux/defaults/main.yml
+++ b/ansible_collections/community/mongodb/roles/mongodb_linux/defaults/main.yml
@@ -8,3 +8,7 @@ swappiness: "1"
nproc_and_nofile_limit: 64000
# TODO: mongo suggests infinity here
memlock_limit: 1024
+
+mongodb_ntp_package:
+mongodb_ntp_service:
+mongodb_gnu_c_lib:
diff --git a/ansible_collections/community/mongodb/roles/mongodb_linux/files/thp-disable.service b/ansible_collections/community/mongodb/roles/mongodb_linux/files/thp-disable.service
index 3602ed7b4..b8b6ba38b 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_linux/files/thp-disable.service
+++ b/ansible_collections/community/mongodb/roles/mongodb_linux/files/thp-disable.service
@@ -1,5 +1,6 @@
[Unit]
Description=Disable Transparent Huge Pages
+ConditionPathIsDirectory=/sys/kernel/mm/transparent_hugepage
[Service]
Type=oneshot
diff --git a/ansible_collections/community/mongodb/roles/mongodb_linux/molecule/default/molecule.yml b/ansible_collections/community/mongodb/roles/mongodb_linux/molecule/default/molecule.yml
index 5d12cbb04..712209f4e 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_linux/molecule/default/molecule.yml
+++ b/ansible_collections/community/mongodb/roles/mongodb_linux/molecule/default/molecule.yml
@@ -18,8 +18,8 @@ platforms:
networks:
- name: "mongodb_linux"
network_mode: "mongodb_linux"
- - name: ubuntu_18
- image: ubuntu:18.04
+ - name: ubuntu_22_04
+ image: ubuntu:22.04
command: /sbin/init
privileged: True
networks:
diff --git a/ansible_collections/community/mongodb/roles/mongodb_linux/tasks/main.yml b/ansible_collections/community/mongodb/roles/mongodb_linux/tasks/main.yml
index e8a61a394..70b223127 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_linux/tasks/main.yml
+++ b/ansible_collections/community/mongodb/roles/mongodb_linux/tasks/main.yml
@@ -17,6 +17,12 @@
tags:
- "vars"
+- name: "Override variables from OS-specific configuration"
+ set_fact:
+ ntp_package: "{{ mongodb_ntp_package | default(ntp_package, true) }}"
+ ntp_service: "{{ mongodb_ntp_service | default(ntp_service, true) }}"
+ gnu_c_lib: "{{ mongodb_gnu_c_lib | default(gnu_c_lib, true) }}"
+
- name: See if we are in docker
when:
- "ansible_facts.virtualization_role == 'guest'"
@@ -126,8 +132,14 @@
- "setup"
- "service"
+- name: Check if transparent_hugepage is enabled in the kernel
+ stat:
+ path: /sys/kernel/mm/transparent_hugepage
+ register: sys_thp
+
- name: Check if disable-transparent-huge-pages service is already run
shell: cat /sys/kernel/mm/transparent_hugepage/enabled | grep -o '[never]'
+ when: sys_thp.stat.exists
register: _huge_page_status
ignore_errors: yes
changed_when: _huge_page_status.stdout == ""
@@ -141,7 +153,7 @@
name: disable-transparent-huge-pages
state: started
enabled: yes
- when: (not in_docker|bool) and (_huge_page_status.stdout == "")
+ when: (not in_docker|bool) and (sys_thp.stat.exists) and (_huge_page_status.stdout == "")
tags:
- "linux"
- "service"
@@ -190,6 +202,7 @@
# TODO: These may need to be configurable for different usage patterns.
- { "name": "vm.dirty_ratio", "value": "15" }
- { "name": "vm.dirty_background_ratio", "value": "5" }
+ - { "name": "vm.max_map_count", "value": "128000" }
- { "name": "net.core.somaxconn ", "value": "4096" }
- { "name": "net.ipv4.tcp_fin_timeout", "value": "30" }
- { "name": "net.ipv4.tcp_keepalive_intvl", "value": "30" }
diff --git a/ansible_collections/community/mongodb/roles/mongodb_linux/vars/Debian-12.yml b/ansible_collections/community/mongodb/roles/mongodb_linux/vars/Debian-12.yml
new file mode 100644
index 000000000..364a59345
--- /dev/null
+++ b/ansible_collections/community/mongodb/roles/mongodb_linux/vars/Debian-12.yml
@@ -0,0 +1,5 @@
+---
+# Packages for Debian distros
+ntp_package: systemd-timesyncd
+ntp_service: systemd-timesyncd
+gnu_c_lib: libc6
diff --git a/ansible_collections/community/mongodb/roles/mongodb_linux/vars/RedHat-9.yml b/ansible_collections/community/mongodb/roles/mongodb_linux/vars/RedHat-9.yml
new file mode 100644
index 000000000..7e8077261
--- /dev/null
+++ b/ansible_collections/community/mongodb/roles/mongodb_linux/vars/RedHat-9.yml
@@ -0,0 +1,5 @@
+---
+# Packages for RedHat-9 distros
+ntp_package: chrony
+ntp_service: chronyd
+gnu_c_lib: glibc
diff --git a/ansible_collections/community/mongodb/roles/mongodb_mongod/README.md b/ansible_collections/community/mongodb/roles/mongodb_mongod/README.md
index 51a801296..f2bf1d935 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_mongod/README.md
+++ b/ansible_collections/community/mongodb/roles/mongodb_mongod/README.md
@@ -6,29 +6,34 @@ A simple role to aid in the setup of a MongoDB replicaset.
Role Variables
--------------
-* `mongod_port`: The port used by the mongod process. Default 27017.
-* `mongod_service`: The name of the mongod service. Default mongod.
-* `mongodb_user`: The Linux OS user for MongoDB. Default mongod.
-* `mongodb_group`: The Linux OS user group for MongoDB. Default mongod.
-* `bind_ip`: The IP address mongod will bind to. Default 0.0.0.0.
-* `bind_ip_all`: Have mongod bind to all IP addresses instead of specifying `bind_ip`. Default false.
-* `log_path`: Path of the log file. Default: /var/log/mongodb/mongod.log.
-* `repl_set_name`: The name of the replicaset the member will participate in. Default rs0.
-* `authorization`: Enable authorization. Default enabled.
+* `mongod_port`: The port used by the mongod process. Default `27017`.
+* `mongod_service`: The name of the mongod service. Default `mongod`.
+* `mongodb_user`: The Linux OS user for MongoDB. Default `mongod`.
+* `mongodb_group`: The Linux OS user group for MongoDB. Default `mongod`.
+* `bind_ip`: The IP address mongod will bind to. Default `0.0.0.0`.
+* `bind_ip_all`: Have mongod bind to all IP addresses instead of specifying `bind_ip`. Default `false`.
+* `log_path`: Path of the log file. Default: `/var/log/mongodb/mongod.log`.
+* `repl_set_name`: The name of the replicaset the member will participate in. Default `rs0`.
+* `authorization`: Enable authorization. Default `enabled`.
* `openssl_keyfile_content`: The keyfile content that MongoDB uses to authenticate within a replicaset. Generate with cmd: openssl rand -base64 756.
-* `openssl_keyfile_path`: Put the openssl_keyfile at this path. Default: /etc/keyfile
-* `mongodb_admin_user`: MongoDB admin username. Default admin.
-* `mongodb_admin_pwd`: MongoDB admin password. Default admin.
-* `mongod_package`: The mongod package to install. Default mongodb-org-server.
-* `replicaset`: When enabled add a replication section to the configuration. Default true.
-* `sharding`: If this replicaset member will form part of a sharded cluster. Default false.
+* `openssl_keyfile_path`: Put the openssl_keyfile at this path. Default: `/etc/keyfile`.
+* `mongodb_admin_user`: MongoDB admin username. Default `admin`.
+* `mongodb_admin_pwd`: MongoDB admin password. Default `admin`.
+* `mongod_package`: The mongod package to install. Default `mongodb-org-server`.
+* `replicaset`: When enabled add a replication section to the configuration. Default `true`.
+* `sharding`: If this replicaset member will form part of a sharded cluster. Default `false`.
* `net_compressors`: If this is set, this sets `net.compression.compressors` in mongod.conf.
-* `mongod_config_template`: If defined allows to override path to mongod config template with custom configuration. Default "mongod.conf.j2"
+* `mongod_config_template`: If defined allows to override path to mongod config template with custom configuration. Default `mongod.conf.j2`.
* `skip_restart`: If set to `true` will skip restarting mongod service when config file or the keyfile content changes. Default `true`.
* `db_path`: Path to database data location. Default `/var/lib/mongodb` on Debian based distributions, `/var/lib/mongo` for others.
-* `mongodb_use_tls`: Wether to use tls. Default false.
+* `mongodb_use_tls`: Whether to use tls. Default `false`.
+* `mongodb_disabled_tls_protocols`: The tls protocols to be disabled. Leave blank to let MongoDB decide which protocols to allow according to the ones available on the system; check the [official docs](https://www.mongodb.com/docs/v6.0/reference/configuration-options/#mongodb-setting-net.tls.disabledProtocols) for details. Default "".
+* `mongodb_allow_connections_without_certificates`: When enabled allows to bypass the certificate validation for clients that do not present a certificate, if a certificate is provided it _must_ be valid. Default `false`.
* `mongodb_certificate_key_file`: Path to the PEM-file containing the certficate and private key.
* `mongodb_certificate_ca_file`: Path to the CA-file.
+* `mongodb_logrotate_enabled`: Add logrotate configuration. Default: `false`.
+* `mongodb_logrotate_template`: Jinja template for the logrotate configuration. Default `mongodb.logrotate.j2`.
+* `mongodb_systemd_service_override`: Content of a file to override systemd configuration.
IMPORTANT NOTE: It is expected that `mongodb_admin_user` & `mongodb_admin_pwd` values be overridden in your own file protected by Ansible Vault. These values are primary included here for Molecule/Travis CI integration. Any production environments should protect these values. For more information see [Ansible Vault](https://docs.ansible.com/ansible/latest/user_guide/vault.html)
diff --git a/ansible_collections/community/mongodb/roles/mongodb_mongod/defaults/main.yml b/ansible_collections/community/mongodb/roles/mongodb_mongod/defaults/main.yml
index b0d9da221..3fd788ec2 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_mongod/defaults/main.yml
+++ b/ansible_collections/community/mongodb/roles/mongodb_mongod/defaults/main.yml
@@ -34,3 +34,15 @@ mongod_config_template: "mongod.conf.j2"
skip_restart: true
db_path: "{{ '/var/lib/mongodb' if ansible_os_family == 'Debian' else '/var/lib/mongo' if ansible_os_family == 'RedHat' else '/var/lib/mongo' }}"
mongodb_use_tls: false
+mongodb_disabled_tls_protocols: ""
+mongodb_allow_connections_without_certificates: false
+mongodb_logrotate_enabled: false
+mongodb_logrotate_template: "mongodb.logrotate.j2"
+
+# Override systemd default configuration
+# Some properties are not overridden: https://askubuntu.com/questions/659267/how-do-i-override-or-configure-systemd-services
+# Examples:
+# mongodb_systemd_service_override: |
+# [Service]
+# Restart=on-failure # Mongod will restart on-failure (by default mongod don't restart)
+mongodb_systemd_service_override: ""
diff --git a/ansible_collections/community/mongodb/roles/mongodb_mongod/handlers/main.yml b/ansible_collections/community/mongodb/roles/mongodb_mongod/handlers/main.yml
index 026817530..6653f9651 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_mongod/handlers/main.yml
+++ b/ansible_collections/community/mongodb/roles/mongodb_mongod/handlers/main.yml
@@ -12,3 +12,8 @@
host: "{{ bind_ip | split(',') | first }}"
port: "{{ mongod_port }}"
when: not skip_restart
+
+- name: Reload systemd configuration
+ listen: daemon-reload
+ systemd:
+ daemon_reload: true
diff --git a/ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/custom_db_path/molecule.yml b/ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/custom_db_path/molecule.yml
index e98e993dc..e3b8a0288 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/custom_db_path/molecule.yml
+++ b/ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/custom_db_path/molecule.yml
@@ -18,8 +18,8 @@ platforms:
networks:
- name: "mongod"
network_mode: "mongod"
- - name: ubuntu_18
- image: ubuntu:18.04
+ - name: ubuntu_22_04
+ image: ubuntu:22.04
command: /sbin/init
privileged: True
networks:
diff --git a/ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/custom_db_path/playbook.yml b/ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/custom_db_path/playbook.yml
index e0bee962e..6e7f5cbc7 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/custom_db_path/playbook.yml
+++ b/ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/custom_db_path/playbook.yml
@@ -15,9 +15,20 @@
name: "{{ 'pymongo==3.12.*' if ansible_python_version[0:3] | float < 3.6 else 'pymongo' }}"
when: ansible_hostname == "fedora"
+ - name: Determine openssl version
+ command: openssl version
+ changed_when: false
+ register: openssl
+
+ - name: Set mongosh package version
+ set_fact:
+ mongosh_package: "{{ 'mongodb-mongosh-shared-openssl3' if openssl.stdout.startswith('OpenSSL 3') else 'mongodb-mongosh-shared-openssl11' }}"
+ when: mongosh_package is not defined
+
- name: Install MongoDB Shell
package:
- name: mongodb-mongosh
+ name:
+ - "{{ mongosh_package }}"
- name: Initialise replicaset
community.mongodb.mongodb_replicaset:
@@ -27,7 +38,7 @@
members:
- almalinux_8:27017
- fedora:27017
- - ubuntu_18:27017
+ - ubuntu_22_04:27017
- debian_bullseye:27017
- ubuntu_22:27017
when: ansible_hostname == "fedora"
diff --git a/ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/custom_db_path/tests/test_default.py b/ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/custom_db_path/tests/test_default.py
index 9aca8518e..4376de40c 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/custom_db_path/tests/test_default.py
+++ b/ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/custom_db_path/tests/test_default.py
@@ -64,7 +64,7 @@ def test_mongod_replicaset(host):
assert "rs0" in r.stdout
assert "almalinux_8:{0}".format(port) in r.stdout
assert "fedora:{0}".format(port) in r.stdout
- assert "ubuntu_18:{0}".format(port) in r.stdout
+ assert "ubuntu_22_04:{0}".format(port) in r.stdout
assert "ubuntu_22:{0}".format(port) in r.stdout
assert "debian_bullseye:{0}".format(port) in r.stdout
diff --git a/ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/default/molecule.yml b/ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/default/molecule.yml
index 2cbd158c4..deb681763 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/default/molecule.yml
+++ b/ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/default/molecule.yml
@@ -18,8 +18,8 @@ platforms:
networks:
- name: "mongod"
network_mode: "mongod"
- - name: ubuntu_18
- image: ubuntu:18.04
+ - name: ubuntu_22_04
+ image: ubuntu:22.04
command: /sbin/init
privileged: True
networks:
diff --git a/ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/default/playbook.yml b/ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/default/playbook.yml
index 54b4def97..0ef97010b 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/default/playbook.yml
+++ b/ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/default/playbook.yml
@@ -13,9 +13,20 @@
name: "{{ 'pymongo==3.12.*' if ansible_python_version[0:3] | float < 3.6 else 'pymongo' }}"
when: ansible_hostname == "fedora"
+ - name: Determine openssl version
+ command: openssl version
+ changed_when: false
+ register: openssl
+
+ - name: Set mongosh package version
+ set_fact:
+ mongosh_package: "{{ 'mongodb-mongosh-shared-openssl3' if openssl.stdout.startswith('OpenSSL 3') else 'mongodb-mongosh-shared-openssl11' }}"
+ when: mongosh_package is not defined
+
- name: Install MongoDB Shell
package:
- name: mongodb-mongosh
+ name:
+ - "{{ mongosh_package }}"
- name: Initialise replicaset
community.mongodb.mongodb_replicaset:
@@ -25,7 +36,7 @@
members:
- almalinux_8:27017
- fedora:27017
- - ubuntu_18:27017
+ - ubuntu_22_04:27017
- debian_bullseye:27017
- ubuntu_22:27017
when: ansible_hostname == "fedora"
diff --git a/ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/default/tests/test_default.py b/ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/default/tests/test_default.py
index 896f0ee58..6a68ce52c 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/default/tests/test_default.py
+++ b/ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/default/tests/test_default.py
@@ -64,7 +64,7 @@ def test_mongod_replicaset(host):
assert "rs0" in r.stdout
assert "almalinux_8:{0}".format(port) in r.stdout
assert "fedora:{0}".format(port) in r.stdout
- assert "ubuntu_18:{0}".format(port) in r.stdout
+ assert "ubuntu_22_04:{0}".format(port) in r.stdout
assert "ubuntu_22:{0}".format(port) in r.stdout
assert "debian_bullseye:{0}".format(port) in r.stdout
diff --git a/ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/multiple_bind_ip/molecule.yml b/ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/multiple_bind_ip/molecule.yml
index b3f2e1199..20a80cfc7 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/multiple_bind_ip/molecule.yml
+++ b/ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/multiple_bind_ip/molecule.yml
@@ -18,8 +18,8 @@ platforms:
networks:
- name: "mongod"
network_mode: "mongod"
- - name: ubuntu_18
- image: ubuntu:18.04
+ - name: ubuntu_22_04
+ image: ubuntu:22.04
command: /sbin/init
privileged: True
networks:
diff --git a/ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/multiple_bind_ip/playbook.yml b/ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/multiple_bind_ip/playbook.yml
index ba1a7f28a..7593d0781 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/multiple_bind_ip/playbook.yml
+++ b/ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/multiple_bind_ip/playbook.yml
@@ -16,9 +16,20 @@
name: "{{ 'pymongo==3.12.*' if ansible_python_version[0:3] | float < 3.6 else 'pymongo' }}"
when: ansible_hostname == "fedora"
+ - name: Determine openssl version
+ command: openssl version
+ changed_when: false
+ register: openssl
+
+ - name: Set mongosh package version
+ set_fact:
+ mongosh_package: "{{ 'mongodb-mongosh-shared-openssl3' if openssl.stdout.startswith('OpenSSL 3') else 'mongodb-mongosh-shared-openssl11' }}"
+ when: mongosh_package is not defined
+
- name: Install MongoDB Shell
package:
- name: mongodb-mongosh
+ name:
+ - "{{ mongosh_package }}"
- name: Initialise replicaset
community.mongodb.mongodb_replicaset:
@@ -28,7 +39,7 @@
members:
- almalinux_8:27017
- fedora:27017
- - ubuntu_18:27017
+ - ubuntu_22_04:27017
- debian_bullseye:27017
- ubuntu_22:27017
when: ansible_hostname == "fedora"
diff --git a/ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/multiple_bind_ip/tests/test_default.py b/ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/multiple_bind_ip/tests/test_default.py
index 6f54d5aad..adc23cda5 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/multiple_bind_ip/tests/test_default.py
+++ b/ansible_collections/community/mongodb/roles/mongodb_mongod/molecule/multiple_bind_ip/tests/test_default.py
@@ -64,7 +64,7 @@ def test_mongod_replicaset(host):
assert "rs0" in r.stdout
assert "almalinux_8:{0}".format(port) in r.stdout
assert "fedora:{0}".format(port) in r.stdout
- assert "ubuntu_18:{0}".format(port) in r.stdout
+ assert "ubuntu_22_04:{0}".format(port) in r.stdout
assert "ubuntu_22:{0}".format(port) in r.stdout
assert "debian_bullseye:{0}".format(port) in r.stdout
diff --git a/ansible_collections/community/mongodb/roles/mongodb_mongod/tasks/logrotate.yml b/ansible_collections/community/mongodb/roles/mongodb_mongod/tasks/logrotate.yml
new file mode 100644
index 000000000..e72fa33d2
--- /dev/null
+++ b/ansible_collections/community/mongodb/roles/mongodb_mongod/tasks/logrotate.yml
@@ -0,0 +1,9 @@
+---
+- name: Install logrotate configuration
+ ansible.builtin.template:
+ src: "{{ mongodb_logrotate_template }}"
+ dest: /etc/logrotate.d/mongod
+ tags:
+ - "mongodb"
+ - "setup"
+ - "service"
diff --git a/ansible_collections/community/mongodb/roles/mongodb_mongod/tasks/main.yml b/ansible_collections/community/mongodb/roles/mongodb_mongod/tasks/main.yml
index bd1eb944d..1f1072a63 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_mongod/tasks/main.yml
+++ b/ansible_collections/community/mongodb/roles/mongodb_mongod/tasks/main.yml
@@ -64,6 +64,30 @@
- "mongodb"
- "setup"
+- name: Override mongod service
+ when: mongodb_systemd_service_override | length > 0
+ tags:
+ - "mongodb"
+ - "setup"
+ - "service"
+ block:
+ - name: "Create {{ mongod_service }}.service.d directory"
+ file:
+ path: "/etc/systemd/system/{{ mongod_service }}.service.d/"
+ state: directory
+ owner: root
+ group: root
+ mode: 0755
+
+ - name: Override mongod service from provided content
+ copy:
+ content: "{{ mongodb_systemd_service_override }}"
+ dest: "/etc/systemd/system/{{ mongod_service }}.service.d/override.conf"
+ owner: root
+ group: root
+ mode: 0644
+ notify: daemon-reload
+
- name: Check for github override
set_fact:
x_github_override: "{{ lookup('env', 'X_GITHUB_OVERRIDE') | default('0', True) }}"
@@ -79,6 +103,15 @@
- "mongodb"
- "setup"
- "service"
+
+- name: Configure logrotate if enabled
+ when: mongodb_logrotate_enabled
+ ansible.builtin.include_tasks: logrotate.yml
+ tags:
+ - "mongodb"
+ - "setup"
+ - "service"
+
# debug section
- pause:
seconds: 5
diff --git a/ansible_collections/community/mongodb/roles/mongodb_mongod/templates/mongod.conf.j2 b/ansible_collections/community/mongodb/roles/mongodb_mongod/templates/mongod.conf.j2
index 9ff5a5dec..cd2d1f0fc 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_mongod/templates/mongod.conf.j2
+++ b/ansible_collections/community/mongodb/roles/mongodb_mongod/templates/mongod.conf.j2
@@ -8,6 +8,9 @@ systemLog:
destination: file
logAppend: true
path: {{ log_path }}
+{% if mongodb_logrotate_enabled %}
+ logRotate: reopen
+{% endif %}
# Where and how to store data.
storage:
@@ -41,6 +44,12 @@ net:
mode: requireTLS
certificateKeyFile: {{ mongodb_certificate_key_file }}
CAFile: {{ mongodb_certificate_ca_file }}
+{% if mongodb_disabled_tls_protocols != "" %}
+ disabledProtocols: {{ mongodb_disabled_tls_protocols }}
+{% endif %}
+{% if mongodb_allow_connections_without_certificates %}
+ allowConnectionsWithoutCertificates: true
+{% endif %}
{% endif %}
{% if authorization == "enabled" %}
diff --git a/ansible_collections/community/mongodb/roles/mongodb_mongod/templates/mongodb.logrotate.j2 b/ansible_collections/community/mongodb/roles/mongodb_mongod/templates/mongodb.logrotate.j2
new file mode 100644
index 000000000..4cecbcadd
--- /dev/null
+++ b/ansible_collections/community/mongodb/roles/mongodb_mongod/templates/mongodb.logrotate.j2
@@ -0,0 +1,14 @@
+{{ log_path }} {
+ daily
+ size 100M
+ rotate 5
+ missingok
+ compress
+ delaycompress
+ notifempty
+ create 640 {{ mongodb_user }} {{ mongodb_group }}
+ sharedscripts
+ postrotate
+ /bin/kill -SIGUSR1 `pidof {{ mongod_service }} 2>/dev/null` >/dev/null 2>&1
+ endscript
+}
diff --git a/ansible_collections/community/mongodb/roles/mongodb_mongos/README.md b/ansible_collections/community/mongodb/roles/mongodb_mongos/README.md
index 414246781..de935f0b6 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_mongos/README.md
+++ b/ansible_collections/community/mongodb/roles/mongodb_mongos/README.md
@@ -13,24 +13,26 @@ good idea to mention in this section that the boto package is required.
Role Variables
--------------
-* `mongos_port`: The port used by the mongos process. Default 27017.
-* `mongos_service`: The name of the mongos service. Default mongos.
-* `mongodb_user`: The Linux OS user for MongoDB. Default mongod.
-* `mongodb_group`: The Linux OS user group for MongoDB. Default mongod.
-* `pid_file`: The pid file for mongos. Default /run/mongodb/mongos.pid.
-* `bind_ip`: The IP address mongos will bind to. Default 0.0.0.0.
-* `bind_ip_all`: Have mongos bind to all IP addresses instead of specifying `bind_ip`. Default false.
-* `log_path`: Path of the log file. Default: /var/log/mongodb/mongos.log.
-* `mypy`: Python interpretor. Default python
-* `mongos_package`: The name of the mongos installation package. Default mongodb-org-mongos.
-* `config_repl_set_name`: The name of the config server replicaset. Default cfg.
+* `mongos_port`: The port used by the mongos process. Default `27017`.
+* `mongos_service`: The name of the mongos service. Default `mongos`.
+* `mongodb_user`: The Linux OS user for MongoDB. Default `mongod`.
+* `mongodb_group`: The Linux OS user group for MongoDB. Default `mongod`.
+* `pid_file`: The pid file for mongos. Default `/run/mongodb/mongos.pid`.
+* `bind_ip`: The IP address mongos will bind to. Default `0.0.0.0`.
+* `bind_ip_all`: Have mongos bind to all IP addresses instead of specifying `bind_ip`. Default `false`.
+* `log_path`: Path of the log file. Default: `/var/log/mongodb/mongos.log`.
+* `mypy`: Python interpretor. Default `python`.
+* `mongos_package`: The name of the mongos installation package. Default `mongodb-org-mongos`.
+* `config_repl_set_name`: The name of the config server replicaset. Default `cfg`.
* `config_servers`: "config1:27019, config2:27019, config3:27019"
* `openssl_keyfile_content`: The kexfile content that MongoDB uses to authenticate within a replicaset. Generate with cmd: openssl rand -base64 756.
-* `openssl_keyfile_path`: Put the openssl_keyfile at this path. Default: /etc/keyfile
+* `openssl_keyfile_path`: Put the openssl_keyfile at this path. Default: `/etc/keyfile`.
* `net_compressors`: If this is set, this sets `net.compression.compressors` in mongos.conf.
-* `mongos_config_template`: If defined allows to override path to mongod config template with custom configuration. Default "mongos.conf.j2"
+* `mongos_config_template`: If defined allows to override path to mongod config template with custom configuration. Default `mongos.conf.j2`.
* `skip_restart`: If set to `true` will skip restarting mongos service when config file or the keyfile content changes. Default `true`.
-* `mongodb_use_tls`: Wether to use tls. Default false.
+* `mongodb_use_tls`: Whether to use tls. Default `false`.
+* `mongodb_disabled_tls_protocols`: The tls protocols to be disabled. Leave blank to let MongoDB decide which protocols to allow according to the ones available on the system; check the [official docs](https://www.mongodb.com/docs/v6.0/reference/configuration-options/#mongodb-setting-net.tls.disabledProtocols) for details. Default "".
+* `mongodb_allow_connections_without_certificates`: When enabled allows to bypass the certificate validation for clients that do not present a certificate, if a certificate is provided it _must_ be valid. Default `false`.
* `mongodb_certificate_key_file`: Path to the PEM-file containing the certficate and private key.
* `mongodb_certificate_ca_file`: Path to the CA-file.
diff --git a/ansible_collections/community/mongodb/roles/mongodb_mongos/defaults/main.yml b/ansible_collections/community/mongodb/roles/mongodb_mongos/defaults/main.yml
index 6d91e8814..0ca7f0371 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_mongos/defaults/main.yml
+++ b/ansible_collections/community/mongodb/roles/mongodb_mongos/defaults/main.yml
@@ -31,3 +31,5 @@ net_compressors: null
mongos_config_template: "mongos.conf.j2"
skip_restart: true
mongodb_use_tls: false
+mongodb_disabled_tls_protocols: ""
+mongodb_allow_connections_without_certificates: false
diff --git a/ansible_collections/community/mongodb/roles/mongodb_mongos/molecule/default/molecule.yml b/ansible_collections/community/mongodb/roles/mongodb_mongos/molecule/default/molecule.yml
index b361e644c..f1e8d4999 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_mongos/molecule/default/molecule.yml
+++ b/ansible_collections/community/mongodb/roles/mongodb_mongos/molecule/default/molecule.yml
@@ -28,8 +28,8 @@ platforms:
networks:
- name: "mymongos"
network_mode: "mymongos"
- - name: ubuntu_18
- image: ubuntu:18.04
+ - name: ubuntu_22_04
+ image: ubuntu:22.04
command: /sbin/init
privileged: True
networks:
@@ -50,7 +50,7 @@ platforms:
# - name: "mymongos"
# network_mode: "mymongos"
- name: config1
- image: ubuntu:18.04
+ image: ubuntu:22.04
command: /sbin/init
privileged: True
networks:
diff --git a/ansible_collections/community/mongodb/roles/mongodb_mongos/molecule/default/playbook.yml b/ansible_collections/community/mongodb/roles/mongodb_mongos/molecule/default/playbook.yml
index de0e856ba..cee69734a 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_mongos/molecule/default/playbook.yml
+++ b/ansible_collections/community/mongodb/roles/mongodb_mongos/molecule/default/playbook.yml
@@ -26,9 +26,20 @@
name: "{{ 'pymongo==3.12.*' if ansible_python_version[0:3] | float < 3.6 else 'pymongo' }}"
when: ansible_hostname == "config1"
+ - name: Determine openssl version
+ command: openssl version
+ changed_when: false
+ register: openssl
+
+ - name: Set mongosh package version
+ set_fact:
+ mongosh_package: "{{ 'mongodb-mongosh-shared-openssl3' if openssl.stdout.startswith('OpenSSL 3') else 'mongodb-mongosh-shared-openssl11' }}"
+ when: mongosh_package is not defined
+
- name: Install MongoDB Shell
package:
- name: mongodb-mongosh
+ name:
+ - "{{ mongosh_package }}"
- name: Init config server replicaset
community.mongodb.mongodb_replicaset:
diff --git a/ansible_collections/community/mongodb/roles/mongodb_mongos/molecule/default/prepare.yml b/ansible_collections/community/mongodb/roles/mongodb_mongos/molecule/default/prepare.yml
index 40efdd033..d9a4dd252 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_mongos/molecule/default/prepare.yml
+++ b/ansible_collections/community/mongodb/roles/mongodb_mongos/molecule/default/prepare.yml
@@ -20,4 +20,8 @@
ansible.builtin.package:
name: "{{ redhat_packages }}"
state: present
- when: ansible_os_family == "RedHat" \ No newline at end of file
+ when: ansible_os_family == "RedHat"
+
+ - name: Install openssl
+ package:
+ name: openssl \ No newline at end of file
diff --git a/ansible_collections/community/mongodb/roles/mongodb_mongos/templates/mongos.conf.j2 b/ansible_collections/community/mongodb/roles/mongodb_mongos/templates/mongos.conf.j2
index 6c61b8716..f9726f2f5 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_mongos/templates/mongos.conf.j2
+++ b/ansible_collections/community/mongodb/roles/mongodb_mongos/templates/mongos.conf.j2
@@ -19,6 +19,12 @@ net:
mode: requireTLS
certificateKeyFile: {{ mongodb_certificate_key_file }}
CAFile: {{ mongodb_certificate_ca_file }}
+{% if mongodb_disabled_tls_protocols != "" %}
+ disabledProtocols: {{ mongodb_disabled_tls_protocols }}
+{% endif %}
+{% if mongodb_allow_connections_without_certificates %}
+ allowConnectionsWithoutCertificates: true
+{% endif %}
{% endif %}
sharding:
configDB: "{{ config_repl_set_name }}/{{ config_servers }}"
diff --git a/ansible_collections/community/mongodb/roles/mongodb_repository/molecule/default/molecule.yml b/ansible_collections/community/mongodb/roles/mongodb_repository/molecule/default/molecule.yml
index a750255f9..18ab8e812 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_repository/molecule/default/molecule.yml
+++ b/ansible_collections/community/mongodb/roles/mongodb_repository/molecule/default/molecule.yml
@@ -11,8 +11,8 @@ lint:
platforms:
- name: almalinux_8
image: almalinux:8
- - name: ubuntu_18
- image: ubuntu:18.04
+ - name: ubuntu_22_04
+ image: ubuntu:22.04
- name: ubuntu_22
image: ubuntu:22.04
- name: debian_bullseye
diff --git a/ansible_collections/community/mongodb/roles/mongodb_selinux/molecule/default/molecule.yml b/ansible_collections/community/mongodb/roles/mongodb_selinux/molecule/default/molecule.yml
index 907a32abc..c54825da3 100644
--- a/ansible_collections/community/mongodb/roles/mongodb_selinux/molecule/default/molecule.yml
+++ b/ansible_collections/community/mongodb/roles/mongodb_selinux/molecule/default/molecule.yml
@@ -11,8 +11,8 @@ lint:
platforms:
- name: almalinux_8
image: almalinux:8
- - name: ubuntu_18
- image: ubuntu:18.04
+ - name: ubuntu_22_04
+ image: ubuntu:22.04
- name: ubuntu_22
image: ubuntu:22.04
- name: debian_bullseye
diff --git a/ansible_collections/community/mysql/.github/workflows/ansible-test-plugins.yml b/ansible_collections/community/mysql/.github/workflows/ansible-test-plugins.yml
index 6533f9461..78644bb25 100644
--- a/ansible_collections/community/mysql/.github/workflows/ansible-test-plugins.yml
+++ b/ansible_collections/community/mysql/.github/workflows/ansible-test-plugins.yml
@@ -22,9 +22,9 @@ jobs:
strategy:
matrix:
ansible:
- - stable-2.12
- - stable-2.13
- stable-2.14
+ - stable-2.15
+ - stable-2.16
- devel
steps:
- name: Perform sanity testing
@@ -41,9 +41,9 @@ jobs:
fail-fast: false
matrix:
ansible:
- - stable-2.12
- - stable-2.13
- stable-2.14
+ - stable-2.15
+ - stable-2.16
- devel
db_engine_name:
- mysql
@@ -112,10 +112,13 @@ jobs:
python: '3.10'
- db_engine_version: 5.7.40
- ansible: stable-2.13
+ ansible: stable-2.14
- db_engine_version: 5.7.40
- ansible: stable-2.14
+ ansible: stable-2.15
+
+ - db_engine_version: 5.7.40
+ ansible: stable-2.16
- db_engine_version: 5.7.40
ansible: devel
@@ -172,22 +175,25 @@ jobs:
connector_version: 2.0.3
- python: '3.8'
- ansible: stable-2.13
+ ansible: stable-2.14
- python: '3.8'
- ansible: stable-2.14
+ ansible: stable-2.15
+
+ - python: '3.8'
+ ansible: stable-2.16
- python: '3.8'
ansible: devel
- python: '3.9'
- ansible: stable-2.12
+ ansible: stable-2.15
- python: '3.9'
- ansible: devel
+ ansible: stable-2.16
- - python: '3.10'
- ansible: stable-2.12
+ - python: '3.9'
+ ansible: devel
services:
db_primary:
@@ -334,22 +340,22 @@ jobs:
fail-fast: true
matrix:
ansible:
- - stable-2.12
- - stable-2.13
- stable-2.14
+ - stable-2.15
+ - stable-2.16
- devel
python:
- 3.8
- 3.9
exclude:
- python: '3.8'
- ansible: stable-2.13
- - python: '3.8'
ansible: stable-2.14
- python: '3.8'
+ ansible: stable-2.15
+ - python: '3.8'
+ ansible: stable-2.16
+ - python: '3.8'
ansible: devel
- - python: '3.9'
- ansible: stable-2.12
steps:
- name: >-
diff --git a/ansible_collections/community/mysql/.github/workflows/ansible-test-roles.yml b/ansible_collections/community/mysql/.github/workflows/ansible-test-roles.yml
index 13e7d4178..da8a805c5 100644
--- a/ansible_collections/community/mysql/.github/workflows/ansible-test-roles.yml
+++ b/ansible_collections/community/mysql/.github/workflows/ansible-test-roles.yml
@@ -24,31 +24,16 @@ jobs:
mysql:
- 2.0.12
ansible:
- - stable-2.11
- - stable-2.12
- stable-2.13
+ - stable-2.14
+ - stable-2.15
- devel
python:
- - 3.6
- 3.8
- 3.9
exclude:
- - python: 3.6
- ansible: stable-2.12
- - python: 3.6
- ansible: stable-2.13
- - python: 3.6
- ansible: devel
- - python: 3.8
- ansible: stable-2.11
- - python: 3.8
- ansible: stable-2.13
- python: 3.8
ansible: devel
- - python: 3.9
- ansible: stable-2.11
- - python: 3.9
- ansible: stable-2.12
steps:
diff --git a/ansible_collections/community/mysql/CHANGELOG.rst b/ansible_collections/community/mysql/CHANGELOG.rst
index 31ee41a87..cc7ab8525 100644
--- a/ansible_collections/community/mysql/CHANGELOG.rst
+++ b/ansible_collections/community/mysql/CHANGELOG.rst
@@ -6,6 +6,56 @@ Community MySQL Collection Release Notes
This changelog describes changes after version 2.0.0.
+v3.9.0
+======
+
+Release Summary
+---------------
+
+This is a minor release of the ``community.mysql`` collection.
+This changelog contains all changes to the modules and plugins in this
+collection that have been made after the previous release.
+
+Major Changes
+-------------
+
+- Collection version 2.*.* is EOL, no more bugfixes will be backported. Please consider upgrading to the latest version.
+
+Minor Changes
+-------------
+
+- mysql_user - add the ``password_expire`` and ``password_expire_interval`` arguments to implement the password expiration management for mysql user (https://github.com/ansible-collections/community.mysql/pull/598).
+- mysql_user - add user attribute support via the ``attributes`` parameter and return value (https://github.com/ansible-collections/community.mysql/pull/604).
+
+Bugfixes
+--------
+
+- mysql_info - the ``slave_status`` filter was returning an empty list on MariaDB with multiple replication channels. It now returns all channels by running ``SHOW ALL SLAVES STATUS`` for MariaDB servers (https://github.com/ansible-collections/community.mysql/issues/603).
+
+v3.8.0
+======
+
+Release Summary
+---------------
+
+This is the minor release of the ``community.mysql`` collection.
+This changelog contains all changes to the modules and plugins in this
+collection that have been made after the previous release.
+
+Major Changes
+-------------
+
+- The community.mysql collection no longer supports ``ansible-core 2.12`` and ``ansible-core 2.13``. While we take no active measures to prevent usage and there are no plans to introduce incompatible code to the modules, we will stop testing those versions. Both are or will soon be End of Life and if you are still using them, you should consider upgrading to the ``latest Ansible / ansible-core 2.15 or later`` as soon as possible (https://github.com/ansible-collections/community.mysql/pull/574).
+- mysql_role - the ``column_case_sensitive`` argument's default value will be changed to ``true`` in community.mysql 4.0.0. If your playbook expected the column to be automatically uppercased for your roles privileges, you should set this to false explicitly (https://github.com/ansible-collections/community.mysql/issues/578).
+- mysql_user - the ``column_case_sensitive`` argument's default value will be changed to ``true`` in community.mysql 4.0.0. If your playbook expected the column to be automatically uppercased for your users privileges, you should set this to false explicitly (https://github.com/ansible-collections/community.mysql/issues/577).
+
+Minor Changes
+-------------
+
+- mysql_info - add filter ``users_info`` (https://github.com/ansible-collections/community.mysql/pull/580).
+- mysql_role - add ``column_case_sensitive`` option to prevent field names from being uppercased (https://github.com/ansible-collections/community.mysql/pull/569).
+- mysql_user - add ``column_case_sensitive`` option to prevent field names from being uppercased (https://github.com/ansible-collections/community.mysql/pull/569).
+
v3.7.2
======
diff --git a/ansible_collections/community/mysql/CONTRIBUTING.md b/ansible_collections/community/mysql/CONTRIBUTING.md
index 70cd5557e..1b6ecdfd7 100644
--- a/ansible_collections/community/mysql/CONTRIBUTING.md
+++ b/ansible_collections/community/mysql/CONTRIBUTING.md
@@ -1,5 +1,80 @@
-# Contributing
+# Contributing to this project
-Refer to the [Ansible Contributing guidelines](https://docs.ansible.com/ansible/devel/community/index.html) to learn how to contribute to this collection.
+In this guide, you will find information relevant for code contributions, though any other kinds of contribution mentioned in the [Ansible Contributing guidelines](https://docs.ansible.com/ansible/devel/community/index.html) are equally appreciated and valuable.
-Refer to the [review checklist](https://docs.ansible.com/ansible/devel/community/collection_contributors/collection_reviewing.html) when triaging issues or reviewing PRs.
+If you have any questions after reading, please contact the community via one or more of the [available channels](https://github.com/ansible-collections/community.mysql#communication). Any feedback on this guide is very welcome.
+
+## Reviewing open issue and pull requests
+
+Refer to the [review checklist](https://docs.ansible.com/ansible/devel/community/collection_contributors/collection_reviewing.html) when triaging issues or reviewing pull requests (hereinafter PRs).
+
+Most important things to pay attention to:
+
+- Do not let major/breaking changes sneak into a minor/bugfix release! All such changes should be discussed in a dedicated issue, added to a corresponding milestone (which can be found or created in the project's Issues), and merged right before the major release. Take a look at similar issues to see what needs to be done and reflect on the steps you did/need to do in the issue.
+- Every PR (except doc, refactoring, test-related, or a PR containing a new module/plugin) contains a [changelog fragment](https://docs.ansible.com/ansible/latest/community/development_process.html#creating-a-changelog-fragment). Let's give users a chance to know about the changes.
+- Every new module `DOCUMENTATION` section contains the `version_added: 'x.y.z'` field. Besides the informative purpose, it is used by the changelog-generating tool to add a corresponding entry to the changelog. As the project follows SemVer, it is typically a next minor (x.y.0) version.
+- Every new module argument contains the `version_added: 'x.y.z'` field. As the project follows SemVer, it is typically a next minor (x.y.0) version.
+- Non-refactoring code changes (bugfixes, new features) are covered with, at least, integration tests! There can be exceptions but generally it is a requirement.
+
+## Code contributions
+
+If you want to submit a bugfix or new feature, refer to the [Quick-start development guide](https://docs.ansible.com/ansible/devel/community/create_pr_quick_start.html) first.
+
+## Project-specific info
+
+We assume you have read the [Quick-start development guide](https://docs.ansible.com/ansible/devel/community/create_pr_quick_start.html).
+
+In order for any submitted PR to get merged, this project requires sanity, unit, and integration tests to pass.
+Codecov job is there but not required.
+We use the GitHub Actions platform to run the tests.
+You can see the result in the bottom of every PR in the box listing the jobs and their results:
+
+- Green checkmark: the test has been passed, no more action is needed.
+- Red cross: the test has failed. You can see the reason by clicking the ``Details`` link. Fix them locally and push the commit.
+
+Generally, all jobs must be green.
+Sometimes, there can be failures unrelated to a PR, for example, when a test container is unavailable or there is another part of the code that does not satisfy recently introduced additional sanity checks.
+If you think the failure does not relate to your changes, put a comment about it.
+
+## CI testing
+
+The jobs are launched automatically by GitHub Actions in every PR based on the [matrix](https://github.com/ansible-collections/community.mysql/blob/main/.github/workflows/ansible-test-plugins.yml).
+
+As the project is included in `ansible` community package, it is a requirement for us to test against all supported `ansible-core` versions and corresponding Python versions.
+To keep the matrix relevant, we are subscribed to the [news-for-maintainers](https://github.com/ansible-collections/news-for-maintainers) repository and the [Collection maintainers & contributors](https://forum.ansible.com/g/CollectionMaintainer) forum group to track announcements affecting CI.
+
+If our matrix is permanently outdated, for example, when supported `ansible-core` versions are missed, the collections can get excluded from the package, so keep it updated!
+
+Read more about our CI implementation in the [TESTING.md](https://github.com/ansible-collections/community.mysql/blob/main/TESTING.md) file.
+
+## Adding tests
+
+If you are new here, read the [Quick-start development guide](https://docs.ansible.com/ansible/devel/community/create_pr_quick_start.html) first.
+
+When fixing a bug, first reproduce it by adding a task as reported to a suitable file under the ``tests/integration/targets/<module_name>/tasks/`` directory and run the integration tests as described below. The same is relevant for new features.
+
+It is not necessary but if you want you can also add unit tests to a suitable file under the ``tests/units/`` directory and run them as described below.
+
+## Checking your code locally
+
+It will make your and other people's life a bit easier if you run the tests locally and fix all failures before pushing. If you're unable to run the tests locally, please create your PR as a **draft** to avoid reviewers being added automatically.
+
+If you are new here, read the [Quick-start development guide](https://docs.ansible.com/ansible/devel/community/create_pr_quick_start.html) first.
+
+We assume you [prepared your local environment](https://docs.ansible.com/ansible/devel/community/create_pr_quick_start.html#prepare-your-environment) as described in the guide before running the following commands. Otherwise, the command will fail.
+
+### Sanity tests
+
+``` console
+$ ansible-test sanity path/to/changed_file.py --docker -v
+```
+
+### Integration tests
+
+See the [TESTING.md](https://github.com/ansible-collections/community.mysql/blob/main/TESTING.md) file to learn how to run integration tests against different server/connector versions.
+
+### Unit tests
+
+``` console
+$ ansible-test units tests/unit/plugins/unit_test_file.py --docker
+```
diff --git a/ansible_collections/community/mysql/CONTRIBUTORS b/ansible_collections/community/mysql/CONTRIBUTORS
index 3acc8f33d..06fb57907 100644
--- a/ansible_collections/community/mysql/CONTRIBUTORS
+++ b/ansible_collections/community/mysql/CONTRIBUTORS
@@ -141,6 +141,7 @@ kalaisubbiah
kenichi-ogawa-1988
kkeane
klingac
+kmarse
koleo
kotso
kuntalFreshBooks
@@ -151,6 +152,7 @@ ldesgrange
leeadh
LeonB
leucos
+lkthomas
loomsen
lorin
lowwalker
diff --git a/ansible_collections/community/mysql/FILES.json b/ansible_collections/community/mysql/FILES.json
index e8a410307..b9139920f 100644
--- a/ansible_collections/community/mysql/FILES.json
+++ b/ansible_collections/community/mysql/FILES.json
@@ -25,14 +25,14 @@
"name": ".github/workflows/ansible-test-plugins.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "853a324a5d61d6fcfcbacfdf8103802f3ec763c85d546b29b9d8351170069a83",
+ "chksum_sha256": "6066bd23ec1ab65baeb8593bfd0b4db728a81c31ab66e5d2905eb8d4d20d61d5",
"format": 1
},
{
"name": ".github/workflows/ansible-test-roles.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a7935fe56bc37e6fd38a78d7db568c91ca3d1b7ce4cbdcb19a98ddaa56a48109",
+ "chksum_sha256": "1ae22305f85045b4491fcd8bbee1821e30905b21687663db68788d5bbb0ff2f8",
"format": 1
},
{
@@ -179,7 +179,7 @@
"name": "changelogs/changelog.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b3508fbc7594b06c88b696e61e87b126ed3ccd549c50f9d63a34ed27b41d9122",
+ "chksum_sha256": "0e910481ea590e77408e127beebe9ce1533d8acc0e9bf6175d0ab0bd640ba189",
"format": 1
},
{
@@ -221,7 +221,7 @@
"name": "plugins/doc_fragments/mysql.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "68615ead33b2ffd38c639a47980ae62ff6b7a3d9063ab322580072c6c7d5c452",
+ "chksum_sha256": "d3866b8a4d0aa946f3dd6b354c2e931e3c1732becb380fd3389acbf8e4245e57",
"format": 1
},
{
@@ -263,7 +263,7 @@
"name": "plugins/module_utils/implementations/mariadb/user.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "946bda63f668235fdc900f12cd3c4323054c7a45ef8aca91cd7379ace294bd7d",
+ "chksum_sha256": "a07ee8fa2b1a27e64c93ceb1065f137cdd84fd817e72d2291dcaca9ff2f55a77",
"format": 1
},
{
@@ -291,7 +291,7 @@
"name": "plugins/module_utils/implementations/mysql/user.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f2f802810550b7d69e13d63f9002e524ab598e633c861caf424e7a5d8c293891",
+ "chksum_sha256": "40b6e268e04472b0b59acf22561c8af1e4877d3a26cccfb0ea7e1151ca954d58",
"format": 1
},
{
@@ -312,14 +312,14 @@
"name": "plugins/module_utils/mysql.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5a8f8404b771e315d091a872e4369d2164c4b54e470ef496bd159caab1001e0c",
+ "chksum_sha256": "140e789e451eb4bf11fd3a39507f1858fb62df985ca74590b3d5e229aaa58424",
"format": 1
},
{
"name": "plugins/module_utils/user.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b8c93c05fecea1778fd0ef1d46bbc7d01f19742fbd4da8162d715fe6a0ed8a2e",
+ "chksum_sha256": "dd37494d932a1be94268c0153570a994667ac787a686cd114f29e4ed01bd2cf6",
"format": 1
},
{
@@ -340,49 +340,49 @@
"name": "plugins/modules/mysql_db.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6a0800f77595c95ea3fb253e9465606946aad289f5599da037f09e7b06c2b4ce",
+ "chksum_sha256": "8cee774c3df78199cb4491893e1ea14d8c9e8bf8b7c1214bfb37e8c7e3dd6217",
"format": 1
},
{
"name": "plugins/modules/mysql_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c66d795038d4ee8fef281f942a936b939a1fbd3a2ba23e4d54ed7b3b47d7ddda",
+ "chksum_sha256": "189fedc5e3f309c1d5ff2ea83d5f9d7cad2df1900a58aee03681089c13090e02",
"format": 1
},
{
"name": "plugins/modules/mysql_query.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b379afe3a4f5ea3d77c5738ad9f4426e33870a7f6d4b679200bfb72272460688",
+ "chksum_sha256": "4ad32cf4d161d446c8ae90fc8e2c49f21200f4162a4aa78abfca1e103ddc137c",
"format": 1
},
{
"name": "plugins/modules/mysql_replication.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "922d024797a958d73462c5bab30c4877db8a509d182402b9f336afad6f8d9a6c",
+ "chksum_sha256": "03e354a0d1fc3efcf958a7c549187f83b64f2a0bd975a160615866dd30d7bedf",
"format": 1
},
{
"name": "plugins/modules/mysql_role.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c10005349310d333fb7911bfe357ce6d9d6d407d4e61f7b256c98f3a0cc93878",
+ "chksum_sha256": "9d5cf95f5462001f080ef5597b027c36db190eeea17104b17a0128fc7f5acb57",
"format": 1
},
{
"name": "plugins/modules/mysql_user.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4ec672963bde8c6d512225bee75a06896a0d0719234d59068e7f4ec754f82cb2",
+ "chksum_sha256": "cb4ca1a4d5b3dd399c71ab07d43e4c8b9dc9bf7a1c2cf90791242dc3a7f97335",
"format": 1
},
{
"name": "plugins/modules/mysql_variables.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a3301591b157740d3c77b8562cd278f8e626f3324741a98eaf14a740ea961135",
+ "chksum_sha256": "44e334271d8c23f015f6ad318328b67fa5f5f75f4f594c13135ac8cc7ecb5d5b",
"format": 1
},
{
@@ -746,7 +746,7 @@
"name": "tests/integration/targets/setup_controller/tasks/verify.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "73cc400b068f45bc2449c791deb0bf602d3a1b5b93254326733b3ece4300c06b",
+ "chksum_sha256": "16ad6d71d64e3b029b4d67502f83d6a3321f801a5ee8e98bcb1ffaa7a6f47763",
"format": 1
},
{
@@ -886,7 +886,7 @@
"name": "tests/integration/targets/test_mysql_db/tasks/state_dump_import.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b022e730780c4ff9071df0bebeaaf6789265e2ef6f9cfbabd1b5a23228b78e67",
+ "chksum_sha256": "92d2da1df27c444a44ab9b966bc1aa59151323a9f723feff7ab7a23996bd8793",
"format": 1
},
{
@@ -918,6 +918,20 @@
"format": 1
},
{
+ "name": "tests/integration/targets/test_mysql_info/files",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/test_mysql_info/files/users_info_create_procedure.sql",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "922c833006f50c3a6ba9f1f612ede6d356a4881abbed00be8d49798ee83a18a9",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/test_mysql_info/meta",
"ftype": "dir",
"chksum_type": null,
@@ -946,6 +960,13 @@
"format": 1
},
{
+ "name": "tests/integration/targets/test_mysql_info/tasks/filter_users_info.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "d0bdd9f57b6bc4675f405d6c8af0de9599b2e69374803946c084df4d76483c1e",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/test_mysql_info/tasks/issue-28.yml",
"ftype": "file",
"chksum_type": "sha256",
@@ -956,7 +977,7 @@
"name": "tests/integration/targets/test_mysql_info/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ecfe0e433cd0468c3fab8f2da767b04effe068fa8b44a16c686801f3bd64feee",
+ "chksum_sha256": "f0fb15a65dfbb875eaf5ff4e7cef8b1f786a724bec084938f45722ba4fc7c6a8",
"format": 1
},
{
@@ -1103,14 +1124,14 @@
"name": "tests/integration/targets/test_mysql_replication/tasks/mysql_replication_channel.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9f8bfabce4c19f9a6acc128ee84e8da916405bbed84f31f19e9d37986f8e596e",
+ "chksum_sha256": "a8d52f907432ad98dd76a66fb0110ba94e777831c23acb08452c2454333e90bc",
"format": 1
},
{
"name": "tests/integration/targets/test_mysql_replication/tasks/mysql_replication_initial.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7855e5b87c17e4ce34c5718cee9c0be79b55abcf8ca342ae50bae03fde7e22a8",
+ "chksum_sha256": "d667eb810ccbc6619a1b0f515235c7c3bbf5579e5166ee56166d22bc915b6629",
"format": 1
},
{
@@ -1173,7 +1194,7 @@
"name": "tests/integration/targets/test_mysql_role/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "98aac442e4be66cf3a9600995379ff46a7b9957358c2402ff3bd9a84fc79e7e0",
+ "chksum_sha256": "d3131bfb97ad6c009c06926341249f28c8009b841992a06e244df018e4b9d6fb",
"format": 1
},
{
@@ -1184,6 +1205,13 @@
"format": 1
},
{
+ "name": "tests/integration/targets/test_mysql_role/tasks/test_column_case_sensitive.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "dc0678ccd9017b7c34be148abbf3376569fdf8ca985c2d7149cc1705eb1b7e27",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/test_mysql_role/tasks/test_priv_subtract.yml",
"ftype": "file",
"chksum_type": "sha256",
@@ -1282,6 +1310,13 @@
"format": 1
},
{
+ "name": "tests/integration/targets/test_mysql_user/tasks/utils/assert_user_password_expire.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "583f31d9b63b441847f5f628bdcc55b966b8ae7529970e5e4c031448bd57a1ef",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/test_mysql_user/tasks/utils/create_user.yml",
"ftype": "file",
"chksum_type": "sha256",
@@ -1334,7 +1369,14 @@
"name": "tests/integration/targets/test_mysql_user/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b471f216d58c90862f192e564df73859521fb7e4395ba38910fc1e53992d72e7",
+ "chksum_sha256": "e233a28e6d60c826bf9426371db1f01f59ca0d42902a2ef746201fa3137cd063",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/test_mysql_user/tasks/test_column_case_sensitive.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "08031e812e21161a3d2dbe03b92741d511e0563a8685409d2f49bef730af5a9c",
"format": 1
},
{
@@ -1345,6 +1387,13 @@
"format": 1
},
{
+ "name": "tests/integration/targets/test_mysql_user/tasks/test_password_expire.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "576ca717899192950e7810d1584a9b9587281e2ca99b28c8cd93957b43e343b5",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/test_mysql_user/tasks/test_priv_append.yml",
"ftype": "file",
"chksum_type": "sha256",
@@ -1408,6 +1457,13 @@
"format": 1
},
{
+ "name": "tests/integration/targets/test_mysql_user/tasks/test_user_attributes.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "967211699ff5ecb1b54f6a534db88060c36f2588c5b30b853aa93000848808e3",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/test_mysql_user/tasks/test_user_grants_with_roles_applied.yml",
"ftype": "file",
"chksum_type": "sha256",
@@ -1527,38 +1583,31 @@
"format": 1
},
{
- "name": "tests/sanity/ignore-2.12.txt",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "26cf6bdacb30652f6105a97ed3695fbfcdce39966654c8f1179427f5ccd10267",
- "format": 1
- },
- {
- "name": "tests/sanity/ignore-2.13.txt",
+ "name": "tests/sanity/ignore-2.14.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "26cf6bdacb30652f6105a97ed3695fbfcdce39966654c8f1179427f5ccd10267",
+ "chksum_sha256": "027977eacb26c23ae808bd0f993bbfd4f65368206ff163a07fe5f0311463cf09",
"format": 1
},
{
- "name": "tests/sanity/ignore-2.14.txt",
+ "name": "tests/sanity/ignore-2.15.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "26cf6bdacb30652f6105a97ed3695fbfcdce39966654c8f1179427f5ccd10267",
+ "chksum_sha256": "d6b04eec2f75f64f71a7942f89bf13a0d46359054e94aab9d89b95676a8794f5",
"format": 1
},
{
- "name": "tests/sanity/ignore-2.15.txt",
+ "name": "tests/sanity/ignore-2.16.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c0db40238b384c184e5e3fc2261d8457fb174721ca6503da105ba173ae4ae203",
+ "chksum_sha256": "d6b04eec2f75f64f71a7942f89bf13a0d46359054e94aab9d89b95676a8794f5",
"format": 1
},
{
- "name": "tests/sanity/ignore-2.16.txt",
+ "name": "tests/sanity/ignore-2.17.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c0db40238b384c184e5e3fc2261d8457fb174721ca6503da105ba173ae4ae203",
+ "chksum_sha256": "d6b04eec2f75f64f71a7942f89bf13a0d46359054e94aab9d89b95676a8794f5",
"format": 1
},
{
@@ -1607,7 +1656,7 @@
"name": "tests/unit/plugins/module_utils/test_mysql.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "20d9ead509f38c46b09e931439e186ce1b678f9ca4ca9cc3242c725c20d05f57",
+ "chksum_sha256": "9e9f549f450946532d3a4f0fde4880131e62383318e954196c2ff8a438924e29",
"format": 1
},
{
@@ -1621,7 +1670,7 @@
"name": "tests/unit/plugins/module_utils/test_mysql_user.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7e705d79f6e69be73ad67c40998df270780757ed8d42e3f36d66562dfceedc4a",
+ "chksum_sha256": "ba9713a572af0894360891a32160852a8b9ebe2b91f512817fd26a1c816b6f05",
"format": 1
},
{
@@ -1649,7 +1698,7 @@
"name": "tests/unit/plugins/modules/test_mysql_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d21791537625289a86302891669eae6260c6f06f2417e28d0345ffad0e988ffa",
+ "chksum_sha256": "539229e1f86eb83fbe151a20269b9785d87ee5d73e569ff91ec1b006a49f9da2",
"format": 1
},
{
@@ -1677,21 +1726,21 @@
"name": "CHANGELOG.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b2aa4c6fb55f7d38aeb3774d4bff2108a8a4bfe71931dc540fd2ad55585baa8d",
+ "chksum_sha256": "9cdedb6a51859ee0917d7ffffaa73996d3801c6bbde74228904ab88e47e4b2f0",
"format": 1
},
{
"name": "CONTRIBUTING.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b0c50cf3715d59964a341dc651a6f626322209ef9fa8c0d03047d3a2b2e420a4",
+ "chksum_sha256": "1441827f0c03057047e9451c3abf9f19a73e9e31ce84cc458fe225a65e6dcbac",
"format": 1
},
{
"name": "CONTRIBUTORS",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2f07f95d703ea52b586842f9a918bf0c7319f8745c0b11099b7f4b6d334fb8cc",
+ "chksum_sha256": "2b3af63595ec0506a0e1b078de18e875d392af93558ecbaa01371e70a181babe",
"format": 1
},
{
@@ -1705,7 +1754,7 @@
"name": "MAINTAINERS",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "edb7885116c564025a692f93e694dcefa5af95ede853cd86e3aed5bf91bb5a7f",
+ "chksum_sha256": "95adaa9e221938f88c50163021d0ea45c35540196b55c89ff9c209dd935d38c2",
"format": 1
},
{
@@ -1733,14 +1782,14 @@
"name": "README.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8f9a28ac1c7026f63d93849398c90b42a1414cebb40e06efff39e64fd6e2e332",
+ "chksum_sha256": "2402f4a603c9077d343fbb9956f79af16ca8b334357752c8de64c3a471a9dcde",
"format": 1
},
{
"name": "TESTING.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d511d97260c97ffbd4ac1c83dda64b612a2924e19f2dd94b5fe473a3f0c4278d",
+ "chksum_sha256": "31a3aad08369f80c20d083c7a34439f99931b2dd8f8456d9f34c047f1644420c",
"format": 1
},
{
diff --git a/ansible_collections/community/mysql/MAINTAINERS b/ansible_collections/community/mysql/MAINTAINERS
index 2228e0044..73feaa42c 100644
--- a/ansible_collections/community/mysql/MAINTAINERS
+++ b/ansible_collections/community/mysql/MAINTAINERS
@@ -1,6 +1,3 @@
betanummeric
-bmalynovytch
-Jorge-Rodriguez
-rsicart
laurent-indermuehle
-Andersson007 (andersson007_ in #ansible-community IRC/Matrix)
+Andersson007
diff --git a/ansible_collections/community/mysql/MANIFEST.json b/ansible_collections/community/mysql/MANIFEST.json
index 8df21709b..244b4d287 100644
--- a/ansible_collections/community/mysql/MANIFEST.json
+++ b/ansible_collections/community/mysql/MANIFEST.json
@@ -2,7 +2,7 @@
"collection_info": {
"namespace": "community",
"name": "mysql",
- "version": "3.7.2",
+ "version": "3.9.0",
"authors": [
"Ansible community"
],
@@ -25,7 +25,7 @@
"name": "FILES.json",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8d05eab7e7ecee1701730919ad3879343876d2b8c4eabd9abe159d0c771552a3",
+ "chksum_sha256": "e89323c7dfbe033bbd3c2a6e1709e8ca4773970b6040f5fdcf9a9912f282458d",
"format": 1
},
"format": 1
diff --git a/ansible_collections/community/mysql/README.md b/ansible_collections/community/mysql/README.md
index 5cb22712f..40264d259 100644
--- a/ansible_collections/community/mysql/README.md
+++ b/ansible_collections/community/mysql/README.md
@@ -3,6 +3,12 @@
This collection is a part of the Ansible package.
+## Our mission
+
+The Ansible `community.mysql` collection goals are to produce and maintain simple,
+flexible, and powerful open-source software for automating MySQL and MariaDB related tasks
+providing good documentation for easy deployment and use.
+
## Code of Conduct
We follow the [Ansible Code of Conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html) in all our interactions within this project.
@@ -17,7 +23,7 @@ We are actively accepting new contributors.
Any kind of contribution is very welcome.
-You don't know how to start? Refer to our [contribution guide](https://github.com/ansible-collections/community.mysql/blob/main/CONTRIBUTING.md)!
+You don't know how to start? Refer to our [contribution guide](https://github.com/ansible-collections/community.mysql/blob/main/CONTRIBUTING.md) or ask us in the [#mysql:ansible.com room](https://matrix.to/#/#mysql:ansible.com) on [Matrix](https://docs.ansible.com/ansible/devel/community/communication.html#ansible-community-on-matrix)!
## Collection maintenance
@@ -34,9 +40,21 @@ They also should be subscribed to Ansible's [The Bullhorn newsletter](https://do
## Communication
+> The `GitHub Discussions` feature is disabled in this repository. Use the `mysql` tag on the forum in the [Project Discussions](https://forum.ansible.com/new-topic?title=topic%20title&body=topic%20body&category=project&tags=mysql) or [Get Help](https://forum.ansible.com/new-topic?title=topic%20title&body=topic%20body&category=help&tags=mysql) category instead.
+
We announce releases and important changes through Ansible's [The Bullhorn newsletter](https://eepurl.com/gZmiEP). Be sure you are subscribed.
-Join us on Matrix in the `#mysql:ansible.com` [room](https://matrix.to/#/#mysql:ansible.com), the `#users:ansible.com` [room](https://matrix.to/#/#users:ansible.com) (general use questions and support), `#ansible-community:ansible.com` [room](https://matrix.to/#/#community:ansible.com) (community and collection development questions), and other Matrix rooms or corresponding bridged Libera.Chat channels. See the [Ansible Communication Guide](https://docs.ansible.com/ansible/devel/community/communication.html) for details.
+Join [our team](https://forum.ansible.com/g/MySQLTeam) on:
+* The Ansible forums:
+ * [News & Announcements](https://forum.ansible.com/c/news/5/none)
+ * [Get Help](https://forum.ansible.com/c/help/6/none)
+ * [Social Spaces](https://forum.ansible.com/c/chat/4)
+ * [Posts tagged 'mysql'](https://forum.ansible.com/tag/mysql)
+* Matrix:
+ * `#mysql:ansible.com` [room](https://matrix.to/#/#mysql:ansible.com): questions on how to contribute and use this collection.
+ * `#users:ansible.com` [room](https://matrix.to/#/#users:ansible.com): general use questions and support.
+ * `#ansible-community:ansible.com` [room](https://matrix.to/#/#community:ansible.com): community and collection development questions.
+ * other Matrix rooms; see the [Ansible Communication Guide](https://docs.ansible.com/ansible/devel/community/communication.html) for details.
We take part in the global quarterly [Ansible Contributor Summit](https://github.com/ansible/community/wiki/Contributor-Summit) virtually or in-person. Track [The Bullhorn newsletter](https://eepurl.com/gZmiEP) and join us.
@@ -44,9 +62,11 @@ For more information about communication, refer to the [Ansible Communication gu
## Governance
+We, [the MySQL team](https://forum.ansible.com/g/MySQLTeam), use [the forum](https://forum.ansible.com/tag/mysql) posts tagged with `mysql` for general announcements and discussions.
+
The process of decision making in this collection is based on discussing and finding consensus among participants.
-Every voice is important and every idea is valuable. If you have something on your mind, create an issue or dedicated discussion and let's discuss it!
+Every voice is important and every idea is valuable. If you have something on your mind, create an issue or dedicated forum [discussion](https://forum.ansible.com/new-topic?title=topic%20title&body=topic%20body&category=project&tags=mysql) and let's discuss it!
## Included content
@@ -62,12 +82,12 @@ Every voice is important and every idea is valuable. If you have something on yo
## Releases Support Timeline
-It has been [decided](https://github.com/ansible-collections/community.mysql/discussions/537) to maintain each major release (1.x.y, 2.x.y, ...) for two years after the next major version is released.
+We maintain each major release (1.x.y, 2.x.y, ...) for two years after the next major version is released.
Here is the table for the support timeline:
- 1.x.y: released 2020-08-17, EOL
-- 2.x.y: released 2021-04-15, supported until 2023-12-01
+- 2.x.y: released 2021-04-15, EOL
- 3.x.y: released 2021-12-01, current
- 4.x.y: To be released
@@ -76,9 +96,9 @@ Here is the table for the support timeline:
### ansible-core
-- 2.12
-- 2.13
-- 2.14
+- stable-2.14
+- stable-2.15
+- stable-2.16
- current development version
### Databases
diff --git a/ansible_collections/community/mysql/TESTING.md b/ansible_collections/community/mysql/TESTING.md
index 7bbafc31d..9e0840a10 100644
--- a/ansible_collections/community/mysql/TESTING.md
+++ b/ansible_collections/community/mysql/TESTING.md
@@ -52,6 +52,8 @@ The Makefile accept the following options
- "stable-2.12"
- "stable-2.13"
- "stable-2.14"
+ - "stable-2.15"
+ - "stable-2.16"
- "devel"
- Description: Version of ansible to install in a venv to run ansible-test
@@ -75,7 +77,7 @@ The Makefile accept the following options
- `connector_name`
- Mandatory: true
- Choices:
- - "pymysql
+ - "pymysql"
- "mysqlclient"
- Description: The python package of the connector to use. In addition to selecting the test container, this value is also used for tests filtering: `when: connector_name == 'pymysql'`.
@@ -151,7 +153,7 @@ python run_all_tests.py
### Add a new Python, Connector or Database version
-You can look into `[.github/workflows/ansible-test-plugins.yml](https://github.com/ansible-collections/community.mysql/tree/main/.github/workflows)` to see how those containers are built using [build-docker-image.yml](https://github.com/ansible-collections/community.mysql/blob/main/.github/workflows/build-docker-image.yml) and all [docker-image-xxx.yml](https://github.com/ansible-collections/community.mysql/blob/main/.github/workflows/docker-image-mariadb103-py38-mysqlclient201.yml) files.
+You can look into [.github/workflows/ansible-test-plugins.yml](https://github.com/ansible-collections/community.mysql/tree/main/.github/workflows) to see how those containers are built using [build-docker-image.yml](https://github.com/ansible-collections/community.mysql/blob/main/.github/workflows/build-docker-image.yml) and all [docker-image-xxx.yml](https://github.com/ansible-collections/community.mysql/blob/main/.github/workflows/docker-image-mariadb103-py38-mysqlclient201.yml) files.
1. Add a workflow in [.github/workflows/](.github/workflows)
1. Add a new folder in [test-containers](test-containers) containing a new Dockerfile. Your container must contains 3 things:
diff --git a/ansible_collections/community/mysql/changelogs/changelog.yaml b/ansible_collections/community/mysql/changelogs/changelog.yaml
index e3431f34f..eb4264dcc 100644
--- a/ansible_collections/community/mysql/changelogs/changelog.yaml
+++ b/ansible_collections/community/mysql/changelogs/changelog.yaml
@@ -346,3 +346,63 @@ releases:
- 3.7.2.yml
- 553_fix_connection_arguemnts_for_old_mysqldb_driver.yaml
release_date: '2023-05-25'
+ 3.8.0:
+ changes:
+ major_changes:
+ - The community.mysql collection no longer supports ``ansible-core 2.12`` and
+ ``ansible-core 2.13``. While we take no active measures to prevent usage and
+ there are no plans to introduce incompatible code to the modules, we will
+ stop testing those versions. Both are or will soon be End of Life and if you
+ are still using them, you should consider upgrading to the ``latest Ansible
+ / ansible-core 2.15 or later`` as soon as possible (https://github.com/ansible-collections/community.mysql/pull/574).
+ - mysql_role - the ``column_case_sensitive`` argument's default value will be
+ changed to ``true`` in community.mysql 4.0.0. If your playbook expected the
+ column to be automatically uppercased for your roles privileges, you should
+ set this to false explicitly (https://github.com/ansible-collections/community.mysql/issues/578).
+ - mysql_user - the ``column_case_sensitive`` argument's default value will be
+ changed to ``true`` in community.mysql 4.0.0. If your playbook expected the
+ column to be automatically uppercased for your users privileges, you should
+ set this to false explicitly (https://github.com/ansible-collections/community.mysql/issues/577).
+ minor_changes:
+ - mysql_info - add filter ``users_info`` (https://github.com/ansible-collections/community.mysql/pull/580).
+ - mysql_role - add ``column_case_sensitive`` option to prevent field names from
+ being uppercased (https://github.com/ansible-collections/community.mysql/pull/569).
+ - mysql_user - add ``column_case_sensitive`` option to prevent field names from
+ being uppercased (https://github.com/ansible-collections/community.mysql/pull/569).
+ release_summary: 'This is the minor release of the ``community.mysql`` collection.
+
+ This changelog contains all changes to the modules and plugins in this
+
+ collection that have been made after the previous release.'
+ fragments:
+ - 3.8.0.yml
+ - 569_fix_column_uppercasing.yml
+ - drop_ansible_core_2_12_and_2_13.yml
+ - lie_mysql_info_users_info.yml
+ release_date: '2023-10-25'
+ 3.9.0:
+ changes:
+ bugfixes:
+ - mysql_info - the ``slave_status`` filter was returning an empty list on MariaDB
+ with multiple replication channels. It now returns all channels by running
+ ``SHOW ALL SLAVES STATUS`` for MariaDB servers (https://github.com/ansible-collections/community.mysql/issues/603).
+ major_changes:
+ - Collection version 2.*.* is EOL, no more bugfixes will be backported. Please
+ consider upgrading to the latest version.
+ minor_changes:
+ - mysql_user - add the ``password_expire`` and ``password_expire_interval``
+ arguments to implement the password expiration management for mysql user (https://github.com/ansible-collections/community.mysql/pull/598).
+ - mysql_user - add user attribute support via the ``attributes`` parameter and
+ return value (https://github.com/ansible-collections/community.mysql/pull/604).
+ release_summary: 'This is a minor release of the ``community.mysql`` collection.
+
+ This changelog contains all changes to the modules and plugins in this
+
+ collection that have been made after the previous release.'
+ fragments:
+ - 0-stable-2-eol.yml
+ - 3.9.0.yml
+ - 598-password_expire-support-for-mysql_user.yml
+ - 602-show-all-slaves-status.yaml
+ - 604-user-attributes.yaml
+ release_date: '2024-02-22'
diff --git a/ansible_collections/community/mysql/plugins/doc_fragments/mysql.py b/ansible_collections/community/mysql/plugins/doc_fragments/mysql.py
index 939126cba..27ec6509a 100644
--- a/ansible_collections/community/mysql/plugins/doc_fragments/mysql.py
+++ b/ansible_collections/community/mysql/plugins/doc_fragments/mysql.py
@@ -110,4 +110,7 @@ notes:
- Alternatively, to avoid using I(login_unix_socket) argument on each invocation you can specify the socket path
using the `socket` option in your MySQL config file (usually C(~/.my.cnf)) on the destination host, for
example C(socket=/var/lib/mysql/mysql.sock).
+attributes:
+ check_mode:
+ description: Can run in check_mode and return changed status prediction without modifying target.
'''
diff --git a/ansible_collections/community/mysql/plugins/module_utils/implementations/mariadb/user.py b/ansible_collections/community/mysql/plugins/module_utils/implementations/mariadb/user.py
index c1d2b6133..cdc14b217 100644
--- a/ansible_collections/community/mysql/plugins/module_utils/implementations/mariadb/user.py
+++ b/ansible_collections/community/mysql/plugins/module_utils/implementations/mariadb/user.py
@@ -23,3 +23,9 @@ def server_supports_alter_user(cursor):
version = get_server_version(cursor)
return LooseVersion(version) >= LooseVersion("10.2")
+
+
+def server_supports_password_expire(cursor):
+ version = get_server_version(cursor)
+
+ return LooseVersion(version) >= LooseVersion("10.4.3")
diff --git a/ansible_collections/community/mysql/plugins/module_utils/implementations/mysql/user.py b/ansible_collections/community/mysql/plugins/module_utils/implementations/mysql/user.py
index 1bdad5740..4e41c0542 100644
--- a/ansible_collections/community/mysql/plugins/module_utils/implementations/mysql/user.py
+++ b/ansible_collections/community/mysql/plugins/module_utils/implementations/mysql/user.py
@@ -24,3 +24,9 @@ def server_supports_alter_user(cursor):
version = get_server_version(cursor)
return LooseVersion(version) >= LooseVersion("5.6")
+
+
+def server_supports_password_expire(cursor):
+ version = get_server_version(cursor)
+
+ return LooseVersion(version) >= LooseVersion("5.7")
diff --git a/ansible_collections/community/mysql/plugins/module_utils/mysql.py b/ansible_collections/community/mysql/plugins/module_utils/mysql.py
index b95d20d0d..10ccfcf44 100644
--- a/ansible_collections/community/mysql/plugins/module_utils/mysql.py
+++ b/ansible_collections/community/mysql/plugins/module_utils/mysql.py
@@ -207,6 +207,13 @@ def get_server_version(cursor):
return version_str
+def get_server_implementation(cursor):
+ if 'mariadb' in get_server_version(cursor).lower():
+ return "mariadb"
+ else:
+ return "mysql"
+
+
def set_session_vars(module, cursor, session_vars):
"""Set session vars."""
for var, value in session_vars.items():
diff --git a/ansible_collections/community/mysql/plugins/module_utils/user.py b/ansible_collections/community/mysql/plugins/module_utils/user.py
index a63ad89b5..17ad4b0c2 100644
--- a/ansible_collections/community/mysql/plugins/module_utils/user.py
+++ b/ansible_collections/community/mysql/plugins/module_utils/user.py
@@ -10,6 +10,7 @@ __metaclass__ = type
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
import string
+import json
import re
from ansible.module_utils.six import iteritems
@@ -112,35 +113,57 @@ def get_grants(cursor, user, host):
return grants.split(", ")
-def get_existing_authentication(cursor, user):
+def get_existing_authentication(cursor, user, host):
# Return the plugin and auth_string if there is exactly one distinct existing plugin and auth_string.
cursor.execute("SELECT VERSION()")
- if 'mariadb' in cursor.fetchone()[0].lower():
+ srv_type = cursor.fetchone()
+ # Mysql_info use a DictCursor so we must convert back to a list
+ # otherwise we get KeyError 0
+ if isinstance(srv_type, dict):
+ srv_type = list(srv_type.values())
+
+ if 'mariadb' in srv_type[0].lower():
# before MariaDB 10.2.19 and 10.3.11, "password" and "authentication_string" can differ
# when using mysql_native_password
cursor.execute("""select plugin, auth from (
select plugin, password as auth from mysql.user where user=%(user)s
+ and host=%(host)s
union select plugin, authentication_string as auth from mysql.user where user=%(user)s
- ) x group by plugin, auth limit 2
- """, {'user': user})
+ and host=%(host)s) x group by plugin, auth limit 2
+ """, {'user': user, 'host': host})
else:
- cursor.execute("""select plugin, authentication_string as auth from mysql.user where user=%(user)s
- group by plugin, authentication_string limit 2""", {'user': user})
+ cursor.execute("""select plugin, authentication_string as auth
+ from mysql.user where user=%(user)s and host=%(host)s
+ group by plugin, authentication_string limit 2""", {'user': user, 'host': host})
rows = cursor.fetchall()
- if len(rows) == 1:
- return {'plugin': rows[0][0], 'auth_string': rows[0][1]}
+
+ # Mysql_info use a DictCursor so we must convert back to a list
+ # otherwise we get KeyError 0
+ if isinstance(rows, dict):
+ rows = list(rows.values())
+
+ if isinstance(rows[0], tuple):
+ return {'plugin': rows[0][0], 'plugin_auth_string': rows[0][1]}
+
+ if isinstance(rows[0], dict):
+ return {'plugin': rows[0].get('plugin'), 'plugin_auth_string': rows[0].get('auth')}
return None
def user_add(cursor, user, host, host_all, password, encrypted,
plugin, plugin_hash_string, plugin_auth_string, new_priv,
- tls_requires, check_mode, reuse_existing_password):
+ attributes, tls_requires, reuse_existing_password, module,
+ password_expire, password_expire_interval):
+ # If attributes are set, perform a sanity check to ensure server supports user attributes before creating user
+ if attributes and not get_attribute_support(cursor):
+ module.fail_json(msg="user attributes were specified but the server does not support user attributes")
+
# we cannot create users without a proper hostname
if host_all:
- return {'changed': False, 'password_changed': False}
+ return {'changed': False, 'password_changed': False, 'attributes': attributes}
- if check_mode:
- return {'changed': True, 'password_changed': None}
+ if module.check_mode:
+ return {'changed': True, 'password_changed': None, 'attributes': attributes}
# Determine what user management method server uses
old_user_mgmt = impl.use_old_user_mgmt(cursor)
@@ -149,7 +172,7 @@ def user_add(cursor, user, host, host_all, password, encrypted,
used_existing_password = False
if reuse_existing_password:
- existing_auth = get_existing_authentication(cursor, user)
+ existing_auth = get_existing_authentication(cursor, user, host)
if existing_auth:
plugin = existing_auth['plugin']
plugin_hash_string = existing_auth['auth_string']
@@ -183,12 +206,25 @@ def user_add(cursor, user, host, host_all, password, encrypted,
query_with_args_and_tls_requires = query_with_args + (tls_requires,)
cursor.execute(*mogrify(*query_with_args_and_tls_requires))
+ if password_expire:
+ if not impl.server_supports_password_expire(cursor):
+ module.fail_json(msg="The server version does not match the requirements "
+ "for password_expire parameter. See module's documentation.")
+ set_password_expire(cursor, user, host, password_expire, password_expire_interval)
+
if new_priv is not None:
for db_table, priv in iteritems(new_priv):
privileges_grant(cursor, user, host, db_table, priv, tls_requires)
if tls_requires is not None:
privileges_grant(cursor, user, host, "*.*", get_grants(cursor, user, host), tls_requires)
- return {'changed': True, 'password_changed': not used_existing_password}
+
+ final_attributes = None
+
+ if attributes:
+ cursor.execute("ALTER USER %s@%s ATTRIBUTE %s", (user, host, json.dumps(attributes)))
+ final_attributes = attributes_get(cursor, user, host)
+
+ return {'changed': True, 'password_changed': not used_existing_password, 'attributes': final_attributes}
def is_hash(password):
@@ -201,7 +237,8 @@ def is_hash(password):
def user_mod(cursor, user, host, host_all, password, encrypted,
plugin, plugin_hash_string, plugin_auth_string, new_priv,
- append_privs, subtract_privs, tls_requires, module, role=False, maria_role=False):
+ append_privs, subtract_privs, attributes, tls_requires, module,
+ password_expire, password_expire_interval, role=False, maria_role=False):
changed = False
msg = "User unchanged"
grant_option = False
@@ -261,27 +298,48 @@ def user_mod(cursor, user, host, host_all, password, encrypted,
if current_pass_hash != encrypted_password:
password_changed = True
msg = "Password updated"
- if module.check_mode:
- return {'changed': True, 'msg': msg, 'password_changed': password_changed}
- if old_user_mgmt:
- cursor.execute("SET PASSWORD FOR %s@%s = %s", (user, host, encrypted_password))
- msg = "Password updated (old style)"
- else:
- try:
- cursor.execute("ALTER USER %s@%s IDENTIFIED WITH mysql_native_password AS %s", (user, host, encrypted_password))
- msg = "Password updated (new style)"
- except (mysql_driver.Error) as e:
- # https://stackoverflow.com/questions/51600000/authentication-string-of-root-user-on-mysql
- # Replacing empty root password with new authentication mechanisms fails with error 1396
- if e.args[0] == 1396:
- cursor.execute(
- "UPDATE mysql.user SET plugin = %s, authentication_string = %s, Password = '' WHERE User = %s AND Host = %s",
- ('mysql_native_password', encrypted_password, user, host)
- )
- cursor.execute("FLUSH PRIVILEGES")
- msg = "Password forced update"
- else:
- raise e
+ if not module.check_mode:
+ if old_user_mgmt:
+ cursor.execute("SET PASSWORD FOR %s@%s = %s", (user, host, encrypted_password))
+ msg = "Password updated (old style)"
+ else:
+ try:
+ cursor.execute("ALTER USER %s@%s IDENTIFIED WITH mysql_native_password AS %s", (user, host, encrypted_password))
+ msg = "Password updated (new style)"
+ except (mysql_driver.Error) as e:
+ # https://stackoverflow.com/questions/51600000/authentication-string-of-root-user-on-mysql
+ # Replacing empty root password with new authentication mechanisms fails with error 1396
+ if e.args[0] == 1396:
+ cursor.execute(
+ "UPDATE mysql.user SET plugin = %s, authentication_string = %s, Password = '' WHERE User = %s AND Host = %s",
+ ('mysql_native_password', encrypted_password, user, host)
+ )
+ cursor.execute("FLUSH PRIVILEGES")
+ msg = "Password forced update"
+ else:
+ raise e
+ changed = True
+
+ # Handle password expiration
+ if bool(password_expire):
+ if not impl.server_supports_password_expire(cursor):
+ module.fail_json(msg="The server version does not match the requirements "
+ "for password_expire parameter. See module's documentation.")
+ update = False
+ mariadb_role = True if "mariadb" in str(impl.__name__) else False
+ current_password_policy = get_password_expiration_policy(cursor, user, host, maria_role=mariadb_role)
+ password_expired = is_password_expired(cursor, user, host)
+ # Check if changes needed to be applied.
+ if not ((current_password_policy == -1 and password_expire == "default") or
+ (current_password_policy == 0 and password_expire == "never") or
+ (current_password_policy == password_expire_interval and password_expire == "interval") or
+ (password_expire == 'now' and password_expired)):
+
+ update = True
+
+ if not module.check_mode:
+ set_password_expire(cursor, user, host, password_expire, password_expire_interval)
+ password_changed = True
changed = True
# Handle plugin authentication
@@ -335,9 +393,8 @@ def user_mod(cursor, user, host, host_all, password, encrypted,
if db_table not in new_priv:
if user != "root" and "PROXY" not in priv:
msg = "Privileges updated"
- if module.check_mode:
- return {'changed': True, 'msg': msg, 'password_changed': password_changed}
- privileges_revoke(cursor, user, host, db_table, priv, grant_option, maria_role)
+ if not module.check_mode:
+ privileges_revoke(cursor, user, host, db_table, priv, grant_option, maria_role)
changed = True
# If the user doesn't currently have any privileges on a db.table, then
@@ -346,9 +403,8 @@ def user_mod(cursor, user, host, host_all, password, encrypted,
for db_table, priv in iteritems(new_priv):
if db_table not in curr_priv:
msg = "New privileges granted"
- if module.check_mode:
- return {'changed': True, 'msg': msg, 'password_changed': password_changed}
- privileges_grant(cursor, user, host, db_table, priv, tls_requires, maria_role)
+ if not module.check_mode:
+ privileges_grant(cursor, user, host, db_table, priv, tls_requires, maria_role)
changed = True
# If the db.table specification exists in both the user's current privileges
@@ -387,17 +443,58 @@ def user_mod(cursor, user, host, host_all, password, encrypted,
if len(grant_privs) + len(revoke_privs) > 0:
msg = "Privileges updated: granted %s, revoked %s" % (grant_privs, revoke_privs)
- if module.check_mode:
- return {'changed': True, 'msg': msg, 'password_changed': password_changed}
- if len(revoke_privs) > 0:
- privileges_revoke(cursor, user, host, db_table, revoke_privs, grant_option, maria_role)
- if len(grant_privs) > 0:
- privileges_grant(cursor, user, host, db_table, grant_privs, tls_requires, maria_role)
+ if not module.check_mode:
+ if len(revoke_privs) > 0:
+ privileges_revoke(cursor, user, host, db_table, revoke_privs, grant_option, maria_role)
+ if len(grant_privs) > 0:
+ privileges_grant(cursor, user, host, db_table, grant_privs, tls_requires, maria_role)
+ else:
+ changed = True
# after privilege manipulation, compare privileges from before and now
after_priv = privileges_get(cursor, user, host, maria_role)
changed = changed or (curr_priv != after_priv)
+ # Handle attributes
+ attribute_support = get_attribute_support(cursor)
+ final_attributes = {}
+
+ if attributes:
+ if not attribute_support:
+ module.fail_json(msg="user attributes were specified but the server does not support user attributes")
+ else:
+ current_attributes = attributes_get(cursor, user, host)
+
+ if current_attributes is None:
+ current_attributes = {}
+
+ attributes_to_change = {}
+
+ for key, value in attributes.items():
+ if key not in current_attributes or current_attributes[key] != value:
+ attributes_to_change[key] = value
+
+ if attributes_to_change:
+ msg = "Attributes updated: %s" % (", ".join(["%s: %s" % (key, value) for key, value in attributes_to_change.items()]))
+
+ # Calculate final attributes by re-running attributes_get when not in check mode, and merge dictionaries when in check mode
+ if not module.check_mode:
+ cursor.execute("ALTER USER %s@%s ATTRIBUTE %s", (user, host, json.dumps(attributes_to_change)))
+ final_attributes = attributes_get(cursor, user, host)
+ else:
+ # Final if statements excludes items whose values are None in attributes_to_change, i.e. attributes that will be deleted
+ final_attributes = {k: v for d in (current_attributes, attributes_to_change) for k, v in d.items() if k not in attributes_to_change or
+ attributes_to_change[k] is not None}
+
+ # Convert empty dict to None per return value requirements
+ final_attributes = final_attributes if final_attributes else None
+ changed = True
+ else:
+ final_attributes = current_attributes
+ else:
+ if attribute_support:
+ final_attributes = attributes_get(cursor, user, host)
+
if role:
continue
@@ -405,24 +502,23 @@ def user_mod(cursor, user, host, host_all, password, encrypted,
current_requires = get_tls_requires(cursor, user, host)
if current_requires != tls_requires:
msg = "TLS requires updated"
- if module.check_mode:
- return {'changed': True, 'msg': msg, 'password_changed': password_changed}
- if not old_user_mgmt:
- pre_query = "ALTER USER"
- else:
- pre_query = "GRANT %s ON *.* TO" % ",".join(get_grants(cursor, user, host))
+ if not module.check_mode:
+ if not old_user_mgmt:
+ pre_query = "ALTER USER"
+ else:
+ pre_query = "GRANT %s ON *.* TO" % ",".join(get_grants(cursor, user, host))
- if tls_requires is not None:
- query = " ".join((pre_query, "%s@%s"))
- query_with_args = mogrify_requires(query, (user, host), tls_requires)
- else:
- query = " ".join((pre_query, "%s@%s REQUIRE NONE"))
- query_with_args = query, (user, host)
+ if tls_requires is not None:
+ query = " ".join((pre_query, "%s@%s"))
+ query_with_args = mogrify_requires(query, (user, host), tls_requires)
+ else:
+ query = " ".join((pre_query, "%s@%s REQUIRE NONE"))
+ query_with_args = query, (user, host)
- cursor.execute(*query_with_args)
+ cursor.execute(*query_with_args)
changed = True
- return {'changed': changed, 'msg': msg, 'password_changed': password_changed}
+ return {'changed': changed, 'msg': msg, 'password_changed': password_changed, 'attributes': final_attributes}
def user_delete(cursor, user, host, host_all, check_mode):
@@ -478,6 +574,12 @@ def privileges_get(cursor, user, host, maria_role=False):
return x
for grant in grants:
+
+ # Mysql_info use a DictCursor so we must convert back to a list
+ # otherwise we get KeyError 0
+ if isinstance(grant, dict):
+ grant = list(grant.values())
+
if not maria_role:
res = re.match("""GRANT (.+) ON (.+) TO (['`"]).*\\3@(['`"]).*\\4( IDENTIFIED BY PASSWORD (['`"]).+\\6)? ?(.*)""", grant[0])
else:
@@ -627,7 +729,7 @@ def sort_column_order(statement):
return '%s(%s)' % (priv_name, ', '.join(columns))
-def privileges_unpack(priv, mode, ensure_usage=True):
+def privileges_unpack(priv, mode, column_case_sensitive, ensure_usage=True):
""" Take a privileges string, typically passed as a parameter, and unserialize
it into a dictionary, the same format as privileges_get() above. We have this
custom format to avoid using YAML/JSON strings inside YAML playbooks. Example
@@ -663,9 +765,14 @@ def privileges_unpack(priv, mode, ensure_usage=True):
pieces[0] = object_type + '.'.join(dbpriv)
if '(' in pieces[1]:
- output[pieces[0]] = re.split(r',\s*(?=[^)]*(?:\(|$))', pieces[1].upper())
- for i in output[pieces[0]]:
- privs.append(re.sub(r'\s*\(.*\)', '', i))
+ if column_case_sensitive is True:
+ output[pieces[0]] = re.split(r',\s*(?=[^)]*(?:\(|$))', pieces[1])
+ for i in output[pieces[0]]:
+ privs.append(re.sub(r'\s*\(.*\)', '', i))
+ else:
+ output[pieces[0]] = re.split(r',\s*(?=[^)]*(?:\(|$))', pieces[1].upper())
+ for i in output[pieces[0]]:
+ privs.append(re.sub(r'\s*\(.*\)', '', i))
else:
output[pieces[0]] = pieces[1].upper().split(',')
privs = output[pieces[0]]
@@ -715,6 +822,14 @@ def privileges_grant(cursor, user, host, db_table, priv, tls_requires, maria_rol
priv_string = ",".join([p for p in priv if p not in ('GRANT', )])
query = ["GRANT %s ON %s" % (priv_string, db_table)]
+ # MySQL and MariaDB don't store roles in the user table the same manner:
+ # select user, host from mysql.user;
+ # +------------------+-----------+
+ # | user | host |
+ # +------------------+-----------+
+ # | role_foo | % | <- MySQL
+ # | role_foo | | <- MariaDB
+ # +------------------+-----------+
if not maria_role:
query.append("TO %s@%s")
params = (user, host)
@@ -772,6 +887,11 @@ def get_resource_limits(cursor, user, host):
cursor.execute(query, (user, host))
res = cursor.fetchone()
+ # Mysql_info use a DictCursor so we must convert back to a list
+ # otherwise we get KeyError 0
+ if isinstance(res, dict):
+ res = list(res.values())
+
if not res:
return None
@@ -783,11 +903,22 @@ def get_resource_limits(cursor, user, host):
}
cursor.execute("SELECT VERSION()")
- if 'mariadb' in cursor.fetchone()[0].lower():
+ srv_type = cursor.fetchone()
+ # Mysql_info use a DictCursor so we must convert back to a list
+ # otherwise we get KeyError 0
+ if isinstance(srv_type, dict):
+ srv_type = list(srv_type.values())
+
+ if 'mariadb' in srv_type[0].lower():
query = ('SELECT max_statement_time AS MAX_STATEMENT_TIME '
'FROM mysql.user WHERE User = %s AND Host = %s')
cursor.execute(query, (user, host))
res_max_statement_time = cursor.fetchone()
+
+ # Mysql_info use a DictCursor so we must convert back to a list
+ # otherwise we get KeyError 0
+ if isinstance(res_max_statement_time, dict):
+ res_max_statement_time = list(res_max_statement_time.values())
current_limits['MAX_STATEMENT_TIME'] = res_max_statement_time[0]
return current_limits
@@ -872,6 +1003,111 @@ def limit_resources(module, cursor, user, host, resource_limits, check_mode):
return True
+def set_password_expire(cursor, user, host, password_expire, password_expire_interval):
+ """Fuction to set passowrd expiration for user.
+
+ Args:
+ cursor (cursor): DB driver cursor object.
+ user (str): User name.
+ host (str): User hostname.
+ password_expire (str): Password expiration mode.
+ password_expire_days (int): Invterval of days password expires.
+ """
+ if password_expire.lower() == "never":
+ statement = "PASSWORD EXPIRE NEVER"
+ elif password_expire.lower() == "default":
+ statement = "PASSWORD EXPIRE DEFAULT"
+ elif password_expire.lower() == "interval":
+ statement = "PASSWORD EXPIRE INTERVAL %d DAY" % (password_expire_interval)
+ elif password_expire.lower() == "now":
+ statement = "PASSWORD EXPIRE"
+
+ cursor.execute("ALTER USER %s@%s " + statement, (user, host))
+
+
+def get_password_expiration_policy(cursor, user, host, maria_role=False):
+ """Function to get password policy for user.
+
+ Args:
+ cursor (cursor): DB driver cursor object.
+ user (str): User name.
+ host (str): User hostname.
+ maria_role (bool, optional): mariadb or mysql. Defaults to False.
+
+ Returns:
+ policy (int): Current users password policy.
+ """
+ if not maria_role:
+ statement = "SELECT IFNULL(password_lifetime, -1) FROM mysql.user \
+ WHERE User = %s AND Host = %s", (user, host)
+ else:
+ statement = "SELECT JSON_EXTRACT(Priv, '$.password_lifetime') AS password_lifetime \
+ FROM mysql.global_priv \
+ WHERE User = %s AND Host = %s", (user, host)
+ cursor.execute(*statement)
+ policy = cursor.fetchone()[0]
+ return int(policy)
+
+
+def is_password_expired(cursor, user, host):
+ """Function to check if password is expired
+
+ Args:
+ cursor (cursor): DB driver cursor object.
+ user (str): User name.
+ host (str): User hostname.
+
+ Returns:
+ expired (bool): True if expired, else False.
+ """
+ statement = "SELECT password_expired FROM mysql.user \
+ WHERE User = %s AND Host = %s", (user, host)
+ cursor.execute(*statement)
+ expired = cursor.fetchone()[0]
+ if str(expired) == "Y":
+ return True
+ return False
+
+
+def get_attribute_support(cursor):
+ """Checks if the MySQL server supports user attributes.
+
+ Args:
+ cursor (cursor): DB driver cursor object.
+ Returns:
+ True if attributes are supported, False if they are not.
+ """
+ try:
+ # information_schema.tables does not hold the tables within information_schema itself
+ cursor.execute("SELECT attribute FROM INFORMATION_SCHEMA.USER_ATTRIBUTES LIMIT 0")
+ cursor.fetchone()
+ except mysql_driver.Error:
+ return False
+
+ return True
+
+
+def attributes_get(cursor, user, host):
+ """Get attributes for a given user.
+
+ Args:
+ cursor (cursor): DB driver cursor object.
+ user (str): User name.
+ host (str): User host name.
+
+ Returns:
+ None if the user does not exist or the user has no attributes set, otherwise a dict of attributes set on the user
+ """
+ cursor.execute("SELECT attribute FROM INFORMATION_SCHEMA.USER_ATTRIBUTES WHERE user = %s AND host = %s", (user, host))
+
+ r = cursor.fetchone()
+ # convert JSON string stored in row into a dict - mysql enforces that user_attributes entires are in JSON format
+ j = json.loads(r[0]) if r and r[0] else None
+
+ # if the attributes dict is empty, return None instead
+ return j if j else None
+
+
def get_impl(cursor):
global impl
cursor.execute("SELECT VERSION()")
diff --git a/ansible_collections/community/mysql/plugins/modules/mysql_db.py b/ansible_collections/community/mysql/plugins/modules/mysql_db.py
index 5a8fe3e3e..2cb67dce2 100644
--- a/ansible_collections/community/mysql/plugins/modules/mysql_db.py
+++ b/ansible_collections/community/mysql/plugins/modules/mysql_db.py
@@ -188,13 +188,14 @@ requirements:
- mysql (command line binary)
- mysqldump (command line binary)
notes:
- - Supports C(check_mode).
- Requires the mysql and mysqldump binaries on the remote host.
- This module is B(not idempotent) when I(state) is C(import),
and will import the dump file each time if run more than once.
+attributes:
+ check_mode:
+ support: full
extends_documentation_fragment:
- community.mysql.mysql
-
'''
EXAMPLES = r'''
@@ -576,14 +577,14 @@ def db_create(cursor, db, encoding, collation):
def main():
argument_spec = mysql_common_argument_spec()
argument_spec.update(
- name=dict(type='list', required=True, aliases=['db']),
+ name=dict(type='list', elements='str', required=True, aliases=['db']),
encoding=dict(type='str', default=''),
collation=dict(type='str', default=''),
target=dict(type='path'),
state=dict(type='str', default='present', choices=['absent', 'dump', 'import', 'present']),
single_transaction=dict(type='bool', default=False),
quick=dict(type='bool', default=True),
- ignore_tables=dict(type='list', default=[]),
+ ignore_tables=dict(type='list', elements='str', default=[]),
hex_blob=dict(default=False, type='bool'),
force=dict(type='bool', default=False),
master_data=dict(type='int', default=0, choices=[0, 1, 2]),
diff --git a/ansible_collections/community/mysql/plugins/modules/mysql_info.py b/ansible_collections/community/mysql/plugins/modules/mysql_info.py
index 11b1a8003..0be25fa8d 100644
--- a/ansible_collections/community/mysql/plugins/modules/mysql_info.py
+++ b/ansible_collections/community/mysql/plugins/modules/mysql_info.py
@@ -5,6 +5,7 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
DOCUMENTATION = r'''
@@ -19,7 +20,7 @@ options:
description:
- Limit the collected information by comma separated string or YAML list.
- Allowable values are C(version), C(databases), C(settings), C(global_status),
- C(users), C(engines), C(master_status), C(slave_status), C(slave_hosts).
+ C(users), C(users_info), C(engines), C(master_status), C(slave_status), C(slave_hosts).
- By default, collects all subsets.
- You can use '!' before value (for example, C(!settings)) to exclude it from the information.
- If you pass including and excluding values to the filter, for example, I(filter=!settings,version),
@@ -47,7 +48,10 @@ options:
notes:
- Calculating the size of a database might be slow, depending on the number and size of tables in it.
To avoid this, use I(exclude_fields=db_size).
-- Supports C(check_mode).
+
+attributes:
+ check_mode:
+ support: full
seealso:
- module: community.mysql.mysql_variables
@@ -71,6 +75,9 @@ EXAMPLES = r'''
# Display only databases and users info:
# ansible mysql-hosts -m mysql_info -a 'filter=databases,users'
+# Display all users privileges:
+# ansible mysql-hosts -m mysql_info -a 'filter=users_info'
+
# Display only slave status:
# ansible standby -m mysql_info -a 'filter=slave_status'
@@ -119,6 +126,38 @@ EXAMPLES = r'''
- databases
exclude_fields: db_size
return_empty_dbs: true
+
+- name: Clone users from one server to another
+ block:
+ # Step 1
+ - name: Fetch information from a source server
+ delegate_to: server_source
+ community.mysql.mysql_info:
+ filter:
+ - users_info
+ register: result
+
+ # Step 2
+ # Don't work with sha256_password and cache_sha2_password
+ - name: Clone users fetched in a previous task to a target server
+ community.mysql.mysql_user:
+ name: "{{ item.name }}"
+ host: "{{ item.host }}"
+ plugin: "{{ item.plugin | default(omit) }}"
+ plugin_auth_string: "{{ item.plugin_auth_string | default(omit) }}"
+ plugin_hash_string: "{{ item.plugin_hash_string | default(omit) }}"
+ tls_require: "{{ item.tls_require | default(omit) }}"
+ priv: "{{ item.priv | default(omit) }}"
+ resource_limits: "{{ item.resource_limits | default(omit) }}"
+ column_case_sensitive: true
+ state: present
+ loop: "{{ result.users_info }}"
+ loop_control:
+ label: "{{ item.name }}@{{ item.host }}"
+ when:
+ - item.name != 'root' # In case you don't want to import admin accounts
+ - item.name != 'mariadb.sys'
+ - item.name != 'mysql'
'''
RETURN = r'''
@@ -178,11 +217,31 @@ global_status:
sample:
- { "Innodb_buffer_pool_read_requests": 123, "Innodb_buffer_pool_reads": 32 }
users:
- description: Users information.
+ description: Return a dictionnary of users grouped by host and with global privileges only.
returned: if not excluded by filter
type: dict
sample:
- { "localhost": { "root": { "Alter_priv": "Y", "Alter_routine_priv": "Y" } } }
+users_info:
+ description:
+ - Information about users accounts.
+ - The output can be used as an input of the M(community.mysql.mysql_user) plugin.
+ - Useful when migrating accounts to another server or to create an inventory.
+ - Does not support proxy privileges. If an account has proxy privileges, they won't appear in the output.
+ - Causes issues with authentications plugins C(sha256_password) and C(caching_sha2_password).
+ If the output is fed to M(community.mysql.mysql_user), the
+ ``plugin_auth_string`` will most likely be unreadable due to non-binary
+ characters.
+ returned: if not excluded by filter
+ type: dict
+ sample:
+ - { "plugin_auth_string": '*1234567',
+ "name": "user1",
+ "host": "host.com",
+ "plugin": "mysql_native_password",
+ "priv": "db1.*:SELECT/db2.*:SELECT",
+ "resource_limits": { "MAX_USER_CONNECTIONS": 100 } }
+ version_added: '3.8.0'
engines:
description: Information about the server's storage engines.
returned: if not excluded by filter
@@ -234,6 +293,13 @@ from ansible_collections.community.mysql.plugins.module_utils.mysql import (
mysql_driver_fail_msg,
get_connector_name,
get_connector_version,
+ get_server_implementation,
+)
+
+from ansible_collections.community.mysql.plugins.module_utils.user import (
+ privileges_get,
+ get_resource_limits,
+ get_existing_authentication,
)
from ansible.module_utils.six import iteritems
from ansible.module_utils._text import to_native
@@ -261,9 +327,10 @@ class MySQL_Info(object):
5. add info about the new subset with an example to RETURN block
"""
- def __init__(self, module, cursor):
+ def __init__(self, module, cursor, server_implementation):
self.module = module
self.cursor = cursor
+ self.server_implementation = server_implementation
self.info = {
'version': {},
'databases': {},
@@ -271,6 +338,7 @@ class MySQL_Info(object):
'global_status': {},
'engines': {},
'users': {},
+ 'users_info': {},
'master_status': {},
'slave_hosts': {},
'slave_status': {},
@@ -339,6 +407,9 @@ class MySQL_Info(object):
if 'users' in wanted:
self.__get_users()
+ if 'users_info' in wanted:
+ self.__get_users_info()
+
if 'master_status' in wanted:
self.__get_master_status()
@@ -429,7 +500,10 @@ class MySQL_Info(object):
def __get_slave_status(self):
"""Get slave status if the instance is a slave."""
- res = self.__exec_sql('SHOW SLAVE STATUS')
+ if self.server_implementation == "mariadb":
+ res = self.__exec_sql('SHOW ALL SLAVES STATUS')
+ else:
+ res = self.__exec_sql('SHOW SLAVE STATUS')
if res:
for line in res:
host = line['Master_Host']
@@ -477,6 +551,86 @@ class MySQL_Info(object):
if vname not in ('Host', 'User'):
self.info['users'][host][user][vname] = self.__convert(val)
+ def __get_users_info(self):
+ """Get user privileges, passwords, resources_limits, ...
+
+ Query the server to get all the users and return a string
+ of privileges that can be used by the mysql_user plugin.
+ For instance:
+
+ "users_info": [
+ {
+ "host": "users_info.com",
+ "priv": "*.*: ALL,GRANT",
+ "name": "users_info_adm"
+ },
+ {
+ "host": "users_info.com",
+ "priv": "`mysql`.*: SELECT/`users_info_db`.*: SELECT",
+ "name": "users_info_multi"
+ }
+ ]
+ """
+ res = self.__exec_sql('SELECT * FROM mysql.user')
+ if not res:
+ return None
+
+ output = list()
+ for line in res:
+ user = line['User']
+ host = line['Host']
+
+ user_priv = privileges_get(self.cursor, user, host)
+
+ if not user_priv:
+ self.module.warn("No privileges found for %s on host %s" % (user, host))
+ continue
+
+ priv_string = list()
+ for db_table, priv in user_priv.items():
+ # Proxy privileges are hard to work with because of different quotes or
+ # backticks like ''@'', ''@'%' or even ``@``. In addition, MySQL will
+ # forbid you to grant a proxy privileges through TCP.
+ if set(priv) == {'PROXY', 'GRANT'} or set(priv) == {'PROXY'}:
+ continue
+
+ unquote_db_table = db_table.replace('`', '').replace("'", '')
+ priv_string.append('%s:%s' % (unquote_db_table, ','.join(priv)))
+
+ # Only keep *.* USAGE if it's the only user privilege given
+ if len(priv_string) > 1 and '*.*:USAGE' in priv_string:
+ priv_string.remove('*.*:USAGE')
+
+ resource_limits = get_resource_limits(self.cursor, user, host)
+
+ copy_ressource_limits = dict.copy(resource_limits)
+ output_dict = {
+ 'name': user,
+ 'host': host,
+ 'priv': '/'.join(priv_string),
+ 'resource_limits': copy_ressource_limits,
+ }
+
+ # Prevent returning a resource limit if empty
+ if resource_limits:
+ for key, value in resource_limits.items():
+ if value == 0:
+ del output_dict['resource_limits'][key]
+ if len(output_dict['resource_limits']) == 0:
+ del output_dict['resource_limits']
+
+ authentications = get_existing_authentication(self.cursor, user, host)
+ if authentications:
+ output_dict.update(authentications)
+
+ # TODO password_option
+ # TODO lock_option
+ # but both are not supported by mysql_user atm. So no point yet.
+
+ output.append(output_dict)
+
+ self.info['users_info'] = output
+
def __get_databases(self, exclude_fields, return_empty_dbs):
"""Get info about databases."""
if not exclude_fields:
@@ -544,8 +698,8 @@ def main():
argument_spec = mysql_common_argument_spec()
argument_spec.update(
login_db=dict(type='str'),
- filter=dict(type='list'),
- exclude_fields=dict(type='list'),
+ filter=dict(type='list', elements='str'),
+ exclude_fields=dict(type='list', elements='str'),
return_empty_dbs=dict(type='bool', default=False),
)
@@ -590,10 +744,12 @@ def main():
'Exception message: %s' % (connector_name, connector_version, config_file, to_native(e)))
module.fail_json(msg)
+ server_implementation = get_server_implementation(cursor)
+
###############################
# Create object and do main job
- mysql = MySQL_Info(module, cursor)
+ mysql = MySQL_Info(module, cursor, server_implementation)
module.exit_json(changed=False,
connector_name=connector_name,
diff --git a/ansible_collections/community/mysql/plugins/modules/mysql_query.py b/ansible_collections/community/mysql/plugins/modules/mysql_query.py
index 12d5a5630..fd3a8e09e 100644
--- a/ansible_collections/community/mysql/plugins/modules/mysql_query.py
+++ b/ansible_collections/community/mysql/plugins/modules/mysql_query.py
@@ -36,6 +36,7 @@ options:
- List of values to be passed as positional arguments to the query.
- Mutually exclusive with I(named_args).
type: list
+ elements: raw
named_args:
description:
- Dictionary of key-value arguments to pass to the query.
@@ -50,6 +51,9 @@ options:
- Where passed queries run in a single transaction (C(yes)) or commit them one-by-one (C(no)).
type: bool
default: false
+attributes:
+ check_mode:
+ support: none
seealso:
- module: community.mysql.mysql_db
author:
@@ -138,7 +142,7 @@ def main():
argument_spec.update(
query=dict(type='raw', required=True),
login_db=dict(type='str'),
- positional_args=dict(type='list'),
+ positional_args=dict(type='list', elements='raw'),
named_args=dict(type='dict'),
single_transaction=dict(type='bool', default=False),
)
diff --git a/ansible_collections/community/mysql/plugins/modules/mysql_replication.py b/ansible_collections/community/mysql/plugins/modules/mysql_replication.py
index 33e14bc26..934b479b9 100644
--- a/ansible_collections/community/mysql/plugins/modules/mysql_replication.py
+++ b/ansible_collections/community/mysql/plugins/modules/mysql_replication.py
@@ -23,12 +23,12 @@ options:
mode:
description:
- Module operating mode. Could be
- C(changeprimary) (CHANGE PRIMARY TO),
- C(getprimary) (SHOW PRIMARY STATUS),
- C(getreplica) (SHOW REPLICA),
+ C(changeprimary) (CHANGE MASTER TO),
+ C(getprimary) (SHOW MASTER STATUS),
+ C(getreplica) (SHOW REPLICA STATUS),
C(startreplica) (START REPLICA),
C(stopreplica) (STOP REPLICA),
- C(resetprimary) (RESET PRIMARY) - supported since community.mysql 0.1.0,
+ C(resetprimary) (RESET MASTER) - supported since community.mysql 0.1.0,
C(resetreplica) (RESET REPLICA),
C(resetreplicaall) (RESET REPLICA ALL).
type: str
@@ -190,10 +190,13 @@ options:
notes:
- If an empty value for the parameter of string type is needed, use an empty string.
+attributes:
+ check_mode:
+ support: none
+
extends_documentation_fragment:
- community.mysql.mysql
-
seealso:
- module: community.mysql.mysql_info
- name: MySQL replication reference
diff --git a/ansible_collections/community/mysql/plugins/modules/mysql_role.py b/ansible_collections/community/mysql/plugins/modules/mysql_role.py
index 070d7939d..3e3462ab1 100644
--- a/ansible_collections/community/mysql/plugins/modules/mysql_role.py
+++ b/ansible_collections/community/mysql/plugins/modules/mysql_role.py
@@ -121,11 +121,24 @@ options:
type: bool
default: true
+ column_case_sensitive:
+ description:
+ - The default is C(false).
+ - When C(true), the module will not uppercase the field in the privileges.
+ - When C(false), the field names will be upper-cased. This was the default before this
+ feature was introduced but since MySQL/MariaDB is case sensitive you should set this
+ to C(true) in most cases.
+ type: bool
+ version_added: '3.8.0'
+
notes:
- Pay attention that the module runs C(SET DEFAULT ROLE ALL TO)
all the I(members) passed by default when the state has changed.
If you want to avoid this behavior, set I(set_default_role_all) to C(no).
- - Supports C(check_mode).
+
+attributes:
+ check_mode:
+ support: full
seealso:
- module: community.mysql.mysql_user
@@ -136,6 +149,8 @@ seealso:
author:
- Andrew Klychkov (@Andersson007)
- Felix Hamme (@betanummeric)
+ - kmarse (@kmarse)
+ - Laurent Indermühle (@laurent-indermuehle)
extends_documentation_fragment:
- community.mysql.mysql
@@ -916,8 +931,9 @@ class Role():
if privs:
result = user_mod(self.cursor, self.name, self.host,
None, None, None, None, None, None,
- privs, append_privs, subtract_privs, None,
- self.module, role=True, maria_role=self.is_mariadb)
+ privs, append_privs, subtract_privs, None, None,
+ self.module, None, None, role=True,
+ maria_role=self.is_mariadb)
changed = result['changed']
if admin:
@@ -954,7 +970,8 @@ def main():
detach_members=dict(type='bool', default=False),
check_implicit_admin=dict(type='bool', default=False),
set_default_role_all=dict(type='bool', default=True),
- members_must_exist=dict(type='bool', default=True)
+ members_must_exist=dict(type='bool', default=True),
+ column_case_sensitive=dict(type='bool', default=None), # TODO 4.0.0 add default=True
)
module = AnsibleModule(
argument_spec=argument_spec,
@@ -989,6 +1006,7 @@ def main():
db = ''
set_default_role_all = module.params['set_default_role_all']
members_must_exist = module.params['members_must_exist']
+ column_case_sensitive = module.params['column_case_sensitive']
if priv and not isinstance(priv, (str, dict)):
msg = ('The "priv" parameter must be str or dict '
@@ -1001,6 +1019,13 @@ def main():
if mysql_driver is None:
module.fail_json(msg=mysql_driver_fail_msg)
+ # TODO Release 4.0.0 : Remove this test and variable assignation
+ if column_case_sensitive is None:
+ column_case_sensitive = False
+ module.warn("Option column_case_sensitive is not provided. "
+ "The default is now false, so the column's name will be uppercased. "
+ "The default will be changed to true in community.mysql 4.0.0.")
+
cursor = None
try:
if check_implicit_admin:
@@ -1038,7 +1063,7 @@ def main():
module.fail_json(msg=to_native(e))
try:
- priv = privileges_unpack(priv, mode, ensure_usage=not subtract_privs)
+ priv = privileges_unpack(priv, mode, column_case_sensitive, ensure_usage=not subtract_privs)
except Exception as e:
module.fail_json(msg='Invalid privileges string: %s' % to_native(e))
diff --git a/ansible_collections/community/mysql/plugins/modules/mysql_user.py b/ansible_collections/community/mysql/plugins/modules/mysql_user.py
index e87fe12db..e02b15326 100644
--- a/ansible_collections/community/mysql/plugins/modules/mysql_user.py
+++ b/ansible_collections/community/mysql/plugins/modules/mysql_user.py
@@ -155,6 +155,37 @@ options:
- Cannot be used to set global variables, use the M(community.mysql.mysql_variables) module instead.
type: dict
version_added: '3.6.0'
+ password_expire:
+ description:
+ - C(never) - I(password) will never expire.
+ - C(default) - I(password) is defined using global system variable I(default_password_lifetime) setting.
+ - C(interval) - I(password) will expire in days which is defined in I(password_expire_interval).
+ - C(now) - I(password) will expire immediately.
+ type: str
+ choices: [ now, never, default, interval ]
+ version_added: '3.9.0'
+ password_expire_interval:
+ description:
+ - Number of days I(password) will expire. Requires I(password_expire=interval).
+ type: int
+ version_added: '3.9.0'
+
+ column_case_sensitive:
+ description:
+ - The default is C(false).
+ - When C(true), the module will not uppercase the field names in the privileges.
+ - When C(false), the field names will be upper-cased. This is the default
+ - This feature was introduced because MySQL 8 and above uses case sensitive
+ fields names in privileges.
+ type: bool
+ version_added: '3.8.0'
+ attributes:
+ description:
+ - "Create, update, or delete user attributes (arbitrary 'key: value' comments) for the user."
+ - MySQL server must support the INFORMATION_SCHEMA.USER_ATTRIBUTES table. Provided since MySQL 8.0.
+ - To delete an existing attribute, set its value to null.
+ type: dict
+ version_added: '3.9.0'
notes:
- "MySQL server installs with default I(login_user) of C(root) and no password.
@@ -163,7 +194,10 @@ notes:
2) drop a C(~/.my.cnf) file containing the new root credentials.
Subsequent runs of the playbook will then succeed by reading the new credentials from the file."
- Currently, there is only support for the C(mysql_native_password) encrypted password hash module.
- - Supports (check_mode).
+
+attributes:
+ check_mode:
+ support: full
seealso:
- module: community.mysql.mysql_info
@@ -178,9 +212,11 @@ author:
- Jonathan Mainguy (@Jmainguy)
- Benjamin Malynovytch (@bmalynovytch)
- Lukasz Tomaszkiewicz (@tomaszkiewicz)
+- kmarse (@kmarse)
+- Laurent Indermühle (@laurent-indermuehle)
+
extends_documentation_fragment:
- community.mysql.mysql
-
'''
EXAMPLES = r'''
@@ -242,6 +278,13 @@ EXAMPLES = r'''
FUNCTION my_db.my_function: EXECUTE
state: present
+- name: Modify user attributes, creating the attribute 'foo' and removing the attribute 'bar'
+ community.mysql.mysql_user:
+ name: bob
+ attributes:
+ foo: "foo"
+ bar: null
+
- name: Modify user to require TLS connection with a valid client certificate
community.mysql.mysql_user:
name: bob
@@ -390,6 +433,7 @@ def main():
tls_requires=dict(type='dict'),
append_privs=dict(type='bool', default=False),
subtract_privs=dict(type='bool', default=False),
+ attributes=dict(type='dict'),
check_implicit_admin=dict(type='bool', default=False),
update_password=dict(type='str', default='always', choices=['always', 'on_create', 'on_new_username'], no_log=False),
sql_log_bin=dict(type='bool', default=True),
@@ -399,6 +443,9 @@ def main():
resource_limits=dict(type='dict'),
force_context=dict(type='bool', default=False),
session_vars=dict(type='dict'),
+ column_case_sensitive=dict(type='bool', default=None), # TODO 4.0.0 add default=True
+ password_expire=dict(type='str', choices=['now', 'never', 'default', 'interval'], no_log=True),
+ password_expire_interval=dict(type='int', required_if=[('password_expire', 'interval', True)], no_log=True),
)
module = AnsibleModule(
argument_spec=argument_spec,
@@ -421,6 +468,7 @@ def main():
append_privs = module.boolean(module.params["append_privs"])
subtract_privs = module.boolean(module.params['subtract_privs'])
update_password = module.params['update_password']
+ attributes = module.params['attributes']
ssl_cert = module.params["client_cert"]
ssl_key = module.params["client_key"]
ssl_ca = module.params["ca_cert"]
@@ -434,6 +482,9 @@ def main():
plugin_auth_string = module.params["plugin_auth_string"]
resource_limits = module.params["resource_limits"]
session_vars = module.params["session_vars"]
+ column_case_sensitive = module.params["column_case_sensitive"]
+ password_expire = module.params["password_expire"]
+ password_expire_interval = module.params["password_expire_interval"]
if priv and not isinstance(priv, (str, dict)):
module.fail_json(msg="priv parameter must be str or dict but %s was passed" % type(priv))
@@ -444,6 +495,10 @@ def main():
if mysql_driver is None:
module.fail_json(msg=mysql_driver_fail_msg)
+ if password_expire_interval and password_expire_interval < 1:
+ module.fail_json(msg="password_expire_interval value \
+ should be positive number")
+
cursor = None
try:
if check_implicit_admin:
@@ -460,6 +515,13 @@ def main():
module.fail_json(msg="unable to connect to database, check login_user and login_password are correct or %s has the credentials. "
"Exception message: %s" % (config_file, to_native(e)))
+ # TODO Release 4.0.0 : Remove this test and variable assignation
+ if column_case_sensitive is None:
+ column_case_sensitive = False
+ module.warn("Option column_case_sensitive is not provided. "
+ "The default is now false, so the column's name will be uppercased. "
+ "The default will be changed to true in community.mysql 4.0.0.")
+
if not sql_log_bin:
cursor.execute("SET SQL_LOG_BIN=0;")
@@ -473,23 +535,28 @@ def main():
mode = get_mode(cursor)
except Exception as e:
module.fail_json(msg=to_native(e))
- priv = privileges_unpack(priv, mode, ensure_usage=not subtract_privs)
+
+ priv = privileges_unpack(priv, mode, column_case_sensitive, ensure_usage=not subtract_privs)
password_changed = False
+ final_attributes = None
if state == "present":
if user_exists(cursor, user, host, host_all):
try:
if update_password == "always":
result = user_mod(cursor, user, host, host_all, password, encrypted,
plugin, plugin_hash_string, plugin_auth_string,
- priv, append_privs, subtract_privs, tls_requires, module)
+ priv, append_privs, subtract_privs, attributes, tls_requires, module,
+ password_expire, password_expire_interval)
else:
result = user_mod(cursor, user, host, host_all, None, encrypted,
None, None, None,
- priv, append_privs, subtract_privs, tls_requires, module)
+ priv, append_privs, subtract_privs, attributes, tls_requires, module,
+ password_expire, password_expire_interval)
changed = result['changed']
msg = result['msg']
password_changed = result['password_changed']
+ final_attributes = result['attributes']
except (SQLParseError, InvalidPrivsError, mysql_driver.Error) as e:
module.fail_json(msg=to_native(e))
@@ -502,9 +569,11 @@ def main():
reuse_existing_password = update_password == 'on_new_username'
result = user_add(cursor, user, host, host_all, password, encrypted,
plugin, plugin_hash_string, plugin_auth_string,
- priv, tls_requires, module.check_mode, reuse_existing_password)
+ priv, attributes, tls_requires, reuse_existing_password, module,
+ password_expire, password_expire_interval)
changed = result['changed']
password_changed = result['password_changed']
+ final_attributes = result['attributes']
if changed:
msg = "User added"
@@ -521,7 +590,7 @@ def main():
else:
changed = False
msg = "User doesn't exist"
- module.exit_json(changed=changed, user=user, msg=msg, password_changed=password_changed)
+ module.exit_json(changed=changed, user=user, msg=msg, password_changed=password_changed, attributes=final_attributes)
if __name__ == '__main__':
diff --git a/ansible_collections/community/mysql/plugins/modules/mysql_variables.py b/ansible_collections/community/mysql/plugins/modules/mysql_variables.py
index f404d5aab..dfe8466f0 100644
--- a/ansible_collections/community/mysql/plugins/modules/mysql_variables.py
+++ b/ansible_collections/community/mysql/plugins/modules/mysql_variables.py
@@ -44,8 +44,9 @@ options:
default: global
version_added: '0.1.0'
-notes:
-- Does not support C(check_mode).
+attributes:
+ check_mode:
+ support: none
seealso:
- module: community.mysql.mysql_info
@@ -175,7 +176,7 @@ def setvariable(cursor, mysqlvar, value, mode='global'):
def main():
argument_spec = mysql_common_argument_spec()
argument_spec.update(
- variable=dict(type='str'),
+ variable=dict(type='str', required=True),
value=dict(type='str'),
mode=dict(type='str', choices=['global', 'persist', 'persist_only'], default='global'),
)
diff --git a/ansible_collections/community/mysql/tests/integration/targets/setup_controller/tasks/verify.yml b/ansible_collections/community/mysql/tests/integration/targets/setup_controller/tasks/verify.yml
index 74aa0f26e..e5b4c9410 100644
--- a/ansible_collections/community/mysql/tests/integration/targets/setup_controller/tasks/verify.yml
+++ b/ansible_collections/community/mysql/tests/integration/targets/setup_controller/tasks/verify.yml
@@ -19,8 +19,11 @@
- name: Assert that test container runs the expected MySQL/MariaDB version
assert:
that:
- - "'{{ primary_info.version.major }}.{{ primary_info.version.minor }}\
- .{{ primary_info.version.release }}' == '{{ db_version }}'"
+ - registred_db_version == db_version
+ vars:
+ registred_db_version:
+ "{{ primary_info.version.major }}.{{ primary_info.version.minor }}\
+ .{{ primary_info.version.release }}"
- name: Assert that mysql_info module used the expected version of pymysql
assert:
@@ -52,8 +55,9 @@
- name: Assert that we run the expected ansible version
assert:
that:
- - >
- "{{ ansible_version.major }}.{{ ansible_version.minor }}"
- is version(test_ansible_version, '==')
+ - ansible_running_version == test_ansible_version
+ vars:
+ ansible_running_version:
+ "{{ ansible_version.major }}.{{ ansible_version.minor }}"
when:
- test_ansible_version != 'devel' # Devel will change overtime
diff --git a/ansible_collections/community/mysql/tests/integration/targets/test_mysql_db/tasks/state_dump_import.yml b/ansible_collections/community/mysql/tests/integration/targets/test_mysql_db/tasks/state_dump_import.yml
index b4f9cda9b..e4ae76283 100644
--- a/ansible_collections/community/mysql/tests/integration/targets/test_mysql_db/tasks/state_dump_import.yml
+++ b/ansible_collections/community/mysql/tests/integration/targets/test_mysql_db/tasks/state_dump_import.yml
@@ -339,7 +339,7 @@
assert:
that:
- result is changed
- - "result.db =='{{ db_name }}'"
+ - result.db == db_name
# - name: Dump and Import | Assert database was backed up successfully
# command: "file {{ db_file_name }}"
diff --git a/ansible_collections/community/mysql/tests/integration/targets/test_mysql_info/files/users_info_create_procedure.sql b/ansible_collections/community/mysql/tests/integration/targets/test_mysql_info/files/users_info_create_procedure.sql
new file mode 100644
index 000000000..5a358f0aa
--- /dev/null
+++ b/ansible_collections/community/mysql/tests/integration/targets/test_mysql_info/files/users_info_create_procedure.sql
@@ -0,0 +1,7 @@
+DELIMITER //
+DROP PROCEDURE IF EXISTS users_info_db.get_all_items;
+CREATE PROCEDURE users_info_db.get_all_items()
+BEGIN
+SELECT * from users_info_db.t1;
+END //
+DELIMITER ;
diff --git a/ansible_collections/community/mysql/tests/integration/targets/test_mysql_info/tasks/filter_users_info.yml b/ansible_collections/community/mysql/tests/integration/targets/test_mysql_info/tasks/filter_users_info.yml
new file mode 100644
index 000000000..2c126c12f
--- /dev/null
+++ b/ansible_collections/community/mysql/tests/integration/targets/test_mysql_info/tasks/filter_users_info.yml
@@ -0,0 +1,280 @@
+---
+
+- module_defaults:
+ community.mysql.mysql_db: &mysql_defaults
+ login_user: "{{ mysql_user }}"
+ login_password: "{{ mysql_password }}"
+ login_host: "{{ mysql_host }}"
+ login_port: "{{ mysql_primary_port }}"
+ community.mysql.mysql_query: *mysql_defaults
+ community.mysql.mysql_info: *mysql_defaults
+ community.mysql.mysql_user: *mysql_defaults
+
+ block:
+
+ # ================================ Prepare ==============================
+ - name: Mysql_info users_info | Create databases
+ community.mysql.mysql_db:
+ name:
+ - users_info_db
+ - users_info_db2
+ - users_info_db3
+ state: present
+
+ - name: Mysql_info users_info | Create tables
+ community.mysql.mysql_query:
+ query:
+ - >-
+ CREATE TABLE IF NOT EXISTS users_info_db.t1
+ (id int, name varchar(9))
+ - >-
+ CREATE TABLE IF NOT EXISTS users_info_db.T_UPPER
+ (id int, name1 varchar(9), NAME2 varchar(9), Name3 varchar(9))
+
+ # I failed to create a procedure using community.mysql.mysql_query.
+ # Maybe it's because we must changed the delimiter.
+ - name: Mysql_info users_info | Create procedure SQL file
+ ansible.builtin.template:
+ src: files/users_info_create_procedure.sql
+ dest: /root/create_procedure.sql
+ owner: root
+ group: root
+ mode: '0700'
+
+ - name: Mysql_info users_info | Create a procedure
+ community.mysql.mysql_db:
+ name: all
+ state: import
+ target: /root/create_procedure.sql
+
+ # Use a query instead of mysql_user, because we want to caches differences
+ # at the end and a bug in mysql_user would be invisible to this tests
+ - name: Mysql_info users_info | Prepare common tests users
+ community.mysql.mysql_query:
+ query:
+ - >-
+ CREATE USER users_info_adm@'users_info.com' IDENTIFIED WITH
+ mysql_native_password AS '*6C387FC3893DBA1E3BA155E74754DA6682D04747'
+ - >
+ GRANT ALL ON *.* to users_info_adm@'users_info.com' WITH GRANT
+ OPTION
+
+ - >-
+ CREATE USER users_info_schema@'users_info.com' IDENTIFIED WITH
+ mysql_native_password AS '*6C387FC3893DBA1E3BA155E74754DA6682D04747'
+ - >-
+ GRANT SELECT, INSERT, UPDATE, DELETE ON users_info_db.* TO
+ users_info_schema@'users_info.com'
+
+ - >-
+ CREATE USER users_info_table@'users_info.com' IDENTIFIED WITH
+ mysql_native_password AS '*6C387FC3893DBA1E3BA155E74754DA6682D04747'
+ - >-
+ GRANT SELECT, INSERT, UPDATE ON users_info_db.t1 TO
+ users_info_table@'users_info.com'
+
+ - >-
+ CREATE USER users_info_col@'users_info.com' IDENTIFIED WITH
+ mysql_native_password AS '*6C387FC3893DBA1E3BA155E74754DA6682D04747'
+ WITH MAX_USER_CONNECTIONS 100
+ - >-
+ GRANT SELECT (id) ON users_info_db.t1 TO
+ users_info_col@'users_info.com'
+
+ - >-
+ CREATE USER users_info_proc@'users_info.com' IDENTIFIED WITH
+ mysql_native_password AS '*6C387FC3893DBA1E3BA155E74754DA6682D04747'
+ WITH MAX_USER_CONNECTIONS 2 MAX_CONNECTIONS_PER_HOUR 60
+ - >-
+ GRANT EXECUTE ON PROCEDURE users_info_db.get_all_items TO
+ users_info_proc@'users_info.com'
+
+ - >-
+ CREATE USER users_info_multi@'users_info.com' IDENTIFIED WITH
+ mysql_native_password AS '*6C387FC3893DBA1E3BA155E74754DA6682D04747'
+ - >-
+ GRANT SELECT ON mysql.* TO
+ users_info_multi@'users_info.com'
+ - >-
+ GRANT ALL ON users_info_db.* TO
+ users_info_multi@'users_info.com'
+ - >-
+ GRANT ALL ON users_info_db2.* TO
+ users_info_multi@'users_info.com'
+ - >-
+ GRANT ALL ON users_info_db3.* TO
+ users_info_multi@'users_info.com'
+
+ - >-
+ CREATE USER users_info_usage_only@'users_info.com' IDENTIFIED WITH
+ mysql_native_password AS '*6C387FC3893DBA1E3BA155E74754DA6682D04747'
+ - >-
+ GRANT USAGE ON *.* TO
+ users_info_usage_only@'users_info.com'
+
+ - >-
+ CREATE USER users_info_columns_uppercase@'users_info.com'
+ IDENTIFIED WITH mysql_native_password AS
+ '*6C387FC3893DBA1E3BA155E74754DA6682D04747'
+ - >-
+ GRANT SELECT,UPDATE(name1,NAME2,Name3) ON users_info_db.T_UPPER TO
+ users_info_columns_uppercase@'users_info.com'
+
+ - >-
+ CREATE USER users_info_multi_hosts@'%'
+ IDENTIFIED WITH mysql_native_password AS
+ '*6C387FC3893DBA1E3BA155E74754DA6682D04747'
+ - GRANT SELECT ON users_info_db.* TO users_info_multi_hosts@'%'
+
+ - >-
+ CREATE USER users_info_multi_hosts@'localhost'
+ IDENTIFIED WITH mysql_native_password AS
+ '*6C387FC3893DBA1E3BA155E74754DA6682D04747'
+ - >-
+ GRANT SELECT ON users_info_db.* TO
+ users_info_multi_hosts@'localhost'
+
+ - >-
+ CREATE USER users_info_multi_hosts@'host1'
+ IDENTIFIED WITH mysql_native_password AS
+ '*6C387FC3893DBA1E3BA155E74754DA6682D04747'
+ - GRANT SELECT ON users_info_db.* TO users_info_multi_hosts@'host1'
+
+ # Different password than the others users_info_multi_hosts
+ - >-
+ CREATE USER users_info_multi_hosts@'host2'
+ IDENTIFIED WITH mysql_native_password AS
+ '*CB3326D5279DE7915FE5D743232165EE887883CA'
+ - GRANT SELECT ON users_info_db.* TO users_info_multi_hosts@'host2'
+
+ - name: Mysql_info users_info | Prepare tests users for MariaDB
+ community.mysql.mysql_user:
+ name: "{{ item.name }}"
+ host: "users_info.com"
+ plugin: "{{ item.plugin | default(omit) }}"
+ plugin_auth_string: "{{ item.plugin_auth_string | default(omit) }}"
+ plugin_hash_string: "{{ item.plugin_hash_string | default(omit) }}"
+ tls_require: "{{ item.tls_require | default(omit) }}"
+ priv: "{{ item.priv }}"
+ resource_limits: "{{ item.resource_limits | default(omit) }}"
+ column_case_sensitive: true
+ state: present
+ loop:
+ - name: users_info_socket # Only for MariaDB
+ priv:
+ '*.*': 'ALL'
+ plugin: 'unix_socket'
+ when:
+ - db_engine == 'mariadb'
+
+ - name: Mysql_info users_info | Prepare tests users for MySQL
+ community.mysql.mysql_user:
+ name: "{{ item.name }}"
+ host: "users_info.com"
+ plugin: "{{ item.plugin | default(omit) }}"
+ plugin_auth_string: "{{ item.plugin_auth_string | default(omit) }}"
+ plugin_hash_string: "{{ item.plugin_hash_string | default(omit) }}"
+ tls_require: "{{ item.tls_require | default(omit) }}"
+ priv: "{{ item.priv }}"
+ resource_limits: "{{ item.resource_limits | default(omit) }}"
+ column_case_sensitive: true
+ state: present
+ loop:
+ - name: users_info_sha256 # Only for MySQL
+ priv:
+ '*.*': 'ALL'
+ plugin_auth_string:
+ '$5$/<w*D`L4\"F$WQiI1Pev.7atAh8udYs3wqlzgdfV8LXoy7rqSEC7NF2'
+ plugin: 'sha256_password'
+ when:
+ - db_engine == 'mysql'
+
+ - name: Mysql_info users_info | Prepare tests users for MySQL 8+
+ community.mysql.mysql_user:
+ name: "{{ item.name }}"
+ host: "users_info.com"
+ plugin: "{{ item.plugin | default(omit) }}"
+ plugin_auth_string: "{{ item.plugin_auth_string | default(omit) }}"
+ plugin_hash_string: "{{ item.plugin_hash_string | default(omit) }}"
+ tls_require: "{{ item.tls_require | default(omit) }}"
+ priv: "{{ item.priv }}"
+ resource_limits: "{{ item.resource_limits | default(omit) }}"
+ column_case_sensitive: true
+ state: present
+ loop:
+ - name: users_info_caching_sha2 # Only for MySQL 8+
+ priv:
+ '*.*': 'ALL'
+ plugin_auth_string:
+ '$A$005$61j/uF%Qb4-=O2xkeO82u2HNkF.lxDq0liO4U3xqi7bDUCbWM6HayRXWn1'
+ plugin: 'caching_sha2_password'
+ when:
+ - db_engine == 'mysql'
+ - db_version is version('8.0', '>=')
+
+ # ================================== Tests ==============================
+
+ - name: Mysql_info users_info | Collect users_info
+ community.mysql.mysql_info:
+ filter:
+ - users_info
+ register: result
+
+ - name: Recreate users from mysql_info users_info result
+ community.mysql.mysql_user:
+ name: "{{ item.name }}"
+ host: "{{ item.host }}"
+ plugin: "{{ item.plugin | default(omit) }}"
+ plugin_auth_string: "{{ item.plugin_auth_string | default(omit) }}"
+ plugin_hash_string: "{{ item.plugin_hash_string | default(omit) }}"
+ tls_require: "{{ item.tls_require | default(omit) }}"
+ priv: "{{ item.priv | default(omit) }}"
+ resource_limits: "{{ item.resource_limits | default(omit) }}"
+ column_case_sensitive: true
+ state: present
+ loop: "{{ result.users_info }}"
+ loop_control:
+ label: "{{ item.name }}@{{ item.host }}"
+ register: recreate_users_result
+ failed_when:
+ - recreate_users_result is changed
+ when:
+ - item.name != 'root'
+ - item.name != 'mysql'
+ - item.name != 'mariadb.sys'
+ - item.name != 'mysql.sys'
+ - item.name != 'mysql.infoschema'
+
+
+ # ================================== Cleanup ============================
+
+ - name: Mysql_info users_info | Cleanup users_info
+ community.mysql.mysql_user:
+ name: "{{ item }}"
+ host_all: true
+ column_case_sensitive: true
+ state: absent
+ loop:
+ - users_info_adm
+ - users_info_schema
+ - users_info_table
+ - users_info_col
+ - users_info_proc
+ - users_info_multi
+ - users_info_db
+ - users_info_usage_only
+ - users_info_columns_uppercase
+ - users_info_multi_hosts
+
+ - name: Mysql_info users_info | Cleanup databases
+ community.mysql.mysql_db:
+ name:
+ - users_info_db
+ - users_info_db2
+ - users_info_db3
+ state: absent
+
+ - name: Mysql_info users_info | Cleanup sql file for the procedure
+ ansible.builtin.file:
+ path: /root/create_procedure.sql
+ state: absent
diff --git a/ansible_collections/community/mysql/tests/integration/targets/test_mysql_info/tasks/main.yml b/ansible_collections/community/mysql/tests/integration/targets/test_mysql_info/tasks/main.yml
index be367f068..5d34da9a0 100644
--- a/ansible_collections/community/mysql/tests/integration/targets/test_mysql_info/tasks/main.yml
+++ b/ansible_collections/community/mysql/tests/integration/targets/test_mysql_info/tasks/main.yml
@@ -219,3 +219,7 @@
assert:
that:
- result.databases.allviews.size == 0
+
+ - name: Import tasks file to tests users_info filter
+ ansible.builtin.import_tasks:
+ file: filter_users_info.yml
diff --git a/ansible_collections/community/mysql/tests/integration/targets/test_mysql_replication/tasks/mysql_replication_channel.yml b/ansible_collections/community/mysql/tests/integration/targets/test_mysql_replication/tasks/mysql_replication_channel.yml
index f438dbf09..7d37df05f 100644
--- a/ansible_collections/community/mysql/tests/integration/targets/test_mysql_replication/tasks/mysql_replication_channel.yml
+++ b/ansible_collections/community/mysql/tests/integration/targets/test_mysql_replication/tasks/mysql_replication_channel.yml
@@ -34,8 +34,14 @@
- assert:
that:
- - result is changed
- - result.queries == ["CHANGE MASTER TO MASTER_HOST='{{ mysql_host }}',MASTER_USER='{{ replication_user }}',MASTER_PASSWORD='********',MASTER_PORT={{ mysql_primary_port }},MASTER_LOG_FILE='{{ mysql_primary_status.File }}',MASTER_LOG_POS={{ mysql_primary_status.Position }} FOR CHANNEL '{{ test_channel }}'"]
+ - result is changed
+ - result.queries == result_query
+ vars:
+ result_query: ["CHANGE MASTER TO MASTER_HOST='{{ mysql_host }}',\
+ MASTER_USER='{{ replication_user }}',MASTER_PASSWORD='********',\
+ MASTER_PORT={{ mysql_primary_port }},MASTER_LOG_FILE=\
+ '{{ mysql_primary_status.File }}',MASTER_LOG_POS=\
+ {{ mysql_primary_status.Position }} FOR CHANNEL '{{ test_channel }}'"]
# Test startreplica mode:
- name: Start replica with channel
@@ -48,8 +54,11 @@
- assert:
that:
- - result is changed
- - result.queries == ["START SLAVE FOR CHANNEL '{{ test_channel }}'"] or result.queries == ["START REPLICA FOR CHANNEL '{{ test_channel }}'"]
+ - result is changed
+ - result.queries == result_query or result_query2
+ vars:
+ result_query: ["START SLAVE FOR CHANNEL '{{ test_channel }}'"]
+ result_query2: ["START REPLICA FOR CHANNEL '{{ test_channel }}'"]
# Test getreplica mode:
- name: Get standby status with channel
@@ -62,26 +71,34 @@
- assert:
that:
- - replica_status.Is_Replica == true
- - replica_status.Master_Host == '{{ mysql_host }}'
- - replica_status.Exec_Master_Log_Pos == mysql_primary_status.Position
- - replica_status.Master_Port == {{ mysql_primary_port }}
- - replica_status.Last_IO_Errno == 0
- - replica_status.Last_IO_Error == ''
- - replica_status.Channel_Name == '{{ test_channel }}'
- - replica_status is not changed
+ - replica_status.Is_Replica is truthy(convert_bool=True)
+ - replica_status.Master_Host == mysql_host_value
+ - replica_status.Exec_Master_Log_Pos == mysql_primary_status.Position
+ - replica_status.Master_Port == mysql_primary_port_value
+ - replica_status.Last_IO_Errno == 0
+ - replica_status.Last_IO_Error == ''
+ - replica_status.Channel_Name == test_channel_value
+ - replica_status is not changed
+ vars:
+ mysql_host_value: '{{ mysql_host }}'
+ mysql_primary_port_value: '{{ mysql_primary_port }}'
+ test_channel_value: '{{ test_channel }}'
when: mysql8022_and_higher == false
- assert:
that:
- - replica_status.Is_Replica == true
- - replica_status.Source_Host == '{{ mysql_host }}'
- - replica_status.Exec_Source_Log_Pos == mysql_primary_status.Position
- - replica_status.Source_Port == {{ mysql_primary_port }}
- - replica_status.Last_IO_Errno == 0
- - replica_status.Last_IO_Error == ''
- - replica_status.Channel_Name == '{{ test_channel }}'
- - replica_status is not changed
+ - replica_status.Is_Replica is truthy(convert_bool=True)
+ - replica_status.Source_Host == mysql_host_value
+ - replica_status.Exec_Source_Log_Pos == mysql_primary_status.Position
+ - replica_status.Source_Port == mysql_primary_port_value
+ - replica_status.Last_IO_Errno == 0
+ - replica_status.Last_IO_Error == ''
+ - replica_status.Channel_Name == test_channel_value
+ - replica_status is not changed
+ vars:
+ mysql_host_value: '{{ mysql_host }}'
+ mysql_primary_port_value: '{{ mysql_primary_port }}'
+ test_channel_value: '{{ test_channel }}'
when: mysql8022_and_higher == true
@@ -96,8 +113,11 @@
- assert:
that:
- - result is changed
- - result.queries == ["STOP SLAVE FOR CHANNEL '{{ test_channel }}'"] or result.queries == ["STOP REPLICA FOR CHANNEL '{{ test_channel }}'"]
+ - result is changed
+ - result.queries == result_query or result.queries == result_query2
+ vars:
+ result_query: ["STOP SLAVE FOR CHANNEL '{{ test_channel }}'"]
+ result_query2: ["STOP REPLICA FOR CHANNEL '{{ test_channel }}'"]
# Test reset
- name: Reset replica with channel
@@ -110,8 +130,11 @@
- assert:
that:
- - result is changed
- - result.queries == ["RESET SLAVE FOR CHANNEL '{{ test_channel }}'"] or result.queries == ["RESET REPLICA FOR CHANNEL '{{ test_channel }}'"]
+ - result is changed
+ - result.queries == result_query or result.queries == result_query2
+ vars:
+ result_query: ["RESET SLAVE FOR CHANNEL '{{ test_channel }}'"]
+ result_query2: ["RESET REPLICA FOR CHANNEL '{{ test_channel }}'"]
# Test reset all
- name: Reset replica all with channel
@@ -124,5 +147,8 @@
- assert:
that:
- - result is changed
- - result.queries == ["RESET SLAVE ALL FOR CHANNEL '{{ test_channel }}'"] or result.queries == ["RESET REPLICA ALL FOR CHANNEL '{{ test_channel }}'"]
+ - result is changed
+ - result.queries == result_query or result.queries == result_query2
+ vars:
+ result_query: ["RESET SLAVE ALL FOR CHANNEL '{{ test_channel }}'"]
+ result_query2: ["RESET REPLICA ALL FOR CHANNEL '{{ test_channel }}'"]
diff --git a/ansible_collections/community/mysql/tests/integration/targets/test_mysql_replication/tasks/mysql_replication_initial.yml b/ansible_collections/community/mysql/tests/integration/targets/test_mysql_replication/tasks/mysql_replication_initial.yml
index ca7301c5b..ea7a5ac8f 100644
--- a/ansible_collections/community/mysql/tests/integration/targets/test_mysql_replication/tasks/mysql_replication_initial.yml
+++ b/ansible_collections/community/mysql/tests/integration/targets/test_mysql_replication/tasks/mysql_replication_initial.yml
@@ -158,7 +158,13 @@
assert:
that:
- result is changed
- - result.queries == ["CHANGE MASTER TO MASTER_HOST='{{ mysql_host }}',MASTER_USER='{{ replication_user }}',MASTER_PASSWORD='********',MASTER_PORT={{ mysql_primary_port }},MASTER_LOG_FILE='{{ mysql_primary_status.File }}',MASTER_LOG_POS={{ mysql_primary_status.Position }},MASTER_SSL=0,MASTER_SSL_CA=''"]
+ - result.queries == expected_queries
+ vars:
+ expected_queries: ["CHANGE MASTER TO MASTER_HOST='{{ mysql_host }}',\
+ MASTER_USER='{{ replication_user }}',MASTER_PASSWORD='********',\
+ MASTER_PORT={{ mysql_primary_port }},MASTER_LOG_FILE=\
+ '{{ mysql_primary_status.File }}',MASTER_LOG_POS=\
+ {{ mysql_primary_status.Position }},MASTER_SSL=0,MASTER_SSL_CA=''"]
# Test startreplica mode:
- name: Start replica
@@ -185,26 +191,32 @@
- name: Assert that getreplica returns expected values for MySQL older than 8.0.22 and Mariadb
assert:
that:
- - replica_status.Is_Replica == true
- - replica_status.Master_Host == '{{ mysql_host }}'
+ - replica_status.Is_Replica is truthy(convert_bool=True)
+ - replica_status.Master_Host == mysql_host_value
- replica_status.Exec_Master_Log_Pos == mysql_primary_status.Position
- - replica_status.Master_Port == {{ mysql_primary_port }}
+ - replica_status.Master_Port == mysql_primary_port_value
- replica_status.Last_IO_Errno == 0
- replica_status.Last_IO_Error == ''
- replica_status is not changed
- when: mysql8022_and_higher == false
+ vars:
+ mysql_host_value: "{{ mysql_host }}"
+ mysql_primary_port_value: "{{ mysql_primary_port }}"
+ when: mysql8022_and_higher is falsy(convert_bool=True)
- name: Assert that getreplica returns expected values for MySQL newer than 8.0.22
assert:
that:
- - replica_status.Is_Replica == true
- - replica_status.Source_Host == '{{ mysql_host }}'
+ - replica_status.Is_Replica is truthy(convert_bool=True)
+ - replica_status.Source_Host == mysql_host_value
- replica_status.Exec_Source_Log_Pos == mysql_primary_status.Position
- - replica_status.Source_Port == {{ mysql_primary_port }}
+ - replica_status.Source_Port == mysql_primary_port_value
- replica_status.Last_IO_Errno == 0
- replica_status.Last_IO_Error == ''
- replica_status is not changed
- when: mysql8022_and_higher == true
+ vars:
+ mysql_host_value: "{{ mysql_host }}"
+ mysql_primary_port_value: "{{ mysql_primary_port }}"
+ when: mysql8022_and_higher is truthy(convert_bool=True)
# Create test table and add data to it:
- name: Create test table
diff --git a/ansible_collections/community/mysql/tests/integration/targets/test_mysql_role/tasks/main.yml b/ansible_collections/community/mysql/tests/integration/targets/test_mysql_role/tasks/main.yml
index b517fc053..44e3308e2 100644
--- a/ansible_collections/community/mysql/tests/integration/targets/test_mysql_role/tasks/main.yml
+++ b/ansible_collections/community/mysql/tests/integration/targets/test_mysql_role/tasks/main.yml
@@ -18,3 +18,7 @@
- include_tasks: test_priv_subtract.yml
vars:
enable_check_mode: yes
+
+- name: Test column case sensitive
+ ansible.builtin.import_tasks:
+ file: test_column_case_sensitive.yml
diff --git a/ansible_collections/community/mysql/tests/integration/targets/test_mysql_role/tasks/test_column_case_sensitive.yml b/ansible_collections/community/mysql/tests/integration/targets/test_mysql_role/tasks/test_column_case_sensitive.yml
new file mode 100644
index 000000000..74849e066
--- /dev/null
+++ b/ansible_collections/community/mysql/tests/integration/targets/test_mysql_role/tasks/test_column_case_sensitive.yml
@@ -0,0 +1,149 @@
+---
+
+- vars:
+ mysql_parameters: &mysql_params
+ login_user: '{{ mysql_user }}'
+ login_password: '{{ mysql_password }}'
+ login_host: '{{ mysql_host }}'
+ login_port: '{{ mysql_primary_port }}'
+
+ block:
+
+ # ========================= Prepare =======================================
+ # We use query to prevent our module of changing the case
+ - name: Mysql_role Column case sensitive | Create a test table
+ community.mysql.mysql_query:
+ <<: *mysql_params
+ query:
+ - CREATE DATABASE mysql_role_column_case
+ - >-
+ CREATE TABLE mysql_role_column_case.t1
+ (a int, B int, cC int, Dd int)
+ - >-
+ INSERT INTO mysql_role_column_case.t1
+ (a, B, cC, Dd) VALUES (1,2,3,4)
+
+ - name: Mysql_role Column case sensitive | Create users
+ community.mysql.mysql_user:
+ <<: *mysql_params
+ name: column_case_sensitive
+ host: '%'
+ password: 'msandbox'
+
+ # ================= Reproduce failure =====================================
+
+ - name: Mysql_role Column case sensitive | Create role
+ community.mysql.mysql_role:
+ <<: *mysql_params
+ name: 'role_column_case_sensitive'
+ state: present
+ members:
+ - 'column_case_sensitive@%'
+ priv:
+ 'mysql_role_column_case.t1': 'SELECT(a, B, cC, Dd)'
+
+ - name: Mysql_role Column case sensitive | Assert role privileges are all caps
+ community.mysql.mysql_query:
+ <<: *mysql_params
+ query:
+ - SHOW GRANTS FOR role_column_case_sensitive
+ register: column_case_insensitive_grants
+ failed_when:
+ # Column order may vary, thus test each separately
+ - >-
+ column_case_insensitive_grants.query_result[0][1]
+ is not search("A", ignorecase=false)
+ or column_case_insensitive_grants.query_result[0][1]
+ is not search("B", ignorecase=false)
+ or column_case_insensitive_grants.query_result[0][1]
+ is not search("CC", ignorecase=false)
+ or column_case_insensitive_grants.query_result[0][1]
+ is not search("DD", ignorecase=false)
+
+ - name: Mysql_role Column case sensitive | Assert 1 column is accessible on MySQL
+ community.mysql.mysql_query:
+ <<: *mysql_params
+ login_user: column_case_sensitive
+ query:
+ - DESC mysql_role_column_case.t1
+ register: assert_1_col_accessible
+ failed_when:
+ - assert_1_col_accessible.rowcount[0] | int != 1
+ when:
+ - db_engine == 'mysql'
+
+ - name: Mysql_role Column case sensitive | Assert 4 column are accessible on MariaDB
+ community.mysql.mysql_query:
+ <<: *mysql_params
+ login_user: column_case_sensitive
+ query:
+ - SET ROLE role_column_case_sensitive
+ - DESC mysql_role_column_case.t1
+ register: assert_4_col_accessible
+ failed_when:
+ - assert_4_col_accessible.rowcount[1] | int != 4
+ when:
+ - db_engine == 'mariadb'
+
+ # ====================== Test the fix =====================================
+
+ - name: Mysql_role Column case sensitive | Recreate role with case sensitive
+ community.mysql.mysql_role:
+ <<: *mysql_params
+ name: 'role_column_case_sensitive'
+ state: present
+ members:
+ - 'column_case_sensitive@%'
+ priv:
+ 'mysql_role_column_case.t1': 'SELECT(a, B, cC, Dd)'
+ column_case_sensitive: true
+
+ - name: Mysql_role Column case sensitive | Assert role privileges are case sensitive
+ community.mysql.mysql_query:
+ <<: *mysql_params
+ query:
+ - SHOW GRANTS FOR role_column_case_sensitive
+ register: column_case_sensitive_grants
+ failed_when:
+ # Column order may vary, thus test each separately
+ - >-
+ column_case_sensitive_grants.query_result[0][1]
+ is not search("a", ignorecase=false)
+ or column_case_sensitive_grants.query_result[0][1]
+ is not search("B", ignorecase=false)
+ or column_case_sensitive_grants.query_result[0][1]
+ is not search("cC", ignorecase=false)
+ or column_case_sensitive_grants.query_result[0][1]
+ is not search("Dd", ignorecase=false)
+
+ - name: Mysql_role Column case sensitive | Assert 4 columns are accessible
+ community.mysql.mysql_query:
+ <<: *mysql_params
+ login_user: column_case_sensitive
+ query:
+ - SET ROLE role_column_case_sensitive
+ - DESC mysql_role_column_case.t1
+ register: assert_4_col_accessible
+ failed_when:
+ - assert_4_col_accessible.rowcount[1] | int != 4
+
+ # ========================= Teardown ======================================
+
+ - name: Mysql_role Column case sensitive | Delete test users
+ community.mysql.mysql_user:
+ <<: *mysql_params
+ name: column_case_sensitive
+ host_all: true
+ state: absent
+
+ - name: Mysql_role Column case sensitive | Delete role
+ community.mysql.mysql_role:
+ <<: *mysql_params
+ name: 'role_column_case_sensitive'
+ state: absent
+
+ - name: Mysql_role Column case sensitive | Delete test database
+ community.mysql.mysql_db:
+ <<: *mysql_params
+ name: mysql_role_column_case
+ state: absent
diff --git a/ansible_collections/community/mysql/tests/integration/targets/test_mysql_user/tasks/main.yml b/ansible_collections/community/mysql/tests/integration/targets/test_mysql_user/tasks/main.yml
index dc5c9d3cd..8ec0798c5 100644
--- a/ansible_collections/community/mysql/tests/integration/targets/test_mysql_user/tasks/main.yml
+++ b/ansible_collections/community/mysql/tests/integration/targets/test_mysql_user/tasks/main.yml
@@ -43,6 +43,8 @@
- include_tasks: test_idempotency.yml
+ - include_tasks: test_password_expire.yml
+
# ============================================================
# Create user with no privileges and verify default privileges are assign
#
@@ -117,8 +119,8 @@
- name: Assert grant access for user1 on multiple database
assert:
that:
- - "'{{ item }}' in result.stdout"
- with_items: "{{ db_names }}"
+ - item in result.stdout
+ loop: "{{ db_names }}"
- name: Show grants access for user2 on multiple database
command: "{{ mysql_command }} -e \"SHOW GRANTS FOR '{{ user_name_2 }}'@'localhost'\""
@@ -127,8 +129,8 @@
- name: Assert grant access for user2 on multiple database
assert:
that:
- - "'{{ item }}' in result.stdout"
- with_items: "{{db_names}}"
+ - item in result.stdout
+ loop: "{{db_names}}"
- include_tasks: utils/remove_user.yml
vars:
@@ -267,6 +269,9 @@
tags:
- issue_465
+ # Tests for user attributes
+ - include_tasks: test_user_attributes.yml
+
# Tests for the TLS requires dictionary
- include_tasks: test_tls_requirements.yml
@@ -286,3 +291,7 @@
- include_tasks: test_user_grants_with_roles_applied.yml
- include_tasks: test_revoke_only_grant.yml
+
+ - name: Mysql_user - test column case sensitive
+ ansible.builtin.import_tasks:
+ file: test_column_case_sensitive.yml
diff --git a/ansible_collections/community/mysql/tests/integration/targets/test_mysql_user/tasks/test_column_case_sensitive.yml b/ansible_collections/community/mysql/tests/integration/targets/test_mysql_user/tasks/test_column_case_sensitive.yml
new file mode 100644
index 000000000..68e95aa4e
--- /dev/null
+++ b/ansible_collections/community/mysql/tests/integration/targets/test_mysql_user/tasks/test_column_case_sensitive.yml
@@ -0,0 +1,134 @@
+---
+
+- vars:
+ mysql_parameters: &mysql_params
+ login_user: '{{ mysql_user }}'
+ login_password: '{{ mysql_password }}'
+ login_host: '{{ mysql_host }}'
+ login_port: '{{ mysql_primary_port }}'
+
+ block:
+
+ # ========================= Prepare =======================================
+ # We use query to prevent our module of changing the case
+ - name: Mysql_user Column case sensitive | Create a test table
+ community.mysql.mysql_query:
+ <<: *mysql_params
+ query:
+ - CREATE DATABASE mysql_user_column_case
+ - >-
+ CREATE TABLE mysql_user_column_case.t1
+ (a int, B int, cC int, Dd int)
+ - >-
+ INSERT INTO mysql_user_column_case.t1
+ (a, B, cC, Dd) VALUES (1,2,3,4)
+
+ # ================= Reproduce failure =====================================
+
+ - name: Mysql_user Column case sensitive | Create test user
+ community.mysql.mysql_user:
+ <<: *mysql_params
+ name: column_case_sensitive
+ host: '%'
+ password: 'msandbox'
+ priv:
+ 'mysql_user_column_case.t1': 'SELECT(a, B, cC, Dd)'
+
+ - name: Mysql_user Column case sensitive | Assert user privileges are all caps
+ community.mysql.mysql_query:
+ <<: *mysql_params
+ query:
+ - SHOW GRANTS FOR column_case_sensitive@'%'
+ register: column_case_insensitive_grants
+ failed_when:
+ # Column order may vary, thus test each separately
+ - >-
+ column_case_insensitive_grants.query_result[0][1]
+ is not search("A", ignorecase=false)
+ or column_case_insensitive_grants.query_result[0][1]
+ is not search("B", ignorecase=false)
+ or column_case_insensitive_grants.query_result[0][1]
+ is not search("CC", ignorecase=false)
+ or column_case_insensitive_grants.query_result[0][1]
+ is not search("DD", ignorecase=false)
+
+ - name: Mysql_user Column case sensitive | Assert 1 column is accessible on MySQL 5.7
+ community.mysql.mysql_query:
+ <<: *mysql_params
+ login_user: column_case_sensitive
+ query:
+ - DESC mysql_user_column_case.t1
+ register: assert_1_col_accessible
+ failed_when:
+ - assert_1_col_accessible.rowcount[0] | int != 1
+ when:
+ - db_engine == 'mysql' and db_version is version('5.7', '<=')
+
+ - name: Mysql_user Column case sensitive | Assert 4 column are accessible on MariaDB and MySQL 8+
+ community.mysql.mysql_query:
+ <<: *mysql_params
+ login_user: column_case_sensitive
+ query:
+ - DESC mysql_user_column_case.t1
+ register: assert_4_col_accessible
+ failed_when:
+ - assert_4_col_accessible.rowcount[0] | int != 4
+ when:
+ - >-
+ db_engine == 'mariadb'
+ or (db_engine == 'mysql' and db_version is version('8.0', '>='))
+
+ # ======================== Test fix ======================================
+
+ - name: Mysql_user Column case sensitive | Create users with case sensitive
+ community.mysql.mysql_user:
+ <<: *mysql_params
+ name: column_case_sensitive
+ host: '%'
+ password: 'msandbox'
+ priv:
+ 'mysql_user_column_case.t1': 'SELECT(a, B, cC, Dd)'
+ column_case_sensitive: true
+
+ - name: Mysql_user Column case sensitive | Assert user privileges are case sensitive
+ community.mysql.mysql_query:
+ <<: *mysql_params
+ query:
+ - SHOW GRANTS FOR column_case_sensitive@'%'
+ register: column_case_sensitive_grants
+ failed_when:
+ # Column order may vary, thus test each separately
+ - >-
+ column_case_sensitive_grants.query_result[0][1]
+ is not search("a", ignorecase=false)
+ or column_case_sensitive_grants.query_result[0][1]
+ is not search("B", ignorecase=false)
+ or column_case_sensitive_grants.query_result[0][1]
+ is not search("cC", ignorecase=false)
+ or column_case_sensitive_grants.query_result[0][1]
+ is not search("Dd", ignorecase=false)
+
+ - name: Mysql_user Column case sensitive | Assert 4 columns are accessible
+ community.mysql.mysql_query:
+ <<: *mysql_params
+ login_user: column_case_sensitive
+ query:
+ - DESC mysql_user_column_case.t1
+ register: assert_4_col_accessible
+ failed_when:
+ - assert_4_col_accessible.rowcount[0] | int != 4
+
+ # ========================= Teardown ======================================
+
+ - name: Mysql_user Column case sensitive | Delete test users
+ community.mysql.mysql_user:
+ <<: *mysql_params
+ name: column_case_sensitive
+ host_all: true
+ state: absent
+
+ - name: Mysql_user Column case sensitive | Delete test database
+ community.mysql.mysql_db:
+ <<: *mysql_params
+ name: mysql_user_column_case
+ state: absent
diff --git a/ansible_collections/community/mysql/tests/integration/targets/test_mysql_user/tasks/test_password_expire.yml b/ansible_collections/community/mysql/tests/integration/targets/test_mysql_user/tasks/test_password_expire.yml
new file mode 100644
index 000000000..7e70ece0e
--- /dev/null
+++ b/ansible_collections/community/mysql/tests/integration/targets/test_mysql_user/tasks/test_password_expire.yml
@@ -0,0 +1,174 @@
+---
+# Tests scenarios for password_expire
+
+- vars:
+ mysql_parameters: &mysql_params
+ login_user: "{{ mysql_user }}"
+ login_password: "{{ mysql_password }}"
+ login_host: "{{ mysql_host }}"
+ login_port: "{{ mysql_primary_port }}"
+
+ block:
+ - include_tasks: utils/assert_user_password_expire.yml
+ vars:
+ username: "{{ item.username }}"
+ host: "{{ item.host | default('localhost')}}"
+ password_expire: "{{ item.password_expire }}"
+ password: "{{ user_password_1 }}"
+ expect_change: "{{ item.expect_change }}"
+ expect_password_expire_change: "{{ item.expect_password_expire_change }}"
+ expected_password_lifetime: "{{ item.expected_password_lifetime }}"
+ password_expire_interval: "{{ item.password_expire_interval | default(omit) }}"
+ expected_password_expired: "{{ item.expected_password_expired }}"
+ check_mode: "{{ item.check_mode | default(omit) }}"
+ loop:
+ # all variants set the password when nothing exists
+ # never expires
+ - username: "{{ user_name_1 }}"
+ host: "%"
+ password_expire: never
+ expect_change: true
+ expected_password_lifetime: "0"
+ expected_password_expired: "N"
+ # expires ussing default policy
+ - username: "{{ user_name_2 }}"
+ password_expire: default
+ expect_change: true
+ expected_password_lifetime: "-1"
+ expected_password_expired: "N"
+ # expires ussing interval
+ - username: "{{ user_name_3 }}"
+ password_expire: interval
+ password_expire_interval: "10"
+ expect_change: true
+ expected_password_lifetime: "10"
+ expected_password_expired: "N"
+
+ # assert idempotency
+ - username: "{{ user_name_1 }}"
+ host: "%"
+ password_expire: never
+ expect_change: false
+ expected_password_lifetime: "0"
+ expected_password_expired: "N"
+ - username: "{{ user_name_2 }}"
+ password_expire: default
+ expect_change: false
+ expected_password_lifetime: "-1"
+ expected_password_expired: "N"
+ - username: "{{ user_name_3 }}"
+ password_expire: interval
+ password_expire_interval: "10"
+ expect_change: false
+ expected_password_lifetime: "10"
+ expected_password_expired: "N"
+
+ # assert change is made
+ - username: "{{ user_name_3 }}"
+ password_expire: never
+ expect_change: true
+ expected_password_lifetime: "0"
+ expected_password_expired: "N"
+ - username: "{{ user_name_1 }}"
+ host: "%"
+ password_expire: default
+ expect_change: true
+ expected_password_lifetime: "-1"
+ expected_password_expired: "N"
+ - username: "{{ user_name_2 }}"
+ password_expire: interval
+ password_expire_interval: "100"
+ expect_change: true
+ expected_password_lifetime: "100"
+ expected_password_expired: "N"
+
+ # assert password expires now
+ - username: "{{ user_name_1 }}"
+ host: "%"
+ password_expire: now
+ expect_change: true
+ expected_password_lifetime: "-1" # password lifetime should be the same
+ expected_password_expired: "Y"
+ - username: "{{ user_name_2 }}"
+ password_expire: now
+ expect_change: true
+ expected_password_lifetime: "100" # password lifetime should be the same
+ expected_password_expired: "Y"
+
+ # assert idempotency password expires now
+ - username: "{{ user_name_1 }}"
+ host: "%"
+ password_expire: now
+ expect_change: false
+ expected_password_lifetime: "-1" # password lifetime should be the same
+ expected_password_expired: "Y"
+ - username: "{{ user_name_2 }}"
+ password_expire: now
+ expect_change: false
+ expected_password_lifetime: "100" # password lifetime should be the same
+ expected_password_expired: "Y"
+
+ # assert check_mode
+ - username: "{{ user_name_3 }}"
+ password_expire: interval
+ password_expire_interval: 10
+ check_mode: true
+ expect_change: false
+ expected_password_lifetime: "0"
+ expected_password_expired: "N"
+
+ - name: password_expire | Set password_expire = interval without password_expire_interval
+ community.mysql.mysql_user:
+ <<: *mysql_params
+ name: '{{ user_name_4 }}'
+ host: '%'
+ password: '{{ user_password_4 }}'
+ password_expire: interval
+ state: present
+ register: result
+ ignore_errors: true
+
+ - name: password_expire | Assert that action fails if 'password_expire_interval' not set
+ ansible.builtin.assert:
+ that:
+ - result is failed
+
+ - name: password_expire | Set password_expire_interval < 1
+ community.mysql.mysql_user:
+ <<: *mysql_params
+ name: '{{ user_name_4 }}'
+ host: '%'
+ password: '{{ user_password_4 }}'
+ password_expire: interval
+ password_expire_interval: -1
+ state: present
+ register: result
+ ignore_errors: true
+
+ - name: password_expire | Assert that action fails if 'password_expire_interval' is < 1
+ ansible.builtin.assert:
+ that:
+ - result is failed
+ - "'should be positive number' in result.msg"
+
+ - name: password_expire | check mode for user creation
+ community.mysql.mysql_user:
+ <<: *mysql_params
+ name: '{{ user_name_4 }}'
+ host: '%'
+ password: '{{ user_password_4 }}'
+ password_expire: interval
+ password_expire_interval: 20
+ state: present
+ register: result
+ check_mode: True
+ failed_when: result is changed
+
+ - include_tasks: utils/remove_user.yml
+ vars:
+ user_name: "{{ item.username }}"
+ loop:
+ - username: "{{ user_name_1 }}"
+ - username: "{{ user_name_2 }}"
+ - username: "{{ user_name_3 }}"
+ - username: "{{ user_name_4 }}"
diff --git a/ansible_collections/community/mysql/tests/integration/targets/test_mysql_user/tasks/test_user_attributes.yml b/ansible_collections/community/mysql/tests/integration/targets/test_mysql_user/tasks/test_user_attributes.yml
new file mode 100644
index 000000000..b5cec1004
--- /dev/null
+++ b/ansible_collections/community/mysql/tests/integration/targets/test_mysql_user/tasks/test_user_attributes.yml
@@ -0,0 +1,474 @@
+---
+- vars:
+ mysql_parameters: &mysql_params
+ login_user: '{{ mysql_user }}'
+ login_password: '{{ mysql_password }}'
+ login_host: '{{ mysql_host }}'
+ login_port: '{{ mysql_primary_port }}'
+
+ block:
+
+ - when: db_engine == 'mariadb'
+ block:
+
+ # ============================================================
+ # Fail creating a user with mariadb
+ #
+
+ # Check mode
+ - name: Attributes | Attempt to create user with attributes with mariadb in check mode
+ mysql_user:
+ <<: *mysql_params
+ name: '{{ user_name_2 }}'
+ host: '%'
+ password: '{{ user_password_2 }}'
+ attributes:
+ key1: "value1"
+ ignore_errors: yes
+ register: result_module
+ check_mode: yes
+
+ - name: Attributes | Run query to verify user creation with attributes fails with mariadb in check mode
+ mysql_query:
+ <<: *mysql_params
+ query: 'SELECT user FROM mysql.user WHERE user = "{{ user_name_2 }}" AND host = "%"'
+ ignore_errors: yes
+ register: result_query
+
+ - name: Attributes | Assert that creating user with attributes fails with mariadb in check mode
+ assert:
+ that:
+ - result_module is failed
+ - not result_query.query_result[0]
+
+ # Real mode
+ - name: Attributes | Attempt to create user with attributes with mariadb
+ mysql_user:
+ <<: *mysql_params
+ name: '{{ user_name_2 }}'
+ host: '%'
+ password: '{{ user_password_2 }}'
+ attributes:
+ key1: "value1"
+ ignore_errors: yes
+ register: result_module
+
+ - name: Attributes | Run query to verify user creation with attributes fails with mariadb
+ mysql_query:
+ <<: *mysql_params
+ query: 'SELECT user FROM mysql.user WHERE user = "{{ user_name_2 }}" AND host = "%"'
+ register: result_query
+
+ - name: Attributes | Assert that creating user with attributes fails with mariadb
+ assert:
+ that:
+ - result_module is failed
+ - not result_query.query_result[0]
+
+ - when: db_engine == 'mysql'
+ block:
+
+ # ============================================================
+ # Create user with no attributes (test attributes return type)
+ #
+
+ # Check mode
+ - name: Attributes | Test creating a user with no attributes in check mode
+ mysql_user:
+ <<: *mysql_params
+ name: '{{ user_name_2 }}'
+ host: '%'
+ password: '{{ user_password_2 }}'
+ register: result_module
+ check_mode: yes
+
+ - name: Attributes | Run query to verify user creation with no attributes did not take place in check mode
+ mysql_query:
+ <<: *mysql_params
+ query: 'SELECT user FROM mysql.user WHERE user = "{{ user_name_2 }}" AND host = "%"'
+ register: result_query
+
+ - name: Attributes | Assert that user would have been created without attributes
+ assert:
+ that:
+ - result_module is changed
+ - result_module.attributes is none
+ - not result_query.query_result[0]
+
+ # Real mode
+ - name: Attributes | Test creating a user with no attributes
+ mysql_user:
+ <<: *mysql_params
+ name: '{{ user_name_2 }}'
+ host: '%'
+ password: '{{ user_password_2 }}'
+ register: result_module
+
+ - name: Attributes | Run query to verify created user without attributes
+ mysql_query:
+ <<: *mysql_params
+ query: 'SELECT attribute FROM INFORMATION_SCHEMA.USER_ATTRIBUTES WHERE user = "{{ user_name_2 }}" AND host = "%"'
+ register: result_query
+
+ - name: Attributes | Assert that user was created without attributes
+ assert:
+ that:
+ - result_module is changed
+ - result_module.attributes is none
+ - result_query.query_result[0][0]['ATTRIBUTE'] is none
+
+ # Clean up user to allow it to be recreated with attributes
+ - include_tasks: utils/remove_user.yml
+ vars:
+ user_name: "{{ user_name_2 }}"
+
+ # ============================================================
+ # Create user with attributes
+ #
+
+ # Check mode
+ - name: Attributes | Test creating a user with attributes in check mode
+ mysql_user:
+ <<: *mysql_params
+ name: '{{ user_name_2 }}'
+ host: '%'
+ password: '{{ user_password_2 }}'
+ attributes:
+ key1: "value1"
+ register: result_module
+ check_mode: yes
+
+ - name: Attributes | Run query to verify user creation did not take place in check mode
+ mysql_query:
+ <<: *mysql_params
+ query: 'SELECT user FROM mysql.user WHERE user = "{{ user_name_2 }}" AND host = "%"'
+ register: result_query
+
+ - name: Attributes | Assert that user would have been created with attributes
+ assert:
+ that:
+ - result_module is changed
+ - result_module.attributes.key1 == "value1"
+ - not result_query.query_result[0]
+
+ # Real mode
+ - name: Attributes | Test creating a user with attributes
+ mysql_user:
+ <<: *mysql_params
+ name: '{{ user_name_2 }}'
+ host: '%'
+ password: '{{ user_password_2 }}'
+ attributes:
+ key1: "value1"
+ register: result_module
+
+ - name: Attributes | Run query to verify created user attributes
+ mysql_query:
+ <<: *mysql_params
+ query: 'SELECT attribute FROM INFORMATION_SCHEMA.USER_ATTRIBUTES WHERE user = "{{ user_name_2 }}" AND host = "%"'
+ register: result_query
+
+ - name: Attributes | Assert that user was created with attributes
+ assert:
+ that:
+ - result_module is changed
+ - result_module.attributes.key1 == "value1"
+ - (result_query.query_result[0][0]['ATTRIBUTE'] | from_yaml)['key1'] == "value1"
+
+ # ============================================================
+ # Append attributes on an existing user
+ #
+
+ # Check mode
+ - name: Attributes | Test appending attributes to an existing user in check mode
+ mysql_user:
+ <<: *mysql_params
+ name: '{{ user_name_2 }}'
+ host: '%'
+ attributes:
+ key2: "value2"
+ register: result_module
+ check_mode: yes
+
+ - name: Attributes | Run query to check appended attributes in check mode
+ mysql_query:
+ <<: *mysql_params
+ query: 'SELECT attribute FROM INFORMATION_SCHEMA.USER_ATTRIBUTES WHERE user = "{{ user_name_2 }}" AND host = "%"'
+ register: result_query
+
+ - name: Attributes | Assert that attribute would have been appended and existing attribute stays
+ assert:
+ that:
+ - result_module is changed
+ - result_module.attributes.key1 == "value1"
+ - result_module.attributes.key2 == "value2"
+ - "'key2' not in result_query.query_result[0][0]['ATTRIBUTE'] | from_yaml"
+
+ # Real mode
+ - name: Attributes | Test appending attributes to an existing user
+ mysql_user:
+ <<: *mysql_params
+ name: '{{ user_name_2 }}'
+ host: '%'
+ attributes:
+ key2: "value2"
+ register: result_module
+
+ - name: Attributes | Run query to check appended attributes
+ mysql_query:
+ <<: *mysql_params
+ query: 'SELECT attribute FROM INFORMATION_SCHEMA.USER_ATTRIBUTES WHERE user = "{{ user_name_2 }}" AND host = "%"'
+ register: result_query
+
+ - name: Attributes | Assert that new attribute was appended and existing attribute stays
+ assert:
+ that:
+ - result_module is changed
+ - result_module.attributes.key1 == "value1"
+ - result_module.attributes.key2 == "value2"
+ - (result_query.query_result[0][0]['ATTRIBUTE'] | from_yaml)['key1'] == "value1"
+ - (result_query.query_result[0][0]['ATTRIBUTE'] | from_yaml)['key2'] == "value2"
+
+ # ============================================================
+ # Test updating existing attributes
+ #
+
+ # Check mode
+ - name: Attributes | Test updating attributes on an existing user in check mode
+ mysql_user:
+ <<: *mysql_params
+ name: '{{ user_name_2 }}'
+ host: '%'
+ attributes:
+ key2: "new_value2"
+ check_mode: yes
+ register: result_module
+
+ - name: Attributes | Run query to verify updated attribute in check mode
+ mysql_query:
+ <<: *mysql_params
+ query: 'SELECT attribute FROM INFORMATION_SCHEMA.USER_ATTRIBUTES WHERE user = "{{ user_name_2 }}" AND host = "%"'
+ register: result_query
+
+ - name: Attributes | Assert that attribute would have been updated
+ assert:
+ that:
+ - result_module is changed
+ - result_module.attributes.key2 == "new_value2"
+ - (result_query.query_result[0][0]['ATTRIBUTE'] | from_yaml)['key2'] == "value2"
+
+ # Real mode
+ - name: Attributes | Test updating attributes on an existing user
+ mysql_user:
+ <<: *mysql_params
+ name: '{{ user_name_2 }}'
+ host: '%'
+ attributes:
+ key2: "new_value2"
+ register: result_module
+
+ - name: Attributes | Run query to verify updated attribute
+ mysql_query:
+ <<: *mysql_params
+ query: 'SELECT attribute FROM INFORMATION_SCHEMA.USER_ATTRIBUTES WHERE user = "{{ user_name_2 }}" AND host = "%"'
+ register: result_query
+
+ - name: Attributes | Assert that attribute was updated
+ assert:
+ that:
+ - result_module is changed
+ - result_module.attributes.key2 == "new_value2"
+ - (result_query.query_result[0][0]['ATTRIBUTE'] | from_yaml)['key2'] == "new_value2"
+
+ # ============================================================
+ # Test attribute idempotency when specifying attributes
+ #
+
+ # Check mode
+ - name: Attributes | Test attribute idempotency by trying to change an already correct attribute in check mode
+ mysql_user:
+ <<: *mysql_params
+ name: '{{ user_name_2 }}'
+ host: '%'
+ attributes:
+ key1: "value1"
+ register: result_module
+ check_mode: yes
+
+ - name: Attributes | Run query to verify idempotency of already correct attribute in check mode
+ mysql_query:
+ <<: *mysql_params
+ query: 'SELECT attribute FROM INFORMATION_SCHEMA.USER_ATTRIBUTES WHERE user = "{{ user_name_2 }}" AND host = "%"'
+ register: result_query
+
+ - name: Attributes | Assert that attribute would not have been updated
+ assert:
+ that:
+ - result_module is not changed
+ - result_module.attributes.key1 == "value1"
+ - (result_query.query_result[0][0]['ATTRIBUTE'] | from_yaml)['key1'] == "value1"
+
+ # Real mode
+ - name: Attributes | Test attribute idempotency by trying to change an already correct attribute
+ mysql_user:
+ <<: *mysql_params
+ name: '{{ user_name_2 }}'
+ host: '%'
+ attributes:
+ key1: "value1"
+ register: result_module
+
+ - name: Attributes | Run query to verify idempotency of already correct attribute
+ mysql_query:
+ <<: *mysql_params
+ query: 'SELECT attribute FROM INFORMATION_SCHEMA.USER_ATTRIBUTES WHERE user = "{{ user_name_2 }}" AND host = "%"'
+ register: result_query
+
+ - name: Attributes | Assert that attribute was not updated
+ assert:
+ that:
+ - result_module is not changed
+ - result_module.attributes.key1 == "value1"
+ - (result_query.query_result[0][0]['ATTRIBUTE'] | from_yaml)['key1'] == "value1"
+
+ # ============================================================
+ # Test attribute idempotency when not specifying attribute parameter
+ #
+
+ # Check mode
+ - name: Attributes | Test attribute idempotency by not specifying attribute parameter in check mode
+ mysql_user:
+ <<: *mysql_params
+ name: '{{ user_name_2 }}'
+ host: '%'
+ register: result_module
+ check_mode: yes
+
+ - name: Attributes | Run query to verify idempotency when not specifying attribute parameter in check mode
+ mysql_query:
+ <<: *mysql_params
+ query: 'SELECT attribute FROM INFORMATION_SCHEMA.USER_ATTRIBUTES WHERE user = "{{ user_name_2 }}" AND host = "%"'
+ register: result_query
+
+ - name: Attributes | Assert that attribute is returned in check mode
+ assert:
+ that:
+ - result_module is not changed
+ - result_module.attributes.key1 == "value1"
+ - (result_query.query_result[0][0]['ATTRIBUTE'] | from_yaml)['key1'] == "value1"
+
+ # Real mode
+ - name: Attributes | Test attribute idempotency by not specifying attribute parameter
+ mysql_user:
+ <<: *mysql_params
+ name: '{{ user_name_2 }}'
+ host: '%'
+ register: result_module
+
+ - name: Attributes | Run query to verify idempotency when not specifying attribute parameter
+ mysql_query:
+ <<: *mysql_params
+ query: 'SELECT attribute FROM INFORMATION_SCHEMA.USER_ATTRIBUTES WHERE user = "{{ user_name_2 }}" AND host = "%"'
+ register: result_query
+
+ - name: Attributes | Assert that attribute is returned
+ assert:
+ that:
+ - result_module is not changed
+ - result_module.attributes.key1 == "value1"
+ - (result_query.query_result[0][0]['ATTRIBUTE'] | from_yaml)['key1'] == "value1"
+
+ # ============================================================
+ # Test deleting attributes
+ #
+
+ # Check mode
+ - name: Attributes | Test deleting attributes on an existing user in check mode
+ mysql_user:
+ <<: *mysql_params
+ name: '{{ user_name_2 }}'
+ host: '%'
+ attributes:
+ key2: null
+ register: result_module
+ check_mode: yes
+
+ - name: Attributes | Run query to verify deleted attribute in check mode
+ mysql_query:
+ <<: *mysql_params
+ query: 'SELECT attribute FROM INFORMATION_SCHEMA.USER_ATTRIBUTES WHERE user = "{{ user_name_2 }}" AND host = "%"'
+ register: result_query
+
+ - name: Attributes | Assert that attribute would have been deleted
+ assert:
+ that:
+ - result_module is changed
+ - "'key2' not in result_module.attributes"
+ - (result_query.query_result[0][0]['ATTRIBUTE'] | from_yaml)['key2'] == "new_value2"
+
+ # Real mode
+ - name: Attributes | Test deleting attributes on an existing user
+ mysql_user:
+ <<: *mysql_params
+ name: '{{ user_name_2 }}'
+ host: '%'
+ attributes:
+ key2: null
+ register: result_module
+
+ - name: Attributes | Run query to verify deleted attribute
+ mysql_query:
+ <<: *mysql_params
+ query: 'SELECT attribute FROM INFORMATION_SCHEMA.USER_ATTRIBUTES WHERE user = "{{ user_name_2 }}" AND host = "%"'
+ register: result_query
+
+ - name: Attributes | Assert that attribute was deleted
+ assert:
+ that:
+ - result_module is changed
+ - "'key2' not in result_module.attributes"
+ - "'key2' not in result_query.query_result[0][0]['ATTRIBUTE'] | from_yaml"
+
+ # ============================================================
+ # Test attribute return value when no attributes exist
+ #
+
+ # Check mode
+ - name: Attributes | Test attributes return value when no attributes exist in check mode
+ mysql_user:
+ <<: *mysql_params
+ name: '{{ user_name_2 }}'
+ host: '%'
+ attributes:
+ key1: null
+ register: result_module
+ check_mode: yes
+
+ - name: Attributes | Assert attributes return value when no attributes exist in check mode
+ assert:
+ that:
+ - result_module is changed
+ - result_module.attributes is none
+
+ # Real mode
+ - name: Attributes | Test attributes return value when no attributes exist
+ mysql_user:
+ <<: *mysql_params
+ name: '{{ user_name_2 }}'
+ host: '%'
+ attributes:
+ key1: null
+ register: result_module
+
+ - name: Attributes | Assert attributes return value when no attributes exist
+ assert:
+ that:
+ - result_module is changed
+ - result_module.attributes is none
+
+ # ============================================================
+ # Cleanup
+ #
+ - include_tasks: utils/remove_user.yml
+ vars:
+ user_name: "{{ user_name_2 }}"
diff --git a/ansible_collections/community/mysql/tests/integration/targets/test_mysql_user/tasks/utils/assert_user_password_expire.yml b/ansible_collections/community/mysql/tests/integration/targets/test_mysql_user/tasks/utils/assert_user_password_expire.yml
new file mode 100644
index 000000000..3798802ea
--- /dev/null
+++ b/ansible_collections/community/mysql/tests/integration/targets/test_mysql_user/tasks/utils/assert_user_password_expire.yml
@@ -0,0 +1,56 @@
+---
+- name: Utils | Assert user password_expire | Create modify {{ username }} with password_expire
+ community.mysql.mysql_user:
+ login_user: "{{ mysql_parameters.login_user }}"
+ login_password: "{{ mysql_parameters.login_password }}"
+ login_host: "{{ mysql_parameters.login_host }}"
+ login_port: "{{ mysql_parameters.login_port }}"
+ state: present
+ name: "{{ username }}"
+ host: "{{ host }}"
+ password: "{{ password }}"
+ password_expire: "{{ password_expire }}"
+ password_expire_interval: "{{ password_expire_interval | default(omit) }}"
+ register: result
+ check_mode: "{{ check_mode | default(false) }}"
+ failed_when: result.changed != expect_change_value
+ vars:
+ expect_change_value: "{{ expect_change }}"
+
+- name: Utils | Assert user password_lifetime | Query user '{{ username }}'
+ ansible.builtin.command:
+ cmd: >
+ {{ mysql_command }} -BNe "SELECT IFNULL(password_lifetime, -1)
+ FROM mysql.user where user='{{ username }}' and host='{{ host }}'"
+ register: password_lifetime
+ when:
+ - db_engine == 'mysql'
+ - db_version is version('5.7.0', '>=')
+ failed_when: expected_password_lifetime_value not in password_lifetime.stdout_lines
+ vars:
+ expected_password_lifetime_value: "{{ expected_password_lifetime }}"
+
+- name: Utils | Assert user password_lifetime | Query user '{{ username }}'
+ ansible.builtin.command:
+ "{{ mysql_command }} -BNe \"SELECT JSON_EXTRACT(Priv, '$.password_lifetime') AS password_lifetime \
+ FROM mysql.global_priv \
+ WHERE user='{{ username }}' and host='{{ host }}'\""
+ register: password_lifetime
+ when:
+ - db_engine == 'mariadb'
+ - db_version is version('10.4.3', '>=')
+ failed_when: expected_password_lifetime_value not in password_lifetime.stdout_lines
+ vars:
+ expected_password_lifetime_value: "{{ expected_password_lifetime }}"
+
+- name: Utils | Assert user password_expired | Query user '{{ username }}'
+ ansible.builtin.command:
+ cmd: >
+ {{ mysql_command }} -BNe "SELECT password_expired FROM mysql.user
+ WHERE user='{{ username }}' and host='{{ host }}'"
+ register: password_expired
+ when: (db_engine == 'mysql' and db_version is version('5.7.0', '>=')) or
+ (db_engine == 'mariadb' and db_version is version('10.4.3', '>='))
+ failed_when: expected_password_expired_value not in password_expired.stdout_lines
+ vars:
+ expected_password_expired_value: "{{ expected_password_expired }}"
diff --git a/ansible_collections/community/mysql/tests/sanity/ignore-2.12.txt b/ansible_collections/community/mysql/tests/sanity/ignore-2.12.txt
deleted file mode 100644
index c0323aff3..000000000
--- a/ansible_collections/community/mysql/tests/sanity/ignore-2.12.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-plugins/modules/mysql_db.py validate-modules:doc-elements-mismatch
-plugins/modules/mysql_db.py validate-modules:parameter-list-no-elements
-plugins/modules/mysql_db.py validate-modules:use-run-command-not-popen
-plugins/modules/mysql_info.py validate-modules:doc-elements-mismatch
-plugins/modules/mysql_info.py validate-modules:parameter-list-no-elements
-plugins/modules/mysql_query.py validate-modules:parameter-list-no-elements
-plugins/modules/mysql_user.py validate-modules:undocumented-parameter
-plugins/modules/mysql_variables.py validate-modules:doc-required-mismatch
diff --git a/ansible_collections/community/mysql/tests/sanity/ignore-2.13.txt b/ansible_collections/community/mysql/tests/sanity/ignore-2.13.txt
deleted file mode 100644
index c0323aff3..000000000
--- a/ansible_collections/community/mysql/tests/sanity/ignore-2.13.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-plugins/modules/mysql_db.py validate-modules:doc-elements-mismatch
-plugins/modules/mysql_db.py validate-modules:parameter-list-no-elements
-plugins/modules/mysql_db.py validate-modules:use-run-command-not-popen
-plugins/modules/mysql_info.py validate-modules:doc-elements-mismatch
-plugins/modules/mysql_info.py validate-modules:parameter-list-no-elements
-plugins/modules/mysql_query.py validate-modules:parameter-list-no-elements
-plugins/modules/mysql_user.py validate-modules:undocumented-parameter
-plugins/modules/mysql_variables.py validate-modules:doc-required-mismatch
diff --git a/ansible_collections/community/mysql/tests/sanity/ignore-2.14.txt b/ansible_collections/community/mysql/tests/sanity/ignore-2.14.txt
index c0323aff3..90ddba308 100644
--- a/ansible_collections/community/mysql/tests/sanity/ignore-2.14.txt
+++ b/ansible_collections/community/mysql/tests/sanity/ignore-2.14.txt
@@ -1,8 +1,2 @@
-plugins/modules/mysql_db.py validate-modules:doc-elements-mismatch
-plugins/modules/mysql_db.py validate-modules:parameter-list-no-elements
plugins/modules/mysql_db.py validate-modules:use-run-command-not-popen
-plugins/modules/mysql_info.py validate-modules:doc-elements-mismatch
-plugins/modules/mysql_info.py validate-modules:parameter-list-no-elements
-plugins/modules/mysql_query.py validate-modules:parameter-list-no-elements
plugins/modules/mysql_user.py validate-modules:undocumented-parameter
-plugins/modules/mysql_variables.py validate-modules:doc-required-mismatch
diff --git a/ansible_collections/community/mysql/tests/sanity/ignore-2.15.txt b/ansible_collections/community/mysql/tests/sanity/ignore-2.15.txt
index da0354c97..55b29043e 100644
--- a/ansible_collections/community/mysql/tests/sanity/ignore-2.15.txt
+++ b/ansible_collections/community/mysql/tests/sanity/ignore-2.15.txt
@@ -1,10 +1,4 @@
-plugins/modules/mysql_db.py validate-modules:doc-elements-mismatch
-plugins/modules/mysql_db.py validate-modules:parameter-list-no-elements
plugins/modules/mysql_db.py validate-modules:use-run-command-not-popen
-plugins/modules/mysql_info.py validate-modules:doc-elements-mismatch
-plugins/modules/mysql_info.py validate-modules:parameter-list-no-elements
-plugins/modules/mysql_query.py validate-modules:parameter-list-no-elements
plugins/modules/mysql_user.py validate-modules:undocumented-parameter
-plugins/modules/mysql_variables.py validate-modules:doc-required-mismatch
plugins/module_utils/mysql.py pylint:unused-import
plugins/module_utils/version.py pylint:unused-import
diff --git a/ansible_collections/community/mysql/tests/sanity/ignore-2.16.txt b/ansible_collections/community/mysql/tests/sanity/ignore-2.16.txt
index da0354c97..55b29043e 100644
--- a/ansible_collections/community/mysql/tests/sanity/ignore-2.16.txt
+++ b/ansible_collections/community/mysql/tests/sanity/ignore-2.16.txt
@@ -1,10 +1,4 @@
-plugins/modules/mysql_db.py validate-modules:doc-elements-mismatch
-plugins/modules/mysql_db.py validate-modules:parameter-list-no-elements
plugins/modules/mysql_db.py validate-modules:use-run-command-not-popen
-plugins/modules/mysql_info.py validate-modules:doc-elements-mismatch
-plugins/modules/mysql_info.py validate-modules:parameter-list-no-elements
-plugins/modules/mysql_query.py validate-modules:parameter-list-no-elements
plugins/modules/mysql_user.py validate-modules:undocumented-parameter
-plugins/modules/mysql_variables.py validate-modules:doc-required-mismatch
plugins/module_utils/mysql.py pylint:unused-import
plugins/module_utils/version.py pylint:unused-import
diff --git a/ansible_collections/community/mysql/tests/sanity/ignore-2.17.txt b/ansible_collections/community/mysql/tests/sanity/ignore-2.17.txt
new file mode 100644
index 000000000..55b29043e
--- /dev/null
+++ b/ansible_collections/community/mysql/tests/sanity/ignore-2.17.txt
@@ -0,0 +1,4 @@
+plugins/modules/mysql_db.py validate-modules:use-run-command-not-popen
+plugins/modules/mysql_user.py validate-modules:undocumented-parameter
+plugins/module_utils/mysql.py pylint:unused-import
+plugins/module_utils/version.py pylint:unused-import
diff --git a/ansible_collections/community/mysql/tests/unit/plugins/module_utils/test_mysql.py b/ansible_collections/community/mysql/tests/unit/plugins/module_utils/test_mysql.py
index ac4de24f4..5410575b6 100644
--- a/ansible_collections/community/mysql/tests/unit/plugins/module_utils/test_mysql.py
+++ b/ansible_collections/community/mysql/tests/unit/plugins/module_utils/test_mysql.py
@@ -1,9 +1,10 @@
from __future__ import (absolute_import, division, print_function)
+
__metaclass__ = type
import pytest
-from ansible_collections.community.mysql.plugins.module_utils.mysql import get_server_version
+from ansible_collections.community.mysql.plugins.module_utils.mysql import get_server_version, get_server_implementation
from ..utils import dummy_cursor_class
@@ -22,3 +23,21 @@ def test_get_server_version(cursor_return_version, cursor_return_type):
"""
cursor = dummy_cursor_class(cursor_return_version, cursor_return_type)
assert get_server_version(cursor) == cursor_return_version
+
+
+@pytest.mark.parametrize(
+ 'cursor_return_version,cursor_return_type,server_implementation',
+ [
+ ('5.7.0-mysql', 'dict', 'mysql'),
+ ('8.0.0-mysql', 'list', 'mysql'),
+ ('10.5.0-mariadb', 'dict', 'mariadb'),
+ ('10.5.1-mariadb', 'list', 'mariadb'),
+ ]
+)
+def test_get_server_implamentation(cursor_return_version, cursor_return_type, server_implementation):
+ """
+ Test that server implementation are handled properly by get_server_implementation() whether the server version returned as a list or dict.
+ """
+ cursor = dummy_cursor_class(cursor_return_version, cursor_return_type)
+
+ assert get_server_implementation(cursor) == server_implementation
diff --git a/ansible_collections/community/mysql/tests/unit/plugins/module_utils/test_mysql_user.py b/ansible_collections/community/mysql/tests/unit/plugins/module_utils/test_mysql_user.py
index 46b3b8eb6..bb1ec2446 100644
--- a/ansible_collections/community/mysql/tests/unit/plugins/module_utils/test_mysql_user.py
+++ b/ansible_collections/community/mysql/tests/unit/plugins/module_utils/test_mysql_user.py
@@ -9,7 +9,8 @@ from ansible_collections.community.mysql.plugins.module_utils.user import (
handle_grant_on_col,
has_grant_on_col,
normalize_col_grants,
- sort_column_order
+ sort_column_order,
+ privileges_unpack,
)
@@ -92,3 +93,21 @@ def test_handle_grant_on_col(privileges, start, end, output):
def test_normalize_col_grants(input_, expected):
"""Tests normalize_col_grants function."""
assert normalize_col_grants(input_) == expected
+
+
+@pytest.mark.parametrize(
+ 'priv,expected,mode,column_case_sensitive,ensure_usage',
+ [
+ ('mydb.*:SELECT', {'"mydb".*': ['SELECT']}, 'ANSI', False, False),
+ ('mydb.*:SELECT', {'`mydb`.*': ['SELECT']}, 'NOTANSI', False, False),
+ ('mydb.*:SELECT', {'"mydb".*': ['SELECT'], '*.*': ['USAGE']}, 'ANSI', False, True),
+ ('mydb.*:SELECT', {'`mydb`.*': ['SELECT'], '*.*': ['USAGE']}, 'NOTANSI', False, True),
+ ('mydb.*:SELECT (a)', {'`mydb`.*': ['SELECT (A)']}, 'NOTANSI', False, False),
+ ('mydb.*:UPDATE (b, a)', {'`mydb`.*': ['UPDATE (a, b)']}, 'NOTANSI', True, False),
+ ('mydb.*:SELECT (b, a, c)', {'`mydb`.*': ['SELECT (A, B, C)']}, 'NOTANSI', False, False),
+ ('mydb.*:SELECT (b, a, c)', {'`mydb`.*': ['SELECT (a, b, c)']}, 'NOTANSI', True, False),
+ ]
+)
+def test_privileges_unpack(priv, mode, column_case_sensitive, ensure_usage, expected):
+ """Tests privileges_unpack function."""
+ assert privileges_unpack(priv, mode, column_case_sensitive, ensure_usage) == expected
diff --git a/ansible_collections/community/mysql/tests/unit/plugins/modules/test_mysql_info.py b/ansible_collections/community/mysql/tests/unit/plugins/modules/test_mysql_info.py
index 7aa9577e5..6aaf66e2c 100644
--- a/ansible_collections/community/mysql/tests/unit/plugins/modules/test_mysql_info.py
+++ b/ansible_collections/community/mysql/tests/unit/plugins/modules/test_mysql_info.py
@@ -14,15 +14,15 @@ from ansible_collections.community.mysql.plugins.modules.mysql_info import MySQL
@pytest.mark.parametrize(
- 'suffix,cursor_output',
+ 'suffix,cursor_output,server_implementation',
[
- ('mysql', '5.5.1-mysql'),
- ('log', '5.7.31-log'),
- ('mariadb', '10.5.0-mariadb'),
- ('', '8.0.22'),
+ ('mysql', '5.5.1-mysql', 'mysql'),
+ ('log', '5.7.31-log', 'mysql'),
+ ('mariadb', '10.5.0-mariadb', 'mariadb'),
+ ('', '8.0.22', 'mysql'),
]
)
-def test_get_info_suffix(suffix, cursor_output):
+def test_get_info_suffix(suffix, cursor_output, server_implementation):
def __cursor_return_value(input_parameter):
if input_parameter == "SHOW GLOBAL VARIABLES":
cursor.fetchall.return_value = [{"Variable_name": "version", "Value": cursor_output}]
@@ -32,6 +32,6 @@ def test_get_info_suffix(suffix, cursor_output):
cursor = MagicMock()
cursor.execute.side_effect = __cursor_return_value
- info = MySQL_Info(MagicMock(), cursor)
+ info = MySQL_Info(MagicMock(), cursor, server_implementation)
assert info.get_info([], [], False)['version']['suffix'] == suffix
diff --git a/ansible_collections/community/network/.ansible-lint b/ansible_collections/community/network/.ansible-lint
new file mode 100644
index 000000000..33953eedb
--- /dev/null
+++ b/ansible_collections/community/network/.ansible-lint
@@ -0,0 +1,11 @@
+skip_list:
+ # Remove these temporary disable skips added during adopting of ansible-lint:
+ - deprecated-module
+ - fqcn
+ - ignore-errors
+ - jinja
+ - key-order
+ - name
+ - no-free-form
+ - sanity
+ - yaml
diff --git a/ansible_collections/community/network/.azure-pipelines/azure-pipelines.yml b/ansible_collections/community/network/.azure-pipelines/azure-pipelines.yml
index 80f9df94d..edff3f6c4 100644
--- a/ansible_collections/community/network/.azure-pipelines/azure-pipelines.yml
+++ b/ansible_collections/community/network/.azure-pipelines/azure-pipelines.yml
@@ -24,14 +24,8 @@ schedules:
always: true
branches:
include:
+ - stable-5
- stable-4
- - stable-3
- - cron: 0 11 * * 0
- displayName: "Weekly (old stable branches)"
- always: true
- branches:
- include:
- - stable-2
variables:
- name: checkoutPath
@@ -48,7 +42,7 @@ variables:
resources:
containers:
- container: default
- image: quay.io/ansible/azure-pipelines-test-container:3.0.0
+ image: quay.io/ansible/azure-pipelines-test-container:4.0.1
pool: Standard
@@ -70,44 +64,46 @@ stages:
- test: 5
- test: extra
- - stage: Sanity_2_14
- displayName: Sanity 2.14
+ - stage: Sanity_2_16
+ displayName: Sanity 2.16
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
nameFormat: Test {0}
- testFormat: 2.14/sanity/{0}
+ testFormat: 2.16/sanity/{0}
targets:
- test: 1
- test: 2
- test: 3
- test: 4
- test: 5
+ - test: extra
- - stage: Sanity_2_13
- displayName: Sanity 2.13
+ - stage: Sanity_2_15
+ displayName: Sanity 2.15
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
nameFormat: Test {0}
- testFormat: 2.13/sanity/{0}
+ testFormat: 2.15/sanity/{0}
targets:
- test: 1
- test: 2
- test: 3
- test: 4
- test: 5
+ - test: extra
- - stage: Sanity_2_12
- displayName: Sanity 2.12
+ - stage: Sanity_2_14
+ displayName: Sanity 2.14
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
nameFormat: Test {0}
- testFormat: 2.12/sanity/{0}
+ testFormat: 2.14/sanity/{0}
targets:
- test: 1
- test: 2
@@ -115,14 +111,14 @@ stages:
- test: 4
- test: 5
- - stage: Sanity_2_11
- displayName: Sanity 2.11
+ - stage: Sanity_2_13
+ displayName: Sanity 2.13
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
nameFormat: Test {0}
- testFormat: 2.11/sanity/{0}
+ testFormat: 2.13/sanity/{0}
targets:
- test: 1
- test: 2
@@ -142,57 +138,50 @@ stages:
targets:
- test: '3.10'
- - stage: Units_2_14
- displayName: Units 2.14
+ - stage: Units_2_16
+ displayName: Units 2.16
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
nameFormat: Python {0}
- testFormat: 2.14/units/{0}/1
+ testFormat: 2.16/units/{0}/1
targets:
- test: '3.10'
- - stage: Units_2_13
- displayName: Units 2.13
+ - stage: Units_2_15
+ displayName: Units 2.15
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
nameFormat: Python {0}
- testFormat: 2.13/units/{0}/1
+ testFormat: 2.15/units/{0}/1
targets:
- - test: 3.8
- test: '3.10'
- - stage: Units_2_12
- displayName: Units 2.12
+ - stage: Units_2_14
+ displayName: Units 2.14
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
nameFormat: Python {0}
- testFormat: 2.12/units/{0}/1
+ testFormat: 2.14/units/{0}/1
targets:
- - test: 3.8
- - test: 3.9
+ - test: '3.10'
- - stage: Units_2_11
- displayName: Units 2.11
+ - stage: Units_2_13
+ displayName: Units 2.13
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
nameFormat: Python {0}
- testFormat: 2.11/units/{0}/1
+ testFormat: 2.13/units/{0}/1
targets:
- - test: 2.6
- - test: 2.7
- - test: 3.5
- - test: 3.6
- - test: 3.7
- test: 3.8
- - test: 3.9
+ - test: '3.10'
### Cloud
- stage: Cloud_devel
@@ -208,72 +197,75 @@ stages:
- test: 3.9
- test: "3.10"
- - stage: Cloud_2_14
- displayName: Cloud 2.14
+ - stage: Cloud_2_16
+ displayName: Cloud 2.16
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
nameFormat: Python {0}
- testFormat: 2.14/cloud/{0}/1
+ testFormat: 2.16/cloud/{0}/1
targets:
- test: 3.8
- test: 3.9
- test: "3.10"
- - stage: Cloud_2_13
- displayName: Cloud 2.13
+ - stage: Cloud_2_15
+ displayName: Cloud 2.15
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
nameFormat: Python {0}
- testFormat: 2.13/cloud/{0}/1
+ testFormat: 2.15/cloud/{0}/1
targets:
+ - test: 3.8
- test: 3.9
- test: "3.10"
- - stage: Cloud_2_12
- displayName: Cloud 2.12
+ - stage: Cloud_2_14
+ displayName: Cloud 2.14
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
nameFormat: Python {0}
- testFormat: 2.12/cloud/{0}/1
+ testFormat: 2.14/cloud/{0}/1
targets:
- test: 3.8
+ - test: 3.9
- test: "3.10"
- - stage: Cloud_2_11
- displayName: Cloud 2.11
+ - stage: Cloud_2_13
+ displayName: Cloud 2.13
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
nameFormat: Python {0}
- testFormat: 2.11/cloud/{0}/1
+ testFormat: 2.13/cloud/{0}/1
targets:
- - test: 3.8
+ - test: 3.9
+ - test: "3.10"
### Finally
- stage: Summary
condition: succeededOrFailed()
dependsOn:
- Sanity_devel
+ - Sanity_2_16
+ - Sanity_2_15
- Sanity_2_14
- Sanity_2_13
- - Sanity_2_12
- - Sanity_2_11
- Units_devel
+ - Units_2_16
+ - Units_2_15
- Units_2_14
- Units_2_13
- - Units_2_12
- - Units_2_11
- Cloud_devel
+ - Cloud_2_16
+ - Cloud_2_15
- Cloud_2_14
- Cloud_2_13
- - Cloud_2_12
- - Cloud_2_11
jobs:
- template: templates/coverage.yml
diff --git a/ansible_collections/community/network/CHANGELOG.rst b/ansible_collections/community/network/CHANGELOG.rst
index e6e0c1ab6..6805773cf 100644
--- a/ansible_collections/community/network/CHANGELOG.rst
+++ b/ansible_collections/community/network/CHANGELOG.rst
@@ -6,6 +6,36 @@ Community Network Release Notes
This changelog describes changes after version 4.0.0.
+v5.0.2
+======
+
+Release Summary
+---------------
+
+This is the mock patch release of the ``community.network`` collection
+caused by Galaxy issues.
+This changelog contains changes made since release 5.0.0.
+See the changelog for version 5.0.1 for details.
+
+v5.0.1
+======
+
+Release Summary
+---------------
+
+This is a patch release of the ``community.network`` collection.
+This changelog contains all changes to the modules and plugins in this collection
+that have been made after the previous release.
+
+Bugfixes
+--------
+
+- cnos_l3_interface - fix import errors (https://github.com/ansible-collections/community.network/pull/531).
+- exos_config - missing whitespace in command with ``defaults: True``. It happened because the command is ``show configurationdetail`` instead of ``show configuration detail`` (https://github.com/ansible-collections/community.network/pull/516).
+- exos_facts - returns timeout error when we use connection type ``network_cli``. It happened because we send command without ``no-refresh`` and script ``cli2json.py`` stuck in loop while reading console output (https://github.com/ansible-collections/community.network/pull/517).
+- icx_l3_interface - fix import errors (https://github.com/ansible-collections/community.network/pull/531).
+- slxos_l3_interface - fix import errors (https://github.com/ansible-collections/community.network/pull/531).
+
v5.0.0
======
diff --git a/ansible_collections/community/network/FILES.json b/ansible_collections/community/network/FILES.json
index fa6972f1f..48d500a30 100644
--- a/ansible_collections/community/network/FILES.json
+++ b/ansible_collections/community/network/FILES.json
@@ -109,7 +109,7 @@
"name": ".azure-pipelines/azure-pipelines.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "870472211ccd5fd8ec26127a2af18c320d13f2e96421d6a2173073008a0388c0",
+ "chksum_sha256": "f2112d8c5ddaca809f1d13953864b03b713590d7cb7805f0c16f62277a009484",
"format": 1
},
{
@@ -172,7 +172,7 @@
"name": "changelogs/changelog.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5c88b6d2e48dae95270f9ae40387f63cb513767dc1373fb0a5608646d9fea075",
+ "chksum_sha256": "9e2550ba9ca90e0d106b52fc04c136140485803b62db3f9e4fb12371b26c914b",
"format": 1
},
{
@@ -515,7 +515,7 @@
"name": "plugins/doc_fragments/a10.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f8946171ce108e332ac9e1e4608987445fa6bdaa31dcfbfb0eaf9a69764093a9",
+ "chksum_sha256": "537a6419a6446712d56a748e7c1bafd7d29757f9dfe33116707bc9c7ccc25b2b",
"format": 1
},
{
@@ -557,28 +557,28 @@
"name": "plugins/doc_fragments/enos.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7b2822cdf9bcf762fe5cb38ccee8fcf9bfce64bc38aab379be3b50fda72349f7",
+ "chksum_sha256": "f5de933da113c5166ca8afc0bc4d650e799d43d77ace91dd71cc3576fd795f1d",
"format": 1
},
{
"name": "plugins/doc_fragments/ingate.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e5785790ff593d2d8054d31e4e3ee6987c3038f389dace7213c1d96b2b7571f9",
+ "chksum_sha256": "ed9297ca9b7a66f1a308d22202e374e88643fd69c136a4fd04e6b721ef65d228",
"format": 1
},
{
"name": "plugins/doc_fragments/ironware.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3daf9ac2ae7f7e876e3e23d4b6e53b7c6d4662b11d3a0100a2e8f16b8e5bd984",
+ "chksum_sha256": "159b6f9ca4cd3a6d5621bf6eb6b585179a70b67383699537f6454f8ced5a7d25",
"format": 1
},
{
"name": "plugins/doc_fragments/netscaler.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c3110f4c82e5c9435f28ebb6783bb368eb17827ad62f6f41380e11950a3b57d0",
+ "chksum_sha256": "46c9fb0676af589ea6c70a764a8efd7e2ccf2b810501c98751a03e260e6d6344",
"format": 1
},
{
@@ -662,7 +662,7 @@
"name": "plugins/lookup/avi.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c35c18bb421ae58a8a9c4cf2c125507761bc42c8c55cf025d24d652b35e6e241",
+ "chksum_sha256": "491caf174a8699ffcd63e7cc4f72dcec372e3bf8639685845507b9ae3c91652d",
"format": 1
},
{
@@ -802,7 +802,7 @@
"name": "plugins/module_utils/network/avi/ansible_utils.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7e227e54f5011c1290030f854c1173dc007faba48c8c4a23dcadf0cc5089aa72",
+ "chksum_sha256": "89c5dc93a837f472305546ac56123ff5bae5a68da749c3cdedad6903b8042dbd",
"format": 1
},
{
@@ -816,7 +816,7 @@
"name": "plugins/module_utils/network/avi/avi_api.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b92370c34fc21c648a540b3492992c711d163e2de4f6c8f7c48c6314a5e29bb3",
+ "chksum_sha256": "65b332935b957c5381504d163d59e208b79cdb7bbe15d017928a547de3134656",
"format": 1
},
{
@@ -1257,7 +1257,7 @@
"name": "plugins/module_utils/network/exos/facts/legacy/base.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f3fcd1a2a7d82bfa30737def6f7efb5e809252a29834b8e124e9971dd56f5f17",
+ "chksum_sha256": "78f42d1812f845f126fa4f4bd3d8481c3e2083e3f4309d7df9465b02d62a74ea",
"format": 1
},
{
@@ -1390,7 +1390,7 @@
"name": "plugins/module_utils/network/ftd/common.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f6922775db1aa9b22c962e5f4a7844511e28edeea7ca012c9fef56223f73be89",
+ "chksum_sha256": "7f37391936ef47f1bd9e45b98e665452c09e5363470b46bbfc1a66c7539398bf",
"format": 1
},
{
@@ -1691,7 +1691,7 @@
"name": "plugins/modules/a10_server_axapi3.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "119bdedf0feb7eb6a5444b386a1049da9964447300f427eaf10d585279a6d134",
+ "chksum_sha256": "cfb34fc25776d56db3680f57d4c7f767157df07f3da372965573ffb36db594c9",
"format": 1
},
{
@@ -1719,7 +1719,7 @@
"name": "plugins/modules/aireos_config.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c65108a6c850cb4db8d11a02ca0edac42a2289b0b7518f60e23d1e93ad3bc357",
+ "chksum_sha256": "8b514ec935383351b344c3d0e8551f3f853c0df4ad03f080b2de7fa43fbfa5ec",
"format": 1
},
{
@@ -1740,7 +1740,7 @@
"name": "plugins/modules/aruba_config.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bedd88945fa682be9179d920a4cbc32c13a6fd4911f890f4f1098b4544f47e7e",
+ "chksum_sha256": "7065a9d8798c4ca0dea6a6c67e25955f988166ef36b1f605c4b647c8d4b95738",
"format": 1
},
{
@@ -1922,7 +1922,7 @@
"name": "plugins/modules/avi_gslb.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7cc53f39ba1591b1c164baaeedc1af074467fa029f78886f917f54fe67c12020",
+ "chksum_sha256": "9df67c6baf109e3eb7850d54f0660a600e74b3bf65767028a5fbd4482d818868",
"format": 1
},
{
@@ -2223,210 +2223,210 @@
"name": "plugins/modules/ce_aaa_server.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9d8f63bac3510618cded25f2a0d0003c6585f62aea4504da210c132f20839aab",
+ "chksum_sha256": "bebe9743e6f9f0f4dd4f52b72342ecc8cfb7c22aa0d818ca373c6268b761e0ad",
"format": 1
},
{
"name": "plugins/modules/ce_aaa_server_host.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d6c922741f535555d97ca0642c9414499e6eb6cea885b393aa637bf5aab0dec6",
+ "chksum_sha256": "2c71e2275325a7acf64c6ebe574b97f158a7b839cd0d4a18fa74e6775105e8a8",
"format": 1
},
{
"name": "plugins/modules/ce_acl.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e3cdda4fb1c0ed9bb3caa6e75d9108406b547e6cd87d7bc5f6dfd2b86bb2d1dd",
+ "chksum_sha256": "a3a5d61e986542b8488916c9431ec5c64a89cc3662bb79fa8914db22b4a0155e",
"format": 1
},
{
"name": "plugins/modules/ce_acl_advance.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5e0e595c447354c08cc3ccd12d1db5b1dc6601738a8b08b698ba1a7852e3a9d3",
+ "chksum_sha256": "bcf858545d5aa2b3447a46ed1af8532223b1f4afa6b30be8488d9f89c3d04c25",
"format": 1
},
{
"name": "plugins/modules/ce_acl_interface.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4ee1d38658f237c3761551eed645b36fcedb0506b66acf4089490b5ff37f2911",
+ "chksum_sha256": "0e02464040763795bef70144a576c00346c56574289b2e43203f0f5917968414",
"format": 1
},
{
"name": "plugins/modules/ce_bfd_global.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "54af83e3b7bf346c19f9df12a86a292ee23d30b3323183940f071ffc353c9fca",
+ "chksum_sha256": "57ba688086b4f3d76b4cf038dddd66533863ab07ff478d5a5ad603fb9358edcd",
"format": 1
},
{
"name": "plugins/modules/ce_bfd_session.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "19d07505d343a6f893f66b25afece590374cd47ea9c7188a1fc32f7ad9d338c8",
+ "chksum_sha256": "6aaa3f668e4580e48928163a62d3ab009b995c118f6a472af30f39b3cf0d5d23",
"format": 1
},
{
"name": "plugins/modules/ce_bfd_view.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "166f1304f4166d575ac6ed82db28a41eb2ca2134c2f73844864f1f38bd9b5537",
+ "chksum_sha256": "5ae0e0a478057131434f3e0df705e283ba5aa2fb36cb0d4a3e47200ea22af683",
"format": 1
},
{
"name": "plugins/modules/ce_bgp.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "965efe6cbad6ab530de150d9e3ab51cc6a0cd5c777a9690452da09971672aedd",
+ "chksum_sha256": "f300c5aa4bf9aae11e156ebcb78b6e077617caf6a76279bf6dcb0e9270b37a75",
"format": 1
},
{
"name": "plugins/modules/ce_bgp_af.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4beaa2e7bf8c365e3e51936a5510bda518af893cc5f614fa4e961913bdad371b",
+ "chksum_sha256": "756055076e839d796fd93ffefcf03a0b7299e9e978c5e9b156317ee1125265f6",
"format": 1
},
{
"name": "plugins/modules/ce_bgp_neighbor.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "98eb6f2bcfc0aea0db3fe2af59370d293939f5a04dc985fb4bcd8a7697620681",
+ "chksum_sha256": "23020323023ff4002c9734e68ca12cc504a62d51fd02ba518d26050e308d0d7b",
"format": 1
},
{
"name": "plugins/modules/ce_bgp_neighbor_af.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d70d24f91490fc34a951f1532db4d04f3b4d100b0667f59d172b153013e6a123",
+ "chksum_sha256": "048fc72ed3e2d02ee23f4ce5da3ab75b7be46ab51fda87ed68faba7e83d45b8f",
"format": 1
},
{
"name": "plugins/modules/ce_command.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "078ab5716698463bdc6fe64f7fb187368995793c9e6059302346ced4b66901cd",
+ "chksum_sha256": "25002eccea52205eacf7683b701bdae152a9504297e632825f93f12add85d2c6",
"format": 1
},
{
"name": "plugins/modules/ce_config.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2c15457adcf3d2e8fa74769437478443eb35ee31f11b4f18f706faaae9eb9b68",
+ "chksum_sha256": "b0670897f1b39dd58598e5b9a08ab336f41cf640d5e2dbb63bb2a382a1617283",
"format": 1
},
{
"name": "plugins/modules/ce_dldp.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "55aecd16fddb19cd52b8aefc9bab68277a3ccd2163321784a889249fb8dc311a",
+ "chksum_sha256": "746612c3f0201e630246854df12e9c12f750a24d2d29be9e4722c8d98f921ddf",
"format": 1
},
{
"name": "plugins/modules/ce_dldp_interface.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8c490f002397270caa0c32682abf91a0865855381d13349606d9015d4ed0cca2",
+ "chksum_sha256": "db86449acc2a77205170c3ecf1f323989ab98410f14d3d193802c2f9c3d928aa",
"format": 1
},
{
"name": "plugins/modules/ce_eth_trunk.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "de46af5ca637e5b1ba0e031fa9a0aa0cc6322b0fdf6d248fa11e85a7f5393861",
+ "chksum_sha256": "12a4db1050db90f99db4d4253261a7132b552a3486718d5b8b84d158ff8fb7c2",
"format": 1
},
{
"name": "plugins/modules/ce_evpn_bd_vni.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4e7b5efef96a063a383f9cf03644d8140e6b6fe19a1dd347481cb6a44b109b57",
+ "chksum_sha256": "e20b596c9b352d9d20af380f6942b6237c8e4398c7748ee4ed4802e487da938f",
"format": 1
},
{
"name": "plugins/modules/ce_evpn_bgp.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e5944fadd87f89a362ba2bf7b7c4f1f192690ddba82a9da286069d016cd9b268",
+ "chksum_sha256": "966b7730bf3995b03b5be36db3deb4e97b8c061ef0ae99a833a1c8a2e255ee45",
"format": 1
},
{
"name": "plugins/modules/ce_evpn_bgp_rr.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0a01815c71be156bd57363a35474d253a2846af759c341d5df8b8ba98aa28c03",
+ "chksum_sha256": "91e1d8c12241421235ec645f0158c498d26136bdd3d587b8bc502072896bb8b1",
"format": 1
},
{
"name": "plugins/modules/ce_evpn_global.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e33654b068d13586ade7f2a0bbe42a55ea872d182c6412249490ec535f222c2a",
+ "chksum_sha256": "eae985d6d15786408b217c20ea81b80a942f4d0b67d8e3b77656ed8f7438ebe3",
"format": 1
},
{
"name": "plugins/modules/ce_facts.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c53727cb04c703d3e4a1937c7e7de06b119a53d75ddd02ae37f1d508401a5af1",
+ "chksum_sha256": "79d5542e50a839acf269a07bc891281641af1e86c420189c6ebd799fbde4a07f",
"format": 1
},
{
"name": "plugins/modules/ce_file_copy.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5642a88de0207053d69b34095fbd2a340aa94ba1983852850bb1c25e25b83677",
+ "chksum_sha256": "057a7d130eed705f46661f78532ad9131dd28851016258afa1ca6904fc59974d",
"format": 1
},
{
"name": "plugins/modules/ce_info_center_debug.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "66c3a95a2e3fb760bcdbbc8bb1b53562a0dced8b4b4d3f43646d313ae94f1f71",
+ "chksum_sha256": "bad0de0ac8f3e9b2bc895144e6db36effc11892eec465d45cfbb73bb402bd287",
"format": 1
},
{
"name": "plugins/modules/ce_info_center_global.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2fa8863dc8035ffc2f92f1009e79068da16328b68f728a7f1ce8737167f1ccd9",
+ "chksum_sha256": "5e151513915e23a31b73c4a5eb27446e3ec223d25f59ef8cd271c2f1459bcdd7",
"format": 1
},
{
"name": "plugins/modules/ce_info_center_log.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "213892d84c4f5896136fdc47a463a782fffe6d38f4674eba28b51839ec91fd31",
+ "chksum_sha256": "97df7d4a668c3465f02f505253065349f1185e9db8c0db9ea9f7df992d362e03",
"format": 1
},
{
"name": "plugins/modules/ce_info_center_trap.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d1321d0ae1bfa9bceff6065df965f721b4debcb886ebefb9814202aae697cda2",
+ "chksum_sha256": "e44ed575948651ad37566f744d0c6cee4ab439fd8cda342857e01cd38feb3c4f",
"format": 1
},
{
"name": "plugins/modules/ce_interface.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "de51078a7928ef8c771ea5597dff72c343b48cac426c1c0816605f14a88cd522",
+ "chksum_sha256": "fe1e49142febcc858f432e510bb0907a9f2b571d5d31a8668a472be402061546",
"format": 1
},
{
"name": "plugins/modules/ce_interface_ospf.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "048dc081fd388e8b54d4c8f434761bcfc7e239d3e3f43806089679687912f8ea",
+ "chksum_sha256": "2c583415df2fce1bde4e2ca0da065e4cfeb627613967409a2351feadf8b2b0b3",
"format": 1
},
{
"name": "plugins/modules/ce_ip_interface.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "80cb6a9dfb50bdf8a7afccc4ce86a852c827bba1df6f3cacf3f16f29aa73a1fa",
+ "chksum_sha256": "cafeae2881c095acaf5e0df8ef7d5e416c5502ac2a34a73f5391ebef98aaedee",
"format": 1
},
{
@@ -2461,7 +2461,7 @@
"name": "plugins/modules/ce_link_status.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0e0c87c00146a55edaba51eae54f5459cd781b244cba65c80b7cf5901963fa52",
+ "chksum_sha256": "e8b7b612425e3ad4f9a38060a3730fb12b94e01e37d72b72237764da78d5693a",
"format": 1
},
{
@@ -2489,21 +2489,21 @@
"name": "plugins/modules/ce_mlag_config.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "03122371995ee2e166ebccf7a69364e3d1e48c3ea7612a2a351dcfaeca3269a1",
+ "chksum_sha256": "d10e9ce8169e358e4f366e53997b7f1912bdd13bfce2a2058fce843090431f64",
"format": 1
},
{
"name": "plugins/modules/ce_mlag_interface.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4ce8641c9b04d5b19f55c6c9fd25806ea4b4b05066eb623e04a92c3fb650dce8",
+ "chksum_sha256": "1690a1c9f5073e14a2c23dd23b3bcd728429868a78c18aefd5286a838057b19c",
"format": 1
},
{
"name": "plugins/modules/ce_mtu.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e2d0944a5a3440d370b2dd839b752a1800f86e1dc639f28f69ffb2ba4f5dba55",
+ "chksum_sha256": "747a0d974bcef5c4f79873c741c721035dcf3421e39761ddfa5e6e91474acbfc",
"format": 1
},
{
@@ -2524,140 +2524,140 @@
"name": "plugins/modules/ce_netconf.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "19c9a1cfc631d5065e094ff64e5d9d90b9def9775b4b1b605d5090a090143b29",
+ "chksum_sha256": "245ae0793746a5411e4130a50b8ebf12f293533738fd4d68504f2190d9c50638",
"format": 1
},
{
"name": "plugins/modules/ce_netstream_aging.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "23d0c25213471d71cca0155d53e05a90e4611aa37879cf75ff4c485fbfbed82d",
+ "chksum_sha256": "4e8380c82c7b0a9ca7b0cdb1e67cd8da3467b2a9f4c8e8447f9ddaff8170f507",
"format": 1
},
{
"name": "plugins/modules/ce_netstream_export.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e784cbf83ac7a41d9b57a909b6c6595eae5acc5c930cb996e8225d60b8a9ba74",
+ "chksum_sha256": "1795f5eadf1890c529536ea99e1c7fc507f7527d66ec72cf204f98d9358c4e3b",
"format": 1
},
{
"name": "plugins/modules/ce_netstream_global.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "513056ad07926689041963c45713b1a7dba10a614374e1633a08b4fbe818e30a",
+ "chksum_sha256": "30858e236d21d64443440fb2934988c7ba44ef0ec4f6f7011daf0b073bf90e64",
"format": 1
},
{
"name": "plugins/modules/ce_netstream_template.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4c54cfff3f136745075ef6d0916b663b9adc64d27fb390f8e2e97cd886fbb6da",
+ "chksum_sha256": "bb28e781a88d154c7aa74244716a8edc4d7504ba5dc13805d3cbd80e837da53e",
"format": 1
},
{
"name": "plugins/modules/ce_ntp.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f00d04b44359350f7cd084d63d4d58033244ddd696bd05cfd208e14104bc70fb",
+ "chksum_sha256": "18ca3284c25013379333b2b8db78aa839ac12335895e7fd04a0d3a15c0c16495",
"format": 1
},
{
"name": "plugins/modules/ce_ntp_auth.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2b10c644e5383c55e46a741c2f40291c1768fa286a42d2d235a3c4525c21ab4c",
+ "chksum_sha256": "f55625180a2f7561548b1c05c402d5bbad391482cbcdc625537ce84e7300cd48",
"format": 1
},
{
"name": "plugins/modules/ce_ospf.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f39c50c58e864b24dc048d462b226db74f58765d02b440958af8a971d84e58f1",
+ "chksum_sha256": "a436b5aff3114f80059f4d87d336b8cf8e31fa5f26284cc83f1f7301d06ed917",
"format": 1
},
{
"name": "plugins/modules/ce_ospf_vrf.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5eba5902209463a5bfb5cfe13cb391c7ca4a1bca2b8061d995e1fa8f085ed7fd",
+ "chksum_sha256": "ba7b0b54299961536b277c8ba7761b2f2d18bf221699399defbba0fdc6aab37b",
"format": 1
},
{
"name": "plugins/modules/ce_reboot.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "55647a2e8e23cb36c658414c66f4faaa32fc42d547295e4185778c926b1d5855",
+ "chksum_sha256": "50d11531fd9f7791ba4fe4a577048f2e9daf0d5f962552add6f8bff53c94377d",
"format": 1
},
{
"name": "plugins/modules/ce_rollback.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fd85bd83ec3207f1ab638cca7197a3569b831c57dcdde9d5e9c0761157201ac7",
+ "chksum_sha256": "0b08168626145cd72b931aa0da55e18cb0a3587d176294a7b8a0742f989974a9",
"format": 1
},
{
"name": "plugins/modules/ce_sflow.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "89d58345c8273121e3b94a885b670ae1b57d57533a0eda86cded31d8a6eeb8b7",
+ "chksum_sha256": "2e569f0a6fc5975d927cef8265669434f6f80c27e152e487d8b26e22c0e90fa8",
"format": 1
},
{
"name": "plugins/modules/ce_snmp_community.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "96ce2c670a87fa6caa62c2b7c759e4ae03ff6893f3612ff2ebbc80ea7c017df9",
+ "chksum_sha256": "a846e0d8edb7930ac308f026c107717ec32e5c6527311ffc9110a5683770283e",
"format": 1
},
{
"name": "plugins/modules/ce_snmp_contact.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "17dcf7188c0787eef9a9d64337e939d5490f4a22753037d1df300361db33b191",
+ "chksum_sha256": "c62905c239d4a65b94c09e9fff362354635f4a746be18c8327624f9ae3fcfa51",
"format": 1
},
{
"name": "plugins/modules/ce_snmp_location.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ef267904934cbc6cfe14b255a93d0a28632a4df7225844ba77345dafe03e94fe",
+ "chksum_sha256": "46b5eabddb61f466b61bbce2060a3c4d07f56cca6f352a2ca3b3fc67b00fd620",
"format": 1
},
{
"name": "plugins/modules/ce_snmp_target_host.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7675516936ecdc62afcd40db1b0a0731d9adbb8ba19661abef4e377fbf1976bf",
+ "chksum_sha256": "891f6a5243f7cc55a935669f8d3520cc7eaaa5acfb238901914f1b2b798e05ea",
"format": 1
},
{
"name": "plugins/modules/ce_snmp_traps.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "138f6b7c82fe15e3d4ed6692200d5da37f37be6748803ea7ea0a0fcb1ad69d26",
+ "chksum_sha256": "ecd1fcb0e8e62c5beec95c797d81658d0f9fc50648064d57183b8806bca7edef",
"format": 1
},
{
"name": "plugins/modules/ce_snmp_user.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2f00c6a8eedb6776eb17d62c0b7cb356e89f228416796adbf0c652866b7b6ef4",
+ "chksum_sha256": "1c8d5955b842861e29ff050ead6f46afc8e91520a4844aa1a9c9443616955403",
"format": 1
},
{
"name": "plugins/modules/ce_startup.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4104ddc898aef41fd98c3dc72da796fe06fe300051c30515ed20fba842ee91f1",
+ "chksum_sha256": "7398855f44ce7d6101eb51ccd222c57fecff81e19b706cfba430c567ac00e439",
"format": 1
},
{
"name": "plugins/modules/ce_static_route.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2501ec0c331e36111761e1401913b9960579ab9146b5ffbf828d2f215eba7328",
+ "chksum_sha256": "bb68a805d169ac876b364ea4f8dca50dc7afb18b6cb2bcd39f4038d059fe5d9b",
"format": 1
},
{
@@ -2671,84 +2671,84 @@
"name": "plugins/modules/ce_stp.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9f2698cb4dfb3cd9e724231b9048e7b99da074613c6d34dc629b4bdb4b640a37",
+ "chksum_sha256": "91c8c336646feddf6cc280a63d02821f83ca15a634130a5b0611815bde8c6da2",
"format": 1
},
{
"name": "plugins/modules/ce_switchport.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1ee5d2de50328a72c7ced10edf4c857bff9ddd9c5b3ff7c58c2cb1c2cbd09afb",
+ "chksum_sha256": "093e6489286ca23a6abbb8f073f8d0d8e9d884b1469f582ec2bf55dda9d67dba",
"format": 1
},
{
"name": "plugins/modules/ce_vlan.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3a34567ab19f117f6137abc49901d6bf9433974100f5fa88a948a834a95dda26",
+ "chksum_sha256": "3dca3e42e6758cc0e8c63aeefb5de16ab7625b8e482cdf0275b0d9b47085d34e",
"format": 1
},
{
"name": "plugins/modules/ce_vrf.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bcce20cc03f360b9da4c8c9049e00a5cb322d65b56f35fa2c820f1f2cd01f8bf",
+ "chksum_sha256": "48cbeb266e88ac50d21cac1f6625c65d9277e75df3d125fb6ea88f82fc62725c",
"format": 1
},
{
"name": "plugins/modules/ce_vrf_af.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a5079a53a6186fbea31e67f72f7031cc8e87d723bc632717386fd9683df39f7d",
+ "chksum_sha256": "8baa66e9b405c040f5105514056fca5e11176bbb5e8a58812e075ce02d53fb66",
"format": 1
},
{
"name": "plugins/modules/ce_vrf_interface.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e16a17dd2d5695860c1f4c5f2f75fd2e2d02458f8c64155c29a46fedc3ba0254",
+ "chksum_sha256": "07f84d8d45b9b2f48b17f31d4b9c70834eccdcf66d5614067a4bcaf01bfa16d4",
"format": 1
},
{
"name": "plugins/modules/ce_vrrp.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b0686edb44db70be6396845d432736118e3ec923883df70e6311c5a8fb10c907",
+ "chksum_sha256": "1f84dfe136c035af9cc57a222d35fa3529e80e0570bfffccc58cfbdb8eb22f5c",
"format": 1
},
{
"name": "plugins/modules/ce_vxlan_arp.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ad6a067ffb374dd70caa5d407d5801a8d973fea9e7087f7206e4ab93d424b4af",
+ "chksum_sha256": "a3a14c956a7aa25c4d4dee6da114df77e331a4d46580888f9479e1b78cb1b981",
"format": 1
},
{
"name": "plugins/modules/ce_vxlan_gateway.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a30fdaaeafb54e08176fe3ee6721f5c8ed9c8a511e46b7ef390a444c946b617d",
+ "chksum_sha256": "03f2095fc7b73eeed918b3d6f02729e1c29f8dbe8151c23a20abe5a9da6c5710",
"format": 1
},
{
"name": "plugins/modules/ce_vxlan_global.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f508833880a069c4038eda8f50f9663fda8f22e447aa8b1f3dd241c98e899f24",
+ "chksum_sha256": "eaaa436bc67bb428dfc2d58a7630fe140b12ecf5f9c9a4120dfa9454fbe8a913",
"format": 1
},
{
"name": "plugins/modules/ce_vxlan_tunnel.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0a12ff3ea66a7043e7485b7975f3be1e6ec793db0416ff6e90b532e603fe9bd4",
+ "chksum_sha256": "d38f9e42b8d845b8d565e0b128e225ec594a858b738101cbea9b65e3fe81469c",
"format": 1
},
{
"name": "plugins/modules/ce_vxlan_vap.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "79c6bae4284df00d9c42eab90e67b7857a94dcb9559dd08642ca41c04756e6b5",
+ "chksum_sha256": "da7a2f51c5ce91249519d456f5f6c98720d5d6cc14e1b0995d504137471cf107",
"format": 1
},
{
@@ -2797,7 +2797,7 @@
"name": "plugins/modules/cnos_config.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "939decccfc864f8bd7cccb248b6b10417b653d7ba3349dd727163e1f74738373",
+ "chksum_sha256": "d61a44027be44f7f71c820b7b7cc4455a1c4a7c36da4a5abf523cde6287d9b80",
"format": 1
},
{
@@ -2825,7 +2825,7 @@
"name": "plugins/modules/cnos_interface.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ca6c4e4856da5cf4e05393f3f6ce6bfbe2b6c04dd13b027bc4a2e6cc0237b27f",
+ "chksum_sha256": "ff18e8532b248794013be907f6df5c67e4d67b93285cfed0516b84e64dea79e1",
"format": 1
},
{
@@ -2839,14 +2839,14 @@
"name": "plugins/modules/cnos_l3_interface.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5f3bed1cf7910be1b89752a0928e269b56af1a17ccfae92a7890ec52292afd55",
+ "chksum_sha256": "4cad107eae103b8e2e9095b336c9a183a34baca95d240cbac63ddadfc4064746",
"format": 1
},
{
"name": "plugins/modules/cnos_linkagg.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a621085161345655a10ba5dad04c4a51d8b49b3d39725b3a51004cdadafb7c67",
+ "chksum_sha256": "04fa561a2d28515553330cb664ab1fdce76d7d38dc1c5fc242d6709c5a3ad191",
"format": 1
},
{
@@ -2902,7 +2902,7 @@
"name": "plugins/modules/cnos_system.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b7aae992df21f2352edc812f2216f1d874aa8f394d6d94715634810cbb06666c",
+ "chksum_sha256": "90dbc562f4e9fd054f30ac7384d9937b4bced2bea2b29826e370393668aa728e",
"format": 1
},
{
@@ -2916,7 +2916,7 @@
"name": "plugins/modules/cnos_user.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1fd028122d23d08086ecff637ef44bbeb99add0c41b65a64bf35711d78be26ce",
+ "chksum_sha256": "2b15a910f0c91a4568ea4599401dfdf3d814f9714e1ed0605ef6ef512e306d67",
"format": 1
},
{
@@ -2930,21 +2930,21 @@
"name": "plugins/modules/cnos_vlan.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "eb59cfe9496c4af59980f45dce7da4e15e2ac7250aeea67625521f2b8c681475",
+ "chksum_sha256": "20c7fcbe60a4f76888151d1880376c2b133fc261e24fd112701158e06b91c470",
"format": 1
},
{
"name": "plugins/modules/cnos_vrf.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "56c7e8ffed69cce4c21b3cae10c8a6837eed8a7cfb43b8da80a26ea14a2a9e11",
+ "chksum_sha256": "4e7d17763b2e90c47e22c842af049cd56ed24417677e707e2478fe2056350341",
"format": 1
},
{
"name": "plugins/modules/cv_server_provision.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "918394f978a469d0788e8b067e0c3461e7965d716b0b7cfc64aa3529f25ca68f",
+ "chksum_sha256": "9971250987aa7ee41d30412dcfe6d911ac2ed2046754b18cdb41bc15627edb1f",
"format": 1
},
{
@@ -2958,21 +2958,21 @@
"name": "plugins/modules/dladm_iptun.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5c4ba9ca683b871ac99a50b5f1822c695acf9e641cb8773aa6517ae525f3c9b5",
+ "chksum_sha256": "28c570bf40fe504a212f1844efcc37e4514f6606e5d15e3028a72844b348d7e8",
"format": 1
},
{
"name": "plugins/modules/dladm_linkprop.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5b6c11c28e5ebc95a48961f8759759df7ae58c826499b723707d238bbcbae47b",
+ "chksum_sha256": "07399023e5681c5c7d6a66be782d8b4575e806048844a19b585ce95e6a414222",
"format": 1
},
{
"name": "plugins/modules/dladm_vlan.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f74190c6018fe56153cf51ee5fb787149c598c1cab41e527b48bf585ce222e99",
+ "chksum_sha256": "0199c407e906067c531ac20432fe72b507a69310dfeed80b0f9cb3f252725394",
"format": 1
},
{
@@ -2986,14 +2986,14 @@
"name": "plugins/modules/edgeos_command.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "132165f664de356ae40ba20140433a3f98bc8fd11ec329733ea257809c78d0a5",
+ "chksum_sha256": "dd26345eaa576390fadd142b13941d58a8c8c5cb85baf8367077d0c6e3b6cbf0",
"format": 1
},
{
"name": "plugins/modules/edgeos_config.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e0491b939eb5faa017b2bfb78b4909d8760ec39732aa5eac67803d991a9c4902",
+ "chksum_sha256": "db9ad6a7942bc6255fe50d84d3a38f1f611acd671516c0bee5a5d984a78f6c09",
"format": 1
},
{
@@ -3014,7 +3014,7 @@
"name": "plugins/modules/edgeswitch_vlan.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c30042ceac9e9d833cd59138f8760ad8735d41ab91a5b791153b13e7d56bbc6a",
+ "chksum_sha256": "d8f4dd47a7c1a2662e2f2776b24f5d7e65cfee9d2255f8511c62b4ed442b926e",
"format": 1
},
{
@@ -3028,14 +3028,14 @@
"name": "plugins/modules/enos_config.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4a247f03d9eac7419a929875ae25563592cc032d4ffdcf7c9e667a1f69262bee",
+ "chksum_sha256": "504f628a94ac42f20c3267c86a81a3d39605b15cb228148c284d84aff79f6f1e",
"format": 1
},
{
"name": "plugins/modules/enos_facts.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "540cacd247c3bf2320ad5f2b8c223e9ed8a9dab7d37695729e1c68dc03bbf032",
+ "chksum_sha256": "3cb400360116f5a6e4443b0712d2b90c01114f90bd16841c1b3db8d691683bce",
"format": 1
},
{
@@ -3056,21 +3056,21 @@
"name": "plugins/modules/exos_config.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f5371b5682689f80baeb027d3a67ed67564a019eecfc32a016d8246050044c2e",
+ "chksum_sha256": "7c4adb35bf6676ea645ccb0633b78afcddaf8a6e22308a2fc12bea76487b8fed",
"format": 1
},
{
"name": "plugins/modules/exos_facts.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "628cfd8d1d5f1a561254ef4e31396c9b06f652a01c94de179ec5b180b9845a40",
+ "chksum_sha256": "1f4dfac707af64cc4bb89a6c7d18ce2a1b66d74ee4eebd4ebd41fcb5c65e2042",
"format": 1
},
{
"name": "plugins/modules/exos_l2_interfaces.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cffece78206592dd8e169c954780ee995c15dfc4a343970f0eaba9aed0afaa0a",
+ "chksum_sha256": "dfa95eda5c343cd86cad0eb75766f4497abafec9119ce1970a4514ebc44ad841",
"format": 1
},
{
@@ -3084,14 +3084,14 @@
"name": "plugins/modules/exos_lldp_interfaces.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ee89d035c037836df98164e1b9bfa50092a1cb4deb40d3857dc61d769a444716",
+ "chksum_sha256": "9557eb88573fb611d3b073ef00b2ab1c580ec0e3ae8d3bff10e39cfbe75654c5",
"format": 1
},
{
"name": "plugins/modules/exos_vlans.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "17a8ca6560c6de2c73b06886535ab67c209206ebc80e2212649c32246e66957d",
+ "chksum_sha256": "a79d6e413f37296549ffe6342b911eac6b856f04aee8aa5004bfef0a6a814c6d",
"format": 1
},
{
@@ -3133,35 +3133,35 @@
"name": "plugins/modules/iap_start_workflow.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "113e084f424d5dce881d38c816b8806063ba71226037ad9eb8c44a193ade4ff5",
+ "chksum_sha256": "0d418e318433561926e351dc498cc35dfd3495d1aa33c080906be39414a1daf6",
"format": 1
},
{
"name": "plugins/modules/iap_token.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e4a29ec44bb23052d6db89921a7f3be6f7664c63bb0d531371dc54a480a8afa1",
+ "chksum_sha256": "e0999f4d5d31083f7d22d5762ba5f4843b22b35d81233e4944ea9eca2a3d6776",
"format": 1
},
{
"name": "plugins/modules/icx_banner.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9a8aa17cebce5da1265cdcd0f4e02d11a8cec26dd6c479106d139f06b769a43d",
+ "chksum_sha256": "cfb365295270e0f7895f8da95a7edb61c7e1a25f2b99500db568e091be726d67",
"format": 1
},
{
"name": "plugins/modules/icx_command.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a72ba5184647f3e74a380bdc2e7c64f3992471a14c29039c8488c56d85f43a9d",
+ "chksum_sha256": "81ddda4515e163ac32ef09519ad214b956574c45fd3fddf5fe7a2e76f33b464d",
"format": 1
},
{
"name": "plugins/modules/icx_config.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c065e751fa34cd39ef8a622c320f2e669bde0630a7b0ad70b70ff97aa0cd8e7f",
+ "chksum_sha256": "20949a377807fa05336bc6ffa5f7397ae510486a8663993e97ca1c2261da451b",
"format": 1
},
{
@@ -3182,35 +3182,35 @@
"name": "plugins/modules/icx_interface.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "dedb6ea8ed2c3f6cbc453428ae0f334352110189023ad7ee941c7dfaae151c96",
+ "chksum_sha256": "4a746aa14308b85a03d9f3ceee6749cb6f7b04954f21147b58269ce58db38dd1",
"format": 1
},
{
"name": "plugins/modules/icx_l3_interface.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "95e8253ed0f1016bb28bed0f4158949d151594a65298497a3856555bb949b2b9",
+ "chksum_sha256": "1c1f0d334519b971ba32c35e5cca8063ed74a16f95733d2ab5d67e5a49f3843e",
"format": 1
},
{
"name": "plugins/modules/icx_linkagg.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4f090219ad0de6780067b138b736e5c07d10ac01469b7dc8e7795bec91e73740",
+ "chksum_sha256": "be446f6d25a2355e089690df8e651243b88915981680ffbe0f0d12e65f9caf3e",
"format": 1
},
{
"name": "plugins/modules/icx_lldp.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "92aeadfcc2cb5c3e3b11c0016c088903768be2948f88f2286b691821d278ec79",
+ "chksum_sha256": "3f9b94e21ae4568ee82101327c3083b3e3ede98889f5033fdcf2150fdc1f6f10",
"format": 1
},
{
"name": "plugins/modules/icx_logging.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "17240b62176a02785763a49333347968028fdc160cf635b779026ff9572f7ed1",
+ "chksum_sha256": "3d496d2b96e7a0996f82303a915488fddfb4bde885cb802e9eef5991ea8c262a",
"format": 1
},
{
@@ -3224,28 +3224,28 @@
"name": "plugins/modules/icx_static_route.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c6943916a26d503350df2cdbf63d717d14a2ceed7ffea26711a093284026fb4d",
+ "chksum_sha256": "fde2ae7ea98eda7b8d2f532fbb1239bdddc26dc484f4771513fe25c73e56a02b",
"format": 1
},
{
"name": "plugins/modules/icx_system.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "564de567d8b29f600e49324b7bfa4b0397a3c7285a517e4e186286a5e4911867",
+ "chksum_sha256": "5d7296602455207f10ede17722e91e76cfdab838a4936e828d587c9df2bb8bd3",
"format": 1
},
{
"name": "plugins/modules/icx_user.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f314c695c884bee8543393e9cf23865462338007125719ab2993b540642717ba",
+ "chksum_sha256": "2c86d8ab13812b20268a103a42aceac9d8ae025d3331a937192b87e7a5bd3a32",
"format": 1
},
{
"name": "plugins/modules/icx_vlan.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a940627ae2a8cdddfb9e640a24c66ddfcaed7c5ca580c36769d171c2ea83b2b8",
+ "chksum_sha256": "73882a21a3432f6d1078ff28bfd0ddb4be61d4394e7c6f232e5190a1510f871e",
"format": 1
},
{
@@ -3266,14 +3266,14 @@
"name": "plugins/modules/ipadm_addr.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0d9e56f0395994e3b42fc45b9b058e5c70169c946644335924852eb440468a39",
+ "chksum_sha256": "ba741b8510e3a3f4cfda29961bcceb8affbffda177bd3a1307d37bcf0e056156",
"format": 1
},
{
"name": "plugins/modules/ipadm_addrprop.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e55af43debb057573a28c57f8fd39ce598ab38cc68d7d314620cdff68a591a43",
+ "chksum_sha256": "d175f07503b46cac5a91a9c8e2b1ed7fc1a502e80ef6a9f53f40ce39f76d5604",
"format": 1
},
{
@@ -3322,7 +3322,7 @@
"name": "plugins/modules/nclu.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c69d24176d3bf1cf92213de0ecb82aa04f5ca82bee8e650a4e368c18783a16bd",
+ "chksum_sha256": "ccfb748b6311f54ba63737eb22b8fa4f7c05d02570085841faff3ca48b0b1179",
"format": 1
},
{
@@ -3336,14 +3336,14 @@
"name": "plugins/modules/netscaler_cs_action.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ea9fb5b3f66ab85d7512ad2e0546ce81f4902ab3704951923365a383ffeb1eac",
+ "chksum_sha256": "bace85b0fc94caf02b1bb3b816d1343b1c7f5ddf27f1c4108257872db0f9bd64",
"format": 1
},
{
"name": "plugins/modules/netscaler_cs_policy.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "99d6305e73f3b2dfd5b705f22820b36693294b678edaa074ef44f2c797e31b27",
+ "chksum_sha256": "6f707d9fac3e731d751d9ac28a7a93c46a3a92c48eff313952126000558f9f74",
"format": 1
},
{
@@ -3378,14 +3378,14 @@
"name": "plugins/modules/netscaler_lb_monitor.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2283bd0f670a9881a59c25fedc0ba6976df0f6362419dce2b8cc0f87979b3084",
+ "chksum_sha256": "551abb22dfba1fadec7b0a1aee85dcdb58330e1aa849a230e1e0293859073cea",
"format": 1
},
{
"name": "plugins/modules/netscaler_lb_vserver.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fd5ef533dba2d6d80aa23c730b22d8a89549ee4cdd8dc7085e17dc082ed8380e",
+ "chksum_sha256": "14e3e6273d7e551eb461a5534cd1bfd77bc80a58e7b34e20d5ffa1cad0081221",
"format": 1
},
{
@@ -3399,21 +3399,21 @@
"name": "plugins/modules/netscaler_save_config.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "77dfecfb3fd65a4fdcf9dc34ee917bd24e960117c6d3ca96a69f897468fb6ece",
+ "chksum_sha256": "953638a641d204598b515595d7f5c4c3a64e8d3134e06959438a14f52a72db17",
"format": 1
},
{
"name": "plugins/modules/netscaler_server.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "94018bd1098c729938483a54e1659e7123640dfda3f5c0f4178299f2832b952b",
+ "chksum_sha256": "1670bb41d3dfd5364e84a033c9d988ec8f23cf72610f2c088bf1cec5586de7fe",
"format": 1
},
{
"name": "plugins/modules/netscaler_service.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "21bd6199634bd0f6e88de94eed6589ee292e34b244877e5b7d86a7e1239e3705",
+ "chksum_sha256": "6fff069a5645e76019a928c40e49f5f3561e39626e7c5e0b487952280295acec",
"format": 1
},
{
@@ -3427,7 +3427,7 @@
"name": "plugins/modules/netscaler_ssl_certkey.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2b16e17610241bf677af421f25b9326c7694a1ed4458960d4109aed5c356a982",
+ "chksum_sha256": "e383c9818608d34f697d9adb3776cd38614698ed84f19a582177e6fa2c851676",
"format": 1
},
{
@@ -3441,7 +3441,7 @@
"name": "plugins/modules/nos_config.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cbdc3ef56e2ce10e391e843aae1a1c10660e4ea26b6177eb014bf797b29bfa12",
+ "chksum_sha256": "270d95142fe7afe23c1818a598110637566f782c9d221cf9e3af75af101845e2",
"format": 1
},
{
@@ -3455,14 +3455,14 @@
"name": "plugins/modules/nuage_vspk.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "aaf49addb8a0863172f66c70c507378e85056a3c94ee1398c8e0a8f883409c8e",
+ "chksum_sha256": "86c61144bddeb36d9d0d916891b6d4a8efb73b9545d5e29a0b4126f110db2ee3",
"format": 1
},
{
"name": "plugins/modules/opx_cps.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d0884de0f1216e608b0ced3fb9235c09bee3d11060cd8f0bf7966fcd7b1d995e",
+ "chksum_sha256": "be0ce2c46241809846c77d9b4c0a4dad53be9aaddf1c8ef9ef5515b5fbafcd83",
"format": 1
},
{
@@ -3483,49 +3483,49 @@
"name": "plugins/modules/pn_access_list.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "560d3097392d6dd35f2e64bfcc5efe6a9f264a996c5f1ec2461040caffc2f027",
+ "chksum_sha256": "500a8de056bfa392df76a0f8c99033e52dc0cb1359acbda51799575fe00a2213",
"format": 1
},
{
"name": "plugins/modules/pn_access_list_ip.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7d2fb80da0557f95b26887df75d62b3bd7756399759f9a01fba8252c5fe50053",
+ "chksum_sha256": "f8008e938d253ef649aad7fc3c4e340b98819578bf663d6f35d368aa82c3b022",
"format": 1
},
{
"name": "plugins/modules/pn_admin_service.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "be72b15bd0a92cfd08d5e8ddeac0dcc2ab8cb0f71a44bea3aa94a1fc522d8980",
+ "chksum_sha256": "4769a9c97624630cabd29a7cc933d5719459eb20391a7c8164176f06061c145a",
"format": 1
},
{
"name": "plugins/modules/pn_admin_session_timeout.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bc66694fc966dd263ecdf1525cbe6a20d11b55259eaf4f79ca8fb47024183c08",
+ "chksum_sha256": "bd2a5ceca06c24312489850ea7bfd1fe737450674e77da75fe2b220930ad3252",
"format": 1
},
{
"name": "plugins/modules/pn_admin_syslog.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "07590b305dea585190e2c893d6623d32300afcc0d3d6b90609284628ad343700",
+ "chksum_sha256": "0d5ce6f3cf05eafd6b2767b8e798d62a4c46c9d4f7a0e6d39d014cad0f8922f2",
"format": 1
},
{
"name": "plugins/modules/pn_connection_stats_settings.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5cd89db3aad5e97e5ee0f94028393f076e05c1ec748f2b7dc027435cb3c734c9",
+ "chksum_sha256": "7d04a08778b53e216de7108abefe2191932b61849620896f65c08862bb54fb23",
"format": 1
},
{
"name": "plugins/modules/pn_cpu_class.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "916b3ada72d9fb160da285212f61af10cb9b64c3ab2a888aea28ab1106576603",
+ "chksum_sha256": "399b8075e51e4b9cb207331c9a00cd7f8891ae9d6532d494838428d163c8d8b1",
"format": 1
},
{
@@ -3539,21 +3539,21 @@
"name": "plugins/modules/pn_dhcp_filter.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8b19415bc22e4726e53d0c7634762216a083768b0c3845ed5138368539514885",
+ "chksum_sha256": "40cccd9e720f598c4093b81906e7d60598768e72dbf12d44657501ad22b25a46",
"format": 1
},
{
"name": "plugins/modules/pn_dscp_map.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "25677097b3f64da8b9fed2442a2e15070fd750e2efdc31142b8d033498e6367d",
+ "chksum_sha256": "c0ab25bdcb2cd27da19a687d525dba06fe1c620888f86a20b528c59ab149d75d",
"format": 1
},
{
"name": "plugins/modules/pn_dscp_map_pri_map.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bfff07c4f2f543ad0291eafd492508d601f13b0857fb77e79147a18c3b9cf0a3",
+ "chksum_sha256": "61dda579a31af7a39ccc921b25fa1fc23310d66a2969a86e73e481b9de03d629",
"format": 1
},
{
@@ -3567,7 +3567,7 @@
"name": "plugins/modules/pn_igmp_snooping.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "568ce1b98165a199ecd549a3ae6cd9e7c0584e9de2b9cdc602f90f560b7d3270",
+ "chksum_sha256": "b49273fc3eb322a13c012cc7f89678c37379e1fb3a896ce642163106163f1f4b",
"format": 1
},
{
@@ -3602,14 +3602,14 @@
"name": "plugins/modules/pn_port_config.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "37cfcec72cd067288255aca035eed825669cda9eb57e5ad1598575f6aa45b47f",
+ "chksum_sha256": "9873dd51eecc2a59b27bf6468fd52cd99d0b2c1527bb3b196630b129a6c48ccc",
"format": 1
},
{
"name": "plugins/modules/pn_port_cos_bw.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0d28dcc219876543ff6ebb33568d8990ba2bd792375e7e6d5ae616a089523e4f",
+ "chksum_sha256": "5c0fa9cf9d0ac89670af14ca5844e704d0c45688aad58711d01fa88f746ddae3",
"format": 1
},
{
@@ -3672,7 +3672,7 @@
"name": "plugins/modules/pn_stp_port.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "324b34d18f966126f9eaf05a0a63288709a419ec5748c36f24e9b8f5df06d279",
+ "chksum_sha256": "21a7f254accdbb0b4d5df29397a16980d2e99b83943dbf80de7faf085a959a0f",
"format": 1
},
{
@@ -3700,7 +3700,7 @@
"name": "plugins/modules/pn_vrouter_bgp.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "69cdf870f2e97e5b5e16d2f200b492c7ed514833e1c784157a3ab43e384305b9",
+ "chksum_sha256": "0fde50f78d3b177c77af5d62d37698a26cc9b41b175c3d1b619db84401f622e1",
"format": 1
},
{
@@ -3756,7 +3756,7 @@
"name": "plugins/modules/pn_vtep.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "58a225400cfc89b8956bd1d2193543e39e009bb1f732fe12a298b9983871067b",
+ "chksum_sha256": "4b190c1711b652f8f6d86defcf86be240eb3b3f61cee16143a21e5258908cefa",
"format": 1
},
{
@@ -3770,7 +3770,7 @@
"name": "plugins/modules/slxos_config.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7c83bbb33887f680037998c0c647bc273f5dc92a4da21cd509894e0f55a294d9",
+ "chksum_sha256": "1ce36b0ff878c7dd330445f9d4401fa80d487cc3f6294f92e01a55385502ac85",
"format": 1
},
{
@@ -3784,7 +3784,7 @@
"name": "plugins/modules/slxos_interface.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "aff441acf1abe5e758b616ec2446efb21189359c742eb35504849274c5362012",
+ "chksum_sha256": "d67e69c02f533451723e497e28b305f5f29eff0ceafee4493dc3f90aacf300ee",
"format": 1
},
{
@@ -3798,7 +3798,7 @@
"name": "plugins/modules/slxos_l3_interface.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d1c89439182f75b326a162576c5e50bfa27951ed9dfafd7389cfc3043d194daf",
+ "chksum_sha256": "f3681f451aff73be0c710643bc2306126ac8e5b05298ec046dfa7c8f80b0a4e4",
"format": 1
},
{
@@ -3819,7 +3819,7 @@
"name": "plugins/modules/slxos_vlan.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a3e6a69ead70965169aa0fc4cca419e793ea106b12a010a550562dda912a0281",
+ "chksum_sha256": "5917d1a70b5135e4e0616e2940a590819ce0859386f995488355b4d8dc942147",
"format": 1
},
{
@@ -3833,7 +3833,7 @@
"name": "plugins/modules/sros_config.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3fdff0fdc5035b8614e005892eafa2c40aaaf221e457dd17173adcfd462296f0",
+ "chksum_sha256": "3ee6b62eb6fe01ee88d7da6810bbdd9e58be08948d6e2887022fed43a188b4bf",
"format": 1
},
{
@@ -3847,7 +3847,7 @@
"name": "plugins/modules/vdirect_commit.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "199e07a4d731aa9f342528cdc208814670a1eaecb3bc0edf52e3293ba8ef5764",
+ "chksum_sha256": "1fe2539f0778d383b2e15e3b95572bdbe49d068e28490465940095d49c40e75a",
"format": 1
},
{
@@ -3875,7 +3875,7 @@
"name": "plugins/modules/voss_config.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1d63b9dd8c656e56d459785c6f272f3ee4bf4ce7e185b514de85be9ee1574e15",
+ "chksum_sha256": "be432bfd7df2c24b12750336cacdfd18676df737c2355177f1e3b0268e46cb31",
"format": 1
},
{
@@ -5359,7 +5359,7 @@
"name": "tests/integration/targets/cnos_conditional_template/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "60858c6006f7396730f831cf31340cb41e05cc9e0299dc99221f6b83c4412fcb",
+ "chksum_sha256": "33dcf33e4c88ade3d1c60730310b05bd52f351023b6cf2c9c06d2ae2fb2bd8d8",
"format": 1
},
{
@@ -6626,7 +6626,7 @@
"name": "tests/integration/targets/cnos_template/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d5a5dab05a433ecd8cf84712f12930fa7caf2d3dbd099832051a828b183530d5",
+ "chksum_sha256": "6dc88162d03f4052b28d1854e4dacff60ff8744e66c54b62952ef68a21910a5c",
"format": 1
},
{
@@ -8257,7 +8257,14 @@
"name": "tests/integration/targets/prepare_nuage_tests/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b08c2318ec3bb630e636c73c78b78064327e2a9f37739cce97c77e62068ac30f",
+ "chksum_sha256": "600b3fe7d93523342ef63fea78046963b1ef6ce4fcdc523b6ff18215159285c7",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/requirements.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "d2255786efeffa835bac71b3e57a0385152201a81563317c182355b8ffa487eb",
"format": 1
},
{
@@ -8317,13 +8324,6 @@
"format": 1
},
{
- "name": "tests/sanity/ignore-2.11.txt",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "4fa4782d1fc09b6b761aad9dab2c4597e2e4039b345807a32b2d156446c774d7",
- "format": 1
- },
- {
"name": "tests/sanity/ignore-2.12.txt",
"ftype": "file",
"chksum_type": "sha256",
@@ -8348,7 +8348,21 @@
"name": "tests/sanity/ignore-2.15.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "88d72bc555cae33347f461bd741bbf04b34c1594ec22ac18bc6b19b6b14ec0b4",
+ "chksum_sha256": "1c18bd4cb71e089a317436248584e1482a76baf50ed173c32ce45915118b575b",
+ "format": 1
+ },
+ {
+ "name": "tests/sanity/ignore-2.16.txt",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "1c18bd4cb71e089a317436248584e1482a76baf50ed173c32ce45915118b575b",
+ "format": 1
+ },
+ {
+ "name": "tests/sanity/ignore-2.17.txt",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "1c18bd4cb71e089a317436248584e1482a76baf50ed173c32ce45915118b575b",
"format": 1
},
{
@@ -8411,7 +8425,7 @@
"name": "tests/unit/mock/loader.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cfe3480f0eae6d3723ee62d01d00a0e9f58fcdc082ea1d8e4836157c56d4fa95",
+ "chksum_sha256": "aec7750aabec8f519349a0b0899efbcc4ceadb57ade3201914debe347f4b26a5",
"format": 1
},
{
@@ -9381,13 +9395,6 @@
"format": 1
},
{
- "name": "tests/unit/plugins/modules/cnos_fixtures/show_ip_interface_brief_vrf_all",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "436485fc03ef0843e5cbe8721a2376b285088dc5f3eb3136e1093bade5071399",
- "format": 1
- },
- {
"name": "tests/unit/plugins/modules/cnos_fixtures/show_ipv6_interface_brief_vrf_all",
"ftype": "file",
"chksum_type": "sha256",
@@ -9409,13 +9416,6 @@
"format": 1
},
{
- "name": "tests/unit/plugins/modules/cnos_fixtures/show_run",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "d87a3adfd4ef61722e7a5c9bf1d0ccc1c6729847530bebb193efd22a9fb11b62",
- "format": 1
- },
- {
"name": "tests/unit/plugins/modules/cnos_fixtures/show_run_interface_ethernet_1_33",
"ftype": "file",
"chksum_type": "sha256",
@@ -9430,13 +9430,6 @@
"format": 1
},
{
- "name": "tests/unit/plugins/modules/cnos_fixtures/show_running-config",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "d87a3adfd4ef61722e7a5c9bf1d0ccc1c6729847530bebb193efd22a9fb11b62",
- "format": 1
- },
- {
"name": "tests/unit/plugins/modules/cnos_fixtures/show_sys-info",
"ftype": "file",
"chksum_type": "sha256",
@@ -9689,7 +9682,7 @@
"format": 1
},
{
- "name": "tests/unit/plugins/modules/exos_fixtures/show_port_config",
+ "name": "tests/unit/plugins/modules/exos_fixtures/show_port_config_no-refresh",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "462e36bae9dba777a0cf5d4a442c2018f54ada1c40d9759f0ca35dfe780e90f6",
@@ -10599,13 +10592,6 @@
"format": 1
},
{
- "name": "tests/unit/plugins/modules/test_avi_user.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "261ea0fb10367675a0f78444335d835f0b20f8bcbf2907e12e2edffe83c4cbeb",
- "format": 1
- },
- {
"name": "tests/unit/plugins/modules/test_ce_is_is_instance.py",
"ftype": "file",
"chksum_type": "sha256",
@@ -10690,20 +10676,6 @@
"format": 1
},
{
- "name": "tests/unit/plugins/modules/test_cnos_command.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "1e5c9bae357d5622b2a15855bea691c3ae393c41592a1bd9488170815440d454",
- "format": 1
- },
- {
- "name": "tests/unit/plugins/modules/test_cnos_facts.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "db56351e78e8c0b020b87789fb4b6890055a45ccb3db3b9027f4e735f2d075c8",
- "format": 1
- },
- {
"name": "tests/unit/plugins/modules/test_cnos_l3_interface.py",
"ftype": "file",
"chksum_type": "sha256",
@@ -10725,13 +10697,6 @@
"format": 1
},
{
- "name": "tests/unit/plugins/modules/test_cnos_static_route.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "e64eb9bf4eb19b632972af81259fb52654f3097a35780ba736f732e731fa6d16",
- "format": 1
- },
- {
"name": "tests/unit/plugins/modules/test_cnos_system.py",
"ftype": "file",
"chksum_type": "sha256",
@@ -10767,13 +10732,6 @@
"format": 1
},
{
- "name": "tests/unit/plugins/modules/test_cv_server_provision.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "3898b3f0bda9ba2ebb75a2beab6a7f7d5b998f8676af1ff1dd36106f5f52c172",
- "format": 1
- },
- {
"name": "tests/unit/plugins/modules/test_dladm_vnic.py",
"ftype": "file",
"chksum_type": "sha256",
@@ -10984,13 +10942,6 @@
"format": 1
},
{
- "name": "tests/unit/plugins/modules/test_icx_static_route.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "b9b1f7236cab4d504abe0efa234e95f89897e09a1d0c2abb40b7d9f2898d2d90",
- "format": 1
- },
- {
"name": "tests/unit/plugins/modules/test_icx_system.py",
"ftype": "file",
"chksum_type": "sha256",
@@ -11638,7 +11589,14 @@
"name": "tests/unit/requirements.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "dddb957cea08ddfa3823960fd199da2d2b628b30e8f32422762c1e2f49c0f244",
+ "chksum_sha256": "eef00da8b8ca02c8a99021d24cf8c60f6fd474afaae30f6b948f42e5e8998b01",
+ "format": 1
+ },
+ {
+ "name": "tests/unit/requirements.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "d2255786efeffa835bac71b3e57a0385152201a81563317c182355b8ffa487eb",
"format": 1
},
{
@@ -11768,10 +11726,10 @@
"format": 1
},
{
- "name": "tests/requirements.yml",
+ "name": ".ansible-lint",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0910d26a3f5e6984e697e713c648c393d998205d83dbbbdda1373674b50ac084",
+ "chksum_sha256": "280a8ef74afe32e46ceb0316724a47a8239ae55dd0d49f56bbb10a1ee22e8e36",
"format": 1
},
{
@@ -11792,7 +11750,7 @@
"name": "CHANGELOG.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c7a4f121e50b29ff1c6158ac617e43185f2e78060b7c1e4752e5941ef2e5744c",
+ "chksum_sha256": "f75120a830b09fe02ee6342d7e5e2f9ce03992ddfa862bdb1538f7b08d9014a0",
"format": 1
},
{
@@ -11820,7 +11778,14 @@
"name": "README.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d0497e5484920022e81cc8de1e75cc2165e4b165aa16ade29c24910fe597b9e7",
+ "chksum_sha256": "5db1e1a06abb9ba8c8c63f78cfc20827eedb55817e3fb58dd41ee48c5373e903",
+ "format": 1
+ },
+ {
+ "name": "requirements.txt",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "7b926e4fb860f4f51801977a857f6d0d4b41bec3b4614bdd1f1f262afe3dff5e",
"format": 1
},
{
diff --git a/ansible_collections/community/network/MANIFEST.json b/ansible_collections/community/network/MANIFEST.json
index 456b504c9..82b457808 100644
--- a/ansible_collections/community/network/MANIFEST.json
+++ b/ansible_collections/community/network/MANIFEST.json
@@ -2,16 +2,16 @@
"collection_info": {
"namespace": "community",
"name": "network",
- "version": "5.0.0",
+ "version": "5.0.2",
"authors": [
"Ansible (https://github.com/ansible)"
],
"readme": "README.md",
"tags": [
"community",
- "network"
+ "networking"
],
- "description": null,
+ "description": "This repository contains the `community.network` Ansible Collection. The collection is a part of the `ansible` package and includes many network modules and plugins supported by Ansible community which are not part of more specialized community collections.\n",
"license": [],
"license_file": "COPYING",
"dependencies": {
@@ -26,7 +26,7 @@
"name": "FILES.json",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d0b93eb8ff82dcc20fb4891b04d94b93e058cca10642fc04c5b40bc8092004a2",
+ "chksum_sha256": "e1c51f77033732d00f7c6000f269e730bdde56f0ff50e22c7be1f81f3d59cfc1",
"format": 1
},
"format": 1
diff --git a/ansible_collections/community/network/README.md b/ansible_collections/community/network/README.md
index 2e103e5c7..5e94a32cf 100644
--- a/ansible_collections/community/network/README.md
+++ b/ansible_collections/community/network/README.md
@@ -31,20 +31,28 @@ If you're interested in becoming a maintainer of this collection, refer to the [
We announce important development changes and releases through Ansible's [The Bullhorn newsletter](https://github.com/ansible/community/wiki/News#the-bullhorn). If you are a contributor, be sure you are [subscribed](https://eepurl.com/gZmiEP).
-Join us on:
+Join us on Matrix in the following (and other) rooms:
-- IRC - the ``#ansible-network`` [irc.libera.chat](https://libera.chat/) channel
-- Slack - https://ansiblenetwork.slack.com
+* [#users:ansible.com](https://matrix.to/#/#users:ansible.com): general use questions and support.
+* [#network:ansible.com](https://matrix.to/#/#network:ansible.com): network-related use questions and support.
+* [#ansible-community:ansible.com](https://matrix.to/#/#community:ansible.com): community and collection development questions.
+* other Matrix rooms
+
+Note that all the rooms above have corresponding bridged IRC channels on Libera.Chat. See the [Ansible Communication Guide](https://docs.ansible.com/ansible/devel/community/communication.html) for details.
+
+Also join us on [Slack](https://ansiblenetwork.slack.com).
Contributors to this collection take part in the global [Ansible Contributor Summit](https://github.com/ansible/community/wiki/Contributor-Summit) virtually or in-person. Track [The Bullhorn newsletter](https://eepurl.com/gZmiEP) and join us.
For more information about communication, refer to the [Ansible communication guide](https://docs.ansible.com/ansible/devel/community/communication.html).
-## Tested with Ansible
+## Tested with ansible-core
-Tested with the Ansible 2.11, 2.12, and 2.13 releases, and the current development version of Ansible. Ansible-core versions before 2.11.0 are not supported. In particular, ansible-base 2.10 and Ansible 2.9 are not supported. Use community.network 3.x.y if you are using Ansible 2.9 or ansible-base 2.10.
+Tested with supported versions of ansible-core.
+Refer to the [AZP test matrix](.azure-pipelines/azure-pipelines.yml) for details.
### Supported connections
+
The community network collection supports `network_cli` and `httpapi` connections.
## Included content
diff --git a/ansible_collections/community/network/changelogs/changelog.yaml b/ansible_collections/community/network/changelogs/changelog.yaml
index 94de9fa0b..36d66e2a3 100644
--- a/ansible_collections/community/network/changelogs/changelog.yaml
+++ b/ansible_collections/community/network/changelogs/changelog.yaml
@@ -80,3 +80,39 @@ releases:
- unflatmap.yml
- validate-plugins.yml
release_date: '2022-11-04'
+ 5.0.1:
+ changes:
+ bugfixes:
+ - cnos_l3_interface - fix import errors (https://github.com/ansible-collections/community.network/pull/531).
+ - 'exos_config - missing whitespace in command with ``defaults: True``. It happened
+ because the command is ``show configurationdetail`` instead of ``show configuration
+ detail`` (https://github.com/ansible-collections/community.network/pull/516).'
+ - exos_facts - returns timeout error when we use connection type ``network_cli``.
+ It happened because we send command without ``no-refresh`` and script ``cli2json.py``
+ stuck in loop while reading console output (https://github.com/ansible-collections/community.network/pull/517).
+ - icx_l3_interface - fix import errors (https://github.com/ansible-collections/community.network/pull/531).
+ - slxos_l3_interface - fix import errors (https://github.com/ansible-collections/community.network/pull/531).
+ release_summary: 'This is a patch release of the ``community.network`` collection.
+
+ This changelog contains all changes to the modules and plugins in this collection
+
+ that have been made after the previous release.'
+ fragments:
+ - 0-fix_imports.yml
+ - 5.0.1.yml
+ - 516-whitespace-exos-config-defaults.yaml
+ - 517-add-ports-no-refresh-in-exos-facts.yaml
+ release_date: '2023-10-24'
+ 5.0.2:
+ changes:
+ release_summary: 'This is the mock patch release of the ``community.network``
+ collection
+
+ caused by Galaxy issues.
+
+ This changelog contains changes made since release 5.0.0.
+
+ See the changelog for version 5.0.1 for details.'
+ fragments:
+ - 5.0.2.yml
+ release_date: '2023-10-25'
diff --git a/ansible_collections/community/network/plugins/doc_fragments/a10.py b/ansible_collections/community/network/plugins/doc_fragments/a10.py
index d6bf5cd7f..2359e4727 100644
--- a/ansible_collections/community/network/plugins/doc_fragments/a10.py
+++ b/ansible_collections/community/network/plugins/doc_fragments/a10.py
@@ -36,13 +36,13 @@ options:
including those that may have been made manually or through other modules,
so care should be taken when specifying C(yes).
type: bool
- default: no
+ default: false
validate_certs:
description:
- If C(no), SSL certificates will not be validated.
- This should only be used on personally controlled devices using self-signed certificates.
type: bool
- default: yes
+ default: true
notes:
- Requires A10 Networks aXAPI 2.1.
'''
diff --git a/ansible_collections/community/network/plugins/doc_fragments/enos.py b/ansible_collections/community/network/plugins/doc_fragments/enos.py
index 8018933ef..bbc2c0c50 100644
--- a/ansible_collections/community/network/plugins/doc_fragments/enos.py
+++ b/ansible_collections/community/network/plugins/doc_fragments/enos.py
@@ -21,7 +21,7 @@ options:
is not specified in the task, the value of environment variable
C(ANSIBLE_NET_AUTHORIZE) will be used instead.
type: bool
- default: no
+ default: false
auth_pass:
description:
- Specifies the password to use if required to enter privileged mode
diff --git a/ansible_collections/community/network/plugins/doc_fragments/ingate.py b/ansible_collections/community/network/plugins/doc_fragments/ingate.py
index 8132d4962..def095adb 100644
--- a/ansible_collections/community/network/plugins/doc_fragments/ingate.py
+++ b/ansible_collections/community/network/plugins/doc_fragments/ingate.py
@@ -53,7 +53,7 @@ options:
description:
- Verify the unit's HTTPS certificate.
type: bool
- default: yes
+ default: true
aliases: [ verify_ssl ]
notes:
- This module requires that the Ingate Python SDK is installed on the
diff --git a/ansible_collections/community/network/plugins/doc_fragments/ironware.py b/ansible_collections/community/network/plugins/doc_fragments/ironware.py
index c41c90063..fd505835b 100644
--- a/ansible_collections/community/network/plugins/doc_fragments/ironware.py
+++ b/ansible_collections/community/network/plugins/doc_fragments/ironware.py
@@ -15,7 +15,7 @@ options:
authorize:
description:
- B(Deprecated)
- - "Starting with Ansible 2.7 we recommend using C(connection: network_cli) and C(become: yes)."
+ - "Starting with Ansible 2.7 we recommend using C(connection: network_cli) and C(become: true)."
- For more information please see the L(IronWare Platform Options guide, ../network/user_guide/platform_ironware.html).
- HORIZONTALLINE
- Instructs the module to enter privileged mode on the remote device
@@ -24,7 +24,7 @@ options:
is not specified in the task, the value of environment variable
C(ANSIBLE_NET_AUTHORIZE) will be used instead.
type: bool
- default: no
+ default: false
notes:
- For more information on using Ansible to manage network devices see the :ref:`Ansible Network Guide <network_guide>`
'''
diff --git a/ansible_collections/community/network/plugins/doc_fragments/netscaler.py b/ansible_collections/community/network/plugins/doc_fragments/netscaler.py
index 7f19053a0..70c40a54f 100644
--- a/ansible_collections/community/network/plugins/doc_fragments/netscaler.py
+++ b/ansible_collections/community/network/plugins/doc_fragments/netscaler.py
@@ -15,19 +15,19 @@ options:
- The ip address of the netscaler appliance where the nitro API calls will be made.
- "The port can be specified with the colon (:). E.g. 192.168.1.1:555."
type: str
- required: True
+ required: true
nitro_user:
description:
- The username with which to authenticate to the netscaler node.
type: str
- required: True
+ required: true
nitro_pass:
description:
- The password with which to authenticate to the netscaler node.
type: str
- required: True
+ required: true
nitro_protocol:
description:
@@ -40,7 +40,7 @@ options:
description:
- If C(no), SSL certificates will not be validated. This should only be used on personally controlled sites using self-signed certificates.
type: bool
- default: yes
+ default: true
nitro_timeout:
description:
@@ -62,7 +62,7 @@ options:
- If C(yes) the module will save the configuration on the netscaler node if it makes any changes.
- The module will not save the configuration on the netscaler node if it made no changes.
type: bool
- default: yes
+ default: true
notes:
- For more information on using Ansible to manage Citrix NetScaler Network devices see U(https://www.ansible.com/ansible-netscaler).
'''
diff --git a/ansible_collections/community/network/plugins/lookup/avi.py b/ansible_collections/community/network/plugins/lookup/avi.py
index 625c87481..a27d64542 100644
--- a/ansible_collections/community/network/plugins/lookup/avi.py
+++ b/ansible_collections/community/network/plugins/lookup/avi.py
@@ -18,7 +18,7 @@ options:
obj_type:
description:
- type of object to query
- required: True
+ required: true
obj_name:
description:
- name of the object to query
diff --git a/ansible_collections/community/network/plugins/module_utils/network/avi/ansible_utils.py b/ansible_collections/community/network/plugins/module_utils/network/avi/ansible_utils.py
index 93de79436..e80ec908d 100644
--- a/ansible_collections/community/network/plugins/module_utils/network/avi/ansible_utils.py
+++ b/ansible_collections/community/network/plugins/module_utils/network/avi/ansible_utils.py
@@ -134,11 +134,11 @@ def cleanup_absent_fields(obj):
:param obj:
:return: Purged object
"""
- if type(obj) != dict:
+ if type(obj) is not dict:
return obj
cleanup_keys = []
for k, v in obj.items():
- if type(v) == dict:
+ if type(v) is dict:
if (('state' in v and v['state'] == 'absent') or
(v == "{'state': 'absent'}")):
cleanup_keys.append(k)
@@ -146,7 +146,7 @@ def cleanup_absent_fields(obj):
cleanup_absent_fields(v)
if not v:
cleanup_keys.append(k)
- elif type(v) == list:
+ elif type(v) is list:
new_list = []
for elem in v:
elem = cleanup_absent_fields(elem)
@@ -265,7 +265,7 @@ def avi_obj_cmp(x, y, sensitive_fields=None):
if type(x) not in [list, dict]:
# if it is not list or dict or string then simply compare the values
return x == y
- if type(x) == list:
+ if type(x) is list:
# should compare each item in the list and that should match
if len(x) != len(y):
log.debug('x has %d items y has %d', len(x), len(y))
@@ -275,7 +275,7 @@ def avi_obj_cmp(x, y, sensitive_fields=None):
# no need to continue
return False
- if type(x) == dict:
+ if type(x) is dict:
x.pop('_last_modified', None)
x.pop('tenant', None)
y.pop('_last_modified', None)
@@ -295,7 +295,7 @@ def avi_obj_cmp(x, y, sensitive_fields=None):
continue
if isinstance(v, dict):
if ('state' in v) and (v['state'] == 'absent'):
- if type(y) == dict and k not in y:
+ if type(y) is dict and k not in y:
d_x_absent_ks.append(k)
else:
return False
diff --git a/ansible_collections/community/network/plugins/module_utils/network/avi/avi_api.py b/ansible_collections/community/network/plugins/module_utils/network/avi/avi_api.py
index 684b2dd15..90e5f7814 100644
--- a/ansible_collections/community/network/plugins/module_utils/network/avi/avi_api.py
+++ b/ansible_collections/community/network/plugins/module_utils/network/avi/avi_api.py
@@ -48,7 +48,7 @@ def avi_timedelta(td):
does not have total_seconds method
:param timedelta object
'''
- if type(td) != timedelta:
+ if type(td) is not timedelta:
raise TypeError()
if sys.version_info >= (2, 7):
ts = td.total_seconds()
@@ -146,7 +146,7 @@ class ApiResponse(Response):
@staticmethod
def to_avi_response(resp):
- if type(resp) == Response:
+ if type(resp) is Response:
return ApiResponse(resp)
return resp
@@ -601,7 +601,7 @@ class ApiSession(Session):
except KeyError:
pass
try:
- if (data is not None) and (type(data) == dict):
+ if (data is not None) and (type(data) is dict):
resp = fn(fullpath, data=json.dumps(data), headers=api_hdrs,
timeout=timeout, cookies=cookies, **kwargs)
else:
diff --git a/ansible_collections/community/network/plugins/module_utils/network/exos/facts/legacy/base.py b/ansible_collections/community/network/plugins/module_utils/network/exos/facts/legacy/base.py
index 5c0bf20b6..690b8a873 100644
--- a/ansible_collections/community/network/plugins/module_utils/network/exos/facts/legacy/base.py
+++ b/ansible_collections/community/network/plugins/module_utils/network/exos/facts/legacy/base.py
@@ -130,7 +130,7 @@ class Interfaces(FactsBase):
COMMANDS = [
'show switch',
- {'command': 'show port config', 'output': 'json'},
+ {'command': 'show port config no-refresh', 'output': 'json'},
{'command': 'show port description', 'output': 'json'},
{'command': 'show vlan detail', 'output': 'json'},
{'command': 'show lldp neighbors', 'output': 'json'}
diff --git a/ansible_collections/community/network/plugins/module_utils/network/ftd/common.py b/ansible_collections/community/network/plugins/module_utils/network/ftd/common.py
index 445797037..7140c49c2 100644
--- a/ansible_collections/community/network/plugins/module_utils/network/ftd/common.py
+++ b/ansible_collections/community/network/plugins/module_utils/network/ftd/common.py
@@ -169,7 +169,7 @@ def equal_values(v1, v2):
if is_string(v1) and is_string(v2):
return to_text(v1) == to_text(v2)
- if type(v1) != type(v2):
+ if type(v1) is not type(v2):
return False
value_type = type(v1)
@@ -214,7 +214,7 @@ def delete_ref_duplicates(d):
"""
def delete_ref_duplicates_from_list(refs):
- if all(type(i) == dict and is_object_ref(i) for i in refs):
+ if all(type(i) is dict and is_object_ref(i) for i in refs):
unique_refs = set()
unique_list = list()
for i in refs:
@@ -233,9 +233,9 @@ def delete_ref_duplicates(d):
modified_d = {}
for k, v in iteritems(d):
- if type(v) == list:
+ if type(v) is list:
modified_d[k] = delete_ref_duplicates_from_list(v)
- elif type(v) == dict:
+ elif type(v) is dict:
modified_d[k] = delete_ref_duplicates(v)
else:
modified_d[k] = v
diff --git a/ansible_collections/community/network/plugins/modules/a10_server_axapi3.py b/ansible_collections/community/network/plugins/modules/a10_server_axapi3.py
index 6c02f5de4..6861dd84e 100644
--- a/ansible_collections/community/network/plugins/modules/a10_server_axapi3.py
+++ b/ansible_collections/community/network/plugins/modules/a10_server_axapi3.py
@@ -73,7 +73,7 @@ EXAMPLES = '''
server_ip: 1.1.1.100
validate_certs: false
server_status: enable
- write_config: yes
+ write_config: true
operation: create
server_ports:
- port-number: 8080
diff --git a/ansible_collections/community/network/plugins/modules/aireos_config.py b/ansible_collections/community/network/plugins/modules/aireos_config.py
index 06fecec9a..23f2e017c 100644
--- a/ansible_collections/community/network/plugins/modules/aireos_config.py
+++ b/ansible_collections/community/network/plugins/modules/aireos_config.py
@@ -170,7 +170,7 @@ EXAMPLES = """
- name: Configurable backup path
community.network.aireos_config:
- backup: yes
+ backup: true
lines: sysname testDevice
backup_options:
filename: backup.cfg
diff --git a/ansible_collections/community/network/plugins/modules/aruba_config.py b/ansible_collections/community/network/plugins/modules/aruba_config.py
index b21098b22..a396d1bbf 100644
--- a/ansible_collections/community/network/plugins/modules/aruba_config.py
+++ b/ansible_collections/community/network/plugins/modules/aruba_config.py
@@ -198,7 +198,7 @@ EXAMPLES = """
- name: Configurable backup path
community.network.aruba_config:
- backup: yes
+ backup: true
lines: hostname {{ inventory_hostname }}
backup_options:
filename: backup.cfg
diff --git a/ansible_collections/community/network/plugins/modules/avi_gslb.py b/ansible_collections/community/network/plugins/modules/avi_gslb.py
index ac6de5a1d..f27c7a7fb 100644
--- a/ansible_collections/community/network/plugins/modules/avi_gslb.py
+++ b/ansible_collections/community/network/plugins/modules/avi_gslb.py
@@ -140,7 +140,7 @@ EXAMPLES = """
ip_addresses:
- type: "V4"
addr: "10.10.28.83"
- enabled: True
+ enabled: true
member_type: "GSLB_ACTIVE_MEMBER"
port: 443
cluster_uuid: "cluster-d4ee5fcc-3e0a-4d4f-9ae6-4182bc605829"
@@ -150,7 +150,7 @@ EXAMPLES = """
ip_addresses:
- type: "V4"
addr: "10.10.28.86"
- enabled: True
+ enabled: true
member_type: "GSLB_ACTIVE_MEMBER"
port: 443
cluster_uuid: "cluster-0c37ae8d-ab62-410c-ad3e-06fa831950b1"
diff --git a/ansible_collections/community/network/plugins/modules/ce_aaa_server.py b/ansible_collections/community/network/plugins/modules/ce_aaa_server.py
index 31cbb2a49..ae9cf750c 100644
--- a/ansible_collections/community/network/plugins/modules/ce_aaa_server.py
+++ b/ansible_collections/community/network/plugins/modules/ce_aaa_server.py
@@ -98,7 +98,7 @@ EXAMPLES = r'''
- name: AAA server test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_aaa_server_host.py b/ansible_collections/community/network/plugins/modules/ce_aaa_server_host.py
index 71f3f8de3..c97594a64 100644
--- a/ansible_collections/community/network/plugins/modules/ce_aaa_server_host.py
+++ b/ansible_collections/community/network/plugins/modules/ce_aaa_server_host.py
@@ -131,7 +131,7 @@ EXAMPLES = '''
- name: AAA server host test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
tasks:
diff --git a/ansible_collections/community/network/plugins/modules/ce_acl.py b/ansible_collections/community/network/plugins/modules/ce_acl.py
index 675613724..44e2a8897 100644
--- a/ansible_collections/community/network/plugins/modules/ce_acl.py
+++ b/ansible_collections/community/network/plugins/modules/ce_acl.py
@@ -108,7 +108,7 @@ EXAMPLES = '''
- name: CloudEngine acl test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
tasks:
diff --git a/ansible_collections/community/network/plugins/modules/ce_acl_advance.py b/ansible_collections/community/network/plugins/modules/ce_acl_advance.py
index ce3e420e3..4013e6373 100644
--- a/ansible_collections/community/network/plugins/modules/ce_acl_advance.py
+++ b/ansible_collections/community/network/plugins/modules/ce_acl_advance.py
@@ -209,7 +209,7 @@ EXAMPLES = '''
- name: CloudEngine advance acl test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_acl_interface.py b/ansible_collections/community/network/plugins/modules/ce_acl_interface.py
index 89f549e08..c5c07fc6b 100644
--- a/ansible_collections/community/network/plugins/modules/ce_acl_interface.py
+++ b/ansible_collections/community/network/plugins/modules/ce_acl_interface.py
@@ -61,7 +61,7 @@ EXAMPLES = '''
- name: CloudEngine acl interface test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_bfd_global.py b/ansible_collections/community/network/plugins/modules/ce_bfd_global.py
index 7e3b2695e..70bae4d8f 100644
--- a/ansible_collections/community/network/plugins/modules/ce_bfd_global.py
+++ b/ansible_collections/community/network/plugins/modules/ce_bfd_global.py
@@ -80,7 +80,7 @@ EXAMPLES = '''
- name: Bfd global module test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_bfd_session.py b/ansible_collections/community/network/plugins/modules/ce_bfd_session.py
index 7a42e30cf..94d22039a 100644
--- a/ansible_collections/community/network/plugins/modules/ce_bfd_session.py
+++ b/ansible_collections/community/network/plugins/modules/ce_bfd_session.py
@@ -87,7 +87,7 @@ EXAMPLES = '''
- name: Bfd session module test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
tasks:
- name: Configuring Single-hop BFD for Detecting Faults on a Layer 2 Link
diff --git a/ansible_collections/community/network/plugins/modules/ce_bfd_view.py b/ansible_collections/community/network/plugins/modules/ce_bfd_view.py
index e40e3d11a..de385b3ff 100644
--- a/ansible_collections/community/network/plugins/modules/ce_bfd_view.py
+++ b/ansible_collections/community/network/plugins/modules/ce_bfd_view.py
@@ -91,7 +91,7 @@ EXAMPLES = '''
- name: Bfd view module test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
tasks:
- name: Set the local discriminator of a BFD session to 80 and the remote discriminator to 800
diff --git a/ansible_collections/community/network/plugins/modules/ce_bgp.py b/ansible_collections/community/network/plugins/modules/ce_bgp.py
index 0ff7c57d7..8d7f5580b 100644
--- a/ansible_collections/community/network/plugins/modules/ce_bgp.py
+++ b/ansible_collections/community/network/plugins/modules/ce_bgp.py
@@ -153,7 +153,7 @@ EXAMPLES = '''
- name: CloudEngine BGP test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_bgp_af.py b/ansible_collections/community/network/plugins/modules/ce_bgp_af.py
index 2aa2d3b16..375a114c9 100644
--- a/ansible_collections/community/network/plugins/modules/ce_bgp_af.py
+++ b/ansible_collections/community/network/plugins/modules/ce_bgp_af.py
@@ -332,7 +332,7 @@ EXAMPLES = '''
- name: CloudEngine BGP address family test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
tasks:
- name: "Config BGP Address_Family"
community.network.ce_bgp_af:
diff --git a/ansible_collections/community/network/plugins/modules/ce_bgp_neighbor.py b/ansible_collections/community/network/plugins/modules/ce_bgp_neighbor.py
index b4a940f74..b3f6b09de 100644
--- a/ansible_collections/community/network/plugins/modules/ce_bgp_neighbor.py
+++ b/ansible_collections/community/network/plugins/modules/ce_bgp_neighbor.py
@@ -193,7 +193,7 @@ EXAMPLES = '''
- name: CloudEngine BGP neighbor test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_bgp_neighbor_af.py b/ansible_collections/community/network/plugins/modules/ce_bgp_neighbor_af.py
index 93bee2a89..0880e7f83 100644
--- a/ansible_collections/community/network/plugins/modules/ce_bgp_neighbor_af.py
+++ b/ansible_collections/community/network/plugins/modules/ce_bgp_neighbor_af.py
@@ -322,7 +322,7 @@ EXAMPLES = '''
- name: CloudEngine BGP neighbor address family test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_command.py b/ansible_collections/community/network/plugins/modules/ce_command.py
index b2c085b32..7b81a1081 100644
--- a/ansible_collections/community/network/plugins/modules/ce_command.py
+++ b/ansible_collections/community/network/plugins/modules/ce_command.py
@@ -82,7 +82,7 @@ EXAMPLES = """
- name: CloudEngine command test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_config.py b/ansible_collections/community/network/plugins/modules/ce_config.py
index c0f05c57a..701961b81 100644
--- a/ansible_collections/community/network/plugins/modules/ce_config.py
+++ b/ansible_collections/community/network/plugins/modules/ce_config.py
@@ -153,13 +153,13 @@ EXAMPLES = """
- name: CloudEngine config test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
tasks:
- name: "Configure top level configuration and save it"
community.network.ce_config:
lines: sysname {{ inventory_hostname }}
- save: yes
+ save: true
- name: "Configure acl configuration and save it"
community.network.ce_config:
@@ -187,7 +187,7 @@ EXAMPLES = """
- name: Configurable backup path
community.network.ce_config:
lines: sysname {{ inventory_hostname }}
- backup: yes
+ backup: true
backup_options:
filename: backup.cfg
dir_path: /home/user
diff --git a/ansible_collections/community/network/plugins/modules/ce_dldp.py b/ansible_collections/community/network/plugins/modules/ce_dldp.py
index f292e0b71..a99e5517b 100644
--- a/ansible_collections/community/network/plugins/modules/ce_dldp.py
+++ b/ansible_collections/community/network/plugins/modules/ce_dldp.py
@@ -72,7 +72,7 @@ EXAMPLES = '''
- name: DLDP test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_dldp_interface.py b/ansible_collections/community/network/plugins/modules/ce_dldp_interface.py
index 276c24b11..6e1292af2 100644
--- a/ansible_collections/community/network/plugins/modules/ce_dldp_interface.py
+++ b/ansible_collections/community/network/plugins/modules/ce_dldp_interface.py
@@ -67,7 +67,7 @@ EXAMPLES = '''
- name: DLDP interface test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_eth_trunk.py b/ansible_collections/community/network/plugins/modules/ce_eth_trunk.py
index c658f93f5..d03bb64c1 100644
--- a/ansible_collections/community/network/plugins/modules/ce_eth_trunk.py
+++ b/ansible_collections/community/network/plugins/modules/ce_eth_trunk.py
@@ -79,7 +79,7 @@ EXAMPLES = '''
- name: Eth_trunk module test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_evpn_bd_vni.py b/ansible_collections/community/network/plugins/modules/ce_evpn_bd_vni.py
index 1fcc8ae65..b50946c77 100644
--- a/ansible_collections/community/network/plugins/modules/ce_evpn_bd_vni.py
+++ b/ansible_collections/community/network/plugins/modules/ce_evpn_bd_vni.py
@@ -93,7 +93,7 @@ EXAMPLES = '''
- name: EVPN BD VNI test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_evpn_bgp.py b/ansible_collections/community/network/plugins/modules/ce_evpn_bgp.py
index 5141a415b..33d4771b1 100644
--- a/ansible_collections/community/network/plugins/modules/ce_evpn_bgp.py
+++ b/ansible_collections/community/network/plugins/modules/ce_evpn_bgp.py
@@ -34,7 +34,7 @@ options:
bgp_instance:
description:
- Name of a BGP instance. The value is a string of 1 to 31 case-sensitive characters, spaces not supported.
- required: True
+ required: true
as_number:
description:
- Specifies integral AS number. The value is an integer ranging from 1 to 4294967295.
@@ -72,7 +72,7 @@ EXAMPLES = '''
- name: Evpn bgp module test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_evpn_bgp_rr.py b/ansible_collections/community/network/plugins/modules/ce_evpn_bgp_rr.py
index a8b5a5b71..a552ce96f 100644
--- a/ansible_collections/community/network/plugins/modules/ce_evpn_bgp_rr.py
+++ b/ansible_collections/community/network/plugins/modules/ce_evpn_bgp_rr.py
@@ -67,7 +67,7 @@ EXAMPLES = '''
- name: BGP RR test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_evpn_global.py b/ansible_collections/community/network/plugins/modules/ce_evpn_global.py
index c60adb13b..be74db7bd 100644
--- a/ansible_collections/community/network/plugins/modules/ce_evpn_global.py
+++ b/ansible_collections/community/network/plugins/modules/ce_evpn_global.py
@@ -42,7 +42,7 @@ EXAMPLES = '''
- name: Evpn global module test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_facts.py b/ansible_collections/community/network/plugins/modules/ce_facts.py
index 6d9c0bab4..079374471 100644
--- a/ansible_collections/community/network/plugins/modules/ce_facts.py
+++ b/ansible_collections/community/network/plugins/modules/ce_facts.py
@@ -54,7 +54,7 @@ EXAMPLES = """
- name: CloudEngine facts test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_file_copy.py b/ansible_collections/community/network/plugins/modules/ce_file_copy.py
index 8007960b6..29baad850 100644
--- a/ansible_collections/community/network/plugins/modules/ce_file_copy.py
+++ b/ansible_collections/community/network/plugins/modules/ce_file_copy.py
@@ -52,7 +52,7 @@ EXAMPLES = '''
- name: File copy test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_info_center_debug.py b/ansible_collections/community/network/plugins/modules/ce_info_center_debug.py
index bdd8ee1ab..20a3bc1cd 100644
--- a/ansible_collections/community/network/plugins/modules/ce_info_center_debug.py
+++ b/ansible_collections/community/network/plugins/modules/ce_info_center_debug.py
@@ -69,7 +69,7 @@ EXAMPLES = '''
- name: CloudEngine info center debug test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_info_center_global.py b/ansible_collections/community/network/plugins/modules/ce_info_center_global.py
index 64fad1570..06cebd691 100644
--- a/ansible_collections/community/network/plugins/modules/ce_info_center_global.py
+++ b/ansible_collections/community/network/plugins/modules/ce_info_center_global.py
@@ -131,7 +131,7 @@ EXAMPLES = '''
- name: Info center global module test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_info_center_log.py b/ansible_collections/community/network/plugins/modules/ce_info_center_log.py
index 9bbdf2c98..648925816 100644
--- a/ansible_collections/community/network/plugins/modules/ce_info_center_log.py
+++ b/ansible_collections/community/network/plugins/modules/ce_info_center_log.py
@@ -78,7 +78,7 @@ EXAMPLES = '''
- name: CloudEngine info center log test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_info_center_trap.py b/ansible_collections/community/network/plugins/modules/ce_info_center_trap.py
index 165ef23b6..80f8d17f7 100644
--- a/ansible_collections/community/network/plugins/modules/ce_info_center_trap.py
+++ b/ansible_collections/community/network/plugins/modules/ce_info_center_trap.py
@@ -78,7 +78,7 @@ EXAMPLES = '''
- name: CloudEngine info center trap test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_interface.py b/ansible_collections/community/network/plugins/modules/ce_interface.py
index 95bab788f..98ed4df18 100644
--- a/ansible_collections/community/network/plugins/modules/ce_interface.py
+++ b/ansible_collections/community/network/plugins/modules/ce_interface.py
@@ -73,7 +73,7 @@ EXAMPLES = '''
- name: Interface module test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_interface_ospf.py b/ansible_collections/community/network/plugins/modules/ce_interface_ospf.py
index 2c7248176..3c666dd9a 100644
--- a/ansible_collections/community/network/plugins/modules/ce_interface_ospf.py
+++ b/ansible_collections/community/network/plugins/modules/ce_interface_ospf.py
@@ -93,7 +93,7 @@ EXAMPLES = '''
- name: Eth_trunk module test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_ip_interface.py b/ansible_collections/community/network/plugins/modules/ce_ip_interface.py
index 149a427da..633f3cb0e 100644
--- a/ansible_collections/community/network/plugins/modules/ce_ip_interface.py
+++ b/ansible_collections/community/network/plugins/modules/ce_ip_interface.py
@@ -70,7 +70,7 @@ EXAMPLES = '''
- name: Ip_interface module test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_link_status.py b/ansible_collections/community/network/plugins/modules/ce_link_status.py
index 0e3c467bf..b40203755 100644
--- a/ansible_collections/community/network/plugins/modules/ce_link_status.py
+++ b/ansible_collections/community/network/plugins/modules/ce_link_status.py
@@ -68,7 +68,7 @@ EXAMPLES = '''
- name: Link status test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_mlag_config.py b/ansible_collections/community/network/plugins/modules/ce_mlag_config.py
index b31411884..dffc0d7d2 100644
--- a/ansible_collections/community/network/plugins/modules/ce_mlag_config.py
+++ b/ansible_collections/community/network/plugins/modules/ce_mlag_config.py
@@ -74,7 +74,7 @@ EXAMPLES = '''
- name: Mlag config module test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_mlag_interface.py b/ansible_collections/community/network/plugins/modules/ce_mlag_interface.py
index 2c4e4d819..952315d79 100644
--- a/ansible_collections/community/network/plugins/modules/ce_mlag_interface.py
+++ b/ansible_collections/community/network/plugins/modules/ce_mlag_interface.py
@@ -70,7 +70,7 @@ EXAMPLES = '''
- name: Mlag interface module test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_mtu.py b/ansible_collections/community/network/plugins/modules/ce_mtu.py
index db902480d..ad7a15c28 100644
--- a/ansible_collections/community/network/plugins/modules/ce_mtu.py
+++ b/ansible_collections/community/network/plugins/modules/ce_mtu.py
@@ -59,7 +59,7 @@ EXAMPLES = '''
- name: Mtu test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_netconf.py b/ansible_collections/community/network/plugins/modules/ce_netconf.py
index c55caa879..e7bc0dadd 100644
--- a/ansible_collections/community/network/plugins/modules/ce_netconf.py
+++ b/ansible_collections/community/network/plugins/modules/ce_netconf.py
@@ -48,7 +48,7 @@ EXAMPLES = '''
- name: CloudEngine netconf test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
tasks:
diff --git a/ansible_collections/community/network/plugins/modules/ce_netstream_aging.py b/ansible_collections/community/network/plugins/modules/ce_netstream_aging.py
index 8f4c046a4..8999b6c8e 100644
--- a/ansible_collections/community/network/plugins/modules/ce_netstream_aging.py
+++ b/ansible_collections/community/network/plugins/modules/ce_netstream_aging.py
@@ -57,7 +57,7 @@ EXAMPLES = '''
- name: Netstream aging module test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_netstream_export.py b/ansible_collections/community/network/plugins/modules/ce_netstream_export.py
index ac6e02875..4a1b1fa37 100644
--- a/ansible_collections/community/network/plugins/modules/ce_netstream_export.py
+++ b/ansible_collections/community/network/plugins/modules/ce_netstream_export.py
@@ -74,7 +74,7 @@ EXAMPLES = '''
- name: Netstream export module test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_netstream_global.py b/ansible_collections/community/network/plugins/modules/ce_netstream_global.py
index acc60c4f3..ed6d35482 100644
--- a/ansible_collections/community/network/plugins/modules/ce_netstream_global.py
+++ b/ansible_collections/community/network/plugins/modules/ce_netstream_global.py
@@ -68,7 +68,7 @@ EXAMPLES = '''
- name: Netstream global module test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
tasks:
diff --git a/ansible_collections/community/network/plugins/modules/ce_netstream_template.py b/ansible_collections/community/network/plugins/modules/ce_netstream_template.py
index 38d9fede2..710d08236 100644
--- a/ansible_collections/community/network/plugins/modules/ce_netstream_template.py
+++ b/ansible_collections/community/network/plugins/modules/ce_netstream_template.py
@@ -67,7 +67,7 @@ EXAMPLES = '''
- name: Netstream template module test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_ntp.py b/ansible_collections/community/network/plugins/modules/ce_ntp.py
index 3c85f93b3..5996e9718 100644
--- a/ansible_collections/community/network/plugins/modules/ce_ntp.py
+++ b/ansible_collections/community/network/plugins/modules/ce_ntp.py
@@ -67,7 +67,7 @@ EXAMPLES = '''
- name: NTP test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
tasks:
diff --git a/ansible_collections/community/network/plugins/modules/ce_ntp_auth.py b/ansible_collections/community/network/plugins/modules/ce_ntp_auth.py
index 4dc7abbc6..304023a35 100644
--- a/ansible_collections/community/network/plugins/modules/ce_ntp_auth.py
+++ b/ansible_collections/community/network/plugins/modules/ce_ntp_auth.py
@@ -75,7 +75,7 @@ EXAMPLES = '''
- name: NTP AUTH test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
tasks:
diff --git a/ansible_collections/community/network/plugins/modules/ce_ospf.py b/ansible_collections/community/network/plugins/modules/ce_ospf.py
index a546e032b..0733eaf4d 100644
--- a/ansible_collections/community/network/plugins/modules/ce_ospf.py
+++ b/ansible_collections/community/network/plugins/modules/ce_ospf.py
@@ -89,7 +89,7 @@ EXAMPLES = '''
- name: Ospf module test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
tasks:
diff --git a/ansible_collections/community/network/plugins/modules/ce_ospf_vrf.py b/ansible_collections/community/network/plugins/modules/ce_ospf_vrf.py
index 6f207f10e..e810099f3 100644
--- a/ansible_collections/community/network/plugins/modules/ce_ospf_vrf.py
+++ b/ansible_collections/community/network/plugins/modules/ce_ospf_vrf.py
@@ -141,7 +141,7 @@ EXAMPLES = '''
- name: Ospf vrf module test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
tasks:
@@ -149,7 +149,7 @@ EXAMPLES = '''
community.network.ce_ospf_vrf:
ospf: 2
route_id: 2.2.2.2
- lsaointervalflag: False
+ lsaointervalflag: false
lsaointerval: 2
'''
@@ -244,7 +244,7 @@ changed:
description: check to see if a change was made on the device
returned: always
type: bool
- sample: False
+ sample: false
'''
from xml.etree import ElementTree
diff --git a/ansible_collections/community/network/plugins/modules/ce_reboot.py b/ansible_collections/community/network/plugins/modules/ce_reboot.py
index 0213a072a..7d13d943b 100644
--- a/ansible_collections/community/network/plugins/modules/ce_reboot.py
+++ b/ansible_collections/community/network/plugins/modules/ce_reboot.py
@@ -49,7 +49,7 @@ EXAMPLES = '''
- name: Reboot module test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_rollback.py b/ansible_collections/community/network/plugins/modules/ce_rollback.py
index d3a63cff0..90bcd7805 100644
--- a/ansible_collections/community/network/plugins/modules/ce_rollback.py
+++ b/ansible_collections/community/network/plugins/modules/ce_rollback.py
@@ -64,7 +64,7 @@ EXAMPLES = '''
- name: Rollback module test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_sflow.py b/ansible_collections/community/network/plugins/modules/ce_sflow.py
index 55c1550fa..33f3b5348 100644
--- a/ansible_collections/community/network/plugins/modules/ce_sflow.py
+++ b/ansible_collections/community/network/plugins/modules/ce_sflow.py
@@ -120,7 +120,7 @@ EXAMPLES = '''
- name: Sflow module test
hosts: ce128
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_snmp_community.py b/ansible_collections/community/network/plugins/modules/ce_snmp_community.py
index 08704ba90..fe18f6f4d 100644
--- a/ansible_collections/community/network/plugins/modules/ce_snmp_community.py
+++ b/ansible_collections/community/network/plugins/modules/ce_snmp_community.py
@@ -73,7 +73,7 @@ EXAMPLES = '''
- name: CloudEngine snmp community test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_snmp_contact.py b/ansible_collections/community/network/plugins/modules/ce_snmp_contact.py
index 873a2aa60..f17f87396 100644
--- a/ansible_collections/community/network/plugins/modules/ce_snmp_contact.py
+++ b/ansible_collections/community/network/plugins/modules/ce_snmp_contact.py
@@ -47,7 +47,7 @@ EXAMPLES = '''
- name: CloudEngine snmp contact test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_snmp_location.py b/ansible_collections/community/network/plugins/modules/ce_snmp_location.py
index 54c604743..6a70e5470 100644
--- a/ansible_collections/community/network/plugins/modules/ce_snmp_location.py
+++ b/ansible_collections/community/network/plugins/modules/ce_snmp_location.py
@@ -47,7 +47,7 @@ EXAMPLES = '''
- name: CloudEngine snmp location test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
tasks:
diff --git a/ansible_collections/community/network/plugins/modules/ce_snmp_target_host.py b/ansible_collections/community/network/plugins/modules/ce_snmp_target_host.py
index 30b64ad54..e4d2a2e91 100644
--- a/ansible_collections/community/network/plugins/modules/ce_snmp_target_host.py
+++ b/ansible_collections/community/network/plugins/modules/ce_snmp_target_host.py
@@ -84,7 +84,7 @@ EXAMPLES = '''
- name: CloudEngine snmp target host test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
tasks:
diff --git a/ansible_collections/community/network/plugins/modules/ce_snmp_traps.py b/ansible_collections/community/network/plugins/modules/ce_snmp_traps.py
index 6d9ea6a13..9845e3969 100644
--- a/ansible_collections/community/network/plugins/modules/ce_snmp_traps.py
+++ b/ansible_collections/community/network/plugins/modules/ce_snmp_traps.py
@@ -64,7 +64,7 @@ EXAMPLES = '''
- name: CloudEngine snmp traps test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_snmp_user.py b/ansible_collections/community/network/plugins/modules/ce_snmp_user.py
index e666ce8bc..90dde723d 100644
--- a/ansible_collections/community/network/plugins/modules/ce_snmp_user.py
+++ b/ansible_collections/community/network/plugins/modules/ce_snmp_user.py
@@ -68,7 +68,7 @@ EXAMPLES = '''
- name: CloudEngine snmp user test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_startup.py b/ansible_collections/community/network/plugins/modules/ce_startup.py
index fe0e143a7..fb0904355 100644
--- a/ansible_collections/community/network/plugins/modules/ce_startup.py
+++ b/ansible_collections/community/network/plugins/modules/ce_startup.py
@@ -58,7 +58,7 @@ EXAMPLES = '''
- name: Startup module test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_static_route.py b/ansible_collections/community/network/plugins/modules/ce_static_route.py
index 0312e5969..346532e9a 100644
--- a/ansible_collections/community/network/plugins/modules/ce_static_route.py
+++ b/ansible_collections/community/network/plugins/modules/ce_static_route.py
@@ -64,7 +64,7 @@ EXAMPLES = '''
- name: Static route module test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
tasks:
diff --git a/ansible_collections/community/network/plugins/modules/ce_stp.py b/ansible_collections/community/network/plugins/modules/ce_stp.py
index b640d1634..a62e238f7 100644
--- a/ansible_collections/community/network/plugins/modules/ce_stp.py
+++ b/ansible_collections/community/network/plugins/modules/ce_stp.py
@@ -101,7 +101,7 @@ EXAMPLES = '''
- name: CloudEngine stp test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
tasks:
diff --git a/ansible_collections/community/network/plugins/modules/ce_switchport.py b/ansible_collections/community/network/plugins/modules/ce_switchport.py
index 7ccfd8bae..f292c4199 100644
--- a/ansible_collections/community/network/plugins/modules/ce_switchport.py
+++ b/ansible_collections/community/network/plugins/modules/ce_switchport.py
@@ -71,7 +71,7 @@ options:
EXAMPLES = '''
- name: Switchport module test
hosts: cloudengine
- gather_facts: no
+ gather_facts: false
vars:
ansible_user: root
ansible_password: PASSWORD
diff --git a/ansible_collections/community/network/plugins/modules/ce_vlan.py b/ansible_collections/community/network/plugins/modules/ce_vlan.py
index 610294103..7c12169ff 100644
--- a/ansible_collections/community/network/plugins/modules/ce_vlan.py
+++ b/ansible_collections/community/network/plugins/modules/ce_vlan.py
@@ -54,7 +54,7 @@ EXAMPLES = '''
- name: Vlan module test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_vrf.py b/ansible_collections/community/network/plugins/modules/ce_vrf.py
index f3293c9a3..02d6e4751 100644
--- a/ansible_collections/community/network/plugins/modules/ce_vrf.py
+++ b/ansible_collections/community/network/plugins/modules/ce_vrf.py
@@ -50,7 +50,7 @@ EXAMPLES = '''
- name: Vrf module test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_vrf_af.py b/ansible_collections/community/network/plugins/modules/ce_vrf_af.py
index 05a205e69..ab941d229 100644
--- a/ansible_collections/community/network/plugins/modules/ce_vrf_af.py
+++ b/ansible_collections/community/network/plugins/modules/ce_vrf_af.py
@@ -73,7 +73,7 @@ EXAMPLES = '''
- name: Vrf af module test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_vrf_interface.py b/ansible_collections/community/network/plugins/modules/ce_vrf_interface.py
index d51f13370..baf553030 100644
--- a/ansible_collections/community/network/plugins/modules/ce_vrf_interface.py
+++ b/ansible_collections/community/network/plugins/modules/ce_vrf_interface.py
@@ -54,7 +54,7 @@ EXAMPLES = '''
- name: VRF interface test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
tasks:
diff --git a/ansible_collections/community/network/plugins/modules/ce_vrrp.py b/ansible_collections/community/network/plugins/modules/ce_vrrp.py
index 9d9fc349c..c5651f4f3 100644
--- a/ansible_collections/community/network/plugins/modules/ce_vrrp.py
+++ b/ansible_collections/community/network/plugins/modules/ce_vrrp.py
@@ -130,7 +130,7 @@ EXAMPLES = '''
- name: Vrrp module test
hosts: cloudengine
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_vxlan_arp.py b/ansible_collections/community/network/plugins/modules/ce_vxlan_arp.py
index bcb1659b5..62be8ce52 100644
--- a/ansible_collections/community/network/plugins/modules/ce_vxlan_arp.py
+++ b/ansible_collections/community/network/plugins/modules/ce_vxlan_arp.py
@@ -81,7 +81,7 @@ EXAMPLES = '''
- name: Vxlan arp module test
hosts: ce128
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_vxlan_gateway.py b/ansible_collections/community/network/plugins/modules/ce_vxlan_gateway.py
index 9a0339763..5fe74240f 100644
--- a/ansible_collections/community/network/plugins/modules/ce_vxlan_gateway.py
+++ b/ansible_collections/community/network/plugins/modules/ce_vxlan_gateway.py
@@ -110,7 +110,7 @@ EXAMPLES = '''
- name: Vxlan gateway module test
hosts: ce128
connection: local
- gather_facts: no
+ gather_facts: false
tasks:
diff --git a/ansible_collections/community/network/plugins/modules/ce_vxlan_global.py b/ansible_collections/community/network/plugins/modules/ce_vxlan_global.py
index e474c9236..8b12f201a 100644
--- a/ansible_collections/community/network/plugins/modules/ce_vxlan_global.py
+++ b/ansible_collections/community/network/plugins/modules/ce_vxlan_global.py
@@ -76,7 +76,7 @@ EXAMPLES = '''
- name: Vxlan global module test
hosts: ce128
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_vxlan_tunnel.py b/ansible_collections/community/network/plugins/modules/ce_vxlan_tunnel.py
index d644b51d2..48b6d23da 100644
--- a/ansible_collections/community/network/plugins/modules/ce_vxlan_tunnel.py
+++ b/ansible_collections/community/network/plugins/modules/ce_vxlan_tunnel.py
@@ -67,7 +67,7 @@ EXAMPLES = '''
- name: Vxlan tunnel module test
hosts: ce128
connection: local
- gather_facts: no
+ gather_facts: false
vars:
cli:
host: "{{ inventory_hostname }}"
diff --git a/ansible_collections/community/network/plugins/modules/ce_vxlan_vap.py b/ansible_collections/community/network/plugins/modules/ce_vxlan_vap.py
index cdae94753..893790866 100644
--- a/ansible_collections/community/network/plugins/modules/ce_vxlan_vap.py
+++ b/ansible_collections/community/network/plugins/modules/ce_vxlan_vap.py
@@ -70,7 +70,7 @@ EXAMPLES = '''
- name: Vxlan vap module test
hosts: ce128
connection: local
- gather_facts: no
+ gather_facts: false
tasks:
diff --git a/ansible_collections/community/network/plugins/modules/cnos_config.py b/ansible_collections/community/network/plugins/modules/cnos_config.py
index e32deb7a1..6ba340c8a 100644
--- a/ansible_collections/community/network/plugins/modules/cnos_config.py
+++ b/ansible_collections/community/network/plugins/modules/cnos_config.py
@@ -159,12 +159,12 @@ Tasks: The following are examples of using the module cnos_config.
- name: Load a config from disk and replace the current config
community.network.cnos_config:
src: config.cfg
- backup: yes
+ backup: true
- name: Configurable backup path
community.network.cnos_config:
src: config.cfg
- backup: yes
+ backup: true
backup_options:
filename: backup.cfg
dir_path: /home/user
diff --git a/ansible_collections/community/network/plugins/modules/cnos_interface.py b/ansible_collections/community/network/plugins/modules/cnos_interface.py
index 48a9bfdf9..02cc102aa 100644
--- a/ansible_collections/community/network/plugins/modules/cnos_interface.py
+++ b/ansible_collections/community/network/plugins/modules/cnos_interface.py
@@ -48,7 +48,7 @@ options:
description:
- Interface link status.
type: bool
- default: True
+ default: true
speed:
description:
- Interface link speed.
@@ -116,12 +116,12 @@ EXAMPLES = """
- name: Make interface up
community.network.cnos_interface:
name: Ethernet1/33
- enabled: True
+ enabled: true
- name: Make interface down
community.network.cnos_interface:
name: Ethernet1/33
- enabled: False
+ enabled: false
- name: Check intent arguments
community.network.cnos_interface:
@@ -140,7 +140,7 @@ EXAMPLES = """
- name: Config + intent
community.network.cnos_interface:
name: Ethernet1/33
- enabled: False
+ enabled: false
state: down
- name: Add interface using aggregate
diff --git a/ansible_collections/community/network/plugins/modules/cnos_l3_interface.py b/ansible_collections/community/network/plugins/modules/cnos_l3_interface.py
index a7a0e81df..9874b30a1 100644
--- a/ansible_collections/community/network/plugins/modules/cnos_l3_interface.py
+++ b/ansible_collections/community/network/plugins/modules/cnos_l3_interface.py
@@ -125,8 +125,10 @@ from ansible_collections.community.network.plugins.module_utils.network.cnos.cno
from ansible_collections.community.network.plugins.module_utils.network.cnos.cnos import run_commands
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.config import NetworkConfig
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import remove_default_spec
-from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import is_netmask, is_masklen
-from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_netmask, to_masklen
+try:
+ from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import is_netmask, is_masklen, to_netmask, to_masklen
+except ImportError:
+ from ansible.module_utils.common.network import is_netmask, is_masklen, to_netmask, to_masklen
def validate_ipv4(value, module):
diff --git a/ansible_collections/community/network/plugins/modules/cnos_linkagg.py b/ansible_collections/community/network/plugins/modules/cnos_linkagg.py
index d7c08e38a..6b3ea73b1 100644
--- a/ansible_collections/community/network/plugins/modules/cnos_linkagg.py
+++ b/ansible_collections/community/network/plugins/modules/cnos_linkagg.py
@@ -56,7 +56,7 @@ options:
description:
- Purge links not defined in the I(aggregate) parameter.
type: bool
- default: no
+ default: false
'''
EXAMPLES = """
diff --git a/ansible_collections/community/network/plugins/modules/cnos_system.py b/ansible_collections/community/network/plugins/modules/cnos_system.py
index eced8ca53..804393f22 100644
--- a/ansible_collections/community/network/plugins/modules/cnos_system.py
+++ b/ansible_collections/community/network/plugins/modules/cnos_system.py
@@ -99,7 +99,7 @@ EXAMPLES = """
- name: Configure DNS Lookup sources
community.network.cnos_system:
lookup_source: MgmtEth0/0/CPU0/0
- lookup_enabled: yes
+ lookup_enabled: true
- name: Configure name servers with VRF support
nxos_system:
diff --git a/ansible_collections/community/network/plugins/modules/cnos_user.py b/ansible_collections/community/network/plugins/modules/cnos_user.py
index 151681f82..c99e3089e 100644
--- a/ansible_collections/community/network/plugins/modules/cnos_user.py
+++ b/ansible_collections/community/network/plugins/modules/cnos_user.py
@@ -101,7 +101,7 @@ EXAMPLES = """
- name: Remove all users except admin
community.network.cnos_user:
- purge: yes
+ purge: true
- name: Set multiple users role
aggregate:
diff --git a/ansible_collections/community/network/plugins/modules/cnos_vlan.py b/ansible_collections/community/network/plugins/modules/cnos_vlan.py
index 753f06209..4ba75c339 100644
--- a/ansible_collections/community/network/plugins/modules/cnos_vlan.py
+++ b/ansible_collections/community/network/plugins/modules/cnos_vlan.py
@@ -65,7 +65,7 @@ options:
purge:
description:
- Purge VLANs not defined in the I(aggregate) parameter.
- default: no
+ default: false
type: bool
state:
description:
diff --git a/ansible_collections/community/network/plugins/modules/cnos_vrf.py b/ansible_collections/community/network/plugins/modules/cnos_vrf.py
index 60bb23dc0..e9d5ab909 100644
--- a/ansible_collections/community/network/plugins/modules/cnos_vrf.py
+++ b/ansible_collections/community/network/plugins/modules/cnos_vrf.py
@@ -58,7 +58,7 @@ options:
purge:
description:
- Purge VRFs not defined in the I(aggregate) parameter.
- default: no
+ default: false
type: bool
delay:
description:
@@ -92,7 +92,7 @@ EXAMPLES = """
- { name: test4, rd: "1:204" }
- { name: test5, rd: "1:205" }
state: present
- purge: yes
+ purge: true
- name: Delete aggregate of VRFs
community.network.cnos_vrf:
diff --git a/ansible_collections/community/network/plugins/modules/cv_server_provision.py b/ansible_collections/community/network/plugins/modules/cv_server_provision.py
index 4cf90d25c..1f5b65332 100644
--- a/ansible_collections/community/network/plugins/modules/cv_server_provision.py
+++ b/ansible_collections/community/network/plugins/modules/cv_server_provision.py
@@ -138,7 +138,7 @@ EXAMPLES = '''
switch_port: 2
template: template_file.j2
action: remove
- auto_run: True
+ auto_run: true
- name: Add template configuration to interface Ethernet2. No VLAN. Run task.
community.network.cv_server_provision:
@@ -151,7 +151,7 @@ EXAMPLES = '''
switch_port: 2
template: single_attached_trunk.j2
action: add
- auto_run: True
+ auto_run: true
- name: Add template with VLAN configuration to interface Ethernet2. Run task.
community.network.cv_server_provision:
@@ -165,7 +165,7 @@ EXAMPLES = '''
port_vlan: 22
template: single_attached_vlan.j2
action: add
- auto_run: True
+ auto_run: true
'''
RETURN = '''
@@ -373,7 +373,7 @@ def port_configurable(module, configlet):
:param module: Ansible module with parameters and client connection.
:param configlet: Dict of configlet info.
- :return: True or False.
+ :return: true or False.
'''
configurable = False
regex = r'^interface Ethernet%s' % module.params['switch_port']
@@ -450,7 +450,7 @@ def valid_template(port, template):
:param port: User specified port.
:param template: Contents of Jinja template.
- :return: True or False
+ :return: true or False
'''
valid = True
regex = r'^interface Ethernet%s' % port
@@ -552,7 +552,7 @@ def wait_for_task_completion(module, task):
:param module: Ansible module with parameters and client connection.
:param task: Task ID to poll for completion.
- :return: True or exit with failure if task is cancelled or fails.
+ :return: true or exit with failure if task is cancelled or fails.
'''
task_complete = False
while not task_complete:
diff --git a/ansible_collections/community/network/plugins/modules/dladm_iptun.py b/ansible_collections/community/network/plugins/modules/dladm_iptun.py
index 7770199e5..81ff8493b 100644
--- a/ansible_collections/community/network/plugins/modules/dladm_iptun.py
+++ b/ansible_collections/community/network/plugins/modules/dladm_iptun.py
@@ -81,7 +81,7 @@ temporary:
description: specifies if operation will persist across reboots
returned: always
type: bool
- sample: True
+ sample: true
local_address:
description: local IP address
returned: always
diff --git a/ansible_collections/community/network/plugins/modules/dladm_linkprop.py b/ansible_collections/community/network/plugins/modules/dladm_linkprop.py
index 0c1a96536..036fcb5cb 100644
--- a/ansible_collections/community/network/plugins/modules/dladm_linkprop.py
+++ b/ansible_collections/community/network/plugins/modules/dladm_linkprop.py
@@ -71,7 +71,7 @@ temporary:
description: specifies if operation will persist across reboots
returned: always
type: bool
- sample: True
+ sample: true
link:
description: link name
returned: always
diff --git a/ansible_collections/community/network/plugins/modules/dladm_vlan.py b/ansible_collections/community/network/plugins/modules/dladm_vlan.py
index a9770bd38..cab712a8c 100644
--- a/ansible_collections/community/network/plugins/modules/dladm_vlan.py
+++ b/ansible_collections/community/network/plugins/modules/dladm_vlan.py
@@ -68,7 +68,7 @@ temporary:
description: specifies if operation will persist across reboots
returned: always
type: bool
- sample: True
+ sample: true
link:
description: VLAN's underlying link name
returned: always
diff --git a/ansible_collections/community/network/plugins/modules/edgeos_command.py b/ansible_collections/community/network/plugins/modules/edgeos_command.py
index cc4a73b74..17e332f32 100644
--- a/ansible_collections/community/network/plugins/modules/edgeos_command.py
+++ b/ansible_collections/community/network/plugins/modules/edgeos_command.py
@@ -30,19 +30,19 @@ options:
remote device. The output of the command is returned to the playbook.
If the C(wait_for) argument is provided, the module is not returned
until the condition is met or the number of retries is exceeded.
- required: True
+ required: true
wait_for:
description:
- Causes the task to wait for a specific condition to be met before
moving forward. If the condition is not met before the specified
number of retries is exceeded, the task will fail.
- required: False
+ required: false
match:
description:
- Used in conjunction with C(wait_for) to create match policy. If set to
C(all), then all conditions in C(wait_for) must be met. If set to
C(any), then only one condition must match.
- required: False
+ required: false
default: 'all'
choices: ['any', 'all']
retries:
@@ -50,12 +50,12 @@ options:
- Number of times a command should be tried before it is considered failed.
The command is run on the target device and evaluated against the
C(wait_for) conditionals.
- required: False
+ required: false
default: 10
interval:
description:
- The number of seconds to wait between C(retries) of the command.
- required: False
+ required: false
default: 1
notes:
diff --git a/ansible_collections/community/network/plugins/modules/edgeos_config.py b/ansible_collections/community/network/plugins/modules/edgeos_config.py
index bf4fd5e54..0f4e1f68d 100644
--- a/ansible_collections/community/network/plugins/modules/edgeos_config.py
+++ b/ansible_collections/community/network/plugins/modules/edgeos_config.py
@@ -116,12 +116,12 @@ EXAMPLES = """
- name: Backup and load from file
community.network.edgeos_config:
src: edgeos.cfg
- backup: yes
+ backup: true
- name: Configurable backup path
community.network.edgeos_config:
src: edgeos.cfg
- backup: yes
+ backup: true
backup_options:
filename: backup.cfg
dir_path: /home/user
diff --git a/ansible_collections/community/network/plugins/modules/edgeswitch_vlan.py b/ansible_collections/community/network/plugins/modules/edgeswitch_vlan.py
index 4520309fa..6e47eb192 100644
--- a/ansible_collections/community/network/plugins/modules/edgeswitch_vlan.py
+++ b/ansible_collections/community/network/plugins/modules/edgeswitch_vlan.py
@@ -65,7 +65,7 @@ options:
purge:
description:
- Purge VLANs not defined in the I(aggregate) parameter.
- default: no
+ default: false
type: bool
state:
description:
diff --git a/ansible_collections/community/network/plugins/modules/enos_config.py b/ansible_collections/community/network/plugins/modules/enos_config.py
index 86a8497da..e74558263 100644
--- a/ansible_collections/community/network/plugins/modules/enos_config.py
+++ b/ansible_collections/community/network/plugins/modules/enos_config.py
@@ -160,12 +160,12 @@ EXAMPLES = """
- name: Load a config from disk and replace the current config
community.network.enos_config:
src: config.cfg
- backup: yes
+ backup: true
- name: Configurable backup path
community.network.enos_config:
src: config.cfg
- backup: yes
+ backup: true
backup_options:
filename: backup.cfg
dir_path: /home/user
diff --git a/ansible_collections/community/network/plugins/modules/enos_facts.py b/ansible_collections/community/network/plugins/modules/enos_facts.py
index f9d72512b..d5c0cbfd3 100644
--- a/ansible_collections/community/network/plugins/modules/enos_facts.py
+++ b/ansible_collections/community/network/plugins/modules/enos_facts.py
@@ -62,7 +62,7 @@ Tasks: The following are examples of using the module enos_facts.
password: admin
transport: cli
timeout: 30
- authorize: True
+ authorize: true
auth_pass:
---
diff --git a/ansible_collections/community/network/plugins/modules/exos_config.py b/ansible_collections/community/network/plugins/modules/exos_config.py
index 7267b3927..8c893fa38 100644
--- a/ansible_collections/community/network/plugins/modules/exos_config.py
+++ b/ansible_collections/community/network/plugins/modules/exos_config.py
@@ -169,7 +169,7 @@ EXAMPLES = """
community.network.exos_config:
lines:
- configure ports 2 description-string "Master Uplink"
- backup: yes
+ backup: true
- name: Check the running-config against master config
community.network.exos_config:
@@ -190,7 +190,7 @@ EXAMPLES = """
community.network.exos_config:
lines:
- configure ports 2 description-string "Master Uplink"
- backup: yes
+ backup: true
backup_options:
filename: backup.cfg
dir_path: /home/user
@@ -323,7 +323,7 @@ def main():
result['warnings'] = warnings
config = None
- flags = ['detail'] if module.params['defaults'] else []
+ flags = [' detail'] if module.params['defaults'] else []
diff_ignore_lines = module.params['diff_ignore_lines']
if module.params['backup'] or (module._diff and module.params['diff_against'] == 'running'):
@@ -412,6 +412,8 @@ def main():
base_config = NetworkConfig(indent=1, contents=contents, ignore_lines=diff_ignore_lines)
if running_config.sha1 != base_config.sha1:
+ before = ''
+ after = ''
if module.params['diff_against'] == 'intended':
before = running_config
after = base_config
diff --git a/ansible_collections/community/network/plugins/modules/exos_facts.py b/ansible_collections/community/network/plugins/modules/exos_facts.py
index 174463dc0..43ea8efab 100644
--- a/ansible_collections/community/network/plugins/modules/exos_facts.py
+++ b/ansible_collections/community/network/plugins/modules/exos_facts.py
@@ -36,6 +36,9 @@ description:
enable or disable collection of additional facts.
notes:
- Tested against EXOS 22.5.1.7
+ - "The I(gather_network_resources) option currently only works with
+ C(ansible_connection: ansible.netcommon.httpapi). For details, see
+ U(https://github.com/ansible-collections/community.network/issues/460)."
options:
gather_subset:
description:
@@ -56,7 +59,8 @@ options:
Can specify a list of values to include a larger subset.
Values can also be used with an initial C(!) to specify that
a specific subset should not be collected.
- Valid subsets are 'all', 'lldp_global'.
+ Valid subsets are 'all', 'lldp_global', 'lldp_interfaces',
+ 'vlans', 'l2_interfaces'.
type: list
'''
@@ -83,13 +87,13 @@ EXAMPLES = """
gather_subset:
- '!all'
- '!min'
- gather_network_resource:
+ gather_network_resources:
- lldp_global
- name: Gather lldp global resource and minimal legacy facts
community.network.exos_facts:
gather_subset: min
- gather_network_resource: lldp_global
+ gather_network_resources: lldp_global
"""
RETURN = """
diff --git a/ansible_collections/community/network/plugins/modules/exos_l2_interfaces.py b/ansible_collections/community/network/plugins/modules/exos_l2_interfaces.py
index 2fc82fef7..747f4634a 100644
--- a/ansible_collections/community/network/plugins/modules/exos_l2_interfaces.py
+++ b/ansible_collections/community/network/plugins/modules/exos_l2_interfaces.py
@@ -49,7 +49,7 @@ options:
description:
- Name of the interface
type: str
- required: True
+ required: true
access:
description:
- Switchport mode access command to configure the interface as a layer 2 access.
diff --git a/ansible_collections/community/network/plugins/modules/exos_lldp_interfaces.py b/ansible_collections/community/network/plugins/modules/exos_lldp_interfaces.py
index 01a7a7609..fb3ff5a94 100644
--- a/ansible_collections/community/network/plugins/modules/exos_lldp_interfaces.py
+++ b/ansible_collections/community/network/plugins/modules/exos_lldp_interfaces.py
@@ -46,7 +46,7 @@ options:
description:
- Name of the interface LLDP needs to be configured on.
type: str
- required: True
+ required: true
enabled:
description:
- This is a boolean value to control disabling of LLDP on the interface C(name)
@@ -122,15 +122,15 @@ EXAMPLES = """
#
# "before":
# - name: '1'
-# enabled: True
+# enabled: true
# - name: '2'
-# enabled: True
+# enabled: true
# - name: '3'
-# enabled: False
+# enabled: false
# - name: '4'
-# enabled: True
+# enabled: true
# - name: '5'
-# enabled: False
+# enabled: false
#
# "requests": [
# {
@@ -159,15 +159,15 @@ EXAMPLES = """
#
# "after":
# - name: '1'
-# enabled: True
+# enabled: true
# - name: '2'
-# enabled: False
+# enabled: false
# - name: '3'
-# enabled: False
+# enabled: false
# - name: '4'
-# enabled: True
+# enabled: true
# - name: '5'
-# enabled: True
+# enabled: true
# After state:
# -------------
@@ -272,15 +272,15 @@ EXAMPLES = """
#
# "before":
# - name: '1'
-# enabled: True
+# enabled: true
# - name: '2'
-# enabled: True
+# enabled: true
# - name: '3'
-# enabled: False
+# enabled: false
# - name: '4'
-# enabled: True
+# enabled: true
# - name: '5'
-# enabled: False
+# enabled: false
#
# "requests": [
# {
@@ -309,15 +309,15 @@ EXAMPLES = """
#
# "after":
# - name: '1'
-# enabled: False
+# enabled: false
# - name: '2'
-# enabled: True
+# enabled: true
# - name: '3'
-# enabled: True
+# enabled: true
# - name: '4'
-# enabled: True
+# enabled: true
# - name: '5'
-# enabled: False
+# enabled: false
# After state:
# -------------
@@ -408,11 +408,11 @@ EXAMPLES = """
#
# "before":
# - name: '1'
-# enabled: False
+# enabled: false
# - name: '2'
-# enabled: False
+# enabled: false
# - name: '3'
-# enabled: False
+# enabled: false
#
# "requests": [
# {
@@ -441,11 +441,11 @@ EXAMPLES = """
#
# "after":
# - name: '1'
-# enabled: True
+# enabled: true
# - name: '2'
-# enabled: False
+# enabled: false
# - name: '3'
-# enabled: True
+# enabled: true
#
# After state:
# -------------
@@ -535,15 +535,15 @@ EXAMPLES = """
#
# "before":
# - name: '1'
-# enabled: True
+# enabled: true
# - name: '2'
-# enabled: True
+# enabled: true
# - name: '3'
-# enabled: False
+# enabled: false
# - name: '4'
-# enabled: True
+# enabled: true
# - name: '5'
-# enabled: False
+# enabled: false
#
# "requests": [
# {
@@ -572,15 +572,15 @@ EXAMPLES = """
#
# "after":
# - name: '1'
-# enabled: True
+# enabled: true
# - name: '2'
-# enabled: True
+# enabled: true
# - name: '3'
-# enabled: True
+# enabled: true
# - name: '4'
-# enabled: True
+# enabled: true
# - name: '5'
-# enabled: True
+# enabled: true
# After state:
# -------------
diff --git a/ansible_collections/community/network/plugins/modules/exos_vlans.py b/ansible_collections/community/network/plugins/modules/exos_vlans.py
index 276ba92d8..806af7229 100644
--- a/ansible_collections/community/network/plugins/modules/exos_vlans.py
+++ b/ansible_collections/community/network/plugins/modules/exos_vlans.py
@@ -54,7 +54,7 @@ options:
description:
- ID of the VLAN. Range 1-4094
type: int
- required: True
+ required: true
state:
description:
- Operational state of the VLAN
diff --git a/ansible_collections/community/network/plugins/modules/iap_start_workflow.py b/ansible_collections/community/network/plugins/modules/iap_start_workflow.py
index c8c2ada8a..7b7206f1e 100644
--- a/ansible_collections/community/network/plugins/modules/iap_start_workflow.py
+++ b/ansible_collections/community/network/plugins/modules/iap_start_workflow.py
@@ -63,14 +63,14 @@ options:
- Use HTTPS to connect
- By default using http
type: bool
- default: False
+ default: false
validate_certs:
description:
- If C(no), SSL certificates for the target url will not be validated. This should only be used
on personally controlled sites using self-signed certificates.
type: bool
- default: False
+ default: false
'''
EXAMPLES = '''
diff --git a/ansible_collections/community/network/plugins/modules/iap_token.py b/ansible_collections/community/network/plugins/modules/iap_token.py
index 72d69df62..bd525f04c 100644
--- a/ansible_collections/community/network/plugins/modules/iap_token.py
+++ b/ansible_collections/community/network/plugins/modules/iap_token.py
@@ -45,14 +45,14 @@ options:
- Use HTTPS to connect
- By default using http
type: bool
- default: False
+ default: false
validate_certs:
description:
- If C(no), SSL certificates for the target url will not be validated. This should only be used
on personally controlled sites using self-signed certificates.
type: bool
- default: False
+ default: false
'''
EXAMPLES = '''
diff --git a/ansible_collections/community/network/plugins/modules/icx_banner.py b/ansible_collections/community/network/plugins/modules/icx_banner.py
index a13756e12..2c98b86fe 100644
--- a/ansible_collections/community/network/plugins/modules/icx_banner.py
+++ b/ansible_collections/community/network/plugins/modules/icx_banner.py
@@ -49,7 +49,7 @@ options:
Module will use environment variable value(default:True), unless it is overridden,
by specifying it as module parameter.
type: bool
- default: yes
+ default: true
'''
@@ -71,12 +71,12 @@ EXAMPLES = """
- name: Configure require-enter-key for motd
community.network.icx_banner:
banner: motd
- enterkey: True
+ enterkey: true
- name: Remove require-enter-key for motd
community.network.icx_banner:
banner: motd
- enterkey: False
+ enterkey: false
"""
RETURN = """
diff --git a/ansible_collections/community/network/plugins/modules/icx_command.py b/ansible_collections/community/network/plugins/modules/icx_command.py
index 85c85fc63..06e2ef4de 100644
--- a/ansible_collections/community/network/plugins/modules/icx_command.py
+++ b/ansible_collections/community/network/plugins/modules/icx_command.py
@@ -112,8 +112,8 @@ tasks:
answer:
- 'y'
- 'qqq\\\r'
- check_all: True
- newline: False
+ check_all: true
+ newline: false
"""
RETURN = """
diff --git a/ansible_collections/community/network/plugins/modules/icx_config.py b/ansible_collections/community/network/plugins/modules/icx_config.py
index 9486900f8..ce052d4e8 100644
--- a/ansible_collections/community/network/plugins/modules/icx_config.py
+++ b/ansible_collections/community/network/plugins/modules/icx_config.py
@@ -232,7 +232,7 @@ EXAMPLES = """
- name: Render template onto an ICX device
community.network.icx_config:
- backup: yes
+ backup: true
src: "{{ lookup('file', 'config.j2') }}"
"""
@@ -460,6 +460,8 @@ def main():
base_config = NetworkConfig(indent=1, contents=contents, ignore_lines=diff_ignore_lines)
if running_config.sha1 != base_config.sha1:
+ before = ''
+ after = ''
if module.params['diff_against'] == 'intended':
before = running_config
after = base_config
diff --git a/ansible_collections/community/network/plugins/modules/icx_interface.py b/ansible_collections/community/network/plugins/modules/icx_interface.py
index 235b90b17..6f7494288 100644
--- a/ansible_collections/community/network/plugins/modules/icx_interface.py
+++ b/ansible_collections/community/network/plugins/modules/icx_interface.py
@@ -29,7 +29,7 @@ options:
enabled:
description:
- Interface link status
- default: yes
+ default: true
type: bool
speed:
description:
@@ -214,7 +214,7 @@ options:
- Check running configuration. This can be set as environment variable.
- Module will use environment variable value(default:True), unless it is overridden,
by specifying it as module parameter.
- default: yes
+ default: true
type: bool
'''
diff --git a/ansible_collections/community/network/plugins/modules/icx_l3_interface.py b/ansible_collections/community/network/plugins/modules/icx_l3_interface.py
index d0f7ca841..fca81bb47 100644
--- a/ansible_collections/community/network/plugins/modules/icx_l3_interface.py
+++ b/ansible_collections/community/network/plugins/modules/icx_l3_interface.py
@@ -114,7 +114,7 @@ options:
- Check running configuration. This can be set as environment variable.
Module will use environment variable value(default:True), unless it is overridden, by specifying it as module parameter.
type: bool
- default: yes
+ default: true
'''
EXAMPLES = """
@@ -129,7 +129,7 @@ EXAMPLES = """
community.network.icx_l3_interface:
name: ethernet 1/1/1
ipv4: 192.168.0.1/24
- replace: yes
+ replace: true
state: absent
- name: Replace ethernet 1/1/1 dynamic IPv4 address
@@ -143,7 +143,7 @@ EXAMPLES = """
community.network.icx_l3_interface:
name: ethernet 1/1/1
ipv4: 192.168.0.1/24
- secondary: yes
+ secondary: true
state: absent
- name: Set ethernet 1/1/1 IPv4 address
@@ -197,7 +197,10 @@ from ansible.module_utils.connection import exec_command
from ansible_collections.community.network.plugins.module_utils.network.icx.icx import get_config, load_config
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.config import NetworkConfig
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import remove_default_spec
-from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import is_netmask, is_masklen, to_netmask, to_masklen
+try:
+ from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import is_netmask, is_masklen, to_netmask, to_masklen
+except ImportError:
+ from ansible.module_utils.common.network import is_netmask, is_masklen, to_netmask, to_masklen
def validate_ipv4(value, module):
diff --git a/ansible_collections/community/network/plugins/modules/icx_linkagg.py b/ansible_collections/community/network/plugins/modules/icx_linkagg.py
index 8dbab5c25..044816b37 100644
--- a/ansible_collections/community/network/plugins/modules/icx_linkagg.py
+++ b/ansible_collections/community/network/plugins/modules/icx_linkagg.py
@@ -47,7 +47,7 @@ options:
- Check running configuration. This can be set as environment variable.
Module will use environment variable value(default:True), unless it is overridden, by specifying it as module parameter.
type: bool
- default: yes
+ default: true
aggregate:
description:
- List of link aggregation definitions.
@@ -85,7 +85,7 @@ options:
description:
- Purge links not defined in the I(aggregate) parameter.
type: bool
- default: no
+ default: false
'''
diff --git a/ansible_collections/community/network/plugins/modules/icx_lldp.py b/ansible_collections/community/network/plugins/modules/icx_lldp.py
index 43d10765f..059d2be82 100644
--- a/ansible_collections/community/network/plugins/modules/icx_lldp.py
+++ b/ansible_collections/community/network/plugins/modules/icx_lldp.py
@@ -36,7 +36,7 @@ options:
- Check running configuration. This can be set as environment variable.
Module will use environment variable value(default:True), unless it is overridden, by specifying it as module parameter.
type: bool
- default: yes
+ default: true
state:
description:
- Enables the receipt and transmission of Link Layer Discovery Protocol (LLDP) globally.
diff --git a/ansible_collections/community/network/plugins/modules/icx_logging.py b/ansible_collections/community/network/plugins/modules/icx_logging.py
index fbe3d73d0..06b3e68a1 100644
--- a/ansible_collections/community/network/plugins/modules/icx_logging.py
+++ b/ansible_collections/community/network/plugins/modules/icx_logging.py
@@ -94,7 +94,7 @@ options:
- Check running configuration. This can be set as environment variable.
Module will use environment variable value(default:True), unless it is overridden, by specifying it as module parameter.
type: bool
- default: yes
+ default: true
'''
EXAMPLES = """
diff --git a/ansible_collections/community/network/plugins/modules/icx_static_route.py b/ansible_collections/community/network/plugins/modules/icx_static_route.py
index b66f6a400..4947c63c7 100644
--- a/ansible_collections/community/network/plugins/modules/icx_static_route.py
+++ b/ansible_collections/community/network/plugins/modules/icx_static_route.py
@@ -68,7 +68,7 @@ options:
purge:
description:
- Purge routes not defined in the I(aggregate) parameter.
- default: no
+ default: false
type: bool
state:
description:
@@ -81,7 +81,7 @@ options:
- Check running configuration. This can be set as environment variable.
Module will use environment variable value(default:True), unless it is overridden, by specifying it as module parameter.
type: bool
- default: yes
+ default: true
'''
EXAMPLES = """
diff --git a/ansible_collections/community/network/plugins/modules/icx_system.py b/ansible_collections/community/network/plugins/modules/icx_system.py
index bc20c174c..bb8f745ec 100644
--- a/ansible_collections/community/network/plugins/modules/icx_system.py
+++ b/ansible_collections/community/network/plugins/modules/icx_system.py
@@ -98,7 +98,7 @@ options:
- Check running configuration. This can be set as environment variable.
Module will use environment variable value(default:True), unless it is overridden, by specifying it as module parameter.
type: bool
- default: yes
+ default: true
'''
EXAMPLES = """
diff --git a/ansible_collections/community/network/plugins/modules/icx_user.py b/ansible_collections/community/network/plugins/modules/icx_user.py
index 3cc6971c8..7d251668a 100644
--- a/ansible_collections/community/network/plugins/modules/icx_user.py
+++ b/ansible_collections/community/network/plugins/modules/icx_user.py
@@ -133,7 +133,7 @@ options:
- Check running configuration. This can be set as environment variable.
Module will use environment variable value(default:True), unless it is overridden, by specifying it as module parameter.
type: bool
- default: yes
+ default: true
'''
EXAMPLES = """
diff --git a/ansible_collections/community/network/plugins/modules/icx_vlan.py b/ansible_collections/community/network/plugins/modules/icx_vlan.py
index 1eb254e26..54c4e03eb 100644
--- a/ansible_collections/community/network/plugins/modules/icx_vlan.py
+++ b/ansible_collections/community/network/plugins/modules/icx_vlan.py
@@ -201,7 +201,7 @@ options:
purge:
description:
- Purge VLANs not defined in the I(aggregate) parameter.
- default: no
+ default: false
type: bool
state:
description:
@@ -214,7 +214,7 @@ options:
- Check running configuration. This can be set as environment variable.
Module will use environment variable value(default:True), unless it is overridden, by specifying it as module parameter.
type: bool
- default: yes
+ default: true
'''
EXAMPLES = """
diff --git a/ansible_collections/community/network/plugins/modules/ipadm_addr.py b/ansible_collections/community/network/plugins/modules/ipadm_addr.py
index 7d42dbcbc..2fb24f8af 100644
--- a/ansible_collections/community/network/plugins/modules/ipadm_addr.py
+++ b/ansible_collections/community/network/plugins/modules/ipadm_addr.py
@@ -82,7 +82,7 @@ temporary:
description: specifies if operation will persist across reboots
returned: always
type: bool
- sample: True
+ sample: true
addrtype:
description: address type
returned: always
diff --git a/ansible_collections/community/network/plugins/modules/ipadm_addrprop.py b/ansible_collections/community/network/plugins/modules/ipadm_addrprop.py
index da5dcc679..7411c06e7 100644
--- a/ansible_collections/community/network/plugins/modules/ipadm_addrprop.py
+++ b/ansible_collections/community/network/plugins/modules/ipadm_addrprop.py
@@ -73,7 +73,7 @@ temporary:
description: specifies if operation will persist across reboots
returned: always
type: bool
- sample: True
+ sample: true
value:
description: property value
returned: when value is provided
diff --git a/ansible_collections/community/network/plugins/modules/nclu.py b/ansible_collections/community/network/plugins/modules/nclu.py
index 2b39dabfe..1f5e78daf 100644
--- a/ansible_collections/community/network/plugins/modules/nclu.py
+++ b/ansible_collections/community/network/plugins/modules/nclu.py
@@ -144,7 +144,7 @@ changed:
description: whether the interface was changed
returned: changed
type: bool
- sample: True
+ sample: true
msg:
description: human-readable report of success or failure
returned: always
diff --git a/ansible_collections/community/network/plugins/modules/netscaler_cs_action.py b/ansible_collections/community/network/plugins/modules/netscaler_cs_action.py
index 8fc7511c8..a134bd2e9 100644
--- a/ansible_collections/community/network/plugins/modules/netscaler_cs_action.py
+++ b/ansible_collections/community/network/plugins/modules/netscaler_cs_action.py
@@ -61,7 +61,7 @@ EXAMPLES = '''
nsip: 172.18.0.2
nitro_user: nsroot
nitro_pass: nsroot
- validate_certs: no
+ validate_certs: false
state: present
diff --git a/ansible_collections/community/network/plugins/modules/netscaler_cs_policy.py b/ansible_collections/community/network/plugins/modules/netscaler_cs_policy.py
index 47459608f..c1d481e6f 100644
--- a/ansible_collections/community/network/plugins/modules/netscaler_cs_policy.py
+++ b/ansible_collections/community/network/plugins/modules/netscaler_cs_policy.py
@@ -79,7 +79,7 @@ EXAMPLES = '''
nsip: 172.18.0.2
nitro_user: nsroot
nitro_pass: nsroot
- validate_certs: no
+ validate_certs: false
state: present
diff --git a/ansible_collections/community/network/plugins/modules/netscaler_lb_monitor.py b/ansible_collections/community/network/plugins/modules/netscaler_lb_monitor.py
index 9221afb49..167c45eeb 100644
--- a/ansible_collections/community/network/plugins/modules/netscaler_lb_monitor.py
+++ b/ansible_collections/community/network/plugins/modules/netscaler_lb_monitor.py
@@ -789,7 +789,7 @@ EXAMPLES = '''
nsip: 172.18.0.2
nitro_user: nsroot
nitro_pass: nsroot
- validate_certs: no
+ validate_certs: false
module: netscaler_lb_monitor
diff --git a/ansible_collections/community/network/plugins/modules/netscaler_lb_vserver.py b/ansible_collections/community/network/plugins/modules/netscaler_lb_vserver.py
index 9869b7459..bf591b35b 100644
--- a/ansible_collections/community/network/plugins/modules/netscaler_lb_vserver.py
+++ b/ansible_collections/community/network/plugins/modules/netscaler_lb_vserver.py
@@ -913,7 +913,7 @@ EXAMPLES = '''
nsip: 172.18.0.2
nitro_user: nsroot
nitro_pass: nsroot
- validate_certs: no
+ validate_certs: false
state: present
@@ -936,7 +936,7 @@ EXAMPLES = '''
nsip: 172.18.0.2
nitro_user: nsroot
nitro_pass: nsroot
- validate_certs: no
+ validate_certs: false
state: present
name: lb_vserver_2
diff --git a/ansible_collections/community/network/plugins/modules/netscaler_save_config.py b/ansible_collections/community/network/plugins/modules/netscaler_save_config.py
index bcc43f103..1fa3f46f2 100644
--- a/ansible_collections/community/network/plugins/modules/netscaler_save_config.py
+++ b/ansible_collections/community/network/plugins/modules/netscaler_save_config.py
@@ -25,17 +25,17 @@ options:
description:
- The ip address of the netscaler appliance where the nitro API calls will be made.
- "The port can be specified with the colon (:). E.g. C(192.168.1.1:555)."
- required: True
+ required: true
nitro_user:
description:
- The username with which to authenticate to the netscaler node.
- required: True
+ required: true
nitro_pass:
description:
- The password with which to authenticate to the netscaler node.
- required: True
+ required: true
nitro_protocol:
choices: [ 'http', 'https' ]
@@ -76,7 +76,7 @@ EXAMPLES = '''
nitro_user: nsroot
nitro_pass: nsroot
- save_config: no
+ save_config: false
name: server-1
ipaddress: 192.168.1.1
diff --git a/ansible_collections/community/network/plugins/modules/netscaler_server.py b/ansible_collections/community/network/plugins/modules/netscaler_server.py
index e33adb205..287758fa6 100644
--- a/ansible_collections/community/network/plugins/modules/netscaler_server.py
+++ b/ansible_collections/community/network/plugins/modules/netscaler_server.py
@@ -186,8 +186,7 @@ def server_identical(client, module, server_proxy):
def diff_list(client, module, server_proxy):
- ret_val = server_proxy.diff_object(server.get_filtered(client, 'name:%s' % module.params['name'])[0]),
- return ret_val[0]
+ return server_proxy.diff_object(server.get_filtered(client, 'name:%s' % module.params['name'])[0])
def do_state_change(client, module, server_proxy):
diff --git a/ansible_collections/community/network/plugins/modules/netscaler_service.py b/ansible_collections/community/network/plugins/modules/netscaler_service.py
index 430d22537..9fe640bc9 100644
--- a/ansible_collections/community/network/plugins/modules/netscaler_service.py
+++ b/ansible_collections/community/network/plugins/modules/netscaler_service.py
@@ -113,7 +113,7 @@ options:
healthmonitor:
description:
- "Monitor the health of this service"
- default: yes
+ default: true
type: bool
maxreq:
@@ -127,7 +127,7 @@ options:
description:
- "Use the transparent cache redirection virtual server to forward requests to the cache server."
- "Note: Do not specify this parameter if you set the Cache Type parameter."
- default: no
+ default: false
type: bool
cip:
@@ -238,7 +238,7 @@ options:
- >-
Use Layer 2 mode to bridge the packets sent to this service if it is marked as DOWN. If the service
is DOWN, and this parameter is disabled, the packets are dropped.
- default: no
+ default: false
type: bool
monthreshold:
description:
@@ -329,7 +329,7 @@ options:
- >-
Shut down gracefully, not accepting any new connections, and disabling the service when all of its
connections are closed.
- default: no
+ default: false
type: bool
monitor_bindings:
@@ -378,7 +378,7 @@ EXAMPLES = '''
# Monitor monitor-1 must have been already setup
- name: Setup http service
- gather_facts: False
+ gather_facts: false
delegate_to: localhost
community.network.netscaler_service:
nsip: 172.18.0.2
diff --git a/ansible_collections/community/network/plugins/modules/netscaler_ssl_certkey.py b/ansible_collections/community/network/plugins/modules/netscaler_ssl_certkey.py
index 58d678f30..0f63ff4a5 100644
--- a/ansible_collections/community/network/plugins/modules/netscaler_ssl_certkey.py
+++ b/ansible_collections/community/network/plugins/modules/netscaler_ssl_certkey.py
@@ -115,7 +115,7 @@ EXAMPLES = '''
expirymonitor: enabled
notificationperiod: 30
inform: PEM
- password: False
+ password: false
passplain: somesecret
'''
diff --git a/ansible_collections/community/network/plugins/modules/nos_config.py b/ansible_collections/community/network/plugins/modules/nos_config.py
index 38e4fb7e7..ed69ea25c 100644
--- a/ansible_collections/community/network/plugins/modules/nos_config.py
+++ b/ansible_collections/community/network/plugins/modules/nos_config.py
@@ -190,7 +190,7 @@ EXAMPLES = """
- name: Configurable backup path
community.network.nos_config:
lines: logging raslog console INFO
- backup: yes
+ backup: true
backup_options:
filename: backup.cfg
dir_path: /home/user
diff --git a/ansible_collections/community/network/plugins/modules/nuage_vspk.py b/ansible_collections/community/network/plugins/modules/nuage_vspk.py
index 39fdae7a0..553a68afc 100644
--- a/ansible_collections/community/network/plugins/modules/nuage_vspk.py
+++ b/ansible_collections/community/network/plugins/modules/nuage_vspk.py
@@ -149,7 +149,7 @@ EXAMPLES = '''
command: find
properties:
name: "{{ enterprise_new_name }}-basic"
- ignore_errors: yes
+ ignore_errors: true
register: nuage_check_enterprise
# Updating an enterprise's name
@@ -192,7 +192,7 @@ EXAMPLES = '''
command: change_password
properties:
password: "ansible-new-password"
- ignore_errors: yes
+ ignore_errors: true
# Finding a group in an enterprise
- name: Find Administrators group in Enterprise
diff --git a/ansible_collections/community/network/plugins/modules/opx_cps.py b/ansible_collections/community/network/plugins/modules/opx_cps.py
index ec5cb6db2..4b026015f 100644
--- a/ansible_collections/community/network/plugins/modules/opx_cps.py
+++ b/ansible_collections/community/network/plugins/modules/opx_cps.py
@@ -160,12 +160,12 @@ db:
description: Denotes if CPS DB transaction was performed
returned: when db is set to True in module options
type: bool
- sample: True
+ sample: true
commit_event:
description: Denotes if auto-commit event is set
returned: when commit_event is set to True in module options
type: bool
- sample: True
+ sample: true
"""
from ansible.module_utils.basic import AnsibleModule
diff --git a/ansible_collections/community/network/plugins/modules/pn_access_list.py b/ansible_collections/community/network/plugins/modules/pn_access_list.py
index 8b9235445..9d264196c 100644
--- a/ansible_collections/community/network/plugins/modules/pn_access_list.py
+++ b/ansible_collections/community/network/plugins/modules/pn_access_list.py
@@ -17,13 +17,13 @@ options:
pn_cliswitch:
description:
- Target switch to run the CLI on.
- required: False
+ required: false
type: str
state:
description:
- State the action to perform. Use 'present' to create access-list and
'absent' to delete access-list.
- required: True
+ required: true
choices: [ "present", "absent"]
pn_name:
description:
diff --git a/ansible_collections/community/network/plugins/modules/pn_access_list_ip.py b/ansible_collections/community/network/plugins/modules/pn_access_list_ip.py
index 78371d8b0..68195a97d 100644
--- a/ansible_collections/community/network/plugins/modules/pn_access_list_ip.py
+++ b/ansible_collections/community/network/plugins/modules/pn_access_list_ip.py
@@ -17,24 +17,24 @@ options:
pn_cliswitch:
description:
- Target switch to run the CLI on.
- required: False
+ required: false
type: str
state:
description:
- State the action to perform. Use 'present' to add access-list-ip and
'absent' to remove access-list-ip.
- required: True
+ required: true
choices: ["present", "absent"]
pn_ip:
description:
- IP associated with the access list.
- required: False
+ required: false
default: '::'
type: str
pn_name:
description:
- Access List Name.
- required: False
+ required: false
type: str
'''
diff --git a/ansible_collections/community/network/plugins/modules/pn_admin_service.py b/ansible_collections/community/network/plugins/modules/pn_admin_service.py
index 3ce9ce6b0..521576865 100644
--- a/ansible_collections/community/network/plugins/modules/pn_admin_service.py
+++ b/ansible_collections/community/network/plugins/modules/pn_admin_service.py
@@ -17,69 +17,69 @@ options:
pn_cliswitch:
description:
- Target switch to run the CLI on.
- required: False
+ required: false
type: str
state:
description:
- State the action to perform. Use C(update) to modify the admin-service.
- required: True
+ required: true
type: str
choices: ['update']
pn_web:
description:
- Web (HTTP) to enable or disable.
- required: False
+ required: false
type: bool
pn_web_ssl:
description:
- Web SSL (HTTPS) to enable or disable.
- required: False
+ required: false
type: bool
pn_snmp:
description:
- Simple Network Monitoring Protocol (SNMP) to enable or disable.
- required: False
+ required: false
type: bool
pn_web_port:
description:
- Web (HTTP) port to enable or disable.
- required: False
+ required: false
type: str
pn_web_ssl_port:
description:
- Web SSL (HTTPS) port to enable or disable.
- required: False
+ required: false
type: str
pn_nfs:
description:
- Network File System (NFS) to enable or disable.
- required: False
+ required: false
type: bool
pn_ssh:
description:
- Secure Shell to enable or disable.
- required: False
+ required: false
type: bool
pn_web_log:
description:
- Web logging to enable or disable.
- required: False
+ required: false
type: bool
pn__if:
description:
- administrative service interface.
- required: False
+ required: false
type: str
choices: ['mgmt', 'data']
pn_icmp:
description:
- Internet Message Control Protocol (ICMP) to enable or disable.
- required: False
+ required: false
type: bool
pn_net_api:
description:
- Netvisor API to enable or disable APIs.
- required: False
+ required: false
type: bool
'''
@@ -89,18 +89,18 @@ EXAMPLES = """
pn_cliswitch: "sw01"
state: "update"
pn__if: "mgmt"
- pn_web: False
- pn_icmp: True
+ pn_web: false
+ pn_icmp: true
- name: Admin service functionality
community.network.pn_admin_service:
pn_cliswitch: "sw01"
state: "update"
- pn_web: False
+ pn_web: false
pn__if: "mgmt"
- pn_snmp: True
- pn_net_api: True
- pn_ssh: True
+ pn_snmp: true
+ pn_net_api: true
+ pn_ssh: true
"""
RETURN = """
diff --git a/ansible_collections/community/network/plugins/modules/pn_admin_session_timeout.py b/ansible_collections/community/network/plugins/modules/pn_admin_session_timeout.py
index 0c69c88c5..cb6587d4d 100644
--- a/ansible_collections/community/network/plugins/modules/pn_admin_session_timeout.py
+++ b/ansible_collections/community/network/plugins/modules/pn_admin_session_timeout.py
@@ -17,20 +17,20 @@ options:
pn_cliswitch:
description:
- Target switch to run the CLI on.
- required: False
+ required: false
type: str
state:
description:
- State the action to perform.
C(update) to modify the admin-session-timeout.
- required: True
+ required: true
type: str
choices: ['update']
pn_timeout:
description:
- Maximum time to wait for user activity before
terminating login session. Minimum should be 60s.
- required: False
+ required: false
type: str
'''
diff --git a/ansible_collections/community/network/plugins/modules/pn_admin_syslog.py b/ansible_collections/community/network/plugins/modules/pn_admin_syslog.py
index 068212137..acac07c7c 100644
--- a/ansible_collections/community/network/plugins/modules/pn_admin_syslog.py
+++ b/ansible_collections/community/network/plugins/modules/pn_admin_syslog.py
@@ -19,48 +19,48 @@ options:
pn_cliswitch:
description:
- Target switch to run the CLI on.
- required: False
+ required: false
type: str
state:
description:
- State the action to perform. Use C(present) to create admin-syslog and
C(absent) to delete admin-syslog C(update) to modify the admin-syslog.
- required: True
+ required: true
type: str
choices: ['present', 'absent', 'update']
pn_scope:
description:
- Scope of the system log.
- required: False
+ required: false
type: str
choices: ['local', 'fabric']
pn_host:
description:
- Hostname to log system events.
- required: False
+ required: false
type: str
pn_port:
description:
- Host port.
- required: False
+ required: false
type: str
pn_transport:
description:
- Transport for log events - tcp/tls or udp.
- required: False
+ required: false
type: str
choices: ['tcp-tls', 'udp']
default: 'udp'
pn_message_format:
description:
- message-format for log events - structured or legacy.
- required: False
+ required: false
choices: ['structured', 'legacy']
type: str
pn_name:
description:
- name of the system log.
- required: False
+ required: false
type: str
'''
diff --git a/ansible_collections/community/network/plugins/modules/pn_connection_stats_settings.py b/ansible_collections/community/network/plugins/modules/pn_connection_stats_settings.py
index 580ad0054..aba6142a3 100644
--- a/ansible_collections/community/network/plugins/modules/pn_connection_stats_settings.py
+++ b/ansible_collections/community/network/plugins/modules/pn_connection_stats_settings.py
@@ -18,94 +18,94 @@ options:
pn_cliswitch:
description:
- Target switch to run the CLI on.
- required: False
+ required: false
type: str
state:
description:
- State the action to perform. Use C(update) to modify the
connection-stats-settings.
- required: True
+ required: true
type: str
choices: ['update']
pn_enable:
description:
- Enable or disable collecting connections statistics.
- required: False
+ required: false
type: bool
pn_connection_backup_enable:
description:
- Enable backup for connection statistics collection.
- required: False
+ required: false
type: bool
pn_client_server_stats_max_memory:
description:
- maximum memory for client server statistics.
- required: False
+ required: false
type: str
pn_connection_stats_log_disk_space:
description:
- disk-space allocated for statistics (including rotated log files).
- required: False
+ required: false
type: str
pn_client_server_stats_log_enable:
description:
- Enable or disable statistics.
- required: False
+ required: false
type: bool
pn_service_stat_max_memory:
description:
- maximum memory allowed for service statistics.
- required: False
+ required: false
type: str
pn_connection_stats_log_interval:
description:
- interval to collect statistics.
- required: False
+ required: false
type: str
pn_fabric_connection_backup_interval:
description:
- backup interval for fabric connection statistics collection.
- required: False
+ required: false
type: str
pn_connection_backup_interval:
description:
- backup interval for connection statistics collection.
- required: False
+ required: false
type: str
pn_connection_stats_log_enable:
description:
- enable or disable statistics.
- required: False
+ required: false
type: bool
pn_fabric_connection_max_memory:
description:
- maximum memory allowed for fabric connection statistics.
- required: False
+ required: false
type: str
pn_fabric_connection_backup_enable:
description:
- enable backup for fabric connection statistics collection.
- required: False
+ required: false
type: bool
pn_client_server_stats_log_disk_space:
description:
- disk-space allocated for statistics (including rotated log files).
- required: False
+ required: false
type: str
pn_connection_max_memory:
description:
- maximum memory allowed for connection statistics.
- required: False
+ required: false
type: str
pn_connection_stats_max_memory:
description:
- maximum memory allowed for connection statistics.
- required: False
+ required: false
type: str
pn_client_server_stats_log_interval:
description:
- interval to collect statistics.
- required: False
+ required: false
type: str
'''
@@ -114,14 +114,14 @@ EXAMPLES = """
community.network.pn_connection_stats_settings:
pn_cliswitch: "sw01"
state: "update"
- pn_enable: False
+ pn_enable: false
pn_fabric_connection_max_memory: "1000"
- name: "Modify connection stats settings"
community.network.pn_connection_stats_settings:
pn_cliswitch: "sw01"
state: "update"
- pn_enable: True
+ pn_enable: true
"""
RETURN = """
diff --git a/ansible_collections/community/network/plugins/modules/pn_cpu_class.py b/ansible_collections/community/network/plugins/modules/pn_cpu_class.py
index 3ef89c818..291ae8188 100644
--- a/ansible_collections/community/network/plugins/modules/pn_cpu_class.py
+++ b/ansible_collections/community/network/plugins/modules/pn_cpu_class.py
@@ -17,13 +17,13 @@ options:
pn_cliswitch:
description:
- Target switch to run the CLI on.
- required: False
+ required: false
type: str
state:
description:
- State the action to perform. Use C(present) to create cpu-class and
C(absent) to delete cpu-class C(update) to modify the cpu-class.
- required: True
+ required: true
type: str
choices: ['present', 'absent', 'update']
pn_scope:
@@ -34,18 +34,18 @@ options:
pn_hog_protect:
description:
- enable host-based hog protection.
- required: False
+ required: false
type: str
choices: ['disable', 'enable', 'enable-and-drop']
pn_rate_limit:
description:
- rate-limit for CPU class.
- required: False
+ required: false
type: str
pn_name:
description:
- name for the CPU class.
- required: False
+ required: false
type: str
'''
diff --git a/ansible_collections/community/network/plugins/modules/pn_dhcp_filter.py b/ansible_collections/community/network/plugins/modules/pn_dhcp_filter.py
index d876d77cf..f5a2a6dcd 100644
--- a/ansible_collections/community/network/plugins/modules/pn_dhcp_filter.py
+++ b/ansible_collections/community/network/plugins/modules/pn_dhcp_filter.py
@@ -17,19 +17,19 @@ options:
pn_cliswitch:
description:
- Target switch to run the CLI on.
- required: False
+ required: false
type: str
state:
description:
- State the action to perform. Use C(present) to create dhcp-filter and
C(absent) to delete dhcp-filter C(update) to modify the dhcp-filter.
- required: True
+ required: true
type: str
choices: ['present', 'absent', 'update']
pn_trusted_ports:
description:
- trusted ports of dhcp config.
- required: False
+ required: false
type: str
pn_name:
description:
diff --git a/ansible_collections/community/network/plugins/modules/pn_dscp_map.py b/ansible_collections/community/network/plugins/modules/pn_dscp_map.py
index d5753fe69..7de7db06d 100644
--- a/ansible_collections/community/network/plugins/modules/pn_dscp_map.py
+++ b/ansible_collections/community/network/plugins/modules/pn_dscp_map.py
@@ -17,24 +17,24 @@ options:
pn_cliswitch:
description:
- Target switch to run the CLI on.
- required: False
+ required: false
type: str
state:
description:
- State the action to perform. Use C(present) to create dscp-map and
C(absent) to delete.
- required: True
+ required: true
type: str
choices: ["present", "absent"]
pn_name:
description:
- Name for the DSCP map.
- required: False
+ required: false
type: str
pn_scope:
description:
- Scope for dscp map.
- required: False
+ required: false
choices: ["local", "fabric"]
'''
diff --git a/ansible_collections/community/network/plugins/modules/pn_dscp_map_pri_map.py b/ansible_collections/community/network/plugins/modules/pn_dscp_map_pri_map.py
index a87b64ea3..760d45d92 100644
--- a/ansible_collections/community/network/plugins/modules/pn_dscp_map_pri_map.py
+++ b/ansible_collections/community/network/plugins/modules/pn_dscp_map_pri_map.py
@@ -17,29 +17,29 @@ options:
pn_cliswitch:
description:
- Target switch to run the CLI on.
- required: False
+ required: false
type: str
state:
description:
- State the action to perform. Use C(update) to modify
the dscp-map-pri-map.
- required: True
+ required: true
type: str
choices: ['update']
pn_pri:
description:
- CoS priority.
- required: False
+ required: false
type: str
pn_name:
description:
- Name for the DSCP map.
- required: False
+ required: false
type: str
pn_dsmap:
description:
- DSCP value(s).
- required: False
+ required: false
type: str
'''
diff --git a/ansible_collections/community/network/plugins/modules/pn_igmp_snooping.py b/ansible_collections/community/network/plugins/modules/pn_igmp_snooping.py
index a2a1ce74b..b91d6497a 100644
--- a/ansible_collections/community/network/plugins/modules/pn_igmp_snooping.py
+++ b/ansible_collections/community/network/plugins/modules/pn_igmp_snooping.py
@@ -17,63 +17,63 @@ options:
pn_cliswitch:
description:
- Target switch to run the CLI on.
- required: False
+ required: false
type: str
state:
description:
- State the action to perform. Use C(update) to modify the igmp-snooping.
- required: True
+ required: true
type: str
choices: ['update']
pn_enable:
description:
- enable or disable IGMP snooping.
- required: False
+ required: false
type: bool
pn_query_interval:
description:
- IGMP query interval in seconds.
- required: False
+ required: false
type: str
pn_igmpv2_vlans:
description:
- VLANs on which to use IGMPv2 protocol.
- required: False
+ required: false
type: str
pn_igmpv3_vlans:
description:
- VLANs on which to use IGMPv3 protocol.
- required: False
+ required: false
type: str
pn_enable_vlans:
description:
- enable per VLAN IGMP snooping.
- required: False
+ required: false
type: str
pn_vxlan:
description:
- enable or disable IGMP snooping on vxlans.
- required: False
+ required: false
type: bool
pn_query_max_response_time:
description:
- maximum response time, in seconds, advertised in IGMP queries.
- required: False
+ required: false
type: str
pn_scope:
description:
- IGMP snooping scope - fabric or local.
- required: False
+ required: false
choices: ['local', 'fabric']
pn_no_snoop_linklocal_vlans:
description:
- Remove snooping of link-local groups(224.0.0.0/24) on these vlans.
- required: False
+ required: false
type: str
pn_snoop_linklocal_vlans:
description:
- Allow snooping of link-local groups(224.0.0.0/24) on these vlans.
- required: False
+ required: false
type: str
'''
@@ -82,7 +82,7 @@ EXAMPLES = """
community.network.pn_igmp_snooping:
pn_cliswitch: 'sw01'
state: 'update'
- pn_vxlan: True
+ pn_vxlan: true
pn_enable_vlans: '1-399,401-4092'
pn_no_snoop_linklocal_vlans: 'none'
pn_igmpv3_vlans: '1-399,401-4092'
@@ -91,7 +91,7 @@ EXAMPLES = """
community.network.pn_igmp_snooping:
pn_cliswitch: 'sw01'
state: 'update'
- pn_vxlan: False
+ pn_vxlan: false
pn_enable_vlans: '1-399'
pn_no_snoop_linklocal_vlans: 'none'
pn_igmpv3_vlans: '1-399'
diff --git a/ansible_collections/community/network/plugins/modules/pn_port_config.py b/ansible_collections/community/network/plugins/modules/pn_port_config.py
index 31f024b4e..62d77af94 100644
--- a/ansible_collections/community/network/plugins/modules/pn_port_config.py
+++ b/ansible_collections/community/network/plugins/modules/pn_port_config.py
@@ -17,151 +17,151 @@ options:
pn_cliswitch:
description:
- Target switch to run the CLI on.
- required: False
+ required: false
type: str
state:
description:
- State the action to perform. Use C(update) to modify the port-config.
- required: True
+ required: true
type: str
choices: ['update']
pn_intf:
description:
- physical interface.
- required: False
+ required: false
type: str
pn_crc_check_enable:
description:
- CRC check on ingress and rewrite on egress.
- required: False
+ required: false
type: bool
pn_dscp_map:
description:
- DSCP map name to enable on port.
- required: False
+ required: false
type: str
pn_autoneg:
description:
- physical port autonegotiation.
- required: False
+ required: false
type: bool
pn_speed:
description:
- physical port speed.
- required: False
+ required: false
choices: ['disable', '10m', '100m', '1g',
'2.5g', '10g', '25g', '40g', '50g', '100g']
pn_port:
description:
- physical port.
- required: False
+ required: false
type: str
pn_vxlan_termination:
description:
- physical port vxlan termination setting.
- required: False
+ required: false
type: bool
pn_pause:
description:
- physical port pause.
- required: False
+ required: false
type: bool
pn_loopback:
description:
- physical port loopback.
- required: False
+ required: false
type: bool
pn_loop_vlans:
description:
- looping vlans.
- required: False
+ required: false
type: str
pn_routing:
description:
- routing.
- required: False
+ required: false
type: bool
pn_edge_switch:
description:
- physical port edge switch.
- required: False
+ required: false
type: bool
pn_enable:
description:
- physical port enable.
- required: False
+ required: false
type: bool
pn_description:
description:
- physical port description.
- required: False
+ required: false
type: str
pn_host_enable:
description:
- Host facing port control setting.
- required: False
+ required: false
type: bool
pn_allowed_tpid:
description:
- Allowed TPID in addition to 0x8100 on Vlan header.
- required: False
+ required: false
type: str
choices: ['vlan', 'q-in-q', 'q-in-q-old']
pn_mirror_only:
description:
- physical port mirror only.
- required: False
+ required: false
type: bool
pn_reflect:
description:
- physical port reflection.
- required: False
+ required: false
type: bool
pn_jumbo:
description:
- jumbo frames on physical port.
- required: False
+ required: false
type: bool
pn_egress_rate_limit:
description:
- max egress port data rate limit.
- required: False
+ required: false
type: str
pn_eth_mode:
description:
- physical Ethernet mode.
- required: False
+ required: false
choices: ['1000base-x', 'sgmii', 'disabled', 'GMII']
pn_fabric_guard:
description:
- Fabric guard configuration.
- required: False
+ required: false
type: bool
pn_local_switching:
description:
- no-local-switching port cannot bridge traffic to
another no-local-switching port.
- required: False
+ required: false
type: bool
pn_lacp_priority:
description:
- LACP priority from 1 to 65535.
- required: False
+ required: false
type: str
pn_send_port:
description:
- send port.
- required: False
+ required: false
type: str
pn_port_mac_address:
description:
- physical port MAC Address.
- required: False
+ required: false
type: str
pn_defer_bringup:
description:
- defer port bringup.
- required: False
+ required: false
type: bool
'''
diff --git a/ansible_collections/community/network/plugins/modules/pn_port_cos_bw.py b/ansible_collections/community/network/plugins/modules/pn_port_cos_bw.py
index 11578dc84..4c96ed742 100644
--- a/ansible_collections/community/network/plugins/modules/pn_port_cos_bw.py
+++ b/ansible_collections/community/network/plugins/modules/pn_port_cos_bw.py
@@ -17,39 +17,39 @@ options:
pn_cliswitch:
description:
- Target switch to run the CLI on.
- required: False
+ required: false
type: str
state:
description:
- State the action to perform. Use C(update) to modify the port-cos-bw.
- required: True
+ required: true
type: str
choices: ['update']
pn_max_bw_limit:
description:
- Maximum b/w in percentage.
- required: False
+ required: false
type: str
pn_cos:
description:
- CoS priority.
- required: False
+ required: false
type: str
pn_port:
description:
- physical port number.
- required: False
+ required: false
type: str
pn_weight:
description:
- Scheduling weight (1 to 127) after b/w guarantee met.
- required: False
+ required: false
type: str
choices: ['priority', 'no-priority']
pn_min_bw_guarantee:
description:
- Minimum b/w in percentage.
- required: False
+ required: false
type: str
'''
diff --git a/ansible_collections/community/network/plugins/modules/pn_stp_port.py b/ansible_collections/community/network/plugins/modules/pn_stp_port.py
index 81b4dde85..2cd7f93a7 100644
--- a/ansible_collections/community/network/plugins/modules/pn_stp_port.py
+++ b/ansible_collections/community/network/plugins/modules/pn_stp_port.py
@@ -67,7 +67,7 @@ EXAMPLES = """
pn_cliswitch: "sw01"
state: "update"
pn_port: "1"
- pn_filter: True
+ pn_filter: true
pn_priority: '144'
- name: Modify stp port
@@ -82,7 +82,7 @@ EXAMPLES = """
pn_cliswitch: "sw01"
state: "update"
pn_port: "1"
- pn_edge: True
+ pn_edge: true
pn_cost: "200"
"""
diff --git a/ansible_collections/community/network/plugins/modules/pn_vrouter_bgp.py b/ansible_collections/community/network/plugins/modules/pn_vrouter_bgp.py
index 8351351b4..bd6a88e8c 100644
--- a/ansible_collections/community/network/plugins/modules/pn_vrouter_bgp.py
+++ b/ansible_collections/community/network/plugins/modules/pn_vrouter_bgp.py
@@ -97,7 +97,7 @@ options:
- BFD protocol support for fault detection.
required: false
type: bool
- default: False
+ default: false
pn_next_hop_self:
description:
- BGP next hop is self or not.
diff --git a/ansible_collections/community/network/plugins/modules/pn_vtep.py b/ansible_collections/community/network/plugins/modules/pn_vtep.py
index cc0a172c8..8294e8e80 100644
--- a/ansible_collections/community/network/plugins/modules/pn_vtep.py
+++ b/ansible_collections/community/network/plugins/modules/pn_vtep.py
@@ -56,7 +56,7 @@ options:
- Tells whether switch in cluster or not.
required: false
type: bool
- default: True
+ default: true
'''
EXAMPLES = """
diff --git a/ansible_collections/community/network/plugins/modules/slxos_config.py b/ansible_collections/community/network/plugins/modules/slxos_config.py
index 76351637c..835cbf62c 100644
--- a/ansible_collections/community/network/plugins/modules/slxos_config.py
+++ b/ansible_collections/community/network/plugins/modules/slxos_config.py
@@ -224,7 +224,7 @@ EXAMPLES = """
- name: Configurable backup path
community.network.slxos_config:
lines: hostname {{ inventory_hostname }}
- backup: yes
+ backup: true
backup_options:
filename: backup.cfg
dir_path: /home/user
@@ -441,6 +441,8 @@ def main():
base_config = NetworkConfig(indent=1, contents=contents, ignore_lines=diff_ignore_lines)
if running_config.sha1 != base_config.sha1:
+ before = ''
+ after = ''
if module.params['diff_against'] == 'intended':
before = running_config
after = base_config
diff --git a/ansible_collections/community/network/plugins/modules/slxos_interface.py b/ansible_collections/community/network/plugins/modules/slxos_interface.py
index f13e8a42a..6837b2da2 100644
--- a/ansible_collections/community/network/plugins/modules/slxos_interface.py
+++ b/ansible_collections/community/network/plugins/modules/slxos_interface.py
@@ -42,7 +42,7 @@ options:
enabled:
description:
- Interface link status.
- default: True
+ default: true
type: bool
speed:
description:
@@ -99,12 +99,12 @@ EXAMPLES = """
- name: Make interface up
community.network.slxos_interface:
name: Ethernet 0/2
- enabled: True
+ enabled: true
- name: Make interface down
community.network.slxos_interface:
name: Ethernet 0/2
- enabled: False
+ enabled: false
- name: Check intent arguments
community.network.slxos_interface:
@@ -123,7 +123,7 @@ EXAMPLES = """
- name: Config + intent
community.network.slxos_interface:
name: Ethernet 0/2
- enabled: False
+ enabled: false
state: down
- name: Add interface using aggregate
diff --git a/ansible_collections/community/network/plugins/modules/slxos_l3_interface.py b/ansible_collections/community/network/plugins/modules/slxos_l3_interface.py
index 240f1024d..ad329d1f7 100644
--- a/ansible_collections/community/network/plugins/modules/slxos_l3_interface.py
+++ b/ansible_collections/community/network/plugins/modules/slxos_l3_interface.py
@@ -107,7 +107,10 @@ from ansible.module_utils.six import iteritems
from ansible_collections.community.network.plugins.module_utils.network.slxos.slxos import get_config, load_config
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.config import NetworkConfig
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import conditional, remove_default_spec
-from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import is_netmask, is_masklen, to_netmask, to_masklen
+try:
+ from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import is_netmask, is_masklen, to_netmask, to_masklen
+except ImportError:
+ from ansible.module_utils.common.network import is_netmask, is_masklen, to_netmask, to_masklen
def validate_ipv4(value, module):
diff --git a/ansible_collections/community/network/plugins/modules/slxos_vlan.py b/ansible_collections/community/network/plugins/modules/slxos_vlan.py
index 0ecf8a8d9..0ec1dc541 100644
--- a/ansible_collections/community/network/plugins/modules/slxos_vlan.py
+++ b/ansible_collections/community/network/plugins/modules/slxos_vlan.py
@@ -53,7 +53,7 @@ options:
description:
- Purge VLANs not defined in the I(aggregate) parameter.
type: bool
- default: no
+ default: false
state:
description:
- State of the VLAN configuration.
diff --git a/ansible_collections/community/network/plugins/modules/sros_config.py b/ansible_collections/community/network/plugins/modules/sros_config.py
index 5b00b9b8f..5570b4a3a 100644
--- a/ansible_collections/community/network/plugins/modules/sros_config.py
+++ b/ansible_collections/community/network/plugins/modules/sros_config.py
@@ -158,12 +158,12 @@ EXAMPLES = """
parents:
- configure
- system
- backup: yes
+ backup: true
- name: Load config from file
community.network.sros_config:
src: "{{ inventory_hostname }}.cfg"
- save: yes
+ save: true
- name: Invalid use of lines
community.network.sros_config:
@@ -182,7 +182,7 @@ EXAMPLES = """
- name: Configurable backup path
community.network.sros_config:
- backup: yes
+ backup: true
backup_options:
filename: backup.cfg
dir_path: /home/user
diff --git a/ansible_collections/community/network/plugins/modules/vdirect_commit.py b/ansible_collections/community/network/plugins/modules/vdirect_commit.py
index 19c25b601..05d436d99 100644
--- a/ansible_collections/community/network/plugins/modules/vdirect_commit.py
+++ b/ansible_collections/community/network/plugins/modules/vdirect_commit.py
@@ -116,7 +116,7 @@ EXAMPLES = '''
vdirect_user: vDirect
vdirect_password: radware
devices: ['dev1', 'dev2']
- sync: no
+ sync: false
'''
RETURN = '''
diff --git a/ansible_collections/community/network/plugins/modules/voss_config.py b/ansible_collections/community/network/plugins/modules/voss_config.py
index 79440b906..9a6a49f0c 100644
--- a/ansible_collections/community/network/plugins/modules/voss_config.py
+++ b/ansible_collections/community/network/plugins/modules/voss_config.py
@@ -177,7 +177,7 @@ EXAMPLES = """
community.network.voss_config:
lines:
- name "ServerA"
- backup: yes
+ backup: true
parents: interface GigabitEthernet 1/1
- name: Check the running-config against master config
@@ -197,7 +197,7 @@ EXAMPLES = """
- name: Configurable backup path
community.network.voss_config:
- backup: yes
+ backup: true
backup_options:
filename: backup.cfg
dir_path: /home/user
diff --git a/ansible_collections/community/network/requirements.txt b/ansible_collections/community/network/requirements.txt
new file mode 100644
index 000000000..9a265e015
--- /dev/null
+++ b/ansible_collections/community/network/requirements.txt
@@ -0,0 +1 @@
+ansible-pylibssh
diff --git a/ansible_collections/community/network/tests/integration/requirements.yml b/ansible_collections/community/network/tests/integration/requirements.yml
new file mode 100644
index 000000000..d4b8365f9
--- /dev/null
+++ b/ansible_collections/community/network/tests/integration/requirements.yml
@@ -0,0 +1,3 @@
+---
+collections:
+ - ansible.netcommon
diff --git a/ansible_collections/community/network/tests/integration/targets/cnos_conditional_template/tasks/main.yml b/ansible_collections/community/network/tests/integration/targets/cnos_conditional_template/tasks/main.yml
index 0aff639d7..15a856a5c 100644
--- a/ansible_collections/community/network/tests/integration/targets/cnos_conditional_template/tasks/main.yml
+++ b/ansible_collections/community/network/tests/integration/targets/cnos_conditional_template/tasks/main.yml
@@ -6,11 +6,11 @@
# This contain sample conditional template execution tasks
---
- name: Replace Config CLI command template with values
- template: src=demo_template.j2 dest=./commands/cnos_conditional_template_{{ inventory_hostname }}_command.txt
+ template: src=demo_template.j2 dest=./commands/cnos_conditional_template_{{ inventory_hostname }}_command.txt mode=0644
with_items: "{{conditional_template_data1}}"
- name: Applying CLI commands on Switches
- cnos_conditional_template: host={{ inventory_hostname }} username={{ hostvars[inventory_hostname]['ansible_ssh_user']}} password={{ hostvars[inventory_hostname]['ansible_ssh_pass']}} deviceType={{ hostvars[inventory_hostname]['deviceType']}}
+ cnos_conditional_template: host={{ inventory_hostname }} username={{ hostvars[inventory_hostname]['ansible_ssh_user']}} password={{ hostvars[inventory_hostname]['ansible_ssh_pass']}} deviceType={{ hostvars[inventory_hostname]['deviceType']}}
condition={{ hostvars[inventory_hostname]['condition'] }} flag='{{item.flag}}' commandfile=./commands/cnos_conditional_template_{{ inventory_hostname }}_command.txt outputfile=./results/cnos_conditional_template_{{ inventory_hostname }}_output.txt
with_items: "{{conditional_template_data1}}"
# Completed file
diff --git a/ansible_collections/community/network/tests/integration/targets/cnos_template/tasks/main.yml b/ansible_collections/community/network/tests/integration/targets/cnos_template/tasks/main.yml
index b26b89748..0fb9efd7c 100644
--- a/ansible_collections/community/network/tests/integration/targets/cnos_template/tasks/main.yml
+++ b/ansible_collections/community/network/tests/integration/targets/cnos_template/tasks/main.yml
@@ -6,10 +6,10 @@
# This contain sample template execution tasks
---
- name: Creates directory
- file: path=./commands state=directory
+ file: path=./commands state=directory mode=0755
- name: Replace Config CLI command template with values
- template: src=demo_template.j2 dest=./commands/cnos_template_{{ inventory_hostname }}_commands.txt
+ template: src=demo_template.j2 dest=./commands/cnos_template_{{ inventory_hostname }}_commands.txt mode=0644
with_items: "{{cnos_template_data}}"
- name: Applying CLI commands on Switches
diff --git a/ansible_collections/community/network/tests/integration/targets/prepare_nuage_tests/tasks/main.yml b/ansible_collections/community/network/tests/integration/targets/prepare_nuage_tests/tasks/main.yml
index 2a902dc82..af4bcdf3c 100644
--- a/ansible_collections/community/network/tests/integration/targets/prepare_nuage_tests/tasks/main.yml
+++ b/ansible_collections/community/network/tests/integration/targets/prepare_nuage_tests/tasks/main.yml
@@ -10,6 +10,7 @@
- name: Start Nuage VSD API Simulator
shell: "(cd /; nuage-vsd-sim >/dev/null 2>&1)"
+ changed_when: false
async: 1800
poll: 0
diff --git a/ansible_collections/community/network/tests/requirements.yml b/ansible_collections/community/network/tests/requirements.yml
deleted file mode 100644
index a218740b1..000000000
--- a/ansible_collections/community/network/tests/requirements.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-integration_tests_dependencies:
-- ansible.netcommon
-unit_tests_dependencies:
-- ansible.netcommon
diff --git a/ansible_collections/community/network/tests/sanity/ignore-2.15.txt b/ansible_collections/community/network/tests/sanity/ignore-2.15.txt
index f82bb18bd..f19cd8d79 100644
--- a/ansible_collections/community/network/tests/sanity/ignore-2.15.txt
+++ b/ansible_collections/community/network/tests/sanity/ignore-2.15.txt
@@ -817,3 +817,114 @@ tests/unit/plugins/modules/test_netscaler_ssl_certkey.py pylint:invalid-class-ob
tests/unit/plugins/modules/test_nos_facts.py pylint:use-maxsplit-arg
tests/unit/plugins/modules/test_slxos_facts.py pylint:use-maxsplit-arg
tests/unit/plugins/modules/test_voss_facts.py pylint:use-maxsplit-arg
+plugins/action/aireos.py pylint:unused-import
+plugins/action/aruba.py pylint:unused-import
+plugins/action/ce.py pylint:unused-import
+plugins/action/cnos.py pylint:unused-import
+plugins/action/enos.py pylint:unused-import
+plugins/action/ironware.py pylint:unused-import
+plugins/action/sros.py pylint:unused-import
+plugins/cliconf/aireos.py pylint:unused-import
+plugins/cliconf/apconos.py pylint:unused-import
+plugins/cliconf/aruba.py pylint:unused-import
+plugins/cliconf/cnos.py pylint:unused-import
+plugins/cliconf/edgeswitch.py pylint:unused-import
+plugins/cliconf/eric_eccli.py pylint:unused-import
+plugins/cliconf/exos.py pylint:unused-import
+plugins/cliconf/icx.py pylint:unused-import
+plugins/cliconf/ironware.py pylint:unused-import
+plugins/cliconf/slxos.py pylint:unused-import
+plugins/cliconf/voss.py pylint:unused-import
+plugins/cliconf/weos4.py pylint:unused-import
+plugins/lookup/avi.py pylint:unused-import
+plugins/module_utils/network/aos/aos.py pylint:unused-import
+plugins/module_utils/network/avi/ansible_utils.py pylint:unused-import
+plugins/module_utils/network/avi/avi.py pylint:unused-import
+plugins/module_utils/network/cloudengine/ce.py pylint:unused-import
+plugins/module_utils/network/cnos/cnos.py pylint:unused-import
+plugins/module_utils/network/eric_eccli/eric_eccli.py pylint:unused-import
+plugins/module_utils/network/exos/config/lldp_interfaces/lldp_interfaces.py pylint:unused-import
+plugins/module_utils/network/exos/exos.py pylint:unused-import
+plugins/module_utils/network/exos/facts/facts.py pylint:unused-import
+plugins/module_utils/network/exos/facts/l2_interfaces/l2_interfaces.py pylint:unused-import
+plugins/module_utils/network/exos/facts/legacy/base.py pylint:unused-import
+plugins/module_utils/network/exos/facts/lldp_global/lldp_global.py pylint:unused-import
+plugins/module_utils/network/exos/facts/lldp_interfaces/lldp_interfaces.py pylint:unused-import
+plugins/module_utils/network/exos/facts/vlans/vlans.py pylint:unused-import
+plugins/module_utils/network/icx/icx.py pylint:unused-import
+plugins/module_utils/network/ironware/ironware.py pylint:unused-import
+plugins/module_utils/network/netscaler/netscaler.py pylint:unused-import
+plugins/module_utils/network/slxos/slxos.py pylint:unused-import
+plugins/module_utils/network/sros/sros.py pylint:unused-import
+plugins/module_utils/version.py pylint:unused-import
+plugins/modules/avi_api_version.py pylint:unused-import
+plugins/modules/avi_gslbservice_patch_member.py pylint:unused-import
+plugins/modules/avi_user.py pylint:unused-import
+plugins/modules/avi_useraccount.py pylint:unused-import
+plugins/modules/ce_acl_interface.py pylint:unused-import
+plugins/modules/ce_bfd_global.py pylint:unused-import
+plugins/modules/ce_bfd_session.py pylint:unused-import
+plugins/modules/ce_bfd_view.py pylint:unused-import
+plugins/modules/ce_config.py pylint:unused-import
+plugins/modules/ce_file_copy.py pylint:unused-import
+plugins/modules/ce_interface.py pylint:unused-import
+plugins/modules/ce_lldp.py pylint:unused-import
+plugins/modules/ce_lldp_interface.py pylint:unused-import
+plugins/modules/ce_mdn_interface.py pylint:unused-import
+plugins/modules/ce_rollback.py pylint:unused-import
+plugins/modules/ce_sflow.py pylint:unused-import
+plugins/modules/ce_switchport.py pylint:unused-import
+plugins/modules/cnos_backup.py pylint:unused-import
+plugins/modules/cnos_banner.py pylint:unused-import
+plugins/modules/cnos_bgp.py pylint:unused-import
+plugins/modules/cnos_command.py pylint:unused-import
+plugins/modules/cnos_conditional_command.py pylint:unused-import
+plugins/modules/cnos_conditional_template.py pylint:unused-import
+plugins/modules/cnos_factory.py pylint:unused-import
+plugins/modules/cnos_image.py pylint:unused-import
+plugins/modules/cnos_interface.py pylint:unused-import
+plugins/modules/cnos_l2_interface.py pylint:unused-import
+plugins/modules/cnos_lldp.py pylint:unused-import
+plugins/modules/cnos_logging.py pylint:unused-import
+plugins/modules/cnos_reload.py pylint:unused-import
+plugins/modules/cnos_rollback.py pylint:unused-import
+plugins/modules/cnos_save.py pylint:unused-import
+plugins/modules/cnos_showrun.py pylint:unused-import
+plugins/modules/cnos_static_route.py pylint:unused-import
+plugins/modules/cnos_system.py pylint:unused-import
+plugins/modules/cnos_template.py pylint:unused-import
+plugins/modules/cnos_user.py pylint:unused-import
+plugins/modules/cnos_vlag.py pylint:unused-import
+plugins/modules/cnos_vlan.py pylint:unused-import
+plugins/modules/cnos_vrf.py pylint:unused-import
+plugins/modules/enos_command.py pylint:unused-import
+plugins/modules/eric_eccli_command.py pylint:unused-import
+plugins/modules/icx_banner.py pylint:unused-import
+plugins/modules/icx_command.py pylint:unused-import
+plugins/modules/icx_config.py pylint:unused-import
+plugins/modules/icx_facts.py pylint:unused-import
+plugins/modules/icx_interface.py pylint:unused-import
+plugins/modules/icx_linkagg.py pylint:unused-import
+plugins/modules/icx_logging.py pylint:unused-import
+plugins/modules/icx_ping.py pylint:unused-import
+plugins/modules/icx_static_route.py pylint:unused-import
+plugins/modules/icx_system.py pylint:unused-import
+plugins/modules/icx_user.py pylint:unused-import
+plugins/modules/icx_vlan.py pylint:unused-import
+plugins/modules/ordnance_config.py pylint:unused-import
+plugins/modules/slxos_l3_interface.py pylint:unused-import
+plugins/modules/sros_rollback.py pylint:unused-import
+plugins/netconf/ce.py pylint:unused-import
+plugins/terminal/aireos.py pylint:unused-import
+plugins/terminal/apconos.py pylint:unused-import
+plugins/terminal/aruba.py pylint:unused-import
+plugins/terminal/eric_eccli.py pylint:unused-import
+plugins/terminal/netvisor.py pylint:unused-import
+plugins/terminal/weos4.py pylint:unused-import
+tests/sanity/extra/botmeta.py pylint:unused-import
+tests/unit/compat/builtins.py pylint:unused-import
+tests/unit/plugins/modules/test_apconos_command.py pylint:unused-import
+tests/unit/plugins/modules/test_icx_logging.py pylint:unused-import
+tests/unit/plugins/modules/test_icx_system.py pylint:unused-import
+tests/unit/plugins/modules/test_pn_log_audit_exception.py pylint:unused-import
+tests/unit/plugins/modules/test_pn_vtep.py pylint:unused-import
diff --git a/ansible_collections/community/network/tests/sanity/ignore-2.11.txt b/ansible_collections/community/network/tests/sanity/ignore-2.16.txt
index 9f8b2367d..f19cd8d79 100644
--- a/ansible_collections/community/network/tests/sanity/ignore-2.11.txt
+++ b/ansible_collections/community/network/tests/sanity/ignore-2.16.txt
@@ -108,6 +108,7 @@ plugins/modules/avi_gslbgeodbprofile.py validate-modules:parameter-type-not-in-d
plugins/modules/avi_gslbservice.py validate-modules:doc-missing-type
plugins/modules/avi_gslbservice.py validate-modules:parameter-list-no-elements
plugins/modules/avi_gslbservice.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_gslbservice_patch_member.py pylint:use-a-generator
plugins/modules/avi_gslbservice_patch_member.py validate-modules:doc-missing-type
plugins/modules/avi_gslbservice_patch_member.py validate-modules:parameter-type-not-in-doc
plugins/modules/avi_hardwaresecuritymodulegroup.py validate-modules:doc-missing-type
@@ -608,6 +609,7 @@ plugins/modules/iap_start_workflow.py validate-modules:doc-required-mismatch
plugins/modules/iap_token.py validate-modules:parameter-type-not-in-doc
plugins/modules/netact_cm_command.py validate-modules:doc-choices-do-not-match-spec
plugins/modules/netact_cm_command.py validate-modules:parameter-type-not-in-doc
+plugins/modules/netscaler_cs_action.py pylint:condition-evals-to-constant # Should be fixed
plugins/modules/netscaler_cs_action.py validate-modules:nonexistent-parameter-documented
plugins/modules/netscaler_cs_action.py validate-modules:parameter-type-not-in-doc
plugins/modules/netscaler_cs_policy.py validate-modules:parameter-type-not-in-doc
@@ -800,3 +802,129 @@ plugins/modules/voss_config.py validate-modules:parameter-list-no-elements
plugins/modules/voss_config.py validate-modules:parameter-type-not-in-doc
plugins/modules/voss_facts.py validate-modules:parameter-list-no-elements
plugins/modules/voss_facts.py validate-modules:parameter-type-not-in-doc
+tests/unit/plugins/modules/test_edgeswitch_facts.py pylint:use-maxsplit-arg
+tests/unit/plugins/modules/test_edgeswitch_vlan.py pylint:use-maxsplit-arg
+tests/unit/plugins/modules/test_icx_ping.py pylint:use-maxsplit-arg
+tests/unit/plugins/modules/test_ironware_config.py pylint:arguments-renamed
+tests/unit/plugins/modules/test_ironware_facts.py pylint:use-maxsplit-arg
+tests/unit/plugins/modules/test_netscaler_cs_action.py pylint:invalid-class-object
+tests/unit/plugins/modules/test_netscaler_cs_vserver.py pylint:invalid-class-object
+tests/unit/plugins/modules/test_netscaler_lb_vserver.py pylint:invalid-class-object
+tests/unit/plugins/modules/test_netscaler_server.py pylint:invalid-class-object
+tests/unit/plugins/modules/test_netscaler_service.py pylint:invalid-class-object
+tests/unit/plugins/modules/test_netscaler_servicegroup.py pylint:invalid-class-object
+tests/unit/plugins/modules/test_netscaler_ssl_certkey.py pylint:invalid-class-object
+tests/unit/plugins/modules/test_nos_facts.py pylint:use-maxsplit-arg
+tests/unit/plugins/modules/test_slxos_facts.py pylint:use-maxsplit-arg
+tests/unit/plugins/modules/test_voss_facts.py pylint:use-maxsplit-arg
+plugins/action/aireos.py pylint:unused-import
+plugins/action/aruba.py pylint:unused-import
+plugins/action/ce.py pylint:unused-import
+plugins/action/cnos.py pylint:unused-import
+plugins/action/enos.py pylint:unused-import
+plugins/action/ironware.py pylint:unused-import
+plugins/action/sros.py pylint:unused-import
+plugins/cliconf/aireos.py pylint:unused-import
+plugins/cliconf/apconos.py pylint:unused-import
+plugins/cliconf/aruba.py pylint:unused-import
+plugins/cliconf/cnos.py pylint:unused-import
+plugins/cliconf/edgeswitch.py pylint:unused-import
+plugins/cliconf/eric_eccli.py pylint:unused-import
+plugins/cliconf/exos.py pylint:unused-import
+plugins/cliconf/icx.py pylint:unused-import
+plugins/cliconf/ironware.py pylint:unused-import
+plugins/cliconf/slxos.py pylint:unused-import
+plugins/cliconf/voss.py pylint:unused-import
+plugins/cliconf/weos4.py pylint:unused-import
+plugins/lookup/avi.py pylint:unused-import
+plugins/module_utils/network/aos/aos.py pylint:unused-import
+plugins/module_utils/network/avi/ansible_utils.py pylint:unused-import
+plugins/module_utils/network/avi/avi.py pylint:unused-import
+plugins/module_utils/network/cloudengine/ce.py pylint:unused-import
+plugins/module_utils/network/cnos/cnos.py pylint:unused-import
+plugins/module_utils/network/eric_eccli/eric_eccli.py pylint:unused-import
+plugins/module_utils/network/exos/config/lldp_interfaces/lldp_interfaces.py pylint:unused-import
+plugins/module_utils/network/exos/exos.py pylint:unused-import
+plugins/module_utils/network/exos/facts/facts.py pylint:unused-import
+plugins/module_utils/network/exos/facts/l2_interfaces/l2_interfaces.py pylint:unused-import
+plugins/module_utils/network/exos/facts/legacy/base.py pylint:unused-import
+plugins/module_utils/network/exos/facts/lldp_global/lldp_global.py pylint:unused-import
+plugins/module_utils/network/exos/facts/lldp_interfaces/lldp_interfaces.py pylint:unused-import
+plugins/module_utils/network/exos/facts/vlans/vlans.py pylint:unused-import
+plugins/module_utils/network/icx/icx.py pylint:unused-import
+plugins/module_utils/network/ironware/ironware.py pylint:unused-import
+plugins/module_utils/network/netscaler/netscaler.py pylint:unused-import
+plugins/module_utils/network/slxos/slxos.py pylint:unused-import
+plugins/module_utils/network/sros/sros.py pylint:unused-import
+plugins/module_utils/version.py pylint:unused-import
+plugins/modules/avi_api_version.py pylint:unused-import
+plugins/modules/avi_gslbservice_patch_member.py pylint:unused-import
+plugins/modules/avi_user.py pylint:unused-import
+plugins/modules/avi_useraccount.py pylint:unused-import
+plugins/modules/ce_acl_interface.py pylint:unused-import
+plugins/modules/ce_bfd_global.py pylint:unused-import
+plugins/modules/ce_bfd_session.py pylint:unused-import
+plugins/modules/ce_bfd_view.py pylint:unused-import
+plugins/modules/ce_config.py pylint:unused-import
+plugins/modules/ce_file_copy.py pylint:unused-import
+plugins/modules/ce_interface.py pylint:unused-import
+plugins/modules/ce_lldp.py pylint:unused-import
+plugins/modules/ce_lldp_interface.py pylint:unused-import
+plugins/modules/ce_mdn_interface.py pylint:unused-import
+plugins/modules/ce_rollback.py pylint:unused-import
+plugins/modules/ce_sflow.py pylint:unused-import
+plugins/modules/ce_switchport.py pylint:unused-import
+plugins/modules/cnos_backup.py pylint:unused-import
+plugins/modules/cnos_banner.py pylint:unused-import
+plugins/modules/cnos_bgp.py pylint:unused-import
+plugins/modules/cnos_command.py pylint:unused-import
+plugins/modules/cnos_conditional_command.py pylint:unused-import
+plugins/modules/cnos_conditional_template.py pylint:unused-import
+plugins/modules/cnos_factory.py pylint:unused-import
+plugins/modules/cnos_image.py pylint:unused-import
+plugins/modules/cnos_interface.py pylint:unused-import
+plugins/modules/cnos_l2_interface.py pylint:unused-import
+plugins/modules/cnos_lldp.py pylint:unused-import
+plugins/modules/cnos_logging.py pylint:unused-import
+plugins/modules/cnos_reload.py pylint:unused-import
+plugins/modules/cnos_rollback.py pylint:unused-import
+plugins/modules/cnos_save.py pylint:unused-import
+plugins/modules/cnos_showrun.py pylint:unused-import
+plugins/modules/cnos_static_route.py pylint:unused-import
+plugins/modules/cnos_system.py pylint:unused-import
+plugins/modules/cnos_template.py pylint:unused-import
+plugins/modules/cnos_user.py pylint:unused-import
+plugins/modules/cnos_vlag.py pylint:unused-import
+plugins/modules/cnos_vlan.py pylint:unused-import
+plugins/modules/cnos_vrf.py pylint:unused-import
+plugins/modules/enos_command.py pylint:unused-import
+plugins/modules/eric_eccli_command.py pylint:unused-import
+plugins/modules/icx_banner.py pylint:unused-import
+plugins/modules/icx_command.py pylint:unused-import
+plugins/modules/icx_config.py pylint:unused-import
+plugins/modules/icx_facts.py pylint:unused-import
+plugins/modules/icx_interface.py pylint:unused-import
+plugins/modules/icx_linkagg.py pylint:unused-import
+plugins/modules/icx_logging.py pylint:unused-import
+plugins/modules/icx_ping.py pylint:unused-import
+plugins/modules/icx_static_route.py pylint:unused-import
+plugins/modules/icx_system.py pylint:unused-import
+plugins/modules/icx_user.py pylint:unused-import
+plugins/modules/icx_vlan.py pylint:unused-import
+plugins/modules/ordnance_config.py pylint:unused-import
+plugins/modules/slxos_l3_interface.py pylint:unused-import
+plugins/modules/sros_rollback.py pylint:unused-import
+plugins/netconf/ce.py pylint:unused-import
+plugins/terminal/aireos.py pylint:unused-import
+plugins/terminal/apconos.py pylint:unused-import
+plugins/terminal/aruba.py pylint:unused-import
+plugins/terminal/eric_eccli.py pylint:unused-import
+plugins/terminal/netvisor.py pylint:unused-import
+plugins/terminal/weos4.py pylint:unused-import
+tests/sanity/extra/botmeta.py pylint:unused-import
+tests/unit/compat/builtins.py pylint:unused-import
+tests/unit/plugins/modules/test_apconos_command.py pylint:unused-import
+tests/unit/plugins/modules/test_icx_logging.py pylint:unused-import
+tests/unit/plugins/modules/test_icx_system.py pylint:unused-import
+tests/unit/plugins/modules/test_pn_log_audit_exception.py pylint:unused-import
+tests/unit/plugins/modules/test_pn_vtep.py pylint:unused-import
diff --git a/ansible_collections/community/network/tests/sanity/ignore-2.17.txt b/ansible_collections/community/network/tests/sanity/ignore-2.17.txt
new file mode 100644
index 000000000..f19cd8d79
--- /dev/null
+++ b/ansible_collections/community/network/tests/sanity/ignore-2.17.txt
@@ -0,0 +1,930 @@
+plugins/action/aireos.py action-plugin-docs # base class for deprecated network platform modules using `connection: local`
+plugins/action/aruba.py action-plugin-docs # base class for deprecated network platform modules using `connection: local`
+plugins/action/ce.py action-plugin-docs # base class for deprecated network platform modules using `connection: local`
+plugins/action/ce_template.py action-plugin-docs # undocumented action plugin to fix, existed before sanity test was added
+plugins/action/cnos.py action-plugin-docs # base class for deprecated network platform modules using `connection: local`
+plugins/action/enos.py action-plugin-docs # base class for deprecated network platform modules using `connection: local`
+plugins/action/exos.py action-plugin-docs # undocumented action plugin to fix
+plugins/action/ironware.py action-plugin-docs # base class for deprecated network platform modules using `connection: local`
+plugins/action/slxos.py action-plugin-docs # undocumented action plugin to fix
+plugins/action/sros.py action-plugin-docs # base class for deprecated network platform modules using `connection: local`
+plugins/action/voss.py action-plugin-docs # undocumented action plugin to fix
+plugins/module_utils/network/edgeswitch/edgeswitch_interface.py pylint:duplicate-string-formatting-argument
+plugins/modules/a10_server.py validate-modules:parameter-list-no-elements
+plugins/modules/a10_server.py validate-modules:parameter-type-not-in-doc
+plugins/modules/a10_server_axapi3.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/a10_server_axapi3.py validate-modules:parameter-list-no-elements
+plugins/modules/a10_server_axapi3.py validate-modules:parameter-type-not-in-doc
+plugins/modules/a10_service_group.py validate-modules:parameter-list-no-elements
+plugins/modules/a10_service_group.py validate-modules:parameter-type-not-in-doc
+plugins/modules/a10_virtual_server.py validate-modules:doc-default-does-not-match-spec
+plugins/modules/a10_virtual_server.py validate-modules:doc-required-mismatch
+plugins/modules/a10_virtual_server.py validate-modules:parameter-list-no-elements
+plugins/modules/a10_virtual_server.py validate-modules:parameter-type-not-in-doc
+plugins/modules/aireos_command.py validate-modules:collection-deprecated-version
+plugins/modules/aireos_command.py validate-modules:doc-missing-type
+plugins/modules/aireos_command.py validate-modules:parameter-list-no-elements
+plugins/modules/aireos_command.py validate-modules:parameter-type-not-in-doc
+plugins/modules/aireos_config.py validate-modules:collection-deprecated-version
+plugins/modules/aireos_config.py validate-modules:doc-missing-type
+plugins/modules/aireos_config.py validate-modules:parameter-list-no-elements
+plugins/modules/aireos_config.py validate-modules:parameter-type-not-in-doc
+plugins/modules/apconos_command.py validate-modules:parameter-list-no-elements
+plugins/modules/aruba_command.py validate-modules:collection-deprecated-version
+plugins/modules/aruba_command.py validate-modules:doc-missing-type
+plugins/modules/aruba_command.py validate-modules:parameter-list-no-elements
+plugins/modules/aruba_command.py validate-modules:parameter-type-not-in-doc
+plugins/modules/aruba_config.py validate-modules:collection-deprecated-version
+plugins/modules/aruba_config.py validate-modules:doc-missing-type
+plugins/modules/aruba_config.py validate-modules:parameter-list-no-elements
+plugins/modules/aruba_config.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_actiongroupconfig.py validate-modules:doc-missing-type
+plugins/modules/avi_actiongroupconfig.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_alertconfig.py validate-modules:doc-missing-type
+plugins/modules/avi_alertconfig.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_alertemailconfig.py validate-modules:doc-missing-type
+plugins/modules/avi_alertemailconfig.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_alertscriptconfig.py validate-modules:doc-missing-type
+plugins/modules/avi_alertscriptconfig.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_alertsyslogconfig.py validate-modules:doc-missing-type
+plugins/modules/avi_alertsyslogconfig.py validate-modules:parameter-list-no-elements
+plugins/modules/avi_alertsyslogconfig.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_analyticsprofile.py validate-modules:doc-missing-type
+plugins/modules/avi_analyticsprofile.py validate-modules:parameter-list-no-elements
+plugins/modules/avi_analyticsprofile.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_api_session.py validate-modules:doc-missing-type
+plugins/modules/avi_api_session.py validate-modules:doc-required-mismatch
+plugins/modules/avi_api_session.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_api_version.py validate-modules:doc-missing-type
+plugins/modules/avi_api_version.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_applicationpersistenceprofile.py validate-modules:doc-missing-type
+plugins/modules/avi_applicationpersistenceprofile.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_applicationprofile.py validate-modules:doc-missing-type
+plugins/modules/avi_applicationprofile.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_authprofile.py validate-modules:doc-missing-type
+plugins/modules/avi_authprofile.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_autoscalelaunchconfig.py validate-modules:doc-missing-type
+plugins/modules/avi_autoscalelaunchconfig.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_backup.py validate-modules:doc-missing-type
+plugins/modules/avi_backup.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_backupconfiguration.py validate-modules:doc-missing-type
+plugins/modules/avi_backupconfiguration.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_certificatemanagementprofile.py validate-modules:doc-missing-type
+plugins/modules/avi_certificatemanagementprofile.py validate-modules:parameter-list-no-elements
+plugins/modules/avi_certificatemanagementprofile.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_cloud.py validate-modules:doc-missing-type
+plugins/modules/avi_cloud.py validate-modules:parameter-list-no-elements
+plugins/modules/avi_cloud.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_cloudconnectoruser.py validate-modules:doc-missing-type
+plugins/modules/avi_cloudconnectoruser.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_cloudproperties.py validate-modules:doc-missing-type
+plugins/modules/avi_cloudproperties.py validate-modules:parameter-list-no-elements
+plugins/modules/avi_cloudproperties.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_cluster.py validate-modules:doc-missing-type
+plugins/modules/avi_cluster.py validate-modules:parameter-list-no-elements
+plugins/modules/avi_cluster.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_clusterclouddetails.py validate-modules:doc-missing-type
+plugins/modules/avi_clusterclouddetails.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_controllerproperties.py validate-modules:doc-missing-type
+plugins/modules/avi_controllerproperties.py validate-modules:parameter-list-no-elements
+plugins/modules/avi_controllerproperties.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_customipamdnsprofile.py validate-modules:doc-missing-type
+plugins/modules/avi_customipamdnsprofile.py validate-modules:parameter-list-no-elements
+plugins/modules/avi_customipamdnsprofile.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_dnspolicy.py validate-modules:doc-missing-type
+plugins/modules/avi_dnspolicy.py validate-modules:parameter-list-no-elements
+plugins/modules/avi_dnspolicy.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_errorpagebody.py validate-modules:doc-missing-type
+plugins/modules/avi_errorpagebody.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_errorpageprofile.py validate-modules:doc-missing-type
+plugins/modules/avi_errorpageprofile.py validate-modules:parameter-list-no-elements
+plugins/modules/avi_errorpageprofile.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_gslb.py validate-modules:doc-missing-type
+plugins/modules/avi_gslb.py validate-modules:parameter-list-no-elements
+plugins/modules/avi_gslb.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_gslbgeodbprofile.py validate-modules:doc-missing-type
+plugins/modules/avi_gslbgeodbprofile.py validate-modules:parameter-list-no-elements
+plugins/modules/avi_gslbgeodbprofile.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_gslbservice.py validate-modules:doc-missing-type
+plugins/modules/avi_gslbservice.py validate-modules:parameter-list-no-elements
+plugins/modules/avi_gslbservice.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_gslbservice_patch_member.py pylint:use-a-generator
+plugins/modules/avi_gslbservice_patch_member.py validate-modules:doc-missing-type
+plugins/modules/avi_gslbservice_patch_member.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_hardwaresecuritymodulegroup.py validate-modules:doc-missing-type
+plugins/modules/avi_hardwaresecuritymodulegroup.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_healthmonitor.py validate-modules:doc-missing-type
+plugins/modules/avi_healthmonitor.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_httppolicyset.py validate-modules:doc-missing-type
+plugins/modules/avi_httppolicyset.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_ipaddrgroup.py validate-modules:doc-missing-type
+plugins/modules/avi_ipaddrgroup.py validate-modules:parameter-list-no-elements
+plugins/modules/avi_ipaddrgroup.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_ipamdnsproviderprofile.py validate-modules:doc-missing-type
+plugins/modules/avi_ipamdnsproviderprofile.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_l4policyset.py validate-modules:doc-missing-type
+plugins/modules/avi_l4policyset.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_microservicegroup.py validate-modules:doc-missing-type
+plugins/modules/avi_microservicegroup.py validate-modules:parameter-list-no-elements
+plugins/modules/avi_microservicegroup.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_network.py validate-modules:doc-missing-type
+plugins/modules/avi_network.py validate-modules:parameter-list-no-elements
+plugins/modules/avi_network.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_networkprofile.py validate-modules:doc-missing-type
+plugins/modules/avi_networkprofile.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_networksecuritypolicy.py validate-modules:doc-missing-type
+plugins/modules/avi_networksecuritypolicy.py validate-modules:parameter-list-no-elements
+plugins/modules/avi_networksecuritypolicy.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_pkiprofile.py validate-modules:doc-missing-type
+plugins/modules/avi_pkiprofile.py validate-modules:parameter-list-no-elements
+plugins/modules/avi_pkiprofile.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_pool.py validate-modules:doc-missing-type
+plugins/modules/avi_pool.py validate-modules:parameter-list-no-elements
+plugins/modules/avi_pool.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_poolgroup.py validate-modules:doc-missing-type
+plugins/modules/avi_poolgroup.py validate-modules:parameter-list-no-elements
+plugins/modules/avi_poolgroup.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_poolgroupdeploymentpolicy.py validate-modules:doc-missing-type
+plugins/modules/avi_poolgroupdeploymentpolicy.py validate-modules:parameter-list-no-elements
+plugins/modules/avi_poolgroupdeploymentpolicy.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_prioritylabels.py validate-modules:doc-missing-type
+plugins/modules/avi_prioritylabels.py validate-modules:parameter-list-no-elements
+plugins/modules/avi_prioritylabels.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_role.py validate-modules:doc-missing-type
+plugins/modules/avi_role.py validate-modules:parameter-list-no-elements
+plugins/modules/avi_role.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_scheduler.py validate-modules:doc-missing-type
+plugins/modules/avi_scheduler.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_seproperties.py validate-modules:doc-missing-type
+plugins/modules/avi_seproperties.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_serverautoscalepolicy.py validate-modules:doc-missing-type
+plugins/modules/avi_serverautoscalepolicy.py validate-modules:parameter-list-no-elements
+plugins/modules/avi_serverautoscalepolicy.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_serviceengine.py validate-modules:doc-missing-type
+plugins/modules/avi_serviceengine.py validate-modules:parameter-list-no-elements
+plugins/modules/avi_serviceengine.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_serviceenginegroup.py validate-modules:doc-missing-type
+plugins/modules/avi_serviceenginegroup.py validate-modules:parameter-list-no-elements
+plugins/modules/avi_serviceenginegroup.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_snmptrapprofile.py validate-modules:doc-missing-type
+plugins/modules/avi_snmptrapprofile.py validate-modules:parameter-list-no-elements
+plugins/modules/avi_snmptrapprofile.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_sslkeyandcertificate.py validate-modules:doc-missing-type
+plugins/modules/avi_sslkeyandcertificate.py validate-modules:parameter-list-no-elements
+plugins/modules/avi_sslkeyandcertificate.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_sslprofile.py validate-modules:doc-missing-type
+plugins/modules/avi_sslprofile.py validate-modules:parameter-list-no-elements
+plugins/modules/avi_sslprofile.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_stringgroup.py validate-modules:doc-missing-type
+plugins/modules/avi_stringgroup.py validate-modules:parameter-list-no-elements
+plugins/modules/avi_stringgroup.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_systemconfiguration.py validate-modules:doc-missing-type
+plugins/modules/avi_systemconfiguration.py validate-modules:parameter-list-no-elements
+plugins/modules/avi_systemconfiguration.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_tenant.py validate-modules:doc-missing-type
+plugins/modules/avi_tenant.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_trafficcloneprofile.py validate-modules:doc-missing-type
+plugins/modules/avi_trafficcloneprofile.py validate-modules:parameter-list-no-elements
+plugins/modules/avi_trafficcloneprofile.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_user.py validate-modules:doc-missing-type
+plugins/modules/avi_user.py validate-modules:parameter-list-no-elements
+plugins/modules/avi_user.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_useraccount.py validate-modules:doc-missing-type
+plugins/modules/avi_useraccount.py validate-modules:doc-required-mismatch
+plugins/modules/avi_useraccount.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_useraccountprofile.py validate-modules:doc-missing-type
+plugins/modules/avi_useraccountprofile.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_virtualservice.py validate-modules:doc-missing-type
+plugins/modules/avi_virtualservice.py validate-modules:parameter-list-no-elements
+plugins/modules/avi_virtualservice.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_vrfcontext.py validate-modules:doc-missing-type
+plugins/modules/avi_vrfcontext.py validate-modules:parameter-list-no-elements
+plugins/modules/avi_vrfcontext.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_vsdatascriptset.py validate-modules:doc-missing-type
+plugins/modules/avi_vsdatascriptset.py validate-modules:parameter-list-no-elements
+plugins/modules/avi_vsdatascriptset.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_vsvip.py validate-modules:doc-missing-type
+plugins/modules/avi_vsvip.py validate-modules:parameter-list-no-elements
+plugins/modules/avi_vsvip.py validate-modules:parameter-type-not-in-doc
+plugins/modules/avi_webhook.py validate-modules:doc-missing-type
+plugins/modules/avi_webhook.py validate-modules:parameter-type-not-in-doc
+plugins/modules/bcf_switch.py validate-modules:doc-missing-type
+plugins/modules/bcf_switch.py validate-modules:parameter-type-not-in-doc
+plugins/modules/bigmon_chain.py validate-modules:doc-missing-type
+plugins/modules/bigmon_chain.py validate-modules:parameter-type-not-in-doc
+plugins/modules/bigmon_policy.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/bigmon_policy.py validate-modules:doc-default-does-not-match-spec
+plugins/modules/bigmon_policy.py validate-modules:doc-missing-type
+plugins/modules/bigmon_policy.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_aaa_server_host.py validate-modules:doc-missing-type
+plugins/modules/ce_aaa_server_host.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_acl.py validate-modules:doc-missing-type
+plugins/modules/ce_acl.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_acl_advance.py validate-modules:doc-missing-type
+plugins/modules/ce_acl_advance.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_acl_interface.py validate-modules:doc-missing-type
+plugins/modules/ce_acl_interface.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_bfd_global.py validate-modules:doc-missing-type
+plugins/modules/ce_bfd_global.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_bfd_session.py validate-modules:doc-missing-type
+plugins/modules/ce_bfd_session.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_bfd_view.py validate-modules:doc-missing-type
+plugins/modules/ce_bfd_view.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_bgp.py validate-modules:doc-missing-type
+plugins/modules/ce_bgp.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_bgp_af.py validate-modules:doc-default-does-not-match-spec
+plugins/modules/ce_bgp_af.py validate-modules:doc-missing-type
+plugins/modules/ce_bgp_af.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_bgp_neighbor.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/ce_bgp_neighbor.py validate-modules:doc-default-does-not-match-spec
+plugins/modules/ce_bgp_neighbor.py validate-modules:doc-missing-type
+plugins/modules/ce_bgp_neighbor.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_bgp_neighbor.py validate-modules:undocumented-parameter
+plugins/modules/ce_bgp_neighbor_af.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/ce_bgp_neighbor_af.py validate-modules:doc-default-does-not-match-spec
+plugins/modules/ce_bgp_neighbor_af.py validate-modules:doc-missing-type
+plugins/modules/ce_bgp_neighbor_af.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_bgp_neighbor_af.py validate-modules:undocumented-parameter
+plugins/modules/ce_command.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/ce_command.py validate-modules:doc-missing-type
+plugins/modules/ce_command.py validate-modules:parameter-list-no-elements
+plugins/modules/ce_command.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_config.py validate-modules:doc-missing-type
+plugins/modules/ce_config.py validate-modules:parameter-list-no-elements
+plugins/modules/ce_config.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_config.py validate-modules:undocumented-parameter
+plugins/modules/ce_dldp.py validate-modules:nonexistent-parameter-documented
+plugins/modules/ce_dldp.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_dldp.py validate-modules:undocumented-parameter
+plugins/modules/ce_dldp_interface.py validate-modules:doc-missing-type
+plugins/modules/ce_dldp_interface.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_eth_trunk.py validate-modules:doc-missing-type
+plugins/modules/ce_eth_trunk.py validate-modules:parameter-list-no-elements
+plugins/modules/ce_eth_trunk.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_evpn_bd_vni.py validate-modules:doc-missing-type
+plugins/modules/ce_evpn_bd_vni.py validate-modules:doc-required-mismatch
+plugins/modules/ce_evpn_bd_vni.py validate-modules:parameter-list-no-elements
+plugins/modules/ce_evpn_bd_vni.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_evpn_bgp.py validate-modules:doc-missing-type
+plugins/modules/ce_evpn_bgp.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_evpn_bgp_rr.py validate-modules:doc-missing-type
+plugins/modules/ce_evpn_bgp_rr.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_evpn_global.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_facts.py validate-modules:parameter-list-no-elements
+plugins/modules/ce_facts.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_file_copy.py validate-modules:doc-missing-type
+plugins/modules/ce_info_center_debug.py validate-modules:doc-missing-type
+plugins/modules/ce_info_center_debug.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_info_center_global.py validate-modules:doc-default-does-not-match-spec
+plugins/modules/ce_info_center_global.py validate-modules:doc-missing-type
+plugins/modules/ce_info_center_global.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_info_center_log.py validate-modules:doc-missing-type
+plugins/modules/ce_info_center_log.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_info_center_trap.py validate-modules:doc-missing-type
+plugins/modules/ce_info_center_trap.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_interface.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/ce_interface.py validate-modules:doc-missing-type
+plugins/modules/ce_interface.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_interface_ospf.py validate-modules:doc-missing-type
+plugins/modules/ce_interface_ospf.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_ip_interface.py validate-modules:doc-missing-type
+plugins/modules/ce_ip_interface.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_is_is_view.py validate-modules:doc-required-mismatch
+plugins/modules/ce_link_status.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_mlag_config.py validate-modules:doc-default-does-not-match-spec
+plugins/modules/ce_mlag_config.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_mlag_interface.py validate-modules:doc-default-does-not-match-spec
+plugins/modules/ce_mlag_interface.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_mtu.py validate-modules:doc-missing-type
+plugins/modules/ce_mtu.py validate-modules:doc-required-mismatch
+plugins/modules/ce_mtu.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_netconf.py validate-modules:doc-missing-type
+plugins/modules/ce_netstream_aging.py validate-modules:doc-missing-type
+plugins/modules/ce_netstream_aging.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_netstream_export.py validate-modules:doc-missing-type
+plugins/modules/ce_netstream_export.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_netstream_global.py validate-modules:doc-missing-type
+plugins/modules/ce_netstream_global.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_netstream_template.py validate-modules:doc-missing-type
+plugins/modules/ce_netstream_template.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_ntp.py validate-modules:doc-missing-type
+plugins/modules/ce_ntp.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_ntp_auth.py validate-modules:doc-missing-type
+plugins/modules/ce_ntp_auth.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_ospf.py validate-modules:doc-missing-type
+plugins/modules/ce_ospf.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_ospf_vrf.py validate-modules:doc-missing-type
+plugins/modules/ce_ospf_vrf.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_rollback.py validate-modules:doc-missing-type
+plugins/modules/ce_rollback.py validate-modules:doc-required-mismatch
+plugins/modules/ce_rollback.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_sflow.py validate-modules:doc-missing-type
+plugins/modules/ce_sflow.py validate-modules:parameter-list-no-elements
+plugins/modules/ce_sflow.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_snmp_community.py validate-modules:doc-missing-type
+plugins/modules/ce_snmp_community.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_snmp_contact.py validate-modules:doc-missing-type
+plugins/modules/ce_snmp_contact.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_snmp_location.py validate-modules:doc-missing-type
+plugins/modules/ce_snmp_location.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_snmp_target_host.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/ce_snmp_target_host.py validate-modules:doc-default-does-not-match-spec
+plugins/modules/ce_snmp_target_host.py validate-modules:doc-missing-type
+plugins/modules/ce_snmp_target_host.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_snmp_target_host.py validate-modules:undocumented-parameter
+plugins/modules/ce_snmp_traps.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/ce_snmp_traps.py validate-modules:doc-default-does-not-match-spec
+plugins/modules/ce_snmp_traps.py validate-modules:doc-missing-type
+plugins/modules/ce_snmp_traps.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_snmp_traps.py validate-modules:undocumented-parameter
+plugins/modules/ce_snmp_user.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/ce_snmp_user.py validate-modules:doc-default-does-not-match-spec
+plugins/modules/ce_snmp_user.py validate-modules:doc-missing-type
+plugins/modules/ce_snmp_user.py validate-modules:mutually_exclusive-unknown
+plugins/modules/ce_snmp_user.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_snmp_user.py validate-modules:undocumented-parameter
+plugins/modules/ce_startup.py validate-modules:doc-default-does-not-match-spec
+plugins/modules/ce_startup.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_static_route.py validate-modules:doc-missing-type
+plugins/modules/ce_static_route.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_static_route_bfd.py validate-modules:doc-required-mismatch
+plugins/modules/ce_static_route_bfd.py validate-modules:parameter-list-no-elements
+plugins/modules/ce_stp.py validate-modules:doc-missing-type
+plugins/modules/ce_stp.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_switchport.py validate-modules:doc-missing-type
+plugins/modules/ce_switchport.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_vlan.py validate-modules:doc-missing-type
+plugins/modules/ce_vlan.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_vrf.py validate-modules:doc-missing-type
+plugins/modules/ce_vrf.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_vrf_af.py validate-modules:doc-missing-type
+plugins/modules/ce_vrf_af.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_vrf_interface.py validate-modules:doc-missing-type
+plugins/modules/ce_vrf_interface.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_vrrp.py validate-modules:doc-default-does-not-match-spec
+plugins/modules/ce_vrrp.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_vxlan_arp.py validate-modules:doc-missing-type
+plugins/modules/ce_vxlan_arp.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_vxlan_gateway.py validate-modules:doc-missing-type
+plugins/modules/ce_vxlan_gateway.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_vxlan_global.py validate-modules:doc-missing-type
+plugins/modules/ce_vxlan_global.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_vxlan_tunnel.py validate-modules:doc-missing-type
+plugins/modules/ce_vxlan_tunnel.py validate-modules:parameter-list-no-elements
+plugins/modules/ce_vxlan_tunnel.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ce_vxlan_vap.py validate-modules:doc-missing-type
+plugins/modules/ce_vxlan_vap.py validate-modules:parameter-type-not-in-doc
+plugins/modules/cv_server_provision.py validate-modules:doc-missing-type
+plugins/modules/cv_server_provision.py validate-modules:doc-required-mismatch
+plugins/modules/cv_server_provision.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/cnos_backup.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/cnos_backup.py validate-modules:doc-missing-type
+plugins/modules/cnos_backup.py validate-modules:doc-required-mismatch
+plugins/modules/cnos_backup.py validate-modules:nonexistent-parameter-documented
+plugins/modules/cnos_backup.py validate-modules:undocumented-parameter
+plugins/modules/cnos_backup.py yamllint:unparsable-with-libyaml
+plugins/modules/cnos_banner.py validate-modules:doc-missing-type
+plugins/modules/cnos_bgp.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/cnos_bgp.py validate-modules:doc-missing-type
+plugins/modules/cnos_bgp.py validate-modules:doc-required-mismatch
+plugins/modules/cnos_bgp.py yamllint:unparsable-with-libyaml
+plugins/modules/cnos_command.py validate-modules:doc-missing-type
+plugins/modules/cnos_command.py validate-modules:parameter-list-no-elements
+plugins/modules/cnos_command.py validate-modules:parameter-type-not-in-doc
+plugins/modules/cnos_conditional_command.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/cnos_conditional_command.py validate-modules:doc-missing-type
+plugins/modules/cnos_conditional_command.py validate-modules:doc-required-mismatch
+plugins/modules/cnos_conditional_command.py yamllint:unparsable-with-libyaml
+plugins/modules/cnos_conditional_template.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/cnos_conditional_template.py validate-modules:doc-missing-type
+plugins/modules/cnos_conditional_template.py validate-modules:doc-required-mismatch
+plugins/modules/cnos_conditional_template.py yamllint:unparsable-with-libyaml
+plugins/modules/cnos_config.py validate-modules:doc-missing-type
+plugins/modules/cnos_config.py validate-modules:parameter-list-no-elements
+plugins/modules/cnos_config.py validate-modules:parameter-type-not-in-doc
+plugins/modules/cnos_config.py yamllint:unparsable-with-libyaml
+plugins/modules/cnos_factory.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/cnos_factory.py validate-modules:doc-required-mismatch
+plugins/modules/cnos_factory.py yamllint:unparsable-with-libyaml
+plugins/modules/cnos_facts.py validate-modules:nonexistent-parameter-documented
+plugins/modules/cnos_facts.py validate-modules:parameter-list-no-elements
+plugins/modules/cnos_facts.py validate-modules:parameter-type-not-in-doc
+plugins/modules/cnos_facts.py yamllint:unparsable-with-libyaml
+plugins/modules/cnos_image.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/cnos_image.py validate-modules:doc-missing-type
+plugins/modules/cnos_image.py validate-modules:doc-required-mismatch
+plugins/modules/cnos_image.py yamllint:unparsable-with-libyaml
+plugins/modules/cnos_interface.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/cnos_interface.py validate-modules:doc-elements-mismatch
+plugins/modules/cnos_interface.py validate-modules:doc-missing-type
+plugins/modules/cnos_interface.py validate-modules:doc-required-mismatch
+plugins/modules/cnos_interface.py validate-modules:missing-suboption-docs
+plugins/modules/cnos_interface.py validate-modules:parameter-type-not-in-doc
+plugins/modules/cnos_interface.py validate-modules:undocumented-parameter
+plugins/modules/cnos_l2_interface.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/cnos_l2_interface.py validate-modules:doc-elements-mismatch
+plugins/modules/cnos_l2_interface.py validate-modules:doc-missing-type
+plugins/modules/cnos_l2_interface.py validate-modules:doc-required-mismatch
+plugins/modules/cnos_l2_interface.py validate-modules:missing-suboption-docs
+plugins/modules/cnos_l2_interface.py validate-modules:parameter-type-not-in-doc
+plugins/modules/cnos_l2_interface.py validate-modules:undocumented-parameter
+plugins/modules/cnos_l3_interface.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/cnos_l3_interface.py validate-modules:doc-elements-mismatch
+plugins/modules/cnos_l3_interface.py validate-modules:doc-missing-type
+plugins/modules/cnos_l3_interface.py validate-modules:doc-required-mismatch
+plugins/modules/cnos_l3_interface.py validate-modules:missing-suboption-docs
+plugins/modules/cnos_l3_interface.py validate-modules:parameter-type-not-in-doc
+plugins/modules/cnos_l3_interface.py validate-modules:undocumented-parameter
+plugins/modules/cnos_linkagg.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/cnos_linkagg.py validate-modules:doc-elements-mismatch
+plugins/modules/cnos_linkagg.py validate-modules:doc-missing-type
+plugins/modules/cnos_linkagg.py validate-modules:doc-required-mismatch
+plugins/modules/cnos_linkagg.py validate-modules:missing-suboption-docs
+plugins/modules/cnos_linkagg.py validate-modules:parameter-list-no-elements
+plugins/modules/cnos_linkagg.py validate-modules:parameter-type-not-in-doc
+plugins/modules/cnos_linkagg.py validate-modules:undocumented-parameter
+plugins/modules/cnos_lldp.py validate-modules:doc-missing-type
+plugins/modules/cnos_logging.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/cnos_logging.py validate-modules:doc-elements-mismatch
+plugins/modules/cnos_logging.py validate-modules:doc-missing-type
+plugins/modules/cnos_logging.py validate-modules:missing-suboption-docs
+plugins/modules/cnos_logging.py validate-modules:parameter-type-not-in-doc
+plugins/modules/cnos_logging.py validate-modules:undocumented-parameter
+plugins/modules/cnos_reload.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/cnos_reload.py validate-modules:doc-required-mismatch
+plugins/modules/cnos_reload.py yamllint:unparsable-with-libyaml
+plugins/modules/cnos_rollback.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/cnos_rollback.py validate-modules:doc-missing-type
+plugins/modules/cnos_rollback.py validate-modules:doc-required-mismatch
+plugins/modules/cnos_rollback.py validate-modules:nonexistent-parameter-documented
+plugins/modules/cnos_rollback.py validate-modules:undocumented-parameter
+plugins/modules/cnos_rollback.py yamllint:unparsable-with-libyaml
+plugins/modules/cnos_save.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/cnos_save.py validate-modules:doc-required-mismatch
+plugins/modules/cnos_save.py yamllint:unparsable-with-libyaml
+plugins/modules/cnos_showrun.py validate-modules:doc-required-mismatch
+plugins/modules/cnos_showrun.py validate-modules:nonexistent-parameter-documented
+plugins/modules/cnos_showrun.py yamllint:unparsable-with-libyaml
+plugins/modules/cnos_static_route.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/cnos_static_route.py validate-modules:doc-elements-mismatch
+plugins/modules/cnos_static_route.py validate-modules:doc-missing-type
+plugins/modules/cnos_static_route.py validate-modules:doc-required-mismatch
+plugins/modules/cnos_static_route.py validate-modules:missing-suboption-docs
+plugins/modules/cnos_static_route.py validate-modules:parameter-type-not-in-doc
+plugins/modules/cnos_static_route.py validate-modules:undocumented-parameter
+plugins/modules/cnos_system.py validate-modules:doc-missing-type
+plugins/modules/cnos_system.py validate-modules:parameter-list-no-elements
+plugins/modules/cnos_system.py validate-modules:parameter-type-not-in-doc
+plugins/modules/cnos_template.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/cnos_template.py validate-modules:doc-missing-type
+plugins/modules/cnos_template.py validate-modules:doc-required-mismatch
+plugins/modules/cnos_template.py yamllint:unparsable-with-libyaml
+plugins/modules/cnos_user.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/cnos_user.py validate-modules:doc-elements-mismatch
+plugins/modules/cnos_user.py validate-modules:doc-missing-type
+plugins/modules/cnos_user.py validate-modules:missing-suboption-docs
+plugins/modules/cnos_user.py validate-modules:parameter-list-no-elements
+plugins/modules/cnos_user.py validate-modules:parameter-type-not-in-doc
+plugins/modules/cnos_user.py validate-modules:undocumented-parameter
+plugins/modules/cnos_vlag.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/cnos_vlag.py validate-modules:doc-missing-type
+plugins/modules/cnos_vlag.py validate-modules:doc-required-mismatch
+plugins/modules/cnos_vlag.py yamllint:unparsable-with-libyaml
+plugins/modules/cnos_vlan.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/cnos_vlan.py validate-modules:doc-elements-mismatch
+plugins/modules/cnos_vlan.py validate-modules:doc-missing-type
+plugins/modules/cnos_vlan.py validate-modules:doc-required-mismatch
+plugins/modules/cnos_vlan.py validate-modules:missing-suboption-docs
+plugins/modules/cnos_vlan.py validate-modules:parameter-list-no-elements
+plugins/modules/cnos_vlan.py validate-modules:parameter-type-not-in-doc
+plugins/modules/cnos_vlan.py validate-modules:undocumented-parameter
+plugins/modules/cnos_vrf.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/cnos_vrf.py validate-modules:doc-elements-mismatch
+plugins/modules/cnos_vrf.py validate-modules:doc-missing-type
+plugins/modules/cnos_vrf.py validate-modules:doc-required-mismatch
+plugins/modules/cnos_vrf.py validate-modules:missing-suboption-docs
+plugins/modules/cnos_vrf.py validate-modules:parameter-list-no-elements
+plugins/modules/cnos_vrf.py validate-modules:parameter-type-not-in-doc
+plugins/modules/cnos_vrf.py validate-modules:undocumented-parameter
+plugins/modules/nclu.py validate-modules:parameter-list-no-elements
+plugins/modules/nclu.py validate-modules:parameter-type-not-in-doc
+plugins/modules/edgeos_command.py validate-modules:doc-missing-type
+plugins/modules/edgeos_command.py validate-modules:parameter-list-no-elements
+plugins/modules/edgeos_command.py validate-modules:parameter-type-not-in-doc
+plugins/modules/edgeos_config.py validate-modules:doc-missing-type
+plugins/modules/edgeos_config.py validate-modules:parameter-type-not-in-doc
+plugins/modules/edgeos_facts.py validate-modules:parameter-list-no-elements
+plugins/modules/edgeos_facts.py validate-modules:parameter-type-not-in-doc
+plugins/modules/edgeswitch_facts.py validate-modules:parameter-list-no-elements
+plugins/modules/edgeswitch_facts.py validate-modules:parameter-type-not-in-doc
+plugins/modules/edgeswitch_vlan.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/edgeswitch_vlan.py validate-modules:doc-elements-mismatch
+plugins/modules/edgeswitch_vlan.py validate-modules:doc-missing-type
+plugins/modules/edgeswitch_vlan.py validate-modules:doc-required-mismatch
+plugins/modules/edgeswitch_vlan.py validate-modules:missing-suboption-docs
+plugins/modules/edgeswitch_vlan.py validate-modules:parameter-list-no-elements
+plugins/modules/edgeswitch_vlan.py validate-modules:parameter-type-not-in-doc
+plugins/modules/edgeswitch_vlan.py validate-modules:undocumented-parameter
+plugins/modules/enos_command.py validate-modules:doc-missing-type
+plugins/modules/enos_command.py validate-modules:nonexistent-parameter-documented
+plugins/modules/enos_command.py validate-modules:parameter-list-no-elements
+plugins/modules/enos_command.py validate-modules:parameter-type-not-in-doc
+plugins/modules/enos_config.py validate-modules:doc-missing-type
+plugins/modules/enos_config.py validate-modules:nonexistent-parameter-documented
+plugins/modules/enos_config.py validate-modules:parameter-list-no-elements
+plugins/modules/enos_config.py validate-modules:parameter-type-not-in-doc
+plugins/modules/enos_facts.py validate-modules:nonexistent-parameter-documented
+plugins/modules/enos_facts.py validate-modules:parameter-list-no-elements
+plugins/modules/enos_facts.py validate-modules:parameter-type-not-in-doc
+plugins/modules/enos_facts.py yamllint:unparsable-with-libyaml
+plugins/modules/eric_eccli_command.py validate-modules:parameter-list-no-elements
+plugins/modules/exos_command.py validate-modules:doc-missing-type
+plugins/modules/exos_command.py validate-modules:parameter-list-no-elements
+plugins/modules/exos_command.py validate-modules:parameter-type-not-in-doc
+plugins/modules/exos_config.py validate-modules:doc-missing-type
+plugins/modules/exos_config.py validate-modules:parameter-list-no-elements
+plugins/modules/exos_config.py validate-modules:parameter-type-not-in-doc
+plugins/modules/exos_facts.py validate-modules:parameter-list-no-elements
+plugins/modules/exos_l2_interfaces.py validate-modules:parameter-list-no-elements
+plugins/modules/icx_command.py validate-modules:parameter-list-no-elements
+plugins/modules/icx_config.py validate-modules:parameter-list-no-elements
+plugins/modules/icx_facts.py validate-modules:parameter-list-no-elements
+plugins/modules/icx_interface.py validate-modules:doc-required-mismatch
+plugins/modules/icx_l3_interface.py validate-modules:doc-required-mismatch
+plugins/modules/icx_linkagg.py validate-modules:doc-elements-mismatch
+plugins/modules/icx_linkagg.py validate-modules:doc-required-mismatch
+plugins/modules/icx_linkagg.py validate-modules:parameter-list-no-elements
+plugins/modules/icx_lldp.py validate-modules:doc-elements-mismatch
+plugins/modules/icx_lldp.py validate-modules:parameter-list-no-elements
+plugins/modules/icx_logging.py validate-modules:doc-elements-mismatch
+plugins/modules/icx_logging.py validate-modules:parameter-list-no-elements
+plugins/modules/icx_static_route.py validate-modules:doc-required-mismatch
+plugins/modules/icx_system.py validate-modules:doc-elements-mismatch
+plugins/modules/icx_system.py validate-modules:parameter-list-no-elements
+plugins/modules/icx_user.py validate-modules:doc-required-mismatch
+plugins/modules/icx_vlan.py validate-modules:doc-elements-mismatch
+plugins/modules/icx_vlan.py validate-modules:doc-required-mismatch
+plugins/modules/icx_vlan.py validate-modules:parameter-list-no-elements
+plugins/modules/dladm_etherstub.py validate-modules:doc-missing-type
+plugins/modules/dladm_iptun.py validate-modules:doc-missing-type
+plugins/modules/dladm_iptun.py validate-modules:parameter-type-not-in-doc
+plugins/modules/dladm_linkprop.py validate-modules:doc-missing-type
+plugins/modules/dladm_linkprop.py validate-modules:no-default-for-required-parameter
+plugins/modules/dladm_linkprop.py validate-modules:parameter-type-not-in-doc
+plugins/modules/dladm_vlan.py validate-modules:doc-default-does-not-match-spec
+plugins/modules/dladm_vlan.py validate-modules:doc-missing-type
+plugins/modules/dladm_vlan.py validate-modules:doc-required-mismatch
+plugins/modules/dladm_vlan.py validate-modules:parameter-type-not-in-doc
+plugins/modules/dladm_vnic.py validate-modules:doc-default-does-not-match-spec
+plugins/modules/flowadm.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/flowadm.py validate-modules:doc-missing-type
+plugins/modules/ipadm_addr.py validate-modules:doc-missing-type
+plugins/modules/ipadm_addr.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ipadm_addrprop.py validate-modules:doc-missing-type
+plugins/modules/ipadm_addrprop.py validate-modules:no-default-for-required-parameter
+plugins/modules/ipadm_if.py validate-modules:doc-missing-type
+plugins/modules/ipadm_ifprop.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/ipadm_ifprop.py validate-modules:doc-missing-type
+plugins/modules/ipadm_ifprop.py validate-modules:no-default-for-required-parameter
+plugins/modules/ipadm_prop.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/ipadm_prop.py validate-modules:doc-missing-type
+plugins/modules/ig_config.py validate-modules:doc-missing-type
+plugins/modules/ig_config.py validate-modules:doc-required-mismatch
+plugins/modules/ig_config.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ig_config.py validate-modules:return-syntax-error
+plugins/modules/ig_unit_information.py validate-modules:doc-required-mismatch
+plugins/modules/ig_unit_information.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ironware_command.py validate-modules:doc-missing-type
+plugins/modules/ironware_command.py validate-modules:nonexistent-parameter-documented
+plugins/modules/ironware_command.py validate-modules:parameter-list-no-elements
+plugins/modules/ironware_command.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ironware_config.py validate-modules:doc-missing-type
+plugins/modules/ironware_config.py validate-modules:nonexistent-parameter-documented
+plugins/modules/ironware_config.py validate-modules:parameter-list-no-elements
+plugins/modules/ironware_config.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ironware_facts.py validate-modules:nonexistent-parameter-documented
+plugins/modules/ironware_facts.py validate-modules:parameter-list-no-elements
+plugins/modules/ironware_facts.py validate-modules:parameter-type-not-in-doc
+plugins/modules/iap_start_workflow.py validate-modules:doc-required-mismatch
+plugins/modules/iap_token.py validate-modules:parameter-type-not-in-doc
+plugins/modules/netact_cm_command.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/netact_cm_command.py validate-modules:parameter-type-not-in-doc
+plugins/modules/netscaler_cs_action.py pylint:condition-evals-to-constant # Should be fixed
+plugins/modules/netscaler_cs_action.py validate-modules:nonexistent-parameter-documented
+plugins/modules/netscaler_cs_action.py validate-modules:parameter-type-not-in-doc
+plugins/modules/netscaler_cs_policy.py validate-modules:parameter-type-not-in-doc
+plugins/modules/netscaler_cs_vserver.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/netscaler_cs_vserver.py validate-modules:nonexistent-parameter-documented
+plugins/modules/netscaler_cs_vserver.py validate-modules:parameter-list-no-elements
+plugins/modules/netscaler_cs_vserver.py validate-modules:parameter-type-not-in-doc
+plugins/modules/netscaler_cs_vserver.py validate-modules:undocumented-parameter
+plugins/modules/netscaler_gslb_service.py validate-modules:parameter-list-no-elements
+plugins/modules/netscaler_gslb_service.py validate-modules:parameter-type-not-in-doc
+plugins/modules/netscaler_gslb_site.py validate-modules:parameter-type-not-in-doc
+plugins/modules/netscaler_gslb_vserver.py validate-modules:parameter-list-no-elements
+plugins/modules/netscaler_gslb_vserver.py validate-modules:parameter-type-not-in-doc
+plugins/modules/netscaler_gslb_vserver.py validate-modules:undocumented-parameter
+plugins/modules/netscaler_lb_monitor.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/netscaler_lb_monitor.py validate-modules:nonexistent-parameter-documented
+plugins/modules/netscaler_lb_monitor.py validate-modules:parameter-list-no-elements
+plugins/modules/netscaler_lb_monitor.py validate-modules:parameter-type-not-in-doc
+plugins/modules/netscaler_lb_vserver.py validate-modules:nonexistent-parameter-documented
+plugins/modules/netscaler_lb_vserver.py validate-modules:parameter-list-no-elements
+plugins/modules/netscaler_lb_vserver.py validate-modules:parameter-type-not-in-doc
+plugins/modules/netscaler_nitro_request.py pylint:ansible-bad-function
+plugins/modules/netscaler_nitro_request.py validate-modules:doc-missing-type
+plugins/modules/netscaler_nitro_request.py validate-modules:doc-required-mismatch
+plugins/modules/netscaler_nitro_request.py validate-modules:parameter-list-no-elements
+plugins/modules/netscaler_nitro_request.py validate-modules:parameter-type-not-in-doc
+plugins/modules/netscaler_save_config.py validate-modules:doc-missing-type
+plugins/modules/netscaler_save_config.py validate-modules:parameter-type-not-in-doc
+plugins/modules/netscaler_server.py validate-modules:doc-default-does-not-match-spec
+plugins/modules/netscaler_server.py validate-modules:parameter-type-not-in-doc
+plugins/modules/netscaler_service.py validate-modules:nonexistent-parameter-documented
+plugins/modules/netscaler_service.py validate-modules:parameter-list-no-elements
+plugins/modules/netscaler_service.py validate-modules:parameter-type-not-in-doc
+plugins/modules/netscaler_servicegroup.py validate-modules:parameter-list-no-elements
+plugins/modules/netscaler_servicegroup.py validate-modules:parameter-type-not-in-doc
+plugins/modules/netscaler_ssl_certkey.py validate-modules:parameter-type-not-in-doc
+plugins/modules/pn_access_list.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/pn_access_list.py validate-modules:parameter-type-not-in-doc
+plugins/modules/pn_access_list_ip.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/pn_access_list_ip.py validate-modules:parameter-type-not-in-doc
+plugins/modules/pn_admin_service.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/pn_admin_session_timeout.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/pn_admin_syslog.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/pn_connection_stats_settings.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/pn_cpu_class.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/pn_cpu_class.py validate-modules:parameter-type-not-in-doc
+plugins/modules/pn_cpu_mgmt_class.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/pn_dhcp_filter.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/pn_dscp_map.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/pn_dscp_map.py validate-modules:parameter-type-not-in-doc
+plugins/modules/pn_dscp_map_pri_map.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/pn_fabric_local.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/pn_fabric_local.py validate-modules:parameter-type-not-in-doc
+plugins/modules/pn_igmp_snooping.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/pn_igmp_snooping.py validate-modules:parameter-type-not-in-doc
+plugins/modules/pn_ipv6security_raguard.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/pn_ipv6security_raguard_port.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/pn_ipv6security_raguard_vlan.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/pn_log_audit_exception.py validate-modules:doc-required-mismatch
+plugins/modules/pn_log_audit_exception.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/pn_port_config.py validate-modules:parameter-type-not-in-doc
+plugins/modules/pn_port_config.py validate-modules:required_one_of-unknown
+plugins/modules/pn_port_cos_bw.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/pn_port_cos_rate_setting.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/pn_prefix_list.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/pn_prefix_list_network.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/pn_role.py validate-modules:doc-required-mismatch
+plugins/modules/pn_role.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/pn_snmp_community.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/pn_snmp_community.py validate-modules:parameter-type-not-in-doc
+plugins/modules/pn_snmp_trap_sink.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/pn_snmp_vacm.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/pn_stp.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/pn_stp_port.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/pn_switch_setup.py validate-modules:parameter-type-not-in-doc
+plugins/modules/pn_user.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/pn_vflow_table_profile.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/pn_vrouter_bgp.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/pn_vrouter_bgp.py validate-modules:parameter-type-not-in-doc
+plugins/modules/pn_vrouter_bgp_network.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/pn_vrouter_interface_ip.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/pn_vrouter_loopback_interface.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/pn_vrouter_ospf.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/pn_vrouter_ospf6.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/pn_vrouter_packet_relay.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/pn_vrouter_pim_config.py validate-modules:doc-required-mismatch
+plugins/modules/pn_vrouter_pim_config.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/pn_vtep.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/nos_command.py validate-modules:doc-missing-type
+plugins/modules/nos_command.py validate-modules:parameter-list-no-elements
+plugins/modules/nos_command.py validate-modules:parameter-type-not-in-doc
+plugins/modules/nos_config.py validate-modules:doc-missing-type
+plugins/modules/nos_config.py validate-modules:parameter-list-no-elements
+plugins/modules/nos_config.py validate-modules:parameter-type-not-in-doc
+plugins/modules/nos_facts.py validate-modules:parameter-list-no-elements
+plugins/modules/nos_facts.py validate-modules:parameter-type-not-in-doc
+plugins/modules/nuage_vspk.py validate-modules:doc-required-mismatch
+plugins/modules/nuage_vspk.py validate-modules:missing-suboption-docs
+plugins/modules/nuage_vspk.py validate-modules:parameter-list-no-elements
+plugins/modules/nuage_vspk.py validate-modules:parameter-type-not-in-doc
+plugins/modules/nuage_vspk.py validate-modules:undocumented-parameter
+plugins/modules/opx_cps.py validate-modules:doc-required-mismatch
+plugins/modules/opx_cps.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ordnance_config.py validate-modules:doc-default-does-not-match-spec
+plugins/modules/ordnance_config.py validate-modules:doc-missing-type
+plugins/modules/ordnance_config.py validate-modules:doc-required-mismatch
+plugins/modules/ordnance_config.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/ordnance_config.py validate-modules:parameter-list-no-elements
+plugins/modules/ordnance_config.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ordnance_config.py validate-modules:undocumented-parameter
+plugins/modules/ordnance_config.py yamllint:unparsable-with-libyaml
+plugins/modules/ordnance_facts.py validate-modules:doc-default-does-not-match-spec
+plugins/modules/ordnance_facts.py validate-modules:doc-missing-type
+plugins/modules/ordnance_facts.py validate-modules:doc-required-mismatch
+plugins/modules/ordnance_facts.py validate-modules:invalid-ansiblemodule-schema
+plugins/modules/ordnance_facts.py validate-modules:parameter-list-no-elements
+plugins/modules/ordnance_facts.py validate-modules:parameter-type-not-in-doc
+plugins/modules/ordnance_facts.py validate-modules:undocumented-parameter
+plugins/modules/ordnance_facts.py yamllint:unparsable-with-libyaml
+plugins/modules/vdirect_commit.py validate-modules:doc-missing-type
+plugins/modules/vdirect_commit.py validate-modules:parameter-list-no-elements
+plugins/modules/vdirect_commit.py validate-modules:parameter-type-not-in-doc
+plugins/modules/vdirect_file.py validate-modules:doc-missing-type
+plugins/modules/vdirect_file.py validate-modules:parameter-type-not-in-doc
+plugins/modules/vdirect_runnable.py validate-modules:doc-missing-type
+plugins/modules/vdirect_runnable.py validate-modules:parameter-type-not-in-doc
+plugins/modules/slxos_command.py validate-modules:doc-missing-type
+plugins/modules/slxos_command.py validate-modules:parameter-list-no-elements
+plugins/modules/slxos_command.py validate-modules:parameter-type-not-in-doc
+plugins/modules/slxos_config.py validate-modules:doc-missing-type
+plugins/modules/slxos_config.py validate-modules:parameter-list-no-elements
+plugins/modules/slxos_config.py validate-modules:parameter-type-not-in-doc
+plugins/modules/slxos_facts.py validate-modules:parameter-list-no-elements
+plugins/modules/slxos_facts.py validate-modules:parameter-type-not-in-doc
+plugins/modules/slxos_interface.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/slxos_interface.py validate-modules:doc-elements-mismatch
+plugins/modules/slxos_interface.py validate-modules:doc-missing-type
+plugins/modules/slxos_interface.py validate-modules:doc-required-mismatch
+plugins/modules/slxos_interface.py validate-modules:missing-suboption-docs
+plugins/modules/slxos_interface.py validate-modules:parameter-type-not-in-doc
+plugins/modules/slxos_interface.py validate-modules:undocumented-parameter
+plugins/modules/slxos_l2_interface.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/slxos_l2_interface.py validate-modules:doc-elements-mismatch
+plugins/modules/slxos_l2_interface.py validate-modules:doc-missing-type
+plugins/modules/slxos_l2_interface.py validate-modules:doc-required-mismatch
+plugins/modules/slxos_l2_interface.py validate-modules:missing-suboption-docs
+plugins/modules/slxos_l2_interface.py validate-modules:parameter-type-not-in-doc
+plugins/modules/slxos_l2_interface.py validate-modules:undocumented-parameter
+plugins/modules/slxos_l3_interface.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/slxos_l3_interface.py validate-modules:doc-elements-mismatch
+plugins/modules/slxos_l3_interface.py validate-modules:doc-missing-type
+plugins/modules/slxos_l3_interface.py validate-modules:doc-required-mismatch
+plugins/modules/slxos_l3_interface.py validate-modules:missing-suboption-docs
+plugins/modules/slxos_l3_interface.py validate-modules:parameter-type-not-in-doc
+plugins/modules/slxos_l3_interface.py validate-modules:undocumented-parameter
+plugins/modules/slxos_linkagg.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/slxos_linkagg.py validate-modules:doc-elements-mismatch
+plugins/modules/slxos_linkagg.py validate-modules:doc-missing-type
+plugins/modules/slxos_linkagg.py validate-modules:doc-required-mismatch
+plugins/modules/slxos_linkagg.py validate-modules:missing-suboption-docs
+plugins/modules/slxos_linkagg.py validate-modules:parameter-list-no-elements
+plugins/modules/slxos_linkagg.py validate-modules:parameter-type-not-in-doc
+plugins/modules/slxos_linkagg.py validate-modules:undocumented-parameter
+plugins/modules/slxos_lldp.py validate-modules:doc-missing-type
+plugins/modules/slxos_vlan.py validate-modules:doc-choices-do-not-match-spec
+plugins/modules/slxos_vlan.py validate-modules:doc-elements-mismatch
+plugins/modules/slxos_vlan.py validate-modules:doc-missing-type
+plugins/modules/slxos_vlan.py validate-modules:doc-required-mismatch
+plugins/modules/slxos_vlan.py validate-modules:missing-suboption-docs
+plugins/modules/slxos_vlan.py validate-modules:parameter-list-no-elements
+plugins/modules/slxos_vlan.py validate-modules:parameter-type-not-in-doc
+plugins/modules/slxos_vlan.py validate-modules:undocumented-parameter
+plugins/modules/sros_command.py validate-modules:collection-deprecated-version
+plugins/modules/sros_command.py validate-modules:doc-missing-type
+plugins/modules/sros_command.py validate-modules:parameter-list-no-elements
+plugins/modules/sros_command.py validate-modules:parameter-type-not-in-doc
+plugins/modules/sros_config.py validate-modules:collection-deprecated-version
+plugins/modules/sros_config.py validate-modules:doc-missing-type
+plugins/modules/sros_config.py validate-modules:nonexistent-parameter-documented
+plugins/modules/sros_config.py validate-modules:parameter-list-no-elements
+plugins/modules/sros_config.py validate-modules:parameter-type-not-in-doc
+plugins/modules/sros_rollback.py validate-modules:collection-deprecated-version
+plugins/modules/sros_rollback.py validate-modules:doc-missing-type
+plugins/modules/sros_rollback.py validate-modules:parameter-type-not-in-doc
+plugins/modules/voss_command.py validate-modules:doc-missing-type
+plugins/modules/voss_command.py validate-modules:parameter-list-no-elements
+plugins/modules/voss_command.py validate-modules:parameter-type-not-in-doc
+plugins/modules/voss_config.py validate-modules:doc-missing-type
+plugins/modules/voss_config.py validate-modules:parameter-list-no-elements
+plugins/modules/voss_config.py validate-modules:parameter-type-not-in-doc
+plugins/modules/voss_facts.py validate-modules:parameter-list-no-elements
+plugins/modules/voss_facts.py validate-modules:parameter-type-not-in-doc
+tests/unit/plugins/modules/test_edgeswitch_facts.py pylint:use-maxsplit-arg
+tests/unit/plugins/modules/test_edgeswitch_vlan.py pylint:use-maxsplit-arg
+tests/unit/plugins/modules/test_icx_ping.py pylint:use-maxsplit-arg
+tests/unit/plugins/modules/test_ironware_config.py pylint:arguments-renamed
+tests/unit/plugins/modules/test_ironware_facts.py pylint:use-maxsplit-arg
+tests/unit/plugins/modules/test_netscaler_cs_action.py pylint:invalid-class-object
+tests/unit/plugins/modules/test_netscaler_cs_vserver.py pylint:invalid-class-object
+tests/unit/plugins/modules/test_netscaler_lb_vserver.py pylint:invalid-class-object
+tests/unit/plugins/modules/test_netscaler_server.py pylint:invalid-class-object
+tests/unit/plugins/modules/test_netscaler_service.py pylint:invalid-class-object
+tests/unit/plugins/modules/test_netscaler_servicegroup.py pylint:invalid-class-object
+tests/unit/plugins/modules/test_netscaler_ssl_certkey.py pylint:invalid-class-object
+tests/unit/plugins/modules/test_nos_facts.py pylint:use-maxsplit-arg
+tests/unit/plugins/modules/test_slxos_facts.py pylint:use-maxsplit-arg
+tests/unit/plugins/modules/test_voss_facts.py pylint:use-maxsplit-arg
+plugins/action/aireos.py pylint:unused-import
+plugins/action/aruba.py pylint:unused-import
+plugins/action/ce.py pylint:unused-import
+plugins/action/cnos.py pylint:unused-import
+plugins/action/enos.py pylint:unused-import
+plugins/action/ironware.py pylint:unused-import
+plugins/action/sros.py pylint:unused-import
+plugins/cliconf/aireos.py pylint:unused-import
+plugins/cliconf/apconos.py pylint:unused-import
+plugins/cliconf/aruba.py pylint:unused-import
+plugins/cliconf/cnos.py pylint:unused-import
+plugins/cliconf/edgeswitch.py pylint:unused-import
+plugins/cliconf/eric_eccli.py pylint:unused-import
+plugins/cliconf/exos.py pylint:unused-import
+plugins/cliconf/icx.py pylint:unused-import
+plugins/cliconf/ironware.py pylint:unused-import
+plugins/cliconf/slxos.py pylint:unused-import
+plugins/cliconf/voss.py pylint:unused-import
+plugins/cliconf/weos4.py pylint:unused-import
+plugins/lookup/avi.py pylint:unused-import
+plugins/module_utils/network/aos/aos.py pylint:unused-import
+plugins/module_utils/network/avi/ansible_utils.py pylint:unused-import
+plugins/module_utils/network/avi/avi.py pylint:unused-import
+plugins/module_utils/network/cloudengine/ce.py pylint:unused-import
+plugins/module_utils/network/cnos/cnos.py pylint:unused-import
+plugins/module_utils/network/eric_eccli/eric_eccli.py pylint:unused-import
+plugins/module_utils/network/exos/config/lldp_interfaces/lldp_interfaces.py pylint:unused-import
+plugins/module_utils/network/exos/exos.py pylint:unused-import
+plugins/module_utils/network/exos/facts/facts.py pylint:unused-import
+plugins/module_utils/network/exos/facts/l2_interfaces/l2_interfaces.py pylint:unused-import
+plugins/module_utils/network/exos/facts/legacy/base.py pylint:unused-import
+plugins/module_utils/network/exos/facts/lldp_global/lldp_global.py pylint:unused-import
+plugins/module_utils/network/exos/facts/lldp_interfaces/lldp_interfaces.py pylint:unused-import
+plugins/module_utils/network/exos/facts/vlans/vlans.py pylint:unused-import
+plugins/module_utils/network/icx/icx.py pylint:unused-import
+plugins/module_utils/network/ironware/ironware.py pylint:unused-import
+plugins/module_utils/network/netscaler/netscaler.py pylint:unused-import
+plugins/module_utils/network/slxos/slxos.py pylint:unused-import
+plugins/module_utils/network/sros/sros.py pylint:unused-import
+plugins/module_utils/version.py pylint:unused-import
+plugins/modules/avi_api_version.py pylint:unused-import
+plugins/modules/avi_gslbservice_patch_member.py pylint:unused-import
+plugins/modules/avi_user.py pylint:unused-import
+plugins/modules/avi_useraccount.py pylint:unused-import
+plugins/modules/ce_acl_interface.py pylint:unused-import
+plugins/modules/ce_bfd_global.py pylint:unused-import
+plugins/modules/ce_bfd_session.py pylint:unused-import
+plugins/modules/ce_bfd_view.py pylint:unused-import
+plugins/modules/ce_config.py pylint:unused-import
+plugins/modules/ce_file_copy.py pylint:unused-import
+plugins/modules/ce_interface.py pylint:unused-import
+plugins/modules/ce_lldp.py pylint:unused-import
+plugins/modules/ce_lldp_interface.py pylint:unused-import
+plugins/modules/ce_mdn_interface.py pylint:unused-import
+plugins/modules/ce_rollback.py pylint:unused-import
+plugins/modules/ce_sflow.py pylint:unused-import
+plugins/modules/ce_switchport.py pylint:unused-import
+plugins/modules/cnos_backup.py pylint:unused-import
+plugins/modules/cnos_banner.py pylint:unused-import
+plugins/modules/cnos_bgp.py pylint:unused-import
+plugins/modules/cnos_command.py pylint:unused-import
+plugins/modules/cnos_conditional_command.py pylint:unused-import
+plugins/modules/cnos_conditional_template.py pylint:unused-import
+plugins/modules/cnos_factory.py pylint:unused-import
+plugins/modules/cnos_image.py pylint:unused-import
+plugins/modules/cnos_interface.py pylint:unused-import
+plugins/modules/cnos_l2_interface.py pylint:unused-import
+plugins/modules/cnos_lldp.py pylint:unused-import
+plugins/modules/cnos_logging.py pylint:unused-import
+plugins/modules/cnos_reload.py pylint:unused-import
+plugins/modules/cnos_rollback.py pylint:unused-import
+plugins/modules/cnos_save.py pylint:unused-import
+plugins/modules/cnos_showrun.py pylint:unused-import
+plugins/modules/cnos_static_route.py pylint:unused-import
+plugins/modules/cnos_system.py pylint:unused-import
+plugins/modules/cnos_template.py pylint:unused-import
+plugins/modules/cnos_user.py pylint:unused-import
+plugins/modules/cnos_vlag.py pylint:unused-import
+plugins/modules/cnos_vlan.py pylint:unused-import
+plugins/modules/cnos_vrf.py pylint:unused-import
+plugins/modules/enos_command.py pylint:unused-import
+plugins/modules/eric_eccli_command.py pylint:unused-import
+plugins/modules/icx_banner.py pylint:unused-import
+plugins/modules/icx_command.py pylint:unused-import
+plugins/modules/icx_config.py pylint:unused-import
+plugins/modules/icx_facts.py pylint:unused-import
+plugins/modules/icx_interface.py pylint:unused-import
+plugins/modules/icx_linkagg.py pylint:unused-import
+plugins/modules/icx_logging.py pylint:unused-import
+plugins/modules/icx_ping.py pylint:unused-import
+plugins/modules/icx_static_route.py pylint:unused-import
+plugins/modules/icx_system.py pylint:unused-import
+plugins/modules/icx_user.py pylint:unused-import
+plugins/modules/icx_vlan.py pylint:unused-import
+plugins/modules/ordnance_config.py pylint:unused-import
+plugins/modules/slxos_l3_interface.py pylint:unused-import
+plugins/modules/sros_rollback.py pylint:unused-import
+plugins/netconf/ce.py pylint:unused-import
+plugins/terminal/aireos.py pylint:unused-import
+plugins/terminal/apconos.py pylint:unused-import
+plugins/terminal/aruba.py pylint:unused-import
+plugins/terminal/eric_eccli.py pylint:unused-import
+plugins/terminal/netvisor.py pylint:unused-import
+plugins/terminal/weos4.py pylint:unused-import
+tests/sanity/extra/botmeta.py pylint:unused-import
+tests/unit/compat/builtins.py pylint:unused-import
+tests/unit/plugins/modules/test_apconos_command.py pylint:unused-import
+tests/unit/plugins/modules/test_icx_logging.py pylint:unused-import
+tests/unit/plugins/modules/test_icx_system.py pylint:unused-import
+tests/unit/plugins/modules/test_pn_log_audit_exception.py pylint:unused-import
+tests/unit/plugins/modules/test_pn_vtep.py pylint:unused-import
diff --git a/ansible_collections/community/network/tests/unit/mock/loader.py b/ansible_collections/community/network/tests/unit/mock/loader.py
index 00a584127..e5eb8b411 100644
--- a/ansible_collections/community/network/tests/unit/mock/loader.py
+++ b/ansible_collections/community/network/tests/unit/mock/loader.py
@@ -30,7 +30,7 @@ class DictDataLoader(DataLoader):
def __init__(self, file_mapping=None):
file_mapping = {} if file_mapping is None else file_mapping
- assert type(file_mapping) == dict
+ assert type(file_mapping) is dict
super(DictDataLoader, self).__init__()
diff --git a/ansible_collections/community/network/tests/unit/plugins/modules/cnos_fixtures/show_ip_interface_brief_vrf_all b/ansible_collections/community/network/tests/unit/plugins/modules/cnos_fixtures/show_ip_interface_brief_vrf_all
deleted file mode 100644
index 4f3a22a12..000000000
--- a/ansible_collections/community/network/tests/unit/plugins/modules/cnos_fixtures/show_ip_interface_brief_vrf_all
+++ /dev/null
@@ -1,10 +0,0 @@
-Interface IP-Address Admin-Status Link-Status VRF
-Ethernet1/5 20.131.1.1 up down default
-Ethernet1/6 20.131.2.1 up down default
-Ethernet1/7 20.141.1.1 up down default
-Ethernet1/8 20.141.2.1 up down default
-Ethernet1/11 1.1.1.2 up down default
-Ethernet1/12 100.10.10.10 up down default
-Ethernet1/13 10.241.107.54 up down default
-mgmt0 10.241.107.39 up up management
-
diff --git a/ansible_collections/community/network/tests/unit/plugins/modules/cnos_fixtures/show_run b/ansible_collections/community/network/tests/unit/plugins/modules/cnos_fixtures/show_run
deleted file mode 100644
index 4367c90fe..000000000
--- a/ansible_collections/community/network/tests/unit/plugins/modules/cnos_fixtures/show_run
+++ /dev/null
@@ -1,331 +0,0 @@
-!
-version "10.8.0.42"
-!
-hostname ip10-241-107-39
-!
-banner motd NMS India CNOS
-banner motd NMS India CNOS G8272
-!
-clock timezone EDT 0 0
-!
-logging console 7
-vrf context management
- ip route 0.0.0.0/0 10.241.107.1
-!
-!
-port-channel load-balance ethernet destination-mac
-port-channel load-balance ethernet source-interface
-feature telnet
-ip domain-name labs.lenovo.com vrf management
-ip domain-list labs.lenovo.com vrf management
-ip name-server 10.241.104.120 vrf management
-ip name-server 10.240.0.10 vrf management
-ip host ip10-241-107-39.labs.lenovo.com 10.241.107.39 vrf management
-ip host ip10-241-107-39 10.241.107.39 vrf management
-ip domain-name labs.lenovo.com vrf default
-ip domain-list labs.lenovo.com vrf default
-ip name-server 10.240.0.10 vrf default
-ip name-server 10.241.104.120 vrf default
-ip host ip10-241-107-39.labs.lenovo.com 10.241.107.39 vrf default
-ip host ip10-241-107-39 10.241.107.39 vrf default
-ntp server 173.230.154.254 prefer
-ntp server 97.127.86.33 prefer
-ntp server 129.250.35.250 prefer
-ntp server 174.136.103.130 prefer
-ntp server 69.10.161.7 prefer
-ntp server 96.226.123.196 prefer
-ntp server 104.238.179.130 prefer
-ntp server 108.61.73.244 prefer
-ntp server 208.75.89.4 prefer
-snmp-server community public group network-operator
-snmp-server community private group network-admin
-snmp-server contact Ralph
-username admin role network-admin password encrypted $6$bJoWyEu/$9pzSgFPAKGRm1stpTCEl3I39htbjxiFCfhqiHag1NQiKHv/IiLQ2lYW0V3p7p72SgSmVHp38em9P9R/EdePpk/
-logging server 10.241.107.231
-logging server 10.241.107.222
-feature restApi
-ovsdb pki ovsdb_mgmt vrf management
-ovsdb pki ovsdb_default vrf default
-lacp system-priority 32769
-vlag tier-id 313
-vlag priority 1313
-vlag isl port-channel 100
-vlag hlthchk keepalive-attempts 5
-vlag hlthchk peer-ip 1.2.3.4
-vlag auto-recovery 266
-vlag startup-delay 323
-vlag enable
-vlag instance 1 port-channel 1003
-vlag instance 1 enable
-vlag instance 2 port-channel 20
-vlag instance 2 enable
-vlag instance 12 port-channel 23
-vlag instance 33 port-channel 333
-vlag instance 33 enable
-spanning-tree mode mst
-telemetry heartbeat enabled interval 15
-!
-policy-map type control-plane copp-system-policy
- class type control-plane copp-s-pvst-bpdu
- police pps 500
- class type control-plane copp-s-ecp
- police pps 3000
- class type control-plane copp-s-igmp
- police pps 3000
-!
-vlan 1-2
- no flood ipv4
-!
-vlan 3
-!
-vlan 5
-!
-vlan 12
-!
-vlan 13
- name dave
-!
-vlan dot1q tag native egress-only
-!
-interface Ethernet1/1
- description Link 1 to LP21
- load-interval counter 2 33
- switchport access vlan 33
- storm-control broadcast level 12.50
- mtu 66
- channel-group 33 mode on
-!
-interface Ethernet1/2
- description Link 2 to LP21
- channel-group 1001 mode active
-!
-interface Ethernet1/3
- description Link 1 to LP22
- switchport mode trunk
- channel-group 1003 mode active
-!
-interface Ethernet1/4
- description Link 2 to LP22
- switchport mode trunk
- channel-group 1004 mode active
-!
-interface Ethernet1/5
- description Link 1 to LP23
- no switchport
- ip address 20.131.1.1/30
-!
-interface Ethernet1/6
- description Link 2 to LP23
- no switchport
- ip address 20.131.2.1/30
-!
-interface Ethernet1/7
- description Link 1 to LP24
- no switchport
- ip address 20.141.1.1/30
-!
-interface Ethernet1/8
- description Link 2 to LP24
- no switchport
- ip address 20.141.2.1/30
-!
-interface Ethernet1/9
-!
-interface Ethernet1/10
-!
-interface Ethernet1/11
- no switchport
- mtu 1402
- ip address 1.1.1.2/8
-!
-interface Ethernet1/12
- no switchport
- ip address 100.10.10.10/24
-!
-interface Ethernet1/13
- no switchport
- ip address 10.241.107.54/24
- vrrp 254
- address 10.241.107.55
- priority 254
- no shutdown
- ip arp timeout 1500
-!
-interface Ethernet1/14
-!
-interface Ethernet1/15
-!
-interface Ethernet1/16
-!
-interface Ethernet1/17
-!
-interface Ethernet1/18
-!
-interface Ethernet1/19
-!
-interface Ethernet1/20
-!
-interface Ethernet1/21
-!
-interface Ethernet1/22
-!
-interface Ethernet1/23
- channel-group 11 mode active
- lacp port-priority 32769
-!
-interface Ethernet1/24
-!
-interface Ethernet1/25
-!
-interface Ethernet1/26
-!
-interface Ethernet1/27
-!
-interface Ethernet1/28
-!
-interface Ethernet1/29
-!
-interface Ethernet1/30
-!
-interface Ethernet1/31
-!
-interface Ethernet1/32
-!
-interface Ethernet1/33
- description Hentammoo
- load-interval counter 2 33
- switchport access vlan 33
- storm-control broadcast level 12.50
- mtu 66
- microburst-detection enable threshold 25
- lldp tlv-select max-frame-size
- lacp port-priority 33
- spanning-tree mst 33-35 cost 33
- spanning-tree bpduguard enable
-!
-interface Ethernet1/34
-!
-interface Ethernet1/35
-!
-interface Ethernet1/36
-!
-interface Ethernet1/37
-!
-interface Ethernet1/38
-!
-interface Ethernet1/39
-!
-interface Ethernet1/40
-!
-interface Ethernet1/41
-!
-interface Ethernet1/42
-!
-interface Ethernet1/43
-!
-interface Ethernet1/44
-!
-interface Ethernet1/45
-!
-interface Ethernet1/46
-!
-interface Ethernet1/47
-!
-interface Ethernet1/48
-!
-interface Ethernet1/49
-!
-interface Ethernet1/50
-!
-interface Ethernet1/51
-!
-interface Ethernet1/52
-!
-interface Ethernet1/53
-!
-interface Ethernet1/54
-!
-interface loopback0
- no switchport
-!
-interface mgmt0
- no switchport
- vrf member management
- no ip address dhcp
- ip address 10.241.107.39/24
- no ipv6 address dhcp
-!
-interface Vlan1
- no switchport
-!
-interface port-channel1
-!
-interface port-channel2
-!
-interface port-channel11
- lacp min-links 2
-!
-interface port-channel13
- switchport mode trunk
-!
-interface port-channel17
- switchport mode trunk
-!
-interface port-channel20
-!
-interface port-channel33
- description Hentammoo
- load-interval counter 2 33
- switchport access vlan 33
- storm-control broadcast level 12.50
- mtu 66
- spanning-tree mst 33-35 cost 33
- spanning-tree bpduguard enable
-!
-interface port-channel100
- switchport mode trunk
-!
-interface port-channel1001
-!
-interface port-channel1002
-!
-interface port-channel1003
- switchport mode trunk
-!
-interface port-channel1004
- switchport mode trunk
-!
-router bgp 33
- router-id 1.2.3.4
- bestpath always-compare-med
- cluster-id 1.2.3.4
- confederation identifier 333
- enforce-first-as
- bgp as-local-count 33
- bestpath compare-confed-aspath
- maxas-limit 333
- graceful-restart-helper
- graceful-restart stalepath-time 333
- timers bgp 333 3333
- address-family ipv4 unicast
- synchronization
- network 0.0.0.0 backdoor
- dampening 13 233 333 15 33
- neighbor 10.241.107.40 remote-as 13
- bfd
- address-family ipv4 unicast
- next-hop-self
-!
-route-map anil permit 10
-!
-ip arp timeout 1000
-!
-line con 0
-line vty 0
- exec-timeout 90 0
-line vty 1 39
-!
-!
-!
-end
-
diff --git a/ansible_collections/community/network/tests/unit/plugins/modules/cnos_fixtures/show_running-config b/ansible_collections/community/network/tests/unit/plugins/modules/cnos_fixtures/show_running-config
deleted file mode 100644
index 4367c90fe..000000000
--- a/ansible_collections/community/network/tests/unit/plugins/modules/cnos_fixtures/show_running-config
+++ /dev/null
@@ -1,331 +0,0 @@
-!
-version "10.8.0.42"
-!
-hostname ip10-241-107-39
-!
-banner motd NMS India CNOS
-banner motd NMS India CNOS G8272
-!
-clock timezone EDT 0 0
-!
-logging console 7
-vrf context management
- ip route 0.0.0.0/0 10.241.107.1
-!
-!
-port-channel load-balance ethernet destination-mac
-port-channel load-balance ethernet source-interface
-feature telnet
-ip domain-name labs.lenovo.com vrf management
-ip domain-list labs.lenovo.com vrf management
-ip name-server 10.241.104.120 vrf management
-ip name-server 10.240.0.10 vrf management
-ip host ip10-241-107-39.labs.lenovo.com 10.241.107.39 vrf management
-ip host ip10-241-107-39 10.241.107.39 vrf management
-ip domain-name labs.lenovo.com vrf default
-ip domain-list labs.lenovo.com vrf default
-ip name-server 10.240.0.10 vrf default
-ip name-server 10.241.104.120 vrf default
-ip host ip10-241-107-39.labs.lenovo.com 10.241.107.39 vrf default
-ip host ip10-241-107-39 10.241.107.39 vrf default
-ntp server 173.230.154.254 prefer
-ntp server 97.127.86.33 prefer
-ntp server 129.250.35.250 prefer
-ntp server 174.136.103.130 prefer
-ntp server 69.10.161.7 prefer
-ntp server 96.226.123.196 prefer
-ntp server 104.238.179.130 prefer
-ntp server 108.61.73.244 prefer
-ntp server 208.75.89.4 prefer
-snmp-server community public group network-operator
-snmp-server community private group network-admin
-snmp-server contact Ralph
-username admin role network-admin password encrypted $6$bJoWyEu/$9pzSgFPAKGRm1stpTCEl3I39htbjxiFCfhqiHag1NQiKHv/IiLQ2lYW0V3p7p72SgSmVHp38em9P9R/EdePpk/
-logging server 10.241.107.231
-logging server 10.241.107.222
-feature restApi
-ovsdb pki ovsdb_mgmt vrf management
-ovsdb pki ovsdb_default vrf default
-lacp system-priority 32769
-vlag tier-id 313
-vlag priority 1313
-vlag isl port-channel 100
-vlag hlthchk keepalive-attempts 5
-vlag hlthchk peer-ip 1.2.3.4
-vlag auto-recovery 266
-vlag startup-delay 323
-vlag enable
-vlag instance 1 port-channel 1003
-vlag instance 1 enable
-vlag instance 2 port-channel 20
-vlag instance 2 enable
-vlag instance 12 port-channel 23
-vlag instance 33 port-channel 333
-vlag instance 33 enable
-spanning-tree mode mst
-telemetry heartbeat enabled interval 15
-!
-policy-map type control-plane copp-system-policy
- class type control-plane copp-s-pvst-bpdu
- police pps 500
- class type control-plane copp-s-ecp
- police pps 3000
- class type control-plane copp-s-igmp
- police pps 3000
-!
-vlan 1-2
- no flood ipv4
-!
-vlan 3
-!
-vlan 5
-!
-vlan 12
-!
-vlan 13
- name dave
-!
-vlan dot1q tag native egress-only
-!
-interface Ethernet1/1
- description Link 1 to LP21
- load-interval counter 2 33
- switchport access vlan 33
- storm-control broadcast level 12.50
- mtu 66
- channel-group 33 mode on
-!
-interface Ethernet1/2
- description Link 2 to LP21
- channel-group 1001 mode active
-!
-interface Ethernet1/3
- description Link 1 to LP22
- switchport mode trunk
- channel-group 1003 mode active
-!
-interface Ethernet1/4
- description Link 2 to LP22
- switchport mode trunk
- channel-group 1004 mode active
-!
-interface Ethernet1/5
- description Link 1 to LP23
- no switchport
- ip address 20.131.1.1/30
-!
-interface Ethernet1/6
- description Link 2 to LP23
- no switchport
- ip address 20.131.2.1/30
-!
-interface Ethernet1/7
- description Link 1 to LP24
- no switchport
- ip address 20.141.1.1/30
-!
-interface Ethernet1/8
- description Link 2 to LP24
- no switchport
- ip address 20.141.2.1/30
-!
-interface Ethernet1/9
-!
-interface Ethernet1/10
-!
-interface Ethernet1/11
- no switchport
- mtu 1402
- ip address 1.1.1.2/8
-!
-interface Ethernet1/12
- no switchport
- ip address 100.10.10.10/24
-!
-interface Ethernet1/13
- no switchport
- ip address 10.241.107.54/24
- vrrp 254
- address 10.241.107.55
- priority 254
- no shutdown
- ip arp timeout 1500
-!
-interface Ethernet1/14
-!
-interface Ethernet1/15
-!
-interface Ethernet1/16
-!
-interface Ethernet1/17
-!
-interface Ethernet1/18
-!
-interface Ethernet1/19
-!
-interface Ethernet1/20
-!
-interface Ethernet1/21
-!
-interface Ethernet1/22
-!
-interface Ethernet1/23
- channel-group 11 mode active
- lacp port-priority 32769
-!
-interface Ethernet1/24
-!
-interface Ethernet1/25
-!
-interface Ethernet1/26
-!
-interface Ethernet1/27
-!
-interface Ethernet1/28
-!
-interface Ethernet1/29
-!
-interface Ethernet1/30
-!
-interface Ethernet1/31
-!
-interface Ethernet1/32
-!
-interface Ethernet1/33
- description Hentammoo
- load-interval counter 2 33
- switchport access vlan 33
- storm-control broadcast level 12.50
- mtu 66
- microburst-detection enable threshold 25
- lldp tlv-select max-frame-size
- lacp port-priority 33
- spanning-tree mst 33-35 cost 33
- spanning-tree bpduguard enable
-!
-interface Ethernet1/34
-!
-interface Ethernet1/35
-!
-interface Ethernet1/36
-!
-interface Ethernet1/37
-!
-interface Ethernet1/38
-!
-interface Ethernet1/39
-!
-interface Ethernet1/40
-!
-interface Ethernet1/41
-!
-interface Ethernet1/42
-!
-interface Ethernet1/43
-!
-interface Ethernet1/44
-!
-interface Ethernet1/45
-!
-interface Ethernet1/46
-!
-interface Ethernet1/47
-!
-interface Ethernet1/48
-!
-interface Ethernet1/49
-!
-interface Ethernet1/50
-!
-interface Ethernet1/51
-!
-interface Ethernet1/52
-!
-interface Ethernet1/53
-!
-interface Ethernet1/54
-!
-interface loopback0
- no switchport
-!
-interface mgmt0
- no switchport
- vrf member management
- no ip address dhcp
- ip address 10.241.107.39/24
- no ipv6 address dhcp
-!
-interface Vlan1
- no switchport
-!
-interface port-channel1
-!
-interface port-channel2
-!
-interface port-channel11
- lacp min-links 2
-!
-interface port-channel13
- switchport mode trunk
-!
-interface port-channel17
- switchport mode trunk
-!
-interface port-channel20
-!
-interface port-channel33
- description Hentammoo
- load-interval counter 2 33
- switchport access vlan 33
- storm-control broadcast level 12.50
- mtu 66
- spanning-tree mst 33-35 cost 33
- spanning-tree bpduguard enable
-!
-interface port-channel100
- switchport mode trunk
-!
-interface port-channel1001
-!
-interface port-channel1002
-!
-interface port-channel1003
- switchport mode trunk
-!
-interface port-channel1004
- switchport mode trunk
-!
-router bgp 33
- router-id 1.2.3.4
- bestpath always-compare-med
- cluster-id 1.2.3.4
- confederation identifier 333
- enforce-first-as
- bgp as-local-count 33
- bestpath compare-confed-aspath
- maxas-limit 333
- graceful-restart-helper
- graceful-restart stalepath-time 333
- timers bgp 333 3333
- address-family ipv4 unicast
- synchronization
- network 0.0.0.0 backdoor
- dampening 13 233 333 15 33
- neighbor 10.241.107.40 remote-as 13
- bfd
- address-family ipv4 unicast
- next-hop-self
-!
-route-map anil permit 10
-!
-ip arp timeout 1000
-!
-line con 0
-line vty 0
- exec-timeout 90 0
-line vty 1 39
-!
-!
-!
-end
-
diff --git a/ansible_collections/community/network/tests/unit/plugins/modules/exos_fixtures/show_port_config b/ansible_collections/community/network/tests/unit/plugins/modules/exos_fixtures/show_port_config_no-refresh
index 271924f09..271924f09 100644
--- a/ansible_collections/community/network/tests/unit/plugins/modules/exos_fixtures/show_port_config
+++ b/ansible_collections/community/network/tests/unit/plugins/modules/exos_fixtures/show_port_config_no-refresh
diff --git a/ansible_collections/community/network/tests/unit/plugins/modules/test_avi_user.py b/ansible_collections/community/network/tests/unit/plugins/modules/test_avi_user.py
deleted file mode 100644
index d9463a346..000000000
--- a/ansible_collections/community/network/tests/unit/plugins/modules/test_avi_user.py
+++ /dev/null
@@ -1,104 +0,0 @@
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-import os
-import json
-from ansible_collections.community.network.tests.unit.compat import unittest
-from ansible_collections.community.network.tests.unit.compat.mock import Mock
-from ansible_collections.community.network.tests.unit.plugins.modules.utils import set_module_args
-from ansible_collections.community.network.plugins.modules import avi_user
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'avi_fixtures')
-with open(fixture_path + '/avi_user.json') as json_file:
- data = json.load(json_file)
-
-
-class TestAviUser(unittest.TestCase):
-
- def test_create_user(self):
- set_module_args({
- "avi_credentials": {
- "controller": "192.0.2.13",
- "username": "username",
- "password": "fakepassword",
- "api_version": "18.2.5"
- },
- "state": "present",
- "name": "testuser",
- "obj_username": "testuser",
- "obj_password": "test123",
- "email": "test@abc.com",
- "access": [
- {
- "role_ref": "/api/role?name=Tenant-Admin",
- "tenant_ref": "/api/tenant?name=Test-Admin",
- "all_tenants": False
- }
- ],
- "user_profile_ref": "/api/useraccountprofile?name=Default-User-Account-Profile",
- "is_active": True,
- "is_superuser": True,
- "default_tenant_ref": "/api/tenant?name=admin"
- })
- avi_user.avi_ansible_api = Mock(return_value=data['mock_create_res'])
- response = avi_user.main()
- assert response['changed']
-
- def test_put_on_user(self):
- set_module_args({
- "avi_credentials": {
- "controller": "192.0.2.13",
- "username": "username",
- "password": "fakepassword",
- "api_version": "18.2.5"
- },
- "state": "present",
- "avi_api_update_method": "put",
- "name": "testuser",
- "obj_username": "testuser",
- "obj_password": "test123",
- "email": "newemail@abc.com",
- "access": [{
- "role_ref": "/api/role?name=Tenant-Admin",
- "tenant_ref": "/api/tenant?name=Test-Admin",
- "all_tenants": False
- }],
- "user_profile_ref": "/api/useraccountprofile?name=Default-User-Account-Profile",
- "is_active": True,
- "is_superuser": True,
- "default_tenant_ref": "/api/tenant?name=admin"
- })
- avi_user.avi_ansible_api = Mock(return_value=data['mock_put_res'])
- response = avi_user.main()
- assert response['changed']
- assert response['obj']
- assert response['old_obj']
-
- def test_delete_user(self):
- set_module_args({
- "avi_credentials": {
- "controller": "192.0.2.13",
- "username": "username",
- "password": "fakepassword",
- "api_version": "18.2.5"
-
- },
- "name": "testuser",
- "obj_username": "testuser",
- "obj_password": "test123",
- "email": "test@abc.com",
- "access": [{
- "role_ref": "/api/role?name=Tenant-Admin",
- "tenant_ref": "/api/tenant?name=Test-Admin",
- "all_tenants": False
- }],
- "user_profile_ref": "/api/useraccountprofile?name=Default-User-Account-Profile",
- "is_active": True,
- "is_superuser": True,
- "default_tenant_ref": "/api/tenant?name=admin"
- })
- avi_user.avi_ansible_api = Mock(return_value=data['mock_del_res'])
- response = avi_user.main()
- assert response['changed']
- assert not response['obj']
- assert response['old_obj']
diff --git a/ansible_collections/community/network/tests/unit/plugins/modules/test_cnos_command.py b/ansible_collections/community/network/tests/unit/plugins/modules/test_cnos_command.py
deleted file mode 100644
index 6b7563efc..000000000
--- a/ansible_collections/community/network/tests/unit/plugins/modules/test_cnos_command.py
+++ /dev/null
@@ -1,104 +0,0 @@
-# Copyright (C) 2017 Lenovo, Inc.
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-from ansible_collections.community.network.tests.unit.compat.mock import patch
-from ansible_collections.community.network.plugins.modules import cnos_command
-from ansible_collections.community.network.tests.unit.plugins.modules.utils import set_module_args
-from .cnos_module import TestCnosModule, load_fixture
-
-
-class TestCnosCommandModule(TestCnosModule):
-
- module = cnos_command
-
- def setUp(self):
- super(TestCnosCommandModule, self).setUp()
- self.mock_run_commands = patch('ansible_collections.community.network.plugins.modules.cnos_command.run_commands')
- self.run_commands = self.mock_run_commands.start()
-
- def tearDown(self):
- super(TestCnosCommandModule, self).tearDown()
- self.mock_run_commands.stop()
-
- def load_fixtures(self, commands=None):
-
- def load_from_file(*args, **kwargs):
- module, commands = args
- output = list()
-
- for item in commands:
- try:
- command = item
- except ValueError:
- command = 'show version'
- filename = str(command).replace(' ', '_')
- output.append(load_fixture(filename))
- return output
-
- self.run_commands.side_effect = load_from_file
-
- def test_cnos_command_simple(self):
- set_module_args(dict(commands=['show version']))
- result = self.execute_module()
- self.assertEqual(len(result['stdout']), 1)
- self.assertTrue(result['stdout'][0].startswith('Lenovo Networking Operating System (NOS) Software'))
-
- def test_cnos_command_multiple(self):
- set_module_args(dict(commands=['show version', 'show running-config']))
- result = self.execute_module()
- self.assertEqual(len(result['stdout']), 2)
- self.assertTrue(result['stdout'][0].startswith('Lenovo Networking Operating System (NOS) Software'))
-
- def test_cnos_command_wait_for(self):
- wait_for = 'result[0] contains "Lenovo Networking Operating System (NOS) Software"'
- set_module_args(dict(commands=['show version'], wait_for=wait_for))
- self.execute_module()
-
- def test_cnos_command_wait_for_fails(self):
- wait_for = 'result[0] contains "test string"'
- set_module_args(dict(commands=['show version'], wait_for=wait_for))
- self.execute_module(failed=True)
- self.assertEqual(self.run_commands.call_count, 10)
-
- def test_cnos_command_retries(self):
- wait_for = 'result[0] contains "test string"'
- set_module_args(dict(commands=['show version'], wait_for=wait_for, retries=2))
- self.execute_module(failed=True)
- self.assertEqual(self.run_commands.call_count, 2)
-
- def test_cnos_command_match_any(self):
- wait_for = ['result[0] contains "Lenovo Networking Operating System (NOS) Software"',
- 'result[0] contains "test string"']
- set_module_args(dict(commands=['show version'], wait_for=wait_for, match='any'))
- self.execute_module()
-
- def test_cnos_command_match_all(self):
- wait_for = ['result[0] contains "Lenovo Networking Operating System (NOS) Software"',
- 'result[0] contains "Lenovo"']
- set_module_args(dict(commands=['show version'], wait_for=wait_for, match='all'))
- self.execute_module()
-
- def test_cnos_command_match_all_failure(self):
- wait_for = ['result[0] contains "Lenovo ENOS"',
- 'result[0] contains "test string"']
- commands = ['show version', 'show run']
- set_module_args(dict(commands=commands, wait_for=wait_for, match='all'))
- self.execute_module(failed=True)
diff --git a/ansible_collections/community/network/tests/unit/plugins/modules/test_cnos_facts.py b/ansible_collections/community/network/tests/unit/plugins/modules/test_cnos_facts.py
deleted file mode 100644
index c55281896..000000000
--- a/ansible_collections/community/network/tests/unit/plugins/modules/test_cnos_facts.py
+++ /dev/null
@@ -1,82 +0,0 @@
-# (c) 2016 Red Hat Inc.
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import json
-
-from ansible_collections.community.network.tests.unit.compat.mock import patch
-from .cnos_module import TestCnosModule, load_fixture
-from ansible_collections.community.network.plugins.modules import cnos_facts
-from ansible_collections.community.network.tests.unit.plugins.modules.utils import set_module_args
-
-
-class TestCnosFacts(TestCnosModule):
-
- module = cnos_facts
-
- def setUp(self):
- super(TestCnosFacts, self).setUp()
- self.mock_run_commands = patch(
- 'ansible_collections.community.network.plugins.modules.cnos_facts.run_commands')
- self.run_commands = self.mock_run_commands.start()
-
- def tearDown(self):
- super(TestCnosFacts, self).tearDown()
- self.mock_run_commands.stop()
-
- def load_fixtures(self, commands=None):
-
- def load_from_file(*args, **kwargs):
- module, commands = args
- output = list()
-
- for item in commands:
- try:
- obj = json.loads(item)
- command = obj['command']
- except ValueError:
- command = item
- filename = str(command).replace(' ', '_')
- filename = filename.replace('/', '7')
- output.append(load_fixture(filename))
- return output
-
- self.run_commands.side_effect = load_from_file
-
- def test_cnos_facts_gather_subset_default(self):
- set_module_args(dict())
- result = self.execute_module()
- ansible_facts = result['ansible_facts']
- self.assertIn('hardware', ansible_facts['ansible_net_gather_subset'])
- self.assertIn('default', ansible_facts['ansible_net_gather_subset'])
- self.assertIn('interfaces', ansible_facts['ansible_net_gather_subset'])
- self.assertEqual('ip10-241-107-39', ansible_facts['ansible_net_hostname'])
- self.assertIn('Ethernet1/1', ansible_facts['ansible_net_interfaces'].keys())
- self.assertEqual(3985.8046875, ansible_facts['ansible_net_memtotal_mb'])
- self.assertEqual(3070.40234375, ansible_facts['ansible_net_memfree_mb'])
-
- def test_cnos_facts_gather_subset_config(self):
- set_module_args({'gather_subset': 'config'})
- result = self.execute_module()
- ansible_facts = result['ansible_facts']
- self.assertIn('default', ansible_facts['ansible_net_gather_subset'])
- self.assertIn('config', ansible_facts['ansible_net_gather_subset'])
- self.assertEqual('ip10-241-107-39', ansible_facts['ansible_net_hostname'])
- self.assertIn('ansible_net_config', ansible_facts)
diff --git a/ansible_collections/community/network/tests/unit/plugins/modules/test_cnos_static_route.py b/ansible_collections/community/network/tests/unit/plugins/modules/test_cnos_static_route.py
deleted file mode 100644
index e0efd2bd7..000000000
--- a/ansible_collections/community/network/tests/unit/plugins/modules/test_cnos_static_route.py
+++ /dev/null
@@ -1,74 +0,0 @@
-# (c) 2016 Red Hat Inc.
-# Copyright (C) 2017 Lenovo.
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-from ansible_collections.community.network.tests.unit.compat.mock import patch
-from ansible_collections.community.network.plugins.modules import cnos_static_route
-from .cnos_module import TestCnosModule, load_fixture
-from ansible_collections.community.network.tests.unit.plugins.modules.utils import set_module_args
-
-
-class TestCnosStaticRouteModule(TestCnosModule):
-
- module = cnos_static_route
-
- def setUp(self):
- super(TestCnosStaticRouteModule, self).setUp()
-
- self.mock_exec_command = patch('ansible_collections.community.network.plugins.modules.cnos_banner.exec_command')
- self.exec_command = self.mock_exec_command.start()
-
- self.mock_load_config = patch('ansible_collections.community.network.plugins.modules.cnos_static_route.load_config')
- self.load_config = self.mock_load_config.start()
-
- self.mock_get_config = patch('ansible_collections.community.network.plugins.modules.cnos_static_route.get_config')
- self.get_config = self.mock_get_config.start()
-
- def tearDown(self):
- super(TestCnosStaticRouteModule, self).tearDown()
- self.mock_exec_command.stop()
- self.mock_load_config.stop()
- self.mock_get_config.stop()
-
- def load_fixtures(self, commands=None):
- self.exec_command.return_value = (0, load_fixture('cnos_static_route.cfg').strip(), None)
- self.load_config.return_value = dict(diff=None, session='session')
-
- def test_cnos_static_route_present(self):
- set_module_args(dict(prefix='10.241.107.20', mask='255.255.255.0', next_hop='10.241.106.1'))
- self.execute_module(changed=True, commands=['ip route 10.241.107.20 255.255.255.0 10.241.106.1 1'])
-
- def test_cnos_static_route_present_no_defaults(self):
- set_module_args(dict(prefix='10.241.106.4', mask='255.255.255.0', next_hop='1.2.3.5',
- description='testing', admin_distance=100))
- self.execute_module(changed=True,
- commands=['ip route 10.241.106.4 255.255.255.0 1.2.3.5 100 description testing'])
-
- def test_cnos_static_route_change(self):
- set_module_args(dict(prefix='10.10.30.64', mask='255.255.255.0', next_hop='1.2.4.8'))
- self.execute_module(changed=True,
- commands=['ip route 10.10.30.64 255.255.255.0 1.2.4.8 1'])
-
- def test_cnos_static_route_absent(self):
- set_module_args(dict(prefix='10.10.30.12',
- mask='255.255.255.0', next_hop='1.2.4.8', state='absent'))
- self.execute_module(changed=True,
- commands=['no ip route 10.10.30.12 255.255.255.0 1.2.4.8 1'])
diff --git a/ansible_collections/community/network/tests/unit/plugins/modules/test_cv_server_provision.py b/ansible_collections/community/network/tests/unit/plugins/modules/test_cv_server_provision.py
deleted file mode 100644
index 8a92b0dec..000000000
--- a/ansible_collections/community/network/tests/unit/plugins/modules/test_cv_server_provision.py
+++ /dev/null
@@ -1,889 +0,0 @@
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-from ansible_collections.community.network.tests.unit.compat import unittest
-from ansible_collections.community.network.tests.unit.compat.mock import patch, Mock
-import sys
-sys.modules['cvprac'] = Mock()
-sys.modules['cvprac.cvp_client'] = Mock()
-sys.modules['cvprac.cvp_client_errors'] = Mock()
-from ansible_collections.community.network.plugins.modules import cv_server_provision
-
-
-class MockException(Exception):
- pass
-
-
-class TestCvServerProvision(unittest.TestCase):
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.CvpApiError',
- new_callable=lambda: MockException)
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.server_configurable_configlet')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.switch_in_compliance')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.switch_info')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.connect')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.AnsibleModule')
- def test_main_module_args(self, mock_module, mock_connect, mock_info,
- mock_comp, mock_server_conf, mock_exception):
- ''' Test main module args.
- '''
- mock_module_object = Mock()
- mock_module_object.params = dict(action='show', switch_name='eos')
- mock_module_object.fail_json.side_effect = SystemExit('Exiting')
- mock_module.return_value = mock_module_object
- mock_connect.return_value = 'Client'
- mock_info.side_effect = mock_exception('Error Getting Info')
- argument_spec = dict(
- host=dict(required=True),
- port=dict(required=False, default=None),
- protocol=dict(default='https', choices=['http', 'https']),
- username=dict(required=True),
- password=dict(required=True, no_log=True),
- server_name=dict(required=True),
- switch_name=dict(required=True),
- switch_port=dict(required=True),
- port_vlan=dict(required=False, default=None),
- template=dict(require=True),
- action=dict(default='show', choices=['show', 'add', 'remove']),
- auto_run=dict(type='bool', default=False),
- )
- self.assertRaises(SystemExit, cv_server_provision.main)
- mock_module.assert_called_with(argument_spec=argument_spec,
- supports_check_mode=False)
- self.assertEqual(mock_connect.call_count, 1)
- self.assertEqual(mock_info.call_count, 1)
- mock_comp.assert_not_called()
- mock_server_conf.assert_not_called()
- mock_module_object.fail_json.assert_called_with(msg='Error Getting Info')
-
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.CvpApiError',
- new_callable=lambda: MockException)
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.server_configurable_configlet')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.switch_in_compliance')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.switch_info')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.connect')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.AnsibleModule')
- def test_main_no_switch_configlet(self, mock_module, mock_connect,
- mock_info, mock_comp, mock_server_conf,
- mock_exception):
- ''' Test main fails if switch has no configlet for Ansible to edit.
- '''
- mock_module_object = Mock()
- mock_module_object.params = dict(action='add', switch_name='eos')
- mock_module_object.fail_json.side_effect = SystemExit('Exiting')
- mock_module.return_value = mock_module_object
- mock_connect.return_value = 'Client'
- mock_info.return_value = 'Info'
- mock_server_conf.return_value = None
- self.assertRaises(SystemExit, cv_server_provision.main)
- self.assertEqual(mock_connect.call_count, 1)
- self.assertEqual(mock_info.call_count, 1)
- self.assertEqual(mock_comp.call_count, 1)
- self.assertEqual(mock_server_conf.call_count, 1)
- mock_module_object.fail_json.assert_called_with(
- msg='Switch eos has no configurable server ports.')
-
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.CvpApiError',
- new_callable=lambda: MockException)
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.port_configurable')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.server_configurable_configlet')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.switch_in_compliance')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.switch_info')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.connect')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.AnsibleModule')
- def test_main_port_not_in_config(self, mock_module, mock_connect, mock_info,
- mock_comp, mock_server_conf,
- mock_port_conf, mock_exception):
- ''' Test main fails if user specified port not in configlet.
- '''
- mock_module_object = Mock()
- mock_module_object.params = dict(action='add', switch_name='eos',
- switch_port='3')
- mock_module_object.fail_json.side_effect = SystemExit('Exiting')
- mock_module.return_value = mock_module_object
- mock_connect.return_value = 'Client'
- mock_info.return_value = 'Info'
- mock_server_conf.return_value = 'Configlet'
- mock_port_conf.return_value = None
- self.assertRaises(SystemExit, cv_server_provision.main)
- self.assertEqual(mock_connect.call_count, 1)
- self.assertEqual(mock_info.call_count, 1)
- self.assertEqual(mock_comp.call_count, 1)
- self.assertEqual(mock_server_conf.call_count, 1)
- self.assertEqual(mock_port_conf.call_count, 1)
- mock_module_object.fail_json.assert_called_with(
- msg='Port 3 is not configurable as a server port on switch eos.')
-
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.configlet_action')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.port_configurable')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.server_configurable_configlet')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.switch_in_compliance')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.switch_info')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.connect')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.AnsibleModule')
- def test_main_show(self, mock_module, mock_connect, mock_info, mock_comp,
- mock_server_conf, mock_port_conf, mock_conf_action):
- ''' Test main good with show action.
- '''
- mock_module_object = Mock()
- mock_module_object.params = dict(action='show', switch_name='eos',
- switch_port='3', auto_run=False)
- mock_module.return_value = mock_module_object
- mock_connect.return_value = 'Client'
- mock_info.return_value = 'Info'
- mock_server_conf.return_value = 'Configlet'
- mock_port_conf.return_value = 'Port'
- mock_conf_action.return_value = dict()
- cv_server_provision.main()
- self.assertEqual(mock_connect.call_count, 1)
- self.assertEqual(mock_info.call_count, 1)
- mock_comp.assert_not_called()
- self.assertEqual(mock_server_conf.call_count, 1)
- self.assertEqual(mock_port_conf.call_count, 1)
- self.assertEqual(mock_conf_action.call_count, 1)
- mock_module_object.fail_json.assert_not_called()
- return_dict = dict(changed=False, switchInfo='Info',
- switchConfigurable=True, portConfigurable=True,
- taskCreated=False, taskExecuted=False,
- taskCompleted=False)
- mock_module_object.exit_json.assert_called_with(**return_dict)
-
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.configlet_action')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.port_configurable')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.server_configurable_configlet')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.switch_in_compliance')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.switch_info')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.connect')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.AnsibleModule')
- def test_main_add_no_auto_run(self, mock_module, mock_connect, mock_info,
- mock_comp, mock_server_conf, mock_port_conf,
- mock_conf_action):
- ''' Test main good with add action and no auto_run.
- '''
- mock_module_object = Mock()
- mock_module_object.params = dict(action='add', switch_name='eos',
- switch_port='3', auto_run=False)
- mock_module.return_value = mock_module_object
- mock_connect.return_value = 'Client'
- mock_info.return_value = 'Info'
- mock_server_conf.return_value = 'Configlet'
- mock_port_conf.return_value = 'Port'
- mock_conf_action.return_value = dict(taskCreated=True)
- cv_server_provision.main()
- self.assertEqual(mock_connect.call_count, 1)
- self.assertEqual(mock_info.call_count, 1)
- self.assertEqual(mock_comp.call_count, 1)
- self.assertEqual(mock_server_conf.call_count, 1)
- self.assertEqual(mock_port_conf.call_count, 1)
- self.assertEqual(mock_conf_action.call_count, 1)
- mock_module_object.fail_json.assert_not_called()
- return_dict = dict(changed=False, switchInfo='Info',
- switchConfigurable=True, portConfigurable=True,
- taskCreated=True, taskExecuted=False,
- taskCompleted=False)
- mock_module_object.exit_json.assert_called_with(**return_dict)
-
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.wait_for_task_completion')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.configlet_update_task')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.configlet_action')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.port_configurable')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.server_configurable_configlet')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.switch_in_compliance')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.switch_info')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.connect')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.AnsibleModule')
- def test_main_add_auto_run(self, mock_module, mock_connect, mock_info,
- mock_comp, mock_server_conf, mock_port_conf,
- mock_conf_action, mock_conf_task, mock_wait):
- ''' Test main good with add and auto_run. Config updated, task created.
- '''
- mock_module_object = Mock()
- mock_module_object.params = dict(action='add', switch_name='eos',
- switch_port='3', auto_run=True)
- mock_module.return_value = mock_module_object
- mock_client_object = Mock()
- mock_connect.return_value = mock_client_object
- mock_info.return_value = 'Info'
- mock_server_conf.return_value = 'Configlet'
- mock_port_conf.return_value = 'Port'
- mock_conf_action.return_value = dict(taskCreated=True, changed=True)
- mock_conf_task.return_value = '7'
- mock_wait.return_value = True
- cv_server_provision.main()
- self.assertEqual(mock_connect.call_count, 1)
- self.assertEqual(mock_info.call_count, 1)
- self.assertEqual(mock_comp.call_count, 1)
- self.assertEqual(mock_server_conf.call_count, 1)
- self.assertEqual(mock_port_conf.call_count, 1)
- self.assertEqual(mock_conf_action.call_count, 1)
- self.assertEqual(mock_conf_task.call_count, 1)
- self.assertEqual(mock_wait.call_count, 1)
- mock_module_object.fail_json.assert_not_called()
- return_dict = dict(changed=True, switchInfo='Info', taskId='7',
- switchConfigurable=True, portConfigurable=True,
- taskCreated=True, taskExecuted=True,
- taskCompleted=True)
- mock_module_object.exit_json.assert_called_with(**return_dict)
-
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.wait_for_task_completion')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.configlet_update_task')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.configlet_action')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.port_configurable')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.server_configurable_configlet')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.switch_in_compliance')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.switch_info')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.connect')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.AnsibleModule')
- def test_main_add_auto_run_no_task(self, mock_module, mock_connect,
- mock_info, mock_comp, mock_server_conf,
- mock_port_conf, mock_conf_action, mock_conf_task,
- mock_wait):
- ''' Test main good with add and auto_run. Config not updated, no task.
- '''
- mock_module_object = Mock()
- mock_module_object.params = dict(action='add', switch_name='eos',
- switch_port='3', auto_run=True)
- mock_module.return_value = mock_module_object
- mock_client_object = Mock()
- mock_connect.return_value = mock_client_object
- mock_info.return_value = 'Info'
- mock_server_conf.return_value = 'Configlet'
- mock_port_conf.return_value = 'Port'
- mock_conf_action.return_value = dict(taskCreated=True, changed=False)
- mock_conf_task.return_value = None
- cv_server_provision.main()
- self.assertEqual(mock_connect.call_count, 1)
- self.assertEqual(mock_info.call_count, 1)
- self.assertEqual(mock_comp.call_count, 1)
- self.assertEqual(mock_server_conf.call_count, 1)
- self.assertEqual(mock_port_conf.call_count, 1)
- self.assertEqual(mock_conf_action.call_count, 1)
- self.assertEqual(mock_conf_task.call_count, 1)
- mock_wait.assert_not_called()
- mock_module_object.fail_json.assert_not_called()
- return_dict = dict(changed=False, switchInfo='Info',
- switchConfigurable=True, portConfigurable=True,
- taskCreated=False, taskExecuted=False,
- taskCompleted=False)
- mock_module_object.exit_json.assert_called_with(**return_dict)
-
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.CvpClient')
- def test_connect_good(self, mock_client):
- ''' Test connect success.
- '''
- module = Mock()
- module.params = dict(host='host', username='username',
- password='password', protocol='https', port='10')
- connect_mock = Mock()
- mock_client.return_value = connect_mock
- client = cv_server_provision.connect(module)
- self.assertIsInstance(client, Mock)
- self.assertEqual(mock_client.call_count, 1)
- connect_mock.connect.assert_called_once_with(['host'], 'username',
- 'password', port='10',
- protocol='https')
- module.fail_json.assert_not_called()
-
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.CvpLoginError',
- new_callable=lambda: MockException)
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.CvpClient')
- def test_connect_fail(self, mock_client, mock_exception):
- ''' Test connect failure with login error.
- '''
- module = Mock()
- module.params = dict(host='host', username='username',
- password='password', protocol='https', port='10')
- module.fail_json.side_effect = SystemExit
- connect_mock = Mock()
- connect_mock.connect.side_effect = mock_exception('Login Error')
- mock_client.return_value = connect_mock
- self.assertRaises(SystemExit, cv_server_provision.connect, module)
- self.assertEqual(connect_mock.connect.call_count, 1)
- module.fail_json.assert_called_once_with(msg='Login Error')
-
- def test_switch_info_good(self):
- ''' Test switch_info success.
- '''
- module = Mock()
- module.params = dict(switch_name='eos')
- module.client.api.get_device_by_name.return_value = dict(fqdn='eos')
- info = cv_server_provision.switch_info(module)
- self.assertEqual(module.client.api.get_device_by_name.call_count, 1)
- self.assertEqual(info['fqdn'], 'eos')
- module.fail_json.assert_not_called()
-
- def test_switch_info_no_switch(self):
- ''' Test switch_info fails.
- '''
- module = Mock()
- module.params = dict(switch_name='eos')
- module.client.api.get_device_by_name.return_value = None
- info = cv_server_provision.switch_info(module)
- self.assertEqual(module.client.api.get_device_by_name.call_count, 1)
- self.assertEqual(info, None)
- module.fail_json.assert_called_once_with(
- msg="Device with name 'eos' does not exist.")
-
- def test_switch_in_compliance_good(self):
- ''' Test switch_in_compliance good.
- '''
- module = Mock()
- module.client.api.check_compliance.return_value = dict(
- complianceCode='0000')
- sw_info = dict(key='key', type='type', fqdn='eos')
- cv_server_provision.switch_in_compliance(module, sw_info)
- self.assertEqual(module.client.api.check_compliance.call_count, 1)
- module.fail_json.assert_not_called()
-
- def test_switch_in_compliance_fail(self):
- ''' Test switch_in_compliance fail.
- '''
- module = Mock()
- module.client.api.check_compliance.return_value = dict(
- complianceCode='0001')
- sw_info = dict(key='key', type='type', fqdn='eos')
- cv_server_provision.switch_in_compliance(module, sw_info)
- self.assertEqual(module.client.api.check_compliance.call_count, 1)
- module.fail_json.assert_called_with(
- msg='Switch eos is not in compliance.'
- ' Returned compliance code 0001.')
-
- def test_server_configurable_configlet_good(self):
- ''' Test server_configurable_configlet good.
- '''
- module = Mock()
- module.params = dict(switch_name='eos')
- configlets = [dict(name='configlet1', info='line'),
- dict(name='eos-server', info='info')]
- module.client.api.get_configlets_by_device_id.return_value = configlets
- sw_info = dict(key='key', type='type', fqdn='eos')
- result = cv_server_provision.server_configurable_configlet(module,
- sw_info)
- self.assertEqual(module.client.api.get_configlets_by_device_id.call_count, 1)
- self.assertIsNotNone(result)
- self.assertEqual(result['name'], 'eos-server')
- self.assertEqual(result['info'], 'info')
-
- def test_server_configurable_configlet_not_configurable(self):
- ''' Test server_configurable_configlet fail. No server configlet.
- '''
- module = Mock()
- module.params = dict(switch_name='eos')
- configlets = [dict(name='configlet1', info='line'),
- dict(name='configlet2', info='info')]
- module.client.api.get_configlets_by_device_id.return_value = configlets
- sw_info = dict(key='key', type='type', fqdn='eos')
- result = cv_server_provision.server_configurable_configlet(module, sw_info)
- self.assertEqual(module.client.api.get_configlets_by_device_id.call_count, 1)
- self.assertIsNone(result)
-
- def test_server_configurable_configlet_no_configlets(self):
- ''' Test server_configurable_configlet fail. No switch configlets.
- '''
- module = Mock()
- module.params = dict(switch_name='eos')
- module.client.api.get_configlets_by_device_id.return_value = []
- sw_info = dict(key='key', type='type', fqdn='eos')
- result = cv_server_provision.server_configurable_configlet(module,
- sw_info)
- self.assertEqual(module.client.api.get_configlets_by_device_id.call_count, 1)
- self.assertIsNone(result)
-
- def test_port_configurable_good(self):
- ''' Test port_configurable user provided switch port in configlet.
- '''
- module = Mock()
- module.params = dict(switch_name='eos', switch_port='3')
- config = '!\ninterface Ethernet3\n!\ninterface Ethernet4\n!'
- configlet = dict(name='eos-server', config=config)
- result = cv_server_provision.port_configurable(module, configlet)
- self.assertTrue(result)
-
- def test_port_configurable_fail(self):
- ''' Test port_configurable user provided switch port not in configlet.
- '''
- module = Mock()
- module.params = dict(switch_name='eos', switch_port='2')
- config = '!\ninterface Ethernet3\n!\ninterface Ethernet4\n!'
- configlet = dict(name='eos-server', config=config)
- result = cv_server_provision.port_configurable(module, configlet)
- self.assertFalse(result)
-
- def test_port_configurable_fail_no_config(self):
- ''' Test port_configurable configlet empty.
- '''
- module = Mock()
- module.params = dict(switch_name='eos', switch_port='2')
- config = ''
- configlet = dict(name='eos-server', config=config)
- result = cv_server_provision.port_configurable(module, configlet)
- self.assertFalse(result)
-
- def test_configlet_action_show_blank_config(self):
- ''' Test configlet_action show returns current port configuration.
- '''
- module = Mock()
- module.params = dict(action='show', switch_name='eos', switch_port='3')
- config = '!\ninterface Ethernet3\n!\ninterface Ethernet4\n!'
- configlet = dict(name='eos-server', key='key', config=config)
- result = cv_server_provision.configlet_action(module, configlet)
- self.assertIsNotNone(result)
- self.assertEqual(result['currentConfigBlock'], 'interface Ethernet3\n!')
- module.client.api.update_configlet.assert_not_called()
-
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.config_from_template')
- def test_configlet_action_add_with_task(self, mock_template):
- ''' Test configlet_action add with change updates configlet and adds
- proper info to return data. Including task spawned info.
- '''
- module = Mock()
- module.params = dict(action='add', switch_name='eos', switch_port='3')
- config = '!\ninterface Ethernet3\n!\ninterface Ethernet4\n!'
- configlet = dict(name='eos-server', key='key', config=config)
- template_config = ('interface Ethernet3\n description Host eos'
- ' managed by Ansible and Jinja template\n'
- ' load-interval 30\n'
- ' switchport\n'
- ' switchport mode trunk\n'
- ' no shutdown\n!')
- mock_template.return_value = template_config
- update_return = dict(data='Configlet eos-server successfully updated'
- ' and task initiated.')
- module.client.api.update_configlet.return_value = update_return
- result = cv_server_provision.configlet_action(module, configlet)
- self.assertIsNotNone(result)
- self.assertEqual(result['oldConfigBlock'], 'interface Ethernet3\n!')
- full_config = '!\n' + template_config + '\ninterface Ethernet4\n!'
- self.assertEqual(result['fullConfig'], full_config)
- self.assertEqual(result['updateConfigletResponse'],
- update_return['data'])
- self.assertTrue(result['changed'])
- self.assertTrue(result['taskCreated'])
- self.assertEqual(module.client.api.update_configlet.call_count, 1)
-
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.config_from_template')
- def test_configlet_action_add_no_task(self, mock_template):
- ''' Test configlet_action add that doesn't change configlet adds proper
- info to return data. Does not including any task info.
- '''
- module = Mock()
- module.params = dict(action='add', switch_name='eos', switch_port='3')
- config = ('!\ninterface Ethernet3\n description test\n'
- '!\ninterface Ethernet4\n!')
- configlet = dict(name='eos-server', key='key', config=config)
- template_config = 'interface Ethernet3\n description test\n!'
- mock_template.return_value = template_config
- update_return = dict(data='Configlet eos-server successfully updated.')
- module.client.api.update_configlet.return_value = update_return
- result = cv_server_provision.configlet_action(module, configlet)
- self.assertIsNotNone(result)
- self.assertEqual(result['oldConfigBlock'],
- 'interface Ethernet3\n description test\n!')
- self.assertEqual(result['fullConfig'], config)
- self.assertEqual(result['updateConfigletResponse'],
- update_return['data'])
- self.assertNotIn('changed', result)
- self.assertNotIn('taskCreated', result)
- self.assertEqual(module.client.api.update_configlet.call_count, 1)
-
- def test_configlet_action_remove_with_task(self):
- ''' Test configlet_action remove with change updates configlet and adds
- proper info to return data. Including task spawned info.
- '''
- module = Mock()
- module.params = dict(action='remove', switch_name='eos',
- switch_port='3')
- config = ('!\ninterface Ethernet3\n description test\n'
- '!\ninterface Ethernet4\n!')
- configlet = dict(name='eos-server', key='key', config=config)
- update_return = dict(data='Configlet eos-server successfully updated'
- ' and task initiated.')
- module.client.api.update_configlet.return_value = update_return
- result = cv_server_provision.configlet_action(module, configlet)
- self.assertIsNotNone(result)
- self.assertEqual(result['oldConfigBlock'],
- 'interface Ethernet3\n description test\n!')
- full_config = '!\ninterface Ethernet3\n!\ninterface Ethernet4\n!'
- self.assertEqual(result['fullConfig'], full_config)
- self.assertEqual(result['updateConfigletResponse'],
- update_return['data'])
- self.assertTrue(result['changed'])
- self.assertTrue(result['taskCreated'])
- self.assertEqual(module.client.api.update_configlet.call_count, 1)
-
- def test_configlet_action_remove_no_task(self):
- ''' Test configlet_action with remove that doesn't change configlet and
- adds proper info to return data. Does not including any task info.
- '''
- module = Mock()
- module.params = dict(action='remove', switch_name='eos',
- switch_port='3')
- config = '!\ninterface Ethernet3\n!\ninterface Ethernet4\n!'
- configlet = dict(name='eos-server', key='key', config=config)
- update_return = dict(data='Configlet eos-server successfully updated.')
- module.client.api.update_configlet.return_value = update_return
- result = cv_server_provision.configlet_action(module, configlet)
- self.assertIsNotNone(result)
- self.assertEqual(result['oldConfigBlock'], 'interface Ethernet3\n!')
- self.assertEqual(result['fullConfig'], config)
- self.assertEqual(result['updateConfigletResponse'],
- update_return['data'])
- self.assertNotIn('changed', result)
- self.assertNotIn('taskCreated', result)
- self.assertEqual(module.client.api.update_configlet.call_count, 1)
-
- def test_current_config_empty_config(self):
- ''' Test current_config with empty config for port
- '''
- module = Mock()
- module.params = dict(switch_name='eos', switch_port='4')
- config = '!\ninterface Ethernet3\n!\ninterface Ethernet4'
- result = cv_server_provision.current_config(module, config)
- self.assertIsNotNone(result)
- self.assertEqual(result, 'interface Ethernet4')
-
- def test_current_config_with_config(self):
- ''' Test current_config with config for port
- '''
- module = Mock()
- module.params = dict(switch_name='eos', switch_port='3')
- config = ('!\ninterface Ethernet3\n description test\n'
- '!\ninterface Ethernet4\n!')
- result = cv_server_provision.current_config(module, config)
- self.assertIsNotNone(result)
- self.assertEqual(result, 'interface Ethernet3\n description test\n!')
-
- def test_current_config_no_match(self):
- ''' Test current_config with no entry for port
- '''
- module = Mock()
- module.fail_json.side_effect = SystemExit
- module.params = dict(switch_name='eos', switch_port='2')
- config = '!\ninterface Ethernet3\n description test\n!'
- self.assertRaises(SystemExit, cv_server_provision.current_config,
- module, config)
-
- def test_valid_template_true(self):
- ''' Test valid_template true
- '''
- template = 'interface Ethernet3\n description test\n!'
- result = cv_server_provision.valid_template('3', template)
- self.assertTrue(result)
-
- def test_valid_template_false(self):
- ''' Test valid_template false
- '''
- template = 'interface Ethernet3\n description test\n!'
- result = cv_server_provision.valid_template('4', template)
- self.assertFalse(result)
-
- @patch('jinja2.DebugUndefined')
- @patch('jinja2.Environment')
- @patch('jinja2.FileSystemLoader')
- def test_config_from_template_no_template(self, mock_file_sys, mock_env,
- mock_debug):
- ''' Test config_from_template good. No template.
- '''
- module = Mock()
- module.fail_json.side_effect = SystemExit
- module.params = dict(switch_name='eos', switch_port='3',
- server_name='new', template='jinja.j2')
- mock_file_sys.return_value = 'file'
- mock_debug.return_value = 'debug'
- env_mock = Mock()
- env_mock.get_template.return_value = None
- mock_env.return_value = env_mock
- self.assertRaises(SystemExit, cv_server_provision.config_from_template,
- module)
- self.assertEqual(mock_file_sys.call_count, 1)
- self.assertEqual(mock_env.call_count, 1)
- self.assertEqual(module.fail_json.call_count, 1)
-
- @patch('jinja2.meta.find_undeclared_variables')
- @patch('jinja2.DebugUndefined')
- @patch('jinja2.Environment')
- @patch('jinja2.FileSystemLoader')
- def test_config_from_template_good_no_vlan(self, mock_file_sys, mock_env, mock_debug,
- mock_find):
- ''' Test config_from_template good. No port_vlan.
- '''
- module = Mock()
- module.params = dict(switch_name='eos', switch_port='3',
- server_name='new', template='jinja.j2')
- mock_file_sys.return_value = 'file'
- mock_debug.return_value = 'debug'
- template_mock = Mock()
- template_mock.render.return_value = ('interface Ethernet3\n'
- ' description test\n'
- ' switchport\n'
- ' switchport mode trunk\n'
- ' no shutdown\n!')
- env_mock = Mock()
- env_mock.loader.get_source.return_value = ['one', 'two']
- env_mock.parse.return_value = 'parsed'
- env_mock.get_template.return_value = template_mock
- mock_env.return_value = env_mock
- mock_find.return_value = dict(server_name=None, switch_port=None)
- result = cv_server_provision.config_from_template(module)
- self.assertIsNotNone(result)
- expected = ('interface Ethernet3\n'
- ' description test\n'
- ' switchport\n'
- ' switchport mode trunk\n'
- ' no shutdown\n!')
- self.assertEqual(result, expected)
- self.assertEqual(mock_file_sys.call_count, 1)
- self.assertEqual(mock_env.call_count, 1)
- module.fail_json.assert_not_called()
-
- @patch('jinja2.meta.find_undeclared_variables')
- @patch('jinja2.DebugUndefined')
- @patch('jinja2.Environment')
- @patch('jinja2.FileSystemLoader')
- def test_config_from_template_good_vlan(self, mock_file_sys, mock_env, mock_debug,
- mock_find):
- ''' Test config_from_template good. With port_vlan.
- '''
- module = Mock()
- module.params = dict(switch_name='eos', switch_port='3',
- server_name='new', template='jinja.j2', port_vlan='7')
- mock_file_sys.return_value = 'file'
- mock_debug.return_value = 'debug'
- template_mock = Mock()
- template_mock.render.return_value = ('interface Ethernet3\n'
- ' description test\n'
- ' switchport\n'
- ' switchport access vlan 7\n'
- ' no shutdown\n!')
- env_mock = Mock()
- env_mock.loader.get_source.return_value = ['one', 'two']
- env_mock.parse.return_value = 'parsed'
- env_mock.get_template.return_value = template_mock
- mock_env.return_value = env_mock
- mock_find.return_value = dict(server_name=None, switch_port=None,
- port_vlan=None)
- result = cv_server_provision.config_from_template(module)
- self.assertIsNotNone(result)
- expected = ('interface Ethernet3\n'
- ' description test\n'
- ' switchport\n'
- ' switchport access vlan 7\n'
- ' no shutdown\n!')
- self.assertEqual(result, expected)
- self.assertEqual(mock_file_sys.call_count, 1)
- self.assertEqual(mock_env.call_count, 1)
- module.fail_json.assert_not_called()
-
- @patch('jinja2.meta.find_undeclared_variables')
- @patch('jinja2.DebugUndefined')
- @patch('jinja2.Environment')
- @patch('jinja2.FileSystemLoader')
- def test_config_from_template_fail_wrong_port(self, mock_file_sys, mock_env,
- mock_debug, mock_find):
- ''' Test config_from_template fail. Wrong port number in template.
- '''
- module = Mock()
- module.params = dict(switch_name='eos', switch_port='4',
- server_name='new', template='jinja.j2')
- mock_file_sys.return_value = 'file'
- mock_debug.return_value = 'debug'
- template_mock = Mock()
- template_mock.render.return_value = ('interface Ethernet3\n'
- ' description test\n!')
- env_mock = Mock()
- env_mock.loader.get_source.return_value = ['one', 'two']
- env_mock.parse.return_value = 'parsed'
- env_mock.get_template.return_value = template_mock
- mock_env.return_value = env_mock
- mock_find.return_value = dict(server_name=None, switch_port=None)
- result = cv_server_provision.config_from_template(module)
- self.assertIsNotNone(result)
- expected = 'interface Ethernet3\n description test\n!'
- self.assertEqual(result, expected)
- self.assertEqual(mock_file_sys.call_count, 1)
- self.assertEqual(mock_env.call_count, 1)
- module.fail_json.assert_called_with(msg='Template content does not'
- ' configure proper interface'
- ' - %s' % expected)
-
- @patch('jinja2.meta.find_undeclared_variables')
- @patch('jinja2.DebugUndefined')
- @patch('jinja2.Environment')
- @patch('jinja2.FileSystemLoader')
- def test_config_from_template_fail_no_vlan(self, mock_file_sys, mock_env,
- mock_debug, mock_find):
- ''' Test config_from_template fail. Template needs vlan but none provided.
- '''
- module = Mock()
- module.params = dict(switch_name='eos', switch_port='3',
- server_name='new', template='jinja.j2',
- port_vlan=None)
- mock_file_sys.return_value = 'file'
- mock_debug.return_value = 'debug'
- template_mock = Mock()
- template_mock.render.return_value = ('interface Ethernet3\n'
- ' description test\n!')
- env_mock = Mock()
- env_mock.loader.get_source.return_value = ['one', 'two']
- env_mock.parse.return_value = 'parsed'
- env_mock.get_template.return_value = template_mock
- mock_env.return_value = env_mock
- mock_find.return_value = dict(server_name=None, switch_port=None,
- port_vlan=None)
- result = cv_server_provision.config_from_template(module)
- self.assertIsNotNone(result)
- expected = 'interface Ethernet3\n description test\n!'
- self.assertEqual(result, expected)
- self.assertEqual(mock_file_sys.call_count, 1)
- self.assertEqual(mock_env.call_count, 1)
- module.fail_json.assert_called_with(msg='Template jinja.j2 requires a'
- ' vlan. Please re-run with vlan'
- ' number provided.')
-
- def test_updated_configlet_content_add(self):
- ''' Test updated_configlet_content. Add config.
- '''
- module = Mock()
- module.params = dict(switch_name='eos', switch_port='3')
- existing_config = '!\ninterface Ethernet3\n!\ninterface Ethernet4\n!'
- new_config_block = 'interface Ethernet3\n description test\n!'
- result = cv_server_provision.updated_configlet_content(module,
- existing_config,
- new_config_block)
- expected = ('!\ninterface Ethernet3\n description test\n'
- '!\ninterface Ethernet4\n!')
- self.assertEqual(result, expected)
- module.fail_json.assert_not_called()
-
- def test_updated_configlet_content_remove(self):
- ''' Test updated_configlet_content. Remove config.
- '''
- module = Mock()
- module.params = dict(switch_name='eos', switch_port='3')
- existing_config = ('!\ninterface Ethernet3\n description test\n'
- '!\ninterface Ethernet4')
- new_config_block = 'interface Ethernet3\n!'
- result = cv_server_provision.updated_configlet_content(module,
- existing_config,
- new_config_block)
- expected = '!\ninterface Ethernet3\n!\ninterface Ethernet4'
- self.assertEqual(result, expected)
- module.fail_json.assert_not_called()
-
- def test_updated_configlet_content_no_match(self):
- ''' Test updated_configlet_content. Interface not in config.
- '''
- module = Mock()
- module.fail_json.side_effect = SystemExit
- module.params = dict(switch_name='eos', switch_port='2')
- existing_config = '!\ninterface Ethernet3\n description test\n!'
- new_config_block = 'interface Ethernet3\n!'
- self.assertRaises(SystemExit,
- cv_server_provision.updated_configlet_content,
- module, existing_config, new_config_block)
-
- @patch('time.sleep')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.switch_info')
- def test_configlet_update_task_good_one_try(self, mock_info, mock_sleep):
- ''' Test configlet_update_task gets task after one try.
- '''
- module = Mock()
- task = dict(data=dict(WORKFLOW_ACTION='Configlet Push'),
- description='Configlet Assign',
- workOrderId='7')
- device_info = dict(taskIdList=[task])
- mock_info.return_value = device_info
- result = cv_server_provision.configlet_update_task(module)
- self.assertEqual(result, '7')
- mock_sleep.assert_not_called()
- self.assertEqual(mock_info.call_count, 1)
-
- @patch('time.sleep')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.switch_info')
- def test_configlet_update_task_good_three_tries(self, mock_info, mock_sleep):
- ''' Test configlet_update_task gets task on third try.
- '''
- module = Mock()
- task1 = dict(data=dict(WORKFLOW_ACTION='Configlet Push'),
- description='Configlet Assign',
- workOrderId='7')
- task2 = dict(data=dict(WORKFLOW_ACTION='Nonsense'),
- description='Configlet Assign',
- workOrderId='700')
- device_info = dict(taskIdList=[task1, task2])
- mock_info.side_effect = [dict(), dict(), device_info]
- result = cv_server_provision.configlet_update_task(module)
- self.assertEqual(result, '7')
- self.assertEqual(mock_sleep.call_count, 2)
- self.assertEqual(mock_info.call_count, 3)
-
- @patch('time.sleep')
- @patch('ansible_collections.community.network.plugins.modules.cv_server_provision.switch_info')
- def test_configlet_update_task_no_task(self, mock_info, mock_sleep):
- ''' Test configlet_update_task does not get task after three tries.
- '''
- module = Mock()
- mock_info.side_effect = [dict(), dict(), dict()]
- result = cv_server_provision.configlet_update_task(module)
- self.assertIsNone(result)
- self.assertEqual(mock_sleep.call_count, 3)
- self.assertEqual(mock_info.call_count, 3)
-
- @patch('time.sleep')
- def test_wait_for_task_completion_good_one_try(self, mock_time):
- ''' Test wait_for_task_completion completed. One Try.
- '''
- module = Mock()
- module.client.api.get_task_by_id.return_value = dict(
- workOrderUserDefinedStatus='Completed')
- result = cv_server_provision.wait_for_task_completion(module, '7')
- self.assertTrue(result)
- self.assertEqual(module.client.api.get_task_by_id.call_count, 1)
- module.fail_json.assert_not_called()
- mock_time.assert_not_called()
-
- @patch('time.sleep')
- def test_wait_for_task_completion_good_three_tries(self, mock_time):
- ''' Test wait_for_task_completion completed. Three tries.
- '''
- module = Mock()
- try_one_two = dict(workOrderUserDefinedStatus='Pending')
- try_three = dict(workOrderUserDefinedStatus='Completed')
- module.client.api.get_task_by_id.side_effect = [try_one_two,
- try_one_two, try_three]
- result = cv_server_provision.wait_for_task_completion(module, '7')
- self.assertTrue(result)
- self.assertEqual(module.client.api.get_task_by_id.call_count, 3)
- module.fail_json.assert_not_called()
- self.assertEqual(mock_time.call_count, 2)
-
- @patch('time.sleep')
- def test_wait_for_task_completion_fail(self, mock_time):
- ''' Test wait_for_task_completion failed.
- '''
- module = Mock()
- try_one = dict(workOrderUserDefinedStatus='Failed')
- try_two = dict(workOrderUserDefinedStatus='Completed')
- module.client.api.get_task_by_id.side_effect = [try_one, try_two]
- result = cv_server_provision.wait_for_task_completion(module, '7')
- self.assertTrue(result)
- self.assertEqual(module.client.api.get_task_by_id.call_count, 2)
- text = ('Task 7 has reported status Failed. Please consult the CVP'
- ' admins for more information.')
- module.fail_json.assert_called_with(msg=text)
- self.assertEqual(mock_time.call_count, 1)
diff --git a/ansible_collections/community/network/tests/unit/plugins/modules/test_icx_static_route.py b/ansible_collections/community/network/tests/unit/plugins/modules/test_icx_static_route.py
deleted file mode 100644
index 3dda2d956..000000000
--- a/ansible_collections/community/network/tests/unit/plugins/modules/test_icx_static_route.py
+++ /dev/null
@@ -1,122 +0,0 @@
-# Copyright: (c) 2019, Ansible Project
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-from ansible_collections.community.network.tests.unit.compat.mock import patch
-from ansible_collections.community.network.plugins.modules import icx_static_route
-from ansible_collections.community.network.tests.unit.plugins.modules.utils import set_module_args
-from .icx_module import TestICXModule, load_fixture
-
-
-class TestICXStaticRouteModule(TestICXModule):
-
- module = icx_static_route
-
- def setUp(self):
- super(TestICXStaticRouteModule, self).setUp()
- self.mock_get_config = patch('ansible_collections.community.network.plugins.modules.icx_static_route.get_config')
- self.get_config = self.mock_get_config.start()
-
- self.mock_load_config = patch('ansible_collections.community.network.plugins.modules.icx_static_route.load_config')
- self.load_config = self.mock_load_config.start()
- self.set_running_config()
-
- def tearDown(self):
- super(TestICXStaticRouteModule, self).tearDown()
- self.mock_get_config.stop()
- self.mock_load_config.stop()
-
- def load_fixtures(self, commands=None):
- compares = None
-
- def load_file(*args, **kwargs):
- module = args
- for arg in args:
- if arg.params['check_running_config'] is True:
- return load_fixture('icx_static_route_config.txt').strip()
- else:
- return ''
-
- self.get_config.side_effect = load_file
- self.load_config.return_value = None
-
- def test_icx_static_route_config(self):
- set_module_args(dict(prefix='192.126.23.0/24', next_hop='10.10.14.3'))
- if not self.ENV_ICX_USE_DIFF:
- result = self.execute_module(changed=True)
- expected_commands = [
- 'ip route 192.126.23.0 255.255.255.0 10.10.14.3'
- ]
- self.assertEqual(result['commands'], expected_commands)
- else:
- result = self.execute_module(changed=True)
- expected_commands = [
- 'ip route 192.126.23.0 255.255.255.0 10.10.14.3'
- ]
- self.assertEqual(result['commands'], expected_commands)
-
- def test_icx_static_route_config_compare(self):
- set_module_args(dict(prefix='172.16.10.0/24', next_hop='10.0.0.8', check_running_config=True))
- if self.get_running_config(compare=True):
- if not self.ENV_ICX_USE_DIFF:
- result = self.execute_module(changed=False)
- expected_commands = [
- ]
- self.assertEqual(result['commands'], expected_commands)
- else:
- result = self.execute_module(changed=False)
- expected_commands = [
- ]
- self.assertEqual(result['commands'], expected_commands)
-
- def test_icx_static_route_distance_config(self):
- set_module_args(dict(prefix='192.126.0.0', mask='255.255.0.0', next_hop='10.10.14.3', admin_distance='40'))
- if not self.ENV_ICX_USE_DIFF:
- result = self.execute_module(changed=True)
- expected_commands = [
- 'ip route 192.126.0.0 255.255.0.0 10.10.14.3 distance 40'
- ]
- self.assertEqual(result['commands'], expected_commands)
- else:
- result = self.execute_module(changed=True)
- expected_commands = [
- 'ip route 192.126.0.0 255.255.0.0 10.10.14.3 distance 40'
- ]
- self.assertEqual(result['commands'], expected_commands)
-
- def test_icx_static_route_aggregate(self):
- aggregate = [
- dict(prefix='192.126.23.0/24', next_hop='10.10.14.3'),
- dict(prefix='192.126.0.0', mask='255.255.0.0', next_hop='10.10.14.3', admin_distance='40')
- ]
- set_module_args(dict(aggregate=aggregate))
- if not self.ENV_ICX_USE_DIFF:
- result = self.execute_module(changed=True)
- expected_commands = [
- 'ip route 192.126.23.0 255.255.255.0 10.10.14.3',
- 'ip route 192.126.0.0 255.255.0.0 10.10.14.3 distance 40'
- ]
- self.assertEqual(result['commands'], expected_commands)
- else:
- result = self.execute_module(changed=True)
- expected_commands = [
- 'ip route 192.126.23.0 255.255.255.0 10.10.14.3',
- 'ip route 192.126.0.0 255.255.0.0 10.10.14.3 distance 40'
- ]
- self.assertEqual(result['commands'], expected_commands)
-
- def test_icx_static_route_remove(self):
- set_module_args(dict(prefix='172.16.10.0/24', next_hop='10.0.0.8', state='absent'))
- if not self.ENV_ICX_USE_DIFF:
- result = self.execute_module(changed=True)
- expected_commands = [
- 'no ip route 172.16.10.0 255.255.255.0 10.0.0.8',
- ]
- self.assertEqual(result['commands'], expected_commands)
-
- else:
- result = self.execute_module(changed=True)
- expected_commands = [
- 'no ip route 172.16.10.0 255.255.255.0 10.0.0.8',
- ]
- self.assertEqual(result['commands'], expected_commands)
diff --git a/ansible_collections/community/network/tests/unit/requirements.txt b/ansible_collections/community/network/tests/unit/requirements.txt
index 51c436d08..c54d5f493 100644
--- a/ansible_collections/community/network/tests/unit/requirements.txt
+++ b/ansible_collections/community/network/tests/unit/requirements.txt
@@ -1,4 +1,6 @@
unittest2 ; python_version <= '2.6'
+jinja2 ; python_version >= '2.7'
+requests ; python_version >= '2.7'
# requirements for ftd module_utils
firepower-kickstart ; python_version >= '3.6' and python_version < '3.9' # Python 3.6+ only; dependency does not work with 3.9 yet
diff --git a/ansible_collections/community/network/tests/unit/requirements.yml b/ansible_collections/community/network/tests/unit/requirements.yml
new file mode 100644
index 000000000..d4b8365f9
--- /dev/null
+++ b/ansible_collections/community/network/tests/unit/requirements.yml
@@ -0,0 +1,3 @@
+---
+collections:
+ - ansible.netcommon
diff --git a/ansible_collections/community/postgresql/.azure-pipelines/azure-pipelines.yml b/ansible_collections/community/postgresql/.azure-pipelines/azure-pipelines.yml
index 4a34c9edf..28f8b2497 100644
--- a/ansible_collections/community/postgresql/.azure-pipelines/azure-pipelines.yml
+++ b/ansible_collections/community/postgresql/.azure-pipelines/azure-pipelines.yml
@@ -36,11 +36,30 @@ variables:
resources:
containers:
- container: default
- image: quay.io/ansible/azure-pipelines-test-container:3.0.0
+ image: quay.io/ansible/azure-pipelines-test-container:4.0.1
pool: Standard
stages:
+ - stage: Python_qualtiy_tools
+ displayName: Python quality
+ dependsOn: []
+ jobs:
+ - job: 'Test'
+ pool:
+ vmImage: 'ubuntu-latest'
+ steps:
+ - task: UsePythonVersion@0
+ displayName: Get Python for Python tools.
+ inputs:
+ versionSpec: '3.11'
+ addToPath: false
+ name: pyTools
+ - script: $(pyTools.pythonLocation)/bin/pip install --upgrade tox
+ displayName: Upgrade/Install tox.
+ - script: $(pyTools.pythonLocation)/bin/tox -e lint
+ displayName: Run tox -e lint
+
## Sanity & units
- stage: Ansible_devel
displayName: Sanity & Units devel
@@ -56,69 +75,74 @@ stages:
- name: Units
test: 'devel/units/1'
- - stage: Ansible_2_15
- displayName: Sanity & Units 2.15
+ - stage: Ansible_2_16
+ displayName: Sanity & Units 2.16
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
targets:
- name: Sanity
- test: '2.15/sanity/1'
+ test: '2.16/sanity/1'
- name: Units
- test: '2.15/units/1'
+ test: '2.16/units/1'
- - stage: Ansible_2_14
- displayName: Sanity & Units 2.14
+ - stage: Ansible_2_15
+ displayName: Sanity & Units 2.15
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
targets:
- name: Sanity
- test: '2.14/sanity/1'
+ test: '2.15/sanity/1'
- name: Units
- test: '2.14/units/1'
+ test: '2.15/units/1'
- - stage: Ansible_2_13
- displayName: Sanity & Units 2.13
+ - stage: Ansible_2_14
+ displayName: Sanity & Units 2.14
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
targets:
- name: Sanity
- test: '2.13/sanity/1'
+ test: '2.14/sanity/1'
- name: Units
- test: '2.13/units/1'
+ test: '2.14/units/1'
- - stage: Ansible_2_12
- displayName: Sanity & Units 2.12
+## Docker
+ - stage: Docker_devel
+ displayName: Docker devel
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
+ testFormat: devel/linux/{0}/1
targets:
- - name: Sanity
- test: '2.12/sanity/1'
- - name: Units
- test: '2.12/units/1'
+ - name: Fedora 39
+ test: fedora39
+ - name: Ubuntu 20.04
+ test: ubuntu2004
+ - name: Ubuntu 22.04
+ test: ubuntu2204
-## Docker
- - stage: Docker_devel
- displayName: Docker devel
+ - stage: Docker_2_16
+ displayName: Docker 2.16
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
- testFormat: devel/linux/{0}/1
+ testFormat: 2.16/linux/{0}/1
targets:
- name: CentOS 7
test: centos7
- - name: Fedora 37
- test: fedora37
+ - name: Fedora 38
+ test: fedora38
- name: Ubuntu 20.04
test: ubuntu2004
+ - name: Ubuntu 22.04
+ test: ubuntu2204
- stage: Docker_2_15
displayName: Docker 2.15
@@ -134,6 +158,8 @@ stages:
test: fedora37
- name: Ubuntu 20.04
test: ubuntu2004
+ - name: Ubuntu 22.04
+ test: ubuntu2204
- stage: Docker_2_14
displayName: Docker 2.14
@@ -145,52 +171,31 @@ stages:
targets:
- name: CentOS 7
test: centos7
- - name: Fedora 36
- test: fedora36
- name: Ubuntu 20.04
test: ubuntu2004
- - stage: Docker_2_13
- displayName: Docker 2.13
- dependsOn: []
- jobs:
- - template: templates/matrix.yml
- parameters:
- testFormat: 2.13/linux/{0}/1
- targets:
- - name: CentOS 7
- test: centos7
- - name: Fedora 35
- test: fedora35
- - name: Ubuntu 20.04
- test: ubuntu2004
-
- - stage: Docker_2_12
- displayName: Docker 2.12
+## Remote
+ - stage: Remote_devel
+ displayName: Remote devel
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
- testFormat: 2.12/linux/{0}/1
+ testFormat: devel/{0}/1
targets:
- - name: CentOS 7
- test: centos7
- - name: Fedora 34
- test: fedora34
- - name: Ubuntu 20.04
- test: ubuntu2004
+ - name: RHEL 9.3
+ test: rhel/9.3
-## Remote
- - stage: Remote_devel
- displayName: Remote devel
+ - stage: Remote_2_16
+ displayName: Remote 2.16
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
- testFormat: devel/{0}/1
+ testFormat: 2.16/{0}/1
targets:
- - name: RHEL 8.7
- test: rhel/8.7
+ - name: RHEL 8.8
+ test: rhel/8.8
- stage: Remote_2_15
displayName: Remote 2.15
@@ -214,47 +219,22 @@ stages:
- name: RHEL 8.6
test: rhel/8.6
- - stage: Remote_2_13
- displayName: Remote 2.13
- dependsOn: []
- jobs:
- - template: templates/matrix.yml
- parameters:
- testFormat: 2.13/{0}/1
- targets:
- - name: RHEL 8.5
- test: rhel/8.5
-
- - stage: Remote_2_12
- displayName: Remote 2.12
- dependsOn: []
- jobs:
- - template: templates/matrix.yml
- parameters:
- testFormat: 2.12/{0}/1
- targets:
- - name: RHEL 8.4
- test: rhel/8.4
-
## Finally
- stage: Summary
condition: succeededOrFailed()
dependsOn:
- Ansible_devel
+ - Ansible_2_16
- Ansible_2_15
- Ansible_2_14
- - Ansible_2_13
- - Ansible_2_12
- Docker_devel
+ - Docker_2_16
- Docker_2_15
- Docker_2_14
- - Docker_2_13
- - Docker_2_12
- Remote_devel
+ - Remote_2_16
- Remote_2_15
- Remote_2_14
- - Remote_2_13
- - Remote_2_12
jobs:
- template: templates/coverage.yml
diff --git a/ansible_collections/community/postgresql/.azure-pipelines/scripts/combine-coverage.py b/ansible_collections/community/postgresql/.azure-pipelines/scripts/combine-coverage.py
index 506ade646..3c3a7ecea 100755
--- a/ansible_collections/community/postgresql/.azure-pipelines/scripts/combine-coverage.py
+++ b/ansible_collections/community/postgresql/.azure-pipelines/scripts/combine-coverage.py
@@ -7,7 +7,8 @@ Keep in mind that Azure Pipelines does not enforce unique job display names (onl
It is up to pipeline authors to avoid name collisions when deviating from the recommended format.
"""
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
import os
diff --git a/ansible_collections/community/postgresql/.azure-pipelines/scripts/time-command.py b/ansible_collections/community/postgresql/.azure-pipelines/scripts/time-command.py
index 5e8eb8d4c..400528798 100755
--- a/ansible_collections/community/postgresql/.azure-pipelines/scripts/time-command.py
+++ b/ansible_collections/community/postgresql/.azure-pipelines/scripts/time-command.py
@@ -1,7 +1,8 @@
#!/usr/bin/env python
"""Prepends a relative timestamp to each input line from stdin and writes it to stdout."""
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
import sys
diff --git a/ansible_collections/community/postgresql/.codespell-exclude-words b/ansible_collections/community/postgresql/.codespell-exclude-words
new file mode 100644
index 000000000..85dc2b77c
--- /dev/null
+++ b/ansible_collections/community/postgresql/.codespell-exclude-words
@@ -0,0 +1,3 @@
+astroid
+hart
+brin
diff --git a/ansible_collections/community/postgresql/.codespellrc b/ansible_collections/community/postgresql/.codespellrc
new file mode 100644
index 000000000..0c61c0b6f
--- /dev/null
+++ b/ansible_collections/community/postgresql/.codespellrc
@@ -0,0 +1,2 @@
+[codespell]
+ignore-words = .codespell-exclude-words
diff --git a/ansible_collections/community/postgresql/.flake8 b/ansible_collections/community/postgresql/.flake8
new file mode 100644
index 000000000..33b26e792
--- /dev/null
+++ b/ansible_collections/community/postgresql/.flake8
@@ -0,0 +1,7 @@
+[flake8]
+ignore =
+ E203,
+ E402,
+ E501,
+ W503,
+max-line-length = 120
diff --git a/ansible_collections/community/postgresql/.pre-commit-config.yaml b/ansible_collections/community/postgresql/.pre-commit-config.yaml
new file mode 100644
index 000000000..13ad43477
--- /dev/null
+++ b/ansible_collections/community/postgresql/.pre-commit-config.yaml
@@ -0,0 +1,36 @@
+# See https://pre-commit.com for more information
+# See https://pre-commit.com/hooks.html for more hooks
+#
+# Should more or less follow lint and typing settings as found is tox.ini
+#
+# Once pre-commit package is installed in your environnement, install hooks
+# with `pre-commit install`
+repos:
+- repo: https://github.com/pre-commit/pre-commit-hooks
+ rev: v4.4.0
+ hooks:
+ - id: trailing-whitespace
+ - id: end-of-file-fixer
+ - id: check-added-large-files
+- repo: local
+ hooks:
+ - id: autoflake
+ name: autoflake
+ entry: autoflake --check-diff
+ language: system
+ types: [python]
+ - id: flake8
+ name: flake8
+ entry: flake8 .
+ language: system
+ types: [python]
+ - id: isort
+ name: isort
+ entry: isort --check --diff .
+ language: system
+ types: [python]
+ - id: codespell
+ name: codespell
+ entry: codespell
+ language: system
+ types: [file]
diff --git a/ansible_collections/community/postgresql/CHANGELOG.rst b/ansible_collections/community/postgresql/CHANGELOG.rst
index 5730f6108..d9990ab6a 100644
--- a/ansible_collections/community/postgresql/CHANGELOG.rst
+++ b/ansible_collections/community/postgresql/CHANGELOG.rst
@@ -5,6 +5,136 @@ Community PostgreSQL Collection Release Notes
.. contents:: Topics
+v3.4.0
+======
+
+Release Summary
+---------------
+
+This is a minor release of the ``community.postgresql`` collection.
+This changelog contains all changes to the modules and plugins in this collection
+that have been made after the previous release.
+
+Minor Changes
+-------------
+
+- postgresql_db - add the ``icu_locale`` argument (https://github.com/ansible-collections/community.postgresql/issues/666).
+- postgresql_db - add the ``locale_provider`` argument (https://github.com/ansible-collections/community.postgresql/issues/666).
+
+Bugfixes
+--------
+
+- postgresql_privs - fix a failure when altering privileges with ``grant_option: true`` (https://github.com/ansible-collections/community.postgresql/issues/668).
+
+v3.3.0
+======
+
+Release Summary
+---------------
+
+This is the minor release of the ``community.postgresql`` collection.
+This changelog contains all changes to the modules and plugins in this collection
+that have been made after the previous release.
+
+Minor Changes
+-------------
+
+- postgresql_db - add the ``comment`` argument (https://github.com/ansible-collections/community.postgresql/issues/614).
+- postgresql_ext - add the ``comment`` argument (https://github.com/ansible-collections/community.postgresql/issues/354).
+- postgresql_publication - add the ``comment`` argument (https://github.com/ansible-collections/community.postgresql/issues/354).
+- postgresql_schema - add the ``comment`` argument (https://github.com/ansible-collections/community.postgresql/issues/354).
+- postgresql_subscription - add the ``comment`` argument (https://github.com/ansible-collections/community.postgresql/issues/354).
+- postgresql_tablespace - add the ``comment`` argument (https://github.com/ansible-collections/community.postgresql/issues/354).
+
+Bugfixes
+--------
+
+- postgresql_query - now reports not changed for queries starting with "SHOW" (https://github.com/ansible-collections/community.postgresql/pull/592).
+- postgresql_user - module failed when running against an SQL_ASCII encoded database as the user's current password was returned as bytes as opposed to a str. Fix now checks for this case and decodes the bytes as an ascii encoded string. (https://github.com/ansible-collections/community.postgresql/issues/584).
+
+v3.2.0
+======
+
+Release Summary
+---------------
+
+This is the minor release of the ``community.postgresql`` collection.
+This changelog contains all changes to the modules and plugins in this collection
+that have been made after the previous release.
+
+Minor Changes
+-------------
+
+- postgres modules - added support for Psycopg 3 library (https://github.com/ansible-collections/community.postgresql/pull/517).
+- postgresql_owner - added support at new object types (https://github.com/ansible-collections/community.postgresql/pull/555).
+
+Bugfixes
+--------
+
+- postgresql_info - fix SQL syntax issue (https://github.com/ansible-collections/community.postgresql/issues/570).
+
+v3.1.0
+======
+
+Release Summary
+---------------
+
+This is the minor release of the ``community.postgresql`` collection.
+This changelog contains all changes to the modules and plugins in this collection
+that have been made after the previous release.
+
+Major Changes
+-------------
+
+- postgres modules - the minimum version of psycopg2 library the collection supports is 2.5.1 (https://github.com/ansible-collections/community.postgresql/pull/556).
+
+Minor Changes
+-------------
+
+- Collection core functions - use ``get_server_version`` in all modules (https://github.com/ansible-collections/community.postgresql/pull/518)."
+- Collection core functions - use common cursor arguments in all modules (https://github.com/ansible-collections/community.postgresql/pull/522)."
+- postgresql_ext - added idempotence always both in standard and in check mode (https://github.com/ansible-collections/community.postgresql/pull/545).
+- postgresql_ext - added idempotence when version=latest (https://github.com/ansible-collections/community.postgresql/pull/504).
+- postgresql_ext - added prev_version and version return values (https://github.com/ansible-collections/community.postgresql/pull/545).
+- postgresql_ext - added queries in module output also in check mode (https://github.com/ansible-collections/community.postgresql/pull/545).
+- postgresql_ext - improved error messages (https://github.com/ansible-collections/community.postgresql/pull/545).
+- postgresql_privs - added idempotence when roles=PUBLIC (https://github.com/ansible-collections/community.postgresql/pull/502).
+- postgresql_privs - added parameters privileges support for PostgreSQL 15 or higher (https://github.com/ansible-collections/community.postgresql/issues/481).
+- postgresql_privs - added support for implicit roles CURRENT_ROLE, CURRENT_USER, and SESSION_USER (https://github.com/ansible-collections/community.postgresql/pull/502).
+- postgresql_tablespace - added idempotence when dropping a non-existing tablespace (https://github.com/ansible-collections/community.postgresql/pull/554).
+
+Deprecated Features
+-------------------
+
+- postgresql_lang - the module has been deprecated and will be removed in ``community.postgresql 4.0.0``. Please use the ``postgresql_ext`` module instead (https://github.com/ansible-collections/community.postgresql/issues/559).
+
+Bugfixes
+--------
+
+- postgresql_ext - fixed queries return value name in documentation (https://github.com/ansible-collections/community.postgresql/pull/545).
+- postgresql_privs - fixed error message and documentation (https://github.com/ansible-collections/community.postgresql/pull/510).
+- postgresql_set - fixed GUC_LIST_QUOTE parameters (https://github.com/ansible-collections/community.postgresql/pull/521).
+- postgresql_set - fixed error message in param_set function (https://github.com/ansible-collections/community.postgresql/pull/505).
+
+v3.0.0
+======
+
+Release Summary
+---------------
+
+This is a major release of the ``community.postgresql`` collection.
+This changelog contains all changes to the modules in this collection that
+have been added after the release of ``community.postgresql`` 2.4.2.
+
+Major Changes
+-------------
+
+- postgresql_pg_hba - remove the deprecated ``order`` argument. The sortorder ``sdu`` is hardcoded (https://github.com/ansible-collections/community.postgresql/pull/496).
+- postgresql_privs - remove the deprecated ``usage_on_types`` argument. Use the ``type`` option of the ``type`` argument to explicitly manipulate privileges on PG types (https://github.com/ansible-collections/community.postgresql/issues/208).
+- postgresql_query - remove the deprecated ``path_to_script`` and ``as_single_query`` arguments. Use the ``postgresql_script`` module to run queries from scripts (https://github.com/ansible-collections/community.postgresql/issues/189).
+- postgresql_user - move the deprecated ``privs`` argument removal to community.postgresql 4.0.0 (https://github.com/ansible-collections/community.postgresql/issues/493).
+- postgresql_user - remove the deprecated ``groups`` argument. Use the ``postgresql_membership`` module instead (https://github.com/ansible-collections/community.postgresql/issues/300).
+
v2.4.2
======
@@ -64,7 +194,7 @@ Minor Changes
Bugfixes
--------
-- postgresql_info - add support for non numeric extenstion version (https://github.com/ansible-collections/community.postgresql/issues/428).
+- postgresql_info - add support for non numeric extension version (https://github.com/ansible-collections/community.postgresql/issues/428).
- postgresql_info - when getting information about subscriptions, check the list of available columns in the pg_subscription table (https://github.com/ansible-collections/community.postgresql/issues/429).
- postgresql_privs - fix connect_params being ignored (https://github.com/ansible-collections/community.postgresql/issues/450).
- postgresql_query - could crash under certain conditions because of a missing import to `psycopg2.extras` (https://github.com/ansible-collections/community.postgresql/issues/283).
diff --git a/ansible_collections/community/postgresql/CONTRIBUTING.md b/ansible_collections/community/postgresql/CONTRIBUTING.md
index 70cd5557e..ecb18f74a 100644
--- a/ansible_collections/community/postgresql/CONTRIBUTING.md
+++ b/ansible_collections/community/postgresql/CONTRIBUTING.md
@@ -3,3 +3,47 @@
Refer to the [Ansible Contributing guidelines](https://docs.ansible.com/ansible/devel/community/index.html) to learn how to contribute to this collection.
Refer to the [review checklist](https://docs.ansible.com/ansible/devel/community/collection_contributors/collection_reviewing.html) when triaging issues or reviewing PRs.
+
+## Checking your code locally
+
+### By hand
+
+You can run flake8 with tox to verify the quality of your code. For that you
+can simply call tox with that command:
+``` console
+$ tox -e lint
+```
+
+If you tox is missing on your environment you can probably install it through
+your package manager (Eg: `sudo apt install tox`) or with pip (within a
+virtualenv):
+
+``` console
+$ python3 -m venv .venv
+$ source .venv
+$ pip install tox
+```
+
+### Automatically for each commit
+
+This repo contains some pre-commit configuration to automatically check your
+code foreach commit. To use that configuration you should "install" it by
+running:
+
+``` console
+$ pre-commit install
+```
+
+Then autoflake, flake8, isort and codespell must run when you add some commits.
+You can also force them to run with this command:
+
+``` console
+$ pre-commit run --all-file
+```
+
+If pre-commit is missing on your system, you can install it (on Debian based
+system) with `apt`:
+
+``` console
+$ sudo apt install pre-commit
+```
diff --git a/ansible_collections/community/postgresql/CONTRIBUTORS b/ansible_collections/community/postgresql/CONTRIBUTORS
deleted file mode 100644
index 419cd9915..000000000
--- a/ansible_collections/community/postgresql/CONTRIBUTORS
+++ /dev/null
@@ -1,230 +0,0 @@
-4n70w4
-abadger
-abguy
-abompard
-acasademont
-AceSlash
-acozine
-aioue
-Akasurde
-alanfairless
-aleksandr-vin
-Alexhha
-AlexTaran
-amarao
-amenonsen
-aminvakil
-amossc
-anasbouzid
-Andersson007
-andreaso
-andreyfedoseev
-andytom
-anis016
-ansibot
-antoinell
-arbazkhan002
-arkag
-artursvonda
-AsgerPetersen
-asifiqbal
-atombrella
-b6d
-balonik
-bcoca
-bearrito
-benformosa
-betanummeric
-billietl
-binf
-blackstar257
-bladypirat
-blindrood
-Boosai
-braderhart
-brophyja
-btoussaint
-cans
-caseyandgina
-chamini2
-Changaco
-char543
-cjewo
-cocoy
-codrinh
-CoffeDriven
-Cohedrin
-coopengo-glecomte
-csamarajeewa
-cThrice
-czenderink
-dagwieers
-dan-mcdonald
-darklajid
-davetapley
-DEvil0000
-d-fence
-dgalpaj
-Dorn-
-drob
-drrtuy
-drybjed
-dschep
-dukex
-ECRR
-elventear
-Ernest0x
-EvanDotPro
-F1rst-Unicorn
-Fale
-faruqisan
-feikesteenbergen
-felixfontein
-fessmage
-fix
-frittentheke
-gearoidibm
-geekq
-ghost
-Glandos
-gordonbondon
-gotmax23
-grasum
-gsauthof
-gsauthor
-gundalow
-Habbie
-herrewig
-hezbucho
-hunleyd
-IgorOhrimenko
-ilicmilan
-indreek
-inertialbit
-iragsdale
-Iridescens
-jacekjaros
-jamescassell
-jamesRUS52
-jborean93
-jbscalia
-jchancojr
-jd-boyd
-jegj
-jensdepuydt
-jerri
-Jhiliano
-jinnko
-jkman340
-jmcginn13
-jmighion
-jnv
-joaocc
-jochu
-johnjelinek
-joshmoore
-jzielke84
-k3rni
-keitalbame
-keithf4
-klando
-kostiantyn-nemchenko
-kustodian
-landryb
-le9i0nx
-legrostdg
-leroyguillaume
-lichensky
-loop-evgeny
-lorin
-LostInTheWoods
-MaayanMordehai
-maletin
-marcflausino
-marcosdiez
-markwort
-matburt
-matonb
-mator
-mattclay
-mattupstate
-maxamillion
-mguillaume
-michael-dev2rights
-MichaelDBA
-mjrepo2
-mkrizek
-mnietz
-mohangk
-monkz
-mribeiro
-mspanc
-mullaiarasu
-nbw74
-nergdron
-nerzhul
-nh2
-nodiscc
-nskalis
-ojc97
-pbaisla
-perezjasonr
-PeteDevoy
-phemmer
-pierot
-Piknik1990
-pilou-
-placaze
-pmauduit
-raneq
-raymondroelands
-replaced
-rgl
-rightaway
-rmfitzpatrick
-rosowiecki
-rouge8
-rtsisyk
-russoz
-sahapasci
-saito-hideki
-samccann
-samdoran
-SantiRaposo
-saxus
-sbulage
-ScottSturdivant
-seanknox
-sebasmannem
-set-db-id
-sfilipov
-SHUFIL
-silvio
-skilyazhnev
-snopoke
-strk
-tartansandal
-Tas-sos
-tcraxs
-tedder
-tiggi
-till
-tinproject
-TJEvans
-tom-clx
-tomscytale
-Trikke76
-truki
-tYYGH
-Vanav
-veger
-vfoucault
-vmalloc
-vosmax
-willthames
-wrosario
-wvidana
-yteraoka
-zikalino
-zswanson
-zyitingftnt
diff --git a/ansible_collections/community/postgresql/FILES.json b/ansible_collections/community/postgresql/FILES.json
index 59d622bc0..4302f209c 100644
--- a/ansible_collections/community/postgresql/FILES.json
+++ b/ansible_collections/community/postgresql/FILES.json
@@ -32,7 +32,7 @@
"name": ".azure-pipelines/scripts/combine-coverage.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e34d4e863a65b9f53c4ca8ae37655858969898a949e050e9cb3cb0d5f02342d0",
+ "chksum_sha256": "3311b626f96165acfea0b76c4f6488867f7c9c4e67163f09b8618d4faa914cb0",
"format": 1
},
{
@@ -67,7 +67,7 @@
"name": ".azure-pipelines/scripts/time-command.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0232f415efeb583ddff907c058986963b775441eaf129d7162aee0acb0d36834",
+ "chksum_sha256": "fcf41d12a2ed5304e9946f9cb7a0350db169f66a60ebd8e4063708e512dd334a",
"format": 1
},
{
@@ -109,7 +109,7 @@
"name": ".azure-pipelines/azure-pipelines.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "41d298e610516fda313e5bfa8de7bbd1be63ccb302c42df4f21a1dc025a0d0ac",
+ "chksum_sha256": "d51571bbcb9d9cd269b46558fbd86071be6a450a189a5383a38b2da0b14b1c86",
"format": 1
},
{
@@ -158,7 +158,7 @@
"name": "changelogs/changelog.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c3e11aa29315386df71622ac86144d7ede576f54dadc87a179d96916fb844f32",
+ "chksum_sha256": "b9669874dadda6fc914c52186ac175b590b7c2c4481da2896dbfaad9d36ea263",
"format": 1
},
{
@@ -200,7 +200,7 @@
"name": "meta/runtime.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b42a308d6db3b0062a9cb8490d522b2369a1b2f502103f2a1188ecad45078f44",
+ "chksum_sha256": "c64894306db0b7108ddb9ee565813b867547f728cfb8b00807e2e14dbda5c7d4",
"format": 1
},
{
@@ -221,7 +221,7 @@
"name": "plugins/doc_fragments/postgres.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a5e6d7613c0b367a3cb1f0094a0ae8ecbb72f7dbbd96dadc5bf59c7e385f2fc9",
+ "chksum_sha256": "c7a33a7d1660cd9b6a60cc5adac9a53e515dcf2cd7851938e4da7625b29c692b",
"format": 1
},
{
@@ -235,35 +235,35 @@
"name": "plugins/module_utils/_version.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ae6c984a7e9dd51753ea7fcb5995d5655016dd5dc187cd9be7216ef7045f220b",
+ "chksum_sha256": "7a281b1b906a3421e2b101932abb684c6d4725d28873ea6cc38b6f030abb3e4b",
"format": 1
},
{
"name": "plugins/module_utils/database.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ae0bbf1af2bec24b4393e731ad6688e452c9ddaef4bf37925f24d935aa3ce3a7",
+ "chksum_sha256": "6633839a483b33df8118d8f316a21d182e83d65a92bc019682c10d5737fc250b",
"format": 1
},
{
"name": "plugins/module_utils/postgres.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bdb9a1aa846495b8dfe3dc8a908ad8208463dab66dd10351f0c3b76114ff18af",
+ "chksum_sha256": "6c0c09c587577a08bc190c2f3cbdebabfffa0f2678ba6fb1535124748f75cad4",
"format": 1
},
{
"name": "plugins/module_utils/saslprep.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c55980dbc037b35033ead955787ca7660e52d2502b09701394940d7c27e63590",
+ "chksum_sha256": "d999997e9b4319da69df919726afbc57215457ed9faff174a0571d681cfd6760",
"format": 1
},
{
"name": "plugins/module_utils/version.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "475a5d990c7314a0ddd22f024b7eaefd2a0f04cbf5dc1543b79b7a3fc7920f4f",
+ "chksum_sha256": "f76414cd8893472f3349c885a184ed066e806b65a856080bd7e8e78d320d28e0",
"format": 1
},
{
@@ -277,161 +277,161 @@
"name": "plugins/modules/postgresql_copy.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a18b00eb5e4c3b6602379c605f8529a434451bcaf7aa238bddafeacd0463c362",
+ "chksum_sha256": "5706a8c4b183ceb4c55f492d2421344b31e8ea9354700a440d1d14373285e10d",
"format": 1
},
{
"name": "plugins/modules/postgresql_db.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8c409cdb6d6dacceda3848e6172d607fcaa7f04395fdc40f9198df9ed5be2f30",
+ "chksum_sha256": "ee2ae220616261dee6e44204168ec6e67e5cdb89d5fb8cb8a79a3d9969800219",
"format": 1
},
{
"name": "plugins/modules/postgresql_ext.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3e22f3438fd9f169b8762a8cba2113a824cdd4239bcf9bf6a82fcf0a73cb568c",
+ "chksum_sha256": "4e715015d05e5273e6a5c78720e837a31d0b65d8c059242391602d7258401248",
"format": 1
},
{
"name": "plugins/modules/postgresql_idx.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7527a54f1aff01168c0687fca7554d4840a24b431b62c75adf21625ee76d307c",
+ "chksum_sha256": "3113e2c7531aaf65c8c5996cdd0906d4a3a4ad603a7eb90ec6c2a61011ef8dbb",
"format": 1
},
{
"name": "plugins/modules/postgresql_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e9220a9def51d2549f791b20925ade84bac4b1f6b11d8e9ea3301abbeabd45e6",
+ "chksum_sha256": "3709f46d48e00f548fbb352ef30a7cc6530ebff7fd67a08723c1e70018a5059c",
"format": 1
},
{
"name": "plugins/modules/postgresql_lang.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bc59aa40e8ce754b1c36793037f1db5f40bdcd240a1a79db03d17f2a532c53f7",
+ "chksum_sha256": "e82581b2d818da4f6dc92816f20d465617553157829e5fddc4ededc03d0a8013",
"format": 1
},
{
"name": "plugins/modules/postgresql_membership.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b3aba16398d37253ebe13585766b4296a63597fb4d5f6f6c4107f305e848d778",
+ "chksum_sha256": "7e0320411240c7b39540357ad4c5a0bb7a336a4aefddeca6b97abf4e5873cd4b",
"format": 1
},
{
"name": "plugins/modules/postgresql_owner.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "de4c4d00203e534c8153a9b89100c52e4fffe53716534bcc6381370960df6bea",
+ "chksum_sha256": "4c10ea66f5e06030b891349042607ceaea7ca961ef8af5c607600372483b9a67",
"format": 1
},
{
"name": "plugins/modules/postgresql_pg_hba.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6eb9946b5dbf34c28c4df8a7560e360a7d0deb52e8219d334bbaee20b5958f60",
+ "chksum_sha256": "e2cc5d06bd1e7eb4662cb5183b0e5ce7af9ce5ce5b6861fa877e7fdcda358406",
"format": 1
},
{
"name": "plugins/modules/postgresql_ping.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5214f3a6fade4670db83abfca1d53cc2e096f8f1c6f9f130c2cead028f526f7d",
+ "chksum_sha256": "c640dc9d74ec6cc08742905b5fa60b6c401e09f3f137976b3281ed6fbed7bab0",
"format": 1
},
{
"name": "plugins/modules/postgresql_privs.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "09a8b6d073b82e735cfb171bc94259cfffc83be36fdf9d21c9bed8d061d87625",
+ "chksum_sha256": "84b979c32e98cbe03a96ff07b009e5c53a24910289498dd2ba15e850417bbe66",
"format": 1
},
{
"name": "plugins/modules/postgresql_publication.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4c99476190a90b080425dbc4d51aacca6a9596ff83eb106cef3b65ebbbaa027f",
+ "chksum_sha256": "ebd97ee3fb70fcf4b0847fb4b27b7b8e8777b001e9a35356553c214d170ea281",
"format": 1
},
{
"name": "plugins/modules/postgresql_query.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0f1b18a99606eb8f1a6b429902a285b469cc587aba98054b8802e4fd80bbd519",
+ "chksum_sha256": "96fecb7c3958176f98c7197b6978d0c15ef2201e87b8fe88cbcb156b947a8a56",
"format": 1
},
{
"name": "plugins/modules/postgresql_schema.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8087b11aac6f47620807bd31d7b88fa6e1370dcb177beb31d14f1d1b9b239c34",
+ "chksum_sha256": "c14a105c2f0524d668e3592332ad1f90ff70653d354cc47cf486b9d447e2fdef",
"format": 1
},
{
"name": "plugins/modules/postgresql_script.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6b7c75cfc2254d91fdf1949ef37548fd3b053cf431ea80d26f557d11b36331f9",
+ "chksum_sha256": "c1f5fe2a12e04c6d60575247b0829a0ab2a91c4bc548f3da08b815a15b1795fb",
"format": 1
},
{
"name": "plugins/modules/postgresql_sequence.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a37fa35888dab62628d7c95bd0a6eb2f8fa0eeb8e45df63dfd1a757d58016929",
+ "chksum_sha256": "7c7b935501f035fdc762201ded31e1dc1a83cb2fce067a4826d8994d721454cd",
"format": 1
},
{
"name": "plugins/modules/postgresql_set.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "52d343f5f3d581072060b4ed6a76f685f75d551f0dc71e5ca06b3b66b5b586fe",
+ "chksum_sha256": "5619f70e1d2d7fd7cb54d6c67e1b77c98c4e1715dcb22083ea7596eef43fa2ee",
"format": 1
},
{
"name": "plugins/modules/postgresql_slot.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "aefaa8ec911503aced0a01eed6d0af599a86107e679e427ed0a92a64746275f7",
+ "chksum_sha256": "49fde6fafd0e87b849aacede12188b7cc9b18897fc050b4923e275b24b756990",
"format": 1
},
{
"name": "plugins/modules/postgresql_subscription.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f27e097da06f819773eb75fa2ce05ad1300882ceb082914354082a2480aa9554",
+ "chksum_sha256": "175e8d28444494201bbf0587ff03f66dad92edeb1a13570e46a86830d947251e",
"format": 1
},
{
"name": "plugins/modules/postgresql_table.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cddbf54618e293cfed69350a05ca311f38a644d45e8e0f5be83a2ceffe1a8a72",
+ "chksum_sha256": "b17fcb050967d6548695bbfc9c93f3eba9e1624bee59484a67372d3002c21691",
"format": 1
},
{
"name": "plugins/modules/postgresql_tablespace.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "526804aa5f0d4a2aa07853ae4cfc6b728e547b71598f996da94b68e7e9dcfcb4",
+ "chksum_sha256": "73ea596342bae900f214ff9ce2ae338dc31b6d8049288ef9c0f10eef51e4e108",
"format": 1
},
{
"name": "plugins/modules/postgresql_user.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f50548605c180c66f01364dc59dd6ea3f7fbb01028b8a4bb7193b6a9c78f1582",
+ "chksum_sha256": "dfd8848754d58778de8d6e26631fb46b2945f1e899840e96b935f5636467bfd5",
"format": 1
},
{
"name": "plugins/modules/postgresql_user_obj_stat_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1cefc5b44bbd893bad22aa2952699a94aded1e3aba28092a4bad8a1949252c37",
+ "chksum_sha256": "e0aa5b156bb66d91e18fd38e547cadee0b3ca131f318663b491070f4d3463d43",
"format": 1
},
{
@@ -522,7 +522,7 @@
"name": "tests/integration/targets/postgresql_db/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "11d903913550d93aaffcda9458d70349ce6e703cf071e922c8124dc24b7f9cdb",
+ "chksum_sha256": "8e0c549afe5fdabc6ecdb462d1dd9383856a9de08c7b1befcee28bb1cfa34c4d",
"format": 1
},
{
@@ -550,7 +550,7 @@
"name": "tests/integration/targets/postgresql_db/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7d950960129fed71c1e93223b6236cd693c66d8bccba1154f62201f1db287c17",
+ "chksum_sha256": "610d83c94a518765ad79b957b76e20a751952ed15d02c2b8ce5c7910fe8f38dc",
"format": 1
},
{
@@ -561,6 +561,13 @@
"format": 1
},
{
+ "name": "tests/integration/targets/postgresql_db/tasks/postgresql_db_comment.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "8620099ddd001e78c893dee552f013e34c1b424dc4fa70e7393f271159106c74",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/postgresql_db/tasks/postgresql_db_general.yml",
"ftype": "file",
"chksum_type": "sha256",
@@ -571,7 +578,7 @@
"name": "tests/integration/targets/postgresql_db/tasks/postgresql_db_initial.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6b8632b1b5caaadee859948072f7083858b39c5399278b7df135daa2bc3b13bd",
+ "chksum_sha256": "c4916aa2f1a918146e862c556a40f9a28fd0eedb50ddc0cd273f1f9a2ed62a23",
"format": 1
},
{
@@ -655,7 +662,7 @@
"name": "tests/integration/targets/postgresql_ext/tasks/postgresql_ext_initial.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "15f44b7169d69b892328252ba599949389ca63c427cd4302c6ef399bb4036b98",
+ "chksum_sha256": "7aca5747d3f4dfa0ba65307fad479db92fb6f3fe16d01fa81d6f4d6d1daaf147",
"format": 1
},
{
@@ -669,7 +676,7 @@
"name": "tests/integration/targets/postgresql_ext/tasks/postgresql_ext_version_opt.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cfd80e8736e13290c4dc2c4e192feb9709044d3d4a627c487e242a751c046143",
+ "chksum_sha256": "dc0b23755c5eb52354cabdbdf7bb9a5a1b8d786154a7b129ab5d224502b100e8",
"format": 1
},
{
@@ -746,7 +753,7 @@
"name": "tests/integration/targets/postgresql_info/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a3506fe6d008386fb0503c072d97973117bb79ad293ad91e000a9c3ce4c3ba7d",
+ "chksum_sha256": "adcabc9849ea03d5b053158644cfb68d528eff27d6088ca5caa16928d06fc6f5",
"format": 1
},
{
@@ -760,7 +767,7 @@
"name": "tests/integration/targets/postgresql_info/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ab541e45bbbeb211496e76434bd09715e9a541449c267f449d4625b044465286",
+ "chksum_sha256": "cc91f9aaa105d7ebdf8f3ecb4801b8e815c91b8af6dbf673c2a4167399c0228e",
"format": 1
},
{
@@ -774,14 +781,14 @@
"name": "tests/integration/targets/postgresql_info/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "41aee9caccefdd5eec4b8fd1eeaea84532cd4402095e8742d0e866cc8139b5b4",
+ "chksum_sha256": "f9daa952ebb493e71dfb75b448b3bb1552c66674aa3fd1ef0d9b73020280f05a",
"format": 1
},
{
"name": "tests/integration/targets/postgresql_info/tasks/postgresql_info_initial.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fbd44018a0af971de6081938ab2d4da7c321776747fd32370bc649077bdde035",
+ "chksum_sha256": "35ebf3faf8705bdb5ab925214f91f84d3efbbafd8165302c5ef7826f29214943",
"format": 1
},
{
@@ -799,90 +806,6 @@
"format": 1
},
{
- "name": "tests/integration/targets/postgresql_lang",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/integration/targets/postgresql_lang/meta",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/integration/targets/postgresql_lang/meta/main.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "cc91f9aaa105d7ebdf8f3ecb4801b8e815c91b8af6dbf673c2a4167399c0228e",
- "format": 1
- },
- {
- "name": "tests/integration/targets/postgresql_lang/tasks",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/integration/targets/postgresql_lang/tasks/main.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "b75ee9a6bf02c5ff2f9e629a35e588e5297d1bca6463f5fc69a06aa27735d96f",
- "format": 1
- },
- {
- "name": "tests/integration/targets/postgresql_lang/tasks/postgresql_lang_add_owner_param.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "948ea39535bf70b471e77c1cbcd13c6a4b7d5e6e4bfa6e2437622c3ba8e16f29",
- "format": 1
- },
- {
- "name": "tests/integration/targets/postgresql_lang/tasks/postgresql_lang_initial.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "e4584a76cf4cf30ac1358827b4cbe45dfcb5b72bcb135e2ee54ea51bd171ad06",
- "format": 1
- },
- {
- "name": "tests/integration/targets/postgresql_lang/vars",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/integration/targets/postgresql_lang/vars/CentOS-7.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "a2395b707eb60229acffb97605104820a7f00a23d83d63d90e353929e97fb4e9",
- "format": 1
- },
- {
- "name": "tests/integration/targets/postgresql_lang/vars/CentOS-8.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "a5b45ee4b79b491c7c057d1c4c940df1ef7fa8e7fa6e1d006cbb1f839eeca40d",
- "format": 1
- },
- {
- "name": "tests/integration/targets/postgresql_lang/vars/default.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
- "format": 1
- },
- {
- "name": "tests/integration/targets/postgresql_lang/aliases",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "9c3727573ab082cf9663d6af87da5aba1a250004f96e94811cfe3e435de28f6f",
- "format": 1
- },
- {
"name": "tests/integration/targets/postgresql_membership",
"ftype": "dir",
"chksum_type": null,
@@ -998,7 +921,7 @@
"name": "tests/integration/targets/postgresql_owner/tasks/postgresql_owner_initial.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "dec6d60389b250e99e4e921f63194be772a2f7ca18db43cb560fb1af40336a9f",
+ "chksum_sha256": "c2976b218eb2aaf5a038ead9936c63528e4b9f7f4de5ffdb86e0be278f8f49f9",
"format": 1
},
{
@@ -1068,7 +991,7 @@
"name": "tests/integration/targets/postgresql_pg_hba/tasks/postgresql_pg_hba_initial.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e101fbb7da23884928d57b0d1db0f05e3161eea29e04aa93a972703fac28ddf9",
+ "chksum_sha256": "ddaf5fcd9ad9f687e31a6924101ce51ac0692bfe4930f4b6bf6f82968e797c3f",
"format": 1
},
{
@@ -1086,17 +1009,17 @@
"format": 1
},
{
- "name": "tests/integration/targets/postgresql_ping/defaults",
+ "name": "tests/integration/targets/postgresql_ping/handlers",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/postgresql_ping/defaults/main.yml",
+ "name": "tests/integration/targets/postgresql_ping/handlers/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ee4c4c179b3e7fdde23d8cf3a4855188e229f2a4ba2828bb3dd8b0a6a1365aea",
+ "chksum_sha256": "f0e424b6d9aa41327dac421608071f2cdba5f812140930ee5493a73763f6ece4",
"format": 1
},
{
@@ -1124,14 +1047,28 @@
"name": "tests/integration/targets/postgresql_ping/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "115c090f1029bac19af8970417d5e50b212a935c55a2d23059175fdb308f3b92",
+ "chksum_sha256": "4bea40334e7a95f3a11239803cbf27ec53a1f8b9543df1e6f34d1b4cd649f34a",
"format": 1
},
{
"name": "tests/integration/targets/postgresql_ping/tasks/postgresql_ping_initial.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f2b1244d57e5b287a6ae73864218c3ed352db0d947ad6bfd4a68a5691a557ebc",
+ "chksum_sha256": "36c47bfcf55153dc6dea950e51c6f8595038475b01dc02d983a1cd23cca8c5f7",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/postgresql_ping/vars",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/postgresql_ping/vars/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "3bb217ec9eb9db6a12457c99a06f9f9d510526cd167ce8d884267792b0669f51",
"format": 1
},
{
@@ -1201,14 +1138,14 @@
"name": "tests/integration/targets/postgresql_privs/tasks/postgresql_privs_general.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "96211bd4e4c063d0ff264f11759bf60bf6a7d788eac99829a6c36788e683e06c",
+ "chksum_sha256": "e6d065e8cb0fbfc8b06b4ef8c4bcb3dd7b36154d406f1c6e36bb006105c83c1b",
"format": 1
},
{
"name": "tests/integration/targets/postgresql_privs/tasks/postgresql_privs_initial.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5f1f4ba86290047039bb1562f7bd2171508f5103c06513132c22fdaa833461e0",
+ "chksum_sha256": "981192ad174194d54af959c4cc6354688c4ecff0497198588d2dd50253e8350d",
"format": 1
},
{
@@ -1222,7 +1159,7 @@
"name": "tests/integration/targets/postgresql_privs/tasks/test_target_role.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c9e749fe3d9b2172ca69efe4bf6072d0fcaebd5b8d291684471af479e0502a5d",
+ "chksum_sha256": "26f34a0ecf7dfc9b33a51c430e57c51341f02ff28326a8a475f2d686816ef92b",
"format": 1
},
{
@@ -1271,7 +1208,7 @@
"name": "tests/integration/targets/postgresql_publication/tasks/postgresql_publication_initial.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "22d46a9a422663a28385e66709700895dceb8c31f6ff5b621c1d055f54e83703",
+ "chksum_sha256": "661eef67dc43cfa3df87e5dbcc8703f7e62e1c62d0fb1ae23681cefeb68db262",
"format": 1
},
{
@@ -1289,27 +1226,6 @@
"format": 1
},
{
- "name": "tests/integration/targets/postgresql_query/files",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/integration/targets/postgresql_query/files/test0.sql",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "b2dc19f190b86228709bced10068509a40c6141f8347a3c0cce52b3f787e1876",
- "format": 1
- },
- {
- "name": "tests/integration/targets/postgresql_query/files/test1.sql",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "8de29e382b1af32c9352400d107e16d232405cc50c126ae7f99a5a0879f34320",
- "format": 1
- },
- {
"name": "tests/integration/targets/postgresql_query/meta",
"ftype": "dir",
"chksum_type": null,
@@ -1341,7 +1257,7 @@
"name": "tests/integration/targets/postgresql_query/tasks/postgresql_query_initial.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f63e7d48deecded04b2273fddd1c4199c315ab88b00447c94ea7064c0369cd5c",
+ "chksum_sha256": "e15f63b055d4271cca4f76f743fdd0c566c12bb46c67d955288dd15855c8943a",
"format": 1
},
{
@@ -1404,7 +1320,7 @@
"name": "tests/integration/targets/postgresql_schema/tasks/postgresql_schema_initial.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5be03157af9f62f7caa17e5ad3dc289cf7b59289fa700cc0d9b930d3cbbdc1d5",
+ "chksum_sha256": "ddbc191e9aec6315913bf97268f5ab2c8d338e07333c960a60ac01a8b04d0d10",
"format": 1
},
{
@@ -1684,7 +1600,7 @@
"name": "tests/integration/targets/postgresql_set/tasks/options_coverage.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f312eb39567039be39982c9ce88aef490b1935622bcb05b056d3ba49b6f4f5e1",
+ "chksum_sha256": "ec75b6318b9d58b65d206c7b49dc6faa4752db7ced30463ba7514d179d374a61",
"format": 1
},
{
@@ -1768,7 +1684,7 @@
"name": "tests/integration/targets/postgresql_subscription/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8104db292a951ca57fe3a0321e894ff18aad3e88d58981e3db7936f5f1d1bb34",
+ "chksum_sha256": "7549ee4e7072899f84ca40f779b02d321974d884938cfceb7243a9c85a37155a",
"format": 1
},
{
@@ -1782,7 +1698,7 @@
"name": "tests/integration/targets/postgresql_subscription/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ab541e45bbbeb211496e76434bd09715e9a541449c267f449d4625b044465286",
+ "chksum_sha256": "cc91f9aaa105d7ebdf8f3ecb4801b8e815c91b8af6dbf673c2a4167399c0228e",
"format": 1
},
{
@@ -1796,14 +1712,14 @@
"name": "tests/integration/targets/postgresql_subscription/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "eca673fddaf151a108873b2567fc9e40fb19ec24f6559355a602e983fdcf5495",
+ "chksum_sha256": "94b3acc771c7e46f783969e10f054d1b229c4897ec8e5e4bef200a5865e12d16",
"format": 1
},
{
"name": "tests/integration/targets/postgresql_subscription/tasks/postgresql_subscription_initial.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6dbb3ba2ca853ffd06bd6883fa5d23e0517237d5a27edc38bc8300fb6b33dc2f",
+ "chksum_sha256": "79b70cc9f28f38637875a1c06f229d713582169a6a420c027a322b0c92d1f75b",
"format": 1
},
{
@@ -1922,7 +1838,7 @@
"name": "tests/integration/targets/postgresql_tablespace/tasks/postgresql_tablespace_initial.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "aff3b89f4673ee60e03ac6e27421682dc328a04fcc5fabc1f477c13a27d89db5",
+ "chksum_sha256": "a07c48bb2567e354c894246d0bfcdea46695ce4f8ca275a4da3313bf578f9ef0",
"format": 1
},
{
@@ -1950,7 +1866,7 @@
"name": "tests/integration/targets/postgresql_user/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b14eed97d15235e2056971743de23709e18c00b91c358fe1e79002c98ece9d60",
+ "chksum_sha256": "d78ac5931ff0383bb350aa6a2c530e0fb853eb699ac2a800ab8979bbd069a5c4",
"format": 1
},
{
@@ -1978,14 +1894,14 @@
"name": "tests/integration/targets/postgresql_user/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0472c601119258ae89952a06b702c47ec3832b55fccc952ec8f1548a006d0f37",
+ "chksum_sha256": "6bb8f3286ac2112268a767d5f6709e291d3e238f0c820dacdfe50596119e1097",
"format": 1
},
{
"name": "tests/integration/targets/postgresql_user/tasks/postgresql_user_general.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7481301d5bc8dd240f78002e63d47b3e79ed995a6632918ae15d4b31b84650e6",
+ "chksum_sha256": "64a3301468c4970452a5c81838f6e818c62bc2fa563e920dc459ba943eae9eea",
"format": 1
},
{
@@ -1996,6 +1912,13 @@
"format": 1
},
{
+ "name": "tests/integration/targets/postgresql_user/tasks/postgresql_user_sql_ascii_db.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "3a05a112efc3c9e46f56a530684bb3660be389f05a916a171074d7265e26b7bc",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/postgresql_user/tasks/test_no_password_change.yml",
"ftype": "file",
"chksum_type": "sha256",
@@ -2069,7 +1992,7 @@
"name": "tests/integration/targets/postgresql_user_obj_stat_info/tasks/postgresql_user_obj_stat_info.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "dacef0aa7902a944e61a6bfb5bd1d4f13a065e63a18d271bfd1099e78df2637f",
+ "chksum_sha256": "cb7a981fa53ff3a756d9fa21e5770b9c2781f7cd85f6298761da61e4e368f25e",
"format": 1
},
{
@@ -2118,7 +2041,7 @@
"name": "tests/integration/targets/setup_postgresql_db/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "254d5cd2cd0525f306778e08c6d9b445e21558fc4f7ecfb20fc86df61969e8da",
+ "chksum_sha256": "38ef024a32b46ef9d0c1d85fed01ae7bec95a70079179eab12d8ca25d3844575",
"format": 1
},
{
@@ -2251,147 +2174,98 @@
"name": "tests/integration/targets/setup_postgresql_db/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8e061afedc2f4520674a2a3136e9c15cfca871eaef9a1d4a2beed9609352be08",
+ "chksum_sha256": "bc4909649a39466b2f04e5aa252c5e06ca5d811b5d570cd6d348fab35d14a385",
"format": 1
},
{
- "name": "tests/integration/targets/setup_postgresql_db/tasks/ssl.yml",
+ "name": "tests/integration/targets/setup_postgresql_db/tasks/replica.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fb482e7ee6912b74be31f9fe6b254a87d1717f9d40ae8823e2913331b9586ad7",
+ "chksum_sha256": "1a66dfc51cae0323a69b33ecf901d4892f5c27b78b896ceb602c7d7024c417f7",
"format": 1
},
{
- "name": "tests/integration/targets/setup_postgresql_db/vars",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/integration/targets/setup_postgresql_db/vars/Debian-8.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "ea1cab96532e023ca4622a31488dd6226c60eb755817868f874c083f8e991eb8",
- "format": 1
- },
- {
- "name": "tests/integration/targets/setup_postgresql_db/vars/RedHat-py3.yml",
+ "name": "tests/integration/targets/setup_postgresql_db/tasks/sql_ascii.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "150c49cf5d8c40a44f33a543d4fb288a952517bbebd367ca223f068e3417c5e1",
+ "chksum_sha256": "36f1490ca93218409cc8027a2b2ab4e0906ff03f2d6b8d32a582bf4c41467948",
"format": 1
},
{
- "name": "tests/integration/targets/setup_postgresql_db/vars/RedHat.yml",
+ "name": "tests/integration/targets/setup_postgresql_db/tasks/ssl.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5252a9c72186f877dcc99a3b66a053474f180248404a39f55da78b1546c95ee2",
+ "chksum_sha256": "fb482e7ee6912b74be31f9fe6b254a87d1717f9d40ae8823e2913331b9586ad7",
"format": 1
},
{
- "name": "tests/integration/targets/setup_postgresql_db/vars/Ubuntu-20-py3.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "94dc4796606b2bcdca95aba5eefe79a1b4e36cb5c600b15badbc1673340a5ecd",
+ "name": "tests/integration/targets/setup_postgresql_db/vars",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/setup_postgresql_db/vars/default-py3.yml",
+ "name": "tests/integration/targets/setup_postgresql_db/vars/Debian-8.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3a88e7f3bdc87e6e9f0a5d02df8672112dba29116fc4ce278eecabc2906f786d",
+ "chksum_sha256": "5bba8a6c488923638e8a1a2b3f4f7445c27c94e5304a01f714095b0dcafea6dd",
"format": 1
},
{
- "name": "tests/integration/targets/setup_postgresql_db/vars/default.yml",
+ "name": "tests/integration/targets/setup_postgresql_db/vars/Fedora-36-py3.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "577e120caebb25a1c1fcafe4991d83e838ca9ef1b18301e2a66e4565057af8e9",
+ "chksum_sha256": "f30fad67c6bae9b0e8118ac1b3b4017352765929a676a91188ed909a59ae4c3e",
"format": 1
},
{
- "name": "tests/integration/targets/setup_postgresql_replication",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/integration/targets/setup_postgresql_replication/defaults",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/integration/targets/setup_postgresql_replication/defaults/main.yml",
+ "name": "tests/integration/targets/setup_postgresql_db/vars/Fedora-38-py3.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "15c12558d8848d3b44b4f14324e6b02888ed48fa609fee2329180b92e59d3fe1",
- "format": 1
- },
- {
- "name": "tests/integration/targets/setup_postgresql_replication/handlers",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
+ "chksum_sha256": "e1b2168aa6e8ed71a0e798d242fcb4ee512246eefa54a913423287b910436381",
"format": 1
},
{
- "name": "tests/integration/targets/setup_postgresql_replication/handlers/main.yml",
+ "name": "tests/integration/targets/setup_postgresql_db/vars/RedHat-py3.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8a6de4eb2d6d7b2702fe7d970e239c4f4a4f8f31643a18628f9363e63bce4cb6",
+ "chksum_sha256": "ff19411262382d7c97cbb6e6b653fb781e8291d752e0816006ea948c610b9da9",
"format": 1
},
{
- "name": "tests/integration/targets/setup_postgresql_replication/tasks",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/integration/targets/setup_postgresql_replication/tasks/main.yml",
+ "name": "tests/integration/targets/setup_postgresql_db/vars/RedHat.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "332fef4bb8a02f7be01b7dea5632ce4608b2aabe87c40464048aa3e172804108",
+ "chksum_sha256": "963f35abad92c7ef89c14dd107f9a34e40bab06200d7d4fe6fd822021db9b69f",
"format": 1
},
{
- "name": "tests/integration/targets/setup_postgresql_replication/tasks/setup_postgresql_cluster.yml",
+ "name": "tests/integration/targets/setup_postgresql_db/vars/Ubuntu-20-py3.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "926f8633822359ea7a106ede40c8913368ed8420c70abccf9ddf623aab6b057e",
+ "chksum_sha256": "ae02d1fc9a308fb0b4643a3200a4712622c09bef0df46ccfcd9b7dbbb0144d1a",
"format": 1
},
{
- "name": "tests/integration/targets/setup_postgresql_replication/templates",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/integration/targets/setup_postgresql_replication/templates/pg_hba.conf.j2",
+ "name": "tests/integration/targets/setup_postgresql_db/vars/Ubuntu-22-py3.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9b3e39d80a8a59947b5fba38e8db942a1933ffefcef368cd13a5594fc2f65668",
+ "chksum_sha256": "c897bcf7d1e0116c886423886d8a875b2cf8f3c0e8cdb6111b2b3e75945f2b9a",
"format": 1
},
{
- "name": "tests/integration/targets/setup_postgresql_replication/templates/primary_postgresql.conf.j2",
+ "name": "tests/integration/targets/setup_postgresql_db/vars/default-py3.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4e40eae546ddaeff2de7356ece590b70001f976feb6c07b0c83a9fd1b86ea23d",
+ "chksum_sha256": "a66ab99eac91dfeed26beb4980cd2116e3033857acc6ad7b63b820e8372d5544",
"format": 1
},
{
- "name": "tests/integration/targets/setup_postgresql_replication/templates/replica_postgresql.conf.j2",
+ "name": "tests/integration/targets/setup_postgresql_db/vars/default.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2a70a2f2e5beaa52cefcc93461ca067ef2b665b859a468cbe74d27464253bc6e",
+ "chksum_sha256": "a74f2e663ed988e7c19149e3746beec16adb2fe48582fcb267002b0450e4782d",
"format": 1
},
{
@@ -2419,42 +2293,49 @@
"name": "tests/sanity/extra/no-unwanted-files.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f1468e7b22ba353d18fcf2f5b18607873f792de629f887798f081eb6e2cd54fc",
+ "chksum_sha256": "71dadb137e8d21b7ed325205def87767bd39308398f399b1b328c3af3f788a7d",
"format": 1
},
{
"name": "tests/sanity/ignore-2.12.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0a7c2f4de6f288675dfebc1f6fbb808728c3ef1bec1a29fe2adb80199372621f",
+ "chksum_sha256": "a856b96e287379255c9014609dfe9c7b6f5205f4631fc45dbf93be935c5bba26",
"format": 1
},
{
"name": "tests/sanity/ignore-2.13.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0a7c2f4de6f288675dfebc1f6fbb808728c3ef1bec1a29fe2adb80199372621f",
+ "chksum_sha256": "a856b96e287379255c9014609dfe9c7b6f5205f4631fc45dbf93be935c5bba26",
"format": 1
},
{
"name": "tests/sanity/ignore-2.14.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0a7c2f4de6f288675dfebc1f6fbb808728c3ef1bec1a29fe2adb80199372621f",
+ "chksum_sha256": "a856b96e287379255c9014609dfe9c7b6f5205f4631fc45dbf93be935c5bba26",
"format": 1
},
{
"name": "tests/sanity/ignore-2.15.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "788d3f00aec392d2c4740329b80911a6b2621e975148d07c2cb9c53d3f736783",
+ "chksum_sha256": "c9621b54c948cd3473ba21add8cbff189ccd914fc00aec1dfdd19cbdb5ce7eb6",
"format": 1
},
{
"name": "tests/sanity/ignore-2.16.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "788d3f00aec392d2c4740329b80911a6b2621e975148d07c2cb9c53d3f736783",
+ "chksum_sha256": "c9621b54c948cd3473ba21add8cbff189ccd914fc00aec1dfdd19cbdb5ce7eb6",
+ "format": 1
+ },
+ {
+ "name": "tests/sanity/ignore-2.17.txt",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f1e2e4351ae7e8b366042aef4f75e1a4df73a64203296484944df297ddbfbdf0",
"format": 1
},
{
@@ -2489,14 +2370,14 @@
"name": "tests/unit/plugins/module_utils/test_postgres.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5c08f2ecc41169ebd451837abd543a5102ece6befcff0e70f9ad06acd4d6ee5c",
+ "chksum_sha256": "d1cdf011913cf9b2056bfa4982cde3856f400fea81f6a1c3444a10c32e27270a",
"format": 1
},
{
"name": "tests/unit/plugins/module_utils/test_saslprep.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f5e044a935e091aaf52115d3f3238bcd32b3627f9cebac26bd1d6d52aa339953",
+ "chksum_sha256": "bf0be697f88d5a76edba65f28f158b0fb74534ec245e0c855ae1f0e83f61f73c",
"format": 1
},
{
@@ -2517,7 +2398,7 @@
"name": "tests/unit/plugins/modules/test_postgresql_set.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1a9478ec6a1548cb1ddf26fea59ef25dea5755340634495d9128f55c22aafce3",
+ "chksum_sha256": "7dc3ce190a662d7b14459ff100ca119164b9f13eaf11713d4dcf46858af6d899",
"format": 1
},
{
@@ -2559,7 +2440,7 @@
"name": "tests/utils/shippable/check_matrix.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "163dc2e4b0fb28faa6a03c02c7a5b2e470ca156e119943bf1d8bbf5efff02c18",
+ "chksum_sha256": "5a6f19f42a2051a181675c8d407c99f1bcf6ac9a3449d4fe51a5552e2582343f",
"format": 1
},
{
@@ -2587,14 +2468,14 @@
"name": "tests/utils/shippable/shippable.sh",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d1ea59d27bbe21954ece52642108b4fd10d3f526d8efa25de875b61cdea180a3",
+ "chksum_sha256": "1e5643958e0f7cea4a3189ac7184d66a174c61b81fa04bc7452d173a2366c2b0",
"format": 1
},
{
"name": "tests/utils/shippable/timing.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ebb7d3553349747ad41d80899ed353e13cf32fcbecbb6566cf36e9d2bc33703e",
+ "chksum_sha256": "fae44c549a138aa795cc2bf757cc812fa7969b914fc5f79fb42530c48c11052a",
"format": 1
},
{
@@ -2626,24 +2507,45 @@
"format": 1
},
{
- "name": "CHANGELOG.rst",
+ "name": ".codespell-exclude-words",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2be3a33e5081dc3262b52ce0600fac4942cac650e3ccde5ba1f4aaeee59077a9",
+ "chksum_sha256": "7896ec8e2f0c01ed844b1e1227decd106137960d931248a54ef005021e7d63c8",
"format": 1
},
{
- "name": "CONTRIBUTING.md",
+ "name": ".codespellrc",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b0c50cf3715d59964a341dc651a6f626322209ef9fa8c0d03047d3a2b2e420a4",
+ "chksum_sha256": "746de3b92c186ceb2a9f20921a53b24523414c0af7441849e2018f14c16c3139",
"format": 1
},
{
- "name": "CONTRIBUTORS",
+ "name": ".flake8",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f43fe39043d7329c341144c785599aa3dd3d262ae6876ef257c7a49547151ae4",
+ "chksum_sha256": "4e97598aa712d2251fd3e645f9bc94be719c72a5ca2a61a21b3474b5e128a51d",
+ "format": 1
+ },
+ {
+ "name": ".pre-commit-config.yaml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "d69be06ce29c020f1f64f67d13d7c7b4867b630c1470f6a7286785571e46f74d",
+ "format": 1
+ },
+ {
+ "name": "CHANGELOG.rst",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "02924d737dff1a6dd5b7e9a137a2c426526ec976780e141bfdfb3262e29557b6",
+ "format": 1
+ },
+ {
+ "name": "CONTRIBUTING.md",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e1b3cbadfbb785585ca2c984365edef37a0d813798ad5c8ea7c296135045f9ee",
"format": 1
},
{
@@ -2664,7 +2566,7 @@
"name": "MAINTAINING.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2435665a6562d5f3841fff1631970f95f0466c498e949d2b8579ccc2a0b810ad",
+ "chksum_sha256": "8b3d09e5ba80c8515ad6c99d36bf59324f9e44e27613a510faacb457d0d06685",
"format": 1
},
{
@@ -2678,7 +2580,7 @@
"name": "README.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c7ef341ae1187f4ad2b6b2505899075ab5dbe06ebd138058055c59f1ef1ebffc",
+ "chksum_sha256": "522dc34d303faf3a818d0a57b1a7b9a7338f3acdadd55de2226ef7720765246f",
"format": 1
},
{
@@ -2701,6 +2603,13 @@
"chksum_type": "sha256",
"chksum_sha256": "f6036f79d054f42e11f2dd52458b4d2282e901d197955e598bf1a23600280cf0",
"format": 1
+ },
+ {
+ "name": "tox.ini",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "24fc228f3c3d845aae0da238b99db74d24f5914be86245b3a04897367aa3ac31",
+ "format": 1
}
],
"format": 1
diff --git a/ansible_collections/community/postgresql/MAINTAINING.md b/ansible_collections/community/postgresql/MAINTAINING.md
index 9fad0d343..1e511e6dd 100644
--- a/ansible_collections/community/postgresql/MAINTAINING.md
+++ b/ansible_collections/community/postgresql/MAINTAINING.md
@@ -1,3 +1,3 @@
# Maintaining this collection
-Refer to the [Maintainer guidelines](https://github.com/ansible/community-docs/blob/main/maintaining.rst).
+Refer to the [Maintainer guidelines](https://docs.ansible.com/ansible/devel/community/maintainers.html).
diff --git a/ansible_collections/community/postgresql/MANIFEST.json b/ansible_collections/community/postgresql/MANIFEST.json
index 98c8a04e6..b16ee0f4d 100644
--- a/ansible_collections/community/postgresql/MANIFEST.json
+++ b/ansible_collections/community/postgresql/MANIFEST.json
@@ -2,7 +2,7 @@
"collection_info": {
"namespace": "community",
"name": "postgresql",
- "version": "2.4.2",
+ "version": "3.4.0",
"authors": [
"Ansible PostgreSQL community"
],
@@ -25,7 +25,7 @@
"name": "FILES.json",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d7e71b7ad0987031481832f772a46ae4e27dbb433409e374dca4668c74260ebd",
+ "chksum_sha256": "87d0437e40df1ddaf3161d1baaf5340d03e0c8983c7326257fab831e5f47e682",
"format": 1
},
"format": 1
diff --git a/ansible_collections/community/postgresql/README.md b/ansible_collections/community/postgresql/README.md
index 076239137..fde669888 100644
--- a/ansible_collections/community/postgresql/README.md
+++ b/ansible_collections/community/postgresql/README.md
@@ -5,6 +5,19 @@
This collection is a part of the Ansible package.
+## Our mission
+
+At the `community.postgresql` Ansible collection project,
+our mission is to produce and maintain simple, flexible,
+and powerful open-source software tailored to automating PostgreSQL-related tasks.
+
+We welcome members from all skill levels to participate actively in our open, inclusive, and vibrant community.
+Whether you are an expert or just beginning your journey with Ansible and PostgreSQL,
+you are encouraged to contribute, share insights, and collaborate with fellow enthusiasts.
+
+We strive to make managing PostgreSQL deployments as effortless and efficient as possible with automation,
+enabling users to focus on their core objectives.
+
## Code of Conduct
We follow the [Ansible Code of Conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html) in all our interactions within this project.
@@ -13,11 +26,9 @@ If you encounter abusive behavior violating the [Ansible Code of Conduct](https:
## Contributing to this collection
-The content of this collection is made by [people](https://github.com/ansible-collections/community.postgresql/blob/main/CONTRIBUTORS) just like you, a community of individuals collaborating on making the world better through developing automation software.
-
-We are actively accepting new contributors.
+The content of this collection is made by [people](https://github.com/ansible-collections/community.postgresql/graphs/contributors) just like you; a community of individuals collaborating on making the world better through developing automation software.
-All types of contributions are very welcome.
+We are actively accepting new contributors and all types of contributions are very welcome.
You don't know how to start? Refer to our [contribution guide](https://github.com/ansible-collections/community.postgresql/blob/main/CONTRIBUTING.md)!
@@ -37,20 +48,27 @@ To learn how to maintain / become a maintainer of this collection, refer to the
It is necessary for maintainers of this collection to be subscribed to:
* The collection itself (the `Watch` button -> `All Activity` in the upper right corner of the repository's homepage).
-* The "Changes Impacting Collection Contributors and Maintainers" [issue](https://github.com/ansible-collections/overview/issues/45).
+* The [news-for-maintainers repository](https://github.com/ansible-collections/news-for-maintainers).
They also should be subscribed to Ansible's [The Bullhorn newsletter](https://docs.ansible.com/ansible/devel/community/communication.html#the-bullhorn).
## Communication
-We announce important development changes and releases through Ansible's [The Bullhorn newsletter](https://docs.ansible.com/ansible/devel/community/communication.html#the-bullhorn). If you are a collection developer, be sure you are subscribed.
+> `GitHub Discussions` feature is disabled in this repository. Use the `postgresql` tag on the forum in the [Project Discussions](https://forum.ansible.com/new-topic?title=topic%20title&body=topic%20body&category=project&tags=postgresql) or [Get Help](https://forum.ansible.com/new-topic?title=topic%20title&body=topic%20body&category=help&tags=postgresql) category instead.
-Join us on Matrix in:
+We announce important development changes and releases through Ansible's [The Bullhorn newsletter](https://docs.ansible.com/ansible/devel/community/communication.html#the-bullhorn). If you are a collection developer, be sure you are subscribed.
-* `#postgresql:ansible.com` [room](https://matrix.to/#/#postgresql:ansible.com): questions on how to contribute and use this collection.
-* `#users:ansible.com` [room](https://matrix.to/#/#users:ansible.com): general use questions and support.
-* `#ansible-community:ansible.com` [room](https://matrix.to/#/#community:ansible.com): community and collection development questions.
-* other Matrix rooms or corresponding bridged Libera.Chat channels. See the [Ansible Communication Guide](https://docs.ansible.com/ansible/devel/community/communication.html) for details.
+Join [our team](https://forum.ansible.com/g/PostgreSQLTeam?asc=true&order=) on:
+* The Ansible forums:
+ * [News & Announcements](https://forum.ansible.com/c/news/5/none)
+ * [Get Help](https://forum.ansible.com/c/help/6/none)
+ * [Social Spaces](https://forum.ansible.com/c/chat/4)
+ * [Posts tagged 'postgresql'](https://forum.ansible.com/tag/postgresql)
+* Matrix:
+ * `#postgresql:ansible.com` [room](https://matrix.to/#/#postgresql:ansible.com): questions on how to contribute and use this collection.
+ * `#users:ansible.com` [room](https://matrix.to/#/#users:ansible.com): general use questions and support.
+ * `#ansible-community:ansible.com` [room](https://matrix.to/#/#community:ansible.com): community and collection development questions.
+ * other Matrix rooms or corresponding bridged Libera.Chat channels. See the [Ansible Communication Guide](https://docs.ansible.com/ansible/devel/community/communication.html) for details.
We take part in the global quarterly [Ansible Contributor Summit](https://github.com/ansible/community/wiki/Contributor-Summit) virtually or in-person. Track [The Bullhorn newsletter](https://docs.ansible.com/ansible/devel/community/communication.html#the-bullhorn) and join us.
@@ -58,31 +76,48 @@ For more information about communication, refer to the [Ansible Communication gu
## Governance
-We, [the PostgreSQL working group](https://github.com/ansible-collections/community.postgresql/wiki/PostgreSQL-Working-Group), use [the community pinboard](https://github.com/ansible-collections/community.postgresql/issues/30) for general announcements and discussions.
+We, [the PostgreSQL working group](https://forum.ansible.com/g/PostgreSQLTeam), use [the forum](https://forum.ansible.com/tag/postgresql) posts tagged with `postgresql` for general announcements and discussions.
The process of decision making in this collection is based on discussing and finding consensus among participants.
-Every voice is important and every idea is valuable. If you have something on your mind, create an issue or dedicated discussion and let's discuss it!
+Every voice is important and every idea is valuable. If you have something on your mind, create an issue or dedicated forum [discussion](https://forum.ansible.com/new-topic?title=topic%20title&body=topic%20body&category=project&tags=postgresql) and let's discuss it!
## External requirements
-The PostgreSQL modules rely on the [Psycopg2](https://www.psycopg.org/docs/) PostgreSQL database adapter.
+The PostgreSQL modules rely on the [Psycopg](https://www.psycopg.org/) PostgreSQL database adapter.
+Both versions [Psycopg2](https://www.psycopg.org/docs/) and [Psycopg3](https://www.psycopg.org/psycopg3/docs/) are supported.
+The minimum supported and tested versions of Psycopg are 2.5.1 and 3.1.8 respectively.
+
+## Releases Support Timeline
+
+We maintain each major release version (1.x.y, 2.x.y, ...) for two years after the next major version is released.
+
+Here is the table for the support timeline:
+- 1.x.y: released 2020-11-17, supported until 2024-02-10
+- 2.x.y: released 2022-02-10, supported until 2025-06-09
+- 3.x.y: released 2023-06-09, current
+- 4.x.y: to be released; not earlier than after Ansible 10 release (~May 2024)
## Tested with ansible-core
Tested with the following `ansible-core` releases:
-- 2.12
-- 2.13
- 2.14
+- 2.15
+- 2.16
- current development version
Ansible-core versions before 2.12.0 are not supported.
Our AZP CI includes testing with the following docker images / PostgreSQL versions:
-- CentOS 7: 9.2
-- RHEL 8.3 / 8.4: 10
-- Fedora 34: 13
-- Ubuntu 20.04: 14
+| Docker image | Psycopg version | PostgreSQL version |
+|--------------|-----------------|--------------------|
+| CentOS 7 | 2.5.1 | 9.2 |
+| RHEL 8 | 2.7.5 | 10 |
+| Fedora 37 | 2.9.6 | 14 |
+| Fedora 38 | 2.9.6 | 15 |
+| Fedora 39 | 2.9.6 | 15 |
+| Ubuntu 20.04 | 2.8.6 | 15 |
+| Ubuntu 22.04 | 3.1.9 | 15 |
## Included content
@@ -132,7 +167,7 @@ collections:
- name: community.postgresql
```
-You can also download the tarball from [Ansible Galaxy](https://galaxy.ansible.com/community/postgresql) and install the collection manually wherever you need.
+You can also download the tarball from [Ansible Galaxy](https://galaxy.ansible.com/ui/repo/published/community/postgresql) and install the collection manually wherever you need.
Note that if you install the collection from Ansible Galaxy with the command-line tool or tarball, it will not be upgraded automatically when you upgrade the Ansible package. To upgrade the collection to the latest available version, run the following command:
@@ -152,10 +187,6 @@ See [Ansible Using collections](https://docs.ansible.com/ansible/latest/user_gui
See the [changelog](https://github.com/ansible-collections/community.postgresql/blob/main/CHANGELOG.rst).
-## Roadmap
-
-See the [release plan](https://github.com/ansible-collections/community.postgresql/issues/13).
-
## More information
- [Ansible Collection overview](https://github.com/ansible-collections/overview)
diff --git a/ansible_collections/community/postgresql/changelogs/changelog.yaml b/ansible_collections/community/postgresql/changelogs/changelog.yaml
index 45e4461b2..bacf00e7a 100644
--- a/ansible_collections/community/postgresql/changelogs/changelog.yaml
+++ b/ansible_collections/community/postgresql/changelogs/changelog.yaml
@@ -446,7 +446,7 @@ releases:
2.4.0:
changes:
bugfixes:
- - postgresql_info - add support for non numeric extenstion version (https://github.com/ansible-collections/community.postgresql/issues/428).
+ - postgresql_info - add support for non numeric extension version (https://github.com/ansible-collections/community.postgresql/issues/428).
- postgresql_info - when getting information about subscriptions, check the
list of available columns in the pg_subscription table (https://github.com/ansible-collections/community.postgresql/issues/429).
- postgresql_privs - fix connect_params being ignored (https://github.com/ansible-collections/community.postgresql/issues/450).
@@ -529,3 +529,152 @@ releases:
- 0-postgresql_info.yml
- 2.4.2.yml
release_date: '2023-06-09'
+ 3.0.0:
+ changes:
+ major_changes:
+ - postgresql_pg_hba - remove the deprecated ``order`` argument. The sortorder
+ ``sdu`` is hardcoded (https://github.com/ansible-collections/community.postgresql/pull/496).
+ - postgresql_privs - remove the deprecated ``usage_on_types`` argument. Use
+ the ``type`` option of the ``type`` argument to explicitly manipulate privileges
+ on PG types (https://github.com/ansible-collections/community.postgresql/issues/208).
+ - postgresql_query - remove the deprecated ``path_to_script`` and ``as_single_query``
+ arguments. Use the ``postgresql_script`` module to run queries from scripts
+ (https://github.com/ansible-collections/community.postgresql/issues/189).
+ - postgresql_user - move the deprecated ``privs`` argument removal to community.postgresql
+ 4.0.0 (https://github.com/ansible-collections/community.postgresql/issues/493).
+ - postgresql_user - remove the deprecated ``groups`` argument. Use the ``postgresql_membership``
+ module instead (https://github.com/ansible-collections/community.postgresql/issues/300).
+ release_summary: 'This is a major release of the ``community.postgresql`` collection.
+
+ This changelog contains all changes to the modules in this collection that
+
+ have been added after the release of ``community.postgresql`` 2.4.2.'
+ fragments:
+ - 0-postgresql_query.yml
+ - 1-postgresql_privs.yml
+ - 3-postgresql_user.yml
+ - 3.0.0.yml
+ - 4-postgresql_user.yml
+ - 5-postgresql_pg_hba.yml
+ release_date: '2023-06-09'
+ 3.1.0:
+ changes:
+ bugfixes:
+ - postgresql_ext - fixed queries return value name in documentation (https://github.com/ansible-collections/community.postgresql/pull/545).
+ - postgresql_privs - fixed error message and documentation (https://github.com/ansible-collections/community.postgresql/pull/510).
+ - postgresql_set - fixed GUC_LIST_QUOTE parameters (https://github.com/ansible-collections/community.postgresql/pull/521).
+ - postgresql_set - fixed error message in param_set function (https://github.com/ansible-collections/community.postgresql/pull/505).
+ deprecated_features:
+ - postgresql_lang - the module has been deprecated and will be removed in ``community.postgresql
+ 4.0.0``. Please use the ``postgresql_ext`` module instead (https://github.com/ansible-collections/community.postgresql/issues/559).
+ major_changes:
+ - postgres modules - the minimum version of psycopg2 library the collection
+ supports is 2.5.1 (https://github.com/ansible-collections/community.postgresql/pull/556).
+ minor_changes:
+ - Collection core functions - use ``get_server_version`` in all modules (https://github.com/ansible-collections/community.postgresql/pull/518)."
+ - Collection core functions - use common cursor arguments in all modules (https://github.com/ansible-collections/community.postgresql/pull/522)."
+ - postgresql_ext - added idempotence always both in standard and in check mode
+ (https://github.com/ansible-collections/community.postgresql/pull/545).
+ - postgresql_ext - added idempotence when version=latest (https://github.com/ansible-collections/community.postgresql/pull/504).
+ - postgresql_ext - added prev_version and version return values (https://github.com/ansible-collections/community.postgresql/pull/545).
+ - postgresql_ext - added queries in module output also in check mode (https://github.com/ansible-collections/community.postgresql/pull/545).
+ - postgresql_ext - improved error messages (https://github.com/ansible-collections/community.postgresql/pull/545).
+ - postgresql_privs - added idempotence when roles=PUBLIC (https://github.com/ansible-collections/community.postgresql/pull/502).
+ - postgresql_privs - added parameters privileges support for PostgreSQL 15 or
+ higher (https://github.com/ansible-collections/community.postgresql/issues/481).
+ - postgresql_privs - added support for implicit roles CURRENT_ROLE, CURRENT_USER,
+ and SESSION_USER (https://github.com/ansible-collections/community.postgresql/pull/502).
+ - postgresql_tablespace - added idempotence when dropping a non-existing tablespace
+ (https://github.com/ansible-collections/community.postgresql/pull/554).
+ release_summary: 'This is the minor release of the ``community.postgresql``
+ collection.
+
+ This changelog contains all changes to the modules and plugins in this collection
+
+ that have been made after the previous release.'
+ fragments:
+ - 3.1.0.yml
+ - 481-postgresql_privs.yml
+ - 502_postgresql_privs.yml
+ - 504_postgresql_ext.yml
+ - 505-postgresql_set.yml
+ - 510-postgresql_privs.yml
+ - 518-psycopg-server_version.yml
+ - 521-postgresql_set.yml
+ - 522-psycopg-cursor_args.yml
+ - 545_postgresql_ext.yml
+ - 554_postgresql_tablespace.yml
+ - 556_psycopg251.yml
+ - 559-postgresql_lang-deprecate.yml
+ release_date: '2023-08-14'
+ 3.2.0:
+ changes:
+ bugfixes:
+ - postgresql_info - fix SQL syntax issue (https://github.com/ansible-collections/community.postgresql/issues/570).
+ minor_changes:
+ - postgres modules - added support for Psycopg 3 library (https://github.com/ansible-collections/community.postgresql/pull/517).
+ - postgresql_owner - added support at new object types (https://github.com/ansible-collections/community.postgresql/pull/555).
+ release_summary: 'This is the minor release of the ``community.postgresql``
+ collection.
+
+ This changelog contains all changes to the modules and plugins in this collection
+
+ that have been made after the previous release.'
+ fragments:
+ - 3.2.0.yml
+ - 517_psycopg3.yml
+ - 555_postgresql_owner.yml
+ - 570_postgresql_info.yml
+ - nuke_contributors.yml
+ release_date: '2023-08-22'
+ 3.3.0:
+ changes:
+ bugfixes:
+ - postgresql_query - now reports not changed for queries starting with "SHOW"
+ (https://github.com/ansible-collections/community.postgresql/pull/592).
+ - postgresql_user - module failed when running against an SQL_ASCII encoded
+ database as the user's current password was returned as bytes as opposed to
+ a str. Fix now checks for this case and decodes the bytes as an ascii encoded
+ string. (https://github.com/ansible-collections/community.postgresql/issues/584).
+ minor_changes:
+ - postgresql_db - add the ``comment`` argument (https://github.com/ansible-collections/community.postgresql/issues/614).
+ - postgresql_ext - add the ``comment`` argument (https://github.com/ansible-collections/community.postgresql/issues/354).
+ - postgresql_publication - add the ``comment`` argument (https://github.com/ansible-collections/community.postgresql/issues/354).
+ - postgresql_schema - add the ``comment`` argument (https://github.com/ansible-collections/community.postgresql/issues/354).
+ - postgresql_subscription - add the ``comment`` argument (https://github.com/ansible-collections/community.postgresql/issues/354).
+ - postgresql_tablespace - add the ``comment`` argument (https://github.com/ansible-collections/community.postgresql/issues/354).
+ release_summary: 'This is the minor release of the ``community.postgresql``
+ collection.
+
+ This changelog contains all changes to the modules and plugins in this collection
+
+ that have been made after the previous release.'
+ fragments:
+ - 0-postgresql_db.yml
+ - 1-postgresql_schema.yml
+ - 3-postgresql_tablespace.yml
+ - 3.3.0.yml
+ - 4-postgresql_ext.yml
+ - 5-postgresql_publication.yml
+ - 585-decode-data-from-sql_ascii-databases.yml
+ - 592-return-not-changed-for-show.yml
+ - 6-postgresql_subscription.yml
+ release_date: '2023-12-20'
+ 3.4.0:
+ changes:
+ bugfixes:
+ - 'postgresql_privs - fix a failure when altering privileges with ``grant_option:
+ true`` (https://github.com/ansible-collections/community.postgresql/issues/668).'
+ minor_changes:
+ - postgresql_db - add the ``icu_locale`` argument (https://github.com/ansible-collections/community.postgresql/issues/666).
+ - postgresql_db - add the ``locale_provider`` argument (https://github.com/ansible-collections/community.postgresql/issues/666).
+ release_summary: 'This is a minor release of the ``community.postgresql`` collection.
+
+ This changelog contains all changes to the modules and plugins in this collection
+
+ that have been made after the previous release.'
+ fragments:
+ - 0-privs.yml
+ - 3.4.0.yml
+ - 667-db_icu_provider.yml
+ release_date: '2024-02-09'
diff --git a/ansible_collections/community/postgresql/meta/runtime.yml b/ansible_collections/community/postgresql/meta/runtime.yml
index f7fa752ae..0cb35f9c8 100644
--- a/ansible_collections/community/postgresql/meta/runtime.yml
+++ b/ansible_collections/community/postgresql/meta/runtime.yml
@@ -25,3 +25,9 @@ action_groups:
- postgresql_tablespace
- postgresql_user
- postgresql_user_obj_stat_info
+plugin_routing:
+ modules:
+ postgresql_lang:
+ deprecation:
+ removal_version: 4.0.0
+ warning_text: Use postgresql_ext instead.
diff --git a/ansible_collections/community/postgresql/plugins/doc_fragments/postgres.py b/ansible_collections/community/postgresql/plugins/doc_fragments/postgres.py
index be74a4552..08b23988c 100644
--- a/ansible_collections/community/postgresql/plugins/doc_fragments/postgres.py
+++ b/ansible_collections/community/postgresql/plugins/doc_fragments/postgres.py
@@ -2,7 +2,8 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
@@ -80,13 +81,12 @@ notes:
- The default authentication assumes that you are either logging in as or sudo'ing to the C(postgres) account on the host.
- To avoid "Peer authentication failed for user postgres" error,
use postgres user as a I(become_user).
-- This module uses C(psycopg2), a Python PostgreSQL database adapter. You must
- ensure that C(psycopg2) is installed on the host before using this module.
+- This module uses C(psycopg), a Python PostgreSQL database adapter. You must
+ ensure that C(psycopg2 >= 2.5.1) or C(psycopg3 >= 3.1.8) is installed on the host before using this module.
- If the remote host is the PostgreSQL server (which is the default case), then
PostgreSQL must also be installed on the remote host.
-- For Ubuntu-based systems, install the C(postgresql), C(libpq-dev), and C(python-psycopg2) packages
+- For Ubuntu-based systems, install the C(postgresql), C(libpq-dev), and C(python3-psycopg2) packages
on the remote host before using this module.
-- The ca_cert parameter requires at least Postgres version 8.4 and I(psycopg2) version 2.4.3.
-requirements: [ psycopg2 ]
+requirements: [ 'psycopg2 >= 2.5.1' ]
'''
diff --git a/ansible_collections/community/postgresql/plugins/module_utils/_version.py b/ansible_collections/community/postgresql/plugins/module_utils/_version.py
index 0a34929e9..391138bd5 100644
--- a/ansible_collections/community/postgresql/plugins/module_utils/_version.py
+++ b/ansible_collections/community/postgresql/plugins/module_utils/_version.py
@@ -24,7 +24,8 @@ Every version number class implements the following interface:
of the same class, thus must follow the same rules)
"""
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
import re
diff --git a/ansible_collections/community/postgresql/plugins/module_utils/database.py b/ansible_collections/community/postgresql/plugins/module_utils/database.py
index 8aba6aad8..fe09a1cc0 100644
--- a/ansible_collections/community/postgresql/plugins/module_utils/database.py
+++ b/ansible_collections/community/postgresql/plugins/module_utils/database.py
@@ -8,12 +8,13 @@
#
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
import re
-from ansible.module_utils._text import to_native
+from ansible.module_utils._text import to_native
# Input patterns for is_input_dangerous function:
#
@@ -148,7 +149,7 @@ def is_input_dangerous(string):
Can be used to prevent SQL injections.
Note: use this function only when you can't use
- psycopg2's cursor.execute method parametrized
+ psycopg's cursor.execute method parametrized
(typically with DDL queries).
"""
if not string:
diff --git a/ansible_collections/community/postgresql/plugins/module_utils/postgres.py b/ansible_collections/community/postgresql/plugins/module_utils/postgres.py
index e4a44df56..06eb157fb 100644
--- a/ansible_collections/community/postgresql/plugins/module_utils/postgres.py
+++ b/ansible_collections/community/postgresql/plugins/module_utils/postgres.py
@@ -9,25 +9,47 @@
#
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
from datetime import timedelta
from decimal import Decimal
from os import environ
-psycopg2 = None # This line needs for unit tests
-try:
- import psycopg2
- import psycopg2.extras
- HAS_PSYCOPG2 = True
-except ImportError:
- HAS_PSYCOPG2 = False
-
-from ansible.module_utils.basic import missing_required_lib
from ansible.module_utils._text import to_native
+from ansible.module_utils.basic import missing_required_lib
from ansible.module_utils.six import iteritems
-from ansible_collections.community.postgresql.plugins.module_utils.version import LooseVersion
+from ansible_collections.community.postgresql.plugins.module_utils.version import \
+ LooseVersion
+
+psycopg = None # This line is needed for unit tests
+psycopg2 = None # This line is needed for unit tests
+pg_cursor_args = None # This line is needed for unit tests
+PSYCOPG_VERSION = LooseVersion("0.0") # This line is needed for unit tests
+
+try:
+ import psycopg
+ from psycopg import ClientCursor
+ from psycopg.rows import dict_row
+
+ # We need Psycopg 3 to be at least 3.1.0 because we need Client-side-binding cursors
+ # When a Linux distribution provides both Psycopg2 and Psycopg 3.0 we will use Psycopg2
+ PSYCOPG_VERSION = LooseVersion(psycopg.__version__)
+ if PSYCOPG_VERSION < LooseVersion("3.1"):
+ raise ImportError
+ HAS_PSYCOPG = True
+ pg_cursor_args = {"row_factory": psycopg.rows.dict_row}
+except ImportError:
+ try:
+ import psycopg2
+ psycopg = psycopg2
+ from psycopg2.extras import DictCursor
+ PSYCOPG_VERSION = LooseVersion(psycopg2.__version__)
+ HAS_PSYCOPG = True
+ pg_cursor_args = {"cursor_factory": DictCursor}
+ except ImportError:
+ HAS_PSYCOPG = False
TYPES_NEED_TO_CONVERT = (Decimal, timedelta)
@@ -51,7 +73,7 @@ def postgres_common_argument_spec():
login_unix_socket=dict(default='', aliases=['unix_socket']),
port=dict(
type='int',
- default=5432 if not env_vars.get("PGPORT") else int(env_vars.get("PGPORT")),
+ default=int(env_vars.get("PGPORT", 5432)),
aliases=['login_port']
),
ssl_mode=dict(
@@ -74,17 +96,21 @@ def postgres_common_argument_spec():
def ensure_required_libs(module):
"""Check required libraries."""
- if not HAS_PSYCOPG2:
+ if not HAS_PSYCOPG:
+ # TODO: Should we raise it as psycopg? That will be a breaking change
module.fail_json(msg=missing_required_lib('psycopg2'))
- if module.params.get('ca_cert') and LooseVersion(psycopg2.__version__) < LooseVersion('2.4.3'):
+ elif PSYCOPG_VERSION < LooseVersion("2.5.1"):
+ module.warn("psycopg should be at least 2.5.1 to support all modules functionality")
+
+ if module.params.get('ca_cert') and PSYCOPG_VERSION < LooseVersion('2.4.3'):
module.fail_json(msg='psycopg2 must be at least 2.4.3 in order to use the ca_cert parameter')
def connect_to_db(module, conn_params, autocommit=False, fail_on_conn=True):
"""Connect to a PostgreSQL database.
- Return a tuple containing a psycopg2 connection object and error message / None.
+ Return a tuple containing a psycopg connection object and error message / None.
Args:
module (AnsibleModule) -- object of ansible.module_utils.basic.AnsibleModule class
@@ -98,16 +124,25 @@ def connect_to_db(module, conn_params, autocommit=False, fail_on_conn=True):
db_connection = None
conn_err = None
try:
- db_connection = psycopg2.connect(**conn_params)
- if autocommit:
- if LooseVersion(psycopg2.__version__) >= LooseVersion('2.4.2'):
- db_connection.set_session(autocommit=True)
- else:
- db_connection.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
+ if PSYCOPG_VERSION >= LooseVersion("3.0"):
+ conn_params["autocommit"] = autocommit
+ conn_params["cursor_factory"] = ClientCursor
+ conn_params["row_factory"] = dict_row
+ db_connection = psycopg.connect(**conn_params)
+ else:
+ db_connection = psycopg2.connect(**conn_params)
+ if autocommit:
+ if PSYCOPG_VERSION >= LooseVersion("2.4.2"):
+ db_connection.set_session(autocommit=True)
+ else:
+ db_connection.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
# Switch role, if specified:
if module.params.get('session_role'):
- cursor = db_connection.cursor(cursor_factory=psycopg2.extras.DictCursor)
+ if PSYCOPG_VERSION >= LooseVersion("3.0"):
+ cursor = db_connection.cursor(row_factory=psycopg.rows.dict_row)
+ else:
+ cursor = db_connection.cursor(cursor_factory=psycopg2.extras.DictCursor)
try:
cursor.execute('SET ROLE "%s"' % module.params['session_role'])
@@ -216,7 +251,7 @@ def get_conn_params(module, params_dict, warn_db_default=True):
}
# Might be different in the modules:
- if LooseVersion(psycopg2.__version__) >= LooseVersion('2.7.0'):
+ if PSYCOPG_VERSION >= LooseVersion("2.7.0"):
if params_dict.get('db'):
params_map['db'] = 'dbname'
elif params_dict.get('database'):
@@ -275,7 +310,7 @@ class PgRole():
res = exec_sql(self, query, query_params={'dst_role': self.name},
add_to_executed=False)
if res:
- return res[0][0]
+ return res[0]["array"]
else:
return []
@@ -397,14 +432,14 @@ class PgMembership(object):
def __roles_exist(self, roles):
tmp = ["'" + x + "'" for x in roles]
query = "SELECT rolname FROM pg_roles WHERE rolname IN (%s)" % ','.join(tmp)
- return [x[0] for x in exec_sql(self, query, add_to_executed=False)]
+ return [x["rolname"] for x in exec_sql(self, query, add_to_executed=False)]
def set_search_path(cursor, search_path):
"""Set session's search_path.
Args:
- cursor (Psycopg2 cursor): Database cursor object.
+ cursor (Psycopg cursor): Database cursor object.
search_path (str): String containing comma-separated schema names.
"""
cursor.execute('SET search_path TO %s' % search_path)
@@ -471,7 +506,68 @@ def get_server_version(conn):
Returns server version (int).
"""
- if LooseVersion(psycopg2.__version__) >= LooseVersion('3.0.0'):
+ if PSYCOPG_VERSION >= LooseVersion("3.0.0"):
return conn.info.server_version
else:
return conn.server_version
+
+
+def set_autocommit(conn, autocommit):
+ """Set autocommit.
+
+ Args:
+ conn (psycopg.Connection) -- Psycopg connection object.
+ autocommit -- bool.
+ """
+ if PSYCOPG_VERSION >= LooseVersion("2.4.2"):
+ conn.autocommit = autocommit
+ else:
+ if autocommit:
+ conn.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
+ else:
+ conn.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_READ_COMMITTED)
+
+
+def get_comment(cursor, obj_type, obj_name):
+ """Get DB object's comment.
+
+ Args:
+ cursor (Psycopg cursor) -- Database cursor object.
+ obj_name (str) -- DB object name to get comment from.
+ obj_type (str) -- Object type.
+
+ Returns object's comment (str) if present or None.
+ """
+ query = ''
+ if obj_type == 'role':
+ query = ("SELECT pg_catalog.shobj_description(r.oid, 'pg_authid') AS comment "
+ "FROM pg_catalog.pg_roles AS r "
+ "WHERE r.rolname = %(obj_name)s")
+ elif obj_type == 'extension':
+ query = ("SELECT pg_catalog.obj_description(e.oid, 'pg_extension') AS comment "
+ "FROM pg_catalog.pg_extension AS e "
+ "WHERE e.extname = %(obj_name)s")
+
+ cursor.execute(query, {'obj_name': obj_name})
+ return cursor.fetchone()['comment']
+
+
+def set_comment(cursor, comment, obj_type, obj_name, check_mode=True, executed_queries=None):
+ """Get DB object's comment.
+
+ Args:
+ cursor (Psycopg cursor) -- Database cursor object.
+ comment(str) -- Comment to set on object.
+ obj_name (str) -- DB object name to set comment on.
+ obj_type (str) -- Object type.
+ executed_statements (list) -- List of executed state-modifying statements.
+ """
+ query = 'COMMENT ON %s "%s" IS ' % (obj_type.upper(), obj_name)
+
+ if not check_mode:
+ cursor.execute(query + '%(comment)s', {'comment': comment})
+
+ if executed_queries is not None:
+ executed_queries.append(cursor.mogrify(query + '%(comment)s', {'comment': comment}))
+
+ return True
diff --git a/ansible_collections/community/postgresql/plugins/module_utils/saslprep.py b/ansible_collections/community/postgresql/plugins/module_utils/saslprep.py
index 804200c37..124858c5f 100644
--- a/ansible_collections/community/postgresql/plugins/module_utils/saslprep.py
+++ b/ansible_collections/community/postgresql/plugins/module_utils/saslprep.py
@@ -10,24 +10,14 @@
#
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
-from stringprep import (
- in_table_a1,
- in_table_b1,
- in_table_c3,
- in_table_c4,
- in_table_c5,
- in_table_c6,
- in_table_c7,
- in_table_c8,
- in_table_c9,
- in_table_c12,
- in_table_c21_c22,
- in_table_d1,
- in_table_d2,
-)
+from stringprep import (in_table_a1, in_table_b1, in_table_c3, in_table_c4,
+ in_table_c5, in_table_c6, in_table_c7, in_table_c8,
+ in_table_c9, in_table_c12, in_table_c21_c22,
+ in_table_d1, in_table_d2)
from unicodedata import normalize
from ansible.module_utils.six import text_type
diff --git a/ansible_collections/community/postgresql/plugins/module_utils/version.py b/ansible_collections/community/postgresql/plugins/module_utils/version.py
index 6afaca75e..578032a42 100644
--- a/ansible_collections/community/postgresql/plugins/module_utils/version.py
+++ b/ansible_collections/community/postgresql/plugins/module_utils/version.py
@@ -1,11 +1,10 @@
# -*- coding: utf-8 -*-
-
# Copyright: (c) 2021, Felix Fontein <felix@fontein.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
"""Provide version object to compare version numbers."""
from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
# Once we drop support for Ansible 2.11, we can
@@ -13,4 +12,4 @@ __metaclass__ = type
#
# from ansible.module_utils.compat.version import LooseVersion
-from ._version import LooseVersion
+from ._version import LooseVersion # noqa
diff --git a/ansible_collections/community/postgresql/plugins/modules/postgresql_copy.py b/ansible_collections/community/postgresql/plugins/modules/postgresql_copy.py
index 37ee9b80f..81e0dba12 100644
--- a/ansible_collections/community/postgresql/plugins/modules/postgresql_copy.py
+++ b/ansible_collections/community/postgresql/plugins/modules/postgresql_copy.py
@@ -4,7 +4,8 @@
# Copyright: (c) 2019, Andrew Klychkov (@Andersson007) <aaklychkov@mail.ru>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
DOCUMENTATION = r'''
@@ -163,41 +164,34 @@ EXAMPLES = r'''
RETURN = r'''
queries:
description: List of executed queries.
- returned: always
+ returned: success
type: str
sample: [ "COPY test_table FROM '/tmp/data_file.txt' (FORMAT csv, DELIMITER ',', NULL 'NULL')" ]
src:
description: Data source.
- returned: always
+ returned: success
type: str
sample: "mytable"
dst:
description: Data destination.
- returned: always
+ returned: success
type: str
sample: "/tmp/data.csv"
'''
-try:
- from psycopg2.extras import DictCursor
-except ImportError:
- # psycopg2 is checked by connect_to_db()
- # from ansible.module_utils.postgres
- pass
-
from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.six import iteritems
from ansible_collections.community.postgresql.plugins.module_utils.database import (
check_input,
pg_quote_identifier,
)
from ansible_collections.community.postgresql.plugins.module_utils.postgres import (
connect_to_db,
- exec_sql,
ensure_required_libs,
- get_conn_params,
+ exec_sql, get_conn_params,
+ pg_cursor_args,
postgres_common_argument_spec,
)
-from ansible.module_utils.six import iteritems
class PgCopyData(object):
@@ -206,11 +200,11 @@ class PgCopyData(object):
Arguments:
module (AnsibleModule) -- object of AnsibleModule class
- cursor (cursor) -- cursor object of psycopg2 library
+ cursor (cursor) -- cursor object of psycopg library
Attributes:
module (AnsibleModule) -- object of AnsibleModule class
- cursor (cursor) -- cursor object of psycopg2 library
+ cursor (cursor) -- cursor object of psycopg library
changed (bool) -- something was changed after execution or not
executed_queries (list) -- executed queries
dst (str) -- data destination table (when copy_from)
@@ -383,12 +377,12 @@ def main():
elif module.params.get('copy_to') and not module.params.get('src'):
module.fail_json(msg='src param is necessary with copy_to')
- # Ensure psycopg2 libraries are available before connecting to DB:
+ # Ensure psycopg libraries are available before connecting to DB:
ensure_required_libs(module)
# Connect to DB and make cursor object:
conn_params = get_conn_params(module, module.params)
db_connection, dummy = connect_to_db(module, conn_params, autocommit=False)
- cursor = db_connection.cursor(cursor_factory=DictCursor)
+ cursor = db_connection.cursor(**pg_cursor_args)
##############
# Create the object and do main job:
diff --git a/ansible_collections/community/postgresql/plugins/modules/postgresql_db.py b/ansible_collections/community/postgresql/plugins/modules/postgresql_db.py
index e45d9b769..ae2faa007 100644
--- a/ansible_collections/community/postgresql/plugins/modules/postgresql_db.py
+++ b/ansible_collections/community/postgresql/plugins/modules/postgresql_db.py
@@ -5,6 +5,7 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
DOCUMENTATION = r'''
@@ -47,6 +48,21 @@ options:
- Must match LC_CTYPE of template database unless C(template0) is used as template.
type: str
default: ''
+ icu_locale:
+ description:
+ - Specifies the ICU locale (ICU_LOCALE) for the database default collation order and character classification, overriding the setting locale.
+ - The locale provider must be ICU. The default is the setting of locale if specified; otherwise the same setting as the template database.
+ type: str
+ default: ''
+ version_added: '3.4.0'
+ locale_provider:
+ description:
+ - Specifies the provider to use for the default collation in this database (LOCALE_PROVIDER).
+ - Possible values are icu (if the server was built with ICU support) or libc.
+ - By default, the provider is the same as that of the template.
+ type: str
+ default: ''
+ version_added: '3.4.0'
session_role:
description:
- Switch to session_role after connecting.
@@ -130,6 +146,12 @@ options:
type: bool
default: true
version_added: '0.2.0'
+ comment:
+ description:
+ - Sets a comment on the database.
+ - To reset the comment, pass an empty string.
+ type: str
+ version_added: '3.3.0'
seealso:
- name: CREATE DATABASE reference
description: Complete reference of the CREATE DATABASE command documentation.
@@ -148,7 +170,7 @@ seealso:
- module: community.postgresql.postgresql_ping
notes:
-- State C(dump) and C(restore) don't require I(psycopg2) since version 2.8.
+- State C(dump) and C(restore) don't require I(psycopg) since ansible version 2.8.
attributes:
check_mode:
@@ -164,6 +186,7 @@ EXAMPLES = r'''
- name: Create a new database with name "acme"
community.postgresql.postgresql_db:
name: acme
+ comment: My test DB
# Note: If a template different from "template0" is specified,
# encoding and locale settings must match those of the template.
@@ -173,6 +196,8 @@ EXAMPLES = r'''
encoding: UTF-8
lc_collate: de_DE.UTF-8
lc_ctype: de_DE.UTF-8
+ locale_provider: icu
+ icu_locale: de-DE-x-icu
template: template0
# Note: Default limit for the number of concurrent connections to
@@ -257,7 +282,7 @@ EXAMPLES = r'''
RETURN = r'''
executed_commands:
description: List of commands which tried to run.
- returned: always
+ returned: success
type: list
sample: ["CREATE DATABASE acme"]
version_added: '0.2.0'
@@ -268,26 +293,22 @@ import os
import subprocess
import traceback
-try:
- from psycopg2.extras import DictCursor
-except ImportError:
- HAS_PSYCOPG2 = False
-else:
- HAS_PSYCOPG2 = True
-
-from ansible_collections.community.postgresql.plugins.module_utils.postgres import (
- connect_to_db,
- get_conn_params,
- ensure_required_libs,
- postgres_common_argument_spec
-)
+from ansible.module_utils._text import to_native
from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.six.moves import shlex_quote
from ansible_collections.community.postgresql.plugins.module_utils.database import (
- check_input,
SQLParseError,
+ check_input,
+)
+from ansible_collections.community.postgresql.plugins.module_utils.postgres import (
+ connect_to_db,
+ ensure_required_libs,
+ get_conn_params,
+ get_server_version,
+ pg_cursor_args,
+ postgres_common_argument_spec,
+ set_comment,
)
-from ansible.module_utils.six.moves import shlex_quote
-from ansible.module_utils._text import to_native
executed_commands = []
@@ -321,16 +342,32 @@ def get_encoding_id(cursor, encoding):
def get_db_info(cursor, db):
- query = """
- SELECT rolname AS owner,
- pg_encoding_to_char(encoding) AS encoding, encoding AS encoding_id,
- datcollate AS lc_collate, datctype AS lc_ctype, pg_database.datconnlimit AS conn_limit,
- spcname AS tablespace
- FROM pg_database
- JOIN pg_roles ON pg_roles.oid = pg_database.datdba
- JOIN pg_tablespace ON pg_tablespace.oid = pg_database.dattablespace
- WHERE datname = %(db)s
- """
+ if get_server_version(cursor.connection) >= 150000:
+ query = """
+ SELECT rolname AS owner,
+ pg_encoding_to_char(encoding) AS encoding, encoding AS encoding_id,
+ datcollate AS lc_collate, datctype AS lc_ctype, daticulocale AS icu_locale,
+ CASE datlocprovider WHEN 'c' THEN 'libc' WHEN 'i' THEN 'icu' END AS locale_provider,
+ pg_database.datconnlimit AS conn_limit, spcname AS tablespace,
+ pg_catalog.shobj_description(pg_database.oid, 'pg_database') AS comment
+ FROM pg_database
+ JOIN pg_roles ON pg_roles.oid = pg_database.datdba
+ JOIN pg_tablespace ON pg_tablespace.oid = pg_database.dattablespace
+ WHERE datname = %(db)s
+ """
+ else:
+ query = """
+ SELECT rolname AS owner,
+ pg_encoding_to_char(encoding) AS encoding, encoding AS encoding_id,
+ datcollate AS lc_collate, datctype AS lc_ctype,
+ null::char AS icu_locale, null::text AS locale_provider,
+ pg_database.datconnlimit AS conn_limit, spcname AS tablespace,
+ pg_catalog.shobj_description(pg_database.oid, 'pg_database') AS comment
+ FROM pg_database
+ JOIN pg_roles ON pg_roles.oid = pg_database.datdba
+ JOIN pg_tablespace ON pg_tablespace.oid = pg_database.dattablespace
+ WHERE datname = %(db)s
+ """
cursor.execute(query, {'db': db})
return cursor.fetchone()
@@ -342,7 +379,7 @@ def db_exists(cursor, db):
def db_dropconns(cursor, db):
- if cursor.connection.server_version >= 90200:
+ if get_server_version(cursor.connection) >= 90200:
""" Drop DB connections in Postgres 9.2 and above """
query_terminate = ("SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity "
"WHERE pg_stat_activity.datname=%(db)s AND pid <> pg_backend_pid()")
@@ -360,7 +397,7 @@ def db_delete(cursor, db, force=False):
if db_exists(cursor, db):
query = 'DROP DATABASE "%s"' % db
if force:
- if cursor.connection.server_version >= 130000:
+ if get_server_version(cursor.connection) >= 130000:
query = ('DROP DATABASE "%s" WITH (FORCE)' % db)
else:
db_dropconns(cursor, db)
@@ -371,8 +408,10 @@ def db_delete(cursor, db, force=False):
return False
-def db_create(cursor, db, owner, template, encoding, lc_collate, lc_ctype, conn_limit, tablespace):
- params = dict(enc=encoding, collate=lc_collate, ctype=lc_ctype, conn_limit=conn_limit, tablespace=tablespace)
+def db_create(cursor, db, owner, template, encoding, lc_collate, lc_ctype, icu_locale, locale_provider, conn_limit, tablespace, comment, check_mode):
+ params = dict(enc=encoding, collate=lc_collate, ctype=lc_ctype, iculocale=icu_locale, localeprovider=locale_provider, conn_limit=conn_limit,
+ tablespace=tablespace)
+ icu_supported = get_server_version(cursor.connection) >= 150000
if not db_exists(cursor, db):
query_fragments = ['CREATE DATABASE "%s"' % db]
if owner:
@@ -385,6 +424,10 @@ def db_create(cursor, db, owner, template, encoding, lc_collate, lc_ctype, conn_
query_fragments.append('LC_COLLATE %(collate)s')
if lc_ctype:
query_fragments.append('LC_CTYPE %(ctype)s')
+ if icu_locale and icu_supported:
+ query_fragments.append('ICU_LOCALE %(iculocale)s')
+ if locale_provider and icu_supported:
+ query_fragments.append('LOCALE_PROVIDER %(localeprovider)s')
if tablespace:
query_fragments.append('TABLESPACE "%s"' % tablespace)
if conn_limit:
@@ -392,6 +435,8 @@ def db_create(cursor, db, owner, template, encoding, lc_collate, lc_ctype, conn_
query = ' '.join(query_fragments)
executed_commands.append(cursor.mogrify(query, params))
cursor.execute(query, params)
+ if comment:
+ set_comment(cursor, comment, 'database', db, check_mode, executed_commands)
return True
else:
db_info = get_db_info(cursor, db)
@@ -410,9 +455,23 @@ def db_create(cursor, db, owner, template, encoding, lc_collate, lc_ctype, conn_
'Changing LC_CTYPE is not supported.'
'Current LC_CTYPE: %s' % db_info['lc_ctype']
)
+ elif icu_locale and icu_locale != db_info['icu_locale']:
+ raise NotSupportedError(
+ 'Changing ICU_LOCALE is not supported.'
+ 'Current ICU_LOCALE: %s' % db_info['icu_locale']
+ )
+ elif locale_provider and locale_provider != db_info['locale_provider']:
+ raise NotSupportedError(
+ 'Changing LOCALE_PROVIDER is not supported.'
+ 'Current LOCALE_PROVIDER: %s' % db_info['locale_provider']
+ )
else:
changed = False
+ if db_info['comment'] is None:
+ # For the resetting comment feature (comment: '') to work correctly
+ db_info['comment'] = ''
+
if owner and owner != db_info['owner']:
changed = set_owner(cursor, db, owner)
@@ -422,26 +481,40 @@ def db_create(cursor, db, owner, template, encoding, lc_collate, lc_ctype, conn_
if tablespace and tablespace != db_info['tablespace']:
changed = set_tablespace(cursor, db, tablespace)
+ if comment is not None and comment != db_info['comment']:
+ changed = set_comment(cursor, comment, 'database', db, check_mode, executed_commands)
+
return changed
-def db_matches(cursor, db, owner, template, encoding, lc_collate, lc_ctype, conn_limit, tablespace):
+def db_matches(cursor, db, owner, template, encoding, lc_collate, lc_ctype, icu_locale, locale_provider, conn_limit, tablespace, comment):
if not db_exists(cursor, db):
return False
else:
db_info = get_db_info(cursor, db)
+
+ if db_info['comment'] is None:
+ # For the resetting comment feature (comment: '') to work correctly
+ db_info['comment'] = ''
+
if (encoding and get_encoding_id(cursor, encoding) != db_info['encoding_id']):
return False
elif lc_collate and lc_collate != db_info['lc_collate']:
return False
elif lc_ctype and lc_ctype != db_info['lc_ctype']:
return False
+ elif icu_locale and icu_locale != db_info['icu_locale']:
+ return False
+ elif locale_provider and locale_provider != db_info['locale_provider']:
+ return False
elif owner and owner != db_info['owner']:
return False
elif conn_limit and conn_limit != str(db_info['conn_limit']):
return False
elif tablespace and tablespace != db_info['tablespace']:
return False
+ elif comment is not None and comment != db_info['comment']:
+ return False
else:
return True
@@ -643,6 +716,8 @@ def main():
encoding=dict(type='str', default=''),
lc_collate=dict(type='str', default=''),
lc_ctype=dict(type='str', default=''),
+ icu_locale=dict(type='str', default=''),
+ locale_provider=dict(type='str', default=''),
state=dict(type='str', default='present',
choices=['absent', 'dump', 'present', 'rename', 'restore']),
target=dict(type='path', default=''),
@@ -654,6 +729,7 @@ def main():
dump_extra_args=dict(type='str', default=None),
trust_input=dict(type='bool', default=True),
force=dict(type='bool', default=False),
+ comment=dict(type='str', default=None),
)
module = AnsibleModule(
@@ -667,6 +743,8 @@ def main():
encoding = module.params["encoding"]
lc_collate = module.params["lc_collate"]
lc_ctype = module.params["lc_ctype"]
+ icu_locale = module.params["icu_locale"]
+ locale_provider = module.params["locale_provider"]
target = module.params["target"]
target_opts = module.params["target_opts"]
state = module.params["state"]
@@ -678,6 +756,7 @@ def main():
dump_extra_args = module.params['dump_extra_args']
trust_input = module.params['trust_input']
force = module.params['force']
+ comment = module.params['comment']
if state == 'rename':
if not target:
@@ -692,7 +771,8 @@ def main():
# Check input
if not trust_input:
# Check input for potentially dangerous elements:
- check_input(module, owner, conn_limit, encoding, db, template, tablespace, session_role)
+ check_input(module, owner, conn_limit, encoding, db,
+ template, tablespace, session_role, comment)
raw_connection = state in ("dump", "restore")
@@ -712,7 +792,7 @@ def main():
if not raw_connection:
db_connection, dummy = connect_to_db(module, conn_params, autocommit=True)
- cursor = db_connection.cursor(cursor_factory=DictCursor)
+ cursor = db_connection.cursor(**pg_cursor_args)
if session_role:
try:
@@ -726,7 +806,8 @@ def main():
changed = db_exists(cursor, db)
elif state == "present":
- changed = not db_matches(cursor, db, owner, template, encoding, lc_collate, lc_ctype, conn_limit, tablespace)
+ changed = not db_matches(cursor, db, owner, template, encoding, lc_collate, lc_ctype,
+ icu_locale, locale_provider, conn_limit, tablespace, comment)
elif state == "rename":
changed = rename_db(module, cursor, db, target, check_mode=True)
@@ -741,7 +822,9 @@ def main():
elif state == "present":
try:
- changed = db_create(cursor, db, owner, template, encoding, lc_collate, lc_ctype, conn_limit, tablespace)
+ changed = db_create(cursor, db, owner, template, encoding, lc_collate,
+ lc_ctype, icu_locale, locale_provider, conn_limit,
+ tablespace, comment, module.check_mode)
except SQLParseError as e:
module.fail_json(msg=to_native(e), exception=traceback.format_exc())
diff --git a/ansible_collections/community/postgresql/plugins/modules/postgresql_ext.py b/ansible_collections/community/postgresql/plugins/modules/postgresql_ext.py
index e9f9e46b7..7dfc95ac4 100644
--- a/ansible_collections/community/postgresql/plugins/modules/postgresql_ext.py
+++ b/ansible_collections/community/postgresql/plugins/modules/postgresql_ext.py
@@ -5,6 +5,7 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
DOCUMENTATION = r'''
@@ -77,7 +78,7 @@ options:
path exists.
- Downgrading is only supported if the extension provides a downgrade path otherwise
the extension must be removed and a lower version of the extension must be made available.
- - Set I(version=latest) to always update the extension to the latest available version.
+ - Set I(version=latest) to update the extension to the latest available version.
type: str
trust_input:
description:
@@ -87,6 +88,13 @@ options:
type: bool
default: true
version_added: '0.2.0'
+ comment:
+ description:
+ - Sets a comment on the extension.
+ - To reset the comment, pass an empty string.
+ type: str
+ version_added: '3.3.0'
+
seealso:
- name: PostgreSQL extensions
description: General information about PostgreSQL extensions.
@@ -114,6 +122,7 @@ author:
- Sandro Santilli (@strk)
- Andrew Klychkov (@Andersson007)
- Keith Fiske (@keithf4)
+- Daniele Giudice (@RealGreenDragon)
extends_documentation_fragment:
- community.postgresql.postgres
@@ -125,6 +134,7 @@ EXAMPLES = r'''
name: postgis
db: acme
schema: foo
+ comment: Test extension
- name: Removes postgis extension to the database acme
community.postgresql.postgresql_ext:
@@ -161,34 +171,40 @@ EXAMPLES = r'''
'''
RETURN = r'''
-query:
+queries:
description: List of executed queries.
- returned: always
+ returned: success
type: list
sample: ["DROP EXTENSION \"acme\""]
-
+prev_version:
+ description: Previous installed extension version or empty string if the extension was not installed.
+ returned: success
+ type: str
+ sample: '1.0'
+ version_added: '3.1.0'
+version:
+ description: Current installed extension version or empty string if the extension is not installed.
+ returned: success
+ type: str
+ sample: '2.0'
+ version_added: '3.1.0'
'''
import traceback
-try:
- from psycopg2.extras import DictCursor
-except ImportError:
- # psycopg2 is checked by connect_to_db()
- # from ansible.module_utils.postgres
- pass
-
+from ansible.module_utils._text import to_native
from ansible.module_utils.basic import AnsibleModule
-from ansible_collections.community.postgresql.plugins.module_utils.database import (
- check_input,
-)
+from ansible_collections.community.postgresql.plugins.module_utils.database import \
+ check_input
from ansible_collections.community.postgresql.plugins.module_utils.postgres import (
connect_to_db,
ensure_required_libs,
+ get_comment,
get_conn_params,
+ pg_cursor_args,
postgres_common_argument_spec,
+ set_comment,
)
-from ansible.module_utils._text import to_native
executed_queries = []
@@ -198,37 +214,35 @@ executed_queries = []
#
-def ext_delete(cursor, ext, current_version, cascade):
+def ext_delete(check_mode, cursor, ext, cascade):
"""Remove the extension from the database.
Return True if success.
Args:
- cursor (cursor) -- cursor object of psycopg2 library
+ cursor (cursor) -- cursor object of psycopg library
ext (str) -- extension name
- current_version (str) -- installed version of the extension.
- Value obtained from ext_get_versions and used to
- determine if the extension was installed.
- cascade (boolean) -- Pass the CASCADE flag to the DROP commmand
+ cascade (boolean) -- Pass the CASCADE flag to the DROP command
"""
- if current_version:
- query = "DROP EXTENSION \"%s\"" % ext
- if cascade:
- query += " CASCADE"
+ query = "DROP EXTENSION \"%s\"" % ext
+
+ if cascade:
+ query += " CASCADE"
+
+ if not check_mode:
cursor.execute(query)
- executed_queries.append(cursor.mogrify(query))
- return True
- else:
- return False
+ executed_queries.append(cursor.mogrify(query))
+
+ return True
-def ext_update_version(cursor, ext, version):
+def ext_update_version(check_mode, cursor, ext, version):
"""Update extension version.
Return True if success.
Args:
- cursor (cursor) -- cursor object of psycopg2 library
+ cursor (cursor) -- cursor object of psycopg library
ext (str) -- extension name
version (str) -- extension version
"""
@@ -239,22 +253,24 @@ def ext_update_version(cursor, ext, version):
query += " TO %(ver)s"
params['ver'] = version
- cursor.execute(query, params)
+ if not check_mode:
+ cursor.execute(query, params)
executed_queries.append(cursor.mogrify(query, params))
return True
-def ext_create(cursor, ext, schema, cascade, version):
+def ext_create(check_mode, cursor, ext, schema, cascade, version):
"""
Create the extension objects inside the database.
Return True if success.
Args:
- cursor (cursor) -- cursor object of psycopg2 library
+ cursor (cursor) -- cursor object of psycopg library
ext (str) -- extension name
schema (str) -- target schema for extension objects
+ cascade (boolean) -- Pass the CASCADE flag to the CREATE command
version (str) -- extension version
"""
query = "CREATE EXTENSION \"%s\"" % ext
@@ -268,18 +284,20 @@ def ext_create(cursor, ext, schema, cascade, version):
if cascade:
query += " CASCADE"
- cursor.execute(query, params)
+ if not check_mode:
+ cursor.execute(query, params)
executed_queries.append(cursor.mogrify(query, params))
+
return True
def ext_get_versions(cursor, ext):
"""
Get the currently created extension version if it is installed
- in the database and versions that are available if it is
- installed on the system.
+ in the database, its default version (used to update to 'latest'),
+ and versions that are available if it is installed on the system.
- Return tuple (current_version, [list of available versions]).
+ Return tuple (current_version, default_version, [list of available versions]).
Note: the list of available versions contains only versions
that higher than the current created version.
@@ -287,11 +305,12 @@ def ext_get_versions(cursor, ext):
available versions.
Args:
- cursor (cursor) -- cursor object of psycopg2 library
+ cursor (cursor) -- cursor object of psycopg library
ext (str) -- extension name
"""
current_version = None
+ default_version = None
params = {}
params['ext'] = ext
@@ -303,54 +322,64 @@ def ext_get_versions(cursor, ext):
res = cursor.fetchone()
if res:
- current_version = res[0]
+ current_version = res["extversion"]
+
+ # 2. Get the extension default version:
+ query = ("SELECT default_version FROM pg_catalog.pg_available_extensions "
+ "WHERE name = %(ext)s")
+
+ cursor.execute(query, params)
+
+ res = cursor.fetchone()
+ if res:
+ default_version = res["default_version"]
- # 2. Get available versions:
- query = ("SELECT version FROM pg_available_extension_versions "
+ # 3. Get extension available versions:
+ query = ("SELECT version FROM pg_catalog.pg_available_extension_versions "
"WHERE name = %(ext)s")
cursor.execute(query, params)
- available_versions = set(r[0] for r in cursor.fetchall())
+ available_versions = set(r["version"] for r in cursor.fetchall())
if current_version is None:
current_version = False
+ if default_version is None:
+ default_version = False
- return (current_version, available_versions)
+ return (current_version, default_version, available_versions)
def ext_valid_update_path(cursor, ext, current_version, version):
"""
Check to see if the installed extension version has a valid update
- path to the given version. A version of 'latest' is always a valid path.
+ path to the given version.
Return True if a valid path exists. Otherwise return False.
+ Note: 'latest' is not a valid value for version here as it can be
+ replaced with default_version specified in extension control file.
+
Args:
- cursor (cursor) -- cursor object of psycopg2 library
+ cursor (cursor) -- cursor object of psycopg library
ext (str) -- extension name
current_version (str) -- installed version of the extension.
version (str) -- target extension version to update to.
- A value of 'latest' is always a valid path and will result
- in the extension update command always being run.
"""
valid_path = False
params = {}
- if version != 'latest':
- query = ("SELECT path FROM pg_extension_update_paths(%(ext)s) "
- "WHERE source = %(cv)s "
- "AND target = %(ver)s")
+ query = ("SELECT path FROM pg_extension_update_paths(%(ext)s) "
+ "WHERE source = %(cv)s "
+ "AND target = %(ver)s")
- params['ext'] = ext
- params['cv'] = current_version
- params['ver'] = version
+ params['ext'] = ext
+ params['cv'] = current_version
+ params['ver'] = version
- cursor.execute(query, params)
- res = cursor.fetchone()
- if res is not None:
- valid_path = True
- else:
+ cursor.execute(query, params)
+ res = cursor.fetchone()
+ if res is not None:
valid_path = True
return (valid_path)
@@ -372,6 +401,7 @@ def main():
session_role=dict(type="str"),
version=dict(type="str"),
trust_input=dict(type="bool", default=True),
+ comment=dict(type="str", default=None),
)
module = AnsibleModule(
@@ -386,56 +416,82 @@ def main():
version = module.params["version"]
session_role = module.params["session_role"]
trust_input = module.params["trust_input"]
+ comment = module.params["comment"]
+
changed = False
if not trust_input:
- check_input(module, ext, schema, version, session_role)
+ check_input(module, ext, schema, version, session_role, comment)
if version and state == 'absent':
module.warn("Parameter version is ignored when state=absent")
- # Ensure psycopg2 libraries are available before connecting to DB:
+ # Ensure psycopg libraries are available before connecting to DB:
ensure_required_libs(module)
conn_params = get_conn_params(module, module.params)
db_connection, dummy = connect_to_db(module, conn_params, autocommit=True)
- cursor = db_connection.cursor(cursor_factory=DictCursor)
+ cursor = db_connection.cursor(**pg_cursor_args)
try:
# Get extension info and available versions:
- curr_version, available_versions = ext_get_versions(cursor, ext)
+ curr_version, default_version, available_versions = ext_get_versions(cursor, ext)
+
+ # Decode version 'latest' when passed (if version is not passed 'latest' is assumed)
+ # Note: real_version used for checks but not in CREATE/DROP/ALTER EXTENSION commands,
+ # as the correct way to obtain 'latest' version is not specify the version
+ if not version or version == 'latest':
+ # If there are not available versions the extension is not available
+ if not available_versions:
+ module.fail_json(msg="Extension %s is not available" % ext)
+ # Check default_version is available
+ if default_version:
+ # 'latest' version matches default_version specified in extension control file
+ real_version = default_version
+ else:
+ # Passed version is 'latest', versions are available, but no default_version is specified
+ # in extension control file. In this situation CREATE/ALTER EXTENSION commands fail if
+ # a specific version is not passed ('latest' cannot be determined).
+ module.fail_json(msg="Passed version 'latest' but no default_version available "
+ "in extension control file")
+ else:
+ real_version = version
if state == "present":
- # If version passed
+ # If version passed:
if version:
# If extension is installed, update to passed version if a valid path exists
if curr_version:
- # Given version already installed
- if curr_version == version:
+ # Given/Latest version already installed
+ if curr_version == real_version:
changed = False
- # Attempt to update to given version or latest version defined in extension control file
- # ALTER EXTENSION is actually run if valid, so 'changed' will be true even if nothing updated
+ # Attempt to update to given/latest version
else:
- valid_update_path = ext_valid_update_path(cursor, ext, curr_version, version)
+ valid_update_path = ext_valid_update_path(cursor, ext, curr_version, real_version)
if valid_update_path:
- if module.check_mode:
- changed = True
- else:
- changed = ext_update_version(cursor, ext, version)
+ changed = ext_update_version(module.check_mode, cursor, ext, version)
else:
- module.fail_json(msg="Passed version '%s' has no valid update path from "
- "the currently installed version '%s' or "
- "the passed version is not available" % (version, curr_version))
+ if version == 'latest':
+ # No valid update path from curr_version to latest extension version
+ # (extension is buggy or no direct update supported)
+ module.fail_json(msg="Latest version '%s' has no valid update path from "
+ "the currently installed version '%s'" % (real_version, curr_version))
+ else:
+ module.fail_json(msg="Passed version '%s' has no valid update path from "
+ "the currently installed version '%s' or "
+ "the passed version is not available" % (version, curr_version))
+ # If extension is not installed, install passed version
else:
- # If not requesting latest version and passed version not available
- if version != 'latest' and version not in available_versions:
- module.fail_json(msg="Passed version '%s' is not available" % version)
- # Else install the passed version when available
- else:
- if module.check_mode:
- changed = True
+ # If passed version not available fail
+ if real_version not in available_versions:
+ if version == 'latest':
+ # Latest version not available (extension is buggy)
+ module.fail_json(msg="Latest version '%s' is not available" % real_version)
else:
- changed = ext_create(cursor, ext, schema, cascade, version)
+ module.fail_json(msg="Passed version '%s' is not available" % real_version)
+ # Else install the passed version
+ else:
+ changed = ext_create(module.check_mode, cursor, ext, schema, cascade, version)
# If version is not passed:
else:
@@ -445,30 +501,51 @@ def main():
else:
# If the ext doesn't exist and is available:
if available_versions:
- if module.check_mode:
- changed = True
- else:
- changed = ext_create(cursor, ext, schema, cascade, 'latest')
-
+ # 'latest' version installed by default if version not passed
+ changed = ext_create(module.check_mode, cursor, ext, schema, cascade, 'latest')
# If the ext doesn't exist and is not available:
else:
module.fail_json(msg="Extension %s is not available" % ext)
+ if comment is not None:
+ current_comment = get_comment(cursor, 'extension', ext)
+ # For the resetting comment feature (comment: '') to work correctly
+ current_comment = current_comment if current_comment is not None else ''
+ if comment != current_comment:
+ changed = set_comment(cursor, comment, 'extension', ext, module.check_mode, executed_queries)
+
elif state == "absent":
if curr_version:
- if module.check_mode:
- changed = True
- else:
- changed = ext_delete(cursor, ext, curr_version, cascade)
+ changed = ext_delete(module.check_mode, cursor, ext, cascade)
else:
changed = False
+ # Get extension info again:
+ new_version, new_default_version, new_available_versions = ext_get_versions(cursor, ext)
+
+ # Parse previous and current version for module output
+ out_prev_version = curr_version if curr_version else ''
+ if module.check_mode and changed:
+ if state == "present":
+ out_version = real_version
+ elif state == "absent":
+ out_version = ''
+ else:
+ out_version = new_version if new_version else ''
+
except Exception as e:
db_connection.close()
module.fail_json(msg="Management of PostgreSQL extension failed: %s" % to_native(e), exception=traceback.format_exc())
db_connection.close()
- module.exit_json(changed=changed, db=module.params["db"], ext=ext, queries=executed_queries)
+ module.exit_json(
+ changed=changed,
+ db=module.params["db"],
+ ext=ext,
+ prev_version=out_prev_version,
+ version=out_version,
+ queries=executed_queries,
+ )
if __name__ == '__main__':
diff --git a/ansible_collections/community/postgresql/plugins/modules/postgresql_idx.py b/ansible_collections/community/postgresql/plugins/modules/postgresql_idx.py
index 2ffb33a8c..7eb35de40 100644
--- a/ansible_collections/community/postgresql/plugins/modules/postgresql_idx.py
+++ b/ansible_collections/community/postgresql/plugins/modules/postgresql_idx.py
@@ -5,6 +5,7 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
DOCUMENTATION = r'''
@@ -222,59 +223,53 @@ EXAMPLES = r'''
RETURN = r'''
name:
description: Index name.
- returned: always
+ returned: success
type: str
sample: 'foo_idx'
state:
description: Index state.
- returned: always
+ returned: success
type: str
sample: 'present'
schema:
description: Schema where index exists.
- returned: always
+ returned: success
type: str
sample: 'public'
tablespace:
description: Tablespace where index exists.
- returned: always
+ returned: success
type: str
sample: 'ssd'
query:
description: Query that was tried to be executed.
- returned: always
+ returned: success
type: str
sample: 'CREATE INDEX CONCURRENTLY foo_idx ON test_table USING BTREE (id)'
storage_params:
description: Index storage parameters.
- returned: always
+ returned: success
type: list
sample: [ "fillfactor=90" ]
valid:
description: Index validity.
- returned: always
+ returned: success
type: bool
sample: true
'''
-try:
- from psycopg2.extras import DictCursor
-except ImportError:
- # psycopg2 is checked by connect_to_db()
- # from ansible.module_utils.postgres
- pass
-
from ansible.module_utils.basic import AnsibleModule
-from ansible_collections.community.postgresql.plugins.module_utils.database import check_input
+from ansible_collections.community.postgresql.plugins.module_utils.database import \
+ check_input
from ansible_collections.community.postgresql.plugins.module_utils.postgres import (
connect_to_db,
- exec_sql,
ensure_required_libs,
+ exec_sql,
get_conn_params,
+ pg_cursor_args,
postgres_common_argument_spec,
)
-
VALID_IDX_TYPES = ('BTREE', 'HASH', 'GIST', 'SPGIST', 'GIN', 'BRIN')
@@ -294,13 +289,13 @@ class Index(object):
Args:
module (AnsibleModule) -- object of AnsibleModule class
- cursor (cursor) -- cursor object of psycopg2 library
+ cursor (cursor) -- cursor object of psycopg library
schema (str) -- name of the index schema
name (str) -- name of the index
Attrs:
module (AnsibleModule) -- object of AnsibleModule class
- cursor (cursor) -- cursor object of psycopg2 library
+ cursor (cursor) -- cursor object of psycopg library
schema (str) -- name of the index schema
name (str) -- name of the index
exists (bool) -- flag the index exists in the DB or not
@@ -357,11 +352,11 @@ class Index(object):
self.info = dict(
name=self.name,
state='present',
- schema=res[0][0],
- tblname=res[0][1],
- tblspace=res[0][2] if res[0][2] else '',
- valid=res[0][3],
- storage_params=res[0][4] if res[0][4] else [],
+ schema=res[0]["schemaname"],
+ tblname=res[0]["tablename"],
+ tblspace=res[0]["tablespace"] if res[0]["tablespace"] else '',
+ valid=res[0]["indisvalid"],
+ storage_params=res[0]["reloptions"] if res[0]["reloptions"] else [],
)
return True
@@ -520,11 +515,11 @@ def main():
if cascade and state != 'absent':
module.fail_json(msg="cascade parameter used only with state=absent")
- # Ensure psycopg2 libraries are available before connecting to DB:
+ # Ensure psycopg libraries are available before connecting to DB:
ensure_required_libs(module)
conn_params = get_conn_params(module, module.params)
db_connection, dummy = connect_to_db(module, conn_params, autocommit=True)
- cursor = db_connection.cursor(cursor_factory=DictCursor)
+ cursor = db_connection.cursor(**pg_cursor_args)
# Set defaults:
changed = False
diff --git a/ansible_collections/community/postgresql/plugins/modules/postgresql_info.py b/ansible_collections/community/postgresql/plugins/modules/postgresql_info.py
index 55bb6ebd8..f21bfcdc1 100644
--- a/ansible_collections/community/postgresql/plugins/modules/postgresql_info.py
+++ b/ansible_collections/community/postgresql/plugins/modules/postgresql_info.py
@@ -5,6 +5,7 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
DOCUMENTATION = r'''
@@ -109,18 +110,18 @@ EXAMPLES = r'''
RETURN = r'''
version:
description: Database server version U(https://www.postgresql.org/support/versioning/).
- returned: always
+ returned: success
type: dict
sample: { "version": { "major": 10, "minor": 6 } }
contains:
major:
description: Major server version.
- returned: always
+ returned: success
type: int
sample: 11
minor:
description: Minor server version.
- returned: always
+ returned: success
type: int
sample: 1
patch:
@@ -131,24 +132,24 @@ version:
version_added: '1.2.0'
full:
description: Full server version.
- returned: always
+ returned: success
type: str
sample: '13.2'
version_added: '1.2.0'
raw:
description: Full output returned by ``SELECT version()``.
- returned: always
+ returned: success
type: str
sample: 'PostgreSQL 13.2 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 10.2.1 20201125 (Red Hat 10.2.1-9), 64-bit'
version_added: '1.2.0'
in_recovery:
description: Indicates if the service is in recovery mode or not.
- returned: always
+ returned: success
type: bool
sample: false
databases:
description: Information about databases.
- returned: always
+ returned: success
type: dict
sample:
- { "postgres": { "access_priv": "", "collate": "en_US.UTF-8",
@@ -156,48 +157,60 @@ databases:
contains:
database_name:
description: Database name.
- returned: always
+ returned: success
type: dict
sample: template1
contains:
access_priv:
description: Database access privileges.
- returned: always
+ returned: success
type: str
sample: "=c/postgres_npostgres=CTc/postgres"
collate:
description:
- Database collation U(https://www.postgresql.org/docs/current/collation.html).
- returned: always
+ returned: success
type: str
sample: en_US.UTF-8
ctype:
description:
- Database LC_CTYPE U(https://www.postgresql.org/docs/current/multibyte.html).
- returned: always
+ returned: success
+ type: str
+ sample: en_US.UTF-8
+ icu_locale:
+ description:
+ - Database ICU_LOCALE U(https://www.postgresql.org/docs/current/locale.html#ICU-LOCALES).
+ returned: success
+ type: str
+ sample: en_US.UTF-8
+ locale_provider:
+ description:
+ - Database LOCALE_PROVIDER U(https://www.postgresql.org/docs/current/locale.html#LOCALE-PROVIDERS).
+ returned: success
type: str
sample: en_US.UTF-8
encoding:
description:
- Database encoding U(https://www.postgresql.org/docs/current/multibyte.html).
- returned: always
+ returned: success
type: str
sample: UTF8
owner:
description:
- Database owner U(https://www.postgresql.org/docs/current/sql-createdatabase.html).
- returned: always
+ returned: success
type: str
sample: postgres
size:
description: Database size in bytes.
- returned: always
+ returned: success
type: str
sample: 8189415
extensions:
description:
- Extensions U(https://www.postgresql.org/docs/current/sql-createextension.html).
- returned: always
+ returned: success
type: dict
sample:
- { "plpgsql": { "description": "PL/pgSQL procedural language",
@@ -210,32 +223,32 @@ databases:
sample: PL/pgSQL procedural language
extversion:
description: Extension description.
- returned: always
+ returned: success
type: dict
contains:
major:
description: Extension major version.
- returned: always
+ returned: success
type: int
sample: 1
minor:
description: Extension minor version.
- returned: always
+ returned: success
type: int
sample: 0
raw:
description: Extension full version.
- returned: always
+ returned: success
type: str
sample: '1.0'
nspname:
description: Namespace where the extension is.
- returned: always
+ returned: success
type: str
sample: pg_catalog
languages:
description: Procedural languages U(https://www.postgresql.org/docs/current/xplang.html).
- returned: always
+ returned: success
type: dict
sample: { "sql": { "lanacl": "", "lanowner": "postgres" } }
contains:
@@ -243,32 +256,32 @@ databases:
description:
- Language access privileges
U(https://www.postgresql.org/docs/current/catalog-pg-language.html).
- returned: always
+ returned: success
type: str
sample: "{postgres=UC/postgres,=U/postgres}"
lanowner:
description:
- Language owner U(https://www.postgresql.org/docs/current/catalog-pg-language.html).
- returned: always
+ returned: success
type: str
sample: postgres
namespaces:
description:
- Namespaces (schema) U(https://www.postgresql.org/docs/current/sql-createschema.html).
- returned: always
+ returned: success
type: dict
sample: { "pg_catalog": { "nspacl": "{postgres=UC/postgres,=U/postgres}", "nspowner": "postgres" } }
contains:
nspacl:
description:
- Access privileges U(https://www.postgresql.org/docs/current/catalog-pg-namespace.html).
- returned: always
+ returned: success
type: str
sample: "{postgres=UC/postgres,=U/postgres}"
nspowner:
description:
- Schema owner U(https://www.postgresql.org/docs/current/catalog-pg-namespace.html).
- returned: always
+ returned: success
type: str
sample: postgres
publications:
@@ -303,24 +316,24 @@ repl_slots:
active:
description:
- True means that a receiver has connected to it, and it is currently reserving archives.
- returned: always
+ returned: success
type: bool
sample: true
database:
description: Database name this slot is associated with, or null.
- returned: always
+ returned: success
type: str
sample: acme
plugin:
description:
- Base name of the shared object containing the output plugin
this logical slot is using, or null for physical slots.
- returned: always
+ returned: success
type: str
sample: pgoutput
slot_type:
description: The slot type - physical or logical.
- returned: always
+ returned: success
type: str
sample: logical
replications:
@@ -336,7 +349,7 @@ replications:
usename:
description:
- Name of the user logged into this WAL sender process ('usename' is a column name in pg_stat_replication view).
- returned: always
+ returned: success
type: str
sample: replication_user
app_name:
@@ -349,30 +362,30 @@ replications:
- IP address of the client connected to this WAL sender.
- If this field is null, it indicates that the client is connected
via a Unix socket on the server machine.
- returned: always
+ returned: success
type: str
sample: 10.0.0.101
client_hostname:
description:
- Host name of the connected client, as reported by a reverse DNS lookup of client_addr.
- This field will only be non-null for IP connections, and only when log_hostname is enabled.
- returned: always
+ returned: success
type: str
sample: dbsrv1
backend_start:
description: Time when this process was started, i.e., when the client connected to this WAL sender.
- returned: always
+ returned: success
type: str
sample: "2019-02-03 00:14:33.908593+03"
state:
description: Current WAL sender state.
- returned: always
+ returned: success
type: str
sample: streaming
tablespaces:
description:
- Information about tablespaces U(https://www.postgresql.org/docs/current/catalog-pg-tablespace.html).
- returned: always
+ returned: success
type: dict
sample:
- { "test": { "spcacl": "{postgres=C/postgres,andreyk=C/postgres}", "spcoptions": [ "seq_page_cost=1" ],
@@ -380,23 +393,23 @@ tablespaces:
contains:
spcacl:
description: Tablespace access privileges.
- returned: always
+ returned: success
type: str
sample: "{postgres=C/postgres,andreyk=C/postgres}"
spcoptions:
description: Tablespace-level options.
- returned: always
+ returned: success
type: list
sample: [ "seq_page_cost=1" ]
spcowner:
description: Owner of the tablespace.
- returned: always
+ returned: success
type: str
sample: test_user
roles:
description:
- Information about roles U(https://www.postgresql.org/docs/current/user-manag.html).
- returned: always
+ returned: success
type: dict
sample:
- { "test_role": { "canlogin": true, "member_of": [ "user_ro" ], "superuser": false,
@@ -404,37 +417,37 @@ roles:
contains:
canlogin:
description: Login privilege U(https://www.postgresql.org/docs/current/role-attributes.html).
- returned: always
+ returned: success
type: bool
sample: true
member_of:
description:
- Role membership U(https://www.postgresql.org/docs/current/role-membership.html).
- returned: always
+ returned: success
type: list
sample: [ "read_only_users" ]
superuser:
description: User is a superuser or not.
- returned: always
+ returned: success
type: bool
sample: false
valid_until:
description:
- Password expiration date U(https://www.postgresql.org/docs/current/sql-alterrole.html).
- returned: always
+ returned: success
type: str
sample: "9999-12-31T23:59:59.999999+00:00"
pending_restart_settings:
description:
- List of settings that are pending restart to be set.
- returned: always
+ returned: success
type: list
sample: [ "shared_buffers" ]
settings:
description:
- Information about run-time server parameters
U(https://www.postgresql.org/docs/current/view-pg-settings.html).
- returned: always
+ returned: success
type: dict
sample:
- { "work_mem": { "boot_val": "4096", "context": "user", "max_val": "2147483647",
@@ -443,30 +456,30 @@ settings:
contains:
setting:
description: Current value of the parameter.
- returned: always
+ returned: success
type: str
sample: 49152
unit:
description: Implicit unit of the parameter.
- returned: always
+ returned: success
type: str
sample: kB
boot_val:
description:
- Parameter value assumed at server startup if the parameter is not otherwise set.
- returned: always
+ returned: success
type: str
sample: 4096
min_val:
description:
- Minimum allowed value of the parameter (null for non-numeric values).
- returned: always
+ returned: success
type: str
sample: 64
max_val:
description:
- Maximum allowed value of the parameter (null for non-numeric values).
- returned: always
+ returned: success
type: str
sample: 2147483647
sourcefile:
@@ -475,20 +488,20 @@ settings:
- Null for values set from sources other than configuration files,
or when examined by a user who is neither a superuser or a member of pg_read_all_settings.
- Helpful when using include directives in configuration files.
- returned: always
+ returned: success
type: str
sample: /var/lib/pgsql/10/data/postgresql.auto.conf
context:
description:
- Context required to set the parameter's value.
- For more information see U(https://www.postgresql.org/docs/current/view-pg-settings.html).
- returned: always
+ returned: success
type: str
sample: user
vartype:
description:
- Parameter type (bool, enum, integer, real, or string).
- returned: always
+ returned: success
type: str
sample: integer
val_in_bytes:
@@ -500,14 +513,14 @@ settings:
pretty_val:
description:
- Value presented in the pretty form.
- returned: always
+ returned: success
type: str
sample: 2MB
pending_restart:
description:
- True if the value has been changed in the configuration file but needs a restart; or false otherwise.
- Returns only if C(settings) is passed.
- returned: always
+ returned: success
type: bool
sample: false
'''
@@ -515,31 +528,25 @@ settings:
import re
from fnmatch import fnmatch
-try:
- from psycopg2.extras import DictCursor
-except ImportError:
- # psycopg2 is checked by connect_to_db()
- # from ansible.module_utils.postgres
- pass
-
+from ansible.module_utils._text import to_native
from ansible.module_utils.basic import AnsibleModule
-from ansible_collections.community.postgresql.plugins.module_utils.database import (
- check_input,
-)
+from ansible.module_utils.six import iteritems
+from ansible_collections.community.postgresql.plugins.module_utils.database import \
+ check_input
from ansible_collections.community.postgresql.plugins.module_utils.postgres import (
connect_to_db,
ensure_required_libs,
get_conn_params,
+ get_server_version,
+ pg_cursor_args,
postgres_common_argument_spec,
)
-from ansible.module_utils.six import iteritems
-from ansible.module_utils._text import to_native
-
# ===========================================
# PostgreSQL module specific support methods.
#
+
class PgDbConn(object):
"""Auxiliary class for working with PostgreSQL connection objects.
@@ -558,14 +565,14 @@ class PgDbConn(object):
Note: connection parameters are passed by self.module object.
"""
- # Ensure psycopg2 libraries are available before connecting to DB:
+ # Ensure psycopg libraries are available before connecting to DB:
ensure_required_libs(self.module)
conn_params = get_conn_params(self.module, self.module.params, warn_db_default=False)
self.db_conn, dummy = connect_to_db(self.module, conn_params, fail_on_conn=fail_on_conn)
if self.db_conn is None:
# only happens if fail_on_conn is False and there actually was an issue connecting to the DB
return None
- return self.db_conn.cursor(cursor_factory=DictCursor)
+ return self.db_conn.cursor(**pg_cursor_args)
def reconnect(self, dbname):
"""Reconnect to another database and return a PostgreSQL cursor object.
@@ -588,7 +595,7 @@ class PgClusterInfo(object):
Arguments:
module (AnsibleModule): Object of AnsibleModule class.
- db_conn_obj (psycopg2.connect): PostgreSQL connection object.
+ db_conn_obj (psycopg.connect): PostgreSQL connection object.
"""
def __init__(self, module, db_conn_obj):
@@ -696,7 +703,7 @@ class PgClusterInfo(object):
"WHERE table_schema = 'pg_catalog' "
"AND table_name = 'pg_subscription'")
columns_result = self.__exec_sql(columns_sub_table)
- columns = ", ".join(["s.%s" % column[0] for column in columns_result])
+ columns = ", ".join(["s.%s" % column["column_name"] for column in columns_result])
query = ("SELECT %s, r.rolname AS ownername, d.datname AS dbname "
"FROM pg_catalog.pg_subscription s "
@@ -736,22 +743,22 @@ class PgClusterInfo(object):
"AND column_name = 'spcoptions'")
if not opt:
- query = ("SELECT s.spcname, pg_catalog.pg_get_userbyid(s.spcowner) as rolname, s.spcacl "
+ query = ("SELECT s.spcname, pg_catalog.pg_get_userbyid(s.spcowner) as rolname, s.spcacl::text "
"FROM pg_tablespace AS s ")
else:
- query = ("SELECT s.spcname, pg_catalog.pg_get_userbyid(s.spcowner) as rolname, s.spcacl, s.spcoptions "
+ query = ("SELECT s.spcname, pg_catalog.pg_get_userbyid(s.spcowner) as rolname, s.spcacl::text, s.spcoptions "
"FROM pg_tablespace AS s ")
res = self.__exec_sql(query)
ts_dict = {}
for i in res:
- ts_name = i[0]
+ ts_name = i["spcname"]
ts_info = dict(
- spcowner=i[1],
- spcacl=i[2] if i[2] else '',
+ spcowner=i["rolname"],
+ spcacl=i["spcacl"] if i["spcacl"] else '',
)
if opt:
- ts_info['spcoptions'] = i[3] if i[3] else []
+ ts_info["spcoptions"] = i["spcoptions"] if i["spcoptions"] else []
ts_dict[ts_name] = ts_info
@@ -763,7 +770,7 @@ class PgClusterInfo(object):
res = self.__exec_sql("SELECT EXISTS (SELECT 1 FROM "
"information_schema.tables "
"WHERE table_name = 'pg_extension')")
- if not res[0][0]:
+ if not res[0]["exists"]:
return True
query = ("SELECT e.extname, e.extversion, n.nspname, c.description "
@@ -776,12 +783,12 @@ class PgClusterInfo(object):
res = self.__exec_sql(query)
ext_dict = {}
for i in res:
- ext_ver_raw = i[1]
+ ext_ver_raw = i["extversion"]
- if re.search(r'^([0-9]+([\-]*[0-9]+)?\.)*[0-9]+([\-]*[0-9]+)?$', i[1]) is None:
+ if re.search(r'^([0-9]+([\-]*[0-9]+)?\.)*[0-9]+([\-]*[0-9]+)?$', i["extversion"]) is None:
ext_ver = [None, None]
else:
- ext_ver = i[1].split('.')
+ ext_ver = i["extversion"].split('.')
if re.search(r'-', ext_ver[0]) is not None:
ext_ver = ext_ver[0].split('-')
else:
@@ -791,14 +798,14 @@ class PgClusterInfo(object):
except IndexError:
ext_ver.append(None)
- ext_dict[i[0]] = dict(
+ ext_dict[i["extname"]] = dict(
extversion=dict(
major=int(ext_ver[0]) if ext_ver[0] else None,
minor=int(ext_ver[1]) if ext_ver[1] else None,
raw=ext_ver_raw,
),
- nspname=i[2],
- description=i[3],
+ nspname=i["nspname"],
+ description=i["description"],
)
return ext_dict
@@ -817,11 +824,11 @@ class PgClusterInfo(object):
res = self.__exec_sql(query)
rol_dict = {}
for i in res:
- rol_dict[i[0]] = dict(
- superuser=i[1],
- canlogin=i[2],
- valid_until=i[3] if i[3] else '',
- member_of=i[4] if i[4] else [],
+ rol_dict[i["rolname"]] = dict(
+ superuser=i["rolsuper"],
+ canlogin=i["rolcanlogin"],
+ valid_until=i["rolvaliduntil"] if i["rolvaliduntil"] else '',
+ member_of=i["memberof"] if i["memberof"] else [],
)
self.pg_info["roles"] = rol_dict
@@ -832,7 +839,7 @@ class PgClusterInfo(object):
res = self.__exec_sql("SELECT EXISTS (SELECT 1 FROM "
"information_schema.tables "
"WHERE table_name = 'pg_replication_slots')")
- if not res[0][0]:
+ if not res[0]["exists"]:
return True
query = ("SELECT slot_name, plugin, slot_type, database, "
@@ -845,11 +852,11 @@ class PgClusterInfo(object):
rslot_dict = {}
for i in res:
- rslot_dict[i[0]] = dict(
- plugin=i[1],
- slot_type=i[2],
- database=i[3],
- active=i[4],
+ rslot_dict[i["slot_name"]] = dict(
+ plugin=i["plugin"],
+ slot_type=i["slot_type"],
+ database=i["database"],
+ active=i["active"],
)
self.pg_info["repl_slots"] = rslot_dict
@@ -874,9 +881,9 @@ class PgClusterInfo(object):
set_dict = {}
for i in res:
val_in_bytes = None
- setting = i[1]
- if i[2]:
- unit = i[2]
+ setting = i["setting"]
+ if i["unit"]:
+ unit = i["unit"]
else:
unit = ''
@@ -892,22 +899,22 @@ class PgClusterInfo(object):
if val_in_bytes is not None and val_in_bytes < 0:
val_in_bytes = 0
- setting_name = i[0]
+ setting_name = i["name"]
pretty_val = self.__get_pretty_val(setting_name)
pending_restart = None
if pend_rest_col_exists:
- pending_restart = i[9]
+ pending_restart = i["pending_restart"]
set_dict[setting_name] = dict(
setting=setting,
unit=unit,
- context=i[3],
- vartype=i[4],
- boot_val=i[5] if i[5] else '',
- min_val=i[6] if i[6] else '',
- max_val=i[7] if i[7] else '',
- sourcefile=i[8] if i[8] else '',
+ context=i["context"],
+ vartype=i["vartype"],
+ boot_val=i["boot_val"] if i["boot_val"] else '',
+ min_val=i["min_val"] if i["min_val"] else '',
+ max_val=i["max_val"] if i["max_val"] else '',
+ sourcefile=i["sourcefile"] if i["sourcefile"] else '',
pretty_val=pretty_val,
)
if val_in_bytes is not None:
@@ -926,10 +933,10 @@ class PgClusterInfo(object):
res = self.__exec_sql("SELECT EXISTS (SELECT 1 FROM "
"information_schema.tables "
"WHERE table_name = 'pg_stat_replication')")
- if not res[0][0]:
+ if not res[0]["exists"]:
return True
- query = ("SELECT r.pid, pg_catalog.pg_get_userbyid(r.usesysid) AS rolname, r.application_name, r.client_addr, "
+ query = ("SELECT r.pid, pg_catalog.pg_get_userbyid(r.usesysid) AS rolname, r.application_name, r.client_addr::text, "
"r.client_hostname, r.backend_start::text, r.state "
"FROM pg_stat_replication AS r ")
res = self.__exec_sql(query)
@@ -940,42 +947,42 @@ class PgClusterInfo(object):
repl_dict = {}
for i in res:
- repl_dict[i[0]] = dict(
- usename=i[1],
- app_name=i[2] if i[2] else '',
- client_addr=i[3],
- client_hostname=i[4] if i[4] else '',
- backend_start=i[5],
- state=i[6],
+ repl_dict[i["pid"]] = dict(
+ usename=i["rolname"],
+ app_name=i["application_name"] if i["application_name"] else '',
+ client_addr=i["client_addr"],
+ client_hostname=i["client_hostname"] if i["client_hostname"] else '',
+ backend_start=i["backend_start"],
+ state=i["state"],
)
self.pg_info["replications"] = repl_dict
def get_lang_info(self):
"""Get information about current supported languages."""
- query = ("SELECT l.lanname, pg_catalog.pg_get_userbyid(l.lanowner) AS rolname, l.lanacl "
+ query = ("SELECT l.lanname, pg_catalog.pg_get_userbyid(l.lanowner) AS rolname, l.lanacl::text "
"FROM pg_language AS l ")
res = self.__exec_sql(query)
lang_dict = {}
for i in res:
- lang_dict[i[0]] = dict(
- lanowner=i[1],
- lanacl=i[2] if i[2] else '',
+ lang_dict[i["lanname"]] = dict(
+ lanowner=i["rolname"],
+ lanacl=i["lanacl"] if i["lanacl"] else '',
)
return lang_dict
def get_namespaces(self):
"""Get information about namespaces."""
- query = ("SELECT n.nspname, pg_catalog.pg_get_userbyid(n.nspowner) AS rolname, n.nspacl "
+ query = ("SELECT n.nspname, pg_catalog.pg_get_userbyid(n.nspowner) AS rolname, n.nspacl::text "
"FROM pg_catalog.pg_namespace AS n ")
res = self.__exec_sql(query)
nsp_dict = {}
for i in res:
- nsp_dict[i[0]] = dict(
- nspowner=i[1],
- nspacl=i[2] if i[2] else '',
+ nsp_dict[i["nspname"]] = dict(
+ nspowner=i["rolname"],
+ nspacl=i["nspacl"] if i["nspacl"] else '',
)
return nsp_dict
@@ -983,7 +990,7 @@ class PgClusterInfo(object):
def get_pg_version(self):
"""Get major and minor PostgreSQL server version."""
query = "SELECT version()"
- raw = self.__exec_sql(query)[0][0]
+ raw = self.__exec_sql(query)[0]["version"]
full = raw.split()[1]
m = re.match(r"(\d+)\.(\d+)(?:\.(\d+))?", full)
@@ -1005,21 +1012,21 @@ class PgClusterInfo(object):
def get_recovery_state(self):
"""Get if the service is in recovery mode."""
- self.pg_info["in_recovery"] = self.__exec_sql("SELECT pg_is_in_recovery()")[0][0]
+ self.pg_info["in_recovery"] = self.__exec_sql("SELECT pg_is_in_recovery()")[0]["pg_is_in_recovery"]
def get_db_info(self):
"""Get information about the current database."""
# Following query returns:
# Name, Owner, Encoding, Collate, Ctype, Access Priv, Size
query = ("SELECT d.datname, "
- "pg_catalog.pg_get_userbyid(d.datdba), "
- "pg_catalog.pg_encoding_to_char(d.encoding), "
+ "pg_catalog.pg_get_userbyid(d.datdba) AS username, "
+ "pg_catalog.pg_encoding_to_char(d.encoding) AS encoding, "
"d.datcollate, "
"d.datctype, "
- "pg_catalog.array_to_string(d.datacl, E'\n'), "
+ "pg_catalog.array_to_string(d.datacl, E'\n') aclstring, "
"CASE WHEN pg_catalog.has_database_privilege(d.datname, 'CONNECT') "
"THEN pg_catalog.pg_database_size(d.datname)::text "
- "ELSE 'No Access' END, "
+ "ELSE 'No Access' END as dbsize, "
"t.spcname "
"FROM pg_catalog.pg_database AS d "
"JOIN pg_catalog.pg_tablespace t ON d.dattablespace = t.oid "
@@ -1029,16 +1036,16 @@ class PgClusterInfo(object):
db_dict = {}
for i in res:
- db_dict[i[0]] = dict(
- owner=i[1],
- encoding=i[2],
- collate=i[3],
- ctype=i[4],
- access_priv=i[5] if i[5] else '',
- size=i[6],
+ db_dict[i["datname"]] = dict(
+ owner=i["username"],
+ encoding=i["encoding"],
+ collate=i["datcollate"],
+ ctype=i["datctype"],
+ access_priv=i["aclstring"] if i["aclstring"] else '',
+ size=i["dbsize"],
)
- if self.cursor.connection.server_version >= 100000:
+ if get_server_version(self.cursor.connection) >= 100000:
subscr_info = self.get_subscr_info()
for datname in db_dict:
@@ -1053,7 +1060,7 @@ class PgClusterInfo(object):
db_dict[datname]['namespaces'] = self.get_namespaces()
db_dict[datname]['extensions'] = self.get_ext_info()
db_dict[datname]['languages'] = self.get_lang_info()
- if self.cursor.connection.server_version >= 100000:
+ if get_server_version(self.cursor.connection) >= 100000:
db_dict[datname]['publications'] = self.get_pub_info()
db_dict[datname]['subscriptions'] = subscr_info.get(datname, {})
@@ -1061,7 +1068,7 @@ class PgClusterInfo(object):
def __get_pretty_val(self, setting):
"""Get setting's value represented by SHOW command."""
- return self.__exec_sql('SHOW "%s"' % setting)[0][0]
+ return self.__exec_sql('SHOW "%s"' % setting)[0][setting]
def __exec_sql(self, query):
"""Execute SQL and return the result."""
diff --git a/ansible_collections/community/postgresql/plugins/modules/postgresql_lang.py b/ansible_collections/community/postgresql/plugins/modules/postgresql_lang.py
index 3d696dba6..2e9ac5b1b 100644
--- a/ansible_collections/community/postgresql/plugins/modules/postgresql_lang.py
+++ b/ansible_collections/community/postgresql/plugins/modules/postgresql_lang.py
@@ -5,6 +5,7 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
@@ -12,6 +13,10 @@ DOCUMENTATION = r'''
---
module: postgresql_lang
short_description: Adds, removes or changes procedural languages with a PostgreSQL database
+deprecated:
+ removed_in: "4.0.0"
+ why: As of PostgreSQL 9.1, most procedural languages have been made into extensions.
+ alternative: Use M(community.postgresql.postgresql_ext) instead.
description:
- Adds, removes or changes procedural languages with a PostgreSQL database.
- This module allows you to add a language, remote a language or change the trust
@@ -163,17 +168,21 @@ EXAMPLES = r'''
RETURN = r'''
queries:
description: List of executed queries.
- returned: always
+ returned: success
type: list
sample: ['CREATE LANGUAGE "acme"']
'''
+# WARNING - The postgresql_lang module has been deprecated and will be removed in community.postgresql 4.0.0.
+
from ansible.module_utils.basic import AnsibleModule
-from ansible_collections.community.postgresql.plugins.module_utils.database import check_input
+from ansible_collections.community.postgresql.plugins.module_utils.database import \
+ check_input
from ansible_collections.community.postgresql.plugins.module_utils.postgres import (
connect_to_db,
ensure_required_libs,
get_conn_params,
+ pg_cursor_args,
postgres_common_argument_spec,
)
@@ -191,7 +200,7 @@ def lang_istrusted(cursor, lang):
"""Checks if language is trusted for db"""
query = "SELECT lanpltrusted FROM pg_language WHERE lanname = %(lang)s"
cursor.execute(query, {'lang': lang})
- return cursor.fetchone()[0]
+ return cursor.fetchone()["lanpltrusted"]
def lang_altertrust(cursor, lang, trust):
@@ -235,21 +244,21 @@ def get_lang_owner(cursor, lang):
"""Get language owner.
Args:
- cursor (cursor): psycopg2 cursor object.
+ cursor (cursor): psycopg cursor object.
lang (str): language name.
"""
query = ("SELECT r.rolname FROM pg_language l "
"JOIN pg_roles r ON l.lanowner = r.oid "
"WHERE l.lanname = %(lang)s")
cursor.execute(query, {'lang': lang})
- return cursor.fetchone()[0]
+ return cursor.fetchone()["rolname"]
def set_lang_owner(cursor, lang, owner):
"""Set language owner.
Args:
- cursor (cursor): psycopg2 cursor object.
+ cursor (cursor): psycopg cursor object.
lang (str): language name.
owner (str): name of new owner.
"""
@@ -294,11 +303,11 @@ def main():
# Check input for potentially dangerous elements:
check_input(module, lang, session_role, owner)
- # Ensure psycopg2 libraries are available before connecting to DB:
+ # Ensure psycopg libraries are available before connecting to DB:
ensure_required_libs(module)
conn_params = get_conn_params(module, module.params)
db_connection, dummy = connect_to_db(module, conn_params, autocommit=False)
- cursor = db_connection.cursor()
+ cursor = db_connection.cursor(**pg_cursor_args)
changed = False
kw = {'db': db, 'lang': lang, 'trust': trust}
diff --git a/ansible_collections/community/postgresql/plugins/modules/postgresql_membership.py b/ansible_collections/community/postgresql/plugins/modules/postgresql_membership.py
index 68d7db2ef..e3b72d20a 100644
--- a/ansible_collections/community/postgresql/plugins/modules/postgresql_membership.py
+++ b/ansible_collections/community/postgresql/plugins/modules/postgresql_membership.py
@@ -4,7 +4,8 @@
# Copyright: (c) 2019, Andrew Klychkov (@Andersson007) <aaklychkov@mail.ru>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
DOCUMENTATION = r'''
@@ -143,7 +144,7 @@ EXAMPLES = r'''
RETURN = r'''
queries:
description: List of executed queries.
- returned: always
+ returned: success
type: str
sample: [ "GRANT \"user_ro\" TO \"alice\"" ]
granted:
@@ -158,33 +159,28 @@ revoked:
sample: { "ro_group": [ "alice", "bob" ] }
state:
description: Membership state that tried to be set.
- returned: always
+ returned: success
type: str
sample: "present"
'''
-try:
- from psycopg2.extras import DictCursor
-except ImportError:
- # psycopg2 is checked by connect_to_db()
- # from ansible.module_utils.postgres
- pass
-
from ansible.module_utils.basic import AnsibleModule
-from ansible_collections.community.postgresql.plugins.module_utils.database import check_input
+from ansible_collections.community.postgresql.plugins.module_utils.database import \
+ check_input
from ansible_collections.community.postgresql.plugins.module_utils.postgres import (
+ PgMembership,
connect_to_db,
ensure_required_libs,
get_conn_params,
- PgMembership,
+ pg_cursor_args,
postgres_common_argument_spec,
)
-
# ===========================================
# Module execution.
#
+
def main():
argument_spec = postgres_common_argument_spec()
argument_spec.update(
@@ -212,11 +208,11 @@ def main():
# Check input for potentially dangerous elements:
check_input(module, groups, target_roles, session_role)
- # Ensure psycopg2 libraries are available before connecting to DB:
+ # Ensure psycopg libraries are available before connecting to DB:
ensure_required_libs(module)
conn_params = get_conn_params(module, module.params, warn_db_default=False)
db_connection, dummy = connect_to_db(module, conn_params, autocommit=False)
- cursor = db_connection.cursor(cursor_factory=DictCursor)
+ cursor = db_connection.cursor(**pg_cursor_args)
##############
# Create the object and do main job:
diff --git a/ansible_collections/community/postgresql/plugins/modules/postgresql_owner.py b/ansible_collections/community/postgresql/plugins/modules/postgresql_owner.py
index 934e3b957..35e960fac 100644
--- a/ansible_collections/community/postgresql/plugins/modules/postgresql_owner.py
+++ b/ansible_collections/community/postgresql/plugins/modules/postgresql_owner.py
@@ -4,7 +4,8 @@
# Copyright: (c) 2019, Andrew Klychkov (@Andersson007) <aaklychkov@mail.ru>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
DOCUMENTATION = r'''
@@ -30,8 +31,14 @@ options:
description:
- Type of a database object.
- Mutually exclusive with I(reassign_owned_by).
+ - I(obj_type=matview) is available since PostgreSQL 9.3.
+ - I(obj_type=event_trigger), I(obj_type=procedure), I(obj_type=publication),
+ I(obj_type=statistics), and I(obj_type=routine) are available since PostgreSQL 11.
type: str
- choices: [ database, function, matview, sequence, schema, table, tablespace, view ]
+ choices: [ aggregate, collation, conversion, database, domain, event_trigger, foreign_data_wrapper,
+ foreign_table, function, language, large_object, matview, procedure, publication, routine,
+ schema, sequence, server, statistics, table, tablespace, text_search_configuration,
+ text_search_dictionary, type, view ]
aliases:
- type
reassign_owned_by:
@@ -74,10 +81,20 @@ options:
type: bool
default: true
version_added: '0.2.0'
+
+notes:
+- Function Overloading is not supported so when I(obj_type) is C(aggregate), C(function), C(routine), or C(procedure)
+ I(obj_name) is considered the only object of same type with this name.
+- Despite Function Overloading is not supported, when I(obj_type=aggregate) I(obj_name) must contain also aggregate
+ signature because it is required by SQL syntax.
+- I(new_owner) must be a superuser if I(obj_type) is C(event_type) or C(foreign_data_wrapper).
+- To manage subscriptions ownership use C(community.postgresql.postgresql_subscription) module.
+
seealso:
- module: community.postgresql.postgresql_user
- module: community.postgresql.postgresql_privs
- module: community.postgresql.postgresql_membership
+- module: community.postgresql.postgresql_subscription
- name: PostgreSQL REASSIGN OWNED command reference
description: Complete reference of the PostgreSQL REASSIGN OWNED command documentation.
link: https://www.postgresql.org/docs/current/sql-reassign-owned.html
@@ -88,6 +105,7 @@ attributes:
author:
- Andrew Klychkov (@Andersson007)
+- Daniele Giudice (@RealGreenDragon)
extends_documentation_fragment:
- community.postgresql.postgres
@@ -143,18 +161,11 @@ EXAMPLES = r'''
RETURN = r'''
queries:
description: List of executed queries.
- returned: always
+ returned: success
type: str
sample: [ 'REASSIGN OWNED BY "bob" TO "alice"' ]
'''
-try:
- from psycopg2.extras import DictCursor
-except ImportError:
- # psycopg2 is checked by connect_to_db()
- # from ansible.module_utils.postgres
- pass
-
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.postgresql.plugins.module_utils.database import (
check_input,
@@ -162,12 +173,19 @@ from ansible_collections.community.postgresql.plugins.module_utils.database impo
)
from ansible_collections.community.postgresql.plugins.module_utils.postgres import (
connect_to_db,
- exec_sql,
ensure_required_libs,
+ exec_sql,
get_conn_params,
+ get_server_version,
+ pg_cursor_args,
postgres_common_argument_spec,
)
+VALID_OBJ_TYPES = ('aggregate', 'collation', 'conversion', 'database', 'domain', 'event_trigger', 'foreign_data_wrapper',
+ 'foreign_table', 'function', 'language', 'large_object', 'matview', 'procedure', 'publication',
+ 'routine', 'schema', 'sequence', 'server', 'statistics', 'table', 'tablespace', 'text_search_configuration',
+ 'text_search_dictionary', 'type', 'view')
+
class PgOwnership(object):
@@ -175,7 +193,7 @@ class PgOwnership(object):
Arguments:
module (AnsibleModule): Object of Ansible module class.
- cursor (psycopg2.connect.cursor): Cursor object for interaction with the database.
+ cursor (psycopg.connect.cursor): Cursor object for interaction with the database.
role (str): Role name to set as a new owner of objects.
Important:
@@ -187,9 +205,10 @@ class PgOwnership(object):
That's all.
"""
- def __init__(self, module, cursor, role):
+ def __init__(self, module, cursor, pg_version, role):
self.module = module
self.cursor = cursor
+ self.pg_version = pg_version
self.check_role_exists(role)
self.role = role
self.changed = False
@@ -285,6 +304,57 @@ class PgOwnership(object):
elif obj_type == 'matview':
self.__set_mat_view_owner()
+ elif obj_type == 'procedure':
+ self.__set_procedure_owner()
+
+ elif obj_type == 'type':
+ self.__set_type_owner()
+
+ elif obj_type == 'aggregate':
+ self.__set_aggregate_owner()
+
+ elif obj_type == 'routine':
+ self.__set_routine_owner()
+
+ elif obj_type == 'language':
+ self.__set_language_owner()
+
+ elif obj_type == 'domain':
+ self.__set_domain_owner()
+
+ elif obj_type == 'collation':
+ self.__set_collation_owner()
+
+ elif obj_type == 'conversion':
+ self.__set_conversion_owner()
+
+ elif obj_type == 'text_search_configuration':
+ self.__set_text_search_configuration_owner()
+
+ elif obj_type == 'text_search_dictionary':
+ self.__set_text_search_dictionary_owner()
+
+ elif obj_type == 'foreign_data_wrapper':
+ self.__set_foreign_data_wrapper_owner()
+
+ elif obj_type == 'server':
+ self.__set_server_owner()
+
+ elif obj_type == 'foreign_table':
+ self.__set_foreign_table_owner()
+
+ elif obj_type == 'event_trigger':
+ self.__set_event_trigger_owner()
+
+ elif obj_type == 'large_object':
+ self.__set_large_object_owner()
+
+ elif obj_type == 'publication':
+ self.__set_publication_owner()
+
+ elif obj_type == 'statistics':
+ self.__set_statistics_owner()
+
def __is_owner(self):
"""Return True if self.role is the current object owner."""
if self.obj_type == 'table':
@@ -298,7 +368,11 @@ class PgOwnership(object):
"WHERE d.datname = %(obj_name)s "
"AND r.rolname = %(role)s")
- elif self.obj_type == 'function':
+ elif self.obj_type in ('aggregate', 'function', 'routine', 'procedure'):
+ if self.obj_type == 'routine' and self.pg_version < 110000:
+ self.module.fail_json(msg="PostgreSQL version must be >= 11 for obj_type=routine.")
+ if self.obj_type == 'procedure' and self.pg_version < 110000:
+ self.module.fail_json(msg="PostgreSQL version must be >= 11 for obj_type=procedure.")
query = ("SELECT 1 FROM pg_proc AS f "
"JOIN pg_roles AS r ON f.proowner = r.oid "
"WHERE f.proname = %(obj_name)s "
@@ -327,11 +401,101 @@ class PgOwnership(object):
"AND viewowner = %(role)s")
elif self.obj_type == 'matview':
+ if self.pg_version < 90300:
+ self.module.fail_json(msg="PostgreSQL version must be >= 9.3 for obj_type=matview.")
query = ("SELECT 1 FROM pg_matviews "
"WHERE matviewname = %(obj_name)s "
"AND matviewowner = %(role)s")
- query_params = {'obj_name': self.obj_name, 'role': self.role}
+ elif self.obj_type in ('domain', 'type'):
+ query = ("SELECT 1 FROM pg_type AS t "
+ "JOIN pg_roles AS r ON t.typowner = r.oid "
+ "WHERE t.typname = %(obj_name)s "
+ "AND r.rolname = %(role)s")
+
+ elif self.obj_type == 'language':
+ query = ("SELECT 1 FROM pg_language AS l "
+ "JOIN pg_roles AS r ON l.lanowner = r.oid "
+ "WHERE l.lanname = %(obj_name)s "
+ "AND r.rolname = %(role)s")
+
+ elif self.obj_type == 'collation':
+ query = ("SELECT 1 FROM pg_collation AS c "
+ "JOIN pg_roles AS r ON c.collowner = r.oid "
+ "WHERE c.collname = %(obj_name)s "
+ "AND r.rolname = %(role)s")
+
+ elif self.obj_type == 'conversion':
+ query = ("SELECT 1 FROM pg_conversion AS c "
+ "JOIN pg_roles AS r ON c.conowner = r.oid "
+ "WHERE c.conname = %(obj_name)s "
+ "AND r.rolname = %(role)s")
+
+ elif self.obj_type == 'text_search_configuration':
+ query = ("SELECT 1 FROM pg_ts_config AS t "
+ "JOIN pg_roles AS r ON t.cfgowner = r.oid "
+ "WHERE t.cfgname = %(obj_name)s "
+ "AND r.rolname = %(role)s")
+
+ elif self.obj_type == 'text_search_dictionary':
+ query = ("SELECT 1 FROM pg_ts_dict AS t "
+ "JOIN pg_roles AS r ON t.dictowner = r.oid "
+ "WHERE t.dictname = %(obj_name)s "
+ "AND r.rolname = %(role)s")
+
+ elif self.obj_type == 'foreign_data_wrapper':
+ query = ("SELECT 1 FROM pg_foreign_data_wrapper AS f "
+ "JOIN pg_roles AS r ON f.fdwowner = r.oid "
+ "WHERE f.fdwname = %(obj_name)s "
+ "AND r.rolname = %(role)s")
+
+ elif self.obj_type == 'server':
+ query = ("SELECT 1 FROM pg_foreign_server AS f "
+ "JOIN pg_roles AS r ON f.srvowner = r.oid "
+ "WHERE f.srvname = %(obj_name)s "
+ "AND r.rolname = %(role)s")
+
+ elif self.obj_type == 'foreign_table':
+ query = ("SELECT 1 FROM pg_class AS c "
+ "JOIN pg_roles AS r ON c.relowner = r.oid "
+ "WHERE c.relkind = 'f' AND c.relname = %(obj_name)s "
+ "AND r.rolname = %(role)s")
+
+ elif self.obj_type == 'event_trigger':
+ if self.pg_version < 110000:
+ self.module.fail_json(msg="PostgreSQL version must be >= 11 for obj_type=event_trigger.")
+ query = ("SELECT 1 FROM pg_event_trigger AS e "
+ "JOIN pg_roles AS r ON e.evtowner = r.oid "
+ "WHERE e.evtname = %(obj_name)s "
+ "AND r.rolname = %(role)s")
+
+ elif self.obj_type == 'large_object':
+ query = ("SELECT 1 FROM pg_largeobject_metadata AS l "
+ "JOIN pg_roles AS r ON l.lomowner = r.oid "
+ "WHERE l.oid = %(obj_name)s "
+ "AND r.rolname = %(role)s")
+
+ elif self.obj_type == 'publication':
+ if self.pg_version < 110000:
+ self.module.fail_json(msg="PostgreSQL version must be >= 11 for obj_type=publication.")
+ query = ("SELECT 1 FROM pg_publication AS p "
+ "JOIN pg_roles AS r ON p.pubowner = r.oid "
+ "WHERE p.pubname = %(obj_name)s "
+ "AND r.rolname = %(role)s")
+
+ elif self.obj_type == 'statistics':
+ if self.pg_version < 110000:
+ self.module.fail_json(msg="PostgreSQL version must be >= 11 for obj_type=statistics.")
+ query = ("SELECT 1 FROM pg_statistic_ext AS s "
+ "JOIN pg_roles AS r ON s.stxowner = r.oid "
+ "WHERE s.stxname = %(obj_name)s "
+ "AND r.rolname = %(role)s")
+
+ if self.obj_type in ('function', 'aggregate', 'procedure', 'routine'):
+ query_params = {'obj_name': self.obj_name.split('(')[0], 'role': self.role}
+ else:
+ query_params = {'obj_name': self.obj_name, 'role': self.role}
+
return exec_sql(self, query, query_params, add_to_executed=False)
def __set_db_owner(self):
@@ -346,7 +510,7 @@ class PgOwnership(object):
def __set_seq_owner(self):
"""Set the sequence owner."""
- query = 'ALTER SEQUENCE %s OWNER TO "%s"' % (pg_quote_identifier(self.obj_name, 'table'),
+ query = 'ALTER SEQUENCE %s OWNER TO "%s"' % (pg_quote_identifier(self.obj_name, 'sequence'),
self.role)
self.changed = exec_sql(self, query, return_bool=True)
@@ -375,10 +539,121 @@ class PgOwnership(object):
def __set_mat_view_owner(self):
"""Set the materialized view owner."""
+ if self.pg_version < 90300:
+ self.module.fail_json(msg="PostgreSQL version must be >= 9.3 for obj_type=matview.")
+
query = 'ALTER MATERIALIZED VIEW %s OWNER TO "%s"' % (pg_quote_identifier(self.obj_name, 'table'),
self.role)
self.changed = exec_sql(self, query, return_bool=True)
+ def __set_procedure_owner(self):
+ """Set the procedure owner."""
+ if self.pg_version < 110000:
+ self.module.fail_json(msg="PostgreSQL version must be >= 11 for obj_type=procedure.")
+
+ query = 'ALTER PROCEDURE %s OWNER TO "%s"' % (pg_quote_identifier(self.obj_name, 'table'),
+ self.role)
+ self.changed = exec_sql(self, query, return_bool=True)
+
+ def __set_type_owner(self):
+ """Set the type owner."""
+ query = 'ALTER TYPE %s OWNER TO "%s"' % (pg_quote_identifier(self.obj_name, 'table'),
+ self.role)
+ self.changed = exec_sql(self, query, return_bool=True)
+
+ def __set_aggregate_owner(self):
+ """Set the aggregate owner."""
+ query = 'ALTER AGGREGATE %s OWNER TO "%s"' % (self.obj_name, self.role)
+ self.changed = exec_sql(self, query, return_bool=True)
+
+ def __set_routine_owner(self):
+ """Set the routine owner."""
+ if self.pg_version < 110000:
+ self.module.fail_json(msg="PostgreSQL version must be >= 11 for obj_type=routine.")
+ query = 'ALTER ROUTINE %s OWNER TO "%s"' % (pg_quote_identifier(self.obj_name, 'table'),
+ self.role)
+ self.changed = exec_sql(self, query, return_bool=True)
+
+ def __set_language_owner(self):
+ """Set the language owner."""
+ query = 'ALTER LANGUAGE %s OWNER TO "%s"' % (self.obj_name, self.role)
+ self.changed = exec_sql(self, query, return_bool=True)
+
+ def __set_domain_owner(self):
+ """Set the domain owner."""
+ query = 'ALTER DOMAIN %s OWNER TO "%s"' % (pg_quote_identifier(self.obj_name, 'table'),
+ self.role)
+ self.changed = exec_sql(self, query, return_bool=True)
+
+ def __set_collation_owner(self):
+ """Set the collation owner."""
+ query = 'ALTER COLLATION %s OWNER TO "%s"' % (pg_quote_identifier(self.obj_name, 'table'),
+ self.role)
+ self.changed = exec_sql(self, query, return_bool=True)
+
+ def __set_conversion_owner(self):
+ """Set the conversion owner."""
+ query = 'ALTER CONVERSION %s OWNER TO "%s"' % (pg_quote_identifier(self.obj_name, 'table'),
+ self.role)
+ self.changed = exec_sql(self, query, return_bool=True)
+
+ def __set_text_search_configuration_owner(self):
+ """Set the text search configuration owner."""
+ query = 'ALTER TEXT SEARCH CONFIGURATION %s OWNER TO "%s"' % (pg_quote_identifier(self.obj_name, 'table'),
+ self.role)
+ self.changed = exec_sql(self, query, return_bool=True)
+
+ def __set_text_search_dictionary_owner(self):
+ """Set the text search dictionary owner."""
+ query = 'ALTER TEXT SEARCH DICTIONARY %s OWNER TO "%s"' % (pg_quote_identifier(self.obj_name, 'table'),
+ self.role)
+ self.changed = exec_sql(self, query, return_bool=True)
+
+ def __set_foreign_data_wrapper_owner(self):
+ """Set the foreign data wrapper owner."""
+ query = 'ALTER FOREIGN DATA WRAPPER %s OWNER TO "%s"' % (pg_quote_identifier(self.obj_name, 'table'),
+ self.role)
+ self.changed = exec_sql(self, query, return_bool=True)
+
+ def __set_server_owner(self):
+ """Set the server owner."""
+ query = 'ALTER SERVER %s OWNER TO "%s"' % (pg_quote_identifier(self.obj_name, 'table'),
+ self.role)
+ self.changed = exec_sql(self, query, return_bool=True)
+
+ def __set_foreign_table_owner(self):
+ """Set the foreign table owner."""
+ query = 'ALTER FOREIGN TABLE %s OWNER TO "%s"' % (pg_quote_identifier(self.obj_name, 'table'),
+ self.role)
+ self.changed = exec_sql(self, query, return_bool=True)
+
+ def __set_event_trigger_owner(self):
+ """Set the event trigger owner."""
+ query = 'ALTER EVENT TRIGGER %s OWNER TO "%s"' % (pg_quote_identifier(self.obj_name, 'table'),
+ self.role)
+ self.changed = exec_sql(self, query, return_bool=True)
+
+ def __set_large_object_owner(self):
+ """Set the large object owner."""
+ query = 'ALTER LARGE OBJECT %s OWNER TO "%s"' % (self.obj_name, self.role)
+ self.changed = exec_sql(self, query, return_bool=True)
+
+ def __set_publication_owner(self):
+ """Set the publication owner."""
+ if self.pg_version < 110000:
+ self.module.fail_json(msg="PostgreSQL version must be >= 11 for obj_type=publication.")
+ query = 'ALTER PUBLICATION %s OWNER TO "%s"' % (pg_quote_identifier(self.obj_name, 'publication'),
+ self.role)
+ self.changed = exec_sql(self, query, return_bool=True)
+
+ def __set_statistics_owner(self):
+ """Set the statistics owner."""
+ if self.pg_version < 110000:
+ self.module.fail_json(msg="PostgreSQL version must be >= 11 for obj_type=statistics.")
+ query = 'ALTER STATISTICS %s OWNER TO "%s"' % (pg_quote_identifier(self.obj_name, 'table'),
+ self.role)
+ self.changed = exec_sql(self, query, return_bool=True)
+
def __role_exists(self, role):
"""Return True if role exists, otherwise return False."""
query_params = {'role': role}
@@ -390,14 +665,12 @@ class PgOwnership(object):
# Module execution.
#
-
def main():
argument_spec = postgres_common_argument_spec()
argument_spec.update(
new_owner=dict(type='str', required=True),
obj_name=dict(type='str'),
- obj_type=dict(type='str', aliases=['type'], choices=[
- 'database', 'function', 'matview', 'sequence', 'schema', 'table', 'tablespace', 'view']),
+ obj_type=dict(type='str', aliases=['type'], choices=VALID_OBJ_TYPES),
reassign_owned_by=dict(type='list', elements='str'),
fail_on_role=dict(type='bool', default=True),
db=dict(type='str', aliases=['login_db']),
@@ -426,15 +699,16 @@ def main():
# Check input for potentially dangerous elements:
check_input(module, new_owner, obj_name, reassign_owned_by, session_role)
- # Ensure psycopg2 libraries are available before connecting to DB:
+ # Ensure psycopg libraries are available before connecting to DB:
ensure_required_libs(module)
conn_params = get_conn_params(module, module.params)
db_connection, dummy = connect_to_db(module, conn_params, autocommit=False)
- cursor = db_connection.cursor(cursor_factory=DictCursor)
+ cursor = db_connection.cursor(**pg_cursor_args)
+ pg_version = get_server_version(db_connection)
##############
# Create the object and do main job:
- pg_ownership = PgOwnership(module, cursor, new_owner)
+ pg_ownership = PgOwnership(module, cursor, pg_version, new_owner)
# if we want to change ownership:
if obj_name:
diff --git a/ansible_collections/community/postgresql/plugins/modules/postgresql_pg_hba.py b/ansible_collections/community/postgresql/plugins/modules/postgresql_pg_hba.py
index 002e7817d..82f5df173 100644
--- a/ansible_collections/community/postgresql/plugins/modules/postgresql_pg_hba.py
+++ b/ansible_collections/community/postgresql/plugins/modules/postgresql_pg_hba.py
@@ -80,16 +80,6 @@ options:
description:
- Additional options for the authentication I(method).
type: str
- order:
- description:
- - The entries will be written out in a specific order.
- With this option you can control by which field they are ordered first, second and last.
- s=source, d=databases, u=users.
- This option is deprecated since 2.9 and will be removed in community.postgresql 3.0.0.
- Sortorder is now hardcoded to sdu.
- type: str
- default: sdu
- choices: [ sdu, sud, dsu, dus, usd, uds ]
overwrite:
description:
- Remove all existing rules before adding rules. (Like I(state=absent) for all pre-existing rules.)
@@ -143,7 +133,6 @@ notes:
In that situation, the 'ip specific rule' will never hit, it is in the C(pg_hba) file obsolete.
After the C(pg_hba) file is rewritten by the M(community.postgresql.postgresql_pg_hba) module, the ip specific rule will be sorted above the range rule.
And then it will hit, which will give unexpected results.
- - With the 'order' parameter you can control which field is used to sort first, next and last.
seealso:
- name: PostgreSQL pg_hba.conf file reference
@@ -232,7 +221,7 @@ EXAMPLES = '''
RETURN = r'''
msgs:
description: List of textual messages what was done.
- returned: always
+ returned: success
type: list
sample:
"msgs": [
@@ -247,7 +236,7 @@ backup_file:
sample: /tmp/pg_hba_jxobj_p
pg_hba:
description: List of the pg_hba rules as they are configured in the specified hba file.
- returned: always
+ returned: success
type: list
sample:
"pg_hba": [
@@ -271,8 +260,9 @@ try:
except ImportError:
IPADDRESS_IMP_ERR = traceback.format_exc()
-import tempfile
import shutil
+import tempfile
+
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
# from ansible.module_utils.postgres import postgres_common_argument_spec
@@ -280,7 +270,6 @@ from ansible.module_utils.basic import AnsibleModule, missing_required_lib
PG_HBA_METHODS = ["trust", "reject", "md5", "password", "gss", "sspi", "krb5", "ident", "peer",
"ldap", "radius", "cert", "pam", "scram-sha-256"]
PG_HBA_TYPES = ["local", "host", "hostssl", "hostnossl", "hostgssenc", "hostnogssenc"]
-PG_HBA_ORDERS = ["sdu", "sud", "dsu", "dus", "usd", "uds"]
PG_HBA_HDR = ['type', 'db', 'usr', 'src', 'mask', 'method', 'options']
WHITESPACES_RE = re.compile(r'\s+')
@@ -322,14 +311,10 @@ class PgHba(object):
pg_hba_file - the pg_hba file almost always /etc/pg_hba
"""
- def __init__(self, pg_hba_file=None, order="sdu", backup=False, create=False, keep_comments_at_rules=False):
- if order not in PG_HBA_ORDERS:
- msg = "invalid order setting {0} (should be one of '{1}')."
- raise PgHbaError(msg.format(order, "', '".join(PG_HBA_ORDERS)))
+ def __init__(self, pg_hba_file=None, backup=False, create=False, keep_comments_at_rules=False):
self.pg_hba_file = pg_hba_file
self.rules = None
self.comment = None
- self.order = order
self.backup = backup
self.last_backup = None
self.create = create
@@ -512,7 +497,7 @@ class PgHbaRule(dict):
def __init__(self, contype=None, databases=None, users=None, source=None, netmask=None,
method=None, options=None, line=None, comment=None):
'''
- This function can be called with a comma seperated list of databases and a comma seperated
+ This function can be called with a comma separated list of databases and a comma separated
list of users and it will act as a generator that returns a expanded list of rules one by
one.
'''
@@ -535,11 +520,11 @@ class PgHbaRule(dict):
# Some sanity checks
for key in ['method', 'type']:
if key not in self:
- raise PgHbaRuleError('Missing {0} in rule {1}'.format(key, self))
+ raise PgHbaRuleError('Missing {method} in rule {rule}'.format(method=key, rule=self))
if self['method'] not in PG_HBA_METHODS:
- msg = "invalid method {0} (should be one of '{1}')."
- raise PgHbaRuleValueError(msg.format(self['method'], "', '".join(PG_HBA_METHODS)))
+ msg = "invalid method {method} (should be one of '{valid_methods}')."
+ raise PgHbaRuleValueError(msg.format(method=self['method'], valid_methods="', '".join(PG_HBA_METHODS)))
if self['type'] not in PG_HBA_TYPES:
msg = "invalid connection type {0} (should be one of '{1}')."
@@ -549,7 +534,7 @@ class PgHbaRule(dict):
self.unset('src')
self.unset('mask')
elif 'src' not in self:
- raise PgHbaRuleError('Missing src in rule {1}'.format(self))
+ raise PgHbaRuleError('Missing src in rule {rule}'.format(rule=self))
elif '/' in self['src']:
self.unset('mask')
else:
@@ -722,7 +707,7 @@ class PgHbaRule(dict):
# hostname, let's assume only one host matches, which is
# IPv4/32 or IPv6/128 (both have weight 128)
return 128
- raise PgHbaValueError('Cannot deduct the source weight of this source {1}'.format(sourceobj))
+ raise PgHbaValueError('Cannot deduct the source weight of this source {sourceobj}'.format(sourceobj=sourceobj))
def source_type_weight(self):
"""Give a weight on the type of this source.
@@ -780,8 +765,6 @@ def main():
method=dict(type='str', default='md5', choices=PG_HBA_METHODS),
netmask=dict(type='str'),
options=dict(type='str'),
- order=dict(type='str', default="sdu", choices=PG_HBA_ORDERS,
- removed_in_version='3.0.0', removed_from_collection='community.postgresql'),
keep_comments_at_rules=dict(type='bool', default=False),
state=dict(type='str', default="present", choices=["absent", "present"]),
users=dict(type='str', default='all'),
@@ -803,7 +786,6 @@ def main():
else:
backup = module.params['backup']
dest = module.params["dest"]
- order = module.params["order"]
keep_comments_at_rules = module.params["keep_comments_at_rules"]
rules = module.params["rules"]
rules_behavior = module.params["rules_behavior"]
@@ -811,7 +793,7 @@ def main():
ret = {'msgs': []}
try:
- pg_hba = PgHba(dest, order, backup=backup, create=create, keep_comments_at_rules=keep_comments_at_rules)
+ pg_hba = PgHba(dest, backup=backup, create=create, keep_comments_at_rules=keep_comments_at_rules)
except PgHbaError as error:
module.fail_json(msg='Error reading file:\n{0}'.format(error))
diff --git a/ansible_collections/community/postgresql/plugins/modules/postgresql_ping.py b/ansible_collections/community/postgresql/plugins/modules/postgresql_ping.py
index fd104022b..e04f45376 100644
--- a/ansible_collections/community/postgresql/plugins/modules/postgresql_ping.py
+++ b/ansible_collections/community/postgresql/plugins/modules/postgresql_ping.py
@@ -5,6 +5,7 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
DOCUMENTATION = r'''
@@ -76,17 +77,17 @@ EXAMPLES = r'''
RETURN = r'''
is_available:
description: PostgreSQL server availability.
- returned: always
+ returned: success
type: bool
sample: true
server_version:
description: PostgreSQL server version.
- returned: always
+ returned: success
type: dict
sample: { major: 13, minor: 2, full: '13.2', raw: 'PostgreSQL 13.2 on x86_64-pc-linux-gnu' }
conn_err_msg:
description: Connection error message.
- returned: always
+ returned: success
type: str
sample: ''
version_added: 1.7.0
@@ -94,26 +95,18 @@ conn_err_msg:
import re
-try:
- from psycopg2.extras import DictCursor
-except ImportError:
- # psycopg2 is checked by connect_to_db()
- # from ansible.module_utils.postgres
- pass
-
from ansible.module_utils.basic import AnsibleModule
-from ansible_collections.community.postgresql.plugins.module_utils.database import (
- check_input,
-)
+from ansible_collections.community.postgresql.plugins.module_utils.database import \
+ check_input
from ansible_collections.community.postgresql.plugins.module_utils.postgres import (
connect_to_db,
- exec_sql,
ensure_required_libs,
+ exec_sql,
get_conn_params,
+ pg_cursor_args,
postgres_common_argument_spec,
)
-
# ===========================================
# PostgreSQL module specific support methods.
#
@@ -132,7 +125,7 @@ class PgPing(object):
def get_pg_version(self):
query = "SELECT version()"
- raw = exec_sql(self, query, add_to_executed=False)[0][0]
+ raw = exec_sql(self, query, add_to_executed=False)[0]["version"]
if not raw:
return
@@ -190,7 +183,7 @@ def main():
conn_err_msg='',
)
- # Ensure psycopg2 libraries are available before connecting to DB:
+ # Ensure psycopg libraries are available before connecting to DB:
ensure_required_libs(module)
conn_params = get_conn_params(module, module.params, warn_db_default=False)
db_connection, err = connect_to_db(module, conn_params, fail_on_conn=False)
@@ -198,7 +191,7 @@ def main():
result['conn_err_msg'] = err
if db_connection is not None:
- cursor = db_connection.cursor(cursor_factory=DictCursor)
+ cursor = db_connection.cursor(**pg_cursor_args)
# Do job:
pg_ping = PgPing(module, cursor)
diff --git a/ansible_collections/community/postgresql/plugins/modules/postgresql_privs.py b/ansible_collections/community/postgresql/plugins/modules/postgresql_privs.py
index 44aaeba3b..2c4ca7086 100644
--- a/ansible_collections/community/postgresql/plugins/modules/postgresql_privs.py
+++ b/ansible_collections/community/postgresql/plugins/modules/postgresql_privs.py
@@ -6,6 +6,7 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
DOCUMENTATION = r'''
@@ -17,9 +18,6 @@ description:
- This module is basically a wrapper around most of the functionality of
PostgreSQL's GRANT and REVOKE statements with detection of changes
(GRANT/REVOKE I(privs) ON I(type) I(objs) TO/FROM I(roles)).
-- B(WARNING) The C(usage_on_types) option has been B(deprecated) and will be removed in
- community.postgresql 3.0.0, please use the C(type) option with value C(type) to
- GRANT/REVOKE permissions on types explicitly.
options:
database:
description:
@@ -48,10 +46,11 @@ options:
- The C(foreign_data_wrapper) and C(foreign_server) object types are available since Ansible version 2.8.
- The C(type) choice is available since Ansible version 2.10.
- The C(procedure) is supported since collection version 1.3.0 and PostgreSQL 11.
+ - The C(parameter) is supported since collection version 3.1.0 and PostgreSQL 15.
type: str
default: table
choices: [ database, default_privs, foreign_data_wrapper, foreign_server, function,
- group, language, table, tablespace, schema, sequence, type , procedure]
+ group, language, table, tablespace, schema, sequence, type, procedure, parameter ]
objs:
description:
- Comma separated list of database objects to set privileges on.
@@ -61,6 +60,7 @@ options:
(This also works with PostgreSQL < 9.0.) (C(ALL_IN_SCHEMA) is available
for C(function) and C(partition table) since Ansible 2.8).
- C(procedure) is supported since PostgreSQL 11 and community.postgresql collection 1.3.0.
+ - C(parameter) is supported since PostgreSQL 15 and community.postgresql collection 3.1.0.
- If I(type) is C(database), this parameter can be omitted, in which case
privileges are set for the database specified via I(database).
- If I(type) is C(function) or C(procedure), colons (":") in object names will be
@@ -80,8 +80,9 @@ options:
roles:
description:
- Comma separated list of role (user/group) names to set permissions for.
- - The special value C(PUBLIC) can be provided instead to set permissions
- for the implicitly defined PUBLIC group.
+ - Roles C(PUBLIC), C(CURRENT_ROLE), C(CURRENT_USER), C(SESSION_USER) are implicitly defined in PostgreSQL.
+ - C(CURRENT_USER) and C(SESSION_USER) implicit roles are supported since collection version 3.1.0 and PostgreSQL 9.5.
+ - C(CURRENT_ROLE) implicit role is supported since collection version 3.1.0 and PostgreSQL 14.
type: str
required: true
aliases:
@@ -128,18 +129,6 @@ options:
type: bool
default: true
version_added: '0.2.0'
- usage_on_types:
- description:
- - This option has been B(deprecated) and will be removed in community.postgresql 3.0.0,
- please use the I(type) option with value C(type) to GRANT/REVOKE permissions on types
- explicitly.
- - When adding default privileges, the module always implicitly adds ``USAGE ON TYPES``.
- - To avoid this behavior, set I(usage_on_types) to C(false).
- - Added to save backwards compatibility.
- - Used only when adding default privileges, ignored otherwise.
- type: bool
- default: true
- version_added: '1.2.0'
notes:
- Parameters that accept comma separated lists (I(privs), I(objs), I(roles))
@@ -148,7 +137,6 @@ notes:
C(present) and I(grant_option) to C(false) (see examples).
- Note that when revoking privileges from a role R, this role may still have
access via privileges granted to any role R is a member of including C(PUBLIC).
-- Note that when you use C(PUBLIC) role, the module always reports that the state has been changed.
- Note that when revoking privileges from a role R, you do so as the user
specified via I(login_user). If R has been granted the same privileges by
another user also, R can still access database objects via these privileges.
@@ -178,6 +166,7 @@ extends_documentation_fragment:
author:
- Bernhard Weitzhofer (@b6d)
- Tobias Birkefeld (@tcraxs)
+- Daniele Giudice (@RealGreenDragon)
'''
EXAMPLES = r'''
@@ -402,43 +391,74 @@ EXAMPLES = r'''
privs: usage
objs: schemas
role: datascience
+
+# Available since community.postgresql 3.1.0
+# Needs PostgreSQL 15 or higher
+- name: GRANT SET ON PARAMETER log_destination,log_line_prefix TO logtest
+ community.postgresql.postgresql_privs:
+ database: logtest
+ state: present
+ privs: SET
+ type: parameter
+ objs: log_destination,log_line_prefix
+ roles: logtest
+
+- name: GRANT ALTER SYSTEM ON PARAMETER primary_conninfo,synchronous_standby_names TO replicamgr
+ community.postgresql.postgresql_privs:
+ database: replicamgr
+ state: present
+ privs: ALTER_SYSTEM
+ type: parameter
+ objs: primary_conninfo,synchronous_standby_names
+ roles: replicamgr
'''
RETURN = r'''
queries:
description: List of executed queries.
- returned: always
+ returned: success
type: list
sample: ['REVOKE GRANT OPTION FOR INSERT ON TABLE "books" FROM "reader";']
'''
import traceback
-PSYCOPG2_IMP_ERR = None
-try:
- import psycopg2
- import psycopg2.extensions
-except ImportError:
- PSYCOPG2_IMP_ERR = traceback.format_exc()
- psycopg2 = None
-
+from ansible.module_utils._text import to_native
# import module snippets
-from ansible.module_utils.basic import AnsibleModule, missing_required_lib
+from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.postgresql.plugins.module_utils.database import (
- pg_quote_identifier,
check_input,
+ pg_quote_identifier,
)
-from ansible_collections.community.postgresql.plugins.module_utils.postgres import postgres_common_argument_spec, get_conn_params
-from ansible.module_utils._text import to_native
+from ansible_collections.community.postgresql.plugins.module_utils.postgres import (
+ HAS_PSYCOPG,
+ PSYCOPG_VERSION,
+ connect_to_db,
+ ensure_required_libs,
+ get_conn_params,
+ get_server_version,
+ pg_cursor_args,
+ postgres_common_argument_spec,
+)
+from ansible_collections.community.postgresql.plugins.module_utils.version import \
+ LooseVersion
-VALID_PRIVS = frozenset(('SELECT', 'INSERT', 'UPDATE', 'DELETE', 'TRUNCATE',
- 'REFERENCES', 'TRIGGER', 'CREATE', 'CONNECT',
- 'TEMPORARY', 'TEMP', 'EXECUTE', 'USAGE', 'ALL'))
+if HAS_PSYCOPG and PSYCOPG_VERSION < LooseVersion("3.0"):
+ from psycopg2 import Error as PsycopgError
+elif HAS_PSYCOPG:
+ from psycopg import Error as PsycopgError
+
+VALID_PRIVS = frozenset(('SELECT', 'INSERT', 'UPDATE', 'DELETE', 'TRUNCATE', 'REFERENCES', 'TRIGGER', 'CREATE',
+ 'CONNECT', 'TEMPORARY', 'TEMP', 'EXECUTE', 'USAGE', 'ALL', 'SET', 'ALTER_SYSTEM'))
VALID_DEFAULT_OBJS = {'TABLES': ('ALL', 'SELECT', 'INSERT', 'UPDATE', 'DELETE', 'TRUNCATE', 'REFERENCES', 'TRIGGER'),
'SEQUENCES': ('ALL', 'SELECT', 'UPDATE', 'USAGE'),
'FUNCTIONS': ('ALL', 'EXECUTE'),
'TYPES': ('ALL', 'USAGE'),
'SCHEMAS': ('CREATE', 'USAGE'), }
+VALID_IMPLICIT_ROLES = {'PUBLIC': 0,
+ 'CURRENT_USER': 95000,
+ 'SESSION_USER': 95000,
+ 'CURRENT_ROLE': 140000, }
executed_queries = []
@@ -447,19 +467,6 @@ class Error(Exception):
pass
-def role_exists(module, cursor, rolname):
- """Check user exists or not"""
- query = "SELECT 1 FROM pg_roles WHERE rolname = '%s'" % rolname
- try:
- cursor.execute(query)
- return cursor.rowcount > 0
-
- except Exception as e:
- module.fail_json(msg="Cannot execute SQL '%s': %s" % (query, to_native(e)))
-
- return False
-
-
# We don't have functools.partial in Python < 2.5
def partial(f, *args, **kwargs):
"""Partial function application"""
@@ -476,21 +483,30 @@ def partial(f, *args, **kwargs):
class Connection(object):
- """Wrapper around a psycopg2 connection with some convenience methods"""
+ """Wrapper around a psycopg connection with some convenience methods"""
def __init__(self, params, module):
self.database = params.database
self.module = module
+ # Ensure psycopg libraries are available before connecting to DB:
+ ensure_required_libs(module)
conn_params = get_conn_params(module, params.__dict__, warn_db_default=False)
- sslrootcert = params.ca_cert
- if psycopg2.__version__ < '2.4.3' and sslrootcert is not None:
- raise ValueError('psycopg2 must be at least 2.4.3 in order to user the ca_cert parameter')
+ self.connection, dummy = connect_to_db(module, conn_params, autocommit=False)
+ self.cursor = self.connection.cursor(**pg_cursor_args)
+ self.pg_version = get_server_version(self.connection)
+
+ # implicit roles in current pg version
+ self.pg_implicit_roles = tuple(
+ implicit_role for implicit_role, version_min in VALID_IMPLICIT_ROLES.items() if self.pg_version >= version_min
+ )
- self.connection = psycopg2.connect(**conn_params)
- self.cursor = self.connection.cursor()
- self.pg_version = self.connection.server_version
+ def execute(self, query, input_vars=None):
+ try:
+ self.cursor.execute(query, input_vars)
+ except Exception as e:
+ self.module.fail_json(msg="Cannot execute SQL '%s': %s" % (query, to_native(e)))
def commit(self):
self.connection.commit()
@@ -498,22 +514,32 @@ class Connection(object):
def rollback(self):
self.connection.rollback()
- @property
- def encoding(self):
- """Connection encoding in Python-compatible form"""
- return psycopg2.extensions.encodings[self.connection.encoding]
+ # Methods for implicit roles managements
+
+ def is_implicit_role(self, rolname):
+ return rolname.upper() in self.pg_implicit_roles
# Methods for querying database objects
+ def role_exists(self, rolname):
+ # check if rolname is a implicit role
+ if self.is_implicit_role(rolname):
+ return True
+
+ # check if rolname is present in pg_catalog.pg_roles
+ query = "SELECT 1 FROM pg_catalog.pg_roles WHERE rolname = %s"
+ self.execute(query, (rolname,))
+ return self.cursor.rowcount > 0
+
# PostgreSQL < 9.0 doesn't support "ALL TABLES IN SCHEMA schema"-like
# phrases in GRANT or REVOKE statements, therefore alternative methods are
# provided here.
def schema_exists(self, schema):
- query = """SELECT count(*)
+ query = """SELECT count(*) c
FROM pg_catalog.pg_namespace WHERE nspname = %s"""
- self.cursor.execute(query, (schema,))
- return self.cursor.fetchone()[0] > 0
+ self.execute(query, (schema,))
+ return self.cursor.fetchone()["c"] > 0
def get_all_tables_in_schema(self, schema):
if schema:
@@ -524,12 +550,12 @@ class Connection(object):
FROM pg_catalog.pg_class c
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE nspname = %s AND relkind in ('r', 'v', 'm', 'p')"""
- self.cursor.execute(query, (schema,))
+ self.execute(query, (schema,))
else:
query = ("SELECT relname FROM pg_catalog.pg_class "
"WHERE relkind in ('r', 'v', 'm', 'p')")
- self.cursor.execute(query)
- return [t[0] for t in self.cursor.fetchall()]
+ self.execute(query)
+ return [t["relname"] for t in self.cursor.fetchall()]
def get_all_sequences_in_schema(self, schema):
if schema:
@@ -539,17 +565,17 @@ class Connection(object):
FROM pg_catalog.pg_class c
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE nspname = %s AND relkind = 'S'"""
- self.cursor.execute(query, (schema,))
+ self.execute(query, (schema,))
else:
- self.cursor.execute("SELECT relname FROM pg_catalog.pg_class WHERE relkind = 'S'")
- return [t[0] for t in self.cursor.fetchall()]
+ self.execute("SELECT relname FROM pg_catalog.pg_class WHERE relkind = 'S'")
+ return [t["relname"] for t in self.cursor.fetchall()]
def get_all_functions_in_schema(self, schema):
if schema:
if not self.schema_exists(schema):
raise Error('Schema "%s" does not exist.' % schema)
- query = ("SELECT p.proname, oidvectortypes(p.proargtypes) "
+ query = ("SELECT p.proname, oidvectortypes(p.proargtypes) ptypes "
"FROM pg_catalog.pg_proc p "
"JOIN pg_namespace n ON n.oid = p.pronamespace "
"WHERE nspname = %s")
@@ -557,30 +583,30 @@ class Connection(object):
if self.pg_version >= 110000:
query += " and p.prokind = 'f'"
- self.cursor.execute(query, (schema,))
+ self.execute(query, (schema,))
else:
- self.cursor.execute("SELECT p.proname, oidvectortypes(p.proargtypes) FROM pg_catalog.pg_proc p")
- return ["%s(%s)" % (t[0], t[1]) for t in self.cursor.fetchall()]
+ self.execute("SELECT p.proname, oidvectortypes(p.proargtypes) ptypes FROM pg_catalog.pg_proc p")
+ return ["%s(%s)" % (t["proname"], t["ptypes"]) for t in self.cursor.fetchall()]
def get_all_procedures_in_schema(self, schema):
if self.pg_version < 110000:
- raise Error("PostgreSQL verion must be >= 11 for type=procedure. Exit")
+ raise Error("PostgreSQL version must be >= 11 for type=procedure. Exit")
if schema:
if not self.schema_exists(schema):
raise Error('Schema "%s" does not exist.' % schema)
- query = ("SELECT p.proname, oidvectortypes(p.proargtypes) "
+ query = ("SELECT p.proname, oidvectortypes(p.proargtypes) ptypes "
"FROM pg_catalog.pg_proc p "
"JOIN pg_namespace n ON n.oid = p.pronamespace "
"WHERE nspname = %s and p.prokind = 'p'")
- self.cursor.execute(query, (schema,))
+ self.execute(query, (schema,))
else:
- query = ("SELECT p.proname, oidvectortypes(p.proargtypes) "
+ query = ("SELECT p.proname, oidvectortypes(p.proargtypes) ptypes "
"FROM pg_catalog.pg_proc p WHERE p.prokind = 'p'")
- self.cursor.execute(query)
- return ["%s(%s)" % (t[0], t[1]) for t in self.cursor.fetchall()]
+ self.execute(query)
+ return ["%s(%s)" % (t["proname"], t["ptypes"]) for t in self.cursor.fetchall()]
# Methods for getting access control lists and group membership info
@@ -592,71 +618,71 @@ class Connection(object):
def get_table_acls(self, schema, tables):
if schema:
- query = """SELECT relacl
+ query = """SELECT relacl::text
FROM pg_catalog.pg_class c
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE nspname = %s AND relkind in ('r','p','v','m') AND relname = ANY (%s)
ORDER BY relname"""
- self.cursor.execute(query, (schema, tables))
+ self.execute(query, (schema, tables))
else:
- query = ("SELECT relacl FROM pg_catalog.pg_class "
+ query = ("SELECT relacl::text FROM pg_catalog.pg_class "
"WHERE relkind in ('r','p','v','m') AND relname = ANY (%s) "
"ORDER BY relname")
- self.cursor.execute(query)
- return [t[0] for t in self.cursor.fetchall()]
+ self.execute(query)
+ return [t["relacl"] for t in self.cursor.fetchall()]
def get_sequence_acls(self, schema, sequences):
if schema:
- query = """SELECT relacl
+ query = """SELECT relacl::text
FROM pg_catalog.pg_class c
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE nspname = %s AND relkind = 'S' AND relname = ANY (%s)
ORDER BY relname"""
- self.cursor.execute(query, (schema, sequences))
+ self.execute(query, (schema, sequences))
else:
- query = ("SELECT relacl FROM pg_catalog.pg_class "
+ query = ("SELECT relacl::text FROM pg_catalog.pg_class "
"WHERE relkind = 'S' AND relname = ANY (%s) ORDER BY relname")
- self.cursor.execute(query)
- return [t[0] for t in self.cursor.fetchall()]
+ self.execute(query)
+ return [t["relacl"] for t in self.cursor.fetchall()]
def get_function_acls(self, schema, function_signatures):
funcnames = [f.split('(', 1)[0] for f in function_signatures]
if schema:
- query = """SELECT proacl
+ query = """SELECT proacl::text
FROM pg_catalog.pg_proc p
JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace
WHERE nspname = %s AND proname = ANY (%s)
ORDER BY proname, proargtypes"""
- self.cursor.execute(query, (schema, funcnames))
+ self.execute(query, (schema, funcnames))
else:
- query = ("SELECT proacl FROM pg_catalog.pg_proc WHERE proname = ANY (%s) "
+ query = ("SELECT proacl::text FROM pg_catalog.pg_proc WHERE proname = ANY (%s) "
"ORDER BY proname, proargtypes")
- self.cursor.execute(query)
- return [t[0] for t in self.cursor.fetchall()]
+ self.execute(query)
+ return [t["proacl"] for t in self.cursor.fetchall()]
def get_schema_acls(self, schemas):
- query = """SELECT nspacl FROM pg_catalog.pg_namespace
+ query = """SELECT nspacl::text FROM pg_catalog.pg_namespace
WHERE nspname = ANY (%s) ORDER BY nspname"""
- self.cursor.execute(query, (schemas,))
- return [t[0] for t in self.cursor.fetchall()]
+ self.execute(query, (schemas,))
+ return [t["nspacl"] for t in self.cursor.fetchall()]
def get_language_acls(self, languages):
- query = """SELECT lanacl FROM pg_catalog.pg_language
+ query = """SELECT lanacl::text FROM pg_catalog.pg_language
WHERE lanname = ANY (%s) ORDER BY lanname"""
- self.cursor.execute(query, (languages,))
- return [t[0] for t in self.cursor.fetchall()]
+ self.execute(query, (languages,))
+ return [t["lanacl"] for t in self.cursor.fetchall()]
def get_tablespace_acls(self, tablespaces):
- query = """SELECT spcacl FROM pg_catalog.pg_tablespace
+ query = """SELECT spcacl::text FROM pg_catalog.pg_tablespace
WHERE spcname = ANY (%s) ORDER BY spcname"""
- self.cursor.execute(query, (tablespaces,))
- return [t[0] for t in self.cursor.fetchall()]
+ self.execute(query, (tablespaces,))
+ return [t["spcacl"] for t in self.cursor.fetchall()]
def get_database_acls(self, databases):
- query = """SELECT datacl FROM pg_catalog.pg_database
+ query = """SELECT datacl::text FROM pg_catalog.pg_database
WHERE datname = ANY (%s) ORDER BY datname"""
- self.cursor.execute(query, (databases,))
- return [t[0] for t in self.cursor.fetchall()]
+ self.execute(query, (databases,))
+ return [t["datacl"] for t in self.cursor.fetchall()]
def get_group_memberships(self, groups):
query = """SELECT roleid, grantor, member, admin_option
@@ -664,48 +690,56 @@ class Connection(object):
JOIN pg_catalog.pg_roles r ON r.oid = am.roleid
WHERE r.rolname = ANY(%s)
ORDER BY roleid, grantor, member"""
- self.cursor.execute(query, (groups,))
+ self.execute(query, (groups,))
return self.cursor.fetchall()
def get_default_privs(self, schema, *args):
if schema:
- query = """SELECT defaclacl
+ query = """SELECT defaclacl::text
FROM pg_default_acl a
JOIN pg_namespace b ON a.defaclnamespace=b.oid
WHERE b.nspname = %s;"""
- self.cursor.execute(query, (schema,))
+ self.execute(query, (schema,))
else:
- self.cursor.execute("SELECT defaclacl FROM pg_default_acl;")
- return [t[0] for t in self.cursor.fetchall()]
+ self.execute("SELECT defaclacl::text FROM pg_default_acl;")
+ return [t["defaclacl"] for t in self.cursor.fetchall()]
def get_foreign_data_wrapper_acls(self, fdws):
- query = """SELECT fdwacl FROM pg_catalog.pg_foreign_data_wrapper
+ query = """SELECT fdwacl::text FROM pg_catalog.pg_foreign_data_wrapper
WHERE fdwname = ANY (%s) ORDER BY fdwname"""
- self.cursor.execute(query, (fdws,))
- return [t[0] for t in self.cursor.fetchall()]
+ self.execute(query, (fdws,))
+ return [t["fdwacl"] for t in self.cursor.fetchall()]
def get_foreign_server_acls(self, fs):
- query = """SELECT srvacl FROM pg_catalog.pg_foreign_server
+ query = """SELECT srvacl::text FROM pg_catalog.pg_foreign_server
WHERE srvname = ANY (%s) ORDER BY srvname"""
- self.cursor.execute(query, (fs,))
- return [t[0] for t in self.cursor.fetchall()]
+ self.execute(query, (fs,))
+ return [t["srvacl"] for t in self.cursor.fetchall()]
def get_type_acls(self, schema, types):
if schema:
- query = """SELECT t.typacl FROM pg_catalog.pg_type t
+ query = """SELECT t.typacl::text FROM pg_catalog.pg_type t
JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
WHERE n.nspname = %s AND t.typname = ANY (%s) ORDER BY typname"""
- self.cursor.execute(query, (schema, types))
+ self.execute(query, (schema, types))
else:
- query = "SELECT typacl FROM pg_catalog.pg_type WHERE typname = ANY (%s) ORDER BY typname"
- self.cursor.execute(query)
- return [t[0] for t in self.cursor.fetchall()]
+ query = "SELECT typacl::text FROM pg_catalog.pg_type WHERE typname = ANY (%s) ORDER BY typname"
+ self.execute(query)
+ return [t["typacl"] for t in self.cursor.fetchall()]
+
+ def get_parameter_acls(self, parameters):
+ if self.pg_version < 150000:
+ raise Error("PostgreSQL version must be >= 15 for type=parameter. Exit")
+
+ query = """SELECT paracl::text FROM pg_catalog.pg_parameter_acl
+ WHERE parname = ANY (%s) ORDER BY parname"""
+ self.cursor.execute(query, (parameters,))
+ return [t["paracl"] for t in self.cursor.fetchall()]
# Manipulating privileges
- # WARNING: usage_on_types has been deprecated and will be removed in community.postgresql 3.0.0, please use an obj_type of 'type' instead.
def manipulate_privs(self, obj_type, privs, objs, orig_objs, roles, target_roles,
- state, grant_option, schema_qualifier=None, fail_on_role=True, usage_on_types=True):
+ state, grant_option, schema_qualifier=None, fail_on_role=True):
"""Manipulate database object privileges.
:param obj_type: Type of database object to grant/revoke
@@ -714,9 +748,8 @@ class Connection(object):
or None if type is "group".
:param objs: List of database objects to grant/revoke
privileges for.
- :param orig_objs: ALL_IN_SCHEMA or None
- :param roles: Either a list of role names or "PUBLIC"
- for the implicitly defined "PUBLIC" group
+ :param orig_objs: ALL_IN_SCHEMA or None.
+ :param roles: List of role names.
:param target_roles: List of role names to grant/revoke
default privileges as.
:param state: "present" to grant privileges, "absent" to revoke.
@@ -752,6 +785,8 @@ class Connection(object):
get_status = self.get_foreign_server_acls
elif obj_type == 'type':
get_status = partial(self.get_type_acls, schema_qualifier)
+ elif obj_type == 'parameter':
+ get_status = self.get_parameter_acls
else:
raise Error('Unsupported database object type "%s".' % obj_type)
@@ -787,33 +822,18 @@ class Connection(object):
obj_ids = [pg_quote_identifier(i, 'table') for i in obj_ids]
# Note: obj_type has been checked against a set of string literals
# and privs was escaped when it was parsed
- # Note: Underscores are replaced with spaces to support multi-word obj_type
+ # Note: Underscores are replaced with spaces to support multi-word privs and obj_type
if orig_objs is not None:
- set_what = '%s ON %s %s' % (','.join(privs), orig_objs, quoted_schema_qualifier)
+ set_what = '%s ON %s %s' % (','.join(privs).replace('_', ' '), orig_objs, quoted_schema_qualifier)
else:
- set_what = '%s ON %s %s' % (','.join(privs), obj_type.replace('_', ' '), ','.join(obj_ids))
+ set_what = '%s ON %s %s' % (','.join(privs).replace('_', ' '), obj_type.replace('_', ' '), ','.join(obj_ids))
# for_whom: SQL-fragment specifying for whom to set the above
- if roles == 'PUBLIC':
- for_whom = 'PUBLIC'
- else:
- for_whom = []
- for r in roles:
- if not role_exists(self.module, self.cursor, r):
- if fail_on_role:
- self.module.fail_json(msg="Role '%s' does not exist" % r.strip())
-
- else:
- self.module.warn("Role '%s' does not exist, pass it" % r.strip())
- else:
- for_whom.append('"%s"' % r)
-
- if not for_whom:
- return False
-
- for_whom = ','.join(for_whom)
+ if not roles:
+ return False
+ for_whom = ','.join(roles)
- # as_who:
+ # as_who: SQL-fragment specifying to who to set the above
as_who = None
if target_roles:
as_who = ','.join('"%s"' % r for r in target_roles)
@@ -828,13 +848,10 @@ class Connection(object):
.for_schema(quoted_schema_qualifier) \
.set_what(set_what) \
.for_objs(objs) \
- .usage_on_types(usage_on_types) \
.build()
executed_queries.append(query)
- self.cursor.execute(query)
- if roles == 'PUBLIC':
- return True
+ self.execute(query)
status_after = get_status(objs)
@@ -843,7 +860,8 @@ class Connection(object):
# to compare NoneType elements by sort method.
if e is None:
return ''
- return e
+ # With Psycopg 3 we get a list of dicts, it is easier to sort it as strings
+ return str(e)
status_before.sort(key=nonesorted)
status_after.sort(key=nonesorted)
@@ -860,7 +878,6 @@ class QueryBuilder(object):
self._state = state
self._schema = None
self._objs = None
- self._usage_on_types = None
self.query = []
def for_objs(self, objs):
@@ -879,10 +896,6 @@ class QueryBuilder(object):
self._for_whom = who
return self
- def usage_on_types(self, usage_on_types):
- self._usage_on_types = usage_on_types
- return self
-
def as_who(self, target_roles):
self._as_who = target_roles
return self
@@ -948,18 +961,6 @@ class QueryBuilder(object):
self._for_whom))
self.add_grant_option()
- if self._usage_on_types:
-
- if self._as_who:
- self.query.append(
- 'ALTER DEFAULT PRIVILEGES FOR ROLE {0}{1} GRANT USAGE ON TYPES TO {2}'.format(self._as_who,
- self._schema,
- self._for_whom))
- else:
- self.query.append(
- 'ALTER DEFAULT PRIVILEGES{0} GRANT USAGE ON TYPES TO {1}'.format(self._schema, self._for_whom))
- self.add_grant_option()
-
def build_present(self):
if self._obj_type == 'default_privs':
self.add_default_revoke()
@@ -1004,7 +1005,8 @@ def main():
'default_privs',
'foreign_data_wrapper',
'foreign_server',
- 'type', ]),
+ 'type',
+ 'parameter', ]),
objs=dict(required=False, aliases=['obj']),
schema=dict(required=False),
roles=dict(required=True, aliases=['role']),
@@ -1019,9 +1021,6 @@ def main():
removed_from_collection='community.postgreql'),
fail_on_role=dict(type='bool', default=True),
trust_input=dict(type='bool', default=True),
- usage_on_types=dict(type='bool', default=True,
- removed_in_version='3.0.0',
- removed_from_collection='community.postgresql'),
)
module = AnsibleModule(
@@ -1030,7 +1029,6 @@ def main():
)
fail_on_role = module.params['fail_on_role']
- usage_on_types = module.params['usage_on_types']
# Create type object as namespace for module params
p = type('Params', (), module.params)
@@ -1083,19 +1081,7 @@ def main():
check_input(module, p.roles, p.target_roles, p.session_role, p.schema)
# Connect to Database
- if not psycopg2:
- module.fail_json(msg=missing_required_lib('psycopg2'), exception=PSYCOPG2_IMP_ERR)
- try:
- conn = Connection(p, module)
- except psycopg2.Error as e:
- module.fail_json(msg='Could not connect to database: %s' % to_native(e), exception=traceback.format_exc())
- except TypeError as e:
- if 'sslrootcert' in e.args[0]:
- module.fail_json(msg='Postgresql server must be at least version 8.4 to support sslrootcert')
- module.fail_json(msg="unable to connect to database: %s" % to_native(e), exception=traceback.format_exc())
- except ValueError as e:
- # We raise this when the psycopg library is too old
- module.fail_json(msg=to_native(e))
+ conn = Connection(p, module)
if p.session_role:
try:
@@ -1156,17 +1142,25 @@ def main():
objs = [obj.replace(':', ',') for obj in objs]
# roles
- if p.roles.upper() == 'PUBLIC':
- roles = 'PUBLIC'
- else:
- roles = p.roles.split(',')
-
- if len(roles) == 1 and not role_exists(module, conn.cursor, roles[0]):
+ roles = []
+ roles_raw = p.roles.split(',')
+ for r in roles_raw:
+ if conn.role_exists(r):
+ if conn.is_implicit_role(r):
+ # Some implicit roles (as PUBLIC) works in uppercase without double quotes and in lowercase with double quotes.
+ # Other implicit roles (as SESSION_USER) works only in uppercase without double quotes.
+ # So the approach that works for all implicit roles is uppercase without double quotes.
+ roles.append('%s' % r.upper())
+ else:
+ roles.append('"%s"' % r.replace('"', '""'))
+ else:
if fail_on_role:
- module.fail_json(msg="Role '%s' does not exist" % roles[0].strip())
+ module.fail_json(msg="Role '%s' does not exist" % r)
else:
- module.warn("Role '%s' does not exist, nothing to do" % roles[0].strip())
- module.exit_json(changed=False, queries=executed_queries)
+ module.warn("Role '%s' does not exist, pass it" % r)
+ if not roles:
+ module.warn("No valid roles provided, nothing to do")
+ module.exit_json(changed=False, queries=executed_queries)
# check if target_roles is set with type: default_privs
if p.target_roles and not p.type == 'default_privs':
@@ -1190,14 +1184,13 @@ def main():
grant_option=p.grant_option,
schema_qualifier=p.schema,
fail_on_role=fail_on_role,
- usage_on_types=usage_on_types,
)
except Error as e:
conn.rollback()
module.fail_json(msg=to_native(e), exception=traceback.format_exc())
- except psycopg2.Error as e:
+ except PsycopgError as e:
conn.rollback()
module.fail_json(msg=to_native(e))
diff --git a/ansible_collections/community/postgresql/plugins/modules/postgresql_publication.py b/ansible_collections/community/postgresql/plugins/modules/postgresql_publication.py
index 5edfc2abb..0ab26e7a5 100644
--- a/ansible_collections/community/postgresql/plugins/modules/postgresql_publication.py
+++ b/ansible_collections/community/postgresql/plugins/modules/postgresql_publication.py
@@ -6,6 +6,7 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
@@ -74,6 +75,12 @@ options:
type: bool
default: true
version_added: '0.2.0'
+ comment:
+ description:
+ - Sets a comment on the publication.
+ - To reset the comment, pass an empty string.
+ type: str
+ version_added: '3.3.0'
notes:
- PostgreSQL version must be 10 or greater.
@@ -104,6 +111,7 @@ EXAMPLES = r'''
community.postgresql.postgresql_publication:
db: test
name: acme
+ comment: Made by Ansible
- name: Create publication "acme" publishing only prices and vehicles tables
community.postgresql.postgresql_publication:
@@ -142,12 +150,12 @@ RETURN = r'''
exists:
description:
- Flag indicates the publication exists or not at the end of runtime.
- returned: always
+ returned: success
type: bool
sample: true
queries:
description: List of executed queries.
- returned: always
+ returned: success
type: str
sample: [ 'DROP PUBLICATION "acme" CASCADE' ]
owner:
@@ -176,26 +184,22 @@ parameters:
'''
-try:
- from psycopg2.extras import DictCursor
-except ImportError:
- # psycopg2 is checked by connect_to_db()
- # from ansible.module_utils.postgres
- pass
-
from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.six import iteritems
from ansible_collections.community.postgresql.plugins.module_utils.database import (
check_input,
pg_quote_identifier,
)
from ansible_collections.community.postgresql.plugins.module_utils.postgres import (
connect_to_db,
- exec_sql,
ensure_required_libs,
+ exec_sql,
get_conn_params,
+ get_server_version,
+ pg_cursor_args,
postgres_common_argument_spec,
+ set_comment,
)
-from ansible.module_utils.six import iteritems
SUPPORTED_PG_VERSION = 10000
@@ -228,12 +232,12 @@ class PgPublication():
Args:
module (AnsibleModule): Object of AnsibleModule class.
- cursor (cursor): Cursor object of psycopg2 library to work with PostgreSQL.
+ cursor (cursor): Cursor object of psycopg library to work with PostgreSQL.
name (str): The name of the publication.
Attributes:
module (AnsibleModule): Object of AnsibleModule class.
- cursor (cursor): Cursor object of psycopg2 library to work with PostgreSQL.
+ cursor (cursor): Cursor object of psycopg library to work with PostgreSQL.
name (str): Name of the publication.
executed_queries (list): List of executed queries.
attrs (dict): Dict with publication attributes.
@@ -276,6 +280,7 @@ class PgPublication():
return False
self.attrs['owner'] = pub_info.get('pubowner')
+ self.attrs['comment'] = pub_info.get('comment') if pub_info.get('comment') is not None else ''
# Publication DML operations:
self.attrs['parameters']['publish'] = {}
@@ -288,10 +293,8 @@ class PgPublication():
# If alltables flag is False, get the list of targeted tables:
if not pub_info.get('puballtables'):
table_info = self.__get_tables_pub_info()
- # Join sublists [['schema', 'table'], ...] to ['schema.table', ...]
- # for better representation:
for i, schema_and_table in enumerate(table_info):
- table_info[i] = pg_quote_identifier('.'.join(schema_and_table), 'table')
+ table_info[i] = pg_quote_identifier(schema_and_table["schema_dot_table"], 'table')
self.attrs['tables'] = table_info
else:
@@ -300,13 +303,14 @@ class PgPublication():
# Publication exists:
return True
- def create(self, tables, params, owner, check_mode=True):
+ def create(self, tables, params, owner, comment, check_mode=True):
"""Create the publication.
Args:
tables (list): List with names of the tables that need to be added to the publication.
params (dict): Dict contains optional publication parameters and their values.
owner (str): Name of the publication owner.
+ comment (str): Comment on the publication.
Kwargs:
check_mode (bool): If True, don't actually change anything,
@@ -340,15 +344,20 @@ class PgPublication():
# executed_queries and return:
self.__pub_set_owner(owner, check_mode=check_mode)
+ if comment is not None:
+ set_comment(self.cursor, comment, 'publication',
+ self.name, check_mode, self.executed_queries)
+
return changed
- def update(self, tables, params, owner, check_mode=True):
+ def update(self, tables, params, owner, comment, check_mode=True):
"""Update the publication.
Args:
tables (list): List with names of the tables that need to be presented in the publication.
params (dict): Dict contains optional publication parameters and their values.
owner (str): Name of the publication owner.
+ comment (str): Comment on the publication.
Kwargs:
check_mode (bool): If True, don't actually change anything,
@@ -414,6 +423,10 @@ class PgPublication():
if owner != self.attrs['owner']:
changed = self.__pub_set_owner(owner, check_mode=check_mode)
+ if comment is not None and comment != self.attrs['comment']:
+ changed = set_comment(self.cursor, comment, 'publication',
+ self.name, check_mode, self.executed_queries)
+
return changed
def drop(self, cascade=False, check_mode=True):
@@ -448,13 +461,15 @@ class PgPublication():
"AND column_name = 'pubtruncate'"), add_to_executed=False)
if pgtrunc_sup:
- query = ("SELECT r.rolname AS pubowner, p.puballtables, p.pubinsert, "
+ query = ("SELECT obj_description(p.oid, 'pg_publication') AS comment, "
+ "r.rolname AS pubowner, p.puballtables, p.pubinsert, "
"p.pubupdate , p.pubdelete, p.pubtruncate FROM pg_publication AS p "
"JOIN pg_catalog.pg_roles AS r "
"ON p.pubowner = r.oid "
"WHERE p.pubname = %(pname)s")
else:
- query = ("SELECT r.rolname AS pubowner, p.puballtables, p.pubinsert, "
+ query = ("SELECT obj_description(p.oid, 'pg_publication') AS comment, "
+ "r.rolname AS pubowner, p.puballtables, p.pubinsert, "
"p.pubupdate , p.pubdelete FROM pg_publication AS p "
"JOIN pg_catalog.pg_roles AS r "
"ON p.pubowner = r.oid "
@@ -472,7 +487,7 @@ class PgPublication():
Returns:
List of dicts with published tables.
"""
- query = ("SELECT schemaname, tablename "
+ query = ("SELECT schemaname || '.' || tablename as schema_dot_table "
"FROM pg_publication_tables WHERE pubname = %(pname)s")
return exec_sql(self, query, query_params={'pname': self.name}, add_to_executed=False)
@@ -603,6 +618,7 @@ def main():
cascade=dict(type='bool', default=False),
session_role=dict(type='str'),
trust_input=dict(type='bool', default=True),
+ comment=dict(type='str', default=None),
)
module = AnsibleModule(
argument_spec=argument_spec,
@@ -618,6 +634,7 @@ def main():
cascade = module.params['cascade']
session_role = module.params['session_role']
trust_input = module.params['trust_input']
+ comment = module.params['comment']
if not trust_input:
# Check input for potentially dangerous elements:
@@ -626,7 +643,8 @@ def main():
else:
params_list = ['%s = %s' % (k, v) for k, v in iteritems(params)]
- check_input(module, name, tables, owner, session_role, params_list)
+ check_input(module, name, tables, owner,
+ session_role, params_list, comment)
if state == 'absent':
if tables:
@@ -639,16 +657,16 @@ def main():
if state == 'present' and cascade:
module.warn('parameter "cascade" is ignored when "state=present"')
- # Ensure psycopg2 libraries are available before connecting to DB:
+ # Ensure psycopg libraries are available before connecting to DB:
ensure_required_libs(module)
# Connect to DB and make cursor object:
conn_params = get_conn_params(module, module.params)
# We check publication state without DML queries execution, so set autocommit:
db_connection, dummy = connect_to_db(module, conn_params, autocommit=True)
- cursor = db_connection.cursor(cursor_factory=DictCursor)
+ cursor = db_connection.cursor(**pg_cursor_args)
# Check version:
- if cursor.connection.server_version < SUPPORTED_PG_VERSION:
+ if get_server_version(cursor.connection) < SUPPORTED_PG_VERSION:
module.fail_json(msg="PostgreSQL server version should be 10.0 or greater")
# Nothing was changed by default:
@@ -664,10 +682,12 @@ def main():
# If module.check_mode=True, nothing will be changed:
if state == 'present':
if not publication.exists:
- changed = publication.create(tables, params, owner, check_mode=module.check_mode)
+ changed = publication.create(tables, params, owner, comment,
+ check_mode=module.check_mode)
else:
- changed = publication.update(tables, params, owner, check_mode=module.check_mode)
+ changed = publication.update(tables, params, owner, comment,
+ check_mode=module.check_mode)
elif state == 'absent':
changed = publication.drop(cascade=cascade, check_mode=module.check_mode)
diff --git a/ansible_collections/community/postgresql/plugins/modules/postgresql_query.py b/ansible_collections/community/postgresql/plugins/modules/postgresql_query.py
index 83f1665ee..2c219f4fa 100644
--- a/ansible_collections/community/postgresql/plugins/modules/postgresql_query.py
+++ b/ansible_collections/community/postgresql/plugins/modules/postgresql_query.py
@@ -5,7 +5,8 @@
# Copyright: (c) 2019, Andrew Klychkov (@Andersson007) <aaklychkov@mail.ru>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
DOCUMENTATION = r'''
@@ -14,17 +15,11 @@ module: postgresql_query
short_description: Run PostgreSQL queries
description:
- Runs arbitrary PostgreSQL queries.
-- B(WARNING) The C(path_to_script) and C(as_single_query) options as well as
- the C(query_list) and C(query_all_results) return values have been B(deprecated) and
- will be removed in community.postgresql 3.0.0, please use the
- M(community.postgresql.postgresql_script) module to execute statements from scripts.
-- Does not run against backup files. Use M(community.postgresql.postgresql_db) with I(state=restore)
- to run queries on files made by pg_dump/pg_dumpall utilities.
options:
query:
description:
- - SQL query string or list of queries to run. Variables can be escaped with psycopg2 syntax
- U(http://initd.org/psycopg/docs/usage.html).
+ - SQL query string or list of queries to run. Variables can be escaped with psycopg syntax
+ U(https://www.psycopg.org/psycopg3/docs/basic/params.html).
type: raw
positional_args:
description:
@@ -39,19 +34,6 @@ options:
When the value is a list, it will be converted to PostgreSQL array.
- Mutually exclusive with I(positional_args).
type: dict
- path_to_script:
- description:
- - This option has been B(deprecated) and will be removed in community.postgresql 3.0.0,
- please use the M(community.postgresql.postgresql_script) module to execute
- statements from scripts.
- - Path to a SQL script on the target machine.
- - If the script contains several queries, they must be semicolon-separated.
- - To run scripts containing objects with semicolons
- (for example, function and procedure definitions), use I(as_single_query=true).
- - To upload dumps or to execute other complex scripts, the preferable way
- is to use the M(community.postgresql.postgresql_db) module with I(state=restore).
- - Mutually exclusive with I(query).
- type: path
session_role:
description:
- Switch to session_role after connecting. The specified session_role must
@@ -91,25 +73,6 @@ options:
type: list
elements: str
version_added: '1.0.0'
- as_single_query:
- description:
- - This option has been B(deprecated) and will be removed in community.postgresql 3.0.0,
- please use the M(community.postgresql.postgresql_script) module to execute
- statements from scripts.
- - If C(true), when reading from the I(path_to_script) file,
- executes its whole content in a single query (not splitting it up
- into separate queries by semicolons). It brings the following changes in
- the module's behavior.
- - When C(true), the C(query_all_results) return value
- contains only the result of the last statement.
- - Whether the state is reported as changed or not
- is determined by the last statement of the file.
- - Used only when I(path_to_script) is specified, otherwise ignored.
- - If set to C(false), the script can contain only semicolon-separated queries.
- (see the I(path_to_script) option documentation).
- type: bool
- default: true
- version_added: '1.1.0'
seealso:
- module: community.postgresql.postgresql_script
- module: community.postgresql.postgresql_db
@@ -178,20 +141,6 @@ EXAMPLES = r'''
db: 'test'
query: 'insert into test (test) values (now())'
-
-# WARNING: The path_to_script and as_single_query options have been deprecated
-# and will be removed in community.postgresql 3.0.0, please
-# use the community.postgresql.postgresql_script module instead.
-# If your script contains semicolons as parts of separate objects
-# like functions, procedures, and so on, use "as_single_query: true"
-- name: Run queries from SQL script using UTF-8 client encoding for session
- community.postgresql.postgresql_query:
- db: test_db
- path_to_script: /var/lib/pgsql/test.sql
- positional_args:
- - 1
- encoding: UTF-8
-
- name: Example of using autocommit parameter
community.postgresql.postgresql_query:
db: test_db
@@ -260,37 +209,35 @@ query:
description:
- Executed query.
- When reading several queries from a file, it contains only the last one.
- returned: always
+ returned: success
type: str
sample: 'SELECT * FROM bar'
statusmessage:
description:
- Attribute containing the message returned by the command.
- When reading several queries from a file, it contains a message of the last one.
- returned: always
+ returned: success
type: str
sample: 'INSERT 0 1'
query_result:
description:
- List of dictionaries in column:value form representing returned rows.
- When running queries from a file, returns result of the last query.
- returned: always
+ returned: success
type: list
elements: dict
sample: [{"Column": "Value1"},{"Column": "Value2"}]
query_list:
description:
- List of executed queries.
- Useful when reading several queries from a file.
- returned: always
+ returned: success
type: list
elements: str
sample: ['SELECT * FROM foo', 'SELECT * FROM bar']
query_all_results:
description:
- List containing results of all queries executed (one sublist for every query).
- Useful when running a list of queries.
- returned: always
+ returned: success
type: list
elements: list
sample: [[{"Column": "Value1"},{"Column": "Value2"}], [{"Column": "Value1"},{"Column": "Value2"}]]
@@ -304,33 +251,34 @@ rowcount:
sample: 5
'''
-try:
- from psycopg2 import ProgrammingError as Psycopg2ProgrammingError
- from psycopg2.extras import DictCursor
-except ImportError:
- # it is needed for checking 'no result to fetch' in main(),
- # psycopg2 availability will be checked by connect_to_db() into
- # ansible.module_utils.postgres
- pass
-
import re
+from ansible.module_utils._text import to_native
from ansible.module_utils.basic import AnsibleModule
-from ansible_collections.community.postgresql.plugins.module_utils.database import (
- check_input,
-)
+from ansible.module_utils.six import iteritems
+from ansible_collections.community.postgresql.plugins.module_utils.database import \
+ check_input
from ansible_collections.community.postgresql.plugins.module_utils.postgres import (
+ HAS_PSYCOPG,
+ PSYCOPG_VERSION,
+ TYPES_NEED_TO_CONVERT,
connect_to_db,
convert_elements_to_pg_arrays,
convert_to_supported,
ensure_required_libs,
get_conn_params,
+ pg_cursor_args,
postgres_common_argument_spec,
set_search_path,
- TYPES_NEED_TO_CONVERT,
)
-from ansible.module_utils._text import to_native
-from ansible.module_utils.six import iteritems
+from ansible_collections.community.postgresql.plugins.module_utils.version import \
+ LooseVersion
+
+if HAS_PSYCOPG and PSYCOPG_VERSION < LooseVersion("3.0"):
+ from psycopg2 import ProgrammingError as PsycopgProgrammingError
+elif HAS_PSYCOPG:
+ from psycopg import ProgrammingError as PsycopgProgrammingError
+
# ===========================================
# Module execution.
@@ -353,12 +301,10 @@ def main():
positional_args=dict(type='list', elements='raw'),
named_args=dict(type='dict'),
session_role=dict(type='str'),
- path_to_script=dict(type='path'),
autocommit=dict(type='bool', default=False),
encoding=dict(type='str'),
trust_input=dict(type='bool', default=True),
search_path=dict(type='list', elements='str'),
- as_single_query=dict(type='bool', default=True),
)
module = AnsibleModule(
@@ -370,13 +316,11 @@ def main():
query = module.params["query"]
positional_args = module.params["positional_args"]
named_args = module.params["named_args"]
- path_to_script = module.params["path_to_script"]
autocommit = module.params["autocommit"]
encoding = module.params["encoding"]
session_role = module.params["session_role"]
trust_input = module.params["trust_input"]
search_path = module.params["search_path"]
- as_single_query = module.params["as_single_query"]
if query and not isinstance(query, (str, list)):
module.fail_json(msg="query argument must be of type string or list")
@@ -388,52 +332,20 @@ def main():
if autocommit and module.check_mode:
module.fail_json(msg="Using autocommit is mutually exclusive with check_mode")
- if path_to_script and query:
- module.fail_json(msg="path_to_script is mutually exclusive with query")
-
query_list = []
- if path_to_script:
- depr_msg = ("The 'path_to_script' option is deprecated. Please use the "
- "'community.postgresql.postgresql_script' module to execute "
- "statements from scripts")
- module.deprecate(msg=depr_msg, version="3.0.0", collection_name="community.postgresql")
- try:
- with open(path_to_script, 'rb') as f:
- query = to_native(f.read())
-
- if not as_single_query:
- depr_msg = ("The 'as_single_query' option is deprecated. Please use the "
- "'community.postgresql.postgresql_script' module to execute "
- "statements from scripts")
- module.deprecate(msg=depr_msg, version="3.0.0", collection_name="community.postgresql")
-
- if ';' in query:
- for q in query.split(';'):
- if insane_query(q):
- continue
- else:
- query_list.append(q)
- else:
- query_list.append(query)
- else:
- query_list.append(query)
-
- except Exception as e:
- module.fail_json(msg="Cannot read file '%s' : %s" % (path_to_script, to_native(e)))
- else:
- if isinstance(query, str):
- query_list.append(query)
- else: # if it's a list
- query_list = query
+ if isinstance(query, str):
+ query_list.append(query)
+ else: # if it's a list
+ query_list = query
- # Ensure psycopg2 libraries are available before connecting to DB:
+ # Ensure psycopg libraries are available before connecting to DB:
ensure_required_libs(module)
conn_params = get_conn_params(module, module.params)
- db_connection, dummy = connect_to_db(module, conn_params, autocommit=autocommit)
if encoding is not None:
- db_connection.set_client_encoding(encoding)
- cursor = db_connection.cursor(cursor_factory=DictCursor)
+ conn_params["client_encoding"] = encoding
+ db_connection, dummy = connect_to_db(module, conn_params, autocommit=autocommit)
+ cursor = db_connection.cursor(**pg_cursor_args)
if search_path:
set_search_path(cursor, '%s' % ','.join([x.strip(' ') for x in search_path]))
@@ -461,6 +373,7 @@ def main():
# Execute query:
for query in query_list:
try:
+ current_query_txt = cursor.mogrify(query, args)
cursor.execute(query, args)
statusmessage = cursor.statusmessage
if cursor.rowcount > 0:
@@ -478,16 +391,21 @@ def main():
query_result.append(row)
- except Psycopg2ProgrammingError as e:
+ # Psycopg 3 doesn't fail with 'no results to fetch'
+ # This exception will be triggered only in Psycopg 2
+ except PsycopgProgrammingError as e:
if to_native(e) == 'no results to fetch':
query_result = {}
except Exception as e:
module.fail_json(msg="Cannot fetch rows from cursor: %s" % to_native(e))
+ if query_result == []:
+ query_result = {}
+
query_all_results.append(query_result)
- if 'SELECT' not in statusmessage:
+ if 'SELECT' not in statusmessage and 'SHOW' not in statusmessage:
if re.search(re.compile(r'(UPDATE|INSERT|DELETE)'), statusmessage):
s = statusmessage.split()
if len(s) == 3:
@@ -520,7 +438,7 @@ def main():
kw = dict(
changed=changed,
- query=cursor.query,
+ query=current_query_txt,
query_list=query_list,
statusmessage=statusmessage,
query_result=query_result,
diff --git a/ansible_collections/community/postgresql/plugins/modules/postgresql_schema.py b/ansible_collections/community/postgresql/plugins/modules/postgresql_schema.py
index f107e1aa0..bfacde6f8 100644
--- a/ansible_collections/community/postgresql/plugins/modules/postgresql_schema.py
+++ b/ansible_collections/community/postgresql/plugins/modules/postgresql_schema.py
@@ -5,6 +5,7 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
DOCUMENTATION = r'''
@@ -59,6 +60,12 @@ options:
type: bool
default: true
version_added: '0.2.0'
+ comment:
+ description:
+ - Sets a comment on the schema.
+ - To reset the comment, pass an empty string.
+ type: str
+ version_added: '3.3.0'
seealso:
- name: PostgreSQL schemas
description: General information about PostgreSQL schemas.
@@ -90,6 +97,7 @@ EXAMPLES = r'''
community.postgresql.postgresql_schema:
db: test
name: acme
+ comment: 'My test schema'
- name: Create a new schema acme with a user bob who will own it
community.postgresql.postgresql_schema:
@@ -106,38 +114,33 @@ EXAMPLES = r'''
RETURN = r'''
schema:
description: Name of the schema.
- returned: success, changed
+ returned: success
type: str
sample: "acme"
queries:
description: List of executed queries.
- returned: always
+ returned: success
type: list
sample: ["CREATE SCHEMA \"acme\""]
'''
import traceback
-try:
- from psycopg2.extras import DictCursor
-except ImportError:
- # psycopg2 is checked by connect_to_db()
- # from ansible.module_utils.postgres
- pass
-
+from ansible.module_utils._text import to_native
from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.community.postgresql.plugins.module_utils.database import (
+ SQLParseError,
+ check_input,
+ pg_quote_identifier,
+)
from ansible_collections.community.postgresql.plugins.module_utils.postgres import (
connect_to_db,
ensure_required_libs,
get_conn_params,
+ pg_cursor_args,
postgres_common_argument_spec,
+ set_comment,
)
-from ansible_collections.community.postgresql.plugins.module_utils.database import (
- check_input,
- pg_quote_identifier,
- SQLParseError,
-)
-from ansible.module_utils._text import to_native
executed_queries = []
@@ -159,7 +162,9 @@ def set_owner(cursor, schema, owner):
def get_schema_info(cursor, schema):
- query = ("SELECT schema_owner AS owner "
+ query = ("SELECT obj_description((SELECT oid "
+ "FROM pg_namespace WHERE nspname = %(schema)s), 'pg_namespace') "
+ "AS comment, schema_owner AS owner "
"FROM information_schema.schemata "
"WHERE schema_name = %(schema)s")
cursor.execute(query, {'schema': schema})
@@ -185,7 +190,7 @@ def schema_delete(cursor, schema, cascade):
return False
-def schema_create(cursor, schema, owner):
+def schema_create(cursor, schema, owner, comment):
if not schema_exists(cursor, schema):
query_fragments = ['CREATE SCHEMA %s' % pg_quote_identifier(schema, 'schema')]
if owner:
@@ -193,24 +198,37 @@ def schema_create(cursor, schema, owner):
query = ' '.join(query_fragments)
cursor.execute(query)
executed_queries.append(query)
+ if comment is not None:
+ set_comment(cursor, comment, 'schema', schema, False, executed_queries)
return True
else:
schema_info = get_schema_info(cursor, schema)
+ changed = False
if owner and owner != schema_info['owner']:
- return set_owner(cursor, schema, owner)
- else:
- return False
+ changed = set_owner(cursor, schema, owner)
+
+ if comment is not None:
+ current_comment = schema_info['comment'] if schema_info['comment'] is not None else ''
+ if comment != current_comment:
+ changed = set_comment(cursor, comment, 'schema', schema, False, executed_queries) or changed
+
+ return changed
-def schema_matches(cursor, schema, owner):
+def schema_matches(cursor, schema, owner, comment):
if not schema_exists(cursor, schema):
return False
else:
schema_info = get_schema_info(cursor, schema)
if owner and owner != schema_info['owner']:
return False
- else:
- return True
+ if comment is not None:
+ # For the resetting comment feature (comment: '') to work correctly
+ current_comment = schema_info['comment'] if schema_info['comment'] is not None else ''
+ if comment != current_comment:
+ return False
+
+ return True
# ===========================================
# Module execution.
@@ -227,6 +245,7 @@ def main():
state=dict(type="str", default="present", choices=["absent", "present"]),
session_role=dict(type="str"),
trust_input=dict(type="bool", default=True),
+ comment=dict(type="str", default=None),
)
module = AnsibleModule(
@@ -240,25 +259,26 @@ def main():
cascade_drop = module.params["cascade_drop"]
session_role = module.params["session_role"]
trust_input = module.params["trust_input"]
+ comment = module.params["comment"]
if not trust_input:
# Check input for potentially dangerous elements:
- check_input(module, schema, owner, session_role)
+ check_input(module, schema, owner, session_role, comment)
changed = False
- # Ensure psycopg2 libraries are available before connecting to DB:
+ # Ensure psycopg libraries are available before connecting to DB:
ensure_required_libs(module)
conn_params = get_conn_params(module, module.params)
db_connection, dummy = connect_to_db(module, conn_params, autocommit=True)
- cursor = db_connection.cursor(cursor_factory=DictCursor)
+ cursor = db_connection.cursor(**pg_cursor_args)
try:
if module.check_mode:
if state == "absent":
changed = not schema_exists(cursor, schema)
elif state == "present":
- changed = not schema_matches(cursor, schema, owner)
+ changed = not schema_matches(cursor, schema, owner, comment)
module.exit_json(changed=changed, schema=schema)
if state == "absent":
@@ -269,7 +289,7 @@ def main():
elif state == "present":
try:
- changed = schema_create(cursor, schema, owner)
+ changed = schema_create(cursor, schema, owner, comment)
except SQLParseError as e:
module.fail_json(msg=to_native(e), exception=traceback.format_exc())
except NotSupportedError as e:
diff --git a/ansible_collections/community/postgresql/plugins/modules/postgresql_script.py b/ansible_collections/community/postgresql/plugins/modules/postgresql_script.py
index acd97f4d2..02a32c2ac 100644
--- a/ansible_collections/community/postgresql/plugins/modules/postgresql_script.py
+++ b/ansible_collections/community/postgresql/plugins/modules/postgresql_script.py
@@ -4,7 +4,8 @@
# Copyright: (c) 2022, Andrew Klychkov (@Andersson007) <aaklychkov@mail.ru>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
DOCUMENTATION = r'''
@@ -180,7 +181,7 @@ query:
- When the C(positional_args) or C(named_args) options are used,
the query contains all variables that were substituted
inside the database connector.
- returned: always
+ returned: success
type: str
sample: 'SELECT * FROM bar'
statusmessage:
@@ -189,7 +190,7 @@ statusmessage:
after executing the script content.
- When there are several statements in the script, returns a message
related to the last statement.
- returned: always
+ returned: success
type: str
sample: 'INSERT 0 1'
query_result:
@@ -197,7 +198,7 @@ query_result:
- List of dictionaries in the column:value form representing returned rows.
- When there are several statements in the script,
returns result of the last statement.
- returned: always
+ returned: success
type: list
elements: dict
sample: [{"Column": "Value1"},{"Column": "Value2"}]
@@ -211,31 +212,31 @@ rowcount:
sample: 5
'''
-try:
- from psycopg2 import ProgrammingError as Psycopg2ProgrammingError
- from psycopg2.extras import DictCursor
-except ImportError:
- # it is needed for checking 'no result to fetch' in main(),
- # psycopg2 availability will be checked by connect_to_db() into
- # ansible.module_utils.postgres
- pass
-
+from ansible.module_utils._text import to_native
from ansible.module_utils.basic import AnsibleModule
-from ansible_collections.community.postgresql.plugins.module_utils.database import (
- check_input,
-)
+from ansible.module_utils.six import iteritems
+from ansible_collections.community.postgresql.plugins.module_utils.database import \
+ check_input
from ansible_collections.community.postgresql.plugins.module_utils.postgres import (
+ HAS_PSYCOPG,
+ PSYCOPG_VERSION,
+ TYPES_NEED_TO_CONVERT,
connect_to_db,
convert_elements_to_pg_arrays,
convert_to_supported,
ensure_required_libs,
get_conn_params,
+ pg_cursor_args,
postgres_common_argument_spec,
set_search_path,
- TYPES_NEED_TO_CONVERT,
)
-from ansible.module_utils._text import to_native
-from ansible.module_utils.six import iteritems
+from ansible_collections.community.postgresql.plugins.module_utils.version import \
+ LooseVersion
+
+if HAS_PSYCOPG and PSYCOPG_VERSION < LooseVersion("3.0"):
+ from psycopg2 import ProgrammingError as PsycopgProgrammingError
+elif HAS_PSYCOPG:
+ from psycopg import ProgrammingError as PsycopgProgrammingError
# ===========================================
# Module execution.
@@ -280,13 +281,13 @@ def main():
except Exception as e:
module.fail_json(msg="Cannot read file '%s' : %s" % (path, to_native(e)))
- # Ensure psycopg2 libraries are available before connecting to DB:
+ # Ensure psycopg libraries are available before connecting to DB:
ensure_required_libs(module)
conn_params = get_conn_params(module, module.params)
- db_connection, dummy = connect_to_db(module, conn_params, autocommit=True)
if encoding is not None:
- db_connection.set_client_encoding(encoding)
- cursor = db_connection.cursor(cursor_factory=DictCursor)
+ conn_params["client_encoding"] = encoding
+ db_connection, dummy = connect_to_db(module, conn_params, autocommit=True)
+ cursor = db_connection.cursor(**pg_cursor_args)
if search_path:
set_search_path(cursor, '%s' % ','.join([x.strip(' ') for x in search_path]))
@@ -306,6 +307,7 @@ def main():
# Execute script content:
try:
+ current_query_txt = cursor.mogrify(script_content, args)
cursor.execute(script_content, args)
except Exception as e:
cursor.close()
@@ -316,9 +318,16 @@ def main():
rowcount = cursor.rowcount
+ # In Psycopg 2, only the result of the last statement is returned.
+ # In Psycopg 3, all the results are available.
+ # https://www.psycopg.org/psycopg3/docs/basic/from_pg2.html#multiple-results-returned-from-multiple-statements
query_result = []
try:
- for row in cursor.fetchall():
+ result_set = cursor.fetchall()
+ if PSYCOPG_VERSION >= LooseVersion("3.0"):
+ while cursor.nextset() is not None:
+ result_set = cursor.fetchall()
+ for row in result_set:
# Ansible engine does not support decimals.
# An explicit conversion is required on the module's side
row = dict(row)
@@ -328,16 +337,21 @@ def main():
query_result.append(row)
- except Psycopg2ProgrammingError as e:
+ # Psycopg 3 doesn't fail with 'no results to fetch'
+ # This exception will be triggered only in Psycopg 2
+ except PsycopgProgrammingError as e:
if to_native(e) == "no results to fetch":
query_result = {}
except Exception as e:
module.fail_json(msg="Cannot fetch rows from cursor: %s" % to_native(e))
+ if query_result == []:
+ query_result = {}
+
kw = dict(
changed=True,
- query=cursor.query,
+ query=current_query_txt,
statusmessage=statusmessage,
query_result=query_result,
rowcount=rowcount,
diff --git a/ansible_collections/community/postgresql/plugins/modules/postgresql_sequence.py b/ansible_collections/community/postgresql/plugins/modules/postgresql_sequence.py
index c874cb970..25b17f26b 100644
--- a/ansible_collections/community/postgresql/plugins/modules/postgresql_sequence.py
+++ b/ansible_collections/community/postgresql/plugins/modules/postgresql_sequence.py
@@ -4,7 +4,8 @@
# Copyright: (c) 2019, Tobias Birkefeld (@tcraxs) <t@craxs.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
DOCUMENTATION = r'''
@@ -232,91 +233,84 @@ EXAMPLES = r'''
RETURN = r'''
state:
description: Sequence state at the end of execution.
- returned: always
+ returned: success
type: str
sample: 'present'
sequence:
description: Sequence name.
- returned: always
+ returned: success
type: str
sample: 'foobar'
queries:
description: List of queries that was tried to be executed.
- returned: always
+ returned: success
type: str
sample: [ "CREATE SEQUENCE \"foo\"" ]
schema:
description: Name of the schema of the sequence.
- returned: always
+ returned: success
type: str
sample: 'foo'
data_type:
description: Shows the current data type of the sequence.
- returned: always
+ returned: success
type: str
sample: 'bigint'
increment:
description: The value of increment of the sequence. A positive value will
make an ascending sequence, a negative one a descending
sequence.
- returned: always
+ returned: success
type: int
sample: -1
minvalue:
description: The value of minvalue of the sequence.
- returned: always
+ returned: success
type: int
sample: 1
maxvalue:
description: The value of maxvalue of the sequence.
- returned: always
+ returned: success
type: int
sample: 9223372036854775807
start:
description: The value of start of the sequence.
- returned: always
+ returned: success
type: int
sample: 12
cycle:
description: Shows if the sequence cycle or not.
- returned: always
+ returned: success
type: bool
sample: false
owner:
description: Shows the current owner of the sequence
after the successful run of the task.
- returned: always
+ returned: success
type: str
sample: 'postgres'
newname:
description: Shows the new sequence name after rename.
- returned: on success
+ returned: success
type: str
sample: 'barfoo'
newschema:
description: Shows the new schema of the sequence after schema change.
- returned: on success
+ returned: success
type: str
sample: 'foobar'
'''
-try:
- from psycopg2.extras import DictCursor
-except ImportError:
- # psycopg2 is checked by connect_to_db()
- # from ansible.module_utils.postgres
- pass
-
from ansible.module_utils.basic import AnsibleModule
-from ansible_collections.community.postgresql.plugins.module_utils.database import (
- check_input,
-)
+from ansible_collections.community.postgresql.plugins.module_utils.database import \
+ check_input
from ansible_collections.community.postgresql.plugins.module_utils.postgres import (
connect_to_db,
- exec_sql,
ensure_required_libs,
+ exec_sql,
get_conn_params,
+ pg_cursor_args,
postgres_common_argument_spec,
)
@@ -326,11 +320,11 @@ class Sequence(object):
Arguments:
module (AnsibleModule) -- object of AnsibleModule class
- cursor (cursor) -- cursor object of psycopg2 library
+ cursor (cursor) -- cursor object of psycopg library
Attributes:
module (AnsibleModule) -- object of AnsibleModule class
- cursor (cursor) -- cursor object of psycopg2 library
+ cursor (cursor) -- cursor object of psycopg library
changed (bool) -- something was changed after execution or not
executed_queries (list) -- executed queries
name (str) -- name of the sequence
@@ -539,12 +533,12 @@ def main():
# Change autocommit to False if check_mode:
autocommit = not module.check_mode
- # Ensure psycopg2 libraries are available before connecting to DB:
+ # Ensure psycopg libraries are available before connecting to DB:
ensure_required_libs(module)
# Connect to DB and make cursor object:
conn_params = get_conn_params(module, module.params)
db_connection, dummy = connect_to_db(module, conn_params, autocommit=autocommit)
- cursor = db_connection.cursor(cursor_factory=DictCursor)
+ cursor = db_connection.cursor(**pg_cursor_args)
##############
# Create the object and do main job:
diff --git a/ansible_collections/community/postgresql/plugins/modules/postgresql_set.py b/ansible_collections/community/postgresql/plugins/modules/postgresql_set.py
index 966aeb004..d8d196acf 100644
--- a/ansible_collections/community/postgresql/plugins/modules/postgresql_set.py
+++ b/ansible_collections/community/postgresql/plugins/modules/postgresql_set.py
@@ -5,6 +5,7 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
DOCUMENTATION = r'''
@@ -60,6 +61,7 @@ options:
type: bool
default: true
version_added: '0.2.0'
+
notes:
- Supported version of PostgreSQL is 9.4 and later.
- Pay attention, change setting with 'postmaster' context can return changed is true
@@ -86,8 +88,11 @@ seealso:
- name: PostgreSQL ALTER SYSTEM command reference
description: Complete reference of the ALTER SYSTEM command documentation.
link: https://www.postgresql.org/docs/current/sql-altersystem.html
+
author:
- Andrew Klychkov (@Andersson007)
+- Daniele Giudice (@RealGreenDragon)
+
extends_documentation_fragment:
- community.postgresql.postgres
'''
@@ -134,22 +139,22 @@ EXAMPLES = r'''
RETURN = r'''
name:
description: Name of PostgreSQL server parameter.
- returned: always
+ returned: success
type: str
sample: 'shared_buffers'
restart_required:
description: Information about parameter current state.
- returned: always
+ returned: success
type: bool
sample: true
prev_val_pretty:
description: Information about previous state of the parameter.
- returned: always
+ returned: success
type: str
sample: '4MB'
value_pretty:
description: Information about current state of the parameter.
- returned: always
+ returned: success
type: str
sample: '64MB'
value:
@@ -157,49 +162,77 @@ value:
- Dictionary that contains the current parameter value (at the time of playbook finish).
- Pay attention that for real change some parameters restart of PostgreSQL server is required.
- Returns the current value in the check mode.
- returned: always
+ returned: success
type: dict
sample: { "value": 67108864, "unit": "b" }
context:
description:
- PostgreSQL setting context.
- returned: always
+ returned: success
type: str
sample: user
'''
-try:
- from psycopg2.extras import DictCursor
-except Exception:
- # psycopg2 is checked by connect_to_db()
- # from ansible.module_utils.postgres
- pass
-
from copy import deepcopy
+from ansible.module_utils._text import to_native
from ansible.module_utils.basic import AnsibleModule
-from ansible_collections.community.postgresql.plugins.module_utils.database import (
- check_input,
-)
+from ansible_collections.community.postgresql.plugins.module_utils.database import \
+ check_input
from ansible_collections.community.postgresql.plugins.module_utils.postgres import (
connect_to_db,
ensure_required_libs,
get_conn_params,
+ get_server_version,
+ pg_cursor_args,
postgres_common_argument_spec,
)
-from ansible.module_utils._text import to_native
PG_REQ_VER = 90400
# To allow to set value like 1mb instead of 1MB, etc:
LOWERCASE_SIZE_UNITS = ("mb", "gb", "tb")
+# GUC_LIST_QUOTE parameters list for each version where they changed (from PG_REQ_VER).
+# It is a tuple of tuples as we need to iterate it in order.
+PARAMETERS_GUC_LIST_QUOTE = (
+ (140000, (
+ 'local_preload_libraries',
+ 'search_path',
+ 'session_preload_libraries',
+ 'shared_preload_libraries',
+ 'temp_tablespaces',
+ 'unix_socket_directories'
+ )),
+ (90400, (
+ 'local_preload_libraries',
+ 'search_path',
+ 'session_preload_libraries',
+ 'shared_preload_libraries',
+ 'temp_tablespaces'
+ )),
+)
+
+
# ===========================================
# PostgreSQL module specific support methods.
#
-def param_get(cursor, module, name):
+def param_is_guc_list_quote(server_version, name):
+ for guc_list_quote_ver, guc_list_quote_params in PARAMETERS_GUC_LIST_QUOTE:
+ if server_version >= guc_list_quote_ver:
+ return name in guc_list_quote_params
+ return False
+
+
+def param_guc_list_unquote(value):
+ # Unquote GUC_LIST_QUOTE parameter (each element can be quoted or not)
+ # Assume the parameter is GUC_LIST_QUOTE (check in param_is_guc_list_quote function)
+ return ', '.join([v.strip('" ') for v in value.split(',')])
+
+
+def param_get(cursor, module, name, is_guc_list_quote):
query = ("SELECT name, setting, unit, context, boot_val "
"FROM pg_settings WHERE name = %(name)s")
try:
@@ -216,15 +249,16 @@ def param_get(cursor, module, name):
"Please check its spelling or presence in your PostgreSQL version "
"(https://www.postgresql.org/docs/current/runtime-config.html)" % name)
+ current_val = val[name]
raw_val = info['setting']
unit = info['unit']
context = info['context']
boot_val = info['boot_val']
- if val[name] == 'True':
- val[name] = 'on'
- elif val[name] == 'False':
- val[name] = 'off'
+ if current_val == 'True':
+ current_val = 'on'
+ elif current_val == 'False':
+ current_val = 'off'
if unit == 'kB':
if int(raw_val) > 0:
@@ -242,8 +276,12 @@ def param_get(cursor, module, name):
unit = 'b'
+ if is_guc_list_quote:
+ current_val = param_guc_list_unquote(current_val)
+ raw_val = param_guc_list_unquote(raw_val)
+
return {
- 'current_val': val[name],
+ 'current_val': current_val,
'raw_val': raw_val,
'unit': unit,
'boot_val': boot_val,
@@ -317,14 +355,22 @@ def pretty_to_bytes(pretty_val):
return pretty_val
-def param_set(cursor, module, name, value, context):
+def param_set(cursor, module, name, value, context, server_version):
try:
if str(value).lower() == 'default':
query = "ALTER SYSTEM SET %s = DEFAULT" % name
else:
- if isinstance(value, str) and ',' in value and not name.endswith(('_command', '_prefix')):
+ if isinstance(value, str) and \
+ ',' in value and \
+ not name.endswith(('_command', '_prefix')) and \
+ not (server_version < 140000 and name == 'unix_socket_directories'):
# Issue https://github.com/ansible-collections/community.postgresql/issues/78
# Change value from 'one, two, three' -> "'one','two','three'"
+ # PR https://github.com/ansible-collections/community.postgresql/pull/400
+ # Parameter names ends with '_command' or '_prefix' can contains commas but are not lists
+ # PR https://github.com/ansible-collections/community.postgresql/pull/521
+ # unix_socket_directories up to PostgreSQL 13 lacks GUC_LIST_INPUT and
+ # GUC_LIST_QUOTE options so it is a single value parameter
value = ','.join(["'" + elem.strip() + "'" for elem in value.split(',')])
query = "ALTER SYSTEM SET %s = %s" % (name, value)
else:
@@ -335,7 +381,7 @@ def param_set(cursor, module, name, value, context):
cursor.execute("SELECT pg_reload_conf()")
except Exception as e:
- module.fail_json(msg="Unable to get %s value due to : %s" % (name, to_native(e)))
+ module.fail_json(msg="Unable to set %s value due to : %s" % (name, to_native(e)))
return True
@@ -385,15 +431,15 @@ def main():
if value is None and not reset:
module.fail_json(msg="%s: at least one of value or reset param must be specified" % name)
- # Ensure psycopg2 libraries are available before connecting to DB:
+ # Ensure psycopg libraries are available before connecting to DB:
ensure_required_libs(module)
conn_params = get_conn_params(module, module.params, warn_db_default=False)
db_connection, dummy = connect_to_db(module, conn_params, autocommit=True)
- cursor = db_connection.cursor(cursor_factory=DictCursor)
+ cursor = db_connection.cursor(**pg_cursor_args)
kw = {}
# Check server version (needs 9.4 or later):
- ver = db_connection.server_version
+ ver = get_server_version(db_connection)
if ver < PG_REQ_VER:
module.warn("PostgreSQL is %s version but %s or later is required" % (ver, PG_REQ_VER))
kw = dict(
@@ -407,6 +453,9 @@ def main():
db_connection.close()
module.exit_json(**kw)
+ # Check parameter is GUC_LIST_QUOTE (done once as depend only on server version)
+ is_guc_list_quote = param_is_guc_list_quote(ver, name)
+
# Set default returned values:
restart_required = False
changed = False
@@ -414,7 +463,7 @@ def main():
kw['restart_required'] = False
# Get info about param state:
- res = param_get(cursor, module, name)
+ res = param_get(cursor, module, name, is_guc_list_quote)
current_val = res['current_val']
raw_val = res['raw_val']
unit = res['unit']
@@ -457,7 +506,7 @@ def main():
# Set param (value can be an empty string):
if value is not None and value != current_val:
- changed = param_set(cursor, module, name, value, context)
+ changed = param_set(cursor, module, name, value, context, ver)
kw['value_pretty'] = value
@@ -471,7 +520,7 @@ def main():
)
module.exit_json(**kw)
- changed = param_set(cursor, module, name, boot_val, context)
+ changed = param_set(cursor, module, name, boot_val, context, ver)
cursor.close()
db_connection.close()
@@ -479,9 +528,9 @@ def main():
# Reconnect and recheck current value:
if context in ('sighup', 'superuser-backend', 'backend', 'superuser', 'user'):
db_connection, dummy = connect_to_db(module, conn_params, autocommit=True)
- cursor = db_connection.cursor(cursor_factory=DictCursor)
+ cursor = db_connection.cursor(**pg_cursor_args)
- res = param_get(cursor, module, name)
+ res = param_get(cursor, module, name, is_guc_list_quote)
# f_ means 'final'
f_value = res['current_val']
f_raw_val = res['raw_val']
diff --git a/ansible_collections/community/postgresql/plugins/modules/postgresql_slot.py b/ansible_collections/community/postgresql/plugins/modules/postgresql_slot.py
index b863784af..9c6a5d04d 100644
--- a/ansible_collections/community/postgresql/plugins/modules/postgresql_slot.py
+++ b/ansible_collections/community/postgresql/plugins/modules/postgresql_slot.py
@@ -5,6 +5,7 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
DOCUMENTATION = r'''
@@ -136,40 +137,34 @@ EXAMPLES = r'''
RETURN = r'''
name:
description: Name of the slot.
- returned: always
+ returned: success
type: str
sample: "physical_one"
queries:
description: List of executed queries.
- returned: always
+ returned: success
type: str
sample: [ "SELECT pg_create_physical_replication_slot('physical_one', False, False)" ]
'''
-try:
- from psycopg2.extras import DictCursor
-except ImportError:
- # psycopg2 is checked by connect_to_db()
- # from ansible.module_utils.postgres
- pass
-
from ansible.module_utils.basic import AnsibleModule
-from ansible_collections.community.postgresql.plugins.module_utils.database import (
- check_input,
-)
+from ansible_collections.community.postgresql.plugins.module_utils.database import \
+ check_input
from ansible_collections.community.postgresql.plugins.module_utils.postgres import (
connect_to_db,
- exec_sql,
ensure_required_libs,
+ exec_sql,
get_conn_params,
+ get_server_version,
+ pg_cursor_args,
postgres_common_argument_spec,
)
-
# ===========================================
# PostgreSQL module specific support methods.
#
+
class PgSlot(object):
def __init__(self, module, cursor, name):
self.module = module
@@ -195,7 +190,7 @@ class PgSlot(object):
if kind == 'physical':
# Check server version (immediately_reserved needs 9.6+):
- if self.cursor.connection.server_version < 90600:
+ if get_server_version(self.cursor.connection) < 90600:
query = "SELECT pg_create_physical_replication_slot(%(name)s)"
else:
@@ -222,7 +217,7 @@ class PgSlot(object):
res = exec_sql(self, query, query_params={'name': self.name}, add_to_executed=False)
if res:
self.exists = True
- self.kind = res[0][0]
+ self.kind = res[0]["slot_type"]
# ===========================================
@@ -271,11 +266,11 @@ def main():
else:
warn_db_default = False
- # Ensure psycopg2 libraries are available before connecting to DB:
+ # Ensure psycopg libraries are available before connecting to DB:
ensure_required_libs(module)
conn_params = get_conn_params(module, module.params, warn_db_default=warn_db_default)
db_connection, dummy = connect_to_db(module, conn_params, autocommit=True)
- cursor = db_connection.cursor(cursor_factory=DictCursor)
+ cursor = db_connection.cursor(**pg_cursor_args)
##################################
# Create an object and do main job
diff --git a/ansible_collections/community/postgresql/plugins/modules/postgresql_subscription.py b/ansible_collections/community/postgresql/plugins/modules/postgresql_subscription.py
index ae46a0dea..a7d30631b 100644
--- a/ansible_collections/community/postgresql/plugins/modules/postgresql_subscription.py
+++ b/ansible_collections/community/postgresql/plugins/modules/postgresql_subscription.py
@@ -5,6 +5,7 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
@@ -92,6 +93,12 @@ options:
type: bool
default: true
version_added: '0.2.0'
+ comment:
+ description:
+ - Sets a comment on the subscription.
+ - To reset the comment, pass an empty string.
+ type: str
+ version_added: '3.3.0'
notes:
- PostgreSQL version must be 10 or greater.
@@ -137,6 +144,7 @@ EXAMPLES = r'''
user: repl
password: replpass
dbname: mydb
+ comment: Made by Ansible
- name: Assuming that acme subscription exists, try to change conn parameters
community.postgresql.postgresql_subscription:
@@ -175,51 +183,48 @@ RETURN = r'''
name:
description:
- Name of the subscription.
- returned: always
+ returned: success
type: str
sample: acme
exists:
description:
- Flag indicates the subscription exists or not at the end of runtime.
- returned: always
+ returned: success
type: bool
sample: true
queries:
description: List of executed queries.
- returned: always
+ returned: success
type: str
sample: [ 'DROP SUBSCRIPTION "mysubscription"' ]
initial_state:
description: Subscription configuration at the beginning of runtime.
- returned: always
+ returned: success
type: dict
sample: {"conninfo": {}, "enabled": true, "owner": "postgres", "slotname": "test", "synccommit": true}
final_state:
description: Subscription configuration at the end of runtime.
- returned: always
+ returned: success
type: dict
sample: {"conninfo": {}, "enabled": true, "owner": "postgres", "slotname": "test", "synccommit": true}
'''
from copy import deepcopy
-try:
- from psycopg2.extras import DictCursor
-except ImportError:
- # psycopg2 is checked by connect_to_db()
- # from ansible.module_utils.postgres
- pass
-
from ansible.module_utils.basic import AnsibleModule
-from ansible_collections.community.postgresql.plugins.module_utils.database import check_input
+from ansible.module_utils.six import iteritems
+from ansible_collections.community.postgresql.plugins.module_utils.database import \
+ check_input
from ansible_collections.community.postgresql.plugins.module_utils.postgres import (
connect_to_db,
- exec_sql,
ensure_required_libs,
+ exec_sql,
get_conn_params,
+ get_server_version,
+ pg_cursor_args,
postgres_common_argument_spec,
+ set_comment,
)
-from ansible.module_utils.six import iteritems
SUPPORTED_PG_VERSION = 10000
@@ -287,13 +292,13 @@ class PgSubscription():
Args:
module (AnsibleModule): Object of AnsibleModule class.
- cursor (cursor): Cursor object of psycopg2 library to work with PostgreSQL.
+ cursor (cursor): Cursor object of psycopg library to work with PostgreSQL.
name (str): The name of the subscription.
db (str): The database name the subscription will be associated with.
Attributes:
module (AnsibleModule): Object of AnsibleModule class.
- cursor (cursor): Cursor object of psycopg2 library to work with PostgreSQL.
+ cursor (cursor): Cursor object of psycopg library to work with PostgreSQL.
name (str): Name of subscription.
executed_queries (list): List of executed queries.
attrs (dict): Dict with subscription attributes.
@@ -313,6 +318,7 @@ class PgSubscription():
'conninfo': {},
'slotname': None,
'publications': [],
+ 'comment': None,
}
self.empty_attrs = deepcopy(self.attrs)
self.exists = self.check_subscr()
@@ -345,6 +351,11 @@ class PgSubscription():
self.attrs['synccommit'] = subscr_info.get('subenabled')
self.attrs['slotname'] = subscr_info.get('subslotname')
self.attrs['publications'] = subscr_info.get('subpublications')
+ if subscr_info.get('comment') is not None:
+ self.attrs['comment'] = subscr_info.get('comment')
+ else:
+ # To support the comment resetting functionality
+ self.attrs['comment'] = ''
if subscr_info.get('subconninfo'):
for param in subscr_info['subconninfo'].split(' '):
tmp = param.split('=')
@@ -471,6 +482,22 @@ class PgSubscription():
query = 'ALTER SUBSCRIPTION %s OWNER TO "%s"' % (self.name, role)
return self.__exec_sql(query, check_mode=check_mode)
+ def set_comment(self, comment, check_mode=True):
+ """Set a subscription comment.
+
+ Args:
+ comment (str): Comment to set on the subscription.
+
+ Kwargs:
+ check_mode (bool): If True, don not change anything.
+
+ Returns:
+ True if success, False otherwise.
+ """
+ set_comment(self.cursor, comment, 'subscription', self.name, check_mode, self.executed_queries)
+
+ return True
+
def refresh(self, check_mode=True):
"""Refresh publication.
@@ -559,7 +586,8 @@ class PgSubscription():
Returns:
Dict with subscription information if successful, False otherwise.
"""
- query = ("SELECT d.datname, r.rolname, s.subenabled, "
+ query = ("SELECT obj_description(s.oid, 'pg_subscription') AS comment, "
+ "d.datname, r.rolname, s.subenabled, "
"s.subconninfo, s.subslotname, s.subsynccommit, "
"s.subpublications FROM pg_catalog.pg_subscription s "
"JOIN pg_catalog.pg_database d "
@@ -615,6 +643,7 @@ def main():
subsparams=dict(type='dict'),
session_role=dict(type='str'),
trust_input=dict(type='bool', default=True),
+ comment=dict(type='str', default=None),
)
module = AnsibleModule(
argument_spec=argument_spec,
@@ -632,6 +661,7 @@ def main():
connparams = module.params['connparams']
session_role = module.params['session_role']
trust_input = module.params['trust_input']
+ comment = module.params['comment']
if not trust_input:
# Check input for potentially dangerous elements:
@@ -646,7 +676,7 @@ def main():
connparams_str = convert_conn_params(connparams)
check_input(module, name, publications, owner, session_role,
- connparams_str, subsparams_str)
+ connparams_str, subsparams_str, comment)
if state == 'present' and cascade:
module.warn('parameter "cascade" is ignored when state is not absent')
@@ -660,17 +690,19 @@ def main():
module.warn("parameter 'connparams' is ignored when state is not 'present'")
if subsparams:
module.warn("parameter 'subsparams' is ignored when state is not 'present'")
+ if comment is not None:
+ module.warn("parameter 'comment' is ignored when state is not 'present'")
- # Ensure psycopg2 libraries are available before connecting to DB:
+ # Ensure psycopg libraries are available before connecting to DB:
ensure_required_libs(module)
# Connect to DB and make cursor object:
pg_conn_params = get_conn_params(module, module.params)
# We check subscription state without DML queries execution, so set autocommit:
db_connection, dummy = connect_to_db(module, pg_conn_params, autocommit=True)
- cursor = db_connection.cursor(cursor_factory=DictCursor)
+ cursor = db_connection.cursor(**pg_cursor_args)
# Check version:
- if cursor.connection.server_version < SUPPORTED_PG_VERSION:
+ if get_server_version(cursor.connection) < SUPPORTED_PG_VERSION:
module.fail_json(msg="PostgreSQL server version should be 10.0 or greater")
# Set defaults:
@@ -711,6 +743,9 @@ def main():
if owner and subscription.attrs['owner'] != owner:
changed = subscription.set_owner(owner, check_mode=module.check_mode) or changed
+ if comment is not None and comment != subscription.attrs['comment']:
+ changed = subscription.set_comment(comment, check_mode=module.check_mode) or changed
+
elif state == 'absent':
changed = subscription.drop(cascade, check_mode=module.check_mode)
diff --git a/ansible_collections/community/postgresql/plugins/modules/postgresql_table.py b/ansible_collections/community/postgresql/plugins/modules/postgresql_table.py
index 33f1c752f..1e25c8f23 100644
--- a/ansible_collections/community/postgresql/plugins/modules/postgresql_table.py
+++ b/ansible_collections/community/postgresql/plugins/modules/postgresql_table.py
@@ -5,6 +5,7 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
DOCUMENTATION = r'''
@@ -212,43 +213,36 @@ EXAMPLES = r'''
RETURN = r'''
table:
description: Name of a table.
- returned: always
+ returned: success
type: str
sample: 'foo'
state:
description: Table state.
- returned: always
+ returned: success
type: str
sample: 'present'
owner:
description: Table owner.
- returned: always
+ returned: success
type: str
sample: 'postgres'
tablespace:
description: Tablespace.
- returned: always
+ returned: success
type: str
sample: 'ssd_tablespace'
queries:
description: List of executed queries.
- returned: always
+ returned: success
type: str
sample: [ 'CREATE TABLE "test_table" (id bigint)' ]
storage_params:
description: Storage parameters.
- returned: always
+ returned: success
type: list
sample: [ "fillfactor=100", "autovacuum_analyze_threshold=1" ]
'''
-try:
- from psycopg2.extras import DictCursor
-except ImportError:
- # psycopg2 is checked by connect_to_db()
- # from ansible.module_utils.postgres
- pass
-
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.postgresql.plugins.module_utils.database import (
check_input,
@@ -256,17 +250,18 @@ from ansible_collections.community.postgresql.plugins.module_utils.database impo
)
from ansible_collections.community.postgresql.plugins.module_utils.postgres import (
connect_to_db,
- exec_sql,
ensure_required_libs,
+ exec_sql,
get_conn_params,
+ pg_cursor_args,
postgres_common_argument_spec,
)
-
# ===========================================
# PostgreSQL module specific support methods.
#
+
class Table(object):
def __init__(self, name, module, cursor):
self.name = name
@@ -305,9 +300,9 @@ class Table(object):
if res:
self.exists = True
self.info = dict(
- owner=res[0][0],
- tblspace=res[0][1] if res[0][1] else '',
- storage_params=res[0][2] if res[0][2] else [],
+ owner=res[0]["tableowner"],
+ tblspace=res[0]["tablespace"] if res[0]["tablespace"] else '',
+ storage_params=res[0]["reloptions"] if res[0]["reloptions"] else [],
)
return True
@@ -536,11 +531,11 @@ def main():
if including and not like:
module.fail_json(msg="%s: including param needs like param specified" % table)
- # Ensure psycopg2 libraries are available before connecting to DB:
+ # Ensure psycopg libraries are available before connecting to DB:
ensure_required_libs(module)
conn_params = get_conn_params(module, module.params)
db_connection, dummy = connect_to_db(module, conn_params, autocommit=False)
- cursor = db_connection.cursor(cursor_factory=DictCursor)
+ cursor = db_connection.cursor(**pg_cursor_args)
if storage_params:
storage_params = ','.join(storage_params)
diff --git a/ansible_collections/community/postgresql/plugins/modules/postgresql_tablespace.py b/ansible_collections/community/postgresql/plugins/modules/postgresql_tablespace.py
index 243005733..7556370aa 100644
--- a/ansible_collections/community/postgresql/plugins/modules/postgresql_tablespace.py
+++ b/ansible_collections/community/postgresql/plugins/modules/postgresql_tablespace.py
@@ -6,7 +6,8 @@
# Copyright: (c) 2019, Andrew Klychkov (@Andersson007) <aaklychkov@mail.ru>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
DOCUMENTATION = r'''
@@ -77,6 +78,12 @@ options:
type: bool
default: true
version_added: '0.2.0'
+ comment:
+ description:
+ - Sets a comment on the tablespace.
+ - To reset the comment, pass an empty string.
+ type: str
+ version_added: '3.3.0'
attributes:
check_mode:
@@ -104,6 +111,7 @@ author:
- Flavien Chantelot (@Dorn-)
- Antoine Levy-Lambert (@antoinell)
- Andrew Klychkov (@Andersson007)
+- Daniele Giudice (@RealGreenDragon)
extends_documentation_fragment:
- community.postgresql.postgres
@@ -115,6 +123,7 @@ EXAMPLES = r'''
name: acme
owner: bob
location: /data/foo
+ comment: "Bob's tablespace"
- name: Create a new tablespace called bar with tablespace options
community.postgresql.postgresql_tablespace:
@@ -143,27 +152,32 @@ EXAMPLES = r'''
RETURN = r'''
queries:
description: List of queries that was tried to be executed.
- returned: always
+ returned: success
type: str
sample: [ "CREATE TABLESPACE bar LOCATION '/incredible/ssd'" ]
tablespace:
description: Tablespace name.
- returned: always
+ returned: success
type: str
sample: 'ssd'
owner:
description: Tablespace owner.
- returned: always
+ returned: success
type: str
sample: 'Bob'
+comment:
+ description: Tablespace comment.
+ returned: success
+ type: str
+ sample: 'Test tablespace'
options:
description: Tablespace options.
- returned: always
+ returned: success
type: dict
sample: { 'random_page_cost': 1, 'seq_page_cost': 1 }
location:
description: Path to the tablespace in the file system.
- returned: always
+ returned: success
type: str
sample: '/incredible/fast/ssd'
newname:
@@ -173,33 +187,24 @@ newname:
sample: new_ssd
state:
description: Tablespace state at the end of execution.
- returned: always
+ returned: success
type: str
sample: 'present'
'''
-try:
- from psycopg2 import __version__ as PSYCOPG2_VERSION
- from psycopg2.extras import DictCursor
- from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT as AUTOCOMMIT
- from psycopg2.extensions import ISOLATION_LEVEL_READ_COMMITTED as READ_COMMITTED
-except ImportError:
- # psycopg2 is checked by connect_to_db()
- # from ansible.module_utils.postgres
- pass
-
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.six import iteritems
-
-from ansible_collections.community.postgresql.plugins.module_utils.database import (
- check_input,
-)
+from ansible_collections.community.postgresql.plugins.module_utils.database import \
+ check_input
from ansible_collections.community.postgresql.plugins.module_utils.postgres import (
connect_to_db,
- exec_sql,
ensure_required_libs,
+ exec_sql,
get_conn_params,
+ pg_cursor_args,
postgres_common_argument_spec,
+ set_autocommit,
+ set_comment,
)
@@ -209,12 +214,12 @@ class PgTablespace(object):
Args:
module (AnsibleModule) -- object of AnsibleModule class
- cursor (cursor) -- cursor object of psycopg2 library
+ cursor (cursor) -- cursor object of psycopg library
name (str) -- name of the tablespace
Attrs:
module (AnsibleModule) -- object of AnsibleModule class
- cursor (cursor) -- cursor object of psycopg2 library
+ cursor (cursor) -- cursor object of psycopg library
name (str) -- name of the tablespace
exists (bool) -- flag the tablespace exists in the DB or not
owner (str) -- tablespace owner
@@ -235,6 +240,7 @@ class PgTablespace(object):
self.executed_queries = []
self.new_name = ''
self.opt_not_supported = False
+ self.comment = None
# Collect info:
self.get_info()
@@ -256,12 +262,14 @@ class PgTablespace(object):
if not opt:
self.opt_not_supported = True
- query = ("SELECT r.rolname, (SELECT Null), %s "
+ query = ("SELECT shobj_description(t.oid, 'pg_tablespace') AS comment, "
+ "r.rolname, (SELECT Null) spcoptions, %s loc_string "
"FROM pg_catalog.pg_tablespace AS t "
"JOIN pg_catalog.pg_roles AS r "
"ON t.spcowner = r.oid " % location)
else:
- query = ("SELECT r.rolname, t.spcoptions, %s "
+ query = ("SELECT shobj_description(t.oid, 'pg_tablespace') AS comment, "
+ "r.rolname, t.spcoptions, %s loc_string "
"FROM pg_catalog.pg_tablespace AS t "
"JOIN pg_catalog.pg_roles AS r "
"ON t.spcowner = r.oid " % location)
@@ -273,19 +281,21 @@ class PgTablespace(object):
self.exists = False
return False
- if res[0][0]:
+ if res[0]["rolname"]:
self.exists = True
- self.owner = res[0][0]
+ self.owner = res[0]["rolname"]
- if res[0][1]:
+ if res[0]["spcoptions"]:
# Options exist:
- for i in res[0][1]:
+ for i in res[0]["spcoptions"]:
i = i.split('=')
self.settings[i[0]] = i[1]
- if res[0][2]:
+ if res[0]["loc_string"]:
# Location exists:
- self.location = res[0][2]
+ self.location = res[0]["loc_string"]
+
+ self.comment = res[0]["comment"] if res[0]["comment"] is not None else ''
def create(self, location):
"""Create tablespace.
@@ -319,6 +329,20 @@ class PgTablespace(object):
query = 'ALTER TABLESPACE "%s" OWNER TO "%s"' % (self.name, new_owner)
return exec_sql(self, query, return_bool=True)
+ def set_comment(self, comment, check_mode):
+ """Set tablespace comment.
+
+ Return True if success, otherwise, return False.
+
+ args:
+ comment (str) -- comment to set for the tablespace"
+ """
+ if comment == self.comment:
+ return False
+
+ return set_comment(self.cursor, comment, 'tablespace', self.name,
+ check_mode, self.executed_queries)
+
def rename(self, newname):
"""Rename tablespace.
@@ -398,11 +422,11 @@ def main():
db=dict(type='str', aliases=['login_db']),
session_role=dict(type='str'),
trust_input=dict(type='bool', default=True),
+ comment=dict(type='str', default=None),
)
module = AnsibleModule(
argument_spec=argument_spec,
- mutually_exclusive=(('positional_args', 'named_args'),),
supports_check_mode=True,
)
@@ -414,6 +438,7 @@ def main():
settings = module.params["set"]
session_role = module.params["session_role"]
trust_input = module.params["trust_input"]
+ comment = module.params["comment"]
if state == 'absent' and (location or owner or rename_to or settings):
module.fail_json(msg="state=absent is mutually exclusive location, "
@@ -427,20 +452,13 @@ def main():
settings_list = ['%s = %s' % (k, v) for k, v in iteritems(settings)]
check_input(module, tablespace, location, owner,
- rename_to, session_role, settings_list)
+ rename_to, session_role, settings_list, comment)
- # Ensure psycopg2 libraries are available before connecting to DB:
+ # Ensure psycopg libraries are available before connecting to DB:
ensure_required_libs(module)
conn_params = get_conn_params(module, module.params, warn_db_default=False)
- db_connection, dummy = connect_to_db(module, conn_params, autocommit=True)
- cursor = db_connection.cursor(cursor_factory=DictCursor)
-
- # Change autocommit to False if check_mode:
- if module.check_mode:
- if PSYCOPG2_VERSION >= '2.4.2':
- db_connection.set_session(autocommit=False)
- else:
- db_connection.set_isolation_level(READ_COMMITTED)
+ db_connection, dummy = connect_to_db(module, conn_params, autocommit=False if module.check_mode else True)
+ cursor = db_connection.cursor(**pg_cursor_args)
# Set defaults:
autocommit = False
@@ -466,26 +484,15 @@ def main():
# Because CREATE TABLESPACE can not be run inside the transaction block:
autocommit = True
- if PSYCOPG2_VERSION >= '2.4.2':
- db_connection.set_session(autocommit=True)
- else:
- db_connection.set_isolation_level(AUTOCOMMIT)
+ set_autocommit(db_connection, True)
changed = tblspace.create(location)
- # Drop non-existing tablespace:
- elif not tblspace.exists and state == 'absent':
- # Nothing to do:
- module.fail_json(msg="Tries to drop nonexistent tablespace '%s'" % tblspace.name)
-
# Drop existing tablespace:
elif tblspace.exists and state == 'absent':
# Because DROP TABLESPACE can not be run inside the transaction block:
autocommit = True
- if PSYCOPG2_VERSION >= '2.4.2':
- db_connection.set_session(autocommit=True)
- else:
- db_connection.set_isolation_level(AUTOCOMMIT)
+ set_autocommit(db_connection, True)
changed = tblspace.drop()
@@ -498,14 +505,18 @@ def main():
# Refresh information:
tblspace.get_info()
- # Change owner and settings:
+ # Change owner, comment and settings:
if state == 'present' and tblspace.exists:
if owner:
- changed = tblspace.set_owner(owner)
+ changed = tblspace.set_owner(owner) or changed
if settings:
- changed = tblspace.set_settings(settings)
+ changed = tblspace.set_settings(settings) or changed
+
+ if comment is not None:
+ changed = tblspace.set_comment(comment, module.check_mode) or changed
+ # Update tablespace information in the class
tblspace.get_info()
# Rollback if it's possible and check_mode:
@@ -527,6 +538,7 @@ def main():
queries=tblspace.executed_queries,
options=tblspace.settings,
location=tblspace.location,
+ comment=tblspace.comment,
)
if state == 'present':
diff --git a/ansible_collections/community/postgresql/plugins/modules/postgresql_user.py b/ansible_collections/community/postgresql/plugins/modules/postgresql_user.py
index 594e0f1ae..8192a5480 100644
--- a/ansible_collections/community/postgresql/plugins/modules/postgresql_user.py
+++ b/ansible_collections/community/postgresql/plugins/modules/postgresql_user.py
@@ -5,6 +5,7 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
DOCUMENTATION = r'''
@@ -21,10 +22,8 @@ description:
- Set I(fail_on_user) to C(false) to make the module ignore failures when trying to remove a user.
In this case, the module reports if changes happened as usual and separately reports
whether the user has been removed or not.
-- B(WARNING) The I(priv) option has been B(deprecated) and will be removed in community.postgresql 3.0.0. Please use the
+- B(WARNING) The I(priv) option has been B(deprecated) and will be removed in community.postgresql 4.0.0. Please use the
M(community.postgresql.postgresql_privs) module instead.
-- B(WARNING) The I(groups) option has been B(deprecated) ans will be removed in community.postgresql 3.0.0.
- Please use the M(community.postgresql.postgresql_membership) module instead.
options:
name:
description:
@@ -64,7 +63,7 @@ options:
priv:
description:
- This option has been B(deprecated) and will be removed in
- community.postgresql 3.0.0. Please use the M(community.postgresql.postgresql_privs) module to
+ community.postgresql 4.0.0. Please use the M(community.postgresql.postgresql_privs) module to
GRANT/REVOKE permissions instead.
- "Slash-separated PostgreSQL privileges string: C(priv1/priv2), where
you can define the user's privileges for the database ( allowed options - 'CREATE',
@@ -141,23 +140,16 @@ options:
- If the file exists, verifies that the server's certificate is signed by one of these authorities.
type: str
aliases: [ ssl_rootcert ]
- groups:
- description:
- - This option has been B(deprecated) and will be removed in community.postgresql 3.0.0.
- Please use the I(postgresql_membership) module to GRANT/REVOKE group/role memberships
- instead.
- - The list of groups (roles) that you want to grant to the user.
- type: list
- elements: str
comment:
description:
- Adds a comment on the user (equivalent to the C(COMMENT ON ROLE) statement).
+ - To reset the comment, pass an empty string.
type: str
version_added: '0.2.0'
trust_input:
description:
- If C(false), checks whether values of options I(name), I(password), I(privs), I(expires),
- I(role_attr_flags), I(groups), I(comment), I(session_role) are potentially dangerous.
+ I(role_attr_flags), I(comment), I(session_role) are potentially dangerous.
- It makes sense to use C(false) only when SQL injections through the options are possible.
type: bool
default: true
@@ -267,15 +259,6 @@ EXAMPLES = r'''
user: test
password: ""
-# This example uses the `group` argument which is deprecated.
-# You should use the `postgresql_membership` module instead.
-- name: Create user test and grant group user_ro and user_rw to it
- community.postgresql.postgresql_user:
- name: test
- groups:
- - user_ro
- - user_rw
-
# Create user with a cleartext password if it does not exist or update its password.
# The password will be encrypted with SCRAM algorithm (available since PostgreSQL 10)
- name: Create appclient user with SCRAM-hashed password
@@ -296,43 +279,47 @@ EXAMPLES = r'''
RETURN = r'''
queries:
description: List of executed queries.
- returned: always
+ returned: success
type: list
sample: ['CREATE USER "alice"', 'GRANT CONNECT ON DATABASE "acme" TO "alice"']
'''
+import hmac
import itertools
import re
import traceback
-from hashlib import md5, sha256
-import hmac
from base64 import b64decode
+from hashlib import md5, sha256
-try:
- import psycopg2
- from psycopg2.extras import DictCursor
-except ImportError:
- # psycopg2 is checked by connect_to_db()
- # from ansible.module_utils.postgres
- pass
-
+from ansible.module_utils._text import to_bytes, to_native, to_text
from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.six import iteritems
+from ansible_collections.community.postgresql.plugins.module_utils import \
+ saslprep
from ansible_collections.community.postgresql.plugins.module_utils.database import (
- pg_quote_identifier,
SQLParseError,
check_input,
+ pg_quote_identifier,
)
from ansible_collections.community.postgresql.plugins.module_utils.postgres import (
+ HAS_PSYCOPG,
+ PSYCOPG_VERSION,
connect_to_db,
ensure_required_libs,
+ get_comment,
get_conn_params,
get_server_version,
- PgMembership,
+ pg_cursor_args,
postgres_common_argument_spec,
+ set_comment,
)
-from ansible.module_utils._text import to_bytes, to_native, to_text
-from ansible.module_utils.six import iteritems
-from ansible_collections.community.postgresql.plugins.module_utils import saslprep
+from ansible_collections.community.postgresql.plugins.module_utils.version import \
+ LooseVersion
+
+if HAS_PSYCOPG and PSYCOPG_VERSION < LooseVersion("3.0"):
+ import psycopg2 as psycopg
+elif HAS_PSYCOPG:
+ import psycopg
try:
# pbkdf2_hmac is missing on python 2.6, we can safely assume,
@@ -348,7 +335,7 @@ FLAGS_BY_VERSION = {'BYPASSRLS': 90500}
SCRAM_SHA256_REGEX = r'^SCRAM-SHA-256\$(\d+):([A-Za-z0-9+\/=]+)\$([A-Za-z0-9+\/=]+):([A-Za-z0-9+\/=]+)$'
-# WARNING: privs are deprecated and will be removed in community.postgresql 3.0.0
+# WARNING: privs are deprecated and will be removed in community.postgresql 4.0.0
VALID_PRIVS = dict(table=frozenset(('SELECT', 'INSERT', 'UPDATE', 'DELETE', 'TRUNCATE', 'REFERENCES', 'TRIGGER', 'ALL')),
database=frozenset(
('CREATE', 'CONNECT', 'TEMPORARY', 'TEMP', 'ALL')),
@@ -428,24 +415,29 @@ def user_should_we_change_password(current_role_attrs, user, password, encrypted
# Do we actually need to do anything?
pwchanging = False
if password is not None:
+ current_password = current_role_attrs['rolpassword']
+ # Handle SQL_ASCII encoded databases
+ if isinstance(current_password, bytes):
+ current_password = current_password.decode('ascii')
+
# Empty password means that the role shouldn't have a password, which
# means we need to check if the current password is None.
if password == '':
- if current_role_attrs['rolpassword'] is not None:
+ if current_password is not None:
pwchanging = True
# If the provided password is a SCRAM hash, compare it directly to the current password
elif re.match(SCRAM_SHA256_REGEX, password):
- if password != current_role_attrs['rolpassword']:
+ if password != current_password:
pwchanging = True
# SCRAM hashes are represented as a special object, containing hash data:
# `SCRAM-SHA-256$<iteration count>:<salt>$<StoredKey>:<ServerKey>`
# for reference, see https://www.postgresql.org/docs/current/catalog-pg-authid.html
- elif current_role_attrs['rolpassword'] is not None \
+ elif current_password is not None \
and pbkdf2_found \
- and re.match(SCRAM_SHA256_REGEX, current_role_attrs['rolpassword']):
+ and re.match(SCRAM_SHA256_REGEX, current_password):
- r = re.match(SCRAM_SHA256_REGEX, current_role_attrs['rolpassword'])
+ r = re.match(SCRAM_SHA256_REGEX, current_password)
try:
# extract SCRAM params from rolpassword
it = int(r.group(1))
@@ -475,11 +467,11 @@ def user_should_we_change_password(current_role_attrs, user, password, encrypted
# When the provided password looks like a MD5-hash, value of
# 'encrypted' is ignored.
elif (password.startswith('md5') and len(password) == 32 + 3) or encrypted == 'UNENCRYPTED':
- if password != current_role_attrs['rolpassword']:
+ if password != current_password:
pwchanging = True
elif encrypted == 'ENCRYPTED':
hashed_password = 'md5{0}'.format(md5(to_bytes(password) + to_bytes(user)).hexdigest())
- if hashed_password != current_role_attrs['rolpassword']:
+ if hashed_password != current_password:
pwchanging = True
return pwchanging
@@ -489,7 +481,7 @@ def user_alter(db_connection, module, user, password, role_attr_flags, encrypted
"""Change user password and/or attributes. Return True if changed, False otherwise."""
changed = False
- cursor = db_connection.cursor(cursor_factory=DictCursor)
+ cursor = db_connection.cursor(**pg_cursor_args)
# Note: role_attr_flags escaped by parse_role_attrs and encrypted is a
# literal
if user == 'PUBLIC':
@@ -508,7 +500,7 @@ def user_alter(db_connection, module, user, password, role_attr_flags, encrypted
cursor.execute(select, {"user": user})
# Grab current role attributes.
current_role_attrs = cursor.fetchone()
- except psycopg2.ProgrammingError:
+ except psycopg.ProgrammingError:
current_role_attrs = None
db_connection.rollback()
@@ -522,7 +514,7 @@ def user_alter(db_connection, module, user, password, role_attr_flags, encrypted
cursor.execute(select, {"user": user})
# Grab current role attributes from pg_roles
current_role_attrs = cursor.fetchone()
- except psycopg2.ProgrammingError as e:
+ except psycopg.ProgrammingError as e:
db_connection.rollback()
module.fail_json(msg="Failed to get role details for current user %s: %s" % (user, e))
@@ -540,8 +532,8 @@ def user_alter(db_connection, module, user, password, role_attr_flags, encrypted
role_attr_flags_changing = True
if expires is not None:
- cursor.execute("SELECT %s::timestamptz;", (expires,))
- expires_with_tz = cursor.fetchone()[0]
+ cursor.execute("SELECT %s::timestamptz exp_timestamp", (expires,))
+ expires_with_tz = cursor.fetchone()["exp_timestamp"]
expires_changing = expires_with_tz != current_role_attrs.get('rolvaliduntil')
else:
expires_changing = False
@@ -572,17 +564,19 @@ def user_alter(db_connection, module, user, password, role_attr_flags, encrypted
cursor.execute(statement, query_password_data)
changed = True
executed_queries.append(statement)
- except psycopg2.InternalError as e:
- if e.pgcode == '25006':
+ # We could catch psycopg.errors.ReadOnlySqlTransaction directly,
+ # but that was added only in Psycopg 2.8
+ except psycopg.InternalError as e:
+ if e.diag.sqlstate == "25006":
# Handle errors due to read-only transactions indicated by pgcode 25006
# ERROR: cannot execute ALTER ROLE in a read-only transaction
changed = False
- module.fail_json(msg=e.pgerror, exception=traceback.format_exc())
+ module.fail_json(msg=e.diag.message_primary, exception=traceback.format_exc())
return changed
else:
- raise psycopg2.InternalError(e)
- except psycopg2.NotSupportedError as e:
- module.fail_json(msg=e.pgerror, exception=traceback.format_exc())
+ raise psycopg.InternalError(e)
+ except psycopg.NotSupportedError as e:
+ module.fail_json(msg=e.diag.message_primary, exception=traceback.format_exc())
elif no_password_changes and role_attr_flags != '':
# Grab role information from pg_roles instead of pg_authid
@@ -617,15 +611,16 @@ def user_alter(db_connection, module, user, password, role_attr_flags, encrypted
statement = ' '.join(alter)
cursor.execute(statement)
executed_queries.append(statement)
- except psycopg2.InternalError as e:
- if e.pgcode == '25006':
+
+ except psycopg.InternalError as e:
+ if e.diag.sqlstate == "25006":
# Handle errors due to read-only transactions indicated by pgcode 25006
# ERROR: cannot execute ALTER ROLE in a read-only transaction
changed = False
- module.fail_json(msg=e.pgerror, exception=traceback.format_exc())
+ module.fail_json(msg=e.diag.message_primary, exception=traceback.format_exc())
return changed
else:
- raise psycopg2.InternalError(e)
+ raise psycopg.InternalError(e)
# Grab new role attributes.
cursor.execute(select, {"user": user})
@@ -653,7 +648,7 @@ def user_delete(cursor, user):
return True
-# WARNING: privs are deprecated and will be removed in community.postgresql 3.0.0
+# WARNING: privs are deprecated and will be removed in community.postgresql 4.0.0
def has_table_privileges(cursor, user, table, privs):
"""
Return the difference between the privileges that a user already has and
@@ -671,7 +666,7 @@ def has_table_privileges(cursor, user, table, privs):
return (have_currently, other_current, desired)
-# WARNING: privs are deprecated and will be removed in community.postgresql 3.0.0
+# WARNING: privs are deprecated and will be removed in community.postgresql 4.0.0
def get_table_privileges(cursor, user, table):
if '.' in table:
schema, table = table.split('.', 1)
@@ -680,10 +675,10 @@ def get_table_privileges(cursor, user, table):
query = ("SELECT privilege_type FROM information_schema.role_table_grants "
"WHERE grantee=%(user)s AND table_name=%(table)s AND table_schema=%(schema)s")
cursor.execute(query, {'user': user, 'table': table, 'schema': schema})
- return frozenset([x[0] for x in cursor.fetchall()])
+ return frozenset([x["privilege_type"] for x in cursor.fetchall()])
-# WARNING: privs are deprecated and will be removed in community.postgresql 3.0.0
+# WARNING: privs are deprecated and will be removed in community.postgresql 4.0.0
def grant_table_privileges(cursor, user, table, privs):
# Note: priv escaped by parse_privs
privs = ', '.join(privs)
@@ -693,7 +688,7 @@ def grant_table_privileges(cursor, user, table, privs):
cursor.execute(query)
-# WARNING: privs are deprecated and will be removed in community.postgresql 3.0.0
+# WARNING: privs are deprecated and will be removed in community.postgresql 4.0.0
def revoke_table_privileges(cursor, user, table, privs):
# Note: priv escaped by parse_privs
privs = ', '.join(privs)
@@ -703,16 +698,16 @@ def revoke_table_privileges(cursor, user, table, privs):
cursor.execute(query)
-# WARNING: privs are deprecated and will be removed in community.postgresql 3.0.0
+# WARNING: privs are deprecated and will be removed in community.postgresql 4.0.0
def get_database_privileges(cursor, user, db):
priv_map = {
'C': 'CREATE',
'T': 'TEMPORARY',
'c': 'CONNECT',
}
- query = 'SELECT datacl FROM pg_database WHERE datname = %s'
+ query = 'SELECT datacl::text FROM pg_database WHERE datname = %s'
cursor.execute(query, (db,))
- datacl = cursor.fetchone()[0]
+ datacl = cursor.fetchone()["datacl"]
if datacl is None:
return set()
r = re.search(r'%s\\?"?=(C?T?c?)/[^,]+,?' % user, datacl)
@@ -724,7 +719,7 @@ def get_database_privileges(cursor, user, db):
return normalize_privileges(o, 'database')
-# WARNING: privs are deprecated and will be removed in community.postgresql 3.0.0
+# WARNING: privs are deprecated and will be removed in community.postgresql 4.0.0
def has_database_privileges(cursor, user, db, privs):
"""
Return the difference between the privileges that a user already has and
@@ -742,7 +737,7 @@ def has_database_privileges(cursor, user, db, privs):
return (have_currently, other_current, desired)
-# WARNING: privs are deprecated and will be removed in community.postgresql 3.0.0
+# WARNING: privs are deprecated and will be removed in community.postgresql 4.0.0
def grant_database_privileges(cursor, user, db, privs):
# Note: priv escaped by parse_privs
privs = ', '.join(privs)
@@ -757,7 +752,7 @@ def grant_database_privileges(cursor, user, db, privs):
cursor.execute(query)
-# WARNING: privs are deprecated and will be removed in community.postgresql 3.0.0
+# WARNING: privs are deprecated and will be removed in community.postgresql 4.0.0
def revoke_database_privileges(cursor, user, db, privs):
# Note: priv escaped by parse_privs
privs = ', '.join(privs)
@@ -772,7 +767,7 @@ def revoke_database_privileges(cursor, user, db, privs):
cursor.execute(query)
-# WARNING: privs are deprecated and will be removed in community.postgresql 3.0.0
+# WARNING: privs are deprecated and will be removed in community.postgresql 4.0.0
def revoke_privileges(cursor, user, privs):
if privs is None:
return False
@@ -794,7 +789,7 @@ def revoke_privileges(cursor, user, privs):
return changed
-# WARNING: privs are deprecated and will be removed in community.postgresql 3.0.0
+# WARNING: privs are deprecated and will be removed in community.postgresql 4.0.0
def grant_privileges(cursor, user, privs):
if privs is None:
return False
@@ -846,7 +841,7 @@ def parse_role_attrs(role_attr_flags, srv_version):
return ' '.join(flags)
-# WARNING: privs are deprecated and will be removed in community.postgresql 3.0.0
+# WARNING: privs are deprecated and will be removed in community.postgresql 4.0.0
def normalize_privileges(privs, type_):
new_privs = set(privs)
if 'ALL' in new_privs:
@@ -859,7 +854,7 @@ def normalize_privileges(privs, type_):
return new_privs
-# WARNING: privs are deprecated and will be removed in community.postgresql 3.0.0
+# WARNING: privs are deprecated and will be removed in community.postgresql 4.0.0
def parse_privs(privs, db):
"""
Parse privilege string to determine permissions for database db.
@@ -913,21 +908,13 @@ def get_valid_flags_by_version(srv_version):
]
-def get_comment(cursor, user):
- """Get user's comment."""
- query = ("SELECT pg_catalog.shobj_description(r.oid, 'pg_authid') "
- "FROM pg_catalog.pg_roles r "
- "WHERE r.rolname = %(user)s")
- cursor.execute(query, {'user': user})
- return cursor.fetchone()[0]
-
-
-def add_comment(cursor, user, comment):
+def add_comment(cursor, user, comment, check_mode):
"""Add comment on user."""
- if comment != get_comment(cursor, user):
- query = 'COMMENT ON ROLE "%s" IS ' % user
- cursor.execute(query + '%(comment)s', {'comment': comment})
- executed_queries.append(cursor.mogrify(query + '%(comment)s', {'comment': comment}))
+ current_comment = get_comment(cursor, 'role', user)
+ # For the resetting comment feature (comment: '') to work correctly
+ current_comment = current_comment if current_comment is not None else ''
+ if comment != current_comment:
+ set_comment(cursor, comment, 'role', user, check_mode, executed_queries)
return True
else:
return False
@@ -943,7 +930,7 @@ def main():
user=dict(type='str', required=True, aliases=['name']),
password=dict(type='str', default=None, no_log=True),
state=dict(type='str', default='present', choices=['absent', 'present']),
- priv=dict(type='str', default=None, removed_in_version='3.0.0', removed_from_collection='community.postgreql'),
+ priv=dict(type='str', default=None, removed_in_version='4.0.0', removed_from_collection='community.postgreql'),
db=dict(type='str', default='', aliases=['login_db']),
fail_on_user=dict(type='bool', default=True, aliases=['fail_on_role']),
role_attr_flags=dict(type='str', default=''),
@@ -952,8 +939,6 @@ def main():
expires=dict(type='str', default=None),
conn_limit=dict(type='int', default=None),
session_role=dict(type='str'),
- # WARNING: groups are deprecated and will be removed in community.postgresql 3.0.0
- groups=dict(type='list', elements='str', removed_in_version='3.0.0', removed_from_collection='community.postgreql'),
comment=dict(type='str', default=None),
trust_input=dict(type='bool', default=True),
)
@@ -966,10 +951,10 @@ def main():
password = module.params["password"]
state = module.params["state"]
fail_on_user = module.params["fail_on_user"]
- # WARNING: privs are deprecated and will be removed in community.postgresql 3.0.0
+ # WARNING: privs are deprecated and will be removed in community.postgresql 4.0.0
if module.params['db'] == '' and module.params["priv"] is not None:
module.fail_json(msg="privileges require a database to be specified")
- # WARNING: privs are deprecated and will be removed in community.postgresql 3.0.0
+ # WARNING: privs are deprecated and will be removed in community.postgresql 4.0.0
privs = parse_privs(module.params["priv"], module.params["db"])
no_password_changes = module.params["no_password_changes"]
if module.params["encrypted"]:
@@ -979,25 +964,20 @@ def main():
expires = module.params["expires"]
conn_limit = module.params["conn_limit"]
role_attr_flags = module.params["role_attr_flags"]
- # WARNING: groups are deprecated and will be removed in community.postgresql 3.0.0
- groups = module.params["groups"]
- if groups:
- groups = [e.strip() for e in groups]
comment = module.params["comment"]
session_role = module.params['session_role']
trust_input = module.params['trust_input']
if not trust_input:
# Check input for potentially dangerous elements:
- # WARNING: groups are deprecated and will be removed in community.postgresql 3.0.0
check_input(module, user, password, privs, expires,
- role_attr_flags, groups, comment, session_role)
+ role_attr_flags, comment, session_role, comment)
- # Ensure psycopg2 libraries are available before connecting to DB:
+ # Ensure psycopg libraries are available before connecting to DB:
ensure_required_libs(module)
conn_params = get_conn_params(module, module.params, warn_db_default=False)
db_connection, dummy = connect_to_db(module, conn_params)
- cursor = db_connection.cursor(cursor_factory=DictCursor)
+ cursor = db_connection.cursor(**pg_cursor_args)
srv_version = get_server_version(db_connection)
@@ -1021,29 +1001,21 @@ def main():
try:
changed = user_add(cursor, user, password,
role_attr_flags, encrypted, expires, conn_limit)
- except psycopg2.ProgrammingError as e:
+ except psycopg.ProgrammingError as e:
module.fail_json(msg="Unable to add user with given requirement "
"due to : %s" % to_native(e),
exception=traceback.format_exc())
except SQLParseError as e:
module.fail_json(msg=to_native(e), exception=traceback.format_exc())
- # WARNING: privs are deprecated and will be removed in community.postgresql 3.0.0
+ # WARNING: privs are deprecated and will be removed in community.postgresql 4.0.0
try:
changed = grant_privileges(cursor, user, privs) or changed
except SQLParseError as e:
module.fail_json(msg=to_native(e), exception=traceback.format_exc())
- # WARNING: groups are deprecated and will be removed in community.postgresql 3.0.0
- if groups:
- target_roles = []
- target_roles.append(user)
- pg_membership = PgMembership(module, cursor, groups, target_roles)
- changed = pg_membership.grant() or changed
- executed_queries.extend(pg_membership.executed_queries)
-
if comment is not None:
try:
- changed = add_comment(cursor, user, comment) or changed
+ changed = add_comment(cursor, user, comment, module.check_mode) or changed
except Exception as e:
module.fail_json(msg='Unable to add comment on role: %s' % to_native(e),
exception=traceback.format_exc())
@@ -1054,7 +1026,7 @@ def main():
changed = True
kw['user_removed'] = True
else:
- # WARNING: privs are deprecated and will be removed in community.postgresql 3.0.0
+ # WARNING: privs are deprecated and will be removed in community.postgresql 4.0.0
try:
changed = revoke_privileges(cursor, user, privs)
user_removed = user_delete(cursor, user)
diff --git a/ansible_collections/community/postgresql/plugins/modules/postgresql_user_obj_stat_info.py b/ansible_collections/community/postgresql/plugins/modules/postgresql_user_obj_stat_info.py
index f443d50c3..35a5b1fd0 100644
--- a/ansible_collections/community/postgresql/plugins/modules/postgresql_user_obj_stat_info.py
+++ b/ansible_collections/community/postgresql/plugins/modules/postgresql_user_obj_stat_info.py
@@ -5,6 +5,7 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
DOCUMENTATION = r'''
@@ -89,41 +90,33 @@ EXAMPLES = r'''
RETURN = r'''
indexes:
description: User index statistics.
- returned: always
+ returned: success
type: dict
sample: {"public": {"test_id_idx": {"idx_scan": 0, "idx_tup_fetch": 0, "idx_tup_read": 0, "relname": "test", "size": 8192, ...}}}
tables:
description: User table statistics.
- returned: always
+ returned: success
type: dict
sample: {"public": {"test": {"analyze_count": 3, "n_dead_tup": 0, "n_live_tup": 0, "seq_scan": 2, "size": 0, "total_size": 8192, ...}}}
functions:
description: User function statistics.
- returned: always
+ returned: success
type: dict
sample: {"public": {"inc": {"calls": 1, "funcid": 26722, "self_time": 0.23, "total_time": 0.23}}}
'''
-try:
- from psycopg2.extras import DictCursor
-except ImportError:
- # psycopg2 is checked by connect_to_db()
- # from ansible.module_utils.postgres
- pass
-
from ansible.module_utils.basic import AnsibleModule
-from ansible_collections.community.postgresql.plugins.module_utils.database import (
- check_input,
-)
+from ansible.module_utils.six import iteritems
+from ansible_collections.community.postgresql.plugins.module_utils.database import \
+ check_input
from ansible_collections.community.postgresql.plugins.module_utils.postgres import (
connect_to_db,
- exec_sql,
ensure_required_libs,
+ exec_sql,
get_conn_params,
+ pg_cursor_args,
postgres_common_argument_spec,
)
-from ansible.module_utils.six import iteritems
-
# ===========================================
# PostgreSQL module specific support methods.
@@ -135,11 +128,11 @@ class PgUserObjStatInfo():
Args:
module (AnsibleModule): Object of AnsibleModule class.
- cursor (cursor): Cursor object of psycopg2 library to work with PostgreSQL.
+ cursor (cursor): Cursor object of psycopg library to work with PostgreSQL.
Attributes:
module (AnsibleModule): Object of AnsibleModule class.
- cursor (cursor): Cursor object of psycopg2 library to work with PostgreSQL.
+ cursor (cursor): Cursor object of psycopg library to work with PostgreSQL.
executed_queries (list): List of executed queries.
info (dict): Statistics dictionary.
obj_func_mapping (dict): Mapping of object types to corresponding functions.
@@ -193,11 +186,12 @@ class PgUserObjStatInfo():
def get_func_stat(self):
"""Get function statistics and fill out self.info dictionary."""
query = "SELECT * FROM pg_stat_user_functions"
+ qp = None
if self.schema:
query = "SELECT * FROM pg_stat_user_functions WHERE schemaname = %s"
+ qp = (self.schema,)
- result = exec_sql(self, query, query_params=(self.schema,),
- add_to_executed=False)
+ result = exec_sql(self, query, query_params=qp, add_to_executed=False)
if not result:
return
@@ -210,11 +204,12 @@ class PgUserObjStatInfo():
def get_idx_stat(self):
"""Get index statistics and fill out self.info dictionary."""
query = "SELECT * FROM pg_stat_user_indexes"
+ qp = None
if self.schema:
query = "SELECT * FROM pg_stat_user_indexes WHERE schemaname = %s"
+ qp = (self.schema,)
- result = exec_sql(self, query, query_params=(self.schema,),
- add_to_executed=False)
+ result = exec_sql(self, query, query_params=qp, add_to_executed=False)
if not result:
return
@@ -227,11 +222,12 @@ class PgUserObjStatInfo():
def get_tbl_stat(self):
"""Get table statistics and fill out self.info dictionary."""
query = "SELECT * FROM pg_stat_user_tables"
+ qp = None
if self.schema:
query = "SELECT * FROM pg_stat_user_tables WHERE schemaname = %s"
+ qp = (self.schema,)
- result = exec_sql(self, query, query_params=(self.schema,),
- add_to_executed=False)
+ result = exec_sql(self, query, query_params=qp, add_to_executed=False)
if not result:
return
@@ -270,23 +266,23 @@ class PgUserObjStatInfo():
query_params=(relname,),
add_to_executed=False)
- self.info[info_key][elem[schema_key]][elem[name_key]]['size'] = result[0][0]
+ self.info[info_key][elem[schema_key]][elem[name_key]]['size'] = result[0]["pg_relation_size"]
if info_key == 'tables':
result = exec_sql(self, "SELECT pg_total_relation_size (%s)",
query_params=(relname,),
add_to_executed=False)
- self.info[info_key][elem[schema_key]][elem[name_key]]['total_size'] = result[0][0]
+ self.info[info_key][elem[schema_key]][elem[name_key]]['total_size'] = result[0]["pg_total_relation_size"]
def set_schema(self, schema):
"""If schema exists, sets self.schema, otherwise fails."""
- query = ("SELECT 1 FROM information_schema.schemata "
+ query = ("SELECT 1 as schema_exists FROM information_schema.schemata "
"WHERE schema_name = %s")
result = exec_sql(self, query, query_params=(schema,),
add_to_executed=False)
- if result and result[0][0]:
+ if result and result[0]["schema_exists"]:
self.schema = schema
else:
self.module.fail_json(msg="Schema '%s' does not exist" % (schema))
@@ -316,13 +312,13 @@ def main():
if not module.params["trust_input"]:
check_input(module, module.params['session_role'])
- # Ensure psycopg2 libraries are available before connecting to DB:
+ # Ensure psycopg libraries are available before connecting to DB:
ensure_required_libs(module)
# Connect to DB and make cursor object:
pg_conn_params = get_conn_params(module, module.params)
# We don't need to commit anything, so, set it to False:
db_connection, dummy = connect_to_db(module, pg_conn_params, autocommit=False)
- cursor = db_connection.cursor(cursor_factory=DictCursor)
+ cursor = db_connection.cursor(**pg_cursor_args)
############################
# Create object and do work:
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_db/defaults/main.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_db/defaults/main.yml
index 766feeecc..d5c9deb57 100644
--- a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_db/defaults/main.yml
+++ b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_db/defaults/main.yml
@@ -1,4 +1,5 @@
db_name: 'ansible_db'
+db_name_icu: 'ansible_db_icu'
db_user1: 'ansible.db.user1'
db_user2: 'ansible.db.user2'
tmp_dir: '/tmp'
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_db/tasks/main.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_db/tasks/main.yml
index dd55c3f98..2c5fc7c95 100644
--- a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_db/tasks/main.yml
+++ b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_db/tasks/main.yml
@@ -45,3 +45,6 @@
# Simple test to create and then drop with force
- import_tasks: manage_database.yml
+
+# Test the comment feature
+- import_tasks: postgresql_db_comment.yml
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_db/tasks/postgresql_db_comment.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_db/tasks/postgresql_db_comment.yml
new file mode 100644
index 000000000..1e4d8426c
--- /dev/null
+++ b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_db/tasks/postgresql_db_comment.yml
@@ -0,0 +1,189 @@
+# Test code for the postgresql_db comment module feature
+# Copyright: (c) 2019, Andrew Klychkov (@Andersson007) <andrew.a.klychkov@gmail.com>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+- name: Set parameters we use with most of tasks
+ ansible.builtin.set_fact:
+ task_parameters: &task_parameters
+ become_user: "{{ pg_user }}"
+ become: true
+ register: result
+
+- name: Create DB with comment
+ <<: *task_parameters
+ postgresql_db:
+ state: present
+ name: comment_db
+ trust_input: false
+ login_user: "{{ pg_user }}"
+ comment: Test DB comment 1
+
+- name: Assert the executed commands
+ assert:
+ that:
+ - result is changed
+ - result.db == "comment_db"
+ - result.executed_commands == ['CREATE DATABASE "comment_db"', "COMMENT ON DATABASE \"comment_db\" IS 'Test DB comment 1'"]
+
+- name: Get the DB comment
+ <<: *task_parameters
+ postgresql_query:
+ login_user: "{{ pg_user }}"
+ query: "SELECT pg_catalog.shobj_description(d.oid, 'pg_database') AS comment FROM pg_catalog.pg_database d WHERE datname = 'comment_db'"
+
+- name: Check the comments match
+ assert:
+ that:
+ - result.query_result[0]['comment'] == "Test DB comment 1"
+
+
+- name: Create DB with another comment in check mode
+ <<: *task_parameters
+ postgresql_db:
+ state: present
+ name: comment_db
+ login_user: "{{ pg_user }}"
+ comment: Another comment
+ check_mode: true
+
+- name: Assert the result
+ assert:
+ that:
+ - result is changed
+
+- name: Check the comment
+ <<: *task_parameters
+ postgresql_query:
+ login_user: "{{ pg_user }}"
+ query: "SELECT pg_catalog.shobj_description(d.oid, 'pg_database') AS comment FROM pg_catalog.pg_database d WHERE datname = 'comment_db'"
+
+- name: Check the comment hasn't changed
+ assert:
+ that:
+ - result.query_result[0]['comment'] == "Test DB comment 1"
+
+
+- name: Create DB with another comment in real mode
+ <<: *task_parameters
+ postgresql_db:
+ state: present
+ name: comment_db
+ login_user: "{{ pg_user }}"
+ comment: Another comment
+
+- name: Assert the result
+ assert:
+ that:
+ - result is changed
+ - result.executed_commands == ["COMMENT ON DATABASE \"comment_db\" IS 'Another comment'"]
+
+- name: Check the comment
+ <<: *task_parameters
+ postgresql_query:
+ login_user: "{{ pg_user }}"
+ query: "SELECT pg_catalog.shobj_description(d.oid, 'pg_database') AS comment FROM pg_catalog.pg_database d WHERE datname = 'comment_db'"
+
+- name: Check the comments match
+ assert:
+ that:
+ - result.query_result[0]['comment'] == "Another comment"
+
+
+- name: Create DB with the same comment in real mode
+ <<: *task_parameters
+ postgresql_db:
+ state: present
+ name: comment_db
+ login_user: "{{ pg_user }}"
+ comment: Another comment
+
+- name: Assert the result
+ assert:
+ that:
+ - result is not changed
+ - result.executed_commands == []
+
+- name: Check the comment
+ <<: *task_parameters
+ postgresql_query:
+ login_user: "{{ pg_user }}"
+ query: "SELECT pg_catalog.shobj_description(d.oid, 'pg_database') AS comment FROM pg_catalog.pg_database d WHERE datname = 'comment_db'"
+
+- name: Check the comments match
+ assert:
+ that:
+ - result.query_result[0]['comment'] == "Another comment"
+
+
+- name: Not specifying the comment will not erase it
+ <<: *task_parameters
+ postgresql_db:
+ state: present
+ name: comment_db
+ login_user: "{{ pg_user }}"
+
+- name: Assert the result
+ assert:
+ that:
+ - result is not changed
+ - result.executed_commands == []
+
+- name: Check the comment
+ <<: *task_parameters
+ postgresql_query:
+ login_user: "{{ pg_user }}"
+ query: "SELECT pg_catalog.shobj_description(d.oid, 'pg_database') AS comment FROM pg_catalog.pg_database d WHERE datname = 'comment_db'"
+
+- name: Check the comments match
+ assert:
+ that:
+ - result.query_result[0]['comment'] == "Another comment"
+
+
+- name: Reset the comment
+ <<: *task_parameters
+ postgresql_db:
+ state: present
+ name: comment_db
+ login_user: "{{ pg_user }}"
+ comment: ''
+
+- name: Assert the result
+ assert:
+ that:
+ - result is changed
+ - result.executed_commands == ["COMMENT ON DATABASE \"comment_db\" IS ''"]
+
+- name: Check the comment
+ <<: *task_parameters
+ postgresql_query:
+ login_user: "{{ pg_user }}"
+ query: "SELECT pg_catalog.shobj_description(d.oid, 'pg_database') AS comment FROM pg_catalog.pg_database d WHERE datname = 'comment_db'"
+
+- name: Check the comments match
+ assert:
+ that:
+ - result.query_result[0]['comment'] == None
+
+
+- name: Reset the comment again
+ <<: *task_parameters
+ postgresql_db:
+ state: present
+ name: comment_db
+ login_user: "{{ pg_user }}"
+ comment: ''
+
+- name: Assert the result
+ assert:
+ that:
+ - result is not changed
+ - result.executed_commands == []
+
+
+- name: Clean up
+ <<: *task_parameters
+ postgresql_db:
+ state: absent
+ name: comment_db
+ login_user: "{{ pg_user }}"
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_db/tasks/postgresql_db_initial.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_db/tasks/postgresql_db_initial.yml
index 472524a23..e87b4c3da 100644
--- a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_db/tasks/postgresql_db_initial.yml
+++ b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_db/tasks/postgresql_db_initial.yml
@@ -105,7 +105,7 @@
#
# Test conn_limit, encoding, collate, ctype, template options
#
-- name: Create a DB with conn_limit, encoding, collate, ctype, and template options
+- name: Create a DB with conn_limit, encoding, collate, ctype and template options
become_user: "{{ pg_user }}"
become: true
postgresql_db:
@@ -124,6 +124,35 @@
- result is changed
- result.executed_commands == ["CREATE DATABASE \"{{ db_name }}\" TEMPLATE \"template0\" ENCODING 'LATIN1' LC_COLLATE 'pt_BR{{ locale_latin_suffix }}' LC_CTYPE 'es_ES{{ locale_latin_suffix }}' CONNECTION LIMIT 100"] or result.executed_commands == ["CREATE DATABASE \"{{ db_name }}\" TEMPLATE \"template0\" ENCODING E'LATIN1' LC_COLLATE E'pt_BR{{ locale_latin_suffix }}' LC_CTYPE E'es_ES{{ locale_latin_suffix }}' CONNECTION LIMIT 100"]
+
+#
+# Test conn_limit, encoding, collate, ctype, icu_locale, icu_provider, template options
+#
+- block:
+
+ - name: Create a DB with conn_limit, encoding, collate, ctype, icu_locale, locale_provider and template options
+ become_user: "{{ pg_user }}"
+ become: true
+ postgresql_db:
+ name: '{{ db_name_icu }}'
+ state: 'present'
+ conn_limit: '100'
+ encoding: 'LATIN1'
+ lc_collate: 'pt_BR{{ locale_latin_suffix }}'
+ lc_ctype: 'es_ES{{ locale_latin_suffix }}'
+ icu_locale: 'es_ES-x-icu'
+ locale_provider: 'icu'
+ template: 'template0'
+ login_user: "{{ pg_user }}"
+ register: result
+
+ - assert:
+ that:
+ - result is changed
+ - result.executed_commands == ["CREATE DATABASE \"{{ db_name_icu }}\" TEMPLATE \"template0\" ENCODING 'LATIN1' LC_COLLATE 'pt_BR{{ locale_latin_suffix }}' LC_CTYPE 'es_ES{{ locale_latin_suffix }}' ICU_LOCALE 'es_ES-x-icu' LOCALE_PROVIDER 'icu' CONNECTION LIMIT 100"] or result.executed_commands == ["CREATE DATABASE \"{{ db_name_icu }}\" TEMPLATE \"template0\" ENCODING E'LATIN1' LC_COLLATE E'pt_BR{{ locale_latin_suffix }}' LC_CTYPE E'es_ES{{ locale_latin_suffix }}' ICU_LOCALE E'es_ES-x-icu' LOCALE_PROVIDER 'icu' CONNECTION LIMIT 100"]
+
+ when: postgres_version_resp.stdout is version('15.0', '>=')
+
- name: Check that the DB has all of our options
become_user: "{{ pg_user }}"
become: true
@@ -140,6 +169,29 @@
- "'en_US' not in result.stdout_lines[-2]"
- "'100' in result.stdout_lines[-2]"
+- block:
+
+ - name: Check that the DB has all of our options including icu
+ become_user: "{{ pg_user }}"
+ become: true
+ shell: echo "select datname, datconnlimit, pg_encoding_to_char(encoding), datcollate, datctype, daticulocale, CASE datlocprovider WHEN 'i' THEN 'lib_icu' WHEN 'c' THEN 'libc' END AS localeprovider from pg_database where datname = '{{ db_name_icu }}';" | psql -d postgres
+ register: result
+
+ - assert:
+ that:
+ - "result.stdout_lines[-1] == '(1 row)'"
+ - "'LATIN1' in result.stdout_lines[-2]"
+ - "'pt_BR' in result.stdout_lines[-2]"
+ - "'es_ES' in result.stdout_lines[-2]"
+ - "'es_ES-x-icu' in result.stdout_lines[-2]"
+ - "'lib_icu' in result.stdout_lines[-2]"
+ - "'UTF8' not in result.stdout_lines[-2]"
+ - "'en_US' not in result.stdout_lines[-2]"
+ - "'100' in result.stdout_lines[-2]"
+
+ when: postgres_version_resp.stdout is version('15.0', '>=')
+
+
- name: Check that running db creation with options a second time does nothing
become_user: "{{ pg_user }}"
become: true
@@ -159,6 +211,30 @@
- result is not changed
+- block:
+
+ - name: Check that running db creation with icu options a second time does nothing
+ become_user: "{{ pg_user }}"
+ become: true
+ postgresql_db:
+ name: '{{ db_name_icu }}'
+ state: 'present'
+ conn_limit: '100'
+ encoding: 'LATIN1'
+ lc_collate: 'pt_BR{{ locale_latin_suffix }}'
+ lc_ctype: 'es_ES{{ locale_latin_suffix }}'
+ icu_locale: 'es_ES-x-icu'
+ locale_provider: 'icu'
+ template: 'template0'
+ login_user: "{{ pg_user }}"
+ register: result
+
+ - assert:
+ that:
+ - result is not changed
+
+ when: postgres_version_resp.stdout is version('15.0', '>=')
+
- name: Check that attempting to change encoding returns an error
become_user: "{{ pg_user }}"
become: true
@@ -177,6 +253,50 @@
that:
- result is failed
+- block:
+
+ - name: Check that attempting to change icu collate returns an error
+ become_user: "{{ pg_user }}"
+ become: true
+ postgresql_db:
+ name: '{{ db_name_icu }}'
+ state: 'present'
+ encoding: 'LATIN1'
+ lc_collate: 'pt_BR{{ locale_utf8_suffix }}'
+ lc_ctype: 'es_ES{{ locale_utf8_suffix }}'
+ icu_locale: 'en_US-x-icu'
+ locale_provider: 'icu'
+ template: 'template0'
+ login_user: "{{ pg_user }}"
+ register: result
+ ignore_errors: true
+
+ - assert:
+ that:
+ - result is failed
+
+ - name: Check that attempting to change locale provider returns an error
+ become_user: "{{ pg_user }}"
+ become: true
+ postgresql_db:
+ name: '{{ db_name_icu }}'
+ state: 'present'
+ encoding: 'LATIN1'
+ lc_collate: 'pt_BR{{ locale_utf8_suffix }}'
+ lc_ctype: 'es_ES{{ locale_utf8_suffix }}'
+ icu_locale: 'es_ES-x-icu'
+ locale_provider: 'libc'
+ template: 'template0'
+ login_user: "{{ pg_user }}"
+ register: result
+ ignore_errors: true
+
+ - assert:
+ that:
+ - result is failed
+
+ when: postgres_version_resp.stdout is version('15.0', '>=')
+
- name: Check that changing the conn_limit actually works
become_user: "{{ pg_user }}"
become: true
@@ -199,13 +319,15 @@
- name: Check that conn_limit has actually been set / updated to 200
become_user: "{{ pg_user }}"
become: true
- shell: echo "SELECT datconnlimit AS conn_limit FROM pg_database WHERE datname = '{{ db_name }}';" | psql -d postgres
+ postgresql_query:
+ login_db: postgres
+ query: "SELECT datconnlimit AS conn_limit FROM pg_database WHERE datname = '{{ db_name }}'"
register: result
- assert:
that:
- - "result.stdout_lines[-1] == '(1 row)'"
- - "'200' == '{{ result.stdout_lines[-2] | trim }}'"
+ - result.rowcount == 1
+ - result.query_result[0]['conn_limit'] == 200
- name: Cleanup test DB
become_user: "{{ pg_user }}"
@@ -215,14 +337,43 @@
state: 'absent'
login_user: "{{ pg_user }}"
-- shell: echo "select datname, pg_encoding_to_char(encoding), datcollate, datctype from pg_database where datname = '{{ db_name }}';" | psql -d postgres
+- name: Check
become_user: "{{ pg_user }}"
become: true
+ postgresql_query:
+ login_db: postgres
+ query: "select datname, pg_encoding_to_char(encoding), datcollate, datctype from pg_database where datname = '{{ db_name }}'"
register: result
- assert:
that:
- - "result.stdout_lines[-1] == '(0 rows)'"
+ - result.rowcount == 0
+
+- block:
+
+ - name: Cleanup icu test DB
+ become_user: "{{ pg_user }}"
+ become: true
+ postgresql_db:
+ name: '{{ db_name_icu }}'
+ state: 'absent'
+ login_user: "{{ pg_user }}"
+
+ - name: Check icu test DB was removed
+ become_user: "{{ pg_user }}"
+ become: true
+ postgresql_query:
+ login_db: postgres
+ query: "select datname, pg_encoding_to_char(encoding), datcollate, datctype from pg_database where datname = '{{ db_name_icu }}'"
+ register: result
+
+ - assert:
+ that:
+ - result.rowcount == 0
+
+ when: postgres_version_resp.stdout is version('15.0', '>=')
+
+
#
# Test db ownership
@@ -320,13 +471,15 @@
- name: Check that the user owns the newly created DB
become_user: "{{ pg_user }}"
become: true
- shell: echo "select pg_catalog.pg_get_userbyid(datdba) from pg_catalog.pg_database where datname = '{{ db_name }}';" | psql -d postgres
+ postgresql_query:
+ login_db: postgres
+ query: "select pg_catalog.pg_get_userbyid(datdba) from pg_catalog.pg_database where datname = '{{ db_name }}'"
register: result
- assert:
that:
- - "result.stdout_lines[-1] == '(1 row)'"
- - "'{{ pg_user }}' == '{{ result.stdout_lines[-2] | trim }}'"
+ - result.rowcount == 1
+ - result.query_result[0]['pg_get_userbyid'] == '{{ pg_user }}'
- name: Cleanup db
become_user: "{{ pg_user }}"
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_ext/tasks/postgresql_ext_initial.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_ext/tasks/postgresql_ext_initial.yml
index 3e3eeda83..8a7afa8ca 100644
--- a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_ext/tasks/postgresql_ext_initial.yml
+++ b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_ext/tasks/postgresql_ext_initial.yml
@@ -33,7 +33,7 @@
- assert:
that:
- result is changed
- - result.queries == []
+ - result.queries == ['CREATE EXTENSION "postgis"']
- name: postgresql_ext - check that extension doesn't exist after the previous step
become_user: '{{ pg_user }}'
@@ -55,13 +55,14 @@
login_db: postgres
login_port: 5432
name: postgis
+ comment: Test comment 1
ignore_errors: true
register: result
- assert:
that:
- result is changed
- - result.queries == ['CREATE EXTENSION "postgis"']
+ - result.queries == ['CREATE EXTENSION "postgis"', "COMMENT ON EXTENSION \"postgis\" IS 'Test comment 1'"]
- name: postgresql_ext - check that extension exists after the previous step
become_user: '{{ pg_user }}'
@@ -76,6 +77,127 @@
that:
- result.rowcount == 1
+- name: Check the comment
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: postgres
+ query: "SELECT obj_description((SELECT oid FROM pg_catalog.pg_extension WHERE extname = 'postgis'), 'pg_extension') AS comment"
+ register: result
+
+- name: Check the comments match
+ assert:
+ that:
+ - result.query_result[0]['comment'] == "Test comment 1"
+
+
+- name: Now after the comment was set, invoke again not pass the comment explicitly
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_ext:
+ login_db: postgres
+ login_port: 5432
+ name: postgis
+ ignore_errors: true
+ register: result
+
+- assert:
+ that:
+ - result is not changed
+ - result.queries == []
+
+- name: Check the comment didn't change
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: postgres
+ query: "SELECT obj_description((SELECT oid FROM pg_catalog.pg_extension WHERE extname = 'postgis'), 'pg_extension') AS comment"
+ register: result
+
+- name: Check the comments match
+ assert:
+ that:
+ - result.query_result[0]['comment'] == "Test comment 1"
+
+
+- name: Reset the comment in check mode
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_ext:
+ login_db: postgres
+ login_port: 5432
+ name: postgis
+ comment: ''
+ ignore_errors: true
+ register: result
+ check_mode: true
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ["COMMENT ON EXTENSION \"postgis\" IS ''"]
+
+- name: Check the comment didn't change
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: postgres
+ query: "SELECT obj_description((SELECT oid FROM pg_catalog.pg_extension WHERE extname = 'postgis'), 'pg_extension') AS comment"
+ register: result
+
+- name: Check the comments match
+ assert:
+ that:
+ - result.query_result[0]['comment'] == "Test comment 1"
+
+
+- name: Reset the comment in real mode
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_ext:
+ login_db: postgres
+ login_port: 5432
+ name: postgis
+ comment: ''
+ ignore_errors: true
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ["COMMENT ON EXTENSION \"postgis\" IS ''"]
+
+- name: Check the comment changed
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: postgres
+ query: "SELECT obj_description((SELECT oid FROM pg_catalog.pg_extension WHERE extname = 'postgis'), 'pg_extension') AS comment"
+ register: result
+
+- name: Check the comments match
+ assert:
+ that:
+ - result.query_result[0]['comment'] == None
+
+
+- name: Reset the comment again
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_ext:
+ login_db: postgres
+ login_port: 5432
+ name: postgis
+ comment: ''
+ ignore_errors: true
+ register: result
+
+- assert:
+ that:
+ - result is not changed
+ - result.queries == []
+
+
- name: postgresql_ext - drop extension postgis
become_user: '{{ pg_user }}'
become: true
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_ext/tasks/postgresql_ext_version_opt.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_ext/tasks/postgresql_ext_version_opt.yml
index 2443fe785..ca255a87a 100644
--- a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_ext/tasks/postgresql_ext_version_opt.yml
+++ b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_ext/tasks/postgresql_ext_version_opt.yml
@@ -14,15 +14,19 @@
login_db: postgres
block:
- # Preparation:
+ ######## Preparation ########
+
- name: postgresql_ext_version - create schema schema1
<<: *task_parameters
postgresql_schema:
<<: *pg_parameters
name: "{{ test_schema }}"
- # Do tests:
- - name: postgresql_ext_version - create extension of specific version, check mode
+ ######## Do tests ########
+
+ #### create extension with specific version ####
+
+ - name: postgresql_ext_version - create extension of specific version in check_mode
<<: *task_parameters
postgresql_ext:
<<: *pg_parameters
@@ -35,6 +39,9 @@
- assert:
that:
- result is changed
+ - result.queries == ["CREATE EXTENSION \"{{ test_ext }}\" WITH SCHEMA \"{{ test_schema }}\" VERSION '1.0'"]
+ - result.prev_version == ''
+ - result.version == '1.0'
- name: postgresql_ext_version - check that nothing was actually changed
<<: *task_parameters
@@ -59,6 +66,8 @@
that:
- result is changed
- result.queries == ["CREATE EXTENSION \"{{ test_ext }}\" WITH SCHEMA \"{{ test_schema }}\" VERSION '1.0'"]
+ - result.prev_version == ''
+ - result.version == '1.0'
- name: postgresql_ext_version - check
<<: *task_parameters
@@ -83,6 +92,9 @@
- assert:
that:
- result is not changed
+ - result.queries == []
+ - result.prev_version == '1.0'
+ - result.version == result.prev_version
- name: postgresql_ext_version - check
<<: *task_parameters
@@ -106,6 +118,9 @@
- assert:
that:
- result is not changed
+ - result.queries == []
+ - result.prev_version == '1.0'
+ - result.version == result.prev_version
- name: postgresql_ext_version - check
<<: *task_parameters
@@ -117,6 +132,8 @@
that:
- result.rowcount == 1
+ #### update the extension to the next version ####
+
- name: postgresql_ext_version - update the extension to the next version in check_mode
<<: *task_parameters
postgresql_ext:
@@ -130,6 +147,9 @@
- assert:
that:
- result is changed
+ - result.queries == ["ALTER EXTENSION \"{{ test_ext }}\" UPDATE TO '2.0'"]
+ - result.prev_version == '1.0'
+ - result.version == '2.0'
- name: postgresql_ext_version - check, the version must be 1.0
<<: *task_parameters
@@ -154,6 +174,8 @@
that:
- result is changed
- result.queries == ["ALTER EXTENSION \"{{ test_ext }}\" UPDATE TO '2.0'"]
+ - result.prev_version == '1.0'
+ - result.version == '2.0'
- name: postgresql_ext_version - check, the version must be 2.0
<<: *task_parameters
@@ -165,6 +187,24 @@
that:
- result.rowcount == 1
+ #### check no change if extension installed but no version specified ####
+
+ - name: postgresql_ext_version - check that version won't be changed if version won't be passed in check_mode
+ <<: *task_parameters
+ postgresql_ext:
+ <<: *pg_parameters
+ name: "{{ test_ext }}"
+ schema: "{{ test_schema }}"
+ trust_input: false
+ check_mode: true
+
+ - assert:
+ that:
+ - result is not changed
+ - result.queries == []
+ - result.prev_version == '2.0'
+ - result.version == result.prev_version
+
- name: postgresql_ext_version - check that version won't be changed if version won't be passed
<<: *task_parameters
postgresql_ext:
@@ -176,6 +216,38 @@
- assert:
that:
- result is not changed
+ - result.queries == []
+ - result.prev_version == '2.0'
+ - result.version == result.prev_version
+
+ - name: postgresql_ext_version - check, the version must be 2.0
+ <<: *task_parameters
+ postgresql_query:
+ <<: *pg_parameters
+ query: "SELECT 1 FROM pg_extension WHERE extname = '{{ test_ext }}' AND extversion = '2.0'"
+
+ - assert:
+ that:
+ - result.rowcount == 1
+
+ #### update the extension to the latest version ####
+
+ - name: postgresql_ext_version - update the extension to the latest version in check_mode
+ <<: *task_parameters
+ postgresql_ext:
+ <<: *pg_parameters
+ name: "{{ test_ext }}"
+ schema: "{{ test_schema }}"
+ version: latest
+ trust_input: false
+ check_mode: true
+
+ - assert:
+ that:
+ - result is changed
+ - result.queries == ["ALTER EXTENSION \"{{ test_ext }}\" UPDATE"]
+ - result.prev_version == '2.0'
+ - result.version == '4.0'
- name: postgresql_ext_version - check, the version must be 2.0
<<: *task_parameters
@@ -200,6 +272,8 @@
that:
- result is changed
- result.queries == ["ALTER EXTENSION \"{{ test_ext }}\" UPDATE"]
+ - result.prev_version == '2.0'
+ - result.version == '4.0'
- name: postgresql_ext_version - check
<<: *task_parameters
@@ -211,7 +285,7 @@
that:
- result.rowcount == 1
- - name: postgresql_ext_version - try to update the extension to the latest version again which always runs an update.
+ - name: postgresql_ext_version - update the extension to the latest version again in check_mode
<<: *task_parameters
postgresql_ext:
<<: *pg_parameters
@@ -219,12 +293,16 @@
schema: "{{ test_schema }}"
version: latest
trust_input: false
+ check_mode: true
- assert:
that:
- - result is changed
+ - result is not changed
+ - result.queries == []
+ - result.prev_version == '4.0'
+ - result.version == result.prev_version
- - name: postgresql_ext_version - check that version number did not change even though update ran
+ - name: postgresql_ext_version - check, the version must be 4.0 (latest)
<<: *task_parameters
postgresql_query:
<<: *pg_parameters
@@ -234,6 +312,34 @@
that:
- result.rowcount == 1
+ - name: postgresql_ext_version - update the extension to the latest version again
+ <<: *task_parameters
+ postgresql_ext:
+ <<: *pg_parameters
+ name: "{{ test_ext }}"
+ schema: "{{ test_schema }}"
+ version: latest
+ trust_input: false
+
+ - assert:
+ that:
+ - result is not changed
+ - result.queries == []
+ - result.prev_version == '4.0'
+ - result.version == result.prev_version
+
+ - name: postgresql_ext_version - check, the version must be 4.0 (latest)
+ <<: *task_parameters
+ postgresql_query:
+ <<: *pg_parameters
+ query: "SELECT 1 FROM pg_extension WHERE extname = '{{ test_ext }}' AND extversion = '4.0'"
+
+ - assert:
+ that:
+ - result.rowcount == 1
+
+ #### downgrade the extension version ####
+
- name: postgresql_ext_version - try to downgrade the extension version, must fail
<<: *task_parameters
postgresql_ext:
@@ -248,6 +354,8 @@
that:
- result.failed == true
+ #### drop extension ####
+
- name: postgresql_ext_version - drop the extension in check_mode
<<: *task_parameters
postgresql_ext:
@@ -260,6 +368,9 @@
- assert:
that:
- result is changed
+ - result.queries == ["DROP EXTENSION \"{{ test_ext }}\""]
+ - result.prev_version == '4.0'
+ - result.version == ''
- name: postgresql_ext_version - check that extension exists
<<: *task_parameters
@@ -282,6 +393,9 @@
- assert:
that:
- result is changed
+ - result.queries == ["DROP EXTENSION \"{{ test_ext }}\""]
+ - result.prev_version == '4.0'
+ - result.version == ''
- name: postgresql_ext_version - check that extension doesn't exist after the prev step
<<: *task_parameters
@@ -293,6 +407,22 @@
that:
- result.rowcount == 0
+ - name: postgresql_ext_version - try to drop the non-existent extension again in check_mode
+ <<: *task_parameters
+ postgresql_ext:
+ <<: *pg_parameters
+ name: "{{ test_ext }}"
+ state: absent
+ trust_input: false
+ check_mode: true
+
+ - assert:
+ that:
+ - result is not changed
+ - result.queries == []
+ - result.prev_version == ''
+ - result.version == result.prev_version
+
- name: postgresql_ext_version - try to drop the non-existent extension again
<<: *task_parameters
postgresql_ext:
@@ -304,6 +434,26 @@
- assert:
that:
- result is not changed
+ - result.queries == []
+ - result.prev_version == ''
+ - result.version == result.prev_version
+
+ #### create extension without specify version ####
+
+ - name: postgresql_ext_version - create the extension without passing version in check_mode
+ <<: *task_parameters
+ postgresql_ext:
+ <<: *pg_parameters
+ name: "{{ test_ext }}"
+ trust_input: false
+ check_mode: true
+
+ - assert:
+ that:
+ - result is changed
+ - result.queries == ["CREATE EXTENSION \"{{ test_ext }}\""]
+ - result.prev_version == ''
+ - result.version == '4.0'
- name: postgresql_ext_version - create the extension without passing version
<<: *task_parameters
@@ -316,6 +466,8 @@
that:
- result is changed
- result.queries == ["CREATE EXTENSION \"{{ test_ext }}\""]
+ - result.prev_version == ''
+ - result.version == '4.0'
- name: postgresql_ext_version - check
<<: *task_parameters
@@ -327,6 +479,37 @@
that:
- result.rowcount == 1
+ - name: postgresql_ext_version - create the extension without passing version again in check_mode
+ <<: *task_parameters
+ postgresql_ext:
+ <<: *pg_parameters
+ name: "{{ test_ext }}"
+ trust_input: false
+ check_mode: true
+
+ - assert:
+ that:
+ - result is not changed
+ - result.queries == []
+ - result.prev_version == '4.0'
+ - result.version == result.prev_version
+
+ - name: postgresql_ext_version - create the extension without passing version again
+ <<: *task_parameters
+ postgresql_ext:
+ <<: *pg_parameters
+ name: "{{ test_ext }}"
+ trust_input: false
+
+ - assert:
+ that:
+ - result is not changed
+ - result.queries == []
+ - result.prev_version == '4.0'
+ - result.version == result.prev_version
+
+ #### create non existent extension ####
+
- name: postgresql_ext_version - try to install non-existent extension
<<: *task_parameters
postgresql_ext:
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_info/defaults/main.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_info/defaults/main.yml
index 7a8fe2a37..af2269ffe 100644
--- a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_info/defaults/main.yml
+++ b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_info/defaults/main.yml
@@ -11,3 +11,8 @@ test_db: acme_db
test_subscription: test
test_subscription2: test2
conn_timeout: 100
+
+primary_port: 5432
+
+# The info module tests require a replica db to test subscriptions info
+replica_db_required: true
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_info/meta/main.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_info/meta/main.yml
index d72e4d23c..4ce5a5837 100644
--- a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_info/meta/main.yml
+++ b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_info/meta/main.yml
@@ -1,2 +1,2 @@
dependencies:
- - setup_postgresql_replication
+ - setup_postgresql_db
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_info/tasks/main.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_info/tasks/main.yml
index 04c7788ad..0e3d5d163 100644
--- a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_info/tasks/main.yml
+++ b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_info/tasks/main.yml
@@ -5,8 +5,10 @@
# For testing getting publication and subscription info
- import_tasks: setup_publication.yml
- when: ansible_distribution == 'Ubuntu' and ansible_distribution_major_version >= '18'
+ when:
+ - ansible_distribution_major_version != "7" # CentOS 7 with Postgres 9.2 doesn't support logical replication
# Initial CI tests of postgresql_info module
- import_tasks: postgresql_info_initial.yml
- when: ansible_distribution == 'Ubuntu' and ansible_distribution_major_version >= '18'
+ when:
+ - ansible_distribution_major_version != "7" # CentOS 7 with Postgres 9.2 doesn't support logical replication
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_info/tasks/postgresql_info_initial.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_info/tasks/postgresql_info_initial.yml
index 6dfe50542..be110ff9c 100644
--- a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_info/tasks/postgresql_info_initial.yml
+++ b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_info/tasks/postgresql_info_initial.yml
@@ -126,16 +126,24 @@
- result.tablespaces
- result.roles
+ - name: Set full server version as X.Y.Z
+ set_fact:
+ version_full: '{{ result.version.major }}.{{ result.version.minor }}.{{ result.version.patch }}'
+ when: result.version.major == 9
+
+ - name: Set full server version as X.Y
+ set_fact:
+ version_full: '{{ result.version.major }}.{{ result.version.minor }}'
+ when: result.version.major >= 10
+
- assert:
that:
- result.version.patch != {}
- - result.version.full == '{{ result.version.major }}.{{ result.version.minor }}.{{ result.version.patch }}'
when: result.version.major == 9
- assert:
that:
- - result.version.full == '{{ result.version.major }}.{{ result.version.minor }}'
- when: result.version.major >= 10
+ - result.version.full == version_full
- name: postgresql_info - check filter param passed by list
<<: *task_parameters
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_lang/aliases b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_lang/aliases
deleted file mode 100644
index a4c92ef85..000000000
--- a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_lang/aliases
+++ /dev/null
@@ -1,2 +0,0 @@
-destructive
-shippable/posix/group1
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_lang/meta/main.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_lang/meta/main.yml
deleted file mode 100644
index 4ce5a5837..000000000
--- a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_lang/meta/main.yml
+++ /dev/null
@@ -1,2 +0,0 @@
-dependencies:
- - setup_postgresql_db
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_lang/tasks/main.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_lang/tasks/main.yml
deleted file mode 100644
index 799501432..000000000
--- a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_lang/tasks/main.yml
+++ /dev/null
@@ -1,25 +0,0 @@
-####################################################################
-# WARNING: These are designed specifically for Ansible tests #
-# and should not be used as examples of how to write Ansible roles #
-####################################################################
-
-- name: Include distribution specific variables
- include_vars: "{{ lookup('first_found', params) }}"
- vars:
- params:
- files:
- - "{{ ansible_facts.distribution }}-{{ ansible_facts.distribution_major_version }}.yml"
- - default.yml
- paths:
- - vars
-
-# Only run on CentOS 7 because there is a stack trace on CentOS 8 because the module
-# is looking for the incorrect version of plpython.
-# https://gist.github.com/samdoran/8fc1b4ae834d3e66d1895d087419b8d8
-- name: Initial CI tests of postgresql_lang module
- when:
- - ansible_facts.distribution == 'CentOS'
- - ansible_facts.distribution_major_version is version ('7', '==')
- block:
- - include_tasks: postgresql_lang_initial.yml
- - include_tasks: postgresql_lang_add_owner_param.yml
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_lang/tasks/postgresql_lang_add_owner_param.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_lang/tasks/postgresql_lang_add_owner_param.yml
deleted file mode 100644
index a08ff82f2..000000000
--- a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_lang/tasks/postgresql_lang_add_owner_param.yml
+++ /dev/null
@@ -1,199 +0,0 @@
-# Copyright: (c) 2019, Andrew Klychkov (@Andersson007) <aaklychkov@mail.ru>
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-- vars:
- test_user1: alice
- test_user2: bob
- test_lang: plperl
- non_existent_role: fake_role
- task_parameters: &task_parameters
- become_user: '{{ pg_user }}'
- become: true
- register: result
- pg_parameters: &pg_parameters
- login_user: '{{ pg_user }}'
- login_db: postgres
-
- block:
- - name: Create roles for tests
- <<: *task_parameters
- postgresql_user:
- <<: *pg_parameters
- name: '{{ item }}'
- loop:
- - '{{ test_user1 }}'
- - '{{ test_user2 }}'
-
- - name: Create lang with owner in check_mode
- <<: *task_parameters
- postgresql_lang:
- <<: *pg_parameters
- name: '{{ test_lang }}'
- owner: '{{ test_user1 }}'
- trust_input: false
- check_mode: true
-
- - assert:
- that:
- - result is changed
- - result.queries == []
-
- - name: Check that nothing was actually changed
- <<: *task_parameters
- postgresql_query:
- <<: *pg_parameters
- query: >
- SELECT r.rolname FROM pg_language l
- JOIN pg_roles r ON l.lanowner = r.oid
- WHERE l.lanname = '{{ test_lang }}'
- AND r.rolname = '{{ test_user1 }}'
-
- - assert:
- that:
- - result.rowcount == 0
-
- - name: Create lang with owner
- <<: *task_parameters
- postgresql_lang:
- <<: *pg_parameters
- name: '{{ test_lang }}'
- owner: '{{ test_user1 }}'
- trust_input: false
-
- - assert:
- that:
- - result is changed
- - result.queries == ['CREATE LANGUAGE "{{ test_lang }}"', 'ALTER LANGUAGE "{{ test_lang }}" OWNER TO "{{ test_user1 }}"']
-
- - name: Check
- <<: *task_parameters
- postgresql_query:
- <<: *pg_parameters
- query: >
- SELECT r.rolname FROM pg_language l
- JOIN pg_roles r ON l.lanowner = r.oid
- WHERE l.lanname = '{{ test_lang }}'
- AND r.rolname = '{{ test_user1 }}'
-
- - assert:
- that:
- - result.rowcount == 1
-
- - name: Change lang owner in check_mode
- <<: *task_parameters
- postgresql_lang:
- <<: *pg_parameters
- name: '{{ test_lang }}'
- owner: '{{ test_user2 }}'
- trust_input: true
- check_mode: true
-
- - assert:
- that:
- - result is changed
- - result.queries == ['ALTER LANGUAGE "{{ test_lang }}" OWNER TO "{{ test_user2 }}"']
-
- - name: Check that nothing was actually changed
- <<: *task_parameters
- postgresql_query:
- <<: *pg_parameters
- query: >
- SELECT r.rolname FROM pg_language l
- JOIN pg_roles r ON l.lanowner = r.oid
- WHERE l.lanname = '{{ test_lang }}'
- AND r.rolname = '{{ test_user2 }}'
-
- - assert:
- that:
- - result.rowcount == 0
-
- - name: Change lang owner
- <<: *task_parameters
- postgresql_lang:
- <<: *pg_parameters
- name: '{{ test_lang }}'
- owner: '{{ test_user2 }}'
-
- - assert:
- that:
- - result is changed
- # TODO: the first elem of the returned list below
- # looks like a bug, not related with the option owner, needs to be checked
- - result.queries == ["UPDATE pg_language SET lanpltrusted = false WHERE lanname = '{{ test_lang }}'", 'ALTER LANGUAGE "{{ test_lang }}" OWNER TO "{{ test_user2 }}"']
-
- - name: Check
- <<: *task_parameters
- postgresql_query:
- <<: *pg_parameters
- query: >
- SELECT r.rolname FROM pg_language l
- JOIN pg_roles r ON l.lanowner = r.oid
- WHERE l.lanname = '{{ test_lang }}'
- AND r.rolname = '{{ test_user2 }}'
-
- - assert:
- that:
- - result.rowcount == 1
-
- - name: Try to change lang owner again to the same role
- <<: *task_parameters
- postgresql_lang:
- <<: *pg_parameters
- name: '{{ test_lang }}'
- owner: '{{ test_user2 }}'
-
- - assert:
- that:
- - result is not changed
- - result.queries == []
-
- - name: Check
- <<: *task_parameters
- postgresql_query:
- <<: *pg_parameters
- query: >
- SELECT r.rolname FROM pg_language l
- JOIN pg_roles r ON l.lanowner = r.oid
- WHERE l.lanname = '{{ test_lang }}'
- AND r.rolname = '{{ test_user2 }}'
-
- - assert:
- that:
- - result.rowcount == 1
-
- - name: Drop test lang with owner, must ignore
- <<: *task_parameters
- postgresql_lang:
- <<: *pg_parameters
- name: '{{ test_lang }}'
- state: absent
- owner: '{{ non_existent_role }}'
-
- - assert:
- that:
- - result is changed
- - result.queries == ["DROP LANGUAGE \"{{ test_lang }}\""]
-
- - name: Check
- <<: *task_parameters
- postgresql_query:
- <<: *pg_parameters
- query: >
- SELECT r.rolname FROM pg_language l
- JOIN pg_roles r ON l.lanowner = r.oid
- WHERE l.lanname = '{{ test_lang }}'
-
- - assert:
- that:
- - result.rowcount == 0
-
- # Clean up
- - name: Drop test roles
- <<: *task_parameters
- postgresql_user:
- <<: *pg_parameters
- name: '{{ item }}'
- state: absent
- loop:
- - '{{ test_user1 }}'
- - '{{ test_user2 }}'
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_lang/tasks/postgresql_lang_initial.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_lang/tasks/postgresql_lang_initial.yml
deleted file mode 100644
index 1d24778b4..000000000
--- a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_lang/tasks/postgresql_lang_initial.yml
+++ /dev/null
@@ -1,231 +0,0 @@
-# Copyright: (c) 2019, Andrew Klychkov (@Andersson007) <aaklychkov@mail.ru>
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-# Preparation for tests:
-- name: Install PostgreSQL support packages
- become: true
- action: "{{ ansible_facts.pkg_mgr }}"
- args:
- name: "{{ postgresql_lang_packages }}"
- state: present
-
-###############
-# Do main tests
-#
-
-# Create language in check_mode:
-- name: postgresql_lang - create plperl in check_mode
- become_user: "{{ pg_user }}"
- become: true
- postgresql_lang:
- db: postgres
- login_user: "{{ pg_user }}"
- name: plperl
- register: result
- ignore_errors: true
- check_mode: true
-
-- assert:
- that:
- - result is changed
- - result.queries == []
-
-- name: postgresql_lang - check that lang doesn't exist after previous step, rowcount must be 0
- become_user: "{{ pg_user }}"
- become: true
- postgresql_query:
- db: postgres
- login_user: "{{ pg_user }}"
- query: "SELECT 1 FROM pg_language WHERE lanname = 'plperl'"
- register: result
-
-- assert:
- that:
- - result.rowcount == 0
-
-# Create language:
-- name: postgresql_lang - create plperl
- become_user: "{{ pg_user }}"
- become: true
- postgresql_lang:
- db: postgres
- login_user: "{{ pg_user }}"
- name: plperl
- register: result
- ignore_errors: true
-
-- assert:
- that:
- - result is changed
- - result.queries == ['CREATE LANGUAGE "plperl"']
-
-- name: postgresql_lang - check that lang exists after previous step
- become_user: "{{ pg_user }}"
- become: true
- postgresql_query:
- db: postgres
- login_user: "{{ pg_user }}"
- query: "SELECT 1 FROM pg_language WHERE lanname = 'plperl'"
- register: result
-
-- assert:
- that:
- - result.rowcount == 1
-
-# Drop language in check_mode:
-- name: postgresql_lang - drop plperl in check_mode
- become_user: "{{ pg_user }}"
- become: true
- postgresql_lang:
- db: postgres
- login_user: "{{ pg_user }}"
- name: plperl
- state: absent
- register: result
- ignore_errors: true
- check_mode: true
-
-- assert:
- that:
- - result is changed
- - result.queries == []
-
-- name: postgresql_lang - check that lang exists after previous step, rowcount must be 1
- become_user: "{{ pg_user }}"
- become: true
- postgresql_query:
- db: postgres
- login_user: "{{ pg_user }}"
- query: "SELECT 1 FROM pg_language WHERE lanname = 'plperl'"
- register: result
-
-- assert:
- that:
- - result.rowcount == 1
-
-# Drop language:
-- name: postgresql_lang - drop plperl
- become_user: "{{ pg_user }}"
- become: true
- postgresql_lang:
- db: postgres
- login_user: "{{ pg_user }}"
- name: plperl
- state: absent
- register: result
- ignore_errors: true
-
-- assert:
- that:
- - result is changed
- - result.queries == ['DROP LANGUAGE "plperl"']
-
-- name: postgresql_lang - check that lang doesn't exist after previous step, rowcount must be 0
- become_user: "{{ pg_user }}"
- become: true
- postgresql_query:
- db: postgres
- login_user: "{{ pg_user }}"
- query: "SELECT 1 FROM pg_language WHERE lanname = 'plperl'"
- register: result
-
-- assert:
- that:
- - result.rowcount == 0
-
-# Check fail_on_drop true
-- name: postgresql_lang - drop c language to check fail_on_drop true
- become_user: "{{ pg_user }}"
- become: true
- postgresql_lang:
- db: postgres
- login_user: "{{ pg_user }}"
- name: c
- state: absent
- fail_on_drop: true
- register: result
- ignore_errors: true
-
-- assert:
- that:
- - result.failed == true
-
-# Check fail_on_drop no
-- name: postgresql_lang - drop c language to check fail_on_drop no
- become_user: "{{ pg_user }}"
- become: true
- postgresql_lang:
- db: postgres
- login_user: "{{ pg_user }}"
- name: c
- state: absent
- fail_on_drop: false
- register: result
- ignore_errors: true
-
-- assert:
- that:
- - result.failed == false
-
-# Create trusted language:
-- name: postgresql_lang - create plpythonu
- become_user: "{{ pg_user }}"
- become: true
- postgresql_lang:
- db: postgres
- login_user: "{{ pg_user }}"
- name: plpythonu
- trust: true
- force_trust: true
- register: result
- ignore_errors: true
-
-- assert:
- that:
- - result is changed
- - result.queries == ['CREATE TRUSTED LANGUAGE "plpythonu"', "UPDATE pg_language SET lanpltrusted = true WHERE lanname = 'plpythonu'"]
-
-- name: postgresql_lang - check that lang exists and it's trusted after previous step
- become_user: "{{ pg_user }}"
- become: true
- postgresql_query:
- db: postgres
- login_user: "{{ pg_user }}"
- query: "SELECT 1 FROM pg_language WHERE lanname = 'plpythonu' AND lanpltrusted = 't'"
- register: result
-
-- assert:
- that:
- - result.rowcount == 1
-
-# Drop language cascade, tests of aliases:
-- name: postgresql_lang - drop plpythonu cascade
- become_user: "{{ pg_user }}"
- become: true
- postgresql_lang:
- login_db: postgres
- login_user: "{{ pg_user }}"
- login_port: 5432
- lang: plpythonu
- state: absent
- cascade: true
- register: result
- ignore_errors: true
-
-- assert:
- that:
- - result is changed
- - result.queries == ['DROP LANGUAGE "plpythonu" CASCADE']
-
-- name: postgresql_lang - check that lang doesn't exist after previous step, rowcount must be 0
- become_user: "{{ pg_user }}"
- become: true
- postgresql_query:
- db: postgres
- login_user: "{{ pg_user }}"
- query: "SELECT 1 FROM pg_language WHERE lanname = 'plpythonu'"
- register: result
-
-- assert:
- that:
- - result.rowcount == 0
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_lang/vars/CentOS-7.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_lang/vars/CentOS-7.yml
deleted file mode 100644
index 8d4bcc7e2..000000000
--- a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_lang/vars/CentOS-7.yml
+++ /dev/null
@@ -1,3 +0,0 @@
-postgresql_lang_packages:
- - postgresql-plperl
- - postgresql-plpython
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_lang/vars/CentOS-8.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_lang/vars/CentOS-8.yml
deleted file mode 100644
index 5da004c8f..000000000
--- a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_lang/vars/CentOS-8.yml
+++ /dev/null
@@ -1,3 +0,0 @@
-postgresql_lang_packages:
- - postgresql-plperl
- - postgresql-plpython3
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_lang/vars/default.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_lang/vars/default.yml
deleted file mode 100644
index e69de29bb..000000000
--- a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_lang/vars/default.yml
+++ /dev/null
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_owner/tasks/postgresql_owner_initial.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_owner/tasks/postgresql_owner_initial.yml
index a21160282..a8e1a9173 100644
--- a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_owner/tasks/postgresql_owner_initial.yml
+++ b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_owner/tasks/postgresql_owner_initial.yml
@@ -2,9 +2,13 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
####################
-# Prepare for tests:
-# Create test roles:
+#
+# Prepare for tests
+#
+
+# Create test roles
+
- name: postgresql_owner - create test roles
become_user: '{{ pg_user }}'
become: true
@@ -17,6 +21,21 @@
- alice
- bob
+- name: postgresql_owner - create test roles superuser
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_user:
+ login_user: '{{ pg_user }}'
+ db: postgres
+ name: '{{ item }}'
+ role_attr_flags: SUPERUSER
+ ignore_errors: true
+ with_items:
+ - alice_super
+ - bob_super
+
+# Create test database
+
- name: postgresql_owner - create test database
become_user: '{{ pg_user }}'
become: true
@@ -24,13 +43,15 @@
login_user: '{{ pg_user }}'
db: acme
+# Create test table
+
- name: postgresql_owner - create test table
become_user: '{{ pg_user }}'
become: true
postgresql_query:
login_user: '{{ pg_user }}'
db: acme
- query: CREATE TABLE my_table (id int)
+ query: CREATE TABLE test_table (id int)
- name: postgresql_owner - set owner
become_user: '{{ pg_user }}'
@@ -39,9 +60,11 @@
login_user: '{{ pg_user }}'
db: acme
new_owner: bob
- obj_name: my_table
+ obj_name: test_table
obj_type: table
+# Create test sequence
+
- name: postgresql_owner - create test sequence
become_user: '{{ pg_user }}'
become: true
@@ -50,6 +73,8 @@
db: acme
query: CREATE SEQUENCE test_seq
+# Create test function
+
- name: postgresql_owner - create test function
become_user: '{{ pg_user }}'
become: true
@@ -57,9 +82,11 @@
login_user: '{{ pg_user }}'
db: acme
query: >
- CREATE FUNCTION increment(integer) RETURNS integer AS 'select $1 + 1;'
+ CREATE FUNCTION test_function(integer) RETURNS integer AS 'select $1 + 1;'
LANGUAGE SQL IMMUTABLE RETURNS NULL ON NULL INPUT;
+# Create test schema
+
- name: postgresql_owner - create test schema
become_user: '{{ pg_user }}'
become: true
@@ -68,13 +95,17 @@
db: acme
query: CREATE SCHEMA test_schema
+# Create test view
+
- name: postgresql_owner - create test view
become_user: '{{ pg_user }}'
become: true
postgresql_query:
login_user: '{{ pg_user }}'
db: acme
- query: CREATE VIEW test_view AS SELECT * FROM my_table
+ query: CREATE VIEW test_view AS SELECT * FROM test_table
+
+# Create test materialized view
- name: postgresql_owner - create test materialized view
become_user: '{{ pg_user }}'
@@ -82,9 +113,11 @@
postgresql_query:
login_user: '{{ pg_user }}'
db: acme
- query: CREATE MATERIALIZED VIEW test_mat_view AS SELECT * FROM my_table
+ query: CREATE MATERIALIZED VIEW test_mat_view AS SELECT * FROM test_table
when: postgres_version_resp.stdout is version('9.4', '>=')
+# Create test materialized tablespace
+
- name: postgresql_owner - drop dir for test tablespace
become: true
file:
@@ -119,12 +152,212 @@
owner: alice
location: '{{ test_tablespace_path }}'
+# Create test procedure
+
+- name: postgresql_owner - create test procedure
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ login_user: '{{ pg_user }}'
+ db: acme
+ query: >
+ CREATE OR REPLACE PROCEDURE test_procedure(id integer)
+ LANGUAGE SQL
+ AS $$
+ INSERT INTO test_table VALUES (id);
+ $$
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+# Create test type
+
+- name: postgresql_owner - create test type
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ login_user: '{{ pg_user }}'
+ db: acme
+ query: CREATE TYPE test_type AS ENUM ('new', 'open', 'closed')
+
+# Create test aggregate
+
+- name: postgresql_owner - create test aggregate
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ login_user: '{{ pg_user }}'
+ db: acme
+ query: >
+ CREATE AGGREGATE test_aggregate (float8)
+ (
+ sfunc = float8_accum,
+ stype = float8[],
+ finalfunc = float8_avg,
+ initcond = '{0,0,0}'
+ )
+
+# Create test routine
+
+- name: postgresql_owner - create test routine
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ login_user: '{{ pg_user }}'
+ db: acme
+ query: >
+ CREATE FUNCTION test_routine(integer) RETURNS integer AS 'select $1 + 1;'
+ LANGUAGE SQL IMMUTABLE RETURNS NULL ON NULL INPUT
+
+# No need to create test language as 'plpgsql' is present by default
+
+# Create test domain
+
+- name: postgresql_owner - create test domain
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ login_user: '{{ pg_user }}'
+ db: acme
+ query: >
+ CREATE DOMAIN test_domain AS TEXT
+ CHECK(
+ VALUE ~ '^\d{5}$'
+ OR VALUE ~ '^\d{5}-\d{4}$'
+ )
+
+# Create test collation
+
+- name: postgresql_owner - create test collation
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ login_user: '{{ pg_user }}'
+ db: acme
+ query: >
+ CREATE COLLATION test_collation (locale = 'en_US.utf8')
+
+# No need to create test conversion as 'windows_1256_to_utf8' is present by default
+
+# No need to create test test search configuration as 'simple' is present by default
+
+# No need to create test test search dict as 'simple' is present by default
+
+# Create test foreign data wrapper
+
+- name: postgresql_owner - create test foreign data wrapper
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ login_user: '{{ pg_user }}'
+ db: acme
+ query: >
+ CREATE FOREIGN DATA WRAPPER test_foreign_data_wrapper
+
+# Create test server
+
+- name: postgresql_owner - create test server
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ login_user: '{{ pg_user }}'
+ db: acme
+ query: >
+ CREATE SERVER test_server FOREIGN DATA WRAPPER test_foreign_data_wrapper
+
+# Create test foreign table
+
+- name: postgresql_owner - create test foreign table
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ login_user: '{{ pg_user }}'
+ db: acme
+ query: >
+ CREATE FOREIGN TABLE test_foreign_table (id int) SERVER test_server
+
+# Create test event trigger
+
+- name: postgresql_owner - create test event trigger function
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ login_user: '{{ pg_user }}'
+ db: acme
+ query: >
+ CREATE FUNCTION test_event_trigger_function()
+ RETURNS event_trigger
+ LANGUAGE plpgsql
+ AS $$
+ BEGIN
+ PERFORM pg_is_in_recovery();
+ END;
+ $$
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- name: postgresql_owner - create test event trigger
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ login_user: '{{ pg_user }}'
+ db: acme
+ query: >
+ CREATE EVENT TRIGGER test_event_trigger ON ddl_command_start
+ EXECUTE FUNCTION test_event_trigger_function()
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+# Create test large object
+
+- name: postgresql_owner - create test large object
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ login_user: '{{ pg_user }}'
+ db: acme
+ query: >
+ SELECT lo_creat(-1);
+ register: result_large_object
+
+- name: postgresql_owner - parse test large object OID
+ set_fact:
+ test_large_object: "{{ result_large_object.query_result[0]['lo_creat'] }}"
+
+# Create test publication
+
+- name: postgresql_owner - create test publication
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ login_user: '{{ pg_user }}'
+ db: acme
+ query: >
+ CREATE PUBLICATION test_publication FOR TABLE test_table
+
+# Create test statistics
+
+- name: postgresql_owner - create test statistics table
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ login_user: '{{ pg_user }}'
+ db: acme
+ query: >
+ CREATE TABLE test_statistics_table (a int, b int)
+
+- name: postgresql_owner - create test statistics
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ login_user: '{{ pg_user }}'
+ db: acme
+ query: >
+ CREATE STATISTICS test_statistics (dependencies) ON a, b FROM test_statistics_table
+
################
# Do main tests:
#
# check reassign_owned_by param
#
+
# try to reassign ownership to non existent user:
- name: postgresql_owner - reassign_owned_by to non existent user
become_user: '{{ pg_user }}'
@@ -179,7 +412,7 @@
db: acme
login_user: '{{ pg_user }}'
query: >
- SELECT 1 FROM pg_tables WHERE tablename = 'my_table'
+ SELECT 1 FROM pg_tables WHERE tablename = 'test_table'
AND tableowner = 'alice'
ignore_errors: true
register: result
@@ -210,7 +443,7 @@
postgresql_query:
db: acme
login_user: '{{ pg_user }}'
- query: SELECT 1 FROM pg_tables WHERE tablename = 'my_table' AND tableowner = 'alice'
+ query: SELECT 1 FROM pg_tables WHERE tablename = 'test_table' AND tableowner = 'alice'
ignore_errors: true
register: result
@@ -260,7 +493,9 @@
#
# #############################
-# check_mode obj_type: database
+
+# Test obj_type: database
+
- name: postgresql_owner - set db owner in check_mode
become_user: '{{ pg_user }}'
become: true
@@ -358,6 +593,8 @@
that:
- result.rowcount == 1
+# Test obj_type: table
+
- name: postgresql_owner - set table owner in check_mode
become_user: '{{ pg_user }}'
become: true
@@ -365,7 +602,7 @@
login_user: '{{ pg_user }}'
db: acme
new_owner: bob
- obj_name: my_table
+ obj_name: test_table
obj_type: table
check_mode: true
register: result
@@ -373,7 +610,7 @@
- assert:
that:
- result is changed
- - result.queries == ['ALTER TABLE "my_table" OWNER TO "bob"']
+ - result.queries == ['ALTER TABLE "test_table" OWNER TO "bob"']
- name: postgresql_owner - check that nothing changed after the previous step
become_user: '{{ pg_user }}'
@@ -382,7 +619,7 @@
db: acme
login_user: '{{ pg_user }}'
query: >
- SELECT 1 FROM pg_tables WHERE tablename = 'my_table'
+ SELECT 1 FROM pg_tables WHERE tablename = 'test_table'
AND tableowner = 'bob'
ignore_errors: true
register: result
@@ -391,21 +628,21 @@
that:
- result.rowcount == 0
-- name: postgresql_owner - set db owner
+- name: postgresql_owner - set table owner
become_user: '{{ pg_user }}'
become: true
postgresql_owner:
login_user: '{{ pg_user }}'
db: acme
new_owner: bob
- obj_name: my_table
+ obj_name: test_table
obj_type: table
register: result
- assert:
that:
- result is changed
- - result.queries == ['ALTER TABLE "my_table" OWNER TO "bob"']
+ - result.queries == ['ALTER TABLE "test_table" OWNER TO "bob"']
- name: postgresql_owner - check that table owner has been changed after the previous step
become_user: '{{ pg_user }}'
@@ -414,7 +651,7 @@
db: acme
login_user: '{{ pg_user }}'
query: >
- SELECT 1 FROM pg_tables WHERE tablename = 'my_table'
+ SELECT 1 FROM pg_tables WHERE tablename = 'test_table'
AND tableowner = 'bob'
ignore_errors: true
register: result
@@ -423,14 +660,14 @@
that:
- result.rowcount == 1
-- name: postgresql_owner - set db owner again
+- name: postgresql_owner - set table owner again
become_user: '{{ pg_user }}'
become: true
postgresql_owner:
login_user: '{{ pg_user }}'
db: acme
new_owner: bob
- obj_name: my_table
+ obj_name: test_table
obj_type: table
register: result
@@ -446,7 +683,7 @@
db: acme
login_user: '{{ pg_user }}'
query: >
- SELECT 1 FROM pg_tables WHERE tablename = 'my_table'
+ SELECT 1 FROM pg_tables WHERE tablename = 'test_table'
AND tableowner = 'bob'
ignore_errors: true
register: result
@@ -455,6 +692,8 @@
that:
- result.rowcount == 1
+# Test obj_type: sequence
+
- name: postgresql_owner - set sequence owner in check_mode
become_user: '{{ pg_user }}'
become: true
@@ -489,7 +728,7 @@
that:
- result.rowcount == 0
-- name: postgresql_owner - set db owner
+- name: postgresql_owner - set sequence owner
become_user: '{{ pg_user }}'
become: true
postgresql_owner:
@@ -522,7 +761,7 @@
that:
- result.rowcount == 1
-- name: postgresql_owner - set db owner again
+- name: postgresql_owner - set sequence owner again
become_user: '{{ pg_user }}'
become: true
postgresql_owner:
@@ -555,6 +794,8 @@
that:
- result.rowcount == 1
+# Test obj_type: function
+
- name: postgresql_owner - set function owner in check_mode
become_user: '{{ pg_user }}'
become: true
@@ -562,7 +803,7 @@
login_user: '{{ pg_user }}'
db: acme
new_owner: bob
- obj_name: increment
+ obj_name: test_function
obj_type: function
check_mode: true
register: result
@@ -571,7 +812,7 @@
- assert:
that:
- result is changed
- - result.queries == ['ALTER FUNCTION increment OWNER TO "bob"']
+ - result.queries == ['ALTER FUNCTION test_function OWNER TO "bob"']
when: postgres_version_resp.stdout is version('10', '>=')
- name: postgresql_owner - check that nothing changed after the previous step
@@ -582,7 +823,7 @@
login_user: '{{ pg_user }}'
query: >
SELECT 1 FROM pg_proc AS f JOIN pg_roles AS r
- ON f.proowner = r.oid WHERE f.proname = 'increment' AND r.rolname = 'bob'
+ ON f.proowner = r.oid WHERE f.proname = 'test_function' AND r.rolname = 'bob'
ignore_errors: true
register: result
when: postgres_version_resp.stdout is version('10', '>=')
@@ -592,14 +833,14 @@
- result.rowcount == 0
when: postgres_version_resp.stdout is version('10', '>=')
-- name: postgresql_owner - set func owner
+- name: postgresql_owner - set function owner
become_user: '{{ pg_user }}'
become: true
postgresql_owner:
login_user: '{{ pg_user }}'
db: acme
new_owner: bob
- obj_name: increment
+ obj_name: test_function
obj_type: function
register: result
when: postgres_version_resp.stdout is version('10', '>=')
@@ -607,10 +848,10 @@
- assert:
that:
- result is changed
- - result.queries == ['ALTER FUNCTION increment OWNER TO "bob"']
+ - result.queries == ['ALTER FUNCTION test_function OWNER TO "bob"']
when: postgres_version_resp.stdout is version('10', '>=')
-- name: postgresql_owner - check that func owner has been changed after the previous step
+- name: postgresql_owner - check that function owner has been changed after the previous step
become_user: '{{ pg_user }}'
become: true
postgresql_query:
@@ -618,7 +859,7 @@
login_user: '{{ pg_user }}'
query: >
SELECT 1 FROM pg_proc AS f JOIN pg_roles AS r
- ON f.proowner = r.oid WHERE f.proname = 'increment' AND r.rolname = 'bob'
+ ON f.proowner = r.oid WHERE f.proname = 'test_function' AND r.rolname = 'bob'
ignore_errors: true
register: result
when: postgres_version_resp.stdout is version('10', '>=')
@@ -628,14 +869,14 @@
- result.rowcount == 1
when: postgres_version_resp.stdout is version('10', '>=')
-- name: postgresql_owner - set func owner again
+- name: postgresql_owner - set function owner again
become_user: '{{ pg_user }}'
become: true
postgresql_owner:
login_user: '{{ pg_user }}'
db: acme
new_owner: bob
- obj_name: increment
+ obj_name: test_function
obj_type: function
register: result
when: postgres_version_resp.stdout is version('10', '>=')
@@ -654,7 +895,7 @@
login_user: '{{ pg_user }}'
query: >
SELECT 1 FROM pg_proc AS f JOIN pg_roles AS r
- ON f.proowner = r.oid WHERE f.proname = 'increment' AND r.rolname = 'bob'
+ ON f.proowner = r.oid WHERE f.proname = 'test_function' AND r.rolname = 'bob'
ignore_errors: true
register: result
when: postgres_version_resp.stdout is version('10', '>=')
@@ -664,6 +905,8 @@
- result.rowcount == 1
when: postgres_version_resp.stdout is version('10', '>=')
+# Test obj_type: schema
+
- name: postgresql_owner - set schema owner in check_mode
become_user: '{{ pg_user }}'
become: true
@@ -761,6 +1004,8 @@
that:
- result.rowcount == 1
+# Test obj_type: view
+
- name: postgresql_owner - set view owner in check_mode
become_user: '{{ pg_user }}'
become: true
@@ -852,6 +1097,8 @@
that:
- result.rowcount == 1
+# Test obj_type: matview
+
- name: postgresql_owner - set matview owner in check_mode
become_user: '{{ pg_user }}'
become: true
@@ -877,7 +1124,7 @@
postgresql_query:
db: acme
login_user: '{{ pg_user }}'
- query: SELECT 1 FROM pg_matviews WHERE matviewname = 'test_view' AND matviewowner = 'bob'
+ query: SELECT 1 FROM pg_matviews WHERE matviewname = 'test_mat_view' AND matviewowner = 'bob'
ignore_errors: true
register: result
when: postgres_version_resp.stdout is version('9.4', '>=')
@@ -955,6 +1202,8 @@
- result.rowcount == 1
when: postgres_version_resp.stdout is version('9.4', '>=')
+# Test obj_type: tablespace
+
- name: postgresql_owner - set tablespace owner in check_mode
become_user: '{{ pg_user }}'
become: true
@@ -1052,9 +1301,1761 @@
that:
- result.rowcount == 1
+# Test obj_type: procedure
+
+- name: postgresql_owner - set procedure owner in check_mode
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: test_procedure
+ obj_type: procedure
+ check_mode: true
+ register: result
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ['ALTER PROCEDURE "test_procedure" OWNER TO "bob"']
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- name: postgresql_owner - check that nothing changed after the previous step
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_proc AS f JOIN pg_roles AS r
+ ON f.proowner = r.oid WHERE f.proname = 'test_procedure' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- assert:
+ that:
+ - result.rowcount == 0
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- name: postgresql_owner - set procedure owner
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: test_procedure
+ obj_type: procedure
+ register: result
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ['ALTER PROCEDURE "test_procedure" OWNER TO "bob"']
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- name: postgresql_owner - check that procedure owner has been changed after the previous step
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_proc AS f JOIN pg_roles AS r
+ ON f.proowner = r.oid WHERE f.proname = 'test_procedure' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- assert:
+ that:
+ - result.rowcount == 1
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- name: postgresql_owner - set procedure owner again
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: test_procedure
+ obj_type: procedure
+ register: result
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- assert:
+ that:
+ - result is not changed
+ - result.queries == []
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- name: postgresql_owner - check that procedure owner is bob
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_proc AS f JOIN pg_roles AS r
+ ON f.proowner = r.oid WHERE f.proname = 'test_procedure' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- assert:
+ that:
+ - result.rowcount == 1
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+# Test obj_type: type
+
+- name: postgresql_owner - set type owner in check_mode
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: test_type
+ obj_type: type
+ check_mode: true
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ['ALTER TYPE "test_type" OWNER TO "bob"']
+
+- name: postgresql_owner - check that nothing changed after the previous step
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_type AS t JOIN pg_roles AS r
+ ON t.typowner = r.oid WHERE t.typname = 'test_type' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 0
+
+- name: postgresql_owner - set type owner
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: test_type
+ obj_type: type
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ['ALTER TYPE "test_type" OWNER TO "bob"']
+
+- name: postgresql_owner - check that type owner has been changed after the previous step
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_type AS t JOIN pg_roles AS r
+ ON t.typowner = r.oid WHERE t.typname = 'test_type' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 1
+
+- name: postgresql_owner - set type owner again
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: test_type
+ obj_type: type
+ register: result
+
+- assert:
+ that:
+ - result is not changed
+ - result.queries == []
+
+- name: postgresql_owner - check that type owner is bob
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_type AS t JOIN pg_roles AS r
+ ON t.typowner = r.oid WHERE t.typname = 'test_type' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 1
+
+# Test obj_type: aggregate
+
+- name: postgresql_owner - set aggregate owner in check_mode
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: test_aggregate(float8)
+ obj_type: aggregate
+ check_mode: true
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ['ALTER AGGREGATE test_aggregate(float8) OWNER TO "bob"']
+
+- name: postgresql_owner - check that nothing changed after the previous step
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_proc AS f JOIN pg_roles AS r
+ ON f.proowner = r.oid WHERE f.proname = 'test_aggregate' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 0
+
+- name: postgresql_owner - set aggregate owner
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: test_aggregate(float8)
+ obj_type: aggregate
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ['ALTER AGGREGATE test_aggregate(float8) OWNER TO "bob"']
+
+- name: postgresql_owner - check that aggregate owner has been changed after the previous step
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_proc AS f JOIN pg_roles AS r
+ ON f.proowner = r.oid WHERE f.proname = 'test_aggregate' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 1
+
+- name: postgresql_owner - set aggregate owner again
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: test_aggregate(float8)
+ obj_type: aggregate
+ register: result
+
+- assert:
+ that:
+ - result is not changed
+ - result.queries == []
+
+- name: postgresql_owner - check that aggregate owner is bob
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_proc AS f JOIN pg_roles AS r
+ ON f.proowner = r.oid WHERE f.proname = 'test_aggregate' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 1
+
+# Test obj_type: routine
+
+- name: postgresql_owner - set routine owner in check_mode
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: test_routine
+ obj_type: routine
+ check_mode: true
+ register: result
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ['ALTER ROUTINE "test_routine" OWNER TO "bob"']
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- name: postgresql_owner - check that nothing changed after the previous step
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_proc AS f JOIN pg_roles AS r
+ ON f.proowner = r.oid WHERE f.proname = 'test_routine' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- assert:
+ that:
+ - result.rowcount == 0
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- name: postgresql_owner - set routine owner
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: test_routine
+ obj_type: routine
+ register: result
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ['ALTER ROUTINE "test_routine" OWNER TO "bob"']
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- name: postgresql_owner - check that routine owner has been changed after the previous step
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_proc AS f JOIN pg_roles AS r
+ ON f.proowner = r.oid WHERE f.proname = 'test_routine' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- assert:
+ that:
+ - result.rowcount == 1
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- name: postgresql_owner - set routine owner again
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: test_routine
+ obj_type: routine
+ register: result
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- assert:
+ that:
+ - result is not changed
+ - result.queries == []
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- name: postgresql_owner - check that routine owner is bob
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_proc AS f JOIN pg_roles AS r
+ ON f.proowner = r.oid WHERE f.proname = 'test_routine' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- assert:
+ that:
+ - result.rowcount == 1
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+# Test obj_type: language
+
+- name: postgresql_owner - set language owner in check_mode
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: plpgsql
+ obj_type: language
+ check_mode: true
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ['ALTER LANGUAGE plpgsql OWNER TO "bob"']
+
+- name: postgresql_owner - check that nothing changed after the previous step
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_language AS l JOIN pg_roles AS r
+ ON l.lanowner = r.oid WHERE l.lanname = 'plpgsql' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 0
+
+- name: postgresql_owner - set language owner
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: plpgsql
+ obj_type: language
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ['ALTER LANGUAGE plpgsql OWNER TO "bob"']
+
+- name: postgresql_owner - check that language owner has been changed after the previous step
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_language AS l JOIN pg_roles AS r
+ ON l.lanowner = r.oid WHERE l.lanname = 'plpgsql' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 1
+
+- name: postgresql_owner - set language owner again
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: plpgsql
+ obj_type: language
+ register: result
+
+- assert:
+ that:
+ - result is not changed
+ - result.queries == []
+
+- name: postgresql_owner - check that language owner is bob
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_language AS l JOIN pg_roles AS r
+ ON l.lanowner = r.oid WHERE l.lanname = 'plpgsql' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 1
+
+# Test obj_type: domain
+
+- name: postgresql_owner - set domain owner in check_mode
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: test_domain
+ obj_type: domain
+ check_mode: true
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ['ALTER DOMAIN "test_domain" OWNER TO "bob"']
+
+- name: postgresql_owner - check that nothing changed after the previous step
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_type AS t JOIN pg_roles AS r
+ ON t.typowner = r.oid WHERE t.typname = 'test_domain' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 0
+
+- name: postgresql_owner - set domain owner
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: test_domain
+ obj_type: domain
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ['ALTER DOMAIN "test_domain" OWNER TO "bob"']
+
+- name: postgresql_owner - check that domain owner has been changed after the previous step
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_type AS t JOIN pg_roles AS r
+ ON t.typowner = r.oid WHERE t.typname = 'test_domain' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 1
+
+- name: postgresql_owner - set domain owner again
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: test_domain
+ obj_type: domain
+ register: result
+
+- assert:
+ that:
+ - result is not changed
+ - result.queries == []
+
+- name: postgresql_owner - check that domain owner is bob
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_type AS t JOIN pg_roles AS r
+ ON t.typowner = r.oid WHERE t.typname = 'test_domain' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 1
+
+# Test obj_type: collation
+
+- name: postgresql_owner - set collation owner in check_mode
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: test_collation
+ obj_type: collation
+ check_mode: true
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ['ALTER COLLATION "test_collation" OWNER TO "bob"']
+
+- name: postgresql_owner - check that nothing changed after the previous step
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_collation AS c JOIN pg_roles AS r
+ ON c.collowner = r.oid WHERE c.collname = 'test_collation' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 0
+
+- name: postgresql_owner - set collation owner
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: test_collation
+ obj_type: collation
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ['ALTER COLLATION "test_collation" OWNER TO "bob"']
+
+- name: postgresql_owner - check that collation owner has been changed after the previous step
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_collation AS c JOIN pg_roles AS r
+ ON c.collowner = r.oid WHERE c.collname = 'test_collation' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 1
+
+- name: postgresql_owner - set collation owner again
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: test_collation
+ obj_type: collation
+ register: result
+
+- assert:
+ that:
+ - result is not changed
+ - result.queries == []
+
+- name: postgresql_owner - check that collation owner is bob
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_collation AS c JOIN pg_roles AS r
+ ON c.collowner = r.oid WHERE c.collname = 'test_collation' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 1
+
+# Test obj_type: conversion
+
+- name: postgresql_owner - set conversion owner in check_mode
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: windows_1256_to_utf8
+ obj_type: conversion
+ check_mode: true
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ['ALTER CONVERSION "windows_1256_to_utf8" OWNER TO "bob"']
+
+- name: postgresql_owner - check that nothing changed after the previous step
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_conversion AS c JOIN pg_roles AS r
+ ON c.conowner = r.oid WHERE c.conname = 'windows_1256_to_utf8' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 0
+
+- name: postgresql_owner - set conversion owner
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: windows_1256_to_utf8
+ obj_type: conversion
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ['ALTER CONVERSION "windows_1256_to_utf8" OWNER TO "bob"']
+
+- name: postgresql_owner - check that conversion owner has been changed after the previous step
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_conversion AS c JOIN pg_roles AS r
+ ON c.conowner = r.oid WHERE c.conname = 'windows_1256_to_utf8' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 1
+
+- name: postgresql_owner - set conversion owner again
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: windows_1256_to_utf8
+ obj_type: conversion
+ register: result
+
+- assert:
+ that:
+ - result is not changed
+ - result.queries == []
+
+- name: postgresql_owner - check that conversion owner is bob
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_conversion AS c JOIN pg_roles AS r
+ ON c.conowner = r.oid WHERE c.conname = 'windows_1256_to_utf8' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 1
+
+# Test obj_type: text_search_configuration
+
+- name: postgresql_owner - set text search configuration owner in check_mode
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: simple
+ obj_type: text_search_configuration
+ check_mode: true
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ['ALTER TEXT SEARCH CONFIGURATION "simple" OWNER TO "bob"']
+
+- name: postgresql_owner - check that nothing changed after the previous step
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_ts_config AS t JOIN pg_roles AS r
+ ON t.cfgowner = r.oid WHERE t.cfgname = 'simple' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 0
+
+- name: postgresql_owner - set text search configuration owner
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: simple
+ obj_type: text_search_configuration
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ['ALTER TEXT SEARCH CONFIGURATION "simple" OWNER TO "bob"']
+
+- name: postgresql_owner - check that text search configuration owner has been changed after the previous step
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_ts_config AS t JOIN pg_roles AS r
+ ON t.cfgowner = r.oid WHERE t.cfgname = 'simple' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 1
+
+- name: postgresql_owner - set text search configuration owner again
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: simple
+ obj_type: text_search_configuration
+ register: result
+
+- assert:
+ that:
+ - result is not changed
+ - result.queries == []
+
+- name: postgresql_owner - check that text search configuration owner is bob
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_ts_config AS t JOIN pg_roles AS r
+ ON t.cfgowner = r.oid WHERE t.cfgname = 'simple' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 1
+
+# Test obj_type: text_search_dictionary
+
+- name: postgresql_owner - set text search dict owner in check_mode
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: simple
+ obj_type: text_search_dictionary
+ check_mode: true
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ['ALTER TEXT SEARCH DICTIONARY "simple" OWNER TO "bob"']
+
+- name: postgresql_owner - check that nothing changed after the previous step
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_ts_dict AS t JOIN pg_roles AS r
+ ON t.dictowner = r.oid WHERE t.dictname = 'simple' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 0
+
+- name: postgresql_owner - set text search dict owner
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: simple
+ obj_type: text_search_dictionary
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ['ALTER TEXT SEARCH DICTIONARY "simple" OWNER TO "bob"']
+
+- name: postgresql_owner - check that text search dict owner has been changed after the previous step
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_ts_dict AS t JOIN pg_roles AS r
+ ON t.dictowner = r.oid WHERE t.dictname = 'simple' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 1
+
+- name: postgresql_owner - set text search dict owner again
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: simple
+ obj_type: text_search_dictionary
+ register: result
+
+- assert:
+ that:
+ - result is not changed
+ - result.queries == []
+
+- name: postgresql_owner - check that text search dict owner is bob
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_ts_dict AS t JOIN pg_roles AS r
+ ON t.dictowner = r.oid WHERE t.dictname = 'simple' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 1
+
+# Test obj_type: foreign_data_wrapper
+
+- name: postgresql_owner - set foreign_data_wrapper owner in check_mode
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob_super
+ obj_name: test_foreign_data_wrapper
+ obj_type: foreign_data_wrapper
+ check_mode: true
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ['ALTER FOREIGN DATA WRAPPER "test_foreign_data_wrapper" OWNER TO "bob_super"']
+
+- name: postgresql_owner - check that nothing changed after the previous step
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_foreign_data_wrapper AS f JOIN pg_roles AS r
+ ON f.fdwowner = r.oid WHERE f.fdwname = 'test_foreign_data_wrapper' AND r.rolname = 'bob_super'
+ ignore_errors: true
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 0
+
+- name: postgresql_owner - set foreign_data_wrapper owner
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob_super
+ obj_name: test_foreign_data_wrapper
+ obj_type: foreign_data_wrapper
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ['ALTER FOREIGN DATA WRAPPER "test_foreign_data_wrapper" OWNER TO "bob_super"']
+
+- name: postgresql_owner - check that foreign_data_wrapper owner has been changed after the previous step
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_foreign_data_wrapper AS f JOIN pg_roles AS r
+ ON f.fdwowner = r.oid WHERE f.fdwname = 'test_foreign_data_wrapper' AND r.rolname = 'bob_super'
+ ignore_errors: true
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 1
+
+- name: postgresql_owner - set foreign_data_wrapper owner again
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob_super
+ obj_name: test_foreign_data_wrapper
+ obj_type: foreign_data_wrapper
+ register: result
+
+- assert:
+ that:
+ - result is not changed
+ - result.queries == []
+
+- name: postgresql_owner - check that foreign_data_wrapper owner is bob_super
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_foreign_data_wrapper AS f JOIN pg_roles AS r
+ ON f.fdwowner = r.oid WHERE f.fdwname = 'test_foreign_data_wrapper' AND r.rolname = 'bob_super'
+ ignore_errors: true
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 1
+
+# Test obj_type: server
+
+- name: postgresql_owner - set server owner in check_mode
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: test_server
+ obj_type: server
+ check_mode: true
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ['ALTER SERVER "test_server" OWNER TO "bob"']
+
+- name: postgresql_owner - check that nothing changed after the previous step
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_foreign_server AS f JOIN pg_roles AS r
+ ON f.srvowner = r.oid WHERE f.srvname = 'test_server' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 0
+
+- name: postgresql_owner - set server owner
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: test_server
+ obj_type: server
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ['ALTER SERVER "test_server" OWNER TO "bob"']
+
+- name: postgresql_owner - check that server owner has been changed after the previous step
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_foreign_server AS f JOIN pg_roles AS r
+ ON f.srvowner = r.oid WHERE f.srvname = 'test_server' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 1
+
+- name: postgresql_owner - set server owner again
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: test_server
+ obj_type: server
+ register: result
+
+- assert:
+ that:
+ - result is not changed
+ - result.queries == []
+
+- name: postgresql_owner - check that server owner is bob
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_foreign_server AS f JOIN pg_roles AS r
+ ON f.srvowner = r.oid WHERE f.srvname = 'test_server' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 1
+
+# Test obj_type: foreign_table
+
+- name: postgresql_owner - set foreign_table owner in check_mode
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: test_foreign_table
+ obj_type: foreign_table
+ check_mode: true
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ['ALTER FOREIGN TABLE "test_foreign_table" OWNER TO "bob"']
+
+- name: postgresql_owner - check that nothing changed after the previous step
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_class AS c JOIN pg_roles AS r
+ ON c.relowner = r.oid WHERE c.relkind = 'f'
+ AND c.relname = 'test_foreign_table' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 0
+
+- name: postgresql_owner - set foreign_table owner
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: test_foreign_table
+ obj_type: foreign_table
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ['ALTER FOREIGN TABLE "test_foreign_table" OWNER TO "bob"']
+
+- name: postgresql_owner - check that foreign_table owner has been changed after the previous step
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_class AS c JOIN pg_roles AS r
+ ON c.relowner = r.oid WHERE c.relkind = 'f'
+ AND c.relname = 'test_foreign_table' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 1
+
+- name: postgresql_owner - set foreign_table owner again
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: test_foreign_table
+ obj_type: foreign_table
+ register: result
+
+- assert:
+ that:
+ - result is not changed
+ - result.queries == []
+
+- name: postgresql_owner - check that foreign_table owner is bob
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_class AS c JOIN pg_roles AS r
+ ON c.relowner = r.oid WHERE c.relkind = 'f'
+ AND c.relname = 'test_foreign_table' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 1
+
+# Test obj_type: event_trigger
+
+- name: postgresql_owner - set event_trigger owner in check_mode
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob_super
+ obj_name: test_event_trigger
+ obj_type: event_trigger
+ check_mode: true
+ register: result
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ['ALTER EVENT TRIGGER "test_event_trigger" OWNER TO "bob_super"']
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- name: postgresql_owner - check that nothing changed after the previous step
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_event_trigger AS e JOIN pg_roles AS r
+ ON e.evtowner = r.oid WHERE e.evtname = 'test_event_trigger' AND r.rolname = 'bob_super'
+ ignore_errors: true
+ register: result
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- assert:
+ that:
+ - result.rowcount == 0
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- name: postgresql_owner - set event_trigger owner
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob_super
+ obj_name: test_event_trigger
+ obj_type: event_trigger
+ register: result
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ['ALTER EVENT TRIGGER "test_event_trigger" OWNER TO "bob_super"']
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- name: postgresql_owner - check that event_trigger owner has been changed after the previous step
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_event_trigger AS e JOIN pg_roles AS r
+ ON e.evtowner = r.oid WHERE e.evtname = 'test_event_trigger' AND r.rolname = 'bob_super'
+ ignore_errors: true
+ register: result
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- assert:
+ that:
+ - result.rowcount == 1
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- name: postgresql_owner - set event_trigger owner again
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob_super
+ obj_name: test_event_trigger
+ obj_type: event_trigger
+ register: result
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- assert:
+ that:
+ - result is not changed
+ - result.queries == []
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- name: postgresql_owner - check that event_trigger owner is bob_super
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_event_trigger AS e JOIN pg_roles AS r
+ ON e.evtowner = r.oid WHERE e.evtname = 'test_event_trigger' AND r.rolname = 'bob_super'
+ ignore_errors: true
+ register: result
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- assert:
+ that:
+ - result.rowcount == 1
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+# Test obj_type: large_object
+
+- name: postgresql_owner - set large_object owner in check_mode
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: '{{ test_large_object }}'
+ obj_type: large_object
+ check_mode: true
+ register: result
+
+- set_fact:
+ query: 'ALTER LARGE OBJECT {{ test_large_object }} OWNER TO "bob"'
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == [query]
+
+- name: postgresql_owner - check that nothing changed after the previous step
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_largeobject_metadata AS l JOIN pg_roles AS r
+ ON l.lomowner = r.oid WHERE l.oid = '{{ test_large_object }}' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 0
+
+- name: postgresql_owner - set large_object owner
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: '{{ test_large_object }}'
+ obj_type: large_object
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == [query]
+
+- name: postgresql_owner - check that large_object owner has been changed after the previous step
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_largeobject_metadata AS l JOIN pg_roles AS r
+ ON l.lomowner = r.oid WHERE l.oid = '{{ test_large_object }}' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 1
+
+- name: postgresql_owner - set large_object owner again
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: '{{ test_large_object }}'
+ obj_type: large_object
+ register: result
+
+- assert:
+ that:
+ - result is not changed
+ - result.queries == []
+
+- name: postgresql_owner - check that large_object owner is bob
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_largeobject_metadata AS l JOIN pg_roles AS r
+ ON l.lomowner = r.oid WHERE l.oid = '{{ test_large_object }}' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 1
+
+# Test obj_type: publication
+
+- name: postgresql_owner - set publication owner in check_mode
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: test_publication
+ obj_type: publication
+ check_mode: true
+ register: result
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ['ALTER PUBLICATION "test_publication" OWNER TO "bob"']
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- name: postgresql_owner - check that nothing changed after the previous step
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_publication AS p JOIN pg_roles AS r
+ ON p.pubowner = r.oid WHERE p.pubname = 'test_publication' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- assert:
+ that:
+ - result.rowcount == 0
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- name: postgresql_owner - set publication owner
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: test_publication
+ obj_type: publication
+ register: result
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ['ALTER PUBLICATION "test_publication" OWNER TO "bob"']
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- name: postgresql_owner - check that publication owner has been changed after the previous step
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_publication AS p JOIN pg_roles AS r
+ ON p.pubowner = r.oid WHERE p.pubname = 'test_publication' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- assert:
+ that:
+ - result.rowcount == 1
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- name: postgresql_owner - set publication owner again
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: test_publication
+ obj_type: publication
+ register: result
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- assert:
+ that:
+ - result is not changed
+ - result.queries == []
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- name: postgresql_owner - check that publication owner is bob
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_publication AS p JOIN pg_roles AS r
+ ON p.pubowner = r.oid WHERE p.pubname = 'test_publication' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- assert:
+ that:
+ - result.rowcount == 1
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+# Test obj_type: statistics
+
+- name: postgresql_owner - set statistics owner in check_mode
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: test_statistics
+ obj_type: statistics
+ check_mode: true
+ register: result
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ['ALTER STATISTICS "test_statistics" OWNER TO "bob"']
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- name: postgresql_owner - check that nothing changed after the previous step
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_statistic_ext AS s JOIN pg_roles AS r
+ ON s.stxowner = r.oid WHERE s.stxname = 'test_statistics' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- assert:
+ that:
+ - result.rowcount == 0
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- name: postgresql_owner - set statistics owner
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: test_statistics
+ obj_type: statistics
+ register: result
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ['ALTER STATISTICS "test_statistics" OWNER TO "bob"']
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- name: postgresql_owner - check that statistics owner has been changed after the previous step
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_statistic_ext AS s JOIN pg_roles AS r
+ ON s.stxowner = r.oid WHERE s.stxname = 'test_statistics' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- assert:
+ that:
+ - result.rowcount == 1
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- name: postgresql_owner - set statistics owner again
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_owner:
+ login_user: '{{ pg_user }}'
+ db: acme
+ new_owner: bob
+ obj_name: test_statistics
+ obj_type: statistics
+ register: result
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- assert:
+ that:
+ - result is not changed
+ - result.queries == []
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- name: postgresql_owner - check that statistics owner is bob
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: acme
+ login_user: '{{ pg_user }}'
+ query: >
+ SELECT 1 FROM pg_statistic_ext AS s JOIN pg_roles AS r
+ ON s.stxowner = r.oid WHERE s.stxname = 'test_statistics' AND r.rolname = 'bob'
+ ignore_errors: true
+ register: result
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+- assert:
+ that:
+ - result.rowcount == 1
+ when: postgres_version_resp.stdout is version('11', '>=')
+
+# #############################
+
#
-# Crean up
+# Clean up
#
+
- name: postgresql_owner - drop test database
become_user: '{{ pg_user }}'
become: true
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_pg_hba/tasks/postgresql_pg_hba_initial.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_pg_hba/tasks/postgresql_pg_hba_initial.yml
index 2a9505a5b..01d98cd5f 100644
--- a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_pg_hba/tasks/postgresql_pg_hba_initial.yml
+++ b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_pg_hba/tasks/postgresql_pg_hba_initial.yml
@@ -11,7 +11,6 @@
netmask: 'ffff:fff0::'
method: md5
backup: 'True'
- order: sud
state: "{{item}}"
check_mode: true
with_items:
@@ -30,7 +29,6 @@
dest: /tmp/pg_hba.conf
method: "{{item.method|default('md5')}}"
netmask: "{{item.netmask|default('')}}"
- order: sud
source: "{{item.source|default('')}}"
state: absent
users: "{{item.users|default('all')}}"
@@ -51,7 +49,6 @@
dest: /tmp/pg_hba.conf
method: "{{item.method|default('md5')}}"
netmask: "{{item.netmask|default('')}}"
- order: sud
source: "{{item.source|default('')}}"
state: present
users: "{{item.users|default('all')}}"
@@ -62,7 +59,6 @@
postgresql_pg_hba:
dest: "/tmp/pg_hba.conf"
users: "+some"
- order: "sud"
state: "present"
contype: "local"
method: "cert"
@@ -76,7 +72,6 @@
postgresql_pg_hba:
dest: "/tmp/pg_hba.conf"
users: "+some"
- order: "sud"
state: "present"
contype: "{{ item.contype }}"
method: "{{ item.method }}"
@@ -100,7 +95,6 @@
dest: /tmp/pg_hba.conf
method: "{{item.method|default('md5')}}"
netmask: "{{item.netmask|default('')}}"
- order: sud
source: "{{item.source|default('')}}"
state: present
users: "{{item.users|default('all')}}"
@@ -119,7 +113,6 @@
dest: /tmp/pg_hba.conf
method: md5
netmask: 255.255.255.0
- order: sud
source: '172.21.0.0'
state: present
register: pg_hba_backup_check2
@@ -130,7 +123,6 @@
contype: host
dest: /tmp/pg_hba.conf
method: md5
- order: sud
source: '172.21.0.0/24'
state: present
register: netmask_sameas_prefix_check
@@ -146,7 +138,6 @@
dest: /tmp/pg_hba.conf
method: md5
netmask: '255.255.255.255'
- order: sud
source: all
state: present
register: pg_hba_fail_src_all_with_netmask
@@ -196,7 +187,6 @@
create: true
method: md5
address: "2001:db8::1/128"
- order: sud
state: present
comment: "comment1"
@@ -220,7 +210,6 @@
dest: /tmp/pg_hba2.conf
method: md5
address: "2001:db8::2/128"
- order: sud
state: present
comment: "comment2"
@@ -244,7 +233,6 @@
dest: /tmp/pg_hba2.conf
method: md5
address: "2001:db8::3/128"
- order: sud
state: present
comment: "comment3"
keep_comments_at_rules: true
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_ping/defaults/main.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_ping/defaults/main.yml
deleted file mode 100644
index 73eb55ae2..000000000
--- a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_ping/defaults/main.yml
+++ /dev/null
@@ -1,2 +0,0 @@
----
-db_default: postgres
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_ping/handlers/main.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_ping/handlers/main.yml
new file mode 100644
index 000000000..535dd6467
--- /dev/null
+++ b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_ping/handlers/main.yml
@@ -0,0 +1,6 @@
+- name: Drop test user
+ become: true
+ become_user: "{{ pg_user }}"
+ community.postgresql.postgresql_user:
+ name: "{{ ping_test_user }}"
+ state: absent
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_ping/tasks/main.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_ping/tasks/main.yml
index bcb18d2fe..73f3e189a 100644
--- a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_ping/tasks/main.yml
+++ b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_ping/tasks/main.yml
@@ -4,6 +4,5 @@
####################################################################
# Initial CI tests of postgresql_ping module
-- import_tasks: postgresql_ping_initial.yml
- vars:
- db_name_nonexist: fake_db
+- name: Import the original test task file
+ ansible.builtin.import_tasks: postgresql_ping_initial.yml
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_ping/tasks/postgresql_ping_initial.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_ping/tasks/postgresql_ping_initial.yml
index 218ae9fd7..be48065df 100644
--- a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_ping/tasks/postgresql_ping_initial.yml
+++ b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_ping/tasks/postgresql_ping_initial.yml
@@ -2,186 +2,198 @@
# Copyright: (c) 2019, Andrew Klychkov (@Andersson007) <aaklychkov@mail.ru>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-- name: postgresql_ping - test return values
- become_user: "{{ pg_user }}"
- become: true
- postgresql_ping:
+- name: Set parameters we use with most of tasks
+ ansible.builtin.set_fact:
+ task_parameters: &task_parameters
+ become_user: "{{ pg_user }}"
+ become: true
+ register: result
+
+
+- name: Test return values
+ <<: *task_parameters
+ ignore_errors: true
+ community.postgresql.postgresql_ping:
db: "{{ db_default }}"
login_user: "{{ pg_user }}"
- register: result
- ignore_errors: true
-- assert:
+- name: Assert return values
+ ansible.builtin.assert:
that:
- - result.is_available == true
- - result.server_version != {}
- - result.server_version.raw is search('PostgreSQL')
- - result.server_version.major != ''
- - result.server_version.minor != ''
- - result is not changed
+ - result.is_available == true
+ - result.server_version != {}
+ - result.server_version.raw is search("PostgreSQL")
+ - result.server_version.major != ""
+ - result.server_version.minor != ""
+ - result is not changed
+
+- name: Set full server version as X.Y.Z
+ set_fact:
+ version_full: '{{ result.server_version.major }}.{{ result.server_version.minor }}.{{ result.server_version.patch }}'
+ when: result.server_version.major == 9
+
+- name: Set full server version as X.Y
+ set_fact:
+ version_full: '{{ result.server_version.major }}.{{ result.server_version.minor }}'
+ when: result.server_version.major >= 10
- assert:
that:
- result.server_version.patch != {}
- - result.server_version.full == '{{ result.server_version.major }}.{{ result.server_version.minor }}.{{ result.server_version.patch }}'
when: result.server_version.major == 9
- assert:
that:
- - result.server_version.full == '{{ result.server_version.major }}.{{ result.server_version.minor }}'
- when: result.server_version.major >= 10
+ - result.server_version.full == version_full
+
-- name: postgresql_ping - check ping of non-existing database doesn't return anything
- become_user: "{{ pg_user }}"
- become: true
- postgresql_ping:
+- name: Test ping of non-existing database returns nothing
+ <<: *task_parameters
+ ignore_errors: true
+ community.postgresql.postgresql_ping:
db: "{{ db_name_nonexist }}"
login_user: "{{ pg_user }}"
- register: result
- ignore_errors: true
-- assert:
+- name: Assert that ping of non-existing database returns nothing
+ ansible.builtin.assert:
that:
- - result.is_available == false
- - result.server_version == {}
- - result is not changed
+ - result.is_available == false
+ - result.server_version == {}
+ - result is not changed
+
-- name: postgresql_ping - check ping of the database on non-existent port does not return anything
- become_user: "{{ pg_user }}"
- become: true
+- name: Test ping of the database on non-existent port returns nothing
+ <<: *task_parameters
environment:
PGPORT: 5435
ignore_errors: true
- postgresql_ping:
+ community.postgresql.postgresql_ping:
db: "{{ db_default }}"
login_user: "{{ pg_user }}"
- register: result
-- assert:
+- name: Assert that ping of the database on non-existent port returns nothing
+ ansible.builtin.assert:
that:
- - result.is_available == false
- - result.server_version == {}
- - result is not changed
+ - result.is_available == false
+ - result.server_version == {}
+ - result is not changed
+
-- name: postgresql_ping - check ping of the database by a non-existent user does not return anything
- become_user: "{{ pg_user }}"
- become: true
+- name: Test ping of the database by a non-existent user returns nothing
+ <<: *task_parameters
environment:
- PGUSER: 'test_user'
+ PGUSER: "none_existent_test_user"
ignore_errors: true
- postgresql_ping:
+ community.postgresql.postgresql_ping:
db: "{{ db_default }}"
- register: result
-- assert:
+- name: Assert that ping of the database by a non-existent user returns nothing
+ ansible.builtin.assert:
that:
- - result.is_available == false
- - result.server_version == {}
- - result is not changed
+ - result.is_available == false
+ - result.server_version == {}
+ - result is not changed
+
-- name: Creating a "test_user" in postresql
- shell:
- cmd: psql -U "{{ pg_user }}" -c "CREATE ROLE test_user WITH LOGIN PASSWORD 'TEST_PASSWORD';"
+- name: Create a {{ ping_test_user }}
+ <<: *task_parameters
+ notify: Drop test user
+ community.postgresql.postgresql_user:
+ name: "{{ ping_test_user }}"
+ role_attr_flags: LOGIN
+ password: "{{ ping_test_user_pass }}"
-- name: postgresql_ping - check ping of the database by a existent user
- become_user: "{{ pg_user }}"
- become: true
+- name: Test ping of the database by existent user
+ <<: *task_parameters
environment:
- PGUSER: 'test_user'
+ PGUSER: "{{ ping_test_user }}"
ignore_errors: true
- postgresql_ping:
+ community.postgresql.postgresql_ping:
db: "{{ db_default }}"
- login_password: "TEST_PASSWORD"
- register: result
+ login_password: "{{ ping_test_user_pass }}"
-- assert:
+- name: Assert ping of the database by existent user
+ ansible.builtin.assert:
that:
- - result.is_available == true
- - result.server_version != {}
- - result.server_version.raw is search('PostgreSQL')
- - result.server_version.major != ''
- - result.server_version.minor != ''
- - result is not changed
-
-- name: postgresql_ping - ping DB with SSL 1
- become_user: "{{ pg_user }}"
- become: true
- postgresql_ping:
- db: "{{ ssl_db }}"
- login_user: "{{ ssl_user }}"
- login_password: "{{ ssl_pass }}"
- login_host: 127.0.0.1
- login_port: 5432
- ssl_mode: require
- ca_cert: '{{ ssl_rootcert }}'
- trust_input: true
- register: result
- when:
- - ansible_os_family == 'Debian'
- - postgres_version_resp.stdout is version('9.4', '>=')
-
-- assert:
- that:
- result.is_available == true
- - result.conn_err_msg == ''
- when:
- - ansible_os_family == 'Debian'
- - postgres_version_resp.stdout is version('9.4', '>=')
-
-- name: postgresql_ping - ping DB with SSL 2
- become_user: "{{ pg_user }}"
- become: true
- postgresql_ping:
- db: "{{ ssl_db }}"
- login_user: "{{ ssl_user }}"
- login_password: "{{ ssl_pass }}"
- login_host: 127.0.0.1
- login_port: 5432
- ssl_mode: verify-full
- ca_cert: '{{ ssl_rootcert }}'
- ssl_cert: '{{ ssl_cert }}'
- ssl_key: '{{ ssl_key }}'
- trust_input: true
- register: result
- when:
- - ansible_os_family == 'Debian'
- - postgres_version_resp.stdout is version('9.4', '>=')
+ - result.server_version != {}
+ - result.server_version.raw is search("PostgreSQL")
+ - result.server_version.major != ""
+ - result.server_version.minor != ""
+ - result is not changed
-- assert:
- that:
- - result.is_available == true
- - result.conn_err_msg == ''
- when:
- - ansible_os_family == 'Debian'
- - postgres_version_resp.stdout is version('9.4', '>=')
-- name: postgresql_ping - check trust_input
- become_user: "{{ pg_user }}"
- become: true
- postgresql_ping:
+- name: Test SSL block
+ when:
+ - ansible_os_family == "Debian"
+ - postgres_version_resp.stdout is version("9.4", ">=")
+ block:
+
+ - name: Test ping DB with SSL 1
+ <<: *task_parameters
+ community.postgresql.postgresql_ping:
+ db: "{{ ssl_db }}"
+ login_user: "{{ ssl_user }}"
+ login_password: "{{ ssl_pass }}"
+ login_host: 127.0.0.1
+ login_port: 5432
+ ssl_mode: require
+ ca_cert: "{{ ssl_rootcert }}"
+ trust_input: true
+
+ - name: Assert ping DB with SSL 1
+ ansible.builtin.assert:
+ that:
+ - result.is_available == true
+ - result.conn_err_msg == ""
+
+
+ - name: Test ping DB with SSL 2
+ <<: *task_parameters
+ community.postgresql.postgresql_ping:
+ db: "{{ ssl_db }}"
+ login_user: "{{ ssl_user }}"
+ login_password: "{{ ssl_pass }}"
+ login_host: 127.0.0.1
+ login_port: 5432
+ ssl_mode: verify-full
+ ca_cert: "{{ ssl_rootcert }}"
+ ssl_cert: "{{ ssl_cert }}"
+ ssl_key: "{{ ssl_key }}"
+ trust_input: true
+
+ - name: Assert ping DB with SSL 2
+ ansible.builtin.assert:
+ that:
+ - result.is_available == true
+ - result.conn_err_msg == ""
+
+
+- name: Test trust_input is false and input looks suspicious
+ <<: *task_parameters
+ ignore_errors: true
+ community.postgresql.postgresql_ping:
db: "{{ db_default }}"
login_user: "{{ pg_user }}"
trust_input: false
session_role: 'curious.anonymous"; SELECT * FROM information_schema.tables; --'
- register: result
- ignore_errors: true
-- assert:
+- name: Assert result when trust_input is false and input looks suspicious
+ ansible.builtin.assert:
that:
- result is failed
- - result.msg is search('is potentially dangerous')
+ - result.msg is search("is potentially dangerous")
+
# Check conn_err_msg return value
- name: Try to connect to non-existent DB
- become_user: "{{ pg_user }}"
- become: true
- postgresql_ping:
- db: blahblah
+ <<: *task_parameters
+ community.postgresql.postgresql_ping:
+ db: "{{ db_name_nonexist }}"
login_user: "{{ pg_user }}"
- register: result
-- name: Check conn_err_msg return value
- assert:
+- name: Assert connection to non-existent DB
+ ansible.builtin.assert:
that:
- result is succeeded
- - result.conn_err_msg is search("database \"blahblah\" does not exist")
+ - result.conn_err_msg is search("database \"{{ db_name_nonexist }}\" does not exist")
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_ping/vars/main.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_ping/vars/main.yml
new file mode 100644
index 000000000..8b7a34379
--- /dev/null
+++ b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_ping/vars/main.yml
@@ -0,0 +1,5 @@
+db_default: postgres
+db_name_nonexist: fake_db
+
+ping_test_user: ping_test_user
+ping_test_user_pass: ping_test_user_pass
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_privs/tasks/postgresql_privs_general.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_privs/tasks/postgresql_privs_general.yml
index 4b4621010..d83472ba1 100644
--- a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_privs/tasks/postgresql_privs_general.yml
+++ b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_privs/tasks/postgresql_privs_general.yml
@@ -73,7 +73,7 @@
# Grant rights to the public schema, since in PostgreSQL 15
# the rights to this schema are taken away from all users except the owner
-- name: GRANT ALL PRIVILEGES ON SCHEMA public TO ansible_db_user1,2,3
+- name: GRANT ALL PRIVILEGES ON SCHEMA public TO ansible_db_user2,3
community.postgresql.postgresql_privs:
db: "{{ db_name }}"
privs: ALL
@@ -96,14 +96,12 @@
obj: TABLES
privs: all
state: present
- usage_on_types: true
register: result
check_mode: true
- assert:
that:
- result is changed
- - result.queries is search('ON TYPES')
# Also covers https://github.com/ansible-collections/community.general/issues/884
- name: Set table default privs on the schema with hyphen in the name
@@ -117,13 +115,11 @@
obj: TABLES
privs: all
state: present
- usage_on_types: false
register: result
- assert:
that:
- result is changed
- - result.queries is not search('ON TYPES')
- name: Delete table default privs on the schema with hyphen in the name
postgresql_privs:
@@ -597,7 +593,7 @@
register: result
- assert:
- that: "'{{ db_user2 }}=X/{{ db_user3 }}' in '{{ result.stdout_lines[0] }}'"
+ that: result.stdout_lines[0] is search('{{ db_user2 }}=X/{{ db_user3 }}')
# Test
- name: Grant execute to all functions again
@@ -839,16 +835,16 @@
- result is changed
when: postgres_version_resp.stdout is version('11', '>=')
-#################################################
-# Test ALL_IN_SCHEMA for 'partioned tables type #
-#################################################
+###################################################
+# Test ALL_IN_SCHEMA for 'partitioned tables type #
+###################################################
# Partitioning tables is a feature introduced in Postgresql 10.
# (see https://www.postgresql.org/docs/10/ddl-partitioning.html )
# The test below check for this version
# Function ALL_IN_SCHEMA Setup
-- name: Create partioned table for test purpose
+- name: Create partitioned table for test purpose
postgresql_query:
query: CREATE TABLE public.testpt (id int not null, logdate date not null) PARTITION BY RANGE (logdate);
db: "{{ db_name }}"
@@ -958,6 +954,22 @@
- assert:
that: "'{{ db_user2 }}=X*/{{ pg_user }}' in result.query_result[0].proacl"
+# Test https://github.com/ansible-collections/community.postgresql/issues/668
+- name: Issue 688
+ become: true
+ become_user: "{{ pg_user }}"
+ register: result
+ postgresql_privs:
+ privs: ALL
+ type: default_privs
+ schema: pg_catalog
+ obj: ALL_DEFAULT
+ db: "{{ db_name }}"
+ roles: "{{ db_user2 }}"
+ login_user: "{{ pg_user }}"
+ grant_option: true
+ state: present
+
# Test
- name: Revoke grant option on pg_create_restore_point function
postgresql_privs:
@@ -1190,7 +1202,7 @@
postgresql_query:
login_user: "{{ pg_user }}"
login_db: "{{ db_name }}"
- query: SELECT typacl FROM pg_catalog.pg_type WHERE typname = 'numeric';
+ query: SELECT typacl::varchar FROM pg_catalog.pg_type WHERE typname = 'numeric';
register: typ_result
when: postgres_version_resp.stdout is version('10', '>=')
@@ -1228,7 +1240,7 @@
postgresql_query:
login_user: "{{ pg_user }}"
login_db: "{{ db_name }}"
- query: SELECT typacl FROM pg_catalog.pg_type WHERE typname = 'numeric';
+ query: SELECT typacl::varchar FROM pg_catalog.pg_type WHERE typname = 'numeric';
register: typ_result
when: postgres_version_resp.stdout is version('10', '>=')
@@ -1265,7 +1277,7 @@
postgresql_query:
login_user: "{{ pg_user }}"
login_db: "{{ db_name }}"
- query: SELECT typacl FROM pg_catalog.pg_type WHERE typname = 'numeric';
+ query: SELECT typacl::varchar FROM pg_catalog.pg_type WHERE typname = 'numeric';
register: typ_result
when: postgres_version_resp.stdout is version('10', '>=')
@@ -1303,7 +1315,7 @@
postgresql_query:
login_user: "{{ pg_user }}"
login_db: "{{ db_name }}"
- query: SELECT typacl FROM pg_catalog.pg_type WHERE typname = 'numeric';
+ query: SELECT typacl::varchar FROM pg_catalog.pg_type WHERE typname = 'numeric';
register: typ_result
when: postgres_version_resp.stdout is version('10', '>=')
@@ -1340,7 +1352,7 @@
postgresql_query:
login_user: "{{ pg_user }}"
login_db: "{{ db_name }}"
- query: SELECT typacl FROM pg_catalog.pg_type WHERE typname = 'numeric';
+ query: SELECT typacl::varchar FROM pg_catalog.pg_type WHERE typname = 'numeric';
register: typ_result
when: postgres_version_resp.stdout is version('10', '>=')
@@ -1388,7 +1400,7 @@
login_user: "{{ pg_user }}"
login_db: "{{ db_name }}"
query: >
- SELECT t.typacl FROM pg_catalog.pg_type t JOIN pg_catalog.pg_namespace n
+ SELECT t.typacl::varchar FROM pg_catalog.pg_type t JOIN pg_catalog.pg_namespace n
ON n.oid = t.typnamespace WHERE t.typname = 'compfoo' AND n.nspname = 'public';
register: typ_result
when: postgres_version_resp.stdout is version('10', '>=')
@@ -1558,7 +1570,7 @@
register: result
- assert:
that:
- - result is changed
+ - result is not changed
- name: check permissions on tables in schemas with special names
become: true
become_user: "{{ pg_user }}"
@@ -1700,6 +1712,132 @@
- result is failed
- result.msg is search('ALL_IN_SCHEMA can be used only for type')
+###########################################
+# Test for 'parameter' value of type parameter #
+###########################################
+
+- when: postgres_version_resp.stdout is version('15', '>=')
+ block:
+ #### GRANT ALTER_SYSTEM/SET - test ####
+ - name: GRANT ALTER SYSTEM ON PARAMETER primary_conninfo,synchronous_standby_names,log_destination TO db_user3
+ community.postgresql.postgresql_privs:
+ login_user: "{{ pg_user }}"
+ database: "{{ db_name }}"
+ state: present
+ privs: ALTER_SYSTEM
+ type: parameter
+ objs: primary_conninfo,synchronous_standby_names,log_destination
+ roles: "{{ db_user3 }}"
+ register: result
+
+ - assert:
+ that:
+ - result is changed
+
+ - name: GRANT SET ON PARAMETER log_destination,log_line_prefix,synchronous_standby_names TO db_user3
+ community.postgresql.postgresql_privs:
+ login_user: "{{ pg_user }}"
+ database: "{{ db_name }}"
+ state: present
+ privs: SET
+ type: parameter
+ objs: log_destination,log_line_prefix,synchronous_standby_names
+ roles: "{{ db_user3 }}"
+
+ - assert:
+ that:
+ - result is changed
+
+ #### GRANT ALTER_SYSTEM/SET - idempotence ####
+ - name: GRANT ALTER SYSTEM ON PARAMETER primary_conninfo,synchronous_standby_names,log_destination TO db_user3
+ community.postgresql.postgresql_privs:
+ login_user: "{{ pg_user }}"
+ database: "{{ db_name }}"
+ state: present
+ privs: ALTER_SYSTEM
+ type: parameter
+ objs: primary_conninfo,synchronous_standby_names,log_destination
+ roles: "{{ db_user3 }}"
+ register: result
+
+ - assert:
+ that:
+ - result is not changed
+
+ - name: GRANT SET ON PARAMETER log_destination,log_line_prefix,synchronous_standby_names TO db_user3
+ community.postgresql.postgresql_privs:
+ login_user: "{{ pg_user }}"
+ database: "{{ db_name }}"
+ state: present
+ privs: SET
+ type: parameter
+ objs: log_destination,log_line_prefix,synchronous_standby_names
+ roles: "{{ db_user3 }}"
+
+ - assert:
+ that:
+ - result is not changed
+
+ #### REVOKE ALTER_SYSTEM/SET - test ####
+ - name: REVOKE ALTER SYSTEM ON PARAMETER primary_conninfo,synchronous_standby_names,log_destination FROM db_user3
+ community.postgresql.postgresql_privs:
+ login_user: "{{ pg_user }}"
+ database: "{{ db_name }}"
+ state: absent
+ privs: ALTER_SYSTEM
+ type: parameter
+ objs: primary_conninfo,synchronous_standby_names,log_destination
+ roles: "{{ db_user3 }}"
+ register: result
+
+ - assert:
+ that:
+ - result is changed
+
+ - name: REVOKE SET ON PARAMETER log_destination,log_line_prefix,synchronous_standby_names FROM db_user3
+ community.postgresql.postgresql_privs:
+ login_user: "{{ pg_user }}"
+ database: "{{ db_name }}"
+ state: absent
+ privs: SET
+ type: parameter
+ objs: log_destination,log_line_prefix,synchronous_standby_names
+ roles: "{{ db_user3 }}"
+
+ - assert:
+ that:
+ - result is changed
+
+ #### REVOKE ALTER_SYSTEM/SET - idempotence ####
+ - name: REVOKE ALTER SYSTEM ON PARAMETER primary_conninfo,synchronous_standby_names,log_destination FROM db_user3
+ community.postgresql.postgresql_privs:
+ login_user: "{{ pg_user }}"
+ database: "{{ db_name }}"
+ state: absent
+ privs: ALTER_SYSTEM
+ type: parameter
+ objs: primary_conninfo,synchronous_standby_names,log_destination
+ roles: "{{ db_user3 }}"
+ register: result
+
+ - assert:
+ that:
+ - result is not changed
+
+ - name: REVOKE SET ON PARAMETER log_destination,log_line_prefix,synchronous_standby_names FROM db_user3
+ community.postgresql.postgresql_privs:
+ login_user: "{{ pg_user }}"
+ database: "{{ db_name }}"
+ state: absent
+ privs: SET
+ type: parameter
+ objs: log_destination,log_line_prefix,synchronous_standby_names
+ roles: "{{ db_user3 }}"
+
+ - assert:
+ that:
+ - result is not changed
+
# Cleanup
- name: Remove privs
become: true
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_privs/tasks/postgresql_privs_initial.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_privs/tasks/postgresql_privs_initial.yml
index 814bc348d..081b13773 100644
--- a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_privs/tasks/postgresql_privs_initial.yml
+++ b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_privs/tasks/postgresql_privs_initial.yml
@@ -41,35 +41,34 @@
- name: Check that the user has the requested permissions (table1)
become_user: "{{ pg_user }}"
become: true
- shell: echo "select privilege_type from information_schema.role_table_grants where grantee='{{ db_user1 }}' and table_name='test_table1';" | psql {{ db_name }}
+ postgresql_query:
+ login_db: '{{ db_name }}'
+ query: "select array_agg(privilege_type::TEXT ORDER BY privilege_type ASC) as privilege_type from information_schema.role_table_grants where grantee='{{ db_user1 }}' and table_name='test_table1'"
register: result_table1
- name: Check that the user has the requested permissions (table2)
become_user: "{{ pg_user }}"
become: true
- shell: echo "select privilege_type from information_schema.role_table_grants where grantee='{{ db_user1 }}' and table_name='test_table2';" | psql {{ db_name }}
+ postgresql_query:
+ login_db: '{{ db_name }}'
+ query: "select privilege_type from information_schema.role_table_grants where grantee='{{ db_user1 }}' and table_name='test_table2'"
register: result_table2
- name: Check that the user has the requested permissions (database)
become_user: "{{ pg_user }}"
become: true
- shell: echo "select datacl from pg_database where datname='{{ db_name }}';" | psql {{ db_name }}
+ postgresql_query:
+ login_db: '{{ db_name }}'
+ query: "select datacl from pg_database where datname='{{ db_name }}'"
register: result_database
- assert:
that:
- - "result_table1.stdout_lines[-1] == '(7 rows)'"
- - "'INSERT' in result_table1.stdout"
- - "'SELECT' in result_table1.stdout"
- - "'UPDATE' in result_table1.stdout"
- - "'DELETE' in result_table1.stdout"
- - "'TRUNCATE' in result_table1.stdout"
- - "'REFERENCES' in result_table1.stdout"
- - "'TRIGGER' in result_table1.stdout"
- - "result_table2.stdout_lines[-1] == '(1 row)'"
- - "'INSERT' == '{{ result_table2.stdout_lines[-2] | trim }}'"
- - "result_database.stdout_lines[-1] == '(1 row)'"
- - "'{{ db_user1 }}=CTc/{{ pg_user }}' in result_database.stdout_lines[-2]"
+ - result_table1.query_result[0]["privilege_type"] == ["DELETE", "INSERT", "REFERENCES", "SELECT", "TRIGGER", "TRUNCATE", "UPDATE"]
+ - result_table2.rowcount == 1
+ - result_table2.query_result[0]['privilege_type'] == 'INSERT'
+ - result_database.rowcount == 1
+ - "'{{ db_user1 }}=CTc/{{ pg_user }}' in result_database.query_result[0]['datacl']"
- name: Add another permission for the user
become_user: "{{ pg_user }}"
@@ -91,14 +90,14 @@
- name: Check that the user has the requested permissions (table2)
become_user: "{{ pg_user }}"
become: true
- shell: echo "select privilege_type from information_schema.role_table_grants where grantee='{{ db_user1 }}' and table_name='test_table2';" | psql {{ db_name }}
+ postgresql_query:
+ login_db: '{{ db_name }}'
+ query: "select array_agg(privilege_type::TEXT ORDER BY privilege_type ASC) as privilege_type from information_schema.role_table_grants where grantee='{{ db_user1 }}' and table_name='test_table2'"
register: result_table2
- assert:
that:
- - "result_table2.stdout_lines[-1] == '(2 rows)'"
- - "'INSERT' in result_table2.stdout"
- - "'SELECT' in result_table2.stdout"
+ - result_table2.query_result[0]['privilege_type'] == ['INSERT', 'SELECT']
#
# Test priv setting via postgresql_privs module
@@ -127,13 +126,15 @@
- name: Check that the user has the requested permissions (table2)
become_user: "{{ pg_user }}"
become: true
- shell: echo "select privilege_type from information_schema.role_table_grants where grantee='{{ db_user1 }}' and table_name='test_table2';" | psql {{ db_name }}
+ postgresql_query:
+ login_db: '{{ db_name }}'
+ query: "select privilege_type from information_schema.role_table_grants where grantee='{{ db_user1 }}' and table_name='test_table2'"
register: result_table2
- assert:
that:
- - "result_table2.stdout_lines[-1] == '(1 row)'"
- - "'SELECT' == '{{ result_table2.stdout_lines[-2] | trim }}'"
+ - result_table2.rowcount == 1
+ - result_table2.query_result[0]['privilege_type'] == 'SELECT'
- name: Revoke many privileges on multiple tables
become_user: "{{ pg_user }}"
@@ -156,19 +157,23 @@
- name: Check that permissions were revoked (table1)
become_user: "{{ pg_user }}"
become: true
- shell: echo "select privilege_type from information_schema.role_table_grants where grantee='{{ db_user1 }}' and table_name='test_table1';" | psql {{ db_name }}
+ postgresql_query:
+ login_db: '{{ db_name }}'
+ query: "select privilege_type from information_schema.role_table_grants where grantee='{{ db_user1 }}' and table_name='test_table1'"
register: result_table1
- name: Check that permissions were revoked (table2)
become_user: "{{ pg_user }}"
become: true
- shell: echo "select privilege_type from information_schema.role_table_grants where grantee='{{ db_user1 }}' and table_name='test_table2';" | psql {{ db_name }}
+ postgresql_query:
+ login_db: '{{ db_name }}'
+ query: "select privilege_type from information_schema.role_table_grants where grantee='{{ db_user1 }}' and table_name='test_table2'"
register: result_table2
- assert:
that:
- - "result_table1.stdout_lines[-1] == '(0 rows)'"
- - "result_table2.stdout_lines[-1] == '(0 rows)'"
+ - result_table1.rowcount == 0
+ - result_table2.rowcount == 0
- name: Revoke database privileges
become_user: "{{ pg_user }}"
@@ -186,13 +191,15 @@
- name: Check that the user has the requested permissions (database)
become_user: "{{ pg_user }}"
become: true
- shell: echo "select datacl from pg_database where datname='{{ db_name }}';" | psql {{ db_name }}
+ postgresql_query:
+ login_db: '{{ db_name }}'
+ query: "select datacl from pg_database where datname='{{ db_name }}'"
register: result_database
- assert:
that:
- - "result_database.stdout_lines[-1] == '(1 row)'"
- - "'{{ db_user1 }}' not in result_database.stdout"
+ - result_database.rowcount == 1
+ - "'{{ db_user1 }}' not in result_database.query_result[0]['datacl']"
- name: Grant database privileges
become_user: "{{ pg_user }}"
@@ -216,13 +223,15 @@
- name: Check that the user has the requested permissions (database)
become_user: "{{ pg_user }}"
become: true
- shell: echo "select datacl from pg_database where datname='{{ db_name }}';" | psql {{ db_name }}
+ postgresql_query:
+ login_db: '{{ db_name }}'
+ query: "select datacl from pg_database where datname='{{ db_name }}'"
register: result_database
- assert:
that:
- - "result_database.stdout_lines[-1] == '(1 row)'"
- - "'{{ db_user1 }}=Cc' in result_database.stdout"
+ - result_database.rowcount == 1
+ - result_database.query_result[0]['datacl'] is search("{{ db_user1 }}=Cc")
- name: Grant a single privilege on a table
become_user: "{{ pg_user }}"
@@ -239,13 +248,15 @@
- name: Check that permissions were added (table1)
become_user: "{{ pg_user }}"
become: true
- shell: echo "select privilege_type from information_schema.role_table_grants where grantee='{{ db_user1 }}' and table_name='test_table1';" | psql {{ db_name }}
+ postgresql_query:
+ login_db: '{{ db_name }}'
+ query: "select privilege_type from information_schema.role_table_grants where grantee='{{ db_user1 }}' and table_name='test_table1'"
register: result_table1
- assert:
that:
- - "result_table1.stdout_lines[-1] == '(1 row)'"
- - "'{{ result_table1.stdout_lines[-2] | trim }}' == 'INSERT'"
+ - result_table1.rowcount == 1
+ - result_table1.query_result[0]['privilege_type'] == 'INSERT'
- name: Grant many privileges on multiple tables
become_user: "{{ pg_user }}"
@@ -262,33 +273,23 @@
- name: Check that permissions were added (table1)
become_user: "{{ pg_user }}"
become: true
- shell: echo "select privilege_type from information_schema.role_table_grants where grantee='{{ db_user1 }}' and table_name='test_table1';" | psql {{ db_name }}
+ postgresql_query:
+ login_db: '{{ db_name }}'
+ query: "select array_agg(privilege_type::TEXT ORDER BY privilege_type ASC) as privilege_type from information_schema.role_table_grants where grantee='{{ db_user1 }}' and table_name='test_table1'"
register: result_table1
- name: Check that permissions were added (table2)
become_user: "{{ pg_user }}"
become: true
- shell: echo "select privilege_type from information_schema.role_table_grants where grantee='{{ db_user1 }}' and table_name='test_table2';" | psql {{ db_name }}
+ postgresql_query:
+ login_db: '{{ db_name }}'
+ query: "select array_agg(privilege_type::TEXT ORDER BY privilege_type ASC) as privilege_type from information_schema.role_table_grants where grantee='{{ db_user1 }}' and table_name='test_table2'"
register: result_table2
- assert:
that:
- - "result_table1.stdout_lines[-1] == '(7 rows)'"
- - "'INSERT' in result_table1.stdout"
- - "'SELECT' in result_table1.stdout"
- - "'UPDATE' in result_table1.stdout"
- - "'DELETE' in result_table1.stdout"
- - "'TRUNCATE' in result_table1.stdout"
- - "'REFERENCES' in result_table1.stdout"
- - "'TRIGGER' in result_table1.stdout"
- - "result_table2.stdout_lines[-1] == '(7 rows)'"
- - "'INSERT' in result_table2.stdout"
- - "'SELECT' in result_table2.stdout"
- - "'UPDATE' in result_table2.stdout"
- - "'DELETE' in result_table2.stdout"
- - "'TRUNCATE' in result_table2.stdout"
- - "'REFERENCES' in result_table2.stdout"
- - "'TRIGGER' in result_table2.stdout"
+ - result_table1.query_result[0]["privilege_type"] == ["DELETE", "INSERT", "REFERENCES", "SELECT", "TRIGGER", "TRUNCATE", "UPDATE"]
+ - result_table2.query_result[0]["privilege_type"] == ["DELETE", "INSERT", "REFERENCES", "SELECT", "TRIGGER", "TRUNCATE", "UPDATE"]
# Check passing roles with dots
# https://github.com/ansible/ansible/issues/63204
@@ -343,22 +344,144 @@
target_roles: "{{ db_user_with_dots2 }}"
trust_input: false
-# Bugfix for https://github.com/ansible-collections/community.general/issues/857
-- name: Test passing lowercase PUBLIC role
+# https://github.com/ansible-collections/community.postgresql/pull/502 - role PUBLIC
+- name: Test passing lowercase PUBLIC role - Grant CREATE ON DATABASE - Test
+ become_user: "{{ pg_user }}"
+ become: true
+ postgresql_privs:
+ db: "{{ db_name }}"
+ login_user: "{{ pg_user }}"
+ state: present
+ type: 'database'
+ privs: 'create'
+ role: 'public'
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ["GRANT CREATE ON database \"{{ db_name }}\" TO PUBLIC;"]
+
+- name: Test passing lowercase PUBLIC role - Grant CREATE ON DATABASE - Idempotence
+ become_user: "{{ pg_user }}"
+ become: true
+ postgresql_privs:
+ db: "{{ db_name }}"
+ login_user: "{{ pg_user }}"
+ state: present
+ type: 'database'
+ privs: 'create'
+ role: 'public'
+ register: result
+
+- assert:
+ that:
+ - result is not changed
+ - result.queries == ["GRANT CREATE ON database \"{{ db_name }}\" TO PUBLIC;"]
+
+- name: Test passing lowercase PUBLIC role - Revoke CREATE ON DATABASE - Test
become_user: "{{ pg_user }}"
become: true
postgresql_privs:
db: "{{ db_name }}"
login_user: "{{ pg_user }}"
+ state: absent
type: 'database'
- privs: 'connect'
+ privs: 'create'
role: 'public'
register: result
- assert:
that:
- result is changed
- - result.queries == ["GRANT CONNECT ON database \"{{ db_name }}\" TO PUBLIC;"]
+ - result.queries == ["REVOKE CREATE ON database \"{{ db_name }}\" FROM PUBLIC;"]
+
+- name: Test passing lowercase PUBLIC role - Revoke CREATE ON DATABASE - Test
+ become_user: "{{ pg_user }}"
+ become: true
+ postgresql_privs:
+ db: "{{ db_name }}"
+ login_user: "{{ pg_user }}"
+ state: absent
+ type: 'database'
+ privs: 'create'
+ role: 'public'
+ register: result
+
+- assert:
+ that:
+ - result is not changed
+ - result.queries == ["REVOKE CREATE ON database \"{{ db_name }}\" FROM PUBLIC;"]
+
+# https://github.com/ansible-collections/community.postgresql/pull/502 - role SESSION_USER
+# first revoke after grant, as the privilege is already granted
+- name: Test passing lowercase SESSION_USER role - Revoke CREATE ON DATABASE - Test
+ become_user: "{{ pg_user }}"
+ become: true
+ postgresql_privs:
+ db: "{{ db_name }}"
+ login_user: "{{ pg_user }}"
+ state: absent
+ type: 'database'
+ privs: 'create'
+ role: 'session_user'
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ["REVOKE CREATE ON database \"{{ db_name }}\" FROM SESSION_USER;"]
+
+- name: Test passing lowercase SESSION_USER role - Revoke CREATE ON DATABASE - Test
+ become_user: "{{ pg_user }}"
+ become: true
+ postgresql_privs:
+ db: "{{ db_name }}"
+ login_user: "{{ pg_user }}"
+ state: absent
+ type: 'database'
+ privs: 'create'
+ role: 'session_user'
+ register: result
+
+- assert:
+ that:
+ - result is not changed
+ - result.queries == ["REVOKE CREATE ON database \"{{ db_name }}\" FROM SESSION_USER;"]
+
+- name: Test passing lowercase SESSION_USER role - Grant CREATE ON DATABASE - Test
+ become_user: "{{ pg_user }}"
+ become: true
+ postgresql_privs:
+ db: "{{ db_name }}"
+ login_user: "{{ pg_user }}"
+ state: present
+ type: 'database'
+ privs: 'create'
+ role: 'session_user'
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ["GRANT CREATE ON database \"{{ db_name }}\" TO SESSION_USER;"]
+
+- name: Test passing lowercase SESSION_USER role - Grant CREATE ON DATABASE - Idempotence
+ become_user: "{{ pg_user }}"
+ become: true
+ postgresql_privs:
+ db: "{{ db_name }}"
+ login_user: "{{ pg_user }}"
+ state: present
+ type: 'database'
+ privs: 'create'
+ role: 'session_user'
+ register: result
+
+- assert:
+ that:
+ - result is not changed
+ - result.queries == ["GRANT CREATE ON database \"{{ db_name }}\" TO SESSION_USER;"]
#
# Cleanup
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_privs/tasks/test_target_role.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_privs/tasks/test_target_role.yml
index 42ece0bad..bf8c76744 100644
--- a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_privs/tasks/test_target_role.yml
+++ b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_privs/tasks/test_target_role.yml
@@ -55,7 +55,7 @@
register: result
- assert:
- that: "'{{ db_user2 }}=r/{{ db_user1 }}' in '{{ result.stdout_lines[0] }}'"
+ that: result.stdout_lines[0] is search('{{ db_user2 }}=r/{{ db_user1 }}')
# Test
- name: Revoke default privileges for new table objects
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_publication/tasks/postgresql_publication_initial.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_publication/tasks/postgresql_publication_initial.yml
index 584a4848b..ac7563c2d 100644
--- a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_publication/tasks/postgresql_publication_initial.yml
+++ b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_publication/tasks/postgresql_publication_initial.yml
@@ -90,20 +90,21 @@
postgresql_publication:
<<: *pg_parameters
name: '{{ test_pub }}'
+ comment: 'Made by Ansible'
trust_input: false
- assert:
that:
- result is changed
- result.exists == true
- - result.queries == ["CREATE PUBLICATION \"{{ test_pub }}\" FOR ALL TABLES"]
+ - result.queries == ["CREATE PUBLICATION \"{{ test_pub }}\" FOR ALL TABLES", "COMMENT ON PUBLICATION \"{{ test_pub }}\" IS 'Made by Ansible'"]
- result.owner == '{{ pg_user }}'
- result.alltables == true
- result.tables == []
- result.parameters.publish != {}
# Check
- - name: postgresql_publication - check that nothing has been changed
+ - name: postgresql_publication - check the publication was created
<<: *task_parameters
postgresql_query:
<<: *pg_parameters
@@ -115,6 +116,85 @@
that:
- result.rowcount == 1
+ - name: Check the comment
+ <<: *task_parameters
+ postgresql_query:
+ <<: *pg_parameters
+ query: "SELECT obj_description(p.oid, 'pg_publication') AS comment FROM pg_publication AS p WHERE p.pubname = '{{ test_pub }}'"
+
+ - assert:
+ that:
+ - result.query_result[0]['comment'] == 'Made by Ansible'
+
+ - name: Not specify the comment explicitly
+ <<: *task_parameters
+ postgresql_publication:
+ <<: *pg_parameters
+ name: '{{ test_pub }}'
+
+ - assert:
+ that:
+ - result is not changed
+ - result.queries == []
+
+ - name: Change the comment in check mode
+ <<: *task_parameters
+ postgresql_publication:
+ <<: *pg_parameters
+ name: '{{ test_pub }}'
+ comment: 'Made by me'
+ check_mode: true
+
+ - assert:
+ that:
+ - result is changed
+ - result.queries == ["COMMENT ON PUBLICATION \"{{ test_pub }}\" IS 'Made by me'"]
+
+ - name: Check the comment didn't change
+ <<: *task_parameters
+ postgresql_query:
+ <<: *pg_parameters
+ query: "SELECT obj_description(p.oid, 'pg_publication') AS comment FROM pg_publication AS p WHERE p.pubname = '{{ test_pub }}'"
+
+ - assert:
+ that:
+ - result.query_result[0]['comment'] == 'Made by Ansible'
+
+ - name: Reset the comment in real mode
+ <<: *task_parameters
+ postgresql_publication:
+ <<: *pg_parameters
+ name: '{{ test_pub }}'
+ comment: ''
+
+ - assert:
+ that:
+ - result is changed
+ - result.queries == ["COMMENT ON PUBLICATION \"{{ test_pub }}\" IS ''"]
+
+ - name: Check the comment was reset
+ <<: *task_parameters
+ postgresql_query:
+ <<: *pg_parameters
+ query: "SELECT obj_description(p.oid, 'pg_publication') AS comment FROM pg_publication AS p WHERE p.pubname = '{{ test_pub }}'"
+
+ - assert:
+ that:
+ - result.query_result[0]['comment'] == None
+
+ - name: Reset the comment again in check mode
+ <<: *task_parameters
+ postgresql_publication:
+ <<: *pg_parameters
+ name: '{{ test_pub }}'
+ comment: ''
+ check_mode: true
+
+ - assert:
+ that:
+ - result is not changed
+ - result.queries == []
+
# Test
- name: postgresql_publication - drop publication, check_mode
<<: *task_parameters
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_query/files/test0.sql b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_query/files/test0.sql
deleted file mode 100644
index e8a5ca03d..000000000
--- a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_query/files/test0.sql
+++ /dev/null
@@ -1,6 +0,0 @@
-SELECT version();
-
-SELECT story FROM test_table
- WHERE id = %s OR story = 'Данные';
-
-
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_query/files/test1.sql b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_query/files/test1.sql
deleted file mode 100644
index 028c192d7..000000000
--- a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_query/files/test1.sql
+++ /dev/null
@@ -1,10 +0,0 @@
-CREATE FUNCTION add(integer, integer) RETURNS integer
- AS 'select $1 + $2;'
- LANGUAGE SQL
- IMMUTABLE
- RETURNS NULL ON NULL INPUT;
-
-SELECT story FROM test_table
- WHERE id = %s OR story = 'Данные';
-
-SELECT version();
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_query/tasks/postgresql_query_initial.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_query/tasks/postgresql_query_initial.yml
index 5d447d608..b784955a4 100644
--- a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_query/tasks/postgresql_query_initial.yml
+++ b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_query/tasks/postgresql_query_initial.yml
@@ -25,19 +25,6 @@
shell: psql postgres -U "{{ pg_user }}" -t -c "INSERT INTO test_table (id, story) VALUES (1, 'first'), (2, 'second'), (3, 'third');"
ignore_errors: true
- - name: Copy script files
- become: true
- copy:
- src: '{{ item }}'
- dest: '~{{ pg_user }}/{{ item }}'
- owner: '{{ pg_user }}'
- force: true
- loop:
- - test0.sql
- - test1.sql
- register: sql_file_created
- ignore_errors: true
-
- name: postgresql_query - analyze test_table
become_user: '{{ pg_user }}'
become: true
@@ -57,29 +44,6 @@
- result.query_result == {}
- result.query_all_results == [{}]
- - name: postgresql_query - run queries from SQL script
- become_user: '{{ pg_user }}'
- become: true
- postgresql_query:
- <<: *pg_parameters
- path_to_script: ~{{ pg_user }}/test0.sql
- positional_args:
- - 1
- encoding: UTF-8
- as_single_query: false
- register: result
- ignore_errors: true
- when: sql_file_created
-
- - assert:
- that:
- - result is not changed
- - result.query == "\n\nSELECT story FROM test_table\n WHERE id = 1 OR story = 'Данные'"
- - result.query_result[0].story == 'first'
- - result.rowcount == 2
- - result.statusmessage == 'SELECT 1' or result.statusmessage == 'SELECT'
- when: sql_file_created
-
- name: postgresql_query - simple select query to test_table
become_user: '{{ pg_user }}'
become: true
@@ -270,6 +234,37 @@
- result.rowcount == 0
- result.statusmessage == 'ALTER TABLE'
+ - name: postgresql_query - alter test_table using encoding
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ <<: *pg_parameters
+ query: ALTER TABLE test_table ADD COLUMN foo2 int
+ encoding: 'UTF-8'
+ register: result
+ ignore_errors: true
+
+ - assert:
+ that:
+ - result is changed
+ - result.query == "ALTER TABLE test_table ADD COLUMN foo2 int"
+ - result.rowcount == 0
+ - result.statusmessage == 'ALTER TABLE'
+
+ - name: postgresql_query - alter test_table using bad encoding
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ <<: *pg_parameters
+ query: ALTER TABLE test_table ADD COLUMN foo888 int
+ encoding: 'UTF-888-bad'
+ register: result
+ ignore_errors: true
+
+ - assert:
+ that:
+ - result.failed == true
+
- name: postgresql_query - vacuum without autocommit must fail
become_user: '{{ pg_user }}'
become: true
@@ -502,28 +497,6 @@
that:
- result is failed
- # Tests for the as_single_query option
- - name: Run queries from SQL script as a single query
- become_user: '{{ pg_user }}'
- become: true
- postgresql_query:
- <<: *pg_parameters
- path_to_script: ~{{ pg_user }}/test1.sql
- positional_args:
- - 1
- encoding: UTF-8
- as_single_query: true
- register: result
-
- - name: >
- Must pass. Not changed because we can only
- check statusmessage of the last query
- assert:
- that:
- - result is not changed
- - result.statusmessage == 'SELECT 1' or result.statusmessage == 'SELECT'
- - result.query_list[0] == "CREATE FUNCTION add(integer, integer) RETURNS integer\n AS 'select $1 + $2;'\n LANGUAGE SQL\n IMMUTABLE\n RETURNS NULL ON NULL INPUT;\n\nSELECT story FROM test_table\n WHERE id = %s OR story = 'Данные';\n\nSELECT version();\n"
-
#############################################################################
# Issue https://github.com/ansible-collections/community.postgresql/issues/45
- name: Create table containing a decimal value
@@ -602,3 +575,15 @@
- result.rowcount == 3
- result.query_result == [{"?column?": 1}]
- 'result.query_all_results == [[{"?column?": 1}], [{"?column?": 1}], [{"?column?": 1}]]'
+
+ - name: Run SHOW query
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ <<: *pg_parameters
+ query: "SHOW hba_file"
+ register: result
+
+ - assert:
+ that:
+ - result is not changed \ No newline at end of file
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_schema/tasks/postgresql_schema_initial.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_schema/tasks/postgresql_schema_initial.yml
index 58832f049..625fb45e2 100644
--- a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_schema/tasks/postgresql_schema_initial.yml
+++ b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_schema/tasks/postgresql_schema_initial.yml
@@ -314,6 +314,205 @@
- result.rowcount == 0
+# Test the comment argument
+- name: Create schema with comment
+ become_user: "{{ pg_user }}"
+ become: true
+ postgresql_schema:
+ login_user: "{{ pg_user }}"
+ database: "{{ db_name }}"
+ name: comment_schema
+ comment: Test schema 1
+ register: result
+
+- name: Check return values
+ assert:
+ that:
+ - result is changed
+ - result.queries == ['CREATE SCHEMA "comment_schema"', "COMMENT ON SCHEMA \"comment_schema\" IS 'Test schema 1'"]
+
+- name: Check the comment
+ become: true
+ become_user: "{{ pg_user }}"
+ postgresql_query:
+ db: "{{ db_name }}"
+ login_user: "{{ pg_user }}"
+ query: "SELECT obj_description((SELECT oid FROM pg_namespace WHERE nspname = 'comment_schema'), 'pg_namespace') AS comment"
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 1
+ - result.query_result[0]['comment'] == 'Test schema 1'
+
+
+- name: Set the same comment in check mode
+ become_user: "{{ pg_user }}"
+ become: true
+ postgresql_schema:
+ login_user: "{{ pg_user }}"
+ database: "{{ db_name }}"
+ name: comment_schema
+ comment: Test schema 1
+ register: result
+ check_mode: true
+
+- name: Check return values
+ assert:
+ that:
+ - result is not changed
+
+
+- name: Set another comment in check mode
+ become_user: "{{ pg_user }}"
+ become: true
+ postgresql_schema:
+ login_user: "{{ pg_user }}"
+ database: "{{ db_name }}"
+ name: comment_schema
+ comment: Test schema 2
+ register: result
+ check_mode: true
+
+- name: Check return values
+ assert:
+ that:
+ - result is changed
+
+- name: Check the comment didn't change
+ become: true
+ become_user: "{{ pg_user }}"
+ postgresql_query:
+ db: "{{ db_name }}"
+ login_user: "{{ pg_user }}"
+ query: "SELECT obj_description((SELECT oid FROM pg_namespace WHERE nspname = 'comment_schema'), 'pg_namespace') AS comment"
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 1
+ - result.query_result[0]['comment'] == 'Test schema 1'
+
+
+- name: Set another comment in real mode
+ become_user: "{{ pg_user }}"
+ become: true
+ postgresql_schema:
+ login_user: "{{ pg_user }}"
+ database: "{{ db_name }}"
+ name: comment_schema
+ comment: Test schema 2
+ register: result
+
+- name: Check return values
+ assert:
+ that:
+ - result is changed
+ - result.queries == ["COMMENT ON SCHEMA \"comment_schema\" IS 'Test schema 2'"]
+
+- name: Check the comment changed
+ become: true
+ become_user: "{{ pg_user }}"
+ postgresql_query:
+ db: "{{ db_name }}"
+ login_user: "{{ pg_user }}"
+ query: "SELECT obj_description((SELECT oid FROM pg_namespace WHERE nspname = 'comment_schema'), 'pg_namespace') AS comment"
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 1
+ - result.query_result[0]['comment'] == 'Test schema 2'
+
+
+- name: Don's specify the comment explicitly
+ become_user: "{{ pg_user }}"
+ become: true
+ postgresql_schema:
+ login_user: "{{ pg_user }}"
+ database: "{{ db_name }}"
+ name: comment_schema
+ register: result
+
+- name: Check return values
+ assert:
+ that:
+ - result is not changed
+ - result.queries == []
+
+- name: Check the comment didn't change
+ become: true
+ become_user: "{{ pg_user }}"
+ postgresql_query:
+ db: "{{ db_name }}"
+ login_user: "{{ pg_user }}"
+ query: "SELECT obj_description((SELECT oid FROM pg_namespace WHERE nspname = 'comment_schema'), 'pg_namespace') AS comment"
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 1
+ - result.query_result[0]['comment'] == 'Test schema 2'
+
+
+- name: Reset the comment
+ become_user: "{{ pg_user }}"
+ become: true
+ postgresql_schema:
+ login_user: "{{ pg_user }}"
+ database: "{{ db_name }}"
+ name: comment_schema
+ comment: ''
+ register: result
+
+- name: Check return values
+ assert:
+ that:
+ - result is changed
+ - result.queries == ["COMMENT ON SCHEMA \"comment_schema\" IS ''"]
+
+- name: Check the comment is None
+ become: true
+ become_user: "{{ pg_user }}"
+ postgresql_query:
+ db: "{{ db_name }}"
+ login_user: "{{ pg_user }}"
+ query: "SELECT obj_description((SELECT oid FROM pg_namespace WHERE nspname = 'comment_schema'), 'pg_namespace') AS comment"
+ register: result
+
+- assert:
+ that:
+ - result.rowcount == 1
+ - result.query_result[0]['comment'] == None
+
+
+- name: Reset the comment again
+ become_user: "{{ pg_user }}"
+ become: true
+ postgresql_schema:
+ login_user: "{{ pg_user }}"
+ database: "{{ db_name }}"
+ name: comment_schema
+ comment: ''
+ register: result
+
+- name: Check return values
+ assert:
+ that:
+ - result is not changed
+ - result.queries == []
+
+
+- name: Drop schema
+ become_user: "{{ pg_user }}"
+ become: true
+ postgresql_schema:
+ login_user: "{{ pg_user }}"
+ database: "{{ db_name }}"
+ name: comment_schema
+ state: absent
+
+
# Cleanup
- name: Remove user
postgresql_user:
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_set/tasks/options_coverage.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_set/tasks/options_coverage.yml
index c4598d2a9..19622d8af 100644
--- a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_set/tasks/options_coverage.yml
+++ b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_set/tasks/options_coverage.yml
@@ -28,8 +28,19 @@
wal_level: replica
log_statement: mod
track_functions: none
- shared_preload_libraries: 'pg_stat_statements, pgaudit'
+ shared_preload_libraries: 'pg_stat_statements, pgcrypto'
log_line_prefix: 'db=%d,user=%u,app=%a,client=%h '
+ unix_socket_directories: '/var/run/postgresql, /var/run/postgresql2'
+
+ - name: Ensure all unix_socket_directories directories exist
+ file:
+ state: directory
+ path: "{{ item }}"
+ owner: "{{ pg_user }}"
+ group: "{{ pg_user }}"
+ mode: '0777'
+ become: true
+ with_list: "{{ setting_map['unix_socket_directories'].split(',') | map('trim') | list }}"
# Check mode:
- name: Set settings in check mode
@@ -51,16 +62,33 @@
with_dict: '{{ setting_map }}'
# https://github.com/ansible-collections/community.postgresql/issues/78
- - name: Test param with comma containing values
+ - name: Test param with comma containing values but no quotes
<<: *task_parameters
shell: "grep shared_preload_libraries {{ pg_auto_conf }}"
register: result
- assert:
that:
- - result.stdout == "shared_preload_libraries = 'pg_stat_statements, pgaudit'"
-
- # Test for single-value params with commas and spaces in value
+ - result.stdout == "shared_preload_libraries = 'pg_stat_statements, pgcrypto'"
+
+ # https://github.com/ansible-collections/community.postgresql/pull/521
+ # unix_socket_directories is a GUC_LIST_QUOTE parameter only from PostgreSQL 14
+ - name: Test param with comma containing values and quotes
+ <<: *task_parameters
+ shell: "grep unix_socket_directories {{ pg_auto_conf }}"
+ register: result
+
+ - assert:
+ that:
+ - result.stdout == "unix_socket_directories = '/var/run/postgresql, /var/run/postgresql2'"
+ when: postgres_version_resp.stdout is version('14', '<')
+
+ - assert:
+ that:
+ - result.stdout == "unix_socket_directories = '\"/var/run/postgresql\", \"/var/run/postgresql2\"'"
+ when: postgres_version_resp.stdout is version('14', '>=')
+
+ # https://github.com/ansible-collections/community.postgresql/pull/400
- name: Test single-value param with commas and spaces in value
<<: *task_parameters
shell: "grep log_line_prefix {{ pg_auto_conf }}"
@@ -69,3 +97,25 @@
- assert:
that:
- result.stdout == "log_line_prefix = 'db=%d,user=%u,app=%a,client=%h '"
+
+ # Restart PostgreSQL:
+ - name: Restart PostgreSQL
+ become: true
+ service:
+ name: "{{ postgresql_service }}"
+ state: restarted
+
+ # Idempotence:
+ - name: Set settings in actual mode again after restart for idempotence
+ <<: *task_parameters
+ postgresql_set:
+ <<: *pg_parameters
+ name: '{{ item.key }}'
+ value: '{{ item.value }}'
+ register: test_idempotence
+ with_dict: '{{ setting_map }}'
+
+ - name: Check idempotence after restart
+ assert:
+ that: not item.changed
+ with_items: '{{ test_idempotence.results }}'
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_subscription/defaults/main.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_subscription/defaults/main.yml
index 8709694ba..ba4513248 100644
--- a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_subscription/defaults/main.yml
+++ b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_subscription/defaults/main.yml
@@ -11,3 +11,7 @@ test_subscription: test
test_role1: alice
test_role2: bob
conn_timeout: 100
+
+primary_port: 5432
+
+replica_db_required: true
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_subscription/meta/main.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_subscription/meta/main.yml
index d72e4d23c..4ce5a5837 100644
--- a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_subscription/meta/main.yml
+++ b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_subscription/meta/main.yml
@@ -1,2 +1,2 @@
dependencies:
- - setup_postgresql_replication
+ - setup_postgresql_db
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_subscription/tasks/main.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_subscription/tasks/main.yml
index e440e8c80..e9cfb4172 100644
--- a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_subscription/tasks/main.yml
+++ b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_subscription/tasks/main.yml
@@ -6,7 +6,9 @@
# Initial tests of postgresql_subscription module:
- import_tasks: setup_publication.yml
- when: ansible_distribution == 'Ubuntu' and ansible_distribution_major_version >= '18'
+ when:
+ - ansible_distribution_major_version != "7" # CentOS 7 with Postgres 9.2 doesn't support logical replication
- import_tasks: postgresql_subscription_initial.yml
- when: ansible_distribution == 'Ubuntu' and ansible_distribution_major_version >= '18'
+ when:
+ - ansible_distribution_major_version != "7" # CentOS 7 with Postgres 9.2 doesn't support logical replication
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_subscription/tasks/postgresql_subscription_initial.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_subscription/tasks/postgresql_subscription_initial.yml
index b464c3dbe..d2997b480 100644
--- a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_subscription/tasks/postgresql_subscription_initial.yml
+++ b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_subscription/tasks/postgresql_subscription_initial.yml
@@ -35,6 +35,7 @@
name: '{{ test_subscription }}'
state: present
publications: '{{ test_pub }}'
+ comment: Made by Ansible
connparams:
host: 127.0.0.1
port: '{{ primary_port }}'
@@ -47,7 +48,7 @@
that:
- result is changed
- result.name == '{{ test_subscription }}'
- - result.queries == ["CREATE SUBSCRIPTION test CONNECTION 'host=127.0.0.1 port={{ primary_port }} user={{ replication_role }} password={{ replication_pass }} dbname={{ test_db }}' PUBLICATION {{ test_pub }}"]
+ - result.queries == ["CREATE SUBSCRIPTION test CONNECTION 'host=127.0.0.1 port={{ primary_port }} user={{ replication_role }} password={{ replication_pass }} dbname={{ test_db }}' PUBLICATION {{ test_pub }}", "COMMENT ON SUBSCRIPTION \"test\" IS 'Made by Ansible'"]
- result.exists == true
- result.initial_state == {}
- result.final_state.owner == '{{ pg_user }}'
@@ -72,6 +73,116 @@
that:
- result.rowcount == 1
+ - name: Check the comment
+ <<: *task_parameters
+ postgresql_query:
+ <<: *pg_parameters
+ login_port: '{{ replica_port }}'
+ query: "SELECT obj_description(s.oid, 'pg_subscription') AS comment FROM pg_subscription AS s WHERE s.subname = 'test'"
+
+ - assert:
+ that:
+ - result.query_result[0]['comment'] == 'Made by Ansible'
+
+ - name: Not specify the comment explicitly
+ <<: *task_parameters
+ postgresql_subscription:
+ <<: *pg_parameters
+ login_port: '{{ replica_port }}'
+ name: '{{ test_subscription }}'
+
+ - assert:
+ that:
+ - result is not changed
+ - result.queries == []
+
+ - name: Check the comment is the same
+ <<: *task_parameters
+ postgresql_query:
+ <<: *pg_parameters
+ login_port: '{{ replica_port }}'
+ query: "SELECT obj_description(s.oid, 'pg_subscription') AS comment FROM pg_subscription AS s WHERE s.subname = 'test'"
+
+ - assert:
+ that:
+ - result.query_result[0]['comment'] == 'Made by Ansible'
+
+ - name: Reset the comment in check mode
+ <<: *task_parameters
+ postgresql_subscription:
+ <<: *pg_parameters
+ login_port: '{{ replica_port }}'
+ name: '{{ test_subscription }}'
+ comment: ''
+ check_mode: true
+
+ - assert:
+ that:
+ - result is changed
+ - result.queries == ["COMMENT ON SUBSCRIPTION \"test\" IS ''"]
+
+ - name: Check the comment is the same
+ <<: *task_parameters
+ postgresql_query:
+ <<: *pg_parameters
+ login_port: '{{ replica_port }}'
+ query: "SELECT obj_description(s.oid, 'pg_subscription') AS comment FROM pg_subscription AS s WHERE s.subname = 'test'"
+
+ - assert:
+ that:
+ - result.query_result[0]['comment'] == 'Made by Ansible'
+
+ - name: Reset the comment in real mode
+ <<: *task_parameters
+ postgresql_subscription:
+ <<: *pg_parameters
+ login_port: '{{ replica_port }}'
+ name: '{{ test_subscription }}'
+ comment: ''
+
+ - assert:
+ that:
+ - result is changed
+ - result.queries == ["COMMENT ON SUBSCRIPTION \"test\" IS ''"]
+
+ - name: Check the comment was reset
+ <<: *task_parameters
+ postgresql_query:
+ <<: *pg_parameters
+ login_port: '{{ replica_port }}'
+ query: "SELECT obj_description(s.oid, 'pg_subscription') AS comment FROM pg_subscription AS s WHERE s.subname = 'test'"
+
+ - assert:
+ that:
+ - result.query_result[0]['comment'] == None
+
+ - name: Reset the comment again
+ <<: *task_parameters
+ postgresql_subscription:
+ <<: *pg_parameters
+ login_port: '{{ replica_port }}'
+ name: '{{ test_subscription }}'
+ comment: ''
+
+ - assert:
+ that:
+ - result is not changed
+ - result.queries == []
+
+ - name: Reset the comment again in check mode
+ <<: *task_parameters
+ postgresql_subscription:
+ <<: *pg_parameters
+ login_port: '{{ replica_port }}'
+ name: '{{ test_subscription }}'
+ comment: ''
+ check_mode: true
+
+ - assert:
+ that:
+ - result is not changed
+ - result.queries == []
+
###################
# Test mode: absent
###################
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_tablespace/tasks/postgresql_tablespace_initial.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_tablespace/tasks/postgresql_tablespace_initial.yml
index b8e6d0b54..a89509af4 100644
--- a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_tablespace/tasks/postgresql_tablespace_initial.yml
+++ b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_tablespace/tasks/postgresql_tablespace_initial.yml
@@ -237,9 +237,205 @@
name: foo
state: absent
register: result
- ignore_errors: true
- assert:
that:
- result is not changed
- - result.msg == "Tries to drop nonexistent tablespace 'foo'"
+ - result.state == 'absent'
+ - result.queries == []
+
+
+# Testing comment argument
+- name: Create tablespace with comment
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_tablespace:
+ db: postgres
+ login_user: '{{ pg_user }}'
+ name: acme
+ location: /ssd
+ comment: Test comment 1
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ["CREATE TABLESPACE \"acme\" LOCATION '/ssd'", "COMMENT ON TABLESPACE \"acme\" IS 'Test comment 1'"]
+
+- name: Check comment
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: postgres
+ login_user: '{{ pg_user }}'
+ query: "SELECT shobj_description((SELECT oid FROM pg_catalog.pg_tablespace WHERE spcname = 'acme'), 'pg_tablespace') AS comment"
+ register: result
+
+- assert:
+ that:
+ - result.query_result[0]['comment'] == "Test comment 1"
+
+
+- name: Try to create tablespace with same comment
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_tablespace:
+ db: postgres
+ login_user: '{{ pg_user }}'
+ name: acme
+ location: /ssd
+ comment: Test comment 1
+ register: result
+
+- assert:
+ that:
+ - result is not changed
+ - result.queries == []
+
+
+- name: Now try not to pass the comment explicitly
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_tablespace:
+ db: postgres
+ login_user: '{{ pg_user }}'
+ name: acme
+ location: /ssd
+ register: result
+
+- assert:
+ that:
+ - result is not changed
+ - result.queries == []
+
+- name: Check comment didn't change
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: postgres
+ login_user: '{{ pg_user }}'
+ query: "SELECT shobj_description((SELECT oid FROM pg_catalog.pg_tablespace WHERE spcname = 'acme'), 'pg_tablespace') AS comment"
+ register: result
+
+- assert:
+ that:
+ - result.query_result[0]['comment'] == "Test comment 1"
+
+
+- name: Set another comment in check mode
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_tablespace:
+ db: postgres
+ login_user: '{{ pg_user }}'
+ name: acme
+ location: /ssd
+ comment: Test comment 2
+ register: result
+ check_mode: true
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ["COMMENT ON TABLESPACE \"acme\" IS 'Test comment 2'"]
+
+- name: Check the comment didn't change
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: postgres
+ login_user: '{{ pg_user }}'
+ query: "SELECT shobj_description((SELECT oid FROM pg_catalog.pg_tablespace WHERE spcname = 'acme'), 'pg_tablespace') AS comment"
+ register: result
+
+- assert:
+ that:
+ - result.query_result[0]['comment'] == "Test comment 1"
+
+
+- name: Set another comment in real mode
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_tablespace:
+ db: postgres
+ login_user: '{{ pg_user }}'
+ name: acme
+ location: /ssd
+ comment: Test comment 2
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ["COMMENT ON TABLESPACE \"acme\" IS 'Test comment 2'"]
+
+- name: Check the comment changed
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: postgres
+ login_user: '{{ pg_user }}'
+ query: "SELECT shobj_description((SELECT oid FROM pg_catalog.pg_tablespace WHERE spcname = 'acme'), 'pg_tablespace') AS comment"
+ register: result
+
+- assert:
+ that:
+ - result.query_result[0]['comment'] == "Test comment 2"
+
+
+- name: Reset the comment
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_tablespace:
+ db: postgres
+ login_user: '{{ pg_user }}'
+ name: acme
+ location: /ssd
+ comment: ''
+ register: result
+
+- assert:
+ that:
+ - result is changed
+ - result.queries == ["COMMENT ON TABLESPACE \"acme\" IS ''"]
+
+- name: Check the comment changed
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_query:
+ db: postgres
+ login_user: '{{ pg_user }}'
+ query: "SELECT shobj_description((SELECT oid FROM pg_catalog.pg_tablespace WHERE spcname = 'acme'), 'pg_tablespace') AS comment"
+ register: result
+
+- assert:
+ that:
+ - result.query_result[0]['comment'] == None
+
+
+- name: Reset the comment again
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_tablespace:
+ db: postgres
+ login_user: '{{ pg_user }}'
+ name: acme
+ location: /ssd
+ comment: ''
+ register: result
+
+- assert:
+ that:
+ - result is not changed
+ - result.queries == []
+
+
+# Clean up
+- name: Drop tablespace
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_tablespace:
+ db: postgres
+ login_user: '{{ pg_user }}'
+ name: acme
+ state: absent
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_user/defaults/main.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_user/defaults/main.yml
index dbcbea120..5da901258 100644
--- a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_user/defaults/main.yml
+++ b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_user/defaults/main.yml
@@ -2,3 +2,6 @@ db_name: 'ansible_db'
db_user1: 'ansible_db_user1'
db_user2: 'ansible_db_user2'
dangerous_name: 'curious.anonymous"; SELECT * FROM information_schema.tables; --'
+
+# The user module tests require an sql_ascii encoded db to test client decoding
+sql_ascii_db_required: true
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_user/tasks/main.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_user/tasks/main.yml
index 150d26efd..8d0c8b489 100644
--- a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_user/tasks/main.yml
+++ b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_user/tasks/main.yml
@@ -10,3 +10,7 @@
# General tests:
- import_tasks: postgresql_user_general.yml
when: postgres_version_resp.stdout is version('9.4', '>=')
+
+# SQL_ASCII database tests:
+- import_tasks: postgresql_user_sql_ascii_db.yml
+ when: postgres_version_resp.stdout is version('9.4', '>=')
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_user/tasks/postgresql_user_general.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_user/tasks/postgresql_user_general.yml
index cde95b0c6..73db14149 100644
--- a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_user/tasks/postgresql_user_general.yml
+++ b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_user/tasks/postgresql_user_general.yml
@@ -5,8 +5,6 @@
- vars:
test_user: hello.user.with.dots
test_user2: hello
- test_group1: group1
- test_group2: group2
test_table: test
test_comment1: 'comment1'
test_comment2: 'comment2'
@@ -66,6 +64,33 @@
that:
- result.rowcount == 1
+# Check comment argument:
+ - name: Add a comment on the user in check mode
+ <<: *task_parameters
+ postgresql_user:
+ <<: *pg_parameters
+ name: '{{ test_user }}'
+ comment: '{{ test_comment1 }}'
+ check_mode: true
+
+ - assert:
+ that:
+ - result is changed
+ - result.queries == ["COMMENT ON ROLE \"{{ test_user }}\" IS '{{ test_comment1 }}'"]
+
+ - name: check the comment didn't change
+ <<: *task_parameters
+ postgresql_query:
+ <<: *pg_parameters
+ query: >
+ SELECT pg_catalog.shobj_description(r.oid, 'pg_authid') AS comment
+ FROM pg_catalog.pg_roles r WHERE r.rolname = '{{ test_user }}'
+
+ - assert:
+ that:
+ - result.rowcount == 1
+ - result.query_result[0].comment == None
+
- name: Add a comment on the user
<<: *task_parameters
postgresql_user:
@@ -103,7 +128,33 @@
that:
- result is not changed
- - name: Try to add another comment on the user
+ - name: Try to add another comment on the user in check mode
+ <<: *task_parameters
+ postgresql_user:
+ <<: *pg_parameters
+ name: '{{ test_user }}'
+ comment: '{{ test_comment2 }}'
+ check_mode: true
+
+ - assert:
+ that:
+ - result is changed
+ - result.queries == ["COMMENT ON ROLE \"{{ test_user }}\" IS '{{ test_comment2 }}'"]
+
+ - name: check the comment didn't change
+ <<: *task_parameters
+ postgresql_query:
+ <<: *pg_parameters
+ query: >
+ SELECT pg_catalog.shobj_description(r.oid, 'pg_authid') AS comment
+ FROM pg_catalog.pg_roles r WHERE r.rolname = '{{ test_user }}'
+
+ - assert:
+ that:
+ - result.rowcount == 1
+ - result.query_result[0].comment == '{{ test_comment1 }}'
+
+ - name: Try to add another comment on the user in real mode
<<: *task_parameters
postgresql_user:
<<: *pg_parameters
@@ -128,6 +179,44 @@
- result.rowcount == 1
- result.query_result[0].comment == '{{ test_comment2 }}'
+ - name: Reset the comment
+ <<: *task_parameters
+ postgresql_user:
+ <<: *pg_parameters
+ name: '{{ test_user }}'
+ comment: ''
+
+ - assert:
+ that:
+ - result is changed
+ - result.queries == ["COMMENT ON ROLE \"{{ test_user }}\" IS ''"]
+
+ - name: check the comment
+ <<: *task_parameters
+ postgresql_query:
+ <<: *pg_parameters
+ query: >
+ SELECT pg_catalog.shobj_description(r.oid, 'pg_authid') AS comment
+ FROM pg_catalog.pg_roles r WHERE r.rolname = '{{ test_user }}'
+
+ - assert:
+ that:
+ - result.rowcount == 1
+ - result.query_result[0].comment == None
+
+ - name: Reset the comment again
+ <<: *task_parameters
+ postgresql_user:
+ <<: *pg_parameters
+ name: '{{ test_user }}'
+ comment: ''
+
+ - assert:
+ that:
+ - result is not changed
+ - result.queries == []
+# End comment argument testing
+
- name: Try to create role again in check_mode
<<: *task_parameters
check_mode: true
@@ -596,134 +685,6 @@
that:
- result is not changed
- #
- # Test groups parameter
- #
- - name: Create test group
- <<: *task_parameters
- postgresql_user:
- <<: *pg_parameters
- name: '{{ test_group2 }}'
- role_attr_flags: NOLOGIN
-
- - name: Create role test_group1 and grant test_group2 to test_group1 in check_mode
- <<: *task_parameters
- postgresql_user:
- <<: *pg_parameters
- name: '{{ test_group1 }}'
- groups: '{{ test_group2 }}'
- role_attr_flags: NOLOGIN
- check_mode: true
-
- - assert:
- that:
- - result is changed
- - result.user == '{{ test_group1 }}'
- - result.queries == ['CREATE USER "{{ test_group1 }}" NOLOGIN', 'GRANT "{{ test_group2 }}" TO "{{ test_group1 }}"']
-
- - name: check that the user doesn't exist
- <<: *task_parameters
- postgresql_query:
- <<: *pg_parameters
- query: "SELECT rolname FROM pg_roles WHERE rolname = '{{ test_group1 }}'"
-
- - assert:
- that:
- - result.rowcount == 0
-
- - name: check membership
- <<: *task_parameters
- postgresql_query:
- <<: *pg_parameters
- query: "SELECT grolist FROM pg_group WHERE groname = '{{ test_group2 }}' AND grolist != '{}'"
-
- - assert:
- that:
- - result.rowcount == 0
-
- - name: Create role test_group1 and grant test_group2 to test_group1
- <<: *task_parameters
- postgresql_user:
- <<: *pg_parameters
- name: '{{ test_group1 }}'
- groups: '{{ test_group2 }}'
- role_attr_flags: NOLOGIN
- trust_input: false
-
- - assert:
- that:
- - result is changed
- - result.user == '{{ test_group1 }}'
- - result.queries == ['CREATE USER "{{ test_group1 }}" NOLOGIN', 'GRANT "{{ test_group2 }}" TO "{{ test_group1 }}"']
-
- - name: check that the user exists
- <<: *task_parameters
- postgresql_query:
- <<: *pg_parameters
- query: "SELECT rolname FROM pg_roles WHERE rolname = '{{ test_group1 }}'"
-
- - assert:
- that:
- - result.rowcount == 1
-
- - name: check membership
- <<: *task_parameters
- postgresql_query:
- <<: *pg_parameters
- query: "SELECT grolist FROM pg_group WHERE groname = '{{ test_group2 }}' AND grolist != '{}'"
-
- - assert:
- that:
- - result.rowcount == 1
-
- - name: Grant test_group2 to test_group1 again
- <<: *task_parameters
- postgresql_user:
- <<: *pg_parameters
- name: '{{ test_group1 }}'
- groups: '{{ test_group2 }}'
-
- - assert:
- that:
- - result is not changed
- - result.user == '{{ test_group1 }}'
-
- - name: check membership
- <<: *task_parameters
- postgresql_query:
- <<: *pg_parameters
- query: "SELECT grolist FROM pg_group WHERE groname = '{{ test_group2 }}' AND grolist != '{}'"
-
- - assert:
- that:
- - result.rowcount == 1
-
- - name: Grant groups to existent role
- <<: *task_parameters
- postgresql_user:
- <<: *pg_parameters
- name: '{{ test_user }}'
- groups:
- - '{{ test_group1 }}'
- - '{{ test_group2 }}'
- trust_input: false
-
- - assert:
- that:
- - result is changed
- - result.user == '{{ test_user }}'
- - result.queries == ['GRANT "{{ test_group1 }}" TO "{{ test_user }}"', 'GRANT "{{ test_group2 }}" TO "{{ test_user }}"']
-
- - name: check membership
- <<: *task_parameters
- postgresql_query:
- <<: *pg_parameters
- query: "SELECT * FROM pg_group WHERE groname in ('{{ test_group1 }}', '{{ test_group2 }}') AND grolist != '{}'"
-
- - assert:
- that:
- - result.rowcount == 2
-
########################
# Test trust_input param
@@ -777,6 +738,35 @@
that:
- result is not changed
+##### Test error handling when the database is read-only
+
+ - name: Set database as read-only
+ <<: *task_parameters
+ postgresql_set:
+ <<: *pg_parameters
+ name: 'default_transaction_read_only'
+ value: 'on'
+
+ - name: Try to alter role in read-only database
+ <<: *task_parameters
+ postgresql_user:
+ <<: *pg_parameters
+ name: '{{ test_user }}'
+ role_attr_flags: 'CREATEDB'
+ register: result
+ ignore_errors: true
+
+ - assert:
+ that:
+ - result.msg == 'ERROR: cannot execute ALTER ROLE in a read-only transaction\n'
+
+ - name: Set database as read-write
+ <<: *task_parameters
+ postgresql_set:
+ <<: *pg_parameters
+ name: 'default_transaction_read_only'
+ value: 'off'
+
always:
#
# Clean up
@@ -797,6 +787,4 @@
loop:
- '{{ test_user }}'
- '{{ test_user2 }}'
- - '{{ test_group1 }}'
- - '{{ test_group2 }}'
- '{{ dangerous_name }}'
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_user/tasks/postgresql_user_sql_ascii_db.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_user/tasks/postgresql_user_sql_ascii_db.yml
new file mode 100644
index 000000000..4f322f152
--- /dev/null
+++ b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_user/tasks/postgresql_user_sql_ascii_db.yml
@@ -0,0 +1,8 @@
+- name: Execute module with no changes
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_user:
+ name: '{{ sql_ascii_user }}'
+ db: '{{ sql_ascii_db }}'
+ role_attr_flags: SUPERUSER
+ password: '{{ sql_ascii_pass }}'
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_user_obj_stat_info/tasks/postgresql_user_obj_stat_info.yml b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_user_obj_stat_info/tasks/postgresql_user_obj_stat_info.yml
index 62f72d9ec..48b6208e0 100644
--- a/ansible_collections/community/postgresql/tests/integration/targets/postgresql_user_obj_stat_info/tasks/postgresql_user_obj_stat_info.yml
+++ b/ansible_collections/community/postgresql/tests/integration/targets/postgresql_user_obj_stat_info/tasks/postgresql_user_obj_stat_info.yml
@@ -75,7 +75,7 @@
state: stopped
when: (ansible_facts.distribution_major_version != '8' and ansible_facts.distribution == 'CentOS') or ansible_facts.distribution != 'CentOS'
- - name: Pause between stop and start PosgreSQL
+ - name: Pause between stop and start PostgreSQL
pause:
seconds: 5
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/defaults/main.yml b/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/defaults/main.yml
index 973d41591..823b6561a 100644
--- a/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/defaults/main.yml
+++ b/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/defaults/main.yml
@@ -4,9 +4,16 @@ postgresql_packages:
- postgresql-server
- python-psycopg2
+pip_packages: []
+
pg_user: postgres
pg_group: root
+pg_dir: "/var/lib/pgsql/data"
+pg_hba_location: "{{ pg_dir }}/pg_hba.conf"
+pg_conf_location: "{{ pg_dir }}/postgresql.conf"
+pg_auto_conf: "{{ pg_dir }}/postgresql.auto.conf"
+
locale_latin_suffix:
locale_utf8_suffix:
@@ -18,4 +25,13 @@ ssl_user: 'ssl_user'
ssl_pass: 'ssl_pass'
ssl_rootcert: '/etc/server-ca.crt'
ssl_cert: '/etc/client.crt'
-ssl_key: '/etc/client.key' \ No newline at end of file
+ssl_key: '/etc/client.key'
+
+# second database, for logical replication testing
+replica_data_dir: "/var/lib/pgsql_replica"
+replica_port: 5533
+
+# defaults for test sql_ascii database
+sql_ascii_db: 'sql_ascii'
+sql_ascii_user: 'sql_ascii_user'
+sql_ascii_pass: 'sql_ascii_pass'
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/tasks/main.yml b/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/tasks/main.yml
index 80bb3c4d4..062fadef7 100644
--- a/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/tasks/main.yml
+++ b/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/tasks/main.yml
@@ -66,20 +66,15 @@
loop_var: loop_item
#
-# Install PostgreSQL 15 on Ubuntu 20.04
-- name: Install PostgreSQL 15 on Ubuntu 20.04
+# Prepare Ubuntu for PostgreSQL install
+- name: Prepare Ubuntu for PostgreSQL
when:
- ansible_facts.distribution == 'Ubuntu'
- - ansible_facts.distribution_major_version == '20'
block:
- name: Run autoremove
become: true
apt:
autoremove: true
-
- - name: Install wget
- package:
- name: wget
- name: Create the file repository configuration
lineinfile:
@@ -108,7 +103,7 @@
##
#
-- name: install dependencies for postgresql test
+- name: Install required OS packages
package:
name: '{{ postgresql_package_item }}'
state: present
@@ -116,6 +111,13 @@
loop_control:
loop_var: postgresql_package_item
+- name: Install required Pip packages
+ pip:
+ name: "{{ pip_package_item }}"
+ with_items: "{{ pip_packages }}"
+ loop_control:
+ loop_var: pip_package_item
+
- name: Initialize postgres (RedHat systemd)
command: postgresql-setup initdb
when: ansible_os_family == "RedHat" and ansible_service_mgr == "systemd"
@@ -125,7 +127,7 @@
when: ansible_os_family == "RedHat" and ansible_service_mgr != "systemd"
- name: Initialize postgres (Debian)
- shell: . /usr/share/postgresql-common/maintscripts-functions && set_system_locale && /usr/bin/pg_createcluster -u postgres {{ pg_ver }} main
+ shell: . /usr/share/postgresql-common/maintscripts-functions && set_system_locale && /usr/bin/pg_createcluster -u postgres {{ pg_ver }} main
args:
creates: /etc/postgresql/{{ pg_ver }}/
when: ansible_os_family == 'Debian'
@@ -208,7 +210,15 @@
- name: Stop postgresql service
service: name={{ postgresql_service }} state=stopped
- when: terminate is not succeeded
+
+- name: Configure postgresql.conf
+ ansible.builtin.lineinfile:
+ path: '{{ pg_conf_location }}'
+ regexp: '^wal_level '
+ line: 'wal_level = logical'
+ when:
+ - replica_db_required is defined and replica_db_required
+ - ansible_distribution_major_version != "7" # CentOS 7 with Postgres 9.2 doesn't support 'logical'
- name: Pause between stop and start
pause:
@@ -277,3 +287,14 @@
when:
- ansible_os_family == 'Debian'
- postgres_version_resp.stdout is version('9.4', '>=')
+
+# Create a second database
+- import_tasks: replica.yml
+ when:
+ - replica_db_required is defined and replica_db_required
+ - ansible_distribution_major_version != "7" # CentOS 7 with Postgres 9.2 doesn't support 'logical'
+
+# Create an SQL_ASCII encoded database
+- import_tasks: sql_ascii.yml
+ when:
+ - sql_ascii_db_required is defined and sql_ascii_db_required
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/tasks/replica.yml b/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/tasks/replica.yml
new file mode 100644
index 000000000..0570db9bb
--- /dev/null
+++ b/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/tasks/replica.yml
@@ -0,0 +1,59 @@
+- name: Replica - find pg_ctl
+ shell: find /usr/lib /usr/bin -type f -name "pg_ctl"
+ register: result
+
+- name: Replica - set path to pg_ctl
+ set_fact:
+ pg_ctl: '{{ result.stdout }}'
+
+- name: Replica - stop database
+ become: true
+ become_user: '{{ pg_user }}'
+ shell: '{{ pg_ctl }} -D {{ replica_data_dir }} stop'
+ ignore_errors: true
+
+- name: Replica - remove old db
+ file:
+ path: '{{ replica_data_dir }}'
+ state: absent
+ ignore_errors: true
+
+- name: Replica - create data dir
+ file:
+ state: directory
+ recurse: true
+ path: "{{ replica_data_dir }}"
+ owner: "{{ pg_user }}"
+ mode: "0700"
+
+- name: Replica - find initdb
+ shell: find /usr/lib /usr/bin -type f -name "initdb"
+ register: result
+
+- name: Replica - set path to initdb
+ set_fact:
+ initdb: '{{ result.stdout }}'
+
+- name: Replica - initialize database
+ become: true
+ become_user: '{{ pg_user }}'
+ shell: '{{ initdb }} --pgdata {{ replica_data_dir }}'
+
+- name: Replica - configure postgresql.conf
+ ansible.builtin.lineinfile:
+ path: '{{ replica_data_dir }}/postgresql.conf'
+ regexp: '^wal_level '
+ line: 'wal_level = logical'
+
+- name: Replica - start database
+ become: true
+ become_user: '{{ pg_user }}'
+ shell: '{{ pg_ctl }} -D {{ replica_data_dir }} -o "-p {{ replica_port }}" -l {{ replica_data_dir }}/replica.log start'
+
+- name: Replica - check connectivity
+ become: true
+ become_user: '{{ pg_user }}'
+ postgresql_ping:
+ db: '{{ pg_user }}'
+ login_user: '{{ pg_user }}'
+ login_port: '{{ replica_port }}'
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/tasks/sql_ascii.yml b/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/tasks/sql_ascii.yml
new file mode 100644
index 000000000..d6641412a
--- /dev/null
+++ b/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/tasks/sql_ascii.yml
@@ -0,0 +1,36 @@
+- name: postgresql SQL_ASCII - create database
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_db:
+ name: '{{ sql_ascii_db }}'
+ encoding: 'SQL_ASCII'
+ template: 'template0'
+
+- name: postgresql SQL_ASCII - ensure db exists with proper encoding
+ become_user: '{{ pg_user }}'
+ become: true
+ shell: "psql -c 'SHOW SERVER_ENCODING' --tuples-only --no-align --dbname {{ sql_ascii_db }}"
+ register: sql_ascii_db_encoding
+
+- ansible.builtin.assert:
+ that:
+ - sql_ascii_db_encoding.stdout == 'SQL_ASCII'
+
+- name: postgresql SQL_ASCII - create role
+ become_user: '{{ pg_user }}'
+ become: true
+ postgresql_user:
+ name: '{{ sql_ascii_user }}'
+ db: '{{ sql_ascii_db }}'
+ role_attr_flags: SUPERUSER
+ password: '{{ sql_ascii_pass }}'
+
+- name: postgresql SQL_ASCII - ensure role was created
+ become: true
+ become_user: "{{ pg_user }}"
+ shell: "psql -c \"select * from pg_authid where rolname='{{ sql_ascii_user }}';\" -d {{ sql_ascii_db }}"
+ register: result
+
+- ansible.builtin.assert:
+ that:
+ - "result.stdout_lines[-1] == '(1 row)'"
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/Debian-8.yml b/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/Debian-8.yml
index 932738d39..8e16579ad 100644
--- a/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/Debian-8.yml
+++ b/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/Debian-8.yml
@@ -3,7 +3,6 @@ postgresql_packages:
- "postgresql-common"
- "python-psycopg2"
-pg_hba_location: "/etc/postgresql/9.4/main/pg_hba.conf"
-pg_dir: "/var/lib/postgresql/9.4/main"
-pg_auto_conf: "{{ pg_dir }}/postgresql.auto.conf"
pg_ver: 9.4
+pg_hba_location: "/etc/postgresql/{{ pg_ver }}/main/pg_hba.conf"
+pg_dir: "/var/lib/postgresql/{{ pg_ver }}/main"
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/Fedora-36-py3.yml b/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/Fedora-36-py3.yml
new file mode 100644
index 000000000..e67a4ac4f
--- /dev/null
+++ b/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/Fedora-36-py3.yml
@@ -0,0 +1,7 @@
+# We install both psycopg2 and psycopg3.
+# As psycopg3 is only 3.0, the modules should use psycopg2.
+postgresql_packages:
+ - "postgresql-contrib"
+ - "postgresql-server"
+ - "python3-psycopg2"
+ - "python3-psycopg3" # psycopg 3.0.16
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/Fedora-38-py3.yml b/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/Fedora-38-py3.yml
new file mode 100644
index 000000000..e233746ed
--- /dev/null
+++ b/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/Fedora-38-py3.yml
@@ -0,0 +1,5 @@
+postgresql_packages:
+ - "postgresql-contrib"
+ - "postgresql-server"
+ - "python3-psycopg2"
+ - "python3-psycopg3"
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/RedHat-py3.yml b/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/RedHat-py3.yml
index 72041a3d7..08d2adb8a 100644
--- a/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/RedHat-py3.yml
+++ b/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/RedHat-py3.yml
@@ -1,9 +1,6 @@
postgresql_packages:
- "postgresql-server"
+ - "postgresql-contrib"
- "python3-psycopg2"
- "bzip2"
- "xz"
-
-pg_hba_location: "/var/lib/pgsql/data/pg_hba.conf"
-pg_dir: "/var/lib/pgsql/data"
-pg_auto_conf: "{{ pg_dir }}/postgresql.auto.conf"
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/RedHat.yml b/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/RedHat.yml
index 30720f8fe..2d82eaefd 100644
--- a/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/RedHat.yml
+++ b/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/RedHat.yml
@@ -1,8 +1,5 @@
postgresql_packages:
- "postgresql-server"
+ - "postgresql-contrib"
- "python-psycopg2"
- "bzip2"
-
-pg_hba_location: "/var/lib/pgsql/data/pg_hba.conf"
-pg_dir: "/var/lib/pgsql/data"
-pg_auto_conf: "{{ pg_dir }}/postgresql.auto.conf"
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/Ubuntu-20-py3.yml b/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/Ubuntu-20-py3.yml
index ff543a385..15c8b4c2b 100644
--- a/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/Ubuntu-20-py3.yml
+++ b/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/Ubuntu-20-py3.yml
@@ -1,13 +1,15 @@
+pg_ver: 15
+
postgresql_packages:
- "apt-utils"
- - "postgresql"
+ - "postgresql-{{ pg_ver }}"
- "postgresql-common"
- "python3-psycopg2"
- "postgresql-client"
-pg_hba_location: "/etc/postgresql/15/main/pg_hba.conf"
-pg_dir: "/var/lib/postgresql/15/main"
+pg_conf_location: "/etc/postgresql/{{ pg_ver }}/main/postgresql.conf"
+pg_hba_location: "/etc/postgresql/{{ pg_ver }}/main/pg_hba.conf"
+pg_dir: "/var/lib/postgresql/{{ pg_ver }}/main"
pg_auto_conf: "{{ pg_dir }}/postgresql.auto.conf"
-pg_ver: 15
-postgis: postgresql-15-postgis-3
+postgis: "postgresql-{{ pg_ver }}-postgis-3"
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/Ubuntu-22-py3.yml b/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/Ubuntu-22-py3.yml
new file mode 100644
index 000000000..334ad27aa
--- /dev/null
+++ b/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/Ubuntu-22-py3.yml
@@ -0,0 +1,18 @@
+pg_ver: 15
+
+postgresql_packages:
+ - "apt-utils"
+ - "postgresql-{{ pg_ver }}"
+ - "postgresql-common"
+ # - "python3-psycopg2"
+ - "postgresql-client"
+
+pip_packages:
+ - "psycopg==3.1.9" # We need at least 3.1 for Client-side-binding cursors
+
+pg_conf_location: "/etc/postgresql/{{ pg_ver }}/main/postgresql.conf"
+pg_hba_location: "/etc/postgresql/{{ pg_ver }}/main/pg_hba.conf"
+pg_dir: "/var/lib/postgresql/{{ pg_ver }}/main"
+pg_auto_conf: "{{ pg_dir }}/postgresql.auto.conf"
+
+postgis: postgresql-{{ pg_ver }}-postgis-3
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/default-py3.yml b/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/default-py3.yml
index 3ff3e0de5..c5fa981e7 100644
--- a/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/default-py3.yml
+++ b/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/default-py3.yml
@@ -1,7 +1,3 @@
postgresql_packages:
- "postgresql-server"
- "python3-psycopg2"
-
-pg_hba_location: "/var/lib/pgsql/data/pg_hba.conf"
-pg_dir: "/var/lib/pgsql/data"
-pg_auto_conf: "{{ pg_dir }}/postgresql.auto.conf"
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/default.yml b/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/default.yml
index 71f1cd46e..af7dfe475 100644
--- a/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/default.yml
+++ b/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_db/vars/default.yml
@@ -1,7 +1,3 @@
postgresql_packages:
- "postgresql-server"
- "python-psycopg2"
-
-pg_hba_location: "/var/lib/pgsql/data/pg_hba.conf"
-pg_dir: "/var/lib/pgsql/data"
-pg_auto_conf: "{{ pg_dir }}/postgresql.auto.conf"
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_replication/defaults/main.yml b/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_replication/defaults/main.yml
deleted file mode 100644
index 5ac314c4b..000000000
--- a/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_replication/defaults/main.yml
+++ /dev/null
@@ -1,26 +0,0 @@
-# General:
-pg_user: postgres
-db_default: postgres
-
-pg_package_list:
-- postgresql
-- postgresql-client
-- python3-psycopg2
-
-packages_to_remove:
-- postgresql
-- postgresql-client
-
-# Master specific defaults:
-primary_root_dir: '/var/lib/pgsql/primary'
-primary_data_dir: '{{ primary_root_dir }}/data'
-primary_postgresql_conf: '{{ primary_data_dir }}/postgresql.conf'
-primary_pg_hba_conf: '{{ primary_data_dir }}/pg_hba.conf'
-primary_port: 5431
-
-# Replica specific defaults:
-replica_root_dir: '/var/lib/pgsql/replica'
-replica_data_dir: '{{ replica_root_dir }}/data'
-replica_postgresql_conf: '{{ replica_data_dir }}/postgresql.conf'
-replica_pg_hba_conf: '{{ replica_data_dir }}/pg_hba.conf'
-replica_port: 5434
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_replication/handlers/main.yml b/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_replication/handlers/main.yml
deleted file mode 100644
index ea230c778..000000000
--- a/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_replication/handlers/main.yml
+++ /dev/null
@@ -1,24 +0,0 @@
-- name: Stop services
- become: true
- become_user: '{{ pg_user }}'
- shell: '{{ pg_ctl }} -D {{ item.datadir }} -o "-p {{ item.port }}" -m immediate stop'
- loop:
- - { datadir: '{{ primary_data_dir }}', port: '{{ primary_port }}' }
- - { datadir: '{{ replica_data_dir }}', port: '{{ replica_port }}' }
- listen: stop postgresql
-
-- name: Remove packages
- apt:
- name: '{{ packages_to_remove }}'
- state: absent
- listen: cleanup postgresql
-
-- name: Remove FS objects
- file:
- state: absent
- path: "{{ item }}"
- force: true
- loop:
- - "{{ primary_root_dir }}"
- - "{{ replica_root_dir }}"
- listen: cleanup postgresql
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_replication/tasks/main.yml b/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_replication/tasks/main.yml
deleted file mode 100644
index 4c6421a18..000000000
--- a/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_replication/tasks/main.yml
+++ /dev/null
@@ -1,13 +0,0 @@
-####################################################################
-# WARNING: These are designed specifically for Ansible tests #
-# and should not be used as examples of how to write Ansible roles #
-####################################################################
-
-# Copyright: (c) 2019, Andrew Klychkov (@Andersson007) <aaklychkov@mail.ru>
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-# Setup PostgreSQL primary-standby replication into one container:
-- import_tasks: setup_postgresql_cluster.yml
- when:
- - ansible_distribution == 'Ubuntu'
- - ansible_distribution_major_version >= '18'
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_replication/tasks/setup_postgresql_cluster.yml b/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_replication/tasks/setup_postgresql_cluster.yml
deleted file mode 100644
index 2bff42e78..000000000
--- a/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_replication/tasks/setup_postgresql_cluster.yml
+++ /dev/null
@@ -1,149 +0,0 @@
-- name: Remove preinstalled packages
- apt:
- name: '{{ packages_to_remove }}'
- state: absent
- become: true
-
-- name: Run autoremove
- become: true
- apt:
- autoremove: true
-
-- name: Configure Ubuntu 20 for PostgreSQL
- when:
- - ansible_facts['distribution'] == 'Ubuntu'
- - ansible_facts['distribution_major_version'] is version('20', 'ge')
- block:
- - name: Install wget
- package:
- name: wget
-
- - name: Add PGDG repository
- lineinfile:
- create: true
- line: "deb http://apt.postgresql.org/pub/repos/apt {{ ansible_facts['distribution_release'] }}-pgdg main"
- path: '/etc/apt/sources.list.d/pgdg.list'
- state: 'present'
-
- - name: Add PGDG GPG key
- ansible.builtin.apt_key:
- state: present
- url: https://www.postgresql.org/media/keys/ACCC4CF8.asc
-
- - name: Update apt cache
- apt:
- update_cache: true
-
-- name: Install apt-utils
- apt:
- name: apt-utils
-
-- name: Install packages
- apt:
- name: '{{ pg_package_list }}'
- policy_rc_d: 101 # prevent the service from starting
- notify: cleanup postgresql
-
-- name: Delete postgresql related files
- file:
- state: absent
- path: '{{ item }}'
- force: true
- loop:
- - '{{ primary_root_dir }}'
- - '{{ replica_root_dir }}'
- - /etc/postgresql
- - /var/lib/postgresql
-
-- name: Create dirs needed
- file:
- state: directory
- recurse: true
- path: '{{ item }}'
- owner: postgres
- group: postgres
- mode: '0700'
- loop:
- - '{{ primary_data_dir }}'
- - '{{ replica_data_dir }}'
- - /var/lib/postgresql
- notify: cleanup postgresql
-
-- name: Find initdb
- shell: find /usr/lib -type f -name "initdb"
- register: result
-
-- name: Set path to initdb
- set_fact:
- initdb: '{{ result.stdout }}'
-
-- name: Initialize databases
- become: true
- become_user: '{{ pg_user }}'
- shell: '{{ initdb }} --pgdata {{ item }}'
- loop:
- - '{{ primary_data_dir }}'
- - '{{ replica_data_dir }}'
-
-- name: Copy config templates
- template:
- src: '{{ item.conf_templ }}'
- dest: '{{ item.conf_dest }}'
- owner: postgres
- group: postgres
- force: true
- loop:
- - conf_templ: primary_postgresql.conf.j2
- conf_dest: '{{ primary_postgresql_conf }}'
- - conf_templ: replica_postgresql.conf.j2
- conf_dest: '{{ replica_postgresql_conf }}'
- - conf_templ: pg_hba.conf.j2
- conf_dest: '{{ primary_pg_hba_conf }}'
- - conf_templ: pg_hba.conf.j2
- conf_dest: '{{ replica_pg_hba_conf }}'
-
-- name: Find pg_ctl
- shell: find /usr/lib -type f -name "pg_ctl"
- register: result
-
-- name: Set path to initdb
- set_fact:
- pg_ctl: '{{ result.stdout }}'
-
-- name: Start primary
- become: true
- become_user: '{{ pg_user }}'
- shell: '{{ pg_ctl }} -D {{ primary_data_dir }} -o "-p {{ primary_port }}" -l {{ primary_data_dir }}/primary.log start'
- notify:
- - stop postgresql
-
-- name: Start replica
- become: true
- become_user: '{{ pg_user }}'
- shell: '{{ pg_ctl }} -D {{ replica_data_dir }} -o "-p {{ replica_port }}" -l {{ replica_data_dir }}/replica.log start'
-
-- name: Check connectivity to the primary and get PostgreSQL version
- become: true
- become_user: '{{ pg_user }}'
- postgresql_ping:
- db: '{{ db_default }}'
- login_user: '{{ pg_user }}'
- login_port: '{{ primary_port }}'
- register: result
-
-- name: Check connectivity to the replica and get PostgreSQL version
- become: true
- become_user: '{{ pg_user }}'
- postgresql_ping:
- db: '{{ db_default }}'
- login_user: '{{ pg_user }}'
- login_port: '{{ replica_port }}'
-
-- name: Define server version
- set_fact:
- pg_major_version: '{{ result.server_version.major }}'
- pg_minor_version: '{{ result.server_version.minor }}'
-
-- name: Print PostgreSQL version
- debug:
- msg: PostgreSQL version is {{ pg_major_version }}.{{ pg_minor_version }}
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_replication/templates/pg_hba.conf.j2 b/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_replication/templates/pg_hba.conf.j2
deleted file mode 100644
index 62e05ffc8..000000000
--- a/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_replication/templates/pg_hba.conf.j2
+++ /dev/null
@@ -1,7 +0,0 @@
-local all all trust
-local replication logical_replication trust
-host replication logical_replication 127.0.0.1/32 trust
-host replication logical_replication 0.0.0.0/0 trust
-local all logical_replication trust
-host all logical_replication 127.0.0.1/32 trust
-host all logical_replication 0.0.0.0/0 trust
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_replication/templates/primary_postgresql.conf.j2 b/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_replication/templates/primary_postgresql.conf.j2
deleted file mode 100644
index 545769f35..000000000
--- a/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_replication/templates/primary_postgresql.conf.j2
+++ /dev/null
@@ -1,28 +0,0 @@
-# Important parameters:
-listen_addresses='*'
-port = {{ primary_port }}
-wal_level = logical
-max_wal_senders = 8
-track_commit_timestamp = on
-max_replication_slots = 10
-
-# Unimportant parameters:
-max_connections=10
-shared_buffers=8MB
-dynamic_shared_memory_type=posix
-log_destination='stderr'
-logging_collector=on
-log_directory='log'
-log_filename='postgresql-%a.log'
-log_truncate_on_rotation=on
-log_rotation_age=1d
-log_rotation_size=0
-log_line_prefix='%m[%p]'
-log_timezone='W-SU'
-datestyle='iso,mdy'
-timezone='W-SU'
-lc_messages='en_US.UTF-8'
-lc_monetary='en_US.UTF-8'
-lc_numeric='en_US.UTF-8'
-lc_time='en_US.UTF-8'
-default_text_search_config='pg_catalog.english'
diff --git a/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_replication/templates/replica_postgresql.conf.j2 b/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_replication/templates/replica_postgresql.conf.j2
deleted file mode 100644
index 206ab2eb3..000000000
--- a/ansible_collections/community/postgresql/tests/integration/targets/setup_postgresql_replication/templates/replica_postgresql.conf.j2
+++ /dev/null
@@ -1,28 +0,0 @@
-# Important parameters:
-listen_addresses='*'
-port = {{ replica_port }}
-wal_level = logical
-max_wal_senders = 8
-track_commit_timestamp = on
-max_replication_slots = 10
-
-# Unimportant parameters:
-max_connections=10
-shared_buffers=8MB
-dynamic_shared_memory_type=posix
-log_destination='stderr'
-logging_collector=on
-log_directory='log'
-log_filename='postgresql-%a.log'
-log_truncate_on_rotation=on
-log_rotation_age=1d
-log_rotation_size=0
-log_line_prefix='%m[%p]'
-log_timezone='W-SU'
-datestyle='iso,mdy'
-timezone='W-SU'
-lc_messages='en_US.UTF-8'
-lc_monetary='en_US.UTF-8'
-lc_numeric='en_US.UTF-8'
-lc_time='en_US.UTF-8'
-default_text_search_config='pg_catalog.english'
diff --git a/ansible_collections/community/postgresql/tests/sanity/extra/no-unwanted-files.py b/ansible_collections/community/postgresql/tests/sanity/extra/no-unwanted-files.py
index 49806f2e2..85d693c61 100755
--- a/ansible_collections/community/postgresql/tests/sanity/extra/no-unwanted-files.py
+++ b/ansible_collections/community/postgresql/tests/sanity/extra/no-unwanted-files.py
@@ -2,7 +2,8 @@
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""Prevent unwanted files from being added to the source tree."""
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
import os
diff --git a/ansible_collections/community/postgresql/tests/sanity/ignore-2.12.txt b/ansible_collections/community/postgresql/tests/sanity/ignore-2.12.txt
index b9cd1303f..d188d3d68 100644
--- a/ansible_collections/community/postgresql/tests/sanity/ignore-2.12.txt
+++ b/ansible_collections/community/postgresql/tests/sanity/ignore-2.12.txt
@@ -1,5 +1,3 @@
-tests/utils/shippable/check_matrix.py replace-urlopen
tests/utils/shippable/timing.py shebang
plugins/modules/postgresql_db.py use-argspec-type-path
plugins/modules/postgresql_db.py validate-modules:use-run-command-not-popen
-plugins/modules/postgresql_tablespace.py validate-modules:mutually_exclusive-unknown
diff --git a/ansible_collections/community/postgresql/tests/sanity/ignore-2.13.txt b/ansible_collections/community/postgresql/tests/sanity/ignore-2.13.txt
index b9cd1303f..d188d3d68 100644
--- a/ansible_collections/community/postgresql/tests/sanity/ignore-2.13.txt
+++ b/ansible_collections/community/postgresql/tests/sanity/ignore-2.13.txt
@@ -1,5 +1,3 @@
-tests/utils/shippable/check_matrix.py replace-urlopen
tests/utils/shippable/timing.py shebang
plugins/modules/postgresql_db.py use-argspec-type-path
plugins/modules/postgresql_db.py validate-modules:use-run-command-not-popen
-plugins/modules/postgresql_tablespace.py validate-modules:mutually_exclusive-unknown
diff --git a/ansible_collections/community/postgresql/tests/sanity/ignore-2.14.txt b/ansible_collections/community/postgresql/tests/sanity/ignore-2.14.txt
index b9cd1303f..d188d3d68 100644
--- a/ansible_collections/community/postgresql/tests/sanity/ignore-2.14.txt
+++ b/ansible_collections/community/postgresql/tests/sanity/ignore-2.14.txt
@@ -1,5 +1,3 @@
-tests/utils/shippable/check_matrix.py replace-urlopen
tests/utils/shippable/timing.py shebang
plugins/modules/postgresql_db.py use-argspec-type-path
plugins/modules/postgresql_db.py validate-modules:use-run-command-not-popen
-plugins/modules/postgresql_tablespace.py validate-modules:mutually_exclusive-unknown
diff --git a/ansible_collections/community/postgresql/tests/sanity/ignore-2.15.txt b/ansible_collections/community/postgresql/tests/sanity/ignore-2.15.txt
index 58b57c247..c71a79a50 100644
--- a/ansible_collections/community/postgresql/tests/sanity/ignore-2.15.txt
+++ b/ansible_collections/community/postgresql/tests/sanity/ignore-2.15.txt
@@ -1,6 +1,4 @@
-tests/utils/shippable/check_matrix.py replace-urlopen
tests/utils/shippable/timing.py shebang
plugins/modules/postgresql_db.py use-argspec-type-path
plugins/modules/postgresql_db.py validate-modules:use-run-command-not-popen
-plugins/modules/postgresql_tablespace.py validate-modules:mutually_exclusive-unknown
plugins/module_utils/version.py pylint:unused-import
diff --git a/ansible_collections/community/postgresql/tests/sanity/ignore-2.16.txt b/ansible_collections/community/postgresql/tests/sanity/ignore-2.16.txt
index 58b57c247..c71a79a50 100644
--- a/ansible_collections/community/postgresql/tests/sanity/ignore-2.16.txt
+++ b/ansible_collections/community/postgresql/tests/sanity/ignore-2.16.txt
@@ -1,6 +1,4 @@
-tests/utils/shippable/check_matrix.py replace-urlopen
tests/utils/shippable/timing.py shebang
plugins/modules/postgresql_db.py use-argspec-type-path
plugins/modules/postgresql_db.py validate-modules:use-run-command-not-popen
-plugins/modules/postgresql_tablespace.py validate-modules:mutually_exclusive-unknown
plugins/module_utils/version.py pylint:unused-import
diff --git a/ansible_collections/community/postgresql/tests/sanity/ignore-2.17.txt b/ansible_collections/community/postgresql/tests/sanity/ignore-2.17.txt
new file mode 100644
index 000000000..230ec3421
--- /dev/null
+++ b/ansible_collections/community/postgresql/tests/sanity/ignore-2.17.txt
@@ -0,0 +1,5 @@
+plugins/modules/postgresql_db.py use-argspec-type-path
+plugins/modules/postgresql_db.py validate-modules:use-run-command-not-popen
+plugins/module_utils/version.py pylint:unused-import
+tests/utils/shippable/timing.py shebang
+tests/unit/plugins/module_utils/test_postgres.py pylint:unidiomatic-typecheck
diff --git a/ansible_collections/community/postgresql/tests/unit/plugins/module_utils/test_postgres.py b/ansible_collections/community/postgresql/tests/unit/plugins/module_utils/test_postgres.py
index 975542446..566c78851 100644
--- a/ansible_collections/community/postgresql/tests/unit/plugins/module_utils/test_postgres.py
+++ b/ansible_collections/community/postgresql/tests/unit/plugins/module_utils/test_postgres.py
@@ -1,14 +1,15 @@
# Copyright: (c) 2019, Andrew Klychkov (@Andersson007) <aaklychkov@mail.ru>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
from os import environ
-import pytest
-
import ansible_collections.community.postgresql.plugins.module_utils.postgres as pg
-
+import pytest
+from ansible_collections.community.postgresql.plugins.module_utils.version import \
+ LooseVersion
INPUT_DICT = dict(
session_role=dict(default=''),
@@ -124,7 +125,7 @@ def m_psycopg2():
class DummyPsycopg2():
def __init__(self):
- self.__version__ = '2.4.3'
+ self.__version__ = "2.9.6"
self.extras = Extras()
self.extensions = Extensions()
@@ -155,8 +156,12 @@ class TestEnsureReqLibs():
class Dummym_ansible_module():
def __init__(self):
self.params = {'ca_cert': False}
+ self.warn_msg = ''
self.err_msg = ''
+ def warn(self, msg):
+ self.warn_msg = msg
+
def fail_json(self, msg):
self.err_msg = msg
@@ -164,13 +169,14 @@ class TestEnsureReqLibs():
def test_ensure_req_libs_has_not_psycopg2(self, m_ansible_module):
"""Test ensure_required_libs() with psycopg2 is None."""
- # HAS_PSYCOPG2 is False by default
+ # HAS_PSYCOPG is False by default
pg.ensure_required_libs(m_ansible_module)
assert 'Failed to import the required Python library (psycopg2)' in m_ansible_module.err_msg
def test_ensure_req_libs_has_psycopg2(self, m_ansible_module, monkeypatch):
"""Test ensure_required_libs() with psycopg2 is not None."""
- monkeypatch.setattr(pg, 'HAS_PSYCOPG2', True)
+ monkeypatch.setattr(pg, 'HAS_PSYCOPG', True)
+ monkeypatch.setattr(pg, 'PSYCOPG_VERSION', "2.9")
pg.ensure_required_libs(m_ansible_module)
assert m_ansible_module.err_msg == ''
@@ -180,8 +186,9 @@ class TestEnsureReqLibs():
Test with module.params['ca_cert'], psycopg2 version is suitable.
"""
m_ansible_module.params['ca_cert'] = True
- monkeypatch.setattr(pg, 'HAS_PSYCOPG2', True)
- monkeypatch.setattr(pg, 'psycopg2', m_psycopg2)
+ monkeypatch.setattr(pg, 'HAS_PSYCOPG', True)
+ monkeypatch.setattr(pg, 'PSYCOPG_VERSION', LooseVersion("2.9.6"))
+ monkeypatch.setattr(pg, 'psycopg', m_psycopg2)
pg.ensure_required_libs(m_ansible_module)
assert m_ansible_module.err_msg == ''
@@ -191,11 +198,10 @@ class TestEnsureReqLibs():
Test with module.params['ca_cert'], psycopg2 version is wrong.
"""
m_ansible_module.params['ca_cert'] = True
- monkeypatch.setattr(pg, 'HAS_PSYCOPG2', True)
+ psycopg = m_psycopg2
+ monkeypatch.setattr(pg, 'psycopg', psycopg)
# Set wrong psycopg2 version number:
- psycopg2 = m_psycopg2
- psycopg2.__version__ = '2.4.2'
- monkeypatch.setattr(pg, 'psycopg2', psycopg2)
+ monkeypatch.setattr(pg, 'PSYCOPG_VERSION', LooseVersion("2.4.2"))
pg.ensure_required_libs(m_ansible_module)
assert 'psycopg2 must be at least 2.4.3' in m_ansible_module.err_msg
@@ -231,10 +237,10 @@ class TestConnectToDb():
"""
Namespace for testing connect_to_db() function.
- When some connection errors occure connect_to_db() caught any of them
+ When some connection errors occur connect_to_db() caught any of them
and invoke fail_json() or warn() methods of AnsibleModule object
depending on the passed parameters.
- connect_to_db may return db_connection object or None if errors occured.
+ connect_to_db may return db_connection object or None if errors occurred.
Therefore we must check:
1. Values of err_msg and warn_msg attributes of m_ansible_module mock object.
2. Types of return objects (db_connection and cursor).
@@ -242,22 +248,22 @@ class TestConnectToDb():
def test_connect_to_db(self, m_ansible_module, monkeypatch, m_psycopg2):
"""Test connect_to_db(), common test."""
- monkeypatch.setattr(pg, 'HAS_PSYCOPG2', True)
+ monkeypatch.setattr(pg, 'psycopg', m_psycopg2)
monkeypatch.setattr(pg, 'psycopg2', m_psycopg2)
conn_params = pg.get_conn_params(m_ansible_module, m_ansible_module.params)
db_connection, dummy = pg.connect_to_db(m_ansible_module, conn_params)
cursor = db_connection.cursor()
# if errors, db_connection returned as None:
- assert type(db_connection) == DbConnection
- assert type(cursor) == Cursor
+ assert type(db_connection) is DbConnection
+ assert type(cursor) is Cursor
assert m_ansible_module.err_msg == ''
# The default behaviour, normal in this case:
assert 'Database name has not been passed' in m_ansible_module.warn_msg
def test_session_role(self, m_ansible_module, monkeypatch, m_psycopg2):
"""Test connect_to_db(), switch on session_role."""
- monkeypatch.setattr(pg, 'HAS_PSYCOPG2', True)
+ monkeypatch.setattr(pg, 'psycopg', m_psycopg2)
monkeypatch.setattr(pg, 'psycopg2', m_psycopg2)
m_ansible_module.params['session_role'] = 'test_role'
@@ -265,8 +271,8 @@ class TestConnectToDb():
db_connection, dummy = pg.connect_to_db(m_ansible_module, conn_params)
cursor = db_connection.cursor()
# if errors, db_connection returned as None:
- assert type(db_connection) == DbConnection
- assert type(cursor) == Cursor
+ assert type(db_connection) is DbConnection
+ assert type(cursor) is Cursor
assert m_ansible_module.err_msg == ''
# The default behaviour, normal in this case:
assert 'Database name has not been passed' in m_ansible_module.warn_msg
@@ -275,8 +281,7 @@ class TestConnectToDb():
"""
Test connect_to_db(), fail_on_conn arg passed as True (the default behavior).
"""
- monkeypatch.setattr(pg, 'HAS_PSYCOPG2', True)
- monkeypatch.setattr(pg, 'psycopg2', m_psycopg2)
+ monkeypatch.setattr(pg, 'psycopg', m_psycopg2)
m_ansible_module.params['login_user'] = 'Exception' # causes Exception
@@ -290,8 +295,7 @@ class TestConnectToDb():
"""
Test connect_to_db(), fail_on_conn arg passed as False.
"""
- monkeypatch.setattr(pg, 'HAS_PSYCOPG2', True)
- monkeypatch.setattr(pg, 'psycopg2', m_psycopg2)
+ monkeypatch.setattr(pg, 'psycopg', m_psycopg2)
m_ansible_module.params['login_user'] = 'Exception' # causes Exception
@@ -306,9 +310,9 @@ class TestConnectToDb():
"""
Test connect_to_db(), autocommit arg passed as True (the default is False).
"""
- monkeypatch.setattr(pg, 'HAS_PSYCOPG2', True)
# case 1: psycopg2.__version >= 2.4.2 (the default in m_psycopg2)
+ monkeypatch.setattr(pg, 'psycopg', m_psycopg2)
monkeypatch.setattr(pg, 'psycopg2', m_psycopg2)
conn_params = pg.get_conn_params(m_ansible_module, m_ansible_module.params)
@@ -316,8 +320,8 @@ class TestConnectToDb():
cursor = db_connection.cursor()
# if errors, db_connection returned as None:
- assert type(db_connection) == DbConnection
- assert type(cursor) == Cursor
+ assert type(db_connection) is DbConnection
+ assert type(cursor) is Cursor
assert m_ansible_module.err_msg == ''
@@ -327,12 +331,12 @@ class TestGetConnParams():
def test_get_conn_params_def(self, m_ansible_module, m_psycopg2, monkeypatch):
"""Test get_conn_params(), warn_db_default kwarg is default."""
- monkeypatch.setattr(pg, 'psycopg2', m_psycopg2)
+ monkeypatch.setattr(pg, 'psycopg', m_psycopg2)
assert pg.get_conn_params(m_ansible_module, INPUT_DICT) == EXPECTED_DICT
assert m_ansible_module.warn_msg == 'Database name has not been passed, used default database to connect to.'
def test_get_conn_params_warn_db_def_false(self, m_ansible_module, m_psycopg2, monkeypatch):
"""Test get_conn_params(), warn_db_default kwarg is False."""
- monkeypatch.setattr(pg, 'psycopg2', m_psycopg2)
+ monkeypatch.setattr(pg, 'psycopg', m_psycopg2)
assert pg.get_conn_params(m_ansible_module, INPUT_DICT, warn_db_default=False) == EXPECTED_DICT
assert m_ansible_module.warn_msg == ''
diff --git a/ansible_collections/community/postgresql/tests/unit/plugins/module_utils/test_saslprep.py b/ansible_collections/community/postgresql/tests/unit/plugins/module_utils/test_saslprep.py
index 62a1704ad..a93bf3f79 100644
--- a/ansible_collections/community/postgresql/tests/unit/plugins/module_utils/test_saslprep.py
+++ b/ansible_collections/community/postgresql/tests/unit/plugins/module_utils/test_saslprep.py
@@ -2,13 +2,13 @@
# Copyright: (c) 2019, Andrey Tuzhilin <andrei.tuzhilin@gmail.com>
# Copyright: (c) 2020, Andrew Klychkov (@Andersson007) <aaklychkov@mail.ru>
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
import pytest
-
-from ansible_collections.community.postgresql.plugins.module_utils.saslprep import saslprep
-
+from ansible_collections.community.postgresql.plugins.module_utils.saslprep import \
+ saslprep
VALID = [
(u'', u''),
@@ -51,5 +51,5 @@ def test_saslprep_conversions(source, target):
@pytest.mark.parametrize('source,exception', INVALID)
def test_saslprep_exceptions(source, exception):
- with pytest.raises(exception) as ex:
+ with pytest.raises(exception):
saslprep(source)
diff --git a/ansible_collections/community/postgresql/tests/unit/plugins/modules/test_postgresql_set.py b/ansible_collections/community/postgresql/tests/unit/plugins/modules/test_postgresql_set.py
index a10678202..8850df251 100644
--- a/ansible_collections/community/postgresql/tests/unit/plugins/modules/test_postgresql_set.py
+++ b/ansible_collections/community/postgresql/tests/unit/plugins/modules/test_postgresql_set.py
@@ -1,12 +1,13 @@
# -*- coding: utf-8 -*-
# Copyright: (c) 2021, Andrew Klychkov (@Andersson007) <aaklychkov@mail.ru>
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
import pytest
-
-from ansible_collections.community.postgresql.plugins.modules.postgresql_set import pretty_to_bytes
+from ansible_collections.community.postgresql.plugins.modules.postgresql_set import \
+ pretty_to_bytes
@pytest.mark.parametrize('input_,expected', [
diff --git a/ansible_collections/community/postgresql/tests/utils/shippable/check_matrix.py b/ansible_collections/community/postgresql/tests/utils/shippable/check_matrix.py
index 608db6923..e0115c124 100755
--- a/ansible_collections/community/postgresql/tests/utils/shippable/check_matrix.py
+++ b/ansible_collections/community/postgresql/tests/utils/shippable/check_matrix.py
@@ -1,6 +1,7 @@
#!/usr/bin/env python
"""Verify the currently executing Shippable test matrix matches the one defined in the "shippable.yml" file."""
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
import datetime
@@ -15,12 +16,7 @@ try:
except ImportError:
NoReturn = None
-try:
- # noinspection PyCompatibility
- from urllib2 import urlopen # pylint: disable=ansible-bad-import-from
-except ImportError:
- # noinspection PyCompatibility
- from urllib.request import urlopen
+from ansible.module_utils.urls import open_url
def main(): # type: () -> None
@@ -47,7 +43,7 @@ def main(): # type: () -> None
for attempts_remaining in range(4, -1, -1):
try:
- jobs = json.loads(urlopen('https://api.shippable.com/jobs?runIds=%s' % run_id).read())
+ jobs = json.loads(open_url('https://api.shippable.com/jobs?runIds=%s' % run_id).read())
if not isinstance(jobs, list):
raise Exception('Shippable run %s data is not a list.' % run_id)
diff --git a/ansible_collections/community/postgresql/tests/utils/shippable/shippable.sh b/ansible_collections/community/postgresql/tests/utils/shippable/shippable.sh
index b181297f9..818324edd 100755
--- a/ansible_collections/community/postgresql/tests/utils/shippable/shippable.sh
+++ b/ansible_collections/community/postgresql/tests/utils/shippable/shippable.sh
@@ -59,6 +59,7 @@ else
retry pip install "https://github.com/ansible/ansible/archive/stable-${ansible_version}.tar.gz" --disable-pip-version-check
fi
+# shellcheck disable=SC2153
if [ "${SHIPPABLE_BUILD_ID:-}" ]; then
export ANSIBLE_COLLECTIONS_PATHS="${HOME}/.ansible"
SHIPPABLE_RESULT_DIR="$(pwd)/shippable"
diff --git a/ansible_collections/community/postgresql/tests/utils/shippable/timing.py b/ansible_collections/community/postgresql/tests/utils/shippable/timing.py
index fb538271b..c6bf15532 100755
--- a/ansible_collections/community/postgresql/tests/utils/shippable/timing.py
+++ b/ansible_collections/community/postgresql/tests/utils/shippable/timing.py
@@ -1,5 +1,6 @@
#!/usr/bin/env python3.7
-from __future__ import (absolute_import, division, print_function)
+from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
import sys
diff --git a/ansible_collections/community/postgresql/tox.ini b/ansible_collections/community/postgresql/tox.ini
new file mode 100644
index 000000000..48a491cd5
--- /dev/null
+++ b/ansible_collections/community/postgresql/tox.ini
@@ -0,0 +1,14 @@
+[tox]
+envlist = lint
+isolated_build = true
+[testenv:lint]
+skip_install = true
+commands =
+ flake8 .
+ codespell
+deps =
+ flake8
+ codespell
+
+[pycodestyle]
+ignore = E226,E302,E71
diff --git a/ansible_collections/community/routeros/.github/workflows/ansible-test.yml b/ansible_collections/community/routeros/.github/workflows/ansible-test.yml
index a5b351913..0444f593f 100644
--- a/ansible_collections/community/routeros/.github/workflows/ansible-test.yml
+++ b/ansible_collections/community/routeros/.github/workflows/ansible-test.yml
@@ -33,6 +33,7 @@ jobs:
- stable-2.13
- stable-2.14
- stable-2.15
+ - stable-2.16
- devel
# Ansible-test on various stable branches does not yet work well with cgroups v2.
# Since ubuntu-latest now uses Ubuntu 22.04, we need to fall back to the ubuntu-20.04
@@ -77,6 +78,7 @@ jobs:
- stable-2.13
- stable-2.14
- stable-2.15
+ - stable-2.16
- devel
steps:
@@ -109,7 +111,6 @@ jobs:
ansible:
- devel
python:
- - 3.9
- "3.10"
- "3.11"
include:
@@ -134,10 +135,13 @@ jobs:
python: "3.10"
# 2.14
- ansible: stable-2.14
- python: "3.9"
+ python: "3.11"
# 2.15
- ansible: stable-2.15
- python: "3.11"
+ python: "3.9"
+ # 2.16
+ - ansible: stable-2.16
+ python: "3.10"
steps:
- name: >-
diff --git a/ansible_collections/community/routeros/.github/workflows/docs-pr.yml b/ansible_collections/community/routeros/.github/workflows/docs-pr.yml
index 4b3f1f373..14a917a5a 100644
--- a/ansible_collections/community/routeros/.github/workflows/docs-pr.yml
+++ b/ansible_collections/community/routeros/.github/workflows/docs-pr.yml
@@ -32,6 +32,8 @@ jobs:
init-extra-html-theme-options: |
documentation_home_url=https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/branch/main/
render-file-line: '> * `$<status>` [$<path_tail>](https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/pr/${{ github.event.number }}/$<path_tail>)'
+ provide-link-targets: |
+ ansible_collections.ansible.netcommon.network_cli_connection__parameter-ssh_type
publish-docs-gh-pages:
# for now we won't run this on forks
diff --git a/ansible_collections/community/routeros/.github/workflows/docs-push.yml b/ansible_collections/community/routeros/.github/workflows/docs-push.yml
index 7408bbb6f..e4595dd1e 100644
--- a/ansible_collections/community/routeros/.github/workflows/docs-push.yml
+++ b/ansible_collections/community/routeros/.github/workflows/docs-push.yml
@@ -28,7 +28,7 @@ jobs:
uses: ansible-community/github-docs-build/.github/workflows/_shared-docs-build-push.yml@main
with:
collection-name: community.routeros
- init-lenient: false
+ init-lenient: true
init-fail-on-error: true
squash-hierarchy: true
init-project: Community.Routeros Collection
diff --git a/ansible_collections/community/routeros/.github/workflows/ee.yml b/ansible_collections/community/routeros/.github/workflows/ee.yml
index 406703a07..523efaf58 100644
--- a/ansible_collections/community/routeros/.github/workflows/ee.yml
+++ b/ansible_collections/community/routeros/.github/workflows/ee.yml
@@ -46,6 +46,10 @@ jobs:
- name: ansible-core devel @ RHEL UBI 9
ansible_core: https://github.com/ansible/ansible/archive/devel.tar.gz
ansible_runner: ansible-runner
+ other_deps: |2
+ python_interpreter:
+ package_system: python3.11 python3.11-pip python3.11-wheel python3.11-cryptography
+ python_path: "/usr/bin/python3.11"
base_image: docker.io/redhat/ubi9:latest
pre_base: '"#"'
- name: ansible-core 2.15 @ Rocky Linux 9
@@ -77,12 +81,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
path: ansible_collections/${{ env.NAMESPACE }}/${{ env.COLLECTION_NAME }}
- name: Set up Python
- uses: actions/setup-python@v4
+ uses: actions/setup-python@v5
with:
python-version: '3.11'
diff --git a/ansible_collections/community/routeros/.github/workflows/extra-tests.yml b/ansible_collections/community/routeros/.github/workflows/extra-tests.yml
index 0bbcdbb38..54872aab0 100644
--- a/ansible_collections/community/routeros/.github/workflows/extra-tests.yml
+++ b/ansible_collections/community/routeros/.github/workflows/extra-tests.yml
@@ -26,22 +26,25 @@ jobs:
steps:
- name: Check out code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
path: ansible_collections/${{env.NAMESPACE}}/${{env.COLLECTION_NAME}}
- name: Set up Python
- uses: actions/setup-python@v4
+ uses: actions/setup-python@v5
with:
- python-version: '3.10'
+ python-version: '3.11'
- name: Install ansible-core
run: pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check
- name: Install collection dependencies
- run: git clone --depth=1 --single-branch https://github.com/ansible-collections/community.internal_test_tools.git ./ansible_collections/community/internal_test_tools
+ run: |
+ git clone --depth=1 --single-branch https://github.com/ansible-collections/community.internal_test_tools.git ./ansible_collections/community/internal_test_tools
+ git clone --depth=1 --single-branch https://github.com/ansible-collections/ansible.netcommon.git ./ansible_collections/ansible/netcommon
+ git clone --depth=1 --single-branch https://github.com/ansible-collections/ansible.utils.git ./ansible_collections/ansible/utils
# NOTE: we're installing with git to work around Galaxy being a huge PITA (https://github.com/ansible/galaxy/issues/2429)
- # run: ansible-galaxy collection install community.internal_test_tools -p .
+ # run: ansible-galaxy collection install community.internal_test_tools ansible.netcommon -p .
- name: Run sanity tests
run: ../../community/internal_test_tools/tools/run.py --color
diff --git a/ansible_collections/community/routeros/.github/workflows/import-galaxy.yml b/ansible_collections/community/routeros/.github/workflows/import-galaxy.yml
index 55a731035..0c0ee402a 100644
--- a/ansible_collections/community/routeros/.github/workflows/import-galaxy.yml
+++ b/ansible_collections/community/routeros/.github/workflows/import-galaxy.yml
@@ -4,7 +4,7 @@
# SPDX-License-Identifier: GPL-3.0-or-later
name: import-galaxy
-on:
+'on':
# Run CI against all pushes (direct commits, also merged PRs) to main, and all Pull Requests
push:
branches:
@@ -12,77 +12,9 @@ on:
- stable-*
pull_request:
-env:
- # Adjust this to your collection
- NAMESPACE: community
- COLLECTION_NAME: routeros
-
jobs:
- build-collection:
- name: Build collection artifact
- runs-on: ubuntu-latest
- steps:
- - name: Check out code
- uses: actions/checkout@v3
- with:
- path: ./checkout
-
- - name: Set up Python
- uses: actions/setup-python@v4
- with:
- python-version: '3.10'
-
- - name: Install ansible-core
- run: pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check
-
- - name: Make sure galaxy.yml has version entry
- run: >-
- python -c
- 'import yaml ;
- f = open("galaxy.yml", "rb") ;
- data = yaml.safe_load(f) ;
- f.close() ;
- data["version"] = data.get("version") or "0.0.1" ;
- f = open("galaxy.yml", "wb") ;
- f.write(yaml.dump(data).encode("utf-8")) ;
- f.close() ;
- '
- working-directory: ./checkout
-
- - name: Build collection
- run: ansible-galaxy collection build
- working-directory: ./checkout
-
- - name: Copy artifact into subdirectory
- run: mkdir ./artifact && mv ./checkout/${{ env.NAMESPACE }}-${{ env.COLLECTION_NAME }}-*.tar.gz ./artifact
-
- - name: Upload artifact
- uses: actions/upload-artifact@v3
- with:
- name: ${{ env.NAMESPACE }}-${{ env.COLLECTION_NAME }}-${{ github.sha }}
- path: ./artifact/
-
import-galaxy:
- name: Import artifact with Galaxy importer
- runs-on: ubuntu-latest
- needs:
- - build-collection
- steps:
- - name: Set up Python
- uses: actions/setup-python@v4
- with:
- python-version: '3.10'
-
- - name: Install ansible-core
- run: pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check
-
- - name: Install galaxy-importer
- run: pip install galaxy-importer --disable-pip-version-check
-
- - name: Download artifact
- uses: actions/download-artifact@v3
- with:
- name: ${{ env.NAMESPACE }}-${{ env.COLLECTION_NAME }}-${{ github.sha }}
-
- - name: Run Galaxy importer
- run: python -m galaxy_importer.main ${{ env.NAMESPACE }}-${{ env.COLLECTION_NAME }}-*.tar.gz
+ permissions:
+ contents: read
+ name: Test to import built collection artifact with Galaxy importer
+ uses: ansible-community/github-action-test-galaxy-import/.github/workflows/test-galaxy-import.yml@main
diff --git a/ansible_collections/community/routeros/.github/workflows/reuse.yml b/ansible_collections/community/routeros/.github/workflows/reuse.yml
index acd7bc8a7..b6732cc42 100644
--- a/ansible_collections/community/routeros/.github/workflows/reuse.yml
+++ b/ansible_collections/community/routeros/.github/workflows/reuse.yml
@@ -21,12 +21,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- - name: Install dependencies
- run: |
- pip install reuse
-
- - name: Check REUSE compliance
- run: |
- reuse lint
+ - name: REUSE Compliance Check
+ uses: fsfe/reuse-action@v3
diff --git a/ansible_collections/community/routeros/CHANGELOG.md b/ansible_collections/community/routeros/CHANGELOG.md
new file mode 100644
index 000000000..99d0bbe6a
--- /dev/null
+++ b/ansible_collections/community/routeros/CHANGELOG.md
@@ -0,0 +1,631 @@
+# Community RouterOS Release Notes
+
+**Topics**
+
+- <a href="#v2-14-0">v2\.14\.0</a>
+ - <a href="#release-summary">Release Summary</a>
+ - <a href="#minor-changes">Minor Changes</a>
+- <a href="#v2-13-0">v2\.13\.0</a>
+ - <a href="#release-summary-1">Release Summary</a>
+ - <a href="#minor-changes-1">Minor Changes</a>
+ - <a href="#bugfixes">Bugfixes</a>
+- <a href="#v2-12-0">v2\.12\.0</a>
+ - <a href="#release-summary-2">Release Summary</a>
+ - <a href="#minor-changes-2">Minor Changes</a>
+- <a href="#v2-11-0">v2\.11\.0</a>
+ - <a href="#release-summary-3">Release Summary</a>
+ - <a href="#minor-changes-3">Minor Changes</a>
+- <a href="#v2-10-0">v2\.10\.0</a>
+ - <a href="#release-summary-4">Release Summary</a>
+ - <a href="#minor-changes-4">Minor Changes</a>
+ - <a href="#bugfixes-1">Bugfixes</a>
+- <a href="#v2-9-0">v2\.9\.0</a>
+ - <a href="#release-summary-5">Release Summary</a>
+ - <a href="#minor-changes-5">Minor Changes</a>
+ - <a href="#bugfixes-2">Bugfixes</a>
+- <a href="#v2-8-3">v2\.8\.3</a>
+ - <a href="#release-summary-6">Release Summary</a>
+ - <a href="#known-issues">Known Issues</a>
+- <a href="#v2-8-2">v2\.8\.2</a>
+ - <a href="#release-summary-7">Release Summary</a>
+ - <a href="#bugfixes-3">Bugfixes</a>
+- <a href="#v2-8-1">v2\.8\.1</a>
+ - <a href="#release-summary-8">Release Summary</a>
+ - <a href="#bugfixes-4">Bugfixes</a>
+- <a href="#v2-8-0">v2\.8\.0</a>
+ - <a href="#release-summary-9">Release Summary</a>
+ - <a href="#minor-changes-6">Minor Changes</a>
+ - <a href="#bugfixes-5">Bugfixes</a>
+- <a href="#v2-7-0">v2\.7\.0</a>
+ - <a href="#release-summary-10">Release Summary</a>
+ - <a href="#minor-changes-7">Minor Changes</a>
+ - <a href="#bugfixes-6">Bugfixes</a>
+- <a href="#v2-6-0">v2\.6\.0</a>
+ - <a href="#release-summary-11">Release Summary</a>
+ - <a href="#minor-changes-8">Minor Changes</a>
+ - <a href="#bugfixes-7">Bugfixes</a>
+- <a href="#v2-5-0">v2\.5\.0</a>
+ - <a href="#release-summary-12">Release Summary</a>
+ - <a href="#minor-changes-9">Minor Changes</a>
+ - <a href="#bugfixes-8">Bugfixes</a>
+- <a href="#v2-4-0">v2\.4\.0</a>
+ - <a href="#release-summary-13">Release Summary</a>
+ - <a href="#minor-changes-10">Minor Changes</a>
+ - <a href="#bugfixes-9">Bugfixes</a>
+ - <a href="#known-issues-1">Known Issues</a>
+- <a href="#v2-3-1">v2\.3\.1</a>
+ - <a href="#release-summary-14">Release Summary</a>
+ - <a href="#known-issues-2">Known Issues</a>
+- <a href="#v2-3-0">v2\.3\.0</a>
+ - <a href="#release-summary-15">Release Summary</a>
+ - <a href="#minor-changes-11">Minor Changes</a>
+ - <a href="#bugfixes-10">Bugfixes</a>
+- <a href="#v2-2-1">v2\.2\.1</a>
+ - <a href="#release-summary-16">Release Summary</a>
+ - <a href="#bugfixes-11">Bugfixes</a>
+- <a href="#v2-2-0">v2\.2\.0</a>
+ - <a href="#release-summary-17">Release Summary</a>
+ - <a href="#minor-changes-12">Minor Changes</a>
+ - <a href="#bugfixes-12">Bugfixes</a>
+ - <a href="#new-modules">New Modules</a>
+- <a href="#v2-1-0">v2\.1\.0</a>
+ - <a href="#release-summary-18">Release Summary</a>
+ - <a href="#minor-changes-13">Minor Changes</a>
+ - <a href="#bugfixes-13">Bugfixes</a>
+ - <a href="#new-modules-1">New Modules</a>
+- <a href="#v2-0-0">v2\.0\.0</a>
+ - <a href="#release-summary-19">Release Summary</a>
+ - <a href="#minor-changes-14">Minor Changes</a>
+ - <a href="#breaking-changes--porting-guide">Breaking Changes / Porting Guide</a>
+ - <a href="#bugfixes-14">Bugfixes</a>
+ - <a href="#new-plugins">New Plugins</a>
+ - <a href="#filter">Filter</a>
+- <a href="#v1-2-0">v1\.2\.0</a>
+ - <a href="#release-summary-20">Release Summary</a>
+ - <a href="#minor-changes-15">Minor Changes</a>
+ - <a href="#bugfixes-15">Bugfixes</a>
+- <a href="#v1-1-0">v1\.1\.0</a>
+ - <a href="#release-summary-21">Release Summary</a>
+ - <a href="#minor-changes-16">Minor Changes</a>
+- <a href="#v1-0-1">v1\.0\.1</a>
+ - <a href="#release-summary-22">Release Summary</a>
+ - <a href="#bugfixes-16">Bugfixes</a>
+- <a href="#v1-0-0">v1\.0\.0</a>
+ - <a href="#release-summary-23">Release Summary</a>
+ - <a href="#bugfixes-17">Bugfixes</a>
+- <a href="#v0-1-1">v0\.1\.1</a>
+ - <a href="#release-summary-24">Release Summary</a>
+ - <a href="#bugfixes-18">Bugfixes</a>
+- <a href="#v0-1-0">v0\.1\.0</a>
+ - <a href="#release-summary-25">Release Summary</a>
+ - <a href="#minor-changes-17">Minor Changes</a>
+
+<a id="v2-14-0"></a>
+## v2\.14\.0
+
+<a id="release-summary"></a>
+### Release Summary
+
+Feature release\.
+
+<a id="minor-changes"></a>
+### Minor Changes
+
+* api\_info\, api\_modify \- add read\-only fields <code>installed\-version</code>\, <code>latest\-version</code> and <code>status</code> in <code>system package update</code> \([https\://github\.com/ansible\-collections/community\.routeros/pull/263](https\://github\.com/ansible\-collections/community\.routeros/pull/263)\)\.
+* api\_info\, api\_modify \- added support for <code>interface wifi</code> and its sub\-paths \([https\://github\.com/ansible\-collections/community\.routeros/pull/266](https\://github\.com/ansible\-collections/community\.routeros/pull/266)\)\.
+* api\_info\, api\_modify \- remove default value for read\-only <code>running</code> field in <code>interface wireless</code> \([https\://github\.com/ansible\-collections/community\.routeros/pull/264](https\://github\.com/ansible\-collections/community\.routeros/pull/264)\)\.
+
+<a id="v2-13-0"></a>
+## v2\.13\.0
+
+<a id="release-summary-1"></a>
+### Release Summary
+
+Bugfix and feature release\.
+
+<a id="minor-changes-1"></a>
+### Minor Changes
+
+* api\_info\, api\_modify \- make path <code>user group</code> modifiable and add <code>comment</code> attribute \([https\://github\.com/ansible\-collections/community\.routeros/issues/256](https\://github\.com/ansible\-collections/community\.routeros/issues/256)\, [https\://github\.com/ansible\-collections/community\.routeros/pull/257](https\://github\.com/ansible\-collections/community\.routeros/pull/257)\)\.
+* api\_modify\, api\_info \- add support for the <code>ip vrf</code> path in RouterOS 7 \([https\://github\.com/ansible\-collections/community\.routeros/pull/259](https\://github\.com/ansible\-collections/community\.routeros/pull/259)\)
+
+<a id="bugfixes"></a>
+### Bugfixes
+
+* facts \- fix date not getting removed for idempotent config export \([https\://github\.com/ansible\-collections/community\.routeros/pull/262](https\://github\.com/ansible\-collections/community\.routeros/pull/262)\)\.
+
+<a id="v2-12-0"></a>
+## v2\.12\.0
+
+<a id="release-summary-2"></a>
+### Release Summary
+
+Feature release\.
+
+<a id="minor-changes-2"></a>
+### Minor Changes
+
+* api\_info\, api\_modify \- add <code>interface ovpn\-client</code> path \([https\://github\.com/ansible\-collections/community\.routeros/issues/242](https\://github\.com/ansible\-collections/community\.routeros/issues/242)\, [https\://github\.com/ansible\-collections/community\.routeros/pull/244](https\://github\.com/ansible\-collections/community\.routeros/pull/244)\)\.
+* api\_info\, api\_modify \- add <code>radius</code> path \([https\://github\.com/ansible\-collections/community\.routeros/issues/241](https\://github\.com/ansible\-collections/community\.routeros/issues/241)\, [https\://github\.com/ansible\-collections/community\.routeros/pull/245](https\://github\.com/ansible\-collections/community\.routeros/pull/245)\)\.
+* api\_info\, api\_modify \- add <code>routing rule</code> path \([https\://github\.com/ansible\-collections/community\.routeros/issues/162](https\://github\.com/ansible\-collections/community\.routeros/issues/162)\, [https\://github\.com/ansible\-collections/community\.routeros/pull/246](https\://github\.com/ansible\-collections/community\.routeros/pull/246)\)\.
+* api\_info\, api\_modify \- add missing path <code>routing bgp template</code> \([https\://github\.com/ansible\-collections/community\.routeros/pull/243](https\://github\.com/ansible\-collections/community\.routeros/pull/243)\)\.
+* api\_info\, api\_modify \- add support for the <code>tx\-power</code> attribute in <code>interface wireless</code> \([https\://github\.com/ansible\-collections/community\.routeros/pull/239](https\://github\.com/ansible\-collections/community\.routeros/pull/239)\)\.
+* api\_info\, api\_modify \- removed <code>host</code> primary key in <code>tool netwatch</code> path \([https\://github\.com/ansible\-collections/community\.routeros/pull/248](https\://github\.com/ansible\-collections/community\.routeros/pull/248)\)\.
+* api\_modify\, api\_info \- added support for <code>interface wifiwave2</code> \([https\://github\.com/ansible\-collections/community\.routeros/pull/226](https\://github\.com/ansible\-collections/community\.routeros/pull/226)\)\.
+
+<a id="v2-11-0"></a>
+## v2\.11\.0
+
+<a id="release-summary-3"></a>
+### Release Summary
+
+Feature and bugfix release\.
+
+<a id="minor-changes-3"></a>
+### Minor Changes
+
+* api\_info\, api\_modify \- add missing DoH parameters <code>doh\-max\-concurrent\-queries</code>\, <code>doh\-max\-server\-connections</code>\, and <code>doh\-timeout</code> to the <code>ip dns</code> path \([https\://github\.com/ansible\-collections/community\.routeros/issues/230](https\://github\.com/ansible\-collections/community\.routeros/issues/230)\, [https\://github\.com/ansible\-collections/community\.routeros/pull/235](https\://github\.com/ansible\-collections/community\.routeros/pull/235)\)
+* api\_info\, api\_modify \- add missing parameters <code>address\-list</code>\, <code>address\-list\-timeout</code>\, <code>randomise\-ports</code>\, and <code>realm</code> to subpaths of the <code>ip firewall</code> path \([https\://github\.com/ansible\-collections/community\.routeros/issues/236](https\://github\.com/ansible\-collections/community\.routeros/issues/236)\, [https\://github\.com/ansible\-collections/community\.routeros/pull/237](https\://github\.com/ansible\-collections/community\.routeros/pull/237)\)\.
+* api\_info\, api\_modify \- mark the <code>interface wireless</code> parameter <code>running</code> as read\-only \([https\://github\.com/ansible\-collections/community\.routeros/pull/233](https\://github\.com/ansible\-collections/community\.routeros/pull/233)\)\.
+* api\_info\, api\_modify \- set the default value to <code>false</code> for the <code>disabled</code> parameter in some more paths where it can be seen in the documentation \([https\://github\.com/ansible\-collections/community\.routeros/pull/237](https\://github\.com/ansible\-collections/community\.routeros/pull/237)\)\.
+* api\_modify \- add missing <code>comment</code> attribute to <code>/routing id</code> \([https\://github\.com/ansible\-collections/community\.routeros/pull/234](https\://github\.com/ansible\-collections/community\.routeros/pull/234)\)\.
+* api\_modify \- add missing attributes to the <code>routing bgp connection</code> path \([https\://github\.com/ansible\-collections/community\.routeros/pull/234](https\://github\.com/ansible\-collections/community\.routeros/pull/234)\)\.
+* api\_modify \- add versioning to the <code>/tool e\-mail</code> path \(RouterOS 7\.12 release\) \([https\://github\.com/ansible\-collections/community\.routeros/pull/234](https\://github\.com/ansible\-collections/community\.routeros/pull/234)\)\.
+* api\_modify \- make <code>/ip traffic\-flow target</code> a multiple value attribute \([https\://github\.com/ansible\-collections/community\.routeros/pull/234](https\://github\.com/ansible\-collections/community\.routeros/pull/234)\)\.
+
+<a id="v2-10-0"></a>
+## v2\.10\.0
+
+<a id="release-summary-4"></a>
+### Release Summary
+
+Bugfix and feature release\.
+
+<a id="minor-changes-4"></a>
+### Minor Changes
+
+* api\_info \- add new <code>include\_read\_only</code> option to select behavior for read\-only values\. By default these are not returned \([https\://github\.com/ansible\-collections/community\.routeros/pull/213](https\://github\.com/ansible\-collections/community\.routeros/pull/213)\)\.
+* api\_info\, api\_modify \- add support for <code>address\-list</code> and <code>match\-subdomain</code> introduced by RouterOS 7\.7 in the <code>ip dns static</code> path \([https\://github\.com/ansible\-collections/community\.routeros/pull/197](https\://github\.com/ansible\-collections/community\.routeros/pull/197)\)\.
+* api\_info\, api\_modify \- add support for <code>user</code>\, <code>time</code> and <code>gmt\-offset</code> under the <code>system clock</code> path \([https\://github\.com/ansible\-collections/community\.routeros/pull/210](https\://github\.com/ansible\-collections/community\.routeros/pull/210)\)\.
+* api\_info\, api\_modify \- add support for the <code>interface ppp\-client</code> path \([https\://github\.com/ansible\-collections/community\.routeros/pull/199](https\://github\.com/ansible\-collections/community\.routeros/pull/199)\)\.
+* api\_info\, api\_modify \- add support for the <code>interface wireless</code> path \([https\://github\.com/ansible\-collections/community\.routeros/pull/195](https\://github\.com/ansible\-collections/community\.routeros/pull/195)\)\.
+* api\_info\, api\_modify \- add support for the <code>iot modbus</code> path \([https\://github\.com/ansible\-collections/community\.routeros/pull/205](https\://github\.com/ansible\-collections/community\.routeros/pull/205)\)\.
+* api\_info\, api\_modify \- add support for the <code>ip dhcp\-server option</code> and <code>ip dhcp\-server option sets</code> paths \([https\://github\.com/ansible\-collections/community\.routeros/pull/223](https\://github\.com/ansible\-collections/community\.routeros/pull/223)\)\.
+* api\_info\, api\_modify \- add support for the <code>ip upnp interfaces</code>\, <code>tool graphing interface</code>\, <code>tool graphing resource</code> paths \([https\://github\.com/ansible\-collections/community\.routeros/pull/227](https\://github\.com/ansible\-collections/community\.routeros/pull/227)\)\.
+* api\_info\, api\_modify \- add support for the <code>ipv6 firewall nat</code> path \([https\://github\.com/ansible\-collections/community\.routeros/pull/204](https\://github\.com/ansible\-collections/community\.routeros/pull/204)\)\.
+* api\_info\, api\_modify \- add support for the <code>mode</code> property in <code>ip neighbor discovery\-settings</code> introduced in RouterOS 7\.7 \([https\://github\.com/ansible\-collections/community\.routeros/pull/198](https\://github\.com/ansible\-collections/community\.routeros/pull/198)\)\.
+* api\_info\, api\_modify \- add support for the <code>port remote\-access</code> path \([https\://github\.com/ansible\-collections/community\.routeros/pull/224](https\://github\.com/ansible\-collections/community\.routeros/pull/224)\)\.
+* api\_info\, api\_modify \- add support for the <code>routing filter rule</code> and <code>routing filter select\-rule</code> paths \([https\://github\.com/ansible\-collections/community\.routeros/pull/200](https\://github\.com/ansible\-collections/community\.routeros/pull/200)\)\.
+* api\_info\, api\_modify \- add support for the <code>routing table</code> path in RouterOS 7 \([https\://github\.com/ansible\-collections/community\.routeros/pull/215](https\://github\.com/ansible\-collections/community\.routeros/pull/215)\)\.
+* api\_info\, api\_modify \- add support for the <code>tool netwatch</code> path in RouterOS 7 \([https\://github\.com/ansible\-collections/community\.routeros/pull/216](https\://github\.com/ansible\-collections/community\.routeros/pull/216)\)\.
+* api\_info\, api\_modify \- add support for the <code>user settings</code> path \([https\://github\.com/ansible\-collections/community\.routeros/pull/201](https\://github\.com/ansible\-collections/community\.routeros/pull/201)\)\.
+* api\_info\, api\_modify \- add support for the <code>user</code> path \([https\://github\.com/ansible\-collections/community\.routeros/pull/211](https\://github\.com/ansible\-collections/community\.routeros/pull/211)\)\.
+* api\_info\, api\_modify \- finalize fields for the <code>interface wireless security\-profiles</code> path and enable it \([https\://github\.com/ansible\-collections/community\.routeros/pull/203](https\://github\.com/ansible\-collections/community\.routeros/pull/203)\)\.
+* api\_info\, api\_modify \- finalize fields for the <code>ppp profile</code> path and enable it \([https\://github\.com/ansible\-collections/community\.routeros/pull/217](https\://github\.com/ansible\-collections/community\.routeros/pull/217)\)\.
+* api\_modify \- add new <code>handle\_read\_only</code> and <code>handle\_write\_only</code> options to handle the module\'s behavior for read\-only and write\-only fields \([https\://github\.com/ansible\-collections/community\.routeros/pull/213](https\://github\.com/ansible\-collections/community\.routeros/pull/213)\)\.
+* api\_modify\, api\_info \- support API paths <code>routing id</code>\, <code>routing bgp connection</code> \([https\://github\.com/ansible\-collections/community\.routeros/pull/220](https\://github\.com/ansible\-collections/community\.routeros/pull/220)\)\.
+
+<a id="bugfixes-1"></a>
+### Bugfixes
+
+* api\_info\, api\_modify \- in the <code>snmp</code> path\, ensure that <code>engine\-id\-suffix</code> is only available on RouterOS 7\.10\+\, and that <code>engine\-id</code> is read\-only on RouterOS 7\.10\+ \([https\://github\.com/ansible\-collections/community\.routeros/issues/208](https\://github\.com/ansible\-collections/community\.routeros/issues/208)\, [https\://github\.com/ansible\-collections/community\.routeros/pull/218](https\://github\.com/ansible\-collections/community\.routeros/pull/218)\)\.
+
+<a id="v2-9-0"></a>
+## v2\.9\.0
+
+<a id="release-summary-5"></a>
+### Release Summary
+
+Bugfix and feature release\.
+
+<a id="minor-changes-5"></a>
+### Minor Changes
+
+* api\_info\, api\_modify \- add path <code>caps\-man channel</code> and enable path <code>caps\-man manager interface</code> \([https\://github\.com/ansible\-collections/community\.routeros/issues/193](https\://github\.com/ansible\-collections/community\.routeros/issues/193)\, [https\://github\.com/ansible\-collections/community\.routeros/pull/194](https\://github\.com/ansible\-collections/community\.routeros/pull/194)\)\.
+* api\_info\, api\_modify \- add path <code>ip traffic\-flow target</code> \([https\://github\.com/ansible\-collections/community\.routeros/issues/191](https\://github\.com/ansible\-collections/community\.routeros/issues/191)\, [https\://github\.com/ansible\-collections/community\.routeros/pull/192](https\://github\.com/ansible\-collections/community\.routeros/pull/192)\)\.
+
+<a id="bugfixes-2"></a>
+### Bugfixes
+
+* api\_modify\, api\_info \- add missing parameter <code>engine\-id\-suffix</code> for the <code>snmp</code> path \([https\://github\.com/ansible\-collections/community\.routeros/issues/189](https\://github\.com/ansible\-collections/community\.routeros/issues/189)\, [https\://github\.com/ansible\-collections/community\.routeros/pull/190](https\://github\.com/ansible\-collections/community\.routeros/pull/190)\)\.
+
+<a id="v2-8-3"></a>
+## v2\.8\.3
+
+<a id="release-summary-6"></a>
+### Release Summary
+
+Maintenance release with updated documentation\.
+
+From this version on\, community\.routeros is using the new [Ansible semantic markup](https\://docs\.ansible\.com/ansible/devel/dev\_guide/developing\_modules\_documenting\.html\#semantic\-markup\-within\-module\-documentation)
+in its documentation\. If you look at documentation with the ansible\-doc CLI tool
+from ansible\-core before 2\.15\, please note that it does not render the markup
+correctly\. You should be still able to read it in most cases\, but you need
+ansible\-core 2\.15 or later to see it as it is intended\. Alternatively you can
+look at [the devel docsite](https\://docs\.ansible\.com/ansible/devel/collections/community/routeros/)
+for the rendered HTML version of the documentation of the latest release\.
+
+<a id="known-issues"></a>
+### Known Issues
+
+* Ansible markup will show up in raw form on ansible\-doc text output for ansible\-core before 2\.15\. If you have trouble deciphering the documentation markup\, please upgrade to ansible\-core 2\.15 \(or newer\)\, or read the HTML documentation on [https\://docs\.ansible\.com/ansible/devel/collections/community/routeros/](https\://docs\.ansible\.com/ansible/devel/collections/community/routeros/)\.
+
+<a id="v2-8-2"></a>
+## v2\.8\.2
+
+<a id="release-summary-7"></a>
+### Release Summary
+
+Bugfix release\.
+
+<a id="bugfixes-3"></a>
+### Bugfixes
+
+* api\_modify\, api\_info \- add missing parameter <code>tls</code> for the <code>tool e\-mail</code> path \([https\://github\.com/ansible\-collections/community\.routeros/issues/179](https\://github\.com/ansible\-collections/community\.routeros/issues/179)\, [https\://github\.com/ansible\-collections/community\.routeros/pull/180](https\://github\.com/ansible\-collections/community\.routeros/pull/180)\)\.
+
+<a id="v2-8-1"></a>
+## v2\.8\.1
+
+<a id="release-summary-8"></a>
+### Release Summary
+
+Bugfix release\.
+
+<a id="bugfixes-4"></a>
+### Bugfixes
+
+* facts \- do not crash in CLI output preprocessing in unexpected situations during line unwrapping \([https\://github\.com/ansible\-collections/community\.routeros/issues/170](https\://github\.com/ansible\-collections/community\.routeros/issues/170)\, [https\://github\.com/ansible\-collections/community\.routeros/pull/177](https\://github\.com/ansible\-collections/community\.routeros/pull/177)\)\.
+
+<a id="v2-8-0"></a>
+## v2\.8\.0
+
+<a id="release-summary-9"></a>
+### Release Summary
+
+Bugfix and feature release\.
+
+<a id="minor-changes-6"></a>
+### Minor Changes
+
+* api\_modify \- adapt data for API paths <code>ip dhcp\-server network</code> \([https\://github\.com/ansible\-collections/community\.routeros/pull/156](https\://github\.com/ansible\-collections/community\.routeros/pull/156)\)\.
+* api\_modify \- add support for API path <code>snmp community</code> \([https\://github\.com/ansible\-collections/community\.routeros/pull/159](https\://github\.com/ansible\-collections/community\.routeros/pull/159)\)\.
+* api\_modify \- add support for <code>trap\-interfaces</code> in API path <code>snmp</code> \([https\://github\.com/ansible\-collections/community\.routeros/pull/159](https\://github\.com/ansible\-collections/community\.routeros/pull/159)\)\.
+* api\_modify \- add support to disable IPv6 in API paths <code>ipv6 settings</code> \([https\://github\.com/ansible\-collections/community\.routeros/pull/158](https\://github\.com/ansible\-collections/community\.routeros/pull/158)\)\.
+* api\_modify \- support API paths <code>ip firewall layer7\-protocol</code> \([https\://github\.com/ansible\-collections/community\.routeros/pull/153](https\://github\.com/ansible\-collections/community\.routeros/pull/153)\)\.
+* command \- workaround for extra characters in stdout in RouterOS versions between 6\.49 and 7\.1\.5 \([https\://github\.com/ansible\-collections/community\.routeros/issues/62](https\://github\.com/ansible\-collections/community\.routeros/issues/62)\, [https\://github\.com/ansible\-collections/community\.routeros/pull/161](https\://github\.com/ansible\-collections/community\.routeros/pull/161)\)\.
+
+<a id="bugfixes-5"></a>
+### Bugfixes
+
+* api\_info\, api\_modify \- fix default and remove behavior for <code>dhcp\-options</code> in path <code>ip dhcp\-client</code> \([https\://github\.com/ansible\-collections/community\.routeros/issues/148](https\://github\.com/ansible\-collections/community\.routeros/issues/148)\, [https\://github\.com/ansible\-collections/community\.routeros/pull/154](https\://github\.com/ansible\-collections/community\.routeros/pull/154)\)\.
+* api\_modify \- fix handling of disabled keys on creation \([https\://github\.com/ansible\-collections/community\.routeros/pull/154](https\://github\.com/ansible\-collections/community\.routeros/pull/154)\)\.
+* various plugins and modules \- remove unnecessary imports \([https\://github\.com/ansible\-collections/community\.routeros/pull/149](https\://github\.com/ansible\-collections/community\.routeros/pull/149)\)\.
+
+<a id="v2-7-0"></a>
+## v2\.7\.0
+
+<a id="release-summary-10"></a>
+### Release Summary
+
+Bugfix and feature release\.
+
+<a id="minor-changes-7"></a>
+### Minor Changes
+
+* api\_modify\, api\_info \- support API paths <code>ip arp</code>\, <code>ip firewall raw</code>\, <code>ipv6 firewall raw</code> \([https\://github\.com/ansible\-collections/community\.routeros/pull/144](https\://github\.com/ansible\-collections/community\.routeros/pull/144)\)\.
+
+<a id="bugfixes-6"></a>
+### Bugfixes
+
+* api\_modify\, api\_info \- defaults corrected for fields in <code>interface wireguard peers</code> API path \([https\://github\.com/ansible\-collections/community\.routeros/pull/144](https\://github\.com/ansible\-collections/community\.routeros/pull/144)\)\.
+
+<a id="v2-6-0"></a>
+## v2\.6\.0
+
+<a id="release-summary-11"></a>
+### Release Summary
+
+Regular bugfix and feature release\.
+
+<a id="minor-changes-8"></a>
+### Minor Changes
+
+* api\_modify\, api\_info \- add field <code>regexp</code> to <code>ip dns static</code> \([https\://github\.com/ansible\-collections/community\.routeros/issues/141](https\://github\.com/ansible\-collections/community\.routeros/issues/141)\)\.
+* api\_modify\, api\_info \- support API paths <code>interface wireguard</code>\, <code>interface wireguard peers</code> \([https\://github\.com/ansible\-collections/community\.routeros/pull/143](https\://github\.com/ansible\-collections/community\.routeros/pull/143)\)\.
+
+<a id="bugfixes-7"></a>
+### Bugfixes
+
+* api\_modify \- do not use <code>name</code> as a unique key in <code>ip dns static</code> \([https\://github\.com/ansible\-collections/community\.routeros/issues/141](https\://github\.com/ansible\-collections/community\.routeros/issues/141)\)\.
+* api\_modify\, api\_info \- do not crash if router contains <code>regexp</code> DNS entries in <code>ip dns static</code> \([https\://github\.com/ansible\-collections/community\.routeros/issues/141](https\://github\.com/ansible\-collections/community\.routeros/issues/141)\)\.
+
+<a id="v2-5-0"></a>
+## v2\.5\.0
+
+<a id="release-summary-12"></a>
+### Release Summary
+
+Feature and bugfix release\.
+
+<a id="minor-changes-9"></a>
+### Minor Changes
+
+* api\_info\, api\_modify \- support API paths <code>interface ethernet poe</code>\, <code>interface gre6</code>\, <code>interface vrrp</code> and also support all previously missing fields of entries in <code>ip dhcp\-server</code> \([https\://github\.com/ansible\-collections/community\.routeros/pull/137](https\://github\.com/ansible\-collections/community\.routeros/pull/137)\)\.
+
+<a id="bugfixes-8"></a>
+### Bugfixes
+
+* api\_modify \- <code>address\-pool</code> field of entries in API path <code>ip dhcp\-server</code> is not required anymore \([https\://github\.com/ansible\-collections/community\.routeros/pull/137](https\://github\.com/ansible\-collections/community\.routeros/pull/137)\)\.
+
+<a id="v2-4-0"></a>
+## v2\.4\.0
+
+<a id="release-summary-13"></a>
+### Release Summary
+
+Feature release improving the <code>api\*</code> modules\.
+
+<a id="minor-changes-10"></a>
+### Minor Changes
+
+* api\* modules \- Add new option <code>force\_no\_cert</code> to connect with ADH ciphers \([https\://github\.com/ansible\-collections/community\.routeros/pull/124](https\://github\.com/ansible\-collections/community\.routeros/pull/124)\)\.
+* api\_info \- new parameter <code>include\_builtin</code> which allows to include \"builtin\" entries that are automatically generated by ROS and cannot be modified by the user \([https\://github\.com/ansible\-collections/community\.routeros/pull/130](https\://github\.com/ansible\-collections/community\.routeros/pull/130)\)\.
+* api\_modify\, api\_info \- support API paths \- <code>interface bonding</code>\, <code>interface bridge mlag</code>\, <code>ipv6 firewall mangle</code>\, <code>ipv6 nd</code>\, <code>system scheduler</code>\, <code>system script</code>\, <code>system ups</code> \([https\://github\.com/ansible\-collections/community\.routeros/pull/133](https\://github\.com/ansible\-collections/community\.routeros/pull/133)\)\.
+* api\_modify\, api\_info \- support API paths <code>caps\-man access\-list</code>\, <code>caps\-man configuration</code>\, <code>caps\-man datapath</code>\, <code>caps\-man manager</code>\, <code>caps\-man provisioning</code>\, <code>caps\-man security</code> \([https\://github\.com/ansible\-collections/community\.routeros/pull/126](https\://github\.com/ansible\-collections/community\.routeros/pull/126)\)\.
+* api\_modify\, api\_info \- support API paths <code>interface list</code> and <code>interface list member</code> \([https\://github\.com/ansible\-collections/community\.routeros/pull/120](https\://github\.com/ansible\-collections/community\.routeros/pull/120)\)\.
+* api\_modify\, api\_info \- support API paths <code>interface pppoe\-client</code>\, <code>interface vlan</code>\, <code>interface bridge</code>\, <code>interface bridge vlan</code> \([https\://github\.com/ansible\-collections/community\.routeros/pull/125](https\://github\.com/ansible\-collections/community\.routeros/pull/125)\)\.
+* api\_modify\, api\_info \- support API paths <code>ip ipsec identity</code>\, <code>ip ipsec peer</code>\, <code>ip ipsec policy</code>\, <code>ip ipsec profile</code>\, <code>ip ipsec proposal</code> \([https\://github\.com/ansible\-collections/community\.routeros/pull/129](https\://github\.com/ansible\-collections/community\.routeros/pull/129)\)\.
+* api\_modify\, api\_info \- support API paths <code>ip route</code> and <code>ip route vrf</code> \([https\://github\.com/ansible\-collections/community\.routeros/pull/123](https\://github\.com/ansible\-collections/community\.routeros/pull/123)\)\.
+* api\_modify\, api\_info \- support API paths <code>ipv6 address</code>\, <code>ipv6 dhcp\-server</code>\, <code>ipv6 dhcp\-server option</code>\, <code>ipv6 route</code>\, <code>queue tree</code>\, <code>routing ospf area</code>\, <code>routing ospf area range</code>\, <code>routing ospf instance</code>\, <code>routing ospf interface\-template</code>\, <code>routing pimsm instance</code>\, <code>routing pimsm interface\-template</code> \([https\://github\.com/ansible\-collections/community\.routeros/pull/131](https\://github\.com/ansible\-collections/community\.routeros/pull/131)\)\.
+* api\_modify\, api\_info \- support API paths <code>system logging</code>\, <code>system logging action</code> \([https\://github\.com/ansible\-collections/community\.routeros/pull/127](https\://github\.com/ansible\-collections/community\.routeros/pull/127)\)\.
+* api\_modify\, api\_info \- support field <code>hw\-offload</code> for path <code>ip firewall filter</code> \([https\://github\.com/ansible\-collections/community\.routeros/pull/121](https\://github\.com/ansible\-collections/community\.routeros/pull/121)\)\.
+* api\_modify\, api\_info \- support fields <code>address\-list</code>\, <code>address\-list\-timeout</code>\, <code>connection\-bytes</code>\, <code>connection\-limit</code>\, <code>connection\-mark</code>\, <code>connection\-rate</code>\, <code>connection\-type</code>\, <code>content</code>\, <code>disabled</code>\, <code>dscp</code>\, <code>dst\-address\-list</code>\, <code>dst\-address\-type</code>\, <code>dst\-limit</code>\, <code>fragment</code>\, <code>hotspot</code>\, <code>icmp\-options</code>\, <code>in\-bridge\-port</code>\, <code>in\-bridge\-port\-list</code>\, <code>ingress\-priority</code>\, <code>ipsec\-policy</code>\, <code>ipv4\-options</code>\, <code>jump\-target</code>\, <code>layer7\-protocol</code>\, <code>limit</code>\, <code>log</code>\, <code>log\-prefix</code>\, <code>nth</code>\, <code>out\-bridge\-port</code>\, <code>out\-bridge\-port\-list</code>\, <code>packet\-mark</code>\, <code>packet\-size</code>\, <code>per\-connection\-classifier</code>\, <code>port</code>\, <code>priority</code>\, <code>psd</code>\, <code>random</code>\, <code>realm</code>\, <code>routing\-mark</code>\, <code>same\-not\-by\-dst</code>\, <code>src\-address</code>\, <code>src\-address\-list</code>\, <code>src\-address\-type</code>\, <code>src\-mac\-address</code>\, <code>src\-port</code>\, <code>tcp\-mss</code>\, <code>time</code>\, <code>tls\-host</code>\, <code>ttl</code> in <code>ip firewall nat</code> path \([https\://github\.com/ansible\-collections/community\.routeros/pull/133](https\://github\.com/ansible\-collections/community\.routeros/pull/133)\)\.
+* api\_modify\, api\_info \- support fields <code>combo\-mode</code>\, <code>comment</code>\, <code>fec\-mode</code>\, <code>mdix\-enable</code>\, <code>poe\-out</code>\, <code>poe\-priority</code>\, <code>poe\-voltage</code>\, <code>power\-cycle\-interval</code>\, <code>power\-cycle\-ping\-address</code>\, <code>power\-cycle\-ping\-enabled</code>\, <code>power\-cycle\-ping\-timeout</code> for path <code>interface ethernet</code> \([https\://github\.com/ansible\-collections/community\.routeros/pull/121](https\://github\.com/ansible\-collections/community\.routeros/pull/121)\)\.
+* api\_modify\, api\_info \- support fields <code>jump\-target</code>\, <code>reject\-with</code> in <code>ip firewall filter</code> API path\, field <code>comment</code> in <code>ip firwall address\-list</code> API path\, field <code>jump\-target</code> in <code>ip firewall mangle</code> API path\, field <code>comment</code> in <code>ipv6 firewall address\-list</code> API path\, fields <code>jump\-target</code>\, <code>reject\-with</code> in <code>ipv6 firewall filter</code> API path \([https\://github\.com/ansible\-collections/community\.routeros/pull/133](https\://github\.com/ansible\-collections/community\.routeros/pull/133)\)\.
+* api\_modify\, api\_info \- support for API fields that can be disabled and have default value at the same time\, support API paths <code>interface gre</code>\, <code>interface eoip</code> \([https\://github\.com/ansible\-collections/community\.routeros/pull/128](https\://github\.com/ansible\-collections/community\.routeros/pull/128)\)\.
+* api\_modify\, api\_info \- support for fields <code>blackhole</code>\, <code>pref\-src</code>\, <code>routing\-table</code>\, <code>suppress\-hw\-offload</code>\, <code>type</code>\, <code>vrf\-interface</code> in <code>ip route</code> path \([https\://github\.com/ansible\-collections/community\.routeros/pull/131](https\://github\.com/ansible\-collections/community\.routeros/pull/131)\)\.
+* api\_modify\, api\_info \- support paths <code>system ntp client servers</code> and <code>system ntp server</code> available in ROS7\, as well as new fields <code>servers</code>\, <code>mode</code>\, and <code>vrf</code> for <code>system ntp client</code> \([https\://github\.com/ansible\-collections/community\.routeros/pull/122](https\://github\.com/ansible\-collections/community\.routeros/pull/122)\)\.
+
+<a id="bugfixes-9"></a>
+### Bugfixes
+
+* api\_modify \- <code>ip route</code> entry can be defined without the need of <code>gateway</code> field\, which is correct for unreachable/blackhole type of routes \([https\://github\.com/ansible\-collections/community\.routeros/pull/131](https\://github\.com/ansible\-collections/community\.routeros/pull/131)\)\.
+* api\_modify \- <code>queue interface</code> path works now \([https\://github\.com/ansible\-collections/community\.routeros/pull/131](https\://github\.com/ansible\-collections/community\.routeros/pull/131)\)\.
+* api\_modify\, api\_info \- removed wrong field <code>dynamic</code> from API path <code>ipv6 firewall address\-list</code> \([https\://github\.com/ansible\-collections/community\.routeros/pull/133](https\://github\.com/ansible\-collections/community\.routeros/pull/133)\)\.
+* api\_modify\, api\_info \- the default of the field <code>ingress\-filtering</code> in <code>interface bridge port</code> is now <code>true</code>\, which is the default in ROS \([https\://github\.com/ansible\-collections/community\.routeros/pull/125](https\://github\.com/ansible\-collections/community\.routeros/pull/125)\)\.
+* command\, facts \- commands do not timeout in safe mode anymore \([https\://github\.com/ansible\-collections/community\.routeros/pull/134](https\://github\.com/ansible\-collections/community\.routeros/pull/134)\)\.
+
+<a id="known-issues-1"></a>
+### Known Issues
+
+* api\_modify \- when limits for entries in <code>queue tree</code> are defined as human readable \- for example <code>25M</code> \-\, the configuration will be correctly set in ROS\, but the module will indicate the item is changed on every run even when there was no change done\. This is caused by the ROS API which returns the number in bytes \- for example <code>25000000</code> \(which is inconsistent with the CLI behavior\)\. In order to mitigate that\, the limits have to be defined in bytes \(those will still appear as human readable in the ROS CLI\) \([https\://github\.com/ansible\-collections/community\.routeros/pull/131](https\://github\.com/ansible\-collections/community\.routeros/pull/131)\)\.
+* api\_modify\, api\_info \- <code>routing ospf area</code>\, <code>routing ospf area range</code>\, <code>routing ospf instance</code>\, <code>routing ospf interface\-template</code> paths are not fully implemented for ROS6 due to the significant changes between ROS6 and ROS7 \([https\://github\.com/ansible\-collections/community\.routeros/pull/131](https\://github\.com/ansible\-collections/community\.routeros/pull/131)\)\.
+
+<a id="v2-3-1"></a>
+## v2\.3\.1
+
+<a id="release-summary-14"></a>
+### Release Summary
+
+Maintenance release with improved documentation\.
+
+<a id="known-issues-2"></a>
+### Known Issues
+
+* The <code>community\.routeros\.command</code> module claims to support check mode\. Since it cannot judge whether the commands executed modify state or not\, this behavior is incorrect\. Since this potentially breaks existing playbooks\, we will not change this behavior until community\.routeros 3\.0\.0\.
+
+<a id="v2-3-0"></a>
+## v2\.3\.0
+
+<a id="release-summary-15"></a>
+### Release Summary
+
+Feature and bugfix release\.
+
+<a id="minor-changes-11"></a>
+### Minor Changes
+
+* The collection repository conforms to the [REUSE specification](https\://reuse\.software/spec/) except for the changelog fragments \([https\://github\.com/ansible\-collections/community\.routeros/pull/108](https\://github\.com/ansible\-collections/community\.routeros/pull/108)\)\.
+* api\* modules \- added <code>timeout</code> parameter \([https\://github\.com/ansible\-collections/community\.routeros/pull/109](https\://github\.com/ansible\-collections/community\.routeros/pull/109)\)\.
+* api\_modify\, api\_info \- support API path <code>ip firewall mangle</code> \([https\://github\.com/ansible\-collections/community\.routeros/pull/110](https\://github\.com/ansible\-collections/community\.routeros/pull/110)\)\.
+
+<a id="bugfixes-10"></a>
+### Bugfixes
+
+* api\_modify\, api\_info \- make API path <code>ip dhcp\-server</code> support <code>script</code>\, and <code>ip firewall nat</code> support <code>in\-interface</code> and <code>in\-interface\-list</code> \([https\://github\.com/ansible\-collections/community\.routeros/pull/110](https\://github\.com/ansible\-collections/community\.routeros/pull/110)\)\.
+
+<a id="v2-2-1"></a>
+## v2\.2\.1
+
+<a id="release-summary-16"></a>
+### Release Summary
+
+Bugfix release\.
+
+<a id="bugfixes-11"></a>
+### Bugfixes
+
+* api\_modify\, api\_info \- make API path <code>ip dhcp\-server lease</code> support <code>server\=all</code> \([https\://github\.com/ansible\-collections/community\.routeros/issues/104](https\://github\.com/ansible\-collections/community\.routeros/issues/104)\, [https\://github\.com/ansible\-collections/community\.routeros/pull/107](https\://github\.com/ansible\-collections/community\.routeros/pull/107)\)\.
+* api\_modify\, api\_info \- make API path <code>ip dhcp\-server network</code> support missing options <code>boot\-file\-name</code>\, <code>dhcp\-option\-set</code>\, <code>dns\-none</code>\, <code>domain</code>\, and <code>next\-server</code> \([https\://github\.com/ansible\-collections/community\.routeros/issues/104](https\://github\.com/ansible\-collections/community\.routeros/issues/104)\, [https\://github\.com/ansible\-collections/community\.routeros/pull/106](https\://github\.com/ansible\-collections/community\.routeros/pull/106)\)\.
+
+<a id="v2-2-0"></a>
+## v2\.2\.0
+
+<a id="release-summary-17"></a>
+### Release Summary
+
+New feature release\.
+
+<a id="minor-changes-12"></a>
+### Minor Changes
+
+* All software licenses are now in the <code>LICENSES/</code> directory of the collection root\. Moreover\, <code>SPDX\-License\-Identifier\:</code> is used to declare the applicable license for every file that is not automatically generated \([https\://github\.com/ansible\-collections/community\.routeros/pull/101](https\://github\.com/ansible\-collections/community\.routeros/pull/101)\)\.
+
+<a id="bugfixes-12"></a>
+### Bugfixes
+
+* Include <code>LICENSES/BSD\-2\-Clause\.txt</code> file for the <code>routeros</code> module utils \([https\://github\.com/ansible\-collections/community\.routeros/pull/101](https\://github\.com/ansible\-collections/community\.routeros/pull/101)\)\.
+
+<a id="new-modules"></a>
+### New Modules
+
+* api\_info \- Retrieve information from API
+* api\_modify \- Modify data at paths with API
+
+<a id="v2-1-0"></a>
+## v2\.1\.0
+
+<a id="release-summary-18"></a>
+### Release Summary
+
+Feature and bugfix release with new modules\.
+
+<a id="minor-changes-13"></a>
+### Minor Changes
+
+* Added a <code>community\.routeros\.api</code> module defaults group\. Use with <code>group/community\.routeros\.api</code> to provide options for all API\-based modules \([https\://github\.com/ansible\-collections/community\.routeros/pull/89](https\://github\.com/ansible\-collections/community\.routeros/pull/89)\)\.
+* Prepare collection for inclusion in an Execution Environment by declaring its dependencies \([https\://github\.com/ansible\-collections/community\.routeros/pull/83](https\://github\.com/ansible\-collections/community\.routeros/pull/83)\)\.
+* api \- add new option <code>extended query</code> more complex queries against RouterOS API \([https\://github\.com/ansible\-collections/community\.routeros/pull/63](https\://github\.com/ansible\-collections/community\.routeros/pull/63)\)\.
+* api \- update <code>query</code> to accept symbolic parameters \([https\://github\.com/ansible\-collections/community\.routeros/pull/63](https\://github\.com/ansible\-collections/community\.routeros/pull/63)\)\.
+* api\* modules \- allow to set an encoding other than the default ASCII for communicating with the API \([https\://github\.com/ansible\-collections/community\.routeros/pull/95](https\://github\.com/ansible\-collections/community\.routeros/pull/95)\)\.
+
+<a id="bugfixes-13"></a>
+### Bugfixes
+
+* query \- fix query function check for <code>\.id</code> vs\. <code>id</code> arguments to not conflict with routeros arguments like <code>identity</code> \([https\://github\.com/ansible\-collections/community\.routeros/pull/68](https\://github\.com/ansible\-collections/community\.routeros/pull/68)\, [https\://github\.com/ansible\-collections/community\.routeros/issues/67](https\://github\.com/ansible\-collections/community\.routeros/issues/67)\)\.
+* quoting and unquoting filter plugins\, api module \- handle the escape sequence <code>\\\_</code> correctly as escaping a space and not an underscore \([https\://github\.com/ansible\-collections/community\.routeros/pull/89](https\://github\.com/ansible\-collections/community\.routeros/pull/89)\)\.
+
+<a id="new-modules-1"></a>
+### New Modules
+
+* api\_facts \- Collect facts from remote devices running MikroTik RouterOS using the API
+* api\_find\_and\_modify \- Find and modify information using the API
+
+<a id="v2-0-0"></a>
+## v2\.0\.0
+
+<a id="release-summary-19"></a>
+### Release Summary
+
+A new major release with breaking changes in the behavior of <code>community\.routeros\.api</code> and <code>community\.routeros\.command</code>\.
+
+<a id="minor-changes-14"></a>
+### Minor Changes
+
+* api \- make validation of <code>WHERE</code> for <code>query</code> more strict \([https\://github\.com/ansible\-collections/community\.routeros/pull/53](https\://github\.com/ansible\-collections/community\.routeros/pull/53)\)\.
+* command \- the <code>commands</code> and <code>wait\_for</code> options now convert the list elements to strings \([https\://github\.com/ansible\-collections/community\.routeros/pull/55](https\://github\.com/ansible\-collections/community\.routeros/pull/55)\)\.
+* facts \- the <code>gather\_subset</code> option now converts the list elements to strings \([https\://github\.com/ansible\-collections/community\.routeros/pull/55](https\://github\.com/ansible\-collections/community\.routeros/pull/55)\)\.
+
+<a id="breaking-changes--porting-guide"></a>
+### Breaking Changes / Porting Guide
+
+* api \- due to a programming error\, the module never failed on errors\. This has now been fixed\. If you are relying on the module not failing in case of idempotent commands \(resulting in errors like <code>failure\: already have such address</code>\)\, you need to adjust your roles/playbooks\. We suggest to use <code>failed\_when</code> to accept failure in specific circumstances\, for example <code>failed\_when\: \"\'failure\: already have \' in result\.msg\[0\]\"</code> \([https\://github\.com/ansible\-collections/community\.routeros/pull/39](https\://github\.com/ansible\-collections/community\.routeros/pull/39)\)\.
+* api \- splitting commands no longer uses a naive split by whitespace\, but a more RouterOS CLI compatible splitting algorithm \([https\://github\.com/ansible\-collections/community\.routeros/pull/45](https\://github\.com/ansible\-collections/community\.routeros/pull/45)\)\.
+* command \- the module now always indicates that a change happens\. If this is not correct\, please use <code>changed\_when</code> to determine the correct changed status for a task \([https\://github\.com/ansible\-collections/community\.routeros/pull/50](https\://github\.com/ansible\-collections/community\.routeros/pull/50)\)\.
+
+<a id="bugfixes-14"></a>
+### Bugfixes
+
+* api \- improve splitting of <code>WHERE</code> queries \([https\://github\.com/ansible\-collections/community\.routeros/pull/47](https\://github\.com/ansible\-collections/community\.routeros/pull/47)\)\.
+* api \- when converting result lists to dictionaries\, no longer removes second <code>\=</code> and text following that if present \([https\://github\.com/ansible\-collections/community\.routeros/pull/47](https\://github\.com/ansible\-collections/community\.routeros/pull/47)\)\.
+* routeros cliconf plugin \- adjust function signature that was modified in Ansible after creation of this plugin \([https\://github\.com/ansible\-collections/community\.routeros/pull/43](https\://github\.com/ansible\-collections/community\.routeros/pull/43)\)\.
+
+<a id="new-plugins"></a>
+### New Plugins
+
+<a id="filter"></a>
+#### Filter
+
+* join \- Join a list of arguments to a command
+* list\_to\_dict \- Convert a list of arguments to a list of dictionary
+* quote\_argument \- Quote an argument
+* quote\_argument\_value \- Quote an argument value
+* split \- Split a command into arguments
+
+<a id="v1-2-0"></a>
+## v1\.2\.0
+
+<a id="release-summary-20"></a>
+### Release Summary
+
+Bugfix and feature release\.
+
+<a id="minor-changes-15"></a>
+### Minor Changes
+
+* Avoid internal ansible\-core module\_utils in favor of equivalent public API available since at least Ansible 2\.9 \([https\://github\.com/ansible\-collections/community\.routeros/pull/38](https\://github\.com/ansible\-collections/community\.routeros/pull/38)\)\.
+* api \- add options <code>validate\_certs</code> \(default value <code>true</code>\)\, <code>validate\_cert\_hostname</code> \(default value <code>false</code>\)\, and <code>ca\_path</code> to control certificate validation \([https\://github\.com/ansible\-collections/community\.routeros/pull/37](https\://github\.com/ansible\-collections/community\.routeros/pull/37)\)\.
+* api \- rename option <code>ssl</code> to <code>tls</code>\, and keep the old name as an alias \([https\://github\.com/ansible\-collections/community\.routeros/pull/37](https\://github\.com/ansible\-collections/community\.routeros/pull/37)\)\.
+* fact \- add fact <code>ansible\_net\_config\_nonverbose</code> to get idempotent config \(no date\, no verbose\) \([https\://github\.com/ansible\-collections/community\.routeros/pull/23](https\://github\.com/ansible\-collections/community\.routeros/pull/23)\)\.
+
+<a id="bugfixes-15"></a>
+### Bugfixes
+
+* api \- when using TLS/SSL\, remove explicit cipher configuration to insecure values\, which also makes it impossible to connect to newer RouterOS versions \([https\://github\.com/ansible\-collections/community\.routeros/pull/34](https\://github\.com/ansible\-collections/community\.routeros/pull/34)\)\.
+
+<a id="v1-1-0"></a>
+## v1\.1\.0
+
+<a id="release-summary-21"></a>
+### Release Summary
+
+This release allow dashes in usernames for SSH\-based modules\.
+
+<a id="minor-changes-16"></a>
+### Minor Changes
+
+* command \- added support for a dash \(<code>\-</code>\) in username \([https\://github\.com/ansible\-collections/community\.routeros/pull/18](https\://github\.com/ansible\-collections/community\.routeros/pull/18)\)\.
+* facts \- added support for a dash \(<code>\-</code>\) in username \([https\://github\.com/ansible\-collections/community\.routeros/pull/18](https\://github\.com/ansible\-collections/community\.routeros/pull/18)\)\.
+
+<a id="v1-0-1"></a>
+## v1\.0\.1
+
+<a id="release-summary-22"></a>
+### Release Summary
+
+Maintenance release with a bugfix for <code>api</code>\.
+
+<a id="bugfixes-16"></a>
+### Bugfixes
+
+* api \- remove <code>id to \.id</code> as default requirement which conflicts with RouterOS <code>id</code> configuration parameter \([https\://github\.com/ansible\-collections/community\.routeros/pull/15](https\://github\.com/ansible\-collections/community\.routeros/pull/15)\)\.
+
+<a id="v1-0-0"></a>
+## v1\.0\.0
+
+<a id="release-summary-23"></a>
+### Release Summary
+
+This is the first production \(non\-prerelease\) release of <code>community\.routeros</code>\.
+
+<a id="bugfixes-17"></a>
+### Bugfixes
+
+* routeros terminal plugin \- allow slashes in hostnames for terminal detection\. Without this\, slashes in hostnames will result in connection timeouts \([https\://github\.com/ansible\-collections/community\.network/pull/138](https\://github\.com/ansible\-collections/community\.network/pull/138)\)\.
+
+<a id="v0-1-1"></a>
+## v0\.1\.1
+
+<a id="release-summary-24"></a>
+### Release Summary
+
+Small improvements and bugfixes over the initial release\.
+
+<a id="bugfixes-18"></a>
+### Bugfixes
+
+* api \- fix crash when the <code>ssl</code> parameter is used \([https\://github\.com/ansible\-collections/community\.routeros/pull/3](https\://github\.com/ansible\-collections/community\.routeros/pull/3)\)\.
+
+<a id="v0-1-0"></a>
+## v0\.1\.0
+
+<a id="release-summary-25"></a>
+### Release Summary
+
+The <code>community\.routeros</code> continues the work on the Ansible RouterOS modules from their state in <code>community\.network</code> 1\.2\.0\. The changes listed here are thus relative to the modules <code>community\.network\.routeros\_\*</code>\.
+
+<a id="minor-changes-17"></a>
+### Minor Changes
+
+* facts \- now also collecting data about BGP and OSPF \([https\://github\.com/ansible\-collections/community\.network/pull/101](https\://github\.com/ansible\-collections/community\.network/pull/101)\)\.
+* facts \- set configuration export on to verbose\, for full configuration export \([https\://github\.com/ansible\-collections/community\.network/pull/104](https\://github\.com/ansible\-collections/community\.network/pull/104)\)\.
diff --git a/ansible_collections/community/routeros/CHANGELOG.md.license b/ansible_collections/community/routeros/CHANGELOG.md.license
new file mode 100644
index 000000000..edff8c768
--- /dev/null
+++ b/ansible_collections/community/routeros/CHANGELOG.md.license
@@ -0,0 +1,3 @@
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
+SPDX-FileCopyrightText: Ansible Project
diff --git a/ansible_collections/community/routeros/CHANGELOG.rst b/ansible_collections/community/routeros/CHANGELOG.rst
index d82c58e47..c7cc6ef67 100644
--- a/ansible_collections/community/routeros/CHANGELOG.rst
+++ b/ansible_collections/community/routeros/CHANGELOG.rst
@@ -4,6 +4,156 @@ Community RouterOS Release Notes
.. contents:: Topics
+v2.14.0
+=======
+
+Release Summary
+---------------
+
+Feature release.
+
+Minor Changes
+-------------
+
+- api_info, api_modify - add read-only fields ``installed-version``, ``latest-version`` and ``status`` in ``system package update`` (https://github.com/ansible-collections/community.routeros/pull/263).
+- api_info, api_modify - added support for ``interface wifi`` and its sub-paths (https://github.com/ansible-collections/community.routeros/pull/266).
+- api_info, api_modify - remove default value for read-only ``running`` field in ``interface wireless`` (https://github.com/ansible-collections/community.routeros/pull/264).
+
+v2.13.0
+=======
+
+Release Summary
+---------------
+
+Bugfix and feature release.
+
+Minor Changes
+-------------
+
+- api_info, api_modify - make path ``user group`` modifiable and add ``comment`` attribute (https://github.com/ansible-collections/community.routeros/issues/256, https://github.com/ansible-collections/community.routeros/pull/257).
+- api_modify, api_info - add support for the ``ip vrf`` path in RouterOS 7 (https://github.com/ansible-collections/community.routeros/pull/259)
+
+Bugfixes
+--------
+
+- facts - fix date not getting removed for idempotent config export (https://github.com/ansible-collections/community.routeros/pull/262).
+
+v2.12.0
+=======
+
+Release Summary
+---------------
+
+Feature release.
+
+Minor Changes
+-------------
+
+- api_info, api_modify - add ``interface ovpn-client`` path (https://github.com/ansible-collections/community.routeros/issues/242, https://github.com/ansible-collections/community.routeros/pull/244).
+- api_info, api_modify - add ``radius`` path (https://github.com/ansible-collections/community.routeros/issues/241, https://github.com/ansible-collections/community.routeros/pull/245).
+- api_info, api_modify - add ``routing rule`` path (https://github.com/ansible-collections/community.routeros/issues/162, https://github.com/ansible-collections/community.routeros/pull/246).
+- api_info, api_modify - add missing path ``routing bgp template`` (https://github.com/ansible-collections/community.routeros/pull/243).
+- api_info, api_modify - add support for the ``tx-power`` attribute in ``interface wireless`` (https://github.com/ansible-collections/community.routeros/pull/239).
+- api_info, api_modify - removed ``host`` primary key in ``tool netwatch`` path (https://github.com/ansible-collections/community.routeros/pull/248).
+- api_modify, api_info - added support for ``interface wifiwave2`` (https://github.com/ansible-collections/community.routeros/pull/226).
+
+v2.11.0
+=======
+
+Release Summary
+---------------
+
+Feature and bugfix release.
+
+Minor Changes
+-------------
+
+- api_info, api_modify - add missing DoH parameters ``doh-max-concurrent-queries``, ``doh-max-server-connections``, and ``doh-timeout`` to the ``ip dns`` path (https://github.com/ansible-collections/community.routeros/issues/230, https://github.com/ansible-collections/community.routeros/pull/235)
+- api_info, api_modify - add missing parameters ``address-list``, ``address-list-timeout``, ``randomise-ports``, and ``realm`` to subpaths of the ``ip firewall`` path (https://github.com/ansible-collections/community.routeros/issues/236, https://github.com/ansible-collections/community.routeros/pull/237).
+- api_info, api_modify - mark the ``interface wireless`` parameter ``running`` as read-only (https://github.com/ansible-collections/community.routeros/pull/233).
+- api_info, api_modify - set the default value to ``false`` for the ``disabled`` parameter in some more paths where it can be seen in the documentation (https://github.com/ansible-collections/community.routeros/pull/237).
+- api_modify - add missing ``comment`` attribute to ``/routing id`` (https://github.com/ansible-collections/community.routeros/pull/234).
+- api_modify - add missing attributes to the ``routing bgp connection`` path (https://github.com/ansible-collections/community.routeros/pull/234).
+- api_modify - add versioning to the ``/tool e-mail`` path (RouterOS 7.12 release) (https://github.com/ansible-collections/community.routeros/pull/234).
+- api_modify - make ``/ip traffic-flow target`` a multiple value attribute (https://github.com/ansible-collections/community.routeros/pull/234).
+
+v2.10.0
+=======
+
+Release Summary
+---------------
+
+Bugfix and feature release.
+
+Minor Changes
+-------------
+
+- api_info - add new ``include_read_only`` option to select behavior for read-only values. By default these are not returned (https://github.com/ansible-collections/community.routeros/pull/213).
+- api_info, api_modify - add support for ``address-list`` and ``match-subdomain`` introduced by RouterOS 7.7 in the ``ip dns static`` path (https://github.com/ansible-collections/community.routeros/pull/197).
+- api_info, api_modify - add support for ``user``, ``time`` and ``gmt-offset`` under the ``system clock`` path (https://github.com/ansible-collections/community.routeros/pull/210).
+- api_info, api_modify - add support for the ``interface ppp-client`` path (https://github.com/ansible-collections/community.routeros/pull/199).
+- api_info, api_modify - add support for the ``interface wireless`` path (https://github.com/ansible-collections/community.routeros/pull/195).
+- api_info, api_modify - add support for the ``iot modbus`` path (https://github.com/ansible-collections/community.routeros/pull/205).
+- api_info, api_modify - add support for the ``ip dhcp-server option`` and ``ip dhcp-server option sets`` paths (https://github.com/ansible-collections/community.routeros/pull/223).
+- api_info, api_modify - add support for the ``ip upnp interfaces``, ``tool graphing interface``, ``tool graphing resource`` paths (https://github.com/ansible-collections/community.routeros/pull/227).
+- api_info, api_modify - add support for the ``ipv6 firewall nat`` path (https://github.com/ansible-collections/community.routeros/pull/204).
+- api_info, api_modify - add support for the ``mode`` property in ``ip neighbor discovery-settings`` introduced in RouterOS 7.7 (https://github.com/ansible-collections/community.routeros/pull/198).
+- api_info, api_modify - add support for the ``port remote-access`` path (https://github.com/ansible-collections/community.routeros/pull/224).
+- api_info, api_modify - add support for the ``routing filter rule`` and ``routing filter select-rule`` paths (https://github.com/ansible-collections/community.routeros/pull/200).
+- api_info, api_modify - add support for the ``routing table`` path in RouterOS 7 (https://github.com/ansible-collections/community.routeros/pull/215).
+- api_info, api_modify - add support for the ``tool netwatch`` path in RouterOS 7 (https://github.com/ansible-collections/community.routeros/pull/216).
+- api_info, api_modify - add support for the ``user settings`` path (https://github.com/ansible-collections/community.routeros/pull/201).
+- api_info, api_modify - add support for the ``user`` path (https://github.com/ansible-collections/community.routeros/pull/211).
+- api_info, api_modify - finalize fields for the ``interface wireless security-profiles`` path and enable it (https://github.com/ansible-collections/community.routeros/pull/203).
+- api_info, api_modify - finalize fields for the ``ppp profile`` path and enable it (https://github.com/ansible-collections/community.routeros/pull/217).
+- api_modify - add new ``handle_read_only`` and ``handle_write_only`` options to handle the module's behavior for read-only and write-only fields (https://github.com/ansible-collections/community.routeros/pull/213).
+- api_modify, api_info - support API paths ``routing id``, ``routing bgp connection`` (https://github.com/ansible-collections/community.routeros/pull/220).
+
+Bugfixes
+--------
+
+- api_info, api_modify - in the ``snmp`` path, ensure that ``engine-id-suffix`` is only available on RouterOS 7.10+, and that ``engine-id`` is read-only on RouterOS 7.10+ (https://github.com/ansible-collections/community.routeros/issues/208, https://github.com/ansible-collections/community.routeros/pull/218).
+
+v2.9.0
+======
+
+Release Summary
+---------------
+
+Bugfix and feature release.
+
+Minor Changes
+-------------
+
+- api_info, api_modify - add path ``caps-man channel`` and enable path ``caps-man manager interface`` (https://github.com/ansible-collections/community.routeros/issues/193, https://github.com/ansible-collections/community.routeros/pull/194).
+- api_info, api_modify - add path ``ip traffic-flow target`` (https://github.com/ansible-collections/community.routeros/issues/191, https://github.com/ansible-collections/community.routeros/pull/192).
+
+Bugfixes
+--------
+
+- api_modify, api_info - add missing parameter ``engine-id-suffix`` for the ``snmp`` path (https://github.com/ansible-collections/community.routeros/issues/189, https://github.com/ansible-collections/community.routeros/pull/190).
+
+v2.8.3
+======
+
+Release Summary
+---------------
+
+Maintenance release with updated documentation.
+
+From this version on, community.routeros is using the new `Ansible semantic markup
+<https://docs.ansible.com/ansible/devel/dev_guide/developing_modules_documenting.html#semantic-markup-within-module-documentation>`__
+in its documentation. If you look at documentation with the ansible-doc CLI tool
+from ansible-core before 2.15, please note that it does not render the markup
+correctly. You should be still able to read it in most cases, but you need
+ansible-core 2.15 or later to see it as it is intended. Alternatively you can
+look at `the devel docsite <https://docs.ansible.com/ansible/devel/collections/community/routeros/>`__
+for the rendered HTML version of the documentation of the latest release.
+
+Known Issues
+------------
+
+- Ansible markup will show up in raw form on ansible-doc text output for ansible-core before 2.15. If you have trouble deciphering the documentation markup, please upgrade to ansible-core 2.15 (or newer), or read the HTML documentation on https://docs.ansible.com/ansible/devel/collections/community/routeros/.
v2.8.2
======
@@ -154,7 +304,7 @@ Known Issues
------------
- api_modify - when limits for entries in ``queue tree`` are defined as human readable - for example ``25M`` -, the configuration will be correctly set in ROS, but the module will indicate the item is changed on every run even when there was no change done. This is caused by the ROS API which returns the number in bytes - for example ``25000000`` (which is inconsistent with the CLI behavior). In order to mitigate that, the limits have to be defined in bytes (those will still appear as human readable in the ROS CLI) (https://github.com/ansible-collections/community.routeros/pull/131).
-- api_modify, api_info - ``routing ospf area``, ``routing ospf area range``, ``routing ospf instance``, ``routing ospf interface-template`` paths are not fully implemeted for ROS6 due to the significat changes between ROS6 and ROS7 (https://github.com/ansible-collections/community.routeros/pull/131).
+- api_modify, api_info - ``routing ospf area``, ``routing ospf area range``, ``routing ospf instance``, ``routing ospf interface-template`` paths are not fully implemented for ROS6 due to the significant changes between ROS6 and ROS7 (https://github.com/ansible-collections/community.routeros/pull/131).
v2.3.1
======
@@ -353,7 +503,6 @@ Release Summary
This is the first production (non-prerelease) release of ``community.routeros``.
-
Bugfixes
--------
@@ -380,7 +529,6 @@ Release Summary
The ``community.routeros`` continues the work on the Ansible RouterOS modules from their state in ``community.network`` 1.2.0. The changes listed here are thus relative to the modules ``community.network.routeros_*``.
-
Minor Changes
-------------
diff --git a/ansible_collections/community/routeros/FILES.json b/ansible_collections/community/routeros/FILES.json
index f0a44a030..65dc9b337 100644
--- a/ansible_collections/community/routeros/FILES.json
+++ b/ansible_collections/community/routeros/FILES.json
@@ -25,49 +25,49 @@
"name": ".github/workflows/ansible-test.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "21b4409514745adc855018f435409f1ec11567dc50c0c9656df0fe8ac8070b66",
+ "chksum_sha256": "7733552e950b67d67c9b00ef9bb1d15c38ee2d765d47ab2d7404cc5efa6fa0b7",
"format": 1
},
{
"name": ".github/workflows/docs-pr.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7447bfd97439ddb95181d05a354af0baaa6075b67897997d2f19e0f140394120",
+ "chksum_sha256": "ea4a8970f7f5e5bc2151c20eaae47953eeed04275c93c61793f9333862a64244",
"format": 1
},
{
"name": ".github/workflows/docs-push.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "90515807b7cc45d54a09d6392547c15f802774a4a4f9d3a2953f7f846ac0e12d",
+ "chksum_sha256": "02ab0cf44983ff3c4f0a852f0eaa01cc7c98e1422a9286592e6e1bcac5a61985",
"format": 1
},
{
"name": ".github/workflows/ee.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cd5a0b5b9f6f084d5fdc49f64fd4fbdc279102cf317be836dcbee3265c8a9cfb",
+ "chksum_sha256": "99536bd592be0fadd2e2c9acce48152aa671b04ba69636097bffd65035c473d6",
"format": 1
},
{
"name": ".github/workflows/extra-tests.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4124755ad295f3e9b6cf2968192fb8d8fd54f8faa0df601b80c0aec4d68b45f0",
+ "chksum_sha256": "355da6ac8dcdeef5fac5fbe943037c1d20d7067233e8d4ce5156a9239e7b58ea",
"format": 1
},
{
"name": ".github/workflows/import-galaxy.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "310dc7ba44c93f61f5f88b323259f6efb8925681bfbbb15a1a18d774af54dcd6",
+ "chksum_sha256": "739c36223d6e0e6ccc98907c43cba53296e7b1ccd64a2d995c2ff21df4ab25a5",
"format": 1
},
{
"name": ".github/workflows/reuse.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "05ee22080e7de7265b2839359ee290b4e81162e089d27d01d59d4af12d54761f",
+ "chksum_sha256": "18e9a8aa2ea33f801011c5e25d3fb30cff5143b05579d063ff58804ec4646b93",
"format": 1
},
{
@@ -151,7 +151,7 @@
"name": "changelogs/changelog.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6269eee40124bb0bb68d94fa7e8c8e42c24988985220832aa0c43e056c60af85",
+ "chksum_sha256": "b9c3d4e8049fa8e3b5e55c2997f4df70ac1942517cfbddb28d7caafef030ba12",
"format": 1
},
{
@@ -165,7 +165,7 @@
"name": "changelogs/config.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "73b52630d73b33f7f7bf31cd751b732a60f8e3db798afe416d6c6ba67ca80044",
+ "chksum_sha256": "3cb54c894797529118cca5be83152602e8db6353062d795b6a9aaeecfc188870",
"format": 1
},
{
@@ -193,21 +193,21 @@
"name": "docs/docsite/rst/api-guide.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "03b35df33b16d917e7fb4d1b975ebfd72e1b050f8a1b25591856fc0d149758f3",
+ "chksum_sha256": "1076e9e460a1d0f958eaedad9c973d3db25da5f537db9057823cc8d34963eab6",
"format": 1
},
{
"name": "docs/docsite/rst/quoting.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "635d3a7c79d2a2aa2d49861ea06979b30261a994875aec510fded7e08c0d394f",
+ "chksum_sha256": "6927f7326a1729c47245673abcd581f93f8ddb3ec203772b0d79499b944217a6",
"format": 1
},
{
"name": "docs/docsite/rst/ssh-guide.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "42fe9bd067713f5a3ffa9f12d38f773c554524bcb36723763382e997baff5d50",
+ "chksum_sha256": "e90301653103e84a71bb5896ad6467ea65b29a6b832a072d87daaf1e2724bc9f",
"format": 1
},
{
@@ -284,7 +284,7 @@
"name": "plugins/doc_fragments/api.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6e1855a22deb8f5a21cadb3594afd67b93e9d0a1500f652d5f558b622948d2b6",
+ "chksum_sha256": "2867e29eadd3e864ee31be16842c70dd32be5c2495e12652769e85078a8294db",
"format": 1
},
{
@@ -312,7 +312,7 @@
"name": "plugins/filter/list_to_dict.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "21837e13bd533aeba2e1843375636b607db7f619d856fd3d2c3e1a69cc953a41",
+ "chksum_sha256": "3469f86f4e183d5ff688c29e6fb79397711a92033e03268b2ea6f7f6bf16809c",
"format": 1
},
{
@@ -354,7 +354,7 @@
"name": "plugins/module_utils/_api_data.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "07633c6f88a503e55a4560be261bbb7867cc8483b5ec2dcfa9984b5cc32410a5",
+ "chksum_sha256": "b5880a7e63053e5f40b3824e0e8311dc2f61d93bcadc0d639d65dcc3ba88a723",
"format": 1
},
{
@@ -368,7 +368,7 @@
"name": "plugins/module_utils/api.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f3795f24d8089bd6dc90de58ba96126c3468e9ead8f4813b14f48af48e9c2f63",
+ "chksum_sha256": "611c9cb0bde858082a1e57e756a49e6d8578a5b999287dcb9dad0dd1aabcf99c",
"format": 1
},
{
@@ -403,49 +403,49 @@
"name": "plugins/modules/api.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "751d2740488997e5c6a41d0c4255059b0dfa5755f8e8d4cafb5a7edc5071bc23",
+ "chksum_sha256": "4381013d865a6e84df15ac633653ac73ef411221a8d53447e3781fff3dc5f538",
"format": 1
},
{
"name": "plugins/modules/api_facts.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2b19e626afe7b30a27896a18d65c1ffdb4ae9446c90b52d01874543d84705590",
+ "chksum_sha256": "7d0555189b8765d25f8bcc841351647fa1ae839e389847b4c9c8397c118dacd2",
"format": 1
},
{
"name": "plugins/modules/api_find_and_modify.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0488928f752e283ae5fa10efe58c56b887840e29f43fa1fbdf65a99b6a6fc4d1",
+ "chksum_sha256": "7ed61fa2c714ee8f7cab1e2747c0d0ea5f19867568b41eb20ab6cdcfa572a68c",
"format": 1
},
{
"name": "plugins/modules/api_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9c3c6d4248fee5ec8866cf18848613143b6c12f0972f8daca1886b7279d737ae",
+ "chksum_sha256": "ed9d94602cc1c6c87fa65e829342c83724376cc8b0d47072e74a6119e10e0505",
"format": 1
},
{
"name": "plugins/modules/api_modify.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6ff23dd65b926b1ad9d7de9d8d4fb1bf699a6ad0b49b48751fa95fa40b833712",
+ "chksum_sha256": "81752a1a70ce47134663c2d721673481a8aea6995469092ae24b13303772820c",
"format": 1
},
{
"name": "plugins/modules/command.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "de6485210c86278b0f8b388f85b71ec26e85d914fa8b11c8c76a0ea8342977fb",
+ "chksum_sha256": "e81c807ca34d262e90b36c9ca75ac54dc91510e8ca2f4778c14636c48e8b8b52",
"format": 1
},
{
"name": "plugins/modules/facts.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "016fffb2831186450dc45cbf680f490963ae9ce26b8a41c4366821eb5146469c",
+ "chksum_sha256": "5364263e3f30a3c2d0d0c357a5dbc218f60c9e52a8ec6e3f5e50d12ff4e2779c",
"format": 1
},
{
@@ -620,7 +620,7 @@
"name": "tests/sanity/extra/extra-docs.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0fbd87476e9c35e4c5feb31be4aa1e8fc6aebf0de13058e5a267879f741ec0bf",
+ "chksum_sha256": "c52e316daf1292bbb063be19429fd1f06e02bce3c9d4622a8dfc61fa3af06688",
"format": 1
},
{
@@ -697,7 +697,7 @@
"name": "tests/sanity/ignore-2.10.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b8ef3a5984c970b2097edc50d6e287f010479ee9d1262c24e5f494339abd60ac",
+ "chksum_sha256": "2a9574f845c6a6ae014798df7136d9f6b2642e5ddec39040c137630a18f8ca4f",
"format": 1
},
{
@@ -792,10 +792,24 @@
"format": 1
},
{
+ "name": "tests/sanity/ignore-2.17.txt",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "1af4ae071777877caae7e48c7a1a1c905d990e0d4d832b285970307cc5ad03df",
+ "format": 1
+ },
+ {
+ "name": "tests/sanity/ignore-2.17.txt.license",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6eb915239f9f35407fa68fdc41ed6522f1fdcce11badbdcd6057548023179ac1",
+ "format": 1
+ },
+ {
"name": "tests/sanity/ignore-2.9.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b8ef3a5984c970b2097edc50d6e287f010479ee9d1262c24e5f494339abd60ac",
+ "chksum_sha256": "2a9574f845c6a6ae014798df7136d9f6b2642e5ddec39040c137630a18f8ca4f",
"format": 1
},
{
@@ -865,7 +879,7 @@
"name": "tests/unit/plugins/module_utils/test__api_data.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ab4f09d9aef04cc60d95ae745e6a549d8c2c1d1b43f4b26a11bb986b06aa169d",
+ "chksum_sha256": "6defff5702c881c28d562db99143acbc1592ca42f038b798fe732c3891be68db",
"format": 1
},
{
@@ -1152,7 +1166,7 @@
"name": "tests/unit/plugins/modules/fake_api.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e1a0e7c26d139c804edad990a43d5c241f9b8832ac6edd7e9043123b57b6d231",
+ "chksum_sha256": "7bc8b4472f73f9e74a3fb0ff3008ccb0a66088bd71f289bd7cf8356848811e8e",
"format": 1
},
{
@@ -1180,21 +1194,21 @@
"name": "tests/unit/plugins/modules/test_api_find_and_modify.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a56e613e9fd26ec90ec72f25c15a7ea8ab7ab99dbccffc92c6251226443cffa1",
+ "chksum_sha256": "e88d7c0c1ee1df86cb85b4a1795803b5f8730e9e4f8f0f50adbd1ae69f06301f",
"format": 1
},
{
"name": "tests/unit/plugins/modules/test_api_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5acc54f1fb618b84431bb94b626718f7faea823704e2e40b73ac0cc22ae0452c",
+ "chksum_sha256": "dcaff05ca93f71d6535636e168b2ba4d2ead37cbac7d2a2a2ddf26b009719210",
"format": 1
},
{
"name": "tests/unit/plugins/modules/test_api_modify.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8903880a669f9d4a33cb9ba6247ac99d7b94fd7ab7e712d189dfc4ee2b1cda87",
+ "chksum_sha256": "6773f2b2ac256e33e4f352d0ab86d6bceaf91c9ca2f32e81f7678f4f87a215a8",
"format": 1
},
{
@@ -1240,10 +1254,24 @@
"format": 1
},
{
+ "name": "CHANGELOG.md",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "b99dd5a4c3af9a341ee8435a0bd595a093508da336b35963c9f4c21e40442a90",
+ "format": 1
+ },
+ {
+ "name": "CHANGELOG.md.license",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6eb915239f9f35407fa68fdc41ed6522f1fdcce11badbdcd6057548023179ac1",
+ "format": 1
+ },
+ {
"name": "CHANGELOG.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7f88e8738859c0d903b42d2a5dcada13a7fd01fb3269ace2974666e0817e2e82",
+ "chksum_sha256": "6f13293d73ce0d0f4ac5a07b1b7e69d3efbfd36dca003148072b792bb5678ffe",
"format": 1
},
{
@@ -1264,7 +1292,7 @@
"name": "README.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "025ee8cc4b894b4a0b87c35b4cef0c747554d44b222c3a4b71344ce8150a49b7",
+ "chksum_sha256": "be40d1889fd07a702d1422a4da11a614fc9cce965f548eae37f50dfa8cf0ba46",
"format": 1
},
{
@@ -1278,7 +1306,7 @@
"name": "update-docs.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bd643824d0b7a1ef65d4760c32f1a38ef37dc7c2b4ec55eec76245164950cbb5",
+ "chksum_sha256": "1624ce27ddbbae15ba0cfefb86d793139201beda0f39a0243701558ee05d6e92",
"format": 1
}
],
diff --git a/ansible_collections/community/routeros/MANIFEST.json b/ansible_collections/community/routeros/MANIFEST.json
index c5afc614b..02c5b44f9 100644
--- a/ansible_collections/community/routeros/MANIFEST.json
+++ b/ansible_collections/community/routeros/MANIFEST.json
@@ -2,7 +2,7 @@
"collection_info": {
"namespace": "community",
"name": "routeros",
- "version": "2.8.2",
+ "version": "2.14.0",
"authors": [
"Egor Zaitsev (github.com/heuels)",
"Nikolay Dachev (github.com/NikolayDachev)",
@@ -31,7 +31,7 @@
"name": "FILES.json",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fa74768aa74fe395b07ca0059809ecea66739b21107d3a9e7ce2c81a45393211",
+ "chksum_sha256": "b61bc5f91d12dd9344c686a1ce2650fea27acfe4e6dceb5ac36d8fc236ecadc0",
"format": 1
},
"format": 1
diff --git a/ansible_collections/community/routeros/README.md b/ansible_collections/community/routeros/README.md
index 7378c34a0..df692d6d5 100644
--- a/ansible_collections/community/routeros/README.md
+++ b/ansible_collections/community/routeros/README.md
@@ -13,7 +13,7 @@ You can find [documentation for the modules and plugins in this collection here]
## Tested with Ansible
-Tested with the current Ansible 2.9, ansible-base 2.10, ansible-core 2.11, ansible-core 2.12, ansible-core 2.13, and ansible-core 2.14 releases and the current development version of ansible-core. Ansible versions before 2.9.10 are not supported.
+Tested with the current Ansible 2.9, ansible-base 2.10, ansible-core 2.11, ansible-core 2.12, ansible-core 2.13, ansible-core 2.14, ansible-core 2.15, and ansible-core 2.16 releases and the current development version of ansible-core. Ansible versions before 2.9.10 are not supported.
## External requirements
@@ -163,7 +163,7 @@ See [Ansible's dev guide](https://docs.ansible.com/ansible/devel/dev_guide/devel
## Release notes
-See the [changelog](https://github.com/ansible-collections/community.routeros/blob/main/CHANGELOG.rst).
+See the [changelog](https://github.com/ansible-collections/community.routeros/blob/main/CHANGELOG.md).
## Roadmap
diff --git a/ansible_collections/community/routeros/changelogs/changelog.yaml b/ansible_collections/community/routeros/changelogs/changelog.yaml
index e09fa3e38..e23348b3a 100644
--- a/ansible_collections/community/routeros/changelogs/changelog.yaml
+++ b/ansible_collections/community/routeros/changelogs/changelog.yaml
@@ -189,6 +189,156 @@ releases:
name: api_find_and_modify
namespace: ''
release_date: '2022-05-25'
+ 2.10.0:
+ changes:
+ bugfixes:
+ - api_info, api_modify - in the ``snmp`` path, ensure that ``engine-id-suffix``
+ is only available on RouterOS 7.10+, and that ``engine-id`` is read-only on
+ RouterOS 7.10+ (https://github.com/ansible-collections/community.routeros/issues/208,
+ https://github.com/ansible-collections/community.routeros/pull/218).
+ minor_changes:
+ - api_info - add new ``include_read_only`` option to select behavior for read-only
+ values. By default these are not returned (https://github.com/ansible-collections/community.routeros/pull/213).
+ - api_info, api_modify - add support for ``address-list`` and ``match-subdomain``
+ introduced by RouterOS 7.7 in the ``ip dns static`` path (https://github.com/ansible-collections/community.routeros/pull/197).
+ - api_info, api_modify - add support for ``user``, ``time`` and ``gmt-offset``
+ under the ``system clock`` path (https://github.com/ansible-collections/community.routeros/pull/210).
+ - api_info, api_modify - add support for the ``interface ppp-client`` path (https://github.com/ansible-collections/community.routeros/pull/199).
+ - api_info, api_modify - add support for the ``interface wireless`` path (https://github.com/ansible-collections/community.routeros/pull/195).
+ - api_info, api_modify - add support for the ``iot modbus`` path (https://github.com/ansible-collections/community.routeros/pull/205).
+ - api_info, api_modify - add support for the ``ip dhcp-server option`` and ``ip
+ dhcp-server option sets`` paths (https://github.com/ansible-collections/community.routeros/pull/223).
+ - api_info, api_modify - add support for the ``ip upnp interfaces``, ``tool
+ graphing interface``, ``tool graphing resource`` paths (https://github.com/ansible-collections/community.routeros/pull/227).
+ - api_info, api_modify - add support for the ``ipv6 firewall nat`` path (https://github.com/ansible-collections/community.routeros/pull/204).
+ - api_info, api_modify - add support for the ``mode`` property in ``ip neighbor
+ discovery-settings`` introduced in RouterOS 7.7 (https://github.com/ansible-collections/community.routeros/pull/198).
+ - api_info, api_modify - add support for the ``port remote-access`` path (https://github.com/ansible-collections/community.routeros/pull/224).
+ - api_info, api_modify - add support for the ``routing filter rule`` and ``routing
+ filter select-rule`` paths (https://github.com/ansible-collections/community.routeros/pull/200).
+ - api_info, api_modify - add support for the ``routing table`` path in RouterOS
+ 7 (https://github.com/ansible-collections/community.routeros/pull/215).
+ - api_info, api_modify - add support for the ``tool netwatch`` path in RouterOS
+ 7 (https://github.com/ansible-collections/community.routeros/pull/216).
+ - api_info, api_modify - add support for the ``user settings`` path (https://github.com/ansible-collections/community.routeros/pull/201).
+ - api_info, api_modify - add support for the ``user`` path (https://github.com/ansible-collections/community.routeros/pull/211).
+ - api_info, api_modify - finalize fields for the ``interface wireless security-profiles``
+ path and enable it (https://github.com/ansible-collections/community.routeros/pull/203).
+ - api_info, api_modify - finalize fields for the ``ppp profile`` path and enable
+ it (https://github.com/ansible-collections/community.routeros/pull/217).
+ - api_modify - add new ``handle_read_only`` and ``handle_write_only`` options
+ to handle the module's behavior for read-only and write-only fields (https://github.com/ansible-collections/community.routeros/pull/213).
+ - api_modify, api_info - support API paths ``routing id``, ``routing bgp connection``
+ (https://github.com/ansible-collections/community.routeros/pull/220).
+ release_summary: Bugfix and feature release.
+ fragments:
+ - 195-add-interface-wireless-data.yml
+ - 197-dns-static-addrlist-matchsubdomain.yml
+ - 198-ip-nd-mode.yml
+ - 199-add-interface-pppclient.yml
+ - 2.10.0.yml
+ - 200-add-routing-filter.yml
+ - 201-add-user-settings.yml
+ - 203-wireless-security-profiles.yml
+ - 204-add-ipv6-firewall-nat.yml
+ - 205-add-iot-modbus.yml
+ - 210-date-time-gmt-offset.yml
+ - 211-user.yml
+ - 213-read-write-only.yml
+ - 215-add-routing-table.yml
+ - 216-add-tool-netwatch.yml
+ - 217-ppp-profiles.yml
+ - 218-snmp-engine-id.yml
+ - 220-routing-id-bgp-connection.yml
+ - 223-add-ip-dhcp-server-option.yml
+ - 224-add-port-remote-access.yml
+ - 227-add-upnp-graphing.yml
+ release_date: '2023-10-08'
+ 2.11.0:
+ changes:
+ minor_changes:
+ - api_info, api_modify - add missing DoH parameters ``doh-max-concurrent-queries``,
+ ``doh-max-server-connections``, and ``doh-timeout`` to the ``ip dns`` path
+ (https://github.com/ansible-collections/community.routeros/issues/230, https://github.com/ansible-collections/community.routeros/pull/235)
+ - api_info, api_modify - add missing parameters ``address-list``, ``address-list-timeout``,
+ ``randomise-ports``, and ``realm`` to subpaths of the ``ip firewall`` path
+ (https://github.com/ansible-collections/community.routeros/issues/236, https://github.com/ansible-collections/community.routeros/pull/237).
+ - api_info, api_modify - mark the ``interface wireless`` parameter ``running``
+ as read-only (https://github.com/ansible-collections/community.routeros/pull/233).
+ - api_info, api_modify - set the default value to ``false`` for the ``disabled``
+ parameter in some more paths where it can be seen in the documentation (https://github.com/ansible-collections/community.routeros/pull/237).
+ - api_modify - add missing ``comment`` attribute to ``/routing id`` (https://github.com/ansible-collections/community.routeros/pull/234).
+ - api_modify - add missing attributes to the ``routing bgp connection`` path
+ (https://github.com/ansible-collections/community.routeros/pull/234).
+ - api_modify - add versioning to the ``/tool e-mail`` path (RouterOS 7.12 release)
+ (https://github.com/ansible-collections/community.routeros/pull/234).
+ - api_modify - make ``/ip traffic-flow target`` a multiple value attribute (https://github.com/ansible-collections/community.routeros/pull/234).
+ release_summary: Feature and bugfix release.
+ fragments:
+ - 2.11.0.yml
+ - 233-wireless-running-read-only.yml
+ - 234-bugfixes-and-update-adaptations.yml
+ - 235-add-missing-dns-attributes.yml
+ - 237-add-missing-ip-firewall-attributes.yml
+ release_date: '2023-12-03'
+ 2.12.0:
+ changes:
+ minor_changes:
+ - api_info, api_modify - add ``interface ovpn-client`` path (https://github.com/ansible-collections/community.routeros/issues/242,
+ https://github.com/ansible-collections/community.routeros/pull/244).
+ - api_info, api_modify - add ``radius`` path (https://github.com/ansible-collections/community.routeros/issues/241,
+ https://github.com/ansible-collections/community.routeros/pull/245).
+ - api_info, api_modify - add ``routing rule`` path (https://github.com/ansible-collections/community.routeros/issues/162,
+ https://github.com/ansible-collections/community.routeros/pull/246).
+ - api_info, api_modify - add missing path ``routing bgp template`` (https://github.com/ansible-collections/community.routeros/pull/243).
+ - api_info, api_modify - add support for the ``tx-power`` attribute in ``interface
+ wireless`` (https://github.com/ansible-collections/community.routeros/pull/239).
+ - api_info, api_modify - removed ``host`` primary key in ``tool netwatch`` path
+ (https://github.com/ansible-collections/community.routeros/pull/248).
+ - api_modify, api_info - added support for ``interface wifiwave2`` (https://github.com/ansible-collections/community.routeros/pull/226).
+ release_summary: Feature release.
+ fragments:
+ - 2.12.0.yml
+ - 226-support-for-WifiWave2.yml
+ - 239-wireless-tx-power.yml
+ - 243-add-routing-bgp-template-path.yml
+ - 244-add-interface-ovpn-client-path.yml
+ - 245-add-radius-path.yml
+ - 246-add-routing-rule-path.yml
+ - 247-removed-primary-key-host-in-tool-netwatch.yml
+ release_date: '2024-01-21'
+ 2.13.0:
+ changes:
+ bugfixes:
+ - facts - fix date not getting removed for idempotent config export (https://github.com/ansible-collections/community.routeros/pull/262).
+ minor_changes:
+ - api_info, api_modify - make path ``user group`` modifiable and add ``comment``
+ attribute (https://github.com/ansible-collections/community.routeros/issues/256,
+ https://github.com/ansible-collections/community.routeros/pull/257).
+ - api_modify, api_info - add support for the ``ip vrf`` path in RouterOS 7 (https://github.com/ansible-collections/community.routeros/pull/259)
+ release_summary: Bugfix and feature release.
+ fragments:
+ - 2.13.0.yml
+ - 257-make-user_group-modifiable.yml
+ - 259-add-routeros7-support-for-ip-vrf.yml
+ - 262-fix-date-removal.yml
+ release_date: '2024-02-25'
+ 2.14.0:
+ changes:
+ minor_changes:
+ - api_info, api_modify - add read-only fields ``installed-version``, ``latest-version``
+ and ``status`` in ``system package update`` (https://github.com/ansible-collections/community.routeros/pull/263).
+ - api_info, api_modify - added support for ``interface wifi`` and its sub-paths
+ (https://github.com/ansible-collections/community.routeros/pull/266).
+ - api_info, api_modify - remove default value for read-only ``running`` field
+ in ``interface wireless`` (https://github.com/ansible-collections/community.routeros/pull/264).
+ release_summary: Feature release.
+ fragments:
+ - 2.14.0.yml
+ - 263-sys-pkg-update.yml
+ - 264-wireless-running-default.yml
+ - 266-interface-wifi.yml
+ release_date: '2024-03-25'
2.2.0:
changes:
bugfixes:
@@ -276,8 +426,8 @@ releases:
in bytes (those will still appear as human readable in the ROS CLI) (https://github.com/ansible-collections/community.routeros/pull/131).
- api_modify, api_info - ``routing ospf area``, ``routing ospf area range``,
``routing ospf instance``, ``routing ospf interface-template`` paths are not
- fully implemeted for ROS6 due to the significat changes between ROS6 and ROS7
- (https://github.com/ansible-collections/community.routeros/pull/131).
+ fully implemented for ROS6 due to the significant changes between ROS6 and
+ ROS7 (https://github.com/ansible-collections/community.routeros/pull/131).
minor_changes:
- api* modules - Add new option ``force_no_cert`` to connect with ADH ciphers
(https://github.com/ansible-collections/community.routeros/pull/124).
@@ -447,3 +597,56 @@ releases:
- 180-fix-tls-in-tool-email.yml
- 2.8.2.yml
release_date: '2023-06-19'
+ 2.8.3:
+ changes:
+ known_issues:
+ - Ansible markup will show up in raw form on ansible-doc text output for ansible-core
+ before 2.15. If you have trouble deciphering the documentation markup, please
+ upgrade to ansible-core 2.15 (or newer), or read the HTML documentation on
+ https://docs.ansible.com/ansible/devel/collections/community/routeros/.
+ release_summary: 'Maintenance release with updated documentation.
+
+
+ From this version on, community.routeros is using the new `Ansible semantic
+ markup
+
+ <https://docs.ansible.com/ansible/devel/dev_guide/developing_modules_documenting.html#semantic-markup-within-module-documentation>`__
+
+ in its documentation. If you look at documentation with the ansible-doc CLI
+ tool
+
+ from ansible-core before 2.15, please note that it does not render the markup
+
+ correctly. You should be still able to read it in most cases, but you need
+
+ ansible-core 2.15 or later to see it as it is intended. Alternatively you
+ can
+
+ look at `the devel docsite <https://docs.ansible.com/ansible/devel/collections/community/routeros/>`__
+
+ for the rendered HTML version of the documentation of the latest release.
+
+ '
+ fragments:
+ - 2.8.3.yml
+ - semantic-markup.yml
+ release_date: '2023-06-27'
+ 2.9.0:
+ changes:
+ bugfixes:
+ - api_modify, api_info - add missing parameter ``engine-id-suffix`` for the
+ ``snmp`` path (https://github.com/ansible-collections/community.routeros/issues/189,
+ https://github.com/ansible-collections/community.routeros/pull/190).
+ minor_changes:
+ - api_info, api_modify - add path ``caps-man channel`` and enable path ``caps-man
+ manager interface`` (https://github.com/ansible-collections/community.routeros/issues/193,
+ https://github.com/ansible-collections/community.routeros/pull/194).
+ - api_info, api_modify - add path ``ip traffic-flow target`` (https://github.com/ansible-collections/community.routeros/issues/191,
+ https://github.com/ansible-collections/community.routeros/pull/192).
+ release_summary: Bugfix and feature release.
+ fragments:
+ - 180-fix-engine-id-suffix-in-snmp.yml
+ - 192-add-ip_traffic-flow_target-path.yml
+ - 194-add-caps-man_channel-and-caps-man_manager_interface.yml
+ - 2.9.0.yml
+ release_date: '2023-08-15'
diff --git a/ansible_collections/community/routeros/changelogs/config.yaml b/ansible_collections/community/routeros/changelogs/config.yaml
index 70a1f6701..86412bafc 100644
--- a/ansible_collections/community/routeros/changelogs/config.yaml
+++ b/ansible_collections/community/routeros/changelogs/config.yaml
@@ -12,6 +12,9 @@ mention_ancestor: true
flatmap: true
new_plugins_after_name: removed_features
notesdir: fragments
+output_formats:
+- rst
+- md
prelude_section_name: release_summary
prelude_section_title: Release Summary
sections:
diff --git a/ansible_collections/community/routeros/docs/docsite/rst/api-guide.rst b/ansible_collections/community/routeros/docs/docsite/rst/api-guide.rst
index f3bb6295b..6140d819d 100644
--- a/ansible_collections/community/routeros/docs/docsite/rst/api-guide.rst
+++ b/ansible_collections/community/routeros/docs/docsite/rst/api-guide.rst
@@ -8,7 +8,7 @@
How to connect to RouterOS devices with the RouterOS API
========================================================
-You can use the :ref:`community.routeros.api module <ansible_collections.community.routeros.api_module>` to connect to a RouterOS device with the RouterOS API. More specific module to modify certain entries are the :ref:`community.routeros.api_modify <ansible_collections.community.routeros.api_modify_module>` and :ref:`community.routeros.api_find_and_modify <ansible_collections.community.routeros.api_find_and_modify_module>` modules. The :ref:`community.routeros.api_info module <ansible_collections.community.routeros.api_info_module>` allows to retrieve information on specific predefined paths that can be used as input for the ``community.routeros.api_modify`` module, and the :ref:`community.routeros.api_facts module <ansible_collections.community.routeros.api_facts_module>` allows to retrieve Ansible facts using the RouterOS API.
+You can use the :ansplugin:`community.routeros.api module <community.routeros.api#module>` to connect to a RouterOS device with the RouterOS API. More specific module to modify certain entries are the :ansplugin:`community.routeros.api_modify <community.routeros.api_modify#module>` and :ansplugin:`community.routeros.api_find_and_modify <community.routeros.api_find_and_modify#module>` modules. The :ansplugin:`community.routeros.api_info module <community.routeros.api_info#module>` allows to retrieve information on specific predefined paths that can be used as input for the :ansplugin:`community.routeros.api_modify <community.routeros.api_modify#module>` module, and the :ansplugin:`community.routeros.api_facts module <community.routeros.api_facts#module>` allows to retrieve Ansible facts using the RouterOS API.
No special setup is needed; the module needs to be run on a host that can connect to the device's API. The most common case is that the module is run on ``localhost``, either by using ``hosts: localhost`` in the playbook, or by using ``delegate_to: localhost`` for the task. The following example shows how to run the equivalent of ``/ip address print``:
@@ -59,12 +59,12 @@ This results in the following output:
PLAY RECAP *******************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
-Check out the documenation of the :ref:`community.routeros.api module <ansible_collections.community.routeros.api_module>` for details on the options.
+Check out the documentation of the :ansplugin:`community.routeros.api module <community.routeros.api#module>` for details on the options.
Using the ``community.routeros.api`` module defaults group
----------------------------------------------------------
-To avoid having to specify common parameters for all the API based modules in every task, you can use the ``community.routeros.api`` module defaults group:
+To avoid having to specify common parameters for all the API based modules in every task, you can use the ``community.routeros.api`` :ref:`module defaults group <module_defaults_groups>`:
.. code-block:: yaml+jinja
@@ -73,7 +73,7 @@ To avoid having to specify common parameters for all the API based modules in ev
hosts: localhost
gather_facts: false
module_defaults:
- group/community.routeros.api
+ group/community.routeros.api:
hostname: 192.168.1.1
password: admin
username: test1234
@@ -85,7 +85,7 @@ To avoid having to specify common parameters for all the API based modules in ev
# If you are using your own PKI, specify the path to your CA certificate here:
# ca_path: /path/to/ca-certificate.pem
tasks:
- - name: Gather facts"
+ - name: Gather facts
community.routeros.api_facts:
- name: Get "ip address print"
@@ -105,12 +105,12 @@ Here all three tasks will use the options set for the module defaults group.
Setting up encryption
---------------------
-It is recommended to always use ``tls: true`` when connecting with the API, even if you are only connecting to the device through a trusted network. The following options control how TLS/SSL is used:
+It is recommended to always use :ansopt:`tls=true` when connecting with the API, even if you are only connecting to the device through a trusted network. The following options control how TLS/SSL is used:
-:force_no_cert: Setting to ``true`` connects to the device without a certificate. **This is discouraged to use in production and is susceptible to Man-in-the-Middle attacks**, but might be useful when setting the device up. The default value is ``false``.
-:validate_certs: Setting to ``false`` disables any certificate validation. **This is discouraged to use in production**, but is needed when setting the device up. The default value is ``true``.
-:validate_cert_hostname: Setting to ``false`` (default) disables hostname verification during certificate validation. This is needed if the hostnames specified in the certificate do not match the hostname used for connecting (usually the device's IP). It is recommended to set up the certificate correctly and set this to ``true``; the default ``false`` is chosen for backwards compatibility to an older version of the module.
-:ca_path: If you are not using a commerically trusted CA certificate to sign your device's certificate, or have not included your CA certificate in Python's truststore, you need to point this option to the CA certificate.
+:force_no_cert: Setting to :ansval:`true` connects to the device without a certificate. **This is discouraged to use in production and is susceptible to Man-in-the-Middle attacks**, but might be useful when setting the device up. The default value is :ansval:`false`.
+:validate_certs: Setting to :ansval:`false` disables any certificate validation. **This is discouraged to use in production**, but is needed when setting the device up. The default value is :ansval:`true`.
+:validate_cert_hostname: Setting to :ansval:`false` (default) disables hostname verification during certificate validation. This is needed if the hostnames specified in the certificate do not match the hostname used for connecting (usually the device's IP). It is recommended to set up the certificate correctly and set this to :ansval:`true`; the default :ansval:`false` is chosen for backwards compatibility to an older version of the module.
+:ca_path: If you are not using a commercially trusted CA certificate to sign your device's certificate, or have not included your CA certificate in Python's truststore, you need to point this option to the CA certificate.
We recommend to create a CA certificate that is used to sign the certificates for your RouterOS devices, and have the certificates include the correct hostname(s), including the IP of the device. That way, you can fully enable TLS and be sure that you always talk to the correct device.
@@ -124,7 +124,7 @@ Installing a certificate on a MikroTik router
Installing the certificate is best done with the SSH connection. (See the :ref:`ansible_collections.community.routeros.docsite.ssh-guide` guide for more information.) Once the certificate has been installed, and the HTTPS API enabled, it's easier to work with the API, since it has a quite a few less problems, and returns data as JSON objects instead of text you first have to parse.
-First you have to convert the certificate and its private key to a `PKCS #12 bundle <https://en.wikipedia.org/wiki/PKCS_12>`_. This can be done with the :ref:`community.crypto.openssl_pkcs12 <ansible_collections.community.crypto.openssl_pkcs12_module>`. The following playbook assumes that the certificate is available as ``keys/{{ inventory_hostname }}.pem``, and its private key is available as ``keys/{{ inventory_hostname }}.key``. It generates a random passphrase to protect the PKCS#12 file.
+First you have to convert the certificate and its private key to a `PKCS #12 bundle <https://en.wikipedia.org/wiki/PKCS_12>`_. This can be done with the :ansplugin:`community.crypto.openssl_pkcs12 <community.crypto.openssl_pkcs12#module>`. The following playbook assumes that the certificate is available as ``keys/{{ inventory_hostname }}.pem``, and its private key is available as ``keys/{{ inventory_hostname }}.key``. It generates a random passphrase to protect the PKCS#12 file.
.. code-block:: yaml+jinja
@@ -186,7 +186,7 @@ First you have to convert the certificate and its private key to a `PKCS #12 bun
The playbook also assumes that ``admin_network`` describes the network from which the HTTPS and API interface can be accessed. This can be for example ``192.168.1.0/24``.
-When this playbook completed successfully, you should be able to use the HTTPS admin interface (reachable in a browser from ``https://192.168.1.1/``, with the correct IP inserted), as well as the :ref:`community.routeros.api module <ansible_collections.community.routeros.api_module>` module with TLS and certificate validation enabled:
+When this playbook completed successfully, you should be able to use the HTTPS admin interface (reachable in a browser from ``https://192.168.1.1/``, with the correct IP inserted), as well as the :ansplugin:`community.routeros.api module <community.routeros.api#module>` module with TLS and certificate validation enabled:
.. code-block:: yaml+jinja
diff --git a/ansible_collections/community/routeros/docs/docsite/rst/quoting.rst b/ansible_collections/community/routeros/docs/docsite/rst/quoting.rst
index 3091fc857..b1c045382 100644
--- a/ansible_collections/community/routeros/docs/docsite/rst/quoting.rst
+++ b/ansible_collections/community/routeros/docs/docsite/rst/quoting.rst
@@ -8,12 +8,12 @@
How to quote and unquote commands and arguments
===============================================
-When using the :ref:`community.routeros.command module <ansible_collections.community.routeros.command_module>` or the :ref:`community.routeros.api module <ansible_collections.community.routeros.api_module>` modules, you need to pass text data in quoted form. While in some cases quoting is not needed (when passing IP addresses or names without spaces, for example), in other cases it is required, like when passing a comment which contains a space.
+When using the :ansplugin:`community.routeros.command module <community.routeros.command#module>` or the :ansplugin:`community.routeros.api module <community.routeros.api#module>` modules, you need to pass text data in quoted form. While in some cases quoting is not needed (when passing IP addresses or names without spaces, for example), in other cases it is required, like when passing a comment which contains a space.
The community.routeros collection provides a set of Jinja2 filter plugins which helps you with these tasks:
-- The :ref:`community.routeros.quote_argument_value filter <ansible_collections.community.routeros.quote_argument_value_filter>` quotes an argument value: ``'this is a "comment"' | community.routeros.quote_argument_value == '"this is a \\"comment\\""'``.
-- The :ref:`community.routeros.quote_argument filter <ansible_collections.community.routeros.quote_argument_filter>` quotes an argument with or without a value: ``'comment=this is a "comment"' | community.routeros.quote_argument == 'comment="this is a \\"comment\\""'``.
-- The :ref:`community.routeros.join filter <ansible_collections.community.routeros.join_filter>` quotes a list of arguments and joins them to one string: ``['foo=bar', 'comment=foo is bar'] | community.routeros.join == 'foo=bar comment="foo is bar"'``.
-- The :ref:`community.routeros.split filter <ansible_collections.community.routeros.split_filter>` splits a command into a list of arguments (with or without values): ``'foo=bar comment="foo is bar"' | community.routeros.split == ['foo=bar', 'comment=foo is bar']``
-- The :ref:`community.routeros.list_to_dict filter <ansible_collections.community.routeros.list_to_dict_filter>` splits a list of arguments with values into a dictionary: ``['foo=bar', 'comment=foo is bar'] | community.routeros.list_to_dict == {'foo': 'bar', 'comment': 'foo is bar'}``. It has two optional arguments: ``require_assignment`` (default value ``true``) allows to accept arguments without values when set to ``false``; and ``skip_empty_values`` (default value ``false``) allows to skip arguments whose value is empty.
+- The :ansplugin:`community.routeros.quote_argument_value filter <community.routeros.quote_argument_value#filter>` quotes an argument value: ``'this is a "comment"' | community.routeros.quote_argument_value == '"this is a \\"comment\\""'``.
+- The :ansplugin:`community.routeros.quote_argument filter <community.routeros.quote_argument#filter>` quotes an argument with or without a value: ``'comment=this is a "comment"' | community.routeros.quote_argument == 'comment="this is a \\"comment\\""'``.
+- The :ansplugin:`community.routeros.join filter <community.routeros.join#filter>` quotes a list of arguments and joins them to one string: ``['foo=bar', 'comment=foo is bar'] | community.routeros.join == 'foo=bar comment="foo is bar"'``.
+- The :ansplugin:`community.routeros.split filter <community.routeros.split#filter>` splits a command into a list of arguments (with or without values): ``'foo=bar comment="foo is bar"' | community.routeros.split == ['foo=bar', 'comment=foo is bar']``
+- The :ansplugin:`community.routeros.list_to_dict filter <community.routeros.list_to_dict#filter>` splits a list of arguments with values into a dictionary: ``['foo=bar', 'comment=foo is bar'] | community.routeros.list_to_dict == {'foo': 'bar', 'comment': 'foo is bar'}``. It has two optional arguments: :ansopt:`community.routeros.list_to_dict#filter:require_assignment` (default value :ansval:`true`) allows to accept arguments without values when set to :ansval:`false`; and :ansopt:`community.routeros.list_to_dict#filter:skip_empty_values` (default value :ansval:`false`) allows to skip arguments whose value is empty.
diff --git a/ansible_collections/community/routeros/docs/docsite/rst/ssh-guide.rst b/ansible_collections/community/routeros/docs/docsite/rst/ssh-guide.rst
index bdbdbfe84..4b0eb2017 100644
--- a/ansible_collections/community/routeros/docs/docsite/rst/ssh-guide.rst
+++ b/ansible_collections/community/routeros/docs/docsite/rst/ssh-guide.rst
@@ -10,17 +10,17 @@ How to connect to RouterOS devices with SSH
The collection offers two modules to connect to RouterOS devies with SSH:
-- The :ref:`community.routeros.facts module <ansible_collections.community.routeros.facts_module>` gathers facts about a RouterOS device;
-- The :ref:`community.routeros.command module <ansible_collections.community.routeros.command_module>` executes commands on a RouterOS device.
+- The :ansplugin:`community.routeros.facts module <community.routeros.facts#module>` gathers facts about a RouterOS device;
+- The :ansplugin:`community.routeros.command module <community.routeros.command#module>` executes commands on a RouterOS device.
-The modules need the :ref:`ansible.netcommon.network_cli connection plugin <ansible_collections.ansible.netcommon.network_cli_connection>` for this.
+The modules need the :ansplugin:`ansible.netcommon.network_cli connection plugin <ansible.netcommon.network_cli#connection>` for this.
Important notes
---------------
1. The SSH-based modules do not support arbitrary symbols in the router's identity. If you are having trouble connecting to your device, please make sure that your MikroTik's identity contains only alphanumeric characters and dashes. Also make sure that the identity string is not longer than 19 characters (`see issue for details <https://github.com/ansible-collections/community.routeros/issues/31>`__). Similar problems can happen for unsupported characters in your username.
-2. The :ref:`community.routeros.command module <ansible_collections.community.routeros.command_module>` does not support nesting commands and expects every command to start with a forward slash (``/``). Running the following command will produce an error:
+2. The :ansplugin:`community.routeros.command module <community.routeros.command#module>` does not support nesting commands and expects every command to start with a forward slash (``/``). Running the following command will produce an error:
.. code-block:: yaml+jinja
@@ -29,9 +29,11 @@ Important notes
- /ip
- print
-3. When using the :ref:`community.routeros.command module <ansible_collections.community.routeros.command_module>` module, make sure to not specify too long commands. Alternatively, add something like ``+cet512w`` to the username (replace ``admin`` with ``admin+cet512w``) to tell RouterOS to not wrap before 512 characters in a line (`see issue for details <https://github.com/ansible-collections/community.routeros/issues/6>`__).
+3. When using the :ansplugin:`community.routeros.command module <community.routeros.command#module>` module, make sure to not specify too long commands. Alternatively, add something like ``+cet512w`` to the username (replace ``admin`` with ``admin+cet512w``) to tell RouterOS to not wrap before 512 characters in a line (`see issue for details <https://github.com/ansible-collections/community.routeros/issues/6>`__).
-4. Finally, the :ref:`ansible.netcommon.network_cli connection plugin <ansible_collections.ansible.netcommon.network_cli_connection>` uses `paramiko <https://pypi.org/project/paramiko/>`_ by default to connect to devices with SSH. You can set its ``ssh_type`` option to ``libssh`` to use `ansible-pylibssh <https://pypi.org/project/ansible-pylibssh/>`_ instead, which offers Python bindings to libssh. See its documentation for details.
+4. The :ansplugin:`ansible.netcommon.network_cli connection plugin <ansible.netcommon.network_cli#connection>` uses `paramiko <https://pypi.org/project/paramiko/>`_ by default to connect to devices with SSH. You can set its :ansopt:`ansible.netcommon.network_cli#connection:ssh_type` option to :ansval:`libssh` to use `ansible-pylibssh <https://pypi.org/project/ansible-pylibssh/>`_ instead, which offers Python bindings to libssh. See its documentation for details.
+
+5. User is **not allowed** to login via SSH by password to modern Mikrotik if SSH key for the user is added!
Setting up an inventory
-----------------------
@@ -49,7 +51,7 @@ An example inventory ``hosts`` file for a RouterOS device is as follows:
ansible_user=admin
ansible_ssh_pass=test1234
-This tells Ansible that you have a RouterOS device called ``router`` with IP ``192.168.2.1``. Ansible should use the :ref:`ansible.netcommon.network_cli connection plugin <ansible_collections.ansible.netcommon.network_cli_connection>` together with the the :ref:`community.routeros.routeros cliconf plugin <ansible_collections.community.routeros.routeros_cliconf>`. The credentials are stored as ``ansible_user`` and ``ansible_ssh_pass`` in the inventory.
+This tells Ansible that you have a RouterOS device called ``router`` with IP ``192.168.2.1``. Ansible should use the :ansplugin:`ansible.netcommon.network_cli connection plugin <ansible.netcommon.network_cli#connection>` together with the the :ansplugin:`community.routeros.routeros cliconf plugin <community.routeros.routeros#cliconf>`. The credentials are stored as ``ansible_user`` and ``ansible_ssh_pass`` in the inventory.
Connecting to the device
------------------------
diff --git a/ansible_collections/community/routeros/plugins/doc_fragments/api.py b/ansible_collections/community/routeros/plugins/doc_fragments/api.py
index dea374b95..7f77e8fe4 100644
--- a/ansible_collections/community/routeros/plugins/doc_fragments/api.py
+++ b/ansible_collections/community/routeros/plugins/doc_fragments/api.py
@@ -43,48 +43,48 @@ options:
- ssl
port:
description:
- - RouterOS api port. If I(tls) is set, port will apply to TLS/SSL connection.
- - Defaults are C(8728) for the HTTP API, and C(8729) for the HTTPS API.
+ - RouterOS api port. If O(tls) is set, port will apply to TLS/SSL connection.
+ - Defaults are V(8728) for the HTTP API, and V(8729) for the HTTPS API.
type: int
force_no_cert:
description:
- - Set to C(true) to connect without a certificate when I(tls=true).
- - See also I(validate_certs).
+ - Set to V(true) to connect without a certificate when O(tls=true).
+ - See also O(validate_certs).
- B(Note:) this forces the use of anonymous Diffie-Hellman (ADH) ciphers. The protocol is susceptible
to Man-in-the-Middle attacks, because the keys used in the exchange are not authenticated.
Instead of simply connecting without a certificate to "make things work" have a look at
- I(validate_certs) and I(ca_path).
+ O(validate_certs) and O(ca_path).
type: bool
default: false
version_added: 2.4.0
validate_certs:
description:
- - Set to C(false) to skip validation of TLS certificates.
- - See also I(validate_cert_hostname). Only used when I(tls=true).
+ - Set to V(false) to skip validation of TLS certificates.
+ - See also O(validate_cert_hostname). Only used when O(tls=true).
- B(Note:) instead of simply deactivating certificate validations to "make things work",
please consider creating your own CA certificate and using it to sign certificates used
- for your router. You can tell the module about your CA certificate with the I(ca_path)
+ for your router. You can tell the module about your CA certificate with the O(ca_path)
option.
type: bool
default: true
version_added: 1.2.0
validate_cert_hostname:
description:
- - Set to C(true) to validate hostnames in certificates.
- - See also I(validate_certs). Only used when I(tls=true) and I(validate_certs=true).
+ - Set to V(true) to validate hostnames in certificates.
+ - See also O(validate_certs). Only used when O(tls=true) and O(validate_certs=true).
type: bool
default: false
version_added: 1.2.0
ca_path:
description:
- PEM formatted file that contains a CA certificate to be used for certificate validation.
- - See also I(validate_cert_hostname). Only used when I(tls=true) and I(validate_certs=true).
+ - See also O(validate_cert_hostname). Only used when O(tls=true) and O(validate_certs=true).
type: path
version_added: 1.2.0
encoding:
description:
- Use the specified encoding when communicating with the RouterOS device.
- - Default is C(ASCII). Note that C(UTF-8) requires librouteros 3.2.1 or newer.
+ - Default is V(ASCII). Note that V(UTF-8) requires librouteros 3.2.1 or newer.
type: str
default: ASCII
version_added: 2.1.0
diff --git a/ansible_collections/community/routeros/plugins/filter/list_to_dict.yml b/ansible_collections/community/routeros/plugins/filter/list_to_dict.yml
index 920414ced..6e7992d3d 100644
--- a/ansible_collections/community/routeros/plugins/filter/list_to_dict.yml
+++ b/ansible_collections/community/routeros/plugins/filter/list_to_dict.yml
@@ -12,18 +12,18 @@ DOCUMENTATION:
options:
_input:
description:
- - A list of assignments. Can be the result of the C(community.routeros.split) filter.
+ - A list of assignments. Can be the result of the P(community.routeros.split#filter) filter.
type: list
elements: string
required: true
require_assignment:
description:
- - Allows to accept arguments without values when set to C(false).
+ - Allows to accept arguments without values when set to V(false).
type: boolean
default: true
skip_empty_values:
description:
- - Allows to skip arguments whose value is empty when set to C(true).
+ - Allows to skip arguments whose value is empty when set to V(true).
type: boolean
default: false
author:
diff --git a/ansible_collections/community/routeros/plugins/module_utils/_api_data.py b/ansible_collections/community/routeros/plugins/module_utils/_api_data.py
index 59e5b5c52..a421cffee 100644
--- a/ansible_collections/community/routeros/plugins/module_utils/_api_data.py
+++ b/ansible_collections/community/routeros/plugins/module_utils/_api_data.py
@@ -9,9 +9,81 @@
from __future__ import absolute_import, division, print_function
__metaclass__ = type
+from ansible_collections.community.routeros.plugins.module_utils.version import LooseVersion
+
+
+def _compare(a, b, comparator):
+ if comparator == '==':
+ return a == b
+ if comparator == '!=':
+ return a != b
+ if comparator == '<':
+ return a < b
+ if comparator == '<=':
+ return a <= b
+ if comparator == '>':
+ return a > b
+ if comparator == '>=':
+ return a >= b
+ raise ValueError('Unknown comparator "{comparator}"'.format(comparator=comparator))
+
class APIData(object):
- def __init__(self, primary_keys=None,
+ def __init__(self,
+ unversioned=None,
+ versioned=None):
+ if (unversioned is None) == (versioned is None):
+ raise ValueError('either unversioned or versioned must be provided')
+ self.unversioned = unversioned
+ self.versioned = versioned
+ if self.unversioned is not None:
+ self.needs_version = self.unversioned.needs_version
+ self.fully_understood = self.unversioned.fully_understood
+ else:
+ self.needs_version = self.versioned is not None
+ # Mark as 'fully understood' if it is for at least one version
+ self.fully_understood = False
+ for dummy, dummy, unversioned in self.versioned:
+ if unversioned and not isinstance(unversioned, str) and unversioned.fully_understood:
+ self.fully_understood = True
+ break
+ self._current = None if self.needs_version else self.unversioned
+
+ def _select(self, data, api_version):
+ if data is None:
+ self._current = None
+ return False, None
+ if isinstance(data, str):
+ self._current = None
+ return False, data
+ self._current = data.specialize_for_version(api_version)
+ return self._current.fully_understood, None
+
+ def provide_version(self, version):
+ if not self.needs_version:
+ return self.unversioned.fully_understood, None
+ api_version = LooseVersion(version)
+ if self.unversioned is not None:
+ self._current = self.unversioned.specialize_for_version(api_version)
+ return self._current.fully_understood, None
+ for other_version, comparator, data in self.versioned:
+ if other_version == '*' and comparator == '*':
+ return self._select(data, api_version)
+ other_api_version = LooseVersion(other_version)
+ if _compare(api_version, other_api_version, comparator):
+ return self._select(data, api_version)
+ self._current = None
+ return False, None
+
+ def get_data(self):
+ if self._current is None:
+ raise ValueError('either provide_version() was not called or it returned False')
+ return self._current
+
+
+class VersionedAPIData(object):
+ def __init__(self,
+ primary_keys=None,
stratify_keys=None,
required_one_of=None,
mutually_exclusive=None,
@@ -20,7 +92,8 @@ class APIData(object):
unknown_mechanism=False,
fully_understood=False,
fixed_entries=False,
- fields=None):
+ fields=None,
+ versioned_fields=None):
if sum([primary_keys is not None, stratify_keys is not None, has_identifier, single_value, unknown_mechanism]) > 1:
raise ValueError('primary_keys, stratify_keys, has_identifier, single_value, and unknown_mechanism are mutually exclusive')
if unknown_mechanism and fully_understood:
@@ -39,6 +112,17 @@ class APIData(object):
if fields is None:
raise ValueError('fields must be provided')
self.fields = fields
+ if versioned_fields is not None:
+ if not isinstance(versioned_fields, list):
+ raise ValueError('unversioned_fields must be a list')
+ for conditions, name, field in versioned_fields:
+ if not isinstance(conditions, (tuple, list)):
+ raise ValueError('conditions must be a list or tuple')
+ if not isinstance(field, KeyInfo):
+ raise ValueError('field must be a KeyInfo object')
+ if name in fields:
+ raise ValueError('"{name}" appears both in fields and versioned_fields'.format(name=name))
+ self.versioned_fields = versioned_fields or []
if primary_keys:
for pk in primary_keys:
if pk not in fields:
@@ -61,26 +145,70 @@ class APIData(object):
for ek in exclusive_list:
if ek not in fields:
raise ValueError('Mutually exclusive key {ek} must be in fields!'.format(ek=ek))
+ self.needs_version = len(self.versioned_fields) > 0
+
+ def specialize_for_version(self, api_version):
+ fields = self.fields.copy()
+ for conditions, name, field in self.versioned_fields:
+ matching = True
+ for other_version, comparator in conditions:
+ other_api_version = LooseVersion(other_version)
+ if not _compare(api_version, other_api_version, comparator):
+ matching = False
+ break
+ if matching:
+ if name in fields:
+ raise ValueError(
+ 'Internal error: field "{field}" already exists for {version}'.format(field=name, version=api_version)
+ )
+ fields[name] = field
+ return VersionedAPIData(
+ primary_keys=self.primary_keys,
+ stratify_keys=self.stratify_keys,
+ required_one_of=self.required_one_of,
+ mutually_exclusive=self.mutually_exclusive,
+ has_identifier=self.has_identifier,
+ single_value=self.single_value,
+ unknown_mechanism=self.unknown_mechanism,
+ fully_understood=self.fully_understood,
+ fixed_entries=self.fixed_entries,
+ fields=fields,
+ )
class KeyInfo(object):
- def __init__(self, _dummy=None, can_disable=False, remove_value=None, absent_value=None, default=None, required=False, automatically_computed_from=None):
+ def __init__(self,
+ _dummy=None,
+ can_disable=False,
+ remove_value=None,
+ absent_value=None,
+ default=None,
+ required=False,
+ automatically_computed_from=None,
+ read_only=False,
+ write_only=False):
if _dummy is not None:
raise ValueError('KeyInfo() does not have positional arguments')
if sum([required, default is not None or can_disable, automatically_computed_from is not None]) > 1:
raise ValueError(
- 'required, default, automatically_computed_from, and can_disable are mutually exclusive ' +
+ 'required, default, automatically_computed_from, and can_disable are mutually exclusive '
'besides default and can_disable which can be set together')
if not can_disable and remove_value is not None:
raise ValueError('remove_value can only be specified if can_disable=True')
if absent_value is not None and any([default is not None, automatically_computed_from is not None, can_disable]):
raise ValueError('absent_value can not be combined with default, automatically_computed_from, can_disable=True, or absent_value')
+ if read_only and write_only:
+ raise ValueError('read_only and write_only cannot be used at the same time')
+ if read_only and any([can_disable, remove_value is not None, absent_value is not None, default is not None, required]):
+ raise ValueError('read_only can not be combined with can_disable, remove_value, absent_value, default, or required')
self.can_disable = can_disable
self.remove_value = remove_value
self.automatically_computed_from = automatically_computed_from
self.default = default
self.required = required
self.absent_value = absent_value
+ self.read_only = read_only
+ self.write_only = write_only
def split_path(path):
@@ -99,2762 +227,4452 @@ def join_path(path):
PATHS = {
('interface', 'bonding'): APIData(
- fully_understood=True,
- primary_keys=('name', ),
- fields={
- 'arp': KeyInfo(default='enabled'),
- 'arp-interval': KeyInfo(default='100ms'),
- 'arp-ip-targets': KeyInfo(default=''),
- 'arp-timeout': KeyInfo(default='auto'),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'disabled': KeyInfo(default=False),
- 'down-delay': KeyInfo(default='0ms'),
- 'forced-mac-address': KeyInfo(can_disable=True),
- 'lacp-rate': KeyInfo(default='30secs'),
- 'lacp-user-key': KeyInfo(can_disable=True, remove_value=0),
- 'link-monitoring': KeyInfo(default='mii'),
- 'mii-interval': KeyInfo(default='100ms'),
- 'min-links': KeyInfo(default=0),
- 'mlag-id': KeyInfo(can_disable=True, remove_value=0),
- 'mode': KeyInfo(default='balance-rr'),
- 'mtu': KeyInfo(default=1500),
- 'name': KeyInfo(),
- 'primary': KeyInfo(default='none'),
- 'slaves': KeyInfo(required=True),
- 'transmit-hash-policy': KeyInfo(default='layer-2'),
- 'up-delay': KeyInfo(default='0ms'),
- }
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ 'arp': KeyInfo(default='enabled'),
+ 'arp-interval': KeyInfo(default='100ms'),
+ 'arp-ip-targets': KeyInfo(default=''),
+ 'arp-timeout': KeyInfo(default='auto'),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'down-delay': KeyInfo(default='0ms'),
+ 'forced-mac-address': KeyInfo(can_disable=True),
+ 'lacp-rate': KeyInfo(default='30secs'),
+ 'lacp-user-key': KeyInfo(can_disable=True, remove_value=0),
+ 'link-monitoring': KeyInfo(default='mii'),
+ 'mii-interval': KeyInfo(default='100ms'),
+ 'min-links': KeyInfo(default=0),
+ 'mlag-id': KeyInfo(can_disable=True, remove_value=0),
+ 'mode': KeyInfo(default='balance-rr'),
+ 'mtu': KeyInfo(default=1500),
+ 'name': KeyInfo(),
+ 'primary': KeyInfo(default='none'),
+ 'slaves': KeyInfo(required=True),
+ 'transmit-hash-policy': KeyInfo(default='layer-2'),
+ 'up-delay': KeyInfo(default='0ms'),
+ }
+ ),
),
('interface', 'bridge'): APIData(
- fully_understood=True,
- primary_keys=('name', ),
- fields={
- 'admin-mac': KeyInfo(default=''),
- 'ageing-time': KeyInfo(default='5m'),
- 'arp': KeyInfo(default='enabled'),
- 'arp-timeout': KeyInfo(default='auto'),
- 'auto-mac': KeyInfo(default=True),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'dhcp-snooping': KeyInfo(default=False),
- 'disabled': KeyInfo(default=False),
- 'ether-type': KeyInfo(default='0x8100'),
- 'fast-forward': KeyInfo(default=True),
- 'frame-types': KeyInfo(default='admit-all'),
- 'forward-delay': KeyInfo(default='15s'),
- 'igmp-snooping': KeyInfo(default=False),
- 'ingress-filtering': KeyInfo(default=True),
- 'max-message-age': KeyInfo(default='20s'),
- 'mtu': KeyInfo(default='auto'),
- 'name': KeyInfo(),
- 'priority': KeyInfo(default='0x8000'),
- 'protocol-mode': KeyInfo(default='rstp'),
- 'pvid': KeyInfo(default=1),
- 'transmit-hold-count': KeyInfo(default=6),
- 'vlan-filtering': KeyInfo(default=False),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ 'admin-mac': KeyInfo(default=''),
+ 'ageing-time': KeyInfo(default='5m'),
+ 'arp': KeyInfo(default='enabled'),
+ 'arp-timeout': KeyInfo(default='auto'),
+ 'auto-mac': KeyInfo(default=True),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'dhcp-snooping': KeyInfo(default=False),
+ 'disabled': KeyInfo(default=False),
+ 'ether-type': KeyInfo(default='0x8100'),
+ 'fast-forward': KeyInfo(default=True),
+ 'frame-types': KeyInfo(default='admit-all'),
+ 'forward-delay': KeyInfo(default='15s'),
+ 'igmp-snooping': KeyInfo(default=False),
+ 'ingress-filtering': KeyInfo(default=True),
+ 'max-message-age': KeyInfo(default='20s'),
+ 'mtu': KeyInfo(default='auto'),
+ 'name': KeyInfo(),
+ 'priority': KeyInfo(default='0x8000'),
+ 'protocol-mode': KeyInfo(default='rstp'),
+ 'pvid': KeyInfo(default=1),
+ 'transmit-hold-count': KeyInfo(default=6),
+ 'vlan-filtering': KeyInfo(default=False),
+ },
+ ),
),
('interface', 'eoip'): APIData(
- fully_understood=True,
- primary_keys=('name',),
- fields={
- 'allow-fast-path': KeyInfo(default=True),
- 'arp': KeyInfo(default='enabled'),
- 'arp-timeout': KeyInfo(default='auto'),
- 'clamp-tcp-mss': KeyInfo(default=True),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'disabled': KeyInfo(default=False),
- 'dont-fragment': KeyInfo(default=False),
- 'dscp': KeyInfo(default='inherit'),
- 'ipsec-secret': KeyInfo(can_disable=True),
- 'keepalive': KeyInfo(default='10s,10', can_disable=True),
- 'local-address': KeyInfo(default='0.0.0.0'),
- 'loop-protect': KeyInfo(default='default'),
- 'loop-protect-disable-time': KeyInfo(default='5m'),
- 'loop-protect-send-interval': KeyInfo(default='5s'),
- 'mac-address': KeyInfo(),
- 'mtu': KeyInfo(default='auto'),
- 'name': KeyInfo(),
- 'remote-address': KeyInfo(required=True),
- 'tunnel-id': KeyInfo(required=True),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name',),
+ fields={
+ 'allow-fast-path': KeyInfo(default=True),
+ 'arp': KeyInfo(default='enabled'),
+ 'arp-timeout': KeyInfo(default='auto'),
+ 'clamp-tcp-mss': KeyInfo(default=True),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'dont-fragment': KeyInfo(default=False),
+ 'dscp': KeyInfo(default='inherit'),
+ 'ipsec-secret': KeyInfo(can_disable=True),
+ 'keepalive': KeyInfo(default='10s,10', can_disable=True),
+ 'local-address': KeyInfo(default='0.0.0.0'),
+ 'loop-protect': KeyInfo(default='default'),
+ 'loop-protect-disable-time': KeyInfo(default='5m'),
+ 'loop-protect-send-interval': KeyInfo(default='5s'),
+ 'mac-address': KeyInfo(),
+ 'mtu': KeyInfo(default='auto'),
+ 'name': KeyInfo(),
+ 'remote-address': KeyInfo(required=True),
+ 'tunnel-id': KeyInfo(required=True),
+ },
+ ),
),
('interface', 'ethernet'): APIData(
- fixed_entries=True,
- fully_understood=True,
- primary_keys=('default-name', ),
- fields={
- 'default-name': KeyInfo(),
- 'advertise': KeyInfo(),
- 'arp': KeyInfo(default='enabled'),
- 'arp-timeout': KeyInfo(default='auto'),
- 'auto-negotiation': KeyInfo(default=True),
- 'bandwidth': KeyInfo(default='unlimited/unlimited'),
- 'combo-mode': KeyInfo(can_disable=True),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'disabled': KeyInfo(default=False),
- 'fec-mode': KeyInfo(can_disable=True),
- 'full-duplex': KeyInfo(default=True),
- 'l2mtu': KeyInfo(default=1598),
- 'loop-protect': KeyInfo(default='default'),
- 'loop-protect-disable-time': KeyInfo(default='5m'),
- 'loop-protect-send-interval': KeyInfo(default='5s'),
- 'mac-address': KeyInfo(),
- 'mdix-enable': KeyInfo(),
- 'mtu': KeyInfo(default=1500),
- 'name': KeyInfo(),
- 'orig-mac-address': KeyInfo(),
- 'poe-out': KeyInfo(can_disable=True),
- 'poe-priority': KeyInfo(can_disable=True),
- 'poe-voltage': KeyInfo(can_disable=True),
- 'power-cycle-interval': KeyInfo(),
- 'power-cycle-ping-address': KeyInfo(can_disable=True),
- 'power-cycle-ping-enabled': KeyInfo(),
- 'power-cycle-ping-timeout': KeyInfo(can_disable=True),
- 'rx-flow-control': KeyInfo(default='off'),
- 'sfp-rate-select': KeyInfo(default='high'),
- 'sfp-shutdown-temperature': KeyInfo(default='95C'),
- 'speed': KeyInfo(),
- 'tx-flow-control': KeyInfo(default='off'),
- },
+ unversioned=VersionedAPIData(
+ fixed_entries=True,
+ fully_understood=True,
+ primary_keys=('default-name', ),
+ fields={
+ 'default-name': KeyInfo(),
+ 'advertise': KeyInfo(),
+ 'arp': KeyInfo(default='enabled'),
+ 'arp-timeout': KeyInfo(default='auto'),
+ 'auto-negotiation': KeyInfo(default=True),
+ 'bandwidth': KeyInfo(default='unlimited/unlimited'),
+ 'combo-mode': KeyInfo(can_disable=True),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'fec-mode': KeyInfo(can_disable=True),
+ 'full-duplex': KeyInfo(default=True),
+ 'l2mtu': KeyInfo(default=1598),
+ 'loop-protect': KeyInfo(default='default'),
+ 'loop-protect-disable-time': KeyInfo(default='5m'),
+ 'loop-protect-send-interval': KeyInfo(default='5s'),
+ 'mac-address': KeyInfo(),
+ 'mdix-enable': KeyInfo(),
+ 'mtu': KeyInfo(default=1500),
+ 'name': KeyInfo(),
+ 'orig-mac-address': KeyInfo(),
+ 'poe-out': KeyInfo(can_disable=True),
+ 'poe-priority': KeyInfo(can_disable=True),
+ 'poe-voltage': KeyInfo(can_disable=True),
+ 'power-cycle-interval': KeyInfo(),
+ 'power-cycle-ping-address': KeyInfo(can_disable=True),
+ 'power-cycle-ping-enabled': KeyInfo(),
+ 'power-cycle-ping-timeout': KeyInfo(can_disable=True),
+ 'rx-flow-control': KeyInfo(default='off'),
+ 'sfp-rate-select': KeyInfo(default='high'),
+ 'sfp-shutdown-temperature': KeyInfo(default='95C'),
+ 'speed': KeyInfo(),
+ 'tx-flow-control': KeyInfo(default='off'),
+ },
+ ),
),
('interface', 'ethernet', 'poe'): APIData(
- fixed_entries=True,
- fully_understood=True,
- primary_keys=('name', ),
- fields={
- 'name': KeyInfo(),
- 'poe-out': KeyInfo(default='auto-on'),
- 'poe-priority': KeyInfo(default=10),
- 'poe-voltage': KeyInfo(default='auto'),
- 'power-cycle-interval': KeyInfo(default='none'),
- 'power-cycle-ping-address': KeyInfo(can_disable=True),
- 'power-cycle-ping-enabled': KeyInfo(default=False),
- 'power-cycle-ping-timeout': KeyInfo(can_disable=True),
- }
+ unversioned=VersionedAPIData(
+ fixed_entries=True,
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ 'name': KeyInfo(),
+ 'poe-out': KeyInfo(default='auto-on'),
+ 'poe-priority': KeyInfo(default=10),
+ 'poe-voltage': KeyInfo(default='auto'),
+ 'power-cycle-interval': KeyInfo(default='none'),
+ 'power-cycle-ping-address': KeyInfo(can_disable=True),
+ 'power-cycle-ping-enabled': KeyInfo(default=False),
+ 'power-cycle-ping-timeout': KeyInfo(can_disable=True),
+ }
+ ),
),
('interface', 'gre'): APIData(
- fully_understood=True,
- primary_keys=('name', ),
- fields={
- 'allow-fast-path': KeyInfo(default=True),
- 'clamp-tcp-mss': KeyInfo(default=True),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'disabled': KeyInfo(default=False),
- 'dont-fragment': KeyInfo(default=False),
- 'dscp': KeyInfo(default='inherit'),
- 'ipsec-secret': KeyInfo(can_disable=True),
- 'keepalive': KeyInfo(default='10s,10', can_disable=True),
- 'local-address': KeyInfo(default='0.0.0.0'),
- 'mtu': KeyInfo(default='auto'),
- 'name': KeyInfo(),
- 'remote-address': KeyInfo(required=True),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ 'allow-fast-path': KeyInfo(default=True),
+ 'clamp-tcp-mss': KeyInfo(default=True),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'dont-fragment': KeyInfo(default=False),
+ 'dscp': KeyInfo(default='inherit'),
+ 'ipsec-secret': KeyInfo(can_disable=True),
+ 'keepalive': KeyInfo(default='10s,10', can_disable=True),
+ 'local-address': KeyInfo(default='0.0.0.0'),
+ 'mtu': KeyInfo(default='auto'),
+ 'name': KeyInfo(),
+ 'remote-address': KeyInfo(required=True),
+ },
+ ),
),
('interface', 'gre6'): APIData(
- fully_understood=True,
- primary_keys=('name',),
- fields={
- 'clamp-tcp-mss': KeyInfo(default=True),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'disabled': KeyInfo(default=False),
- 'dscp': KeyInfo(default='inherit'),
- 'ipsec-secret': KeyInfo(can_disable=True),
- 'keepalive': KeyInfo(default='10s,10', can_disable=True),
- 'local-address': KeyInfo(default='::'),
- 'mtu': KeyInfo(default='auto'),
- 'name': KeyInfo(),
- 'remote-address': KeyInfo(required=True),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name',),
+ fields={
+ 'clamp-tcp-mss': KeyInfo(default=True),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'dscp': KeyInfo(default='inherit'),
+ 'ipsec-secret': KeyInfo(can_disable=True),
+ 'keepalive': KeyInfo(default='10s,10', can_disable=True),
+ 'local-address': KeyInfo(default='::'),
+ 'mtu': KeyInfo(default='auto'),
+ 'name': KeyInfo(),
+ 'remote-address': KeyInfo(required=True),
+ },
+ ),
),
('interface', 'list'): APIData(
- primary_keys=('name', ),
- fully_understood=True,
- fields={
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'exclude': KeyInfo(),
- 'include': KeyInfo(),
- 'name': KeyInfo(),
- },
+ unversioned=VersionedAPIData(
+ primary_keys=('name', ),
+ fully_understood=True,
+ fields={
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'exclude': KeyInfo(),
+ 'include': KeyInfo(),
+ 'name': KeyInfo(),
+ },
+ ),
),
('interface', 'list', 'member'): APIData(
- primary_keys=('list', 'interface', ),
- fully_understood=True,
- fields={
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'interface': KeyInfo(),
- 'list': KeyInfo(),
- 'disabled': KeyInfo(default=False),
- },
+ unversioned=VersionedAPIData(
+ primary_keys=('list', 'interface', ),
+ fully_understood=True,
+ fields={
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'interface': KeyInfo(),
+ 'list': KeyInfo(),
+ 'disabled': KeyInfo(default=False),
+ },
+ ),
),
('interface', 'lte', 'apn'): APIData(
- unknown_mechanism=True,
- # primary_keys=('default', ),
- fields={
- 'default': KeyInfo(),
- 'add-default-route': KeyInfo(),
- 'apn': KeyInfo(),
- 'default-route-distance': KeyInfo(),
- 'name': KeyInfo(),
- 'use-peer-dns': KeyInfo(),
- },
+ unversioned=VersionedAPIData(
+ unknown_mechanism=True,
+ # primary_keys=('default', ),
+ fields={
+ 'default': KeyInfo(),
+ 'add-default-route': KeyInfo(),
+ 'apn': KeyInfo(),
+ 'default-route-distance': KeyInfo(),
+ 'name': KeyInfo(),
+ 'use-peer-dns': KeyInfo(),
+ },
+ ),
+ ),
+ ('interface', 'ppp-client'): APIData(
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ 'add-default-route': KeyInfo(default=True),
+ 'allow': KeyInfo(default='pap,chap,mschap1,mschap2'),
+ 'apn': KeyInfo(default='internet'),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'data-channel': KeyInfo(default=0),
+ 'default-route-distance': KeyInfo(default=1),
+ 'dial-command': KeyInfo(default="ATDT"),
+ 'dial-on-demand': KeyInfo(default=True),
+ 'disabled': KeyInfo(default=True),
+ 'info-channel': KeyInfo(default=0),
+ 'keepalive-timeout': KeyInfo(default=30),
+ 'max-mru': KeyInfo(default=1500),
+ 'max-mtu': KeyInfo(default=1500),
+ 'modem-init': KeyInfo(default=''),
+ 'mrru': KeyInfo(default='disabled'),
+ 'name': KeyInfo(),
+ 'null-modem': KeyInfo(default=False),
+ 'password': KeyInfo(default=''),
+ 'phone': KeyInfo(default=''),
+ 'pin': KeyInfo(default=''),
+ 'port': KeyInfo(),
+ 'profile': KeyInfo(default='default'),
+ 'use-peer-dns': KeyInfo(default=True),
+ 'user': KeyInfo(default=''),
+ },
+ ),
),
('interface', 'pppoe-client'): APIData(
- fully_understood=True,
- primary_keys=('name', ),
- fields={
- 'ac-name': KeyInfo(default=''),
- 'add-default-route': KeyInfo(default=False),
- 'allow': KeyInfo(default='pap,chap,mschap1,mschap2'),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'default-route-distance': KeyInfo(default=1),
- 'dial-on-demand': KeyInfo(default=False),
- 'disabled': KeyInfo(default=True),
- 'host-uniq': KeyInfo(can_disable=True),
- 'interface': KeyInfo(required=True),
- 'keepalive-timeout': KeyInfo(default=10),
- 'max-mru': KeyInfo(default='auto'),
- 'max-mtu': KeyInfo(default='auto'),
- 'mrru': KeyInfo(default='disabled'),
- 'name': KeyInfo(),
- 'password': KeyInfo(default=''),
- 'profile': KeyInfo(default='default'),
- 'service-name': KeyInfo(default=''),
- 'use-peer-dns': KeyInfo(default=False),
- 'user': KeyInfo(default=''),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ 'ac-name': KeyInfo(default=''),
+ 'add-default-route': KeyInfo(default=False),
+ 'allow': KeyInfo(default='pap,chap,mschap1,mschap2'),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'default-route-distance': KeyInfo(default=1),
+ 'dial-on-demand': KeyInfo(default=False),
+ 'disabled': KeyInfo(default=True),
+ 'host-uniq': KeyInfo(can_disable=True),
+ 'interface': KeyInfo(required=True),
+ 'keepalive-timeout': KeyInfo(default=10),
+ 'max-mru': KeyInfo(default='auto'),
+ 'max-mtu': KeyInfo(default='auto'),
+ 'mrru': KeyInfo(default='disabled'),
+ 'name': KeyInfo(),
+ 'password': KeyInfo(default=''),
+ 'profile': KeyInfo(default='default'),
+ 'service-name': KeyInfo(default=''),
+ 'use-peer-dns': KeyInfo(default=False),
+ 'user': KeyInfo(default=''),
+ },
+ ),
),
('interface', 'vlan'): APIData(
- fully_understood=True,
- primary_keys=('name', ),
- fields={
- 'arp': KeyInfo(default='enabled'),
- 'arp-timeout': KeyInfo(default='auto'),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'disabled': KeyInfo(default=False),
- 'interface': KeyInfo(required=True),
- 'loop-protect': KeyInfo(default='default'),
- 'loop-protect-disable-time': KeyInfo(default='5m'),
- 'loop-protect-send-interval': KeyInfo(default='5s'),
- 'mtu': KeyInfo(default=1500),
- 'name': KeyInfo(),
- 'use-service-tag': KeyInfo(default=False),
- 'vlan-id': KeyInfo(required=True),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ 'arp': KeyInfo(default='enabled'),
+ 'arp-timeout': KeyInfo(default='auto'),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'interface': KeyInfo(required=True),
+ 'loop-protect': KeyInfo(default='default'),
+ 'loop-protect-disable-time': KeyInfo(default='5m'),
+ 'loop-protect-send-interval': KeyInfo(default='5s'),
+ 'mtu': KeyInfo(default=1500),
+ 'name': KeyInfo(),
+ 'use-service-tag': KeyInfo(default=False),
+ 'vlan-id': KeyInfo(required=True),
+ },
+ ),
),
('interface', 'vrrp'): APIData(
- fully_understood=True,
- primary_keys=('name', ),
- fields={
- 'arp': KeyInfo(default='enabled'),
- 'arp-timeout': KeyInfo(default='auto'),
- 'authentication': KeyInfo(default='none'),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'disabled': KeyInfo(default=False),
- 'group-master': KeyInfo(default=''),
- 'interface': KeyInfo(required=True),
- 'interval': KeyInfo(default='1s'),
- 'mtu': KeyInfo(default=1500),
- 'name': KeyInfo(),
- 'on-backup': KeyInfo(default=''),
- 'on-fail': KeyInfo(default=''),
- 'on-master': KeyInfo(default=''),
- 'password': KeyInfo(default=''),
- 'preemption-mode': KeyInfo(default=True),
- 'priority': KeyInfo(default=100),
- 'remote-address': KeyInfo(),
- 'sync-connection-tracking': KeyInfo(default=False),
- 'v3-protocol': KeyInfo(default='ipv4'),
- 'version': KeyInfo(default=3),
- 'vrid': KeyInfo(default=1),
- },
- ),
- ('interface', 'wireless', 'security-profiles'): APIData(
- unknown_mechanism=True,
- # primary_keys=('default', ),
- fields={
- 'default': KeyInfo(),
- 'authentication-types': KeyInfo(),
- 'disable-pmkid': KeyInfo(),
- 'eap-methods': KeyInfo(),
- 'group-ciphers': KeyInfo(),
- 'group-key-update': KeyInfo(),
- 'interim-update': KeyInfo(),
- 'management-protection': KeyInfo(),
- 'management-protection-key': KeyInfo(),
- 'mode': KeyInfo(),
- 'mschapv2-password': KeyInfo(),
- 'mschapv2-username': KeyInfo(),
- 'name': KeyInfo(),
- 'radius-called-format': KeyInfo(),
- 'radius-eap-accounting': KeyInfo(),
- 'radius-mac-accounting': KeyInfo(),
- 'radius-mac-authentication': KeyInfo(),
- 'radius-mac-caching': KeyInfo(),
- 'radius-mac-format': KeyInfo(),
- 'radius-mac-mode': KeyInfo(),
- 'static-algo-0': KeyInfo(),
- 'static-algo-1': KeyInfo(),
- 'static-algo-2': KeyInfo(),
- 'static-algo-3': KeyInfo(),
- 'static-key-0': KeyInfo(),
- 'static-key-1': KeyInfo(),
- 'static-key-2': KeyInfo(),
- 'static-key-3': KeyInfo(),
- 'static-sta-private-algo': KeyInfo(),
- 'static-sta-private-key': KeyInfo(),
- 'static-transmit-key': KeyInfo(),
- 'supplicant-identity': KeyInfo(),
- 'tls-certificate': KeyInfo(),
- 'tls-mode': KeyInfo(),
- 'unicast-ciphers': KeyInfo(),
- 'wpa-pre-shared-key': KeyInfo(),
- 'wpa2-pre-shared-key': KeyInfo(),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ 'arp': KeyInfo(default='enabled'),
+ 'arp-timeout': KeyInfo(default='auto'),
+ 'authentication': KeyInfo(default='none'),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'group-master': KeyInfo(default=''),
+ 'interface': KeyInfo(required=True),
+ 'interval': KeyInfo(default='1s'),
+ 'mtu': KeyInfo(default=1500),
+ 'name': KeyInfo(),
+ 'on-backup': KeyInfo(default=''),
+ 'on-fail': KeyInfo(default=''),
+ 'on-master': KeyInfo(default=''),
+ 'password': KeyInfo(default=''),
+ 'preemption-mode': KeyInfo(default=True),
+ 'priority': KeyInfo(default=100),
+ 'remote-address': KeyInfo(),
+ 'sync-connection-tracking': KeyInfo(default=False),
+ 'v3-protocol': KeyInfo(default='ipv4'),
+ 'version': KeyInfo(default=3),
+ 'vrid': KeyInfo(default=1),
+ },
+ ),
),
('ip', 'hotspot', 'profile'): APIData(
- unknown_mechanism=True,
- # primary_keys=('default', ),
- fields={
- 'default': KeyInfo(),
- 'dns-name': KeyInfo(),
- 'hotspot-address': KeyInfo(),
- 'html-directory': KeyInfo(),
- 'html-directory-override': KeyInfo(),
- 'http-cookie-lifetime': KeyInfo(),
- 'http-proxy': KeyInfo(),
- 'login-by': KeyInfo(),
- 'name': KeyInfo(),
- 'rate-limit': KeyInfo(),
- 'smtp-server': KeyInfo(),
- 'split-user-domain': KeyInfo(),
- 'use-radius': KeyInfo(),
- },
+ unversioned=VersionedAPIData(
+ unknown_mechanism=True,
+ # primary_keys=('default', ),
+ fields={
+ 'default': KeyInfo(),
+ 'dns-name': KeyInfo(),
+ 'hotspot-address': KeyInfo(),
+ 'html-directory': KeyInfo(),
+ 'html-directory-override': KeyInfo(),
+ 'http-cookie-lifetime': KeyInfo(),
+ 'http-proxy': KeyInfo(),
+ 'login-by': KeyInfo(),
+ 'name': KeyInfo(),
+ 'rate-limit': KeyInfo(),
+ 'smtp-server': KeyInfo(),
+ 'split-user-domain': KeyInfo(),
+ 'use-radius': KeyInfo(),
+ },
+ ),
),
('ip', 'hotspot', 'user', 'profile'): APIData(
- unknown_mechanism=True,
- # primary_keys=('default', ),
- fields={
- 'default': KeyInfo(),
- 'add-mac-cookie': KeyInfo(),
- 'address-list': KeyInfo(),
- 'idle-timeout': KeyInfo(),
- 'insert-queue-before': KeyInfo(can_disable=True),
- 'keepalive-timeout': KeyInfo(),
- 'mac-cookie-timeout': KeyInfo(),
- 'name': KeyInfo(),
- 'parent-queue': KeyInfo(can_disable=True),
- 'queue-type': KeyInfo(can_disable=True),
- 'shared-users': KeyInfo(),
- 'status-autorefresh': KeyInfo(),
- 'transparent-proxy': KeyInfo(),
- },
+ unversioned=VersionedAPIData(
+ unknown_mechanism=True,
+ # primary_keys=('default', ),
+ fields={
+ 'default': KeyInfo(),
+ 'add-mac-cookie': KeyInfo(),
+ 'address-list': KeyInfo(),
+ 'idle-timeout': KeyInfo(),
+ 'insert-queue-before': KeyInfo(can_disable=True),
+ 'keepalive-timeout': KeyInfo(),
+ 'mac-cookie-timeout': KeyInfo(),
+ 'name': KeyInfo(),
+ 'parent-queue': KeyInfo(can_disable=True),
+ 'queue-type': KeyInfo(can_disable=True),
+ 'shared-users': KeyInfo(),
+ 'status-autorefresh': KeyInfo(),
+ 'transparent-proxy': KeyInfo(),
+ },
+ ),
),
('ip', 'ipsec', 'identity'): APIData(
- fully_understood=True,
- primary_keys=('peer', ),
- fields={
- 'auth-method': KeyInfo(default='pre-shared-key'),
- 'certificate': KeyInfo(),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'disabled': KeyInfo(default=False),
- 'eap-methods': KeyInfo(default='eap-tls'),
- 'generate-policy': KeyInfo(default=False),
- 'key': KeyInfo(),
- 'match-by': KeyInfo(can_disable=True, remove_value='remote-id'),
- 'mode-config': KeyInfo(can_disable=True, remove_value='none'),
- 'my-id': KeyInfo(can_disable=True, remove_value='auto'),
- 'notrack-chain': KeyInfo(can_disable=True, remove_value=''),
- 'password': KeyInfo(),
- 'peer': KeyInfo(),
- 'policy-template-group': KeyInfo(can_disable=True, remove_value='default'),
- 'remote-certificate': KeyInfo(),
- 'remote-id': KeyInfo(can_disable=True, remove_value='auto'),
- 'remote-key': KeyInfo(),
- 'secret': KeyInfo(default=''),
- 'username': KeyInfo(),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('peer', ),
+ fields={
+ 'auth-method': KeyInfo(default='pre-shared-key'),
+ 'certificate': KeyInfo(),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'eap-methods': KeyInfo(default='eap-tls'),
+ 'generate-policy': KeyInfo(default=False),
+ 'key': KeyInfo(),
+ 'match-by': KeyInfo(can_disable=True, remove_value='remote-id'),
+ 'mode-config': KeyInfo(can_disable=True, remove_value='none'),
+ 'my-id': KeyInfo(can_disable=True, remove_value='auto'),
+ 'notrack-chain': KeyInfo(can_disable=True, remove_value=''),
+ 'password': KeyInfo(),
+ 'peer': KeyInfo(),
+ 'policy-template-group': KeyInfo(can_disable=True, remove_value='default'),
+ 'remote-certificate': KeyInfo(),
+ 'remote-id': KeyInfo(can_disable=True, remove_value='auto'),
+ 'remote-key': KeyInfo(),
+ 'secret': KeyInfo(default=''),
+ 'username': KeyInfo(),
+ },
+ ),
),
('ip', 'ipsec', 'mode-config'): APIData(
- unknown_mechanism=True,
- # primary_keys=('default', ),
- fields={
- 'default': KeyInfo(),
- 'name': KeyInfo(),
- 'responder': KeyInfo(),
- 'use-responder-dns': KeyInfo(),
- },
+ unversioned=VersionedAPIData(
+ unknown_mechanism=True,
+ # primary_keys=('default', ),
+ fields={
+ 'default': KeyInfo(),
+ 'name': KeyInfo(),
+ 'responder': KeyInfo(),
+ 'use-responder-dns': KeyInfo(),
+ },
+ ),
),
('ip', 'ipsec', 'peer'): APIData(
- fully_understood=True,
- primary_keys=('name', ),
- fields={
- 'address': KeyInfo(can_disable=True, remove_value=''),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'disabled': KeyInfo(default=False),
- 'exchange-mode': KeyInfo(default='main'),
- 'local-address': KeyInfo(can_disable=True, remove_value='0.0.0.0'),
- 'name': KeyInfo(),
- 'passive': KeyInfo(can_disable=True, remove_value=False),
- 'port': KeyInfo(can_disable=True, remove_value=500),
- 'profile': KeyInfo(default='default'),
- 'send-initial-contact': KeyInfo(default=True),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ 'address': KeyInfo(can_disable=True, remove_value=''),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'exchange-mode': KeyInfo(default='main'),
+ 'local-address': KeyInfo(can_disable=True, remove_value='0.0.0.0'),
+ 'name': KeyInfo(),
+ 'passive': KeyInfo(can_disable=True, remove_value=False),
+ 'port': KeyInfo(can_disable=True, remove_value=500),
+ 'profile': KeyInfo(default='default'),
+ 'send-initial-contact': KeyInfo(default=True),
+ },
+ ),
),
('ip', 'ipsec', 'policy', 'group'): APIData(
- unknown_mechanism=True,
- # primary_keys=('default', ),
- fields={
- 'default': KeyInfo(),
- 'name': KeyInfo(),
- },
+ unversioned=VersionedAPIData(
+ unknown_mechanism=True,
+ # primary_keys=('default', ),
+ fields={
+ 'default': KeyInfo(),
+ 'name': KeyInfo(),
+ },
+ ),
),
('ip', 'ipsec', 'profile'): APIData(
- fully_understood=True,
- primary_keys=('name', ),
- fields={
- 'dh-group': KeyInfo(default='modp2048,modp1024'),
- 'dpd-interval': KeyInfo(default='2m'),
- 'dpd-maximum-failures': KeyInfo(default=5),
- 'enc-algorithm': KeyInfo(default='aes-128,3des'),
- 'hash-algorithm': KeyInfo(default='sha1'),
- 'lifebytes': KeyInfo(can_disable=True, remove_value=0),
- 'lifetime': KeyInfo(default='1d'),
- 'name': KeyInfo(),
- 'nat-traversal': KeyInfo(default=True),
- 'prf-algorithm': KeyInfo(can_disable=True, remove_value='auto'),
- 'proposal-check': KeyInfo(default='obey'),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ 'dh-group': KeyInfo(default='modp2048,modp1024'),
+ 'dpd-interval': KeyInfo(default='2m'),
+ 'dpd-maximum-failures': KeyInfo(default=5),
+ 'enc-algorithm': KeyInfo(default='aes-128,3des'),
+ 'hash-algorithm': KeyInfo(default='sha1'),
+ 'lifebytes': KeyInfo(can_disable=True, remove_value=0),
+ 'lifetime': KeyInfo(default='1d'),
+ 'name': KeyInfo(),
+ 'nat-traversal': KeyInfo(default=True),
+ 'prf-algorithm': KeyInfo(can_disable=True, remove_value='auto'),
+ 'proposal-check': KeyInfo(default='obey'),
+ },
+ ),
),
('ip', 'ipsec', 'proposal'): APIData(
- fully_understood=True,
- primary_keys=('name', ),
- fields={
- 'auth-algorithms': KeyInfo(default='sha1'),
- 'disabled': KeyInfo(default=False),
- 'enc-algorithms': KeyInfo(default='aes-256-cbc,aes-192-cbc,aes-128-cbc'),
- 'lifetime': KeyInfo(default='30m'),
- 'name': KeyInfo(),
- 'pfs-group': KeyInfo(default='modp1024'),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ 'auth-algorithms': KeyInfo(default='sha1'),
+ 'disabled': KeyInfo(default=False),
+ 'enc-algorithms': KeyInfo(default='aes-256-cbc,aes-192-cbc,aes-128-cbc'),
+ 'lifetime': KeyInfo(default='30m'),
+ 'name': KeyInfo(),
+ 'pfs-group': KeyInfo(default='modp1024'),
+ },
+ ),
),
('ip', 'pool'): APIData(
- fully_understood=True,
- primary_keys=('name', ),
- fields={
- 'name': KeyInfo(),
- 'ranges': KeyInfo(),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ 'name': KeyInfo(),
+ 'ranges': KeyInfo(),
+ },
+ ),
),
('ip', 'route'): APIData(
- fully_understood=True,
- fields={
- 'blackhole': KeyInfo(can_disable=True),
- 'check-gateway': KeyInfo(can_disable=True),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'disabled': KeyInfo(default=False),
- 'distance': KeyInfo(),
- 'dst-address': KeyInfo(),
- 'gateway': KeyInfo(),
- 'pref-src': KeyInfo(),
- 'routing-table': KeyInfo(default='main'),
- 'route-tag': KeyInfo(can_disable=True),
- 'routing-mark': KeyInfo(can_disable=True),
- 'scope': KeyInfo(),
- 'suppress-hw-offload': KeyInfo(default=False),
- 'target-scope': KeyInfo(),
- 'type': KeyInfo(can_disable=True, remove_value='unicast'),
- 'vrf-interface': KeyInfo(can_disable=True),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ fields={
+ 'blackhole': KeyInfo(can_disable=True),
+ 'check-gateway': KeyInfo(can_disable=True),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'distance': KeyInfo(),
+ 'dst-address': KeyInfo(),
+ 'gateway': KeyInfo(),
+ 'pref-src': KeyInfo(),
+ 'routing-table': KeyInfo(default='main'),
+ 'route-tag': KeyInfo(can_disable=True),
+ 'routing-mark': KeyInfo(can_disable=True),
+ 'scope': KeyInfo(),
+ 'suppress-hw-offload': KeyInfo(default=False),
+ 'target-scope': KeyInfo(),
+ 'type': KeyInfo(can_disable=True, remove_value='unicast'),
+ 'vrf-interface': KeyInfo(can_disable=True),
+ },
+ ),
+ ),
+ ('ip', 'vrf'): APIData(
+ versioned=[
+ ('7', '>=', VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'interfaces': KeyInfo(),
+ 'name': KeyInfo(),
+ },
+ )),
+ ]
),
('ip', 'route', 'vrf'): APIData(
- fully_understood=True,
- primary_keys=('routing-mark', ),
- fields={
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'disabled': KeyInfo(default=False),
- 'interfaces': KeyInfo(),
- 'routing-mark': KeyInfo(),
- },
+ versioned=[
+ ('7', '<', VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('routing-mark', ),
+ fields={
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'interfaces': KeyInfo(),
+ 'routing-mark': KeyInfo(),
+ },
+ )),
+ ],
),
('ip', 'dhcp-server'): APIData(
- fully_understood=True,
- primary_keys=('name', ),
- fields={
- 'address-pool': KeyInfo(default='static-only'),
- 'allow-dual-stack-queue': KeyInfo(can_disable=True, remove_value=True),
- 'always-broadcast': KeyInfo(can_disable=True, remove_value=False),
- 'authoritative': KeyInfo(default=True),
- 'bootp-lease-time': KeyInfo(default='forever'),
- 'bootp-support': KeyInfo(can_disable=True, remove_value='static'),
- 'client-mac-limit': KeyInfo(can_disable=True, remove_value='unlimited'),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'conflict-detection': KeyInfo(can_disable=True, remove_value=True),
- 'delay-threshold': KeyInfo(can_disable=True, remove_value='none'),
- 'dhcp-option-set': KeyInfo(can_disable=True, remove_value='none'),
- 'disabled': KeyInfo(default=False),
- 'insert-queue-before': KeyInfo(can_disable=True, remove_value='first'),
- 'interface': KeyInfo(required=True),
- 'lease-script': KeyInfo(default=''),
- 'lease-time': KeyInfo(default='10m'),
- 'name': KeyInfo(),
- 'parent-queue': KeyInfo(can_disable=True, remove_value='none'),
- 'relay': KeyInfo(can_disable=True, remove_value='0.0.0.0'),
- 'server-address': KeyInfo(can_disable=True, remove_value='0.0.0.0'),
- 'use-framed-as-classless': KeyInfo(can_disable=True, remove_value=True),
- 'use-radius': KeyInfo(default=False),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ 'address-pool': KeyInfo(default='static-only'),
+ 'allow-dual-stack-queue': KeyInfo(can_disable=True, remove_value=True),
+ 'always-broadcast': KeyInfo(can_disable=True, remove_value=False),
+ 'authoritative': KeyInfo(default=True),
+ 'bootp-lease-time': KeyInfo(default='forever'),
+ 'bootp-support': KeyInfo(can_disable=True, remove_value='static'),
+ 'client-mac-limit': KeyInfo(can_disable=True, remove_value='unlimited'),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'conflict-detection': KeyInfo(can_disable=True, remove_value=True),
+ 'delay-threshold': KeyInfo(can_disable=True, remove_value='none'),
+ 'dhcp-option-set': KeyInfo(can_disable=True, remove_value='none'),
+ 'disabled': KeyInfo(default=False),
+ 'insert-queue-before': KeyInfo(can_disable=True, remove_value='first'),
+ 'interface': KeyInfo(required=True),
+ 'lease-script': KeyInfo(default=''),
+ 'lease-time': KeyInfo(default='10m'),
+ 'name': KeyInfo(),
+ 'parent-queue': KeyInfo(can_disable=True, remove_value='none'),
+ 'relay': KeyInfo(can_disable=True, remove_value='0.0.0.0'),
+ 'server-address': KeyInfo(can_disable=True, remove_value='0.0.0.0'),
+ 'use-framed-as-classless': KeyInfo(can_disable=True, remove_value=True),
+ 'use-radius': KeyInfo(default=False),
+ },
+ ),
+ ),
+ ('routing', 'filter', 'rule'): APIData(
+ versioned=[
+ ('7', '>=', VersionedAPIData(
+ fully_understood=True,
+ fields={
+ 'chain': KeyInfo(required=True),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(can_disable=True),
+ 'rule': KeyInfo(can_disable=True),
+ },
+ )),
+ ],
+ ),
+ ('routing', 'filter', 'select-rule'): APIData(
+ versioned=[
+ ('7', '>=', VersionedAPIData(
+ fully_understood=True,
+ fields={
+ 'chain': KeyInfo(required=True),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(can_disable=True),
+ 'do-group-num': KeyInfo(can_disable=True),
+ 'do-group-prfx': KeyInfo(can_disable=True),
+ 'do-jump': KeyInfo(can_disable=True),
+ 'do-select-num': KeyInfo(can_disable=True),
+ 'do-select-prfx': KeyInfo(can_disable=True),
+ 'do-take': KeyInfo(can_disable=True),
+ 'do-where': KeyInfo(can_disable=True),
+ },
+ )),
+ ],
),
('routing', 'ospf', 'instance'): APIData(
- fully_understood=True,
- primary_keys=('name', ),
- fields={
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'disabled': KeyInfo(default=False),
- 'domain-id': KeyInfo(can_disable=True),
- 'domain-tag': KeyInfo(can_disable=True),
- 'in-filter-chain': KeyInfo(can_disable=True),
- 'mpls-te-address': KeyInfo(can_disable=True),
- 'mpls-te-area': KeyInfo(can_disable=True),
- 'name': KeyInfo(),
- 'originate-default': KeyInfo(can_disable=True),
- 'out-filter-chain': KeyInfo(can_disable=True),
- 'out-filter-select': KeyInfo(can_disable=True),
- 'redistribute': KeyInfo(can_disable=True),
- 'router-id': KeyInfo(default='main'),
- 'routing-table': KeyInfo(can_disable=True),
- 'use-dn': KeyInfo(can_disable=True),
- 'version': KeyInfo(default=2),
- 'vrf': KeyInfo(default='main'),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'domain-id': KeyInfo(can_disable=True),
+ 'domain-tag': KeyInfo(can_disable=True),
+ 'in-filter-chain': KeyInfo(can_disable=True),
+ 'mpls-te-address': KeyInfo(can_disable=True),
+ 'mpls-te-area': KeyInfo(can_disable=True),
+ 'name': KeyInfo(),
+ 'originate-default': KeyInfo(can_disable=True),
+ 'out-filter-chain': KeyInfo(can_disable=True),
+ 'out-filter-select': KeyInfo(can_disable=True),
+ 'redistribute': KeyInfo(can_disable=True),
+ 'router-id': KeyInfo(default='main'),
+ 'routing-table': KeyInfo(can_disable=True),
+ 'use-dn': KeyInfo(can_disable=True),
+ 'version': KeyInfo(default=2),
+ 'vrf': KeyInfo(default='main'),
+ },
+ ),
),
('routing', 'ospf', 'area'): APIData(
- fully_understood=True,
- primary_keys=('name', ),
- fields={
- 'area-id': KeyInfo(default='0.0.0.0'),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'default-cost': KeyInfo(can_disable=True),
- 'disabled': KeyInfo(default=False),
- 'instance': KeyInfo(required=True),
- 'name': KeyInfo(),
- 'no-summaries': KeyInfo(can_disable=True),
- 'nssa-translator': KeyInfo(can_disable=True),
- 'type': KeyInfo(default='default'),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ 'area-id': KeyInfo(default='0.0.0.0'),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'default-cost': KeyInfo(can_disable=True),
+ 'disabled': KeyInfo(default=False),
+ 'instance': KeyInfo(required=True),
+ 'name': KeyInfo(),
+ 'no-summaries': KeyInfo(can_disable=True),
+ 'nssa-translator': KeyInfo(can_disable=True),
+ 'type': KeyInfo(default='default'),
+ },
+ ),
),
('routing', 'ospf', 'area', 'range'): APIData(
- fully_understood=True,
- primary_keys=('area', 'prefix', ),
- fields={
- 'advertise': KeyInfo(default=True),
- 'area': KeyInfo(),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'cost': KeyInfo(can_disable=True),
- 'disabled': KeyInfo(default=False),
- 'prefix': KeyInfo(),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('area', 'prefix', ),
+ fields={
+ 'advertise': KeyInfo(default=True),
+ 'area': KeyInfo(),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'cost': KeyInfo(can_disable=True),
+ 'disabled': KeyInfo(default=False),
+ 'prefix': KeyInfo(),
+ },
+ ),
),
('routing', 'ospf', 'interface-template'): APIData(
- fully_understood=True,
- fields={
- 'area': KeyInfo(required=True),
- 'auth': KeyInfo(can_disable=True),
- 'auth-id': KeyInfo(can_disable=True),
- 'auth-key': KeyInfo(can_disable=True),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'cost': KeyInfo(default=1),
- 'dead-interval': KeyInfo(default='40s'),
- 'disabled': KeyInfo(default=False),
- 'hello-interval': KeyInfo(default='10s'),
- 'instance-id': KeyInfo(default=0),
- 'interfaces': KeyInfo(can_disable=True),
- 'networks': KeyInfo(can_disable=True),
- 'passive': KeyInfo(can_disable=True),
- 'prefix-list': KeyInfo(can_disable=True),
- 'priority': KeyInfo(default=128),
- 'retransmit-interval': KeyInfo(default='5s'),
- 'transmit-delay': KeyInfo(default='1s'),
- 'type': KeyInfo(default='broadcast'),
- 'vlink-neighbor-id': KeyInfo(can_disable=True),
- 'vlink-transit-area': KeyInfo(can_disable=True),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ fields={
+ 'area': KeyInfo(required=True),
+ 'auth': KeyInfo(can_disable=True),
+ 'auth-id': KeyInfo(can_disable=True),
+ 'auth-key': KeyInfo(can_disable=True),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'cost': KeyInfo(default=1),
+ 'dead-interval': KeyInfo(default='40s'),
+ 'disabled': KeyInfo(default=False),
+ 'hello-interval': KeyInfo(default='10s'),
+ 'instance-id': KeyInfo(default=0),
+ 'interfaces': KeyInfo(can_disable=True),
+ 'networks': KeyInfo(can_disable=True),
+ 'passive': KeyInfo(can_disable=True),
+ 'prefix-list': KeyInfo(can_disable=True),
+ 'priority': KeyInfo(default=128),
+ 'retransmit-interval': KeyInfo(default='5s'),
+ 'transmit-delay': KeyInfo(default='1s'),
+ 'type': KeyInfo(default='broadcast'),
+ 'vlink-neighbor-id': KeyInfo(can_disable=True),
+ 'vlink-transit-area': KeyInfo(can_disable=True),
+ },
+ ),
),
('routing', 'ospf-v3', 'instance'): APIData(
- unknown_mechanism=True,
- # primary_keys=('default', ),
- fields={
- 'default': KeyInfo(),
- 'disabled': KeyInfo(),
- 'distribute-default': KeyInfo(),
- 'metric-bgp': KeyInfo(),
- 'metric-connected': KeyInfo(),
- 'metric-default': KeyInfo(),
- 'metric-other-ospf': KeyInfo(),
- 'metric-rip': KeyInfo(),
- 'metric-static': KeyInfo(),
- 'name': KeyInfo(),
- 'redistribute-bgp': KeyInfo(),
- 'redistribute-connected': KeyInfo(),
- 'redistribute-other-ospf': KeyInfo(),
- 'redistribute-rip': KeyInfo(),
- 'redistribute-static': KeyInfo(),
- 'router-id': KeyInfo(),
- },
+ unversioned=VersionedAPIData(
+ unknown_mechanism=True,
+ # primary_keys=('default', ),
+ fields={
+ 'default': KeyInfo(),
+ 'disabled': KeyInfo(),
+ 'distribute-default': KeyInfo(),
+ 'metric-bgp': KeyInfo(),
+ 'metric-connected': KeyInfo(),
+ 'metric-default': KeyInfo(),
+ 'metric-other-ospf': KeyInfo(),
+ 'metric-rip': KeyInfo(),
+ 'metric-static': KeyInfo(),
+ 'name': KeyInfo(),
+ 'redistribute-bgp': KeyInfo(),
+ 'redistribute-connected': KeyInfo(),
+ 'redistribute-other-ospf': KeyInfo(),
+ 'redistribute-rip': KeyInfo(),
+ 'redistribute-static': KeyInfo(),
+ 'router-id': KeyInfo(),
+ },
+ ),
),
('routing', 'ospf-v3', 'area'): APIData(
- unknown_mechanism=True,
- # primary_keys=('default', ),
- fields={
- 'default': KeyInfo(),
- 'area-id': KeyInfo(),
- 'disabled': KeyInfo(),
- 'instance': KeyInfo(),
- 'name': KeyInfo(),
- 'type': KeyInfo(),
- },
+ unversioned=VersionedAPIData(
+ unknown_mechanism=True,
+ # primary_keys=('default', ),
+ fields={
+ 'default': KeyInfo(),
+ 'area-id': KeyInfo(),
+ 'disabled': KeyInfo(),
+ 'instance': KeyInfo(),
+ 'name': KeyInfo(),
+ 'type': KeyInfo(),
+ },
+ ),
),
('routing', 'pimsm', 'instance'): APIData(
- fully_understood=True,
- primary_keys=('name', ),
- fields={
- 'afi': KeyInfo(default='ipv4'),
- 'bsm-forward-back': KeyInfo(),
- 'crp-advertise-contained': KeyInfo(),
- 'disabled': KeyInfo(default=False),
- 'name': KeyInfo(),
- 'rp-hash-mask-length': KeyInfo(),
- 'rp-static-override': KeyInfo(default=False),
- 'ssm-range': KeyInfo(),
- 'switch-to-spt': KeyInfo(default=True),
- 'switch-to-spt-bytes': KeyInfo(default=0),
- 'switch-to-spt-interval': KeyInfo(),
- 'vrf': KeyInfo(default="main"),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ 'afi': KeyInfo(default='ipv4'),
+ 'bsm-forward-back': KeyInfo(),
+ 'crp-advertise-contained': KeyInfo(),
+ 'disabled': KeyInfo(default=False),
+ 'name': KeyInfo(),
+ 'rp-hash-mask-length': KeyInfo(),
+ 'rp-static-override': KeyInfo(default=False),
+ 'ssm-range': KeyInfo(),
+ 'switch-to-spt': KeyInfo(default=True),
+ 'switch-to-spt-bytes': KeyInfo(default=0),
+ 'switch-to-spt-interval': KeyInfo(),
+ 'vrf': KeyInfo(default="main"),
+ },
+ ),
),
('routing', 'pimsm', 'interface-template'): APIData(
- fully_understood=True,
- fields={
- 'disabled': KeyInfo(default=False),
- 'hello-delay': KeyInfo(default='5s'),
- 'hello-period': KeyInfo(default='30s'),
- 'instance': KeyInfo(required=True),
- 'interfaces': KeyInfo(can_disable=True),
- 'join-prune-period': KeyInfo(default='1m'),
- 'join-tracking-support': KeyInfo(default=True),
- 'override-interval': KeyInfo(default='2s500ms'),
- 'priority': KeyInfo(default=1),
- 'propagation-delay': KeyInfo(default='500ms'),
- 'source-addresses': KeyInfo(can_disable=True),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ fields={
+ 'disabled': KeyInfo(default=False),
+ 'hello-delay': KeyInfo(default='5s'),
+ 'hello-period': KeyInfo(default='30s'),
+ 'instance': KeyInfo(required=True),
+ 'interfaces': KeyInfo(can_disable=True),
+ 'join-prune-period': KeyInfo(default='1m'),
+ 'join-tracking-support': KeyInfo(default=True),
+ 'override-interval': KeyInfo(default='2s500ms'),
+ 'priority': KeyInfo(default=1),
+ 'propagation-delay': KeyInfo(default='500ms'),
+ 'source-addresses': KeyInfo(can_disable=True),
+ },
+ ),
+ ),
+ ('routing', 'rule'): APIData(
+ versioned=[
+ ('7', '>=', VersionedAPIData(
+ fully_understood=True,
+ fields={
+ 'action': KeyInfo(can_disable=True),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'dst-address': KeyInfo(can_disable=True),
+ 'interface': KeyInfo(can_disable=True),
+ 'min-prefix': KeyInfo(can_disable=True),
+ 'routing-mark': KeyInfo(can_disable=True),
+ 'src-address': KeyInfo(can_disable=True),
+ 'table': KeyInfo(can_disable=True),
+ },
+ )),
+ ],
+ ),
+ ('routing', 'table'): APIData(
+ versioned=[
+ ('7', '>=', VersionedAPIData(
+ fully_understood=True,
+ fields={
+ 'name': KeyInfo(required=True),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'fib': KeyInfo(),
+ },
+ )),
+ ],
),
('snmp', 'community'): APIData(
- fully_understood=True,
- primary_keys=('name', ),
- fields={
- 'addresses': KeyInfo(default='::/0'),
- 'authentication-password': KeyInfo(default=''),
- 'authentication-protocol': KeyInfo(default='MD5'),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'disabled': KeyInfo(default=False),
- 'encryption-password': KeyInfo(default=''),
- 'encryption-protocol': KeyInfo(default='DES'),
- 'name': KeyInfo(required=True),
- 'read-access': KeyInfo(default=True),
- 'security': KeyInfo(default='none'),
- 'write-access': KeyInfo(default=False),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ 'addresses': KeyInfo(default='::/0'),
+ 'authentication-password': KeyInfo(default=''),
+ 'authentication-protocol': KeyInfo(default='MD5'),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'encryption-password': KeyInfo(default=''),
+ 'encryption-protocol': KeyInfo(default='DES'),
+ 'name': KeyInfo(required=True),
+ 'read-access': KeyInfo(default=True),
+ 'security': KeyInfo(default='none'),
+ 'write-access': KeyInfo(default=False),
+ },
+ ),
),
('caps-man', 'aaa'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'called-format': KeyInfo(default='mac:ssid'),
- 'interim-update': KeyInfo(default='disabled'),
- 'mac-caching': KeyInfo(default='disabled'),
- 'mac-format': KeyInfo(default='XX:XX:XX:XX:XX:XX'),
- 'mac-mode': KeyInfo(default='as-username'),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'called-format': KeyInfo(default='mac:ssid'),
+ 'interim-update': KeyInfo(default='disabled'),
+ 'mac-caching': KeyInfo(default='disabled'),
+ 'mac-format': KeyInfo(default='XX:XX:XX:XX:XX:XX'),
+ 'mac-mode': KeyInfo(default='as-username'),
+ },
+ ),
),
('caps-man', 'access-list'): APIData(
- fully_understood=True,
- fields={
- 'action': KeyInfo(can_disable=True),
- 'allow-signal-out-of-range': KeyInfo(can_disable=True),
- 'ap-tx-limit': KeyInfo(can_disable=True),
- 'client-to-client-forwarding': KeyInfo(can_disable=True),
- 'client-tx-limit': KeyInfo(can_disable=True),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'disabled': KeyInfo(),
- 'interface': KeyInfo(can_disable=True),
- 'mac-address': KeyInfo(can_disable=True),
- 'mac-address-mask': KeyInfo(can_disable=True),
- 'private-passphrase': KeyInfo(can_disable=True),
- 'radius-accounting': KeyInfo(can_disable=True),
- 'signal-range': KeyInfo(can_disable=True),
- 'ssid-regexp': KeyInfo(),
- 'time': KeyInfo(can_disable=True),
- 'vlan-id': KeyInfo(can_disable=True),
- 'vlan-mode': KeyInfo(can_disable=True),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ fields={
+ 'action': KeyInfo(can_disable=True),
+ 'allow-signal-out-of-range': KeyInfo(can_disable=True),
+ 'ap-tx-limit': KeyInfo(can_disable=True),
+ 'client-to-client-forwarding': KeyInfo(can_disable=True),
+ 'client-tx-limit': KeyInfo(can_disable=True),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'interface': KeyInfo(can_disable=True),
+ 'mac-address': KeyInfo(can_disable=True),
+ 'mac-address-mask': KeyInfo(can_disable=True),
+ 'private-passphrase': KeyInfo(can_disable=True),
+ 'radius-accounting': KeyInfo(can_disable=True),
+ 'signal-range': KeyInfo(can_disable=True),
+ 'ssid-regexp': KeyInfo(),
+ 'time': KeyInfo(can_disable=True),
+ 'vlan-id': KeyInfo(can_disable=True),
+ 'vlan-mode': KeyInfo(can_disable=True),
+ },
+ ),
+ ),
+ ('caps-man', 'channel'): APIData(
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ 'band': KeyInfo(can_disable=True),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'control-channel-width': KeyInfo(can_disable=True),
+ 'extension-channel': KeyInfo(can_disable=True),
+ 'frequency': KeyInfo(can_disable=True),
+ 'name': KeyInfo(),
+ 'reselect-interval': KeyInfo(can_disable=True),
+ 'save-selected': KeyInfo(can_disable=True),
+ 'secondary-frequency': KeyInfo(can_disable=True),
+ 'skip-dfs-channels': KeyInfo(can_disable=True),
+ 'tx-power': KeyInfo(can_disable=True),
+ },
+ ),
),
('caps-man', 'configuration'): APIData(
- fully_understood=True,
- primary_keys=('name', ),
- fields={
- 'channel': KeyInfo(can_disable=True),
- 'channel.band': KeyInfo(can_disable=True),
- 'channel.control-channel-width': KeyInfo(can_disable=True),
- 'channel.extension-channel': KeyInfo(can_disable=True),
- 'channel.frequency': KeyInfo(can_disable=True),
- 'channel.reselect-interval': KeyInfo(can_disable=True),
- 'channel.save-selected': KeyInfo(can_disable=True),
- 'channel.secondary-frequency': KeyInfo(can_disable=True),
- 'channel.skip-dfs-channels': KeyInfo(can_disable=True),
- 'channel.tx-power': KeyInfo(can_disable=True),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'country': KeyInfo(can_disable=True),
- 'datapath': KeyInfo(can_disable=True),
- 'datapath.arp': KeyInfo(),
- 'datapath.bridge': KeyInfo(can_disable=True),
- 'datapath.bridge-cost': KeyInfo(can_disable=True),
- 'datapath.bridge-horizon': KeyInfo(can_disable=True),
- 'datapath.client-to-client-forwarding': KeyInfo(can_disable=True),
- 'datapath.interface-list': KeyInfo(can_disable=True),
- 'datapath.l2mtu': KeyInfo(),
- 'datapath.local-forwarding': KeyInfo(can_disable=True),
- 'datapath.mtu': KeyInfo(),
- 'datapath.openflow-switch': KeyInfo(can_disable=True),
- 'datapath.vlan-id': KeyInfo(can_disable=True),
- 'datapath.vlan-mode': KeyInfo(can_disable=True),
- 'disconnect-timeout': KeyInfo(can_disable=True),
- 'distance': KeyInfo(can_disable=True),
- 'frame-lifetime': KeyInfo(can_disable=True),
- 'guard-interval': KeyInfo(can_disable=True),
- 'hide-ssid': KeyInfo(can_disable=True),
- 'hw-protection-mode': KeyInfo(can_disable=True),
- 'hw-retries': KeyInfo(can_disable=True),
- 'installation': KeyInfo(can_disable=True),
- 'keepalive-frames': KeyInfo(can_disable=True),
- 'load-balancing-group': KeyInfo(can_disable=True),
- 'max-sta-count': KeyInfo(can_disable=True),
- 'mode': KeyInfo(can_disable=True),
- 'multicast-helper': KeyInfo(can_disable=True),
- 'name': KeyInfo(),
- 'rates': KeyInfo(can_disable=True),
- 'rates.basic': KeyInfo(can_disable=True),
- 'rates.ht-basic-mcs': KeyInfo(can_disable=True),
- 'rates.ht-supported-mcs': KeyInfo(can_disable=True),
- 'rates.supported': KeyInfo(can_disable=True),
- 'rates.vht-basic-mcs': KeyInfo(can_disable=True),
- 'rates.vht-supported-mcs': KeyInfo(can_disable=True),
- 'rx-chains': KeyInfo(can_disable=True),
- 'security': KeyInfo(can_disable=True),
- 'security.authentication-types': KeyInfo(can_disable=True),
- 'security.disable-pmkid': KeyInfo(can_disable=True),
- 'security.eap-methods': KeyInfo(can_disable=True),
- 'security.eap-radius-accounting': KeyInfo(can_disable=True),
- 'security.encryption': KeyInfo(can_disable=True),
- 'security.group-encryption': KeyInfo(can_disable=True),
- 'security.group-key-update': KeyInfo(),
- 'security.passphrase': KeyInfo(can_disable=True),
- 'security.tls-certificate': KeyInfo(),
- 'security.tls-mode': KeyInfo(),
- 'ssid': KeyInfo(can_disable=True),
- 'tx-chains': KeyInfo(can_disable=True),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ 'channel': KeyInfo(can_disable=True),
+ 'channel.band': KeyInfo(can_disable=True),
+ 'channel.control-channel-width': KeyInfo(can_disable=True),
+ 'channel.extension-channel': KeyInfo(can_disable=True),
+ 'channel.frequency': KeyInfo(can_disable=True),
+ 'channel.reselect-interval': KeyInfo(can_disable=True),
+ 'channel.save-selected': KeyInfo(can_disable=True),
+ 'channel.secondary-frequency': KeyInfo(can_disable=True),
+ 'channel.skip-dfs-channels': KeyInfo(can_disable=True),
+ 'channel.tx-power': KeyInfo(can_disable=True),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'country': KeyInfo(can_disable=True),
+ 'datapath': KeyInfo(can_disable=True),
+ 'datapath.arp': KeyInfo(),
+ 'datapath.bridge': KeyInfo(can_disable=True),
+ 'datapath.bridge-cost': KeyInfo(can_disable=True),
+ 'datapath.bridge-horizon': KeyInfo(can_disable=True),
+ 'datapath.client-to-client-forwarding': KeyInfo(can_disable=True),
+ 'datapath.interface-list': KeyInfo(can_disable=True),
+ 'datapath.l2mtu': KeyInfo(),
+ 'datapath.local-forwarding': KeyInfo(can_disable=True),
+ 'datapath.mtu': KeyInfo(),
+ 'datapath.openflow-switch': KeyInfo(can_disable=True),
+ 'datapath.vlan-id': KeyInfo(can_disable=True),
+ 'datapath.vlan-mode': KeyInfo(can_disable=True),
+ 'disconnect-timeout': KeyInfo(can_disable=True),
+ 'distance': KeyInfo(can_disable=True),
+ 'frame-lifetime': KeyInfo(can_disable=True),
+ 'guard-interval': KeyInfo(can_disable=True),
+ 'hide-ssid': KeyInfo(can_disable=True),
+ 'hw-protection-mode': KeyInfo(can_disable=True),
+ 'hw-retries': KeyInfo(can_disable=True),
+ 'installation': KeyInfo(can_disable=True),
+ 'keepalive-frames': KeyInfo(can_disable=True),
+ 'load-balancing-group': KeyInfo(can_disable=True),
+ 'max-sta-count': KeyInfo(can_disable=True),
+ 'mode': KeyInfo(can_disable=True),
+ 'multicast-helper': KeyInfo(can_disable=True),
+ 'name': KeyInfo(),
+ 'rates': KeyInfo(can_disable=True),
+ 'rates.basic': KeyInfo(can_disable=True),
+ 'rates.ht-basic-mcs': KeyInfo(can_disable=True),
+ 'rates.ht-supported-mcs': KeyInfo(can_disable=True),
+ 'rates.supported': KeyInfo(can_disable=True),
+ 'rates.vht-basic-mcs': KeyInfo(can_disable=True),
+ 'rates.vht-supported-mcs': KeyInfo(can_disable=True),
+ 'rx-chains': KeyInfo(can_disable=True),
+ 'security': KeyInfo(can_disable=True),
+ 'security.authentication-types': KeyInfo(can_disable=True),
+ 'security.disable-pmkid': KeyInfo(can_disable=True),
+ 'security.eap-methods': KeyInfo(can_disable=True),
+ 'security.eap-radius-accounting': KeyInfo(can_disable=True),
+ 'security.encryption': KeyInfo(can_disable=True),
+ 'security.group-encryption': KeyInfo(can_disable=True),
+ 'security.group-key-update': KeyInfo(),
+ 'security.passphrase': KeyInfo(can_disable=True),
+ 'security.tls-certificate': KeyInfo(),
+ 'security.tls-mode': KeyInfo(),
+ 'ssid': KeyInfo(can_disable=True),
+ 'tx-chains': KeyInfo(can_disable=True),
+ },
+ ),
),
('caps-man', 'datapath'): APIData(
- fully_understood=True,
- primary_keys=('name', ),
- fields={
- 'arp': KeyInfo(),
- 'bridge': KeyInfo(can_disable=True),
- 'bridge-cost': KeyInfo(can_disable=True),
- 'bridge-horizon': KeyInfo(can_disable=True),
- 'client-to-client-forwarding': KeyInfo(can_disable=True),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'interface-list': KeyInfo(can_disable=True),
- 'l2mtu': KeyInfo(),
- 'local-forwarding': KeyInfo(can_disable=True),
- 'mtu': KeyInfo(),
- 'name': KeyInfo(),
- 'openflow-switch': KeyInfo(can_disable=True),
- 'vlan-id': KeyInfo(can_disable=True),
- 'vlan-mode': KeyInfo(can_disable=True),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ 'arp': KeyInfo(),
+ 'bridge': KeyInfo(can_disable=True),
+ 'bridge-cost': KeyInfo(can_disable=True),
+ 'bridge-horizon': KeyInfo(can_disable=True),
+ 'client-to-client-forwarding': KeyInfo(can_disable=True),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'interface-list': KeyInfo(can_disable=True),
+ 'l2mtu': KeyInfo(),
+ 'local-forwarding': KeyInfo(can_disable=True),
+ 'mtu': KeyInfo(),
+ 'name': KeyInfo(),
+ 'openflow-switch': KeyInfo(can_disable=True),
+ 'vlan-id': KeyInfo(can_disable=True),
+ 'vlan-mode': KeyInfo(can_disable=True),
+ },
+ ),
),
('caps-man', 'manager', 'interface'): APIData(
- unknown_mechanism=True,
- # primary_keys=('default', ),
- fields={
- 'default': KeyInfo(),
- 'disabled': KeyInfo(),
- 'forbid': KeyInfo(),
- 'interface': KeyInfo(),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('interface', ),
+ fields={
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'default': KeyInfo(),
+ 'disabled': KeyInfo(default=False),
+ 'forbid': KeyInfo(default=False),
+ 'interface': KeyInfo(),
+ },
+ ),
),
('caps-man', 'provisioning'): APIData(
- fully_understood=True,
- fields={
- 'action': KeyInfo(default='none'),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'common-name-regexp': KeyInfo(default=''),
- 'disabled': KeyInfo(default=False),
- 'hw-supported-modes': KeyInfo(default=''),
- 'identity-regexp': KeyInfo(default=''),
- 'ip-address-ranges': KeyInfo(default=''),
- 'master-configuration': KeyInfo(default='*FFFFFFFF'),
- 'name-format': KeyInfo(default='cap'),
- 'name-prefix': KeyInfo(default=''),
- 'radio-mac': KeyInfo(default='00:00:00:00:00:00'),
- 'slave-configurations': KeyInfo(default=''),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ fields={
+ 'action': KeyInfo(default='none'),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'common-name-regexp': KeyInfo(default=''),
+ 'disabled': KeyInfo(default=False),
+ 'hw-supported-modes': KeyInfo(default=''),
+ 'identity-regexp': KeyInfo(default=''),
+ 'ip-address-ranges': KeyInfo(default=''),
+ 'master-configuration': KeyInfo(default='*FFFFFFFF'),
+ 'name-format': KeyInfo(default='cap'),
+ 'name-prefix': KeyInfo(default=''),
+ 'radio-mac': KeyInfo(default='00:00:00:00:00:00'),
+ 'slave-configurations': KeyInfo(default=''),
+ },
+ ),
),
('caps-man', 'security'): APIData(
- fully_understood=True,
- primary_keys=('name', ),
- fields={
- 'authentication-types': KeyInfo(can_disable=True),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'disable-pmkid': KeyInfo(can_disable=True),
- 'eap-methods': KeyInfo(can_disable=True),
- 'eap-radius-accounting': KeyInfo(can_disable=True),
- 'encryption': KeyInfo(can_disable=True),
- 'group-encryption': KeyInfo(can_disable=True),
- 'group-key-update': KeyInfo(),
- 'name': KeyInfo(),
- 'passphrase': KeyInfo(can_disable=True),
- 'tls-certificate': KeyInfo(),
- 'tls-mode': KeyInfo(),
- }
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ 'authentication-types': KeyInfo(can_disable=True),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disable-pmkid': KeyInfo(can_disable=True),
+ 'eap-methods': KeyInfo(can_disable=True),
+ 'eap-radius-accounting': KeyInfo(can_disable=True),
+ 'encryption': KeyInfo(can_disable=True),
+ 'group-encryption': KeyInfo(can_disable=True),
+ 'group-key-update': KeyInfo(),
+ 'name': KeyInfo(),
+ 'passphrase': KeyInfo(can_disable=True),
+ 'tls-certificate': KeyInfo(),
+ 'tls-mode': KeyInfo(),
+ }
+ ),
),
('certificate', 'settings'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'crl-download': KeyInfo(default=False),
- 'crl-store': KeyInfo(default='ram'),
- 'crl-use': KeyInfo(default=False),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'crl-download': KeyInfo(default=False),
+ 'crl-store': KeyInfo(default='ram'),
+ 'crl-use': KeyInfo(default=False),
+ },
+ ),
),
('interface', 'bridge', 'port'): APIData(
- fully_understood=True,
- primary_keys=('interface', ),
- fields={
- 'auto-isolate': KeyInfo(default=False),
- 'bpdu-guard': KeyInfo(default=False),
- 'bridge': KeyInfo(required=True),
- 'broadcast-flood': KeyInfo(default=True),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'disabled': KeyInfo(default=False),
- 'edge': KeyInfo(default='auto'),
- 'fast-leave': KeyInfo(default=False),
- 'frame-types': KeyInfo(default='admit-all'),
- 'horizon': KeyInfo(default='none'),
- 'hw': KeyInfo(default=True),
- 'ingress-filtering': KeyInfo(default=True),
- 'interface': KeyInfo(),
- 'internal-path-cost': KeyInfo(default=10),
- 'learn': KeyInfo(default='auto'),
- 'multicast-router': KeyInfo(default='temporary-query'),
- 'path-cost': KeyInfo(default=10),
- 'point-to-point': KeyInfo(default='auto'),
- 'priority': KeyInfo(default='0x80'),
- 'pvid': KeyInfo(default=1),
- 'restricted-role': KeyInfo(default=False),
- 'restricted-tcn': KeyInfo(default=False),
- 'tag-stacking': KeyInfo(default=False),
- 'trusted': KeyInfo(default=False),
- 'unknown-multicast-flood': KeyInfo(default=True),
- 'unknown-unicast-flood': KeyInfo(default=True),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('interface', ),
+ fields={
+ 'auto-isolate': KeyInfo(default=False),
+ 'bpdu-guard': KeyInfo(default=False),
+ 'bridge': KeyInfo(required=True),
+ 'broadcast-flood': KeyInfo(default=True),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'edge': KeyInfo(default='auto'),
+ 'fast-leave': KeyInfo(default=False),
+ 'frame-types': KeyInfo(default='admit-all'),
+ 'horizon': KeyInfo(default='none'),
+ 'hw': KeyInfo(default=True),
+ 'ingress-filtering': KeyInfo(default=True),
+ 'interface': KeyInfo(),
+ 'internal-path-cost': KeyInfo(default=10),
+ 'learn': KeyInfo(default='auto'),
+ 'multicast-router': KeyInfo(default='temporary-query'),
+ 'path-cost': KeyInfo(default=10),
+ 'point-to-point': KeyInfo(default='auto'),
+ 'priority': KeyInfo(default='0x80'),
+ 'pvid': KeyInfo(default=1),
+ 'restricted-role': KeyInfo(default=False),
+ 'restricted-tcn': KeyInfo(default=False),
+ 'tag-stacking': KeyInfo(default=False),
+ 'trusted': KeyInfo(default=False),
+ 'unknown-multicast-flood': KeyInfo(default=True),
+ 'unknown-unicast-flood': KeyInfo(default=True),
+ },
+ ),
),
('interface', 'bridge', 'mlag'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'bridge': KeyInfo(default='none'),
- 'peer-port': KeyInfo(default='none'),
- }
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'bridge': KeyInfo(default='none'),
+ 'peer-port': KeyInfo(default='none'),
+ }
+ ),
),
('interface', 'bridge', 'port-controller'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'bridge': KeyInfo(default='none'),
- 'cascade-ports': KeyInfo(default=''),
- 'switch': KeyInfo(default='none'),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'bridge': KeyInfo(default='none'),
+ 'cascade-ports': KeyInfo(default=''),
+ 'switch': KeyInfo(default='none'),
+ },
+ ),
),
('interface', 'bridge', 'port-extender'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'control-ports': KeyInfo(default=''),
- 'excluded-ports': KeyInfo(default=''),
- 'switch': KeyInfo(default='none'),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'control-ports': KeyInfo(default=''),
+ 'excluded-ports': KeyInfo(default=''),
+ 'switch': KeyInfo(default='none'),
+ },
+ ),
),
('interface', 'bridge', 'settings'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'allow-fast-path': KeyInfo(default=True),
- 'use-ip-firewall': KeyInfo(default=False),
- 'use-ip-firewall-for-pppoe': KeyInfo(default=False),
- 'use-ip-firewall-for-vlan': KeyInfo(default=False),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'allow-fast-path': KeyInfo(default=True),
+ 'use-ip-firewall': KeyInfo(default=False),
+ 'use-ip-firewall-for-pppoe': KeyInfo(default=False),
+ 'use-ip-firewall-for-vlan': KeyInfo(default=False),
+ },
+ ),
),
('interface', 'bridge', 'vlan'): APIData(
- fully_understood=True,
- primary_keys=('bridge', 'vlan-ids', ),
- fields={
- 'bridge': KeyInfo(),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'disabled': KeyInfo(default=False),
- 'tagged': KeyInfo(default=''),
- 'untagged': KeyInfo(default=''),
- 'vlan-ids': KeyInfo(),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('bridge', 'vlan-ids', ),
+ fields={
+ 'bridge': KeyInfo(),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'tagged': KeyInfo(default=''),
+ 'untagged': KeyInfo(default=''),
+ 'vlan-ids': KeyInfo(),
+ },
+ ),
),
('ip', 'firewall', 'connection', 'tracking'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'enabled': KeyInfo(default='auto'),
- 'generic-timeout': KeyInfo(default='10m'),
- 'icmp-timeout': KeyInfo(default='10s'),
- 'loose-tcp-tracking': KeyInfo(default=True),
- 'tcp-close-timeout': KeyInfo(default='10s'),
- 'tcp-close-wait-timeout': KeyInfo(default='10s'),
- 'tcp-established-timeout': KeyInfo(default='1d'),
- 'tcp-fin-wait-timeout': KeyInfo(default='10s'),
- 'tcp-last-ack-timeout': KeyInfo(default='10s'),
- 'tcp-max-retrans-timeout': KeyInfo(default='5m'),
- 'tcp-syn-received-timeout': KeyInfo(default='5s'),
- 'tcp-syn-sent-timeout': KeyInfo(default='5s'),
- 'tcp-time-wait-timeout': KeyInfo(default='10s'),
- 'tcp-unacked-timeout': KeyInfo(default='5m'),
- 'udp-stream-timeout': KeyInfo(default='3m'),
- 'udp-timeout': KeyInfo(default='10s'),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'enabled': KeyInfo(default='auto'),
+ 'generic-timeout': KeyInfo(default='10m'),
+ 'icmp-timeout': KeyInfo(default='10s'),
+ 'loose-tcp-tracking': KeyInfo(default=True),
+ 'tcp-close-timeout': KeyInfo(default='10s'),
+ 'tcp-close-wait-timeout': KeyInfo(default='10s'),
+ 'tcp-established-timeout': KeyInfo(default='1d'),
+ 'tcp-fin-wait-timeout': KeyInfo(default='10s'),
+ 'tcp-last-ack-timeout': KeyInfo(default='10s'),
+ 'tcp-max-retrans-timeout': KeyInfo(default='5m'),
+ 'tcp-syn-received-timeout': KeyInfo(default='5s'),
+ 'tcp-syn-sent-timeout': KeyInfo(default='5s'),
+ 'tcp-time-wait-timeout': KeyInfo(default='10s'),
+ 'tcp-unacked-timeout': KeyInfo(default='5m'),
+ 'udp-stream-timeout': KeyInfo(default='3m'),
+ 'udp-timeout': KeyInfo(default='10s'),
+ },
+ ),
),
('ip', 'neighbor', 'discovery-settings'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'discover-interface-list': KeyInfo(),
- 'lldp-med-net-policy-vlan': KeyInfo(default='disabled'),
- 'protocol': KeyInfo(default='cdp,lldp,mndp'),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ versioned_fields=[
+ ([('7.7', '>=')], 'mode', KeyInfo(default='tx-and-rx')),
+ ],
+ fields={
+ 'discover-interface-list': KeyInfo(),
+ 'lldp-med-net-policy-vlan': KeyInfo(default='disabled'),
+ 'protocol': KeyInfo(default='cdp,lldp,mndp'),
+ },
+ ),
),
('ip', 'settings'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'accept-redirects': KeyInfo(default=False),
- 'accept-source-route': KeyInfo(default=False),
- 'allow-fast-path': KeyInfo(default=True),
- 'arp-timeout': KeyInfo(default='30s'),
- 'icmp-rate-limit': KeyInfo(default=10),
- 'icmp-rate-mask': KeyInfo(default='0x1818'),
- 'ip-forward': KeyInfo(default=True),
- 'max-neighbor-entries': KeyInfo(default=8192),
- 'route-cache': KeyInfo(default=True),
- 'rp-filter': KeyInfo(default=False),
- 'secure-redirects': KeyInfo(default=True),
- 'send-redirects': KeyInfo(default=True),
- 'tcp-syncookies': KeyInfo(default=False),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'accept-redirects': KeyInfo(default=False),
+ 'accept-source-route': KeyInfo(default=False),
+ 'allow-fast-path': KeyInfo(default=True),
+ 'arp-timeout': KeyInfo(default='30s'),
+ 'icmp-rate-limit': KeyInfo(default=10),
+ 'icmp-rate-mask': KeyInfo(default='0x1818'),
+ 'ip-forward': KeyInfo(default=True),
+ 'max-neighbor-entries': KeyInfo(default=8192),
+ 'route-cache': KeyInfo(default=True),
+ 'rp-filter': KeyInfo(default=False),
+ 'secure-redirects': KeyInfo(default=True),
+ 'send-redirects': KeyInfo(default=True),
+ 'tcp-syncookies': KeyInfo(default=False),
+ },
+ ),
),
('ipv6', 'address'): APIData(
- fully_understood=True,
- fields={
- 'address': KeyInfo(),
- 'advertise': KeyInfo(default=True),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'disabled': KeyInfo(default=False),
- 'eui-64': KeyInfo(default=False),
- 'from-pool': KeyInfo(),
- 'interface': KeyInfo(required=True),
- 'no-dad': KeyInfo(default=False),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ fields={
+ 'address': KeyInfo(),
+ 'advertise': KeyInfo(default=True),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'eui-64': KeyInfo(default=False),
+ 'from-pool': KeyInfo(),
+ 'interface': KeyInfo(required=True),
+ 'no-dad': KeyInfo(default=False),
+ },
+ ),
),
('ipv6', 'settings'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'accept-redirects': KeyInfo(default='yes-if-forwarding-disabled'),
- 'accept-router-advertisements': KeyInfo(default='yes-if-forwarding-disabled'),
- 'disable-ipv6': KeyInfo(default=False),
- 'forward': KeyInfo(default=True),
- 'max-neighbor-entries': KeyInfo(default=8192),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'accept-redirects': KeyInfo(default='yes-if-forwarding-disabled'),
+ 'accept-router-advertisements': KeyInfo(default='yes-if-forwarding-disabled'),
+ 'disable-ipv6': KeyInfo(default=False),
+ 'forward': KeyInfo(default=True),
+ 'max-neighbor-entries': KeyInfo(default=8192),
+ },
+ ),
),
('interface', 'detect-internet'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'detect-interface-list': KeyInfo(default='none'),
- 'internet-interface-list': KeyInfo(default='none'),
- 'lan-interface-list': KeyInfo(default='none'),
- 'wan-interface-list': KeyInfo(default='none'),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'detect-interface-list': KeyInfo(default='none'),
+ 'internet-interface-list': KeyInfo(default='none'),
+ 'lan-interface-list': KeyInfo(default='none'),
+ 'wan-interface-list': KeyInfo(default='none'),
+ },
+ ),
),
('interface', 'l2tp-server', 'server'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'allow-fast-path': KeyInfo(default=False),
- 'authentication': KeyInfo(default='pap,chap,mschap1,mschap2'),
- 'caller-id-type': KeyInfo(default='ip-address'),
- 'default-profile': KeyInfo(default='default-encryption'),
- 'enabled': KeyInfo(default=False),
- 'ipsec-secret': KeyInfo(default=''),
- 'keepalive-timeout': KeyInfo(default=30),
- 'max-mru': KeyInfo(default=1450),
- 'max-mtu': KeyInfo(default=1450),
- 'max-sessions': KeyInfo(default='unlimited'),
- 'mrru': KeyInfo(default='disabled'),
- 'one-session-per-host': KeyInfo(default=False),
- 'use-ipsec': KeyInfo(default=False),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'allow-fast-path': KeyInfo(default=False),
+ 'authentication': KeyInfo(default='pap,chap,mschap1,mschap2'),
+ 'caller-id-type': KeyInfo(default='ip-address'),
+ 'default-profile': KeyInfo(default='default-encryption'),
+ 'enabled': KeyInfo(default=False),
+ 'ipsec-secret': KeyInfo(default=''),
+ 'keepalive-timeout': KeyInfo(default=30),
+ 'max-mru': KeyInfo(default=1450),
+ 'max-mtu': KeyInfo(default=1450),
+ 'max-sessions': KeyInfo(default='unlimited'),
+ 'mrru': KeyInfo(default='disabled'),
+ 'one-session-per-host': KeyInfo(default=False),
+ 'use-ipsec': KeyInfo(default=False),
+ },
+ ),
+ ),
+ ('interface', 'ovpn-client'): APIData(
+ unversioned=VersionedAPIData(
+ primary_keys=('name', ),
+ fully_understood=True,
+ fields={
+ 'add-default-route': KeyInfo(default=False),
+ 'auth': KeyInfo(default='sha1'),
+ 'certificate': KeyInfo(),
+ 'cipher': KeyInfo(default='blowfish128'),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'connect-to': KeyInfo(),
+ 'disabled': KeyInfo(default=True),
+ 'disconnect-notify': KeyInfo(),
+ 'mac-address': KeyInfo(),
+ 'max-mtu': KeyInfo(default=1500),
+ 'mode': KeyInfo(default='ip'),
+ 'name': KeyInfo(),
+ 'password': KeyInfo(),
+ 'port': KeyInfo(default=1194),
+ 'profile': KeyInfo(default='default'),
+ 'protocol': KeyInfo(default='tcp'),
+ 'route-nopull': KeyInfo(default=False),
+ 'tls-version': KeyInfo(default='any'),
+ 'use-peer-dns': KeyInfo(default=True),
+ 'user': KeyInfo(),
+ 'verify-server-certificate': KeyInfo(default=False),
+ },
+ ),
),
('interface', 'ovpn-server', 'server'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'auth': KeyInfo(),
- 'cipher': KeyInfo(),
- 'default-profile': KeyInfo(default='default'),
- 'enabled': KeyInfo(default=False),
- 'keepalive-timeout': KeyInfo(default=60),
- 'mac-address': KeyInfo(),
- 'max-mtu': KeyInfo(default=1500),
- 'mode': KeyInfo(default='ip'),
- 'netmask': KeyInfo(default=24),
- 'port': KeyInfo(default=1194),
- 'require-client-certificate': KeyInfo(default=False),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'auth': KeyInfo(),
+ 'cipher': KeyInfo(),
+ 'default-profile': KeyInfo(default='default'),
+ 'enabled': KeyInfo(default=False),
+ 'keepalive-timeout': KeyInfo(default=60),
+ 'mac-address': KeyInfo(),
+ 'max-mtu': KeyInfo(default=1500),
+ 'mode': KeyInfo(default='ip'),
+ 'netmask': KeyInfo(default=24),
+ 'port': KeyInfo(default=1194),
+ 'require-client-certificate': KeyInfo(default=False),
+ },
+ ),
),
('interface', 'pptp-server', 'server'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'authentication': KeyInfo(default='mschap1,mschap2'),
- 'default-profile': KeyInfo(default='default-encryption'),
- 'enabled': KeyInfo(default=False),
- 'keepalive-timeout': KeyInfo(default=30),
- 'max-mru': KeyInfo(default=1450),
- 'max-mtu': KeyInfo(default=1450),
- 'mrru': KeyInfo(default='disabled'),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'authentication': KeyInfo(default='mschap1,mschap2'),
+ 'default-profile': KeyInfo(default='default-encryption'),
+ 'enabled': KeyInfo(default=False),
+ 'keepalive-timeout': KeyInfo(default=30),
+ 'max-mru': KeyInfo(default=1450),
+ 'max-mtu': KeyInfo(default=1450),
+ 'mrru': KeyInfo(default='disabled'),
+ },
+ ),
),
('interface', 'sstp-server', 'server'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'authentication': KeyInfo(default='pap,chap,mschap1,mschap2'),
- 'certificate': KeyInfo(default='none'),
- 'default-profile': KeyInfo(default='default'),
- 'enabled': KeyInfo(default=False),
- 'force-aes': KeyInfo(default=False),
- 'keepalive-timeout': KeyInfo(default=60),
- 'max-mru': KeyInfo(default=1500),
- 'max-mtu': KeyInfo(default=1500),
- 'mrru': KeyInfo(default='disabled'),
- 'pfs': KeyInfo(default=False),
- 'port': KeyInfo(default=443),
- 'tls-version': KeyInfo(default='any'),
- 'verify-client-certificate': KeyInfo(default='no'),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'authentication': KeyInfo(default='pap,chap,mschap1,mschap2'),
+ 'certificate': KeyInfo(default='none'),
+ 'default-profile': KeyInfo(default='default'),
+ 'enabled': KeyInfo(default=False),
+ 'force-aes': KeyInfo(default=False),
+ 'keepalive-timeout': KeyInfo(default=60),
+ 'max-mru': KeyInfo(default=1500),
+ 'max-mtu': KeyInfo(default=1500),
+ 'mrru': KeyInfo(default='disabled'),
+ 'pfs': KeyInfo(default=False),
+ 'port': KeyInfo(default=443),
+ 'tls-version': KeyInfo(default='any'),
+ 'verify-client-certificate': KeyInfo(default='no'),
+ },
+ ),
+ ),
+ ('interface', 'wifi'): APIData(
+ versioned=[
+ ('7.13', '>=', VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ required_one_of=[['default-name', 'radio-mac', 'master-interface']],
+ fields={
+ 'aaa.called-format': KeyInfo(can_disable=True),
+ 'aaa.calling-format': KeyInfo(can_disable=True),
+ 'aaa.interim-update': KeyInfo(can_disable=True),
+ 'aaa.mac-caching': KeyInfo(can_disable=True),
+ 'aaa.nas-identifier': KeyInfo(can_disable=True),
+ 'aaa.password-format': KeyInfo(can_disable=True),
+ 'aaa.username-format': KeyInfo(can_disable=True),
+ 'aaa': KeyInfo(can_disable=True),
+ 'arp-timeout': KeyInfo(default='auto'),
+ 'arp': KeyInfo(can_disable=True),
+ 'channel.band': KeyInfo(can_disable=True),
+ 'channel.frequency': KeyInfo(can_disable=True),
+ 'channel.secondary-frequency': KeyInfo(can_disable=True),
+ 'channel.skip-dfs-channels': KeyInfo(can_disable=True),
+ 'channel.width': KeyInfo(can_disable=True),
+ 'channel': KeyInfo(can_disable=True),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'configuration.antenna-gain': KeyInfo(can_disable=True),
+ 'configuration.beacon-interval': KeyInfo(can_disable=True),
+ 'configuration.chains': KeyInfo(can_disable=True),
+ 'configuration.country': KeyInfo(can_disable=True),
+ 'configuration.dtim-period': KeyInfo(can_disable=True),
+ 'configuration.hide-ssid': KeyInfo(can_disable=True),
+ 'configuration.manager': KeyInfo(can_disable=True),
+ 'configuration.mode': KeyInfo(can_disable=True),
+ 'configuration.multicast-enhance': KeyInfo(can_disable=True),
+ 'configuration.qos-classifier': KeyInfo(can_disable=True),
+ 'configuration.ssid': KeyInfo(can_disable=True),
+ 'configuration.tx-chain': KeyInfo(can_disable=True),
+ 'configuration.tx-power': KeyInfo(can_disable=True),
+ 'configuration': KeyInfo(can_disable=True),
+ 'datapath.bridge-cost': KeyInfo(can_disable=True),
+ 'datapath.bridge-horizon': KeyInfo(can_disable=True),
+ 'datapath.bridge': KeyInfo(can_disable=True),
+ 'datapath.client-isolation': KeyInfo(can_disable=True),
+ 'datapath.interface-list': KeyInfo(can_disable=True),
+ 'datapath.vlan-id': KeyInfo(can_disable=True),
+ 'datapath': KeyInfo(can_disable=True),
+ 'default-name': KeyInfo(),
+ 'disable-running-check': KeyInfo(can_disable=True),
+ 'disabled': KeyInfo(default=True),
+ 'interworking.3gpp-info': KeyInfo(can_disable=True),
+ 'interworking.authentication-types': KeyInfo(can_disable=True),
+ 'interworking.connection-capabilities': KeyInfo(can_disable=True),
+ 'interworking.domain-names': KeyInfo(can_disable=True),
+ 'interworking.esr': KeyInfo(can_disable=True),
+ 'interworking.hessid': KeyInfo(can_disable=True),
+ 'interworking.hotspot20-dgaf': KeyInfo(can_disable=True),
+ 'interworking.hotspot20': KeyInfo(can_disable=True),
+ 'interworking.internet': KeyInfo(can_disable=True),
+ 'interworking.ipv4-availability': KeyInfo(can_disable=True),
+ 'interworking.ipv6-availability': KeyInfo(can_disable=True),
+ 'interworking.network-type': KeyInfo(can_disable=True),
+ 'interworking.operational-classes': KeyInfo(can_disable=True),
+ 'interworking.operator-names': KeyInfo(can_disable=True),
+ 'interworking.realms': KeyInfo(can_disable=True),
+ 'interworking.roaming-ois': KeyInfo(can_disable=True),
+ 'interworking.uesa': KeyInfo(can_disable=True),
+ 'interworking.venue-names': KeyInfo(can_disable=True),
+ 'interworking.venue': KeyInfo(can_disable=True),
+ 'interworking.wan-at-capacity': KeyInfo(can_disable=True),
+ 'interworking.wan-downlink-load': KeyInfo(can_disable=True),
+ 'interworking.wan-downlink': KeyInfo(can_disable=True),
+ 'interworking.wan-measurement-duration': KeyInfo(can_disable=True),
+ 'interworking.wan-status': KeyInfo(can_disable=True),
+ 'interworking.wan-symmetric': KeyInfo(can_disable=True),
+ 'interworking.wan-uplink-load': KeyInfo(can_disable=True),
+ 'interworking.wan-uplink': KeyInfo(can_disable=True),
+ 'interworking': KeyInfo(can_disable=True),
+ 'l2mtu': KeyInfo(default=1560),
+ 'mac-address': KeyInfo(),
+ 'master-interface': KeyInfo(),
+ 'mtu': KeyInfo(default=1500),
+ 'name': KeyInfo(),
+ 'radio-mac': KeyInfo(),
+ 'security.authentication-types': KeyInfo(can_disable=True),
+ 'security.connect-group': KeyInfo(can_disable=True),
+ 'security.connect-priority': KeyInfo(can_disable=True),
+ 'security.dh-groups': KeyInfo(can_disable=True),
+ 'security.disable-pmkid': KeyInfo(can_disable=True),
+ 'security.eap-accounting': KeyInfo(can_disable=True),
+ 'security.eap-anonymous-identity': KeyInfo(can_disable=True),
+ 'security.eap-certificate-mode': KeyInfo(can_disable=True),
+ 'security.eap-methods': KeyInfo(can_disable=True),
+ 'security.eap-password': KeyInfo(can_disable=True),
+ 'security.eap-tls-certificate': KeyInfo(can_disable=True),
+ 'security.eap-username': KeyInfo(can_disable=True),
+ 'security.encryption': KeyInfo(can_disable=True),
+ 'security.ft-mobility-domain': KeyInfo(can_disable=True),
+ 'security.ft-nas-identifier': KeyInfo(can_disable=True),
+ 'security.ft-over-ds': KeyInfo(can_disable=True),
+ 'security.ft-preserve-vlanid': KeyInfo(can_disable=True),
+ 'security.ft-r0-key-lifetime': KeyInfo(can_disable=True),
+ 'security.ft-reassociation-deadline': KeyInfo(can_disable=True),
+ 'security.ft': KeyInfo(can_disable=True),
+ 'security.group-encryption': KeyInfo(can_disable=True),
+ 'security.group-key-update': KeyInfo(can_disable=True),
+ 'security.management-encryption': KeyInfo(can_disable=True),
+ 'security.management-protection': KeyInfo(can_disable=True),
+ 'security.owe-transition-interface': KeyInfo(can_disable=True),
+ 'security.passphrase': KeyInfo(can_disable=True),
+ 'security.sae-anti-clogging-threshold': KeyInfo(can_disable=True),
+ 'security.sae-max-failure-rate': KeyInfo(can_disable=True),
+ 'security.sae-pwe': KeyInfo(can_disable=True),
+ 'security.wps': KeyInfo(can_disable=True),
+ 'security': KeyInfo(can_disable=True),
+ 'steering.neighbor-group': KeyInfo(can_disable=True),
+ 'steering.rrm': KeyInfo(can_disable=True),
+ 'steering.wnm': KeyInfo(can_disable=True),
+ 'steering': KeyInfo(can_disable=True),
+ },
+ )),
+ ],
+ ),
+ ('interface', 'wifi', 'aaa'): APIData(
+ versioned=[
+ ('7.13', '>=', VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ 'called-format': KeyInfo(can_disable=True),
+ 'calling-format': KeyInfo(can_disable=True),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'interim-update': KeyInfo(can_disable=True),
+ 'mac-caching': KeyInfo(can_disable=True),
+ 'name': KeyInfo(),
+ 'nas-identifier': KeyInfo(can_disable=True),
+ 'password-format': KeyInfo(can_disable=True),
+ 'username-format': KeyInfo(can_disable=True),
+ },
+ )),
+ ],
+ ),
+ ('interface', 'wifi', 'access-list'): APIData(
+ versioned=[
+ ('7.13', '>=', VersionedAPIData(
+ fully_understood=True,
+ fields={
+ 'action': KeyInfo(default='accept'),
+ 'allow-signal-out-of-range': KeyInfo(can_disable=True),
+ 'client-isolation': KeyInfo(can_disable=True),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'interface': KeyInfo(can_disable=True),
+ 'mac-address-mask': KeyInfo(can_disable=True),
+ 'mac-address': KeyInfo(can_disable=True),
+ 'passphrase': KeyInfo(can_disable=True),
+ 'radius-accounting': KeyInfo(can_disable=True),
+ 'signal-range': KeyInfo(can_disable=True),
+ 'ssid-regexp': KeyInfo(can_disable=True),
+ 'time': KeyInfo(can_disable=True),
+ 'vlan-id': KeyInfo(can_disable=True),
+ },
+ )),
+ ],
+ ),
+ ('interface', 'wifi', 'cap'): APIData(
+ versioned=[
+ ('7.13', '>=', VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'caps-man-addresses': KeyInfo(default=''),
+ 'caps-man-certificate-common-names': KeyInfo(default=''),
+ 'caps-man-names': KeyInfo(default=''),
+ 'certificate': KeyInfo(default='none'),
+ 'discovery-interfaces': KeyInfo(default=''),
+ 'enabled': KeyInfo(default=False),
+ 'lock-to-caps-man': KeyInfo(default=False),
+ 'slaves-datapath': KeyInfo(),
+ 'slaves-static': KeyInfo(),
+ },
+ )),
+ ],
+ ),
+ ('interface', 'wifi', 'capsman'): APIData(
+ versioned=[
+ ('7.13', '>=', VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'ca-certificate': KeyInfo(default=''),
+ 'certificate': KeyInfo(default='none'),
+ 'enabled': KeyInfo(default=False),
+ 'interfaces': KeyInfo(default=''),
+ 'package-path': KeyInfo(default=''),
+ 'require-peer-certificate': KeyInfo(default=False),
+ 'upgrade-policy': KeyInfo(default='none'),
+ },
+ )),
+ ],
+ ),
+ ('interface', 'wifi', 'channel'): APIData(
+ versioned=[
+ ('7.13', '>=', VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ 'band': KeyInfo(can_disable=True),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'frequency': KeyInfo(can_disable=True),
+ 'name': KeyInfo(),
+ 'secondary-frequency': KeyInfo(can_disable=True),
+ 'skip-dfs-channels': KeyInfo(can_disable=True),
+ 'width': KeyInfo(can_disable=True),
+ },
+ )),
+ ],
+ ),
+ ('interface', 'wifi', 'configuration'): APIData(
+ versioned=[
+ ('7.13', '>=', VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ 'aaa': KeyInfo(can_disable=True),
+ 'antenna-gain': KeyInfo(can_disable=True),
+ 'beacon-interval': KeyInfo(can_disable=True),
+ 'chains': KeyInfo(can_disable=True),
+ 'channel': KeyInfo(can_disable=True),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'country': KeyInfo(can_disable=True),
+ 'datapath': KeyInfo(can_disable=True),
+ 'disabled': KeyInfo(default=False),
+ 'dtim-period': KeyInfo(can_disable=True),
+ 'hide-ssid': KeyInfo(default=False),
+ 'interworking': KeyInfo(can_disable=True),
+ 'manager': KeyInfo(can_disable=True),
+ 'mode': KeyInfo(can_disable=True),
+ 'multicast-enhance': KeyInfo(can_disable=True),
+ 'name': KeyInfo(),
+ 'qos-classifier': KeyInfo(can_disable=True),
+ 'security': KeyInfo(can_disable=True),
+ 'ssid': KeyInfo(can_disable=True),
+ 'steering': KeyInfo(can_disable=True),
+ 'tx-chains': KeyInfo(can_disable=True),
+ 'tx-power': KeyInfo(can_disable=True),
+ },
+ )),
+ ],
+ ),
+ ('interface', 'wifi', 'datapath'): APIData(
+ versioned=[
+ ('7.13', '>=', VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ 'bridge-cost': KeyInfo(can_disable=True),
+ 'bridge-horizon': KeyInfo(can_disable=True),
+ 'bridge': KeyInfo(can_disable=True),
+ 'client-isolation': KeyInfo(can_disable=True),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'interface-list': KeyInfo(can_disable=True),
+ 'name': KeyInfo(),
+ 'vlan-id': KeyInfo(can_disable=True),
+ },
+ )),
+ ],
+ ),
+ ('interface', 'wifi', 'interworking'): APIData(
+ versioned=[
+ ('7.13', '>=', VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ '3gpp-info': KeyInfo(can_disable=True),
+ 'authentication-types': KeyInfo(can_disable=True),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'connection-capabilities': KeyInfo(can_disable=True),
+ 'disabled': KeyInfo(default=False),
+ 'domain-names': KeyInfo(can_disable=True),
+ 'esr': KeyInfo(can_disable=True),
+ 'hessid': KeyInfo(can_disable=True),
+ 'hotspot20-dgaf': KeyInfo(can_disable=True),
+ 'hotspot20': KeyInfo(can_disable=True),
+ 'internet': KeyInfo(can_disable=True),
+ 'ipv4-availability': KeyInfo(can_disable=True),
+ 'ipv6-availability': KeyInfo(can_disable=True),
+ 'name': KeyInfo(),
+ 'network-type': KeyInfo(can_disable=True),
+ 'operational-classes': KeyInfo(can_disable=True),
+ 'operator-names': KeyInfo(can_disable=True),
+ 'realms': KeyInfo(can_disable=True),
+ 'roaming-ois': KeyInfo(can_disable=True),
+ 'uesa': KeyInfo(can_disable=True),
+ 'venue-names': KeyInfo(can_disable=True),
+ 'venue': KeyInfo(can_disable=True),
+ 'wan-at-capacity': KeyInfo(can_disable=True),
+ 'wan-downlink-load': KeyInfo(can_disable=True),
+ 'wan-downlink': KeyInfo(can_disable=True),
+ 'wan-measurement-duration': KeyInfo(can_disable=True),
+ 'wan-status': KeyInfo(can_disable=True),
+ 'wan-symmetric': KeyInfo(can_disable=True),
+ 'wan-uplink-load': KeyInfo(can_disable=True),
+ 'wan-uplink': KeyInfo(can_disable=True),
+ },
+ )),
+ ],
+ ),
+ ('interface', 'wifi', 'provisioning'): APIData(
+ versioned=[
+ ('7.13', '>=', VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('action', ),
+ fields={
+ 'action': KeyInfo(default='none'),
+ 'address-ranges': KeyInfo(can_disable=True),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'common-name-regexp': KeyInfo(can_disable=True),
+ 'disabled': KeyInfo(default=False),
+ 'identity-regexp': KeyInfo(can_disable=True),
+ 'master-configuration': KeyInfo(can_disable=True),
+ 'name-format': KeyInfo(can_disable=True),
+ 'radio-mac': KeyInfo(can_disable=True),
+ 'slave-configurations': KeyInfo(can_disable=True),
+ 'supported-bands': KeyInfo(can_disable=True),
+ },
+ )),
+ ],
+ ),
+ ('interface', 'wifi', 'security'): APIData(
+ versioned=[
+ ('7.13', '>=', VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ 'authentication-types': KeyInfo(can_disable=True),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'connect-group': KeyInfo(can_disable=True),
+ 'connect-priority': KeyInfo(can_disable=True),
+ 'dh-groups': KeyInfo(can_disable=True),
+ 'disable-pmkid': KeyInfo(can_disable=True),
+ 'disabled': KeyInfo(default=False),
+ 'eap-accounting': KeyInfo(can_disable=True),
+ 'eap-anonymous-identity': KeyInfo(can_disable=True),
+ 'eap-certificate-mode': KeyInfo(can_disable=True),
+ 'eap-methods': KeyInfo(can_disable=True),
+ 'eap-password': KeyInfo(can_disable=True),
+ 'eap-tls-certificate': KeyInfo(can_disable=True),
+ 'eap-username': KeyInfo(can_disable=True),
+ 'encryption': KeyInfo(can_disable=True),
+ 'ft-mobility-domain': KeyInfo(can_disable=True),
+ 'ft-nas-identifier': KeyInfo(can_disable=True),
+ 'ft-over-ds': KeyInfo(can_disable=True),
+ 'ft-preserve-vlanid': KeyInfo(can_disable=True),
+ 'ft-r0-key-lifetime': KeyInfo(can_disable=True),
+ 'ft-reassociation-deadline': KeyInfo(can_disable=True),
+ 'ft': KeyInfo(can_disable=True),
+ 'group-encryption': KeyInfo(can_disable=True),
+ 'group-key-update': KeyInfo(can_disable=True),
+ 'management-encryption': KeyInfo(can_disable=True),
+ 'management-protection': KeyInfo(can_disable=True),
+ 'name': KeyInfo(),
+ 'owe-transition-interface': KeyInfo(can_disable=True),
+ 'passphrase': KeyInfo(can_disable=True),
+ 'sae-anti-clogging-threshold': KeyInfo(can_disable=True),
+ 'sae-max-failure-rate': KeyInfo(can_disable=True),
+ 'sae-pwe': KeyInfo(can_disable=True),
+ 'wps': KeyInfo(can_disable=True),
+ },
+ )),
+ ],
+ ),
+ ('interface', 'wifi', 'steering'): APIData(
+ versioned=[
+ ('7.13', '>=', VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'name': KeyInfo(),
+ 'neighbor-group': KeyInfo(can_disable=True),
+ 'rrm': KeyInfo(can_disable=True),
+ 'wnm': KeyInfo(can_disable=True),
+ },
+ )),
+ ],
+ ),
+ ('interface', 'wifiwave2'): APIData(
+ versioned=[
+ ('7.13', '>=', 'RouterOS 7.13 uses WiFi package'),
+ ('7.8', '>=', VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ required_one_of=[['default-name', 'master-interface']],
+ fields={
+ 'aaa': KeyInfo(),
+ 'arp-timeout': KeyInfo(default='auto'),
+ 'arp': KeyInfo(default='enabled'),
+ 'channel': KeyInfo(),
+ 'configuration': KeyInfo(),
+ 'datapath': KeyInfo(),
+ 'default-name': KeyInfo(),
+ 'disable-running-check': KeyInfo(default=False),
+ 'interworking': KeyInfo(),
+ 'l2mtu': KeyInfo(default=1600),
+ 'mac-address': KeyInfo(),
+ 'master-interface': KeyInfo(),
+ 'mtu': KeyInfo(default=1500),
+ 'name': KeyInfo(),
+ 'security': KeyInfo(),
+ 'steering': KeyInfo(),
+ },
+ )),
+ ],
+ ),
+ ('interface', 'wifiwave2', 'aaa'): APIData(
+ versioned=[
+ ('7.13', '>=', 'RouterOS 7.13 uses WiFi package'),
+ ('7.8', '>=', VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ 'called-format': KeyInfo(can_disable=True),
+ 'calling-format': KeyInfo(can_disable=True),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=True),
+ 'interim-update': KeyInfo(can_disable=True),
+ 'mac-caching': KeyInfo(can_disable=True),
+ 'name': KeyInfo(),
+ 'nas-identifier': KeyInfo(can_disable=True),
+ 'password-format': KeyInfo(can_disable=True),
+ 'username-format': KeyInfo(can_disable=True),
+ },
+ )),
+ ],
+ ),
+ ('interface', 'wifiwave2', 'access-list'): APIData(
+ versioned=[
+ ('7.13', '>=', 'RouterOS 7.13 uses WiFi package'),
+ ('7.8', '>=', VersionedAPIData(
+ fully_understood=True,
+ fields={
+ 'action': KeyInfo(can_disable=True),
+ 'allow-signal-out-of-range': KeyInfo(can_disable=True),
+ 'client-isolation': KeyInfo(can_disable=True),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=True),
+ 'interface': KeyInfo(can_disable=True),
+ 'mac-address': KeyInfo(can_disable=True),
+ 'mac-address-mask': KeyInfo(can_disable=True),
+ 'passphrase': KeyInfo(can_disable=True),
+ 'radius-accounting': KeyInfo(can_disable=True),
+ 'signal-range': KeyInfo(can_disable=True),
+ 'ssid-regexp': KeyInfo(),
+ 'time': KeyInfo(can_disable=True),
+ 'vlan-id': KeyInfo(can_disable=True),
+ },
+ )),
+ ],
+ ),
+ ('interface', 'wifiwave2', 'cap'): APIData(
+ versioned=[
+ ('7.13', '>=', 'RouterOS 7.13 uses WiFi package'),
+ ('7.8', '>=', VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'caps-man-addresses': KeyInfo(default=''),
+ 'caps-man-certificate-common-names': KeyInfo(default=''),
+ 'caps-man-names': KeyInfo(default=''),
+ 'certificate': KeyInfo(default='none'),
+ 'discovery-interfaces': KeyInfo(default=''),
+ 'enabled': KeyInfo(default=False),
+ 'lock-to-caps-man': KeyInfo(default=False),
+ 'slaves-datapath': KeyInfo(),
+ 'slaves-static': KeyInfo(),
+ },
+ )),
+ ],
+ ),
+ ('interface', 'wifiwave2', 'capsman'): APIData(
+ versioned=[
+ ('7.13', '>=', 'RouterOS 7.13 uses WiFi package'),
+ ('7.8', '>=', VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'ca-certificate': KeyInfo(default=''),
+ 'certificate': KeyInfo(default='none'),
+ 'enabled': KeyInfo(default=False),
+ 'package-path': KeyInfo(default=''),
+ 'require-peer-certificate': KeyInfo(default=False),
+ 'upgrade-policy': KeyInfo(default='none'),
+ 'interfaces': KeyInfo(default=''),
+ },
+ )),
+ ],
+ ),
+ ('interface', 'wifiwave2', 'channel'): APIData(
+ versioned=[
+ ('7.13', '>=', 'RouterOS 7.13 uses WiFi package'),
+ ('7.8', '>=', VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ 'band': KeyInfo(),
+ 'frequency': KeyInfo(),
+ 'name': KeyInfo(),
+ 'secondary-frequency': KeyInfo(),
+ 'skip-dfs-channels': KeyInfo(default='disabled'),
+ 'width': KeyInfo(),
+ },
+ )),
+ ],
+ ),
+ ('interface', 'wifiwave2', 'configuration'): APIData(
+ versioned=[
+ ('7.13', '>=', 'RouterOS 7.13 uses WiFi package'),
+ ('7.8', '>=', VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ 'aaa': KeyInfo(),
+ 'antenna-gain': KeyInfo(),
+ 'beacon-interval': KeyInfo(default=100),
+ 'chains': KeyInfo(),
+ 'channel': KeyInfo(),
+ 'country': KeyInfo(default='United States'),
+ 'datapath': KeyInfo(),
+ 'dtim-period': KeyInfo(default=1),
+ 'hide-ssid': KeyInfo(default=False),
+ 'interworking': KeyInfo(),
+ 'manager': KeyInfo(),
+ 'mode': KeyInfo(default='ap'),
+ 'name': KeyInfo(),
+ 'security': KeyInfo(),
+ 'ssid': KeyInfo(),
+ 'steering': KeyInfo(),
+ 'tx-chains': KeyInfo(),
+ 'tx-power': KeyInfo(),
+ },
+ )),
+ ],
+ ),
+ ('interface', 'wifiwave2', 'datapath'): APIData(
+ versioned=[
+ ('7.13', '>=', 'RouterOS 7.13 uses WiFi package'),
+ ('7.8', '>=', VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ 'bridge': KeyInfo(),
+ 'bridge-cost': KeyInfo(),
+ 'bridge-horizon': KeyInfo(),
+ 'client-isolation': KeyInfo(default=False),
+ 'interface-list': KeyInfo(),
+ 'name': KeyInfo(),
+ 'openflow-switch': KeyInfo(),
+ 'vlan-id': KeyInfo(),
+ },
+ )),
+ ],
+ ),
+ ('interface', 'wifiwave2', 'interworking'): APIData(
+ versioned=[
+ ('7.13', '>=', 'RouterOS 7.13 uses WiFi package'),
+ ('7.8', '>=', VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ '3gpp-info': KeyInfo(),
+ 'authentication-types': KeyInfo(),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'connection-capabilities': KeyInfo(),
+ 'disabled': KeyInfo(default=False),
+ 'domain-names': KeyInfo(),
+ 'esr': KeyInfo(),
+ 'hessid': KeyInfo(),
+ 'hotspot20': KeyInfo(),
+ 'hotspot20-dgaf': KeyInfo(),
+ 'internet': KeyInfo(),
+ 'ipv4-availability': KeyInfo(),
+ 'ipv6-availability': KeyInfo(),
+ 'name': KeyInfo(),
+ 'network-type': KeyInfo(),
+ 'operational-classes': KeyInfo(),
+ 'operator-names': KeyInfo(),
+ 'realms': KeyInfo(),
+ 'roaming-ois': KeyInfo(),
+ 'uesa': KeyInfo(),
+ 'venue': KeyInfo(),
+ 'venue-names': KeyInfo(),
+ 'wan-at-capacity': KeyInfo(),
+ 'wan-downlink': KeyInfo(),
+ 'wan-downlink-load': KeyInfo(),
+ 'wan-measurement-duration': KeyInfo(),
+ 'wan-status': KeyInfo(),
+ 'wan-symmetric': KeyInfo(),
+ 'wan-uplink': KeyInfo(),
+ 'wan-uplink-load': KeyInfo(),
+ },
+ )),
+ ],
+ ),
+ ('interface', 'wifiwave2', 'provisioning'): APIData(
+ versioned=[
+ ('7.13', '>=', 'RouterOS 7.13 uses WiFi package'),
+ ('7.8', '>=', VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('action', ),
+ fields={
+ 'action': KeyInfo(default='none'),
+ 'address-ranges': KeyInfo(),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'common-name-regexp': KeyInfo(),
+ 'disabled': KeyInfo(default=False),
+ 'identity-regexp': KeyInfo(),
+ 'master-configuration': KeyInfo(),
+ 'name-format': KeyInfo(),
+ 'radio-mac': KeyInfo(),
+ 'slave-configurations': KeyInfo(),
+ 'supported-bands': KeyInfo(),
+ },
+ )),
+ ],
+ ),
+ ('interface', 'wifiwave2', 'security'): APIData(
+ versioned=[
+ ('7.13', '>=', 'RouterOS 7.13 uses WiFi package'),
+ ('7.8', '>=', VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ 'authentication-types': KeyInfo(),
+ 'connect-group': KeyInfo(can_disable=True),
+ 'connect-priority': KeyInfo(),
+ 'dh-groups': KeyInfo(),
+ 'disable-pmkid': KeyInfo(default=False),
+ 'eap-accounting': KeyInfo(default=False),
+ 'eap-anonymous-identity': KeyInfo(),
+ 'eap-certificate-mode': KeyInfo(default='dont-verify-certificate'),
+ 'eap-methods': KeyInfo(),
+ 'eap-password': KeyInfo(),
+ 'eap-tls-certificate': KeyInfo(),
+ 'eap-username': KeyInfo(),
+ 'encryption': KeyInfo(default='ccmp'),
+ 'ft-mobility-domain': KeyInfo(default=0xADC4),
+ 'ft-nas-identifier': KeyInfo(),
+ 'ft-over-ds': KeyInfo(default=False),
+ 'ft-preserve-vlanid': KeyInfo(default=True),
+ 'ft-r0-key-lifetime': KeyInfo(default='600000s'),
+ 'ft-reassociation-deadline': KeyInfo(default='20s'),
+ 'ft': KeyInfo(default=False),
+ 'group-encryption': KeyInfo(default='ccmp'),
+ 'group-key-update': KeyInfo(default='24h'),
+ 'management-encryption': KeyInfo(default='cmac'),
+ 'management-protection': KeyInfo(),
+ 'name': KeyInfo(),
+ 'owe-transition-interface': KeyInfo(),
+ 'passphrase': KeyInfo(default=''),
+ 'sae-anti-clogging-threshold': KeyInfo(can_disable=True),
+ 'sae-max-failure-rate': KeyInfo(can_disable=True),
+ 'sae-pwe': KeyInfo(default='both'),
+ 'wps': KeyInfo(default='push-button'),
+ },
+ )),
+ ],
+ ),
+ ('interface', 'wifiwave2', 'steering'): APIData(
+ versioned=[
+ ('7.13', '>=', 'RouterOS 7.13 uses WiFi package'),
+ ('7.8', '>=', VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'name': KeyInfo(),
+ 'neighbor-group': KeyInfo(),
+ 'rrm': KeyInfo(),
+ 'wnm': KeyInfo(),
+ },
+ )),
+ ],
),
('interface', 'wireguard'): APIData(
- fully_understood=True,
- primary_keys=('name', ),
- fields={
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'disabled': KeyInfo(default=False),
- 'listen-port': KeyInfo(),
- 'mtu': KeyInfo(default=1420),
- 'name': KeyInfo(),
- 'private-key': KeyInfo(),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'listen-port': KeyInfo(),
+ 'mtu': KeyInfo(default=1420),
+ 'name': KeyInfo(),
+ 'private-key': KeyInfo(),
+ },
+ ),
),
('interface', 'wireguard', 'peers'): APIData(
- fully_understood=True,
- primary_keys=('public-key', 'interface'),
- fields={
- 'allowed-address': KeyInfo(required=True),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'disabled': KeyInfo(default=False),
- 'endpoint-address': KeyInfo(default=''),
- 'endpoint-port': KeyInfo(default=0),
- 'interface': KeyInfo(),
- 'persistent-keepalive': KeyInfo(can_disable=True, remove_value=0),
- 'preshared-key': KeyInfo(can_disable=True, remove_value=''),
- 'public-key': KeyInfo(),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('public-key', 'interface'),
+ fields={
+ 'allowed-address': KeyInfo(required=True),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'endpoint-address': KeyInfo(default=''),
+ 'endpoint-port': KeyInfo(default=0),
+ 'interface': KeyInfo(),
+ 'persistent-keepalive': KeyInfo(can_disable=True, remove_value=0),
+ 'preshared-key': KeyInfo(can_disable=True, remove_value=''),
+ 'public-key': KeyInfo(),
+ },
+ ),
+ ),
+ ('interface', 'wireless'): APIData(
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ required_one_of=[['default-name', 'master-interface']],
+ fields={
+ 'adaptive-noise-immunity': KeyInfo(default='none'),
+ 'allow-sharedkey': KeyInfo(default=False),
+ 'ampdu-priorities': KeyInfo(default=0),
+ 'amsdu-limit': KeyInfo(default=8192),
+ 'amsdu-threshold': KeyInfo(default=8192),
+ 'antenna-gain': KeyInfo(default=0),
+ 'antenna-mode': KeyInfo(),
+ 'area': KeyInfo(default=''),
+ 'arp': KeyInfo(default='enabled'),
+ 'arp-timeout': KeyInfo(default='auto'),
+ 'band': KeyInfo(),
+ 'basic-rates-a/g': KeyInfo(default='6Mbps'),
+ 'basic-rates-b': KeyInfo(default='1Mbps'),
+ 'bridge-mode': KeyInfo(default='enabled'),
+ 'channel-width': KeyInfo(default='20mhz'),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'compression': KeyInfo(default=False),
+ 'country': KeyInfo(default='etsi'),
+ 'default-ap-tx-limit': KeyInfo(default=0),
+ 'default-authentication': KeyInfo(default=True),
+ 'default-client-tx-limit': KeyInfo(default=0),
+ 'default-forwarding': KeyInfo(default=True),
+ 'default-name': KeyInfo(),
+ 'disable-running-check': KeyInfo(default=False),
+ 'disabled': KeyInfo(default=True),
+ 'disconnect-timeout': KeyInfo(default='3s'),
+ 'distance': KeyInfo(default='dynamic'),
+ 'frame-lifetime': KeyInfo(default=0),
+ 'frequency': KeyInfo(),
+ 'frequency-mode': KeyInfo(default='regulatory-domain'),
+ 'frequency-offset': KeyInfo(default=0),
+ 'guard-interval': KeyInfo(default='any'),
+ 'hide-ssid': KeyInfo(default=False),
+ 'ht-basic-mcs': KeyInfo(),
+ 'ht-supported-mcs': KeyInfo(),
+ 'hw-fragmentation-threshold': KeyInfo(default='disabled'),
+ 'hw-protection-mode': KeyInfo(default='none'),
+ 'hw-protection-threshold': KeyInfo(default=0),
+ 'hw-retries': KeyInfo(default=7),
+ 'installation': KeyInfo(default='any'),
+ 'interworking-profile': KeyInfo(default='disabled'),
+ 'keepalive-frames': KeyInfo(default='enabled'),
+ 'l2mtu': KeyInfo(default=1600),
+ 'mac-address': KeyInfo(),
+ 'master-interface': KeyInfo(),
+ 'max-station-count': KeyInfo(default=2007),
+ 'mode': KeyInfo(default='ap-bridge'),
+ 'mtu': KeyInfo(default=1500),
+ 'multicast-buffering': KeyInfo(default='enabled'),
+ 'multicast-helper': KeyInfo(default='default'),
+ 'name': KeyInfo(),
+ 'noise-floor-threshold': KeyInfo(default='default'),
+ 'nv2-cell-radius': KeyInfo(default=30),
+ 'nv2-downlink-ratio': KeyInfo(default=50),
+ 'nv2-mode': KeyInfo(default='dynamic-downlink'),
+ 'nv2-noise-floor-offset': KeyInfo(default='default'),
+ 'nv2-preshared-key': KeyInfo(default=''),
+ 'nv2-qos': KeyInfo(default='default'),
+ 'nv2-queue-count': KeyInfo(default=2),
+ 'nv2-security': KeyInfo(default='disabled'),
+ 'nv2-sync-secret': KeyInfo(default=''),
+ 'on-fail-retry-time': KeyInfo(default='100ms'),
+ 'preamble-mode': KeyInfo(default='both'),
+ 'radio-name': KeyInfo(),
+ 'rate-selection': KeyInfo(default='advanced'),
+ 'rate-set': KeyInfo(default='default'),
+ 'running': KeyInfo(read_only=True),
+ 'rx-chains': KeyInfo(default='0,1'),
+ 'scan-list': KeyInfo(default='default'),
+ 'secondary-frequency': KeyInfo(default=''),
+ 'security-profile': KeyInfo(default='default'),
+ 'skip-dfs-channels': KeyInfo(default='disabled'),
+ 'ssid': KeyInfo(required=True),
+ 'station-bridge-clone-mac': KeyInfo(),
+ 'station-roaming': KeyInfo(default='disabled'),
+ 'supported-rates-a/g': KeyInfo(),
+ 'supported-rates-b': KeyInfo(),
+ 'tdma-period-size': KeyInfo(default=2),
+ 'tx-chains': KeyInfo(),
+ 'tx-power': KeyInfo(default=''),
+ 'tx-power-mode': KeyInfo(default='default'),
+ 'update-stats-interval': KeyInfo(default='disabled'),
+ 'vlan-id': KeyInfo(default=1),
+ 'vlan-mode': KeyInfo(default='no-tag'),
+ 'wds-cost-range': KeyInfo(default='50-150'),
+ 'wds-default-bridge': KeyInfo(default='none'),
+ 'wds-default-cost': KeyInfo(default=100),
+ 'wds-ignore-ssid': KeyInfo(default=False),
+ 'wds-mode': KeyInfo(default='disabled'),
+ 'wireless-protocol': KeyInfo(default='any'),
+ 'wmm-support': KeyInfo(default='disabled'),
+ 'wps-mode': KeyInfo(default='push-button'),
+ },
+ ),
),
('interface', 'wireless', 'align'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'active-mode': KeyInfo(default=True),
- 'audio-max': KeyInfo(default=-20),
- 'audio-min': KeyInfo(default=-100),
- 'audio-monitor': KeyInfo(default='00:00:00:00:00:00'),
- 'filter-mac': KeyInfo(default='00:00:00:00:00:00'),
- 'frame-size': KeyInfo(default=300),
- 'frames-per-second': KeyInfo(default=25),
- 'receive-all': KeyInfo(default=False),
- 'ssid-all': KeyInfo(default=False),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'active-mode': KeyInfo(default=True),
+ 'audio-max': KeyInfo(default=-20),
+ 'audio-min': KeyInfo(default=-100),
+ 'audio-monitor': KeyInfo(default='00:00:00:00:00:00'),
+ 'filter-mac': KeyInfo(default='00:00:00:00:00:00'),
+ 'frame-size': KeyInfo(default=300),
+ 'frames-per-second': KeyInfo(default=25),
+ 'receive-all': KeyInfo(default=False),
+ 'ssid-all': KeyInfo(default=False),
+ },
+ ),
),
('interface', 'wireless', 'cap'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'bridge': KeyInfo(default='none'),
- 'caps-man-addresses': KeyInfo(default=''),
- 'caps-man-certificate-common-names': KeyInfo(default=''),
- 'caps-man-names': KeyInfo(default=''),
- 'certificate': KeyInfo(default='none'),
- 'discovery-interfaces': KeyInfo(default=''),
- 'enabled': KeyInfo(default=False),
- 'interfaces': KeyInfo(default=''),
- 'lock-to-caps-man': KeyInfo(default=False),
- 'static-virtual': KeyInfo(default=False),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'bridge': KeyInfo(default='none'),
+ 'caps-man-addresses': KeyInfo(default=''),
+ 'caps-man-certificate-common-names': KeyInfo(default=''),
+ 'caps-man-names': KeyInfo(default=''),
+ 'certificate': KeyInfo(default='none'),
+ 'discovery-interfaces': KeyInfo(default=''),
+ 'enabled': KeyInfo(default=False),
+ 'interfaces': KeyInfo(default=''),
+ 'lock-to-caps-man': KeyInfo(default=False),
+ 'static-virtual': KeyInfo(default=False),
+ },
+ ),
+ ),
+ ('interface', 'wireless', 'security-profiles'): APIData(
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ 'authentication-types': KeyInfo(),
+ 'disable-pmkid': KeyInfo(default=False),
+ 'disabled': KeyInfo(default=True),
+ 'eap-methods': KeyInfo(),
+ 'group-ciphers': KeyInfo(),
+ 'group-key-update': KeyInfo(default='5m'),
+ 'interim-update': KeyInfo(),
+ 'management-protection': KeyInfo(default='disabled'),
+ 'management-protection-key': KeyInfo(default=''),
+ 'mode': KeyInfo(default='none'),
+ 'mschapv2-password': KeyInfo(default=''),
+ 'mschapv2-username': KeyInfo(default=''),
+ 'name': KeyInfo(),
+ 'radius-called-format': KeyInfo(),
+ 'radius-eap-accounting': KeyInfo(default=False),
+ 'radius-mac-accounting': KeyInfo(default=False),
+ 'radius-mac-authentication': KeyInfo(default=False),
+ 'radius-mac-caching': KeyInfo(default='disabled'),
+ 'radius-mac-format': KeyInfo(default='XX:XX:XX:XX:XX:XX'),
+ 'radius-mac-mode': KeyInfo(default='as-username'),
+ 'static-algo-0': KeyInfo(default='none'),
+ 'static-algo-1': KeyInfo(default='none'),
+ 'static-algo-2': KeyInfo(default='none'),
+ 'static-algo-3': KeyInfo(default='none'),
+ 'static-key-0': KeyInfo(),
+ 'static-key-1': KeyInfo(),
+ 'static-key-2': KeyInfo(),
+ 'static-key-3': KeyInfo(),
+ 'static-sta-private-algo': KeyInfo(default='none'),
+ 'static-sta-private-key': KeyInfo(),
+ 'static-transmit-key': KeyInfo(),
+ 'supplicant-identity': KeyInfo(default='MikroTik'),
+ 'tls-certificate': KeyInfo(default='none'),
+ 'tls-mode': KeyInfo(),
+ 'unicast-ciphers': KeyInfo(),
+ 'wpa-pre-shared-key': KeyInfo(),
+ 'wpa2-pre-shared-key': KeyInfo(),
+ },
+ ),
),
('interface', 'wireless', 'sniffer'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'channel-time': KeyInfo(default='200ms'),
- 'file-limit': KeyInfo(default=10),
- 'file-name': KeyInfo(default=''),
- 'memory-limit': KeyInfo(default=10),
- 'multiple-channels': KeyInfo(default=False),
- 'only-headers': KeyInfo(default=False),
- 'receive-errors': KeyInfo(default=False),
- 'streaming-enabled': KeyInfo(default=False),
- 'streaming-max-rate': KeyInfo(default=0),
- 'streaming-server': KeyInfo(default='0.0.0.0'),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'channel-time': KeyInfo(default='200ms'),
+ 'file-limit': KeyInfo(default=10),
+ 'file-name': KeyInfo(default=''),
+ 'memory-limit': KeyInfo(default=10),
+ 'multiple-channels': KeyInfo(default=False),
+ 'only-headers': KeyInfo(default=False),
+ 'receive-errors': KeyInfo(default=False),
+ 'streaming-enabled': KeyInfo(default=False),
+ 'streaming-max-rate': KeyInfo(default=0),
+ 'streaming-server': KeyInfo(default='0.0.0.0'),
+ },
+ ),
),
('interface', 'wireless', 'snooper'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'channel-time': KeyInfo(default='200ms'),
- 'multiple-channels': KeyInfo(default=True),
- 'receive-errors': KeyInfo(default=False),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'channel-time': KeyInfo(default='200ms'),
+ 'multiple-channels': KeyInfo(default=True),
+ 'receive-errors': KeyInfo(default=False),
+ },
+ ),
+ ),
+ ('iot', 'modbus'): APIData(
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'disabled': KeyInfo(default=True),
+ 'hardware-port': KeyInfo(default='modbus'),
+ 'tcp-port': KeyInfo(default=502),
+ 'timeout': KeyInfo(default=1000),
+ },
+ ),
),
('ip', 'accounting'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'account-local-traffic': KeyInfo(default=False),
- 'enabled': KeyInfo(default=False),
- 'threshold': KeyInfo(default=256),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'account-local-traffic': KeyInfo(default=False),
+ 'enabled': KeyInfo(default=False),
+ 'threshold': KeyInfo(default=256),
+ },
+ ),
),
('ip', 'accounting', 'web-access'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'accessible-via-web': KeyInfo(default=False),
- 'address': KeyInfo(default='0.0.0.0/0'),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'accessible-via-web': KeyInfo(default=False),
+ 'address': KeyInfo(default='0.0.0.0/0'),
+ },
+ ),
),
('ip', 'address'): APIData(
- fully_understood=True,
- primary_keys=('address', 'interface', ),
- fields={
- 'address': KeyInfo(),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'disabled': KeyInfo(default=False),
- 'interface': KeyInfo(),
- 'network': KeyInfo(automatically_computed_from=('address', )),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('address', 'interface', ),
+ fields={
+ 'address': KeyInfo(),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'interface': KeyInfo(),
+ 'network': KeyInfo(automatically_computed_from=('address', )),
+ },
+ ),
),
('ip', 'arp'): APIData(
- fully_understood=True,
- fields={
- 'address': KeyInfo(default='0.0.0.0'),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'disabled': KeyInfo(default=False),
- 'interface': KeyInfo(required=True),
- 'mac-address': KeyInfo(default='00:00:00:00:00:00'),
- 'published': KeyInfo(default=False),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ fields={
+ 'address': KeyInfo(default='0.0.0.0'),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'interface': KeyInfo(required=True),
+ 'mac-address': KeyInfo(default='00:00:00:00:00:00'),
+ 'published': KeyInfo(default=False),
+ },
+ ),
),
('ip', 'cloud'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'ddns-enabled': KeyInfo(default=False),
- 'ddns-update-interval': KeyInfo(default='none'),
- 'update-time': KeyInfo(default=True),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'ddns-enabled': KeyInfo(default=False),
+ 'ddns-update-interval': KeyInfo(default='none'),
+ 'update-time': KeyInfo(default=True),
+ },
+ ),
),
('ip', 'cloud', 'advanced'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'use-local-address': KeyInfo(default=False),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'use-local-address': KeyInfo(default=False),
+ },
+ ),
),
('ip', 'dhcp-client'): APIData(
- fully_understood=True,
- primary_keys=('interface', ),
- fields={
- 'add-default-route': KeyInfo(default=True),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'default-route-distance': KeyInfo(default=1),
- 'dhcp-options': KeyInfo(default='hostname,clientid', can_disable=True, remove_value=''),
- 'disabled': KeyInfo(default=False),
- 'interface': KeyInfo(),
- 'script': KeyInfo(can_disable=True),
- 'use-peer-dns': KeyInfo(default=True),
- 'use-peer-ntp': KeyInfo(default=True),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('interface', ),
+ fields={
+ 'add-default-route': KeyInfo(default=True),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'default-route-distance': KeyInfo(default=1),
+ 'dhcp-options': KeyInfo(default='hostname,clientid', can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'interface': KeyInfo(),
+ 'script': KeyInfo(can_disable=True),
+ 'use-peer-dns': KeyInfo(default=True),
+ 'use-peer-ntp': KeyInfo(default=True),
+ },
+ ),
),
('ip', 'dhcp-server', 'config'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'accounting': KeyInfo(default=True),
- 'interim-update': KeyInfo(default='0s'),
- 'store-leases-disk': KeyInfo(default='5m'),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'accounting': KeyInfo(default=True),
+ 'interim-update': KeyInfo(default='0s'),
+ 'store-leases-disk': KeyInfo(default='5m'),
+ },
+ ),
),
('ip', 'dhcp-server', 'lease'): APIData(
- fully_understood=True,
- primary_keys=('server', 'address', ),
- fields={
- 'address': KeyInfo(),
- 'address-lists': KeyInfo(default=''),
- 'always-broadcast': KeyInfo(),
- 'client-id': KeyInfo(can_disable=True, remove_value=''),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'dhcp-option': KeyInfo(default=''),
- 'disabled': KeyInfo(default=False),
- 'insert-queue-before': KeyInfo(can_disable=True),
- 'mac-address': KeyInfo(can_disable=True, remove_value=''),
- 'server': KeyInfo(absent_value='all'),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('server', 'address', ),
+ fields={
+ 'address': KeyInfo(),
+ 'address-lists': KeyInfo(default=''),
+ 'always-broadcast': KeyInfo(),
+ 'client-id': KeyInfo(can_disable=True, remove_value=''),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'dhcp-option': KeyInfo(default=''),
+ 'disabled': KeyInfo(default=False),
+ 'insert-queue-before': KeyInfo(can_disable=True),
+ 'mac-address': KeyInfo(can_disable=True, remove_value=''),
+ 'server': KeyInfo(absent_value='all'),
+ },
+ ),
),
('ip', 'dhcp-server', 'network'): APIData(
- fully_understood=True,
- primary_keys=('address', ),
- fields={
- 'address': KeyInfo(),
- 'boot-file-name': KeyInfo(default=''),
- 'caps-manager': KeyInfo(default=''),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'dhcp-option': KeyInfo(default=''),
- 'dhcp-option-set': KeyInfo(default=''),
- 'dns-none': KeyInfo(default=False),
- 'dns-server': KeyInfo(default=''),
- 'domain': KeyInfo(default=''),
- 'gateway': KeyInfo(default=''),
- 'netmask': KeyInfo(can_disable=True, remove_value=0),
- 'next-server': KeyInfo(can_disable=True),
- 'ntp-server': KeyInfo(default=''),
- 'wins-server': KeyInfo(default=''),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('address', ),
+ fields={
+ 'address': KeyInfo(),
+ 'boot-file-name': KeyInfo(default=''),
+ 'caps-manager': KeyInfo(default=''),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'dhcp-option': KeyInfo(default=''),
+ 'dhcp-option-set': KeyInfo(default=''),
+ 'dns-none': KeyInfo(default=False),
+ 'dns-server': KeyInfo(default=''),
+ 'domain': KeyInfo(default=''),
+ 'gateway': KeyInfo(default=''),
+ 'netmask': KeyInfo(can_disable=True, remove_value=0),
+ 'next-server': KeyInfo(can_disable=True),
+ 'ntp-server': KeyInfo(default=''),
+ 'wins-server': KeyInfo(default=''),
+ },
+ ),
+ ),
+ ('ip', 'dhcp-server', 'option'): APIData(
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name',),
+ fields={
+ 'code': KeyInfo(required=True),
+ 'name': KeyInfo(),
+ 'value': KeyInfo(default=''),
+ 'force': KeyInfo(),
+ },
+ ),
+ ),
+ ('ip', 'dhcp-server', 'option', 'sets'): APIData(
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name',),
+ fields={
+ 'name': KeyInfo(required=True),
+ 'options': KeyInfo(),
+ },
+ ),
),
('ip', 'dns'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'allow-remote-requests': KeyInfo(),
- 'cache-max-ttl': KeyInfo(default='1w'),
- 'cache-size': KeyInfo(default='2048KiB'),
- 'max-concurrent-queries': KeyInfo(default=100),
- 'max-concurrent-tcp-sessions': KeyInfo(default=20),
- 'max-udp-packet-size': KeyInfo(default=4096),
- 'query-server-timeout': KeyInfo(default='2s'),
- 'query-total-timeout': KeyInfo(default='10s'),
- 'servers': KeyInfo(default=''),
- 'use-doh-server': KeyInfo(default=''),
- 'verify-doh-cert': KeyInfo(default=False),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ versioned_fields=[
+ ([('7.8', '>=')], 'doh-max-concurrent-queries', KeyInfo(default=50)),
+ ([('7.8', '>=')], 'doh-max-server-connections', KeyInfo(default=5)),
+ ([('7.8', '>=')], 'doh-timeout', KeyInfo(default='5s')),
+ ],
+ fields={
+ 'allow-remote-requests': KeyInfo(),
+ 'cache-max-ttl': KeyInfo(default='1w'),
+ 'cache-size': KeyInfo(default='2048KiB'),
+ 'max-concurrent-queries': KeyInfo(default=100),
+ 'max-concurrent-tcp-sessions': KeyInfo(default=20),
+ 'max-udp-packet-size': KeyInfo(default=4096),
+ 'query-server-timeout': KeyInfo(default='2s'),
+ 'query-total-timeout': KeyInfo(default='10s'),
+ 'servers': KeyInfo(default=''),
+ 'use-doh-server': KeyInfo(default=''),
+ 'verify-doh-cert': KeyInfo(default=False),
+ },
+ ),
),
('ip', 'dns', 'static'): APIData(
- fully_understood=True,
- required_one_of=[['name', 'regexp']],
- mutually_exclusive=[['name', 'regexp']],
- fields={
- 'address': KeyInfo(),
- 'cname': KeyInfo(),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'disabled': KeyInfo(default=False),
- 'forward-to': KeyInfo(),
- 'mx-exchange': KeyInfo(),
- 'mx-preference': KeyInfo(),
- 'name': KeyInfo(),
- 'ns': KeyInfo(),
- 'regexp': KeyInfo(),
- 'srv-port': KeyInfo(),
- 'srv-priority': KeyInfo(),
- 'srv-target': KeyInfo(),
- 'srv-weight': KeyInfo(),
- 'text': KeyInfo(),
- 'ttl': KeyInfo(default='1d'),
- 'type': KeyInfo(),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ required_one_of=[['name', 'regexp']],
+ mutually_exclusive=[['name', 'regexp']],
+ versioned_fields=[
+ ([('7.5', '>=')], 'address-list', KeyInfo()),
+ ([('7.5', '>=')], 'match-subdomain', KeyInfo(default=False)),
+ ],
+ fields={
+ 'address': KeyInfo(),
+ 'cname': KeyInfo(),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'forward-to': KeyInfo(),
+ 'mx-exchange': KeyInfo(),
+ 'mx-preference': KeyInfo(),
+ 'name': KeyInfo(),
+ 'ns': KeyInfo(),
+ 'regexp': KeyInfo(),
+ 'srv-port': KeyInfo(),
+ 'srv-priority': KeyInfo(),
+ 'srv-target': KeyInfo(),
+ 'srv-weight': KeyInfo(),
+ 'text': KeyInfo(),
+ 'ttl': KeyInfo(default='1d'),
+ 'type': KeyInfo(),
+ },
+ ),
),
('ip', 'firewall', 'address-list'): APIData(
- fully_understood=True,
- primary_keys=('address', 'list', ),
- fields={
- 'address': KeyInfo(),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'disabled': KeyInfo(default=False),
- 'list': KeyInfo(),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('address', 'list', ),
+ fields={
+ 'address': KeyInfo(),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'list': KeyInfo(),
+ },
+ ),
),
('ip', 'firewall', 'filter'): APIData(
- fully_understood=True,
- stratify_keys=('chain', ),
- fields={
- 'action': KeyInfo(),
- 'chain': KeyInfo(),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'connection-bytes': KeyInfo(can_disable=True),
- 'connection-limit': KeyInfo(can_disable=True),
- 'connection-mark': KeyInfo(can_disable=True),
- 'connection-nat-state': KeyInfo(can_disable=True),
- 'connection-rate': KeyInfo(can_disable=True),
- 'connection-state': KeyInfo(can_disable=True),
- 'connection-type': KeyInfo(can_disable=True),
- 'content': KeyInfo(can_disable=True),
- 'disabled': KeyInfo(),
- 'dscp': KeyInfo(can_disable=True),
- 'dst-address': KeyInfo(can_disable=True),
- 'dst-address-list': KeyInfo(can_disable=True),
- 'dst-address-type': KeyInfo(can_disable=True),
- 'dst-limit': KeyInfo(can_disable=True),
- 'dst-port': KeyInfo(can_disable=True),
- 'fragment': KeyInfo(can_disable=True),
- 'hotspot': KeyInfo(can_disable=True),
- 'hw-offload': KeyInfo(can_disable=True),
- 'icmp-options': KeyInfo(can_disable=True),
- 'in-bridge-port': KeyInfo(can_disable=True),
- 'in-bridge-port-list': KeyInfo(can_disable=True),
- 'in-interface': KeyInfo(can_disable=True),
- 'in-interface-list': KeyInfo(can_disable=True),
- 'ingress-priority': KeyInfo(can_disable=True),
- 'ipsec-policy': KeyInfo(can_disable=True),
- 'ipv4-options': KeyInfo(can_disable=True),
- 'jump-target': KeyInfo(),
- 'layer7-protocol': KeyInfo(can_disable=True),
- 'limit': KeyInfo(can_disable=True),
- 'log': KeyInfo(),
- 'log-prefix': KeyInfo(),
- 'nth': KeyInfo(can_disable=True),
- 'out-bridge-port': KeyInfo(can_disable=True),
- 'out-bridge-port-list': KeyInfo(can_disable=True),
- 'out-interface': KeyInfo(can_disable=True),
- 'out-interface-list': KeyInfo(can_disable=True),
- 'p2p': KeyInfo(can_disable=True),
- 'packet-mark': KeyInfo(can_disable=True),
- 'packet-size': KeyInfo(can_disable=True),
- 'per-connection-classifier': KeyInfo(can_disable=True),
- 'port': KeyInfo(can_disable=True),
- 'priority': KeyInfo(can_disable=True),
- 'protocol': KeyInfo(can_disable=True),
- 'psd': KeyInfo(can_disable=True),
- 'random': KeyInfo(can_disable=True),
- 'reject-with': KeyInfo(),
- 'routing-mark': KeyInfo(can_disable=True),
- 'routing-table': KeyInfo(can_disable=True),
- 'src-address': KeyInfo(can_disable=True),
- 'src-address-list': KeyInfo(can_disable=True),
- 'src-address-type': KeyInfo(can_disable=True),
- 'src-mac-address': KeyInfo(can_disable=True),
- 'src-port': KeyInfo(can_disable=True),
- 'tcp-flags': KeyInfo(can_disable=True),
- 'tcp-mss': KeyInfo(can_disable=True),
- 'time': KeyInfo(can_disable=True),
- 'tls-host': KeyInfo(can_disable=True),
- 'ttl': KeyInfo(can_disable=True),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ stratify_keys=('chain', ),
+ fields={
+ 'action': KeyInfo(),
+ 'address-list': KeyInfo(can_disable=True),
+ 'address-list-timeout': KeyInfo(can_disable=True),
+ 'chain': KeyInfo(),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'connection-bytes': KeyInfo(can_disable=True),
+ 'connection-limit': KeyInfo(can_disable=True),
+ 'connection-mark': KeyInfo(can_disable=True),
+ 'connection-nat-state': KeyInfo(can_disable=True),
+ 'connection-rate': KeyInfo(can_disable=True),
+ 'connection-state': KeyInfo(can_disable=True),
+ 'connection-type': KeyInfo(can_disable=True),
+ 'content': KeyInfo(can_disable=True),
+ 'disabled': KeyInfo(default=False),
+ 'dscp': KeyInfo(can_disable=True),
+ 'dst-address': KeyInfo(can_disable=True),
+ 'dst-address-list': KeyInfo(can_disable=True),
+ 'dst-address-type': KeyInfo(can_disable=True),
+ 'dst-limit': KeyInfo(can_disable=True),
+ 'dst-port': KeyInfo(can_disable=True),
+ 'fragment': KeyInfo(can_disable=True),
+ 'hotspot': KeyInfo(can_disable=True),
+ 'hw-offload': KeyInfo(can_disable=True),
+ 'icmp-options': KeyInfo(can_disable=True),
+ 'in-bridge-port': KeyInfo(can_disable=True),
+ 'in-bridge-port-list': KeyInfo(can_disable=True),
+ 'in-interface': KeyInfo(can_disable=True),
+ 'in-interface-list': KeyInfo(can_disable=True),
+ 'ingress-priority': KeyInfo(can_disable=True),
+ 'ipsec-policy': KeyInfo(can_disable=True),
+ 'ipv4-options': KeyInfo(can_disable=True),
+ 'jump-target': KeyInfo(can_disable=True),
+ 'layer7-protocol': KeyInfo(can_disable=True),
+ 'limit': KeyInfo(can_disable=True),
+ 'log': KeyInfo(can_disable=True),
+ 'log-prefix': KeyInfo(can_disable=True),
+ 'nth': KeyInfo(can_disable=True),
+ 'out-bridge-port': KeyInfo(can_disable=True),
+ 'out-bridge-port-list': KeyInfo(can_disable=True),
+ 'out-interface': KeyInfo(can_disable=True),
+ 'out-interface-list': KeyInfo(can_disable=True),
+ 'p2p': KeyInfo(can_disable=True),
+ 'packet-mark': KeyInfo(can_disable=True),
+ 'packet-size': KeyInfo(can_disable=True),
+ 'per-connection-classifier': KeyInfo(can_disable=True),
+ 'port': KeyInfo(can_disable=True),
+ 'priority': KeyInfo(can_disable=True),
+ 'protocol': KeyInfo(can_disable=True),
+ 'psd': KeyInfo(can_disable=True),
+ 'random': KeyInfo(can_disable=True),
+ 'realm': KeyInfo(can_disable=True),
+ 'reject-with': KeyInfo(can_disable=True),
+ 'routing-mark': KeyInfo(can_disable=True),
+ 'routing-table': KeyInfo(can_disable=True),
+ 'src-address': KeyInfo(can_disable=True),
+ 'src-address-list': KeyInfo(can_disable=True),
+ 'src-address-type': KeyInfo(can_disable=True),
+ 'src-mac-address': KeyInfo(can_disable=True),
+ 'src-port': KeyInfo(can_disable=True),
+ 'tcp-flags': KeyInfo(can_disable=True),
+ 'tcp-mss': KeyInfo(can_disable=True),
+ 'time': KeyInfo(can_disable=True),
+ 'tls-host': KeyInfo(can_disable=True),
+ 'ttl': KeyInfo(can_disable=True),
+ },
+ ),
),
('ip', 'firewall', 'mangle'): APIData(
- fully_understood=True,
- stratify_keys=('chain', ),
- fields={
- 'action': KeyInfo(),
- 'chain': KeyInfo(),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'connection-bytes': KeyInfo(can_disable=True),
- 'connection-limit': KeyInfo(can_disable=True),
- 'connection-mark': KeyInfo(can_disable=True),
- 'connection-nat-state': KeyInfo(can_disable=True),
- 'connection-rate': KeyInfo(can_disable=True),
- 'connection-state': KeyInfo(can_disable=True),
- 'connection-type': KeyInfo(can_disable=True),
- 'content': KeyInfo(can_disable=True),
- 'disabled': KeyInfo(),
- 'dscp': KeyInfo(can_disable=True),
- 'dst-address': KeyInfo(can_disable=True),
- 'dst-address-list': KeyInfo(can_disable=True),
- 'dst-address-type': KeyInfo(can_disable=True),
- 'dst-limit': KeyInfo(can_disable=True),
- 'dst-port': KeyInfo(can_disable=True),
- 'fragment': KeyInfo(can_disable=True),
- 'hotspot': KeyInfo(can_disable=True),
- 'icmp-options': KeyInfo(can_disable=True),
- 'in-bridge-port': KeyInfo(can_disable=True),
- 'in-bridge-port-list': KeyInfo(can_disable=True),
- 'in-interface': KeyInfo(can_disable=True),
- 'in-interface-list': KeyInfo(can_disable=True),
- 'ingress-priority': KeyInfo(can_disable=True),
- 'ipsec-policy': KeyInfo(can_disable=True),
- 'ipv4-options': KeyInfo(can_disable=True),
- 'jump-target': KeyInfo(),
- 'layer7-protocol': KeyInfo(can_disable=True),
- 'limit': KeyInfo(can_disable=True),
- 'log': KeyInfo(),
- 'log-prefix': KeyInfo(),
- 'new-connection-mark': KeyInfo(can_disable=True),
- 'new-dscp': KeyInfo(can_disable=True),
- 'new-mss': KeyInfo(can_disable=True),
- 'new-packet-mark': KeyInfo(can_disable=True),
- 'new-priority': KeyInfo(can_disable=True),
- 'new-routing-mark': KeyInfo(can_disable=True),
- 'new-ttl': KeyInfo(can_disable=True),
- 'nth': KeyInfo(can_disable=True),
- 'out-bridge-port': KeyInfo(can_disable=True),
- 'out-bridge-port-list': KeyInfo(can_disable=True),
- 'out-interface': KeyInfo(can_disable=True),
- 'out-interface-list': KeyInfo(can_disable=True),
- 'p2p': KeyInfo(can_disable=True),
- 'packet-mark': KeyInfo(can_disable=True),
- 'packet-size': KeyInfo(can_disable=True),
- 'passthrough': KeyInfo(can_disable=True),
- 'per-connection-classifier': KeyInfo(can_disable=True),
- 'port': KeyInfo(can_disable=True),
- 'priority': KeyInfo(can_disable=True),
- 'protocol': KeyInfo(can_disable=True),
- 'psd': KeyInfo(can_disable=True),
- 'random': KeyInfo(can_disable=True),
- 'route-dst': KeyInfo(can_disable=True),
- 'routing-mark': KeyInfo(can_disable=True),
- 'routing-table': KeyInfo(can_disable=True),
- 'sniff-id': KeyInfo(can_disable=True),
- 'sniff-target': KeyInfo(can_disable=True),
- 'sniff-target-port': KeyInfo(can_disable=True),
- 'src-address': KeyInfo(can_disable=True),
- 'src-address-list': KeyInfo(can_disable=True),
- 'src-address-type': KeyInfo(can_disable=True),
- 'src-mac-address': KeyInfo(can_disable=True),
- 'src-port': KeyInfo(can_disable=True),
- 'tcp-flags': KeyInfo(can_disable=True),
- 'tcp-mss': KeyInfo(can_disable=True),
- 'time': KeyInfo(can_disable=True),
- 'tls-host': KeyInfo(can_disable=True),
- 'ttl': KeyInfo(can_disable=True),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ stratify_keys=('chain', ),
+ fields={
+ 'action': KeyInfo(),
+ 'address-list': KeyInfo(can_disable=True),
+ 'address-list-timeout': KeyInfo(can_disable=True),
+ 'chain': KeyInfo(),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'connection-bytes': KeyInfo(can_disable=True),
+ 'connection-limit': KeyInfo(can_disable=True),
+ 'connection-mark': KeyInfo(can_disable=True),
+ 'connection-nat-state': KeyInfo(can_disable=True),
+ 'connection-rate': KeyInfo(can_disable=True),
+ 'connection-state': KeyInfo(can_disable=True),
+ 'connection-type': KeyInfo(can_disable=True),
+ 'content': KeyInfo(can_disable=True),
+ 'disabled': KeyInfo(default=False),
+ 'dscp': KeyInfo(can_disable=True),
+ 'dst-address': KeyInfo(can_disable=True),
+ 'dst-address-list': KeyInfo(can_disable=True),
+ 'dst-address-type': KeyInfo(can_disable=True),
+ 'dst-limit': KeyInfo(can_disable=True),
+ 'dst-port': KeyInfo(can_disable=True),
+ 'fragment': KeyInfo(can_disable=True),
+ 'hotspot': KeyInfo(can_disable=True),
+ 'icmp-options': KeyInfo(can_disable=True),
+ 'in-bridge-port': KeyInfo(can_disable=True),
+ 'in-bridge-port-list': KeyInfo(can_disable=True),
+ 'in-interface': KeyInfo(can_disable=True),
+ 'in-interface-list': KeyInfo(can_disable=True),
+ 'ingress-priority': KeyInfo(can_disable=True),
+ 'ipsec-policy': KeyInfo(can_disable=True),
+ 'ipv4-options': KeyInfo(can_disable=True),
+ 'jump-target': KeyInfo(can_disable=True),
+ 'layer7-protocol': KeyInfo(can_disable=True),
+ 'limit': KeyInfo(can_disable=True),
+ 'log': KeyInfo(can_disable=True),
+ 'log-prefix': KeyInfo(can_disable=True),
+ 'new-connection-mark': KeyInfo(can_disable=True),
+ 'new-dscp': KeyInfo(can_disable=True),
+ 'new-mss': KeyInfo(can_disable=True),
+ 'new-packet-mark': KeyInfo(can_disable=True),
+ 'new-priority': KeyInfo(can_disable=True),
+ 'new-routing-mark': KeyInfo(can_disable=True),
+ 'new-ttl': KeyInfo(can_disable=True),
+ 'nth': KeyInfo(can_disable=True),
+ 'out-bridge-port': KeyInfo(can_disable=True),
+ 'out-bridge-port-list': KeyInfo(can_disable=True),
+ 'out-interface': KeyInfo(can_disable=True),
+ 'out-interface-list': KeyInfo(can_disable=True),
+ 'p2p': KeyInfo(can_disable=True),
+ 'packet-mark': KeyInfo(can_disable=True),
+ 'packet-size': KeyInfo(can_disable=True),
+ 'passthrough': KeyInfo(can_disable=True),
+ 'per-connection-classifier': KeyInfo(can_disable=True),
+ 'port': KeyInfo(can_disable=True),
+ 'priority': KeyInfo(can_disable=True),
+ 'protocol': KeyInfo(can_disable=True),
+ 'psd': KeyInfo(can_disable=True),
+ 'random': KeyInfo(can_disable=True),
+ 'realm': KeyInfo(can_disable=True),
+ 'route-dst': KeyInfo(can_disable=True),
+ 'routing-mark': KeyInfo(can_disable=True),
+ 'routing-table': KeyInfo(can_disable=True),
+ 'sniff-id': KeyInfo(can_disable=True),
+ 'sniff-target': KeyInfo(can_disable=True),
+ 'sniff-target-port': KeyInfo(can_disable=True),
+ 'src-address': KeyInfo(can_disable=True),
+ 'src-address-list': KeyInfo(can_disable=True),
+ 'src-address-type': KeyInfo(can_disable=True),
+ 'src-mac-address': KeyInfo(can_disable=True),
+ 'src-port': KeyInfo(can_disable=True),
+ 'tcp-flags': KeyInfo(can_disable=True),
+ 'tcp-mss': KeyInfo(can_disable=True),
+ 'time': KeyInfo(can_disable=True),
+ 'tls-host': KeyInfo(can_disable=True),
+ 'ttl': KeyInfo(can_disable=True),
+ },
+ ),
),
('ip', 'firewall', 'nat'): APIData(
- fully_understood=True,
- stratify_keys=('chain', ),
- fields={
- 'action': KeyInfo(),
- 'address-list': KeyInfo(),
- 'address-list-timeout': KeyInfo(),
- 'chain': KeyInfo(),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'connection-bytes': KeyInfo(can_disable=True),
- 'connection-limit': KeyInfo(can_disable=True),
- 'connection-mark': KeyInfo(can_disable=True),
- 'connection-rate': KeyInfo(can_disable=True),
- 'connection-type': KeyInfo(can_disable=True),
- 'content': KeyInfo(can_disable=True),
- 'disabled': KeyInfo(),
- 'dscp': KeyInfo(can_disable=True),
- 'dst-address': KeyInfo(can_disable=True),
- 'dst-address-list': KeyInfo(can_disable=True),
- 'dst-address-type': KeyInfo(can_disable=True),
- 'dst-limit': KeyInfo(can_disable=True),
- 'dst-port': KeyInfo(can_disable=True),
- 'fragment': KeyInfo(can_disable=True),
- 'hotspot': KeyInfo(can_disable=True),
- 'icmp-options': KeyInfo(can_disable=True),
- 'in-bridge-port': KeyInfo(can_disable=True),
- 'in-bridge-port-list': KeyInfo(can_disable=True),
- 'in-interface': KeyInfo(can_disable=True),
- 'in-interface-list': KeyInfo(can_disable=True),
- 'ingress-priority': KeyInfo(can_disable=True),
- 'ipsec-policy': KeyInfo(can_disable=True),
- 'ipv4-options': KeyInfo(can_disable=True),
- 'jump-target': KeyInfo(),
- 'layer7-protocol': KeyInfo(can_disable=True),
- 'limit': KeyInfo(can_disable=True),
- 'log': KeyInfo(),
- 'log-prefix': KeyInfo(),
- 'nth': KeyInfo(can_disable=True),
- 'out-bridge-port': KeyInfo(can_disable=True),
- 'out-bridge-port-list': KeyInfo(can_disable=True),
- 'out-interface': KeyInfo(can_disable=True),
- 'out-interface-list': KeyInfo(can_disable=True),
- 'packet-mark': KeyInfo(can_disable=True),
- 'packet-size': KeyInfo(can_disable=True),
- 'per-connection-classifier': KeyInfo(can_disable=True),
- 'port': KeyInfo(can_disable=True),
- 'priority': KeyInfo(can_disable=True),
- 'protocol': KeyInfo(can_disable=True),
- 'psd': KeyInfo(can_disable=True),
- 'random': KeyInfo(can_disable=True),
- 'realm': KeyInfo(can_disable=True),
- 'routing-mark': KeyInfo(can_disable=True),
- 'same-not-by-dst': KeyInfo(),
- 'src-address': KeyInfo(can_disable=True),
- 'src-address-list': KeyInfo(can_disable=True),
- 'src-address-type': KeyInfo(can_disable=True),
- 'src-mac-address': KeyInfo(can_disable=True),
- 'src-port': KeyInfo(can_disable=True),
- 'tcp-mss': KeyInfo(can_disable=True),
- 'time': KeyInfo(can_disable=True),
- 'tls-host': KeyInfo(can_disable=True),
- 'to-addresses': KeyInfo(can_disable=True),
- 'to-ports': KeyInfo(can_disable=True),
- 'ttl': KeyInfo(can_disable=True),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ stratify_keys=('chain', ),
+ fields={
+ 'action': KeyInfo(),
+ 'address-list': KeyInfo(can_disable=True),
+ 'address-list-timeout': KeyInfo(can_disable=True),
+ 'chain': KeyInfo(),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'connection-bytes': KeyInfo(can_disable=True),
+ 'connection-limit': KeyInfo(can_disable=True),
+ 'connection-mark': KeyInfo(can_disable=True),
+ 'connection-rate': KeyInfo(can_disable=True),
+ 'connection-type': KeyInfo(can_disable=True),
+ 'content': KeyInfo(can_disable=True),
+ 'disabled': KeyInfo(default=False),
+ 'dscp': KeyInfo(can_disable=True),
+ 'dst-address': KeyInfo(can_disable=True),
+ 'dst-address-list': KeyInfo(can_disable=True),
+ 'dst-address-type': KeyInfo(can_disable=True),
+ 'dst-limit': KeyInfo(can_disable=True),
+ 'dst-port': KeyInfo(can_disable=True),
+ 'fragment': KeyInfo(can_disable=True),
+ 'hotspot': KeyInfo(can_disable=True),
+ 'icmp-options': KeyInfo(can_disable=True),
+ 'in-bridge-port': KeyInfo(can_disable=True),
+ 'in-bridge-port-list': KeyInfo(can_disable=True),
+ 'in-interface': KeyInfo(can_disable=True),
+ 'in-interface-list': KeyInfo(can_disable=True),
+ 'ingress-priority': KeyInfo(can_disable=True),
+ 'ipsec-policy': KeyInfo(can_disable=True),
+ 'ipv4-options': KeyInfo(can_disable=True),
+ 'jump-target': KeyInfo(can_disable=True),
+ 'layer7-protocol': KeyInfo(can_disable=True),
+ 'limit': KeyInfo(can_disable=True),
+ 'log': KeyInfo(can_disable=True),
+ 'log-prefix': KeyInfo(can_disable=True),
+ 'nth': KeyInfo(can_disable=True),
+ 'out-bridge-port': KeyInfo(can_disable=True),
+ 'out-bridge-port-list': KeyInfo(can_disable=True),
+ 'out-interface': KeyInfo(can_disable=True),
+ 'out-interface-list': KeyInfo(can_disable=True),
+ 'packet-mark': KeyInfo(can_disable=True),
+ 'packet-size': KeyInfo(can_disable=True),
+ 'per-connection-classifier': KeyInfo(can_disable=True),
+ 'port': KeyInfo(can_disable=True),
+ 'priority': KeyInfo(can_disable=True),
+ 'protocol': KeyInfo(can_disable=True),
+ 'psd': KeyInfo(can_disable=True),
+ 'random': KeyInfo(can_disable=True),
+ 'randomise-ports': KeyInfo(can_disable=True),
+ 'realm': KeyInfo(can_disable=True),
+ 'routing-mark': KeyInfo(can_disable=True),
+ 'same-not-by-dst': KeyInfo(can_disable=True),
+ 'src-address': KeyInfo(can_disable=True),
+ 'src-address-list': KeyInfo(can_disable=True),
+ 'src-address-type': KeyInfo(can_disable=True),
+ 'src-mac-address': KeyInfo(can_disable=True),
+ 'src-port': KeyInfo(can_disable=True),
+ 'tcp-mss': KeyInfo(can_disable=True),
+ 'time': KeyInfo(can_disable=True),
+ 'tls-host': KeyInfo(can_disable=True),
+ 'to-addresses': KeyInfo(can_disable=True),
+ 'to-ports': KeyInfo(can_disable=True),
+ 'ttl': KeyInfo(can_disable=True),
+ },
+ ),
),
('ip', 'firewall', 'raw'): APIData(
- fully_understood=True,
- stratify_keys=('chain',),
- fields={
- 'action': KeyInfo(),
- 'address-list': KeyInfo(),
- 'address-list-timeout': KeyInfo(),
- 'chain': KeyInfo(),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'content': KeyInfo(can_disable=True),
- 'disabled': KeyInfo(),
- 'dscp': KeyInfo(can_disable=True),
- 'dst-address': KeyInfo(can_disable=True),
- 'dst-address-list': KeyInfo(can_disable=True),
- 'dst-address-type': KeyInfo(can_disable=True),
- 'dst-limit': KeyInfo(can_disable=True),
- 'dst-port': KeyInfo(can_disable=True),
- 'fragment': KeyInfo(can_disable=True),
- 'hotspot': KeyInfo(can_disable=True),
- 'icmp-options': KeyInfo(can_disable=True),
- 'in-bridge-port': KeyInfo(can_disable=True),
- 'in-bridge-port-list': KeyInfo(can_disable=True),
- 'in-interface': KeyInfo(can_disable=True),
- 'in-interface-list': KeyInfo(can_disable=True),
- 'ingress-priority': KeyInfo(can_disable=True),
- 'ipsec-policy': KeyInfo(can_disable=True),
- 'ipv4-options': KeyInfo(can_disable=True),
- 'jump-target': KeyInfo(),
- 'limit': KeyInfo(can_disable=True),
- 'log': KeyInfo(),
- 'log-prefix': KeyInfo(),
- 'nth': KeyInfo(can_disable=True),
- 'out-bridge-port': KeyInfo(can_disable=True),
- 'out-bridge-port-list': KeyInfo(can_disable=True),
- 'out-interface': KeyInfo(can_disable=True),
- 'out-interface-list': KeyInfo(can_disable=True),
- 'packet-mark': KeyInfo(can_disable=True),
- 'packet-size': KeyInfo(can_disable=True),
- 'per-connection-classifier': KeyInfo(can_disable=True),
- 'port': KeyInfo(can_disable=True),
- 'priority': KeyInfo(can_disable=True),
- 'protocol': KeyInfo(can_disable=True),
- 'psd': KeyInfo(can_disable=True),
- 'random': KeyInfo(can_disable=True),
- 'src-address': KeyInfo(can_disable=True),
- 'src-address-list': KeyInfo(can_disable=True),
- 'src-address-type': KeyInfo(can_disable=True),
- 'src-mac-address': KeyInfo(can_disable=True),
- 'src-port': KeyInfo(can_disable=True),
- 'tcp-flags': KeyInfo(can_disable=True),
- 'tcp-mss': KeyInfo(can_disable=True),
- 'time': KeyInfo(can_disable=True),
- 'tls-host': KeyInfo(can_disable=True),
- 'ttl': KeyInfo(can_disable=True),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ stratify_keys=('chain',),
+ fields={
+ 'action': KeyInfo(),
+ 'address-list': KeyInfo(can_disable=True),
+ 'address-list-timeout': KeyInfo(can_disable=True),
+ 'chain': KeyInfo(),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'content': KeyInfo(can_disable=True),
+ 'disabled': KeyInfo(default=False),
+ 'dscp': KeyInfo(can_disable=True),
+ 'dst-address': KeyInfo(can_disable=True),
+ 'dst-address-list': KeyInfo(can_disable=True),
+ 'dst-address-type': KeyInfo(can_disable=True),
+ 'dst-limit': KeyInfo(can_disable=True),
+ 'dst-port': KeyInfo(can_disable=True),
+ 'fragment': KeyInfo(can_disable=True),
+ 'hotspot': KeyInfo(can_disable=True),
+ 'icmp-options': KeyInfo(can_disable=True),
+ 'in-bridge-port': KeyInfo(can_disable=True),
+ 'in-bridge-port-list': KeyInfo(can_disable=True),
+ 'in-interface': KeyInfo(can_disable=True),
+ 'in-interface-list': KeyInfo(can_disable=True),
+ 'ingress-priority': KeyInfo(can_disable=True),
+ 'ipsec-policy': KeyInfo(can_disable=True),
+ 'ipv4-options': KeyInfo(can_disable=True),
+ 'jump-target': KeyInfo(can_disable=True),
+ 'limit': KeyInfo(can_disable=True),
+ 'log': KeyInfo(can_disable=True),
+ 'log-prefix': KeyInfo(can_disable=True),
+ 'nth': KeyInfo(can_disable=True),
+ 'out-bridge-port': KeyInfo(can_disable=True),
+ 'out-bridge-port-list': KeyInfo(can_disable=True),
+ 'out-interface': KeyInfo(can_disable=True),
+ 'out-interface-list': KeyInfo(can_disable=True),
+ 'packet-mark': KeyInfo(can_disable=True),
+ 'packet-size': KeyInfo(can_disable=True),
+ 'per-connection-classifier': KeyInfo(can_disable=True),
+ 'port': KeyInfo(can_disable=True),
+ 'priority': KeyInfo(can_disable=True),
+ 'protocol': KeyInfo(can_disable=True),
+ 'psd': KeyInfo(can_disable=True),
+ 'random': KeyInfo(can_disable=True),
+ 'src-address': KeyInfo(can_disable=True),
+ 'src-address-list': KeyInfo(can_disable=True),
+ 'src-address-type': KeyInfo(can_disable=True),
+ 'src-mac-address': KeyInfo(can_disable=True),
+ 'src-port': KeyInfo(can_disable=True),
+ 'tcp-flags': KeyInfo(can_disable=True),
+ 'tcp-mss': KeyInfo(can_disable=True),
+ 'time': KeyInfo(can_disable=True),
+ 'tls-host': KeyInfo(can_disable=True),
+ 'ttl': KeyInfo(can_disable=True),
+ },
+ ),
),
('ip', 'hotspot', 'user'): APIData(
- unknown_mechanism=True,
- # primary_keys=('default', ),
- fields={
- 'default': KeyInfo(),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'disabled': KeyInfo(),
- 'name': KeyInfo(),
- },
+ unversioned=VersionedAPIData(
+ unknown_mechanism=True,
+ # primary_keys=('default', ),
+ fields={
+ 'default': KeyInfo(),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(),
+ 'name': KeyInfo(),
+ },
+ ),
),
('ip', 'ipsec', 'settings'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'accounting': KeyInfo(default=True),
- 'interim-update': KeyInfo(default='0s'),
- 'xauth-use-radius': KeyInfo(default=False),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'accounting': KeyInfo(default=True),
+ 'interim-update': KeyInfo(default='0s'),
+ 'xauth-use-radius': KeyInfo(default=False),
+ },
+ ),
),
('ip', 'proxy'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'always-from-cache': KeyInfo(default=False),
- 'anonymous': KeyInfo(default=False),
- 'cache-administrator': KeyInfo(default='webmaster'),
- 'cache-hit-dscp': KeyInfo(default=4),
- 'cache-on-disk': KeyInfo(default=False),
- 'cache-path': KeyInfo(default='web-proxy'),
- 'enabled': KeyInfo(default=False),
- 'max-cache-object-size': KeyInfo(default='2048KiB'),
- 'max-cache-size': KeyInfo(default='unlimited'),
- 'max-client-connections': KeyInfo(default=600),
- 'max-fresh-time': KeyInfo(default='3d'),
- 'max-server-connections': KeyInfo(default=600),
- 'parent-proxy': KeyInfo(default='::'),
- 'parent-proxy-port': KeyInfo(default=0),
- 'port': KeyInfo(default=8080),
- 'serialize-connections': KeyInfo(default=False),
- 'src-address': KeyInfo(default='::'),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'always-from-cache': KeyInfo(default=False),
+ 'anonymous': KeyInfo(default=False),
+ 'cache-administrator': KeyInfo(default='webmaster'),
+ 'cache-hit-dscp': KeyInfo(default=4),
+ 'cache-on-disk': KeyInfo(default=False),
+ 'cache-path': KeyInfo(default='web-proxy'),
+ 'enabled': KeyInfo(default=False),
+ 'max-cache-object-size': KeyInfo(default='2048KiB'),
+ 'max-cache-size': KeyInfo(default='unlimited'),
+ 'max-client-connections': KeyInfo(default=600),
+ 'max-fresh-time': KeyInfo(default='3d'),
+ 'max-server-connections': KeyInfo(default=600),
+ 'parent-proxy': KeyInfo(default='::'),
+ 'parent-proxy-port': KeyInfo(default=0),
+ 'port': KeyInfo(default=8080),
+ 'serialize-connections': KeyInfo(default=False),
+ 'src-address': KeyInfo(default='::'),
+ },
+ ),
),
('ip', 'smb'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'allow-guests': KeyInfo(default=True),
- 'comment': KeyInfo(default='MikrotikSMB'),
- 'domain': KeyInfo(default='MSHOME'),
- 'enabled': KeyInfo(default=False),
- 'interfaces': KeyInfo(default='all'),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'allow-guests': KeyInfo(default=True),
+ 'comment': KeyInfo(default='MikrotikSMB'),
+ 'domain': KeyInfo(default='MSHOME'),
+ 'enabled': KeyInfo(default=False),
+ 'interfaces': KeyInfo(default='all'),
+ },
+ ),
),
('ip', 'smb', 'shares'): APIData(
- unknown_mechanism=True,
- # primary_keys=('default', ),
- fields={
- 'default': KeyInfo(),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'directory': KeyInfo(),
- 'disabled': KeyInfo(),
- 'max-sessions': KeyInfo(),
- 'name': KeyInfo(),
- },
+ unversioned=VersionedAPIData(
+ unknown_mechanism=True,
+ # primary_keys=('default', ),
+ fields={
+ 'default': KeyInfo(),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'directory': KeyInfo(),
+ 'disabled': KeyInfo(),
+ 'max-sessions': KeyInfo(),
+ 'name': KeyInfo(),
+ },
+ ),
),
('ip', 'smb', 'users'): APIData(
- unknown_mechanism=True,
- # primary_keys=('default', ),
- fields={
- 'default': KeyInfo(),
- 'disabled': KeyInfo(),
- 'name': KeyInfo(),
- 'password': KeyInfo(),
- 'read-only': KeyInfo(),
- },
+ unversioned=VersionedAPIData(
+ unknown_mechanism=True,
+ # primary_keys=('default', ),
+ fields={
+ 'default': KeyInfo(),
+ 'disabled': KeyInfo(),
+ 'name': KeyInfo(),
+ 'password': KeyInfo(),
+ 'read-only': KeyInfo(),
+ },
+ ),
),
('ip', 'socks'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'auth-method': KeyInfo(default='none'),
- 'connection-idle-timeout': KeyInfo(default='2m'),
- 'enabled': KeyInfo(default=False),
- 'max-connections': KeyInfo(default=200),
- 'port': KeyInfo(default=1080),
- 'version': KeyInfo(default=4),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'auth-method': KeyInfo(default='none'),
+ 'connection-idle-timeout': KeyInfo(default='2m'),
+ 'enabled': KeyInfo(default=False),
+ 'max-connections': KeyInfo(default=200),
+ 'port': KeyInfo(default=1080),
+ 'version': KeyInfo(default=4),
+ },
+ ),
),
('ip', 'ssh'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'allow-none-crypto': KeyInfo(default=False),
- 'always-allow-password-login': KeyInfo(default=False),
- 'forwarding-enabled': KeyInfo(default=False),
- 'host-key-size': KeyInfo(default=2048),
- 'strong-crypto': KeyInfo(default=False),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'allow-none-crypto': KeyInfo(default=False),
+ 'always-allow-password-login': KeyInfo(default=False),
+ 'forwarding-enabled': KeyInfo(default=False),
+ 'host-key-size': KeyInfo(default=2048),
+ 'strong-crypto': KeyInfo(default=False),
+ },
+ ),
),
('ip', 'tftp', 'settings'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'max-block-size': KeyInfo(default=4096),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'max-block-size': KeyInfo(default=4096),
+ },
+ ),
),
('ip', 'traffic-flow'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'active-flow-timeout': KeyInfo(default='30m'),
- 'cache-entries': KeyInfo(default='32k'),
- 'enabled': KeyInfo(default=False),
- 'inactive-flow-timeout': KeyInfo(default='15s'),
- 'interfaces': KeyInfo(default='all'),
- 'packet-sampling': KeyInfo(default=False),
- 'sampling-interval': KeyInfo(default=0),
- 'sampling-space': KeyInfo(default=0),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'active-flow-timeout': KeyInfo(default='30m'),
+ 'cache-entries': KeyInfo(default='32k'),
+ 'enabled': KeyInfo(default=False),
+ 'inactive-flow-timeout': KeyInfo(default='15s'),
+ 'interfaces': KeyInfo(default='all'),
+ 'packet-sampling': KeyInfo(default=False),
+ 'sampling-interval': KeyInfo(default=0),
+ 'sampling-space': KeyInfo(default=0),
+ },
+ ),
),
('ip', 'traffic-flow', 'ipfix'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'bytes': KeyInfo(default=True),
- 'dst-address': KeyInfo(default=True),
- 'dst-address-mask': KeyInfo(default=True),
- 'dst-mac-address': KeyInfo(default=True),
- 'dst-port': KeyInfo(default=True),
- 'first-forwarded': KeyInfo(default=True),
- 'gateway': KeyInfo(default=True),
- 'icmp-code': KeyInfo(default=True),
- 'icmp-type': KeyInfo(default=True),
- 'igmp-type': KeyInfo(default=True),
- 'in-interface': KeyInfo(default=True),
- 'ip-header-length': KeyInfo(default=True),
- 'ip-total-length': KeyInfo(default=True),
- 'ipv6-flow-label': KeyInfo(default=True),
- 'is-multicast': KeyInfo(default=True),
- 'last-forwarded': KeyInfo(default=True),
- 'nat-dst-address': KeyInfo(default=True),
- 'nat-dst-port': KeyInfo(default=True),
- 'nat-events': KeyInfo(default=False),
- 'nat-src-address': KeyInfo(default=True),
- 'nat-src-port': KeyInfo(default=True),
- 'out-interface': KeyInfo(default=True),
- 'packets': KeyInfo(default=True),
- 'protocol': KeyInfo(default=True),
- 'src-address': KeyInfo(default=True),
- 'src-address-mask': KeyInfo(default=True),
- 'src-mac-address': KeyInfo(default=True),
- 'src-port': KeyInfo(default=True),
- 'sys-init-time': KeyInfo(default=True),
- 'tcp-ack-num': KeyInfo(default=True),
- 'tcp-flags': KeyInfo(default=True),
- 'tcp-seq-num': KeyInfo(default=True),
- 'tcp-window-size': KeyInfo(default=True),
- 'tos': KeyInfo(default=True),
- 'ttl': KeyInfo(default=True),
- 'udp-length': KeyInfo(default=True),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'bytes': KeyInfo(default=True),
+ 'dst-address': KeyInfo(default=True),
+ 'dst-address-mask': KeyInfo(default=True),
+ 'dst-mac-address': KeyInfo(default=True),
+ 'dst-port': KeyInfo(default=True),
+ 'first-forwarded': KeyInfo(default=True),
+ 'gateway': KeyInfo(default=True),
+ 'icmp-code': KeyInfo(default=True),
+ 'icmp-type': KeyInfo(default=True),
+ 'igmp-type': KeyInfo(default=True),
+ 'in-interface': KeyInfo(default=True),
+ 'ip-header-length': KeyInfo(default=True),
+ 'ip-total-length': KeyInfo(default=True),
+ 'ipv6-flow-label': KeyInfo(default=True),
+ 'is-multicast': KeyInfo(default=True),
+ 'last-forwarded': KeyInfo(default=True),
+ 'nat-dst-address': KeyInfo(default=True),
+ 'nat-dst-port': KeyInfo(default=True),
+ 'nat-events': KeyInfo(default=False),
+ 'nat-src-address': KeyInfo(default=True),
+ 'nat-src-port': KeyInfo(default=True),
+ 'out-interface': KeyInfo(default=True),
+ 'packets': KeyInfo(default=True),
+ 'protocol': KeyInfo(default=True),
+ 'src-address': KeyInfo(default=True),
+ 'src-address-mask': KeyInfo(default=True),
+ 'src-mac-address': KeyInfo(default=True),
+ 'src-port': KeyInfo(default=True),
+ 'sys-init-time': KeyInfo(default=True),
+ 'tcp-ack-num': KeyInfo(default=True),
+ 'tcp-flags': KeyInfo(default=True),
+ 'tcp-seq-num': KeyInfo(default=True),
+ 'tcp-window-size': KeyInfo(default=True),
+ 'tos': KeyInfo(default=True),
+ 'ttl': KeyInfo(default=True),
+ 'udp-length': KeyInfo(default=True),
+ },
+ ),
+ ),
+ ('ip', 'traffic-flow', 'target'): APIData(
+ unversioned=VersionedAPIData(
+ single_value=False,
+ fully_understood=True,
+ fields={
+ 'address': KeyInfo(),
+ 'disabled': KeyInfo(default=False),
+ 'dst-address': KeyInfo(),
+ 'port': KeyInfo(default=2055),
+ 'src-address': KeyInfo(),
+ 'v9-template-refresh': KeyInfo(default=20),
+ 'v9-template-timeout': KeyInfo(),
+ 'version': KeyInfo(),
+ },
+ ),
),
('ip', 'upnp'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'allow-disable-external-interface': KeyInfo(default=False),
- 'enabled': KeyInfo(default=False),
- 'show-dummy-rule': KeyInfo(default=True),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'allow-disable-external-interface': KeyInfo(default=False),
+ 'enabled': KeyInfo(default=False),
+ 'show-dummy-rule': KeyInfo(default=True),
+ },
+ ),
+ ),
+ ('ip', 'upnp', 'interfaces'): APIData(
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('interface', 'type'),
+ fields={
+ 'disabled': KeyInfo(default=False),
+ 'interface': KeyInfo(),
+ 'type': KeyInfo(),
+ 'forced-ip': KeyInfo(can_disable=True),
+ },
+ ),
),
('ipv6', 'dhcp-client'): APIData(
- fully_understood=True,
- primary_keys=('interface', 'request'),
- fields={
- 'add-default-route': KeyInfo(default=False),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'default-route-distance': KeyInfo(default=1),
- 'dhcp-options': KeyInfo(default=''),
- 'disabled': KeyInfo(default=False),
- 'interface': KeyInfo(),
- 'pool-name': KeyInfo(required=True),
- 'pool-prefix-length': KeyInfo(default=64),
- 'prefix-hint': KeyInfo(default='::/0'),
- 'request': KeyInfo(),
- 'use-peer-dns': KeyInfo(default=True),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('interface', 'request'),
+ fields={
+ 'add-default-route': KeyInfo(default=False),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'default-route-distance': KeyInfo(default=1),
+ 'dhcp-options': KeyInfo(default=''),
+ 'disabled': KeyInfo(default=False),
+ 'interface': KeyInfo(),
+ 'pool-name': KeyInfo(required=True),
+ 'pool-prefix-length': KeyInfo(default=64),
+ 'prefix-hint': KeyInfo(default='::/0'),
+ 'request': KeyInfo(),
+ 'use-peer-dns': KeyInfo(default=True),
+ },
+ ),
),
('ipv6', 'dhcp-server'): APIData(
- fully_understood=True,
- primary_keys=('name', ),
- fields={
- 'address-pool': KeyInfo(required=True),
- 'allow-dual-stack-queue': KeyInfo(can_disable=True, remove_value=True),
- 'binding-script': KeyInfo(can_disable=True, remove_value=''),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'dhcp-option': KeyInfo(default=''),
- 'disabled': KeyInfo(default=False),
- 'insert-queue-before': KeyInfo(can_disable=True, remove_value='first'),
- 'interface': KeyInfo(required=True),
- 'lease-time': KeyInfo(default='3d'),
- 'name': KeyInfo(),
- 'parent-queue': KeyInfo(can_disable=True, remove_value='none'),
- 'preference': KeyInfo(default=255),
- 'rapid-commit': KeyInfo(default=True),
- 'route-distance': KeyInfo(default=1),
- 'use-radius': KeyInfo(default=False),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ 'address-pool': KeyInfo(required=True),
+ 'allow-dual-stack-queue': KeyInfo(can_disable=True, remove_value=True),
+ 'binding-script': KeyInfo(can_disable=True, remove_value=''),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'dhcp-option': KeyInfo(default=''),
+ 'disabled': KeyInfo(default=False),
+ 'insert-queue-before': KeyInfo(can_disable=True, remove_value='first'),
+ 'interface': KeyInfo(required=True),
+ 'lease-time': KeyInfo(default='3d'),
+ 'name': KeyInfo(),
+ 'parent-queue': KeyInfo(can_disable=True, remove_value='none'),
+ 'preference': KeyInfo(default=255),
+ 'rapid-commit': KeyInfo(default=True),
+ 'route-distance': KeyInfo(default=1),
+ 'use-radius': KeyInfo(default=False),
+ },
+ ),
),
('ipv6', 'dhcp-server', 'option'): APIData(
- fully_understood=True,
- primary_keys=('name',),
- fields={
- 'code': KeyInfo(required=True),
- 'name': KeyInfo(),
- 'value': KeyInfo(default=''),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name',),
+ fields={
+ 'code': KeyInfo(required=True),
+ 'name': KeyInfo(),
+ 'value': KeyInfo(default=''),
+ },
+ ),
),
('ipv6', 'firewall', 'address-list'): APIData(
- fully_understood=True,
- primary_keys=('address', 'list', ),
- fields={
- 'address': KeyInfo(),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'disabled': KeyInfo(default=False),
- 'list': KeyInfo(),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('address', 'list', ),
+ fields={
+ 'address': KeyInfo(),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'list': KeyInfo(),
+ },
+ ),
),
('ipv6', 'firewall', 'filter'): APIData(
- fully_understood=True,
- stratify_keys=('chain', ),
- fields={
- 'action': KeyInfo(),
- 'chain': KeyInfo(),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'connection-bytes': KeyInfo(can_disable=True),
- 'connection-limit': KeyInfo(can_disable=True),
- 'connection-mark': KeyInfo(can_disable=True),
- 'connection-rate': KeyInfo(can_disable=True),
- 'connection-state': KeyInfo(can_disable=True),
- 'connection-type': KeyInfo(can_disable=True),
- 'content': KeyInfo(can_disable=True),
- 'disabled': KeyInfo(),
- 'dscp': KeyInfo(can_disable=True),
- 'dst-address': KeyInfo(can_disable=True),
- 'dst-address-list': KeyInfo(can_disable=True),
- 'dst-address-type': KeyInfo(can_disable=True),
- 'dst-limit': KeyInfo(can_disable=True),
- 'dst-port': KeyInfo(can_disable=True),
- 'headers': KeyInfo(can_disable=True),
- 'hop-limit': KeyInfo(can_disable=True),
- 'icmp-options': KeyInfo(can_disable=True),
- 'in-bridge-port': KeyInfo(can_disable=True),
- 'in-bridge-port-list': KeyInfo(can_disable=True),
- 'in-interface': KeyInfo(can_disable=True),
- 'in-interface-list': KeyInfo(can_disable=True),
- 'ingress-priority': KeyInfo(can_disable=True),
- 'ipsec-policy': KeyInfo(can_disable=True),
- 'jump-target': KeyInfo(),
- 'limit': KeyInfo(can_disable=True),
- 'log': KeyInfo(),
- 'log-prefix': KeyInfo(),
- 'nth': KeyInfo(can_disable=True),
- 'out-bridge-port': KeyInfo(can_disable=True),
- 'out-bridge-port-list': KeyInfo(can_disable=True),
- 'out-interface': KeyInfo(can_disable=True),
- 'out-interface-list': KeyInfo(can_disable=True),
- 'packet-mark': KeyInfo(can_disable=True),
- 'packet-size': KeyInfo(can_disable=True),
- 'per-connection-classifier': KeyInfo(can_disable=True),
- 'port': KeyInfo(can_disable=True),
- 'priority': KeyInfo(can_disable=True),
- 'protocol': KeyInfo(can_disable=True),
- 'random': KeyInfo(can_disable=True),
- 'reject-with': KeyInfo(),
- 'src-address': KeyInfo(can_disable=True),
- 'src-address-list': KeyInfo(can_disable=True),
- 'src-address-type': KeyInfo(can_disable=True),
- 'src-mac-address': KeyInfo(can_disable=True),
- 'src-port': KeyInfo(can_disable=True),
- 'tcp-flags': KeyInfo(can_disable=True),
- 'tcp-mss': KeyInfo(can_disable=True),
- 'time': KeyInfo(can_disable=True),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ stratify_keys=('chain', ),
+ fields={
+ 'action': KeyInfo(),
+ 'address-list': KeyInfo(can_disable=True),
+ 'address-list-timeout': KeyInfo(can_disable=True),
+ 'chain': KeyInfo(),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'connection-bytes': KeyInfo(can_disable=True),
+ 'connection-limit': KeyInfo(can_disable=True),
+ 'connection-mark': KeyInfo(can_disable=True),
+ 'connection-rate': KeyInfo(can_disable=True),
+ 'connection-state': KeyInfo(can_disable=True),
+ 'connection-type': KeyInfo(can_disable=True),
+ 'content': KeyInfo(can_disable=True),
+ 'disabled': KeyInfo(default=False),
+ 'dscp': KeyInfo(can_disable=True),
+ 'dst-address': KeyInfo(can_disable=True),
+ 'dst-address-list': KeyInfo(can_disable=True),
+ 'dst-address-type': KeyInfo(can_disable=True),
+ 'dst-limit': KeyInfo(can_disable=True),
+ 'dst-port': KeyInfo(can_disable=True),
+ 'headers': KeyInfo(can_disable=True),
+ 'hop-limit': KeyInfo(can_disable=True),
+ 'icmp-options': KeyInfo(can_disable=True),
+ 'in-bridge-port': KeyInfo(can_disable=True),
+ 'in-bridge-port-list': KeyInfo(can_disable=True),
+ 'in-interface': KeyInfo(can_disable=True),
+ 'in-interface-list': KeyInfo(can_disable=True),
+ 'ingress-priority': KeyInfo(can_disable=True),
+ 'ipsec-policy': KeyInfo(can_disable=True),
+ 'jump-target': KeyInfo(can_disable=True),
+ 'limit': KeyInfo(can_disable=True),
+ 'log': KeyInfo(can_disable=False),
+ 'log-prefix': KeyInfo(can_disable=False),
+ 'nth': KeyInfo(can_disable=True),
+ 'out-bridge-port': KeyInfo(can_disable=True),
+ 'out-bridge-port-list': KeyInfo(can_disable=True),
+ 'out-interface': KeyInfo(can_disable=True),
+ 'out-interface-list': KeyInfo(can_disable=True),
+ 'packet-mark': KeyInfo(can_disable=True),
+ 'packet-size': KeyInfo(can_disable=True),
+ 'per-connection-classifier': KeyInfo(can_disable=True),
+ 'port': KeyInfo(can_disable=True),
+ 'priority': KeyInfo(can_disable=True),
+ 'protocol': KeyInfo(can_disable=True),
+ 'random': KeyInfo(can_disable=True),
+ 'reject-with': KeyInfo(),
+ 'src-address': KeyInfo(can_disable=True),
+ 'src-address-list': KeyInfo(can_disable=True),
+ 'src-address-type': KeyInfo(can_disable=True),
+ 'src-mac-address': KeyInfo(can_disable=True),
+ 'src-port': KeyInfo(can_disable=True),
+ 'tcp-flags': KeyInfo(can_disable=True),
+ 'tcp-mss': KeyInfo(can_disable=True),
+ 'time': KeyInfo(can_disable=True),
+ },
+ ),
),
('ipv6', 'firewall', 'mangle'): APIData(
- fully_understood=True,
- stratify_keys=('chain', ),
- fields={
- 'action': KeyInfo(),
- 'address-list': KeyInfo(),
- 'address-list-timeout': KeyInfo(),
- 'chain': KeyInfo(),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'connection-bytes': KeyInfo(can_disable=True),
- 'connection-limit': KeyInfo(can_disable=True),
- 'connection-mark': KeyInfo(can_disable=True),
- 'connection-rate': KeyInfo(can_disable=True),
- 'connection-state': KeyInfo(can_disable=True),
- 'connection-type': KeyInfo(can_disable=True),
- 'content': KeyInfo(can_disable=True),
- 'disabled': KeyInfo(),
- 'dscp': KeyInfo(can_disable=True),
- 'dst-address': KeyInfo(can_disable=True),
- 'dst-address-list': KeyInfo(can_disable=True),
- 'dst-address-type': KeyInfo(can_disable=True),
- 'dst-limit': KeyInfo(can_disable=True),
- 'dst-port': KeyInfo(can_disable=True),
- 'dst-prefix': KeyInfo(),
- 'headers': KeyInfo(can_disable=True),
- 'hop-limit': KeyInfo(can_disable=True),
- 'icmp-options': KeyInfo(can_disable=True),
- 'in-bridge-port': KeyInfo(can_disable=True),
- 'in-bridge-port-list': KeyInfo(can_disable=True),
- 'in-interface': KeyInfo(can_disable=True),
- 'in-interface-list': KeyInfo(can_disable=True),
- 'ingress-priority': KeyInfo(can_disable=True),
- 'ipsec-policy': KeyInfo(can_disable=True),
- 'jump-target': KeyInfo(),
- 'limit': KeyInfo(can_disable=True),
- 'log': KeyInfo(),
- 'log-prefix': KeyInfo(),
- 'new-connection-mark': KeyInfo(),
- 'new-dscp': KeyInfo(),
- 'new-hop-limit': KeyInfo(),
- 'new-mss': KeyInfo(),
- 'new-packet-mark': KeyInfo(),
- 'new-routing-mark': KeyInfo(),
- 'nth': KeyInfo(can_disable=True),
- 'out-bridge-port': KeyInfo(can_disable=True),
- 'out-bridge-port-list': KeyInfo(can_disable=True),
- 'out-interface': KeyInfo(can_disable=True),
- 'out-interface-list': KeyInfo(can_disable=True),
- 'packet-mark': KeyInfo(can_disable=True),
- 'packet-size': KeyInfo(can_disable=True),
- 'passthrough': KeyInfo(),
- 'per-connection-classifier': KeyInfo(can_disable=True),
- 'port': KeyInfo(can_disable=True),
- 'priority': KeyInfo(can_disable=True),
- 'protocol': KeyInfo(can_disable=True),
- 'random': KeyInfo(can_disable=True),
- 'routing-mark': KeyInfo(can_disable=True),
- 'sniff-id': KeyInfo(),
- 'sniff-target': KeyInfo(),
- 'sniff-target-port': KeyInfo(),
- 'src-address': KeyInfo(can_disable=True),
- 'src-address-list': KeyInfo(can_disable=True),
- 'src-address-type': KeyInfo(can_disable=True),
- 'src-mac-address': KeyInfo(can_disable=True),
- 'src-port': KeyInfo(can_disable=True),
- 'src-prefix': KeyInfo(),
- 'tcp-flags': KeyInfo(can_disable=True),
- 'tcp-mss': KeyInfo(can_disable=True),
- 'time': KeyInfo(can_disable=True),
- 'tls-host': KeyInfo(can_disable=True),
- }
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ stratify_keys=('chain', ),
+ fields={
+ 'action': KeyInfo(),
+ 'address-list': KeyInfo(),
+ 'address-list-timeout': KeyInfo(),
+ 'chain': KeyInfo(),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'connection-bytes': KeyInfo(can_disable=True),
+ 'connection-limit': KeyInfo(can_disable=True),
+ 'connection-mark': KeyInfo(can_disable=True),
+ 'connection-rate': KeyInfo(can_disable=True),
+ 'connection-state': KeyInfo(can_disable=True),
+ 'connection-type': KeyInfo(can_disable=True),
+ 'content': KeyInfo(can_disable=True),
+ 'disabled': KeyInfo(default=False),
+ 'dscp': KeyInfo(can_disable=True),
+ 'dst-address': KeyInfo(can_disable=True),
+ 'dst-address-list': KeyInfo(can_disable=True),
+ 'dst-address-type': KeyInfo(can_disable=True),
+ 'dst-limit': KeyInfo(can_disable=True),
+ 'dst-port': KeyInfo(can_disable=True),
+ 'dst-prefix': KeyInfo(),
+ 'headers': KeyInfo(can_disable=True),
+ 'hop-limit': KeyInfo(can_disable=True),
+ 'icmp-options': KeyInfo(can_disable=True),
+ 'in-bridge-port': KeyInfo(can_disable=True),
+ 'in-bridge-port-list': KeyInfo(can_disable=True),
+ 'in-interface': KeyInfo(can_disable=True),
+ 'in-interface-list': KeyInfo(can_disable=True),
+ 'ingress-priority': KeyInfo(can_disable=True),
+ 'ipsec-policy': KeyInfo(can_disable=True),
+ 'jump-target': KeyInfo(),
+ 'limit': KeyInfo(can_disable=True),
+ 'log': KeyInfo(),
+ 'log-prefix': KeyInfo(),
+ 'new-connection-mark': KeyInfo(),
+ 'new-dscp': KeyInfo(),
+ 'new-hop-limit': KeyInfo(),
+ 'new-mss': KeyInfo(),
+ 'new-packet-mark': KeyInfo(),
+ 'new-routing-mark': KeyInfo(),
+ 'nth': KeyInfo(can_disable=True),
+ 'out-bridge-port': KeyInfo(can_disable=True),
+ 'out-bridge-port-list': KeyInfo(can_disable=True),
+ 'out-interface': KeyInfo(can_disable=True),
+ 'out-interface-list': KeyInfo(can_disable=True),
+ 'packet-mark': KeyInfo(can_disable=True),
+ 'packet-size': KeyInfo(can_disable=True),
+ 'passthrough': KeyInfo(),
+ 'per-connection-classifier': KeyInfo(can_disable=True),
+ 'port': KeyInfo(can_disable=True),
+ 'priority': KeyInfo(can_disable=True),
+ 'protocol': KeyInfo(can_disable=True),
+ 'random': KeyInfo(can_disable=True),
+ 'routing-mark': KeyInfo(can_disable=True),
+ 'sniff-id': KeyInfo(),
+ 'sniff-target': KeyInfo(),
+ 'sniff-target-port': KeyInfo(),
+ 'src-address': KeyInfo(can_disable=True),
+ 'src-address-list': KeyInfo(can_disable=True),
+ 'src-address-type': KeyInfo(can_disable=True),
+ 'src-mac-address': KeyInfo(can_disable=True),
+ 'src-port': KeyInfo(can_disable=True),
+ 'src-prefix': KeyInfo(),
+ 'tcp-flags': KeyInfo(can_disable=True),
+ 'tcp-mss': KeyInfo(can_disable=True),
+ 'time': KeyInfo(can_disable=True),
+ 'tls-host': KeyInfo(can_disable=True),
+ }
+ ),
+ ),
+ ('ipv6', 'firewall', 'nat'): APIData(
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ stratify_keys=('chain', ),
+ fields={
+ 'action': KeyInfo(),
+ 'address-list': KeyInfo(),
+ 'address-list-timeout': KeyInfo(),
+ 'chain': KeyInfo(),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'connection-bytes': KeyInfo(can_disable=True),
+ 'connection-limit': KeyInfo(can_disable=True),
+ 'connection-mark': KeyInfo(can_disable=True),
+ 'connection-rate': KeyInfo(can_disable=True),
+ 'connection-state': KeyInfo(can_disable=True),
+ 'connection-type': KeyInfo(can_disable=True),
+ 'content': KeyInfo(can_disable=True),
+ 'disabled': KeyInfo(default=False),
+ 'dscp': KeyInfo(can_disable=True),
+ 'dst-address': KeyInfo(can_disable=True),
+ 'dst-address-list': KeyInfo(can_disable=True),
+ 'dst-address-type': KeyInfo(can_disable=True),
+ 'dst-limit': KeyInfo(can_disable=True),
+ 'dst-port': KeyInfo(can_disable=True),
+ 'icmp-options': KeyInfo(can_disable=True),
+ 'in-bridge-port': KeyInfo(can_disable=True),
+ 'in-bridge-port-list': KeyInfo(can_disable=True),
+ 'in-interface': KeyInfo(can_disable=True),
+ 'in-interface-list': KeyInfo(can_disable=True),
+ 'ingress-priority': KeyInfo(can_disable=True),
+ 'ipsec-policy': KeyInfo(can_disable=True),
+ 'jump-target': KeyInfo(),
+ 'layer7-protocol': KeyInfo(can_disable=True),
+ 'limit': KeyInfo(can_disable=True),
+ 'log': KeyInfo(),
+ 'log-prefix': KeyInfo(),
+ 'out-bridge-port': KeyInfo(can_disable=True),
+ 'out-bridge-port-list': KeyInfo(can_disable=True),
+ 'out-interface': KeyInfo(can_disable=True),
+ 'out-interface-list': KeyInfo(can_disable=True),
+ 'packet-mark': KeyInfo(can_disable=True),
+ 'packet-size': KeyInfo(can_disable=True),
+ 'per-connection-classifier': KeyInfo(can_disable=True),
+ 'port': KeyInfo(can_disable=True),
+ 'priority': KeyInfo(can_disable=True),
+ 'protocol': KeyInfo(can_disable=True),
+ 'random': KeyInfo(can_disable=True),
+ 'routing-mark': KeyInfo(can_disable=True),
+ 'src-address': KeyInfo(can_disable=True),
+ 'src-address-list': KeyInfo(can_disable=True),
+ 'src-address-type': KeyInfo(can_disable=True),
+ 'src-mac-address': KeyInfo(can_disable=True),
+ 'src-port': KeyInfo(can_disable=True),
+ 'tcp-flags': KeyInfo(can_disable=True),
+ 'tcp-mss': KeyInfo(can_disable=True),
+ 'time': KeyInfo(can_disable=True),
+ 'tls-host': KeyInfo(can_disable=True),
+ 'to-addresses': KeyInfo(can_disable=True),
+ 'to-ports': KeyInfo(can_disable=True),
+ },
+ ),
),
('ipv6', 'firewall', 'raw'): APIData(
- fully_understood=True,
- stratify_keys=('chain',),
- fields={
- 'action': KeyInfo(),
- 'address-list': KeyInfo(),
- 'address-list-timeout': KeyInfo(),
- 'chain': KeyInfo(),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'content': KeyInfo(can_disable=True),
- 'disabled': KeyInfo(),
- 'dscp': KeyInfo(can_disable=True),
- 'dst-address': KeyInfo(can_disable=True),
- 'dst-address-list': KeyInfo(can_disable=True),
- 'dst-address-type': KeyInfo(can_disable=True),
- 'dst-limit': KeyInfo(can_disable=True),
- 'dst-port': KeyInfo(can_disable=True),
- 'headers': KeyInfo(can_disable=True),
- 'hop-limit': KeyInfo(can_disable=True),
- 'icmp-options': KeyInfo(can_disable=True),
- 'in-bridge-port': KeyInfo(can_disable=True),
- 'in-bridge-port-list': KeyInfo(can_disable=True),
- 'in-interface': KeyInfo(can_disable=True),
- 'in-interface-list': KeyInfo(can_disable=True),
- 'ingress-priority': KeyInfo(can_disable=True),
- 'ipsec-policy': KeyInfo(can_disable=True),
- 'jump-target': KeyInfo(),
- 'limit': KeyInfo(can_disable=True),
- 'log': KeyInfo(),
- 'log-prefix': KeyInfo(),
- 'nth': KeyInfo(can_disable=True),
- 'out-bridge-port': KeyInfo(can_disable=True),
- 'out-bridge-port-list': KeyInfo(can_disable=True),
- 'out-interface': KeyInfo(can_disable=True),
- 'out-interface-list': KeyInfo(can_disable=True),
- 'packet-mark': KeyInfo(can_disable=True),
- 'packet-size': KeyInfo(can_disable=True),
- 'per-connection-classifier': KeyInfo(can_disable=True),
- 'port': KeyInfo(can_disable=True),
- 'priority': KeyInfo(can_disable=True),
- 'protocol': KeyInfo(can_disable=True),
- 'random': KeyInfo(can_disable=True),
- 'src-address': KeyInfo(can_disable=True),
- 'src-address-list': KeyInfo(can_disable=True),
- 'src-address-type': KeyInfo(can_disable=True),
- 'src-mac-address': KeyInfo(can_disable=True),
- 'src-port': KeyInfo(can_disable=True),
- 'tcp-flags': KeyInfo(can_disable=True),
- 'tcp-mss': KeyInfo(can_disable=True),
- 'time': KeyInfo(can_disable=True),
- 'tls-host': KeyInfo(can_disable=True),
- }
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ stratify_keys=('chain',),
+ fields={
+ 'action': KeyInfo(),
+ 'address-list': KeyInfo(),
+ 'address-list-timeout': KeyInfo(),
+ 'chain': KeyInfo(),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'content': KeyInfo(can_disable=True),
+ 'disabled': KeyInfo(default=False),
+ 'dscp': KeyInfo(can_disable=True),
+ 'dst-address': KeyInfo(can_disable=True),
+ 'dst-address-list': KeyInfo(can_disable=True),
+ 'dst-address-type': KeyInfo(can_disable=True),
+ 'dst-limit': KeyInfo(can_disable=True),
+ 'dst-port': KeyInfo(can_disable=True),
+ 'headers': KeyInfo(can_disable=True),
+ 'hop-limit': KeyInfo(can_disable=True),
+ 'icmp-options': KeyInfo(can_disable=True),
+ 'in-bridge-port': KeyInfo(can_disable=True),
+ 'in-bridge-port-list': KeyInfo(can_disable=True),
+ 'in-interface': KeyInfo(can_disable=True),
+ 'in-interface-list': KeyInfo(can_disable=True),
+ 'ingress-priority': KeyInfo(can_disable=True),
+ 'ipsec-policy': KeyInfo(can_disable=True),
+ 'jump-target': KeyInfo(),
+ 'limit': KeyInfo(can_disable=True),
+ 'log': KeyInfo(),
+ 'log-prefix': KeyInfo(),
+ 'nth': KeyInfo(can_disable=True),
+ 'out-bridge-port': KeyInfo(can_disable=True),
+ 'out-bridge-port-list': KeyInfo(can_disable=True),
+ 'out-interface': KeyInfo(can_disable=True),
+ 'out-interface-list': KeyInfo(can_disable=True),
+ 'packet-mark': KeyInfo(can_disable=True),
+ 'packet-size': KeyInfo(can_disable=True),
+ 'per-connection-classifier': KeyInfo(can_disable=True),
+ 'port': KeyInfo(can_disable=True),
+ 'priority': KeyInfo(can_disable=True),
+ 'protocol': KeyInfo(can_disable=True),
+ 'random': KeyInfo(can_disable=True),
+ 'src-address': KeyInfo(can_disable=True),
+ 'src-address-list': KeyInfo(can_disable=True),
+ 'src-address-type': KeyInfo(can_disable=True),
+ 'src-mac-address': KeyInfo(can_disable=True),
+ 'src-port': KeyInfo(can_disable=True),
+ 'tcp-flags': KeyInfo(can_disable=True),
+ 'tcp-mss': KeyInfo(can_disable=True),
+ 'time': KeyInfo(can_disable=True),
+ 'tls-host': KeyInfo(can_disable=True),
+ }
+ ),
),
('ipv6', 'nd'): APIData(
- fully_understood=True,
- primary_keys=('interface', ),
- fields={
- 'advertise-dns': KeyInfo(default=True),
- 'advertise-mac-address': KeyInfo(default=True),
- 'disabled': KeyInfo(default=False),
- 'dns': KeyInfo(default=''),
- 'hop-limit': KeyInfo(default='unspecified'),
- 'interface': KeyInfo(),
- 'managed-address-configuration': KeyInfo(default=False),
- 'mtu': KeyInfo(default='unspecified'),
- 'other-configuration': KeyInfo(default=False),
- 'ra-delay': KeyInfo(default='3s'),
- 'ra-interval': KeyInfo(default='3m20s-10m'),
- 'ra-lifetime': KeyInfo(default='30m'),
- 'ra-preference': KeyInfo(default='medium'),
- 'reachable-time': KeyInfo(default='unspecified'),
- 'retransmit-interval': KeyInfo(default='unspecified'),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('interface', ),
+ fields={
+ 'advertise-dns': KeyInfo(default=True),
+ 'advertise-mac-address': KeyInfo(default=True),
+ 'disabled': KeyInfo(default=False),
+ 'dns': KeyInfo(default=''),
+ 'hop-limit': KeyInfo(default='unspecified'),
+ 'interface': KeyInfo(),
+ 'managed-address-configuration': KeyInfo(default=False),
+ 'mtu': KeyInfo(default='unspecified'),
+ 'other-configuration': KeyInfo(default=False),
+ 'ra-delay': KeyInfo(default='3s'),
+ 'ra-interval': KeyInfo(default='3m20s-10m'),
+ 'ra-lifetime': KeyInfo(default='30m'),
+ 'ra-preference': KeyInfo(default='medium'),
+ 'reachable-time': KeyInfo(default='unspecified'),
+ 'retransmit-interval': KeyInfo(default='unspecified'),
+ },
+ ),
),
('ipv6', 'nd', 'prefix', 'default'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'autonomous': KeyInfo(default=True),
- 'preferred-lifetime': KeyInfo(default='1w'),
- 'valid-lifetime': KeyInfo(default='4w2d'),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'autonomous': KeyInfo(default=True),
+ 'preferred-lifetime': KeyInfo(default='1w'),
+ 'valid-lifetime': KeyInfo(default='4w2d'),
+ },
+ ),
),
('ipv6', 'route'): APIData(
- fully_understood=True,
- fields={
- 'bgp-as-path': KeyInfo(can_disable=True),
- 'bgp-atomic-aggregate': KeyInfo(can_disable=True),
- 'bgp-communities': KeyInfo(can_disable=True),
- 'bgp-local-pref': KeyInfo(can_disable=True),
- 'bgp-med': KeyInfo(can_disable=True),
- 'bgp-origin': KeyInfo(can_disable=True),
- 'bgp-prepend': KeyInfo(can_disable=True),
- 'type': KeyInfo(can_disable=True, remove_value='unicast'),
- 'blackhole': KeyInfo(can_disable=True),
- 'check-gateway': KeyInfo(can_disable=True),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'disabled': KeyInfo(),
- 'distance': KeyInfo(default=1),
- 'dst-address': KeyInfo(),
- 'gateway': KeyInfo(),
- 'route-tag': KeyInfo(can_disable=True),
- 'routing-table': KeyInfo(default='main'),
- 'scope': KeyInfo(default=30),
- 'target-scope': KeyInfo(default=10),
- 'vrf-interface': KeyInfo(can_disable=True),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ fields={
+ 'bgp-as-path': KeyInfo(can_disable=True),
+ 'bgp-atomic-aggregate': KeyInfo(can_disable=True),
+ 'bgp-communities': KeyInfo(can_disable=True),
+ 'bgp-local-pref': KeyInfo(can_disable=True),
+ 'bgp-med': KeyInfo(can_disable=True),
+ 'bgp-origin': KeyInfo(can_disable=True),
+ 'bgp-prepend': KeyInfo(can_disable=True),
+ 'type': KeyInfo(can_disable=True, remove_value='unicast'),
+ 'blackhole': KeyInfo(can_disable=True),
+ 'check-gateway': KeyInfo(can_disable=True),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'distance': KeyInfo(default=1),
+ 'dst-address': KeyInfo(),
+ 'gateway': KeyInfo(),
+ 'route-tag': KeyInfo(can_disable=True),
+ 'routing-table': KeyInfo(default='main'),
+ 'scope': KeyInfo(default=30),
+ 'target-scope': KeyInfo(default=10),
+ 'vrf-interface': KeyInfo(can_disable=True),
+ },
+ ),
),
('mpls', ): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'allow-fast-path': KeyInfo(default=True),
- 'dynamic-label-range': KeyInfo(default='16-1048575'),
- 'propagate-ttl': KeyInfo(default=True),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'allow-fast-path': KeyInfo(default=True),
+ 'dynamic-label-range': KeyInfo(default='16-1048575'),
+ 'propagate-ttl': KeyInfo(default=True),
+ },
+ ),
),
('mpls', 'interface'): APIData(
- unknown_mechanism=True,
- # primary_keys=('default', ),
- fields={
- 'default': KeyInfo(),
- 'disabled': KeyInfo(),
- 'interface': KeyInfo(),
- 'mpls-mtu': KeyInfo(),
- },
+ unversioned=VersionedAPIData(
+ unknown_mechanism=True,
+ # primary_keys=('default', ),
+ fields={
+ 'default': KeyInfo(),
+ 'disabled': KeyInfo(),
+ 'interface': KeyInfo(),
+ 'mpls-mtu': KeyInfo(),
+ },
+ ),
),
('mpls', 'ldp'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'distribute-for-default-route': KeyInfo(default=False),
- 'enabled': KeyInfo(default=False),
- 'hop-limit': KeyInfo(default=255),
- 'loop-detect': KeyInfo(default=False),
- 'lsr-id': KeyInfo(default='0.0.0.0'),
- 'path-vector-limit': KeyInfo(default=255),
- 'transport-address': KeyInfo(default='0.0.0.0'),
- 'use-explicit-null': KeyInfo(default=False),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'distribute-for-default-route': KeyInfo(default=False),
+ 'enabled': KeyInfo(default=False),
+ 'hop-limit': KeyInfo(default=255),
+ 'loop-detect': KeyInfo(default=False),
+ 'lsr-id': KeyInfo(default='0.0.0.0'),
+ 'path-vector-limit': KeyInfo(default=255),
+ 'transport-address': KeyInfo(default='0.0.0.0'),
+ 'use-explicit-null': KeyInfo(default=False),
+ },
+ ),
),
('port', 'firmware'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'directory': KeyInfo(default='firmware'),
- 'ignore-directip-modem': KeyInfo(default=False),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'directory': KeyInfo(default='firmware'),
+ 'ignore-directip-modem': KeyInfo(default=False),
+ },
+ ),
+ ),
+ ('port', 'remote-access'): APIData(
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ fields={
+ 'allowed-addresses': KeyInfo(default='0.0.0.0/0'),
+ 'channel': KeyInfo(default=0),
+ 'disabled': KeyInfo(default=False),
+ 'log-file': KeyInfo(default=""),
+ 'port': KeyInfo(required=True),
+ 'protocol': KeyInfo(default='rfc2217'),
+ 'tcp-port': KeyInfo(default=0),
+ },
+ ),
),
('ppp', 'aaa'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'accounting': KeyInfo(default=True),
- 'interim-update': KeyInfo(default='0s'),
- 'use-circuit-id-in-nas-port-id': KeyInfo(default=False),
- 'use-radius': KeyInfo(default=False),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'accounting': KeyInfo(default=True),
+ 'interim-update': KeyInfo(default='0s'),
+ 'use-circuit-id-in-nas-port-id': KeyInfo(default=False),
+ 'use-radius': KeyInfo(default=False),
+ },
+ ),
+ ),
+ ('radius', ): APIData(
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ fields={
+ 'accounting-backup': KeyInfo(default=False),
+ 'accounting-port': KeyInfo(default=1813),
+ 'address': KeyInfo(default='0.0.0.0'),
+ 'authentication-port': KeyInfo(default=1812),
+ 'called-id': KeyInfo(),
+ 'certificate': KeyInfo(),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'domain': KeyInfo(),
+ 'protocol': KeyInfo(default='udp'),
+ 'realm': KeyInfo(),
+ 'secret': KeyInfo(),
+ 'service': KeyInfo(),
+ 'src-address': KeyInfo(default='0.0.0.0'),
+ 'timeout': KeyInfo(default='300ms'),
+ },
+ ),
),
('radius', 'incoming'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'accept': KeyInfo(default=False),
- 'port': KeyInfo(default=3799),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'accept': KeyInfo(default=False),
+ 'port': KeyInfo(default=3799),
+ },
+ ),
+ ),
+ ('routing', 'id'): APIData(
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ fields={
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'id': KeyInfo(),
+ 'name': KeyInfo(),
+ 'select-dynamic-id': KeyInfo(),
+ 'select-from-vrf': KeyInfo(),
+ },
+ ),
),
('routing', 'bfd', 'interface'): APIData(
- unknown_mechanism=True,
- # primary_keys=('default', ),
- fields={
- 'default': KeyInfo(),
- 'disabled': KeyInfo(),
- 'interface': KeyInfo(),
- 'interval': KeyInfo(),
- 'min-rx': KeyInfo(),
- 'multiplier': KeyInfo(),
- },
+ unversioned=VersionedAPIData(
+ unknown_mechanism=True,
+ # primary_keys=('default', ),
+ fields={
+ 'default': KeyInfo(),
+ 'disabled': KeyInfo(),
+ 'interface': KeyInfo(),
+ 'interval': KeyInfo(),
+ 'min-rx': KeyInfo(),
+ 'multiplier': KeyInfo(),
+ },
+ ),
),
('routing', 'mme'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'bidirectional-timeout': KeyInfo(default=2),
- 'gateway-class': KeyInfo(default='none'),
- 'gateway-keepalive': KeyInfo(default='1m'),
- 'gateway-selection': KeyInfo(default='no-gateway'),
- 'origination-interval': KeyInfo(default='5s'),
- 'preferred-gateway': KeyInfo(default='0.0.0.0'),
- 'timeout': KeyInfo(default='1m'),
- 'ttl': KeyInfo(default=50),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'bidirectional-timeout': KeyInfo(default=2),
+ 'gateway-class': KeyInfo(default='none'),
+ 'gateway-keepalive': KeyInfo(default='1m'),
+ 'gateway-selection': KeyInfo(default='no-gateway'),
+ 'origination-interval': KeyInfo(default='5s'),
+ 'preferred-gateway': KeyInfo(default='0.0.0.0'),
+ 'timeout': KeyInfo(default='1m'),
+ 'ttl': KeyInfo(default=50),
+ },
+ ),
),
('routing', 'rip'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'distribute-default': KeyInfo(default='never'),
- 'garbage-timer': KeyInfo(default='2m'),
- 'metric-bgp': KeyInfo(default=1),
- 'metric-connected': KeyInfo(default=1),
- 'metric-default': KeyInfo(default=1),
- 'metric-ospf': KeyInfo(default=1),
- 'metric-static': KeyInfo(default=1),
- 'redistribute-bgp': KeyInfo(default=False),
- 'redistribute-connected': KeyInfo(default=False),
- 'redistribute-ospf': KeyInfo(default=False),
- 'redistribute-static': KeyInfo(default=False),
- 'routing-table': KeyInfo(default='main'),
- 'timeout-timer': KeyInfo(default='3m'),
- 'update-timer': KeyInfo(default='30s'),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'distribute-default': KeyInfo(default='never'),
+ 'garbage-timer': KeyInfo(default='2m'),
+ 'metric-bgp': KeyInfo(default=1),
+ 'metric-connected': KeyInfo(default=1),
+ 'metric-default': KeyInfo(default=1),
+ 'metric-ospf': KeyInfo(default=1),
+ 'metric-static': KeyInfo(default=1),
+ 'redistribute-bgp': KeyInfo(default=False),
+ 'redistribute-connected': KeyInfo(default=False),
+ 'redistribute-ospf': KeyInfo(default=False),
+ 'redistribute-static': KeyInfo(default=False),
+ 'routing-table': KeyInfo(default='main'),
+ 'timeout-timer': KeyInfo(default='3m'),
+ 'update-timer': KeyInfo(default='30s'),
+ },
+ ),
),
('routing', 'ripng'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'distribute-default': KeyInfo(default='never'),
- 'garbage-timer': KeyInfo(default='2m'),
- 'metric-bgp': KeyInfo(default=1),
- 'metric-connected': KeyInfo(default=1),
- 'metric-default': KeyInfo(default=1),
- 'metric-ospf': KeyInfo(default=1),
- 'metric-static': KeyInfo(default=1),
- 'redistribute-bgp': KeyInfo(default=False),
- 'redistribute-connected': KeyInfo(default=False),
- 'redistribute-ospf': KeyInfo(default=False),
- 'redistribute-static': KeyInfo(default=False),
- 'timeout-timer': KeyInfo(default='3m'),
- 'update-timer': KeyInfo(default='30s'),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'distribute-default': KeyInfo(default='never'),
+ 'garbage-timer': KeyInfo(default='2m'),
+ 'metric-bgp': KeyInfo(default=1),
+ 'metric-connected': KeyInfo(default=1),
+ 'metric-default': KeyInfo(default=1),
+ 'metric-ospf': KeyInfo(default=1),
+ 'metric-static': KeyInfo(default=1),
+ 'redistribute-bgp': KeyInfo(default=False),
+ 'redistribute-connected': KeyInfo(default=False),
+ 'redistribute-ospf': KeyInfo(default=False),
+ 'redistribute-static': KeyInfo(default=False),
+ 'timeout-timer': KeyInfo(default='3m'),
+ 'update-timer': KeyInfo(default='30s'),
+ },
+ ),
),
('snmp', ): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'contact': KeyInfo(default=''),
- 'enabled': KeyInfo(default=False),
- 'engine-id': KeyInfo(default=''),
- 'location': KeyInfo(default=''),
- 'src-address': KeyInfo(default='::'),
- 'trap-community': KeyInfo(default='public'),
- 'trap-generators': KeyInfo(default='temp-exception'),
- 'trap-target': KeyInfo(default=''),
- 'trap-version': KeyInfo(default=1),
- 'trap-interfaces': KeyInfo(default=''),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'contact': KeyInfo(default=''),
+ 'enabled': KeyInfo(default=False),
+ 'location': KeyInfo(default=''),
+ 'src-address': KeyInfo(default='::'),
+ 'trap-community': KeyInfo(default='public'),
+ 'trap-generators': KeyInfo(default='temp-exception'),
+ 'trap-target': KeyInfo(default=''),
+ 'trap-version': KeyInfo(default=1),
+ 'trap-interfaces': KeyInfo(default=''),
+ },
+ versioned_fields=[
+ ([('7.10', '<')], 'engine-id', KeyInfo(default='')),
+ ([('7.10', '>=')], 'engine-id', KeyInfo(read_only=True)),
+ ([('7.10', '>=')], 'engine-id-suffix', KeyInfo(default='')),
+ ],
+ ),
),
('system', 'clock'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'time-zone-autodetect': KeyInfo(default=True),
- 'time-zone-name': KeyInfo(default='manual'),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'date': KeyInfo(),
+ 'gmt-offset': KeyInfo(),
+ 'time': KeyInfo(),
+ 'time-zone-autodetect': KeyInfo(default=True),
+ 'time-zone-name': KeyInfo(default='manual'),
+ },
+ ),
),
('system', 'clock', 'manual'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'dst-delta': KeyInfo(default='00:00'),
- 'dst-end': KeyInfo(default='jan/01/1970 00:00:00'),
- 'dst-start': KeyInfo(default='jan/01/1970 00:00:00'),
- 'time-zone': KeyInfo(default='+00:00'),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'dst-delta': KeyInfo(default='00:00'),
+ 'dst-end': KeyInfo(default='jan/01/1970 00:00:00'),
+ 'dst-start': KeyInfo(default='jan/01/1970 00:00:00'),
+ 'time-zone': KeyInfo(default='+00:00'),
+ },
+ ),
),
('system', 'identity'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'name': KeyInfo(default='Mikrotik'),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'name': KeyInfo(default='Mikrotik'),
+ },
+ ),
),
('system', 'leds', 'settings'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'all-leds-off': KeyInfo(default='never'),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'all-leds-off': KeyInfo(default='never'),
+ },
+ ),
),
('system', 'note'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'note': KeyInfo(default=''),
- 'show-at-login': KeyInfo(default=True),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'note': KeyInfo(default=''),
+ 'show-at-login': KeyInfo(default=True),
+ },
+ ),
),
('system', 'ntp', 'client'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'enabled': KeyInfo(default=False),
- 'primary-ntp': KeyInfo(default='0.0.0.0'),
- 'secondary-ntp': KeyInfo(default='0.0.0.0'),
- 'server-dns-names': KeyInfo(default=''),
- 'servers': KeyInfo(default=''),
- 'mode': KeyInfo(default='unicast'),
- 'vrf': KeyInfo(default='main'),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'enabled': KeyInfo(default=False),
+ 'primary-ntp': KeyInfo(default='0.0.0.0'),
+ 'secondary-ntp': KeyInfo(default='0.0.0.0'),
+ 'server-dns-names': KeyInfo(default=''),
+ 'servers': KeyInfo(default=''),
+ 'mode': KeyInfo(default='unicast'),
+ 'vrf': KeyInfo(default='main'),
+ },
+ ),
),
('system', 'ntp', 'client', 'servers'): APIData(
- primary_keys=('address', ),
- fully_understood=True,
- fields={
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'disabled': KeyInfo(default=False),
- 'address': KeyInfo(),
- 'auth-key': KeyInfo(default='none'),
- 'iburst': KeyInfo(default=True),
- 'max-poll': KeyInfo(default=10),
- 'min-poll': KeyInfo(default=6),
- },
+ unversioned=VersionedAPIData(
+ primary_keys=('address', ),
+ fully_understood=True,
+ fields={
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'address': KeyInfo(),
+ 'auth-key': KeyInfo(default='none'),
+ 'iburst': KeyInfo(default=True),
+ 'max-poll': KeyInfo(default=10),
+ 'min-poll': KeyInfo(default=6),
+ },
+ ),
),
('system', 'ntp', 'server'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'auth-key': KeyInfo(default='none'),
- 'broadcast': KeyInfo(default=False),
- 'broadcast-addresses': KeyInfo(default=''),
- 'enabled': KeyInfo(default=False),
- 'local-clock-stratum': KeyInfo(default=5),
- 'manycast': KeyInfo(default=False),
- 'multicast': KeyInfo(default=False),
- 'use-local-clock': KeyInfo(default=False),
- 'vrf': KeyInfo(default='main'),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'auth-key': KeyInfo(default='none'),
+ 'broadcast': KeyInfo(default=False),
+ 'broadcast-addresses': KeyInfo(default=''),
+ 'enabled': KeyInfo(default=False),
+ 'local-clock-stratum': KeyInfo(default=5),
+ 'manycast': KeyInfo(default=False),
+ 'multicast': KeyInfo(default=False),
+ 'use-local-clock': KeyInfo(default=False),
+ 'vrf': KeyInfo(default='main'),
+ },
+ ),
),
('system', 'package', 'update'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'channel': KeyInfo(default='stable'),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'channel': KeyInfo(default='stable'),
+ 'installed-version': KeyInfo(read_only=True),
+ 'latest-version': KeyInfo(read_only=True),
+ 'status': KeyInfo(read_only=True),
+ },
+ ),
),
('system', 'routerboard', 'settings'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'auto-upgrade': KeyInfo(default=False),
- 'baud-rate': KeyInfo(default=115200),
- 'boot-delay': KeyInfo(default='2s'),
- 'boot-device': KeyInfo(default='nand-if-fail-then-ethernet'),
- 'boot-protocol': KeyInfo(default='bootp'),
- 'enable-jumper-reset': KeyInfo(default=True),
- 'enter-setup-on': KeyInfo(default='any-key'),
- 'force-backup-booter': KeyInfo(default=False),
- 'protected-routerboot': KeyInfo(default='disabled'),
- 'reformat-hold-button': KeyInfo(default='20s'),
- 'reformat-hold-button-max': KeyInfo(default='10m'),
- 'silent-boot': KeyInfo(default=False),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'auto-upgrade': KeyInfo(default=False),
+ 'baud-rate': KeyInfo(default=115200),
+ 'boot-delay': KeyInfo(default='2s'),
+ 'boot-device': KeyInfo(default='nand-if-fail-then-ethernet'),
+ 'boot-protocol': KeyInfo(default='bootp'),
+ 'enable-jumper-reset': KeyInfo(default=True),
+ 'enter-setup-on': KeyInfo(default='any-key'),
+ 'force-backup-booter': KeyInfo(default=False),
+ 'protected-routerboot': KeyInfo(default='disabled'),
+ 'reformat-hold-button': KeyInfo(default='20s'),
+ 'reformat-hold-button-max': KeyInfo(default='10m'),
+ 'silent-boot': KeyInfo(default=False),
+ },
+ ),
),
('system', 'upgrade', 'mirror'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'check-interval': KeyInfo(default='1d'),
- 'enabled': KeyInfo(default=False),
- 'primary-server': KeyInfo(default='0.0.0.0'),
- 'secondary-server': KeyInfo(default='0.0.0.0'),
- 'user': KeyInfo(default=''),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'check-interval': KeyInfo(default='1d'),
+ 'enabled': KeyInfo(default=False),
+ 'primary-server': KeyInfo(default='0.0.0.0'),
+ 'secondary-server': KeyInfo(default='0.0.0.0'),
+ 'user': KeyInfo(default=''),
+ },
+ ),
),
('system', 'ups'): APIData(
- fully_understood=True,
- primary_keys=('name', ),
- fields={
- 'alarm-setting': KeyInfo(default='immediate'),
- 'check-capabilities': KeyInfo(can_disable=True, remove_value=True),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'disabled': KeyInfo(default=True),
- 'min-runtime': KeyInfo(default='never'),
- 'name': KeyInfo(),
- 'offline-time': KeyInfo(default='0s'),
- 'port': KeyInfo(required=True),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ 'alarm-setting': KeyInfo(default='immediate'),
+ 'check-capabilities': KeyInfo(can_disable=True, remove_value=True),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=True),
+ 'min-runtime': KeyInfo(default='never'),
+ 'name': KeyInfo(),
+ 'offline-time': KeyInfo(default='0s'),
+ 'port': KeyInfo(required=True),
+ },
+ ),
),
('system', 'watchdog'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'auto-send-supout': KeyInfo(default=False),
- 'automatic-supout': KeyInfo(default=True),
- 'ping-start-after-boot': KeyInfo(default='5m'),
- 'ping-timeout': KeyInfo(default='1m'),
- 'watch-address': KeyInfo(default='none'),
- 'watchdog-timer': KeyInfo(default=True),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'auto-send-supout': KeyInfo(default=False),
+ 'automatic-supout': KeyInfo(default=True),
+ 'ping-start-after-boot': KeyInfo(default='5m'),
+ 'ping-timeout': KeyInfo(default='1m'),
+ 'watch-address': KeyInfo(default='none'),
+ 'watchdog-timer': KeyInfo(default=True),
+ },
+ ),
),
('tool', 'bandwidth-server'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'allocate-udp-ports-from': KeyInfo(default=2000),
- 'authenticate': KeyInfo(default=True),
- 'enabled': KeyInfo(default=True),
- 'max-sessions': KeyInfo(default=100),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'allocate-udp-ports-from': KeyInfo(default=2000),
+ 'authenticate': KeyInfo(default=True),
+ 'enabled': KeyInfo(default=True),
+ 'max-sessions': KeyInfo(default=100),
+ },
+ ),
),
('tool', 'e-mail'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'address': KeyInfo(default='0.0.0.0'),
- 'from': KeyInfo(default='<>'),
- 'password': KeyInfo(default=''),
- 'port': KeyInfo(default=25),
- 'start-tls': KeyInfo(default=False),
- 'tls': KeyInfo(default=False),
- 'user': KeyInfo(default=''),
- },
+ versioned=[
+ ('7.12', '>=', VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'from': KeyInfo(default='<>'),
+ 'password': KeyInfo(default=''),
+ 'port': KeyInfo(default=25),
+ 'server': KeyInfo(default='0.0.0.0'),
+ 'start-tls': KeyInfo(default=False),
+ 'tls': KeyInfo(default=False),
+ 'user': KeyInfo(default=''),
+ 'vfr': KeyInfo(default=''),
+ },
+ )),
+ ('7.12', '<', VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'address': KeyInfo(default='0.0.0.0'),
+ 'from': KeyInfo(default='<>'),
+ 'password': KeyInfo(default=''),
+ 'port': KeyInfo(default=25),
+ 'start-tls': KeyInfo(default=False),
+ 'tls': KeyInfo(default=False),
+ 'user': KeyInfo(default=''),
+ 'vfr': KeyInfo(default=''),
+ },
+ )),
+ ],
),
('tool', 'graphing'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'page-refresh': KeyInfo(default=300),
- 'store-every': KeyInfo(default='5min'),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'page-refresh': KeyInfo(default=300),
+ 'store-every': KeyInfo(default='5min'),
+ },
+ ),
+ ),
+ ('tool', 'graphing', 'interface'): APIData(
+ versioned=[
+ ('7', '>=', VersionedAPIData(
+ fully_understood=True,
+ fields={
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'allow-address': KeyInfo(default='0.0.0.0/0'),
+ 'interface': KeyInfo(default='all'),
+ 'store-on-disk': KeyInfo(default=True),
+ },
+ )),
+ ],
+ ),
+ ('tool', 'graphing', 'resource'): APIData(
+ versioned=[
+ ('7', '>=', VersionedAPIData(
+ fully_understood=True,
+ fields={
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'allow-address': KeyInfo(default='0.0.0.0/0'),
+ 'store-on-disk': KeyInfo(default=True),
+ },
+ )),
+ ],
),
('tool', 'mac-server'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'allowed-interface-list': KeyInfo(),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'allowed-interface-list': KeyInfo(),
+ },
+ ),
),
('tool', 'mac-server', 'mac-winbox'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'allowed-interface-list': KeyInfo(),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'allowed-interface-list': KeyInfo(),
+ },
+ ),
),
('tool', 'mac-server', 'ping'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'enabled': KeyInfo(default=True),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'enabled': KeyInfo(default=True),
+ },
+ ),
+ ),
+ ('tool', 'netwatch'): APIData(
+ versioned=[
+ ('7', '>=', VersionedAPIData(
+ fully_understood=True,
+ fields={
+ 'certificate': KeyInfo(),
+ 'check-certificate': KeyInfo(),
+ 'comment': KeyInfo(),
+ 'disabled': KeyInfo(default=False),
+ 'down-script': KeyInfo(),
+ 'host': KeyInfo(required=True),
+ 'http-codes': KeyInfo(),
+ 'interval': KeyInfo(),
+ 'name': KeyInfo(),
+ 'packet-count': KeyInfo(),
+ 'packet-interval': KeyInfo(),
+ 'packet-size': KeyInfo(),
+ 'port': KeyInfo(),
+ 'src-address': KeyInfo(),
+ 'start-delay': KeyInfo(),
+ 'startup-delay': KeyInfo(),
+ 'test-script': KeyInfo(),
+ 'thr-avg': KeyInfo(),
+ 'thr-http-time': KeyInfo(),
+ 'thr-jitter': KeyInfo(),
+ 'thr-loss-count': KeyInfo(),
+ 'thr-loss-percent': KeyInfo(),
+ 'thr-max': KeyInfo(),
+ 'thr-stdev': KeyInfo(),
+ 'thr-tcp-conn-time': KeyInfo(),
+ 'timeout': KeyInfo(),
+ 'type': KeyInfo(default='simple'),
+ 'up-script': KeyInfo(),
+ },
+ )),
+ ],
),
('tool', 'romon'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'enabled': KeyInfo(default=False),
- 'id': KeyInfo(default='00:00:00:00:00:00'),
- 'secrets': KeyInfo(default=''),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'enabled': KeyInfo(default=False),
+ 'id': KeyInfo(default='00:00:00:00:00:00'),
+ 'secrets': KeyInfo(default=''),
+ },
+ ),
),
('tool', 'romon', 'port'): APIData(
- fields={
- 'cost': KeyInfo(),
- 'disabled': KeyInfo(),
- 'forbid': KeyInfo(),
- 'interface': KeyInfo(),
- 'secrets': KeyInfo(),
- },
+ unversioned=VersionedAPIData(
+ fields={
+ 'cost': KeyInfo(),
+ 'disabled': KeyInfo(),
+ 'forbid': KeyInfo(),
+ 'interface': KeyInfo(),
+ 'secrets': KeyInfo(),
+ },
+ ),
),
('tool', 'sms'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'allowed-number': KeyInfo(default=''),
- 'auto-erase': KeyInfo(default=False),
- 'channel': KeyInfo(default=0),
- 'port': KeyInfo(default='none'),
- 'receive-enabled': KeyInfo(default=False),
- 'secret': KeyInfo(default=''),
- 'sim-pin': KeyInfo(default=''),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'allowed-number': KeyInfo(default=''),
+ 'auto-erase': KeyInfo(default=False),
+ 'channel': KeyInfo(default=0),
+ 'port': KeyInfo(default='none'),
+ 'receive-enabled': KeyInfo(default=False),
+ 'secret': KeyInfo(default=''),
+ 'sim-pin': KeyInfo(default=''),
+ },
+ ),
),
('tool', 'sniffer'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'file-limit': KeyInfo(default='1000KiB'),
- 'file-name': KeyInfo(default=''),
- 'filter-cpu': KeyInfo(default=''),
- 'filter-direction': KeyInfo(default='any'),
- 'filter-interface': KeyInfo(default=''),
- 'filter-ip-address': KeyInfo(default=''),
- 'filter-ip-protocol': KeyInfo(default=''),
- 'filter-ipv6-address': KeyInfo(default=''),
- 'filter-mac-address': KeyInfo(default=''),
- 'filter-mac-protocol': KeyInfo(default=''),
- 'filter-operator-between-entries': KeyInfo(default='or'),
- 'filter-port': KeyInfo(default=''),
- 'filter-size': KeyInfo(default=''),
- 'filter-stream': KeyInfo(default=False),
- 'memory-limit': KeyInfo(default='100KiB'),
- 'memory-scroll': KeyInfo(default=True),
- 'only-headers': KeyInfo(default=False),
- 'streaming-enabled': KeyInfo(default=False),
- 'streaming-server': KeyInfo(default='0.0.0.0:37008'),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'file-limit': KeyInfo(default='1000KiB'),
+ 'file-name': KeyInfo(default=''),
+ 'filter-cpu': KeyInfo(default=''),
+ 'filter-direction': KeyInfo(default='any'),
+ 'filter-interface': KeyInfo(default=''),
+ 'filter-ip-address': KeyInfo(default=''),
+ 'filter-ip-protocol': KeyInfo(default=''),
+ 'filter-ipv6-address': KeyInfo(default=''),
+ 'filter-mac-address': KeyInfo(default=''),
+ 'filter-mac-protocol': KeyInfo(default=''),
+ 'filter-operator-between-entries': KeyInfo(default='or'),
+ 'filter-port': KeyInfo(default=''),
+ 'filter-size': KeyInfo(default=''),
+ 'filter-stream': KeyInfo(default=False),
+ 'memory-limit': KeyInfo(default='100KiB'),
+ 'memory-scroll': KeyInfo(default=True),
+ 'only-headers': KeyInfo(default=False),
+ 'streaming-enabled': KeyInfo(default=False),
+ 'streaming-server': KeyInfo(default='0.0.0.0:37008'),
+ },
+ ),
),
('tool', 'traffic-generator'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'latency-distribution-max': KeyInfo(default='100us'),
- 'measure-out-of-order': KeyInfo(default=True),
- 'stats-samples-to-keep': KeyInfo(default=100),
- 'test-id': KeyInfo(default=0),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'latency-distribution-max': KeyInfo(default='100us'),
+ 'measure-out-of-order': KeyInfo(default=True),
+ 'stats-samples-to-keep': KeyInfo(default=100),
+ 'test-id': KeyInfo(default=0),
+ },
+ ),
+ ),
+ ('user',): APIData(
+ unversioned=VersionedAPIData(
+ primary_keys=('name', ),
+ fully_understood=True,
+ fields={
+ 'address': KeyInfo(),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'expired': KeyInfo(read_only=True),
+ 'group': KeyInfo(),
+ 'last-logged-in': KeyInfo(read_only=True),
+ 'name': KeyInfo(),
+ 'password': KeyInfo(write_only=True),
+ },
+ ),
),
('user', 'aaa'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'accounting': KeyInfo(default=True),
- 'default-group': KeyInfo(default='read'),
- 'exclude-groups': KeyInfo(default=''),
- 'interim-update': KeyInfo(default='0s'),
- 'use-radius': KeyInfo(default=False),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'accounting': KeyInfo(default=True),
+ 'default-group': KeyInfo(default='read'),
+ 'exclude-groups': KeyInfo(default=''),
+ 'interim-update': KeyInfo(default='0s'),
+ 'use-radius': KeyInfo(default=False),
+ },
+ ),
+ ),
+ ('user', 'settings'): APIData(
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'minimum-categories': KeyInfo(),
+ 'minimum-password-length': KeyInfo(),
+ },
+ ),
),
('queue', 'interface'): APIData(
- primary_keys=('interface', ),
- fully_understood=True,
- fixed_entries=True,
- fields={
- 'interface': KeyInfo(required=True),
- 'queue': KeyInfo(required=True),
- },
+ unversioned=VersionedAPIData(
+ primary_keys=('interface', ),
+ fully_understood=True,
+ fixed_entries=True,
+ fields={
+ 'interface': KeyInfo(required=True),
+ 'queue': KeyInfo(required=True),
+ },
+ ),
),
('queue', 'tree'): APIData(
- primary_keys=('name', ),
- fully_understood=True,
- fields={
- 'bucket-size': KeyInfo(default='0.1'),
- 'burst-limit': KeyInfo(default=0),
- 'burst-threshold': KeyInfo(default=0),
- 'burst-time': KeyInfo(default='0s'),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'disabled': KeyInfo(default=False),
- 'limit-at': KeyInfo(default=0),
- 'max-limit': KeyInfo(default=0),
- 'name': KeyInfo(),
- 'packet-mark': KeyInfo(default=''),
- 'parent': KeyInfo(required=True),
- 'priority': KeyInfo(default=8),
- 'queue': KeyInfo(default='default-small'),
- },
+ unversioned=VersionedAPIData(
+ primary_keys=('name', ),
+ fully_understood=True,
+ fields={
+ 'bucket-size': KeyInfo(default='0.1'),
+ 'burst-limit': KeyInfo(default=0),
+ 'burst-threshold': KeyInfo(default=0),
+ 'burst-time': KeyInfo(default='0s'),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'limit-at': KeyInfo(default=0),
+ 'max-limit': KeyInfo(default=0),
+ 'name': KeyInfo(),
+ 'packet-mark': KeyInfo(default=''),
+ 'parent': KeyInfo(required=True),
+ 'priority': KeyInfo(default=8),
+ 'queue': KeyInfo(default='default-small'),
+ },
+ ),
),
('interface', 'ethernet', 'switch'): APIData(
- fixed_entries=True,
- primary_keys=('name', ),
- fully_understood=True,
- fields={
- 'cpu-flow-control': KeyInfo(default=True),
- 'mirror-source': KeyInfo(default='none'),
- 'mirror-target': KeyInfo(default='none'),
- 'name': KeyInfo(),
- },
+ unversioned=VersionedAPIData(
+ fixed_entries=True,
+ primary_keys=('name', ),
+ fully_understood=True,
+ fields={
+ 'cpu-flow-control': KeyInfo(default=True),
+ 'mirror-source': KeyInfo(default='none'),
+ 'mirror-target': KeyInfo(default='none'),
+ 'name': KeyInfo(),
+ },
+ ),
),
('interface', 'ethernet', 'switch', 'port'): APIData(
- fixed_entries=True,
- primary_keys=('name', ),
- fully_understood=True,
- fields={
- 'default-vlan-id': KeyInfo(),
- 'name': KeyInfo(),
- 'vlan-header': KeyInfo(default='leave-as-is'),
- 'vlan-mode': KeyInfo(default='disabled'),
- },
+ unversioned=VersionedAPIData(
+ fixed_entries=True,
+ primary_keys=('name', ),
+ fully_understood=True,
+ fields={
+ 'default-vlan-id': KeyInfo(),
+ 'name': KeyInfo(),
+ 'vlan-header': KeyInfo(default='leave-as-is'),
+ 'vlan-mode': KeyInfo(default='disabled'),
+ },
+ ),
),
('ip', 'dhcp-client', 'option'): APIData(
- fixed_entries=True,
- primary_keys=('name', ),
- fully_understood=True,
- fields={
- 'code': KeyInfo(),
- 'name': KeyInfo(),
- 'value': KeyInfo(),
- },
+ unversioned=VersionedAPIData(
+ fixed_entries=True,
+ primary_keys=('name', ),
+ fully_understood=True,
+ fields={
+ 'code': KeyInfo(),
+ 'name': KeyInfo(),
+ 'value': KeyInfo(),
+ },
+ ),
),
('ppp', 'profile'): APIData(
- has_identifier=True,
- fields={
- 'address-list': KeyInfo(),
- 'bridge': KeyInfo(can_disable=True),
- 'bridge-horizon': KeyInfo(can_disable=True),
- 'bridge-learning': KeyInfo(),
- 'bridge-path-cost': KeyInfo(can_disable=True),
- 'bridge-port-priority': KeyInfo(can_disable=True),
- 'change-tcp-mss': KeyInfo(),
- 'dns-server': KeyInfo(can_disable=True),
- 'idle-timeout': KeyInfo(can_disable=True),
- 'incoming-filter': KeyInfo(can_disable=True),
- 'insert-queue-before': KeyInfo(can_disable=True),
- 'interface-list': KeyInfo(can_disable=True),
- 'local-address': KeyInfo(can_disable=True),
- 'name': KeyInfo(),
- 'on-down': KeyInfo(),
- 'on-up': KeyInfo(),
- 'only-one': KeyInfo(),
- 'outgoing-filter': KeyInfo(can_disable=True),
- 'parent-queue': KeyInfo(can_disable=True),
- 'queue-type': KeyInfo(can_disable=True),
- 'rate-limit': KeyInfo(can_disable=True),
- 'remote-address': KeyInfo(can_disable=True),
- 'session-timeout': KeyInfo(can_disable=True),
- 'use-compression': KeyInfo(),
- 'use-encryption': KeyInfo(),
- 'use-ipv6': KeyInfo(),
- 'use-mpls': KeyInfo(),
- 'use-upnp': KeyInfo(),
- 'wins-server': KeyInfo(can_disable=True),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ 'address-list': KeyInfo(default=''),
+ 'bridge': KeyInfo(can_disable=True),
+ 'bridge-horizon': KeyInfo(can_disable=True),
+ 'bridge-learning': KeyInfo(default='default'),
+ 'bridge-path-cost': KeyInfo(can_disable=True),
+ 'bridge-port-priority': KeyInfo(can_disable=True),
+ 'change-tcp-mss': KeyInfo(default=True),
+ 'dns-server': KeyInfo(can_disable=True),
+ 'idle-timeout': KeyInfo(can_disable=True),
+ 'incoming-filter': KeyInfo(can_disable=True),
+ 'insert-queue-before': KeyInfo(can_disable=True),
+ 'interface-list': KeyInfo(can_disable=True),
+ 'local-address': KeyInfo(can_disable=True),
+ 'name': KeyInfo(required=True),
+ 'on-down': KeyInfo(default=''),
+ 'on-up': KeyInfo(default=''),
+ 'only-one': KeyInfo(default='default'),
+ 'outgoing-filter': KeyInfo(can_disable=True),
+ 'parent-queue': KeyInfo(can_disable=True),
+ 'queue-type': KeyInfo(can_disable=True),
+ 'rate-limit': KeyInfo(can_disable=True),
+ 'remote-address': KeyInfo(can_disable=True),
+ 'session-timeout': KeyInfo(can_disable=True),
+ 'use-compression': KeyInfo(default='default'),
+ 'use-encryption': KeyInfo(default='default'),
+ 'use-ipv6': KeyInfo(default=True),
+ 'use-mpls': KeyInfo(default='default'),
+ 'use-upnp': KeyInfo(default='default'),
+ 'wins-server': KeyInfo(can_disable=True),
+ },
+ ),
),
('queue', 'type'): APIData(
- has_identifier=True,
- fields={
- 'kind': KeyInfo(),
- 'mq-pfifo-limit': KeyInfo(),
- 'name': KeyInfo(),
- 'pcq-burst-rate': KeyInfo(),
- 'pcq-burst-threshold': KeyInfo(),
- 'pcq-burst-time': KeyInfo(),
- 'pcq-classifier': KeyInfo(),
- 'pcq-dst-address-mask': KeyInfo(),
- 'pcq-dst-address6-mask': KeyInfo(),
- 'pcq-limit': KeyInfo(),
- 'pcq-rate': KeyInfo(),
- 'pcq-src-address-mask': KeyInfo(),
- 'pcq-src-address6-mask': KeyInfo(),
- 'pcq-total-limit': KeyInfo(),
- 'pfifo-limit': KeyInfo(),
- 'red-avg-packet': KeyInfo(),
- 'red-burst': KeyInfo(),
- 'red-limit': KeyInfo(),
- 'red-max-threshold': KeyInfo(),
- 'red-min-threshold': KeyInfo(),
- 'sfq-allot': KeyInfo(),
- 'sfq-perturb': KeyInfo(),
- },
+ unversioned=VersionedAPIData(
+ has_identifier=True,
+ fields={
+ 'kind': KeyInfo(),
+ 'mq-pfifo-limit': KeyInfo(),
+ 'name': KeyInfo(),
+ 'pcq-burst-rate': KeyInfo(),
+ 'pcq-burst-threshold': KeyInfo(),
+ 'pcq-burst-time': KeyInfo(),
+ 'pcq-classifier': KeyInfo(),
+ 'pcq-dst-address-mask': KeyInfo(),
+ 'pcq-dst-address6-mask': KeyInfo(),
+ 'pcq-limit': KeyInfo(),
+ 'pcq-rate': KeyInfo(),
+ 'pcq-src-address-mask': KeyInfo(),
+ 'pcq-src-address6-mask': KeyInfo(),
+ 'pcq-total-limit': KeyInfo(),
+ 'pfifo-limit': KeyInfo(),
+ 'red-avg-packet': KeyInfo(),
+ 'red-burst': KeyInfo(),
+ 'red-limit': KeyInfo(),
+ 'red-max-threshold': KeyInfo(),
+ 'red-min-threshold': KeyInfo(),
+ 'sfq-allot': KeyInfo(),
+ 'sfq-perturb': KeyInfo(),
+ },
+ ),
+ ),
+ ('routing', 'bgp', 'connection'): APIData(
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ fields={
+ 'as': KeyInfo(),
+ 'add-path-out': KeyInfo(),
+ 'address-families': KeyInfo(),
+ 'cisco-vpls-nlri-len-fmt': KeyInfo(),
+ 'cluster-id': KeyInfo(),
+ 'comment': KeyInfo(),
+ 'connect': KeyInfo(default=True),
+ 'disabled': KeyInfo(default=False),
+ 'hold-time': KeyInfo(),
+ 'input.accept-communities': KeyInfo(),
+ 'input.accept-ext-communities': KeyInfo(),
+ 'input.accept-large-communities': KeyInfo(),
+ 'input.accpet-nlri': KeyInfo(),
+ 'input.accept-unknown': KeyInfo(),
+ 'input.affinity': KeyInfo(),
+ 'input.allow-as': KeyInfo(),
+ 'input.filter': KeyInfo(),
+ 'input.ignore-as-path-len': KeyInfo(),
+ 'input.limit-process-routes-ipv4': KeyInfo(),
+ 'input.limit-process-routes-ipv6': KeyInfo(),
+ 'keepalive-time': KeyInfo(),
+ 'listen': KeyInfo(default=True),
+ 'local.address': KeyInfo(),
+ 'local.port': KeyInfo(),
+ 'local.role': KeyInfo(required=True),
+ 'local.ttl': KeyInfo(),
+ 'multihop': KeyInfo(),
+ 'name': KeyInfo(required=True),
+ 'nexthop-choice': KeyInfo(),
+ 'output.affinity': KeyInfo(),
+ 'output.as-override': KeyInfo(),
+ 'output.default-originate': KeyInfo(),
+ 'output.default-prepend': KeyInfo(),
+ 'output.filter-chain': KeyInfo(),
+ 'output.filter-select': KeyInfo(),
+ 'output.keep-sent-attributes': KeyInfo(),
+ 'output.network': KeyInfo(),
+ 'output.no-client-to-client-reflection': KeyInfo(),
+ 'output.no-early-cut': KeyInfo(),
+ 'output.redistribute': KeyInfo(),
+ 'output.remote-private-as': KeyInfo(),
+ 'remote.address': KeyInfo(required=True),
+ 'remote.port': KeyInfo(),
+ 'remote.as': KeyInfo(),
+ 'remote.allowed-as': KeyInfo(),
+ 'remote.ttl': KeyInfo(),
+ 'router-id': KeyInfo(),
+ 'routing-table': KeyInfo(),
+ 'save-to': KeyInfo(),
+ 'tcp-md5-key': KeyInfo(),
+ 'templates': KeyInfo(),
+ 'use-bfd': KeyInfo(),
+ 'vrf': KeyInfo(),
+ },
+ ),
),
('routing', 'bgp', 'instance'): APIData(
- fixed_entries=True,
- primary_keys=('name', ),
- fully_understood=True,
- fields={
- 'as': KeyInfo(),
- 'client-to-client-reflection': KeyInfo(),
- 'cluster-id': KeyInfo(can_disable=True),
- 'confederation': KeyInfo(can_disable=True),
- 'disabled': KeyInfo(),
- 'ignore-as-path-len': KeyInfo(),
- 'name': KeyInfo(),
- 'out-filter': KeyInfo(),
- 'redistribute-connected': KeyInfo(),
- 'redistribute-ospf': KeyInfo(),
- 'redistribute-other-bgp': KeyInfo(),
- 'redistribute-rip': KeyInfo(),
- 'redistribute-static': KeyInfo(),
- 'router-id': KeyInfo(),
- 'routing-table': KeyInfo(),
- },
+ unversioned=VersionedAPIData(
+ fixed_entries=True,
+ primary_keys=('name', ),
+ fully_understood=True,
+ fields={
+ 'as': KeyInfo(),
+ 'client-to-client-reflection': KeyInfo(),
+ 'cluster-id': KeyInfo(can_disable=True),
+ 'confederation': KeyInfo(can_disable=True),
+ 'disabled': KeyInfo(default=False),
+ 'ignore-as-path-len': KeyInfo(),
+ 'name': KeyInfo(),
+ 'out-filter': KeyInfo(),
+ 'redistribute-connected': KeyInfo(),
+ 'redistribute-ospf': KeyInfo(),
+ 'redistribute-other-bgp': KeyInfo(),
+ 'redistribute-rip': KeyInfo(),
+ 'redistribute-static': KeyInfo(),
+ 'router-id': KeyInfo(),
+ 'routing-table': KeyInfo(),
+ },
+ ),
+ ),
+ ('routing', 'bgp', 'template'): APIData(
+ unversioned=VersionedAPIData(
+ primary_keys=('name', ),
+ fully_understood=True,
+ fields={
+ 'add-path-out': KeyInfo(),
+ 'address-families': KeyInfo(default='ip'),
+ 'as': KeyInfo(),
+ 'as-override': KeyInfo(default=False),
+ 'cisco-vpls-nlri-len-fmt': KeyInfo(),
+ 'cluster-id': KeyInfo(),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'hold-time': KeyInfo(default='3m'),
+ 'input.accept-communities': KeyInfo(),
+ 'input.accept-ext-communities': KeyInfo(),
+ 'input.accept-large-communities': KeyInfo(),
+ 'input.accept-unknown': KeyInfo(),
+ 'input.accept-nlri': KeyInfo(),
+ 'input.affinity': KeyInfo(),
+ 'input.allow-as': KeyInfo(),
+ 'input.filter': KeyInfo(),
+ 'input.ignore-as-path-len': KeyInfo(default=False),
+ 'input.limit-nlri-diversity': KeyInfo(),
+ 'input.limit-process-routes-ipv4': KeyInfo(),
+ 'input.limit-process-routes-ipv6': KeyInfo(),
+ 'keepalive-time': KeyInfo(default='3m'),
+ 'multihop': KeyInfo(default=False),
+ 'name': KeyInfo(),
+ 'nexthop-choice': KeyInfo(default='default'),
+ 'output.affinity': KeyInfo(),
+ 'output.default-originate': KeyInfo(default='never'),
+ 'output.default-prepent': KeyInfo(),
+ 'output.filter-chain': KeyInfo(),
+ 'output.filter-select': KeyInfo(),
+ 'output.keep-sent-attributes': KeyInfo(default=False),
+ 'output.network': KeyInfo(),
+ 'output.no-client-to-client-reflection': KeyInfo(),
+ 'output.no-early-cut': KeyInfo(),
+ 'output.redistribute': KeyInfo(),
+ 'remove-private-as': KeyInfo(default=False),
+ 'router-id': KeyInfo(default='main'),
+ 'routing-table': KeyInfo(default='main'),
+ 'save-to': KeyInfo(),
+ 'templates': KeyInfo(),
+ 'use-bfd': KeyInfo(default=False),
+ 'vrf': KeyInfo(default='main'),
+ },
+ ),
),
('system', 'logging', 'action'): APIData(
- fully_understood=True,
- primary_keys=('name',),
- fields={
- 'bsd-syslog': KeyInfo(default=False),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'disk-file-count': KeyInfo(default=2),
- 'disk-file-name': KeyInfo(default='log'),
- 'disk-lines-per-file': KeyInfo(default=1000),
- 'disk-stop-on-full': KeyInfo(default=False),
- 'email-start-tls': KeyInfo(default=False),
- 'email-to': KeyInfo(default=''),
- 'memory-lines': KeyInfo(default=1000),
- 'memory-stop-on-full': KeyInfo(default=False),
- 'name': KeyInfo(),
- 'remember': KeyInfo(default=True),
- 'remote': KeyInfo(default='0.0.0.0'),
- 'remote-port': KeyInfo(default=514),
- 'src-address': KeyInfo(default='0.0.0.0'),
- 'syslog-facility': KeyInfo(default='daemon'),
- 'syslog-severity': KeyInfo(default='auto'),
- 'syslog-time-format': KeyInfo(default='bsd-syslog'),
- 'target': KeyInfo(required=True),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name',),
+ fields={
+ 'bsd-syslog': KeyInfo(default=False),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disk-file-count': KeyInfo(default=2),
+ 'disk-file-name': KeyInfo(default='log'),
+ 'disk-lines-per-file': KeyInfo(default=1000),
+ 'disk-stop-on-full': KeyInfo(default=False),
+ 'email-start-tls': KeyInfo(default=False),
+ 'email-to': KeyInfo(default=''),
+ 'memory-lines': KeyInfo(default=1000),
+ 'memory-stop-on-full': KeyInfo(default=False),
+ 'name': KeyInfo(),
+ 'remember': KeyInfo(default=True),
+ 'remote': KeyInfo(default='0.0.0.0'),
+ 'remote-port': KeyInfo(default=514),
+ 'src-address': KeyInfo(default='0.0.0.0'),
+ 'syslog-facility': KeyInfo(default='daemon'),
+ 'syslog-severity': KeyInfo(default='auto'),
+ 'syslog-time-format': KeyInfo(default='bsd-syslog'),
+ 'target': KeyInfo(required=True),
+ },
+ ),
),
('user', 'group'): APIData(
- fixed_entries=True,
- primary_keys=('name', ),
- fully_understood=True,
- fields={
- 'name': KeyInfo(),
- 'policy': KeyInfo(),
- 'skin': KeyInfo(default='default'),
- },
+ unversioned=VersionedAPIData(
+ primary_keys=('name', ),
+ fully_understood=True,
+ fields={
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'name': KeyInfo(),
+ 'policy': KeyInfo(),
+ 'skin': KeyInfo(default='default'),
+ },
+ ),
),
('caps-man', 'manager'): APIData(
- single_value=True,
- fully_understood=True,
- fields={
- 'ca-certificate': KeyInfo(default='none'),
- 'certificate': KeyInfo(default='none'),
- 'enabled': KeyInfo(default=False),
- 'package-path': KeyInfo(default=''),
- 'require-peer-certificate': KeyInfo(default=False),
- 'upgrade-policy': KeyInfo(default='none'),
- },
+ unversioned=VersionedAPIData(
+ single_value=True,
+ fully_understood=True,
+ fields={
+ 'ca-certificate': KeyInfo(default='none'),
+ 'certificate': KeyInfo(default='none'),
+ 'enabled': KeyInfo(default=False),
+ 'package-path': KeyInfo(default=''),
+ 'require-peer-certificate': KeyInfo(default=False),
+ 'upgrade-policy': KeyInfo(default='none'),
+ },
+ ),
),
('ip', 'firewall', 'service-port'): APIData(
- primary_keys=('name', ),
- fully_understood=True,
- fields={
- 'disabled': KeyInfo(default=False),
- 'name': KeyInfo(),
- 'ports': KeyInfo(),
- 'sip-direct-media': KeyInfo(),
- 'sip-timeout': KeyInfo(),
- },
+ unversioned=VersionedAPIData(
+ primary_keys=('name', ),
+ fully_understood=True,
+ fields={
+ 'disabled': KeyInfo(default=False),
+ 'name': KeyInfo(),
+ 'ports': KeyInfo(),
+ 'sip-direct-media': KeyInfo(),
+ 'sip-timeout': KeyInfo(),
+ },
+ ),
),
('ip', 'firewall', 'layer7-protocol'): APIData(
- primary_keys=('name', ),
- fully_understood=True,
- fields={
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'name': KeyInfo(),
- 'regexp': KeyInfo(),
- },
+ unversioned=VersionedAPIData(
+ primary_keys=('name', ),
+ fully_understood=True,
+ fields={
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'name': KeyInfo(),
+ 'regexp': KeyInfo(),
+ },
+ ),
),
('ip', 'hotspot', 'service-port'): APIData(
- fixed_entries=True,
- primary_keys=('name', ),
- fully_understood=True,
- fields={
- 'disabled': KeyInfo(default=False),
- 'name': KeyInfo(),
- 'ports': KeyInfo(),
- },
+ unversioned=VersionedAPIData(
+ fixed_entries=True,
+ primary_keys=('name', ),
+ fully_understood=True,
+ fields={
+ 'disabled': KeyInfo(default=False),
+ 'name': KeyInfo(),
+ 'ports': KeyInfo(),
+ },
+ ),
),
('ip', 'ipsec', 'policy'): APIData(
- fully_understood=True,
- fields={
- 'action': KeyInfo(default='encrypt'),
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'disabled': KeyInfo(default=False),
- 'dst-address': KeyInfo(),
- 'dst-port': KeyInfo(default='any'),
- 'group': KeyInfo(can_disable=True, remove_value='default'),
- 'ipsec-protocols': KeyInfo(default='esp'),
- 'level': KeyInfo(default='require'),
- 'peer': KeyInfo(),
- 'proposal': KeyInfo(default='default'),
- 'protocol': KeyInfo(default='all'),
- 'src-address': KeyInfo(),
- 'src-port': KeyInfo(default='any'),
- 'template': KeyInfo(can_disable=True, remove_value=False),
- # the tepmlate field can't really be changed once the item is created. This config captures the behavior best as it can
- # i.e. tepmplate=yes is shown, tepmlate=no is hidden
- 'tunnel': KeyInfo(default=False),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ fields={
+ 'action': KeyInfo(default='encrypt'),
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'dst-address': KeyInfo(),
+ 'dst-port': KeyInfo(default='any'),
+ 'group': KeyInfo(can_disable=True, remove_value='default'),
+ 'ipsec-protocols': KeyInfo(default='esp'),
+ 'level': KeyInfo(default='require'),
+ 'peer': KeyInfo(),
+ 'proposal': KeyInfo(default='default'),
+ 'protocol': KeyInfo(default='all'),
+ 'src-address': KeyInfo(),
+ 'src-port': KeyInfo(default='any'),
+ 'template': KeyInfo(can_disable=True, remove_value=False),
+ # the tepmlate field can't really be changed once the item is created. This config captures the behavior best as it can
+ # i.e. tepmplate=yes is shown, tepmlate=no is hidden
+ 'tunnel': KeyInfo(default=False),
+ },
+ ),
),
('ip', 'service'): APIData(
- fixed_entries=True,
- primary_keys=('name', ),
- fully_understood=True,
- fields={
- 'address': KeyInfo(),
- 'certificate': KeyInfo(),
- 'disabled': KeyInfo(default=False),
- 'name': KeyInfo(),
- 'port': KeyInfo(),
- 'tls-version': KeyInfo(),
- },
+ unversioned=VersionedAPIData(
+ fixed_entries=True,
+ primary_keys=('name', ),
+ fully_understood=True,
+ fields={
+ 'address': KeyInfo(),
+ 'certificate': KeyInfo(),
+ 'disabled': KeyInfo(default=False),
+ 'name': KeyInfo(),
+ 'port': KeyInfo(),
+ 'tls-version': KeyInfo(),
+ },
+ ),
),
('system', 'logging'): APIData(
- fully_understood=True,
- fields={
- 'action': KeyInfo(default='memory'),
- 'disabled': KeyInfo(default=False),
- 'prefix': KeyInfo(default=''),
- 'topics': KeyInfo(default=''),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ fields={
+ 'action': KeyInfo(default='memory'),
+ 'disabled': KeyInfo(default=False),
+ 'prefix': KeyInfo(default=''),
+ 'topics': KeyInfo(default=''),
+ },
+ ),
),
('system', 'resource', 'irq'): APIData(
- has_identifier=True,
- fields={
- 'cpu': KeyInfo(),
- },
+ unversioned=VersionedAPIData(
+ has_identifier=True,
+ fields={
+ 'cpu': KeyInfo(),
+ },
+ ),
),
('system', 'scheduler'): APIData(
- fully_understood=True,
- primary_keys=('name', ),
- fields={
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'disabled': KeyInfo(default=False),
- 'interval': KeyInfo(default='0s'),
- 'name': KeyInfo(),
- 'on-event': KeyInfo(default=''),
- 'policy': KeyInfo(default='ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon'),
- 'start-date': KeyInfo(),
- 'start-time': KeyInfo(),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name', ),
+ fields={
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'disabled': KeyInfo(default=False),
+ 'interval': KeyInfo(default='0s'),
+ 'name': KeyInfo(),
+ 'on-event': KeyInfo(default=''),
+ 'policy': KeyInfo(default='ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon'),
+ 'start-date': KeyInfo(),
+ 'start-time': KeyInfo(),
+ },
+ ),
),
('system', 'script'): APIData(
- fully_understood=True,
- primary_keys=('name',),
- fields={
- 'comment': KeyInfo(can_disable=True, remove_value=''),
- 'dont-require-permissions': KeyInfo(default=False),
- 'name': KeyInfo(),
- 'owner': KeyInfo(),
- 'policy': KeyInfo(default='ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon'),
- 'source': KeyInfo(default=''),
- },
+ unversioned=VersionedAPIData(
+ fully_understood=True,
+ primary_keys=('name',),
+ fields={
+ 'comment': KeyInfo(can_disable=True, remove_value=''),
+ 'dont-require-permissions': KeyInfo(default=False),
+ 'name': KeyInfo(),
+ 'owner': KeyInfo(),
+ 'policy': KeyInfo(default='ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon'),
+ 'source': KeyInfo(default=''),
+ },
+ ),
),
}
diff --git a/ansible_collections/community/routeros/plugins/module_utils/api.py b/ansible_collections/community/routeros/plugins/module_utils/api.py
index 5c598f3eb..6c276d730 100644
--- a/ansible_collections/community/routeros/plugins/module_utils/api.py
+++ b/ansible_collections/community/routeros/plugins/module_utils/api.py
@@ -97,6 +97,7 @@ def _ros_api_connect(module, username, password, host, port, use_tls, force_no_c
def create_api(module):
+ """Create an API object."""
return _ros_api_connect(
module,
module.params['username'],
@@ -111,3 +112,9 @@ def create_api(module):
module.params['encoding'],
module.params['timeout'],
)
+
+
+def get_api_version(api):
+ """Given an API object, query the system's version."""
+ system_info = list(api.path().join('system', 'resource'))[0]
+ return system_info['version'].split(' ', 1)[0]
diff --git a/ansible_collections/community/routeros/plugins/modules/api.py b/ansible_collections/community/routeros/plugins/modules/api.py
index f9c619fc1..4857a3cd9 100644
--- a/ansible_collections/community/routeros/plugins/modules/api.py
+++ b/ansible_collections/community/routeros/plugins/modules/api.py
@@ -17,7 +17,7 @@ description:
- Ansible module for RouterOS API with the Python C(librouteros) library.
- This module can add, remove, update, query and execute arbitrary command in RouterOS via API.
notes:
- - I(add), I(remove), I(update), I(cmd) and I(query) are mutually exclusive.
+ - O(add), O(remove), O(update), O(cmd), and O(query) are mutually exclusive.
- Use the M(community.routeros.api_modify) and M(community.routeros.api_find_and_modify) modules
for more specific modifications, and the M(community.routeros.api_info) module for a more controlled
way of returning all entries for a path.
@@ -40,26 +40,26 @@ options:
description:
- Main path for all other arguments.
- If other arguments are not set, api will return all items in selected path.
- - Example C(ip address). Equivalent of RouterOS CLI C(/ip address print).
+ - Example V(ip address). Equivalent of RouterOS CLI C(/ip address print).
required: true
type: str
add:
description:
- Will add selected arguments in selected path to RouterOS config.
- - Example C(address=1.1.1.1/32 interface=ether1).
+ - Example V(address=1.1.1.1/32 interface=ether1).
- Equivalent in RouterOS CLI C(/ip address add address=1.1.1.1/32 interface=ether1).
type: str
remove:
description:
- Remove config/value from RouterOS by '.id'.
- - Example C(*03) will remove config/value with C(id=*03) in selected path.
+ - Example V(*03) will remove config/value with C(id=*03) in selected path.
- Equivalent in RouterOS CLI C(/ip address remove numbers=1).
- Note C(number) in RouterOS CLI is different from C(.id).
type: str
update:
description:
- Update config/value in RouterOS by '.id' in selected path.
- - Example C(.id=*03 address=1.1.1.3/32) and path C(ip address) will replace existing ip address with C(.id=*03).
+ - Example V(.id=*03 address=1.1.1.3/32) and path V(ip address) will replace existing ip address with C(.id=*03).
- Equivalent in RouterOS CLI C(/ip address set address=1.1.1.3/32 numbers=1).
- Note C(number) in RouterOS CLI is different from C(.id).
type: str
@@ -67,11 +67,11 @@ options:
description:
- Query given path for selected query attributes from RouterOS aip.
- WHERE is key word which extend query. WHERE format is key operator value - with spaces.
- - WHERE valid operators are C(==) or C(eq), C(!=) or C(not), C(>) or C(more), C(<) or C(less).
- - Example path C(ip address) and query C(.id address) will return only C(.id) and C(address) for all items in C(ip address) path.
- - Example path C(ip address) and query C(.id address WHERE address == 1.1.1.3/32).
- will return only C(.id) and C(address) for items in C(ip address) path, where address is eq to 1.1.1.3/32.
- - Example path C(interface) and query C(mtu name WHERE mut > 1400) will
+ - WHERE valid operators are V(==) or V(eq), V(!=) or V(not), V(>) or V(more), V(<) or V(less).
+ - Example path V(ip address) and query V(.id address) will return only C(.id) and C(address) for all items in V(ip address) path.
+ - Example path V(ip address) and query V(.id address WHERE address == 1.1.1.3/32).
+ will return only C(.id) and C(address) for items in V(ip address) path, where address is eq to 1.1.1.3/32.
+ - Example path V(interface) and query V(mtu name WHERE mut > 1400) will
return only interfaces C(mtu,name) where mtu is bigger than 1400.
- Equivalent in RouterOS CLI C(/interface print where mtu > 1400).
type: str
@@ -84,65 +84,69 @@ options:
attributes:
description:
- The list of attributes to return.
- - Every attribute used in a I(where) clause need to be listed here.
+ - Every attribute used in a O(extended_query.where[]) clause need to be listed here.
type: list
elements: str
required: true
where:
description:
- Allows to restrict the objects returned.
- - The conditions here must all match. An I(or) condition needs at least one of its conditions to match.
+ - The conditions here must all match. An O(extended_query.where[].or) condition needs at least one of its conditions to match.
type: list
elements: dict
suboptions:
attribute:
description:
- - The attribute to match. Must be part of I(attributes).
- - Either I(or) or all of I(attribute), I(is), and I(value) have to be specified.
+ - The attribute to match. Must be part of O(extended_query.attributes).
+ - Either O(extended_query.where[].or) or all of O(extended_query.where[].attribute), O(extended_query.where[].is),
+ and O(extended_query.where[].value) have to be specified.
type: str
is:
description:
- The operator to use for matching.
- - For equality use C(==) or C(eq). For less use C(<) or C(less). For more use C(>) or C(more).
- - Use C(in) to check whether the value is part of a list. In that case, I(value) must be a list.
- - Either I(or) or all of I(attribute), I(is), and I(value) have to be specified.
+ - For equality use V(==) or V(eq). For less use V(<) or V(less). For more use V(>) or V(more).
+ - Use V(in) to check whether the value is part of a list. In that case, O(extended_query.where[].value) must be a list.
+ - Either O(extended_query.where[].or) or all of O(extended_query.where[].attribute), O(extended_query.where[].is),
+ and O(extended_query.where[].value) have to be specified.
type: str
choices: ["==", "!=", ">", "<", "in", "eq", "not", "more", "less"]
value:
description:
- - The value to compare to. Must be a list for I(is=in).
- - Either I(or) or all of I(attribute), I(is), and I(value) have to be specified.
+ - The value to compare to. Must be a list for O(extended_query.where[].is=in).
+ - Either O(extended_query.where[].or) or all of O(extended_query.where[].attribute), O(extended_query.where[].is),
+ and O(extended_query.where[].value) have to be specified.
type: raw
or:
description:
- A list of conditions so that at least one of them has to match.
- - Either I(or) or all of I(attribute), I(is), and I(value) have to be specified.
+ - Either O(extended_query.where[].or) or all of O(extended_query.where[].attribute), O(extended_query.where[].is),
+ and O(extended_query.where[].value) have to be specified.
type: list
elements: dict
suboptions:
attribute:
description:
- - The attribute to match. Must be part of I(attributes).
+ - The attribute to match. Must be part of O(extended_query.attributes).
type: str
required: true
is:
description:
- The operator to use for matching.
- - For equality use C(==) or C(eq). For less use C(<) or C(less). For more use C(>) or C(more).
- - Use C(in) to check whether the value is part of a list. In that case, I(value) must be a list.
+ - For equality use V(==) or V(eq). For less use V(<) or V(less). For more use V(>) or V(more).
+ - Use V(in) to check whether the value is part of a list. In that case, O(extended_query.where[].or[].value) must be a list.
type: str
choices: ["==", "!=", ">", "<", "in", "eq", "not", "more", "less"]
required: true
value:
description:
- - The value to compare to. Must be a list for I(is=in).
+ - The value to compare to. Must be a list for O(extended_query.where[].or[].is=in).
type: raw
required: true
cmd:
description:
- Execute any/arbitrary command in selected path, after the command we can add C(.id).
- - Example path C(system script) and cmd C(run .id=*03) is equivalent in RouterOS CLI C(/system script run number=0).
- - Example path C(ip address) and cmd C(print) is equivalent in RouterOS CLI C(/ip address print).
+ - Example path V(system script) and cmd V(run .id=*03) is equivalent in RouterOS CLI C(/system script run number=0).
+ - Example path V(ip address) and cmd V(print) is equivalent in RouterOS CLI C(/ip address print).
type: str
seealso:
- ref: ansible_collections.community.routeros.docsite.quoting
@@ -220,7 +224,7 @@ EXAMPLES = '''
ansible.builtin.debug:
msg: '{{ extended_queryout }}'
-- name: Update example - ether2 ip addres with ".id = *14"
+- name: Update example - ether2 ip address with ".id = *14"
community.routeros.api:
hostname: "{{ hostname }}"
password: "{{ password }}"
diff --git a/ansible_collections/community/routeros/plugins/modules/api_facts.py b/ansible_collections/community/routeros/plugins/modules/api_facts.py
index f29723667..296621ea6 100644
--- a/ansible_collections/community/routeros/plugins/modules/api_facts.py
+++ b/ansible_collections/community/routeros/plugins/modules/api_facts.py
@@ -41,9 +41,9 @@ options:
description:
- When supplied, this argument will restrict the facts collected
to a given subset. Possible values for this argument include
- C(all), C(hardware), C(interfaces), and C(routing).
+ V(all), V(hardware), V(interfaces), and V(routing).
- Can specify a list of values to include a larger subset.
- Values can also be used with an initial C(!) to specify that a
+ Values can also be used with an initial V(!) to specify that a
specific subset should not be collected.
required: false
default:
@@ -89,93 +89,93 @@ ansible_facts:
# default
ansible_net_model:
description: The model name returned from the device.
- returned: I(gather_subset) contains C(default)
+ returned: O(gather_subset) contains V(default)
type: str
ansible_net_serialnum:
description: The serial number of the remote device.
- returned: I(gather_subset) contains C(default)
+ returned: O(gather_subset) contains V(default)
type: str
ansible_net_version:
description: The operating system version running on the remote device.
- returned: I(gather_subset) contains C(default)
+ returned: O(gather_subset) contains V(default)
type: str
ansible_net_hostname:
description: The configured hostname of the device.
- returned: I(gather_subset) contains C(default)
+ returned: O(gather_subset) contains V(default)
type: str
ansible_net_arch:
description: The CPU architecture of the device.
- returned: I(gather_subset) contains C(default)
+ returned: O(gather_subset) contains V(default)
type: str
ansible_net_uptime:
description: The uptime of the device.
- returned: I(gather_subset) contains C(default)
+ returned: O(gather_subset) contains V(default)
type: str
ansible_net_cpu_load:
description: Current CPU load.
- returned: I(gather_subset) contains C(default)
+ returned: O(gather_subset) contains V(default)
type: str
# hardware
ansible_net_spacefree_mb:
description: The available disk space on the remote device in MiB.
- returned: I(gather_subset) contains C(hardware)
+ returned: O(gather_subset) contains V(hardware)
type: dict
ansible_net_spacetotal_mb:
description: The total disk space on the remote device in MiB.
- returned: I(gather_subset) contains C(hardware)
+ returned: O(gather_subset) contains V(hardware)
type: dict
ansible_net_memfree_mb:
description: The available free memory on the remote device in MiB.
- returned: I(gather_subset) contains C(hardware)
+ returned: O(gather_subset) contains V(hardware)
type: int
ansible_net_memtotal_mb:
description: The total memory on the remote device in MiB.
- returned: I(gather_subset) contains C(hardware)
+ returned: O(gather_subset) contains V(hardware)
type: int
# interfaces
ansible_net_all_ipv4_addresses:
description: All IPv4 addresses configured on the device.
- returned: I(gather_subset) contains C(interfaces)
+ returned: O(gather_subset) contains V(interfaces)
type: list
ansible_net_all_ipv6_addresses:
description: All IPv6 addresses configured on the device.
- returned: I(gather_subset) contains C(interfaces)
+ returned: O(gather_subset) contains V(interfaces)
type: list
ansible_net_interfaces:
description: A hash of all interfaces running on the system.
- returned: I(gather_subset) contains C(interfaces)
+ returned: O(gather_subset) contains V(interfaces)
type: dict
ansible_net_neighbors:
description: The list of neighbors from the remote device.
- returned: I(gather_subset) contains C(interfaces)
+ returned: O(gather_subset) contains V(interfaces)
type: dict
# routing
ansible_net_bgp_peer:
description: A dictionary with BGP peer information.
- returned: I(gather_subset) contains C(routing)
+ returned: O(gather_subset) contains V(routing)
type: dict
ansible_net_bgp_vpnv4_route:
description: A dictionary with BGP vpnv4 route information.
- returned: I(gather_subset) contains C(routing)
+ returned: O(gather_subset) contains V(routing)
type: dict
ansible_net_bgp_instance:
description: A dictionary with BGP instance information.
- returned: I(gather_subset) contains C(routing)
+ returned: O(gather_subset) contains V(routing)
type: dict
ansible_net_route:
description: A dictionary for routes in all routing tables.
- returned: I(gather_subset) contains C(routing)
+ returned: O(gather_subset) contains V(routing)
type: dict
ansible_net_ospf_instance:
description: A dictionary with OSPF instances.
- returned: I(gather_subset) contains C(routing)
+ returned: O(gather_subset) contains V(routing)
type: dict
ansible_net_ospf_neighbor:
description: A dictionary with OSPF neighbors.
- returned: I(gather_subset) contains C(routing)
+ returned: O(gather_subset) contains V(routing)
type: dict
"""
diff --git a/ansible_collections/community/routeros/plugins/modules/api_find_and_modify.py b/ansible_collections/community/routeros/plugins/modules/api_find_and_modify.py
index 0be3f7039..176c9437f 100644
--- a/ansible_collections/community/routeros/plugins/modules/api_find_and_modify.py
+++ b/ansible_collections/community/routeros/plugins/modules/api_find_and_modify.py
@@ -21,7 +21,7 @@ description:
or change multiple entries in different ways in one step.
notes:
- "If you want to change values based on their old values (like change all comments 'foo' to 'bar') and make sure that
- there are at least N such values, you can use I(require_matches_min=N) together with I(allow_no_matches=true).
+ there are at least N such values, you can use O(require_matches_min=N) together with O(allow_no_matches=true).
This will make the module fail if there are less than N such entries, but not if there is no match. The latter case
is needed for idempotency of the task: once the values have been changed, there should be no further match."
extends_documentation_fragment:
@@ -40,21 +40,21 @@ options:
path:
description:
- Path to query.
- - An example value is C(ip address). This is equivalent to running C(/ip address) in the RouterOS CLI.
+ - An example value is V(ip address). This is equivalent to running C(/ip address) in the RouterOS CLI.
required: true
type: str
find:
description:
- Fields to search for.
- - The module will only consider entries in the given I(path) that match all fields provided here.
- - Use YAML C(~), or prepend keys with C(!), to specify an unset value.
+ - The module will only consider entries in the given O(path) that match all fields provided here.
+ - Use YAML V(~), or prepend keys with V(!), to specify an unset value.
- Note that if the dictionary specified here is empty, every entry in the path will be matched.
required: true
type: dict
values:
description:
- - On all entries matching the conditions in I(find), set the keys of this option to the values specified here.
- - Use YAML C(~), or prepend keys with C(!), to specify to unset a value.
+ - On all entries matching the conditions in O(find), set the keys of this option to the values specified here.
+ - Use YAML V(~), or prepend keys with V(!), to specify to unset a value.
required: true
type: dict
require_matches_min:
@@ -72,7 +72,7 @@ options:
allow_no_matches:
description:
- Whether to allow that no match is found.
- - If not specified, this value is induced from whether I(require_matches_min) is 0 or larger.
+ - If not specified, this value is induced from whether O(require_matches_min) is 0 or larger.
type: bool
seealso:
- module: community.routeros.api
@@ -146,7 +146,7 @@ new_data:
returned: success
match_count:
description:
- - The number of entries that matched the criteria in I(find).
+ - The number of entries that matched the criteria in O(find).
sample: 1
type: int
returned: success
diff --git a/ansible_collections/community/routeros/plugins/modules/api_info.py b/ansible_collections/community/routeros/plugins/modules/api_info.py
index 50228c063..f9a39464f 100644
--- a/ansible_collections/community/routeros/plugins/modules/api_info.py
+++ b/ansible_collections/community/routeros/plugins/modules/api_info.py
@@ -18,9 +18,9 @@ version_added: 2.2.0
description:
- Allows to retrieve information for a path using the API.
- This can be used to backup a path to restore it with the M(community.routeros.api_modify) module.
- - Entries are normalized, dynamic and builtin entries are not returned. Use the I(handle_disabled) and
- I(hide_defaults) options to control normalization, the I(include_dynamic) and I(include_builtin) options to also return
- dynamic resp. builtin entries, and use I(unfiltered) to return all fields including counters.
+ - Entries are normalized, dynamic and builtin entries are not returned. Use the O(handle_disabled) and
+ O(hide_defaults) options to control normalization, the O(include_dynamic) and O(include_builtin) options to also return
+ dynamic resp. builtin entries, and use O(unfiltered) to return all fields including counters.
- B(Note) that this module is still heavily in development, and only supports B(some) paths.
If you want to support new paths, or think you found problems with existing paths, please first
L(create an issue in the community.routeros Issue Tracker,https://github.com/ansible-collections/community.routeros/issues/).
@@ -37,16 +37,18 @@ options:
path:
description:
- Path to query.
- - An example value is C(ip address). This is equivalent to running C(/ip address print) in the RouterOS CLI.
+ - An example value is V(ip address). This is equivalent to running C(/ip address print) in the RouterOS CLI.
required: true
type: str
choices:
# BEGIN PATH LIST
- caps-man aaa
- caps-man access-list
+ - caps-man channel
- caps-man configuration
- caps-man datapath
- caps-man manager
+ - caps-man manager interface
- caps-man provisioning
- caps-man security
- certificate settings
@@ -69,18 +71,47 @@ options:
- interface l2tp-server server
- interface list
- interface list member
+ - interface ovpn-client
- interface ovpn-server server
+ - interface ppp-client
- interface pppoe-client
- interface pptp-server server
- interface sstp-server server
- interface vlan
- interface vrrp
+ - interface wifi
+ - interface wifi aaa
+ - interface wifi access-list
+ - interface wifi cap
+ - interface wifi capsman
+ - interface wifi channel
+ - interface wifi configuration
+ - interface wifi datapath
+ - interface wifi interworking
+ - interface wifi provisioning
+ - interface wifi security
+ - interface wifi steering
+ - interface wifiwave2
+ - interface wifiwave2 aaa
+ - interface wifiwave2 access-list
+ - interface wifiwave2 cap
+ - interface wifiwave2 capsman
+ - interface wifiwave2 channel
+ - interface wifiwave2 configuration
+ - interface wifiwave2 datapath
+ - interface wifiwave2 interworking
+ - interface wifiwave2 provisioning
+ - interface wifiwave2 security
+ - interface wifiwave2 steering
- interface wireguard
- interface wireguard peers
+ - interface wireless
- interface wireless align
- interface wireless cap
+ - interface wireless security-profiles
- interface wireless sniffer
- interface wireless snooper
+ - iot modbus
- ip accounting
- ip accounting web-access
- ip address
@@ -93,6 +124,8 @@ options:
- ip dhcp-server config
- ip dhcp-server lease
- ip dhcp-server network
+ - ip dhcp-server option
+ - ip dhcp-server option sets
- ip dns
- ip dns static
- ip firewall address-list
@@ -123,7 +156,10 @@ options:
- ip tftp settings
- ip traffic-flow
- ip traffic-flow ipfix
+ - ip traffic-flow target
- ip upnp
+ - ip upnp interfaces
+ - ip vrf
- ipv6 address
- ipv6 dhcp-client
- ipv6 dhcp-server
@@ -131,6 +167,7 @@ options:
- ipv6 firewall address-list
- ipv6 firewall filter
- ipv6 firewall mangle
+ - ipv6 firewall nat
- ipv6 firewall raw
- ipv6 nd
- ipv6 nd prefix default
@@ -139,11 +176,19 @@ options:
- mpls
- mpls ldp
- port firmware
+ - port remote-access
- ppp aaa
+ - ppp profile
- queue interface
- queue tree
+ - radius
- radius incoming
+ - routing bgp connection
- routing bgp instance
+ - routing bgp template
+ - routing filter rule
+ - routing filter select-rule
+ - routing id
- routing mme
- routing ospf area
- routing ospf area range
@@ -153,6 +198,8 @@ options:
- routing pimsm interface-template
- routing rip
- routing ripng
+ - routing rule
+ - routing table
- snmp
- snmp community
- system clock
@@ -175,15 +222,20 @@ options:
- tool bandwidth-server
- tool e-mail
- tool graphing
+ - tool graphing interface
+ - tool graphing resource
- tool mac-server
- tool mac-server mac-winbox
- tool mac-server ping
+ - tool netwatch
- tool romon
- tool sms
- tool sniffer
- tool traffic-generator
+ - user
- user aaa
- user group
+ - user settings
# END PATH LIST
unfiltered:
description:
@@ -194,9 +246,9 @@ options:
handle_disabled:
description:
- How to handle unset values.
- - C(exclamation) prepends the keys with C(!) in the output with value C(null).
- - C(null-value) uses the regular key with value C(null).
- - C(omit) omits these values from the result.
+ - V(exclamation) prepends the keys with V(!) in the output with value V(null).
+ - V(null-value) uses the regular key with value V(null).
+ - V(omit) omits these values from the result.
type: str
choices:
- exclamation
@@ -212,17 +264,24 @@ options:
description:
- Whether to include dynamic values.
- By default, they are not returned, and the C(dynamic) keys are omitted.
- - If set to C(true), they are returned as well, and the C(dynamic) keys are returned as well.
+ - If set to V(true), they are returned as well, and the C(dynamic) keys are returned as well.
type: bool
default: false
include_builtin:
description:
- Whether to include builtin values.
- By default, they are not returned, and the C(builtin) keys are omitted.
- - If set to C(true), they are returned as well, and the C(builtin) keys are returned as well.
+ - If set to V(true), they are returned as well, and the C(builtin) keys are returned as well.
type: bool
default: false
version_added: 2.4.0
+ include_read_only:
+ description:
+ - Whether to include read-only fields.
+ - By default, they are not returned.
+ type: bool
+ default: false
+ version_added: 2.10.0
seealso:
- module: community.routeros.api
- module: community.routeros.api_facts
@@ -271,6 +330,7 @@ from ansible_collections.community.routeros.plugins.module_utils.api import (
api_argument_spec,
check_has_library,
create_api,
+ get_api_version,
)
from ansible_collections.community.routeros.plugins.module_utils._api_data import (
@@ -301,6 +361,7 @@ def main():
hide_defaults=dict(type='bool', default=True),
include_dynamic=dict(type='bool', default=False),
include_builtin=dict(type='bool', default=False),
+ include_read_only=dict(type='bool', default=False),
)
module_args.update(api_argument_spec())
@@ -313,14 +374,24 @@ def main():
api = create_api(module)
path = split_path(module.params['path'])
- path_info = PATHS.get(tuple(path))
- if path_info is None:
+ versioned_path_info = PATHS.get(tuple(path))
+ if versioned_path_info is None:
module.fail_json(msg='Path /{path} is not yet supported'.format(path='/'.join(path)))
+ if versioned_path_info.needs_version:
+ api_version = get_api_version(api)
+ supported, not_supported_msg = versioned_path_info.provide_version(api_version)
+ if not supported:
+ msg = 'Path /{path} is not supported for API version {api_version}'.format(path='/'.join(path), api_version=api_version)
+ if not_supported_msg:
+ msg = '{0}: {1}'.format(msg, not_supported_msg)
+ module.fail_json(msg=msg)
+ path_info = versioned_path_info.get_data()
handle_disabled = module.params['handle_disabled']
hide_defaults = module.params['hide_defaults']
include_dynamic = module.params['include_dynamic']
include_builtin = module.params['include_builtin']
+ include_read_only = module.params['include_read_only']
try:
api_path = compose_api_path(api, path)
@@ -344,7 +415,10 @@ def main():
if k not in path_info.fields:
entry.pop(k)
if handle_disabled != 'omit':
- for k in path_info.fields:
+ for k, field_info in path_info.fields.items():
+ if field_info.write_only:
+ entry.pop(k, None)
+ continue
if k not in entry:
if handle_disabled == 'exclamation':
k = '!%s' % k
@@ -355,6 +429,8 @@ def main():
entry.pop(k)
if field_info.absent_value and k not in entry:
entry[k] = field_info.absent_value
+ if not include_read_only and k in entry and field_info.read_only:
+ entry.pop(k)
result.append(entry)
module.exit_json(result=result)
diff --git a/ansible_collections/community/routeros/plugins/modules/api_modify.py b/ansible_collections/community/routeros/plugins/modules/api_modify.py
index 5d410e9fb..d71750073 100644
--- a/ansible_collections/community/routeros/plugins/modules/api_modify.py
+++ b/ansible_collections/community/routeros/plugins/modules/api_modify.py
@@ -24,6 +24,10 @@ description:
- B(Note) that this module is still heavily in development, and only supports B(some) paths.
If you want to support new paths, or think you found problems with existing paths, please first
L(create an issue in the community.routeros Issue Tracker,https://github.com/ansible-collections/community.routeros/issues/).
+notes:
+ - If write-only fields are present in the path, the module is B(not idempotent) in a strict sense,
+ since it is not able to verify the current value of these fields. The behavior the module should
+ assume can be controlled with the O(handle_write_only) option.
requirements:
- Needs L(ordereddict,https://pypi.org/project/ordereddict) for Python 2.6
extends_documentation_fragment:
@@ -42,16 +46,18 @@ options:
path:
description:
- Path to query.
- - An example value is C(ip address). This is equivalent to running modification commands in C(/ip address) in the RouterOS CLI.
+ - An example value is V(ip address). This is equivalent to running modification commands in C(/ip address) in the RouterOS CLI.
required: true
type: str
choices:
# BEGIN PATH LIST
- caps-man aaa
- caps-man access-list
+ - caps-man channel
- caps-man configuration
- caps-man datapath
- caps-man manager
+ - caps-man manager interface
- caps-man provisioning
- caps-man security
- certificate settings
@@ -74,18 +80,47 @@ options:
- interface l2tp-server server
- interface list
- interface list member
+ - interface ovpn-client
- interface ovpn-server server
+ - interface ppp-client
- interface pppoe-client
- interface pptp-server server
- interface sstp-server server
- interface vlan
- interface vrrp
+ - interface wifi
+ - interface wifi aaa
+ - interface wifi access-list
+ - interface wifi cap
+ - interface wifi capsman
+ - interface wifi channel
+ - interface wifi configuration
+ - interface wifi datapath
+ - interface wifi interworking
+ - interface wifi provisioning
+ - interface wifi security
+ - interface wifi steering
+ - interface wifiwave2
+ - interface wifiwave2 aaa
+ - interface wifiwave2 access-list
+ - interface wifiwave2 cap
+ - interface wifiwave2 capsman
+ - interface wifiwave2 channel
+ - interface wifiwave2 configuration
+ - interface wifiwave2 datapath
+ - interface wifiwave2 interworking
+ - interface wifiwave2 provisioning
+ - interface wifiwave2 security
+ - interface wifiwave2 steering
- interface wireguard
- interface wireguard peers
+ - interface wireless
- interface wireless align
- interface wireless cap
+ - interface wireless security-profiles
- interface wireless sniffer
- interface wireless snooper
+ - iot modbus
- ip accounting
- ip accounting web-access
- ip address
@@ -98,6 +133,8 @@ options:
- ip dhcp-server config
- ip dhcp-server lease
- ip dhcp-server network
+ - ip dhcp-server option
+ - ip dhcp-server option sets
- ip dns
- ip dns static
- ip firewall address-list
@@ -128,7 +165,10 @@ options:
- ip tftp settings
- ip traffic-flow
- ip traffic-flow ipfix
+ - ip traffic-flow target
- ip upnp
+ - ip upnp interfaces
+ - ip vrf
- ipv6 address
- ipv6 dhcp-client
- ipv6 dhcp-server
@@ -136,6 +176,7 @@ options:
- ipv6 firewall address-list
- ipv6 firewall filter
- ipv6 firewall mangle
+ - ipv6 firewall nat
- ipv6 firewall raw
- ipv6 nd
- ipv6 nd prefix default
@@ -144,11 +185,19 @@ options:
- mpls
- mpls ldp
- port firmware
+ - port remote-access
- ppp aaa
+ - ppp profile
- queue interface
- queue tree
+ - radius
- radius incoming
+ - routing bgp connection
- routing bgp instance
+ - routing bgp template
+ - routing filter rule
+ - routing filter select-rule
+ - routing id
- routing mme
- routing ospf area
- routing ospf area range
@@ -158,6 +207,8 @@ options:
- routing pimsm interface-template
- routing rip
- routing ripng
+ - routing rule
+ - routing table
- snmp
- snmp community
- system clock
@@ -180,15 +231,20 @@ options:
- tool bandwidth-server
- tool e-mail
- tool graphing
+ - tool graphing interface
+ - tool graphing resource
- tool mac-server
- tool mac-server mac-winbox
- tool mac-server ping
+ - tool netwatch
- tool romon
- tool sms
- tool sniffer
- tool traffic-generator
+ - user
- user aaa
- user group
+ - user settings
# END PATH LIST
data:
description:
@@ -200,15 +256,15 @@ options:
elements: dict
ensure_order:
description:
- - Whether to ensure the same order of the config as present in I(data).
- - Requires I(handle_absent_entries=remove).
+ - Whether to ensure the same order of the config as present in O(data).
+ - Requires O(handle_absent_entries=remove).
type: bool
default: false
handle_absent_entries:
description:
- - How to handle entries that are present in the current config, but not in I(data).
- - C(ignore) ignores them.
- - C(remove) removes them.
+ - How to handle entries that are present in the current config, but not in O(data).
+ - V(ignore) ignores them.
+ - V(remove) removes them.
type: str
choices:
- ignore
@@ -216,18 +272,48 @@ options:
default: ignore
handle_entries_content:
description:
- - For a single entry in I(data), this describes how to handle fields that are not mentioned
+ - For a single entry in O(data), this describes how to handle fields that are not mentioned
in that entry, but appear in the actual config.
- - If C(ignore), they are not modified.
- - If C(remove), they are removed. If at least one cannot be removed, the module will fail.
- - If C(remove_as_much_as_possible), all that can be removed will be removed. The ones that
+ - If V(ignore), they are not modified.
+ - If V(remove), they are removed. If at least one cannot be removed, the module will fail.
+ - If V(remove_as_much_as_possible), all that can be removed will be removed. The ones that
cannot be removed will be kept.
+ - Note that V(remove) and V(remove_as_much_as_possible) do not apply to write-only fields.
type: str
choices:
- ignore
- remove
- remove_as_much_as_possible
default: ignore
+ handle_read_only:
+ description:
+ - How to handle values passed in for read-only fields.
+ - If V(ignore), they are not passed to the API.
+ - If V(validate), the values are not passed for creation, and for updating they are compared to the value returned for the object.
+ If they differ, the module fails.
+ - If V(error), the module will fail if read-only fields are provided.
+ type: str
+ choices:
+ - ignore
+ - validate
+ - error
+ default: error
+ version_added: 2.10.0
+ handle_write_only:
+ description:
+ - How to handle values passed in for write-only fields.
+ - If V(create_only), they are passed on creation, and ignored for updating.
+ - If V(always_update), they are always passed to the API. This means that if such a value is present,
+ the module will always result in C(changed) since there is no way to validate whether the value
+ actually changed.
+ - If V(error), the module will fail if write-only fields are provided.
+ type: str
+ choices:
+ - create_only
+ - always_update
+ - error
+ default: create_only
+ version_added: 2.10.0
seealso:
- module: community.routeros.api
- module: community.routeros.api_facts
@@ -320,6 +406,7 @@ from ansible_collections.community.routeros.plugins.module_utils.api import (
api_argument_spec,
check_has_library,
create_api,
+ get_api_version,
)
from ansible_collections.community.routeros.plugins.module_utils._api_data import (
@@ -373,6 +460,18 @@ def find_modifications(old_entry, new_entry, path_info, module, for_text='', ret
continue
if k not in old_entry and path_info.fields[k].default == v and not path_info.fields[k].can_disable:
continue
+ key_info = path_info.fields[k]
+ if key_info.read_only:
+ # handle_read_only must be 'validate'
+ if old_entry.get(k) != v:
+ module.fail_json(
+ msg='Read-only key "{key}" has value "{old_value}", but should have new value "{new_value}"{for_text}.'.format(
+ key=k, old_value=old_entry.get(k), new_value=v, for_text=for_text))
+ continue
+ if key_info.write_only:
+ if module.params['handle_write_only'] == 'create_only':
+ # do not update this value
+ continue
if k not in old_entry or old_entry[k] != v:
modifications[k] = v
updated_entry[k] = v
@@ -441,6 +540,18 @@ def essentially_same_weight(old_entry, new_entry, path_info, module):
return weight
+def remove_read_only(entry, path_info):
+ to_remove = []
+ for real_k, v in entry.items():
+ k = real_k
+ if k.startswith('!'):
+ k = k[1:]
+ if path_info.fields[k].read_only:
+ to_remove.append(real_k)
+ for k in to_remove:
+ entry.pop(k)
+
+
def format_pk(primary_keys, values):
return ', '.join('{pk}="{value}"'.format(pk=pk, value=value) for pk, value in zip(primary_keys, values))
@@ -448,6 +559,7 @@ def format_pk(primary_keys, values):
def polish_entry(entry, path_info, module, for_text):
if '.id' in entry:
entry.pop('.id')
+ to_remove = []
for key, value in entry.items():
real_key = key
disabled_key = False
@@ -467,6 +579,16 @@ def polish_entry(entry, path_info, module, for_text):
elif value is None:
if not key_info.can_disable:
module.fail_json(msg='Key "{key}" must not be disabled (value null/~/None){for_text}.'.format(key=key, for_text=for_text))
+ if key_info.read_only:
+ if module.params['handle_read_only'] == 'error':
+ module.fail_json(msg='Key "{key}" is read-only{for_text}, and handle_read_only=error.'.format(key=key, for_text=for_text))
+ if module.params['handle_read_only'] == 'ignore':
+ to_remove.append(real_key)
+ if key_info.write_only:
+ if module.params['handle_write_only'] == 'error':
+ module.fail_json(msg='Key "{key}" is write-only{for_text}, and handle_write_only=error.'.format(key=key, for_text=for_text))
+ for key in to_remove:
+ entry.pop(key)
for key, field_info in path_info.fields.items():
if field_info.required and key not in entry:
module.fail_json(msg='Key "{key}" must be present{for_text}.'.format(key=key, for_text=for_text))
@@ -622,6 +744,7 @@ def sync_list(module, api, path, path_info):
new_data.append((old_index, updated_entry))
new_entry['.id'] = old_entry['.id']
else:
+ remove_read_only(new_entry, path_info)
create_list.append(new_entry)
if handle_absent_entries == 'remove':
@@ -814,6 +937,7 @@ def sync_with_primary_keys(module, api, path, path_info):
for primary_key in primary_keys
]),
))
+ remove_read_only(new_entry, path_info)
create_list.append(new_entry)
new_entry = new_entry.copy()
for key in list(new_entry):
@@ -992,14 +1116,31 @@ def get_backend(path_info):
return None
+def has_backend(versioned_path_info):
+ if not versioned_path_info.fully_understood:
+ return False
+
+ if versioned_path_info.unversioned is not None:
+ return get_backend(versioned_path_info.unversioned) is not None
+
+ if versioned_path_info.versioned is not None:
+ for dummy, dummy, unversioned in versioned_path_info.versioned:
+ if unversioned and not isinstance(unversioned, str) and get_backend(unversioned) is not None:
+ return True
+
+ return False
+
+
def main():
- path_choices = sorted([join_path(path) for path, path_info in PATHS.items() if get_backend(path_info) is not None])
+ path_choices = sorted([join_path(path) for path, versioned_path_info in PATHS.items() if has_backend(versioned_path_info)])
module_args = dict(
path=dict(type='str', required=True, choices=path_choices),
data=dict(type='list', elements='dict', required=True),
handle_absent_entries=dict(type='str', choices=['ignore', 'remove'], default='ignore'),
handle_entries_content=dict(type='str', choices=['ignore', 'remove', 'remove_as_much_as_possible'], default='ignore'),
ensure_order=dict(type='bool', default=False),
+ handle_read_only=dict(type='str', default='error', choices=['ignore', 'validate', 'error']),
+ handle_write_only=dict(type='str', default='create_only', choices=['create_only', 'always_update', 'error']),
)
module_args.update(api_argument_spec())
@@ -1018,7 +1159,17 @@ def main():
api = create_api(module)
path = split_path(module.params['path'])
- path_info = PATHS.get(tuple(path))
+ versioned_path_info = PATHS.get(tuple(path))
+ if versioned_path_info.needs_version:
+ api_version = get_api_version(api)
+ supported, not_supported_msg = versioned_path_info.provide_version(api_version)
+ if not supported:
+ msg = 'Path /{path} is not supported for API version {api_version}'.format(path='/'.join(path), api_version=api_version)
+ if not_supported_msg:
+ msg = '{0}: {1}'.format(msg, not_supported_msg)
+ module.fail_json(msg=msg)
+ path_info = versioned_path_info.get_data()
+
backend = get_backend(path_info)
if path_info is None or backend is None:
module.fail_json(msg='Path /{path} is not yet supported'.format(path='/'.join(path)))
diff --git a/ansible_collections/community/routeros/plugins/modules/command.py b/ansible_collections/community/routeros/plugins/modules/command.py
index 84426025c..52b916ba2 100644
--- a/ansible_collections/community/routeros/plugins/modules/command.py
+++ b/ansible_collections/community/routeros/plugins/modules/command.py
@@ -40,7 +40,7 @@ options:
description:
- List of commands to send to the remote RouterOS device over the
configured provider. The resulting output from the command
- is returned. If the I(wait_for) argument is provided, the
+ is returned. If the O(wait_for) argument is provided, the
module is not returned until the condition is satisfied or
the number of retries has expired.
required: true
@@ -57,11 +57,11 @@ options:
elements: str
match:
description:
- - The I(match) argument is used in conjunction with the
- I(wait_for) argument to specify the match policy. Valid
- values are C(all) or C(any). If the value is set to C(all)
+ - The O(match) argument is used in conjunction with the
+ O(wait_for) argument to specify the match policy. Valid
+ values are V(all) or V(any). If the value is set to V(all)
then all conditionals in the wait_for must be satisfied. If
- the value is set to C(any) then only one of the values must be
+ the value is set to V(any) then only one of the values must be
satisfied.
default: all
choices: ['any', 'all']
@@ -71,7 +71,7 @@ options:
- Specifies the number of retries a command should by tried
before it is considered failed. The command is run on the
target device every retry and evaluated against the
- I(wait_for) conditions.
+ O(wait_for) conditions.
default: 10
type: int
interval:
diff --git a/ansible_collections/community/routeros/plugins/modules/facts.py b/ansible_collections/community/routeros/plugins/modules/facts.py
index 85c0b37c4..50f9a21fc 100644
--- a/ansible_collections/community/routeros/plugins/modules/facts.py
+++ b/ansible_collections/community/routeros/plugins/modules/facts.py
@@ -31,9 +31,9 @@ options:
description:
- When supplied, this argument will restrict the facts collected
to a given subset. Possible values for this argument include
- C(all), C(hardware), C(config), C(interfaces), and C(routing).
+ V(all), V(hardware), V(config), V(interfaces), and V(routing).
- Can specify a list of values to include a larger subset.
- Values can also be used with an initial C(!) to specify that a
+ Values can also be used with an initial V(!) to specify that a
specific subset should not be collected.
required: false
default:
@@ -75,55 +75,55 @@ ansible_facts:
# default
ansible_net_model:
description: The model name returned from the device.
- returned: I(gather_subset) contains C(default)
+ returned: O(gather_subset) contains V(default)
type: str
ansible_net_serialnum:
description: The serial number of the remote device.
- returned: I(gather_subset) contains C(default)
+ returned: O(gather_subset) contains V(default)
type: str
ansible_net_version:
description: The operating system version running on the remote device.
- returned: I(gather_subset) contains C(default)
+ returned: O(gather_subset) contains V(default)
type: str
ansible_net_hostname:
description: The configured hostname of the device.
- returned: I(gather_subset) contains C(default)
+ returned: O(gather_subset) contains V(default)
type: str
ansible_net_arch:
description: The CPU architecture of the device.
- returned: I(gather_subset) contains C(default)
+ returned: O(gather_subset) contains V(default)
type: str
ansible_net_uptime:
description: The uptime of the device.
- returned: I(gather_subset) contains C(default)
+ returned: O(gather_subset) contains V(default)
type: str
ansible_net_cpu_load:
description: Current CPU load.
- returned: I(gather_subset) contains C(default)
+ returned: O(gather_subset) contains V(default)
type: str
# hardware
ansible_net_spacefree_mb:
description: The available disk space on the remote device in MiB.
- returned: I(gather_subset) contains C(hardware)
+ returned: O(gather_subset) contains V(hardware)
type: dict
ansible_net_spacetotal_mb:
description: The total disk space on the remote device in MiB.
- returned: I(gather_subset) contains C(hardware)
+ returned: O(gather_subset) contains V(hardware)
type: dict
ansible_net_memfree_mb:
description: The available free memory on the remote device in MiB.
- returned: I(gather_subset) contains C(hardware)
+ returned: O(gather_subset) contains V(hardware)
type: int
ansible_net_memtotal_mb:
description: The total memory on the remote device in MiB.
- returned: I(gather_subset) contains C(hardware)
+ returned: O(gather_subset) contains V(hardware)
type: int
# config
ansible_net_config:
description: The current active config from the device.
- returned: I(gather_subset) contains C(config)
+ returned: O(gather_subset) contains V(config)
type: str
ansible_net_config_nonverbose:
@@ -132,52 +132,52 @@ ansible_facts:
- This value is idempotent in the sense that if the facts module is run twice and the device's config
was not changed between the runs, the value is identical. This is achieved by running C(/export)
and stripping the timestamp from the comment in the first line.
- returned: I(gather_subset) contains C(config)
+ returned: O(gather_subset) contains V(config)
type: str
version_added: 1.2.0
# interfaces
ansible_net_all_ipv4_addresses:
description: All IPv4 addresses configured on the device.
- returned: I(gather_subset) contains C(interfaces)
+ returned: O(gather_subset) contains V(interfaces)
type: list
ansible_net_all_ipv6_addresses:
description: All IPv6 addresses configured on the device.
- returned: I(gather_subset) contains C(interfaces)
+ returned: O(gather_subset) contains V(interfaces)
type: list
ansible_net_interfaces:
description: A hash of all interfaces running on the system.
- returned: I(gather_subset) contains C(interfaces)
+ returned: O(gather_subset) contains V(interfaces)
type: dict
ansible_net_neighbors:
description: The list of neighbors from the remote device.
- returned: I(gather_subset) contains C(interfaces)
+ returned: O(gather_subset) contains V(interfaces)
type: dict
# routing
ansible_net_bgp_peer:
description: A dictionary with BGP peer information.
- returned: I(gather_subset) contains C(routing)
+ returned: O(gather_subset) contains V(routing)
type: dict
ansible_net_bgp_vpnv4_route:
description: A dictionary with BGP vpnv4 route information.
- returned: I(gather_subset) contains C(routing)
+ returned: O(gather_subset) contains V(routing)
type: dict
ansible_net_bgp_instance:
description: A dictionary with BGP instance information.
- returned: I(gather_subset) contains C(routing)
+ returned: O(gather_subset) contains V(routing)
type: dict
ansible_net_route:
description: A dictionary for routes in all routing tables.
- returned: I(gather_subset) contains C(routing)
+ returned: O(gather_subset) contains V(routing)
type: dict
ansible_net_ospf_instance:
description: A dictionary with OSPF instances.
- returned: I(gather_subset) contains C(routing)
+ returned: O(gather_subset) contains V(routing)
type: dict
ansible_net_ospf_neighbor:
description: A dictionary with OSPF neighbors.
- returned: I(gather_subset) contains C(routing)
+ returned: O(gather_subset) contains V(routing)
type: dict
"""
import re
@@ -311,7 +311,7 @@ class Config(FactsBase):
'/export',
]
- RM_DATE_RE = re.compile(r'^# [a-z0-9/][a-z0-9/]* [0-9:]* by RouterOS')
+ RM_DATE_RE = re.compile(r'^# [a-z0-9/-][a-z0-9/-]* [0-9:]* by RouterOS')
def populate(self):
super(Config, self).populate()
diff --git a/ansible_collections/community/routeros/tests/sanity/extra/extra-docs.py b/ansible_collections/community/routeros/tests/sanity/extra/extra-docs.py
index c636beb08..251e6d70f 100755
--- a/ansible_collections/community/routeros/tests/sanity/extra/extra-docs.py
+++ b/ansible_collections/community/routeros/tests/sanity/extra/extra-docs.py
@@ -17,7 +17,7 @@ def main():
suffix = ':{env}'.format(env=env["ANSIBLE_COLLECTIONS_PATH"]) if 'ANSIBLE_COLLECTIONS_PATH' in env else ''
env['ANSIBLE_COLLECTIONS_PATH'] = '{root}{suffix}'.format(root=os.path.dirname(os.path.dirname(os.path.dirname(os.getcwd()))), suffix=suffix)
p = subprocess.run(
- ['antsibull-docs', 'lint-collection-docs', '--plugin-docs', '--disallow-semantic-markup', '--skip-rstcheck', '.'],
+ ['antsibull-docs', 'lint-collection-docs', '--plugin-docs', '--skip-rstcheck', '.'],
env=env,
check=False,
)
diff --git a/ansible_collections/community/routeros/tests/sanity/ignore-2.10.txt b/ansible_collections/community/routeros/tests/sanity/ignore-2.10.txt
index 876765a85..ece5b2977 100644
--- a/ansible_collections/community/routeros/tests/sanity/ignore-2.10.txt
+++ b/ansible_collections/community/routeros/tests/sanity/ignore-2.10.txt
@@ -1,3 +1,6 @@
+docs/docsite/rst/api-guide.rst rstcheck
+docs/docsite/rst/quoting.rst rstcheck
+docs/docsite/rst/ssh-guide.rst rstcheck
update-docs.py compile-2.6
update-docs.py compile-2.7
update-docs.py compile-3.5
diff --git a/ansible_collections/community/routeros/tests/sanity/ignore-2.17.txt b/ansible_collections/community/routeros/tests/sanity/ignore-2.17.txt
new file mode 100644
index 000000000..0a5234bdb
--- /dev/null
+++ b/ansible_collections/community/routeros/tests/sanity/ignore-2.17.txt
@@ -0,0 +1,2 @@
+update-docs.py shebang
+tests/unit/compat/mock.py pylint:use-yield-from # suggested construct does not work with Python 2
diff --git a/ansible_collections/community/routeros/tests/sanity/ignore-2.17.txt.license b/ansible_collections/community/routeros/tests/sanity/ignore-2.17.txt.license
new file mode 100644
index 000000000..edff8c768
--- /dev/null
+++ b/ansible_collections/community/routeros/tests/sanity/ignore-2.17.txt.license
@@ -0,0 +1,3 @@
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
+SPDX-FileCopyrightText: Ansible Project
diff --git a/ansible_collections/community/routeros/tests/sanity/ignore-2.9.txt b/ansible_collections/community/routeros/tests/sanity/ignore-2.9.txt
index 876765a85..ece5b2977 100644
--- a/ansible_collections/community/routeros/tests/sanity/ignore-2.9.txt
+++ b/ansible_collections/community/routeros/tests/sanity/ignore-2.9.txt
@@ -1,3 +1,6 @@
+docs/docsite/rst/api-guide.rst rstcheck
+docs/docsite/rst/quoting.rst rstcheck
+docs/docsite/rst/ssh-guide.rst rstcheck
update-docs.py compile-2.6
update-docs.py compile-2.7
update-docs.py compile-3.5
diff --git a/ansible_collections/community/routeros/tests/unit/plugins/module_utils/test__api_data.py b/ansible_collections/community/routeros/tests/unit/plugins/module_utils/test__api_data.py
index 1250fdaa5..4c0267e96 100644
--- a/ansible_collections/community/routeros/tests/unit/plugins/module_utils/test__api_data.py
+++ b/ansible_collections/community/routeros/tests/unit/plugins/module_utils/test__api_data.py
@@ -10,7 +10,7 @@ __metaclass__ = type
import pytest
from ansible_collections.community.routeros.plugins.module_utils._api_data import (
- APIData,
+ VersionedAPIData,
KeyInfo,
split_path,
join_path,
@@ -19,7 +19,7 @@ from ansible_collections.community.routeros.plugins.module_utils._api_data impor
def test_api_data_errors():
with pytest.raises(ValueError) as exc:
- APIData()
+ VersionedAPIData()
assert exc.value.args[0] == 'fields must be provided'
values = [
@@ -33,39 +33,39 @@ def test_api_data_errors():
for index, (param, param_value) in enumerate(values):
for param2, param2_value in values[index + 1:]:
with pytest.raises(ValueError) as exc:
- APIData(**{param: param_value, param2: param2_value})
+ VersionedAPIData(**{param: param_value, param2: param2_value})
assert exc.value.args[0] == 'primary_keys, stratify_keys, has_identifier, single_value, and unknown_mechanism are mutually exclusive'
with pytest.raises(ValueError) as exc:
- APIData(unknown_mechanism=True, fully_understood=True)
+ VersionedAPIData(unknown_mechanism=True, fully_understood=True)
assert exc.value.args[0] == 'unknown_mechanism and fully_understood cannot be combined'
with pytest.raises(ValueError) as exc:
- APIData(unknown_mechanism=True, fixed_entries=True)
+ VersionedAPIData(unknown_mechanism=True, fixed_entries=True)
assert exc.value.args[0] == 'fixed_entries can only be used with primary_keys'
with pytest.raises(ValueError) as exc:
- APIData(primary_keys=['foo'], fields={})
+ VersionedAPIData(primary_keys=['foo'], fields={})
assert exc.value.args[0] == 'Primary key foo must be in fields!'
with pytest.raises(ValueError) as exc:
- APIData(stratify_keys=['foo'], fields={})
+ VersionedAPIData(stratify_keys=['foo'], fields={})
assert exc.value.args[0] == 'Stratify key foo must be in fields!'
with pytest.raises(ValueError) as exc:
- APIData(required_one_of=['foo'], fields={})
+ VersionedAPIData(required_one_of=['foo'], fields={})
assert exc.value.args[0] == 'Require one of element at index #1 must be a list!'
with pytest.raises(ValueError) as exc:
- APIData(required_one_of=[['foo']], fields={})
+ VersionedAPIData(required_one_of=[['foo']], fields={})
assert exc.value.args[0] == 'Require one of key foo must be in fields!'
with pytest.raises(ValueError) as exc:
- APIData(mutually_exclusive=['foo'], fields={})
+ VersionedAPIData(mutually_exclusive=['foo'], fields={})
assert exc.value.args[0] == 'Mutually exclusive element at index #1 must be a list!'
with pytest.raises(ValueError) as exc:
- APIData(mutually_exclusive=[['foo']], fields={})
+ VersionedAPIData(mutually_exclusive=[['foo']], fields={})
assert exc.value.args[0] == 'Mutually exclusive key foo must be in fields!'
@@ -99,8 +99,16 @@ def test_key_info_errors():
KeyInfo(remove_value='')
assert exc.value.args[0] == 'remove_value can only be specified if can_disable=True'
+ with pytest.raises(ValueError) as exc:
+ KeyInfo(read_only=True, write_only=True)
+ assert exc.value.args[0] == 'read_only and write_only cannot be used at the same time'
+
+ with pytest.raises(ValueError) as exc:
+ KeyInfo(read_only=True, default=0)
+ assert exc.value.args[0] == 'read_only can not be combined with can_disable, remove_value, absent_value, default, or required'
+
-SPLITTED_PATHS = [
+SPLIT_PATHS = [
('', [], ''),
(' ip ', ['ip'], 'ip'),
('ip', ['ip'], 'ip'),
@@ -108,7 +116,7 @@ SPLITTED_PATHS = [
]
-@pytest.mark.parametrize("joined_input, splitted, joined_output", SPLITTED_PATHS)
-def test_join_split_path(joined_input, splitted, joined_output):
- assert split_path(joined_input) == splitted
- assert join_path(splitted) == joined_output
+@pytest.mark.parametrize("joined_input, split, joined_output", SPLIT_PATHS)
+def test_join_split_path(joined_input, split, joined_output):
+ assert split_path(joined_input) == split
+ assert join_path(split) == joined_output
diff --git a/ansible_collections/community/routeros/tests/unit/plugins/modules/fake_api.py b/ansible_collections/community/routeros/tests/unit/plugins/modules/fake_api.py
index a5ddb3180..cbcd2371c 100644
--- a/ansible_collections/community/routeros/tests/unit/plugins/modules/fake_api.py
+++ b/ansible_collections/community/routeros/tests/unit/plugins/modules/fake_api.py
@@ -9,6 +9,9 @@ __metaclass__ = type
from ansible_collections.community.routeros.plugins.module_utils._api_data import PATHS
+FAKE_ROS_VERSION = '7.5.0'
+
+
class FakeLibRouterosError(Exception):
def __init__(self, message):
self.message = message
@@ -16,7 +19,7 @@ class FakeLibRouterosError(Exception):
class TrapError(FakeLibRouterosError):
- def __init__(self, message="failure: already have interface with such name"):
+ def __init__(self, message='failure: already have interface with such name'):
super(TrapError, self).__init__(message)
@@ -133,7 +136,9 @@ def _normalize_entry(entry, path_info, on_create=False):
def massage_expected_result_data(values, path, keep_all=False, remove_dynamic=False, remove_builtin=False):
- path_info = PATHS[path]
+ versioned_path_info = PATHS[path]
+ versioned_path_info.provide_version(FAKE_ROS_VERSION)
+ path_info = versioned_path_info.get_data()
if remove_dynamic:
values = [entry for entry in values if not entry.get('dynamic', False)]
if remove_builtin:
@@ -155,15 +160,25 @@ def massage_expected_result_data(values, path, keep_all=False, remove_dynamic=Fa
class Path(object):
def __init__(self, path, initial_values, read_only=False):
self._path = path
- self._path_info = PATHS[path]
+ versioned_path_info = PATHS[path]
+ versioned_path_info.provide_version(FAKE_ROS_VERSION)
+ self._path_info = versioned_path_info.get_data()
self._values = [entry.copy() for entry in initial_values]
for entry in self._values:
_normalize_entry(entry, self._path_info)
self._new_id_counter = 0
self._read_only = read_only
+ def _sanitize(self, entry):
+ entry = entry.copy()
+ for field, field_info in self._path_info.fields.items():
+ if field in entry:
+ if field_info.write_only:
+ del entry[field]
+ return entry
+
def __iter__(self):
- return [entry.copy() for entry in self._values].__iter__()
+ return [self._sanitize(entry) for entry in self._values].__iter__()
def _find_id(self, id, required=False):
for index, entry in enumerate(self._values):
@@ -187,7 +202,15 @@ class Path(object):
entry = {
'.id': id,
}
- entry.update(kwargs)
+ for field, value in kwargs.items():
+ if field.startswith('!'):
+ field = field[1:]
+ if field not in self._path_info.fields:
+ raise ValueError('Trying to set unknown field "{field}"'.format(field=field))
+ field_info = self._path_info.fields[field]
+ if field_info.read_only:
+ raise ValueError('Trying to set read-only field "{field}"'.format(field=field))
+ entry[field] = value
_normalize_entry(entry, self._path_info, on_create=True)
self._values.append(entry)
return id
@@ -216,6 +239,16 @@ class Path(object):
entry = self._values[index]
if entry.get('dynamic', False) or entry.get('builtin', False):
raise Exception('Trying to update a dynamic or builtin entry')
+ for field in kwargs:
+ if field == '.id':
+ continue
+ if field.startswith('!'):
+ field = field[1:]
+ if field not in self._path_info.fields:
+ raise ValueError('Trying to update unknown field "{field}"'.format(field=field))
+ field_info = self._path_info.fields[field]
+ if field_info.read_only:
+ raise ValueError('Trying to update read-only field "{field}"'.format(field=field))
entry.update(kwargs)
_normalize_entry(entry, self._path_info)
diff --git a/ansible_collections/community/routeros/tests/unit/plugins/modules/test_api_find_and_modify.py b/ansible_collections/community/routeros/tests/unit/plugins/modules/test_api_find_and_modify.py
index 384bc8885..2f47af4f6 100644
--- a/ansible_collections/community/routeros/tests/unit/plugins/modules/test_api_find_and_modify.py
+++ b/ansible_collections/community/routeros/tests/unit/plugins/modules/test_api_find_and_modify.py
@@ -389,6 +389,7 @@ class TestRouterosApiFindAndModifyModule(ModuleTestCase):
'ttl': '1d',
'disabled': False,
'dynamic': False,
+ 'match-subdomain': False,
},
{
'.id': '*A',
@@ -397,6 +398,7 @@ class TestRouterosApiFindAndModifyModule(ModuleTestCase):
'ttl': '1d',
'disabled': False,
'dynamic': False,
+ 'match-subdomain': False,
},
{
'.id': '*7',
@@ -406,6 +408,7 @@ class TestRouterosApiFindAndModifyModule(ModuleTestCase):
'ttl': '1d',
'disabled': False,
'dynamic': False,
+ 'match-subdomain': False,
},
])
self.assertEqual(result['diff']['before']['values'], [
@@ -416,6 +419,7 @@ class TestRouterosApiFindAndModifyModule(ModuleTestCase):
'ttl': '1d',
'disabled': False,
'dynamic': False,
+ 'match-subdomain': False,
},
])
self.assertEqual(result['diff']['after']['values'], [
@@ -427,6 +431,7 @@ class TestRouterosApiFindAndModifyModule(ModuleTestCase):
'ttl': '1d',
'disabled': False,
'dynamic': False,
+ 'match-subdomain': False,
},
])
self.assertEqual(result['match_count'], 1)
@@ -459,6 +464,7 @@ class TestRouterosApiFindAndModifyModule(ModuleTestCase):
'ttl': '1d',
'disabled': False,
'dynamic': False,
+ 'match-subdomain': False,
},
{
'.id': '*A',
@@ -467,6 +473,7 @@ class TestRouterosApiFindAndModifyModule(ModuleTestCase):
'ttl': '1d',
'disabled': False,
'dynamic': False,
+ 'match-subdomain': False,
},
{
'.id': '*7',
@@ -475,6 +482,7 @@ class TestRouterosApiFindAndModifyModule(ModuleTestCase):
'ttl': '1d',
'disabled': False,
'dynamic': False,
+ 'match-subdomain': False,
},
])
self.assertEqual('diff' in result, False)
@@ -508,6 +516,7 @@ class TestRouterosApiFindAndModifyModule(ModuleTestCase):
'ttl': '1d',
'disabled': False,
'dynamic': False,
+ 'match-subdomain': False,
},
{
'.id': '*A',
@@ -516,6 +525,7 @@ class TestRouterosApiFindAndModifyModule(ModuleTestCase):
'ttl': '1d',
'disabled': False,
'dynamic': False,
+ 'match-subdomain': False,
},
{
'.id': '*7',
@@ -524,6 +534,7 @@ class TestRouterosApiFindAndModifyModule(ModuleTestCase):
'ttl': '1d',
'disabled': False,
'dynamic': False,
+ 'match-subdomain': False,
},
])
self.assertEqual(result['match_count'], 3)
@@ -556,6 +567,7 @@ class TestRouterosApiFindAndModifyModule(ModuleTestCase):
'ttl': '1d',
'disabled': False,
'dynamic': False,
+ 'match-subdomain': False,
},
{
'.id': '*A',
@@ -564,6 +576,7 @@ class TestRouterosApiFindAndModifyModule(ModuleTestCase):
'ttl': '1d',
'disabled': False,
'dynamic': False,
+ 'match-subdomain': False,
},
{
'.id': '*7',
@@ -572,6 +585,7 @@ class TestRouterosApiFindAndModifyModule(ModuleTestCase):
'ttl': '1d',
'disabled': False,
'dynamic': False,
+ 'match-subdomain': False,
},
])
self.assertEqual(result['match_count'], 3)
@@ -605,24 +619,28 @@ class TestRouterosApiFindAndModifyModule(ModuleTestCase):
'chain': 'input',
'comment': 'defconf',
'protocol': 'icmp',
+ 'disabled': False,
},
{
'.id': '*3',
'action': 'accept',
'chain': 'input',
'comment': 'defconf',
+ 'disabled': False,
},
{
'.id': '*4',
'action': 'accept',
'chain': 'input',
'comment': 'defconf',
+ 'disabled': False,
},
{
'.id': '*7',
'action': 'drop',
'chain': 'input',
'comment': 'defconf',
+ 'disabled': False,
'in-interface': 'wan',
},
{
@@ -631,6 +649,7 @@ class TestRouterosApiFindAndModifyModule(ModuleTestCase):
'chain': 'forward',
'comment': 'defconf',
'connection-state': 'established',
+ 'disabled': False,
},
{
'.id': '*9',
@@ -638,6 +657,7 @@ class TestRouterosApiFindAndModifyModule(ModuleTestCase):
'chain': 'forward',
'comment': 'defconf',
'connection-state': 'related',
+ 'disabled': False,
},
{
'.id': '*A',
@@ -645,6 +665,7 @@ class TestRouterosApiFindAndModifyModule(ModuleTestCase):
'chain': 'forward',
'comment': 'defconf',
'connection-status': 'invalid',
+ 'disabled': False,
},
])
self.assertEqual(result['match_count'], 3)
diff --git a/ansible_collections/community/routeros/tests/unit/plugins/modules/test_api_info.py b/ansible_collections/community/routeros/tests/unit/plugins/modules/test_api_info.py
index 2dabc36ef..3564668e7 100644
--- a/ansible_collections/community/routeros/tests/unit/plugins/modules/test_api_info.py
+++ b/ansible_collections/community/routeros/tests/unit/plugins/modules/test_api_info.py
@@ -7,7 +7,9 @@ from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
from ansible_collections.community.routeros.tests.unit.compat.mock import patch, MagicMock
-from ansible_collections.community.routeros.tests.unit.plugins.modules.fake_api import FakeLibRouterosError, Key, fake_ros_api
+from ansible_collections.community.routeros.tests.unit.plugins.modules.fake_api import (
+ FAKE_ROS_VERSION, FakeLibRouterosError, Key, fake_ros_api,
+)
from ansible_collections.community.routeros.tests.unit.plugins.modules.utils import set_module_args, AnsibleExitJson, AnsibleFailJson, ModuleTestCase
from ansible_collections.community.routeros.plugins.modules import api_info
@@ -22,6 +24,10 @@ class TestRouterosApiInfoModule(ModuleTestCase):
self.module.check_has_library = MagicMock()
self.patch_create_api = patch('ansible_collections.community.routeros.plugins.modules.api_info.create_api', MagicMock(new=fake_ros_api))
self.patch_create_api.start()
+ self.patch_get_api_version = patch(
+ 'ansible_collections.community.routeros.plugins.modules.api_info.get_api_version',
+ MagicMock(return_value=FAKE_ROS_VERSION))
+ self.patch_get_api_version.start()
self.module.Key = MagicMock(new=Key)
self.config_module_args = {
'username': 'admin',
@@ -30,6 +36,7 @@ class TestRouterosApiInfoModule(ModuleTestCase):
}
def tearDown(self):
+ self.patch_get_api_version.stop()
self.patch_create_api.stop()
def test_module_fail_when_required_args_missing(self):
@@ -191,6 +198,8 @@ class TestRouterosApiInfoModule(ModuleTestCase):
'chain': 'input',
'in-interface-list': 'LAN',
'!action': None,
+ '!address-list': None,
+ '!address-list-timeout': None,
'!comment': None,
'!connection-bytes': None,
'!connection-limit': None,
@@ -236,6 +245,7 @@ class TestRouterosApiInfoModule(ModuleTestCase):
'!protocol': None,
'!psd': None,
'!random': None,
+ '!realm': None,
'!reject-with': None,
'!routing-mark': None,
'!routing-table': None,
@@ -277,6 +287,8 @@ class TestRouterosApiInfoModule(ModuleTestCase):
'chain': 'input',
'in-interface-list': 'LAN',
'action': None,
+ 'address-list': None,
+ 'address-list-timeout': None,
'comment': None,
'connection-bytes': None,
'connection-limit': None,
@@ -322,6 +334,7 @@ class TestRouterosApiInfoModule(ModuleTestCase):
'protocol': None,
'psd': None,
'random': None,
+ 'realm': None,
'reject-with': None,
'routing-mark': None,
'routing-table': None,
diff --git a/ansible_collections/community/routeros/tests/unit/plugins/modules/test_api_modify.py b/ansible_collections/community/routeros/tests/unit/plugins/modules/test_api_modify.py
index 78979733d..f4aa77742 100644
--- a/ansible_collections/community/routeros/tests/unit/plugins/modules/test_api_modify.py
+++ b/ansible_collections/community/routeros/tests/unit/plugins/modules/test_api_modify.py
@@ -8,7 +8,7 @@ __metaclass__ = type
from ansible_collections.community.routeros.tests.unit.compat.mock import patch, MagicMock
from ansible_collections.community.routeros.tests.unit.plugins.modules.fake_api import (
- FakeLibRouterosError, fake_ros_api, massage_expected_result_data, create_fake_path,
+ FAKE_ROS_VERSION, FakeLibRouterosError, fake_ros_api, massage_expected_result_data, create_fake_path,
)
from ansible_collections.community.routeros.tests.unit.plugins.modules.utils import set_module_args, AnsibleExitJson, AnsibleFailJson, ModuleTestCase
from ansible_collections.community.routeros.plugins.modules import api_modify
@@ -302,6 +302,10 @@ class TestRouterosApiModifyModule(ModuleTestCase):
'ansible_collections.community.routeros.plugins.modules.api_modify.create_api',
MagicMock(new=fake_ros_api))
self.patch_create_api.start()
+ self.patch_get_api_version = patch(
+ 'ansible_collections.community.routeros.plugins.modules.api_modify.get_api_version',
+ MagicMock(return_value=FAKE_ROS_VERSION))
+ self.patch_get_api_version.start()
self.config_module_args = {
'username': 'admin',
'password': 'pаss',
@@ -309,6 +313,7 @@ class TestRouterosApiModifyModule(ModuleTestCase):
}
def tearDown(self):
+ self.patch_get_api_version.stop()
self.patch_create_api.stop()
def test_module_fail_when_required_args_missing(self):
@@ -600,6 +605,7 @@ class TestRouterosApiModifyModule(ModuleTestCase):
'address': '192.168.88.1',
'ttl': '1d',
'disabled': False,
+ 'match-subdomain': False,
},
{
'.id': '*A',
@@ -607,6 +613,7 @@ class TestRouterosApiModifyModule(ModuleTestCase):
'text': 'Router Text Entry',
'ttl': '1d',
'disabled': False,
+ 'match-subdomain': False,
},
{
'.id': '*7',
@@ -614,6 +621,7 @@ class TestRouterosApiModifyModule(ModuleTestCase):
'address': '192.168.88.2',
'ttl': '1d',
'disabled': False,
+ 'match-subdomain': False,
},
{
'.id': '*NEW1',
@@ -621,6 +629,7 @@ class TestRouterosApiModifyModule(ModuleTestCase):
'text': 'Router Text Entry 2',
'ttl': '1d',
'disabled': False,
+ 'match-subdomain': False,
},
])
@@ -661,6 +670,7 @@ class TestRouterosApiModifyModule(ModuleTestCase):
'address': '192.168.88.1',
'ttl': '1d',
'disabled': False,
+ 'match-subdomain': False,
},
{
'.id': '*A',
@@ -668,6 +678,7 @@ class TestRouterosApiModifyModule(ModuleTestCase):
'text': 'Router Text Entry',
'ttl': '1d',
'disabled': False,
+ 'match-subdomain': False,
},
{
'.id': '*7',
@@ -675,6 +686,7 @@ class TestRouterosApiModifyModule(ModuleTestCase):
'address': '192.168.88.2',
'ttl': '1d',
'disabled': False,
+ 'match-subdomain': False,
},
{
'.id': '*NEW1',
@@ -682,6 +694,7 @@ class TestRouterosApiModifyModule(ModuleTestCase):
'text': 'Router Text Entry 2',
'ttl': '1d',
'disabled': False,
+ 'match-subdomain': False,
},
])
@@ -723,6 +736,7 @@ class TestRouterosApiModifyModule(ModuleTestCase):
'address': '192.168.88.1',
'ttl': '1d',
'disabled': False,
+ 'match-subdomain': False,
},
{
'.id': '*A',
@@ -730,6 +744,7 @@ class TestRouterosApiModifyModule(ModuleTestCase):
'text': 'Router Text Entry',
'ttl': '1d',
'disabled': False,
+ 'match-subdomain': False,
},
{
'.id': '*7',
@@ -737,6 +752,7 @@ class TestRouterosApiModifyModule(ModuleTestCase):
'address': '192.168.88.2',
'ttl': '1d',
'disabled': False,
+ 'match-subdomain': False,
},
{
'name': 'router',
@@ -782,6 +798,7 @@ class TestRouterosApiModifyModule(ModuleTestCase):
'address': '192.168.88.1',
'ttl': '1d',
'disabled': False,
+ 'match-subdomain': False,
},
{
'.id': '*A',
@@ -789,6 +806,7 @@ class TestRouterosApiModifyModule(ModuleTestCase):
'text': 'Router Text Entry 2',
'ttl': '1d',
'disabled': False,
+ 'match-subdomain': False,
},
{
'.id': '*7',
@@ -796,6 +814,7 @@ class TestRouterosApiModifyModule(ModuleTestCase):
'address': '192.168.88.2',
'ttl': '1d',
'disabled': False,
+ 'match-subdomain': False,
},
])
@@ -838,6 +857,7 @@ class TestRouterosApiModifyModule(ModuleTestCase):
'address': '192.168.88.1',
'ttl': '1d',
'disabled': False,
+ 'match-subdomain': False,
},
{
'.id': '*A',
@@ -845,6 +865,7 @@ class TestRouterosApiModifyModule(ModuleTestCase):
'text': 'Router Text Entry 2',
'ttl': '1d',
'disabled': False,
+ 'match-subdomain': False,
},
{
'.id': '*7',
@@ -852,6 +873,7 @@ class TestRouterosApiModifyModule(ModuleTestCase):
'address': '192.168.88.2',
'ttl': '1d',
'disabled': False,
+ 'match-subdomain': False,
},
])
@@ -894,6 +916,7 @@ class TestRouterosApiModifyModule(ModuleTestCase):
'address': '192.168.88.1',
'ttl': '1d',
'disabled': False,
+ 'match-subdomain': False,
},
{
'.id': '*7',
@@ -901,6 +924,7 @@ class TestRouterosApiModifyModule(ModuleTestCase):
'address': '192.168.88.2',
'ttl': '1d',
'disabled': False,
+ 'match-subdomain': False,
},
{
'.id': '*NEW1',
@@ -908,6 +932,7 @@ class TestRouterosApiModifyModule(ModuleTestCase):
'cname': 'router.com.',
'ttl': '1d',
'disabled': False,
+ 'match-subdomain': False,
},
])
@@ -951,6 +976,7 @@ class TestRouterosApiModifyModule(ModuleTestCase):
'address': '192.168.88.1',
'ttl': '1d',
'disabled': False,
+ 'match-subdomain': False,
},
{
'.id': '*7',
@@ -958,6 +984,7 @@ class TestRouterosApiModifyModule(ModuleTestCase):
'address': '192.168.88.2',
'ttl': '1d',
'disabled': False,
+ 'match-subdomain': False,
},
{
'name': 'router',
@@ -1003,6 +1030,7 @@ class TestRouterosApiModifyModule(ModuleTestCase):
'address': '192.168.88.1',
'ttl': '1d',
'disabled': False,
+ 'match-subdomain': False,
},
{
'.id': '*A',
@@ -1011,6 +1039,7 @@ class TestRouterosApiModifyModule(ModuleTestCase):
'text': 'Router Text Entry 2',
'ttl': '1d',
'disabled': False,
+ 'match-subdomain': False,
},
{
'.id': '*7',
@@ -1018,6 +1047,7 @@ class TestRouterosApiModifyModule(ModuleTestCase):
'address': '192.168.88.2',
'ttl': '1d',
'disabled': False,
+ 'match-subdomain': False,
},
])
@@ -1060,6 +1090,7 @@ class TestRouterosApiModifyModule(ModuleTestCase):
'address': '192.168.88.1',
'ttl': '1d',
'disabled': False,
+ 'match-subdomain': False,
},
{
'.id': '*A',
@@ -1068,6 +1099,7 @@ class TestRouterosApiModifyModule(ModuleTestCase):
'text': 'Router Text Entry 2',
'ttl': '1d',
'disabled': False,
+ 'match-subdomain': False,
},
{
'.id': '*7',
@@ -1075,6 +1107,7 @@ class TestRouterosApiModifyModule(ModuleTestCase):
'address': '192.168.88.2',
'ttl': '1d',
'disabled': False,
+ 'match-subdomain': False,
},
])
@@ -1109,6 +1142,7 @@ class TestRouterosApiModifyModule(ModuleTestCase):
'address': '192.168.88.1',
'ttl': '1d',
'disabled': False,
+ 'match-subdomain': False,
},
])
@@ -1144,6 +1178,7 @@ class TestRouterosApiModifyModule(ModuleTestCase):
'address': '192.168.88.1',
'ttl': '1d',
'disabled': False,
+ 'match-subdomain': False,
},
])
@@ -1190,6 +1225,7 @@ class TestRouterosApiModifyModule(ModuleTestCase):
'address': '192.168.88.2',
'ttl': '1d',
'disabled': False,
+ 'match-subdomain': False,
},
{
'.id': '*NEW1',
@@ -1197,6 +1233,7 @@ class TestRouterosApiModifyModule(ModuleTestCase):
'text': 'bar',
'ttl': '1d',
'disabled': False,
+ 'match-subdomain': False,
},
{
'.id': '*A',
@@ -1204,6 +1241,7 @@ class TestRouterosApiModifyModule(ModuleTestCase):
'text': 'Router Text Entry',
'ttl': '1d',
'disabled': False,
+ 'match-subdomain': False,
},
{
'.id': '*1',
@@ -1212,6 +1250,7 @@ class TestRouterosApiModifyModule(ModuleTestCase):
'address': '192.168.88.1',
'ttl': '1d',
'disabled': False,
+ 'match-subdomain': False,
},
])
@@ -1259,6 +1298,7 @@ class TestRouterosApiModifyModule(ModuleTestCase):
'address': '192.168.88.2',
'ttl': '1d',
'disabled': False,
+ 'match-subdomain': False,
},
{
'name': 'foo',
@@ -1270,6 +1310,7 @@ class TestRouterosApiModifyModule(ModuleTestCase):
'text': 'Router Text Entry',
'ttl': '1d',
'disabled': False,
+ 'match-subdomain': False,
},
{
'.id': '*1',
@@ -1278,6 +1319,7 @@ class TestRouterosApiModifyModule(ModuleTestCase):
'address': '192.168.88.1',
'ttl': '1d',
'disabled': False,
+ 'match-subdomain': False,
},
])
diff --git a/ansible_collections/community/routeros/update-docs.py b/ansible_collections/community/routeros/update-docs.py
index 17a431b05..05a9ee743 100755
--- a/ansible_collections/community/routeros/update-docs.py
+++ b/ansible_collections/community/routeros/update-docs.py
@@ -9,7 +9,12 @@
Updates DOCUMENTATION of modules using module_utils._api_data with the correct list of supported paths.
'''
-from plugins.module_utils._api_data import (
+import sys
+
+# Ensure that we can import things from ansible_collections
+sys.path.append('../../..')
+
+from ansible_collections.community.routeros.plugins.module_utils._api_data import (
PATHS,
join_path,
)
diff --git a/ansible_collections/community/sap/.github/workflows/ansible-test.yml b/ansible_collections/community/sap/.github/workflows/ansible-test.yml
index 1671f6579..c29b8123a 100644
--- a/ansible_collections/community/sap/.github/workflows/ansible-test.yml
+++ b/ansible_collections/community/sap/.github/workflows/ansible-test.yml
@@ -1,126 +1,126 @@
-name: CI
-on:
- # Run CI against all pushes (direct commits, also merged PRs), Pull Requests
- push:
- pull_request:
- # Run CI once per day (at 06:00 UTC)
- # This ensures that even if there haven't been commits that we are still testing against latest version of ansible-test for each ansible-base version
- schedule:
- - cron: '0 6 * * *'
-env:
- NAMESPACE: community
- COLLECTION_NAME: sap
+# name: CI
+# on:
+# # Run CI against all pushes (direct commits, also merged PRs), Pull Requests
+# push:
+# pull_request:
+# # Run CI once per day (at 06:00 UTC)
+# # This ensures that even if there haven't been commits that we are still testing against latest version of ansible-test for each ansible-base version
+# schedule:
+# - cron: '0 6 * * *'
+# env:
+# NAMESPACE: community
+# COLLECTION_NAME: sap
-jobs:
- sanity:
- name: Sanity (Ⓐ${{ matrix.ansible }})
- strategy:
- matrix:
- ansible:
- - stable-2.9
- - stable-2.10
- - stable-2.11
- - stable-2.12
- - devel
- runs-on: ubuntu-latest
- steps:
+# jobs:
+# sanity:
+# name: Sanity (Ⓐ${{ matrix.ansible }})
+# strategy:
+# matrix:
+# ansible:
+# - stable-2.9
+# - stable-2.10
+# - stable-2.11
+# - stable-2.12
+# - devel
+# runs-on: ubuntu-latest
+# steps:
- - name: Check out code
- uses: actions/checkout@v2
+# - name: Check out code
+# uses: actions/checkout@v2
- - name: Perform sanity testing with ansible-test
- uses: ansible-community/ansible-test-gh-action@release/v1
- with:
- ansible-core-version: ${{ matrix.ansible }}
- testing-type: sanity
+# - name: Perform sanity testing with ansible-test
+# uses: ansible-community/ansible-test-gh-action@release/v1
+# with:
+# ansible-core-version: ${{ matrix.ansible }}
+# testing-type: sanity
- units:
- runs-on: ubuntu-latest
- name: Units (Ⓐ${{ matrix.ansible }}+py${{ matrix.python }})
- strategy:
- # As soon as the first unit test fails, cancel the others to free up the CI queue
- fail-fast: true
- matrix:
- ansible:
- - stable-2.9 # Only if your collection supports Ansible 2.9
- - stable-2.10
- - stable-2.11
- - stable-2.12
- - devel
- python:
- - 2.6
- - 2.7
- - 3.5
- - 3.6
- - 3.7
- - 3.8
- - 3.9
- exclude:
- # Because ansible-test doesn't support python3.9 for Ansible 2.9
- - ansible: stable-2.9
- python: 3.9
- - ansible: devel
- python: 2.6
+# units:
+# runs-on: ubuntu-latest
+# name: Units (Ⓐ${{ matrix.ansible }}+py${{ matrix.python }})
+# strategy:
+# # As soon as the first unit test fails, cancel the others to free up the CI queue
+# fail-fast: true
+# matrix:
+# ansible:
+# - stable-2.9 # Only if your collection supports Ansible 2.9
+# - stable-2.10
+# - stable-2.11
+# - stable-2.12
+# - devel
+# python:
+# - 2.6
+# - 2.7
+# - 3.5
+# - 3.6
+# - 3.7
+# - 3.8
+# - 3.9
+# exclude:
+# # Because ansible-test doesn't support python3.9 for Ansible 2.9
+# - ansible: stable-2.9
+# python: 3.9
+# - ansible: devel
+# python: 2.6
- steps:
- - name: Check out code
- uses: actions/checkout@v2
+# steps:
+# - name: Check out code
+# uses: actions/checkout@v2
- - name: Perform unit testing with ansible-test
- uses: ansible-community/ansible-test-gh-action@release/v1
- with:
- ansible-core-version: ${{ matrix.ansible }}
- target-python-version: ${{ matrix.python }}
- python-version: 3.8
- testing-type: units
- test-deps: >-
- ansible.netcommon
- ansible.utils
+# - name: Perform unit testing with ansible-test
+# uses: ansible-community/ansible-test-gh-action@release/v1
+# with:
+# ansible-core-version: ${{ matrix.ansible }}
+# target-python-version: ${{ matrix.python }}
+# python-version: 3.8
+# testing-type: units
+# test-deps: >-
+# ansible.netcommon
+# ansible.utils
-# Please consult the Readme for information on why we disabled integration tests temporarily.
+# # Please consult the Readme for information on why we disabled integration tests temporarily.
- # integration:
- # runs-on: ubuntu-latest
- # name: I (Ⓐ${{ matrix.ansible }}+py${{ matrix.python }})
- # strategy:
- # fail-fast: false
- # matrix:
- # ansible:
- # - stable-2.9 # Only if your collection supports Ansible 2.9
- # - stable-2.10
- # - stable-2.11
- # - stable-2.12
- # - devel
- # python:
- # - 2.6
- # - 2.7
- # - 3.5
- # - 3.6
- # - 3.7
- # - 3.8
- # - 3.9
- # exclude:
- # # Because ansible-test doesn't support python3.9 for Ansible 2.9
- # - ansible: stable-2.9
- # python: 3.9
- # - ansible: devel
- # python: 2.6
+# # integration:
+# # runs-on: ubuntu-latest
+# # name: I (Ⓐ${{ matrix.ansible }}+py${{ matrix.python }})
+# # strategy:
+# # fail-fast: false
+# # matrix:
+# # ansible:
+# # - stable-2.9 # Only if your collection supports Ansible 2.9
+# # - stable-2.10
+# # - stable-2.11
+# # - stable-2.12
+# # - devel
+# # python:
+# # - 2.6
+# # - 2.7
+# # - 3.5
+# # - 3.6
+# # - 3.7
+# # - 3.8
+# # - 3.9
+# # exclude:
+# # # Because ansible-test doesn't support python3.9 for Ansible 2.9
+# # - ansible: stable-2.9
+# # python: 3.9
+# # - ansible: devel
+# # python: 2.6
- # steps:
- # - name: Check out code
- # uses: actions/checkout@v2
+# # steps:
+# # - name: Check out code
+# # uses: actions/checkout@v2
- # - name: Perform integration testing with ansible-test
- # uses: ansible-community/ansible-test-gh-action@release/v1
- # with:
- # ansible-core-version: ${{ matrix.ansible }}
- # python-version: 3.8
- # pre-test-cmd: >-
- # mkdir -p tests/output/
- # touch tests/output/coverage
- # target-python-version: ${{ matrix.python }}
- # testing-type: integration
- # test-deps: >-
- # ansible.netcommon
- # ansible.utils
+# # - name: Perform integration testing with ansible-test
+# # uses: ansible-community/ansible-test-gh-action@release/v1
+# # with:
+# # ansible-core-version: ${{ matrix.ansible }}
+# # python-version: 3.8
+# # pre-test-cmd: >-
+# # mkdir -p tests/output/
+# # touch tests/output/coverage
+# # target-python-version: ${{ matrix.python }}
+# # testing-type: integration
+# # test-deps: >-
+# # ansible.netcommon
+# # ansible.utils
diff --git a/ansible_collections/community/sap/CHANGELOG.rst b/ansible_collections/community/sap/CHANGELOG.rst
index 2662ad232..714ed15a5 100644
--- a/ansible_collections/community/sap/CHANGELOG.rst
+++ b/ansible_collections/community/sap/CHANGELOG.rst
@@ -5,15 +5,37 @@ Community SAP Release Notes
.. contents:: Topics
+v2.0.0
+======
+
+Release Summary
+---------------
+
+This release deprecates all modules and redirect them to community.sap_libs. The modules are removed in this release.
+The modules are available in the community.sap_libs repository.
+
+Major Changes
+-------------
+
+- all modules - everything is now a redirect to the new collection community.sap_libs
+
+Deprecated Features
+-------------------
+
+- community.sap.hana_query - is deprecated in favor of community.sap_libs.sap_hdbsql
+- community.sap.sap_company - is deprecated in favor of community.sap_libs.sap_company
+- community.sap.sap_snote - is deprecated in favor of community.sap_libs.sap_snote
+- community.sap.sap_task_list_execute - is deprecated in favor of community.sap_libs.sap_task_list_execute
+- community.sap.sap_user - is deprecated in favor of community.sap_libs.sap_user
+- community.sap.sapcar_extract - is deprecated in favor of community.sap_libs.sapcar_extract
+
v1.0.0
======
Release Summary
---------------
-This is the fir major release of the ``community.sap`` collection.
-This changelog contains all changes to the modules and plugins in this collection
-that have been made after the previous release.
+This is the first major release of the ``community.sap`` collection. This changelog contains all changes to the modules and plugins in this collection that have been made after the previous release.
Minor Changes
-------------
@@ -26,14 +48,14 @@ New Modules
Identity
~~~~~~~~
-- identity.sap_company - This module will manage a company entities in a SAP S4HANA environment
-- identity.sap_user - This module will manage a user entities in a SAP S4/HANA environment
+- sap_company - This module will manage a company entities in a SAP S4HANA environment
+- sap_user - This module will manage a user entities in a SAP S4/HANA environment
System
~~~~~~
-- system.sap_snote - This module will upload and (de)implements C(SNOTES) in a SAP S4HANA environment.
-- system.sap_system_facts - Gathers SAP facts in a host
+- sap_snote - This module will upload and (de)implements C(SNOTES) in a SAP S4HANA environment.
+- sap_system_facts - Gathers SAP facts in a host
v0.1.0
======
@@ -52,14 +74,14 @@ Database
saphana
^^^^^^^
-- database.saphana.hana_query - Execute SQL on HANA
+- hana_query - Execute SQL on HANA
Files
~~~~~
-- files.sapcar_extract - Manages SAP SAPCAR archives
+- sapcar_extract - Manages SAP SAPCAR archives
System
~~~~~~
-- system.sap_task_list_execute - Perform SAP Task list execution
+- sap_task_list_execute - Perform SAP Task list execution
diff --git a/ansible_collections/community/sap/FILES.json b/ansible_collections/community/sap/FILES.json
index 94f9d13cb..05e702336 100644
--- a/ansible_collections/community/sap/FILES.json
+++ b/ansible_collections/community/sap/FILES.json
@@ -60,7 +60,7 @@
"name": ".github/workflows/ansible-test.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b33230275f011323f420a5c0bac294a83590804750a1895e78ab9d8f0e89e874",
+ "chksum_sha256": "141fb2c403baf2847bf06f9281f397e22fc5325262ef017cace4bde09d6f803d",
"format": 1
},
{
@@ -102,14 +102,14 @@
"name": "changelogs/changelog.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6638411429b43df9657c1fda5c88510094303f9f58b929c5676f66fac72b8d4c",
+ "chksum_sha256": "d58ffee3cafd91ae2cebaa92a66100609fcf1a19501b2e00c1d5b93d0bbc7fcb",
"format": 1
},
{
"name": "changelogs/config.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "60799a00c74a20f69eadcfd8e4fa218bf3d118cc3d6bc2e538ff6efb47760d00",
+ "chksum_sha256": "5f253a9432287fcdfe3100b556bf39d442a5e8b5a5fd3ec4a971f37f954ebac0",
"format": 1
},
{
@@ -123,7 +123,7 @@
"name": "meta/runtime.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "df18179bb2f5447a56ac92261a911649b96821c0b2c08eea62d5cc6b0195203f",
+ "chksum_sha256": "9a8c86337928225fea4abd7361f2813f48b1770c4ae83aac940e7b491a4e143a",
"format": 1
},
{
@@ -169,136 +169,10 @@
"format": 1
},
{
- "name": "plugins/modules/hana_query.py",
+ "name": "plugins/modules/__init__.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "44ffd7642f1285a808a04bb7772a1869c4a0075a049c6370f98c53c5581ad8b6",
- "format": 1
- },
- {
- "name": "plugins/modules/sap_company.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "daf9bd3a40aba75148729b1b10fd4c4d0a320d6660228bce8d7c1cd90c6bf5e8",
- "format": 1
- },
- {
- "name": "plugins/modules/sap_snote.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "52b12cacc618430f176efc1cd91021bf83e74ed9f4d2febf7f1200241fb559bb",
- "format": 1
- },
- {
- "name": "plugins/modules/sap_system_facts.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "def5406922e38fb12999ebd2463bf3e560dd2cc7b6052c63426b4277e2963b23",
- "format": 1
- },
- {
- "name": "plugins/modules/sap_task_list_execute.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "62052a6017278b4bc1d22bad9f0638f4fc78f5b2ba7de72870fa5de5cf15c96c",
- "format": 1
- },
- {
- "name": "plugins/modules/sap_user.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "73079c029034e5d047231f06b0302d362c23b494448a856011bad7a2d93abd62",
- "format": 1
- },
- {
- "name": "plugins/modules/sapcar_extract.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "52a51f17cd9f0ffd5ddeb63d2c397526db7ced2c78fc3008385e9ca00659ae72",
- "format": 1
- },
- {
- "name": "plugins/modules/database",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "plugins/modules/database/saphana",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "plugins/modules/database/saphana/hana_query.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "44ffd7642f1285a808a04bb7772a1869c4a0075a049c6370f98c53c5581ad8b6",
- "format": 1
- },
- {
- "name": "plugins/modules/files",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "plugins/modules/files/sapcar_extract.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "52a51f17cd9f0ffd5ddeb63d2c397526db7ced2c78fc3008385e9ca00659ae72",
- "format": 1
- },
- {
- "name": "plugins/modules/identity",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "plugins/modules/identity/sap_company.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "daf9bd3a40aba75148729b1b10fd4c4d0a320d6660228bce8d7c1cd90c6bf5e8",
- "format": 1
- },
- {
- "name": "plugins/modules/identity/sap_user.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "73079c029034e5d047231f06b0302d362c23b494448a856011bad7a2d93abd62",
- "format": 1
- },
- {
- "name": "plugins/modules/system",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "plugins/modules/system/sap_snote.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "52b12cacc618430f176efc1cd91021bf83e74ed9f4d2febf7f1200241fb559bb",
- "format": 1
- },
- {
- "name": "plugins/modules/system/sap_system_facts.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "def5406922e38fb12999ebd2463bf3e560dd2cc7b6052c63426b4277e2963b23",
- "format": 1
- },
- {
- "name": "plugins/modules/system/sap_task_list_execute.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "62052a6017278b4bc1d22bad9f0638f4fc78f5b2ba7de72870fa5de5cf15c96c",
+ "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"format": 1
},
{
@@ -606,7 +480,7 @@
"name": "CHANGELOG.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "96de6ff24a33521295f40c708f78bd801ce7a7cf5756a2982e292fc8de826d5e",
+ "chksum_sha256": "63e3ec595a36659d4977981c1abfd3c8efb0fe2eace862746feabe968e13ba3f",
"format": 1
},
{
@@ -648,7 +522,7 @@
"name": "README.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "241e90547fb638d794abf998542e9e72675b4ce97ed1e3ff223267f195818a63",
+ "chksum_sha256": "d600b5ca720d33e93ee89c9bdfba410c8f7dc435fa29ea7ca4ebfa3159f4311b",
"format": 1
},
{
diff --git a/ansible_collections/community/sap/MANIFEST.json b/ansible_collections/community/sap/MANIFEST.json
index b03f312a2..5385f2f71 100644
--- a/ansible_collections/community/sap/MANIFEST.json
+++ b/ansible_collections/community/sap/MANIFEST.json
@@ -2,7 +2,7 @@
"collection_info": {
"namespace": "community",
"name": "sap",
- "version": "1.0.0",
+ "version": "2.0.0",
"authors": [
"Rainer Leber (github.com/rainerleber)",
"Robert Kraemer (github.com/rkpobe)"
@@ -14,9 +14,11 @@
"description": "SAP community collection for Ansible",
"license": [],
"license_file": "LICENSE",
- "dependencies": {},
+ "dependencies": {
+ "community.sap_libs": ">=1.0.0"
+ },
"repository": "https://github.com/ansible-collections/community.sap",
- "documentation": "https://github.com/ansible-collection/community.sap/tree/main/docs",
+ "documentation": "https://github.com/ansible-collection/community.sap",
"homepage": "https://github.com/ansible-collections/community.sap",
"issues": "https://github.com/ansible-collections/community.sap/issues"
},
@@ -24,7 +26,7 @@
"name": "FILES.json",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "37274fcb06645cec88067238f9d976cb36d1a807453950618d6f8537de8483bc",
+ "chksum_sha256": "90eb59f365d6576a46b04852a21d5998d4ad14dcbb20ae1547d5a1667dcda9d9",
"format": 1
},
"format": 1
diff --git a/ansible_collections/community/sap/README.md b/ansible_collections/community/sap/README.md
index 84940afce..dd935b270 100644
--- a/ansible_collections/community/sap/README.md
+++ b/ansible_collections/community/sap/README.md
@@ -1,5 +1,11 @@
-# Community SAP Collection
+# Deprecated Community SAP Collection
+# **WARNING: This collection is deprecated, not maintained anymore and superseded by the collection [**community.sap_libs**](https://github.com/sap-linuxlab/community.sap_libs)**
+
+**Feel free to raise issues at the new place.
+All CI tests are disabled.**
+
+---
This repository contains the community.sap Ansible Collection. The collection includes modules and plugins supported by the Ansible SAP community to help SAP landscape management.
# SAP Collection for Ansible
diff --git a/ansible_collections/community/sap/changelogs/changelog.yaml b/ansible_collections/community/sap/changelogs/changelog.yaml
index bfa4aa056..39f79a298 100644
--- a/ansible_collections/community/sap/changelogs/changelog.yaml
+++ b/ansible_collections/community/sap/changelogs/changelog.yaml
@@ -21,9 +21,9 @@ releases:
changes:
minor_changes:
- sapcar_extract.py - more strict logic for filenames
- release_summary: 'This is the first major release of the ``community.sap`` collection.
+ release_summary: This is the first major release of the ``community.sap`` collection.
This changelog contains all changes to the modules and plugins in this collection
- that have been made after the previous release.'
+ that have been made after the previous release.
fragments:
- 1.0.0.yml
- 11-filenamesuffixcheck.yml
@@ -42,3 +42,22 @@ releases:
name: sap_user
namespace: identity
release_date: '2022-02-17'
+ 2.0.0:
+ changes:
+ deprecated_features:
+ - community.sap.hana_query - is deprecated in favor of community.sap_libs.sap_hdbsql
+ - community.sap.sap_company - is deprecated in favor of community.sap_libs.sap_company
+ - community.sap.sap_snote - is deprecated in favor of community.sap_libs.sap_snote
+ - community.sap.sap_task_list_execute - is deprecated in favor of community.sap_libs.sap_task_list_execute
+ - community.sap.sap_user - is deprecated in favor of community.sap_libs.sap_user
+ - community.sap.sapcar_extract - is deprecated in favor of community.sap_libs.sapcar_extract
+ major_changes:
+ - all modules - everything is now a redirect to the new collection community.sap_libs
+ release_summary: 'This release deprecates all modules and redirect them to community.sap_libs.
+ The modules are removed in this release.
+
+ The modules are available in the community.sap_libs repository.'
+ fragments:
+ - 0029-deprecation.yml
+ - 2.0.0.yml
+ release_date: '2023-07-14'
diff --git a/ansible_collections/community/sap/changelogs/config.yaml b/ansible_collections/community/sap/changelogs/config.yaml
index 76c44c97e..db443763c 100644
--- a/ansible_collections/community/sap/changelogs/config.yaml
+++ b/ansible_collections/community/sap/changelogs/config.yaml
@@ -4,6 +4,7 @@ changes_file: changelog.yaml
changes_format: combined
keep_fragments: false
mention_ancestor: true
+flatmap: true
new_plugins_after_name: removed_features
notesdir: fragments
prelude_section_name: release_summary
diff --git a/ansible_collections/community/sap/meta/runtime.yml b/ansible_collections/community/sap/meta/runtime.yml
index 2ee3c9fa9..15cbcba59 100644
--- a/ansible_collections/community/sap/meta/runtime.yml
+++ b/ansible_collections/community/sap/meta/runtime.yml
@@ -1,2 +1,33 @@
---
requires_ansible: '>=2.9.10'
+
+plugin_routing:
+ modules:
+ community.sap.hana_query:
+ redirect: community.sap_libs.sap_hdbsql
+ deprecation:
+ warning_text: Use community.sap_libs.sap_hdbsql instead.
+ community.sap.sap_company:
+ redirect: community.sap_libs.sap_company
+ deprecation:
+ warning_text: Use community.sap_libs.sap_company instead.
+ community.sap.sap_snote:
+ redirect: community.sap_libs.sap_snote
+ deprecation:
+ warning_text: Use community.sap_libs.sap_snote instead.
+ community.sap.sap_snote:
+ redirect: community.sap_libs.sap_system_facts
+ deprecation:
+ warning_text: Use community.sap_libs.sap_system_facts instead.
+ community.sap.sap_user:
+ redirect: community.sap_libs.sap_user
+ deprecation:
+ warning_text: Use community.sap_libs.sap_user instead.
+ community.sap.sap_task_list_execute:
+ redirect: community.sap_libs.sap_task_list_execute
+ deprecation:
+ warning_text: Use community.sap_libs.sap_task_list_execute instead.
+ community.sap.sapcar_extract:
+ redirect: community.sap_libs.sapcar_extract
+ deprecation:
+ warning_text: Use community.sap_libs.sapcar_extract instead.
diff --git a/ansible_collections/community/google/tests/unit/compat/__init__.py b/ansible_collections/community/sap/plugins/modules/__init__.py
index e69de29bb..e69de29bb 100644
--- a/ansible_collections/community/google/tests/unit/compat/__init__.py
+++ b/ansible_collections/community/sap/plugins/modules/__init__.py
diff --git a/ansible_collections/community/sap/plugins/modules/database/saphana/hana_query.py b/ansible_collections/community/sap/plugins/modules/database/saphana/hana_query.py
deleted file mode 100644
index 9eb43db09..000000000
--- a/ansible_collections/community/sap/plugins/modules/database/saphana/hana_query.py
+++ /dev/null
@@ -1,238 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# Copyright: (c) 2021, Rainer Leber <rainerleber@gmail.com>
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-DOCUMENTATION = r'''
----
-module: hana_query
-short_description: Execute SQL on HANA
-version_added: "0.1.0"
-description: This module executes SQL statements on HANA with hdbsql.
-options:
- sid:
- description: The system ID.
- type: str
- required: false
- bin_path:
- description: The path to the hdbsql binary.
- type: str
- required: false
- instance:
- description: The instance number.
- type: str
- required: true
- user:
- description: A dedicated username. The user could be also in hdbuserstore.
- type: str
- default: SYSTEM
- userstore:
- description: If C(true), the user must be in hdbuserstore.
- type: bool
- default: false
- password:
- description:
- - The password to connect to the database.
- - "B(Note:) Since the passwords have to be passed as command line arguments, I(userstore=true) should
- be used whenever possible, as command line arguments can be seen by other users
- on the same machine."
- type: str
- autocommit:
- description: Autocommit the statement.
- type: bool
- default: true
- host:
- description: The Host IP address. The port can be defined as well.
- type: str
- database:
- description: Define the database on which to connect.
- type: str
- encrypted:
- description: Use encrypted connection.
- type: bool
- default: false
- filepath:
- description:
- - One or more files each containing one SQL query to run.
- - Must be a string or list containing strings.
- type: list
- elements: path
- query:
- description:
- - SQL query to run.
- - Must be a string or list containing strings. Please note that if you supply a string, it will be split by commas (C(,)) to a list.
- It is better to supply a one-element list instead to avoid mangled input.
- type: list
- elements: str
-notes:
- - Does not support C(check_mode). Always reports that the state has changed even if no changes have been made.
-author:
- - Rainer Leber (@rainerleber)
-'''
-
-EXAMPLES = r'''
-- name: Simple select query
- community.sap.hana_query:
- sid: "hdb"
- instance: "01"
- password: "Test123"
- query: select user_name from users
-
-- name: RUN select query with host port
- community.sap.hana_query:
- sid: "hdb"
- instance: "01"
- password: "Test123"
- host: "10.10.2.4:30001"
- query: select user_name from users
-
-- name: Run several queries
- community.sap.hana_query:
- sid: "hdb"
- instance: "01"
- password: "Test123"
- query:
- - select user_name from users
- - select * from SYSTEM
- host: "localhost"
- autocommit: False
-
-- name: Run several queries with path
- community.sap.hana_query:
- bin_path: "/usr/sap/HDB/HDB01/exe/hdbsql"
- instance: "01"
- password: "Test123"
- query:
- - select user_name from users
- - select * from users
- host: "localhost"
- autocommit: False
-
-- name: Run several queries from file
- community.sap.hana_query:
- sid: "hdb"
- instance: "01"
- password: "Test123"
- filepath:
- - /tmp/HANA_CPU_UtilizationPerCore_2.00.020+.txt
- - /tmp/HANA.txt
- host: "localhost"
-
-- name: Run several queries from user store
- community.sap.hana_query:
- sid: "hdb"
- instance: "01"
- user: hdbstoreuser
- userstore: true
- query:
- - select user_name from users
- - select * from users
- autocommit: False
-'''
-
-RETURN = r'''
-query_result:
- description: List containing results of all queries executed (one sublist for every query).
- returned: on success
- type: list
- elements: list
- sample: [[{"Column": "Value1"}, {"Column": "Value2"}], [{"Column": "Value1"}, {"Column": "Value2"}]]
-'''
-
-import csv
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.six import StringIO
-from ansible.module_utils.common.text.converters import to_native
-
-
-def csv_to_list(rawcsv):
- reader_raw = csv.DictReader(StringIO(rawcsv))
- reader = [dict((k, v.strip()) for k, v in row.items()) for row in reader_raw]
- return list(reader)
-
-
-def main():
- module = AnsibleModule(
- argument_spec=dict(
- sid=dict(type='str', required=False),
- bin_path=dict(type='str', required=False),
- instance=dict(type='str', required=True),
- encrypted=dict(type='bool', default=False),
- host=dict(type='str', required=False),
- user=dict(type='str', default="SYSTEM"),
- userstore=dict(type='bool', default=False),
- password=dict(type='str', no_log=True),
- database=dict(type='str', required=False),
- query=dict(type='list', elements='str', required=False),
- filepath=dict(type='list', elements='path', required=False),
- autocommit=dict(type='bool', default=True),
- ),
- required_one_of=[('query', 'filepath'), ('sid', 'instance')],
- required_if=[('userstore', False, ['password'])],
- supports_check_mode=False,
- )
- rc, out, err, out_raw = [0, [], "", ""]
-
- params = module.params
-
- sid = params['sid']
- bin_path = params['bin_path']
- instance = params['instance']
- user = params['user']
- userstore = params['userstore']
- password = params['password']
- autocommit = params['autocommit']
- host = params['host']
- database = params['database']
- encrypted = params['encrypted']
-
- filepath = params['filepath']
- query = params['query']
-
- if bin_path is None:
- bin_path = "/usr/sap/{sid}/HDB{instance}/exe/hdbsql".format(sid=sid.upper(), instance=instance)
-
- try:
- command = [module.get_bin_path(bin_path, required=True)]
- except Exception as e:
- module.fail_json(msg='Failed to find hdbsql at the expected path "{0}".Please check SID and instance number: "{1}"'.format(bin_path, to_native(e)))
-
- if encrypted is True:
- command.extend(['-attemptencrypt'])
- if autocommit is False:
- command.extend(['-z'])
- if host is not None:
- command.extend(['-n', host])
- if database is not None:
- command.extend(['-d', database])
- # -x Suppresses additional output, such as the number of selected rows in a result set.
- if userstore:
- command.extend(['-x', '-U', user])
- else:
- command.extend(['-x', '-i', instance, '-u', user, '-p', password])
-
- if filepath is not None:
- command.extend(['-I'])
- for p in filepath:
- # makes a command like hdbsql -i 01 -u SYSTEM -p secret123# -I /tmp/HANA_CPU_UtilizationPerCore_2.00.020+.txt,
- # iterates through files and append the output to var out.
- query_command = command + [p]
- (rc, out_raw, err) = module.run_command(query_command)
- out.append(csv_to_list(out_raw))
- if query is not None:
- for q in query:
- # makes a command like hdbsql -i 01 -u SYSTEM -p secret123# "select user_name from users",
- # iterates through multiple commands and append the output to var out.
- query_command = command + [q]
- (rc, out_raw, err) = module.run_command(query_command)
- out.append(csv_to_list(out_raw))
- changed = True
-
- module.exit_json(changed=changed, rc=rc, query_result=out, stderr=err)
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/sap/plugins/modules/files/sapcar_extract.py b/ansible_collections/community/sap/plugins/modules/files/sapcar_extract.py
deleted file mode 100644
index d586dd330..000000000
--- a/ansible_collections/community/sap/plugins/modules/files/sapcar_extract.py
+++ /dev/null
@@ -1,220 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# Copyright: (c) 2021, Rainer Leber <rainerleber@gmail.com>
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-DOCUMENTATION = r'''
----
-module: sapcar_extract
-short_description: Manages SAP SAPCAR archives
-version_added: "0.1.0"
-description:
- - Provides support for unpacking C(sar)/C(car) files with the SAPCAR binary from SAP and pulling
- information back into Ansible.
-options:
- path:
- description: The path to the SAR/CAR file.
- type: path
- required: true
- dest:
- description:
- - The destination where SAPCAR extracts the SAR file. Missing folders will be created.
- If this parameter is not provided, it will unpack in the same folder as the SAR file.
- type: path
- binary_path:
- description:
- - The path to the SAPCAR binary, for example, C(/home/dummy/sapcar) or C(https://myserver/SAPCAR).
- If this parameter is not provided, the module will look in C(PATH).
- type: path
- signature:
- description:
- - If C(true), the signature will be extracted.
- default: false
- type: bool
- security_library:
- description:
- - The path to the security library, for example, C(/usr/sap/hostctrl/exe/libsapcrytp.so), for signature operations.
- type: path
- manifest:
- description:
- - The name of the manifest.
- default: "SIGNATURE.SMF"
- type: str
- remove:
- description:
- - If C(true), the SAR/CAR file will be removed. B(This should be used with caution!)
- default: false
- type: bool
-author:
- - Rainer Leber (@RainerLeber)
-notes:
- - Always returns C(changed=true) in C(check_mode).
-'''
-
-EXAMPLES = r"""
-- name: Extract SAR file
- community.sap.sapcar_extract:
- path: "~/source/hana.sar"
-
-- name: Extract SAR file with destination
- community.sap.sapcar_extract:
- path: "~/source/hana.sar"
- dest: "~/test/"
-
-- name: Extract SAR file with destination and download from webserver can be a fileshare as well
- community.sap.sapcar_extract:
- path: "~/source/hana.sar"
- dest: "~/dest/"
- binary_path: "https://myserver/SAPCAR"
-
-- name: Extract SAR file and delete SAR after extract
- community.sap.sapcar_extract:
- path: "~/source/hana.sar"
- remove: true
-
-- name: Extract SAR file with manifest
- community.sap.sapcar_extract:
- path: "~/source/hana.sar"
- signature: true
-
-- name: Extract SAR file with manifest and rename it
- community.sap.sapcar_extract:
- path: "~/source/hana.sar"
- manifest: "MyNewSignature.SMF"
- signature: true
-"""
-
-import os
-from tempfile import NamedTemporaryFile
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.urls import open_url
-from ansible.module_utils.common.text.converters import to_native
-
-
-def get_list_of_files(dir_name):
- # create a list of file and directories
- # names in the given directory
- list_of_file = os.listdir(dir_name)
- allFiles = list()
- # Iterate over all the entries
- for entry in list_of_file:
- # Create full path
- fullPath = os.path.join(dir_name, entry)
- # If entry is a directory then get the list of files in this directory
- if os.path.isdir(fullPath):
- allFiles = allFiles + [fullPath]
- allFiles = allFiles + get_list_of_files(fullPath)
- else:
- allFiles.append(fullPath)
- return allFiles
-
-
-def download_SAPCAR(binary_path, module):
- bin_path = None
- # download sapcar binary if url is provided otherwise path is returned
- if binary_path is not None:
- if binary_path.startswith('https://') or binary_path.startswith('http://'):
- random_file = NamedTemporaryFile(delete=False)
- with open_url(binary_path) as response:
- with random_file as out_file:
- data = response.read()
- out_file.write(data)
- os.chmod(out_file.name, 0o700)
- bin_path = out_file.name
- module.add_cleanup_file(bin_path)
- else:
- bin_path = binary_path
- return bin_path
-
-
-def check_if_present(command, path, dest, signature, manifest, module):
- # manipulating output from SAR file for compare with already extracted files
- iter_command = [command, '-tvf', path]
- sar_out = module.run_command(iter_command)[1]
- sar_raw = sar_out.split("\n")[1:]
- if dest[-1] != "/":
- dest = dest + "/"
- sar_files = [dest + x.split(" ")[-1] for x in sar_raw if x]
- # remove any SIGNATURE.SMF from list because it will not unpacked if signature is false
- if not signature:
- sar_files = [item for item in sar_files if not item.endswith('.SMF')]
- # if signature is renamed manipulate files in list of sar file for compare.
- if manifest != "SIGNATURE.SMF":
- sar_files = [item for item in sar_files if not item.endswith('.SMF')]
- sar_files = sar_files + [manifest]
- # get extracted files if present
- files_extracted = get_list_of_files(dest)
- # compare extracted files with files in sar file
- present = all(elem in files_extracted for elem in sar_files)
- return present
-
-
-def main():
- module = AnsibleModule(
- argument_spec=dict(
- path=dict(type='path', required=True),
- dest=dict(type='path'),
- binary_path=dict(type='path'),
- signature=dict(type='bool', default=False),
- security_library=dict(type='path'),
- manifest=dict(type='str', default="SIGNATURE.SMF"),
- remove=dict(type='bool', default=False),
- ),
- supports_check_mode=True,
- )
- rc, out, err = [0, "", ""]
- params = module.params
- check_mode = module.check_mode
-
- path = params['path']
- dest = params['dest']
- signature = params['signature']
- security_library = params['security_library']
- manifest = params['manifest']
- remove = params['remove']
-
- bin_path = download_SAPCAR(params['binary_path'], module)
-
- if dest is None:
- dest_head_tail = os.path.split(path)
- dest = dest_head_tail[0] + '/'
- else:
- if not os.path.exists(dest):
- os.makedirs(dest, 0o755)
-
- if bin_path is not None:
- command = [module.get_bin_path(bin_path, required=True)]
- else:
- try:
- command = [module.get_bin_path('sapcar', required=True)]
- except Exception as e:
- module.fail_json(msg='Failed to find SAPCAR at the expected path or URL "{0}". Please check whether it is available: {1}'
- .format(bin_path, to_native(e)))
-
- present = check_if_present(command[0], path, dest, signature, manifest, module)
-
- if not present:
- command.extend(['-xvf', path, '-R', dest])
- if security_library:
- command.extend(['-L', security_library])
- if signature:
- command.extend(['-manifest', manifest])
- if not check_mode:
- (rc, out, err) = module.run_command(command, check_rc=True)
- changed = True
- else:
- changed = False
- out = "already unpacked"
-
- if remove:
- os.remove(path)
-
- module.exit_json(changed=changed, message=rc, stdout=out,
- stderr=err, command=' '.join(command))
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/sap/plugins/modules/hana_query.py b/ansible_collections/community/sap/plugins/modules/hana_query.py
deleted file mode 100644
index 9eb43db09..000000000
--- a/ansible_collections/community/sap/plugins/modules/hana_query.py
+++ /dev/null
@@ -1,238 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# Copyright: (c) 2021, Rainer Leber <rainerleber@gmail.com>
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-DOCUMENTATION = r'''
----
-module: hana_query
-short_description: Execute SQL on HANA
-version_added: "0.1.0"
-description: This module executes SQL statements on HANA with hdbsql.
-options:
- sid:
- description: The system ID.
- type: str
- required: false
- bin_path:
- description: The path to the hdbsql binary.
- type: str
- required: false
- instance:
- description: The instance number.
- type: str
- required: true
- user:
- description: A dedicated username. The user could be also in hdbuserstore.
- type: str
- default: SYSTEM
- userstore:
- description: If C(true), the user must be in hdbuserstore.
- type: bool
- default: false
- password:
- description:
- - The password to connect to the database.
- - "B(Note:) Since the passwords have to be passed as command line arguments, I(userstore=true) should
- be used whenever possible, as command line arguments can be seen by other users
- on the same machine."
- type: str
- autocommit:
- description: Autocommit the statement.
- type: bool
- default: true
- host:
- description: The Host IP address. The port can be defined as well.
- type: str
- database:
- description: Define the database on which to connect.
- type: str
- encrypted:
- description: Use encrypted connection.
- type: bool
- default: false
- filepath:
- description:
- - One or more files each containing one SQL query to run.
- - Must be a string or list containing strings.
- type: list
- elements: path
- query:
- description:
- - SQL query to run.
- - Must be a string or list containing strings. Please note that if you supply a string, it will be split by commas (C(,)) to a list.
- It is better to supply a one-element list instead to avoid mangled input.
- type: list
- elements: str
-notes:
- - Does not support C(check_mode). Always reports that the state has changed even if no changes have been made.
-author:
- - Rainer Leber (@rainerleber)
-'''
-
-EXAMPLES = r'''
-- name: Simple select query
- community.sap.hana_query:
- sid: "hdb"
- instance: "01"
- password: "Test123"
- query: select user_name from users
-
-- name: RUN select query with host port
- community.sap.hana_query:
- sid: "hdb"
- instance: "01"
- password: "Test123"
- host: "10.10.2.4:30001"
- query: select user_name from users
-
-- name: Run several queries
- community.sap.hana_query:
- sid: "hdb"
- instance: "01"
- password: "Test123"
- query:
- - select user_name from users
- - select * from SYSTEM
- host: "localhost"
- autocommit: False
-
-- name: Run several queries with path
- community.sap.hana_query:
- bin_path: "/usr/sap/HDB/HDB01/exe/hdbsql"
- instance: "01"
- password: "Test123"
- query:
- - select user_name from users
- - select * from users
- host: "localhost"
- autocommit: False
-
-- name: Run several queries from file
- community.sap.hana_query:
- sid: "hdb"
- instance: "01"
- password: "Test123"
- filepath:
- - /tmp/HANA_CPU_UtilizationPerCore_2.00.020+.txt
- - /tmp/HANA.txt
- host: "localhost"
-
-- name: Run several queries from user store
- community.sap.hana_query:
- sid: "hdb"
- instance: "01"
- user: hdbstoreuser
- userstore: true
- query:
- - select user_name from users
- - select * from users
- autocommit: False
-'''
-
-RETURN = r'''
-query_result:
- description: List containing results of all queries executed (one sublist for every query).
- returned: on success
- type: list
- elements: list
- sample: [[{"Column": "Value1"}, {"Column": "Value2"}], [{"Column": "Value1"}, {"Column": "Value2"}]]
-'''
-
-import csv
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.six import StringIO
-from ansible.module_utils.common.text.converters import to_native
-
-
-def csv_to_list(rawcsv):
- reader_raw = csv.DictReader(StringIO(rawcsv))
- reader = [dict((k, v.strip()) for k, v in row.items()) for row in reader_raw]
- return list(reader)
-
-
-def main():
- module = AnsibleModule(
- argument_spec=dict(
- sid=dict(type='str', required=False),
- bin_path=dict(type='str', required=False),
- instance=dict(type='str', required=True),
- encrypted=dict(type='bool', default=False),
- host=dict(type='str', required=False),
- user=dict(type='str', default="SYSTEM"),
- userstore=dict(type='bool', default=False),
- password=dict(type='str', no_log=True),
- database=dict(type='str', required=False),
- query=dict(type='list', elements='str', required=False),
- filepath=dict(type='list', elements='path', required=False),
- autocommit=dict(type='bool', default=True),
- ),
- required_one_of=[('query', 'filepath'), ('sid', 'instance')],
- required_if=[('userstore', False, ['password'])],
- supports_check_mode=False,
- )
- rc, out, err, out_raw = [0, [], "", ""]
-
- params = module.params
-
- sid = params['sid']
- bin_path = params['bin_path']
- instance = params['instance']
- user = params['user']
- userstore = params['userstore']
- password = params['password']
- autocommit = params['autocommit']
- host = params['host']
- database = params['database']
- encrypted = params['encrypted']
-
- filepath = params['filepath']
- query = params['query']
-
- if bin_path is None:
- bin_path = "/usr/sap/{sid}/HDB{instance}/exe/hdbsql".format(sid=sid.upper(), instance=instance)
-
- try:
- command = [module.get_bin_path(bin_path, required=True)]
- except Exception as e:
- module.fail_json(msg='Failed to find hdbsql at the expected path "{0}".Please check SID and instance number: "{1}"'.format(bin_path, to_native(e)))
-
- if encrypted is True:
- command.extend(['-attemptencrypt'])
- if autocommit is False:
- command.extend(['-z'])
- if host is not None:
- command.extend(['-n', host])
- if database is not None:
- command.extend(['-d', database])
- # -x Suppresses additional output, such as the number of selected rows in a result set.
- if userstore:
- command.extend(['-x', '-U', user])
- else:
- command.extend(['-x', '-i', instance, '-u', user, '-p', password])
-
- if filepath is not None:
- command.extend(['-I'])
- for p in filepath:
- # makes a command like hdbsql -i 01 -u SYSTEM -p secret123# -I /tmp/HANA_CPU_UtilizationPerCore_2.00.020+.txt,
- # iterates through files and append the output to var out.
- query_command = command + [p]
- (rc, out_raw, err) = module.run_command(query_command)
- out.append(csv_to_list(out_raw))
- if query is not None:
- for q in query:
- # makes a command like hdbsql -i 01 -u SYSTEM -p secret123# "select user_name from users",
- # iterates through multiple commands and append the output to var out.
- query_command = command + [q]
- (rc, out_raw, err) = module.run_command(query_command)
- out.append(csv_to_list(out_raw))
- changed = True
-
- module.exit_json(changed=changed, rc=rc, query_result=out, stderr=err)
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/sap/plugins/modules/identity/sap_company.py b/ansible_collections/community/sap/plugins/modules/identity/sap_company.py
deleted file mode 100644
index 8d3838e5f..000000000
--- a/ansible_collections/community/sap/plugins/modules/identity/sap_company.py
+++ /dev/null
@@ -1,326 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# Copyright: (c) 2021, Rainer Leber <rainerleber@gmail.com> <rainer.leber@sva.de>
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-DOCUMENTATION = r'''
----
-module: sap_company
-
-short_description: This module will manage a company entities in a SAP S4HANA environment
-
-version_added: "1.0.0"
-
-description:
- - The M(community.sap.sap_user) module depends on C(pyrfc) Python library (version 2.4.0 and upwards).
- Depending on distribution you are using, you may need to install additional packages to
- have these available.
- - This module will use the company BAPIs C(BAPI_COMPANY_CLONE) and C(BAPI_COMPANY_DELETE) to manage company entities.
-
-options:
- state:
- description:
- - The decision what to do with the company.
- default: 'present'
- choices:
- - 'present'
- - 'absent'
- required: false
- type: str
- conn_username:
- description: The required username for the SAP system.
- required: true
- type: str
- conn_password:
- description: The required password for the SAP system.
- required: true
- type: str
- host:
- description: The required host for the SAP system. Can be either an FQDN or IP Address.
- required: true
- type: str
- sysnr:
- description:
- - The system number of the SAP system.
- - You must quote the value to ensure retaining the leading zeros.
- required: false
- default: '01'
- type: str
- client:
- description:
- - The client number to connect to.
- - You must quote the value to ensure retaining the leading zeros.
- required: false
- default: '000'
- type: str
- company_id:
- description: The company id.
- required: true
- type: str
- name:
- description: The company name.
- required: false
- type: str
- name_2:
- description: Additional company name.
- required: false
- type: str
- country:
- description: The country code for the company. For example, C('DE').
- required: false
- type: str
- time_zone:
- description: The timezone.
- required: false
- type: str
- city:
- description: The city where the company is located.
- required: false
- type: str
- post_code:
- description: The post code from the city.
- required: false
- type: str
- street:
- description: Street where the company is located.
- required: false
- type: str
- street_no:
- description: Street number.
- required: false
- type: str
- e_mail:
- description: General E-Mail address.
- required: false
- type: str
-
-requirements:
- - pyrfc >= 2.4.0
-
-author:
- - Rainer Leber (@rainerleber)
-
-notes:
- - Does not support C(check_mode).
-'''
-
-EXAMPLES = r'''
-- name: Create SAP Company
- community.sap.sap_company:
- conn_username: 'DDIC'
- conn_password: 'HECtna2021#'
- host: 100.0.201.20
- sysnr: '01'
- client: '000'
- state: present
- company_id: "Comp_ID"
- name: "Test_comp"
- name_2: "LTD"
- country: "DE"
- time_zone: "UTC"
- city: "City"
- post_code: "12345"
- street: "test_street"
- street_no: "1"
- e_mail: "test@test.de"
-
-# pass in a message and have changed true
-- name: Delete SAP Company
- community.sap.sap_company:
- conn_username: 'DDIC'
- conn_password: 'HECtna2021#'
- host: 100.0.201.20
- sysnr: '01'
- client: '000'
- state: absent
- company_id: "Comp_ID"
- name: "Test_comp"
- name_2: "LTD"
- country: "DE"
- time_zone: "UTC"
- city: "City"
- post_code: "12345"
- street: "test_street"
- street_no: "1"
- e_mail: "test@test.de"
-'''
-
-RETURN = r'''
-# These are examples of possible return values, and in general should use other names for return values.
-msg:
- description: A small execution description.
- type: str
- returned: always
- sample: 'Company address COMP_ID created'
-out:
- description: A complete description of the executed tasks. If this is available.
- type: list
- elements: dict
- returned: always
- sample: '{
- "RETURN": [
- {
- "FIELD": "",
- "ID": "01",
- "LOG_MSG_NO": "000000",
- "LOG_NO": "",
- "MESSAGE": "Company address COMP_ID created",
- "MESSAGE_V1": "COMP_ID",
- "MESSAGE_V2": "",
- "MESSAGE_V3": "",
- "MESSAGE_V4": "",
- "NUMBER": "078",
- "PARAMETER": "",
- "ROW": 0,
- "SYSTEM": "",
- "TYPE": "S"
- }
- ]
- }
- }'
-'''
-
-from ansible.module_utils.basic import AnsibleModule, missing_required_lib
-import traceback
-try:
- from pyrfc import Connection
-except ImportError:
- HAS_PYRFC_LIBRARY = False
- ANOTHER_LIBRARY_IMPORT_ERROR = traceback.format_exc()
-else:
- HAS_PYRFC_LIBRARY = True
-
-
-def call_rfc_method(connection, method_name, kwargs):
- # PyRFC call function
- return connection.call(method_name, **kwargs)
-
-
-def build_company_params(name, name_2, country, time_zone, city, post_code, street, street_no, e_mail):
- # Creates RFC parameters for creating organizations
- # define dicts in batch
- params = dict()
- # define company name
- params['NAME'] = name
- params['NAME_2'] = name_2
- # define location
- params['COUNTRY'] = country
- params['TIME_ZONE'] = time_zone
- params['CITY'] = city
- params['POSTL_COD1'] = post_code
- params['STREET'] = street
- params['STREET_NO'] = street_no
- # define communication
- params['E_MAIL'] = e_mail
- # return dict
- return params
-
-
-def return_analysis(raw):
- change = False
- failed = False
- msg = raw['RETURN'][0]['MESSAGE']
- for state in raw['RETURN']:
- if state['TYPE'] == "E":
- if state['NUMBER'] == '081':
- change = False
- else:
- failed = True
- if state['TYPE'] == "S":
- if state['NUMBER'] != '079':
- change = True
- else:
- msg = "No changes where made."
- return [{"change": change}, {"failed": failed}, {"msg": msg}]
-
-
-def run_module():
- module = AnsibleModule(
- argument_spec=dict(
- state=dict(default='present', choices=['absent', 'present']),
- conn_username=dict(type='str', required=True),
- conn_password=dict(type='str', required=True, no_log=True),
- host=dict(type='str', required=True),
- sysnr=dict(type='str', default="01"),
- client=dict(type='str', default="000"),
- company_id=dict(type='str', required=True),
- name=dict(type='str', required=False),
- name_2=dict(type='str', required=False),
- country=dict(type='str', required=False),
- time_zone=dict(type='str', required=False),
- city=dict(type='str', required=False),
- post_code=dict(type='str', required=False),
- street=dict(type='str', required=False),
- street_no=dict(type='str', required=False),
- e_mail=dict(type='str', required=False),
- ),
- supports_check_mode=False,
- )
- result = dict(changed=False, msg='', out={})
- raw = ""
-
- params = module.params
-
- state = params['state']
- conn_username = (params['conn_username']).upper()
- conn_password = params['conn_password']
- host = params['host']
- sysnr = params['sysnr']
- client = params['client']
-
- company_id = (params['company_id']).upper()
- name = params['name']
- name_2 = params['name_2']
- country = params['country']
- time_zone = params['time_zone']
- city = params['city']
- post_code = params['post_code']
- street = params['street']
- street_no = params['street_no']
- e_mail = params['e_mail']
-
- if not HAS_PYRFC_LIBRARY:
- module.fail_json(
- msg=missing_required_lib('pyrfc'),
- exception=ANOTHER_LIBRARY_IMPORT_ERROR)
-
- # basic RFC connection with pyrfc
- try:
- conn = Connection(user=conn_username, passwd=conn_password, ashost=host, sysnr=sysnr, client=client)
- except Exception as err:
- result['error'] = str(err)
- result['msg'] = 'Something went wrong connecting to the SAP system.'
- module.fail_json(**result)
-
- # build parameter dict of dict
- company_params = build_company_params(name, name_2, country, time_zone, city, post_code, street, street_no, e_mail)
-
- if state == "absent":
- raw = call_rfc_method(conn, 'BAPI_COMPANY_DELETE', {'COMPANY': company_id})
-
- if state == "present":
- raw = call_rfc_method(conn, 'BAPI_COMPANY_CLONE',
- {'METHOD': {'USMETHOD': 'COMPANY_CLONE'}, 'COMPANY': company_id, 'COMP_DATA': company_params})
-
- analysed = return_analysis(raw)
-
- result['out'] = raw
-
- result['changed'] = analysed[0]['change']
- result['msg'] = analysed[2]['msg']
-
- if analysed[1]['failed']:
- module.fail_json(**result)
-
- module.exit_json(**result)
-
-
-def main():
- run_module()
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/sap/plugins/modules/identity/sap_user.py b/ansible_collections/community/sap/plugins/modules/identity/sap_user.py
deleted file mode 100644
index f83472657..000000000
--- a/ansible_collections/community/sap/plugins/modules/identity/sap_user.py
+++ /dev/null
@@ -1,499 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# Copyright: (c) 2021, Rainer Leber <rainerleber@gmail.com> <rainer.leber@sva.de>
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-DOCUMENTATION = r'''
----
-module: sap_user
-short_description: This module will manage a user entities in a SAP S4/HANA environment
-version_added: "1.0.0"
-description:
- - The M(community.sap.sap_user) module depends on C(pyrfc) Python library (version 2.4.0 and upwards).
- Depending on distribution you are using, you may need to install additional packages to
- have these available.
- - This module will use the following user BAPIs to manage user entities.
- - C(BAPI_USER_GET_DETAIL)
- - C(BAPI_USER_DELETE)
- - C(BAPI_USER_CREATE1)
- - C(BAPI_USER_CHANGE)
- - C(BAPI_USER_ACTGROUPS_ASSIGN)
- - C(BAPI_USER_PROFILES_ASSIGN)
- - C(BAPI_USER_UNLOCK)
- - C(BAPI_USER_LOCK)
-options:
- state:
- description:
- - The decision what to do with the user.
- default: 'present'
- choices:
- - 'present'
- - 'absent'
- - 'lock'
- - 'unlock'
- required: false
- type: str
- force:
- description:
- - Must be C('True') if the password or type should be overwritten.
- default: False
- required: false
- type: bool
- conn_username:
- description: The required username for the SAP system.
- required: true
- type: str
- conn_password:
- description: The required password for the SAP system.
- required: true
- type: str
- host:
- description: The required host for the SAP system. Can be either an FQDN or IP Address.
- required: true
- type: str
- sysnr:
- description:
- - The system number of the SAP system.
- - You must quote the value to ensure retaining the leading zeros.
- default: '00'
- type: str
- client:
- description:
- - The client number to connect to.
- - You must quote the value to ensure retaining the leading zeros.
- default: '000'
- type: str
- username:
- description:
- - The username.
- type: str
- required: true
- firstname:
- description:
- - The Firstname of the user in the SAP system.
- type: str
- required: false
- lastname:
- description:
- - The lastname of the user in the SAP system.
- type: str
- required: false
- email:
- description:
- - The email address of the user in the SAP system.
- type: str
- required: false
- password:
- description:
- - The password for the user in the SAP system.
- type: str
- required: false
- useralias:
- description:
- - The alias for the user in the SAP system.
- type: str
- required: false
- user_type:
- description:
- - The type for the user in the SAP system.
- - C('A') Dialog user, C('B') System User, C('C') Communication User,
- C('S') Service User, C('L') Reference User.
- - Must be in uppercase.
- type: str
- required: false
- default: 'A'
- choices: ['A', 'B', 'C', 'S', 'L']
- company:
- description:
- - The specific company the user belongs to.
- - The company name must be available in the SAP system.
- type: str
- required: false
- profiles:
- description:
- - Assign profiles to the user.
- - Should be in uppercase, for example C('SAP_NEW') or C('SAP_ALL').
- type: list
- elements: str
- default: ['']
- required: false
- roles:
- description:
- - Assign roles to the user.
- type: list
- elements: str
- default: ['']
- required: false
-
-requirements:
- - pyrfc >= 2.4.0
-author:
- - Rainer Leber (@rainerleber)
-notes:
- - Does not support C(check_mode).
-'''
-
-EXAMPLES = r'''
-- name: Create SAP User
- community.sap.sap_user:
- conn_username: 'DDIC'
- conn_password: 'Test123'
- host: 192.168.1.150
- sysnr: '01'
- client: '000'
- state: present
- username: ADMIN
- firstname: first_admin
- lastname: last_admin
- email: admin@test.de
- password: Test123456
- useralias: ADMIN
- company: DEFAULT_COMPANY
- roles:
- - "SAP_ALL"
-
-- name: Force change SAP User
- community.sap.sap_user:
- conn_username: 'DDIC'
- conn_password: 'Test123'
- host: 192.168.1.150
- sysnr: '01'
- client: '000'
- state: present
- force: true
- username: ADMIN
- firstname: first_admin
- lastname: last_admin
- email: admin@test.de
- password: Test123456
- useralias: ADMIN
- company: DEFAULT_COMPANY
- roles:
- - "SAP_ALL"
-
-- name: Delete SAP User
- community.sap.sap_user:
- conn_username: 'DDIC'
- conn_password: 'Test123'
- host: 192.168.1.150
- sysnr: '01'
- client: '000'
- state: absent
- force: true
- username: ADMIN
-
-- name: Unlock SAP User
- community.sap.sap_user:
- conn_username: 'DDIC'
- conn_password: 'Test123'
- host: 192.168.1.150
- sysnr: '01'
- client: '000'
- state: unlock
- force: true
- username: ADMIN
-'''
-
-RETURN = r'''
-msg:
- description: A small execution description about the user action.
- type: str
- returned: always
- sample: 'User ADMIN created'
-out:
- description: A detailed description about the user action.
- type: list
- elements: dict
- returned: on success
- sample: [...,{
- "RETURN": [
- {
- "FIELD": "BNAME",
- "ID": "01",
- "LOG_MSG_NO": "000000",
- "LOG_NO": "",
- "MESSAGE": "User ADMIN created",
- "MESSAGE_V1": "ADMIN",
- "MESSAGE_V2": "",
- "MESSAGE_V3": "",
- "MESSAGE_V4": "",
- "NUMBER": "102",
- "PARAMETER": "",
- "ROW": 0,
- "SYSTEM": "",
- "TYPE": "S"
- }
- ],
- "SAPUSER_UUID_HIST": []}]
-'''
-from ansible.module_utils.basic import AnsibleModule, missing_required_lib
-import traceback
-import datetime
-try:
- from pyrfc import Connection
-except ImportError:
- HAS_PYRFC_LIBRARY = False
- PYRFC_LIBRARY_IMPORT_ERROR = traceback.format_exc()
-else:
- HAS_PYRFC_LIBRARY = True
-
-
-def add_to_dict(target_dict, target_key, value):
- # Adds the given value to a dict as the key
- # check if the given key is in the given dict yet
- if target_key in target_dict:
- return False
- target_dict[target_key] = value
- return True
-
-
-def call_rfc_method(connection, method_name, kwargs):
- # PyRFC call function
- return connection.call(method_name, **kwargs)
-
-
-def build_rfc_user_params(username, firstname, lastname, email, raw_password,
- useralias, user_type, raw_company, user_change, force):
- """Creates RFC parameters for Creating users"""
- # define dicts in batch
- params = dict()
- address = dict()
- password = dict()
- alias = dict()
- logondata = dict()
- company = dict()
- # for change parameters
- addressx = dict()
- passwordx = dict()
- logondatax = dict()
- companyx = dict()
- # define username
- add_to_dict(params, 'USERNAME', username)
- # define Address
- add_to_dict(address, 'FIRSTNAME', firstname)
- add_to_dict(address, 'LASTNAME', lastname)
- add_to_dict(address, 'E_MAIL', email)
- # define Password
- add_to_dict(password, 'BAPIPWD', raw_password)
- # define Alias
- add_to_dict(alias, 'USERALIAS', useralias)
- # define LogonData
- add_to_dict(logondata, 'GLTGV', datetime.date.today())
- add_to_dict(logondata, 'GLTGB', '20991231')
- add_to_dict(logondata, 'USTYP', user_type)
- # define company
- add_to_dict(company, 'COMPANY', raw_company)
- params['LOGONDATA'] = logondata
- params['ADDRESS'] = address
- params['COMPANY'] = company
- params['ALIAS'] = alias
- params['PASSWORD'] = password
- # add change if user exists
- if user_change and force:
- add_to_dict(addressx, 'FIRSTNAME', 'X')
- add_to_dict(addressx, 'LASTNAME', 'X')
- add_to_dict(addressx, 'E_MAIL', 'X')
- # define Password
- add_to_dict(passwordx, 'BAPIPWD', 'X')
- # define LogonData
- add_to_dict(logondatax, 'USTYP', 'X')
- # define company
- add_to_dict(companyx, 'COMPANY', 'X')
- params['LOGONDATAX'] = logondatax
- params['ADDRESSX'] = addressx
- params['COMPANYX'] = companyx
- params['PASSWORDX'] = passwordx
- return params
-
-
-def user_role_assignment_build_rfc_params(roles, username):
- rfc_table = []
-
- for role_name in roles:
- table_row = {'AGR_NAME': role_name}
-
- add_to_dict(table_row, 'FROM_DAT', datetime.date.today())
- add_to_dict(table_row, 'TO_DAT', '20991231')
-
- rfc_table.append(table_row)
-
- return {
- 'USERNAME': username,
- 'ACTIVITYGROUPS': rfc_table
- }
-
-
-def user_profile_assignment_build_rfc_params(profiles, username):
- rfc_table = []
-
- for profile_name in profiles:
- table_row = {'BAPIPROF': profile_name}
- rfc_table.append(table_row)
-
- return {
- 'USERNAME': username,
- 'PROFILES': rfc_table
- }
-
-
-def check_user(user_detail):
- if len(user_detail['RETURN']) > 0:
- for sub in user_detail['RETURN']:
- if sub['NUMBER'] == '124':
- return False
- return True
-
-
-def return_analysis(raw):
- change = False
- failed = False
- for state in raw['RETURN']:
- if state['TYPE'] == "E":
- if state['NUMBER'] == '224' or state['NUMBER'] == '124':
- change = False
- else:
- failed = True
- if state['TYPE'] == "S":
- if state['NUMBER'] != '029':
- change = True
- if state['TYPE'] == "W":
- if state['NUMBER'] == '049' or state['NUMBER'] == '047':
- change = True
- if state['NUMBER'] == '255':
- change = True
- return [{"change": change}, {"failed": failed}]
-
-
-def run_module():
- module = AnsibleModule(
- argument_spec=dict(
- # logical values
- state=dict(default='present', choices=[
- 'absent', 'present', 'lock', 'unlock']),
- force=dict(type='bool', default=False),
- # values for connection
- conn_username=dict(type='str', required=True),
- conn_password=dict(type='str', required=True, no_log=True),
- host=dict(type='str', required=True),
- sysnr=dict(type='str', default="00"),
- client=dict(type='str', default="000"),
- # values for the new or existing user
- username=dict(type='str', required=True),
- firstname=dict(type='str', required=False),
- lastname=dict(type='str', required=False),
- email=dict(type='str', required=False),
- password=dict(type='str', required=False, no_log=True),
- useralias=dict(type='str', required=False),
- user_type=dict(default="A",
- choices=['A', 'B', 'C', 'S', 'L']),
- company=dict(type='str', required=False),
- # values for profile must a list
- # Example ["SAP_NEW", "SAP_ALL"]
- profiles=dict(type='list', elements='str', default=[""]),
- # values for roles must a list
- roles=dict(type='list', elements='str', default=[""]),
- ),
- supports_check_mode=False,
- required_if=[('state', 'present', ['useralias', 'company'])]
- )
- result = dict(changed=False, msg='', out='')
- count = 0
- raw = ""
-
- params = module.params
-
- state = params['state']
- conn_username = (params['conn_username']).upper()
- conn_password = params['conn_password']
- host = params['host']
- sysnr = params['sysnr']
- client = params['client']
-
- username = (params['username']).upper()
- firstname = params['firstname']
- lastname = params['lastname']
- email = params['email']
- password = params['password']
- force = params['force']
- if not params['useralias'] is None:
- useralias = (params['useralias']).upper()
- user_type = (params['user_type']).upper()
- company = params['company']
-
- profiles = params['profiles']
- roles = params['roles']
-
- if not HAS_PYRFC_LIBRARY:
- module.fail_json(
- msg=missing_required_lib('pyrfc'),
- exception=PYRFC_LIBRARY_IMPORT_ERROR)
-
- # basic RFC connection with pyrfc
- try:
- conn = Connection(user=conn_username, passwd=conn_password, ashost=host, sysnr=sysnr, client=client)
- except Exception as err:
- result['error'] = str(err)
- result['msg'] = 'Something went wrong connecting to the SAP system.'
- module.fail_json(**result)
-
- # user details
- user_detail = call_rfc_method(conn, 'BAPI_USER_GET_DETAIL', {'USERNAME': username})
- user_exists = check_user(user_detail)
-
- if state == "absent":
- if user_exists:
- raw = call_rfc_method(conn, 'BAPI_USER_DELETE', {'USERNAME': username})
-
- if state == "present":
- user_params = build_rfc_user_params(username, firstname, lastname, email, password, useralias, user_type, company, user_exists, force)
- if not user_exists:
- raw = call_rfc_method(conn, 'BAPI_USER_CREATE1', user_params)
-
- if user_exists:
- # check for address changes when user exists
- user_no_changes = all((user_detail.get('ADDRESS')).get(k) == v for k, v in (user_params.get('ADDRESS')).items())
- if not user_no_changes or force:
- raw = call_rfc_method(conn, 'BAPI_USER_CHANGE', user_params)
-
- call_rfc_method(conn, 'BAPI_USER_ACTGROUPS_ASSIGN', user_role_assignment_build_rfc_params(roles, username))
-
- call_rfc_method(conn, 'BAPI_USER_PROFILES_ASSIGN', user_profile_assignment_build_rfc_params(profiles, username))
-
- if state == "unlock":
- if user_exists:
- raw = call_rfc_method(conn, 'BAPI_USER_UNLOCK', {'USERNAME': username})
-
- if state == "lock":
- if user_exists:
- raw = call_rfc_method(conn, 'BAPI_USER_LOCK', {'USERNAME': username})
-
- # analyse return value
- if raw != '':
- analysed = return_analysis(raw)
-
- result['out'] = raw
-
- result['changed'] = analysed[0]['change']
- for msgs in raw['RETURN']:
- if count > 0:
- result['msg'] = result['msg'] + '\n'
- result['msg'] = result['msg'] + msgs['MESSAGE']
- count = count + 1
-
- if analysed[1]['failed']:
- module.fail_json(**result)
- else:
- result['msg'] = "No changes where made."
-
- module.exit_json(**result)
-
-
-def main():
- run_module()
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/sap/plugins/modules/sap_company.py b/ansible_collections/community/sap/plugins/modules/sap_company.py
deleted file mode 100644
index 8d3838e5f..000000000
--- a/ansible_collections/community/sap/plugins/modules/sap_company.py
+++ /dev/null
@@ -1,326 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# Copyright: (c) 2021, Rainer Leber <rainerleber@gmail.com> <rainer.leber@sva.de>
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-DOCUMENTATION = r'''
----
-module: sap_company
-
-short_description: This module will manage a company entities in a SAP S4HANA environment
-
-version_added: "1.0.0"
-
-description:
- - The M(community.sap.sap_user) module depends on C(pyrfc) Python library (version 2.4.0 and upwards).
- Depending on distribution you are using, you may need to install additional packages to
- have these available.
- - This module will use the company BAPIs C(BAPI_COMPANY_CLONE) and C(BAPI_COMPANY_DELETE) to manage company entities.
-
-options:
- state:
- description:
- - The decision what to do with the company.
- default: 'present'
- choices:
- - 'present'
- - 'absent'
- required: false
- type: str
- conn_username:
- description: The required username for the SAP system.
- required: true
- type: str
- conn_password:
- description: The required password for the SAP system.
- required: true
- type: str
- host:
- description: The required host for the SAP system. Can be either an FQDN or IP Address.
- required: true
- type: str
- sysnr:
- description:
- - The system number of the SAP system.
- - You must quote the value to ensure retaining the leading zeros.
- required: false
- default: '01'
- type: str
- client:
- description:
- - The client number to connect to.
- - You must quote the value to ensure retaining the leading zeros.
- required: false
- default: '000'
- type: str
- company_id:
- description: The company id.
- required: true
- type: str
- name:
- description: The company name.
- required: false
- type: str
- name_2:
- description: Additional company name.
- required: false
- type: str
- country:
- description: The country code for the company. For example, C('DE').
- required: false
- type: str
- time_zone:
- description: The timezone.
- required: false
- type: str
- city:
- description: The city where the company is located.
- required: false
- type: str
- post_code:
- description: The post code from the city.
- required: false
- type: str
- street:
- description: Street where the company is located.
- required: false
- type: str
- street_no:
- description: Street number.
- required: false
- type: str
- e_mail:
- description: General E-Mail address.
- required: false
- type: str
-
-requirements:
- - pyrfc >= 2.4.0
-
-author:
- - Rainer Leber (@rainerleber)
-
-notes:
- - Does not support C(check_mode).
-'''
-
-EXAMPLES = r'''
-- name: Create SAP Company
- community.sap.sap_company:
- conn_username: 'DDIC'
- conn_password: 'HECtna2021#'
- host: 100.0.201.20
- sysnr: '01'
- client: '000'
- state: present
- company_id: "Comp_ID"
- name: "Test_comp"
- name_2: "LTD"
- country: "DE"
- time_zone: "UTC"
- city: "City"
- post_code: "12345"
- street: "test_street"
- street_no: "1"
- e_mail: "test@test.de"
-
-# pass in a message and have changed true
-- name: Delete SAP Company
- community.sap.sap_company:
- conn_username: 'DDIC'
- conn_password: 'HECtna2021#'
- host: 100.0.201.20
- sysnr: '01'
- client: '000'
- state: absent
- company_id: "Comp_ID"
- name: "Test_comp"
- name_2: "LTD"
- country: "DE"
- time_zone: "UTC"
- city: "City"
- post_code: "12345"
- street: "test_street"
- street_no: "1"
- e_mail: "test@test.de"
-'''
-
-RETURN = r'''
-# These are examples of possible return values, and in general should use other names for return values.
-msg:
- description: A small execution description.
- type: str
- returned: always
- sample: 'Company address COMP_ID created'
-out:
- description: A complete description of the executed tasks. If this is available.
- type: list
- elements: dict
- returned: always
- sample: '{
- "RETURN": [
- {
- "FIELD": "",
- "ID": "01",
- "LOG_MSG_NO": "000000",
- "LOG_NO": "",
- "MESSAGE": "Company address COMP_ID created",
- "MESSAGE_V1": "COMP_ID",
- "MESSAGE_V2": "",
- "MESSAGE_V3": "",
- "MESSAGE_V4": "",
- "NUMBER": "078",
- "PARAMETER": "",
- "ROW": 0,
- "SYSTEM": "",
- "TYPE": "S"
- }
- ]
- }
- }'
-'''
-
-from ansible.module_utils.basic import AnsibleModule, missing_required_lib
-import traceback
-try:
- from pyrfc import Connection
-except ImportError:
- HAS_PYRFC_LIBRARY = False
- ANOTHER_LIBRARY_IMPORT_ERROR = traceback.format_exc()
-else:
- HAS_PYRFC_LIBRARY = True
-
-
-def call_rfc_method(connection, method_name, kwargs):
- # PyRFC call function
- return connection.call(method_name, **kwargs)
-
-
-def build_company_params(name, name_2, country, time_zone, city, post_code, street, street_no, e_mail):
- # Creates RFC parameters for creating organizations
- # define dicts in batch
- params = dict()
- # define company name
- params['NAME'] = name
- params['NAME_2'] = name_2
- # define location
- params['COUNTRY'] = country
- params['TIME_ZONE'] = time_zone
- params['CITY'] = city
- params['POSTL_COD1'] = post_code
- params['STREET'] = street
- params['STREET_NO'] = street_no
- # define communication
- params['E_MAIL'] = e_mail
- # return dict
- return params
-
-
-def return_analysis(raw):
- change = False
- failed = False
- msg = raw['RETURN'][0]['MESSAGE']
- for state in raw['RETURN']:
- if state['TYPE'] == "E":
- if state['NUMBER'] == '081':
- change = False
- else:
- failed = True
- if state['TYPE'] == "S":
- if state['NUMBER'] != '079':
- change = True
- else:
- msg = "No changes where made."
- return [{"change": change}, {"failed": failed}, {"msg": msg}]
-
-
-def run_module():
- module = AnsibleModule(
- argument_spec=dict(
- state=dict(default='present', choices=['absent', 'present']),
- conn_username=dict(type='str', required=True),
- conn_password=dict(type='str', required=True, no_log=True),
- host=dict(type='str', required=True),
- sysnr=dict(type='str', default="01"),
- client=dict(type='str', default="000"),
- company_id=dict(type='str', required=True),
- name=dict(type='str', required=False),
- name_2=dict(type='str', required=False),
- country=dict(type='str', required=False),
- time_zone=dict(type='str', required=False),
- city=dict(type='str', required=False),
- post_code=dict(type='str', required=False),
- street=dict(type='str', required=False),
- street_no=dict(type='str', required=False),
- e_mail=dict(type='str', required=False),
- ),
- supports_check_mode=False,
- )
- result = dict(changed=False, msg='', out={})
- raw = ""
-
- params = module.params
-
- state = params['state']
- conn_username = (params['conn_username']).upper()
- conn_password = params['conn_password']
- host = params['host']
- sysnr = params['sysnr']
- client = params['client']
-
- company_id = (params['company_id']).upper()
- name = params['name']
- name_2 = params['name_2']
- country = params['country']
- time_zone = params['time_zone']
- city = params['city']
- post_code = params['post_code']
- street = params['street']
- street_no = params['street_no']
- e_mail = params['e_mail']
-
- if not HAS_PYRFC_LIBRARY:
- module.fail_json(
- msg=missing_required_lib('pyrfc'),
- exception=ANOTHER_LIBRARY_IMPORT_ERROR)
-
- # basic RFC connection with pyrfc
- try:
- conn = Connection(user=conn_username, passwd=conn_password, ashost=host, sysnr=sysnr, client=client)
- except Exception as err:
- result['error'] = str(err)
- result['msg'] = 'Something went wrong connecting to the SAP system.'
- module.fail_json(**result)
-
- # build parameter dict of dict
- company_params = build_company_params(name, name_2, country, time_zone, city, post_code, street, street_no, e_mail)
-
- if state == "absent":
- raw = call_rfc_method(conn, 'BAPI_COMPANY_DELETE', {'COMPANY': company_id})
-
- if state == "present":
- raw = call_rfc_method(conn, 'BAPI_COMPANY_CLONE',
- {'METHOD': {'USMETHOD': 'COMPANY_CLONE'}, 'COMPANY': company_id, 'COMP_DATA': company_params})
-
- analysed = return_analysis(raw)
-
- result['out'] = raw
-
- result['changed'] = analysed[0]['change']
- result['msg'] = analysed[2]['msg']
-
- if analysed[1]['failed']:
- module.fail_json(**result)
-
- module.exit_json(**result)
-
-
-def main():
- run_module()
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/sap/plugins/modules/sap_snote.py b/ansible_collections/community/sap/plugins/modules/sap_snote.py
deleted file mode 100644
index 24f393927..000000000
--- a/ansible_collections/community/sap/plugins/modules/sap_snote.py
+++ /dev/null
@@ -1,258 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# Copyright: (c) 2021, Rainer Leber <rainerleber@gmail.com> <rainer.leber@sva.de>
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-DOCUMENTATION = r'''
----
-module: sap_snote
-
-short_description: This module will upload and (de)implements C(SNOTES) in a SAP S4HANA environment.
-
-version_added: "1.0.0"
-
-description:
- - The C(sap_snote) module depends on C(pyrfc) Python library (version 2.4.0 and upwards).
- Depending on distribution you are using, you may need to install additional packages to
- have these available.
- - This module will use the Function Group C(SCWB_API).
- - The C(TMS) must be configured at first.
- - Integrating SNOTES cannot be done via C(DDIC)- or C(SAP*)-User.
-options:
- state:
- description:
- - The decision what to do with the SNOTE.
- - Could be C('present'), C('absent')
- default: 'present'
- choices:
- - 'present'
- - 'absent'
- required: false
- type: str
- conn_username:
- description: The required username for the SAP system.
- required: true
- type: str
- conn_password:
- description: The required password for the SAP system.
- required: true
- type: str
- host:
- description: The required host for the SAP system. Can be either an FQDN or IP Address.
- required: true
- type: str
- sysnr:
- description:
- - The system number of the SAP system.
- - You must quote the value to ensure retaining the leading zeros.
- required: false
- default: '01'
- type: str
- client:
- description:
- - The client number to connect to.
- - You must quote the value to ensure retaining the leading zeros.
- required: false
- default: '000'
- type: str
- snote_path:
- description:
- - The path to the extracted SNOTE txt file.
- - The File could be extracted from SAR package.
- - If C(snote_path) is not provided, the C(snote) parameter must be defined.
- - The SNOTE txt file must be at a place where the SAP System is authorized for. For example C(/usr/sap/trans/files).
- required: false
- type: str
- snote:
- description:
- - With the C(snote) paramter only implementation and deimplementation will work.
- - Upload SNOTES to the System is only available if C(snote_path) is provided.
- required: false
- type: str
-
-requirements:
- - pyrfc >= 2.4.0
-
-author:
- - Rainer Leber (@rainerleber)
-'''
-
-EXAMPLES = r'''
-- name: test snote module
- hosts: localhost
- tasks:
- - name: implement SNOTE
- community.sap.sap_snote:
- conn_username: 'DDIC'
- conn_password: 'Passwd1234'
- host: 192.168.1.100
- sysnr: '01'
- client: '000'
- state: present
- snote_path: /usr/sap/trans/tmp/0002949148.txt
-
-- name: test snote module without path
- hosts: localhost
- tasks:
- - name: deimplement SNOTE
- community.sap.sap_snote:
- conn_username: 'DDIC'
- conn_password: 'Passwd1234'
- host: 192.168.1.100
- sysnr: '01'
- client: '000'
- state: absent
- snote: 0002949148
-
-'''
-
-RETURN = r'''
-msg:
- description: A small execution description.
- type: str
- returned: always
- sample: 'SNOTE 000298026 implemented.'
-out:
- description: A complete description of the SNOTE implementation. If this is available.
- type: list
- elements: dict
- returned: always
- sample: '{
- "RETURN": [{"ES_MSG": { "MSGNO": "000", "MSGTY": "", "MSGTXT": "", "MSGV1": "" },
- "ET_MSG": [],
- "EV_RC": 0,
- "ET_MISSING_NOTES": [],
- "IT_FILENAME": [{"FILENAME": "/usr/sap/trans/tmp/0002980265.txt"}],
- "IT_NOTES": [{"NUMM": "0002980265", "VERSNO": "0000"}]
- }]}'
-'''
-
-from ansible.module_utils.basic import AnsibleModule, missing_required_lib
-from os import path as os_path
-import traceback
-try:
- from pyrfc import Connection
-except ImportError:
- HAS_PYRFC_LIBRARY = False
- ANOTHER_LIBRARY_IMPORT_ERROR = traceback.format_exc()
-else:
- HAS_PYRFC_LIBRARY = True
-
-
-def call_rfc_method(connection, method_name, kwargs):
- # PyRFC call function
- return connection.call(method_name, **kwargs)
-
-
-def check_implementation(conn, snote):
- check_implemented = call_rfc_method(conn, 'SCWB_API_GET_NOTES_IMPLEMENTED', {})
- for snote_list in check_implemented['ET_NOTES_IMPL']:
- if snote in snote_list['NUMM']:
- return True
- return False
-
-
-def run_module():
- module = AnsibleModule(
- argument_spec=dict(
- state=dict(default='present', choices=['absent', 'present']),
- conn_username=dict(type='str', required=True),
- conn_password=dict(type='str', required=True, no_log=True),
- host=dict(type='str', required=True),
- sysnr=dict(type='str', default="01"),
- client=dict(type='str', default="000"),
- snote_path=dict(type='str', required=False),
- snote=dict(type='str', required=False),
- ),
- required_one_of=[('snote_path', 'snote')],
- supports_check_mode=False,
- )
- result = dict(changed=False, msg='', out={}, error='')
- raw = ""
- post_check = False
-
- params = module.params
-
- state = params['state']
- conn_username = (params['conn_username']).upper()
- conn_password = params['conn_password']
- host = params['host']
- sysnr = (params['sysnr']).zfill(2)
- client = params['client']
-
- path = params['snote_path']
- snote = params['snote']
-
- if not HAS_PYRFC_LIBRARY:
- module.fail_json(
- msg=missing_required_lib('pyrfc'),
- exception=ANOTHER_LIBRARY_IMPORT_ERROR)
-
- if conn_username == "DDIC" or conn_username == "SAP*":
- result['msg'] = 'User C(DDIC) or C(SAP*) not allowed for this operation.'
- module.fail_json(**result)
-
- # basic RFC connection with pyrfc
- try:
- conn = Connection(user=conn_username, passwd=conn_password, ashost=host, sysnr=sysnr, client=client)
- except Exception as err:
- result['error'] = str(err)
- result['msg'] = 'Something went wrong connecting to the SAP system.'
- module.fail_json(**result)
-
- # pre evaluation of parameters
- if path is not None:
- if path.endswith('.txt'):
- # splits snote number from path and txt extension
- snote = os_path.basename(os_path.normpath(path)).split('.')[0]
- else:
- result['msg'] = 'The path must include the extracted snote file and ends with txt.'
- module.fail_json(**result)
-
- pre_check = check_implementation(conn, snote)
-
- if state == "absent" and pre_check:
- raw = call_rfc_method(conn, 'SCWB_API_NOTES_DEIMPLEMENT', {'IT_NOTES': [snote]})
-
- if state == "present" and not pre_check:
- if path:
- raw_upload = call_rfc_method(conn, 'SCWB_API_UPLOAD_NOTES', {'IT_FILENAME': [path], 'IT_NOTES': [snote]})
- if raw_upload['EV_RC'] != 0:
- result['out'] = raw_upload
- result['msg'] = raw_upload['ES_MSG']['MSGTXT']
- module.fail_json(**result)
-
- raw = call_rfc_method(conn, 'SCWB_API_NOTES_IMPLEMENT', {'IT_NOTES': [snote]})
- queued = call_rfc_method(conn, 'SCWB_API_CINST_QUEUE_GET', {})
-
- if queued['ET_MANUAL_ACTIVITIES']:
- raw = call_rfc_method(conn, 'SCWB_API_CONFIRM_MAN_ACTIVITY', {})
-
- if raw:
- if raw['EV_RC'] == 0:
- post_check = check_implementation(conn, snote)
- if post_check and state == "present":
- result['changed'] = True
- result['msg'] = 'SNOTE "{0}" implemented.'.format(snote)
- if not post_check and state == "absent":
- result['changed'] = True
- result['msg'] = 'SNOTE "{0}" deimplemented.'.format(snote)
- else:
- result['msg'] = "Something went wrong."
- module.fail_json(**result)
- result['out'] = raw
- else:
- result['msg'] = "Nothing to do."
-
- module.exit_json(**result)
-
-
-def main():
- run_module()
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/sap/plugins/modules/sap_system_facts.py b/ansible_collections/community/sap/plugins/modules/sap_system_facts.py
deleted file mode 100644
index b5f4eb9b6..000000000
--- a/ansible_collections/community/sap/plugins/modules/sap_system_facts.py
+++ /dev/null
@@ -1,206 +0,0 @@
-#!/usr/bin/python
-
-# Copyright: (c) 2022, Rainer Leber rainerleber@gmail.com>
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-DOCUMENTATION = r'''
----
-module: sap_system_facts
-
-short_description: Gathers SAP facts in a host
-
-version_added: "1.0.0"
-
-description:
- - This facts module gathers SAP system facts about the running instance.
-
-author:
- - Rainer Leber (@rainerleber)
-
-notes:
- - Supports C(check_mode).
-'''
-
-EXAMPLES = r'''
-- name: Return SAP system ansible_facts
- community.sap.sap_system_fact:
-'''
-
-RETURN = r'''
-# These are examples of possible return values,
-# and in general should use other names for return values.
-ansible_facts:
- description: Facts to add to ansible_facts.
- returned: always
- type: list
- elements: dict
- contains:
- sap:
- description: Facts about the running SAP system.
- type: list
- elements: dict
- returned: When SAP system fact is present
- sample: [
- {
- "InstanceType": "NW",
- "NR": "00",
- "SID": "ABC",
- "TYPE": "ASCS"
- },
- {
- "InstanceType": "NW",
- "NR": "01",
- "SID": "ABC",
- "TYPE": "PAS"
- },
- {
- "InstanceType": "HANA",
- "NR": "02",
- "SID": "HDB",
- "TYPE": "HDB"
- },
- {
- "InstanceType": "NW",
- "NR": "80",
- "SID": "WEB",
- "TYPE": "WebDisp"
- }
- ]
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-import os
-import re
-
-
-def get_all_hana_sid():
- hana_sid = list()
- if os.path.isdir("/hana/shared"):
- # /hana/shared directory exists
- for sid in os.listdir('/hana/shared'):
- if os.path.isdir("/usr/sap/" + sid):
- hana_sid = hana_sid + [sid]
- if hana_sid:
- return hana_sid
-
-
-def get_all_nw_sid():
- nw_sid = list()
- if os.path.isdir("/sapmnt"):
- # /sapmnt directory exists
- for sid in os.listdir('/sapmnt'):
- if os.path.isdir("/usr/sap/" + sid):
- nw_sid = nw_sid + [sid]
- else:
- # Check to see if /sapmnt/SID/sap_bobj exists
- if os.path.isdir("/sapmnt/" + sid + "/sap_bobj"):
- # is a bobj system
- nw_sid = nw_sid + [sid]
- if nw_sid:
- return nw_sid
-
-
-def get_hana_nr(sids, module):
- hana_list = list()
- for sid in sids:
- for instance in os.listdir('/usr/sap/' + sid):
- if 'HDB' in instance:
- instance_nr = instance[-2:]
- # check if instance number exists
- command = [module.get_bin_path('/usr/sap/hostctrl/exe/sapcontrol', required=True)]
- command.extend(['-nr', instance_nr, '-function', 'GetProcessList'])
- check_instance = module.run_command(command, check_rc=False)
- # sapcontrol returns c(0 - 5) exit codes only c(1) is unavailable
- if check_instance[0] != 1:
- hana_list.append({'NR': instance_nr, 'SID': sid, 'TYPE': 'HDB', 'InstanceType': 'HANA'})
- return hana_list
-
-
-def get_nw_nr(sids, module):
- nw_list = list()
- type = ""
- for sid in sids:
- for instance in os.listdir('/usr/sap/' + sid):
- instance_nr = instance[-2:]
- command = [module.get_bin_path('/usr/sap/hostctrl/exe/sapcontrol', required=True)]
- # check if returned instance_nr is a number because sapcontrol returns all if a random string is provided
- if instance_nr.isdigit():
- command.extend(['-nr', instance_nr, '-function', 'GetInstanceProperties'])
- check_instance = module.run_command(command, check_rc=False)
- if check_instance[0] != 1:
- for line in check_instance[1].splitlines():
- if re.search('INSTANCE_NAME', line):
- # convert to list and extract last
- type_raw = (line.strip('][').split(', '))[-1]
- # split instance number
- type = type_raw[:-2]
- nw_list.append({'NR': instance_nr, 'SID': sid, 'TYPE': get_instance_type(type), 'InstanceType': 'NW'})
- return nw_list
-
-
-def get_instance_type(raw_type):
- if raw_type[0] == "D":
- # It's a PAS
- type = "PAS"
- elif raw_type[0] == "A":
- # It's an ASCS
- type = "ASCS"
- elif raw_type[0] == "W":
- # It's a Webdisp
- type = "WebDisp"
- elif raw_type[0] == "J":
- # It's a Java
- type = "Java"
- elif raw_type[0] == "S":
- # It's an SCS
- type = "SCS"
- elif raw_type[0] == "E":
- # It's an ERS
- type = "ERS"
- else:
- # Unknown instance type
- type = "XXX"
- return type
-
-
-def run_module():
- module_args = dict()
- system_result = list()
-
- result = dict(
- changed=False,
- ansible_facts=dict(),
- )
-
- module = AnsibleModule(
- argument_spec=module_args,
- supports_check_mode=True,
- )
-
- hana_sid = get_all_hana_sid()
- if hana_sid:
- system_result = system_result + get_hana_nr(hana_sid, module)
-
- nw_sid = get_all_nw_sid()
- if nw_sid:
- system_result = system_result + get_nw_nr(nw_sid, module)
-
- if system_result:
- result['ansible_facts'] = {'sap': system_result}
- else:
- result['ansible_facts']
-
- if module.check_mode:
- module.exit_json(**result)
-
- module.exit_json(**result)
-
-
-def main():
- run_module()
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/sap/plugins/modules/sap_task_list_execute.py b/ansible_collections/community/sap/plugins/modules/sap_task_list_execute.py
deleted file mode 100644
index 0ae25903f..000000000
--- a/ansible_collections/community/sap/plugins/modules/sap_task_list_execute.py
+++ /dev/null
@@ -1,340 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# Copyright: (c) 2021, Rainer Leber <rainerleber@gmail.com>
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-DOCUMENTATION = r'''
----
-module: sap_task_list_execute
-short_description: Perform SAP Task list execution
-version_added: "0.1.0"
-description:
- - The M(community.sap.sap_task_list_execute) module depends on C(pyrfc) Python library (version 2.4.0 and upwards).
- Depending on distribution you are using, you may need to install additional packages to
- have these available.
- - Tasks in the task list which requires manual activities will be confirmed automatically.
- - This module will use the RFC package C(STC_TM_API).
-
-requirements:
- - pyrfc >= 2.4.0
- - xmltodict
-
-options:
- conn_username:
- description: The required username for the SAP system.
- required: true
- type: str
- conn_password:
- description: The required password for the SAP system.
- required: true
- type: str
- host:
- description: The required host for the SAP system. Can be either an FQDN or IP Address.
- required: true
- type: str
- sysnr:
- description:
- - The system number of the SAP system.
- - You must quote the value to ensure retaining the leading zeros.
- default: '00'
- type: str
- client:
- description:
- - The client number to connect to.
- - You must quote the value to ensure retaining the leading zeros.
- default: '000'
- type: str
- task_to_execute:
- description: The task list which will be executed.
- required: true
- type: str
- task_parameters:
- description:
- - The tasks and the parameters for execution.
- - If the task list does not need any parameters, this could be empty.
- - If only specific tasks from the task list should be executed,
- the tasks even when no parameter is needed must be provided
- alongside with the module parameter I(task_skip=true).
- type: list
- elements: dict
- suboptions:
- TASKNAME:
- description: The name of the task in the task list.
- type: str
- required: true
- FIELDNAME:
- description: The name of the field of the task.
- type: str
- VALUE:
- description: The value which have to be set.
- type: raw
- task_settings:
- description:
- - Setting for the execution of the task list. This can be the following as in TCODE SE80 described.
- Check Mode C(CHECKRUN), Background Processing Active C(BATCH) (this is the default value),
- Asynchronous Execution C(ASYNC), Trace Mode C(TRACE), Server Name C(BATCH_TARGET).
- default: ['BATCH']
- type: list
- elements: str
- task_skip:
- description:
- - If this parameter is C(true), not defined tasks in I(task_parameters) are skipped.
- - This could be the case when only certain tasks should run from the task list.
- default: false
- type: bool
-
-notes:
- - Does not support C(check_mode). Always returns that the state has changed.
-author:
- - Rainer Leber (@rainerleber)
-'''
-
-EXAMPLES = r'''
-# Pass in a message
-- name: Test task execution
- community.sap.sap_task_list_execute:
- conn_username: DDIC
- conn_password: Passwd1234
- host: 10.1.8.10
- sysnr: '01'
- client: '000'
- task_to_execute: SAP_BASIS_SSL_CHECK
- task_settings: batch
-
-- name: Pass in input parameters
- community.sap.sap_task_list_execute:
- conn_username: DDIC
- conn_password: Passwd1234
- host: 10.1.8.10
- sysnr: '00'
- client: '000'
- task_to_execute: SAP_BASIS_SSL_CHECK
- task_parameters :
- - { 'TASKNAME': 'CL_STCT_CHECK_SEC_CRYPTO', 'FIELDNAME': 'P_OPT2', 'VALUE': 'X' }
- - TASKNAME: CL_STCT_CHECK_SEC_CRYPTO
- FIELDNAME: P_OPT3
- VALUE: X
- task_settings: batch
-
-# Exported environment variables
-- name: Hint if module will fail with error message like ImportError libsapnwrfc.so...
- community.sap.sap_task_list_execute:
- conn_username: DDIC
- conn_password: Passwd1234
- host: 10.1.8.10
- sysnr: '00'
- client: '000'
- task_to_execute: SAP_BASIS_SSL_CHECK
- task_settings: batch
- environment:
- SAPNWRFC_HOME: /usr/local/sap/nwrfcsdk
- LD_LIBRARY_PATH: /usr/local/sap/nwrfcsdk/lib
-'''
-
-RETURN = r'''
-msg:
- description: A small execution description.
- type: str
- returned: always
- sample: 'Successful'
-out:
- description: A complete description of the executed tasks. If this is available.
- type: list
- elements: dict
- returned: on success
- sample: [...,{
- "LOG": {
- "STCTM_S_LOG": [
- {
- "ACTIVITY": "U_CONFIG",
- "ACTIVITY_DESCR": "Configuration changed",
- "DETAILS": null,
- "EXEC_ID": "20210728184903.815739",
- "FIELD": null,
- "ID": "STC_TASK",
- "LOG_MSG_NO": "000000",
- "LOG_NO": null,
- "MESSAGE": "For radiobutton group ICM too many options are set; choose only one option",
- "MESSAGE_V1": "ICM",
- "MESSAGE_V2": null,
- "MESSAGE_V3": null,
- "MESSAGE_V4": null,
- "NUMBER": "048",
- "PARAMETER": null,
- "PERIOD": "M",
- "PERIOD_DESCR": "Maintenance",
- "ROW": "0",
- "SRC_LINE": "170",
- "SRC_OBJECT": "CL_STCTM_REPORT_UI IF_STCTM_UI_TASK~SET_PARAMETERS",
- "SYSTEM": null,
- "TIMESTMP": "20210728184903",
- "TSTPNM": "DDIC",
- "TYPE": "E"
- },...
- ]}}]
-'''
-
-from ansible.module_utils.basic import AnsibleModule, missing_required_lib
-import traceback
-try:
- from pyrfc import Connection
-except ImportError:
- HAS_PYRFC_LIBRARY = False
- PYRFC_LIBRARY_IMPORT_ERROR = traceback.format_exc()
-else:
- HAS_PYRFC_LIBRARY = True
-try:
- import xmltodict
-except ImportError:
- HAS_XMLTODICT_LIBRARY = False
- XMLTODICT_LIBRARY_IMPORT_ERROR = traceback.format_exc()
-else:
- HAS_XMLTODICT_LIBRARY = True
-
-
-def call_rfc_method(connection, method_name, kwargs):
- # PyRFC call function
- return connection.call(method_name, **kwargs)
-
-
-def process_exec_settings(task_settings):
- # processes task settings to objects
- exec_settings = {}
- for settings in task_settings:
- temp_dict = {settings.upper(): 'X'}
- for key, value in temp_dict.items():
- exec_settings[key] = value
- return exec_settings
-
-
-def xml_to_dict(xml_raw):
- try:
- xml_parsed = xmltodict.parse(xml_raw, dict_constructor=dict)
- xml_dict = xml_parsed['asx:abap']['asx:values']['SESSION']['TASKLIST']
- except KeyError:
- xml_dict = "No logs available."
- return xml_dict
-
-
-def run_module():
-
- params_spec = dict(
- TASKNAME=dict(type='str', required=True),
- FIELDNAME=dict(type='str'),
- VALUE=dict(type='raw'),
- )
-
- # define available arguments/parameters a user can pass to the module
- module = AnsibleModule(
- argument_spec=dict(
- # values for connection
- conn_username=dict(type='str', required=True),
- conn_password=dict(type='str', required=True, no_log=True),
- host=dict(type='str', required=True),
- sysnr=dict(type='str', default="00"),
- client=dict(type='str', default="000"),
- # values for execution tasks
- task_to_execute=dict(type='str', required=True),
- task_parameters=dict(type='list', elements='dict', options=params_spec),
- task_settings=dict(type='list', elements='str', default=['BATCH']),
- task_skip=dict(type='bool', default=False),
- ),
- supports_check_mode=False,
- )
- result = dict(changed=False, msg='', out={})
-
- params = module.params
-
- username = params['conn_username'].upper()
- password = params['conn_password']
- host = params['host']
- sysnr = params['sysnr']
- client = params['client']
-
- task_parameters = params['task_parameters']
- task_to_execute = params['task_to_execute']
- task_settings = params['task_settings']
- task_skip = params['task_skip']
-
- if not HAS_PYRFC_LIBRARY:
- module.fail_json(
- msg=missing_required_lib('pyrfc'),
- exception=PYRFC_LIBRARY_IMPORT_ERROR)
-
- if not HAS_XMLTODICT_LIBRARY:
- module.fail_json(
- msg=missing_required_lib('xmltodict'),
- exception=XMLTODICT_LIBRARY_IMPORT_ERROR)
-
- # basic RFC connection with pyrfc
- try:
- conn = Connection(user=username, passwd=password, ashost=host, sysnr=sysnr, client=client)
- except Exception as err:
- result['error'] = str(err)
- result['msg'] = 'Something went wrong connecting to the SAP system.'
- module.fail_json(**result)
-
- try:
- raw_params = call_rfc_method(conn, 'STC_TM_SCENARIO_GET_PARAMETERS',
- {'I_SCENARIO_ID': task_to_execute})
- except Exception as err:
- result['error'] = str(err)
- result['msg'] = 'The task list does not exist.'
- module.fail_json(**result)
- exec_settings = process_exec_settings(task_settings)
- # initialize session task
- session_init = call_rfc_method(conn, 'STC_TM_SESSION_BEGIN',
- {'I_SCENARIO_ID': task_to_execute,
- 'I_INIT_ONLY': 'X'})
- # Confirm Tasks which requires manual activities from Task List Run
- for task in raw_params['ET_PARAMETER']:
- call_rfc_method(conn, 'STC_TM_TASK_CONFIRM',
- {'I_SESSION_ID': session_init['E_SESSION_ID'],
- 'I_TASKNAME': task['TASKNAME']})
- if task_skip:
- for task in raw_params['ET_PARAMETER']:
- call_rfc_method(conn, 'STC_TM_TASK_SKIP',
- {'I_SESSION_ID': session_init['E_SESSION_ID'],
- 'I_TASKNAME': task['TASKNAME'], 'I_SKIP_DEP_TASKS': 'X'})
- # unskip defined tasks and set parameters
- if task_parameters is not None:
- for task in task_parameters:
- call_rfc_method(conn, 'STC_TM_TASK_UNSKIP',
- {'I_SESSION_ID': session_init['E_SESSION_ID'],
- 'I_TASKNAME': task['TASKNAME'], 'I_UNSKIP_DEP_TASKS': 'X'})
-
- call_rfc_method(conn, 'STC_TM_SESSION_SET_PARAMETERS',
- {'I_SESSION_ID': session_init['E_SESSION_ID'],
- 'IT_PARAMETER': task_parameters})
- # start the task
- try:
- session_start = call_rfc_method(conn, 'STC_TM_SESSION_RESUME',
- {'I_SESSION_ID': session_init['E_SESSION_ID'],
- 'IS_EXEC_SETTINGS': exec_settings})
- except Exception as err:
- result['error'] = str(err)
- result['msg'] = 'Something went wrong. See error.'
- module.fail_json(**result)
- # get task logs because the execution may successfully but the tasks shows errors or warnings
- # returned value is ABAPXML https://help.sap.com/doc/abapdocu_755_index_htm/7.55/en-US/abenabap_xslt_asxml_general.htm
- session_log = call_rfc_method(conn, 'STC_TM_SESSION_GET_LOG',
- {'I_SESSION_ID': session_init['E_SESSION_ID']})
-
- task_list = xml_to_dict(session_log['E_LOG'])
-
- result['changed'] = True
- result['msg'] = session_start['E_STATUS_DESCR']
- result['out'] = task_list
-
- module.exit_json(**result)
-
-
-def main():
- run_module()
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/sap/plugins/modules/sap_user.py b/ansible_collections/community/sap/plugins/modules/sap_user.py
deleted file mode 100644
index f83472657..000000000
--- a/ansible_collections/community/sap/plugins/modules/sap_user.py
+++ /dev/null
@@ -1,499 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# Copyright: (c) 2021, Rainer Leber <rainerleber@gmail.com> <rainer.leber@sva.de>
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-DOCUMENTATION = r'''
----
-module: sap_user
-short_description: This module will manage a user entities in a SAP S4/HANA environment
-version_added: "1.0.0"
-description:
- - The M(community.sap.sap_user) module depends on C(pyrfc) Python library (version 2.4.0 and upwards).
- Depending on distribution you are using, you may need to install additional packages to
- have these available.
- - This module will use the following user BAPIs to manage user entities.
- - C(BAPI_USER_GET_DETAIL)
- - C(BAPI_USER_DELETE)
- - C(BAPI_USER_CREATE1)
- - C(BAPI_USER_CHANGE)
- - C(BAPI_USER_ACTGROUPS_ASSIGN)
- - C(BAPI_USER_PROFILES_ASSIGN)
- - C(BAPI_USER_UNLOCK)
- - C(BAPI_USER_LOCK)
-options:
- state:
- description:
- - The decision what to do with the user.
- default: 'present'
- choices:
- - 'present'
- - 'absent'
- - 'lock'
- - 'unlock'
- required: false
- type: str
- force:
- description:
- - Must be C('True') if the password or type should be overwritten.
- default: False
- required: false
- type: bool
- conn_username:
- description: The required username for the SAP system.
- required: true
- type: str
- conn_password:
- description: The required password for the SAP system.
- required: true
- type: str
- host:
- description: The required host for the SAP system. Can be either an FQDN or IP Address.
- required: true
- type: str
- sysnr:
- description:
- - The system number of the SAP system.
- - You must quote the value to ensure retaining the leading zeros.
- default: '00'
- type: str
- client:
- description:
- - The client number to connect to.
- - You must quote the value to ensure retaining the leading zeros.
- default: '000'
- type: str
- username:
- description:
- - The username.
- type: str
- required: true
- firstname:
- description:
- - The Firstname of the user in the SAP system.
- type: str
- required: false
- lastname:
- description:
- - The lastname of the user in the SAP system.
- type: str
- required: false
- email:
- description:
- - The email address of the user in the SAP system.
- type: str
- required: false
- password:
- description:
- - The password for the user in the SAP system.
- type: str
- required: false
- useralias:
- description:
- - The alias for the user in the SAP system.
- type: str
- required: false
- user_type:
- description:
- - The type for the user in the SAP system.
- - C('A') Dialog user, C('B') System User, C('C') Communication User,
- C('S') Service User, C('L') Reference User.
- - Must be in uppercase.
- type: str
- required: false
- default: 'A'
- choices: ['A', 'B', 'C', 'S', 'L']
- company:
- description:
- - The specific company the user belongs to.
- - The company name must be available in the SAP system.
- type: str
- required: false
- profiles:
- description:
- - Assign profiles to the user.
- - Should be in uppercase, for example C('SAP_NEW') or C('SAP_ALL').
- type: list
- elements: str
- default: ['']
- required: false
- roles:
- description:
- - Assign roles to the user.
- type: list
- elements: str
- default: ['']
- required: false
-
-requirements:
- - pyrfc >= 2.4.0
-author:
- - Rainer Leber (@rainerleber)
-notes:
- - Does not support C(check_mode).
-'''
-
-EXAMPLES = r'''
-- name: Create SAP User
- community.sap.sap_user:
- conn_username: 'DDIC'
- conn_password: 'Test123'
- host: 192.168.1.150
- sysnr: '01'
- client: '000'
- state: present
- username: ADMIN
- firstname: first_admin
- lastname: last_admin
- email: admin@test.de
- password: Test123456
- useralias: ADMIN
- company: DEFAULT_COMPANY
- roles:
- - "SAP_ALL"
-
-- name: Force change SAP User
- community.sap.sap_user:
- conn_username: 'DDIC'
- conn_password: 'Test123'
- host: 192.168.1.150
- sysnr: '01'
- client: '000'
- state: present
- force: true
- username: ADMIN
- firstname: first_admin
- lastname: last_admin
- email: admin@test.de
- password: Test123456
- useralias: ADMIN
- company: DEFAULT_COMPANY
- roles:
- - "SAP_ALL"
-
-- name: Delete SAP User
- community.sap.sap_user:
- conn_username: 'DDIC'
- conn_password: 'Test123'
- host: 192.168.1.150
- sysnr: '01'
- client: '000'
- state: absent
- force: true
- username: ADMIN
-
-- name: Unlock SAP User
- community.sap.sap_user:
- conn_username: 'DDIC'
- conn_password: 'Test123'
- host: 192.168.1.150
- sysnr: '01'
- client: '000'
- state: unlock
- force: true
- username: ADMIN
-'''
-
-RETURN = r'''
-msg:
- description: A small execution description about the user action.
- type: str
- returned: always
- sample: 'User ADMIN created'
-out:
- description: A detailed description about the user action.
- type: list
- elements: dict
- returned: on success
- sample: [...,{
- "RETURN": [
- {
- "FIELD": "BNAME",
- "ID": "01",
- "LOG_MSG_NO": "000000",
- "LOG_NO": "",
- "MESSAGE": "User ADMIN created",
- "MESSAGE_V1": "ADMIN",
- "MESSAGE_V2": "",
- "MESSAGE_V3": "",
- "MESSAGE_V4": "",
- "NUMBER": "102",
- "PARAMETER": "",
- "ROW": 0,
- "SYSTEM": "",
- "TYPE": "S"
- }
- ],
- "SAPUSER_UUID_HIST": []}]
-'''
-from ansible.module_utils.basic import AnsibleModule, missing_required_lib
-import traceback
-import datetime
-try:
- from pyrfc import Connection
-except ImportError:
- HAS_PYRFC_LIBRARY = False
- PYRFC_LIBRARY_IMPORT_ERROR = traceback.format_exc()
-else:
- HAS_PYRFC_LIBRARY = True
-
-
-def add_to_dict(target_dict, target_key, value):
- # Adds the given value to a dict as the key
- # check if the given key is in the given dict yet
- if target_key in target_dict:
- return False
- target_dict[target_key] = value
- return True
-
-
-def call_rfc_method(connection, method_name, kwargs):
- # PyRFC call function
- return connection.call(method_name, **kwargs)
-
-
-def build_rfc_user_params(username, firstname, lastname, email, raw_password,
- useralias, user_type, raw_company, user_change, force):
- """Creates RFC parameters for Creating users"""
- # define dicts in batch
- params = dict()
- address = dict()
- password = dict()
- alias = dict()
- logondata = dict()
- company = dict()
- # for change parameters
- addressx = dict()
- passwordx = dict()
- logondatax = dict()
- companyx = dict()
- # define username
- add_to_dict(params, 'USERNAME', username)
- # define Address
- add_to_dict(address, 'FIRSTNAME', firstname)
- add_to_dict(address, 'LASTNAME', lastname)
- add_to_dict(address, 'E_MAIL', email)
- # define Password
- add_to_dict(password, 'BAPIPWD', raw_password)
- # define Alias
- add_to_dict(alias, 'USERALIAS', useralias)
- # define LogonData
- add_to_dict(logondata, 'GLTGV', datetime.date.today())
- add_to_dict(logondata, 'GLTGB', '20991231')
- add_to_dict(logondata, 'USTYP', user_type)
- # define company
- add_to_dict(company, 'COMPANY', raw_company)
- params['LOGONDATA'] = logondata
- params['ADDRESS'] = address
- params['COMPANY'] = company
- params['ALIAS'] = alias
- params['PASSWORD'] = password
- # add change if user exists
- if user_change and force:
- add_to_dict(addressx, 'FIRSTNAME', 'X')
- add_to_dict(addressx, 'LASTNAME', 'X')
- add_to_dict(addressx, 'E_MAIL', 'X')
- # define Password
- add_to_dict(passwordx, 'BAPIPWD', 'X')
- # define LogonData
- add_to_dict(logondatax, 'USTYP', 'X')
- # define company
- add_to_dict(companyx, 'COMPANY', 'X')
- params['LOGONDATAX'] = logondatax
- params['ADDRESSX'] = addressx
- params['COMPANYX'] = companyx
- params['PASSWORDX'] = passwordx
- return params
-
-
-def user_role_assignment_build_rfc_params(roles, username):
- rfc_table = []
-
- for role_name in roles:
- table_row = {'AGR_NAME': role_name}
-
- add_to_dict(table_row, 'FROM_DAT', datetime.date.today())
- add_to_dict(table_row, 'TO_DAT', '20991231')
-
- rfc_table.append(table_row)
-
- return {
- 'USERNAME': username,
- 'ACTIVITYGROUPS': rfc_table
- }
-
-
-def user_profile_assignment_build_rfc_params(profiles, username):
- rfc_table = []
-
- for profile_name in profiles:
- table_row = {'BAPIPROF': profile_name}
- rfc_table.append(table_row)
-
- return {
- 'USERNAME': username,
- 'PROFILES': rfc_table
- }
-
-
-def check_user(user_detail):
- if len(user_detail['RETURN']) > 0:
- for sub in user_detail['RETURN']:
- if sub['NUMBER'] == '124':
- return False
- return True
-
-
-def return_analysis(raw):
- change = False
- failed = False
- for state in raw['RETURN']:
- if state['TYPE'] == "E":
- if state['NUMBER'] == '224' or state['NUMBER'] == '124':
- change = False
- else:
- failed = True
- if state['TYPE'] == "S":
- if state['NUMBER'] != '029':
- change = True
- if state['TYPE'] == "W":
- if state['NUMBER'] == '049' or state['NUMBER'] == '047':
- change = True
- if state['NUMBER'] == '255':
- change = True
- return [{"change": change}, {"failed": failed}]
-
-
-def run_module():
- module = AnsibleModule(
- argument_spec=dict(
- # logical values
- state=dict(default='present', choices=[
- 'absent', 'present', 'lock', 'unlock']),
- force=dict(type='bool', default=False),
- # values for connection
- conn_username=dict(type='str', required=True),
- conn_password=dict(type='str', required=True, no_log=True),
- host=dict(type='str', required=True),
- sysnr=dict(type='str', default="00"),
- client=dict(type='str', default="000"),
- # values for the new or existing user
- username=dict(type='str', required=True),
- firstname=dict(type='str', required=False),
- lastname=dict(type='str', required=False),
- email=dict(type='str', required=False),
- password=dict(type='str', required=False, no_log=True),
- useralias=dict(type='str', required=False),
- user_type=dict(default="A",
- choices=['A', 'B', 'C', 'S', 'L']),
- company=dict(type='str', required=False),
- # values for profile must a list
- # Example ["SAP_NEW", "SAP_ALL"]
- profiles=dict(type='list', elements='str', default=[""]),
- # values for roles must a list
- roles=dict(type='list', elements='str', default=[""]),
- ),
- supports_check_mode=False,
- required_if=[('state', 'present', ['useralias', 'company'])]
- )
- result = dict(changed=False, msg='', out='')
- count = 0
- raw = ""
-
- params = module.params
-
- state = params['state']
- conn_username = (params['conn_username']).upper()
- conn_password = params['conn_password']
- host = params['host']
- sysnr = params['sysnr']
- client = params['client']
-
- username = (params['username']).upper()
- firstname = params['firstname']
- lastname = params['lastname']
- email = params['email']
- password = params['password']
- force = params['force']
- if not params['useralias'] is None:
- useralias = (params['useralias']).upper()
- user_type = (params['user_type']).upper()
- company = params['company']
-
- profiles = params['profiles']
- roles = params['roles']
-
- if not HAS_PYRFC_LIBRARY:
- module.fail_json(
- msg=missing_required_lib('pyrfc'),
- exception=PYRFC_LIBRARY_IMPORT_ERROR)
-
- # basic RFC connection with pyrfc
- try:
- conn = Connection(user=conn_username, passwd=conn_password, ashost=host, sysnr=sysnr, client=client)
- except Exception as err:
- result['error'] = str(err)
- result['msg'] = 'Something went wrong connecting to the SAP system.'
- module.fail_json(**result)
-
- # user details
- user_detail = call_rfc_method(conn, 'BAPI_USER_GET_DETAIL', {'USERNAME': username})
- user_exists = check_user(user_detail)
-
- if state == "absent":
- if user_exists:
- raw = call_rfc_method(conn, 'BAPI_USER_DELETE', {'USERNAME': username})
-
- if state == "present":
- user_params = build_rfc_user_params(username, firstname, lastname, email, password, useralias, user_type, company, user_exists, force)
- if not user_exists:
- raw = call_rfc_method(conn, 'BAPI_USER_CREATE1', user_params)
-
- if user_exists:
- # check for address changes when user exists
- user_no_changes = all((user_detail.get('ADDRESS')).get(k) == v for k, v in (user_params.get('ADDRESS')).items())
- if not user_no_changes or force:
- raw = call_rfc_method(conn, 'BAPI_USER_CHANGE', user_params)
-
- call_rfc_method(conn, 'BAPI_USER_ACTGROUPS_ASSIGN', user_role_assignment_build_rfc_params(roles, username))
-
- call_rfc_method(conn, 'BAPI_USER_PROFILES_ASSIGN', user_profile_assignment_build_rfc_params(profiles, username))
-
- if state == "unlock":
- if user_exists:
- raw = call_rfc_method(conn, 'BAPI_USER_UNLOCK', {'USERNAME': username})
-
- if state == "lock":
- if user_exists:
- raw = call_rfc_method(conn, 'BAPI_USER_LOCK', {'USERNAME': username})
-
- # analyse return value
- if raw != '':
- analysed = return_analysis(raw)
-
- result['out'] = raw
-
- result['changed'] = analysed[0]['change']
- for msgs in raw['RETURN']:
- if count > 0:
- result['msg'] = result['msg'] + '\n'
- result['msg'] = result['msg'] + msgs['MESSAGE']
- count = count + 1
-
- if analysed[1]['failed']:
- module.fail_json(**result)
- else:
- result['msg'] = "No changes where made."
-
- module.exit_json(**result)
-
-
-def main():
- run_module()
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/sap/plugins/modules/sapcar_extract.py b/ansible_collections/community/sap/plugins/modules/sapcar_extract.py
deleted file mode 100644
index d586dd330..000000000
--- a/ansible_collections/community/sap/plugins/modules/sapcar_extract.py
+++ /dev/null
@@ -1,220 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# Copyright: (c) 2021, Rainer Leber <rainerleber@gmail.com>
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-DOCUMENTATION = r'''
----
-module: sapcar_extract
-short_description: Manages SAP SAPCAR archives
-version_added: "0.1.0"
-description:
- - Provides support for unpacking C(sar)/C(car) files with the SAPCAR binary from SAP and pulling
- information back into Ansible.
-options:
- path:
- description: The path to the SAR/CAR file.
- type: path
- required: true
- dest:
- description:
- - The destination where SAPCAR extracts the SAR file. Missing folders will be created.
- If this parameter is not provided, it will unpack in the same folder as the SAR file.
- type: path
- binary_path:
- description:
- - The path to the SAPCAR binary, for example, C(/home/dummy/sapcar) or C(https://myserver/SAPCAR).
- If this parameter is not provided, the module will look in C(PATH).
- type: path
- signature:
- description:
- - If C(true), the signature will be extracted.
- default: false
- type: bool
- security_library:
- description:
- - The path to the security library, for example, C(/usr/sap/hostctrl/exe/libsapcrytp.so), for signature operations.
- type: path
- manifest:
- description:
- - The name of the manifest.
- default: "SIGNATURE.SMF"
- type: str
- remove:
- description:
- - If C(true), the SAR/CAR file will be removed. B(This should be used with caution!)
- default: false
- type: bool
-author:
- - Rainer Leber (@RainerLeber)
-notes:
- - Always returns C(changed=true) in C(check_mode).
-'''
-
-EXAMPLES = r"""
-- name: Extract SAR file
- community.sap.sapcar_extract:
- path: "~/source/hana.sar"
-
-- name: Extract SAR file with destination
- community.sap.sapcar_extract:
- path: "~/source/hana.sar"
- dest: "~/test/"
-
-- name: Extract SAR file with destination and download from webserver can be a fileshare as well
- community.sap.sapcar_extract:
- path: "~/source/hana.sar"
- dest: "~/dest/"
- binary_path: "https://myserver/SAPCAR"
-
-- name: Extract SAR file and delete SAR after extract
- community.sap.sapcar_extract:
- path: "~/source/hana.sar"
- remove: true
-
-- name: Extract SAR file with manifest
- community.sap.sapcar_extract:
- path: "~/source/hana.sar"
- signature: true
-
-- name: Extract SAR file with manifest and rename it
- community.sap.sapcar_extract:
- path: "~/source/hana.sar"
- manifest: "MyNewSignature.SMF"
- signature: true
-"""
-
-import os
-from tempfile import NamedTemporaryFile
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.urls import open_url
-from ansible.module_utils.common.text.converters import to_native
-
-
-def get_list_of_files(dir_name):
- # create a list of file and directories
- # names in the given directory
- list_of_file = os.listdir(dir_name)
- allFiles = list()
- # Iterate over all the entries
- for entry in list_of_file:
- # Create full path
- fullPath = os.path.join(dir_name, entry)
- # If entry is a directory then get the list of files in this directory
- if os.path.isdir(fullPath):
- allFiles = allFiles + [fullPath]
- allFiles = allFiles + get_list_of_files(fullPath)
- else:
- allFiles.append(fullPath)
- return allFiles
-
-
-def download_SAPCAR(binary_path, module):
- bin_path = None
- # download sapcar binary if url is provided otherwise path is returned
- if binary_path is not None:
- if binary_path.startswith('https://') or binary_path.startswith('http://'):
- random_file = NamedTemporaryFile(delete=False)
- with open_url(binary_path) as response:
- with random_file as out_file:
- data = response.read()
- out_file.write(data)
- os.chmod(out_file.name, 0o700)
- bin_path = out_file.name
- module.add_cleanup_file(bin_path)
- else:
- bin_path = binary_path
- return bin_path
-
-
-def check_if_present(command, path, dest, signature, manifest, module):
- # manipulating output from SAR file for compare with already extracted files
- iter_command = [command, '-tvf', path]
- sar_out = module.run_command(iter_command)[1]
- sar_raw = sar_out.split("\n")[1:]
- if dest[-1] != "/":
- dest = dest + "/"
- sar_files = [dest + x.split(" ")[-1] for x in sar_raw if x]
- # remove any SIGNATURE.SMF from list because it will not unpacked if signature is false
- if not signature:
- sar_files = [item for item in sar_files if not item.endswith('.SMF')]
- # if signature is renamed manipulate files in list of sar file for compare.
- if manifest != "SIGNATURE.SMF":
- sar_files = [item for item in sar_files if not item.endswith('.SMF')]
- sar_files = sar_files + [manifest]
- # get extracted files if present
- files_extracted = get_list_of_files(dest)
- # compare extracted files with files in sar file
- present = all(elem in files_extracted for elem in sar_files)
- return present
-
-
-def main():
- module = AnsibleModule(
- argument_spec=dict(
- path=dict(type='path', required=True),
- dest=dict(type='path'),
- binary_path=dict(type='path'),
- signature=dict(type='bool', default=False),
- security_library=dict(type='path'),
- manifest=dict(type='str', default="SIGNATURE.SMF"),
- remove=dict(type='bool', default=False),
- ),
- supports_check_mode=True,
- )
- rc, out, err = [0, "", ""]
- params = module.params
- check_mode = module.check_mode
-
- path = params['path']
- dest = params['dest']
- signature = params['signature']
- security_library = params['security_library']
- manifest = params['manifest']
- remove = params['remove']
-
- bin_path = download_SAPCAR(params['binary_path'], module)
-
- if dest is None:
- dest_head_tail = os.path.split(path)
- dest = dest_head_tail[0] + '/'
- else:
- if not os.path.exists(dest):
- os.makedirs(dest, 0o755)
-
- if bin_path is not None:
- command = [module.get_bin_path(bin_path, required=True)]
- else:
- try:
- command = [module.get_bin_path('sapcar', required=True)]
- except Exception as e:
- module.fail_json(msg='Failed to find SAPCAR at the expected path or URL "{0}". Please check whether it is available: {1}'
- .format(bin_path, to_native(e)))
-
- present = check_if_present(command[0], path, dest, signature, manifest, module)
-
- if not present:
- command.extend(['-xvf', path, '-R', dest])
- if security_library:
- command.extend(['-L', security_library])
- if signature:
- command.extend(['-manifest', manifest])
- if not check_mode:
- (rc, out, err) = module.run_command(command, check_rc=True)
- changed = True
- else:
- changed = False
- out = "already unpacked"
-
- if remove:
- os.remove(path)
-
- module.exit_json(changed=changed, message=rc, stdout=out,
- stderr=err, command=' '.join(command))
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/sap/plugins/modules/system/sap_snote.py b/ansible_collections/community/sap/plugins/modules/system/sap_snote.py
deleted file mode 100644
index 24f393927..000000000
--- a/ansible_collections/community/sap/plugins/modules/system/sap_snote.py
+++ /dev/null
@@ -1,258 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# Copyright: (c) 2021, Rainer Leber <rainerleber@gmail.com> <rainer.leber@sva.de>
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-DOCUMENTATION = r'''
----
-module: sap_snote
-
-short_description: This module will upload and (de)implements C(SNOTES) in a SAP S4HANA environment.
-
-version_added: "1.0.0"
-
-description:
- - The C(sap_snote) module depends on C(pyrfc) Python library (version 2.4.0 and upwards).
- Depending on distribution you are using, you may need to install additional packages to
- have these available.
- - This module will use the Function Group C(SCWB_API).
- - The C(TMS) must be configured at first.
- - Integrating SNOTES cannot be done via C(DDIC)- or C(SAP*)-User.
-options:
- state:
- description:
- - The decision what to do with the SNOTE.
- - Could be C('present'), C('absent')
- default: 'present'
- choices:
- - 'present'
- - 'absent'
- required: false
- type: str
- conn_username:
- description: The required username for the SAP system.
- required: true
- type: str
- conn_password:
- description: The required password for the SAP system.
- required: true
- type: str
- host:
- description: The required host for the SAP system. Can be either an FQDN or IP Address.
- required: true
- type: str
- sysnr:
- description:
- - The system number of the SAP system.
- - You must quote the value to ensure retaining the leading zeros.
- required: false
- default: '01'
- type: str
- client:
- description:
- - The client number to connect to.
- - You must quote the value to ensure retaining the leading zeros.
- required: false
- default: '000'
- type: str
- snote_path:
- description:
- - The path to the extracted SNOTE txt file.
- - The File could be extracted from SAR package.
- - If C(snote_path) is not provided, the C(snote) parameter must be defined.
- - The SNOTE txt file must be at a place where the SAP System is authorized for. For example C(/usr/sap/trans/files).
- required: false
- type: str
- snote:
- description:
- - With the C(snote) paramter only implementation and deimplementation will work.
- - Upload SNOTES to the System is only available if C(snote_path) is provided.
- required: false
- type: str
-
-requirements:
- - pyrfc >= 2.4.0
-
-author:
- - Rainer Leber (@rainerleber)
-'''
-
-EXAMPLES = r'''
-- name: test snote module
- hosts: localhost
- tasks:
- - name: implement SNOTE
- community.sap.sap_snote:
- conn_username: 'DDIC'
- conn_password: 'Passwd1234'
- host: 192.168.1.100
- sysnr: '01'
- client: '000'
- state: present
- snote_path: /usr/sap/trans/tmp/0002949148.txt
-
-- name: test snote module without path
- hosts: localhost
- tasks:
- - name: deimplement SNOTE
- community.sap.sap_snote:
- conn_username: 'DDIC'
- conn_password: 'Passwd1234'
- host: 192.168.1.100
- sysnr: '01'
- client: '000'
- state: absent
- snote: 0002949148
-
-'''
-
-RETURN = r'''
-msg:
- description: A small execution description.
- type: str
- returned: always
- sample: 'SNOTE 000298026 implemented.'
-out:
- description: A complete description of the SNOTE implementation. If this is available.
- type: list
- elements: dict
- returned: always
- sample: '{
- "RETURN": [{"ES_MSG": { "MSGNO": "000", "MSGTY": "", "MSGTXT": "", "MSGV1": "" },
- "ET_MSG": [],
- "EV_RC": 0,
- "ET_MISSING_NOTES": [],
- "IT_FILENAME": [{"FILENAME": "/usr/sap/trans/tmp/0002980265.txt"}],
- "IT_NOTES": [{"NUMM": "0002980265", "VERSNO": "0000"}]
- }]}'
-'''
-
-from ansible.module_utils.basic import AnsibleModule, missing_required_lib
-from os import path as os_path
-import traceback
-try:
- from pyrfc import Connection
-except ImportError:
- HAS_PYRFC_LIBRARY = False
- ANOTHER_LIBRARY_IMPORT_ERROR = traceback.format_exc()
-else:
- HAS_PYRFC_LIBRARY = True
-
-
-def call_rfc_method(connection, method_name, kwargs):
- # PyRFC call function
- return connection.call(method_name, **kwargs)
-
-
-def check_implementation(conn, snote):
- check_implemented = call_rfc_method(conn, 'SCWB_API_GET_NOTES_IMPLEMENTED', {})
- for snote_list in check_implemented['ET_NOTES_IMPL']:
- if snote in snote_list['NUMM']:
- return True
- return False
-
-
-def run_module():
- module = AnsibleModule(
- argument_spec=dict(
- state=dict(default='present', choices=['absent', 'present']),
- conn_username=dict(type='str', required=True),
- conn_password=dict(type='str', required=True, no_log=True),
- host=dict(type='str', required=True),
- sysnr=dict(type='str', default="01"),
- client=dict(type='str', default="000"),
- snote_path=dict(type='str', required=False),
- snote=dict(type='str', required=False),
- ),
- required_one_of=[('snote_path', 'snote')],
- supports_check_mode=False,
- )
- result = dict(changed=False, msg='', out={}, error='')
- raw = ""
- post_check = False
-
- params = module.params
-
- state = params['state']
- conn_username = (params['conn_username']).upper()
- conn_password = params['conn_password']
- host = params['host']
- sysnr = (params['sysnr']).zfill(2)
- client = params['client']
-
- path = params['snote_path']
- snote = params['snote']
-
- if not HAS_PYRFC_LIBRARY:
- module.fail_json(
- msg=missing_required_lib('pyrfc'),
- exception=ANOTHER_LIBRARY_IMPORT_ERROR)
-
- if conn_username == "DDIC" or conn_username == "SAP*":
- result['msg'] = 'User C(DDIC) or C(SAP*) not allowed for this operation.'
- module.fail_json(**result)
-
- # basic RFC connection with pyrfc
- try:
- conn = Connection(user=conn_username, passwd=conn_password, ashost=host, sysnr=sysnr, client=client)
- except Exception as err:
- result['error'] = str(err)
- result['msg'] = 'Something went wrong connecting to the SAP system.'
- module.fail_json(**result)
-
- # pre evaluation of parameters
- if path is not None:
- if path.endswith('.txt'):
- # splits snote number from path and txt extension
- snote = os_path.basename(os_path.normpath(path)).split('.')[0]
- else:
- result['msg'] = 'The path must include the extracted snote file and ends with txt.'
- module.fail_json(**result)
-
- pre_check = check_implementation(conn, snote)
-
- if state == "absent" and pre_check:
- raw = call_rfc_method(conn, 'SCWB_API_NOTES_DEIMPLEMENT', {'IT_NOTES': [snote]})
-
- if state == "present" and not pre_check:
- if path:
- raw_upload = call_rfc_method(conn, 'SCWB_API_UPLOAD_NOTES', {'IT_FILENAME': [path], 'IT_NOTES': [snote]})
- if raw_upload['EV_RC'] != 0:
- result['out'] = raw_upload
- result['msg'] = raw_upload['ES_MSG']['MSGTXT']
- module.fail_json(**result)
-
- raw = call_rfc_method(conn, 'SCWB_API_NOTES_IMPLEMENT', {'IT_NOTES': [snote]})
- queued = call_rfc_method(conn, 'SCWB_API_CINST_QUEUE_GET', {})
-
- if queued['ET_MANUAL_ACTIVITIES']:
- raw = call_rfc_method(conn, 'SCWB_API_CONFIRM_MAN_ACTIVITY', {})
-
- if raw:
- if raw['EV_RC'] == 0:
- post_check = check_implementation(conn, snote)
- if post_check and state == "present":
- result['changed'] = True
- result['msg'] = 'SNOTE "{0}" implemented.'.format(snote)
- if not post_check and state == "absent":
- result['changed'] = True
- result['msg'] = 'SNOTE "{0}" deimplemented.'.format(snote)
- else:
- result['msg'] = "Something went wrong."
- module.fail_json(**result)
- result['out'] = raw
- else:
- result['msg'] = "Nothing to do."
-
- module.exit_json(**result)
-
-
-def main():
- run_module()
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/sap/plugins/modules/system/sap_system_facts.py b/ansible_collections/community/sap/plugins/modules/system/sap_system_facts.py
deleted file mode 100644
index b5f4eb9b6..000000000
--- a/ansible_collections/community/sap/plugins/modules/system/sap_system_facts.py
+++ /dev/null
@@ -1,206 +0,0 @@
-#!/usr/bin/python
-
-# Copyright: (c) 2022, Rainer Leber rainerleber@gmail.com>
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-DOCUMENTATION = r'''
----
-module: sap_system_facts
-
-short_description: Gathers SAP facts in a host
-
-version_added: "1.0.0"
-
-description:
- - This facts module gathers SAP system facts about the running instance.
-
-author:
- - Rainer Leber (@rainerleber)
-
-notes:
- - Supports C(check_mode).
-'''
-
-EXAMPLES = r'''
-- name: Return SAP system ansible_facts
- community.sap.sap_system_fact:
-'''
-
-RETURN = r'''
-# These are examples of possible return values,
-# and in general should use other names for return values.
-ansible_facts:
- description: Facts to add to ansible_facts.
- returned: always
- type: list
- elements: dict
- contains:
- sap:
- description: Facts about the running SAP system.
- type: list
- elements: dict
- returned: When SAP system fact is present
- sample: [
- {
- "InstanceType": "NW",
- "NR": "00",
- "SID": "ABC",
- "TYPE": "ASCS"
- },
- {
- "InstanceType": "NW",
- "NR": "01",
- "SID": "ABC",
- "TYPE": "PAS"
- },
- {
- "InstanceType": "HANA",
- "NR": "02",
- "SID": "HDB",
- "TYPE": "HDB"
- },
- {
- "InstanceType": "NW",
- "NR": "80",
- "SID": "WEB",
- "TYPE": "WebDisp"
- }
- ]
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-import os
-import re
-
-
-def get_all_hana_sid():
- hana_sid = list()
- if os.path.isdir("/hana/shared"):
- # /hana/shared directory exists
- for sid in os.listdir('/hana/shared'):
- if os.path.isdir("/usr/sap/" + sid):
- hana_sid = hana_sid + [sid]
- if hana_sid:
- return hana_sid
-
-
-def get_all_nw_sid():
- nw_sid = list()
- if os.path.isdir("/sapmnt"):
- # /sapmnt directory exists
- for sid in os.listdir('/sapmnt'):
- if os.path.isdir("/usr/sap/" + sid):
- nw_sid = nw_sid + [sid]
- else:
- # Check to see if /sapmnt/SID/sap_bobj exists
- if os.path.isdir("/sapmnt/" + sid + "/sap_bobj"):
- # is a bobj system
- nw_sid = nw_sid + [sid]
- if nw_sid:
- return nw_sid
-
-
-def get_hana_nr(sids, module):
- hana_list = list()
- for sid in sids:
- for instance in os.listdir('/usr/sap/' + sid):
- if 'HDB' in instance:
- instance_nr = instance[-2:]
- # check if instance number exists
- command = [module.get_bin_path('/usr/sap/hostctrl/exe/sapcontrol', required=True)]
- command.extend(['-nr', instance_nr, '-function', 'GetProcessList'])
- check_instance = module.run_command(command, check_rc=False)
- # sapcontrol returns c(0 - 5) exit codes only c(1) is unavailable
- if check_instance[0] != 1:
- hana_list.append({'NR': instance_nr, 'SID': sid, 'TYPE': 'HDB', 'InstanceType': 'HANA'})
- return hana_list
-
-
-def get_nw_nr(sids, module):
- nw_list = list()
- type = ""
- for sid in sids:
- for instance in os.listdir('/usr/sap/' + sid):
- instance_nr = instance[-2:]
- command = [module.get_bin_path('/usr/sap/hostctrl/exe/sapcontrol', required=True)]
- # check if returned instance_nr is a number because sapcontrol returns all if a random string is provided
- if instance_nr.isdigit():
- command.extend(['-nr', instance_nr, '-function', 'GetInstanceProperties'])
- check_instance = module.run_command(command, check_rc=False)
- if check_instance[0] != 1:
- for line in check_instance[1].splitlines():
- if re.search('INSTANCE_NAME', line):
- # convert to list and extract last
- type_raw = (line.strip('][').split(', '))[-1]
- # split instance number
- type = type_raw[:-2]
- nw_list.append({'NR': instance_nr, 'SID': sid, 'TYPE': get_instance_type(type), 'InstanceType': 'NW'})
- return nw_list
-
-
-def get_instance_type(raw_type):
- if raw_type[0] == "D":
- # It's a PAS
- type = "PAS"
- elif raw_type[0] == "A":
- # It's an ASCS
- type = "ASCS"
- elif raw_type[0] == "W":
- # It's a Webdisp
- type = "WebDisp"
- elif raw_type[0] == "J":
- # It's a Java
- type = "Java"
- elif raw_type[0] == "S":
- # It's an SCS
- type = "SCS"
- elif raw_type[0] == "E":
- # It's an ERS
- type = "ERS"
- else:
- # Unknown instance type
- type = "XXX"
- return type
-
-
-def run_module():
- module_args = dict()
- system_result = list()
-
- result = dict(
- changed=False,
- ansible_facts=dict(),
- )
-
- module = AnsibleModule(
- argument_spec=module_args,
- supports_check_mode=True,
- )
-
- hana_sid = get_all_hana_sid()
- if hana_sid:
- system_result = system_result + get_hana_nr(hana_sid, module)
-
- nw_sid = get_all_nw_sid()
- if nw_sid:
- system_result = system_result + get_nw_nr(nw_sid, module)
-
- if system_result:
- result['ansible_facts'] = {'sap': system_result}
- else:
- result['ansible_facts']
-
- if module.check_mode:
- module.exit_json(**result)
-
- module.exit_json(**result)
-
-
-def main():
- run_module()
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/sap/plugins/modules/system/sap_task_list_execute.py b/ansible_collections/community/sap/plugins/modules/system/sap_task_list_execute.py
deleted file mode 100644
index 0ae25903f..000000000
--- a/ansible_collections/community/sap/plugins/modules/system/sap_task_list_execute.py
+++ /dev/null
@@ -1,340 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# Copyright: (c) 2021, Rainer Leber <rainerleber@gmail.com>
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-DOCUMENTATION = r'''
----
-module: sap_task_list_execute
-short_description: Perform SAP Task list execution
-version_added: "0.1.0"
-description:
- - The M(community.sap.sap_task_list_execute) module depends on C(pyrfc) Python library (version 2.4.0 and upwards).
- Depending on distribution you are using, you may need to install additional packages to
- have these available.
- - Tasks in the task list which requires manual activities will be confirmed automatically.
- - This module will use the RFC package C(STC_TM_API).
-
-requirements:
- - pyrfc >= 2.4.0
- - xmltodict
-
-options:
- conn_username:
- description: The required username for the SAP system.
- required: true
- type: str
- conn_password:
- description: The required password for the SAP system.
- required: true
- type: str
- host:
- description: The required host for the SAP system. Can be either an FQDN or IP Address.
- required: true
- type: str
- sysnr:
- description:
- - The system number of the SAP system.
- - You must quote the value to ensure retaining the leading zeros.
- default: '00'
- type: str
- client:
- description:
- - The client number to connect to.
- - You must quote the value to ensure retaining the leading zeros.
- default: '000'
- type: str
- task_to_execute:
- description: The task list which will be executed.
- required: true
- type: str
- task_parameters:
- description:
- - The tasks and the parameters for execution.
- - If the task list does not need any parameters, this could be empty.
- - If only specific tasks from the task list should be executed,
- the tasks even when no parameter is needed must be provided
- alongside with the module parameter I(task_skip=true).
- type: list
- elements: dict
- suboptions:
- TASKNAME:
- description: The name of the task in the task list.
- type: str
- required: true
- FIELDNAME:
- description: The name of the field of the task.
- type: str
- VALUE:
- description: The value which have to be set.
- type: raw
- task_settings:
- description:
- - Setting for the execution of the task list. This can be the following as in TCODE SE80 described.
- Check Mode C(CHECKRUN), Background Processing Active C(BATCH) (this is the default value),
- Asynchronous Execution C(ASYNC), Trace Mode C(TRACE), Server Name C(BATCH_TARGET).
- default: ['BATCH']
- type: list
- elements: str
- task_skip:
- description:
- - If this parameter is C(true), not defined tasks in I(task_parameters) are skipped.
- - This could be the case when only certain tasks should run from the task list.
- default: false
- type: bool
-
-notes:
- - Does not support C(check_mode). Always returns that the state has changed.
-author:
- - Rainer Leber (@rainerleber)
-'''
-
-EXAMPLES = r'''
-# Pass in a message
-- name: Test task execution
- community.sap.sap_task_list_execute:
- conn_username: DDIC
- conn_password: Passwd1234
- host: 10.1.8.10
- sysnr: '01'
- client: '000'
- task_to_execute: SAP_BASIS_SSL_CHECK
- task_settings: batch
-
-- name: Pass in input parameters
- community.sap.sap_task_list_execute:
- conn_username: DDIC
- conn_password: Passwd1234
- host: 10.1.8.10
- sysnr: '00'
- client: '000'
- task_to_execute: SAP_BASIS_SSL_CHECK
- task_parameters :
- - { 'TASKNAME': 'CL_STCT_CHECK_SEC_CRYPTO', 'FIELDNAME': 'P_OPT2', 'VALUE': 'X' }
- - TASKNAME: CL_STCT_CHECK_SEC_CRYPTO
- FIELDNAME: P_OPT3
- VALUE: X
- task_settings: batch
-
-# Exported environment variables
-- name: Hint if module will fail with error message like ImportError libsapnwrfc.so...
- community.sap.sap_task_list_execute:
- conn_username: DDIC
- conn_password: Passwd1234
- host: 10.1.8.10
- sysnr: '00'
- client: '000'
- task_to_execute: SAP_BASIS_SSL_CHECK
- task_settings: batch
- environment:
- SAPNWRFC_HOME: /usr/local/sap/nwrfcsdk
- LD_LIBRARY_PATH: /usr/local/sap/nwrfcsdk/lib
-'''
-
-RETURN = r'''
-msg:
- description: A small execution description.
- type: str
- returned: always
- sample: 'Successful'
-out:
- description: A complete description of the executed tasks. If this is available.
- type: list
- elements: dict
- returned: on success
- sample: [...,{
- "LOG": {
- "STCTM_S_LOG": [
- {
- "ACTIVITY": "U_CONFIG",
- "ACTIVITY_DESCR": "Configuration changed",
- "DETAILS": null,
- "EXEC_ID": "20210728184903.815739",
- "FIELD": null,
- "ID": "STC_TASK",
- "LOG_MSG_NO": "000000",
- "LOG_NO": null,
- "MESSAGE": "For radiobutton group ICM too many options are set; choose only one option",
- "MESSAGE_V1": "ICM",
- "MESSAGE_V2": null,
- "MESSAGE_V3": null,
- "MESSAGE_V4": null,
- "NUMBER": "048",
- "PARAMETER": null,
- "PERIOD": "M",
- "PERIOD_DESCR": "Maintenance",
- "ROW": "0",
- "SRC_LINE": "170",
- "SRC_OBJECT": "CL_STCTM_REPORT_UI IF_STCTM_UI_TASK~SET_PARAMETERS",
- "SYSTEM": null,
- "TIMESTMP": "20210728184903",
- "TSTPNM": "DDIC",
- "TYPE": "E"
- },...
- ]}}]
-'''
-
-from ansible.module_utils.basic import AnsibleModule, missing_required_lib
-import traceback
-try:
- from pyrfc import Connection
-except ImportError:
- HAS_PYRFC_LIBRARY = False
- PYRFC_LIBRARY_IMPORT_ERROR = traceback.format_exc()
-else:
- HAS_PYRFC_LIBRARY = True
-try:
- import xmltodict
-except ImportError:
- HAS_XMLTODICT_LIBRARY = False
- XMLTODICT_LIBRARY_IMPORT_ERROR = traceback.format_exc()
-else:
- HAS_XMLTODICT_LIBRARY = True
-
-
-def call_rfc_method(connection, method_name, kwargs):
- # PyRFC call function
- return connection.call(method_name, **kwargs)
-
-
-def process_exec_settings(task_settings):
- # processes task settings to objects
- exec_settings = {}
- for settings in task_settings:
- temp_dict = {settings.upper(): 'X'}
- for key, value in temp_dict.items():
- exec_settings[key] = value
- return exec_settings
-
-
-def xml_to_dict(xml_raw):
- try:
- xml_parsed = xmltodict.parse(xml_raw, dict_constructor=dict)
- xml_dict = xml_parsed['asx:abap']['asx:values']['SESSION']['TASKLIST']
- except KeyError:
- xml_dict = "No logs available."
- return xml_dict
-
-
-def run_module():
-
- params_spec = dict(
- TASKNAME=dict(type='str', required=True),
- FIELDNAME=dict(type='str'),
- VALUE=dict(type='raw'),
- )
-
- # define available arguments/parameters a user can pass to the module
- module = AnsibleModule(
- argument_spec=dict(
- # values for connection
- conn_username=dict(type='str', required=True),
- conn_password=dict(type='str', required=True, no_log=True),
- host=dict(type='str', required=True),
- sysnr=dict(type='str', default="00"),
- client=dict(type='str', default="000"),
- # values for execution tasks
- task_to_execute=dict(type='str', required=True),
- task_parameters=dict(type='list', elements='dict', options=params_spec),
- task_settings=dict(type='list', elements='str', default=['BATCH']),
- task_skip=dict(type='bool', default=False),
- ),
- supports_check_mode=False,
- )
- result = dict(changed=False, msg='', out={})
-
- params = module.params
-
- username = params['conn_username'].upper()
- password = params['conn_password']
- host = params['host']
- sysnr = params['sysnr']
- client = params['client']
-
- task_parameters = params['task_parameters']
- task_to_execute = params['task_to_execute']
- task_settings = params['task_settings']
- task_skip = params['task_skip']
-
- if not HAS_PYRFC_LIBRARY:
- module.fail_json(
- msg=missing_required_lib('pyrfc'),
- exception=PYRFC_LIBRARY_IMPORT_ERROR)
-
- if not HAS_XMLTODICT_LIBRARY:
- module.fail_json(
- msg=missing_required_lib('xmltodict'),
- exception=XMLTODICT_LIBRARY_IMPORT_ERROR)
-
- # basic RFC connection with pyrfc
- try:
- conn = Connection(user=username, passwd=password, ashost=host, sysnr=sysnr, client=client)
- except Exception as err:
- result['error'] = str(err)
- result['msg'] = 'Something went wrong connecting to the SAP system.'
- module.fail_json(**result)
-
- try:
- raw_params = call_rfc_method(conn, 'STC_TM_SCENARIO_GET_PARAMETERS',
- {'I_SCENARIO_ID': task_to_execute})
- except Exception as err:
- result['error'] = str(err)
- result['msg'] = 'The task list does not exist.'
- module.fail_json(**result)
- exec_settings = process_exec_settings(task_settings)
- # initialize session task
- session_init = call_rfc_method(conn, 'STC_TM_SESSION_BEGIN',
- {'I_SCENARIO_ID': task_to_execute,
- 'I_INIT_ONLY': 'X'})
- # Confirm Tasks which requires manual activities from Task List Run
- for task in raw_params['ET_PARAMETER']:
- call_rfc_method(conn, 'STC_TM_TASK_CONFIRM',
- {'I_SESSION_ID': session_init['E_SESSION_ID'],
- 'I_TASKNAME': task['TASKNAME']})
- if task_skip:
- for task in raw_params['ET_PARAMETER']:
- call_rfc_method(conn, 'STC_TM_TASK_SKIP',
- {'I_SESSION_ID': session_init['E_SESSION_ID'],
- 'I_TASKNAME': task['TASKNAME'], 'I_SKIP_DEP_TASKS': 'X'})
- # unskip defined tasks and set parameters
- if task_parameters is not None:
- for task in task_parameters:
- call_rfc_method(conn, 'STC_TM_TASK_UNSKIP',
- {'I_SESSION_ID': session_init['E_SESSION_ID'],
- 'I_TASKNAME': task['TASKNAME'], 'I_UNSKIP_DEP_TASKS': 'X'})
-
- call_rfc_method(conn, 'STC_TM_SESSION_SET_PARAMETERS',
- {'I_SESSION_ID': session_init['E_SESSION_ID'],
- 'IT_PARAMETER': task_parameters})
- # start the task
- try:
- session_start = call_rfc_method(conn, 'STC_TM_SESSION_RESUME',
- {'I_SESSION_ID': session_init['E_SESSION_ID'],
- 'IS_EXEC_SETTINGS': exec_settings})
- except Exception as err:
- result['error'] = str(err)
- result['msg'] = 'Something went wrong. See error.'
- module.fail_json(**result)
- # get task logs because the execution may successfully but the tasks shows errors or warnings
- # returned value is ABAPXML https://help.sap.com/doc/abapdocu_755_index_htm/7.55/en-US/abenabap_xslt_asxml_general.htm
- session_log = call_rfc_method(conn, 'STC_TM_SESSION_GET_LOG',
- {'I_SESSION_ID': session_init['E_SESSION_ID']})
-
- task_list = xml_to_dict(session_log['E_LOG'])
-
- result['changed'] = True
- result['msg'] = session_start['E_STATUS_DESCR']
- result['out'] = task_list
-
- module.exit_json(**result)
-
-
-def main():
- run_module()
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/sap_libs/.github/workflows/ansible-test.yml b/ansible_collections/community/sap_libs/.github/workflows/ansible-test.yml
index e0fc592fb..a1b40a4d2 100644
--- a/ansible_collections/community/sap_libs/.github/workflows/ansible-test.yml
+++ b/ansible_collections/community/sap_libs/.github/workflows/ansible-test.yml
@@ -23,6 +23,8 @@ jobs:
- stable-2.12
- stable-2.13
- stable-2.14
+ - stable-2.15
+ - stable-2.16
- devel
runs-on: >-
@@ -32,7 +34,7 @@ jobs:
steps:
- name: Check out code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Perform sanity testing with ansible-test
uses: ansible-community/ansible-test-gh-action@release/v1
@@ -58,20 +60,22 @@ jobs:
- stable-2.12
- stable-2.13
- stable-2.14
+ - stable-2.15
+ - stable-2.16
- devel
steps:
- name: Check out code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Perform unit testing with ansible-test
uses: ansible-community/ansible-test-gh-action@release/v1
with:
ansible-core-version: ${{ matrix.ansible }}
testing-type: units
- test-deps: >-
- ansible.netcommon
- ansible.utils
+ # test-deps: >-
+ # ansible.netcommon
+ # ansible.utils
# Please consult the Readme for information on why we disabled integration tests temporarily.
diff --git a/ansible_collections/community/sap_libs/FILES.json b/ansible_collections/community/sap_libs/FILES.json
index d16215449..dd25de020 100644
--- a/ansible_collections/community/sap_libs/FILES.json
+++ b/ansible_collections/community/sap_libs/FILES.json
@@ -60,7 +60,7 @@
"name": ".github/workflows/ansible-test.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "58507c49766179b58c1e6b550f15668c01b5dad25d88da745e1e140457c4583e",
+ "chksum_sha256": "8ae89f65bb4bf7682dd28e91b0b29050c81ac8770b1e7a8f1b84128b080e60fc",
"format": 1
},
{
@@ -102,7 +102,7 @@
"name": "changelogs/changelog.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0131d36807f4d8b8ff8572729792c11bdbf5dafec7554e19ecd00b95945f08b8",
+ "chksum_sha256": "00ba82136fb16e705f0eeca3eb787c6d20d27cba52b92c8d478f019fe30f5d5e",
"format": 1
},
{
@@ -337,6 +337,20 @@
"format": 1
},
{
+ "name": "tests/sanity/ignore-2.16.txt",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "4b96e6fd9dd5ffdf1d5a0860ea5407249eecc1fcd4505693e040ef70ba6b2d97",
+ "format": 1
+ },
+ {
+ "name": "tests/sanity/ignore-2.17.txt",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "4b96e6fd9dd5ffdf1d5a0860ea5407249eecc1fcd4505693e040ef70ba6b2d97",
+ "format": 1
+ },
+ {
"name": "tests/sanity/ignore-2.9.txt",
"ftype": "file",
"chksum_type": "sha256",
@@ -403,7 +417,7 @@
"name": "tests/unit/mock/loader.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3452ac615f89c99a76d1df4ab1ad84d1aff546e5b5fde18034a241239690d05a",
+ "chksum_sha256": "a9fc29c6e613dd574f5aa6c96585ddd74c31f0bdd1056206521b4e94c743f625",
"format": 1
},
{
@@ -592,7 +606,7 @@
"name": "README.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "feb05211584ede33d61c331bfe223f9bbb19579cb73068ca1624c17bde8e9069",
+ "chksum_sha256": "247e8ca44c00d265e6b031c99aa2509d2f12dfaeeb966e7f4c0a425b524abfd2",
"format": 1
},
{
diff --git a/ansible_collections/community/sap_libs/MANIFEST.json b/ansible_collections/community/sap_libs/MANIFEST.json
index d3cfbb838..b514d5efb 100644
--- a/ansible_collections/community/sap_libs/MANIFEST.json
+++ b/ansible_collections/community/sap_libs/MANIFEST.json
@@ -2,7 +2,7 @@
"collection_info": {
"namespace": "community",
"name": "sap_libs",
- "version": "1.4.1",
+ "version": "1.4.2",
"authors": [
"Rainer Leber (github.com/rainerleber)",
"Robert Kraemer (github.com/rkpobe)",
@@ -25,7 +25,7 @@
"name": "FILES.json",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "296f2cdd0cd68d42c4dcfa4b9678ecdc575b8dffc9aa91064b75beab0199046b",
+ "chksum_sha256": "d99acd8b8f0315f069547258b8d6de41d473076f6946949f4b3deb5d95cd9f69",
"format": 1
},
"format": 1
diff --git a/ansible_collections/community/sap_libs/README.md b/ansible_collections/community/sap_libs/README.md
index 61a89551e..f4b69aee7 100644
--- a/ansible_collections/community/sap_libs/README.md
+++ b/ansible_collections/community/sap_libs/README.md
@@ -71,6 +71,8 @@ Tested Ansible versions:
- 2.12
- 2.13
- 2.14
+- 2.15
+- 2.16
- devel
Tested Python versions:
@@ -102,14 +104,14 @@ For some modules the below requirements are needed on the host that executes a m
## Included content
- **Modules**:
- - [sap_hdbsql](https://docs.ansible.com/ansible/latest/collections/community/sap_libs/sap_hdbsql.html)
- - [sap_task_list_execute](https://docs.ansible.com/ansible/latest/collections/community/sap_libs/sap_task_list_execute.html)
- - [sapcar_extract](https://docs.ansible.com/ansible/latest/collections/community/sap_libs/sapcar_extract.html)
- - [sap_company](https://docs.ansible.com/ansible/latest/collections/community/sap_libs/sap_company.html)
- - [sap_snote](https://docs.ansible.com/ansible/latest/collections/community/sap_libs/sap_snote.html)
- - [sap_user](https://docs.ansible.com/ansible/latest/collections/community/sap_libs/sap_user.html)
- - [sap_system_facts](https://docs.ansible.com/ansible/latest/collections/community/sap_libs/sap_system_facts.html)
- - [sap_control_exec](https://docs.ansible.com/ansible/latest/collections/community/sap_libs/sap_control_exec.html)
+ - [sap_hdbsql](https://docs.ansible.com/ansible/latest/collections/community/sap_libs/sap_hdbsql_module.html)
+ - [sap_task_list_execute](https://docs.ansible.com/ansible/latest/collections/community/sap_libs/sap_task_list_execute_module.html)
+ - [sapcar_extract](https://docs.ansible.com/ansible/latest/collections/community/sap_libs/sapcar_extract_module.html)
+ - [sap_company](https://docs.ansible.com/ansible/latest/collections/community/sap_libs/sap_company_module.html)
+ - [sap_snote](https://docs.ansible.com/ansible/latest/collections/community/sap_libs/sap_snote_module.html)
+ - [sap_user](https://docs.ansible.com/ansible/latest/collections/community/sap_libs/sap_user_module.html)
+ - [sap_system_facts](https://docs.ansible.com/ansible/latest/collections/community/sap_libs/sap_system_facts_module.html)
+ - [sap_control_exec](https://docs.ansible.com/ansible/latest/collections/community/sap_libs/sap_control_exec_module.html)
## Using this collection
diff --git a/ansible_collections/community/sap_libs/changelogs/changelog.yaml b/ansible_collections/community/sap_libs/changelogs/changelog.yaml
index e29a18049..32ef1ede2 100644
--- a/ansible_collections/community/sap_libs/changelogs/changelog.yaml
+++ b/ansible_collections/community/sap_libs/changelogs/changelog.yaml
@@ -114,3 +114,13 @@ releases:
- 28-fix-sapcontrol-issue.yml
- 29-fix-lint-issues.yml
release_date: '2023-03-09'
+ 1.4.2:
+ changes:
+ bugfixes:
+ - fixes failures in sanity test for all modules
+ release_summary: This is the 1.4.2 patch release of the ``community.sap_libs``
+ collection. This changelog contains all changes to the modules and plugins
+ in this collection that have been made after the previous release.
+ fragments:
+ - 30-fix-lint-issues.yml
+ release_date: '2024-23-01'
diff --git a/ansible_collections/community/sap_libs/tests/sanity/ignore-2.16.txt b/ansible_collections/community/sap_libs/tests/sanity/ignore-2.16.txt
new file mode 100644
index 000000000..3883757f2
--- /dev/null
+++ b/ansible_collections/community/sap_libs/tests/sanity/ignore-2.16.txt
@@ -0,0 +1,9 @@
+plugins/modules/sap_pyrfc.py validate-modules:missing-gplv3-license # Licensed under Apache 2.0
+plugins/modules/sap_company.py validate-modules:missing-gplv3-license # Licensed under Apache 2.0
+plugins/modules/sap_control_exec.py validate-modules:missing-gplv3-license # Licensed under Apache 2.0
+plugins/modules/sap_hdbsql.py validate-modules:missing-gplv3-license # Licensed under Apache 2.0
+plugins/modules/sap_snote.py validate-modules:missing-gplv3-license # Licensed under Apache 2.0
+plugins/modules/sap_system_facts.py validate-modules:missing-gplv3-license # Licensed under Apache 2.0
+plugins/modules/sap_task_list_execute.py validate-modules:missing-gplv3-license # Licensed under Apache 2.0
+plugins/modules/sap_user.py validate-modules:missing-gplv3-license # Licensed under Apache 2.0
+plugins/modules/sapcar_extract.py validate-modules:missing-gplv3-license # Licensed under Apache 2.0 \ No newline at end of file
diff --git a/ansible_collections/community/sap_libs/tests/sanity/ignore-2.17.txt b/ansible_collections/community/sap_libs/tests/sanity/ignore-2.17.txt
new file mode 100644
index 000000000..3883757f2
--- /dev/null
+++ b/ansible_collections/community/sap_libs/tests/sanity/ignore-2.17.txt
@@ -0,0 +1,9 @@
+plugins/modules/sap_pyrfc.py validate-modules:missing-gplv3-license # Licensed under Apache 2.0
+plugins/modules/sap_company.py validate-modules:missing-gplv3-license # Licensed under Apache 2.0
+plugins/modules/sap_control_exec.py validate-modules:missing-gplv3-license # Licensed under Apache 2.0
+plugins/modules/sap_hdbsql.py validate-modules:missing-gplv3-license # Licensed under Apache 2.0
+plugins/modules/sap_snote.py validate-modules:missing-gplv3-license # Licensed under Apache 2.0
+plugins/modules/sap_system_facts.py validate-modules:missing-gplv3-license # Licensed under Apache 2.0
+plugins/modules/sap_task_list_execute.py validate-modules:missing-gplv3-license # Licensed under Apache 2.0
+plugins/modules/sap_user.py validate-modules:missing-gplv3-license # Licensed under Apache 2.0
+plugins/modules/sapcar_extract.py validate-modules:missing-gplv3-license # Licensed under Apache 2.0 \ No newline at end of file
diff --git a/ansible_collections/community/sap_libs/tests/unit/mock/loader.py b/ansible_collections/community/sap_libs/tests/unit/mock/loader.py
index 5389bdcb2..f7aff17c3 100644
--- a/ansible_collections/community/sap_libs/tests/unit/mock/loader.py
+++ b/ansible_collections/community/sap_libs/tests/unit/mock/loader.py
@@ -1,6 +1,7 @@
-# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
+# Copyright (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
#
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
@@ -16,7 +17,7 @@ class DictDataLoader(DataLoader):
def __init__(self, file_mapping=None):
file_mapping = {} if file_mapping is None else file_mapping
- assert type(file_mapping) == dict
+ assert isinstance(file_mapping, dict)
super(DictDataLoader, self).__init__()
diff --git a/ansible_collections/community/skydive/.github/workflows/ansible-test.yml b/ansible_collections/community/skydive/.github/workflows/ansible-test.yml
deleted file mode 100644
index 76923befb..000000000
--- a/ansible_collections/community/skydive/.github/workflows/ansible-test.yml
+++ /dev/null
@@ -1,179 +0,0 @@
-name: CI
-on:
-# Run CI against all pushes (direct commits) and Pull Requests
-- push
-- pull_request
-
-jobs:
-
-###
-# Sanity tests (REQUIRED)
-#
-# https://docs.ansible.com/ansible/latest/dev_guide/testing_sanity.html
-
- sanity:
- name: Sanity (Ⓐ${{ matrix.ansible }})
- strategy:
- matrix:
- ansible:
- # It's important that Sanity is tested against all stable-X.Y branches
- # Testing against `devel` may fail as new tests are added.
- - stable-2.9 # Only if your collection supports Ansible 2.9
- - stable-2.10
- - devel
- runs-on: ubuntu-latest
- steps:
-
- # ansible-test requires the collection to be in a directory in the form
- # .../ansible_collections/community/skydive/
-
- - name: Check out code
- uses: actions/checkout@v2
- with:
- path: ansible_collections/community/skydive
-
- - name: Set up Python
- uses: actions/setup-python@v2
- with:
- # it is just required to run that once as "ansible-test sanity" in the docker image
- # will run on all python versions it supports.
- python-version: 3.8
-
- # Install the head of the given branch (devel, stable-2.10)
- - name: Install ansible-base (${{ matrix.ansible }})
- run: pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz --disable-pip-version-check
-
- # run ansible-test sanity inside of Docker.
- # The docker container has all the pinned dependencies that are required
- # and all python versions ansible supports.
- - name: Run sanity tests
- run: ansible-test sanity --docker -v --color
- working-directory: ./ansible_collections/community/skydive
-
-####
-## Unit tests (OPTIONAL)
-##
-## https://docs.ansible.com/ansible/latest/dev_guide/testing_units.html
-#
-# units:
-# runs-on: ubuntu-latest
-# name: Units (Ⓐ${{ matrix.ansible }}+py${{ matrix.python }})
-# strategy:
-# # As soon as the first unit test fails, cancel the others to free up the CI queue
-# fail-fast: true
-# matrix:
-# ansible:
-# # - stable-2.9 # Only if your collection supports Ansible 2.9
-# - stable-2.10
-# - devel
-# python:
-# - 2.6
-# - 2.7
-# - 3.5
-# - 3.6
-# - 3.7
-# - 3.8
-# - 3.9
-# exclude:
-# - ansible: stable-2.9
-# python: 3.9
-#
-# steps:
-# - name: Check out code
-# uses: actions/checkout@v2
-# with:
-# path: ansible_collections/community/skydive
-#
-# - name: Set up Python ${{ matrix.ansible }}
-# uses: actions/setup-python@v2
-# with:
-# python-version: ${{ matrix.python }}
-#
-# - name: Install ansible-base (${{ matrix.ansible }})
-# run: pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz --disable-pip-version-check
-#
-# # OPTIONAL If your unit test requires Python libraries from other collections
-# # Install them like this
-# - name: Install collection dependencies
-# run: ansible-galaxy collection install ansible.netcommon -p .
-#
-# # Run the unit tests
-# - name: Run unit test
-# run: ansible-test units -v --color --python ${{ matrix.python }} --docker --coverage
-# working-directory: ./ansible_collections/community/skydive
-#
-# # ansible-test support producing code coverage date
-# - name: Generate coverage report
-# run: ansible-test coverage xml -v --requirements --group-by command --group-by version
-# working-directory: ./ansible_collections/community/skydive
-#
-# # See the reports at https://codecov.io/gh/ansible_collections/GITHUBORG/REPONAME
-# - uses: codecov/codecov-action@v1
-# with:
-# fail_ci_if_error: false
-
-####
-## Integration tests (RECOMMENDED)
-##
-## https://docs.ansible.com/ansible/latest/dev_guide/testing_integration.html
-#
-#
-## If the application you are testing is available as a docker container and you want to test
-## multiple versions see the following for an example:
-## https://github.com/ansible-collections/community.zabbix/tree/master/.github/workflows
-#
-# integration:
-# runs-on: ubuntu-latest
-# name: I (Ⓐ${{ matrix.ansible }}+py${{ matrix.python }}})
-# strategy:
-# fail-fast: false
-# matrix:
-# ansible:
-# # - stable-2.9 # Only if your collection supports Ansible 2.9
-# - stable-2.10
-# - devel
-# python:
-# - 2.6
-# - 2.7
-# - 3.5
-# - 3.6
-# - 3.7
-# - 3.8
-# - 3.9
-# exclude:
-# - ansible: stable-2.9
-# python: 3.9
-#
-# steps:
-# - name: Check out code
-# uses: actions/checkout@v2
-# with:
-# path: ansible_collections/community/skydive
-#
-# - name: Set up Python ${{ matrix.ansible }}
-# uses: actions/setup-python@v2
-# with:
-# python-version: ${{ matrix.python }}
-#
-# - name: Install ansible-base (${{ matrix.ansible }})
-# run: pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz --disable-pip-version-check
-#
-# # OPTIONAL If your integration test requires Python libraries or modules from other collections
-# # Install them like this
-# - name: Install collection dependencies
-# run: ansible-galaxy collection install ansible.netcommon -p .
-#
-# # Run the integration tests
-# - name: Run integration test
-# run: ansible-test integration -v --color --retry-on-error --continue-on-error --diff --python ${{ matrix.python }} --docker --coverage
-# working-directory: ./ansible_collections/community/skydive
-#
-# # ansible-test support producing code coverage date
-# - name: Generate coverage report
-# run: ansible-test coverage xml -v --requirements --group-by command --group-by version
-# working-directory: ./ansible_collections/community/skydive
-#
-# # See the reports at https://codecov.io/gh/ansible_collections/GITHUBORG/REPONAME
-# - uses: codecov/codecov-action@v1
-# with:
-# fail_ci_if_error: false
diff --git a/ansible_collections/community/skydive/.gitignore b/ansible_collections/community/skydive/.gitignore
deleted file mode 100644
index 740c81154..000000000
--- a/ansible_collections/community/skydive/.gitignore
+++ /dev/null
@@ -1,132 +0,0 @@
-/tests/output/
-/changelogs/.plugin-cache.yaml
-
-# Byte-compiled / optimized / DLL files
-__pycache__/
-*.py[cod]
-*$py.class
-
-# C extensions
-*.so
-
-# Distribution / packaging
-.Python
-build/
-develop-eggs/
-dist/
-downloads/
-eggs/
-.eggs/
-lib/
-lib64/
-parts/
-sdist/
-var/
-wheels/
-pip-wheel-metadata/
-share/python-wheels/
-*.egg-info/
-.installed.cfg
-*.egg
-MANIFEST
-
-# PyInstaller
-# Usually these files are written by a python script from a template
-# before PyInstaller builds the exe, so as to inject date/other infos into it.
-*.manifest
-*.spec
-
-# Installer logs
-pip-log.txt
-pip-delete-this-directory.txt
-
-# Unit test / coverage reports
-htmlcov/
-.tox/
-.nox/
-.coverage
-.coverage.*
-.cache
-nosetests.xml
-coverage.xml
-*.cover
-*.py,cover
-.hypothesis/
-.pytest_cache/
-
-# Translations
-*.mo
-*.pot
-
-# Django stuff:
-*.log
-local_settings.py
-db.sqlite3
-db.sqlite3-journal
-
-# Flask stuff:
-instance/
-.webassets-cache
-
-# Scrapy stuff:
-.scrapy
-
-# Sphinx documentation
-docs/_build/
-
-# PyBuilder
-target/
-
-# Jupyter Notebook
-.ipynb_checkpoints
-
-# IPython
-profile_default/
-ipython_config.py
-
-# pyenv
-.python-version
-
-# pipenv
-# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
-# However, in case of collaboration, if having platform-specific dependencies or dependencies
-# having no cross-platform support, pipenv may install dependencies that don't work, or not
-# install all needed dependencies.
-#Pipfile.lock
-
-# PEP 582; used by e.g. github.com/David-OConnor/pyflow
-__pypackages__/
-
-# Celery stuff
-celerybeat-schedule
-celerybeat.pid
-
-# SageMath parsed files
-*.sage.py
-
-# Environments
-.env
-.venv
-env/
-venv/
-ENV/
-env.bak/
-venv.bak/
-
-# Spyder project settings
-.spyderproject
-.spyproject
-
-# Rope project settings
-.ropeproject
-
-# mkdocs documentation
-/site
-
-# mypy
-.mypy_cache/
-.dmypy.json
-dmypy.json
-
-# Pyre type checker
-.pyre/
diff --git a/ansible_collections/community/skydive/.yamllint b/ansible_collections/community/skydive/.yamllint
deleted file mode 100644
index 6f0d12b3a..000000000
--- a/ansible_collections/community/skydive/.yamllint
+++ /dev/null
@@ -1,14 +0,0 @@
----
-extends: default
-
-ignore: |
- .tox
-
-rules:
- braces:
- max-spaces-inside: 1
- level: error
- brackets:
- max-spaces-inside: 1
- level: error
- line-length: disable
diff --git a/ansible_collections/community/skydive/CHANGELOG.rst b/ansible_collections/community/skydive/CHANGELOG.rst
deleted file mode 100644
index fe7cbe650..000000000
--- a/ansible_collections/community/skydive/CHANGELOG.rst
+++ /dev/null
@@ -1,16 +0,0 @@
-=====================
-Skydive Release Notes
-=====================
-
-.. contents:: Topics
-
-
-v1.0.0
-======
-
-Release Summary
----------------
-
-| Release Date: 2020-08-18
-| Adapt to Ansible 2.10 collections
-
diff --git a/ansible_collections/community/skydive/FILES.json b/ansible_collections/community/skydive/FILES.json
deleted file mode 100644
index 7163b815c..000000000
--- a/ansible_collections/community/skydive/FILES.json
+++ /dev/null
@@ -1,327 +0,0 @@
-{
- "files": [
- {
- "format": 1,
- "ftype": "dir",
- "chksum_sha256": null,
- "name": ".",
- "chksum_type": null
- },
- {
- "ftype": "file",
- "chksum_sha256": "3d452a1344d28ffe1f8eb2f305d59252ef000b0e827e2f777d4e70b635376247",
- "name": "CHANGELOG.rst",
- "chksum_type": "sha256",
- "format": 1
- },
- {
- "ftype": "file",
- "chksum_sha256": "51aed152ad949ba2a2965a2db34fd378ac9b9bfcddf3e019c8db640d6f681b5c",
- "name": "test-requirements.txt",
- "chksum_type": "sha256",
- "format": 1
- },
- {
- "ftype": "file",
- "chksum_sha256": "c68f4100f7f923dd7e15403829b2a53852d8f167a53d42ff8b814e5ca39cc7f2",
- "name": ".gitignore",
- "chksum_type": "sha256",
- "format": 1
- },
- {
- "ftype": "dir",
- "chksum_sha256": null,
- "name": "tests",
- "chksum_type": null,
- "format": 1
- },
- {
- "ftype": "file",
- "chksum_sha256": "b5726d3ec9335a09c124469eca039523847a6b0f08a083efaefd002b83326600",
- "name": "tests/.gitignore",
- "chksum_type": "sha256",
- "format": 1
- },
- {
- "ftype": "dir",
- "chksum_sha256": null,
- "name": "tests/sanity",
- "chksum_type": null,
- "format": 1
- },
- {
- "ftype": "file",
- "chksum_sha256": "1d4fb7dbb1ce0bbc4b047df8cc0725d80463573bf505dd386bfcc8ae84299902",
- "name": "tests/sanity/ignore-2.11.txt",
- "chksum_type": "sha256",
- "format": 1
- },
- {
- "ftype": "file",
- "chksum_sha256": "5dd8da6c473730effea03be910fae0307afe0352c6f27034ea5e9e71c033af73",
- "name": "tests/sanity/ignore-2.9.txt",
- "chksum_type": "sha256",
- "format": 1
- },
- {
- "ftype": "file",
- "chksum_sha256": "1d4fb7dbb1ce0bbc4b047df8cc0725d80463573bf505dd386bfcc8ae84299902",
- "name": "tests/sanity/ignore-2.10.txt",
- "chksum_type": "sha256",
- "format": 1
- },
- {
- "ftype": "file",
- "chksum_sha256": "c8a4ac4bfdef88e75d6e748e35a42fb4915947dfa2b7dd788626fd829600e014",
- "name": "tests/sanity/requirements.txt",
- "chksum_type": "sha256",
- "format": 1
- },
- {
- "ftype": "dir",
- "chksum_sha256": null,
- "name": "tests/unit",
- "chksum_type": null,
- "format": 1
- },
- {
- "ftype": "file",
- "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
- "name": "tests/unit/__init__.py",
- "chksum_type": "sha256",
- "format": 1
- },
- {
- "ftype": "file",
- "chksum_sha256": "49ba996dc4735c3463e9af561344346dfae14bcc1a68096ce78364b377f0df1f",
- "name": "tests/unit/requirements.txt",
- "chksum_type": "sha256",
- "format": 1
- },
- {
- "ftype": "file",
- "chksum_sha256": "3972dc9744f6499f0f9b2dbf76696f2ae7ad8af9b23dde66d6af86c9dfb36986",
- "name": "LICENSE",
- "chksum_type": "sha256",
- "format": 1
- },
- {
- "ftype": "file",
- "chksum_sha256": "80645079eb025b3a905b4775ac545d080a3d7d35d537c31e04f7197c94315ab5",
- "name": "bindep.txt",
- "chksum_type": "sha256",
- "format": 1
- },
- {
- "ftype": "dir",
- "chksum_sha256": null,
- "name": "meta",
- "chksum_type": null,
- "format": 1
- },
- {
- "ftype": "file",
- "chksum_sha256": "df18179bb2f5447a56ac92261a911649b96821c0b2c08eea62d5cc6b0195203f",
- "name": "meta/runtime.yml",
- "chksum_type": "sha256",
- "format": 1
- },
- {
- "ftype": "dir",
- "chksum_sha256": null,
- "name": "plugins",
- "chksum_type": null,
- "format": 1
- },
- {
- "ftype": "dir",
- "chksum_sha256": null,
- "name": "plugins/modules",
- "chksum_type": null,
- "format": 1
- },
- {
- "ftype": "file",
- "chksum_sha256": "85b5e33f24911147e83fa6f7df4c73989a47a50af1370760b60601c2d0028e05",
- "name": "plugins/modules/skydive_node.py",
- "chksum_type": "sha256",
- "format": 1
- },
- {
- "ftype": "file",
- "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
- "name": "plugins/modules/__init__.py",
- "chksum_type": "sha256",
- "format": 1
- },
- {
- "ftype": "file",
- "chksum_sha256": "2285a8247bfb4ac7d026b6df0a33c6a873cadba6b42859a5a35ed52c73bdb2ff",
- "name": "plugins/modules/skydive_edge.py",
- "chksum_type": "sha256",
- "format": 1
- },
- {
- "ftype": "file",
- "chksum_sha256": "fc4661883071c7ff3231a163cfa42604f875ed7b0653057f0574bb549b4abf9d",
- "name": "plugins/modules/skydive_capture.py",
- "chksum_type": "sha256",
- "format": 1
- },
- {
- "ftype": "dir",
- "chksum_sha256": null,
- "name": "plugins/module_utils",
- "chksum_type": null,
- "format": 1
- },
- {
- "ftype": "dir",
- "chksum_sha256": null,
- "name": "plugins/module_utils/network",
- "chksum_type": null,
- "format": 1
- },
- {
- "ftype": "dir",
- "chksum_sha256": null,
- "name": "plugins/module_utils/network/skydive",
- "chksum_type": null,
- "format": 1
- },
- {
- "ftype": "file",
- "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
- "name": "plugins/module_utils/network/skydive/__init__.py",
- "chksum_type": "sha256",
- "format": 1
- },
- {
- "ftype": "file",
- "chksum_sha256": "8b902f7373d7ab08fdeb7a56d1d130243a239fa45efee975639a262448982614",
- "name": "plugins/module_utils/network/skydive/api.py",
- "chksum_type": "sha256",
- "format": 1
- },
- {
- "ftype": "file",
- "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
- "name": "plugins/module_utils/__init__.py",
- "chksum_type": "sha256",
- "format": 1
- },
- {
- "ftype": "dir",
- "chksum_sha256": null,
- "name": "plugins/lookup",
- "chksum_type": null,
- "format": 1
- },
- {
- "ftype": "file",
- "chksum_sha256": "8118cc779916f5d0e191d0267c6c3d8ed5ce5b6a9bb79095800e19743403c886",
- "name": "plugins/lookup/skydive.py",
- "chksum_type": "sha256",
- "format": 1
- },
- {
- "ftype": "file",
- "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
- "name": "plugins/lookup/__init__.py",
- "chksum_type": "sha256",
- "format": 1
- },
- {
- "ftype": "dir",
- "chksum_sha256": null,
- "name": "plugins/doc_fragments",
- "chksum_type": null,
- "format": 1
- },
- {
- "ftype": "file",
- "chksum_sha256": "2e22b0b58e3b2c0159cebc5a43651d7bb935aa465e752bade6bf707a5a593531",
- "name": "plugins/doc_fragments/skydive.py",
- "chksum_type": "sha256",
- "format": 1
- },
- {
- "ftype": "file",
- "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
- "name": "plugins/doc_fragments/__init__.py",
- "chksum_type": "sha256",
- "format": 1
- },
- {
- "ftype": "file",
- "chksum_sha256": "0d40aece0cd4887e7f29dd479b350b614bf15b73f1168af0ea0bac71f1ef1600",
- "name": "tox.ini",
- "chksum_type": "sha256",
- "format": 1
- },
- {
- "ftype": "dir",
- "chksum_sha256": null,
- "name": ".github",
- "chksum_type": null,
- "format": 1
- },
- {
- "ftype": "dir",
- "chksum_sha256": null,
- "name": ".github/workflows",
- "chksum_type": null,
- "format": 1
- },
- {
- "ftype": "file",
- "chksum_sha256": "115cb022e870c680fed48de248e1e81c06def5bda86bfe5be49681e1117a7184",
- "name": ".github/workflows/ansible-test.yml",
- "chksum_type": "sha256",
- "format": 1
- },
- {
- "ftype": "file",
- "chksum_sha256": "241f61c1280d6cd3fea93a8e6e804ebe521441f8e0e53fbf19331d7d090342e1",
- "name": "README.md",
- "chksum_type": "sha256",
- "format": 1
- },
- {
- "ftype": "file",
- "chksum_sha256": "6cfd68f9160b620f26d34a82dc0f6bee28e97d6e78f61774bba63dbb143144ae",
- "name": "requirements.txt",
- "chksum_type": "sha256",
- "format": 1
- },
- {
- "ftype": "dir",
- "chksum_sha256": null,
- "name": "changelogs",
- "chksum_type": null,
- "format": 1
- },
- {
- "ftype": "file",
- "chksum_sha256": "e6a47ddc8d122cbfed7befbe3ebbc04649c6f75da7e8fd1095b14b22d1983af3",
- "name": "changelogs/config.yaml",
- "chksum_type": "sha256",
- "format": 1
- },
- {
- "ftype": "file",
- "chksum_sha256": "33819adecd8320a3b2fc609996606654396b7941c7cb51d25a1f25ac737a4f1a",
- "name": "changelogs/changelog.yaml",
- "chksum_type": "sha256",
- "format": 1
- },
- {
- "ftype": "file",
- "chksum_sha256": "5f8b92f9b2c5645d9086cdb2d96378b445156e01d5ebeab075f0ac76da82e7c1",
- "name": ".yamllint",
- "chksum_type": "sha256",
- "format": 1
- }
- ],
- "format": 1
-} \ No newline at end of file
diff --git a/ansible_collections/community/skydive/LICENSE b/ansible_collections/community/skydive/LICENSE
deleted file mode 100644
index f288702d2..000000000
--- a/ansible_collections/community/skydive/LICENSE
+++ /dev/null
@@ -1,674 +0,0 @@
- GNU GENERAL PUBLIC LICENSE
- Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The GNU General Public License is a free, copyleft license for
-software and other kinds of works.
-
- The licenses for most software and other practical works are designed
-to take away your freedom to share and change the works. By contrast,
-the GNU General Public License is intended to guarantee your freedom to
-share and change all versions of a program--to make sure it remains free
-software for all its users. We, the Free Software Foundation, use the
-GNU General Public License for most of our software; it applies also to
-any other work released this way by its authors. You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-them if you wish), that you receive source code or can get it if you
-want it, that you can change the software or use pieces of it in new
-free programs, and that you know you can do these things.
-
- To protect your rights, we need to prevent others from denying you
-these rights or asking you to surrender the rights. Therefore, you have
-certain responsibilities if you distribute copies of the software, or if
-you modify it: responsibilities to respect the freedom of others.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must pass on to the recipients the same
-freedoms that you received. You must make sure that they, too, receive
-or can get the source code. And you must show them these terms so they
-know their rights.
-
- Developers that use the GNU GPL protect your rights with two steps:
-(1) assert copyright on the software, and (2) offer you this License
-giving you legal permission to copy, distribute and/or modify it.
-
- For the developers' and authors' protection, the GPL clearly explains
-that there is no warranty for this free software. For both users' and
-authors' sake, the GPL requires that modified versions be marked as
-changed, so that their problems will not be attributed erroneously to
-authors of previous versions.
-
- Some devices are designed to deny users access to install or run
-modified versions of the software inside them, although the manufacturer
-can do so. This is fundamentally incompatible with the aim of
-protecting users' freedom to change the software. The systematic
-pattern of such abuse occurs in the area of products for individuals to
-use, which is precisely where it is most unacceptable. Therefore, we
-have designed this version of the GPL to prohibit the practice for those
-products. If such problems arise substantially in other domains, we
-stand ready to extend this provision to those domains in future versions
-of the GPL, as needed to protect the freedom of users.
-
- Finally, every program is threatened constantly by software patents.
-States should not allow patents to restrict development and use of
-software on general-purpose computers, but in those that do, we wish to
-avoid the special danger that patents applied to a free program could
-make it effectively proprietary. To prevent this, the GPL assures that
-patents cannot be used to render the program non-free.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- TERMS AND CONDITIONS
-
- 0. Definitions.
-
- "This License" refers to version 3 of the GNU General Public License.
-
- "Copyright" also means copyright-like laws that apply to other kinds of
-works, such as semiconductor masks.
-
- "The Program" refers to any copyrightable work licensed under this
-License. Each licensee is addressed as "you". "Licensees" and
-"recipients" may be individuals or organizations.
-
- To "modify" a work means to copy from or adapt all or part of the work
-in a fashion requiring copyright permission, other than the making of an
-exact copy. The resulting work is called a "modified version" of the
-earlier work or a work "based on" the earlier work.
-
- A "covered work" means either the unmodified Program or a work based
-on the Program.
-
- To "propagate" a work means to do anything with it that, without
-permission, would make you directly or secondarily liable for
-infringement under applicable copyright law, except executing it on a
-computer or modifying a private copy. Propagation includes copying,
-distribution (with or without modification), making available to the
-public, and in some countries other activities as well.
-
- To "convey" a work means any kind of propagation that enables other
-parties to make or receive copies. Mere interaction with a user through
-a computer network, with no transfer of a copy, is not conveying.
-
- An interactive user interface displays "Appropriate Legal Notices"
-to the extent that it includes a convenient and prominently visible
-feature that (1) displays an appropriate copyright notice, and (2)
-tells the user that there is no warranty for the work (except to the
-extent that warranties are provided), that licensees may convey the
-work under this License, and how to view a copy of this License. If
-the interface presents a list of user commands or options, such as a
-menu, a prominent item in the list meets this criterion.
-
- 1. Source Code.
-
- The "source code" for a work means the preferred form of the work
-for making modifications to it. "Object code" means any non-source
-form of a work.
-
- A "Standard Interface" means an interface that either is an official
-standard defined by a recognized standards body, or, in the case of
-interfaces specified for a particular programming language, one that
-is widely used among developers working in that language.
-
- The "System Libraries" of an executable work include anything, other
-than the work as a whole, that (a) is included in the normal form of
-packaging a Major Component, but which is not part of that Major
-Component, and (b) serves only to enable use of the work with that
-Major Component, or to implement a Standard Interface for which an
-implementation is available to the public in source code form. A
-"Major Component", in this context, means a major essential component
-(kernel, window system, and so on) of the specific operating system
-(if any) on which the executable work runs, or a compiler used to
-produce the work, or an object code interpreter used to run it.
-
- The "Corresponding Source" for a work in object code form means all
-the source code needed to generate, install, and (for an executable
-work) run the object code and to modify the work, including scripts to
-control those activities. However, it does not include the work's
-System Libraries, or general-purpose tools or generally available free
-programs which are used unmodified in performing those activities but
-which are not part of the work. For example, Corresponding Source
-includes interface definition files associated with source files for
-the work, and the source code for shared libraries and dynamically
-linked subprograms that the work is specifically designed to require,
-such as by intimate data communication or control flow between those
-subprograms and other parts of the work.
-
- The Corresponding Source need not include anything that users
-can regenerate automatically from other parts of the Corresponding
-Source.
-
- The Corresponding Source for a work in source code form is that
-same work.
-
- 2. Basic Permissions.
-
- All rights granted under this License are granted for the term of
-copyright on the Program, and are irrevocable provided the stated
-conditions are met. This License explicitly affirms your unlimited
-permission to run the unmodified Program. The output from running a
-covered work is covered by this License only if the output, given its
-content, constitutes a covered work. This License acknowledges your
-rights of fair use or other equivalent, as provided by copyright law.
-
- You may make, run and propagate covered works that you do not
-convey, without conditions so long as your license otherwise remains
-in force. You may convey covered works to others for the sole purpose
-of having them make modifications exclusively for you, or provide you
-with facilities for running those works, provided that you comply with
-the terms of this License in conveying all material for which you do
-not control copyright. Those thus making or running the covered works
-for you must do so exclusively on your behalf, under your direction
-and control, on terms that prohibit them from making any copies of
-your copyrighted material outside their relationship with you.
-
- Conveying under any other circumstances is permitted solely under
-the conditions stated below. Sublicensing is not allowed; section 10
-makes it unnecessary.
-
- 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-
- No covered work shall be deemed part of an effective technological
-measure under any applicable law fulfilling obligations under article
-11 of the WIPO copyright treaty adopted on 20 December 1996, or
-similar laws prohibiting or restricting circumvention of such
-measures.
-
- When you convey a covered work, you waive any legal power to forbid
-circumvention of technological measures to the extent such circumvention
-is effected by exercising rights under this License with respect to
-the covered work, and you disclaim any intention to limit operation or
-modification of the work as a means of enforcing, against the work's
-users, your or third parties' legal rights to forbid circumvention of
-technological measures.
-
- 4. Conveying Verbatim Copies.
-
- You may convey verbatim copies of the Program's source code as you
-receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice;
-keep intact all notices stating that this License and any
-non-permissive terms added in accord with section 7 apply to the code;
-keep intact all notices of the absence of any warranty; and give all
-recipients a copy of this License along with the Program.
-
- You may charge any price or no price for each copy that you convey,
-and you may offer support or warranty protection for a fee.
-
- 5. Conveying Modified Source Versions.
-
- You may convey a work based on the Program, or the modifications to
-produce it from the Program, in the form of source code under the
-terms of section 4, provided that you also meet all of these conditions:
-
- a) The work must carry prominent notices stating that you modified
- it, and giving a relevant date.
-
- b) The work must carry prominent notices stating that it is
- released under this License and any conditions added under section
- 7. This requirement modifies the requirement in section 4 to
- "keep intact all notices".
-
- c) You must license the entire work, as a whole, under this
- License to anyone who comes into possession of a copy. This
- License will therefore apply, along with any applicable section 7
- additional terms, to the whole of the work, and all its parts,
- regardless of how they are packaged. This License gives no
- permission to license the work in any other way, but it does not
- invalidate such permission if you have separately received it.
-
- d) If the work has interactive user interfaces, each must display
- Appropriate Legal Notices; however, if the Program has interactive
- interfaces that do not display Appropriate Legal Notices, your
- work need not make them do so.
-
- A compilation of a covered work with other separate and independent
-works, which are not by their nature extensions of the covered work,
-and which are not combined with it such as to form a larger program,
-in or on a volume of a storage or distribution medium, is called an
-"aggregate" if the compilation and its resulting copyright are not
-used to limit the access or legal rights of the compilation's users
-beyond what the individual works permit. Inclusion of a covered work
-in an aggregate does not cause this License to apply to the other
-parts of the aggregate.
-
- 6. Conveying Non-Source Forms.
-
- You may convey a covered work in object code form under the terms
-of sections 4 and 5, provided that you also convey the
-machine-readable Corresponding Source under the terms of this License,
-in one of these ways:
-
- a) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by the
- Corresponding Source fixed on a durable physical medium
- customarily used for software interchange.
-
- b) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by a
- written offer, valid for at least three years and valid for as
- long as you offer spare parts or customer support for that product
- model, to give anyone who possesses the object code either (1) a
- copy of the Corresponding Source for all the software in the
- product that is covered by this License, on a durable physical
- medium customarily used for software interchange, for a price no
- more than your reasonable cost of physically performing this
- conveying of source, or (2) access to copy the
- Corresponding Source from a network server at no charge.
-
- c) Convey individual copies of the object code with a copy of the
- written offer to provide the Corresponding Source. This
- alternative is allowed only occasionally and noncommercially, and
- only if you received the object code with such an offer, in accord
- with subsection 6b.
-
- d) Convey the object code by offering access from a designated
- place (gratis or for a charge), and offer equivalent access to the
- Corresponding Source in the same way through the same place at no
- further charge. You need not require recipients to copy the
- Corresponding Source along with the object code. If the place to
- copy the object code is a network server, the Corresponding Source
- may be on a different server (operated by you or a third party)
- that supports equivalent copying facilities, provided you maintain
- clear directions next to the object code saying where to find the
- Corresponding Source. Regardless of what server hosts the
- Corresponding Source, you remain obligated to ensure that it is
- available for as long as needed to satisfy these requirements.
-
- e) Convey the object code using peer-to-peer transmission, provided
- you inform other peers where the object code and Corresponding
- Source of the work are being offered to the general public at no
- charge under subsection 6d.
-
- A separable portion of the object code, whose source code is excluded
-from the Corresponding Source as a System Library, need not be
-included in conveying the object code work.
-
- A "User Product" is either (1) a "consumer product", which means any
-tangible personal property which is normally used for personal, family,
-or household purposes, or (2) anything designed or sold for incorporation
-into a dwelling. In determining whether a product is a consumer product,
-doubtful cases shall be resolved in favor of coverage. For a particular
-product received by a particular user, "normally used" refers to a
-typical or common use of that class of product, regardless of the status
-of the particular user or of the way in which the particular user
-actually uses, or expects or is expected to use, the product. A product
-is a consumer product regardless of whether the product has substantial
-commercial, industrial or non-consumer uses, unless such uses represent
-the only significant mode of use of the product.
-
- "Installation Information" for a User Product means any methods,
-procedures, authorization keys, or other information required to install
-and execute modified versions of a covered work in that User Product from
-a modified version of its Corresponding Source. The information must
-suffice to ensure that the continued functioning of the modified object
-code is in no case prevented or interfered with solely because
-modification has been made.
-
- If you convey an object code work under this section in, or with, or
-specifically for use in, a User Product, and the conveying occurs as
-part of a transaction in which the right of possession and use of the
-User Product is transferred to the recipient in perpetuity or for a
-fixed term (regardless of how the transaction is characterized), the
-Corresponding Source conveyed under this section must be accompanied
-by the Installation Information. But this requirement does not apply
-if neither you nor any third party retains the ability to install
-modified object code on the User Product (for example, the work has
-been installed in ROM).
-
- The requirement to provide Installation Information does not include a
-requirement to continue to provide support service, warranty, or updates
-for a work that has been modified or installed by the recipient, or for
-the User Product in which it has been modified or installed. Access to a
-network may be denied when the modification itself materially and
-adversely affects the operation of the network or violates the rules and
-protocols for communication across the network.
-
- Corresponding Source conveyed, and Installation Information provided,
-in accord with this section must be in a format that is publicly
-documented (and with an implementation available to the public in
-source code form), and must require no special password or key for
-unpacking, reading or copying.
-
- 7. Additional Terms.
-
- "Additional permissions" are terms that supplement the terms of this
-License by making exceptions from one or more of its conditions.
-Additional permissions that are applicable to the entire Program shall
-be treated as though they were included in this License, to the extent
-that they are valid under applicable law. If additional permissions
-apply only to part of the Program, that part may be used separately
-under those permissions, but the entire Program remains governed by
-this License without regard to the additional permissions.
-
- When you convey a copy of a covered work, you may at your option
-remove any additional permissions from that copy, or from any part of
-it. (Additional permissions may be written to require their own
-removal in certain cases when you modify the work.) You may place
-additional permissions on material, added by you to a covered work,
-for which you have or can give appropriate copyright permission.
-
- Notwithstanding any other provision of this License, for material you
-add to a covered work, you may (if authorized by the copyright holders of
-that material) supplement the terms of this License with terms:
-
- a) Disclaiming warranty or limiting liability differently from the
- terms of sections 15 and 16 of this License; or
-
- b) Requiring preservation of specified reasonable legal notices or
- author attributions in that material or in the Appropriate Legal
- Notices displayed by works containing it; or
-
- c) Prohibiting misrepresentation of the origin of that material, or
- requiring that modified versions of such material be marked in
- reasonable ways as different from the original version; or
-
- d) Limiting the use for publicity purposes of names of licensors or
- authors of the material; or
-
- e) Declining to grant rights under trademark law for use of some
- trade names, trademarks, or service marks; or
-
- f) Requiring indemnification of licensors and authors of that
- material by anyone who conveys the material (or modified versions of
- it) with contractual assumptions of liability to the recipient, for
- any liability that these contractual assumptions directly impose on
- those licensors and authors.
-
- All other non-permissive additional terms are considered "further
-restrictions" within the meaning of section 10. If the Program as you
-received it, or any part of it, contains a notice stating that it is
-governed by this License along with a term that is a further
-restriction, you may remove that term. If a license document contains
-a further restriction but permits relicensing or conveying under this
-License, you may add to a covered work material governed by the terms
-of that license document, provided that the further restriction does
-not survive such relicensing or conveying.
-
- If you add terms to a covered work in accord with this section, you
-must place, in the relevant source files, a statement of the
-additional terms that apply to those files, or a notice indicating
-where to find the applicable terms.
-
- Additional terms, permissive or non-permissive, may be stated in the
-form of a separately written license, or stated as exceptions;
-the above requirements apply either way.
-
- 8. Termination.
-
- You may not propagate or modify a covered work except as expressly
-provided under this License. Any attempt otherwise to propagate or
-modify it is void, and will automatically terminate your rights under
-this License (including any patent licenses granted under the third
-paragraph of section 11).
-
- However, if you cease all violation of this License, then your
-license from a particular copyright holder is reinstated (a)
-provisionally, unless and until the copyright holder explicitly and
-finally terminates your license, and (b) permanently, if the copyright
-holder fails to notify you of the violation by some reasonable means
-prior to 60 days after the cessation.
-
- Moreover, your license from a particular copyright holder is
-reinstated permanently if the copyright holder notifies you of the
-violation by some reasonable means, this is the first time you have
-received notice of violation of this License (for any work) from that
-copyright holder, and you cure the violation prior to 30 days after
-your receipt of the notice.
-
- Termination of your rights under this section does not terminate the
-licenses of parties who have received copies or rights from you under
-this License. If your rights have been terminated and not permanently
-reinstated, you do not qualify to receive new licenses for the same
-material under section 10.
-
- 9. Acceptance Not Required for Having Copies.
-
- You are not required to accept this License in order to receive or
-run a copy of the Program. Ancillary propagation of a covered work
-occurring solely as a consequence of using peer-to-peer transmission
-to receive a copy likewise does not require acceptance. However,
-nothing other than this License grants you permission to propagate or
-modify any covered work. These actions infringe copyright if you do
-not accept this License. Therefore, by modifying or propagating a
-covered work, you indicate your acceptance of this License to do so.
-
- 10. Automatic Licensing of Downstream Recipients.
-
- Each time you convey a covered work, the recipient automatically
-receives a license from the original licensors, to run, modify and
-propagate that work, subject to this License. You are not responsible
-for enforcing compliance by third parties with this License.
-
- An "entity transaction" is a transaction transferring control of an
-organization, or substantially all assets of one, or subdividing an
-organization, or merging organizations. If propagation of a covered
-work results from an entity transaction, each party to that
-transaction who receives a copy of the work also receives whatever
-licenses to the work the party's predecessor in interest had or could
-give under the previous paragraph, plus a right to possession of the
-Corresponding Source of the work from the predecessor in interest, if
-the predecessor has it or can get it with reasonable efforts.
-
- You may not impose any further restrictions on the exercise of the
-rights granted or affirmed under this License. For example, you may
-not impose a license fee, royalty, or other charge for exercise of
-rights granted under this License, and you may not initiate litigation
-(including a cross-claim or counterclaim in a lawsuit) alleging that
-any patent claim is infringed by making, using, selling, offering for
-sale, or importing the Program or any portion of it.
-
- 11. Patents.
-
- A "contributor" is a copyright holder who authorizes use under this
-License of the Program or a work on which the Program is based. The
-work thus licensed is called the contributor's "contributor version".
-
- A contributor's "essential patent claims" are all patent claims
-owned or controlled by the contributor, whether already acquired or
-hereafter acquired, that would be infringed by some manner, permitted
-by this License, of making, using, or selling its contributor version,
-but do not include claims that would be infringed only as a
-consequence of further modification of the contributor version. For
-purposes of this definition, "control" includes the right to grant
-patent sublicenses in a manner consistent with the requirements of
-this License.
-
- Each contributor grants you a non-exclusive, worldwide, royalty-free
-patent license under the contributor's essential patent claims, to
-make, use, sell, offer for sale, import and otherwise run, modify and
-propagate the contents of its contributor version.
-
- In the following three paragraphs, a "patent license" is any express
-agreement or commitment, however denominated, not to enforce a patent
-(such as an express permission to practice a patent or covenant not to
-sue for patent infringement). To "grant" such a patent license to a
-party means to make such an agreement or commitment not to enforce a
-patent against the party.
-
- If you convey a covered work, knowingly relying on a patent license,
-and the Corresponding Source of the work is not available for anyone
-to copy, free of charge and under the terms of this License, through a
-publicly available network server or other readily accessible means,
-then you must either (1) cause the Corresponding Source to be so
-available, or (2) arrange to deprive yourself of the benefit of the
-patent license for this particular work, or (3) arrange, in a manner
-consistent with the requirements of this License, to extend the patent
-license to downstream recipients. "Knowingly relying" means you have
-actual knowledge that, but for the patent license, your conveying the
-covered work in a country, or your recipient's use of the covered work
-in a country, would infringe one or more identifiable patents in that
-country that you have reason to believe are valid.
-
- If, pursuant to or in connection with a single transaction or
-arrangement, you convey, or propagate by procuring conveyance of, a
-covered work, and grant a patent license to some of the parties
-receiving the covered work authorizing them to use, propagate, modify
-or convey a specific copy of the covered work, then the patent license
-you grant is automatically extended to all recipients of the covered
-work and works based on it.
-
- A patent license is "discriminatory" if it does not include within
-the scope of its coverage, prohibits the exercise of, or is
-conditioned on the non-exercise of one or more of the rights that are
-specifically granted under this License. You may not convey a covered
-work if you are a party to an arrangement with a third party that is
-in the business of distributing software, under which you make payment
-to the third party based on the extent of your activity of conveying
-the work, and under which the third party grants, to any of the
-parties who would receive the covered work from you, a discriminatory
-patent license (a) in connection with copies of the covered work
-conveyed by you (or copies made from those copies), or (b) primarily
-for and in connection with specific products or compilations that
-contain the covered work, unless you entered into that arrangement,
-or that patent license was granted, prior to 28 March 2007.
-
- Nothing in this License shall be construed as excluding or limiting
-any implied license or other defenses to infringement that may
-otherwise be available to you under applicable patent law.
-
- 12. No Surrender of Others' Freedom.
-
- If conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot convey a
-covered work so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you may
-not convey it at all. For example, if you agree to terms that obligate you
-to collect a royalty for further conveying from those to whom you convey
-the Program, the only way you could satisfy both those terms and this
-License would be to refrain entirely from conveying the Program.
-
- 13. Use with the GNU Affero General Public License.
-
- Notwithstanding any other provision of this License, you have
-permission to link or combine any covered work with a work licensed
-under version 3 of the GNU Affero General Public License into a single
-combined work, and to convey the resulting work. The terms of this
-License will continue to apply to the part which is the covered work,
-but the special requirements of the GNU Affero General Public License,
-section 13, concerning interaction through a network will apply to the
-combination as such.
-
- 14. Revised Versions of this License.
-
- The Free Software Foundation may publish revised and/or new versions of
-the GNU General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
- Each version is given a distinguishing version number. If the
-Program specifies that a certain numbered version of the GNU General
-Public License "or any later version" applies to it, you have the
-option of following the terms and conditions either of that numbered
-version or of any later version published by the Free Software
-Foundation. If the Program does not specify a version number of the
-GNU General Public License, you may choose any version ever published
-by the Free Software Foundation.
-
- If the Program specifies that a proxy can decide which future
-versions of the GNU General Public License can be used, that proxy's
-public statement of acceptance of a version permanently authorizes you
-to choose that version for the Program.
-
- Later license versions may give you additional or different
-permissions. However, no additional obligations are imposed on any
-author or copyright holder as a result of your choosing to follow a
-later version.
-
- 15. Disclaimer of Warranty.
-
- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
-APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
-HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
-OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
-IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
-ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
- 16. Limitation of Liability.
-
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
-THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
-GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
-USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
-DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
-PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
-EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGES.
-
- 17. Interpretation of Sections 15 and 16.
-
- If the disclaimer of warranty and limitation of liability provided
-above cannot be given local legal effect according to their terms,
-reviewing courts shall apply local law that most closely approximates
-an absolute waiver of all civil liability in connection with the
-Program, unless a warranty or assumption of liability accompanies a
-copy of the Program in return for a fee.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-state the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-Also add information on how to contact you by electronic and paper mail.
-
- If the program does terminal interaction, make it output a short
-notice like this when it starts in an interactive mode:
-
- <program> Copyright (C) <year> <name of author>
- This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, your program's commands
-might be different; for a GUI interface, you would use an "about box".
-
- You should also get your employer (if you work as a programmer) or school,
-if any, to sign a "copyright disclaimer" for the program, if necessary.
-For more information on this, and how to apply and follow the GNU GPL, see
-<https://www.gnu.org/licenses/>.
-
- The GNU General Public License does not permit incorporating your program
-into proprietary programs. If your program is a subroutine library, you
-may consider it more useful to permit linking proprietary applications with
-the library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License. But first, please read
-<https://www.gnu.org/licenses/why-not-lgpl.html>.
diff --git a/ansible_collections/community/skydive/MANIFEST.json b/ansible_collections/community/skydive/MANIFEST.json
deleted file mode 100644
index b2a558cab..000000000
--- a/ansible_collections/community/skydive/MANIFEST.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "collection_info": {
- "description": "Collection allowing to create nodes, edges and captures in Skydive",
- "repository": "https://github.com/ansible-collections/skydive",
- "tags": [
- "skydive",
- "monitoring",
- "network"
- ],
- "dependencies": {},
- "authors": [
- "Sumit Jaiswal (@sjaiswal)"
- ],
- "issues": "https://github.com/ansible-collections/skydive/issues",
- "name": "skydive",
- "license": [],
- "documentation": null,
- "namespace": "community",
- "version": "1.0.0",
- "readme": "README.md",
- "license_file": "LICENSE",
- "homepage": "https://github.com/ansible-collections/skydive"
- },
- "file_manifest_file": {
- "format": 1,
- "ftype": "file",
- "chksum_sha256": "bdd31aafa321b782d131afb9dabfb6d2e832283c628f004e45fddacb28dd501c",
- "name": "FILES.json",
- "chksum_type": "sha256"
- },
- "format": 1
-} \ No newline at end of file
diff --git a/ansible_collections/community/skydive/README.md b/ansible_collections/community/skydive/README.md
deleted file mode 100644
index 7f697ac77..000000000
--- a/ansible_collections/community/skydive/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# Skydive Ansible Collection
-
-Ansible Collection for the [Skydive](http://skydive.network) network / protocols analyzer.
diff --git a/ansible_collections/community/skydive/bindep.txt b/ansible_collections/community/skydive/bindep.txt
deleted file mode 100644
index ba9c980fb..000000000
--- a/ansible_collections/community/skydive/bindep.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-# This is a cross-platform list tracking distribution packages needed by tests;
-# see https://docs.openstack.org/infra/bindep/ for additional information.
-
-gcc-c++ [doc test platform:rpm]
-python3-devel [test platform:rpm]
-python3 [test platform:rpm]
diff --git a/ansible_collections/community/skydive/changelogs/changelog.yaml b/ansible_collections/community/skydive/changelogs/changelog.yaml
deleted file mode 100644
index ae02485cd..000000000
--- a/ansible_collections/community/skydive/changelogs/changelog.yaml
+++ /dev/null
@@ -1,12 +0,0 @@
-ancestor: null
-releases:
- 1.0.0:
- changes:
- release_summary: '| Release Date: 2020-08-18
-
- | Adapt to Ansible 2.10 collections
-
- '
- fragments:
- - v1.0.0_summary.yaml
- release_date: '2020-08-18'
diff --git a/ansible_collections/community/skydive/meta/runtime.yml b/ansible_collections/community/skydive/meta/runtime.yml
deleted file mode 100644
index 2ee3c9fa9..000000000
--- a/ansible_collections/community/skydive/meta/runtime.yml
+++ /dev/null
@@ -1,2 +0,0 @@
----
-requires_ansible: '>=2.9.10'
diff --git a/ansible_collections/community/skydive/plugins/doc_fragments/__init__.py b/ansible_collections/community/skydive/plugins/doc_fragments/__init__.py
deleted file mode 100644
index e69de29bb..000000000
--- a/ansible_collections/community/skydive/plugins/doc_fragments/__init__.py
+++ /dev/null
diff --git a/ansible_collections/community/skydive/plugins/doc_fragments/skydive.py b/ansible_collections/community/skydive/plugins/doc_fragments/skydive.py
deleted file mode 100644
index 08c2e17b7..000000000
--- a/ansible_collections/community/skydive/plugins/doc_fragments/skydive.py
+++ /dev/null
@@ -1,55 +0,0 @@
-#
-# (c) 2019, Sumit Jaiswal (@sjaiswal)
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-
-
-class ModuleDocFragment(object):
-
- # Standard files documentation fragment
- DOCUMENTATION = """options:
- provider:
- description:
- - A dict object containing connection details.
- suboptions:
- endpoint:
- description:
- - Specifies the hostname/address along with the port as C(localhost:8082)for
- connecting to the remote instance of SKYDIVE client over the REST API.
- required: true
- user:
- description:
- - Configures the username to use to authenticate the connection to the remote
- instance of SKYDIVE client.
- password:
- description:
- - Specifies the password to use to authenticate the connection to the remote
- instance of SKYDIVE client.
- insecure:
- description:
- - Ignore SSL certification verification.
- type: bool
- default: false
- ssl:
- description:
- - Specifies the ssl parameter that decides if the connection type shall be
- http or https.
- type: bool
- default: false
-notes:
-- 'This module must be run locally, which can be achieved by specifying C(connection:
- local).'
-"""
diff --git a/ansible_collections/community/skydive/plugins/lookup/__init__.py b/ansible_collections/community/skydive/plugins/lookup/__init__.py
deleted file mode 100644
index e69de29bb..000000000
--- a/ansible_collections/community/skydive/plugins/lookup/__init__.py
+++ /dev/null
diff --git a/ansible_collections/community/skydive/plugins/lookup/skydive.py b/ansible_collections/community/skydive/plugins/lookup/skydive.py
deleted file mode 100644
index bd85fc72e..000000000
--- a/ansible_collections/community/skydive/plugins/lookup/skydive.py
+++ /dev/null
@@ -1,79 +0,0 @@
-#
-# Copyright 2018 Red Hat | Ansible
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-
-from __future__ import absolute_import, division, print_function
-
-__metaclass__ = type
-
-DOCUMENTATION = r"""
-lookup: skydive
-short_description: Query Skydive objects
-description:
-- Uses the Skydive python REST client to return the queried object from Skydive network
- analyzer.
-requirements:
-- skydive-client
-extends_documentation_fragment:
-- community.skydive.skydive
-options:
- filter:
- description: a dict object that is used to filter the return objects
-"""
-
-EXAMPLES = r"""
-- name: return skydive metdata if present based on Name
- set_fact:
- skydive_meta: >-
- {{ lookup('community.skydive.skydive', filter={'query': "G.V().Has('Name', 'sumit-VirtualBox')"}) }}
-
-- name: return all the skydive metdata having parameter Name
- set_fact:
- skydive: >-
- {{ lookup('community.skydive.skydive', filter={'query': "G.V().Has('Name')"},
- provider={'endpoint': 'localhost:8082', 'username': 'admin', 'password': 'password'}) }}
-"""
-
-RETURN = r"""
-_list:
- description:
- - The list of queried object metadata
- returned: always
- type: list
-"""
-
-
-from ansible.plugins.lookup import LookupBase
-from ansible_collections.community.skydive.plugins.module_utils.network.skydive.api import (
- skydive_lookup,
-)
-from ansible.module_utils._text import to_text
-from ansible.errors import AnsibleError
-
-
-class LookupModule(LookupBase):
- def run(self, terms, variables=None, **kwargs):
-
- provider = kwargs.pop("provider", {})
- filter_data = kwargs.pop("filter", {})
- try:
- skydive_obj = skydive_lookup(provider)
- result = skydive_obj.lookup_query(filter_data)
- except Exception as exc:
- raise AnsibleError(to_text(exc))
-
- return [result]
diff --git a/ansible_collections/community/skydive/plugins/module_utils/__init__.py b/ansible_collections/community/skydive/plugins/module_utils/__init__.py
deleted file mode 100644
index e69de29bb..000000000
--- a/ansible_collections/community/skydive/plugins/module_utils/__init__.py
+++ /dev/null
diff --git a/ansible_collections/community/skydive/plugins/module_utils/network/skydive/__init__.py b/ansible_collections/community/skydive/plugins/module_utils/network/skydive/__init__.py
deleted file mode 100644
index e69de29bb..000000000
--- a/ansible_collections/community/skydive/plugins/module_utils/network/skydive/__init__.py
+++ /dev/null
diff --git a/ansible_collections/community/skydive/plugins/module_utils/network/skydive/api.py b/ansible_collections/community/skydive/plugins/module_utils/network/skydive/api.py
deleted file mode 100644
index 06a6f5f53..000000000
--- a/ansible_collections/community/skydive/plugins/module_utils/network/skydive/api.py
+++ /dev/null
@@ -1,465 +0,0 @@
-# This code is part of Ansible, but is an independent component.
-# This particular file snippet, and this file snippet only, is BSD licensed.
-# Modules you write using this snippet, which is embedded dynamically by Ansible
-# still belong to the author of the module, and may assign their own license
-# to the complete work.
-#
-# (c) 2019 Red Hat Inc.
-#
-# Redistribution and use in source and binary forms, with or without modification,
-# are permitted provided that the following conditions are met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-
-import os
-import uuid
-
-from ansible.module_utils.six import iteritems
-from ansible.module_utils.six import iterkeys
-from ansible.module_utils._text import to_text
-from ansible.module_utils.basic import env_fallback
-
-try:
- from skydive.graph import Node, Edge
- from skydive.rest.client import RESTClient
- from skydive.websocket.client import (
- NodeAddedMsgType,
- NodeUpdatedMsgType,
- NodeDeletedMsgType,
- )
- from skydive.websocket.client import (
- EdgeAddedMsgType,
- EdgeUpdatedMsgType,
- EdgeDeletedMsgType,
- )
- from skydive.websocket.client import (
- WSClient,
- WSClientDefaultProtocol,
- WSMessage,
- )
-
- HAS_SKYDIVE_CLIENT = True
-except ImportError:
- HAS_SKYDIVE_CLIENT = False
-
-# defining skydive constants
-SKYDIVE_GREMLIN_QUERY = "G.V().Has"
-SKYDIVE_GREMLIN_EDGE_QUERY = "G.E().Has"
-
-SKYDIVE_PROVIDER_SPEC = {
- "endpoint": dict(fallback=(env_fallback, ["SKYDIVE_ENDPOINT"])),
- "username": dict(fallback=(env_fallback, ["SKYDIVE_USERNAME"])),
- "password": dict(
- fallback=(env_fallback, ["SKYDIVE_PASSWORD"]), no_log=True
- ),
- "insecure": dict(
- type="bool",
- default=False,
- fallback=(env_fallback, ["SKYDIVE_INSECURE"]),
- ),
- "ssl": dict(
- type="bool", default=False, fallback=(env_fallback, ["SKYDIVE_SSL"])
- ),
-}
-
-
-class skydive_client_check(object):
- """ Base class for implementing Skydive Rest API """
-
- provider_spec = {
- "provider": dict(type="dict", options=SKYDIVE_PROVIDER_SPEC)
- }
-
- def __init__(self, **kwargs):
- """ Base class for implementing Skydive Rest API """
- if not HAS_SKYDIVE_CLIENT:
- raise Exception(
- "skydive-client is required but does not appear "
- "to be installed. It can be installed using the "
- "command `pip install skydive-client`"
- )
-
- if not set(kwargs.keys()).issubset(SKYDIVE_PROVIDER_SPEC.keys()):
- raise Exception(
- "invalid or unsupported keyword argument for skydive_restclient connection."
- )
- for key, value in iteritems(SKYDIVE_PROVIDER_SPEC):
- if key not in kwargs:
- # apply default values from SKYDIVE_PROVIDER_SPEC since we cannot just
- # assume the provider values are coming from AnsibleModule
- if "default" in value:
- kwargs[key] = value["default"]
- # override any values with env variables unless they were
- # explicitly set
- env = ("SKYDIVE_%s" % key).upper()
- if env in os.environ:
- kwargs[key] = os.environ.get(env)
-
-
-class skydive_inject_protocol(object):
- """ Implements inject protocol for node and edge modules """
-
- def onOpen(self):
- module = self.factory.kwargs["module"]
- params = self.factory.kwargs["params"]
- result = self.factory.kwargs["result"]
- if "node1" and "node2" in self.factory.kwargs:
- node1 = self.factory.kwargs["node1"]
- node2 = self.factory.kwargs["node2"]
-
- if module.check_mode:
- self.stop()
- return
- try:
- host = params["host"]
- if params["metadata"]:
- metadata = module._check_type_dict(params["metadata"])
- else:
- metadata = {}
- if "node_type" in params:
- metadata["Name"] = params["name"]
- metadata["Type"] = params["node_type"]
- seed = params["seed"]
- if not seed:
- seed = "%s:%s" % (params["name"], params["node_type"])
- if (
- module.params["state"] == "present"
- or module.params["state"] == "update"
- ):
- uid = str(uuid.uuid5(uuid.NAMESPACE_OID, seed))
- node = Node(uid, host, metadata=metadata)
- if module.params["state"] == "present":
- msg = WSMessage("Graph", NodeAddedMsgType, node)
- else:
- msg = WSMessage("Graph", NodeUpdatedMsgType, node)
- else:
- uid = params["id"]
- node = Node(uid, host, metadata=metadata)
- msg = WSMessage("Graph", NodeDeletedMsgType, node)
- elif "relation_type" in params:
- metadata["RelationType"] = params["relation_type"]
- if (
- module.params["state"] == "present"
- or module.params["state"] == "update"
- ):
- uid = str(
- uuid.uuid5(
- uuid.NAMESPACE_OID,
- "%s:%s:%s"
- % (node1, node2, params["relation_type"]),
- )
- )
- edge = Edge(uid, host, node1, node2, metadata=metadata)
- if module.params["state"] == "present":
- msg = WSMessage("Graph", EdgeAddedMsgType, edge)
- else:
- msg = WSMessage("Graph", EdgeUpdatedMsgType, edge)
- else:
- uid = module.params["id"]
- edge = Edge(uid, host, node1, node2, metadata=metadata)
- msg = WSMessage("Graph", EdgeDeletedMsgType, edge)
-
- self.sendWSMessage(msg)
- if uid:
- result["UUID"] = uid
- result["changed"] = True
- except Exception as e:
- module.fail_json(
- msg="Error during topology update %s" % e, **result
- )
- finally:
- self.stop_when_complete()
-
-
-class skydive_wsclient(skydive_client_check):
- """ Base class for implementing Skydive Websocket API """
-
- def __init__(self, module, **kwargs):
- super(skydive_wsclient, self).__init__(**kwargs)
-
- class skydive_full_inject_protocol(
- skydive_inject_protocol, WSClientDefaultProtocol
- ):
- pass
-
- kwargs["scheme"] = "ws"
- if "ssl" in kwargs:
- if kwargs["ssl"]:
- kwargs["scheme"] = "wss"
- if "insecure" not in kwargs:
- kwargs["insecure"] = False
- scheme = kwargs["scheme"]
- self.result = dict(changed=False)
- if "node_type" in module.params:
- self.wsclient_object = WSClient(
- "ansible-" + str(os.getpid()) + "-" + module.params["host"],
- "%s://%s/ws/publisher" % (scheme, kwargs["endpoint"]),
- protocol=type(
- "skydive_full_inject_protocol",
- (skydive_inject_protocol, WSClientDefaultProtocol),
- dict(),
- ),
- persistent=True,
- insecure=kwargs["insecure"],
- username=kwargs["username"],
- password=kwargs["password"],
- module=module,
- params=module.params,
- result=self.result,
- )
- elif "relation_type" in module.params:
- self.parent_node = self.get_node_id(module.params["parent_node"])
- self.child_node = self.get_node_id(module.params["child_node"])
-
- self.wsclient_object = WSClient(
- "ansible-" + str(os.getpid()) + "-" + module.params["host"],
- "%s://%s/ws/publisher" % (scheme, kwargs["endpoint"]),
- protocol=type(
- "skydive_full_inject_protocol",
- (skydive_inject_protocol, WSClientDefaultProtocol),
- dict(),
- ),
- persistent=True,
- insecure=kwargs["insecure"],
- username=kwargs["username"],
- password=kwargs["password"],
- module=module,
- params=module.params,
- node1=self.parent_node,
- node2=self.child_node,
- result=self.result,
- )
-
- def get_node_id(self, node_selector):
- """ Checks if Gremlin expresssion is passed as input to get the nodes UUID """
- if node_selector.startswith("G.") or node_selector.startswith("g."):
- nodes = self.restclient_object.lookup_nodes(node_selector)
- if len(nodes) == 0:
- raise self.module.fail_json(
- msg=to_text("Node not found: {0}".format(node_selector))
- )
- elif len(nodes) > 1:
- raise self.module.fail_json(
- msg=to_text(
- "Node selection should return only one node: {0}".format(
- node_selector
- )
- )
- )
- return str(nodes[0].id)
- return node_selector
-
-
-class skydive_restclient(skydive_client_check):
- """ Base class for implementing Skydive Rest API """
-
- def __init__(self, **kwargs):
- super(skydive_restclient, self).__init__(**kwargs)
- kwargs["scheme"] = "http"
- if "ssl" in kwargs:
- if kwargs["ssl"]:
- kwargs["scheme"] = "https"
- if "insecure" not in kwargs:
- kwargs["insecure"] = False
- self.restclient_object = RESTClient(
- kwargs["endpoint"],
- scheme=kwargs["scheme"],
- insecure=kwargs["insecure"],
- username=kwargs["username"],
- password=kwargs["password"],
- )
-
-
-class skydive_lookup(skydive_restclient):
- """ Implements Skydive Lookup queries """
-
- provider_spec = {
- "provider": dict(type="dict", options=SKYDIVE_PROVIDER_SPEC)
- }
-
- def __init__(self, provider):
- super(skydive_lookup, self).__init__(**provider)
- self.query_str = ""
-
- def lookup_query(self, filter_data):
- query_key = filter_data.keys()[0]
- self.query_str = filter_data[query_key]
- nodes = self.restclient_object.lookup_nodes(self.query_str)
- result = []
- for each in nodes:
- result.append(each.__dict__)
- if len(result) == 0:
- raise Exception(
- "Cannot find any entry for the input Gremlin query!"
- )
- return result
-
-
-class skydive_flow_capture(skydive_restclient):
- """ Implements Skydive Flow capture modules """
-
- def __init__(self, module):
- self.module = module
- provider = module.params["provider"]
-
- super(skydive_flow_capture, self).__init__(**provider)
-
- def run(self, ib_spec):
- state = self.module.params["state"]
- if state not in ("present", "absent"):
- self.module.fail_json(
- msg="state must be one of `present`, `absent`, got `%s`"
- % state
- )
-
- result = {"changed": False}
- obj_filter = dict(
- [
- (k, self.module.params[k])
- for k, v in iteritems(ib_spec)
- if v.get("ib_req")
- ]
- )
-
- proposed_object = {}
- for key in iterkeys(ib_spec):
- if self.module.params[key] is not None:
- proposed_object[key] = self.module.params[key]
-
- if obj_filter["query"]:
- cature_query = obj_filter["query"]
- elif obj_filter["interface_name"] and obj_filter["type"]:
- cature_query = (
- SKYDIVE_GREMLIN_QUERY
- + "('Name', '{0}', 'Type', '{1}')".format(
- obj_filter["interface_name"], obj_filter["type"]
- )
- )
- else:
- raise self.module.fail_json(
- msg="Interface name and Type is required if gremlin query is not defined!"
- )
-
- # to check current object ref for idempotency
- captured_list_objs = self.restclient_object.capture_list()
- current_ref_uuid = None
- for each_capture in captured_list_objs:
- if cature_query == each_capture.__dict__["query"]:
- current_ref_uuid = each_capture.__dict__["uuid"]
- break
- if state == "present":
- if not current_ref_uuid:
- try:
- self.restclient_object.capture_create(
- cature_query,
- obj_filter["capture_name"],
- obj_filter["description"],
- obj_filter["extra_tcp_metric"],
- obj_filter["ip_defrag"],
- obj_filter["reassemble_tcp"],
- obj_filter["layer_key_mode"],
- )
- except Exception as e:
- self.module.fail_json(msg=to_text(e))
- result["changed"] = True
- if state == "absent":
- if current_ref_uuid:
- try:
- self.restclient_object.capture_delete(current_ref_uuid)
- except Exception as e:
- self.module.fail_json(msg=to_text(e))
- result["changed"] = True
-
- return result
-
-
-class skydive_node(skydive_wsclient, skydive_restclient):
- """ Implements Skydive Node modules """
-
- def __init__(self, module):
- self.module = module
- provider = module.params["provider"]
- super(skydive_node, self).__init__(self.module, **provider)
-
- def run(self):
- try:
- lookup_query = (
- SKYDIVE_GREMLIN_QUERY
- + "('Name', '{0}', 'Type', '{1}')".format(
- self.module.params["name"], self.module.params["node_type"]
- )
- )
- node_exists = self.restclient_object.lookup_nodes(lookup_query)
-
- if not node_exists and self.module.params["state"] == "present":
- self.wsclient_object.connect()
- self.wsclient_object.start()
- elif (
- len(node_exists) > 0
- and self.module.params["state"] == "update"
- ):
- self.wsclient_object.connect()
- self.wsclient_object.start()
- elif (
- len(node_exists) > 0
- and self.module.params["state"] == "absent"
- ):
- self.module.params["id"] = node_exists[0].__dict__["id"]
- self.wsclient_object.connect()
- self.wsclient_object.start()
- except Exception as e:
- self.module.fail_json(msg=to_text(e))
- return self.result
-
-
-class skydive_edge(skydive_wsclient, skydive_restclient):
- """ Implements Skydive Edge modules """
-
- def __init__(self, module):
- self.module = module
- provider = module.params["provider"]
-
- super(skydive_edge, self).__init__(self.module, **provider)
-
- def run(self):
- try:
- edge_exists = False
- edge_query = (
- SKYDIVE_GREMLIN_EDGE_QUERY
- + "('Parent', '{0}', 'Child', '{1}')".format(
- self.parent_node, self.child_node
- )
- )
- query_result = self.restclient_object.lookup_edges(edge_query)
- if query_result:
- query_result = query_result[0].__dict__
- edge_exists = True
-
- if not edge_exists and self.module.params["state"] == "present":
- self.wsclient_object.connect()
- self.wsclient_object.start()
- elif edge_exists and self.module.params["state"] == "update":
- self.wsclient_object.connect()
- self.wsclient_object.start()
- elif edge_exists and self.module.params["state"] == "absent":
- self.module.params["id"] = query_result["id"]
- self.wsclient_object.connect()
- self.wsclient_object.start()
- except Exception as e:
- self.module.fail_json(msg=to_text(e))
- return self.result
diff --git a/ansible_collections/community/skydive/plugins/modules/__init__.py b/ansible_collections/community/skydive/plugins/modules/__init__.py
deleted file mode 100644
index e69de29bb..000000000
--- a/ansible_collections/community/skydive/plugins/modules/__init__.py
+++ /dev/null
diff --git a/ansible_collections/community/skydive/plugins/modules/skydive_capture.py b/ansible_collections/community/skydive/plugins/modules/skydive_capture.py
deleted file mode 100644
index f884a0cfa..000000000
--- a/ansible_collections/community/skydive/plugins/modules/skydive_capture.py
+++ /dev/null
@@ -1,189 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# (c) 2019, Ansible by Red Hat, inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {
- "metadata_version": "1.1",
- "status": ["preview"],
- "supported_by": "network",
-}
-
-DOCUMENTATION = r"""
----
-module: skydive_capture
-author:
-- Sumit Jaiswal (@sjaiswal)
-short_description: Module which manages flow capture on interfaces
-description:
-- This module manages flow capture on interfaces. The Gremlin expression is continuously
- evaluated which means that it is possible to define a capture on nodes that do not
- exist yet.
-- It is useful when you want to start a capture on all OpenvSwitch whatever the number
- of Skydive agents you will start.
-- While starting the capture, user can specify the capture name, capture description
- and capture type optionally.
-requirements:
-- skydive-client
-extends_documentation_fragment:
-- community.skydive.skydive
-options:
- query:
- description:
- - It's the complete gremlin query which the users can input, I(G.V().Has('Name',
- 'eth0', 'Type', 'device')), to create the capture. And, if the user directly
- inputs the gremlin query then user is not required to input any other module
- parameter as gremlin query takes care of creating the flow capture.
- required: false
- interface_name:
- description:
- - To define flow capture interface name.
- required: false
- type:
- description:
- - To define flow capture interface type.
- required: false
- capture_name:
- description:
- - To define flow capture name.
- required: false
- default: ''
- description:
- description:
- - Configures a text string to be associated with the instance of this object.
- default: ''
- extra_tcp_metric:
- description:
- - To define flow capture ExtraTCPMetric.
- type: bool
- default: false
- ip_defrag:
- description:
- - To define flow capture IPDefrag.
- type: bool
- default: false
- reassemble_tcp:
- description:
- - To define flow capture ReassembleTCP.
- type: bool
- default: false
- layer_key_mode:
- description:
- - To define flow capture Layer KeyMode.
- type: str
- default: L2
- state:
- description:
- - State of the flow capture. If value is I(present) flow capture will be created
- else if it is I(absent) it will be deleted.
- default: present
- choices:
- - present
- - absent
-"""
-
-EXAMPLES = r"""
-- name: start a new flow capture directly from gremlin query
- community.skydive.skydive_capture:
- query: G.V().Has('Name', 'eth0', 'Type', 'device')
- state: present
- provider:
- endpoint: localhost:8082
- username: admin
- password: admin
-
-- name: stop the flow capture directly from gremlin query
- community.skydive.skydive_capture:
- query: G.V().Has('Name', 'eth0', 'Type', 'device')
- state: absent
- provider:
- endpoint: localhost:8082
- username: admin
- password: admin
-
-- name: start a new flow capture from user's input
- community.skydive.skydive_capture:
- interface_name: Node1
- type: myhost
- capture_name: test_capture
- description: test description
- extra_tcp_metric: true
- ip_defrag: true
- reassemble_tcp: true
- state: present
- provider:
- endpoint: localhost:8082
- username: admin
- password: admin
-
-- name: stop the flow capture
- community.skydive.skydive_capture:
- interface_name: Node1
- type: myhost
- capture_name: test_capture
- description: test description
- extra_tcp_metric: true
- ip_defrag: true
- reassemble_tcp: true
- state: absent
- provider:
- endpoint: localhost:8082
- username: admin
- password: admin
-"""
-
-RETURN = r""" # """
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible_collections.community.skydive.plugins.module_utils.network.skydive.api import (
- skydive_flow_capture,
-)
-
-
-def main():
- """ Main entry point for module execution
- """
- ib_spec = dict(
- query=dict(required=False, ib_req=True),
- interface_name=dict(required=False, ib_req=True),
- type=dict(required=False, ib_req=True),
- capture_name=dict(required=False, default="", ib_req=True),
- description=dict(default="", ib_req=True),
- extra_tcp_metric=dict(
- type="bool", required=False, ib_req=True, default=False
- ),
- ip_defrag=dict(
- type="bool", required=False, ib_req=True, default=False
- ),
- reassemble_tcp=dict(
- type="bool", required=False, ib_req=True, default=False
- ),
- layer_key_mode=dict(required=False, ib_req=True, default="L2"),
- )
-
- argument_spec = dict(
- provider=dict(required=False),
- state=dict(default="present", choices=["present", "absent"]),
- )
-
- argument_spec.update(ib_spec)
- argument_spec.update(skydive_flow_capture.provider_spec)
-
- module = AnsibleModule(
- argument_spec=argument_spec, supports_check_mode=True
- )
-
- skydive_obj = skydive_flow_capture(module)
- result = skydive_obj.run(ib_spec)
-
- module.exit_json(**result)
-
-
-if __name__ == "__main__":
- main()
diff --git a/ansible_collections/community/skydive/plugins/modules/skydive_edge.py b/ansible_collections/community/skydive/plugins/modules/skydive_edge.py
deleted file mode 100644
index 88c3c1c41..000000000
--- a/ansible_collections/community/skydive/plugins/modules/skydive_edge.py
+++ /dev/null
@@ -1,202 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# (c) 2019, Ansible by Red Hat, inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {
- "metadata_version": "1.1",
- "status": ["preview"],
- "supported_by": "network",
-}
-
-DOCUMENTATION = r"""
-module: skydive_edge
-author:
-- Sumit Jaiswal (@sjaiswal)
-short_description: Module to add edges to Skydive topology
-description:
-- This module handles setting up edges between two nodes based on the relationship
- type to the Skydive topology.
-requirements:
-- skydive-client
-extends_documentation_fragment:
-- community.skydive.skydive
-options:
- parent_node:
- description:
- - To defined the first node of the link, it can be either an ID or a gremlin expression
- required: true
- child_node:
- description:
- - To defined the second node of the link, it can be either an ID or a gremlin
- expression
- required: true
- relation_type:
- description:
- - To define relation type of the node I(ownership, layer2, layer3).
- required: true
- host:
- description:
- - To define the host of the node.
- default: ''
- required: false
- metadata:
- description:
- - To define metadata for the edge.
- required: false
- state:
- description:
- - State of the Skydive Edge. If value is I(present) new edge will be created else
- if it is I(absent) it will be deleted.
- default: present
- choices:
- - present
- - absent
-"""
-
-EXAMPLES = r"""
-- name: create tor
- community.skydive.skydive_node:
- name: 'TOR'
- node_type: "fabric"
- seed: TOR
- metadata:
- Model: Cisco xxxx
- provider:
- endpoint: localhost:8082
- username: admin
- password: admin
- register: tor_result
-
-- name: create port 1
- community.skydive.skydive_node:
- name: 'PORT1'
- node_type: 'fabric'
- seed: PORT1
- provider:
- endpoint: localhost:8082
- username: admin
- password: admin
- register: port1_result
-
-- name: create port 2
- community.skydive.skydive_node:
- name: 'PORT2'
- node_type: 'fabric'
- seed: PORT2
- provider:
- endpoint: localhost:8082
- username: admin
- password: admin
- register: port2_result
-
-- name: link node tor and port 1
- community.skydive.skydive_edge:
- parent_node: "{{ tor_result.UUID }}"
- child_node: "{{ port1_result.UUID }}"
- relation_type: ownership
- state: present
- provider:
- endpoint: localhost:8082
- username: admin
- password: admin
-
-- name: link node tor and port 2
- community.skydive.skydive_edge:
- parent_node: "{{ tor_result.UUID }}"
- child_node: "{{ port2_result.UUID }}"
- relation_type: ownership
- state: present
- provider:
- endpoint: localhost:8082
- username: admin
- password: admin
-
-- name: update link node tor and port 1 relation
- community.skydive.skydive_edge:
- parent_node: "{{ tor_result.UUID }}"
- child_node: "{{ port2_result.UUID }}"
- relation_type: layer2
- state: upadte
- provider:
- endpoint: localhost:8082
- username: admin
- password: admin
-
-- name: Unlink tor and port 2
- community.skydive.skydive_edge:
- parent_node: "{{ tor_result.UUID }}"
- child_node: "{{ port2_result.UUID }}"
- relation_type: ownership
- state: absent
- provider:
- endpoint: localhost:8082
- username: admin
- password: admin
-
-- name: link tor and port 2 via Gremlin expression
- community.skydive.skydive_edge:
- parent_node: G.V().Has('Name', 'TOR')
- child_node: G.V().Has('Name', 'PORT2')
- relation_type: ownership
- state: present
- provider:
- endpoint: localhost:8082
- username: admin
- password: admin
-
-- name: Unlink tor and port 2 via Gremlin expression
- community.skydive.skydive_edge:
- parent_node: G.V().Has('Name', 'TOR')
- child_node: G.V().Has('Name', 'PORT2')
- relation_type: ownership
- state: absent
- provider:
- endpoint: localhost:8082
- username: admin
- password: admin
-"""
-
-RETURN = r""" # """
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible_collections.community.skydive.plugins.module_utils.network.skydive.api import (
- skydive_edge,
-)
-
-
-def main():
- """ Main entry point for module execution
- """
- ib_spec = dict(
- relation_type=dict(type="str", required=True),
- parent_node=dict(type="str", required=True),
- child_node=dict(type="str", required=True),
- host=dict(type="str", default=""),
- metadata=dict(type="dict", default=dict()),
- )
-
- argument_spec = dict(
- provider=dict(required=False),
- state=dict(default="present", choices=["present", "absent"]),
- )
-
- argument_spec.update(ib_spec)
- argument_spec.update(skydive_edge.provider_spec)
- module = AnsibleModule(
- argument_spec=argument_spec, supports_check_mode=True
- )
-
- skydive_obj = skydive_edge(module)
- result = skydive_obj.run()
- module.exit_json(**result)
-
-
-if __name__ == "__main__":
- main()
diff --git a/ansible_collections/community/skydive/plugins/modules/skydive_node.py b/ansible_collections/community/skydive/plugins/modules/skydive_node.py
deleted file mode 100644
index fcfa2a221..000000000
--- a/ansible_collections/community/skydive/plugins/modules/skydive_node.py
+++ /dev/null
@@ -1,138 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# (c) 2019, Ansible by Red Hat, inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {
- "metadata_version": "1.1",
- "status": ["preview"],
- "supported_by": "network",
-}
-
-DOCUMENTATION = r"""
-module: skydive_node
-author:
-- Sumit Jaiswal (@sjaiswal)
-short_description: Module which add nodes to Skydive topology
-description:
-- This module handles adding node to the Skydive topology.
-requirements:
-- skydive-client
-extends_documentation_fragment:
-- community.skydive.skydive
-options:
- name:
- description:
- - To define name for the node.
- required: true
- node_type:
- description:
- - To define type for the node.
- required: true
- host:
- description:
- - To define host for the node.
- required: false
- seed:
- description:
- - used to generate the UUID of the node
- default: ''
- metadata:
- description:
- - To define metadata for the node.
- required: false
- state:
- description:
- - State of the Skydive Node. If value is I(present) new node will be created else
- if it is I(absent) it will be deleted.
- default: present
- choices:
- - present
- - update
- - absent
-"""
-
-EXAMPLES = r"""
-- name: create tor node
- community.skydive.skydive_node:
- name: TOR
- node_type: fabric
- seed: TOR1
- metadata:
- Model: Cisco 5300
- state: present
- provider:
- endpoint: localhost:8082
- username: admin
- password: admin
-
-- name: update tor node
- community.skydive.skydive_node:
- name: TOR
- node_type: host
- seed: TOR1
- metadata:
- Model: Cisco 3400
- state: update
- provider:
- endpoint: localhost:8082
- username: admin
- password: admin
-
-- name: Delete the tor node
- community.skydive.skydive_node:
- name: TOR
- node_type: host
- seed: TOR1
- metadata:
- Model: Cisco 3400
- state: absent
- provider:
- endpoint: localhost:8082
- username: admin
- password: admin
-"""
-
-RETURN = r""" # """
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible_collections.community.skydive.plugins.module_utils.network.skydive.api import (
- skydive_node,
-)
-
-
-def main():
- """ Main entry point for module execution
- """
- ib_spec = dict(
- name=dict(required=True, ib_req=True),
- node_type=dict(required=True, ib_req=True),
- host=dict(required=False, ib_req=True, default=""),
- seed=dict(required=False, ib_req=True, default=""),
- metadata=dict(required=False, ib_req=True, default=dict()),
- )
-
- argument_spec = dict(
- provider=dict(required=False),
- state=dict(default="present", choices=["present", "update", "absent"]),
- )
-
- argument_spec.update(ib_spec)
- argument_spec.update(skydive_node.provider_spec)
- module = AnsibleModule(
- argument_spec=argument_spec, supports_check_mode=True
- )
-
- skydive_obj = skydive_node(module)
- result = skydive_obj.run()
- module.exit_json(**result)
-
-
-if __name__ == "__main__":
- main()
diff --git a/ansible_collections/community/skydive/requirements.txt b/ansible_collections/community/skydive/requirements.txt
deleted file mode 100644
index 90d40550b..000000000
--- a/ansible_collections/community/skydive/requirements.txt
+++ /dev/null
@@ -1 +0,0 @@
-ansible
diff --git a/ansible_collections/community/skydive/test-requirements.txt b/ansible_collections/community/skydive/test-requirements.txt
deleted file mode 100644
index 238108317..000000000
--- a/ansible_collections/community/skydive/test-requirements.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-black==19.3b0
-flake8
diff --git a/ansible_collections/community/skydive/tests/.gitignore b/ansible_collections/community/skydive/tests/.gitignore
deleted file mode 100644
index ea1472ec1..000000000
--- a/ansible_collections/community/skydive/tests/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-output/
diff --git a/ansible_collections/community/skydive/tests/sanity/ignore-2.10.txt b/ansible_collections/community/skydive/tests/sanity/ignore-2.10.txt
deleted file mode 100644
index 121eab686..000000000
--- a/ansible_collections/community/skydive/tests/sanity/ignore-2.10.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-plugins/module_utils/network/skydive/api.py future-import-boilerplate
-plugins/module_utils/network/skydive/api.py metaclass-boilerplate
-plugins/modules/skydive_capture.py validate-modules:doc-missing-type
-plugins/modules/skydive_capture.py validate-modules:doc-required-mismatch
-plugins/modules/skydive_capture.py validate-modules:invalid-ansiblemodule-schema
-plugins/modules/skydive_capture.py validate-modules:nonexistent-parameter-documented
-plugins/modules/skydive_capture.py validate-modules:parameter-type-not-in-doc
-plugins/modules/skydive_capture.py validate-modules:undocumented-parameter
-plugins/modules/skydive_edge.py validate-modules:doc-missing-type
-plugins/modules/skydive_edge.py validate-modules:doc-required-mismatch
-plugins/modules/skydive_edge.py validate-modules:nonexistent-parameter-documented
-plugins/modules/skydive_edge.py validate-modules:parameter-type-not-in-doc
-plugins/modules/skydive_edge.py validate-modules:undocumented-parameter
-plugins/modules/skydive_node.py validate-modules:doc-missing-type
-plugins/modules/skydive_node.py validate-modules:doc-required-mismatch
-plugins/modules/skydive_node.py validate-modules:invalid-ansiblemodule-schema
-plugins/modules/skydive_node.py validate-modules:nonexistent-parameter-documented
-plugins/modules/skydive_node.py validate-modules:parameter-type-not-in-doc
-plugins/modules/skydive_node.py validate-modules:undocumented-parameter
-plugins/doc_fragments/skydive.py future-import-boilerplate
-plugins/doc_fragments/skydive.py metaclass-boilerplate \ No newline at end of file
diff --git a/ansible_collections/community/skydive/tests/sanity/ignore-2.11.txt b/ansible_collections/community/skydive/tests/sanity/ignore-2.11.txt
deleted file mode 100644
index 121eab686..000000000
--- a/ansible_collections/community/skydive/tests/sanity/ignore-2.11.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-plugins/module_utils/network/skydive/api.py future-import-boilerplate
-plugins/module_utils/network/skydive/api.py metaclass-boilerplate
-plugins/modules/skydive_capture.py validate-modules:doc-missing-type
-plugins/modules/skydive_capture.py validate-modules:doc-required-mismatch
-plugins/modules/skydive_capture.py validate-modules:invalid-ansiblemodule-schema
-plugins/modules/skydive_capture.py validate-modules:nonexistent-parameter-documented
-plugins/modules/skydive_capture.py validate-modules:parameter-type-not-in-doc
-plugins/modules/skydive_capture.py validate-modules:undocumented-parameter
-plugins/modules/skydive_edge.py validate-modules:doc-missing-type
-plugins/modules/skydive_edge.py validate-modules:doc-required-mismatch
-plugins/modules/skydive_edge.py validate-modules:nonexistent-parameter-documented
-plugins/modules/skydive_edge.py validate-modules:parameter-type-not-in-doc
-plugins/modules/skydive_edge.py validate-modules:undocumented-parameter
-plugins/modules/skydive_node.py validate-modules:doc-missing-type
-plugins/modules/skydive_node.py validate-modules:doc-required-mismatch
-plugins/modules/skydive_node.py validate-modules:invalid-ansiblemodule-schema
-plugins/modules/skydive_node.py validate-modules:nonexistent-parameter-documented
-plugins/modules/skydive_node.py validate-modules:parameter-type-not-in-doc
-plugins/modules/skydive_node.py validate-modules:undocumented-parameter
-plugins/doc_fragments/skydive.py future-import-boilerplate
-plugins/doc_fragments/skydive.py metaclass-boilerplate \ No newline at end of file
diff --git a/ansible_collections/community/skydive/tests/sanity/ignore-2.9.txt b/ansible_collections/community/skydive/tests/sanity/ignore-2.9.txt
deleted file mode 100644
index a3bb73edc..000000000
--- a/ansible_collections/community/skydive/tests/sanity/ignore-2.9.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-plugins/module_utils/network/skydive/api.py future-import-boilerplate
-plugins/module_utils/network/skydive/api.py metaclass-boilerplate
-plugins/modules/skydive_capture.py validate-modules:doc-missing-type
-plugins/modules/skydive_capture.py validate-modules:nonexistent-parameter-documented
-plugins/modules/skydive_capture.py validate-modules:parameter-type-not-in-doc
-plugins/modules/skydive_capture.py validate-modules:undocumented-parameter
-plugins/modules/skydive_edge.py validate-modules:doc-missing-type
-plugins/modules/skydive_edge.py validate-modules:nonexistent-parameter-documented
-plugins/modules/skydive_edge.py validate-modules:parameter-type-not-in-doc
-plugins/modules/skydive_edge.py validate-modules:undocumented-parameter
-plugins/modules/skydive_node.py validate-modules:doc-missing-type
-plugins/modules/skydive_node.py validate-modules:nonexistent-parameter-documented
-plugins/modules/skydive_node.py validate-modules:parameter-type-not-in-doc
-plugins/modules/skydive_node.py validate-modules:undocumented-parameter
-plugins/doc_fragments/skydive.py future-import-boilerplate
-plugins/doc_fragments/skydive.py metaclass-boilerplate
diff --git a/ansible_collections/community/skydive/tests/sanity/requirements.txt b/ansible_collections/community/skydive/tests/sanity/requirements.txt
deleted file mode 100644
index 3e3a96692..000000000
--- a/ansible_collections/community/skydive/tests/sanity/requirements.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-packaging # needed for update-bundled and changelog
-sphinx ; python_version >= '3.5' # docs build requires python 3+
-sphinx-notfound-page ; python_version >= '3.5' # docs build requires python 3+
-straight.plugin ; python_version >= '3.5' # needed for hacking/build-ansible.py which will host changelog generation and requires python 3+
diff --git a/ansible_collections/community/skydive/tests/unit/__init__.py b/ansible_collections/community/skydive/tests/unit/__init__.py
deleted file mode 100644
index e69de29bb..000000000
--- a/ansible_collections/community/skydive/tests/unit/__init__.py
+++ /dev/null
diff --git a/ansible_collections/community/skydive/tests/unit/requirements.txt b/ansible_collections/community/skydive/tests/unit/requirements.txt
deleted file mode 100644
index a9772bea1..000000000
--- a/ansible_collections/community/skydive/tests/unit/requirements.txt
+++ /dev/null
@@ -1,42 +0,0 @@
-boto3
-placebo
-pycrypto
-passlib
-pypsrp
-python-memcached
-pytz
-pyvmomi
-redis
-requests
-setuptools > 0.6 # pytest-xdist installed via requirements does not work with very old setuptools (sanity_ok)
-unittest2 ; python_version < '2.7'
-importlib ; python_version < '2.7'
-netaddr
-ipaddress
-netapp-lib
-solidfire-sdk-python
-
-# requirements for F5 specific modules
-f5-sdk ; python_version >= '2.7'
-f5-icontrol-rest ; python_version >= '2.7'
-deepdiff
-
-# requirement for Fortinet specific modules
-pyFMG
-
-# requirement for aci_rest module
-xmljson
-
-# requirement for winrm connection plugin tests
-pexpect
-
-# requirement for the linode module
-linode-python # APIv3
-linode_api4 ; python_version > '2.6' # APIv4
-
-# requirement for the gitlab module
-python-gitlab
-httmock
-
-# requirment for kubevirt modules
-openshift ; python_version >= '2.7'
diff --git a/ansible_collections/community/skydive/tox.ini b/ansible_collections/community/skydive/tox.ini
deleted file mode 100644
index 1aceac0a0..000000000
--- a/ansible_collections/community/skydive/tox.ini
+++ /dev/null
@@ -1,31 +0,0 @@
-[tox]
-minversion = 1.4.2
-envlist = linters
-skipsdist = True
-
-[testenv]
-deps = -r{toxinidir}/requirements.txt
- -r{toxinidir}/test-requirements.txt
-
-[testenv:black]
-install_command = pip install {opts} {packages}
-commands =
- black -v -l79 {toxinidir}
-
-[testenv:linters]
-install_command = pip install {opts} {packages}
-commands =
- black -v -l79 --check {toxinidir}
- flake8 {posargs}
-
-[testenv:venv]
-commands = {posargs}
-
-[flake8]
-# E123, E125 skipped as they are invalid PEP-8.
-
-show-source = True
-ignore = E123,E125,E402,E501,E741,W503
-max-line-length = 160
-builtins = _
-exclude = .git,.tox,tests/unit/compat/
diff --git a/ansible_collections/community/sops/.github/workflows/ansible-test.yml b/ansible_collections/community/sops/.github/workflows/ansible-test.yml
index eeec801aa..f31dfca6b 100644
--- a/ansible_collections/community/sops/.github/workflows/ansible-test.yml
+++ b/ansible_collections/community/sops/.github/workflows/ansible-test.yml
@@ -33,6 +33,7 @@ jobs:
- stable-2.13
- stable-2.14
- stable-2.15
+ - stable-2.16
- devel
# Ansible-test on various stable branches does not yet work well with cgroups v2.
# Since ubuntu-latest now uses Ubuntu 22.04, we need to fall back to the ubuntu-20.04
@@ -69,11 +70,12 @@ jobs:
docker_container:
- ubuntu2004
- ubuntu2204
- - fedora37
+ - fedora38
sops_version:
- 3.5.0
- 3.6.0
- 3.7.3
+ - 3.8.0
python_version:
- ''
include:
@@ -108,19 +110,27 @@ jobs:
- ansible: stable-2.15
docker_container: ubuntu2204
sops_version: 3.7.3
+ # 2.16
+ - ansible: stable-2.16
+ docker_container: ubuntu2204
+ sops_version: 3.8.0
+ - ansible: stable-2.16
+ docker_container: quay.io/ansible-community/test-image:centos-stream8
+ python_version: '3.6'
+ sops_version: latest
# devel
- ansible: devel
docker_container: quay.io/ansible-community/test-image:archlinux
python_version: '3.11'
sops_version: latest
- ansible: devel
+ docker_container: quay.io/ansible-community/test-image:debian-bookworm
+ python_version: '3.11'
+ sops_version: latest
+ - ansible: stable-2.15
docker_container: quay.io/ansible-community/test-image:debian-bullseye
python_version: '3.9'
sops_version: latest
- - ansible: devel
- docker_container: quay.io/ansible-community/test-image:centos-stream8
- python_version: '3.6'
- sops_version: latest
steps:
- name: >-
Perform integration testing against
@@ -177,6 +187,10 @@ jobs:
docker_container: ubuntu2204
python_version: ''
target: gha/install/1/
+ - ansible: devel
+ docker_container: fedora38
+ python_version: ''
+ target: gha/install/1/
# Install on localhost vs. remote host
- ansible: devel
docker_container: ubuntu2004
@@ -191,18 +205,23 @@ jobs:
# NOTE: we're installing with git to work around Galaxy being a huge PITA (https://github.com/ansible/galaxy/issues/2429)
pre-test-cmd: |-
git clone --depth=1 --single-branch https://github.com/ansible-collections/community.general.git ../../community/general
- - ansible: devel
+ - ansible: stable-2.15
docker_container: quay.io/ansible-community/test-image:centos-stream8
python_version: '3.9'
target: gha/install/3/
github_latest_detection: auto
- ansible: devel
+ docker_container: quay.io/ansible-community/test-image:debian-bookworm
+ python_version: '3.11'
+ target: gha/install/3/
+ github_latest_detection: auto
+ - ansible: stable-2.16
docker_container: quay.io/ansible-community/test-image:debian-bullseye
python_version: '3.9'
target: gha/install/3/
github_latest_detection: auto
- ansible: devel
- docker_container: fedora37
+ docker_container: fedora38
python_version: ''
target: gha/install/3/
github_latest_detection: auto
@@ -224,6 +243,7 @@ jobs:
# # NOTE: we're installing with git to work around Galaxy being a huge PITA (https://github.com/ansible/galaxy/issues/2429)
# pre-test-cmd: |-
# git clone --depth=1 --single-branch https://github.com/ansible-collections/community.general.git ../../community/general
+ # Install 3.8.0-rc.1 prerelease
steps:
- name: >-
Perform sops installation integration testing against
diff --git a/ansible_collections/community/sops/.github/workflows/ee.yml b/ansible_collections/community/sops/.github/workflows/ee.yml
index 22ec55014..3fccaa057 100644
--- a/ansible_collections/community/sops/.github/workflows/ee.yml
+++ b/ansible_collections/community/sops/.github/workflows/ee.yml
@@ -48,6 +48,10 @@ jobs:
- name: ansible-core devel @ RHEL UBI 9
ansible_core: https://github.com/ansible/ansible/archive/devel.tar.gz
ansible_runner: ansible-runner
+ other_deps: |2
+ python_interpreter:
+ package_system: python3.11 python3.11-pip python3.11-wheel python3.11-cryptography
+ python_path: "/usr/bin/python3.11"
base_image: docker.io/redhat/ubi9:latest
pre_base: '"#"'
execute_playbook: ansible-playbook -v community.sops.install_localhost
@@ -90,7 +94,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
path: ansible_collections/${{ env.NAMESPACE }}/${{ env.COLLECTION_NAME }}
diff --git a/ansible_collections/community/sops/.github/workflows/extra-tests.yml b/ansible_collections/community/sops/.github/workflows/extra-tests.yml
index fd2f7f55e..af386ec83 100644
--- a/ansible_collections/community/sops/.github/workflows/extra-tests.yml
+++ b/ansible_collections/community/sops/.github/workflows/extra-tests.yml
@@ -26,14 +26,14 @@ jobs:
steps:
- name: Check out code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
path: ansible_collections/${{env.NAMESPACE}}/${{env.COLLECTION_NAME}}
- name: Set up Python
uses: actions/setup-python@v4
with:
- python-version: '3.10'
+ python-version: '3.11'
- name: Install ansible-core
run: pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check
diff --git a/ansible_collections/community/sops/.github/workflows/import-galaxy.yml b/ansible_collections/community/sops/.github/workflows/import-galaxy.yml
index ae472845d..420dafb68 100644
--- a/ansible_collections/community/sops/.github/workflows/import-galaxy.yml
+++ b/ansible_collections/community/sops/.github/workflows/import-galaxy.yml
@@ -23,14 +23,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
path: ./checkout
- name: Set up Python
uses: actions/setup-python@v4
with:
- python-version: '3.10'
+ python-version: '3.11'
- name: Install ansible-core
run: pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check
@@ -71,7 +71,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v4
with:
- python-version: '3.10'
+ python-version: '3.11'
- name: Install ansible-core
run: pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check
diff --git a/ansible_collections/community/sops/.github/workflows/reuse.yml b/ansible_collections/community/sops/.github/workflows/reuse.yml
index f487d7969..dbdc1d499 100644
--- a/ansible_collections/community/sops/.github/workflows/reuse.yml
+++ b/ansible_collections/community/sops/.github/workflows/reuse.yml
@@ -21,7 +21,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Install dependencies
run: |
diff --git a/ansible_collections/community/sops/CHANGELOG.rst b/ansible_collections/community/sops/CHANGELOG.rst
index 8d2c88ca5..45ce0662a 100644
--- a/ansible_collections/community/sops/CHANGELOG.rst
+++ b/ansible_collections/community/sops/CHANGELOG.rst
@@ -5,6 +5,82 @@ Community Sops Release Notes
.. contents:: Topics
+v1.6.7
+======
+
+Release Summary
+---------------
+
+Bugfix release.
+
+Bugfixes
+--------
+
+- sops_encrypt - ensure that output-type is set to ``yaml`` when the file extension ``.yml`` is used. Now both ``.yaml`` and ``.yml`` files use the SOPS ``--output-type=yaml`` formatting (https://github.com/ansible-collections/community.sops/issues/164).
+
+v1.6.6
+======
+
+Release Summary
+---------------
+
+Make fully compatible with and test against sops 3.8.0.
+
+Bugfixes
+--------
+
+- Fix RPM URL for the 3.8.0 release (https://github.com/ansible-collections/community.sops/pull/161).
+
+v1.6.5
+======
+
+Release Summary
+---------------
+
+Make compatible with and test against sops 3.8.0-rc.1.
+
+Bugfixes
+--------
+
+- Avoid pre-releases when picking the latest version when using the GitHub API method (https://github.com/ansible-collections/community.sops/pull/159).
+- Fix changed DEB and RPM URLs for 3.8.0 and its prerelease(s) (https://github.com/ansible-collections/community.sops/pull/159).
+
+v1.6.4
+======
+
+Release Summary
+---------------
+
+Maintenance/bugfix release for the move of sops to the new `getsops GitHub organization <https://github.com/getsops>`__.
+
+Bugfixes
+--------
+
+- install role - fix ``sops_github_latest_detection=latest-release``, which broke due to sops moving to another GitHub organization (https://github.com/ansible-collections/community.sops/pull/151).
+
+v1.6.3
+======
+
+Release Summary
+---------------
+
+Maintenance release with updated documentation.
+
+From this version on, community.sops is using the new `Ansible semantic markup
+<https://docs.ansible.com/ansible/devel/dev_guide/developing_modules_documenting.html#semantic-markup-within-module-documentation>`__
+in its documentation. If you look at documentation with the ansible-doc CLI tool
+from ansible-core before 2.15, please note that it does not render the markup
+correctly. You should be still able to read it in most cases, but you need
+ansible-core 2.15 or later to see it as it is intended. Alternatively you can
+look at `the devel docsite <https://docs.ansible.com/ansible/devel/collections/community/sops/>`__
+for the rendered HTML version of the documentation of the latest release.
+
+
+Known Issues
+------------
+
+- Ansible markup will show up in raw form on ansible-doc text output for ansible-core before 2.15. If you have trouble deciphering the documentation markup, please upgrade to ansible-core 2.15 (or newer), or read the HTML documentation on https://docs.ansible.com/ansible/devel/collections/community/sops/.
+
v1.6.2
======
diff --git a/ansible_collections/community/sops/FILES.json b/ansible_collections/community/sops/FILES.json
index 63a027b18..022bae0cf 100644
--- a/ansible_collections/community/sops/FILES.json
+++ b/ansible_collections/community/sops/FILES.json
@@ -25,7 +25,7 @@
"name": ".github/workflows/ansible-test.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "73cdfbd8026911429246bc1660c77606b7e5ed2357cc678198ce494a36350497",
+ "chksum_sha256": "bed33c6620f2d7323d8468f8f621f3ea543db46d90e5598c81b02d814b0e832a",
"format": 1
},
{
@@ -46,28 +46,28 @@
"name": ".github/workflows/ee.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e924f232654dee81b0fc831ff559e1f4671b768221cc68bc6fe951d15933efd3",
+ "chksum_sha256": "13442db7f1b12ea9a4c6e8127e5dc3132c3165c75ccca509bfcc3c3b519b4da5",
"format": 1
},
{
"name": ".github/workflows/extra-tests.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d37c57a221512fa1d7e7477c382cd11941df95c39ddccc9ede1fc49c205ccfcb",
+ "chksum_sha256": "3f1745c9267b6672479989d71a4c9e23f051ec220ee61370f8fad321991b3525",
"format": 1
},
{
"name": ".github/workflows/import-galaxy.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "12f44c852cdcf4d6606110a18180751ce115c7431d9ecac8860c38ca68de3c95",
+ "chksum_sha256": "ed5db1ac5b80fbf247248ba6f66cb5bdedee09381c743bbfa60e5b133a4aa4ec",
"format": 1
},
{
"name": ".github/workflows/reuse.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "dc3684b09ddd4dea6622cbf4501c0bd4408f676bb9d05cedb6aff72529b6b4d0",
+ "chksum_sha256": "bd69ae1fc4d1e551fc67a9d9271ca04a3fe6d8a0e30181815b87fbad49a15afa",
"format": 1
},
{
@@ -151,7 +151,7 @@
"name": "changelogs/changelog.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8eb38241c4918f5e7f59a46059dde0eaacdc12a189168fb58e13cf048aa1726e",
+ "chksum_sha256": "d13211ac91f7af53225f9fd56bfa5789d7a98d647318d07902429484420a3e39",
"format": 1
},
{
@@ -193,7 +193,7 @@
"name": "docs/docsite/rst/guide.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "32f8fc68467e5c175a4d1301596f5647c7f1f7a6f36187cde01ec8e6047ab9b4",
+ "chksum_sha256": "4289f051c08662a484e50f334941aa14fa4ccfab05a6ac3f719f50359dceaf25",
"format": 1
},
{
@@ -298,7 +298,7 @@
"name": "plugins/doc_fragments/sops.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b301331d83a268914aa2c3e3042430de79bf572aa53a80d7b50fb5b00761b58f",
+ "chksum_sha256": "08c5b477751feb90ac32e78047c90fc4eb0b71000970fa488a43d0a85a485fed",
"format": 1
},
{
@@ -312,14 +312,14 @@
"name": "plugins/filter/_latest_version.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6db24f13e472ba499e1d891507b9bc14c5df17c73e8ad12d31fe2f362a69f177",
+ "chksum_sha256": "b5ed2b5fbd3d6673031cff857e0d056daf2842d5eeb17249774772129e254182",
"format": 1
},
{
"name": "plugins/filter/decrypt.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "47f4aea8e22c96d0ba032644299306d593c568fc4b2e04be1cb3ad81d20160a6",
+ "chksum_sha256": "172aa3716d5acd49b82cd9078e68526421a85d28116a6174b2fe5374befeefb1",
"format": 1
},
{
@@ -333,7 +333,7 @@
"name": "plugins/lookup/sops.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c2b9f850e93e4cde59e3f21f101ed06fc7174211fc9cd110f83cbe3271a992f9",
+ "chksum_sha256": "ec4b218296a27faea5ec01c6165ea379df3025ef9a2098efaa4058069b92e302",
"format": 1
},
{
@@ -354,7 +354,7 @@
"name": "plugins/module_utils/sops.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "34e358a918b7bfa0985203faada16b5f11424ba69a6ca1afed9f17c51bdd6fde",
+ "chksum_sha256": "1cdbd5b09ac6367893596fa957b2637d76e3db62a65957545d786248c4e8dd72",
"format": 1
},
{
@@ -368,14 +368,14 @@
"name": "plugins/modules/load_vars.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5c83a9e5afcc1cd978f07375510c0beb5928cbdfe0b132380f54dfedce7eda73",
+ "chksum_sha256": "6f65eada73c1cec0f3082cd548c9dd87b48d16f0516c803faa004d1333ac5b76",
"format": 1
},
{
"name": "plugins/modules/sops_encrypt.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "31eb7e974044dbcfb20aceeaa35dbe6a4db40cde34d8106376d0b87c618db3e2",
+ "chksum_sha256": "34631d7cf9ea31448682b2e88d37f01813dd773248b14453f0a3906e9b028823",
"format": 1
},
{
@@ -403,7 +403,7 @@
"name": "plugins/vars/sops.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8e69aae9a1f264fade4bab781b1ec69fd28dea343af3e79cdd76015b94de68bc",
+ "chksum_sha256": "4c7150b9893c7ebf553dc327e08fe5bfea675e1ddf5e99d13596fb296ac7c227",
"format": 1
},
{
@@ -571,14 +571,14 @@
"name": "roles/install/meta/argument_specs.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "365a49e747895ee0b404ef735fcf92b29c3dbcdd5fbc5844d5cb545d1d9fbde5",
+ "chksum_sha256": "bc32b9924cd06c20b06d7448b2be73a5affbcece5689573069cebf9ee92432ee",
"format": 1
},
{
"name": "roles/install/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "aec443fa842205021f4e5df3be4263de4344d8ce157307eca5f4523718a736e2",
+ "chksum_sha256": "073b60bfdecd6e185bb9f8d02f7e7167bb2db02f7c8af4394cd6085aa54c15be",
"format": 1
},
{
@@ -606,14 +606,14 @@
"name": "roles/install/tasks/github_api.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d2686f68158196c379e609f7c149d0ac8a3887b0685995ba3c6caac9f2990779",
+ "chksum_sha256": "e3dc6d2da9fbae52228765cc4f5f6d3a4a18af8a5d7691c13963943000df8219",
"format": 1
},
{
"name": "roles/install/tasks/github_latest_release.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3fcf412aa7c3a0c87c08ab45f8d0235304180212d37c0c8efc9097326516adfc",
+ "chksum_sha256": "8d02ba847bc7b10996d2e762bc5304b4446af592594363edb573dff6ede1e7cb",
"format": 1
},
{
@@ -655,14 +655,14 @@
"name": "roles/install/vars/OS-Debian.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f80fc923f141c7ea06989923786218befca11a5159372898d8b518110975715a",
+ "chksum_sha256": "68c63c8de33f7078997c2ae5c01998df4b33ab27dba401fe2c069d5ed311ca31",
"format": 1
},
{
"name": "roles/install/vars/OS-RedHat.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "69ec003b243d7a0e83e3787a2bc87e1ffd9eb88a42cf58e703deb97e03c63db3",
+ "chksum_sha256": "80434723c267d857e977bc19d9ceb8e60bb8b85eedf7e01d1fa339d772257720",
"format": 1
},
{
@@ -767,7 +767,7 @@
"name": "tests/ee/all.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "82f189010cba28eb4264c7a19ac085579c6f9fe7dd82e2f4c551d2e865dd132b",
+ "chksum_sha256": "34eaea22a6ab72535f9ed1e47e0bdf0c93648e900869b72b78b863118b3ec40e",
"format": 1
},
{
@@ -834,6 +834,34 @@
"format": 1
},
{
+ "name": "tests/integration/targets/filter__latest_version",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/filter__latest_version/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/filter__latest_version/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "eb403955be963645a440cc08e3b80cd5a20b831b51a7a54d05a63b2f56874626",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/filter__latest_version/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e5ced53ad61a1730fd8027e388426ff76ab537963c84bee1ad84ad5fc57dbb2a",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/filter_decrypt",
"ftype": "dir",
"chksum_type": null,
@@ -1527,6 +1555,20 @@
"format": 1
},
{
+ "name": "tests/integration/targets/role_install_latest/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/role_install_latest/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e11ca6edae518cc531ab425daa9eb93f78f89b9ddd515deabd239e8c7925323d",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/role_install_latest/tasks",
"ftype": "dir",
"chksum_type": null,
@@ -1555,6 +1597,20 @@
"format": 1
},
{
+ "name": "tests/integration/targets/role_install_localhost_remote/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/role_install_localhost_remote/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e11ca6edae518cc531ab425daa9eb93f78f89b9ddd515deabd239e8c7925323d",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/role_install_localhost_remote/tasks",
"ftype": "dir",
"chksum_type": null,
@@ -1583,6 +1639,20 @@
"format": 1
},
{
+ "name": "tests/integration/targets/role_install_version/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/role_install_version/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e11ca6edae518cc531ab425daa9eb93f78f89b9ddd515deabd239e8c7925323d",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/role_install_version/tasks",
"ftype": "dir",
"chksum_type": null,
@@ -1593,7 +1663,7 @@
"name": "tests/integration/targets/role_install_version/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1754b5e36e03ba81600f3678fd0f30de5a1f25f48999aa9b6cd9a42347edcfdb",
+ "chksum_sha256": "b407ca27828842bd8034fb2e124019ce35a22d01b22607aec39f59eb4539234b",
"format": 1
},
{
@@ -1604,6 +1674,34 @@
"format": 1
},
{
+ "name": "tests/integration/targets/setup_pkg_mgr",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_pkg_mgr/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_pkg_mgr/tasks/archlinux.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "cd071a182e3762f530cddc36a67e55e9c1ea8c404bbc18316d8d12347f4fbe01",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_pkg_mgr/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "0fb106d2ee26ad02f4d9f5328055b76932dbef01bc491dd336d2684ace8ee673",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/setup_remote_tmp_dir",
"ftype": "dir",
"chksum_type": null,
@@ -1660,6 +1758,20 @@
"format": 1
},
{
+ "name": "tests/integration/targets/setup_sops/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/setup_sops/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "e11ca6edae518cc531ab425daa9eb93f78f89b9ddd515deabd239e8c7925323d",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/setup_sops/tasks",
"ftype": "dir",
"chksum_type": null,
@@ -1670,7 +1782,7 @@
"name": "tests/integration/targets/setup_sops/tasks/install.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e5577e9ad872bf1bf6c2b91d506af8a4d74560f677cbf248023bb1283e979862",
+ "chksum_sha256": "e0f475dd8981e6625aff8ae443e001e80a48ce493fbca78351a04218cfaa9fb6",
"format": 1
},
{
@@ -2244,7 +2356,7 @@
"name": "tests/integration/targets/var_sops/README.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c43f777b5e871249b9b0ce642fe54d3eb5d04c8191dce97ab2c36c083e6168ae",
+ "chksum_sha256": "4060937137a2b2e254805ed81e6d02c71c39b9adaaa9989c5a8fe35ef306fb9f",
"format": 1
},
{
@@ -2300,7 +2412,7 @@
"name": "tests/sanity/extra/extra-docs.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0fbd87476e9c35e4c5feb31be4aa1e8fc6aebf0de13058e5a267879f741ec0bf",
+ "chksum_sha256": "c52e316daf1292bbb063be19429fd1f06e02bce3c9d4622a8dfc61fa3af06688",
"format": 1
},
{
@@ -2356,7 +2468,7 @@
"name": "tests/sanity/ignore-2.10.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "339f0feb36bead5f3e7ea0b6f9e2a87c0c3206f495d294ecfad057f7defa0225",
+ "chksum_sha256": "207d9d00a3131630b45a21968dabaf3f694bb463a1774a7a78c8b51b6cda85ab",
"format": 1
},
{
@@ -2370,7 +2482,7 @@
"name": "tests/sanity/ignore-2.11.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "339f0feb36bead5f3e7ea0b6f9e2a87c0c3206f495d294ecfad057f7defa0225",
+ "chksum_sha256": "d26c7ab4c1dcbea0e31206fc725ae736cb801d6386cc2b35e1e7ba54e9fa05d2",
"format": 1
},
{
@@ -2384,7 +2496,7 @@
"name": "tests/sanity/ignore-2.12.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "339f0feb36bead5f3e7ea0b6f9e2a87c0c3206f495d294ecfad057f7defa0225",
+ "chksum_sha256": "d26c7ab4c1dcbea0e31206fc725ae736cb801d6386cc2b35e1e7ba54e9fa05d2",
"format": 1
},
{
@@ -2398,7 +2510,7 @@
"name": "tests/sanity/ignore-2.13.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "339f0feb36bead5f3e7ea0b6f9e2a87c0c3206f495d294ecfad057f7defa0225",
+ "chksum_sha256": "66755c2d6580a1638312b6a2cddcce6252ca5e054202be2e2bfc6dbd0fc22ed4",
"format": 1
},
{
@@ -2412,7 +2524,7 @@
"name": "tests/sanity/ignore-2.14.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "339f0feb36bead5f3e7ea0b6f9e2a87c0c3206f495d294ecfad057f7defa0225",
+ "chksum_sha256": "66755c2d6580a1638312b6a2cddcce6252ca5e054202be2e2bfc6dbd0fc22ed4",
"format": 1
},
{
@@ -2451,13 +2563,27 @@
"format": 1
},
{
- "name": "tests/sanity/ignore-2.9.txt",
+ "name": "tests/sanity/ignore-2.17.txt",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "339f0feb36bead5f3e7ea0b6f9e2a87c0c3206f495d294ecfad057f7defa0225",
"format": 1
},
{
+ "name": "tests/sanity/ignore-2.17.txt.license",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "6eb915239f9f35407fa68fdc41ed6522f1fdcce11badbdcd6057548023179ac1",
+ "format": 1
+ },
+ {
+ "name": "tests/sanity/ignore-2.9.txt",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "207d9d00a3131630b45a21968dabaf3f694bb463a1774a7a78c8b51b6cda85ab",
+ "format": 1
+ },
+ {
"name": "tests/sanity/ignore-2.9.txt.license",
"ftype": "file",
"chksum_type": "sha256",
@@ -2482,7 +2608,7 @@
"name": "CHANGELOG.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "531c8f5e2e2dd47278c4fa5654e690b1fc6cd54dbdef459d025898900b02ca8c",
+ "chksum_sha256": "a7b18f61218c66190213237ad87a8a53538216df356e7ff98230b41861a520ef",
"format": 1
},
{
@@ -2510,7 +2636,7 @@
"name": "README.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "907940525a54d4a9d69b4048a78401b9179df58b138c4b2a1da500e827b093b6",
+ "chksum_sha256": "11a9e3713e564c010a8585c501e4d2e19157bbc741f1cc02fd4acb86cfb220ea",
"format": 1
},
{
diff --git a/ansible_collections/community/sops/MANIFEST.json b/ansible_collections/community/sops/MANIFEST.json
index 036a68d46..4bb1d9cd0 100644
--- a/ansible_collections/community/sops/MANIFEST.json
+++ b/ansible_collections/community/sops/MANIFEST.json
@@ -2,7 +2,7 @@
"collection_info": {
"namespace": "community",
"name": "sops",
- "version": "1.6.2",
+ "version": "1.6.7",
"authors": [
"Edoardo Tenani"
],
@@ -14,7 +14,7 @@
"secret",
"vault"
],
- "description": "Support usage of mozilla/sops from your Ansible playbooks",
+ "description": "Support usage of getsops/sops from your Ansible playbooks",
"license": [
"GPL-3.0-or-later",
"BSD-2-Clause"
@@ -30,7 +30,7 @@
"name": "FILES.json",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e6916843346085be643662b3c5a4d3f0eef3494fef82743749705370497a308c",
+ "chksum_sha256": "f1faf463236d1f6e7b988b2cd3f36cf25adeb331a206014b589d00b32f402ad2",
"format": 1
},
"format": 1
diff --git a/ansible_collections/community/sops/README.md b/ansible_collections/community/sops/README.md
index 0e7c85213..537822ef4 100644
--- a/ansible_collections/community/sops/README.md
+++ b/ansible_collections/community/sops/README.md
@@ -8,9 +8,9 @@ SPDX-License-Identifier: GPL-3.0-or-later
[![CI](https://github.com/ansible-collections/community.sops/workflows/CI/badge.svg?event=push)](https://github.com/ansible-collections/community.sops/actions) [![Codecov](https://img.shields.io/codecov/c/github/ansible-collections/community.sops)](https://codecov.io/gh/ansible-collections/community.sops)
<!-- Describe the collection and why a user would want to use it. What does the collection do? -->
-The `community.sops` collection allows integrating [`mozilla/sops`](https://github.com/mozilla/sops) in Ansible.
+The `community.sops` collection allows integrating [`getsops/sops`](https://github.com/getsops/sops) in Ansible.
-`mozilla/sops` is a tool for encryption and decryption of files using secure keys (GPG, KMS). It can be leveraged in Ansible to provide an easy to use and flexible to manage way to manage ecrypted secrets' files.
+`getsops/sops` is a tool for encryption and decryption of files using secure keys (GPG, KMS, age). It can be leveraged in Ansible to provide an easy to use and flexible to manage way to manage ecrypted secrets' files.
Please note that this collection does **not** support Windows targets.
@@ -18,15 +18,15 @@ Please note that this collection does **not** support Windows targets.
The following table shows which versions of sops were tested with which versions of the collection. Older (or newer) versions of sops can still work fine, it just means that we did not test them. In some cases, it could be that a minimal required version of sops is explicitly documented for a specific feature. Right now, that is not the case.
-|`community.sops` version|`mozilla/sops` version|
+|`community.sops` version|`getsops/sops` version|
|---|---|
|0.1.0|`3.5.0+`|
|1.0.6|`3.5.0+`|
-|`main` branch|`3.5.0`, `3.6.0`, `3.7.1`, `3.7.2`, `3.7.3`|
+|`main` branch|`3.5.0`, `3.6.0`, `3.7.3`, `3.8.0`|
## Tested with Ansible
-Tested with the current Ansible 2.9, ansible-base 2.10, ansible-core 2.11, ansible-core 2.12, ansible-core 2.13, and ansible-core 2.14 releases and the current development version of ansible-core. Ansible versions before 2.9.10 are not supported.
+Tested with the current Ansible 2.9, ansible-base 2.10, ansible-core 2.11, ansible-core 2.12, ansible-core 2.13, ansible-core 2.14, ansible-core 2.15, and ansible-core 2.16 releases and the current development version of ansible-core. Ansible versions before 2.9.10 are not supported.
The vars plugin requires ansible-base 2.10 or later.
@@ -34,7 +34,7 @@ The vars plugin requires ansible-base 2.10 or later.
<!-- List any external resources the collection depends on, for example minimum versions of an OS, libraries, or utilities. Do not list other Ansible collections here. -->
-You will need to install [`sops`](https://github.com/mozilla/sops) manually before using plugins provided by this
+You will need to install [`sops`](https://github.com/getsops/sops) manually before using plugins provided by this
collection.
## Collection Documentation
diff --git a/ansible_collections/community/sops/changelogs/changelog.yaml b/ansible_collections/community/sops/changelogs/changelog.yaml
index a91ec5463..2638bca69 100644
--- a/ansible_collections/community/sops/changelogs/changelog.yaml
+++ b/ansible_collections/community/sops/changelogs/changelog.yaml
@@ -275,3 +275,78 @@ releases:
- 1.6.2.yml
- 146-install-facts.yml
release_date: '2023-06-15'
+ 1.6.3:
+ changes:
+ known_issues:
+ - Ansible markup will show up in raw form on ansible-doc text output for ansible-core
+ before 2.15. If you have trouble deciphering the documentation markup, please
+ upgrade to ansible-core 2.15 (or newer), or read the HTML documentation on
+ https://docs.ansible.com/ansible/devel/collections/community/sops/.
+ release_summary: 'Maintenance release with updated documentation.
+
+
+ From this version on, community.sops is using the new `Ansible semantic markup
+
+ <https://docs.ansible.com/ansible/devel/dev_guide/developing_modules_documenting.html#semantic-markup-within-module-documentation>`__
+
+ in its documentation. If you look at documentation with the ansible-doc CLI
+ tool
+
+ from ansible-core before 2.15, please note that it does not render the markup
+
+ correctly. You should be still able to read it in most cases, but you need
+
+ ansible-core 2.15 or later to see it as it is intended. Alternatively you
+ can
+
+ look at `the devel docsite <https://docs.ansible.com/ansible/devel/collections/community/sops/>`__
+
+ for the rendered HTML version of the documentation of the latest release.
+
+ '
+ fragments:
+ - 1.6.3.yml
+ - semantic-markup.yml
+ release_date: '2023-06-27'
+ 1.6.4:
+ changes:
+ bugfixes:
+ - install role - fix ``sops_github_latest_detection=latest-release``, which
+ broke due to sops moving to another GitHub organization (https://github.com/ansible-collections/community.sops/pull/151).
+ release_summary: Maintenance/bugfix release for the move of sops to the new
+ `getsops GitHub organization <https://github.com/getsops>`__.
+ fragments:
+ - 1.6.4.yml
+ - 151-github.yml
+ release_date: '2023-06-30'
+ 1.6.5:
+ changes:
+ bugfixes:
+ - Avoid pre-releases when picking the latest version when using the GitHub API
+ method (https://github.com/ansible-collections/community.sops/pull/159).
+ - Fix changed DEB and RPM URLs for 3.8.0 and its prerelease(s) (https://github.com/ansible-collections/community.sops/pull/159).
+ release_summary: Make compatible with and test against sops 3.8.0-rc.1.
+ fragments:
+ - 1.6.5.yml
+ - 159-new-releases.yml
+ release_date: '2023-08-25'
+ 1.6.6:
+ changes:
+ bugfixes:
+ - Fix RPM URL for the 3.8.0 release (https://github.com/ansible-collections/community.sops/pull/161).
+ release_summary: Make fully compatible with and test against sops 3.8.0.
+ fragments:
+ - 1.6.6.yml
+ - 161-rhel-3.8.0.yml
+ release_date: '2023-09-15'
+ 1.6.7:
+ changes:
+ bugfixes:
+ - sops_encrypt - ensure that output-type is set to ``yaml`` when the file extension
+ ``.yml`` is used. Now both ``.yaml`` and ``.yml`` files use the SOPS ``--output-type=yaml``
+ formatting (https://github.com/ansible-collections/community.sops/issues/164).
+ release_summary: Bugfix release.
+ fragments:
+ - 1.6.7.yml
+ - 165-yaml-output-for-yml-extension.yaml
+ release_date: '2023-10-29'
diff --git a/ansible_collections/community/sops/docs/docsite/rst/guide.rst b/ansible_collections/community/sops/docs/docsite/rst/guide.rst
index bc071a194..8f7118d88 100644
--- a/ansible_collections/community/sops/docs/docsite/rst/guide.rst
+++ b/ansible_collections/community/sops/docs/docsite/rst/guide.rst
@@ -8,9 +8,9 @@
Protecting Ansible secrets with Mozilla SOPS
============================================
-`Mozilla SOPS <https://github.com/mozilla/sops>`_ allows to encrypt and decrypt files using various key sources (GPG, AWS KMS, GCP KMS, ...). For structured data, such as YAML, JSON, INI and ENV files, it will encrypt values, but not mapping keys. For YAML files, it also encrypts comments. This makes it a great tool for encrypting credentials with Ansible: you can easily see which files contain which variable, but the variables themselves are encrypted.
+`Mozilla SOPS <https://github.com/getsops/sops>`_ allows to encrypt and decrypt files using various key sources (GPG, AWS KMS, GCP KMS, ...). For structured data, such as YAML, JSON, INI and ENV files, it will encrypt values, but not mapping keys. For YAML files, it also encrypts comments. This makes it a great tool for encrypting credentials with Ansible: you can easily see which files contain which variable, but the variables themselves are encrypted.
-The ability to utilize various keysources makes it easier to use in complex environments than `Ansible Vault <https://docs.ansible.com/ansible/latest/user_guide/vault.html>`_.
+The ability to utilize various keysources makes it easier to use in complex environments than :ref:`Ansible Vault <vault_guide_index>`.
.. contents::
:local:
@@ -19,9 +19,9 @@ The ability to utilize various keysources makes it easier to use in complex envi
Installing sops
---------------
-You can find binaries and packages `on the project's release page <https://github.com/mozilla/sops/releases>`_. Depending on your operating system, you might also be able to install it with your system's package manager.
+You can find binaries and packages `on the project's release page <https://github.com/getsops/sops/releases>`_. Depending on your operating system, you might also be able to install it with your system's package manager.
-This collection provides a `role community.sops.install <ansible_collections.community.sops.install_role>`_ which allows to install sops and `GNU Privacy Guard (GPG) <https://en.wikipedia.org/wiki/GNU_Privacy_Guard>`__. The role allows to install sops from the system's package manager or from GitHub. Both sops and GPG can be installed on the remote hosts or the Ansible controller.
+This collection provides a :ansplugin:`role community.sops.install <community.sops.install#role>` which allows to install sops and `GNU Privacy Guard (GPG) <https://en.wikipedia.org/wiki/GNU_Privacy_Guard>`__. The role allows to install sops from the system's package manager or from GitHub. Both sops and GPG can be installed on the remote hosts or the Ansible controller.
.. code-block:: yaml
@@ -63,24 +63,24 @@ The simplest way of ensuring this is to use the ``community.sops.install_localho
.. code-block:: yaml
---
- version: 1
+ version: 3
dependencies:
galaxy: requirements.yml
additional_build_steps:
- append:
+ append_final:
# Ensure that sops is installed in the EE, assuming the EE is for ansible-core 2.11 or newer
- RUN ansible-playbook -v community.sops.install_localhost
-Note that this only works if the execution environment is built with ansible-core 2.11 or newer. When using an execution environment with Ansible 2.9, you have to use the ``community.sops.install`` role manually. Also note that you need to make sure that Ansible 2.9 uses the correct Python interpreter to be able to install system packages with; in the below example we are assuming a RHEL/CentOS based execution environment base image:
+Note that this only works if the execution environment is built with ansible-core 2.11 or newer. When using an execution environment with Ansible 2.9, you have to use the :ansplugin:`community.sops.install#role` role manually. Also note that you need to make sure that Ansible 2.9 uses the correct Python interpreter to be able to install system packages with; in the below example we are assuming a RHEL/CentOS based execution environment base image:
.. code-block:: yaml
---
- version: 1
+ version: 3
dependencies:
galaxy: requirements.yml
additional_build_steps:
- append:
+ append_final:
# Special step needed for Ansible 2.9 based EEs
- >-
RUN ansible localhost -m include_role -a name=community.sops.install
@@ -160,7 +160,7 @@ At the end, the ``sops`` section contains metadata, which includes the private k
Working with encrypted files
----------------------------
-You can decrypt sops-encrypted files with the :ref:`community.sops.sops lookup plugin <ansible_collections.community.sops.sops_lookup>`, and dynamically encrypt data with the :ref:`community.sops.sops_encrypt module <ansible_collections.community.sops.sops_encrypt_module>`. Being able to encrypt is useful when you create or update secrets in your Ansible playbooks.
+You can decrypt sops-encrypted files with the :ansplugin:`community.sops.sops lookup plugin <community.sops.sops#lookup>`, and dynamically encrypt data with the :ansplugin:`community.sops.sops_encrypt module <community.sops.sops_encrypt#module>`. Being able to encrypt is useful when you create or update secrets in your Ansible playbooks.
Assume that you have an encrypted private key ``keys/private_key.pem.sops``, which was in PEM format before being encrypted by sops:
@@ -170,7 +170,7 @@ Assume that you have an encrypted private key ``keys/private_key.pem.sops``, whi
$ sops --encrypt keys/private_key.pem > keys/private_key.pem.sops
$ wipe keys/private_key.pem
-To use it in a playbook, for example to pass it to the :ref:`community.crypto.openssl_csr module <ansible_collections.community.crypto.openssl_csr_module>` to create a certificate signing request (CSR), you can use the :ref:`community.sops.sops lookup plugin <ansible_collections.community.sops.sops_lookup>` to load it:
+To use it in a playbook, for example to pass it to the :ansplugin:`community.crypto.openssl_csr module <community.crypto.openssl_csr#module>` to create a certificate signing request (CSR), you can use the :ansplugin:`community.sops.sops lookup plugin <community.sops.sops#lookup>` to load it:
.. code-block:: yaml+jinja
@@ -205,7 +205,7 @@ This results in the following output:
Afterwards, you will have a CSR ``ansible.com.csr`` for the encrypted private key ``keys/private_key.pem.sops``.
-If you want to use Ansible to generate (or update) the encrypted private key, you can use the :ref:`community.crypto.openssl_privatekey_pipe module <ansible_collections.community.crypto.openssl_privatekey_pipe_module>` to generate (or update) the private key, and use the :ref:`community.sops.sops_encrypt module <ansible_collections.community.sops.sops_encrypt_module>` to write it to disk in encrypted form:
+If you want to use Ansible to generate (or update) the encrypted private key, you can use the :ansplugin:`community.crypto.openssl_privatekey_pipe module <community.crypto.openssl_privatekey_pipe#module>` to generate (or update) the private key, and use the :ansplugin:`community.sops.sops_encrypt module <community.sops.sops_encrypt#module>` to write it to disk in encrypted form:
.. code-block:: yaml+jinja
@@ -266,7 +266,7 @@ This playbook creates a new key on every run. If you want the private key creati
set_fact:
private_key: ''
-The ``empty_on_not_exist=true`` flag is needed to avoid the lookup to fail when the key does not yet exist. When this playbook is run twice, the output will be:
+The :ansopt:`community.sops.sops#lookup:empty_on_not_exist=true` flag is needed to avoid the lookup to fail when the key does not yet exist. When this playbook is run twice, the output will be:
.. code-block:: ansible-output
@@ -287,9 +287,9 @@ The ``empty_on_not_exist=true`` flag is needed to avoid the lookup to fail when
Working with encrypted data from other sources
----------------------------------------------
-You can use the :ref:`community.sops.decrypt Jinja2 filter <ansible_collections.community.sops.decrypt_filter>` to decrypt arbitrary data. This can be data read earlier from a file, returned from an action, or obtained through some other means.
+You can use the :ansplugin:`community.sops.decrypt Jinja2 filter <community.sops.decrypt#filter>` to decrypt arbitrary data. This can be data read earlier from a file, returned from an action, or obtained through some other means.
-For example, assume that you want to decrypt a file retrieved from a HTTPS server with the `ansible.builtin.uri module <ansible_collections.ansible.builtin.uri_module>`_. To use the :ref:`community.sops.sops lookup <ansible_collections.community.sops.sops_lookup>`, you have to write it to a file first. With the filter, you can directly decrypt it:
+For example, assume that you want to decrypt a file retrieved from a HTTPS server with the :ansplugin:`ansible.builtin.uri module <ansible.builtin.uri#module>`. To use the :ansplugin:`community.sops.sops lookup <community.sops.sops#lookup>`, you have to write it to a file first. With the filter, you can directly decrypt it:
.. code-block:: yaml+jinja
@@ -300,7 +300,7 @@ For example, assume that you want to decrypt a file retrieved from a HTTPS serve
tasks:
- name: Fetch file from URL
ansible.builtin.uri:
- url: https://raw.githubusercontent.com/mozilla/sops/master/functional-tests/res/comments.enc.yaml
+ url: https://raw.githubusercontent.com/getsops/sops/master/functional-tests/res/comments.enc.yaml
return_content: true
register: encrypted_content
@@ -365,7 +365,7 @@ The output will be:
PLAY RECAP *******************************************************************************************************
localhost : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
-Please note that if you put a Jinja2 expression in a variable, it will be evaluated **every time it is used**. Decrypting data takes a certain amount of time. If you need to use an expression multiple times, it is better to store its evaluated form as a fact with `ansible.bulitin.set_fact <ansible_collections.ansible.builtin.set_fact_module>`_ first. This can be important if decrypted data should be passed to a role
+Please note that if you put a Jinja2 expression in a variable, it will be evaluated **every time it is used**. Decrypting data takes a certain amount of time. If you need to use an expression multiple times, it is better to store its evaluated form as a fact with :ansplugin:`ansible.bulitin.set_fact <ansible.builtin.set_fact#module>` first. This can be important if decrypted data should be passed to a role
.. code-block:: yaml+jinja
@@ -376,7 +376,7 @@ Please note that if you put a Jinja2 expression in a variable, it will be evalua
tasks:
- name: Fetch file from URL
ansible.builtin.uri:
- url: https://raw.githubusercontent.com/mozilla/sops/master/functional-tests/res/comments.enc.yaml
+ url: https://raw.githubusercontent.com/getsops/sops/master/functional-tests/res/comments.enc.yaml
return_content: true
register: encrypted_content
@@ -403,7 +403,7 @@ Please note that if you put a Jinja2 expression in a variable, it will be evalua
Working with encrypted variables
--------------------------------
-You can load encrypted variables similarly to the :ref:`ansible.builtin.host_group_vars vars plugin <ansible_collections.ansible.builtin.host_group_vars_vars>` with the :ref:`community.sops.sops vars plugin <ansible_collections.community.sops.sops_vars>`. If you need to load variables dynamically similarly to the :ref:`ansible.builtin.include_vars action <ansible_collections.ansible.builtin.include_vars_module>`, you can use the :ref:`community.sops.load_vars action <ansible_collections.community.sops.load_vars_module>`.
+You can load encrypted variables similarly to the :ansplugin:`ansible.builtin.host_group_vars vars plugin <ansible.builtin.host_group_vars#vars>` with the :ansplugin:`community.sops.sops vars plugin <community.sops.sops#vars>`. If you need to load variables dynamically similarly to the :ansplugin:`ansible.builtin.include_vars action <ansible.builtin.include_vars#module>`, you can use the :ansplugin:`community.sops.load_vars action <community.sops.load_vars#module>`.
To use the vars plugin, you need to enable it in your Ansible config file (``ansible.cfg``):
@@ -420,9 +420,9 @@ See :ref:`VARIABLE_PLUGINS_ENABLED <VARIABLE_PLUGINS_ENABLED>` for more details
The vars plugin will decrypt them and you can use their unencrypted content transparently.
-If you need to dynamically load encrypted variables, similar to the built-in :ref:`ansible.builtin.include_vars action <ansible_collections.ansible.builtin.include_vars_module>`, you can use the :ref:`community.sops.load_vars action <ansible_collections.community.sops.load_vars_module>` action. Please note that it is not a perfect replacement, since the built-in action relies on some hard-coded special casing in ansible-core which allows it to load the variables actually as variables (more precisely: as "unsafe" Jinja2 expressions which are automatically evaluated when used). Other action plugins, such as ``community.sops.load_vars``, cannot do that and have to load the variables as facts instead.
+If you need to dynamically load encrypted variables, similar to the built-in :ansplugin:`ansible.builtin.include_vars action <ansible.builtin.include_vars#module>`, you can use the :ansplugin:`community.sops.load_vars action <community.sops.load_vars#module>` action. Please note that it is not a perfect replacement, since the built-in action relies on some hard-coded special casing in ansible-core which allows it to load the variables actually as variables (more precisely: as "unsafe" Jinja2 expressions which are automatically evaluated when used). Other action plugins, such as :ansplugin:`community.sops.load_vars#module`, cannot do that and have to load the variables as facts instead.
-This is mostly relevant if you use Jinja2 expressions in the encrypted variable file. When ``include_vars`` loads a variable file with expressions, these expressions will only be evaluated when the variable that defines them needs to be evaluated (lazy evaluation). Since ``community.sops.load_vars`` returns facts, it has to directly evaluate expressions at load time. (For this, set its ``expressions`` option to ``evaluate-on-load``.) This is mostly relevant if you want to refer to other variables from the same file: this will not work, since Ansible does not know the other variable yet while evaluating the first. It will only "know" them as facts after all have been evaluated and the action finishes.
+This is mostly relevant if you use Jinja2 expressions in the encrypted variable file. When :ansplugin:`ansible.builtin.include_vars#module` loads a variable file with expressions, these expressions will only be evaluated when the variable that defines them needs to be evaluated (lazy evaluation). Since :ansplugin:`community.sops.load_vars#module` returns facts, it has to directly evaluate expressions at load time. (For this, set its :ansopt:`community.sops.load_vars#module:expressions` option to :ansval:`evaluate-on-load`.) This is mostly relevant if you want to refer to other variables from the same file: this will not work, since Ansible does not know the other variable yet while evaluating the first. It will only "know" them as facts after all have been evaluated and the action finishes.
For the following example, assume you have the encrypted file ``keys/credentials.sops.yml`` which decrypts to:
diff --git a/ansible_collections/community/sops/plugins/doc_fragments/sops.py b/ansible_collections/community/sops/plugins/doc_fragments/sops.py
index ffbfe2d54..15a0ea118 100644
--- a/ansible_collections/community/sops/plugins/doc_fragments/sops.py
+++ b/ansible_collections/community/sops/plugins/doc_fragments/sops.py
@@ -20,14 +20,14 @@ options:
age_key:
description:
- One or more age private keys that can be used to decrypt encrypted files.
- - Will be set as the C(SOPS_AGE_KEY) environment variable when calling sops.
+ - Will be set as the E(SOPS_AGE_KEY) environment variable when calling sops.
type: str
version_added: 1.4.0
age_keyfile:
description:
- The file containing the age private keys that sops can use to decrypt
encrypted files.
- - Will be set as the C(SOPS_AGE_KEY_FILE) environment variable when calling sops.
+ - Will be set as the E(SOPS_AGE_KEY_FILE) environment variable when calling sops.
- By default, sops looks for C(sops/age/keys.txt) inside your user configuration
directory.
type: path
@@ -41,19 +41,19 @@ options:
aws_access_key_id:
description:
- The AWS access key ID to use for requests to AWS.
- - Sets the environment variable C(AWS_ACCESS_KEY_ID) for the sops call.
+ - Sets the environment variable E(AWS_ACCESS_KEY_ID) for the sops call.
type: str
version_added: 1.0.0
aws_secret_access_key:
description:
- The AWS secret access key to use for requests to AWS.
- - Sets the environment variable C(AWS_SECRET_ACCESS_KEY) for the sops call.
+ - Sets the environment variable E(AWS_SECRET_ACCESS_KEY) for the sops call.
type: str
version_added: 1.0.0
aws_session_token:
description:
- The AWS session token to use for requests to AWS.
- - Sets the environment variable C(AWS_SESSION_TOKEN) for the sops call.
+ - Sets the environment variable E(AWS_SESSION_TOKEN) for the sops call.
type: str
version_added: 1.0.0
config_path:
@@ -264,7 +264,7 @@ options:
description:
- Override the encrypted key suffix.
- When set to an empty string, all keys will be encrypted that are not explicitly
- marked by I(unencrypted_suffix).
+ marked by O(unencrypted_suffix).
- This corresponds to the sops C(--encrypted-suffix) option.
type: str
version_added: 1.0.0
@@ -293,7 +293,7 @@ options:
description:
- The number of distinct keys required to retrieve the data key with
L(Shamir's Secret Sharing, https://en.wikipedia.org/wiki/Shamir%27s_Secret_Sharing).
- - If not set here and in the sops config file, will default to C(0).
+ - If not set here and in the sops config file, will default to V(0).
- This corresponds to the sops C(--shamir-secret-sharing-threshold) option.
type: int
version_added: 1.0.0
diff --git a/ansible_collections/community/sops/plugins/filter/_latest_version.py b/ansible_collections/community/sops/plugins/filter/_latest_version.py
index a4de0f17b..9aecc45d7 100644
--- a/ansible_collections/community/sops/plugins/filter/_latest_version.py
+++ b/ansible_collections/community/sops/plugins/filter/_latest_version.py
@@ -62,6 +62,8 @@ except ImportError:
def pick_latest_version(version_list):
'''Pick latest version from a list of versions.'''
+ # Remove all prereleases (versions with '+' or '-' in them)
+ version_list = [v for v in version_list if '-' not in v and '+' not in v]
if not version_list:
return ''
return sorted(version_list, key=LooseVersion, reverse=True)[0]
diff --git a/ansible_collections/community/sops/plugins/filter/decrypt.py b/ansible_collections/community/sops/plugins/filter/decrypt.py
index a27d1c70f..015d93881 100644
--- a/ansible_collections/community/sops/plugins/filter/decrypt.py
+++ b/ansible_collections/community/sops/plugins/filter/decrypt.py
@@ -46,9 +46,9 @@ options:
output_type:
description:
- Tell sops how to interpret the decrypted file.
- - Please note that the output is always text or bytes, depending on the value of I(decode_output).
- To parse the resulting JSON or YAML, use corresponding filters such as C(ansible.builtin.from_json)
- and C(ansible.builtin.from_yaml).
+ - Please note that the output is always text or bytes, depending on the value of O(decode_output).
+ To parse the resulting JSON or YAML, use corresponding filters such as P(ansible.builtin.from_json#filter)
+ and P(ansible.builtin.from_yaml#filter).
type: str
choices:
- binary
@@ -59,8 +59,8 @@ options:
decode_output:
description:
- Whether to decode the output to bytes.
- - When I(output_type=binary), and the file isn't known to contain UTF-8 encoded text,
- this should better be set to C(false) to prevent mangling the data with UTF-8 decoding.
+ - When O(output_type=binary), and the file isn't known to contain UTF-8 encoded text,
+ this should better be set to V(false) to prevent mangling the data with UTF-8 decoding.
type: bool
default: true
extends_documentation_fragment:
@@ -80,7 +80,7 @@ EXAMPLES = '''
tasks:
- name: Fetch file from URL
ansible.builtin.uri:
- url: https://raw.githubusercontent.com/mozilla/sops/master/functional-tests/res/comments.enc.yaml
+ url: https://raw.githubusercontent.com/getsops/sops/master/functional-tests/res/comments.enc.yaml
return_content: true
register: encrypted_content
@@ -100,7 +100,7 @@ EXAMPLES = '''
RETURN = '''
_value:
description:
- - Decrypted data as text (I(decode_output=true), default) or binary string (I(decode_output=false)).
+ - Decrypted data as text (O(decode_output=true), default) or binary string (O(decode_output=false)).
type: string
'''
diff --git a/ansible_collections/community/sops/plugins/lookup/sops.py b/ansible_collections/community/sops/plugins/lookup/sops.py
index 64990ae55..8d39432f5 100644
--- a/ansible_collections/community/sops/plugins/lookup/sops.py
+++ b/ansible_collections/community/sops/plugins/lookup/sops.py
@@ -55,7 +55,7 @@ DOCUMENTATION = """
- dotenv
empty_on_not_exist:
description:
- - When set to C(true), will not raise an error when a file cannot be found,
+ - When set to V(true), will not raise an error when a file cannot be found,
but return an empty string instead.
type: bool
default: false
@@ -67,14 +67,12 @@ DOCUMENTATION = """
notes:
- This lookup does not understand 'globbing' - use the fileglob lookup instead.
seealso:
- - ref: community.sops.decrypt filter <ansible_collections.community.sops.decrypt_filter>
+ - plugin: community.sops.decrypt
+ plugin_type: filter
description: The decrypt filter can be used to descrypt sops-encrypted in-memory data.
- # - plugin: community.sops.decrypt
- # plugin_type: filter
- - ref: community.sops.sops vars plugin <ansible_collections.community.sops.sops_vars>
+ - plugin: community.sops.sops
+ plugin_type: vars
description: The sops vars plugin can be used to load sops-encrypted host or group variables.
- # - plugin: community.sops.sops
- # plugin_type: vars
- module: community.sops.load_vars
"""
diff --git a/ansible_collections/community/sops/plugins/module_utils/sops.py b/ansible_collections/community/sops/plugins/module_utils/sops.py
index d3c98d1d2..c66405237 100644
--- a/ansible_collections/community/sops/plugins/module_utils/sops.py
+++ b/ansible_collections/community/sops/plugins/module_utils/sops.py
@@ -14,7 +14,7 @@ from ansible.module_utils.common.text.converters import to_text, to_native
from subprocess import Popen, PIPE
-# From https://github.com/mozilla/sops/blob/master/cmd/sops/codes/codes.go
+# From https://github.com/getsops/sops/blob/master/cmd/sops/codes/codes.go
# Should be manually updated
SOPS_ERROR_CODES = {
1: "ErrorGeneric",
@@ -112,7 +112,7 @@ ENCRYPT_OPTIONS = {
class SopsError(Exception):
- ''' Extend Exception class with sops specific informations '''
+ ''' Extend Exception class with sops specific information '''
def __init__(self, filename, exit_code, message, decryption=True):
if exit_code in SOPS_ERROR_CODES:
diff --git a/ansible_collections/community/sops/plugins/modules/load_vars.py b/ansible_collections/community/sops/plugins/modules/load_vars.py
index 27e9ae8c2..26366078f 100644
--- a/ansible_collections/community/sops/plugins/modules/load_vars.py
+++ b/ansible_collections/community/sops/plugins/modules/load_vars.py
@@ -28,13 +28,13 @@ options:
name:
description:
- The name of a variable into which assign the included vars.
- - If omitted (C(null)) they will be made top level vars.
+ - If omitted (V(null)) they will be made top level vars.
type: str
expressions:
description:
- This option controls how Jinja2 expressions in values in the loaded file are handled.
- - If set to C(ignore), expressions will not be evaluated, but treated as regular strings.
- - If set to C(evaluate-on-load), expressions will be evaluated on execution of this module,
+ - If set to V(ignore), expressions will not be evaluated, but treated as regular strings.
+ - If set to V(evaluate-on-load), expressions will be evaluated on execution of this module,
in other words, when the file is loaded.
- Unfortunately, there is no way for non-core modules to handle expressions "unsafe",
in other words, evaluate them only on use. This can only achieved by M(ansible.builtin.include_vars),
@@ -69,18 +69,15 @@ seealso:
- module: ansible.builtin.include_vars
- ref: playbooks_delegation
description: More information related to task delegation.
- - ref: community.sops.sops lookup <ansible_collections.community.sops.sops_lookup>
+ - plugin: community.sops.sops
+ plugin_type: lookup
description: The sops lookup can be used decrypt sops-encrypted files.
- # - plugin: community.sops.sops
- # plugin_type: lookup
- - ref: community.sops.decrypt filter <ansible_collections.community.sops.decrypt_filter>
+ - plugin: community.sops.decrypt
+ plugin_type: filter
description: The decrypt filter can be used to descrypt sops-encrypted in-memory data.
- # - plugin: community.sops.decrypt
- # plugin_type: filter
- - ref: community.sops.sops vars plugin <ansible_collections.community.sops.sops_vars>
+ - plugin: community.sops.sops
+ plugin_type: vars
description: The sops vars plugin can be used to load sops-encrypted host or group variables.
- # - plugin: community.sops.sops
- # plugin_type: vars
'''
EXAMPLES = r'''
diff --git a/ansible_collections/community/sops/plugins/modules/sops_encrypt.py b/ansible_collections/community/sops/plugins/modules/sops_encrypt.py
index d4ba34353..9fd9b5081 100644
--- a/ansible_collections/community/sops/plugins/modules/sops_encrypt.py
+++ b/ansible_collections/community/sops/plugins/modules/sops_encrypt.py
@@ -32,24 +32,24 @@ options:
description:
- The data to encrypt. Must be a Unicode text.
- Please note that the module might not be idempotent if the text can be parsed as JSON or YAML.
- - Exactly one of I(content_text), I(content_binary), I(content_json) and I(content_yaml) must be specified.
+ - Exactly one of O(content_text), O(content_binary), O(content_json), and O(content_yaml) must be specified.
type: str
content_binary:
description:
- The data to encrypt. Must be L(Base64 encoded,https://en.wikipedia.org/wiki/Base64) binary data.
- Please note that the module might not be idempotent if the data can be parsed as JSON or YAML.
- - Exactly one of I(content_text), I(content_binary), I(content_json) and I(content_yaml) must be specified.
+ - Exactly one of O(content_text), O(content_binary), O(content_json), and O(content_yaml) must be specified.
type: str
content_json:
description:
- The data to encrypt. Must be a JSON dictionary.
- - Exactly one of I(content_text), I(content_binary), I(content_json) and I(content_yaml) must be specified.
+ - Exactly one of O(content_text), O(content_binary), O(content_json), and O(content_yaml) must be specified.
type: dict
content_yaml:
description:
- The data to encrypt. Must be a YAML dictionary.
- Please note that Ansible only allows to pass data that can be represented as a JSON dictionary.
- - Exactly one of I(content_text), I(content_binary), I(content_json) and I(content_yaml) must be specified.
+ - Exactly one of O(content_text), O(content_binary), O(content_json), and O(content_yaml) must be specified.
type: dict
extends_documentation_fragment:
- ansible.builtin.files
@@ -65,10 +65,9 @@ attributes:
safe_file_operations:
support: full
seealso:
- - ref: community.sops.sops lookup <ansible_collections.community.sops.sops_lookup>
+ - plugin: community.sops.sops
+ plugin_type: lookup
description: The sops lookup can be used decrypt sops-encrypted files.
- # - plugin: community.sops.sops
- # plugin_type: lookup
'''
EXAMPLES = r'''
@@ -217,7 +216,7 @@ def main():
output_type = None
if path.endswith('.json'):
output_type = 'json'
- elif path.endswith('.yaml'):
+ elif path.endswith('.yaml') or path.endswith('.yml'):
output_type = 'yaml'
data = Sops.encrypt(
data=input_data, cwd=directory, input_type=input_type, output_type=output_type,
diff --git a/ansible_collections/community/sops/plugins/vars/sops.py b/ansible_collections/community/sops/plugins/vars/sops.py
index 547480351..8b83a06b3 100644
--- a/ansible_collections/community/sops/plugins/vars/sops.py
+++ b/ansible_collections/community/sops/plugins/vars/sops.py
@@ -38,7 +38,7 @@ DOCUMENTATION = '''
- If the cache is disabled, the files will be decrypted for almost every task. This is very slow!
- Only disable caching if you modify the variable files during a playbook run and want the updated
result to be available from the next task on.
- - "Note that setting I(stage) to C(inventory) has the same effect as setting I(cache) to C(true):
+ - "Note that setting O(stage=inventory) has the same effect as setting O(cache=true):
the variables will be loaded only once (during inventory loading) and the vars plugin will not
be called for every task."
type: bool
@@ -64,14 +64,12 @@ DOCUMENTATION = '''
- community.sops.sops.ansible_env
- community.sops.sops.ansible_ini
seealso:
- - ref: community.sops.sops lookup <ansible_collections.community.sops.sops_lookup>
+ - plugin: community.sops.sops
+ plugin_type: lookup
description: The sops lookup can be used decrypt sops-encrypted files.
- # - plugin: community.sops.sops
- # plugin_type: lookup
- - ref: community.sops.decrypt filter <ansible_collections.community.sops.decrypt_filter>
+ - plugin: community.sops.decrypt
+ plugin_type: filter
description: The decrypt filter can be used to descrypt sops-encrypted in-memory data.
- # - plugin: community.sops.decrypt
- # plugin_type: filter
- module: community.sops.load_vars
'''
@@ -137,7 +135,7 @@ class VarsModule(BaseVarsPlugin):
if os.path.exists(b_opath):
if os.path.isdir(b_opath):
self._display.debug("\tprocessing dir %s" % opath)
- # NOTE: iterating without extension allow retriving files recursively
+ # NOTE: iterating without extension allow retrieving files recursively
# A filter is then applied by iterating on all results and filtering by
# extension.
# See:
diff --git a/ansible_collections/community/sops/roles/install/meta/argument_specs.yml b/ansible_collections/community/sops/roles/install/meta/argument_specs.yml
index e6f3e8746..83c890a5b 100644
--- a/ansible_collections/community/sops/roles/install/meta/argument_specs.yml
+++ b/ansible_collections/community/sops/roles/install/meta/argument_specs.yml
@@ -8,7 +8,7 @@ argument_specs:
short_description: Install Mozilla sops
version_added: 1.5.0
description:
- - This role installs L(Mozilla sops,https://github.com/mozilla/sops) and Gnu Privacy Guard (GPG).
+ - This role installs L(Mozilla sops,https://github.com/getsops/sops) and Gnu Privacy Guard (GPG).
- >-
This role supports the following operating systems:
Alpine (new enough),
@@ -19,7 +19,7 @@ argument_specs:
RHEL 7 or newer,
Ubuntu 16.04 or newer LTS versions
- The Ansible facts C(ansible_facts.architecture), C(ansible_facts.distribution), C(ansible_facts.distribution_major_version),
- C(ansible_facts.distribution_version), and C(ansible_facts.os_family) are expected to be present if I(sops_install_on_localhost) is C(false).
+ C(ansible_facts.distribution_version), and C(ansible_facts.os_family) are expected to be present if O(sops_install_on_localhost) is V(false).
author:
- Felix Fontein (@felixfontein)
options:
@@ -27,15 +27,15 @@ argument_specs:
default: latest
description:
- The version of sops to install.
- - Should be a version like C(3.7.2). The special value C(latest) will select the latest version available form the given source.
+ - Should be a version like V(3.7.2). The special value V(latest) will select the latest version available form the given source.
type: str
sops_source:
default: auto
description:
- Determines the source from where sops is installed.
- - The value C(github) will install sops from the Mozilla sops releases on GitHub (U(https://github.com/mozilla/sops/releases/)).
- - The value C(system) will install sops from the system packages. Note that not all system package repositories support sops.
- - The value C(auto) will determine the best source to install sops from. Here, system package repositories are preferred over GitHub.
+ - The value V(github) will install sops from the Mozilla sops releases on GitHub (U(https://github.com/getsops/sops/releases/)).
+ - The value V(system) will install sops from the system packages. Note that not all system package repositories support sops.
+ - The value V(auto) will determine the best source to install sops from. Here, system package repositories are preferred over GitHub.
type: str
choices:
- auto
@@ -54,9 +54,9 @@ argument_specs:
sops_github_latest_detection:
description:
- When installing the latest sops version from GitHub, configures how the latest release is detected.
- - C(auto) tries C(api) first and then uses C(latest-release).
- - C(api) asks the GitHub API for a list of recent releases and picks the highest version.
- - C(latest-release) uses a not fully documented URL to retrieve the release marked as "latest" by the repository maintainers.
+ - V(auto) tries V(api) first and then uses V(latest-release).
+ - V(api) asks the GitHub API for a list of recent releases and picks the highest version. Pre-releases are avoided.
+ - V(latest-release) uses a not fully documented URL to retrieve the release marked as "latest" by the repository maintainers.
type: str
choices:
- auto
diff --git a/ansible_collections/community/sops/roles/install/meta/main.yml b/ansible_collections/community/sops/roles/install/meta/main.yml
index f6dc6814e..376d956b6 100644
--- a/ansible_collections/community/sops/roles/install/meta/main.yml
+++ b/ansible_collections/community/sops/roles/install/meta/main.yml
@@ -6,6 +6,6 @@
galaxy_info:
standalone: false
description: >
- Install Mozilla sops (https://github.com/mozilla/sops).
+ Install Mozilla sops (https://github.com/getsops/sops).
dependencies: []
diff --git a/ansible_collections/community/sops/roles/install/tasks/github_api.yml b/ansible_collections/community/sops/roles/install/tasks/github_api.yml
index 01d9b77b3..43dc526b4 100644
--- a/ansible_collections/community/sops/roles/install/tasks/github_api.yml
+++ b/ansible_collections/community/sops/roles/install/tasks/github_api.yml
@@ -11,7 +11,7 @@
status_code:
- 200
- 403 # "HTTP Error 403: rate limit exceeded"
- url: https://api.github.com/repos/mozilla/sops/releases
+ url: https://api.github.com/repos/getsops/sops/releases
register: _community_sops_install_github_releases
delegate_to: localhost
run_once: true
diff --git a/ansible_collections/community/sops/roles/install/tasks/github_latest_release.yml b/ansible_collections/community/sops/roles/install/tasks/github_latest_release.yml
index ca67b3cd6..748918657 100644
--- a/ansible_collections/community/sops/roles/install/tasks/github_latest_release.yml
+++ b/ansible_collections/community/sops/roles/install/tasks/github_latest_release.yml
@@ -9,7 +9,7 @@
status_code:
- 302
- 307
- url: https://github.com/mozilla/sops/releases/latest/
+ url: https://github.com/getsops/sops/releases/latest/
register: _community_sops_install_github_latest_release
delegate_to: localhost
run_once: true
@@ -28,7 +28,7 @@
- name: In case this failed, inform user
ansible.builtin.debug:
msg: >-
- Could not obtain latest version from https://github.com/mozilla/sops/releases/latest/.
+ Could not obtain latest version from https://github.com/getsops/sops/releases/latest/.
Please create an issue in https://github.com/ansible-collections/community.sops/issues/
if there is not already one.
when: _community_sops_install_effective_sops_version == ''
diff --git a/ansible_collections/community/sops/roles/install/vars/OS-Debian.yml b/ansible_collections/community/sops/roles/install/vars/OS-Debian.yml
index 5f9cf2609..64e23f2d5 100644
--- a/ansible_collections/community/sops/roles/install/vars/OS-Debian.yml
+++ b/ansible_collections/community/sops/roles/install/vars/OS-Debian.yml
@@ -16,10 +16,10 @@ _community_sops_install_system_packages_unsigned: []
_community_sops_install_arch_transform:
x86_64: amd64
_community_sops_install_system_package_deb_github: >-
- https://github.com/mozilla/sops/releases/download/v{{
+ https://github.com/getsops/sops/releases/download/v{{
_community_sops_install_effective_sops_version
}}/sops_{{
- _community_sops_install_effective_sops_version
+ _community_sops_install_effective_sops_version.replace('-', '.')
}}_{{
_community_sops_install_arch_transform.get(ansible_facts.architecture, ansible_facts.architecture)
}}.deb
diff --git a/ansible_collections/community/sops/roles/install/vars/OS-RedHat.yml b/ansible_collections/community/sops/roles/install/vars/OS-RedHat.yml
index 95f7d2abe..e06c62806 100644
--- a/ansible_collections/community/sops/roles/install/vars/OS-RedHat.yml
+++ b/ansible_collections/community/sops/roles/install/vars/OS-RedHat.yml
@@ -17,13 +17,15 @@ _community_sops_install_system_package_deb_github: false
_community_sops_install_system_packages_github: []
_community_sops_install_system_packages_unsigned_github:
- >-
- https://github.com/mozilla/sops/releases/download/v{{
+ https://github.com/getsops/sops/releases/download/v{{
_community_sops_install_effective_sops_version
}}/sops-{{
(_community_sops_install_effective_sops_version is version('3.6.0', '<')) | ternary('v', '')
}}{{
- _community_sops_install_effective_sops_version
- }}-1.{{
+ _community_sops_install_effective_sops_version.replace('-', '.')
+ }}{{
+ (_community_sops_install_effective_sops_version is version('3.8.0', '<')) | ternary('-1', '')
+ }}.{{
ansible_facts.architecture
}}.rpm
diff --git a/ansible_collections/community/sops/tests/ee/all.yml b/ansible_collections/community/sops/tests/ee/all.yml
index 18c7eda41..f42fdb634 100644
--- a/ansible_collections/community/sops/tests/ee/all.yml
+++ b/ansible_collections/community/sops/tests/ee/all.yml
@@ -7,7 +7,7 @@
tasks:
- name: Download sops test GPG key on localhost
get_url:
- url: https://raw.githubusercontent.com/mozilla/sops/master/pgp/sops_functional_tests_key.asc
+ url: https://raw.githubusercontent.com/getsops/sops/master/pgp/sops_functional_tests_key.asc
dest: /tmp/sops_functional_tests_key.asc
- name: Import sops test GPG key on localhost
command: gpg --import /tmp/sops_functional_tests_key.asc
diff --git a/ansible_collections/community/sops/tests/integration/targets/filter__latest_version/aliases b/ansible_collections/community/sops/tests/integration/targets/filter__latest_version/aliases
new file mode 100644
index 000000000..977ec3882
--- /dev/null
+++ b/ansible_collections/community/sops/tests/integration/targets/filter__latest_version/aliases
@@ -0,0 +1,9 @@
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+gha/main
+skip/aix
+skip/osx
+skip/freebsd
+skip/python2.6 # lookups are controller only, and we no longer support Python 2.6 on the controller
diff --git a/ansible_collections/community/sops/tests/integration/targets/filter__latest_version/tasks/main.yml b/ansible_collections/community/sops/tests/integration/targets/filter__latest_version/tasks/main.yml
new file mode 100644
index 000000000..6d1ba661d
--- /dev/null
+++ b/ansible_collections/community/sops/tests/integration/targets/filter__latest_version/tasks/main.yml
@@ -0,0 +1,39 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- name: Test _latest_version filter
+ ansible.builtin.assert:
+ that:
+ - list_0 | community.sops._latest_version == '1.0.0'
+ - list_1 | community.sops._latest_version == '1.2.1'
+ - list_2 | community.sops._latest_version == '1.2.1'
+ - list_3 | community.sops._latest_version == '1.2.3'
+ - list_4 | community.sops._latest_version == ''
+ - "[] | community.sops._latest_version == ''"
+ vars:
+ list_0:
+ - '1'
+ - '1.0'
+ - 1.0.0
+ list_1:
+ - '1.0'
+ - 1.2.1
+ - 1.0.0
+ list_2:
+ - '1.0'
+ - 1.2.1
+ - 1.2.1-rc.1
+ - 1.0.0
+ list_3:
+ - '1.0'
+ - 1.2.3
+ - 1.4.0-rc.1
+ - 1.4.0-a1+5
+ - 1.4.0+5
+ - 1.0.0
+ list_4:
+ - 1.4.0-rc.1
+ - 1.4.0-a1+5
+ - 1.4.0+5
diff --git a/ansible_collections/community/sops/tests/integration/targets/role_install_latest/meta/main.yml b/ansible_collections/community/sops/tests/integration/targets/role_install_latest/meta/main.yml
new file mode 100644
index 000000000..2fcd152f9
--- /dev/null
+++ b/ansible_collections/community/sops/tests/integration/targets/role_install_latest/meta/main.yml
@@ -0,0 +1,7 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+dependencies:
+ - setup_pkg_mgr
diff --git a/ansible_collections/community/sops/tests/integration/targets/role_install_localhost_remote/meta/main.yml b/ansible_collections/community/sops/tests/integration/targets/role_install_localhost_remote/meta/main.yml
new file mode 100644
index 000000000..2fcd152f9
--- /dev/null
+++ b/ansible_collections/community/sops/tests/integration/targets/role_install_localhost_remote/meta/main.yml
@@ -0,0 +1,7 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+dependencies:
+ - setup_pkg_mgr
diff --git a/ansible_collections/community/sops/tests/integration/targets/role_install_version/meta/main.yml b/ansible_collections/community/sops/tests/integration/targets/role_install_version/meta/main.yml
new file mode 100644
index 000000000..2fcd152f9
--- /dev/null
+++ b/ansible_collections/community/sops/tests/integration/targets/role_install_version/meta/main.yml
@@ -0,0 +1,7 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+dependencies:
+ - setup_pkg_mgr
diff --git a/ansible_collections/community/sops/tests/integration/targets/role_install_version/tasks/main.yml b/ansible_collections/community/sops/tests/integration/targets/role_install_version/tasks/main.yml
index 037a13b58..6443596b5 100644
--- a/ansible_collections/community/sops/tests/integration/targets/role_install_version/tasks/main.yml
+++ b/ansible_collections/community/sops/tests/integration/targets/role_install_version/tasks/main.yml
@@ -38,3 +38,21 @@
that:
- >-
'sops 3.7.0' in output.stdout
+
+- name: Install sops 3.8.0-rc.1
+ include_role:
+ name: community.sops.install
+ vars:
+ sops_version: 3.8.0-rc.1
+ sops_github_token: "{{ github_token | default('') | string }}"
+
+- name: Figure out sops version
+ command:
+ cmd: sops --version --disable-version-check
+ register: output
+
+- name: Check sops version
+ assert:
+ that:
+ - >-
+ 'sops 3.8.0-rc.1' == output.stdout
diff --git a/ansible_collections/community/sops/tests/integration/targets/setup_pkg_mgr/tasks/archlinux.yml b/ansible_collections/community/sops/tests/integration/targets/setup_pkg_mgr/tasks/archlinux.yml
new file mode 100644
index 000000000..f471cc19a
--- /dev/null
+++ b/ansible_collections/community/sops/tests/integration/targets/setup_pkg_mgr/tasks/archlinux.yml
@@ -0,0 +1,28 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# Since Arch Linux is a rolling distribution, it regularly needs its packages upgraded, otherwise some tests might
+# stop working due to conflicts during package installation. Since there is no good way to do this on container
+# startup time, we use the setup_pkg_mgr setup role to do this once per CI run (hopefully). In case the Arch Linux
+# tests are run outside of a container, we're using a date-based tag (see below) to avoid this running more than
+# once per day.
+
+- name: Create tag
+ copy:
+ dest: /tmp/.ansible_archlinux_sysupgrade_tag
+ content: |
+ Last ArchLinux system upgrade by integration tests was done on {{ ansible_facts.date_time.date }}.
+ register: archlinux_upgrade_tag
+
+- name: Upgrade all packages
+ pacman:
+ update_cache: true
+ upgrade: true
+ when: archlinux_upgrade_tag is changed
+
+- name: Remove EXTERNALLY-MANAGED file
+ file:
+ path: /usr/lib/python{{ ansible_python.version.major }}.{{ ansible_python.version.minor }}/EXTERNALLY-MANAGED
+ state: absent
diff --git a/ansible_collections/community/sops/tests/integration/targets/setup_pkg_mgr/tasks/main.yml b/ansible_collections/community/sops/tests/integration/targets/setup_pkg_mgr/tasks/main.yml
new file mode 100644
index 000000000..5b4c0be38
--- /dev/null
+++ b/ansible_collections/community/sops/tests/integration/targets/setup_pkg_mgr/tasks/main.yml
@@ -0,0 +1,9 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+- when: ansible_os_family == "Archlinux"
+ block:
+ - name: ArchLinux specific setup
+ include_tasks: archlinux.yml
diff --git a/ansible_collections/community/sops/tests/integration/targets/setup_sops/meta/main.yml b/ansible_collections/community/sops/tests/integration/targets/setup_sops/meta/main.yml
new file mode 100644
index 000000000..2fcd152f9
--- /dev/null
+++ b/ansible_collections/community/sops/tests/integration/targets/setup_sops/meta/main.yml
@@ -0,0 +1,7 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+dependencies:
+ - setup_pkg_mgr
diff --git a/ansible_collections/community/sops/tests/integration/targets/setup_sops/tasks/install.yml b/ansible_collections/community/sops/tests/integration/targets/setup_sops/tasks/install.yml
index 29ff98e18..86416fa68 100644
--- a/ansible_collections/community/sops/tests/integration/targets/setup_sops/tasks/install.yml
+++ b/ansible_collections/community/sops/tests/integration/targets/setup_sops/tasks/install.yml
@@ -19,7 +19,7 @@
- name: Download sops test GPG key on localhost
get_url:
- url: https://raw.githubusercontent.com/mozilla/sops/master/pgp/sops_functional_tests_key.asc
+ url: https://raw.githubusercontent.com/getsops/sops/master/pgp/sops_functional_tests_key.asc
dest: /tmp/sops_functional_tests_key.asc
delegate_to: localhost
@@ -43,7 +43,7 @@
- name: Download sops test GPG key on remote
get_url:
- url: https://raw.githubusercontent.com/mozilla/sops/master/pgp/sops_functional_tests_key.asc
+ url: https://raw.githubusercontent.com/getsops/sops/master/pgp/sops_functional_tests_key.asc
dest: /tmp/sops_functional_tests_key.asc
- name: Import sops test GPG key on remote
diff --git a/ansible_collections/community/sops/tests/integration/targets/var_sops/README.md b/ansible_collections/community/sops/tests/integration/targets/var_sops/README.md
index 38a3cfaa5..dad222e7a 100644
--- a/ansible_collections/community/sops/tests/integration/targets/var_sops/README.md
+++ b/ansible_collections/community/sops/tests/integration/targets/var_sops/README.md
@@ -23,4 +23,4 @@ If possible, extend an existing test. If that's not possible, or if you are afra
2. Create a `playbook.yml` and `validate.sh` in there (copy from a similar test and adjust);
3. Create subdirectories `group_vars` and/or `host_vars` and fill them as needed.
-For creating sops encrypted files, use the private GPG keys from https://raw.githubusercontent.com/mozilla/sops/master/pgp/sops_functional_tests_key.asc. There is a `.sops.yaml` file in this directory which makes sure that sops automatically uses the correct one of the keys provided in that file.
+For creating sops encrypted files, use the private GPG keys from https://raw.githubusercontent.com/getsops/sops/master/pgp/sops_functional_tests_key.asc. There is a `.sops.yaml` file in this directory which makes sure that sops automatically uses the correct one of the keys provided in that file.
diff --git a/ansible_collections/community/sops/tests/sanity/extra/extra-docs.py b/ansible_collections/community/sops/tests/sanity/extra/extra-docs.py
index c636beb08..251e6d70f 100755
--- a/ansible_collections/community/sops/tests/sanity/extra/extra-docs.py
+++ b/ansible_collections/community/sops/tests/sanity/extra/extra-docs.py
@@ -17,7 +17,7 @@ def main():
suffix = ':{env}'.format(env=env["ANSIBLE_COLLECTIONS_PATH"]) if 'ANSIBLE_COLLECTIONS_PATH' in env else ''
env['ANSIBLE_COLLECTIONS_PATH'] = '{root}{suffix}'.format(root=os.path.dirname(os.path.dirname(os.path.dirname(os.getcwd()))), suffix=suffix)
p = subprocess.run(
- ['antsibull-docs', 'lint-collection-docs', '--plugin-docs', '--disallow-semantic-markup', '--skip-rstcheck', '.'],
+ ['antsibull-docs', 'lint-collection-docs', '--plugin-docs', '--skip-rstcheck', '.'],
env=env,
check=False,
)
diff --git a/ansible_collections/community/sops/tests/sanity/ignore-2.10.txt b/ansible_collections/community/sops/tests/sanity/ignore-2.10.txt
index 787dfec72..aacf26fbd 100644
--- a/ansible_collections/community/sops/tests/sanity/ignore-2.10.txt
+++ b/ansible_collections/community/sops/tests/sanity/ignore-2.10.txt
@@ -1,3 +1,6 @@
+docs/docsite/rst/guide.rst rstcheck
+plugins/modules/load_vars.py validate-modules:invalid-documentation
+plugins/modules/sops_encrypt.py validate-modules:invalid-documentation
tests/integration/targets/filter_decrypt/files/hidden-binary.yaml yamllint:error
tests/integration/targets/filter_decrypt/files/hidden-json.yaml yamllint:error
tests/integration/targets/lookup_sops/files/hidden-binary.yaml yamllint:error
diff --git a/ansible_collections/community/sops/tests/sanity/ignore-2.11.txt b/ansible_collections/community/sops/tests/sanity/ignore-2.11.txt
index 787dfec72..0db7d8897 100644
--- a/ansible_collections/community/sops/tests/sanity/ignore-2.11.txt
+++ b/ansible_collections/community/sops/tests/sanity/ignore-2.11.txt
@@ -1,3 +1,5 @@
+plugins/modules/load_vars.py validate-modules:invalid-documentation
+plugins/modules/sops_encrypt.py validate-modules:invalid-documentation
tests/integration/targets/filter_decrypt/files/hidden-binary.yaml yamllint:error
tests/integration/targets/filter_decrypt/files/hidden-json.yaml yamllint:error
tests/integration/targets/lookup_sops/files/hidden-binary.yaml yamllint:error
diff --git a/ansible_collections/community/sops/tests/sanity/ignore-2.12.txt b/ansible_collections/community/sops/tests/sanity/ignore-2.12.txt
index 787dfec72..0db7d8897 100644
--- a/ansible_collections/community/sops/tests/sanity/ignore-2.12.txt
+++ b/ansible_collections/community/sops/tests/sanity/ignore-2.12.txt
@@ -1,3 +1,5 @@
+plugins/modules/load_vars.py validate-modules:invalid-documentation
+plugins/modules/sops_encrypt.py validate-modules:invalid-documentation
tests/integration/targets/filter_decrypt/files/hidden-binary.yaml yamllint:error
tests/integration/targets/filter_decrypt/files/hidden-json.yaml yamllint:error
tests/integration/targets/lookup_sops/files/hidden-binary.yaml yamllint:error
diff --git a/ansible_collections/community/sops/tests/sanity/ignore-2.13.txt b/ansible_collections/community/sops/tests/sanity/ignore-2.13.txt
index 787dfec72..be35d9d66 100644
--- a/ansible_collections/community/sops/tests/sanity/ignore-2.13.txt
+++ b/ansible_collections/community/sops/tests/sanity/ignore-2.13.txt
@@ -1,3 +1,7 @@
+plugins/lookup/sops.py validate-modules:invalid-documentation
+plugins/modules/load_vars.py validate-modules:invalid-documentation
+plugins/modules/sops_encrypt.py validate-modules:invalid-documentation
+plugins/vars/sops.py validate-modules:invalid-documentation
tests/integration/targets/filter_decrypt/files/hidden-binary.yaml yamllint:error
tests/integration/targets/filter_decrypt/files/hidden-json.yaml yamllint:error
tests/integration/targets/lookup_sops/files/hidden-binary.yaml yamllint:error
diff --git a/ansible_collections/community/sops/tests/sanity/ignore-2.14.txt b/ansible_collections/community/sops/tests/sanity/ignore-2.14.txt
index 787dfec72..be35d9d66 100644
--- a/ansible_collections/community/sops/tests/sanity/ignore-2.14.txt
+++ b/ansible_collections/community/sops/tests/sanity/ignore-2.14.txt
@@ -1,3 +1,7 @@
+plugins/lookup/sops.py validate-modules:invalid-documentation
+plugins/modules/load_vars.py validate-modules:invalid-documentation
+plugins/modules/sops_encrypt.py validate-modules:invalid-documentation
+plugins/vars/sops.py validate-modules:invalid-documentation
tests/integration/targets/filter_decrypt/files/hidden-binary.yaml yamllint:error
tests/integration/targets/filter_decrypt/files/hidden-json.yaml yamllint:error
tests/integration/targets/lookup_sops/files/hidden-binary.yaml yamllint:error
diff --git a/ansible_collections/community/sops/tests/sanity/ignore-2.17.txt b/ansible_collections/community/sops/tests/sanity/ignore-2.17.txt
new file mode 100644
index 000000000..787dfec72
--- /dev/null
+++ b/ansible_collections/community/sops/tests/sanity/ignore-2.17.txt
@@ -0,0 +1,4 @@
+tests/integration/targets/filter_decrypt/files/hidden-binary.yaml yamllint:error
+tests/integration/targets/filter_decrypt/files/hidden-json.yaml yamllint:error
+tests/integration/targets/lookup_sops/files/hidden-binary.yaml yamllint:error
+tests/integration/targets/lookup_sops/files/hidden-json.yaml yamllint:error
diff --git a/ansible_collections/community/sops/tests/sanity/ignore-2.17.txt.license b/ansible_collections/community/sops/tests/sanity/ignore-2.17.txt.license
new file mode 100644
index 000000000..edff8c768
--- /dev/null
+++ b/ansible_collections/community/sops/tests/sanity/ignore-2.17.txt.license
@@ -0,0 +1,3 @@
+GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+SPDX-License-Identifier: GPL-3.0-or-later
+SPDX-FileCopyrightText: Ansible Project
diff --git a/ansible_collections/community/sops/tests/sanity/ignore-2.9.txt b/ansible_collections/community/sops/tests/sanity/ignore-2.9.txt
index 787dfec72..aacf26fbd 100644
--- a/ansible_collections/community/sops/tests/sanity/ignore-2.9.txt
+++ b/ansible_collections/community/sops/tests/sanity/ignore-2.9.txt
@@ -1,3 +1,6 @@
+docs/docsite/rst/guide.rst rstcheck
+plugins/modules/load_vars.py validate-modules:invalid-documentation
+plugins/modules/sops_encrypt.py validate-modules:invalid-documentation
tests/integration/targets/filter_decrypt/files/hidden-binary.yaml yamllint:error
tests/integration/targets/filter_decrypt/files/hidden-json.yaml yamllint:error
tests/integration/targets/lookup_sops/files/hidden-binary.yaml yamllint:error
diff --git a/ansible_collections/community/vmware/.github/workflows/ansible-test.yml b/ansible_collections/community/vmware/.github/workflows/ansible-test.yml
index 8c9bbbe18..1cbb1a26f 100644
--- a/ansible_collections/community/vmware/.github/workflows/ansible-test.yml
+++ b/ansible_collections/community/vmware/.github/workflows/ansible-test.yml
@@ -20,6 +20,7 @@ on:
branches:
- main
- stable-2.x
+ - stable-3.x
pull_request:
# Run CI once per day (at 07:12 UTC)
# This ensures that even if there haven't been commits that we are still
@@ -61,9 +62,10 @@ jobs:
# - stable-2.10 # Only if your collection supports ansible-base 2.10
# - stable-2.11 # Only if your collection supports ansible-core 2.11
# - stable-2.12
- - stable-2.13
- - stable-2.14
+ # - stable-2.13
+ # - stable-2.14
- stable-2.15
+ - stable-2.16
# - devel
- milestone
# Ansible-test on various stable branches does not yet work well with cgroups v2.
@@ -94,7 +96,9 @@ jobs:
# OPTIONAL If set to true, will test only against changed files,
# which should improve CI performance. See limitations on
# https://github.com/ansible-community/ansible-test-gh-action#pull-request-change-detection
- pull-request-change-detection: true
+ pull-request-change-detection: false
+ # Disable Codecov
+ coverage: never
###
# Unit tests (OPTIONAL)
@@ -123,9 +127,10 @@ jobs:
# - stable-2.10 # Only if your collection supports ansible-base 2.10
# - stable-2.11 # Only if your collection supports ansible-core 2.11
# - stable-2.12
- - stable-2.13
- - stable-2.14
+ # - stable-2.13
+ # - stable-2.14
- stable-2.15
+ - stable-2.16
# - devel
- milestone
@@ -147,7 +152,9 @@ jobs:
# OPTIONAL If set to true, will test only against changed files,
# which should improve CI performance. See limitations on
# https://github.com/ansible-community/ansible-test-gh-action#pull-request-change-detection
- pull-request-change-detection: true
+ pull-request-change-detection: false
+ # Disable Codecov
+ coverage: never
check: # This job does nothing and is only used for the branch protection
# or multi-stage CI jobs, like making sure that all tests pass before
diff --git a/ansible_collections/community/vmware/.github/workflows/extra-docs-linting.yml b/ansible_collections/community/vmware/.github/workflows/extra-docs-linting.yml
index df6a9636c..b36247113 100644
--- a/ansible_collections/community/vmware/.github/workflows/extra-docs-linting.yml
+++ b/ansible_collections/community/vmware/.github/workflows/extra-docs-linting.yml
@@ -5,6 +5,7 @@ on:
branches:
- main
- stable-2.x
+ - stable-3.x
pull_request:
# Run CI once per day (at 07:12 UTC)
# This ensures that even if there haven't been commits that we are still testing against latest version of ansible-test for each ansible-base version
diff --git a/ansible_collections/community/vmware/.github/workflows/import-galaxy.yml b/ansible_collections/community/vmware/.github/workflows/import-galaxy.yml
new file mode 100644
index 000000000..0c0ee402a
--- /dev/null
+++ b/ansible_collections/community/vmware/.github/workflows/import-galaxy.yml
@@ -0,0 +1,20 @@
+---
+# Copyright (c) Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+name: import-galaxy
+'on':
+ # Run CI against all pushes (direct commits, also merged PRs) to main, and all Pull Requests
+ push:
+ branches:
+ - main
+ - stable-*
+ pull_request:
+
+jobs:
+ import-galaxy:
+ permissions:
+ contents: read
+ name: Test to import built collection artifact with Galaxy importer
+ uses: ansible-community/github-action-test-galaxy-import/.github/workflows/test-galaxy-import.yml@main
diff --git a/ansible_collections/community/vmware/.gitignore b/ansible_collections/community/vmware/.gitignore
index 4cb80191f..d1e2cb20e 100644
--- a/ansible_collections/community/vmware/.gitignore
+++ b/ansible_collections/community/vmware/.gitignore
@@ -389,3 +389,6 @@ changelogs/.plugin-cache.yaml
# End of https://www.gitignore.io/api/git,linux,pydev,python,windows,pycharm+all,jupyternotebook,vim,webstorm,emacs,dotenv
tests/integration/cloud-config-vcenter.ini
+
+# Visual Studio Code
+.vscode \ No newline at end of file
diff --git a/ansible_collections/community/vmware/CHANGELOG.rst b/ansible_collections/community/vmware/CHANGELOG.rst
index 518d1df19..2c9e8318a 100644
--- a/ansible_collections/community/vmware/CHANGELOG.rst
+++ b/ansible_collections/community/vmware/CHANGELOG.rst
@@ -4,1081 +4,77 @@ community.vmware Release Notes
.. contents:: Topics
+This changelog describes changes after version 3.9.0.
-v3.7.0
+v4.2.0
======
Minor Changes
-------------
-- vmware_cluster_drs_recommendations - Add the Module to apply the drs recommendations (https://github.com/ansible-collections/community.vmware/pull/1736)
-- vmware_guest_serial_port - add support for proxyURI parameter to enable use of a virtual serial port concentrator (https://github.com/ansible-collections/community.vmware/issues/1742)
+- Add standard function vmware_argument_spec() from module_utils for using default env fallback function. https://github.com/ansible-collections/community.vmware/issues/1977
+- vmware_first_class_disk_info - Add a module to gather informations about first class disks. (https://github.com/ansible-collections/community.vmware/pull/1996). (https://github.com/ansible-collections/community.vmware/issues/1988).
+- vmware_host_facts - Add the possibility to get the related datacenter. (https://github.com/ansible-collections/community.vmware/pull/1994).
+- vmware_vm_inventory - Add parameter `subproperties` (https://github.com/ansible-collections/community.vmware/pull/1972).
+- vmware_vmkernel - Add the function to set the enable_backup_nfc setting (https://github.com/ansible-collections/community.vmware/pull/1978)
+- vsphere_copy - Add parameter to tell vsphere_copy which diskformat is being uploaded (https://github.com/ansible-collections/community.vmware/pull/1995).
-Bugfixes
---------
-
-- Add missing modules to runtime.yml (https://github.com/ansible-collections/community.vmware/pull/1764).
-- vmware_vm_info - Add missing show_folder parameter (https://github.com/ansible-collections/community.vmware/issues/1709).
-
-New Modules
------------
-
-- vmware_cluster_drs_recommendations - Apply DRS Recommendations
-- vmware_vsan_release_catalog - Uploads the vSAN Release Catalog
-
-v3.6.0
-======
-
-Bugfixes
---------
-
-- vmware_guest - Fixed issue where custom attributes were not getting set on VM creation (https://github.com/ansible-collections/community.vmware/pull/1713)
-- vmware_vsan_health_info - Fix return value (https://github.com/ansible-collections/community.vmware/pull/1706).
-
-New Modules
------------
-
-- vsan_health_silent_checks - Silence vSAN health checks
-
-v3.5.0
-======
-
-Major Changes
--------------
-
-- Use true/false (lowercase) for boolean values in documentation and examples (https://github.com/ansible-collections/community.vmware/issues/1660).
-
-Minor Changes
--------------
-
-- vmware_migrate_vmk - Improve error handling (https://github.com/ansible-collections/community.vmware/issues/1118).
-- vmware_tag - Allow to use category names for tag management (https://github.com/ansible-collections/community.vmware/issues/1614).
-- vmware_tag_manager - Improve performance of tag attachments and detachments (https://github.com/ansible-collections/community.vmware/issues/1603).
-- vmware_tools - ansible_vmware_guest_uuid added for easier use of vmware_tools connection plugin with vmware_vm_inventory plugin
-- vmware_vm_info - Add several parameters to skip discovering some information (https://github.com/ansible-collections/community.vmware/issues/1682)
-
-Bugfixes
---------
-
-- vmware_cross_vc_clone - Fix SSL Thumbprint validation to ignore if destination_vcenter_validate_certs is false (https://github.com/ansible-collections/community.vmware/issues/1433).
-- vmware_guest - Fixes adding new NVDIMM device issue by connecting to ESXi host (https://github.com/ansible-collections/community.vmware/issues/1644).
-- vmware_guest_cross_vc_clone - Fix vim.fault.NotAuthenticated issue (https://github.com/ansible-collections/community.vmware/issues/1223).
-- vmware_guest_cross_vc_clone - New parameter timeout in order to allow clone running longer than 1 hour
-- vmware_tag - Fix a performance issue during tag processing (https://github.com/ansible-collections/community.vmware/issues/1603).
-
-New Modules
------------
-
-- vmware_vsan_hcl_db - Manages the vSAN Hardware Compatibility List (HCL) database
-
-v3.4.0
-======
-
-Minor Changes
--------------
-
-- vmware_guest_disk - Add support for IDE disk add, remove or reconfigure, and change to gather same VM disk info as in vmware_guest_disk_info (https://github.com/ansible-collections/community.vmware/issues/1428).
-- vmware_guest_disk - Extend return value documentation for vmware_guest_disk (https://github.com/ansible-collections/community.vmware/pull/1641)
-- vmware_guest_disk_info - Move gather VM disk info function to vm_device_helper.py (https://github.com/ansible-collections/community.vmware/issues/1617)
-- vmware_vmotion - New parameter timeout in order to allow vmotions running longer than 1 hour (https://github.com/ansible-collections/community.vmware/pulls/1629).
-
-Bugfixes
---------
-
-- scenario guides - Fix broken references (https://github.com/ansible-collections/community.vmware/issues/1610).
-- various - Fix new pylint issues (https://github.com/ansible-collections/community.vmware/pull/1637).
-- vmware_cluster_info - Fix pylint issues (https://github.com/ansible-collections/community.vmware/issues/1618).
-- vmware_dvswitch - Fix pylint issues (https://github.com/ansible-collections/community.vmware/issues/1618).
-- vmware_dvswitch_lacp - Fix pylint issues (https://github.com/ansible-collections/community.vmware/issues/1618).
-- vmware_dvswitch_uplink_pg - Fix pylint issues (https://github.com/ansible-collections/community.vmware/issues/1618).
-- vmware_guest_custom_attributes - Fixes assigning attributes to new VMs (https://github.com/ansible-collections/community.vmware/issues/1606).
-- vmware_guest_disk - Fix wrong key in the documentation of the return values (https://github.com/ansible-collections/community.vmware/issues/1615)
-- vmware_object_rename - Add missing quotation mark to error message (https://github.com/ansible-collections/community.vmware/issues/1633)
-- vmware_portgroup - Fix pylint issues (https://github.com/ansible-collections/community.vmware/issues/1618).
-- vmware_vcenter_settings - Fix pylint issues (https://github.com/ansible-collections/community.vmware/issues/1618).
-- vmware_vcenter_statistics - Fix pylint issues (https://github.com/ansible-collections/community.vmware/issues/1618).
-
-v3.3.0
-======
-
-Minor Changes
--------------
-
-- vmware_cluster_drs - Add predictive DRS Setting (https://github.com/ansible-collections/community.vmware/pull/1542).
-- vmware_guest_network - Add PVRDMA network adapter type (https://github.com/ansible-collections/community.vmware/pull/1579).
-
-Bugfixes
---------
-
-- vmware_cluster_dpm - Fix an issue that the slider and the values of the host_power_action_rate works invertet in the vCenter
-- vmware_cluster_drs - Fix drs_vmotion_rate so that the value corresponds to the vCenter UI. Previously, choosing 1 / 2 configured a migration threshold of 5 / 4 and vice versa (https://github.com/ansible-collections/community.vmware/pull/1542).
-- vmware_guest - Fix check mode (https://github.com/ansible-collections/community.vmware/issues/1272).
-- vmware_host_lockdown_exceptions - Avoid setting exception users to what they already are (https://github.com/ansible-collections/community.vmware/pull/1585).
-- vmware_tools - Fix an issue with pyVmomi 8.0.0.1 (https://github.com/ansible-collections/community.vmware/issues/1578).
-
-New Modules
------------
-
-- vmware_guest_vgpu_info - Gather information about vGPU profiles of the specified virtual machine in the given vCenter infrastructure
-
-v3.2.0
-======
-
-Minor Changes
--------------
-
-- vmware_guest - Add sub-option to configure virtual performance counters (https://github.com/ansible-collections/community.vmware/issues/1511).
-- vmware_guest - Adding sub-options to configure CPU and memory shares (https://github.com/ansible-collections/community.vmware/issues/356).
-- vmware_guest_boot_manager - Add a new parameter boot_hdd_name to specify the boot disk name(https://github.com/ansible-collections/community.vmware/pull/1543).
-- vmware_guest_custom_attributes - Improve the code quality and added the return value for diff(https://github.com/ansible-collections/community.vmware/pull/1532).
-- vmware_vm_info - Adding resource pool of the VM to result (https://github.com/ansible-collections/community.vmware/pull/1551).
-
-Bugfixes
---------
-
-- vmware_dvs_portgroup - Fix an issue when deleting portgroups (https://github.com/ansible-collections/community.vmware/issues/1522).
-- vmware_guest_instant_clone - Fix an issue with pyVmomi 8.0.0.1 (https://github.com/ansible-collections/community.vmware/issues/1555).
-- vmware_host_lockdown - Fix issue `'VmwareLockdownManager' object has no attribute 'warn'` (https://github.com/ansible-collections/community.vmware/pull/1540).
-- vmware_object_custom_attributes_info - Fixed an issue that has occurred an error if a custom attribute is the global type(https://github.com/ansible-collections/community.vmware/pull/1541).
-- vmware_portgroup_info - Fix an issue that can fail the module after manually updating a portgroup through vCenter (https://github.com/ansible-collections/community.vmware/issues/1544).
-
-New Modules
------------
-
-- vmware_custom_attribute - Manage custom attributes definitions
-- vmware_custom_attribute_manager - Manage custom attributes from VMware for the given vSphere object
-
-v3.1.0
-======
-
-Minor Changes
--------------
-
-- vmware_dvs_portgroup - Add deprecaded securityPolicyOverrideAllowed because without it make problems if securityPolicyOverrideAllowed and macManagementOverrideAllowed has not the same value (https://github.com/ansible-collections/community.vmware/pull/1508)
-- vmware_guest - Adding `script_text` parameter to execute scripts in Linux guests (https://github.com/ansible-collections/community.vmware/pull/1485).
-- vmware_host_lockdown - Add the ability to enable ``strict`` lockdown mode (https://github.com/ansible-collections/community.vmware/pull/1514).
-- vmware_host_lockdown - Add two new choices for ``state``, ``disabled`` and ``normal``, to replace ``absent`` and ``present``. Please note that ``absent`` and ``present`` will be removed in the next major release (https://github.com/ansible-collections/community.vmware/pull/1514).
-- vmware_host_lockdown - Replace deprecated vSphere API calls (https://github.com/ansible-collections/community.vmware/pull/1514).
-
-Bugfixes
---------
-
-- vmware_guest_file_operation - Add a new parameter for timeout(https://github.com/ansible-collections/community.vmware/pull/1513).
-- vmware_tag_manager - Fix a performance issue during tag processing (https://github.com/ansible-collections/community.vmware/issues/1503).
-- vmware_tag_manager - Fix an issue that causes a failure when changing a single cardinal tag category (https://github.com/ansible-collections/community.vmware/issues/1501).
-
-New Modules
------------
-
-- vmware_host_lockdown_exceptions - Manage Lockdown Mode Exception Users
-
-v3.0.0
-======
-
-Minor Changes
--------------
-
-- vmware_guest_disk - Adding `iolimit` modifications of an existing disk without changing size (https://github.com/ansible-collections/community.vmware/pull/1466).
-
-Breaking Changes / Porting Guide
---------------------------------
-
-- Removed support for ansible-core version < 2.13.0.
-- vmware_dvs_portgroup - Add a new sub-option `inherited` to the `in_traffic_shaping` parameter. This means you can keep the setting as-is by not defining the parameter, but also that you have to define the setting as not `inherited` if you want to override it at the PG level (https://github.com/ansible-collections/community.vmware/pull/1483).
-- vmware_dvs_portgroup - Add a new sub-option `inherited` to the `out_traffic_shaping` parameter. This means you can keep the setting as-is by not defining the parameter, but also that you have to define the setting as not `inherited` if you want to override it at the PG level (https://github.com/ansible-collections/community.vmware/pull/1483).
-- vmware_dvs_portgroup - Change the type of `net_flow` to string to allow setting it implicitly to inherited or to keep the value as-is. This means you can keep the setting as-is by not defining the parameter, but also that while `true` or `no` still work, `True` or `Off` (uppercase) won't (https://github.com/ansible-collections/community.vmware/pull/1483).
-- vmware_dvs_portgroup - Remove support for vSphere API less than 6.7.
-- vmware_dvs_portgroup - Remove the default for `network_policy` and add a new sub-option `inherited`. This means you can keep the setting as-is by not defining the parameter, but also that you have to define the setting as not `inherited` if you want to override it at the PG level (https://github.com/ansible-collections/community.vmware/pull/1483).
-- vmware_dvs_portgroup_info - Remove support for vSphere API less than 6.7.
-- vmware_dvswitch - Remove support for vSphere API less than 6.7.
-- vmware_dvswitch_uplink_pg - Remove support for vSphere API less than 6.7.
-- vmware_guest_boot_manager - Remove default for ``secure_boot_enabled`` parameter (https://github.com/ansible-collections/community.vmware/issues/1461).
-- vmware_vm_config_option - Dict item names in result are changed from strings joined with spaces to strings joined with underlines, e.g. `Guest fullname` is changed to `guest_fullname` (https://github.com/ansible-collections/community.vmware/issues/1268).
-- vmware_vspan_session - Remove support for vSphere API less than 6.7.
-
-Removed Features (previously deprecated)
-----------------------------------------
-
-- vca_fw - The deprecated module ``vca_fw`` has been removed.
-- vca_nat - The deprecated module ``vca_nat`` has been removed.
-- vca_vapp - The deprecated module ``vca_vapp`` has been removed.
-- vmware_dns_config - The deprecated module ``vmware_dns_config`` has been removed, you can use ``vmware_host_dns`` instead.
-- vmware_guest_network - The deprecated parameter ``networks`` has been removed, use loops to handle multiple interfaces (https://github.com/ansible-collections/community.vmware/pull/1459).
-- vmware_guest_vnc - The deprecated module ``vmware_guest_vnc`` has been removed. The VNC support has been dropped with vSphere 7 and later (https://github.com/ansible-collections/community.vmware/pull/1454).
-- vmware_host_firewall_manager - The module doesn't accept a list for ``allowed_hosts`` anymore, use a dict instead. Additionally, ``all_ip`` is now a required sub-option of ``allowed_hosts`` (https://github.com/ansible-collections/community.vmware/pull/1463).
-- vsphere_copy - The deprecated parameters ``host`` and ``login`` have been removed. Use ``hostname`` and ``username`` instead (https://github.com/ansible-collections/community.vmware/pull/1456).
-
-Bugfixes
---------
-
-- vmware_dvs_portgroup - Fix update of NetFlow Setting (https://github.com/ansible-collections/community.vmware/pull/1443).
-- vmware_tag_manager - Fix idempotency for state `set` (https://github.com/ansible-collections/community.vmware/issues/1265).
-
-New Modules
------------
-
-- vmware_datastore - Configure Datastores
-
-v2.9.1
-======
-
-Bugfixes
---------
-
-- 2.9.0 wasn't released correctly, some changes are missing from the package. Releasing 2.9.1 to fix this.
-
-v2.9.0
-======
-
-Minor Changes
--------------
-
-- vmware_cluster_ha - Add APD settings (https://github.com/ansible-collections/community.vmware/pull/1420).
-- vmware_content_library_info - Add Subscribed Libraries (https://github.com/ansible-collections/community.vmware/issues/1430).
-- vmware_drs_group_manager - Improve error handling (https://github.com/ansible-collections/community.vmware/pull/1448).
-
-Bugfixes
---------
-
-- vmware_cfg_backup - Fix a bug that failed the restore when port 80 is blocked (https://github.com/ansible-collections/community.vmware/issues/1440).
-- vmware_vswitch - Fix broken logic of `failback` parameter (https://github.com/ansible-collections/community.vmware/issues/1431).
-
-v2.8.0
-======
-
-Minor Changes
--------------
-
-- vmware_cfg_backup - Improve error message (https://github.com/ansible-collections/community.vmware/pull/1388).
-- vmware_dvs_portgroup - Fix a `spec.numPorts is None` issue when the `num_ports` parameter isn't set (https://github.com/ansible-collections/community.vmware/pull/1419).
-- vmware_guest_sendkey - Add CTRL_X binding support (https://github.com/ansible-collections/community.vmware/pull/1376).
-- vmware_host_vmnic_info - add CDP information to output when applicable (https://github.com/ansible-collections/community.vmware/pull/1418).
-
-Bugfixes
---------
-
-- vmware_cfg_backup - Fix a possible urlopen error when connecting directly to an ESXi host (https://github.com/ansible-collections/community.vmware/issues/1383).
-- vmware_guest - Fix no fail attribute issue (https://github.com/ansible-collections/community.vmware/issues/1401).
-- vmware_vm_info - Fix 'NoneType' object has no attribute 'datastoreUrl' for inaccessible VMs (https://github.com/ansible-collections/community.vmware/issues/1407).
-
-v2.7.0
-======
-
-Minor Changes
--------------
-
-- vmware_dvswitch.py - Add Netflow Settings. (https://github.com/ansible-collections/community.vmware/pull/1352)
-- vmware_dvswitch_nioc.py - Add backupNfc and nvmetcp to the resources. (https://github.com/ansible-collections/community.vmware/pull/1351)
-- vmware_guest_disk - Add a new disk type to support add/reconfigure/remove vPMem disk (https://github.com/ansible-collections/community.vmware/pull/1382).
-- vmware_host_passthrough - Support the PCI id in the devices parameter(https://github.com/ansible-collections/community.vmware/pull/1365).
-- vmware_object_role_permission.py - Add StoragePod to the list of object_types. (https://github.com/ansible-collections/community.vmware/pull/1338)
-- vmware_object_role_permission_info.py - Add StoragePod and DistributedVirtalPortgroup to the list of object_types. (https://github.com/ansible-collections/community.vmware/pull/1338)
-
-Bugfixes
---------
-
-- vmware_content_deploy_ovf_template - Fixed a bug that ignored `resource_pool` in some cases. (https://github.com/ansible-collections/community.vmware/issues/1290).
-- vmware_content_deploy_template - Fixed a bug that ignored `resource_pool` in some cases. (https://github.com/ansible-collections/community.vmware/issues/1290).
-- vmware_guest_disk - Ignore datastores in maintenance mode (https://github.com/ansible-collections/community.vmware/pull/1321).
-- vmware_guest_instant_clone - Support FQPN in the folder parameter.
-- vmware_guest_network - Fix a typo in the code for SR-IOV NICs (https://github.com/ansible-collections/community.vmware/issues/1317).
-- vmware_guest_network - Fix an `AttributeError` when using SR-IOV NICs (https://github.com/ansible-collections/community.vmware/issues/1318).
-
-v2.6.0
-======
-
-Minor Changes
--------------
-
-- vmware_vmotion - Add the feature to use cluster and datastore cluster (storage pods) to define where the vmotion shold go. (https://github.com/ansible-collections/community.vmware/pull/1240)
-
-Bugfixes
---------
-
-- vmware_cfg_backup - Fix a bug that failed the module when port 80 is blocked (https://github.com/ansible-collections/community.vmware/issues/1270).
-- vmware_host_facts - Fix a bug that crashes the module when a host is disconnected (https://github.com/ansible-collections/vmware/issues/184).
-- vmware_host_vmnic_info - Fix a bug that crashes the module when a host is disconnected (https://github.com/ansible-collections/community.vmware/pull/1337).
-
-v2.5.0
-======
-
-Minor Changes
--------------
-
-- vmware_vm_info - Add the feature to get the output of allocated storage, cpu und memory. (https://github.com/ansible-collections/community.vmware/pull/1283)
-
-New Modules
------------
-
-- vmware_guest_vgpu - Modify vGPU video card profile of the specified virtual machine in the given vCenter infrastructure
-
-v2.4.0
-======
-
-Minor Changes
--------------
-
-- vmware_maintenancemode - Add support for check_mode (https://github.com/ansible-collections/community.vmware/pull/1311).
-- vmware_migrate_vmk - Add `migrate_vlan_id` to use for the VMK interface when migrating from VDS to VSS (https://github.com/ansible-collections/community.vmware/issues/1297).
-- vmware_vswitch - Add support to manage security, teaming and traffic shaping policies on vSwitches. (https://github.com/ansible-collections/community.vmware/pull/1298).
-- vmware_vswitch_info - Add support to return security, teaming and traffic shaping policies on vSwitches. (https://github.com/ansible-collections/community.vmware/pull/1309).
-
-v2.3.0
-======
-
-Major Changes
--------------
-
-- Drop VCSIM as a test target (https://github.com/ansible-collections/community.vmware/pull/1294).
-
-Minor Changes
--------------
-
-- vmware_dvs_portgroup - Add the feature to configure ingress and egress traffinc shaping and netflow on the dvs portgroup. (https://github.com/ansible-collections/community.vmware/pull/1224)
-- vmware_guest_network - Add parameters `physical_function_backing`, `virtual_function_backing` and `allow_guest_os_mtu_change` (https://github.com/ansible-collections/community.vmware/pull/1218)
-
-Bugfixes
---------
-
-- vmware_dvs_portgroup - Fix an idempotency issue when `num_ports` is unset (https://github.com/ansible-collections/community.vmware/pull/1286).
-- vmware_guest_powerstate - Ignore trailing `/` in `folder` parameter like other guest modules do (https://github.com/ansible-collections/community.vmware/issues/1238).
-- vmware_host_powerstate - Do not execute the powerstate changes in check_mode. (https://github.com/ansible-collections/community.vmware/pull/1299).
-- vmware_vmotion - Like already define in the examples, allow Storage vMotion without defining a resource pool. (https://github.com/ansible-collections/community.vmware/pull/1236).
-
-v2.2.0
-======
-
-Minor Changes
--------------
-
-- vmware_vm_info - Add the posibility to get the configuration informations of only one vm by name. (https://github.com/ansible-collections/community.vmware/pull/1241)
-
-Bugfixes
---------
-
-- vmware_dvs_host - match the list of the host nics in the correct order based on the uplink port name in vCenter (https://github.com/ansible-collections/community.vmware/issues/1242).
-- vmware_guest_powerstate - `shutdownguest` power state is not idempotent (https://github.com/ansible-collections/community.vmware/pull/1227).
-
-v2.1.0
-======
-
-Minor Changes
--------------
-
-- Remove `version_added` documentation that pre-dates the collection, that is refers to Ansible < 2.10 (https://github.com/ansible-collections/community.vmware/pull/1215).
-- vmware_guest_storage_policy - New parameter `controller_number` to support multiple SCSI controllers (https://github.com/ansible-collections/community.vmware/issues/1203).
-- vmware_object_role_permission - added VMware DV portgroup object_type for setting permissions (https://github.com/ansible-collections/community.vmware/pull/1176)
-- vmware_vm_config_option - Fix the parameter not correct issue when hostname is set to ESXi host(https://github.com/ansible-collections/community.vmware/pull/1171).
-- vmware_vm_info - adding fact about ``datastore_url`` to output (https://github.com/ansible-collections/community.vmware/pull/1143).
-
-New Modules
------------
-
-- vmware_host_user_manager - Manage users of ESXi
-
-v2.0.0
-======
-
-Minor Changes
--------------
-
-- vmware_export_ovf - Add a new parameter 'export_with_extraconfig' to support export extra config options in ovf (https://github.com/ansible-collections/community.vmware/pull/1161).
-
-Breaking Changes / Porting Guide
---------------------------------
-
-- The collection now requires at least ansible-core 2.11.0. Ansible 3 and before, and ansible-base versions are no longer supported.
-- vmware_cluster_drs - The default for ``enable`` has been changed from ``false`` to ``true``.
-- vmware_cluster_drs - The parameter alias ``enable_drs`` has been removed, use ``enable`` instead.
-- vmware_cluster_ha - The default for ``enable`` has been changed from ``false`` to ``true``.
-- vmware_cluster_ha - The parameter alias ``enable_ha`` has been removed, use ``enable`` instead.
-- vmware_cluster_vsan - The default for ``enable`` has been changed from ``false`` to ``true``.
-- vmware_cluster_vsan - The parameter alias ``enable_vsan`` has been removed, use ``enable`` instead.
-- vmware_guest - Virtualization Based Security has some requirements (``nested_virt``, ``secure_boot`` and ``iommu``) that the module silently enabled. They have to be enabled explicitly now.
-
-Removed Features (previously deprecated)
-----------------------------------------
-
-- vcenter_extension_facts - The deprecated module ``vcenter_extension_facts`` has been removed, use ``vcenter_extension_info`` instead.
-- vmware_about_facts - The deprecated module ``vmware_about_facts`` has been removed, use ``vmware_about_info`` instead.
-- vmware_category_facts - The deprecated module ``vmware_category_facts`` has been removed, use ``vmware_category_info`` instead.
-- vmware_cluster - Remove DRS configuration in favour of module ``vmware_cluster_drs``.
-- vmware_cluster - Remove HA configuration in favour of module ``vmware_cluster_ha``.
-- vmware_cluster - Remove VSAN configuration in favour of module ``vmware_cluster_vsan``.
-- vmware_cluster_facts - The deprecated module ``vmware_cluster_facts`` has been removed, use ``vmware_cluster_info`` instead.
-- vmware_datastore_facts - The deprecated module ``vmware_datastore_facts`` has been removed, use ``vmware_datastore_info`` instead.
-- vmware_drs_group_facts - The deprecated module ``vmware_drs_group_facts`` has been removed, use ``vmware_drs_group_info`` instead.
-- vmware_drs_rule_facts - The deprecated module ``vmware_drs_rule_facts`` has been removed, use ``vmware_drs_rule_info`` instead.
-- vmware_dvs_portgroup - The deprecated parameter ``portgroup_type`` has been removed, use ``port_binding`` instead.
-- vmware_dvs_portgroup_facts - The deprecated module ``vmware_dvs_portgroup_facts`` has been removed, use ``vmware_dvs_portgroup_info`` instead.
-- vmware_guest_boot_facts - The deprecated module ``vmware_guest_boot_facts`` has been removed, use ``vmware_guest_boot_info`` instead.
-- vmware_guest_customization_facts - The deprecated module ``vmware_guest_customization_facts`` has been removed, use ``vmware_guest_customization_info`` instead.
-- vmware_guest_disk_facts - The deprecated module ``vmware_guest_disk_facts`` has been removed, use ``vmware_guest_disk_info`` instead.
-- vmware_guest_facts - The deprecated module ``vmware_guest_facts`` has been removed, use ``vmware_guest_info`` instead.
-- vmware_guest_snapshot_facts - The deprecated module ``vmware_guest_snapshot_facts`` has been removed, use ``vmware_guest_snapshot_info`` instead.
-- vmware_host_capability_facts - The deprecated module ``vmware_host_capability_facts`` has been removed, use ``vmware_host_capability_info`` instead.
-- vmware_host_config_facts - The deprecated module ``vmware_host_config_facts`` has been removed, use ``vmware_host_config_info`` instead.
-- vmware_host_dns_facts - The deprecated module ``vmware_host_dns_facts`` has been removed, use ``vmware_host_dns_info`` instead.
-- vmware_host_feature_facts - The deprecated module ``vmware_host_feature_facts`` has been removed, use ``vmware_host_feature_info`` instead.
-- vmware_host_firewall_facts - The deprecated module ``vmware_host_firewall_facts`` has been removed, use ``vmware_host_firewall_info`` instead.
-- vmware_host_ntp_facts - The deprecated module ``vmware_host_ntp_facts`` has been removed, use ``vmware_host_ntp_info`` instead.
-- vmware_host_package_facts - The deprecated module ``vmware_host_package_facts`` has been removed, use ``vmware_host_package_info`` instead.
-- vmware_host_service_facts - The deprecated module ``vmware_host_service_facts`` has been removed, use ``vmware_host_service_info`` instead.
-- vmware_host_ssl_facts - The deprecated module ``vmware_host_ssl_facts`` has been removed, use ``vmware_host_ssl_info`` instead.
-- vmware_host_vmhba_facts - The deprecated module ``vmware_host_vmhba_facts`` has been removed, use ``vmware_host_vmhba_info`` instead.
-- vmware_host_vmnic_facts - The deprecated module ``vmware_host_vmnic_facts`` has been removed, use ``vmware_host_vmnic_info`` instead.
-- vmware_local_role_facts - The deprecated module ``vmware_local_role_facts`` has been removed, use ``vmware_local_role_info`` instead.
-- vmware_local_user_facts - The deprecated module ``vmware_local_user_facts`` has been removed, use ``vmware_local_user_info`` instead.
-- vmware_portgroup_facts - The deprecated module ``vmware_portgroup_facts`` has been removed, use ``vmware_portgroup_info`` instead.
-- vmware_resource_pool_facts - The deprecated module ``vmware_resource_pool_facts`` has been removed, use ``vmware_resource_pool_info`` instead.
-- vmware_tag_facts - The deprecated module ``vmware_tag_facts`` has been removed, use ``vmware_tag_info`` instead.
-- vmware_target_canonical_facts - The deprecated module ``vmware_target_canonical_facts`` has been removed, use ``vmware_target_canonical_info`` instead.
-- vmware_vm_facts - The deprecated module ``vmware_vm_facts`` has been removed, use ``vmware_vm_info`` instead.
-- vmware_vmkernel_facts - The deprecated module ``vmware_vmkernel_facts`` has been removed, use ``vmware_vmkernel_info`` instead.
-- vmware_vmkernel_ip_config - The deprecated module ``vmware_vmkernel_ip_config`` has been removed, use ``vmware_vmkernel`` instead.
-- vmware_vswitch_facts - The deprecated module ``vmware_vswitch_facts`` has been removed, use ``vmware_vswitch_info`` instead.
-
-Bugfixes
---------
-
-- Various modules and plugins - use vendored version of ``distutils.version`` included in ansible-core 2.12 if available. This avoids breakage when ``distutils`` is removed from the standard library of Python 3.12. Note that ansible-core 2.11, ansible-base 2.10 and Ansible 2.9 are right now not compatible with Python 3.12, hence this fix does not target these ansible-core/-base/2.9 versions.
-- create_nic - add advanced SR-IOV options from the VMware API (PCI dev PF/VF backing and guest OS MTU change)
-- vcenter_folder - fixed folders search collision issue (https://github.com/ansible-collections/community.vmware/issues/1112).
-- vmware_guest_network - fix a bug that can crash the module due to an uncaught exception (https://github.com/ansible-collections/community.vmware/issues/25).
-
-v1.17.0
-=======
-
-Minor Changes
--------------
-
-- vmware_datastore_info - added show_tag parameters to allow datastore tags to be read in a uniform way across _info modules (https://github.com/ansible-collections/community.vmware/pull/1085).
-- vmware_guest_disk - Added a new key 'cluster_disk' which allows you to use a filename originating from a VM with an RDM.
-- vmware_guest_disk - Added bus_sharing as an option for SCSI devices.
-- vmware_guest_disk - Enabled the use of up to 64 disks on a paravirtual SCSI controller when the hardware is version 14 or higher.
-- vmware_guest_sendkey - added additional USB scan codes for HOME and END.
-- vmware_host_scanhba - add rescan_vmfs parameter to allow rescaning for new VMFS volumes. Also add rescan_hba parameter with default true to allow for not rescaning HBAs as this might be very slow. (https://github.com/ansible-collections/community.vmware/issues/479)
-- vmware_host_snmp - implement setting syscontact and syslocation (https://github.com/ansible-collections/community.vmware/issues/1044).
-- vmware_rest_client module_util - added function get_tags_for_datastore for convenient tag collection (https://github.com/ansible-collections/community.vmware/pull/1085).
-
-Bugfixes
---------
-
-- vmware_guest - when ``customization.password`` is not defined, the Administrator password is made empty instead of setting it to string 'None' (https://github.com/ansible-collections/community.vmware/issues/1017).
-
-v1.16.0
-=======
-
-Minor Changes
--------------
-
-- vmware - add vTPM information to default gather information (https://github.com/ansible-collections/community.vmware/pull/1082).
-- vmware_guest_cross_vc_clone - Added the is_template option to mark a cloned vm/template as a template (https://github.com/ansible-collections/community.vmware/pull/996).
-
-Bugfixes
---------
-
-- update_vswitch - add the possibility to remove nics from vswitch (https://github.com/ansible-collections/community.vmware/issues/536)
-- vmware_guest_serial_port - handle correct serial backing type (https://github.com/ansible-collections/community.vmware/issues/1043).
-- vmware_host_lockdown - Fix an issue when enabling or disabling lockdown mode failes (https://github.com/ansible-collections/community.vmware/issues/1083)
-
-New Modules
------------
-
-- vmware_guest_tpm - Add or remove vTPM device for specified VM.
-
-v1.15.0
-=======
-
-Minor Changes
--------------
-
-- vm_device_helper - move NIC device types from vmware_guest module to vm_device_helper (https://github.com/ansible-collections/community.vmware/pull/998).
-
-Deprecated Features
--------------------
-
-- vmware_guest_vnc - Sphere 7.0 removed the built-in VNC server (https://docs.vmware.com/en/VMware-vSphere/7.0/rn/vsphere-esxi-vcenter-server-70-release-notes.html#productsupport).
-
-Bugfixes
---------
-
-- Fix a bug that prevented enabling VSAN on more than one vmk, risking splitting the whole cluster during interface migration scenarios (https://github.com/ansible-collections/community.vmware/issues/891)
-- vmware_deploy_ovf - Fix deploy ovf issue when there are more than one datacenter in VC (https://github.com/ansible-collections/community.vmware/issues/164).
-- vmware_deploy_ovf - fixed to display suitable the error when not exist an ovf file path (https://github.com/ansible-collections/community.vmware/pull/1065).
-- vmware_guest_powerstate - handle 'present' state as 'poweredon' (https://github.com/ansible-collections/community.vmware/pull/1033).
-- vmware_guest_tools_wait - add documentation about datacenter parameter (https://github.com/ansible-collections/community.vmware/pull/870).
-- vmware_object_rename - fixed an issue that an error has occurred when getting than 1,000 objects (https://github.com/ansible-collections/community.vmware/pull/1010).
-- vmware_vcenter_settings_info - fix to return all VCSA settings when setting vsphere to the schema and not specifying the properties (https://github.com/ansible-collections/community.vmware/pull/1050).
-- vmware_vm_inventory - remove erroneous ``ansible_host`` condition (https://github.com/ansible-collections/community.vmware/issues/975).
-
-New Modules
------------
-
-- vmware_vm_config_option - Return supported guest ID list and VM recommended config option for specific guest OS
-
-v1.14.0
-=======
-
-Minor Changes
--------------
-
-- vmware_host_service_manager - Introducing a new state "unchanged" to allow defining startup policy without defining service state or automatically starting it (https://github.com/ansible-collections/community.vmware/issues/916).
-
-Bugfixes
---------
-
-- vmware_category - fixed some issues that the errors have occurred in executing the module (https://github.com/ansible-collections/community.vmware/pull/990).
-- vmware_guest_network - Fix adding more than one NIC to a VM before powering on (https://github.com/ansible-collections/community.vmware/issues/860).
-
-v1.13.0
-=======
-
-Minor Changes
--------------
-
-- vm_device_helper - Add new functions for create, remove or reconfigure virutal NVDIMM device (https://github.com/ansible-collections/community.vmware/issues/853).
-- vmware - the scenario guides from Ansible repo migrated to collection repo.
-- vmware_guest - Add new parameter 'nvdimm' for add, remove or reconfigure virutal NVDIMM device of virtual machine (https://github.com/ansible-collections/community.vmware/issues/853).
-- vmware_guest_disk - add the capability to create and remove RDM disks from Virtual Machines.
-- vmware_guest_snapshot_info - add quiesced status in VM snapshot info (https://github.com/ansible-collections/community.vmware/pull/978)
-- vmware_host_datastore - added a new parameter to expand a datastore capacity (https://github.com/ansible-collections/community.vmware/pull/915).
-- vmware_host_inventory - filter hosts before templating hostnames (https://github.com/ansible-collections/community.vmware/issues/850).
-- vmware_portgroup - Disable traffic shaping without defining ``traffic_shaping.average_bandwidth``, ``traffic_shaping.burst_size`` and ``traffic_shaping.peak_bandwidth`` (https://github.com/ansible-collections/community.vmware/issues/955).
-- vmware_spbm - Add a new function 'find_storage_profile_by_name' (https://github.com/ansible-collections/community.vmware/issues/853).
-- vmware_vm_inventory - filter guests before templating hostnames (https://github.com/ansible-collections/community.vmware/issues/850).
-
-Bugfixes
---------
-
-- vmware - changed to use from isinstance to type in the if condition of option_diff method (https://github.com/ansible-collections/community.vmware/pull/983).
-- vmware_guest - add message for `deploy_vm` method when it fails with timeout error while customizing the VM (https://github.com/ansible-collections/community.vmware/pull/933).
-- vmware_guest_instant_clone - fixed an issue that the module should be required the guestinfo_vars parameter when executing (https://github.com/ansible-collections/community.vmware/pull/962).
-- vmware_guest_powerstate - added the datacenter parameter to fix an issue that datacenter key error has been occurring (https://github.com/ansible-collections/community.vmware/pull/924).
-- vmware_host_datastore - fixed an issue that the right error message isn't displayed (https://github.com/ansible-collections/community.vmware/pull/976).
-
-v1.12.0
-=======
-
-Minor Changes
--------------
-
-- vmware - add processing to answer if the answer question is occurred in starting the vm (https://github.com/ansible-collections/community.vmware/pull/821).
-- vmware - find_folder_by_fqpn added to support specifying folders by their fully qualified path name, defined as I(datacenter)/I(folder_type)/subfolder1/subfolder2/.
-- vmware - folder field default changed from None to vm.
-- vmware_content_deploy_ovf_template - storage_provisioning default changed from None to thin, in keeping with VMware best practices for flash storage.
-- vmware_dvs_host - implement adding pNICs to LAGs (https://github.com/ansible-collections/community.vmware/issues/112).
-- vmware_guest_instant_clone - added a new option to wait until the vmware tools start (https://github.com/ansible-collections/community.vmware/pull/904).
-- vmware_guest_instant_clone - added a reboot processing to reflect the customization parameters to an instant clone vm (https://github.com/ansible-collections/community.vmware/pull/904).
-- vmware_guest_powerstate - Add an option that answers whether it was copied or moved the vm if the vm is blocked (https://github.com/ansible-collections/community.vmware/pull/821).
-- vmware_host_inventory - support api access via proxy (https://github.com/ansible-collections/community.vmware/pull/817).
-- vmware_object_role_permission_info - added principal to provide list of individual permissions on specified entity (https://github.com/ansible-collections/community.vmware/issues/868).
-- vmware_rest_client - support proxy feature for module using this API (https://github.com/ansible-collections/community.vmware/pull/848).
-- vmware_vm_inventory - support api access via proxy (https://github.com/ansible-collections/community.vmware/pull/817).
-
-Bugfixes
---------
-
-- vmware_content_deploy_ovf_template - no longer requires host, datastore, resource_pool.
-- vmware_content_deploy_xxx - deploys to recommended datastore in specified datastore_cluster.
-- vmware_content_deploy_xxx - honors folder specified by fully qualified path name.
-- vmware_guest - Use hostname parameter in customization only if value is not None (https://github.com/ansible-collections/community.vmware/issues/655)
-
-v1.11.0
-=======
-
-Major Changes
--------------
-
-- vmware_object_custom_attributes_info - added a new module to gather custom attributes of an object (https://github.com/ansible-collections/community.vmware/pull/851).
-
-Minor Changes
--------------
-
-- vmware - added a new method to search Managed Object based on moid and object type (https://github.com/ansible-collections/community.vmware/pull/879).
-- vmware_dvswitch - Dynamically check the DVS versions vCenter supports (https://github.com/ansible-collections/community.vmware/issues/839).
-- vmware_dvswitch - Implement network_policy parameter with suboptions promiscuous, forged_transmits and mac_changes (https://github.com/ansible-collections/community.vmware/issues/833).
-- vmware_guest - Make the requirements for Virtualization Based Security explicit (https://github.com/ansible-collections/community.vmware/pull/816).
-- vmware_guest - New parameter ``secure_boot`` to manage (U)EFI secure boot on VMs (https://github.com/ansible-collections/community.vmware/pull/816).
-- vmware_guest - New parameter ``vvtd`` to manage Intel Virtualization Technology for Directed I/O on VMs (https://github.com/ansible-collections/community.vmware/pull/816).
-- vmware_guest_controller - added bus_sharing property to scsi controllers (https://github.com/ansible-collections/community.vmware/pull/878).
-- vmware_guest_instant_clone - added the the guestinfo_vars parameter to provide GuestOS Customization functionality in instant cloned VM (https://github.com/ansible-collections/community.vmware/pull/796).
-- vmware_host_custom_attributes - new module (https://github.com/ansible-collections/community.vmware/pull/838).
-- vmware_host_inventory - added ability for username to be a vault encrypted variable, and updated documentation to reflect ability for username and password to be vaulted. (https://github.com/ansible-collections/community.vmware/issues/854).
-- vmware_host_passthrough - added a new module to enable or disable passthrough of PCI devices with ESXi host has (https://github.com/ansible-collections/community.vmware/pull/872).
-- vmware_host_tcpip_stacks - added ipv6_gateway parameter and nsx_overlay as an alias of vxlan (https://github.com/ansible-collections/community.vmware/pull/834).
-- vmware_host_vmnic_info - add LLDP information to output when applicable (https://github.com/ansible-collections/community.vmware/pull/828).
-- vmware_object_custom_attributes_info - added a new parameter to support moid (https://github.com/ansible-collections/community.vmware/pull/879).
-- vmware_vcenter_settings.py - Add advanced_settings parameter (https://github.com/ansible-collections/community.vmware/pull/819).
-- vmware_vm_inventory - added ability for username to be a vault encrypted variable, and updated documentation to reflect ability for username and password to be vaulted. (https://github.com/ansible-collections/community.vmware/issues/854).
-
-Bugfixes
---------
-
-- vmware - fix that the return value should be returned None if moId doesn't exist of a virtual machine (https://github.com/ansible-collections/community.vmware/pull/867).
-- vmware_vmotion - implement new parameter named destination_datacenter to fix failure to move storage when datastores are shared across datacenters (https://github.com/ansible-collections/community.vmware/issues/858)
-
-New Plugins
------------
-
-Inventory
-~~~~~~~~~
-
-- vmware_host_inventory - VMware ESXi hostsystem inventory source
-
-New Modules
------------
-
-- vmware_host_custom_attributes - Manage custom attributes from VMware for the given ESXi host
-- vmware_host_passthrough - Manage PCI device passthrough settings on host
-- vmware_object_custom_attributes_info - Gather custom attributes of an object
-- vmware_object_role_permission_info - Gather information about object's permissions
-- vmware_recommended_datastore - Returns the recommended datastore from a SDRS-enabled datastore cluster
-
-v1.10.0
-=======
-
-Minor Changes
--------------
-
-- vmware_cluster_drs - Make enable_drs an alias of enable and add a warning that the default will change from false to true in a future version (https://github.com/ansible-collections/community.vmware/pull/766)
-- vmware_cluster_ha - Make enable_ha an alias of enable and add a warning that the default will change from false to true in a future version (https://github.com/ansible-collections/community.vmware/pull/766)
-- vmware_cluster_vsan - Make enable_vsan an alias of enable and add a warning that the default will change from false to true in a future version (https://github.com/ansible-collections/community.vmware/pull/766)
-- vmware_dvs_portgroup - Implement 'elastic' port group configuration (https://github.com/ansible-collections/community.vmware/issues/410).
-- vmware_dvs_portgroup - Implement MAC learning configuration (https://github.com/ansible-collections/community.vmware/issues/644).
-- vmware_dvs_portgroup - Implement configuration of active and standby uplinks (https://github.com/ansible-collections/community.vmware/issues/709).
-- vmware_dvs_portgroup - Remove default for teaming_policy.inbound_policy (https://github.com/ansible-collections/community.vmware/pull/743).
-- vmware_dvs_portgroup_info - Return information about MAC learning configuration (https://github.com/ansible-collections/community.vmware/issues/644).
-- vmware_dvs_portgroup_info - Return information about uplinks (https://github.com/ansible-collections/community.vmware/issues/709).
-- vmware_guest - add more documentation about ``is_template`` (https://github.com/ansible-collections/community.vmware/pull/794).
-- vmware_host_iscsi_info - added a list(detected_iscsi_drives) of detected iscsi drives to the return value after set an iscsi config (https://github.com/ansible-collections/community.vmware/pull/729).
-- vmware_tag - modified the category_id parameter to required (https://github.com/ansible-collections/community.vmware/pull/790).
-- vmware_vm_inventory - set default to ``True`` for ``with_nested_properties`` (https://github.com/ansible-collections/community.vmware/issues/712).
-
-Bugfixes
---------
-
-- vmware - fixed a bug that the guest_guestion in the facts doesn't convert to the dictionary (https://github.com/ansible-collections/community.vmware/pull/825).
-- vmware - handle exception raised in ``get_all_objs`` and ``find_object_by_name`` which occurs due to multiple parallel operations (https://github.com/ansible-collections/community.vmware/issues/791).
-- vmware_cluster_info - Fix a bug that returned enabled_vsan and vsan_auto_claim_storage as lists instead of just true or false (https://github.com/ansible-collections/community.vmware/issues/805).
-- vmware_evc_mode - fixed an issue that evc_mode is required when the state parameter set to absent (https://github.com/ansible-collections/community.vmware/pull/764).
-- vmware_guest - skip customvalues while deploying VM on a standalone ESXi (https://github.com/ansible-collections/community.vmware/issues/721).
-- vmware_host_iscsi_info - fixed an issue that an error occurs gathering iSCSI information against an ESXi Host with iSCSI disabled (https://github.com/ansible-collections/community.vmware/pull/729).
-- vmware_vm_info - handle vApp parent logic (https://github.com/ansible-collections/community.vmware/issues/777).
-- vmware_vm_shell - handle exception raised while performing the operation (https://github.com/ansible-collections/community.vmware/issues/732).
-- vmware_vm_storage_policy_info - fixed an issue that the module can't get storage policy info when the policy has the tag base rules (https://github.com/ansible-collections/community.vmware/pull/788).
-- vmware_vmotion - Provide an meaningful error message when providing a bad ESXi node as ``destination_host`` (https://github.com/ansible-collections/vmware/pull/804).
-
-New Modules
------------
-
-- vmware_host_tcpip_stacks - Manage the TCP/IP Stacks configuration of ESXi host
-
-v1.9.0
+v4.1.0
======
Minor Changes
-------------
-- vmware_guest_instant_clone - supported esxi_hostname parameter as an alias (https://github.com/ansible-collections/community.vmware/pull/745).
-- vmware_resource_pool - Add parent_resource_pool parameter which is mutually exclusive with cluster and esxi_hostname (https://github.com/ansible-collections/community.vmware/issues/717)
-- vmware_vm_inventory - add an example of FQDN as hostname (https://github.com/ansible-collections/community.vmware/issues/678).
-- vmware_vm_inventory - skip disconnected VMs.
-
-Deprecated Features
--------------------
-
-- vmware_vmkernel_ip_config - deprecate in favor of vmware_vmkernel (https://github.com/ansible-collections/community.vmware/pull/667).
-
-Security Fixes
---------------
-
-- vmware_host_iscsi - mark the ``chap_secret`` parameter as ``no_log`` to avoid accidental leaking of secrets in logs (https://github.com/ansible-collections/community.vmware/pull/715).
-- vmware_host_iscsi - mark the ``mutual_chap_secret`` parameter as ``no_log`` to avoid accidental leaking of secrets in logs (https://github.com/ansible-collections/community.vmware/pull/715).
-- vmware_vc_infraprofile_info - mark the ``decryption_key`` parameter as ``no_log`` to avoid accidental leaking of secrets in logs (https://github.com/ansible-collections/community.vmware/pull/715).
-- vmware_vc_infraprofile_info - mark the ``encryption_key`` parameter as ``no_log`` to avoid accidental leaking of secrets in logs (https://github.com/ansible-collections/community.vmware/pull/715).
+- vmware_guest - Add IPv6 support for VM network interfaces (https://github.com/ansible-collections/community.vmware/pull/1937).
+- vmware_guest_sendkey - Add Windows key (https://github.com/ansible-collections/community.vmware/issues/1959).
+- vmware_guest_tools_upgrade - Add parameter `installer_options` to pass command line options to the installer to modify the installation procedure for tools (https://github.com/ansible-collections/community.vmware/pull/1059).
Bugfixes
--------
-- vmware - add the default value of parameter resource_pool_name in the find_resource_pool_by_name function (https://github.com/ansible-collections/community.vmware/pull/670).
-- vmware_cluster_vsan - fixed a bug that made the module fail when advanced_options is not set (https://github.com/ansible-collections/community.vmware/issues/728).
-- vmware_deploy_ovf - fixed an issue that a return value hasn't the instance key when the power_on parameter is False (https://github.com/ansible-collections/community.vmware/pull/698).
-- vmware_deploy_ovf - fixed an issue that deploy template in datacenter with more than one standalone hosts (https://github.com/ansible-collections/community.vmware/pull/670).
-- vmware_guest - fixed a bug that made the module fail when disk.controller_number or disk.unit_number are 0 (https://github.com/ansible-collections/community.vmware/issues/703).
-- vmware_local_user_manager - fixed to require local_user_password when the state is present (https://github.com/ansible-collections/community.vmware/pull/724).
-- vmware_vm_inventory - Skip over ghost tags attached to virtual machines (https://github.com/ansible-collections/community.vmware/issues/681).
+- Fix InsecureRequestWarning for modules based on the VmwareRestClient module util when setting ``validate_certs`` to ``False`` (https://github.com/ansible-collections/community.vmware/pull/1969).
+- module_utils/vmware.py - remove ssl.wrap_socet() function. Replaced for code based on ssl.get_server_certificate (https://github.com/ansible-collections/community.vmware/issues/1930).
+- vmware_guest - Fix failure of vm reconfiguration with enabled virt_based_security (https://github.com/ansible-collections/community.vmware/pull/1848).
-New Modules
------------
-
-- vmware_guest_instant_clone - Instant Clone VM
-- vmware_guest_storage_policy - Set VM Home and disk(s) storage policy profiles.
-
-v1.8.0
-======
-
-Minor Changes
--------------
-
-- Define sub-options of disk in argument_spec (https://github.com/ansible-collections/community.vmware/pull/640).
-- vmware_guest - Remove unnecessary hardware version check (https://github.com/ansible-collections/community.vmware/issues/636).
-- vmware_vcenter_settings - supported the diff mode (https://github.com/ansible-collections/community.vmware/pull/641).
-
-Bugfixes
---------
-
-- vcenter_license - fixed a bug that the license doesn't assign in VCSA 7.0u1c (https://github.com/ansible-collections/community.vmware/pull/643).
-- vmware - fixed an issue that a port group name doesn't compare correctly in the find_network_by_name function (https://github.com/ansible-collections/community.vmware/pull/661).
-- vmware_category - append namespace to associable types (https://github.com/ansible-collections/community.vmware/issues/579).
-- vmware_cluster_ha - fix enabling APD or PDL response (https://github.com/ansible-collections/community.vmware/issues/676).
-- vmware_cluster_info - return VSAN status correctly (https://github.com/ansible-collections/community.vmware/issues/673).
-- vmware_deploy_ovf - fixed an issue that an error message doesn't show when not finding a port group name (https://github.com/ansible-collections/community.vmware/pull/661).
-- vmware_dvs_portgroup - fixed the issue that the VLAN configuration isn't compared correctly in the module (https://github.com/ansible-collections/community.vmware/pull/638).
-- vmware_dvs_portgroup_find - fixed to decode the special characters URL-encoded in the dvs port group name (https://github.com/ansible-collections/community.vmware/pull/648).
-- vmware_dvs_portgroup_info - fixed to decode the special characters URL-encoded in the dvs port group name (https://github.com/ansible-collections/community.vmware/pull/648).
-- vmware_guest - add support for ``advanced settings`` in vmware_guest (https://github.com/ansible-collections/community.vmware/issues/602).
-- vmware_guest_register_operation - fixed an issue that an error has been occurring when not specifying a datacenter name (https://github.com/ansible-collections/community.vmware/pull/693).
-- vmware_vm_storage_policy - fixed an issue that an error for pyvmomi(SDK) occurred when a tag or category doesn't exist (https://github.com/ansible-collections/community.vmware/pull/682).
-
-v1.7.0
-======
-
-Minor Changes
--------------
-
-- vmware_cluster_info - added a parent datacenter name of Cluster to the return value (https://github.com/ansible-collections/community.vmware/pull/591).
-- vmware_content_deploy_ovf_template - consistent ``eagerZeroedThick`` value (https://github.com/ansible-collections/community.vmware/issues/618).
-- vmware_content_deploy_template - add datastore cluster parameter (https://github.com/ansible-collections/community.vmware/issues/397).
-- vmware_content_deploy_template - make resource pool, host, cluster, datastore optional parameter and add check (https://github.com/ansible-collections/community.vmware/issues/397).
-- vmware_guest - Define sub-options of hardware and customization in argument_spec (https://github.com/ansible-collections/community.vmware/issues/555).
-- vmware_guest_register_operation - supported the check_mode
-- vmware_host_iscsi - added a name(iqn) changing option for iSCSI (https://github.com/ansible-collections/community.vmware/pull/617).
-- vmware_host_lockdown - Support check mode (https://github.com/ansible-collections/community.vmware/pull/633).
-
-Deprecated Features
--------------------
-
-- vmware_host_firewall_manager - the creation of new rule with no ``allowed_ip`` entry in the ``allowed_hosts`` dictionary won't be allowed after 2.0.0 release.
-
-Bugfixes
---------
-
-- vmware_content_library_manager - added support for subscribed library (https://github.com/ansible-collections/community.vmware/pull/569).
-- vmware_datastore_cluster_manager - Fix idempotency in check mode (https://github.com/ansible-collections/community.vmware/issues/623).
-- vmware_dvswitch - correctly add contact information (https://github.com/ansible-collections/community.vmware/issues/608).
-- vmware_dvswitch_lacp - typecast uplink number in lag_options (https://github.com/ansible-collections/community.vmware/issues/111).
-- vmware_guest - handle NoneType values before passing to ``len`` API (https://github.com/ansible-collections/community.vmware/issues/593).
-
-New Modules
------------
-
-- vmware_drs_group_manager - Manage VMs and Hosts in DRS group.
-- vmware_first_class_disk - Manage VMware vSphere First Class Disks
-
-v1.6.0
-======
-
-Minor Changes
--------------
-
-- vmware_guest_disk - add new parameters controller_type and controller_number for supporting SATA and NVMe disk (https://github.com/ansible-collections/vmware/issues/196).
-- vmware_guest_file_operation - provide useful error message when exception occurs (https://github.com/ansible-collections/community.vmware/issues/485).
-- vmware_guest_network - add support for private vlan id (https://github.com/ansible-collections/community.vmware/pull/511).
-- vmware_host - added a new state option, the ``disconnected`` (https://github.com/ansible-collections/community.vmware/pull/589).
-- vmware_host_facts - Add ESXi host current time info in returned host facts(https://github.com/ansible-collections/community.vmware/issues/527)
-- vmware_vsan_health_info - add new parameter to support datacenter.
-
-Bugfixes
---------
-
-- Fix remove hosts from cluster to use cluster name variable
-- Fix vSwitch0 default port group removal to run against all hosts
-- For vSphere 7.0u1, add steps to tests to remove vCLS VMs before removing datastore
-- vmware_cluster - consider datacenter name while creating cluster (https://github.com/ansible-collections/community.vmware/issues/575).
-- vmware_cluster_drs - consider datacenter name while managing cluster (https://github.com/ansible-collections/community.vmware/issues/575).
-- vmware_cluster_ha - consider datacenter name while managing cluster (https://github.com/ansible-collections/community.vmware/issues/575).
-- vmware_cluster_vsan - consider datacenter name while managing cluster (https://github.com/ansible-collections/community.vmware/issues/575).
-- vmware_dvswitch - fix an issue with vSphere 7 when no switch_version is defined (https://github.com/ansible-collections/community.vmware/issues/576)
-- vmware_guest - fix an issue with vSphere 7 when adding several virtual disks and / or vNICs (https://github.com/ansible-collections/community.vmware/issues/545)
-- vmware_guest - handle computer name in existing VM customization (https://github.com/ansible-collections/community.vmware/issues/570).
-- vmware_guest_disk - fix an issue with vSphere 7 when adding several virtual disks and (https://github.com/ansible-collections/community.vmware/issues/373)
-- vmware_host_logbundle - handle fetch_url status before attempting to read response.
-- vmware_host_ntp - fix an issue with disconnected hosts (https://github.com/ansible-collections/community.vmware/issues/539)
-- vsphere_copy - handle unboundlocalerror when timeout occurs (https://github.com/ansible-collections/community.vmware/issues/554).
-
-New Modules
------------
-
-- vcenter_domain_user_group_info - Gather user or group information of a domain
-
-v1.5.1
-======
-
-Minor Changes
--------------
-
-- vmware_resource_pool - relabel the change introduced in 1.5.0 as Minor Changes (https://github.com/ansible-collections/community.vmware/issues/540).
-
-v1.5.0
-======
-
-Minor Changes
--------------
-
-- vmware_content_deploy_ovf_template - added new parameter "content_library" to get the OVF template from (https://github.com/ansible-collections/community.vmware/issues/514).
-- vmware_drs_group - code refactor (https://github.com/ansible-collections/community.vmware/pull/475).
-- vmware_guest - add documentation for networks parameters connected and start_connected (https://github.com/ansible-collections/community.vmware/issues/507).
-- vmware_guest_controller - error handling in task exception.
-- vmware_resource_pool - manage resource pools on ESXi hosts (https://github.com/ansible-collections/community.vmware/issues/492).
-- vmware_vm_inventory - skip inaccessible vm configuration.
-
-Bugfixes
---------
-
-- vmware_cluster_ha - added APD and PDL configuration (https://github.com/ansible-collections/community.vmware/issues/451).
-- vmware_deploy_ovf - fixed an UnboundLocalError for variable 'name' in check mode (https://github.com/ansible-collections/community.vmware/pull/499).
-- vmware_object_role_permission - add support for role name presented in vSphere Web UI (https://github.com/ansible-collections/community.vmware/issues/436).
-
-v1.4.0
+v4.0.1
======
-Minor Changes
--------------
-
-- vmware_category - add additional associable object types (https://github.com/ansible-collections/community.vmware/issues/454).
-- vmware_dvswitch - Added support to create vds version 7.0.0.
-- vmware_guest - Fixed issue of checking hardware version when set VBS(https://github.com/ansible-collections/community.vmware/issues/351)
-- vmware_guest - Fixed issue of comparing latest hardware version str type with int(https://github.com/ansible-collections/community.vmware/issues/381)
-- vmware_guest_info - added a new parameter to gather detailed information about tag from the given virtual machine.
-- vmware_guest_video - gather facts for video devices even if the virtual machine is poweredoff (https://github.com/ansible-collections/community.vmware/issues/408).
-- vmware_object_role_permission - add missing required fields of hostname, username, and password to module examples (https://github.com/ansible-collections/community.vmware/issues/426).
-- vmware_resource_pool - add new allocation shares options for cpu and memory(https://github.com/ansible-collections/community.vmware/pull/461).
-- vmware_vm_inventory - support for categories and tag, category relation (https://github.com/ansible-collections/community.vmware/issues/350).
-
Bugfixes
--------
-- Fixed the find_obj method in the ``module_utils/vmware.py`` to handle an object name using special characters that URL-decoded(https://github.com/ansible-collections/community.vmware/pull/460).
-- vmware_cluster_info - return tag related information (https://github.com/ansible-collections/community.vmware/issues/453).
-- vmware_deploy_ovf - fixed network mapping in multi-datacenter environments
-- vmware_folder_info - added the flat_folder_info in the return value.
-- vmware_guest_sendkey - add sleep_time parameter to add delay in-between keys sent (https://github.com/ansible-collections/community.vmware/issues/404).
-- vmware_resource_pool - added a changing feature of resource pool config (https://github.com/ansible-collections/community.vmware/pull/469).
-- vmware_resource_pool - fixed that always updates occur bug on vCenter Server even when not changing resource pool config (https://github.com/ansible-collections/community.vmware/pull/482).
-- vmware_tag_manager - added new parameter 'moid' to identify VMware object to tag (https://github.com/ansible-collections/community.vmware/issues/430).
-- vmware_vm_info - added the moid information in the return value.
-- vmware_vm_inventory - ensure self.port is integer (https://github.com/ansible-collections/community.vmware/issues/488).
-- vmware_vm_inventory - improve plugin performance (https://github.com/ansible-collections/community.vmware/issues/434).
-- vmware_vm_vm_drs_rule - report changes in check mode (https://github.com/ansible-collections/community.vmware/issues/440).
+- vmware_vm_info - Fix an AttributeError when gathering network information (https://github.com/ansible-collections/community.vmware/pull/1919).
-v1.3.0
+v4.0.0
======
Minor Changes
-------------
-- module_utils/vmware - Ignore leading and trailing whitespace when searching for objects (https://github.com/ansible-collections/vmware/issues/335)
-- vmware_cluster_info - Fixed issue of a cluster name doesn't URL-decode(https://github.com/ansible-collections/vmware/pull/366)
-- vmware_guest - takes now into account the ``esxi_hostname`` argument to create the vm on the right host according to the doc (https://github.com/ansible-collections/vmware/pull/359).
-- vmware_guest_custom_attributes - Fixed issue when trying to set a VM custom attribute when there are custom attributes with the same name for other object types (https://github.com/ansible-collections/community.vmware/issues/412).
-- vmware_guest_customization_info - Fixed to get values properly for LinuxPrep and SysPrep parameters(https://github.com/ansible-collections/vmware/pull/368)
-- vmware_guest_info - Fix get tags API call (https://github.com/ansible-collections/community.vmware/issues/403).
-- vmware_guest_network - Fixed to port group changes to work properly and NSX-T port group supported(https://github.com/ansible-collections/community.vmware/pull/401).
-- vmware_host_iscsi_info - a new module for the ESXi hosts that is dedicated to gathering information of the iSCSI configuration(https://github.com/ansible-collections/community.vmware/pull/402).
-- vmware_vm_inventory - update requirements doc.
-
-Bugfixes
---------
-
-- ``module_utils/vmware.py`` handles an object name using special characters that URL-decoded(https://github.com/ansible-collections/vmware/pull/380).
-
-v1.2.0
-======
-
-Minor Changes
--------------
-
-- vmware_cluster_ha - treat truthy advanced options ('true', 'false') as strings instead of booleans (https://github.com/ansible-collections/vmware/issues/286).
-- vmware_cluster_vsan - implement advanced VSAN options (https://github.com/ansible-collections/vmware/issues/260).
-- vmware_cluster_vsan - requires the vSAN Management SDK, which needs to be downloaded from VMware and installed manually.
-- vmware_content_deploy_ovf_template - requires the resource_pool parameter.
-- vmware_guest_disk - add backing_uuid value to return (https://github.com/ansible-collections/vmware/pull/348).
-- vmware_guest_serial_port - ensure we can run the module two times in a row without unexpected side effect(https://github.com/ansible-collections/vmware/pull/358).
-
-Deprecated Features
--------------------
-
-- vmware_guest - deprecate specifying CDROM configuration as a dict, instead use a list.
-
-Bugfixes
---------
-
-- vmware_content_deploy_ovf_template - fixed issue where wrong resource pool identifier was returned when same resource pool name was used across clusters in the same datacenter (https://github.com/ansible-collections/vmware/pull/363)
-- vmware_vmkernel - fixed issue where Repl and ReplNFC services were not being identified as enabled on a vmk interface (https://github.com/ansible-collections/vmware/issues/362).
-
-v1.1.0
-======
-
-Minor Changes
--------------
-
-- Added module to be able to create, update, or delete VMware VM storage policies for virtual machines.
-- vmware_cluster_info - added ``properties`` and ``schema`` options and supported the getting of clusters resource summary information.
-- vmware_content_deploy_ovf_template - handle exception while deploying VM using OVF template.
-- vmware_content_deploy_template - handle exception while deploying VM (https://github.com/ansible-collections/vmware/issues/182).
-- vmware_dvs_portgroup - Added support for distributed port group with private VLAN.
-- vmware_guest_snapshot_info - Document that `folder` is required if the VM `name` is defined (https://github.com/ansible-collections/vmware/issues/243)
-- vmware_host_iscsi - a new module for the ESXi hosts that is dedicated to the management of the iSCSI configuration
-- vmware_migrate_vmk - allow migration from a VMware vSphere Distrubuted Switch to a ESXi Standard Switch
-- vmware_vcenter_settings_info - a new module for gather information about vCenter settings
+- Removed module / plugin documentation RST files from the repository (https://github.com/ansible-collections/community.vmware/pull/1897).
+- Using semantic markup in documentation (https://github.com/ansible-collections/community.vmware/issues/1771).
+- vmware_deploy_ovf - New parameter enable_hidden_properties to force OVF properties marked as `ovf:userConfigurable=false` to become user configurable (https://github.com/ansible-collections/community.vmware/issues/802).
+- vmware_dvs_portgroup_info - add moid property in the return value for the module (https://github.com/ansible-collections/community.vmware/issues/1849).
+- vmware_guest_snapshot - add new snapshot_id option (https://github.com/ansible-collections/community.vmware/pull/1847).
+- vmware_host_snmp module now can configure SNMP agent on set of hosts (list in esxi_hostname parameter or as cluster in cluster_name parameter). The ability to configure the host directly remains (https://github.com/ansible-collections/community.vmware/issues/1799).
Breaking Changes / Porting Guide
--------------------------------
-- vmware_datastore_maintenancemode - now returns ``datastore_status`` instead of Ansible internal key ``results``.
-- vmware_guest_custom_attributes - does not require VM name which was a required parameter for releases prior to Ansible 2.10.
-- vmware_guest_find - the ``datacenter`` option has been removed.
-- vmware_host_kernel_manager - now returns ``host_kernel_status`` instead of Ansible internal key ``results``.
-- vmware_host_ntp - now returns ``host_ntp_status`` instead of Ansible internal key ``results``.
-- vmware_host_service_manager - now returns ``host_service_status`` instead of Ansible internal key ``results``.
-- vmware_tag - now returns ``tag_status`` instead of Ansible internal key ``results``.
-- vmware_vmkernel - the options ``ip_address`` and ``subnet_mask`` have been removed; use the suboptions ``ip_address`` and ``subnet_mask`` of the ``network`` option instead.
-
-Deprecated Features
--------------------
-
-- The vmware_dns_config module has been deprecated and will be removed in a later release; use vmware_host_dns instead.
-- vca - vca_fw, vca_nat, vca_app are deprecated since these modules rely on deprecated part of Pyvcloud library.
-- vmware_tag_info - in a later release, the module will not return ``tag_facts`` since it does not return multiple tags with the same name and different category id. To maintain the existing behavior use ``tag_info`` which is a list of tag metadata.
-
-Removed Features (previously deprecated)
-----------------------------------------
-
-- vmware_portgroup - removed 'inbound_policy', and 'rolling_order' deprecated options.
-
-Bugfixes
---------
-
-- vmware_content_deploy_ovf_template - use datastore_id in deployment_spec (https://github.com/ansible-collections/vmware/pull/287).
-- vmware_dvs_portgroup_find - Fix comparison between str and int on method vlan_match (https://github.com/ansible-collections/vmware/pull/52).
-- vmware_guest - cdrom.controller_number, cdrom.unit_number are handled as integer. (https://github.com/ansible-collections/vmware/issues/274).
-- vmware_vm_inventory - CustomFieldManager is not present in ESXi, handle this condition (https://github.com/ansible-collections/vmware/issues/269).
-
-v1.0.0
-======
-
-Minor Changes
--------------
-
-- A `vmware` module_defaults group has been added to simplify parameters for multiple VMware tasks. This group includes all VMware modules.
-- Add a flag 'force_upgrade' to force VMware tools upgrade installation (https://github.com/ansible-collections/vmware/issues/75).
-- Add powerstates to match vmware_guest_powerstate module with vmware_guest (https://github.com/ansible/ansible/issues/55653).
-- Added a timeout parameter `wait_for_ip_address_timeout` for `wait_for_ip_address` for longer-running tasks in vmware_guest.
-- Added missing backing_disk_mode information about disk which was removed by mistake in vmware_guest_disk_info.
-- Correct datatype for state in vmware_host_lockdown module.
-- Correct example from doc of `vmware_local_role_info.py` to match the change of returned structure.
-- Correct example from doc of `vmware_local_role_info.py` to match the change of returned structure.
-- Handle exceptions raised in connect_to_vsphere_client API.
-- Minor typo fixes in vmware_httpapi related modules and module_utils.
-- Removed ANSIBLE_METADATA from all the modules.
-- Return additional information about hosts inside the cluster using vmware_cluster_info.
-- Update Module examples with FQCN.
-- Update README.md for installing any third party required Python libraries using pip (https://github.com/ansible-collections/vmware/issues/154).
-- add storage_provisioning type into vmware_content_deploy_ovf_template.
-- add vmware_content_deploy_ovf_template module for creating VMs from OVF templates
-- new code module for new feature for operations of VCenter infra profile config.
-- vmware.py - Only add configured network interfaces to facts.
-- vmware_cluster_drs - Implemented DRS advanced settings (https://github.com/ansible/ansible/issues/66217)
-- vmware_cluster_ha - Implemented HA advanced settings (https://github.com/ansible/ansible/issues/61421)
-- vmware_cluster_ha - Remove a wrong parameter from an example in the documentation.
-- vmware_content_deploy_template - added new field "content_library" to search template inside the specified content library.
-- vmware_datastore_cluster - Added basic SDRS configuration (https://github.com/ansible/ansible/issues/65154).
-- vmware_datastore_info - added ``properties`` and ``schema`` options.
-- vmware_datastore_maintenancemode now returns datastore_status instead of Ansible internal key results (https://github.com/ansible/ansible/issues/62083).
-- vmware_dvs_portgroup_info - Include the value of the Portgroup ``key`` in the result
-- vmware_dvswitch now returns the UUID of the switch
-- vmware_dvswitch_info also returns the switch UUID
-- vmware_export_ovf - increase default timeout to 30s
-- vmware_export_ovf - timeout value is actually in seconds, not minutes
-- vmware_guest - Don't search for VMDK if filename is defined.
-- vmware_guest - Extracts repeated code from configure_vapp_properties() to set_vapp_properties() in vmware_guest.py.
-- vmware_guest - add support VM creation and reconfiguration with multiple types of disk controllers and disks
-- vmware_guest - add support for create and reconfigure CDROMs attaching to SATA (https://github.com/ansible/ansible/issues/42995)
-- vmware_guest - add support hardware version 17 for vSphere 7.0
-- vmware_guest_custom_attributes does not require VM name (https://github.com/ansible/ansible/issues/63222).
-- vmware_guest_disk - Add `destroy` option which allows to remove a disk without deleting the VMDK file.
-- vmware_guest_disk - Add `filename` option which allows to create a disk from an existing VMDK.
-- vmware_guest_disk - add support for setting the sharing/multi-writer mode of virtual disks (https://github.com/ansible-collections/vmware/issues/212)
-- vmware_guest_network - network adapters can be configured without lists
-- vmware_guest_network - network_info returns a list of dictionaries for ease of use
-- vmware_guest_network - put deprecation warning for the networks parameter
-- vmware_guest_tools_wait now exposes a ``timeout`` parameter that allow the user to adjust the timeout (second).
-- vmware_host_active_directory - Fail when there are unrecoverable problems with AD membership instead of reporting a change that doesn't take place (https://github.com/ansible-collections/vmware/issues/59).
-- vmware_host_dns - New module replacing vmware_dns_config with increased functionality.
-- vmware_host_dns can now set the following empty values, ``domain``, ``search_domains`` and ``dns_servers``.
-- vmware_host_facts - added ``properties`` and ``schema`` options.
-- vmware_host_firewall_manager - ``allowed_hosts`` excpects a dict as parameter, list is deprecated
-- vmware_host_kernel_manager now returns host_kernel_status instead of Ansible internal key results (https://github.com/ansible/ansible/issues/62083).
-- vmware_host_logbundle - new code module for a new feature for ESXi support log bundle download operation
-- vmware_host_logbundle_info - new code module for a new feature for getting manifests for ESXi support log bundle
-- vmware_host_ntp now returns host_ntp_status instead of Ansible internal key results (https://github.com/ansible/ansible/issues/62083).
-- vmware_host_service_manager now returns host_service_status instead of Ansible internal key results (https://github.com/ansible/ansible/issues/62083).
-- vmware_rest_client - Added a new definition get_library_item_from_content_library_name.
-- vmware_tag now returns tag_status instead of Ansible internal key results (https://github.com/ansible/ansible/issues/62083).
-- vmware_vm_inventory inventory plugin, raise more descriptive error when all template strings in ``hostnames`` fail.
-
-Deprecated Features
--------------------
-
-- vmware_dns_config - Deprecate in favour of new module vmware_host_dns.
+- Removed support for ansible-core version < 2.15.0.
+- vmware_dvs_host - removed defaults for `vmnics` and `lag_uplinks` (https://github.com/ansible-collections/community.vmware/issues/1516).
+- vmware_host_acceptance - removed `acceptance_level` and used its options in `state`. This also means there will be no state `list` anymore. In order to get information about the current acceptance level, use the new module `vmware_host_acceptance_info` (https://github.com/ansible-collections/community.vmware/issues/1872).
+- vmware_vm_info - added prefix length to IP addresses in vm_network, so they now show up as for example 10.76.33.228/24 instead of just 10.76.33.228 (https://github.com/ansible-collections/community.vmware/issues/1761).
Removed Features (previously deprecated)
----------------------------------------
-- vmware_guest_find - Removed deprecated ``datacenter`` option
-- vmware_vmkernel - Removed deprecated ``ip_address`` option; use sub-option ip_address in the network option instead
-- vmware_vmkernel - Removed deprecated ``subnet_mask`` option; use sub-option subnet_mask in the network option instead
+- Removed module util `version` (https://github.com/ansible-collections/community.vmware/issues/1639).
+- vmware_guest - removed specifying CDROM configuration as a dict, instead use a list (https://github.com/ansible-collections/community.vmware/issues/1472).
+- vmware_host_lockdown - removed deprecated states `absent` and `present` (https://github.com/ansible-collections/community.vmware/issues/1517).
+- vmware_rest_client - removed deprecated method `get_tag_by_category()` (https://github.com/ansible-collections/community.vmware/issues/1898).
Bugfixes
--------
-- Added 'compose' and 'groups' feature in vmware_vm_inventory plugin.
-- Added keyed_groups feature in vmware_vm_inventory plugin.
-- Added support to vmware_tag_manager module for specifying tag and category as dict if any of the name contains colon (https://github.com/ansible/ansible/issues/65765).
-- Check for virtualNicManager in Esxi host system before accessing properties in vmware_vmkernel_info (https://github.com/ansible/ansible/issues/62772).
-- Fixed typo in vmware_guest_powerstate module (https://github.com/ansible/ansible/issues/65161).
-- Handle Base64 Binary while JSON serialization in vmware_vm_inventory.
-- Handle NoneType error when accessing service system info in vmware_host_service_info module (https://github.com/ansible/ansible/issues/67615).
-- Handle list items in vSphere schema while handling facts using to_json API (https://github.com/ansible-collections/vmware/issues/33).
-- Handle multiple tags name with different category id in vmware_tag module (https://github.com/ansible/ansible/issues/66340).
-- Handle slashes in VMware network name (https://github.com/ansible/ansible/issues/64399).
-- In inventory plugin, serialize properties user specifies which are objects as dicts (https://github.com/ansible-collections/vmware/pull/58).
-- In vmware_guest_network module use appropriate network while creating or reconfiguring (https://github.com/ansible/ansible/issues/65968).
-- Made vmnics attributes optional when creating DVS as they are optional on the API and GUI as well.
-- VMware Guest Inventory plugin enhancements and features.
-- VMware guest inventory plugin support for filters.
-- Vmware Fix for Create overwrites a VM of same name even when the folder is different(https://github.com/ansible/ansible/issues/43161)
-- `vmware_content_deploy_template`'s `cluster` argument no longer fails with an error message about resource pools.
-- return correct datastore cluster placement recommendations during when adding disk using the vmware_guest_disk module
-- vmware - Ensure we can use the modules with Python < 2.7.9 or RHEL/CentOS < 7.4, this as soon as ``validate_certs`` is disabled.
-- vmware_category - fix associable datatypes (https://github.com/ansible-collections/vmware/issues/197).
-- vmware_content_deploy_template - Added param content_library to the main function
-- vmware_deploy_ovf - Fixed ova deploy error occur if vm exists
-- vmware_dvs_portgroup - Implemented configuration changes on an existing Distributed vSwitch portgroup.
-- vmware_dvs_portgroup_find - Cast variable to integer for comparison.
-- vmware_guest - Add ability to upgrade the guest hardware version to latest fix issue (https://github.com/ansible/ansible/issues/56273).
-- vmware_guest - Allow '-' (Dash) special char in windows DNS name.
-- vmware_guest - Exclude dvswitch_name from triggering guest os customization.
-- vmware_guest - Updated reference link to vapp_properties property
-- vmware_host_capability_facts - Fixed vSphere API legacy version errors occur in pyvmomi 7.0 and later
-- vmware_host_capability_info - Fixed vSphere API legacy version errors occur in pyvmomi 7.0 and later
-- vmware_host_facts - handle facts when ESXi hostsystem is poweredoff (https://github.com/ansible-collections/vmware/issues/183).
-- vmware_host_firewall_manager - Ensure we can set rule with no ``allowed_hosts`` key (https://github.com/ansible/ansible/issues/61332)
-- vmware_host_firewall_manager - Fixed creating IP specific firewall rules with Python 2 (https://github.com/ansible/ansible/issues/67303)
-- vmware_host_vmhba_info - fixed node_wwn and port_wwn for FC HBA to hexadecimal format(https://github.com/ansible/ansible/issues/63045).
-- vmware_vcenter_settings - Fixed when runtime_settings parameters not defined occur error(https://github.com/ansible/ansible/issues/66713)
-- vmware_vcenter_statistics - Fix some corner cases like increasing some interval and decreasing another at the same time.
-- vmware_vm_inventory inventory plugin, use the port value while connecting to vCenter (https://github.com/ansible/ansible/issues/64096).
-- vmware_vmkernel - Remove duplicate checks.
-- vmware_vspan_session - Extract repeated code and reduce complexity of function.
+- vmware_deploy_ovf - fix error in finding networks part of code (https://github.com/ansible-collections/community.vmware/issues/1853).
+- vmware_guest_custom_attributes - fix problem when module try apply non global or non VM type custom attribute to VM object (https://github.com/ansible-collections/community.vmware/issues/1772).
diff --git a/ansible_collections/community/vmware/FILES.json b/ansible_collections/community/vmware/FILES.json
index 5889173cc..82d6f277e 100644
--- a/ansible_collections/community/vmware/FILES.json
+++ b/ansible_collections/community/vmware/FILES.json
@@ -25,14 +25,21 @@
"name": ".github/workflows/ansible-test.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ae0b8ea2be4c8a983c774d29cced186c9630ff788e2dfe6cbe8e560a1a413a58",
+ "chksum_sha256": "c7dfcceab897d76f899e9745a5ef5134a7deffe84c7c9aca9bcce00e903a7ca8",
"format": 1
},
{
"name": ".github/workflows/extra-docs-linting.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "230186e54ae1acc0a55b0d09852bce562b337e2d96ac6b234281051ffe12bfa6",
+ "chksum_sha256": "19bb097e3a34621e1b74ce740716ee78818a3d6b752b1563f10e69d20450556c",
+ "format": 1
+ },
+ {
+ "name": ".github/workflows/import-galaxy.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "739c36223d6e0e6ccc98907c43cba53296e7b1ccd64a2d995c2ff21df4ab25a5",
"format": 1
},
{
@@ -81,14 +88,14 @@
"name": "changelogs/changelog.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b1992da9af4f25919d834e219d95c9f5282d7f22e18324a066bbc0b65d125377",
+ "chksum_sha256": "c77e5b2e21540ce43a2d83a648e341766d6373b8a909280c8a6f8cc160a40bc7",
"format": 1
},
{
"name": "changelogs/config.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d445938f17e29b4a6d6812a8726321ab4feaf22342b34565eeba715394ab4f31",
+ "chksum_sha256": "599da66776ab4d934698a0a9e8353df2c2df9adce42d2b7536f9a889a1b3d727",
"format": 1
},
{
@@ -274,1203 +281,6 @@
"format": 1
},
{
- "name": "docs/community.vmware.vcenter_domain_user_group_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "068aa894c6cb6fa829cc6370f1acd8925e078ca04c14e97ba851b0d04a2eb22a",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vcenter_extension_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "9fcb85aa67ec9c55baad376b0b95f73877e14583942adaef434e48e86071f39b",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vcenter_extension_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "5c39f7810bbe40f784f28e92a963eba35a91c4a0550316261b53c2130f4b6e00",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vcenter_folder_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "f13182a7b2f59a330199d8b1412d558eca933f1656a0148f579a51c847340264",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vcenter_license_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "dce0703abe60b45d54a9257cf4ced632da7769a960f870a0c15192636c398986",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vcenter_standard_key_provider_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "72ff518d548edf2cb96126eda4d2734a7af92ed36948e0d764027b1aa4020ed7",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_about_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "be1842a2f1cd360edc46cb4ebcb6f6922506ac9ecc8f8defe1d9e44cf2bb42d7",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_category_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "9c888d8f07017a59dc6ab3f58bc885aebb69804d2dd585e59f89d641377f81ee",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_category_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "5125fc2931192ce242ac88c658b03ccf5a6f6a7a3b9733185f35ecc888b5b321",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_cfg_backup_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "01eef57c42ea776eb638feef4d8277c11fc10ff8f0a8201f030121a17f215388",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_cluster_dpm_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "0e5f3e21e20895eaca6108cac0057c4d2326b0092f6d72ffc564a8640a10462a",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_cluster_drs_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "a4453c1f24c31359622dc9e47ab4e15acaced0e13a1927b2e8cda2bd7552bdce",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_cluster_drs_recommendations_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "acd7d7fde1366f53a39355266267da9abc3ada70be6c532d7927cd057d866890",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_cluster_ha_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "0dbef7a88233e29614ecbf7570675eaf3dd4eb47378fab92b93a5ec496b97972",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_cluster_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "961fdbade29094b68d5923ebc6be286046459b80e895421058d39bc6b4fc258b",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_cluster_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "9f661f215c8c596ba95df9d4e1726d4c42385f7ffa669f4587d671479c8751c2",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_cluster_vcls_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "b524ef18fdacccd177de8c8b6e55795cb5863b74dd51eba8e5db992e187592d1",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_cluster_vsan_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "479e5d438352f8348d76e334f2e0d171c0b526f98b907d1c8979181256ed8750",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_content_deploy_ovf_template_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "0eed9003ae2a7f47a94a2f145581b51bcdc38ba35ae84eef920194114255ac31",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_content_deploy_template_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "05b2aa0a230676bd6dfedf9a6e2241d9013f66a25c79d2b180e9c3adc223900e",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_content_library_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "1ef3dc7a2748218734f70da0789ed885676ea653d3faf5d115277da898a2fb10",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_content_library_manager_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "a5a8b39892cbf063d51d8b72f88d3f5a01beea4c5a6f37689ac599c88797497f",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_custom_attribute_manager_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "6319ae5a37f0defa59755c5e32e4af6fa99a6547854adfe26c4e1310452a34a2",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_custom_attribute_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "1f33a0037ec51235be21121050a88814ef8ae46cc4d97830c04e289f7d2645b3",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_datacenter_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "4aa2414d31e8af044d24c08dc3f9c76fd1965b2a67bc950930b3d97f128d9002",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_datacenter_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "bcd1d339f2b7882d91566996d8e2e97703fda9228ea4c068dc215ae9818b345f",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_datastore_cluster_manager_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "e2a05e2cdc2a15b876a2e05d4842f1306348d0da4d338825cf9fc56bda89073a",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_datastore_cluster_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "24897ec8e7cb276546fa94c7666aae15aeeceb7871948cf82428abd4d3b56f8c",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_datastore_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "c1ee927e0d894b798c35ad5ab8d82f0fd56c758bb757e54e9871dd624ba76663",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_datastore_maintenancemode_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "2a0fdb9b75a6177aaefcb2aa86cf522c014376fa1986ff446a49d50abd523bf1",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_datastore_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "875ad5490c84034f642b2e18897da50eea4f24861b9a9fe061b4078186c402cc",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_deploy_ovf_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "ca229da48e83758f1b9f4cb0c2f3c90916b56d9e60ea0c83fb7fc12545c50482",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_drs_group_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "008fda7aeb3fd3cd1fb907ae4804da1d00ed48509f0d76bfad331eba90e4dab6",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_drs_group_manager_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "57070309b3d0330ea70088480f43cbbb10a69334c4e0b8f3efd72d46f6766a02",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_drs_group_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "b297cb46870f2dfbfba37a3f139ec4815bab84b616557fa9b415312f9714bf57",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_drs_rule_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "0e326ca37d557de68a3f51d1ba99938f776f8ab8111a162cbcc9cdb4d24bbe26",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_dvs_host_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "bb5866af85c9a85db72e02edc44704b05bdc59646c096b1af7f58e6847e40af7",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_dvs_portgroup_find_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "603ff353f319d2a2b0d7dac604c045930237b64e022dbec1a3fbd9ced9a9810b",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_dvs_portgroup_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "0d62caa77024b3e083346e2b9e2c8cc92ab44905d50fa38d37fc96778b2c90f0",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_dvs_portgroup_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "438d25ec2077bba507cef44ea4481cf533705dc6b452547955141ce9e63044af",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_dvswitch_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "607629004a6e8b50477ad1d08e2d8ef95dd5ce02f65af7bdd59dfb5c88c24656",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_dvswitch_lacp_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "46d7a4e37e884886578d0165ed495b51c2701b442a232c5313e68f80a0ccd25e",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_dvswitch_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "6e4fd3e940a438f66aa93b9fb32a4ab2bec34dcedc3a2f58e41af6b2d82facf4",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_dvswitch_nioc_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "ca1ec29ff354440849b7a2bac77b7990c27e94dfb3c11d73cb944d16e0500974",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_dvswitch_pvlans_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "828ee7aef139ce3846e7a28ab0dea58f1d9e3d1bdd211124dd838ce105068954",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_dvswitch_uplink_pg_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "ab73230c445c571b5af95f8a98a0d8a438d70ccae4b1ca8c1f1ad34f8b1cb80b",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_evc_mode_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "3a0f39b2f45f6b313957378e2bac5ce37f660a4da0daff2f44ed16be4ff0ad19",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_export_ovf_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "ae1434f8a5d4ae0a8346f70e28e49bfd1cf44396b080a36e9c34b2714d6dd5c5",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_first_class_disk_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "7ad0a737e06542acb4ee60dcc66e01d7889448142b40dcd0a5b2913eec5ff7f9",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_folder_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "3c0fb43f56da88ece0963d40bff1f17b03fc74c57fc25bcbeed8178ddbb0add2",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_guest_boot_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "bfec4edba184c18fcb3534440f9b8f1f5892c7ae3f90a37669e15026d6fd9260",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_guest_boot_manager_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "1e066b6c317d86abdabdbefe654ed2857fe7281c51828a7cb18e266165ac93c5",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_guest_controller_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "3a40a2577fe04f0d84f9d84d1e02ffd5d7673c297e0173ba36525b26c4060cb6",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_guest_cross_vc_clone_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "e582677ea1472c7d0e19467db9c58393fe96dc11fb853c498912154745fddea7",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_guest_custom_attribute_defs_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "ee16271d09a304413c3b3bf465bdc792d788402cff95950d0312ff73625fec63",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_guest_custom_attributes_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "55970f2b7e01cc2dbd4bc1de4c8ea677cad75b99289c5cf4a5414bad0ec891ef",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_guest_customization_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "9580d40d2ed2b621b9723a04593fca7989b5b4052247220d7c15cda9ed7dbae5",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_guest_disk_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "a4c85bc125ec09b3d81581ccf975e85de36214c31bea1d1ca5b96e3b789f8701",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_guest_disk_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "d5dfd1608d488c2165a7423e564220da9a4b116061a708bddf067e01dbf061e6",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_guest_file_operation_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "6b3cf2150c13a7f37d418476724fc381f7480ac17e36c07e39981f5053fce379",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_guest_find_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "703deef7ebca354c2917fc78319c67d6889578f09ada528dd365960d26b4b203",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_guest_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "71eaccfe3d2573725dcf249d250643dd90f76a08c5a683c375e01d72865d19c1",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_guest_instant_clone_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "3a2b477a6bd39c31c334f0ba8d96ab5266802b194bd79e69c7281970a509ee77",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_guest_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "9fc1d0847df5ca224cf7f2a77bfb246fd971912ab7a3a39a39a31cdf75121084",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_guest_move_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "c3eedce46c6a6b469ff0bee8ae5699d1ed3aef89c297b8093ebf89477fede09e",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_guest_network_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "bd74fe9f9debfbdd639046181d286f88a693f18a81be9f67f65a1edaaf37415a",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_guest_powerstate_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "a2627c19b14d62d99ed361464ed2c3e109745195bf5ca6c2f17160c64e6ba308",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_guest_register_operation_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "70386a526429066ce5a01643822620551accc5c4d858423445bdf3778d158b86",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_guest_screenshot_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "ac5ab5e1bc87b4038a9bdb6fe458121b11be5a3edf03a8900f03171bfb7b48f9",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_guest_sendkey_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "f91930dd32ae3880393fa7c78b25a152adaed7a15e5f1505d2bc6db506d819e3",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_guest_serial_port_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "64638706622f37aff84b59d57b9bab79ae621ca3c6d5a6bdabf57297b2a33eb7",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_guest_snapshot_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "e338b3f37dfe996ce0f5f1e632ba1b02cbb0c970dec14fc142692a7c01330ce0",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_guest_snapshot_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "ee4637dd73432a90f835e29a61f29d15a06d4db570b782ed2707cff46a4e6a4a",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_guest_storage_policy_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "d6aded1f3e7f50859104a9b37c1f8efe8349b1e3f60ecc4132a94e4974e88bc6",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_guest_tools_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "84c2c774ff6251334e7b3bffdb255f66e6d66fe945d041e05f8f747a236b75db",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_guest_tools_upgrade_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "6b40de20a18ed213bbf1e1534a3124fd0a4da2d2978bfa14ddec48b8176af221",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_guest_tools_wait_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "bce15e144e64c9d0f953bcc3e1b0383ceacb1c60765f558aa4d8fec41b454987",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_guest_tpm_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "697dd7406d32ab8719886be4f668359ef6486020ec813214b213f4d90bdcc985",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_guest_vgpu_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "4026d5df40ea4cecc8cf82389e1b12301b67de669c0cb46d87b242cdb86760a6",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_guest_vgpu_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "0d5c747d5dfe0748b50aaeea3af1d9cff7394a420b26494b7f7321a0feae0f75",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_guest_video_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "910e7ae8da76a79f675e0f0925423a07af5f519050cd57ee09f347a160c6cd36",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_acceptance_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "b56f7d60fc0536d7674b97a98c9e9222e435beb0de9195740f38fc4ae36bc69c",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_active_directory_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "e8a0c821ff3d0567130596f787f9c8d23aae95cf604e2a30f72b1dd8598645ad",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_auto_start_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "eef062ea463a71141ba9bd4105b1b252c86af51799ce28957c0b91d6a819e6b6",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_capability_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "7adc723de2e3d95f4e50f8890da8a9ffa89e3935c37b66c3c5f46353b498838c",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_config_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "a3efd10f7492840d23bcd162407bce6b5eddfb91db2eb020d16325a3598ad9cc",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_config_manager_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "0b5b2c582b214cb5436d27c9c4525e30cb943a11f51d5b06d275ef2ce379f6f7",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_custom_attributes_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "da110b28ebfb45a7f09c1a6e41edcdb64990956b51ab513dcb199262016013f4",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_datastore_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "2b5f95d3e3c64350818cd971daa8afc8b7064f5ad278ce385121b77be3bae1d8",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_disk_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "85bbae65d082c64b79dc36f07f88c5b9d9b27ae25c2c865b9f5186b83b72a2f0",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_dns_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "dfc7b549d5147d0eaaa1f1b7788e7d81245f0c140ec9c9904255d3bbd564cb5e",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_dns_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "405e8494cb23abeb749324c83d4579a6fb1daea1adeaa5d4ffb0c1505ee0e9dd",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_facts_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "bb5d6f256f9bbbbef9ce78d94034560c1f7c327a0a68dd8319547a07533899fe",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_feature_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "996ff4c4991b675aea9d1b47bec4c8defb1cd02193f9caaf4854611cc23b6ace",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_firewall_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "22dc384bb5a008c3c9f78bc4a4bd6207193e2654406a8e33007174dd843becb7",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_firewall_manager_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "18609541684ef4c77ae2139979e991b2394b965e28c39c501b269c61dd994d0a",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_hyperthreading_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "a48ec9c62daa72a5b8e7ad9b1f7ef1affae1387738a9c87a9ab3d925590300c6",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_inventory_inventory.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "d231ea12254777395414f1039407ab3dde05c7055c6071671b6d6cd06b8baeb2",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_ipv6_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "55245a86cafca7dc9094aa7006f833aa9020609c1b9aa181743e5d2cbb0952f0",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_iscsi_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "26f104941282606f82494992d2af4563d4194eff2d60a9380fb29718ee2725ff",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_iscsi_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "4f9e57ce0fea7d409b2cfc1dc9de6df70c9f14193105db3474f0d9412817a6f4",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_kernel_manager_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "778d23c91951d537a5d3592028f0d7ad367a55811c73be32d4b44f7378ca2f5a",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_lockdown_exceptions_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "81379d280d708b5fcf3358d561974f4e16c3195e5da518685ac7cbcaa8690865",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_lockdown_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "c916e4de5de2d2923c25cf32853ffe8d06c1e2a45262721fa0f7cbb8bd08c146",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_logbundle_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "459b1bbc8ea3c68408167de8706e77bf7eb7a5a109c31c7714e55b6971d5963b",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_logbundle_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "7c24de18efc8a210f92bc33862850ddf72761ad3aae17b0c39ee6ff5a081148a",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "d6566bdf3a010ea987a3879ee98935baf8b8cc6dbc084b6ebcff5c73eef0f2df",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_ntp_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "aeeb259224118c7ca13e789ea3cd0eeb67dc695102db0021a70a43e7acdb46dc",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_ntp_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "14e23e9b1e6a2467e512304cb9f5d4c90102baa7e3b2e1b68042727629136fed",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_package_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "93e69bb4afe71af5b9e39c3f4bc2510e19b1b6c4d792e51d83e8225e34715ea0",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_passthrough_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "11c6309162ee20bcfe3cf4fae8511a750f9f1b872df1c21f6b71d928fcd2c189",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_powermgmt_policy_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "4184ab0a7fd717d9aeecd86caa582855a0222b7d88c7dab4fd90da1497956b53",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_powerstate_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "39d408e3effa2fdaa96a2932fc7855a7893114ebccf3483f82c3d4889cc3f064",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_scanhba_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "796da6615e0ed0e7ea85fd9a6df1ddd0bcfdfa076cf2b272828668c652167515",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_scsidisk_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "6dd5869da0a8714bc58d2bf7fe5f35e8ff8ff8d938db1482c5baf3a94637f9ca",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_service_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "6dbe41bbfbac97daba9e82e7e4694b71f2f1d7ca922bf8abfd8792617f061ae7",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_service_manager_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "ca3e75627ebebc1dbe56fe1a72e120fb165a01df0df4308921c5b2a77547e4f1",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_snmp_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "a8d5e0cd09a49a65648f7fa87b5f6dee5da515898af98011f3ae107de6c199c6",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_sriov_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "89d5fa860d45d374ad885da720a91a2429830c705502893e1a84160168cbe050",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_ssl_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "3900a9e55f1e557f4d8ce0e57aba2e3e92305fcf7be9ed3a238ead9eed56ea35",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_tcpip_stacks_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "ef4bcb55ea1aa4b804c6fc9ada675f3b36d9e9242e049798a99c57e11e5a9951",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_user_manager_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "b555d0946f03756c5e3c270dd4640d77da903a179cde92c8ab72866d3f74c004",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_vmhba_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "69f4d6713af3e8f6c7fc345cdffc7143ff0b4458a9aeb62ba8684b5cbf3adabc",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_host_vmnic_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "896d3e924b42f8806f29270235df9c12bcc96fde32cd9e6635b875c668f82cc9",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_httpapi.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "9994d078a993f75c14191548a29d647c3528c68dbe6b07d58033e2a4861441c3",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_local_role_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "1dab4c8e11e5164d23d82d94389f218153fc21ab7fe6eca03f20fc2d941bbab9",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_local_role_manager_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "8ef08646876af48d5afabdba032fa4afe9e4cace26f99d61f7c8d2f2223cd3f0",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_local_user_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "e66c293e45828b720063f7ab6d3ab80987d108b8d131a6d9da865160c2112503",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_local_user_manager_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "7a9bb5570d201802a5dec6da9a94844007af2e8fdd15b158369f47f0fb0a91a2",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_maintenancemode_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "dd969741baf165860f18b3a128784f276240fde1dff0d8c151f720086bff4724",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_migrate_vmk_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "3852922c062edf70bb49c9afe6adc024cf0e1d0020b31d2ebdd436168b881af7",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_object_custom_attributes_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "8f88b09cb1ba09f20ae4f600fdcd858c9b551c0292b5f793aca47b4a703fcc77",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_object_rename_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "56a632d6382ecbb18a435216101141e0cd40369ff1ef9a2d7866873e44a4f8cf",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_object_role_permission_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "73bedbb95195dd721cd2f45daef1f6c3d9db4d6b6c8ff5392b7c16cd7f09c780",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_object_role_permission_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "9816ee19a49a893b83ae65cbfb57505f7fd739200208db2c633f7441b75d88b4",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_portgroup_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "8770df13c5efdc35bbca7ecf9ddc1acd4693d20a9b8c82fafd0d6167d7b391de",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_portgroup_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "107bbf738e557aa4f1069abcd2b37717ee524c388ebb8465a25e736b60be85e7",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_recommended_datastore_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "bd897cf188c9e9db82e26f94d620a8efb852d79844f4ad2327eeb3997a46eb59",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_resource_pool_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "b3ea59b5356eb502b7c9d4342a5bb4958c24d4fea47be0839e680643308bae0d",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_resource_pool_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "460c2e7d94914a430c5700ea53534cd52da3ee1f5a3b34c797c734ea742a7b6d",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_tag_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "36551aa2ba9ef224538aa67fb8b30e109fc222802c6ba81632b2972da71fa37a",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_tag_manager_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "a3ba19b31cc8cad6e8cad03f4fe656c9e352bbfa4cbba32694088c339cf77307",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_tag_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "ddb403883cd973553deb669d7e2d8abf464e329c19ac83dacb1ad9e1ab2f54e3",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_target_canonical_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "d923cce176f87500ca45c93a188ace7da1c61a783acb46f5e0337bbd48ade56c",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_tools_connection.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "068cf52267619e88df28fe4273ee04d488e351d10bb0abd4d70d843569dc45c8",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_vc_infraprofile_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "c9b57b8f24b7c4cfb7bc7abec655cac1ede74d923d412614754fbf20c1447093",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_vcenter_settings_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "9734e525bab3aea58148b93f5a063cfcf08988ff923ff1e965db669d8f7cf8ea",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_vcenter_settings_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "caac66e456abdc12313a9a9c863d35981502f03edcaad9b4b33d84ad0c4fddf9",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_vcenter_statistics_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "66c1ff4ad11b3ec2960b25c2db985fd895ff8093e6a662115f7bdac87b75e941",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_vm_config_option_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "aa7642c13167e60344aada2a68a5cae00bc43ef93ca217c9d0de3af785c22b81",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_vm_host_drs_rule_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "e4ebabf7a2f4b27a451384156a0379abf579dfbadbdedfd3a3e9184031d5d9a9",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_vm_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "2769d922a74358139c2782261b2ab6a9890cd9b4996916e64dc9cdada1f0ecb8",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_vm_inventory_inventory.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "579320a0a90fa341d0a1bd9d932724bdc0b1d4a5c9b779e2a86a867c3e2d99ae",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_vm_shell_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "0453c7a53d5719592540df2f4af46293379a42cc87c0ec6f15fc77dd6f904402",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_vm_storage_policy_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "007306aefddb55260cef566639060d3877ece6a99105069a3c3749a4da921ca6",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_vm_storage_policy_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "f2394ebde2cc5f36ce4972feaeac0e2c24b5263309b9a448aa18606df9e14f37",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_vm_vm_drs_rule_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "1f991138a206b72df15b1211b677e032766689c04b4bd346f2de53437fcde55c",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_vm_vss_dvs_migrate_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "a8ab5ceab522302e441367b82ee5b4b2f0c41162fbf4a996f37ed47121e3abfa",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_vmkernel_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "9174d960e1d8796770db5d75f77af32e899878490e03feda42a4846d796d0f0a",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_vmkernel_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "e0d434bf12c4885034f7663c075e23ca02efb6b56f7698f8778455d36426894b",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_vmotion_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "95d1fc06cb4cd5f0f473e173b50c3ef33c858bb8c91bb846f9d4d94cfeec2e0f",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_vsan_cluster_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "2cfee124b1d4742b14a932734ead90064ea897367fbff71942c3a529b826d8a6",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_vsan_hcl_db_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "c7dcf802675e727ad300bae57e1924e9a40ddab255a65d2e2bc643b82eac414b",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_vsan_health_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "f54a431c671365f487e10883b5c5ab42d3644a3f336aef43ad48551a06abf8c4",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_vsan_release_catalog_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "23d643e42b6f043860cf001ee630f901f672e34a8dddb530e8501d77ff40497d",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_vspan_session_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "b747d2f5f7c9bb7b358777033aadbeda2eff2deaea98cc1c4a41068558ca520c",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_vswitch_info_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "fea651c81066ed85ce03d7bed104166fbdf9ea7411023f61f49b2dab14e10fef",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vmware_vswitch_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "6614186e522d47b1e02018ca59795009f72e0dd555e9e5b8a291cfbae02f95d2",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vsan_health_silent_checks_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "b39bfb7ca7b396b6fd25e83dfa148d7b2e8e5c203332aac10ff62943e966cccb",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vsphere_copy_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "5b79af421d514e99586619e48dad4a410712cd50ac1d8b75290b6f9969192c50",
- "format": 1
- },
- {
- "name": "docs/community.vmware.vsphere_file_module.rst",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "7924574243254027980a0cd0ecbfad8759544b3ab4f2ed03a5dc77ecec72a391",
- "format": 1
- },
- {
"name": "meta",
"ftype": "dir",
"chksum_type": null,
@@ -1481,7 +291,7 @@
"name": "meta/runtime.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5afb1282c86d41608f064895b0630e873292d76eda1b27a086027d8a7f561e2c",
+ "chksum_sha256": "6b8f4f91c50cad886a4518aefee3ec6b06d0ba0f8b4ca1012b9f2f5086549b2e",
"format": 1
},
{
@@ -1509,7 +319,7 @@
"name": "plugins/connection/vmware_tools.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c7c6a9a1ff83ad574b306616b148fbabaef0fd63dd66d2729caa6664afa98191",
+ "chksum_sha256": "de2217a846324e94fbcb993a297d718b5f3aa4ba3e81f6ec875198b5e29b2a27",
"format": 1
},
{
@@ -1530,14 +340,14 @@
"name": "plugins/doc_fragments/vmware.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f4fbd8c2b9cb357e5bd2439a3c938b6a29449b8eec7cdf1a768ce2cfd4504958",
+ "chksum_sha256": "06348a39b25b21a24f79031dc99652b42cc09df93f54c29445df2dce0bbddd7d",
"format": 1
},
{
"name": "plugins/doc_fragments/vmware_rest_client.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "970ad3139b7ac3465ad1781b69fba4a6409aeaa5c3328eb9c7127294d579c27a",
+ "chksum_sha256": "cc694d07e9412e11238a8fab29a003337a21a1acb73c836ba9ed91923a74b8e3",
"format": 1
},
{
@@ -1579,14 +389,14 @@
"name": "plugins/inventory/vmware_host_inventory.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e71ac011595da71e9c3ee0be98a7625e5329bf46976cdaa5a6e662d49f9d0b46",
+ "chksum_sha256": "103e7ca1360c9ea98800c50e542a81977e819fb81956e953b9cb6e3cde2f0f87",
"format": 1
},
{
"name": "plugins/inventory/vmware_vm_inventory.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ece922d0c2eaccc911a0ac2f4cba9d23767e8f600c5ae19cc2d9bc43640094de",
+ "chksum_sha256": "2edc7d6e16362878fd029939721cf0a7e50d52bdfd46ebe0c0352aeed275e937",
"format": 1
},
{
@@ -1604,31 +414,31 @@
"format": 1
},
{
- "name": "plugins/module_utils/version.py",
+ "name": "plugins/module_utils/vm_device_helper.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "dfafbda5ff026a5f83dc968e9ab8c5a13a216794c69c2ffcd689b03d39c3e8ea",
+ "chksum_sha256": "89707aab7b77904283e1f33f99e14c0b81932d0958fb3c8716cdce9c68c2e892",
"format": 1
},
{
- "name": "plugins/module_utils/vm_device_helper.py",
+ "name": "plugins/module_utils/vmware.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "89707aab7b77904283e1f33f99e14c0b81932d0958fb3c8716cdce9c68c2e892",
+ "chksum_sha256": "7dc70d2619b3e76336b732af47103d65ede45c8bd780aea3a67cb324ddcf3ff8",
"format": 1
},
{
- "name": "plugins/module_utils/vmware.py",
+ "name": "plugins/module_utils/vmware_rest_client.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "118c1ee8ca543d5f1758b2f08aa8a03d73808c87d1615caf77da91f47183eb65",
+ "chksum_sha256": "0dfcdb4ae7c09657e05b6abd7da0e4120bbc83085769e82e3562a6d83afda15d",
"format": 1
},
{
- "name": "plugins/module_utils/vmware_rest_client.py",
+ "name": "plugins/module_utils/vmware_sms.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "39a7616284f46c36c84d924d51a3a613a984b615e88eb42a74b112fcf4102725",
+ "chksum_sha256": "b17e5551eeee0fdff8997d10fe11bd1935ebfc8a330a498ac0205d1936a95110",
"format": 1
},
{
@@ -1656,14 +466,14 @@
"name": "plugins/modules/vcenter_domain_user_group_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "746e579f611d55b23cca35a0135aac2f85d264b31b813845ded4ad5fc3f04f67",
+ "chksum_sha256": "5c9b152d01215b050c5cd656b641e730d621910bf8c109a517d82ed7641a9666",
"format": 1
},
{
"name": "plugins/modules/vcenter_extension.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "87ec2b5a4bf5c844b2392740af99f4e676c4cdb43bb4e8ce13a6aeac5e750bfc",
+ "chksum_sha256": "c3961b0642ef04bbdcdbd361a00cbc618068496db39b59c97bdb466be184969e",
"format": 1
},
{
@@ -1677,21 +487,28 @@
"name": "plugins/modules/vcenter_folder.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "63d53b9534d79c7acc9e1e4ee9c48238030fc2af1076517f248aeb475b533de0",
+ "chksum_sha256": "11e5b4064182b25aaeb7ab2ab1d9e5749f1e0a89244848f90c9f40b34bc82196",
"format": 1
},
{
"name": "plugins/modules/vcenter_license.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "22650c8ef4306d6f384a0d02d72259bef418b241f24e0bd48f2b52cf3baa20b7",
+ "chksum_sha256": "4009ac400a6dd98b3930f8400b4eee72e84ec6a64a6ce19eeac5ea7f543c96a0",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/vcenter_root_password_expiration.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "b7cc723fffa49de72aef8bc2d3f813ffa3dca970d6db9a48ee85783c00b656b4",
"format": 1
},
{
"name": "plugins/modules/vcenter_standard_key_provider.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "be76a4b09b8162b79402fba49ee807a1ff8f9015527b79bd3e0f1ce1bdb3c0f8",
+ "chksum_sha256": "3a5fc421ea0352317540e148ec1dd23dd1cffdc05ced66c0de285bd22ff04764",
"format": 1
},
{
@@ -1705,7 +522,7 @@
"name": "plugins/modules/vmware_category.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "de20b63f4d028477eb55e5b3ba4a1b28f2b580a3adb2687f6f4830b8b11057ed",
+ "chksum_sha256": "803becfbcd55ee9cbfd72cd45c462bc712506b9cb88dd1a74cdfde0dbc8e127e",
"format": 1
},
{
@@ -1719,28 +536,28 @@
"name": "plugins/modules/vmware_cfg_backup.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fcceeae9a329e013ea387804048704209df1b5fe5e95f36d26f9f5b4b29da0ef",
+ "chksum_sha256": "35d19a37c477be3b7c9ba360732a27687db6ab39825a62e8dcda963369db93b4",
"format": 1
},
{
"name": "plugins/modules/vmware_cluster.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "abdb07d8fc9b503cffba21ba79d71b302ef1c4137377421b15038c7f74ef6879",
+ "chksum_sha256": "4a98362ca64844cddaaf8878893a9def9bace3193a2bc8da8a877bee1edf854a",
"format": 1
},
{
"name": "plugins/modules/vmware_cluster_dpm.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5b9be5d125a67aac16b7a0935e8bc9c53f3768883f84485c3c9c3044d52f2aac",
+ "chksum_sha256": "3f463cf81333d20291c899891abda5f48b1ff74108e949cf3b11c4b754df8683",
"format": 1
},
{
"name": "plugins/modules/vmware_cluster_drs.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5d1283a1abe53df7d6724ea1b3c2b2479f0b096203776f5d26d4739a1e652604",
+ "chksum_sha256": "2b9b944de75a0973e2540aefca3bd3d5853d803cf5965d967a7a79c2a4b96dc3",
"format": 1
},
{
@@ -1754,14 +571,14 @@
"name": "plugins/modules/vmware_cluster_ha.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d3803b51827c5df33128ac54a37d52080a3c35d0226512e942b26b147147a056",
+ "chksum_sha256": "f5d91c541f5e62fa4dfa246dc8d887128ddf0f23876b15dbcb6f069973c69cce",
"format": 1
},
{
"name": "plugins/modules/vmware_cluster_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "38233014947450992f3edc5dfd7a5db98260f08c5d4bec29c736e04bec9d18ad",
+ "chksum_sha256": "82f3e55c5865b15aa735c536c1a6798cb202c7f79a043b54852da7f3e29c3599",
"format": 1
},
{
@@ -1775,7 +592,7 @@
"name": "plugins/modules/vmware_cluster_vsan.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9423d8f879cbcc54be5ab8f210df38e52f1c423ede1a38bc2bc4638c6878b9fd",
+ "chksum_sha256": "fc41f927567108b1d8fe017195d140378a73480f89d503011b270818e6b8728c",
"format": 1
},
{
@@ -1789,7 +606,7 @@
"name": "plugins/modules/vmware_content_deploy_template.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "55ed4a64d080198aea2445c0b98d68855d51241bd3ab34e3281b86251b8c92fd",
+ "chksum_sha256": "f72369be7754bc4e22ffef0cb6a56db07532f0d391b19011f20f2b5ecc426d84",
"format": 1
},
{
@@ -1803,21 +620,21 @@
"name": "plugins/modules/vmware_content_library_manager.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1f2f21f397f5d38c450424d171d48649f21b2d2aaffdc6682a538ad228250dc1",
+ "chksum_sha256": "4efe68143e7233415a30e91fb71b68b24fd8635305a29899462943fe6e834286",
"format": 1
},
{
"name": "plugins/modules/vmware_custom_attribute.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a85680714031951bb4eb573f1bfb2d974c2da76e7d0b7adabcd28f5eab131cf3",
+ "chksum_sha256": "a9ec9279354b74f77ca3abe317a36906f9f68b63fcfb4d10afcab78da41c0e9c",
"format": 1
},
{
"name": "plugins/modules/vmware_custom_attribute_manager.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ff905c8890be7bc756adcc835587e22156ee57b1f7c81700727b9d874b928fa3",
+ "chksum_sha256": "70625e3e723db202cf4c3510d3cc85d369c010ea0a37eb21274a43734323f1b9",
"format": 1
},
{
@@ -1831,161 +648,161 @@
"name": "plugins/modules/vmware_datacenter_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a3482472401dcc64635465baea3c081b082868e90dc9bbfe3b365ab83a4e752d",
+ "chksum_sha256": "206991b567645c273700b018f4453bb777f3a182f73844a7ed658c38c9d41311",
"format": 1
},
{
"name": "plugins/modules/vmware_datastore.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b6f0432d0fb703569e3ddbd465be0b4276ad0d73f570f1275babca18117e9f34",
+ "chksum_sha256": "5dc249eeb966428d4c9d426680f5fae46ff8b50e6a5626ad04a4b979243faa74",
"format": 1
},
{
"name": "plugins/modules/vmware_datastore_cluster.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fbc75aa5e1b04bacc0d3ee538f38f90a784cdf640949776c656108adf704cf31",
+ "chksum_sha256": "32e575cf227fec3ae5004d97b413c3d9a2ed4bf0f0b3b6a0479b344d6c7c7147",
"format": 1
},
{
"name": "plugins/modules/vmware_datastore_cluster_manager.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c57f803612c047bf22ebfd0f3e34a164c486a082076c252b1aae0c99b9539ffd",
+ "chksum_sha256": "d777f38acda366326fbf061e4037ef5a0ffb98384998224076a45192ee73f69c",
"format": 1
},
{
"name": "plugins/modules/vmware_datastore_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "24735940b6df13769d3e9472c724c8753f2dcd1d5c0f82440f77192d3e773223",
+ "chksum_sha256": "f18ba418804c7f5bc856500ab4a6d9e24fa558a15340c5dcb28495961b5e562a",
"format": 1
},
{
"name": "plugins/modules/vmware_datastore_maintenancemode.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0a1da4552796a9b9cf785e960719c17b2784f53d84d1ce23ed0ae244ec2d968c",
+ "chksum_sha256": "cfa2dba2a112f0b14660ea505009439a398568b01706e4aa2e8a57035a0502b6",
"format": 1
},
{
"name": "plugins/modules/vmware_deploy_ovf.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "22848988b0c33934f53e65a2a65dfc7322158879578f9d94579b696016ba8bb9",
+ "chksum_sha256": "7fc7ced342d72f868d3d6d8919f071732ee35bdee34af491c9dbcae1272a29c9",
"format": 1
},
{
"name": "plugins/modules/vmware_drs_group.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "deaa4c855d0042897c718bda4e498872a2744c8dfeaee5a5bfcf68a55cd090a0",
+ "chksum_sha256": "2f3714821afe537c19a0e7c0a4b753099f0eb1de8b6673aa5205a866c1084a2f",
"format": 1
},
{
"name": "plugins/modules/vmware_drs_group_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "351e401cdf82f7a5d262ffbcfde5464ad6c835b290490c87db24cb6d10a9ccde",
+ "chksum_sha256": "3197dac994ee145b1497effaf9b2104598b72cadd78139e1082931e843489859",
"format": 1
},
{
"name": "plugins/modules/vmware_drs_group_manager.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "db6b5c3322b130cd95b0a00be18daee521fff756287b6fc58f8f22c2bfb7707a",
+ "chksum_sha256": "9defc31500f12550df1ef928cdec3c6bb8aa03d695e8557886792ee9f26e1cdf",
"format": 1
},
{
"name": "plugins/modules/vmware_drs_rule_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8efe3a7cfbc861ec34895818f186029ca7ec76ddc7896908475af53ea5968b76",
+ "chksum_sha256": "cbd5b6eb89f4b3199f868e84fc450a120a4f90d984413b54df9567009aa84cdb",
"format": 1
},
{
"name": "plugins/modules/vmware_dvs_host.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d62d1b0635402f3ed85800f4d001ae94f282ff9a658a9756ca1bc8b92e518176",
+ "chksum_sha256": "09e02529b1e9c99300074bbf5f020cf072c785e1e3c4d707a6bcc87cb282db1e",
"format": 1
},
{
"name": "plugins/modules/vmware_dvs_portgroup.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "74d2b1a061d57ea2c9b71ed809c6de0e9ce8f529ff6a75211bdecd1ba708b29e",
+ "chksum_sha256": "62e5113c13f94cb054db298f8e7ba9ea775fab8f7b148312f2837ffcd68c4eba",
"format": 1
},
{
"name": "plugins/modules/vmware_dvs_portgroup_find.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9c689d7a7d3ad5a2984ddb41dcc10e00bc6cd746c5b1dcb7d8816d7be6f18dee",
+ "chksum_sha256": "d16b2bfbf8adfb052f1ba30aacee1dc5704069779ca6425690244ee1cf8edc5f",
"format": 1
},
{
"name": "plugins/modules/vmware_dvs_portgroup_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "572db99b54d7710d40966629b7aae7b54876eefc2ae4edf11c983dbb0ee5bae2",
+ "chksum_sha256": "49c2496bdcd3c70b5ac49a2ce90ce306b240a53995d77fdc28ffd5883ae7aaed",
"format": 1
},
{
"name": "plugins/modules/vmware_dvswitch.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1e99c68faf7836e649c0421092890110280b762ba23825992505941a01d66df3",
+ "chksum_sha256": "e0b58b5ff685fd093fa0b97931473dd6be059b435a6c0e332915019d342ef893",
"format": 1
},
{
"name": "plugins/modules/vmware_dvswitch_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "30afefbdd83095015696f7dbcb6a1cd9324bcaa3abfc883ff03e61e9f91b8946",
+ "chksum_sha256": "60c4835bda0af924c470d6fa719849a1189e8877b9580e207927b82095a15b25",
"format": 1
},
{
"name": "plugins/modules/vmware_dvswitch_lacp.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8472e07e259f68f2bedad519fae1c5fb1a251f64e2d23391f26d0ef3af374543",
+ "chksum_sha256": "8b03f00a9983ee51f2fa62e9c1ea4fb46b5f961cf26fb08cc23e54b0e490247c",
"format": 1
},
{
"name": "plugins/modules/vmware_dvswitch_nioc.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6b33075b47fda62bfad71244c1ad67895780cedb86f32a7cddb77105313e7820",
+ "chksum_sha256": "d453940f5054398ea7d16de2e3fc47ee44f3a652c65d83da164c837e8b602c1e",
"format": 1
},
{
"name": "plugins/modules/vmware_dvswitch_pvlans.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bfd5c066cf8d416c5aae3a8f9cdacfc2183dd31e874da9da36334ded77f98393",
+ "chksum_sha256": "6dee478aaf84e496370ae03049a89042030d1101d07d6f19a4d1d4d9aa5a8ff7",
"format": 1
},
{
"name": "plugins/modules/vmware_dvswitch_uplink_pg.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2a127eee6ef84fe0cda4915818daadca633ae883a0ca4226a9e384ca1b88e7f8",
+ "chksum_sha256": "81fb9cbc4a1fa038a15b6e958faf967a61dbe0a616dbd1bfaaecd36c57d59c71",
"format": 1
},
{
"name": "plugins/modules/vmware_evc_mode.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a51bdcbb448b2f1f5345b35e3bbb53d7ef0ed0db3dd553aeae9c005f4cad177e",
+ "chksum_sha256": "0d54062714308aab1b7ccc227da06181fbde31b5be0db7ea40fcb72f31a693e9",
"format": 1
},
{
"name": "plugins/modules/vmware_export_ovf.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "542215f39c93f342ebf91a85c545590d9008c824f959da960e9b43b971b30a87",
+ "chksum_sha256": "55d635752a4c3cc1af02ae255a1acf073781e4ce441195e76bcf5764551e098c",
"format": 1
},
{
@@ -1996,59 +813,66 @@
"format": 1
},
{
+ "name": "plugins/modules/vmware_first_class_disk_info.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "648ef76f0cfae66e1059df64a04ff78e3e352bc7d5a38004ff300bb15fc02869",
+ "format": 1
+ },
+ {
"name": "plugins/modules/vmware_folder_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "14fb65dd16fb6405e0785003752325c560eb91c14d4d7961427d0a3a2d48d3e4",
+ "chksum_sha256": "44a6c0578b32c362e69cb35b56727e19cd35a647dc7dbe26be048c2efd1c50e3",
"format": 1
},
{
"name": "plugins/modules/vmware_guest.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b41f86e5e2b2d43279aef20c67d75504fc58ef22b19f01fc480fbb999659353b",
+ "chksum_sha256": "55738b294073afb1f44d52bbcd1590ebd9f4a3fd93cdf563aa663a35f9e41560",
"format": 1
},
{
"name": "plugins/modules/vmware_guest_boot_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3a251403c587cf9246cdf9aec8a32cf5900a4356732297d67837e1438e5ffb50",
+ "chksum_sha256": "bfde416306ef52a5e3672db96bfee375ae25bada3dd20f3ecda7683f47524ce0",
"format": 1
},
{
"name": "plugins/modules/vmware_guest_boot_manager.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "15eee23b8ebdf79f3bbc506c25edb71a230e239d3f55936dfb0bec42c5c93862",
+ "chksum_sha256": "67e88707f99a21714c12a0263bccae93e7f2e7179eae4f5ce0083de4d268dbde",
"format": 1
},
{
"name": "plugins/modules/vmware_guest_controller.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "303044399f3af0eb1fe4d65463a9c385812b847dff751dc1a92e1700f6a0cdf2",
+ "chksum_sha256": "80c4af1521de6264c891a2e60f60fbd62d342011d072cf198cf702b52e26ce71",
"format": 1
},
{
"name": "plugins/modules/vmware_guest_cross_vc_clone.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ae9cb93ac82755628ccc6c22d84668bcf8046a23c5c1684af870396d04d5b660",
+ "chksum_sha256": "283ac6f176ab1cd023ac5b65784fa3fbfdf5979113b86ca3ca0473f1f36ac4e8",
"format": 1
},
{
"name": "plugins/modules/vmware_guest_custom_attribute_defs.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "625a8ab88b6f904b5d2044605b5f013d787b224477caa9bbf7e1ef4d3da14adf",
+ "chksum_sha256": "9f38d37c69a5ec093b0079f26e9edac222067812f7aa010567d60b8e7e507644",
"format": 1
},
{
"name": "plugins/modules/vmware_guest_custom_attributes.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6a46625deb7e277eacba740763841adbeb111d74cc6f2a0c3fae61471bc50ced",
+ "chksum_sha256": "44b22e628ab3590fc40fe01c79509c8bb598a7e0c6fbaff399760a2f0735f765",
"format": 1
},
{
@@ -2062,322 +886,336 @@
"name": "plugins/modules/vmware_guest_disk.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "90bb7f3f880392a45e2cd8b9602148cf1a2f54a554853c5eb3c19498344774b5",
+ "chksum_sha256": "aaadad51ac60409131ac1870bf3718e084b7a1ab931424acd68ccf430ff0c96c",
"format": 1
},
{
"name": "plugins/modules/vmware_guest_disk_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cd6c46293a0a87d307b661dc4245b7ccd96aa54be6d5c4edaf143f84efb01d43",
+ "chksum_sha256": "5e3f6251a881e672180694dbfe1c548625acabb8a0ac525d1c675d98aafeae7e",
"format": 1
},
{
"name": "plugins/modules/vmware_guest_file_operation.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "28156fdf4e14fd54241092ae9473b6a57c72445ce5a6268acb4b5338e4bdfae3",
+ "chksum_sha256": "09e4a33350bc881a2abf86ad5a5915ebe145287d251823b1d5ad940e9723c7e5",
"format": 1
},
{
"name": "plugins/modules/vmware_guest_find.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e628891c39f9c36defd936bd75991a64b45419c9ba75674abb97695c086a01f3",
+ "chksum_sha256": "708408a436e0f8dbdf60b47df093fafbf9cfbb6a29dee594f16aa6db494ce6e4",
"format": 1
},
{
"name": "plugins/modules/vmware_guest_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e94827c13358e6cf447117fee4101ce37112aaea3bcd1ac4e40dcbce2cf75e17",
+ "chksum_sha256": "da25048b3ce8b821bb13c1c12f71546303867535cbcc8cf0957fd0d82a70d22d",
"format": 1
},
{
"name": "plugins/modules/vmware_guest_instant_clone.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "29ddf4cd4d86fe7acdb4d6b3fd8134c6edd8a87e478b5aba9d759605f6d1918b",
+ "chksum_sha256": "13d57b323a3f9662c6ef419b0d549f03b76fb98909c5361ce90ed387213359e0",
"format": 1
},
{
"name": "plugins/modules/vmware_guest_move.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "05f68686a81d17856797c701296cb8a7f191b6574a9503ee88d9ff88600d8121",
+ "chksum_sha256": "a7a8c7fa21886fd90d091511ebe933e0f3848fea87b886358dcf41d5aab48112",
"format": 1
},
{
"name": "plugins/modules/vmware_guest_network.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0c2573e00d9a77d67c8f799d4007e62ffe097906bf62f2dbade5ae18eb6b443c",
+ "chksum_sha256": "5a9b071cc10ca50911430c8b0fad83d92afe4f69206eabf6a1ad8ebfb1316779",
"format": 1
},
{
"name": "plugins/modules/vmware_guest_powerstate.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b57e0dc59cb4f10abf527f3b6077e49c088d10f33265a991cee39cd0e136ab8a",
+ "chksum_sha256": "7296037dcfa5296e29eb3a2f1fa6968267e80acfbd97f8279141331197f432b1",
"format": 1
},
{
"name": "plugins/modules/vmware_guest_register_operation.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f701312c790b7c17f14e8a2800c61912f013ed63b428e652ab37e268953a1b08",
+ "chksum_sha256": "367d95915f41ade54a88f5277a56d76012920e990fe6e2b2f6e99914cdc0ac67",
"format": 1
},
{
"name": "plugins/modules/vmware_guest_screenshot.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8312d556f741ed3425db4f2377ab24b6a2a6700120451986b0a656034d9d2ec2",
+ "chksum_sha256": "581e791515b4de8f1d010a63aafb6fd032621d716f84df4ed0c8c17643d1481d",
"format": 1
},
{
"name": "plugins/modules/vmware_guest_sendkey.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9c360dd991ab96b09e5ddb75219a2cabedda58305e62550aa7e294e7757413a9",
+ "chksum_sha256": "b7c7233857e429495fe4590bb04bb1d5969a69e51f13e4710f1f63858c6c8029",
"format": 1
},
{
"name": "plugins/modules/vmware_guest_serial_port.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "91eeaefbd798c3206504a1080354867ed23c8764e85cb3ce11f4128d5cb809df",
+ "chksum_sha256": "3d4a82e0766147b2bf06ed29a3c2ff8c18e8ef9b4fb903bcb2009ac2bad806e2",
"format": 1
},
{
"name": "plugins/modules/vmware_guest_snapshot.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4036cdef09ece74ac82564ba412aeb879884b20587f5d296b8be609832882acc",
+ "chksum_sha256": "bf3c5339f076c95b0b0525281829f407b862ebc9e5d3c41a85127d52c85ebd64",
"format": 1
},
{
"name": "plugins/modules/vmware_guest_snapshot_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5d4a301d533abe0d81f23fba0d5920d454a0820583a04cd24ad4f0c3aa159ef2",
+ "chksum_sha256": "fa004c7810fa6a502c68f6de1b89e74d329e744fc0ae803c9414ba59fece9098",
"format": 1
},
{
"name": "plugins/modules/vmware_guest_storage_policy.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2dc36d951e5e6bd5fef0be02152110a37e416c811f11a9fae02f81c2d3453ae9",
+ "chksum_sha256": "83de69a093891f34dd8ad71be700ad455616f00344f9aa05de00b25290b1749d",
"format": 1
},
{
"name": "plugins/modules/vmware_guest_tools_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9e926b81e6bf2dde9bb9ed02fb3a95ab8e53e3e3797032eabbf3fa0344180259",
+ "chksum_sha256": "b0eee01ad1315b25b15cccb47332890b7d60fb7f486e18951cda7b91678a7b3c",
"format": 1
},
{
"name": "plugins/modules/vmware_guest_tools_upgrade.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5c9854783e5550865de7f976ac8a64ffe4f0fbe86e0b6a79314919858290177e",
+ "chksum_sha256": "ba5550dafb743876fd5c67f9482d4cfc20fd070e5f56b4181f76e081f2c97366",
"format": 1
},
{
"name": "plugins/modules/vmware_guest_tools_wait.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6eb01f4463b6aefcd1c8aa104749e01dd9b84cc1ff2b17e37f52bdc55db20310",
+ "chksum_sha256": "3cadff1f0af126c21c659b2f1cc2e7874a7ea809ab4b3fa42cc19630ad36d6c6",
"format": 1
},
{
"name": "plugins/modules/vmware_guest_tpm.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cce195c73de54929946f88832448efcb287641d036a5038b2cc5572ef4a70432",
+ "chksum_sha256": "e73e993987116bb0a8f94f15be9a298ad523a1edc75577e70b18124f0a11fc50",
"format": 1
},
{
"name": "plugins/modules/vmware_guest_vgpu.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b2724252eba7174d50afd94f13b2076801e52d9dddace221f887eea4098e0979",
+ "chksum_sha256": "bc7cef555f0688d289cfaa7fac62e32fc2f0801e406602adeb0e85150ce6ac24",
"format": 1
},
{
"name": "plugins/modules/vmware_guest_vgpu_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "17de36fba0c30d24ad79f7045b895b79f2156d8620d34cc991e1af637f1c53d5",
+ "chksum_sha256": "d42e32c21a8c8b2447b869d73ee3235f893ab4ab9f0419be4bfb351b09c8711c",
"format": 1
},
{
"name": "plugins/modules/vmware_guest_video.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cbd740d193a7cbe1800ac82042aa74835d8a6e8633246e4b60423bd8e9417138",
+ "chksum_sha256": "e9bbb46a7f1d814bc172f12339ed7c74eabcd7b1b5f2734f5cca08b44f27587b",
"format": 1
},
{
"name": "plugins/modules/vmware_host.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fcd780dbc602c0e67952dd09551acb67b07850d475773dd1425c7f633cf9a50a",
+ "chksum_sha256": "ea3818fed15eded586a2964cb5e2a626ac69a5fdf108bc525d15717397c82a4a",
"format": 1
},
{
"name": "plugins/modules/vmware_host_acceptance.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "20675a69efcfb56c0a9ed895d1656aa685018c2cb816262172912a6f21ccc06d",
+ "chksum_sha256": "5270448dc1240a00b455ff9bbc7b848c0c23c1082fd546b1a4c8774ba13ea4be",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/vmware_host_acceptance_info.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "d6a69316e50d9bf5c410e3ed98b39110aae8768adfede6004a967b0974b54ce5",
"format": 1
},
{
"name": "plugins/modules/vmware_host_active_directory.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4fd12c2e86f29b81753b045344284a3897f06110106e85e9033e512a2697ae32",
+ "chksum_sha256": "6d5a878a3f01cbcc55ef4a26d93086c029ad9284fb261000785f85503343885b",
"format": 1
},
{
"name": "plugins/modules/vmware_host_auto_start.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "594c449435f3c00d65037a25d287d3af148b75cdcc6cf773053500f1720d6bd5",
+ "chksum_sha256": "34c72771c77a461fa397df3df74905bd9de242692f4ed221846e2fcafc460b61",
"format": 1
},
{
"name": "plugins/modules/vmware_host_capability_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "46833b7d624664b3b698b0e68907b634b5690a813122ab74f98d8f702b90e6f1",
+ "chksum_sha256": "6475ae92860532f64d6aa35e918b966684bae1f1490a80f3131ed7327f33a31c",
"format": 1
},
{
"name": "plugins/modules/vmware_host_config_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "284fb3b40086a5e12de0147f1fd7dccf04c2b2bb5c3dcf56304543b357dd877f",
+ "chksum_sha256": "3e53cc3b426241ec053605251d08900780a4184d6e8f2e868f866be7893f5711",
"format": 1
},
{
"name": "plugins/modules/vmware_host_config_manager.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b74db8703cb3735407fb0b6bb3450669a8900c52d777bd4428995551279335ac",
+ "chksum_sha256": "59707142d13cd525970bbd93f600dbbfd43b2b8e1d98786f6dc6a4d1a1b551e8",
"format": 1
},
{
"name": "plugins/modules/vmware_host_custom_attributes.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "984c2cc19b0736cdf2700d5ae4c946933dbd849dea3efa711ee024df7b12f616",
+ "chksum_sha256": "f6c809d372a36d1746263c726231460726825a4690bd3208106ce578444a2eb5",
"format": 1
},
{
"name": "plugins/modules/vmware_host_datastore.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "aebb1af2dfec7ab3296d9063c440f7a189984d7cc999c6f292e6190bffc02c79",
+ "chksum_sha256": "d16e63c55e7f60e67c444d2e6221979bd9686fb6b505da6f4c1c1a5bac327043",
"format": 1
},
{
"name": "plugins/modules/vmware_host_disk_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4d84b8d39fb7542ccdffe4236c4fa27a3be248b54a0b0a2e6c3003004154e50f",
+ "chksum_sha256": "7d83d26758d282c9fd27f3f712cf56d490f98a43b7ead5cca49594bc0474be89",
"format": 1
},
{
"name": "plugins/modules/vmware_host_dns.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4b0dd7763263c3fd604e0d4c520a6be28fd08cb50170bf38c8d744aa4ad1c9fa",
+ "chksum_sha256": "46d79edb87c59510365dce22c6fa88bdcc426b23036a90035a3fc11e59c4e2cb",
"format": 1
},
{
"name": "plugins/modules/vmware_host_dns_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e4e2d4ad739f1dccafe2addf49e17d7ea696894ed663fba9cccef819c4ddb100",
+ "chksum_sha256": "6ff0ef349e63ba77ffe530527281f057e605556e44680196a1fc7ae6af6bf52b",
"format": 1
},
{
"name": "plugins/modules/vmware_host_facts.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7fe594630e2804245e5d59a7ab42b628cf4fad22bc4d194bcbc4f2fa1eff87fe",
+ "chksum_sha256": "0be83e8553f01c0feee73f3256d60828c7a599bb99828afa64ed359c30ba1bb8",
"format": 1
},
{
"name": "plugins/modules/vmware_host_feature_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8d0bc2cb1ae4ee768410542b719694a397e19476a678216d0003b5e72dd2b1a0",
+ "chksum_sha256": "89312711f641b716bb198753eae5af72f6c39922527cfaebffdc99a1b362d4c7",
"format": 1
},
{
"name": "plugins/modules/vmware_host_firewall_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "48a5095b746558185769c98c7c591b2a231f4db8631ac82f025a243ae5e88a80",
+ "chksum_sha256": "90512b72545b949cafbb8af8d5271a1f234f2333cbb5ade1272255f2b8242600",
"format": 1
},
{
"name": "plugins/modules/vmware_host_firewall_manager.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "791eff4abe7728e8447b4182277435f52b886db90fda5234d136dd254037217c",
+ "chksum_sha256": "77d49747fa145b71d11a5a5d0e7055eeb1f6983835cda05547ab40364e341f28",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/vmware_host_graphics.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ce20b465771445456d0709f5891bc94c924e590969c620176c57c54b991ff26c",
"format": 1
},
{
"name": "plugins/modules/vmware_host_hyperthreading.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5595c2abe99e8b9c1bd0a6c681031dafad670b942ccca543cb92e84e47bacec7",
+ "chksum_sha256": "fdaea33235c0bea928c42763e4be84d7ae0bef3c679ab20a8365927a2e459efd",
"format": 1
},
{
"name": "plugins/modules/vmware_host_ipv6.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a57c762c4f9021ac5d603b84bfe2a621ecd8f6382ac8d281bab596d9739be942",
+ "chksum_sha256": "25711d76747c1440ac8e5aa6783c28ee365f59f85a0391d0bed8a8bcbca1ca4a",
"format": 1
},
{
"name": "plugins/modules/vmware_host_iscsi.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b60d9650fc74cf05409e6242cf728e7a54d7784f2629d2e6ab1bbd1b6687584a",
+ "chksum_sha256": "476d39c902bfa3a5bedbe22b7ac53b776d431b984395d0f35501dbfb04bf97d3",
"format": 1
},
{
"name": "plugins/modules/vmware_host_iscsi_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6f6e6b14145e9d992a148cd1583da3094e0c9387f551cf0a4cc20d3f2221306d",
+ "chksum_sha256": "6d36c4b0d8be1b5073e1d955284977c07a600f220386b063a70e8771afaa9e96",
"format": 1
},
{
"name": "plugins/modules/vmware_host_kernel_manager.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4ea7c77e999bb2ebe1001a6e8f1eebd4e1c962e815f23f0c4cc6fc5dff28c89e",
+ "chksum_sha256": "bb99555767db854efa9dcf0fed6e9f6ea70b5b02f280b5151704adec84ba1cea",
"format": 1
},
{
"name": "plugins/modules/vmware_host_lockdown.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8e3e07175c87a4b713280679985b3027807cca27530f24437c8008aefada2d2b",
+ "chksum_sha256": "0928b4198afb453f5112bbdfbf6c1bb79acfa727f1880c2041a68d547cf29df4",
"format": 1
},
{
"name": "plugins/modules/vmware_host_lockdown_exceptions.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7803d42a2e582053dd1eb67f7866ee54f49af2d7533a628ca1debf86fe622e7c",
+ "chksum_sha256": "f160e9dd9508feaf378f91d81756bec62fdd341c69af59cd7ca42d6a93abddae",
"format": 1
},
{
@@ -2398,91 +1236,91 @@
"name": "plugins/modules/vmware_host_ntp.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cea6f2155469417d728eb6a44ed276e13f816b18ea4574a1b670a193f6c67cf7",
+ "chksum_sha256": "c9adc49b64dc75bac97b87dd68e8cd9baf4fcb2e57fb6c3834a85d4ec3cd152c",
"format": 1
},
{
"name": "plugins/modules/vmware_host_ntp_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "969d88b79e9487814bf258deaace230ab9c5b488cff1667b447e0a7f421bb500",
+ "chksum_sha256": "1f3cf7d1d73050c5c196d2d674047d190034e7bdb6f0817fa3e9db7942894671",
"format": 1
},
{
"name": "plugins/modules/vmware_host_package_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c856e03d5dd75889d0c7134887e0768d078cccc823cd03960df56f1dec824b8f",
+ "chksum_sha256": "d72f851036acb86afc5ff429f717955461758853f4cc407ea382947c71ab8471",
"format": 1
},
{
"name": "plugins/modules/vmware_host_passthrough.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "76fee38d1aaa4ae8518984b79e7456be077b7bd60c3461830b13918333799340",
+ "chksum_sha256": "363157dea5e6e45394531ae9985a5861357eb909a1dea2d87744038caa406809",
"format": 1
},
{
"name": "plugins/modules/vmware_host_powermgmt_policy.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "67f41243fe798a4cb015749f0955c9a273fb5bed2eaa9fcac6ce8b43382b53d5",
+ "chksum_sha256": "a18b7c99ac20c1750438b1015c436999b9180797d669481c07aec3aeefab79a7",
"format": 1
},
{
"name": "plugins/modules/vmware_host_powerstate.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "441b025ba191a8d17d4ad6b81a0467c1a6fbe6f8118d49c23dd7a15b4d5ff311",
+ "chksum_sha256": "0a67874257138c4e36856a764ed5ad18ae13fefda2adc3ae88c1539b928717a9",
"format": 1
},
{
"name": "plugins/modules/vmware_host_scanhba.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "77f68c9b40a1955f9ddd29253e4a86005f06f9a9136ad393b092aac017d36ff3",
+ "chksum_sha256": "7b3a3aafa0fd9786cfd95cd61a2d48c275f2239695ac5a7e4724c2ad79b675ab",
"format": 1
},
{
"name": "plugins/modules/vmware_host_scsidisk_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "28328d79435ae01597b685c39b5a78e24fcb53d37e3e4b6b4ee0ff778c6b08a3",
+ "chksum_sha256": "494904d8fc5d611418e450792f79a14c6c8038e7987de8c772de96a1a7455c50",
"format": 1
},
{
"name": "plugins/modules/vmware_host_service_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ab37b9361ba1ee3a8fffdf0d62919da35a39deb0e531b231d3f0f53542e241b6",
+ "chksum_sha256": "1868169ffc2a71f17d0bff33042926096bf0fb56f892d4b5a5397b165641ec55",
"format": 1
},
{
"name": "plugins/modules/vmware_host_service_manager.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "15706c7b553f5b4d5e56d6706ba08e1347b38ed2f4bfef1c0e3d7acc8e124bb2",
+ "chksum_sha256": "fddd75b424effbe09e03cea64447b0cdfe1a1f0768a8a2d83e22b85e70c8b68c",
"format": 1
},
{
"name": "plugins/modules/vmware_host_snmp.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b0c68712bb6e2fa789295d9d33509927d34ab23b3844b02acb9d8f122c6376dc",
+ "chksum_sha256": "6b08c28416ad2407914a62709e32e277837416915d0b3426017f4efb529df524",
"format": 1
},
{
"name": "plugins/modules/vmware_host_sriov.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2a7bac23edd95df5ef8eb4770f0ca55a01fa99ad8f460cb8917cf12595cf4891",
+ "chksum_sha256": "78fb50abc8c1a3e1a9d783b31444c5c8289338dd735a7017c1378340f0c2c898",
"format": 1
},
{
"name": "plugins/modules/vmware_host_ssl_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "71eab937314bec13b4db5706238393ff50651856ed2e63f885e2742a1706efee",
+ "chksum_sha256": "76ea9ebf060ef54926b5a2a1bcf16176872cafa4428fb17077e1ce442ce30d05",
"format": 1
},
{
@@ -2496,21 +1334,21 @@
"name": "plugins/modules/vmware_host_user_manager.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3ef8c9544773fa73128dada4a070b5f4abc2d616116b2a0411fc2e94dbe4f569",
+ "chksum_sha256": "86c166dc1ba3f7a1d7600758ee8e9221f517aa36c3161218a0c965b9baf6a532",
"format": 1
},
{
"name": "plugins/modules/vmware_host_vmhba_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "aab2e0cc0f0ee0926a70fb71c1e791d1e5bed26c2fe2db01166568f89d427c03",
+ "chksum_sha256": "feb0ec2b965cb4b0e7ff7c87910dea0ce5a45105b886d9ec9fa484ebe3e588a4",
"format": 1
},
{
"name": "plugins/modules/vmware_host_vmnic_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9c9918e6c7234115008be35a472571a6de3295bd7bb34ba1649f2764b28b8c23",
+ "chksum_sha256": "456ce2fc6c828a00b50d24a961d67c9c77a4525e5ea01399dd21f2e3828028f8",
"format": 1
},
{
@@ -2524,7 +1362,7 @@
"name": "plugins/modules/vmware_local_role_manager.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "558a6ffa3750dceb929831a4a390ea0d525e5663c64eef000fc4b3f88f47f62d",
+ "chksum_sha256": "9023472c382831bae947687df8a4ae9c130964173970053ff74186709f7dd236",
"format": 1
},
{
@@ -2538,63 +1376,63 @@
"name": "plugins/modules/vmware_local_user_manager.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8ce6756c9c5e7fb9de912c24cff074903f4a8b65fcd46364da1e3ab801eefba1",
+ "chksum_sha256": "2fb04e44f1553abd39c44f9349963df6992d1b13114f84cec5f4fc8d9edaf4b2",
"format": 1
},
{
"name": "plugins/modules/vmware_maintenancemode.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "093758e716868dd001ba3c75773dea093b8cf1d608e363115dce8239b9be0d72",
+ "chksum_sha256": "6e875077d5ed73aba0ccc34d60678c93756959994994a5018269aad4916830b8",
"format": 1
},
{
"name": "plugins/modules/vmware_migrate_vmk.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d58ca907c05a362262e6251e92e72ce666e66f3bb058cd6f192d5d216014a178",
+ "chksum_sha256": "f84c674e4aeb92cd39fc41617fc869931bf96b0494b1711ddaea7c4a3d32354c",
"format": 1
},
{
"name": "plugins/modules/vmware_object_custom_attributes_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a1c03b9a6b5a42e1b1695103b9bf66def986e2862790138a9b5be385777c0e33",
+ "chksum_sha256": "71a2232c98e6077a701b72f6b685f5323817c77f0b79c44b1660b0603a28256a",
"format": 1
},
{
"name": "plugins/modules/vmware_object_rename.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ba848db12ff7a911d2a15ddc98da252b15cd6da5d908c8d84d4d7a5110c78ed8",
+ "chksum_sha256": "37f489b055f824b6359902d4bc137fbd8d15766089d5f48f7633eac0e424d314",
"format": 1
},
{
"name": "plugins/modules/vmware_object_role_permission.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6135ec18362c6d39cd3142c98512c8f6cf272560b8162477d75209f669867760",
+ "chksum_sha256": "872e2e2b8b345a6c13cd2d3ff8e33fc526ba8b0220639a9fc609fb6a3bc2ed31",
"format": 1
},
{
"name": "plugins/modules/vmware_object_role_permission_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4614888da3cdf4abbc09d36a5df3a6bcfe0a4bbc14a8f4c05568e900dcb30dbb",
+ "chksum_sha256": "6eb2446a424c03e0e77c1081842abf6d7940c8970294fe84bcfa448847b36ca2",
"format": 1
},
{
"name": "plugins/modules/vmware_portgroup.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "49c5e5367a619896fa30567fd4424f31b2760e8a5938346ada56358f98462e56",
+ "chksum_sha256": "9eaeddc06e1974f3f305080ec6a233f1b571c514f8482b120522f44fe26983b4",
"format": 1
},
{
"name": "plugins/modules/vmware_portgroup_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "efbe706d75a0a7b9768fa095e5e261344b89778240d9a18544b88e0c13bb0226",
+ "chksum_sha256": "d37f5e93a5e1b88a8249e6a3bb108e6743a419168dc4655db256d2ae62e741b8",
"format": 1
},
{
@@ -2608,7 +1446,7 @@
"name": "plugins/modules/vmware_resource_pool.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f80c2c3aba60a74833b58b812c3dbf06970148043845463895ad513922fd5bee",
+ "chksum_sha256": "4d4fccf81182b712fdbe54c95b22ae695f4d6a9c17207b79c53ddb56ac3a8016",
"format": 1
},
{
@@ -2622,7 +1460,7 @@
"name": "plugins/modules/vmware_tag.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "df77fdae1b661d563728c61d237d53f445f2e831fe77b14e012250e4724f35a4",
+ "chksum_sha256": "4518b9e396ba1f7bc6e1bfc940354894de6de17fcad23a25a4fd291c9af78908",
"format": 1
},
{
@@ -2636,77 +1474,91 @@
"name": "plugins/modules/vmware_tag_manager.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cdc64269bb3a7ac8c4b40fc0fa18e7148a8fe876b92310cacebe4e0ef0911539",
+ "chksum_sha256": "71e0a9229c66e5e788e65bb80450508024efda304620562a6ab0b250474e2225",
"format": 1
},
{
"name": "plugins/modules/vmware_target_canonical_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0e93bdd31279065c30afa48703a9d2869b3b4862afdf50bbe7d92931d647a5ec",
+ "chksum_sha256": "8148589a25004e9dd9ce61159fb7c7891456affa39576c3cec49332596008bdb",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/vmware_vasa.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "606fa23066bdda5e614fd926cfa2906301a7c6e811d98a9c2d8b3ab1123edda0",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/vmware_vasa_info.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "8a306fab8946b8655f79b831cd3a9a0fb811eb99ff060ea2a4dc5cb738ee1bb5",
"format": 1
},
{
"name": "plugins/modules/vmware_vc_infraprofile_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "571276d1700040aa7911c204b83315922b4a6b466b6c229221e781bbb6d82906",
+ "chksum_sha256": "c3a9e5a035ff87eb4843be8c2a3785d16efad669d93f07d5e47c924ead2c0ef7",
"format": 1
},
{
"name": "plugins/modules/vmware_vcenter_settings.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7aba83a3200dca62fe222c0fd221f602b7b7e4d2e3b66b9d280741760734077a",
+ "chksum_sha256": "88e4b713af95255ad55c5ad77e20adcb97569c183149f311faf55486ba018454",
"format": 1
},
{
"name": "plugins/modules/vmware_vcenter_settings_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b84834d52aee73f7ef1084822de50d3db548ded037fca1ae05eab9e090f60892",
+ "chksum_sha256": "00e24ba53faf96b10b84298e0a97b2a1915b0bb9d63e62ff0ff3ed17797bb271",
"format": 1
},
{
"name": "plugins/modules/vmware_vcenter_statistics.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "76e1487a5ed949bc5eb9290fefd3edcbd9849a7a0de99d9f2bcc22395022aefc",
+ "chksum_sha256": "2c4ed400a2591c0b673433cea1646e8072351d0ac50e1f2efeb9def063dae687",
"format": 1
},
{
"name": "plugins/modules/vmware_vm_config_option.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a48363b992fd6bddc6da3cb613831e3eb2977603765c66e9add3f1a59c5500d4",
+ "chksum_sha256": "591504d7977d1ced5a5f538783b01a81b56a5bd8de82e5990949663058a1359d",
"format": 1
},
{
"name": "plugins/modules/vmware_vm_host_drs_rule.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "954f30b89409593260157486dddcb74bd73a7d0a3f34822e56e03d03612dbba4",
+ "chksum_sha256": "9b15d6f0149083c0e77d4a5be47e6d651d7979da9703248f6af1e70854cbd9f7",
"format": 1
},
{
"name": "plugins/modules/vmware_vm_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cde43eebdf5c2fc6e5ba88c112fe37333a95fddfba41c0c718b5fb55653b15d1",
+ "chksum_sha256": "058f3b0b04e552bf4282a0e420c64312f279dcb49427bcb2fafc3f1e4422c0d7",
"format": 1
},
{
"name": "plugins/modules/vmware_vm_shell.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "23f8047eba340d0dddbd9af7fcdf7931ac520c358d1ff1be284fe6807014ca77",
+ "chksum_sha256": "9416f7b6cd6fb70e09b9b1a5ee5aac81250544037017bca639a916da47a5690d",
"format": 1
},
{
"name": "plugins/modules/vmware_vm_storage_policy.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "997c1573c452b3d4e1a5062b4d06f401692e2b94334e9dfa920973c8a262bf1b",
+ "chksum_sha256": "ead36f8fa628340339bc0ce89f1e56dc8983447d3e257373a01b2f298b8af7b3",
"format": 1
},
{
@@ -2720,7 +1572,7 @@
"name": "plugins/modules/vmware_vm_vm_drs_rule.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f5843fae6e89075fc643c92ca0688868779e5463ff3a3b538f5515b406c2f79b",
+ "chksum_sha256": "c693e6ea2f6381c490a42a31655a557f63a4a6c33f0623eef8a37af933b90eb2",
"format": 1
},
{
@@ -2734,21 +1586,21 @@
"name": "plugins/modules/vmware_vmkernel.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fb5912ee364bca890320a248fcf388abbdc781478ba89344082115462f927cd1",
+ "chksum_sha256": "07db3a86d1c3110d5459e730ab3c33586a254beda63f88c50bec310559397e23",
"format": 1
},
{
"name": "plugins/modules/vmware_vmkernel_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d109c64926e2c71994b74fb8889f7b4ce94d4885fa38b26fbe2f493a6e01c84b",
+ "chksum_sha256": "d2a2beb2b0b857784b64b63407a43be16610decdd1fc33bb82531b39e45ea5f5",
"format": 1
},
{
"name": "plugins/modules/vmware_vmotion.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6bd3515e8a33fd7fb2aa8949b9cfc0f2bacf7b85c16741f07632b371e449cdb5",
+ "chksum_sha256": "3b4aa3303ecfdf65c8be049f93c538c0f5088133bf8574831467dde747838372",
"format": 1
},
{
@@ -2769,7 +1621,7 @@
"name": "plugins/modules/vmware_vsan_health_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "35678c0ff49803247a99f931c638d464dfd1de389c308e2f5891215e37b8ff75",
+ "chksum_sha256": "f1f1cd15f00fc30518dff21437bc09178e8e7d78746a08686f4879992f19d2a5",
"format": 1
},
{
@@ -2783,42 +1635,42 @@
"name": "plugins/modules/vmware_vspan_session.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b721e7fc40ef76583e7e630dc45c561b26eac187aa2b72f09753e6f6bf467710",
+ "chksum_sha256": "5e63fc80e42289de36eb4f5f526777d9444bf09d41086a65afe1201572b60800",
"format": 1
},
{
"name": "plugins/modules/vmware_vswitch.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0595071e755fa9e8019c41b464cdeb5a33a579f7367c6e08c035145f876d2b57",
+ "chksum_sha256": "d4e7b5912e134d8579a5dcefbc6e8e88971d78534133659198f10e1ba4c463d1",
"format": 1
},
{
"name": "plugins/modules/vmware_vswitch_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "daaa9f54459009ced90fadf913870646dcac4676e15f10527a9c65397463cd44",
+ "chksum_sha256": "864ac9d9211a4da61bcddfe36d186490e738c838aa95e41c83e24da1b1d482e5",
"format": 1
},
{
"name": "plugins/modules/vsan_health_silent_checks.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "91716d0fcf3ff581b66b0226fd780849248eb04f7858033281cfb7ea0e18e09a",
+ "chksum_sha256": "9e764aa54aac248d501bdfc39536583f2bc3699b24196543bf893b1f4cceee04",
"format": 1
},
{
"name": "plugins/modules/vsphere_copy.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ca79bd20506ac791d93974b93df402b1c32eea7fb5ebbcded88f815929089bbf",
+ "chksum_sha256": "5cd7e150f6b948b2011f67322a66dd0eccaa483d19b9a76b3e2e1edbd68392df",
"format": 1
},
{
"name": "plugins/modules/vsphere_file.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ee1d16f89425be8428ff041d0c49b629927d144b545a11a9847dd928ffa893bd",
+ "chksum_sha256": "f35e9a6942b9c7d57d89934312c69887a682adf1ce472cf1dd71f99f18422b3d",
"format": 1
},
{
@@ -3203,7 +2055,7 @@
"name": "tests/integration/targets/prepare_vmware_tests/tasks/setup_virtualmachines.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "23681b5f0dd4c665b4291a80ed1d3df7e2eea913750361c9d63a069c3f79f598",
+ "chksum_sha256": "c4eb36560c280c492a245065cf6703e5cb590e47ff8214175f86893b21efb90b",
"format": 1
},
{
@@ -3452,6 +2304,34 @@
"format": 1
},
{
+ "name": "tests/integration/targets/vcenter_root_password_expiration",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/vcenter_root_password_expiration/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/vcenter_root_password_expiration/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "709165db6299cdef33425f1c1a66fa4fa8b01b6d9b65503505430a1c342e7321",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/vcenter_root_password_expiration/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "01fa35194bf770a07637986fce41a7c40c11393e55b7ac1799a241d22e5cc211",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/vmware_about_info",
"ftype": "dir",
"chksum_type": null,
@@ -3469,7 +2349,7 @@
"name": "tests/integration/targets/vmware_about_info/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0fc2588f52fd66159321107de1431f14c48263ed5ecabd567b00bc028ad2d417",
+ "chksum_sha256": "c6f7177adb31abf985586e4c372e6a2d19d52bcbcdd810c7eb8d5071bc6d37fa",
"format": 1
},
{
@@ -3497,7 +2377,7 @@
"name": "tests/integration/targets/vmware_category/tasks/associable_obj_test.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5f20379862a9b505347ae124f97d305f0cd862792c726aa6f18a3e01a507af98",
+ "chksum_sha256": "832da27f0b265699f5a297a3f73b1dd68d0c4f7accf6f2004b604e082e3772b4",
"format": 1
},
{
@@ -3511,7 +2391,7 @@
"name": "tests/integration/targets/vmware_category/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "087c0d15ba420631f30e0be24e3da100200a5a49ef6ca80ca52e39fd837018ef",
+ "chksum_sha256": "19ba06a9157a48b749dce1d270e2b44355836ee06f59850e919fbd961f4e9b4d",
"format": 1
},
{
@@ -4211,7 +3091,7 @@
"name": "tests/integration/targets/vmware_dvs_portgroup/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f9a29edecfbaba52241e8dd8eb8810c09521e3dcfc95638096f2dca0050d5bf3",
+ "chksum_sha256": "aa654a9325a4ed0af466f17af77dbf9623cf65298d16472f1a01436ca3fa1af8",
"format": 1
},
{
@@ -4516,6 +3396,34 @@
"format": 1
},
{
+ "name": "tests/integration/targets/vmware_first_class_disk_info",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/vmware_first_class_disk_info/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/vmware_first_class_disk_info/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "be533a5f4d72feeadb3625389103760986a940bbe76f12d9eb13d14a9afa3967",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/vmware_first_class_disk_info/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9a91847a8381b27f60fc118141a1917a1d27e73ef8fa40ffa6bd484aaebccfac",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/vmware_folder_info",
"ftype": "dir",
"chksum_type": null,
@@ -4533,7 +3441,7 @@
"name": "tests/integration/targets/vmware_folder_info/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f5225df6471f6ea9a37e454ff682ba83691b302f04693685c20c6f39bdc59d77",
+ "chksum_sha256": "4423812b42229d1cf8dca05a78f59af78c21f3de5543b64dcb9bb2c6289e47bc",
"format": 1
},
{
@@ -4589,7 +3497,7 @@
"name": "tests/integration/targets/vmware_guest/tasks/cdrom_d1_c1_f0.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c63efd697a90c3353d1e8cb0012c3044cff046360c0aa31fc1ef16fa1a42a493",
+ "chksum_sha256": "304da52c3067b6c32a683e9be7996a883d0d40f958ccf27b27a53f0aa695f344",
"format": 1
},
{
@@ -4603,14 +3511,14 @@
"name": "tests/integration/targets/vmware_guest/tasks/check_mode.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8b7a619287cd4a64adc534750135c6ff9b636dd78233558be767035de34b0efb",
+ "chksum_sha256": "3e881a0c8827936e42cf8677082d92079823aa5285feceada30aed14e12b824d",
"format": 1
},
{
"name": "tests/integration/targets/vmware_guest/tasks/clone_customize_guest_test.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5877241e70156865f2a282f88033a14fcd1ae8f43d69b0cef8fb1e8a2bfb4b3e",
+ "chksum_sha256": "1f5dca0b63d32b5ef075af860e4172ad7cd3c083eb62f71f890bd4bcf68e37ed",
"format": 1
},
{
@@ -4631,7 +3539,7 @@
"name": "tests/integration/targets/vmware_guest/tasks/clone_with_convert.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f0ad92a05c48278171303f8c453153aa5e24cbcc1d7341b99735bda9f93929ba",
+ "chksum_sha256": "d903599aba004068472423a912a14616df23aa80895ef2074d4d4c44e675849c",
"format": 1
},
{
@@ -4792,7 +3700,7 @@
"name": "tests/integration/targets/vmware_guest/tasks/windows_vbs_d1_c1_f0.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "37a163193240c1467fdbce7a4c48920fa2f55581f6716cf48492888c3bcc2916",
+ "chksum_sha256": "4e34cb13f90089ddcc52028a18163563169f4496d61764df19a5283342f77cd1",
"format": 1
},
{
@@ -4876,7 +3784,7 @@
"name": "tests/integration/targets/vmware_guest_controller/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6ef59d3a2dab7e7e36485f8f7371b97ebd0be2a8218d0b20071df7121d850e57",
+ "chksum_sha256": "3e7d96a51d7811887961db48a389463515aa30ed52eaf56dd2010a7d5cd4af02",
"format": 1
},
{
@@ -5016,7 +3924,7 @@
"name": "tests/integration/targets/vmware_guest_disk/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bf466158455f443ba7aa06185fc85e6c738ae62f809ca8aad05a8644ff7d6ec9",
+ "chksum_sha256": "eebb0925259b29ab85ec88c0ac6f6f8907cc186f3fbfd2d96ca8aec9e108b0f3",
"format": 1
},
{
@@ -5044,7 +3952,7 @@
"name": "tests/integration/targets/vmware_guest_disk_info/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fb9d1ee962223ac0fe8ab18ff4936c7b709c008f364661c630cc22bc9f7db0fc",
+ "chksum_sha256": "74ece641b61bfd08551ea4ad48d586d6b305e1fca153077dd10b3c994e44ea82",
"format": 1
},
{
@@ -5184,7 +4092,7 @@
"name": "tests/integration/targets/vmware_guest_network/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "313e4dd2d3b2b478acdcd8a60c6904e777f816084907a7e2814ae1c27507a731",
+ "chksum_sha256": "0383abd1afaadc3cff2a4b1c427d89b85133392dd84f18045730165d4a23b29d",
"format": 1
},
{
@@ -5212,7 +4120,7 @@
"name": "tests/integration/targets/vmware_guest_powerstate/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7dcb3d430b897050d478abc3c9a0ca621625da9184b78935c5bd823e42350d37",
+ "chksum_sha256": "855a4a795b3e77da16ce4a5a1297a07ce8f83f060dca1f972d226bc375923820",
"format": 1
},
{
@@ -5352,7 +4260,7 @@
"name": "tests/integration/targets/vmware_guest_snapshot/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "add515bb74c30b39e5af3d5caf2b3e4f5c3915cf3b68c705c50dd8012786e9f6",
+ "chksum_sha256": "13a9a37d3d31c9cb875a31f80921ef336a5d446c4d622c93495ea543764b849e",
"format": 1
},
{
@@ -5464,7 +4372,7 @@
"name": "tests/integration/targets/vmware_guest_tools_wait/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e87c1b411283251f39d079084d139af91083021f30adfe544a08ddd5a2d285e4",
+ "chksum_sha256": "61b522974f048eb100c3897ba7e84a12b442bab6e6569bb216e2fd7a3bd0895a",
"format": 1
},
{
@@ -5520,7 +4428,7 @@
"name": "tests/integration/targets/vmware_host_acceptance/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "394c5a063bd7247c166d707039f237f58de6ec81be47078bc0bd97028f0b33f2",
+ "chksum_sha256": "dd7d1f5d0af9c10ec1958b5174e19c97e397419e68c5b1e02d74b8a2c238954b",
"format": 1
},
{
@@ -5531,6 +4439,34 @@
"format": 1
},
{
+ "name": "tests/integration/targets/vmware_host_acceptance_info",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/vmware_host_acceptance_info/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/vmware_host_acceptance_info/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c1c1ef98e1bc1d92a2a385a91ed0d62bda354cf979d3fc89af1be095685c9bb0",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/vmware_host_acceptance_info/aliases",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9a91847a8381b27f60fc118141a1917a1d27e73ef8fa40ffa6bd484aaebccfac",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/vmware_host_active_directory",
"ftype": "dir",
"chksum_type": null,
@@ -5583,7 +4519,7 @@
"name": "tests/integration/targets/vmware_host_auto_start/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b806861daa1e7d9ccde6e0a5ebf914d8ea0789e8e5f9cf8b384fe879f46da2be",
+ "chksum_sha256": "6d6b3adba495dada5b251ce09f421fb44f12b54b3b1e1d8f8f7a989311613b6d",
"format": 1
},
{
@@ -6549,14 +5485,14 @@
"name": "tests/integration/targets/vmware_host_snmp/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c473006fc5f4901d24c8fb2c0ae33f227d19c92b4c938488bd8e1cb6fa3b1a9a",
+ "chksum_sha256": "719d7143be8d43a3e87e4b2667afba7ec74b1f266ccad6dc28e0e704343e8d6e",
"format": 1
},
{
"name": "tests/integration/targets/vmware_host_snmp/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9a91847a8381b27f60fc118141a1917a1d27e73ef8fa40ffa6bd484aaebccfac",
+ "chksum_sha256": "40e1108d91c93d2856de6551e111522d563cb5937532d5c831fdaafde6f725be",
"format": 1
},
{
@@ -7004,7 +5940,7 @@
"name": "tests/integration/targets/vmware_object_rename/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0561b714bf475adcdeca12260194532dab24ba38a2b4a6c319139e8aa3998d96",
+ "chksum_sha256": "f13f29a3201f29791a155781d0875a315cba83cf4d82ee4998f5badb940faf0f",
"format": 1
},
{
@@ -7249,7 +6185,7 @@
"name": "tests/integration/targets/vmware_tag/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "66a5d247379edc326497da108f1a845bab96cc8d53dbdd80f3874e64e90bef10",
+ "chksum_sha256": "94086aa2a022a70bfee986754f3cd7ef8fff2366aca4557ff6edb4dcac4f4d16",
"format": 1
},
{
@@ -7298,7 +6234,7 @@
"name": "tests/integration/targets/vmware_tag_info/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d870372ba09d86d540e6defaa2a99ea2c529effb5b354eb6a88bd02445582ce7",
+ "chksum_sha256": "4c94bec34c84280ac53f55f1f63cb5646d9ddd9974f34185da752140cc02d55a",
"format": 1
},
{
@@ -7340,7 +6276,7 @@
"name": "tests/integration/targets/vmware_tag_manager/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d8c6b3cbb743da247df3bfbe4bea1b4499cadcae88ff688dc54c50d6be94b162",
+ "chksum_sha256": "a93a67e5f36b9d55bb3f84d69a0bd44e437f1655af9587a8b305a21c0ca342a3",
"format": 1
},
{
@@ -7606,7 +6542,7 @@
"name": "tests/integration/targets/vmware_vm_inventory/prepare_environment.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "45bf764108d8db88090ca4f8daa4150b857083306ce48e30fd00a694baca8682",
+ "chksum_sha256": "e8cf6296fc1b8656fb482c9625d636685678265e26297df745a9f13d19bc08a3",
"format": 1
},
{
@@ -7960,24 +6896,24 @@
"format": 1
},
{
- "name": "tests/sanity/ignore-2.13.txt",
+ "name": "tests/sanity/ignore-2.15.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "27c2ff3e501253b91d57e1f700d4fc5591d80e1bb64e60df49f0d68b2e0c3efc",
+ "chksum_sha256": "df93edbdf6fa0c5c35589f18588aca9ad8ee1d7dfa3804a5d115c453cb49aac2",
"format": 1
},
{
- "name": "tests/sanity/ignore-2.14.txt",
+ "name": "tests/sanity/ignore-2.16.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "27c2ff3e501253b91d57e1f700d4fc5591d80e1bb64e60df49f0d68b2e0c3efc",
+ "chksum_sha256": "5c62bddf4ca5eac160fda8aa8cc0ce0998ab1a3dccb91c37270a837c2d1e20cd",
"format": 1
},
{
- "name": "tests/sanity/ignore-2.15.txt",
+ "name": "tests/sanity/ignore-2.17.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "27c2ff3e501253b91d57e1f700d4fc5591d80e1bb64e60df49f0d68b2e0c3efc",
+ "chksum_sha256": "5c62bddf4ca5eac160fda8aa8cc0ce0998ab1a3dccb91c37270a837c2d1e20cd",
"format": 1
},
{
@@ -7988,34 +6924,6 @@
"format": 1
},
{
- "name": "tests/unit/compat",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/unit/compat/__init__.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
- "format": 1
- },
- {
- "name": "tests/unit/compat/mock.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "d2c1cbdf2ab686b52b5ff67ad7bca77868639f2f934183a9f3abac8ba8448477",
- "format": 1
- },
- {
- "name": "tests/unit/compat/unittest.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "5401a046e5ce71fa19b6d905abd0f9bdf816c0c635f7bdda6730b3ef06e67096",
- "format": 1
- },
- {
"name": "tests/unit/mock",
"ftype": "dir",
"chksum_type": null,
@@ -8040,14 +6948,14 @@
"name": "tests/unit/mock/path.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "67eadb9424472bacfa8e0a35ec5491c9ec3639351cc53e7f862b52327c69e930",
+ "chksum_sha256": "f4fdad691bcdd434eba0c1089fceab713f2e8c623ac323868a4abf1f1baed7be",
"format": 1
},
{
"name": "tests/unit/mock/procenv.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "75ce791d3bcdd63a564e1f90a6dcdc79eced54f9a82064500cfc47d8a1ca97be",
+ "chksum_sha256": "bdcd95649b08bb6fd6c87eed3c171234096a043515fb4e2d528f06686c99ef7a",
"format": 1
},
{
@@ -8089,7 +6997,7 @@
"name": "tests/unit/module_utils/test_vmware.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7a4fcc79601f6ba7915e4b58da4557011d34c7b6c8404701ff9e126d3bac475a",
+ "chksum_sha256": "e58af3235d4e0786ef747f879f6cd4e856ba9b736d312a8f6b57adcbe401abc1",
"format": 1
},
{
@@ -8145,7 +7053,7 @@
"name": "tests/unit/modules/cloud/vmware/test_vmware_host_sriov.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c743e8beb0f3a2c839e88b3e543e9a841a2e6228490b08ea63e8be2598b6f760",
+ "chksum_sha256": "55cfbb3dc0ec00327817be5916a43a5c302719aa0397cd5589368c3cb13a2718",
"format": 1
},
{
@@ -8173,7 +7081,7 @@
"name": "tests/unit/modules/utils.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3058cbe614af5af8cc25b28b208a3169dced0dc5881fde9a7e00cbf3fb202458",
+ "chksum_sha256": "1ad02fa8858ac3fc78e7c107d983f321ba64bea05d6deefe5f409cc5e77c3c68",
"format": 1
},
{
@@ -8219,17 +7127,10 @@
"format": 1
},
{
- "name": "tools/create_documentation_tasks.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "7f2945d104528e48b85e07ab858c4c45c9991543563c8a840d7727e14c429d54",
- "format": 1
- },
- {
"name": "tools/prepare_release.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "199a659f967c9b726fffe749f6157a69a2337c8137c6459fd03609291ae26e7f",
+ "chksum_sha256": "721ec06097800ea7f03707e12e1f02b3095c6b14789afaf9932fe02dfa3eb198",
"format": 1
},
{
@@ -8240,17 +7141,10 @@
"format": 1
},
{
- "name": "tools/update_documentation.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "a19087208b6012bf1e2d87132673c0c82b7733a37be9ff8a2054d6fe0618220c",
- "format": 1
- },
- {
"name": ".gitignore",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "691857f536d75b4adda44c4b8bb94cc486984678f5139c7e27e5c515d41625d5",
+ "chksum_sha256": "6fd014c0b43025af762c87405b2e864626c66f7780545b2a98d39d63d5f91827",
"format": 1
},
{
@@ -8264,7 +7158,7 @@
"name": "CHANGELOG.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3b25df8adb1df7dd77fcf4381809a88f7ecd791f20f48766d4b69caf348a2158",
+ "chksum_sha256": "a26eb552f9062d66fdecc635a886f159a66790045e05dcfc7da4574f974140b3",
"format": 1
},
{
@@ -8285,7 +7179,7 @@
"name": "README.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "93c53e4a9542a3d352fddfcea7c75c0bfb606d15897d147b78f5a25f43237cf5",
+ "chksum_sha256": "cb1cf943b2d05b5c343c6921fb04b166f979ee4ac3fc33ba03acd344c4e3aab1",
"format": 1
},
{
@@ -8306,14 +7200,14 @@
"name": "testing.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d643b36c2825d43dc5f8d90cfd0d29599a1c270195927a67f4007fb40136a7b4",
+ "chksum_sha256": "f10a4ed48eb3b3003396d73467d452b5f7d90d6b6704750d71c2e9b91476690e",
"format": 1
},
{
"name": "tox.ini",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4f1fa0be662cea3704ab255975ef23916757a2caebc80afd1cc49b78f3701a57",
+ "chksum_sha256": "44f971308257563834fe8046f5060f29333bde51299a66942763e76a00b24761",
"format": 1
}
],
diff --git a/ansible_collections/community/vmware/MANIFEST.json b/ansible_collections/community/vmware/MANIFEST.json
index 0b0bb86f0..acc7f148d 100644
--- a/ansible_collections/community/vmware/MANIFEST.json
+++ b/ansible_collections/community/vmware/MANIFEST.json
@@ -2,7 +2,7 @@
"collection_info": {
"namespace": "community",
"name": "vmware",
- "version": "3.7.0",
+ "version": "4.2.0",
"authors": [
"Ansible (https://github.com/ansible)"
],
@@ -28,7 +28,7 @@
"name": "FILES.json",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "81f209ac2432cfdc118055239d4505b9d0268671ff8b5d02ed1ad1718709bda3",
+ "chksum_sha256": "1ef7fbdfa909824b3ed7734c6a79135d82971bdff522b1ddd9c3cb4844c21d9a",
"format": 1
},
"format": 1
diff --git a/ansible_collections/community/vmware/README.md b/ansible_collections/community/vmware/README.md
index 1bc4235a6..13511c4d7 100644
--- a/ansible_collections/community/vmware/README.md
+++ b/ansible_collections/community/vmware/README.md
@@ -6,23 +6,19 @@ The collection includes the VMware modules and plugins supported by Ansible VMwa
## Releases and maintenance
-| Release | Status | Expected end of life |
-| ------: | --------------------------: | -------------------: |
-| 3 | Maintained | Nov 2024 |
-| 2 | Maintained (bug fixes only) | Nov 2023 |
-| 1 | Unmaintained | Nov 2022 |
+| Release | Status | End of life |
+| ------: | --------------------------: | ----------: |
+| 4 | Maintained | Nov 2025 |
+| 3 | Maintained (bug fixes only) | Nov 2024 |
+| 2 | Unmaintained | Nov 2023 |
-<!--start requires_ansible-->
## Ansible version compatibility
-This collection has been tested against following Ansible versions: **>=2.13.0**.
+This collection has been tested against following Ansible versions: **>=2.15.0**.
-For collections that support Ansible 2.9, please ensure you update your `network_os` to use the
-fully qualified collection name (for example, `cisco.ios.ios`).
Plugins and modules within a collection may be tested with only specific Ansible versions.
A collection may contain metadata that identifies these versions.
PEP440 is the schema used to describe the versions of Ansible.
-<!--end requires_ansible-->
## Installation and Usage
@@ -41,7 +37,7 @@ collections:
### Required Python libraries
-VMware community collection depends on Python 3.8+ and on following third party libraries:
+VMware community collection depends on Python 3.9+ and on following third party libraries:
* [`Pyvmomi`](https://github.com/vmware/pyvmomi)
* [`vSphere Automation SDK for Python`](https://github.com/vmware/vsphere-automation-sdk-python/)
@@ -57,199 +53,6 @@ If you are working on developing and/or testing VMware community collection, you
pip install -r ~/.ansible/collections/ansible_collections/community/vmware/test-requirements.txt
-
-## Included content
-
-<!--start collection content-->
-### Connection plugins
-Name | Description
---- | ---
-[community.vmware.vmware_tools](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_tools_connection.rst)|Execute tasks inside a VM via VMware Tools
-
-### Httpapi plugins
-Name | Description
---- | ---
-[community.vmware.vmware](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_httpapi.rst)|HttpApi Plugin for VMware REST API
-
-### Inventory plugins
-Name | Description
---- | ---
-[community.vmware.vmware_host_inventory](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_inventory_inventory.rst)|VMware ESXi hostsystem inventory source
-[community.vmware.vmware_vm_inventory](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_vm_inventory_inventory.rst)|VMware Guest inventory source
-
-### Modules
-Name | Description
---- | ---
-[community.vmware.vcenter_domain_user_group_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vcenter_domain_user_group_info_module.rst)|Gather user or group information of a domain
-[community.vmware.vcenter_extension](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vcenter_extension_module.rst)|Register/deregister vCenter Extensions
-[community.vmware.vcenter_extension_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vcenter_extension_info_module.rst)|Gather info vCenter extensions
-[community.vmware.vcenter_folder](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vcenter_folder_module.rst)|Manage folders on given datacenter
-[community.vmware.vcenter_license](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vcenter_license_module.rst)|Manage VMware vCenter license keys
-[community.vmware.vcenter_standard_key_provider](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vcenter_standard_key_provider_module.rst)|Add, reconfigure or remove Standard Key Provider on vCenter server
-[community.vmware.vmware_about_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_about_info_module.rst)|Provides information about VMware server to which user is connecting to
-[community.vmware.vmware_category](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_category_module.rst)|Manage VMware categories
-[community.vmware.vmware_category_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_category_info_module.rst)|Gather info about VMware tag categories
-[community.vmware.vmware_cfg_backup](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_cfg_backup_module.rst)|Backup / Restore / Reset ESXi host configuration
-[community.vmware.vmware_cluster](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_cluster_module.rst)|Manage VMware vSphere clusters
-[community.vmware.vmware_cluster_dpm](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_cluster_dpm_module.rst)|Manage Distributed Power Management (DPM) on VMware vSphere clusters
-[community.vmware.vmware_cluster_drs](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_cluster_drs_module.rst)|Manage Distributed Resource Scheduler (DRS) on VMware vSphere clusters
-[community.vmware.vmware_cluster_drs_recommendations](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_cluster_drs_recommendations_module.rst)|Apply DRS Recommendations
-[community.vmware.vmware_cluster_ha](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_cluster_ha_module.rst)|Manage High Availability (HA) on VMware vSphere clusters
-[community.vmware.vmware_cluster_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_cluster_info_module.rst)|Gather info about clusters available in given vCenter
-[community.vmware.vmware_cluster_vcls](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_cluster_vcls_module.rst)|Override the default vCLS (vSphere Cluster Services) VM disk placement for this cluster.
-[community.vmware.vmware_cluster_vsan](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_cluster_vsan_module.rst)|Manages virtual storage area network (vSAN) configuration on VMware vSphere clusters
-[community.vmware.vmware_content_deploy_ovf_template](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_content_deploy_ovf_template_module.rst)|Deploy Virtual Machine from ovf template stored in content library.
-[community.vmware.vmware_content_deploy_template](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_content_deploy_template_module.rst)|Deploy Virtual Machine from template stored in content library.
-[community.vmware.vmware_content_library_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_content_library_info_module.rst)|Gather information about VMWare Content Library
-[community.vmware.vmware_content_library_manager](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_content_library_manager_module.rst)|Create, update and delete VMware content library
-[community.vmware.vmware_custom_attribute](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_custom_attribute_module.rst)|Manage custom attributes definitions
-[community.vmware.vmware_custom_attribute_manager](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_custom_attribute_manager_module.rst)|Manage custom attributes from VMware for the given vSphere object
-[community.vmware.vmware_datacenter](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_datacenter_module.rst)|Manage VMware vSphere Datacenters
-[community.vmware.vmware_datacenter_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_datacenter_info_module.rst)|Gather information about VMware vSphere Datacenters
-[community.vmware.vmware_datastore](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_datastore_module.rst)|Configure Datastores
-[community.vmware.vmware_datastore_cluster](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_datastore_cluster_module.rst)|Manage VMware vSphere datastore clusters
-[community.vmware.vmware_datastore_cluster_manager](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_datastore_cluster_manager_module.rst)|Manage VMware vSphere datastore cluster's members
-[community.vmware.vmware_datastore_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_datastore_info_module.rst)|Gather info about datastores available in given vCenter
-[community.vmware.vmware_datastore_maintenancemode](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_datastore_maintenancemode_module.rst)|Place a datastore into maintenance mode
-[community.vmware.vmware_deploy_ovf](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_deploy_ovf_module.rst)|Deploys a VMware virtual machine from an OVF or OVA file
-[community.vmware.vmware_drs_group](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_drs_group_module.rst)|Creates vm/host group in a given cluster.
-[community.vmware.vmware_drs_group_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_drs_group_info_module.rst)|Gathers info about DRS VM/Host groups on the given cluster
-[community.vmware.vmware_drs_group_manager](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_drs_group_manager_module.rst)|Manage VMs and Hosts in DRS group.
-[community.vmware.vmware_drs_rule_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_drs_rule_info_module.rst)|Gathers info about DRS rule on the given cluster
-[community.vmware.vmware_dvs_host](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_dvs_host_module.rst)|Add or remove a host from distributed virtual switch
-[community.vmware.vmware_dvs_portgroup](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_dvs_portgroup_module.rst)|Create or remove a Distributed vSwitch portgroup.
-[community.vmware.vmware_dvs_portgroup_find](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_dvs_portgroup_find_module.rst)|Find portgroup(s) in a VMware environment
-[community.vmware.vmware_dvs_portgroup_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_dvs_portgroup_info_module.rst)|Gathers info DVS portgroup configurations
-[community.vmware.vmware_dvswitch](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_dvswitch_module.rst)|Create or remove a Distributed Switch
-[community.vmware.vmware_dvswitch_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_dvswitch_info_module.rst)|Gathers info dvswitch configurations
-[community.vmware.vmware_dvswitch_lacp](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_dvswitch_lacp_module.rst)|Manage LACP configuration on a Distributed Switch
-[community.vmware.vmware_dvswitch_nioc](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_dvswitch_nioc_module.rst)|Manage distributed switch Network IO Control
-[community.vmware.vmware_dvswitch_pvlans](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_dvswitch_pvlans_module.rst)|Manage Private VLAN configuration of a Distributed Switch
-[community.vmware.vmware_dvswitch_uplink_pg](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_dvswitch_uplink_pg_module.rst)|Manage uplink portproup configuration of a Distributed Switch
-[community.vmware.vmware_evc_mode](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_evc_mode_module.rst)|Enable/Disable EVC mode on vCenter
-[community.vmware.vmware_export_ovf](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_export_ovf_module.rst)|Exports a VMware virtual machine to an OVF file, device files and a manifest file
-[community.vmware.vmware_first_class_disk](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_first_class_disk_module.rst)|Manage VMware vSphere First Class Disks
-[community.vmware.vmware_folder_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_folder_info_module.rst)|Provides information about folders in a datacenter
-[community.vmware.vmware_guest](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_guest_module.rst)|Manages virtual machines in vCenter
-[community.vmware.vmware_guest_boot_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_guest_boot_info_module.rst)|Gather info about boot options for the given virtual machine
-[community.vmware.vmware_guest_boot_manager](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_guest_boot_manager_module.rst)|Manage boot options for the given virtual machine
-[community.vmware.vmware_guest_controller](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_guest_controller_module.rst)|Manage disk or USB controllers related to virtual machine in given vCenter infrastructure
-[community.vmware.vmware_guest_cross_vc_clone](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_guest_cross_vc_clone_module.rst)|Cross-vCenter VM/template clone
-[community.vmware.vmware_guest_custom_attribute_defs](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_guest_custom_attribute_defs_module.rst)|Manage custom attributes definitions for virtual machine from VMware
-[community.vmware.vmware_guest_custom_attributes](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_guest_custom_attributes_module.rst)|Manage custom attributes from VMware for the given virtual machine
-[community.vmware.vmware_guest_customization_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_guest_customization_info_module.rst)|Gather info about VM customization specifications
-[community.vmware.vmware_guest_disk](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_guest_disk_module.rst)|Manage disks related to virtual machine in given vCenter infrastructure
-[community.vmware.vmware_guest_disk_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_guest_disk_info_module.rst)|Gather info about disks of given virtual machine
-[community.vmware.vmware_guest_file_operation](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_guest_file_operation_module.rst)|Files operation in a VMware guest operating system without network
-[community.vmware.vmware_guest_find](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_guest_find_module.rst)|Find the folder path(s) for a virtual machine by name or UUID
-[community.vmware.vmware_guest_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_guest_info_module.rst)|Gather info about a single VM
-[community.vmware.vmware_guest_instant_clone](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_guest_instant_clone_module.rst)|Instant Clone VM
-[community.vmware.vmware_guest_move](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_guest_move_module.rst)|Moves virtual machines in vCenter
-[community.vmware.vmware_guest_network](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_guest_network_module.rst)|Manage network adapters of specified virtual machine in given vCenter infrastructure
-[community.vmware.vmware_guest_powerstate](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_guest_powerstate_module.rst)|Manages power states of virtual machines in vCenter
-[community.vmware.vmware_guest_register_operation](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_guest_register_operation_module.rst)|VM inventory registration operation
-[community.vmware.vmware_guest_screenshot](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_guest_screenshot_module.rst)|Create a screenshot of the Virtual Machine console.
-[community.vmware.vmware_guest_sendkey](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_guest_sendkey_module.rst)|Send USB HID codes to the Virtual Machine's keyboard.
-[community.vmware.vmware_guest_serial_port](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_guest_serial_port_module.rst)|Manage serial ports on an existing VM
-[community.vmware.vmware_guest_snapshot](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_guest_snapshot_module.rst)|Manages virtual machines snapshots in vCenter
-[community.vmware.vmware_guest_snapshot_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_guest_snapshot_info_module.rst)|Gather info about virtual machine's snapshots in vCenter
-[community.vmware.vmware_guest_storage_policy](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_guest_storage_policy_module.rst)|Set VM Home and disk(s) storage policy profiles.
-[community.vmware.vmware_guest_tools_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_guest_tools_info_module.rst)|Gather info about VMware tools installed in VM
-[community.vmware.vmware_guest_tools_upgrade](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_guest_tools_upgrade_module.rst)|Module to upgrade VMTools
-[community.vmware.vmware_guest_tools_wait](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_guest_tools_wait_module.rst)|Wait for VMware tools to become available
-[community.vmware.vmware_guest_tpm](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_guest_tpm_module.rst)|Add or remove vTPM device for specified VM.
-[community.vmware.vmware_guest_vgpu](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_guest_vgpu_module.rst)|Modify vGPU video card profile of the specified virtual machine in the given vCenter infrastructure
-[community.vmware.vmware_guest_vgpu_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_guest_vgpu_info_module.rst)|Gather information about vGPU profiles of the specified virtual machine in the given vCenter infrastructure
-[community.vmware.vmware_guest_video](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_guest_video_module.rst)|Modify video card configurations of specified virtual machine in given vCenter infrastructure
-[community.vmware.vmware_host](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_module.rst)|Add, remove, or move an ESXi host to, from, or within vCenter
-[community.vmware.vmware_host_acceptance](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_acceptance_module.rst)|Manage the host acceptance level of an ESXi host
-[community.vmware.vmware_host_active_directory](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_active_directory_module.rst)|Joins an ESXi host system to an Active Directory domain or leaves it
-[community.vmware.vmware_host_auto_start](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_auto_start_module.rst)|Manage the auto power ON or OFF for vm on ESXi host
-[community.vmware.vmware_host_capability_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_capability_info_module.rst)|Gathers info about an ESXi host's capability information
-[community.vmware.vmware_host_config_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_config_info_module.rst)|Gathers info about an ESXi host's advance configuration information
-[community.vmware.vmware_host_config_manager](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_config_manager_module.rst)|Manage advanced system settings of an ESXi host
-[community.vmware.vmware_host_custom_attributes](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_custom_attributes_module.rst)|Manage custom attributes from VMware for the given ESXi host
-[community.vmware.vmware_host_datastore](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_datastore_module.rst)|Manage a datastore on ESXi host
-[community.vmware.vmware_host_disk_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_disk_info_module.rst)|Gathers information about disks attached to given ESXi host/s.
-[community.vmware.vmware_host_dns](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_dns_module.rst)|Manage DNS configuration of an ESXi host system
-[community.vmware.vmware_host_dns_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_dns_info_module.rst)|Gathers info about an ESXi host's DNS configuration information
-[community.vmware.vmware_host_facts](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_facts_module.rst)|Gathers facts about remote ESXi hostsystem
-[community.vmware.vmware_host_feature_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_feature_info_module.rst)|Gathers info about an ESXi host's feature capability information
-[community.vmware.vmware_host_firewall_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_firewall_info_module.rst)|Gathers info about an ESXi host's firewall configuration information
-[community.vmware.vmware_host_firewall_manager](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_firewall_manager_module.rst)|Manage firewall configurations about an ESXi host
-[community.vmware.vmware_host_hyperthreading](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_hyperthreading_module.rst)|Enables/Disables Hyperthreading optimization for an ESXi host system
-[community.vmware.vmware_host_ipv6](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_ipv6_module.rst)|Enables/Disables IPv6 support for an ESXi host system
-[community.vmware.vmware_host_iscsi](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_iscsi_module.rst)|Manage the iSCSI configuration of ESXi host
-[community.vmware.vmware_host_iscsi_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_iscsi_info_module.rst)|Gather iSCSI configuration information of ESXi host
-[community.vmware.vmware_host_kernel_manager](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_kernel_manager_module.rst)|Manage kernel module options on ESXi hosts
-[community.vmware.vmware_host_lockdown](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_lockdown_module.rst)|Manage administrator permission for the local administrative account for the ESXi host
-[community.vmware.vmware_host_lockdown_exceptions](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_lockdown_exceptions_module.rst)|Manage Lockdown Mode Exception Users
-[community.vmware.vmware_host_logbundle](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_logbundle_module.rst)|Fetch logbundle file from ESXi
-[community.vmware.vmware_host_logbundle_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_logbundle_info_module.rst)|Gathers manifest info for logbundle
-[community.vmware.vmware_host_ntp](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_ntp_module.rst)|Manage NTP server configuration of an ESXi host
-[community.vmware.vmware_host_ntp_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_ntp_info_module.rst)|Gathers info about NTP configuration on an ESXi host
-[community.vmware.vmware_host_package_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_package_info_module.rst)|Gathers info about available packages on an ESXi host
-[community.vmware.vmware_host_passthrough](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_passthrough_module.rst)|Manage PCI device passthrough settings on host
-[community.vmware.vmware_host_powermgmt_policy](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_powermgmt_policy_module.rst)|Manages the Power Management Policy of an ESXI host system
-[community.vmware.vmware_host_powerstate](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_powerstate_module.rst)|Manages power states of host systems in vCenter
-[community.vmware.vmware_host_scanhba](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_scanhba_module.rst)|Rescan host HBA's and optionally refresh the storage system
-[community.vmware.vmware_host_scsidisk_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_scsidisk_info_module.rst)|Gather information about SCSI disk attached to the given ESXi
-[community.vmware.vmware_host_service_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_service_info_module.rst)|Gathers info about an ESXi host's services
-[community.vmware.vmware_host_service_manager](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_service_manager_module.rst)|Manage services on a given ESXi host
-[community.vmware.vmware_host_snmp](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_snmp_module.rst)|Configures SNMP on an ESXi host system
-[community.vmware.vmware_host_sriov](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_sriov_module.rst)|Manage SR-IOV settings on host
-[community.vmware.vmware_host_ssl_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_ssl_info_module.rst)|Gather info of ESXi host system about SSL
-[community.vmware.vmware_host_tcpip_stacks](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_tcpip_stacks_module.rst)|Manage the TCP/IP Stacks configuration of ESXi host
-[community.vmware.vmware_host_user_manager](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_user_manager_module.rst)|Manage users of ESXi
-[community.vmware.vmware_host_vmhba_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_vmhba_info_module.rst)|Gathers info about vmhbas available on the given ESXi host
-[community.vmware.vmware_host_vmnic_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_host_vmnic_info_module.rst)|Gathers info about vmnics available on the given ESXi host
-[community.vmware.vmware_local_role_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_local_role_info_module.rst)|Gather info about local roles on an ESXi host or vCenter
-[community.vmware.vmware_local_role_manager](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_local_role_manager_module.rst)|Manage local roles on an ESXi host or vCenter
-[community.vmware.vmware_local_user_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_local_user_info_module.rst)|Gather info about users on the given ESXi host
-[community.vmware.vmware_local_user_manager](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_local_user_manager_module.rst)|Manage local users on an ESXi host
-[community.vmware.vmware_maintenancemode](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_maintenancemode_module.rst)|Place a host into maintenance mode
-[community.vmware.vmware_migrate_vmk](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_migrate_vmk_module.rst)|Migrate a VMK interface from VSS to VDS
-[community.vmware.vmware_object_custom_attributes_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_object_custom_attributes_info_module.rst)|Gather custom attributes of an object
-[community.vmware.vmware_object_rename](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_object_rename_module.rst)|Renames VMware objects
-[community.vmware.vmware_object_role_permission](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_object_role_permission_module.rst)|Manage local roles on an ESXi host or vCenter
-[community.vmware.vmware_object_role_permission_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_object_role_permission_info_module.rst)|Gather information about object's permissions
-[community.vmware.vmware_portgroup](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_portgroup_module.rst)|Create a VMware portgroup
-[community.vmware.vmware_portgroup_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_portgroup_info_module.rst)|Gathers info about an ESXi host's Port Group configuration
-[community.vmware.vmware_recommended_datastore](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_recommended_datastore_module.rst)|Returns the recommended datastore from a SDRS-enabled datastore cluster
-[community.vmware.vmware_resource_pool](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_resource_pool_module.rst)|Add/remove resource pools to/from vCenter
-[community.vmware.vmware_resource_pool_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_resource_pool_info_module.rst)|Gathers info about resource pool information
-[community.vmware.vmware_tag](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_tag_module.rst)|Manage VMware tags
-[community.vmware.vmware_tag_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_tag_info_module.rst)|Manage VMware tag info
-[community.vmware.vmware_tag_manager](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_tag_manager_module.rst)|Manage association of VMware tags with VMware objects
-[community.vmware.vmware_target_canonical_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_target_canonical_info_module.rst)|Return canonical (NAA) from an ESXi host system
-[community.vmware.vmware_vc_infraprofile_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_vc_infraprofile_info_module.rst)|List and Export VMware vCenter infra profile configs.
-[community.vmware.vmware_vcenter_settings](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_vcenter_settings_module.rst)|Configures general settings on a vCenter server
-[community.vmware.vmware_vcenter_settings_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_vcenter_settings_info_module.rst)|Gather info vCenter settings
-[community.vmware.vmware_vcenter_statistics](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_vcenter_statistics_module.rst)|Configures statistics on a vCenter server
-[community.vmware.vmware_vm_config_option](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_vm_config_option_module.rst)|Return supported guest ID list and VM recommended config option for specific guest OS
-[community.vmware.vmware_vm_host_drs_rule](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_vm_host_drs_rule_module.rst)|Creates vm/host group in a given cluster
-[community.vmware.vmware_vm_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_vm_info_module.rst)|Return basic info pertaining to a VMware machine guest
-[community.vmware.vmware_vm_shell](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_vm_shell_module.rst)|Run commands in a VMware guest operating system
-[community.vmware.vmware_vm_storage_policy](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_vm_storage_policy_module.rst)|Create vSphere storage policies
-[community.vmware.vmware_vm_storage_policy_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_vm_storage_policy_info_module.rst)|Gather information about vSphere storage profile defined storage policy information.
-[community.vmware.vmware_vm_vm_drs_rule](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_vm_vm_drs_rule_module.rst)|Configure VMware DRS Affinity rule for virtual machines in the given cluster
-[community.vmware.vmware_vm_vss_dvs_migrate](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_vm_vss_dvs_migrate_module.rst)|Migrates a virtual machine from a standard vswitch to distributed
-[community.vmware.vmware_vmkernel](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_vmkernel_module.rst)|Manages a VMware VMkernel Adapter of an ESXi host.
-[community.vmware.vmware_vmkernel_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_vmkernel_info_module.rst)|Gathers VMKernel info about an ESXi host
-[community.vmware.vmware_vmotion](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_vmotion_module.rst)|Move a virtual machine using vMotion, and/or its vmdks using storage vMotion.
-[community.vmware.vmware_vsan_cluster](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_vsan_cluster_module.rst)|Configure VSAN clustering on an ESXi host
-[community.vmware.vmware_vsan_hcl_db](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_vsan_hcl_db_module.rst)|Manages the vSAN Hardware Compatibility List (HCL) database
-[community.vmware.vmware_vsan_health_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_vsan_health_info_module.rst)|Gather information about a VMware vSAN cluster's health
-[community.vmware.vmware_vsan_release_catalog](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_vsan_release_catalog_module.rst)|Uploads the vSAN Release Catalog
-[community.vmware.vmware_vspan_session](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_vspan_session_module.rst)|Create or remove a Port Mirroring session.
-[community.vmware.vmware_vswitch](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_vswitch_module.rst)|Manage a VMware Standard Switch to an ESXi host.
-[community.vmware.vmware_vswitch_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_vswitch_info_module.rst)|Gathers info about an ESXi host's vswitch configurations
-[community.vmware.vsan_health_silent_checks](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vsan_health_silent_checks_module.rst)|Silence vSAN health checks
-[community.vmware.vsphere_copy](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vsphere_copy_module.rst)|Copy a file to a VMware datastore
-[community.vmware.vsphere_file](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vsphere_file_module.rst)|Manage files on a vCenter datastore
-
-<!--end collection content-->
-
## Testing and Development
If you want to develop new content for this collection or improve what is already here, the easiest way to work on the collection is to clone it into one of the configured [`COLLECTIONS_PATHS`](https://docs.ansible.com/ansible/latest/reference_appendices/config.html#collections-paths), and work on it there.
@@ -260,10 +63,6 @@ If you want to develop new content for this collection or improve what is alread
Refer [testing](testing.md) for more information.
-### Updating documentation
-
-`ansible-playbook tools/update_documentation.yml`
-
## Publishing New Version
Assuming your (local) repository has set `origin` to your GitHub fork and this repository is added as `upstream`:
@@ -285,9 +84,9 @@ Revert the version in `galaxy.yml` back to `null`:
## Communication
-We have a dedicated Working Group for VMware.
-You can find other people interested in this in the `#ansible-vmware` channel on [libera.chat](https://libera.chat/) IRC.
-For more information about communities, meetings and agendas see https://github.com/ansible/community/wiki/VMware.
+You can find other people interested in this in the `Ansible VMware` room on [Matrix](https://matrix.to/#/#vmware:ansible.com) / in the `#ansible-vmware` channel on [libera.chat](https://libera.chat/) IRC.
+
+For general usage question, please also consider the `Get Help` category in the [Ansible Community Forum](https://forum.ansible.com/) and tag it with `vmware`.
## License
diff --git a/ansible_collections/community/vmware/changelogs/changelog.yaml b/ansible_collections/community/vmware/changelogs/changelog.yaml
index 33af538ad..f2d8cea11 100644
--- a/ansible_collections/community/vmware/changelogs/changelog.yaml
+++ b/ansible_collections/community/vmware/changelogs/changelog.yaml
@@ -1,1591 +1,104 @@
-ancestor: null
+ancestor: 3.9.0
releases:
- 1.0.0:
- changes:
- bugfixes:
- - Added 'compose' and 'groups' feature in vmware_vm_inventory plugin.
- - Added keyed_groups feature in vmware_vm_inventory plugin.
- - Added support to vmware_tag_manager module for specifying tag and category
- as dict if any of the name contains colon (https://github.com/ansible/ansible/issues/65765).
- - Check for virtualNicManager in Esxi host system before accessing properties
- in vmware_vmkernel_info (https://github.com/ansible/ansible/issues/62772).
- - Fixed typo in vmware_guest_powerstate module (https://github.com/ansible/ansible/issues/65161).
- - Handle Base64 Binary while JSON serialization in vmware_vm_inventory.
- - Handle NoneType error when accessing service system info in vmware_host_service_info
- module (https://github.com/ansible/ansible/issues/67615).
- - Handle list items in vSphere schema while handling facts using to_json API
- (https://github.com/ansible-collections/vmware/issues/33).
- - Handle multiple tags name with different category id in vmware_tag module
- (https://github.com/ansible/ansible/issues/66340).
- - Handle slashes in VMware network name (https://github.com/ansible/ansible/issues/64399).
- - In inventory plugin, serialize properties user specifies which are objects
- as dicts (https://github.com/ansible-collections/vmware/pull/58).
- - In vmware_guest_network module use appropriate network while creating or reconfiguring
- (https://github.com/ansible/ansible/issues/65968).
- - Made vmnics attributes optional when creating DVS as they are optional on
- the API and GUI as well.
- - VMware Guest Inventory plugin enhancements and features.
- - VMware guest inventory plugin support for filters.
- - Vmware Fix for Create overwrites a VM of same name even when the folder is
- different(https://github.com/ansible/ansible/issues/43161)
- - '`vmware_content_deploy_template`''s `cluster` argument no longer fails with
- an error message about resource pools.'
- - return correct datastore cluster placement recommendations during when adding
- disk using the vmware_guest_disk module
- - vmware - Ensure we can use the modules with Python < 2.7.9 or RHEL/CentOS
- < 7.4, this as soon as ``validate_certs`` is disabled.
- - vmware_category - fix associable datatypes (https://github.com/ansible-collections/vmware/issues/197).
- - vmware_content_deploy_template - Added param content_library to the main function
- - vmware_deploy_ovf - Fixed ova deploy error occur if vm exists
- - vmware_dvs_portgroup - Implemented configuration changes on an existing Distributed
- vSwitch portgroup.
- - vmware_dvs_portgroup_find - Cast variable to integer for comparison.
- - vmware_guest - Add ability to upgrade the guest hardware version to latest
- fix issue (https://github.com/ansible/ansible/issues/56273).
- - vmware_guest - Allow '-' (Dash) special char in windows DNS name.
- - vmware_guest - Exclude dvswitch_name from triggering guest os customization.
- - vmware_guest - Updated reference link to vapp_properties property
- - vmware_host_capability_facts - Fixed vSphere API legacy version errors occur
- in pyvmomi 7.0 and later
- - vmware_host_capability_info - Fixed vSphere API legacy version errors occur
- in pyvmomi 7.0 and later
- - vmware_host_facts - handle facts when ESXi hostsystem is poweredoff (https://github.com/ansible-collections/vmware/issues/183).
- - vmware_host_firewall_manager - Ensure we can set rule with no ``allowed_hosts``
- key (https://github.com/ansible/ansible/issues/61332)
- - vmware_host_firewall_manager - Fixed creating IP specific firewall rules with
- Python 2 (https://github.com/ansible/ansible/issues/67303)
- - vmware_host_vmhba_info - fixed node_wwn and port_wwn for FC HBA to hexadecimal
- format(https://github.com/ansible/ansible/issues/63045).
- - vmware_vcenter_settings - Fixed when runtime_settings parameters not defined
- occur error(https://github.com/ansible/ansible/issues/66713)
- - vmware_vcenter_statistics - Fix some corner cases like increasing some interval
- and decreasing another at the same time.
- - vmware_vm_inventory inventory plugin, use the port value while connecting
- to vCenter (https://github.com/ansible/ansible/issues/64096).
- - vmware_vmkernel - Remove duplicate checks.
- - vmware_vspan_session - Extract repeated code and reduce complexity of function.
- deprecated_features:
- - vmware_dns_config - Deprecate in favour of new module vmware_host_dns.
- minor_changes:
- - A `vmware` module_defaults group has been added to simplify parameters for
- multiple VMware tasks. This group includes all VMware modules.
- - Add a flag 'force_upgrade' to force VMware tools upgrade installation (https://github.com/ansible-collections/vmware/issues/75).
- - Add powerstates to match vmware_guest_powerstate module with vmware_guest
- (https://github.com/ansible/ansible/issues/55653).
- - Added a timeout parameter `wait_for_ip_address_timeout` for `wait_for_ip_address`
- for longer-running tasks in vmware_guest.
- - Added missing backing_disk_mode information about disk which was removed by
- mistake in vmware_guest_disk_info.
- - Correct datatype for state in vmware_host_lockdown module.
- - Correct example from doc of `vmware_local_role_info.py` to match the change
- of returned structure.
- - Correct example from doc of `vmware_local_role_info.py` to match the change
- of returned structure.
- - Handle exceptions raised in connect_to_vsphere_client API.
- - Minor typo fixes in vmware_httpapi related modules and module_utils.
- - Removed ANSIBLE_METADATA from all the modules.
- - Return additional information about hosts inside the cluster using vmware_cluster_info.
- - Update Module examples with FQCN.
- - Update README.md for installing any third party required Python libraries
- using pip (https://github.com/ansible-collections/vmware/issues/154).
- - add storage_provisioning type into vmware_content_deploy_ovf_template.
- - add vmware_content_deploy_ovf_template module for creating VMs from OVF templates
- - new code module for new feature for operations of VCenter infra profile config.
- - vmware.py - Only add configured network interfaces to facts.
- - vmware_cluster_drs - Implemented DRS advanced settings (https://github.com/ansible/ansible/issues/66217)
- - vmware_cluster_ha - Implemented HA advanced settings (https://github.com/ansible/ansible/issues/61421)
- - vmware_cluster_ha - Remove a wrong parameter from an example in the documentation.
- - vmware_content_deploy_template - added new field "content_library" to search
- template inside the specified content library.
- - vmware_datastore_cluster - Added basic SDRS configuration (https://github.com/ansible/ansible/issues/65154).
- - vmware_datastore_info - added ``properties`` and ``schema`` options.
- - vmware_datastore_maintenancemode now returns datastore_status instead of Ansible
- internal key results (https://github.com/ansible/ansible/issues/62083).
- - vmware_dvs_portgroup_info - Include the value of the Portgroup ``key`` in
- the result
- - vmware_dvswitch now returns the UUID of the switch
- - vmware_dvswitch_info also returns the switch UUID
- - vmware_export_ovf - increase default timeout to 30s
- - vmware_export_ovf - timeout value is actually in seconds, not minutes
- - vmware_guest - Don't search for VMDK if filename is defined.
- - vmware_guest - Extracts repeated code from configure_vapp_properties() to
- set_vapp_properties() in vmware_guest.py.
- - vmware_guest - add support VM creation and reconfiguration with multiple types
- of disk controllers and disks
- - vmware_guest - add support for create and reconfigure CDROMs attaching to
- SATA (https://github.com/ansible/ansible/issues/42995)
- - vmware_guest - add support hardware version 17 for vSphere 7.0
- - vmware_guest_custom_attributes does not require VM name (https://github.com/ansible/ansible/issues/63222).
- - vmware_guest_disk - Add `destroy` option which allows to remove a disk without
- deleting the VMDK file.
- - vmware_guest_disk - Add `filename` option which allows to create a disk from
- an existing VMDK.
- - vmware_guest_disk - add support for setting the sharing/multi-writer mode
- of virtual disks (https://github.com/ansible-collections/vmware/issues/212)
- - vmware_guest_network - network adapters can be configured without lists
- - vmware_guest_network - network_info returns a list of dictionaries for ease
- of use
- - vmware_guest_network - put deprecation warning for the networks parameter
- - vmware_guest_tools_wait now exposes a ``timeout`` parameter that allow the
- user to adjust the timeout (second).
- - vmware_host_active_directory - Fail when there are unrecoverable problems
- with AD membership instead of reporting a change that doesn't take place (https://github.com/ansible-collections/vmware/issues/59).
- - vmware_host_dns - New module replacing vmware_dns_config with increased functionality.
- - vmware_host_dns can now set the following empty values, ``domain``, ``search_domains``
- and ``dns_servers``.
- - vmware_host_facts - added ``properties`` and ``schema`` options.
- - vmware_host_firewall_manager - ``allowed_hosts`` excpects a dict as parameter,
- list is deprecated
- - vmware_host_kernel_manager now returns host_kernel_status instead of Ansible
- internal key results (https://github.com/ansible/ansible/issues/62083).
- - vmware_host_logbundle - new code module for a new feature for ESXi support
- log bundle download operation
- - vmware_host_logbundle_info - new code module for a new feature for getting
- manifests for ESXi support log bundle
- - vmware_host_ntp now returns host_ntp_status instead of Ansible internal key
- results (https://github.com/ansible/ansible/issues/62083).
- - vmware_host_service_manager now returns host_service_status instead of Ansible
- internal key results (https://github.com/ansible/ansible/issues/62083).
- - vmware_rest_client - Added a new definition get_library_item_from_content_library_name.
- - vmware_tag now returns tag_status instead of Ansible internal key results
- (https://github.com/ansible/ansible/issues/62083).
- - vmware_vm_inventory inventory plugin, raise more descriptive error when all
- template strings in ``hostnames`` fail.
- removed_features:
- - vmware_guest_find - Removed deprecated ``datacenter`` option
- - vmware_vmkernel - Removed deprecated ``ip_address`` option; use sub-option
- ip_address in the network option instead
- - vmware_vmkernel - Removed deprecated ``subnet_mask`` option; use sub-option
- subnet_mask in the network option instead
- fragments:
- - 109-vmware_host_logbundle.yml
- - 110-vmware_host_logbundle_info.yml
- - 113_vmware_content_deploy_ovf_template.yml
- - 121-vpsan_session-reduce-complexity.yaml
- - 129_vmware_vm_inventory.yml
- - 141_Correct_doc_of_vmware_local_role_info
- - 141_Correct_doc_of_vmware_local_role_info.yaml
- - 145-vmware_dvs_portgroup_find-integer-cast.yaml
- - 149-remove-duplicate-checks.yaml
- - 153-vmware_guest.yml
- - 154_update_doc.yml
- - 166-vmware_deploy_ovf.yml
- - 183_vmware_host_facts.yml
- - 185-make_vnics_optional_for_dvs.yml
- - 188-vmware_content_deploy_template-specify_content_library_name.yml
- - 197_vmware_category.yml
- - 214-add-disk-sharing.yaml
- - 219-vmware_content_deploy_template_added_param_content_library.yml
- - 225-vmware_vcenter_settings.yml
- - 253-inventory_hostnames_fail_message.yml
- - 33-vmware_guest_info_list_fix.yml
- - 44957-vmware_guest.yml
- - 46-Vcenter-infra-profile-config-operations.yml
- - 55653-vmware_guest_powerstate.yml
- - 56-vmware_rest.yml
- - 57185-fix_vmware_modules_py_pre2.79.yaml
- - 57535-vmware_vcenter_statistics_corner-cases.yml
- - 58-non-json-properties.yml
- - 58824-vmware_cluster_ha-advanced-settings.yml
- - 58824-vmware_dvs_portgroup-implement-portgroup-updates.yml
- - 59_vmware_host_active_directory.yml
- - 62083-vmware-internal_results.yml
- - 62188-VMware-Guest-Support-latest-version-while-upgrading-VM-hardware.yml
- - 62616-vmware_cluster_ha-fix-documentation.yml
- - 62772-vmware_vmkernel_info-fix.yml
- - 62810-Vmware-Guest-Allow-DashInWindowsServerDNSName.yml
- - 62916-add_properties_option_to_vmware_host_facts.yml
- - 629400-add_properties_option_to_vmware_datastore_info.yml
- - 63740-vmware_guest_disk_filename_destroy.yaml
- - 63741-do_not_search_for_vmdk_if_filename_defined.yaml
- - 64399_vmware_guest.yml
- - 64458-vmware_host_dns.yaml
- - 65-vmware_guest.yml
- - 65154-vmware_datastore_cluster-configure-dns.yml
- - 65715-vmware-content-deploy-template-fix-cluster.yml
- - 65733-fix-vmware-guest-properties-doc.yaml
- - 65765-vmware_tag_manager.yml
- - 65922-filter-VMs-of-Same-name-on-the-basis-of-folder.yml
- - 65968-vmware_guest_network.yml
- - 65997-vmware_guest-exclude-dvswitch-name-from-os-customization.yml
- - 66217-vmware_cluster_drs-advanced-settings.yml
- - 66340-vmware_tag.yml
- - 66692-vmware_host_vmhba_info_fix_63045.yml
- - 66877-vmware_host_dns.yaml
- - 66922-vmware_guest_network.yml
- - 67221-vmware-guest-disk-storage-drs-fix.yml
- - 67282-remove_options_from_some_vmware_modules_that_aren't_used_in_the_code.yml
- - 67303-vmware_host_firewall_manager-fix_ip_specific_firewall_rules_for_python2.yml
- - 67615-vmware_host_service_info_fix.yml
- - 69-vmware-extract-repeat-code.yaml
- - 7052_awx_handle_binary.yml
- - 75-vmware_guest_tool_upgrade.yml
- - fix-vim-legacy-version-error-vmware_host_capability_facts.yml
- - fix-vim-legacy-version-error-vmware_host_capability_info.yml
- - metadata_removal.yml
- - typo_fix_vmware_guest_powerstate.yml
- - update_examples.yml
- - vmware-module_fragments-group.yml
- - vmware-only-add-configured-interfaces.yml
- - vmware_cluster_info_hosts.yml
- - vmware_content_deploy_ovf_template_add_storage_provision_type.yml
- - vmware_dvs_portgroup_info_key.yaml
- - vmware_dvswitch_uuid.yaml
- - vmware_export_ovf.yaml
- - vmware_guest.yaml
- - vmware_guest_custom_attributes.yml
- - vmware_guest_disk_info_disk_mode.yml
- - vmware_guest_tools_wait_time.yaml
- - vmware_host_firewall_manager_fix_61332.yaml
- - vmware_host_lockdown_typo_fix.yml
- - vmware_httpapi_fix.yml
- - vmware_vm_inventory_compose.yml
- - vmware_vm_inventory_filter.yml
- - vmware_vm_inventory_keyed_groups.yml
- - vmware_vm_inventory_port.yml
- release_date: '2020-06-19'
- 1.1.0:
+ 4.0.0:
changes:
breaking_changes:
- - vmware_datastore_maintenancemode - now returns ``datastore_status`` instead
- of Ansible internal key ``results``.
- - vmware_guest_custom_attributes - does not require VM name which was a required
- parameter for releases prior to Ansible 2.10.
- - vmware_guest_find - the ``datacenter`` option has been removed.
- - vmware_host_kernel_manager - now returns ``host_kernel_status`` instead of
- Ansible internal key ``results``.
- - vmware_host_ntp - now returns ``host_ntp_status`` instead of Ansible internal
- key ``results``.
- - vmware_host_service_manager - now returns ``host_service_status`` instead
- of Ansible internal key ``results``.
- - vmware_tag - now returns ``tag_status`` instead of Ansible internal key ``results``.
- - vmware_vmkernel - the options ``ip_address`` and ``subnet_mask`` have been
- removed; use the suboptions ``ip_address`` and ``subnet_mask`` of the ``network``
- option instead.
- bugfixes:
- - vmware_content_deploy_ovf_template - use datastore_id in deployment_spec (https://github.com/ansible-collections/vmware/pull/287).
- - vmware_dvs_portgroup_find - Fix comparison between str and int on method vlan_match
- (https://github.com/ansible-collections/vmware/pull/52).
- - vmware_guest - cdrom.controller_number, cdrom.unit_number are handled as integer.
- (https://github.com/ansible-collections/vmware/issues/274).
- - vmware_vm_inventory - CustomFieldManager is not present in ESXi, handle this
- condition (https://github.com/ansible-collections/vmware/issues/269).
- deprecated_features:
- - The vmware_dns_config module has been deprecated and will be removed in a
- later release; use vmware_host_dns instead.
- - vca - vca_fw, vca_nat, vca_app are deprecated since these modules rely on
- deprecated part of Pyvcloud library.
- - vmware_tag_info - in a later release, the module will not return ``tag_facts``
- since it does not return multiple tags with the same name and different category
- id. To maintain the existing behavior use ``tag_info`` which is a list of
- tag metadata.
- minor_changes:
- - Added module to be able to create, update, or delete VMware VM storage policies
- for virtual machines.
- - vmware_cluster_info - added ``properties`` and ``schema`` options and supported
- the getting of clusters resource summary information.
- - vmware_content_deploy_ovf_template - handle exception while deploying VM using
- OVF template.
- - vmware_content_deploy_template - handle exception while deploying VM (https://github.com/ansible-collections/vmware/issues/182).
- - vmware_dvs_portgroup - Added support for distributed port group with private
- VLAN.
- - vmware_guest_snapshot_info - Document that `folder` is required if the VM
- `name` is defined (https://github.com/ansible-collections/vmware/issues/243)
- - vmware_host_iscsi - a new module for the ESXi hosts that is dedicated to the
- management of the iSCSI configuration
- - vmware_migrate_vmk - allow migration from a VMware vSphere Distrubuted Switch
- to a ESXi Standard Switch
- - vmware_vcenter_settings_info - a new module for gather information about vCenter
- settings
+ - Removed support for ansible-core version < 2.15.0.
+ - vmware_dvs_host - removed defaults for `vmnics` and `lag_uplinks` (https://github.com/ansible-collections/community.vmware/issues/1516).
+ - vmware_host_acceptance - removed `acceptance_level` and used its options in
+ `state`. This also means there will be no state `list` anymore. In order to
+ get information about the current acceptance level, use the new module `vmware_host_acceptance_info`
+ (https://github.com/ansible-collections/community.vmware/issues/1872).
+ - vmware_vm_info - added prefix length to IP addresses in vm_network, so they
+ now show up as for example 10.76.33.228/24 instead of just 10.76.33.228 (https://github.com/ansible-collections/community.vmware/issues/1761).
+ bugfixes:
+ - vmware_deploy_ovf - fix error in finding networks part of code (https://github.com/ansible-collections/community.vmware/issues/1853).
+ - vmware_guest_custom_attributes - fix problem when module try apply non global
+ or non VM type custom attribute to VM object (https://github.com/ansible-collections/community.vmware/issues/1772).
+ minor_changes:
+ - Removed module / plugin documentation RST files from the repository (https://github.com/ansible-collections/community.vmware/pull/1897).
+ - Using semantic markup in documentation (https://github.com/ansible-collections/community.vmware/issues/1771).
+ - vmware_deploy_ovf - New parameter enable_hidden_properties to force OVF properties
+ marked as `ovf:userConfigurable=false` to become user configurable (https://github.com/ansible-collections/community.vmware/issues/802).
+ - vmware_dvs_portgroup_info - add moid property in the return value for the
+ module (https://github.com/ansible-collections/community.vmware/issues/1849).
+ - vmware_guest_snapshot - add new snapshot_id option (https://github.com/ansible-collections/community.vmware/pull/1847).
+ - vmware_host_snmp module now can configure SNMP agent on set of hosts (list
+ in esxi_hostname parameter or as cluster in cluster_name parameter). The ability
+ to configure the host directly remains (https://github.com/ansible-collections/community.vmware/issues/1799).
removed_features:
- - vmware_portgroup - removed 'inbound_policy', and 'rolling_order' deprecated
- options.
- fragments:
- - 124-vmware-migrate-vmk-to-std-switch.yaml
- - 182_content_library.yml
- - 224-vmware_host_iscsi.yml
- - 243_vmware_guest_snapshot_info.yml
- - 269_vmware_vm_inventory.yml
- - 274_vmware_guest.yml
- - 275_vmware_vcenter_settings_info.yml
- - 287_deploy_ovf_template.yml
- - 321-vmware_cluster_info.yml
- - 52-vmware_dvs_portgroup_find_fix.yml
- - porting-guide.yml
- - pvlan-config-vmware-dvs-portgroup.yml
- - vca_deprecate.yml
- - vmware_pg_options.yml
- - vmware_vm_storage_policy_module.yml
- release_date: '2020-08-01'
- 1.10.0:
- changes:
- bugfixes:
- - vmware - fixed a bug that the guest_guestion in the facts doesn't convert
- to the dictionary (https://github.com/ansible-collections/community.vmware/pull/825).
- - vmware - handle exception raised in ``get_all_objs`` and ``find_object_by_name``
- which occurs due to multiple parallel operations (https://github.com/ansible-collections/community.vmware/issues/791).
- - vmware_cluster_info - Fix a bug that returned enabled_vsan and vsan_auto_claim_storage
- as lists instead of just true or false (https://github.com/ansible-collections/community.vmware/issues/805).
- - vmware_evc_mode - fixed an issue that evc_mode is required when the state
- parameter set to absent (https://github.com/ansible-collections/community.vmware/pull/764).
- - vmware_guest - skip customvalues while deploying VM on a standalone ESXi (https://github.com/ansible-collections/community.vmware/issues/721).
- - vmware_host_iscsi_info - fixed an issue that an error occurs gathering iSCSI
- information against an ESXi Host with iSCSI disabled (https://github.com/ansible-collections/community.vmware/pull/729).
- - vmware_vm_info - handle vApp parent logic (https://github.com/ansible-collections/community.vmware/issues/777).
- - vmware_vm_shell - handle exception raised while performing the operation (https://github.com/ansible-collections/community.vmware/issues/732).
- - vmware_vm_storage_policy_info - fixed an issue that the module can't get storage
- policy info when the policy has the tag base rules (https://github.com/ansible-collections/community.vmware/pull/788).
- - vmware_vmotion - Provide an meaningful error message when providing a bad
- ESXi node as ``destination_host`` (https://github.com/ansible-collections/vmware/pull/804).
- minor_changes:
- - vmware_cluster_drs - Make enable_drs an alias of enable and add a warning
- that the default will change from false to true in a future version (https://github.com/ansible-collections/community.vmware/pull/766)
- - vmware_cluster_ha - Make enable_ha an alias of enable and add a warning that
- the default will change from false to true in a future version (https://github.com/ansible-collections/community.vmware/pull/766)
- - vmware_cluster_vsan - Make enable_vsan an alias of enable and add a warning
- that the default will change from false to true in a future version (https://github.com/ansible-collections/community.vmware/pull/766)
- - vmware_dvs_portgroup - Implement 'elastic' port group configuration (https://github.com/ansible-collections/community.vmware/issues/410).
- - vmware_dvs_portgroup - Implement MAC learning configuration (https://github.com/ansible-collections/community.vmware/issues/644).
- - vmware_dvs_portgroup - Implement configuration of active and standby uplinks
- (https://github.com/ansible-collections/community.vmware/issues/709).
- - vmware_dvs_portgroup - Remove default for teaming_policy.inbound_policy (https://github.com/ansible-collections/community.vmware/pull/743).
- - vmware_dvs_portgroup_info - Return information about MAC learning configuration
- (https://github.com/ansible-collections/community.vmware/issues/644).
- - vmware_dvs_portgroup_info - Return information about uplinks (https://github.com/ansible-collections/community.vmware/issues/709).
- - vmware_guest - add more documentation about ``is_template`` (https://github.com/ansible-collections/community.vmware/pull/794).
- - vmware_host_iscsi_info - added a list(detected_iscsi_drives) of detected iscsi
- drives to the return value after set an iscsi config (https://github.com/ansible-collections/community.vmware/pull/729).
- - vmware_tag - modified the category_id parameter to required (https://github.com/ansible-collections/community.vmware/pull/790).
- - vmware_vm_inventory - set default to ``True`` for ``with_nested_properties``
- (https://github.com/ansible-collections/community.vmware/issues/712).
- fragments:
- - 644-vmware_dvs_portgroup.yml
- - 712_vmware_vm_inventory.yml
- - 721_vmware_guest.yml
- - 729-vmware_host_iscsi_info.yml
- - 732_vmware_vm_shell.yml
- - 739-vmware_cluster_drs.yml
- - 764-vmware_evc_mode.yml
- - 777_vapp_info.yml
- - 788-vmware_vm_storage_policy_info.yml
- - 790-vmware_tag.yml
- - 791_vmware.yml
- - 803-vmware_vmotion-better-error-msg.yml
- - 805-vmware_cluster_info.yml
- - 825-vmware.yml
- - is_template.yml
- modules:
- - description: Manage the TCP/IP Stacks configuration of ESXi host
- name: vmware_host_tcpip_stacks
- namespace: ''
- release_date: '2021-05-05'
- 1.11.0:
- changes:
- bugfixes:
- - vmware - fix that the return value should be returned None if moId doesn't
- exist of a virtual machine (https://github.com/ansible-collections/community.vmware/pull/867).
- - vmware_vmotion - implement new parameter named destination_datacenter to fix
- failure to move storage when datastores are shared across datacenters (https://github.com/ansible-collections/community.vmware/issues/858)
- major_changes:
- - vmware_object_custom_attributes_info - added a new module to gather custom
- attributes of an object (https://github.com/ansible-collections/community.vmware/pull/851).
- minor_changes:
- - vmware - added a new method to search Managed Object based on moid and object
- type (https://github.com/ansible-collections/community.vmware/pull/879).
- - vmware_dvswitch - Dynamically check the DVS versions vCenter supports (https://github.com/ansible-collections/community.vmware/issues/839).
- - vmware_dvswitch - Implement network_policy parameter with suboptions promiscuous,
- forged_transmits and mac_changes (https://github.com/ansible-collections/community.vmware/issues/833).
- - vmware_guest - Make the requirements for Virtualization Based Security explicit
- (https://github.com/ansible-collections/community.vmware/pull/816).
- - vmware_guest - New parameter ``secure_boot`` to manage (U)EFI secure boot
- on VMs (https://github.com/ansible-collections/community.vmware/pull/816).
- - vmware_guest - New parameter ``vvtd`` to manage Intel Virtualization Technology
- for Directed I/O on VMs (https://github.com/ansible-collections/community.vmware/pull/816).
- - vmware_guest_controller - added bus_sharing property to scsi controllers (https://github.com/ansible-collections/community.vmware/pull/878).
- - vmware_guest_instant_clone - added the the guestinfo_vars parameter to provide
- GuestOS Customization functionality in instant cloned VM (https://github.com/ansible-collections/community.vmware/pull/796).
- - vmware_host_custom_attributes - new module (https://github.com/ansible-collections/community.vmware/pull/838).
- - vmware_host_inventory - added ability for username to be a vault encrypted
- variable, and updated documentation to reflect ability for username and password
- to be vaulted. (https://github.com/ansible-collections/community.vmware/issues/854).
- - vmware_host_passthrough - added a new module to enable or disable passthrough
- of PCI devices with ESXi host has (https://github.com/ansible-collections/community.vmware/pull/872).
- - vmware_host_tcpip_stacks - added ipv6_gateway parameter and nsx_overlay as
- an alias of vxlan (https://github.com/ansible-collections/community.vmware/pull/834).
- - vmware_host_vmnic_info - add LLDP information to output when applicable (https://github.com/ansible-collections/community.vmware/pull/828).
- - vmware_object_custom_attributes_info - added a new parameter to support moid
- (https://github.com/ansible-collections/community.vmware/pull/879).
- - vmware_vcenter_settings.py - Add advanced_settings parameter (https://github.com/ansible-collections/community.vmware/pull/819).
- - vmware_vm_inventory - added ability for username to be a vault encrypted variable,
- and updated documentation to reflect ability for username and password to
- be vaulted. (https://github.com/ansible-collections/community.vmware/issues/854).
- fragments:
- - 796-vmware_guest_instant_clone.yml
- - 816-vmware_guest.yml
- - 819-vmware_vcenter_settings-advanced_setting.yml
- - 828_vmware_host_vmnic_info.yml
- - 833-vmware_dvswitch-network_policy.yml
- - 834-vmware_host_tcpip_stacks.yml
- - 838_vmware_host_custom_attributes.yml
- - 851-vmware_object_custom_attributes_info.yml
- - 855_vmware_host_inventory.yml
- - 855_vmware_vm_inventory.yml
- - 858_vmware_vmotion_add_destination_datacenter_parameter.yml
- - 867-vmware.yml
- - 872-vmware_host_passthrough.yml
- - 878_vmware_guest_controller.yml
- - 879-vmware_object_custom_attributes_info.yml
- modules:
- - description: Manage custom attributes from VMware for the given ESXi host
- name: vmware_host_custom_attributes
- namespace: ''
- - description: Manage PCI device passthrough settings on host
- name: vmware_host_passthrough
- namespace: ''
- - description: Gather custom attributes of an object
- name: vmware_object_custom_attributes_info
- namespace: ''
- - description: Gather information about object's permissions
- name: vmware_object_role_permission_info
- namespace: ''
- - description: Returns the recommended datastore from a SDRS-enabled datastore
- cluster
- name: vmware_recommended_datastore
- namespace: ''
- plugins:
- inventory:
- - description: VMware ESXi hostsystem inventory source
- name: vmware_host_inventory
- namespace: null
- release_date: '2021-06-11'
- 1.12.0:
- changes:
- bugfixes:
- - vmware_content_deploy_ovf_template - no longer requires host, datastore, resource_pool.
- - vmware_content_deploy_xxx - deploys to recommended datastore in specified
- datastore_cluster.
- - vmware_content_deploy_xxx - honors folder specified by fully qualified path
- name.
- - vmware_guest - Use hostname parameter in customization only if value is not
- None (https://github.com/ansible-collections/community.vmware/issues/655)
- minor_changes:
- - vmware - add processing to answer if the answer question is occurred in starting
- the vm (https://github.com/ansible-collections/community.vmware/pull/821).
- - vmware - find_folder_by_fqpn added to support specifying folders by their
- fully qualified path name, defined as I(datacenter)/I(folder_type)/subfolder1/subfolder2/.
- - vmware - folder field default changed from None to vm.
- - vmware_content_deploy_ovf_template - storage_provisioning default changed
- from None to thin, in keeping with VMware best practices for flash storage.
- - vmware_dvs_host - implement adding pNICs to LAGs (https://github.com/ansible-collections/community.vmware/issues/112).
- - vmware_guest_instant_clone - added a new option to wait until the vmware tools
- start (https://github.com/ansible-collections/community.vmware/pull/904).
- - vmware_guest_instant_clone - added a reboot processing to reflect the customization
- parameters to an instant clone vm (https://github.com/ansible-collections/community.vmware/pull/904).
- - vmware_guest_powerstate - Add an option that answers whether it was copied
- or moved the vm if the vm is blocked (https://github.com/ansible-collections/community.vmware/pull/821).
- - vmware_host_inventory - support api access via proxy (https://github.com/ansible-collections/community.vmware/pull/817).
- - vmware_object_role_permission_info - added principal to provide list of individual
- permissions on specified entity (https://github.com/ansible-collections/community.vmware/issues/868).
- - vmware_rest_client - support proxy feature for module using this API (https://github.com/ansible-collections/community.vmware/pull/848).
- - vmware_vm_inventory - support api access via proxy (https://github.com/ansible-collections/community.vmware/pull/817).
- fragments:
- - 112-vmware_dvs_host.yml
- - 738-vmware_content_deploy_xxx.yml
- - 817-vmware_vm_inventory-support-proxy.yml
- - 821-vmware_guest_powerstate.yml
- - 831-vmware_guest-hostname.yml
- - 848_vmware_rest_client_add_support_for_proxy.yml
- - 874-vmware_object_role_permission_info-principal_permissions.yml
- - 904-vmware_guest_instant_clone.yml
- release_date: '2021-07-07'
- 1.13.0:
- changes:
- bugfixes:
- - vmware - changed to use from isinstance to type in the if condition of option_diff
- method (https://github.com/ansible-collections/community.vmware/pull/983).
- - vmware_guest - add message for `deploy_vm` method when it fails with timeout
- error while customizing the VM (https://github.com/ansible-collections/community.vmware/pull/933).
- - vmware_guest_instant_clone - fixed an issue that the module should be required
- the guestinfo_vars parameter when executing (https://github.com/ansible-collections/community.vmware/pull/962).
- - vmware_guest_powerstate - added the datacenter parameter to fix an issue that
- datacenter key error has been occurring (https://github.com/ansible-collections/community.vmware/pull/924).
- - vmware_host_datastore - fixed an issue that the right error message isn't
- displayed (https://github.com/ansible-collections/community.vmware/pull/976).
- minor_changes:
- - vm_device_helper - Add new functions for create, remove or reconfigure virutal
- NVDIMM device (https://github.com/ansible-collections/community.vmware/issues/853).
- - vmware - the scenario guides from Ansible repo migrated to collection repo.
- - vmware_guest - Add new parameter 'nvdimm' for add, remove or reconfigure virutal
- NVDIMM device of virtual machine (https://github.com/ansible-collections/community.vmware/issues/853).
- - vmware_guest_disk - add the capability to create and remove RDM disks from
- Virtual Machines.
- - vmware_guest_snapshot_info - add quiesced status in VM snapshot info (https://github.com/ansible-collections/community.vmware/pull/978)
- - vmware_host_datastore - added a new parameter to expand a datastore capacity
- (https://github.com/ansible-collections/community.vmware/pull/915).
- - vmware_host_inventory - filter hosts before templating hostnames (https://github.com/ansible-collections/community.vmware/issues/850).
- - vmware_portgroup - Disable traffic shaping without defining ``traffic_shaping.average_bandwidth``,
- ``traffic_shaping.burst_size`` and ``traffic_shaping.peak_bandwidth`` (https://github.com/ansible-collections/community.vmware/issues/955).
- - vmware_spbm - Add a new function 'find_storage_profile_by_name' (https://github.com/ansible-collections/community.vmware/issues/853).
- - vmware_vm_inventory - filter guests before templating hostnames (https://github.com/ansible-collections/community.vmware/issues/850).
- fragments:
- - 449-vmware_guest_disk_rdm.yml
- - 850_vmware_inventory.yml
- - 853-vmware_guest.yml
- - 915-vmware_host_datastore.yml
- - 924-vmware_guest_powerstate.yml
- - 933-vmware_guest_add_msg_customization_failed.yml
- - 955-vmware_portgroup.yml
- - 962-vmware_guest_instant_clone.yml
- - 976-vmware_host_datastore.yml
- - 978-vmware_guest_snapshot_info.yml
- - 983-vmware.yml
- - migrate_vmware_scenario_guides.yml
- release_date: '2021-08-16'
- 1.14.0:
- changes:
- bugfixes:
- - vmware_category - fixed some issues that the errors have occurred in executing
- the module (https://github.com/ansible-collections/community.vmware/pull/990).
- - vmware_guest_network - Fix adding more than one NIC to a VM before powering
- on (https://github.com/ansible-collections/community.vmware/issues/860).
- minor_changes:
- - vmware_host_service_manager - Introducing a new state "unchanged" to allow
- defining startup policy without defining service state or automatically starting
- it (https://github.com/ansible-collections/community.vmware/issues/916).
- fragments:
- - 860-vmware_guest_network.yml
- - 916-vmware_host_service_manager.yml
- - 990-vmware_category.yml
- release_date: '2021-09-01'
- 1.15.0:
- changes:
- bugfixes:
- - Fix a bug that prevented enabling VSAN on more than one vmk, risking splitting
- the whole cluster during interface migration scenarios (https://github.com/ansible-collections/community.vmware/issues/891)
- - vmware_deploy_ovf - Fix deploy ovf issue when there are more than one datacenter
- in VC (https://github.com/ansible-collections/community.vmware/issues/164).
- - vmware_deploy_ovf - fixed to display suitable the error when not exist an
- ovf file path (https://github.com/ansible-collections/community.vmware/pull/1065).
- - vmware_guest_powerstate - handle 'present' state as 'poweredon' (https://github.com/ansible-collections/community.vmware/pull/1033).
- - vmware_guest_tools_wait - add documentation about datacenter parameter (https://github.com/ansible-collections/community.vmware/pull/870).
- - vmware_object_rename - fixed an issue that an error has occurred when getting
- than 1,000 objects (https://github.com/ansible-collections/community.vmware/pull/1010).
- - vmware_vcenter_settings_info - fix to return all VCSA settings when setting
- vsphere to the schema and not specifying the properties (https://github.com/ansible-collections/community.vmware/pull/1050).
- - vmware_vm_inventory - remove erroneous ``ansible_host`` condition (https://github.com/ansible-collections/community.vmware/issues/975).
- deprecated_features:
- - vmware_guest_vnc - Sphere 7.0 removed the built-in VNC server (https://docs.vmware.com/en/VMware-vSphere/7.0/rn/vsphere-esxi-vcenter-server-70-release-notes.html#productsupport).
- minor_changes:
- - vm_device_helper - move NIC device types from vmware_guest module to vm_device_helper
- (https://github.com/ansible-collections/community.vmware/pull/998).
- fragments:
- - 0-copy_ignore_txt.yml
- - 1010-vmware_object_rename.yml
- - 1050-vmware_vcenter_settings_info.yml
- - 1065-vmware_deploy_ovf.yml
- - 164-vmware_deploy_ovf.yml
- - 870_vmware_guest_tools_wait.yml
- - 892-vmware_vmkernel.yml
- - 975_vmware_vm_inventory.yml
- - 993-vmware_vm_config_option.yml
- - deprecate-vmware_guest_vnc.yml
- - powerstate.yml
- modules:
- - description: Return supported guest ID list and VM recommended config option
- for specific guest OS
- name: vmware_vm_config_option
- namespace: ''
- release_date: '2021-10-05'
- 1.16.0:
- changes:
- bugfixes:
- - update_vswitch - add the possibility to remove nics from vswitch (https://github.com/ansible-collections/community.vmware/issues/536)
- - vmware_guest_serial_port - handle correct serial backing type (https://github.com/ansible-collections/community.vmware/issues/1043).
- - vmware_host_lockdown - Fix an issue when enabling or disabling lockdown mode
- failes (https://github.com/ansible-collections/community.vmware/issues/1083)
- minor_changes:
- - vmware - add vTPM information to default gather information (https://github.com/ansible-collections/community.vmware/pull/1082).
- - vmware_guest_cross_vc_clone - Added the is_template option to mark a cloned
- vm/template as a template (https://github.com/ansible-collections/community.vmware/pull/996).
- fragments:
- - 1043_vmware_guest_serial.yml
- - 1082_vmware.yml
- - 1083_vmware_host_lockdown.yml
- - 840_vmware_vswitch.yml
- - 996_vmware_guest_cross_vc_clone.yml
- modules:
- - description: Add or remove vTPM device for specified VM.
- name: vmware_guest_tpm
- namespace: ''
- release_date: '2021-11-05'
- 1.17.0:
- changes:
- bugfixes:
- - vmware_guest - when ``customization.password`` is not defined, the Administrator
- password is made empty instead of setting it to string 'None' (https://github.com/ansible-collections/community.vmware/issues/1017).
- minor_changes:
- - vmware_datastore_info - added show_tag parameters to allow datastore tags
- to be read in a uniform way across _info modules (https://github.com/ansible-collections/community.vmware/pull/1085).
- - vmware_guest_disk - Added a new key 'cluster_disk' which allows you to use
- a filename originating from a VM with an RDM.
- - vmware_guest_disk - Added bus_sharing as an option for SCSI devices.
- - vmware_guest_disk - Enabled the use of up to 64 disks on a paravirtual SCSI
- controller when the hardware is version 14 or higher.
- - vmware_guest_sendkey - added additional USB scan codes for HOME and END.
- - vmware_host_scanhba - add rescan_vmfs parameter to allow rescaning for new
- VMFS volumes. Also add rescan_hba parameter with default true to allow for
- not rescaning HBAs as this might be very slow. (https://github.com/ansible-collections/community.vmware/issues/479)
- - vmware_host_snmp - implement setting syscontact and syslocation (https://github.com/ansible-collections/community.vmware/issues/1044).
- - vmware_rest_client module_util - added function get_tags_for_datastore for
- convenient tag collection (https://github.com/ansible-collections/community.vmware/pull/1085).
- fragments:
- - 1013-vmware_rdm_updates.yml
- - 1017-vmware_guest-fix_administrator_password.yml
- - 1044_add_syscontact_syslocation_vmware_host_snmp.yml
- - 1085_add_show_tag_to_vmware_datastore_info.yml
- - 1117_add_additional_usb_scan_codes.yml
- - rescan_VMFS_feature.yml
- release_date: '2021-12-06'
- 1.2.0:
- changes:
- bugfixes:
- - vmware_content_deploy_ovf_template - fixed issue where wrong resource pool
- identifier was returned when same resource pool name was used across clusters
- in the same datacenter (https://github.com/ansible-collections/vmware/pull/363)
- - vmware_vmkernel - fixed issue where Repl and ReplNFC services were not being
- identified as enabled on a vmk interface (https://github.com/ansible-collections/vmware/issues/362).
- deprecated_features:
- - vmware_guest - deprecate specifying CDROM configuration as a dict, instead
- use a list.
- minor_changes:
- - vmware_cluster_ha - treat truthy advanced options ('true', 'false') as strings
- instead of booleans (https://github.com/ansible-collections/vmware/issues/286).
- - vmware_cluster_vsan - implement advanced VSAN options (https://github.com/ansible-collections/vmware/issues/260).
- - vmware_cluster_vsan - requires the vSAN Management SDK, which needs to be
- downloaded from VMware and installed manually.
- - vmware_content_deploy_ovf_template - requires the resource_pool parameter.
- - vmware_guest_disk - add backing_uuid value to return (https://github.com/ansible-collections/vmware/pull/348).
- - vmware_guest_serial_port - ensure we can run the module two times in a row
- without unexpected side effect(https://github.com/ansible-collections/vmware/pull/358).
- fragments:
- - 163-vmware_content_deploy_ovf_template.py.yml
- - 260-vmware_cluster_vsan.yml
- - 286-vmware_cluster_ha.yml
- - 348-vmware_guest_disk.yml
- - 358-vmware_guest_serial_port.yml
- - 363-vmware_content_deploy_ovf_template.yml
- - 364-vmware_vmkernel-replciation-fix.yml
- - cdrom_dict_removal.yml
- release_date: '2020-08-28'
- 1.3.0:
- changes:
- bugfixes:
- - '``module_utils/vmware.py`` handles an object name using special characters
- that URL-decoded(https://github.com/ansible-collections/vmware/pull/380).'
- minor_changes:
- - module_utils/vmware - Ignore leading and trailing whitespace when searching
- for objects (https://github.com/ansible-collections/vmware/issues/335)
- - vmware_cluster_info - Fixed issue of a cluster name doesn't URL-decode(https://github.com/ansible-collections/vmware/pull/366)
- - vmware_guest - takes now into account the ``esxi_hostname`` argument to create
- the vm on the right host according to the doc (https://github.com/ansible-collections/vmware/pull/359).
- - vmware_guest_custom_attributes - Fixed issue when trying to set a VM custom
- attribute when there are custom attributes with the same name for other object
- types (https://github.com/ansible-collections/community.vmware/issues/412).
- - vmware_guest_customization_info - Fixed to get values properly for LinuxPrep
- and SysPrep parameters(https://github.com/ansible-collections/vmware/pull/368)
- - vmware_guest_info - Fix get tags API call (https://github.com/ansible-collections/community.vmware/issues/403).
- - vmware_guest_network - Fixed to port group changes to work properly and NSX-T
- port group supported(https://github.com/ansible-collections/community.vmware/pull/401).
- - vmware_host_iscsi_info - a new module for the ESXi hosts that is dedicated
- to gathering information of the iSCSI configuration(https://github.com/ansible-collections/community.vmware/pull/402).
- - vmware_vm_inventory - update requirements doc.
- fragments:
- - 335-vmware-strip-names-when-searching.yml
- - 366-vmware_cluster_info.yml
- - 368-vmware_guest_customization_info.yml
- - 380-vmware-handle-special-characters.yml
- - 400-vm-created-on-specified-host.yml
- - 401-vmware_guest_network.yml
- - 402-vmware_host_iscsi_info.yml
- - 403_fix_vmware_guest_info.yml
- - 412-vmware_guest_custom_attributes.yml
- - vmware_vm_inventory_req.yml
- release_date: '2020-10-01'
- 1.4.0:
- changes:
- bugfixes:
- - Fixed the find_obj method in the ``module_utils/vmware.py`` to handle an object
- name using special characters that URL-decoded(https://github.com/ansible-collections/community.vmware/pull/460).
- - vmware_cluster_info - return tag related information (https://github.com/ansible-collections/community.vmware/issues/453).
- - vmware_deploy_ovf - fixed network mapping in multi-datacenter environments
- - vmware_folder_info - added the flat_folder_info in the return value.
- - vmware_guest_sendkey - add sleep_time parameter to add delay in-between keys
- sent (https://github.com/ansible-collections/community.vmware/issues/404).
- - vmware_resource_pool - added a changing feature of resource pool config (https://github.com/ansible-collections/community.vmware/pull/469).
- - vmware_resource_pool - fixed that always updates occur bug on vCenter Server
- even when not changing resource pool config (https://github.com/ansible-collections/community.vmware/pull/482).
- - vmware_tag_manager - added new parameter 'moid' to identify VMware object
- to tag (https://github.com/ansible-collections/community.vmware/issues/430).
- - vmware_vm_info - added the moid information in the return value.
- - vmware_vm_inventory - ensure self.port is integer (https://github.com/ansible-collections/community.vmware/issues/488).
- - vmware_vm_inventory - improve plugin performance (https://github.com/ansible-collections/community.vmware/issues/434).
- - vmware_vm_vm_drs_rule - report changes in check mode (https://github.com/ansible-collections/community.vmware/issues/440).
- minor_changes:
- - vmware_category - add additional associable object types (https://github.com/ansible-collections/community.vmware/issues/454).
- - vmware_dvswitch - Added support to create vds version 7.0.0.
- - vmware_guest - Fixed issue of checking hardware version when set VBS(https://github.com/ansible-collections/community.vmware/issues/351)
- - vmware_guest - Fixed issue of comparing latest hardware version str type with
- int(https://github.com/ansible-collections/community.vmware/issues/381)
- - vmware_guest_info - added a new parameter to gather detailed information about
- tag from the given virtual machine.
- - vmware_guest_video - gather facts for video devices even if the virtual machine
- is poweredoff (https://github.com/ansible-collections/community.vmware/issues/408).
- - vmware_object_role_permission - add missing required fields of hostname, username,
- and password to module examples (https://github.com/ansible-collections/community.vmware/issues/426).
- - vmware_resource_pool - add new allocation shares options for cpu and memory(https://github.com/ansible-collections/community.vmware/pull/461).
- - vmware_vm_inventory - support for categories and tag, category relation (https://github.com/ansible-collections/community.vmware/issues/350).
- fragments:
- - 350_vmware_vm_inventory.yml
- - 381-vmware_guest.yml
- - 404_vmware_guest_sendkey.yml
- - 408_video_facts.yml
- - 426_vmware_object_role_permission.yml
- - 430_vmware_tag_manager.yml
- - 440_vmware_drs_rule.yml
- - 441_vmware_vm_inventory_performance.yaml
- - 453_vmware_cluster_info.yml
- - 454_vmware_category.yml
- - 460_module_utils_vmware.yml
- - 461_vmware_resource_pool.yml
- - 469_vmware_resource_pool.yml
- - 474_vmware_dvswitch.yml
- - 482_vmware_resource_pool.yml
- - 489_vmware_vm_inventory_port_cast_integer.yaml
- - vmware_deploy_ovf.yml
- - vmware_guest_info.yml
- release_date: '2020-11-12'
- 1.5.0:
- changes:
- bugfixes:
- - vmware_cluster_ha - added APD and PDL configuration (https://github.com/ansible-collections/community.vmware/issues/451).
- - vmware_deploy_ovf - fixed an UnboundLocalError for variable 'name' in check
- mode (https://github.com/ansible-collections/community.vmware/pull/499).
- - vmware_object_role_permission - add support for role name presented in vSphere
- Web UI (https://github.com/ansible-collections/community.vmware/issues/436).
- minor_changes:
- - vmware_content_deploy_ovf_template - added new parameter "content_library"
- to get the OVF template from (https://github.com/ansible-collections/community.vmware/issues/514).
- - vmware_drs_group - code refactor (https://github.com/ansible-collections/community.vmware/pull/475).
- - vmware_guest - add documentation for networks parameters connected and start_connected
- (https://github.com/ansible-collections/community.vmware/issues/507).
- - vmware_guest_controller - error handling in task exception.
- - vmware_resource_pool - manage resource pools on ESXi hosts (https://github.com/ansible-collections/community.vmware/issues/492).
- - vmware_vm_inventory - skip inaccessible vm configuration.
- fragments:
- - 436_vmware_object_role_permission.yml
- - 451_vmware_cluster_ha.yml
- - 492-vmware_resource_pool-esxi_host.yml
- - 499-vmware_deploy_ovf.yml
- - 507-vmware_guest_fix-documentation.yml
- - 514_vmware_content_deploy_ovf_template-add_content_library_parameter.yml
- - 81_vmware_drs_group.yml
- - inventory_fix.yml
- - vmware_guest_ctrl.yml
- release_date: '2020-12-01'
- 1.5.1:
- changes:
- minor_changes:
- - vmware_resource_pool - relabel the change introduced in 1.5.0 as Minor Changes
- (https://github.com/ansible-collections/community.vmware/issues/540).
- release_date: '2020-12-02'
- 1.6.0:
- changes:
- bugfixes:
- - Fix remove hosts from cluster to use cluster name variable
- - Fix vSwitch0 default port group removal to run against all hosts
- - For vSphere 7.0u1, add steps to tests to remove vCLS VMs before removing datastore
- - vmware_cluster - consider datacenter name while creating cluster (https://github.com/ansible-collections/community.vmware/issues/575).
- - vmware_cluster_drs - consider datacenter name while managing cluster (https://github.com/ansible-collections/community.vmware/issues/575).
- - vmware_cluster_ha - consider datacenter name while managing cluster (https://github.com/ansible-collections/community.vmware/issues/575).
- - vmware_cluster_vsan - consider datacenter name while managing cluster (https://github.com/ansible-collections/community.vmware/issues/575).
- - vmware_dvswitch - fix an issue with vSphere 7 when no switch_version is defined
- (https://github.com/ansible-collections/community.vmware/issues/576)
- - vmware_guest - fix an issue with vSphere 7 when adding several virtual disks
- and / or vNICs (https://github.com/ansible-collections/community.vmware/issues/545)
- - vmware_guest - handle computer name in existing VM customization (https://github.com/ansible-collections/community.vmware/issues/570).
- - vmware_guest_disk - fix an issue with vSphere 7 when adding several virtual
- disks and (https://github.com/ansible-collections/community.vmware/issues/373)
- - vmware_host_logbundle - handle fetch_url status before attempting to read
- response.
- - vmware_host_ntp - fix an issue with disconnected hosts (https://github.com/ansible-collections/community.vmware/issues/539)
- - vsphere_copy - handle unboundlocalerror when timeout occurs (https://github.com/ansible-collections/community.vmware/issues/554).
- minor_changes:
- - vmware_guest_disk - add new parameters controller_type and controller_number
- for supporting SATA and NVMe disk (https://github.com/ansible-collections/vmware/issues/196).
- - vmware_guest_file_operation - provide useful error message when exception
- occurs (https://github.com/ansible-collections/community.vmware/issues/485).
- - vmware_guest_network - add support for private vlan id (https://github.com/ansible-collections/community.vmware/pull/511).
- - vmware_host - added a new state option, the ``disconnected`` (https://github.com/ansible-collections/community.vmware/pull/589).
- - vmware_host_facts - Add ESXi host current time info in returned host facts(https://github.com/ansible-collections/community.vmware/issues/527)
- - vmware_vsan_health_info - add new parameter to support datacenter.
- fragments:
- - 196_vmware_guest_disk.yml
- - 373-vmware_guest_disk.yml
- - 485_vmware_file_operation.yml
- - 527-vmware_host_facts.yml
- - 539-vmware_host_ntp.yml
- - 545-vmware_guest.yml
- - 554_vsphere_copy.yml
- - 568_teardown_with_esxi.yaml
- - 570_vmware_guest.yml
- - 575_vmware_cluster.yml
- - 576-vmware_dvswitch.yml
- - 589_vmware_host.yml
- - pvlan_support.yml
- - vmware_host_logbundle.yml
- - vsan_health_info_refactor.yml
- modules:
- - description: Gather user or group information of a domain
- name: vcenter_domain_user_group_info
- namespace: ''
- release_date: '2021-01-04'
- 1.7.0:
- changes:
- bugfixes:
- - vmware_content_library_manager - added support for subscribed library (https://github.com/ansible-collections/community.vmware/pull/569).
- - vmware_datastore_cluster_manager - Fix idempotency in check mode (https://github.com/ansible-collections/community.vmware/issues/623).
- - vmware_dvswitch - correctly add contact information (https://github.com/ansible-collections/community.vmware/issues/608).
- - vmware_dvswitch_lacp - typecast uplink number in lag_options (https://github.com/ansible-collections/community.vmware/issues/111).
- - vmware_guest - handle NoneType values before passing to ``len`` API (https://github.com/ansible-collections/community.vmware/issues/593).
- deprecated_features:
- - vmware_host_firewall_manager - the creation of new rule with no ``allowed_ip``
- entry in the ``allowed_hosts`` dictionary won't be allowed after 2.0.0 release.
- minor_changes:
- - vmware_cluster_info - added a parent datacenter name of Cluster to the return
- value (https://github.com/ansible-collections/community.vmware/pull/591).
- - vmware_content_deploy_ovf_template - consistent ``eagerZeroedThick`` value
- (https://github.com/ansible-collections/community.vmware/issues/618).
- - vmware_content_deploy_template - add datastore cluster parameter (https://github.com/ansible-collections/community.vmware/issues/397).
- - vmware_content_deploy_template - make resource pool, host, cluster, datastore
- optional parameter and add check (https://github.com/ansible-collections/community.vmware/issues/397).
- - vmware_guest - Define sub-options of hardware and customization in argument_spec
- (https://github.com/ansible-collections/community.vmware/issues/555).
- - vmware_guest_register_operation - supported the check_mode
- - vmware_host_iscsi - added a name(iqn) changing option for iSCSI (https://github.com/ansible-collections/community.vmware/pull/617).
- - vmware_host_lockdown - Support check mode (https://github.com/ansible-collections/community.vmware/pull/633).
- fragments:
- - 111-vmware_dvswitch_loop.yml
- - 397_vmware_content.yml
- - 555-vmware_guest.yml
- - 569_content_library.yml
- - 591-vmware_cluster_info.yml
- - 593_vmware_guest.yml
- - 608_vmware_dvswitch.yml
- - 617-vmware_host_iscsi.yml
- - 618_vmware_content_deploy_ovf_template.yml
- - 623-vmware_datastore_cluster_manager.yml
- - 626-vmware_guest_register_operation.yml
- - 633-vmware_host_lockdown.yml
- - vmware_host_firewall_manager-prepare-all_ip-transition.yaml
- modules:
- - description: Manage VMs and Hosts in DRS group.
- name: vmware_drs_group_manager
- namespace: ''
- - description: Manage VMware vSphere First Class Disks
- name: vmware_first_class_disk
- namespace: ''
- release_date: '2021-02-01'
- 1.8.0:
- changes:
- bugfixes:
- - vcenter_license - fixed a bug that the license doesn't assign in VCSA 7.0u1c
- (https://github.com/ansible-collections/community.vmware/pull/643).
- - vmware - fixed an issue that a port group name doesn't compare correctly in
- the find_network_by_name function (https://github.com/ansible-collections/community.vmware/pull/661).
- - vmware_category - append namespace to associable types (https://github.com/ansible-collections/community.vmware/issues/579).
- - vmware_cluster_ha - fix enabling APD or PDL response (https://github.com/ansible-collections/community.vmware/issues/676).
- - vmware_cluster_info - return VSAN status correctly (https://github.com/ansible-collections/community.vmware/issues/673).
- - vmware_deploy_ovf - fixed an issue that an error message doesn't show when
- not finding a port group name (https://github.com/ansible-collections/community.vmware/pull/661).
- - vmware_dvs_portgroup - fixed the issue that the VLAN configuration isn't compared
- correctly in the module (https://github.com/ansible-collections/community.vmware/pull/638).
- - vmware_dvs_portgroup_find - fixed to decode the special characters URL-encoded
- in the dvs port group name (https://github.com/ansible-collections/community.vmware/pull/648).
- - vmware_dvs_portgroup_info - fixed to decode the special characters URL-encoded
- in the dvs port group name (https://github.com/ansible-collections/community.vmware/pull/648).
- - vmware_guest - add support for ``advanced settings`` in vmware_guest (https://github.com/ansible-collections/community.vmware/issues/602).
- - vmware_guest_register_operation - fixed an issue that an error has been occurring
- when not specifying a datacenter name (https://github.com/ansible-collections/community.vmware/pull/693).
- - vmware_vm_storage_policy - fixed an issue that an error for pyvmomi(SDK) occurred
- when a tag or category doesn't exist (https://github.com/ansible-collections/community.vmware/pull/682).
- minor_changes:
- - Define sub-options of disk in argument_spec (https://github.com/ansible-collections/community.vmware/pull/640).
- - vmware_guest - Remove unnecessary hardware version check (https://github.com/ansible-collections/community.vmware/issues/636).
- - vmware_vcenter_settings - supported the diff mode (https://github.com/ansible-collections/community.vmware/pull/641).
- fragments:
- - 579_vmware_category.yml
- - 602_vmware_guest.yml
- - 636_vmware_guest.yml
- - 638-vmware_dvs_portgroup.yml
- - 640-vmware_guest-disk_suboptions.yml
- - 641-vmware_vcenter_settings.yml
- - 643-vcenter_license.yml
- - 648-vmware_dvs_portgroup_find_info.yml
- - 661-vmware_deploy_ovf_and_vmware.yml
- - 673-vmware_cluster_info.yml
- - 676_vmware_cluster_ha.yml
- - 682-vmware_vm_storage_policy.yml
- - 693-vmware_guest_register_operation.yml
- release_date: '2021-03-05'
- 1.9.0:
- changes:
- bugfixes:
- - vmware - add the default value of parameter resource_pool_name in the find_resource_pool_by_name
- function (https://github.com/ansible-collections/community.vmware/pull/670).
- - vmware_cluster_vsan - fixed a bug that made the module fail when advanced_options
- is not set (https://github.com/ansible-collections/community.vmware/issues/728).
- - vmware_deploy_ovf - fixed an issue that a return value hasn't the instance
- key when the power_on parameter is False (https://github.com/ansible-collections/community.vmware/pull/698).
- - vmware_deploy_ovf - fixed an issue that deploy template in datacenter with
- more than one standalone hosts (https://github.com/ansible-collections/community.vmware/pull/670).
- - vmware_guest - fixed a bug that made the module fail when disk.controller_number
- or disk.unit_number are 0 (https://github.com/ansible-collections/community.vmware/issues/703).
- - vmware_local_user_manager - fixed to require local_user_password when the
- state is present (https://github.com/ansible-collections/community.vmware/pull/724).
- - vmware_vm_inventory - Skip over ghost tags attached to virtual machines (https://github.com/ansible-collections/community.vmware/issues/681).
- deprecated_features:
- - vmware_vmkernel_ip_config - deprecate in favor of vmware_vmkernel (https://github.com/ansible-collections/community.vmware/pull/667).
- minor_changes:
- - vmware_guest_instant_clone - supported esxi_hostname parameter as an alias
- (https://github.com/ansible-collections/community.vmware/pull/745).
- - vmware_resource_pool - Add parent_resource_pool parameter which is mutually
- exclusive with cluster and esxi_hostname (https://github.com/ansible-collections/community.vmware/issues/717)
- - vmware_vm_inventory - add an example of FQDN as hostname (https://github.com/ansible-collections/community.vmware/issues/678).
- - vmware_vm_inventory - skip disconnected VMs.
- security_fixes:
- - vmware_host_iscsi - mark the ``chap_secret`` parameter as ``no_log`` to avoid
- accidental leaking of secrets in logs (https://github.com/ansible-collections/community.vmware/pull/715).
- - vmware_host_iscsi - mark the ``mutual_chap_secret`` parameter as ``no_log``
- to avoid accidental leaking of secrets in logs (https://github.com/ansible-collections/community.vmware/pull/715).
- - vmware_vc_infraprofile_info - mark the ``decryption_key`` parameter as ``no_log``
- to avoid accidental leaking of secrets in logs (https://github.com/ansible-collections/community.vmware/pull/715).
- - vmware_vc_infraprofile_info - mark the ``encryption_key`` parameter as ``no_log``
- to avoid accidental leaking of secrets in logs (https://github.com/ansible-collections/community.vmware/pull/715).
- fragments:
- - 667-vmware_vmkernel_ip_config.yml
- - 670-vmware_deploy_ovf_and_vmware.yml
- - 681_vmware_inventory.yml
- - 698-vmware_deploy_ovf.yml
- - 703-vmware_guest.yml
- - 717-vmware_resource_pool.yml
- - 724-vmware_local_user_manager.yml
- - 728-vmware_cluster_vsan.yml
- - 745-vmware_guest_instant_clone.yml
- - disconnect_inventory.yml
- - no_log_sanity.yml
- - vmware_inventory_example.yml
- modules:
- - description: Instant Clone VM
- name: vmware_guest_instant_clone
- namespace: ''
- - description: Set VM Home and disk(s) storage policy profiles.
- name: vmware_guest_storage_policy
- namespace: ''
- release_date: '2021-04-01'
- 2.0.0:
- changes:
- breaking_changes:
- - The collection now requires at least ansible-core 2.11.0. Ansible 3 and before,
- and ansible-base versions are no longer supported.
- - vmware_cluster_drs - The default for ``enable`` has been changed from ``false``
- to ``true``.
- - vmware_cluster_drs - The parameter alias ``enable_drs`` has been removed,
- use ``enable`` instead.
- - vmware_cluster_ha - The default for ``enable`` has been changed from ``false``
- to ``true``.
- - vmware_cluster_ha - The parameter alias ``enable_ha`` has been removed, use
- ``enable`` instead.
- - vmware_cluster_vsan - The default for ``enable`` has been changed from ``false``
- to ``true``.
- - vmware_cluster_vsan - The parameter alias ``enable_vsan`` has been removed,
- use ``enable`` instead.
- - vmware_guest - Virtualization Based Security has some requirements (``nested_virt``,
- ``secure_boot`` and ``iommu``) that the module silently enabled. They have
- to be enabled explicitly now.
- bugfixes:
- - Various modules and plugins - use vendored version of ``distutils.version``
- included in ansible-core 2.12 if available. This avoids breakage when ``distutils``
- is removed from the standard library of Python 3.12. Note that ansible-core
- 2.11, ansible-base 2.10 and Ansible 2.9 are right now not compatible with
- Python 3.12, hence this fix does not target these ansible-core/-base/2.9 versions.
- - create_nic - add advanced SR-IOV options from the VMware API (PCI dev PF/VF
- backing and guest OS MTU change)
- - vcenter_folder - fixed folders search collision issue (https://github.com/ansible-collections/community.vmware/issues/1112).
- - vmware_guest_network - fix a bug that can crash the module due to an uncaught
- exception (https://github.com/ansible-collections/community.vmware/issues/25).
- minor_changes:
- - vmware_export_ovf - Add a new parameter 'export_with_extraconfig' to support
- export extra config options in ovf (https://github.com/ansible-collections/community.vmware/pull/1161).
- removed_features:
- - vcenter_extension_facts - The deprecated module ``vcenter_extension_facts``
- has been removed, use ``vcenter_extension_info`` instead.
- - vmware_about_facts - The deprecated module ``vmware_about_facts`` has been
- removed, use ``vmware_about_info`` instead.
- - vmware_category_facts - The deprecated module ``vmware_category_facts`` has
- been removed, use ``vmware_category_info`` instead.
- - vmware_cluster - Remove DRS configuration in favour of module ``vmware_cluster_drs``.
- - vmware_cluster - Remove HA configuration in favour of module ``vmware_cluster_ha``.
- - vmware_cluster - Remove VSAN configuration in favour of module ``vmware_cluster_vsan``.
- - vmware_cluster_facts - The deprecated module ``vmware_cluster_facts`` has
- been removed, use ``vmware_cluster_info`` instead.
- - vmware_datastore_facts - The deprecated module ``vmware_datastore_facts``
- has been removed, use ``vmware_datastore_info`` instead.
- - vmware_drs_group_facts - The deprecated module ``vmware_drs_group_facts``
- has been removed, use ``vmware_drs_group_info`` instead.
- - vmware_drs_rule_facts - The deprecated module ``vmware_drs_rule_facts`` has
- been removed, use ``vmware_drs_rule_info`` instead.
- - vmware_dvs_portgroup - The deprecated parameter ``portgroup_type`` has been
- removed, use ``port_binding`` instead.
- - vmware_dvs_portgroup_facts - The deprecated module ``vmware_dvs_portgroup_facts``
- has been removed, use ``vmware_dvs_portgroup_info`` instead.
- - vmware_guest_boot_facts - The deprecated module ``vmware_guest_boot_facts``
- has been removed, use ``vmware_guest_boot_info`` instead.
- - vmware_guest_customization_facts - The deprecated module ``vmware_guest_customization_facts``
- has been removed, use ``vmware_guest_customization_info`` instead.
- - vmware_guest_disk_facts - The deprecated module ``vmware_guest_disk_facts``
- has been removed, use ``vmware_guest_disk_info`` instead.
- - vmware_guest_facts - The deprecated module ``vmware_guest_facts`` has been
- removed, use ``vmware_guest_info`` instead.
- - vmware_guest_snapshot_facts - The deprecated module ``vmware_guest_snapshot_facts``
- has been removed, use ``vmware_guest_snapshot_info`` instead.
- - vmware_host_capability_facts - The deprecated module ``vmware_host_capability_facts``
- has been removed, use ``vmware_host_capability_info`` instead.
- - vmware_host_config_facts - The deprecated module ``vmware_host_config_facts``
- has been removed, use ``vmware_host_config_info`` instead.
- - vmware_host_dns_facts - The deprecated module ``vmware_host_dns_facts`` has
- been removed, use ``vmware_host_dns_info`` instead.
- - vmware_host_feature_facts - The deprecated module ``vmware_host_feature_facts``
- has been removed, use ``vmware_host_feature_info`` instead.
- - vmware_host_firewall_facts - The deprecated module ``vmware_host_firewall_facts``
- has been removed, use ``vmware_host_firewall_info`` instead.
- - vmware_host_ntp_facts - The deprecated module ``vmware_host_ntp_facts`` has
- been removed, use ``vmware_host_ntp_info`` instead.
- - vmware_host_package_facts - The deprecated module ``vmware_host_package_facts``
- has been removed, use ``vmware_host_package_info`` instead.
- - vmware_host_service_facts - The deprecated module ``vmware_host_service_facts``
- has been removed, use ``vmware_host_service_info`` instead.
- - vmware_host_ssl_facts - The deprecated module ``vmware_host_ssl_facts`` has
- been removed, use ``vmware_host_ssl_info`` instead.
- - vmware_host_vmhba_facts - The deprecated module ``vmware_host_vmhba_facts``
- has been removed, use ``vmware_host_vmhba_info`` instead.
- - vmware_host_vmnic_facts - The deprecated module ``vmware_host_vmnic_facts``
- has been removed, use ``vmware_host_vmnic_info`` instead.
- - vmware_local_role_facts - The deprecated module ``vmware_local_role_facts``
- has been removed, use ``vmware_local_role_info`` instead.
- - vmware_local_user_facts - The deprecated module ``vmware_local_user_facts``
- has been removed, use ``vmware_local_user_info`` instead.
- - vmware_portgroup_facts - The deprecated module ``vmware_portgroup_facts``
- has been removed, use ``vmware_portgroup_info`` instead.
- - vmware_resource_pool_facts - The deprecated module ``vmware_resource_pool_facts``
- has been removed, use ``vmware_resource_pool_info`` instead.
- - vmware_tag_facts - The deprecated module ``vmware_tag_facts`` has been removed,
- use ``vmware_tag_info`` instead.
- - vmware_target_canonical_facts - The deprecated module ``vmware_target_canonical_facts``
- has been removed, use ``vmware_target_canonical_info`` instead.
- - vmware_vm_facts - The deprecated module ``vmware_vm_facts`` has been removed,
- use ``vmware_vm_info`` instead.
- - vmware_vmkernel_facts - The deprecated module ``vmware_vmkernel_facts`` has
- been removed, use ``vmware_vmkernel_info`` instead.
- - vmware_vmkernel_ip_config - The deprecated module ``vmware_vmkernel_ip_config``
- has been removed, use ``vmware_vmkernel`` instead.
- - vmware_vswitch_facts - The deprecated module ``vmware_vswitch_facts`` has
- been removed, use ``vmware_vswitch_info`` instead.
- fragments:
- - 1080-add-sr-iov-advanced-options.yml
- - 1112-vcenter_folder.yml
- - 1182_ansible_version.yml
- - 25-vmware_guest_network-catch_taskerror.yml
- - disutils.version.yml
- - remove_deprecated_facts_modules.yml
- - remove_vmware_vmkernel_ip_config.yml
- - vmware_cluster-remove-deprecated-features.yml
- - vmware_cluster_drs-ha-vsan-enable_default.yml
- - vmware_dvs_portgroup-portgroup_type.yml
- - vmware_export_ovf.yml
- - vmware_guest-vbs.yml
- release_date: '2022-01-11'
- 2.1.0:
- changes:
- minor_changes:
- - Remove `version_added` documentation that pre-dates the collection, that is
- refers to Ansible < 2.10 (https://github.com/ansible-collections/community.vmware/pull/1215).
- - vmware_guest_storage_policy - New parameter `controller_number` to support
- multiple SCSI controllers (https://github.com/ansible-collections/community.vmware/issues/1203).
- - vmware_object_role_permission - added VMware DV portgroup object_type for
- setting permissions (https://github.com/ansible-collections/community.vmware/pull/1176)
- - vmware_vm_config_option - Fix the parameter not correct issue when hostname
- is set to ESXi host(https://github.com/ansible-collections/community.vmware/pull/1171).
- - vmware_vm_info - adding fact about ``datastore_url`` to output (https://github.com/ansible-collections/community.vmware/pull/1143).
- fragments:
- - 1176-vmware_dv_portgroup.yml
- - 1203-vmware_guest_storage_policy-controller_number-param.yml
- - datastore_url-added-to-vm_info.yaml
- - remove_pre-collection_version_added.yml
- - vmware_vm_config_option.yml
- modules:
- - description: Manage users of ESXi
- name: vmware_host_user_manager
- namespace: ''
- release_date: '2022-02-16'
- 2.2.0:
- changes:
- bugfixes:
- - vmware_dvs_host - match the list of the host nics in the correct order based
- on the uplink port name in vCenter (https://github.com/ansible-collections/community.vmware/issues/1242).
- - vmware_guest_powerstate - `shutdownguest` power state is not idempotent (https://github.com/ansible-collections/community.vmware/pull/1227).
- minor_changes:
- - vmware_vm_info - Add the posibility to get the configuration informations
- of only one vm by name. (https://github.com/ansible-collections/community.vmware/pull/1241)
- fragments:
- - 1241-vmware_vm_info-add_the_posibility_to_get_only_one_vm_by_name.yaml
- - 1243-vmware-dvs-host-uplink-ordering.yml
- - fix_shutdownguest_state_idempotency.yml
- release_date: '2022-03-28'
- 2.3.0:
- changes:
- bugfixes:
- - vmware_dvs_portgroup - Fix an idempotency issue when `num_ports` is unset
- (https://github.com/ansible-collections/community.vmware/pull/1286).
- - vmware_guest_powerstate - Ignore trailing `/` in `folder` parameter like other
- guest modules do (https://github.com/ansible-collections/community.vmware/issues/1238).
- - vmware_host_powerstate - Do not execute the powerstate changes in check_mode.
- (https://github.com/ansible-collections/community.vmware/pull/1299).
- - vmware_vmotion - Like already define in the examples, allow Storage vMotion
- without defining a resource pool. (https://github.com/ansible-collections/community.vmware/pull/1236).
- major_changes:
- - Drop VCSIM as a test target (https://github.com/ansible-collections/community.vmware/pull/1294).
- minor_changes:
- - vmware_dvs_portgroup - Add the feature to configure ingress and egress traffinc
- shaping and netflow on the dvs portgroup. (https://github.com/ansible-collections/community.vmware/pull/1224)
- - vmware_guest_network - Add parameters `physical_function_backing`, `virtual_function_backing`
- and `allow_guest_os_mtu_change` (https://github.com/ansible-collections/community.vmware/pull/1218)
- fragments:
- - 1224-vmware_dvs_portgroup-ingress_egress_traffic_shaping_and_netflow.yaml
- - 1236-vmware_vmotion-svmotion_without_resourcepool.yml
- - 1238-vmware_guest_powerstate-ignore_trailing_slash_in_folder.yml
- - 1286-vmware_dvs_portgroup-fix_idempotency.yml
- - 1294-remove_vcsim.yml
- - 1299-vnware_host_powerstate-fix_check_mode.yml
- - add-sriov-advanced-options-to-vmware_guest_network.yml
- release_date: '2022-05-02'
- 2.4.0:
- changes:
- minor_changes:
- - vmware_maintenancemode - Add support for check_mode (https://github.com/ansible-collections/community.vmware/pull/1311).
- - vmware_migrate_vmk - Add `migrate_vlan_id` to use for the VMK interface when
- migrating from VDS to VSS (https://github.com/ansible-collections/community.vmware/issues/1297).
- - vmware_vswitch - Add support to manage security, teaming and traffic shaping
- policies on vSwitches. (https://github.com/ansible-collections/community.vmware/pull/1298).
- - vmware_vswitch_info - Add support to return security, teaming and traffic
- shaping policies on vSwitches. (https://github.com/ansible-collections/community.vmware/pull/1309).
- fragments:
- - 1297-vmware_migrate_vmk-add_vlan.yml
- - 1298-vmware_vswitch-add_network_policy_support.yml
- - 1309-vmware_vswitch_info-add_network_policy_support.yml
- - 1311-vmware_maintenancemode-check_mode.yml
- release_date: '2022-05-08'
- 2.5.0:
- changes:
- minor_changes:
- - vmware_vm_info - Add the feature to get the output of allocated storage, cpu
- und memory. (https://github.com/ansible-collections/community.vmware/pull/1283)
- fragments:
- - 1283-vmware_vm_info-allocaded_storag_cpu_memory_output.yaml
- modules:
- - description: Modify vGPU video card profile of the specified virtual machine
- in the given vCenter infrastructure
- name: vmware_guest_vgpu
- namespace: ''
- release_date: '2022-05-23'
- 2.6.0:
- changes:
- bugfixes:
- - vmware_cfg_backup - Fix a bug that failed the module when port 80 is blocked
- (https://github.com/ansible-collections/community.vmware/issues/1270).
- - vmware_host_facts - Fix a bug that crashes the module when a host is disconnected
- (https://github.com/ansible-collections/vmware/issues/184).
- - vmware_host_vmnic_info - Fix a bug that crashes the module when a host is
- disconnected (https://github.com/ansible-collections/community.vmware/pull/1337).
- minor_changes:
- - vmware_vmotion - Add the feature to use cluster and datastore cluster (storage
- pods) to define where the vmotion shold go. (https://github.com/ansible-collections/community.vmware/pull/1240)
- fragments:
- - 1240-vmware_vmotion-add_cluster_storage_cluster.yaml
- - 1270-vmware_cfg_backup-failed_to_write_backup_file.yaml
- - 1337_vmware_host_vmnic_info-fix_disconnected.yml
- - 184_vmware_host_facts.yml
- release_date: '2022-06-04'
- 2.7.0:
- changes:
- bugfixes:
- - vmware_content_deploy_ovf_template - Fixed a bug that ignored `resource_pool`
- in some cases. (https://github.com/ansible-collections/community.vmware/issues/1290).
- - vmware_content_deploy_template - Fixed a bug that ignored `resource_pool`
- in some cases. (https://github.com/ansible-collections/community.vmware/issues/1290).
- - vmware_guest_disk - Ignore datastores in maintenance mode (https://github.com/ansible-collections/community.vmware/pull/1321).
- - vmware_guest_instant_clone - Support FQPN in the folder parameter.
- - vmware_guest_network - Fix a typo in the code for SR-IOV NICs (https://github.com/ansible-collections/community.vmware/issues/1317).
- - vmware_guest_network - Fix an `AttributeError` when using SR-IOV NICs (https://github.com/ansible-collections/community.vmware/issues/1318).
- minor_changes:
- - vmware_dvswitch.py - Add Netflow Settings. (https://github.com/ansible-collections/community.vmware/pull/1352)
- - vmware_dvswitch_nioc.py - Add backupNfc and nvmetcp to the resources. (https://github.com/ansible-collections/community.vmware/pull/1351)
- - vmware_guest_disk - Add a new disk type to support add/reconfigure/remove
- vPMem disk (https://github.com/ansible-collections/community.vmware/pull/1382).
- - vmware_host_passthrough - Support the PCI id in the devices parameter(https://github.com/ansible-collections/community.vmware/pull/1365).
- - vmware_object_role_permission.py - Add StoragePod to the list of object_types.
- (https://github.com/ansible-collections/community.vmware/pull/1338)
- - vmware_object_role_permission_info.py - Add StoragePod and DistributedVirtalPortgroup
- to the list of object_types. (https://github.com/ansible-collections/community.vmware/pull/1338)
- fragments:
- - 1317-vmware_guest_network_typo.yml
- - 1318-vmware_guest_network-attribute_error.yml
- - 1321-vmware_vm_info-allocaded_storag_cpu_memory_output.yaml
- - 1338-vmware_object_role_permission-and-vmware_object_role_permission_info.yaml
- - 1351-vmaware_dvswitch_nioc.yaml
- - 1352-vmaware_dvswitch.yaml
- - 1354-vmware_guest_instant_clone.yml
- - 1362.yml
- - 1365-vmware_host_passthrough.yml
- - 1382-vmware_guest_disk.yml
- release_date: '2022-07-08'
- 2.8.0:
- changes:
- bugfixes:
- - vmware_cfg_backup - Fix a possible urlopen error when connecting directly
- to an ESXi host (https://github.com/ansible-collections/community.vmware/issues/1383).
- - vmware_guest - Fix no fail attribute issue (https://github.com/ansible-collections/community.vmware/issues/1401).
- - vmware_vm_info - Fix 'NoneType' object has no attribute 'datastoreUrl' for
- inaccessible VMs (https://github.com/ansible-collections/community.vmware/issues/1407).
- minor_changes:
- - vmware_cfg_backup - Improve error message (https://github.com/ansible-collections/community.vmware/pull/1388).
- - vmware_dvs_portgroup - Fix a `spec.numPorts is None` issue when the `num_ports`
- parameter isn't set (https://github.com/ansible-collections/community.vmware/pull/1419).
- - vmware_guest_sendkey - Add CTRL_X binding support (https://github.com/ansible-collections/community.vmware/pull/1376).
- - vmware_host_vmnic_info - add CDP information to output when applicable (https://github.com/ansible-collections/community.vmware/pull/1418).
- fragments:
- - 1376-vmware_guest_sendkey-add-ctrl_x-support.yaml
- - 1388-vmware_cfg_backup-improve_error_msg.yml
- - 1392-proposed_fixes_for_backup_behavior_1383.yml
- - 1402-vmware_guest_change_to_fail_json.yml
- - 1407-vmware_vm_info-inaccessible_vm.yml
- - 1418_vmware_host_vmnic_info.yml
- - 1419-vmware_dvs_portgroup-problem_with_spec_numPorts_is_none_solved.yaml
- release_date: '2022-08-16'
- 2.9.0:
- changes:
- bugfixes:
- - vmware_cfg_backup - Fix a bug that failed the restore when port 80 is blocked
- (https://github.com/ansible-collections/community.vmware/issues/1440).
- - vmware_vswitch - Fix broken logic of `failback` parameter (https://github.com/ansible-collections/community.vmware/issues/1431).
- minor_changes:
- - vmware_cluster_ha - Add APD settings (https://github.com/ansible-collections/community.vmware/pull/1420).
- - vmware_content_library_info - Add Subscribed Libraries (https://github.com/ansible-collections/community.vmware/issues/1430).
- - vmware_drs_group_manager - Improve error handling (https://github.com/ansible-collections/community.vmware/pull/1448).
- fragments:
- - 1420-vmware_cluster_ha-add_apd_settings.yaml
- - 1430-vmware_content_library_info-add_subscribed_libraries.yaml
- - 1431-vmware_vswitch-fix_failback.yml
- - 1440-vmware_cfg_backup-fails-to-restore-port-80-blocked.yaml
- - 1448-vmware_drs_group_manager-error_msg.yml
- release_date: '2022-09-06'
- 2.9.1:
- changes:
- bugfixes:
- - 2.9.0 wasn't released correctly, some changes are missing from the package.
- Releasing 2.9.1 to fix this.
- fragments:
- - 2.9.1-fix-release.yml
- release_date: '2022-09-07'
- 3.0.0:
- changes:
- breaking_changes:
- - Removed support for ansible-core version < 2.13.0.
- - vmware_dvs_portgroup - Add a new sub-option `inherited` to the `in_traffic_shaping`
- parameter. This means you can keep the setting as-is by not defining the parameter,
- but also that you have to define the setting as not `inherited` if you want
- to override it at the PG level (https://github.com/ansible-collections/community.vmware/pull/1483).
- - vmware_dvs_portgroup - Add a new sub-option `inherited` to the `out_traffic_shaping`
- parameter. This means you can keep the setting as-is by not defining the parameter,
- but also that you have to define the setting as not `inherited` if you want
- to override it at the PG level (https://github.com/ansible-collections/community.vmware/pull/1483).
- - vmware_dvs_portgroup - Change the type of `net_flow` to string to allow setting
- it implicitly to inherited or to keep the value as-is. This means you can
- keep the setting as-is by not defining the parameter, but also that while
- `true` or `no` still work, `True` or `Off` (uppercase) won't (https://github.com/ansible-collections/community.vmware/pull/1483).
- - vmware_dvs_portgroup - Remove support for vSphere API less than 6.7.
- - vmware_dvs_portgroup - Remove the default for `network_policy` and add a new
- sub-option `inherited`. This means you can keep the setting as-is by not defining
- the parameter, but also that you have to define the setting as not `inherited`
- if you want to override it at the PG level (https://github.com/ansible-collections/community.vmware/pull/1483).
- - vmware_dvs_portgroup_info - Remove support for vSphere API less than 6.7.
- - vmware_dvswitch - Remove support for vSphere API less than 6.7.
- - vmware_dvswitch_uplink_pg - Remove support for vSphere API less than 6.7.
- - vmware_guest_boot_manager - Remove default for ``secure_boot_enabled`` parameter
- (https://github.com/ansible-collections/community.vmware/issues/1461).
- - vmware_vm_config_option - Dict item names in result are changed from strings
- joined with spaces to strings joined with underlines, e.g. `Guest fullname`
- is changed to `guest_fullname` (https://github.com/ansible-collections/community.vmware/issues/1268).
- - vmware_vspan_session - Remove support for vSphere API less than 6.7.
- bugfixes:
- - vmware_dvs_portgroup - Fix update of NetFlow Setting (https://github.com/ansible-collections/community.vmware/pull/1443).
- - vmware_tag_manager - Fix idempotency for state `set` (https://github.com/ansible-collections/community.vmware/issues/1265).
- minor_changes:
- - vmware_guest_disk - Adding `iolimit` modifications of an existing disk without
- changing size (https://github.com/ansible-collections/community.vmware/pull/1466).
- removed_features:
- - vca_fw - The deprecated module ``vca_fw`` has been removed.
- - vca_nat - The deprecated module ``vca_nat`` has been removed.
- - vca_vapp - The deprecated module ``vca_vapp`` has been removed.
- - vmware_dns_config - The deprecated module ``vmware_dns_config`` has been removed,
- you can use ``vmware_host_dns`` instead.
- - vmware_guest_network - The deprecated parameter ``networks`` has been removed,
- use loops to handle multiple interfaces (https://github.com/ansible-collections/community.vmware/pull/1459).
- - vmware_guest_vnc - The deprecated module ``vmware_guest_vnc`` has been removed.
- The VNC support has been dropped with vSphere 7 and later (https://github.com/ansible-collections/community.vmware/pull/1454).
- - vmware_host_firewall_manager - The module doesn't accept a list for ``allowed_hosts``
- anymore, use a dict instead. Additionally, ``all_ip`` is now a required sub-option
- of ``allowed_hosts`` (https://github.com/ansible-collections/community.vmware/pull/1463).
- - vsphere_copy - The deprecated parameters ``host`` and ``login`` have been
- removed. Use ``hostname`` and ``username`` instead (https://github.com/ansible-collections/community.vmware/pull/1456).
- fragments:
- - 1195-vmware_guest_network-remove_networks.yml
- - 1196-vmware_host_firewall_manager-remove_deprecated_stuff.yml
- - 1196-vsphere_copy-remove_deprecated_parameters.yml
- - 1257-vmware_guest_boot_manager-remove_secure_boot_default.yml
- - 1265-vmware_tag_manager-set_idempotency.yml
- - 1268-vmware_vm_config_option-change_result.yml
- - 1443-vmware_dvs_portgroup-update_netflow_not_work.yaml
- - 1466-vmware_guest_disk-change_iolimit_without_size.yml
- - 1483-vmware_dvs_portgroup.yml
- - 3.0.0-required_ansible_version.yml
- - remove_deprecated_dns_config_module.yml
- - remove_deprecated_vca_modules.yml
- - remove_deprecated_vmware_guest_vnc_module.yml
- - vmware_dvs_portgroup-securityPolicy.yml
- - vmware_dvs_portgroup_info-securityPolicy.yml
- - vmware_dvswitch-securityPolicy.yml
- - vmware_dvswitch_uplink_pg-securityPolicyOverrideAllowed.yml
- - vmware_vspan_session-securityPolicy.yml
- modules:
- - description: Configure Datastores
- name: vmware_datastore
- namespace: ''
- release_date: '2022-10-10'
- 3.1.0:
- changes:
- bugfixes:
- - vmware_guest_file_operation - Add a new parameter for timeout(https://github.com/ansible-collections/community.vmware/pull/1513).
- - vmware_tag_manager - Fix a performance issue during tag processing (https://github.com/ansible-collections/community.vmware/issues/1503).
- - vmware_tag_manager - Fix an issue that causes a failure when changing a single
- cardinal tag category (https://github.com/ansible-collections/community.vmware/issues/1501).
- minor_changes:
- - vmware_dvs_portgroup - Add deprecaded securityPolicyOverrideAllowed because
- without it make problems if securityPolicyOverrideAllowed and macManagementOverrideAllowed
- has not the same value (https://github.com/ansible-collections/community.vmware/pull/1508)
- - vmware_guest - Adding `script_text` parameter to execute scripts in Linux
- guests (https://github.com/ansible-collections/community.vmware/pull/1485).
- - vmware_host_lockdown - Add the ability to enable ``strict`` lockdown mode
- (https://github.com/ansible-collections/community.vmware/pull/1514).
- - vmware_host_lockdown - Add two new choices for ``state``, ``disabled`` and
- ``normal``, to replace ``absent`` and ``present``. Please note that ``absent``
- and ``present`` will be removed in the next major release (https://github.com/ansible-collections/community.vmware/pull/1514).
- - vmware_host_lockdown - Replace deprecated vSphere API calls (https://github.com/ansible-collections/community.vmware/pull/1514).
- fragments:
- - 1323-vmware_guest_file_operation.yml
- - 1485-vmware_guest_add_script_text.yml
- - 1501-vmware_tag_manager-Fix_failure_when_changing_single_cardinal_tag_category.yml
- - 1503-vmware_tag_manager-fix_performance_issue_during_tag_processing.yml
- - 1508-vmware_dvs_portgroup.yaml
- - 1514-vmware_host_lockdown-remove-deprecated-api-calls.yml
- modules:
- - description: Manage Lockdown Mode Exception Users
- name: vmware_host_lockdown_exceptions
- namespace: ''
- release_date: '2022-10-31'
- 3.2.0:
- changes:
- bugfixes:
- - vmware_dvs_portgroup - Fix an issue when deleting portgroups (https://github.com/ansible-collections/community.vmware/issues/1522).
- - vmware_guest_instant_clone - Fix an issue with pyVmomi 8.0.0.1 (https://github.com/ansible-collections/community.vmware/issues/1555).
- - vmware_host_lockdown - Fix issue `'VmwareLockdownManager' object has no attribute
- 'warn'` (https://github.com/ansible-collections/community.vmware/pull/1540).
- - vmware_object_custom_attributes_info - Fixed an issue that has occurred an
- error if a custom attribute is the global type(https://github.com/ansible-collections/community.vmware/pull/1541).
- - vmware_portgroup_info - Fix an issue that can fail the module after manually
- updating a portgroup through vCenter (https://github.com/ansible-collections/community.vmware/issues/1544).
- minor_changes:
- - vmware_guest - Add sub-option to configure virtual performance counters (https://github.com/ansible-collections/community.vmware/issues/1511).
- - vmware_guest - Adding sub-options to configure CPU and memory shares (https://github.com/ansible-collections/community.vmware/issues/356).
- - vmware_guest_boot_manager - Add a new parameter boot_hdd_name to specify the
- boot disk name(https://github.com/ansible-collections/community.vmware/pull/1543).
- - vmware_guest_custom_attributes - Improve the code quality and added the return
- value for diff(https://github.com/ansible-collections/community.vmware/pull/1532).
- - vmware_vm_info - Adding resource pool of the VM to result (https://github.com/ansible-collections/community.vmware/pull/1551).
- fragments:
- - 1511-vmware_guest-vpmc.yml
- - 1511-vmware_vm_info.yml
- - 1522-vmware_dvs_portgroup.yml
- - 1532-vmware_guest_custom_attributes.yml
- - 1539-vmware_guest_shares.yml
- - 1540-vmware_host_lockdown.yml
- - 1541-vmware_object_custom_attributes_info.yml
- - 1543-vmware_guest_boot_manager.yml
- - 1544-vmware_portgroup_info.yml
- - 1555-vmware_guest_instant_clone-pyvmomi_8_0_0_1.yml
- modules:
- - description: Manage custom attributes definitions
- name: vmware_custom_attribute
- namespace: ''
- - description: Manage custom attributes from VMware for the given vSphere object
- name: vmware_custom_attribute_manager
- namespace: ''
- release_date: '2022-12-01'
- 3.3.0:
- changes:
- bugfixes:
- - vmware_cluster_dpm - Fix an issue that the slider and the values of the host_power_action_rate
- works invertet in the vCenter
- - vmware_cluster_drs - Fix drs_vmotion_rate so that the value corresponds to
- the vCenter UI. Previously, choosing 1 / 2 configured a migration threshold
- of 5 / 4 and vice versa (https://github.com/ansible-collections/community.vmware/pull/1542).
- - vmware_guest - Fix check mode (https://github.com/ansible-collections/community.vmware/issues/1272).
- - vmware_host_lockdown_exceptions - Avoid setting exception users to what they
- already are (https://github.com/ansible-collections/community.vmware/pull/1585).
- - vmware_tools - Fix an issue with pyVmomi 8.0.0.1 (https://github.com/ansible-collections/community.vmware/issues/1578).
- minor_changes:
- - vmware_cluster_drs - Add predictive DRS Setting (https://github.com/ansible-collections/community.vmware/pull/1542).
- - vmware_guest_network - Add PVRDMA network adapter type (https://github.com/ansible-collections/community.vmware/pull/1579).
- fragments:
- - 1272-vmware_guest-check_mode.yml
- - 1542-vmware_cluster_drs.yaml
- - 1556-vmware_cluster_dpm.yml
- - 1578-vmware_tools-pyvmomi_8_0_0_1.yml
- - 1579-vmware_guest_network.yml
- - 1585-vmware_host_lockdown_exceptions-unnecessary_task.yml
- modules:
- - description: Gather information about vGPU profiles of the specified virtual
- machine in the given vCenter infrastructure
- name: vmware_guest_vgpu_info
- namespace: ''
- release_date: '2023-01-20'
- 3.4.0:
- changes:
- bugfixes:
- - scenario guides - Fix broken references (https://github.com/ansible-collections/community.vmware/issues/1610).
- - various - Fix new pylint issues (https://github.com/ansible-collections/community.vmware/pull/1637).
- - vmware_cluster_info - Fix pylint issues (https://github.com/ansible-collections/community.vmware/issues/1618).
- - vmware_dvswitch - Fix pylint issues (https://github.com/ansible-collections/community.vmware/issues/1618).
- - vmware_dvswitch_lacp - Fix pylint issues (https://github.com/ansible-collections/community.vmware/issues/1618).
- - vmware_dvswitch_uplink_pg - Fix pylint issues (https://github.com/ansible-collections/community.vmware/issues/1618).
- - vmware_guest_custom_attributes - Fixes assigning attributes to new VMs (https://github.com/ansible-collections/community.vmware/issues/1606).
- - vmware_guest_disk - Fix wrong key in the documentation of the return values
- (https://github.com/ansible-collections/community.vmware/issues/1615)
- - vmware_object_rename - Add missing quotation mark to error message (https://github.com/ansible-collections/community.vmware/issues/1633)
- - vmware_portgroup - Fix pylint issues (https://github.com/ansible-collections/community.vmware/issues/1618).
- - vmware_vcenter_settings - Fix pylint issues (https://github.com/ansible-collections/community.vmware/issues/1618).
- - vmware_vcenter_statistics - Fix pylint issues (https://github.com/ansible-collections/community.vmware/issues/1618).
- minor_changes:
- - vmware_guest_disk - Add support for IDE disk add, remove or reconfigure, and
- change to gather same VM disk info as in vmware_guest_disk_info (https://github.com/ansible-collections/community.vmware/issues/1428).
- - vmware_guest_disk - Extend return value documentation for vmware_guest_disk
- (https://github.com/ansible-collections/community.vmware/pull/1641)
- - vmware_guest_disk_info - Move gather VM disk info function to vm_device_helper.py
- (https://github.com/ansible-collections/community.vmware/issues/1617)
- - vmware_vmotion - New parameter timeout in order to allow vmotions running
- longer than 1 hour (https://github.com/ansible-collections/community.vmware/pulls/1629).
- fragments:
- - 1606-vmware_guest_custom_attributes.yml
- - 1610-scenario_guides.yml
- - 1615-wrong_key_for_return_value.yml
- - 1616-vmware_guest_disk.yml
- - 1618_pylint.yml
- - 1629-vmware_vmotion.yml
- - 1633-missing_quotation_mark.yml
- - 1637-pylint-issues.yml
- - 1641_extend_result_docs_guest_disk
- release_date: '2023-02-25'
- 3.5.0:
- changes:
- bugfixes:
- - vmware_cross_vc_clone - Fix SSL Thumbprint validation to ignore if destination_vcenter_validate_certs
- is false (https://github.com/ansible-collections/community.vmware/issues/1433).
- - vmware_guest - Fixes adding new NVDIMM device issue by connecting to ESXi
- host (https://github.com/ansible-collections/community.vmware/issues/1644).
- - vmware_guest_cross_vc_clone - Fix vim.fault.NotAuthenticated issue (https://github.com/ansible-collections/community.vmware/issues/1223).
- - vmware_guest_cross_vc_clone - New parameter timeout in order to allow clone
- running longer than 1 hour
- - vmware_tag - Fix a performance issue during tag processing (https://github.com/ansible-collections/community.vmware/issues/1603).
- major_changes:
- - Use true/false (lowercase) for boolean values in documentation and examples
- (https://github.com/ansible-collections/community.vmware/issues/1660).
- minor_changes:
- - vmware_migrate_vmk - Improve error handling (https://github.com/ansible-collections/community.vmware/issues/1118).
- - vmware_tag - Allow to use category names for tag management (https://github.com/ansible-collections/community.vmware/issues/1614).
- - vmware_tag_manager - Improve performance of tag attachments and detachments
- (https://github.com/ansible-collections/community.vmware/issues/1603).
- - vmware_tools - ansible_vmware_guest_uuid added for easier use of vmware_tools
- connection plugin with vmware_vm_inventory plugin
- - vmware_vm_info - Add several parameters to skip discovering some information
- (https://github.com/ansible-collections/community.vmware/issues/1682)
- fragments:
- - 1118-vmware_migrate_vmk.yml
- - 1223-cross_vc_clone_timeout.yml
- - 1603-fix_tagging_performance_issue.yml
- - 1614-allow_to_use_category_names_for_tag_management.yml
- - 1647-uuid_vmware_tools_connections.yml
- - 1653-cross_vc_clone_ssl_thumbprint.yml
- - 1657-vmware_guest.yml
- - 1660_truthy.yml
- - 1682_vmware_vm_info
- modules:
- - description: Manages the vSAN Hardware Compatibility List (HCL) database
- name: vmware_vsan_hcl_db
- namespace: ''
- release_date: '2023-03-26'
- 3.6.0:
- changes:
- bugfixes:
- - vmware_guest - Fixed issue where custom attributes were not getting set on
- VM creation (https://github.com/ansible-collections/community.vmware/pull/1713)
- - vmware_vsan_health_info - Fix return value (https://github.com/ansible-collections/community.vmware/pull/1706).
- fragments:
- - 1706-vmware_vsan_health_info.yml
- - 1713-vmware_guest-custom_attributes_on_create.yaml
- modules:
- - description: Silence vSAN health checks
- name: vsan_health_silent_checks
- namespace: ''
- release_date: '2023-05-12'
- 3.7.0:
- changes:
- bugfixes:
- - Add missing modules to runtime.yml (https://github.com/ansible-collections/community.vmware/pull/1764).
- - vmware_vm_info - Add missing show_folder parameter (https://github.com/ansible-collections/community.vmware/issues/1709).
- minor_changes:
- - vmware_cluster_drs_recommendations - Add the Module to apply the drs recommendations
- (https://github.com/ansible-collections/community.vmware/pull/1736)
- - vmware_guest_serial_port - add support for proxyURI parameter to enable use
- of a virtual serial port concentrator (https://github.com/ansible-collections/community.vmware/issues/1742)
- fragments:
- - 1710_vmware_vm_info.yaml
- - 1736-vmware_cluster_drs_recommendations.yaml
- - 1742-vmware_guest_serial_port-vspc.yml
- - 1764_runtime.yaml
- modules:
- - description: Apply DRS Recommendations
- name: vmware_cluster_drs_recommendations
- namespace: ''
- - description: Uploads the vSAN Release Catalog
- name: vmware_vsan_release_catalog
- namespace: ''
- release_date: '2023-06-09'
+ - Removed module util `version` (https://github.com/ansible-collections/community.vmware/issues/1639).
+ - vmware_guest - removed specifying CDROM configuration as a dict, instead use
+ a list (https://github.com/ansible-collections/community.vmware/issues/1472).
+ - vmware_host_lockdown - removed deprecated states `absent` and `present` (https://github.com/ansible-collections/community.vmware/issues/1517).
+ - vmware_rest_client - removed deprecated method `get_tag_by_category()` (https://github.com/ansible-collections/community.vmware/issues/1898).
+ fragments:
+ - 1472-vmware_guest.yml
+ - 1516-vmware_dvs_host.yml
+ - 1517_vmware_host_lockdown.yml
+ - 1639.yml
+ - 1761_vmware_vm_info.yml
+ - 1771-semantic_markup.yml
+ - 1799_configure_snmp_on_esxii_hosts_via_vcenter.yaml
+ - 1847_vmware_guest_snapshot.yml
+ - 1853.yml
+ - 1855_vmware_dsv_portgroup_info.yml
+ - 1872-vmware_host_acceptance.yml
+ - 1898-vmware_rest_client.yml
+ - 20231026-remove_module_docs.yml
+ - 4.0.0-required_ansible_version.yml
+ - 802-vmware_deploy_ovf.yml
+ - issue_1772.yml
+ release_date: '2023-10-31'
+ 4.0.1:
+ changes:
+ bugfixes:
+ - vmware_vm_info - Fix an AttributeError when gathering network information
+ (https://github.com/ansible-collections/community.vmware/pull/1919).
+ fragments:
+ - 1919-vmware_vm_info.yml
+ release_date: '2023-11-28'
+ 4.1.0:
+ changes:
+ bugfixes:
+ - Fix InsecureRequestWarning for modules based on the VmwareRestClient module
+ util when setting ``validate_certs`` to ``False`` (https://github.com/ansible-collections/community.vmware/pull/1969).
+ - module_utils/vmware.py - remove ssl.wrap_socet() function. Replaced for code
+ based on ssl.get_server_certificate (https://github.com/ansible-collections/community.vmware/issues/1930).
+ - vmware_guest - Fix failure of vm reconfiguration with enabled virt_based_security
+ (https://github.com/ansible-collections/community.vmware/pull/1848).
+ minor_changes:
+ - vmware_guest - Add IPv6 support for VM network interfaces (https://github.com/ansible-collections/community.vmware/pull/1937).
+ - vmware_guest_sendkey - Add Windows key (https://github.com/ansible-collections/community.vmware/issues/1959).
+ - vmware_guest_tools_upgrade - Add parameter `installer_options` to pass command
+ line options to the installer to modify the installation procedure for tools
+ (https://github.com/ansible-collections/community.vmware/pull/1059).
+ fragments:
+ - 1059-vmware_guest_tools_upgrade.yml
+ - 1848-fix-vm-reconfiguration-with-enabled-vbs.yml
+ - 1930-fix_ssl_deprecation_function.yml
+ - 1937-vmware_guest.yml
+ - 1959-vmware_guest_sendkey.yml
+ - 1969-InsecureRequestWarning.yml
+ release_date: '2024-01-25'
+ 4.2.0:
+ changes:
+ minor_changes:
+ - Add standard function vmware_argument_spec() from module_utils for using default
+ env fallback function. https://github.com/ansible-collections/community.vmware/issues/1977
+ - vmware_first_class_disk_info - Add a module to gather informations about first
+ class disks. (https://github.com/ansible-collections/community.vmware/pull/1996).
+ (https://github.com/ansible-collections/community.vmware/issues/1988).
+ - vmware_host_facts - Add the possibility to get the related datacenter. (https://github.com/ansible-collections/community.vmware/pull/1994).
+ - vmware_vm_inventory - Add parameter `subproperties` (https://github.com/ansible-collections/community.vmware/pull/1972).
+ - vmware_vmkernel - Add the function to set the enable_backup_nfc setting (https://github.com/ansible-collections/community.vmware/pull/1978)
+ - vsphere_copy - Add parameter to tell vsphere_copy which diskformat is being
+ uploaded (https://github.com/ansible-collections/community.vmware/pull/1995).
+ fragments:
+ - 1972-vm_inventory_subproperties.yml
+ - 1977-vsphere_file_add_env_fallback.yml
+ - 1978-vmware_vmkernel.yaml
+ - 1994-vmware-host-facts.yml
+ - 1995-vsphere_copy.yml
+ - 1996 - vmware_first_class_disk_info.yml
+ release_date: '2024-02-24'
diff --git a/ansible_collections/community/vmware/changelogs/config.yaml b/ansible_collections/community/vmware/changelogs/config.yaml
index a12afeb8d..e24227abd 100644
--- a/ansible_collections/community/vmware/changelogs/config.yaml
+++ b/ansible_collections/community/vmware/changelogs/config.yaml
@@ -2,7 +2,7 @@ changelog_filename_template: ../CHANGELOG.rst
changelog_filename_version_depth: 0
changes_file: changelog.yaml
changes_format: combined
-keep_fragments: true
+keep_fragments: false
mention_ancestor: true
new_plugins_after_name: removed_features
notesdir: fragments
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vcenter_domain_user_group_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vcenter_domain_user_group_info_module.rst
deleted file mode 100644
index d331b0208..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vcenter_domain_user_group_info_module.rst
+++ /dev/null
@@ -1,390 +0,0 @@
-.. _community.vmware.vcenter_domain_user_group_info_module:
-
-
-***********************************************
-community.vmware.vcenter_domain_user_group_info
-***********************************************
-
-**Gather user or group information of a domain**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to gather information about user or group of a domain.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>belongs_to_group</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>If a group existing, returned contains only users or groups that directly belong to the specified group.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>belongs_to_user</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>If a user existing, returned contains only groups that directly contain the specified user.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>domain</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">"vsphere.local"</div>
- </td>
- <td>
- <div>The <em>domain</em> to be specified searching.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>exact_match</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>If <em>exact_match</em> is <code>true</code>, it indicates the <em>search_string</em> passed should match a user or group name exactly.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>find_groups</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>If <em>find_groups</em> is <code>true</code>, domain groups will be included in the result.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>find_users</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>If <em>find_users</em> is <code>true</code>, domain users will be included in the result.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>search_string</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The <em>search_string</em> is a string to be specified searching.</div>
- <div>Specify the domain user or group name to be searched.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Gather all domain user and group of vsphere.local
- community.vmware.vcenter_domain_user_group_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- validate_certs: false
- domain: vsphere.local
- search_string: ''
- register: gather_all_domain_user_group_result
-
- - name: Gather all domain user and group included the administrator string
- community.vmware.vcenter_domain_user_group_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- validate_certs: false
- domain: vsphere.local
- search_string: administrator
- register: gather_domain_user_group_result
-
- - name: Gather all domain user of vsphere.local
- community.vmware.vcenter_domain_user_group_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- validate_certs: false
- domain: vsphere.local
- search_string: ''
- find_users: true
- find_groups: false
- register: gather_all_domain_user_result
-
- - name: Gather administrator user by exact match condition
- community.vmware.vcenter_domain_user_group_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- validate_certs: false
- domain: vsphere.local
- search_string: "vsphere.local\\administrator"
- exact_match: true
- register: gather_administrator_user_exact_match_result
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>domain_user_groups</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- </div>
- </td>
- <td>success</td>
- <td>
- <div>list of domain user and group information</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">[
- {
- &quot;fullName&quot;: &quot;Administrator vsphere.local&quot;,
- &quot;group&quot;: false,
- &quot;principal&quot;: &quot;Administrator&quot;
- }
- ]</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- sky-joker (@sky-joker)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vcenter_extension_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vcenter_extension_info_module.rst
deleted file mode 100644
index 0a8cb670b..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vcenter_extension_info_module.rst
+++ /dev/null
@@ -1,229 +0,0 @@
-.. _community.vmware.vcenter_extension_info_module:
-
-
-***************************************
-community.vmware.vcenter_extension_info
-***************************************
-
-**Gather info vCenter extensions**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to gather information about vCenter extension.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Gather info about vCenter Extensions
- community.vmware.vcenter_extension_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- register: ext_info
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>extension_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- </div>
- </td>
- <td>success</td>
- <td>
- <div>List of extensions</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">[{&#x27;extension_company&#x27;: &#x27;VMware, Inc.&#x27;, &#x27;extension_key&#x27;: &#x27;com.vmware.vim.ls&#x27;, &#x27;extension_label&#x27;: &#x27;License Services&#x27;, &#x27;extension_last_heartbeat_time&#x27;: &#x27;2018-09-03T09:36:18.003768+00:00&#x27;, &#x27;extension_subject_name&#x27;: &#x27;&#x27;, &#x27;extension_summary&#x27;: &#x27;Provides various license services&#x27;, &#x27;extension_type&#x27;: &#x27;&#x27;, &#x27;extension_version&#x27;: &#x27;5.0&#x27;}, {&#x27;extension_company&#x27;: &#x27;VMware Inc.&#x27;, &#x27;extension_key&#x27;: &#x27;com.vmware.vim.sms&#x27;, &#x27;extension_label&#x27;: &#x27;VMware vCenter Storage Monitoring Service&#x27;, &#x27;extension_last_heartbeat_time&#x27;: &#x27;2018-09-03T09:36:18.005730+00:00&#x27;, &#x27;extension_subject_name&#x27;: &#x27;&#x27;, &#x27;extension_summary&#x27;: &#x27;Storage Monitoring and Reporting&#x27;, &#x27;extension_type&#x27;: &#x27;&#x27;, &#x27;extension_version&#x27;: &#x27;5.5&#x27;}]</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vcenter_extension_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vcenter_extension_module.rst
deleted file mode 100644
index df807ddc0..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vcenter_extension_module.rst
+++ /dev/null
@@ -1,441 +0,0 @@
-.. _community.vmware.vcenter_extension_module:
-
-
-**********************************
-community.vmware.vcenter_extension
-**********************************
-
-**Register/deregister vCenter Extensions**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to register/deregister vCenter Extensions.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>client_type</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">"vsphere-client-serenity"</div>
- </td>
- <td>
- <div>Required for <code>state=present</code>. Type of client the extension is (win32, .net, linux, etc.).</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>company</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Required for <code>state=present</code>. The name of the company that makes the extension.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>description</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Required for <code>state=present</code>. A short description of the extension.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>email</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Required for <code>state=present</code>. Administrator email to use for extension.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>extension_key</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The extension key of the extension to install or uninstall.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Required for <code>state=present</code>. The name of the extension you are installing.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>server_type</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">"vsphere-client-serenity"</div>
- </td>
- <td>
- <div>Required for <code>state=present</code>. Type of server being used to install the extension (SOAP, REST, HTTP, etc.).</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>ssl_thumbprint</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Required for <code>state=present</code>. SSL thumbprint of the extension hosting server.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>absent</li>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Add or remove vCenter Extension.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>url</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Required for <code>state=present</code>. Link to server hosting extension zip file to install.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>version</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The version of the extension you are installing or uninstalling.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>visible</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Show the extension in solution manager inside vCenter.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Register vCenter Extension
- community.vmware.vcenter_extension:
- hostname: "{{ groups['vcsa'][0] }}"
- username: "{{ vcenter_username }}"
- password: "{{ site_password }}"
- extension_key: "{{ extension_key }}"
- version: "1.0"
- company: "Acme"
- name: "Acme Extension"
- description: "acme management"
- email: "user@example.com"
- url: "https://10.0.0.1/ACME-vSphere-web-plugin-1.0.zip"
- ssl_thumbprint: "{{ ssl_thumbprint }}"
- state: present
- delegate_to: localhost
- register: register_extension
-
- - name: Deregister vCenter Extension
- community.vmware.vcenter_extension:
- hostname: "{{ groups['vcsa'][0] }}"
- username: "{{ vcenter_username }}"
- password: "{{ site_password }}"
- extension_key: "{{ extension_key }}"
- version: "1.0"
- state: absent
- delegate_to: localhost
- register: deregister_extension
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>result</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>information about performed operation</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">&#x27;com.acme.Extension&#x27; installed.</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Michael Tipton (@castawayegr)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vcenter_folder_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vcenter_folder_module.rst
deleted file mode 100644
index e06b8db15..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vcenter_folder_module.rst
+++ /dev/null
@@ -1,405 +0,0 @@
-.. _community.vmware.vcenter_folder_module:
-
-
-*******************************
-community.vmware.vcenter_folder
-*******************************
-
-**Manage folders on given datacenter**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to create, delete, move and rename folder on then given datacenter.
-- This module is only supported for vCenter.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the datacenter.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: datacenter_name</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>folder_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of folder to be managed.</div>
- <div>This is case sensitive parameter.</div>
- <div>Folder name should be under 80 characters. This is a VMware restriction.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>folder_type</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>datastore</li>
- <li>host</li>
- <li>network</li>
- <li><div style="color: blue"><b>vm</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>This is type of folder.</div>
- <div>If set to <code>vm</code>, then &#x27;VM and Template Folder&#x27; is created under datacenter.</div>
- <div>If set to <code>host</code>, then &#x27;Host and Cluster Folder&#x27; is created under datacenter.</div>
- <div>If set to <code>datastore</code>, then &#x27;Storage Folder&#x27; is created under datacenter.</div>
- <div>If set to <code>network</code>, then &#x27;Network Folder&#x27; is created under datacenter.</div>
- <div>This parameter is required, if <code>state</code> is set to <code>present</code> and parent_folder is absent.</div>
- <div>This option is ignored, if <code>parent_folder</code> is set.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>parent_folder</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the parent folder under which new folder needs to be created.</div>
- <div>This is case sensitive parameter.</div>
- <div>If user wants to create a folder under &#x27;/DC0/vm/vm_folder&#x27;, this value will be &#x27;vm_folder&#x27;.</div>
- <div>If user wants to create a folder under &#x27;/DC0/vm/folder1/folder2&#x27;, this value will be &#x27;folder1/folder2&#x27;.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>State of folder.</div>
- <div>If set to <code>present</code> without parent folder parameter, then folder with <code>folder_type</code> is created.</div>
- <div>If set to <code>present</code> with parent folder parameter, then folder in created under parent folder. <code>folder_type</code> is ignored.</div>
- <div>If set to <code>absent</code>, then folder is unregistered and destroyed.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Create a VM folder on given datacenter
- community.vmware.vcenter_folder:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter_name: datacenter_name
- folder_name: sample_vm_folder
- folder_type: vm
- state: present
- register: vm_folder_creation_result
- delegate_to: localhost
-
- - name: Create a datastore folder on given datacenter
- community.vmware.vcenter_folder:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter_name: datacenter_name
- folder_name: sample_datastore_folder
- folder_type: datastore
- state: present
- register: datastore_folder_creation_result
- delegate_to: localhost
-
- - name: Create a sub folder under VM folder on given datacenter
- community.vmware.vcenter_folder:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter_name: datacenter_name
- folder_name: sample_sub_folder
- parent_folder: vm_folder
- state: present
- register: sub_folder_creation_result
- delegate_to: localhost
-
- - name: Delete a VM folder on given datacenter
- community.vmware.vcenter_folder:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter_name: datacenter_name
- folder_name: sample_vm_folder
- folder_type: vm
- state: absent
- register: vm_folder_deletion_result
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="2">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>result</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">complex</span>
- </div>
- </td>
- <td>On success</td>
- <td>
- <div>The detail about the new folder</div>
- <br/>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder">&nbsp;</td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>msg</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td></td>
- <td>
- <div>string stating about result</div>
- <br/>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder">&nbsp;</td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>path</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td></td>
- <td>
- <div>the full path of the new folder</div>
- <br/>
- </td>
- </tr>
-
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
-- Christian Kotte (@ckotte) <christian.kotte@gmx.de>
-- Jan Meerkamp (@meerkampdvv)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vcenter_license_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vcenter_license_module.rst
deleted file mode 100644
index 839ce07c4..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vcenter_license_module.rst
+++ /dev/null
@@ -1,361 +0,0 @@
-.. _community.vmware.vcenter_license_module:
-
-
-********************************
-community.vmware.vcenter_license
-********************************
-
-**Manage VMware vCenter license keys**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- Add and delete vCenter, ESXi server license keys.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the cluster to apply vSAN license.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The datacenter name to use for the operation.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname of the ESXi server to which the specified license will be assigned.</div>
- <div>This parameter is optional.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable supported added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>labels</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">{"source": "ansible"}</div>
- </td>
- <td>
- <div>The optional labels of the license key to manage in vSphere vCenter.</div>
- <div>This is dictionary with key/value pair.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>license</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The license key to manage in vSphere vCenter.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable supported added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable supported added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>absent</li>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Whether to add (<code>present</code>) or remove (<code>absent</code>) the license key.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable supported added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable supported added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - This module will also auto-assign the current vCenter to the license key if the product matches the license key, and vCenter us currently assigned an evaluation license only.
- - The evaluation license (00000-00000-00000-00000-00000) is not listed when unused.
- - If ``esxi_hostname`` is specified, then will assign the ``license`` key to the ESXi host.
- - If ``esxi_hostname`` is not specified, then will just register the ``license`` key to vCenter inventory without assigning it to an ESXi host.
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Add a new vCenter license
- community.vmware.vcenter_license:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- license: f600d-21ae3-5592b-249e0-cc341
- state: present
- delegate_to: localhost
-
- - name: Remove an (unused) vCenter license
- community.vmware.vcenter_license:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- license: f600d-21ae3-5592b-249e0-cc341
- state: absent
- delegate_to: localhost
-
- - name: Add ESXi license and assign to the ESXi host
- community.vmware.vcenter_license:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- license: f600d-21ae3-5592b-249e0-dd502
- state: present
- delegate_to: localhost
-
- - name: Add vSAN license and assign to the given cluster
- community.vmware.vcenter_license:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter: '{{ datacenter_name }}'
- cluster_name: '{{ cluster_name }}'
- license: f600d-21ae3-5592b-249e0-dd502
- state: present
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>licenses</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>list of license keys after module executed</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">[&#x27;f600d-21ae3-5592b-249e0-cc341&#x27;, &#x27;143cc-0e942-b2955-3ea12-d006f&#x27;]</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Dag Wieers (@dagwieers)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vcenter_standard_key_provider_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vcenter_standard_key_provider_module.rst
deleted file mode 100644
index 0b63ece27..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vcenter_standard_key_provider_module.rst
+++ /dev/null
@@ -1,549 +0,0 @@
-.. _community.vmware.vcenter_standard_key_provider_module:
-
-
-**********************************************
-community.vmware.vcenter_standard_key_provider
-**********************************************
-
-**Add, reconfigure or remove Standard Key Provider on vCenter server**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module is used for adding, reconfiguring or removing Standard Key Provider on vCenter server. Refer to VMware docs for more information: `Standard Key Provider <https://docs.vmware.com/en/VMware-vSphere/7.0/com.vmware.vsphere.security.doc/GUID-6DB1E745-9624-43EA-847C-DD2F767CB94B.html>`_
-
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="2">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>kms_info</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">[]</div>
- </td>
- <td>
- <div>The information of an external key server (KMS).</div>
- <div><code>kms_name</code>, <code>kms_ip</code> are required when adding a Standard Key Provider.</div>
- <div>If <code>kms_port</code> is not specified, the default port 5696 will be used.</div>
- <div><code>kms_ip</code>, <code>kms_port</code> can be reconfigured for an existing KMS with name <code>kms_name</code>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>kms_ip</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>IP address of the external KMS.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>kms_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the KMS to be configured.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>kms_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the external KMS.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>remove_kms</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Remove the configured KMS with name <code>kms_name</code> from the KMIP cluster.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>kms_password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Password to authenticate to the KMS.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>kms_username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Username to authenticate to the KMS.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>make_kms_trust_vc</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>After adding the Standard Key Provider to the vCenter Server, you can establish a trusted connection, the exact process depends on the certificates that the key provider accepts, and on your company policy.</div>
- <div>Three methods implemented here, (1) upload client certificate and private key through <code>upload_client_cert</code> and <code>upload_client_key</code> parameters, (2) generate, update, download vCenter self signed certificate through <code>download_self_signed_cert</code> parameter, (3) download generated Certificate Signing Request(CSR) through <code>download_client_csr</code> parameter, send it to KMS then upload the KMS signed CSR through <code>upload_kms_signed_client_csr</code> parameter.</div>
- <div>This is not set to be mandatory, if not set, please go to vCenter to setup trust connection with KMS manually.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>download_client_csr</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">path</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The absolute path on local machine for keeping vCenter generated CSR.</div>
- <div>Then upload the KMS signed CSR using <code>upload_kms_signed_client_csr</code> to vCenter.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>download_self_signed_cert</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">path</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The absolute path on local machine for keeping vCenter generated self signed client cert.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>upload_client_cert</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">path</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The absolute file path of client certificate.</div>
- <div>Request a certificate and private key from the KMS vendor. The files are X509 files in PEM format.</div>
- <div>The certificate might be already trusted by the KMS server.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>upload_client_key</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">path</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The absolute file path of client private key to be uploaded together with <code>upload_client_cert</code>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>upload_kms_signed_client_csr</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">path</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The absolute file path of KMS signed CSR downloaded from <code>download_client_csr</code>.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>mark_default</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Set specified Key Provider with name <code>name</code> as the default Key Provider.</div>
- <div>If new added Key Provider is the only key provider in vCenter, then will mark it as default after adding.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the Key Provider to be added, reconfigured or removed from vCenter.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the proxy server.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_server</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of the proxy server to connect to KMS.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>If set to <code>absent</code>, the named Key Provider will be removed from vCenter.</div>
- <div>If set to <code>present</code>, the named existing Key Provider will be reconfigured or new Key Provider will be added.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Add a new Standard Key Provider with client certificate and private key
- community.vmware.vcenter_standard_key_provider:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- name: 'test_standard_kp'
- state: 'present'
- mark_default: true
- kms_info:
- - kms_name: test_kms_1
- kms_ip: 192.168.1.10
- make_kms_trust_vc:
- upload_client_cert: "/tmp/test_cert.pem"
- upload_client_key: "/tmp/test_cert_key.pem"
- register: add_skp_result
-
- - name: Remove the KMS from the key provider cluster
- community.vmware.vcenter_standard_key_provider:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- name: 'test_standard_kp'
- state: 'present'
- kms_info:
- - kms_name: test_kms_1
- remove_kms: true
- register: remove_kms_result
-
- - name: Remove the Standard Key Provider
- community.vmware.vcenter_standard_key_provider:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- name: 'test_standard_kp'
- state: 'absent'
- register: remove_kp_result
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>key_provider_clusters</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>the Key Provider cluster info</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">[{&#x27;has_backup&#x27;: None, &#x27;key_id&#x27;: None, &#x27;key_provide_id&#x27;: &#x27;test_standard&#x27;, &#x27;management_type&#x27;: None, &#x27;servers&#x27;: [{&#x27;address&#x27;: &#x27;192.168.1.10&#x27;, &#x27;name&#x27;: &#x27;test_kms&#x27;, &#x27;port&#x27;: 5696, &#x27;protocol&#x27;: &#x27;&#x27;, &#x27;proxy&#x27;: &#x27;&#x27;, &#x27;proxy_port&#x27;: None, &#x27;user_name&#x27;: &#x27;&#x27;}], &#x27;tpm_required&#x27;: None, &#x27;use_as_default&#x27;: True}]</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Diane Wang (@Tomorrow9) <dianew@vmware.com>
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_about_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_about_info_module.rst
deleted file mode 100644
index 575032f68..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_about_info_module.rst
+++ /dev/null
@@ -1,237 +0,0 @@
-.. _community.vmware.vmware_about_info_module:
-
-
-**********************************
-community.vmware.vmware_about_info
-**********************************
-
-**Provides information about VMware server to which user is connecting to**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to gather information about VMware server to which user is trying to connect.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Provide information about vCenter
- community.vmware.vmware_about_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- delegate_to: localhost
- register: vcenter_about_info
-
- - name: Provide information about a standalone ESXi server
- community.vmware.vmware_about_info:
- hostname: '{{ esxi_hostname }}'
- username: '{{ esxi_username }}'
- password: '{{ esxi_password }}'
- delegate_to: localhost
- register: esxi_about_info
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>about_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>success</td>
- <td>
- <div>dict about VMware server</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;api_type&#x27;: &#x27;VirtualCenter&#x27;, &#x27;api_version&#x27;: &#x27;6.5&#x27;, &#x27;build&#x27;: &#x27;5973321&#x27;, &#x27;instance_uuid&#x27;: &#x27;dbed6e0c-bd88-4ef6-b594-21283e1c677f&#x27;, &#x27;license_product_name&#x27;: &#x27;VMware VirtualCenter Server&#x27;, &#x27;license_product_version&#x27;: &#x27;6.0&#x27;, &#x27;locale_build&#x27;: &#x27;000&#x27;, &#x27;locale_version&#x27;: &#x27;INTL&#x27;, &#x27;os_type&#x27;: &#x27;darwin-amd64&#x27;, &#x27;product_full_name&#x27;: &#x27;VMware vCenter Server 6.5.0 build-5973321&#x27;, &#x27;product_line_id&#x27;: &#x27;vpx&#x27;, &#x27;product_name&#x27;: &#x27;VMware vCenter Server (govmomi simulator)&#x27;, &#x27;vendor&#x27;: &#x27;VMware, Inc.&#x27;, &#x27;version&#x27;: &#x27;6.5.0&#x27;}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_category_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_category_info_module.rst
deleted file mode 100644
index 6ec0d3f44..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_category_info_module.rst
+++ /dev/null
@@ -1,259 +0,0 @@
-.. _community.vmware.vmware_category_info_module:
-
-
-*************************************
-community.vmware.vmware_category_info
-*************************************
-
-**Gather info about VMware tag categories**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to gather information about VMware tag categories.
-- Tag feature is introduced in vSphere 6 version, so this module is not supported in earlier versions of vSphere.
-- All variables and VMware object names are case sensitive.
-
-
-
-Requirements
-------------
-The below requirements are needed on the host that executes this module.
-
-- vSphere Automation SDK
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>protocol</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>http</li>
- <li><div style="color: blue"><b>https</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>The connection to protocol.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid.</div>
- <div>Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Gather info about tag categories
- community.vmware.vmware_category_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- delegate_to: localhost
- register: all_tag_category_info
-
- - name: Gather category id from given tag category
- community.vmware.vmware_category_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- delegate_to: localhost
- register: tag_category_results
-
- - set_fact:
- category_id: "{{ item.category_id }}"
- loop: "{{ tag_category_results.tag_category_info|json_query(query) }}"
- vars:
- query: "[?category_name==`Category0001`]"
- - debug: var=category_id
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>tag_category_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata of tag categories</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">[{&#x27;category_associable_types&#x27;: [], &#x27;category_cardinality&#x27;: &#x27;MULTIPLE&#x27;, &#x27;category_description&#x27;: &#x27;awesome description&#x27;, &#x27;category_id&#x27;: &#x27;urn:vmomi:InventoryServiceCategory:e785088d-6981-4b1c-9fb8-1100c3e1f742:GLOBAL&#x27;, &#x27;category_name&#x27;: &#x27;Category0001&#x27;, &#x27;category_used_by&#x27;: []}, {&#x27;category_associable_types&#x27;: [&#x27;VirtualMachine&#x27;], &#x27;category_cardinality&#x27;: &#x27;SINGLE&#x27;, &#x27;category_description&#x27;: &#x27;another awesome description&#x27;, &#x27;category_id&#x27;: &#x27;urn:vmomi:InventoryServiceCategory:ae5b7c6c-e622-4671-9b96-76e93adb70f2:GLOBAL&#x27;, &#x27;category_name&#x27;: &#x27;template_tag&#x27;, &#x27;category_used_by&#x27;: []}]</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_category_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_category_module.rst
deleted file mode 100644
index 72cb068bc..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_category_module.rst
+++ /dev/null
@@ -1,413 +0,0 @@
-.. _community.vmware.vmware_category_module:
-
-
-********************************
-community.vmware.vmware_category
-********************************
-
-**Manage VMware categories**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to create / delete / update VMware categories.
-- Tag feature is introduced in vSphere 6 version, so this module is not supported in the earlier versions of vSphere.
-- All variables and VMware object names are case sensitive.
-
-
-
-Requirements
-------------
-The below requirements are needed on the host that executes this module.
-
-- vSphere Automation SDK
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>associable_object_types</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>All objects</li>
- <li>Cluster</li>
- <li>Content Library</li>
- <li>Datacenter</li>
- <li>Datastore</li>
- <li>Datastore Cluster</li>
- <li>Distributed Port Group</li>
- <li>Distributed Switch</li>
- <li>Folder</li>
- <li>Host</li>
- <li>Library item</li>
- <li>Network</li>
- <li>Host Network</li>
- <li>Opaque Network</li>
- <li>Resource Pool</li>
- <li>vApp</li>
- <li>Virtual Machine</li>
- </ul>
- </td>
- <td>
- <div>List of object types that can be associated with the given category.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>category_cardinality</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>multiple</b>&nbsp;&larr;</div></li>
- <li>single</li>
- </ul>
- </td>
- <td>
- <div>The category cardinality.</div>
- <div>This parameter is ignored, when updating existing category.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>category_description</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">""</div>
- </td>
- <td>
- <div>The category description.</div>
- <div>This is required only if <code>state</code> is set to <code>present</code>.</div>
- <div>This parameter is ignored, when <code>state</code> is set to <code>absent</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>category_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of category to manage.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>new_category_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The new name for an existing category.</div>
- <div>This value is used while updating an existing category.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>protocol</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>http</li>
- <li><div style="color: blue"><b>https</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>The connection to protocol.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>The state of category.</div>
- <div>If set to <code>present</code> and category does not exists, then category is created.</div>
- <div>If set to <code>present</code> and category exists, then category is updated.</div>
- <div>If set to <code>absent</code> and category exists, then category is deleted.</div>
- <div>If set to <code>absent</code> and category does not exists, no action is taken.</div>
- <div>Process of updating category only allows name, description change.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid.</div>
- <div>Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Create a category
- community.vmware.vmware_category:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- category_name: Sample_Cat_0001
- category_description: Sample Description
- category_cardinality: 'multiple'
- state: present
-
- - name: Rename category
- community.vmware.vmware_category:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- category_name: Sample_Category_0001
- new_category_name: Sample_Category_0002
- state: present
-
- - name: Update category description
- community.vmware.vmware_category:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- category_name: Sample_Category_0001
- category_description: Some fancy description
- state: present
-
- - name: Delete category
- community.vmware.vmware_category:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- category_name: Sample_Category_0002
- state: absent
-
- - name: Create category with 2 associable object types
- community.vmware.vmware_category:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- category_name: 'Sample_Category_0003'
- category_description: 'sample description'
- associable_object_types:
- - Datastore
- - Cluster
- state: present
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>category_results</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>on success</td>
- <td>
- <div>dictionary of category metadata</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;category_id&#x27;: &#x27;urn:vmomi:InventoryServiceCategory:d7120bda-9fa5-4f92-9d71-aa1acff2e5a8:GLOBAL&#x27;, &#x27;msg&#x27;: &#x27;Category NewCat_0001 updated.&#x27;}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_cfg_backup_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_cfg_backup_module.rst
deleted file mode 100644
index a44b42863..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_cfg_backup_module.rst
+++ /dev/null
@@ -1,312 +0,0 @@
-.. _community.vmware.vmware_cfg_backup_module:
-
-
-**********************************
-community.vmware.vmware_cfg_backup
-**********************************
-
-**Backup / Restore / Reset ESXi host configuration**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to perform various operations related to backup, restore and reset of ESXi host configuration.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>dest</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">path</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The destination where the ESXi configuration bundle will be saved. The <em>dest</em> can be a folder or a file.</div>
- <div>If <em>dest</em> is a folder, the backup file will be saved in the folder with the default filename generated from the ESXi server.</div>
- <div>If <em>dest</em> is a file, the backup file will be saved with that filename. The file extension will always be .tgz.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of ESXi server. This is required only if authentication against a vCenter is done.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>src</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">path</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The file containing the ESXi configuration that will be restored.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>saved</li>
- <li>absent</li>
- <li>loaded</li>
- </ul>
- </td>
- <td>
- <div>If <code>saved</code>, the .tgz backup bundle will be saved in <em>dest</em>.</div>
- <div>If <code>absent</code>, the host configuration will be reset to default values.</div>
- <div>If <code>loaded</code>, the backup file in <em>src</em> will be loaded to the ESXi host rewriting the hosts settings.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - Works only for ESXi hosts
- - For configuration load or reset, the host will be switched automatically to maintenance mode.
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Save the ESXi configuration locally by authenticating directly against the ESXi host
- community.vmware.vmware_cfg_backup:
- hostname: '{{ esxi_hostname }}'
- username: '{{ esxi_username }}'
- password: '{{ esxi_password }}'
- state: saved
- dest: /tmp/
- delegate_to: localhost
-
- - name: Save the ESXi configuration locally by authenticating against the vCenter and selecting the ESXi host
- community.vmware.vmware_cfg_backup:
- hostname: '{{ vcenter_hostname }}'
- esxi_hostname: '{{ esxi_hostname }}'
- username: '{{ esxi_username }}'
- password: '{{ esxi_password }}'
- state: saved
- dest: /tmp/
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>dest_file</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>changed</td>
- <td>
- <div>The full path of where the file holding the ESXi configurations was stored</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">/tmp/configBundle-esxi.host.domain.tgz</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Andreas Nafpliotis (@nafpliot-ibm)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_cluster_dpm_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_cluster_dpm_module.rst
deleted file mode 100644
index c3c8c5c6e..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_cluster_dpm_module.rst
+++ /dev/null
@@ -1,296 +0,0 @@
-.. _community.vmware.vmware_cluster_dpm_module:
-
-
-***********************************
-community.vmware.vmware_cluster_dpm
-***********************************
-
-**Manage Distributed Power Management (DPM) on VMware vSphere clusters**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- Manages DPM on VMware vSphere clusters.
-- All values and VMware object names are case sensitive.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the cluster to be managed.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the datacenter.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: datacenter_name</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>default_dpm_behaviour</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>automated</b>&nbsp;&larr;</div></li>
- <li>manual</li>
- </ul>
- </td>
- <td>
- <div>Whether dpm should be automated or manual</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>enable_dpm</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether to enable DPM.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>host_power_action_rate</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>1</li>
- <li>2</li>
- <li><div style="color: blue"><b>3</b>&nbsp;&larr;</div></li>
- <li>4</li>
- <li>5</li>
- </ul>
- </td>
- <td>
- <div>specify host power action rate</div>
- <div>1 is the lowest and 5 the highest</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Enable DPM
- community.vmware.vmware_cluster_dpm:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter_name: datacenter
- cluster_name: cluster
- enable_dpm: true
- default_dpm_behaviour: automated
- host_power_action_rate: 2
- delegate_to: localhost
-
-
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Olivia Luetolf (@olilu)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_cluster_drs_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_cluster_drs_module.rst
deleted file mode 100644
index 01f955017..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_cluster_drs_module.rst
+++ /dev/null
@@ -1,376 +0,0 @@
-.. _community.vmware.vmware_cluster_drs_module:
-
-
-***********************************
-community.vmware.vmware_cluster_drs
-***********************************
-
-**Manage Distributed Resource Scheduler (DRS) on VMware vSphere clusters**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- Manages DRS on VMware vSphere clusters.
-- All values and VMware object names are case sensitive.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>advanced_settings</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">{}</div>
- </td>
- <td>
- <div>A dictionary of advanced DRS settings.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the cluster to be managed.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the datacenter.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: datacenter_name</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>drs_default_vm_behavior</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>fullyAutomated</b>&nbsp;&larr;</div></li>
- <li>manual</li>
- <li>partiallyAutomated</li>
- </ul>
- </td>
- <td>
- <div>Specifies the cluster-wide default DRS behavior for virtual machines.</div>
- <div>If set to <code>partiallyAutomated</code>, vCenter generates recommendations for virtual machine migration and for the placement with a host, then automatically implements placement recommendations at power on.</div>
- <div>If set to <code>manual</code>, then vCenter generates recommendations for virtual machine migration and for the placement with a host, but does not implement the recommendations automatically.</div>
- <div>If set to <code>fullyAutomated</code>, then vCenter automates both the migration of virtual machines and their placement with a host at power on.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>drs_enable_vm_behavior_overrides</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Whether DRS Behavior overrides for individual virtual machines are enabled.</div>
- <div>If set to <code>true</code>, overrides <code>drs_default_vm_behavior</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>drs_vmotion_rate</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>1</li>
- <li>2</li>
- <li><div style="color: blue"><b>3</b>&nbsp;&larr;</div></li>
- <li>4</li>
- <li>5</li>
- </ul>
- </td>
- <td>
- <div>Threshold for generated ClusterRecommendations ranging from 1 (lowest) to 5 (highest).</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>enable</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Whether to enable DRS.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>predictive_drs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 3.3.0</div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>In addition to real-time metrics, DRS will respond to forecasted metrics provided by vRealize Operations Manager.</div>
- <div>You must also configure Predictive DRS in a version of vRealize Operations that supports this feature.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Enable DRS
- community.vmware.vmware_cluster_drs:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter_name: datacenter
- cluster_name: cluster
- enable: true
- delegate_to: localhost
- - name: Enable DRS and distribute a more even number of virtual machines across hosts for availability
- community.vmware.vmware_cluster_drs:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter_name: datacenter
- cluster_name: cluster
- enable: true
- advanced_settings:
- 'TryBalanceVmsPerHost': '1'
- delegate_to: localhost
- - name: Enable DRS and set default VM behavior to partially automated
- community.vmware.vmware_cluster_drs:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter_name: DC0
- cluster_name: "{{ cluster_name }}"
- enable: true
- drs_default_vm_behavior: partiallyAutomated
- delegate_to: localhost
-
-
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Joseph Callen (@jcpowermac)
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_cluster_drs_recommendations_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_cluster_drs_recommendations_module.rst
deleted file mode 100644
index 0c4d8d974..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_cluster_drs_recommendations_module.rst
+++ /dev/null
@@ -1,265 +0,0 @@
-.. _community.vmware.vmware_cluster_drs_recommendations_module:
-
-
-***************************************************
-community.vmware.vmware_cluster_drs_recommendations
-***************************************************
-
-**Apply DRS Recommendations**
-
-
-Version added: 3.7.0
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- Apply DRS Recommendations for Cluster.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the cluster to be managed.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the datacenter.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: datacenter_name</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Apply DRS Recommendations for Cluster
- community.vmware.vmware_cluster:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter_name: datacenter
- cluster_name: cluster
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>result</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>list of the recommendations</div>
- <div>What server moved from which host to which host.</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">[&#x27;server1 move from host1 to host2.&#x27;, &#x27;server2 move from host1 to host2.&#x27;]</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Nina Loser (@Nina2244)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_cluster_ha_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_cluster_ha_module.rst
deleted file mode 100644
index ece53763a..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_cluster_ha_module.rst
+++ /dev/null
@@ -1,699 +0,0 @@
-.. _community.vmware.vmware_cluster_ha_module:
-
-
-**********************************
-community.vmware.vmware_cluster_ha
-**********************************
-
-**Manage High Availability (HA) on VMware vSphere clusters**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- Manages HA configuration on VMware vSphere clusters.
-- All values and VMware object names are case sensitive.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="2">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>advanced_settings</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">{}</div>
- </td>
- <td>
- <div>A dictionary of advanced HA settings.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>apd_delay</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 2.9.0</div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">180</div>
- </td>
- <td>
- <div>The response recovery delay time in sec for storage failures categorized as All Paths Down (APD).</div>
- <div>Only set if <code>apd_response</code> is <code>restartConservative</code> or <code>restartAggressive</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>apd_reaction</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 2.9.0</div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>reset</b>&nbsp;&larr;</div></li>
- <li>none</li>
- </ul>
- </td>
- <td>
- <div>VM response recovery reaction for storage failures categorized as All Paths Down (APD).</div>
- <div>Only set if <code>apd_response</code> is <code>restartConservative</code> or <code>restartAggressive</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>apd_response</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>disabled</li>
- <li><div style="color: blue"><b>warning</b>&nbsp;&larr;</div></li>
- <li>restartConservative</li>
- <li>restartAggressive</li>
- </ul>
- </td>
- <td>
- <div>VM storage protection setting for storage failures categorized as All Paths Down (APD).</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the cluster to be managed.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the datacenter.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: datacenter_name</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>enable</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Whether to enable HA.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>failover_host_admission_control</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Configure dedicated failover hosts.</div>
- <div><code>slot_based_admission_control</code>, <code>reservation_based_admission_control</code> and <code>failover_host_admission_control</code> are mutually exclusive.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>failover_hosts</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>List of dedicated failover hosts.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>ha_host_monitoring</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>enabled</b>&nbsp;&larr;</div></li>
- <li>disabled</li>
- </ul>
- </td>
- <td>
- <div>Whether HA restarts virtual machines after a host fails.</div>
- <div>If set to <code>enabled</code>, HA restarts virtual machines after a host fails.</div>
- <div>If set to <code>disabled</code>, HA does not restart virtual machines after a host fails.</div>
- <div>If <code>enable</code> is set to <code>false</code>, then this value is ignored.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>ha_restart_priority</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>disabled</li>
- <li>high</li>
- <li>low</li>
- <li><div style="color: blue"><b>medium</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Priority HA gives to a virtual machine if sufficient capacity is not available to power on all failed virtual machines.</div>
- <div>Valid only if <em>ha_vm_monitoring</em> is set to either <code>vmAndAppMonitoring</code> or <code>vmMonitoringOnly</code>.</div>
- <div>If set to <code>disabled</code>, then HA is disabled for this virtual machine.</div>
- <div>If set to <code>high</code>, then virtual machine with this priority have a higher chance of powering on after a failure, when there is insufficient capacity on hosts to meet all virtual machine needs.</div>
- <div>If set to <code>medium</code>, then virtual machine with this priority have an intermediate chance of powering on after a failure, when there is insufficient capacity on hosts to meet all virtual machine needs.</div>
- <div>If set to <code>low</code>, then virtual machine with this priority have a lower chance of powering on after a failure, when there is insufficient capacity on hosts to meet all virtual machine needs.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>ha_vm_failure_interval</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">30</div>
- </td>
- <td>
- <div>The number of seconds after which virtual machine is declared as failed if no heartbeat has been received.</div>
- <div>This setting is only valid if <code>ha_vm_monitoring</code> is set to, either <code>vmAndAppMonitoring</code> or <code>vmMonitoringOnly</code>.</div>
- <div>Unit is seconds.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>ha_vm_max_failure_window</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">-1</div>
- </td>
- <td>
- <div>The number of seconds for the window during which up to <code>ha_vm_max_failures</code> resets can occur before automated responses stop.</div>
- <div>Valid only when <em>ha_vm_monitoring</em> is set to either <code>vmAndAppMonitoring</code> or <code>vmMonitoringOnly</code>.</div>
- <div>Unit is seconds.</div>
- <div>Default specifies no failure window.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>ha_vm_max_failures</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">3</div>
- </td>
- <td>
- <div>Maximum number of failures and automated resets allowed during the time that <code>ha_vm_max_failure_window</code> specifies.</div>
- <div>Valid only when <em>ha_vm_monitoring</em> is set to either <code>vmAndAppMonitoring</code> or <code>vmMonitoringOnly</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>ha_vm_min_up_time</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">120</div>
- </td>
- <td>
- <div>The number of seconds for the virtual machine&#x27;s heartbeats to stabilize after the virtual machine has been powered on.</div>
- <div>Valid only when <em>ha_vm_monitoring</em> is set to either <code>vmAndAppMonitoring</code> or <code>vmMonitoringOnly</code>.</div>
- <div>Unit is seconds.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>ha_vm_monitoring</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>vmAndAppMonitoring</li>
- <li>vmMonitoringOnly</li>
- <li><div style="color: blue"><b>vmMonitoringDisabled</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>State of virtual machine health monitoring service.</div>
- <div>If set to <code>vmAndAppMonitoring</code>, HA response to both virtual machine and application heartbeat failure.</div>
- <div>If set to <code>vmMonitoringDisabled</code>, virtual machine health monitoring is disabled.</div>
- <div>If set to <code>vmMonitoringOnly</code>, HA response to virtual machine heartbeat failure.</div>
- <div>If <code>enable</code> is set to <code>false</code>, then this value is ignored.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>host_isolation_response</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>none</b>&nbsp;&larr;</div></li>
- <li>powerOff</li>
- <li>shutdown</li>
- </ul>
- </td>
- <td>
- <div>Indicates whether or VMs should be powered off if a host determines that it is isolated from the rest of the compute resource.</div>
- <div>If set to <code>none</code>, do not power off VMs in the event of a host network isolation.</div>
- <div>If set to <code>powerOff</code>, power off VMs in the event of a host network isolation.</div>
- <div>If set to <code>shutdown</code>, shut down VMs guest operating system in the event of a host network isolation.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>pdl_response</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>disabled</li>
- <li><div style="color: blue"><b>warning</b>&nbsp;&larr;</div></li>
- <li>restartAggressive</li>
- </ul>
- </td>
- <td>
- <div>VM storage protection setting for storage failures categorized as Permenant Device Loss (PDL).</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>reservation_based_admission_control</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Configure reservation based admission control policy.</div>
- <div><code>slot_based_admission_control</code>, <code>reservation_based_admission_control</code> and <code>failover_host_admission_control</code> are mutually exclusive.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>auto_compute_percentages</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>By default, <code>failover_level</code> is used to calculate <code>cpu_failover_resources_percent</code> and <code>memory_failover_resources_percent</code>. If a user wants to override the percentage values, he has to set this field to false.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cpu_failover_resources_percent</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">50</div>
- </td>
- <td>
- <div>Percentage of CPU resources in the cluster to reserve for failover. Ignored if <code>auto_compute_percentages</code> is not set to false.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>failover_level</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Number of host failures that should be tolerated.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>memory_failover_resources_percent</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">50</div>
- </td>
- <td>
- <div>Percentage of memory resources in the cluster to reserve for failover. Ignored if <code>auto_compute_percentages</code> is not set to false.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>slot_based_admission_control</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Configure slot based admission control policy.</div>
- <div><code>slot_based_admission_control</code>, <code>reservation_based_admission_control</code> and <code>failover_host_admission_control</code> are mutually exclusive.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>failover_level</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Number of host failures that should be tolerated.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Enable HA without admission control
- community.vmware.vmware_cluster_ha:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter_name: datacenter
- cluster_name: cluster
- enable: true
- delegate_to: localhost
-
- - name: Enable HA and VM monitoring without admission control
- community.vmware.vmware_cluster_ha:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter_name: DC0
- cluster_name: "{{ cluster_name }}"
- enable: true
- ha_vm_monitoring: vmMonitoringOnly
- delegate_to: localhost
-
- - name: Enable HA with admission control reserving 50% of resources for HA
- community.vmware.vmware_cluster_ha:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter_name: datacenter
- cluster_name: cluster
- enable: true
- reservation_based_admission_control:
- auto_compute_percentages: false
- failover_level: 1
- cpu_failover_resources_percent: 50
- memory_failover_resources_percent: 50
- delegate_to: localhost
-
-
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Joseph Callen (@jcpowermac)
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_cluster_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_cluster_info_module.rst
deleted file mode 100644
index 9c17e24bd..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_cluster_info_module.rst
+++ /dev/null
@@ -1,362 +0,0 @@
-.. _community.vmware.vmware_cluster_info_module:
-
-
-************************************
-community.vmware.vmware_cluster_info
-************************************
-
-**Gather info about clusters available in given vCenter**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to gather information about clusters in VMWare infrastructure.
-- All values and VMware object names are case sensitive.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the cluster.</div>
- <div>If set, information of this cluster will be returned.</div>
- <div>This parameter is required, if <code>datacenter</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Datacenter to search for cluster/s.</div>
- <div>This parameter is required, if <code>cluster_name</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>properties</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Specify the properties to retrieve.</div>
- <div>Example:</div>
- <div>properties: [</div>
- <div>&quot;name&quot;,</div>
- <div>&quot;configuration.dasConfig.enabled&quot;,</div>
- <div>&quot;summary.totalCpu&quot;</div>
- <div>]</div>
- <div>Only valid when <code>schema</code> is <code>vsphere</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>schema</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>summary</b>&nbsp;&larr;</div></li>
- <li>vsphere</li>
- </ul>
- </td>
- <td>
- <div>Specify the output schema desired.</div>
- <div>The &#x27;summary&#x27; output schema is the legacy output from the module.</div>
- <div>The &#x27;vsphere&#x27; output schema is the vSphere API class definition which requires pyvmomi&gt;6.7.1.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>show_tag</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Tags related to cluster are shown if set to <code>true</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Gather cluster info from given datacenter
- community.vmware.vmware_cluster_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter: ha-datacenter
- delegate_to: localhost
- register: cluster_info
-
- - name: Gather info from datacenter about specific cluster
- community.vmware.vmware_cluster_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- cluster_name: DC0_C0
- delegate_to: localhost
- register: cluster_info
-
- - name: Gather info from datacenter about specific cluster with tags
- community.vmware.vmware_cluster_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- cluster_name: DC0_C0
- show_tag: true
- delegate_to: localhost
- register: cluster_info
-
- - name: Gather some info from a cluster using the vSphere API output schema
- vmware_cluster_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- cluster_name: DC0_C0
- schema: vsphere
- properties:
- - name
- - configuration.dasConfig.enabled
- - summary.totalCpu
- delegate_to: localhost
- register: cluster_info
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>clusters</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about the available clusters</div>
- <div>datacenter added in the return values from version 1.6.0</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;DC0_C0&#x27;: {&#x27;datacenter&#x27;: &#x27;DC0&#x27;, &#x27;moid&#x27;: &#x27;domain-c9&#x27;, &#x27;drs_default_vm_behavior&#x27;: None, &#x27;drs_enable_vm_behavior_overrides&#x27;: None, &#x27;drs_vmotion_rate&#x27;: None, &#x27;enable_ha&#x27;: None, &#x27;enabled_drs&#x27;: True, &#x27;enabled_vsan&#x27;: False, &#x27;ha_admission_control_enabled&#x27;: None, &#x27;ha_failover_level&#x27;: None, &#x27;ha_host_monitoring&#x27;: None, &#x27;ha_restart_priority&#x27;: None, &#x27;ha_vm_failure_interval&#x27;: None, &#x27;ha_vm_max_failure_window&#x27;: None, &#x27;ha_vm_max_failures&#x27;: None, &#x27;ha_vm_min_up_time&#x27;: None, &#x27;ha_vm_monitoring&#x27;: None, &#x27;ha_vm_tools_monitoring&#x27;: None, &#x27;vsan_auto_claim_storage&#x27;: False, &#x27;hosts&#x27;: [{&#x27;name&#x27;: &#x27;esxi01.vsphere.local&#x27;, &#x27;folder&#x27;: &#x27;/DC0/host/DC0_C0&#x27;}, {&#x27;name&#x27;: &#x27;esxi02.vsphere.local&#x27;, &#x27;folder&#x27;: &#x27;/DC0/host/DC0_C0&#x27;}, {&#x27;name&#x27;: &#x27;esxi03.vsphere.local&#x27;, &#x27;folder&#x27;: &#x27;/DC0/host/DC0_C0&#x27;}, {&#x27;name&#x27;: &#x27;esxi04.vsphere.local&#x27;, &#x27;folder&#x27;: &#x27;/DC0/host/DC0_C0&#x27;}], &#x27;resource_summary&#x27;: {&#x27;cpuCapacityMHz&#x27;: 4224, &#x27;cpuUsedMHz&#x27;: 87, &#x27;memCapacityMB&#x27;: 6139, &#x27;memUsedMB&#x27;: 1254, &#x27;pMemAvailableMB&#x27;: 0, &#x27;pMemCapacityMB&#x27;: 0, &#x27;storageCapacityMB&#x27;: 33280, &#x27;storageUsedMB&#x27;: 19953}, &#x27;tags&#x27;: [{&#x27;category_id&#x27;: &#x27;urn:vmomi:InventoryServiceCategory:9fbf83de-7903-442e-8004-70fd3940297c:GLOBAL&#x27;, &#x27;category_name&#x27;: &#x27;sample_cluster_cat_0001&#x27;, &#x27;description&#x27;: &#x27;&#x27;, &#x27;id&#x27;: &#x27;urn:vmomi:InventoryServiceTag:93d680db-b3a6-4834-85ad-3e9516e8fee8:GLOBAL&#x27;, &#x27;name&#x27;: &#x27;sample_cluster_tag_0001&#x27;}]}}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
-- Christian Neugum (@digifuchsi)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_cluster_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_cluster_module.rst
deleted file mode 100644
index 4cdf0c4f8..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_cluster_module.rst
+++ /dev/null
@@ -1,275 +0,0 @@
-.. _community.vmware.vmware_cluster_module:
-
-
-*******************************
-community.vmware.vmware_cluster
-*******************************
-
-**Manage VMware vSphere clusters**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- Adds or removes VMware vSphere clusters.
-- To manage DRS, HA and VSAN related configurations, use the new modules vmware_cluster_drs, vmware_cluster_ha and vmware_cluster_vsan.
-- All values and VMware object names are case sensitive.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the cluster to be managed.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the datacenter.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: datacenter_name</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>absent</li>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Create <code>present</code> or remove <code>absent</code> a VMware vSphere cluster.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-See Also
---------
-
-.. seealso::
-
- :ref:`community.vmware.vmware_cluster_drs_module`
- The official documentation on the **community.vmware.vmware_cluster_drs** module.
- :ref:`community.vmware.vmware_cluster_ha_module`
- The official documentation on the **community.vmware.vmware_cluster_ha** module.
- :ref:`community.vmware.vmware_cluster_vsan_module`
- The official documentation on the **community.vmware.vmware_cluster_vsan** module.
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Create Cluster
- community.vmware.vmware_cluster:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter_name: datacenter
- cluster_name: cluster
- delegate_to: localhost
-
- - name: Delete Cluster
- community.vmware.vmware_cluster:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter_name: datacenter
- cluster_name: cluster
- state: absent
- delegate_to: localhost
-
-
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Joseph Callen (@jcpowermac)
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_cluster_vcls_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_cluster_vcls_module.rst
deleted file mode 100644
index 680ad64e9..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_cluster_vcls_module.rst
+++ /dev/null
@@ -1,287 +0,0 @@
-.. _community.vmware.vmware_cluster_vcls_module:
-
-
-************************************
-community.vmware.vmware_cluster_vcls
-************************************
-
-**Override the default vCLS (vSphere Cluster Services) VM disk placement for this cluster.**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- Override the default vCLS VM disk placement for this cluster.
-- Some datastores cannot be selected for vCLS 'Allowed' as they are blocked by solutions as SRM or vSAN maintenance mode where vCLS cannot be configured.
-- All values and VMware object names are case sensitive.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>allowed_datastores</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>List of the allowed Datastores.</div>
- <div>If there is one more in the current List it will be removed.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the cluster to be managed.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the datacenter.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: datacenter_name</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Set Allowed vCLS Datastores
- community.vmware.vmware_cluster_vcls:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter_name: datacenter
- cluster_name: cluster
- allowed_datastores:
- - ds1
- - ds2
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>result</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>information about performed operation</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;result&#x27;: None, &#x27;Added_AllowedDatastores&#x27;: [&#x27;ds2&#x27;], &#x27;Removed_AllowedDatastores&#x27;: [&#x27;ds3&#x27;]}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Joseph Callen (@jcpowermac)
-- Nina Loser (@Nina2244)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_cluster_vsan_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_cluster_vsan_module.rst
deleted file mode 100644
index c723f88cb..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_cluster_vsan_module.rst
+++ /dev/null
@@ -1,415 +0,0 @@
-.. _community.vmware.vmware_cluster_vsan_module:
-
-
-************************************
-community.vmware.vmware_cluster_vsan
-************************************
-
-**Manages virtual storage area network (vSAN) configuration on VMware vSphere clusters**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- Manages vSAN on VMware vSphere clusters.
-- All values and VMware object names are case sensitive.
-
-
-
-Requirements
-------------
-The below requirements are needed on the host that executes this module.
-
-- vSAN Management SDK, which needs to be downloaded from VMware and installed manually.
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="2">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>advanced_options</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Advanced VSAN Options.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>automatic_rebalance</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>If enabled, vSAN automatically rebalances (moves the data among disks) when a capacity disk fullness hits proactive rebalance threshold.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>disable_site_read_locality</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>For vSAN stretched clusters, reads to vSAN objects occur on the site the VM resides on.</div>
- <div>Setting to <code>true</code> will force reads across all mirrors.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>large_cluster_support</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Allow &gt; 32 VSAN hosts per cluster; if this is changed on an existing vSAN cluster, all hosts are required to reboot to apply this change.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>object_repair_timer</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Delay time in minutes for VSAN to wait for the absent component to come back before starting to repair it.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>thin_swap</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>When <code>enabled</code>, swap objects would not reserve 100% space of their size on vSAN datastore.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the cluster to be managed.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the datacenter.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: datacenter_name</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>enable</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Whether to enable vSAN.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vsan_auto_claim_storage</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether the VSAN service is configured to automatically claim local storage on VSAN-enabled hosts in the cluster.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Enable vSAN
- community.vmware.vmware_cluster_vsan:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter_name: datacenter
- cluster_name: cluster
- enable: true
- delegate_to: localhost
-
- - name: Enable vSAN and automatic rebalancing
- community.vmware.vmware_cluster_vsan:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter_name: datacenter
- cluster_name: cluster
- enable: true
- advanced_options:
- automatic_rebalance: true
- delegate_to: localhost
-
- - name: Enable vSAN and claim storage automatically
- community.vmware.vmware_cluster_vsan:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter_name: DC0
- cluster_name: "{{ cluster_name }}"
- enable: true
- vsan_auto_claim_storage: true
- delegate_to: localhost
-
-
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Joseph Callen (@jcpowermac)
-- Abhijeet Kasurde (@Akasurde)
-- Mario Lenz (@mariolenz)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_content_deploy_ovf_template_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_content_deploy_ovf_template_module.rst
deleted file mode 100644
index 7ca26359d..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_content_deploy_ovf_template_module.rst
+++ /dev/null
@@ -1,461 +0,0 @@
-.. _community.vmware.vmware_content_deploy_ovf_template_module:
-
-
-***************************************************
-community.vmware.vmware_content_deploy_ovf_template
-***************************************************
-
-**Deploy Virtual Machine from ovf template stored in content library.**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- Module to deploy virtual machine from ovf template in content library.
-- All variables and VMware object names are case sensitive.
-
-
-
-Requirements
-------------
-The below requirements are needed on the host that executes this module.
-
-- vSphere Automation SDK
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the cluster in datacenter in which to place deployed VM.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the datacenter, where VM to be deployed.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datastore</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the datastore to store deployed VM and disk.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datastore_cluster</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the datastore cluster housing a datastore to store deployed VM and disk.</div>
- <div>If datastore is not specified, the recommended datastore from this cluster will be used.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>folder</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">"vm"</div>
- </td>
- <td>
- <div>Name of the folder in datacenter in which to place deployed VM.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the ESX Host in datacenter in which to place deployed VM. The host has to be a member of the cluster that contains the resource pool.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>library</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the content library from where the template resides.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: content_library, content_library_src</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>log_level</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>debug</li>
- <li>info</li>
- <li><div style="color: blue"><b>normal</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>The level of logging desired in this module.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the VM to be deployed.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: vm_name</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>protocol</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>http</li>
- <li><div style="color: blue"><b>https</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>The connection to protocol.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>resource_pool</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the resourcepool in datacenter in which to place deployed VM.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>storage_provisioning</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>thin</b>&nbsp;&larr;</div></li>
- <li>thick</li>
- <li>eagerZeroedThick</li>
- <li>eagerzeroedthick</li>
- </ul>
- </td>
- <td>
- <div>Default storage provisioning type to use for all sections of type vmw:StorageSection in the OVF descriptor.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>template</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of OVF template from which VM to be deployed.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: ovf, ovf_template, template_src</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid.</div>
- <div>Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Deploy Virtual Machine from OVF template in content library
- community.vmware.vmware_content_deploy_ovf_template:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- ovf_template: rhel_test_template
- datastore: Shared_NFS_Volume
- folder: vm
- datacenter: Sample_DC_1
- name: Sample_VM
- resource_pool: test_rp
- delegate_to: localhost
-
- - name: Deploy Virtual Machine from OVF template in content library with eagerZeroedThick storage
- vmware_content_deploy_ovf_template:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- ovf_template: rhel_test_template
- datastore: Shared_NFS_Volume
- folder: vm
- datacenter: Sample_DC_1
- name: Sample_VM
- resource_pool: test_rp
- storage_provisioning: eagerZeroedThick
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>vm_deploy_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>on success</td>
- <td>
- <div>Virtual machine deployment message and vm_id</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;msg&#x27;: &quot;Deployed Virtual Machine &#x27;Sample_VM&#x27;.&quot;, &#x27;vm_id&#x27;: &#x27;vm-1009&#x27;}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Lev Goncharv (@ultral)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_content_deploy_template_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_content_deploy_template_module.rst
deleted file mode 100644
index 87f2ad237..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_content_deploy_template_module.rst
+++ /dev/null
@@ -1,477 +0,0 @@
-.. _community.vmware.vmware_content_deploy_template_module:
-
-
-***********************************************
-community.vmware.vmware_content_deploy_template
-***********************************************
-
-**Deploy Virtual Machine from template stored in content library.**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- Module to deploy virtual machine from template in content library.
-- Content Library feature is introduced in vSphere 6.0 version.
-- vmtx templates feature is introduced in vSphere 67U1 and APIs for clone template from content library in 67U2.
-- This module does not work with vSphere version older than 67U2.
-- All variables and VMware object names are case sensitive.
-
-
-
-Requirements
-------------
-The below requirements are needed on the host that executes this module.
-
-- vSphere Automation SDK
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the cluster in datacenter in which to place deployed VM.</div>
- <div>Required if <em>resource_pool</em> is not specified.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the datacenter, where VM to be deployed.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datastore</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the datastore to store deployed VM and disk.</div>
- <div>Required if <em>datastore_cluster</em> is not provided.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datastore_cluster</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the datastore cluster to store deployed VM and disk.</div>
- <div>Please make sure Storage DRS is active for recommended datastore from the given datastore cluster.</div>
- <div>If Storage DRS is not enabled, datastore with largest free storage space is selected.</div>
- <div>Required if <em>datastore</em> is not provided.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>folder</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">"vm"</div>
- </td>
- <td>
- <div>Name of the folder in datacenter in which to place deployed VM.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the ESX Host in datacenter in which to place deployed VM.</div>
- <div>The host has to be a member of the cluster that contains the resource pool.</div>
- <div>Required with <em>resource_pool</em> to find resource pool details. This will be used as additional information when there are resource pools with same name.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>library</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the content library from where the template resides.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: content_library, content_library_src</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>log_level</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>debug</li>
- <li>info</li>
- <li><div style="color: blue"><b>normal</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>The level of logging desired in this module.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the VM to be deployed.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: vm_name</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>protocol</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>http</li>
- <li><div style="color: blue"><b>https</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>The connection to protocol.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>resource_pool</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the resource pool in datacenter in which to place deployed VM.</div>
- <div>Required if <em>cluster</em> is not specified.</div>
- <div>For default or non-unique resource pool names, specify <em>host</em> and <em>cluster</em>.</div>
- <div><code>Resources</code> is the default name of resource pool.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>poweredon</li>
- </ul>
- </td>
- <td>
- <div>The state of Virtual Machine deployed from template in content library.</div>
- <div>If set to <code>present</code> and VM does not exists, then VM is created.</div>
- <div>If set to <code>present</code> and VM exists, no action is taken.</div>
- <div>If set to <code>poweredon</code> and VM does not exists, then VM is created with powered on state.</div>
- <div>If set to <code>poweredon</code> and VM exists, no action is taken.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>template</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of template from which VM to be deployed.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: template_src</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid.</div>
- <div>Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Deploy Virtual Machine from template in content library
- community.vmware.vmware_content_deploy_template:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- template: rhel_test_template
- datastore: Shared_NFS_Volume
- folder: vm
- datacenter: Sample_DC_1
- name: Sample_VM
- resource_pool: test_rp
- state: present
- delegate_to: localhost
-
- - name: Deploy Virtual Machine from template in content library with PowerON State
- community.vmware.vmware_content_deploy_template:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- template: rhel_test_template
- content_library: test_content_library
- datastore: Shared_NFS_Volume
- folder: vm
- datacenter: Sample_DC_1
- name: Sample_VM
- resource_pool: test_rp
- state: poweredon
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>vm_deploy_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>on success</td>
- <td>
- <div>Virtual machine deployment message and vm_id</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;msg&#x27;: &quot;Deployed Virtual Machine &#x27;Sample_VM&#x27;.&quot;, &#x27;vm_id&#x27;: &#x27;vm-1009&#x27;}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Pavan Bidkar (@pgbidkar)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_content_library_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_content_library_info_module.rst
deleted file mode 100644
index 6b9dce2c0..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_content_library_info_module.rst
+++ /dev/null
@@ -1,284 +0,0 @@
-.. _community.vmware.vmware_content_library_info_module:
-
-
-********************************************
-community.vmware.vmware_content_library_info
-********************************************
-
-**Gather information about VMWare Content Library**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- Module to list the content libraries.
-- Module to get information about specific content library.
-- Content Library feature is introduced in vSphere 6.0 version, so this module is not supported in the earlier versions of vSphere.
-- All variables and VMware object names are case sensitive.
-
-
-
-Requirements
-------------
-The below requirements are needed on the host that executes this module.
-
-- vSphere Automation SDK
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>library_id</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>content library id for which details needs to be fetched.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>protocol</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>http</li>
- <li><div style="color: blue"><b>https</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>The connection to protocol.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid.</div>
- <div>Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Get List of Content Libraries
- community.vmware.vmware_content_library_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- delegate_to: localhost
-
- - name: Get information about content library
- community.vmware.vmware_content_library_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- library_id: '13b0f060-f4d3-4f84-b61f-0fe1b0c0a5a8'
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>content_lib_details</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- </div>
- </td>
- <td>on success</td>
- <td>
- <div>list of content library metadata</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">[{&#x27;library_creation_time&#x27;: &#x27;2019-07-02T11:50:52.242000&#x27;, &#x27;library_description&#x27;: &#x27;new description&#x27;, &#x27;library_id&#x27;: &#x27;13b0f060-f4d3-4f84-b61f-0fe1b0c0a5a8&#x27;, &#x27;library_name&#x27;: &#x27;demo-local-lib&#x27;, &#x27;library_publish_info&#x27;: {&#x27;authentication_method&#x27;: &#x27;NONE&#x27;, &#x27;persist_json_enabled&#x27;: False, &#x27;publish_url&#x27;: None, &#x27;published&#x27;: False, &#x27;user_name&#x27;: None}, &#x27;library_server_guid&#x27;: &#x27;0fd5813b-aac7-4b92-9fb7-f18f16565613&#x27;, &#x27;library_type&#x27;: &#x27;LOCAL&#x27;, &#x27;library_version&#x27;: &#x27;3&#x27;}]</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>content_libs</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- </div>
- </td>
- <td>on success</td>
- <td>
- <div>list of content libraries</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">[&#x27;ded9c4d5-0dcd-4837-b1d8-af7398511e33&#x27;, &#x27;36b72549-14ed-4b5f-94cb-6213fecacc02&#x27;]</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Pavan Bidkar (@pgbidkar)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_content_library_manager_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_content_library_manager_module.rst
deleted file mode 100644
index 5ccd12cad..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_content_library_manager_module.rst
+++ /dev/null
@@ -1,439 +0,0 @@
-.. _community.vmware.vmware_content_library_manager_module:
-
-
-***********************************************
-community.vmware.vmware_content_library_manager
-***********************************************
-
-**Create, update and delete VMware content library**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- Module to manage VMware content Library
-- Content Library feature is introduced in vSphere 6.0 version, so this module is not supported in the earlier versions of vSphere.
-- All variables and VMware object names are case sensitive.
-
-
-
-Requirements
-------------
-The below requirements are needed on the host that executes this module.
-
-- vSphere Automation SDK
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datastore_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the datastore on which backing content library is created.</div>
- <div>This is required only if <em>state</em> is set to <code>present</code>.</div>
- <div>This parameter is ignored, when <em>state</em> is set to <code>absent</code>.</div>
- <div>Currently only datastore backing creation is supported.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: datastore</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>library_description</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The content library description.</div>
- <div>This is required only if <em>state</em> is set to <code>present</code>.</div>
- <div>This parameter is ignored, when <em>state</em> is set to <code>absent</code>.</div>
- <div>Process of updating content library only allows description change.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>library_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of VMware content library to manage.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>library_type</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>local</b>&nbsp;&larr;</div></li>
- <li>subscribed</li>
- </ul>
- </td>
- <td>
- <div>The content library type.</div>
- <div>This is required only if <em>state</em> is set to <code>present</code>.</div>
- <div>This parameter is ignored, when <em>state</em> is set to <code>absent</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>protocol</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>http</li>
- <li><div style="color: blue"><b>https</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>The connection to protocol.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>ssl_thumbprint</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">""</div>
- </td>
- <td>
- <div>The SHA1 SSL thumbprint of the subscribed content library to subscribe to.</div>
- <div>This is required only if <em>library_type</em> is set to <code>subscribed</code> and the library is https.</div>
- <div>This parameter is ignored, when <em>state</em> is set to <code>absent</code>.</div>
- <div>The information can be extracted using openssl using the following example: <code>echo | openssl s_client -connect test-library.com:443 |&amp; openssl x509 -fingerprint -noout</code></div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>The state of content library.</div>
- <div>If set to <code>present</code> and library does not exists, then content library is created.</div>
- <div>If set to <code>present</code> and library exists, then content library is updated.</div>
- <div>If set to <code>absent</code> and library exists, then content library is deleted.</div>
- <div>If set to <code>absent</code> and library does not exists, no action is taken.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>subscription_url</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">""</div>
- </td>
- <td>
- <div>The url of the content library to subscribe to.</div>
- <div>This is required only if <em>library_type</em> is set to <code>subscribed</code>.</div>
- <div>This parameter is ignored, when <em>state</em> is set to <code>absent</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>update_on_demand</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether to download all content on demand.</div>
- <div>If set to <code>true</code>, all content will be downloaded on demand.</div>
- <div>If set to <code>false</code> content will be downloaded ahead of time.</div>
- <div>This is required only if <em>library_type</em> is set to <code>subscribed</code>.</div>
- <div>This parameter is ignored, when <em>state</em> is set to <code>absent</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid.</div>
- <div>Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Create Local Content Library
- community.vmware.vmware_content_library_manager:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- library_name: test-content-lib
- library_description: 'Library with Datastore Backing'
- library_type: local
- datastore_name: datastore
- state: present
- delegate_to: localhost
-
- - name: Create Subscribed Content Library
- community.vmware.vmware_content_library_manager:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- library_name: test-content-lib
- library_description: 'Subscribed Library with Datastore Backing'
- library_type: subscribed
- datastore_name: datastore
- subscription_url: 'https://library.url'
- ssl_thumbprint: 'aa:bb:cc:dd:ee:ff:gg:hh:ii:jj:kk:ll:mm:nn:oo:pp:qq:rr:ss:tt'
- update_on_demand: true
- state: present
- delegate_to: localhost
-
- - name: Update Content Library
- community.vmware.vmware_content_library_manager:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- library_name: test-content-lib
- library_description: 'Library with Datastore Backing'
- state: present
- delegate_to: localhost
-
- - name: Delete Content Library
- community.vmware.vmware_content_library_manager:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- library_name: test-content-lib
- state: absent
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>content_library_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>on success</td>
- <td>
- <div>library creation success and library_id</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;library_id&#x27;: &#x27;d0b92fa9-7039-4f29-8e9c-0debfcb22b72&#x27;, &#x27;library_description&#x27;: &#x27;Test description&#x27;, &#x27;library_type&#x27;: &#x27;LOCAL&#x27;, &#x27;msg&#x27;: &quot;Content Library &#x27;demo-local-lib-4&#x27; created.&quot;}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Pavan Bidkar (@pgbidkar)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_custom_attribute_manager_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_custom_attribute_manager_module.rst
deleted file mode 100644
index 3a9077229..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_custom_attribute_manager_module.rst
+++ /dev/null
@@ -1,347 +0,0 @@
-.. _community.vmware.vmware_custom_attribute_manager_module:
-
-
-************************************************
-community.vmware.vmware_custom_attribute_manager
-************************************************
-
-**Manage custom attributes from VMware for the given vSphere object**
-
-
-Version added: 3.2.0
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to add, remove and update custom attributes for the given vSphere object.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="2">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>custom_attributes</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=dictionary</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>A list of name and value of custom attributes that needs to be manage.</div>
- <div>Value of custom attribute is not required and will be ignored, if <code>state</code> is set to <code>absent</code>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the attribute.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>value</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">""</div>
- </td>
- <td>
- <div>Value of the attribute.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>object_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the vSphere object to work with.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>object_type</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>Cluster</li>
- <li>Datacenter</li>
- <li>Datastore</li>
- <li>DistributedVirtualPortgroup</li>
- <li>DistributedVirtualSwitch</li>
- <li>Folder</li>
- <li>HostSystem</li>
- <li>ResourcePool</li>
- <li>VirtualMachine</li>
- </ul>
- </td>
- <td>
- <div>Type of the object the custom attribute is associated with.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>If set to <code>present</code>, the custom attribute is set to the given value.</div>
- <div>If set to <code>absent</code>, the custom attribute is cleared. The given value is ignored in this case.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Add virtual machine custom attributes
- community.vmware.vmware_custom_attribute_manager:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- object_name: vm1
- object_type: VirtualMachine
- state: present
- custom_attributes:
- - name: MyAttribute
- value: MyValue
- delegate_to: localhost
-
- - name: Add multiple virtual machine custom attributes
- community.vmware.vmware_custom_attribute_manager:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- object_name: vm1
- object_type: VirtualMachine
- state: present
- custom_attributes:
- - name: MyAttribute
- value: MyValue
- - name: MyAttribute2
- value: MyValue2
- delegate_to: localhost
-
- - name: Remove virtual machine Attribute
- community.vmware.vmware_custom_attribute_manager:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- object_name: vm1
- object_type: VirtualMachine
- state: absent
- custom_attributes:
- - name: MyAttribute
- delegate_to: localhost
- register: attributes
-
-
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Mario Lenz (@mariolenz)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_custom_attribute_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_custom_attribute_module.rst
deleted file mode 100644
index 6cf068807..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_custom_attribute_module.rst
+++ /dev/null
@@ -1,279 +0,0 @@
-.. _community.vmware.vmware_custom_attribute_module:
-
-
-****************************************
-community.vmware.vmware_custom_attribute
-****************************************
-
-**Manage custom attributes definitions**
-
-
-Version added: 3.2.0
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to add and remove custom attributes definitions for various vSphere objects.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>custom_attribute</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the custom attribute.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>object_type</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>Cluster</li>
- <li>Datacenter</li>
- <li>Datastore</li>
- <li>DistributedVirtualPortgroup</li>
- <li>DistributedVirtualSwitch</li>
- <li>Folder</li>
- <li>Global</li>
- <li>HostSystem</li>
- <li>ResourcePool</li>
- <li>VirtualMachine</li>
- </ul>
- </td>
- <td>
- <div>Type of the object the custom attribute is associated with.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>Manage definition of custom attributes.</div>
- <div>If set to <code>present</code> and definition not present, then custom attribute definition is created.</div>
- <div>If set to <code>present</code> and definition is present, then no action taken.</div>
- <div>If set to <code>absent</code> and definition is present, then custom attribute definition is removed.</div>
- <div>If set to <code>absent</code> and definition is absent, then no action taken.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Add VM Custom Attribute Definition
- community.vmware.vmware_custom_attribute:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- state: present
- object_type: VirtualMachine
- custom_attribute: custom_attr_def_1
- delegate_to: localhost
- register: defs
-
- - name: Remove VM Custom Attribute Definition
- community.vmware.vmware_custom_attribute:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- state: absent
- object_type: VirtualMachine
- custom_attribute: custom_attr_def_1
- delegate_to: localhost
- register: defs
-
-
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Mario Lenz (@mariolenz)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_datacenter_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_datacenter_info_module.rst
deleted file mode 100644
index a7503a742..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_datacenter_info_module.rst
+++ /dev/null
@@ -1,336 +0,0 @@
-.. _community.vmware.vmware_datacenter_info_module:
-
-
-***************************************
-community.vmware.vmware_datacenter_info
-***************************************
-
-**Gather information about VMware vSphere Datacenters**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to gather information VMware vSphere Datacenters.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the datacenter to gather information for.</div>
- <div>If not provided, will gather information about all datacenters from the VMware infra.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: datacenter_name</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>properties</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Specify the properties to retrieve.</div>
- <div>If not specified, all properties are retrieved (deeply).</div>
- <div>Results are returned in a structure identical to the vSphere API.</div>
- <div>Example:</div>
- <div>properties: [</div>
- <div>&quot;overallStatus&quot;</div>
- <div>]</div>
- <div>Only valid when <code>schema</code> is <code>vsphere</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>schema</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>summary</b>&nbsp;&larr;</div></li>
- <li>vsphere</li>
- </ul>
- </td>
- <td>
- <div>Specify the output schema desired.</div>
- <div>The &#x27;summary&#x27; output schema is the legacy output from the module.</div>
- <div>The &#x27;vsphere&#x27; output schema is the vSphere API class definition which requires pyvmomi&gt;6.7.1.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>show_tag</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Tags related to Datacenter are shown if set to <code>true</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Gather information about all datacenters
- community.vmware.vmware_datacenter_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- delegate_to: localhost
-
- - name: Gather information about a particular datacenter
- community.vmware.vmware_datacenter_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter: '{{ datacenter_name }}'
- delegate_to: localhost
-
- - name: Gather information about a particular datacenter
- community.vmware.vmware_datacenter_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter: '{{ datacenter_name }}'
- show_tag: true
- delegate_to: localhost
-
- - name: Gather vSphere schema information
- community.vmware.vmware_datacenter_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter: '{{ datacenter_name }}'
- schema: vsphere
- properties:
- - configStatus
- - overallStatus
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>datacenter_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>Information about datacenter</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">[{&#x27;configStatus&#x27;: &#x27;gray&#x27;, &#x27;moid&#x27;: &#x27;datacenter-2&#x27;, &#x27;name&#x27;: &#x27;Asia-Datacenter1&#x27;}]</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_datacenter_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_datacenter_module.rst
deleted file mode 100644
index 535a7d413..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_datacenter_module.rst
+++ /dev/null
@@ -1,244 +0,0 @@
-.. _community.vmware.vmware_datacenter_module:
-
-
-**********************************
-community.vmware.vmware_datacenter
-**********************************
-
-**Manage VMware vSphere Datacenters**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to manage (create, delete) VMware vSphere Datacenters.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the datacenter the cluster will be created in.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>If the datacenter should be present or absent.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Create Datacenter
- community.vmware.vmware_datacenter:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter_name: '{{ datacenter_name }}'
- state: present
- delegate_to: localhost
-
- - name: Delete Datacenter
- community.vmware.vmware_datacenter:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter_name: '{{ datacenter_name }}'
- state: absent
- delegate_to: localhost
- register: datacenter_delete_result
-
-
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Joseph Callen (@jcpowermac)
-- Kamil Szczygiel (@kamsz)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_datastore_cluster_manager_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_datastore_cluster_manager_module.rst
deleted file mode 100644
index f43579cfa..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_datastore_cluster_manager_module.rst
+++ /dev/null
@@ -1,318 +0,0 @@
-.. _community.vmware.vmware_datastore_cluster_manager_module:
-
-
-*************************************************
-community.vmware.vmware_datastore_cluster_manager
-*************************************************
-
-**Manage VMware vSphere datastore cluster's members**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to add datastore in the datastore cluster.
-- All parameters and VMware object values are case sensitive.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the datacenter.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: datacenter</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datastore_cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the datastore cluster.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: datastore_cluster</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datastores</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>A list of datastores to be manage.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>If set to <em>present</em>, datastores specified by <em>datastores</em> will be added to the given datastore cluster.</div>
- <div>If set to <em>absent</em>, datastores specified by <em>datastores</em> will be moved from the given datastore cluster to datstore folder of the parent datacenter.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Add datastore to the given datastore cluster
- community.vmware.vmware_datastore_cluster_manager:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter_name: '{{ datacenter_name }}'
- datastore_cluster_name: '{{ datastore_cluster_name }}'
- datastores:
- - ds_001
- - ds_002
- - ds_003
- state: present
- delegate_to: localhost
-
- - name: Move datastore from the given datastore cluster
- community.vmware.vmware_datastore_cluster_manager:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter_name: '{{ datacenter_name }}'
- datastore_cluster_name: '{{ datastore_cluster_name }}'
- datastores:
- - ds_001
- state: absent
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>datastore_cluster_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>information about datastore cluster</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;changed_datastores&#x27;: [&#x27;ds_171_1&#x27;], &#x27;current_datastores&#x27;: [], &#x27;msg&#x27;: None, &#x27;previous_datastores&#x27;: [&#x27;ds_171_1&#x27;]}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_datastore_cluster_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_datastore_cluster_module.rst
deleted file mode 100644
index 27d9b0c4a..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_datastore_cluster_module.rst
+++ /dev/null
@@ -1,424 +0,0 @@
-.. _community.vmware.vmware_datastore_cluster_module:
-
-
-*****************************************
-community.vmware.vmware_datastore_cluster
-*****************************************
-
-**Manage VMware vSphere datastore clusters**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to add and delete datastore cluster in given VMware environment.
-- All parameters and VMware object values are case sensitive.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>automation_level</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>automated</li>
- <li><div style="color: blue"><b>manual</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Run SDRS automated or manually.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the datacenter.</div>
- <div>You must specify either a <code>datacenter_name</code> or a <code>folder</code>.</div>
- <div>Mutually exclusive with <code>folder</code> parameter.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: datacenter</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datastore_cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the datastore cluster.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>enable_io_loadbalance</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether or not storage DRS takes into account storage I/O workload when making load balancing and initial placement recommendations.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>enable_sdrs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether or not storage DRS is enabled.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>folder</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Destination folder, absolute path to place datastore cluster in.</div>
- <div>The folder should include the datacenter.</div>
- <div>This parameter is case sensitive.</div>
- <div>You must specify either a <code>folder</code> or a <code>datacenter_name</code>.</div>
- <div>Examples:</div>
- <div>folder: /datacenter1/datastore</div>
- <div>folder: datacenter1/datastore</div>
- <div>folder: /datacenter1/datastore/folder1</div>
- <div>folder: datacenter1/datastore/folder1</div>
- <div>folder: /folder1/datacenter1/datastore</div>
- <div>folder: folder1/datacenter1/datastore</div>
- <div>folder: /folder1/datacenter1/datastore/folder2</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>keep_vmdks_together</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Specifies whether or not each VM in this datastore cluster should have its virtual disks on the same datastore by default.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>loadbalance_interval</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">480</div>
- </td>
- <td>
- <div>Specify the interval in minutes that storage DRS runs to load balance among datastores.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>If the datastore cluster should be present or absent.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Create datastore cluster and enable SDRS
- community.vmware.vmware_datastore_cluster:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter_name: '{{ datacenter_name }}'
- datastore_cluster_name: '{{ datastore_cluster_name }}'
- enable_sdrs: true
- state: present
- delegate_to: localhost
-
- - name: Create datastore cluster using folder
- community.vmware.vmware_datastore_cluster:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- folder: '/{{ datacenter_name }}/datastore/ds_folder'
- datastore_cluster_name: '{{ datastore_cluster_name }}'
- state: present
- delegate_to: localhost
-
- - name: Delete datastore cluster
- community.vmware.vmware_datastore_cluster:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter_name: '{{ datacenter_name }}'
- datastore_cluster_name: '{{ datastore_cluster_name }}'
- state: absent
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>result</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>information about datastore cluster operation</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">Datastore cluster &#x27;DSC2&#x27; created successfully.</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_datastore_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_datastore_info_module.rst
deleted file mode 100644
index af37de0da..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_datastore_info_module.rst
+++ /dev/null
@@ -1,414 +0,0 @@
-.. _community.vmware.vmware_datastore_info_module:
-
-
-**************************************
-community.vmware.vmware_datastore_info
-**************************************
-
-**Gather info about datastores available in given vCenter**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to gather information about datastores in VMWare infrastructure.
-- All values and VMware object names are case sensitive.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Cluster to search for datastores.</div>
- <div>If set, information of datastores belonging this clusters will be returned.</div>
- <div>This parameter is required, if <code>datacenter</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Datacenter to search for datastores.</div>
- <div>This parameter is required, if <code>cluster</code> is not supplied.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: datacenter_name</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>gather_nfs_mount_info</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Gather mount information of NFS datastores.</div>
- <div>Disabled per default because this slows down the execution if you have a lot of datastores.</div>
- <div>Only valid when <code>schema</code> is <code>summary</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>gather_vmfs_mount_info</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Gather mount information of VMFS datastores.</div>
- <div>Disabled per default because this slows down the execution if you have a lot of datastores.</div>
- <div>Only valid when <code>schema</code> is <code>summary</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the datastore to match.</div>
- <div>If set, information of specific datastores are returned.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>properties</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Specify the properties to retrieve.</div>
- <div>If not specified, all properties are retrieved (deeply).</div>
- <div>Results are returned in a structure identical to the vsphere API.</div>
- <div>Example:</div>
- <div>properties: [</div>
- <div>&quot;name&quot;,</div>
- <div>&quot;info.vmfs.ssd&quot;,</div>
- <div>&quot;capability.vsanSparseSupported&quot;,</div>
- <div>&quot;overallStatus&quot;</div>
- <div>]</div>
- <div>Only valid when <code>schema</code> is <code>vsphere</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>schema</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>summary</b>&nbsp;&larr;</div></li>
- <li>vsphere</li>
- </ul>
- </td>
- <td>
- <div>Specify the output schema desired.</div>
- <div>The &#x27;summary&#x27; output schema is the legacy output from the module</div>
- <div>The &#x27;vsphere&#x27; output schema is the vSphere API class definition which requires pyvmomi&gt;6.7.1</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>show_tag</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Tags related to Datastore are shown if set to <code>true</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Gather info from standalone ESXi server having datacenter as 'ha-datacenter'
- community.vmware.vmware_datastore_info:
- hostname: '{{ esxi_hostname }}'
- username: '{{ esxi_username }}'
- password: '{{ esxi_password }}'
- datacenter_name: "ha-datacenter"
- delegate_to: localhost
- register: info
-
- - name: Gather info from datacenter about specific datastore
- community.vmware.vmware_datastore_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter_name: '{{ datacenter_name }}'
- name: datastore1
- delegate_to: localhost
- register: info
-
- - name: Gather some info from a datastore using the vSphere API output schema
- community.vmware.vmware_datastore_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter_name: '{{ datacenter_name }}'
- schema: vsphere
- properties:
- - name
- - info.vmfs.ssd
- - capability.vsanSparseSupported
- - overallStatus
- delegate_to: localhost
- register: info
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>datastores</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about the available datastores</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">[{&#x27;accessible&#x27;: False, &#x27;capacity&#x27;: 42681237504, &#x27;datastore_cluster&#x27;: &#x27;datacluster0&#x27;, &#x27;freeSpace&#x27;: 39638269952, &#x27;maintenanceMode&#x27;: &#x27;normal&#x27;, &#x27;multipleHostAccess&#x27;: False, &#x27;name&#x27;: &#x27;datastore2&#x27;, &#x27;provisioned&#x27;: 12289211488, &#x27;type&#x27;: &#x27;VMFS&#x27;, &#x27;uncommitted&#x27;: 9246243936, &#x27;url&#x27;: &#x27;ds:///vmfs/volumes/5a69b18a-c03cd88c-36ae-5254001249ce/&#x27;, &#x27;vmfs_blockSize&#x27;: 1024, &#x27;vmfs_uuid&#x27;: &#x27;5a69b18a-c03cd88c-36ae-5254001249ce&#x27;, &#x27;vmfs_version&#x27;: &#x27;6.81&#x27;}, {&#x27;accessible&#x27;: True, &#x27;capacity&#x27;: 5497558138880, &#x27;datastore_cluster&#x27;: &#x27;datacluster0&#x27;, &#x27;freeSpace&#x27;: 4279000641536, &#x27;maintenanceMode&#x27;: &#x27;normal&#x27;, &#x27;multipleHostAccess&#x27;: True, &#x27;name&#x27;: &#x27;datastore3&#x27;, &#x27;nfs_path&#x27;: &#x27;/vol/datastore3&#x27;, &#x27;nfs_server&#x27;: &#x27;nfs_server1&#x27;, &#x27;provisioned&#x27;: 1708109410304, &#x27;type&#x27;: &#x27;NFS&#x27;, &#x27;uncommitted&#x27;: 489551912960, &#x27;url&#x27;: &#x27;ds:///vmfs/volumes/420b3e73-67070776/&#x27;}]</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Tim Rightnour (@garbled1)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_datastore_maintenancemode_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_datastore_maintenancemode_module.rst
deleted file mode 100644
index 1b4bc2bef..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_datastore_maintenancemode_module.rst
+++ /dev/null
@@ -1,328 +0,0 @@
-.. _community.vmware.vmware_datastore_maintenancemode_module:
-
-
-*************************************************
-community.vmware.vmware_datastore_maintenancemode
-*************************************************
-
-**Place a datastore into maintenance mode**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to manage maintenance mode of a datastore.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the cluster where datastore is connected to.</div>
- <div>If multiple datastores are connected to the given cluster, then all datastores will be managed by <code>state</code>.</div>
- <div>If <code>datastore</code> or <code>datastore_cluster</code> are not set, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datastore</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of datastore to manage.</div>
- <div>If <code>datastore_cluster</code> or <code>cluster_name</code> are not set, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datastore_cluster</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the datastore cluster from all child datastores to be managed.</div>
- <div>If <code>datastore</code> or <code>cluster_name</code> are not set, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>If set to <code>present</code>, then enter datastore into maintenance mode.</div>
- <div>If set to <code>present</code> and datastore is already in maintenance mode, then no action will be taken.</div>
- <div>If set to <code>absent</code> and datastore is in maintenance mode, then exit maintenance mode.</div>
- <div>If set to <code>absent</code> and datastore is not in maintenance mode, then no action will be taken.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Enter datastore into Maintenance Mode
- community.vmware.vmware_datastore_maintenancemode:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datastore: '{{ datastore_name }}'
- state: present
- delegate_to: localhost
-
- - name: Enter all datastores under cluster into Maintenance Mode
- community.vmware.vmware_datastore_maintenancemode:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- cluster_name: '{{ cluster_name }}'
- state: present
- delegate_to: localhost
-
- - name: Enter all datastores under datastore cluster into Maintenance Mode
- community.vmware.vmware_datastore_maintenancemode:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datastore_cluster: '{{ datastore_cluster_name }}'
- state: present
- delegate_to: localhost
-
- - name: Exit datastore into Maintenance Mode
- community.vmware.vmware_datastore_maintenancemode:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datastore: '{{ datastore_name }}'
- state: absent
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>datastore_status</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>Action taken for datastore</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;ds_226_01&#x27;: &quot;Datastore &#x27;ds_226_01&#x27; is already in maintenance mode.&quot;}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_datastore_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_datastore_module.rst
deleted file mode 100644
index 96304be52..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_datastore_module.rst
+++ /dev/null
@@ -1,345 +0,0 @@
-.. _community.vmware.vmware_datastore_module:
-
-
-*********************************
-community.vmware.vmware_datastore
-*********************************
-
-**Configure Datastores**
-
-
-Version added: 3.0.0
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- Configure Storage I/O Control Settings of a Datastore.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>congestion_threshold_manual</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Storage I/O congestion threshold in ms.</div>
- <div>Only use <code>congestion_threshold_percentage</code> or <code>congestion_threshold_manual</code>.</div>
- <div>Only valid when <code>storage_io_control</code> is <code>enable_io_statistics</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>congestion_threshold_percentage</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">90</div>
- </td>
- <td>
- <div>Storage I/O congestion threshold in percentage of peak throughput.</div>
- <div>A value between 50% and 100%.</div>
- <div>Recommended: 90%</div>
- <div>Only use <code>congestion_threshold_percentage</code> or <code>congestion_threshold_manual</code>.</div>
- <div>Only valid when <code>storage_io_control</code> is <code>enable_io_statistics</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Datacenter to search for the datastores.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: datacenter_name</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the datastore.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>statistic_collection</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Include I/O statistics for SDRS.</div>
- <div>Only valid when <code>storage_io_control</code> is <code>enable_io_statistics</code> or <code>enable_statistics</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>storage_io_control</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>enable_io_statistics</li>
- <li>enable_statistics</li>
- <li>disable</li>
- </ul>
- </td>
- <td>
- <div>Specify datastore typ.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Configure Storage I/O Control of an mounted datastore
- community.vmware.vmware_datastore_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter_name: '{{ datacenter_name }}'
- name: datastore1
- storage_io_control: 'enable_io_statistics'
- congestion_threshold_manual: 30
- statistic_collection: true
- delegate_to: localhost
- register: info
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>result</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>Information about datastore operation.</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">Datastore configured successfully.</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Nina Loser (@Nina2244)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_deploy_ovf_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_deploy_ovf_module.rst
deleted file mode 100644
index be2a35d11..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_deploy_ovf_module.rst
+++ /dev/null
@@ -1,584 +0,0 @@
-.. _community.vmware.vmware_deploy_ovf_module:
-
-
-**********************************
-community.vmware.vmware_deploy_ovf
-**********************************
-
-**Deploys a VMware virtual machine from an OVF or OVA file**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to deploy a VMware VM from an OVF or OVA file
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>allow_duplicates</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- <b>Default:</b><br/><div style="color: blue">"True"</div>
- </td>
- <td>
- <div>Whether or not to allow duplicate VM names. ESXi allows duplicates, vCenter may not.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Cluster to deploy to.</div>
- <div>This is a required parameter, if <code>esxi_hostname</code> is not set and <code>hostname</code> is set to the vCenter server.</div>
- <div><code>esxi_hostname</code> and <code>cluster</code> are mutually exclusive parameters.</div>
- <div>This parameter is case sensitive.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">"ha-datacenter"</div>
- </td>
- <td>
- <div>Datacenter to deploy to.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datastore</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">"datastore1"</div>
- </td>
- <td>
- <div>Datastore to deploy to.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>deployment_option</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The key of the chosen deployment option.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>disk_provisioning</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>flat</li>
- <li>eagerZeroedThick</li>
- <li>monolithicSparse</li>
- <li>twoGbMaxExtentSparse</li>
- <li>twoGbMaxExtentFlat</li>
- <li><div style="color: blue"><b>thin</b>&nbsp;&larr;</div></li>
- <li>sparse</li>
- <li>thick</li>
- <li>seSparse</li>
- <li>monolithicFlat</li>
- </ul>
- </td>
- <td>
- <div>Disk provisioning type.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The ESXi hostname where the virtual machine will run.</div>
- <div>This is a required parameter, if <code>cluster</code> is not set and <code>hostname</code> is set to the vCenter server.</div>
- <div><code>esxi_hostname</code> and <code>cluster</code> are mutually exclusive parameters.</div>
- <div>This parameter is case sensitive.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>fail_on_spec_warnings</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Cause the module to treat OVF Import Spec warnings as errors.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>folder</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Absolute path of folder to place the virtual machine.</div>
- <div>If not specified, defaults to the value of <code>datacenter.vmFolder</code>.</div>
- <div>Examples:</div>
- <div>folder: /ha-datacenter/vm</div>
- <div>folder: ha-datacenter/vm</div>
- <div>folder: /datacenter1/vm</div>
- <div>folder: datacenter1/vm</div>
- <div>folder: /datacenter1/vm/folder1</div>
- <div>folder: datacenter1/vm/folder1</div>
- <div>folder: /folder1/datacenter1/vm</div>
- <div>folder: folder1/datacenter1/vm</div>
- <div>folder: /folder1/datacenter1/vm/folder2</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>inject_ovf_env</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Force the given properties to be inserted into an OVF Environment and injected through VMware Tools.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the VM to work with.</div>
- <div>Virtual machine names in vCenter are not necessarily unique, which may be problematic.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>networks</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">{"VM Network": "VM Network"}</div>
- </td>
- <td>
- <div><code>key: value</code> mapping of OVF network name, to the vCenter network name.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>ovf</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">path</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Path to OVF or OVA file to deploy.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: ova</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>power_on</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Whether or not to power on the virtual machine after creation.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>properties</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The assignment of values to the properties found in the OVF as key value pairs.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>resource_pool</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">"Resources"</div>
- </td>
- <td>
- <div>Resource Pool to deploy to.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>wait</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Wait for the host to power on.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>wait_for_ip_address</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Wait until vCenter detects an IP address for the VM.</div>
- <div>This requires vmware-tools (vmtoolsd) to properly work after creation.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - community.vmware.vmware_deploy_ovf:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- ovf: /path/to/ubuntu-16.04-amd64.ovf
- wait_for_ip_address: true
- delegate_to: localhost
-
- # Deploys a new VM named 'NewVM' in specific datacenter/cluster, with network mapping taken from variable and using ova template from an absolute path
- - community.vmware.vmware_deploy_ovf:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter: Datacenter1
- cluster: Cluster1
- datastore: vsandatastore
- name: NewVM
- networks: "{u'VM Network':u'{{ ProvisioningNetworkLabel }}'}"
- power_on: false
- ovf: /absolute/path/to/template/mytemplate.ova
- delegate_to: localhost
-
- - community.vmware.vmware_deploy_ovf:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter: Datacenter1
- esxi_hostname: test-server
- datastore: test-datastore
- ovf: /path/to/ubuntu-16.04-amd64.ovf
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>instance</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about the new virtual machine</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">None</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Matt Martz (@sivel)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_drs_group_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_drs_group_info_module.rst
deleted file mode 100644
index 97457bc91..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_drs_group_info_module.rst
+++ /dev/null
@@ -1,273 +0,0 @@
-.. _community.vmware.vmware_drs_group_info_module:
-
-
-**************************************
-community.vmware.vmware_drs_group_info
-**************************************
-
-**Gathers info about DRS VM/Host groups on the given cluster**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to gather information about DRS VM/HOST groups from the given cluster.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Cluster to search for VM/Host groups.</div>
- <div>If set, information of DRS groups belonging this cluster will be returned.</div>
- <div>Not needed if <code>datacenter</code> is set.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Datacenter to search for DRS VM/Host groups.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: datacenter_name</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- ---
- - name: "Gather DRS info about given Cluster"
- register: cluster_drs_group_info
- community.vmware.vmware_drs_group_info:
- hostname: "{{ vcenter_hostname }}"
- password: "{{ vcenter_password }}"
- username: "{{ vcenter_username }}"
- cluster_name: "{{ cluster_name }}"
- delegate_to: localhost
-
- - name: "Gather DRS group info about all clusters in given datacenter"
- register: cluster_drs_group_info
- community.vmware.vmware_drs_group_info:
- hostname: "{{ vcenter_hostname }}"
- password: "{{ vcenter_password }}"
- username: "{{ vcenter_username }}"
- datacenter: "{{ datacenter }}"
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>drs_group_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>Metadata about DRS group from given cluster / datacenter</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;drs_group_info&#x27;: {&#x27;DC0_C0&#x27;: [{&#x27;group_name&#x27;: &#x27;GROUP_HOST_S01&#x27;, &#x27;hosts&#x27;: [&#x27;vm-01.zone&#x27;, &#x27;vm-02.zone&#x27;], &#x27;type&#x27;: &#x27;host&#x27;}, {&#x27;group_name&#x27;: &#x27;GROUP_HOST_S02&#x27;, &#x27;hosts&#x27;: [&#x27;vm-03.zone&#x27;, &#x27;vm-04.zone&#x27;], &#x27;type&#x27;: &#x27;host&#x27;}, {&#x27;group_name&#x27;: &#x27;GROUP_VM_S01&#x27;, &#x27;type&#x27;: &#x27;vm&#x27;, &#x27;vms&#x27;: [&#x27;test-node01&#x27;]}, {&#x27;group_name&#x27;: &#x27;GROUP_VM_S02&#x27;, &#x27;type&#x27;: &#x27;vm&#x27;, &#x27;vms&#x27;: [&#x27;test-node02&#x27;]}], &#x27;DC0_C1&#x27;: []}}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Karsten Kaj Jakobsen (@karstenjakobsen)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_drs_group_manager_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_drs_group_manager_module.rst
deleted file mode 100644
index 5bfe13f38..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_drs_group_manager_module.rst
+++ /dev/null
@@ -1,397 +0,0 @@
-.. _community.vmware.vmware_drs_group_manager_module:
-
-
-*****************************************
-community.vmware.vmware_drs_group_manager
-*****************************************
-
-**Manage VMs and Hosts in DRS group.**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- The module can be used to add VMs / Hosts to or remove them from a DRS group.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Cluster to which DRS group associated with.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: cluster_name</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the datacenter.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: datacenter_name</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>group_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the group to manage.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hosts</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>A List of hosts to add / remove in the group.</div>
- <div>Required only if <em>vms</em> is not set.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>If set to <code>present</code>, VMs/hosts will be added to the given DRS group.</div>
- <div>If set to <code>absent</code>, VMs/hosts will be removed from the given DRS group.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vms</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>A List of vms to add / remove in the group.</div>
- <div>Required only if <em>hosts</em> is not set.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- ---
- - name: Add VMs in an existing DRS VM group
- delegate_to: localhost
- community.vmware.vmware_drs_group_manager:
- hostname: "{{ vcenter_hostname }}"
- password: "{{ vcenter_password }}"
- username: "{{ vcenter_username }}"
- cluster: DC0_C0
- datacenter: DC0
- group_name: TEST_VM_01
- vms:
- - DC0_C0_RP0_VM0
- - DC0_C0_RP0_VM1
- state: present
-
- - name: Add Hosts in an existing DRS Host group
- delegate_to: localhost
- community.vmware.vmware_drs_group_manager:
- hostname: "{{ vcenter_hostname }}"
- password: "{{ vcenter_password }}"
- username: "{{ vcenter_username }}"
- cluster: DC0_C0
- datacenter: DC0
- group_name: TEST_HOST_01
- hosts:
- - DC0_C0_H0
- - DC0_C0_H1
- - DC0_C0_H2
- state: present
-
- - name: Remove VM from an existing DRS VM group
- delegate_to: localhost
- community.vmware.vmware_drs_group_manager:
- hostname: "{{ vcenter_hostname }}"
- password: "{{ vcenter_password }}"
- username: "{{ vcenter_username }}"
- cluster: DC0_C0
- datacenter: DC0
- group_name: TEST_VM_01
- vms:
- - DC0_C0_RP0_VM0
- state: absent
-
- - name: Remove host from an existing DRS Host group
- delegate_to: localhost
- community.vmware.vmware_drs_group_manager:
- hostname: "{{ vcenter_hostname }}"
- password: "{{ vcenter_password }}"
- username: "{{ vcenter_username }}"
- cluster: DC0_C0
- datacenter: DC0
- group_name: TEST_HOST_01
- hosts:
- - DC0_C0_H0
- state: absent
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>drs_group_member_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>Metadata about DRS group</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;Asia-Cluster1&#x27;: [{&#x27;group_name&#x27;: &#x27;vm_group_002&#x27;, &#x27;type&#x27;: &#x27;vm&#x27;, &#x27;vms&#x27;: [&#x27;dev-1&#x27;]}]}</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>msg</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>Info message</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">Updated host group TEST_HOST_01 successfully</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_drs_group_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_drs_group_module.rst
deleted file mode 100644
index 9e347fa94..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_drs_group_module.rst
+++ /dev/null
@@ -1,364 +0,0 @@
-.. _community.vmware.vmware_drs_group_module:
-
-
-*********************************
-community.vmware.vmware_drs_group
-*********************************
-
-**Creates vm/host group in a given cluster.**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to create VM/Host groups in a given cluster. Creates a vm group if ``vms`` is set. Creates a host group if ``hosts`` is set.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Cluster to create vm/host group.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Datacenter to search for given cluster. If not set, we use first cluster we encounter with <code>cluster_name</code>.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: datacenter_name</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>group_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the group to create or remove.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hosts</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>List of hosts to create in group.</div>
- <div>Required only if <code>vms</code> is not set.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>If set to <code>present</code> and the group doesn&#x27;t exists then the group will be created.</div>
- <div>If set to <code>absent</code> and the group exists then the group will be deleted.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vms</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>List of vms to create in group.</div>
- <div>Required only if <code>hosts</code> is not set.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- ---
- - name: "Create DRS VM group"
- delegate_to: localhost
- community.vmware.vmware_drs_group:
- hostname: "{{ vcenter_hostname }}"
- password: "{{ vcenter_password }}"
- username: "{{ vcenter_username }}"
- cluster_name: DC0_C0
- datacenter_name: DC0
- group_name: TEST_VM_01
- vms:
- - DC0_C0_RP0_VM0
- - DC0_C0_RP0_VM1
- state: present
-
- - name: "Create DRS Host group"
- delegate_to: localhost
- community.vmware.vmware_drs_group:
- hostname: "{{ vcenter_hostname }}"
- password: "{{ vcenter_password }}"
- username: "{{ vcenter_username }}"
- cluster_name: DC0_C0
- datacenter_name: DC0
- group_name: TEST_HOST_01
- hosts:
- - DC0_C0_H0
- - DC0_C0_H1
- - DC0_C0_H2
- state: present
-
- - name: "Delete DRS Host group"
- delegate_to: localhost
- community.vmware.vmware_drs_group:
- hostname: "{{ vcenter_hostname }}"
- password: "{{ vcenter_password }}"
- username: "{{ vcenter_username }}"
- cluster_name: DC0_C0
- datacenter_name: DC0
- group_name: TEST_HOST_01
- state: absent
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>drs_group_facts</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>Metadata about DRS group created</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;drs_group_facts&#x27;: {&#x27;changed&#x27;: True, &#x27;failed&#x27;: False, &#x27;msg&#x27;: &#x27;Created host group TEST_HOST_01 successfully&#x27;, &#x27;result&#x27;: {&#x27;DC0_C0&#x27;: [{&#x27;group_name&#x27;: &#x27;TEST_HOST_01&#x27;, &#x27;hosts&#x27;: [&#x27;DC0_C0_H0&#x27;, &#x27;DC0_C0_H1&#x27;, &#x27;DC0_C0_H2&#x27;], &#x27;type&#x27;: &#x27;host&#x27;}]}}}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Karsten Kaj Jakobsen (@karstenjakobsen)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_drs_rule_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_drs_rule_info_module.rst
deleted file mode 100644
index 6faacf84b..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_drs_rule_info_module.rst
+++ /dev/null
@@ -1,273 +0,0 @@
-.. _community.vmware.vmware_drs_rule_info_module:
-
-
-*************************************
-community.vmware.vmware_drs_rule_info
-*************************************
-
-**Gathers info about DRS rule on the given cluster**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to gather information about DRS VM-VM and VM-HOST rules from the given cluster.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the cluster.</div>
- <div>DRS information for the given cluster will be returned.</div>
- <div>This is required parameter if <code>datacenter</code> parameter is not provided.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the datacenter.</div>
- <div>DRS information for all the clusters from the given datacenter will be returned.</div>
- <div>This is required parameter if <code>cluster_name</code> parameter is not provided.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Gather DRS info about given Cluster
- community.vmware.vmware_drs_rule_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- cluster_name: '{{ cluster_name }}'
- delegate_to: localhost
- register: cluster_drs_info
-
- - name: Gather DRS info about all Clusters in given datacenter
- community.vmware.vmware_drs_rule_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter: '{{ datacenter_name }}'
- delegate_to: localhost
- register: datacenter_drs_info
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>drs_rule_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about DRS rule from given cluster / datacenter</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;DC0_C0&#x27;: [{&#x27;rule_affinity&#x27;: False, &#x27;rule_enabled&#x27;: True, &#x27;rule_key&#x27;: 1, &#x27;rule_mandatory&#x27;: True, &#x27;rule_name&#x27;: &#x27;drs_rule_0001&#x27;, &#x27;rule_type&#x27;: &#x27;vm_vm_rule&#x27;, &#x27;rule_uuid&#x27;: &#x27;52be5061-665a-68dc-3d25-85cd2d37e114&#x27;, &#x27;rule_vms&#x27;: [&#x27;VM_65&#x27;, &#x27;VM_146&#x27;]}], &#x27;DC1_C1&#x27;: [{&#x27;rule_affine_host_group_name&#x27;: &#x27;host_group_1&#x27;, &#x27;rule_affine_hosts&#x27;: [&#x27;10.76.33.204&#x27;], &#x27;rule_anti_affine_host_group_name&#x27;: None, &#x27;rule_anti_affine_hosts&#x27;: [], &#x27;rule_enabled&#x27;: True, &#x27;rule_key&#x27;: 1, &#x27;rule_mandatory&#x27;: False, &#x27;rule_name&#x27;: &#x27;vm_host_rule_0001&#x27;, &#x27;rule_type&#x27;: &#x27;vm_host_rule&#x27;, &#x27;rule_uuid&#x27;: &#x27;52687108-4d3a-76f2-d29c-b708c40dbe40&#x27;, &#x27;rule_vm_group_name&#x27;: &#x27;test_vm_group_1&#x27;, &#x27;rule_vms&#x27;: [&#x27;VM_8916&#x27;, &#x27;VM_4010&#x27;]}]}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_dvs_host_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_dvs_host_module.rst
deleted file mode 100644
index 36fd43cae..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_dvs_host_module.rst
+++ /dev/null
@@ -1,411 +0,0 @@
-.. _community.vmware.vmware_dvs_host_module:
-
-
-********************************
-community.vmware.vmware_dvs_host
-********************************
-
-**Add or remove a host from distributed virtual switch**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- Manage a host system from distributed virtual switch.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="2">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The ESXi hostname.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>lag_uplinks</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">[]</div>
- </td>
- <td>
- <div>The ESXi hosts vmnics to use with specific LAGs.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>lag</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the LAG.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vmnics</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">[]</div>
- </td>
- <td>
- <div>The ESXi hosts vmnics to use with the LAG.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>If the host should be present or absent attached to the vSwitch.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>switch_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the Distributed vSwitch.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vendor_specific_config</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>List of key, value dictionaries for the Vendor Specific Configuration.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>key</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Key of setting.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>value</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Value of setting.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vmnics</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">[]</div>
- </td>
- <td>
- <div>The ESXi hosts vmnics to use with the Distributed vSwitch.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Add Host to dVS
- community.vmware.vmware_dvs_host:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- switch_name: dvSwitch
- vmnics:
- - vmnic0
- - vmnic1
- state: present
- delegate_to: localhost
-
- - name: Add vmnics to LAGs
- community.vmware.vmware_dvs_host:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- switch_name: dvSwitch
- lag_uplinks:
- - lag: lag1
- vmnics:
- - vmnic0
- - vmnic1
- - lag: lag2
- vmnics:
- - vmnic2
- - vmnic3
- state: present
- delegate_to: localhost
-
- - name: Add Host to dVS/enable learnswitch (https://labs.vmware.com/flings/learnswitch)
- community.vmware.vmware_dvs_host:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- switch_name: dvSwitch
- vendor_specific_config:
- - key: com.vmware.netoverlay.layer1
- value: learnswitch
- vmnics:
- - vmnic0
- - vmnic1
- state: present
- delegate_to: localhost
-
-
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Joseph Callen (@jcpowermac)
-- Abhijeet Kasurde (@Akasurde)
-- Joseph Andreatta (@vmwjoseph)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_dvs_portgroup_find_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_dvs_portgroup_find_module.rst
deleted file mode 100644
index 00d20063c..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_dvs_portgroup_find_module.rst
+++ /dev/null
@@ -1,304 +0,0 @@
-.. _community.vmware.vmware_dvs_portgroup_find_module:
-
-
-******************************************
-community.vmware.vmware_dvs_portgroup_find
-******************************************
-
-**Find portgroup(s) in a VMware environment**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- Find portgroup(s) based on different criteria such as distributed vSwitch, VLAN id or a string in the name.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>dvswitch</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of a distributed vSwitch to look for.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>string to check inside the name of the portgroup.</div>
- <div>Basic containment check using python <code>in</code> operation.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>show_uplink</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Show or hide uplink portgroups.</div>
- <div>Only relevant when <code>vlanid</code> is supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vlanid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>VLAN id can be any number between 1 and 4094.</div>
- <div>This search criteria will looks into VLAN ranges to find possible matches.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Get all portgroups in dvswitch vDS
- community.vmware.vmware_dvs_portgroup_find:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- dvswitch: 'vDS'
- delegate_to: localhost
-
- - name: Confirm if vlan 15 is present
- community.vmware.vmware_dvs_portgroup_find:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- vlanid: '15'
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>dvs_portgroups</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- </div>
- </td>
- <td>on success</td>
- <td>
- <div>basic details of portgroups found</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">[{&#x27;dvswitch&#x27;: &#x27;vDS&#x27;, &#x27;name&#x27;: &#x27;N-51&#x27;, &#x27;pvlan&#x27;: True, &#x27;trunk&#x27;: True, &#x27;vlan_id&#x27;: &#x27;0&#x27;}]</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- David Martinez (@dx0xm)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_dvs_portgroup_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_dvs_portgroup_info_module.rst
deleted file mode 100644
index c245c66ed..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_dvs_portgroup_info_module.rst
+++ /dev/null
@@ -1,382 +0,0 @@
-.. _community.vmware.vmware_dvs_portgroup_info_module:
-
-
-******************************************
-community.vmware.vmware_dvs_portgroup_info
-******************************************
-
-**Gathers info DVS portgroup configurations**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to gather information about DVS portgroup configurations.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the datacenter.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>dvswitch</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of a dvswitch to look for.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>show_mac_learning</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Show or hide MAC learning information of the DVS portgroup.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>show_network_policy</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Show or hide network policies of DVS portgroup.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>show_port_policy</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Show or hide port policies of DVS portgroup.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>show_teaming_policy</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Show or hide teaming policies of DVS portgroup.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>show_uplinks</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Show or hide uplinks of DVS portgroup.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>show_vlan_info</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Show or hide vlan information of the DVS portgroup.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Get info about DVPG
- community.vmware.vmware_dvs_portgroup_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- register: dvpg_info
-
- - name: Get number of ports for portgroup 'dvpg_001' in 'dvs_001'
- debug:
- msg: "{{ item.num_ports }}"
- with_items:
- - "{{ dvpg_info.dvs_portgroup_info['dvs_001'] | json_query(query) }}"
- vars:
- query: "[?portgroup_name=='dvpg_001']"
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>dvs_portgroup_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>on success</td>
- <td>
- <div>metadata about DVS portgroup configuration</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;dvs_0&#x27;: [{&#x27;description&#x27;: None, &#x27;dvswitch_name&#x27;: &#x27;dvs_001&#x27;, &#x27;network_policy&#x27;: {&#x27;forged_transmits&#x27;: False, &#x27;mac_changes&#x27;: False, &#x27;promiscuous&#x27;: False}, &#x27;num_ports&#x27;: 8, &#x27;port_policy&#x27;: {&#x27;block_override&#x27;: True, &#x27;ipfix_override&#x27;: False, &#x27;live_port_move&#x27;: False, &#x27;network_rp_override&#x27;: False, &#x27;port_config_reset_at_disconnect&#x27;: True, &#x27;security_override&#x27;: False, &#x27;shaping_override&#x27;: False, &#x27;traffic_filter_override&#x27;: False, &#x27;uplink_teaming_override&#x27;: False, &#x27;vendor_config_override&#x27;: False, &#x27;vlan_override&#x27;: False}, &#x27;portgroup_name&#x27;: &#x27;dvpg_001&#x27;, &#x27;teaming_policy&#x27;: {&#x27;inbound_policy&#x27;: True, &#x27;notify_switches&#x27;: True, &#x27;policy&#x27;: &#x27;loadbalance_srcid&#x27;, &#x27;rolling_order&#x27;: False}, &#x27;vlan_info&#x27;: {&#x27;trunk&#x27;: False, &#x27;pvlan&#x27;: False, &#x27;vlan_id&#x27;: 0}, &#x27;type&#x27;: &#x27;earlyBinding&#x27;}]}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_dvs_portgroup_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_dvs_portgroup_module.rst
deleted file mode 100644
index bf3f8649c..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_dvs_portgroup_module.rst
+++ /dev/null
@@ -1,1250 +0,0 @@
-.. _community.vmware.vmware_dvs_portgroup_module:
-
-
-*************************************
-community.vmware.vmware_dvs_portgroup
-*************************************
-
-**Create or remove a Distributed vSwitch portgroup.**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- Create or remove a Distributed vSwitch portgroup.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="2">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>in_traffic_shaping</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 2.3.0</div>
- </td>
- <td>
- </td>
- <td>
- <div>Dictionary which configures the ingress traffic shaping settings for the portgroup.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>average_bandwidth</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Establishes the number of bits per second to allow across a port, averaged over time, that is, the allowed average load.</div>
- <div>Ignored if <code>inherited</code> is true.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>burst_size</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The maximum number of bits per second to allow across a port when it is sending/sending or receiving a burst of traffic.</div>
- <div>Ignored if <code>inherited</code> is true.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>enabled</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Indicates whether ingress traffic shaping is activated or not.</div>
- <div>Ignored if <code>inherited</code> is true.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>inherited</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Inherit the settings from the switch or not.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>peak_bandwidth</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The maximum number of bytes to allow in a burst.</div>
- <div>Ignored if <code>inherited</code> is true.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>mac_learning</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Dictionary which configures MAC learning for portgroup.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>allow_unicast_flooding</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>The flag to allow flooding of unlearned MAC for ingress traffic.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>enabled</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>The flag to indicate if source MAC address learning is allowed.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>limit</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The maximum number of MAC addresses that can be learned.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>limit_policy</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>allow</li>
- <li>drop</li>
- </ul>
- </td>
- <td>
- <div>The default switching policy after MAC limit is exceeded.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>net_flow</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 2.3.0</div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>true</li>
- <li>on</li>
- <li>yes</li>
- <li>false</li>
- <li>off</li>
- <li>no</li>
- <li>inherited</li>
- </ul>
- </td>
- <td>
- <div>Indicate whether or not the virtual machine IP traffic that flows through a vds gets analyzed by sending reports to a NetFlow collector.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>network_policy</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Dictionary which configures the different security values for portgroup.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>forged_transmits</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Indicates whether forged transmits are allowed. Ignored if <code>inherited</code> is true.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>inherited</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Inherit the settings from the switch or not.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>mac_changes</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Indicates whether mac changes are allowed. Ignored if <code>inherited</code> is true.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>promiscuous</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Indicates whether promiscuous mode is allowed. Ignored if <code>inherited</code> is true.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>num_ports</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The number of ports the portgroup should contain.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>out_traffic_shaping</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 2.3.0</div>
- </td>
- <td>
- </td>
- <td>
- <div>Dictionary which configures the egress traffic shaping settings for the portgroup.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>average_bandwidth</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Establishes the number of bits per second to allow across a port, averaged over time, that is, the allowed average load.</div>
- <div>Ignored if <code>inherited</code> is true.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>burst_size</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The maximum number of bits per second to allow across a port when it is sending/sending or receiving a burst of traffic.</div>
- <div>Ignored if <code>inherited</code> is true.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>enabled</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Indicates whether egress traffic shaping is activated or not.</div>
- <div>Ignored if <code>inherited</code> is true.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>inherited</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Inherit the settings from the switch or not.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>peak_bandwidth</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The maximum number of bytes to allow in a burst.</div>
- <div>Ignored if <code>inherited</code> is true.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port_allocation</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>elastic</li>
- <li>fixed</li>
- </ul>
- </td>
- <td>
- <div>Elastic port groups automatically increase or decrease the number of ports as needed.</div>
- <div>Only valid if <em>port_binding</em> is set to <code>static</code>.</div>
- <div>Will be <code>elastic</code> if not specified and <em>port_binding</em> is set to <code>static</code>.</div>
- <div>Will be <code>fixed</code> if not specified and <em>port_binding</em> is set to <code>ephemeral</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port_binding</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>static</li>
- <li>ephemeral</li>
- </ul>
- </td>
- <td>
- <div>The type of port binding determines when ports in a port group are assigned to virtual machines.</div>
- <div>See VMware KB 1022312 <a href='https://kb.vmware.com/s/article/1022312'>https://kb.vmware.com/s/article/1022312</a> for more details.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port_policy</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">{"block_override": true, "ipfix_override": false, "live_port_move": false, "mac_management_override": false, "network_rp_override": false, "port_config_reset_at_disconnect": true, "shaping_override": false, "traffic_filter_override": false, "uplink_teaming_override": false, "vendor_config_override": false, "vlan_override": false}</div>
- </td>
- <td>
- <div>Dictionary which configures the advanced policy settings for the portgroup.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>block_override</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Indicates if the block policy can be changed per port.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>ipfix_override</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Indicates if the ipfix policy can be changed per port.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>live_port_move</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Indicates if a live port can be moved in or out of the portgroup.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>mac_management_override</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Indicates if the security policy can be changed per port.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: security_override</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>network_rp_override</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Indicates if the network resource pool can be changed per port.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port_config_reset_at_disconnect</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Indicates if the configuration of a port is reset automatically after disconnect.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>shaping_override</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Indicates if the shaping policy can be changed per port.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>traffic_filter_override</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Indicates if the traffic filter can be changed per port.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>uplink_teaming_override</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Indicates if the uplink teaming policy can be changed per port.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vendor_config_override</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Indicates if the vendor config can be changed per port.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vlan_override</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Indicates if the vlan can be changed per port.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>portgroup_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the portgroup that is to be created or deleted.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>present</li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>Determines if the portgroup should be present or not.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>switch_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the distributed vSwitch the port group should be created on.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>teaming_policy</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">{"load_balance_policy": "loadbalance_srcid", "notify_switches": true, "rolling_order": false}</div>
- </td>
- <td>
- <div>Dictionary which configures the different teaming values for portgroup.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>active_uplinks</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>List of active uplinks used for load balancing.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>inbound_policy</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Indicate whether or not the teaming policy is applied to inbound frames as well.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>load_balance_policy</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>loadbalance_ip</li>
- <li>loadbalance_srcmac</li>
- <li><div style="color: blue"><b>loadbalance_srcid</b>&nbsp;&larr;</div></li>
- <li>loadbalance_loadbased</li>
- <li>failover_explicit</li>
- </ul>
- </td>
- <td>
- <div>Network adapter teaming policy.</div>
- <div><code>loadbalance_loadbased</code> is available from version 2.6 and onwards.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>notify_switches</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Indicate whether or not to notify the physical switch if a link fails.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>rolling_order</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Indicate whether or not to use a rolling policy when restoring links.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>standby_uplinks</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>List of standby uplinks used for failover.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vlan_id</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The VLAN ID that should be configured with the portgroup, use 0 for no VLAN.</div>
- <div>If <code>vlan_trunk</code> is configured to be <em>true</em>, this can be a combination of multiple ranges and numbers, example: 1-200, 205, 400-4094.</div>
- <div>The valid <code>vlan_id</code> range is from 0 to 4094. Overlapping ranges are allowed.</div>
- <div>If <code>vlan_private</code> is configured to be <em>true</em>, the corresponding private VLAN should already be configured in the distributed vSwitch.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vlan_private</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Indicates whether this is for a private VLAN or not.</div>
- <div>Mutually exclusive with <code>vlan_trunk</code> parameter.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vlan_trunk</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Indicates whether this is a VLAN trunk or not.</div>
- <div>Mutually exclusive with <code>vlan_private</code> parameter.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Create vlan portgroup
- community.vmware.vmware_dvs_portgroup:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- portgroup_name: vlan-123-portrgoup
- switch_name: dvSwitch
- vlan_id: 123
- num_ports: 120
- port_binding: static
- state: present
- delegate_to: localhost
-
- - name: Create vlan trunk portgroup
- community.vmware.vmware_dvs_portgroup:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- portgroup_name: vlan-trunk-portrgoup
- switch_name: dvSwitch
- vlan_id: 1-1000, 1005, 1100-1200
- vlan_trunk: true
- num_ports: 120
- port_binding: static
- state: present
- delegate_to: localhost
-
- - name: Create private vlan portgroup
- vmware_dvs_portgroup:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- portgroup_name: private-vlan-portrgoup
- switch_name: dvSwitch
- vlan_id: 1001
- vlan_private: true
- num_ports: 120
- port_binding: static
- state: present
- delegate_to: localhost
-
- - name: Create no-vlan portgroup
- community.vmware.vmware_dvs_portgroup:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- portgroup_name: no-vlan-portrgoup
- switch_name: dvSwitch
- vlan_id: 0
- num_ports: 120
- port_binding: static
- state: present
- delegate_to: localhost
-
- - name: Create vlan portgroup with all security and port policies
- community.vmware.vmware_dvs_portgroup:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- portgroup_name: vlan-123-portrgoup
- switch_name: dvSwitch
- vlan_id: 123
- num_ports: 120
- port_binding: static
- state: present
- network_policy:
- inherited: false
- promiscuous: true
- forged_transmits: true
- mac_changes: true
- port_policy:
- block_override: true
- ipfix_override: true
- live_port_move: true
- network_rp_override: true
- port_config_reset_at_disconnect: true
- mac_management_override: true
- shaping_override: true
- traffic_filter_override: true
- uplink_teaming_override: true
- vendor_config_override: true
- vlan_override: true
- delegate_to: localhost
-
-
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Joseph Callen (@jcpowermac)
-- Philippe Dellaert (@pdellaert) <philippe@dellaert.org>
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_dvswitch_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_dvswitch_info_module.rst
deleted file mode 100644
index 5508d115c..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_dvswitch_info_module.rst
+++ /dev/null
@@ -1,349 +0,0 @@
-.. _community.vmware.vmware_dvswitch_info_module:
-
-
-*************************************
-community.vmware.vmware_dvswitch_info
-*************************************
-
-**Gathers info dvswitch configurations**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to gather information about dvswitch configurations.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>folder</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Specify a folder location of dvswitch to gather information from.</div>
- <div>Examples:</div>
- <div>folder: /datacenter1/network</div>
- <div>folder: datacenter1/network</div>
- <div>folder: /datacenter1/network/folder1</div>
- <div>folder: datacenter1/network/folder1</div>
- <div>folder: /folder1/datacenter1/network</div>
- <div>folder: folder1/datacenter1/network</div>
- <div>folder: /folder1/datacenter1/network/folder2</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>properties</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Specify the properties to retrieve.</div>
- <div>If not specified, all properties are retrieved (deeply).</div>
- <div>Results are returned in a structure identical to the vsphere API.</div>
- <div>Example:</div>
- <div>properties: [</div>
- <div>&quot;summary.name&quot;,</div>
- <div>&quot;summary.numPorts&quot;,</div>
- <div>&quot;config.maxMtu&quot;,</div>
- <div>&quot;overallStatus&quot;</div>
- <div>]</div>
- <div>Only valid when <code>schema</code> is <code>vsphere</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>schema</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>summary</b>&nbsp;&larr;</div></li>
- <li>vsphere</li>
- </ul>
- </td>
- <td>
- <div>Specify the output schema desired.</div>
- <div>The &#x27;summary&#x27; output schema is the legacy output from the module</div>
- <div>The &#x27;vsphere&#x27; output schema is the vSphere API class definition which requires pyvmomi&gt;6.7.1</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>switch_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of a dvswitch to look for.</div>
- <div>If <code>switch_name</code> not specified gather all dvswitch information.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: switch, dvswitch</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Gather all registered dvswitch
- community.vmware.vmware_dvswitch_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- delegate_to: localhost
- register: dvswitch_info
-
- - name: Gather info about specific dvswitch
- community.vmware.vmware_dvswitch_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- switch_name: DVSwitch01
- delegate_to: localhost
- register: dvswitch_info
-
- - name: Gather info from folder about specific dvswitch
- community.vmware.vmware_dvswitch_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- folder: /datacenter1/network/F01
- switch_name: DVSwitch02
- delegate_to: localhost
- register: dvswitch_info
-
- - name: Gather some info from a dvswitch using the vSphere API output schema
- community.vmware.vmware_dvswitch_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- schema: vsphere
- properties:
- - summary.name
- - summary.numPorts
- - config.maxMtu
- - overallStatus
- switch_name: DVSwitch01
- register: dvswitch_info
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>distributed_virtual_switches</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>list of dictionary of dvswitch and their information</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">[{&#x27;configure&#x27;: {&#x27;folder&#x27;: &#x27;network&#x27;, &#x27;hosts&#x27;: [&#x27;esxi-test-02.local&#x27;, &#x27;esxi-test-01.local&#x27;], &#x27;settings&#x27;: {&#x27;healthCheck&#x27;: {&#x27;TeamingHealthCheckConfig&#x27;: False, &#x27;VlanMtuHealthCheckConfig&#x27;: False}, &#x27;netflow&#x27;: {&#x27;activeFlowTimeout&#x27;: 60, &#x27;collectorIpAddress&#x27;: &#x27;&#x27;, &#x27;collectorPort&#x27;: 0, &#x27;idleFlowTimeout&#x27;: 15, &#x27;internalFlowsOnly&#x27;: False, &#x27;observationDomainId&#x27;: 0, &#x27;samplingRate&#x27;: 0, &#x27;switchIpAddress&#x27;: None}, &#x27;properties&#x27;: {&#x27;administratorContact&#x27;: {&#x27;contact&#x27;: None, &#x27;name&#x27;: None}, &#x27;advanced&#x27;: {&#x27;maxMtu&#x27;: 1500, &#x27;multicastFilteringMode&#x27;: &#x27;legacyFiltering&#x27;}, &#x27;discoveryProtocol&#x27;: {&#x27;operation&#x27;: &#x27;listen&#x27;, &#x27;protocol&#x27;: &#x27;cdp&#x27;}, &#x27;general&#x27;: {&#x27;ioControl&#x27;: True, &#x27;name&#x27;: &#x27;DVSwitch01&#x27;, &#x27;numPorts&#x27;: 10, &#x27;numUplinks&#x27;: 1, &#x27;vendor&#x27;: &#x27;VMware, Inc.&#x27;, &#x27;version&#x27;: &#x27;6.6.0&#x27;}}, &#x27;privateVlan&#x27;: []}}, &#x27;uuid&#x27;: &#x27;50 30 99 9c a7 60 8a 4f-05 9f e7 b5 da df 8f 17&#x27;}]</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- sky-joker (@sky-joker)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_dvswitch_lacp_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_dvswitch_lacp_module.rst
deleted file mode 100644
index 16b0353c2..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_dvswitch_lacp_module.rst
+++ /dev/null
@@ -1,405 +0,0 @@
-.. _community.vmware.vmware_dvswitch_lacp_module:
-
-
-*************************************
-community.vmware.vmware_dvswitch_lacp
-*************************************
-
-**Manage LACP configuration on a Distributed Switch**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to configure Link Aggregation Control Protocol (LACP) support mode and Link Aggregation Groups (LAGs).
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="2">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>link_aggregation_groups</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">[]</div>
- </td>
- <td>
- <div>Can only be used if <code>lacp_support</code> is set to <code>enhanced</code>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>load_balancing_mode</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">"srcDestIpTcpUdpPortVlan"</div>
- </td>
- <td>
- <div>Load balancing algorithm.</div>
- <div>Valid values are as follows</div>
- <div>- srcTcpUdpPort: Source TCP/UDP port number.</div>
- <div>- srcDestIpTcpUdpPortVlan: Source and destination IP, source and destination TCP/UDP port number and VLAN.</div>
- <div>- srcIpVlan: Source IP and VLAN.</div>
- <div>- srcDestTcpUdpPort: Source and destination TCP/UDP port number.</div>
- <div>- srcMac: Source MAC address.</div>
- <div>- destIp: Destination IP.</div>
- <div>- destMac: Destination MAC address.</div>
- <div>- vlan: VLAN only.</div>
- <div>- srcDestIp: Source and Destination IP.</div>
- <div>- srcIpTcpUdpPortVlan: Source IP, TCP/UDP port number and VLAN.</div>
- <div>- srcDestIpTcpUdpPort: Source and destination IP and TCP/UDP port number.</div>
- <div>- srcDestMac: Source and destination MAC address.</div>
- <div>- destIpTcpUdpPort: Destination IP and TCP/UDP port number.</div>
- <div>- srcPortId: Source Virtual Port Id.</div>
- <div>- srcIp: Source IP.</div>
- <div>- srcIpTcpUdpPort: Source IP and TCP/UDP port number.</div>
- <div>- destIpTcpUdpPortVlan: Destination IP, TCP/UDP port number and VLAN.</div>
- <div>- destTcpUdpPort: Destination TCP/UDP port number.</div>
- <div>- destIpVlan: Destination IP and VLAN.</div>
- <div>- srcDestIpVlan: Source and destination IP and VLAN.</div>
- <div>Please see examples for more information.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>mode</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>active</li>
- <li>passive</li>
- </ul>
- </td>
- <td>
- <div>The negotiating state of the uplinks/ports.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the LAG.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>uplink_number</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Number of uplinks.</div>
- <div>Can 1 to 30.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>support_mode</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>basic</b>&nbsp;&larr;</div></li>
- <li>enhanced</li>
- </ul>
- </td>
- <td>
- <div>The LACP support mode.</div>
- <div><code>basic</code>: One Link Aggregation Control Protocol group in the switch (singleLag).</div>
- <div><code>enhanced</code>: Multiple Link Aggregation Control Protocol groups in the switch (multipleLag).</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>switch</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the Distributed Switch to manage.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: dvswitch</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - You need to run the task two times if you want to remove all LAGs and change the support mode to 'basic'
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Enable enhanced mode on a Distributed Switch
- community.vmware.vmware_dvswitch_lacp:
- hostname: '{{ inventory_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- switch: dvSwitch
- support_mode: enhanced
- validate_certs: "{{ validate_vcenter_certs }}"
- delegate_to: localhost
- loop_control:
- label: "{{ item.name }}"
- with_items: "{{ vcenter_distributed_switches }}"
-
- - name: Enable enhanced mode and create two LAGs on a Distributed Switch
- community.vmware.vmware_dvswitch_lacp:
- hostname: '{{ inventory_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- switch: dvSwitch
- support_mode: enhanced
- link_aggregation_groups:
- - name: lag1
- uplink_number: 2
- mode: active
- load_balancing_mode: srcDestIpTcpUdpPortVlan
- - name: lag2
- uplink_number: 2
- mode: passive
- load_balancing_mode: srcDestIp
- validate_certs: "{{ validate_vcenter_certs }}"
- delegate_to: localhost
- loop_control:
- label: "{{ item.name }}"
- with_items: "{{ vcenter_distributed_switches }}"
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>result</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>information about performed operation</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;changed&#x27;: True, &#x27;dvswitch&#x27;: &#x27;dvSwitch&#x27;, &#x27;link_aggregation_groups&#x27;: [{&#x27;load_balancing_mode&#x27;: &#x27;srcDestIpTcpUdpPortVlan&#x27;, &#x27;mode&#x27;: &#x27;active&#x27;, &#x27;name&#x27;: &#x27;lag1&#x27;, &#x27;uplink_number&#x27;: 2}, {&#x27;load_balancing_mode&#x27;: &#x27;srcDestIp&#x27;, &#x27;mode&#x27;: &#x27;active&#x27;, &#x27;name&#x27;: &#x27;lag2&#x27;, &#x27;uplink_number&#x27;: 2}], &#x27;link_aggregation_groups_previous&#x27;: [], &#x27;support_mode&#x27;: &#x27;enhanced&#x27;, &#x27;result&#x27;: &#x27;lacp lags changed&#x27;}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Christian Kotte (@ckotte)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_dvswitch_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_dvswitch_module.rst
deleted file mode 100644
index 9c00d39c7..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_dvswitch_module.rst
+++ /dev/null
@@ -1,877 +0,0 @@
-.. _community.vmware.vmware_dvswitch_module:
-
-
-********************************
-community.vmware.vmware_dvswitch
-********************************
-
-**Create or remove a Distributed Switch**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to create, remove a Distributed Switch.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="2">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>contact</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Dictionary which configures administrator contact name and description for the Distributed Switch.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>description</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Description or other details.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Administrator name.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the datacenter that will contain the Distributed Switch.</div>
- <div>This parameter is optional, if <code>folder</code> is provided.</div>
- <div>Mutually exclusive with <code>folder</code> parameter.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: datacenter</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>description</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Description of the Distributed Switch.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>discovery_operation</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>both</li>
- <li>advertise</li>
- <li><div style="color: blue"><b>listen</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Select the discovery operation.</div>
- <div>Required parameter for <code>state</code> both <code>present</code> and <code>absent</code>, before Ansible 2.6 version.</div>
- <div>Required only if <code>state</code> is set to <code>present</code>, for Ansible 2.6 and onwards.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>discovery_proto</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>cdp</b>&nbsp;&larr;</div></li>
- <li>lldp</li>
- <li>disabled</li>
- </ul>
- </td>
- <td>
- <div>Link discovery protocol between Cisco and Link Layer discovery.</div>
- <div>Required parameter for <code>state</code> both <code>present</code> and <code>absent</code>, before Ansible 2.6 version.</div>
- <div>Required only if <code>state</code> is set to <code>present</code>, for Ansible 2.6 and onwards.</div>
- <div><code>cdp</code>: Use Cisco Discovery Protocol (CDP).</div>
- <div><code>lldp</code>: Use Link Layer Discovery Protocol (LLDP).</div>
- <div><code>disabled</code>: Do not use a discovery protocol.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: discovery_protocol</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>folder</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Destination folder, absolute path to place dvswitch in.</div>
- <div>The folder should include the datacenter.</div>
- <div>This parameter is case sensitive.</div>
- <div>This parameter is optional, if <code>datacenter</code> is provided.</div>
- <div>Examples:</div>
- <div>folder: /datacenter1/network</div>
- <div>folder: datacenter1/network</div>
- <div>folder: /datacenter1/network/folder1</div>
- <div>folder: datacenter1/network/folder1</div>
- <div>folder: /folder1/datacenter1/network</div>
- <div>folder: folder1/datacenter1/network</div>
- <div>folder: /folder1/datacenter1/network/folder2</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>health_check</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">{"teaming_failover": false, "teaming_failover_interval": 0, "vlan_mtu": false, "vlan_mtu_interval": 0}</div>
- </td>
- <td>
- <div>Dictionary which configures Health Check for the Distributed Switch.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>teaming_failover</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Teaming and failover health check.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>teaming_failover_interval</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">0</div>
- </td>
- <td>
- <div>Teaming and failover health check interval (minutes).</div>
- <div>The default value is 1 in the vSphere Client if the Teaming and failover health check is enabled.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vlan_mtu</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>VLAN and MTU health check.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vlan_mtu_interval</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">0</div>
- </td>
- <td>
- <div>VLAN and MTU health check interval (minutes).</div>
- <div>The default value is 1 in the vSphere Client if the VLAN and MTU health check is enabled.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>mtu</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">1500</div>
- </td>
- <td>
- <div>The switch maximum transmission unit.</div>
- <div>Required parameter for <code>state</code> both <code>present</code> and <code>absent</code>, before Ansible 2.6 version.</div>
- <div>Required only if <code>state</code> is set to <code>present</code>, for Ansible 2.6 and onwards.</div>
- <div>Accepts value between 1280 to 9000 (both inclusive).</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>multicast_filtering_mode</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>basic</b>&nbsp;&larr;</div></li>
- <li>snooping</li>
- </ul>
- </td>
- <td>
- <div>The multicast filtering mode.</div>
- <div><code>basic</code> mode: multicast traffic for virtual machines is forwarded according to the destination MAC address of the multicast group.</div>
- <div><code>snooping</code> mode: the Distributed Switch provides IGMP and MLD snooping according to RFC 4541.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>net_flow</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 2.7.0</div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">{"active_flow_timeout": 60, "collector_port": 0, "idle_flow_timeout": 15, "internal_flows_only": false, "observation_domain_id": 0, "sampling_rate": 4096}</div>
- </td>
- <td>
- <div>Dictionary which configures the Net Flow for the Distributed Switch.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>active_flow_timeout</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">60</div>
- </td>
- <td>
- <div>The time, in seconds, to wait before sending information after the flow is initiated.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>collector_ip</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The IP Address (IPv4 or IPv6) of the NetFlow collector.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>collector_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">0</div>
- </td>
- <td>
- <div>The Port of the NetFlow collector.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>idle_flow_timeout</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">15</div>
- </td>
- <td>
- <div>The time, in seconds, to wait before sending information after the flow is initiated.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>internal_flows_only</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>If True, data on network activity between vms on the same host will be collected only.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>observation_domain_id</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">0</div>
- </td>
- <td>
- <div>Identifies the information related to the switch.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>sampling_rate</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">4096</div>
- </td>
- <td>
- <div>The portion of data that the switch collects.</div>
- <div>The sampling rate represents the number of packets that NetFlow drops after every collected packet.</div>
- <div>If the rate is 0, NetFlow samples every packet, that is, collect one packet and drop none.</div>
- <div>If the rate is 1, NetFlow samples a packet and drops the next one, and so on.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>network_policy</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Dictionary which configures the different default security values for portgroups.</div>
- <div>If set, these options are inherited by the portgroups of the DVS.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>forged_transmits</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Indicates whether forged transmits are allowed.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>mac_changes</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Indicates whether mac changes are allowed.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>promiscuous</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Indicates whether promiscuous mode is allowed.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>If set to <code>present</code> and the Distributed Switch does not exist, the Distributed Switch will be created.</div>
- <div>If set to <code>absent</code> and the Distributed Switch exists, the Distributed Switch will be deleted.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>switch_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the distribute vSwitch to create or remove.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: switch, dvswitch</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>switch_version</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The version of the Distributed Switch to create.</div>
- <div>The version must match the version of the ESXi hosts you want to connect.</div>
- <div>The version of the vCenter server is used if not specified.</div>
- <div>Required only if <code>state</code> is set to <code>present</code>.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: version</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>uplink_prefix</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">"Uplink "</div>
- </td>
- <td>
- <div>The prefix used for the naming of the uplinks.</div>
- <div>Only valid if the Distributed Switch will be created. Not used if the Distributed Switch is already present.</div>
- <div>Uplinks are created as Uplink 1, Uplink 2, etc. pp. by default.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>uplink_quantity</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Quantity of uplink per ESXi host added to the Distributed Switch.</div>
- <div>The uplink quantity can be increased or decreased, but a decrease will only be successfull if the uplink isn&#x27;t used by a portgroup.</div>
- <div>Required parameter for <code>state</code> both <code>present</code> and <code>absent</code>, before Ansible 2.6 version.</div>
- <div>Required only if <code>state</code> is set to <code>present</code>, for Ansible 2.6 and onwards.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Create dvSwitch
- community.vmware.vmware_dvswitch:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter: '{{ datacenter }}'
- switch: dvSwitch
- version: 6.0.0
- mtu: 9000
- uplink_quantity: 2
- discovery_protocol: lldp
- discovery_operation: both
- state: present
- delegate_to: localhost
-
- - name: Create dvSwitch with all options
- community.vmware.vmware_dvswitch:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter: '{{ datacenter }}'
- switch: dvSwitch
- version: 6.5.0
- mtu: 9000
- uplink_quantity: 2
- uplink_prefix: 'Uplink_'
- discovery_protocol: cdp
- discovery_operation: both
- multicast_filtering_mode: snooping
- health_check:
- vlan_mtu: true
- vlan_mtu_interval: 1
- teaming_failover: true
- teaming_failover_interval: 1
- net_flow:
- collector_ip: 192.168.10.50
- collector_port: 50034
- observation_domain_id: 0
- active_flow_timeout: 60
- idle_flow_timeout: 15
- sampling_rate: 4096
- internal_flows_only: false
- state: present
- delegate_to: localhost
-
- - name: Delete dvSwitch
- community.vmware.vmware_dvswitch:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter: '{{ datacenter }}'
- switch: dvSwitch
- state: absent
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>result</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>information about performed operation</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;changed&#x27;: False, &#x27;contact&#x27;: None, &#x27;contact_details&#x27;: None, &#x27;description&#x27;: None, &#x27;discovery_operation&#x27;: &#x27;both&#x27;, &#x27;discovery_protocol&#x27;: &#x27;cdp&#x27;, &#x27;dvswitch&#x27;: &#x27;test&#x27;, &#x27;health_check_teaming&#x27;: False, &#x27;health_check_teaming_interval&#x27;: 0, &#x27;health_check_vlan&#x27;: False, &#x27;health_check_vlan_interval&#x27;: 0, &#x27;net_flow_collector_ip&#x27;: &#x27;192.168.10.50&#x27;, &#x27;net_flow_collector_port&#x27;: 50034, &#x27;net_flow_observation_domain_id&#x27;: 0, &#x27;net_flow_active_flow_timeout&#x27;: 60, &#x27;net_flow_idle_flow_timeout&#x27;: 15, &#x27;net_flow_sampling_rate&#x27;: 4096, &#x27;net_flow_internal_flows_only&#x27;: False, &#x27;mtu&#x27;: 9000, &#x27;multicast_filtering_mode&#x27;: &#x27;basic&#x27;, &#x27;result&#x27;: &#x27;DVS already configured properly&#x27;, &#x27;uplink_quantity&#x27;: 2, &#x27;uplinks&#x27;: [&#x27;Uplink_1&#x27;, &#x27;Uplink_2&#x27;], &#x27;version&#x27;: &#x27;6.6.0&#x27;}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Joseph Callen (@jcpowermac)
-- Abhijeet Kasurde (@Akasurde)
-- Christian Kotte (@ckotte)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_dvswitch_nioc_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_dvswitch_nioc_module.rst
deleted file mode 100644
index afef793a6..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_dvswitch_nioc_module.rst
+++ /dev/null
@@ -1,449 +0,0 @@
-.. _community.vmware.vmware_dvswitch_nioc_module:
-
-
-*************************************
-community.vmware.vmware_dvswitch_nioc
-*************************************
-
-**Manage distributed switch Network IO Control**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to manage distributed switch Network IO Control configurations.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="2">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>resources</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">[]</div>
- </td>
- <td>
- <div>List of dicts containing.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>limit</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">-1</div>
- </td>
- <td>
- <div>The maximum allowed usage for a traffic class belonging to this resource pool per host physical NIC.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>faultTolerance</li>
- <li>hbr</li>
- <li>iSCSI</li>
- <li>management</li>
- <li>nfs</li>
- <li>vdp</li>
- <li>virtualMachine</li>
- <li>vmotion</li>
- <li>vsan</li>
- <li>backupNfc</li>
- <li>nvmetcp</li>
- </ul>
- </td>
- <td>
- <div>Resource name.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>reservation</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">0</div>
- </td>
- <td>
- <div>Ignored if NIOC version is set to version2</div>
- <div>Amount of bandwidth resource that is guaranteed available to the host infrastructure traffic class.</div>
- <div>If the utilization is less than the reservation, the extra bandwidth is used for other host infrastructure traffic class types.</div>
- <div>Reservation is not allowed to exceed the value of limit, if limit is set.</div>
- <div>Unit is Mbits/sec.</div>
- <div>Ignored unless version is &quot;version3&quot;.</div>
- <div>Amount of bandwidth resource that is guaranteed available to the host infrastructure traffic class.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>shares</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The number of shares allocated.</div>
- <div>Ignored unless <code>shares_level</code> is &quot;custom&quot;.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>shares_level</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>low</li>
- <li>normal</li>
- <li>high</li>
- <li>custom</li>
- </ul>
- </td>
- <td>
- <div>The allocation level</div>
- <div>The level is a simplified view of shares.</div>
- <div>Levels map to a pre-determined set of numeric values for shares.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>Enable or disable NIOC on the distributed switch.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>switch</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the distributed switch.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: dvswitch</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>version</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>version2</li>
- <li>version3</li>
- </ul>
- </td>
- <td>
- <div>Network IO control version.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Enable NIOC
- community.vmware.vmware_dvswitch_nioc:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- switch: dvSwitch
- version: version3
- resources:
- - name: vmotion
- limit: -1
- reservation: 128
- shares_level: normal
- - name: vsan
- limit: -1
- shares_level: custom
- shares: 99
- reservation: 256
- state: present
- delegate_to: localhost
-
- - name: Disable NIOC
- community.vmware.vmware_dvswitch_nioc:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- switch: dvSwitch
- state: absent
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>dvswitch_nioc_status</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>success</td>
- <td>
- <div>result of the changes</div>
- <br/>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>resources_changed</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- </div>
- </td>
- <td>success</td>
- <td>
- <div>list of resources which were changed</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">[&#x27;vmotion&#x27;, &#x27;vsan&#x27;]</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Joseph Andreatta (@vmwjoseph)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_dvswitch_pvlans_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_dvswitch_pvlans_module.rst
deleted file mode 100644
index b85e818ae..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_dvswitch_pvlans_module.rst
+++ /dev/null
@@ -1,323 +0,0 @@
-.. _community.vmware.vmware_dvswitch_pvlans_module:
-
-
-***************************************
-community.vmware.vmware_dvswitch_pvlans
-***************************************
-
-**Manage Private VLAN configuration of a Distributed Switch**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to configure Private VLANs (PVLANs) on a Distributed Switch.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>primary_pvlans</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">[]</div>
- </td>
- <td>
- <div>A list of VLAN IDs that should be configured as Primary PVLANs.</div>
- <div>If <code>primary_pvlans</code> isn&#x27;t specified, all PVLANs will be deleted if present.</div>
- <div>Each member of the list requires primary_pvlan_id (int) set.</div>
- <div>The secondary promiscuous PVLAN will be created automatically.</div>
- <div>If <code>secondary_pvlans</code> isn&#x27;t specified, the primary PVLANs and each secondary promiscuous PVLAN will be created.</div>
- <div>Please see examples for more information.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>secondary_pvlans</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">[]</div>
- </td>
- <td>
- <div>A list of VLAN IDs that should be configured as Secondary PVLANs.</div>
- <div><code>primary_pvlans</code> need to be specified to create any Secondary PVLAN.</div>
- <div>If <code>primary_pvlans</code> isn&#x27;t specified, all PVLANs will be deleted if present.</div>
- <div>Each member of the list requires primary_pvlan_id (int), secondary_pvlan_id (int), and pvlan_type (str) to be set.</div>
- <div>The type of the secondary PVLAN can be isolated or community. The secondary promiscuous PVLAN will be created automatically.</div>
- <div>Please see examples for more information.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>switch</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the Distributed Switch.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: dvswitch</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Create PVLANs on a Distributed Switch
- community.vmware.vmware_dvswitch_pvlans:
- hostname: '{{ inventory_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- switch: dvSwitch
- primary_pvlans:
- - primary_pvlan_id: 1
- - primary_pvlan_id: 4
- secondary_pvlans:
- - primary_pvlan_id: 1
- secondary_pvlan_id: 2
- pvlan_type: isolated
- - primary_pvlan_id: 1
- secondary_pvlan_id: 3
- pvlan_type: community
- - primary_pvlan_id: 4
- secondary_pvlan_id: 5
- pvlan_type: community
- delegate_to: localhost
-
- - name: Create primary PVLAN and secondary promiscuous PVLAN on a Distributed Switch
- community.vmware.vmware_dvswitch_pvlans:
- hostname: '{{ inventory_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- switch: dvSwitch
- primary_pvlans:
- - primary_pvlan_id: 1
- delegate_to: localhost
-
- - name: Remove all PVLANs from a Distributed Switch
- community.vmware.vmware_dvswitch_pvlans:
- hostname: '{{ inventory_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- switch: dvSwitch
- primary_pvlans: []
- secondary_pvlans: []
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>result</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>information about performed operation</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;changed&#x27;: True, &#x27;dvswitch&#x27;: &#x27;dvSwitch&#x27;, &#x27;private_vlans&#x27;: [{&#x27;primary_pvlan_id&#x27;: 1, &#x27;pvlan_type&#x27;: &#x27;promiscuous&#x27;, &#x27;secondary_pvlan_id&#x27;: 1}, {&#x27;primary_pvlan_id&#x27;: 1, &#x27;pvlan_type&#x27;: &#x27;isolated&#x27;, &#x27;secondary_pvlan_id&#x27;: 2}, {&#x27;primary_pvlan_id&#x27;: 1, &#x27;pvlan_type&#x27;: &#x27;community&#x27;, &#x27;secondary_pvlan_id&#x27;: 3}], &#x27;private_vlans_previous&#x27;: [], &#x27;result&#x27;: &#x27;All private VLANs added&#x27;}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Christian Kotte (@ckotte)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_dvswitch_uplink_pg_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_dvswitch_uplink_pg_module.rst
deleted file mode 100644
index c3c4f506a..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_dvswitch_uplink_pg_module.rst
+++ /dev/null
@@ -1,552 +0,0 @@
-.. _community.vmware.vmware_dvswitch_uplink_pg_module:
-
-
-******************************************
-community.vmware.vmware_dvswitch_uplink_pg
-******************************************
-
-**Manage uplink portproup configuration of a Distributed Switch**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to configure the uplink portgroup of a Distributed Switch.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="2">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>advanced</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">{"block_override": true, "netflow_override": false, "port_config_reset_at_disconnect": true, "traffic_filter_override": false, "vendor_config_override": false, "vlan_override": false}</div>
- </td>
- <td>
- <div>Dictionary which configures the advanced policy settings for the uplink portgroup.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: port_policy</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>block_override</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Indicates if the block policy can be changed per port.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>netflow_override</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Indicates if the NetFlow policy can be changed per port.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port_config_reset_at_disconnect</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Indicates if the configuration of a port is reset automatically after disconnect.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>traffic_filter_override</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Indicates if the traffic filter can be changed per port.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vendor_config_override</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Indicates if the vendor config can be changed per port.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vlan_override</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Indicates if the vlan can be changed per port.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>block_all_ports</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Indicates if all ports are blocked on the uplink portgroup.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>description</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The description of the uplink portgroup.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>lacp</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">{"mode": "passive", "status": "disabled"}</div>
- </td>
- <td>
- <div>Dictionary which configures the LACP settings for the uplink portgroup.</div>
- <div>The options are only used if the LACP support mode is set to &#x27;basic&#x27;.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>mode</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>active</li>
- <li><div style="color: blue"><b>passive</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>The negotiating state of the uplinks/ports.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>status</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>enabled</li>
- <li><div style="color: blue"><b>disabled</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Indicates if LACP is enabled.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the uplink portgroup.</div>
- <div>The current name will be used if not specified.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>netflow_enabled</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Indicates if NetFlow is enabled on the uplink portgroup.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>switch</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the Distributed Switch.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: dvswitch</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vlan_trunk_range</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">["0-4094"]</div>
- </td>
- <td>
- <div>The VLAN trunk range that should be configured with the uplink portgroup.</div>
- <div>This can be a combination of multiple ranges and numbers, example: [ 2-3967, 4049-4092 ].</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Configure Uplink portgroup
- community.vmware.vmware_dvswitch_uplink_pg:
- hostname: '{{ inventory_hostname }}'
- username: '{{ vcsa_username }}'
- password: '{{ vcsa_password }}'
- switch: dvSwitch
- name: dvSwitch-DVUplinks
- advanced:
- port_config_reset_at_disconnect: true
- block_override: true
- vendor_config_override: false
- vlan_override: false
- netflow_override: false
- traffic_filter_override: false
- vlan_trunk_range:
- - '0-4094'
- netflow_enabled: false
- block_all_ports: false
- delegate_to: localhost
-
- - name: Enabled LACP on Uplink portgroup
- community.vmware.vmware_dvswitch_uplink_pg:
- hostname: '{{ inventory_hostname }}'
- username: '{{ vcsa_username }}'
- password: '{{ vcsa_password }}'
- switch: dvSwitch
- lacp:
- status: enabled
- mode: active
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>result</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>information about performed operation</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;adv_block_ports&#x27;: True, &#x27;adv_netflow&#x27;: False, &#x27;adv_reset_at_disconnect&#x27;: True, &#x27;adv_traffic_filtering&#x27;: False, &#x27;adv_vendor_conf&#x27;: False, &#x27;adv_vlan&#x27;: False, &#x27;block_all_ports&#x27;: False, &#x27;changed&#x27;: False, &#x27;description&#x27;: None, &#x27;dvswitch&#x27;: &#x27;dvSwitch&#x27;, &#x27;lacp_status&#x27;: &#x27;disabled&#x27;, &#x27;lacp_status_previous&#x27;: &#x27;enabled&#x27;, &#x27;name&#x27;: &#x27;dvSwitch-DVUplinks&#x27;, &#x27;netflow_enabled&#x27;: False, &#x27;result&#x27;: &#x27;Uplink portgroup already configured properly&#x27;, &#x27;vlan_trunk_range&#x27;: [&#x27;2-3967&#x27;, &#x27;4049-4092&#x27;]}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Christian Kotte (@ckotte)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_evc_mode_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_evc_mode_module.rst
deleted file mode 100644
index c36ac105c..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_evc_mode_module.rst
+++ /dev/null
@@ -1,313 +0,0 @@
-.. _community.vmware.vmware_evc_mode_module:
-
-
-********************************
-community.vmware.vmware_evc_mode
-********************************
-
-**Enable/Disable EVC mode on vCenter**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to enable/disable EVC mode on vCenter.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the cluster to enable or disable EVC mode on.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: cluster</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the datacenter the cluster belongs to that you want to enable or disable EVC mode on.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: datacenter</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>evc_mode</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Required for <code>state=present</code>.</div>
- <div>The EVC mode to enable or disable on the cluster. (intel-broadwell, intel-nehalem, intel-merom, etc.).</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>absent</li>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Add or remove EVC mode.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Enable EVC Mode
- community.vmware.vmware_evc_mode:
- hostname: "{{ groups['vcsa'][0] }}"
- username: "{{ vcenter_username }}"
- password: "{{ site_password }}"
- datacenter_name: "{{ datacenter_name }}"
- cluster_name: "{{ cluster_name }}"
- evc_mode: "intel-broadwell"
- state: present
- delegate_to: localhost
- register: enable_evc
-
- - name: Disable EVC Mode
- community.vmware.vmware_evc_mode:
- hostname: "{{ groups['vcsa'][0] }}"
- username: "{{ vcenter_username }}"
- password: "{{ site_password }}"
- datacenter_name: "{{ datacenter_name }}"
- cluster_name: "{{ cluster_name }}"
- state: absent
- delegate_to: localhost
- register: disable_evc
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>result</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>information about performed operation</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">EVC Mode for &#x27;intel-broadwell&#x27; has been enabled.</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Michael Tipton (@castawayegr)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_export_ovf_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_export_ovf_module.rst
deleted file mode 100644
index 988b545f2..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_export_ovf_module.rst
+++ /dev/null
@@ -1,397 +0,0 @@
-.. _community.vmware.vmware_export_ovf_module:
-
-
-**********************************
-community.vmware.vmware_export_ovf
-**********************************
-
-**Exports a VMware virtual machine to an OVF file, device files and a manifest file**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to export a VMware virtual machine to OVF template from vCenter server or ESXi host.
-
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">"ha-datacenter"</div>
- </td>
- <td>
- <div>Datacenter name of the virtual machine to export.</div>
- <div>This parameter is case sensitive.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>download_timeout</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">30</div>
- </td>
- <td>
- <div>The user defined timeout in second of exporting file.</div>
- <div>If the vmdk file is too large, you can increase the value.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>export_dir</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">path</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Absolute path to place the exported files on the server running this task, must have write permission.</div>
- <div>If folder not exist will create it, also create a folder under this path named with VM name.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>export_with_extraconfig</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 2.0.0</div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>All extra configuration options are exported for a virtual machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>export_with_images</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Export an ISO image of the media mounted on the CD/DVD Drive within the virtual machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>folder</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Destination folder, absolute path to find the specified guest.</div>
- <div>The folder should include the datacenter. ESX datacenter is ha-datacenter.</div>
- <div>This parameter is case sensitive.</div>
- <div>If multiple machines are found with same name, this parameter is used to identify</div>
- <div>Examples:</div>
- <div>folder: /ha-datacenter/vm</div>
- <div>folder: ha-datacenter/vm</div>
- <div>folder: /datacenter1/vm</div>
- <div>folder: datacenter1/vm</div>
- <div>folder: /datacenter1/vm/folder1</div>
- <div>folder: datacenter1/vm/folder1</div>
- <div>folder: /folder1/datacenter1/vm</div>
- <div>folder: folder1/datacenter1/vm</div>
- <div>folder: /folder1/datacenter1/vm/folder2</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>moid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.</div>
- <div>This is required if <code>name</code> or <code>uuid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the virtual machine to export.</div>
- <div>This is a required parameter, if parameter <code>uuid</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Uuid of the virtual machine to export.</div>
- <div>This is a required parameter, if parameter <code>name</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - community.vmware.vmware_export_ovf:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- name: '{{ vm_name }}'
- export_with_images: true
- export_dir: /path/to/ovf_template/
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>instance</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>list of the exported files, if exported from vCenter server, device file is not named with vm name</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">None</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Diane Wang (@Tomorrow9) <dianew@vmware.com>
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_first_class_disk_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_first_class_disk_module.rst
deleted file mode 100644
index 744d3d606..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_first_class_disk_module.rst
+++ /dev/null
@@ -1,334 +0,0 @@
-.. _community.vmware.vmware_first_class_disk_module:
-
-
-****************************************
-community.vmware.vmware_first_class_disk
-****************************************
-
-**Manage VMware vSphere First Class Disks**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to manage (create, delete, resize) VMware vSphere First Class Disks.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the datacenter.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datastore_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of datastore or datastore cluster to be used for the disk.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>disk_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the disk.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>size</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Disk storage size, an integer plus a unit.</div>
- <div>There is no space allowed in between size number and unit.</div>
- <div>Allowed units are MB, GB and TB.</div>
- <div>Examples:</div>
- <div>size: 2048MB</div>
- <div>size: 10GB</div>
- <div>size: 1TB</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>If the disk should be present or absent.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Create Disk
- community.vmware.vmware_first_class_disk:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datastore_name: '{{ datastore_name }}'
- disk_name: '1GBDisk'
- size: '1GB'
- state: present
- delegate_to: localhost
-
- - name: Delete Disk
- community.vmware.vmware_first_class_disk:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datastore_name: '{{ datastore_name }}'
- disk_name: 'FirstClassDisk'
- state: absent
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>first_class_disk</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>changed</td>
- <td>
- <div>First-class disk returned when created, deleted or changed</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{
- &quot;name&quot;: &quot;1GBDisk&quot;
- &quot;datastore_name&quot;: &quot;DS0&quot;
- &quot;size_mb&quot;: &quot;1024&quot;
- &quot;state&quot;: &quot;present&quot;
- }</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Mario Lenz (@mariolenz)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_folder_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_folder_info_module.rst
deleted file mode 100644
index a647ddc5e..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_folder_info_module.rst
+++ /dev/null
@@ -1,277 +0,0 @@
-.. _community.vmware.vmware_folder_info_module:
-
-
-***********************************
-community.vmware.vmware_folder_info
-***********************************
-
-**Provides information about folders in a datacenter**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- The module can be used to gather a hierarchical view of the folders that exist within a datacenter
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the datacenter.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: datacenter_name</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - ``flat_folder_info`` added in VMware collection 1.4.0.
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Provide information about vCenter folders
- community.vmware.vmware_folder_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter: datacenter_name
- delegate_to: localhost
- register: vcenter_folder_info
-
- - name: Get information about folders
- community.vmware.vmware_folder_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter: 'Asia-Datacenter1'
- register: r
-
- - name: Set Managed object ID for the given folder
- ansible.builtin.set_fact:
- folder_mo_id: "{{ (r.flat_folder_info | selectattr('path', 'equalto', '/Asia-Datacenter1/vm/tier1/tier2') | map(attribute='moid'))[0] }}"
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>flat_folder_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- </div>
- </td>
- <td>success</td>
- <td>
- <div>list of dict about folders in flat structure</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">[{&#x27;moid&#x27;: &#x27;group-v3&#x27;, &#x27;path&#x27;: &#x27;/Asia-Datacenter1/vm&#x27;}, {&#x27;moid&#x27;: &#x27;group-v44&#x27;, &#x27;path&#x27;: &#x27;/Asia-Datacenter1/vm/tier1&#x27;}, {&#x27;moid&#x27;: &#x27;group-v45&#x27;, &#x27;path&#x27;: &#x27;/Asia-Datacenter1/vm/tier1/tier2&#x27;}]</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>folder_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>success</td>
- <td>
- <div>dict about folders</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;datastoreFolders&#x27;: {&#x27;moid&#x27;: &#x27;group-v10&#x27;, &#x27;path&#x27;: &#x27;/DC01/datastore&#x27;, &#x27;subfolders&#x27;: {&#x27;Local Datastores&#x27;: {&#x27;path&#x27;: &#x27;/DC01/datastore/Local Datastores&#x27;, &#x27;subfolders&#x27;: {}}}}, &#x27;hostFolders&#x27;: {&#x27;moid&#x27;: &#x27;group-v21&#x27;, &#x27;path&#x27;: &#x27;/DC01/host&#x27;, &#x27;subfolders&#x27;: {}}, &#x27;networkFolders&#x27;: {&#x27;moid&#x27;: &#x27;group-v31&#x27;, &#x27;path&#x27;: &#x27;/DC01/network&#x27;, &#x27;subfolders&#x27;: {}}, &#x27;vmFolders&#x27;: {&#x27;moid&#x27;: &#x27;group-v41&#x27;, &#x27;path&#x27;: &#x27;/DC01/vm&#x27;, &#x27;subfolders&#x27;: {&#x27;Core Infrastructure Servers&#x27;: {&#x27;moid&#x27;: &#x27;group-v42&#x27;, &#x27;path&#x27;: &#x27;/DC01/vm/Core Infrastructure Servers&#x27;, &#x27;subfolders&#x27;: {&#x27;Staging Network Services&#x27;: {&#x27;moid&#x27;: &#x27;group-v43&#x27;, &#x27;path&#x27;: &#x27;/DC01/vm/Core Infrastructure Servers/Staging Network Services&#x27;, &#x27;subfolders&#x27;: {}}, &#x27;VMware&#x27;: {&#x27;moid&#x27;: &#x27;group-v44&#x27;, &#x27;path&#x27;: &#x27;/DC01/vm/Core Infrastructure Servers/VMware&#x27;, &#x27;subfolders&#x27;: {}}}}}}}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- David Hewitt (@davidmhewitt)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_boot_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_boot_info_module.rst
deleted file mode 100644
index 989517008..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_boot_info_module.rst
+++ /dev/null
@@ -1,323 +0,0 @@
-.. _community.vmware.vmware_guest_boot_info_module:
-
-
-***************************************
-community.vmware.vmware_guest_boot_info
-***************************************
-
-**Gather info about boot options for the given virtual machine**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- Gather information about boot options for the given virtual machine.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>moid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.</div>
- <div>This is required if <code>name</code> or <code>uuid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the VM to work with.</div>
- <div>This is required if <code>uuid</code> or <code>moid</code> parameter is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name_match</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>first</b>&nbsp;&larr;</div></li>
- <li>last</li>
- </ul>
- </td>
- <td>
- <div>If multiple virtual machines matching the name, use the first or last found.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>use_instance_uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether to use the VMware instance UUID rather than the BIOS UUID.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>UUID of the instance to manage if known, this is VMware&#x27;s BIOS UUID by default.</div>
- <div>This is required if <code>name</code> or <code>moid</code> parameter is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Gather info about virtual machine's boot order and related parameters
- community.vmware.vmware_guest_boot_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- name: "{{ vm_name }}"
- register: vm_boot_order_info
-
- - name: Gather information about virtual machine's boot order using MoID
- community.vmware.vmware_guest_boot_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- moid: "vm-42"
- register: vm_moid_boot_order_info
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>vm_boot_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about boot order of virtual machine</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;current_boot_order&#x27;: [&#x27;floppy&#x27;, &#x27;disk&#x27;, &#x27;ethernet&#x27;, &#x27;cdrom&#x27;], &#x27;current_boot_delay&#x27;: 2000, &#x27;current_boot_retry_delay&#x27;: 22300, &#x27;current_boot_retry_enabled&#x27;: True, &#x27;current_enter_bios_setup&#x27;: True, &#x27;current_boot_firmware&#x27;: &#x27;bios&#x27;, &#x27;current_secure_boot_enabled&#x27;: False}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_boot_manager_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_boot_manager_module.rst
deleted file mode 100644
index bd2f644a9..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_boot_manager_module.rst
+++ /dev/null
@@ -1,490 +0,0 @@
-.. _community.vmware.vmware_guest_boot_manager_module:
-
-
-******************************************
-community.vmware.vmware_guest_boot_manager
-******************************************
-
-**Manage boot options for the given virtual machine**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to manage boot options for the given virtual machine.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>boot_delay</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Delay in milliseconds before starting the boot sequence.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>boot_firmware</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>bios</li>
- <li>efi</li>
- </ul>
- </td>
- <td>
- <div>Choose which firmware should be used to boot the virtual machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>boot_hdd_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 3.2.0</div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of disk to be set as boot disk, which is case sensitive, e.g., &#x27;Hard disk 1&#x27;.</div>
- <div>This parameter is optional, if not set, will use the first virtual disk found in VM device list.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>boot_order</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">[]</div>
- </td>
- <td>
- <div>List of the boot devices.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>boot_retry_delay</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Specify the time in milliseconds between virtual machine boot failure and subsequent attempt to boot again.</div>
- <div>If set, will automatically set <code>boot_retry_enabled</code> to <code>true</code> as this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>boot_retry_enabled</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>If set to <code>true</code>, the virtual machine that fails to boot, will try to boot again after <code>boot_retry_delay</code> is expired.</div>
- <div>If set to <code>false</code>, the virtual machine waits indefinitely for user intervention.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>enter_bios_setup</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>If set to <code>true</code>, the virtual machine automatically enters BIOS setup the next time it boots.</div>
- <div>The virtual machine resets this flag, so that the machine boots proceeds normally.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>moid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.</div>
- <div>This is required if <code>name</code> or <code>uuid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the VM to work with.</div>
- <div>This is required if <code>uuid</code> or <code>moid</code> parameter is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name_match</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>first</b>&nbsp;&larr;</div></li>
- <li>last</li>
- </ul>
- </td>
- <td>
- <div>If multiple virtual machines matching the name, use the first or last found.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>secure_boot_enabled</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Choose if EFI secure boot should be enabled. EFI secure boot can only be enabled with boot_firmware = efi</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>use_instance_uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether to use the VMware instance UUID rather than the BIOS UUID.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>UUID of the instance to manage if known, this is VMware&#x27;s BIOS UUID by default.</div>
- <div>This is required if <code>name</code> or <code>moid</code> parameter is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Change virtual machine's boot order and related parameters
- community.vmware.vmware_guest_boot_manager:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- name: testvm
- boot_delay: 2000
- enter_bios_setup: true
- boot_retry_enabled: true
- boot_retry_delay: 22300
- boot_firmware: bios
- secure_boot_enabled: false
- boot_order:
- - floppy
- - cdrom
- - ethernet
- - disk
- delegate_to: localhost
- register: vm_boot_order
-
- - name: Change virtual machine's boot order using Virtual Machine MoID
- community.vmware.vmware_guest_boot_manager:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- moid: vm-42
- boot_delay: 2000
- enter_bios_setup: true
- boot_retry_enabled: true
- boot_retry_delay: 22300
- boot_firmware: bios
- secure_boot_enabled: false
- boot_order:
- - floppy
- - cdrom
- - ethernet
- - disk
- delegate_to: localhost
- register: vm_boot_order
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>vm_boot_status</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about boot order of virtual machine</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;current_boot_order&#x27;: [&#x27;floppy&#x27;, &#x27;disk&#x27;, &#x27;ethernet&#x27;, &#x27;cdrom&#x27;], &#x27;current_boot_delay&#x27;: 2000, &#x27;current_boot_retry_delay&#x27;: 22300, &#x27;current_boot_retry_enabled&#x27;: True, &#x27;current_enter_bios_setup&#x27;: True, &#x27;current_boot_firmware&#x27;: &#x27;bios&#x27;, &#x27;current_secure_boot_enabled&#x27;: False, &#x27;previous_boot_delay&#x27;: 10, &#x27;previous_boot_retry_delay&#x27;: 10000, &#x27;previous_boot_retry_enabled&#x27;: True, &#x27;previous_enter_bios_setup&#x27;: False, &#x27;previous_boot_firmware&#x27;: &#x27;efi&#x27;, &#x27;previous_secure_boot_enabled&#x27;: True, &#x27;previous_boot_order&#x27;: [&#x27;ethernet&#x27;, &#x27;cdrom&#x27;, &#x27;floppy&#x27;, &#x27;disk&#x27;]}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde) <akasurde@redhat.com>
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_controller_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_controller_module.rst
deleted file mode 100644
index f5162b7f9..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_controller_module.rst
+++ /dev/null
@@ -1,522 +0,0 @@
-.. _community.vmware.vmware_guest_controller_module:
-
-
-****************************************
-community.vmware.vmware_guest_controller
-****************************************
-
-**Manage disk or USB controllers related to virtual machine in given vCenter infrastructure**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to add, remove disk controllers or USB controllers belonging to given virtual machine.
-- All parameters and VMware object names are case sensitive.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="2">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>controllers</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>A list of disk or USB controllers to add or remove.</div>
- <div>Total 4 disk controllers with the same type are allowed per VM.</div>
- <div>Total 2 USB controllers are allowed per VM, 1 USB 2.0 and 1 USB 3.0 or 3.1.</div>
- <div>For specific guest OS, supported controller types please refer to VMware Compatibility Guide.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>bus_sharing</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>noSharing</b>&nbsp;&larr;</div></li>
- <li>physicalSharing</li>
- <li>virtualSharing</li>
- </ul>
- </td>
- <td>
- <div>Bus sharing type for SCSI controller.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>controller_number</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>0</li>
- <li>1</li>
- <li>2</li>
- <li>3</li>
- </ul>
- </td>
- <td>
- <div>Disk controller bus number. When <code>state</code> is set to <code>absent</code>, this parameter is required.</div>
- <div>When <code>type</code> set to <code>usb2</code> or <code>usb3</code>, this parameter is not required.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>present</li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>Add new controller or remove specified existing controller.</div>
- <div>If <code>state</code> is set to <code>absent</code>, the specified controller will be removed from virtual machine when there is no disk or device attaching to it.</div>
- <div>If specified controller is removed or not exist, no action will be taken only warning message.</div>
- <div>If <code>state</code> is set to <code>present</code>, new controller with specified type will be added.</div>
- <div>If the number of controller with specified controller type reaches it&#x27;s maximum, no action will be taken only warning message.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>type</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>buslogic</li>
- <li>lsilogic</li>
- <li>lsilogicsas</li>
- <li>paravirtual</li>
- <li>sata</li>
- <li>nvme</li>
- <li>usb2</li>
- <li>usb3</li>
- </ul>
- </td>
- <td>
- <div>Type of disk or USB controller.</div>
- <div>From vSphere 6.5 and virtual machine with hardware version 13, <code>nvme</code> controller starts to be supported.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">"ha-datacenter"</div>
- </td>
- <td>
- <div>The datacenter name to which virtual machine belongs to.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>folder</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Destination folder, absolute or relative path to find an existing guest.</div>
- <div>This is a required parameter, only if multiple VMs are found with same name.</div>
- <div>The folder should include the datacenter. ESX&#x27;s datacenter is ha-datacenter</div>
- <div>Examples:</div>
- <div>folder: /ha-datacenter/vm</div>
- <div>folder: ha-datacenter/vm</div>
- <div>folder: /datacenter1/vm</div>
- <div>folder: datacenter1/vm</div>
- <div>folder: /datacenter1/vm/folder1</div>
- <div>folder: datacenter1/vm/folder1</div>
- <div>folder: /folder1/datacenter1/vm</div>
- <div>folder: folder1/datacenter1/vm</div>
- <div>folder: /folder1/datacenter1/vm/folder2</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>gather_disk_controller_facts</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether to collect existing disk and USB controllers facts only.</div>
- <div>When this parameter is set to <code>true</code>, <code>controllers</code> parameter will be ignored.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>moid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.</div>
- <div>This is required if <code>name</code> or <code>uuid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the virtual machine.</div>
- <div>This is a required parameter, if parameter <code>uuid</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>sleep_time</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">10</div>
- </td>
- <td>
- <div>The sleep time in seconds after VM reconfigure task completes, used when not get the updated VM controller facts after VM reconfiguration.</div>
- <div>This parameter is not required. Maximum value is 600.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>use_instance_uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether to use the VMware instance UUID rather than the BIOS UUID.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>UUID of the instance to gather facts if known, this is VMware&#x27;s unique identifier.</div>
- <div>This is a required parameter, if parameter <code>name</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Add disk and USB 3.0 controllers for virtual machine located by name
- community.vmware.vmware_guest_controller:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- name: test_VM
- controllers:
- - state: present
- type: sata
- - state: present
- type: nvme
- - state: present
- type: usb3
- delegate_to: localhost
- register: disk_controller_facts
-
- - name: Remove disk controllers and USB 2.0 from virtual machine located by moid
- community.vmware.vmware_guest_controller:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- moid: vm-33
- controllers:
- - state: absent
- controller_number: 1
- type: sata
- - state: absent
- controller_number: 0
- type: nvme
- - state: absent
- type: usb2
- delegate_to: localhost
- register: disk_controller_facts
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>disk_controller_status</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about the virtual machine&#x27;s existing disk controllers or after adding or removing operation</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;nvme&#x27;: {&#x27;0&#x27;: {&#x27;controller_busnumber&#x27;: 0, &#x27;controller_controllerkey&#x27;: 100, &#x27;controller_devicekey&#x27;: 31000, &#x27;controller_disks_devicekey&#x27;: [], &#x27;controller_label&#x27;: &#x27;NVME controller 0&#x27;, &#x27;controller_summary&#x27;: &#x27;NVME controller 0&#x27;, &#x27;controller_unitnumber&#x27;: 30}}, &#x27;sata&#x27;: {&#x27;0&#x27;: {&#x27;controller_busnumber&#x27;: 0, &#x27;controller_controllerkey&#x27;: 100, &#x27;controller_devicekey&#x27;: 15000, &#x27;controller_disks_devicekey&#x27;: [16000, 16001], &#x27;controller_label&#x27;: &#x27;SATA controller 0&#x27;, &#x27;controller_summary&#x27;: &#x27;AHCI&#x27;, &#x27;controller_unitnumber&#x27;: 24}}, &#x27;scsi&#x27;: {&#x27;0&#x27;: {&#x27;controller_busnumber&#x27;: 0, &#x27;controller_controllerkey&#x27;: 100, &#x27;controller_devicekey&#x27;: 1000, &#x27;controller_disks_devicekey&#x27;: [2000], &#x27;controller_label&#x27;: &#x27;SCSI controller 0&#x27;, &#x27;controller_summary&#x27;: &#x27;LSI Logic SAS&#x27;, &#x27;controller_unitnumber&#x27;: 3, &#x27;controller_bus_sharing&#x27;: &#x27;noSharing&#x27;}, &#x27;1&#x27;: {&#x27;controller_busnumber&#x27;: 1, &#x27;controller_controllerkey&#x27;: 100, &#x27;controller_devicekey&#x27;: 1001, &#x27;controller_disks_devicekey&#x27;: [], &#x27;controller_label&#x27;: &#x27;SCSI controller 1&#x27;, &#x27;controller_summary&#x27;: &#x27;VMware paravirtual SCSI&#x27;, &#x27;controller_unitnumber&#x27;: 4, &#x27;controller_bus_sharing&#x27;: &#x27;physicalSharing&#x27;}}, &#x27;usb2&#x27;: {&#x27;0&#x27;: {&#x27;controller_busnumber&#x27;: 0, &#x27;controller_controllerkey&#x27;: 100, &#x27;controller_devicekey&#x27;: 7000, &#x27;controller_disks_devicekey&#x27;: [], &#x27;controller_label&#x27;: &#x27;USB Controller&#x27;, &#x27;controller_summary&#x27;: &#x27;Auto connect Disabled&#x27;, &#x27;controller_unitnumber&#x27;: 22}}}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Diane Wang (@Tomorrow9) <dianew@vmware.com>
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_cross_vc_clone_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_cross_vc_clone_module.rst
deleted file mode 100644
index f501d06ec..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_cross_vc_clone_module.rst
+++ /dev/null
@@ -1,566 +0,0 @@
-.. _community.vmware.vmware_guest_cross_vc_clone_module:
-
-
-********************************************
-community.vmware.vmware_guest_cross_vc_clone
-********************************************
-
-**Cross-vCenter VM/template clone**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used for Cross-vCenter vm/template clone
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>destination_datastore</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the destination datastore or the datastore cluster.</div>
- <div>If datastore cluster name is specified, we will find the Storage DRS recommended datastore in that cluster.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>destination_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the destination host.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>destination_resource_pool</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Destination resource pool.</div>
- <div>If not provided, the destination host&#x27;s parent&#x27;s resource pool will be used.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>destination_vcenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the destination VCenter.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>destination_vcenter_password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the destination VCenter.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>destination_vcenter_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port to establish connection in the destination VCenter.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>destination_vcenter_username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the destination VCenter.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>destination_vcenter_validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Parameter to indicate if certification validation needs to be done on destination VCenter.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>destination_vm_folder</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Destination folder, absolute path to deploy the cloned vm.</div>
- <div>This parameter is case sensitive.</div>
- <div>Examples:</div>
- <div>folder: vm</div>
- <div>folder: ha-datacenter/vm</div>
- <div>folder: /datacenter1/vm</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>destination_vm_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the cloned VM.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>is_template</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Specifies whether or not the new virtual machine should be marked as a template.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>moid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Managed Object ID of the vm/template instance to manage if known, this is a unique identifier only within a single vCenter instance.</div>
- <div>This is required if <code>name</code> or <code>uuid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the virtual machine or template.</div>
- <div>This is a required parameter, if parameter <code>uuid</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>poweredon</li>
- </ul>
- </td>
- <td>
- <div>The state of Virtual Machine deployed.</div>
- <div>If set to <code>present</code> and VM does not exists, then VM is created.</div>
- <div>If set to <code>present</code> and VM exists, no action is taken.</div>
- <div>If set to <code>poweredon</code> and VM does not exists, then VM is created with powered on state.</div>
- <div>If set to <code>poweredon</code> and VM exists, no action is taken.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>timeout</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 3.5.0</div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">3600</div>
- </td>
- <td>
- <div>The timeout in seconds. When the timeout is reached, the module will fail.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>use_instance_uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether to use the VMware instance UUID rather than the BIOS UUID.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>UUID of the vm/template instance to clone from, this is VMware&#x27;s unique identifier.</div>
- <div>This is a required parameter, if parameter <code>name</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- # Clone template
- - name: clone a template across VC
- community.vmware.vmware_guest_cross_vc_clone:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- name: "test_vm1"
- destination_vm_name: "cloned_vm_from_template"
- destination_vcenter: '{{ destination_vcenter_hostname }}'
- destination_vcenter_username: '{{ destination_vcenter_username }}'
- destination_vcenter_password: '{{ destination_vcenter_password }}'
- destination_vcenter_port: '{{ destination_vcenter_port }}'
- destination_vcenter_validate_certs: '{{ destination_vcenter_validate_certs }}'
- destination_host: '{{ destination_esxi }}'
- destination_datastore: '{{ destination_datastore }}'
- destination_vm_folder: '{{ destination_vm_folder }}'
- state: present
- register: cross_vc_clone_from_template
-
- - name: clone a VM across VC
- community.vmware.vmware_guest_cross_vc_clone:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: "{{ vcenter_password }}"
- name: "test_vm1"
- destination_vm_name: "cloned_vm_from_vm"
- destination_vcenter: '{{ destination_vcenter_hostname }}'
- destination_vcenter_username: '{{ destination_vcenter_username }}'
- destination_vcenter_password: '{{ destination_vcenter_password }}'
- destination_host: '{{ destination_esxi }}'
- destination_datastore: '{{ destination_datastore }}'
- destination_vm_folder: '{{ destination_vm_folder }}'
- state: poweredon
- register: cross_vc_clone_from_vm
-
- - name: check_mode support
- community.vmware.vmware_guest_cross_vc_clone:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: "{{ vcenter_password }}"
- name: "test_vm1"
- destination_vm_name: "cloned_vm_from_vm"
- destination_vcenter: '{{ destination_vcenter_hostname }}'
- destination_vcenter_username: '{{ destination_vcenter_username }}'
- destination_vcenter_password: '{{ destination_vcenter_password }}'
- destination_host: '{{ destination_esxi }}'
- destination_datastore: '{{ destination_datastore }}'
- destination_vm_folder: '{{ destination_vm_folder }}'
- check_mode: true
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>vm_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about the virtual machine</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;vm_name&#x27;: &#x27;&#x27;, &#x27;vcenter&#x27;: &#x27;&#x27;, &#x27;host&#x27;: &#x27;&#x27;, &#x27;datastore&#x27;: &#x27;&#x27;, &#x27;vm_folder&#x27;: &#x27;&#x27;, &#x27;power_on&#x27;: &#x27;&#x27;}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Anusha Hegde (@anusha94)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_custom_attribute_defs_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_custom_attribute_defs_module.rst
deleted file mode 100644
index 3fa560e1c..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_custom_attribute_defs_module.rst
+++ /dev/null
@@ -1,281 +0,0 @@
-.. _community.vmware.vmware_guest_custom_attribute_defs_module:
-
-
-***************************************************
-community.vmware.vmware_guest_custom_attribute_defs
-***************************************************
-
-**Manage custom attributes definitions for virtual machine from VMware**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to add and remove custom attributes definitions for the given virtual machine from VMware.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>attribute_key</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the custom attribute definition.</div>
- <div>This is required parameter, if <code>state</code> is set to <code>present</code> or <code>absent</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>Manage definition of custom attributes.</div>
- <div>If set to <code>present</code> and definition not present, then custom attribute definition is created.</div>
- <div>If set to <code>present</code> and definition is present, then no action taken.</div>
- <div>If set to <code>absent</code> and definition is present, then custom attribute definition is removed.</div>
- <div>If set to <code>absent</code> and definition is absent, then no action taken.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Add VMware Attribute Definition
- community.vmware.vmware_guest_custom_attribute_defs:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- state: present
- attribute_key: custom_attr_def_1
- delegate_to: localhost
- register: defs
-
- - name: Remove VMware Attribute Definition
- community.vmware.vmware_guest_custom_attribute_defs:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- state: absent
- attribute_key: custom_attr_def_1
- delegate_to: localhost
- register: defs
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>custom_attribute_defs</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>list of all current attribute definitions</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">[&#x27;sample_5&#x27;, &#x27;sample_4&#x27;]</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Jimmy Conner (@cigamit)
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_custom_attributes_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_custom_attributes_module.rst
deleted file mode 100644
index 33423baa9..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_custom_attributes_module.rst
+++ /dev/null
@@ -1,446 +0,0 @@
-.. _community.vmware.vmware_guest_custom_attributes_module:
-
-
-***********************************************
-community.vmware.vmware_guest_custom_attributes
-***********************************************
-
-**Manage custom attributes from VMware for the given virtual machine**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to add, remove and update custom attributes for the given virtual machine.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="2">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>attributes</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">[]</div>
- </td>
- <td>
- <div>A list of name and value of custom attributes that needs to be manage.</div>
- <div>Value of custom attribute is not required and will be ignored, if <code>state</code> is set to <code>absent</code>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the attribute.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>value</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">""</div>
- </td>
- <td>
- <div>Value of the attribute.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Datacenter name where the virtual machine is located in.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>folder</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Absolute path to find an existing guest.</div>
- <div>This is required parameter, if <code>name</code> is supplied and multiple virtual machines with same name are found.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>moid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.</div>
- <div>This is required if <code>name</code> or <code>uuid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the virtual machine to work with.</div>
- <div>This is required parameter, if <code>uuid</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>The action to take.</div>
- <div>If set to <code>present</code>, then custom attribute is added or updated.</div>
- <div>If set to <code>absent</code>, then custom attribute value is removed.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>use_instance_uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether to use the VMware instance UUID rather than the BIOS UUID.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>UUID of the virtual machine to manage if known. This is VMware&#x27;s unique identifier.</div>
- <div>This is required parameter, if <code>name</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Add virtual machine custom attributes
- community.vmware.vmware_guest_custom_attributes:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- uuid: 421e4592-c069-924d-ce20-7e7533fab926
- state: present
- attributes:
- - name: MyAttribute
- value: MyValue
- delegate_to: localhost
- register: attributes
-
- - name: Add multiple virtual machine custom attributes
- community.vmware.vmware_guest_custom_attributes:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- uuid: 421e4592-c069-924d-ce20-7e7533fab926
- state: present
- attributes:
- - name: MyAttribute
- value: MyValue
- - name: MyAttribute2
- value: MyValue2
- delegate_to: localhost
- register: attributes
-
- - name: Remove virtual machine Attribute
- community.vmware.vmware_guest_custom_attributes:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- uuid: 421e4592-c069-924d-ce20-7e7533fab926
- state: absent
- attributes:
- - name: MyAttribute
- delegate_to: localhost
- register: attributes
-
- - name: Remove virtual machine Attribute using Virtual Machine MoID
- community.vmware.vmware_guest_custom_attributes:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- moid: vm-42
- state: absent
- attributes:
- - name: MyAttribute
- delegate_to: localhost
- register: attributes
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>custom_attributes</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about the virtual machine attributes</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;mycustom&#x27;: &#x27;my_custom_value&#x27;, &#x27;mycustom_2&#x27;: &#x27;my_custom_value_2&#x27;, &#x27;sample_1&#x27;: &#x27;sample_1_value&#x27;, &#x27;sample_2&#x27;: &#x27;sample_2_value&#x27;, &#x27;sample_3&#x27;: &#x27;sample_3_value&#x27;}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Jimmy Conner (@cigamit)
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_customization_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_customization_info_module.rst
deleted file mode 100644
index c0a6f54a3..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_customization_info_module.rst
+++ /dev/null
@@ -1,254 +0,0 @@
-.. _community.vmware.vmware_guest_customization_info_module:
-
-
-************************************************
-community.vmware.vmware_guest_customization_info
-************************************************
-
-**Gather info about VM customization specifications**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to gather information about customization specifications.
-- All parameters and VMware object names are case sensitive.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>spec_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of customization specification to find.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Gather info about all customization specification
- community.vmware.vmware_guest_customization_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- delegate_to: localhost
- register: all_custom_spec_info
-
- - name: Gather info about customization specification with the given name
- community.vmware.vmware_guest_customization_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- spec_name: custom_linux_spec
- delegate_to: localhost
- register: custom_spec_info
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>custom_spec_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about the customization specification</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;assignip-eee0d684-44b7-457c-8c55-2585590b0d99&#x27;: {&#x27;change_version&#x27;: &#x27;1523438001&#x27;, &#x27;description&#x27;: &#x27;sample description&#x27;, &#x27;dns_server_list&#x27;: [], &#x27;dns_suffix_list&#x27;: [], &#x27;domain&#x27;: &#x27;None&#x27;, &#x27;hostname&#x27;: &#x27;sample1&#x27;, &#x27;hw_clock_utc&#x27;: None, &#x27;last_updated_time&#x27;: &#x27;2018-04-11T09:13:21+00:00&#x27;, &#x27;name&#x27;: &#x27;sample&#x27;, &#x27;nic_setting_map&#x27;: [{&#x27;dns_domain&#x27;: None, &#x27;gateway&#x27;: [], &#x27;ip_address&#x27;: &#x27;192.168.10.10&#x27;, &#x27;net_bios&#x27;: None, &#x27;nic_dns_server_list&#x27;: [], &#x27;primary_wins&#x27;: None, &#x27;secondry_wins&#x27;: None, &#x27;subnet_mask&#x27;: &#x27;255.255.255.0&#x27;}], &#x27;time_zone&#x27;: None, &#x27;type&#x27;: &#x27;Linux&#x27;}}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_disk_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_disk_info_module.rst
deleted file mode 100644
index ed49d9742..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_disk_info_module.rst
+++ /dev/null
@@ -1,362 +0,0 @@
-.. _community.vmware.vmware_guest_disk_info_module:
-
-
-***************************************
-community.vmware.vmware_guest_disk_info
-***************************************
-
-**Gather info about disks of given virtual machine**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to gather information about disks belonging to given virtual machine.
-- All parameters and VMware object names are case sensitive.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The datacenter name to which virtual machine belongs to.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>folder</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Destination folder, absolute or relative path to find an existing guest.</div>
- <div>This is required parameter, only if multiple VMs are found with same name.</div>
- <div>The folder should include the datacenter. ESX&#x27;s datacenter is ha-datacenter</div>
- <div>Examples:</div>
- <div>folder: /ha-datacenter/vm</div>
- <div>folder: ha-datacenter/vm</div>
- <div>folder: /datacenter1/vm</div>
- <div>folder: datacenter1/vm</div>
- <div>folder: /datacenter1/vm/folder1</div>
- <div>folder: datacenter1/vm/folder1</div>
- <div>folder: /folder1/datacenter1/vm</div>
- <div>folder: folder1/datacenter1/vm</div>
- <div>folder: /folder1/datacenter1/vm/folder2</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>moid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.</div>
- <div>This is required if <code>name</code> or <code>uuid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the virtual machine.</div>
- <div>This is required parameter, if parameter <code>uuid</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>use_instance_uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether to use the VMware instance UUID rather than the BIOS UUID.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>UUID of the instance to gather information if known, this is VMware&#x27;s unique identifier.</div>
- <div>This is required parameter, if parameter <code>name</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Gather disk info from virtual machine using UUID
- community.vmware.vmware_guest_disk_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: ha-datacenter
- uuid: 421e4592-c069-924d-ce20-7e7533fab926
- delegate_to: localhost
- register: disk_info
-
- - name: Gather disk info from virtual machine using name
- community.vmware.vmware_guest_disk_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: ha-datacenter
- name: VM_225
- delegate_to: localhost
- register: disk_info
-
- - name: Gather disk info from virtual machine using moid
- community.vmware.vmware_guest_disk_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: ha-datacenter
- moid: vm-42
- delegate_to: localhost
- register: disk_info
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>guest_disk_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about the virtual machine&#x27;s disks</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;0&#x27;: {&#x27;backing_datastore&#x27;: &#x27;datastore2&#x27;, &#x27;backing_disk_mode&#x27;: &#x27;persistent&#x27;, &#x27;backing_diskmode&#x27;: &#x27;persistent&#x27;, &#x27;backing_eagerlyscrub&#x27;: False, &#x27;backing_filename&#x27;: &#x27;[datastore2] VM_225/VM_225.vmdk&#x27;, &#x27;backing_thinprovisioned&#x27;: False, &#x27;backing_type&#x27;: &#x27;FlatVer2&#x27;, &#x27;backing_writethrough&#x27;: False, &#x27;backing_uuid&#x27;: &#x27;200C3A00-f82a-97af-02ff-62a595f0020a&#x27;, &#x27;capacity_in_bytes&#x27;: 10485760, &#x27;capacity_in_kb&#x27;: 10240, &#x27;controller_bus_number&#x27;: 0, &#x27;controller_key&#x27;: 1000, &#x27;controller_type&#x27;: &#x27;paravirtual&#x27;, &#x27;key&#x27;: 2000, &#x27;label&#x27;: &#x27;Hard disk 1&#x27;, &#x27;summary&#x27;: &#x27;10,240 KB&#x27;, &#x27;unit_number&#x27;: 0}, &#x27;1&#x27;: {&#x27;backing_datastore&#x27;: &#x27;datastore3&#x27;, &#x27;backing_devicename&#x27;: &#x27;vml.012345678901234567890123456789012345678901234567890123&#x27;, &#x27;backing_disk_mode&#x27;: &#x27;independent_persistent&#x27;, &#x27;backing_diskmode&#x27;: &#x27;independent_persistent&#x27;, &#x27;backing_filename&#x27;: &#x27;[datastore3] VM_226/VM_226.vmdk&#x27;, &#x27;backing_lunuuid&#x27;: &#x27;012345678901234567890123456789012345678901234567890123&#x27;, &#x27;backing_type&#x27;: &#x27;RawDiskMappingVer1&#x27;, &#x27;backing_uuid&#x27;: None, &#x27;capacity_in_bytes&#x27;: 15728640, &#x27;capacity_in_kb&#x27;: 15360, &#x27;controller_bus_number&#x27;: 0, &#x27;controller_key&#x27;: 1000, &#x27;controller_type&#x27;: &#x27;paravirtual&#x27;, &#x27;key&#x27;: 2001, &#x27;label&#x27;: &#x27;Hard disk 3&#x27;, &#x27;summary&#x27;: &#x27;15,360 KB&#x27;, &#x27;unit_number&#x27;: 1}}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde) <akasurde@redhat.com>
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_disk_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_disk_module.rst
deleted file mode 100644
index fd020db09..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_disk_module.rst
+++ /dev/null
@@ -1,1210 +0,0 @@
-.. _community.vmware.vmware_guest_disk_module:
-
-
-**********************************
-community.vmware.vmware_guest_disk
-**********************************
-
-**Manage disks related to virtual machine in given vCenter infrastructure**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to add, remove and update disks belonging to given virtual machine.
-- All parameters and VMware object names are case sensitive.
-- This module is destructive in nature, please read documentation carefully before proceeding.
-- Be careful while removing disk specified as this may lead to data loss.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="4">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="4">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The datacenter name to which virtual machine belongs to.</div>
- </td>
- </tr>
- <tr>
- <td colspan="4">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>disk</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">[]</div>
- </td>
- <td>
- <div>A list of disks to add or remove.</div>
- <div>The virtual disk related information is provided using this list.</div>
- <div>All values and parameters are case sensitive.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>autoselect_datastore</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Select the less used datastore. Specify only if <code>datastore</code> is not specified.</div>
- <div>Not applicable when disk <code>type</code> is set to <code>vpmemdisk</code>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>bus_sharing</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>noSharing</b>&nbsp;&larr;</div></li>
- <li>physicalSharing</li>
- <li>virtualSharing</li>
- </ul>
- </td>
- <td>
- <div>Only functions with Paravirtual SCSI Controller.</div>
- <div>Allows for the sharing of the scsi bus between two virtual machines.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_disk</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>This value allows for the sharing of an RDM between two machines.</div>
- <div>The primary machine holding the RDM uses the default <code>false</code>.</div>
- <div>The secondary machine holding the RDM uses <code>true</code>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>compatibility_mode</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>physicalMode</li>
- <li>virtualMode</li>
- </ul>
- </td>
- <td>
- <div>Compatibility mode for raw devices. Required when disk type <code>type</code> is set to <code>rdm</code>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>controller_number</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>0</li>
- <li>1</li>
- <li>2</li>
- <li>3</li>
- </ul>
- </td>
- <td>
- <div>This parameter is used with <code>controller_type</code> for specifying controller bus number.</div>
- <div>For <code>ide</code> controller type, valid value is 0 or 1.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>controller_type</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>buslogic</li>
- <li>lsilogic</li>
- <li>lsilogicsas</li>
- <li>paravirtual</li>
- <li>sata</li>
- <li>nvme</li>
- <li>ide</li>
- </ul>
- </td>
- <td>
- <div>This parameter is added for managing disks attaching other types of controllers, e.g., SATA or NVMe.</div>
- <div>If either <code>controller_type</code> or <code>scsi_type</code> is not specified, then use <code>paravirtual</code> type.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datastore</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of datastore or datastore cluster to be used for the disk.</div>
- <div>Not applicable when disk <code>type</code> is set to <code>vpmemdisk</code>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>destroy</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>If <code>state</code> is <code>absent</code>, make sure the disk file is deleted from the datastore. Added in version 2.10.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>disk_mode</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>persistent</li>
- <li>independent_persistent</li>
- <li>independent_nonpersistent</li>
- </ul>
- </td>
- <td>
- <div>Type of disk mode. If not specified then use <code>persistent</code> mode for new disk.</div>
- <div>If set to &#x27;persistent&#x27; mode, changes are immediately and permanently written to the virtual disk.</div>
- <div>If set to &#x27;independent_persistent&#x27; mode, same as persistent, but not affected by snapshots.</div>
- <div>If set to &#x27;independent_nonpersistent&#x27; mode, changes to virtual disk are made to a redo log and discarded at power off, but not affected by snapshots.</div>
- <div>Not applicable when disk <code>type</code> is set to <code>vpmemdisk</code>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>filename</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Existing disk image to be used. Filename must already exist on the datastore.</div>
- <div>Specify filename string in <code>[datastore_name] path/to/file.vmdk</code> format. Added in version 2.10.</div>
- <div>Not applicable when disk <code>type</code> is set to <code>vpmemdisk</code>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>iolimit</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Section specifies the shares and limit for storage I/O resource.</div>
- <div>Not applicable when disk <code>type</code> is set to <code>vpmemdisk</code>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>limit</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Section specifies values for limit where the utilization of a virtual machine will not exceed, even if there are available resources.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>shares</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Specifies different types of shares user can add for the given disk.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>level</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>low</li>
- <li>normal</li>
- <li>high</li>
- <li>custom</li>
- </ul>
- </td>
- <td>
- <div>Specifies different level for the shares section.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>level_value</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Custom value when <code>level</code> is set as <code>custom</code>.</div>
- </td>
- </tr>
-
-
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>rdm_path</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Path of LUN for Raw Device Mapping required for disk type <code>rdm</code>.</div>
- <div>Only valid if <code>type</code> is set to <code>rdm</code>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>scsi_controller</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>0</li>
- <li>1</li>
- <li>2</li>
- <li>3</li>
- </ul>
- </td>
- <td>
- <div>SCSI controller number. Only 4 SCSI controllers are allowed per VM.</div>
- <div>Care should be taken while specifying &#x27;scsi_controller&#x27; is 0 and &#x27;unit_number&#x27; as 0 as this disk may contain OS.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>scsi_type</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>buslogic</li>
- <li>lsilogic</li>
- <li>lsilogicsas</li>
- <li>paravirtual</li>
- </ul>
- </td>
- <td>
- <div>Type of SCSI controller. This value is required only for the first occurrence of SCSI Controller.</div>
- <div>This value is ignored, if SCSI Controller is already present or <code>state</code> is <code>absent</code>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>shares</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Section for iolimit section tells about what are all different types of shares user can add for disk.</div>
- <div>Not applicable when disk <code>type</code> is set to <code>vpmemdisk</code>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>level</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>low</li>
- <li>normal</li>
- <li>high</li>
- <li>custom</li>
- </ul>
- </td>
- <td>
- <div>Tells about different level for the shares section.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>level_value</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Custom value when <code>level</code> is set as <code>custom</code>.</div>
- </td>
- </tr>
-
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>sharing</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>The sharing mode of the virtual disk.</div>
- <div>Setting sharing means that multiple virtual machines can write to the virtual disk.</div>
- <div>Sharing can only be set if <code>type</code> is set to <code>eagerzeroedthick</code> or <code>rdm</code>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>size</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Disk storage size.</div>
- <div>If size specified then unit must be specified. There is no space allowed in between size number and unit.</div>
- <div>Only first occurrence in disk element will be considered, even if there are multiple size* parameters available.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>size_gb</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Disk storage size in gb.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>size_kb</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Disk storage size in kb.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>size_mb</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Disk storage size in mb.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>size_tb</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Disk storage size in tb.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>State of disk.</div>
- <div>If set to &#x27;absent&#x27;, disk will be removed permanently from virtual machine configuration and from VMware storage.</div>
- <div>If set to &#x27;present&#x27;, disk will be added if not present at given Controller and Unit Number.</div>
- <div>or disk exists with different size, disk size is increased, reducing disk size is not allowed.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>type</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>thin</li>
- <li>eagerzeroedthick</li>
- <li>thick</li>
- <li>rdm</li>
- <li>vpmemdisk</li>
- </ul>
- </td>
- <td>
- <div>The type of disk, if not specified then use <code>thick</code> type for new disk, no eagerzero.</div>
- <div>The disk type <code>rdm</code> is added in version 1.13.0.</div>
- <div>The disk type <code>vpmemdisk</code> is added in version 2.7.0.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>unit_number</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Disk Unit Number.</div>
- <div>Valid value range from 0 to 15, except 7 for SCSI Controller.</div>
- <div>Valid value range from 0 to 64, except 7 for Paravirtual SCSI Controller on Virtual Hardware version 14 or higher.</div>
- <div>Valid value range from 0 to 29 for SATA controller.</div>
- <div>Valid value range from 0 to 14 for NVME controller.</div>
- <div>Valid value range from 0 to 1 for IDE controller.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="4">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>folder</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Destination folder, absolute or relative path to find an existing guest.</div>
- <div>This is a required parameter, only if multiple VMs are found with same name.</div>
- <div>The folder should include the datacenter. ESX&#x27;s datacenter is ha-datacenter</div>
- <div>Examples:</div>
- <div>folder: /ha-datacenter/vm</div>
- <div>folder: ha-datacenter/vm</div>
- <div>folder: /datacenter1/vm</div>
- <div>folder: datacenter1/vm</div>
- <div>folder: /datacenter1/vm/folder1</div>
- <div>folder: datacenter1/vm/folder1</div>
- <div>folder: /folder1/datacenter1/vm</div>
- <div>folder: folder1/datacenter1/vm</div>
- <div>folder: /folder1/datacenter1/vm/folder2</div>
- </td>
- </tr>
- <tr>
- <td colspan="4">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="4">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>moid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.</div>
- <div>This is required if <code>name</code> or <code>uuid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="4">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the virtual machine.</div>
- <div>This is a required parameter, if parameter <code>uuid</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="4">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="4">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="4">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="4">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="4">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>use_instance_uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether to use the VMware instance UUID rather than the BIOS UUID.</div>
- </td>
- </tr>
- <tr>
- <td colspan="4">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="4">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>UUID of the instance to gather facts if known, this is VMware&#x27;s unique identifier.</div>
- <div>This is a required parameter, if parameter <code>name</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="4">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Add disks to virtual machine using UUID
- community.vmware.vmware_guest_disk:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- uuid: 421e4592-c069-924d-ce20-7e7533fab926
- disk:
- - size_mb: 10
- type: thin
- datastore: datacluster0
- state: present
- scsi_controller: 1
- unit_number: 1
- scsi_type: 'paravirtual'
- disk_mode: 'persistent'
- - size_gb: 10
- type: eagerzeroedthick
- state: present
- autoselect_datastore: true
- scsi_controller: 2
- scsi_type: 'buslogic'
- unit_number: 12
- disk_mode: 'independent_persistent'
- - size: 10Gb
- type: eagerzeroedthick
- state: present
- autoselect_datastore: true
- scsi_controller: 2
- scsi_type: 'buslogic'
- unit_number: 1
- disk_mode: 'independent_nonpersistent'
- - filename: "[datastore1] path/to/existing/disk.vmdk"
- delegate_to: localhost
- register: disk_facts
-
- - name: Add disks with specified shares to the virtual machine
- community.vmware.vmware_guest_disk:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- disk:
- - size_gb: 1
- type: thin
- datastore: datacluster0
- state: present
- scsi_controller: 1
- unit_number: 1
- disk_mode: 'independent_persistent'
- shares:
- level: custom
- level_value: 1300
- delegate_to: localhost
- register: test_custom_shares
-
- - name: Add physical raw device mapping to virtual machine using name
- community.vmware.vmware_guest_disk:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- validate_certs: false
- name: "Test_VM"
- disk:
- - type: rdm
- state: present
- scsi_controller: 1
- unit_number: 5
- rdm_path: /vmfs/devices/disks/naa.060000003b1234efb453
- compatibility_mode: 'physicalMode'
-
- - name: Add virtual raw device mapping to virtual machine using name and virtual mode
- community.vmware.vmware_guest_disk:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- validate_certs: false
- name: "Test_VM"
- disk:
- - type: rdm
- state: present
- scsi_controller: 1
- unit_number: 5
- rdm_path: /vmfs/devices/disks/naa.060000003b1234efb453
- compatibility_mode: 'virtualMode'
- disk_mode: 'persistent'
-
- - name: Add raw device mapping to virtual machine with Physical bus sharing
- community.vmware.vmware_guest_disk:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- validate_certs: false
- name: "Test_VM"
- disk:
- - type: rdm
- state: present
- scsi_controller: 1
- unit_number: 5
- rdm_path: /vmfs/devices/disks/naa.060000003b1234efb453
- compatibility_mode: 'virtualMode'
- disk_mode: 'persistent'
- bus_sharing: physicalSharing
-
- - name: Add raw device mapping to virtual machine with Physical bus sharing and clustered disk
- community.vmware.vmware_guest_disk:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- validate_certs: false
- name: "Test_VM"
- disk:
- - type: rdm
- state: present
- scsi_controller: 1
- unit_number: 5
- compatibility_mode: 'virtualMode'
- disk_mode: 'persistent'
- bus_sharing: physicalSharing
- filename: "[datastore1] path/to/rdm/disk-marker.vmdk"
-
- - name: create new disk with custom IO limits and shares in IO Limits
- community.vmware.vmware_guest_disk:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- disk:
- - size_gb: 1
- type: thin
- datastore: datacluster0
- state: present
- scsi_controller: 1
- unit_number: 1
- disk_mode: 'independent_persistent'
- iolimit:
- limit: 1506
- shares:
- level: custom
- level_value: 1305
- delegate_to: localhost
- register: test_custom_IoLimit_shares
-
- - name: Remove disks from virtual machine using name
- community.vmware.vmware_guest_disk:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- name: VM_225
- disk:
- - state: absent
- scsi_controller: 1
- unit_number: 1
- delegate_to: localhost
- register: disk_facts
-
- - name: Remove disk from virtual machine using moid
- community.vmware.vmware_guest_disk:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- moid: vm-42
- disk:
- - state: absent
- scsi_controller: 1
- unit_number: 1
- delegate_to: localhost
- register: disk_facts
-
- - name: Remove disk from virtual machine but keep the VMDK file on the datastore
- community.vmware.vmware_guest_disk:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- name: VM_225
- disk:
- - state: absent
- scsi_controller: 1
- unit_number: 2
- destroy: false
- delegate_to: localhost
- register: disk_facts
-
- - name: Add disks to virtual machine using UUID to SATA and NVMe controller
- community.vmware.vmware_guest_disk:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- validate_certs: false
- uuid: 421e4592-c069-924d-ce20-7e7533fab926
- disk:
- - size_mb: 256
- type: thin
- datastore: datacluster0
- state: present
- controller_type: sata
- controller_number: 1
- unit_number: 1
- disk_mode: 'persistent'
- - size_gb: 1
- state: present
- autoselect_datastore: true
- controller_type: nvme
- controller_number: 2
- unit_number: 3
- disk_mode: 'independent_persistent'
- delegate_to: localhost
- register: disk_facts
-
- - name: Add a new vPMem disk to virtual machine to SATA controller
- community.vmware.vmware_guest_disk:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- validate_certs: false
- name: VM_226
- disk:
- - type: vpmemdisk
- size_gb: 1
- state: present
- controller_type: sata
- controller_number: 1
- unit_number: 2
- delegate_to: localhost
- register: disk_facts
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>disk_changes</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>result of each task, key is the 0-based index with the same sequence in which the tasks were defined</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;0&#x27;: &#x27;Disk deleted.&#x27;, &#x27;1&#x27;: &#x27;Disk created.&#x27;}</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>disk_data</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about the virtual machine&#x27;s disks after managing them</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;0&#x27;: {&#x27;backing_datastore&#x27;: &#x27;datastore2&#x27;, &#x27;backing_disk_mode&#x27;: &#x27;persistent&#x27;, &#x27;backing_eagerlyscrub&#x27;: False, &#x27;backing_filename&#x27;: &#x27;[datastore2] VM_225/VM_225.vmdk&#x27;, &#x27;backing_thinprovisioned&#x27;: False, &#x27;backing_writethrough&#x27;: False, &#x27;backing_uuid&#x27;: &#x27;421e4592-c069-924d-ce20-7e7533fab926&#x27;, &#x27;capacity_in_bytes&#x27;: 10485760, &#x27;capacity_in_kb&#x27;: 10240, &#x27;controller_key&#x27;: 1000, &#x27;key&#x27;: 2000, &#x27;label&#x27;: &#x27;Hard disk 1&#x27;, &#x27;summary&#x27;: &#x27;10,240 KB&#x27;, &#x27;unit_number&#x27;: 0}}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde) <akasurde@redhat.com>
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_file_operation_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_file_operation_module.rst
deleted file mode 100644
index 6d7754034..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_file_operation_module.rst
+++ /dev/null
@@ -1,631 +0,0 @@
-.. _community.vmware.vmware_guest_file_operation_module:
-
-
-********************************************
-community.vmware.vmware_guest_file_operation
-********************************************
-
-**Files operation in a VMware guest operating system without network**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- Module to copy a file to a VM, fetch a file from a VM and create or delete a directory in the guest OS.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="2">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The cluster hosting the virtual machine.</div>
- <div>If set, it will help to speed up virtual machine search.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>copy</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Copy file to vm without requiring network.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>dest</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>File destination, path must be exist.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>overwrite</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Overwrite or not.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>src</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>File source absolute or relative.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The datacenter hosting the virtual machine.</div>
- <div>If set, it will help to speed up virtual machine search.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>directory</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Create or delete a directory.</div>
- <div>Can be used to create temp directory inside guest using mktemp operation.</div>
- <div>mktemp sets variable <code>dir</code> in the result with the name of the new directory.</div>
- <div>mktemp operation option is added in version 2.8.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>operation</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>create</li>
- <li>delete</li>
- <li>mktemp</li>
- </ul>
- </td>
- <td>
- <div>Operation to perform.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>path</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Directory path.</div>
- <div>Required for <code>create</code> or <code>remove</code>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>prefix</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Temporary directory prefix.</div>
- <div>Required for <code>mktemp</code>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>recurse</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Not required.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>suffix</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Temporary directory suffix.</div>
- <div>Required for <code>mktemp</code>.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>fetch</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Get file from virtual machine without requiring network.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>dest</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>File destination on localhost, path must be exist.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>src</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The file on the remote system to fetch.</div>
- <div>This <em>must</em> be a file, not a directory.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>folder</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Destination folder, absolute path to find an existing guest or create the new guest.</div>
- <div>The folder should include the datacenter. ESX&#x27;s datacenter is ha-datacenter</div>
- <div>Used only if <code>vm_id_type</code> is <code>inventory_path</code>.</div>
- <div>Examples:</div>
- <div>folder: /ha-datacenter/vm</div>
- <div>folder: ha-datacenter/vm</div>
- <div>folder: /datacenter1/vm</div>
- <div>folder: datacenter1/vm</div>
- <div>folder: /datacenter1/vm/folder1</div>
- <div>folder: datacenter1/vm/folder1</div>
- <div>folder: /folder1/datacenter1/vm</div>
- <div>folder: folder1/datacenter1/vm</div>
- <div>folder: /folder1/datacenter1/vm/folder2</div>
- <div>folder: vm/folder2</div>
- <div>folder: folder2</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>timeout</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 3.1.0</div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">100</div>
- </td>
- <td>
- <div>Timeout seconds for fetching or copying a file.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vm_id</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the virtual machine to work with.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vm_id_type</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>uuid</li>
- <li>instance_uuid</li>
- <li>dns_name</li>
- <li>inventory_path</li>
- <li><div style="color: blue"><b>vm_name</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>The VMware identification method by which the virtual machine will be identified.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vm_password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password used to login-in to the virtual machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vm_username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The user to login in to the virtual machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - Only the first match against vm_id is used, even if there are multiple matches
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Create directory inside a vm
- community.vmware.vmware_guest_file_operation:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- vm_id: "{{ guest_name }}"
- vm_username: "{{ guest_username }}"
- vm_password: "{{ guest_userpassword }}"
- directory:
- path: "/test"
- operation: create
- recurse: false
- delegate_to: localhost
-
- - name: copy file to vm
- community.vmware.vmware_guest_file_operation:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- vm_id: "{{ guest_name }}"
- vm_username: "{{ guest_username }}"
- vm_password: "{{ guest_userpassword }}"
- copy:
- src: "files/test.zip"
- dest: "/root/test.zip"
- overwrite: false
- delegate_to: localhost
-
- - name: fetch file from vm
- community.vmware.vmware_guest_file_operation:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- vm_id: "{{ guest_name }}"
- vm_username: "{{ guest_username }}"
- vm_password: "{{ guest_userpassword }}"
- fetch:
- src: "/root/test.zip"
- dest: "files/test.zip"
- delegate_to: localhost
-
- - name: If a timeout error occurs, specify a high(er) timeout value
- community.vmware.vmware_guest_file_operation:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- vm_id: "{{ guest_name }}"
- vm_username: "{{ guest_username }}"
- vm_password: "{{ guest_userpassword }}"
- timeout: 10000
- copy:
- src: "files/test.zip"
- dest: "/root/test.zip"
- overwrite: false
- delegate_to: localhost
-
-
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Stéphane Travassac (@stravassac)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_find_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_find_module.rst
deleted file mode 100644
index 533e3eb2b..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_find_module.rst
+++ /dev/null
@@ -1,290 +0,0 @@
-.. _community.vmware.vmware_guest_find_module:
-
-
-**********************************
-community.vmware.vmware_guest_find
-**********************************
-
-**Find the folder path(s) for a virtual machine by name or UUID**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- Find the folder path(s) for a virtual machine by name or UUID
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the VM to work with.</div>
- <div>This is required if <code>uuid</code> parameter is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>use_instance_uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether to use the VMware instance UUID rather than the BIOS UUID.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>UUID of the instance to manage if known, this is VMware&#x27;s BIOS UUID by default.</div>
- <div>This is required if <code>name</code> parameter is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Find Guest's Folder using name
- community.vmware.vmware_guest_find:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- name: testvm
- delegate_to: localhost
- register: vm_folder
-
- - name: Find Guest's Folder using UUID
- community.vmware.vmware_guest_find:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- uuid: 38c4c89c-b3d7-4ae6-ae4e-43c5118eae49
- delegate_to: localhost
- register: vm_folder
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>folders</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- </div>
- </td>
- <td>on success</td>
- <td>
- <div>List of folders for user specified virtual machine</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">[&#x27;/DC0/vm&#x27;]</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde) <akasurde@redhat.com>
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_info_module.rst
deleted file mode 100644
index 6f61ef5de..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_info_module.rst
+++ /dev/null
@@ -1,499 +0,0 @@
-.. _community.vmware.vmware_guest_info_module:
-
-
-**********************************
-community.vmware.vmware_guest_info
-**********************************
-
-**Gather info about a single VM**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- Gather information about a single VM on a VMware ESX cluster.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Destination datacenter for the deploy operation</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>folder</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Destination folder, absolute or relative path to find an existing guest.</div>
- <div>This is required if name is supplied.</div>
- <div>The folder should include the datacenter. ESX&#x27;s datacenter is ha-datacenter</div>
- <div>Examples:</div>
- <div>folder: /ha-datacenter/vm</div>
- <div>folder: ha-datacenter/vm</div>
- <div>folder: /datacenter1/vm</div>
- <div>folder: datacenter1/vm</div>
- <div>folder: /datacenter1/vm/folder1</div>
- <div>folder: datacenter1/vm/folder1</div>
- <div>folder: /folder1/datacenter1/vm</div>
- <div>folder: folder1/datacenter1/vm</div>
- <div>folder: /folder1/datacenter1/vm/folder2</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>moid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.</div>
- <div>This is required if <code>name</code> or <code>uuid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the VM to work with</div>
- <div>This is required if <code>uuid</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name_match</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>first</b>&nbsp;&larr;</div></li>
- <li>last</li>
- </ul>
- </td>
- <td>
- <div>If multiple VMs matching the name, use the first or last found</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>properties</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Specify the properties to retrieve.</div>
- <div>If not specified, all properties are retrieved (deeply).</div>
- <div>Results are returned in a structure identical to the vsphere API.</div>
- <div>Example:</div>
- <div>properties: [</div>
- <div>&quot;config.hardware.memoryMB&quot;,</div>
- <div>&quot;config.hardware.numCPU&quot;,</div>
- <div>&quot;guest.disk&quot;,</div>
- <div>&quot;overallStatus&quot;</div>
- <div>]</div>
- <div>Only valid when <code>schema</code> is <code>vsphere</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>schema</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>summary</b>&nbsp;&larr;</div></li>
- <li>vsphere</li>
- </ul>
- </td>
- <td>
- <div>Specify the output schema desired.</div>
- <div>The &#x27;summary&#x27; output schema is the legacy output from the module</div>
- <div>The &#x27;vsphere&#x27; output schema is the vSphere API class definition which requires pyvmomi&gt;6.7.1</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>tag_details</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>If set <code>true</code>, detail information about &#x27;tags&#x27; returned.</div>
- <div>Without this flag, the &#x27;tags&#x27; returns a list of tag names.</div>
- <div>With this flag, the &#x27;tags&#x27; returns a list of dict about tag information with additional details like category name, category id, and tag id.</div>
- <div>This parameter is added to maintain backward compatability.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>tags</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether to show tags or not.</div>
- <div>If set <code>true</code>, shows tags information. Returns a list of tag names.</div>
- <div>If set <code>false</code>, hides tags information.</div>
- <div>vSphere Automation SDK is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>use_instance_uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether to use the VMware instance UUID rather than the BIOS UUID.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>UUID of the instance to manage if known, this is VMware&#x27;s unique identifier.</div>
- <div>This is required if <code>name</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Gather info from standalone ESXi server having datacenter as 'ha-datacenter'
- community.vmware.vmware_guest_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: ha-datacenter
- uuid: 421e4592-c069-924d-ce20-7e7533fab926
- delegate_to: localhost
- register: info
-
- - name: Gather some info from a guest using the vSphere API output schema
- community.vmware.vmware_guest_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- name: "{{ vm_name }}"
- schema: "vsphere"
- properties: ["config.hardware.memoryMB", "guest.disk", "overallStatus"]
- delegate_to: localhost
- register: info
-
- - name: Gather some information about a guest using MoID
- community.vmware.vmware_guest_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- moid: vm-42
- schema: "vsphere"
- properties: ["config.hardware.memoryMB", "guest.disk", "overallStatus"]
- delegate_to: localhost
- register: vm_moid_info
-
- - name: Gather Managed object ID (moid) from a guest using the vSphere API output schema for REST Calls
- community.vmware.vmware_guest_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- name: "{{ vm_name }}"
- schema: "vsphere"
- properties:
- - _moId
- delegate_to: localhost
- register: moid_info
-
- - name: Gather detailed information about tags and category associated with the given VM
- community.vmware.vmware_guest_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- name: "{{ vm_name }}"
- tags: true
- tag_details: true
- register: detailed_tag_info
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>instance</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about the virtual machine</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;advanced_settings&#x27;: {}, &#x27;annotation&#x27;: &#x27;&#x27;, &#x27;current_snapshot&#x27;: None, &#x27;customvalues&#x27;: {}, &#x27;guest_consolidation_needed&#x27;: False, &#x27;guest_question&#x27;: None, &#x27;guest_tools_status&#x27;: &#x27;guestToolsNotRunning&#x27;, &#x27;guest_tools_version&#x27;: &#x27;10247&#x27;, &#x27;hw_cores_per_socket&#x27;: 1, &#x27;hw_datastores&#x27;: [&#x27;ds_226_3&#x27;], &#x27;hw_esxi_host&#x27;: &#x27;10.76.33.226&#x27;, &#x27;hw_eth0&#x27;: {&#x27;addresstype&#x27;: &#x27;assigned&#x27;, &#x27;ipaddresses&#x27;: None, &#x27;label&#x27;: &#x27;Network adapter 1&#x27;, &#x27;macaddress&#x27;: &#x27;00:50:56:87:a5:9a&#x27;, &#x27;macaddress_dash&#x27;: &#x27;00-50-56-87-a5-9a&#x27;, &#x27;portgroup_key&#x27;: None, &#x27;portgroup_portkey&#x27;: None, &#x27;summary&#x27;: &#x27;VM Network&#x27;}, &#x27;hw_files&#x27;: [&#x27;[ds_226_3] ubuntu_t/ubuntu_t.vmx&#x27;, &#x27;[ds_226_3] ubuntu_t/ubuntu_t.nvram&#x27;, &#x27;[ds_226_3] ubuntu_t/ubuntu_t.vmsd&#x27;, &#x27;[ds_226_3] ubuntu_t/vmware.log&#x27;, &#x27;[ds_226_3] u0001/u0001.vmdk&#x27;], &#x27;hw_folder&#x27;: &#x27;/DC0/vm/Discovered virtual machine&#x27;, &#x27;hw_guest_full_name&#x27;: None, &#x27;hw_guest_ha_state&#x27;: None, &#x27;hw_guest_id&#x27;: None, &#x27;hw_interfaces&#x27;: [&#x27;eth0&#x27;], &#x27;hw_is_template&#x27;: False, &#x27;hw_memtotal_mb&#x27;: 1024, &#x27;hw_name&#x27;: &#x27;ubuntu_t&#x27;, &#x27;hw_power_status&#x27;: &#x27;poweredOff&#x27;, &#x27;hw_processor_count&#x27;: 1, &#x27;hw_product_uuid&#x27;: &#x27;4207072c-edd8-3bd5-64dc-903fd3a0db04&#x27;, &#x27;hw_version&#x27;: &#x27;vmx-13&#x27;, &#x27;instance_uuid&#x27;: &#x27;5007769d-add3-1e12-f1fe-225ae2a07caf&#x27;, &#x27;ipv4&#x27;: None, &#x27;ipv6&#x27;: None, &#x27;module_hw&#x27;: True, &#x27;snapshots&#x27;: [], &#x27;tags&#x27;: [&#x27;backup&#x27;], &#x27;vnc&#x27;: {}, &#x27;moid&#x27;: &#x27;vm-42&#x27;, &#x27;vimref&#x27;: &#x27;vim.VirtualMachine:vm-42&#x27;}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Loic Blot (@nerzhul) <loic.blot@unix-experience.fr>
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_instant_clone_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_instant_clone_module.rst
deleted file mode 100644
index 0bef2af61..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_instant_clone_module.rst
+++ /dev/null
@@ -1,684 +0,0 @@
-.. _community.vmware.vmware_guest_instant_clone_module:
-
-
-*******************************************
-community.vmware.vmware_guest_instant_clone
-*******************************************
-
-**Instant Clone VM**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used for Creating a powered-on Instant Clone of a virtual machine.
-- All variables and VMware object names are case sensitive.
-- :ref:`community.vmware.vmware_guest <community.vmware.vmware_guest_module>` module is needed for creating a VM with poweredon state which would be used as a parent VM.
-- :ref:`community.vmware.vmware_guest_powerstate <community.vmware.vmware_guest_powerstate_module>` module is also needed to poweroff the instant cloned module.
-- The powered off VM would in turn be deleted by again using :ref:`community.vmware.vmware_guest <community.vmware.vmware_guest_module>` module.
-- Thus :ref:`community.vmware.vmware_guest <community.vmware.vmware_guest_module>` module is necessary for removing Instant Cloned VM when VMs being created in testing environment.
-- Also GuestOS Customization has now been added with guestinfo_vars parameter.
-- The Parent VM must have The Guest customization Engine for instant Clone to customize Guest OS.
-- Only Linux Os in Parent VM enable support for native vSphere Guest Customization for Instant Clone in vSphere 7.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="2">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the datacenter, where VM to be deployed.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datastore</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the datastore or the datastore cluster.</div>
- <div>If datastore cluster name is specified, module will find the Storage DRS recommended datastore in that cluster.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>folder</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Destination folder, absolute path to deploy the cloned vm.</div>
- <div>This parameter is case sensitive.</div>
- <div>Examples:</div>
- <div>folder: ha-datacenter/vm</div>
- <div>folder: /datacenter1/vm</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>guestinfo_vars</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Provides GuestOS Customization functionality in instant cloned VM.</div>
- <div>A list of key value pairs that will be passed to the destination VM.</div>
- <div>These pairs should be used to provide user-defined customization to differentiate the destination VM from the source VM.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>dns</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>dns is used to set the dns in Instant Cloned Guest Operating System..</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>domain</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>domain is used to set A fully qualified domain name (FQDN) or complete domain name for Instant Cloned Guest operating System.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>gateway</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>netmask is used to set the netmask in Instant Cloned Guest Operating System.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>hostname is used to obtain the DNS(Domain Name System) name and set the Guest system&#x27;s hostname.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>ipaddress</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>ipaddress is used to set the ipaddress in Instant Cloned Guest Operating System.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>netmask</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>netmask is used to set the netmask in Instant Cloned Guest Operating System.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the ESX Host in datacenter in which to place cloned VM.</div>
- <div>The host has to be a member of the cluster that contains the resource pool.</div>
- <div>Required with <em>resource_pool</em> to find resource pool details. This will be used as additional information when there are resource pools with same name.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: esxi_hostname</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>moid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Managed Object ID of the vm instance to manage if known, this is a unique identifier only within a single vCenter instance.</div>
- <div>This is required if <code>parent_vm</code> or <code>uuid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the Cloned virtual machine.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: vm_name</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>parent_vm</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the parent virtual machine.</div>
- <div>This is a required parameter, if parameter <code>uuid</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>resource_pool</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the resource pool in datacenter in which to place deployed VM.</div>
- <div>Required if <em>cluster</em> is not specified.</div>
- <div>For default or non-unique resource pool names, specify <em>host</em> and <em>cluster</em>.</div>
- <div><code>Resources</code> is the default name of resource pool.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>use_instance_uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether to use the VMware instance UUID rather than the BIOS UUID.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>UUID of the vm instance to clone from, this is VMware&#x27;s unique identifier.</div>
- <div>This is a required parameter, if parameter <code>parent_vm</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vm_password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password used to login-in to the virtual machine.</div>
- <div>Only required when using guest customization feature.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vm_username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The user to login-in to the virtual machine.</div>
- <div>Only required when using guest customization feature.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>wait_vm_tools</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Whether waiting until vm tools start after rebooting an instant clone vm.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>wait_vm_tools_timeout</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">300</div>
- </td>
- <td>
- <div>Define a timeout (in seconds) for <em>the wait_vm_tools</em> parameter.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Instant Clone a VM
- community.vmware.vmware_guest_instant_clone:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- validate_certs: false
- folder: "{{ f0 }}"
- datastore: "{{ rw_datastore }}"
- datacenter: "{{ dc1 }}"
- host: "{{ esxi1 }}"
- name: "{{ Clone_vm }}"
- parent_vm: "{{ testvm_1 }}"
- resource_pool: "{{ test_resource_001 }}"
- register: vm_clone
- delegate_to: localhost
-
- - name: set state to poweroff the Cloned VM
- community.vmware.vmware_guest_powerstate:
- validate_certs: false
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- name: "cloned_vm_from_vm_cluster"
- folder: "{{ f0 }}"
- state: powered-off
- register: poweroff_instant_clone_from_vm_when_cluster
- delegate_to: localhost
-
- - name: Clean VM
- community.vmware.vmware_guest:
- validate_certs: false
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- name: "cloned_vm_from_vm_cluster"
- datacenter: "{{ dc1 }}"
- state: absent
- register: delete_instant_clone_from_vm_when_cluster
- ignore_errors: true
- delegate_to: localhost
-
- - name: Instant Clone a VM with guest_customization
- community.vmware.vmware_guest_instant_clone:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- vm_username: "root"
- vm_password: "SuperSecret"
- validate_certs: false
- folder: "{{ f0 }}"
- datastore: "{{ rw_datastore }}"
- datacenter: "{{ dc1 }}"
- host: "{{ esxi1 }}"
- guestinfo_vars:
- - hostname: "{{ guestinfo.ic.hostname }}"
- ipaddress: "{{ guestinfo.ic.ipaddress }}"
- netmask: "{{ guestinfo.ic.netmask }}"
- gateway: "{{ guestinfo.ic.gateway }}"
- dns: "{{ guestinfo.ic.dns }}"
- domain: "{{ guestinfo.ic.domain }}"
- name: "Instant_clone_guest_customize"
- parent_vm: "test_vm1"
- resource_pool: DC0_C0_RP1
- register: Instant_cloned_guest_customize
- delegate_to: localhost
-
- - name: Instant Clone a VM when skipping optional params
- community.vmware.vmware_guest_instant_clone:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- validate_certs: false
- name: "{{ Clone_vm }}"
- parent_vm: "{{ testvm_1 }}"
- datacenter: "{{ dc1 }}"
- datastore: "{{ rw_datastore }}"
- host: "{{ esxi1 }}"
- register: VM_clone_optional_arguments
- delegate_to: localhost
-
- - name: Instant clone in check mode
- community.vmware.vmware_guest_instant_clone:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- validate_certs: false
- folder: "{{ f0 }}"
- datastore: "{{ rw_datastore }}"
- datacenter: "{{ dc1 }}"
- host: "{{ esx1 }}"
- name: "{{ Clone_vm }}"
- parent_vm: "{{ testvm_2 }}"
- resource_pool: "{{ test_resource_001 }}"
- check_mode: true
- register: check_mode_clone
- delegate_to: localhost
- - debug:
- var: check_mode_clone
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>vm_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about the virtual machine</div>
- <div>added instance_uuid from version 1.12.0</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;vm_name&#x27;: &#x27;&#x27;, &#x27;vcenter&#x27;: &#x27;&#x27;, &#x27;host&#x27;: &#x27;&#x27;, &#x27;datastore&#x27;: &#x27;&#x27;, &#x27;vm_folder&#x27;: &#x27;&#x27;, &#x27;instance_uuid&#x27;: &#x27;&#x27;}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Anant Chopra (@Anant99-sys)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_module.rst
deleted file mode 100644
index d533b181b..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_module.rst
+++ /dev/null
@@ -1,2763 +0,0 @@
-.. _community.vmware.vmware_guest_module:
-
-
-*****************************
-community.vmware.vmware_guest
-*****************************
-
-**Manages virtual machines in vCenter**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to create new virtual machines from templates or other virtual machines, manage power state of virtual machine such as power on, power off, suspend, shutdown, reboot, restart etc., modify various virtual machine components like network, disk, customization etc., rename a virtual machine and remove a virtual machine with associated components.
-
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="2">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>advanced_settings</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">[]</div>
- </td>
- <td>
- <div>Define a list of advanced settings to be added to the VMX config.</div>
- <div>An advanced settings object takes two fields <code>key</code> and <code>value</code>.</div>
- <div>Incorrect key and values will be ignored.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>annotation</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>A note or annotation to include in the virtual machine.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: notes</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cdrom</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">raw</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">[]</div>
- </td>
- <td>
- <div>A list of CD-ROM configurations for the virtual machine. Added in version 2.9.</div>
- <div>Providing CD-ROM configuration as dict is deprecated and will be removed VMware collection 4.0.0. Please use a list instead.</div>
- <div>Parameters <code>controller_type</code>, <code>controller_number</code>, <code>unit_number</code>, <code>state</code> are added for a list of CD-ROMs configuration support.</div>
- <div>For <code>ide</code> controller, hot-add or hot-remove CD-ROM is not supported.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>controller_number</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>For <code>ide</code> controller, valid value is 0 or 1.</div>
- <div>For <code>sata</code> controller, valid value is 0 to 3.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>controller_type</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Valid options are <code>ide</code> and <code>sata</code>.</div>
- <div>Default value is <code>ide</code>.</div>
- <div>When set to <code>sata</code>, please make sure <code>unit_number</code> is correct and not used by SATA disks.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>iso_path</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The datastore path to the ISO file to use, in the form of <code>[datastore1] path/to/file.iso</code>.</div>
- <div>Required if type is set <code>iso</code>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Valid value is <code>present</code> or <code>absent</code>.</div>
- <div>Default is <code>present</code>.</div>
- <div>If set to <code>absent</code>, then the specified CD-ROM will be removed.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>type</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The type of CD-ROM, valid options are <code>none</code>, <code>client</code> or <code>iso</code>.</div>
- <div>With <code>none</code> the CD-ROM will be disconnected but present.</div>
- <div>The default value is <code>client</code>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>unit_number</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>For CD-ROM device attach to <code>ide</code> controller, valid value is 0 or 1.</div>
- <div>For CD-ROM device attach to <code>sata</code> controller, valid value is 0 to 29.</div>
- <div><code>controller_number</code> and <code>unit_number</code> are mandatory attributes.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The cluster name where the virtual machine will run.</div>
- <div>This is a required parameter, if <code>esxi_hostname</code> is not set.</div>
- <div><code>esxi_hostname</code> and <code>cluster</code> are mutually exclusive parameters.</div>
- <div>This parameter is case sensitive.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>convert</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>thin</li>
- <li>thick</li>
- <li>eagerzeroedthick</li>
- </ul>
- </td>
- <td>
- <div>Specify convert disk type while cloning template or virtual machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>customization</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">{}</div>
- </td>
- <td>
- <div>Parameters for OS customization when cloning from the template or the virtual machine, or apply to the existing virtual machine directly.</div>
- <div>Not all operating systems are supported for customization with respective vCenter version, please check VMware documentation for respective OS customization.</div>
- <div>For supported customization operating system matrix, (see <a href='http://partnerweb.vmware.com/programs/guestOS/guest-os-customization-matrix.pdf'>http://partnerweb.vmware.com/programs/guestOS/guest-os-customization-matrix.pdf</a>)</div>
- <div>All parameters and VMware object names are case sensitive.</div>
- <div>Linux based OSes requires Perl package to be installed for OS customizations.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>autologon</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Auto logon after virtual machine customization.</div>
- <div>Specific to Windows customization.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>autologoncount</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Number of autologon after reboot.</div>
- <div>Specific to Windows customization.</div>
- <div>Ignored if <code>autologon</code> is unset or set to <code>false</code>.</div>
- <div>If unset, 1 will be used.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>dns_servers</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>List of DNS servers to configure.</div>
- <div>Common for Linux and Windows customization.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>dns_suffix</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>List of domain suffixes, also known as DNS search path.</div>
- <div>Default <code>domain</code> parameter.</div>
- <div>Common for Linux and Windows customization.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>domain</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>DNS domain name to use.</div>
- <div>Common for Linux and Windows customization.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>domainadmin</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>User used to join in AD domain.</div>
- <div>Required if <code>joindomain</code> specified.</div>
- <div>Specific to Windows customization.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>domainadminpassword</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Password used to join in AD domain.</div>
- <div>Required if <code>joindomain</code> specified.</div>
- <div>Specific to Windows customization.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>existing_vm</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>If set to <code>true</code>, do OS customization on the specified virtual machine directly.</div>
- <div>Common for Linux and Windows customization.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>fullname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Server owner name.</div>
- <div>Specific to Windows customization.</div>
- <div>If unset, &quot;Administrator&quot; will be used as a fall-back.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Computer hostname.</div>
- <div>Default is shortened <code>name</code> parameter.</div>
- <div>Allowed characters are alphanumeric (uppercase and lowercase) and minus, rest of the characters are dropped as per RFC 952.</div>
- <div>Common for Linux and Windows customization.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hwclockUTC</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Specifies whether the hardware clock is in UTC or local time.</div>
- <div>Specific to Linux customization.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>joindomain</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>AD domain to join.</div>
- <div>Not compatible with <code>joinworkgroup</code>.</div>
- <div>Specific to Windows customization.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>joinworkgroup</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Workgroup to join.</div>
- <div>Not compatible with <code>joindomain</code>.</div>
- <div>Specific to Windows customization.</div>
- <div>If unset, &quot;WORKGROUP&quot; will be used as a fall-back.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>orgname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Organisation name.</div>
- <div>Specific to Windows customization.</div>
- <div>If unset, &quot;ACME&quot; will be used as a fall-back.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Local administrator password.</div>
- <div>If not defined, the password will be set to blank (that is, no password).</div>
- <div>Specific to Windows customization.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>productid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Product ID.</div>
- <div>Specific to Windows customization.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>runonce</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>List of commands to run at first user logon.</div>
- <div>Specific to Windows customization.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>script_text</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 3.1.0</div>
- </td>
- <td>
- </td>
- <td>
- <div>Script to run with shebang.</div>
- <div>Needs to be enabled in vmware tools with vmware-toolbox-cmd config set deployPkg enable-custom-scripts true</div>
- <div>https://docs.vmware.com/en/VMware-vSphere/7.0/com.vmware.vsphere.vm_admin.doc/GUID-9A5093A5-C54F-4502-941B-3F9C0F573A39.html</div>
- <div>Specific to Linux customization.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>timezone</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Timezone.</div>
- <div>See List of supported time zones for different vSphere versions in Linux/Unix.</div>
- <div>Common for Linux and Windows customization.</div>
- <div><a href='https://msdn.microsoft.com/en-us/library/ms912391.aspx'>Windows</a>.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>customization_spec</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Unique name identifying the requested customization specification.</div>
- <div>This parameter is case sensitive.</div>
- <div>If set, then overrides <code>customization</code> parameter values.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>customvalues</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">[]</div>
- </td>
- <td>
- <div>Define a list of custom values to set on virtual machine.</div>
- <div>A custom value object takes two fields <code>key</code> and <code>value</code>.</div>
- <div>Incorrect key and values will be ignored.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">"ha-datacenter"</div>
- </td>
- <td>
- <div>Destination datacenter for the deploy operation.</div>
- <div>This parameter is case sensitive.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datastore</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Specify datastore or datastore cluster to provision virtual machine.</div>
- <div>This parameter takes precedence over <code>disk.datastore</code> parameter.</div>
- <div>This parameter can be used to override datastore or datastore cluster setting of the virtual machine when deployed from the template.</div>
- <div>Please see example for more usage.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>delete_from_inventory</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether to delete Virtual machine from inventory or delete from disk.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>disk</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">[]</div>
- </td>
- <td>
- <div>A list of disks to add.</div>
- <div>This parameter is case sensitive.</div>
- <div>Shrinking disks is not supported.</div>
- <div>Removing existing disks of the virtual machine is not supported.</div>
- <div>Attributes <code>controller_type</code>, <code>controller_number</code>, <code>unit_number</code> are used to configure multiple types of disk controllers and disks for creating or reconfiguring virtual machine. Added in Ansible 2.10.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>autoselect_datastore</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Select the less used datastore.</div>
- <div><code>disk.datastore</code> and <code>disk.autoselect_datastore</code> will not be used if <code>datastore</code> is specified outside this <code>disk</code> configuration.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>controller_number</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>0</li>
- <li>1</li>
- <li>2</li>
- <li>3</li>
- </ul>
- </td>
- <td>
- <div>Disk controller bus number.</div>
- <div>The maximum number of same type controller is 4 per VM.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>controller_type</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>buslogic</li>
- <li>lsilogic</li>
- <li>lsilogicsas</li>
- <li>paravirtual</li>
- <li>sata</li>
- <li>nvme</li>
- </ul>
- </td>
- <td>
- <div>Type of disk controller.</div>
- <div><code>nvme</code> controller type support starts on ESXi 6.5 with VM hardware version <code>version</code> 13. Set this type on not supported ESXi or VM hardware version will lead to failure in deployment.</div>
- <div>When set to <code>sata</code>, please make sure <code>unit_number</code> is correct and not used by SATA CDROMs.</div>
- <div>If set to <code>sata</code> type, please make sure <code>controller_number</code> and <code>unit_number</code> are set correctly when <code>cdrom</code> also set to <code>sata</code> type.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datastore</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of datastore which will be used for the disk.</div>
- <div>If <code>autoselect_datastore</code> is set to True, will select the less used datastore whose name contains this &quot;disk.datastore&quot; string.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>disk_mode</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>persistent</li>
- <li>independent_persistent</li>
- <li>independent_nonpersistent</li>
- </ul>
- </td>
- <td>
- <div>Type of disk mode.</div>
- <div>Added in Ansible 2.6.</div>
- <div>If <code>persistent</code> specified, changes are immediately and permanently written to the virtual disk. This is default.</div>
- <div>If <code>independent_persistent</code> specified, same as persistent, but not affected by snapshots.</div>
- <div>If <code>independent_nonpersistent</code> specified, changes to virtual disk are made to a redo log and discarded at power off, but not affected by snapshots.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>filename</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Existing disk image to be used.</div>
- <div>Filename must already exist on the datastore.</div>
- <div>Specify filename string in <code>[datastore_name] path/to/file.vmdk</code> format. Added in Ansible 2.8.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>size</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Disk storage size.</div>
- <div>Please specify storage unit like [kb, mb, gb, tb].</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>size_gb</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Disk storage size in gb.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>size_kb</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Disk storage size in kb.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>size_mb</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Disk storage size in mb.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>size_tb</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Disk storage size in tb.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>type</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>thin</li>
- <li>thick</li>
- <li>eagerzeroedthick</li>
- </ul>
- </td>
- <td>
- <div>Type of disk.</div>
- <div>If <code>thin</code> specified, disk type is set to thin disk.</div>
- <div>If <code>eagerzeroedthick</code> specified, disk type is set to eagerzeroedthick disk. Added Ansible 2.5.</div>
- <div>If not specified, disk type is inherited from the source VM or template when cloned and thick disk, no eagerzero otherwise.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>unit_number</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Disk Unit Number.</div>
- <div>Valid value range from 0 to 15 for SCSI controller, except 7.</div>
- <div>Valid value range from 0 to 14 for NVME controller.</div>
- <div>Valid value range from 0 to 29 for SATA controller.</div>
- <div><code>controller_type</code>, <code>controller_number</code> and <code>unit_number</code> are required when creating or reconfiguring VMs with multiple types of disk controllers and disks.</div>
- <div>When creating new VM, the first configured disk in the <code>disk</code> list will be &quot;Hard Disk 1&quot;.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The ESXi hostname where the virtual machine will run.</div>
- <div>This is a required parameter, if <code>cluster</code> is not set.</div>
- <div><code>esxi_hostname</code> and <code>cluster</code> are mutually exclusive parameters.</div>
- <div>This parameter is case sensitive.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>folder</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Destination folder, absolute path to find an existing guest or create the new guest.</div>
- <div>The folder should include the datacenter. ESXi&#x27;s datacenter is ha-datacenter.</div>
- <div>This parameter is case sensitive.</div>
- <div>If multiple machines are found with same name, this parameter is used to identify</div>
- <div>uniqueness of the virtual machine. Added in Ansible 2.5.</div>
- <div>Examples:</div>
- <div>folder: /ha-datacenter/vm</div>
- <div>folder: ha-datacenter/vm</div>
- <div>folder: /datacenter1/vm</div>
- <div>folder: datacenter1/vm</div>
- <div>folder: /datacenter1/vm/folder1</div>
- <div>folder: datacenter1/vm/folder1</div>
- <div>folder: /folder1/datacenter1/vm</div>
- <div>folder: folder1/datacenter1/vm</div>
- <div>folder: /folder1/datacenter1/vm/folder2</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>force</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Ignore warnings and complete the actions.</div>
- <div>This parameter is useful while removing virtual machine which is powered on state.</div>
- <div>This module reflects the VMware vCenter API and UI workflow, as such, in some cases the `force` flag will be mandatory to perform the action to ensure you are certain the action has to be taken, no matter what the consequence. This is specifically the case for removing a powered on the virtual machine when <code>state</code> is set to <code>absent</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>guest_id</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Set the guest ID.</div>
- <div>This parameter is case sensitive.</div>
- <div><code>rhel7_64Guest</code> for virtual machine with RHEL7 64 bit.</div>
- <div><code>centos64Guest</code> for virtual machine with CentOS 64 bit.</div>
- <div><code>ubuntu64Guest</code> for virtual machine with Ubuntu 64 bit.</div>
- <div>This field is required when creating a virtual machine, not required when creating from the template.</div>
- <div>Valid values are referenced here: <a href='https://code.vmware.com/apis/358/doc/vim.vm.GuestOsDescriptor.GuestOsIdentifier.html'>https://code.vmware.com/apis/358/doc/vim.vm.GuestOsDescriptor.GuestOsIdentifier.html</a></div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hardware</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">{}</div>
- </td>
- <td>
- <div>Manage virtual machine&#x27;s hardware attributes.</div>
- <div>All parameters case sensitive.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>boot_firmware</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>bios</li>
- <li>efi</li>
- </ul>
- </td>
- <td>
- <div>Choose which firmware should be used to boot the virtual machine.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cpu_limit</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The CPU utilization of a virtual machine will not exceed this limit.</div>
- <div>Unit is MHz.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cpu_reservation</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The amount of CPU resource that is guaranteed available to the virtual machine.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cpu_shares</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 3.2.0</div>
- </td>
- <td>
- </td>
- <td>
- <div>The number of shares of CPU allocated to this virtual machine</div>
- <div>cpu_shares_level will automatically be set to &#x27;custom&#x27;</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cpu_shares_level</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 3.2.0</div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>low</li>
- <li>normal</li>
- <li>high</li>
- <li>custom</li>
- </ul>
- </td>
- <td>
- <div>The allocation level of CPU resources for the virtual machine.</div>
- <div>Valid Values are <code>low</code>, <code>normal</code>, <code>high</code> and <code>custom</code>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hotadd_cpu</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Allow virtual CPUs to be added while the virtual machine is running.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hotadd_memory</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Allow memory to be added while the virtual machine is running.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hotremove_cpu</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Allow virtual CPUs to be removed while the virtual machine is running.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>iommu</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Flag to specify if I/O MMU is enabled for this virtual machine.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>max_connections</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Maximum number of active remote display connections for the virtual machines.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>mem_limit</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The memory utilization of a virtual machine will not exceed this limit.</div>
- <div>Unit is MB.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>mem_reservation</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The amount of memory resource that is guaranteed available to the virtual machine.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: memory_reservation</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>mem_shares</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 3.2.0</div>
- </td>
- <td>
- </td>
- <td>
- <div>The number of shares of memory allocated to this virtual machine</div>
- <div>mem_shares_level will automatically be set to &#x27;custom&#x27;</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>mem_shares_level</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 3.2.0</div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>low</li>
- <li>normal</li>
- <li>high</li>
- <li>custom</li>
- </ul>
- </td>
- <td>
- <div>The allocation level of memory resources for the virtual machine.</div>
- <div>Valid Values are <code>low</code>, <code>normal</code>, <code>high</code> and <code>custom</code>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>memory_mb</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Amount of memory in MB.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>memory_reservation_lock</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>If set <code>true</code>, memory resource reservation for the virtual machine.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>nested_virt</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Enable nested virtualization.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>num_cpu_cores_per_socket</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Number of Cores Per Socket.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>num_cpus</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Number of CPUs.</div>
- <div><code>num_cpus</code> must be a multiple of <code>num_cpu_cores_per_socket</code>.</div>
- <div>For example, to create a VM with 2 sockets of 4 cores, specify <code>num_cpus</code> as 8 and <code>num_cpu_cores_per_socket</code> as 4.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>scsi</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>buslogic</li>
- <li>lsilogic</li>
- <li>lsilogicsas</li>
- <li>paravirtual</li>
- </ul>
- </td>
- <td>
- <div>Valid values are <code>buslogic</code>, <code>lsilogic</code>, <code>lsilogicsas</code> and <code>paravirtual</code>.</div>
- <div><code>paravirtual</code> is default.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>secure_boot</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether to enable or disable (U)EFI secure boot.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>version</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The Virtual machine hardware versions.</div>
- <div>Default is 10 (ESXi 5.5 and onwards).</div>
- <div>If set to <code>latest</code>, the specified virtual machine will be upgraded to the most current hardware version supported on the host.</div>
- <div><code>latest</code> is added in Ansible 2.10.</div>
- <div>Please check VMware documentation for correct virtual machine hardware version.</div>
- <div>Incorrect hardware version may lead to failure in deployment. If hardware version is already equal to the given.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>virt_based_security</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Enable Virtualization Based Security feature for Windows on ESXi 6.7 and later, from hardware version 14.</div>
- <div>Supported Guest OS are Windows 10 64 bit, Windows Server 2016, Windows Server 2019 and later.</div>
- <div>The firmware of virtual machine must be EFI and secure boot must be enabled.</div>
- <div>Virtualization Based Security depends on nested virtualization and Intel Virtualization Technology for Directed I/O.</div>
- <div>Deploy on unsupported ESXi, hardware version or firmware may lead to failure or deployed VM with unexpected configurations.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vpmc_enabled</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 3.2.0</div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Enable virtual CPU Performance Counters.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>is_template</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Flag the instance as a template.</div>
- <div>This will mark the given virtual machine as template.</div>
- <div>Note, this may need to be done in a dedicated task invocation that is not making any other changes. For example, user cannot change the state from powered-on to powered-off AND save as template in the same task.</div>
- <div>See <span class='module'>community.vmware.vmware_guest</span> source for more details.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>linked_clone</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether to create a linked clone from the snapshot specified.</div>
- <div>If specified, then <code>snapshot_src</code> is required parameter.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the virtual machine to work with.</div>
- <div>Virtual machine names in vCenter are not necessarily unique, which may be problematic, see <code>name_match</code>.</div>
- <div>If multiple virtual machines with same name exists, then <code>folder</code> is required parameter to identify uniqueness of the virtual machine.</div>
- <div>This parameter is required, if <code>state</code> is set to <code>poweredon</code>, <code>powered-on</code>, <code>poweredoff</code>, <code>powered-off</code>, <code>present</code>, <code>restarted</code>, <code>suspended</code> and virtual machine does not exists.</div>
- <div>This parameter is case sensitive.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name_match</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>first</b>&nbsp;&larr;</div></li>
- <li>last</li>
- </ul>
- </td>
- <td>
- <div>If multiple virtual machines matching the name, use the first or last found.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>networks</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">[]</div>
- </td>
- <td>
- <div>A list of networks (in the order of the NICs).</div>
- <div>Removing NICs is not allowed, while reconfiguring the virtual machine.</div>
- <div>All parameters and VMware object names are case sensitive.</div>
- <div>The <em>type</em>, <em>ip</em>, <em>netmask</em>, <em>gateway</em>, <em>domain</em>, <em>dns_servers</em> options don&#x27;t set to a guest when creating a blank new virtual machine. They are set by the customization via vmware-tools. If you want to set the value of the options to a guest, you need to clone from a template with installed OS and vmware-tools(also Perl when Linux).</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>connected</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Indicates whether the NIC is currently connected.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>device_type</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Virtual network device.</div>
- <div>Valid value can be one of <code>e1000</code>, <code>e1000e</code>, <code>pcnet32</code>, <code>vmxnet2</code>, <code>vmxnet3</code>, <code>sriov</code>.</div>
- <div><code>vmxnet3</code> is default.</div>
- <div>Optional per entry.</div>
- <div>Used for virtual hardware.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>dns_servers</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>DNS servers for this network interface (Windows).</div>
- <div>Optional per entry.</div>
- <div>Used for OS customization.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>domain</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Domain name for this network interface (Windows).</div>
- <div>Optional per entry.</div>
- <div>Used for OS customization.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>dvswitch_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the distributed vSwitch.</div>
- <div>Optional per entry.</div>
- <div>Used for virtual hardware.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>gateway</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Static gateway.</div>
- <div>Optional per entry.</div>
- <div>Used for OS customization.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>ip</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Static IP address. Implies <code>type=static</code>.</div>
- <div>Optional per entry.</div>
- <div>Used for OS customization.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>mac</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Customize MAC address.</div>
- <div>Optional per entry.</div>
- <div>Used for virtual hardware.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the portgroup or distributed virtual portgroup for this interface.</div>
- <div>Required per entry.</div>
- <div>When specifying distributed virtual portgroup make sure given <code>esxi_hostname</code> or <code>cluster</code> is associated with it.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>netmask</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Static netmask required for <code>ip</code>.</div>
- <div>Optional per entry.</div>
- <div>Used for OS customization.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>start_connected</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Specifies whether or not to connect the device when the virtual machine starts.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>type</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Type of IP assignment.</div>
- <div>Valid values are one of <code>dhcp</code>, <code>static</code>.</div>
- <div><code>dhcp</code> is default.</div>
- <div>Optional per entry.</div>
- <div>Used for OS customization.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vlan</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>VLAN number for this interface.</div>
- <div>Required per entry.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>nvdimm</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">{}</div>
- </td>
- <td>
- <div>Add or remove a virtual NVDIMM device to the virtual machine.</div>
- <div>VM virtual hardware version must be 14 or higher on vSphere 6.7 or later.</div>
- <div>Verify that guest OS of the virtual machine supports PMem before adding virtual NVDIMM device.</div>
- <div>Verify that you have the <em>Datastore.Allocate</em> space privilege on the virtual machine.</div>
- <div>Make sure that the host or the cluster on which the virtual machine resides has available PMem resources.</div>
- <div>To add or remove virtual NVDIMM device to the existing virtual machine, it must be in power off state.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>label</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The label of the virtual NVDIMM device to be removed or configured, e.g., &quot;NVDIMM 1&quot;.</div>
- <div>This parameter is required when <code>state</code> is set to <code>absent</code>, or <code>present</code> to reconfigure NVDIMM device size. When add a new device, please do not set <code>label</code>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>size_mb</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">1024</div>
- </td>
- <td>
- <div>Virtual NVDIMM device size in MB.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>present</li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>Valid value is <code>present</code> or <code>absent</code>.</div>
- <div>If set to <code>absent</code>, then the NVDIMM device with specified <code>label</code> will be removed.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>resource_pool</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Use the given resource pool for virtual machine operation.</div>
- <div>This parameter is case sensitive.</div>
- <div>Resource pool should be child of the selected host parent.</div>
- <div>When not specified <em>Resources</em> is taken as default value.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>snapshot_src</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the existing snapshot to use to create a clone of a virtual machine.</div>
- <div>This parameter is case sensitive.</div>
- <div>While creating linked clone using <code>linked_clone</code> parameter, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>absent</li>
- <li>poweredon</li>
- <li>powered-on</li>
- <li>poweredoff</li>
- <li>powered-off</li>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>rebootguest</li>
- <li>reboot-guest</li>
- <li>restarted</li>
- <li>suspended</li>
- <li>shutdownguest</li>
- <li>shutdown-guest</li>
- </ul>
- </td>
- <td>
- <div>Specify the state the virtual machine should be in.</div>
- <div>If <code>state</code> is set to <code>present</code> and virtual machine exists, ensure the virtual machine configurations conforms to task arguments.</div>
- <div>If <code>state</code> is set to <code>absent</code> and virtual machine exists, then the specified virtual machine is removed with it&#x27;s associated components.</div>
- <div>If <code>state</code> is set to one of the following <code>poweredon</code>, <code>powered-on</code>, <code>poweredoff</code>, <code>powered-off</code>, <code>present</code>, <code>restarted</code>, <code>suspended</code> and virtual machine does not exists, virtual machine is deployed with the given parameters.</div>
- <div>If <code>state</code> is set to <code>poweredon</code> or <code>powered-on</code> and virtual machine exists with powerstate other than powered on, then the specified virtual machine is powered on.</div>
- <div>If <code>state</code> is set to <code>poweredoff</code> or <code>powered-off</code> and virtual machine exists with powerstate other than powered off, then the specified virtual machine is powered off.</div>
- <div>If <code>state</code> is set to <code>restarted</code> and virtual machine exists, then the virtual machine is restarted.</div>
- <div>If <code>state</code> is set to <code>suspended</code> and virtual machine exists, then the virtual machine is set to suspended mode.</div>
- <div>If <code>state</code> is set to <code>shutdownguest</code> or <code>shutdown-guest</code> and virtual machine exists, then the virtual machine is shutdown.</div>
- <div>If <code>state</code> is set to <code>rebootguest</code> or <code>reboot-guest</code> and virtual machine exists, then the virtual machine is rebooted.</div>
- <div>Powerstate <code>powered-on</code> and <code>powered-off</code> is added in version 2.10.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state_change_timeout</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">0</div>
- </td>
- <td>
- <div>If the <code>state</code> is set to <code>shutdownguest</code>, by default the module will return immediately after sending the shutdown signal.</div>
- <div>If this argument is set to a positive integer, the module will instead wait for the virtual machine to reach the poweredoff state.</div>
- <div>The value sets a timeout in seconds for the module to wait for the state change.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>template</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Template or existing virtual machine used to create new virtual machine.</div>
- <div>If this value is not set, virtual machine is created without using a template.</div>
- <div>If the virtual machine already exists, this parameter will be ignored.</div>
- <div>This parameter is case sensitive.</div>
- <div>From version 2.8 onwards, absolute path to virtual machine or template can be used.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: template_src</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>use_instance_uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether to use the VMware instance UUID rather than the BIOS UUID.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>UUID of the virtual machine to manage if known, this is VMware&#x27;s unique identifier.</div>
- <div>This is required if <code>name</code> is not supplied.</div>
- <div>If virtual machine does not exists, then this parameter is ignored.</div>
- <div>Please note that a supplied UUID will be ignored on virtual machine creation, as VMware creates the UUID internally.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vapp_properties</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">[]</div>
- </td>
- <td>
- <div>A list of vApp properties.</div>
- <div>For full list of attributes and types refer to: <a href='https://code.vmware.com/apis/704/vsphere/vim.vApp.PropertyInfo.html'>https://code.vmware.com/apis/704/vsphere/vim.vApp.PropertyInfo.html</a></div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>id</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Property ID.</div>
- <div>Required per entry.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>operation</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The <code>remove</code> attribute is required only when removing properties.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>type</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Value type, string type by default.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>value</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Property value.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>wait_for_customization</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Wait until vCenter detects all guest customizations as successfully completed.</div>
- <div>When enabled, the VM will automatically be powered on.</div>
- <div>If vCenter does not detect guest customization start or succeed, failed events after time <code>wait_for_customization_timeout</code> parameter specified, warning message will be printed and task result is fail.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>wait_for_customization_timeout</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">"3600"</div>
- </td>
- <td>
- <div>Define a timeout (in seconds) for the wait_for_customization parameter.</div>
- <div>Be careful when setting this value since the time guest customization took may differ among guest OSes.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>wait_for_ip_address</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Wait until vCenter detects an IP address for the virtual machine.</div>
- <div>This requires vmware-tools (vmtoolsd) to properly work after creation.</div>
- <div>vmware-tools needs to be installed on the given virtual machine in order to work with this parameter.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>wait_for_ip_address_timeout</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">"300"</div>
- </td>
- <td>
- <div>Define a timeout (in seconds) for the wait_for_ip_address parameter.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - Please make sure that the user used for :ref:`community.vmware.vmware_guest <community.vmware.vmware_guest_module>` has the correct level of privileges.
- - For example, following is the list of minimum privileges required by users to create virtual machines.
- - DataStore > Allocate Space
- - Virtual Machine > Configuration > Add New Disk
- - Virtual Machine > Configuration > Add or Remove Device
- - Virtual Machine > Inventory > Create New
- - Network > Assign Network
- - Resource > Assign Virtual Machine to Resource Pool
- - Module may require additional privileges as well, which may be required for gathering facts - e.g. ESXi configurations.
- - Use SCSI disks instead of IDE when you want to expand online disks by specifying a SCSI controller.
- - Uses SysPrep for Windows VM (depends on 'guest_id' parameter match 'win') with PyVmomi.
- - In order to change the VM's parameters (e.g. number of CPUs), the VM must be powered off unless the hot-add support is enabled and the ``state=present`` must be used to apply the changes.
- - For additional information please visit Ansible VMware community wiki - https://github.com/ansible/community/wiki/VMware.
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Create a virtual machine on given ESXi hostname
- community.vmware.vmware_guest:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- folder: /DC1/vm/
- name: test_vm_0001
- state: poweredon
- guest_id: centos64Guest
- # This is hostname of particular ESXi server on which user wants VM to be deployed
- esxi_hostname: "{{ esxi_hostname }}"
- disk:
- - size_gb: 10
- type: thin
- datastore: datastore1
- hardware:
- memory_mb: 512
- num_cpus: 4
- scsi: paravirtual
- networks:
- - name: VM Network
- mac: aa:bb:dd:aa:00:14
- ip: 10.10.10.100
- netmask: 255.255.255.0
- device_type: vmxnet3
- wait_for_ip_address: true
- wait_for_ip_address_timeout: 600
- delegate_to: localhost
- register: deploy_vm
-
- - name: Create a virtual machine from a template
- community.vmware.vmware_guest:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- folder: /testvms
- name: testvm_2
- state: poweredon
- template: template_el7
- disk:
- - size_gb: 10
- type: thin
- datastore: g73_datastore
- # Add another disk from an existing VMDK
- - filename: "[datastore1] testvms/testvm_2_1/testvm_2_1.vmdk"
- hardware:
- memory_mb: 512
- num_cpus: 6
- num_cpu_cores_per_socket: 3
- scsi: paravirtual
- memory_reservation_lock: true
- mem_limit: 8096
- mem_reservation: 4096
- cpu_shares_level: "high"
- mem_shares_level: "high"
- cpu_limit: 8096
- cpu_reservation: 4096
- max_connections: 5
- hotadd_cpu: true
- hotremove_cpu: true
- hotadd_memory: false
- version: 12 # Hardware version of virtual machine
- boot_firmware: "efi"
- cdrom:
- - controller_number: 0
- unit_number: 0
- state: present
- type: iso
- iso_path: "[datastore1] livecd.iso"
- networks:
- - name: VM Network
- mac: aa:bb:dd:aa:00:14
- wait_for_ip_address: true
- delegate_to: localhost
- register: deploy
-
- - name: Clone a virtual machine from Windows template and customize
- community.vmware.vmware_guest:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: datacenter1
- cluster: cluster
- name: testvm-2
- template: template_windows
- networks:
- - name: VM Network
- ip: 192.168.1.100
- netmask: 255.255.255.0
- gateway: 192.168.1.1
- mac: aa:bb:dd:aa:00:14
- domain: my_domain
- dns_servers:
- - 192.168.1.1
- - 192.168.1.2
- - vlan: 1234
- type: dhcp
- customization:
- autologon: true
- dns_servers:
- - 192.168.1.1
- - 192.168.1.2
- domain: my_domain
- password: new_vm_password
- runonce:
- - powershell.exe -ExecutionPolicy Unrestricted -File C:\Windows\Temp\ConfigureRemotingForAnsible.ps1 -ForceNewSSLCert -EnableCredSSP
- delegate_to: localhost
-
- - name: Clone a virtual machine from Linux template and customize
- community.vmware.vmware_guest:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter }}"
- state: present
- folder: /DC1/vm
- template: "{{ template }}"
- name: "{{ vm_name }}"
- cluster: DC1_C1
- networks:
- - name: VM Network
- ip: 192.168.10.11
- netmask: 255.255.255.0
- wait_for_ip_address: true
- customization:
- domain: "{{ guest_domain }}"
- dns_servers:
- - 8.9.9.9
- - 7.8.8.9
- dns_suffix:
- - example.com
- - example2.com
- script_text: |
- #!/bin/bash
- touch /tmp/touch-from-playbook
- delegate_to: localhost
-
- - name: Rename a virtual machine (requires the virtual machine's uuid)
- community.vmware.vmware_guest:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- uuid: "{{ vm_uuid }}"
- name: new_name
- state: present
- delegate_to: localhost
-
- - name: Remove a virtual machine by uuid
- community.vmware.vmware_guest:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- uuid: "{{ vm_uuid }}"
- state: absent
- delegate_to: localhost
-
- - name: Remove a virtual machine from inventory
- community.vmware.vmware_guest:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- name: vm_name
- delete_from_inventory: true
- state: absent
- delegate_to: localhost
-
- - name: Manipulate vApp properties
- community.vmware.vmware_guest:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- name: vm_name
- state: present
- vapp_properties:
- - id: remoteIP
- category: Backup
- label: Backup server IP
- type: string
- value: 10.10.10.1
- - id: old_property
- operation: remove
- delegate_to: localhost
-
- - name: Set powerstate of a virtual machine to poweroff by using UUID
- community.vmware.vmware_guest:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- uuid: "{{ vm_uuid }}"
- state: poweredoff
- delegate_to: localhost
-
- - name: Deploy a virtual machine in a datastore different from the datastore of the template
- community.vmware.vmware_guest:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- name: "{{ vm_name }}"
- state: present
- template: "{{ template_name }}"
- # Here datastore can be different which holds template
- datastore: "{{ virtual_machine_datastore }}"
- hardware:
- memory_mb: 512
- num_cpus: 2
- scsi: paravirtual
- delegate_to: localhost
-
- - name: Create a diskless VM
- community.vmware.vmware_guest:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ dc1 }}"
- state: poweredoff
- cluster: "{{ ccr1 }}"
- name: diskless_vm
- folder: /Asia-Datacenter1/vm
- guest_id: centos64Guest
- datastore: "{{ ds1 }}"
- hardware:
- memory_mb: 1024
- num_cpus: 2
- num_cpu_cores_per_socket: 1
-
- - name: Create a VM with multiple disks of different disk controller types
- community.vmware.vmware_guest:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- folder: /DC1/vm/
- name: test_vm_multi_disks
- state: poweredoff
- guest_id: centos64Guest
- datastore: datastore1
- disk:
- - size_gb: 10
- controller_type: 'nvme'
- controller_number: 0
- unit_number: 0
- - size_gb: 10
- controller_type: 'paravirtual'
- controller_number: 0
- unit_number: 1
- - size_gb: 10
- controller_type: 'sata'
- controller_number: 0
- unit_number: 2
- hardware:
- memory_mb: 512
- num_cpus: 4
- version: 14
- networks:
- - name: VM Network
- device_type: vmxnet3
- delegate_to: localhost
- register: deploy_vm
-
- - name: Create a VM with NVDIMM device
- community.vmware.vmware_guest:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- folder: /DC1/vm/
- name: test_vm_nvdimm
- state: poweredoff
- guest_id: centos7_64Guest
- datastore: datastore1
- hardware:
- memory_mb: 512
- num_cpus: 4
- version: 14
- networks:
- - name: VM Network
- device_type: vmxnet3
- nvdimm:
- state: present
- size_mb: 2048
- delegate_to: localhost
- register: deploy_vm
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>instance</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about the new virtual machine</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">None</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Loic Blot (@nerzhul) <loic.blot@unix-experience.fr>
-- Philippe Dellaert (@pdellaert) <philippe@dellaert.org>
-- Abhijeet Kasurde (@Akasurde) <akasurde@redhat.com>
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_move_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_move_module.rst
deleted file mode 100644
index 33d3eb5bc..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_move_module.rst
+++ /dev/null
@@ -1,393 +0,0 @@
-.. _community.vmware.vmware_guest_move_module:
-
-
-**********************************
-community.vmware.vmware_guest_move
-**********************************
-
-**Moves virtual machines in vCenter**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to move virtual machines between folders.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Destination datacenter for the move operation</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>dest_folder</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Absolute path to move an existing guest</div>
- <div>The dest_folder should include the datacenter. ESX&#x27;s datacenter is ha-datacenter.</div>
- <div>This parameter is case sensitive.</div>
- <div>Examples:</div>
- <div>dest_folder: /ha-datacenter/vm</div>
- <div>dest_folder: ha-datacenter/vm</div>
- <div>dest_folder: /datacenter1/vm</div>
- <div>dest_folder: datacenter1/vm</div>
- <div>dest_folder: /datacenter1/vm/folder1</div>
- <div>dest_folder: datacenter1/vm/folder1</div>
- <div>dest_folder: /folder1/datacenter1/vm</div>
- <div>dest_folder: folder1/datacenter1/vm</div>
- <div>dest_folder: /folder1/datacenter1/vm/folder2</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>moid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.</div>
- <div>This is required if <code>name</code> or <code>uuid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the existing virtual machine to move.</div>
- <div>This is required if <code>uuid</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name_match</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>first</b>&nbsp;&larr;</div></li>
- <li>last</li>
- </ul>
- </td>
- <td>
- <div>If multiple virtual machines matching the name, use the first or last found.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>use_instance_uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether to use the VMware instance UUID rather than the BIOS UUID.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>UUID of the virtual machine to manage if known, this is VMware&#x27;s unique identifier.</div>
- <div>This is required if <code>name</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Move Virtual Machine
- community.vmware.vmware_guest_move:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: datacenter
- name: testvm-1
- dest_folder: "/{{ datacenter }}/vm"
- delegate_to: localhost
-
- - name: Move Virtual Machine using MoID
- community.vmware.vmware_guest_move:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: datacenter
- moid: vm-42
- dest_folder: "/{{ datacenter }}/vm"
- delegate_to: localhost
-
- - name: Get VM UUID
- vmware_guest_facts:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter }}"
- folder: "/{{ datacenter }}/vm"
- name: "{{ vm_name }}"
- delegate_to: localhost
- register: vm_facts
-
- - name: Get UUID from previous task and pass it to this task
- community.vmware.vmware_guest_move:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter }}"
- uuid: "{{ vm_facts.instance.hw_product_uuid }}"
- dest_folder: "/DataCenter/vm/path/to/new/folder/where/we/want"
- delegate_to: localhost
- register: facts
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>instance</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about the virtual machine</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;annotation&#x27;: None, &#x27;current_snapshot&#x27;: None, &#x27;customvalues&#x27;: {}, &#x27;guest_consolidation_needed&#x27;: False, &#x27;guest_question&#x27;: None, &#x27;guest_tools_status&#x27;: None, &#x27;guest_tools_version&#x27;: &#x27;0&#x27;, &#x27;hw_cores_per_socket&#x27;: 1, &#x27;hw_datastores&#x27;: [&#x27;LocalDS_0&#x27;], &#x27;hw_esxi_host&#x27;: &#x27;DC0_H0&#x27;, &#x27;hw_eth0&#x27;: {&#x27;addresstype&#x27;: &#x27;generated&#x27;, &#x27;ipaddresses&#x27;: None, &#x27;label&#x27;: &#x27;ethernet-0&#x27;, &#x27;macaddress&#x27;: &#x27;00:0c:29:6b:34:2c&#x27;, &#x27;macaddress_dash&#x27;: &#x27;00-0c-29-6b-34-2c&#x27;, &#x27;summary&#x27;: &#x27;DVSwitch: 43cdd1db-1ef7-4016-9bbe-d96395616199&#x27;}, &#x27;hw_files&#x27;: [&#x27;[LocalDS_0] DC0_H0_VM0/DC0_H0_VM0.vmx&#x27;], &#x27;hw_folder&#x27;: &#x27;/F0/DC0/vm/F0&#x27;, &#x27;hw_guest_full_name&#x27;: None, &#x27;hw_guest_ha_state&#x27;: None, &#x27;hw_guest_id&#x27;: &#x27;otherGuest&#x27;, &#x27;hw_interfaces&#x27;: [&#x27;eth0&#x27;], &#x27;hw_is_template&#x27;: False, &#x27;hw_memtotal_mb&#x27;: 32, &#x27;hw_name&#x27;: &#x27;DC0_H0_VM0&#x27;, &#x27;hw_power_status&#x27;: &#x27;poweredOn&#x27;, &#x27;hw_processor_count&#x27;: 1, &#x27;hw_product_uuid&#x27;: &#x27;581c2808-64fb-45ee-871f-6a745525cb29&#x27;, &#x27;instance_uuid&#x27;: &#x27;8bcb0b6e-3a7d-4513-bf6a-051d15344352&#x27;, &#x27;ipv4&#x27;: None, &#x27;ipv6&#x27;: None, &#x27;module_hw&#x27;: True, &#x27;snapshots&#x27;: []}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Jose Angel Munoz (@imjoseangel)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_network_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_network_module.rst
deleted file mode 100644
index ccc3efbb1..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_network_module.rst
+++ /dev/null
@@ -1,736 +0,0 @@
-.. _community.vmware.vmware_guest_network_module:
-
-
-*************************************
-community.vmware.vmware_guest_network
-*************************************
-
-**Manage network adapters of specified virtual machine in given vCenter infrastructure**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module is used to add, reconfigure, remove network adapter of given virtual machine.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>allow_guest_os_mtu_change</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 2.3.0</div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows the guest OS to change the MTU on a SR-IOV network adapter.</div>
- <div>This option is only compatible for SR-IOV network adapters.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of cluster where VM belongs to.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>connected</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>If NIC should be connected to the network.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">"ha-datacenter"</div>
- </td>
- <td>
- <div>Datacenter the VM belongs to.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>device_type</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">"vmxnet3"</div>
- </td>
- <td>
- <div>Type of virtual network device.</div>
- <div>Valid choices are - <code>e1000</code>, <code>e1000e</code>, <code>pcnet32</code>, <code>vmxnet2</code>, <code>vmxnet3</code> (default), <code>sriov</code>, <code>pvrdma</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>directpath_io</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Enable Universal Pass-through (UPT).</div>
- <div>Only compatible with the <code>vmxnet3</code> device type.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname of the ESXi host where the VM belongs to.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>folder</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Folder location of given VM, this is only required when there&#x27;s multiple VM&#x27;s with the same name.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>force</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Force adapter creation even if an existing adapter is attached to the same network.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>gather_network_info</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Return information about current guest network adapters.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: gather_network_facts</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>guest_control</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Enables guest control over whether the connectable device is connected.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>label</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Label of the NIC that should be altered. <code>mac_address</code> or <code>label</code> should be set to get the corresponding device to reconfigure.</div>
- <div>Alter the name of the network adapter.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>mac_address</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>MAC address of the NIC that should be altered, if a MAC address is not supplied a new nic will be created.</div>
- <div>Required when <em>state=absent</em>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>moid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.</div>
- <div>Required if <code>uuid</code> or <code>name</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of virtual machine</div>
- <div>Required if <code>uuid</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>network_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of network in vSphere.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>physical_function_backing</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 2.3.0</div>
- </td>
- <td>
- </td>
- <td>
- <div>If set, specifies the PCI ID of the physical function to use as backing for a SR-IOV network adapter.</div>
- <div>This option is only compatible for SR-IOV network adapters.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>pvrdma_device_protocol</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 3.3.0</div>
- </td>
- <td>
- </td>
- <td>
- <div>The PVRDMA device protocol used. Valid choices are - <code>rocev1</code>, <code>rocev2</code>.</div>
- <div>This parameter is only used on the VM with hardware version &gt;=14 and &lt;= 19.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>start_connected</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>If NIC should be connected to network on startup.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>NIC state.</div>
- <div>When <code>state=present</code>, a nic will be added if a mac address or label does not previously exists or is unset.</div>
- <div>When <code>state=absent</code>, the <em>mac_address</em> parameter has to be set.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>switch</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the (dv)switch for destination network, this is only required for dvswitches.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>use_instance_uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether to use the VMware instance UUID rather than the BIOS UUID.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>vm uuid</div>
- <div>Required if <code>name</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>virtual_function_backing</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 2.3.0</div>
- </td>
- <td>
- </td>
- <td>
- <div>If set, specifies the PCI ID of the physical function to use as backing for a SR-IOV network adapter.</div>
- <div>This option is only compatible for SR-IOV network adapters.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vlan_id</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>VLAN id associated with the network.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>wake_onlan</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Enable wake on LAN.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - For backwards compatibility network_data is returned when using the gather_network_info parameter
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: change network for 00:50:56:11:22:33 on vm01.domain.fake
- community.vmware.vmware_guest_network:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- name: vm01.domain.fake
- mac_address: 00:50:56:11:22:33
- network_name: admin-network
- state: present
-
- - name: add a nic on network with vlan id 2001 for 422d000d-2000-ffff-0000-b00000000000
- community.vmware.vmware_guest_network:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- uuid: 422d000d-2000-ffff-0000-b00000000000
- vlan_id: 2001
-
- - name: remove nic with mac 00:50:56:11:22:33 from vm01.domain.fake
- community.vmware.vmware_guest_network:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- mac_address: 00:50:56:11:22:33
- name: vm01.domain.fake
- state: absent
-
- - name: add multiple nics to vm01.domain.fake
- community.vmware.vmware_guest_network:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- name: vm01.domain.fake
- state: present
- vlan_id: "{{ item.vlan_id | default(omit) }}"
- network_name: "{{ item.network_name | default(omit) }}"
- connected: "{{ item.connected | default(omit) }}"
- loop:
- - vlan_id: 2000
- connected: false
- - network_name: guest-net
- connected: true
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>network_data</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>when using gather_network_info parameter</td>
- <td>
- <div>For backwards compatibility, metadata about the virtual machine network adapters</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;network_data&#x27;: {&#x27;0&#x27;: {&#x27;mac_addr&#x27;: &#x27;00:50:56:AA:AA:AA&#x27;, &#x27;mac_address&#x27;: &#x27;00:50:56:AA:AA:AA&#x27;, &#x27;allow_guest_ctl&#x27;: True, &#x27;connected&#x27;: True, &#x27;device_type&#x27;: &#x27;vmxnet3&#x27;, &#x27;label&#x27;: &#x27;Network adapter 2&#x27;, &#x27;name&#x27;: &#x27;admin-net&#x27;, &#x27;network_name&#x27;: &#x27;admin-net&#x27;, &#x27;start_connected&#x27;: True, &#x27;switch&#x27;: &#x27;vSwitch0&#x27;, &#x27;unit_number&#x27;: 8, &#x27;vlan_id&#x27;: 10, &#x27;wake_onlan&#x27;: False}, &#x27;1&#x27;: {&#x27;mac_addr&#x27;: &#x27;00:50:56:BB:BB:BB&#x27;, &#x27;mac_address&#x27;: &#x27;00:50:56:BB:BB:BB&#x27;, &#x27;allow_guest_ctl&#x27;: True, &#x27;connected&#x27;: True, &#x27;device_type&#x27;: &#x27;vmxnet3&#x27;, &#x27;label&#x27;: &#x27;Network adapter 1&#x27;, &#x27;name&#x27;: &#x27;guest-net&#x27;, &#x27;network_name&#x27;: &#x27;guest-net&#x27;, &#x27;start_connected&#x27;: True, &#x27;switch&#x27;: &#x27;vSwitch0&#x27;, &#x27;unit_number&#x27;: 7, &#x27;vlan_id&#x27;: 10, &#x27;wake_onlan&#x27;: True}}}</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>network_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about the virtual machine network adapters</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;network_info&#x27;: [{&#x27;mac_address&#x27;: &#x27;00:50:56:AA:AA:AA&#x27;, &#x27;allow_guest_ctl&#x27;: True, &#x27;connected&#x27;: True, &#x27;device_type&#x27;: &#x27;vmxnet3&#x27;, &#x27;label&#x27;: &#x27;Network adapter 2&#x27;, &#x27;network_name&#x27;: &#x27;admin-net&#x27;, &#x27;start_connected&#x27;: True, &#x27;switch&#x27;: &#x27;vSwitch0&#x27;, &#x27;unit_number&#x27;: 8, &#x27;vlan_id&#x27;: 10, &#x27;wake_onlan&#x27;: False}, {&#x27;mac_address&#x27;: &#x27;00:50:56:BB:BB:BB&#x27;, &#x27;allow_guest_ctl&#x27;: True, &#x27;connected&#x27;: True, &#x27;device_type&#x27;: &#x27;vmxnet3&#x27;, &#x27;label&#x27;: &#x27;Network adapter 1&#x27;, &#x27;network_name&#x27;: &#x27;guest-net&#x27;, &#x27;start_connected&#x27;: True, &#x27;switch&#x27;: &#x27;vSwitch0&#x27;, &#x27;unit_number&#x27;: 7, &#x27;vlan_id&#x27;: 10, &#x27;wake_onlan&#x27;: True}]}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Diane Wang (@Tomorrow9) <dianew@vmware.com>
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_powerstate_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_powerstate_module.rst
deleted file mode 100644
index e8e79b59a..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_powerstate_module.rst
+++ /dev/null
@@ -1,574 +0,0 @@
-.. _community.vmware.vmware_guest_powerstate_module:
-
-
-****************************************
-community.vmware.vmware_guest_powerstate
-****************************************
-
-**Manages power states of virtual machines in vCenter**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- Power on / Power off / Restart a virtual machine.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="2">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>answer</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>A list of questions to answer, should one or more arise while waiting for the task to complete.</div>
- <div>Some common uses are to allow a cdrom to be changed even if locked, or to answer the question as to whether a VM was copied or moved.</div>
- <div>The <em>answer</em> can be used if <em>state</em> is <code>powered-on</code>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>question</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The message id, for example <code>msg.uuid.altered</code>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>response</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The choice key, for example <code>button.uuid.copiedTheVM</code>.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">"ha-datacenter"</div>
- </td>
- <td>
- <div>The <em>datacenter</em> where the VM you&#x27;d like to operate the power.</div>
- <div>This parameter is case sensitive.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>folder</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Destination folder, absolute or relative path to find an existing guest.</div>
- <div>The folder should include the datacenter. ESX&#x27;s datacenter is ha-datacenter</div>
- <div>Examples:</div>
- <div>folder: /ha-datacenter/vm</div>
- <div>folder: ha-datacenter/vm</div>
- <div>folder: /datacenter1/vm</div>
- <div>folder: datacenter1/vm</div>
- <div>folder: /datacenter1/vm/folder1</div>
- <div>folder: datacenter1/vm/folder1</div>
- <div>folder: /folder1/datacenter1/vm</div>
- <div>folder: folder1/datacenter1/vm</div>
- <div>folder: /folder1/datacenter1/vm/folder2</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>force</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Ignore warnings and complete the actions.</div>
- <div>This parameter is useful while forcing virtual machine state.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>moid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.</div>
- <div>This is required if <code>name</code> or <code>uuid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the virtual machine to work with.</div>
- <div>Virtual machine names in vCenter are not necessarily unique, which may be problematic, see <code>name_match</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name_match</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>first</b>&nbsp;&larr;</div></li>
- <li>last</li>
- </ul>
- </td>
- <td>
- <div>If multiple virtual machines matching the name, use the first or last found.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>schedule_task_description</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Description of schedule task.</div>
- <div>Valid only if <code>scheduled_at</code> is specified.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>schedule_task_enabled</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Flag to indicate whether the scheduled task is enabled or disabled.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>schedule_task_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of schedule task.</div>
- <div>Valid only if <code>scheduled_at</code> is specified.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>scheduled_at</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Date and time in string format at which specified task needs to be performed.</div>
- <div>The required format for date and time - &#x27;dd/mm/yyyy hh:mm&#x27;.</div>
- <div>Scheduling task requires vCenter server. A standalone ESXi server does not support this option.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>powered-off</li>
- <li>powered-on</li>
- <li>reboot-guest</li>
- <li>restarted</li>
- <li>shutdown-guest</li>
- <li>suspended</li>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Set the state of the virtual machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state_change_timeout</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">0</div>
- </td>
- <td>
- <div>If the <code>state</code> is set to <code>shutdown-guest</code>, by default the module will return immediately after sending the shutdown signal.</div>
- <div>If this argument is set to a positive integer, the module will instead wait for the VM to reach the poweredoff state.</div>
- <div>The value sets a timeout in seconds for the module to wait for the state change.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>use_instance_uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether to use the VMware instance UUID rather than the BIOS UUID.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>UUID of the instance to manage if known, this is VMware&#x27;s unique identifier.</div>
- <div>This is required if <code>name</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Set the state of a virtual machine to poweroff
- community.vmware.vmware_guest_powerstate:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- folder: "/{{ datacenter_name }}/vm/my_folder"
- name: "{{ guest_name }}"
- state: powered-off
- delegate_to: localhost
- register: deploy
-
- - name: Set the state of a virtual machine to poweron using MoID
- community.vmware.vmware_guest_powerstate:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- folder: "/{{ datacenter_name }}/vm/my_folder"
- moid: vm-42
- state: powered-on
- delegate_to: localhost
- register: deploy
-
- - name: Set the state of a virtual machine to poweroff at given scheduled time
- community.vmware.vmware_guest_powerstate:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- folder: "/{{ datacenter_name }}/vm/my_folder"
- name: "{{ guest_name }}"
- state: powered-off
- scheduled_at: "09/01/2018 10:18"
- schedule_task_name: "task_00001"
- schedule_task_description: "Sample task to poweroff VM"
- schedule_task_enabled: true
- delegate_to: localhost
- register: deploy_at_schedule_datetime
-
- - name: Wait for the virtual machine to shutdown
- community.vmware.vmware_guest_powerstate:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- name: "{{ guest_name }}"
- state: shutdown-guest
- state_change_timeout: 200
- delegate_to: localhost
- register: deploy
-
- - name: Automatically answer if a question locked a virtual machine
- block:
- - name: Power on a virtual machine without the answer param
- community.vmware.vmware_guest_powerstate:
- hostname: "{{ esxi_hostname }}"
- username: "{{ esxi_username }}"
- password: "{{ esxi_password }}"
- validate_certs: false
- folder: "{{ f1 }}"
- name: "{{ vm_name }}"
- state: powered-on
- rescue:
- - name: Power on a virtual machine with the answer param
- community.vmware.vmware_guest_powerstate:
- hostname: "{{ esxi_hostname }}"
- username: "{{ esxi_username }}"
- password: "{{ esxi_password }}"
- validate_certs: false
- folder: "{{ f1 }}"
- name: "{{ vm_name }}"
- answer:
- - question: "msg.uuid.altered"
- response: "button.uuid.copiedTheVM"
- state: powered-on
-
-
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde) <akasurde@redhat.com>
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_register_operation_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_register_operation_module.rst
deleted file mode 100644
index bb572dd0d..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_register_operation_module.rst
+++ /dev/null
@@ -1,417 +0,0 @@
-.. _community.vmware.vmware_guest_register_operation_module:
-
-
-************************************************
-community.vmware.vmware_guest_register_operation
-************************************************
-
-**VM inventory registration operation**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can register or unregister VMs to the inventory.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Specify a cluster name to register VM.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">"ha-datacenter"</div>
- </td>
- <td>
- <div>Destination datacenter for the register/unregister operation.</div>
- <div>This parameter is case sensitive.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The ESXi hostname where the virtual machine will run.</div>
- <div>This parameter is case sensitive.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>folder</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Description folder, absolute path of the target folder.</div>
- <div>The folder should include the datacenter. ESX&#x27;s datacenter is ha-datacenter.</div>
- <div>This parameter is case sensitive.</div>
- <div>Examples:</div>
- <div>folder: /ha-datacenter/vm</div>
- <div>folder: ha-datacenter/vm</div>
- <div>folder: /datacenter1/vm</div>
- <div>folder: datacenter1/vm</div>
- <div>folder: /datacenter1/vm/folder1</div>
- <div>folder: datacenter1/vm/folder1</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Specify VM name to be registered in the inventory.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>path</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Specify the path of vmx file.</div>
- <div>Examples:</div>
- <div>[datastore1] vm/vm.vmx</div>
- <div>[datastore1] vm/vm.vmtx</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>resource_pool</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Specify a resource pool name to register VM.</div>
- <div>This parameter is case sensitive.</div>
- <div>Resource pool should be child of the selected host parent.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>Specify the state the virtual machine should be in.</div>
- <div>if set to <code>present</code>, register VM in inventory.</div>
- <div>if set to <code>absent</code>, unregister VM from inventory.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>template</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether to register VM as a template.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>UUID of the virtual machine to manage if known, this is VMware&#x27;s unique identifier.</div>
- <div>If virtual machine does not exists, then this parameter is ignored.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Register VM to inventory
- community.vmware.vmware_guest_register_operation:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter }}"
- folder: "/vm"
- esxi_hostname: "{{ esxi_hostname }}"
- name: "{{ vm_name }}"
- template: false
- path: "[datastore1] vm/vm.vmx"
- state: present
-
- - name: Register VM in resource pool
- community.vmware.vmware_guest_register_operation:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter }}"
- folder: "/vm"
- resource_pool: "{{ resource_pool }}"
- name: "{{ vm_name }}"
- template: false
- path: "[datastore1] vm/vm.vmx"
- state: present
-
- - name: Register VM in Cluster
- community.vmware.vmware_guest_register_operation:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter }}"
- folder: "/vm"
- cluster: "{{ cluster_name }}"
- name: "{{ vm_name }}"
- template: false
- path: "[datastore1] vm/vm.vmx"
- state: present
-
- - name: UnRegister VM from inventory
- community.vmware.vmware_guest_register_operation:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter }}"
- folder: "/vm"
- name: "{{ vm_name }}"
- state: absent
-
-
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- sky-joker (@sky-joker)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_screenshot_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_screenshot_module.rst
deleted file mode 100644
index 0d4039eb9..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_screenshot_module.rst
+++ /dev/null
@@ -1,386 +0,0 @@
-.. _community.vmware.vmware_guest_screenshot_module:
-
-
-****************************************
-community.vmware.vmware_guest_screenshot
-****************************************
-
-**Create a screenshot of the Virtual Machine console.**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module is used to take screenshot of the given virtual machine when virtual machine is powered on.
-- All parameters and VMware object names are case sensitive.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of cluster where the virtual machine is running.</div>
- <div>This is a required parameter, if <code>esxi_hostname</code> is not set.</div>
- <div><code>esxi_hostname</code> and <code>cluster</code> are mutually exclusive parameters.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The datacenter name to which virtual machine belongs to.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The ESXi hostname where the virtual machine is running.</div>
- <div>This is a required parameter, if <code>cluster</code> is not set.</div>
- <div><code>esxi_hostname</code> and <code>cluster</code> are mutually exclusive parameters.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>folder</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Destination folder, absolute or relative path to find an existing guest.</div>
- <div>This is a required parameter, only if multiple VMs are found with same name.</div>
- <div>The folder should include the datacenter. ESXi server&#x27;s datacenter is ha-datacenter.</div>
- <div>Examples:</div>
- <div>folder: /ha-datacenter/vm</div>
- <div>folder: ha-datacenter/vm</div>
- <div>folder: /datacenter1/vm</div>
- <div>folder: datacenter1/vm</div>
- <div>folder: /datacenter1/vm/folder1</div>
- <div>folder: datacenter1/vm/folder1</div>
- <div>folder: /folder1/datacenter1/vm</div>
- <div>folder: folder1/datacenter1/vm</div>
- <div>folder: /folder1/datacenter1/vm/folder2</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>local_path</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">path</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>If <code>local_path</code> is not set, the created screenshot file will be kept in the directory of the virtual machine on ESXi host. If <code>local_path</code> is set to a valid path on local machine, then the screenshot file will be downloaded from ESXi host to the local directory.</div>
- <div>If not download screenshot file to local machine, you can open it through the returned file URL in screenshot facts manually.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>moid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.</div>
- <div>This is required if <code>name</code> or <code>uuid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the virtual machine.</div>
- <div>This is a required parameter, if parameter <code>uuid</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>UUID of the instance to gather facts if known, this is VMware&#x27;s unique identifier.</div>
- <div>This is a required parameter, if parameter <code>name</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: take a screenshot of the virtual machine console
- community.vmware.vmware_guest_screenshot:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- folder: "{{ folder_name }}"
- name: "{{ vm_name }}"
- local_path: "/tmp/"
- delegate_to: localhost
- register: take_screenshot
-
- - name: Take a screenshot of the virtual machine console using MoID
- community.vmware.vmware_guest_screenshot:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- folder: "{{ folder_name }}"
- moid: vm-42
- local_path: "/tmp/"
- delegate_to: localhost
- register: take_screenshot
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>screenshot_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>display the facts of captured virtual machine screenshot file</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;virtual_machine&#x27;: &#x27;test_vm&#x27;, &#x27;screenshot_file&#x27;: &#x27;[datastore0] test_vm/test_vm-1.png&#x27;, &#x27;task_start_time&#x27;: &#x27;2019-05-25T10:35:04.215016Z&#x27;, &#x27;task_complete_time&#x27;: &#x27;2019-05-25T10:35:04.412622Z&#x27;, &#x27;result&#x27;: &#x27;success&#x27;, &#x27;screenshot_file_url&#x27;: &#x27;https://test_vcenter/folder/test_vm/test_vm-1.png?dcPath=test-dc&amp;dsName=datastore0&#x27;, &#x27;download_local_path&#x27;: &#x27;/tmp/&#x27;, &#x27;download_file_size&#x27;: 2367}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Diane Wang (@Tomorrow9) <dianew@vmware.com>
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_sendkey_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_sendkey_module.rst
deleted file mode 100644
index 8be423ef2..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_sendkey_module.rst
+++ /dev/null
@@ -1,439 +0,0 @@
-.. _community.vmware.vmware_guest_sendkey_module:
-
-
-*************************************
-community.vmware.vmware_guest_sendkey
-*************************************
-
-**Send USB HID codes to the Virtual Machine's keyboard.**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module is used to send keystrokes to given virtual machine.
-- All parameters and VMware object names are case sensitive.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of cluster where the virtual machine is running.</div>
- <div>This is a required parameter, if <code>esxi_hostname</code> is not set.</div>
- <div><code>esxi_hostname</code> and <code>cluster</code> are mutually exclusive parameters.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The datacenter name to which virtual machine belongs to.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The ESXi hostname where the virtual machine is running.</div>
- <div>This is a required parameter, if <code>cluster</code> is not set.</div>
- <div><code>esxi_hostname</code> and <code>cluster</code> are mutually exclusive parameters.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>folder</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Destination folder, absolute or relative path to find an existing guest.</div>
- <div>This is a required parameter, only if multiple VMs are found with same name.</div>
- <div>The folder should include the datacenter. ESXi server&#x27;s datacenter is ha-datacenter.</div>
- <div>Examples:</div>
- <div>folder: /ha-datacenter/vm</div>
- <div>folder: ha-datacenter/vm</div>
- <div>folder: /datacenter1/vm</div>
- <div>folder: datacenter1/vm</div>
- <div>folder: /datacenter1/vm/folder1</div>
- <div>folder: datacenter1/vm/folder1</div>
- <div>folder: /folder1/datacenter1/vm</div>
- <div>folder: folder1/datacenter1/vm</div>
- <div>folder: /folder1/datacenter1/vm/folder2</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>keys_send</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">[]</div>
- </td>
- <td>
- <div>The list of the keys will be sent to the virtual machine.</div>
- <div>Valid values are <code>ENTER</code>, <code>ESC</code>, <code>BACKSPACE</code>, <code>TAB</code>, <code>SPACE</code>, <code>CAPSLOCK</code>, <code>HOME</code>, <code>DELETE</code>, <code>END</code>, <code>CTRL_ALT_DEL</code>, <code>CTRL_C</code>, <code>CTRL_X</code> and <code>F1</code> to <code>F12</code>, <code>RIGHTARROW</code>, <code>LEFTARROW</code>, <code>DOWNARROW</code>, <code>UPARROW</code>.</div>
- <div>If both <code>keys_send</code> and <code>string_send</code> are specified, keys in <code>keys_send</code> list will be sent in front of the <code>string_send</code>.</div>
- <div>Values <code>HOME</code> and <code>END</code> are added in version 1.17.0.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>moid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.</div>
- <div>This is required if <code>name</code> or <code>uuid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the virtual machine.</div>
- <div>This is a required parameter, if parameter <code>uuid</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>sleep_time</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">0</div>
- </td>
- <td>
- <div>Sleep time in seconds between two keys or string sent to the virtual machine.</div>
- <div>API is faster than actual key or string send to virtual machine, this parameter allow to control delay between keys and/or strings.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>string_send</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The string will be sent to the virtual machine.</div>
- <div>This string can contain valid special character, alphabet and digit on the keyboard.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>UUID of the instance to gather facts if known, this is VMware&#x27;s unique identifier.</div>
- <div>This is a required parameter, if parameter <code>name</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Send list of keys to virtual machine
- community.vmware.vmware_guest_sendkey:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- folder: "{{ folder_name }}"
- name: "{{ vm_name }}"
- keys_send:
- - TAB
- - TAB
- - ENTER
- delegate_to: localhost
- register: keys_num_sent
-
- - name: Send list of keys to virtual machine using MoID
- community.vmware.vmware_guest_sendkey:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- folder: "{{ folder_name }}"
- moid: vm-42
- keys_send:
- - CTRL_ALT_DEL
- delegate_to: localhost
- register: ctrl_alt_del_sent
-
- - name: Send a string to virtual machine
- community.vmware.vmware_guest_sendkey:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- folder: "{{ folder_name }}"
- name: "{{ vm_name }}"
- string_send: "user_logon"
- delegate_to: localhost
- register: keys_num_sent
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>sendkey_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>display the keys and the number of keys sent to the virtual machine</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;virtual_machine&#x27;: &#x27;test_vm&#x27;, &#x27;keys_send&#x27;: [&#x27;SPACE&#x27;, &#x27;DOWNARROW&#x27;, &#x27;DOWNARROW&#x27;, &#x27;ENTER&#x27;], &#x27;string_send&#x27;: None, &#x27;keys_send_number&#x27;: 4, &#x27;returned_keys_send_number&#x27;: 4}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Diane Wang (@Tomorrow9) <dianew@vmware.com>
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_serial_port_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_serial_port_module.rst
deleted file mode 100644
index b7ec6b62d..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_serial_port_module.rst
+++ /dev/null
@@ -1,583 +0,0 @@
-.. _community.vmware.vmware_guest_serial_port_module:
-
-
-*****************************************
-community.vmware.vmware_guest_serial_port
-*****************************************
-
-**Manage serial ports on an existing VM**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to manage serial ports on an existing VM
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="2">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>backings</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=dictionary</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>A list of backings for serial ports.</div>
- <div><code>backing_type</code> (str): is required to add or reconfigure or remove an existing serial port.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>backing_type</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Backing type is required for the serial ports to be added or reconfigured or removed.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: type</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>device_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Serial device absolutely path.</div>
- <div>Required when <em>backing_type=device</em>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>direction</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>client</b>&nbsp;&larr;</div></li>
- <li>server</li>
- </ul>
- </td>
- <td>
- <div>The direction of the connection.</div>
- <div>Required when <em>backing_type=network</em>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>endpoint</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>client</b>&nbsp;&larr;</div></li>
- <li>server</li>
- </ul>
- </td>
- <td>
- <div>When you use serial port pipe backing to connect a virtual machine to another process, you must define the endpoints.</div>
- <div>Required when <em>backing_type=pipe</em>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>file_path</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>File path for the host file used in this backing. Fully qualified path is required, like &lt;datastore_name&gt;/&lt;file_name&gt;.</div>
- <div>Required when <em>backing_type=file</em>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>no_rx_loss</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Enables optimized data transfer over the pipe.</div>
- <div>Required when <em>backing_type=pipe</em>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>pipe_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Pipe name for the host pipe.</div>
- <div>Required when <em>backing_type=pipe</em>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_uri</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 3.7.0</div>
- </td>
- <td>
- </td>
- <td>
- <div>Identifies a vSPC proxy service that provides network access to the <em>service_uri</em>.</div>
- <div>If you specify a proxy URI, the virtual machine initiates a connection with the proxy service and forwards the serviceURI and direction to the proxy.</div>
- <div>The <code>Use Virtual Serial Port Concentrator</code> option is automatically enabled when <em>proxy_uri</em> is set.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>service_uri</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Identifies the local host or a system on the network, depending on the value of <em>direction</em>.</div>
- <div>If you use the virtual machine as a server, the URI identifies the host on which the virtual machine runs.</div>
- <div>In this case, the host name part of the URI should be empty, or it should specify the address of the local host.</div>
- <div>If you use the virtual machine as a client, the URI identifies the remote system on the network.</div>
- <div>Required when <em>backing_type=network</em>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div><code>state</code> is required to identify whether we are adding, modifying or removing the serial port.</div>
- <div>If <code>state</code> is set to <code>present</code>, a serial port will be added or modified.</div>
- <div>If <code>state</code> is set to <code>absent</code>, an existing serial port will be removed.</div>
- <div>If an existing serial port to modify or remove, <code>backing_type</code> and either of <code>service_uri</code> or <code>pipe_name</code> or <code>device_name</code> or <code>file_path</code> are required.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>yield_on_poll</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Enables CPU yield behavior.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>moid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.</div>
- <div>This is required if <code>name</code> or <code>uuid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the virtual machine.</div>
- <div>This is a required parameter, if parameter <code>uuid</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>use_instance_uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether to use the VMware instance UUID rather than the BIOS UUID.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>UUID of the instance to manage the serial ports, this is VMware&#x27;s unique identifier.</div>
- <div>This is a required parameter, if parameter <code>name</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- # Create serial ports
- - name: Create multiple serial ports with Backing type - network, pipe, device and file
- community.vmware.vmware_guest_serial_port:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- name: "test_vm1"
- backings:
- - type: 'network'
- direction: 'client'
- service_uri: 'tcp://6000'
- yield_on_poll: true
- - type: 'pipe'
- pipe_name: 'serial_pipe'
- endpoint: 'client'
- - type: 'device'
- device_name: '/dev/char/serial/uart0'
- - type: 'file'
- file_path: '[datastore1]/file1'
- yield_on_poll: true
- register: create_multiple_ports
-
- # Create vSPC port
- - name: Create network serial port with vSPC
- community.vmware.vmware_guest_serial_port:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- name: "test_vm1"
- backings:
- - type: 'network'
- direction: 'server'
- service_uri: 'vSPC.py'
- proxy_uri: 'telnets://<host>:<port>'
- yield_on_poll: true
-
- # Modify existing serial port
- - name: Modify Network backing type
- community.vmware.vmware_guest_serial_port:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- name: '{{ name }}'
- backings:
- - type: 'network'
- state: 'present'
- direction: 'server'
- service_uri: 'tcp://6000'
- delegate_to: localhost
-
- # Remove serial port
- - name: Remove pipe backing type
- community.vmware.vmware_guest_serial_port:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- name: '{{ name }}'
- backings:
- - type: 'pipe'
- state: 'absent'
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>serial_port_data</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about the virtual machine&#x27;s serial ports after managing them</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">[{&#x27;backing_type&#x27;: &#x27;network&#x27;, &#x27;direction&#x27;: &#x27;client&#x27;, &#x27;service_uri&#x27;: &#x27;tcp://6000&#x27;}, {&#x27;backing_type&#x27;: &#x27;pipe&#x27;, &#x27;direction&#x27;: &#x27;server&#x27;, &#x27;pipe_name&#x27;: &#x27;serial pipe&#x27;}]</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Anusha Hegde (@anusha94)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_snapshot_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_snapshot_info_module.rst
deleted file mode 100644
index 1c8872170..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_snapshot_info_module.rst
+++ /dev/null
@@ -1,353 +0,0 @@
-.. _community.vmware.vmware_guest_snapshot_info_module:
-
-
-*******************************************
-community.vmware.vmware_guest_snapshot_info
-*******************************************
-
-**Gather info about virtual machine's snapshots in vCenter**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to gather information about virtual machine's snapshots.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the datacenter.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>folder</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Destination folder, absolute or relative path to find an existing guest.</div>
- <div>This is required parameter, if <code>name</code> is supplied.</div>
- <div>The folder should include the datacenter. ESX&#x27;s datacenter is ha-datacenter</div>
- <div>Examples:</div>
- <div>folder: /ha-datacenter/vm</div>
- <div>folder: ha-datacenter/vm</div>
- <div>folder: /datacenter1/vm</div>
- <div>folder: datacenter1/vm</div>
- <div>folder: /datacenter1/vm/folder1</div>
- <div>folder: datacenter1/vm/folder1</div>
- <div>folder: /folder1/datacenter1/vm</div>
- <div>folder: folder1/datacenter1/vm</div>
- <div>folder: /folder1/datacenter1/vm/folder2</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>moid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.</div>
- <div>This is required if <code>name</code> or <code>uuid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the VM to work with.</div>
- <div>This is required if <code>uuid</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>use_instance_uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether to use the VMware instance UUID rather than the BIOS UUID.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>UUID of the instance to manage if known, this is VMware&#x27;s BIOS UUID by default.</div>
- <div>This is required if <code>name</code> or <code>moid</code> parameter is not supplied.</div>
- <div>The <code>folder</code> is ignored, if <code>uuid</code> is provided.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Gather snapshot information about the virtual machine in the given vCenter
- community.vmware.vmware_guest_snapshot_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- folder: "/{{ datacenter_name }}/vm/"
- name: "{{ guest_name }}"
- delegate_to: localhost
- register: snapshot_info
-
- - name: Gather snapshot information about the virtual machine using MoID
- community.vmware.vmware_guest_snapshot_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- moid: vm-42
- delegate_to: localhost
- register: snapshot_info
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>guest_snapshots</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about the snapshot information</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;current_snapshot&#x27;: {&#x27;creation_time&#x27;: &#x27;2018-02-10T14:48:31.999459+00:00&#x27;, &#x27;description&#x27;: &#x27;&#x27;, &#x27;id&#x27;: 28, &#x27;name&#x27;: &#x27;snap_0003&#x27;, &#x27;state&#x27;: &#x27;poweredOff&#x27;, &#x27;quiesced&#x27;: False}, &#x27;snapshots&#x27;: [{&#x27;creation_time&#x27;: &#x27;2018-02-10T14:48:31.999459+00:00&#x27;, &#x27;description&#x27;: &#x27;&#x27;, &#x27;id&#x27;: 28, &#x27;name&#x27;: &#x27;snap_0003&#x27;, &#x27;state&#x27;: &#x27;poweredOff&#x27;, &#x27;quiesced&#x27;: False}]}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_snapshot_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_snapshot_module.rst
deleted file mode 100644
index f6dceb2de..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_snapshot_module.rst
+++ /dev/null
@@ -1,604 +0,0 @@
-.. _community.vmware.vmware_guest_snapshot_module:
-
-
-**************************************
-community.vmware.vmware_guest_snapshot
-**************************************
-
-**Manages virtual machines snapshots in vCenter**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to create, delete and update snapshot(s) of the given virtual machine.
-- All parameters and VMware object names are case sensitive.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Destination datacenter for the deploy operation.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>description</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">""</div>
- </td>
- <td>
- <div>Define an arbitrary description to attach to snapshot.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>folder</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Destination folder, absolute or relative path to find an existing guest.</div>
- <div>This is required parameter, if <code>name</code> is supplied.</div>
- <div>The folder should include the datacenter. ESX&#x27;s datacenter is ha-datacenter.</div>
- <div>Examples:</div>
- <div>folder: /ha-datacenter/vm</div>
- <div>folder: ha-datacenter/vm</div>
- <div>folder: /datacenter1/vm</div>
- <div>folder: datacenter1/vm</div>
- <div>folder: /datacenter1/vm/folder1</div>
- <div>folder: datacenter1/vm/folder1</div>
- <div>folder: /folder1/datacenter1/vm</div>
- <div>folder: folder1/datacenter1/vm</div>
- <div>folder: /folder1/datacenter1/vm/folder2</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>memory_dump</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>If set to <code>true</code>, memory dump of virtual machine is also included in snapshot.</div>
- <div>Note that memory snapshots take time and resources, this will take longer time to create.</div>
- <div>If virtual machine does not provide capability to take memory snapshot, then this flag is set to <code>false</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>moid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.</div>
- <div>This is required if <code>name</code> or <code>uuid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the virtual machine to work with.</div>
- <div>This is required parameter, if <code>uuid</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name_match</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>first</b>&nbsp;&larr;</div></li>
- <li>last</li>
- </ul>
- </td>
- <td>
- <div>If multiple VMs matching the name, use the first or last found.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>new_description</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Value to change the description of an existing snapshot to.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>new_snapshot_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Value to rename the existing snapshot to.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>quiesce</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>If set to <code>true</code> and virtual machine is powered on, it will quiesce the file system in virtual machine.</div>
- <div>Note that VMware Tools are required for this flag.</div>
- <div>If virtual machine is powered off or VMware Tools are not available, then this flag is set to <code>false</code>.</div>
- <div>If virtual machine does not provide capability to take quiesce snapshot, then this flag is set to <code>false</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>remove_children</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>If set to <code>true</code> and state is set to <code>absent</code>, then entire snapshot subtree is set for removal.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>snapshot_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Sets the snapshot name to manage.</div>
- <div>This param is required only if state is not <code>remove_all</code></div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- <li>revert</li>
- <li>remove_all</li>
- </ul>
- </td>
- <td>
- <div>Manage snapshot(s) attached to a specific virtual machine.</div>
- <div>If set to <code>present</code> and snapshot absent, then will create a new snapshot with the given name.</div>
- <div>If set to <code>present</code> and snapshot present, then no changes are made.</div>
- <div>If set to <code>absent</code> and snapshot present, then snapshot with the given name is removed.</div>
- <div>If set to <code>absent</code> and snapshot absent, then no changes are made.</div>
- <div>If set to <code>revert</code> and snapshot present, then virtual machine state is reverted to the given snapshot.</div>
- <div>If set to <code>revert</code> and snapshot absent, then no changes are made.</div>
- <div>If set to <code>remove_all</code> and snapshot(s) present, then all snapshot(s) will be removed.</div>
- <div>If set to <code>remove_all</code> and snapshot(s) absent, then no changes are made.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>use_instance_uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether to use the VMware instance UUID rather than the BIOS UUID.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>UUID of the instance to manage if known, this is VMware&#x27;s BIOS UUID by default.</div>
- <div>This is required if <code>name</code> or <code>moid</code> parameter is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Create a snapshot
- community.vmware.vmware_guest_snapshot:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- folder: "/{{ datacenter_name }}/vm/"
- name: "{{ guest_name }}"
- state: present
- snapshot_name: snap1
- description: snap1_description
- delegate_to: localhost
-
- - name: Remove a snapshot
- community.vmware.vmware_guest_snapshot:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- folder: "/{{ datacenter_name }}/vm/"
- name: "{{ guest_name }}"
- state: absent
- snapshot_name: snap1
- delegate_to: localhost
-
- - name: Revert to a snapshot
- community.vmware.vmware_guest_snapshot:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- folder: "/{{ datacenter_name }}/vm/"
- name: "{{ guest_name }}"
- state: revert
- snapshot_name: snap1
- delegate_to: localhost
-
- - name: Remove all snapshots of a VM
- community.vmware.vmware_guest_snapshot:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- folder: "/{{ datacenter_name }}/vm/"
- name: "{{ guest_name }}"
- state: remove_all
- delegate_to: localhost
-
- - name: Remove all snapshots of a VM using MoID
- community.vmware.vmware_guest_snapshot:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- folder: "/{{ datacenter_name }}/vm/"
- moid: vm-42
- state: remove_all
- delegate_to: localhost
-
- - name: Take snapshot of a VM using quiesce and memory flag on
- community.vmware.vmware_guest_snapshot:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- folder: "/{{ datacenter_name }}/vm/"
- name: "{{ guest_name }}"
- state: present
- snapshot_name: dummy_vm_snap_0001
- quiesce: true
- memory_dump: true
- delegate_to: localhost
-
- - name: Remove a snapshot and snapshot subtree
- community.vmware.vmware_guest_snapshot:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- folder: "/{{ datacenter_name }}/vm/"
- name: "{{ guest_name }}"
- state: absent
- remove_children: true
- snapshot_name: snap1
- delegate_to: localhost
-
- - name: Rename a snapshot
- community.vmware.vmware_guest_snapshot:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- folder: "/{{ datacenter_name }}/vm/"
- name: "{{ guest_name }}"
- state: present
- snapshot_name: current_snap_name
- new_snapshot_name: im_renamed
- new_description: "{{ new_snapshot_description }}"
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>snapshot_results</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about the virtual machine snapshots</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;current_snapshot&#x27;: {&#x27;creation_time&#x27;: &#x27;2019-04-09T14:40:26.617427+00:00&#x27;, &#x27;description&#x27;: &#x27;Snapshot 4 example&#x27;, &#x27;id&#x27;: 4, &#x27;name&#x27;: &#x27;snapshot4&#x27;, &#x27;state&#x27;: &#x27;poweredOff&#x27;}, &#x27;snapshots&#x27;: [{&#x27;creation_time&#x27;: &#x27;2019-04-09T14:38:24.667543+00:00&#x27;, &#x27;description&#x27;: &#x27;Snapshot 3 example&#x27;, &#x27;id&#x27;: 3, &#x27;name&#x27;: &#x27;snapshot3&#x27;, &#x27;state&#x27;: &#x27;poweredOff&#x27;}, {&#x27;creation_time&#x27;: &#x27;2019-04-09T14:40:26.617427+00:00&#x27;, &#x27;description&#x27;: &#x27;Snapshot 4 example&#x27;, &#x27;id&#x27;: 4, &#x27;name&#x27;: &#x27;snapshot4&#x27;, &#x27;state&#x27;: &#x27;poweredOff&#x27;}]}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Loic Blot (@nerzhul) <loic.blot@unix-experience.fr>
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_storage_policy_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_storage_policy_module.rst
deleted file mode 100644
index 36bae3f07..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_storage_policy_module.rst
+++ /dev/null
@@ -1,429 +0,0 @@
-.. _community.vmware.vmware_guest_storage_policy_module:
-
-
-********************************************
-community.vmware.vmware_guest_storage_policy
-********************************************
-
-**Set VM Home and disk(s) storage policy profiles.**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to enforce storage policy profiles per disk and/or VM Home on a virtual machine.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="2">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>disk</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>A list of disks with storage profile policies to enforce.</div>
- <div>All values and parameters are case sensitive.</div>
- <div>At least one of <code>disk</code> and <code>vm_home</code> are required parameters.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>controller_number</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">0</div>
- </td>
- <td>
- <div>SCSI controller number.</div>
- <div>Valid values range from 0 to 3.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>policy</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the storage profile policy to enforce for the disk.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>unit_number</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Disk Unit Number.</div>
- <div>Valid values range from 0 to 15.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>folder</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Destination folder, absolute or relative path to find an existing guest.</div>
- <div>This is a required parameter if multiple VMs are found with same name.</div>
- <div>The folder should include the datacenter. ESX&#x27;s datacenter is ha-datacenter.</div>
- <div>Examples:</div>
- <div>folder: /ha-datacenter/vm</div>
- <div>folder: ha-datacenter/vm</div>
- <div>folder: /datacenter1/vm</div>
- <div>folder: datacenter1/vm</div>
- <div>folder: /datacenter1/vm/folder1</div>
- <div>folder: datacenter1/vm/folder1</div>
- <div>folder: /folder1/datacenter1/vm</div>
- <div>folder: folder1/datacenter1/vm</div>
- <div>folder: /folder1/datacenter1/vm/folder2</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>moid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.</div>
- <div>One of <code>name</code>, <code>uuid</code>, or <code>moid</code> are required to define the virtual machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the virtual machine.</div>
- <div>One of <code>name</code>, <code>uuid</code>, or <code>moid</code> are required to define the virtual machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>UUID of the virtual machine.</div>
- <div>One of <code>name</code>, <code>uuid</code>, or <code>moid</code> are required to define the virtual machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vm_home</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>A storage profile policy to set on VM Home.</div>
- <div>All values and parameters are case sensitive.</div>
- <div>At least one of <code>disk</code> or <code>vm_home</code> are required parameters.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Enforce storepol1 policy for disk 0 and 1 on SCSI controller 0 using UUID
- community.vmware.vmware_guest_storage_policy:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- validate_certs: false
- uuid: cefd316c-fc19-45f3-a539-2cd03427a78d
- disk:
- - unit_number: 0
- controller_number: 0
- policy: storepol1
- - unit_number: 1
- controller_number: 0
- policy: storepol1
- delegate_to: localhost
- register: policy_status
-
- - name: Enforce storepol1 policy for VM Home using name
- community.vmware.vmware_guest_storage_policy:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- validate_certs: false
- name: hostname1
- vm_home: storepol1
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>changed_policies</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>Dictionary containing the changed policies of disk (list of dictionaries) and vm_home.</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;disk&#x27;: [{&#x27;policy&#x27;: &#x27;storepol1&#x27;, &#x27;unit_number&#x27;: 0}], &#x27;vm_home&#x27;: &#x27;storepol1&#x27;}</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>msg</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>Informational message on the job result.</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">Policies successfully set.</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Tyler Gates (@tgates81)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_tools_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_tools_info_module.rst
deleted file mode 100644
index 8fa844f1c..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_tools_info_module.rst
+++ /dev/null
@@ -1,369 +0,0 @@
-.. _community.vmware.vmware_guest_tools_info_module:
-
-
-****************************************
-community.vmware.vmware_guest_tools_info
-****************************************
-
-**Gather info about VMware tools installed in VM**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- Gather information about the VMware tools installed in virtual machine.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The datacenter name to which virtual machine belongs to.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>folder</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Destination folder, absolute or relative path to find an existing guest.</div>
- <div>This is required if name is supplied.</div>
- <div>The folder should include the datacenter. ESXi server&#x27;s datacenter is ha-datacenter.</div>
- <div>Examples:</div>
- <div>folder: /ha-datacenter/vm</div>
- <div>folder: ha-datacenter/vm</div>
- <div>folder: /datacenter1/vm</div>
- <div>folder: datacenter1/vm</div>
- <div>folder: /datacenter1/vm/folder1</div>
- <div>folder: datacenter1/vm/folder1</div>
- <div>folder: /folder1/datacenter1/vm</div>
- <div>folder: folder1/datacenter1/vm</div>
- <div>folder: /folder1/datacenter1/vm/folder2</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>moid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.</div>
- <div>This is required if <code>name</code> or <code>uuid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the VM to get VMware tools info.</div>
- <div>This is required if <code>uuid</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name_match</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>first</b>&nbsp;&larr;</div></li>
- <li>last</li>
- </ul>
- </td>
- <td>
- <div>If multiple VMs matching the name, use the first or last found.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>use_instance_uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether to use the VMware instance UUID rather than the BIOS UUID.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>UUID of the instance to manage if known, this is VMware&#x27;s unique identifier.</div>
- <div>This is required if <code>name</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Gather VMware tools info installed in VM specified by uuid
- community.vmware.vmware_guest_tools_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- uuid: 421e4592-c069-924d-ce20-7e7533fab926
- delegate_to: localhost
- register: vmtools_info
-
- - name: Gather VMware tools info installed in VM specified by name
- community.vmware.vmware_guest_tools_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- name: "{{ vm_name }}"
- delegate_to: localhost
- register: vmtools_info
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>vmtools_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about the VMware tools installed in virtual machine</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;vm_uuid&#x27;: None, &#x27;vm_moid&#x27;: None, &#x27;vm_use_instance_uuid&#x27;: False, &#x27;vm_guest_fullname&#x27;: &#x27;Microsoft Windows 10 (64-bit)&#x27;, &#x27;vm_guest_hostname&#x27;: &#x27;test&#x27;, &#x27;vm_guest_id&#x27;: &#x27;windows9_64Guest&#x27;, &#x27;vm_hw_version&#x27;: &#x27;vmx-14&#x27;, &#x27;vm_ipaddress&#x27;: &#x27;10.10.10.10&#x27;, &#x27;vm_name&#x27;: &#x27;test_vm&#x27;, &#x27;vm_tools_install_status&#x27;: &#x27;toolsOk&#x27;, &#x27;vm_tools_install_type&#x27;: &#x27;guestToolsTypeMSI&#x27;, &#x27;vm_tools_last_install_count&#x27;: 0, &#x27;vm_tools_running_status&#x27;: &#x27;guestToolsRunning&#x27;, &#x27;vm_tools_upgrade_policy&#x27;: &#x27;manual&#x27;, &#x27;vm_tools_version&#x27;: 10341, &#x27;vm_tools_version_status&#x27;: &#x27;guestToolsCurrent&#x27;}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Diane Wang (@Tomorrow9) <dianew@vmware.com>
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_tools_upgrade_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_tools_upgrade_module.rst
deleted file mode 100644
index 08e3cd52a..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_tools_upgrade_module.rst
+++ /dev/null
@@ -1,351 +0,0 @@
-.. _community.vmware.vmware_guest_tools_upgrade_module:
-
-
-*******************************************
-community.vmware.vmware_guest_tools_upgrade
-*******************************************
-
-**Module to upgrade VMTools**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module upgrades the VMware Tools on Windows and Linux guests and reboots them.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Destination datacenter where the virtual machine exists.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>folder</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Destination folder, absolute or relative path to find an existing guest.</div>
- <div>This is required, if <code>name</code> is supplied.</div>
- <div>The folder should include the datacenter. ESX&#x27;s datacenter is ha-datacenter</div>
- <div>Examples:</div>
- <div>folder: /ha-datacenter/vm</div>
- <div>folder: ha-datacenter/vm</div>
- <div>folder: /datacenter1/vm</div>
- <div>folder: datacenter1/vm</div>
- <div>folder: /datacenter1/vm/folder1</div>
- <div>folder: datacenter1/vm/folder1</div>
- <div>folder: /folder1/datacenter1/vm</div>
- <div>folder: folder1/datacenter1/vm</div>
- <div>folder: /folder1/datacenter1/vm/folder2</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>force_upgrade</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>This flag overrides the guest operating system detection and forcibly upgrade VMware tools or open-vm-tools.</div>
- <div>This is useful when VMware tools is too old and unable to detect the &#x27;guestFamily&#x27; value.</div>
- <div>Using this flag may sometime give unexpected results since module will override the default</div>
- <div>behaviour of &#x27;guestFamily&#x27; detection.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>moid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.</div>
- <div>This is required if <code>name</code> or <code>uuid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the virtual machine to work with.</div>
- <div>This is required if <code>uuid</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name_match</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>first</b>&nbsp;&larr;</div></li>
- <li>last</li>
- </ul>
- </td>
- <td>
- <div>If multiple virtual machines matching the name, use the first or last found.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>UUID of the instance to manage if known, this is VMware&#x27;s unique identifier.</div>
- <div>This is required if <code>name</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - In order to upgrade VMTools, please power on virtual machine before hand - either 'manually' or using module :ref:`community.vmware.vmware_guest_powerstate <community.vmware.vmware_guest_powerstate_module>`.
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Get VM UUID
- vmware_guest_facts:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter }}"
- folder: "/{{datacenter}}/vm"
- name: "{{ vm_name }}"
- delegate_to: localhost
- register: vm_facts
-
- - name: Upgrade VMware Tools using uuid
- community.vmware.vmware_guest_tools_upgrade:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- uuid: "{{ vm_facts.instance.hw_product_uuid }}"
- delegate_to: localhost
-
- - name: Upgrade VMware Tools using MoID
- community.vmware.vmware_guest_tools_upgrade:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- moid: vm-42
- delegate_to: localhost
-
-
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Mike Klebolt (@MikeKlebolt) <michael.klebolt@centurylink.com>
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_tools_wait_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_tools_wait_module.rst
deleted file mode 100644
index 7913fb0ec..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_tools_wait_module.rst
+++ /dev/null
@@ -1,407 +0,0 @@
-.. _community.vmware.vmware_guest_tools_wait_module:
-
-
-****************************************
-community.vmware.vmware_guest_tools_wait
-****************************************
-
-**Wait for VMware tools to become available**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to wait for VMware tools to become available on the given VM and return facts.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the datacenter.</div>
- <div>The datacenter to search for a virtual machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>folder</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Destination folder, absolute or relative path to find an existing guest.</div>
- <div>This is required only, if multiple VMs with same <code>name</code> is found.</div>
- <div>The folder should include the datacenter. ESX&#x27;s datacenter is <code>ha-datacenter</code>.</div>
- <div>Examples:</div>
- <div>folder: /ha-datacenter/vm</div>
- <div>folder: ha-datacenter/vm</div>
- <div>folder: /datacenter1/vm</div>
- <div>folder: datacenter1/vm</div>
- <div>folder: /datacenter1/vm/folder1</div>
- <div>folder: datacenter1/vm/folder1</div>
- <div>folder: /folder1/datacenter1/vm</div>
- <div>folder: folder1/datacenter1/vm</div>
- <div>folder: /folder1/datacenter1/vm/folder2</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>moid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.</div>
- <div>This is required if <code>name</code> or <code>uuid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the VM for which to wait until the tools become available.</div>
- <div>This is required if <code>uuid</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name_match</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>first</b>&nbsp;&larr;</div></li>
- <li>last</li>
- </ul>
- </td>
- <td>
- <div>If multiple VMs match the name, use the first or last found.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>timeout</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">500</div>
- </td>
- <td>
- <div>Max duration of the waiting period (seconds).</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>use_instance_uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether to use the VMware instance UUID rather than the BIOS UUID.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>UUID of the VM for which to wait until the tools become available, if known. This is VMware&#x27;s unique identifier.</div>
- <div>This is required, if <code>name</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Wait for VMware tools to become available by UUID
- vmware_guest_facts:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter }}"
- folder: "/{{datacenter}}/vm"
- name: "{{ vm_name }}"
- delegate_to: localhost
- register: vm_facts
-
- - name: Get UUID from previous task and pass it to this task
- community.vmware.vmware_guest_tools_wait:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- uuid: "{{ vm_facts.instance.hw_product_uuid }}"
- delegate_to: localhost
- register: facts
-
-
- - name: Wait for VMware tools to become available by MoID
- community.vmware.vmware_guest_tools_wait:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- moid: vm-42
- delegate_to: localhost
- register: facts
-
- - name: Wait for VMware tools to become available by name
- community.vmware.vmware_guest_tools_wait:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- name: test-vm
- folder: "/{{datacenter}}/vm"
- datacenter: "{{ datacenter }}"
- delegate_to: localhost
- register: facts
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>instance</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about the virtual machine</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">None</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Philippe Dellaert (@pdellaert) <philippe@dellaert.org>
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_tpm_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_tpm_module.rst
deleted file mode 100644
index c3adf83bd..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_tpm_module.rst
+++ /dev/null
@@ -1,355 +0,0 @@
-.. _community.vmware.vmware_guest_tpm_module:
-
-
-*********************************
-community.vmware.vmware_guest_tpm
-*********************************
-
-**Add or remove vTPM device for specified VM.**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module is used for adding or removing Virtual Trusted Platform Module(vTPM) device for an existing Virtual Machine. You must create a key provider on vCenter before you can add a vTPM. The ESXi hosts running in your environment must be ESXi 6.7 or later (Windows guest OS), or 7.0 Update 2 (Linux guest OS).
-
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The vCenter datacenter name used to get specified cluster or host.</div>
- <div>This parameter is case sensitive.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>folder</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>VM folder, absolute or relative path to find an existing VM.</div>
- <div>This parameter is not required, only when multiple VMs are found with the same name.</div>
- <div>The folder should include the datacenter name.</div>
- <div>Examples:</div>
- <div>folder: /datacenter1/vm</div>
- <div>folder: datacenter1/vm</div>
- <div>folder: /datacenter1/vm/folder1</div>
- <div>folder: datacenter1/vm/folder1</div>
- <div>folder: /folder1/datacenter1/vm</div>
- <div>folder: folder1/datacenter1/vm</div>
- <div>folder: /folder1/datacenter1/vm/folder2</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>moid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.</div>
- <div>This is required if <code>name</code> or <code>uuid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the virtual machine.</div>
- <div>This is required if parameter <code>uuid</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>State of vTPM device.</div>
- <div>If set to &#x27;absent&#x27;, vTPM device will be removed from VM.</div>
- <div>If set to &#x27;present&#x27;, vTPM device will be added if not present.</div>
- <div>Virtual machine should be turned off before add or remove vTPM device.</div>
- <div>Virtual machine should not contain snapshots before add vTPM device.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>UUID of the instance to manage if known, this is VMware&#x27;s unique identifier.</div>
- <div>This is required if parameter <code>name</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Add vTPM to specified VM
- community.vmware.vmware_guest_tpm:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter }}"
- name: "Test_VM"
- state: present
- delegate_to: localhost
-
- - name: Remove vTPM from specified VM
- community.vmware.vmware_guest_tpm:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter }}"
- name: "Test_VM"
- state: absent
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>instance</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about the VM vTPM device</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">None</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Diane Wang (@Tomorrow9) <dianew@vmware.com>
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_vgpu_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_vgpu_info_module.rst
deleted file mode 100644
index 8760ebca6..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_vgpu_info_module.rst
+++ /dev/null
@@ -1,345 +0,0 @@
-.. _community.vmware.vmware_guest_vgpu_info_module:
-
-
-***************************************
-community.vmware.vmware_guest_vgpu_info
-***************************************
-
-**Gather information about vGPU profiles of the specified virtual machine in the given vCenter infrastructure**
-
-
-Version added: 3.3.0
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module is used to gather metadata about vGPU profiles of the given virtual machine.
-- All parameters and VMware object names are case sensitive.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">"ha-datacenter"</div>
- </td>
- <td>
- <div>The datacenter name to which virtual machine belongs to.</div>
- <div>This parameter is case sensitive.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>folder</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Destination folder, absolute or relative path to find an existing guest.</div>
- <div>This is a required parameter, only if multiple VMs are found with same name.</div>
- <div>The folder should include the datacenter. ESXi server&#x27;s datacenter is ha-datacenter.</div>
- <div>Examples:</div>
- <div>folder: /ha-datacenter/vm</div>
- <div>folder: ha-datacenter/vm</div>
- <div>folder: /datacenter1/vm</div>
- <div>folder: datacenter1/vm</div>
- <div>folder: /datacenter1/vm/folder1</div>
- <div>folder: datacenter1/vm/folder1</div>
- <div>folder: /folder1/datacenter1/vm</div>
- <div>folder: folder1/datacenter1/vm</div>
- <div>folder: /folder1/datacenter1/vm/folder2</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>moid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.</div>
- <div>This is required if <code>name</code> or <code>uuid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the virtual machine.</div>
- <div>This is a required parameter, if parameter <code>uuid</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>use_instance_uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether to use the VMware instance UUID rather than the BIOS UUID.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>UUID of the instance to gather facts if known, this is VMware&#x27;s unique identifier.</div>
- <div>This is a required parameter, if parameter <code>name</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Gather information about vGPU profiles of a VM
- community.vmware.vmware_guest_vgpu_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- validate_certs: false
- name: UbuntuTest
- delegate_to: localhost
- register: vgpu_info
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>vgpu_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about the virtual machine&#x27;s vGPU profiles</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;vgpu&#x27;: [{&#x27;Controller_Key&#x27;: 100, &#x27;Key&#x27;: 13000, &#x27;Label&#x27;: &#x27;PCI device 0&#x27;, &#x27;Summary&#x27;: &#x27;NVIDIA GRID vGPU grid_m10-8q&#x27;, &#x27;Unit_Number&#x27;: 18, &#x27;Vgpu&#x27;: &#x27;grid_m10-8q&#x27;}]}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Jared Priddy (@jdptechnc)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_vgpu_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_vgpu_module.rst
deleted file mode 100644
index 0e252ec62..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_vgpu_module.rst
+++ /dev/null
@@ -1,447 +0,0 @@
-.. _community.vmware.vmware_guest_vgpu_module:
-
-
-**********************************
-community.vmware.vmware_guest_vgpu
-**********************************
-
-**Modify vGPU video card profile of the specified virtual machine in the given vCenter infrastructure**
-
-
-Version added: 2.5.0
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module is used to reconfigure vGPU card profile of the given virtual machine.
-- All parameters and VMware object names are case sensitive.
-- VM must be power off :ref:`community.vmware.vmware_guest_powerstate <community.vmware.vmware_guest_powerstate_module>` module can perform that task.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The cluster name where the virtual machine is running.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">"ha-datacenter"</div>
- </td>
- <td>
- <div>The datacenter name to which virtual machine belongs to.</div>
- <div>This parameter is case sensitive.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The ESXi hostname where the virtual machine is running.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>folder</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Destination folder, absolute or relative path to find an existing guest.</div>
- <div>This is a required parameter, only if multiple VMs are found with same name.</div>
- <div>The folder should include the datacenter. ESXi server&#x27;s datacenter is ha-datacenter.</div>
- <div>Examples:</div>
- <div>folder: /ha-datacenter/vm</div>
- <div>folder: ha-datacenter/vm</div>
- <div>folder: /datacenter1/vm</div>
- <div>folder: datacenter1/vm</div>
- <div>folder: /datacenter1/vm/folder1</div>
- <div>folder: datacenter1/vm/folder1</div>
- <div>folder: /folder1/datacenter1/vm</div>
- <div>folder: folder1/datacenter1/vm</div>
- <div>folder: /folder1/datacenter1/vm/folder2</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>force</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Force operation.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>moid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.</div>
- <div>This is required if <code>name</code> or <code>uuid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the virtual machine.</div>
- <div>This is a required parameter, if parameter <code>uuid</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>vGPU profile state.</div>
- <div>When <code>state=present</code>, the selected vGPU profile will be added if the VM hosted ESXi host NVIDIA GPU offer it.</div>
- <div>When <code>state=absent</code>, the selected vGPU profile gets removed from the VM.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>use_instance_uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether to use the VMware instance UUID rather than the BIOS UUID.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>UUID of the instance to gather facts if known, this is VMware&#x27;s unique identifier.</div>
- <div>This is a required parameter, if parameter <code>name</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vgpu</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>A supported vGPU profile depending on the GPU model. Required for any operation.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Add vGPU profile to VM
- community.vmware.vmware_guest_vgpu:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- validate_certs: false
- name: UbuntuTest
- vgpu: 'grid_m10-8q'
- state: present
- delegate_to: localhost
- register: vgpu_info
-
- - name: Remove vGPU profile to VM
- community.vmware.vmware_guest_vgpu:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- validate_certs: false
- name: UbuntuTest
- vgpu: 'grid_m10-8q'
- state: absent
- delegate_to: localhost
- register: vgpu_info
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>vgpu_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about the virtual machine&#x27;s vGPU profile</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;vgpu&#x27;: {&#x27;Controller_Key&#x27;: 100, &#x27;Key&#x27;: 13000, &#x27;Label&#x27;: &#x27;PCI device 0&#x27;, &#x27;Summary&#x27;: &#x27;NVIDIA GRID vGPU grid_m10-8q&#x27;, &#x27;Unit_Number&#x27;: 18, &#x27;Vgpu&#x27;: &#x27;grid_m10-8q&#x27;}}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Mohamed Alibi (@Medalibi)
-- Unknown (@matancarmeli7)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_video_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_video_module.rst
deleted file mode 100644
index 4ebcea220..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_guest_video_module.rst
+++ /dev/null
@@ -1,486 +0,0 @@
-.. _community.vmware.vmware_guest_video_module:
-
-
-***********************************
-community.vmware.vmware_guest_video
-***********************************
-
-**Modify video card configurations of specified virtual machine in given vCenter infrastructure**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module is used to reconfigure video card settings of given virtual machine.
-- All parameters and VMware object names are case sensitive.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">"ha-datacenter"</div>
- </td>
- <td>
- <div>The datacenter name to which virtual machine belongs to.</div>
- <div>This parameter is case sensitive.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>display_number</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The number of display. Valid value from 1 to 10. The maximum display number is 4 on vCenter 6.0, 6.5 web UI.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>enable_3D</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Enable 3D for guest operating systems on which VMware supports 3D.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>folder</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Destination folder, absolute or relative path to find an existing guest.</div>
- <div>This is a required parameter, only if multiple VMs are found with same name.</div>
- <div>The folder should include the datacenter. ESXi server&#x27;s datacenter is ha-datacenter.</div>
- <div>Examples:</div>
- <div>folder: /ha-datacenter/vm</div>
- <div>folder: ha-datacenter/vm</div>
- <div>folder: /datacenter1/vm</div>
- <div>folder: datacenter1/vm</div>
- <div>folder: /datacenter1/vm/folder1</div>
- <div>folder: datacenter1/vm/folder1</div>
- <div>folder: /folder1/datacenter1/vm</div>
- <div>folder: folder1/datacenter1/vm</div>
- <div>folder: /folder1/datacenter1/vm/folder2</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>gather_video_facts</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>If set to <code>true</code>, return settings of the video card, other attributes are ignored.</div>
- <div>If set to <code>false</code>, will do reconfiguration and return video card settings.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>memory_3D_mb</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The value of 3D Memory must be power of 2 and valid value is from 32 MB to 2048 MB.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>moid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.</div>
- <div>This is required if <code>name</code> or <code>uuid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the virtual machine.</div>
- <div>This is a required parameter, if parameter <code>uuid</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>renderer_3D</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>automatic</li>
- <li>software</li>
- <li>hardware</li>
- </ul>
- </td>
- <td>
- <div>If set to <code>automatic</code>, selects the appropriate option (software or hardware) for this virtual machine automatically.</div>
- <div>If set to <code>software</code>, uses normal CPU processing for 3D calculations.</div>
- <div>If set to <code>hardware</code>, requires graphics hardware (GPU) for faster 3D calculations.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>use_auto_detect</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>If set to <code>true</code>, applies common video settings to the guest operating system, attributes <code>display_number</code> and <code>video_memory_mb</code> are ignored.</div>
- <div>If set to <code>false</code>, the number of display and the total video memory will be reconfigured using <code>display_number</code> and <code>video_memory_mb</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>UUID of the instance to gather facts if known, this is VMware&#x27;s unique identifier.</div>
- <div>This is a required parameter, if parameter <code>name</code> or <code>moid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>video_memory_mb</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">float</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Valid total MB of video memory range of virtual machine is from 1.172 MB to 256 MB on ESXi 6.7U1, from 1.172 MB to 128 MB on ESXi 6.7 and previous versions.</div>
- <div>For specific guest OS, supported minimum and maximum video memory are different, please be careful on setting this.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Change video card settings of virtual machine
- community.vmware.vmware_guest_video:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- name: test-vm
- gather_video_facts: false
- use_auto_detect: false
- display_number: 2
- video_memory_mb: 8.0
- enable_3D: true
- renderer_3D: automatic
- memory_3D_mb: 512
- delegate_to: localhost
- register: video_facts
-
- - name: Change video card settings of virtual machine using MoID
- community.vmware.vmware_guest_video:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- moid: vm-42
- gather_video_facts: false
- use_auto_detect: false
- display_number: 2
- video_memory_mb: 8.0
- enable_3D: true
- renderer_3D: automatic
- memory_3D_mb: 512
- delegate_to: localhost
- register: video_facts
-
- - name: Gather video card settings of virtual machine
- community.vmware.vmware_guest_video:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter_name }}"
- name: test-vm
- gather_video_facts: false
- delegate_to: localhost
- register: video_facts
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>video_status</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about the virtual machine&#x27;s video card after managing them</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;auto_detect&#x27;: False, &#x27;display_number&#x27;: 2, &#x27;enable_3D_support&#x27;: True, &#x27;memory_3D&#x27;: 524288, &#x27;renderer_3D&#x27;: &#x27;automatic&#x27;, &#x27;video_memory&#x27;: 8192}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Diane Wang (@Tomorrow9) <dianew@vmware.com>
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_acceptance_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_acceptance_module.rst
deleted file mode 100644
index 8766c25e5..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_acceptance_module.rst
+++ /dev/null
@@ -1,334 +0,0 @@
-.. _community.vmware.vmware_host_acceptance_module:
-
-
-***************************************
-community.vmware.vmware_host_acceptance
-***************************************
-
-**Manage the host acceptance level of an ESXi host**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to manage the host acceptance level of an ESXi host.
-- The host acceptance level controls the acceptance level of each VIB on a ESXi host.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>acceptance_level</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>community</li>
- <li>partner</li>
- <li>vmware_accepted</li>
- <li>vmware_certified</li>
- </ul>
- </td>
- <td>
- <div>Name of acceptance level.</div>
- <div>If set to <code>partner</code>, then accept only partner and VMware signed and certified VIBs.</div>
- <div>If set to <code>vmware_certified</code>, then accept only VIBs that are signed and certified by VMware.</div>
- <div>If set to <code>vmware_accepted</code>, then accept VIBs that have been accepted by VMware.</div>
- <div>If set to <code>community</code>, then accept all VIBs, even those that are not signed.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the cluster.</div>
- <div>Acceptance level of all ESXi host system in the given cluster will be managed.</div>
- <div>If <code>esxi_hostname</code> is not given, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>ESXi hostname.</div>
- <div>Acceptance level of this ESXi host system will be managed.</div>
- <div>If <code>cluster_name</code> is not given, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>list</b>&nbsp;&larr;</div></li>
- <li>present</li>
- </ul>
- </td>
- <td>
- <div>Set or list acceptance level of the given ESXi host.</div>
- <div>If set to <code>list</code>, then will return current acceptance level of given host system/s.</div>
- <div>If set to <code>present</code>, then will set given acceptance level.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Set acceptance level to community for all ESXi Host in given Cluster
- community.vmware.vmware_host_acceptance:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- cluster_name: cluster_name
- acceptance_level: 'community'
- state: present
- delegate_to: localhost
- register: cluster_acceptance_level
-
- - name: Set acceptance level to vmware_accepted for the given ESXi Host
- community.vmware.vmware_host_acceptance:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- acceptance_level: 'vmware_accepted'
- state: present
- delegate_to: localhost
- register: host_acceptance_level
-
- - name: Get acceptance level from the given ESXi Host
- community.vmware.vmware_host_acceptance:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- state: list
- delegate_to: localhost
- register: host_acceptance_level
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>facts</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>facts</td>
- <td>
- <div>dict with hostname as key and dict with acceptance level facts, error as value</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;facts&#x27;: {&#x27;localhost.localdomain&#x27;: {&#x27;error&#x27;: &#x27;NA&#x27;, &#x27;level&#x27;: &#x27;vmware_certified&#x27;}}}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_active_directory_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_active_directory_module.rst
deleted file mode 100644
index e312114cb..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_active_directory_module.rst
+++ /dev/null
@@ -1,343 +0,0 @@
-.. _community.vmware.vmware_host_active_directory_module:
-
-
-*********************************************
-community.vmware.vmware_host_active_directory
-*********************************************
-
-**Joins an ESXi host system to an Active Directory domain or leaves it**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to join or leave an ESXi host to or from an Active Directory domain.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>ad_domain</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">""</div>
- </td>
- <td>
- <div>AD Domain to join.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: domain, domain_name</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>ad_password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">""</div>
- </td>
- <td>
- <div>Password for AD domain join.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>ad_state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>present</li>
- <li><div style="color: blue"><b>absent</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Whether the ESXi host is joined to an AD domain or not.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: state</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>ad_user</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">""</div>
- </td>
- <td>
- <div>Username for AD domain join.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the cluster from which all host systems will be used.</div>
- <div>This parameter is required if <code>esxi_hostname</code> is not specified.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the host system to work with.</div>
- <div>This parameter is required if <code>cluster_name</code> is not specified.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Join an AD domain
- community.vmware.vmware_host_active_directory:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- ad_domain: example.local
- ad_user: adjoin
- ad_password: Password123$
- ad_state: present
- delegate_to: localhost
-
- - name: Leave AD domain
- community.vmware.vmware_host_active_directory:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- ad_state: absent
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>results</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about host system&#x27;s AD domain join state</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;esxi01&#x27;: {&#x27;changed&#x27;: True, &#x27;domain&#x27;: &#x27;example.local&#x27;, &#x27;membership_state&#x27;: &#x27;ok&#x27;, &#x27;msg&#x27;: &#x27;Host joined to AD domain&#x27;, &#x27;ad_state&#x27;: &#x27;present&#x27;, &#x27;ad_state_current&#x27;: &#x27;present&#x27;, &#x27;ad_state_previous&#x27;: &#x27;absent&#x27;}}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Christian Kotte (@ckotte)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_auto_start_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_auto_start_module.rst
deleted file mode 100644
index cb44f4a62..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_auto_start_module.rst
+++ /dev/null
@@ -1,609 +0,0 @@
-.. _community.vmware.vmware_host_auto_start_module:
-
-
-***************************************
-community.vmware.vmware_host_auto_start
-***************************************
-
-**Manage the auto power ON or OFF for vm on ESXi host**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- In this module, can set up automatic startup and shutdown of virtual machines according to host startup or shutdown.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="2">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>ESXi hostname where the VM to set auto power on or off exists.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>moid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.</div>
- <div>This is required if <code>name</code> or <code>uuid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>VM name to set auto power on or off.</div>
- <div>This is not necessary if change only system default VM settings for autoStart config.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>power_info</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">{"start_action": "none", "start_delay": -1, "start_order": -1, "stop_action": "systemDefault", "stop_delay": -1, "wait_for_heartbeat": "systemDefault"}</div>
- </td>
- <td>
- <div>Startup or shutdown settings of virtual machine.</div>
- <div>This setting will override the system defaults.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>start_action</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>none</b>&nbsp;&larr;</div></li>
- <li>powerOn</li>
- </ul>
- </td>
- <td>
- <div>Whether to start the virtual machine when the host startup.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>start_delay</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">-1</div>
- </td>
- <td>
- <div>Auto start delay in seconds of virtual machine.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>start_order</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">-1</div>
- </td>
- <td>
- <div>The autostart priority of virtual machine.</div>
- <div>Virtual machines with a lower number are powered on first.</div>
- <div>On host shutdown, the virtual machines are shut down in reverse order, meaning those with a higher number are powered off first.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>stop_action</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>none</li>
- <li><div style="color: blue"><b>systemDefault</b>&nbsp;&larr;</div></li>
- <li>powerOff</li>
- <li>suspend</li>
- </ul>
- </td>
- <td>
- <div>Stop action executed on the virtual machine when the system stops of virtual machine.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>stop_delay</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">-1</div>
- </td>
- <td>
- <div>Auto stop delay in seconds of virtual machine.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>wait_for_heartbeat</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- <li><div style="color: blue"><b>systemDefault</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Continue power on processing when VMware Tools started.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>system_defaults</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>System defaults for auto-start or auto-stop config for virtual machine.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>enabled</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Enable automatically start or stop of virtual machines.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>start_delay</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">120</div>
- </td>
- <td>
- <div>Default auto start delay in seconds.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>stop_action</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>none</li>
- <li>guestShutdown</li>
- <li><div style="color: blue"><b>powerOff</b>&nbsp;&larr;</div></li>
- <li>suspend</li>
- </ul>
- </td>
- <td>
- <div>Default stop action executed on the virtual machine when the system stops.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>stop_delay</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">120</div>
- </td>
- <td>
- <div>Default auto stop delay in seconds.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>wait_for_heartbeat</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Continue power on processing when VMware Tools started.</div>
- <div>If this parameter is enabled to powers on the next virtual machine without waiting for the delay to pass.</div>
- <div>However, the virtual machine must have VMware Tools installed.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>use_instance_uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether to use the VMware instance UUID rather than the BIOS UUID.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>VM uuid to set auto power on or off, this is VMware&#x27;s unique identifier.</div>
- <div>This is required if <code>name</code> is not supplied.</div>
- <div>This is not necessary if change only system default VM settings for autoStart config.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- ---
- - name: Update for system defaults config.
- community.vmware.vmware_host_auto_start:
- hostname: "{{ hostname }}"
- username: "{{ username }}"
- password: "{{ password }}"
- esxi_hostname: "{{ esxi_hostname }}"
- system_defaults:
- enabled: true
- start_delay: 100
- stop_action: guestShutdown
-
- - name: Update for powerInfo config of virtual machine.
- community.vmware.vmware_host_auto_start:
- hostname: "{{ hostname }}"
- username: "{{ username }}"
- password: "{{ password }}"
- esxi_hostname: "{{ esxi_hostname }}"
- name: "{{ vm_name }}"
- power_info:
- start_action: powerOn
- start_delay: 10
- start_order: 1
- stop_action: powerOff
- wait_for_heartbeat: true
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>power_info_config</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>changed</td>
- <td>
- <div>Parameter return when virtual machine power info config is changed.</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{
- &quot;start_action&quot;: &quot;powerOn&quot;,
- &quot;start_delay&quot;: -1,
- &quot;start_order&quot;: -1,
- &quot;stop_action&quot;: &quot;systemDefault&quot;,
- &quot;stop_delay&quot;: -1,
- &quot;wait_for_heartbeat&quot;: &quot;systemDefault&quot;
- }</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>system_defaults_config</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>changed</td>
- <td>
- <div>Parameter return when system defaults config is changed.</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{
- &quot;enabled&quot;: true,
- &quot;start_delay&quot;: 120,
- &quot;stop_action&quot;: &quot;powerOff&quot;,
- &quot;stop_delay&quot;: 120,
- &quot;wait_for_heartbeat&quot;: false
- }</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- sky-joker (@sky-joker)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_capability_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_capability_info_module.rst
deleted file mode 100644
index ba9a11b46..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_capability_info_module.rst
+++ /dev/null
@@ -1,271 +0,0 @@
-.. _community.vmware.vmware_host_capability_info_module:
-
-
-********************************************
-community.vmware.vmware_host_capability_info
-********************************************
-
-**Gathers info about an ESXi host's capability information**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to gather information about an ESXi host's capability information when ESXi hostname or Cluster name is given.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the cluster from all host systems to be used for information gathering.</div>
- <div>If <code>esxi_hostname</code> is not given, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>ESXi hostname to gather information from.</div>
- <div>If <code>cluster_name</code> is not given, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Gather capability info about all ESXi Host in given Cluster
- community.vmware.vmware_host_capability_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- cluster_name: cluster_name
- delegate_to: localhost
- register: all_cluster_hosts_info
-
- - name: Gather capability info about ESXi Host
- community.vmware.vmware_host_capability_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- delegate_to: localhost
- register: hosts_info
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>hosts_capability_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about host&#x27;s capability info</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;esxi_hostname_0001&#x27;: {&#x27;accel3dSupported&#x27;: False, &#x27;backgroundSnapshotsSupported&#x27;: False, &#x27;checkpointFtCompatibilityIssues&#x27;: [], &#x27;checkpointFtSupported&#x27;: False, &#x27;cloneFromSnapshotSupported&#x27;: True, &#x27;cpuHwMmuSupported&#x27;: True}}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_config_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_config_info_module.rst
deleted file mode 100644
index b7ed1f010..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_config_info_module.rst
+++ /dev/null
@@ -1,269 +0,0 @@
-.. _community.vmware.vmware_host_config_info_module:
-
-
-****************************************
-community.vmware.vmware_host_config_info
-****************************************
-
-**Gathers info about an ESXi host's advance configuration information**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to gather information about an ESXi host's advance configuration information when ESXi hostname or Cluster name is given.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the cluster from which the ESXi host belong to.</div>
- <div>If <code>esxi_hostname</code> is not given, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>ESXi hostname to gather information from.</div>
- <div>If <code>cluster_name</code> is not given, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Gather info about all ESXi Host in given Cluster
- community.vmware.vmware_host_config_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- cluster_name: cluster_name
- delegate_to: localhost
-
- - name: Gather info about ESXi Host
- community.vmware.vmware_host_config_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>hosts_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>dict with hostname as key and dict with host config information</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;10.76.33.226&#x27;: {&#x27;Annotations.WelcomeMessage&#x27;: &#x27;&#x27;, &#x27;BufferCache.FlushInterval&#x27;: 30000, &#x27;BufferCache.HardMaxDirty&#x27;: 95, &#x27;BufferCache.PerFileHardMaxDirty&#x27;: 50, &#x27;BufferCache.SoftMaxDirty&#x27;: 15}}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_config_manager_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_config_manager_module.rst
deleted file mode 100644
index fb47d56c6..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_config_manager_module.rst
+++ /dev/null
@@ -1,273 +0,0 @@
-.. _community.vmware.vmware_host_config_manager_module:
-
-
-*******************************************
-community.vmware.vmware_host_config_manager
-*******************************************
-
-**Manage advanced system settings of an ESXi host**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to manage advanced system settings of an ESXi host when ESXi hostname or Cluster name is given.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the cluster.</div>
- <div>Settings are applied to every ESXi host in given cluster.</div>
- <div>If <code>esxi_hostname</code> is not given, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>ESXi hostname.</div>
- <div>Settings are applied to this ESXi host.</div>
- <div>If <code>cluster_name</code> is not given, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>options</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">{}</div>
- </td>
- <td>
- <div>A dictionary of advanced system settings.</div>
- <div>Invalid options will cause module to error.</div>
- <div>Note that the list of advanced options (with description and values) can be found by running `vim-cmd hostsvc/advopt/options`.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Manage Log level setting for all ESXi hosts in given Cluster
- community.vmware.vmware_host_config_manager:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- cluster_name: cluster_name
- options:
- 'Config.HostAgent.log.level': 'info'
- delegate_to: localhost
-
- - name: Manage Log level setting for an ESXi host
- community.vmware.vmware_host_config_manager:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- options:
- 'Config.HostAgent.log.level': 'verbose'
- delegate_to: localhost
-
- - name: Manage multiple settings for an ESXi host
- community.vmware.vmware_host_config_manager:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- options:
- 'Config.HostAgent.log.level': 'verbose'
- 'Annotations.WelcomeMessage': 'Hello World'
- 'Config.HostAgent.plugins.solo.enableMob': false
- delegate_to: localhost
-
-
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_custom_attributes_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_custom_attributes_module.rst
deleted file mode 100644
index ef0d60705..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_custom_attributes_module.rst
+++ /dev/null
@@ -1,337 +0,0 @@
-.. _community.vmware.vmware_host_custom_attributes_module:
-
-
-**********************************************
-community.vmware.vmware_host_custom_attributes
-**********************************************
-
-**Manage custom attributes from VMware for the given ESXi host**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to add, remove and update custom attributes for the given ESXi host.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="2">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>attributes</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">[]</div>
- </td>
- <td>
- <div>A list of name and value of custom attributes that needs to be manage.</div>
- <div>Value of custom attribute is not required and will be ignored, if <code>state</code> is set to <code>absent</code>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the attribute.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>value</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">""</div>
- </td>
- <td>
- <div>Value of the attribute.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the ESXi host to work with.</div>
- <div>This is a required parameter</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>The action to take.</div>
- <div>If set to <code>present</code>, then custom attribute is added or updated.</div>
- <div>If set to <code>absent</code>, then custom attribute is removed.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Add ESXi host custom attributes
- community.vmware.vmware_host_custom_attributes:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- esxi_hostname: host1
- state: present
- attributes:
- - name: MyAttribute
- value: MyValue
- delegate_to: localhost
- register: attributes
-
- - name: Remove ESXi host Attribute
- community.vmware.vmware_host_custom_attributes:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- esxi_hostname: host1
- state: absent
- attributes:
- - name: MyAttribute
- delegate_to: localhost
- register: attributes
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>custom_attributes</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>changed</td>
- <td>
- <div>metadata about the ESXi host attributes</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;mycustom&#x27;: &#x27;my_custom_value&#x27;, &#x27;mycustom_2&#x27;: &#x27;my_custom_value_2&#x27;, &#x27;sample_1&#x27;: &#x27;sample_1_value&#x27;, &#x27;sample_2&#x27;: &#x27;sample_2_value&#x27;, &#x27;sample_3&#x27;: &#x27;sample_3_value&#x27;}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Hunter Christain (@exp-hc)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_datastore_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_datastore_module.rst
deleted file mode 100644
index 7bcd1eb92..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_datastore_module.rst
+++ /dev/null
@@ -1,428 +0,0 @@
-.. _community.vmware.vmware_host_datastore_module:
-
-
-**************************************
-community.vmware.vmware_host_datastore
-**************************************
-
-**Manage a datastore on ESXi host**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to mount/umount datastore on ESXi host.
-- This module only supports NFS (NFS v3 or NFS v4.1) and VMFS datastores.
-- For VMFS datastore, available device must already be connected on ESXi host.
-- All parameters and VMware object names are case sensitive.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>auto_expand</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Expand a datastore capacity to full if it has free capacity.</div>
- <div>This parameter can&#x27;t be extend using another datastore.</div>
- <div>A use case example in <em>auto_expand</em>, it can be used to expand a datastore capacity after increasing LUN volume.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datastore_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the datastore to add/remove.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datastore_type</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>nfs</li>
- <li>nfs41</li>
- <li>vmfs</li>
- </ul>
- </td>
- <td>
- <div>Type of the datastore to configure (nfs/nfs41/vmfs).</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>ESXi hostname to manage the datastore.</div>
- <div>Required when used with a vcenter</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>nfs_path</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Resource path on NFS host.</div>
- <div>Required if datastore type is set to <code>nfs</code>/<code>nfs41</code> and state is set to <code>present</code>, else unused.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>nfs_ro</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>ReadOnly or ReadWrite mount.</div>
- <div>Unused if datastore type is not set to <code>nfs</code>/<code>nfs41</code> and state is not set to <code>present</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>nfs_server</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>NFS host serving nfs datastore.</div>
- <div>Required if datastore type is set to <code>nfs</code>/<code>nfs41</code> and state is set to <code>present</code>, else unused.</div>
- <div>Two or more servers can be defined if datastore type is set to <code>nfs41</code></div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>present: Mount datastore on host if datastore is absent else do nothing.</div>
- <div>absent: Umount datastore if datastore is present else do nothing.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vmfs_device_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the device to be used as VMFS datastore.</div>
- <div>Required for VMFS datastore type and state is set to <code>present</code>, else unused.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vmfs_version</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>VMFS version to use for datastore creation.</div>
- <div>Unused if datastore type is not set to <code>vmfs</code> and state is not set to <code>present</code>.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - Kerberos authentication with NFS v4.1 isn't implemented
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Mount VMFS datastores to ESXi
- community.vmware.vmware_host_datastore:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datastore_name: '{{ item.name }}'
- datastore_type: '{{ item.type }}'
- vmfs_device_name: 'naa.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
- vmfs_version: 6
- esxi_hostname: '{{ inventory_hostname }}'
- state: present
- delegate_to: localhost
-
- - name: Mount NFS datastores to ESXi
- community.vmware.vmware_host_datastore:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datastore_name: '{{ item.name }}'
- datastore_type: '{{ item.type }}'
- nfs_server: '{{ item.server }}'
- nfs_path: '{{ item.path }}'
- nfs_ro: false
- esxi_hostname: '{{ inventory_hostname }}'
- state: present
- delegate_to: localhost
- loop:
- - { 'name': 'NasDS_vol01', 'server': 'nas01', 'path': '/mnt/vol01', 'type': 'nfs'}
- - { 'name': 'NasDS_vol02', 'server': 'nas01', 'path': '/mnt/vol02', 'type': 'nfs'}
-
- - name: Mount NFS v4.1 datastores to ESXi
- community.vmware.vmware_host_datastore:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datastore_name: '{{ item.name }}'
- datastore_type: '{{ item.type }}'
- nfs_server: '{{ item.server }}'
- nfs_path: '{{ item.path }}'
- nfs_ro: false
- esxi_hostname: '{{ inventory_hostname }}'
- state: present
- delegate_to: localhost
- loop:
- - { 'name': 'NasDS_vol03', 'server': 'nas01,nas02', 'path': '/mnt/vol01', 'type': 'nfs41'}
- - { 'name': 'NasDS_vol04', 'server': 'nas01,nas02', 'path': '/mnt/vol02', 'type': 'nfs41'}
-
- - name: Remove/Umount Datastores from a ESXi
- community.vmware.vmware_host_datastore:
- hostname: '{{ esxi_hostname }}'
- username: '{{ esxi_username }}'
- password: '{{ esxi_password }}'
- datastore_name: NasDS_vol01
- state: absent
- delegate_to: localhost
-
-
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Ludovic Rivallain (@lrivallain) <ludovic.rivallain@gmail.com>
-- Christian Kotte (@ckotte) <christian.kotte@gmx.de>
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_disk_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_disk_info_module.rst
deleted file mode 100644
index 496407c3c..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_disk_info_module.rst
+++ /dev/null
@@ -1,295 +0,0 @@
-.. _community.vmware.vmware_host_disk_info_module:
-
-
-**************************************
-community.vmware.vmware_host_disk_info
-**************************************
-
-**Gathers information about disks attached to given ESXi host/s.**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module returns information about disks attached to given ESXi host/s
-- If *cluster_name* is provided, then disk information about all hosts from the given cluster will be returned.
-- If *esxi_hostname* is provided, then disk information about the given host system will be returned.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the cluster from which the ESXi host belong to.</div>
- <div>If <code>esxi_hostname</code> is not given, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>ESXi hostname to gather information from.</div>
- <div>If <code>cluster_name</code> is not given, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Gather info about vmhbas of all ESXi Host in the given Cluster
- community.vmware.vmware_host_disk_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- cluster_name: '{{ cluster_name }}'
- delegate_to: localhost
- register: cluster_host_vmhbas
-
- - name: Gather info about vmhbas of an ESXi Host
- community.vmware.vmware_host_disk_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- delegate_to: localhost
- register: host_vmhbas
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>hosts_disk_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>list of information for all disks attached to each ESXi host</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">&quot;192.168.0.182&quot;: [
- {
- &quot;canonical_name&quot;: &quot;naa.6000c296ed6217bd61df35622eb21a3a&quot;,
- &quot;capacity_mb&quot;: 4096,
- &quot;device_path&quot;: &quot;/vmfs/devices/disks/naa.6000c296ed6217bd61df35622eb21a3a&quot;,
- &quot;device_type&quot;: &quot;disk&quot;,
- &quot;device_ctd_list&quot;: [
- &quot;vmhba0:C0:T1:L0&quot;
- ],
- &quot;disk_uid&quot;: &quot;key-vim.host.ScsiDisk-02000000006000c296ed6217bd61df35622eb21a3a566972747561&quot;,
- &quot;display_name&quot;: &quot;Local VMware Disk (naa.6000c296ed6217bd61df35622eb21a3a)&quot;
- },
- {
- &quot;canonical_name&quot;: &quot;naa.6000c2968ad7142d93faae527fe8822b&quot;,
- &quot;capacity_mb&quot;: 204800,
- &quot;device_path&quot;: &quot;/vmfs/devices/disks/naa.6000c2968ad7142d93faae527fe8822b&quot;,
- &quot;device_type&quot;: &quot;disk&quot;,
- &quot;device_ctd_list&quot;: [
- &quot;vmhba0:C0:T3:L0&quot;
- ],
- &quot;disk_uid&quot;: &quot;key-vim.host.ScsiDisk-02000000006000c2968ad7142d93faae527fe8822b566972747561&quot;,
- &quot;display_name&quot;: &quot;Local VMware Disk (naa.6000c2968ad7142d93faae527fe8822b)&quot;
- },]</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Matt Proud (@laidbackware)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_dns_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_dns_info_module.rst
deleted file mode 100644
index 166f0f2aa..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_dns_info_module.rst
+++ /dev/null
@@ -1,270 +0,0 @@
-.. _community.vmware.vmware_host_dns_info_module:
-
-
-*************************************
-community.vmware.vmware_host_dns_info
-*************************************
-
-**Gathers info about an ESXi host's DNS configuration information**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to gather information about an ESXi host's DNS configuration information when ESXi hostname or Cluster name is given.
-- All parameters and VMware object names are case sensitive.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the cluster from which the ESXi host belong to.</div>
- <div>If <code>esxi_hostname</code> is not given, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>ESXi hostname to gather information from.</div>
- <div>If <code>cluster_name</code> is not given, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Gather DNS info about all ESXi Hosts in given Cluster
- community.vmware.vmware_host_dns_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- cluster_name: cluster_name
- delegate_to: localhost
-
- - name: Gather DNS info about ESXi Host
- community.vmware.vmware_host_dns_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>hosts_dns_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about DNS config from given cluster / host system</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;DC0_C0_H0&#x27;: {&#x27;dhcp&#x27;: True, &#x27;domain_name&#x27;: &#x27;localdomain&#x27;, &#x27;host_name&#x27;: &#x27;localhost&#x27;, &#x27;ip_address&#x27;: [&#x27;8.8.8.8&#x27;], &#x27;search_domain&#x27;: [&#x27;localdomain&#x27;], &#x27;virtual_nic_device&#x27;: &#x27;vmk0&#x27;}}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_dns_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_dns_module.rst
deleted file mode 100644
index d566a4856..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_dns_module.rst
+++ /dev/null
@@ -1,422 +0,0 @@
-.. _community.vmware.vmware_host_dns_module:
-
-
-********************************
-community.vmware.vmware_host_dns
-********************************
-
-**Manage DNS configuration of an ESXi host system**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to configure DNS for the default TCP/IP stack on an ESXi host system.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the cluster from which all host systems will be used.</div>
- <div>This parameter is required if <code>esxi_hostname</code> is not specified and you connect to a vCenter.</div>
- <div>Cannot be used when you connect directly to an ESXi host.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>device</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The VMkernel network adapter to obtain DNS settings from.</div>
- <div>Needs to get its IP through DHCP, a static network configuration combined with a dynamic DNS configuration doesn&#x27;t work.</div>
- <div>The parameter is only required in case of <code>type</code> is set to <code>dhcp</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>dns_servers</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>A list of DNS servers to be used.</div>
- <div>The order of the DNS servers is important as they are used consecutively in order.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>domain</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The domain name to be used for the ESXi host.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the host system to work with.</div>
- <div>This parameter is required if <code>cluster_name</code> is not specified and you connect to a vCenter.</div>
- <div>Cannot be used when you connect directly to an ESXi host.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>host_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname to be used for the ESXi host.</div>
- <div>Cannot be used when configuring a complete cluster.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>search_domains</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>A list of domains to be searched through by the resolver.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>type</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>dhcp</li>
- <li>static</li>
- </ul>
- </td>
- <td>
- <div>Type of DNS assignment. Either <code>dhcp</code> or <code>static</code>.</div>
- <div>A VMkernel adapter needs to be set to DHCP if <code>type</code> is set to <code>dhcp</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>verbose</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Verbose output of the DNS server configuration change.</div>
- <div>Explains if an DNS server was added, removed, or if the DNS server sequence was changed.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - This module is a replacement for the module ``vmware_dns_config``
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Configure DNS for an ESXi host
- community.vmware.vmware_host_dns:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- type: static
- host_name: esx01
- domain: example.local
- dns_servers:
- - 192.168.1.10
- - 192.168.1.11
- search_domains:
- - subdomain.example.local
- - example.local
- delegate_to: localhost
-
- - name: Configure DNS for all ESXi hosts of a cluster
- community.vmware.vmware_host_dns:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- cluster_name: '{{ cluster_name }}'
- type: static
- domain: example.local
- dns_servers:
- - 192.168.1.10
- - 192.168.1.11
- search_domains:
- - subdomain.example.local
- - example.local
- delegate_to: localhost
-
- - name: Configure DNS via DHCP for an ESXi host
- community.vmware.vmware_host_dns:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- type: dhcp
- device: vmk0
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>dns_config_result</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about host system&#x27;s DNS configuration</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;esx01.example.local&#x27;: {&#x27;changed&#x27;: True, &#x27;dns_servers_changed&#x27;: [&#x27;192.168.1.12&#x27;, &#x27;192.168.1.13&#x27;], &#x27;dns_servers&#x27;: [&#x27;192.168.1.10&#x27;, &#x27;192.168.1.11&#x27;], &#x27;dns_servers_previous&#x27;: [&#x27;192.168.1.10&#x27;, &#x27;192.168.1.11&#x27;, &#x27;192.168.1.12&#x27;, &#x27;192.168.1.13&#x27;], &#x27;domain&#x27;: &#x27;example.local&#x27;, &#x27;host_name&#x27;: &#x27;esx01&#x27;, &#x27;msg&#x27;: &#x27;DNS servers and Search domains changed&#x27;, &#x27;search_domains_changed&#x27;: [&#x27;subdomain.example.local&#x27;], &#x27;search_domains&#x27;: [&#x27;subdomain.example.local&#x27;, &#x27;example.local&#x27;], &#x27;search_domains_previous&#x27;: [&#x27;example.local&#x27;]}}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Christian Kotte (@ckotte)
-- Mario Lenz (@mariolenz)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_facts_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_facts_module.rst
deleted file mode 100644
index c9c015f0d..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_facts_module.rst
+++ /dev/null
@@ -1,368 +0,0 @@
-.. _community.vmware.vmware_host_facts_module:
-
-
-**********************************
-community.vmware.vmware_host_facts
-**********************************
-
-**Gathers facts about remote ESXi hostsystem**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to gathers facts like CPU, memory, datastore, network and system etc. about ESXi host system.
-- Please specify hostname or IP address of ESXi host system as ``hostname``.
-- If hostname or IP address of vCenter is provided as ``hostname`` and ``esxi_hostname`` is not specified, then the module will throw an error.
-- VSAN facts added in 2.7 version.
-- SYSTEM fact uuid added in 2.10 version.
-- Connection state fact added in VMware collection 2.6.0.
-- Please note that when ESXi host connection state is not ``connected``, facts returned from vCenter might be stale. Users are recommended to check connection state value and take appropriate decision in the playbook.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>ESXi hostname.</div>
- <div>Host facts about the specified ESXi server will be returned.</div>
- <div>By specifying this option, you can select which ESXi hostsystem is returned if connecting to a vCenter.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>properties</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Specify the properties to retrieve.</div>
- <div>If not specified, all properties are retrieved (deeply).</div>
- <div>Results are returned in a structure identical to the vsphere API.</div>
- <div>Example:</div>
- <div>properties: [</div>
- <div>&quot;hardware.memorySize&quot;,</div>
- <div>&quot;hardware.cpuInfo.numCpuCores&quot;,</div>
- <div>&quot;config.product.apiVersion&quot;,</div>
- <div>&quot;overallStatus&quot;</div>
- <div>]</div>
- <div>Only valid when <code>schema</code> is <code>vsphere</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>schema</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>summary</b>&nbsp;&larr;</div></li>
- <li>vsphere</li>
- </ul>
- </td>
- <td>
- <div>Specify the output schema desired.</div>
- <div>The &#x27;summary&#x27; output schema is the legacy output from the module</div>
- <div>The &#x27;vsphere&#x27; output schema is the vSphere API class definition which requires pyvmomi&gt;6.7.1</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>show_tag</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Tags related to Host are shown if set to <code>true</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Gather vmware host facts
- community.vmware.vmware_host_facts:
- hostname: "{{ esxi_server }}"
- username: "{{ esxi_username }}"
- password: "{{ esxi_password }}"
- register: host_facts
- delegate_to: localhost
-
- - name: Gather vmware host facts from vCenter
- community.vmware.vmware_host_facts:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- esxi_hostname: "{{ esxi_hostname }}"
- register: host_facts
- delegate_to: localhost
-
- - name: Gather vmware host facts from vCenter with tag information
- community.vmware.vmware_host_facts:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- esxi_hostname: "{{ esxi_hostname }}"
- show_tag: true
- register: host_facts_tag
- delegate_to: localhost
-
- - name: Get VSAN Cluster UUID from host facts
- community.vmware.vmware_host_facts:
- hostname: "{{ esxi_server }}"
- username: "{{ esxi_username }}"
- password: "{{ esxi_password }}"
- register: host_facts
- - set_fact:
- cluster_uuid: "{{ host_facts['ansible_facts']['vsan_cluster_uuid'] }}"
-
- - name: Gather some info from a host using the vSphere API output schema
- community.vmware.vmware_host_facts:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- esxi_hostname: "{{ esxi_hostname }}"
- schema: vsphere
- properties:
- - hardware.memorySize
- - hardware.cpuInfo.numCpuCores
- - config.product.apiVersion
- - overallStatus
- register: host_facts
-
- - name: Gather information about powerstate and connection state
- community.vmware.vmware_host_facts:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- esxi_hostname: "{{ esxi_hostname }}"
- schema: vsphere
- properties:
- - runtime.connectionState
- - runtime.powerState
-
- - name: How to retrieve Product, Version, Build, Update info for ESXi from vCenter
- block:
- - name: Gather product version info for ESXi from vCenter
- community.vmware.vmware_host_facts:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- esxi_hostname: "{{ esxi_hostname }}"
- schema: vsphere
- properties:
- - config.product
- - config.option
- register: gather_host_facts_result
-
- - name: Extract update level info from option properties
- set_fact:
- update_level_info: "{{ item.value }}"
- loop: "{{ gather_host_facts_result.ansible_facts.config.option }}"
- when:
- - item.key == 'Misc.HostAgentUpdateLevel'
-
- - name: The output of Product, Version, Build, Update info for ESXi
- debug:
- msg:
- - "Product : {{ gather_host_facts_result.ansible_facts.config.product.name }}"
- - "Version : {{ gather_host_facts_result.ansible_facts.config.product.version }}"
- - "Build : {{ gather_host_facts_result.ansible_facts.config.product.build }}"
- - "Update : {{ update_level_info }}"
-
-
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Wei Gao (@woshihaoren)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_feature_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_feature_info_module.rst
deleted file mode 100644
index 9ccf0e1e1..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_feature_info_module.rst
+++ /dev/null
@@ -1,279 +0,0 @@
-.. _community.vmware.vmware_host_feature_info_module:
-
-
-*****************************************
-community.vmware.vmware_host_feature_info
-*****************************************
-
-**Gathers info about an ESXi host's feature capability information**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to gather information about an ESXi host's feature capability information when ESXi hostname or Cluster name is given.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the cluster from all host systems to be used for information gathering.</div>
- <div>If <code>esxi_hostname</code> is not given, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>ESXi hostname to gather information from.</div>
- <div>If <code>cluster_name</code> is not given, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Gather feature capability info about all ESXi Hosts in given Cluster
- community.vmware.vmware_host_feature_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- cluster_name: '{{ cluster_name }}'
- delegate_to: localhost
- register: all_cluster_hosts_info
-
- - name: Check if ESXi is vulnerable for Speculative Store Bypass Disable (SSBD) vulnerability
- community.vmware.vmware_host_feature_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- esxi_hostname: "{{ esxi_hostname }}"
- register: features_set
- - set_fact:
- ssbd : "{{ item.value }}"
- loop: "{{ features_set.host_feature_info[esxi_hostname] |json_query(name) }}"
- vars:
- name: "[?key=='cpuid.SSBD']"
- - assert:
- that:
- - ssbd|int == 1
- when: ssbd is defined
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>hosts_feature_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about host&#x27;s feature capability information</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;10.76.33.226&#x27;: [{&#x27;feature_name&#x27;: &#x27;cpuid.3DNOW&#x27;, &#x27;key&#x27;: &#x27;cpuid.3DNOW&#x27;, &#x27;value&#x27;: &#x27;0&#x27;}, {&#x27;feature_name&#x27;: &#x27;cpuid.3DNOWPLUS&#x27;, &#x27;key&#x27;: &#x27;cpuid.3DNOWPLUS&#x27;, &#x27;value&#x27;: &#x27;0&#x27;}]}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_firewall_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_firewall_info_module.rst
deleted file mode 100644
index 295e750e0..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_firewall_info_module.rst
+++ /dev/null
@@ -1,269 +0,0 @@
-.. _community.vmware.vmware_host_firewall_info_module:
-
-
-******************************************
-community.vmware.vmware_host_firewall_info
-******************************************
-
-**Gathers info about an ESXi host's firewall configuration information**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to gather information about an ESXi host's firewall configuration information when ESXi hostname or Cluster name is given.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the cluster from which the ESXi host belong to.</div>
- <div>If <code>esxi_hostname</code> is not given, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>ESXi hostname to gather information from.</div>
- <div>If <code>cluster_name</code> is not given, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Gather firewall info about all ESXi Host in given Cluster
- community.vmware.vmware_host_firewall_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- cluster_name: cluster_name
- delegate_to: localhost
-
- - name: Gather firewall info about ESXi Host
- community.vmware.vmware_host_firewall_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>hosts_firewall_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>on success</td>
- <td>
- <div>metadata about host&#x27;s firewall configuration</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;esxi_hostname_0001&#x27;: [{&#x27;allowed_hosts&#x27;: {&#x27;all_ip&#x27;: True, &#x27;ip_address&#x27;: [&#x27;10.10.10.1&#x27;], &#x27;ip_network&#x27;: [&#x27;11.111.112.0/22&#x27;, &#x27;192.168.10.1/24&#x27;]}, &#x27;enabled&#x27;: True, &#x27;key&#x27;: &#x27;CIMHttpServer&#x27;, &#x27;rule&#x27;: [{&#x27;direction&#x27;: &#x27;inbound&#x27;, &#x27;end_port&#x27;: None, &#x27;port&#x27;: 5988, &#x27;port_type&#x27;: &#x27;dst&#x27;, &#x27;protocol&#x27;: &#x27;tcp&#x27;}], &#x27;service&#x27;: &#x27;sfcbd-watchdog&#x27;}]}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_firewall_manager_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_firewall_manager_module.rst
deleted file mode 100644
index d10dba142..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_firewall_manager_module.rst
+++ /dev/null
@@ -1,464 +0,0 @@
-.. _community.vmware.vmware_host_firewall_manager_module:
-
-
-*********************************************
-community.vmware.vmware_host_firewall_manager
-*********************************************
-
-**Manage firewall configurations about an ESXi host**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to manage firewall configurations about an ESXi host when ESXi hostname or Cluster name is given.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="3">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the cluster.</div>
- <div>Firewall settings are applied to every ESXi host system in given cluster.</div>
- <div>If <code>esxi_hostname</code> is not given, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>ESXi hostname.</div>
- <div>Firewall settings are applied to this ESXi host system.</div>
- <div>If <code>cluster_name</code> is not given, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>rules</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">[]</div>
- </td>
- <td>
- <div>A list of Rule set which needs to be managed.</div>
- <div>Each member of list is rule set name and state to be set the rule.</div>
- <div>Both rule name and rule state are required parameters.</div>
- <div>Additional IPs and networks can also be specified</div>
- <div>Please see examples for more information.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>allowed_hosts</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Define the allowed hosts for this rule set.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>all_ip</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether all hosts should be allowed or not.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>ip_address</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">[]</div>
- </td>
- <td>
- <div>List of allowed IP addresses.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>ip_network</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">[]</div>
- </td>
- <td>
- <div>List of allowed IP networks.</div>
- </td>
- </tr>
-
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>enabled</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether the rule set is enabled or not.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Rule set name.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Enable vvold rule set for all ESXi Host in given Cluster
- community.vmware.vmware_host_firewall_manager:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- cluster_name: cluster_name
- rules:
- - name: vvold
- enabled: true
- allowed_hosts:
- all_ip: true
- delegate_to: localhost
-
- - name: Enable vvold rule set for an ESXi Host
- community.vmware.vmware_host_firewall_manager:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- rules:
- - name: vvold
- enabled: true
- allowed_hosts:
- all_ip: true
- delegate_to: localhost
-
- - name: Manage multiple rule set for an ESXi Host
- community.vmware.vmware_host_firewall_manager:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- rules:
- - name: vvold
- enabled: true
- allowed_hosts:
- all_ip: true
- - name: CIMHttpServer
- enabled: false
- delegate_to: localhost
-
- - name: Manage IP and network based firewall permissions for ESXi
- community.vmware.vmware_host_firewall_manager:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- rules:
- - name: gdbserver
- enabled: true
- allowed_hosts:
- all_ip: false
- ip_address:
- - 192.168.20.10
- - 192.168.20.11
- - name: CIMHttpServer
- enabled: true
- allowed_hosts:
- all_ip: false
- ip_network:
- - 192.168.100.0/24
- - name: remoteSerialPort
- enabled: true
- allowed_hosts:
- all_ip: false
- ip_address:
- - 192.168.100.11
- ip_network:
- - 192.168.200.0/24
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>rule_set_state</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>success</td>
- <td>
- <div>dict with hostname as key and dict with firewall rule set facts as value</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;rule_set_state&#x27;: {&#x27;localhost.localdomain&#x27;: {&#x27;CIMHttpServer&#x27;: {&#x27;current_state&#x27;: False, &#x27;desired_state&#x27;: False, &#x27;previous_state&#x27;: True, &#x27;allowed_hosts&#x27;: {&#x27;current_allowed_all&#x27;: True, &#x27;previous_allowed_all&#x27;: True, &#x27;desired_allowed_all&#x27;: True, &#x27;current_allowed_ip&#x27;: [], &#x27;previous_allowed_ip&#x27;: [], &#x27;desired_allowed_ip&#x27;: [], &#x27;current_allowed_networks&#x27;: [], &#x27;previous_allowed_networks&#x27;: [], &#x27;desired_allowed_networks&#x27;: []}}, &#x27;remoteSerialPort&#x27;: {&#x27;current_state&#x27;: True, &#x27;desired_state&#x27;: True, &#x27;previous_state&#x27;: True, &#x27;allowed_hosts&#x27;: {&#x27;current_allowed_all&#x27;: False, &#x27;previous_allowed_all&#x27;: True, &#x27;desired_allowed_all&#x27;: False, &#x27;current_allowed_ip&#x27;: [&#x27;192.168.100.11&#x27;], &#x27;previous_allowed_ip&#x27;: [], &#x27;desired_allowed_ip&#x27;: [&#x27;192.168.100.11&#x27;], &#x27;current_allowed_networks&#x27;: [&#x27;192.168.200.0/24&#x27;], &#x27;previous_allowed_networks&#x27;: [], &#x27;desired_allowed_networks&#x27;: [&#x27;192.168.200.0/24&#x27;]}}}}}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
-- Aaron Longchamps (@alongchamps)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_hyperthreading_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_hyperthreading_module.rst
deleted file mode 100644
index 6c80ae455..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_hyperthreading_module.rst
+++ /dev/null
@@ -1,303 +0,0 @@
-.. _community.vmware.vmware_host_hyperthreading_module:
-
-
-*******************************************
-community.vmware.vmware_host_hyperthreading
-*******************************************
-
-**Enables/Disables Hyperthreading optimization for an ESXi host system**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to enable or disable Hyperthreading optimization for ESXi host systems in given vCenter infrastructure.
-- It also checks if Hyperthreading is activated/deactivated and if the host needs to be restarted.
-- The module informs the user if Hyperthreading is enabled but inactive because the processor is vulnerable to L1 Terminal Fault (L1TF).
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the cluster from which all host systems will be used.</div>
- <div>This parameter is required if <code>esxi_hostname</code> is not specified.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the host system to work with.</div>
- <div>This parameter is required if <code>cluster_name</code> is not specified.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>enabled</b>&nbsp;&larr;</div></li>
- <li>disabled</li>
- </ul>
- </td>
- <td>
- <div>Enable or disable Hyperthreading.</div>
- <div>You need to reboot the ESXi host if you change the configuration.</div>
- <div>Make sure that Hyperthreading is enabled in the BIOS. Otherwise, it will be enabled, but never activated.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Enable Hyperthreading for an host system
- community.vmware.vmware_host_hyperthreading:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- state: enabled
- delegate_to: localhost
-
- - name: Disable Hyperthreading for an host system
- community.vmware.vmware_host_hyperthreading:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- state: disabled
- delegate_to: localhost
-
- - name: Disable Hyperthreading for all host systems from cluster
- community.vmware.vmware_host_hyperthreading:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- cluster_name: '{{ cluster_name }}'
- state: disabled
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>results</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about host system&#x27;s Hyperthreading configuration</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;esxi01&#x27;: {&#x27;msg&#x27;: &quot;Hyperthreading is already enabled and active for host &#x27;esxi01&#x27;&quot;, &#x27;state_current&#x27;: &#x27;active&#x27;, &#x27;state&#x27;: &#x27;enabled&#x27;}}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Christian Kotte (@ckotte)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_inventory_inventory.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_inventory_inventory.rst
deleted file mode 100644
index 89d19d430..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_inventory_inventory.rst
+++ /dev/null
@@ -1,776 +0,0 @@
-.. _community.vmware.vmware_host_inventory_inventory:
-
-
-**************************************
-community.vmware.vmware_host_inventory
-**************************************
-
-**VMware ESXi hostsystem inventory source**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- Get VMware ESXi hostsystem as inventory hosts from VMware environment.
-- Uses any file which ends with vmware.yml, vmware.yaml, vmware_host_inventory.yml, or vmware_host_inventory.yaml as a YAML configuration file.
-
-
-
-Requirements
-------------
-The below requirements are needed on the local Ansible controller node that executes this inventory.
-
-- vSphere Automation SDK - For tag feature
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="2">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th>Configuration</th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cache</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div> ini entries:
- <p>[inventory]<br>cache = no</p>
- </div>
- <div>env:ANSIBLE_INVENTORY_CACHE</div>
- </td>
- <td>
- <div>Toggle to enable/disable the caching of the inventory&#x27;s source data, requires a cache plugin setup to work.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cache_connection</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div> ini entries:
- <p>[defaults]<br>fact_caching_connection = VALUE</p>
- <p>[inventory]<br>cache_connection = VALUE</p>
- </div>
- <div>env:ANSIBLE_CACHE_PLUGIN_CONNECTION</div>
- <div>env:ANSIBLE_INVENTORY_CACHE_CONNECTION</div>
- </td>
- <td>
- <div>Cache connection data or path, read cache plugin documentation for specifics.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cache_plugin</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">"memory"</div>
- </td>
- <td>
- <div> ini entries:
- <p>[defaults]<br>fact_caching = memory</p>
- <p>[inventory]<br>cache_plugin = memory</p>
- </div>
- <div>env:ANSIBLE_CACHE_PLUGIN</div>
- <div>env:ANSIBLE_INVENTORY_CACHE_PLUGIN</div>
- </td>
- <td>
- <div>Cache plugin to use for the inventory&#x27;s source data.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cache_prefix</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">-</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">"ansible_inventory_"</div>
- </td>
- <td>
- <div> ini entries:
- <p>[default]<br>fact_caching_prefix = ansible_inventory_</p>
- <p>[defaults]<br>fact_caching_prefix = ansible_inventory_</p>
- <p>[inventory]<br>cache_prefix = ansible_inventory_</p>
- </div>
- <div>env:ANSIBLE_CACHE_PLUGIN_PREFIX</div>
- <div>env:ANSIBLE_INVENTORY_CACHE_PLUGIN_PREFIX</div>
- </td>
- <td>
- <div>Prefix to use for cache plugin files/tables</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cache_timeout</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">3600</div>
- </td>
- <td>
- <div> ini entries:
- <p>[defaults]<br>fact_caching_timeout = 3600</p>
- <p>[inventory]<br>cache_timeout = 3600</p>
- </div>
- <div>env:ANSIBLE_CACHE_PLUGIN_TIMEOUT</div>
- <div>env:ANSIBLE_INVENTORY_CACHE_TIMEOUT</div>
- </td>
- <td>
- <div>Cache duration in seconds</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>compose</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">{}</div>
- </td>
- <td>
- </td>
- <td>
- <div>Create vars from jinja2 expressions.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>filters</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">[]</div>
- </td>
- <td>
- </td>
- <td>
- <div>This option allows client-side filtering hosts with jinja templating.</div>
- <div>When server-side filtering is introduced, it should be preferred over this.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>groups</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">{}</div>
- </td>
- <td>
- </td>
- <td>
- <div>Add hosts to group based on Jinja2 conditionals.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">-</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>env:VMWARE_HOST</div>
- <div>env:VMWARE_SERVER</div>
- </td>
- <td>
- <div>Name of vCenter or ESXi server.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostnames</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">["name"]</div>
- </td>
- <td>
- </td>
- <td>
- <div>A list of templates in order of precedence to compose inventory_hostname.</div>
- <div>Ignores template if resulted in an empty string or None value.</div>
- <div>You can use property specified in <em>properties</em> as variables in the template.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>keyed_groups</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">[{"key": "summary.runtime.powerState", "separator": ""}]</div>
- </td>
- <td>
- </td>
- <td>
- <div>Add hosts to group based on the values of a variable.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>default_value</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 2.12</div>
- </td>
- <td>
- </td>
- <td>
- </td>
- <td>
- <div>The default value when the host variable&#x27;s value is an empty string.</div>
- <div>This option is mutually exclusive with <code>trailing_separator</code>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>key</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- </td>
- <td>
- <div>The key from input dictionary used to generate groups</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>parent_group</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- </td>
- <td>
- <div>parent group for keyed group</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>prefix</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">""</div>
- </td>
- <td>
- </td>
- <td>
- <div>A keyed group name will start with this prefix</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>separator</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">"_"</div>
- </td>
- <td>
- </td>
- <td>
- <div>separator used to build the keyed group name</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>trailing_separator</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 2.12</div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- </td>
- <td>
- <div>Set this option to <em>False</em> to omit the <code>separator</code> after the host variable when the value is an empty string.</div>
- <div>This option is mutually exclusive with <code>default_value</code>.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>leading_separator</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 2.11</div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">"yes"</div>
- </td>
- <td>
- </td>
- <td>
- <div>Use in conjunction with keyed_groups.</div>
- <div>By default, a keyed group that does not have a prefix or a separator provided will have a name that starts with an underscore.</div>
- <div>This is because the default prefix is &quot;&quot; and the default separator is &quot;_&quot;.</div>
- <div>Set this option to False to omit the leading underscore (or other separator) if no prefix is given.</div>
- <div>If the group name is derived from a mapping the separator is still used to concatenate the items.</div>
- <div>To not use a separator in the group name at all, set the separator for the keyed group to an empty string instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">-</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>env:VMWARE_PASSWORD</div>
- </td>
- <td>
- <div>Password of vSphere user.</div>
- <div>Accepts vault encrypted variable.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>env:VMWARE_PORT</div>
- </td>
- <td>
- <div>Port number used to connect to vCenter or ESXi Server.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>properties</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">["name", "customValue", "summary.runtime.powerState"]</div>
- </td>
- <td>
- </td>
- <td>
- <div>Specify the list of VMware schema properties associated with the ESXi hostsystem.</div>
- <div>These properties will be populated in hostvars of the given ESXi hostsystem.</div>
- <div>Each value in the list can be a path to a specific property in hostsystem object or a path to a collection of hostsystem objects.</div>
- <div><code>summary.runtime.powerState</code> are required if <code>keyed_groups</code> is set to default.</div>
- <div>Please make sure that all the properties that are used in other parameters are included in this options.</div>
- <div>In addition to ESXi hostsystem&#x27;s properties, the following are special values</div>
- <div>Use <code>customValue</code> to populate ESXi hostsystem&#x27;s custom attributes. <code>customValue</code> is only supported by vCenter and not by ESXi.</div>
- <div>Use <code>all</code> to populate all the properties of the virtual machine. The value <code>all</code> is time consuming operation, do not use unless required absolutely.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>env:VMWARE_PROXY_HOST</div>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>This feature depends on a version of pyvmomi&gt;=v6.7.1.2018.12.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>env:VMWARE_PROXY_PORT</div>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>resources</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">[]</div>
- </td>
- <td>
- </td>
- <td>
- <div>A list of resources to limit search scope.</div>
- <div>Each resource item is represented by exactly one <code>&#x27;vim_type_snake_case</code>:<code>list of resource names</code> pair and optional nested <em>resources</em></div>
- <div>Key name is based on snake case of a vim type name; e.g <code>host_system</code> correspond to <code>vim.HostSystem</code></div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>strict</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- </td>
- <td>
- <div>If <code>yes</code> make invalid entries a fatal error, otherwise skip and continue.</div>
- <div>Since it is possible to use facts in the expressions they might not always be available and we ignore those errors by default.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>use_extra_vars</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 2.11</div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div> ini entries:
- <p>[inventory_plugins]<br>use_extra_vars = no</p>
- </div>
- <div>env:ANSIBLE_INVENTORY_USE_EXTRA_VARS</div>
- </td>
- <td>
- <div>Merge extra vars into the available variables for composition (highest precedence).</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">-</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>env:VMWARE_USER</div>
- <div>env:VMWARE_USERNAME</div>
- </td>
- <td>
- <div>Name of vSphere user.</div>
- <div>Accepts vault encrypted variable.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>env:VMWARE_VALIDATE_CERTS</div>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid.</div>
- <div>Set to <code>false</code> when certificates are not trusted.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>with_nested_properties</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- </td>
- <td>
- <div>This option transform flatten properties name to nested dictionary.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>with_path</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- </td>
- <td>
- <div>Include ESXi hostsystem&#x27;s path.</div>
- <div>Set this option to a string value to replace root name from <em>&#x27;Datacenters&#x27;</em>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>with_sanitized_property_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- </td>
- <td>
- <div>This option allows property name sanitization to create safe property names for use in Ansible.</div>
- <div>Also, transforms property name to snake case.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>with_tags</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- </td>
- <td>
- <div>Include tags and associated hosts.</div>
- <div>Requires &#x27;vSphere Automation SDK&#x27; library to be installed on the given controller machine.</div>
- <div>Please refer following URLs for installation steps</div>
- <div><a href='https://code.vmware.com/web/sdk/7.0/vsphere-automation-python'>https://code.vmware.com/web/sdk/7.0/vsphere-automation-python</a></div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- # Sample configuration file for VMware Host dynamic inventory
- plugin: community.vmware.vmware_host_inventory
- strict: false
- hostname: 10.65.223.31
- username: administrator@vsphere.local
- password: Esxi@123$%
- validate_certs: false
- with_tags: true
-
- # Using compose
- plugin: community.vmware.vmware_host_inventory
- hostname: 10.65.223.31
- username: administrator@vsphere.local
- password: Esxi@123$%
- validate_certs: false
- properties:
- - name
- - summary
- - config.lockdownMode
- compose:
- ansible_user: "'root'"
- ansible_connection: "'ssh'"
-
-
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
-
-
-.. hint::
- Configuration entries for each entry type have a low to high priority order. For example, a variable that is lower in the list will override a variable that is higher up.
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_ipv6_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_ipv6_module.rst
deleted file mode 100644
index 5ca3f39b2..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_ipv6_module.rst
+++ /dev/null
@@ -1,301 +0,0 @@
-.. _community.vmware.vmware_host_ipv6_module:
-
-
-*********************************
-community.vmware.vmware_host_ipv6
-*********************************
-
-**Enables/Disables IPv6 support for an ESXi host system**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to enable or disable IPv6 support for ESXi host systems in given vCenter infrastructure.
-- It also checks if the host needs to be restarted.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the cluster from which all host systems will be used.</div>
- <div>This is required parameter if <code>esxi_hostname</code> is not specified.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the host system to work with.</div>
- <div>This is required parameter if <code>cluster_name</code> is not specified.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>enabled</b>&nbsp;&larr;</div></li>
- <li>disabled</li>
- </ul>
- </td>
- <td>
- <div>Enable or disable IPv6 support.</div>
- <div>You need to reboot the ESXi host if you change the configuration.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Enable IPv6 for an host system
- community.vmware.vmware_host_ipv6:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- state: enabled
- delegate_to: localhost
-
- - name: Disable IPv6 for an host system
- community.vmware.vmware_host_ipv6:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- state: disabled
- delegate_to: localhost
-
- - name: Disable IPv6 for all host systems from cluster
- community.vmware.vmware_host_ipv6:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- cluster_name: '{{ cluster_name }}'
- state: disabled
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>result</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about host system&#x27;s IPv6 configuration</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;esxi01&#x27;: {&#x27;changed&#x27;: False, &#x27;msg&#x27;: &quot;IPv6 is already enabled and active for host &#x27;esxi01&#x27;&quot;}}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Christian Kotte (@ckotte) <christian.kotte@gmx.de>
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_iscsi_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_iscsi_info_module.rst
deleted file mode 100644
index 216b0f0a0..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_iscsi_info_module.rst
+++ /dev/null
@@ -1,326 +0,0 @@
-.. _community.vmware.vmware_host_iscsi_info_module:
-
-
-***************************************
-community.vmware.vmware_host_iscsi_info
-***************************************
-
-**Gather iSCSI configuration information of ESXi host**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to gather information about the iSCSI configuration of the ESXi host.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The ESXi hostname on which to gather iSCSI settings.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Gather iSCSI configuration information of ESXi host
- community.vmware.vmware_host_iscsi_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- esxi_hostname: "{{ esxi_hostname }}"
- register: iscsi_info
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>detected_iscsi_drives</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>list of detected iSCSI drive</div>
- <div>added from version 1.9.0</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">[
- {
- &quot;address&quot;: [
- &quot;192.168.0.57:3260&quot;
- ],
- &quot;canonical_name&quot;: &quot;naa.60014055f198fb3d0cb4bd7ae1f802e1&quot;,
- &quot;iscsi_name&quot;: &quot;iqn.2021-03.local.iscsi-target:iscsi-storage.target0&quot;
- }
- ]</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>iscsi_properties</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>dictionary of current iSCSI information</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{
- &quot;iscsi_alias&quot;: &quot;&quot;,
- &quot;iscsi_authentication_properties&quot;: {
- &quot;_vimtype&quot;: &quot;vim.host.InternetScsiHba.AuthenticationProperties&quot;,
- &quot;chapAuthEnabled&quot;: false,
- &quot;chapAuthenticationType&quot;: &quot;chapProhibited&quot;,
- &quot;chapInherited&quot;: null,
- &quot;chapName&quot;: &quot;&quot;,
- &quot;chapSecret&quot;: &quot;XXXXXXXXX&quot;,
- &quot;mutualChapAuthenticationType&quot;: &quot;chapProhibited&quot;,
- &quot;mutualChapInherited&quot;: null,
- &quot;mutualChapName&quot;: &quot;&quot;,
- &quot;mutualChapSecret&quot;: &quot;XXXXXXXXX&quot;
- },
- &quot;iscsi_enabled&quot;: true,
- &quot;iscsi_name&quot;: &quot;iqn.1998-01.com.vmware:esxi-033f58ee&quot;,
- &quot;iscsi_send_targets&quot;: [
- {
- &quot;address&quot;: &quot;192.168.0.1&quot;,
- &quot;authenticationProperties&quot;: {
- &quot;_vimtype&quot;: &quot;vim.host.InternetScsiHba.AuthenticationProperties&quot;,
- &quot;chapAuthEnabled&quot;: false,
- &quot;chapAuthenticationType&quot;: &quot;chapProhibited&quot;,
- &quot;chapInherited&quot;: true,
- &quot;chapName&quot;: &quot;&quot;,
- &quot;chapSecret&quot;: &quot;XXXXXXXXX&quot;,
- &quot;mutualChapAuthenticationType&quot;: &quot;chapProhibited&quot;,
- &quot;mutualChapInherited&quot;: true,
- &quot;mutualChapName&quot;: &quot;&quot;,
- &quot;mutualChapSecret&quot;: &quot;XXXXXXXXX&quot;
- },
- &quot;port&quot;: 3260
- }
- ],
- &quot;iscsi_static_targets&quot;: [
- {
- &quot;address&quot;: &quot;192.168.0.1&quot;,
- &quot;authenticationProperties&quot;: {
- &quot;_vimtype&quot;: &quot;vim.host.InternetScsiHba.AuthenticationProperties&quot;,
- &quot;chapAuthEnabled&quot;: false,
- &quot;chapAuthenticationType&quot;: &quot;chapProhibited&quot;,
- &quot;chapInherited&quot;: true,
- &quot;chapName&quot;: &quot;&quot;,
- &quot;chapSecret&quot;: &quot;XXXXXXXXX&quot;,
- &quot;mutualChapAuthenticationType&quot;: &quot;chapProhibited&quot;,
- &quot;mutualChapInherited&quot;: true,
- &quot;mutualChapName&quot;: &quot;&quot;,
- &quot;mutualChapSecret&quot;: &quot;XXXXXXXXX&quot;
- },
- &quot;iscsi_name&quot;: &quot;iqn.2004-04.com.qnap:tvs-673:iscsi.vm3.2c580e&quot;,
- &quot;port&quot;: 3260
- }
- ],
- &quot;port_bind&quot;: [],
- &quot;vmhba_name&quot;: &quot;vmhba65&quot;
- }</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- sky-joker (@sky-joker)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_iscsi_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_iscsi_module.rst
deleted file mode 100644
index 1e3b0e280..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_iscsi_module.rst
+++ /dev/null
@@ -1,1148 +0,0 @@
-.. _community.vmware.vmware_host_iscsi_module:
-
-
-**********************************
-community.vmware.vmware_host_iscsi
-**********************************
-
-**Manage the iSCSI configuration of ESXi host**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- In this module, can manage the iSCSI configuration of ESXi host
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="4">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="4">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The ESXi hostname on which to change iSCSI settings.</div>
- </td>
- </tr>
- <tr>
- <td colspan="4">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="4">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>iscsi_config</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The iSCSI configs.</div>
- <div>This parameter is required if <em>state=present</em> or <em>state=absent</em>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>alias</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">""</div>
- </td>
- <td>
- <div>The new value for the alias of the adapter.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>authentication</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>CHAP authentication parent settings for iSCSI.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>chap_auth_enabled</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether to enable CHAP authentication.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>chap_authentication_type</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>chapDiscouraged</li>
- <li>chapPreferred</li>
- <li>chapRequired</li>
- <li><div style="color: blue"><b>chapProhibited</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>The preference for CHAP or non-CHAP protocol of CHAP if CHAP is enabled.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>chap_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">""</div>
- </td>
- <td>
- <div>CHAP user name if CHAP is enabled.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>chap_secret</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The secret password of CHAP if CHAP is enabled.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>mutual_chap_authentication_type</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>chapProhibited</b>&nbsp;&larr;</div></li>
- <li>chapRequired</li>
- </ul>
- </td>
- <td>
- <div>The preference for CHAP or non-CHAP protocol of Mutual-CHAP if CHAP is enabled.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>mutual_chap_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">""</div>
- </td>
- <td>
- <div>The user name that the target needs to use to authenticate with the initiator if Mutual-CHAP is enabled.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>mutual_chap_secret</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The secret password of mutual CHAP if Mutual-CHAP is enabled.</div>
- </td>
- </tr>
-
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>force</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Force port bind VMkernels to be removed.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>iscsi_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name for the iSCSI HBA adapter.</div>
- <div>This is iSCSI qualified name.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: initiator_iqn</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port_bind</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">[]</div>
- </td>
- <td>
- <div>The list of the VMkernels if use port bindings.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>send_target</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The iSCSI dynamic target settings.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>address</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The IP address or hostname of the storage device.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>authentication</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>CHAP authentication settings of a dynamic target for iSCSI.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>chap_auth_enabled</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether to enable CHAP authentication.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>chap_authentication_type</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>chapDiscouraged</li>
- <li>chapPreferred</li>
- <li>chapRequired</li>
- <li><div style="color: blue"><b>chapProhibited</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>The preference for CHAP or non-CHAP protocol of CHAP if CHAP is enabled.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>chap_inherited</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Whether or not to inherit CHAP settings from the parent settings.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>chap_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">""</div>
- </td>
- <td>
- <div>CHAP user name if CHAP is enabled.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>chap_secret</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The secret password of CHAP if CHAP is enabled.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>mutual_chap_authentication_type</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>chapProhibited</b>&nbsp;&larr;</div></li>
- <li>chapRequired</li>
- </ul>
- </td>
- <td>
- <div>The preference for CHAP or non-CHAP protocol of Mutual-CHAP if CHAP is enabled.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>mutual_chap_inherited</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Whether or not to inherit Mutual-CHAP settings from the parent settings.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>mutual_chap_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">""</div>
- </td>
- <td>
- <div>The user name that the target needs to use to authenticate with the initiator if Mutual-CHAP is enabled.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>mutual_chap_secret</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The secret password of mutual CHAP if Mutual-CHAP is enabled.</div>
- </td>
- </tr>
-
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">3260</div>
- </td>
- <td>
- <div>The TCP port of the storage device.</div>
- <div>If not specified, the standard default of 3260 is used.</div>
- </td>
- </tr>
-
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>static_target</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The iSCSI static target settings.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>address</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The IP address or hostname of the storage device.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>authentication</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>CHAP authentication settings of a static target for iSCSI.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>chap_auth_enabled</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether to enable CHAP authentication.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>chap_authentication_type</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>chapDiscouraged</li>
- <li>chapPreferred</li>
- <li>chapRequired</li>
- <li><div style="color: blue"><b>chapProhibited</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>The preference for CHAP or non-CHAP protocol of CHAP if CHAP is enabled.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>chap_inherited</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Whether or not to inherit CHAP settings from the parent settings.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>chap_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">""</div>
- </td>
- <td>
- <div>CHAP user name if CHAP is enabled.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>chap_secret</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The secret password of CHAP if CHAP is enabled.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>mutual_chap_authentication_type</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>chapProhibited</b>&nbsp;&larr;</div></li>
- <li>chapRequired</li>
- </ul>
- </td>
- <td>
- <div>The preference for CHAP or non-CHAP protocol of Mutual-CHAP if CHAP is enabled.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>mutual_chap_inherited</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Whether or not to inherit Mutual-CHAP settings from the parent settings.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>mutual_chap_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">""</div>
- </td>
- <td>
- <div>The user name that the target needs to use to authenticate with the initiator if Mutual-CHAP is enabled.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>mutual_chap_secret</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The secret password of mutual CHAP if Mutual-CHAP is enabled.</div>
- </td>
- </tr>
-
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>iscsi_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the iSCSI target to connect to.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td class="elbow-placeholder"></td>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">3260</div>
- </td>
- <td>
- <div>The TCP port of the storage device.</div>
- <div>If not specified, the standard default of 3260 is used.</div>
- </td>
- </tr>
-
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="3">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vmhba_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The iSCSI adapter name.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="4">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="4">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="4">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="4">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="4">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- <li>enabled</li>
- <li>disabled</li>
- </ul>
- </td>
- <td>
- <div>If set to <code>present</code>, add the iSCSI target or the bind ports if they are not existing.</div>
- <div>If set to <code>present</code>, update the iSCSI settings if they already exist and occur change.</div>
- <div>If set to <code>absent</code>, remove the iSCSI target or the bind ports if they are existing.</div>
- <div>If set to (enabled), enable the iSCSI of ESXi if the iSCSI is disabled.</div>
- <div>If set to (disabled), disable the iSCSI of ESXi if the iSCSI is enabled.</div>
- </td>
- </tr>
- <tr>
- <td colspan="4">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="4">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Enable iSCSI of ESXi
- community.vmware.vmware_host_iscsi:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- esxi_hostname: "{{ esxi_hostname }}"
- state: enabled
-
- - name: Add a dynamic target to iSCSI config of ESXi
- community.vmware.vmware_host_iscsi:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- esxi_hostname: "{{ esxi_hostname }}"
- iscsi_config:
- vmhba_name: vmhba65
- send_target:
- address: "{{ send_target_address }}"
- state: present
-
- - name: Add a static target to iSCSI config of ESXi
- community.vmware.vmware_host_iscsi:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- esxi_hostname: "{{ esxi_hostname }}"
- iscsi_config:
- vmhba_name: vmhba65
- static_target:
- iscsi_name: iqn.2011-08.com.xxxxxxx:as6104t-8c3e9d.target001
- address: "{{ send_target_address }}"
- state: present
-
- - name: Add VMKernels to iSCSI config of ESXi
- community.vmware.vmware_host_iscsi:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- esxi_hostname: "{{ esxi_hostname }}"
- iscsi_config:
- vmhba_name: vmhba65
- port_bind:
- - vmk0
- - vmk1
- state: present
-
- - name: Use CHAP authentication
- community.vmware.vmware_host_iscsi:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- esxi_hostname: "{{ esxi_hostname }}"
- iscsi_config:
- vmhba_name: vmhba65
- authentication:
- chap_auth_enabled: true
- chap_authentication_type: chapPreferred
- chap_name: chap_user_name
- chap_secret: secret
- state: present
-
- - name: Remove a dynamic target from iSCSI config of ESXi
- community.vmware.vmware_host_iscsi:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- esxi_hostname: "{{ esxi_hostname }}"
- iscsi_config:
- vmhba_name: vmhba65
- send_target:
- address: "{{ send_target_address }}"
- state: absent
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>iscsi_properties</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>changed</td>
- <td>
- <div>Parameter return when system defaults config is changed.</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{
- &quot;iscsi_alias&quot;: &quot;&quot;,
- &quot;iscsi_authentication_properties&quot;: {
- &quot;_vimtype&quot;: &quot;vim.host.InternetScsiHba.AuthenticationProperties&quot;,
- &quot;chapAuthEnabled&quot;: false,
- &quot;chapAuthenticationType&quot;: &quot;chapProhibited&quot;,
- &quot;chapInherited&quot;: null,
- &quot;chapName&quot;: &quot;&quot;,
- &quot;chapSecret&quot;: &quot;XXXXXXXXXXXXXXXXXXXXX&quot;,
- &quot;mutualChapAuthenticationType&quot;: &quot;chapProhibited&quot;,
- &quot;mutualChapInherited&quot;: null,
- &quot;mutualChapName&quot;: &quot;XXXXXXXXXXXXXXXXXXXXX&quot;,
- &quot;mutualChapSecret&quot;: &quot;&quot;
- },
- &quot;iscsi_enabled&quot;: true,
- &quot;iscsi_name&quot;: &quot;&quot;,
- &quot;iscsi_send_targets&quot;: [],
- &quot;iscsi_static_targets&quot;: [],
- &quot;port_bind&quot;: [],
- &quot;vmhba_name&quot;: &quot;vmhba65&quot;
- }</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- sky-joker (@sky-joker)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_kernel_manager_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_kernel_manager_module.rst
deleted file mode 100644
index bc360bab3..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_kernel_manager_module.rst
+++ /dev/null
@@ -1,309 +0,0 @@
-.. _community.vmware.vmware_host_kernel_manager_module:
-
-
-*******************************************
-community.vmware.vmware_host_kernel_manager
-*******************************************
-
-**Manage kernel module options on ESXi hosts**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to manage kernel module options on ESXi hosts.
-- All connected ESXi hosts in scope will be configured when specified.
-- If a host is not connected at time of configuration, it will be marked as such in the output.
-- Kernel module options may require a reboot to take effect which is not covered here.
-- You can use :ref:`ansible.builtin.reboot <ansible.builtin.reboot_module>` or :ref:`community.vmware.vmware_host_powerstate <community.vmware.vmware_host_powerstate_module>` module to reboot all ESXi host systems.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the VMware cluster to work on.</div>
- <div>All ESXi hosts in this cluster will be configured.</div>
- <div>This parameter is required if <code>esxi_hostname</code> is not specified.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the ESXi host to work on.</div>
- <div>This parameter is required if <code>cluster_name</code> is not specified.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>kernel_module_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the kernel module to be configured.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>kernel_module_option</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Specified configurations will be applied to the given module.</div>
- <div>These values are specified in key=value pairs and separated by a space when there are multiple options.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Configure IPv6 to be off via tcpip4 kernel module
- community.vmware.vmware_host_kernel_manager:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- kernel_module_name: "tcpip4"
- kernel_module_option: "ipv6=0"
-
- - name: Using cluster_name, configure vmw_psp_rr options
- community.vmware.vmware_host_kernel_manager:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- cluster_name: '{{ virtual_cluster_name }}'
- kernel_module_name: "vmw_psp_rr"
- kernel_module_option: "maxPathsPerDevice=2"
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>host_kernel_status</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>success</td>
- <td>
- <div>dict with information on what was changed, by ESXi host in scope.</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;results&#x27;: {&#x27;myhost01.example.com&#x27;: {&#x27;changed&#x27;: True, &#x27;configured_options&#x27;: &#x27;ipv6=0&#x27;, &#x27;msg&#x27;: &#x27;Options have been changed on the kernel module&#x27;, &#x27;original_options&#x27;: &#x27;ipv6=1&#x27;}}}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Aaron Longchamps (@alongchamps)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_lockdown_exceptions_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_lockdown_exceptions_module.rst
deleted file mode 100644
index a2097c128..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_lockdown_exceptions_module.rst
+++ /dev/null
@@ -1,308 +0,0 @@
-.. _community.vmware.vmware_host_lockdown_exceptions_module:
-
-
-************************************************
-community.vmware.vmware_host_lockdown_exceptions
-************************************************
-
-**Manage Lockdown Mode Exception Users**
-
-
-Version added: 3.1.0
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to manage Lockdown Mode Exception Users.
-- All parameters and VMware objects values are case sensitive.
-- Please specify ``hostname`` as vCenter IP or hostname only, as lockdown operations are not possible from standalone ESXi server.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of cluster.</div>
- <div>All host systems from given cluster used to manage exception users.</div>
- <div>Required parameter, if <code>esxi_hostname</code> is not set.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>List of ESXi hostname to manage exception users.</div>
- <div>Required parameter, if <code>cluster_name</code> is not set.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>exception_users</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>List of Lockdown Mode Exception Users.</div>
- <div>To remove all Exception Users, <em>state=set</em> the empty list.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- <li>set</li>
- </ul>
- </td>
- <td>
- <div>If <code>present</code>, make sure the given users are defined as Lockdown Mode Exception Users.</div>
- <div>If <code>absent</code>, make sure the given users are NO Lockdown Mode Exception Users.</div>
- <div>If <code>set</code>, will replace Lockdown Mode Exception Users defined list of users.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Remove all Lockdown Mode Exception Users on a host
- community.vmware.vmware_host_lockdown:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- exception_users: []
- state: set
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>results</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about exception users of Host systems</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;host_lockdown_exceptions&#x27;: {&#x27;DC0_C0&#x27;: {&#x27;current_exception_users&#x27;: [], &#x27;desired_exception_users&#x27;: [], &#x27;previous_exception_users&#x27;: [&#x27;root&#x27;]}}}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Mario Lenz (@mariolenz)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_lockdown_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_lockdown_module.rst
deleted file mode 100644
index 97c6e45e2..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_lockdown_module.rst
+++ /dev/null
@@ -1,336 +0,0 @@
-.. _community.vmware.vmware_host_lockdown_module:
-
-
-*************************************
-community.vmware.vmware_host_lockdown
-*************************************
-
-**Manage administrator permission for the local administrative account for the ESXi host**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to manage administrator permission for the local administrative account for the host when ESXi hostname is given.
-- All parameters and VMware objects values are case sensitive.
-- This module is destructive as administrator permission are managed using APIs used, please read options carefully and proceed.
-- Please specify ``hostname`` as vCenter IP or hostname only, as lockdown operations are not possible from standalone ESXi server.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of cluster.</div>
- <div>All host systems from given cluster used to manage lockdown.</div>
- <div>Required parameter, if <code>esxi_hostname</code> is not set.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>List of ESXi hostname to manage lockdown.</div>
- <div>Required parameter, if <code>cluster_name</code> is not set.</div>
- <div>See examples for specifications.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>disabled</li>
- <li><div style="color: blue"><b>normal</b>&nbsp;&larr;</div></li>
- <li>strict</li>
- <li>present</li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>State of hosts system</div>
- <div>If set to <code>disabled</code>, all host systems will be removed from lockdown mode.</div>
- <div>If host system is already out of lockdown mode and set to <code>disabled</code>, no action will be taken.</div>
- <div>If set to <code>normal</code>, all host systems will be set in lockdown mode.</div>
- <div>If host system is already in lockdown mode and set to <code>normal</code>, no action will be taken.</div>
- <div>If set to <code>strict</code>, all host systems will be set in strict lockdown mode.</div>
- <div>If host system is already in strict lockdown mode and set to <code>strict</code>, no action will be taken.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Enter host system into lockdown mode
- community.vmware.vmware_host_lockdown:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- state: normal
- delegate_to: localhost
-
- - name: Exit host systems from lockdown mode
- community.vmware.vmware_host_lockdown:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- state: disabled
- delegate_to: localhost
-
- - name: Enter host systems into lockdown mode
- community.vmware.vmware_host_lockdown:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname:
- - '{{ esxi_hostname_1 }}'
- - '{{ esxi_hostname_2 }}'
- state: normal
- delegate_to: localhost
-
- - name: Exit host systems from lockdown mode
- community.vmware.vmware_host_lockdown:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname:
- - '{{ esxi_hostname_1 }}'
- - '{{ esxi_hostname_2 }}'
- state: disabled
- delegate_to: localhost
-
- - name: Enter all host system from cluster into lockdown mode
- community.vmware.vmware_host_lockdown:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- cluster_name: '{{ cluster_name }}'
- state: normal
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>results</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about state of Host system lock down</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;host_lockdown_state&#x27;: {&#x27;DC0_C0&#x27;: {&#x27;current_state&#x27;: &#x27;normal&#x27;, &#x27;previous_state&#x27;: &#x27;disabled&#x27;, &#x27;desired_state&#x27;: &#x27;normal&#x27;}}}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_logbundle_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_logbundle_info_module.rst
deleted file mode 100644
index 8d5ae6512..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_logbundle_info_module.rst
+++ /dev/null
@@ -1,245 +0,0 @@
-.. _community.vmware.vmware_host_logbundle_info_module:
-
-
-*******************************************
-community.vmware.vmware_host_logbundle_info
-*******************************************
-
-**Gathers manifest info for logbundle**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to gather manifest information for logbundle from ESXi.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the host system to fetch the manifests for logbundle.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: fetch the manifests for logbundle from ESXi
- community.vmware.vmware_host_logbundle_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- esxi_hostname: "{{ esxi_hostname }}"
- register: fetch_manifests_result
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>manifests</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>list of dictionary of manifest information for logbundle</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">[{&#x27;enabled&#x27;: &#x27;true&#x27;, &#x27;group&#x27;: &#x27;System&#x27;, &#x27;id&#x27;: &#x27;System:Base&#x27;, &#x27;name&#x27;: &#x27;Base&#x27;, &#x27;vmOnly&#x27;: &#x27;false&#x27;}, {&#x27;enabled&#x27;: &#x27;false&#x27;, &#x27;group&#x27;: &#x27;System&#x27;, &#x27;id&#x27;: &#x27;System:BaseMinmal&#x27;, &#x27;name&#x27;: &#x27;BaseMinmal&#x27;, &#x27;vmOnly&#x27;: &#x27;false&#x27;}, {&#x27;enabled&#x27;: &#x27;true&#x27;, &#x27;group&#x27;: &#x27;Fcd&#x27;, &#x27;id&#x27;: &#x27;Fcd:Catalog&#x27;, &#x27;name&#x27;: &#x27;Catalog&#x27;, &#x27;vmOnly&#x27;: &#x27;false&#x27;}, {&#x27;enabled&#x27;: &#x27;false&#x27;, &#x27;group&#x27;: &#x27;VirtualMachines&#x27;, &#x27;id&#x27;: &#x27;VirtualMachines:CoreDumpHung&#x27;, &#x27;name&#x27;: &#x27;CoreDumpHung&#x27;, &#x27;vmOnly&#x27;: &#x27;true&#x27;}, {&#x27;enabled&#x27;: &#x27;true&#x27;, &#x27;group&#x27;: &#x27;System&#x27;, &#x27;id&#x27;: &#x27;System:CoreDumps&#x27;, &#x27;name&#x27;: &#x27;CoreDumps&#x27;, &#x27;vmOnly&#x27;: &#x27;false&#x27;}]</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- sky-joker (@sky-joker)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_logbundle_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_logbundle_module.rst
deleted file mode 100644
index 1a5029e26..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_logbundle_module.rst
+++ /dev/null
@@ -1,340 +0,0 @@
-.. _community.vmware.vmware_host_logbundle_module:
-
-
-**************************************
-community.vmware.vmware_host_logbundle
-**************************************
-
-**Fetch logbundle file from ESXi**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to fetch logbundle file from ESXi.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="2">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>dest</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>file destination on localhost, path must be exist.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the host system to fetch the logbundle.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>manifests</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">["System:Base", "System:CoreDumps", "System:EsxImage", "System:IOFilter", "System:LoadESX", "System:Modules", "System:RDMA", "System:ResourceGroups", "System:TPM", "System:VFlash", "System:VMTools", "System:VmiofPlugins", "System:ntp", "System:uwstats", "Fcd:Catalog", "VirtualMachines:CoreDumps", "VirtualMachines:VirtualMachineStats", "VirtualMachines:base", "VirtualMachines:base", "VirtualMachines:diskinfo", "VirtualMachines:logs", "Storage:FCoE", "Storage:Multipathing", "Storage:NAS", "Storage:VSAN", "Storage:VSANHealth", "Storage:VSANIscsiTarget", "Storage:VSANPerfStats", "Storage:VSANPerfSvc", "Storage:VSANTraces", "Storage:VVOL", "Storage:base", "Storage:iodm", "Storage:iscsi", "FeatureStateSwitch:FeatureStateSwitch", "Userworld:HostAgent", "Userworld:ProcessInformation", "Configuration:System", "Logs:System", "hostProfiles:SystemImageCacheHostProfile", "hostProfiles:hostProfiles", "FileSystem:VMFSDiskDump", "FileSystem:base", "ActiveDirectory:base", "CIM:base", "Hardware:base", "Hardware:usb", "Installer:base", "Network:base", "Network:dvs", "Network:lacp", "Network:nscd", "Network:tcpip", "IntegrityChecks:md5sums"]</div>
- </td>
- <td>
- <div>Logs to include in the logbundle file.</div>
- <div>Refer to the id key of the <span class='module'>community.vmware.vmware_host_logbundle_info</span> module for values that can be specified in the manifest.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>performance_data</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Gather performance data for ESXi.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>duration</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">300</div>
- </td>
- <td>
- <div>Duration for which performance data is gathered.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>interval</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">5</div>
- </td>
- <td>
- <div>Interval for which performance data is gathered.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: fetch logbundle file from ESXi
- community.vmware.vmware_host_logbundle:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- esxi_hostname: "{{ esxi_hostname }}"
- dest: ./esxi-log.tgz
-
- - name: fetch logbundle file from ESXi with manifests
- community.vmware.vmware_host_logbundle:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- esxi_hostname: "{{ esxi_hostname }}"
- dest: ./esxi-log.tgz
- manifests:
- - System:Base
- - VirtualMachines:VirtualMachineStats
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>dest</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>on success</td>
- <td>
- <div>saved path of a logbundle file for ESXi</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;changed&#x27;: True, &#x27;dest&#x27;: &#x27;./esxi-log.tgz&#x27;, &#x27;failed&#x27;: False, &#x27;gid&#x27;: 0, &#x27;group&#x27;: &#x27;root&#x27;, &#x27;mode&#x27;: &#x27;0644&#x27;, &#x27;owner&#x27;: &#x27;root&#x27;, &#x27;size&#x27;: 25783140, &#x27;state&#x27;: &#x27;file&#x27;, &#x27;uid&#x27;: 0}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- sky-joker (@sky-joker)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_module.rst
deleted file mode 100644
index ab28301e7..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_module.rst
+++ /dev/null
@@ -1,533 +0,0 @@
-.. _community.vmware.vmware_host_module:
-
-
-****************************
-community.vmware.vmware_host
-****************************
-
-**Add, remove, or move an ESXi host to, from, or within vCenter**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to add, reconnect, or remove an ESXi host to or from vCenter.
-- This module can also be used to move an ESXi host to a cluster or folder, or vice versa, within the same datacenter.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>add_connected</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>If set to <code>true</code>, then the host should be connected as soon as it is added.</div>
- <div>This parameter is ignored if state is set to a value other than <code>present</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the cluster to add the host.</div>
- <div>If <code>folder</code> is not set, then this parameter is required.</div>
- <div>Aliases added in version 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: cluster</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the datacenter to add the host.</div>
- <div>Aliases added in version 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: datacenter</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>ESXi hostname to manage.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>ESXi password.</div>
- <div>Required for adding a host.</div>
- <div>Optional for reconnect.</div>
- <div>Unused for removing.</div>
- <div>No longer a required parameter from version 2.5.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_ssl_thumbprint</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">""</div>
- </td>
- <td>
- <div>Specifying the hostsystem certificate&#x27;s thumbprint.</div>
- <div>Use following command to get hostsystem certificate&#x27;s thumbprint -</div>
- <div># openssl x509 -in /etc/vmware/ssl/rui.crt -fingerprint -sha1 -noout</div>
- <div>Only used if <code>fetch_thumbprint</code> isn&#x27;t set to <code>true</code>.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: ssl_thumbprint</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>ESXi username.</div>
- <div>Required for adding a host.</div>
- <div>Optional for reconnect. If both <code>esxi_username</code> and <code>esxi_password</code> are used</div>
- <div>Unused for removing.</div>
- <div>No longer a required parameter from version 2.5.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>fetch_ssl_thumbprint</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Fetch the thumbprint of the host&#x27;s SSL certificate.</div>
- <div>This basically disables the host certificate verification (check if it was signed by a recognized CA).</div>
- <div>Disable this option if you want to allow only hosts with valid certificates to be added to vCenter.</div>
- <div>If this option is set to <code>false</code> and the certificate can&#x27;t be verified, an add or reconnect will fail.</div>
- <div>Unused when <code>esxi_ssl_thumbprint</code> is set.</div>
- <div>Optional for reconnect, but only used if <code>esxi_username</code> and <code>esxi_password</code> are used.</div>
- <div>Unused for removing.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>folder</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the folder under which host to add.</div>
- <div>If <code>cluster_name</code> is not set, then this parameter is required.</div>
- <div>For example, if there is a datacenter &#x27;dc1&#x27; under folder called &#x27;Site1&#x27; then, this value will be &#x27;/Site1/dc1/host&#x27;.</div>
- <div>Here &#x27;host&#x27; is an invisible folder under VMware Web Client.</div>
- <div>Another example, if there is a nested folder structure like &#x27;/myhosts/india/pune&#x27; under datacenter &#x27;dc2&#x27;, then <code>folder</code> value will be &#x27;/dc2/host/myhosts/india/pune&#x27;.</div>
- <div>Other Examples: &#x27;/Site2/dc2/Asia-Cluster/host&#x27; or &#x27;/dc3/Asia-Cluster/host&#x27;</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: folder_name</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>force_connection</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Force the connection if the host is already being managed by another vCenter server.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>reconnect_disconnected</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Reconnect disconnected hosts.</div>
- <div>This is only used if <code>state</code> is set to <code>present</code> and if the host already exists.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- <li>add_or_reconnect</li>
- <li>reconnect</li>
- <li>disconnected</li>
- </ul>
- </td>
- <td>
- <div>If set to <code>present</code>, add the host if host is absent.</div>
- <div>If set to <code>present</code>, update the location of the host if host already exists.</div>
- <div>If set to <code>absent</code>, remove the host if host is present.</div>
- <div>If set to <code>absent</code>, do nothing if host already does not exists.</div>
- <div>If set to <code>add_or_reconnect</code>, add the host if it&#x27;s absent else reconnect it and update the location.</div>
- <div>If set to <code>reconnect</code>, then reconnect the host if it&#x27;s present and update the location.</div>
- <div>If set to <code>disconnected</code>, disconnect the host if the host already exists.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Add ESXi Host to vCenter
- community.vmware.vmware_host:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter: datacenter_name
- cluster: cluster_name
- esxi_hostname: '{{ esxi_hostname }}'
- esxi_username: '{{ esxi_username }}'
- esxi_password: '{{ esxi_password }}'
- state: present
- delegate_to: localhost
-
- - name: Add ESXi Host to vCenter under a specific folder
- community.vmware.vmware_host:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter: datacenter_name
- folder: '/Site2/Asia-Cluster/host'
- esxi_hostname: '{{ esxi_hostname }}'
- esxi_username: '{{ esxi_username }}'
- esxi_password: '{{ esxi_password }}'
- state: present
- add_connected: true
- delegate_to: localhost
-
- - name: Reconnect ESXi Host (with username/password set)
- community.vmware.vmware_host:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter: datacenter_name
- cluster: cluster_name
- esxi_hostname: '{{ esxi_hostname }}'
- esxi_username: '{{ esxi_username }}'
- esxi_password: '{{ esxi_password }}'
- state: reconnect
- delegate_to: localhost
-
- - name: Reconnect ESXi Host (with default username/password)
- community.vmware.vmware_host:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter: datacenter_name
- cluster: cluster_name
- esxi_hostname: '{{ esxi_hostname }}'
- state: reconnect
- delegate_to: localhost
-
- - name: Add ESXi Host with SSL Thumbprint to vCenter
- community.vmware.vmware_host:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter: datacenter_name
- cluster: cluster_name
- esxi_hostname: '{{ esxi_hostname }}'
- esxi_username: '{{ esxi_username }}'
- esxi_password: '{{ esxi_password }}'
- esxi_ssl_thumbprint: "3C:A5:60:6F:7A:B7:C4:6C:48:28:3D:2F:A5:EC:A3:58:13:88:F6:DD"
- state: present
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>result</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>on successful addition</td>
- <td>
- <div>metadata about the new host system added</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">Host already connected to vCenter &#x27;vcenter01&#x27; in cluster &#x27;cluster01&#x27;</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Joseph Callen (@jcpowermac)
-- Russell Teague (@mtnbikenc)
-- Maxime de Roucy (@tchernomax)
-- Christian Kotte (@ckotte)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_ntp_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_ntp_info_module.rst
deleted file mode 100644
index b4cf2be1e..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_ntp_info_module.rst
+++ /dev/null
@@ -1,273 +0,0 @@
-.. _community.vmware.vmware_host_ntp_info_module:
-
-
-*************************************
-community.vmware.vmware_host_ntp_info
-*************************************
-
-**Gathers info about NTP configuration on an ESXi host**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to gather information about NTP configurations on an ESXi host.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the cluster.</div>
- <div>NTP config information about each ESXi server will be returned for the given cluster.</div>
- <div>If <code>esxi_hostname</code> is not given, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>ESXi hostname.</div>
- <div>NTP config information about this ESXi server will be returned.</div>
- <div>If <code>cluster_name</code> is not given, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Gather NTP info about all ESXi Host in the given Cluster
- community.vmware.vmware_host_ntp_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- cluster_name: cluster_name
- delegate_to: localhost
- register: cluster_host_ntp
-
- - name: Gather NTP info about ESXi Host
- community.vmware.vmware_host_ntp_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- delegate_to: localhost
- register: host_ntp
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>hosts_ntp_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>hosts_ntp_info</td>
- <td>
- <div>dict with hostname as key and dict with NTP infos as value</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;10.76.33.226&#x27;: [{&#x27;ntp_servers&#x27;: [], &#x27;time_zone_description&#x27;: &#x27;UTC&#x27;, &#x27;time_zone_gmt_offset&#x27;: 0, &#x27;time_zone_identifier&#x27;: &#x27;UTC&#x27;, &#x27;time_zone_name&#x27;: &#x27;UTC&#x27;}]}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_ntp_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_ntp_module.rst
deleted file mode 100644
index 132900ead..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_ntp_module.rst
+++ /dev/null
@@ -1,361 +0,0 @@
-.. _community.vmware.vmware_host_ntp_module:
-
-
-********************************
-community.vmware.vmware_host_ntp
-********************************
-
-**Manage NTP server configuration of an ESXi host**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to configure, add or remove NTP servers from an ESXi host.
-- If ``state`` is not given, the NTP servers will be configured in the exact sequence.
-- User can specify an ESXi hostname or Cluster name. In case of cluster name, all ESXi hosts are updated.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the cluster from which all host systems will be used.</div>
- <div>This parameter is required if <code>esxi_hostname</code> is not specified.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the host system to work with.</div>
- <div>This parameter is required if <code>cluster_name</code> is not specified.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>ntp_servers</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>IP or FQDN of NTP server(s).</div>
- <div>This accepts a list of NTP servers. For multiple servers, please look at the examples.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>present</li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>present: Add NTP server(s), if specified server(s) are absent else do nothing.</div>
- <div>absent: Remove NTP server(s), if specified server(s) are present else do nothing.</div>
- <div>Specified NTP server(s) will be configured if <code>state</code> isn&#x27;t specified.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>verbose</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Verbose output of the configuration change.</div>
- <div>Explains if an NTP server was added, removed, or if the NTP server sequence was changed.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Configure NTP servers for an ESXi Host
- community.vmware.vmware_host_ntp:
- hostname: vcenter01.example.local
- username: administrator@vsphere.local
- password: SuperSecretPassword
- esxi_hostname: esx01.example.local
- ntp_servers:
- - 0.pool.ntp.org
- - 1.pool.ntp.org
- delegate_to: localhost
-
- - name: Set NTP servers for all ESXi Host in given Cluster
- community.vmware.vmware_host_ntp:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- cluster_name: '{{ cluster_name }}'
- state: present
- ntp_servers:
- - 0.pool.ntp.org
- - 1.pool.ntp.org
- delegate_to: localhost
-
- - name: Set NTP servers for an ESXi Host
- community.vmware.vmware_host_ntp:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- state: present
- ntp_servers:
- - 0.pool.ntp.org
- - 1.pool.ntp.org
- delegate_to: localhost
-
- - name: Remove NTP servers for an ESXi Host
- community.vmware.vmware_host_ntp:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- state: absent
- ntp_servers:
- - bad.server.ntp.org
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>host_ntp_status</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about host system&#x27;s NTP configuration</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;esx01.example.local&#x27;: {&#x27;ntp_servers_changed&#x27;: [&#x27;time1.example.local&#x27;, &#x27;time2.example.local&#x27;, &#x27;time3.example.local&#x27;, &#x27;time4.example.local&#x27;], &#x27;ntp_servers&#x27;: [&#x27;time3.example.local&#x27;, &#x27;time4.example.local&#x27;], &#x27;ntp_servers_previous&#x27;: [&#x27;time1.example.local&#x27;, &#x27;time2.example.local&#x27;]}, &#x27;esx02.example.local&#x27;: {&#x27;ntp_servers_changed&#x27;: [&#x27;time3.example.local&#x27;], &#x27;ntp_servers_current&#x27;: [&#x27;time1.example.local&#x27;, &#x27;time2.example.local&#x27;, &#x27;time3.example.local&#x27;], &#x27;state&#x27;: &#x27;present&#x27;, &#x27;ntp_servers_previous&#x27;: [&#x27;time1.example.local&#x27;, &#x27;time2.example.local&#x27;]}}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
-- Christian Kotte (@ckotte)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_package_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_package_info_module.rst
deleted file mode 100644
index da4c8ba6d..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_package_info_module.rst
+++ /dev/null
@@ -1,273 +0,0 @@
-.. _community.vmware.vmware_host_package_info_module:
-
-
-*****************************************
-community.vmware.vmware_host_package_info
-*****************************************
-
-**Gathers info about available packages on an ESXi host**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to gather information about available packages and their status on an ESXi host.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the cluster.</div>
- <div>Package information about each ESXi server will be returned for given cluster.</div>
- <div>If <code>esxi_hostname</code> is not given, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>ESXi hostname.</div>
- <div>Package information about this ESXi server will be returned.</div>
- <div>If <code>cluster_name</code> is not given, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Gather info about all ESXi Host in given Cluster
- community.vmware.vmware_host_package_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- cluster_name: cluster_name
- delegate_to: localhost
- register: cluster_host_packages
-
- - name: Gather info about ESXi Host
- community.vmware.vmware_host_package_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- delegate_to: localhost
- register: host_packages
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>hosts_package_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>hosts_package_info</td>
- <td>
- <div>dict with hostname as key and dict with package information as value</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;hosts_package_info&#x27;: {&#x27;localhost.localdomain&#x27;: []}}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_passthrough_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_passthrough_module.rst
deleted file mode 100644
index 915ec57ea..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_passthrough_module.rst
+++ /dev/null
@@ -1,376 +0,0 @@
-.. _community.vmware.vmware_host_passthrough_module:
-
-
-****************************************
-community.vmware.vmware_host_passthrough
-****************************************
-
-**Manage PCI device passthrough settings on host**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be managed PCI device passthrough settings on host.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="2">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the cluster from which all host systems will be used.</div>
- <div>This parameter is required if <code>esxi_hostname</code> is not specified.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: cluster_name</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>devices</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=dictionary</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>List of PCI device name or id.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>device</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of PCI device to enable passthrough.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: name, device_name</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the host system to work with.</div>
- <div>This parameter is required if <code>cluster_name</code> is not specified.</div>
- <div>User can specify specific host from the cluster.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>If <em>state=present</em>, passthrough of PCI device will be enabled.</div>
- <div>If <em>state=absent</em>, passthrough of PCI device will be disabled.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - Supports ``check_mode``.
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Enable PCI device passthrough against the whole ESXi in a cluster
- community.vmware.vmware_host_passthrough:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- validate_certs: false
- cluster: "{{ ccr1 }}"
- devices:
- - device_name: "Dual Band Wireless AC 3165"
- state: present
-
- - name: Enable PCI device passthrough against one ESXi
- community.vmware.vmware_host_passthrough:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- validate_certs: false
- esxi_hostname: "{{ esxi1 }}"
- devices:
- - device_name: "Dual Band Wireless AC 3165"
- state: present
-
- - name: Enable PCI device passthrough with PCI ids
- community.vmware.vmware_host_passthrough:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- validate_certs: false
- esxi_hostname: "{{ esxi1 }}"
- devices:
- - device: '0000:03:00.0'
- - device: '0000:00:02.0'
- state: present
-
- - name: Disable PCI device passthrough against the whole ESXi in a cluster
- community.vmware.vmware_host_passthrough:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- validate_certs: false
- cluster: "{{ ccr1 }}"
- devices:
- - device_name: "Dual Band Wireless AC 3165"
- state: absent
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>passthrough_configs</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=dictionary</span>
- </div>
- </td>
- <td>changed</td>
- <td>
- <div>list of that PCI devices have been enabled passthrough for each host system.</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">[
- {
- &quot;esxi-01.example.com&quot;: [
- {
- &quot;device_id&quot;: &quot;0000:03:00.0&quot;,
- &quot;device_name&quot;: &quot;Dual Band Wireless AC 3165&quot;,
- &quot;passthruEnabled&quot;: true
- }
- ]
- },
- {
- &quot;esxi-02.example.com&quot;: [
- {
- &quot;device_id&quot;: &quot;0000:03:00.0&quot;,
- &quot;device_name&quot;: &quot;Dual Band Wireless AC 3165&quot;,
- &quot;passthruEnabled&quot;: true
- }
- ]
- }
- ]</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- sky-joker (@sky-joker)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_powermgmt_policy_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_powermgmt_policy_module.rst
deleted file mode 100644
index 58bb2c51c..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_powermgmt_policy_module.rst
+++ /dev/null
@@ -1,292 +0,0 @@
-.. _community.vmware.vmware_host_powermgmt_policy_module:
-
-
-*********************************************
-community.vmware.vmware_host_powermgmt_policy
-*********************************************
-
-**Manages the Power Management Policy of an ESXI host system**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to manage the Power Management Policy of ESXi host systems in given vCenter infrastructure.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the cluster from which all host systems will be used.</div>
- <div>This is required parameter if <code>esxi_hostname</code> is not specified.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the host system to work with.</div>
- <div>This is required parameter if <code>cluster_name</code> is not specified.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>policy</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>high-performance</li>
- <li><div style="color: blue"><b>balanced</b>&nbsp;&larr;</div></li>
- <li>low-power</li>
- <li>custom</li>
- </ul>
- </td>
- <td>
- <div>Set the Power Management Policy of the host system.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Set the Power Management Policy of a host system to high-performance
- community.vmware.vmware_host_powermgmt_policy:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_host }}'
- policy: high-performance
- delegate_to: localhost
-
- - name: Set the Power Management Policy of all host systems from cluster to high-performance
- community.vmware.vmware_host_powermgmt_policy:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- cluster_name: '{{ cluster_name }}'
- policy: high-performance
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>result</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about host system&#x27;s Power Management Policy</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;changed&#x27;: True, &#x27;result&#x27;: {&#x27;esxi01&#x27;: {&#x27;changed&#x27;: True, &#x27;current_state&#x27;: &#x27;high-performance&#x27;, &#x27;desired_state&#x27;: &#x27;high-performance&#x27;, &#x27;msg&#x27;: &#x27;Power policy changed&#x27;, &#x27;previous_state&#x27;: &#x27;balanced&#x27;}}}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Christian Kotte (@ckotte) <christian.kotte@gmx.de>
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_powerstate_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_powerstate_module.rst
deleted file mode 100644
index 7d7773af8..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_powerstate_module.rst
+++ /dev/null
@@ -1,347 +0,0 @@
-.. _community.vmware.vmware_host_powerstate_module:
-
-
-***************************************
-community.vmware.vmware_host_powerstate
-***************************************
-
-**Manages power states of host systems in vCenter**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to manage power states of host systems in given vCenter infrastructure.
-- User can set power state to 'power-down-to-standby', 'power-up-from-standby', 'shutdown-host' and 'reboot-host'.
-- State 'reboot-host', 'shutdown-host' and 'power-down-to-standby' are not supported by all the host systems.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the cluster from which all host systems will be used.</div>
- <div>This is required parameter if <code>esxi_hostname</code> is not specified.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the host system to work with.</div>
- <div>This is required parameter if <code>cluster_name</code> is not specified.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>force</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>This parameter specify if the host should be proceeding with user defined powerstate regardless of whether it is in maintenance mode.</div>
- <div>If <code>state</code> set to <code>reboot-host</code> and <code>force</code> as <code>true</code>, then host system is rebooted regardless of whether it is in maintenance mode.</div>
- <div>If <code>state</code> set to <code>shutdown-host</code> and <code>force</code> as <code>true</code>, then host system is shutdown regardless of whether it is in maintenance mode.</div>
- <div>If <code>state</code> set to <code>power-down-to-standby</code> and <code>force</code> to <code>true</code>, then all powered off VMs will evacuated.</div>
- <div>Not applicable if <code>state</code> set to <code>power-up-from-standby</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>power-down-to-standby</li>
- <li>power-up-from-standby</li>
- <li><div style="color: blue"><b>shutdown-host</b>&nbsp;&larr;</div></li>
- <li>reboot-host</li>
- </ul>
- </td>
- <td>
- <div>Set the state of the host system.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>timeout</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">600</div>
- </td>
- <td>
- <div>This parameter defines timeout for <code>state</code> set to <code>power-down-to-standby</code> or <code>power-up-from-standby</code>.</div>
- <div>Ignored if <code>state</code> set to <code>reboot-host</code> or <code>shutdown-host</code>.</div>
- <div>This parameter is defined in seconds.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Set the state of a host system to reboot
- community.vmware.vmware_host_powerstate:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- state: reboot-host
- delegate_to: localhost
- register: reboot_host
-
- - name: Set the state of a host system to power down to standby
- community.vmware.vmware_host_powerstate:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- state: power-down-to-standby
- delegate_to: localhost
- register: power_down
-
- - name: Set the state of all host systems from cluster to reboot
- community.vmware.vmware_host_powerstate:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- cluster_name: '{{ cluster_name }}'
- state: reboot-host
- delegate_to: localhost
- register: reboot_host
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>result</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about host system&#x27;s state</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;esxi01&#x27;: {&#x27;msg&#x27;: &quot;power down &#x27;esxi01&#x27; to standby&quot;, &#x27;error&#x27;: &#x27;&#x27;}}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_scanhba_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_scanhba_module.rst
deleted file mode 100644
index 86e02a024..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_scanhba_module.rst
+++ /dev/null
@@ -1,348 +0,0 @@
-.. _community.vmware.vmware_host_scanhba_module:
-
-
-************************************
-community.vmware.vmware_host_scanhba
-************************************
-
-**Rescan host HBA's and optionally refresh the storage system**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can force a rescan of the hosts HBA subsystem which is needed when wanting to mount a new datastore.
-- You could use this before using :ref:`community.vmware.vmware_host_datastore <community.vmware.vmware_host_datastore_module>` to mount a new datastore to ensure your device/volume is ready.
-- You can also optionally force a Refresh of the Storage System in vCenter/ESXi Web Client.
-- All parameters and VMware object names are case sensitive.
-- You can supply an esxi_hostname or a cluster_name
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Cluster name to Rescan the storage subsystem on (this will run the rescan task on each host in the cluster).</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>ESXi hostname to Rescan the storage subsystem on.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>refresh_storage</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Refresh the storage system in vCenter/ESXi Web Client for each host found</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>rescan_hba</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Rescan all host bus adapters for new storage devices. Rescanning all adapters can be slow.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>rescan_vmfs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Rescan all known storage devices for new VMFS volumes.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Recan HBA's for a given ESXi host and refresh storage system objects
- community.vmware.vmware_host_scanhba:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ inventory_hostname }}'
- refresh_storage: true
- delegate_to: localhost
-
- - name: Rescan HBA's for a given cluster - all found hosts will be scanned
- community.vmware.vmware_host_scanhba:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ inventory_hostname }}'
- refresh_storage: true
- delegate_to: localhost
-
- - name: Rescan for new VMFS Volumes in a given cluster, but do not scan for new Devices - all found hosts will be scanned
- community.vmware.vmware_host_scanhba:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ inventory_hostname }}'
- rescan_vmfs: true
- rescan_hba: false
- delegate_to: localhost
-
- - name: Recan HBA's for a given ESXi host and don't refresh storage system objects
- community.vmware.vmware_host_scanhba:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ inventory_hostname }}'
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>result</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>return confirmation of requested host and updated / refreshed storage system</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;esxi01.example.com&#x27;: {&#x27;rescaned_hba&#x27;: &#x27;true&#x27;, &#x27;refreshed_storage&#x27;: &#x27;true&#x27;, &#x27;rescaned_vmfs&#x27;: &#x27;true&#x27;}}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Michael Eaton (@michaeldeaton)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_scsidisk_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_scsidisk_info_module.rst
deleted file mode 100644
index b0162cb79..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_scsidisk_info_module.rst
+++ /dev/null
@@ -1,271 +0,0 @@
-.. _community.vmware.vmware_host_scsidisk_info_module:
-
-
-******************************************
-community.vmware.vmware_host_scsidisk_info
-******************************************
-
-**Gather information about SCSI disk attached to the given ESXi**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to gather information about SCSI disk attached to the given ESXi.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the cluster from which all host systems will be used.</div>
- <div>SCSI disk information about each ESXi server will be returned for the given cluster.</div>
- <div>This parameter is required if <em>esxi_hostname</em> is not specified.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the host system to work with.</div>
- <div>SCSI disk information about this ESXi server will be returned.</div>
- <div>This parameter is required if <em>cluster_name</em> is not specified.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Gather information SCSI disk attached to the given ESXi
- community.vmware.vmware_host_scsidisk_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- delegate_to: localhost
-
- - name: Gather information of all host systems from the given cluster
- community.vmware.vmware_host_scsidisk_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- cluster_name: '{{ cluster_name }}'
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>hosts_scsidisk_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about host system SCSI disk information</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;10.65.201.106&#x27;: [{&#x27;block&#x27;: 41943040, &#x27;block_size&#x27;: 512, &#x27;canonical_name&#x27;: &#x27;t10.ATA_QEMU_HARDDISK_QM00001_&#x27;, &#x27;device_name&#x27;: &#x27;/vmfs/devices/disks/t10.ATA_QEMU_HARDDISK_QM00001_&#x27;, &#x27;device_path&#x27;: &#x27;/vmfs/devices/disks/t10.ATA_QEMU_HARDDISK_QM00001_&#x27;, &#x27;device_type&#x27;: &#x27;disk&#x27;, &#x27;display_name&#x27;: &#x27;Local ATA Disk (t10.ATA_QEMU_HARDDISK_QM00001_)&#x27;, &#x27;key&#x27;: &#x27;key-vim.host.ScsiDisk-0100000000514d30303030312020202020202020202020202051454d552048&#x27;, &#x27;local_disk&#x27;: True, &#x27;lun_type&#x27;: &#x27;disk&#x27;, &#x27;model&#x27;: &#x27;QEMU HARDDISK &#x27;, &#x27;perenniallyReserved&#x27;: None, &#x27;protocol_endpoint&#x27;: False, &#x27;revision&#x27;: &#x27;1.5.&#x27;, &#x27;scsi_disk_type&#x27;: &#x27;native512&#x27;, &#x27;scsi_level&#x27;: 5, &#x27;serial_number&#x27;: &#x27;unavailable&#x27;, &#x27;ssd&#x27;: False, &#x27;uuid&#x27;: &#x27;0100000000514d30303030312020202020202020202020202051454d552048&#x27;, &#x27;vStorageSupport&#x27;: &#x27;vStorageUnsupported&#x27;, &#x27;vendor&#x27;: &#x27;ATA &#x27;}]}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_service_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_service_info_module.rst
deleted file mode 100644
index 246abc5eb..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_service_info_module.rst
+++ /dev/null
@@ -1,274 +0,0 @@
-.. _community.vmware.vmware_host_service_info_module:
-
-
-*****************************************
-community.vmware.vmware_host_service_info
-*****************************************
-
-**Gathers info about an ESXi host's services**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to gather information about an ESXi host's services.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the cluster.</div>
- <div>Service information about each ESXi server will be returned for given cluster.</div>
- <div>If <code>esxi_hostname</code> is not given, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>ESXi hostname.</div>
- <div>Service information about this ESXi server will be returned.</div>
- <div>If <code>cluster_name</code> is not given, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - If source package name is not available then fact is populated as null.
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Gather info about all ESXi Host in given Cluster
- community.vmware.vmware_host_service_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- cluster_name: cluster_name
- delegate_to: localhost
- register: cluster_host_services
-
- - name: Gather info about ESXi Host
- community.vmware.vmware_host_service_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- delegate_to: localhost
- register: host_services
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>host_service_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>dict with hostname as key and dict with host service config information</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;10.76.33.226&#x27;: [{&#x27;key&#x27;: &#x27;DCUI&#x27;, &#x27;label&#x27;: &#x27;Direct Console UI&#x27;, &#x27;policy&#x27;: &#x27;on&#x27;, &#x27;required&#x27;: False, &#x27;running&#x27;: True, &#x27;uninstallable&#x27;: False, &#x27;source_package_name&#x27;: &#x27;esx-base&#x27;, &#x27;source_package_desc&#x27;: &#x27;This VIB contains all of the base functionality of vSphere ESXi.&#x27;}, {&#x27;key&#x27;: &#x27;TSM&#x27;, &#x27;label&#x27;: &#x27;ESXi Shell&#x27;, &#x27;policy&#x27;: &#x27;off&#x27;, &#x27;required&#x27;: False, &#x27;running&#x27;: False, &#x27;uninstallable&#x27;: False, &#x27;source_package_name&#x27;: &#x27;esx-base&#x27;, &#x27;source_package_desc&#x27;: &#x27;This VIB contains all of the base functionality of vSphere ESXi.&#x27;}]}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_service_manager_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_service_manager_module.rst
deleted file mode 100644
index 7066e4f72..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_service_manager_module.rst
+++ /dev/null
@@ -1,332 +0,0 @@
-.. _community.vmware.vmware_host_service_manager_module:
-
-
-********************************************
-community.vmware.vmware_host_service_manager
-********************************************
-
-**Manage services on a given ESXi host**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to manage (start, stop, restart) services on a given ESXi host.
-- If cluster_name is provided, specified service will be managed on all ESXi host belonging to that cluster.
-- If specific esxi_hostname is provided, then specified service will be managed on given ESXi host only.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the cluster.</div>
- <div>Service settings are applied to every ESXi host system/s in given cluster.</div>
- <div>If <code>esxi_hostname</code> is not given, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>ESXi hostname.</div>
- <div>Service settings are applied to this ESXi host system.</div>
- <div>If <code>cluster_name</code> is not given, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>service_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of Service to be managed. This is a brief identifier for the service, for example, ntpd, vxsyslogd etc.</div>
- <div>This value should be a valid ESXi service name.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>service_policy</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>automatic</li>
- <li>off</li>
- <li>on</li>
- </ul>
- </td>
- <td>
- <div>Set of valid service policy strings.</div>
- <div>If set <code>on</code>, then service should be started when the host starts up.</div>
- <div>If set <code>automatic</code>, then service should run if and only if it has open firewall ports.</div>
- <div>If set <code>off</code>, then Service should not be started when the host starts up.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>absent</li>
- <li>present</li>
- <li>restart</li>
- <li><div style="color: blue"><b>start</b>&nbsp;&larr;</div></li>
- <li>stop</li>
- <li>unchanged</li>
- </ul>
- </td>
- <td>
- <div>Desired state of service.</div>
- <div>State value &#x27;start&#x27; and &#x27;present&#x27; has same effect.</div>
- <div>State value &#x27;stop&#x27; and &#x27;absent&#x27; has same effect.</div>
- <div>State value <code>unchanged</code> is added in version 1.14.0 to allow defining startup policy without defining or changing service state.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Start ntpd service setting for all ESXi Host in given Cluster
- community.vmware.vmware_host_service_manager:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- cluster_name: '{{ cluster_name }}'
- service_name: ntpd
- state: present
- delegate_to: localhost
-
- - name: Start ntpd setting for an ESXi Host
- community.vmware.vmware_host_service_manager:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- service_name: ntpd
- state: present
- delegate_to: localhost
-
- - name: Start ntpd setting for an ESXi Host with Service policy
- community.vmware.vmware_host_service_manager:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- service_name: ntpd
- service_policy: 'on'
- state: present
- delegate_to: localhost
-
- - name: Stop ntpd setting for an ESXi Host
- community.vmware.vmware_host_service_manager:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- service_name: ntpd
- state: absent
- delegate_to: localhost
-
-
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_snmp_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_snmp_module.rst
deleted file mode 100644
index 86f861b04..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_snmp_module.rst
+++ /dev/null
@@ -1,447 +0,0 @@
-.. _community.vmware.vmware_host_snmp_module:
-
-
-*********************************
-community.vmware.vmware_host_snmp
-*********************************
-
-**Configures SNMP on an ESXi host system**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to configure the embedded SNMP agent on an ESXi host.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>community</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">[]</div>
- </td>
- <td>
- <div>List of SNMP community strings.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hw_source</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>indications</b>&nbsp;&larr;</div></li>
- <li>sensors</li>
- </ul>
- </td>
- <td>
- <div>Source hardware events from IPMI sensors or CIM Indications.</div>
- <div>The embedded SNMP agent receives hardware events either from IPMI sensors <code>sensors</code> or CIM indications <code>indications</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>log_level</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>debug</li>
- <li><div style="color: blue"><b>info</b>&nbsp;&larr;</div></li>
- <li>warning</li>
- <li>error</li>
- </ul>
- </td>
- <td>
- <div>Syslog logging level.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>send_trap</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Send a test trap to validate the configuration.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>snmp_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">161</div>
- </td>
- <td>
- <div>Port used by the SNMP agent.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>disabled</b>&nbsp;&larr;</div></li>
- <li>enabled</li>
- <li>reset</li>
- </ul>
- </td>
- <td>
- <div>Enable, disable, or reset the SNMP agent.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>sys_contact</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>System contact who manages the system.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>sys_location</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>System location.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>trap_filter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>A list of trap oids for traps not to be sent by agent, e.g. [ 1.3.6.1.4.1.6876.4.1.1.0, 1.3.6.1.4.1.6876.4.1.1.1 ]</div>
- <div>Use value <code>reset</code> to clear settings.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>trap_targets</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">[]</div>
- </td>
- <td>
- <div>A list of trap targets.</div>
- <div>You need to use <code>hostname</code>, <code>port</code>, and <code>community</code> for each trap target.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - You need to reset the agent (to factory defaults) if you want to clear all community strings, trap targets, or filters
- - SNMP v3 configuration isn't implemented yet
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Enable and configure SNMP community
- community.vmware.vmware_host_snmp:
- hostname: '{{ esxi_hostname }}'
- username: '{{ esxi_username }}'
- password: '{{ esxi_password }}'
- community: [ test ]
- state: enabled
- delegate_to: localhost
-
- - name: Configure SNMP traps and filters
- community.vmware.vmware_host_snmp:
- hostname: '{{ esxi_hostname }}'
- username: '{{ esxi_username }}'
- password: '{{ esxi_password }}'
- community: [ test ]
- trap_targets:
- - hostname: 192.168.1.100
- port: 162
- community: test123
- - hostname: 192.168.1.101
- port: 162
- community: test1234
- trap_filter:
- - 1.3.6.1.4.1.6876.4.1.1.0
- - 1.3.6.1.4.1.6876.4.1.1.1
- state: enabled
- delegate_to: localhost
-
- - name: Enable and configure SNMP system contact and location
- community.vmware.vmware_host_snmp:
- hostname: '{{ esxi_hostname }}'
- username: '{{ esxi_username }}'
- password: '{{ esxi_password }}'
- sys_contact: "admin@testemail.com"
- sys_location: "Austin, USA"
- state: enabled
- delegate_to: localhost
-
- - name: Disable SNMP
- community.vmware.vmware_host_snmp:
- hostname: '{{ esxi_hostname }}'
- username: '{{ esxi_username }}'
- password: '{{ esxi_password }}'
- state: disabled
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>results</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about host system&#x27;s SNMP configuration</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;esxi01&#x27;: {&#x27;changed&#x27;: False, &#x27;community&#x27;: [&#x27;test&#x27;], &#x27;hw_source&#x27;: &#x27;indications&#x27;, &#x27;msg&#x27;: &#x27;SNMP already configured properly&#x27;, &#x27;port&#x27;: 161, &#x27;state&#x27;: &#x27;enabled&#x27;, &#x27;trap_targets&#x27;: []}}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Christian Kotte (@ckotte)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_sriov_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_sriov_module.rst
deleted file mode 100644
index f4645203c..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_sriov_module.rst
+++ /dev/null
@@ -1,352 +0,0 @@
-.. _community.vmware.vmware_host_sriov_module:
-
-
-**********************************
-community.vmware.vmware_host_sriov
-**********************************
-
-**Manage SR-IOV settings on host**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to configure, enable or disable SR-IOV functions on ESXi host.
-- Module does not reboot the host after changes, but puts it in output "rebootRequired" state.
-- User can specify an ESXi hostname or Cluster name. In case of cluster name, all ESXi hosts are updated.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the cluster from which all host systems will be used.</div>
- <div>This parameter is required if <code>esxi_hostname</code> is not specified.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the host system to work with.</div>
- <div>This parameter is required if <code>cluster_name</code> is not specified.</div>
- <div>User can specify specific host from the cluster.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>num_virt_func</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>number of functions to activate on interface.</div>
- <div>0 means SR-IOV disabled.</div>
- <div>number greater than 0 means SR-IOV enabled.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>sriov_on</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>optional parameter, related to <code>num_virt_func</code>.</div>
- <div>SR-IOV can be enabled only if <code>num_virt_func</code> &gt; 0.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vmnic</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Interface name, like vmnic0.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: enable SR-IOV on vmnic0 with 8 functions
- community.vmware.vmware_host_sriov:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- esxi_hostname: "{{ esxi1 }}"
- vmnic: vmnic0
- sriov_on: true
- num_virt_func: 8
-
- - name: enable SR-IOV on already enabled interface vmnic0
- community.vmware.vmware_host_sriov:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- esxi_hostname: "{{ esxi1 }}"
- vmnic: vmnic0
- sriov_on: true
- num_virt_func: 8
-
- - name: enable SR-IOV on vmnic0 with big number of functions
- community.vmware.vmware_host_sriov:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- esxi_hostname: "{{ esxi1 }}"
- vmnic: vmnic0
- sriov_on: true
- num_virt_func: 100
- ignore_errors: true
-
- - name: disable SR-IOV on vmnic0
- community.vmware.vmware_host_sriov:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- esxi_hostname: "{{ esxi1 }}"
- vmnic: vmnic0
- sriov_on: false
- num_virt_func: 0
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>host_sriov_diff</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>contains info about SR-IOV status on vmnic before, after and requested changes</div>
- <div>sometimes vCenter slowly update info, as result &quot;after&quot; contains same info as &quot;before&quot; need to run again in check_mode or reboot host, as ESXi requested</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;changed&#x27;: True, &#x27;diff&#x27;: {&#x27;after&#x27;: {&#x27;host_test&#x27;: {&#x27;sriovActive&#x27;: False, &#x27;sriovEnabled&#x27;: True, &#x27;maxVirtualFunctionSupported&#x27;: 63, &#x27;numVirtualFunction&#x27;: 0, &#x27;numVirtualFunctionRequested&#x27;: 8, &#x27;rebootRequired&#x27;: True, &#x27;sriovCapable&#x27;: True}}, &#x27;before&#x27;: {&#x27;host_test&#x27;: {&#x27;sriovActive&#x27;: False, &#x27;sriovEnabled&#x27;: False, &#x27;maxVirtualFunctionSupported&#x27;: 63, &#x27;numVirtualFunction&#x27;: 0, &#x27;numVirtualFunctionRequested&#x27;: 0, &#x27;rebootRequired&#x27;: False, &#x27;sriovCapable&#x27;: True}}, &#x27;changes&#x27;: {&#x27;host_test&#x27;: {&#x27;numVirtualFunction&#x27;: 8, &#x27;rebootRequired&#x27;: True, &#x27;sriovEnabled&#x27;: True}}}}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Viktor Tsymbalyuk (@victron)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_ssl_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_ssl_info_module.rst
deleted file mode 100644
index 5ea83fe11..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_ssl_info_module.rst
+++ /dev/null
@@ -1,288 +0,0 @@
-.. _community.vmware.vmware_host_ssl_info_module:
-
-
-*************************************
-community.vmware.vmware_host_ssl_info
-*************************************
-
-**Gather info of ESXi host system about SSL**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to gather information of the SSL thumbprint information for a host.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the cluster.</div>
- <div>SSL thumbprint information about all ESXi host system in the given cluster will be reported.</div>
- <div>If <code>esxi_hostname</code> is not given, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>ESXi hostname.</div>
- <div>SSL thumbprint information of this ESXi host system will be reported.</div>
- <div>If <code>cluster_name</code> is not given, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Gather SSL thumbprint information about all ESXi Hosts in given Cluster
- community.vmware.vmware_host_ssl_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- cluster_name: '{{ cluster_name }}'
- delegate_to: localhost
- register: all_host_ssl_info
-
- - name: Get SSL Thumbprint info about "{{ esxi_hostname }}"
- community.vmware.vmware_host_ssl_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- esxi_hostname: '{{ esxi_hostname }}'
- register: ssl_info
- - set_fact:
- ssl_thumbprint: "{{ ssl_info['host_ssl_info'][esxi_hostname]['ssl_thumbprints'][0] }}"
- - debug:
- msg: "{{ ssl_thumbprint }}"
- - name: Add ESXi Host to vCenter
- vmware_host:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter_name: '{{ datacenter_name }}'
- cluster_name: '{{ cluster_name }}'
- esxi_hostname: '{{ esxi_hostname }}'
- esxi_username: '{{ esxi_username }}'
- esxi_password: '{{ esxi_password }}'
- esxi_ssl_thumbprint: '{{ ssl_thumbprint }}'
- state: present
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>host_ssl_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>info</td>
- <td>
- <div>dict with hostname as key and dict with SSL thumbprint related info</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;10.76.33.215&#x27;: {&#x27;owner_tag&#x27;: &#x27;&#x27;, &#x27;principal&#x27;: &#x27;vpxuser&#x27;, &#x27;ssl_thumbprints&#x27;: [&#x27;E3:E8:A9:20:8D:32:AE:59:C6:8D:A5:91:B0:20:EF:00:A2:7C:27:EE&#x27;, &#x27;F1:AC:DA:6E:D8:1E:37:36:4A:5C:07:E5:04:0B:87:C8:75:FB:42:01&#x27;]}}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_tcpip_stacks_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_tcpip_stacks_module.rst
deleted file mode 100644
index 9134999e2..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_tcpip_stacks_module.rst
+++ /dev/null
@@ -1,805 +0,0 @@
-.. _community.vmware.vmware_host_tcpip_stacks_module:
-
-
-*****************************************
-community.vmware.vmware_host_tcpip_stacks
-*****************************************
-
-**Manage the TCP/IP Stacks configuration of ESXi host**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to modify the TCP/IP stacks configuration.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="2">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>default</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The TCP/IP stacks configuration of the <em>default</em>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>alternate_dns</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The IP address of the alternate dns server.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>congestion_algorithm</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>newreno</b>&nbsp;&larr;</div></li>
- <li>cubic</li>
- </ul>
- </td>
- <td>
- <div>The TCP congest control algorithm.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>domain</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The domain name portion of the DNS name.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>gateway</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The ipv4 gateway address.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The host name of the ESXi host.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>ipv6_gateway</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The ipv6 gateway address.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>max_num_connections</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">11000</div>
- </td>
- <td>
- <div>The maximum number of socket connection that are requested.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>preferred_dns</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The IP address of the preferred dns server.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>search_domains</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">[]</div>
- </td>
- <td>
- <div>The domain in which to search for hosts, placed in order of preference.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the ESXi host.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>provisioning</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The TCP/IP stacks configuration of the <em>provisioning</em>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>congestion_algorithm</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>newreno</b>&nbsp;&larr;</div></li>
- <li>cubic</li>
- </ul>
- </td>
- <td>
- <div>The TCP congest control algorithm.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>gateway</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The ipv4 gateway address.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>ipv6_gateway</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The ipv6 gateway address.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>max_num_connections</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">11000</div>
- </td>
- <td>
- <div>The maximum number of socket connection that are requested.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vmotion</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The TCP/IP stacks configuration of the <em>vmotion</em>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>congestion_algorithm</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>newreno</b>&nbsp;&larr;</div></li>
- <li>cubic</li>
- </ul>
- </td>
- <td>
- <div>The TCP congest control algorithm.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>gateway</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The ipv4 gateway address.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>ipv6_gateway</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The ipv6 gateway address.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>max_num_connections</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">11000</div>
- </td>
- <td>
- <div>The maximum number of socket connection that are requested.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vxlan</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The TCP/IP stacks configuration of the <em>vxlan</em>.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: nsx_overlay</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>congestion_algorithm</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>newreno</b>&nbsp;&larr;</div></li>
- <li>cubic</li>
- </ul>
- </td>
- <td>
- <div>The TCP congest control algorithm.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>gateway</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The ipv4 gateway address.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>ipv6_gateway</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The ipv6 gateway address.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>max_num_connections</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">11000</div>
- </td>
- <td>
- <div>The maximum number of socket connection that are requested.</div>
- </td>
- </tr>
-
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Update the TCP/IP stack configuration of the default
- community.vmware.vmware_host_tcpip_stacks:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- validate_certs: false
- esxi_hostname: "{{ esxi_hostname }}"
- default:
- hostname: "{{ esxi_hostname }}"
- domain: example.com
- preferred_dns: 192.168.10.1
- alternate_dns: 192.168.20.1
- search_domains:
- - hoge.com
- - fuga.com
- gateway: 192.168.10.1
- congestion_algorithm: cubic
- max_num_connections: 12000
-
- - name: Update the TCP/IP stack configuration of the provisioning
- community.vmware.vmware_host_tcpip_stacks:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- validate_certs: false
- esxi_hostname: "{{ esxi_hostname }}"
- provisioning:
- congestion_algorithm: newreno
- max_num_connections: 12000
- gateway: 10.10.10.254
-
- - name: Update the TCP/IP stack configuration of the default and provisioning
- community.vmware.vmware_host_tcpip_stacks:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- validate_certs: false
- esxi_hostname: "{{ esxi_hostname }}"
- default:
- hostname: "{{ esxi_hostname }}"
- domain: example.com
- preferred_dns: 192.168.10.1
- alternate_dns: 192.168.20.1
- search_domains:
- - hoge.com
- - fuga.com
- gateway: 192.168.10.1
- congestion_algorithm: cubic
- max_num_connections: 12000
- provisioning:
- congestion_algorithm: newreno
- max_num_connections: 12000
- gateway: 10.10.10.254
-
- - name: Update the ipv6 gateway of the provisioning TCP/IP stack
- community.vmware.vmware_host_tcpip_stacks:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- validate_certs: false
- esxi_hostname: "{{ esxi_hostname }}"
- provisioning:
- ipv6_gateway: ::ffff:6440:301
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>default</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>dict of the TCP/IP stack configuration of the default.</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{
- &quot;alternate_dns&quot;: &quot;192.168.20.1&quot;,
- &quot;congestion_algorithm&quot;: &quot;cubic&quot;,
- &quot;domain&quot;: &quot;example.com&quot;,
- &quot;gateway&quot;: &quot;192.168.10.1&quot;,
- &quot;ipv6_gateway&quot;, null,
- &quot;hostname&quot;: &quot;esxi-test03&quot;,
- &quot;max_num_connections&quot;: 12000,
- &quot;preferred_dns&quot;: &quot;192.168.10.1&quot;,
- &quot;search_domains&quot;: [
- &quot;hoge.com&quot;,
- &quot;fuga.com&quot;
- ]
- }</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>provisioning</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>dict of the TCP/IP stack configuration of the provisioning.</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{
- &quot;congestion_algorithm&quot;: &quot;newreno&quot;,
- &quot;gateway&quot;: &quot;10.10.10.254&quot;,
- &quot;ipv6_gateway&quot;: null,
- &quot;max_num_connections&quot;: 12000
- }</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>vmotion</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>dict of the TCP/IP stack configuration of the vmotion.</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{
- &quot;congestion_algorithm&quot;: &quot;newreno&quot;,
- &quot;gateway&quot;: null,
- &quot;ipv6_gateway&quot;: null,
- &quot;max_num_connections&quot;: 11000
- }</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>vxlan</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>dict of the TCP/IP stack configuration of the vxlan.</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{
- &quot;congestion_algorithm&quot;: &quot;newreno&quot;,
- &quot;gateway&quot;: null,
- &quot;ipv6_gateway&quot;: null,
- &quot;max_num_connections&quot;: 11000
- }</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- sky-joker (@sky-joker)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_user_manager_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_user_manager_module.rst
deleted file mode 100644
index 9f7f6b322..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_user_manager_module.rst
+++ /dev/null
@@ -1,364 +0,0 @@
-.. _community.vmware.vmware_host_user_manager_module:
-
-
-*****************************************
-community.vmware.vmware_host_user_manager
-*****************************************
-
-**Manage users of ESXi**
-
-
-Version added: 2.1.0
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can add, update or delete local users on ESXi host.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the ESXi host that is managing the local user.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>override_user_password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>If the local user exists and updates the password, change this parameter value is true.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>If set to <code>present</code>, add a new local user or update information.</div>
- <div>If set to <code>absent</code>, delete the local user.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>user_description</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The local user description.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: local_user_description</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>user_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the local user.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: local_user_name</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>user_password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The local user password.</div>
- <div>If you&#x27;d like to update the password, require the <em>override_user_password</em> is true.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: local_user_password</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Add new local user to ESXi host
- community.vmware.vmware_host_user_manager:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- validate_certs: false
- esxi_hostname: "{{ esxi1 }}"
- user_name: example
- user_description: "example user"
- user_password: "{{ local_user_password }}"
- state: present
-
- - name: Update the local user password in ESXi host
- community.vmware.vmware_host_user_manager:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- validate_certs: false
- esxi_hostname: "{{ esxi1 }}"
- user_name: example
- user_description: "example user"
- user_password: "{{ local_user_password }}"
- override_user_password: true
- state: present
-
- - name: Delete the local user in ESXi host
- community.vmware.vmware_host_user_manager:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- validate_certs: false
- esxi_hostname: "{{ esxi1 }}"
- user_name: example
- state: absent
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>msg</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>The executed result for the module.</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{
- &quot;msg&quot;: &quot;Added the new user.
- }</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- sky-joker (@sky-joker)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_vmhba_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_vmhba_info_module.rst
deleted file mode 100644
index f817bb845..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_vmhba_info_module.rst
+++ /dev/null
@@ -1,275 +0,0 @@
-.. _community.vmware.vmware_host_vmhba_info_module:
-
-
-***************************************
-community.vmware.vmware_host_vmhba_info
-***************************************
-
-**Gathers info about vmhbas available on the given ESXi host**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to gather information about vmhbas available on the given ESXi host.
-- If ``cluster_name`` is provided, then vmhba information about all hosts from given cluster will be returned.
-- If ``esxi_hostname`` is provided, then vmhba information about given host system will be returned.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the cluster from which all host systems will be used.</div>
- <div>Vmhba information about each ESXi server will be returned for the given cluster.</div>
- <div>This parameter is required if <code>esxi_hostname</code> is not specified.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the host system to work with.</div>
- <div>Vmhba information about this ESXi server will be returned.</div>
- <div>This parameter is required if <code>cluster_name</code> is not specified.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Gather info about vmhbas of all ESXi Host in the given Cluster
- community.vmware.vmware_host_vmhba_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- cluster_name: '{{ cluster_name }}'
- delegate_to: localhost
- register: cluster_host_vmhbas
-
- - name: Gather info about vmhbas of an ESXi Host
- community.vmware.vmware_host_vmhba_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- delegate_to: localhost
- register: host_vmhbas
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>hosts_vmhbas_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>hosts_vmhbas_info</td>
- <td>
- <div>dict with hostname as key and dict with vmhbas information as value.</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;10.76.33.204&#x27;: {&#x27;vmhba_details&#x27;: [{&#x27;adapter&#x27;: &#x27;HPE Smart Array P440ar&#x27;, &#x27;bus&#x27;: 3, &#x27;device&#x27;: &#x27;vmhba0&#x27;, &#x27;driver&#x27;: &#x27;nhpsa&#x27;, &#x27;location&#x27;: &#x27;0000:03:00.0&#x27;, &#x27;model&#x27;: &#x27;Smart Array P440ar&#x27;, &#x27;node_wwn&#x27;: &#x27;50:01:43:80:37:18:9e:a0&#x27;, &#x27;status&#x27;: &#x27;unknown&#x27;, &#x27;type&#x27;: &#x27;SAS&#x27;}, {&#x27;adapter&#x27;: &#x27;QLogic Corp ISP2532-based 8Gb Fibre Channel to PCI Express HBA&#x27;, &#x27;bus&#x27;: 5, &#x27;device&#x27;: &#x27;vmhba1&#x27;, &#x27;driver&#x27;: &#x27;qlnativefc&#x27;, &#x27;location&#x27;: &#x27;0000:05:00.0&#x27;, &#x27;model&#x27;: &#x27;ISP2532-based 8Gb Fibre Channel to PCI Express HBA&#x27;, &#x27;node_wwn&#x27;: &#x27;57:64:96:32:15:90:23:95:82&#x27;, &#x27;port_type&#x27;: &#x27;unknown&#x27;, &#x27;port_wwn&#x27;: &#x27;57:64:96:32:15:90:23:95:82&#x27;, &#x27;speed&#x27;: 8, &#x27;status&#x27;: &#x27;online&#x27;, &#x27;type&#x27;: &#x27;Fibre Channel&#x27;}, {&#x27;adapter&#x27;: &#x27;QLogic Corp ISP2532-based 8Gb Fibre Channel to PCI Express HBA&#x27;, &#x27;bus&#x27;: 8, &#x27;device&#x27;: &#x27;vmhba2&#x27;, &#x27;driver&#x27;: &#x27;qlnativefc&#x27;, &#x27;location&#x27;: &#x27;0000:08:00.0&#x27;, &#x27;model&#x27;: &#x27;ISP2532-based 8Gb Fibre Channel to PCI Express HBA&#x27;, &#x27;node_wwn&#x27;: &#x27;57:64:96:32:15:90:23:95:21&#x27;, &#x27;port_type&#x27;: &#x27;unknown&#x27;, &#x27;port_wwn&#x27;: &#x27;57:64:96:32:15:90:23:95:21&#x27;, &#x27;speed&#x27;: 8, &#x27;status&#x27;: &#x27;online&#x27;, &#x27;type&#x27;: &#x27;Fibre Channel&#x27;}]}}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Christian Kotte (@ckotte)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_vmnic_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_host_vmnic_info_module.rst
deleted file mode 100644
index c76f45259..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_host_vmnic_info_module.rst
+++ /dev/null
@@ -1,339 +0,0 @@
-.. _community.vmware.vmware_host_vmnic_info_module:
-
-
-***************************************
-community.vmware.vmware_host_vmnic_info
-***************************************
-
-**Gathers info about vmnics available on the given ESXi host**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to gather information about vmnics available on the given ESXi host.
-- If ``cluster_name`` is provided, then vmnic information about all hosts from given cluster will be returned.
-- If ``esxi_hostname`` is provided, then vmnic information about given host system will be returned.
-- Additional details about vswitch and dvswitch with respective vmnic is also provided which is added in 2.7 version.
-- Additional details about lldp added in 1.11.0
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>capabilities</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Gather information about general capabilities (Auto negotiation, Wake On LAN, and Network I/O Control).</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the cluster from which all host systems will be used.</div>
- <div>Vmnic information about each ESXi server will be returned for the given cluster.</div>
- <div>This parameter is required if <code>esxi_hostname</code> is not specified.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>directpath_io</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Gather information about DirectPath I/O capabilities and configuration.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the host system to work with.</div>
- <div>Vmnic information about this ESXi server will be returned.</div>
- <div>This parameter is required if <code>cluster_name</code> is not specified.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>sriov</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Gather information about SR-IOV capabilities and configuration.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Gather info about vmnics of all ESXi Host in the given Cluster
- community.vmware.vmware_host_vmnic_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- cluster_name: '{{ cluster_name }}'
- delegate_to: localhost
- register: cluster_host_vmnics
-
- - name: Gather info about vmnics of an ESXi Host
- community.vmware.vmware_host_vmnic_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- delegate_to: localhost
- register: host_vmnics
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>hosts_vmnics_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>hosts_vmnics_info</td>
- <td>
- <div>dict with hostname as key and dict with vmnics information as value.</div>
- <div>for <code>num_vmnics</code>, only NICs starting with vmnic are counted. NICs like vusb* are not counted.</div>
- <div>details about vswitch and dvswitch was added in version 2.7.</div>
- <div>details about vmnics was added in version 2.8.</div>
- <div>details about lldp was added in version 1.11.0</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;10.76.33.204&#x27;: {&#x27;all&#x27;: [&#x27;vmnic0&#x27;, &#x27;vmnic1&#x27;], &#x27;available&#x27;: [], &#x27;dvswitch&#x27;: {&#x27;dvs_0002&#x27;: [&#x27;vmnic1&#x27;]}, &#x27;num_vmnics&#x27;: 2, &#x27;used&#x27;: [&#x27;vmnic1&#x27;, &#x27;vmnic0&#x27;], &#x27;vmnic_details&#x27;: [{&#x27;actual_duplex&#x27;: &#x27;Full Duplex&#x27;, &#x27;actual_speed&#x27;: 10000, &#x27;adapter&#x27;: &#x27;Intel(R) 82599 10 Gigabit Dual Port Network Connection&#x27;, &#x27;configured_duplex&#x27;: &#x27;Auto negotiate&#x27;, &#x27;configured_speed&#x27;: &#x27;Auto negotiate&#x27;, &#x27;device&#x27;: &#x27;vmnic0&#x27;, &#x27;driver&#x27;: &#x27;ixgbe&#x27;, &#x27;lldp_info&#x27;: {&#x27;Aggregated Port ID&#x27;: &#x27;0&#x27;, &#x27;Aggregation Status&#x27;: &#x27;1&#x27;, &#x27;Enabled Capabilities&#x27;: {&#x27;_vimtype&#x27;: &#x27;vim.host.PhysicalNic.CdpDeviceCapability&#x27;, &#x27;host&#x27;: False, &#x27;igmpEnabled&#x27;: False, &#x27;networkSwitch&#x27;: False, &#x27;repeater&#x27;: False, &#x27;router&#x27;: True, &#x27;sourceRouteBridge&#x27;: False, &#x27;transparentBridge&#x27;: True}, &#x27;MTU&#x27;: &#x27;9216&#x27;, &#x27;Port Description&#x27;: &#x27;switch port description&#x27;, &#x27;Samples&#x27;: 18814, &#x27;System Description&#x27;: &#x27;omitted from output&#x27;, &#x27;System Name&#x27;: &#x27;sw1&#x27;, &#x27;TimeOut&#x27;: 30, &#x27;Vlan ID&#x27;: &#x27;1&#x27;}, &#x27;location&#x27;: &#x27;0000:01:00.0&#x27;, &#x27;mac&#x27;: &#x27;aa:bb:cc:dd:ee:ff&#x27;, &#x27;status&#x27;: &#x27;Connected&#x27;}, {&#x27;actual_duplex&#x27;: &#x27;Full Duplex&#x27;, &#x27;actual_speed&#x27;: 10000, &#x27;adapter&#x27;: &#x27;Intel(R) 82599 10 Gigabit Dual Port Network Connection&#x27;, &#x27;configured_duplex&#x27;: &#x27;Auto negotiate&#x27;, &#x27;configured_speed&#x27;: &#x27;Auto negotiate&#x27;, &#x27;device&#x27;: &#x27;vmnic1&#x27;, &#x27;driver&#x27;: &#x27;ixgbe&#x27;, &#x27;lldp_info&#x27;: &#x27;N/A&#x27;, &#x27;location&#x27;: &#x27;0000:01:00.1&#x27;, &#x27;mac&#x27;: &#x27;ab:ba:cc:dd:ee:ff&#x27;, &#x27;status&#x27;: &#x27;Connected&#x27;}], &#x27;vswitch&#x27;: {&#x27;vSwitch0&#x27;: [&#x27;vmnic0&#x27;]}}}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
-- Christian Kotte (@ckotte)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_httpapi.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_httpapi.rst
deleted file mode 100644
index a00609b77..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_httpapi.rst
+++ /dev/null
@@ -1,42 +0,0 @@
-.. _community.vmware.vmware_httpapi:
-
-
-***********************
-community.vmware.vmware
-***********************
-
-**HttpApi Plugin for VMware REST API**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This HttpApi plugin provides methods to connect to VMware vCenter over a HTTP(S)-based APIs.
-
-
-
-
-
-
-
-
-
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
-
-
-.. hint::
- Configuration entries for each entry type have a low to high priority order. For example, a variable that is lower in the list will override a variable that is higher up.
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_local_role_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_local_role_info_module.rst
deleted file mode 100644
index 7c6febcb0..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_local_role_info_module.rst
+++ /dev/null
@@ -1,236 +0,0 @@
-.. _community.vmware.vmware_local_role_info_module:
-
-
-***************************************
-community.vmware.vmware_local_role_info
-***************************************
-
-**Gather info about local roles on an ESXi host or vCenter**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to gather information about local role info on an ESXi host or vCenter
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - Be sure that the user used for login, has the appropriate rights to view roles
- - The module returns a list of dict in version 2.8 and above.
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Gather info about local role from an ESXi (or vCenter)
- community.vmware.vmware_local_role_info:
- hostname: '{{ esxi_hostname }}'
- username: '{{ esxi_username }}'
- password: '{{ esxi_password }}'
- register: fact_details
- delegate_to: localhost
- - name: Get Admin privileges
- set_fact:
- admin_priv: "{{ fact_details.local_role_info | selectattr('role_name', 'equalto', 'Admin') | map(attribute='privileges') | first }}"
- - debug:
- msg: "{{ admin_priv }}"
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>local_role_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>A list of dict about role information present on ESXi host</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">[{&#x27;privileges&#x27;: [&#x27;Alarm.Acknowledge&#x27;, &#x27;Alarm.Create&#x27;, &#x27;Alarm.Delete&#x27;, &#x27;Alarm.DisableActions&#x27;], &#x27;role_id&#x27;: -12, &#x27;role_info_label&#x27;: &#x27;Ansible User&#x27;, &#x27;role_info_summary&#x27;: &#x27;Ansible Automation user&#x27;, &#x27;role_name&#x27;: &#x27;AnsiUser1&#x27;, &#x27;role_system&#x27;: True}, {&#x27;privileges&#x27;: [], &#x27;role_id&#x27;: -5, &#x27;role_info_label&#x27;: &#x27;No access&#x27;, &#x27;role_info_summary&#x27;: &#x27;Used for restricting granted access&#x27;, &#x27;role_name&#x27;: &#x27;NoAccess&#x27;, &#x27;role_system&#x27;: True}, {&#x27;privileges&#x27;: [&#x27;System.Anonymous&#x27;, &#x27;System.View&#x27;], &#x27;role_id&#x27;: -3, &#x27;role_info_label&#x27;: &#x27;View&#x27;, &#x27;role_info_summary&#x27;: &#x27;Visibility access (cannot be granted)&#x27;, &#x27;role_name&#x27;: &#x27;View&#x27;, &#x27;role_system&#x27;: True}]</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_local_role_manager_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_local_role_manager_module.rst
deleted file mode 100644
index 05014bdd1..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_local_role_manager_module.rst
+++ /dev/null
@@ -1,465 +0,0 @@
-.. _community.vmware.vmware_local_role_manager_module:
-
-
-******************************************
-community.vmware.vmware_local_role_manager
-******************************************
-
-**Manage local roles on an ESXi host or vCenter**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to manage local roles on an ESXi host or vCenter.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>action</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>add</li>
- <li>remove</li>
- <li><div style="color: blue"><b>set</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>This parameter is only valid while updating an existing role with privileges.</div>
- <div><code>add</code> will add the privileges to the existing privilege list.</div>
- <div><code>remove</code> will remove the privileges from the existing privilege list.</div>
- <div><code>set</code> will replace the privileges of the existing privileges with user defined list of privileges.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>force_remove</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>If set to <code>false</code> then prevents the role from being removed if any permissions are using it.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>local_privilege_ids</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">[]</div>
- </td>
- <td>
- <div>The list of privileges that role needs to have.</div>
- <div>Please see <a href='https://docs.vmware.com/en/VMware-vSphere/6.0/com.vmware.vsphere.security.doc/GUID-ED56F3C4-77D0-49E3-88B6-B99B8B437B62.html'>https://docs.vmware.com/en/VMware-vSphere/6.0/com.vmware.vsphere.security.doc/GUID-ED56F3C4-77D0-49E3-88B6-B99B8B437B62.html</a></div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>local_role_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The local role name to be managed.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>Indicate desired state of the role.</div>
- <div>If the role already exists when <code>state=present</code>, the role info is updated.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - Be sure that the user used for login, has the appropriate rights to create / delete / edit roles
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Add local role to ESXi
- community.vmware.vmware_local_role_manager:
- hostname: '{{ esxi_hostname }}'
- username: '{{ esxi_username }}'
- password: '{{ esxi_password }}'
- local_role_name: vmware_qa
- state: present
- delegate_to: localhost
-
- - name: Add local role with privileges to vCenter
- community.vmware.vmware_local_role_manager:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- local_role_name: vmware_qa
- local_privilege_ids: [ 'Folder.Create', 'Folder.Delete']
- state: present
- delegate_to: localhost
-
- - name: Remove local role from ESXi
- community.vmware.vmware_local_role_manager:
- hostname: '{{ esxi_hostname }}'
- username: '{{ esxi_username }}'
- password: '{{ esxi_password }}'
- local_role_name: vmware_qa
- state: absent
- delegate_to: localhost
-
- - name: Add a privilege to an existing local role
- community.vmware.vmware_local_role_manager:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- local_role_name: vmware_qa
- local_privilege_ids: [ 'Folder.Create' ]
- action: add
- delegate_to: localhost
-
- - name: Remove a privilege to an existing local role
- community.vmware.vmware_local_role_manager:
- hostname: '{{ esxi_hostname }}'
- username: '{{ esxi_username }}'
- password: '{{ esxi_password }}'
- local_role_name: vmware_qa
- local_privilege_ids: [ 'Folder.Create' ]
- action: remove
- delegate_to: localhost
-
- - name: Set a privilege to an existing local role
- community.vmware.vmware_local_role_manager:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- local_role_name: vmware_qa
- local_privilege_ids: [ 'Folder.Create' ]
- action: set
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>local_role_name</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>Name of local role</div>
- <br/>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>new_privileges</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>List of privileges</div>
- <br/>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>old_privileges</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- </div>
- </td>
- <td>on update</td>
- <td>
- <div>List of privileges of role before the update</div>
- <br/>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>privileges</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>List of privileges</div>
- <br/>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>privileges_previous</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- </div>
- </td>
- <td>on update</td>
- <td>
- <div>List of privileges of role before the update</div>
- <br/>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>role_id</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>Generated local role id</div>
- <br/>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>role_name</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>Name of local role</div>
- <br/>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
-- Christian Kotte (@ckotte)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_local_user_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_local_user_info_module.rst
deleted file mode 100644
index d2123d7bf..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_local_user_info_module.rst
+++ /dev/null
@@ -1,232 +0,0 @@
-.. _community.vmware.vmware_local_user_info_module:
-
-
-***************************************
-community.vmware.vmware_local_user_info
-***************************************
-
-**Gather info about users on the given ESXi host**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to gather information about users present on the given ESXi host system in VMware infrastructure.
-- All variables and VMware object names are case sensitive.
-- User must hold the 'Authorization.ModifyPermissions' privilege to invoke this module.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Gather info about all Users on given ESXi host system
- community.vmware.vmware_local_user_info:
- hostname: '{{ esxi_hostname }}'
- username: '{{ esxi_username }}'
- password: '{{ esxi_password }}'
- delegate_to: localhost
- register: all_user_info
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>local_user_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about all local users</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">[{&#x27;role&#x27;: &#x27;admin&#x27;, &#x27;description&#x27;: &#x27;Administrator&#x27;, &#x27;group&#x27;: False, &#x27;user_id&#x27;: 0, &#x27;user_name&#x27;: &#x27;root&#x27;, &#x27;shell_access&#x27;: True}, {&#x27;role&#x27;: &#x27;admin&#x27;, &#x27;description&#x27;: &#x27;DCUI User&#x27;, &#x27;group&#x27;: False, &#x27;user_id&#x27;: 100, &#x27;user_name&#x27;: &#x27;dcui&#x27;, &#x27;shell_access&#x27;: False}]</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
-- Christian Kotte (@ckotte)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_local_user_manager_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_local_user_manager_module.rst
deleted file mode 100644
index 431e048bc..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_local_user_manager_module.rst
+++ /dev/null
@@ -1,264 +0,0 @@
-.. _community.vmware.vmware_local_user_manager_module:
-
-
-******************************************
-community.vmware.vmware_local_user_manager
-******************************************
-
-**Manage local users on an ESXi host**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- Manage local users on an ESXi host
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>local_user_description</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Description for the user.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>local_user_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The local user name to be changed.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>local_user_password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password to be set.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>Indicate desired state of the user. If the user already exists when <code>state=present</code>, the user info is updated</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - Be sure that the ESXi user used for login, has the appropriate rights to create / delete / edit users
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Add local user to ESXi
- community.vmware.vmware_local_user_manager:
- hostname: esxi_hostname
- username: root
- password: vmware
- local_user_name: foo
- local_user_password: password
- delegate_to: localhost
-
-
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Andreas Nafpliotis (@nafpliot-ibm)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_maintenancemode_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_maintenancemode_module.rst
deleted file mode 100644
index 265dcb808..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_maintenancemode_module.rst
+++ /dev/null
@@ -1,360 +0,0 @@
-.. _community.vmware.vmware_maintenancemode_module:
-
-
-***************************************
-community.vmware.vmware_maintenancemode
-***************************************
-
-**Place a host into maintenance mode**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used for placing a ESXi host into maintenance mode.
-- Support for VSAN compliant maintenance mode when selected.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the host as defined in vCenter.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>evacuate</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>If set to <code>true</code>, evacuate all powered off VMs.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>Enter or exit maintenance mode.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>timeout</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">0</div>
- </td>
- <td>
- <div>Specify a timeout for the operation.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vsan</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>ensureObjectAccessibility</li>
- <li>evacuateAllData</li>
- <li>noAction</li>
- </ul>
- </td>
- <td>
- <div>Specify which VSAN compliant mode to enter.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: vsan_mode</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Enter VSAN-Compliant Maintenance Mode
- community.vmware.vmware_maintenancemode:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- esxi_hostname: "{{ esxi_hostname }}"
- vsan: ensureObjectAccessibility
- evacuate: true
- timeout: 3600
- state: present
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>Name of host in vCenter</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">esxi.local.domain</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>hostsystem</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>Name of vim reference</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">&#x27;vim.HostSystem:host-236&#x27;</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>status</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>Action taken</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">ENTER</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Jay Jahns (@jjahns) <jjahns@vmware.com>
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_migrate_vmk_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_migrate_vmk_module.rst
deleted file mode 100644
index 626a07975..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_migrate_vmk_module.rst
+++ /dev/null
@@ -1,316 +0,0 @@
-.. _community.vmware.vmware_migrate_vmk_module:
-
-
-***********************************
-community.vmware.vmware_migrate_vmk
-***********************************
-
-**Migrate a VMK interface from VSS to VDS**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- Migrate a VMK interface from VSS to VDS
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>current_portgroup_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Portgroup name VMK interface is currently on</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>current_switch_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Switch VMK interface is currently on</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>device</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>VMK interface name</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>ESXi hostname to be managed</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>migrate_portgroup_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Portgroup name to migrate VMK interface to</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>migrate_switch_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Switch name to migrate VMK interface to</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>migrate_vlan_id</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 2.4.0</div>
- </td>
- <td>
- </td>
- <td>
- <div>VLAN to use for the VMK interface when migrating from VDS to VSS</div>
- <div>Will be ignored when migrating from VSS to VDS</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Migrate Management vmk
- community.vmware.vmware_migrate_vmk:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- esxi_hostname: "{{ esxi_hostname }}"
- device: vmk1
- current_switch_name: temp_vswitch
- current_portgroup_name: esx-mgmt
- migrate_switch_name: dvSwitch
- migrate_portgroup_name: Management
- delegate_to: localhost
-
-
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Joseph Callen (@jcpowermac)
-- Russell Teague (@mtnbikenc)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_object_custom_attributes_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_object_custom_attributes_info_module.rst
deleted file mode 100644
index 70cfd1f2b..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_object_custom_attributes_info_module.rst
+++ /dev/null
@@ -1,320 +0,0 @@
-.. _community.vmware.vmware_object_custom_attributes_info_module:
-
-
-*****************************************************
-community.vmware.vmware_object_custom_attributes_info
-*****************************************************
-
-**Gather custom attributes of an object**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be gathered custom attributes of an object.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>moid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Managed Object ID of the instance to get if known, this is a unique identifier only within a single vCenter instance.</div>
- <div>This is required if <code>object_name</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>object_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the object to work with.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: name</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>object_type</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>Datacenter</li>
- <li>Cluster</li>
- <li>HostSystem</li>
- <li>ResourcePool</li>
- <li>Folder</li>
- <li>VirtualMachine</li>
- <li>DistributedVirtualSwitch</li>
- <li>DistributedVirtualPortgroup</li>
- <li>Datastore</li>
- </ul>
- </td>
- <td>
- <div>Type of an object to work with.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - Supports ``check_mode``.
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Gather custom attributes of a virtual machine
- community.vmware.vmware_object_custom_attributes_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- validate_certs: false
- object_type: VirtualMachine
- object_name: "{{ object_name }}"
- register: vm_attributes
-
- - name: Gather custom attributes of a virtual machine with moid
- community.vmware.vmware_object_custom_attributes_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- validate_certs: false
- object_type: VirtualMachine
- moid: "{{ moid }}"
- register: vm_attributes
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>custom_attributes</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>list of custom attributes of an object.</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">[
- {
- &quot;attribute&quot;: &quot;example01&quot;,
- &quot;key&quot;: 132,
- &quot;type&quot;: &quot;VirtualMachine&quot;,
- &quot;value&quot;: &quot;10&quot;
- },
- {
- &quot;attribute&quot;: &quot;example02&quot;,
- &quot;key&quot;: 131,
- &quot;type&quot;: &quot;VirtualMachine&quot;,
- &quot;value&quot;: &quot;20&quot;
- },
- {
- &quot;attribute&quot;: &quot;example03&quot;,
- &quot;key&quot;: 130,
- &quot;type&quot;: &quot;VirtualMachine&quot;,
- &quot;value&quot;: null
- }
- ]</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- sky-joker (@sky-joker)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_object_rename_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_object_rename_module.rst
deleted file mode 100644
index fad6d8a0f..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_object_rename_module.rst
+++ /dev/null
@@ -1,363 +0,0 @@
-.. _community.vmware.vmware_object_rename_module:
-
-
-*************************************
-community.vmware.vmware_object_rename
-*************************************
-
-**Renames VMware objects**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to rename VMware objects.
-- All variables and VMware object names are case sensitive.
-- Renaming Host and Network is not supported by VMware APIs.
-
-
-
-Requirements
-------------
-The below requirements are needed on the host that executes this module.
-
-- vSphere Automation SDK
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>new_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>New name for VMware object.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: object_new_name</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>object_moid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Managed object id of the VMware object to work with.</div>
- <div>Mutually exclusive with <code>object_name</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>object_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the object to work with.</div>
- <div>Mutually exclusive with <code>object_moid</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>object_type</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>ClusterComputeResource</li>
- <li>Cluster</li>
- <li>Datacenter</li>
- <li>Datastore</li>
- <li>Folder</li>
- <li>Network</li>
- <li>ResourcePool</li>
- <li>VM</li>
- <li>VirtualMachine</li>
- </ul>
- </td>
- <td>
- <div>Type of object to work with.</div>
- <div>Valid options are Cluster, ClusterComputeResource, Datacenter, Datastore, Folder, ResourcePool, VM or VirtualMachine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>protocol</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>http</li>
- <li><div style="color: blue"><b>https</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>The connection to protocol.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid.</div>
- <div>Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Rename a virtual machine
- community.vmware.vmware_object_rename:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- new_name: Fedora_31
- object_name: Fedora_VM
- object_type: VirtualMachine
- delegate_to: localhost
-
- - name: Rename a virtual machine using moid
- community.vmware.vmware_object_rename:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- new_name: Fedora_31
- object_moid: vm-14
- object_type: VirtualMachine
- delegate_to: localhost
-
- - name: Rename a datacenter
- community.vmware.vmware_object_rename:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- new_name: Asia_Datacenter
- object_name: dc1
- object_type: Datacenter
- delegate_to: localhost
-
- - name: Rename a folder with moid
- community.vmware.vmware_object_rename:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- new_name: backup
- object_moid: group-v46
- object_type: Folder
- delegate_to: localhost
-
- - name: Rename a cluster with moid
- community.vmware.vmware_object_rename:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- new_name: CCR_1
- object_moid: domain-c33
- object_type: Cluster
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>rename_status</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>on success</td>
- <td>
- <div>metadata about VMware object rename operation</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;current_name&#x27;: &#x27;Fedora_31&#x27;, &#x27;desired_name&#x27;: &#x27;Fedora_31&#x27;, &#x27;previous_name&#x27;: &#x27;Fedora_VM&#x27;}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_object_role_permission_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_object_role_permission_info_module.rst
deleted file mode 100644
index 1343a8493..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_object_role_permission_info_module.rst
+++ /dev/null
@@ -1,320 +0,0 @@
-.. _community.vmware.vmware_object_role_permission_info_module:
-
-
-***************************************************
-community.vmware.vmware_object_role_permission_info
-***************************************************
-
-**Gather information about object's permissions**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to gather object permissions on the given VMware object.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>moid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Managed object ID for the given object.</div>
- <div>Mutually exclusive with <em>object_name</em>.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: object_moid</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>object_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The object name to assigned permission.</div>
- <div>Mutually exclusive with <em>moid</em>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>object_type</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>Folder</b>&nbsp;&larr;</div></li>
- <li>VirtualMachine</li>
- <li>Datacenter</li>
- <li>ResourcePool</li>
- <li>Datastore</li>
- <li>Network</li>
- <li>HostSystem</li>
- <li>ComputeResource</li>
- <li>ClusterComputeResource</li>
- <li>DistributedVirtualSwitch</li>
- <li>DistributedVirtualPortgroup</li>
- <li>StoragePod</li>
- </ul>
- </td>
- <td>
- <div>The object type being targeted.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>principal</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The optional name of an entity, such as a user, assigned permissions on an object.</div>
- <div>If provided, actual permissions on the specified object are returned for the principal, instead of roles.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - The ESXi or vCenter login user must have the appropriate rights to administer permissions.
- - Supports check mode.
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Gather role information about Datastore
- community.vmware.vmware_object_role_permission_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- validate_certs: false
- object_name: ds_200
- object_type: Datastore
-
- - name: Gather permissions on Datastore for a User
- community.vmware.vmware_object_role_permission_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- validate_certs: false
- principal: some.user@company.com
- object_name: ds_200
- object_type: Datastore
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>permission_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>information about object&#x27;s permission</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">[{&#x27;principal&#x27;: &#x27;VSPHERE.LOCAL\\vpxd-extension-12e0b667-892c-4694-8a5e-f13147e45dbd&#x27;, &#x27;propagate&#x27;: True, &#x27;role_id&#x27;: -1, &#x27;role_name&#x27;: &#x27;Admin&#x27;}]</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_object_role_permission_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_object_role_permission_module.rst
deleted file mode 100644
index 0b8f74b91..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_object_role_permission_module.rst
+++ /dev/null
@@ -1,413 +0,0 @@
-.. _community.vmware.vmware_object_role_permission_module:
-
-
-**********************************************
-community.vmware.vmware_object_role_permission
-**********************************************
-
-**Manage local roles on an ESXi host or vCenter**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to manage object permissions on the given host or vCenter.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>group</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The group to be assigned permission.</div>
- <div>Required if <code>principal</code> is not specified.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>object_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The object name to assigned permission.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>object_type</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>Folder</b>&nbsp;&larr;</div></li>
- <li>VirtualMachine</li>
- <li>Datacenter</li>
- <li>ResourcePool</li>
- <li>Datastore</li>
- <li>Network</li>
- <li>HostSystem</li>
- <li>ComputeResource</li>
- <li>ClusterComputeResource</li>
- <li>DistributedVirtualSwitch</li>
- <li>DistributedVirtualPortgroup</li>
- <li>StoragePod</li>
- </ul>
- </td>
- <td>
- <div>The object type being targeted.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>principal</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The user to be assigned permission.</div>
- <div>Required if <code>group</code> is not specified.</div>
- <div>If specifying domain user, required separator of domain uses backslash.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>recursive</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Should the permissions be recursively applied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>role</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The role to be assigned permission.</div>
- <div>User can also specify role name presented in Web UI. Supported added in 1.5.0.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>Indicate desired state of the object&#x27;s permission.</div>
- <div>When <code>state=present</code>, the permission will be added if it doesn&#x27;t already exist.</div>
- <div>When <code>state=absent</code>, the permission is removed if it exists.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - The login user must have the appropriate rights to administer permissions.
- - Permissions for a distributed switch must be defined and managed on either the datacenter or a folder containing the switch.
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Assign user to VM folder
- community.vmware.vmware_object_role_permission:
- hostname: '{{ esxi_hostname }}'
- username: '{{ esxi_username }}'
- password: '{{ esxi_password }}'
- role: Admin
- principal: user_bob
- object_name: services
- state: present
- delegate_to: localhost
-
- - name: Remove user from VM folder
- community.vmware.vmware_object_role_permission:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- role: Admin
- principal: user_bob
- object_name: services
- state: absent
- delegate_to: localhost
-
- - name: Assign finance group to VM folder
- community.vmware.vmware_object_role_permission:
- hostname: '{{ esxi_hostname }}'
- username: '{{ esxi_username }}'
- password: '{{ esxi_password }}'
- role: Limited Users
- group: finance
- object_name: Accounts
- state: present
- delegate_to: localhost
-
- - name: Assign view_user Read Only permission at root folder
- community.vmware.vmware_object_role_permission:
- hostname: '{{ esxi_hostname }}'
- username: '{{ esxi_username }}'
- password: '{{ esxi_password }}'
- role: ReadOnly
- principal: view_user
- object_name: rootFolder
- state: present
- delegate_to: localhost
-
- - name: Assign domain user to VM folder
- community.vmware.vmware_object_role_permission:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- validate_certs: false
- role: Admin
- principal: "vsphere.local\\domainuser"
- object_name: services
- state: present
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>changed</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>whether or not a change was made to the object&#x27;s role</div>
- <br/>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Derek Rushing (@kryptsi)
-- Joseph Andreatta (@vmwjoseph)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_portgroup_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_portgroup_info_module.rst
deleted file mode 100644
index edf3ad7d2..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_portgroup_info_module.rst
+++ /dev/null
@@ -1,291 +0,0 @@
-.. _community.vmware.vmware_portgroup_info_module:
-
-
-**************************************
-community.vmware.vmware_portgroup_info
-**************************************
-
-**Gathers info about an ESXi host's Port Group configuration**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to gather information about an ESXi host's Port Group configuration when ESXi hostname or Cluster name is given.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the cluster.</div>
- <div>Info will be returned for all hostsystem belonging to this cluster name.</div>
- <div>If <code>esxi_hostname</code> is not given, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>ESXi hostname to gather information from.</div>
- <div>If <code>cluster_name</code> is not given, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>policies</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Gather information about Security, Traffic Shaping, as well as Teaming and failover.</div>
- <div>The property <code>ts</code> stands for Traffic Shaping and <code>lb</code> for Load Balancing.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Gather portgroup info about all ESXi Host in given Cluster
- community.vmware.vmware_portgroup_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- cluster_name: '{{ cluster_name }}'
- delegate_to: localhost
-
- - name: Gather portgroup info about ESXi Host system
- community.vmware.vmware_portgroup_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>hosts_portgroup_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>on success</td>
- <td>
- <div>metadata about host&#x27;s portgroup configuration</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;esx01&#x27;: [{&#x27;failback&#x27;: True, &#x27;failover_active&#x27;: [&#x27;vmnic0&#x27;, &#x27;vmnic1&#x27;], &#x27;failover_standby&#x27;: [], &#x27;failure_detection&#x27;: &#x27;link_status_only&#x27;, &#x27;lb&#x27;: &#x27;loadbalance_srcid&#x27;, &#x27;notify&#x27;: True, &#x27;portgroup&#x27;: &#x27;Management Network&#x27;, &#x27;security&#x27;: [False, False, False], &#x27;ts&#x27;: &#x27;No override&#x27;, &#x27;vlan_id&#x27;: 0, &#x27;vswitch&#x27;: &#x27;vSwitch0&#x27;}, {&#x27;failback&#x27;: True, &#x27;failover_active&#x27;: [&#x27;vmnic2&#x27;], &#x27;failover_standby&#x27;: [&#x27;vmnic3&#x27;], &#x27;failure_detection&#x27;: &#x27;No override&#x27;, &#x27;lb&#x27;: &#x27;No override&#x27;, &#x27;notify&#x27;: True, &#x27;portgroup&#x27;: &#x27;vMotion&#x27;, &#x27;security&#x27;: [False, False, False], &#x27;ts&#x27;: &#x27;No override&#x27;, &#x27;vlan_id&#x27;: 33, &#x27;vswitch&#x27;: &#x27;vSwitch1&#x27;}]}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
-- Christian Kotte (@ckotte)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_portgroup_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_portgroup_module.rst
deleted file mode 100644
index cb7e67684..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_portgroup_module.rst
+++ /dev/null
@@ -1,714 +0,0 @@
-.. _community.vmware.vmware_portgroup_module:
-
-
-*********************************
-community.vmware.vmware_portgroup
-*********************************
-
-**Create a VMware portgroup**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- Create a VMware Port Group on a VMware Standard Switch (vSS) for given ESXi host(s) or hosts of given cluster.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="2">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of cluster name for host membership.</div>
- <div>Portgroup will be created on all hosts of the given cluster.</div>
- <div>This option is required if <code>hosts</code> is not specified.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: cluster</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hosts</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>List of name of host or hosts on which portgroup needs to be added.</div>
- <div>This option is required if <code>cluster_name</code> is not specified.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: esxi_hostname</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>portgroup</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Portgroup name to add.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: portgroup_name</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>security</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Network policy specifies layer 2 security settings for a portgroup such as promiscuous mode, where guest adapter listens to all the packets, MAC address changes and forged transmits.</div>
- <div>Dict which configures the different security values for portgroup.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: security_policy, network_policy</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>forged_transmits</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Indicates whether forged transmits are allowed.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>mac_changes</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Indicates whether mac changes are allowed.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>promiscuous_mode</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Indicates whether promiscuous mode is allowed.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>Determines if the portgroup should be present or not.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>switch</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>vSwitch to modify.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: switch_name, vswitch</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>teaming</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Dictionary which configures the different teaming values for portgroup.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: teaming_policy</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>active_adapters</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>List of active adapters used for load balancing.</div>
- <div>All vmnics are used as active adapters if <code>active_adapters</code> and <code>standby_adapters</code> are not defined.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>failback</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Indicate whether or not to use a failback when restoring links.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>load_balancing</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>loadbalance_ip</li>
- <li>loadbalance_srcmac</li>
- <li>loadbalance_srcid</li>
- <li>failover_explicit</li>
- </ul>
- </td>
- <td>
- <div>Network adapter teaming policy.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: load_balance_policy</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>network_failure_detection</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>link_status_only</li>
- <li>beacon_probing</li>
- </ul>
- </td>
- <td>
- <div>Network failure detection.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>notify_switches</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Indicate whether or not to notify the physical switch if a link fails.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>standby_adapters</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>List of standby adapters used for failover.</div>
- <div>All vmnics are used as active adapters if <code>active_adapters</code> and <code>standby_adapters</code> are not defined.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>traffic_shaping</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Dictionary which configures traffic shaping for the switch.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>average_bandwidth</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Average bandwidth (kbit/s).</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>burst_size</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Burst size (KB).</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>enabled</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Status of Traffic Shaping Policy.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>peak_bandwidth</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Peak bandwidth (kbit/s).</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vlan_id</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">0</div>
- </td>
- <td>
- <div>VLAN ID to assign to portgroup.</div>
- <div>Set to 0 (no VLAN tagging) by default.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: vlan</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Add Management Network VM Portgroup
- community.vmware.vmware_portgroup:
- hostname: "{{ esxi_hostname }}"
- username: "{{ esxi_username }}"
- password: "{{ esxi_password }}"
- switch: "{{ vswitch_name }}"
- portgroup: "{{ portgroup_name }}"
- vlan_id: "{{ vlan_id }}"
- delegate_to: localhost
-
- - name: Add Portgroup with Promiscuous Mode Enabled
- community.vmware.vmware_portgroup:
- hostname: "{{ esxi_hostname }}"
- username: "{{ esxi_username }}"
- password: "{{ esxi_password }}"
- switch: "{{ vswitch_name }}"
- portgroup: "{{ portgroup_name }}"
- security:
- promiscuous_mode: true
- delegate_to: localhost
-
- - name: Add Management Network VM Portgroup to specific hosts
- community.vmware.vmware_portgroup:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- hosts: [esxi_hostname_one]
- switch: "{{ vswitch_name }}"
- portgroup: "{{ portgroup_name }}"
- vlan_id: "{{ vlan_id }}"
- delegate_to: localhost
-
- - name: Add Management Network VM Portgroup to all hosts in a cluster
- community.vmware.vmware_portgroup:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- cluster_name: "{{ cluster_name }}"
- switch: "{{ vswitch_name }}"
- portgroup: "{{ portgroup_name }}"
- vlan_id: "{{ vlan_id }}"
- delegate_to: localhost
-
- - name: Remove Management Network VM Portgroup to all hosts in a cluster
- community.vmware.vmware_portgroup:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- cluster_name: "{{ cluster_name }}"
- switch: "{{ vswitch_name }}"
- portgroup: "{{ portgroup_name }}"
- vlan_id: "{{ vlan_id }}"
- state: absent
- delegate_to: localhost
-
- - name: Add Portgroup with all settings defined
- community.vmware.vmware_portgroup:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- esxi_hostname: "{{ inventory_hostname }}"
- switch: "{{ vswitch_name }}"
- portgroup: "{{ portgroup_name }}"
- vlan_id: 10
- security:
- promiscuous_mode: false
- mac_changes: false
- forged_transmits: false
- traffic_shaping:
- enabled: true
- average_bandwidth: 100000
- peak_bandwidth: 100000
- burst_size: 102400
- teaming:
- load_balancing: failover_explicit
- network_failure_detection: link_status_only
- notify_switches: true
- failback: true
- active_adapters:
- - vmnic0
- standby_adapters:
- - vmnic1
- delegate_to: localhost
- register: teaming_result
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>result</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about the portgroup</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;esxi01.example.com&#x27;: {&#x27;changed&#x27;: True, &#x27;failback&#x27;: &#x27;No override&#x27;, &#x27;failover_active&#x27;: &#x27;No override&#x27;, &#x27;failover_standby&#x27;: &#x27;No override&#x27;, &#x27;failure_detection&#x27;: &#x27;No override&#x27;, &#x27;load_balancing&#x27;: &#x27;No override&#x27;, &#x27;msg&#x27;: &#x27;Port Group added&#x27;, &#x27;notify_switches&#x27;: &#x27;No override&#x27;, &#x27;portgroup&#x27;: &#x27;vMotion&#x27;, &#x27;sec_forged_transmits&#x27;: False, &#x27;sec_mac_changes&#x27;: False, &#x27;sec_promiscuous_mode&#x27;: False, &#x27;traffic_shaping&#x27;: &#x27;No override&#x27;, &#x27;vlan_id&#x27;: 33, &#x27;vswitch&#x27;: &#x27;vSwitch1&#x27;}}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Joseph Callen (@jcpowermac)
-- Russell Teague (@mtnbikenc)
-- Abhijeet Kasurde (@Akasurde)
-- Christian Kotte (@ckotte)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_recommended_datastore_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_recommended_datastore_module.rst
deleted file mode 100644
index 441e65b1c..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_recommended_datastore_module.rst
+++ /dev/null
@@ -1,266 +0,0 @@
-.. _community.vmware.vmware_recommended_datastore_module:
-
-
-*********************************************
-community.vmware.vmware_recommended_datastore
-*********************************************
-
-**Returns the recommended datastore from a SDRS-enabled datastore cluster**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module provides the recommended datastore name from a datastore cluster only if the SDRS is enabled for the specified datastore cluster
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the datacenter.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datastore_cluster</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the datastore cluster.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - Supports Check mode.
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Get recommended datastore from a Storage DRS-enabled datastore cluster
- community.vmware.vmware_recommended_datastore:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- validate_certs: false
- datastore_cluster: '{{ datastore_cluster_name }}'
- datacenter: '{{ datacenter }}'
- register: recommended_ds
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>recommended_datastore</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about the recommended datastore</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;recommended_datastore&#x27;: &#x27;datastore-01&#x27;}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Unknown (@MalfuncEddie)
-- Alina Buzachis (@alinabuzachis)
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_resource_pool_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_resource_pool_info_module.rst
deleted file mode 100644
index e7cab3b28..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_resource_pool_info_module.rst
+++ /dev/null
@@ -1,229 +0,0 @@
-.. _community.vmware.vmware_resource_pool_info_module:
-
-
-******************************************
-community.vmware.vmware_resource_pool_info
-******************************************
-
-**Gathers info about resource pool information**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to gather information about all resource configuration information.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Gather resource pool info about all resource pools available
- community.vmware.vmware_resource_pool_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- register: rp_info
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>resource_pool_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- </div>
- </td>
- <td>on success</td>
- <td>
- <div>metadata about resource pool configuration</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">[{&#x27;cpu_allocation_expandable_reservation&#x27;: False, &#x27;cpu_allocation_limit&#x27;: 4121, &#x27;cpu_allocation_overhead_limit&#x27;: None, &#x27;cpu_allocation_reservation&#x27;: 4121, &#x27;cpu_allocation_shares&#x27;: 9000, &#x27;cpu_allocation_shares_level&#x27;: &#x27;custom&#x27;, &#x27;mem_allocation_expandable_reservation&#x27;: False, &#x27;mem_allocation_limit&#x27;: 961, &#x27;mem_allocation_overhead_limit&#x27;: None, &#x27;mem_allocation_reservation&#x27;: 961, &#x27;mem_allocation_shares&#x27;: 9000, &#x27;mem_allocation_shares_level&#x27;: &#x27;custom&#x27;, &#x27;name&#x27;: &#x27;Resources&#x27;, &#x27;overall_status&#x27;: &#x27;green&#x27;, &#x27;owner&#x27;: &#x27;DC0_H0&#x27;, &#x27;runtime_cpu_max_usage&#x27;: 4121, &#x27;runtime_cpu_overall_usage&#x27;: 0, &#x27;runtime_cpu_reservation_used&#x27;: 0, &#x27;runtime_cpu_reservation_used_vm&#x27;: 0, &#x27;runtime_cpu_unreserved_for_pool&#x27;: 4121, &#x27;runtime_cpu_unreserved_for_vm&#x27;: 4121, &#x27;runtime_memory_max_usage&#x27;: 1007681536, &#x27;runtime_memory_overall_usage&#x27;: 0, &#x27;runtime_memory_reservation_used&#x27;: 0, &#x27;runtime_memory_reservation_used_vm&#x27;: 0, &#x27;runtime_memory_unreserved_for_pool&#x27;: 1007681536, &#x27;runtime_memory_unreserved_for_vm&#x27;: 1007681536}]</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_resource_pool_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_resource_pool_module.rst
deleted file mode 100644
index 11748a5fc..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_resource_pool_module.rst
+++ /dev/null
@@ -1,571 +0,0 @@
-.. _community.vmware.vmware_resource_pool_module:
-
-
-*************************************
-community.vmware.vmware_resource_pool
-*************************************
-
-**Add/remove resource pools to/from vCenter**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to add/remove a resource pool to/from vCenter
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the cluster to configure the resource pool.</div>
- <div>This parameter is required if <code>esxi_hostname</code> or <code>parent_resource_pool</code> is not specified.</div>
- <div>The <code>cluster</code>, <code>esxi_hostname</code> and <code>parent_resource_pool</code> parameters are mutually exclusive.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cpu_allocation_shares</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">4000</div>
- </td>
- <td>
- <div>The number of cpu shares allocated.</div>
- <div>This value is only set if <em>cpu_shares</em> is set to <code>custom</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cpu_expandable_reservations</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>In a resource pool with an expandable reservation, the reservation on a resource pool can grow beyond the specified value.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cpu_limit</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">-1</div>
- </td>
- <td>
- <div>The utilization of a virtual machine/resource pool will not exceed this limit, even if there are available resources.</div>
- <div>The default value -1 indicates no limit.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cpu_reservation</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">0</div>
- </td>
- <td>
- <div>Amount of resource that is guaranteed available to the virtual machine or resource pool.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cpu_shares</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>high</li>
- <li>custom</li>
- <li>low</li>
- <li><div style="color: blue"><b>normal</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Memory shares are used in case of resource contention.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the datacenter.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the host to configure the resource pool.</div>
- <div>The host must not be member of a cluster.</div>
- <div>This parameter is required if <code>cluster</code> or <code>parent_resource_pool</code> is not specified.</div>
- <div>The <code>cluster</code>, <code>esxi_hostname</code> and <code>parent_resource_pool</code> parameters are mutually exclusive.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>mem_allocation_shares</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">163840</div>
- </td>
- <td>
- <div>The number of memory shares allocated.</div>
- <div>This value is only set if <em>mem_shares</em> is set to <code>custom</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>mem_expandable_reservations</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>In a resource pool with an expandable reservation, the reservation on a resource pool can grow beyond the specified value.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>mem_limit</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">-1</div>
- </td>
- <td>
- <div>The utilization of a virtual machine/resource pool will not exceed this limit, even if there are available resources.</div>
- <div>The default value -1 indicates no limit.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>mem_reservation</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">0</div>
- </td>
- <td>
- <div>Amount of resource that is guaranteed available to the virtual machine or resource pool.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>mem_shares</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>high</li>
- <li>custom</li>
- <li>low</li>
- <li><div style="color: blue"><b>normal</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Memory shares are used in case of resource contention.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>parent_resource_pool</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the parent resource pool.</div>
- <div>This parameter is required if <code>cluster</code> or <code>esxi_hostname</code> is not specified.</div>
- <div>The <code>cluster</code>, <code>esxi_hostname</code> and <code>parent_resource_pool</code> parameters are mutually exclusive.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>resource_pool</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Resource pool name to manage.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>Add or remove the resource pool</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Add resource pool to vCenter
- community.vmware.vmware_resource_pool:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter: '{{ datacenter_name }}'
- cluster: '{{ cluster_name }}'
- resource_pool: '{{ resource_pool_name }}'
- mem_shares: normal
- mem_limit: -1
- mem_reservation: 0
- mem_expandable_reservations: true
- cpu_shares: normal
- cpu_limit: -1
- cpu_reservation: 0
- cpu_expandable_reservations: true
- state: present
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>instance</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about the new resource pool</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">None</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>resource_pool_config</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>config data about the resource pool, version added 1.4.0</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{
- &quot;_vimtype&quot;: &quot;vim.ResourceConfigSpec&quot;,
- &quot;changeVersion&quot;: null,
- &quot;cpuAllocation&quot;: {
- &quot;_vimtype&quot;: &quot;vim.ResourceAllocationInfo&quot;,
- &quot;expandableReservation&quot;: true,
- &quot;limit&quot;: -1,
- &quot;overheadLimit&quot;: null,
- &quot;reservation&quot;: 0,
- &quot;shares&quot;: {
- &quot;_vimtype&quot;: &quot;vim.SharesInfo&quot;,
- &quot;level&quot;: &quot;normal&quot;,
- &quot;shares&quot;: 4000
- }
- },
- &quot;entity&quot;: &quot;vim.ResourcePool:resgroup-1108&quot;,
- &quot;lastModified&quot;: null,
- &quot;memoryAllocation&quot;: {
- &quot;_vimtype&quot;: &quot;vim.ResourceAllocationInfo&quot;,
- &quot;expandableReservation&quot;: true,
- &quot;limit&quot;: -1,
- &quot;overheadLimit&quot;: null,
- &quot;reservation&quot;: 0,
- &quot;shares&quot;: {
- &quot;_vimtype&quot;: &quot;vim.SharesInfo&quot;,
- &quot;level&quot;: &quot;high&quot;,
- &quot;shares&quot;: 327680
- }
- },
- &quot;name&quot;: &quot;test_pr1&quot;,
- &quot;scaleDescendantsShares&quot;: null
- }</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Davis Phillips (@dav1x)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_tag_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_tag_info_module.rst
deleted file mode 100644
index aaeaa9563..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_tag_info_module.rst
+++ /dev/null
@@ -1,284 +0,0 @@
-.. _community.vmware.vmware_tag_info_module:
-
-
-********************************
-community.vmware.vmware_tag_info
-********************************
-
-**Manage VMware tag info**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to collect information about VMware tags.
-- Tag feature is introduced in vSphere 6 version, so this module is not supported in the earlier versions of vSphere.
-- All variables and VMware object names are case sensitive.
-
-
-
-Requirements
-------------
-The below requirements are needed on the host that executes this module.
-
-- vSphere Automation SDK
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>protocol</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>http</li>
- <li><div style="color: blue"><b>https</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>The connection to protocol.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid.</div>
- <div>Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Get info about tag
- community.vmware.vmware_tag_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- delegate_to: localhost
-
- - name: Get category id from the given tag
- community.vmware.vmware_tag_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- delegate_to: localhost
- register: tag_details
- - debug:
- msg: "{{ tag_details.tag_facts['fedora_machines']['tag_category_id'] }}"
-
- - name: Gather tag id from the given tag
- community.vmware.vmware_tag_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- delegate_to: localhost
- register: tag_results
- - set_fact:
- tag_id: "{{ item.tag_id }}"
- loop: "{{ tag_results.tag_info|json_query(query) }}"
- vars:
- query: "[?tag_name==`tag0001`]"
- - debug: var=tag_id
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>tag_facts</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>on success</td>
- <td>
- <div>dictionary of tag metadata</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;Sample_Tag_0002&#x27;: {&#x27;tag_category_id&#x27;: &#x27;urn:vmomi:InventoryServiceCategory:6de17f28-7694-43ec-a783-d09c141819ae:GLOBAL&#x27;, &#x27;tag_description&#x27;: &#x27;Sample Description&#x27;, &#x27;tag_id&#x27;: &#x27;urn:vmomi:InventoryServiceTag:a141f212-0f82-4f05-8eb3-c49647c904c5:GLOBAL&#x27;, &#x27;tag_used_by&#x27;: []}, &#x27;fedora_machines&#x27;: {&#x27;tag_category_id&#x27;: &#x27;urn:vmomi:InventoryServiceCategory:baa90bae-951b-4e87-af8c-be681a1ba30c:GLOBAL&#x27;, &#x27;tag_description&#x27;: &#x27;&#x27;, &#x27;tag_id&#x27;: &#x27;urn:vmomi:InventoryServiceTag:7d27d182-3ecd-4200-9d72-410cc6398a8a:GLOBAL&#x27;, &#x27;tag_used_by&#x27;: []}, &#x27;ubuntu_machines&#x27;: {&#x27;tag_category_id&#x27;: &#x27;urn:vmomi:InventoryServiceCategory:89573410-29b4-4cac-87a4-127c084f3d50:GLOBAL&#x27;, &#x27;tag_description&#x27;: &#x27;&#x27;, &#x27;tag_id&#x27;: &#x27;urn:vmomi:InventoryServiceTag:7f3516d5-a750-4cb9-8610-6747eb39965d:GLOBAL&#x27;, &#x27;tag_used_by&#x27;: []}}</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>tag_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- </div>
- </td>
- <td>on success</td>
- <td>
- <div>list of tag metadata</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">[{&#x27;tag_name&#x27;: &#x27;Sample_Tag_0002&#x27;, &#x27;tag_category_id&#x27;: &#x27;urn:vmomi:InventoryServiceCategory:6de17f28-7694-43ec-a783-d09c141819ae:GLOBAL&#x27;, &#x27;tag_description&#x27;: &#x27;Sample Description&#x27;, &#x27;tag_id&#x27;: &#x27;urn:vmomi:InventoryServiceTag:a141f212-0f82-4f05-8eb3-c49647c904c5:GLOBAL&#x27;, &#x27;tag_used_by&#x27;: []}, {&#x27;tag_name&#x27;: &#x27;Sample_Tag_0002&#x27;, &#x27;tag_category_id&#x27;: &#x27;urn:vmomi:InventoryServiceCategory:6de17f28-7694-43ec-a783-d09c141819ae:GLOBAL&#x27;, &#x27;tag_description&#x27;: &#x27;&#x27;, &#x27;tag_id&#x27;: &#x27;urn:vmomi:InventoryServiceTag:7d27d182-3ecd-4200-9d72-410cc6398a8a:GLOBAL&#x27;, &#x27;tag_used_by&#x27;: []}, {&#x27;tag_name&#x27;: &#x27;ubuntu_machines&#x27;, &#x27;tag_category_id&#x27;: &#x27;urn:vmomi:InventoryServiceCategory:89573410-29b4-4cac-87a4-127c084f3d50:GLOBAL&#x27;, &#x27;tag_description&#x27;: &#x27;&#x27;, &#x27;tag_id&#x27;: &#x27;urn:vmomi:InventoryServiceTag:7f3516d5-a750-4cb9-8610-6747eb39965d:GLOBAL&#x27;, &#x27;tag_used_by&#x27;: []}]</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_tag_manager_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_tag_manager_module.rst
deleted file mode 100644
index fef1a255f..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_tag_manager_module.rst
+++ /dev/null
@@ -1,430 +0,0 @@
-.. _community.vmware.vmware_tag_manager_module:
-
-
-***********************************
-community.vmware.vmware_tag_manager
-***********************************
-
-**Manage association of VMware tags with VMware objects**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to assign / remove VMware tags from the given VMware objects.
-- Tag feature is introduced in vSphere 6 version, so this module is not supported in the earlier versions of vSphere.
-- All variables and VMware object names are case sensitive.
-
-
-
-Requirements
-------------
-The below requirements are needed on the host that executes this module.
-
-- vSphere Automation SDK
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>moid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Managed object ID for the given object.</div>
- <div>Required if <code>object_name</code> is not set.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>object_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the object to work with.</div>
- <div>For DistributedVirtualPortgroups the format should be &quot;switch_name:portgroup_name&quot;</div>
- <div>Required if <code>moid</code> is not set.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>object_type</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>VirtualMachine</li>
- <li>Datacenter</li>
- <li>ClusterComputeResource</li>
- <li>HostSystem</li>
- <li>DistributedVirtualSwitch</li>
- <li>DistributedVirtualPortgroup</li>
- <li>Datastore</li>
- <li>DatastoreCluster</li>
- <li>ResourcePool</li>
- <li>Folder</li>
- </ul>
- </td>
- <td>
- <div>Type of object to work with.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>protocol</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>http</li>
- <li><div style="color: blue"><b>https</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>The connection to protocol.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>present</li>
- <li>absent</li>
- <li><div style="color: blue"><b>add</b>&nbsp;&larr;</div></li>
- <li>remove</li>
- <li>set</li>
- </ul>
- </td>
- <td>
- <div>If <code>state</code> is set to <code>add</code> or <code>present</code> will add the tags to the existing tag list of the given object.</div>
- <div>If <code>state</code> is set to <code>remove</code> or <code>absent</code> will remove the tags from the existing tag list of the given object.</div>
- <div>If <code>state</code> is set to <code>set</code> will replace the tags of the given objects with the user defined list of tags.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>tag_names</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=raw</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>List of tag(s) to be managed.</div>
- <div>User can also specify category name by specifying colon separated value. For example, &quot;category_name:tag_name&quot;.</div>
- <div>User can also specify tag and category as dict, when tag or category contains colon. See example for more information. Added in version 2.10.</div>
- <div>User can skip category name if you have unique tag names.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid.</div>
- <div>Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Add tags to a virtual machine
- community.vmware.vmware_tag_manager:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- tag_names:
- - Sample_Tag_0002
- - Category_0001:Sample_Tag_0003
- object_name: Fedora_VM
- object_type: VirtualMachine
- state: add
- delegate_to: localhost
-
- - name: Specify tag and category as dict
- community.vmware.vmware_tag_manager:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- tag_names:
- - tag: tag_0001
- category: cat_0001
- - tag: tag_0002
- category: cat_0002
- object_name: Fedora_VM
- object_type: VirtualMachine
- state: add
- delegate_to: localhost
-
- - name: Remove a tag from a virtual machine
- community.vmware.vmware_tag_manager:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- tag_names:
- - Sample_Tag_0002
- object_name: Fedora_VM
- object_type: VirtualMachine
- state: remove
- delegate_to: localhost
-
- - name: Add tags to a distributed virtual switch
- community.vmware.vmware_tag_manager:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- tag_names:
- - Sample_Tag_0003
- object_name: Switch_0001
- object_type: DistributedVirtualSwitch
- state: add
- delegate_to: localhost
-
- - name: Add tags to a distributed virtual portgroup
- community.vmware.vmware_tag_manager:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- tag_names:
- - Sample_Tag_0004
- object_name: Switch_0001:Portgroup_0001
- object_type: DistributedVirtualPortgroup
- state: add
- delegate_to: localhost
-
-
- - name: Get information about folders
- community.vmware.vmware_folder_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- datacenter: 'Asia-Datacenter1'
- delegate_to: localhost
- register: r
- - name: Set Managed object ID for the given folder
- ansible.builtin.set_fact:
- folder_mo_id: "{{ (r.flat_folder_info | selectattr('path', 'equalto', '/Asia-Datacenter1/vm/tier1/tier2') | map(attribute='moid'))[0] }}"
- - name: Add tags to a Folder using managed object id
- community.vmware.vmware_tag_manager:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- tag_names:
- - Sample_Cat_0004:Sample_Tag_0004
- object_type: Folder
- moid: "{{ folder_mo_id }}"
- state: add
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>tag_status</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- </div>
- </td>
- <td>on success</td>
- <td>
- <div>metadata about tags related to object configuration</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;attached_tags&#x27;: [&#x27;urn:vmomi:InventoryServiceCategory:76f69e84-f6b9-4e64-954c-fac545d2c0ba:GLOBAL:security&#x27;], &#x27;current_tags&#x27;: [&#x27;urn:vmomi:InventoryServiceCategory:927f5ff8-62e6-4364-bc94-23e3bfd7dee7:GLOBAL:backup&#x27;, &#x27;urn:vmomi:InventoryServiceCategory:76f69e84-f6b9-4e64-954c-fac545d2c0ba:GLOBAL:security&#x27;], &#x27;detached_tags&#x27;: [], &#x27;previous_tags&#x27;: [&#x27;urn:vmomi:InventoryServiceCategory:927f5ff8-62e6-4364-bc94-23e3bfd7dee7:GLOBAL:backup&#x27;]}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
-- Frederic Van Reet (@GBrawl)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_tag_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_tag_module.rst
deleted file mode 100644
index 85307aa9f..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_tag_module.rst
+++ /dev/null
@@ -1,361 +0,0 @@
-.. _community.vmware.vmware_tag_module:
-
-
-***************************
-community.vmware.vmware_tag
-***************************
-
-**Manage VMware tags**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to create / delete / update VMware tags.
-- Tag feature is introduced in vSphere 6 version, so this module is not supported in the earlier versions of vSphere.
-- All variables and VMware object names are case sensitive.
-
-
-
-Requirements
-------------
-The below requirements are needed on the host that executes this module.
-
-- vSphere Automation SDK
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>category_id</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The unique ID generated by vCenter should be used to.</div>
- <div>User can get this unique ID from facts module.</div>
- <div>Required if <code>category_name</code> is not set.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>category_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 3.5.0</div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of category.</div>
- <div>Required if <code>category_id</code> is not set.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: category</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>protocol</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>http</li>
- <li><div style="color: blue"><b>https</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>The connection to protocol.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>The state of tag.</div>
- <div>If set to <code>present</code> and tag does not exists, then tag is created.</div>
- <div>If set to <code>present</code> and tag exists, then tag is updated.</div>
- <div>If set to <code>absent</code> and tag exists, then tag is deleted.</div>
- <div>If set to <code>absent</code> and tag does not exists, no action is taken.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>tag_description</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">""</div>
- </td>
- <td>
- <div>The tag description.</div>
- <div>This is required only if <code>state</code> is set to <code>present</code>.</div>
- <div>This parameter is ignored, when <code>state</code> is set to <code>absent</code>.</div>
- <div>Process of updating tag only allows description change.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: description</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>tag_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of tag to manage.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: tag, name</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid.</div>
- <div>Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Create a tag
- community.vmware.vmware_tag:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- category_id: 'urn:vmomi:InventoryServiceCategory:e785088d-6981-4b1c-9fb8-1100c3e1f742:GLOBAL'
- tag_name: Sample_Tag_0002
- tag_description: Sample Description
- state: present
- delegate_to: localhost
-
- - name: Update tag description
- community.vmware.vmware_tag:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- tag_name: Sample_Tag_0002
- tag_description: Some fancy description
- state: present
- delegate_to: localhost
-
- - name: Delete tag
- community.vmware.vmware_tag:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- tag_name: Sample_Tag_0002
- state: absent
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>tag_status</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>on success</td>
- <td>
- <div>dictionary of tag metadata</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;msg&#x27;: &quot;Tag &#x27;Sample_Tag_0002&#x27; created.&quot;, &#x27;tag_id&#x27;: &#x27;urn:vmomi:InventoryServiceTag:bff91819-f529-43c9-80ca-1c9dfda09441:GLOBAL&#x27;}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_target_canonical_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_target_canonical_info_module.rst
deleted file mode 100644
index 326bdbb74..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_target_canonical_info_module.rst
+++ /dev/null
@@ -1,314 +0,0 @@
-.. _community.vmware.vmware_target_canonical_info_module:
-
-
-*********************************************
-community.vmware.vmware_target_canonical_info
-*********************************************
-
-**Return canonical (NAA) from an ESXi host system**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to gather information about canonical (NAA) from an ESXi host based on SCSI target ID.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the cluster.</div>
- <div>Info about all SCSI devices for all host system in the given cluster is returned.</div>
- <div>This parameter is required, if <code>esxi_hostname</code> is not provided.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the ESXi host system.</div>
- <div>Info about all SCSI devices for the given ESXi host system is returned.</div>
- <div>This parameter is required, if <code>cluster_name</code> is not provided.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>target_id</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The target id based on order of scsi device.</div>
- <div>version 2.6 onwards, this parameter is optional.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Get Canonical name of particular target on particular ESXi host system
- community.vmware.vmware_target_canonical_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- target_id: 7
- esxi_hostname: esxi_hostname
- delegate_to: localhost
-
- - name: Get Canonical name of all target on particular ESXi host system
- community.vmware.vmware_target_canonical_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- delegate_to: localhost
-
- - name: Get Canonical name of all ESXi hostname on particular Cluster
- community.vmware.vmware_target_canonical_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- cluster_name: '{{ cluster_name }}'
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>canonical</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>if host system and target id is given</td>
- <td>
- <div>metadata about SCSI Target device</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">mpx.vmhba0:C0:T0:L0</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>scsi_tgt_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>if host system or cluster is given</td>
- <td>
- <div>metadata about all SCSI Target devices</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;DC0_C0_H0&#x27;: {&#x27;scsilun_canonical&#x27;: {&#x27;key-vim.host.ScsiDisk-0000000000766d686261303a303a30&#x27;: &#x27;mpx.vmhba0:C0:T0:L0&#x27;, &#x27;key-vim.host.ScsiLun-0005000000766d686261313a303a30&#x27;: &#x27;mpx.vmhba1:C0:T0:L0&#x27;}, &#x27;target_lun_uuid&#x27;: {&#x27;0&#x27;: &#x27;key-vim.host.ScsiDisk-0000000000766d686261303a303a30&#x27;}}, &#x27;DC0_C0_H1&#x27;: {&#x27;scsilun_canonical&#x27;: {&#x27;key-vim.host.ScsiDisk-0000000000766d686261303a303a30&#x27;: &#x27;mpx.vmhba0:C0:T0:L0&#x27;, &#x27;key-vim.host.ScsiLun-0005000000766d686261313a303a30&#x27;: &#x27;mpx.vmhba1:C0:T0:L0&#x27;}, &#x27;target_lun_uuid&#x27;: {&#x27;0&#x27;: &#x27;key-vim.host.ScsiDisk-0000000000766d686261303a303a30&#x27;}}}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Joseph Callen (@jcpowermac)
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_tools_connection.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_tools_connection.rst
deleted file mode 100644
index 80e6cd333..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_tools_connection.rst
+++ /dev/null
@@ -1,326 +0,0 @@
-.. _community.vmware.vmware_tools_connection:
-
-
-*****************************
-community.vmware.vmware_tools
-*****************************
-
-**Execute tasks inside a VM via VMware Tools**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- Use VMware tools to run tasks in, or put/fetch files to guest operating systems running in VMware infrastructure.
-- In case of Windows VMs, set ``ansible_shell_type`` to ``powershell``.
-- Does not work with 'become'.
-
-
-
-Requirements
-------------
-The below requirements are needed on the local Ansible controller node that executes this connection.
-
-- requests (Python library)
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th>Configuration</th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>exec_command_sleep_interval</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">float</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">0.5</div>
- </td>
- <td>
- <div>var: ansible_vmware_tools_exec_command_sleep_interval</div>
- </td>
- <td>
- <div>Time in seconds to sleep between execution of command.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>executable</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">-</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">"/bin/sh"</div>
- </td>
- <td>
- <div> ini entries:
- <p>[defaults]<br>executable = /bin/sh</p>
- </div>
- <div>env:ANSIBLE_EXECUTABLE</div>
- <div>var: ansible_executable</div>
- <div>var: ansible_vmware_tools_executable</div>
- </td>
- <td>
- <div>shell to use for execution inside container</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>file_chunk_size</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">128</div>
- </td>
- <td>
- <div>var: ansible_vmware_tools_file_chunk_size</div>
- </td>
- <td>
- <div>File chunk size.</div>
- <div>(Applicable when writing a file to disk, example: using the <code>fetch</code> module.)</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>env:VMWARE_VALIDATE_CERTS</div>
- <div>var: ansible_vmware_validate_certs</div>
- </td>
- <td>
- <div>Verify SSL for the connection.</div>
- <div>Note: This will validate certs for both <code>vmware_host</code> and the ESXi host running the VM.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vm_password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">-</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>var: ansible_password</div>
- <div>var: ansible_vmware_tools_password</div>
- </td>
- <td>
- <div>Password for the user in guest operating system.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vm_path</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">-</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>var: ansible_vmware_guest_path</div>
- </td>
- <td>
- <div>Mutually exclusive with vm_uuid</div>
- <div>VM path absolute to the connection.</div>
- <div>vCenter Example: <code>Datacenter/vm/Discovered virtual machine/testVM</code>.</div>
- <div>ESXi Host Example: <code>ha-datacenter/vm/testVM</code>.</div>
- <div>Must include VM name, appended to &#x27;folder&#x27; as would be passed to <span class='module'>community.vmware.vmware_guest</span>.</div>
- <div>Needs to include <em>vm</em> between the Datacenter and the rest of the VM path.</div>
- <div>Datacenter default value for ESXi server is <code>ha-datacenter</code>.</div>
- <div>Folder <em>vm</em> is not visible in the vSphere Web Client but necessary for VMware API to work.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vm_user</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">-</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>var: ansible_user</div>
- <div>var: ansible_vmware_tools_user</div>
- </td>
- <td>
- <div>VM username.</div>
- <div><code>ansible_vmware_tools_user</code> is used for connecting to the VM.</div>
- <div><code>ansible_user</code> is used by Ansible on the VM.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vm_uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">-</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>var: ansible_vmware_guest_uuid</div>
- </td>
- <td>
- <div>Mutually exclusive with vm_path</div>
- <div>VM UUID to the connection.</div>
- <div>UUID of the virtual machine from property config.uuid of vmware_vm_inventory plugin</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vmware_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">-</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>env:VI_SERVER</div>
- <div>env:VMWARE_HOST</div>
- <div>var: ansible_host</div>
- <div>var: ansible_vmware_host</div>
- </td>
- <td>
- <div>FQDN or IP Address for the connection (vCenter or ESXi Host).</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vmware_password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">-</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>env:VI_PASSWORD</div>
- <div>env:VMWARE_PASSWORD</div>
- <div>var: ansible_vmware_password</div>
- </td>
- <td>
- <div>Password for the connection.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vmware_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">-</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>env:VI_PORTNUMBER</div>
- <div>env:VMWARE_PORT</div>
- <div>var: ansible_port</div>
- <div>var: ansible_vmware_port</div>
- </td>
- <td>
- <div>Port for the connection.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vmware_user</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">-</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>env:VI_USERNAME</div>
- <div>env:VMWARE_USER</div>
- <div>var: ansible_vmware_user</div>
- </td>
- <td>
- <div>Username for the connection.</div>
- <div>Requires the following permissions on the VM: - VirtualMachine.GuestOperations.Execute - VirtualMachine.GuestOperations.Modify - VirtualMachine.GuestOperations.Query</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-
-
-
-
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Deric Crago (@dericcrago) <deric.crago@gmail.com>
-
-
-.. hint::
- Configuration entries for each entry type have a low to high priority order. For example, a variable that is lower in the list will override a variable that is higher up.
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_vc_infraprofile_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_vc_infraprofile_info_module.rst
deleted file mode 100644
index df6801e22..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_vc_infraprofile_info_module.rst
+++ /dev/null
@@ -1,420 +0,0 @@
-.. _community.vmware.vmware_vc_infraprofile_info_module:
-
-
-********************************************
-community.vmware.vmware_vc_infraprofile_info
-********************************************
-
-**List and Export VMware vCenter infra profile configs.**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- Module to manage VMware vCenter infra profile configs.
-- vCenter infra profile Library feature is introduced in vSphere 7.0 version, so this module is not supported in the earlier versions of vSphere.
-- All variables and VMware object names are case sensitive.
-
-
-
-Requirements
-------------
-The below requirements are needed on the host that executes this module.
-
-- vSphere Automation SDK
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>api</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>export</li>
- <li>import</li>
- <li>list</li>
- <li>validate</li>
- </ul>
- </td>
- <td>
- <div>API which needs to be executed</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>config_path</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Config file path which contains infra profile config JSON data, supports both relative and absolute path.</div>
- <div>This parameter is required only when <code>import</code>,<code>validate</code> APIs are being used.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>decryption_key</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>decryption_key argument for while doing import profile task as of now its not taken into account form API team.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>description</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Description of about encryption or decryption key.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>encryption_key</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>encryption_key argument for while doing import profile task as of now its not taken into account form API team.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>profiles</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>A list of profile names to be exported, imported, and validated.</div>
- <div>This parameter is not required while running for List API, not for <code>export</code>,<code>import</code> and <code>validate</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>protocol</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>http</li>
- <li><div style="color: blue"><b>https</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>The connection to protocol.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid.</div>
- <div>Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Get information about VC infraprofile
- vmware_vc_infraprofile_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- delegate_to: localhost
-
- - name: export vCenter appliance infra profile config
- vmware_vc_infraprofile_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- api: "export"
- profiles: "ApplianceManagement"
- delegate_to: localhost
-
- - name: validate vCenter appliance infra profile config
- vmware_vc_infraprofile_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- api: "validate"
- profiles: "ApplianceManagement"
- config_path: "export.json"
-
- - name: import vCenter appliance infra profile config
- vmware_vc_infraprofile_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- api: "import"
- profiles: "ApplianceManagement"
- config_path: "import.json"
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>export_infra</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>On success with API set as &quot;export&quot;</td>
- <td>
- <div>A message about the exported file</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;export_config_json&#x27;: &#x27;json exported to file&#x27;}</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>import_profile</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>On success with API set as &quot;import&quot;</td>
- <td>
- <div>A message about import on import_profile spec</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;changed&#x27;: True, &#x27;failed&#x27;: False, &#x27;status&#x27;: &#x27;0.0&#x27;}</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>list_infra</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- </div>
- </td>
- <td>on success with API as &quot;list&quot;</td>
- <td>
- <div>A list of infra configs,</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">[{&#x27;info&#x27;: &#x27;ApplianceManagement&#x27;, &#x27;name&#x27;: &#x27;ApplianceManagement&#x27;}, {&#x27;info&#x27;: &#x27;ApplianceNetwork&#x27;, &#x27;name&#x27;: &#x27;ApplianceNetwork&#x27;}, {&#x27;info&#x27;: &#x27;Authentication &amp; Authorization Management&#x27;, &#x27;name&#x27;: &#x27;AuthManagement&#x27;}]</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>validate_infra</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>On success with API set as &quot;validate&quot;</td>
- <td>
- <div>A message about validate on exported file</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;changed&#x27;: False, &#x27;failed&#x27;: False, &#x27;status&#x27;: &#x27;VALID&#x27;}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Naveenkumar G P (@ngp)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_vcenter_settings_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_vcenter_settings_info_module.rst
deleted file mode 100644
index 07f202253..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_vcenter_settings_info_module.rst
+++ /dev/null
@@ -1,315 +0,0 @@
-.. _community.vmware.vmware_vcenter_settings_info_module:
-
-
-*********************************************
-community.vmware.vmware_vcenter_settings_info
-*********************************************
-
-**Gather info vCenter settings**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to gather information about vCenter settings.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>properties</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Specify the properties to retrieve.</div>
- <div>Example:</div>
- <div>properties: [</div>
- <div>&quot;config.workflow.port&quot;</div>
- <div>]</div>
- <div>Only valid when <code>schema</code> is <code>vsphere</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>schema</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>summary</b>&nbsp;&larr;</div></li>
- <li>vsphere</li>
- </ul>
- </td>
- <td>
- <div>Specify the output schema desired.</div>
- <div>The &#x27;summary&#x27; output schema is the legacy output from the module.</div>
- <div>The &#x27;vsphere&#x27; output schema is the vSphere API class definition which requires pyvmomi&gt;6.7.1.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: "Gather info about vCenter settings"
- community.vmware.vmware_vcenter_settings_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- register: vcenter_settings_info
-
- - name: "Gather some info from vCenter using the vSphere API output schema"
- community.vmware.vmware_vcenter_settings_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- schema: vsphere
- properties:
- - config.workflow.port
- register: vcenter_settings_info_vsphere_api
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>vcenter_config_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>success</td>
- <td>
- <div>dict of vCenter settings</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{
- &quot;db_event_cleanup_previous&quot;: true,
- &quot;db_event_retention_previous&quot;: 30,
- &quot;db_max_connections_previous&quot;: 50,
- &quot;db_task_cleanup_previous&quot;: true,
- &quot;db_task_retention_previous&quot;: 30,
- &quot;directory_query_limit_previous&quot;: true,
- &quot;directory_query_limit_size_previous&quot;: 5000,
- &quot;directory_timeout_previous&quot;: 60,
- &quot;directory_validation_period_previous&quot;: 1440,
- &quot;directory_validation_previous&quot;: true,
- &quot;logging_options_previous&quot;: &quot;info&quot;,
- &quot;mail_sender_previous&quot;: &quot;&quot;,
- &quot;mail_server_previous&quot;: &quot;&quot;,
- &quot;runtime_managed_address_previous&quot;: &quot;&quot;,
- &quot;runtime_server_name_previous&quot;: &quot;vcenter.local&quot;,
- &quot;runtime_unique_id_previous&quot;: 48,
- &quot;snmp_1_community_previous&quot;: &quot;public&quot;,
- &quot;snmp_1_enabled_previous&quot;: true,
- &quot;snmp_1_url_previous&quot;: &quot;localhost&quot;,
- &quot;snmp_2_community_previous&quot;: &quot;&quot;,
- &quot;snmp_2_enabled_previous&quot;: false,
- &quot;snmp_2_url_previous&quot;: &quot;&quot;,
- &quot;snmp_3_community_previous&quot;: &quot;&quot;,
- &quot;snmp_3_enabled_previous&quot;: false,
- &quot;snmp_3_url_previous&quot;: &quot;&quot;,
- &quot;snmp_4_community_previous&quot;: &quot;&quot;,
- &quot;snmp_4_enabled_previous&quot;: false,
- &quot;snmp_4_url_previous&quot;: &quot;&quot;,
- &quot;snmp_receiver_1_port_previous&quot;: 162,
- &quot;snmp_receiver_2_port_previous&quot;: 162,
- &quot;snmp_receiver_3_port_previous&quot;: 162,
- &quot;snmp_receiver_4_port_previous&quot;: 162,
- &quot;timeout_long_operations_previous&quot;: 120,
- &quot;timeout_normal_operations_previous&quot;: 30
- }</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- sky-joker (@sky-joker)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_vcenter_settings_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_vcenter_settings_module.rst
deleted file mode 100644
index 8c5307bad..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_vcenter_settings_module.rst
+++ /dev/null
@@ -1,987 +0,0 @@
-.. _community.vmware.vmware_vcenter_settings_module:
-
-
-****************************************
-community.vmware.vmware_vcenter_settings
-****************************************
-
-**Configures general settings on a vCenter server**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to configure the vCenter server general settings (except the statistics).
-- The statistics can be configured with the module ``vmware_vcenter_statistics``.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="2">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>advanced_settings</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">{}</div>
- </td>
- <td>
- <div>A dictionary of advanced settings.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>database</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">{"event_cleanup": true, "event_retention": 30, "max_connections": 50, "task_cleanup": true, "task_retention": 30}</div>
- </td>
- <td>
- <div>The database settings for vCenter server.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>event_cleanup</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Event cleanup.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>event_retention</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">30</div>
- </td>
- <td>
- <div>Event retention in days.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>max_connections</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">50</div>
- </td>
- <td>
- <div>Maximum connections.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>task_cleanup</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Task cleanup.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>task_retention</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">30</div>
- </td>
- <td>
- <div>Task retention in days.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>logging_options</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>none</li>
- <li>error</li>
- <li>warning</li>
- <li><div style="color: blue"><b>info</b>&nbsp;&larr;</div></li>
- <li>verbose</li>
- <li>trivia</li>
- </ul>
- </td>
- <td>
- <div>The level of detail that vCenter server usesfor log files.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>mail</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">{"sender": "", "server": ""}</div>
- </td>
- <td>
- <div>The settings vCenter server uses to send email alerts.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>sender</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Mail sender address.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>server</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Mail server.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>runtime_settings</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The unique runtime settings for vCenter server.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>managed_address</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>vCenter server managed address.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>unique_id</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>vCenter server unique ID.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vcenter_server_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>vCenter server name. Default is FQDN.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>snmp_receivers</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">{"snmp_receiver_1_community": "public", "snmp_receiver_1_enabled": true, "snmp_receiver_1_port": 162, "snmp_receiver_1_url": "localhost", "snmp_receiver_2_community": "", "snmp_receiver_2_enabled": false, "snmp_receiver_2_port": 162, "snmp_receiver_2_url": "", "snmp_receiver_3_community": "", "snmp_receiver_3_enabled": false, "snmp_receiver_3_port": 162, "snmp_receiver_3_url": "", "snmp_receiver_4_community": "", "snmp_receiver_4_enabled": false, "snmp_receiver_4_port": 162, "snmp_receiver_4_url": ""}</div>
- </td>
- <td>
- <div>SNMP trap destinations for vCenter server alerts.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>snmp_receiver_1_community</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">"public"</div>
- </td>
- <td>
- <div>Community string.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>snmp_receiver_1_enabled</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Enable receiver.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>snmp_receiver_1_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">162</div>
- </td>
- <td>
- <div>Receiver port.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>snmp_receiver_1_url</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">"localhost"</div>
- </td>
- <td>
- <div>Primary Receiver ULR.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>snmp_receiver_2_community</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">""</div>
- </td>
- <td>
- <div>Community string.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>snmp_receiver_2_enabled</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Enable receiver.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>snmp_receiver_2_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">162</div>
- </td>
- <td>
- <div>Receiver port.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>snmp_receiver_2_url</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">""</div>
- </td>
- <td>
- <div>Receiver 2 ULR.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>snmp_receiver_3_community</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">""</div>
- </td>
- <td>
- <div>Community string.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>snmp_receiver_3_enabled</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Enable receiver.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>snmp_receiver_3_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">162</div>
- </td>
- <td>
- <div>Receiver port.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>snmp_receiver_3_url</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">""</div>
- </td>
- <td>
- <div>Receiver 3 ULR.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>snmp_receiver_4_community</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">""</div>
- </td>
- <td>
- <div>Community string.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>snmp_receiver_4_enabled</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Enable receiver.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>snmp_receiver_4_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">162</div>
- </td>
- <td>
- <div>Receiver port.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>snmp_receiver_4_url</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">""</div>
- </td>
- <td>
- <div>Receiver 4 ULR.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>timeout_settings</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">{"long_operations": 120, "normal_operations": 30}</div>
- </td>
- <td>
- <div>The vCenter server connection timeout for normal and long operations.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>long_operations</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">120</div>
- </td>
- <td>
- <div>Long operation timeout.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>normal_operations</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">30</div>
- </td>
- <td>
- <div>Normal operation timeout.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>user_directory</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">{"query_limit": true, "query_limit_size": 5000, "timeout": 60, "validation": true, "validation_period": 1440}</div>
- </td>
- <td>
- <div>The user directory settings for the vCenter server installation.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>query_limit</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Query limit.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>query_limit_size</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">5000</div>
- </td>
- <td>
- <div>Query limit size.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>timeout</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">60</div>
- </td>
- <td>
- <div>User directory timeout.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validation</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Mail Validation.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validation_period</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">1440</div>
- </td>
- <td>
- <div>Validation period.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Configure vCenter general settings
- community.vmware.vmware_vcenter_settings:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- database:
- max_connections: 50
- task_cleanup: true
- task_retention: 30
- event_cleanup: true
- event_retention: 30
- runtime_settings:
- unique_id: 1
- managed_address: "{{ lookup('dig', inventory_hostname) }}"
- vcenter_server_name: "{{ inventory_hostname }}"
- user_directory:
- timeout: 60
- query_limit: true
- query_limit_size: 5000
- validation: true
- validation_period: 1440
- mail:
- server: mail.example.com
- sender: vcenter@{{ inventory_hostname }}
- snmp_receivers:
- snmp_receiver_1_url: localhost
- snmp_receiver_1_enabled: true
- snmp_receiver_1_port: 162
- snmp_receiver_1_community: public
- timeout_settings:
- normal_operations: 30
- long_operations: 120
- logging_options: info
- delegate_to: localhost
-
- - name: Enable Retreat Mode for cluster with MOID domain-c8 (https://kb.vmware.com/kb/80472)
- community.vmware.vmware_vcenter_settings:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- advanced_settings:
- 'config.vcls.clusters.domain-c8.enabled': 'false'
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>results</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about vCenter settings</div>
- <div>supported diff mode from version 1.8.0</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;changed&#x27;: False, &#x27;db_event_cleanup&#x27;: True, &#x27;db_event_retention&#x27;: 30, &#x27;db_max_connections&#x27;: 50, &#x27;db_task_cleanup&#x27;: True, &#x27;db_task_retention&#x27;: 30, &#x27;directory_query_limit&#x27;: True, &#x27;directory_query_limit_size&#x27;: 5000, &#x27;directory_timeout&#x27;: 60, &#x27;directory_validation&#x27;: True, &#x27;directory_validation_period&#x27;: 1440, &#x27;logging_options&#x27;: &#x27;info&#x27;, &#x27;mail_sender&#x27;: &#x27;vcenter@vcenter01.example.com&#x27;, &#x27;mail_server&#x27;: &#x27;mail.example.com&#x27;, &#x27;msg&#x27;: &#x27;vCenter settings already configured properly&#x27;, &#x27;runtime_managed_address&#x27;: &#x27;192.168.1.10&#x27;, &#x27;runtime_server_name&#x27;: &#x27;vcenter01.example.com&#x27;, &#x27;runtime_unique_id&#x27;: 1, &#x27;timeout_long_operations&#x27;: 120, &#x27;timeout_normal_operations&#x27;: 30, &#x27;diff&#x27;: {&#x27;after&#x27;: {&#x27;db_event_cleanup&#x27;: True, &#x27;db_event_retention&#x27;: 30, &#x27;db_max_connections&#x27;: 50, &#x27;db_task_cleanup&#x27;: True, &#x27;db_task_retention&#x27;: 30, &#x27;directory_query_limit&#x27;: True, &#x27;directory_query_limit_size&#x27;: 5000, &#x27;directory_timeout&#x27;: 60, &#x27;directory_validation&#x27;: True, &#x27;directory_validation_period&#x27;: 1440, &#x27;logging_options&#x27;: &#x27;info&#x27;, &#x27;mail_sender&#x27;: &#x27;vcenter@vcenter01.example.com&#x27;, &#x27;mail_server&#x27;: &#x27;mail.example.com&#x27;, &#x27;runtime_managed_address&#x27;: &#x27;192.168.1.10&#x27;, &#x27;runtime_server_name&#x27;: &#x27;vcenter01.example.com&#x27;, &#x27;runtime_unique_id&#x27;: 1, &#x27;snmp_receiver_1_community&#x27;: &#x27;public&#x27;, &#x27;snmp_receiver_1_enabled&#x27;: True, &#x27;snmp_receiver_1_port&#x27;: 162, &#x27;snmp_receiver_1_url&#x27;: &#x27;localhost&#x27;, &#x27;snmp_receiver_2_community&#x27;: &#x27;&#x27;, &#x27;snmp_receiver_2_enabled&#x27;: False, &#x27;snmp_receiver_2_port&#x27;: 162, &#x27;snmp_receiver_2_url&#x27;: &#x27;&#x27;, &#x27;snmp_receiver_3_community&#x27;: &#x27;&#x27;, &#x27;snmp_receiver_3_enabled&#x27;: False, &#x27;snmp_receiver_3_port&#x27;: 162, &#x27;snmp_receiver_3_url&#x27;: &#x27;&#x27;, &#x27;snmp_receiver_4_community&#x27;: &#x27;&#x27;, &#x27;snmp_receiver_4_enabled&#x27;: False, &#x27;snmp_receiver_4_port&#x27;: 162, &#x27;snmp_receiver_4_url&#x27;: &#x27;&#x27;, &#x27;timeout_long_operations&#x27;: 120, &#x27;timeout_normal_operations&#x27;: 30}, &#x27;before&#x27;: {&#x27;db_event_cleanup&#x27;: True, &#x27;db_event_retention&#x27;: 30, &#x27;db_max_connections&#x27;: 50, &#x27;db_task_cleanup&#x27;: True, &#x27;db_task_retention&#x27;: 30, &#x27;directory_query_limit&#x27;: True, &#x27;directory_query_limit_size&#x27;: 5000, &#x27;directory_timeout&#x27;: 60, &#x27;directory_validation&#x27;: True, &#x27;directory_validation_period&#x27;: 1440, &#x27;logging_options&#x27;: &#x27;info&#x27;, &#x27;mail_sender&#x27;: &#x27;vcenter@vcenter01.example.com&#x27;, &#x27;mail_server&#x27;: &#x27;mail.example.com&#x27;, &#x27;runtime_managed_address&#x27;: &#x27;192.168.1.10&#x27;, &#x27;runtime_server_name&#x27;: &#x27;vcenter01.example.com&#x27;, &#x27;runtime_unique_id&#x27;: 1, &#x27;snmp_receiver_1_community&#x27;: &#x27;public&#x27;, &#x27;snmp_receiver_1_enabled&#x27;: True, &#x27;snmp_receiver_1_port&#x27;: 162, &#x27;snmp_receiver_1_url&#x27;: &#x27;localhost&#x27;, &#x27;snmp_receiver_2_community&#x27;: &#x27;&#x27;, &#x27;snmp_receiver_2_enabled&#x27;: False, &#x27;snmp_receiver_2_port&#x27;: 162, &#x27;snmp_receiver_2_url&#x27;: &#x27;&#x27;, &#x27;snmp_receiver_3_community&#x27;: &#x27;&#x27;, &#x27;snmp_receiver_3_enabled&#x27;: False, &#x27;snmp_receiver_3_port&#x27;: 162, &#x27;snmp_receiver_3_url&#x27;: &#x27;&#x27;, &#x27;snmp_receiver_4_community&#x27;: &#x27;&#x27;, &#x27;snmp_receiver_4_enabled&#x27;: False, &#x27;snmp_receiver_4_port&#x27;: 162, &#x27;snmp_receiver_4_url&#x27;: &#x27;&#x27;, &#x27;timeout_long_operations&#x27;: 120, &#x27;timeout_normal_operations&#x27;: 30}}}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Christian Kotte (@ckotte)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_vcenter_statistics_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_vcenter_statistics_module.rst
deleted file mode 100644
index 9973db4ac..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_vcenter_statistics_module.rst
+++ /dev/null
@@ -1,640 +0,0 @@
-.. _community.vmware.vmware_vcenter_statistics_module:
-
-
-******************************************
-community.vmware.vmware_vcenter_statistics
-******************************************
-
-**Configures statistics on a vCenter server**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to configure the vCenter server statistics.
-- The remaining settings can be configured with the module ``vmware_vcenter_settings``.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="2">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>interval_past_day</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Settings for vCenter server past day statistic collection.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>enabled</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Past day statistics collection enabled.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>interval_minutes</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>1</li>
- <li>2</li>
- <li>3</li>
- <li>4</li>
- <li><div style="color: blue"><b>5</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Interval duration in minutes.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>level</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>1</b>&nbsp;&larr;</div></li>
- <li>2</li>
- <li>3</li>
- <li>4</li>
- </ul>
- </td>
- <td>
- <div>Statistics level.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>save_for_days</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>1</b>&nbsp;&larr;</div></li>
- <li>2</li>
- <li>3</li>
- <li>4</li>
- <li>5</li>
- </ul>
- </td>
- <td>
- <div>Save for value in days.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>interval_past_month</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Settings for vCenter server past month statistic collection.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>enabled</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Past month statistics collection enabled.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>interval_hours</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>2</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Interval duration in hours.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>level</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>1</b>&nbsp;&larr;</div></li>
- <li>2</li>
- <li>3</li>
- <li>4</li>
- </ul>
- </td>
- <td>
- <div>Statistics level.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>save_for_months</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>1</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Save for value in months.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>interval_past_week</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Settings for vCenter server past week statistic collection.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>enabled</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Past week statistics collection enabled.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>interval_minutes</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>30</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Interval duration in minutes.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>level</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>1</b>&nbsp;&larr;</div></li>
- <li>2</li>
- <li>3</li>
- <li>4</li>
- </ul>
- </td>
- <td>
- <div>Statistics level.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>save_for_weeks</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>1</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Save for value in weeks.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>interval_past_year</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Settings for vCenter server past month statistic collection.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>enabled</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Past month statistics collection enabled.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>interval_days</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>1</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Interval duration in days.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>level</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>1</b>&nbsp;&larr;</div></li>
- <li>2</li>
- <li>3</li>
- <li>4</li>
- </ul>
- </td>
- <td>
- <div>Statistics level.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>save_for_years</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>1</b>&nbsp;&larr;</div></li>
- <li>2</li>
- <li>3</li>
- <li>4</li>
- <li>5</li>
- </ul>
- </td>
- <td>
- <div>Save for value in years.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Configure vCenter statistics
- community.vmware.vmware_vcenter_statistics:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- interval_past_day:
- enabled: true
- interval_minutes: 5
- save_for_days: 1
- level: 1
- interval_past_week:
- enabled: true
- level: 1
- interval_past_month:
- enabled: true
- level: 1
- interval_past_year:
- enabled: true
- save_for_years: 1
- level: 1
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>results</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about vCenter statistics settings</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;changed&#x27;: False, &#x27;msg&#x27;: &#x27;vCenter statistics already configured properly&#x27;, &#x27;past_day_enabled&#x27;: True, &#x27;past_day_interval&#x27;: 5, &#x27;past_day_level&#x27;: 1, &#x27;past_day_save_for&#x27;: 1, &#x27;past_month_enabled&#x27;: True, &#x27;past_month_interval&#x27;: 2, &#x27;past_month_level&#x27;: 1, &#x27;past_month_save_for&#x27;: 1, &#x27;past_week_enabled&#x27;: True, &#x27;past_week_interval&#x27;: 30, &#x27;past_week_level&#x27;: 1, &#x27;past_week_save_for&#x27;: 1, &#x27;past_year_enabled&#x27;: True, &#x27;past_year_interval&#x27;: 1, &#x27;past_year_level&#x27;: 1, &#x27;past_year_save_for&#x27;: 1}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Christian Kotte (@ckotte)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_vm_config_option_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_vm_config_option_module.rst
deleted file mode 100644
index a77f79441..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_vm_config_option_module.rst
+++ /dev/null
@@ -1,382 +0,0 @@
-.. _community.vmware.vmware_vm_config_option_module:
-
-
-****************************************
-community.vmware.vmware_vm_config_option
-****************************************
-
-**Return supported guest ID list and VM recommended config option for specific guest OS**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module is used for getting the hardware versions supported for creation, the guest ID list supported by ESXi host for the most recent virtual hardware supported or specified hardware version, the VM recommended config options for specified guest OS ID.
-
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the cluster.</div>
- <div>If <code>esxi_hostname</code> is not given, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">"ha-datacenter"</div>
- </td>
- <td>
- <div>The datacenter name used to get specified cluster or host.</div>
- <div>This parameter is case sensitive.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>ESXi hostname.</div>
- <div>Obtain VM configure options on this ESXi host.</div>
- <div>If <code>cluster_name</code> is not given, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>get_config_options</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Return the dict of VM recommended config options for guest ID specified by <code>guest_id</code> with hardware version specified by <code>hardware_version</code> or the default hardware version.</div>
- <div>When set to True, <code>guest_id</code> must be set.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>get_guest_os_ids</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Return the list of guest OS IDs supported on the specified entity.</div>
- <div>If <code>hardware_version</code> is set, will return the corresponding guest OS ID list supported, or will return the guest OS ID list for the default hardware version.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>get_hardware_versions</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Return the list of VM hardware versions supported for creation and the default hardware version on the specified entity.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>guest_id</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The guest OS ID from the returned list when <code>get_guest_os_ids</code> is set to <code>true</code>, e.g., &#x27;rhel8_64Guest&#x27;.</div>
- <div>This parameter must be set when <code>get_config_options</code> is set to <code>true</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hardware_version</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hardware version from the returned list when <code>get_hardware_versions</code> is set to <code>true</code>, e.g., &#x27;vmx-19&#x27;.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - Known issue on vSphere 7.0 (https://github.com/vmware/pyvmomi/issues/915)
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Get supported guest ID list on given ESXi host for with default hardware version
- community.vmware.vmware_vm_config_option:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- esxi_hostname: "{{ esxi_hostname }}"
- get_guest_os_ids: true
- delegate_to: localhost
-
- - name: Get VM recommended config option for Windows 10 guest OS on given ESXi host
- community.vmware.vmware_vm_config_option:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- esxi_hostname: "{{ esxi_hostname }}"
- get_config_options: true
- guest_id: "windows9_64Guest"
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>instance</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about the VM recommended configuration</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">None</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Diane Wang (@Tomorrow9) <dianew@vmware.com>
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_vm_host_drs_rule_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_vm_host_drs_rule_module.rst
deleted file mode 100644
index 410260f31..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_vm_host_drs_rule_module.rst
+++ /dev/null
@@ -1,364 +0,0 @@
-.. _community.vmware.vmware_vm_host_drs_rule_module:
-
-
-****************************************
-community.vmware.vmware_vm_host_drs_rule
-****************************************
-
-**Creates vm/host group in a given cluster**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to create VM-Host rules in a given cluster.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>affinity_rule</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>If set to <code>true</code>, the DRS rule will be an Affinity rule.</div>
- <div>If set to <code>false</code>, the DRS rule will be an Anti-Affinity rule.</div>
- <div>Effective only if <code>state</code> is set to <code>present</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Cluster to create VM-Host rule.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Datacenter to search for given cluster. If not set, we use first cluster we encounter with <code>cluster_name</code>.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: datacenter_name</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>drs_rule_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of rule to create or remove.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>enabled</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>If set to <code>true</code>, the DRS rule will be enabled.</div>
- <div>Effective only if <code>state</code> is set to <code>present</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>host_group_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of Host group to use with rule.</div>
- <div>Effective only if <code>state</code> is set to <code>present</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>mandatory</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>If set to <code>true</code>, the DRS rule will be mandatory.</div>
- <div>Effective only if <code>state</code> is set to <code>present</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>If set to <code>present</code> and the rule does not exist then the rule will be created.</div>
- <div>If set to <code>absent</code> and the rule exists then the rule will be deleted.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vm_group_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of VM group to use with rule.</div>
- <div>Effective only if <code>state</code> is set to <code>present</code>.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- ---
- - name: "Create mandatory DRS Affinity rule for VM/Host"
- community.vmware.vmware_vm_host_drs_rule:
- hostname: "{{ vcenter_hostname }}"
- password: "{{ vcenter_password }}"
- username: "{{ vcenter_username }}"
- cluster_name: DC0_C0
- drs_rule_name: drs_rule_host_aff_0001
- host_group_name: DC0_C0_HOST_GR1
- vm_group_name: DC0_C0_VM_GR1
- mandatory: true
- enabled: true
- affinity_rule: true
-
-
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Karsten Kaj Jakobsen (@karstenjakobsen)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_vm_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_vm_info_module.rst
deleted file mode 100644
index 3d426b66d..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_vm_info_module.rst
+++ /dev/null
@@ -1,615 +0,0 @@
-.. _community.vmware.vmware_vm_info_module:
-
-
-*******************************
-community.vmware.vmware_vm_info
-*******************************
-
-**Return basic info pertaining to a VMware machine guest**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- Return basic information pertaining to a vSphere or ESXi virtual machine guest.
-- Cluster name as fact is added in version 2.7.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>folder</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Specify a folder location of VMs to gather information from.</div>
- <div>Examples:</div>
- <div>folder: /ha-datacenter/vm</div>
- <div>folder: ha-datacenter/vm</div>
- <div>folder: /datacenter1/vm</div>
- <div>folder: datacenter1/vm</div>
- <div>folder: /datacenter1/vm/folder1</div>
- <div>folder: datacenter1/vm/folder1</div>
- <div>folder: /folder1/datacenter1/vm</div>
- <div>folder: folder1/datacenter1/vm</div>
- <div>folder: /folder1/datacenter1/vm/folder2</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>show_allocated</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 2.5.0</div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Allocated storage in byte and memory in MB are shown if it set to True.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>show_attribute</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Attributes related to VM guest shown in information only when this is set <code>true</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>show_cluster</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 3.5.0</div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Tags virtual machine&#x27;s cluster is shown if set to <code>true</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>show_datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 3.5.0</div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Tags virtual machine&#x27;s datacenter is shown if set to <code>true</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>show_datastore</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 3.5.0</div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Tags virtual machine&#x27;s datastore is shown if set to <code>true</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>show_esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 3.5.0</div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Tags virtual machine&#x27;s ESXi host is shown if set to <code>true</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>show_folder</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 3.7.0</div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Show folders</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>show_mac_address</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 3.5.0</div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Tags virtual machine&#x27;s mac address is shown if set to <code>true</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>show_net</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 3.5.0</div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Tags virtual machine&#x27;s network is shown if set to <code>true</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>show_resource_pool</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 3.5.0</div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Tags virtual machine&#x27;s resource pool is shown if set to <code>true</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>show_tag</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Tags related to virtual machine are shown if set to <code>true</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vm_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the virtual machine to get related configurations information from.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vm_type</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>all</b>&nbsp;&larr;</div></li>
- <li>vm</li>
- <li>template</li>
- </ul>
- </td>
- <td>
- <div>If set to <code>vm</code>, then information are gathered for virtual machines only.</div>
- <div>If set to <code>template</code>, then information are gathered for virtual machine templates only.</div>
- <div>If set to <code>all</code>, then information are gathered for all virtual machines and virtual machine templates.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - Fact about ``moid`` added in VMware collection 1.4.0.
- - Fact about ``datastore_url`` is added in VMware collection 1.18.0.
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Gather all registered virtual machines
- community.vmware.vmware_vm_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- delegate_to: localhost
- register: vminfo
-
- - debug:
- var: vminfo.virtual_machines
-
- - name: Gather one specific VM
- community.vmware.vmware_vm_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- vm_name: 'vm_name_as_per_vcenter'
- delegate_to: localhost
- register: vm_info
-
- - debug:
- var: vminfo.virtual_machines
-
- - name: Gather only registered virtual machine templates
- community.vmware.vmware_vm_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- vm_type: template
- delegate_to: localhost
- register: template_info
-
- - debug:
- var: template_info.virtual_machines
-
- - name: Gather only registered virtual machines
- community.vmware.vmware_vm_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- vm_type: vm
- delegate_to: localhost
- register: vm_info
-
- - debug:
- var: vm_info.virtual_machines
-
- - name: Get UUID from given VM Name
- block:
- - name: Get virtual machine info
- community.vmware.vmware_vm_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- folder: "/datacenter/vm/folder"
- delegate_to: localhost
- register: vm_info
-
- - debug:
- msg: "{{ item.uuid }}"
- with_items:
- - "{{ vm_info.virtual_machines | community.general.json_query(query) }}"
- vars:
- query: "[?guest_name=='DC0_H0_VM0']"
-
- - name: Get Tags from given VM Name
- block:
- - name: Get virtual machine info
- community.vmware.vmware_vm_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- folder: "/datacenter/vm/folder"
- delegate_to: localhost
- register: vm_info
-
- - debug:
- msg: "{{ item.tags }}"
- with_items:
- - "{{ vm_info.virtual_machines | community.general.json_query(query) }}"
- vars:
- query: "[?guest_name=='DC0_H0_VM0']"
-
- - name: Gather all VMs from a specific folder
- community.vmware.vmware_vm_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- folder: "/Asia-Datacenter1/vm/prod"
- delegate_to: localhost
- register: vm_info
-
- - name: Get datastore_url from given VM name
- block:
- - name: Get virtual machine info
- community.vmware.vmware_vm_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- delegate_to: localhost
- register: vm_info
-
- - debug:
- msg: "{{ item.datastore_url }}"
- with_items:
- - "{{ vm_info.virtual_machines | community.general.json_query(query) }}"
- vars:
- query: "[?guest_name=='DC0_H0_VM0']"
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>virtual_machines</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- </div>
- </td>
- <td>success</td>
- <td>
- <div>list of dictionary of virtual machines and their information</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">[{&#x27;guest_name&#x27;: &#x27;ubuntu_t&#x27;, &#x27;datacenter&#x27;: &#x27;Datacenter-1&#x27;, &#x27;cluster&#x27;: None, &#x27;esxi_hostname&#x27;: &#x27;10.76.33.226&#x27;, &#x27;folder&#x27;: &#x27;/Datacenter-1/vm&#x27;, &#x27;guest_fullname&#x27;: &#x27;Ubuntu Linux (64-bit)&#x27;, &#x27;ip_address&#x27;: &#x27;&#x27;, &#x27;mac_address&#x27;: [&#x27;00:50:56:87:a5:9a&#x27;], &#x27;power_state&#x27;: &#x27;poweredOff&#x27;, &#x27;uuid&#x27;: &#x27;4207072c-edd8-3bd5-64dc-903fd3a0db04&#x27;, &#x27;vm_network&#x27;: {&#x27;00:50:56:87:a5:9a&#x27;: {&#x27;ipv4&#x27;: [&#x27;10.76.33.228&#x27;], &#x27;ipv6&#x27;: []}}, &#x27;attributes&#x27;: {&#x27;job&#x27;: &#x27;backup-prepare&#x27;}, &#x27;datastore_url&#x27;: [{&#x27;name&#x27;: &#x27;t880-o2g&#x27;, &#x27;url&#x27;: &#x27;/vmfs/volumes/e074264a-e5c82a58&#x27;}], &#x27;tags&#x27;: [{&#x27;category_id&#x27;: &#x27;urn:vmomi:InventoryServiceCategory:b316cc45-f1a9-4277-811d-56c7e7975203:GLOBAL&#x27;, &#x27;category_name&#x27;: &#x27;cat_0001&#x27;, &#x27;description&#x27;: &#x27;&#x27;, &#x27;id&#x27;: &#x27;urn:vmomi:InventoryServiceTag:43737ec0-b832-4abf-abb1-fd2448ce3b26:GLOBAL&#x27;, &#x27;name&#x27;: &#x27;tag_0001&#x27;}], &#x27;moid&#x27;: &#x27;vm-24&#x27;, &#x27;allocated&#x27;: {&#x27;storage&#x27;: 500000000, &#x27;cpu&#x27;: 2, &#x27;memory&#x27;: 16}}]</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Joseph Callen (@jcpowermac)
-- Abhijeet Kasurde (@Akasurde)
-- Fedor Vompe (@sumkincpp)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_vm_inventory_inventory.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_vm_inventory_inventory.rst
deleted file mode 100644
index 983c16eee..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_vm_inventory_inventory.rst
+++ /dev/null
@@ -1,974 +0,0 @@
-.. _community.vmware.vmware_vm_inventory_inventory:
-
-
-************************************
-community.vmware.vmware_vm_inventory
-************************************
-
-**VMware Guest inventory source**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- Get virtual machines as inventory hosts from VMware environment.
-- Uses any file which ends with vmware.yml, vmware.yaml, vmware_vm_inventory.yml, or vmware_vm_inventory.yaml as a YAML configuration file.
-
-
-
-Requirements
-------------
-The below requirements are needed on the local Ansible controller node that executes this inventory.
-
-- requests >= 2.3
-- vSphere Automation SDK - For tag feature
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="2">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th>Configuration</th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cache</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div> ini entries:
- <p>[inventory]<br>cache = no</p>
- </div>
- <div>env:ANSIBLE_INVENTORY_CACHE</div>
- </td>
- <td>
- <div>Toggle to enable/disable the caching of the inventory&#x27;s source data, requires a cache plugin setup to work.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cache_connection</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div> ini entries:
- <p>[defaults]<br>fact_caching_connection = VALUE</p>
- <p>[inventory]<br>cache_connection = VALUE</p>
- </div>
- <div>env:ANSIBLE_CACHE_PLUGIN_CONNECTION</div>
- <div>env:ANSIBLE_INVENTORY_CACHE_CONNECTION</div>
- </td>
- <td>
- <div>Cache connection data or path, read cache plugin documentation for specifics.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cache_plugin</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">"memory"</div>
- </td>
- <td>
- <div> ini entries:
- <p>[defaults]<br>fact_caching = memory</p>
- <p>[inventory]<br>cache_plugin = memory</p>
- </div>
- <div>env:ANSIBLE_CACHE_PLUGIN</div>
- <div>env:ANSIBLE_INVENTORY_CACHE_PLUGIN</div>
- </td>
- <td>
- <div>Cache plugin to use for the inventory&#x27;s source data.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cache_prefix</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">-</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">"ansible_inventory_"</div>
- </td>
- <td>
- <div> ini entries:
- <p>[default]<br>fact_caching_prefix = ansible_inventory_</p>
- <p>[defaults]<br>fact_caching_prefix = ansible_inventory_</p>
- <p>[inventory]<br>cache_prefix = ansible_inventory_</p>
- </div>
- <div>env:ANSIBLE_CACHE_PLUGIN_PREFIX</div>
- <div>env:ANSIBLE_INVENTORY_CACHE_PLUGIN_PREFIX</div>
- </td>
- <td>
- <div>Prefix to use for cache plugin files/tables</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cache_timeout</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">3600</div>
- </td>
- <td>
- <div> ini entries:
- <p>[defaults]<br>fact_caching_timeout = 3600</p>
- <p>[inventory]<br>cache_timeout = 3600</p>
- </div>
- <div>env:ANSIBLE_CACHE_PLUGIN_TIMEOUT</div>
- <div>env:ANSIBLE_INVENTORY_CACHE_TIMEOUT</div>
- </td>
- <td>
- <div>Cache duration in seconds</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>compose</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">{}</div>
- </td>
- <td>
- </td>
- <td>
- <div>Create vars from jinja2 expressions.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>filters</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">[]</div>
- </td>
- <td>
- </td>
- <td>
- <div>This option allows client-side filtering hosts with jinja templating.</div>
- <div>When server-side filtering is introduced, it should be preferred over this.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>groups</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">{}</div>
- </td>
- <td>
- </td>
- <td>
- <div>Add hosts to group based on Jinja2 conditionals.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">-</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>env:VMWARE_HOST</div>
- <div>env:VMWARE_SERVER</div>
- </td>
- <td>
- <div>Name of vCenter or ESXi server.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostnames</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">["config.name + \"_\" + config.uuid"]</div>
- </td>
- <td>
- </td>
- <td>
- <div>A list of templates in order of precedence to compose inventory_hostname.</div>
- <div>Ignores template if resulted in an empty string or None value.</div>
- <div>You can use property specified in <em>properties</em> as variables in the template.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>keyed_groups</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">[{"key": "config.guestId", "separator": ""}, {"key": "summary.runtime.powerState", "separator": ""}]</div>
- </td>
- <td>
- </td>
- <td>
- <div>Add hosts to group based on the values of a variable.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>default_value</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 2.12</div>
- </td>
- <td>
- </td>
- <td>
- </td>
- <td>
- <div>The default value when the host variable&#x27;s value is an empty string.</div>
- <div>This option is mutually exclusive with <code>trailing_separator</code>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>key</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- </td>
- <td>
- <div>The key from input dictionary used to generate groups</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>parent_group</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- </td>
- <td>
- <div>parent group for keyed group</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>prefix</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">""</div>
- </td>
- <td>
- </td>
- <td>
- <div>A keyed group name will start with this prefix</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>separator</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">"_"</div>
- </td>
- <td>
- </td>
- <td>
- <div>separator used to build the keyed group name</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>trailing_separator</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 2.12</div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- </td>
- <td>
- <div>Set this option to <em>False</em> to omit the <code>separator</code> after the host variable when the value is an empty string.</div>
- <div>This option is mutually exclusive with <code>default_value</code>.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>leading_separator</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 2.11</div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">"yes"</div>
- </td>
- <td>
- </td>
- <td>
- <div>Use in conjunction with keyed_groups.</div>
- <div>By default, a keyed group that does not have a prefix or a separator provided will have a name that starts with an underscore.</div>
- <div>This is because the default prefix is &quot;&quot; and the default separator is &quot;_&quot;.</div>
- <div>Set this option to False to omit the leading underscore (or other separator) if no prefix is given.</div>
- <div>If the group name is derived from a mapping the separator is still used to concatenate the items.</div>
- <div>To not use a separator in the group name at all, set the separator for the keyed group to an empty string instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">-</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>env:VMWARE_PASSWORD</div>
- </td>
- <td>
- <div>Password of vSphere user.</div>
- <div>Accepts vault encrypted variable.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>env:VMWARE_PORT</div>
- </td>
- <td>
- <div>Port number used to connect to vCenter or ESXi Server.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>properties</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">["name", "config.cpuHotAddEnabled", "config.cpuHotRemoveEnabled", "config.instanceUuid", "config.hardware.numCPU", "config.template", "config.name", "config.uuid", "guest.hostName", "guest.ipAddress", "guest.guestId", "guest.guestState", "runtime.maxMemoryUsage", "customValue", "summary.runtime.powerState", "config.guestId"]</div>
- </td>
- <td>
- </td>
- <td>
- <div>Specify the list of VMware schema properties associated with the VM.</div>
- <div>These properties will be populated in hostvars of the given VM.</div>
- <div>Each value in the list can be a path to a specific property in VM object or a path to a collection of VM objects.</div>
- <div><code>config.name</code>, <code>config.uuid</code> are required properties if <code>hostnames</code> is set to default.</div>
- <div><code>config.guestId</code>, <code>summary.runtime.powerState</code> are required if <code>keyed_groups</code> is set to default.</div>
- <div>Please make sure that all the properties that are used in other parameters are included in this options.</div>
- <div>In addition to VM properties, the following are special values</div>
- <div>Use <code>customValue</code> to populate virtual machine&#x27;s custom attributes. <code>customValue</code> is only supported by vCenter and not by ESXi.</div>
- <div>Use <code>all</code> to populate all the properties of the virtual machine. The value <code>all</code> is time consuming operation, do not use unless required absolutely.</div>
- <div>Please refer more VMware guest attributes which can be used as properties <a href='https://docs.ansible.com/ansible/latest/collections/community/vmware/docsite/vmware_scenarios/vmware_inventory_vm_attributes.html'>https://docs.ansible.com/ansible/latest/collections/community/vmware/docsite/vmware_scenarios/vmware_inventory_vm_attributes.html</a></div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>env:VMWARE_PROXY_HOST</div>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>This feature depends on a version of pyvmomi&gt;=v6.7.1.2018.12.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>env:VMWARE_PROXY_PORT</div>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>resources</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">[]</div>
- </td>
- <td>
- </td>
- <td>
- <div>A list of resources to limit search scope.</div>
- <div>Each resource item is represented by exactly one <code>&#x27;vim_type_snake_case</code>:<code>list of resource names</code> pair and optional nested <em>resources</em></div>
- <div>Key name is based on snake case of a vim type name; e.g <code>host_system</code> correspond to <code>vim.HostSystem</code></div>
- <div>See <a href='https://pubs.vmware.com/vi-sdk/visdk250/ReferenceGuide/index-mo_types.html'>VIM Types</a></div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>strict</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- </td>
- <td>
- <div>If <code>yes</code> make invalid entries a fatal error, otherwise skip and continue.</div>
- <div>Since it is possible to use facts in the expressions they might not always be available and we ignore those errors by default.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>use_extra_vars</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 2.11</div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div> ini entries:
- <p>[inventory_plugins]<br>use_extra_vars = no</p>
- </div>
- <div>env:ANSIBLE_INVENTORY_USE_EXTRA_VARS</div>
- </td>
- <td>
- <div>Merge extra vars into the available variables for composition (highest precedence).</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">-</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>env:VMWARE_USER</div>
- <div>env:VMWARE_USERNAME</div>
- </td>
- <td>
- <div>Name of vSphere user.</div>
- <div>Accepts vault encrypted variable.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>env:VMWARE_VALIDATE_CERTS</div>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid.</div>
- <div>Set to <code>false</code> when certificates are not trusted.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>with_nested_properties</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- </td>
- <td>
- <div>This option transform flatten properties name to nested dictionary.</div>
- <div>From 1.10.0 and onwards, default value is set to <code>true</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>with_path</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- </td>
- <td>
- <div>Include virtual machines path.</div>
- <div>Set this option to a string value to replace root name from <em>&#x27;Datacenters&#x27;</em>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>with_sanitized_property_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- </td>
- <td>
- <div>This option allows property name sanitization to create safe property names for use in Ansible.</div>
- <div>Also, transforms property name to snake case.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>with_tags</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- </td>
- <td>
- <div>Include tags and associated virtual machines.</div>
- <div>Requires &#x27;vSphere Automation SDK&#x27; library to be installed on the given controller machine.</div>
- <div>Please refer following URLs for installation steps</div>
- <div><a href='https://code.vmware.com/web/sdk/7.0/vsphere-automation-python'>https://code.vmware.com/web/sdk/7.0/vsphere-automation-python</a></div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- # Sample configuration file for VMware Guest dynamic inventory
- plugin: community.vmware.vmware_vm_inventory
- strict: false
- hostname: 10.65.223.31
- username: administrator@vsphere.local
- password: Esxi@123$%
- validate_certs: false
- with_tags: true
-
- # Gather minimum set of properties for VMware guest
- plugin: community.vmware.vmware_vm_inventory
- strict: false
- hostname: 10.65.223.31
- username: administrator@vsphere.local
- password: Esxi@123$%
- validate_certs: false
- properties:
- - 'name'
- - 'guest.ipAddress'
- - 'config.name'
- - 'config.uuid'
-
- # Create Groups based upon VMware Tools status
- plugin: community.vmware.vmware_vm_inventory
- strict: false
- hostname: 10.65.223.31
- username: administrator@vsphere.local
- password: Esxi@123$%
- validate_certs: false
- properties:
- - 'name'
- - 'config.name'
- - 'guest.toolsStatus'
- - 'guest.toolsRunningStatus'
- hostnames:
- - config.name
- keyed_groups:
- - key: guest.toolsStatus
- separator: ''
- - key: guest.toolsRunningStatus
- separator: ''
-
- # Filter VMs based upon condition
- plugin: community.vmware.vmware_vm_inventory
- strict: false
- hostname: 10.65.223.31
- username: administrator@vsphere.local
- password: Esxi@123$%
- validate_certs: false
- properties:
- - 'runtime.powerState'
- - 'config.name'
- filters:
- - runtime.powerState == "poweredOn"
- hostnames:
- - config.name
-
- # Filter VM's based on OR conditions
- plugin: community.vmware.vmware_vm_inventory
- strict: false
- hostname: 10.65.223.31
- username: administrator@vsphere.local
- password: Esxi@123$%
- validate_certs: false
- properties:
- - 'name'
- - 'config.name'
- - 'guest.ipAddress'
- - 'guest.toolsStatus'
- - 'guest.toolsRunningStatus'
- - 'config.guestFullName'
- - 'config.guestId'
- hostnames:
- - 'config.name'
- filters:
- - config.guestId == "rhel7_64Guest" or config.name == "rhel_20_04_empty"
-
- # Filter VM's based on regex conditions
- plugin: community.vmware.vmware_vm_inventory
- strict: false
- hostname: 10.65.223.31
- username: administrator@vsphere.local
- password: Esxi@123$%
- validate_certs: false
- properties:
- - 'config.name'
- - 'config.guestId'
- - 'guest.ipAddress'
- - 'summary.runtime.powerState'
- filters:
- - guest.ipAddress is defined and (guest.ipAddress is match('192.168.*') or guest.ipAddress is match('192.169.*'))
-
- # Using compose and groups
- plugin: community.vmware.vmware_vm_inventory
- strict: false
- hostname: 10.65.223.31
- username: administrator@vsphere.local
- password: Esxi@123$%
- validate_certs: false
- properties:
- - 'name'
- - 'config.name'
- - 'guest.ipAddress'
- compose:
- # This will populate the IP address of virtual machine if available
- # and will be used while communicating to the given virtual machine
- ansible_host: 'guest.ipAddress'
- composed_var: 'config.name'
- # This will populate a host variable with a string value
- ansible_user: "'admin'"
- ansible_connection: "'ssh'"
- groups:
- VMs: true
- hostnames:
- - config.name
-
- # Use Datacenter, Cluster and Folder value to list VMs
- plugin: community.vmware.vmware_vm_inventory
- strict: false
- hostname: 10.65.200.241
- username: administrator@vsphere.local
- password: Esxi@123$%
- validate_certs: false
- with_tags: true
- resources:
- - datacenter:
- - Asia-Datacenter1
- - Asia-Datacenter2
- resources:
- - compute_resource:
- - Asia-Cluster1
- resources:
- - host_system:
- - Asia-ESXI4
- - folder:
- - dev
- - prod
-
- # Use Category and it's relation with Tag
- plugin: community.vmware.vmware_vm_inventory
- strict: false
- hostname: 10.65.201.128
- username: administrator@vsphere.local
- password: Esxi@123$%
- validate_certs: false
- hostnames:
- - 'config.name'
- properties:
- - 'config.name'
- - 'config.guestId'
- - 'guest.ipAddress'
- - 'summary.runtime.powerState'
- with_tags: true
- keyed_groups:
- - key: tag_category.OS
- prefix: "vmware_tag_os_category_"
- separator: ""
- with_nested_properties: true
- filters:
- - "tag_category.OS is defined and 'Linux' in tag_category.OS"
-
- # customizing hostnames based on VM's FQDN. The second hostnames template acts as a fallback mechanism.
- plugin: community.vmware.vmware_vm_inventory
- strict: false
- hostname: 10.65.223.31
- username: administrator@vsphere.local
- password: Esxi@123$%
- validate_certs: false
- hostnames:
- - 'config.name+"."+guest.ipStack.0.dnsConfig.domainName'
- - 'config.name'
- properties:
- - 'config.name'
- - 'config.guestId'
- - 'guest.hostName'
- - 'guest.ipAddress'
- - 'guest.guestFamily'
- - 'guest.ipStack'
-
- # Select a specific IP address for use by ansible when multiple NICs are present on the VM
- plugin: community.vmware.vmware_vm_inventory
- strict: false
- hostname: 10.65.223.31
- username: administrator@vsphere.local
- password: Esxi@123$%
- validate_certs: false
- compose:
- # Set the IP address used by ansible to one that starts by 10.42. or 10.43.
- ansible_host: >-
- guest.net
- | selectattr('ipAddress')
- | map(attribute='ipAddress')
- | flatten
- | select('match', '^10.42.*|^10.43.*')
- | list
- | first
- properties:
- - guest.net
-
- # Group hosts using Jinja2 conditionals
- plugin: community.vmware.vmware_vm_inventory
- strict: false
- hostname: 10.65.13.37
- username: administrator@vsphere.local
- password: Esxi@123$%
- validate_certs: false
- hostnames:
- - config.name
- properties:
- - 'name'
- - 'config.name'
- - 'config.datastoreUrl'
- groups:
- slow_storage: "'Nas01' in config.datastoreUrl[0].name"
- fast_storage: "'SSD' in config.datastoreUrl[0].name"
-
-
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
-
-
-.. hint::
- Configuration entries for each entry type have a low to high priority order. For example, a variable that is lower in the list will override a variable that is higher up.
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_vm_shell_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_vm_shell_module.rst
deleted file mode 100644
index 014a576a7..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_vm_shell_module.rst
+++ /dev/null
@@ -1,516 +0,0 @@
-.. _community.vmware.vmware_vm_shell_module:
-
-
-********************************
-community.vmware.vmware_vm_shell
-********************************
-
-**Run commands in a VMware guest operating system**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- Module allows user to run common system administration commands in the guest operating system.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The cluster hosting the virtual machine.</div>
- <div>If set, it will help to speed up virtual machine search.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The datacenter hosting the virtual machine.</div>
- <div>If set, it will help to speed up virtual machine search.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>folder</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Destination folder, absolute or relative path to find an existing guest or create the new guest.</div>
- <div>The folder should include the datacenter. ESX&#x27;s datacenter is ha-datacenter.</div>
- <div>Examples:</div>
- <div>folder: /ha-datacenter/vm</div>
- <div>folder: ha-datacenter/vm</div>
- <div>folder: /datacenter1/vm</div>
- <div>folder: datacenter1/vm</div>
- <div>folder: /datacenter1/vm/folder1</div>
- <div>folder: datacenter1/vm/folder1</div>
- <div>folder: /folder1/datacenter1/vm</div>
- <div>folder: folder1/datacenter1/vm</div>
- <div>folder: /folder1/datacenter1/vm/folder2</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>timeout</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">3600</div>
- </td>
- <td>
- <div>Timeout in seconds.</div>
- <div>If set to positive integers, then <code>wait_for_process</code> will honor this parameter and will exit after this timeout.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vm_id</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the virtual machine to work with.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vm_id_type</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>uuid</li>
- <li>instance_uuid</li>
- <li>dns_name</li>
- <li>inventory_path</li>
- <li><div style="color: blue"><b>vm_name</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>The VMware identification method by which the virtual machine will be identified.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vm_password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password used to login-in to the virtual machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vm_shell</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The absolute path to the program to start.</div>
- <div>On Linux, shell is executed via bash.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vm_shell_args</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">" "</div>
- </td>
- <td>
- <div>The argument to the program.</div>
- <div>The characters which must be escaped to the shell also be escaped on the command line provided.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vm_shell_cwd</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The current working directory of the application from which it will be run.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vm_shell_env</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Comma separated list of environment variable, specified in the guest OS notation.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vm_username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The user to login-in to the virtual machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>wait_for_process</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>If set to <code>true</code>, module will wait for process to complete in the given virtual machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - Only the first match against vm_id is used, even if there are multiple matches.
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Run command inside a virtual machine
- community.vmware.vmware_vm_shell:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter }}"
- folder: "/{{datacenter}}/vm"
- vm_id: "{{ vm_name }}"
- vm_username: root
- vm_password: superSecret
- vm_shell: /bin/echo
- vm_shell_args: " $var >> myFile "
- vm_shell_env:
- - "PATH=/bin"
- - "VAR=test"
- vm_shell_cwd: "/tmp"
- delegate_to: localhost
- register: shell_command_output
-
- - name: Run command inside a virtual machine with wait and timeout
- community.vmware.vmware_vm_shell:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter }}"
- folder: "/{{datacenter}}/vm"
- vm_id: NameOfVM
- vm_username: root
- vm_password: superSecret
- vm_shell: /bin/sleep
- vm_shell_args: 100
- wait_for_process: true
- timeout: 2000
- delegate_to: localhost
- register: shell_command_with_wait_timeout
-
- - name: Change user password in the guest machine
- community.vmware.vmware_vm_shell:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter }}"
- folder: "/{{datacenter}}/vm"
- vm_id: "{{ vm_name }}"
- vm_username: sample
- vm_password: old_password
- vm_shell: "/bin/echo"
- vm_shell_args: "-e 'old_password\nnew_password\nnew_password' | passwd sample > /tmp/$$.txt 2>&1"
- delegate_to: localhost
-
- - name: Change hostname of guest machine
- community.vmware.vmware_vm_shell:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- datacenter: "{{ datacenter }}"
- folder: "/{{datacenter}}/vm"
- vm_id: "{{ vm_name }}"
- vm_username: testUser
- vm_password: SuperSecretPassword
- vm_shell: "/usr/bin/hostnamectl"
- vm_shell_args: "set-hostname new_hostname > /tmp/$$.txt 2>&1"
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>results</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>on success</td>
- <td>
- <div>metadata about the new process after completion with wait_for_process</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;cmd_line&#x27;: &#x27;&quot;/bin/sleep&quot; 1&#x27;, &#x27;end_time&#x27;: &#x27;2018-04-26T05:03:21+00:00&#x27;, &#x27;exit_code&#x27;: 0, &#x27;name&#x27;: &#x27;sleep&#x27;, &#x27;owner&#x27;: &#x27;dev1&#x27;, &#x27;start_time&#x27;: &#x27;2018-04-26T05:03:19+00:00&#x27;, &#x27;uuid&#x27;: &#x27;564db1e2-a3ff-3b0e-8b77-49c25570bb66&#x27;}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Ritesh Khadgaray (@ritzk)
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_vm_storage_policy_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_vm_storage_policy_info_module.rst
deleted file mode 100644
index 1eed0f71a..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_vm_storage_policy_info_module.rst
+++ /dev/null
@@ -1,230 +0,0 @@
-.. _community.vmware.vmware_vm_storage_policy_info_module:
-
-
-**********************************************
-community.vmware.vmware_vm_storage_policy_info
-**********************************************
-
-**Gather information about vSphere storage profile defined storage policy information.**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- Returns basic information on vSphere storage profiles.
-- A vSphere storage profile defines storage policy information that describes storage requirements for virtual machines and storage capabilities of storage providers.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Get SPBM info
- community.vmware.vmware_vm_storage_policy_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- delegate_to: localhost
- register: profiles
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>spbm_profiles</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- </div>
- </td>
- <td>success</td>
- <td>
- <div>list of dictionary of SPBM info</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">[{&#x27;constraints_sub_profiles&#x27;: [{&#x27;rule_set_info&#x27;: [{&#x27;id&#x27;: &#x27;hostFailuresToTolerate&#x27;, &#x27;value&#x27;: 1}, {&#x27;id&#x27;: &#x27;stripeWidth&#x27;, &#x27;value&#x27;: 1}, {&#x27;id&#x27;: &#x27;forceProvisioning&#x27;, &#x27;value&#x27;: False}, {&#x27;id&#x27;: &#x27;proportionalCapacity&#x27;, &#x27;value&#x27;: 0}, {&#x27;id&#x27;: &#x27;cacheReservation&#x27;, &#x27;value&#x27;: 0}], &#x27;rule_set_name&#x27;: &#x27;VSAN sub-profile&#x27;}], &#x27;description&#x27;: &#x27;Storage policy used as default for vSAN datastores&#x27;, &#x27;id&#x27;: &#x27;aa6d5a82-1c88-45da-85d3-3d74b91a5bad&#x27;, &#x27;name&#x27;: &#x27;vSAN Default Storage Policy&#x27;}]</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_vm_storage_policy_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_vm_storage_policy_module.rst
deleted file mode 100644
index 70bf31373..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_vm_storage_policy_module.rst
+++ /dev/null
@@ -1,352 +0,0 @@
-.. _community.vmware.vmware_vm_storage_policy_module:
-
-
-*****************************************
-community.vmware.vmware_vm_storage_policy
-*****************************************
-
-**Create vSphere storage policies**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- A vSphere storage policy defines metadata that describes storage requirements for virtual machines and storage capabilities of storage providers.
-- Currently, only tag-based storage policy creation is supported.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>description</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Description of the storage policy to create or update.</div>
- <div>This parameter is ignored when <code>state=absent</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the storage policy to create, update, or delete.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>absent</li>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>State of storage policy.</div>
- <div>If set to <code>present</code>, the storage policy is created.</div>
- <div>If set to <code>absent</code>, the storage policy is deleted.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>tag_affinity</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>If set to <code>true</code>, the storage policy enforces that virtual machines require the existence of a tag for datastore placement.</div>
- <div>If set to <code>false</code>, the storage policy enforces that virtual machines require the absence of a tag for datastore placement.</div>
- <div>This parameter is ignored when <code>state=absent</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>tag_category</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the pre-existing tag category to assign to the storage policy.</div>
- <div>This parameter is ignored when <code>state=absent</code>.</div>
- <div>This parameter is required when <code>state=present</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>tag_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the pre-existing tag to assign to the storage policy.</div>
- <div>This parameter is ignored when <code>state=absent</code>.</div>
- <div>This parameter is required when <code>state=present</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Create or update a vSphere tag-based storage policy
- community.vmware.vmware_vm_storage_policy:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- name: "vSphere storage policy"
- description: "vSphere storage performance policy"
- tag_category: "performance_tier"
- tag_name: "gold"
- tag_affinity: true
- state: "present"
- delegate_to: localhost
-
- - name: Remove a vSphere tag-based storage policy
- community.vmware.vmware_vm_storage_policy:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- name: "vSphere storage policy"
- state: "absent"
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>vmware_vm_storage_policy</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>success</td>
- <td>
- <div>dictionary of information for the storage policy</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;vmware_vm_storage_policy&#x27;: {&#x27;description&#x27;: &#x27;Storage policy for gold-tier storage&#x27;, &#x27;id&#x27;: &#x27;aa6d5a82-1c88-45da-85d3-3d74b91a5bad&#x27;, &#x27;name&#x27;: &#x27;gold&#x27;}}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Dustin Scott (@scottd018)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_vm_vm_drs_rule_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_vm_vm_drs_rule_module.rst
deleted file mode 100644
index 122c407cc..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_vm_vm_drs_rule_module.rst
+++ /dev/null
@@ -1,392 +0,0 @@
-.. _community.vmware.vmware_vm_vm_drs_rule_module:
-
-
-**************************************
-community.vmware.vmware_vm_vm_drs_rule
-**************************************
-
-**Configure VMware DRS Affinity rule for virtual machines in the given cluster**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to configure VMware DRS Affinity rule for virtual machines in the given cluster.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>affinity_rule</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>If set to <code>true</code>, the DRS rule will be an Affinity rule.</div>
- <div>If set to <code>false</code>, the DRS rule will be an Anti-Affinity rule.</div>
- <div>Effective only if <code>state</code> is set to <code>present</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Desired cluster name where virtual machines are present for the DRS rule.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>drs_rule_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the DRS rule to manage.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>enabled</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>If set to <code>true</code>, the DRS rule will be enabled.</div>
- <div>Effective only if <code>state</code> is set to <code>present</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>mandatory</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>If set to <code>true</code>, the DRS rule will be mandatory.</div>
- <div>Effective only if <code>state</code> is set to <code>present</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>If set to <code>present</code>, then the DRS rule is created if not present.</div>
- <div>If set to <code>present</code>, then the DRS rule is already present, it updates to the given configurations.</div>
- <div>If set to <code>absent</code>, then the DRS rule is deleted if present.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vms</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>List of virtual machines name for which DRS rule needs to be applied.</div>
- <div>Required if <code>state</code> is set to <code>present</code>.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Create DRS Affinity Rule for VM-VM
- community.vmware.vmware_vm_vm_drs_rule:
- hostname: "{{ esxi_server }}"
- username: "{{ esxi_username }}"
- password: "{{ esxi_password }}"
- cluster_name: "{{ cluster_name }}"
- vms:
- - vm1
- - vm2
- drs_rule_name: vm1-vm2-affinity-rule-001
- enabled: true
- mandatory: true
- affinity_rule: true
- delegate_to: localhost
-
- - name: Create DRS Anti-Affinity Rule for VM-VM
- community.vmware.vmware_vm_vm_drs_rule:
- hostname: "{{ esxi_server }}"
- username: "{{ esxi_username }}"
- password: "{{ esxi_password }}"
- cluster_name: "{{ cluster_name }}"
- enabled: true
- vms:
- - vm1
- - vm2
- drs_rule_name: vm1-vm2-affinity-rule-001
- mandatory: true
- affinity_rule: false
- delegate_to: localhost
-
- - name: Delete DRS Affinity Rule for VM-VM
- community.vmware.vmware_vm_vm_drs_rule:
- hostname: "{{ esxi_server }}"
- username: "{{ esxi_username }}"
- password: "{{ esxi_password }}"
- cluster_name: "{{ cluster_name }}"
- drs_rule_name: vm1-vm2-affinity-rule-001
- state: absent
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>result</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>when state is present</td>
- <td>
- <div>metadata about DRS VM and VM rule</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;rule_enabled&#x27;: False, &#x27;rule_key&#x27;: 20, &#x27;rule_mandatory&#x27;: True, &#x27;rule_name&#x27;: &#x27;drs_rule_0014&#x27;, &#x27;rule_uuid&#x27;: &#x27;525f3bc0-253f-825a-418e-2ec93bffc9ae&#x27;, &#x27;rule_vms&#x27;: [&#x27;VM_65&#x27;, &#x27;VM_146&#x27;]}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_vm_vss_dvs_migrate_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_vm_vss_dvs_migrate_module.rst
deleted file mode 100644
index 965b530d9..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_vm_vss_dvs_migrate_module.rst
+++ /dev/null
@@ -1,230 +0,0 @@
-.. _community.vmware.vmware_vm_vss_dvs_migrate_module:
-
-
-******************************************
-community.vmware.vmware_vm_vss_dvs_migrate
-******************************************
-
-**Migrates a virtual machine from a standard vswitch to distributed**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- Migrates a virtual machine from a standard vswitch to distributed
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>dvportgroup_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the portgroup to migrate to the virtual machine to</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vm_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the virtual machine to migrate to a dvSwitch</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Migrate VCSA to vDS
- community.vmware.vmware_vm_vss_dvs_migrate:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- vm_name: '{{ vm_name }}'
- dvportgroup_name: '{{ distributed_portgroup_name }}'
- delegate_to: localhost
-
-
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Joseph Callen (@jcpowermac)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_vmkernel_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_vmkernel_info_module.rst
deleted file mode 100644
index 39b143557..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_vmkernel_info_module.rst
+++ /dev/null
@@ -1,273 +0,0 @@
-.. _community.vmware.vmware_vmkernel_info_module:
-
-
-*************************************
-community.vmware.vmware_vmkernel_info
-*************************************
-
-**Gathers VMKernel info about an ESXi host**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to gather VMKernel information about an ESXi host from given ESXi hostname or cluster name.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the cluster.</div>
- <div>VMKernel information about each ESXi server will be returned for the given cluster.</div>
- <div>If <code>esxi_hostname</code> is not given, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>ESXi hostname.</div>
- <div>VMKernel information about this ESXi server will be returned.</div>
- <div>If <code>cluster_name</code> is not given, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Gather VMKernel info about all ESXi Host in given Cluster
- community.vmware.vmware_vmkernel_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- cluster_name: cluster_name
- delegate_to: localhost
- register: cluster_host_vmks
-
- - name: Gather VMKernel info about ESXi Host
- community.vmware.vmware_vmkernel_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- delegate_to: localhost
- register: host_vmks
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>host_vmk_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>success</td>
- <td>
- <div>metadata about VMKernel present on given host system</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;10.76.33.208&#x27;: [{&#x27;device&#x27;: &#x27;vmk0&#x27;, &#x27;dhcp&#x27;: True, &#x27;enable_ft&#x27;: False, &#x27;enable_management&#x27;: True, &#x27;enable_vmotion&#x27;: False, &#x27;enable_vsan&#x27;: False, &#x27;ipv4_address&#x27;: &#x27;10.76.33.28&#x27;, &#x27;ipv4_subnet_mask&#x27;: &#x27;255.255.255.0&#x27;, &#x27;key&#x27;: &#x27;key-vim.host.VirtualNic-vmk0&#x27;, &#x27;mac&#x27;: &#x27;52:54:00:12:50:ce&#x27;, &#x27;mtu&#x27;: 1500, &#x27;portgroup&#x27;: &#x27;Management Network&#x27;, &#x27;stack&#x27;: &#x27;defaultTcpipStack&#x27;}]}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_vmkernel_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_vmkernel_module.rst
deleted file mode 100644
index 89471fc25..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_vmkernel_module.rst
+++ /dev/null
@@ -1,692 +0,0 @@
-.. _community.vmware.vmware_vmkernel_module:
-
-
-********************************
-community.vmware.vmware_vmkernel
-********************************
-
-**Manages a VMware VMkernel Adapter of an ESXi host.**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to manage the VMKernel adapters / VMKernel network interfaces of an ESXi host.
-- The module assumes that the host is already configured with the Port Group in case of a vSphere Standard Switch (vSS).
-- The module assumes that the host is already configured with the Distributed Port Group in case of a vSphere Distributed Switch (vDS).
-- The module automatically migrates the VMKernel adapter from vSS to vDS or vice versa if present.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="2">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>device</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Search VMkernel adapter by device name.</div>
- <div>The parameter is required only in case of <code>type</code> is set to <code>dhcp</code>.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>dvswitch_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the vSphere Distributed Switch (vDS) where to add the VMKernel interface.</div>
- <div>Required parameter only if <code>state</code> is set to <code>present</code>.</div>
- <div>Optional parameter from version 2.8 and onwards.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: dvswitch</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>enable_ft</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Enable Fault Tolerance traffic on the VMKernel adapter.</div>
- <div>This option is only allowed if the default TCP/IP stack is used.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>enable_mgmt</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Enable Management traffic on the VMKernel adapter.</div>
- <div>This option is only allowed if the default TCP/IP stack is used.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>enable_provisioning</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Enable Provisioning traffic on the VMKernel adapter.</div>
- <div>This option is only allowed if the default TCP/IP stack is used.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>enable_replication</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Enable vSphere Replication traffic on the VMKernel adapter.</div>
- <div>This option is only allowed if the default TCP/IP stack is used.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>enable_replication_nfc</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Enable vSphere Replication NFC traffic on the VMKernel adapter.</div>
- <div>This option is only allowed if the default TCP/IP stack is used.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>enable_vmotion</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Enable vMotion traffic on the VMKernel adapter.</div>
- <div>This option is only allowed if the default TCP/IP stack is used.</div>
- <div>You cannot enable vMotion on an additional adapter if you already have an adapter with the vMotion TCP/IP stack configured.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>enable_vsan</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Enable VSAN traffic on the VMKernel adapter.</div>
- <div>This option is only allowed if the default TCP/IP stack is used.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of ESXi host to which VMKernel is to be managed.</div>
- <div>From version 2.5 onwards, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>mtu</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">1500</div>
- </td>
- <td>
- <div>The MTU for the VMKernel interface.</div>
- <div>The default value of 1500 is valid from version 2.5 and onwards.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>network</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">{"tcpip_stack": "default", "type": "static"}</div>
- </td>
- <td>
- <div>A dictionary of network details.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>default_gateway</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Default gateway (Override default gateway for this adapter).</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>ip_address</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Static IP address.</div>
- <div>Required if <code>type</code> is set to <code>static</code>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>subnet_mask</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Static netmask required.</div>
- <div>Required if <code>type</code> is set to <code>static</code>.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>tcpip_stack</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>default</b>&nbsp;&larr;</div></li>
- <li>provisioning</li>
- <li>vmotion</li>
- <li>vxlan</li>
- </ul>
- </td>
- <td>
- <div>The TCP/IP stack for the VMKernel interface.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>type</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>static</b>&nbsp;&larr;</div></li>
- <li>dhcp</li>
- </ul>
- </td>
- <td>
- <div>Type of IP assignment.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>portgroup_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the port group for the VMKernel interface.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: portgroup</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>If set to <code>present</code>, the VMKernel adapter will be created with the given specifications.</div>
- <div>If set to <code>absent</code>, the VMKernel adapter will be removed.</div>
- <div>If set to <code>present</code> and VMKernel adapter exists, the configurations will be updated.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vswitch_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the vSwitch where to add the VMKernel interface.</div>
- <div>Required parameter only if <code>state</code> is set to <code>present</code>.</div>
- <div>Optional parameter from version 2.5 and onwards.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: vswitch</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - The option ``device`` need to be used with DHCP because otherwise it's not possible to check if a VMkernel device is already present
- - You can only change from DHCP to static, and vSS to vDS, or vice versa, in one step, without creating a new device, with ``device`` specified.
- - You can only create the VMKernel adapter on a vDS if authenticated to vCenter and not if authenticated to ESXi.
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Add Management vmkernel port using static network type
- community.vmware.vmware_vmkernel:
- hostname: '{{ esxi_hostname }}'
- username: '{{ esxi_username }}'
- password: '{{ esxi_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- vswitch_name: vSwitch0
- portgroup_name: PG_0001
- network:
- type: 'static'
- ip_address: 192.168.127.10
- subnet_mask: 255.255.255.0
- state: present
- enable_mgmt: true
- delegate_to: localhost
-
- - name: Add Management vmkernel port using DHCP network type
- community.vmware.vmware_vmkernel:
- hostname: '{{ esxi_hostname }}'
- username: '{{ esxi_username }}'
- password: '{{ esxi_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- vswitch_name: vSwitch0
- portgroup_name: PG_0002
- state: present
- network:
- type: 'dhcp'
- enable_mgmt: true
- delegate_to: localhost
-
- - name: Change IP allocation from static to dhcp
- community.vmware.vmware_vmkernel:
- hostname: '{{ esxi_hostname }}'
- username: '{{ esxi_username }}'
- password: '{{ esxi_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- vswitch_name: vSwitch0
- portgroup_name: PG_0002
- state: present
- device: vmk1
- network:
- type: 'dhcp'
- enable_mgmt: true
- delegate_to: localhost
-
- - name: Delete VMkernel port
- community.vmware.vmware_vmkernel:
- hostname: '{{ esxi_hostname }}'
- username: '{{ esxi_username }}'
- password: '{{ esxi_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- vswitch_name: vSwitch0
- portgroup_name: PG_0002
- state: absent
- delegate_to: localhost
-
- - name: Add Management vmkernel port to Distributed Switch
- community.vmware.vmware_vmkernel:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- dvswitch_name: dvSwitch1
- portgroup_name: dvPG_0001
- network:
- type: 'static'
- ip_address: 192.168.127.10
- subnet_mask: 255.255.255.0
- state: present
- enable_mgmt: true
- delegate_to: localhost
-
- - name: Add vMotion vmkernel port with vMotion TCP/IP stack
- community.vmware.vmware_vmkernel:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- dvswitch_name: dvSwitch1
- portgroup_name: dvPG_0001
- network:
- type: 'static'
- ip_address: 192.168.127.10
- subnet_mask: 255.255.255.0
- tcpip_stack: vmotion
- state: present
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>result</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>metadata about VMKernel name</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;changed&#x27;: False, &#x27;msg&#x27;: &#x27;VMkernel Adapter already configured properly&#x27;, &#x27;device&#x27;: &#x27;vmk1&#x27;, &#x27;ipv4&#x27;: &#x27;static&#x27;, &#x27;ipv4_gw&#x27;: &#x27;No override&#x27;, &#x27;ipv4_ip&#x27;: &#x27;192.168.1.15&#x27;, &#x27;ipv4_sm&#x27;: &#x27;255.255.255.0&#x27;, &#x27;mtu&#x27;: 9000, &#x27;services&#x27;: &#x27;vMotion&#x27;, &#x27;switch&#x27;: &#x27;vDS&#x27;}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Joseph Callen (@jcpowermac)
-- Russell Teague (@mtnbikenc)
-- Abhijeet Kasurde (@Akasurde)
-- Christian Kotte (@ckotte)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_vmotion_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_vmotion_module.rst
deleted file mode 100644
index a9806a413..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_vmotion_module.rst
+++ /dev/null
@@ -1,486 +0,0 @@
-.. _community.vmware.vmware_vmotion_module:
-
-
-*******************************
-community.vmware.vmware_vmotion
-*******************************
-
-**Move a virtual machine using vMotion, and/or its vmdks using storage vMotion.**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- Using VMware vCenter, move a virtual machine using vMotion to a different host, and/or its vmdks to another datastore using storage vMotion.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>destination_cluster</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 2.5.0</div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the destination cluster the virtual machine should be running on.</div>
- <div>Only works if drs is enabled for this cluster.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>destination_datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the destination datacenter the datastore is located on.</div>
- <div>Optional, required only when datastores are shared across datacenters.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>destination_datastore</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the destination datastore the virtual machine&#x27;s vmdk should be moved on.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: datastore</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>destination_datastore_cluster</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 2.5.0</div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the destination datastore cluster (storage pod) the virtual machine&#x27;s vmdk should be moved on.</div>
- <div>Only works if drs is enabled for the cluster the vm is running / should run.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>destination_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the destination host the virtual machine should be running on.</div>
- <div>Version 2.6 onwards, this parameter is not a required parameter, unlike the previous versions.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: destination</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>destination_resourcepool</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the destination resource pool where the virtual machine should be running.</div>
- <div>Resource pool is required if vmotion is done between hosts which are part of different clusters or datacenters.</div>
- <div>if not passed, resource_pool object will be retrived from host_obj parent.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: resource_pool</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>moid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.</div>
- <div>This is required if <code>vm_name</code> or <code>vm_uuid</code> is not supplied.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>timeout</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 3.4.0</div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">3600</div>
- </td>
- <td>
- <div>The timeout in seconds. When the timeout is reached, the module will fail.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>use_instance_uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether to use the VMware instance UUID rather than the BIOS UUID.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vm_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the VM to perform a vMotion on.</div>
- <div>This is required parameter, if <code>vm_uuid</code> is not set.</div>
- <div>Version 2.6 onwards, this parameter is not a required parameter, unlike the previous versions.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: vm</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>vm_uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>UUID of the virtual machine to perform a vMotion operation on.</div>
- <div>This is a required parameter, if <code>vm_name</code> or <code>moid</code> is not set.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: uuid</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Perform vMotion of virtual machine
- community.vmware.vmware_vmotion:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- vm_name: 'vm_name_as_per_vcenter'
- destination_host: 'destination_host_as_per_vcenter'
- delegate_to: localhost
-
- - name: Perform vMotion of virtual machine
- community.vmware.vmware_vmotion:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- moid: vm-42
- destination_host: 'destination_host_as_per_vcenter'
- delegate_to: localhost
-
- - name: Perform vMotion of virtual machine to resource_pool
- community.vmware.vmware_vmotion:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- moid: vm-42
- destination_host: 'destination_host_as_per_vcenter'
- destination_resourcepool: 'destination_resourcepool_as_per_vcenter'
- delegate_to: localhost
-
- - name: Perform storage vMotion of virtual machine
- community.vmware.vmware_vmotion:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- vm_name: 'vm_name_as_per_vcenter'
- destination_datastore: 'destination_datastore_as_per_vcenter'
- delegate_to: localhost
-
- - name: Perform storage vMotion and host vMotion of virtual machine
- community.vmware.vmware_vmotion:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- vm_name: 'vm_name_as_per_vcenter'
- destination_host: 'destination_host_as_per_vcenter'
- destination_datastore: 'destination_datastore_as_per_vcenter'
- delegate_to: localhost
-
- - name: Perform storage vMotion to a Storage Cluster and vMotion to a Cluster of virtual machine
- community.vmware.vmware_vmotion:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- vm_name: 'vm_name_as_per_vcenter'
- destination_cluster: 'destination_cluster_as_per_vcenter'
- destination_datastore_cluster: 'destination_datastore_cluster_as_per_vcenter'
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>datastore</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>changed or success</td>
- <td>
- <div>List the datastore the virtual machine is on.</div>
- <div>Only returned if there is asked for a Storage vMotion (Datastore or Datastore Cluster).</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">datastore1</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>running_host</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>changed or success</td>
- <td>
- <div>List the host the virtual machine is registered to.</div>
- <div>Only returned if there is asked for a vMotion (Cluster or Host).</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">host1.example.com</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Bede Carroll (@bedecarroll)
-- Olivier Boukili (@oboukili)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_vsan_cluster_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_vsan_cluster_module.rst
deleted file mode 100644
index bc3263544..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_vsan_cluster_module.rst
+++ /dev/null
@@ -1,226 +0,0 @@
-.. _community.vmware.vmware_vsan_cluster_module:
-
-
-************************************
-community.vmware.vmware_vsan_cluster
-************************************
-
-**Configure VSAN clustering on an ESXi host**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to configure VSAN clustering on an ESXi host
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_uuid</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Desired cluster UUID</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Configure VMware VSAN Cluster
- hosts: deploy_node
- tags:
- - vsan
- tasks:
- - name: Configure VSAN on first host
- community.vmware.vmware_vsan_cluster:
- hostname: "{{ groups['esxi'][0] }}"
- username: "{{ esxi_username }}"
- password: "{{ site_password }}"
- delegate_to: localhost
- register: vsan_cluster
-
- - name: Configure VSAN on remaining hosts
- community.vmware.vmware_vsan_cluster:
- hostname: "{{ item }}"
- username: "{{ esxi_username }}"
- password: "{{ site_password }}"
- cluster_uuid: "{{ vsan_cluster.cluster_uuid }}"
- delegate_to: localhost
- loop: "{{ groups['esxi'][1:] }}"
-
-
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Russell Teague (@mtnbikenc)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_vsan_hcl_db_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_vsan_hcl_db_module.rst
deleted file mode 100644
index 47328c6e7..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_vsan_hcl_db_module.rst
+++ /dev/null
@@ -1,228 +0,0 @@
-.. _community.vmware.vmware_vsan_hcl_db_module:
-
-
-***********************************
-community.vmware.vmware_vsan_hcl_db
-***********************************
-
-**Manages the vSAN Hardware Compatibility List (HCL) database**
-
-
-Version added: 3.5.0
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- Manages vSAN HCL db on vSphere
-- DB file can be downloaded from https://partnerweb.vmware.com/service/vsan/all.json
-
-
-
-Requirements
-------------
-The below requirements are needed on the host that executes this module.
-
-- vSAN Management SDK, which needs to be downloaded from VMware and installed manually.
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>source</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The path to the HCL db file</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Fetch HCL db file
- ansible.builtin.get_url:
- url: https://partnerweb.vmware.com/service/vsan/all.json
- dest: hcl_db.json
- force: true
- delegate_to: localhost
-
- - name: Upload HCL db file to vCenter
- community.vmware.vmware_vsan_hcl_db:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- source: hcl_db.json
- delegate_to: localhost
-
-
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Philipp Fruck (@p-fruck)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_vsan_health_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_vsan_health_info_module.rst
deleted file mode 100644
index fea57f715..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_vsan_health_info_module.rst
+++ /dev/null
@@ -1,295 +0,0 @@
-.. _community.vmware.vmware_vsan_health_info_module:
-
-
-****************************************
-community.vmware.vmware_vsan_health_info
-****************************************
-
-**Gather information about a VMware vSAN cluster's health**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- Gather information about a VMware vSAN cluster's health.
-
-
-
-Requirements
-------------
-The below requirements are needed on the host that executes this module.
-
-- VMware vSAN Python's SDK
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the vSAN cluster.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the Datacenter.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: datacenter_name</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>fetch_from_cache</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div><code>true</code> to return the result from cache directly instead of running the full health check.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Gather health info from a vSAN's cluster
- community.vmware.vmware_vsan_health_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- cluster_name: 'vSAN01'
- fetch_from_cache: false
-
- - name: Gather health info from a vSAN's cluster with datacenter
- community.vmware.vmware_vsan_health_info:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- cluster_name: 'vSAN01'
- datacenter: 'Datacenter_01'
- fetch_from_cache: true
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>vsan_health_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>on success</td>
- <td>
- <div>vSAN cluster health info</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;_vimtype&#x27;: &#x27;vim.cluster.VsanClusterHealthSummary&#x27;, &#x27;burnInTest&#x27;: None, &#x27;clusterStatus&#x27;: {&#x27;_vimtype&#x27;: &#x27;vim.cluster.VsanClusterHealthSystemStatusResult&#x27;, &#x27;goalState&#x27;: &#x27;installed&#x27;, &#x27;status&#x27;: &#x27;green&#x27;, &#x27;trackedHostsStatus&#x27;: [{&#x27;_vimtype&#x27;: &#x27;vim.host.VsanHostHealthSystemStatusResult&#x27;, &#x27;hostname&#x27;: &#x27;esxi01.example.com&#x27;, &#x27;issues&#x27;: [], &#x27;status&#x27;: &#x27;green&#x27;}, {&#x27;_vimtype&#x27;: &#x27;vim.host.VsanHostHealthSystemStatusResult&#x27;, &#x27;hostname&#x27;: &#x27;esxi04.example.com&#x27;, &#x27;issues&#x27;: [], &#x27;status&#x27;: &#x27;green&#x27;}, {&#x27;_vimtype&#x27;: &#x27;vim.host.VsanHostHealthSystemStatusResult&#x27;, &#x27;hostname&#x27;: &#x27;esxi02.example.com&#x27;, &#x27;issues&#x27;: [], &#x27;status&#x27;: &#x27;green&#x27;}, {&#x27;_vimtype&#x27;: &#x27;vim.host.VsanHostHealthSystemStatusResult&#x27;, &#x27;hostname&#x27;: &#x27;esxi03.example.com&#x27;, &#x27;issues&#x27;: [], &#x27;status&#x27;: &#x27;green&#x27;}], &#x27;untrackedHosts&#x27;: []}}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Erwan Quelin (@equelin)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_vsan_release_catalog_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_vsan_release_catalog_module.rst
deleted file mode 100644
index f4ed2792b..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_vsan_release_catalog_module.rst
+++ /dev/null
@@ -1,221 +0,0 @@
-.. _community.vmware.vmware_vsan_release_catalog_module:
-
-
-********************************************
-community.vmware.vmware_vsan_release_catalog
-********************************************
-
-**Uploads the vSAN Release Catalog**
-
-
-Version added: 3.7.0
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- Manually upload the vSAN Release Catalog the the vCenter
-- See https://kb.vmware.com/s/article/58891 for more details
-
-
-
-Requirements
-------------
-The below requirements are needed on the host that executes this module.
-
-- vSAN Management SDK, which needs to be downloaded from VMware and installed manually.
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>source</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The path to the release catalog file</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Upload release catalog file to vCenter
- community.vmware.vmware_vsan_release_catalog:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- source: release_catalog.json
- delegate_to: localhost
-
-
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Philipp Fruck (@p-fruck)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_vspan_session_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_vspan_session_module.rst
deleted file mode 100644
index 9adf4dc79..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_vspan_session_module.rst
+++ /dev/null
@@ -1,622 +0,0 @@
-.. _community.vmware.vmware_vspan_session_module:
-
-
-*************************************
-community.vmware.vmware_vspan_session
-*************************************
-
-**Create or remove a Port Mirroring session.**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to create, delete or edit different kind of port mirroring sessions.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="2">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>description</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The description for the session.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>destination_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Destination port that received the mirrored packets.</div>
- <div>Also any port designated in the value of this property can not match the source port in any of the Distributed Port Mirroring session.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>destination_vm</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>With this parameter it is possible, to add a NIC of a VM to a port mirroring session.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the VM.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>nic_label</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Label of the network interface card to use.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>enabled</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Whether the session is enabled.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>encapsulation_vlan_id</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>VLAN ID used to encapsulate the mirrored traffic.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>mirrored_packet_length</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>An integer that describes how much of each frame to mirror.</div>
- <div>If unset, all of the frame would be mirrored.</div>
- <div>Setting this property to a smaller value is useful when the consumer will look only at the headers.</div>
- <div>The value cannot be less than 60.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the session.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>normal_traffic_allowed</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether or not destination ports can send and receive &quot;normal&quot; traffic.</div>
- <div>Setting this to false will make mirror ports be used solely for mirroring and not double as normal access ports.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>sampling_rate</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Sampling rate of the session.</div>
- <div>If its value is n, one of every n packets is mirrored.</div>
- <div>Valid values are between 1 to 65535.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>session_type</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>encapsulatedRemoteMirrorSource</li>
- <li>remoteMirrorDest</li>
- <li>remoteMirrorSource</li>
- <li><div style="color: blue"><b>dvPortMirror</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Select the mirroring type.</div>
- <div>In <code>encapsulatedRemoteMirrorSource</code> session, Distributed Ports can be used as source entities, and IP address can be used as destination entities.</div>
- <div>In <code>remoteMirrorDest</code> session, VLAN IDs can be used as source entities, and Distributed Ports can be used as destination entities.</div>
- <div>In <code>remoteMirrorSource</code> session, Distributed Ports can be used as source entities, and uplink ports name can be used as destination entities.</div>
- <div>In <code>dvPortMirror</code> session, Distributed Ports can be used as both source and destination entities.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>source_port_received</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Source port for which received packets are mirrored.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>source_port_transmitted</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Source port for which transmitted packets are mirrored.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>source_vm_received</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>With this parameter it is possible, to add a NIC of a VM to a port mirroring session.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the VM.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>nic_label</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Label of the network interface card to use.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>source_vm_transmitted</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>With this parameter it is possible, to add a NIC of a VM to a port mirroring session.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the VM.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>nic_label</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Label of the network interface card to use.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>present</li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>Create or remove the session.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>strip_original_vlan</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Whether to strip the original VLAN tag.</div>
- <div>If false, the original VLAN tag will be preserved on the mirrored traffic.</div>
- <div>If <code>encapsulationVlanId</code> has been set and this property is false, the frames will be double tagged with the original VLAN ID as the inner tag.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>switch</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The name of the distributed vSwitch on which to add or remove the mirroring session.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: switch_name</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Create distributed mirroring session.
- community.vmware.vmware_vspan_session:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- switch_name: dvSwitch
- state: present
- name: Basic Session
- enabled: true
- description: "Example description"
- source_port_transmitted: 817
- source_port_received: 817
- destination_port: 815
- delegate_to: localhost
-
- - name: Create remote destination mirroring session.
- community.vmware.vmware_vspan_session:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- switch_name: dvSwitch
- state: present
- name: Remote Session
- enabled: true
- description: "Example description"
- source_port_received: 105
- destination_port: 815
- session_type: "remoteMirrorDest"
- delegate_to: localhost
-
- - name: Delete remote destination mirroring session.
- community.vmware.vmware_vspan_session:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- switch_name: dvSwitch
- state: absent
- name: Remote Session
- delegate_to: localhost
-
-
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Peter Gyorgy (@gyorgypeter)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_vswitch_info_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_vswitch_info_module.rst
deleted file mode 100644
index 9864dd4fb..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_vswitch_info_module.rst
+++ /dev/null
@@ -1,296 +0,0 @@
-.. _community.vmware.vmware_vswitch_info_module:
-
-
-************************************
-community.vmware.vmware_vswitch_info
-************************************
-
-**Gathers info about an ESXi host's vswitch configurations**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to gather information about an ESXi host's vswitch configurations when ESXi hostname or Cluster name is given.
-- The vSphere Client shows the value for the number of ports as elastic from vSphere 5.5 and above.
-- Other tools like esxcli might show the number of ports as 1536 or 5632.
-- See https://kb.vmware.com/s/article/2064511 for more details.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the cluster.</div>
- <div>Info about vswitch belonging to every ESXi host systems under this cluster will be returned.</div>
- <div>If <code>esxi_hostname</code> is not given, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>ESXi hostname to gather information from.</div>
- <div>If <code>cluster_name</code> is not given, this parameter is required.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>policies</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 2.4.0</div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Gather information about Security, Traffic Shaping, as well as Teaming and failover.</div>
- <div>The property <code>ts</code> stands for Traffic Shaping and <code>lb</code> for Load Balancing.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Gather vswitch info about all ESXi Host in given Cluster
- community.vmware.vmware_vswitch_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- cluster_name: '{{ cluster_name }}'
- delegate_to: localhost
- register: all_hosts_vswitch_info
-
- - name: Gather vswitch info about ESXi Host
- community.vmware.vmware_vswitch_info:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- delegate_to: localhost
- register: all_vswitch_info
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>hosts_vswitch_info</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- </td>
- <td>on success</td>
- <td>
- <div>metadata about host&#x27;s vswitch configuration</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">{&#x27;10.76.33.218&#x27;: {&#x27;vSwitch0&#x27;: {&#x27;mtu&#x27;: 1500, &#x27;num_ports&#x27;: 128, &#x27;pnics&#x27;: [&#x27;vmnic0&#x27;], &#x27;failback&#x27;: True, &#x27;failover_active&#x27;: [&#x27;vmnic0&#x27;], &#x27;failover_standby&#x27;: [], &#x27;failure_detection&#x27;: &#x27;link_status_only&#x27;, &#x27;lb&#x27;: &#x27;loadbalance_srcid&#x27;, &#x27;notify&#x27;: True, &#x27;security&#x27;: [False, False, False], &#x27;ts&#x27;: False}, &#x27;vSwitch_0011&#x27;: {&#x27;mtu&#x27;: 1500, &#x27;num_ports&#x27;: 128, &#x27;pnics&#x27;: [&#x27;vmnic2&#x27;, &#x27;vmnic1&#x27;], &#x27;failback&#x27;: True, &#x27;failover_active&#x27;: [&#x27;vmnic1&#x27;], &#x27;failover_standby&#x27;: [&#x27;vmnic2&#x27;], &#x27;failure_detection&#x27;: &#x27;link_status_only&#x27;, &#x27;lb&#x27;: &#x27;loadbalance_srcid&#x27;, &#x27;notify&#x27;: True, &#x27;security&#x27;: [False, False, False], &#x27;ts&#x27;: False}}}</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Abhijeet Kasurde (@Akasurde)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vmware_vswitch_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vmware_vswitch_module.rst
deleted file mode 100644
index 4f6b98af4..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vmware_vswitch_module.rst
+++ /dev/null
@@ -1,727 +0,0 @@
-.. _community.vmware.vmware_vswitch_module:
-
-
-*******************************
-community.vmware.vmware_vswitch
-*******************************
-
-**Manage a VMware Standard Switch to an ESXi host.**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- This module can be used to add, remove and update a VMware Standard Switch to an ESXi host.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="2">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>esxi_hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Manage the vSwitch using this ESXi host system.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: host</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>mtu</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">1500</div>
- </td>
- <td>
- <div>MTU to configure on vSwitch.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>nics</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">[]</div>
- </td>
- <td>
- <div>A list of vmnic names or vmnic name to attach to vSwitch.</div>
- <div>Alias <code>nics</code> is added in version 2.4.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: nic_name</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>number_of_ports</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">128</div>
- </td>
- <td>
- <div>Number of port to configure on vSwitch.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>security</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 2.4.0</div>
- </td>
- <td>
- </td>
- <td>
- <div>Network policy specifies layer 2 security settings for a portgroup such as promiscuous mode, where guest adapter listens to all the packets, MAC address changes and forged transmits.</div>
- <div>Dict which configures the different security values for portgroup.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: security_policy, network_policy</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>forged_transmits</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Indicates whether forged transmits are allowed.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>mac_changes</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Indicates whether mac changes are allowed.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>promiscuous_mode</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Indicates whether promiscuous mode is allowed.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>absent</li>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Add or remove the switch.</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>switch</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>vSwitch name to add.</div>
- <div>Alias <code>switch</code> is added in version 2.4.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: switch_name</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>teaming</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 2.4.0</div>
- </td>
- <td>
- </td>
- <td>
- <div>Dictionary which configures the different teaming values for portgroup.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: teaming_policy</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>active_adapters</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>List of active adapters used for load balancing.</div>
- <div>All vmnics are used as active adapters if <code>active_adapters</code> and <code>standby_adapters</code> are not defined.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>failback</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Indicate whether or not to use a failback when restoring links.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>load_balancing</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>loadbalance_ip</li>
- <li>loadbalance_srcmac</li>
- <li>loadbalance_srcid</li>
- <li>failover_explicit</li>
- </ul>
- </td>
- <td>
- <div>Network adapter teaming policy.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: load_balance_policy</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>network_failure_detection</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>link_status_only</li>
- <li>beacon_probing</li>
- </ul>
- </td>
- <td>
- <div>Network failure detection.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>notify_switches</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Indicate whether or not to notify the physical switch if a link fails.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>standby_adapters</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>List of standby adapters used for failover.</div>
- <div>All vmnics are used as active adapters if <code>active_adapters</code> and <code>standby_adapters</code> are not defined.</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>traffic_shaping</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">dictionary</span>
- </div>
- <div style="font-style: italic; font-size: small; color: darkgreen">added in 2.4.0</div>
- </td>
- <td>
- </td>
- <td>
- <div>Dictionary which configures traffic shaping for the switch.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>average_bandwidth</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Average bandwidth (kbit/s).</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>burst_size</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Burst size (KB).</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>enabled</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li>yes</li>
- </ul>
- </td>
- <td>
- <div>Status of Traffic Shaping Policy.</div>
- </td>
- </tr>
- <tr>
- <td class="elbow-placeholder"></td>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>peak_bandwidth</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Peak bandwidth (kbit/s).</div>
- </td>
- </tr>
-
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Add a VMware vSwitch
- community.vmware.vmware_vswitch:
- hostname: '{{ esxi_hostname }}'
- username: '{{ esxi_username }}'
- password: '{{ esxi_password }}'
- switch: vswitch_name
- nics: vmnic_name
- mtu: 9000
- delegate_to: localhost
-
- - name: Add a VMware vSwitch without any physical NIC attached
- community.vmware.vmware_vswitch:
- hostname: '{{ esxi_hostname }}'
- username: '{{ esxi_username }}'
- password: '{{ esxi_password }}'
- switch: vswitch_0001
- mtu: 9000
- delegate_to: localhost
-
- - name: Add a VMware vSwitch with multiple NICs
- community.vmware.vmware_vswitch:
- hostname: '{{ esxi_hostname }}'
- username: '{{ esxi_username }}'
- password: '{{ esxi_password }}'
- switch: vmware_vswitch_0004
- nics:
- - vmnic1
- - vmnic2
- mtu: 9000
- delegate_to: localhost
-
- - name: Add a VMware vSwitch to a specific host system
- community.vmware.vmware_vswitch:
- hostname: '{{ esxi_hostname }}'
- username: '{{ esxi_username }}'
- password: '{{ esxi_password }}'
- esxi_hostname: DC0_H0
- switch_name: vswitch_001
- nic_name: vmnic0
- mtu: 9000
- delegate_to: localhost
-
- - name: Add a VMware vSwitch to a specific host system with Promiscuous Mode Enabled
- community.vmware.vmware_vswitch:
- hostname: '{{ esxi_hostname }}'
- username: '{{ esxi_username }}'
- password: '{{ esxi_password }}'
- esxi_hostname: DC0_H0
- switch_name: vswitch_001
- nic_name: vmnic0
- mtu: 9000
- security:
- promiscuous_mode: true
- delegate_to: localhost
-
- - name: Add a VMware vSwitch to a specific host system with active/standby teaming
- community.vmware.vmware_vswitch:
- hostname: '{{ esxi_hostname }}'
- username: '{{ esxi_username }}'
- password: '{{ esxi_password }}'
- esxi_hostname: DC0_H0
- switch_name: vswitch_001
- nic_name:
- - vmnic0
- - vmnic1
- teaming:
- active_adapters:
- - vmnic0
- standby_adapters:
- - vmnic1
- delegate_to: localhost
-
- - name: Add a VMware vSwitch to a specific host system with traffic shaping
- community.vmware.vmware_vswitch:
- hostname: '{{ esxi_hostname }}'
- username: '{{ esxi_username }}'
- password: '{{ esxi_password }}'
- esxi_hostname: DC0_H0
- switch_name: vswitch_001
- nic_name:
- - vmnic0
- - vmnic1
- traffic_shaping:
- enabled: true
- average_bandwidth: 100000
- peak_bandwidth: 100000
- burst_size: 102400
- delegate_to: localhost
-
- - name: Delete a VMware vSwitch in a specific host system
- community.vmware.vmware_vswitch:
- hostname: '{{ esxi_hostname }}'
- username: '{{ esxi_username }}'
- password: '{{ esxi_password }}'
- esxi_hostname: DC0_H0
- switch_name: vswitch_001
- state: absent
- delegate_to: localhost
-
-
-
-Return Values
--------------
-Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Key</th>
- <th>Returned</th>
- <th width="100%">Description</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="return-"></div>
- <b>result</b>
- <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>always</td>
- <td>
- <div>information about performed operation</div>
- <br/>
- <div style="font-size: smaller"><b>Sample:</b></div>
- <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">vSwitch &#x27;vSwitch_1002&#x27; is created successfully</div>
- </td>
- </tr>
- </table>
- <br/><br/>
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Joseph Callen (@jcpowermac)
-- Russell Teague (@mtnbikenc)
-- Abhijeet Kasurde (@Akasurde) <akasurde@redhat.com>
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vsan_health_silent_checks_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vsan_health_silent_checks_module.rst
deleted file mode 100644
index 4f4d49c07..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vsan_health_silent_checks_module.rst
+++ /dev/null
@@ -1,271 +0,0 @@
-.. _community.vmware.vsan_health_silent_checks_module:
-
-
-******************************************
-community.vmware.vsan_health_silent_checks
-******************************************
-
-**Silence vSAN health checks**
-
-
-Version added: 3.6.0
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- Take a list of vSAN health checks and silence them
-- Re-enable alerts for previously silenced health checks
-
-
-
-Requirements
-------------
-The below requirements are needed on the host that executes this module.
-
-- vSAN Management SDK, which needs to be downloaded from VMware and installed manually.
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>checks</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">list</span>
- / <span style="color: purple">elements=string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The checks to silence.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>cluster_name</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Name of the vSAN cluster.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li><div style="color: blue"><b>present</b>&nbsp;&larr;</div></li>
- <li>absent</li>
- </ul>
- </td>
- <td>
- <div>The state of the health checks.</div>
- <div>If set to <code>present</code>, all given health checks will be silenced.</div>
- <div>If set to <code>absent</code>, all given health checks will be removed from the list of silent checks.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Disable the vSAN Support Insight health check
- community.vmware.vsan_health_silent_checks:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- checks: vsanenablesupportinsight
- cluster_name: 'vSAN01'
- delegate_to: localhost
-
- - name: Re-enable health check alerts for release catalog and HCL DB
- community.vmware.vsan_health_silent_checks:
- hostname: "{{ vcenter_hostname }}"
- username: "{{ vcenter_username }}"
- password: "{{ vcenter_password }}"
- checks:
- - releasecataloguptodate
- - autohclupdate
- state: absent
- cluster_name: 'vSAN01'
- delegate_to: localhost
-
-
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Philipp Fruck (@p-fruck)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vsphere_copy_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vsphere_copy_module.rst
deleted file mode 100644
index 8df8c2e2b..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vsphere_copy_module.rst
+++ /dev/null
@@ -1,304 +0,0 @@
-.. _community.vmware.vsphere_copy_module:
-
-
-*****************************
-community.vmware.vsphere_copy
-*****************************
-
-**Copy a file to a VMware datastore**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- Upload files to a VMware datastore through a vCenter REST API.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The datacenter on the vCenter server that holds the datastore.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datastore</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The datastore to push files to.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>hostname</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The hostname or IP address of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_HOST</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PASSWORD</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: pass, pwd</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>path</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The file to push to the datastore.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: dest</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">443</div>
- </td>
- <td>
- <div>The port number of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PORT</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Address of a proxy that will receive all HTTPS requests and relay them.</div>
- <div>The format is a hostname or a IP.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_HOST</code> will be used instead.</div>
- <div>This feature depends on a version of pyvmomi greater than v6.7.1.2018.12</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>proxy_port</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>Port of the HTTP proxy that will receive all HTTPS requests and relay them.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_PROXY_PORT</code> will be used instead.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>src</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The file to push to vCenter.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: name</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>timeout</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">10</div>
- </td>
- <td>
- <div>The timeout in seconds for the upload to the datastore.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The username of the vSphere vCenter or ESXi server.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_USER</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: admin, user</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>Allows connection when SSL certificates are not valid. Set to <code>false</code> when certificates are not trusted.</div>
- <div>If the value is not specified in the task, the value of environment variable <code>VMWARE_VALIDATE_CERTS</code> will be used instead.</div>
- <div>Environment variable support added in Ansible 2.6.</div>
- <div>If set to <code>true</code>, please make sure Python &gt;= 2.7.9 is installed on the given machine.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - This module ought to be run from a system that can access the vCenter or the ESXi directly and has the file to transfer. It can be the normal remote target or you can change it either by using ``transport: local`` or using ``delegate_to``.
- - All modules requires API write access and hence is not supported on a free ESXi license.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Copy file to datastore using delegate_to
- community.vmware.vsphere_copy:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- src: /some/local/file
- datacenter: DC1 Someplace
- datastore: datastore1
- path: some/remote/file
- delegate_to: localhost
-
- - name: Copy file to datastore when datacenter is inside folder called devel
- community.vmware.vsphere_copy:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- src: /some/local/file
- datacenter: devel/DC1
- datastore: datastore1
- path: some/remote/file
- delegate_to: localhost
-
- - name: Copy file to datastore using other_system
- community.vmware.vsphere_copy:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- src: /other/local/file
- datacenter: DC2 Someplace
- datastore: datastore2
- path: other/remote/file
- delegate_to: other_system
-
-
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Dag Wieers (@dagwieers)
diff --git a/ansible_collections/community/vmware/docs/community.vmware.vsphere_file_module.rst b/ansible_collections/community/vmware/docs/community.vmware.vsphere_file_module.rst
deleted file mode 100644
index b27448c9e..000000000
--- a/ansible_collections/community/vmware/docs/community.vmware.vsphere_file_module.rst
+++ /dev/null
@@ -1,265 +0,0 @@
-.. _community.vmware.vsphere_file_module:
-
-
-*****************************
-community.vmware.vsphere_file
-*****************************
-
-**Manage files on a vCenter datastore**
-
-
-
-.. contents::
- :local:
- :depth: 1
-
-
-Synopsis
---------
-- Manage files on a vCenter datastore.
-
-
-
-
-Parameters
-----------
-
-.. raw:: html
-
- <table border=0 cellpadding=0 class="documentation-table">
- <tr>
- <th colspan="1">Parameter</th>
- <th>Choices/<font color="blue">Defaults</font></th>
- <th width="100%">Comments</th>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datacenter</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The datacenter on the vCenter server that holds the datastore.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>datastore</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The datastore on the vCenter server to push files to.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>host</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The vCenter server on which the datastore is available.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: hostname</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>password</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The password to authenticate on the vCenter server.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>path</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The file or directory on the datastore on the vCenter server.</div>
- <div style="font-size: small; color: darkgreen"><br/>aliases: dest</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>state</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>absent</li>
- <li>directory</li>
- <li><div style="color: blue"><b>file</b>&nbsp;&larr;</div></li>
- <li>touch</li>
- </ul>
- </td>
- <td>
- <div>The state of or the action on the provided path.</div>
- <div>If <code>absent</code>, the file will be removed.</div>
- <div>If <code>directory</code>, the directory will be created.</div>
- <div>If <code>file</code>, more information of the (existing) file will be returned.</div>
- <div>If <code>touch</code>, an empty file will be created if the path does not exist.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>timeout</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">integer</span>
- </div>
- </td>
- <td>
- <b>Default:</b><br/><div style="color: blue">10</div>
- </td>
- <td>
- <div>The timeout in seconds for the upload to the datastore.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>username</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">string</span>
- / <span style="color: red">required</span>
- </div>
- </td>
- <td>
- </td>
- <td>
- <div>The user name to authenticate on the vCenter server.</div>
- </td>
- </tr>
- <tr>
- <td colspan="1">
- <div class="ansibleOptionAnchor" id="parameter-"></div>
- <b>validate_certs</b>
- <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
- <div style="font-size: small">
- <span style="color: purple">boolean</span>
- </div>
- </td>
- <td>
- <ul style="margin: 0; padding: 0"><b>Choices:</b>
- <li>no</li>
- <li><div style="color: blue"><b>yes</b>&nbsp;&larr;</div></li>
- </ul>
- </td>
- <td>
- <div>If <code>false</code>, SSL certificates will not be validated. This should only be set to <code>false</code> when no other option exists.</div>
- </td>
- </tr>
- </table>
- <br/>
-
-
-Notes
------
-
-.. note::
- - The vSphere folder API does not allow to remove directory objects.
-
-
-
-Examples
---------
-
-.. code-block:: yaml
-
- - name: Create an empty file on a datastore
- community.vmware.vsphere_file:
- host: '{{ vhost }}'
- username: '{{ vuser }}'
- password: '{{ vpass }}'
- datacenter: DC1 Someplace
- datastore: datastore1
- path: some/remote/file
- state: touch
- delegate_to: localhost
-
- - name: Create a directory on a datastore
- community.vmware.vsphere_file:
- host: '{{ vhost }}'
- username: '{{ vuser }}'
- password: '{{ vpass }}'
- datacenter: DC2 Someplace
- datastore: datastore2
- path: other/remote/file
- state: directory
- delegate_to: localhost
-
- - name: Query a file on a datastore
- community.vmware.vsphere_file:
- host: '{{ vhost }}'
- username: '{{ vuser }}'
- password: '{{ vpass }}'
- datacenter: DC1 Someplace
- datastore: datastore1
- path: some/remote/file
- state: file
- delegate_to: localhost
- ignore_errors: true
-
- - name: Delete a file on a datastore
- community.vmware.vsphere_file:
- host: '{{ vhost }}'
- username: '{{ vuser }}'
- password: '{{ vpass }}'
- datacenter: DC2 Someplace
- datastore: datastore2
- path: other/remote/file
- state: absent
- delegate_to: localhost
-
-
-
-
-Status
-------
-
-
-Authors
-~~~~~~~
-
-- Dag Wieers (@dagwieers)
diff --git a/ansible_collections/community/vmware/meta/runtime.yml b/ansible_collections/community/vmware/meta/runtime.yml
index 1b05c7bd4..92196f500 100644
--- a/ansible_collections/community/vmware/meta/runtime.yml
+++ b/ansible_collections/community/vmware/meta/runtime.yml
@@ -1,5 +1,5 @@
---
-requires_ansible: '>=2.13.0'
+requires_ansible: '>=2.15.0'
action_groups:
vmware:
@@ -8,6 +8,7 @@ action_groups:
- vcenter_extension_info
- vcenter_folder
- vcenter_license
+ - vcenter_root_password_expiration
- vcenter_standard_key_provider
- vmware_about_info
- vmware_category
@@ -52,6 +53,7 @@ action_groups:
- vmware_evc_mode
- vmware_export_ovf
- vmware_first_class_disk
+ - vmware_first_class_disk_info
- vmware_folder_info
- vmware_guest
- vmware_guest_boot_info
@@ -86,6 +88,7 @@ action_groups:
- vmware_guest_video
- vmware_host
- vmware_host_acceptance
+ - vmware_host_acceptance_info
- vmware_host_active_directory
- vmware_host_auto_start
- vmware_host_capability_info
@@ -100,6 +103,7 @@ action_groups:
- vmware_host_feature_info
- vmware_host_firewall_info
- vmware_host_firewall_manager
+ - vmware_host_graphics
- vmware_host_hyperthreading
- vmware_host_ipv6
- vmware_host_iscsi
@@ -145,6 +149,8 @@ action_groups:
- vmware_tag_info
- vmware_tag_manager
- vmware_target_canonical_info
+ - vmware_vasa
+ - vmware_vasa_info
- vmware_vcenter_settings
- vmware_vcenter_settings_info
- vmware_vcenter_statistics
diff --git a/ansible_collections/community/vmware/plugins/connection/vmware_tools.py b/ansible_collections/community/vmware/plugins/connection/vmware_tools.py
index 533ededb1..a542a64a1 100644
--- a/ansible_collections/community/vmware/plugins/connection/vmware_tools.py
+++ b/ansible_collections/community/vmware/plugins/connection/vmware_tools.py
@@ -14,7 +14,7 @@ DOCUMENTATION = r'''
description:
- Use VMware tools to run tasks in, or put/fetch files to guest operating systems running in VMware infrastructure.
- In case of Windows VMs, set C(ansible_shell_type) to C(powershell).
- - Does not work with 'become'.
+ - Does not work with C(become).
requirements:
- requests (Python library)
options:
@@ -64,7 +64,7 @@ DOCUMENTATION = r'''
validate_certs:
description:
- Verify SSL for the connection.
- - "Note: This will validate certs for both C(vmware_host) and the ESXi host running the VM."
+ - "Note: This will validate certs for both O(vmware_host) and the ESXi host running the VM."
env:
- name: VMWARE_VALIDATE_CERTS
vars:
@@ -73,10 +73,10 @@ DOCUMENTATION = r'''
type: bool
vm_path:
description:
- - Mutually exclusive with vm_uuid
+ - Mutually exclusive with O(vm_uuid)
- VM path absolute to the connection.
- - "vCenter Example: C(Datacenter/vm/Discovered virtual machine/testVM)."
- - "ESXi Host Example: C(ha-datacenter/vm/testVM)."
+ - "vCenter Example: V(Datacenter/vm/Discovered virtual machine/testVM)."
+ - "ESXi Host Example: V(ha-datacenter/vm/testVM)."
- Must include VM name, appended to 'folder' as would be passed to M(community.vmware.vmware_guest).
- Needs to include I(vm) between the Datacenter and the rest of the VM path.
- Datacenter default value for ESXi server is C(ha-datacenter).
@@ -86,9 +86,9 @@ DOCUMENTATION = r'''
required: false
vm_uuid:
description:
- - Mutually exclusive with vm_path
+ - Mutually exclusive with O(vm_path)
- VM UUID to the connection.
- - UUID of the virtual machine from property config.uuid of vmware_vm_inventory plugin
+ - UUID of the virtual machine from property config.uuid of P(community.vmware.vmware_vm_inventory#lookup) plugin
vars:
- name: ansible_vmware_guest_uuid
required: false
@@ -118,7 +118,7 @@ DOCUMENTATION = r'''
file_chunk_size:
description:
- File chunk size.
- - "(Applicable when writing a file to disk, example: using the C(fetch) module.)"
+ - "(Applicable when writing a file to disk, example: using the M(ansible.builtin.fetch) module.)"
vars:
- name: ansible_vmware_tools_file_chunk_size
default: 128
diff --git a/ansible_collections/community/vmware/plugins/doc_fragments/vmware.py b/ansible_collections/community/vmware/plugins/doc_fragments/vmware.py
index 51f182e87..5df2762c1 100644
--- a/ansible_collections/community/vmware/plugins/doc_fragments/vmware.py
+++ b/ansible_collections/community/vmware/plugins/doc_fragments/vmware.py
@@ -19,50 +19,43 @@ options:
hostname:
description:
- The hostname or IP address of the vSphere vCenter or ESXi server.
- - If the value is not specified in the task, the value of environment variable C(VMWARE_HOST) will be used instead.
- - Environment variable support added in Ansible 2.6.
+ - If the value is not specified in the task, the value of environment variable E(VMWARE_HOST) will be used instead.
type: str
username:
description:
- The username of the vSphere vCenter or ESXi server.
- - If the value is not specified in the task, the value of environment variable C(VMWARE_USER) will be used instead.
- - Environment variable support added in Ansible 2.6.
+ - If the value is not specified in the task, the value of environment variable E(VMWARE_USER) will be used instead.
type: str
aliases: [ admin, user ]
password:
description:
- The password of the vSphere vCenter or ESXi server.
- - If the value is not specified in the task, the value of environment variable C(VMWARE_PASSWORD) will be used instead.
- - Environment variable support added in Ansible 2.6.
+ - If the value is not specified in the task, the value of environment variable E(VMWARE_PASSWORD) will be used instead.
type: str
aliases: [ pass, pwd ]
validate_certs:
description:
- - Allows connection when SSL certificates are not valid. Set to C(false) when certificates are not trusted.
- - If the value is not specified in the task, the value of environment variable C(VMWARE_VALIDATE_CERTS) will be used instead.
- - Environment variable support added in Ansible 2.6.
- - If set to C(true), please make sure Python >= 2.7.9 is installed on the given machine.
+ - Allows connection when SSL certificates are not valid. Set to V(false) when certificates are not trusted.
+ - If the value is not specified in the task, the value of environment variable E(VMWARE_VALIDATE_CERTS) will be used instead.
type: bool
default: true
port:
description:
- The port number of the vSphere vCenter or ESXi server.
- - If the value is not specified in the task, the value of environment variable C(VMWARE_PORT) will be used instead.
- - Environment variable support added in Ansible 2.6.
+ - If the value is not specified in the task, the value of environment variable E(VMWARE_PORT) will be used instead.
type: int
default: 443
proxy_host:
description:
- Address of a proxy that will receive all HTTPS requests and relay them.
- The format is a hostname or a IP.
- - If the value is not specified in the task, the value of environment variable C(VMWARE_PROXY_HOST) will be used instead.
- - This feature depends on a version of pyvmomi greater than v6.7.1.2018.12
+ - If the value is not specified in the task, the value of environment variable E(VMWARE_PROXY_HOST) will be used instead.
type: str
required: false
proxy_port:
description:
- Port of the HTTP proxy that will receive all HTTPS requests and relay them.
- - If the value is not specified in the task, the value of environment variable C(VMWARE_PROXY_PORT) will be used instead.
+ - If the value is not specified in the task, the value of environment variable E(VMWARE_PROXY_PORT) will be used instead.
type: int
required: false
'''
@@ -75,49 +68,43 @@ options:
hostname:
description:
- The hostname or IP address of the vSphere vCenter server.
- - If the value is not specified in the task, the value of environment variable C(VMWARE_HOST) will be used instead.
- - Environment variable supported added in Ansible 2.6.
+ - If the value is not specified in the task, the value of environment variable E(VMWARE_HOST) will be used instead.
type: str
username:
description:
- The username of the vSphere vCenter server.
- - If the value is not specified in the task, the value of environment variable C(VMWARE_USER) will be used instead.
- - Environment variable supported added in Ansible 2.6.
+ - If the value is not specified in the task, the value of environment variable E(VMWARE_USER) will be used instead.
type: str
aliases: [ admin, user ]
password:
description:
- The password of the vSphere vCenter server.
- - If the value is not specified in the task, the value of environment variable C(VMWARE_PASSWORD) will be used instead.
- - Environment variable supported added in Ansible 2.6.
+ - If the value is not specified in the task, the value of environment variable E(VMWARE_PASSWORD) will be used instead.
type: str
aliases: [ pass, pwd ]
validate_certs:
description:
- - Allows connection when SSL certificates are not valid. Set to C(false) when certificates are not trusted.
- - If the value is not specified in the task, the value of environment variable C(VMWARE_VALIDATE_CERTS) will be used instead.
- - Environment variable supported added in Ansible 2.6.
- - If set to C(true), please make sure Python >= 2.7.9 is installed on the given machine.
+ - Allows connection when SSL certificates are not valid. Set to V(false) when certificates are not trusted.
+ - If the value is not specified in the task, the value of environment variable E(VMWARE_VALIDATE_CERTS) will be used instead.
type: bool
default: true
port:
description:
- The port number of the vSphere vCenter server.
- - If the value is not specified in the task, the value of environment variable C(VMWARE_PORT) will be used instead.
- - Environment variable supported added in Ansible 2.6.
+ - If the value is not specified in the task, the value of environment variable E(VMWARE_PORT) will be used instead.
type: int
default: 443
proxy_host:
description:
- Address of a proxy that will receive all HTTPS requests and relay them.
- The format is a hostname or a IP.
- - If the value is not specified in the task, the value of environment variable C(VMWARE_PROXY_HOST) will be used instead.
+ - If the value is not specified in the task, the value of environment variable E(VMWARE_PROXY_HOST) will be used instead.
type: str
required: false
proxy_port:
description:
- Port of the HTTP proxy that will receive all HTTPS requests and relay them.
- - If the value is not specified in the task, the value of environment variable C(VMWARE_PROXY_PORT) will be used instead.
+ - If the value is not specified in the task, the value of environment variable E(VMWARE_PROXY_PORT) will be used instead.
type: int
required: false
'''
diff --git a/ansible_collections/community/vmware/plugins/doc_fragments/vmware_rest_client.py b/ansible_collections/community/vmware/plugins/doc_fragments/vmware_rest_client.py
index c98c42670..f852173d6 100644
--- a/ansible_collections/community/vmware/plugins/doc_fragments/vmware_rest_client.py
+++ b/ansible_collections/community/vmware/plugins/doc_fragments/vmware_rest_client.py
@@ -16,31 +16,31 @@ options:
hostname:
description:
- The hostname or IP address of the vSphere vCenter server.
- - If the value is not specified in the task, the value of environment variable C(VMWARE_HOST) will be used instead.
+ - If the value is not specified in the task, the value of environment variable E(VMWARE_HOST) will be used instead.
type: str
username:
description:
- The username of the vSphere vCenter server.
- - If the value is not specified in the task, the value of environment variable C(VMWARE_USER) will be used instead.
+ - If the value is not specified in the task, the value of environment variable E(VMWARE_USER) will be used instead.
type: str
aliases: [ admin, user ]
password:
description:
- The password of the vSphere vCenter server.
- - If the value is not specified in the task, the value of environment variable C(VMWARE_PASSWORD) will be used instead.
+ - If the value is not specified in the task, the value of environment variable E(VMWARE_PASSWORD) will be used instead.
type: str
aliases: [ pass, pwd ]
validate_certs:
description:
- Allows connection when SSL certificates are not valid.
- - Set to C(false) when certificates are not trusted.
- - If the value is not specified in the task, the value of environment variable C(VMWARE_VALIDATE_CERTS) will be used instead.
+ - Set to V(false) when certificates are not trusted.
+ - If the value is not specified in the task, the value of environment variable E(VMWARE_VALIDATE_CERTS) will be used instead.
type: bool
default: true
port:
description:
- The port number of the vSphere vCenter.
- - If the value is not specified in the task, the value of environment variable C(VMWARE_PORT) will be used instead.
+ - If the value is not specified in the task, the value of environment variable E(VMWARE_PORT) will be used instead.
type: int
default: 443
protocol:
@@ -53,13 +53,13 @@ options:
description:
- Address of a proxy that will receive all HTTPS requests and relay them.
- The format is a hostname or a IP.
- - If the value is not specified in the task, the value of environment variable C(VMWARE_PROXY_HOST) will be used instead.
+ - If the value is not specified in the task, the value of environment variable E(VMWARE_PROXY_HOST) will be used instead.
type: str
required: false
proxy_port:
description:
- Port of the HTTP proxy that will receive all HTTPS requests and relay them.
- - If the value is not specified in the task, the value of environment variable C(VMWARE_PROXY_PORT) will be used instead.
+ - If the value is not specified in the task, the value of environment variable E(VMWARE_PROXY_PORT) will be used instead.
type: int
required: false
'''
diff --git a/ansible_collections/community/vmware/plugins/inventory/vmware_host_inventory.py b/ansible_collections/community/vmware/plugins/inventory/vmware_host_inventory.py
index 20a930c47..e6847573f 100644
--- a/ansible_collections/community/vmware/plugins/inventory/vmware_host_inventory.py
+++ b/ansible_collections/community/vmware/plugins/inventory/vmware_host_inventory.py
@@ -32,6 +32,7 @@ DOCUMENTATION = r"""
description:
- Name of vSphere user.
- Accepts vault encrypted variable.
+ - Accepts Jinja to template the value
required: true
env:
- name: VMWARE_USER
@@ -40,6 +41,7 @@ DOCUMENTATION = r"""
description:
- Password of vSphere user.
- Accepts vault encrypted variable.
+ - Accepts Jinja to template the value
required: true
env:
- name: VMWARE_PASSWORD
@@ -52,7 +54,7 @@ DOCUMENTATION = r"""
validate_certs:
description:
- Allows connection when SSL certificates are not valid.
- - Set to C(false) when certificates are not trusted.
+ - Set to V(false) when certificates are not trusted.
default: true
type: bool
env:
@@ -69,7 +71,7 @@ DOCUMENTATION = r"""
description:
- A list of templates in order of precedence to compose inventory_hostname.
- Ignores template if resulted in an empty string or None value.
- - You can use property specified in I(properties) as variables in the template.
+ - You can use property specified in O(properties) as variables in the template.
type: list
elements: string
default: ['name']
@@ -78,12 +80,12 @@ DOCUMENTATION = r"""
- Specify the list of VMware schema properties associated with the ESXi hostsystem.
- These properties will be populated in hostvars of the given ESXi hostsystem.
- Each value in the list can be a path to a specific property in hostsystem object or a path to a collection of hostsystem objects.
- - C(summary.runtime.powerState) are required if C(keyed_groups) is set to default.
+ - V(summary.runtime.powerState) are required if O(keyed_groups) is set to default.
- Please make sure that all the properties that are used in other parameters are included in this options.
- In addition to ESXi hostsystem's properties, the following are special values
- - Use C(customValue) to populate ESXi hostsystem's custom attributes. C(customValue) is only supported by vCenter and not by ESXi.
- - Use C(all) to populate all the properties of the virtual machine.
- The value C(all) is time consuming operation, do not use unless required absolutely.
+ - Use V(customValue) to populate ESXi hostsystem's custom attributes. V(customValue) is only supported by vCenter and not by ESXi.
+ - Use V(all) to populate all the properties of the virtual machine.
+ The value V(all) is time consuming operation, do not use unless required absolutely.
type: list
elements: string
default: [ 'name', 'customValue', 'summary.runtime.powerState' ]
@@ -110,7 +112,7 @@ DOCUMENTATION = r"""
description:
- A list of resources to limit search scope.
- Each resource item is represented by exactly one C('vim_type_snake_case):C(list of resource names) pair and optional nested I(resources)
- - Key name is based on snake case of a vim type name; e.g C(host_system) correspond to C(vim.HostSystem)
+ - Key name is based on snake case of a vim type name; e.g V(host_system) correspond to C(vim.HostSystem)
required: false
type: list
elements: dict
@@ -131,7 +133,6 @@ DOCUMENTATION = r"""
description:
- Address of a proxy that will receive all HTTPS requests and relay them.
- The format is a hostname or a IP.
- - This feature depends on a version of pyvmomi>=v6.7.1.2018.12.
type: str
required: false
env:
@@ -155,6 +156,15 @@ EXAMPLES = r"""
validate_certs: false
with_tags: true
+# Sample configuration file for VMware Guest dynamic inventory using Jinja to template the username and password.
+ plugin: community.vmware.vmware_host_inventory
+ strict: false
+ hostname: 10.65.223.31
+ username: '{{ (lookup("file","~/.config/vmware.yaml") | from_yaml).username }}'
+ password: '{{ (lookup("file","~/.config/vmware.yaml") | from_yaml).password }}'
+ validate_certs: false
+ with_tags: true
+
# Using compose
plugin: community.vmware.vmware_host_inventory
hostname: 10.65.223.31
@@ -236,12 +246,16 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
username = self.get_option("username")
password = self.get_option("password")
- if isinstance(username, AnsibleVaultEncryptedUnicode):
- username = username.data
-
- if isinstance(password, AnsibleVaultEncryptedUnicode):
+ if self.templar.is_template(password):
+ password = self.templar.template(variable=password, disable_lookups=False)
+ elif isinstance(password, AnsibleVaultEncryptedUnicode):
password = password.data
+ if self.templar.is_template(username):
+ username = self.templar.template(variable=username, disable_lookups=False)
+ elif isinstance(username, AnsibleVaultEncryptedUnicode):
+ username = username.data
+
self.pyv = BaseVMwareInventory(
hostname=self.get_option("hostname"),
username=username,
diff --git a/ansible_collections/community/vmware/plugins/inventory/vmware_vm_inventory.py b/ansible_collections/community/vmware/plugins/inventory/vmware_vm_inventory.py
index a8747d731..d26b8984c 100644
--- a/ansible_collections/community/vmware/plugins/inventory/vmware_vm_inventory.py
+++ b/ansible_collections/community/vmware/plugins/inventory/vmware_vm_inventory.py
@@ -32,6 +32,7 @@ DOCUMENTATION = r'''
description:
- Name of vSphere user.
- Accepts vault encrypted variable.
+ - Accepts Jinja to template the value
required: true
env:
- name: VMWARE_USER
@@ -40,6 +41,7 @@ DOCUMENTATION = r'''
description:
- Password of vSphere user.
- Accepts vault encrypted variable.
+ - Accepts Jinja to template the value
required: true
env:
- name: VMWARE_PASSWORD
@@ -52,7 +54,7 @@ DOCUMENTATION = r'''
validate_certs:
description:
- Allows connection when SSL certificates are not valid.
- - Set to C(false) when certificates are not trusted.
+ - Set to V(false) when certificates are not trusted.
default: true
type: bool
env:
@@ -69,7 +71,7 @@ DOCUMENTATION = r'''
description:
- A list of templates in order of precedence to compose inventory_hostname.
- Ignores template if resulted in an empty string or None value.
- - You can use property specified in I(properties) as variables in the template.
+ - You can use property specified in O(properties) as variables in the template.
type: list
elements: string
default: ['config.name + "_" + config.uuid']
@@ -78,13 +80,13 @@ DOCUMENTATION = r'''
- Specify the list of VMware schema properties associated with the VM.
- These properties will be populated in hostvars of the given VM.
- Each value in the list can be a path to a specific property in VM object or a path to a collection of VM objects.
- - C(config.name), C(config.uuid) are required properties if C(hostnames) is set to default.
- - C(config.guestId), C(summary.runtime.powerState) are required if C(keyed_groups) is set to default.
+ - V(config.name), V(config.uuid) are required properties if O(hostnames) is set to default.
+ - V(config.guestId), V(summary.runtime.powerState) are required if O(keyed_groups) is set to default.
- Please make sure that all the properties that are used in other parameters are included in this options.
- In addition to VM properties, the following are special values
- - Use C(customValue) to populate virtual machine's custom attributes. C(customValue) is only supported by vCenter and not by ESXi.
- - Use C(all) to populate all the properties of the virtual machine.
- The value C(all) is time consuming operation, do not use unless required absolutely.
+ - Use V(customValue) to populate virtual machine's custom attributes. V(customValue) is only supported by vCenter and not by ESXi.
+ - Use V(all) to populate all the properties of the virtual machine.
+ The value V(all) is time consuming operation, do not use unless required absolutely.
- Please refer more VMware guest attributes which can be used as properties
U(https://docs.ansible.com/ansible/latest/collections/community/vmware/docsite/vmware_scenarios/vmware_inventory_vm_attributes.html)
type: list
@@ -95,10 +97,28 @@ DOCUMENTATION = r'''
'guest.guestId', 'guest.guestState', 'runtime.maxMemoryUsage',
'customValue', 'summary.runtime.powerState', 'config.guestId',
]
+ subproperties:
+ version_added: 4.2.0
+ description:
+ - List of subproperties from an normal property.
+ - These subproperties will also populated to the hostvars of the given VM.
+ type: list
+ elements: dict
+ default: []
+ suboptions:
+ property:
+ description:
+ - Name of the Property
+ type: str
+ required: true
+ subelements:
+ description:
+ - List of subelements
+ type: list
+ elements: str
with_nested_properties:
description:
- This option transform flatten properties name to nested dictionary.
- - From 1.10.0 and onwards, default value is set to C(true).
type: bool
default: true
keyed_groups:
@@ -120,7 +140,7 @@ DOCUMENTATION = r'''
description:
- A list of resources to limit search scope.
- Each resource item is represented by exactly one C('vim_type_snake_case):C(list of resource names) pair and optional nested I(resources)
- - Key name is based on snake case of a vim type name; e.g C(host_system) correspond to C(vim.HostSystem)
+ - Key name is based on snake case of a vim type name; e.g V(host_system) correspond to C(vim.HostSystem)
- See L(VIM Types,https://pubs.vmware.com/vi-sdk/visdk250/ReferenceGuide/index-mo_types.html)
required: false
type: list
@@ -142,7 +162,6 @@ DOCUMENTATION = r'''
description:
- Address of a proxy that will receive all HTTPS requests and relay them.
- The format is a hostname or a IP.
- - This feature depends on a version of pyvmomi>=v6.7.1.2018.12.
type: str
required: false
env:
@@ -166,6 +185,15 @@ EXAMPLES = r'''
validate_certs: false
with_tags: true
+# Sample configuration file for VMware Guest dynamic inventory using Jinja to template the username and password.
+ plugin: community.vmware.vmware_vm_inventory
+ strict: false
+ hostname: 10.65.223.31
+ username: '{{ (lookup("file","~/.config/vmware.yaml") | from_yaml).username }}'
+ password: '{{ (lookup("file","~/.config/vmware.yaml") | from_yaml).password }}'
+ validate_certs: false
+ with_tags: true
+
# Gather minimum set of properties for VMware guest
plugin: community.vmware.vmware_vm_inventory
strict: false
@@ -179,6 +207,24 @@ EXAMPLES = r'''
- 'config.name'
- 'config.uuid'
+# Gather subproperties such as the parent (mostly cluster) of an ESXi
+ plugin: community.vmware.vmware_vm_inventory
+ strict: false
+ hostname: 10.65.223.31
+ username: administrator@vsphere.local
+ password: Esxi@123$%
+ validate_certs: false
+ properties:
+ - 'name'
+ - 'guest.ipAddress'
+ - 'config.name'
+ - 'config.uuid'
+ subproperties:
+ - property: 'summary.runtime.host'
+ subelements:
+ - 'name'
+ - 'parent.name'
+
# Create Groups based upon VMware Tools status
plugin: community.vmware.vmware_vm_inventory
strict: false
@@ -383,6 +429,7 @@ from ansible.module_utils.six import text_type
from ansible_collections.community.vmware.plugins.plugin_utils.inventory import (
to_nested_dict,
to_flatten_dict,
+ parse_vim_property
)
display = Display()
@@ -658,12 +705,16 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
username = self.get_option('username')
password = self.get_option('password')
- if isinstance(username, AnsibleVaultEncryptedUnicode):
- username = username.data
-
- if isinstance(password, AnsibleVaultEncryptedUnicode):
+ if self.templar.is_template(password):
+ password = self.templar.template(variable=password, disable_lookups=False)
+ elif isinstance(password, AnsibleVaultEncryptedUnicode):
password = password.data
+ if self.templar.is_template(username):
+ username = self.templar.template(variable=username, disable_lookups=False)
+ elif isinstance(username, AnsibleVaultEncryptedUnicode):
+ username = username.data
+
self.pyv = BaseVMwareInventory(
hostname=self.get_option('hostname'),
username=username,
@@ -711,6 +762,9 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
strict = self.get_option('strict')
vm_properties = self.get_option('properties')
+ vm_subproperties = {e['property']: e['subelements'] for e in self.get_option('subproperties')}
+ vm_properties.extend(vm_subproperties.keys())
+
if not isinstance(vm_properties, list):
vm_properties = [vm_properties]
@@ -747,7 +801,18 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
for vm_obj in objects:
properties = dict()
for vm_obj_property in vm_obj.propSet:
- properties[vm_obj_property.name] = vm_obj_property.val
+ if vm_obj_property.name in vm_subproperties:
+ for subproperty in vm_subproperties[vm_obj_property.name]:
+ subproperty_parts = subproperty.split('.')
+
+ value = vm_obj_property.val
+ for subproperty_part in subproperty_parts:
+ value = value.__getattribute__(subproperty_part)
+
+ subproperty_parsed = parse_vim_property(value)
+ properties[vm_obj_property.name + "." + subproperty] = subproperty_parsed
+ else:
+ properties[vm_obj_property.name] = vm_obj_property.val
if (properties.get('runtime.connectionState') or properties['runtime'].connectionState) in ('orphaned', 'inaccessible', 'disconnected'):
continue
diff --git a/ansible_collections/community/vmware/plugins/module_utils/version.py b/ansible_collections/community/vmware/plugins/module_utils/version.py
deleted file mode 100644
index 3633a307b..000000000
--- a/ansible_collections/community/vmware/plugins/module_utils/version.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright: (c) 2021, Felix Fontein <felix@fontein.de>
-# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
-# SPDX-License-Identifier: GPL-3.0-or-later
-
-"""Provide version object to compare version numbers."""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-from ansible.module_utils.six import raise_from
-
-try:
- from ansible.module_utils.compat.version import LooseVersion # noqa: F401, pylint: disable=unused-import
-except ImportError:
- try:
- from distutils.version import LooseVersion # noqa: F401
- except ImportError as exc:
- raise_from(ImportError('To use this plugin or module with ansible-core < 2.11, you need to use Python < 3.12 with distutils.version present'), exc)
-
-try:
- from ansible.module_utils.compat.version import StrictVersion # noqa: F401, pylint: disable=unused-import
-except ImportError:
- try:
- from distutils.version import StrictVersion # noqa: F401
- except ImportError as exc:
- raise_from(ImportError('To use this plugin or module with ansible-core < 2.11, you need to use Python < 3.12 with distutils.version present'), exc)
diff --git a/ansible_collections/community/vmware/plugins/module_utils/vmware.py b/ansible_collections/community/vmware/plugins/module_utils/vmware.py
index 926cf2932..a7b61bdae 100644
--- a/ansible_collections/community/vmware/plugins/module_utils/vmware.py
+++ b/ansible_collections/community/vmware/plugins/module_utils/vmware.py
@@ -21,9 +21,10 @@ import time
import traceback
import datetime
from collections import OrderedDict
-from ansible_collections.community.vmware.plugins.module_utils.version import StrictVersion
+from ansible.module_utils.compat.version import StrictVersion
from random import randint
+
REQUESTS_IMP_ERR = None
try:
# requests is required for exception handling of the ConnectionError
@@ -219,6 +220,23 @@ def find_object_by_name(content, name, obj_type, folder=None, recurse=True):
return None
+def find_all_objects_by_name(content, name, obj_type, folder=None, recurse=True):
+ if not isinstance(obj_type, list):
+ obj_type = [obj_type]
+
+ name = name.strip()
+ result = []
+
+ objects = get_all_objs(content, obj_type, folder=folder, recurse=recurse)
+ for obj in objects:
+ try:
+ if unquote(obj.name) == name:
+ result.append(obj)
+ except vmodl.fault.ManagedObjectNotFound:
+ pass
+ return result
+
+
def find_cluster_by_name(content, cluster_name, datacenter=None):
if datacenter and hasattr(datacenter, 'hostFolder'):
folder = datacenter.hostFolder
@@ -326,6 +344,10 @@ def find_network_by_name(content, network_name, datacenter_name=None):
return find_object_by_name(content, network_name, [vim.Network], datacenter_name)
+def find_all_networks_by_name(content, network_name, datacenter_name=None):
+ return find_all_objects_by_name(content, network_name, [vim.Network], datacenter_name)
+
+
def find_vm_by_id(content, vm_id, vm_id_type="vm_name", datacenter=None,
cluster=None, folder=None, match_first=False):
""" UUID is unique to a VM, every other id returns the first match. """
@@ -1152,9 +1174,9 @@ class PyVmomi(object):
self.module.fail_json(msg='The passed vCenter version: %s is None.' % version)
def get_cert_fingerprint(self, fqdn, port, proxy_host=None, proxy_port=None):
- sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- sock.settimeout(1)
if proxy_host:
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ sock.settimeout(1)
sock.connect((
proxy_host,
proxy_port))
@@ -1169,17 +1191,16 @@ class PyVmomi(object):
der_cert_bin = ctx.wrap_socket(sock, server_hostname=fqdn).getpeercert(True)
sock.close()
else:
- wrapped_socket = ssl.wrap_socket(sock)
try:
- wrapped_socket.connect((fqdn, port))
- except socket.error as socket_error:
- self.module.fail_json(msg="Cannot connect to host : %s" % socket_error)
- else:
- der_cert_bin = wrapped_socket.getpeercert(True)
- wrapped_socket.close()
-
- string = str(hashlib.sha1(der_cert_bin).hexdigest())
- return ':'.join(a + b for a, b in zip(string[::2], string[1::2]))
+ pem = ssl.get_server_certificate((fqdn, port))
+ except Exception:
+ self.module.fail_json(msg=f"Cannot connect to host: {fqdn}")
+ der_cert_bin = ssl.PEM_cert_to_DER_cert(pem)
+ if der_cert_bin:
+ string = str(hashlib.sha1(der_cert_bin).hexdigest())
+ return ':'.join(a + b for a, b in zip(string[::2], string[1::2]))
+ else:
+ self.module.fail_json(msg=f"Unable to obtain certificate fingerprint for host: {fqdn}")
def get_managed_objects_properties(self, vim_type, properties=None):
"""
@@ -1853,6 +1874,30 @@ class PyVmomi(object):
return None
+ def find_first_class_disks(self, datastore_obj):
+ """
+ Get first-class disks managed object
+ Args:
+ datastore_obj: Managed object of datastore
+
+ Returns: First-class disks managed object if found else None
+
+ """
+
+ disks = []
+
+ if self.is_vcenter():
+ for id in self.content.vStorageObjectManager.ListVStorageObject(datastore_obj):
+ disks.append(self.content.vStorageObjectManager.RetrieveVStorageObject(id, datastore_obj))
+
+ else:
+ for id in self.content.vStorageObjectManager.HostListVStorageObject(datastore_obj):
+ disks.append(self.content.vStorageObjectManager.HostRetrieveVStorageObject(id, datastore_obj))
+
+ if disks == []:
+ return None
+ else:
+ return disks
#
# Conversion to JSON
#
diff --git a/ansible_collections/community/vmware/plugins/module_utils/vmware_rest_client.py b/ansible_collections/community/vmware/plugins/module_utils/vmware_rest_client.py
index c98496c2b..c51e3ad18 100644
--- a/ansible_collections/community/vmware/plugins/module_utils/vmware_rest_client.py
+++ b/ansible_collections/community/vmware/plugins/module_utils/vmware_rest_client.py
@@ -44,6 +44,16 @@ except ImportError:
VSPHERE_IMP_ERR = traceback.format_exc()
HAS_VSPHERE = False
+try:
+ from requests.packages import urllib3
+ HAS_URLLIB3 = True
+except ImportError:
+ try:
+ import urllib3
+ HAS_URLLIB3 = True
+ except ImportError:
+ HAS_URLLIB3 = False
+
from ansible.module_utils.basic import env_fallback, missing_required_lib
from ansible.module_utils._text import to_native
@@ -131,13 +141,17 @@ class VmwareRestClient(object):
username = self.params.get('username')
password = self.params.get('password')
hostname = self.params.get('hostname')
+ validate_certs = self.params.get('validate_certs')
port = self.params.get('port')
session = requests.Session()
- session.verify = self.params.get('validate_certs')
+ session.verify = validate_certs
protocol = self.params.get('protocol')
proxy_host = self.params.get('proxy_host')
proxy_port = self.params.get('proxy_port')
+ if validate_certs is False:
+ if HAS_URLLIB3:
+ urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
if all([protocol, proxy_host, proxy_port]):
proxies = {protocol: "{0}://{1}:{2}".format(protocol, proxy_host, proxy_port)}
session.proxies.update(proxies)
@@ -539,36 +553,3 @@ class VmwareRestClient(object):
category_id = category_obj.id
return self.get_tag_by_category_id(tag_name=tag_name, category_id=category_id)
-
- def get_tag_by_category(self, tag_name=None, category_name=None, category_id=None):
- """
- Return tag object by name and category name specified
- Args:
- tag_name: Name of tag
- category_name: Name of category (mutually exclusive with 'category_id')
- category_id: Id of category, if known in advance (mutually exclusive with 'category_name')
- Returns: Tag object if found else None
- """
- message = "The method 'get_tag_by_category' is deprecated and scheduled for removal. "\
- "Please update your code and use 'get_tag_by_category_id' or 'get_tag_by_category_name' instead"
- self.module.deprecate(message, version='4.0.0', collection_name='community.vmware')
-
- if not tag_name:
- return None
-
- if category_id or category_name:
- if not category_id:
- category_obj = self.get_category_by_name(category_name=category_name)
-
- if not category_obj:
- return None
-
- category_id = category_obj.id
-
- for tag_object in self.api_client.tagging.Tag.list_tags_for_category(category_id):
- tag_obj = self.api_client.tagging.Tag.get(tag_object)
-
- if tag_obj.name == tag_name:
- return tag_obj
- else:
- return self.search_svc_object_by_name(service=self.api_client.tagging.Tag, svc_obj_name=tag_name)
diff --git a/ansible_collections/community/vmware/plugins/module_utils/vmware_sms.py b/ansible_collections/community/vmware/plugins/module_utils/vmware_sms.py
new file mode 100644
index 000000000..cc5748a03
--- /dev/null
+++ b/ansible_collections/community/vmware/plugins/module_utils/vmware_sms.py
@@ -0,0 +1,76 @@
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Ansible Project
+# Copyright: (c) 2023, Pure Storage, Inc.
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+try:
+ from pyVmomi import sms
+ from pyVim.connect import SoapStubAdapter
+except ImportError:
+ pass
+
+from ansible_collections.community.vmware.plugins.module_utils.vmware import PyVmomi
+from random import randint
+import time
+
+
+class TaskError(Exception):
+ def __init__(self, *args, **kwargs):
+ super(TaskError, self).__init__(*args, **kwargs)
+
+
+class SMS(PyVmomi):
+ def __init__(self, module):
+ super(SMS, self).__init__(module)
+ self.sms_si = None
+ self.version = "sms.version.v7_0_0_1"
+
+ def get_sms_connection(self):
+ """
+ Creates a Service instance for VMware SMS
+ """
+ client_stub = self.si._GetStub()
+ try:
+ session_cookie = client_stub.cookie.split('"')[1]
+ except IndexError:
+ self.module.fail_json(msg="Failed to get session cookie")
+ ssl_context = client_stub.schemeArgs.get('context')
+ additional_headers = {'vcSessionCookie': session_cookie}
+ hostname = self.module.params['hostname']
+ if not hostname:
+ self.module.fail_json(msg="Please specify required parameter - hostname")
+ stub = SoapStubAdapter(host=hostname, path="/sms/sdk", version=self.version,
+ sslContext=ssl_context, requestContext=additional_headers)
+
+ self.sms_si = sms.ServiceInstance("ServiceInstance", stub)
+
+
+def wait_for_sms_task(task, max_backoff=64, timeout=3600):
+ """Wait for given task using exponential back-off algorithm.
+
+ Args:
+ task: VMware SMS task object
+ max_backoff: Maximum amount of sleep time in seconds
+ timeout: Timeout for the given task in seconds
+
+ Returns: Tuple with True and result for successful task
+ Raises: TaskError on failure
+ """
+ failure_counter = 0
+ start_time = time.time()
+
+ while True:
+ task_info = task.QuerySmsTaskInfo()
+ if time.time() - start_time >= timeout:
+ raise TaskError("Timeout")
+ if task_info.state == sms.TaskInfo.State.success:
+ return True, task_info.result
+ if task_info.state == sms.TaskInfo.State.error:
+ return False, task_info.error
+ if task_info.state in [sms.TaskInfo.State.running, sms.TaskInfo.State.queued]:
+ sleep_time = min(2 ** failure_counter + randint(1, 1000) / 1000, max_backoff)
+ time.sleep(sleep_time)
+ failure_counter += 1
diff --git a/ansible_collections/community/vmware/plugins/modules/vcenter_domain_user_group_info.py b/ansible_collections/community/vmware/plugins/modules/vcenter_domain_user_group_info.py
index 4200784ec..9992f00cc 100644
--- a/ansible_collections/community/vmware/plugins/modules/vcenter_domain_user_group_info.py
+++ b/ansible_collections/community/vmware/plugins/modules/vcenter_domain_user_group_info.py
@@ -37,17 +37,17 @@ options:
type: str
exact_match:
description:
- - If I(exact_match) is C(true), it indicates the I(search_string) passed should match a user or group name exactly.
+ - If V(true), it indicates the O(search_string) passed should match a user or group name exactly.
type: bool
default: false
find_users:
description:
- - If I(find_users) is C(true), domain users will be included in the result.
+ - If V(true), domain users will be included in the result.
type: bool
default: true
find_groups:
description:
- - If I(find_groups) is C(true), domain groups will be included in the result.
+ - If V(true), domain groups will be included in the result.
type: bool
default: true
extends_documentation_fragment:
diff --git a/ansible_collections/community/vmware/plugins/modules/vcenter_extension.py b/ansible_collections/community/vmware/plugins/modules/vcenter_extension.py
index cca92fcae..f877d6bfb 100644
--- a/ansible_collections/community/vmware/plugins/modules/vcenter_extension.py
+++ b/ansible_collections/community/vmware/plugins/modules/vcenter_extension.py
@@ -30,36 +30,36 @@ options:
type: str
name:
description:
- - Required for C(state=present). The name of the extension you are installing.
+ - Required for O(state=present). The name of the extension you are installing.
type: str
company:
description:
- - Required for C(state=present). The name of the company that makes the extension.
+ - Required for O(state=present). The name of the company that makes the extension.
type: str
description:
description:
- - Required for C(state=present). A short description of the extension.
+ - Required for O(state=present). A short description of the extension.
type: str
email:
description:
- - Required for C(state=present). Administrator email to use for extension.
+ - Required for O(state=present). Administrator email to use for extension.
type: str
url:
description:
- - Required for C(state=present). Link to server hosting extension zip file to install.
+ - Required for O(state=present). Link to server hosting extension zip file to install.
type: str
ssl_thumbprint:
description:
- - Required for C(state=present). SSL thumbprint of the extension hosting server.
+ - Required for O(state=present). SSL thumbprint of the extension hosting server.
type: str
server_type:
description:
- - Required for C(state=present). Type of server being used to install the extension (SOAP, REST, HTTP, etc.).
+ - Required for O(state=present). Type of server being used to install the extension (SOAP, REST, HTTP, etc.).
default: vsphere-client-serenity
type: str
client_type:
description:
- - Required for C(state=present). Type of client the extension is (win32, .net, linux, etc.).
+ - Required for O(state=present). Type of client the extension is (win32, .net, linux, etc.).
default: vsphere-client-serenity
type: str
visible:
diff --git a/ansible_collections/community/vmware/plugins/modules/vcenter_folder.py b/ansible_collections/community/vmware/plugins/modules/vcenter_folder.py
index 149e3ed33..7103e6285 100644
--- a/ansible_collections/community/vmware/plugins/modules/vcenter_folder.py
+++ b/ansible_collections/community/vmware/plugins/modules/vcenter_folder.py
@@ -45,12 +45,12 @@ options:
folder_type:
description:
- This is type of folder.
- - "If set to C(vm), then 'VM and Template Folder' is created under datacenter."
- - "If set to C(host), then 'Host and Cluster Folder' is created under datacenter."
- - "If set to C(datastore), then 'Storage Folder' is created under datacenter."
- - "If set to C(network), then 'Network Folder' is created under datacenter."
- - This parameter is required, if C(state) is set to C(present) and parent_folder is absent.
- - This option is ignored, if C(parent_folder) is set.
+ - "If set to V(vm), then 'VM and Template Folder' is created under datacenter."
+ - "If set to V(host), then 'Host and Cluster Folder' is created under datacenter."
+ - "If set to V(datastore), then 'Storage Folder' is created under datacenter."
+ - "If set to V(network), then 'Network Folder' is created under datacenter."
+ - This parameter is required, if O(state=absent) and O(parent_folder) is not set.
+ - This option is ignored, if O(parent_folder) is set.
default: vm
type: str
required: false
@@ -58,9 +58,9 @@ options:
state:
description:
- State of folder.
- - If set to C(present) without parent folder parameter, then folder with C(folder_type) is created.
- - If set to C(present) with parent folder parameter, then folder in created under parent folder. C(folder_type) is ignored.
- - If set to C(absent), then folder is unregistered and destroyed.
+ - If set to V(present) without parent folder parameter, then folder with V(folder_type) is created.
+ - If set to V(present) with parent folder parameter, then folder in created under parent folder. V(folder_type) is ignored.
+ - If set to V(absent), then folder is unregistered and destroyed.
default: present
choices: [ present, absent ]
type: str
diff --git a/ansible_collections/community/vmware/plugins/modules/vcenter_license.py b/ansible_collections/community/vmware/plugins/modules/vcenter_license.py
index 6836d03e0..c7e09d3e5 100644
--- a/ansible_collections/community/vmware/plugins/modules/vcenter_license.py
+++ b/ansible_collections/community/vmware/plugins/modules/vcenter_license.py
@@ -31,7 +31,7 @@ options:
type: str
state:
description:
- - Whether to add (C(present)) or remove (C(absent)) the license key.
+ - Whether to add (V(present)) or remove (V(absent)) the license key.
choices: [absent, present]
default: present
type: str
@@ -54,9 +54,9 @@ notes:
an evaluation license only.
- The evaluation license (00000-00000-00000-00000-00000) is not listed
when unused.
-- If C(esxi_hostname) is specified, then will assign the C(license) key to
+- If O(esxi_hostname) is specified, then will assign the O(license) key to
the ESXi host.
-- If C(esxi_hostname) is not specified, then will just register the C(license) key to
+- If O(esxi_hostname) is not specified, then will just register the O(license) key to
vCenter inventory without assigning it to an ESXi host.
extends_documentation_fragment:
- community.vmware.vmware.vcenter_documentation
diff --git a/ansible_collections/community/vmware/plugins/modules/vcenter_root_password_expiration.py b/ansible_collections/community/vmware/plugins/modules/vcenter_root_password_expiration.py
new file mode 100644
index 000000000..7becddfe7
--- /dev/null
+++ b/ansible_collections/community/vmware/plugins/modules/vcenter_root_password_expiration.py
@@ -0,0 +1,157 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2018, Ansible Project
+# Copyright: (c) 2023, Valentin Yonev <valentin.ionev@live.com>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+DOCUMENTATION = r'''
+---
+module: vcenter_root_password_expiration
+version_added: '3.10.0'
+short_description: root password expiration of vCSA
+description: Manages password expiration configuration for root user of vCSA appliance
+author:
+ - Valentin Yonev (@valentinJonev)
+options:
+ state:
+ description:
+ - present - represents that password expiration must be configured
+ - absent - represents no expiration for root user
+ choices: [ present, absent ]
+ default: 'present'
+ type: str
+ email:
+ description:
+ - e-mail to send password expiration warnings to
+ type: str
+ required: false
+ max_days_between_password_change:
+ description:
+ - Maximum days between password change
+ type: int
+ required: false
+ min_days_between_password_change:
+ description:
+ - Minimum days between password change
+ type: int
+ required: false
+ warn_days_before_password_expiration:
+ description:
+ - Days before password expires and password expiration e-mail should be sent
+ type: int
+ required: false
+extends_documentation_fragment:
+- community.vmware.vmware.documentation
+'''
+
+EXAMPLES = r'''
+- name: Configures expiring root password
+ vcenter_root_password_expiration:
+ hostname: '{{ vcenter_hostname }}'
+ username: '{{ vcenter_localos_username }}'
+ password: '{{ vcenter_password }}'
+ max_days_between_password_change: 60
+ min_days_between_password_change: 6
+ warn_days_before_password_expiration: 7
+ email: example@vmware.com
+ state: present
+ delegate_to: localhost
+
+- name: Configures non-expiring root password
+ vcenter_root_password_expiration:
+ hostname: '{{ vcenter_hostname }}'
+ username: '{{ vcenter_localos_username }}'
+ password: '{{ vcenter_localos_password }}'
+ state: absent
+ delegate_to: localhost
+'''
+
+from ansible_collections.community.vmware.plugins.module_utils.vmware import vmware_argument_spec
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.community.vmware.plugins.module_utils.vmware_rest_client import VmwareRestClient
+
+
+class VcRootPasswordExpiration(VmwareRestClient):
+ def __init__(self, module: AnsibleModule):
+ super(VcRootPasswordExpiration, self).__init__(module)
+ self.module = module
+ self._state = True if self.module.params['state'] == 'present' else False
+
+ def configure_root_account_password_policy(self):
+ default_config = self.api_client.appliance.LocalAccounts.UpdateConfig()
+
+ current_vcenter_info = self.api_client.appliance.LocalAccounts.get('root').to_dict()
+
+ if self._state and self.module.params['min_days_between_password_change'] > self.module.params['max_days_between_password_change']:
+ self.module.fail_json("min_days_between_password_change cannot be higher than max_days_between_password_change")
+
+ if self._state:
+ _password_expiration_config = {
+ "email": self.module.params['email'],
+ "min_days_between_password_change": self.module.params['min_days_between_password_change'],
+ "max_days_between_password_change": self.module.params['max_days_between_password_change'],
+ "warn_days_before_password_expiration": self.module.params['warn_days_before_password_expiration'],
+
+ }
+ else:
+ _password_expiration_config = {
+ "max_days_between_password_change": -1
+ }
+
+ _changes_dict = dict()
+ for k, v in _password_expiration_config.items():
+ try:
+ if current_vcenter_info[k] != v:
+ _changes_dict[k] = v
+ if k == 'fullname':
+ setattr(default_config, 'full_name', v)
+ continue
+ except KeyError:
+ '''
+ Handles the case of newly installed vCenter when email field isn't present in the current config,
+ because it was never set befores
+ '''
+ _changes_dict[k] = v
+ setattr(default_config, k, v)
+ _change_result_key = 'values_would_be_changed'
+ if _changes_dict:
+ if not self.module.check_mode:
+ _change_result_key = 'values_changed'
+ self.api_client.appliance.LocalAccounts.update('root', default_config)
+ self.module.exit_json(changed=True, result={_change_result_key: _changes_dict})
+ self.module.exit_json(changed=False, result="No configuration changes needed")
+
+
+def main():
+ argument_spec = vmware_argument_spec()
+ argument_spec.update(
+ dict(
+ state=dict(default='present',
+ choices=['present', 'absent'],
+ type='str')
+ ),
+ email=dict(required=False, type='str'),
+ max_days_between_password_change=dict(type='int', no_log=False),
+ min_days_between_password_change=dict(type='int', no_log=False),
+ warn_days_before_password_expiration=dict(type='int', no_log=False),
+ )
+
+ module = AnsibleModule(argument_spec=argument_spec,
+ required_if=[
+ (
+ 'state',
+ 'present',
+ ('email', 'max_days_between_password_change', 'min_days_between_password_change', 'warn_days_before_password_expiration')
+ ),
+ ],
+ supports_check_mode=True)
+
+ vc_root_password_policy_manager = VcRootPasswordExpiration(module)
+ vc_root_password_policy_manager.configure_root_account_password_policy()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/vmware/plugins/modules/vcenter_standard_key_provider.py b/ansible_collections/community/vmware/plugins/modules/vcenter_standard_key_provider.py
index f931ebf38..8ce8f48c6 100644
--- a/ansible_collections/community/vmware/plugins/modules/vcenter_standard_key_provider.py
+++ b/ansible_collections/community/vmware/plugins/modules/vcenter_standard_key_provider.py
@@ -27,14 +27,14 @@ options:
required: true
mark_default:
description:
- - Set specified Key Provider with name C(name) as the default Key Provider.
+ - Set specified Key Provider with name O(name) as the default Key Provider.
- If new added Key Provider is the only key provider in vCenter, then will mark it as default after adding.
type: bool
default: false
state:
description:
- - If set to C(absent), the named Key Provider will be removed from vCenter.
- - If set to C(present), the named existing Key Provider will be reconfigured or new Key Provider will be added.
+ - If set to V(absent), the named Key Provider will be removed from vCenter.
+ - If set to V(present), the named existing Key Provider will be reconfigured or new Key Provider will be added.
type: str
choices:
- present
@@ -43,9 +43,9 @@ options:
kms_info:
description:
- The information of an external key server (KMS).
- - C(kms_name), C(kms_ip) are required when adding a Standard Key Provider.
- - If C(kms_port) is not specified, the default port 5696 will be used.
- - C(kms_ip), C(kms_port) can be reconfigured for an existing KMS with name C(kms_name).
+ - O(kms_info.kms_name), O(kms_info.kms_ip) are required when adding a Standard Key Provider.
+ - If O(kms_info.kms_port) is not specified, the default port 5696 will be used.
+ - O(kms_info.kms_ip), O(kms_info.kms_port) can be reconfigured for an existing KMS with name O(kms_info.kms_name).
type: list
default: []
elements: dict
@@ -60,7 +60,7 @@ options:
description: Port of the external KMS.
type: int
remove_kms:
- description: Remove the configured KMS with name C(kms_name) from the KMIP cluster.
+ description: Remove the configured KMS with name O(kms_info.kms_name) from the KMIP cluster.
type: bool
proxy_server:
description: Address of the proxy server to connect to KMS.
@@ -79,10 +79,10 @@ options:
- After adding the Standard Key Provider to the vCenter Server, you can establish a trusted connection, the
exact process depends on the certificates that the key provider accepts, and on your company policy.
- Three methods implemented here,
- (1) upload client certificate and private key through C(upload_client_cert) and C(upload_client_key) parameters,
- (2) generate, update, download vCenter self signed certificate through C(download_self_signed_cert) parameter,
- (3) download generated Certificate Signing Request(CSR) through C(download_client_csr) parameter, send it to
- KMS then upload the KMS signed CSR through C(upload_kms_signed_client_csr) parameter.
+ (1) upload client certificate and private key through O(make_kms_trust_vc.upload_client_cert) and O(make_kms_trust_vc.upload_client_key) parameters,
+ (2) generate, update, download vCenter self signed certificate through O(make_kms_trust_vc.download_self_signed_cert) parameter,
+ (3) download generated Certificate Signing Request(CSR) through O(make_kms_trust_vc.download_client_csr) parameter, send it to
+ KMS then upload the KMS signed CSR through O(make_kms_trust_vc.upload_kms_signed_client_csr) parameter.
- This is not set to be mandatory, if not set, please go to vCenter to setup trust connection with KMS manually.
type: dict
suboptions:
@@ -93,7 +93,7 @@ options:
- The certificate might be already trusted by the KMS server.
type: path
upload_client_key:
- description: The absolute file path of client private key to be uploaded together with C(upload_client_cert).
+ description: The absolute file path of client private key to be uploaded together with O(make_kms_trust_vc.upload_client_cert).
type: path
download_self_signed_cert:
description: The absolute path on local machine for keeping vCenter generated self signed client cert.
@@ -101,10 +101,10 @@ options:
download_client_csr:
description:
- The absolute path on local machine for keeping vCenter generated CSR.
- - Then upload the KMS signed CSR using C(upload_kms_signed_client_csr) to vCenter.
+ - Then upload the KMS signed CSR using O(make_kms_trust_vc.upload_kms_signed_client_csr) to vCenter.
type: path
upload_kms_signed_client_csr:
- description: The absolute file path of KMS signed CSR downloaded from C(download_client_csr).
+ description: The absolute file path of KMS signed CSR downloaded from O(make_kms_trust_vc.download_client_csr).
type: path
extends_documentation_fragment:
- community.vmware.vmware.documentation
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_category.py b/ansible_collections/community/vmware/plugins/modules/vmware_category.py
index fa5371359..c107c4f13 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_category.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_category.py
@@ -31,14 +31,20 @@ options:
category_description:
description:
- The category description.
- - This is required only if C(state) is set to C(present).
- - This parameter is ignored, when C(state) is set to C(absent).
+ - This is required if O(state=present).
+ - This parameter is ignored when O(state=absent).
default: ''
type: str
category_cardinality:
description:
- The category cardinality.
- This parameter is ignored, when updating existing category.
+ - V(single) means an object can only be assigned one of the tags in this category.
+ For example, if a O(category_name=Operating System), then different tags of this category would be "Windows", "Linux", and so on.
+ In this case a VM object can be assigned only one of these tags and hence the cardinality of the associated category here is V(single).
+ - V(multiple) means an object can be assigned several of the tags in this category.
+ For example, if a O(category_name=Server), then different tags of this category would be "AppServer", "DatabaseServer" and so on.
+ In this case a VM object can be assigned more than one of the above tags and hence the cardinality of the associated category here is V(multiple).
choices: ['multiple', 'single']
default: 'multiple'
type: str
@@ -50,10 +56,10 @@ options:
state:
description:
- The state of category.
- - If set to C(present) and category does not exists, then category is created.
- - If set to C(present) and category exists, then category is updated.
- - If set to C(absent) and category exists, then category is deleted.
- - If set to C(absent) and category does not exists, no action is taken.
+ - If set to V(present) and category does not exists, then category is created.
+ - If set to V(present) and category exists, then category is updated.
+ - If set to V(absent) and category exists, then category is deleted.
+ - If set to V(absent) and category does not exists, no action is taken.
- Process of updating category only allows name, description change.
default: 'present'
choices: [ 'present', 'absent' ]
@@ -149,7 +155,7 @@ category_results:
from ansible.module_utils._text import to_native
from ansible.module_utils.basic import AnsibleModule
-from ansible_collections.community.vmware.plugins.module_utils.version import LooseVersion
+from ansible.module_utils.compat.version import LooseVersion
from ansible_collections.community.vmware.plugins.module_utils.vmware import connect_to_api
from ansible_collections.community.vmware.plugins.module_utils.vmware_rest_client import VmwareRestClient
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_cfg_backup.py b/ansible_collections/community/vmware/plugins/modules/vmware_cfg_backup.py
index 1a3a78813..60a680641 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_cfg_backup.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_cfg_backup.py
@@ -29,9 +29,9 @@ options:
type: str
dest:
description:
- - The destination where the ESXi configuration bundle will be saved. The I(dest) can be a folder or a file.
- - If I(dest) is a folder, the backup file will be saved in the folder with the default filename generated from the ESXi server.
- - If I(dest) is a file, the backup file will be saved with that filename. The file extension will always be .tgz.
+ - The destination where the ESXi configuration bundle will be saved. Can be a folder or a file.
+ - If a folder, the backup file will be saved in the folder with the default filename generated from the ESXi server.
+ - If a file, the backup file will be saved with that filename. The file extension will always be .tgz.
type: path
src:
description:
@@ -39,9 +39,9 @@ options:
type: path
state:
description:
- - If C(saved), the .tgz backup bundle will be saved in I(dest).
- - If C(absent), the host configuration will be reset to default values.
- - If C(loaded), the backup file in I(src) will be loaded to the ESXi host rewriting the hosts settings.
+ - If V(saved), the .tgz backup bundle will be saved in O(dest).
+ - If V(absent), the host configuration will be reset to default values.
+ - If V(loaded), the backup file in O(src) will be loaded to the ESXi host rewriting the hosts settings.
choices: [saved, absent, loaded]
type: str
required: true
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_cluster.py b/ansible_collections/community/vmware/plugins/modules/vmware_cluster.py
index 6007b2f08..479d31520 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_cluster.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_cluster.py
@@ -16,7 +16,7 @@ module: vmware_cluster
short_description: Manage VMware vSphere clusters
description:
- Adds or removes VMware vSphere clusters.
- - To manage DRS, HA and VSAN related configurations, use the new modules vmware_cluster_drs, vmware_cluster_ha and vmware_cluster_vsan.
+ - To manage DRS, HA and VSAN related configurations, use the modules vmware_cluster_drs, vmware_cluster_ha and vmware_cluster_vsan.
- All values and VMware object names are case sensitive.
author:
- Joseph Callen (@jcpowermac)
@@ -35,7 +35,7 @@ options:
aliases: [ datacenter_name ]
state:
description:
- - Create C(present) or remove C(absent) a VMware vSphere cluster.
+ - Create V(present) or remove V(absent) a VMware vSphere cluster.
choices: [ absent, present ]
default: present
type: str
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_cluster_dpm.py b/ansible_collections/community/vmware/plugins/modules/vmware_cluster_dpm.py
index 5ba62b2f9..61551263c 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_cluster_dpm.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_cluster_dpm.py
@@ -46,7 +46,7 @@ options:
host_power_action_rate:
description:
- specify host power action rate
- - 1 is the lowest and 5 the highest
+ - V(1) is the lowest and V(5) the highest
type: int
default: 3
choices: [1, 2, 3, 4, 5]
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_cluster_drs.py b/ansible_collections/community/vmware/plugins/modules/vmware_cluster_drs.py
index 8954ff188..3027c2910 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_cluster_drs.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_cluster_drs.py
@@ -40,24 +40,24 @@ options:
drs_enable_vm_behavior_overrides:
description:
- Whether DRS Behavior overrides for individual virtual machines are enabled.
- - If set to C(true), overrides C(drs_default_vm_behavior).
+ - If set to V(true), overrides O(drs_default_vm_behavior).
type: bool
default: true
drs_default_vm_behavior:
description:
- Specifies the cluster-wide default DRS behavior for virtual machines.
- - If set to C(partiallyAutomated), vCenter generates recommendations for virtual machine migration and
+ - If set to V(partiallyAutomated), vCenter generates recommendations for virtual machine migration and
for the placement with a host, then automatically implements placement recommendations at power on.
- - If set to C(manual), then vCenter generates recommendations for virtual machine migration and
+ - If set to V(manual), then vCenter generates recommendations for virtual machine migration and
for the placement with a host, but does not implement the recommendations automatically.
- - If set to C(fullyAutomated), then vCenter automates both the migration of virtual machines
+ - If set to V(fullyAutomated), then vCenter automates both the migration of virtual machines
and their placement with a host at power on.
type: str
default: fullyAutomated
choices: [ fullyAutomated, manual, partiallyAutomated ]
drs_vmotion_rate:
description:
- - Threshold for generated ClusterRecommendations ranging from 1 (lowest) to 5 (highest).
+ - Threshold for generated ClusterRecommendations ranging from V(1) (lowest) to V(5) (highest).
type: int
default: 3
choices: [ 1, 2, 3, 4, 5 ]
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_cluster_ha.py b/ansible_collections/community/vmware/plugins/modules/vmware_cluster_ha.py
index d9896caa2..1ad532d4b 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_cluster_ha.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_cluster_ha.py
@@ -41,35 +41,35 @@ options:
ha_host_monitoring:
description:
- Whether HA restarts virtual machines after a host fails.
- - If set to C(enabled), HA restarts virtual machines after a host fails.
- - If set to C(disabled), HA does not restart virtual machines after a host fails.
- - If C(enable) is set to C(false), then this value is ignored.
+ - If set to V(enabled), HA restarts virtual machines after a host fails.
+ - If set to V(disabled), HA does not restart virtual machines after a host fails.
+ - If O(enable=false), this value is ignored.
type: str
choices: [ 'enabled', 'disabled' ]
default: 'enabled'
ha_vm_monitoring:
description:
- State of virtual machine health monitoring service.
- - If set to C(vmAndAppMonitoring), HA response to both virtual machine and application heartbeat failure.
- - If set to C(vmMonitoringDisabled), virtual machine health monitoring is disabled.
- - If set to C(vmMonitoringOnly), HA response to virtual machine heartbeat failure.
- - If C(enable) is set to C(false), then this value is ignored.
+ - If set to V(vmAndAppMonitoring), HA response to both virtual machine and application heartbeat failure.
+ - If set to V(vmMonitoringDisabled), virtual machine health monitoring is disabled.
+ - If set to V(vmMonitoringOnly), HA response to virtual machine heartbeat failure.
+ - If O(enable=false), then this value is ignored.
type: str
choices: ['vmAndAppMonitoring', 'vmMonitoringOnly', 'vmMonitoringDisabled']
default: 'vmMonitoringDisabled'
host_isolation_response:
description:
- Indicates whether or VMs should be powered off if a host determines that it is isolated from the rest of the compute resource.
- - If set to C(none), do not power off VMs in the event of a host network isolation.
- - If set to C(powerOff), power off VMs in the event of a host network isolation.
- - If set to C(shutdown), shut down VMs guest operating system in the event of a host network isolation.
+ - If set to V(none), do not power off VMs in the event of a host network isolation.
+ - If set to V(powerOff), power off VMs in the event of a host network isolation.
+ - If set to V(shutdown), shut down VMs guest operating system in the event of a host network isolation.
type: str
choices: ['none', 'powerOff', 'shutdown']
default: 'none'
slot_based_admission_control:
description:
- Configure slot based admission control policy.
- - C(slot_based_admission_control), C(reservation_based_admission_control) and C(failover_host_admission_control) are mutually exclusive.
+ - O(slot_based_admission_control), O(reservation_based_admission_control) and O(failover_host_admission_control) are mutually exclusive.
suboptions:
failover_level:
description:
@@ -80,7 +80,7 @@ options:
reservation_based_admission_control:
description:
- Configure reservation based admission control policy.
- - C(slot_based_admission_control), C(reservation_based_admission_control) and C(failover_host_admission_control) are mutually exclusive.
+ - O(slot_based_admission_control), O(reservation_based_admission_control) and O(failover_host_admission_control) are mutually exclusive.
suboptions:
failover_level:
description:
@@ -89,27 +89,29 @@ options:
required: true
auto_compute_percentages:
description:
- - By default, C(failover_level) is used to calculate C(cpu_failover_resources_percent) and C(memory_failover_resources_percent).
+ - By default, O(reservation_based_admission_control.failover_level) is used to calculate
+ O(reservation_based_admission_control.cpu_failover_resources_percent)
+ and O(reservation_based_admission_control.memory_failover_resources_percent).
If a user wants to override the percentage values, he has to set this field to false.
type: bool
default: true
cpu_failover_resources_percent:
description:
- Percentage of CPU resources in the cluster to reserve for failover.
- Ignored if C(auto_compute_percentages) is not set to false.
+ Ignored if O(reservation_based_admission_control.auto_compute_percentages) is not set to false.
type: int
default: 50
memory_failover_resources_percent:
description:
- Percentage of memory resources in the cluster to reserve for failover.
- Ignored if C(auto_compute_percentages) is not set to false.
+ Ignored if O(reservation_based_admission_control.auto_compute_percentages) is not set to false.
type: int
default: 50
type: dict
failover_host_admission_control:
description:
- Configure dedicated failover hosts.
- - C(slot_based_admission_control), C(reservation_based_admission_control) and C(failover_host_admission_control) are mutually exclusive.
+ - O(slot_based_admission_control), O(reservation_based_admission_control) and O(failover_host_admission_control) are mutually exclusive.
suboptions:
failover_hosts:
description:
@@ -122,7 +124,7 @@ options:
description:
- The number of seconds after which virtual machine is declared as failed
if no heartbeat has been received.
- - This setting is only valid if C(ha_vm_monitoring) is set to, either C(vmAndAppMonitoring) or C(vmMonitoringOnly).
+ - This setting is only valid if O(ha_vm_monitoring=vmAndAppMonitoring) or O(ha_vm_monitoring=vmMonitoringOnly).
- Unit is seconds.
type: int
default: 30
@@ -130,22 +132,22 @@ options:
description:
- The number of seconds for the virtual machine's heartbeats to stabilize after
the virtual machine has been powered on.
- - Valid only when I(ha_vm_monitoring) is set to either C(vmAndAppMonitoring) or C(vmMonitoringOnly).
+ - Valid only when O(ha_vm_monitoring=vmAndAppMonitoring) or O(ha_vm_monitoring=vmMonitoringOnly).
- Unit is seconds.
type: int
default: 120
ha_vm_max_failures:
description:
- Maximum number of failures and automated resets allowed during the time
- that C(ha_vm_max_failure_window) specifies.
- - Valid only when I(ha_vm_monitoring) is set to either C(vmAndAppMonitoring) or C(vmMonitoringOnly).
+ that O(ha_vm_max_failure_window) specifies.
+ - Valid only when O(ha_vm_monitoring=vmAndAppMonitoring) or O(ha_vm_monitoring=vmMonitoringOnly).
type: int
default: 3
ha_vm_max_failure_window:
description:
- - The number of seconds for the window during which up to C(ha_vm_max_failures) resets
+ - The number of seconds for the window during which up to O(ha_vm_max_failures) resets
can occur before automated responses stop.
- - Valid only when I(ha_vm_monitoring) is set to either C(vmAndAppMonitoring) or C(vmMonitoringOnly).
+ - Valid only when O(ha_vm_monitoring=vmAndAppMonitoring) or O(ha_vm_monitoring=vmMonitoringOnly).
- Unit is seconds.
- Default specifies no failure window.
type: int
@@ -154,13 +156,13 @@ options:
description:
- Priority HA gives to a virtual machine if sufficient capacity is not available
to power on all failed virtual machines.
- - Valid only if I(ha_vm_monitoring) is set to either C(vmAndAppMonitoring) or C(vmMonitoringOnly).
- - If set to C(disabled), then HA is disabled for this virtual machine.
- - If set to C(high), then virtual machine with this priority have a higher chance of powering on after a failure,
+ - Valid only when O(ha_vm_monitoring=vmAndAppMonitoring) or O(ha_vm_monitoring=vmMonitoringOnly).
+ - If set to V(disabled), then HA is disabled for this virtual machine.
+ - If set to V(high), then virtual machine with this priority have a higher chance of powering on after a failure,
when there is insufficient capacity on hosts to meet all virtual machine needs.
- - If set to C(medium), then virtual machine with this priority have an intermediate chance of powering on after a failure,
+ - If set to V(medium), then virtual machine with this priority have an intermediate chance of powering on after a failure,
when there is insufficient capacity on hosts to meet all virtual machine needs.
- - If set to C(low), then virtual machine with this priority have a lower chance of powering on after a failure,
+ - If set to V(low), then virtual machine with this priority have a lower chance of powering on after a failure,
when there is insufficient capacity on hosts to meet all virtual machine needs.
type: str
default: 'medium'
@@ -179,18 +181,16 @@ options:
apd_delay:
description:
- The response recovery delay time in sec for storage failures categorized as All Paths Down (APD).
- - Only set if C(apd_response) is C(restartConservative) or C(restartAggressive).
+ - Only set if O(apd_response=restartConservative) or O(apd_response=restartAggressive).
type: int
default: 180
- version_added: '2.9.0'
apd_reaction:
description:
- VM response recovery reaction for storage failures categorized as All Paths Down (APD).
- - Only set if C(apd_response) is C(restartConservative) or C(restartAggressive).
+ - Only set if O(apd_response=restartConservative) or O(apd_response=restartAggressive).
type: str
default: 'reset'
choices: [ 'reset', 'none' ]
- version_added: '2.9.0'
pdl_response:
description:
- VM storage protection setting for storage failures categorized as Permenant Device Loss (PDL).
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_cluster_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_cluster_info.py
index b3eded647..a015b6fc3 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_cluster_info.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_cluster_info.py
@@ -24,26 +24,26 @@ options:
datacenter:
description:
- Datacenter to search for cluster/s.
- - This parameter is required, if C(cluster_name) is not supplied.
+ - This parameter is required, if O(cluster_name) is not supplied.
required: false
type: str
cluster_name:
description:
- Name of the cluster.
- If set, information of this cluster will be returned.
- - This parameter is required, if C(datacenter) is not supplied.
+ - This parameter is required, if O(datacenter) is not supplied.
required: false
type: str
show_tag:
description:
- - Tags related to cluster are shown if set to C(true).
+ - Tags related to cluster are shown if set to V(true).
default: false
type: bool
schema:
description:
- Specify the output schema desired.
- - The 'summary' output schema is the legacy output from the module.
- - The 'vsphere' output schema is the vSphere API class definition which requires pyvmomi>6.7.1.
+ - The V(summary) output schema is the legacy output from the module.
+ - The V(vsphere) output schema is the vSphere API class definition which requires pyvmomi>6.7.1.
choices: ['summary', 'vsphere']
default: 'summary'
type: str
@@ -56,7 +56,7 @@ options:
- ' "configuration.dasConfig.enabled",'
- ' "summary.totalCpu"'
- ' ]'
- - Only valid when C(schema) is C(vsphere).
+ - Only valid when O(schema=vsphere).
type: list
elements: str
extends_documentation_fragment:
@@ -112,7 +112,6 @@ RETURN = r'''
clusters:
description:
- metadata about the available clusters
- - datacenter added in the return values from version 1.6.0
returned: always
type: dict
sample: {
@@ -184,7 +183,7 @@ except ImportError:
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.six.moves.urllib.parse import unquote
-from ansible_collections.community.vmware.plugins.module_utils.vmware import PyVmomi, vmware_argument_spec, find_datacenter_by_name, find_cluster_by_name,\
+from ansible_collections.community.vmware.plugins.module_utils.vmware import PyVmomi, vmware_argument_spec, find_datacenter_by_name, find_cluster_by_name, \
get_parent_datacenter
from ansible_collections.community.vmware.plugins.module_utils.vmware_rest_client import VmwareRestClient
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_cluster_vsan.py b/ansible_collections/community/vmware/plugins/modules/vmware_cluster_vsan.py
index a78aa1575..9f82aada8 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_cluster_vsan.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_cluster_vsan.py
@@ -57,7 +57,7 @@ options:
disable_site_read_locality:
description:
- For vSAN stretched clusters, reads to vSAN objects occur on the site the VM resides on.
- - Setting to C(true) will force reads across all mirrors.
+ - Setting to V(true) will force reads across all mirrors.
type: bool
large_cluster_support:
description:
@@ -69,7 +69,7 @@ options:
type: int
thin_swap:
description:
- - When C(enabled), swap objects would not reserve 100% space of their size on vSAN datastore.
+ - When V(true), swap objects would not reserve 100% space of their size on vSAN datastore.
type: bool
type: dict
extends_documentation_fragment:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_content_deploy_template.py b/ansible_collections/community/vmware/plugins/modules/vmware_content_deploy_template.py
index 6a10d7daa..3e0603373 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_content_deploy_template.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_content_deploy_template.py
@@ -58,7 +58,7 @@ options:
datastore:
description:
- Name of the datastore to store deployed VM and disk.
- - Required if I(datastore_cluster) is not provided.
+ - Required if O(datastore_cluster) is not provided.
type: str
required: false
datastore_cluster:
@@ -66,7 +66,7 @@ options:
- Name of the datastore cluster to store deployed VM and disk.
- Please make sure Storage DRS is active for recommended datastore from the given datastore cluster.
- If Storage DRS is not enabled, datastore with largest free storage space is selected.
- - Required if I(datastore) is not provided.
+ - Required if O(datastore) is not provided.
type: str
required: false
folder:
@@ -78,31 +78,31 @@ options:
description:
- Name of the ESX Host in datacenter in which to place deployed VM.
- The host has to be a member of the cluster that contains the resource pool.
- - Required with I(resource_pool) to find resource pool details. This will be used as additional
+ - Required with O(resource_pool) to find resource pool details. This will be used as additional
information when there are resource pools with same name.
type: str
required: false
resource_pool:
description:
- Name of the resource pool in datacenter in which to place deployed VM.
- - Required if I(cluster) is not specified.
- - For default or non-unique resource pool names, specify I(host) and I(cluster).
+ - Required if O(cluster) is not specified.
+ - For default or non-unique resource pool names, specify O(host) and O(cluster).
- C(Resources) is the default name of resource pool.
type: str
required: false
cluster:
description:
- Name of the cluster in datacenter in which to place deployed VM.
- - Required if I(resource_pool) is not specified.
+ - Required if O(resource_pool) is not specified.
type: str
required: false
state:
description:
- The state of Virtual Machine deployed from template in content library.
- - If set to C(present) and VM does not exists, then VM is created.
- - If set to C(present) and VM exists, no action is taken.
- - If set to C(poweredon) and VM does not exists, then VM is created with powered on state.
- - If set to C(poweredon) and VM exists, no action is taken.
+ - If set to V(present) and VM does not exists, then VM is created.
+ - If set to V(present) and VM exists, no action is taken.
+ - If set to V(poweredon) and VM does not exists, then VM is created with powered on state.
+ - If set to V(poweredon) and VM exists, no action is taken.
type: str
required: false
default: 'present'
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_content_library_manager.py b/ansible_collections/community/vmware/plugins/modules/vmware_content_library_manager.py
index 4b52b6cd1..932b77b6d 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_content_library_manager.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_content_library_manager.py
@@ -31,16 +31,16 @@ options:
library_description:
description:
- The content library description.
- - This is required only if I(state) is set to C(present).
- - This parameter is ignored, when I(state) is set to C(absent).
+ - This is required only if O(state=present).
+ - This parameter is ignored, when O(state=absent).
- Process of updating content library only allows description change.
type: str
required: false
library_type:
description:
- The content library type.
- - This is required only if I(state) is set to C(present).
- - This parameter is ignored, when I(state) is set to C(absent).
+ - This is required only if O(state=resent).
+ - This parameter is ignored, when O(state=absent).
type: str
required: false
default: 'local'
@@ -48,8 +48,8 @@ options:
datastore_name:
description:
- Name of the datastore on which backing content library is created.
- - This is required only if I(state) is set to C(present).
- - This parameter is ignored, when I(state) is set to C(absent).
+ - This is required if O(state=present).
+ - This parameter is ignored, when O(state=absent).
- Currently only datastore backing creation is supported.
type: str
required: false
@@ -57,16 +57,16 @@ options:
subscription_url:
description:
- The url of the content library to subscribe to.
- - This is required only if I(library_type) is set to C(subscribed).
- - This parameter is ignored, when I(state) is set to C(absent).
+ - This is required if O(library_type=subscribed).
+ - This parameter is ignored, when O(state=absent).
type: str
default: ''
required: false
ssl_thumbprint:
description:
- The SHA1 SSL thumbprint of the subscribed content library to subscribe to.
- - This is required only if I(library_type) is set to C(subscribed) and the library is https.
- - This parameter is ignored, when I(state) is set to C(absent).
+ - This is required if O(library_type=subscribed) and the library is https.
+ - This parameter is ignored, when O(state=absent).
- 'The information can be extracted using openssl using the following example:
C(echo | openssl s_client -connect test-library.com:443 |& openssl x509 -fingerprint -noout)'
type: str
@@ -75,19 +75,19 @@ options:
update_on_demand:
description:
- Whether to download all content on demand.
- - If set to C(true), all content will be downloaded on demand.
- - If set to C(false) content will be downloaded ahead of time.
- - This is required only if I(library_type) is set to C(subscribed).
- - This parameter is ignored, when I(state) is set to C(absent).
+ - If set to V(true), all content will be downloaded on demand.
+ - If set to V(false) content will be downloaded ahead of time.
+ - This is required if O(library_type=subscribed).
+ - This parameter is ignored, when O(state=absent).
type: bool
default: false
state:
description:
- The state of content library.
- - If set to C(present) and library does not exists, then content library is created.
- - If set to C(present) and library exists, then content library is updated.
- - If set to C(absent) and library exists, then content library is deleted.
- - If set to C(absent) and library does not exists, no action is taken.
+ - If set to V(present) and library does not exists, then content library is created.
+ - If set to V(present) and library exists, then content library is updated.
+ - If set to V(absent) and library exists, then content library is deleted.
+ - If set to V(absent) and library does not exists, no action is taken.
type: str
required: false
default: 'present'
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_custom_attribute.py b/ansible_collections/community/vmware/plugins/modules/vmware_custom_attribute.py
index 618aa6fe0..2d33ba254 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_custom_attribute.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_custom_attribute.py
@@ -43,10 +43,10 @@ options:
state:
description:
- Manage definition of custom attributes.
- - If set to C(present) and definition not present, then custom attribute definition is created.
- - If set to C(present) and definition is present, then no action taken.
- - If set to C(absent) and definition is present, then custom attribute definition is removed.
- - If set to C(absent) and definition is absent, then no action taken.
+ - If set to V(present) and definition not present, then custom attribute definition is created.
+ - If set to V(present) and definition is present, then no action taken.
+ - If set to V(absent) and definition is present, then custom attribute definition is removed.
+ - If set to V(absent) and definition is absent, then no action taken.
default: 'present'
choices: ['present', 'absent']
type: str
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_custom_attribute_manager.py b/ansible_collections/community/vmware/plugins/modules/vmware_custom_attribute_manager.py
index 65ad207c4..0eef52182 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_custom_attribute_manager.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_custom_attribute_manager.py
@@ -22,7 +22,7 @@ options:
custom_attributes:
description:
- A list of name and value of custom attributes that needs to be manage.
- - Value of custom attribute is not required and will be ignored, if C(state) is set to C(absent).
+ - Value of custom attribute is not required and will be ignored if O(state=absent).
suboptions:
name:
description:
@@ -59,8 +59,8 @@ options:
required: true
state:
description:
- - If set to C(present), the custom attribute is set to the given value.
- - If set to C(absent), the custom attribute is cleared. The given value is ignored in this case.
+ - If set to V(present), the custom attribute is set to the given value.
+ - If set to V(absent), the custom attribute is cleared. The given value is ignored in this case.
default: 'present'
choices: ['present', 'absent']
type: str
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_datacenter_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_datacenter_info.py
index de1f7addf..3b8dfc878 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_datacenter_info.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_datacenter_info.py
@@ -28,8 +28,8 @@ options:
schema:
description:
- Specify the output schema desired.
- - The 'summary' output schema is the legacy output from the module.
- - The 'vsphere' output schema is the vSphere API class definition which requires pyvmomi>6.7.1.
+ - The V(summary) output schema is the legacy output from the module.
+ - The V(vsphere) output schema is the vSphere API class definition which requires pyvmomi>6.7.1.
choices: ['summary', 'vsphere']
default: 'summary'
type: str
@@ -42,12 +42,12 @@ options:
- ' properties: ['
- ' "overallStatus"'
- ' ]'
- - Only valid when C(schema) is C(vsphere).
+ - Only valid when O(schema=vsphere).
type: list
elements: str
show_tag:
description:
- - Tags related to Datacenter are shown if set to C(true).
+ - Tags related to Datacenter are shown if set to V(true).
default: false
type: bool
extends_documentation_fragment:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_datastore.py b/ansible_collections/community/vmware/plugins/modules/vmware_datastore.py
index b26ebbc9e..9ca1119e8 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_datastore.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_datastore.py
@@ -40,20 +40,20 @@ options:
- Storage I/O congestion threshold in percentage of peak throughput.
- "A value between 50% and 100%."
- "Recommended: 90%"
- - Only use C(congestion_threshold_percentage) or C(congestion_threshold_manual).
- - Only valid when C(storage_io_control) is C(enable_io_statistics).
+ - Only use O(congestion_threshold_percentage) or O(congestion_threshold_manual).
+ - Only valid when O(storage_io_control=enable_io_statistics).
type: int
default: 90
congestion_threshold_manual:
description:
- Storage I/O congestion threshold in ms.
- - Only use C(congestion_threshold_percentage) or C(congestion_threshold_manual).
- - Only valid when C(storage_io_control) is C(enable_io_statistics).
+ - Only use O(congestion_threshold_percentage) or O(congestion_threshold_manual).
+ - Only valid when O(storage_io_control=enable_io_statistics).
type: int
statistic_collection:
description:
- Include I/O statistics for SDRS.
- - Only valid when C(storage_io_control) is C(enable_io_statistics) or C(enable_statistics).
+ - Only valid when O(storage_io_control=enable_io_statistics) or O(storage_io_control=enable_statistics).
type: bool
default: true
extends_documentation_fragment:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_datastore_cluster.py b/ansible_collections/community/vmware/plugins/modules/vmware_datastore_cluster.py
index a6170b19d..7a7dccbaf 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_datastore_cluster.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_datastore_cluster.py
@@ -23,8 +23,8 @@ options:
datacenter_name:
description:
- The name of the datacenter.
- - You must specify either a C(datacenter_name) or a C(folder).
- - Mutually exclusive with C(folder) parameter.
+ - You must specify either a O(datacenter_name) or a O(folder).
+ - Mutually exclusive with O(folder) parameter.
required: false
aliases: [ datacenter ]
type: str
@@ -44,7 +44,7 @@ options:
- Destination folder, absolute path to place datastore cluster in.
- The folder should include the datacenter.
- This parameter is case sensitive.
- - You must specify either a C(folder) or a C(datacenter_name).
+ - You must specify either a O(folder) or a O(datacenter_name).
- 'Examples:'
- ' folder: /datacenter1/datastore'
- ' folder: datacenter1/datastore'
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_datastore_cluster_manager.py b/ansible_collections/community/vmware/plugins/modules/vmware_datastore_cluster_manager.py
index f22a98393..b36b45af1 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_datastore_cluster_manager.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_datastore_cluster_manager.py
@@ -34,8 +34,8 @@ options:
aliases: [ datastore_cluster ]
state:
description:
- - If set to I(present), datastores specified by I(datastores) will be added to the given datastore cluster.
- - If set to I(absent), datastores specified by I(datastores) will be moved from the given datastore cluster to datstore folder of the parent datacenter.
+ - If set to V(present), datastores specified by O(datastores) will be added to the given datastore cluster.
+ - If set to V(absent), datastores specified by O(datastores) will be moved from the given datastore cluster to datstore folder of the parent datacenter.
choices: [ present, absent ]
default: present
type: str
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_datastore_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_datastore_info.py
index ed3a85cb5..053c1bb1f 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_datastore_info.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_datastore_info.py
@@ -29,7 +29,7 @@ options:
datacenter:
description:
- Datacenter to search for datastores.
- - This parameter is required, if C(cluster) is not supplied.
+ - This parameter is required, if O(cluster) is not supplied.
required: false
aliases: ['datacenter_name']
type: str
@@ -37,21 +37,21 @@ options:
description:
- Cluster to search for datastores.
- If set, information of datastores belonging this clusters will be returned.
- - This parameter is required, if C(datacenter) is not supplied.
+ - This parameter is required, if O(datacenter) is not supplied.
required: false
type: str
gather_nfs_mount_info:
description:
- Gather mount information of NFS datastores.
- Disabled per default because this slows down the execution if you have a lot of datastores.
- - Only valid when C(schema) is C(summary).
+ - Only valid when O(schema=summary).
type: bool
default: false
gather_vmfs_mount_info:
description:
- Gather mount information of VMFS datastores.
- Disabled per default because this slows down the execution if you have a lot of datastores.
- - Only valid when C(schema) is C(summary).
+ - Only valid when O(schema=summary).
type: bool
default: false
schema:
@@ -65,7 +65,7 @@ options:
type: str
show_tag:
description:
- - Tags related to Datastore are shown if set to C(true).
+ - Tags related to Datastore are shown if set to V(true).
default: false
type: bool
properties:
@@ -80,7 +80,7 @@ options:
- ' "capability.vsanSparseSupported",'
- ' "overallStatus"'
- ' ]'
- - Only valid when C(schema) is C(vsphere).
+ - Only valid when O(schema=vsphere).
type: list
required: false
elements: str
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_datastore_maintenancemode.py b/ansible_collections/community/vmware/plugins/modules/vmware_datastore_maintenancemode.py
index df14e4bda..079bdbeb4 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_datastore_maintenancemode.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_datastore_maintenancemode.py
@@ -22,25 +22,25 @@ options:
datastore:
description:
- Name of datastore to manage.
- - If C(datastore_cluster) or C(cluster_name) are not set, this parameter is required.
+ - If O(datastore_cluster) or O(cluster_name) are not set, this parameter is required.
type: str
datastore_cluster:
description:
- Name of the datastore cluster from all child datastores to be managed.
- - If C(datastore) or C(cluster_name) are not set, this parameter is required.
+ - If O(datastore) or O(cluster_name) are not set, this parameter is required.
type: str
cluster_name:
description:
- Name of the cluster where datastore is connected to.
- - If multiple datastores are connected to the given cluster, then all datastores will be managed by C(state).
- - If C(datastore) or C(datastore_cluster) are not set, this parameter is required.
+ - If multiple datastores are connected to the given cluster, then all datastores will be managed by O(state).
+ - If O(datastore) or O(datastore_cluster) are not set, this parameter is required.
type: str
state:
description:
- - If set to C(present), then enter datastore into maintenance mode.
- - If set to C(present) and datastore is already in maintenance mode, then no action will be taken.
- - If set to C(absent) and datastore is in maintenance mode, then exit maintenance mode.
- - If set to C(absent) and datastore is not in maintenance mode, then no action will be taken.
+ - If set to V(present), then enter datastore into maintenance mode.
+ - If set to V(present) and datastore is already in maintenance mode, then no action will be taken.
+ - If set to V(absent) and datastore is in maintenance mode, then exit maintenance mode.
+ - If set to V(absent) and datastore is not in maintenance mode, then no action will be taken.
choices: [ present, absent ]
default: present
required: false
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_deploy_ovf.py b/ansible_collections/community/vmware/plugins/modules/vmware_deploy_ovf.py
index cece1cb76..06ca29f74 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_deploy_ovf.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_deploy_ovf.py
@@ -1,7 +1,8 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
-# Copyright: (c) 2017, Matt Martz <matt@sivel.net>
+# based on code vmware_deploy_ovf from Matt Martz <matt@sivel.net>
+# Copyright: (c) 2023, Alexander Nikitin <alexander@ihumster.ru>
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
@@ -10,12 +11,15 @@ __metaclass__ = type
DOCUMENTATION = r'''
-author: 'Matt Martz (@sivel)'
-short_description: 'Deploys a VMware virtual machine from an OVF or OVA file'
+author:
+ - Alexander Nikitin (@ihumster)
+ - Matt Martz (@sivel)
+short_description: 'Deploys a VMware virtual machine from an OVF or OVA file, placed on file system or HTTP server'
description:
-- 'This module can be used to deploy a VMware VM from an OVF or OVA file'
+ - 'This module can be used to deploy a VMware VM from an OVF or OVA file, placed on file system or HTTP server'
module: vmware_deploy_ovf
-notes: []
+notes:
+ - 'For use https as source need enable in firewall incoming 443 port'
options:
allow_duplicates:
default: "True"
@@ -30,15 +34,15 @@ options:
cluster:
description:
- Cluster to deploy to.
- - This is a required parameter, if C(esxi_hostname) is not set and C(hostname) is set to the vCenter server.
- - C(esxi_hostname) and C(cluster) are mutually exclusive parameters.
+ - This is a required parameter, if O(esxi_hostname) is not set and O(hostname) is set to the vCenter server.
+ - O(esxi_hostname) and O(cluster) are mutually exclusive parameters.
- This parameter is case sensitive.
type: str
esxi_hostname:
description:
- The ESXi hostname where the virtual machine will run.
- - This is a required parameter, if C(cluster) is not set and C(hostname) is set to the vCenter server.
- - C(esxi_hostname) and C(cluster) are mutually exclusive parameters.
+ - This is a required parameter, if O(cluster) is not set and O(hostname) is set to the vCenter server.
+ - O(esxi_hostname) and O(cluster) are mutually exclusive parameters.
- This parameter is case sensitive.
type: str
datastore:
@@ -66,6 +70,12 @@ options:
description:
- Disk provisioning type.
type: str
+ enable_hidden_properties:
+ description:
+ - Enable source properties that are marked as C(ovf:userConfigurable=false).
+ default: false
+ version_added: '3.11.0'
+ type: bool
fail_on_spec_warnings:
description:
- Cause the module to treat OVF Import Spec warnings as errors.
@@ -105,9 +115,18 @@ options:
ovf:
description:
- 'Path to OVF or OVA file to deploy.'
+ - Required if O(url) is not set.
+ - O(ovf) and O(url) are mutually exclusive parameters.
aliases:
- ova
type: path
+ url:
+ description:
+ - 'URL for OVA file to deploy.'
+ - Required if O(ovf) is not set.
+ - O(url) and O(ovf) are mutually exclusive parameters.
+ type: str
+ version_added: '3.9.0'
power_on:
default: true
description:
@@ -170,6 +189,14 @@ EXAMPLES = r'''
datastore: test-datastore
ovf: /path/to/ubuntu-16.04-amd64.ovf
delegate_to: localhost
+
+- community.vmware.vmware_deploy_ovf:
+ hostname: '{{ vcenter_hostname }}'
+ username: '{{ vcenter_username }}'
+ password: '{{ vcenter_password }}'
+ url: https://cloud-images.ubuntu.com/releases/xenial/release/ubuntu-16.04-server-cloudimg-amd64.ova
+ wait_for_ip_address: true
+ delegate_to: localhost
'''
@@ -181,8 +208,11 @@ instance:
sample: None
'''
+import hashlib
import io
import os
+import re
+import ssl
import sys
import tarfile
import time
@@ -195,9 +225,10 @@ from threading import Thread
from ansible.module_utils._text import to_native
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.six import string_types
+from ansible.module_utils.six.moves.urllib.request import Request, urlopen
from ansible.module_utils.urls import generic_urlparse, open_url, urlparse, urlunparse
from ansible_collections.community.vmware.plugins.module_utils.vmware import (
- find_network_by_name,
+ find_all_networks_by_name,
find_vm_by_name,
PyVmomi,
gather_vm_facts,
@@ -217,10 +248,98 @@ def path_exists(value):
value = str(value)
value = os.path.expanduser(os.path.expandvars(value))
if not os.path.exists(value):
- raise ValueError('%s is not a valid path' % value)
+ raise ValueError(f"'{value}' is not a valid path")
return value
+class WebHandle(object):
+ def __init__(self, url):
+ self.url = url
+ self.thumbprint = None
+ self.ssl_context = None
+
+ self.parsed_url = self._parse_url(url)
+
+ self.https = self.parsed_url.group('scheme') == 'https://'
+
+ if self.https:
+ self.ssl_context = ssl._create_default_https_context()
+ self.ssl_context.check_hostname = False
+ self.ssl_context.verify_mode = ssl.CERT_NONE
+
+ self.thumbprint = self._get_thumbprint(
+ self.parsed_url.group('hostname'))
+ r = urlopen(url=url, context=self.ssl_context)
+ else:
+ r = urlopen(url)
+ if r.code != 200:
+ raise FileNotFoundError(url)
+ self.headers = self._headers_to_dict(r)
+ if 'accept-ranges' not in self.headers:
+ raise Exception("Site does not accept ranges")
+ self.st_size = int(self.headers['content-length'])
+ self.offset = 0
+
+ def _parse_url(self, url):
+ HTTP_SCHEMA_PATTERN = (
+ r"(?P<url>(?:(?P<scheme>[a-zA-Z]+:\/\/)?(?P<hostname>(?:[-a-zA-Z0-9@%_\+~#=]{1,256}\.){1,256}(?:[-a-zA-Z0-9@%_\+~#=]{1,256})))"
+ r"(?::(?P<port>[[:digit:]]+))?(?P<path>(?:\/[-a-zA-Z0-9!$&'()*+,\\\/:;=@\[\]._~%]*)*)"
+ r"(?P<query>(?:(?:\#|\?)[-a-zA-Z0-9!$&'()*+,\\\/:;=@\[\]._~]*)*))"
+ )
+ return re.match(HTTP_SCHEMA_PATTERN, url)
+
+ def _get_thumbprint(self, hostname):
+ pem = ssl.get_server_certificate((hostname, 443))
+ sha1 = hashlib.sha1(
+ ssl.PEM_cert_to_DER_cert(pem)).hexdigest().upper()
+ colon_notion = ':'.join(sha1[i:i + 2] for i in range(0, len(sha1), 2))
+
+ return None if sha1 is None else colon_notion
+
+ def _headers_to_dict(self, r):
+ result = {}
+ if hasattr(r, 'getheaders'):
+ for n, v in r.getheaders():
+ result[n.lower()] = v.strip()
+ else:
+ for line in r.info().headers:
+ if line.find(':') != -1:
+ n, v = line.split(': ', 1)
+ result[n.lower()] = v.strip()
+ return result
+
+ def tell(self):
+ return self.offset
+
+ def seek(self, offset, whence=0):
+ if whence == 0:
+ self.offset = offset
+ elif whence == 1:
+ self.offset += offset
+ elif whence == 2:
+ self.offset = self.st_size - offset
+ return self.offset
+
+ def seekable(self):
+ return True
+
+ def read(self, amount):
+ start = self.offset
+ end = self.offset + amount - 1
+ req = Request(self.url,
+ headers={'Range': 'bytes=%d-%d' % (start, end)})
+ r = urlopen(req) if not self.ssl_context else urlopen(
+ req, context=self.ssl_context)
+ self.offset += amount
+ result = r.read(amount)
+ r.close()
+ return result
+
+ # A slightly more accurate percentage
+ def progress(self):
+ return int(100.0 * self.offset / self.st_size)
+
+
class ProgressReader(io.FileIO):
def __init__(self, name, mode='r', closefd=True):
self.bytes_read = 0
@@ -326,6 +445,7 @@ class VMwareDeployOvf(PyVmomi):
self.module = module
self.params = module.params
+ self.handle = None
self.datastore = None
self.datacenter = None
self.resource_pool = None
@@ -342,26 +462,27 @@ class VMwareDeployOvf(PyVmomi):
# Get datacenter firstly
self.datacenter = self.find_datacenter_by_name(self.params['datacenter'])
if self.datacenter is None:
- self.module.fail_json(msg="Datacenter '%(datacenter)s' could not be located" % self.params)
+ self.module.fail_json(msg=f"Datacenter '{self.params['datacenter']}' could not be located")
# Get cluster in datacenter if cluster configured
if self.params['cluster']:
cluster = self.find_cluster_by_name(self.params['cluster'], datacenter_name=self.datacenter)
if cluster is None:
- self.module.fail_json(msg="Unable to find cluster '%(cluster)s'" % self.params)
+ self.module.fail_json(msg=f"Unable to find cluster '{self.params['cluster']}'")
self.resource_pool = self.find_resource_pool_by_cluster(self.params['resource_pool'], cluster=cluster)
# Or get ESXi host in datacenter if ESXi host configured
elif self.params['esxi_hostname']:
host = self.find_hostsystem_by_name(self.params['esxi_hostname'], datacenter=self.datacenter)
if host is None:
- self.module.fail_json(msg="Unable to find host '%(esxi_hostname)s' in datacenter '%(datacenter)s'" % self.params)
+ self.module.fail_json(msg=f"Unable to find host '{self.params['esxi_hostname']}' in datacenter"
+ " '{self.params['datacenter']}'")
self.resource_pool = self.find_resource_pool_by_name(self.params['resource_pool'], folder=host.parent)
else:
# For more than one datacenter env, specify 'folder' to datacenter hostFolder
self.resource_pool = self.find_resource_pool_by_name(self.params['resource_pool'], folder=self.datacenter.hostFolder)
if not self.resource_pool:
- self.module.fail_json(msg="Resource pool '%(resource_pool)s' could not be located" % self.params)
+ self.module.fail_json(msg=f"Resource pool '{self.params['resource_pool']}' could not be located")
self.datastore = None
datastore_cluster_obj = self.find_datastore_cluster_by_name(self.params['datastore'], datacenter=self.datacenter)
@@ -381,44 +502,67 @@ class VMwareDeployOvf(PyVmomi):
self.datastore = self.find_datastore_by_name(self.params['datastore'], datacenter_name=self.datacenter)
if self.datastore is None:
- self.module.fail_json(msg="Datastore '%(datastore)s' could not be located on specified ESXi host or"
- " datacenter" % self.params)
+ self.module.fail_json(msg=f"Datastore '{self.params['datastore']}' could not be located on specified ESXi host or"
+ " datacenter")
for key, value in self.params['networks'].items():
- network = find_network_by_name(self.content, value, datacenter_name=self.datacenter)
- if not network:
- self.module.fail_json(msg='%(networks)s could not be located' % self.params)
- network_mapping = vim.OvfManager.NetworkMapping()
- network_mapping.name = key
- network_mapping.network = network
- self.network_mappings.append(network_mapping)
-
+ # If we have the same network name defined in multiple clusters, check all networks to get the right one
+ networks = find_all_networks_by_name(self.content, value, datacenter_name=self.datacenter)
+ if not networks:
+ self.module.fail_json(msg=f"Network '{value}' could not be located")
+ # Search for the network key of the same network name, that resides in a cluster parameter
+ for network in networks:
+ if self.params['cluster']:
+ if network in cluster.network:
+ network_mapping = vim.OvfManager.NetworkMapping()
+ network_mapping.name = key
+ network_mapping.network = network
+ self.network_mappings.append(network_mapping)
+ else:
+ network_mapping = vim.OvfManager.NetworkMapping()
+ network_mapping.name = key
+ network_mapping.network = network
+ self.network_mappings.append(network_mapping)
return self.datastore, self.datacenter, self.resource_pool, self.network_mappings
def get_ovf_descriptor(self):
- # Check whether ovf/ova file exists
- try:
- path_exists(self.params['ovf'])
- except ValueError as e:
- self.module.fail_json(msg="%s" % e)
-
- if tarfile.is_tarfile(self.params['ovf']):
- self.tar = tarfile.open(self.params['ovf'])
- ovf = None
- for candidate in self.tar.getmembers():
- dummy, ext = os.path.splitext(candidate.name)
- if ext.lower() == '.ovf':
- ovf = candidate
- break
- if not ovf:
- self.module.fail_json(msg='Could not locate OVF file in %(ovf)s' % self.params)
-
- self.ovf_descriptor = to_native(self.tar.extractfile(ovf).read())
- else:
- with open(self.params['ovf']) as f:
- self.ovf_descriptor = f.read()
+ if self.params['url'] is None:
+ # Check whether ovf/ova file exists
+ try:
+ path_exists(self.params['ovf'])
+ except ValueError as e:
+ self.module.fail_json(msg="%s" % e)
+
+ if tarfile.is_tarfile(self.params['ovf']):
+ self.tar = tarfile.open(self.params['ovf'])
+ ovf = None
+ for candidate in self.tar.getmembers():
+ dummy, ext = os.path.splitext(candidate.name)
+ if ext.lower() == '.ovf':
+ ovf = candidate
+ break
+ if not ovf:
+ self.module.fail_json(msg='Could not locate OVF file in %(ovf)s' % self.params)
+
+ self.ovf_descriptor = to_native(self.tar.extractfile(ovf).read())
+ else:
+ with open(self.params['ovf'], encoding="utf-8") as f:
+ self.ovf_descriptor = f.read()
- return self.ovf_descriptor
+ return self.ovf_descriptor
+ else:
+ self.handle = WebHandle(self.params['url'])
+ self.tar = tarfile.open(fileobj=self.handle)
+ ovffilename = list(
+ filter(lambda x: x.endswith('.ovf'), self.tar.getnames()))[0]
+ ovffile = self.tar.extractfile(ovffilename)
+ self.ovf_descriptor = ovffile.read().decode()
+
+ if self.ovf_descriptor:
+ return self.ovf_descriptor
+ else:
+ self.module.fail_json(
+ msg='Could not locate OVF file in %(url)s' % self.params)
def get_lease(self):
datastore, datacenter, resource_pool, network_mappings = self.get_objects()
@@ -443,7 +587,7 @@ class VMwareDeployOvf(PyVmomi):
if self.params['folder']:
folder = self.content.searchIndex.FindByInventoryPath(self.params['folder'])
if not folder:
- self.module.fail_json(msg="Unable to find the specified folder %(folder)s" % self.params)
+ self.module.fail_json(msg=f"Unable to find the specified folder {self.params['folder']}")
else:
folder = datacenter.vmFolder
@@ -458,6 +602,10 @@ class VMwareDeployOvf(PyVmomi):
spec_params
)
+ if self.params['enable_hidden_properties']:
+ for prop in self.import_spec.importSpec.configSpec.vAppConfig.property:
+ prop.info.userConfigurable = True
+
errors = [to_native(e.msg) for e in getattr(self.import_spec, 'error', [])]
if self.params['fail_on_spec_warnings']:
errors.extend(
@@ -465,11 +613,11 @@ class VMwareDeployOvf(PyVmomi):
)
if errors:
self.module.fail_json(
- msg='Failure validating OVF import spec: %s' % '. '.join(errors)
+ msg=f"Failure validating OVF import spec: {'. '.join(errors)}"
)
for warning in getattr(self.import_spec, 'warning', []):
- self.module.warn('Problem validating OVF import spec: %s' % to_native(warning.msg))
+ self.module.warn(f"Problem validating OVF import spec: {to_native(warning.msg)}")
name = self.params.get('name')
if not self.params['allow_duplicates']:
@@ -486,9 +634,9 @@ class VMwareDeployOvf(PyVmomi):
self.import_spec.importSpec,
folder
)
- except vmodl.fault.SystemError as e:
+ except vmodl.fault.SystemError as err:
self.module.fail_json(
- msg='Failed to start import: %s' % to_native(e.msg)
+ msg=f"Failed to start import: {to_native(err.msg)}"
)
while self.lease.state != vim.HttpNfcLease.State.ready:
@@ -520,81 +668,97 @@ class VMwareDeployOvf(PyVmomi):
def upload(self):
if self.params['ovf'] is None:
- self.module.fail_json(msg="OVF path is required for upload operation.")
+ # Upload from url
+ lease, import_spec = self.get_lease()
+
+ ssl_thumbprint = self.handle.thumbprint if self.handle.thumbprint else None
+ source_files = []
+ for file_item in import_spec.fileItem:
+ source_file = vim.HttpNfcLease.SourceFile(
+ url=self.handle.url,
+ targetDeviceId=file_item.deviceId,
+ create=file_item.create,
+ size=file_item.size,
+ sslThumbprint=ssl_thumbprint,
+ memberName=file_item.path
+ )
+ source_files.append(source_file)
- ovf_dir = os.path.dirname(self.params['ovf'])
+ wait_for_task(lease.HttpNfcLeasePullFromUrls_Task(source_files))
+ else:
+ ovf_dir = os.path.dirname(self.params['ovf'])
- lease, import_spec = self.get_lease()
+ lease, import_spec = self.get_lease()
- uploaders = []
+ uploaders = []
- for file_item in import_spec.fileItem:
- device_upload_url = None
- for device_url in lease.info.deviceUrl:
- if file_item.deviceId == device_url.importKey:
- device_upload_url = self._normalize_url(device_url.url)
- break
+ for file_item in import_spec.fileItem:
+ device_upload_url = None
+ for device_url in lease.info.deviceUrl:
+ if file_item.deviceId == device_url.importKey:
+ device_upload_url = self._normalize_url(device_url.url)
+ break
- if not device_upload_url:
- lease.HttpNfcLeaseAbort(
- vmodl.fault.SystemError(reason='Failed to find deviceUrl for file %s' % file_item.path)
- )
- self.module.fail_json(
- msg='Failed to find deviceUrl for file %s' % file_item.path
- )
-
- vmdk_tarinfo = None
- if self.tar:
- vmdk = self.tar
- try:
- vmdk_tarinfo = self.tar.getmember(file_item.path)
- except KeyError:
+ if not device_upload_url:
lease.HttpNfcLeaseAbort(
- vmodl.fault.SystemError(reason='Failed to find VMDK file %s in OVA' % file_item.path)
+ vmodl.fault.SystemError(reason=f"Failed to find deviceUrl for file '{file_item.path}'")
)
self.module.fail_json(
- msg='Failed to find VMDK file %s in OVA' % file_item.path
+ msg=f"Failed to find deviceUrl for file '{file_item.path}'"
)
- else:
- vmdk = os.path.join(ovf_dir, file_item.path)
- try:
- path_exists(vmdk)
- except ValueError:
+
+ vmdk_tarinfo = None
+ if self.tar:
+ vmdk = self.tar
+ try:
+ vmdk_tarinfo = self.tar.getmember(file_item.path)
+ except KeyError:
+ lease.HttpNfcLeaseAbort(
+ vmodl.fault.SystemError(reason=f"Failed to find VMDK file '{file_item.path}' in OVA")
+ )
+ self.module.fail_json(
+ msg=f"Failed to find VMDK file '{file_item.path}' in OVA"
+ )
+ else:
+ vmdk = os.path.join(ovf_dir, file_item.path)
+ try:
+ path_exists(vmdk)
+ except ValueError:
+ lease.HttpNfcLeaseAbort(
+ vmodl.fault.SystemError(reason=f"Failed to find VMDK file at '{vmdk}'")
+ )
+ self.module.fail_json(
+ msg=f"Failed to find VMDK file at '{vmdk}'"
+ )
+
+ uploaders.append(
+ VMDKUploader(
+ vmdk,
+ device_upload_url,
+ self.params['validate_certs'],
+ tarinfo=vmdk_tarinfo,
+ create=file_item.create
+ )
+ )
+
+ total_size = sum(u.size for u in uploaders)
+ total_bytes_read = [0] * len(uploaders)
+ for i, uploader in enumerate(uploaders):
+ uploader.start()
+ while uploader.is_alive():
+ time.sleep(0.1)
+ total_bytes_read[i] = uploader.bytes_read
+ lease.HttpNfcLeaseProgress(int(100.0 * sum(total_bytes_read) / total_size))
+
+ if uploader.e:
lease.HttpNfcLeaseAbort(
- vmodl.fault.SystemError(reason='Failed to find VMDK file at %s' % vmdk)
+ vmodl.fault.SystemError(reason='%s' % to_native(uploader.e[1]))
)
self.module.fail_json(
- msg='Failed to find VMDK file at %s' % vmdk
+ msg='%s' % to_native(uploader.e[1]),
+ exception=''.join(traceback.format_tb(uploader.e[2]))
)
- uploaders.append(
- VMDKUploader(
- vmdk,
- device_upload_url,
- self.params['validate_certs'],
- tarinfo=vmdk_tarinfo,
- create=file_item.create
- )
- )
-
- total_size = sum(u.size for u in uploaders)
- total_bytes_read = [0] * len(uploaders)
- for i, uploader in enumerate(uploaders):
- uploader.start()
- while uploader.is_alive():
- time.sleep(0.1)
- total_bytes_read[i] = uploader.bytes_read
- lease.HttpNfcLeaseProgress(int(100.0 * sum(total_bytes_read) / total_size))
-
- if uploader.e:
- lease.HttpNfcLeaseAbort(
- vmodl.fault.SystemError(reason='%s' % to_native(uploader.e[1]))
- )
- self.module.fail_json(
- msg='%s' % to_native(uploader.e[1]),
- exception=''.join(traceback.format_tb(uploader.e[2]))
- )
-
def complete(self):
self.lease.HttpNfcLeaseComplete()
@@ -688,6 +852,9 @@ def main():
'type': 'path',
'aliases': ['ova'],
},
+ 'url': {
+ 'type': 'str',
+ },
'disk_provisioning': {
'choices': [
'flat',
@@ -703,6 +870,10 @@ def main():
],
'default': 'thin',
},
+ 'enable_hidden_properties': {
+ 'default': False,
+ 'type': 'bool',
+ },
'power_on': {
'type': 'bool',
'default': True,
@@ -730,8 +901,12 @@ def main():
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
+ required_one_of=[
+ ['ovf', 'url'],
+ ],
mutually_exclusive=[
['cluster', 'esxi_hostname'],
+ ['ovf', 'url'],
],
)
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_drs_group.py b/ansible_collections/community/vmware/plugins/modules/vmware_drs_group.py
index a4400d789..ef607072a 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_drs_group.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_drs_group.py
@@ -15,7 +15,7 @@ DOCUMENTATION = r'''
author:
- "Karsten Kaj Jakobsen (@karstenjakobsen)"
description:
- - "This module can be used to create VM/Host groups in a given cluster. Creates a vm group if C(vms) is set. Creates a host group if C(hosts) is set."
+ - "This module can be used to create VM/Host groups in a given cluster. Creates a vm group if O(vms) is set. Creates a host group if O(hosts) is set."
extends_documentation_fragment:
- community.vmware.vmware.documentation
@@ -30,7 +30,7 @@ options:
aliases:
- datacenter_name
description:
- - "Datacenter to search for given cluster. If not set, we use first cluster we encounter with C(cluster_name)."
+ - "Datacenter to search for given cluster. If not set, we use first cluster we encounter with O(cluster_name)."
required: false
type: str
group_name:
@@ -41,7 +41,8 @@ options:
hosts:
description:
- "List of hosts to create in group."
- - "Required only if C(vms) is not set."
+ - "Required if O(vms) is not set."
+ - "O(hosts) and O(vms) are mutually exclusive parameters."
required: false
type: list
elements: str
@@ -51,13 +52,14 @@ options:
- absent
default: present
description:
- - "If set to C(present) and the group doesn't exists then the group will be created."
- - "If set to C(absent) and the group exists then the group will be deleted."
+ - "If set to V(present) and the group doesn't exists then the group will be created."
+ - "If set to V(absent) and the group exists then the group will be deleted."
type: str
vms:
description:
- "List of vms to create in group."
- - "Required only if C(hosts) is not set."
+ - "Required if O(hosts) is not set."
+ - "O(hosts) and O(vms) are mutually exclusive parameters."
required: false
type: list
elements: str
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_drs_group_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_drs_group_info.py
index d964b5527..ff1e0773a 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_drs_group_info.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_drs_group_info.py
@@ -25,7 +25,8 @@ options:
description:
- "Cluster to search for VM/Host groups."
- "If set, information of DRS groups belonging this cluster will be returned."
- - "Not needed if C(datacenter) is set."
+ - "Needed if O(datacenter) is not set."
+ - "O(cluster_name) and O(datacenter) are mutually exclusive parameters."
required: false
type: str
datacenter:
@@ -33,6 +34,8 @@ options:
- datacenter_name
description:
- "Datacenter to search for DRS VM/Host groups."
+ - "Needed if O(cluster_name) is not set."
+ - "O(cluster_name) and O(datacenter) are mutually exclusive parameters."
required: false
type: str
short_description: "Gathers info about DRS VM/Host groups on the given cluster"
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_drs_group_manager.py b/ansible_collections/community/vmware/plugins/modules/vmware_drs_group_manager.py
index 2fc842718..36d41819a 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_drs_group_manager.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_drs_group_manager.py
@@ -44,14 +44,16 @@ options:
hosts:
description:
- A List of hosts to add / remove in the group.
- - Required only if I(vms) is not set.
+ - Required if O(vms) is not set.
+ - O(hosts) and O(vms) are mutually exclusive parameters.
required: false
type: list
elements: str
vms:
description:
- A List of vms to add / remove in the group.
- - Required only if I(hosts) is not set.
+ - Required if O(hosts) is not set.
+ - O(hosts) and O(vms) are mutually exclusive parameters.
required: false
type: list
elements: str
@@ -59,8 +61,8 @@ options:
choices: [ present, absent ]
default: present
description:
- - If set to C(present), VMs/hosts will be added to the given DRS group.
- - If set to C(absent), VMs/hosts will be removed from the given DRS group.
+ - If set to V(present), VMs/hosts will be added to the given DRS group.
+ - If set to V(absent), VMs/hosts will be removed from the given DRS group.
type: str
'''
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_drs_rule_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_drs_rule_info.py
index b401c2b26..df7d9a5a9 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_drs_rule_info.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_drs_rule_info.py
@@ -23,13 +23,13 @@ options:
description:
- Name of the cluster.
- DRS information for the given cluster will be returned.
- - This is required parameter if C(datacenter) parameter is not provided.
+ - This is required parameter if O(datacenter) parameter is not provided.
type: str
datacenter:
description:
- Name of the datacenter.
- DRS information for all the clusters from the given datacenter will be returned.
- - This is required parameter if C(cluster_name) parameter is not provided.
+ - This is required parameter if O(cluster_name) parameter is not provided.
type: str
extends_documentation_fragment:
- community.vmware.vmware.documentation
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_dvs_host.py b/ansible_collections/community/vmware/plugins/modules/vmware_dvs_host.py
index 790151c96..5d4fe27ea 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_dvs_host.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_dvs_host.py
@@ -36,17 +36,21 @@ options:
vmnics:
description:
- The ESXi hosts vmnics to use with the Distributed vSwitch.
+ - If unset, the current non-LAG uplinks will be kept.
+ - To remove all non-LAG uplinks, use the empty list V([]).
required: false
type: list
- default: []
elements: str
lag_uplinks:
required: false
type: list
- default: []
elements: dict
description:
- The ESXi hosts vmnics to use with specific LAGs.
+ - If unset, the current LAG uplinks will be kept.
+ - If set, LAG uplinks will be set to I(exactly) this list. So you always have to define the complete LAG uplink configuration;
+ if you don't, you might loose LAG uplinks.
+ - To remove all LAG uplinks, use the empty list V([]).
suboptions:
lag:
description:
@@ -156,7 +160,6 @@ from ansible.module_utils._text import to_native
class VMwareDvsHost(PyVmomi):
def __init__(self, module):
super(VMwareDvsHost, self).__init__(module)
- self.uplink_portgroup = None
self.host = None
self.dv_switch = None
self.desired_state = {}
@@ -174,13 +177,16 @@ class VMwareDvsHost(PyVmomi):
self.module.fail_json(msg="A distributed virtual switch %s "
"does not exist" % self.switch_name)
+ self.uplink_portgroup = self.find_dvs_uplink_pg()
+
self.lags = {}
for lag in self.dv_switch.config.lacpGroupConfig:
self.lags[lag.name] = lag
- for lag_uplink in self.lag_uplinks:
- if lag_uplink['lag'] not in self.lags:
- self.module.fail_json(msg="LAG %s not found" % lag_uplink['lag'])
+ if self.lag_uplinks is not None:
+ for lag_uplink in self.lag_uplinks:
+ if lag_uplink['lag'] not in self.lags:
+ self.module.fail_json(msg="LAG %s not found" % lag_uplink['lag'])
def process_state(self):
dvs_host_states = {
@@ -284,6 +290,10 @@ class VMwareDvsHost(PyVmomi):
lag_uplinks = []
switch_uplink_ports = {'non_lag': []}
+ for dvs_host_member in self.dv_switch.config.host:
+ if dvs_host_member.config.host.name == self.esxi_hostname:
+ break
+
portCriteria = vim.dvs.PortCriteria()
portCriteria.host = [self.host]
portCriteria.portgroupKey = self.uplink_portgroup.key
@@ -302,16 +312,30 @@ class VMwareDvsHost(PyVmomi):
if port.key in self.uplink_portgroup.portKeys and port.key not in lag_uplinks:
switch_uplink_ports['non_lag'].append(port.key)
- count = 0
- for vmnic in self.vmnics:
- self.desired_state[vmnic] = switch_uplink_ports['non_lag'][count]
- count += 1
-
- for lag in self.lag_uplinks:
+ # If defined, use vmnics as non-LAG uplinks
+ if self.vmnics is not None:
count = 0
- for vmnic in lag['vmnics']:
- self.desired_state[vmnic] = switch_uplink_ports[lag['lag']][count]
+ for vmnic in self.vmnics:
+ self.desired_state[vmnic] = switch_uplink_ports['non_lag'][count]
count += 1
+ # Otherwise keep current non-LAG uplinks
+ else:
+ for pnicSpec in dvs_host_member.config.backing.pnicSpec:
+ if pnicSpec.uplinkPortKey not in lag_uplinks:
+ self.desired_state[pnicSpec.pnicDevice] = pnicSpec.uplinkPortKey
+
+ # If defined, use lag_uplinks as LAG uplinks
+ if self.lag_uplinks is not None:
+ for lag in self.lag_uplinks:
+ count = 0
+ for vmnic in lag['vmnics']:
+ self.desired_state[vmnic] = switch_uplink_ports[lag['lag']][count]
+ count += 1
+ # Otherwise keep current LAG uplinks
+ else:
+ for pnicSpec in dvs_host_member.config.backing.pnicSpec:
+ if pnicSpec.uplinkPortKey in lag_uplinks:
+ self.desired_state[pnicSpec.pnicDevice] = pnicSpec.uplinkPortKey
def check_uplinks(self):
pnic_device = []
@@ -336,8 +360,6 @@ class VMwareDvsHost(PyVmomi):
return True
def check_dvs_host_state(self):
- self.uplink_portgroup = self.find_dvs_uplink_pg()
-
if self.uplink_portgroup is None:
self.module.fail_json(msg="An uplink portgroup does not exist on"
" the distributed virtual switch %s" % self.switch_name)
@@ -368,7 +390,7 @@ def main():
dict(
esxi_hostname=dict(required=True, type='str'),
switch_name=dict(required=True, type='str'),
- vmnics=dict(required=False, type='list', default=[], elements='str'),
+ vmnics=dict(required=False, type='list', elements='str'),
state=dict(default='present', choices=['present', 'absent'], type='str'),
vendor_specific_config=dict(
type='list',
@@ -381,7 +403,6 @@ def main():
),
lag_uplinks=dict(
type='list',
- default=[],
required=False,
elements='dict',
options=dict(
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_dvs_portgroup.py b/ansible_collections/community/vmware/plugins/modules/vmware_dvs_portgroup.py
index 83cd59f25..a7b09d0c7 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_dvs_portgroup.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_dvs_portgroup.py
@@ -33,9 +33,9 @@ options:
vlan_id:
description:
- The VLAN ID that should be configured with the portgroup, use 0 for no VLAN.
- - 'If C(vlan_trunk) is configured to be I(true), this can be a combination of multiple ranges and numbers, example: 1-200, 205, 400-4094.'
- - The valid C(vlan_id) range is from 0 to 4094. Overlapping ranges are allowed.
- - 'If C(vlan_private) is configured to be I(true), the corresponding private VLAN should already be configured in the distributed vSwitch.'
+ - 'If O(vlan_trunk=true), this can be a combination of multiple ranges and numbers, example: 1-200, 205, 400-4094.'
+ - The valid range is from 0 to 4094. Overlapping ranges are allowed.
+ - 'If O(vlan_private=true), the corresponding private VLAN should already be configured in the distributed vSwitch.'
required: true
type: str
num_ports:
@@ -54,9 +54,9 @@ options:
port_allocation:
description:
- Elastic port groups automatically increase or decrease the number of ports as needed.
- - Only valid if I(port_binding) is set to C(static).
- - Will be C(elastic) if not specified and I(port_binding) is set to C(static).
- - Will be C(fixed) if not specified and I(port_binding) is set to C(ephemeral).
+ - Only valid if O(port_binding=static).
+ - Will be V(elastic) if not specified and O(port_binding=static).
+ - Will be V(fixed) if not specified and O(port_binding=ephemeral).
type: str
choices:
- 'elastic'
@@ -72,14 +72,14 @@ options:
vlan_trunk:
description:
- Indicates whether this is a VLAN trunk or not.
- - Mutually exclusive with C(vlan_private) parameter.
+ - Mutually exclusive with O(vlan_private) parameter.
required: false
default: false
type: bool
vlan_private:
description:
- Indicates whether this is for a private VLAN or not.
- - Mutually exclusive with C(vlan_trunk) parameter.
+ - Mutually exclusive with O(vlan_trunk) parameter.
required: false
default: false
type: bool
@@ -117,13 +117,13 @@ options:
required: true
promiscuous:
type: bool
- description: Indicates whether promiscuous mode is allowed. Ignored if C(inherited) is true.
+ description: Indicates whether promiscuous mode is allowed. Ignored if O(network_policy.inherited=true).
forged_transmits:
type: bool
- description: Indicates whether forged transmits are allowed. Ignored if C(inherited) is true.
+ description: Indicates whether forged transmits are allowed. Ignored if O(network_policy.inherited=true).
mac_changes:
type: bool
- description: Indicates whether mac changes are allowed. Ignored if C(inherited) is true.
+ description: Indicates whether mac changes are allowed. Ignored if O(network_policy.inherited=true).
required: false
type: dict
teaming_policy:
@@ -133,7 +133,6 @@ options:
load_balance_policy:
description:
- Network adapter teaming policy.
- - C(loadbalance_loadbased) is available from version 2.6 and onwards.
default: 'loadbalance_srcid'
type: str
choices:
@@ -260,7 +259,6 @@ options:
- 'off'
- 'no'
- 'inherited'
- version_added: '2.3.0'
in_traffic_shaping:
description:
- Dictionary which configures the ingress traffic shaping settings for the portgroup.
@@ -273,25 +271,24 @@ options:
type: bool
description:
- Indicates whether ingress traffic shaping is activated or not.
- - Ignored if C(inherited) is true.
+ - Ignored if O(in_traffic_shaping.inherited=true).
average_bandwidth:
type: int
description:
- Establishes the number of bits per second to allow across a port, averaged over time, that is, the allowed average load.
- - Ignored if C(inherited) is true.
+ - Ignored if O(in_traffic_shaping.inherited=true).
burst_size:
type: int
description:
- The maximum number of bits per second to allow across a port when it is sending/sending or receiving a burst of traffic.
- - Ignored if C(inherited) is true.
+ - Ignored if O(in_traffic_shaping.inherited=true).
peak_bandwidth:
type: int
description:
- The maximum number of bytes to allow in a burst.
- - Ignored if C(inherited) is true.
+ - Ignored if O(in_traffic_shaping.inherited=true).
required: false
type: dict
- version_added: '2.3.0'
out_traffic_shaping:
description:
- Dictionary which configures the egress traffic shaping settings for the portgroup.
@@ -305,25 +302,24 @@ options:
type: bool
description:
- Indicates whether egress traffic shaping is activated or not.
- - Ignored if C(inherited) is true.
+ - Ignored if O(out_traffic_shaping.inherited=true).
average_bandwidth:
type: int
description:
- Establishes the number of bits per second to allow across a port, averaged over time, that is, the allowed average load.
- - Ignored if C(inherited) is true.
+ - Ignored if O(out_traffic_shaping.inherited=true).
burst_size:
type: int
description:
- The maximum number of bits per second to allow across a port when it is sending/sending or receiving a burst of traffic.
- - Ignored if C(inherited) is true.
+ - Ignored if O(out_traffic_shaping.inherited=true).
peak_bandwidth:
type: int
description:
- The maximum number of bytes to allow in a burst.
- - Ignored if C(inherited) is true.
+ - Ignored if O(out_traffic_shaping.inherited=true).
required: false
type: dict
- version_added: '2.3.0'
extends_documentation_fragment:
- community.vmware.vmware.documentation
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_dvs_portgroup_find.py b/ansible_collections/community/vmware/plugins/modules/vmware_dvs_portgroup_find.py
index f47edb0de..1af2eb0d0 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_dvs_portgroup_find.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_dvs_portgroup_find.py
@@ -36,7 +36,7 @@ options:
show_uplink:
description:
- Show or hide uplink portgroups.
- - Only relevant when C(vlanid) is supplied.
+ - Only relevant when O(vlanid) is supplied.
type: bool
default: false
extends_documentation_fragment:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_dvs_portgroup_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_dvs_portgroup_info.py
index d80d4ec17..1a07e142d 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_dvs_portgroup_info.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_dvs_portgroup_info.py
@@ -90,14 +90,28 @@ dvs_portgroup_info:
sample: {
"dvs_0":[
{
+ "active_uplinks": [
+ "uplink 1"
+ ],
"description": null,
"dvswitch_name": "dvs_001",
+ "key": "dvportgroup-1014",
+ "mac_learning": {
+ "allow_unicast_flooding": null,
+ "enabled": false,
+ "limit": null,
+ "limit_policy": null
+ },
+ "moid": "dvportgroup-1014",
"network_policy": {
"forged_transmits": false,
"mac_changes": false,
"promiscuous": false
},
"num_ports": 8,
+ "port_allocation": "elastic",
+ "port_binding": "static",
+ "standby_uplinks": [],
"port_policy": {
"block_override": true,
"ipfix_override": false,
@@ -264,6 +278,7 @@ class DVSPortgroupInfoManager(PyVmomi):
dvpg_details = dict(
portgroup_name=unquote(dvs_pg.name),
+ moid=dvs_pg._moId,
num_ports=dvs_pg.config.numPorts,
dvswitch_name=dvs_pg.config.distributedVirtualSwitch.name,
description=dvs_pg.config.description,
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_dvswitch.py b/ansible_collections/community/vmware/plugins/modules/vmware_dvswitch.py
index 1d184b2dc..604385568 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_dvswitch.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_dvswitch.py
@@ -26,8 +26,8 @@ options:
datacenter_name:
description:
- The name of the datacenter that will contain the Distributed Switch.
- - This parameter is optional, if C(folder) is provided.
- - Mutually exclusive with C(folder) parameter.
+ - Required if O(folder) is not provided.
+ - Mutually exclusive with O(folder) parameter.
required: false
aliases: ['datacenter']
type: str
@@ -42,22 +42,21 @@ options:
- The version of the Distributed Switch to create.
- The version must match the version of the ESXi hosts you want to connect.
- The version of the vCenter server is used if not specified.
- - Required only if C(state) is set to C(present).
+ - Required if O(state=present).
aliases: ['version']
type: str
mtu:
description:
- The switch maximum transmission unit.
- - Required parameter for C(state) both C(present) and C(absent), before Ansible 2.6 version.
- - Required only if C(state) is set to C(present), for Ansible 2.6 and onwards.
+ - Required if O(state=present).
- Accepts value between 1280 to 9000 (both inclusive).
type: int
default: 1500
multicast_filtering_mode:
description:
- The multicast filtering mode.
- - 'C(basic) mode: multicast traffic for virtual machines is forwarded according to the destination MAC address of the multicast group.'
- - 'C(snooping) mode: the Distributed Switch provides IGMP and MLD snooping according to RFC 4541.'
+ - 'V(basic) mode: multicast traffic for virtual machines is forwarded according to the destination MAC address of the multicast group.'
+ - 'V(snooping) mode: the Distributed Switch provides IGMP and MLD snooping according to RFC 4541.'
type: str
choices: ['basic', 'snooping']
default: 'basic'
@@ -65,8 +64,7 @@ options:
description:
- Quantity of uplink per ESXi host added to the Distributed Switch.
- The uplink quantity can be increased or decreased, but a decrease will only be successfull if the uplink isn't used by a portgroup.
- - Required parameter for C(state) both C(present) and C(absent), before Ansible 2.6 version.
- - Required only if C(state) is set to C(present), for Ansible 2.6 and onwards.
+ - Required if O(state=present).
type: int
uplink_prefix:
description:
@@ -78,11 +76,10 @@ options:
discovery_proto:
description:
- Link discovery protocol between Cisco and Link Layer discovery.
- - Required parameter for C(state) both C(present) and C(absent), before Ansible 2.6 version.
- - Required only if C(state) is set to C(present), for Ansible 2.6 and onwards.
- - 'C(cdp): Use Cisco Discovery Protocol (CDP).'
- - 'C(lldp): Use Link Layer Discovery Protocol (LLDP).'
- - 'C(disabled): Do not use a discovery protocol.'
+ - Required if O(state=present).
+ - 'V(cdp): Use Cisco Discovery Protocol (CDP).'
+ - 'V(lldp): Use Link Layer Discovery Protocol (LLDP).'
+ - 'V(disabled): Do not use a discovery protocol.'
choices: ['cdp', 'lldp', 'disabled']
default: 'cdp'
aliases: [ 'discovery_protocol' ]
@@ -90,8 +87,7 @@ options:
discovery_operation:
description:
- Select the discovery operation.
- - Required parameter for C(state) both C(present) and C(absent), before Ansible 2.6 version.
- - Required only if C(state) is set to C(present), for Ansible 2.6 and onwards.
+ - Required if O(state=present).
choices: ['both', 'advertise', 'listen']
default: 'listen'
type: str
@@ -162,8 +158,8 @@ options:
type: dict
state:
description:
- - If set to C(present) and the Distributed Switch does not exist, the Distributed Switch will be created.
- - If set to C(absent) and the Distributed Switch exists, the Distributed Switch will be deleted.
+ - If set to V(present) and the Distributed Switch does not exist, the Distributed Switch will be created.
+ - If set to V(absent) and the Distributed Switch exists, the Distributed Switch will be deleted.
default: 'present'
choices: ['present', 'absent']
type: str
@@ -172,7 +168,8 @@ options:
- Destination folder, absolute path to place dvswitch in.
- The folder should include the datacenter.
- This parameter is case sensitive.
- - This parameter is optional, if C(datacenter) is provided.
+ - Required if O(datacenter) is not provided.
+ - Mutually exclusive with O(datacenter) parameter.
- 'Examples:'
- ' folder: /datacenter1/network'
- ' folder: datacenter1/network'
@@ -184,7 +181,6 @@ options:
required: false
type: str
net_flow:
- version_added: '2.7.0'
description:
- Dictionary which configures the Net Flow for the Distributed Switch.
suboptions:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_dvswitch_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_dvswitch_info.py
index 5cba227c8..b4fa9c7c3 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_dvswitch_info.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_dvswitch_info.py
@@ -34,7 +34,7 @@ options:
switch_name:
description:
- Name of a dvswitch to look for.
- - If C(switch_name) not specified gather all dvswitch information.
+ - If O(switch_name) not specified gather all dvswitch information.
aliases: ['switch', 'dvswitch']
required: false
type: str
@@ -59,7 +59,7 @@ options:
- ' "config.maxMtu",'
- ' "overallStatus"'
- ' ]'
- - Only valid when C(schema) is C(vsphere).
+ - Only valid when O(schema=vsphere).
type: list
elements: str
required: false
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_dvswitch_lacp.py b/ansible_collections/community/vmware/plugins/modules/vmware_dvswitch_lacp.py
index 7e86b96a6..8ac7b491d 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_dvswitch_lacp.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_dvswitch_lacp.py
@@ -29,14 +29,14 @@ options:
support_mode:
description:
- The LACP support mode.
- - 'C(basic): One Link Aggregation Control Protocol group in the switch (singleLag).'
- - 'C(enhanced): Multiple Link Aggregation Control Protocol groups in the switch (multipleLag).'
+ - 'V(basic): One Link Aggregation Control Protocol group in the switch (singleLag).'
+ - 'V(enhanced): Multiple Link Aggregation Control Protocol groups in the switch (multipleLag).'
type: str
default: 'basic'
choices: ['basic', 'enhanced']
link_aggregation_groups:
description:
- - Can only be used if C(lacp_support) is set to C(enhanced).
+ - Can only be used if O(support_mode=enhanced).
suboptions:
name:
type: str
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_dvswitch_nioc.py b/ansible_collections/community/vmware/plugins/modules/vmware_dvswitch_nioc.py
index b0ee71abc..6f3d182f7 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_dvswitch_nioc.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_dvswitch_nioc.py
@@ -77,7 +77,7 @@ options:
shares:
description:
- The number of shares allocated.
- - Ignored unless C(shares_level) is "custom".
+ - Ignored unless O(resources.shares_level=custom).
type: int
required: false
type: list
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_dvswitch_pvlans.py b/ansible_collections/community/vmware/plugins/modules/vmware_dvswitch_pvlans.py
index ed84a2116..a767af52b 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_dvswitch_pvlans.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_dvswitch_pvlans.py
@@ -27,10 +27,10 @@ options:
primary_pvlans:
description:
- A list of VLAN IDs that should be configured as Primary PVLANs.
- - If C(primary_pvlans) isn't specified, all PVLANs will be deleted if present.
+ - If not specified, all PVLANs will be deleted if present.
- Each member of the list requires primary_pvlan_id (int) set.
- The secondary promiscuous PVLAN will be created automatically.
- - If C(secondary_pvlans) isn't specified, the primary PVLANs and each secondary promiscuous PVLAN will be created.
+ - If O(secondary_pvlans) isn't specified, the primary PVLANs and each secondary promiscuous PVLAN will be created.
- Please see examples for more information.
type: list
default: []
@@ -38,8 +38,8 @@ options:
secondary_pvlans:
description:
- A list of VLAN IDs that should be configured as Secondary PVLANs.
- - 'C(primary_pvlans) need to be specified to create any Secondary PVLAN.'
- - If C(primary_pvlans) isn't specified, all PVLANs will be deleted if present.
+ - 'O(primary_pvlans) need to be specified to create any Secondary PVLAN.'
+ - If O(primary_pvlans) isn't specified, all PVLANs will be deleted if present.
- Each member of the list requires primary_pvlan_id (int), secondary_pvlan_id (int), and pvlan_type (str) to be set.
- The type of the secondary PVLAN can be isolated or community. The secondary promiscuous PVLAN will be created automatically.
- Please see examples for more information.
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_dvswitch_uplink_pg.py b/ansible_collections/community/vmware/plugins/modules/vmware_dvswitch_uplink_pg.py
index e291237c4..8d9f308a3 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_dvswitch_uplink_pg.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_dvswitch_uplink_pg.py
@@ -12,7 +12,7 @@ __metaclass__ = type
DOCUMENTATION = r'''
---
module: vmware_dvswitch_uplink_pg
-short_description: Manage uplink portproup configuration of a Distributed Switch
+short_description: Manage uplink portgroup configuration of a Distributed Switch
description:
- This module can be used to configure the uplink portgroup of a Distributed Switch.
author:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_evc_mode.py b/ansible_collections/community/vmware/plugins/modules/vmware_evc_mode.py
index 11f9b73ba..054a27def 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_evc_mode.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_evc_mode.py
@@ -34,7 +34,7 @@ options:
- cluster
evc_mode:
description:
- - Required for C(state=present).
+ - Required for O(state=present).
- The EVC mode to enable or disable on the cluster. (intel-broadwell, intel-nehalem, intel-merom, etc.).
type: str
state:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_export_ovf.py b/ansible_collections/community/vmware/plugins/modules/vmware_export_ovf.py
index d447ea983..6ea440a4e 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_export_ovf.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_export_ovf.py
@@ -23,17 +23,17 @@ options:
name:
description:
- Name of the virtual machine to export.
- - This is a required parameter, if parameter C(uuid) or C(moid) is not supplied.
+ - This is a required parameter, if parameter O(uuid) or O(moid) is not supplied.
type: str
uuid:
description:
- Uuid of the virtual machine to export.
- - This is a required parameter, if parameter C(name) or C(moid) is not supplied.
+ - This is a required parameter, if parameter O(name) or O(moid) is not supplied.
type: str
moid:
description:
- Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.
- - This is required if C(name) or C(uuid) is not supplied.
+ - This is required if O(name) or O(uuid) is not supplied.
type: str
datacenter:
default: ha-datacenter
@@ -74,7 +74,6 @@ options:
default: false
description:
- All extra configuration options are exported for a virtual machine.
- version_added: '2.0.0'
download_timeout:
description:
- The user defined timeout in second of exporting file.
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_first_class_disk_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_first_class_disk_info.py
new file mode 100644
index 000000000..dc900bca1
--- /dev/null
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_first_class_disk_info.py
@@ -0,0 +1,143 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2024, Nina Loser <nina.loser@muenchen.de>
+# Copyright: (c) 2021, Ansible Project
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+DOCUMENTATION = r'''
+---
+module: vmware_first_class_disk_info
+short_description: Gather info about VMware vSphere First Class Disks
+description:
+ - This module can be used to gather information about VMware vSphere First Class Disks.
+author:
+- Nina Loser (@nina2244)
+options:
+ datacenter_name:
+ description: The name of the datacenter.
+ type: str
+ datastore_name:
+ description: Name of datastore or datastore cluster of the disk.
+ required: true
+ type: str
+ disk_name:
+ description: The name of the disk. If not set return all found.
+ type: str
+extends_documentation_fragment: vmware.documentation
+'''
+
+EXAMPLES = r'''
+- name: Gather info of 1GBDisk
+ community.vmware.vmware_first_class_disk_info:
+ hostname: '{{ vcenter_hostname }}'
+ username: '{{ vcenter_username }}'
+ password: '{{ vcenter_password }}'
+ datastore_name: '{{ datastore_name }}'
+ disk_name: '1GBDisk'
+ register: disk_info
+ delegate_to: localhost
+
+- debug:
+ var: disk_info.first_class_disks
+
+- name: Gather info of all first class disks
+ community.vmware.vmware_first_class_disk_info:
+ hostname: '{{ vcenter_hostname }}'
+ username: '{{ vcenter_username }}'
+ password: '{{ vcenter_password }}'
+ datastore_name: '{{ datastore_name }}'
+ register: disk_info
+ delegate_to: localhost
+
+- debug:
+ var: disk_info.first_class_disks
+'''
+
+RETURN = r'''
+first_class_disks:
+ description: list of dictionary of First-class disk and their information
+ returned: success
+ type: list
+ sample: [
+ {
+ "name": "1GBDisk",
+ "datastore_name": "DS0",
+ "size_mb": "1024",
+ "consumption_type": "disk",
+ "descriptor_version": 0,
+ "consumer_ids": []
+ }
+ ]
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.community.vmware.plugins.module_utils.vmware import PyVmomi, vmware_argument_spec
+
+
+class FirstClassDiskInfo(PyVmomi):
+ def __init__(self, module):
+ super(FirstClassDiskInfo, self).__init__(module)
+ self.datacenter_name = self.params['datacenter_name']
+ self.datastore_name = self.params['datastore_name']
+ self.disk_name = self.params['disk_name']
+
+ def gather_first_class_disk_info(self):
+ self.datastore_obj = self.find_datastore_by_name(datastore_name=self.datastore_name, datacenter_name=self.datacenter_name)
+ if not self.datastore_obj:
+ self.module.fail_json(msg='Failed to find datastore %s.' % self.datastore_name)
+
+ if self.disk_name:
+ self.disk_obj = self.find_first_class_disk_by_name(self.disk_name, self.datastore_obj)
+ if not self.disk_obj:
+ self.module.fail_json(msg='Failed to find disk %s.' % self.disk_name)
+
+ self.disks = [self.disk_obj]
+
+ else:
+ self.disks = self.find_first_class_disks(self.datastore_obj)
+ if not self.disks:
+ return []
+
+ disk_infos = list()
+ for disk in self.disks:
+ disk_info = dict(
+ name=disk.config.name,
+ id=disk.config.id.id,
+ datastore_name=disk.config.backing.datastore.name,
+ size_mb=disk.config.capacityInMB,
+ consumption_type=disk.config.consumptionType,
+ descriptor_version=disk.config.descriptorVersion,
+ consumer_ids=list(id.id for id in disk.config.consumerId)
+ )
+ disk_infos.append(disk_info)
+
+ return disk_infos
+
+
+def main():
+ argument_spec = vmware_argument_spec()
+ argument_spec.update(
+ dict(
+ datacenter_name=dict(type='str'),
+ datastore_name=dict(required=True, type='str'),
+ disk_name=dict(type='str')
+ )
+ )
+
+ module = AnsibleModule(argument_spec=argument_spec,
+ supports_check_mode=True)
+
+ first_class_disk = FirstClassDiskInfo(module)
+
+ _first_class_disks = first_class_disk.gather_first_class_disk_info()
+
+ module.exit_json(changed=False, first_class_disks=_first_class_disks)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_folder_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_folder_info.py
index fd99d782b..569832fd0 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_folder_info.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_folder_info.py
@@ -17,8 +17,6 @@ description:
- The module can be used to gather a hierarchical view of the folders that exist within a datacenter
author:
- David Hewitt (@davidmhewitt)
-notes:
-- C(flat_folder_info) added in VMware collection 1.4.0.
options:
datacenter:
description:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_guest.py b/ansible_collections/community/vmware/plugins/modules/vmware_guest.py
index 16dcb301c..1f5a0a818 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_guest.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_guest.py
@@ -35,36 +35,35 @@ notes:
- Use SCSI disks instead of IDE when you want to expand online disks by specifying a SCSI controller.
- Uses SysPrep for Windows VM (depends on 'guest_id' parameter match 'win') with PyVmomi.
- In order to change the VM's parameters (e.g. number of CPUs), the VM must be powered off unless the hot-add
- support is enabled and the C(state=present) must be used to apply the changes.
+ support is enabled and the O(state=present) must be used to apply the changes.
- "For additional information please visit Ansible VMware community wiki - U(https://github.com/ansible/community/wiki/VMware)."
options:
state:
description:
- Specify the state the virtual machine should be in.
- - If C(state) is set to C(present) and virtual machine exists, ensure the virtual machine configurations conforms to task arguments.
- - If C(state) is set to C(absent) and virtual machine exists, then the specified virtual machine is removed with it's associated components.
- - If C(state) is set to one of the following C(poweredon), C(powered-on), C(poweredoff), C(powered-off),
- C(present), C(restarted), C(suspended) and virtual machine does not exists, virtual machine is deployed with the given parameters.
- - If C(state) is set to C(poweredon) or C(powered-on) and virtual machine exists with powerstate other than powered on,
+ - If V(present) and virtual machine exists, ensure the virtual machine configurations conforms to task arguments.
+ - If V(absent) and virtual machine exists, then the specified virtual machine is removed with it's associated components.
+ - If set to one of V(poweredon), V(powered-on), V(poweredoff), V(powered-off),
+ V(present), V(restarted), V(suspended) and virtual machine does not exists, virtual machine is deployed with the given parameters.
+ - If set to V(poweredon) or V(powered-on) and virtual machine exists with powerstate other than powered on,
then the specified virtual machine is powered on.
- - If C(state) is set to C(poweredoff) or C(powered-off) and virtual machine exists with powerstate other than powered off,
+ - If set to V(poweredoff) or V(powered-off) and virtual machine exists with powerstate other than powered off,
then the specified virtual machine is powered off.
- - If C(state) is set to C(restarted) and virtual machine exists, then the virtual machine is restarted.
- - If C(state) is set to C(suspended) and virtual machine exists, then the virtual machine is set to suspended mode.
- - If C(state) is set to C(shutdownguest) or C(shutdown-guest) and virtual machine exists, then the virtual machine is shutdown.
- - If C(state) is set to C(rebootguest) or C(reboot-guest) and virtual machine exists, then the virtual machine is rebooted.
- - Powerstate C(powered-on) and C(powered-off) is added in version 2.10.
+ - If set to V(restarted) and virtual machine exists, then the virtual machine is restarted.
+ - If set to V(suspended) and virtual machine exists, then the virtual machine is set to suspended mode.
+ - If set to V(shutdownguest) or V(shutdown-guest) and virtual machine exists, then the virtual machine is shutdown.
+ - If set to V(rebootguest) or V(reboot-guest) and virtual machine exists, then the virtual machine is rebooted.
default: present
type: str
choices: [ absent, poweredon, powered-on, poweredoff, powered-off, present, rebootguest, reboot-guest, restarted, suspended, shutdownguest, shutdown-guest]
name:
description:
- Name of the virtual machine to work with.
- - Virtual machine names in vCenter are not necessarily unique, which may be problematic, see C(name_match).
- - If multiple virtual machines with same name exists, then C(folder) is required parameter to
+ - Virtual machine names in vCenter are not necessarily unique, which may be problematic, see O(name_match).
+ - If multiple virtual machines with same name exists, then O(folder) is required parameter to
identify uniqueness of the virtual machine.
- - This parameter is required, if C(state) is set to C(poweredon), C(powered-on), C(poweredoff), C(powered-off),
- C(present), C(restarted), C(suspended) and virtual machine does not exists.
+ - This parameter is required, if O(state=poweredon), O(state=powered-on), O(state=poweredoff), O(state=powered-off),
+ O(state=present), O(state=restarted), O(state=suspended) and virtual machine does not exists.
- This parameter is case sensitive.
type: str
name_match:
@@ -76,7 +75,7 @@ options:
uuid:
description:
- UUID of the virtual machine to manage if known, this is VMware's unique identifier.
- - This is required if C(name) is not supplied.
+ - This is required if O(name) is not supplied.
- If virtual machine does not exists, then this parameter is ignored.
- Please note that a supplied UUID will be ignored on virtual machine creation, as VMware creates the UUID internally.
type: str
@@ -110,7 +109,7 @@ options:
- "The folder should include the datacenter. ESXi's datacenter is ha-datacenter."
- This parameter is case sensitive.
- 'If multiple machines are found with same name, this parameter is used to identify'
- - 'uniqueness of the virtual machine. Added in Ansible 2.5.'
+ - 'uniqueness of the virtual machine.'
- 'Examples:'
- ' folder: /ha-datacenter/vm'
- ' folder: ha-datacenter/vm'
@@ -145,8 +144,8 @@ options:
type: int
description:
- Number of CPUs.
- - C(num_cpus) must be a multiple of C(num_cpu_cores_per_socket).
- - For example, to create a VM with 2 sockets of 4 cores, specify C(num_cpus) as 8 and C(num_cpu_cores_per_socket) as 4.
+ - Must be a multiple of O(hardware.num_cpu_cores_per_socket).
+ - For example, to create a VM with 2 sockets of 4 cores, specify O(hardware.num_cpus) as 8 and O(hardware.num_cpu_cores_per_socket) as 4.
num_cpu_cores_per_socket:
type: int
description: Number of Cores Per Socket.
@@ -155,7 +154,6 @@ options:
choices: [ 'low', 'normal', 'high', 'custom' ]
description:
- The allocation level of CPU resources for the virtual machine.
- - Valid Values are C(low), C(normal), C(high) and C(custom).
version_added: '3.2.0'
cpu_shares:
type: int
@@ -170,8 +168,8 @@ options:
scsi:
type: str
description:
- - Valid values are C(buslogic), C(lsilogic), C(lsilogicsas) and C(paravirtual).
- - C(paravirtual) is default.
+ - Valid values are V(buslogic), V(lsilogic), V(lsilogicsas) and V(paravirtual).
+ - V(paravirtual) is default.
choices: [ 'buslogic', 'lsilogic', 'lsilogicsas', 'paravirtual' ]
secure_boot:
type: bool
@@ -179,7 +177,7 @@ options:
memory_reservation_lock:
type: bool
description:
- - If set C(true), memory resource reservation for the virtual machine.
+ - If set V(true), memory resource reservation for the virtual machine.
max_connections:
type: int
description:
@@ -197,7 +195,6 @@ options:
type: str
description:
- The allocation level of memory resources for the virtual machine.
- - Valid Values are C(low), C(normal), C(high) and C(custom).
choices: [ 'low', 'normal', 'high', 'custom' ]
version_added: '3.2.0'
mem_shares:
@@ -219,8 +216,7 @@ options:
description:
- The Virtual machine hardware versions.
- Default is 10 (ESXi 5.5 and onwards).
- - If set to C(latest), the specified virtual machine will be upgraded to the most current hardware version supported on the host.
- - C(latest) is added in Ansible 2.10.
+ - If set to V(latest), the specified virtual machine will be upgraded to the most current hardware version supported on the host.
- Please check VMware documentation for correct virtual machine hardware version.
- Incorrect hardware version may lead to failure in deployment. If hardware version is already equal to the given.
boot_firmware:
@@ -242,14 +238,27 @@ options:
iommu:
type: bool
description: Flag to specify if I/O MMU is enabled for this virtual machine.
+ encryption:
+ type: dict
+ default: {}
+ description:
+ - Manage virtual machine encryption settings
+ - All parameters case sensitive.
+ version_added: '3.9.0'
+ suboptions:
+ encrypted_vmotion:
+ type: str
+ description: Controls encryption for live migrations with vmotion
+ choices: ['disabled', 'opportunistic', 'required']
+ encrypted_ft:
+ type: str
+ description: Controls encryption for fault tolerance replication
+ choices: ['disabled', 'opportunistic', 'required']
guest_id:
type: str
description:
- Set the guest ID.
- This parameter is case sensitive.
- - C(rhel7_64Guest) for virtual machine with RHEL7 64 bit.
- - C(centos64Guest) for virtual machine with CentOS 64 bit.
- - C(ubuntu64Guest) for virtual machine with Ubuntu 64 bit.
- This field is required when creating a virtual machine, not required when creating from the template.
- >
Valid values are referenced here:
@@ -260,8 +269,8 @@ options:
- This parameter is case sensitive.
- Shrinking disks is not supported.
- Removing existing disks of the virtual machine is not supported.
- - 'Attributes C(controller_type), C(controller_number), C(unit_number) are used to configure multiple types of disk
- controllers and disks for creating or reconfiguring virtual machine. Added in Ansible 2.10.'
+ - 'Attributes O(disk.controller_type), O(disk.controller_number), O(disk.unit_number) are used to configure multiple types of disk
+ controllers and disks for creating or reconfiguring virtual machine.'
type: list
default: []
elements: dict
@@ -286,8 +295,6 @@ options:
type:
description:
- Type of disk.
- - If C(thin) specified, disk type is set to thin disk.
- - If C(eagerzeroedthick) specified, disk type is set to eagerzeroedthick disk. Added Ansible 2.5.
- If not specified, disk type is inherited from the source VM or template when cloned and thick disk, no eagerzero otherwise.
type: str
choices: [ 'thin', 'thick', 'eagerzeroedthick' ]
@@ -295,37 +302,35 @@ options:
type: str
description:
- The name of datastore which will be used for the disk.
- - If C(autoselect_datastore) is set to True, will select the less used datastore whose name contains this "disk.datastore" string.
+ - If O(disk.autoselect_datastore) is set to True, will select the less used datastore whose name contains this "disk.datastore" string.
filename:
type: str
description:
- Existing disk image to be used.
- Filename must already exist on the datastore.
- - Specify filename string in C([datastore_name] path/to/file.vmdk) format. Added in Ansible 2.8.
+ - Specify filename string in C([datastore_name] path/to/file.vmdk) format.
autoselect_datastore:
type: bool
description:
- Select the less used datastore.
- - C(disk.datastore) and C(disk.autoselect_datastore) will not be used if C(datastore) is specified outside this C(disk) configuration.
+ - O(disk.datastore) and O(disk.autoselect_datastore) will not be used if O(datastore) is specified outside this O(disk) configuration.
disk_mode:
type: str
choices: ['persistent', 'independent_persistent', 'independent_nonpersistent']
description:
- Type of disk mode.
- - Added in Ansible 2.6.
- - If C(persistent) specified, changes are immediately and permanently written to the virtual disk. This is default.
- - If C(independent_persistent) specified, same as persistent, but not affected by snapshots.
- - If C(independent_nonpersistent) specified, changes to virtual disk are made to a redo log and discarded at power off,
+ - If V(persistent) specified, changes are immediately and permanently written to the virtual disk. This is default.
+ - If V(independent_persistent) specified, same as persistent, but not affected by snapshots.
+ - If V(independent_nonpersistent) specified, changes to virtual disk are made to a redo log and discarded at power off,
but not affected by snapshots.
controller_type:
type: str
choices: ['buslogic', 'lsilogic', 'lsilogicsas', 'paravirtual', 'sata', 'nvme']
description:
- Type of disk controller.
- - C(nvme) controller type support starts on ESXi 6.5 with VM hardware version C(version) 13.
Set this type on not supported ESXi or VM hardware version will lead to failure in deployment.
- - When set to C(sata), please make sure C(unit_number) is correct and not used by SATA CDROMs.
- - If set to C(sata) type, please make sure C(controller_number) and C(unit_number) are set correctly when C(cdrom) also set to C(sata) type.
+ - When set to V(sata), please make sure O(disk.unit_number) is correct and not used by SATA CDROMs.
+ - If set to V(sata) type, please make sure O(disk.controller_number) and O(disk.unit_number) are set correctly when O(cdrom=sata).
controller_number:
type: int
choices: [0, 1, 2, 3]
@@ -339,9 +344,9 @@ options:
- Valid value range from 0 to 15 for SCSI controller, except 7.
- Valid value range from 0 to 14 for NVME controller.
- Valid value range from 0 to 29 for SATA controller.
- - C(controller_type), C(controller_number) and C(unit_number) are required when creating or reconfiguring VMs
+ - O(disk.controller_type), O(disk.controller_number) and O(disk.unit_number) are required when creating or reconfiguring VMs
with multiple types of disk controllers and disks.
- - When creating new VM, the first configured disk in the C(disk) list will be "Hard Disk 1".
+ - When creating new VM, the first configured disk in the O(disk) list will be "Hard Disk 1".
nvdimm:
description:
- Add or remove a virtual NVDIMM device to the virtual machine.
@@ -356,8 +361,7 @@ options:
state:
type: str
description:
- - Valid value is C(present) or C(absent).
- - If set to C(absent), then the NVDIMM device with specified C(label) will be removed.
+ - If set to V(absent), then the NVDIMM device with specified O(nvdimm.label) will be removed.
choices: ['present', 'absent']
size_mb:
type: int
@@ -367,53 +371,51 @@ options:
type: str
description:
- The label of the virtual NVDIMM device to be removed or configured, e.g., "NVDIMM 1".
- - 'This parameter is required when C(state) is set to C(absent), or C(present) to reconfigure NVDIMM device
- size. When add a new device, please do not set C(label).'
+ - 'This parameter is required when O(nvdimm.state=absent), or O(nvdimm.state=present) to reconfigure NVDIMM device
+ size. When add a new device, please do not set.'
cdrom:
description:
- - A list of CD-ROM configurations for the virtual machine. Added in version 2.9.
- - Providing CD-ROM configuration as dict is deprecated and will be removed VMware collection 4.0.0.
- Please use a list instead.
- - 'Parameters C(controller_type), C(controller_number), C(unit_number), C(state) are added for a list of CD-ROMs
- configuration support.'
- - For C(ide) controller, hot-add or hot-remove CD-ROM is not supported.
- type: raw
+ - A list of CD-ROM configurations for the virtual machine.
+ - For V(ide) controller, hot-add or hot-remove CD-ROM is not supported.
+ type: list
default: []
+ elements: dict
suboptions:
type:
type: str
description:
- - The type of CD-ROM, valid options are C(none), C(client) or C(iso).
- - With C(none) the CD-ROM will be disconnected but present.
- - The default value is C(client).
+ - The type of CD-ROM.
+ - With V(none) the CD-ROM will be disconnected but present.
+ choices: [ 'none', 'client', 'iso' ]
+ default: client
iso_path:
type: str
description:
- The datastore path to the ISO file to use, in the form of C([datastore1] path/to/file.iso).
- - Required if type is set C(iso).
+ - Required if type is set V(iso).
controller_type:
type: str
description:
- - Valid options are C(ide) and C(sata).
- - Default value is C(ide).
- - When set to C(sata), please make sure C(unit_number) is correct and not used by SATA disks.
+ - When set to V(sata), please make sure O(cdrom.unit_number) is correct and not used by SATA disks.
+ choices: [ 'ide', 'sata' ]
+ default: ide
controller_number:
type: int
description:
- - For C(ide) controller, valid value is 0 or 1.
- - For C(sata) controller, valid value is 0 to 3.
+ - For O(cdrom.controller_type=ide), valid value is 0 or 1.
+ - For O(cdrom.controller_type=sata), valid value is 0 to 3.
unit_number:
type: int
description:
- - For CD-ROM device attach to C(ide) controller, valid value is 0 or 1.
- - For CD-ROM device attach to C(sata) controller, valid value is 0 to 29.
- - C(controller_number) and C(unit_number) are mandatory attributes.
+ - For O(cdrom.controller_type=ide), valid value is 0 or 1.
+ - For O(cdrom.controller_type=sata), valid value is 0 to 29.
+ - O(cdrom.controller_number) and O(cdrom.unit_number) are mandatory attributes.
state:
type: str
description:
- - Valid value is C(present) or C(absent).
- - Default is C(present).
- - If set to C(absent), then the specified CD-ROM will be removed.
+ - If set to V(absent), then the specified CD-ROM will be removed.
+ choices: [ 'present', 'absent' ]
+ default: present
resource_pool:
description:
- Use the given resource pool for virtual machine operation.
@@ -444,12 +446,12 @@ options:
- Wait until vCenter detects all guest customizations as successfully completed.
- When enabled, the VM will automatically be powered on.
- "If vCenter does not detect guest customization start or succeed, failed events after time
- C(wait_for_customization_timeout) parameter specified, warning message will be printed and task result is fail."
+ O(wait_for_customization_timeout) parameter specified, warning message will be printed and task result is fail."
default: false
type: bool
state_change_timeout:
description:
- - If the C(state) is set to C(shutdownguest), by default the module will return immediately after sending the shutdown signal.
+ - If the O(state=shutdownguest), by default the module will return immediately after sending the shutdown signal.
- If this argument is set to a positive integer, the module will instead wait for the virtual machine to reach the poweredoff state.
- The value sets a timeout in seconds for the module to wait for the state change.
default: 0
@@ -458,12 +460,12 @@ options:
description:
- Name of the existing snapshot to use to create a clone of a virtual machine.
- This parameter is case sensitive.
- - While creating linked clone using C(linked_clone) parameter, this parameter is required.
+ - While creating linked clone using O(linked_clone) parameter, this parameter is required.
type: str
linked_clone:
description:
- Whether to create a linked clone from the snapshot specified.
- - If specified, then C(snapshot_src) is required parameter.
+ - If specified, then O(snapshot_src) is required parameter.
default: false
type: bool
force:
@@ -472,7 +474,7 @@ options:
- This parameter is useful while removing virtual machine which is powered on state.
- 'This module reflects the VMware vCenter API and UI workflow, as such, in some cases the `force` flag will
be mandatory to perform the action to ensure you are certain the action has to be taken, no matter what the consequence.
- This is specifically the case for removing a powered on the virtual machine when C(state) is set to C(absent).'
+ This is specifically the case for removing a powered on the virtual machine when O(state=absent).'
default: false
type: bool
delete_from_inventory:
@@ -489,21 +491,21 @@ options:
cluster:
description:
- The cluster name where the virtual machine will run.
- - This is a required parameter, if C(esxi_hostname) is not set.
- - C(esxi_hostname) and C(cluster) are mutually exclusive parameters.
+ - This is a required parameter, if O(esxi_hostname) is not set.
+ - O(esxi_hostname) and O(cluster) are mutually exclusive parameters.
- This parameter is case sensitive.
type: str
esxi_hostname:
description:
- The ESXi hostname where the virtual machine will run.
- - This is a required parameter, if C(cluster) is not set.
- - C(esxi_hostname) and C(cluster) are mutually exclusive parameters.
+ - This is a required parameter, if O(cluster) is not set.
+ - O(esxi_hostname) and O(cluster) are mutually exclusive parameters.
- This parameter is case sensitive.
type: str
advanced_settings:
description:
- Define a list of advanced settings to be added to the VMX config.
- - An advanced settings object takes two fields C(key) and C(value).
+ - An advanced settings object takes the two fields C(key) and C(value).
- Incorrect key and values will be ignored.
elements: dict
type: list
@@ -516,7 +518,7 @@ options:
customvalues:
description:
- Define a list of custom values to set on virtual machine.
- - A custom value object takes two fields C(key) and C(value).
+ - A custom value object takes the two fields C(key) and C(value).
- Incorrect key and values will be ignored.
elements: dict
type: list
@@ -538,7 +540,7 @@ options:
description:
- Name of the portgroup or distributed virtual portgroup for this interface.
- Required per entry.
- - When specifying distributed virtual portgroup make sure given C(esxi_hostname) or C(cluster) is associated with it.
+ - When specifying distributed virtual portgroup make sure given O(esxi_hostname) or O(cluster) is associated with it.
vlan:
type: int
description:
@@ -590,6 +592,36 @@ options:
- Static gateway.
- Optional per entry.
- Used for OS customization.
+ typev6:
+ version_added: '4.1.0'
+ type: str
+ description:
+ - Type of IP assignment.
+ - Valid values are one of C(dhcp), C(static).
+ - C(dhcp) is default.
+ - Optional per entry.
+ - Used for OS customization.
+ ipv6:
+ version_added: '4.1.0'
+ type: str
+ description:
+ - Static IP address. Implies C(type=static).
+ - Optional per entry.
+ - Used for OS customization.
+ netmaskv6:
+ version_added: '4.1.0'
+ type: str
+ description:
+ - Static netmask required for C(ip).
+ - Optional per entry.
+ - Used for OS customization.
+ gatewayv6:
+ version_added: '4.1.0'
+ type: str
+ description:
+ - Static gateway.
+ - Optional per entry.
+ - Used for OS customization.
dns_servers:
type: str
description:
@@ -622,7 +654,7 @@ options:
existing_vm:
type: bool
description:
- - If set to C(true), do OS customization on the specified virtual machine directly.
+ - If set to V(true), do OS customization on the specified virtual machine directly.
- Common for Linux and Windows customization.
dns_servers:
type: list
@@ -646,7 +678,7 @@ options:
type: str
description:
- Computer hostname.
- - Default is shortened C(name) parameter.
+ - Default is shortened O(name) parameter.
- Allowed characters are alphanumeric (uppercase and lowercase) and minus, rest of the characters are dropped as per RFC 952.
- Common for Linux and Windows customization.
timezone:
@@ -679,19 +711,19 @@ options:
description:
- Number of autologon after reboot.
- Specific to Windows customization.
- - Ignored if C(autologon) is unset or set to C(false).
+ - Ignored if O(customization.autologon) is unset or set to O(customization.autologon=false).
- If unset, 1 will be used.
domainadmin:
type: str
description:
- User used to join in AD domain.
- - Required if C(joindomain) specified.
+ - Required if O(customization.joindomain) specified.
- Specific to Windows customization.
domainadminpassword:
type: str
description:
- Password used to join in AD domain.
- - Required if C(joindomain) specified.
+ - Required if O(customization.joindomain) specified.
- Specific to Windows customization.
fullname:
type: str
@@ -703,13 +735,13 @@ options:
type: str
description:
- AD domain to join.
- - Not compatible with C(joinworkgroup).
+ - Not compatible with O(customization.joinworkgroup).
- Specific to Windows customization.
joinworkgroup:
type: str
description:
- Workgroup to join.
- - Not compatible with C(joindomain).
+ - Not compatible with O(customization.joindomain).
- Specific to Windows customization.
- If unset, "WORKGROUP" will be used as a fall-back.
orgname:
@@ -766,12 +798,12 @@ options:
description:
- Unique name identifying the requested customization specification.
- This parameter is case sensitive.
- - If set, then overrides C(customization) parameter values.
+ - If set, then overrides O(customization) parameter values.
type: str
datastore:
description:
- Specify datastore or datastore cluster to provision virtual machine.
- - This parameter takes precedence over C(disk.datastore) parameter.
+ - This parameter takes precedence over O(disk.datastore) parameter.
- This parameter can be used to override datastore or datastore cluster setting
of the virtual machine when deployed from the template.
- Please see example for more usage.
@@ -1425,36 +1457,21 @@ class PyVmomiHelper(PyVmomi):
expected_cdrom_spec = self.params.get('cdrom')
if expected_cdrom_spec:
for cdrom_spec in expected_cdrom_spec:
- # set CDROM controller type is 'ide' by default
- cdrom_spec['controller_type'] = cdrom_spec.get('controller_type', 'ide').lower()
- if cdrom_spec['controller_type'] not in ['ide', 'sata']:
- self.module.fail_json(msg="Invalid cdrom.controller_type: %s, valid value is 'ide' or 'sata'."
- % cdrom_spec['controller_type'])
-
- # set CDROM state is 'present' by default
- cdrom_spec['state'] = cdrom_spec.get('state', 'present').lower()
- if cdrom_spec['state'] not in ['present', 'absent']:
- self.module.fail_json(msg="Invalid cdrom.state: %s, valid value is 'present', 'absent'."
- % cdrom_spec['state'])
+ cdrom_spec['controller_type'] = cdrom_spec.get('controller_type')
+ cdrom_spec['state'] = cdrom_spec.get('state')
if cdrom_spec['state'] == 'present':
# set CDROM type is 'client' by default
- cdrom_spec['type'] = cdrom_spec.get('type', 'client').lower()
- if cdrom_spec['type'] not in ['none', 'client', 'iso']:
- self.module.fail_json(msg="Invalid cdrom.type: %s, valid value is 'none', 'client' or 'iso'."
- % cdrom_spec.get('type'))
+ cdrom_spec['type'] = cdrom_spec.get('type')
if cdrom_spec['type'] == 'iso' and not cdrom_spec.get('iso_path'):
self.module.fail_json(msg="cdrom.iso_path is mandatory when cdrom.type is set to iso.")
if 'controller_number' not in cdrom_spec or 'unit_number' not in cdrom_spec:
self.module.fail_json(msg="'cdrom.controller_number' and 'cdrom.unit_number' are required"
" parameters when configure CDROM list.")
- try:
- cdrom_ctl_num = int(cdrom_spec.get('controller_number'))
- cdrom_ctl_unit_num = int(cdrom_spec.get('unit_number'))
- except ValueError:
- self.module.fail_json(msg="'cdrom.controller_number' and 'cdrom.unit_number' attributes should be "
- "integer values.")
+
+ cdrom_ctl_num = int(cdrom_spec.get('controller_number'))
+ cdrom_ctl_unit_num = int(cdrom_spec.get('unit_number'))
if cdrom_spec['controller_type'] == 'ide' and (cdrom_ctl_num not in [0, 1] or cdrom_ctl_unit_num not in [0, 1]):
self.module.fail_json(msg="Invalid cdrom.controller_number: %s or cdrom.unit_number: %s, valid"
@@ -1494,55 +1511,7 @@ class PyVmomiHelper(PyVmomi):
# Changing CD-ROM settings on a template is not supported
return
- if isinstance(self.params.get('cdrom'), dict):
- self.configure_cdrom_dict(vm_obj)
- elif isinstance(self.params.get('cdrom'), list):
- self.configure_cdrom_list(vm_obj)
-
- def configure_cdrom_dict(self, vm_obj):
- self.module.deprecate(
- msg="Specifying CD-ROM configuration as dict is deprecated, Please use list to specify CD-ROM configuration.",
- version="4.0.0",
- collection_name="community.vmware"
- )
- if self.params["cdrom"].get('type') not in ['none', 'client', 'iso']:
- self.module.fail_json(msg="cdrom.type is mandatory. Options are 'none', 'client', and 'iso'.")
- if self.params["cdrom"]['type'] == 'iso' and not self.params["cdrom"].get('iso_path'):
- self.module.fail_json(msg="cdrom.iso_path is mandatory when cdrom.type is set to iso.")
-
- cdrom_spec = None
- cdrom_devices = self.get_vm_cdrom_devices(vm=vm_obj)
- iso_path = self.params["cdrom"].get("iso_path")
- if len(cdrom_devices) == 0:
- # Creating new CD-ROM
- ide_devices = self.get_vm_ide_devices(vm=vm_obj)
- if len(ide_devices) == 0:
- # Creating new IDE device
- ide_ctl = self.device_helper.create_ide_controller()
- ide_device = ide_ctl.device
- self.change_detected = True
- self.configspec.deviceChange.append(ide_ctl)
- else:
- ide_device = ide_devices[0]
- if len(ide_device.device) > 3:
- self.module.fail_json(msg="hardware.cdrom specified for a VM or template which already has 4"
- " IDE devices of which none are a cdrom")
-
- cdrom_spec = self.device_helper.create_cdrom(ctl_device=ide_device, cdrom_type=self.params["cdrom"]["type"],
- iso_path=iso_path)
- if vm_obj and vm_obj.runtime.powerState == vim.VirtualMachinePowerState.poweredOn:
- cdrom_spec.device.connectable.connected = (self.params["cdrom"]["type"] != "none")
-
- elif not self.device_helper.is_equal_cdrom(vm_obj=vm_obj, cdrom_device=cdrom_devices[0],
- cdrom_type=self.params["cdrom"]["type"], iso_path=iso_path):
- self.device_helper.update_cdrom_config(vm_obj, self.params["cdrom"], cdrom_devices[0], iso_path=iso_path)
- cdrom_spec = vim.vm.device.VirtualDeviceSpec()
- cdrom_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.edit
- cdrom_spec.device = cdrom_devices[0]
-
- if cdrom_spec:
- self.change_detected = True
- self.configspec.deviceChange.append(cdrom_spec)
+ self.configure_cdrom_list(vm_obj)
def configure_cdrom_list(self, vm_obj):
configured_cdroms = self.sanitize_cdrom_params()
@@ -1703,12 +1672,32 @@ class PyVmomiHelper(PyVmomi):
virt_based_security = self.params['hardware']['virt_based_security']
if virt_based_security is not None:
- if vm_obj is None or virt_based_security != self.configspec.flags.vbsEnabled:
+ if vm_obj is None or virt_based_security != vm_obj.config.flags.vbsEnabled:
self.change_detected = True
if self.configspec.flags is None:
self.configspec.flags = vim.vm.FlagInfo()
self.configspec.flags.vbsEnabled = virt_based_security
+ def configure_encryption_params(self, vm_obj):
+
+ encrypted_vmotion = self.params['encryption']['encrypted_vmotion']
+ if encrypted_vmotion is not None:
+ if vm_obj is None or encrypted_vmotion != vm_obj.config.migrateEncryption:
+ self.change_detected = True
+ self.configspec.migrateEncryption = encrypted_vmotion
+
+ encrypted_ft = self.params['encryption']['encrypted_ft']
+ if encrypted_ft is not None:
+ if encrypted_ft == "disabled":
+ encrypted_ft_cfg = "ftEncryptionDisabled"
+ elif encrypted_ft == "opportunistic":
+ encrypted_ft_cfg = "ftEncryptionOpportunistic"
+ elif encrypted_ft == "required":
+ encrypted_ft_cfg = "ftEncryptionRequired"
+ if vm_obj is None or encrypted_ft_cfg != vm_obj.config.ftEncryptionMode:
+ self.change_detected = True
+ self.configspec.ftEncryptionMode = encrypted_ft_cfg
+
def get_device_by_type(self, vm=None, type=None):
device_list = []
if vm is None or type is None:
@@ -1883,6 +1872,30 @@ class PyVmomiHelper(PyVmomi):
self.module.fail_json(msg="'ip' is required if 'netmask' is"
" specified under VM network list.")
+ if 'typev6' in network:
+ if network['typev6'] not in ['dhcp', 'static']:
+ self.module.fail_json(msg="Network type '%(typev6)s' for IPv6 is not a valid parameter."
+ " Valid parameters are ['dhcp', 'static']." % network)
+ if network['typev6'] != 'static' and ('ipv6' in network or 'netmaskv6' in network):
+ self.module.fail_json(msg='Static IPv6 information provided for network "%(name)s",'
+ ' but "typev6" is set to "%(typev6)s".' % network)
+ else:
+ # Type is optional parameter, if user provided IP or Subnet assume
+ # network type as 'static'
+ if 'ipv6' in network or 'netmaskv6' in network:
+ network['typev6'] = 'static'
+ else:
+ # User wants network type as 'dhcp'
+ network['typev6'] = 'dhcp'
+
+ if network.get('typev6') == 'static':
+ if 'ipv6' in network and 'netmaskv6' not in network:
+ self.module.fail_json(msg="'netmaskv6' is required if 'ipv6' is"
+ " specified under VM network list.")
+ if 'ipv6' not in network and 'netmaskv6' in network:
+ self.module.fail_json(msg="'ipv6' is required if 'netmaskv6' is"
+ " specified under VM network list.")
+
if 'device_type' in network and network['device_type'] not in self.device_helper.nic_device_type.keys():
self.module.fail_json(msg="Device type specified '%s' is not valid. Please specify correct device type"
" from ['%s']." % (network['device_type'],
@@ -2239,9 +2252,21 @@ class PyVmomiHelper(PyVmomi):
elif 'type' in network and network['type'] == 'dhcp':
guest_map.adapter.ip = vim.vm.customization.DhcpIpGenerator()
+ if "ipv6" in network and 'netmaskv6' in network:
+ guest_map.adapter.ipV6Spec = vim.vm.customization.IPSettings.IpV6AddressSpec()
+ guest_map.adapter.ipV6Spec.ip = [vim.vm.customization.FixedIpV6()]
+ guest_map.adapter.ipV6Spec.ip[0].ipAddress = str(network['ipv6'])
+ guest_map.adapter.ipV6Spec.ip[0].subnetMask = int(network['netmaskv6'])
+ elif 'typev6' in network and network['typev6'] == 'dhcp':
+ guest_map.adapter.ipV6Spec = vim.vm.customization.IPSettings.IpV6AddressSpec()
+ guest_map.adapter.ipV6Spec.ip = [vim.vm.customization.DhcpIpV6Generator()]
+
if 'gateway' in network:
guest_map.adapter.gateway = network['gateway']
+ if "gatewayv6" in network:
+ guest_map.adapter.ipV6Spec.gateway = network['gatewayv6']
+
# On Windows, DNS domain and DNS servers can be set by network interface
# https://pubs.vmware.com/vi3/sdk/ReferenceGuide/vim.vm.customization.IPSettings.html
if 'domain' in network:
@@ -2739,13 +2764,13 @@ class PyVmomiHelper(PyVmomi):
for host in cluster.host:
for mi in host.configManager.storageSystem.fileSystemVolumeInfo.mountInfo:
- if mi.volume.type == "VMFS":
+ if mi.volume.type == "VMFS" or mi.volume.type == "NFS":
datastores.append(self.cache.find_obj(self.content, [vim.Datastore], mi.volume.name))
elif self.params['esxi_hostname']:
host = self.find_hostsystem_by_name(self.params['esxi_hostname'])
for mi in host.configManager.storageSystem.fileSystemVolumeInfo.mountInfo:
- if mi.volume.type == "VMFS":
+ if mi.volume.type == "VMFS" or mi.volume.type == "NFS":
datastores.append(self.cache.find_obj(self.content, [vim.Datastore], mi.volume.name))
else:
datastores = self.cache.get_all_objs(self.content, [vim.Datastore])
@@ -2981,6 +3006,7 @@ class PyVmomiHelper(PyVmomi):
self.configure_guestid(vm_obj=vm_obj, vm_creation=True)
self.configure_cpu_and_memory(vm_obj=vm_obj, vm_creation=True)
self.configure_hardware_params(vm_obj=vm_obj)
+ self.configure_encryption_params(vm_obj=vm_obj)
self.configure_resource_alloc_info(vm_obj=vm_obj)
self.configure_vapp_properties(vm_obj=vm_obj)
self.configure_disks(vm_obj=vm_obj)
@@ -3165,6 +3191,7 @@ class PyVmomiHelper(PyVmomi):
self.configure_guestid(vm_obj=self.current_vm_obj)
self.configure_cpu_and_memory(vm_obj=self.current_vm_obj)
self.configure_hardware_params(vm_obj=self.current_vm_obj)
+ self.configure_encryption_params(vm_obj=self.current_vm_obj)
self.configure_disks(vm_obj=self.current_vm_obj)
self.configure_network(vm_obj=self.current_vm_obj)
self.configure_cdrom(vm_obj=self.current_vm_obj)
@@ -3419,7 +3446,19 @@ def main():
size_mb=dict(type='int', default=1024),
)
),
- cdrom=dict(type='raw', default=[]),
+ cdrom=dict(
+ type='list',
+ default=[],
+ elements='dict',
+ options=dict(
+ type=dict(type='str', choices=['none', 'client', 'iso'], default='client'),
+ iso_path=dict(type='str'),
+ controller_type=dict(type='str', choices=['ide', 'sata'], default='ide'),
+ controller_number=dict(type='int'),
+ unit_number=dict(type='int'),
+ state=dict(type='str', choices=['present', 'absent'], default='present'),
+ )
+ ),
hardware=dict(
type='dict',
default={},
@@ -3449,6 +3488,13 @@ def main():
virt_based_security=dict(type='bool'),
iommu=dict(type='bool')
)),
+ encryption=dict(
+ type='dict',
+ default={},
+ options=dict(
+ encrypted_vmotion=dict(type='str', choices=['disabled', 'opportunistic', 'required']),
+ encrypted_ft=dict(type='str', choices=['disabled', 'opportunistic', 'required'])
+ )),
force=dict(type='bool', default=False),
datacenter=dict(type='str', default='ha-datacenter'),
esxi_hostname=dict(type='str'),
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_guest_boot_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_guest_boot_info.py
index f440d3704..711488e80 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_guest_boot_info.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_guest_boot_info.py
@@ -22,17 +22,17 @@ options:
name:
description:
- Name of the VM to work with.
- - This is required if C(uuid) or C(moid) parameter is not supplied.
+ - This is required if O(uuid) or O(moid) parameter is not supplied.
type: str
uuid:
description:
- UUID of the instance to manage if known, this is VMware's BIOS UUID by default.
- - This is required if C(name) or C(moid) parameter is not supplied.
+ - This is required if O(name) or O(moid) parameter is not supplied.
type: str
moid:
description:
- Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.
- - This is required if C(name) or C(uuid) is not supplied.
+ - This is required if O(name) or O(uuid) is not supplied.
type: str
use_instance_uuid:
description:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_guest_boot_manager.py b/ansible_collections/community/vmware/plugins/modules/vmware_guest_boot_manager.py
index 63be3ae0c..ad89e6aed 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_guest_boot_manager.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_guest_boot_manager.py
@@ -22,17 +22,17 @@ options:
name:
description:
- Name of the VM to work with.
- - This is required if C(uuid) or C(moid) parameter is not supplied.
+ - This is required if O(uuid) or O(moid) parameter is not supplied.
type: str
uuid:
description:
- UUID of the instance to manage if known, this is VMware's BIOS UUID by default.
- - This is required if C(name) or C(moid) parameter is not supplied.
+ - This is required if O(name) or O(moid) parameter is not supplied.
type: str
moid:
description:
- Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.
- - This is required if C(name) or C(uuid) is not supplied.
+ - This is required if O(name) or O(uuid) is not supplied.
type: str
use_instance_uuid:
description:
@@ -63,18 +63,18 @@ options:
type: int
enter_bios_setup:
description:
- - If set to C(true), the virtual machine automatically enters BIOS setup the next time it boots.
+ - If set to V(true), the virtual machine automatically enters BIOS setup the next time it boots.
- The virtual machine resets this flag, so that the machine boots proceeds normally.
type: 'bool'
boot_retry_enabled:
description:
- - If set to C(true), the virtual machine that fails to boot, will try to boot again after C(boot_retry_delay) is expired.
- - If set to C(false), the virtual machine waits indefinitely for user intervention.
+ - If set to V(true), the virtual machine that fails to boot, will try to boot again after O(boot_retry_delay) is expired.
+ - If set to V(false), the virtual machine waits indefinitely for user intervention.
type: 'bool'
boot_retry_delay:
description:
- Specify the time in milliseconds between virtual machine boot failure and subsequent attempt to boot again.
- - If set, will automatically set C(boot_retry_enabled) to C(true) as this parameter is required.
+ - If set, will automatically set O(boot_retry_enabled=true) as this parameter is required.
type: int
boot_firmware:
description:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_guest_controller.py b/ansible_collections/community/vmware/plugins/modules/vmware_guest_controller.py
index 85b7d3438..df92a9a05 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_guest_controller.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_guest_controller.py
@@ -23,17 +23,17 @@ options:
name:
description:
- Name of the virtual machine.
- - This is a required parameter, if parameter C(uuid) or C(moid) is not supplied.
+ - This is a required parameter, if parameter O(uuid) or O(moid) is not supplied.
type: str
uuid:
description:
- UUID of the instance to gather facts if known, this is VMware's unique identifier.
- - This is a required parameter, if parameter C(name) or C(moid) is not supplied.
+ - This is a required parameter, if parameter O(name) or O(moid) is not supplied.
type: str
moid:
description:
- Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.
- - This is required if C(name) or C(uuid) is not supplied.
+ - This is required if O(name) or O(uuid) is not supplied.
type: str
folder:
description:
@@ -70,8 +70,8 @@ options:
suboptions:
controller_number:
description:
- - Disk controller bus number. When C(state) is set to C(absent), this parameter is required.
- - When C(type) set to C(usb2) or C(usb3), this parameter is not required.
+ - Disk controller bus number. When O(controllers.state=absent), this parameter is required.
+ - When O(controllers.type=usb2) or O(controllers.type=usb3), this parameter is not required.
type: int
choices:
- 0
@@ -81,7 +81,7 @@ options:
type:
description:
- Type of disk or USB controller.
- - From vSphere 6.5 and virtual machine with hardware version 13, C(nvme) controller starts to be supported.
+ - From vSphere 6.5 and virtual machine with hardware version 13, V(nvme) controller starts to be supported.
required: true
type: str
choices:
@@ -96,9 +96,9 @@ options:
state:
description:
- Add new controller or remove specified existing controller.
- - If C(state) is set to C(absent), the specified controller will be removed from virtual machine when there is no disk or device attaching to it.
+ - If set to V(absent), the specified controller will be removed from virtual machine when there is no disk or device attaching to it.
- If specified controller is removed or not exist, no action will be taken only warning message.
- - If C(state) is set to C(present), new controller with specified type will be added.
+ - If set to V(present), new controller with specified type will be added.
- If the number of controller with specified controller type reaches it's maximum, no action will be taken only warning message.
required: true
type: str
@@ -117,7 +117,7 @@ options:
gather_disk_controller_facts:
description:
- Whether to collect existing disk and USB controllers facts only.
- - When this parameter is set to C(true), C(controllers) parameter will be ignored.
+ - When this parameter is set to V(true), O(controllers) parameter will be ignored.
type: bool
default: false
sleep_time:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_guest_cross_vc_clone.py b/ansible_collections/community/vmware/plugins/modules/vmware_guest_cross_vc_clone.py
index 5da157081..8d7c4abac 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_guest_cross_vc_clone.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_guest_cross_vc_clone.py
@@ -22,17 +22,17 @@ options:
name:
description:
- Name of the virtual machine or template.
- - This is a required parameter, if parameter C(uuid) or C(moid) is not supplied.
+ - This is a required parameter, if parameter O(uuid) or O(moid) is not supplied.
type: str
uuid:
description:
- UUID of the vm/template instance to clone from, this is VMware's unique identifier.
- - This is a required parameter, if parameter C(name) or C(moid) is not supplied.
+ - This is a required parameter, if parameter O(name) or O(moid) is not supplied.
type: str
moid:
description:
- Managed Object ID of the vm/template instance to manage if known, this is a unique identifier only within a single vCenter instance.
- - This is required if C(name) or C(uuid) is not supplied.
+ - This is required if O(name) or O(uuid) is not supplied.
type: str
use_instance_uuid:
description:
@@ -103,10 +103,10 @@ options:
state:
description:
- The state of Virtual Machine deployed.
- - If set to C(present) and VM does not exists, then VM is created.
- - If set to C(present) and VM exists, no action is taken.
- - If set to C(poweredon) and VM does not exists, then VM is created with powered on state.
- - If set to C(poweredon) and VM exists, no action is taken.
+ - If set to V(present) and VM does not exists, then VM is created.
+ - If set to V(present) and VM exists, no action is taken.
+ - If set to V(poweredon) and VM does not exists, then VM is created with powered on state.
+ - If set to V(poweredon) and VM exists, no action is taken.
type: str
required: false
default: 'present'
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_guest_custom_attribute_defs.py b/ansible_collections/community/vmware/plugins/modules/vmware_guest_custom_attribute_defs.py
index c7fdec652..9ff05e412 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_guest_custom_attribute_defs.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_guest_custom_attribute_defs.py
@@ -22,16 +22,16 @@ options:
attribute_key:
description:
- Name of the custom attribute definition.
- - This is required parameter, if C(state) is set to C(present) or C(absent).
+ - This is required parameter, if O(state=present) or O(state=absent).
required: false
type: str
state:
description:
- Manage definition of custom attributes.
- - If set to C(present) and definition not present, then custom attribute definition is created.
- - If set to C(present) and definition is present, then no action taken.
- - If set to C(absent) and definition is present, then custom attribute definition is removed.
- - If set to C(absent) and definition is absent, then no action taken.
+ - If set to V(present) and definition not present, then custom attribute definition is created.
+ - If set to V(present) and definition is present, then no action taken.
+ - If set to V(absent) and definition is present, then custom attribute definition is removed.
+ - If set to V(absent) and definition is absent, then no action taken.
default: 'present'
choices: ['present', 'absent']
type: str
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_guest_custom_attributes.py b/ansible_collections/community/vmware/plugins/modules/vmware_guest_custom_attributes.py
index 1677f9ef2..7f7566ebd 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_guest_custom_attributes.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_guest_custom_attributes.py
@@ -23,25 +23,25 @@ options:
name:
description:
- Name of the virtual machine to work with.
- - This is required parameter, if C(uuid) or C(moid) is not supplied.
+ - This is required parameter, if O(uuid) or O(moid) is not supplied.
type: str
state:
description:
- The action to take.
- - If set to C(present), then custom attribute is added or updated.
- - If set to C(absent), then custom attribute value is removed.
+ - If set to V(present), then custom attribute is added or updated.
+ - If set to V(absent), then custom attribute value is removed.
default: 'present'
choices: ['present', 'absent']
type: str
uuid:
description:
- UUID of the virtual machine to manage if known. This is VMware's unique identifier.
- - This is required parameter, if C(name) or C(moid) is not supplied.
+ - This is required parameter, if O(name) or O(moid) is not supplied.
type: str
moid:
description:
- Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.
- - This is required if C(name) or C(uuid) is not supplied.
+ - This is required if O(name) or O(uuid) is not supplied.
type: str
use_instance_uuid:
description:
@@ -51,7 +51,7 @@ options:
folder:
description:
- Absolute path to find an existing guest.
- - This is required parameter, if C(name) is supplied and multiple virtual machines with same name are found.
+ - This is required parameter, if O(name) is supplied and multiple virtual machines with same name are found.
type: str
datacenter:
description:
@@ -60,7 +60,7 @@ options:
attributes:
description:
- A list of name and value of custom attributes that needs to be manage.
- - Value of custom attribute is not required and will be ignored, if C(state) is set to C(absent).
+ - Value of custom attribute is not required and will be ignored, if O(state=absent).
suboptions:
name:
description:
@@ -247,7 +247,11 @@ class VmAttributeManager(PyVmomi):
"""
# Gather the available existing custom attributes based on user_fields
existing_custom_attributes = []
- for k, n in [(x.key, x.name) for x in self.custom_field_mgr for v in user_fields if x.name == v['name']]:
+ for k, n in [(x.key, x.name) for x in self.custom_field_mgr
+ # vmware_guest_custome_attributes must work with self moref type of custom attributes or with global custom attributes
+ if x.managedObjectType == vim.VirtualMachine or x.managedObjectType is None
+ for v in user_fields
+ if x.name == v['name']]:
existing_custom_attributes.append({
"key": k,
"name": n
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_guest_disk.py b/ansible_collections/community/vmware/plugins/modules/vmware_guest_disk.py
index fd54d41fa..56251b444 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_guest_disk.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_guest_disk.py
@@ -25,17 +25,17 @@ options:
name:
description:
- Name of the virtual machine.
- - This is a required parameter, if parameter C(uuid) or C(moid) is not supplied.
+ - This is a required parameter, if parameter O(uuid) or O(moid) is not supplied.
type: str
uuid:
description:
- UUID of the instance to gather facts if known, this is VMware's unique identifier.
- - This is a required parameter, if parameter C(name) or C(moid) is not supplied.
+ - This is a required parameter, if parameter O(name) or O(moid) is not supplied.
type: str
moid:
description:
- Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.
- - This is required if C(name) or C(uuid) is not supplied.
+ - This is required if O(name) or O(uuid) is not supplied.
type: str
folder:
description:
@@ -89,58 +89,55 @@ options:
type: int
type:
description:
- - The type of disk, if not specified then use C(thick) type for new disk, no eagerzero.
- - The disk type C(rdm) is added in version 1.13.0.
- - The disk type C(vpmemdisk) is added in version 2.7.0.
+ - The type of disk, if not specified then use V(thick) type for new disk, no eagerzero.
type: str
choices: ['thin', 'eagerzeroedthick', 'thick', 'rdm', 'vpmemdisk']
disk_mode:
description:
- - Type of disk mode. If not specified then use C(persistent) mode for new disk.
- - If set to 'persistent' mode, changes are immediately and permanently written to the virtual disk.
- - If set to 'independent_persistent' mode, same as persistent, but not affected by snapshots.
- - If set to 'independent_nonpersistent' mode, changes to virtual disk are made to a redo log and discarded
+ - Type of disk mode. If not specified then use V(persistent) mode for new disk.
+ - If set to V(persistent) mode, changes are immediately and permanently written to the virtual disk.
+ - If set to V(independent_persistent) mode, same as persistent, but not affected by snapshots.
+ - If set to V('independent_nonpersistent) mode, changes to virtual disk are made to a redo log and discarded
at power off, but not affected by snapshots.
- - Not applicable when disk C(type) is set to C(vpmemdisk).
+ - Not applicable when disk O(disk.type=vpmemdisk).
type: str
choices: ['persistent', 'independent_persistent', 'independent_nonpersistent']
rdm_path:
description:
- - Path of LUN for Raw Device Mapping required for disk type C(rdm).
- - Only valid if C(type) is set to C(rdm).
+ - Path of LUN for Raw Device Mapping required for O(disk.type=rdm).
+ - Only valid if O(disk.type=rdm).
type: str
cluster_disk:
description:
- This value allows for the sharing of an RDM between two machines.
- - The primary machine holding the RDM uses the default C(false).
- - The secondary machine holding the RDM uses C(true).
+ - The primary machine holding the RDM uses the default V(false).
+ - The secondary machine holding the RDM uses V(true).
type: bool
default: false
compatibility_mode:
- description: Compatibility mode for raw devices. Required when disk type C(type) is set to C(rdm).
+ description: Compatibility mode for raw devices. Required when O(disk.type=rdm).
type: str
choices: ['physicalMode','virtualMode']
sharing:
description:
- The sharing mode of the virtual disk.
- Setting sharing means that multiple virtual machines can write to the virtual disk.
- - Sharing can only be set if C(type) is set to C(eagerzeroedthick) or C(rdm).
+ - Sharing can only be set if O(disk.type=eagerzeroedthick) or O(disk.type=rdm).
type: bool
default: false
datastore:
description:
- Name of datastore or datastore cluster to be used for the disk.
- - Not applicable when disk C(type) is set to C(vpmemdisk).
+ - Not applicable when disk O(disk.type=vpmemdisk).
type: str
autoselect_datastore:
description:
- - Select the less used datastore. Specify only if C(datastore) is not specified.
- - Not applicable when disk C(type) is set to C(vpmemdisk).
+ - Select the less used datastore. Specify only if O(disk.datastore) is not specified.
+ - Not applicable when disk O(disk.type=vpmemdisk).
type: bool
scsi_controller:
description:
- SCSI controller number. Only 4 SCSI controllers are allowed per VM.
- - Care should be taken while specifying 'scsi_controller' is 0 and 'unit_number' as 0 as this disk may contain OS.
type: int
choices: [0, 1, 2, 3]
bus_sharing:
@@ -163,24 +160,24 @@ options:
scsi_type:
description:
- Type of SCSI controller. This value is required only for the first occurrence of SCSI Controller.
- - This value is ignored, if SCSI Controller is already present or C(state) is C(absent).
+ - This value is ignored, if SCSI Controller is already present or O(disk.state=absent).
type: str
choices: ['buslogic', 'lsilogic', 'lsilogicsas', 'paravirtual']
destroy:
- description: If C(state) is C(absent), make sure the disk file is deleted from the datastore. Added in version 2.10.
+ description: If O(disk.state=absent), make sure the disk file is deleted from the datastore.
type: bool
default: true
filename:
description:
- Existing disk image to be used. Filename must already exist on the datastore.
- - Specify filename string in C([datastore_name] path/to/file.vmdk) format. Added in version 2.10.
- - Not applicable when disk C(type) is set to C(vpmemdisk).
+ - Specify filename string in C([datastore_name] path/to/file.vmdk) format.
+ - Not applicable when disk O(disk.type=vpmemdisk).
type: str
state:
description:
- State of disk.
- - If set to 'absent', disk will be removed permanently from virtual machine configuration and from VMware storage.
- - If set to 'present', disk will be added if not present at given Controller and Unit Number.
+ - If set to V(absent), disk will be removed permanently from virtual machine configuration and from VMware storage.
+ - If set to V(present), disk will be added if not present at given Controller and Unit Number.
- or disk exists with different size, disk size is increased, reducing disk size is not allowed.
type: str
choices: ['present', 'absent']
@@ -188,19 +185,19 @@ options:
controller_type:
description:
- This parameter is added for managing disks attaching other types of controllers, e.g., SATA or NVMe.
- - If either C(controller_type) or C(scsi_type) is not specified, then use C(paravirtual) type.
+ - If either O(disk.controller_type) or O(disk.scsi_type) is not specified, then use V(paravirtual) type.
type: str
choices: ['buslogic', 'lsilogic', 'lsilogicsas', 'paravirtual', 'sata', 'nvme', 'ide']
controller_number:
description:
- - This parameter is used with C(controller_type) for specifying controller bus number.
- - For C(ide) controller type, valid value is 0 or 1.
+ - This parameter is used with O(disk.controller_type) for specifying controller bus number.
+ - For O(disk.controller_type=ide), valid value is 0 or 1.
type: int
choices: [0, 1, 2, 3]
iolimit:
description:
- Section specifies the shares and limit for storage I/O resource.
- - Not applicable when disk C(type) is set to C(vpmemdisk).
+ - Not applicable when O(disk.type=vpmemdisk).
suboptions:
limit:
description: Section specifies values for limit where the utilization of a virtual machine will not exceed, even if there are available resources.
@@ -213,21 +210,21 @@ options:
type: str
choices: ['low', 'normal', 'high', 'custom']
level_value:
- description: Custom value when C(level) is set as C(custom).
+ description: Custom value when O(disk.iolimit.shares.level=custom).
type: int
type: dict
type: dict
shares:
description:
- Section for iolimit section tells about what are all different types of shares user can add for disk.
- - Not applicable when disk C(type) is set to C(vpmemdisk).
+ - Not applicable when disk O(disk.type=vpmemdisk).
suboptions:
level:
description: Tells about different level for the shares section.
type: str
choices: ['low', 'normal', 'high', 'custom']
level_value:
- description: Custom value when C(level) is set as C(custom).
+ description: Custom value when O(disk.shares.level=custom).
type: int
type: dict
default: []
@@ -516,7 +513,7 @@ except ImportError:
from random import randint
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_native
-from ansible_collections.community.vmware.plugins.module_utils.vmware import PyVmomi, vmware_argument_spec,\
+from ansible_collections.community.vmware.plugins.module_utils.vmware import PyVmomi, vmware_argument_spec, \
wait_for_task, find_obj, get_all_objs, get_parent_datacenter
from ansible_collections.community.vmware.plugins.module_utils.vm_device_helper import PyVmomiDeviceHelper
@@ -810,10 +807,6 @@ class PyVmomiHelper(PyVmomi):
disk_change_list.append(disk_change)
results['disk_changes'][disk['disk_index']] = "Disk created."
break
- if not disk_found and disk['state'] == 'absent':
- self.module.fail_json(msg="Not found disk with 'controller_type': '%s',"
- " 'controller_number': '%s', 'unit_number': '%s' to remove."
- % (disk['controller_type'], disk['controller_number'], disk['disk_unit_number']))
if disk_change:
# Adding multiple disks in a single attempt raises weird errors
# So adding single disk at a time.
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_guest_disk_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_guest_disk_info.py
index 1d12b2573..06c5d3565 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_guest_disk_info.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_guest_disk_info.py
@@ -24,17 +24,17 @@ options:
name:
description:
- Name of the virtual machine.
- - This is required parameter, if parameter C(uuid) or C(moid) is not supplied.
+ - This is required parameter, if parameter O(uuid) or O(moid) is not supplied.
type: str
uuid:
description:
- UUID of the instance to gather information if known, this is VMware's unique identifier.
- - This is required parameter, if parameter C(name) or C(moid) is not supplied.
+ - This is required parameter, if parameter O(name) or O(moid) is not supplied.
type: str
moid:
description:
- Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.
- - This is required if C(name) or C(uuid) is not supplied.
+ - This is required if O(name) or O(uuid) is not supplied.
type: str
use_instance_uuid:
description:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_guest_file_operation.py b/ansible_collections/community/vmware/plugins/modules/vmware_guest_file_operation.py
index 69a0a112a..487fe1298 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_guest_file_operation.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_guest_file_operation.py
@@ -34,7 +34,7 @@ options:
description:
- Destination folder, absolute path to find an existing guest or create the new guest.
- The folder should include the datacenter. ESX's datacenter is ha-datacenter
- - Used only if C(vm_id_type) is C(inventory_path).
+ - Used only if O(vm_id_type=inventory_path).
- 'Examples:'
- ' folder: /ha-datacenter/vm'
- ' folder: ha-datacenter/vm'
@@ -79,7 +79,6 @@ options:
- Create or delete a directory.
- Can be used to create temp directory inside guest using mktemp operation.
- mktemp sets variable C(dir) in the result with the name of the new directory.
- - mktemp operation option is added in version 2.8.
suboptions:
operation:
description:
@@ -91,17 +90,17 @@ options:
type: str
description:
- Directory path.
- - Required for C(create) or C(remove).
+ - Required for O(directory.operation=create) or O(directory.operation=remove).
prefix:
description:
- Temporary directory prefix.
- - Required for C(mktemp).
+ - Required for O(directory.operation=mktemp).
type: str
suffix:
type: str
description:
- Temporary directory suffix.
- - Required for C(mktemp).
+ - Required for O(directory.operation=mktemp).
recurse:
type: bool
description:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_guest_find.py b/ansible_collections/community/vmware/plugins/modules/vmware_guest_find.py
index 7197613b7..64b5b2f3a 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_guest_find.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_guest_find.py
@@ -21,12 +21,12 @@ options:
name:
description:
- Name of the VM to work with.
- - This is required if C(uuid) parameter is not supplied.
+ - This is required if O(uuid) parameter is not supplied.
type: str
uuid:
description:
- UUID of the instance to manage if known, this is VMware's BIOS UUID by default.
- - This is required if C(name) parameter is not supplied.
+ - This is required if O(name) parameter is not supplied.
type: str
use_instance_uuid:
description:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_guest_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_guest_info.py
index fb4735625..470f76642 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_guest_info.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_guest_info.py
@@ -22,7 +22,7 @@ options:
name:
description:
- Name of the VM to work with
- - This is required if C(uuid) or C(moid) is not supplied.
+ - This is required if O(uuid) or O(moid) is not supplied.
type: str
name_match:
description:
@@ -33,7 +33,7 @@ options:
uuid:
description:
- UUID of the instance to manage if known, this is VMware's unique identifier.
- - This is required if C(name) or C(moid) is not supplied.
+ - This is required if O(name) or O(moid) is not supplied.
type: str
use_instance_uuid:
description:
@@ -43,12 +43,12 @@ options:
moid:
description:
- Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.
- - This is required if C(name) or C(uuid) is not supplied.
+ - This is required if O(name) or O(uuid) is not supplied.
type: str
folder:
description:
- Destination folder, absolute or relative path to find an existing guest.
- - This is required if name is supplied.
+ - This is required if O(name) is supplied.
- The folder should include the datacenter. ESX's datacenter is ha-datacenter
- 'Examples:'
- ' folder: /ha-datacenter/vm'
@@ -69,24 +69,24 @@ options:
tags:
description:
- Whether to show tags or not.
- - If set C(true), shows tags information. Returns a list of tag names.
- - If set C(false), hides tags information.
+ - If set V(true), shows tags information. Returns a list of tag names.
+ - If set V(false), hides tags information.
- vSphere Automation SDK is required.
default: false
type: bool
tag_details:
description:
- - If set C(true), detail information about 'tags' returned.
- - Without this flag, the 'tags' returns a list of tag names.
- - With this flag, the 'tags' returns a list of dict about tag information with additional details like category name, category id, and tag id.
+ - If set V(true), detail information about tags returned.
+ - Without this flag, O(tags=true) returns a list of tag names.
+ - With this flag, O(tags=true) returns a list of dict about tag information with additional details like category name, category id, and tag id.
- This parameter is added to maintain backward compatability.
default: false
type: bool
schema:
description:
- Specify the output schema desired.
- - The 'summary' output schema is the legacy output from the module
- - The 'vsphere' output schema is the vSphere API class definition
+ - The V(summary) output schema is the legacy output from the module
+ - The V(vsphere) output schema is the vSphere API class definition
which requires pyvmomi>6.7.1
choices: ['summary', 'vsphere']
default: 'summary'
@@ -103,7 +103,7 @@ options:
- ' "guest.disk",'
- ' "overallStatus"'
- ' ]'
- - Only valid when C(schema) is C(vsphere).
+ - Only valid when O(schema=vsphere).
type: list
elements: str
required: false
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_guest_instant_clone.py b/ansible_collections/community/vmware/plugins/modules/vmware_guest_instant_clone.py
index 3e487ca12..2b824338c 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_guest_instant_clone.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_guest_instant_clone.py
@@ -36,17 +36,17 @@ options:
parent_vm:
description:
- Name of the parent virtual machine.
- - This is a required parameter, if parameter C(uuid) or C(moid) is not supplied.
+ - This is a required parameter, if parameter O(uuid) or O(moid) is not supplied.
type: str
uuid:
description:
- UUID of the vm instance to clone from, this is VMware's unique identifier.
- - This is a required parameter, if parameter C(parent_vm) or C(moid) is not supplied.
+ - This is a required parameter, if parameter O(parent_vm) or O(moid) is not supplied.
type: str
moid:
description:
- Managed Object ID of the vm instance to manage if known, this is a unique identifier only within a single vCenter instance.
- - This is required if C(parent_vm) or C(uuid) is not supplied.
+ - This is required if O(parent_vm) or O(uuid) is not supplied.
type: str
use_instance_uuid:
description:
@@ -57,7 +57,7 @@ options:
description:
- Name of the ESX Host in datacenter in which to place cloned VM.
- The host has to be a member of the cluster that contains the resource pool.
- - Required with I(resource_pool) to find resource pool details. This will be used as additional information when there are resource pools with same name.
+ - Required with O(resource_pool) to find resource pool details. This will be used as additional information when there are resource pools with same name.
type: str
aliases: ['esxi_hostname']
required: true
@@ -83,8 +83,6 @@ options:
resource_pool:
description:
- Name of the resource pool in datacenter in which to place deployed VM.
- - Required if I(cluster) is not specified.
- - For default or non-unique resource pool names, specify I(host) and I(cluster).
- C(Resources) is the default name of resource pool.
type: str
required: false
@@ -139,7 +137,7 @@ options:
default: true
wait_vm_tools_timeout:
description:
- - Define a timeout (in seconds) for I(the wait_vm_tools) parameter.
+ - Define a timeout (in seconds) for the O(wait_vm_tools) parameter.
type: int
default: 300
extends_documentation_fragment:
@@ -256,7 +254,6 @@ RETURN = r'''
vm_info:
description:
- metadata about the virtual machine
- - added instance_uuid from version 1.12.0
returned: always
type: dict
sample: {
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_guest_move.py b/ansible_collections/community/vmware/plugins/modules/vmware_guest_move.py
index cef4e8276..53f27adb3 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_guest_move.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_guest_move.py
@@ -22,17 +22,17 @@ options:
name:
description:
- Name of the existing virtual machine to move.
- - This is required if C(uuid) or C(moid) is not supplied.
+ - This is required if O(uuid) or O(moid) is not supplied.
type: str
uuid:
description:
- UUID of the virtual machine to manage if known, this is VMware's unique identifier.
- - This is required if C(name) or C(moid) is not supplied.
+ - This is required if O(name) or O(moid) is not supplied.
type: str
moid:
description:
- Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.
- - This is required if C(name) or C(uuid) is not supplied.
+ - This is required if O(name) or O(uuid) is not supplied.
type: str
use_instance_uuid:
description:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_guest_network.py b/ansible_collections/community/vmware/plugins/modules/vmware_guest_network.py
index 5cde25c03..799d19d3f 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_guest_network.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_guest_network.py
@@ -23,12 +23,12 @@ options:
name:
description:
- Name of virtual machine
- - Required if C(uuid) or C(moid) is not supplied.
+ - Required if O(uuid) or O(moid) is not supplied.
type: str
uuid:
description:
- vm uuid
- - Required if C(name) or C(moid) is not supplied.
+ - Required if O(name) or O(moid) is not supplied.
type: str
use_instance_uuid:
description:
@@ -38,7 +38,7 @@ options:
moid:
description:
- Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.
- - Required if C(uuid) or C(name) is not supplied.
+ - Required if O(uuid) or O(name) is not supplied.
type: str
folder:
description:
@@ -60,11 +60,11 @@ options:
mac_address:
description:
- MAC address of the NIC that should be altered, if a MAC address is not supplied a new nic will be created.
- - Required when I(state=absent).
+ - Required when O(state=absent).
type: str
label:
description:
- - 'Label of the NIC that should be altered. C(mac_address) or C(label) should be set to get the corresponding
+ - 'Label of the NIC that should be altered. O(mac_address) or O(label) should be set to get the corresponding
device to reconfigure.'
- Alter the name of the network adapter.
type: str
@@ -80,12 +80,12 @@ options:
default: vmxnet3
description:
- Type of virtual network device.
- - 'Valid choices are - C(e1000), C(e1000e), C(pcnet32), C(vmxnet2), C(vmxnet3) (default), C(sriov), C(pvrdma).'
+ - 'Valid choices are - V(e1000), V(e1000e), V(pcnet32), V(vmxnet2), V(vmxnet3) (default), V(sriov), V(pvrdma).'
type: str
pvrdma_device_protocol:
version_added: '3.3.0'
description:
- - The PVRDMA device protocol used. Valid choices are - C(rocev1), C(rocev2).
+ - The PVRDMA device protocol used. Valid choices are - V(rocev1), V(rocev2).
- This parameter is only used on the VM with hardware version >=14 and <= 19.
type: str
switch:
@@ -102,8 +102,8 @@ options:
choices: ['present', 'absent']
description:
- NIC state.
- - When C(state=present), a nic will be added if a mac address or label does not previously exists or is unset.
- - When C(state=absent), the I(mac_address) parameter has to be set.
+ - When V(present), a nic will be added if a mac address or label does not previously exists or is unset.
+ - When V(absent), the O(mac_address) parameter has to be set.
type: str
start_connected:
default: true
@@ -124,22 +124,19 @@ options:
default: false
description:
- Enable Universal Pass-through (UPT).
- - Only compatible with the C(vmxnet3) device type.
+ - Only compatible with the O(device_type=vmxnet3).
type: bool
physical_function_backing:
- version_added: '2.3.0'
type: str
description:
- If set, specifies the PCI ID of the physical function to use as backing for a SR-IOV network adapter.
- This option is only compatible for SR-IOV network adapters.
virtual_function_backing:
- version_added: '2.3.0'
type: str
description:
- If set, specifies the PCI ID of the physical function to use as backing for a SR-IOV network adapter.
- This option is only compatible for SR-IOV network adapters.
allow_guest_os_mtu_change:
- version_added: '2.3.0'
default: true
type: bool
description:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_guest_powerstate.py b/ansible_collections/community/vmware/plugins/modules/vmware_guest_powerstate.py
index 8b0f546a4..aaff49d45 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_guest_powerstate.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_guest_powerstate.py
@@ -20,7 +20,7 @@ author:
options:
datacenter:
description:
- - The I(datacenter) where the VM you'd like to operate the power.
+ - The datacenter where the VM you'd like to operate the power.
- This parameter is case sensitive.
default: ha-datacenter
type: str
@@ -33,7 +33,7 @@ options:
name:
description:
- Name of the virtual machine to work with.
- - Virtual machine names in vCenter are not necessarily unique, which may be problematic, see C(name_match).
+ - Virtual machine names in vCenter are not necessarily unique, which may be problematic, see O(name_match).
type: str
name_match:
description:
@@ -44,12 +44,12 @@ options:
uuid:
description:
- UUID of the instance to manage if known, this is VMware's unique identifier.
- - This is required if C(name) or C(moid) is not supplied.
+ - This is required if O(name) or O(moid) is not supplied.
type: str
moid:
description:
- Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.
- - This is required if C(name) or C(uuid) is not supplied.
+ - This is required if O(name) or O(uuid) is not supplied.
type: str
use_instance_uuid:
description:
@@ -80,13 +80,13 @@ options:
schedule_task_name:
description:
- Name of schedule task.
- - Valid only if C(scheduled_at) is specified.
+ - Valid only if O(scheduled_at) is specified.
type: str
required: false
schedule_task_description:
description:
- Description of schedule task.
- - Valid only if C(scheduled_at) is specified.
+ - Valid only if O(scheduled_at) is specified.
type: str
required: false
schedule_task_enabled:
@@ -103,7 +103,7 @@ options:
type: bool
state_change_timeout:
description:
- - If the C(state) is set to C(shutdown-guest), by default the module will return immediately after sending the shutdown signal.
+ - If the O(state=shutdown-guest), by default the module will return immediately after sending the shutdown signal.
- If this argument is set to a positive integer, the module will instead wait for the VM to reach the poweredoff state.
- The value sets a timeout in seconds for the module to wait for the state change.
default: 0
@@ -112,7 +112,7 @@ options:
description:
- A list of questions to answer, should one or more arise while waiting for the task to complete.
- Some common uses are to allow a cdrom to be changed even if locked, or to answer the question as to whether a VM was copied or moved.
- - The I(answer) can be used if I(state) is C(powered-on).
+ - Can be used if O(state=powered-on).
suboptions:
question:
description:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_guest_register_operation.py b/ansible_collections/community/vmware/plugins/modules/vmware_guest_register_operation.py
index 4aa7e84a9..bd99f1ca4 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_guest_register_operation.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_guest_register_operation.py
@@ -76,8 +76,8 @@ options:
state:
description:
- Specify the state the virtual machine should be in.
- - if set to C(present), register VM in inventory.
- - if set to C(absent), unregister VM from inventory.
+ - if set to V(present), register VM in inventory.
+ - if set to V(absent), unregister VM from inventory.
default: present
choices: [ present, absent ]
type: str
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_guest_screenshot.py b/ansible_collections/community/vmware/plugins/modules/vmware_guest_screenshot.py
index 1f3fb43ec..7c71997c7 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_guest_screenshot.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_guest_screenshot.py
@@ -23,17 +23,17 @@ options:
name:
description:
- Name of the virtual machine.
- - This is a required parameter, if parameter C(uuid) or C(moid) is not supplied.
+ - This is a required parameter, if parameter O(uuid) or O(moid) is not supplied.
type: str
uuid:
description:
- UUID of the instance to gather facts if known, this is VMware's unique identifier.
- - This is a required parameter, if parameter C(name) or C(moid) is not supplied.
+ - This is a required parameter, if parameter O(name) or O(moid) is not supplied.
type: str
moid:
description:
- Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.
- - This is required if C(name) or C(uuid) is not supplied.
+ - This is required if O(name) or O(uuid) is not supplied.
type: str
folder:
description:
@@ -54,14 +54,14 @@ options:
cluster:
description:
- The name of cluster where the virtual machine is running.
- - This is a required parameter, if C(esxi_hostname) is not set.
- - C(esxi_hostname) and C(cluster) are mutually exclusive parameters.
+ - This is a required parameter, if O(esxi_hostname) is not set.
+ - O(esxi_hostname) and O(cluster) are mutually exclusive.
type: str
esxi_hostname:
description:
- The ESXi hostname where the virtual machine is running.
- - This is a required parameter, if C(cluster) is not set.
- - C(esxi_hostname) and C(cluster) are mutually exclusive parameters.
+ - This is a required parameter, if O(cluster) is not set.
+ - O(esxi_hostname) and O(cluster) are mutually exclusive.
type: str
datacenter:
description:
@@ -69,8 +69,8 @@ options:
type: str
local_path:
description:
- - 'If C(local_path) is not set, the created screenshot file will be kept in the directory of the virtual machine
- on ESXi host. If C(local_path) is set to a valid path on local machine, then the screenshot file will be
+ - 'If not set, the created screenshot file will be kept in the directory of the virtual machine
+ on ESXi host. If set to a valid path on local machine, then the screenshot file will be
downloaded from ESXi host to the local directory.'
- 'If not download screenshot file to local machine, you can open it through the returned file URL in screenshot
facts manually.'
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_guest_sendkey.py b/ansible_collections/community/vmware/plugins/modules/vmware_guest_sendkey.py
index 3b858edd2..8d1c56cff 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_guest_sendkey.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_guest_sendkey.py
@@ -23,17 +23,17 @@ options:
name:
description:
- Name of the virtual machine.
- - This is a required parameter, if parameter C(uuid) or C(moid) is not supplied.
+ - This is a required parameter, if parameter O(uuid) or O(moid) is not supplied.
type: str
uuid:
description:
- UUID of the instance to gather facts if known, this is VMware's unique identifier.
- - This is a required parameter, if parameter C(name) or C(moid) is not supplied.
+ - This is a required parameter, if parameter O(name) or O(moid) is not supplied.
type: str
moid:
description:
- Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.
- - This is required if C(name) or C(uuid) is not supplied.
+ - This is required if O(name) or O(uuid) is not supplied.
type: str
folder:
description:
@@ -54,14 +54,14 @@ options:
cluster:
description:
- The name of cluster where the virtual machine is running.
- - This is a required parameter, if C(esxi_hostname) is not set.
- - C(esxi_hostname) and C(cluster) are mutually exclusive parameters.
+ - This is a required parameter, if O(esxi_hostname) is not set.
+ - O(esxi_hostname) and O(cluster) are mutually exclusive.
type: str
esxi_hostname:
description:
- The ESXi hostname where the virtual machine is running.
- - This is a required parameter, if C(cluster) is not set.
- - C(esxi_hostname) and C(cluster) are mutually exclusive parameters.
+ - This is a required parameter, if O(cluster) is not set.
+ - O(esxi_hostname) and O(cluster) are mutually exclusive.
type: str
datacenter:
description:
@@ -71,14 +71,14 @@ options:
description:
- The string will be sent to the virtual machine.
- This string can contain valid special character, alphabet and digit on the keyboard.
+ - If both O(keys_send) and O(string_send) are specified, keys in O(keys_send) list will be sent in front of the O(string_send).
type: str
keys_send:
description:
- The list of the keys will be sent to the virtual machine.
- 'Valid values are C(ENTER), C(ESC), C(BACKSPACE), C(TAB), C(SPACE), C(CAPSLOCK), C(HOME), C(DELETE), C(END), C(CTRL_ALT_DEL),
- C(CTRL_C), C(CTRL_X) and C(F1) to C(F12), C(RIGHTARROW), C(LEFTARROW), C(DOWNARROW), C(UPARROW).'
- - If both C(keys_send) and C(string_send) are specified, keys in C(keys_send) list will be sent in front of the C(string_send).
- - Values C(HOME) and C(END) are added in version 1.17.0.
+ C(CTRL_C), C(CTRL_X) and C(F1) to C(F12), C(RIGHTARROW), C(LEFTARROW), C(DOWNARROW), C(UPARROW), C(WINDOWS).'
+ - If both O(keys_send) and O(string_send) are specified, keys in O(keys_send) list will be sent in front of the O(string_send).
type: list
default: []
elements: str
@@ -249,6 +249,7 @@ class PyVmomiHelper(PyVmomi):
('LEFTARROW', '0x50', [('', [])]),
('DOWNARROW', '0x51', [('', [])]),
('UPARROW', '0x52', [('', [])]),
+ ('WINDOWS', '0xe3', [('', [])]),
]
@staticmethod
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_guest_serial_port.py b/ansible_collections/community/vmware/plugins/modules/vmware_guest_serial_port.py
index bc1b4c7db..3c26361eb 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_guest_serial_port.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_guest_serial_port.py
@@ -19,17 +19,17 @@ options:
name:
description:
- Name of the virtual machine.
- - This is a required parameter, if parameter C(uuid) or C(moid) is not supplied.
+ - This is a required parameter, if parameter O(uuid) or O(moid) is not supplied.
type: str
uuid:
description:
- UUID of the instance to manage the serial ports, this is VMware's unique identifier.
- - This is a required parameter, if parameter C(name) or C(moid) is not supplied.
+ - This is a required parameter, if parameter O(name) or O(moid) is not supplied.
type: str
moid:
description:
- Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.
- - This is required if C(name) or C(uuid) is not supplied.
+ - This is required if O(name) or O(uuid) is not supplied.
type: str
use_instance_uuid:
description:
@@ -41,7 +41,7 @@ options:
elements: dict
description:
- A list of backings for serial ports.
- - 'C(backing_type) (str): is required to add or reconfigure or remove an existing serial port.'
+ - 'O(backings.backing_type) is required to add or reconfigure or remove an existing serial port.'
required: true
suboptions:
backing_type:
@@ -53,11 +53,11 @@ options:
- type
state:
description:
- - C(state) is required to identify whether we are adding, modifying or removing the serial port.
- - If C(state) is set to C(present), a serial port will be added or modified.
- - If C(state) is set to C(absent), an existing serial port will be removed.
- - If an existing serial port to modify or remove, C(backing_type) and either of C(service_uri) or C(pipe_name)
- or C(device_name) or C(file_path) are required.
+ - O(backings.state) is required to identify whether we are adding, modifying or removing the serial port.
+ - If V(present), a serial port will be added or modified.
+ - If V(absent), an existing serial port will be removed.
+ - If an existing serial port to modify or remove, O(backings.backing_type) and either of O(backings.service_uri) or O(backings.pipe_name)
+ or O(backings.device_name) or O(backings.file_path) are required.
choices:
- present
- absent
@@ -71,12 +71,12 @@ options:
pipe_name:
description:
- Pipe name for the host pipe.
- - Required when I(backing_type=pipe).
+ - Required when O(backings.backing_type=pipe).
type: str
endpoint:
description:
- When you use serial port pipe backing to connect a virtual machine to another process, you must define the endpoints.
- - Required when I(backing_type=pipe).
+ - Required when O(backings.backing_type=pipe).
type: str
choices:
- client
@@ -85,29 +85,29 @@ options:
no_rx_loss:
description:
- Enables optimized data transfer over the pipe.
- - Required when I(backing_type=pipe).
+ - Required when O(backings.backing_type=pipe).
type: bool
default: false
service_uri:
description:
- - Identifies the local host or a system on the network, depending on the value of I(direction).
+ - Identifies the local host or a system on the network, depending on the value of O(backings.direction).
- If you use the virtual machine as a server, the URI identifies the host on which the virtual machine runs.
- In this case, the host name part of the URI should be empty, or it should specify the address of the local host.
- If you use the virtual machine as a client, the URI identifies the remote system on the network.
- - Required when I(backing_type=network).
+ - Required when O(backings.backing_type=pipe).
type: str
proxy_uri:
description:
- - Identifies a vSPC proxy service that provides network access to the I(service_uri).
+ - Identifies a vSPC proxy service that provides network access to the O(backings.service_uri).
- If you specify a proxy URI, the virtual machine initiates a connection with the proxy service
and forwards the serviceURI and direction to the proxy.
- - The C(Use Virtual Serial Port Concentrator) option is automatically enabled when I(proxy_uri) is set.
+ - The C(Use Virtual Serial Port Concentrator) option is automatically enabled when O(backings.proxy_uri) is set.
type: str
version_added: '3.7.0'
direction:
description:
- The direction of the connection.
- - Required when I(backing_type=network).
+ - Required when O(backings.backing_type=network).
type: str
choices:
- client
@@ -116,12 +116,12 @@ options:
device_name:
description:
- Serial device absolutely path.
- - Required when I(backing_type=device).
+ - Required when O(backings.backing_type=device).
type: str
file_path:
description:
- File path for the host file used in this backing. Fully qualified path is required, like <datastore_name>/<file_name>.
- - Required when I(backing_type=file).
+ - Required when O(backings.backing_type=file).
type: str
extends_documentation_fragment:
- community.vmware.vmware.documentation
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_guest_snapshot.py b/ansible_collections/community/vmware/plugins/modules/vmware_guest_snapshot.py
index 6e33d2b95..da0cf5565 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_guest_snapshot.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_guest_snapshot.py
@@ -23,21 +23,21 @@ options:
state:
description:
- Manage snapshot(s) attached to a specific virtual machine.
- - If set to C(present) and snapshot absent, then will create a new snapshot with the given name.
- - If set to C(present) and snapshot present, then no changes are made.
- - If set to C(absent) and snapshot present, then snapshot with the given name is removed.
- - If set to C(absent) and snapshot absent, then no changes are made.
- - If set to C(revert) and snapshot present, then virtual machine state is reverted to the given snapshot.
- - If set to C(revert) and snapshot absent, then no changes are made.
- - If set to C(remove_all) and snapshot(s) present, then all snapshot(s) will be removed.
- - If set to C(remove_all) and snapshot(s) absent, then no changes are made.
+ - If set to V(present) and snapshot absent, then will create a new snapshot with the given name.
+ - If set to V(present) and snapshot present, then no changes are made.
+ - If set to V(absent) and snapshot present, then snapshot with the given name is removed.
+ - If set to V(absent) and snapshot absent, then no changes are made.
+ - If set to V(revert) and snapshot present, then virtual machine state is reverted to the given snapshot.
+ - If set to V(revert) and snapshot absent, then no changes are made.
+ - If set to V(remove_all) and snapshot(s) present, then all snapshot(s) will be removed.
+ - If set to V(remove_all) and snapshot(s) absent, then no changes are made.
choices: ['present', 'absent', 'revert', 'remove_all']
default: 'present'
type: str
name:
description:
- Name of the virtual machine to work with.
- - This is required parameter, if C(uuid) or C(moid) is not supplied.
+ - This is required parameter, if O(uuid) or O(moid) is not supplied.
type: str
name_match:
description:
@@ -48,12 +48,12 @@ options:
uuid:
description:
- UUID of the instance to manage if known, this is VMware's BIOS UUID by default.
- - This is required if C(name) or C(moid) parameter is not supplied.
+ - This is required if O(name) or O(moid) parameter is not supplied.
type: str
moid:
description:
- Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.
- - This is required if C(name) or C(uuid) is not supplied.
+ - This is required if O(name) or O(uuid) is not supplied.
type: str
use_instance_uuid:
description:
@@ -63,7 +63,7 @@ options:
folder:
description:
- Destination folder, absolute or relative path to find an existing guest.
- - This is required parameter, if C(name) is supplied.
+ - This is required parameter, if O(name) is supplied.
- The folder should include the datacenter. ESX's datacenter is ha-datacenter.
- 'Examples:'
- ' folder: /ha-datacenter/vm'
@@ -84,8 +84,14 @@ options:
snapshot_name:
description:
- Sets the snapshot name to manage.
- - This param is required only if state is not C(remove_all)
+ - This param or O(snapshot_id) is required only if O(state) is not C(remove_all)
type: str
+ snapshot_id:
+ description:
+ - Sets the snapshot id to manage.
+ - This param is available when O(state=absent).
+ type: int
+ version_added: 3.10.0
description:
description:
- Define an arbitrary description to attach to snapshot.
@@ -93,24 +99,24 @@ options:
type: str
quiesce:
description:
- - If set to C(true) and virtual machine is powered on, it will quiesce the file system in virtual machine.
+ - If set to V(true) and virtual machine is powered on, it will quiesce the file system in virtual machine.
- Note that VMware Tools are required for this flag.
- - If virtual machine is powered off or VMware Tools are not available, then this flag is set to C(false).
- - If virtual machine does not provide capability to take quiesce snapshot, then this flag is set to C(false).
+ - If virtual machine is powered off or VMware Tools are not available, then this flag is set to V(false).
+ - If virtual machine does not provide capability to take quiesce snapshot, then this flag is set to V(false).
required: false
type: bool
default: false
memory_dump:
description:
- - If set to C(true), memory dump of virtual machine is also included in snapshot.
+ - If set to V(true), memory dump of virtual machine is also included in snapshot.
- Note that memory snapshots take time and resources, this will take longer time to create.
- - If virtual machine does not provide capability to take memory snapshot, then this flag is set to C(false).
+ - If virtual machine does not provide capability to take memory snapshot, then this flag is set to V(false).
required: false
type: bool
default: false
remove_children:
description:
- - If set to C(true) and state is set to C(absent), then entire snapshot subtree is set for removal.
+ - If set to V(true) and O(state=absent), then entire snapshot subtree is set for removal.
required: false
type: bool
default: false
@@ -214,6 +220,18 @@ EXAMPLES = r'''
snapshot_name: snap1
delegate_to: localhost
+ - name: Remove a snapshot with a snapshot id
+ community.vmware.vmware_guest_snapshot:
+ hostname: "{{ vcenter_hostname }}"
+ username: "{{ vcenter_username }}"
+ password: "{{ vcenter_password }}"
+ datacenter: "{{ datacenter_name }}"
+ folder: "/{{ datacenter_name }}/vm/"
+ name: "{{ guest_name }}"
+ snapshot_id: 10
+ state: absent
+ delegate_to: localhost
+
- name: Rename a snapshot
community.vmware.vmware_guest_snapshot:
hostname: "{{ vcenter_hostname }}"
@@ -293,6 +311,16 @@ class PyVmomiHelper(PyVmomi):
snap_obj = snap_obj + self.get_snapshots_by_name_recursively(snapshot.childSnapshotList, snapname)
return snap_obj
+ def get_snapshots_by_id_recursively(self, snapshots, snapid):
+ snap_obj = []
+ for snapshot in snapshots:
+ if snapshot.id == snapid:
+ snap_obj.append(snapshot)
+ else:
+ snap_obj = snap_obj + self.get_snapshots_by_id_recursively(snapshot.childSnapshotList, snapid)
+
+ return snap_obj
+
def snapshot_vm(self, vm):
memory_dump = False
quiesce = False
@@ -357,8 +385,13 @@ class PyVmomiHelper(PyVmomi):
self.module.exit_json(msg="virtual machine - %s doesn't have any"
" snapshots to remove." % vm_name)
- snap_obj = self.get_snapshots_by_name_recursively(vm.snapshot.rootSnapshotList,
- self.module.params["snapshot_name"])
+ if self.module.params["snapshot_name"]:
+ snap_obj = self.get_snapshots_by_name_recursively(vm.snapshot.rootSnapshotList,
+ self.module.params["snapshot_name"])
+ elif self.module.params["snapshot_id"]:
+ snap_obj = self.get_snapshots_by_id_recursively(vm.snapshot.rootSnapshotList,
+ self.module.params["snapshot_id"])
+
task = None
if len(snap_obj) == 1:
snap_obj = snap_obj[0].snapshot
@@ -414,6 +447,7 @@ def main():
folder=dict(type='str'),
datacenter=dict(required=True, type='str'),
snapshot_name=dict(type='str'),
+ snapshot_id=dict(type='int'),
description=dict(type='str', default=''),
quiesce=dict(type='bool', default=False),
memory_dump=dict(type='bool', default=False),
@@ -429,6 +463,9 @@ def main():
required_one_of=[
['name', 'uuid', 'moid']
],
+ mutually_exclusive=[
+ ['snapshot_name', 'snapshot_id']
+ ]
)
if module.params['folder']:
@@ -444,7 +481,7 @@ def main():
vm_id = (module.params.get('uuid') or module.params.get('name') or module.params.get('moid'))
module.fail_json(msg="Unable to manage snapshots for non-existing VM %s" % vm_id)
- if not module.params['snapshot_name'] and module.params['state'] != 'remove_all':
+ if not (module.params['snapshot_name'] or module.params['snapshot_id']) and module.params['state'] != 'remove_all':
module.fail_json(msg="snapshot_name param is required when state is '%(state)s'" % module.params)
result = pyv.apply_snapshot_op(vm)
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_guest_snapshot_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_guest_snapshot_info.py
index b408bb222..562dd3261 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_guest_snapshot_info.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_guest_snapshot_info.py
@@ -22,18 +22,18 @@ options:
name:
description:
- Name of the VM to work with.
- - This is required if C(uuid) or C(moid) is not supplied.
+ - This is required if O(uuid) or O(moid) is not supplied.
type: str
uuid:
description:
- UUID of the instance to manage if known, this is VMware's BIOS UUID by default.
- - This is required if C(name) or C(moid) parameter is not supplied.
- - The C(folder) is ignored, if C(uuid) is provided.
+ - This is required if O(name) or O(moid) parameter is not supplied.
+ - The O(folder) is ignored, if O(uuid) is provided.
type: str
moid:
description:
- Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.
- - This is required if C(name) or C(uuid) is not supplied.
+ - This is required if O(name) or O(uuid) is not supplied.
type: str
use_instance_uuid:
description:
@@ -43,7 +43,7 @@ options:
folder:
description:
- Destination folder, absolute or relative path to find an existing guest.
- - This is required parameter, if C(name) is supplied.
+ - This is required parameter, if O(name) is supplied.
- The folder should include the datacenter. ESX's datacenter is ha-datacenter
- 'Examples:'
- ' folder: /ha-datacenter/vm'
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_guest_storage_policy.py b/ansible_collections/community/vmware/plugins/modules/vmware_guest_storage_policy.py
index 362020c7e..2c855eac5 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_guest_storage_policy.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_guest_storage_policy.py
@@ -34,19 +34,19 @@ options:
name:
description:
- Name of the virtual machine.
- - One of C(name), C(uuid), or C(moid) are required to define the virtual machine.
+ - One of O(name), O(uuid), or O(moid) are required to define the virtual machine.
type: str
required: false
uuid:
description:
- UUID of the virtual machine.
- - One of C(name), C(uuid), or C(moid) are required to define the virtual machine.
+ - One of O(name), O(uuid), or O(moid) are required to define the virtual machine.
type: str
required: false
moid:
description:
- Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.
- - One of C(name), C(uuid), or C(moid) are required to define the virtual machine.
+ - One of O(name), O(uuid), or O(moid) are required to define the virtual machine.
type: str
required: false
folder:
@@ -70,14 +70,14 @@ options:
description:
- A storage profile policy to set on VM Home.
- All values and parameters are case sensitive.
- - At least one of C(disk) or C(vm_home) are required parameters.
+ - At least one of O(disk) or O(vm_home) are required parameters.
required: false
type: str
disk:
description:
- A list of disks with storage profile policies to enforce.
- All values and parameters are case sensitive.
- - At least one of C(disk) and C(vm_home) are required parameters.
+ - At least one of O(disk) and O(vm_home) are required parameters.
required: false
type: list
elements: dict
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_guest_tools_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_guest_tools_info.py
index 77c152474..e707cc82c 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_guest_tools_info.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_guest_tools_info.py
@@ -22,7 +22,7 @@ options:
name:
description:
- Name of the VM to get VMware tools info.
- - This is required if C(uuid) or C(moid) is not supplied.
+ - This is required if O(uuid) or O(moid) is not supplied.
type: str
name_match:
description:
@@ -33,7 +33,7 @@ options:
uuid:
description:
- UUID of the instance to manage if known, this is VMware's unique identifier.
- - This is required if C(name) or C(moid) is not supplied.
+ - This is required if O(name) or O(moid) is not supplied.
type: str
use_instance_uuid:
description:
@@ -43,7 +43,7 @@ options:
moid:
description:
- Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.
- - This is required if C(name) or C(uuid) is not supplied.
+ - This is required if O(name) or O(uuid) is not supplied.
type: str
folder:
description:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_guest_tools_upgrade.py b/ansible_collections/community/vmware/plugins/modules/vmware_guest_tools_upgrade.py
index 73ef09613..969eb4fd6 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_guest_tools_upgrade.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_guest_tools_upgrade.py
@@ -22,7 +22,7 @@ options:
name:
description:
- Name of the virtual machine to work with.
- - 'This is required if C(uuid) or C(moid) is not supplied.'
+ - 'This is required if O(uuid) or O(moid) is not supplied.'
type: str
name_match:
description:
@@ -33,17 +33,17 @@ options:
uuid:
description:
- "UUID of the instance to manage if known, this is VMware's unique identifier."
- - This is required if C(name) or C(moid) is not supplied.
+ - This is required if O(name) or O(moid) is not supplied.
type: str
moid:
description:
- Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.
- - This is required if C(name) or C(uuid) is not supplied.
+ - This is required if O(name) or O(uuid) is not supplied.
type: str
folder:
description:
- Destination folder, absolute or relative path to find an existing guest.
- - This is required, if C(name) is supplied.
+ - This is required, if O(name) is supplied.
- "The folder should include the datacenter. ESX's datacenter is ha-datacenter"
- 'Examples:'
- ' folder: /ha-datacenter/vm'
@@ -70,6 +70,12 @@ options:
default: false
type: bool
required: false
+ installer_options:
+ version_added: '4.1.0'
+ description:
+ - Command line options passed to the installer to modify the installation procedure for tools.
+ type: str
+ required: false
extends_documentation_fragment:
- community.vmware.vmware.documentation
@@ -151,8 +157,12 @@ class PyVmomiHelper(PyVmomi):
elif vm.guest.toolsStatus == "toolsOld":
try:
force = self.module.params.get('force_upgrade')
+ installer_options = self.module.params.get('installer_options')
if force or vm.guest.guestFamily in ["linuxGuest", "windowsGuest"]:
- task = vm.UpgradeTools()
+ if installer_options is not None:
+ task = vm.UpgradeTools(installer_options)
+ else:
+ task = vm.UpgradeTools()
changed, err_msg = wait_for_task(task)
result.update(changed=changed, msg=to_native(err_msg))
else:
@@ -182,6 +192,7 @@ def main():
folder=dict(type='str'),
datacenter=dict(type='str', required=True),
force_upgrade=dict(type='bool', default=False),
+ installer_options=dict(type='str'),
)
module = AnsibleModule(
argument_spec=argument_spec,
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_guest_tools_wait.py b/ansible_collections/community/vmware/plugins/modules/vmware_guest_tools_wait.py
index 58224b32c..13ed6c164 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_guest_tools_wait.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_guest_tools_wait.py
@@ -21,7 +21,7 @@ options:
name:
description:
- Name of the VM for which to wait until the tools become available.
- - This is required if C(uuid) or C(moid) is not supplied.
+ - This is required if O(uuid) or O(moid) is not supplied.
type: str
name_match:
description:
@@ -32,7 +32,7 @@ options:
folder:
description:
- Destination folder, absolute or relative path to find an existing guest.
- - This is required only, if multiple VMs with same C(name) is found.
+ - This is required only, if multiple VMs with same O(name) is found.
- The folder should include the datacenter. ESX's datacenter is C(ha-datacenter).
- 'Examples:'
- ' folder: /ha-datacenter/vm'
@@ -48,12 +48,12 @@ options:
uuid:
description:
- UUID of the VM for which to wait until the tools become available, if known. This is VMware's unique identifier.
- - This is required, if C(name) or C(moid) is not supplied.
+ - This is required, if O(name) or O(moid) is not supplied.
type: str
moid:
description:
- Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.
- - This is required if C(name) or C(uuid) is not supplied.
+ - This is required if O(name) or O(uuid) is not supplied.
type: str
use_instance_uuid:
description:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_guest_tpm.py b/ansible_collections/community/vmware/plugins/modules/vmware_guest_tpm.py
index 3ea74a86f..2b0178474 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_guest_tpm.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_guest_tpm.py
@@ -23,17 +23,17 @@ options:
name:
description:
- Name of the virtual machine.
- - This is required if parameter C(uuid) or C(moid) is not supplied.
+ - This is required if parameter O(uuid) or O(moid) is not supplied.
type: str
uuid:
description:
- UUID of the instance to manage if known, this is VMware's unique identifier.
- - This is required if parameter C(name) or C(moid) is not supplied.
+ - This is required if parameter O(name) or O(moid) is not supplied.
type: str
moid:
description:
- Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.
- - This is required if C(name) or C(uuid) is not supplied.
+ - This is required if O(name) or O(uuid) is not supplied.
type: str
folder:
description:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_guest_vgpu.py b/ansible_collections/community/vmware/plugins/modules/vmware_guest_vgpu.py
index 835f9d186..1c8557681 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_guest_vgpu.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_guest_vgpu.py
@@ -25,17 +25,17 @@ options:
name:
description:
- Name of the virtual machine.
- - This is a required parameter, if parameter C(uuid) or C(moid) is not supplied.
+ - This is a required parameter, if parameter O(uuid) or O(moid) is not supplied.
type: str
uuid:
description:
- UUID of the instance to gather facts if known, this is VMware's unique identifier.
- - This is a required parameter, if parameter C(name) or C(moid) is not supplied.
+ - This is a required parameter, if parameter O(name) or O(moid) is not supplied.
type: str
moid:
description:
- Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.
- - This is required if C(name) or C(uuid) is not supplied.
+ - This is required if O(name) or O(uuid) is not supplied.
type: str
folder:
description:
@@ -64,8 +64,8 @@ options:
choices: [ 'present', 'absent' ]
description:
- vGPU profile state.
- - When C(state=present), the selected vGPU profile will be added if the VM hosted ESXi host NVIDIA GPU offer it.
- - When C(state=absent), the selected vGPU profile gets removed from the VM.
+ - When V(present), the selected vGPU profile will be added if the VM hosted ESXi host NVIDIA GPU offer it.
+ - When V(absent), the selected vGPU profile gets removed from the VM.
type: str
vgpu:
description:
@@ -91,7 +91,6 @@ options:
type: str
extends_documentation_fragment:
- community.vmware.vmware.documentation
-version_added: '2.5.0'
"""
EXAMPLES = r"""
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_guest_vgpu_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_guest_vgpu_info.py
index 9dc12eea7..090c71588 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_guest_vgpu_info.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_guest_vgpu_info.py
@@ -24,17 +24,17 @@ options:
name:
description:
- Name of the virtual machine.
- - This is a required parameter, if parameter C(uuid) or C(moid) is not supplied.
+ - This is a required parameter, if parameter O(uuid) or O(moid) is not supplied.
type: str
uuid:
description:
- UUID of the instance to gather facts if known, this is VMware's unique identifier.
- - This is a required parameter, if parameter C(name) or C(moid) is not supplied.
+ - This is a required parameter, if parameter O(name) or O(moid) is not supplied.
type: str
moid:
description:
- Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.
- - This is required if C(name) or C(uuid) is not supplied.
+ - This is required if O(name) or O(uuid) is not supplied.
type: str
folder:
description:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_guest_video.py b/ansible_collections/community/vmware/plugins/modules/vmware_guest_video.py
index 253a1ac74..de5e4c628 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_guest_video.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_guest_video.py
@@ -23,17 +23,17 @@ options:
name:
description:
- Name of the virtual machine.
- - This is a required parameter, if parameter C(uuid) or C(moid) is not supplied.
+ - This is a required parameter, if parameter O(uuid) or O(moid) is not supplied.
type: str
uuid:
description:
- UUID of the instance to gather facts if known, this is VMware's unique identifier.
- - This is a required parameter, if parameter C(name) or C(moid) is not supplied.
+ - This is a required parameter, if parameter O(name) or O(moid) is not supplied.
type: str
moid:
description:
- Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.
- - This is required if C(name) or C(uuid) is not supplied.
+ - This is required if O(name) or O(uuid) is not supplied.
type: str
folder:
description:
@@ -59,14 +59,14 @@ options:
type: str
gather_video_facts:
description:
- - If set to C(true), return settings of the video card, other attributes are ignored.
- - If set to C(false), will do reconfiguration and return video card settings.
+ - If set to V(true), return settings of the video card, other attributes are ignored.
+ - If set to V(false), will do reconfiguration and return video card settings.
type: bool
default: false
use_auto_detect:
description:
- - 'If set to C(true), applies common video settings to the guest operating system, attributes C(display_number) and C(video_memory_mb) are ignored.'
- - 'If set to C(false), the number of display and the total video memory will be reconfigured using C(display_number) and C(video_memory_mb).'
+ - 'If set to V(true), applies common video settings to the guest operating system, attributes O(display_number) and O(video_memory_mb) are ignored.'
+ - 'If set to V(false), the number of display and the total video memory will be reconfigured using O(display_number) and O(video_memory_mb).'
type: bool
display_number:
description:
@@ -84,9 +84,9 @@ options:
type: bool
renderer_3D:
description:
- - 'If set to C(automatic), selects the appropriate option (software or hardware) for this virtual machine automatically.'
- - 'If set to C(software), uses normal CPU processing for 3D calculations.'
- - 'If set to C(hardware), requires graphics hardware (GPU) for faster 3D calculations.'
+ - 'If set to V(automatic), selects the appropriate option (software or hardware) for this virtual machine automatically.'
+ - 'If set to V(software), uses normal CPU processing for 3D calculations.'
+ - 'If set to V(hardware), requires graphics hardware (GPU) for faster 3D calculations.'
choices: [ automatic, software, hardware ]
type: str
memory_3D_mb:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host.py b/ansible_collections/community/vmware/plugins/modules/vmware_host.py
index 284d50ea8..d5b586b32 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_host.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host.py
@@ -27,32 +27,30 @@ options:
datacenter_name:
description:
- Name of the datacenter to add the host.
- - Aliases added in version 2.6.
required: true
aliases: ['datacenter']
type: str
cluster_name:
description:
- Name of the cluster to add the host.
- - If C(folder) is not set, then this parameter is required.
- - Aliases added in version 2.6.
+ - If O(folder) is not set, then this parameter is required.
aliases: ['cluster']
type: str
folder:
description:
- Name of the folder under which host to add.
- - If C(cluster_name) is not set, then this parameter is required.
+ - If O(cluster_name) is not set, then this parameter is required.
- "For example, if there is a datacenter 'dc1' under folder called 'Site1' then, this value will be '/Site1/dc1/host'."
- "Here 'host' is an invisible folder under VMware Web Client."
- "Another example, if there is a nested folder structure like '/myhosts/india/pune' under
- datacenter 'dc2', then C(folder) value will be '/dc2/host/myhosts/india/pune'."
+ datacenter 'dc2', then O(folder) value will be '/dc2/host/myhosts/india/pune'."
- "Other Examples: '/Site2/dc2/Asia-Cluster/host' or '/dc3/Asia-Cluster/host'"
aliases: ['folder_name']
type: str
add_connected:
description:
- - If set to C(true), then the host should be connected as soon as it is added.
- - This parameter is ignored if state is set to a value other than C(present).
+ - If set to V(true), then the host should be connected as soon as it is added.
+ - This parameter is ignored if not O(state=present).
default: true
type: bool
esxi_hostname:
@@ -64,7 +62,7 @@ options:
description:
- ESXi username.
- Required for adding a host.
- - Optional for reconnect. If both C(esxi_username) and C(esxi_password) are used
+ - Optional for reconnect. If both O(esxi_username) and O(esxi_password) are used
- Unused for removing.
- No longer a required parameter from version 2.5.
type: str
@@ -78,13 +76,13 @@ options:
type: str
state:
description:
- - If set to C(present), add the host if host is absent.
- - If set to C(present), update the location of the host if host already exists.
- - If set to C(absent), remove the host if host is present.
- - If set to C(absent), do nothing if host already does not exists.
- - If set to C(add_or_reconnect), add the host if it's absent else reconnect it and update the location.
- - If set to C(reconnect), then reconnect the host if it's present and update the location.
- - If set to C(disconnected), disconnect the host if the host already exists.
+ - If set to V(present), add the host if host is absent.
+ - If set to V(present), update the location of the host if host already exists.
+ - If set to V(absent), remove the host if host is present.
+ - If set to V(absent), do nothing if host already does not exists.
+ - If set to V(add_or_reconnect), add the host if it's absent else reconnect it and update the location.
+ - If set to V(reconnect), then reconnect the host if it's present and update the location.
+ - If set to V(disconnected), disconnect the host if the host already exists.
default: present
choices: ['present', 'absent', 'add_or_reconnect', 'reconnect', 'disconnected']
type: str
@@ -93,7 +91,6 @@ options:
- "Specifying the hostsystem certificate's thumbprint."
- "Use following command to get hostsystem certificate's thumbprint - "
- "# openssl x509 -in /etc/vmware/ssl/rui.crt -fingerprint -sha1 -noout"
- - Only used if C(fetch_thumbprint) isn't set to C(true).
default: ''
type: str
aliases: ['ssl_thumbprint']
@@ -102,9 +99,9 @@ options:
- Fetch the thumbprint of the host's SSL certificate.
- This basically disables the host certificate verification (check if it was signed by a recognized CA).
- Disable this option if you want to allow only hosts with valid certificates to be added to vCenter.
- - If this option is set to C(false) and the certificate can't be verified, an add or reconnect will fail.
- - Unused when C(esxi_ssl_thumbprint) is set.
- - Optional for reconnect, but only used if C(esxi_username) and C(esxi_password) are used.
+ - If this option is set to V(false) and the certificate can't be verified, an add or reconnect will fail.
+ - Unused when O(esxi_ssl_thumbprint) is set.
+ - Optional for reconnect, but only used if O(esxi_username) and O(esxi_password) are used.
- Unused for removing.
type: bool
default: true
@@ -116,7 +113,7 @@ options:
reconnect_disconnected:
description:
- Reconnect disconnected hosts.
- - This is only used if C(state) is set to C(present) and if the host already exists.
+ - This is only used if O(state=present) and if the host already exists.
type: bool
default: true
extends_documentation_fragment:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host_acceptance.py b/ansible_collections/community/vmware/plugins/modules/vmware_host_acceptance.py
index bbc989e02..92dc98328 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_host_acceptance.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host_acceptance.py
@@ -23,32 +23,22 @@ options:
description:
- Name of the cluster.
- Acceptance level of all ESXi host system in the given cluster will be managed.
- - If C(esxi_hostname) is not given, this parameter is required.
+ - If O(esxi_hostname) is not given, this parameter is required.
type: str
esxi_hostname:
description:
- ESXi hostname.
- Acceptance level of this ESXi host system will be managed.
- - If C(cluster_name) is not given, this parameter is required.
+ - If O(cluster_name) is not given, this parameter is required.
type: str
state:
description:
- - Set or list acceptance level of the given ESXi host.
- - 'If set to C(list), then will return current acceptance level of given host system/s.'
- - If set to C(present), then will set given acceptance level.
- choices: [ list, present ]
- required: false
- default: 'list'
- type: str
- acceptance_level:
- description:
- - Name of acceptance level.
- - If set to C(partner), then accept only partner and VMware signed and certified VIBs.
- - If set to C(vmware_certified), then accept only VIBs that are signed and certified by VMware.
- - If set to C(vmware_accepted), then accept VIBs that have been accepted by VMware.
- - If set to C(community), then accept all VIBs, even those that are not signed.
+ - If set to V(partner), then accept only partner and VMware signed and certified VIBs.
+ - If set to V(vmware_certified), then accept only VIBs that are signed and certified by VMware.
+ - If set to V(vmware_accepted), then accept VIBs that have been accepted by VMware.
+ - If set to V(community), then accept all VIBs, even those that are not signed.
choices: [ community, partner, vmware_accepted, vmware_certified ]
- required: false
+ required: true
type: str
extends_documentation_fragment:
- community.vmware.vmware.documentation
@@ -62,8 +52,7 @@ EXAMPLES = r'''
username: '{{ vcenter_username }}'
password: '{{ vcenter_password }}'
cluster_name: cluster_name
- acceptance_level: 'community'
- state: present
+ state: 'community'
delegate_to: localhost
register: cluster_acceptance_level
@@ -73,18 +62,7 @@ EXAMPLES = r'''
username: '{{ vcenter_username }}'
password: '{{ vcenter_password }}'
esxi_hostname: '{{ esxi_hostname }}'
- acceptance_level: 'vmware_accepted'
- state: present
- delegate_to: localhost
- register: host_acceptance_level
-
-- name: Get acceptance level from the given ESXi Host
- community.vmware.vmware_host_acceptance:
- hostname: '{{ vcenter_hostname }}'
- username: '{{ vcenter_username }}'
- password: '{{ vcenter_password }}'
- esxi_hostname: '{{ esxi_hostname }}'
- state: list
+ state: 'vmware_accepted'
delegate_to: localhost
register: host_acceptance_level
'''
@@ -115,9 +93,9 @@ class VMwareAccpetanceManager(PyVmomi):
self.hosts = self.get_all_host_objs(cluster_name=cluster_name, esxi_host_name=esxi_host_name)
self.desired_state = self.params.get('state')
self.hosts_facts = {}
- self.acceptance_level = self.params.get('acceptance_level')
- def gather_acceptance_facts(self):
+ def set_acceptance_level(self):
+ change = []
for host in self.hosts:
self.hosts_facts[host.name] = dict(level='', error='NA')
host_image_config_mgr = host.configManager.imageConfigManager
@@ -126,45 +104,31 @@ class VMwareAccpetanceManager(PyVmomi):
self.hosts_facts[host.name]['level'] = host_image_config_mgr.HostImageConfigGetAcceptance()
except vim.fault.HostConfigFault as e:
self.hosts_facts[host.name]['error'] = to_native(e.msg)
-
- def set_acceptance_level(self):
- change = []
- for host in self.hosts:
host_changed = False
- if self.hosts_facts[host.name]['level'] != self.acceptance_level:
- host_image_config_mgr = host.configManager.imageConfigManager
- if host_image_config_mgr:
- try:
- if self.module.check_mode:
- self.hosts_facts[host.name]['level'] = self.acceptance_level
- else:
- host_image_config_mgr.UpdateHostImageAcceptanceLevel(newAcceptanceLevel=self.acceptance_level)
- self.hosts_facts[host.name]['level'] = host_image_config_mgr.HostImageConfigGetAcceptance()
- host_changed = True
- except vim.fault.HostConfigFault as e:
- self.hosts_facts[host.name]['error'] = to_native(e.msg)
+ if self.hosts_facts[host.name]['level'] != self.desired_state:
+ try:
+ if self.module.check_mode:
+ self.hosts_facts[host.name]['level'] = self.desired_state
+ else:
+ host_image_config_mgr.UpdateHostImageAcceptanceLevel(newAcceptanceLevel=self.desired_state)
+ self.hosts_facts[host.name]['level'] = host_image_config_mgr.HostImageConfigGetAcceptance()
+ host_changed = True
+ except vim.fault.HostConfigFault as e:
+ self.hosts_facts[host.name]['error'] = to_native(e.msg)
change.append(host_changed)
self.module.exit_json(changed=any(change), facts=self.hosts_facts)
- def check_acceptance_state(self):
- self.gather_acceptance_facts()
- if self.desired_state == 'list':
- self.module.exit_json(changed=False, facts=self.hosts_facts)
- self.set_acceptance_level()
-
def main():
argument_spec = vmware_argument_spec()
argument_spec.update(
cluster_name=dict(type='str', required=False),
esxi_hostname=dict(type='str', required=False),
- acceptance_level=dict(type='str',
- choices=['community', 'partner', 'vmware_accepted', 'vmware_certified']
- ),
state=dict(type='str',
- choices=['list', 'present'],
- default='list'),
+ choices=['community', 'partner', 'vmware_accepted', 'vmware_certified'],
+ required=True
+ ),
)
module = AnsibleModule(
@@ -172,14 +136,11 @@ def main():
required_one_of=[
['cluster_name', 'esxi_hostname'],
],
- required_if=[
- ['state', 'present', ['acceptance_level']],
- ],
supports_check_mode=True
)
vmware_host_accept_config = VMwareAccpetanceManager(module)
- vmware_host_accept_config.check_acceptance_state()
+ vmware_host_accept_config.set_acceptance_level()
if __name__ == "__main__":
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host_acceptance_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_host_acceptance_info.py
new file mode 100644
index 000000000..03308c975
--- /dev/null
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host_acceptance_info.py
@@ -0,0 +1,110 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2018, Abhijeet Kasurde <akasurde@redhat.com>
+# Copyright: (c) 2023, Mario Lenz <m@riolenz.de>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+
+DOCUMENTATION = r'''
+---
+module: vmware_host_acceptance_info
+short_description: Gather host acceptance level of ESXi hosts
+description:
+- This module can be used to gather the host acceptance level of ESXi hosts.
+- The host acceptance level controls the acceptance level of each VIB on a ESXi host.
+author:
+- Abhijeet Kasurde (@Akasurde)
+- Mario Lenz (@mariolenz)
+options:
+ cluster_name:
+ description:
+ - Name of the cluster.
+ - Acceptance level of all ESXi host system in the given cluster will be gathered.
+ - If O(esxi_hostname) is not given, this parameter is required.
+ type: str
+ esxi_hostname:
+ description:
+ - ESXi hostname.
+ - Acceptance level of this ESXi host system will be gathered.
+ - If O(cluster_name) is not given, this parameter is required.
+ type: str
+extends_documentation_fragment:
+- community.vmware.vmware.documentation
+
+'''
+
+EXAMPLES = r'''
+- name: Get acceptance level from the given ESXi Host
+ community.vmware.vmware_host_acceptance_info:
+ hostname: '{{ vcenter_hostname }}'
+ username: '{{ vcenter_username }}'
+ password: '{{ vcenter_password }}'
+ esxi_hostname: '{{ esxi_hostname }}'
+ delegate_to: localhost
+ register: host_acceptance_level
+'''
+
+RETURN = r'''
+host_acceptance_info:
+ description:
+ - dict with hostname as key and dict with acceptance level facts, error as value
+ returned: facts
+ type: dict
+ sample: { "facts": { "localhost.localdomain": { "error": "NA", "level": "vmware_certified" }}}
+'''
+
+try:
+ from pyVmomi import vim
+except ImportError:
+ pass
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.community.vmware.plugins.module_utils.vmware import vmware_argument_spec, PyVmomi
+from ansible.module_utils._text import to_native
+
+
+class VMwareAccpetanceManager(PyVmomi):
+ def __init__(self, module):
+ super(VMwareAccpetanceManager, self).__init__(module)
+ cluster_name = self.params.get('cluster_name', None)
+ esxi_host_name = self.params.get('esxi_hostname', None)
+ self.hosts = self.get_all_host_objs(cluster_name=cluster_name, esxi_host_name=esxi_host_name)
+ self.hosts_facts = {}
+
+ def gather_acceptance_info(self):
+ for host in self.hosts:
+ self.hosts_facts[host.name] = dict(level='', error='NA')
+ host_image_config_mgr = host.configManager.imageConfigManager
+ if host_image_config_mgr:
+ try:
+ self.hosts_facts[host.name]['level'] = host_image_config_mgr.HostImageConfigGetAcceptance()
+ except vim.fault.HostConfigFault as e:
+ self.hosts_facts[host.name]['error'] = to_native(e.msg)
+ self.module.exit_json(changed=False, host_acceptance_info=self.hosts_facts)
+
+
+def main():
+ argument_spec = vmware_argument_spec()
+ argument_spec.update(
+ cluster_name=dict(type='str', required=False),
+ esxi_hostname=dict(type='str', required=False),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_one_of=[
+ ['cluster_name', 'esxi_hostname'],
+ ],
+ supports_check_mode=True
+ )
+
+ vmware_host_accept_config = VMwareAccpetanceManager(module)
+ vmware_host_accept_config.gather_acceptance_info()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host_active_directory.py b/ansible_collections/community/vmware/plugins/modules/vmware_host_active_directory.py
index bc0c4a479..b6b205c2e 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_host_active_directory.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host_active_directory.py
@@ -44,12 +44,12 @@ options:
esxi_hostname:
description:
- Name of the host system to work with.
- - This parameter is required if C(cluster_name) is not specified.
+ - This parameter is required if O(cluster_name) is not specified.
type: str
cluster_name:
description:
- Name of the cluster from which all host systems will be used.
- - This parameter is required if C(esxi_hostname) is not specified.
+ - This parameter is required if O(esxi_hostname) is not specified.
type: str
extends_documentation_fragment:
- community.vmware.vmware.documentation
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host_auto_start.py b/ansible_collections/community/vmware/plugins/modules/vmware_host_auto_start.py
index 2aafc1ab6..4109066de 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_host_auto_start.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host_auto_start.py
@@ -30,7 +30,7 @@ options:
uuid:
description:
- VM uuid to set auto power on or off, this is VMware's unique identifier.
- - This is required if C(name) is not supplied.
+ - This is required if O(name) is not supplied.
- This is not necessary if change only system default VM settings for autoStart config.
type: str
use_instance_uuid:
@@ -41,7 +41,7 @@ options:
moid:
description:
- Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.
- - This is required if C(name) or C(uuid) is not supplied.
+ - This is required if O(name) or O(uuid) is not supplied.
type: str
system_defaults:
description:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host_capability_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_host_capability_info.py
index 30d0864a1..ac6030cba 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_host_capability_info.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host_capability_info.py
@@ -21,12 +21,12 @@ options:
cluster_name:
description:
- Name of the cluster from all host systems to be used for information gathering.
- - If C(esxi_hostname) is not given, this parameter is required.
+ - If O(esxi_hostname) is not given, this parameter is required.
type: str
esxi_hostname:
description:
- ESXi hostname to gather information from.
- - If C(cluster_name) is not given, this parameter is required.
+ - If O(cluster_name) is not given, this parameter is required.
type: str
extends_documentation_fragment:
- community.vmware.vmware.documentation
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host_config_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_host_config_info.py
index bea73acb0..49796818d 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_host_config_info.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host_config_info.py
@@ -21,12 +21,12 @@ options:
cluster_name:
description:
- Name of the cluster from which the ESXi host belong to.
- - If C(esxi_hostname) is not given, this parameter is required.
+ - If O(esxi_hostname) is not given, this parameter is required.
type: str
esxi_hostname:
description:
- ESXi hostname to gather information from.
- - If C(cluster_name) is not given, this parameter is required.
+ - If O(cluster_name) is not given, this parameter is required.
type: str
extends_documentation_fragment:
- community.vmware.vmware.documentation
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host_config_manager.py b/ansible_collections/community/vmware/plugins/modules/vmware_host_config_manager.py
index 3fe91ab80..1c331631f 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_host_config_manager.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host_config_manager.py
@@ -22,13 +22,13 @@ options:
description:
- Name of the cluster.
- Settings are applied to every ESXi host in given cluster.
- - If C(esxi_hostname) is not given, this parameter is required.
+ - If O(esxi_hostname) is not given, this parameter is required.
type: str
esxi_hostname:
description:
- ESXi hostname.
- Settings are applied to this ESXi host.
- - If C(cluster_name) is not given, this parameter is required.
+ - If O(cluster_name) is not given, this parameter is required.
type: str
options:
description:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host_custom_attributes.py b/ansible_collections/community/vmware/plugins/modules/vmware_host_custom_attributes.py
index 31cb3d427..7285e322c 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_host_custom_attributes.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host_custom_attributes.py
@@ -26,15 +26,15 @@ options:
state:
description:
- The action to take.
- - If set to C(present), then custom attribute is added or updated.
- - If set to C(absent), then custom attribute is removed.
+ - If set to V(present), then custom attribute is added or updated.
+ - If set to V(absent), then custom attribute is removed.
default: 'present'
choices: ['present', 'absent']
type: str
attributes:
description:
- A list of name and value of custom attributes that needs to be manage.
- - Value of custom attribute is not required and will be ignored, if C(state) is set to C(absent).
+ - Value of custom attribute is not required and will be ignored, if O(state=absent).
suboptions:
name:
description:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host_datastore.py b/ansible_collections/community/vmware/plugins/modules/vmware_host_datastore.py
index 3d28aa184..db8b9be91 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_host_datastore.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host_datastore.py
@@ -2,6 +2,7 @@
# -*- coding: utf-8 -*-
# Copyright: (c) 2018, Ansible Project
+# Copyright: (c) 2023, Pure Storage, Inc.
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
@@ -21,6 +22,7 @@ description:
author:
- Ludovic Rivallain (@lrivallain) <ludovic.rivallain@gmail.com>
- Christian Kotte (@ckotte) <christian.kotte@gmx.de>
+- Eugenio Grosso (@genegr) <eugenio.grosso@purestorage.com>
notes:
- Kerberos authentication with NFS v4.1 isn't implemented
options:
@@ -31,36 +33,49 @@ options:
type: str
datastore_type:
description:
- - Type of the datastore to configure (nfs/nfs41/vmfs).
- choices: [ 'nfs', 'nfs41', 'vmfs' ]
+ - Type of the datastore to configure (nfs/nfs41/vmfs/vvol).
+ choices: [ 'nfs', 'nfs41', 'vmfs', 'vvol' ]
type: str
nfs_server:
description:
- NFS host serving nfs datastore.
- - Required if datastore type is set to C(nfs)/C(nfs41) and state is set to C(present), else unused.
- - Two or more servers can be defined if datastore type is set to C(nfs41)
+ - Required if O(datastore_type=nfs) / O(datastore_type=nfs41) and O(state=present), else unused.
+ - Two or more servers can be defined if O(datastore_type=nfs41)
type: str
nfs_path:
description:
- Resource path on NFS host.
- - Required if datastore type is set to C(nfs)/C(nfs41) and state is set to C(present), else unused.
+ - Required if O(datastore_type=nfs) / O(datastore_type=nfs41) and O(state=present), else unused.
type: str
nfs_ro:
description:
- ReadOnly or ReadWrite mount.
- - Unused if datastore type is not set to C(nfs)/C(nfs41) and state is not set to C(present).
+ - Unused if datastore type is not set to O(datastore_type=nfs) / O(datastore_type=nfs41) and not O(state=present).
default: false
type: bool
+ resignature:
+ description:
+ - Allows forcing resignature of unresolved VMFS datastore that already exists on the specified disk device.
+ - Unused if not O(datastore_type=vmfs) and not O(state=present).
+ default: false
+ type: bool
+ version_added: '3.9.0'
vmfs_device_name:
description:
- Name of the device to be used as VMFS datastore.
- - Required for VMFS datastore type and state is set to C(present), else unused.
+ - Required for VMFS datastore type and O(state=present), else unused.
type: str
vmfs_version:
description:
- VMFS version to use for datastore creation.
- - Unused if datastore type is not set to C(vmfs) and state is not set to C(present).
+ - Unused if not O(datastore_type=vmfs) and not O(state=present).
type: int
+ vasa_provider:
+ description:
+ - hostname or ipaddress of the VASA provider to use for vVols provisioning
+ type: str
+ required: false
+ version_added: '3.9.0'
esxi_hostname:
description:
- ESXi hostname to manage the datastore.
@@ -71,7 +86,7 @@ options:
description:
- Expand a datastore capacity to full if it has free capacity.
- This parameter can't be extend using another datastore.
- - A use case example in I(auto_expand), it can be used to expand a datastore capacity after increasing LUN volume.
+ - Can be used to expand a datastore capacity after increasing LUN volume.
type: bool
default: true
state:
@@ -134,6 +149,31 @@ EXAMPLES = r'''
- { 'name': 'NasDS_vol03', 'server': 'nas01,nas02', 'path': '/mnt/vol01', 'type': 'nfs41'}
- { 'name': 'NasDS_vol04', 'server': 'nas01,nas02', 'path': '/mnt/vol02', 'type': 'nfs41'}
+- name: Mount vVols datastore to ESXi
+ community.vmware.vmware_host_datastore:
+ hostname: '{{ vcenter_hostname }}'
+ username: '{{ vcenter_username }}'
+ password: '{{ vcenter_password }}'
+ datastore_name: myvvolds
+ datastore_type: vvol
+ vasa_provider: pure-X90a
+ esxi_hostname: esxi-1
+ state: absent
+ delegate_to: localhost
+
+- name: Mount unresolved VMFS datastores to ESXi
+ community.vmware.vmware_host_datastore:
+ hostname: '{{ vcenter_hostname }}'
+ username: '{{ vcenter_username }}'
+ password: '{{ vcenter_password }}'
+ datastore_name: mydatastore01
+ vmfs_device_name: 'naa.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
+ vmfs_version: 6
+ esxi_hostname: esxi01
+ resignature: true
+ state: present
+ delegate_to: localhost
+
- name: Remove/Umount Datastores from a ESXi
community.vmware.vmware_host_datastore:
hostname: '{{ esxi_hostname }}'
@@ -153,11 +193,12 @@ except ImportError:
pass
from ansible.module_utils.basic import AnsibleModule
-from ansible_collections.community.vmware.plugins.module_utils.vmware import vmware_argument_spec, PyVmomi, find_datastore_by_name, find_obj
+from ansible_collections.community.vmware.plugins.module_utils.vmware import vmware_argument_spec, find_datastore_by_name, find_obj, wait_for_task
+from ansible_collections.community.vmware.plugins.module_utils.vmware_sms import SMS
from ansible.module_utils._text import to_native
-class VMwareHostDatastore(PyVmomi):
+class VMwareHostDatastore(SMS):
def __init__(self, module):
super(VMwareHostDatastore, self).__init__(module)
@@ -167,7 +208,9 @@ class VMwareHostDatastore(PyVmomi):
self.nfs_path = module.params['nfs_path']
self.nfs_ro = module.params['nfs_ro']
self.vmfs_device_name = module.params['vmfs_device_name']
+ self.vasa_provider_name = module.params['vasa_provider']
self.vmfs_version = module.params['vmfs_version']
+ self.resignature = module.params['resignature']
self.esxi_hostname = module.params['esxi_hostname']
self.auto_expand = module.params['auto_expand']
self.state = module.params['state']
@@ -264,6 +307,8 @@ class VMwareHostDatastore(PyVmomi):
self.mount_nfs_datastore_host()
if self.datastore_type == 'vmfs':
self.mount_vmfs_datastore_host()
+ if self.datastore_type == 'vvol':
+ self.mount_vvol_datastore_host()
def mount_nfs_datastore_host(self):
if self.module.check_mode is False:
@@ -308,13 +353,27 @@ class VMwareHostDatastore(PyVmomi):
self.module.fail_json(msg="%s" % error_message_used_disk)
error_message_mount = "Cannot mount datastore %s on host %s" % (self.datastore_name, self.esxi.name)
try:
- vmfs_ds_options = ds_system.QueryVmfsDatastoreCreateOptions(host_ds_system,
- ds_path,
- self.vmfs_version)
- vmfs_ds_options[0].spec.vmfs.volumeName = self.datastore_name
- ds_system.CreateVmfsDatastore(
- host_ds_system,
- vmfs_ds_options[0].spec)
+ if self.resignature:
+ storage_system = self.esxi.configManager.storageSystem
+ host_unres_volumes = storage_system.QueryUnresolvedVmfsVolume()
+ unres_vol_extents = {}
+ for unres_vol in host_unres_volumes:
+ for ext in unres_vol.extent:
+ unres_vol_extents[ext.device.diskName] = ext
+ if self.vmfs_device_name in unres_vol_extents:
+ spec = vim.host.UnresolvedVmfsResignatureSpec()
+ spec.extentDevicePath = unres_vol_extents[self.vmfs_device_name].devicePath
+ task = host_ds_system.ResignatureUnresolvedVmfsVolume_Task(spec)
+ wait_for_task(task=task)
+ task.info.result.result.RenameDatastore(self.datastore_name)
+ else:
+ vmfs_ds_options = ds_system.QueryVmfsDatastoreCreateOptions(host_ds_system,
+ ds_path,
+ self.vmfs_version)
+ vmfs_ds_options[0].spec.vmfs.volumeName = self.datastore_name
+ ds_system.CreateVmfsDatastore(
+ host_ds_system,
+ vmfs_ds_options[0].spec)
except (vim.fault.NotFound, vim.fault.DuplicateName,
vim.fault.HostConfigFault, vmodl.fault.InvalidArgument) as fault:
self.module.fail_json(msg="%s : %s" % (error_message_mount, to_native(fault.msg)))
@@ -322,19 +381,53 @@ class VMwareHostDatastore(PyVmomi):
self.module.fail_json(msg="%s : %s" % (error_message_mount, to_native(e)))
self.module.exit_json(changed=True, result="Datastore %s on host %s" % (self.datastore_name, self.esxi.name))
+ def mount_vvol_datastore_host(self):
+ if self.module.check_mode is False:
+ self.get_sms_connection()
+ storage_manager = self.sms_si.QueryStorageManager()
+ container_result = storage_manager.QueryStorageContainer()
+ provider = None
+ for p in container_result.providerInfo:
+ if p.name == self.vasa_provider_name:
+ provider = p
+ break
+ if provider is None:
+ error_message_provider = "VASA provider %s not found" % self.vasa_provider_name
+ self.module.fail_json(msg="%s" % error_message_provider)
+
+ container = None
+ for sc in container_result.storageContainer:
+ if sc.providerId[0] == provider.uid:
+ container = sc
+ break
+ if container is None:
+ error_message_container = "vVol container for provider %s not found" % provider.uid
+ self.module.fail_json(msg="%s" % error_message_container)
+
+ vvol_spec = vim.HostDatastoreSystem.VvolDatastoreSpec(name=self.datastore_name, scId=container.uuid)
+ host_ds_system = self.esxi.configManager.datastoreSystem
+ error_message_mount = "Cannot mount datastore %s on host %s" % (self.datastore_name, self.esxi.name)
+ try:
+ host_ds_system.CreateVvolDatastore(vvol_spec)
+ except Exception as e:
+ self.module.fail_json(msg="%s : %s" % (error_message_mount, to_native(e)))
+ self.module.exit_json(changed=True, result="Datastore %s on host %s" % (self.datastore_name, self.esxi.name))
+
def main():
argument_spec = vmware_argument_spec()
argument_spec.update(
datastore_name=dict(type='str', required=True),
- datastore_type=dict(type='str', choices=['nfs', 'nfs41', 'vmfs']),
+ datastore_type=dict(type='str', choices=['nfs', 'nfs41', 'vmfs', 'vvol']),
nfs_server=dict(type='str'),
nfs_path=dict(type='str'),
nfs_ro=dict(type='bool', default=False),
vmfs_device_name=dict(type='str'),
vmfs_version=dict(type='int'),
+ resignature=dict(type='bool', default=False),
esxi_hostname=dict(type='str', required=False),
auto_expand=dict(type='bool', default=True),
+ vasa_provider=dict(type='str'),
state=dict(type='str', default='present', choices=['absent', 'present'])
)
@@ -346,6 +439,7 @@ def main():
['datastore_type', 'vmfs', ['vmfs_device_name']],
['datastore_type', 'nfs', ['nfs_server', 'nfs_path']],
['datastore_type', 'nfs41', ['nfs_server', 'nfs_path']],
+ ['datastore_type', 'vvol', ['vasa_provider']],
]
)
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host_disk_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_host_disk_info.py
index 2ba105928..117751d98 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_host_disk_info.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host_disk_info.py
@@ -14,20 +14,20 @@ module: vmware_host_disk_info
short_description: Gathers information about disks attached to given ESXi host/s.
description:
- This module returns information about disks attached to given ESXi host/s
-- If I(cluster_name) is provided, then disk information about all hosts from the given cluster will be returned.
-- If I(esxi_hostname) is provided, then disk information about the given host system will be returned.
+- If O(cluster_name) is provided, then disk information about all hosts from the given cluster will be returned.
+- If O(esxi_hostname) is provided, then disk information about the given host system will be returned.
author:
- Matt Proud (@laidbackware)
options:
cluster_name:
description:
- Name of the cluster from which the ESXi host belong to.
- - If C(esxi_hostname) is not given, this parameter is required.
+ - If O(esxi_hostname) is not given, this parameter is required.
type: str
esxi_hostname:
description:
- ESXi hostname to gather information from.
- - If C(cluster_name) is not given, this parameter is required.
+ - If O(cluster_name) is not given, this parameter is required.
type: str
extends_documentation_fragment:
- community.vmware.vmware.documentation
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host_dns.py b/ansible_collections/community/vmware/plugins/modules/vmware_host_dns.py
index 0a03f0ae2..6ba4532c7 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_host_dns.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host_dns.py
@@ -18,13 +18,11 @@ description:
author:
- Christian Kotte (@ckotte)
- Mario Lenz (@mariolenz)
-notes:
-- This module is a replacement for the module C(vmware_dns_config)
options:
type:
description:
- - Type of DNS assignment. Either C(dhcp) or C(static).
- - A VMkernel adapter needs to be set to DHCP if C(type) is set to C(dhcp).
+ - Type of DNS assignment. Either V(dhcp) or V(static).
+ - A VMkernel adapter needs to be set to DHCP if set to V(dhcp).
type: str
choices: [ 'dhcp', 'static' ]
required: true
@@ -32,7 +30,7 @@ options:
description:
- The VMkernel network adapter to obtain DNS settings from.
- Needs to get its IP through DHCP, a static network configuration combined with a dynamic DNS configuration doesn't work.
- - The parameter is only required in case of C(type) is set to C(dhcp).
+ - The parameter is only required in case of O(type=dhcp).
type: str
host_name:
description:
@@ -63,13 +61,13 @@ options:
esxi_hostname:
description:
- Name of the host system to work with.
- - This parameter is required if C(cluster_name) is not specified and you connect to a vCenter.
+ - This parameter is required if O(cluster_name) is not specified and you connect to a vCenter.
- Cannot be used when you connect directly to an ESXi host.
type: str
cluster_name:
description:
- Name of the cluster from which all host systems will be used.
- - This parameter is required if C(esxi_hostname) is not specified and you connect to a vCenter.
+ - This parameter is required if O(esxi_hostname) is not specified and you connect to a vCenter.
- Cannot be used when you connect directly to an ESXi host.
type: str
extends_documentation_fragment:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host_dns_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_host_dns_info.py
index 182fd2548..bee8c58eb 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_host_dns_info.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host_dns_info.py
@@ -22,12 +22,12 @@ options:
cluster_name:
description:
- Name of the cluster from which the ESXi host belong to.
- - If C(esxi_hostname) is not given, this parameter is required.
+ - If O(esxi_hostname) is not given, this parameter is required.
type: str
esxi_hostname:
description:
- ESXi hostname to gather information from.
- - If C(cluster_name) is not given, this parameter is required.
+ - If O(cluster_name) is not given, this parameter is required.
type: str
extends_documentation_fragment:
- community.vmware.vmware.documentation
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host_facts.py b/ansible_collections/community/vmware/plugins/modules/vmware_host_facts.py
index 172ced427..a4738b117 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_host_facts.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host_facts.py
@@ -15,12 +15,9 @@ module: vmware_host_facts
short_description: Gathers facts about remote ESXi hostsystem
description:
- This module can be used to gathers facts like CPU, memory, datastore, network and system etc. about ESXi host system.
- - Please specify hostname or IP address of ESXi host system as C(hostname).
- - If hostname or IP address of vCenter is provided as C(hostname) and C(esxi_hostname) is not specified, then the
+ - Please specify hostname or IP address of ESXi host system as O(hostname).
+ - If hostname or IP address of vCenter is provided as O(hostname) and O(esxi_hostname) is not specified, then the
module will throw an error.
- - VSAN facts added in 2.7 version.
- - SYSTEM fact uuid added in 2.10 version.
- - Connection state fact added in VMware collection 2.6.0.
- Please note that when ESXi host connection state is not C(connected), facts returned from vCenter might be stale.
Users are recommended to check connection state value and take appropriate decision in the playbook.
author:
@@ -34,15 +31,22 @@ options:
type: str
show_tag:
description:
- - Tags related to Host are shown if set to C(true).
+ - Tags related to Host are shown if set to V(true).
+ default: false
+ type: bool
+ required: false
+ show_datacenter:
+ version_added: 4.2.0
+ description:
+ - Return the related Datacenter if set to V(true).
default: false
type: bool
required: false
schema:
description:
- Specify the output schema desired.
- - The 'summary' output schema is the legacy output from the module
- - The 'vsphere' output schema is the vSphere API class definition
+ - The V(summary) output schema is the legacy output from the module
+ - The V(vsphere) output schema is the vSphere API class definition
which requires pyvmomi>6.7.1
choices: ['summary', 'vsphere']
default: 'summary'
@@ -59,7 +63,7 @@ options:
- ' "config.product.apiVersion",'
- ' "overallStatus"'
- ' ]'
- - Only valid when C(schema) is C(vsphere).
+ - Only valid when O(schema=vsphere).
type: list
elements: str
required: false
@@ -270,6 +274,8 @@ class VMwareHostFactManager(PyVmomi):
ansible_facts.update(self.get_vsan_facts())
ansible_facts.update(self.get_cluster_facts())
ansible_facts.update({'host_date_time': ansible_date_time_facts(self.esxi_time)})
+ if self.params.get('show_datacenter'):
+ ansible_facts.update(self.get_datacenter_facts())
if self.params.get('show_tag'):
vmware_client = VmwareRestClient(self.module)
tag_info = {
@@ -285,6 +291,18 @@ class VMwareHostFactManager(PyVmomi):
cluster_facts.update(cluster=self.host.parent.name)
return cluster_facts
+ def get_datacenter_facts(self):
+ datatacenter_facts = {'datacenter': None}
+
+ parent = self.host.parent
+ while parent:
+ if isinstance(parent, vim.Datacenter):
+ datatacenter_facts.update(datacenter=parent.name)
+ break
+ parent = parent.parent
+
+ return datatacenter_facts
+
def get_vsan_facts(self):
config_mgr = self.host.configManager.vsanSystem
ret = {
@@ -404,6 +422,7 @@ def main():
argument_spec.update(
esxi_hostname=dict(type='str', required=False),
show_tag=dict(type='bool', default=False),
+ show_datacenter=dict(type='bool', default=False),
schema=dict(type='str', choices=['summary', 'vsphere'], default='summary'),
properties=dict(type='list', elements='str')
)
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host_feature_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_host_feature_info.py
index 33c33a562..dcf885e47 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_host_feature_info.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host_feature_info.py
@@ -21,12 +21,12 @@ options:
cluster_name:
description:
- Name of the cluster from all host systems to be used for information gathering.
- - If C(esxi_hostname) is not given, this parameter is required.
+ - If O(esxi_hostname) is not given, this parameter is required.
type: str
esxi_hostname:
description:
- ESXi hostname to gather information from.
- - If C(cluster_name) is not given, this parameter is required.
+ - If O(cluster_name) is not given, this parameter is required.
type: str
extends_documentation_fragment:
- community.vmware.vmware.documentation
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host_firewall_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_host_firewall_info.py
index f735ac651..05479fe51 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_host_firewall_info.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host_firewall_info.py
@@ -21,12 +21,12 @@ options:
cluster_name:
description:
- Name of the cluster from which the ESXi host belong to.
- - If C(esxi_hostname) is not given, this parameter is required.
+ - If O(esxi_hostname) is not given, this parameter is required.
type: str
esxi_hostname:
description:
- ESXi hostname to gather information from.
- - If C(cluster_name) is not given, this parameter is required.
+ - If O(cluster_name) is not given, this parameter is required.
type: str
extends_documentation_fragment:
- community.vmware.vmware.documentation
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host_firewall_manager.py b/ansible_collections/community/vmware/plugins/modules/vmware_host_firewall_manager.py
index 62e6ea638..3f70a5c8d 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_host_firewall_manager.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host_firewall_manager.py
@@ -23,13 +23,13 @@ options:
description:
- Name of the cluster.
- Firewall settings are applied to every ESXi host system in given cluster.
- - If C(esxi_hostname) is not given, this parameter is required.
+ - If O(esxi_hostname) is not given, this parameter is required.
type: str
esxi_hostname:
description:
- ESXi hostname.
- Firewall settings are applied to this ESXi host system.
- - If C(cluster_name) is not given, this parameter is required.
+ - If O(cluster_name) is not given, this parameter is required.
type: str
rules:
description:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host_graphics.py b/ansible_collections/community/vmware/plugins/modules/vmware_host_graphics.py
new file mode 100644
index 000000000..aa357602f
--- /dev/null
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host_graphics.py
@@ -0,0 +1,190 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Alexander Nikitin (ihumster@ihumster.ru)
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+DOCUMENTATION = r'''
+---
+module: vmware_host_graphics
+version_added: '3.10.0'
+short_description: Manage Host Graphic Settings
+description:
+- This module can be used to manage Host Graphic Settings
+author:
+- Alexander Nikitin (@ihumster)
+options:
+ cluster_name:
+ description:
+ - Name of cluster.
+ - All host system from given cluster used to manage Host Graphic Settings.
+ - Required parameter, if O(esxi_hostname) is not set.
+ type: str
+ esxi_hostname:
+ description:
+ - List of ESXi hostname to manage Host Graphic Settings.
+ - Required parameter, if O(cluster_name) is not set.
+ type: list
+ elements: str
+ graphic_type:
+ description:
+ - Default graphics type
+ default: shared
+ choices: [ shared, sharedDirect ]
+ type: str
+ assigment_policy:
+ description:
+ - Shared passthrough GPU assignment policy
+ default: performance
+ choices: [ consolidation, performance ]
+ type: str
+ restart_xorg:
+ description:
+ - Restart X.Org Server after change any parameter ( O(graphic_type) or O(assigment_policy) )
+ default: False
+ type: bool
+extends_documentation_fragment:
+- community.vmware.vmware.documentation
+
+'''
+
+EXAMPLES = r'''
+- name: Change Host Graphics Settings
+ community.vmware.vmware_host_graphics:
+ hostname: '{{ vcenter_hostname }}'
+ username: '{{ vcenter_username }}'
+ password: '{{ vcenter_password }}'
+ esxi_hostname: '{{ esxi_hostname }}'
+ graphic_type: sharedDirect
+ assigment_policy: consolidation
+ delegate_to: localhost
+'''
+
+RETURN = r'''
+results:
+ description:
+ - data about host system graphics settings.
+ returned: always
+ type: dict
+ sample: {
+ "changed": true,
+ "esxi01": {
+ "changed": false,
+ "msg": "All Host Graphics Settings already configured"
+ },
+ "esxi02": {
+ "changed": true,
+ "msg": "New host graphics settings changed to: hostDefaultGraphicsType = 'shared', sharedPassthruAssignmentPolicy = 'performance'.X.Org was restarted"
+ }
+ }
+'''
+
+try:
+ from pyVmomi import vim
+ HAS_PYVMOMI = True
+except ImportError:
+ HAS_PYVMOMI = False
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.community.vmware.plugins.module_utils.vmware import vmware_argument_spec, PyVmomi
+from ansible.module_utils._text import to_native
+
+
+class VMwareHostGraphicSettings(PyVmomi):
+ """ Main class for configuring Host Graphics Settings """
+ def __init__(self, module):
+ super(VMwareHostGraphicSettings, self).__init__(module)
+ self.graphic_type = self.params['graphic_type']
+ self.assigment_policy = self.params['assigment_policy']
+ self.restart_xorg = self.params['restart_xorg']
+ self.results = {"changed": False}
+ esxi_hostname = self.params['esxi_hostname']
+ cluster_name = self.params['cluster_name']
+ self.hosts = self.get_all_host_objs(cluster_name=cluster_name, esxi_host_name=esxi_hostname)
+ if self.hosts is None:
+ self.module.fail_json(msg="Failed to find host system.")
+
+ def ensure(self):
+ """
+ Function to manage host graphics
+ """
+ for host in self.hosts:
+ self.results[host.name] = dict()
+ if host.runtime.connectionState == "connected":
+ hgm = host.configManager.graphicsManager
+ hsm = host.configManager.serviceSystem
+ changed = False
+ current_config = hgm.graphicsConfig
+ if current_config.hostDefaultGraphicsType != self.graphic_type:
+ changed = True
+ current_config.hostDefaultGraphicsType = self.graphic_type
+ if current_config.sharedPassthruAssignmentPolicy != self.assigment_policy:
+ changed = True
+ current_config.sharedPassthruAssignmentPolicy = self.assigment_policy
+
+ if changed:
+ if self.module.check_mode:
+ not_world = '' if self.restart_xorg else 'not '
+ self.results[host.name]['changed'] = False
+ self.results[host.name]['msg'] = f"New host graphics settings will be changed to: hostDefaultGraphicsType = \
+ '{current_config.hostDefaultGraphicsType}', sharedPassthruAssignmentPolicy = \
+ '{current_config.sharedPassthruAssignmentPolicy}'. \
+ X.Org will {not_world}be restarted."
+ else:
+ try:
+ hgm.UpdateGraphicsConfig(current_config)
+ if self.restart_xorg:
+ hsm.RestartService('xorg')
+ xorg_status = 'was restarted' if self.restart_xorg else 'was not restarted.'
+ self.results['changed'] = True
+ self.results[host.name]['changed'] = True
+ self.results[host.name]['msg'] = f"New host graphics settings changed to: hostDefaultGraphicsType = \
+ '{current_config.hostDefaultGraphicsType}', sharedPassthruAssignmentPolicy = \
+ '{current_config.sharedPassthruAssignmentPolicy}'. \
+ X.Org {xorg_status}"
+ except vim.fault.HostConfigFault as config_fault:
+ self.module.fail_json(
+ msg=f"Failed to configure host graphics settings for host {host.name} due to : {to_native(config_fault.msg)}"
+ )
+ else:
+ self.results[host.name]['changed'] = False
+ self.results[host.name]['msg'] = 'All Host Graphics Settings have already been configured'
+ else:
+ self.results[host.name]['changed'] = False
+ self.results[host.name]['msg'] = f"Host {host.name} is disconnected and cannot be changed"
+
+ self.module.exit_json(**self.results)
+
+
+def main():
+ """ Main module method"""
+ argument_spec = vmware_argument_spec()
+ argument_spec.update(
+ cluster_name=dict(type='str'),
+ esxi_hostname=dict(type='list', elements='str'),
+ graphic_type=dict(type='str', default='shared', choices=['shared', 'sharedDirect']),
+ assigment_policy=dict(type='str', default='performance', choices=['consolidation', 'performance']),
+ restart_xorg=dict(type='bool', default=False),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_one_of=[
+ ['cluster_name', 'esxi_hostname'],
+ ],
+ )
+
+ if not HAS_PYVMOMI:
+ module.fail_json(msg='pyvmomi required for this module')
+
+ vmware_host_graphics = VMwareHostGraphicSettings(module)
+ vmware_host_graphics.ensure()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host_hyperthreading.py b/ansible_collections/community/vmware/plugins/modules/vmware_host_hyperthreading.py
index e3431ca7b..556dc3cd3 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_host_hyperthreading.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host_hyperthreading.py
@@ -31,12 +31,12 @@ options:
esxi_hostname:
description:
- Name of the host system to work with.
- - This parameter is required if C(cluster_name) is not specified.
+ - This parameter is required if O(cluster_name) is not specified.
type: str
cluster_name:
description:
- Name of the cluster from which all host systems will be used.
- - This parameter is required if C(esxi_hostname) is not specified.
+ - This parameter is required if O(esxi_hostname) is not specified.
type: str
extends_documentation_fragment:
- community.vmware.vmware.documentation
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host_ipv6.py b/ansible_collections/community/vmware/plugins/modules/vmware_host_ipv6.py
index 320e4a185..8c6cf3cf0 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_host_ipv6.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host_ipv6.py
@@ -29,12 +29,12 @@ options:
esxi_hostname:
description:
- Name of the host system to work with.
- - This is required parameter if C(cluster_name) is not specified.
+ - This is required parameter if O(cluster_name) is not specified.
type: str
cluster_name:
description:
- Name of the cluster from which all host systems will be used.
- - This is required parameter if C(esxi_hostname) is not specified.
+ - This is required parameter if O(esxi_hostname) is not specified.
type: str
extends_documentation_fragment:
- community.vmware.vmware.documentation
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host_iscsi.py b/ansible_collections/community/vmware/plugins/modules/vmware_host_iscsi.py
index f8739ab60..c6e2eced2 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_host_iscsi.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host_iscsi.py
@@ -24,7 +24,7 @@ options:
iscsi_config:
description:
- The iSCSI configs.
- - This parameter is required if I(state=present) or I(state=absent).
+ - This parameter is required if O(state=present) or O(state=absent).
type: dict
suboptions:
iscsi_name:
@@ -252,11 +252,11 @@ options:
type: str
state:
description:
- - If set to C(present), add the iSCSI target or the bind ports if they are not existing.
- - If set to C(present), update the iSCSI settings if they already exist and occur change.
- - If set to C(absent), remove the iSCSI target or the bind ports if they are existing.
- - If set to (enabled), enable the iSCSI of ESXi if the iSCSI is disabled.
- - If set to (disabled), disable the iSCSI of ESXi if the iSCSI is enabled.
+ - If set to V(present), add the iSCSI target or the bind ports if they are not existing.
+ - If set to V(present), update the iSCSI settings if they already exist and occur change.
+ - If set to V(absent), remove the iSCSI target or the bind ports if they are existing.
+ - If set to V(enabled), enable the iSCSI of ESXi if the iSCSI is disabled.
+ - If set to V(disabled), disable the iSCSI of ESXi if the iSCSI is enabled.
type: str
default: present
choices:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host_iscsi_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_host_iscsi_info.py
index 4030b3ba6..d9599a26d 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_host_iscsi_info.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host_iscsi_info.py
@@ -100,7 +100,6 @@ iscsi_properties:
detected_iscsi_drives:
description:
- list of detected iSCSI drive
- - added from version 1.9.0
returned: always
type: list
sample: >-
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host_kernel_manager.py b/ansible_collections/community/vmware/plugins/modules/vmware_host_kernel_manager.py
index 834d994c0..1fdfec703 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_host_kernel_manager.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host_kernel_manager.py
@@ -24,13 +24,13 @@ options:
esxi_hostname:
description:
- Name of the ESXi host to work on.
- - This parameter is required if C(cluster_name) is not specified.
+ - This parameter is required if O(cluster_name) is not specified.
type: str
cluster_name:
description:
- Name of the VMware cluster to work on.
- All ESXi hosts in this cluster will be configured.
- - This parameter is required if C(esxi_hostname) is not specified.
+ - This parameter is required if O(esxi_hostname) is not specified.
type: str
kernel_module_name:
description:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host_lockdown.py b/ansible_collections/community/vmware/plugins/modules/vmware_host_lockdown.py
index 2686d2f13..023f116b7 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_host_lockdown.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host_lockdown.py
@@ -17,7 +17,7 @@ description:
- This module can be used to manage administrator permission for the local administrative account for the host when ESXi hostname is given.
- All parameters and VMware objects values are case sensitive.
- This module is destructive as administrator permission are managed using APIs used, please read options carefully and proceed.
-- Please specify C(hostname) as vCenter IP or hostname only, as lockdown operations are not possible from standalone ESXi server.
+- Please specify O(hostname) as vCenter IP or hostname only, as lockdown operations are not possible from standalone ESXi server.
author:
- Abhijeet Kasurde (@Akasurde)
options:
@@ -25,26 +25,26 @@ options:
description:
- Name of cluster.
- All host systems from given cluster used to manage lockdown.
- - Required parameter, if C(esxi_hostname) is not set.
+ - Required parameter, if O(esxi_hostname) is not set.
type: str
esxi_hostname:
description:
- List of ESXi hostname to manage lockdown.
- - Required parameter, if C(cluster_name) is not set.
+ - Required parameter, if O(cluster_name) is not set.
- See examples for specifications.
type: list
elements: str
state:
description:
- State of hosts system
- - If set to C(disabled), all host systems will be removed from lockdown mode.
- - If host system is already out of lockdown mode and set to C(disabled), no action will be taken.
- - If set to C(normal), all host systems will be set in lockdown mode.
- - If host system is already in lockdown mode and set to C(normal), no action will be taken.
- - If set to C(strict), all host systems will be set in strict lockdown mode.
- - If host system is already in strict lockdown mode and set to C(strict), no action will be taken.
+ - If set to V(disabled), all host systems will be removed from lockdown mode.
+ - If host system is already out of lockdown mode and set to V(disabled), no action will be taken.
+ - If set to V(normal), all host systems will be set in lockdown mode.
+ - If host system is already in lockdown mode and set to V(normal), no action will be taken.
+ - If set to V(strict), all host systems will be set in strict lockdown mode.
+ - If host system is already in strict lockdown mode and set to V(strict), no action will be taken.
default: normal
- choices: [ disabled, normal, strict, present, absent ]
+ choices: [ disabled, normal, strict ]
type: str
extends_documentation_fragment:
- community.vmware.vmware.documentation
@@ -148,13 +148,6 @@ class VmwareLockdownManager(PyVmomi):
change_list = []
desired_state = self.params.get('state')
- if desired_state == 'present':
- self.module.warn("'present' will be removed in a future version. Please use 'normal' instead.")
- desired_state = 'normal'
- elif desired_state == 'absent':
- self.module.warn("'absent' will be removed in a future version. Please use 'disabled' instead.")
- desired_state = 'disabled'
-
for host in self.hosts:
current_state_api = host.configManager.hostAccessManager.lockdownMode
current_state = current_state_api[8:].lower()
@@ -193,7 +186,7 @@ def main():
argument_spec.update(
cluster_name=dict(type='str', required=False),
esxi_hostname=dict(type='list', required=False, elements='str'),
- state=dict(type='str', default='normal', choices=['disabled', 'normal', 'strict', 'present', 'absent'], required=False),
+ state=dict(type='str', default='normal', choices=['disabled', 'normal', 'strict'], required=False),
)
module = AnsibleModule(
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host_lockdown_exceptions.py b/ansible_collections/community/vmware/plugins/modules/vmware_host_lockdown_exceptions.py
index 00c9ec793..892daeb39 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_host_lockdown_exceptions.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host_lockdown_exceptions.py
@@ -17,7 +17,7 @@ short_description: Manage Lockdown Mode Exception Users
description:
- This module can be used to manage Lockdown Mode Exception Users.
- All parameters and VMware objects values are case sensitive.
-- Please specify C(hostname) as vCenter IP or hostname only, as lockdown operations are not possible from standalone ESXi server.
+- Please specify O(hostname) as vCenter IP or hostname only, as lockdown operations are not possible from standalone ESXi server.
author:
- Mario Lenz (@mariolenz)
options:
@@ -25,26 +25,26 @@ options:
description:
- Name of cluster.
- All host systems from given cluster used to manage exception users.
- - Required parameter, if C(esxi_hostname) is not set.
+ - Required parameter, if O(esxi_hostname) is not set.
type: str
esxi_hostname:
description:
- List of ESXi hostname to manage exception users.
- - Required parameter, if C(cluster_name) is not set.
+ - Required parameter, if O(cluster_name) is not set.
type: list
elements: str
state:
description:
- - If C(present), make sure the given users are defined as Lockdown Mode Exception Users.
- - If C(absent), make sure the given users are NO Lockdown Mode Exception Users.
- - If C(set), will replace Lockdown Mode Exception Users defined list of users.
+ - If V(present), make sure the given users are defined as Lockdown Mode Exception Users.
+ - If V(absent), make sure the given users are NO Lockdown Mode Exception Users.
+ - If V(set), will replace Lockdown Mode Exception Users defined list of users.
default: present
choices: [ present, absent , set ]
type: str
exception_users:
description:
- List of Lockdown Mode Exception Users.
- - To remove all Exception Users, I(state=set) the empty list.
+ - To remove all Exception Users, O(state=set) the empty list.
type: list
elements: str
required: true
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host_ntp.py b/ansible_collections/community/vmware/plugins/modules/vmware_host_ntp.py
index 3d6b0612e..d04e0820c 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_host_ntp.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host_ntp.py
@@ -16,7 +16,7 @@ module: vmware_host_ntp
short_description: Manage NTP server configuration of an ESXi host
description:
- This module can be used to configure, add or remove NTP servers from an ESXi host.
-- If C(state) is not given, the NTP servers will be configured in the exact sequence.
+- If O(state) is not given, the NTP servers will be configured in the exact sequence.
- User can specify an ESXi hostname or Cluster name. In case of cluster name, all ESXi hosts are updated.
author:
- Abhijeet Kasurde (@Akasurde)
@@ -25,12 +25,12 @@ options:
esxi_hostname:
description:
- Name of the host system to work with.
- - This parameter is required if C(cluster_name) is not specified.
+ - This parameter is required if O(cluster_name) is not specified.
type: str
cluster_name:
description:
- Name of the cluster from which all host systems will be used.
- - This parameter is required if C(esxi_hostname) is not specified.
+ - This parameter is required if O(esxi_hostname) is not specified.
type: str
ntp_servers:
description:
@@ -41,9 +41,9 @@ options:
elements: str
state:
description:
- - "present: Add NTP server(s), if specified server(s) are absent else do nothing."
- - "absent: Remove NTP server(s), if specified server(s) are present else do nothing."
- - Specified NTP server(s) will be configured if C(state) isn't specified.
+ - "V(present): Add NTP server(s), if specified server(s) are absent else do nothing."
+ - "V(absent): Remove NTP server(s), if specified server(s) are present else do nothing."
+ - Specified NTP server(s) will be configured if O(state) isn't specified.
choices: [ present, absent ]
type: str
verbose:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host_ntp_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_host_ntp_info.py
index 1515328a8..0bc976d54 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_host_ntp_info.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host_ntp_info.py
@@ -22,13 +22,13 @@ options:
description:
- Name of the cluster.
- NTP config information about each ESXi server will be returned for the given cluster.
- - If C(esxi_hostname) is not given, this parameter is required.
+ - If O(esxi_hostname) is not given, this parameter is required.
type: str
esxi_hostname:
description:
- ESXi hostname.
- NTP config information about this ESXi server will be returned.
- - If C(cluster_name) is not given, this parameter is required.
+ - If O(cluster_name) is not given, this parameter is required.
type: str
extends_documentation_fragment:
- community.vmware.vmware.documentation
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host_package_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_host_package_info.py
index 9e53f69da..fd0a27cd8 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_host_package_info.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host_package_info.py
@@ -22,13 +22,13 @@ options:
description:
- Name of the cluster.
- Package information about each ESXi server will be returned for given cluster.
- - If C(esxi_hostname) is not given, this parameter is required.
+ - If O(esxi_hostname) is not given, this parameter is required.
type: str
esxi_hostname:
description:
- ESXi hostname.
- Package information about this ESXi server will be returned.
- - If C(cluster_name) is not given, this parameter is required.
+ - If O(cluster_name) is not given, this parameter is required.
type: str
extends_documentation_fragment:
- community.vmware.vmware.documentation
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host_passthrough.py b/ansible_collections/community/vmware/plugins/modules/vmware_host_passthrough.py
index 9693a9d01..3b8b36633 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_host_passthrough.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host_passthrough.py
@@ -16,20 +16,18 @@ author:
- sky-joker (@sky-joker)
description:
- This module can be managed PCI device passthrough settings on host.
-notes:
- - Supports C(check_mode).
options:
cluster:
description:
- Name of the cluster from which all host systems will be used.
- - This parameter is required if C(esxi_hostname) is not specified.
+ - This parameter is required if O(esxi_hostname) is not specified.
aliases:
- cluster_name
type: str
esxi_hostname:
description:
- Name of the host system to work with.
- - This parameter is required if C(cluster_name) is not specified.
+ - This parameter is required if O(cluster_name) is not specified.
- User can specify specific host from the cluster.
type: str
devices:
@@ -48,8 +46,8 @@ options:
type: list
state:
description:
- - If I(state=present), passthrough of PCI device will be enabled.
- - If I(state=absent), passthrough of PCI device will be disabled.
+ - If V(state=present), passthrough of PCI device will be enabled.
+ - If V(state=absent), passthrough of PCI device will be disabled.
choices:
- present
- absent
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host_powermgmt_policy.py b/ansible_collections/community/vmware/plugins/modules/vmware_host_powermgmt_policy.py
index 6573e591c..4bce43970 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_host_powermgmt_policy.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host_powermgmt_policy.py
@@ -27,12 +27,12 @@ options:
esxi_hostname:
description:
- Name of the host system to work with.
- - This is required parameter if C(cluster_name) is not specified.
+ - This is required parameter if O(cluster_name) is not specified.
type: str
cluster_name:
description:
- Name of the cluster from which all host systems will be used.
- - This is required parameter if C(esxi_hostname) is not specified.
+ - This is required parameter if O(esxi_hostname) is not specified.
type: str
extends_documentation_fragment:
- community.vmware.vmware.documentation
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host_powerstate.py b/ansible_collections/community/vmware/plugins/modules/vmware_host_powerstate.py
index a68cac141..fad0af4bb 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_host_powerstate.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host_powerstate.py
@@ -30,27 +30,27 @@ options:
esxi_hostname:
description:
- Name of the host system to work with.
- - This is required parameter if C(cluster_name) is not specified.
+ - This is required parameter if O(cluster_name) is not specified.
type: str
cluster_name:
description:
- Name of the cluster from which all host systems will be used.
- - This is required parameter if C(esxi_hostname) is not specified.
+ - This is required parameter if O(esxi_hostname) is not specified.
type: str
force:
description:
- 'This parameter specify if the host should be proceeding with user defined powerstate
regardless of whether it is in maintenance mode.'
- - 'If C(state) set to C(reboot-host) and C(force) as C(true), then host system is rebooted regardless of whether it is in maintenance mode.'
- - 'If C(state) set to C(shutdown-host) and C(force) as C(true), then host system is shutdown regardless of whether it is in maintenance mode.'
- - 'If C(state) set to C(power-down-to-standby) and C(force) to C(true), then all powered off VMs will evacuated.'
- - 'Not applicable if C(state) set to C(power-up-from-standby).'
+ - 'If O(state=reboot-host) and O(force=true), then host system is rebooted regardless of whether it is in maintenance mode.'
+ - 'If O(state=shutdown-host) and O(force=true), then host system is shutdown regardless of whether it is in maintenance mode.'
+ - 'If O(state=power-down-to-standby) and O(force=true), then all powered off VMs will evacuated.'
+ - 'Not applicable if O(state=power-up-from-standby).'
type: bool
default: false
timeout:
description:
- - 'This parameter defines timeout for C(state) set to C(power-down-to-standby) or C(power-up-from-standby).'
- - 'Ignored if C(state) set to C(reboot-host) or C(shutdown-host).'
+ - 'This parameter defines timeout for O(state=power-down-to-standby) or O(state=power-up-from-standby).'
+ - 'Ignored if O(state=reboot-host) or O(state=shutdown-host).'
- 'This parameter is defined in seconds.'
default: 600
type: int
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host_scanhba.py b/ansible_collections/community/vmware/plugins/modules/vmware_host_scanhba.py
index 0dfa1d707..0087c8a2c 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_host_scanhba.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host_scanhba.py
@@ -57,7 +57,7 @@ extends_documentation_fragment:
'''
EXAMPLES = r'''
-- name: Recan HBA's for a given ESXi host and refresh storage system objects
+- name: Rescan HBA's for a given ESXi host and refresh storage system objects
community.vmware.vmware_host_scanhba:
hostname: '{{ vcenter_hostname }}'
username: '{{ vcenter_username }}'
@@ -85,7 +85,7 @@ EXAMPLES = r'''
rescan_hba: false
delegate_to: localhost
-- name: Recan HBA's for a given ESXi host and don't refresh storage system objects
+- name: Rescan HBA's for a given ESXi host and don't refresh storage system objects
community.vmware.vmware_host_scanhba:
hostname: '{{ vcenter_hostname }}'
username: '{{ vcenter_username }}'
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host_scsidisk_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_host_scsidisk_info.py
index 00cfb027a..7619edebe 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_host_scsidisk_info.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host_scsidisk_info.py
@@ -23,13 +23,13 @@ options:
description:
- Name of the host system to work with.
- SCSI disk information about this ESXi server will be returned.
- - This parameter is required if I(cluster_name) is not specified.
+ - This parameter is required if O(cluster_name) is not specified.
type: str
cluster_name:
description:
- Name of the cluster from which all host systems will be used.
- SCSI disk information about each ESXi server will be returned for the given cluster.
- - This parameter is required if I(esxi_hostname) is not specified.
+ - This parameter is required if O(esxi_hostname) is not specified.
type: str
extends_documentation_fragment:
- community.vmware.vmware.documentation
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host_service_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_host_service_info.py
index fe3b83573..21e45ca74 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_host_service_info.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host_service_info.py
@@ -24,13 +24,13 @@ options:
description:
- Name of the cluster.
- Service information about each ESXi server will be returned for given cluster.
- - If C(esxi_hostname) is not given, this parameter is required.
+ - If O(esxi_hostname) is not given, this parameter is required.
type: str
esxi_hostname:
description:
- ESXi hostname.
- Service information about this ESXi server will be returned.
- - If C(cluster_name) is not given, this parameter is required.
+ - If O(cluster_name) is not given, this parameter is required.
type: str
extends_documentation_fragment:
- community.vmware.vmware.documentation
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host_service_manager.py b/ansible_collections/community/vmware/plugins/modules/vmware_host_service_manager.py
index 543ffcf31..f63a80435 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_host_service_manager.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host_service_manager.py
@@ -24,29 +24,29 @@ options:
description:
- Name of the cluster.
- Service settings are applied to every ESXi host system/s in given cluster.
- - If C(esxi_hostname) is not given, this parameter is required.
+ - If O(esxi_hostname) is not given, this parameter is required.
type: str
esxi_hostname:
description:
- ESXi hostname.
- Service settings are applied to this ESXi host system.
- - If C(cluster_name) is not given, this parameter is required.
+ - If O(cluster_name) is not given, this parameter is required.
type: str
state:
description:
- Desired state of service.
- - "State value 'start' and 'present' has same effect."
- - "State value 'stop' and 'absent' has same effect."
- - State value C(unchanged) is added in version 1.14.0 to allow defining startup policy without defining or changing service state.
+ - V(start) and V(present) has same effect.
+ - V(stop) and V(absent) has same effect.
+ - V(unchanged) allows defining O(service_policy) without defining or changing service state.
choices: [ absent, present, restart, start, stop, unchanged ]
type: str
default: 'start'
service_policy:
description:
- Set of valid service policy strings.
- - If set C(on), then service should be started when the host starts up.
- - If set C(automatic), then service should run if and only if it has open firewall ports.
- - If set C(off), then Service should not be started when the host starts up.
+ - If set V(on), then service should be started when the host starts up.
+ - If set V(automatic), then service should run if and only if it has open firewall ports.
+ - If set V(off), then Service should not be started when the host starts up.
choices: [ 'automatic', 'off', 'on' ]
type: str
service_name:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host_snmp.py b/ansible_collections/community/vmware/plugins/modules/vmware_host_snmp.py
index e0bfc404f..095bd9a63 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_host_snmp.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host_snmp.py
@@ -17,10 +17,25 @@ description:
- This module can be used to configure the embedded SNMP agent on an ESXi host.
author:
- Christian Kotte (@ckotte)
+- Alexander Nikitin (@ihumster)
notes:
- You need to reset the agent (to factory defaults) if you want to clear all community strings, trap targets, or filters
- SNMP v3 configuration isn't implemented yet
options:
+ cluster_name:
+ description:
+ - Name of cluster.
+ - All host system from given cluster used to manage SNMP agent.
+ - Required parameter, if O(esxi_hostname) is not set.
+ type: str
+ version_added: '3.11.0'
+ esxi_hostname:
+ description:
+ - List of ESXi hostname to manage SNMP agent.
+ - Required parameter, if O(cluster_name) is not set.
+ type: list
+ elements: str
+ version_added: '3.11.0'
state:
description:
- Enable, disable, or reset the SNMP agent.
@@ -49,7 +64,7 @@ options:
description:
- A list of trap oids for traps not to be sent by agent,
e.g. [ 1.3.6.1.4.1.6876.4.1.1.0, 1.3.6.1.4.1.6876.4.1.1.1 ]
- - Use value C(reset) to clear settings.
+ - Use value V(reset) to clear settings.
type: list
elements: str
send_trap:
@@ -60,7 +75,7 @@ options:
hw_source:
description:
- Source hardware events from IPMI sensors or CIM Indications.
- - The embedded SNMP agent receives hardware events either from IPMI sensors C(sensors) or CIM indications C(indications).
+ - The embedded SNMP agent receives hardware events either from IPMI sensors V(sensors) or CIM indications V(indications).
type: str
choices: [ indications, sensors ]
default: indications
@@ -84,7 +99,7 @@ extends_documentation_fragment:
'''
EXAMPLES = r'''
-- name: Enable and configure SNMP community
+- name: Enable and configure SNMP community on standalone ESXi host
community.vmware.vmware_host_snmp:
hostname: '{{ esxi_hostname }}'
username: '{{ esxi_username }}'
@@ -93,11 +108,12 @@ EXAMPLES = r'''
state: enabled
delegate_to: localhost
-- name: Configure SNMP traps and filters
+- name: Configure SNMP traps and filters on cluster
community.vmware.vmware_host_snmp:
- hostname: '{{ esxi_hostname }}'
- username: '{{ esxi_username }}'
- password: '{{ esxi_password }}'
+ hostname: '{{ vcenter_hostname }}'
+ username: '{{ vcenter_username }}'
+ password: '{{ vcenter_password }}'
+ cluster_name: '{{ cluster_name }}'
community: [ test ]
trap_targets:
- hostname: 192.168.1.100
@@ -112,17 +128,18 @@ EXAMPLES = r'''
state: enabled
delegate_to: localhost
-- name: Enable and configure SNMP system contact and location
+- name: Enable and configure SNMP system contact and location on simple ESXi host in vCenter
community.vmware.vmware_host_snmp:
- hostname: '{{ esxi_hostname }}'
- username: '{{ esxi_username }}'
- password: '{{ esxi_password }}'
+ hostname: '{{ vcenter_hostname }}'
+ username: '{{ vcenter_username }}'
+ password: '{{ vcenter_password }}'
+ esxi_hostname: '{{ esxi_hostname }}'
sys_contact: "admin@testemail.com"
sys_location: "Austin, USA"
state: enabled
delegate_to: localhost
-- name: Disable SNMP
+- name: Disable SNMP on standalone ESXi host
community.vmware.vmware_host_snmp:
hostname: '{{ esxi_hostname }}'
username: '{{ esxi_username }}'
@@ -137,22 +154,34 @@ results:
returned: always
type: dict
sample: {
- "esxi01": {
- "changed": false,
- "community": ["test"],
+ "changed": true,
+ "esx01.example.local": {
+ "changed": true,
+ "community": [
+ "test"
+ ],
+ "community_previous": [],
"hw_source": "indications",
- "msg": "SNMP already configured properly",
+ "log_level": "info",
+ "log_level_previous": "warning",
+ "msg": "SNMP state, community list, log level, sys contact, and sys location changed",
"port": 161,
"state": "enabled",
+ "state_previous": "disabled",
+ "sys_contact_previous": "",
+ "sys_location_previous": "",
+ "trap_filter": null,
"trap_targets": []
},
+ "failed": false
}
'''
try:
from pyVmomi import vim
+ HAS_PYVMOMI = True
except ImportError:
- pass
+ HAS_PYVMOMI = False
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.vmware.plugins.module_utils.vmware import PyVmomi, vmware_argument_spec, find_obj
@@ -164,20 +193,34 @@ class VmwareHostSnmp(PyVmomi):
def __init__(self, module):
super(VmwareHostSnmp, self).__init__(module)
+ self.results = {"changed": False}
+ self.changed = False
+ self.hosts = None
if self.is_vcenter():
- self.module.fail_json(
- msg="You have to connect directly to the ESXi host. "
- "It's not possible to configure SNMP through a vCenter connection."
- )
+ esxi_hostname = self.params['esxi_hostname']
+ cluster_name = self.params['cluster_name']
+ if all([esxi_hostname, cluster_name]):
+ self.module.fail_json(
+ msg="Only one of parameters [cluster_name, esxi_hostname] is required"
+ )
+ else:
+ if cluster_name:
+ self.hosts = self.get_all_host_objs(cluster_name=cluster_name)
+ if self.hosts is None:
+ self.module.fail_json(msg="Failed to find host system in cluster %s." % cluster_name)
+ if esxi_hostname:
+ self.hosts = self.get_all_host_objs(esxi_host_name=esxi_hostname)
+ if self.hosts is None:
+ self.module.fail_json(msg="Failed to find host system.")
else:
- self.host = find_obj(self.content, [vim.HostSystem], None)
- if self.host is None:
- self.module.fail_json(msg="Failed to find host system.")
+ host = find_obj(self.content, [vim.HostSystem], None)
+ self.hosts = list()
+ self.hosts.append(host)
def ensure(self):
"""Manage SNMP configuration for an ESXi host system"""
- results = dict(changed=False, result=dict())
+ # results = dict(changed=False, result=dict())
snmp_state = self.params.get('state')
snmp_port = self.params.get('snmp_port')
community = self.params.get('community')
@@ -191,271 +234,273 @@ class VmwareHostSnmp(PyVmomi):
event_filter = None
if trap_filter:
event_filter = ';'.join(trap_filter)
- changed = False
reset_hint = None
- changed_list = []
- results = dict(msg='')
- snmp_system = self.host.configManager.snmpSystem
- if snmp_system:
- if snmp_system.configuration:
- snmp_config_spec = snmp_system.configuration
- else:
- self.module.fail_json(msg="SNMP agent configuration isn't supported on the ESXi host")
- else:
- self.module.fail_json(msg="SNMP system isn't available on the ESXi host")
-
- # Check state
- results['state'] = snmp_state
- if snmp_state == 'reset':
- changed = True
- # Get previous config
- if snmp_config_spec.enabled:
- results['state_previous'] = 'enabled'
+ for host in self.hosts:
+ changed = False
+ changed_list = []
+ self.results[host.name] = dict(changed=False, msg='')
+ snmp_system = host.configManager.snmpSystem
+ if snmp_system:
+ if snmp_system.configuration:
+ snmp_config_spec = snmp_system.configuration
+ else:
+ self.module.fail_json(msg="SNMP agent configuration isn't supported on the ESXi host")
else:
- results['state_previous'] = 'disabled'
- results['port_previous'] = snmp_config_spec.port
- results['community_previous'] = snmp_config_spec.readOnlyCommunities
- results['trap_targets_previous'] = self.get_previous_targets(snmp_config_spec.trapTargets)
- for option in snmp_config_spec.option:
- if option.key == 'EnvEventSource' and option.value != hw_source:
- results['hw_source_previous'] = option.value
- if option.key == 'loglevel' and option.value != hw_source:
- results['log_level_previous'] = option.value
- if option.key == 'EventFilter' and option.value != hw_source:
- results['trap_filter_previous'] = option.value.split(';')
- if option.key == 'syscontact' and option.value != hw_source:
- results['syscontact_previous'] = option.value
- if option.key == 'syslocation' and option.value != hw_source:
- results['syslocation_previous'] = option.value
- # Build factory default config
- destination = vim.host.SnmpSystem.SnmpConfigSpec.Destination()
- destination.hostName = ""
- destination.port = 0
- destination.community = ""
- options = []
- options.append(self.create_option('EnvEventSource', 'indications'))
- options.append(self.create_option('EventFilter', 'reset'))
- snmp_config_spec = vim.host.SnmpSystem.SnmpConfigSpec()
- # Looks like this value is causing the reset
- snmp_config_spec.readOnlyCommunities = [""]
- snmp_config_spec.trapTargets = [destination]
- snmp_config_spec.port = 161
- snmp_config_spec.enabled = False
- snmp_config_spec.option = options
- else:
- if snmp_state == 'enabled' and not snmp_config_spec.enabled:
- changed = True
- changed_list.append("state")
- results['state_previous'] = 'disabled'
- snmp_config_spec.enabled = True
- elif snmp_state == 'disabled' and snmp_config_spec.enabled:
- changed = True
- changed_list.append("state")
- results['state_previous'] = 'enabled'
- snmp_config_spec.enabled = False
+ self.module.fail_json(msg="SNMP system isn't available on the ESXi host")
- # Check port
- results['port'] = snmp_port
- if snmp_config_spec.port != snmp_port:
- changed = True
- changed_list.append("port")
- results['port_previous'] = snmp_config_spec.port
- snmp_config_spec.port = snmp_port
-
- # Check read-only community strings
- results['community'] = community
- if snmp_config_spec.readOnlyCommunities != community:
+ # Check state
+ self.results[host.name]['state'] = snmp_state
+ if snmp_state == 'reset':
changed = True
- changed_list.append("community list")
- results['community_previous'] = snmp_config_spec.readOnlyCommunities
- if community:
- snmp_config_spec.readOnlyCommunities = community
+ # Get previous config
+ if snmp_config_spec.enabled:
+ self.results[host.name]['state_previous'] = 'enabled'
else:
- # Doesn't work. Need to reset config instead
- # snmp_config_spec.readOnlyCommunities = []
- reset_hint = True
+ self.results[host.name]['state_previous'] = 'disabled'
+ self.results[host.name]['port_previous'] = snmp_config_spec.port
+ self.results[host.name]['community_previous'] = snmp_config_spec.readOnlyCommunities
+ self.results[host.name]['trap_targets_previous'] = self.get_previous_targets(snmp_config_spec.trapTargets)
+ for option in snmp_config_spec.option:
+ if option.key == 'EnvEventSource' and option.value != hw_source:
+ self.results[host.name]['hw_source_previous'] = option.value
+ if option.key == 'loglevel' and option.value != hw_source:
+ self.results[host.name]['log_level_previous'] = option.value
+ if option.key == 'EventFilter' and option.value != hw_source:
+ self.results[host.name]['trap_filter_previous'] = option.value.split(';')
+ if option.key == 'syscontact' and option.value != hw_source:
+ self.results[host.name]['syscontact_previous'] = option.value
+ if option.key == 'syslocation' and option.value != hw_source:
+ self.results[host.name]['syslocation_previous'] = option.value
+ # Build factory default config
+ destination = vim.host.SnmpSystem.SnmpConfigSpec.Destination()
+ destination.hostName = ""
+ destination.port = 0
+ destination.community = ""
+ options = []
+ options.append(self.create_option('EnvEventSource', 'indications'))
+ options.append(self.create_option('EventFilter', 'reset'))
+ snmp_config_spec = vim.host.SnmpSystem.SnmpConfigSpec()
+ # Looks like this value is causing the reset
+ snmp_config_spec.readOnlyCommunities = [""]
+ snmp_config_spec.trapTargets = [destination]
+ snmp_config_spec.port = 161
+ snmp_config_spec.enabled = False
+ snmp_config_spec.option = options
+ else:
+ if snmp_state == 'enabled' and not snmp_config_spec.enabled:
+ changed = True
+ changed_list.append("state")
+ self.results[host.name]['state_previous'] = 'disabled'
+ snmp_config_spec.enabled = True
+ elif snmp_state == 'disabled' and snmp_config_spec.enabled:
+ changed = True
+ changed_list.append("state")
+ self.results[host.name]['state_previous'] = 'enabled'
+ snmp_config_spec.enabled = False
+
+ # Check port
+ self.results[host.name]['port'] = snmp_port
+ if snmp_config_spec.port != snmp_port:
+ changed = True
+ changed_list.append("port")
+ self.results[host.name]['port_previous'] = snmp_config_spec.port
+ snmp_config_spec.port = snmp_port
- # Check trap targets
- results['trap_targets'] = desired_trap_targets
- if snmp_config_spec.trapTargets:
- if desired_trap_targets:
- temp_desired_targets = []
- # Loop through desired targets
- for target in desired_trap_targets:
- dest_hostname, dest_port, dest_community = self.check_if_options_are_valid(target)
- trap_target_found = False
+ # Check read-only community strings
+ self.results[host.name]['community'] = community
+ if snmp_config_spec.readOnlyCommunities != community:
+ changed = True
+ changed_list.append("community list")
+ self.results[host.name]['community_previous'] = snmp_config_spec.readOnlyCommunities
+ if community:
+ snmp_config_spec.readOnlyCommunities = community
+ else:
+ # Doesn't work. Need to reset config instead
+ # snmp_config_spec.readOnlyCommunities = []
+ reset_hint = True
+
+ # Check trap targets
+ self.results[host.name]['trap_targets'] = desired_trap_targets
+ if snmp_config_spec.trapTargets:
+ if desired_trap_targets:
+ temp_desired_targets = []
+ # Loop through desired targets
+ for target in desired_trap_targets:
+ dest_hostname, dest_port, dest_community = self.check_if_options_are_valid(target)
+ trap_target_found = False
+ for trap_target in snmp_config_spec.trapTargets:
+ if trap_target.hostName == dest_hostname:
+ if trap_target.port != dest_port or trap_target.community != dest_community:
+ changed = True
+ changed_list.append("trap target '%s'" % dest_hostname)
+ trap_target_found = True
+ break
+ if not trap_target_found:
+ changed = True
+ changed_list.append("trap target '%s'" % dest_hostname)
+ # Build destination and add to temp target list
+ destination = self.build_destination(dest_hostname, dest_port, dest_community)
+ temp_desired_targets.append(destination)
+ # Loop through existing targets to find targets that need to be deleted
for trap_target in snmp_config_spec.trapTargets:
- if trap_target.hostName == dest_hostname:
- if trap_target.port != dest_port or trap_target.community != dest_community:
- changed = True
- changed_list.append("trap target '%s'" % dest_hostname)
- trap_target_found = True
- break
- if not trap_target_found:
- changed = True
- changed_list.append("trap target '%s'" % dest_hostname)
- # Build destination and add to temp target list
- destination = self.build_destination(dest_hostname, dest_port, dest_community)
- temp_desired_targets.append(destination)
- # Loop through existing targets to find targets that need to be deleted
- for trap_target in snmp_config_spec.trapTargets:
- target_found = False
+ target_found = False
+ for target in desired_trap_targets:
+ if trap_target.hostName == target.get('hostname'):
+ target_found = True
+ break
+ if not target_found:
+ changed = True
+ changed_list.append("trap target '%s'" % trap_target.hostName)
+ # Configure trap targets if something has changed
+ if changed:
+ self.results[host.name]['trap_targets_previous'] = self.get_previous_targets(snmp_config_spec.trapTargets)
+ snmp_config_spec.trapTargets = temp_desired_targets
+ else:
+ changed = True
+ changed_list.append("trap targets")
+ self.results[host.name]['trap_targets_previous'] = self.get_previous_targets(snmp_config_spec.trapTargets)
+ # Doesn't work. Need to reset config instead
+ # snmp_config_spec.trapTargets = []
+ reset_hint = True
+ else:
+ if desired_trap_targets:
+ changed = True
+ changed_list.append("trap targets")
+ self.results[host.name]['trap_targets_previous'] = None
+ desired_targets = []
for target in desired_trap_targets:
- if trap_target.hostName == target.get('hostname'):
- target_found = True
- break
- if not target_found:
+ dest_hostname, dest_port, dest_community = self.check_if_options_are_valid(target)
+ destination = self.build_destination(dest_hostname, dest_port, dest_community)
+ desired_targets.append(destination)
+ snmp_config_spec.trapTargets = desired_targets
+
+ # Check options
+ self.results[host.name]['hw_source'] = hw_source
+ self.results[host.name]['log_level'] = log_level
+ self.results[host.name]['trap_filter'] = trap_filter
+ event_filter_found = False
+ sys_contact_found = False
+ sys_location_found = False
+ if snmp_config_spec.option:
+ for option in snmp_config_spec.option:
+ if option.key == 'EnvEventSource' and option.value != hw_source:
changed = True
- changed_list.append("trap target '%s'" % trap_target.hostName)
- # Configure trap targets if something has changed
- if changed:
- results['trap_targets_previous'] = self.get_previous_targets(snmp_config_spec.trapTargets)
- snmp_config_spec.trapTargets = temp_desired_targets
- else:
+ changed_list.append("HW source")
+ self.results[host.name]['hw_source_previous'] = option.value
+ option.value = hw_source
+ if option.key == 'loglevel' and option.value != log_level:
+ changed = True
+ changed_list.append("log level")
+ self.results[host.name]['log_level_previous'] = option.value
+ option.value = log_level
+ if option.key == 'EventFilter':
+ event_filter_found = True
+ if event_filter and option.value != event_filter:
+ changed = True
+ changed_list.append("trap filter")
+ self.results[host.name]['trap_filter_previous'] = option.value.split(';')
+ option.value = event_filter
+ if option.key == 'syscontact':
+ sys_contact_found = True
+ if sys_contact is not None and option.value != sys_contact:
+ changed = True
+ changed_list.append("sys contact")
+ self.results[host.name]['sys_contact_previous'] = option.value
+ option.value = sys_contact
+ if option.key == 'syslocation':
+ sys_location_found = True
+ if sys_location is not None and option.value != sys_location:
+ changed = True
+ changed_list.append("sys location")
+ self.results[host.name]['sys_location_previous'] = option.value
+ option.value = sys_location
+ if trap_filter and not event_filter_found:
+ changed = True
+ changed_list.append("trap filter")
+ self.results[host.name]['trap_filter_previous'] = []
+ snmp_config_spec.option.append(self.create_option('EventFilter', event_filter))
+ elif not trap_filter and event_filter_found:
changed = True
- changed_list.append("trap targets")
- results['trap_targets_previous'] = self.get_previous_targets(snmp_config_spec.trapTargets)
+ changed_list.append("trap filter")
+ # options = []
+ for option in snmp_config_spec.option:
+ if option.key == 'EventFilter':
+ self.results[host.name]['trap_filter_previous'] = option.value.split(';')
+ # else:
+ # options.append(option)
# Doesn't work. Need to reset config instead
- # snmp_config_spec.trapTargets = []
+ # snmp_config_spec.option = options
reset_hint = True
- else:
- if desired_trap_targets:
+ if sys_contact and not sys_contact_found:
changed = True
- changed_list.append("trap targets")
- results['trap_targets_previous'] = None
- desired_targets = []
- for target in desired_trap_targets:
- dest_hostname, dest_port, dest_community = self.check_if_options_are_valid(target)
- destination = self.build_destination(dest_hostname, dest_port, dest_community)
- desired_targets.append(destination)
- snmp_config_spec.trapTargets = desired_targets
-
- # Check options
- results['hw_source'] = hw_source
- results['log_level'] = log_level
- results['trap_filter'] = trap_filter
- event_filter_found = False
- sys_contact_found = False
- sys_location_found = False
- if snmp_config_spec.option:
- for option in snmp_config_spec.option:
- if option.key == 'EnvEventSource' and option.value != hw_source:
- changed = True
- changed_list.append("HW source")
- results['hw_source_previous'] = option.value
- option.value = hw_source
- if option.key == 'loglevel' and option.value != log_level:
- changed = True
- changed_list.append("log level")
- results['log_level_previous'] = option.value
- option.value = log_level
- if option.key == 'EventFilter':
- event_filter_found = True
- if event_filter and option.value != event_filter:
- changed = True
- changed_list.append("trap filter")
- results['trap_filter_previous'] = option.value.split(';')
- option.value = event_filter
- if option.key == 'syscontact':
- sys_contact_found = True
- if sys_contact is not None and option.value != sys_contact:
- changed = True
- changed_list.append("sys contact")
- results['sys_contact_previous'] = option.value
- option.value = sys_contact
- if option.key == 'syslocation':
- sys_location_found = True
- if sys_location is not None and option.value != sys_location:
- changed = True
- changed_list.append("sys location")
- results['sys_location_previous'] = option.value
- option.value = sys_location
- if trap_filter and not event_filter_found:
- changed = True
- changed_list.append("trap filter")
- results['trap_filter_previous'] = []
- snmp_config_spec.option.append(self.create_option('EventFilter', event_filter))
- elif not trap_filter and event_filter_found:
- changed = True
- changed_list.append("trap filter")
- # options = []
- for option in snmp_config_spec.option:
- if option.key == 'EventFilter':
- results['trap_filter_previous'] = option.value.split(';')
- # else:
- # options.append(option)
- # Doesn't work. Need to reset config instead
- # snmp_config_spec.option = options
- reset_hint = True
- if sys_contact and not sys_contact_found:
- changed = True
- changed_list.append("sys contact")
- results['sys_contact_previous'] = ''
- snmp_config_spec.option.append(self.create_option('syscontact', sys_contact))
- if sys_location and not sys_location_found:
- changed = True
- changed_list.append("sys location")
- results['sys_location_previous'] = ''
- snmp_config_spec.option.append(self.create_option('syslocation', sys_location))
- if changed:
- if snmp_state == 'reset':
- if self.module.check_mode:
- message = "SNMP agent would be reset to factory defaults"
+ changed_list.append("sys contact")
+ self.results[host.name]['sys_contact_previous'] = ''
+ snmp_config_spec.option.append(self.create_option('syscontact', sys_contact))
+ if sys_location and not sys_location_found:
+ changed = True
+ changed_list.append("sys location")
+ self.results[host.name]['sys_location_previous'] = ''
+ snmp_config_spec.option.append(self.create_option('syslocation', sys_location))
+ if changed:
+ if snmp_state == 'reset':
+ if self.module.check_mode:
+ message = "SNMP agent would be reset to factory defaults"
+ else:
+ message = "SNMP agent config reset to factory defaults"
else:
- message = "SNMP agent config reset to factory defaults"
+ if self.module.check_mode:
+ changed_suffix = ' would be changed'
+ else:
+ changed_suffix = ' changed'
+ if len(changed_list) > 2:
+ message = ', '.join(changed_list[:-1]) + ', and ' + str(changed_list[-1])
+ elif len(changed_list) == 2:
+ message = ' and '.join(changed_list)
+ elif len(changed_list) == 1:
+ message = changed_list[0]
+ message = "SNMP " + message + changed_suffix
+ if reset_hint:
+ message += ". Agent reset required!"
+ if not self.module.check_mode:
+ try:
+ snmp_system.ReconfigureSnmpAgent(snmp_config_spec)
+ except vim.fault.NotFound as not_found:
+ self.module.fail_json(
+ msg="Not found : %s" % to_native(not_found)
+ )
+ except vim.fault.InsufficientResourcesFault as insufficient_resources:
+ self.module.fail_json(
+ msg="Insufficient resources : %s" % to_native(insufficient_resources)
+ )
else:
+ message = "SNMP already configured properly"
+ if not snmp_state == 'reset' and send_trap and desired_trap_targets:
+ # Check if there was a change before
+ if changed:
+ message += " and "
+ else:
+ message += ", but "
+ changed = True
if self.module.check_mode:
- changed_suffix = ' would be changed'
+ message = message + "a test trap would be sent"
else:
- changed_suffix = ' changed'
- if len(changed_list) > 2:
- message = ', '.join(changed_list[:-1]) + ', and ' + str(changed_list[-1])
- elif len(changed_list) == 2:
- message = ' and '.join(changed_list)
- elif len(changed_list) == 1:
- message = changed_list[0]
- message = "SNMP " + message + changed_suffix
- if reset_hint:
- message += ". Agent reset required!"
- if not self.module.check_mode:
- try:
- snmp_system.ReconfigureSnmpAgent(snmp_config_spec)
- except vim.fault.NotFound as not_found:
- self.module.fail_json(
- msg="Not found : %s" % to_native(not_found)
- )
- except vim.fault.InsufficientResourcesFault as insufficient_resources:
- self.module.fail_json(
- msg="Insufficient resources : %s" % to_native(insufficient_resources)
- )
- else:
- message = "SNMP already configured properly"
- if not snmp_state == 'reset' and send_trap and desired_trap_targets:
- # Check if there was a change before
- if changed:
- message += " and "
- else:
- message += ", but "
- changed = True
- if self.module.check_mode:
- message = message + "a test trap would be sent"
- else:
- try:
- snmp_system.SendTestNotification()
- message = message + "a test trap was sent"
- except vim.fault.NotFound as not_found:
- self.module.fail_json(
- msg="Error during trap test : Not found : %s" % to_native(not_found)
- )
- except vim.fault.InsufficientResourcesFault as insufficient_resources:
- self.module.fail_json(
- msg="Error during trap test : Insufficient resources : %s" % to_native(insufficient_resources)
- )
- results['changed'] = changed
- results['msg'] = message
-
- self.module.exit_json(**results)
+ try:
+ snmp_system.SendTestNotification()
+ message = message + "a test trap was sent"
+ except vim.fault.NotFound as not_found:
+ self.module.fail_json(
+ msg="Error during trap test : Not found : %s" % to_native(not_found)
+ )
+ except vim.fault.InsufficientResourcesFault as insufficient_resources:
+ self.module.fail_json(
+ msg="Error during trap test : Insufficient resources : %s" % to_native(insufficient_resources)
+ )
+ self.changed = any([self.changed, changed])
+ self.results[host.name]['changed'] = changed
+ self.results[host.name]['msg'] = message
+ self.results['changed'] = self.changed
+ self.module.exit_json(**self.results)
@staticmethod
def create_option(key, value):
@@ -510,6 +555,8 @@ def main():
"""Main"""
argument_spec = vmware_argument_spec()
argument_spec.update(
+ cluster_name=dict(type='str', required=False),
+ esxi_hostname=dict(type='list', elements='str', required=False),
state=dict(type='str', default='disabled', choices=['enabled', 'disabled', 'reset']),
snmp_port=dict(type='int', default=161),
community=dict(type='list', default=[], elements='str'),
@@ -524,9 +571,12 @@ def main():
module = AnsibleModule(
argument_spec=argument_spec,
- supports_check_mode=True
+ supports_check_mode=True,
)
+ if not HAS_PYVMOMI:
+ module.fail_json(msg='pyvmomi required for this module')
+
host_snmp = VmwareHostSnmp(module)
host_snmp.ensure()
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host_sriov.py b/ansible_collections/community/vmware/plugins/modules/vmware_host_sriov.py
index 5277dc6ba..69e391f13 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_host_sriov.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host_sriov.py
@@ -24,13 +24,13 @@ options:
esxi_hostname:
description:
- Name of the host system to work with.
- - This parameter is required if C(cluster_name) is not specified.
+ - This parameter is required if O(cluster_name) is not specified.
- User can specify specific host from the cluster.
type: str
cluster_name:
description:
- Name of the cluster from which all host systems will be used.
- - This parameter is required if C(esxi_hostname) is not specified.
+ - This parameter is required if O(esxi_hostname) is not specified.
type: str
vmnic:
description:
@@ -46,8 +46,8 @@ options:
required: true
sriov_on:
description:
- - optional parameter, related to C(num_virt_func).
- - SR-IOV can be enabled only if C(num_virt_func) > 0.
+ - optional parameter, related to O(num_virt_func).
+ - SR-IOV can be enabled only if O(num_virt_func) > 0.
type: bool
required: false
extends_documentation_fragment:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host_ssl_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_host_ssl_info.py
index 9530e96dd..de3162d4b 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_host_ssl_info.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host_ssl_info.py
@@ -22,13 +22,13 @@ options:
description:
- Name of the cluster.
- SSL thumbprint information about all ESXi host system in the given cluster will be reported.
- - If C(esxi_hostname) is not given, this parameter is required.
+ - If O(esxi_hostname) is not given, this parameter is required.
type: str
esxi_hostname:
description:
- ESXi hostname.
- SSL thumbprint information of this ESXi host system will be reported.
- - If C(cluster_name) is not given, this parameter is required.
+ - If O(cluster_name) is not given, this parameter is required.
type: str
extends_documentation_fragment:
- community.vmware.vmware.documentation
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host_user_manager.py b/ansible_collections/community/vmware/plugins/modules/vmware_host_user_manager.py
index 7a81f5f0a..f2ebaf934 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_host_user_manager.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host_user_manager.py
@@ -15,7 +15,6 @@ author:
- sky-joker (@sky-joker)
description:
- This module can add, update or delete local users on ESXi host.
-version_added: '2.1.0'
options:
esxi_hostname:
description:
@@ -32,7 +31,7 @@ options:
user_password:
description:
- The local user password.
- - If you'd like to update the password, require the I(override_user_password) is true.
+ - If you'd like to update the password, requires O(override_user_password=true).
aliases:
- local_user_password
type: str
@@ -49,8 +48,8 @@ options:
type: bool
state:
description:
- - If set to C(present), add a new local user or update information.
- - If set to C(absent), delete the local user.
+ - If set to V(present), add a new local user or update information.
+ - If set to V(absent), delete the local user.
default: present
type: str
choices:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host_vmhba_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_host_vmhba_info.py
index 5d625b774..178d806a8 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_host_vmhba_info.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host_vmhba_info.py
@@ -15,8 +15,8 @@ module: vmware_host_vmhba_info
short_description: Gathers info about vmhbas available on the given ESXi host
description:
- This module can be used to gather information about vmhbas available on the given ESXi host.
-- If C(cluster_name) is provided, then vmhba information about all hosts from given cluster will be returned.
-- If C(esxi_hostname) is provided, then vmhba information about given host system will be returned.
+- If O(cluster_name) is provided, then vmhba information about all hosts from given cluster will be returned.
+- If O(esxi_hostname) is provided, then vmhba information about given host system will be returned.
author:
- Christian Kotte (@ckotte)
options:
@@ -24,13 +24,13 @@ options:
description:
- Name of the host system to work with.
- Vmhba information about this ESXi server will be returned.
- - This parameter is required if C(cluster_name) is not specified.
+ - This parameter is required if O(cluster_name) is not specified.
type: str
cluster_name:
description:
- Name of the cluster from which all host systems will be used.
- Vmhba information about each ESXi server will be returned for the given cluster.
- - This parameter is required if C(esxi_hostname) is not specified.
+ - This parameter is required if O(esxi_hostname) is not specified.
type: str
extends_documentation_fragment:
- community.vmware.vmware.documentation
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_host_vmnic_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_host_vmnic_info.py
index 02a5ac827..af6bfc6f9 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_host_vmnic_info.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_host_vmnic_info.py
@@ -16,10 +16,8 @@ module: vmware_host_vmnic_info
short_description: Gathers info about vmnics available on the given ESXi host
description:
- This module can be used to gather information about vmnics available on the given ESXi host.
-- If C(cluster_name) is provided, then vmnic information about all hosts from given cluster will be returned.
-- If C(esxi_hostname) is provided, then vmnic information about given host system will be returned.
-- Additional details about vswitch and dvswitch with respective vmnic is also provided which is added in 2.7 version.
-- Additional details about lldp added in 1.11.0
+- If O(cluster_name) is provided, then vmnic information about all hosts from given cluster will be returned.
+- If O(esxi_hostname) is provided, then vmnic information about given host system will be returned.
author:
- Abhijeet Kasurde (@Akasurde)
- Christian Kotte (@ckotte)
@@ -43,13 +41,13 @@ options:
description:
- Name of the host system to work with.
- Vmnic information about this ESXi server will be returned.
- - This parameter is required if C(cluster_name) is not specified.
+ - This parameter is required if O(cluster_name) is not specified.
type: str
cluster_name:
description:
- Name of the cluster from which all host systems will be used.
- Vmnic information about each ESXi server will be returned for the given cluster.
- - This parameter is required if C(esxi_hostname) is not specified.
+ - This parameter is required if O(esxi_hostname) is not specified.
type: str
extends_documentation_fragment:
- community.vmware.vmware.documentation
@@ -81,9 +79,6 @@ hosts_vmnics_info:
description:
- dict with hostname as key and dict with vmnics information as value.
- for C(num_vmnics), only NICs starting with vmnic are counted. NICs like vusb* are not counted.
- - details about vswitch and dvswitch was added in version 2.7.
- - details about vmnics was added in version 2.8.
- - details about lldp was added in version 1.11.0
returned: hosts_vmnics_info
type: dict
sample:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_local_role_manager.py b/ansible_collections/community/vmware/plugins/modules/vmware_local_role_manager.py
index e4c672d2c..cebf4000e 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_local_role_manager.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_local_role_manager.py
@@ -37,21 +37,21 @@ options:
state:
description:
- Indicate desired state of the role.
- - If the role already exists when C(state=present), the role info is updated.
+ - If the role already exists when V(present), the role info is updated.
choices: ['present', 'absent']
default: present
type: str
force_remove:
description:
- - If set to C(false) then prevents the role from being removed if any permissions are using it.
+ - If set to V(false) then prevents the role from being removed if any permissions are using it.
default: false
type: bool
action:
description:
- This parameter is only valid while updating an existing role with privileges.
- - C(add) will add the privileges to the existing privilege list.
- - C(remove) will remove the privileges from the existing privilege list.
- - C(set) will replace the privileges of the existing privileges with user defined list of privileges.
+ - V(add) will add the privileges to the existing privilege list.
+ - V(remove) will remove the privileges from the existing privilege list.
+ - V(set) will replace the privileges of the existing privileges with user defined list of privileges.
default: set
choices: [ add, remove, set ]
type: str
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_local_user_manager.py b/ansible_collections/community/vmware/plugins/modules/vmware_local_user_manager.py
index 3a95ae2d2..065e8e0a0 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_local_user_manager.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_local_user_manager.py
@@ -38,7 +38,7 @@ options:
type: str
state:
description:
- - Indicate desired state of the user. If the user already exists when C(state=present), the user info is updated
+ - Indicate desired state of the user. If the user already exists when V(present), the user info is updated
choices: ['present', 'absent']
default: present
type: str
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_maintenancemode.py b/ansible_collections/community/vmware/plugins/modules/vmware_maintenancemode.py
index ed198b7cf..faeda3a31 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_maintenancemode.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_maintenancemode.py
@@ -38,7 +38,7 @@ options:
type: str
evacuate:
description:
- - If set to C(true), evacuate all powered off VMs.
+ - If set to V(true), evacuate all powered off VMs.
default: false
required: false
type: bool
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_migrate_vmk.py b/ansible_collections/community/vmware/plugins/modules/vmware_migrate_vmk.py
index f14fac601..b50ba7f5d 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_migrate_vmk.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_migrate_vmk.py
@@ -50,7 +50,6 @@ options:
required: true
type: str
migrate_vlan_id:
- version_added: '2.4.0'
description:
- VLAN to use for the VMK interface when migrating from VDS to VSS
- Will be ignored when migrating from VSS to VDS
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_object_custom_attributes_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_object_custom_attributes_info.py
index 465e84fbf..7d2fa00e5 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_object_custom_attributes_info.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_object_custom_attributes_info.py
@@ -43,7 +43,7 @@ options:
moid:
description:
- Managed Object ID of the instance to get if known, this is a unique identifier only within a single vCenter instance.
- - This is required if C(object_name) is not supplied.
+ - This is required if O(object_name) is not supplied.
type: str
extends_documentation_fragment:
- community.vmware.vmware.documentation
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_object_rename.py b/ansible_collections/community/vmware/plugins/modules/vmware_object_rename.py
index 0827c9369..8f5cbb752 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_object_rename.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_object_rename.py
@@ -41,12 +41,12 @@ options:
object_name:
description:
- Name of the object to work with.
- - Mutually exclusive with C(object_moid).
+ - Mutually exclusive with O(object_moid).
type: str
object_moid:
description:
- Managed object id of the VMware object to work with.
- - Mutually exclusive with C(object_name).
+ - Mutually exclusive with O(object_name).
type: str
new_name:
description:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_object_role_permission.py b/ansible_collections/community/vmware/plugins/modules/vmware_object_role_permission.py
index 98bd2b649..f05a3a5ff 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_object_role_permission.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_object_role_permission.py
@@ -26,19 +26,19 @@ options:
role:
description:
- The role to be assigned permission.
- - User can also specify role name presented in Web UI. Supported added in 1.5.0.
+ - User can also specify role name presented in Web UI.
required: true
type: str
principal:
description:
- The user to be assigned permission.
- - Required if C(group) is not specified.
+ - Required if O(group) is not specified.
- If specifying domain user, required separator of domain uses backslash.
type: str
group:
description:
- The group to be assigned permission.
- - Required if C(principal) is not specified.
+ - Required if O(principal) is not specified.
type: str
object_name:
description:
@@ -62,8 +62,8 @@ options:
state:
description:
- Indicate desired state of the object's permission.
- - When C(state=present), the permission will be added if it doesn't already exist.
- - When C(state=absent), the permission is removed if it exists.
+ - When V(present), the permission will be added if it doesn't already exist.
+ - When V(absent), the permission is removed if it exists.
choices: ['present', 'absent']
default: present
type: str
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_object_role_permission_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_object_role_permission_info.py
index 08b668798..d6049ad7b 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_object_role_permission_info.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_object_role_permission_info.py
@@ -33,7 +33,7 @@ options:
object_name:
description:
- The object name to assigned permission.
- - Mutually exclusive with I(moid).
+ - Mutually exclusive with O(moid).
type: str
object_type:
description:
@@ -47,7 +47,7 @@ options:
moid:
description:
- Managed object ID for the given object.
- - Mutually exclusive with I(object_name).
+ - Mutually exclusive with O(object_name).
aliases: ['object_moid']
type: 'str'
extends_documentation_fragment:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_portgroup.py b/ansible_collections/community/vmware/plugins/modules/vmware_portgroup.py
index 7f5e57d83..c4e569b87 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_portgroup.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_portgroup.py
@@ -87,13 +87,13 @@ options:
type: list
description:
- List of active adapters used for load balancing.
- - All vmnics are used as active adapters if C(active_adapters) and C(standby_adapters) are not defined.
+ - All vmnics are used as active adapters if O(teaming.active_adapters) and O(teaming.standby_adapters) are not defined.
elements: str
standby_adapters:
type: list
description:
- List of standby adapters used for failover.
- - All vmnics are used as active adapters if C(active_adapters) and C(standby_adapters) are not defined.
+ - All vmnics are used as active adapters if O(teaming.active_adapters) and O(teaming.standby_adapters) are not defined.
elements: str
required: false
aliases: [ 'teaming_policy' ]
@@ -120,13 +120,13 @@ options:
description:
- Name of cluster name for host membership.
- Portgroup will be created on all hosts of the given cluster.
- - This option is required if C(hosts) is not specified.
+ - This option is required if O(hosts) is not specified.
aliases: [ 'cluster' ]
type: str
hosts:
description:
- List of name of host or hosts on which portgroup needs to be added.
- - This option is required if C(cluster_name) is not specified.
+ - This option is required if O(cluster_name) is not specified.
aliases: [ esxi_hostname ]
type: list
elements: str
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_portgroup_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_portgroup_info.py
index b94be38db..6d3fa00ab 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_portgroup_info.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_portgroup_info.py
@@ -30,12 +30,12 @@ options:
description:
- Name of the cluster.
- Info will be returned for all hostsystem belonging to this cluster name.
- - If C(esxi_hostname) is not given, this parameter is required.
+ - If O(esxi_hostname) is not given, this parameter is required.
type: str
esxi_hostname:
description:
- ESXi hostname to gather information from.
- - If C(cluster_name) is not given, this parameter is required.
+ - If O(cluster_name) is not given, this parameter is required.
type: str
extends_documentation_fragment:
- community.vmware.vmware.documentation
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_resource_pool.py b/ansible_collections/community/vmware/plugins/modules/vmware_resource_pool.py
index 2ed81f821..319542c54 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_resource_pool.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_resource_pool.py
@@ -26,21 +26,21 @@ options:
cluster:
description:
- Name of the cluster to configure the resource pool.
- - This parameter is required if C(esxi_hostname) or C(parent_resource_pool) is not specified.
- - The C(cluster), C(esxi_hostname) and C(parent_resource_pool) parameters are mutually exclusive.
+ - This parameter is required if O(esxi_hostname) or O(parent_resource_pool) is not specified.
+ - The O(cluster), O(esxi_hostname) and O(parent_resource_pool) parameters are mutually exclusive.
type: str
esxi_hostname:
description:
- Name of the host to configure the resource pool.
- The host must not be member of a cluster.
- - This parameter is required if C(cluster) or C(parent_resource_pool) is not specified.
- - The C(cluster), C(esxi_hostname) and C(parent_resource_pool) parameters are mutually exclusive.
+ - This parameter is required if O(cluster) or O(parent_resource_pool) is not specified.
+ - The O(cluster), O(esxi_hostname) and O(parent_resource_pool) parameters are mutually exclusive.
type: str
parent_resource_pool:
description:
- Name of the parent resource pool.
- - This parameter is required if C(cluster) or C(esxi_hostname) is not specified.
- - The C(cluster), C(esxi_hostname) and C(parent_resource_pool) parameters are mutually exclusive.
+ - This parameter is required if O(cluster) or O(esxi_hostname) is not specified.
+ - The O(cluster), O(esxi_hostname) and O(parent_resource_pool) parameters are mutually exclusive.
type: str
resource_pool:
description:
@@ -76,7 +76,7 @@ options:
cpu_allocation_shares:
description:
- The number of cpu shares allocated.
- - This value is only set if I(cpu_shares) is set to C(custom).
+ - This value is only set if O(cpu_shares=custom).
type: int
default: 4000
mem_expandable_reservations:
@@ -108,7 +108,7 @@ options:
mem_allocation_shares:
description:
- The number of memory shares allocated.
- - This value is only set if I(mem_shares) is set to C(custom).
+ - This value is only set if O(mem_shares=custom).
type: int
default: 163840
state:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_tag.py b/ansible_collections/community/vmware/plugins/modules/vmware_tag.py
index cf6e07a3c..c37f310a7 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_tag.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_tag.py
@@ -32,8 +32,8 @@ options:
tag_description:
description:
- The tag description.
- - This is required only if C(state) is set to C(present).
- - This parameter is ignored, when C(state) is set to C(absent).
+ - This is required only if O(state=present).
+ - This parameter is ignored, when O(state=absent).
- Process of updating tag only allows description change.
required: false
default: ''
@@ -43,13 +43,13 @@ options:
description:
- The unique ID generated by vCenter should be used to.
- User can get this unique ID from facts module.
- - Required if C(category_name) is not set.
+ - Required if O(category_name) is not set.
required: false
type: str
category_name:
description:
- The name of category.
- - Required if C(category_id) is not set.
+ - Required if O(category_id) is not set.
required: false
aliases: [ 'category' ]
type: str
@@ -57,10 +57,10 @@ options:
state:
description:
- The state of tag.
- - If set to C(present) and tag does not exists, then tag is created.
- - If set to C(present) and tag exists, then tag is updated.
- - If set to C(absent) and tag exists, then tag is deleted.
- - If set to C(absent) and tag does not exists, no action is taken.
+ - If set to V(present) and tag does not exists, then tag is created.
+ - If set to V(present) and tag exists, then tag is updated.
+ - If set to V(absent) and tag exists, then tag is deleted.
+ - If set to V(absent) and tag does not exists, no action is taken.
required: false
default: 'present'
choices: [ 'present', 'absent' ]
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_tag_manager.py b/ansible_collections/community/vmware/plugins/modules/vmware_tag_manager.py
index 29ed32539..109188b45 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_tag_manager.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_tag_manager.py
@@ -29,16 +29,16 @@ options:
- List of tag(s) to be managed.
- User can also specify category name by specifying colon separated value. For example, "category_name:tag_name".
- User can also specify tag and category as dict, when tag or category contains colon.
- See example for more information. Added in version 2.10.
+ See example for more information.
- User can skip category name if you have unique tag names.
required: true
type: list
elements: raw
state:
description:
- - If C(state) is set to C(add) or C(present) will add the tags to the existing tag list of the given object.
- - If C(state) is set to C(remove) or C(absent) will remove the tags from the existing tag list of the given object.
- - If C(state) is set to C(set) will replace the tags of the given objects with the user defined list of tags.
+ - If set to V(add) or V(present) will add the tags to the existing tag list of the given object.
+ - If set to V(remove) or V(absent) will remove the tags from the existing tag list of the given object.
+ - If set to V(set) will replace the tags of the given objects with the user defined list of tags.
default: add
choices: [ present, absent, add, remove, set ]
type: str
@@ -62,13 +62,13 @@ options:
description:
- Name of the object to work with.
- For DistributedVirtualPortgroups the format should be "switch_name:portgroup_name"
- - Required if C(moid) is not set.
+ - Required if O(moid) is not set.
required: false
type: str
moid:
description:
- Managed object ID for the given object.
- - Required if C(object_name) is not set.
+ - Required if O(object_name) is not set.
required: false
type: str
extends_documentation_fragment:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_target_canonical_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_target_canonical_info.py
index 26aa81014..8ba7cfbbe 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_target_canonical_info.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_target_canonical_info.py
@@ -30,13 +30,13 @@ options:
description:
- Name of the cluster.
- Info about all SCSI devices for all host system in the given cluster is returned.
- - This parameter is required, if C(esxi_hostname) is not provided.
+ - This parameter is required, if O(esxi_hostname) is not provided.
type: str
esxi_hostname:
description:
- Name of the ESXi host system.
- Info about all SCSI devices for the given ESXi host system is returned.
- - This parameter is required, if C(cluster_name) is not provided.
+ - This parameter is required, if O(cluster_name) is not provided.
type: str
extends_documentation_fragment:
- community.vmware.vmware.documentation
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_vasa.py b/ansible_collections/community/vmware/plugins/modules/vmware_vasa.py
new file mode 100644
index 000000000..405cc795a
--- /dev/null
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_vasa.py
@@ -0,0 +1,260 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Pure Storage, Inc.
+# Author(s): Eugenio Grosso, <eugenio.grosso@purestorage.com>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+
+DOCUMENTATION = r'''
+module: vmware_vasa
+version_added: '3.8.0'
+short_description: Manage VMware Virtual Volumes storage provider
+author:
+ - Eugenio Grosso (@genegr) <eugenio.grosso@purestorage.com>
+description:
+ - This module can be used to register and unregister a VASA provider
+options:
+ vasa_name:
+ description:
+ - The name of the VASA provider to be managed.
+ type: str
+ required: True
+ vasa_url:
+ description:
+ - The url of the VASA provider to be managed.
+ - This parameter is required if O(state=present)
+ type: str
+ required: True
+ vasa_username:
+ description:
+ - The user account to connect to the VASA provider.
+ - This parameter is required if O(state=present)
+ type: str
+ vasa_password:
+ description:
+ - The password of the user account to connect to the VASA provider.
+ - This parameter is required if O(state=present)
+ type: str
+ vasa_certificate:
+ description:
+ - The SSL certificate of the VASA provider.
+ - This parameter is required if O(state=present)
+ type: str
+ state:
+ description:
+ - Create (V(present)) or remove (V(absent)) a VASA provider.
+ choices: [ absent, present ]
+ default: present
+ type: str
+seealso:
+- module: community.vmware.vmware_vasa_info
+extends_documentation_fragment:
+- community.vmware.vmware.documentation
+'''
+
+EXAMPLES = r'''
+- name: Create Cluster
+ community.vmware.vmware_cluster:
+ hostname: "{{ vcenter_hostname }}"
+ username: "{{ vcenter_username }}"
+ password: "{{ vcenter_password }}"
+ vasa_name: "{{ vasa_name }}"
+ vasa_url: "{{ vasa_url }}"
+ vasa_username: "{{ vasa_username }}"
+ vasa_password: "{{ vasa_password }}"
+ vasa_certificate: "{{ vasa_certificate }}"
+ state: present
+ delegate_to: localhost
+
+- name: Unregister VASA provider
+ community.vmware.vmware_vasa:
+ hostname: "{{ vcenter_hostname }}"
+ username: "{{ vcenter_username }}"
+ password: "{{ vcenter_password }}"
+ vasa_name: "{{ vasa_name }}"
+ state: absent
+ delegate_to: localhost
+'''
+
+RETURN = r'''
+'''
+try:
+ from pyVmomi import sms
+except ImportError:
+ pass
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.community.vmware.plugins.module_utils.vmware_sms import (
+ SMS,
+ TaskError,
+ wait_for_sms_task)
+from ansible_collections.community.vmware.plugins.module_utils.vmware import vmware_argument_spec
+from ansible.module_utils._text import to_native
+
+
+class VMwareVASA(SMS):
+ def __init__(self, module):
+ super(VMwareVASA, self).__init__(module)
+ self.vasa_name = module.params['vasa_name']
+ self.vasa_url = module.params['vasa_url']
+ self.vasa_username = module.params['vasa_username']
+ self.vasa_password = module.params['vasa_password']
+ self.vasa_certificate = module.params['vasa_certificate']
+ self.desired_state = module.params['state']
+ self.storage_manager = None
+
+ def process_state(self):
+ """
+ Manage internal states of VASA provider
+ """
+ vasa_states = {
+ 'absent': {
+ 'present': self.state_unregister_vasa,
+ 'absent': self.state_exit_unchanged,
+ },
+ 'present': {
+ 'present': self.state_exit_unchanged,
+ 'absent': self.state_register_vasa,
+ }
+ }
+ # Initialize connection to SMS manager
+ self.get_sms_connection()
+ current_state = self.check_vasa_configuration()
+ # Based on the desired_state and the current_state call
+ # the appropriate method from the dictionary
+ vasa_states[self.desired_state][current_state]()
+
+ def state_register_vasa(self):
+ """
+ Register VASA provider with vcenter
+ """
+ changed, result = True, None
+ vasa_provider_spec = sms.provider.VasaProviderSpec()
+ vasa_provider_spec.name = self.vasa_name
+ vasa_provider_spec.username = self.vasa_username
+ vasa_provider_spec.password = self.vasa_password
+ vasa_provider_spec.url = self.vasa_url
+ vasa_provider_spec.certificate = self.vasa_certificate
+ try:
+ if not self.module.check_mode:
+ task = self.storage_manager.RegisterProvider_Task(vasa_provider_spec)
+ changed, result = wait_for_sms_task(task)
+ # This second step is required to register self-signed certs,
+ # since the previous task returns the certificate back waiting
+ # for confirmation
+ if isinstance(result, sms.fault.CertificateNotTrusted):
+ vasa_provider_spec.certificate = result.certificate
+ task = self.storage_manager.RegisterProvider_Task(vasa_provider_spec)
+ changed, result = wait_for_sms_task(task)
+ if isinstance(result, sms.provider.VasaProvider):
+ provider_info = result.QueryProviderInfo()
+ temp_provider_info = {
+ 'name': provider_info.name,
+ 'uid': provider_info.uid,
+ 'description': provider_info.description,
+ 'version': provider_info.version,
+ 'certificate_status': provider_info.certificateStatus,
+ 'url': provider_info.url,
+ 'status': provider_info.status,
+ 'related_storage_array': []
+ }
+ for a in provider_info.relatedStorageArray:
+ temp_storage_array = {
+ 'active': str(a.active),
+ 'array_id': a.arrayId,
+ 'manageable': str(a.manageable),
+ 'priority': str(a.priority)
+ }
+ temp_provider_info['related_storage_array'].append(temp_storage_array)
+ result = temp_provider_info
+
+ self.module.exit_json(changed=changed, result=result)
+ except TaskError as task_err:
+ self.module.fail_json(msg="Failed to register VASA provider"
+ " due to task exception %s" % to_native(task_err))
+ except Exception as generic_exc:
+ self.module.fail_json(msg="Failed to register VASA"
+ " due to generic exception %s" % to_native(generic_exc))
+
+ def state_unregister_vasa(self):
+ """
+ Unregister VASA provider
+ """
+ changed, result = True, None
+
+ try:
+ if not self.module.check_mode:
+ uid = self.vasa_provider_info.uid
+ task = self.storage_manager.UnregisterProvider_Task(uid)
+ changed, result = wait_for_sms_task(task)
+ self.module.exit_json(changed=changed, result=result)
+ except Exception as generic_exc:
+ self.module.fail_json(msg="Failed to unregister VASA"
+ " due to generic exception %s" % to_native(generic_exc))
+
+ def state_exit_unchanged(self):
+ """
+ Exit without any change
+ """
+ self.module.exit_json(changed=False)
+
+ def check_vasa_configuration(self):
+ """
+ Check VASA configuration
+ Returns: 'Present' if VASA provider exists, else 'absent'
+
+ """
+ self.vasa_provider_info = None
+ self.storage_manager = self.sms_si.QueryStorageManager()
+ storage_providers = self.storage_manager.QueryProvider()
+
+ try:
+ for provider in storage_providers:
+ provider_info = provider.QueryProviderInfo()
+ if provider_info.name == self.vasa_name:
+ if provider_info.url != self.vasa_url:
+ raise Exception("VASA provider '%s' URL '%s' "
+ "is inconsistent with task parameter '%s'"
+ % (self.vasa_name, provider_info.url, self.vasa_url))
+ self.vasa_provider_info = provider_info
+ break
+ if self.vasa_provider_info is None:
+ return 'absent'
+ return 'present'
+ except Exception as generic_exc:
+ self.module.fail_json(msg="Failed to check configuration"
+ " due to generic exception %s" % to_native(generic_exc))
+
+
+def main():
+ argument_spec = vmware_argument_spec()
+ argument_spec.update(dict(
+ vasa_name=dict(type='str', required=True),
+ vasa_url=dict(type='str', required=True),
+ vasa_username=dict(type='str'),
+ vasa_password=dict(type='str', no_log=True),
+ vasa_certificate=dict(type='str'),
+ state=dict(type='str',
+ default='present',
+ choices=['absent', 'present']),
+ ))
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ['state', 'present', ['vasa_username', 'vasa_password', 'vasa_certificate']]
+ ]
+ )
+
+ vmware_vasa = VMwareVASA(module)
+ vmware_vasa.process_state()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_vasa_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_vasa_info.py
new file mode 100644
index 000000000..5d182cf1b
--- /dev/null
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_vasa_info.py
@@ -0,0 +1,116 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Pure Storage, Inc.
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+
+DOCUMENTATION = r'''
+---
+module: vmware_vasa_info
+version_added: '3.8.0'
+short_description: Gather information about vSphere VASA providers.
+description:
+- Returns basic information on the vSphere VASA providers registered in the
+ vcenter.
+author:
+- Eugenio Grosso (@genegr) <eugenio.grosso@purestorage.com>
+extends_documentation_fragment:
+- community.vmware.vmware.documentation
+
+'''
+
+EXAMPLES = r'''
+- name: Get VASA providers info
+ community.vmware.vmware_vasa_info:
+ hostname: '{{ vcenter_hostname }}'
+ username: '{{ vcenter_username }}'
+ password: '{{ vcenter_password }}'
+ delegate_to: localhost
+ register: providers
+'''
+
+RETURN = r'''
+vasa_providers:
+ description: list of dictionary of VASA info
+ returned: success
+ type: list
+ sample: [
+ {
+ "certificate_status": "valid",
+ "description": "IOFILTER VASA Provider on host host01.domain.local",
+ "name": "IOFILTER Provider host01.domain.local",
+ "related_storage_array": [
+ {
+ "active": "True",
+ "array_id": "IOFILTERS:616d4715-7de2-7be2-997a-10f920c5fdbe",
+ "manageable": "True",
+ "priority": "1"
+ }
+ ],
+ "status": "online",
+ "uid": "02e10bc5-dd77-4ce4-9100-5aee44e7abaa",
+ "url": "https://host01.domain.local:9080/version.xml",
+ "version": "1.0"
+ },
+ ]
+'''
+
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.community.vmware.plugins.module_utils.vmware_sms import SMS
+from ansible_collections.community.vmware.plugins.module_utils.vmware import vmware_argument_spec
+
+
+class SMSClient(SMS):
+ def __init__(self, module):
+ super(SMSClient, self).__init__(module)
+
+ def get_vasa_provider_info(self):
+ self.get_sms_connection()
+
+ results = dict(changed=False, vasa_providers=[])
+ storage_manager = self.sms_si.QueryStorageManager()
+ storage_providers = storage_manager.QueryProvider()
+
+ for provider in storage_providers:
+ provider_info = provider.QueryProviderInfo()
+ temp_provider_info = {
+ 'name': provider_info.name,
+ 'uid': provider_info.uid,
+ 'description': provider_info.description,
+ 'version': provider_info.version,
+ 'certificate_status': provider_info.certificateStatus,
+ 'url': provider_info.url,
+ 'status': provider_info.status,
+ 'related_storage_array': []
+ }
+ for a in provider_info.relatedStorageArray:
+ temp_storage_array = {
+ 'active': str(a.active),
+ 'array_id': a.arrayId,
+ 'manageable': str(a.manageable),
+ 'priority': str(a.priority)
+ }
+ temp_provider_info['related_storage_array'].append(temp_storage_array)
+
+ results['vasa_providers'].append(temp_provider_info)
+
+ self.module.exit_json(**results)
+
+
+def main():
+ argument_spec = vmware_argument_spec()
+
+ module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)
+
+ sms_client = SMSClient(module)
+ sms_client.get_vasa_provider_info()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_vc_infraprofile_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_vc_infraprofile_info.py
index 7a50da32b..a4312e62e 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_vc_infraprofile_info.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_vc_infraprofile_info.py
@@ -42,13 +42,13 @@ options:
config_path:
description:
- Config file path which contains infra profile config JSON data, supports both relative and absolute path.
- - This parameter is required only when C(import),C(validate) APIs are being used.
+ - This parameter is required only when V(import),V(validate) APIs are being used.
type: str
required: false
profiles:
description:
- A list of profile names to be exported, imported, and validated.
- - This parameter is not required while running for List API, not for C(export),C(import) and C(validate).
+ - This parameter is not required while running for List API, not for V(export),V(import) and V(validate).
type: str
required: false
description:
@@ -147,7 +147,7 @@ import_profile:
'''
from ansible.module_utils.basic import AnsibleModule
-from ansible_collections.community.vmware.plugins.module_utils.version import LooseVersion
+from ansible.module_utils.compat.version import LooseVersion
from ansible_collections.community.vmware.plugins.module_utils.vmware_rest_client import VmwareRestClient
from ansible_collections.community.vmware.plugins.module_utils.vmware import PyVmomi
import json
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_vcenter_settings.py b/ansible_collections/community/vmware/plugins/modules/vmware_vcenter_settings.py
index db3a35ab0..eb7709f86 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_vcenter_settings.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_vcenter_settings.py
@@ -15,7 +15,7 @@ module: vmware_vcenter_settings
short_description: Configures general settings on a vCenter server
description:
- This module can be used to configure the vCenter server general settings (except the statistics).
-- The statistics can be configured with the module C(vmware_vcenter_statistics).
+- The statistics can be configured with the module M(community.vmware.vmware_vcenter_statistics).
author:
- Christian Kotte (@ckotte)
options:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_vcenter_settings_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_vcenter_settings_info.py
index cdf033e3a..3936cc770 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_vcenter_settings_info.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_vcenter_settings_info.py
@@ -33,7 +33,7 @@ options:
- ' properties: ['
- ' "config.workflow.port"'
- ' ]'
- - Only valid when C(schema) is C(vsphere).
+ - Only valid when O(schema=vsphere).
type: list
elements: str
extends_documentation_fragment:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_vcenter_statistics.py b/ansible_collections/community/vmware/plugins/modules/vmware_vcenter_statistics.py
index 9b8415449..ad3821d1c 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_vcenter_statistics.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_vcenter_statistics.py
@@ -15,7 +15,7 @@ module: vmware_vcenter_statistics
short_description: Configures statistics on a vCenter server
description:
- This module can be used to configure the vCenter server statistics.
-- The remaining settings can be configured with the module C(vmware_vcenter_settings).
+- The remaining settings can be configured with the module M(community.vmware.vmware_vcenter_settings).
author:
- Christian Kotte (@ckotte)
options:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_vm_config_option.py b/ansible_collections/community/vmware/plugins/modules/vmware_vm_config_option.py
index 171fd476e..fd1e67837 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_vm_config_option.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_vm_config_option.py
@@ -32,13 +32,13 @@ options:
cluster_name:
description:
- Name of the cluster.
- - If C(esxi_hostname) is not given, this parameter is required.
+ - If O(esxi_hostname) is not given, this parameter is required.
type: str
esxi_hostname:
description:
- ESXi hostname.
- Obtain VM configure options on this ESXi host.
- - If C(cluster_name) is not given, this parameter is required.
+ - If O(cluster_name) is not given, this parameter is required.
type: str
get_hardware_versions:
description:
@@ -49,25 +49,25 @@ options:
get_guest_os_ids:
description:
- Return the list of guest OS IDs supported on the specified entity.
- - If C(hardware_version) is set, will return the corresponding guest OS ID list supported, or will return the
+ - If O(hardware_version) is set, will return the corresponding guest OS ID list supported, or will return the
guest OS ID list for the default hardware version.
type: bool
default: false
get_config_options:
description:
- - Return the dict of VM recommended config options for guest ID specified by C(guest_id) with hardware version
- specified by C(hardware_version) or the default hardware version.
- - When set to True, C(guest_id) must be set.
+ - Return the dict of VM recommended config options for guest ID specified by O(guest_id) with hardware version
+ specified by O(hardware_version) or the default hardware version.
+ - When set to V(true), O(guest_id) must be set.
type: bool
default: false
guest_id:
description:
- - The guest OS ID from the returned list when C(get_guest_os_ids) is set to C(true), e.g., 'rhel8_64Guest'.
- - This parameter must be set when C(get_config_options) is set to C(true).
+ - The guest OS ID from the returned list when O(get_guest_os_ids=true), e.g., 'rhel8_64Guest'.
+ - This parameter must be set when O(get_config_options=true).
type: str
hardware_version:
description:
- - The hardware version from the returned list when C(get_hardware_versions) is set to C(true), e.g., 'vmx-19'.
+ - The hardware version from the returned list when O(get_hardware_versions=true), e.g., 'vmx-19'.
type: str
extends_documentation_fragment:
- community.vmware.vmware.documentation
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_vm_host_drs_rule.py b/ansible_collections/community/vmware/plugins/modules/vmware_vm_host_drs_rule.py
index 68f1dc629..a63f5f5c2 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_vm_host_drs_rule.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_vm_host_drs_rule.py
@@ -23,15 +23,15 @@ options:
affinity_rule:
default: true
description:
- - "If set to C(true), the DRS rule will be an Affinity rule."
- - "If set to C(false), the DRS rule will be an Anti-Affinity rule."
- - "Effective only if C(state) is set to C(present)."
+ - "If set to V(true), the DRS rule will be an Affinity rule."
+ - "If set to V(false), the DRS rule will be an Anti-Affinity rule."
+ - "Effective only if O(state=present)."
type: bool
datacenter:
aliases:
- datacenter_name
description:
- - "Datacenter to search for given cluster. If not set, we use first cluster we encounter with C(cluster_name)."
+ - "Datacenter to search for given cluster. If not set, we use first cluster we encounter with O(cluster_name)."
required: false
type: str
cluster_name:
@@ -47,19 +47,19 @@ options:
enabled:
default: false
description:
- - "If set to C(true), the DRS rule will be enabled."
- - "Effective only if C(state) is set to C(present)."
+ - "If set to V(true), the DRS rule will be enabled."
+ - "Effective only if O(state=present)."
type: bool
host_group_name:
description:
- "Name of Host group to use with rule."
- - "Effective only if C(state) is set to C(present)."
+ - "Effective only if O(state=present)."
type: str
mandatory:
default: false
description:
- - "If set to C(true), the DRS rule will be mandatory."
- - "Effective only if C(state) is set to C(present)."
+ - "If set to V(true), the DRS rule will be mandatory."
+ - "Effective only if O(state=present)."
type: bool
state:
choices:
@@ -67,13 +67,13 @@ options:
- absent
default: present
description:
- - "If set to C(present) and the rule does not exist then the rule will be created."
- - "If set to C(absent) and the rule exists then the rule will be deleted."
+ - "If set to V(present) and the rule does not exist then the rule will be created."
+ - "If set to V(absent) and the rule exists then the rule will be deleted."
type: str
vm_group_name:
description:
- "Name of VM group to use with rule."
- - "Effective only if C(state) is set to C(present)."
+ - "Effective only if O(state=present)."
type: str
short_description: "Creates vm/host group in a given cluster"
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_vm_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_vm_info.py
index 142cd3b0b..20f89e7cc 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_vm_info.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_vm_info.py
@@ -17,27 +17,23 @@ module: vmware_vm_info
short_description: Return basic info pertaining to a VMware machine guest
description:
- Return basic information pertaining to a vSphere or ESXi virtual machine guest.
-- Cluster name as fact is added in version 2.7.
author:
- Joseph Callen (@jcpowermac)
- Abhijeet Kasurde (@Akasurde)
- Fedor Vompe (@sumkincpp)
-notes:
-- Fact about C(moid) added in VMware collection 1.4.0.
-- Fact about C(datastore_url) is added in VMware collection 1.18.0.
options:
vm_type:
description:
- - If set to C(vm), then information are gathered for virtual machines only.
- - If set to C(template), then information are gathered for virtual machine templates only.
- - If set to C(all), then information are gathered for all virtual machines and virtual machine templates.
+ - If set to V(vm), then information are gathered for virtual machines only.
+ - If set to V(template), then information are gathered for virtual machine templates only.
+ - If set to V(all), then information are gathered for all virtual machines and virtual machine templates.
required: false
default: 'all'
choices: [ all, vm, template ]
type: str
show_attribute:
description:
- - Attributes related to VM guest shown in information only when this is set C(true).
+ - Attributes related to VM guest shown in information only when this is set V(true).
default: false
type: bool
folder:
@@ -56,25 +52,25 @@ options:
type: str
show_cluster:
description:
- - Tags virtual machine's cluster is shown if set to C(true).
+ - Tags virtual machine's cluster is shown if set to V(true).
version_added: '3.5.0'
default: true
type: bool
show_datacenter:
description:
- - Tags virtual machine's datacenter is shown if set to C(true).
+ - Tags virtual machine's datacenter is shown if set to V(true).
version_added: '3.5.0'
default: true
type: bool
show_datastore:
description:
- - Tags virtual machine's datastore is shown if set to C(true).
+ - Tags virtual machine's datastore is shown if set to V(true).
version_added: '3.5.0'
default: true
type: bool
show_esxi_hostname:
description:
- - Tags virtual machine's ESXi host is shown if set to C(true).
+ - Tags virtual machine's ESXi host is shown if set to V(true).
version_added: '3.5.0'
default: true
type: bool
@@ -86,29 +82,28 @@ options:
type: bool
show_mac_address:
description:
- - Tags virtual machine's mac address is shown if set to C(true).
+ - Tags virtual machine's mac address is shown if set to V(true).
version_added: '3.5.0'
default: true
type: bool
show_net:
description:
- - Tags virtual machine's network is shown if set to C(true).
+ - Tags virtual machine's network is shown if set to V(true).
version_added: '3.5.0'
default: true
type: bool
show_resource_pool:
description:
- - Tags virtual machine's resource pool is shown if set to C(true).
+ - Tags virtual machine's resource pool is shown if set to V(true).
version_added: '3.5.0'
default: true
type: bool
show_tag:
description:
- - Tags related to virtual machine are shown if set to C(true).
+ - Tags related to virtual machine are shown if set to V(true).
default: false
type: bool
show_allocated:
- version_added: '2.5.0'
description:
- Allocated storage in byte and memory in MB are shown if it set to True.
default: false
@@ -254,7 +249,7 @@ virtual_machines:
"vm_network": {
"00:50:56:87:a5:9a": {
"ipv4": [
- "10.76.33.228"
+ "10.76.33.228/24"
],
"ipv6": []
}
@@ -357,11 +352,12 @@ class VmwareVmInfo(PyVmomi):
net_dict[device.macAddress] = dict()
net_dict[device.macAddress]['ipv4'] = []
net_dict[device.macAddress]['ipv6'] = []
- for ip_addr in device.ipAddress:
- if "::" in ip_addr:
- net_dict[device.macAddress]['ipv6'].append(ip_addr)
- else:
- net_dict[device.macAddress]['ipv4'].append(ip_addr)
+ if device.ipConfig is not None:
+ for ip_addr in device.ipConfig.ipAddress:
+ if "::" in ip_addr.ipAddress:
+ net_dict[device.macAddress]['ipv6'].append(ip_addr.ipAddress + "/" + str(ip_addr.prefixLength))
+ else:
+ net_dict[device.macAddress]['ipv4'].append(ip_addr.ipAddress + "/" + str(ip_addr.prefixLength))
esxi_hostname = None
esxi_parent = None
@@ -421,6 +417,7 @@ class VmwareVmInfo(PyVmomi):
"ip_address": _ip_address, # Kept for backward compatibility
"mac_address": _mac_address, # Kept for backward compatibility
"uuid": summary.config.uuid,
+ "instance_uuid": summary.config.instanceUuid,
"vm_network": net_dict,
"esxi_hostname": esxi_hostname,
"datacenter": None if datacenter is None else datacenter.name,
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_vm_shell.py b/ansible_collections/community/vmware/plugins/modules/vmware_vm_shell.py
index c3ae86a2a..76f1d5308 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_vm_shell.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_vm_shell.py
@@ -92,13 +92,13 @@ options:
type: str
wait_for_process:
description:
- - If set to C(true), module will wait for process to complete in the given virtual machine.
+ - If set to V(true), module will wait for process to complete in the given virtual machine.
default: false
type: bool
timeout:
description:
- Timeout in seconds.
- - If set to positive integers, then C(wait_for_process) will honor this parameter and will exit after this timeout.
+ - If set to positive integers, then O(wait_for_process=true) will honor this parameter and will exit after this timeout.
default: 3600
type: int
extends_documentation_fragment:
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_vm_storage_policy.py b/ansible_collections/community/vmware/plugins/modules/vmware_vm_storage_policy.py
index e1cf859bf..7f8eed013 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_vm_storage_policy.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_vm_storage_policy.py
@@ -28,36 +28,36 @@ options:
description:
description:
- Description of the storage policy to create or update.
- - This parameter is ignored when C(state=absent).
+ - This parameter is ignored when O(state=absent).
type: str
required: false
tag_category:
description:
- Name of the pre-existing tag category to assign to the storage policy.
- - This parameter is ignored when C(state=absent).
- - This parameter is required when C(state=present).
+ - This parameter is ignored when O(state=absent).
+ - This parameter is required when O(state=present).
required: false
type: str
tag_name:
description:
- Name of the pre-existing tag to assign to the storage policy.
- - This parameter is ignored when C(state=absent).
- - This parameter is required when C(state=present).
+ - This parameter is ignored when O(state=absent).
+ - This parameter is required when O(state=present).
required: false
type: str
tag_affinity:
description:
- - If set to C(true), the storage policy enforces that virtual machines require the existence of a tag for datastore placement.
- - If set to C(false), the storage policy enforces that virtual machines require the absence of a tag for datastore placement.
- - This parameter is ignored when C(state=absent).
+ - If set to V(true), the storage policy enforces that virtual machines require the existence of a tag for datastore placement.
+ - If set to V(false), the storage policy enforces that virtual machines require the absence of a tag for datastore placement.
+ - This parameter is ignored when O(state=absent).
required: false
type: bool
default: true
state:
description:
- State of storage policy.
- - If set to C(present), the storage policy is created.
- - If set to C(absent), the storage policy is deleted.
+ - If set to V(present), the storage policy is created.
+ - If set to V(absent), the storage policy is deleted.
default: present
choices: [ absent, present ]
type: str
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_vm_vm_drs_rule.py b/ansible_collections/community/vmware/plugins/modules/vmware_vm_vm_drs_rule.py
index 178cd1423..f94d7def3 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_vm_vm_drs_rule.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_vm_vm_drs_rule.py
@@ -26,7 +26,7 @@ options:
vms:
description:
- List of virtual machines name for which DRS rule needs to be applied.
- - Required if C(state) is set to C(present).
+ - Required if O(state=present).
type: list
elements: str
drs_rule_name:
@@ -36,28 +36,28 @@ options:
type: str
enabled:
description:
- - If set to C(true), the DRS rule will be enabled.
- - Effective only if C(state) is set to C(present).
+ - If set to V(true), the DRS rule will be enabled.
+ - Effective only if O(state=present).
default: false
type: bool
mandatory:
description:
- - If set to C(true), the DRS rule will be mandatory.
- - Effective only if C(state) is set to C(present).
+ - If set to V(true), the DRS rule will be mandatory.
+ - Effective only if O(state=present).
default: false
type: bool
affinity_rule:
description:
- - If set to C(true), the DRS rule will be an Affinity rule.
- - If set to C(false), the DRS rule will be an Anti-Affinity rule.
- - Effective only if C(state) is set to C(present).
+ - If set to V(true), the DRS rule will be an Affinity rule.
+ - If set to V(false), the DRS rule will be an Anti-Affinity rule.
+ - Effective only if O(state=present).
default: true
type: bool
state:
description:
- - If set to C(present), then the DRS rule is created if not present.
- - If set to C(present), then the DRS rule is already present, it updates to the given configurations.
- - If set to C(absent), then the DRS rule is deleted if present.
+ - If set to V(present), then the DRS rule is created if not present.
+ - If set to V(present), then the DRS rule is already present, it updates to the given configurations.
+ - If set to V(absent), then the DRS rule is deleted if present.
required: false
default: present
choices: [ present, absent ]
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_vmkernel.py b/ansible_collections/community/vmware/plugins/modules/vmware_vmkernel.py
index a42d5bbb4..26dbe7b2b 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_vmkernel.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_vmkernel.py
@@ -26,22 +26,23 @@ author:
- Russell Teague (@mtnbikenc)
- Abhijeet Kasurde (@Akasurde)
- Christian Kotte (@ckotte)
+- Nina Loser (@Nina2244)
notes:
- - The option C(device) need to be used with DHCP because otherwise it's not possible to check if a VMkernel device is already present
- - You can only change from DHCP to static, and vSS to vDS, or vice versa, in one step, without creating a new device, with C(device) specified.
+ - The option O(device) need to be used with DHCP because otherwise it's not possible to check if a VMkernel device is already present
+ - You can only change from DHCP to static, and vSS to vDS, or vice versa, in one step, without creating a new device, with O(device) specified.
- You can only create the VMKernel adapter on a vDS if authenticated to vCenter and not if authenticated to ESXi.
options:
vswitch_name:
description:
- The name of the vSwitch where to add the VMKernel interface.
- - Required parameter only if C(state) is set to C(present).
+ - Required parameter only if O(state=present).
- Optional parameter from version 2.5 and onwards.
type: str
aliases: ['vswitch']
dvswitch_name:
description:
- The name of the vSphere Distributed Switch (vDS) where to add the VMKernel interface.
- - Required parameter only if C(state) is set to C(present).
+ - Required parameter only if O(state=present).
- Optional parameter from version 2.8 and onwards.
type: str
aliases: ['dvswitch']
@@ -65,12 +66,12 @@ options:
type: str
description:
- Static IP address.
- - Required if C(type) is set to C(static).
+ - Required if O(network.type=static).
subnet_mask:
type: str
description:
- Static netmask required.
- - Required if C(type) is set to C(static).
+ - Required if O(network.type=static).
default_gateway:
type: str
description: Default gateway (Override default gateway for this adapter).
@@ -94,7 +95,7 @@ options:
device:
description:
- Search VMkernel adapter by device name.
- - The parameter is required only in case of C(type) is set to C(dhcp).
+ - The parameter is required only in case of O(network.type=dhcp).
type: str
enable_vsan:
description:
@@ -139,18 +140,24 @@ options:
- This option is only allowed if the default TCP/IP stack is used.
type: bool
default: false
+ enable_backup_nfc:
+ version_added: 4.2.0
+ description:
+ - Enable vSphere Backup NFC traffic on the VMKernel adapter.
+ - This option is only allowed if the default TCP/IP stack is used.
+ type: bool
+ default: false
state:
description:
- - If set to C(present), the VMKernel adapter will be created with the given specifications.
- - If set to C(absent), the VMKernel adapter will be removed.
- - If set to C(present) and VMKernel adapter exists, the configurations will be updated.
+ - If set to V(present), the VMKernel adapter will be created with the given specifications.
+ - If set to V(absent), the VMKernel adapter will be removed.
+ - If set to V(present) and VMKernel adapter exists, the configurations will be updated.
choices: [ present, absent ]
default: present
type: str
esxi_hostname:
description:
- Name of ESXi host to which VMKernel is to be managed.
- - "From version 2.5 onwards, this parameter is required."
required: true
type: str
extends_documentation_fragment:
@@ -302,6 +309,7 @@ class PyVmomiHelper(PyVmomi):
self.enable_provisioning = self.params['enable_provisioning']
self.enable_replication = self.params['enable_replication']
self.enable_replication_nfc = self.params['enable_replication_nfc']
+ self.enable_backup_nfc = self.params['enable_backup_nfc']
self.vswitch_name = self.params['vswitch_name']
self.vds_name = self.params['dvswitch_name']
@@ -495,7 +503,7 @@ class PyVmomiHelper(PyVmomi):
"""
changed = changed_settings = changed_vds = changed_services = \
changed_service_vmotion = changed_service_mgmt = changed_service_ft = \
- changed_service_vsan = changed_service_prov = changed_service_rep = changed_service_rep_nfc = False
+ changed_service_vsan = changed_service_prov = changed_service_rep = changed_service_rep_nfc = changed_service_backup_nfc = False
changed_list = []
results = dict(changed=False, msg='')
@@ -624,6 +632,11 @@ class PyVmomiHelper(PyVmomi):
if (self.enable_replication_nfc and self.vnic.device not in service_type_vmks['vSphereReplicationNFC']) or \
(not self.enable_replication_nfc and self.vnic.device in service_type_vmks['vSphereReplicationNFC']):
changed_services = changed_service_rep_nfc = True
+
+ if (self.enable_backup_nfc and self.vnic.device not in service_type_vmks['vSphereBackupNFC']) or \
+ (not self.enable_backup_nfc and self.vnic.device in service_type_vmks['vSphereBackupNFC']):
+ changed_services = changed_service_backup_nfc = True
+
if changed_services:
changed_list.append("services")
@@ -745,6 +758,14 @@ class PyVmomiHelper(PyVmomi):
vnic_manager=vnic_manager, vmk=self.vnic, service_type='vSphereReplicationNFC', operation=operation
)
+ if changed_service_backup_nfc:
+ if self.vnic.device in service_type_vmks['vSphereBackupNFC']:
+ services_previous.append('Backup_NFC')
+ operation = 'select' if self.enable_backup_nfc else 'deselect'
+ self.set_service_type(
+ vnic_manager=vnic_manager, vmk=self.vnic, service_type='vSphereBackupNFC', operation=operation
+ )
+
if changed_service_vsan:
if self.vnic.device in service_type_vmks['vsan']:
services_previous.append('VSAN')
@@ -919,7 +940,7 @@ class PyVmomiHelper(PyVmomi):
option is False for option in [self.enable_vsan, self.enable_vmotion,
self.enable_mgmt, self.enable_ft,
self.enable_provisioning, self.enable_replication,
- self.enable_replication_nfc]):
+ self.enable_replication_nfc, self.enable_backup_nfc]):
self.vnic = self.get_vmkernel_by_device(device_name=vmk_device)
# VSAN
@@ -946,6 +967,9 @@ class PyVmomiHelper(PyVmomi):
if self.enable_replication_nfc:
self.set_service_type(host_vnic_manager, self.vnic, 'vSphereReplicationNFC')
+ if self.enable_backup_nfc:
+ self.set_service_type(host_vnic_manager, self.vnic, 'vSphereBackupNFC')
+
self.module.exit_json(**results)
def set_service_type(self, vnic_manager, vmk, service_type, operation='select'):
@@ -985,6 +1009,7 @@ class PyVmomiHelper(PyVmomi):
vSphereProvisioning=[],
vSphereReplication=[],
vSphereReplicationNFC=[],
+ vSphereBackupNFC=[],
)
for service_type in list(service_type_vmk):
@@ -1038,6 +1063,8 @@ class PyVmomiHelper(PyVmomi):
services.append('Repl')
if self.enable_replication_nfc:
services.append('Repl_NFC')
+ if self.enable_backup_nfc:
+ services.append('Backup_NFC')
return ', '.join(services)
@staticmethod
@@ -1076,6 +1103,7 @@ def main():
enable_provisioning=dict(type='bool', default=False),
enable_replication=dict(type='bool', default=False),
enable_replication_nfc=dict(type='bool', default=False),
+ enable_backup_nfc=dict(type='bool', default=False),
vswitch_name=dict(required=False, type='str', aliases=['vswitch']),
dvswitch_name=dict(required=False, type='str', aliases=['dvswitch']),
network=dict(
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_vmkernel_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_vmkernel_info.py
index 0ea95bb8d..9638397dc 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_vmkernel_info.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_vmkernel_info.py
@@ -22,13 +22,13 @@ options:
description:
- Name of the cluster.
- VMKernel information about each ESXi server will be returned for the given cluster.
- - If C(esxi_hostname) is not given, this parameter is required.
+ - If O(esxi_hostname) is not given, this parameter is required.
type: str
esxi_hostname:
description:
- ESXi hostname.
- VMKernel information about this ESXi server will be returned.
- - If C(cluster_name) is not given, this parameter is required.
+ - If O(cluster_name) is not given, this parameter is required.
type: str
extends_documentation_fragment:
- community.vmware.vmware.documentation
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_vmotion.py b/ansible_collections/community/vmware/plugins/modules/vmware_vmotion.py
index e9d39c920..021157544 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_vmotion.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_vmotion.py
@@ -25,20 +25,19 @@ options:
vm_name:
description:
- Name of the VM to perform a vMotion on.
- - This is required parameter, if C(vm_uuid) is not set.
- - Version 2.6 onwards, this parameter is not a required parameter, unlike the previous versions.
+ - This is required parameter, if O(vm_uuid) is not set.
aliases: ['vm']
type: str
vm_uuid:
description:
- UUID of the virtual machine to perform a vMotion operation on.
- - This is a required parameter, if C(vm_name) or C(moid) is not set.
+ - This is a required parameter, if O(vm_name) or O(moid) is not set.
aliases: ['uuid']
type: str
moid:
description:
- Managed Object ID of the instance to manage if known, this is a unique identifier only within a single vCenter instance.
- - This is required if C(vm_name) or C(vm_uuid) is not supplied.
+ - This is required if O(vm_name) or O(vm_uuid) is not supplied.
type: str
use_instance_uuid:
description:
@@ -52,13 +51,11 @@ options:
aliases: ['destination']
type: str
destination_cluster:
- version_added: '2.5.0'
description:
- Name of the destination cluster the virtual machine should be running on.
- Only works if drs is enabled for this cluster.
type: str
destination_datastore_cluster:
- version_added: '2.5.0'
description:
- Name of the destination datastore cluster (storage pod) the virtual machine's vmdk should be moved on.
- Only works if drs is enabled for the cluster the vm is running / should run.
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_vsan_health_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_vsan_health_info.py
index 89db649de..565b2b859 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_vsan_health_info.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_vsan_health_info.py
@@ -28,7 +28,7 @@ options:
type: str
fetch_from_cache:
description:
- - C(true) to return the result from cache directly instead of running the full health check.
+ - V(true) to return the result from cache directly instead of running the full health check.
required: false
default: false
type: bool
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_vspan_session.py b/ansible_collections/community/vmware/plugins/modules/vmware_vspan_session.py
index ac1a2999f..d69830f8d 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_vspan_session.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_vspan_session.py
@@ -49,13 +49,13 @@ options:
- 'dvPortMirror'
description:
- Select the mirroring type.
- - In C(encapsulatedRemoteMirrorSource) session, Distributed Ports can be used as source entities,
+ - In V(encapsulatedRemoteMirrorSource) session, Distributed Ports can be used as source entities,
and IP address can be used as destination entities.
- - In C(remoteMirrorDest) session, VLAN IDs can be used as source entities, and
+ - In V(remoteMirrorDest) session, VLAN IDs can be used as source entities, and
Distributed Ports can be used as destination entities.
- - In C(remoteMirrorSource) session, Distributed Ports can be used as source
+ - In V(remoteMirrorSource) session, Distributed Ports can be used as source
entities, and uplink ports name can be used as destination entities.
- - In C(dvPortMirror) session, Distributed Ports can be used as both source and
+ - In V(dvPortMirror) session, Distributed Ports can be used as both source and
destination entities.
required: false
type: str
@@ -95,7 +95,7 @@ options:
description:
- Whether to strip the original VLAN tag.
- If false, the original VLAN tag will be preserved on the mirrored traffic.
- - If C(encapsulationVlanId) has been set and this property is false, the frames will be double tagged
+ - If O(encapsulation_vlan_id) has been set and this property is V(false), the frames will be double tagged
with the original VLAN ID as the inner tag.
type: bool
required: false
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_vswitch.py b/ansible_collections/community/vmware/plugins/modules/vmware_vswitch.py
index 56f3b4c38..619eb5af7 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_vswitch.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_vswitch.py
@@ -25,14 +25,12 @@ options:
switch:
description:
- vSwitch name to add.
- - Alias C(switch) is added in version 2.4.
required: true
aliases: [ switch_name ]
type: str
nics:
description:
- A list of vmnic names or vmnic name to attach to vSwitch.
- - Alias C(nics) is added in version 2.4.
aliases: [ nic_name ]
default: []
type: list
@@ -64,7 +62,6 @@ options:
portgroup such as promiscuous mode, where guest adapter listens
to all the packets, MAC address changes and forged transmits.
- Dict which configures the different security values for portgroup.
- version_added: '2.4.0'
suboptions:
promiscuous_mode:
type: bool
@@ -81,7 +78,6 @@ options:
teaming:
description:
- Dictionary which configures the different teaming values for portgroup.
- version_added: '2.4.0'
suboptions:
load_balancing:
type: str
@@ -103,13 +99,13 @@ options:
type: list
description:
- List of active adapters used for load balancing.
- - All vmnics are used as active adapters if C(active_adapters) and C(standby_adapters) are not defined.
+ - All vmnics are used as active adapters if O(teaming.active_adapters) and O(teaming.standby_adapters) are not defined.
elements: str
standby_adapters:
type: list
description:
- List of standby adapters used for failover.
- - All vmnics are used as active adapters if C(active_adapters) and C(standby_adapters) are not defined.
+ - All vmnics are used as active adapters if O(teaming.active_adapters) and O(teaming.standby_adapters) are not defined.
elements: str
required: false
aliases: [ 'teaming_policy' ]
@@ -117,7 +113,6 @@ options:
traffic_shaping:
description:
- Dictionary which configures traffic shaping for the switch.
- version_added: '2.4.0'
suboptions:
enabled:
type: bool
diff --git a/ansible_collections/community/vmware/plugins/modules/vmware_vswitch_info.py b/ansible_collections/community/vmware/plugins/modules/vmware_vswitch_info.py
index e053a4b1d..ff21a7958 100644
--- a/ansible_collections/community/vmware/plugins/modules/vmware_vswitch_info.py
+++ b/ansible_collections/community/vmware/plugins/modules/vmware_vswitch_info.py
@@ -22,7 +22,6 @@ author:
- Abhijeet Kasurde (@Akasurde)
options:
policies:
- version_added: '2.4.0'
description:
- Gather information about Security, Traffic Shaping, as well as Teaming and failover.
- The property C(ts) stands for Traffic Shaping and C(lb) for Load Balancing.
@@ -32,12 +31,12 @@ options:
description:
- Name of the cluster.
- Info about vswitch belonging to every ESXi host systems under this cluster will be returned.
- - If C(esxi_hostname) is not given, this parameter is required.
+ - If O(esxi_hostname) is not given, this parameter is required.
type: str
esxi_hostname:
description:
- ESXi hostname to gather information from.
- - If C(cluster_name) is not given, this parameter is required.
+ - If O(cluster_name) is not given, this parameter is required.
type: str
extends_documentation_fragment:
- community.vmware.vmware.documentation
diff --git a/ansible_collections/community/vmware/plugins/modules/vsan_health_silent_checks.py b/ansible_collections/community/vmware/plugins/modules/vsan_health_silent_checks.py
index b62068220..eaa6b240a 100644
--- a/ansible_collections/community/vmware/plugins/modules/vsan_health_silent_checks.py
+++ b/ansible_collections/community/vmware/plugins/modules/vsan_health_silent_checks.py
@@ -37,8 +37,8 @@ options:
state:
description:
- The state of the health checks.
- - If set to C(present), all given health checks will be silenced.
- - If set to C(absent), all given health checks will be removed from the list of silent checks.
+ - If set to V(present), all given health checks will be silenced.
+ - If set to V(absent), all given health checks will be removed from the list of silent checks.
default: 'present'
choices: [ 'present', 'absent' ]
type: str
diff --git a/ansible_collections/community/vmware/plugins/modules/vsphere_copy.py b/ansible_collections/community/vmware/plugins/modules/vsphere_copy.py
index 3fe227e68..670a8e86a 100644
--- a/ansible_collections/community/vmware/plugins/modules/vsphere_copy.py
+++ b/ansible_collections/community/vmware/plugins/modules/vsphere_copy.py
@@ -45,6 +45,14 @@ options:
- The timeout in seconds for the upload to the datastore.
default: 10
type: int
+ diskformat:
+ version_added: 4.2.0
+ description:
+ - Optional argument - Set a diskformat for certain uploads like stream optimized VMDKs
+ - There is no official documentation, but it looks like V(StreamVmdk) needs to be set for stream optimized VMDKs that are uploaded to vSAN storage
+ - Setting this for non-VMDK files might lead to undefined behavior and is not supported.
+ choices: ["StreamVmdk"]
+ type: str
notes:
- "This module ought to be run from a system that can access the vCenter or the ESXi directly and has the file to transfer.
@@ -87,6 +95,19 @@ EXAMPLES = r'''
datastore: datastore2
path: other/remote/file
delegate_to: other_system
+
+- name: Copy file to datastore using other_system
+ community.vmware.vsphere_copy:
+ hostname: '{{ vcenter_hostname }}'
+ username: '{{ vcenter_username }}'
+ password: '{{ vcenter_password }}'
+ src: /other/local/streamOptimized.vmdk
+ datacenter: DC2 Someplace
+ datastore: datastore2
+ path: disk_imports/streamOptimized.vmdk
+ timeout: 360
+ diskformat: StreamVmdk
+ delegate_to: other_system
'''
import atexit
@@ -103,7 +124,7 @@ from ansible.module_utils.urls import open_url
from ansible_collections.community.vmware.plugins.module_utils.vmware import vmware_argument_spec
-def vmware_path(datastore, datacenter, path):
+def vmware_path(datastore, datacenter, path, diskformat):
''' Constructs a URL path that vSphere accepts reliably '''
path = "/folder/%s" % quote(path.lstrip("/"))
# Due to a software bug in vSphere, it fails to handle ampersand in datacenter names
@@ -114,6 +135,8 @@ def vmware_path(datastore, datacenter, path):
if datacenter:
datacenter = datacenter.replace('&', '%26')
params["dcPath"] = datacenter
+ if diskformat:
+ params["diskFormat"] = diskformat
params = urlencode(params)
return "%s?%s" % (path, params)
@@ -125,7 +148,8 @@ def main():
datacenter=dict(required=False),
datastore=dict(required=True),
path=dict(required=True, aliases=['dest'], type='str'),
- timeout=dict(default=10, type='int'))
+ timeout=dict(default=10, type='int'),
+ diskformat=dict(required=False, type='str', choices=['StreamVmdk']))
)
module = AnsibleModule(
@@ -141,6 +165,7 @@ def main():
datacenter = module.params.get('datacenter')
datastore = module.params.get('datastore')
path = module.params.get('path')
+ diskformat = module.params.get('diskformat')
validate_certs = module.params.get('validate_certs')
timeout = module.params.get('timeout')
@@ -156,7 +181,7 @@ def main():
data = mmap.mmap(fd.fileno(), 0, access=mmap.ACCESS_READ)
atexit.register(data.close)
- remote_path = vmware_path(datastore, datacenter, path)
+ remote_path = vmware_path(datastore, datacenter, path, diskformat)
if not all([hostname, username, password]):
module.fail_json(msg="One of following parameter is missing - hostname, username, password")
diff --git a/ansible_collections/community/vmware/plugins/modules/vsphere_file.py b/ansible_collections/community/vmware/plugins/modules/vsphere_file.py
index c42ef84de..327f76c02 100644
--- a/ansible_collections/community/vmware/plugins/modules/vsphere_file.py
+++ b/ansible_collections/community/vmware/plugins/modules/vsphere_file.py
@@ -18,22 +18,6 @@ description:
author:
- Dag Wieers (@dagwieers)
options:
- host:
- description:
- - The vCenter server on which the datastore is available.
- type: str
- required: true
- aliases: [ hostname ]
- username:
- description:
- - The user name to authenticate on the vCenter server.
- type: str
- required: true
- password:
- description:
- - The password to authenticate on the vCenter server.
- type: str
- required: true
datacenter:
description:
- The datacenter on the vCenter server that holds the datastore.
@@ -50,12 +34,6 @@ options:
type: str
required: true
aliases: [ dest ]
- validate_certs:
- description:
- - If C(false), SSL certificates will not be validated. This should only be
- set to C(false) when no other option exists.
- type: bool
- default: true
timeout:
description:
- The timeout in seconds for the upload to the datastore.
@@ -64,15 +42,17 @@ options:
state:
description:
- The state of or the action on the provided path.
- - If C(absent), the file will be removed.
- - If C(directory), the directory will be created.
- - If C(file), more information of the (existing) file will be returned.
- - If C(touch), an empty file will be created if the path does not exist.
+ - If V(absent), the file will be removed.
+ - If V(directory), the directory will be created.
+ - If V(file), more information of the (existing) file will be returned.
+ - If V(touch), an empty file will be created if the path does not exist.
type: str
choices: [ absent, directory, file, touch ]
default: file
notes:
- The vSphere folder API does not allow to remove directory objects.
+extends_documentation_fragment:
+- community.vmware.vmware.documentation
'''
EXAMPLES = r'''
@@ -134,6 +114,7 @@ from ansible.module_utils.six.moves.urllib.error import HTTPError
from ansible.module_utils.six.moves.urllib.parse import quote, urlencode
from ansible.module_utils.urls import open_url
from ansible.module_utils._text import to_native
+from ansible_collections.community.vmware.plugins.module_utils.vmware import vmware_argument_spec
def vmware_path(datastore, datacenter, path):
@@ -152,22 +133,22 @@ def vmware_path(datastore, datacenter, path):
def main():
+ argument_spec = vmware_argument_spec()
+
+ argument_spec.update(dict(
+ datacenter=dict(type='str', required=True),
+ datastore=dict(type='str', required=True),
+ path=dict(type='str', required=True, aliases=['dest']),
+ state=dict(type='str', default='file', choices=['absent', 'directory', 'file', 'touch']),
+ timeout=dict(type='int', default=10),
+ ))
+
module = AnsibleModule(
- argument_spec=dict(
- host=dict(type='str', required=True, aliases=['hostname']),
- username=dict(type='str', required=True),
- password=dict(type='str', required=True, no_log=True),
- datacenter=dict(type='str', required=True),
- datastore=dict(type='str', required=True),
- path=dict(type='str', required=True, aliases=['dest']),
- state=dict(type='str', default='file', choices=['absent', 'directory', 'file', 'touch']),
- timeout=dict(type='int', default=10),
- validate_certs=dict(type='bool', default=True),
- ),
+ argument_spec=argument_spec,
supports_check_mode=True,
)
- host = module.params.get('host')
+ host = module.params.get('hostname')
username = module.params.get('username')
password = module.params.get('password')
datacenter = module.params.get('datacenter')
diff --git a/ansible_collections/community/vmware/testing.md b/ansible_collections/community/vmware/testing.md
index 4122e61de..b798cbf4f 100644
--- a/ansible_collections/community/vmware/testing.md
+++ b/ansible_collections/community/vmware/testing.md
@@ -40,4 +40,4 @@ $ VMWARE_TEST_PLATFORM=static ansible-test integration --diff --no-temp-workdir
## More Information
-* [Developer guide for testing](https://docs.ansible.com/ansible/latest/dev_guide/platforms/vmware_guidelines.html#testing-with-your-own-infrastructure)
+* [Developer guide for testing](https://docs.ansible.com/ansible/latest/collections/community/vmware/docsite/dev_guide.html#testing-with-your-own-infrastructure)
diff --git a/ansible_collections/community/vmware/tests/integration/targets/prepare_vmware_tests/tasks/setup_virtualmachines.yml b/ansible_collections/community/vmware/tests/integration/targets/prepare_vmware_tests/tasks/setup_virtualmachines.yml
index 5506fb132..2b2b39285 100644
--- a/ansible_collections/community/vmware/tests/integration/targets/prepare_vmware_tests/tasks/setup_virtualmachines.yml
+++ b/ansible_collections/community/vmware/tests/integration/targets/prepare_vmware_tests/tasks/setup_virtualmachines.yml
@@ -16,6 +16,8 @@
scsi: paravirtual
version: 11
cdrom:
+ - controller_number: 0
+ unit_number: 0
type: iso
iso_path: "[{{ ro_datastore }}] fedora.iso"
networks:
@@ -40,6 +42,8 @@
num_cpus: 1
scsi: paravirtual
cdrom:
+ - controller_number: 0
+ unit_number: 0
type: iso
iso_path: "[{{ ro_datastore }}] fedora.iso"
networks:
diff --git a/ansible_collections/community/vmware/tests/integration/targets/vcenter_root_password_expiration/aliases b/ansible_collections/community/vmware/tests/integration/targets/vcenter_root_password_expiration/aliases
new file mode 100644
index 000000000..b1682114e
--- /dev/null
+++ b/ansible_collections/community/vmware/tests/integration/targets/vcenter_root_password_expiration/aliases
@@ -0,0 +1,3 @@
+cloud/vcenter
+needs/target/prepare_vmware_tests
+zuul/vmware/vcenter_only
diff --git a/ansible_collections/community/vmware/tests/integration/targets/vcenter_root_password_expiration/tasks/main.yml b/ansible_collections/community/vmware/tests/integration/targets/vcenter_root_password_expiration/tasks/main.yml
new file mode 100644
index 000000000..e80baf9c9
--- /dev/null
+++ b/ansible_collections/community/vmware/tests/integration/targets/vcenter_root_password_expiration/tasks/main.yml
@@ -0,0 +1,23 @@
+# Test code for the vcenter_root_password_expiration module.
+# Copyright: (c) 2023, Mario Lenz <m@riolenz.de>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+- import_role:
+ name: prepare_vmware_tests
+
+- name: Set vCenter root password expiration
+ vcenter_root_password_expiration:
+ hostname: "{{ vcenter_hostname }}"
+ username: "{{ vcenter_username }}"
+ password: "{{ vcenter_password }}"
+ state: present
+ email: "vCenter-Admin@community.vmware.example"
+ max_days_between_password_change: 93
+ min_days_between_password_change: 7
+ warn_days_before_password_expiration: 22
+ validate_certs: false
+ register: pw_expiration
+
+- assert:
+ that:
+ - pw_expiration is changed
diff --git a/ansible_collections/community/vmware/tests/integration/targets/vmware_about_info/tasks/main.yml b/ansible_collections/community/vmware/tests/integration/targets/vmware_about_info/tasks/main.yml
index 94a9941d8..d5f09d6ef 100644
--- a/ansible_collections/community/vmware/tests/integration/targets/vmware_about_info/tasks/main.yml
+++ b/ansible_collections/community/vmware/tests/integration/targets/vmware_about_info/tasks/main.yml
@@ -15,7 +15,7 @@
- assert:
that:
- - about.about_info["{{ item }}"] is defined
+ - about.about_info[item] is defined
with_items:
- api_type
- api_version
@@ -40,7 +40,7 @@
- assert:
that:
- - about.about_info["{{ item }}"] is defined
+ - about.about_info[item] is defined
with_items:
- api_type
- api_version
diff --git a/ansible_collections/community/vmware/tests/integration/targets/vmware_category/tasks/associable_obj_test.yml b/ansible_collections/community/vmware/tests/integration/targets/vmware_category/tasks/associable_obj_test.yml
index 3069f15dd..14c9c5d01 100644
--- a/ansible_collections/community/vmware/tests/integration/targets/vmware_category/tasks/associable_obj_test.yml
+++ b/ansible_collections/community/vmware/tests/integration/targets/vmware_category/tasks/associable_obj_test.yml
@@ -35,4 +35,4 @@
- name: Check if we get correct associable datatype for {{ category_name }}
assert:
that:
- - "'{{ expected_result }}' in {{ category_datatype }}" \ No newline at end of file
+ - "expected_result in category_datatype"
diff --git a/ansible_collections/community/vmware/tests/integration/targets/vmware_category/tasks/main.yml b/ansible_collections/community/vmware/tests/integration/targets/vmware_category/tasks/main.yml
index 598e9da46..128f7a37f 100644
--- a/ansible_collections/community/vmware/tests/integration/targets/vmware_category/tasks/main.yml
+++ b/ansible_collections/community/vmware/tests/integration/targets/vmware_category/tasks/main.yml
@@ -4,4 +4,4 @@
- import_role:
name: prepare_vmware_tests
-- include: associable_obj_types.yml
+- include_tasks: associable_obj_types.yml
diff --git a/ansible_collections/community/vmware/tests/integration/targets/vmware_dvs_portgroup/tasks/main.yml b/ansible_collections/community/vmware/tests/integration/targets/vmware_dvs_portgroup/tasks/main.yml
index 8e6119f45..8d45b2e28 100644
--- a/ansible_collections/community/vmware/tests/integration/targets/vmware_dvs_portgroup/tasks/main.yml
+++ b/ansible_collections/community/vmware/tests/integration/targets/vmware_dvs_portgroup/tasks/main.yml
@@ -407,7 +407,7 @@
assert:
that:
- not dvs_pg_result_0013.changed
- - "'vlan_id range 1-4096 specified is incorrect. The valid vlan_id range is from 0 to 4094.' == '{{ dvs_pg_result_0013.msg }}'"
+ - "'vlan_id range 1-4096 specified is incorrect. The valid vlan_id range is from 0 to 4094.' == dvs_pg_result_0013.msg"
- name: Change VLAN on basic VLAN portgroup
community.vmware.vmware_dvs_portgroup:
@@ -508,7 +508,7 @@
assert:
that:
- not dvs_pg_result_0018.changed
- - "'No private vlan with id 10 in distributed vSwitch {{ dvswitch1 }}' == '{{ dvs_pg_result_0018.msg }}'"
+ - "'No private vlan with id 10 in distributed vSwitch {{ dvswitch1 }}' == dvs_pg_result_0018.msg"
- name: Run tests and clean up
block:
diff --git a/ansible_collections/community/vmware/tests/integration/targets/vmware_first_class_disk_info/aliases b/ansible_collections/community/vmware/tests/integration/targets/vmware_first_class_disk_info/aliases
new file mode 100644
index 000000000..07e8732a3
--- /dev/null
+++ b/ansible_collections/community/vmware/tests/integration/targets/vmware_first_class_disk_info/aliases
@@ -0,0 +1,3 @@
+cloud/vcenter
+needs/target/prepare_vmware_tests
+zuul/vmware/vcenter_1esxi
diff --git a/ansible_collections/community/vmware/tests/integration/targets/vmware_first_class_disk_info/tasks/main.yml b/ansible_collections/community/vmware/tests/integration/targets/vmware_first_class_disk_info/tasks/main.yml
new file mode 100644
index 000000000..da18648c5
--- /dev/null
+++ b/ansible_collections/community/vmware/tests/integration/targets/vmware_first_class_disk_info/tasks/main.yml
@@ -0,0 +1,96 @@
+# Test code for the vmware_first_class_disk_info module.
+# Copyright: (c) 2021, Mario Lenz <m@riolenz.de>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+- import_role:
+ name: prepare_vmware_tests
+ vars:
+ setup_attach_host: true
+ setup_datastore: true
+
+- name: Gather Info if no first-class disk exists
+ vmware_first_class_disk_info: &disk_info
+ hostname: "{{ vcenter_hostname }}"
+ username: "{{ vcenter_username }}"
+ password: "{{ vcenter_password }}"
+ datastore_name: "{{ rw_datastore }}"
+ validate_certs: false
+ register: disk_info
+ delegate_to: localhost
+
+- debug:
+ var: disk_info
+
+- assert:
+ that:
+ - "disk_info['first_class_disks'] == []"
+
+- name: Create first-class disk through vCenter
+ vmware_first_class_disk:
+ hostname: "{{ vcenter_hostname }}"
+ username: "{{ vcenter_username }}"
+ password: "{{ vcenter_password }}"
+ disk_name: "firstclassdisk"
+ size: 1GB
+ datastore_name: "{{ rw_datastore }}"
+ state: present
+ validate_certs: false
+
+- name: Gather Info of the generated first-class disk
+ vmware_first_class_disk_info:
+ <<: *disk_info
+ register: disk_info
+
+- name: assert for first-class disk info
+ assert:
+ that:
+ - "(disk_info['first_class_disks'] | length) == 1"
+ - "disk_info['first_class_disks'][0]['name'] == 'firstclassdisk'"
+ - "disk_info['first_class_disks'][0]['datastore_name'] == rw_datastore"
+ - "disk_info['first_class_disks'][0]['size_mb'] == 1024"
+ - "disk_info['first_class_disks'][0]['consumption_type'] is defined"
+ - "disk_info['first_class_disks'][0]['descriptor_version'] is defined"
+ - "disk_info['first_class_disks'][0]['consumer_ids'] is defined"
+
+- name: Create a second first-class disk through vCenter
+ vmware_first_class_disk:
+ hostname: "{{ vcenter_hostname }}"
+ username: "{{ vcenter_username }}"
+ password: "{{ vcenter_password }}"
+ disk_name: "secondclassdisk"
+ size: 1GB
+ datastore_name: "{{ rw_datastore }}"
+ state: present
+ validate_certs: false
+
+- name: Gather Info of the two generated first-class disk
+ vmware_first_class_disk_info:
+ <<: *disk_info
+ register: disk_info
+
+- name: assert for first-class disk info
+ assert:
+ that:
+ - "(disk_info['first_class_disks'] | length) == 2"
+
+- name: Gather Info of first-class disk 'firstclassdisk'
+ vmware_first_class_disk_info:
+ hostname: "{{ vcenter_hostname }}"
+ username: "{{ vcenter_username }}"
+ password: "{{ vcenter_password }}"
+ datastore_name: "{{ rw_datastore }}"
+ disk_name: "firstclassdisk"
+ validate_certs: false
+ register: disk_info
+ delegate_to: localhost
+
+- name: assert for first-class disk info
+ assert:
+ that:
+ - "(disk_info['first_class_disks'] | length) == 1"
+ - "disk_info['first_class_disks'][0]['name'] == 'firstclassdisk'"
+ - "disk_info['first_class_disks'][0]['datastore_name'] == rw_datastore"
+ - "disk_info['first_class_disks'][0]['size_mb'] == 1024"
+ - "disk_info['first_class_disks'][0]['consumption_type'] is defined"
+ - "disk_info['first_class_disks'][0]['descriptor_version'] is defined"
+ - "disk_info['first_class_disks'][0]['consumer_ids'] is defined" \ No newline at end of file
diff --git a/ansible_collections/community/vmware/tests/integration/targets/vmware_folder_info/tasks/main.yml b/ansible_collections/community/vmware/tests/integration/targets/vmware_folder_info/tasks/main.yml
index 51b53f4b5..f3816b0cf 100644
--- a/ansible_collections/community/vmware/tests/integration/targets/vmware_folder_info/tasks/main.yml
+++ b/ansible_collections/community/vmware/tests/integration/targets/vmware_folder_info/tasks/main.yml
@@ -31,7 +31,7 @@
- assert:
that:
- - "{{ item }} is defined"
+ - "item is defined"
with_items:
- folder_info_0001['folder_info']
- folder_info_0001['flat_folder_info']
diff --git a/ansible_collections/community/vmware/tests/integration/targets/vmware_guest/tasks/cdrom_d1_c1_f0.yml b/ansible_collections/community/vmware/tests/integration/targets/vmware_guest/tasks/cdrom_d1_c1_f0.yml
index abe194fdf..23d35a9c8 100644
--- a/ansible_collections/community/vmware/tests/integration/targets/vmware_guest/tasks/cdrom_d1_c1_f0.yml
+++ b/ansible_collections/community/vmware/tests/integration/targets/vmware_guest/tasks/cdrom_d1_c1_f0.yml
@@ -20,6 +20,8 @@
type: thin
datastore: "{{ rw_datastore }}"
cdrom:
+ - controller_number: 0
+ unit_number: 0
type: iso
iso_path: "[{{ ro_datastore }}] centos.iso"
register: cdrom_vm
@@ -42,6 +44,8 @@
datastore: "{{ rw_datastore }}"
datacenter: "{{ dc1 }}"
cdrom:
+ - controller_number: 0
+ unit_number: 0
type: iso
iso_path: "[{{ ro_datastore }}] fedora.iso"
state: present
@@ -66,6 +70,8 @@
datastore: "{{ rw_datastore }}"
datacenter: "{{ dc1 }}"
cdrom:
+ - controller_number: 0
+ unit_number: 0
type: iso
iso_path: "[{{ ro_datastore }}] fedora.iso"
state: present
@@ -88,6 +94,8 @@
name: test_vm1
datacenter: "{{ dc1 }}"
cdrom:
+ - controller_number: 0
+ unit_number: 0
type: client
state: present
register: cdrom_vm
@@ -110,6 +118,8 @@
name: test_vm1
datacenter: "{{ dc1 }}"
cdrom:
+ - controller_number: 0
+ unit_number: 0
type: client
state: present
register: cdrom_vm
@@ -144,6 +154,8 @@
name: test_vm2
datacenter: "{{ dc1 }}"
cdrom:
+ - controller_number: 0
+ unit_number: 0
type: none
state: present
register: cdrom_vm
@@ -182,6 +194,8 @@
type: thin
datastore: "{{ rw_datastore }}"
cdrom:
+ - controller_number: 0
+ unit_number: 0
type: iso
iso_path: "[{{ ro_datastore }}] fedora.iso"
register: cdrom_vm
@@ -220,6 +234,8 @@
type: thin
datastore: "{{ rw_datastore }}"
cdrom:
+ - controller_number: 0
+ unit_number: 0
type: iso
iso_path: "[{{ ro_datastore }}] base.iso"
register: cdrom_vm
diff --git a/ansible_collections/community/vmware/tests/integration/targets/vmware_guest/tasks/check_mode.yml b/ansible_collections/community/vmware/tests/integration/targets/vmware_guest/tasks/check_mode.yml
index 2d2ace997..e17f4effd 100644
--- a/ansible_collections/community/vmware/tests/integration/targets/vmware_guest/tasks/check_mode.yml
+++ b/ansible_collections/community/vmware/tests/integration/targets/vmware_guest/tasks/check_mode.yml
@@ -19,6 +19,8 @@
scsi: paravirtual
version: 11
cdrom:
+ - controller_number: 0
+ unit_number: 0
type: iso
iso_path: "[{{ ro_datastore }}] fedora.iso"
networks:
diff --git a/ansible_collections/community/vmware/tests/integration/targets/vmware_guest/tasks/clone_customize_guest_test.yml b/ansible_collections/community/vmware/tests/integration/targets/vmware_guest/tasks/clone_customize_guest_test.yml
index 77a94e2b5..ab1f44919 100644
--- a/ansible_collections/community/vmware/tests/integration/targets/vmware_guest/tasks/clone_customize_guest_test.yml
+++ b/ansible_collections/community/vmware/tests/integration/targets/vmware_guest/tasks/clone_customize_guest_test.yml
@@ -19,6 +19,8 @@
scsi: paravirtual
version: 11
cdrom:
+ - controller_number: 0
+ unit_number: 0
type: iso
iso_path: "[{{ ro_datastore }}] fedora.iso"
networks:
diff --git a/ansible_collections/community/vmware/tests/integration/targets/vmware_guest/tasks/clone_with_convert.yml b/ansible_collections/community/vmware/tests/integration/targets/vmware_guest/tasks/clone_with_convert.yml
index 50063016a..f4e14b534 100644
--- a/ansible_collections/community/vmware/tests/integration/targets/vmware_guest/tasks/clone_with_convert.yml
+++ b/ansible_collections/community/vmware/tests/integration/targets/vmware_guest/tasks/clone_with_convert.yml
@@ -19,6 +19,8 @@
scsi: paravirtual
version: 11
cdrom:
+ - controller_number: 0
+ unit_number: 0
type: iso
iso_path: "[{{ ro_datastore }}] fedora.iso"
networks:
diff --git a/ansible_collections/community/vmware/tests/integration/targets/vmware_guest/tasks/windows_vbs_d1_c1_f0.yml b/ansible_collections/community/vmware/tests/integration/targets/vmware_guest/tasks/windows_vbs_d1_c1_f0.yml
index cd151620a..af72c9feb 100644
--- a/ansible_collections/community/vmware/tests/integration/targets/vmware_guest/tasks/windows_vbs_d1_c1_f0.yml
+++ b/ansible_collections/community/vmware/tests/integration/targets/vmware_guest/tasks/windows_vbs_d1_c1_f0.yml
@@ -22,6 +22,8 @@
type: thin
datastore: '{{ rw_datastore }}'
cdrom:
+ - controller_number: 0
+ unit_number: 0
type: client
register: vbs_vm
@@ -56,6 +58,8 @@
type: thin
datastore: '{{ rw_datastore }}'
cdrom:
+ - controller_number: 0
+ unit_number: 0
type: client
register: vbs_vm
diff --git a/ansible_collections/community/vmware/tests/integration/targets/vmware_guest_controller/tasks/main.yml b/ansible_collections/community/vmware/tests/integration/targets/vmware_guest_controller/tasks/main.yml
index 790eb4a11..6ff9d522d 100644
--- a/ansible_collections/community/vmware/tests/integration/targets/vmware_guest_controller/tasks/main.yml
+++ b/ansible_collections/community/vmware/tests/integration/targets/vmware_guest_controller/tasks/main.yml
@@ -50,8 +50,8 @@
assert:
that:
- "add_disk_controller.changed == true"
- - "{{ add_disk_controller.disk_controller_data.scsi | length | int }} == {{ scsi_num | int + 1 }}"
- - "{{ add_disk_controller.disk_controller_data.sata | length | int }} == {{ sata_num | int + 1 }}"
+ - "add_disk_controller.disk_controller_data.scsi | length | int == scsi_num | int + 1"
+ - "add_disk_controller.disk_controller_data.sata | length | int == sata_num | int + 1"
- name: delete specified disk controllers
vmware_guest_controller:
@@ -76,5 +76,5 @@
assert:
that:
- "del_disk_controller.changed == true"
- - "{{ del_disk_controller.disk_controller_data.sata | length | int }} == {{ sata_num | int }}"
- - "{{ del_disk_controller.disk_controller_data.scsi | length | int }} == {{ scsi_num | int }}"
+ - "del_disk_controller.disk_controller_data.sata | length | int == sata_num | int"
+ - "del_disk_controller.disk_controller_data.scsi | length | int == scsi_num | int"
diff --git a/ansible_collections/community/vmware/tests/integration/targets/vmware_guest_disk/tasks/main.yml b/ansible_collections/community/vmware/tests/integration/targets/vmware_guest_disk/tasks/main.yml
index 6e50231e6..ed3ca1295 100644
--- a/ansible_collections/community/vmware/tests/integration/targets/vmware_guest_disk/tasks/main.yml
+++ b/ansible_collections/community/vmware/tests/integration/targets/vmware_guest_disk/tasks/main.yml
@@ -24,6 +24,8 @@
type: thin
datastore: local
cdrom:
+ - controller_number: 0
+ unit_number: 0
type: iso
iso_path: "[{{ ro_datastore }}] fedora.iso"
hardware:
@@ -607,4 +609,28 @@
- name: assert that changes were made
assert:
that:
- - test_remove_ide_disk is changed \ No newline at end of file
+ - test_remove_ide_disk is changed
+
+- name: Try to remove non-existing SCSI disk
+ vmware_guest_disk:
+ hostname: "{{ vcenter_hostname }}"
+ username: "{{ vcenter_username }}"
+ password: "{{ vcenter_password }}"
+ datacenter: "{{ dc1 }}"
+ validate_certs: false
+ name: test_vm1
+ disk:
+ - state: "absent"
+ controller_type: 'paravirtual'
+ controller_number: 0
+ unit_number: 15
+ register: test_remove_non_existing_disk
+ ignore_errors: true
+
+- debug:
+ msg: "{{ test_remove_non_existing_disk }}"
+
+- name: assert that removing non existing disk does not fail
+ assert:
+ that:
+ - test_remove_non_existing_disk is not failed
diff --git a/ansible_collections/community/vmware/tests/integration/targets/vmware_guest_disk_info/tasks/main.yml b/ansible_collections/community/vmware/tests/integration/targets/vmware_guest_disk_info/tasks/main.yml
index decb904f9..28de37840 100644
--- a/ansible_collections/community/vmware/tests/integration/targets/vmware_guest_disk_info/tasks/main.yml
+++ b/ansible_collections/community/vmware/tests/integration/targets/vmware_guest_disk_info/tasks/main.yml
@@ -25,6 +25,8 @@
scsi: paravirtual
version: 11
cdrom:
+ - controller_number: 0
+ unit_number: 0
type: iso
iso_path: "[{{ ro_datastore }}] fedora.iso"
networks:
diff --git a/ansible_collections/community/vmware/tests/integration/targets/vmware_guest_network/tasks/main.yml b/ansible_collections/community/vmware/tests/integration/targets/vmware_guest_network/tasks/main.yml
index cb70cbbd3..0dad050e7 100644
--- a/ansible_collections/community/vmware/tests/integration/targets/vmware_guest_network/tasks/main.yml
+++ b/ansible_collections/community/vmware/tests/integration/targets/vmware_guest_network/tasks/main.yml
@@ -31,6 +31,8 @@
num_cpus: 1
scsi: paravirtual
cdrom:
+ - controller_number: 0
+ unit_number: 0
type: iso
iso_path: "[{{ ro_datastore }}] fedora.iso"
networks:
@@ -89,7 +91,7 @@
assert:
that:
- add_netadapter is changed
- - "{{ add_netadapter.results[1].network_info | length | int }} == {{ netadapter_num | int + 2 }}"
+ - "add_netadapter.results[1].network_info | length | int == netadapter_num | int + 2"
- name: delete one specified network adapter
community.vmware.vmware_guest_network:
@@ -108,7 +110,7 @@
assert:
that:
- del_netadapter is changed
- - "{{ del_netadapter.network_info | length | int }} == {{ netadapter_num | int + 1 }}"
+ - "del_netadapter.network_info | length | int == netadapter_num | int + 1"
- name: get instance uuid of virtual machines
community.vmware.vmware_guest_info:
@@ -142,7 +144,7 @@
assert:
that:
- add_netadapter_instanceuuid is changed
- - "{{ add_netadapter_instanceuuid.network_info | length | int }} == {{ netadapter_num | int + 2 }}"
+ - "add_netadapter_instanceuuid.network_info | length | int == netadapter_num | int + 2"
- name: delete one specified network adapter
community.vmware.vmware_guest_network:
@@ -159,7 +161,7 @@
assert:
that:
- del_netadapter is changed
- - "{{ del_netadapter.network_info | length | int }} == {{ netadapter_num | int + 1 }}"
+ - "del_netadapter.network_info | length | int == netadapter_num | int + 1"
- name: delete again one specified network adapter (idempotency)
community.vmware.vmware_guest_network:
@@ -178,7 +180,7 @@
assert:
that:
- not (del_again_netadapter is changed)
- - "{{ del_again_netadapter.network_info | length | int }} == {{ netadapter_num | int + 1 }}"
+ - "del_again_netadapter.network_info | length | int == netadapter_num | int + 1"
- name: disable DirectPath I/O on a Vmxnet3 adapter
community.vmware.vmware_guest_network:
@@ -226,7 +228,7 @@
assert:
that:
- disc_netadapter is changed
- - "{{ disc_netadapter.network_info[netadapter_num | int]['connected'] }} == false"
+ - "disc_netadapter.network_info[netadapter_num | int]['connected'] == false"
- name: Check if network does not exists
community.vmware.vmware_guest_network:
@@ -396,7 +398,7 @@
- name: check that there's no adapters left
assert:
that:
- - "{{ nic_info2.network_info | length | int }} == 0"
+ - "nic_info2.network_info | length | int == 0"
- name: add new adapter(s)
community.vmware.vmware_guest_network:
@@ -412,7 +414,7 @@
- name: check that nic was created
assert:
that:
- - "{{ new_nic.network_info | length | int }} > 0"
+ - "new_nic.network_info | length | int > 0"
- name: add new PVRDMA adapter
community.vmware.vmware_guest_network:
@@ -429,7 +431,7 @@
- name: check that PVRDMA nic was created
assert:
that:
- - "{{ new_nic_pvrdma.network_info | length | int }} == {{ new_nic.network_info | length | int + 1 }}"
+ - "new_nic_pvrdma.network_info | length | int == new_nic.network_info | length | int + 1"
- name: remove PVRDMA adapter
community.vmware.vmware_guest_network:
@@ -445,7 +447,7 @@
- name: check that PVRDMA nic was removed
assert:
that:
- - "{{ new_nic_pvrdma.network_info | length | int - 1 }} == {{ remove_nic_pvrdma.network_info | length | int }}"
+ - "new_nic_pvrdma.network_info | length | int - 1 == remove_nic_pvrdma.network_info | length | int"
# https://github.com/ansible-collections/community.vmware/issues/204
- name: "Change a dvpg with in same DVS(integration test for 204)"
diff --git a/ansible_collections/community/vmware/tests/integration/targets/vmware_guest_powerstate/tasks/main.yml b/ansible_collections/community/vmware/tests/integration/targets/vmware_guest_powerstate/tasks/main.yml
index 048470966..462ae52ae 100644
--- a/ansible_collections/community/vmware/tests/integration/targets/vmware_guest_powerstate/tasks/main.yml
+++ b/ansible_collections/community/vmware/tests/integration/targets/vmware_guest_powerstate/tasks/main.yml
@@ -28,6 +28,8 @@
num_cpus: 1
scsi: paravirtual
cdrom:
+ - controller_number: 0
+ unit_number: 0
type: iso
iso_path: "[{{ ro_datastore }}] fedora.iso"
networks:
diff --git a/ansible_collections/community/vmware/tests/integration/targets/vmware_guest_snapshot/tasks/main.yml b/ansible_collections/community/vmware/tests/integration/targets/vmware_guest_snapshot/tasks/main.yml
index 622a69c70..4eeb11cf5 100644
--- a/ansible_collections/community/vmware/tests/integration/targets/vmware_guest_snapshot/tasks/main.yml
+++ b/ansible_collections/community/vmware/tests/integration/targets/vmware_guest_snapshot/tasks/main.yml
@@ -7,7 +7,7 @@
# Test0001: Try to delete the non-existent snapshot
- name: 0001 - Delete non-existent snapshot
- vmware_guest_snapshot:
+ community.vmware.vmware_guest_snapshot:
validate_certs: false
hostname: '{{ vcenter_hostname }}'
username: '{{ vcenter_username }}'
@@ -20,7 +20,7 @@
# Test0002: Create two snapshots
- name: 0002 - Create snapshot
- vmware_guest_snapshot:
+ community.vmware.vmware_guest_snapshot:
validate_certs: false
hostname: '{{ vcenter_hostname }}'
username: '{{ vcenter_username }}'
@@ -37,7 +37,7 @@
# Test0003: Reanme a to c
- name: 0003 - Rename snapshot
- vmware_guest_snapshot:
+ community.vmware.vmware_guest_snapshot:
validate_certs: false
hostname: '{{ vcenter_hostname }}'
username: '{{ vcenter_username }}'
@@ -51,7 +51,7 @@
# Test0004: Create snap_a again
- name: 0004 - Re-create snapshot a
- vmware_guest_snapshot:
+ community.vmware.vmware_guest_snapshot:
validate_certs: false
hostname: '{{ vcenter_hostname }}'
username: '{{ vcenter_username }}'
@@ -65,7 +65,7 @@
# Test0005: Change description of snap_c
- name: 0005 - Change description of snap_c
- vmware_guest_snapshot:
+ community.vmware.vmware_guest_snapshot:
validate_certs: false
hostname: '{{ vcenter_hostname }}'
username: '{{ vcenter_username }}'
@@ -79,7 +79,7 @@
# Test0006: Delete snap_b with child remove
- name: 0006 - Delete snap_b with child remove
- vmware_guest_snapshot:
+ community.vmware.vmware_guest_snapshot:
validate_certs: false
hostname: '{{ vcenter_hostname }}'
username: '{{ vcenter_username }}'
@@ -93,7 +93,7 @@
# Test0007: Delete all snapshots
- name: 0007 - Delete all snapshots
- vmware_guest_snapshot:
+ community.vmware.vmware_guest_snapshot:
validate_certs: false
hostname: '{{ vcenter_hostname }}'
username: '{{ vcenter_username }}'
@@ -105,7 +105,7 @@
# Test0008: Create snap_a again and revert to it
- name: 0008 - Re-create snapshot a
- vmware_guest_snapshot:
+ community.vmware.vmware_guest_snapshot:
validate_certs: false
hostname: '{{ vcenter_hostname }}'
username: '{{ vcenter_username }}'
@@ -118,7 +118,7 @@
description: "snap named a"
- name: 0008 - Revert to snap_a
- vmware_guest_snapshot:
+ community.vmware.vmware_guest_snapshot:
validate_certs: false
hostname: '{{ vcenter_hostname }}'
username: '{{ vcenter_username }}'
@@ -131,7 +131,7 @@
# Test0009: Create snap_a and check in result
- name: 0009 - create snapshot a
- vmware_guest_snapshot:
+ community.vmware.vmware_guest_snapshot:
validate_certs: false
hostname: '{{ vcenter_hostname }}'
username: '{{ vcenter_username }}'
@@ -144,16 +144,16 @@
description: "snap named a"
register: snapshot_details
-- debug: var=snapshot_details
+- ansible.builtin.debug: var=snapshot_details
- name: Check if snapshot details available or not
- assert:
+ ansible.builtin.assert:
that:
- "snapshot_details['msg'] == 'Snapshot named [snap_a] already exists and is current.'"
# Test0011: Failure sceanrios - when name and UUID is not specified
- name: 0011 - name and UUID is missing
- vmware_guest_snapshot:
+ community.vmware.vmware_guest_snapshot:
validate_certs: false
hostname: '{{ vcenter_hostname }}'
username: '{{ vcenter_username }}'
@@ -166,7 +166,84 @@
ignore_errors: true
- name: Check if error is shown
- assert:
+ ansible.builtin.assert:
that:
- "'one of the following is required: name, uuid' in snapshot_failure_details['msg']"
- "snapshot_failure_details.changed == false"
+
+# Test0010 : Test for revert and remove a snapshot to specify snapshot_id
+- name: 0012 - Create snapshot
+ community.vmware.vmware_guest_snapshot:
+ validate_certs: false
+ hostname: '{{ vcenter_hostname }}'
+ username: '{{ vcenter_username }}'
+ password: '{{ vcenter_password }}'
+ datacenter: "{{ dc1 }}"
+ name: "{{ virtual_machines[0].name }}"
+ folder: "{{ virtual_machines[0].folder }}"
+ state: present
+ snapshot_name: "snap_{{item}}"
+ description: "snap named {{item}}"
+ with_items:
+ - b
+ - c
+ register: snapshot_creation_result0012
+
+- name: Create the snapshot_ids variable
+ ansible.builtin.set_fact:
+ snapshot_ids: >-
+ {{ snapshot_ids | default([])
+ + [({
+ 'name': item.snapshot_results.current_snapshot.name,
+ 'snapshot_id': item.snapshot_results.current_snapshot.id
+ })]
+ }}
+ loop: "{{ snapshot_creation_result0012.results }}"
+
+- name: 0013 - Revert to snap_b with snapshot_id
+ community.vmware.vmware_guest_snapshot:
+ validate_certs: false
+ hostname: '{{ vcenter_hostname }}'
+ username: '{{ vcenter_username }}'
+ password: '{{ vcenter_password }}'
+ datacenter: "{{ dc1 }}"
+ name: "{{ virtual_machines[0].name }}"
+ folder: "{{ virtual_machines[0].folder }}"
+ state: revert
+ snapshot_id: "{{ item.snapshot_id }}"
+ loop: "{{ snapshot_ids }}"
+ when:
+ - item.name == "snap_b"
+ register: revert_snapshot_with_id_result
+
+- name: Make sure whether reverted with snapshot_id
+ ansible.builtin.assert:
+ that:
+ - item.changed is sameas true
+ loop: "{{ revert_snapshot_with_id_result.results }}"
+ when:
+ - item.item.name == "snap_b"
+
+- name: 0014 - Remove snap_b with snapshot_id
+ community.vmware.vmware_guest_snapshot:
+ validate_certs: false
+ hostname: '{{ vcenter_hostname }}'
+ username: '{{ vcenter_username }}'
+ password: '{{ vcenter_password }}'
+ datacenter: "{{ dc1 }}"
+ name: "{{ virtual_machines[0].name }}"
+ folder: "{{ virtual_machines[0].folder }}"
+ state: absent
+ snapshot_id: "{{ item.snapshot_id }}"
+ loop: "{{ snapshot_ids }}"
+ when:
+ - item.name == "snap_b"
+ register: remove_snapshot_with_id_result
+
+- name: Make sure whether removed with snapshot_id
+ ansible.builtin.assert:
+ that:
+ - item.changed is sameas true
+ loop: "{{ remove_snapshot_with_id_result.results }}"
+ when:
+ - item.item.name == "snap_b"
diff --git a/ansible_collections/community/vmware/tests/integration/targets/vmware_guest_tools_wait/tasks/main.yml b/ansible_collections/community/vmware/tests/integration/targets/vmware_guest_tools_wait/tasks/main.yml
index 2b3a23268..c675d138b 100644
--- a/ansible_collections/community/vmware/tests/integration/targets/vmware_guest_tools_wait/tasks/main.yml
+++ b/ansible_collections/community/vmware/tests/integration/targets/vmware_guest_tools_wait/tasks/main.yml
@@ -31,6 +31,8 @@
num_cpus: 1
scsi: paravirtual
cdrom:
+ - controller_number: 0
+ unit_number: 0
type: iso
iso_path: "[{{ ro_datastore }}] fedora.iso"
networks:
diff --git a/ansible_collections/community/vmware/tests/integration/targets/vmware_host_acceptance/tasks/main.yml b/ansible_collections/community/vmware/tests/integration/targets/vmware_host_acceptance/tasks/main.yml
index 9d3352e6d..cab3aa222 100644
--- a/ansible_collections/community/vmware/tests/integration/targets/vmware_host_acceptance/tasks/main.yml
+++ b/ansible_collections/community/vmware/tests/integration/targets/vmware_host_acceptance/tasks/main.yml
@@ -7,33 +7,48 @@
vars:
setup_attach_host: true
-- name: Change acceptance level of given hosts
+- name: Change acceptance level of given host in check mode
vmware_host_acceptance:
hostname: "{{ vcenter_hostname }}"
username: "{{ vcenter_username }}"
password: "{{ vcenter_password }}"
esxi_hostname: '{{ esxi1 }}'
validate_certs: false
- acceptance_level: community
- state: present
- register: host_acceptance_info
-- debug: var=host_acceptance_info
+ state: community
+ register: host_acceptance_community_check_mode
+ check_mode: true
+- debug: var=host_acceptance_community_check_mode
- assert:
that:
- - host_acceptance_info.facts is defined
+ - host_acceptance_community_check_mode.facts is defined
+ - host_acceptance_community_check_mode.changed
-- name: Change acceptance level of given hosts in check mode
+- name: Change acceptance level of given host
vmware_host_acceptance:
hostname: "{{ vcenter_hostname }}"
username: "{{ vcenter_username }}"
password: "{{ vcenter_password }}"
esxi_hostname: '{{ esxi1 }}'
validate_certs: false
- acceptance_level: community
- state: present
- register: host_acceptance_info_check_mode
- check_mode: true
-- debug: var=host_acceptance_info_check_mode
+ state: community
+ register: host_acceptance_community
+- debug: var=host_acceptance_community
+- assert:
+ that:
+ - host_acceptance_community.facts is defined
+ - host_acceptance_community.changed
+
+- name: Change acceptance level of given host again (idempotency)
+ vmware_host_acceptance:
+ hostname: "{{ vcenter_hostname }}"
+ username: "{{ vcenter_username }}"
+ password: "{{ vcenter_password }}"
+ esxi_hostname: '{{ esxi1 }}'
+ validate_certs: false
+ state: community
+ register: host_acceptance_community_again
+- debug: var=host_acceptance_community_again
- assert:
that:
- - host_acceptance_info_check_mode.facts is defined
+ - host_acceptance_community_again.facts is defined
+ - host_acceptance_community_again.changed is false
diff --git a/ansible_collections/community/vmware/tests/integration/targets/vmware_host_acceptance_info/aliases b/ansible_collections/community/vmware/tests/integration/targets/vmware_host_acceptance_info/aliases
new file mode 100644
index 000000000..07e8732a3
--- /dev/null
+++ b/ansible_collections/community/vmware/tests/integration/targets/vmware_host_acceptance_info/aliases
@@ -0,0 +1,3 @@
+cloud/vcenter
+needs/target/prepare_vmware_tests
+zuul/vmware/vcenter_1esxi
diff --git a/ansible_collections/community/vmware/tests/integration/targets/vmware_host_acceptance_info/tasks/main.yml b/ansible_collections/community/vmware/tests/integration/targets/vmware_host_acceptance_info/tasks/main.yml
new file mode 100644
index 000000000..483391ecd
--- /dev/null
+++ b/ansible_collections/community/vmware/tests/integration/targets/vmware_host_acceptance_info/tasks/main.yml
@@ -0,0 +1,22 @@
+# Test code for the vmware_host_acceptance module.
+# Copyright: (c) 2018, Abhijeet Kasurde <akasurde@redhat.com>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+- import_role:
+ name: prepare_vmware_tests
+ vars:
+ setup_attach_host: true
+
+- name: Gather acceptance level of given host
+ vmware_host_acceptance_info:
+ hostname: "{{ vcenter_hostname }}"
+ username: "{{ vcenter_username }}"
+ password: "{{ vcenter_password }}"
+ esxi_hostname: '{{ esxi1 }}'
+ validate_certs: false
+ register: result
+- debug: var=result
+- assert:
+ that:
+ - result.host_acceptance_info is defined
+ - result.changed is false
diff --git a/ansible_collections/community/vmware/tests/integration/targets/vmware_host_auto_start/tasks/main.yml b/ansible_collections/community/vmware/tests/integration/targets/vmware_host_auto_start/tasks/main.yml
index 7e5369e1a..c3028864e 100644
--- a/ansible_collections/community/vmware/tests/integration/targets/vmware_host_auto_start/tasks/main.yml
+++ b/ansible_collections/community/vmware/tests/integration/targets/vmware_host_auto_start/tasks/main.yml
@@ -50,8 +50,8 @@
with_items: ['test_vm1', 'test_vm2']
- include_tasks: reset_auto_start_config.yml
- - include: vcenter_auto_start_ops.yml
+ - include_tasks: vcenter_auto_start_ops.yml
- include_tasks: reset_auto_start_config.yml
- - include: esxi_auto_start_ops.yml
+ - include_tasks: esxi_auto_start_ops.yml
always:
- include_tasks: reset_auto_start_config.yml
diff --git a/ansible_collections/community/vmware/tests/integration/targets/vmware_host_snmp/aliases b/ansible_collections/community/vmware/tests/integration/targets/vmware_host_snmp/aliases
index 07e8732a3..d1d14d229 100644
--- a/ansible_collections/community/vmware/tests/integration/targets/vmware_host_snmp/aliases
+++ b/ansible_collections/community/vmware/tests/integration/targets/vmware_host_snmp/aliases
@@ -1,3 +1,3 @@
cloud/vcenter
needs/target/prepare_vmware_tests
-zuul/vmware/vcenter_1esxi
+zuul/vmware/vcenter_2esxi
diff --git a/ansible_collections/community/vmware/tests/integration/targets/vmware_host_snmp/tasks/main.yml b/ansible_collections/community/vmware/tests/integration/targets/vmware_host_snmp/tasks/main.yml
index a1fad114a..d84dae45f 100644
--- a/ansible_collections/community/vmware/tests/integration/targets/vmware_host_snmp/tasks/main.yml
+++ b/ansible_collections/community/vmware/tests/integration/targets/vmware_host_snmp/tasks/main.yml
@@ -7,7 +7,6 @@
vars:
setup_attach_host: true
-# SNMP works only with standalone ESXi server
- name: Enable and configure SNMP community in check mode
vmware_host_snmp:
hostname: '{{ esxi1 }}'
@@ -68,3 +67,133 @@
that:
- snmp_disabled is defined
- snmp_disabled.changed
+
+- name: Enable and configure SNMP community via vCenter in check mode
+ vmware_host_snmp:
+ hostname: '{{ vcenter_hostname }}'
+ username: '{{ vcenter_username }}'
+ password: '{{ vcenter_password }}'
+ esxi_hostname: '{{ esxi2 }}'
+ community: [ test ]
+ state: enabled
+ validate_certs: false
+ register: snmp_enabled_check_mode
+ check_mode: true
+- debug: var=snmp_enabled_check_mode
+- assert:
+ that:
+ - snmp_enabled_check_mode is defined
+ - snmp_enabled_check_mode.changed
+
+- name: Enable and configure SNMP community via vCenter
+ vmware_host_snmp:
+ hostname: '{{ vcenter_hostname }}'
+ username: '{{ vcenter_username }}'
+ password: '{{ vcenter_password }}'
+ esxi_hostname: '{{ esxi2 }}'
+ community: [ test ]
+ state: enabled
+ validate_certs: false
+ register: snmp_enabled
+- debug: var=snmp_enabled
+- assert:
+ that:
+ - snmp_enabled is defined
+ - snmp_enabled.changed
+
+- name: Enable and configure SNMP system contact and location via vCenter
+ vmware_host_snmp:
+ hostname: '{{ vcenter_hostname }}'
+ username: '{{ vcenter_username }}'
+ password: '{{ vcenter_password }}'
+ esxi_hostname: '{{ esxi2 }}'
+ sys_contact: "admin@testemail.com"
+ sys_location: "Austin, USA"
+ state: enabled
+ validate_certs: false
+ register: snmp_enabled_sys_options
+- debug: var=snmp_enabled_sys_options
+- assert:
+ that:
+ - snmp_enabled_sys_options is defined
+ - snmp_enabled_sys_options.changed
+
+- name: Disable SNMP via vCenter
+ vmware_host_snmp:
+ hostname: '{{ vcenter_hostname }}'
+ username: '{{ vcenter_username }}'
+ password: '{{ vcenter_password }}'
+ esxi_hostname: '{{ esxi2 }}'
+ state: disabled
+ validate_certs: false
+ register: snmp_disabled
+- debug: var=snmp_disabled
+- assert:
+ that:
+ - snmp_disabled is defined
+ - snmp_disabled.changed
+
+- name: Enable and configure SNMP community in a cluster via vCenter in check mode
+ vmware_host_snmp:
+ hostname: '{{ vcenter_hostname }}'
+ username: '{{ vcenter_username }}'
+ password: '{{ vcenter_password }}'
+ cluster_name: "{{ ccr1 }}"
+ community: [ test2 ]
+ state: enabled
+ validate_certs: false
+ register: snmp_enabled_check_mode
+ check_mode: true
+- debug: var=snmp_enabled_check_mode
+- assert:
+ that:
+ - snmp_enabled_check_mode is defined
+ - snmp_enabled_check_mode.changed
+
+- name: Enable and configure SNMP community in a cluster via vCenter
+ vmware_host_snmp:
+ hostname: '{{ vcenter_hostname }}'
+ username: '{{ vcenter_username }}'
+ password: '{{ vcenter_password }}'
+ cluster_name: "{{ ccr1 }}"
+ community: [ test2 ]
+ state: enabled
+ validate_certs: false
+ register: snmp_enabled
+- debug: var=snmp_enabled
+- assert:
+ that:
+ - snmp_enabled is defined
+ - snmp_enabled.changed
+
+- name: Enable and configure SNMP system contact and location in a cluster via vCenter
+ vmware_host_snmp:
+ hostname: '{{ vcenter_hostname }}'
+ username: '{{ vcenter_username }}'
+ password: '{{ vcenter_password }}'
+ cluster_name: "{{ ccr1 }}"
+ sys_contact: "admin2@testemail.com"
+ sys_location: "Austin, USA"
+ state: enabled
+ validate_certs: false
+ register: snmp_enabled_sys_options
+- debug: var=snmp_enabled_sys_options
+- assert:
+ that:
+ - snmp_enabled_sys_options is defined
+ - snmp_enabled_sys_options.changed
+
+- name: Disable SNMP in a cluster via vCenter
+ vmware_host_snmp:
+ hostname: '{{ vcenter_hostname }}'
+ username: '{{ vcenter_username }}'
+ password: '{{ vcenter_password }}'
+ cluster_name: "{{ ccr1 }}"
+ state: disabled
+ validate_certs: false
+ register: snmp_disabled
+- debug: var=snmp_disabled
+- assert:
+ that:
+ - snmp_disabled is defined
+ - snmp_disabled.changed
diff --git a/ansible_collections/community/vmware/tests/integration/targets/vmware_object_rename/tasks/main.yml b/ansible_collections/community/vmware/tests/integration/targets/vmware_object_rename/tasks/main.yml
index 6fb176169..086bf0399 100644
--- a/ansible_collections/community/vmware/tests/integration/targets/vmware_object_rename/tasks/main.yml
+++ b/ansible_collections/community/vmware/tests/integration/targets/vmware_object_rename/tasks/main.yml
@@ -2,4 +2,4 @@
# Copyright: (c) 2019, Abhijeet Kasurde <akasurde@redhat.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-- include: dc_rename.yml
+- include_tasks: dc_rename.yml
diff --git a/ansible_collections/community/vmware/tests/integration/targets/vmware_tag/tasks/main.yml b/ansible_collections/community/vmware/tests/integration/targets/vmware_tag/tasks/main.yml
index 8961c6916..e0baeea76 100644
--- a/ansible_collections/community/vmware/tests/integration/targets/vmware_tag/tasks/main.yml
+++ b/ansible_collections/community/vmware/tests/integration/targets/vmware_tag/tasks/main.yml
@@ -2,6 +2,6 @@
# Copyright: (c) 2019, Pavan Bidkar <pbidkar@vmware.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-- include: tag_crud_ops.yml
-- include: tag_manager_ops.yml
-- include: tag_manager_duplicate_tag_cat.yml
+- include_tasks: tag_crud_ops.yml
+- include_tasks: tag_manager_ops.yml
+- include_tasks: tag_manager_duplicate_tag_cat.yml
diff --git a/ansible_collections/community/vmware/tests/integration/targets/vmware_tag_info/tasks/main.yml b/ansible_collections/community/vmware/tests/integration/targets/vmware_tag_info/tasks/main.yml
index c7b0209a9..d3a5abb94 100644
--- a/ansible_collections/community/vmware/tests/integration/targets/vmware_tag_info/tasks/main.yml
+++ b/ansible_collections/community/vmware/tests/integration/targets/vmware_tag_info/tasks/main.yml
@@ -2,4 +2,4 @@
# Copyright: (c) 2020, Abhijeet Kasurde <akasurde@redhat.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-- include: tag_info.yml \ No newline at end of file
+- include_tasks: tag_info.yml
diff --git a/ansible_collections/community/vmware/tests/integration/targets/vmware_tag_manager/tasks/main.yml b/ansible_collections/community/vmware/tests/integration/targets/vmware_tag_manager/tasks/main.yml
index e49301ef7..60dd2bd9b 100644
--- a/ansible_collections/community/vmware/tests/integration/targets/vmware_tag_manager/tasks/main.yml
+++ b/ansible_collections/community/vmware/tests/integration/targets/vmware_tag_manager/tasks/main.yml
@@ -28,6 +28,6 @@
- name: Set category one id
set_fact: cat_one_id={{ category_one_create['category_results']['category_id'] }}
- - include: tag_manager_dict.yml
+ - include_tasks: tag_manager_dict.yml
always:
- - include: cleanup.yml
+ - include_tasks: cleanup.yml
diff --git a/ansible_collections/community/vmware/tests/integration/targets/vmware_vm_inventory/prepare_environment.yml b/ansible_collections/community/vmware/tests/integration/targets/vmware_vm_inventory/prepare_environment.yml
index 65e643b74..7e24b2d94 100644
--- a/ansible_collections/community/vmware/tests/integration/targets/vmware_vm_inventory/prepare_environment.yml
+++ b/ansible_collections/community/vmware/tests/integration/targets/vmware_vm_inventory/prepare_environment.yml
@@ -31,6 +31,8 @@
type: thin
datastore: local
cdrom:
+ - controller_number: 0
+ unit_number: 0
type: iso
iso_path: "[{{ ro_datastore }}] fedora.iso"
hardware:
diff --git a/ansible_collections/community/vmware/tests/sanity/ignore-2.13.txt b/ansible_collections/community/vmware/tests/sanity/ignore-2.13.txt
deleted file mode 100644
index e8a48ca14..000000000
--- a/ansible_collections/community/vmware/tests/sanity/ignore-2.13.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-plugins/modules/vmware_deploy_ovf.py use-argspec-type-path!skip
-plugins/modules/vmware_host_acceptance.py validate-modules:parameter-state-invalid-choice
diff --git a/ansible_collections/community/vmware/tests/sanity/ignore-2.14.txt b/ansible_collections/community/vmware/tests/sanity/ignore-2.14.txt
deleted file mode 100644
index e8a48ca14..000000000
--- a/ansible_collections/community/vmware/tests/sanity/ignore-2.14.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-plugins/modules/vmware_deploy_ovf.py use-argspec-type-path!skip
-plugins/modules/vmware_host_acceptance.py validate-modules:parameter-state-invalid-choice
diff --git a/ansible_collections/community/vmware/tests/sanity/ignore-2.15.txt b/ansible_collections/community/vmware/tests/sanity/ignore-2.15.txt
index e8a48ca14..8203d8990 100644
--- a/ansible_collections/community/vmware/tests/sanity/ignore-2.15.txt
+++ b/ansible_collections/community/vmware/tests/sanity/ignore-2.15.txt
@@ -1,2 +1,2 @@
+plugins/modules/vmware_deploy_ovf.py replace-urlopen!skip
plugins/modules/vmware_deploy_ovf.py use-argspec-type-path!skip
-plugins/modules/vmware_host_acceptance.py validate-modules:parameter-state-invalid-choice
diff --git a/ansible_collections/community/vmware/tests/sanity/ignore-2.16.txt b/ansible_collections/community/vmware/tests/sanity/ignore-2.16.txt
new file mode 100644
index 000000000..4a0d49a7d
--- /dev/null
+++ b/ansible_collections/community/vmware/tests/sanity/ignore-2.16.txt
@@ -0,0 +1,4 @@
+plugins/modules/vmware_deploy_ovf.py replace-urlopen!skip
+plugins/modules/vmware_deploy_ovf.py use-argspec-type-path!skip
+scripts/inventory/vmware_inventory.py pep8!skip
+tests/unit/mock/loader.py pep8!skip
diff --git a/ansible_collections/community/vmware/tests/sanity/ignore-2.17.txt b/ansible_collections/community/vmware/tests/sanity/ignore-2.17.txt
new file mode 100644
index 000000000..4a0d49a7d
--- /dev/null
+++ b/ansible_collections/community/vmware/tests/sanity/ignore-2.17.txt
@@ -0,0 +1,4 @@
+plugins/modules/vmware_deploy_ovf.py replace-urlopen!skip
+plugins/modules/vmware_deploy_ovf.py use-argspec-type-path!skip
+scripts/inventory/vmware_inventory.py pep8!skip
+tests/unit/mock/loader.py pep8!skip
diff --git a/ansible_collections/community/vmware/tests/unit/compat/__init__.py b/ansible_collections/community/vmware/tests/unit/compat/__init__.py
deleted file mode 100644
index e69de29bb..000000000
--- a/ansible_collections/community/vmware/tests/unit/compat/__init__.py
+++ /dev/null
diff --git a/ansible_collections/community/vmware/tests/unit/compat/mock.py b/ansible_collections/community/vmware/tests/unit/compat/mock.py
deleted file mode 100644
index 53b6048dc..000000000
--- a/ansible_collections/community/vmware/tests/unit/compat/mock.py
+++ /dev/null
@@ -1,122 +0,0 @@
-# (c) 2014, Toshio Kuratomi <tkuratomi@ansible.com>
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-'''
-Compat module for Python3.x's unittest.mock module
-'''
-import sys
-import _io
-
-# Python 2.7
-
-# Note: Could use the pypi mock library on python3.x as well as python2.x. It
-# is the same as the python3 stdlib mock library
-
-try:
- # Allow wildcard import because we really do want to import all of mock's
- # symbols into this compat shim
- # pylint: disable=wildcard-import,unused-wildcard-import
- from unittest.mock import *
-except ImportError:
- # Python 2
- # pylint: disable=wildcard-import,unused-wildcard-import
- try:
- from mock import *
- except ImportError:
- print('You need the mock library installed on python2.x to run tests')
-
-
-# Prior to 3.4.4, mock_open cannot handle binary read_data
-if sys.version_info >= (3,) and sys.version_info < (3, 4, 4):
- file_spec = None
-
- def _iterate_read_data(read_data):
- # Helper for mock_open:
- # Retrieve lines from read_data via a generator so that separate calls to
- # readline, read, and readlines are properly interleaved
- sep = b'\n' if isinstance(read_data, bytes) else '\n'
- data_as_list = [l + sep for l in read_data.split(sep)]
-
- if data_as_list[-1] == sep:
- # If the last line ended in a newline, the list comprehension will have an
- # extra entry that's just a newline. Remove this.
- data_as_list = data_as_list[:-1]
- else:
- # If there wasn't an extra newline by itself, then the file being
- # emulated doesn't have a newline to end the last line remove the
- # newline that our naive format() added
- data_as_list[-1] = data_as_list[-1][:-1]
-
- for line in data_as_list:
- yield line
-
- def mock_open(mock=None, read_data=''):
- """
- A helper function to create a mock to replace the use of `open`. It works
- for `open` called directly or used as a context manager.
-
- The `mock` argument is the mock object to configure. If `None` (the
- default) then a `MagicMock` will be created for you, with the API limited
- to methods or attributes available on standard file handles.
-
- `read_data` is a string for the `read` methoddline`, and `readlines` of the
- file handle to return. This is an empty string by default.
- """
- def _readlines_side_effect(*args, **kwargs):
- if handle.readlines.return_value is not None:
- return handle.readlines.return_value
- return list(_data)
-
- def _read_side_effect(*args, **kwargs):
- if handle.read.return_value is not None:
- return handle.read.return_value
- return type(read_data)().join(_data)
-
- def _readline_side_effect():
- if handle.readline.return_value is not None:
- while True:
- yield handle.readline.return_value
- for line in _data:
- yield line
-
- global file_spec
- if file_spec is None:
- file_spec = list(set(dir(_io.TextIOWrapper)).union(set(dir(_io.BytesIO))))
-
- if mock is None:
- mock = MagicMock(name='open', spec=open)
-
- handle = MagicMock(spec=file_spec)
- handle.__enter__.return_value = handle
-
- _data = _iterate_read_data(read_data)
-
- handle.write.return_value = None
- handle.read.return_value = None
- handle.readline.return_value = None
- handle.readlines.return_value = None
-
- handle.read.side_effect = _read_side_effect
- handle.readline.side_effect = _readline_side_effect()
- handle.readlines.side_effect = _readlines_side_effect
-
- mock.return_value = handle
- return mock
diff --git a/ansible_collections/community/vmware/tests/unit/compat/unittest.py b/ansible_collections/community/vmware/tests/unit/compat/unittest.py
deleted file mode 100644
index 98f08ad6a..000000000
--- a/ansible_collections/community/vmware/tests/unit/compat/unittest.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# (c) 2014, Toshio Kuratomi <tkuratomi@ansible.com>
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-'''
-Compat module for Python2.7's unittest module
-'''
-
-import sys
-
-# Allow wildcard import because we really do want to import all of
-# unittests's symbols into this compat shim
-# pylint: disable=wildcard-import,unused-wildcard-import
-if sys.version_info < (2, 7):
- try:
- # Need unittest2 on python2.6
- from unittest2 import *
- except ImportError:
- print('You need unittest2 installed on python2.6.x to run tests')
-else:
- from unittest import *
diff --git a/ansible_collections/community/vmware/tests/unit/mock/path.py b/ansible_collections/community/vmware/tests/unit/mock/path.py
index 37959e5c8..f6a3ebb46 100644
--- a/ansible_collections/community/vmware/tests/unit/mock/path.py
+++ b/ansible_collections/community/vmware/tests/unit/mock/path.py
@@ -4,7 +4,8 @@
from __future__ import absolute_import, division, print_function
__metaclass__ = type
-from ansible_collections.community.vmware.tests.unit.compat.mock import MagicMock
+from unittest.mock import MagicMock
+
from ansible.utils.path import unfrackpath
diff --git a/ansible_collections/community/vmware/tests/unit/mock/procenv.py b/ansible_collections/community/vmware/tests/unit/mock/procenv.py
index 30f3b2bf6..4cb47f572 100644
--- a/ansible_collections/community/vmware/tests/unit/mock/procenv.py
+++ b/ansible_collections/community/vmware/tests/unit/mock/procenv.py
@@ -21,11 +21,11 @@ from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import sys
+import unittest
import json
from contextlib import contextmanager
from io import BytesIO, StringIO
-from ansible_collections.community.vmware.tests.unit.compat import unittest
from ansible.module_utils.six import PY3
from ansible.module_utils._text import to_bytes
diff --git a/ansible_collections/community/vmware/tests/unit/module_utils/test_vmware.py b/ansible_collections/community/vmware/tests/unit/module_utils/test_vmware.py
index 11483d34d..5b1790abe 100644
--- a/ansible_collections/community/vmware/tests/unit/module_utils/test_vmware.py
+++ b/ansible_collections/community/vmware/tests/unit/module_utils/test_vmware.py
@@ -10,9 +10,10 @@ import ssl
import sys
import pytest
+from unittest import mock
+
pyvmomi = pytest.importorskip('pyVmomi')
-from ansible_collections.community.vmware.tests.unit.compat import mock
from ansible_collections.community.vmware.plugins.module_utils.vmware import option_diff
import ansible_collections.community.vmware.plugins.module_utils.vmware as vmware_module_utils
@@ -110,7 +111,7 @@ def test_lib_loading_failure(monkeypatch, fake_ansible_module, key, libname):
with pytest.raises(FailJsonException):
vmware_module_utils.PyVmomi(fake_ansible_module)
error_str = 'Failed to import the required Python library (%s)' % libname
- assert fake_ansible_module.fail_json.called_once()
+ fake_ansible_module.fail_json.assert_called_once()
assert error_str in fake_ansible_module.fail_json.call_args[1]['msg']
@@ -121,7 +122,7 @@ def test_required_params(request, params, msg, fake_ansible_module):
fake_ansible_module.params = params
with pytest.raises(FailJsonException):
vmware_module_utils.connect_to_api(fake_ansible_module)
- assert fake_ansible_module.fail_json.called_once()
+ fake_ansible_module.fail_json.assert_called_once()
# TODO: assert msg in fake_ansible_module.fail_json.call_args[1]['msg']
@@ -135,7 +136,7 @@ def test_validate_certs(monkeypatch, fake_ansible_module):
vmware_module_utils.PyVmomi(fake_ansible_module)
msg = 'pyVim does not support changing verification mode with python < 2.7.9.' \
' Either update python or use validate_certs=false.'
- assert fake_ansible_module.fail_json.called_once()
+ fake_ansible_module.fail_json.assert_called_once()
assert msg == fake_ansible_module.fail_json.call_args[1]['msg']
@@ -157,7 +158,7 @@ def test_vmdk_disk_path_split_negative(monkeypatch, fake_ansible_module):
with pytest.raises(FailJsonException):
pyv = vmware_module_utils.PyVmomi(fake_ansible_module)
pyv.vmdk_disk_path_split('[ds1]')
- assert fake_ansible_module.fail_json.called_once()
+ fake_ansible_module.fail_json.assert_called_once()
assert 'Bad path' in fake_ansible_module.fail_json.call_args[1]['msg']
diff --git a/ansible_collections/community/vmware/tests/unit/modules/cloud/vmware/test_vmware_host_sriov.py b/ansible_collections/community/vmware/tests/unit/modules/cloud/vmware/test_vmware_host_sriov.py
index 1d2190dbb..a8ade1fa9 100644
--- a/ansible_collections/community/vmware/tests/unit/modules/cloud/vmware/test_vmware_host_sriov.py
+++ b/ansible_collections/community/vmware/tests/unit/modules/cloud/vmware/test_vmware_host_sriov.py
@@ -2,14 +2,10 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type
import json
-
-
-try:
- from unittest import mock
-except ImportError:
- import mock
import unittest
+from unittest import mock
+
from ansible.module_utils import basic
from ansible.module_utils._text import to_bytes
diff --git a/ansible_collections/community/vmware/tests/unit/modules/utils.py b/ansible_collections/community/vmware/tests/unit/modules/utils.py
index 001d6c165..d27a8ef0c 100644
--- a/ansible_collections/community/vmware/tests/unit/modules/utils.py
+++ b/ansible_collections/community/vmware/tests/unit/modules/utils.py
@@ -5,9 +5,10 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type
import json
+import unittest
+
+from unittest.mock import patch
-from ansible_collections.community.vmware.tests.unit.compat import unittest
-from ansible_collections.community.vmware.tests.unit.compat.mock import patch
from ansible.module_utils import basic
from ansible.module_utils._text import to_bytes
diff --git a/ansible_collections/community/vmware/tools/create_documentation_tasks.yml b/ansible_collections/community/vmware/tools/create_documentation_tasks.yml
deleted file mode 100644
index 8394cd0bf..000000000
--- a/ansible_collections/community/vmware/tools/create_documentation_tasks.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-- name: Install tox
- ansible.builtin.pip:
- name: tox
-
-- name: Refresh module documentation and README.md
- ansible.builtin.shell: tox -e add_docs
diff --git a/ansible_collections/community/vmware/tools/prepare_release.yml b/ansible_collections/community/vmware/tools/prepare_release.yml
index fb14a22fc..3d52dd28c 100644
--- a/ansible_collections/community/vmware/tools/prepare_release.yml
+++ b/ansible_collections/community/vmware/tools/prepare_release.yml
@@ -20,16 +20,14 @@
regexp: "^version: "
line: "version: {{ version }}"
- - name: Update documentation
- import_tasks: create_documentation_tasks.yml
-
- - name: Refresh the changelog
- ansible.builtin.shell: 'tox -e antsibull-changelog -- release --verbose --version {{ version }}'
+ - name: Update changelog
+ block:
+ - name: Install tox
+ ansible.builtin.pip:
+ name: tox
- - name: Clean up the changelog fragments
- ansible.builtin.file:
- path: "{{ playbook_dir }}/../changelogs/fragments"
- state: absent
+ - name: Refresh the changelog
+ ansible.builtin.shell: 'tox -e antsibull-changelog -- release --verbose --version {{ version }}'
- name: Add everything
ansible.builtin.shell: git add --all
diff --git a/ansible_collections/community/vmware/tools/update_documentation.yml b/ansible_collections/community/vmware/tools/update_documentation.yml
deleted file mode 100644
index da65057c0..000000000
--- a/ansible_collections/community/vmware/tools/update_documentation.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-- hosts: localhost
- tasks:
- - name: Update documentation
- import_tasks: create_documentation_tasks.yml
diff --git a/ansible_collections/community/vmware/tox.ini b/ansible_collections/community/vmware/tox.ini
index 2dff770b6..9428c771a 100644
--- a/ansible_collections/community/vmware/tox.ini
+++ b/ansible_collections/community/vmware/tox.ini
@@ -16,6 +16,8 @@ commands =
antsibull-changelog lint
{toxinidir}/tools/check-ignores-order
yamllint -c .yamllint.yaml tests
+allowlist_externals =
+ {toxinidir}/tools/check-ignores-order
[testenv:add_docs]
deps = git+https://github.com/ansible-network/collection_prep
diff --git a/ansible_collections/community/windows/.ansible-lint b/ansible_collections/community/windows/.ansible-lint
new file mode 100644
index 000000000..cad3b8e14
--- /dev/null
+++ b/ansible_collections/community/windows/.ansible-lint
@@ -0,0 +1,11 @@
+profile: production
+
+exclude_paths:
+ # This file is autogenerated so we cannot change the format
+ - changelogs/changelog.yaml
+ # Incorrect error around supported ansible versions in this file
+ - meta/runtime.yml
+ - tests/integration/
+ # We skip a rule that has to be skipped
+ - tests/sanity/ignore-*.txt
+ - tests/unit/
diff --git a/ansible_collections/community/windows/.azure-pipelines/azure-pipelines.yml b/ansible_collections/community/windows/.azure-pipelines/azure-pipelines.yml
index 2b5d2e8b0..8e434aa48 100644
--- a/ansible_collections/community/windows/.azure-pipelines/azure-pipelines.yml
+++ b/ansible_collections/community/windows/.azure-pipelines/azure-pipelines.yml
@@ -36,7 +36,7 @@ variables:
resources:
containers:
- container: default
- image: quay.io/ansible/azure-pipelines-test-container:3.0.0
+ image: quay.io/ansible/azure-pipelines-test-container:4.0.1
pool: Standard
@@ -44,89 +44,77 @@ stages:
- stage: Dependencies
displayName: Dependencies
jobs:
- - job: dep_download
- displayName: Download Dependencies
- pool:
- vmImage: ubuntu-latest
- steps:
- - checkout: self
- fetchDepth: 1
- - task: UsePythonVersion@0
- inputs:
- versionSpec: '3.10'
- - bash: python -m pip install ansible-core
- displayName: Install Ansible
- - bash: ansible-galaxy collection install -r tests/requirements.yml -p collections
- displayName: Install collection requirements
- - task: PublishPipelineArtifact@1
- inputs:
- targetPath: collections
- artifactName: CollectionRequirements
+ - job: dep_download
+ displayName: Download Dependencies
+ pool:
+ vmImage: ubuntu-latest
+ steps:
+ - checkout: self
+ fetchDepth: 1
+ - task: UsePythonVersion@0
+ inputs:
+ versionSpec: "3.10"
+ - bash: python -m pip install ansible-core
+ displayName: Install Ansible
+ - bash: ansible-galaxy collection install -r tests/requirements.yml -p collections
+ displayName: Install collection requirements
+ - task: PublishPipelineArtifact@1
+ inputs:
+ targetPath: collections
+ artifactName: CollectionRequirements
- stage: Ansible_devel
displayName: Ansible devel
dependsOn:
- - Dependencies
+ - Dependencies
jobs:
- template: templates/matrix.yml
parameters:
- nameFormat: '{0}'
- testFormat: 'devel/{0}'
+ nameFormat: "{0}"
+ testFormat: "devel/{0}"
targets:
- name: Sanity
test: sanity
- name: Units
test: units
- - stage: Ansible_2_15
- displayName: Ansible 2.15
+ - name: Lint
+ test: lint
+ - stage: Ansible_2_16
+ displayName: Ansible 2.16
dependsOn:
- - Dependencies
+ - Dependencies
jobs:
- template: templates/matrix.yml
parameters:
- nameFormat: '{0}'
- testFormat: '2.15/{0}'
+ nameFormat: "{0}"
+ testFormat: "2.16/{0}"
targets:
- name: Sanity
test: sanity
- name: Units
test: units
- - stage: Ansible_2_14
- displayName: Ansible 2.14
- dependsOn:
- - Dependencies
- jobs:
- - template: templates/matrix.yml
- parameters:
- nameFormat: '{0}'
- testFormat: '2.14/{0}'
- targets:
- - name: Sanity
- test: sanity
- - name: Units
- test: units
- - stage: Ansible_2_13
- displayName: Ansible 2.13
+ - stage: Ansible_2_15
+ displayName: Ansible 2.15
dependsOn:
- - Dependencies
+ - Dependencies
jobs:
- template: templates/matrix.yml
parameters:
- nameFormat: '{0}'
- testFormat: '2.13/{0}'
+ nameFormat: "{0}"
+ testFormat: "2.15/{0}"
targets:
- name: Sanity
test: sanity
- name: Units
test: units
- - stage: Ansible_2_12
- displayName: Ansible 2.12
+ - stage: Ansible_2_14
+ displayName: Ansible 2.14
dependsOn:
- - Dependencies
+ - Dependencies
jobs:
- template: templates/matrix.yml
parameters:
- nameFormat: '{0}'
- testFormat: '2.12/{0}'
+ nameFormat: "{0}"
+ testFormat: "2.14/{0}"
targets:
- name: Sanity
test: sanity
@@ -135,15 +123,13 @@ stages:
- stage: Windows
displayName: Windows
dependsOn:
- - Dependencies
+ - Dependencies
jobs:
- template: templates/matrix.yml
parameters:
nameFormat: Server {0}
testFormat: devel/windows/{0}
targets:
- - test: 2012
- - test: 2012-R2
- test: 2016
- test: 2019
- test: 2022
@@ -157,10 +143,9 @@ stages:
condition: succeededOrFailed()
dependsOn:
- Ansible_devel
+ - Ansible_2_16
- Ansible_2_15
- Ansible_2_14
- - Ansible_2_13
- - Ansible_2_12
- Windows
jobs:
- template: templates/coverage.yml
diff --git a/ansible_collections/community/windows/.github/workflows/docs-pr.yml b/ansible_collections/community/windows/.github/workflows/docs-pr.yml
index 3b89bc6a7..cc0320a93 100644
--- a/ansible_collections/community/windows/.github/workflows/docs-pr.yml
+++ b/ansible_collections/community/windows/.github/workflows/docs-pr.yml
@@ -2,7 +2,7 @@ name: Collection Docs
concurrency:
group: docs-pr-${{ github.head_ref }}
cancel-in-progress: true
-on:
+"on":
pull_request_target:
types: [opened, synchronize, reopened, closed]
@@ -44,7 +44,7 @@ jobs:
- name: PR comment
uses: ansible-community/github-docs-build/actions/ansible-docs-build-comment@main
with:
- body-includes: '## Docs Build'
+ body-includes: "## Docs Build"
reactions: heart
action: ${{ needs.build-docs.outputs.changed != 'true' && 'remove' || '' }}
on-closed-action: remove
diff --git a/ansible_collections/community/windows/.github/workflows/docs-push.yml b/ansible_collections/community/windows/.github/workflows/docs-push.yml
index a59f1553d..736e4db60 100644
--- a/ansible_collections/community/windows/.github/workflows/docs-push.yml
+++ b/ansible_collections/community/windows/.github/workflows/docs-push.yml
@@ -2,14 +2,14 @@ name: Collection Docs
concurrency:
group: docs-push-${{ github.sha }}
cancel-in-progress: true
-on:
+"on":
push:
branches:
- main
tags:
- - '*'
+ - "*"
schedule:
- - cron: '0 13 * * *'
+ - cron: "0 13 * * *"
jobs:
build-docs:
diff --git a/ansible_collections/community/windows/.github/workflows/stale.yml b/ansible_collections/community/windows/.github/workflows/stale.yml
index aef40d7fd..ae3719413 100644
--- a/ansible_collections/community/windows/.github/workflows/stale.yml
+++ b/ansible_collections/community/windows/.github/workflows/stale.yml
@@ -1,7 +1,7 @@
name: Stale pull request handler
-on:
+"on":
schedule:
- - cron: 0 0 * * *
+ - cron: 0 0 * * *
permissions:
pull-requests: write
@@ -11,13 +11,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/stale@v4.0.0
- id: stale
- with:
- days-before-stale: -1
- days-before-pr-stale: 28
- days-before-pr-close: 14
- stale-pr-label: stale
- stale-pr-message: >-
- This pull request is stale because it has been open for 4 weeks with no activity.
- Remove stale label or comment or this will be closed in 2 weeks.
+ - uses: actions/stale@v4.0.0
+ id: stale
+ with:
+ days-before-stale: -1
+ days-before-pr-stale: 28
+ days-before-pr-close: 14
+ stale-pr-label: stale
+ stale-pr-message: >-
+ This pull request is stale because it has been open for 4 weeks with no activity.
+ Remove stale label or comment or this will be closed in 2 weeks.
diff --git a/ansible_collections/community/windows/CHANGELOG.rst b/ansible_collections/community/windows/CHANGELOG.rst
index 45b4f6eaa..a034d4423 100644
--- a/ansible_collections/community/windows/CHANGELOG.rst
+++ b/ansible_collections/community/windows/CHANGELOG.rst
@@ -4,6 +4,83 @@ Community Windows Release Notes
.. contents:: Topics
+v2.2.0
+======
+
+Release Summary
+---------------
+
+Release summary for v2.2.0
+
+Minor Changes
+-------------
+
+- win_regmerge - Add content 'content' parameter for specifying registry file contents directly
+
+Bugfixes
+--------
+
+- win_format, win_partition - Add support for Windows failover cluster disks
+- win_psmodule - Fix up error message with ``state=latest``
+- win_robocopy - Fix up ``cmd`` return value to include the executable ``robocopy``
+
+v2.1.0
+======
+
+Release Summary
+---------------
+
+Release summary for v2.1.0
+
+Minor Changes
+-------------
+
+- Set minimum supported Ansible version to 2.14 to align with the versions still supported by Ansible.
+
+Bugfixes
+--------
+
+- Remove some code which is no longer valid for dotnet 5+
+- community.windows.win_psmodule_info - exception thrown when host has no Installed Module. Fix now checks that variable $installedModules is not null before calling the .Contains(..) function on it.
+- win_rabbitmq_plugin - Avoid using ``Invoke-Expression`` when running external commands
+- win_rds_rap - The module crashed when creating a RAP with Gateway Managed Computer Group (https://github.com/ansible-collections/community.windows/issues/184).
+
+v2.0.0
+======
+
+Release Summary
+---------------
+
+Version ``2.0.0`` is a major release of the ``community.windows`` collection that removes some deprecated features. Please review the changelog to see what deprecated features have been removed in this release.
+
+Minor Changes
+-------------
+
+- win_dns_record - Added ``zone_scope`` option to manage a record in a specific zone scope
+
+Deprecated Features
+-------------------
+
+- win_domain_computer - Module is deprecated in favour of the ``microsoft.ad.computer`` module, the ``community.windows.win_domain_computer`` module will be removed in the ``3.0.0`` release of this collection.
+- win_domain_group - Module is deprecated in favour of the ``microsoft.ad.group`` module, the ``community.windows.win_domain_group`` module will be removed in the ``3.0.0`` release of this collection.
+- win_domain_group_membership - Module is deprecated in favour of the ``microsoft.ad.group`` module, the ``community.windows.win_domain_group_membership`` module will be removed in the ``3.0.0`` release of this collection.
+- win_domain_object_info - Module is deprecated in favour of the ``microsoft.ad.object_info`` module, the ``community.windows.win_domain_object_info`` module will be removed in the ``3.0.0`` release of this collection.
+- win_domain_ou - Module is deprecated in favour of the ``microsoft.ad.ou`` module, the ``community.windows.win_domain_ou`` module will be removed in the ``3.0.0`` release of this collection.
+- win_domain_user - Module is deprecated in favour of the ``microsoft.ad.user`` module, the ``community.windows.win_domain_user`` module will be removed in the ``3.0.0`` release of this collection.
+
+Removed Features (previously deprecated)
+----------------------------------------
+
+- Removed testing for Server 2012 and Server 2012 R2 as they are reaching End of Life status from Microsoft. These OS versions may continue to work but will not be tested in CI.
+- win_nssm - Removed the deprecated module option ``app_parameters``, use ``arguments`` instead.
+- win_psmodule - Removed the deprecated module option ``url``, use ``community.windows.win_psrepository`` to manage repositories instead
+- win_psmodule - Will no longer remove the ``repository`` specified when ``state: absent``, use ``community.windows.win_psrepository`` to manage repositories instead
+- win_scheduled_tasks - Removed support for a trigger ``repetition`` to be defined as a list of dictionary entries. Specify the ``repetition`` as a dictionary value rather than a list of dictionaries.
+
+Bugfixes
+--------
+
+- win_psmodule - fix requireLicenseAcceptance test so that it is no longer always true
v1.13.0
=======
@@ -326,7 +403,6 @@ Release Summary
This is the first proper release of the ``community.windows`` collection on 2020-07-18.
The changelog describes all changes made to the modules and plugins included in this collection since Ansible 2.9.0.
-
Minor Changes
-------------
diff --git a/ansible_collections/community/windows/FILES.json b/ansible_collections/community/windows/FILES.json
index 284a5a7ca..59c335f9d 100644
--- a/ansible_collections/community/windows/FILES.json
+++ b/ansible_collections/community/windows/FILES.json
@@ -102,7 +102,7 @@
"name": ".azure-pipelines/azure-pipelines.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ada52203f7901d9d80e8d41e6eebc59286cf5714861b6116f0f97e3b5a1b3ef6",
+ "chksum_sha256": "f9e66cbce7db2f8e7037e82c31b18245226c70b681dcf42fc63c96f3fe077b15",
"format": 1
},
{
@@ -123,21 +123,21 @@
"name": ".github/workflows/docs-pr.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "391d92c0465a8e47effc66a9cf324f29d0c4e2a930f88a51e3b59f293f3bd5af",
+ "chksum_sha256": "e04671e2fc8ead695e9c803b7bc515653a265704d2f15b1c42b3294ab022e202",
"format": 1
},
{
"name": ".github/workflows/docs-push.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ba71916285a82cf9cacc58f577512499bb43f41fd2ba27c00ac874218bae07a0",
+ "chksum_sha256": "ea42c6f23a4ca65338c3b6c60ba8c3685be82953436b90637c9d98c0911c45ae",
"format": 1
},
{
"name": ".github/workflows/stale.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3cc60f9f80d3ba1aa09b8a9567584d3afbe528096b3d51d54fd6d5c4059f6853",
+ "chksum_sha256": "504e98827023f00fa37cd0bc7e8cab6e0eecbf080bdd87a99f4201ed34899026",
"format": 1
},
{
@@ -193,14 +193,14 @@
"name": "changelogs/changelog.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5419d8ff3c4a72c1f34b09c65c2eb2ce65de539ca84131eb529ecc3f42c26796",
+ "chksum_sha256": "acc734e50ec2397abfa8a2b4c04c16f5f5fe6e5aeee829752838aeada0a1004e",
"format": 1
},
{
"name": "changelogs/config.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8f873bb78d459bee3cdc629a2699cbf3ee098b5fb23a9638debb3b6329a3c4cc",
+ "chksum_sha256": "6891b73b4bb0d0c9e85070ec6a3976e347181b3c9cdd9456c0a7b85766b6422b",
"format": 1
},
{
@@ -235,7 +235,7 @@
"name": "meta/runtime.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b3ac5ce6c7ef3a7d47cad35d9a0b4256e079e80aed408946b73baf607016ce00",
+ "chksum_sha256": "f4d1aaefc9e52171511e57cb7f1cfc178ec4dff4f9d08853075bdcbb4a0ddea4",
"format": 1
},
{
@@ -298,7 +298,7 @@
"name": "plugins/modules/psexec.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a156009dfc461486b41ddfa6b4693cc641873b89937ae03da7002ab4200e5997",
+ "chksum_sha256": "6b30a7063f4c36bea72ba06612b22c18fbd0e6bcb07ca1bac3d3fe006a1eb14c",
"format": 1
},
{
@@ -333,7 +333,7 @@
"name": "plugins/modules/win_auto_logon.ps1",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "84aba3946501f41523f0e41c064b312178f101337e41bf99c4b555978de90215",
+ "chksum_sha256": "51c0066bd04cc4568704cff9170b7a1821973afa6c11e6196b16e4ad7feab303",
"format": 1
},
{
@@ -375,14 +375,14 @@
"name": "plugins/modules/win_credential.ps1",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "80fa527239f1bfcfecdd6bf1c616f2d87c6189bd172d743738543a9e9cd0b321",
+ "chksum_sha256": "6f0eb7e5bdc435018d488e3c947e7deed3bc1477ca9e9702ebd147a8d73b87ac",
"format": 1
},
{
"name": "plugins/modules/win_credential.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "30a85aba06521091552b1fa44a137d7d988514ca81eeed77e86ade699d101e05",
+ "chksum_sha256": "da90b006141a7a03bd4128ebfa0bcc7161bff107f96638aff21b4a93a1f13da3",
"format": 1
},
{
@@ -459,14 +459,14 @@
"name": "plugins/modules/win_dns_record.ps1",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1657585583bbc73e932b55cbe86945ae68c931170771430415024258d7cf984d",
+ "chksum_sha256": "1806634992e7f38ed8218ddbf79a37141ea46936fa1b1dc59dfd1dc824c9e67c",
"format": 1
},
{
"name": "plugins/modules/win_dns_record.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "10a9b6919bef02f4034f83dd03560f1b77aff0406f00150b2d36c87a71b19060",
+ "chksum_sha256": "75d23179a2ccf6f8d71f9da78173790e3e0c7cdec719140d5485908e04e5a957",
"format": 1
},
{
@@ -494,7 +494,7 @@
"name": "plugins/modules/win_domain_computer.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "101d6fd2f2ef02c41c2cec63b4fa1ee8f460b11248c1dfc745c994a5d0ab9175",
+ "chksum_sha256": "d0e9b4bc1f347f99580946baae8359d88e01461d8db274b1efe27de7dea24390",
"format": 1
},
{
@@ -508,7 +508,7 @@
"name": "plugins/modules/win_domain_group.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fb916eeb85dce7f787139f38710681470a7a8a840d9361d9221bc9214c463884",
+ "chksum_sha256": "270c7869c34c1dc5a61db813da0690e9919570c841c759174875abc79625ad52",
"format": 1
},
{
@@ -522,7 +522,7 @@
"name": "plugins/modules/win_domain_group_membership.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "97fa2920c38801363c85556ea90f53b22f9ff066f54d9e5bcd3f06f0381616ac",
+ "chksum_sha256": "616cd688337e94fb1cb7e31f153700c8c515f7ef3719aac23c17afde7686e79f",
"format": 1
},
{
@@ -536,7 +536,7 @@
"name": "plugins/modules/win_domain_object_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "aa05994f622b5165b24eba67fcfdddede7b1f5cda26ac73a9f15eafbac2e9cbe",
+ "chksum_sha256": "fe2becb52bf28e56fe877c1f377752703d302d2e1868b45e66645a4693646939",
"format": 1
},
{
@@ -550,7 +550,7 @@
"name": "plugins/modules/win_domain_ou.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4043273060a7c06c086008b2227f612aa36dfaffb261004419e80c8cbadbedd1",
+ "chksum_sha256": "3fd9171adaf9d95b36b0c76d4001a8922d55a386617a3c084e356319709b5d73",
"format": 1
},
{
@@ -564,7 +564,7 @@
"name": "plugins/modules/win_domain_user.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ffe798e9c9350f6a1fc4289269c6693f6cc20128050e09d8fdcf74cbdeb9b1bd",
+ "chksum_sha256": "7c1593bcaaed2711f41ef6366e0d5ba50d6989c9bec255b627ab1e5476bcf352",
"format": 1
},
{
@@ -683,7 +683,7 @@
"name": "plugins/modules/win_format.ps1",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f34249c8490c3805bdf9318ad5312716ad163663266b8e493e9af3f7d910bde0",
+ "chksum_sha256": "87c46e72f4ffbcab5a7760e5eed9668c90401297192f59d6798570094f263267",
"format": 1
},
{
@@ -774,7 +774,7 @@
"name": "plugins/modules/win_iis_webapppool.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4bbaa7ca07e530b819b95fd1ba1afa424373362d53a03cd7a1b386121926a29e",
+ "chksum_sha256": "a0616e1302bd9afc15fb1fe6f27df0ebd984ca7d331924bcf0ec255e6e2201a8",
"format": 1
},
{
@@ -809,7 +809,7 @@
"name": "plugins/modules/win_inet_proxy.ps1",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d347533fbe138a3c22b01a6543a098ff43d01a2fbd663e1744e7ffadbab570b6",
+ "chksum_sha256": "69f8260ba7ff90407d0deb521fcc4156d276f397a2b73746edaebec3523f31a7",
"format": 1
},
{
@@ -865,7 +865,7 @@
"name": "plugins/modules/win_mapped_drive.ps1",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5758175d8fbf5bb442624ddb44497b9325faacb7fff23e9967916df5b75db8d6",
+ "chksum_sha256": "9581ca7440a217b919e60dca32cb6eeb489e912851dcd704aa8b0c32aafbe58a",
"format": 1
},
{
@@ -921,14 +921,14 @@
"name": "plugins/modules/win_nssm.ps1",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "40a69e606cb129c93644a67b1b18c49dd1cb1f93d28f51e3b5129189ebaa3c5a",
+ "chksum_sha256": "10f9bcd315bc9a413eb1ff032c77865048091ff47e11dbb38e88535a3f7a1ebe",
"format": 1
},
{
"name": "plugins/modules/win_nssm.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "03a2671f21160afbe8065cfb359a397683403edffe889099f78751f4dc7fc236",
+ "chksum_sha256": "4d5fee450a9ff0f5780f7874891c34c297ed1524b9a22614957c8554b197dc28",
"format": 1
},
{
@@ -949,7 +949,7 @@
"name": "plugins/modules/win_partition.ps1",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f74e3a9f1e375f074bf162a20f3a0724f7e18d78ba5730c555b047112c4dceb9",
+ "chksum_sha256": "dba5c80d079a7479dc93c692792cbed0d4ddd6947293527f03ae0dee4d337a93",
"format": 1
},
{
@@ -1019,21 +1019,21 @@
"name": "plugins/modules/win_psmodule.ps1",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "892a75069e7880102b5816ff654fcc0d730e3d04d5fc9ae139e1b6ed57af4435",
+ "chksum_sha256": "d01a267bd3a69ab50e8c4ff2a57496ee9c0d5c89afcb86bc724f7f54dcbb8bbe",
"format": 1
},
{
"name": "plugins/modules/win_psmodule.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "133ad88c1854ddfabc775e9bd0c3298f294cbe17170a1374bee0d38011dd5df9",
+ "chksum_sha256": "ac7931ddce525878bb89e73581bd55943788d8fe6f53eee18fb15da3c2d5d6b4",
"format": 1
},
{
"name": "plugins/modules/win_psmodule_info.ps1",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "59f0097dbee173d19af29d9e403d1979cbe67ee82dd3983b561743f3d9faf98a",
+ "chksum_sha256": "1d30f60c398b7b53f51df29944788a80d6a0f05ea983e8bcd4eeee080939a6c2",
"format": 1
},
{
@@ -1131,7 +1131,7 @@
"name": "plugins/modules/win_rabbitmq_plugin.ps1",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "07addf969c9dd2aa3976166d666088f9b2ae983c14d9b093f11df73e85427fcc",
+ "chksum_sha256": "6cbf960ac3ba845976971b9607ba696a099229f27273a2bdf9e02aa7cccc533d",
"format": 1
},
{
@@ -1159,7 +1159,7 @@
"name": "plugins/modules/win_rds_rap.ps1",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a68868e66f66e4a61770a9ee796e99e8ebbe357115f84ad4da828c64526d2227",
+ "chksum_sha256": "818f11da75fd59f1acb92311d3d1c3aaa694818a20a3d65ff0bb346c544787bd",
"format": 1
},
{
@@ -1187,7 +1187,7 @@
"name": "plugins/modules/win_region.ps1",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "dc30a601eb36f93f8eebe60b3c72fe465dd5ce398158592c3987188009348b01",
+ "chksum_sha256": "58e3f10a8730f2c06443cdaab0823ed530e4fc8a90ce312505bc630bce998c70",
"format": 1
},
{
@@ -1201,21 +1201,21 @@
"name": "plugins/modules/win_regmerge.ps1",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4f2dbcc0eb79462e852a0c5fd980b8648a5afadbbb10340e8360281e30daadbf",
+ "chksum_sha256": "5bdcb076d4ec4daad3f3878ebf570249d06cd9aa2c73e5a5bac7766d9e690648",
"format": 1
},
{
"name": "plugins/modules/win_regmerge.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "681d727dab3d657faa5066afdf8297e0a7aeb7a2541ce671d31ae155b7e7999b",
+ "chksum_sha256": "16353c422cb513a4aa95557c50a661c0f9a81b3ce2ac60d7a47bda69540bb8e7",
"format": 1
},
{
"name": "plugins/modules/win_robocopy.ps1",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9598922f7696810f4a460223401cb9b068095bb93fc2b8a75729b80328c1ec45",
+ "chksum_sha256": "0aab4398e3f5c84be878d111112b0b96400a976864e6d35a47fce968951fa253",
"format": 1
},
{
@@ -1257,7 +1257,7 @@
"name": "plugins/modules/win_scheduled_task.ps1",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3e96402641385a6f49b4de9570cb1c389015fe32dbdb111006ed9e9e5d5a3036",
+ "chksum_sha256": "a24a38351245c1ecbb5c75d7bfbfe4ae48f10071f46f46bfe49a084c31cb7c28",
"format": 1
},
{
@@ -1698,7 +1698,7 @@
"name": "tests/integration/targets/setup_win_device/library/win_device.ps1",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ebab88c2d4b9e18e34416b0c2950c53667ac82f3541ddce608336a3bfedfe016",
+ "chksum_sha256": "dd14c9de24e7d4b98933ec647855943f9c7ce2bc3a620e7afdceab312967b6a3",
"format": 1
},
{
@@ -1838,7 +1838,7 @@
"name": "tests/integration/targets/win_audit_rule/library/test_get_audit_rule.ps1",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "950e0feb2ffb782733e73110d4b97461351c78795fd8e3f08f221bda9174dbc1",
+ "chksum_sha256": "ed0025cc73f469716c8078170b5e843143e8e1141b04f12e5a767965d96efda7",
"format": 1
},
{
@@ -1915,7 +1915,7 @@
"name": "tests/integration/targets/win_auto_logon/library/test_autologon_info.ps1",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5ee3deabbadcd11357c7215a8d8b61967d58fae1541e06fd7f6a6f06a6acc88f",
+ "chksum_sha256": "f9344d3e8ea22a902f00f4938a5f225a9fe42453b3213363edbb32886c9c5749",
"format": 1
},
{
@@ -2118,7 +2118,7 @@
"name": "tests/integration/targets/win_credential/library/test_cred_facts.ps1",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "30545f69012f834c56b0bacfe121e2ea81d14f3fb513b1ff9de9401c8c0c2646",
+ "chksum_sha256": "1a65f992212e4e2e045b79b6014b27bc94314c784d184cc8862c24cd10045046",
"format": 1
},
{
@@ -2195,14 +2195,14 @@
"name": "tests/integration/targets/win_data_deduplication/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "11015c09652cce419325b63f7e5a8a2243ee87d5174a119d569c51a774776990",
+ "chksum_sha256": "e140d411afb8b79a7577198b20fe365c681d01055384a292d42806f668e6ddd2",
"format": 1
},
{
"name": "tests/integration/targets/win_data_deduplication/tasks/pre_test.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a0005d284731b397c14fce162751f7df806f1ce3bde97f9e5af79dd46412d991",
+ "chksum_sha256": "99f1637ea650578796bd4eee82135ee1ad6bb95b2aa16592aa48fcd48bf547c0",
"format": 1
},
{
@@ -2237,7 +2237,7 @@
"name": "tests/integration/targets/win_data_deduplication/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "73346dc8234e120681840b8d2642d4ebd05e1d25db50cb2cbe9376e5632528c8",
+ "chksum_sha256": "758d23e7651820af7b1af35846b0a80daee9e3c321fd9e93a0f60b929035610f",
"format": 1
},
{
@@ -2314,7 +2314,7 @@
"name": "tests/integration/targets/win_disk_facts/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "25d09891b2275f91de4d285b10e8d93437e1be449691bfa328875b963e841084",
+ "chksum_sha256": "e0ee323b8dc5a00d08437896e844ed7f5586d761baaca2689439df816384762a",
"format": 1
},
{
@@ -2370,7 +2370,7 @@
"name": "tests/integration/targets/win_dns_record/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f9cee2e389f87db84fe355d51e7517db5737663e1373765c2ff5b923eaf19e92",
+ "chksum_sha256": "522e5f3cb38a169d18a5363bd0cdeddd6577b3abdd4db3113a5b15736ad89597",
"format": 1
},
{
@@ -2503,7 +2503,7 @@
"name": "tests/integration/targets/win_dns_zone/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8ba362a47e99d88d85643228ff2a522e7e4c1496b38e09d024fa05b20b993542",
+ "chksum_sha256": "5663f103af71f218bb9a50a0d25b7dd6cc83f8761d3ef3c93c7f697f6b6bd1c0",
"format": 1
},
{
@@ -2685,7 +2685,7 @@
"name": "tests/integration/targets/win_domain_ou/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "247913365e3e278d856d0a3264801f680390008f151e1824e53419c04471bb0e",
+ "chksum_sha256": "1aabf18b3e493a2bf65e8256494940c15795202c0132ef951482454ec995d2da",
"format": 1
},
{
@@ -2748,7 +2748,7 @@
"name": "tests/integration/targets/win_domain_user/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "247913365e3e278d856d0a3264801f680390008f151e1824e53419c04471bb0e",
+ "chksum_sha256": "1aabf18b3e493a2bf65e8256494940c15795202c0132ef951482454ec995d2da",
"format": 1
},
{
@@ -3007,7 +3007,7 @@
"name": "tests/integration/targets/win_firewall/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7f5f4eb215f2a504baa753e868434b6942a07378e5d8a65ded04fd355964c8fa",
+ "chksum_sha256": "d7127ace6c1571fdf343a57b543cd35ed5b5181a330ab6e79ea892bf1ffff082",
"format": 1
},
{
@@ -3070,14 +3070,14 @@
"name": "tests/integration/targets/win_format/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "caf4a8024c4bc4133974d5f64086f381e7acbae8e4a4b005bbd896e14751ff5d",
+ "chksum_sha256": "e1697f5d2174eace51fd9c5a9fd39e3b0f385d390b77b16714e9026e17e82423",
"format": 1
},
{
"name": "tests/integration/targets/win_format/tasks/pre_test.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7c0849818d5413031a20e8a0d22152d8bb8ee8428b87df32ae335ef1935c5e2b",
+ "chksum_sha256": "605dde22f21960667693488dc68a4af01fe646025a431482835dae4da6c3f7c7",
"format": 1
},
{
@@ -3553,7 +3553,7 @@
"name": "tests/integration/targets/win_inet_proxy/library/win_inet_proxy_info.ps1",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "802f94faa392e3437e2ca6b3344fd646d28de42b3003788dcf23813acce5b279",
+ "chksum_sha256": "d8dc6e3a2400e0e84f217ae62073adaa904db15e6b2a5a8c804fb8bbef225f0b",
"format": 1
},
{
@@ -3623,7 +3623,7 @@
"name": "tests/integration/targets/win_initialize_disk/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a919bbc05e30662072f7cffef03f934527564d1952fab12370f466f53e0e7a5b",
+ "chksum_sha256": "bf6852c5596e05cc768a17b95ccb2b4f4d168918c252f6a9dbc9dd6f3d12e9f7",
"format": 1
},
{
@@ -4239,7 +4239,7 @@
"name": "tests/integration/targets/win_nssm/tasks/tests.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6ea9f0f86fd003478b4a1b284f6ed3f278912e5dfe5bfd4825ac8a8a74195f3e",
+ "chksum_sha256": "7cbfa6b4edf95562b9e47afc6081d6d2a5f6c03897905cf0e7fadca86886b43e",
"format": 1
},
{
@@ -4323,7 +4323,7 @@
"name": "tests/integration/targets/win_partition/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b11173553bfb63c218e5f4100c538d6d2cceb11a0f09771d0da768d50efa880e",
+ "chksum_sha256": "7f6faaa2b8815d0e608a72f50b1ae4acb36f9def21768645e22f61b22cbeb8e2",
"format": 1
},
{
@@ -4589,14 +4589,14 @@
"name": "tests/integration/targets/win_psmodule/files/module/template.psd1",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e3c123b79dc7d6c177aad7aec2340f3fd67c42bbbb58f056c792f416bc165160",
+ "chksum_sha256": "5a411be05c13817cfaab55b0b70616364d5c4278bc4e64863e760dc2edd141f3",
"format": 1
},
{
"name": "tests/integration/targets/win_psmodule/files/module/template.psm1",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c3af1c293b061aeae55a75922f682b72fe073d23a0214a92ecdf0330ae236c74",
+ "chksum_sha256": "9b49040430524eab09037994e7b0d8f2f6d0f843cd0f77d4081a2e6d81ab0a70",
"format": 1
},
{
@@ -4610,14 +4610,14 @@
"name": "tests/integration/targets/win_psmodule/files/setup_certs.sh",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4db82cd49211a1b4463ec62639d894099c781468198ea22d1448edc8f56d2a01",
+ "chksum_sha256": "4b11bc1ba1c7d92fc8d9d9d4a544a76e4991ea5d00b3458a2d3f43f8f002f7b6",
"format": 1
},
{
"name": "tests/integration/targets/win_psmodule/files/setup_modules.ps1",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "71ab33b143470a2ca97ee569f906401cfcef2efdebd2758ef37c26df35c41624",
+ "chksum_sha256": "e7c6c6a7553f7c07ce0e5d4ef3c07324bf87f4d55e41ca53737bef27cfb56b2e",
"format": 1
},
{
@@ -4659,14 +4659,14 @@
"name": "tests/integration/targets/win_psmodule/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1b2adee5ca3e7db150c1ad9adcbe1b485ac72c2d8fc9b614949a0414950a6784",
+ "chksum_sha256": "f9c5ee848b771149076768be9c678aed807c33c1f233f4a29eebd7f3fb5f5c16",
"format": 1
},
{
"name": "tests/integration/targets/win_psmodule/tasks/setup.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "91ab3cbcd9536663ad8f68671add4d794152923e3eb76c04d3aea439aa9e60c3",
+ "chksum_sha256": "c7ccb7644b101659b949b7836f7e0f7400b417b09f2b0d7d3c334ce9f8b898fe",
"format": 1
},
{
@@ -5531,6 +5531,13 @@
"format": 1
},
{
+ "name": "tests/integration/targets/win_regmerge/files/settings1c.reg",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9821422fa24c2ed02b15e97aeb9e71250a97a2f76edbc08dc688ce095cd97907",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/win_regmerge/files/settings2.reg",
"ftype": "file",
"chksum_type": "sha256",
@@ -5545,6 +5552,13 @@
"format": 1
},
{
+ "name": "tests/integration/targets/win_regmerge/files/settings3c.reg",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "597165b8a39656ac0f00b52eaee83bd3f8913f33b6e77d692dbac94c528c6216",
+ "format": 1
+ },
+ {
"name": "tests/integration/targets/win_regmerge/meta",
"ftype": "dir",
"chksum_type": null,
@@ -5569,7 +5583,7 @@
"name": "tests/integration/targets/win_regmerge/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "334193f120c8b5dff8a7ce25f0b81f5b7eb2b47aea9ef93ea44fe77ad418cc96",
+ "chksum_sha256": "3898860d5721005f107dbac08d111a16f2447d6b9b892eed76f65b45d54d14e4",
"format": 1
},
{
@@ -5639,7 +5653,7 @@
"name": "tests/integration/targets/win_route/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "131541f93918493fa5b08f5c3530f3f061a9ba09527b6d30ba7a2aa5fdb983e9",
+ "chksum_sha256": "9ac97039b67100936e00412c2750abcfc2f9fb72a3738d0254c880a7511f6eb8",
"format": 1
},
{
@@ -5751,7 +5765,7 @@
"name": "tests/integration/targets/win_scheduled_task/tasks/triggers.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "276ab72db53df66741541bbf8307dc0d93d2223b6d05ca703606736e3b377618",
+ "chksum_sha256": "95ca035a21af310338182001ea0e56b434c51d72665fcc287ab24c8f78466395",
"format": 1
},
{
@@ -5856,7 +5870,7 @@
"name": "tests/integration/targets/win_scoop/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7ca8e11325c78f2d61739d8993cb9846c41a74083f1a52399e6bafd8ffcbe2c7",
+ "chksum_sha256": "758d23e7651820af7b1af35846b0a80daee9e3c321fd9e93a0f60b929035610f",
"format": 1
},
{
@@ -5905,7 +5919,7 @@
"name": "tests/integration/targets/win_scoop_bucket/aliases",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "dfe04062f14c840d5f0ba976715b69d7f347084312eee07a233081f28bd78bb6",
+ "chksum_sha256": "1aabf18b3e493a2bf65e8256494940c15795202c0132ef951482454ec995d2da",
"format": 1
},
{
@@ -6462,139 +6476,41 @@
"format": 1
},
{
- "name": "tests/sanity/ignore-2.12.txt",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "adbb2b958c5689ab8a5376528853a261f23292a7386a16f2ee445894b513ccfc",
- "format": 1
- },
- {
- "name": "tests/sanity/ignore-2.13.txt",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "adbb2b958c5689ab8a5376528853a261f23292a7386a16f2ee445894b513ccfc",
- "format": 1
- },
- {
"name": "tests/sanity/ignore-2.14.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "adbb2b958c5689ab8a5376528853a261f23292a7386a16f2ee445894b513ccfc",
+ "chksum_sha256": "34d5db2339487ea46fe63a62a31074ae416d290c53f05d3097674fb7ad5c8cd4",
"format": 1
},
{
"name": "tests/sanity/ignore-2.15.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "adbb2b958c5689ab8a5376528853a261f23292a7386a16f2ee445894b513ccfc",
+ "chksum_sha256": "34d5db2339487ea46fe63a62a31074ae416d290c53f05d3097674fb7ad5c8cd4",
"format": 1
},
{
"name": "tests/sanity/ignore-2.16.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "adbb2b958c5689ab8a5376528853a261f23292a7386a16f2ee445894b513ccfc",
- "format": 1
- },
- {
- "name": "tests/unit",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/unit/compat",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/unit/compat/__init__.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
- "format": 1
- },
- {
- "name": "tests/unit/compat/mock.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "a4c95e1616f09fd8cecc228b798dc4a15936d96764e3d9ccdfd7a0d65bec38e4",
- "format": 1
- },
- {
- "name": "tests/unit/mock",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/unit/mock/__init__.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
- "format": 1
- },
- {
- "name": "tests/unit/mock/loader.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "3b51ec0d45347a3568300e50f688998007e346f052bd2e961c2ac6d13f7cee4d",
- "format": 1
- },
- {
- "name": "tests/unit/mock/path.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "94808cc4dc172c6b671c9b01db06c497c2af358ab989d16ab0638701e88f1921",
+ "chksum_sha256": "34d5db2339487ea46fe63a62a31074ae416d290c53f05d3097674fb7ad5c8cd4",
"format": 1
},
{
- "name": "tests/unit/mock/procenv.py",
+ "name": "tests/sanity/ignore-2.17.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f924e8a25cfa0531e00bc35df6e3b9790469302296f662c225374b12797bba7b",
+ "chksum_sha256": "34d5db2339487ea46fe63a62a31074ae416d290c53f05d3097674fb7ad5c8cd4",
"format": 1
},
{
- "name": "tests/unit/mock/vault_helper.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "4535613601c419f7d20f0c21e638dabccf69b4a7fac99d5f6f9b81d1519dafd6",
- "format": 1
- },
- {
- "name": "tests/unit/mock/yaml_helper.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "fada9f3506c951e21c60c2a0e68d3cdf3cadd71c8858b2d14a55c4b778f10983",
- "format": 1
- },
- {
- "name": "tests/unit/modules",
+ "name": "tests/unit",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/unit/modules/__init__.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
- "format": 1
- },
- {
- "name": "tests/unit/modules/utils.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "f69d69fb3ae2f709ff2470342f81bd8db3d7a03bc6296e099a0791d782faffb6",
- "format": 1
- },
- {
"name": "tests/unit/plugins",
"ftype": "dir",
"chksum_type": null,
@@ -6609,20 +6525,6 @@
"format": 1
},
{
- "name": "tests/unit/plugins/lookup/fixtures",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/unit/plugins/lookup/fixtures/avi.json",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "3739de410d134591fada61f62053bfab6fcbd5c80fe2267faa7971f9fe36570d",
- "format": 1
- },
- {
"name": "tests/unit/plugins/lookup/__init__.py",
"ftype": "file",
"chksum_type": "sha256",
@@ -6633,7 +6535,7 @@
"name": "tests/unit/plugins/lookup/test_laps_password.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d23071d213784b71a61661cc7c63ce4308c177ea8f758e3c53c14420675923f2",
+ "chksum_sha256": "750dc241398eb37b8185e37e920df70a2dfca313ee677a8f8af802df6975d48b",
"format": 1
},
{
@@ -6679,6 +6581,13 @@
"format": 1
},
{
+ "name": "tests/utils/shippable/lint.sh",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "f945142c1487de0996b9bc46bc18c82d5c0b6c9470f0f48b87634c2e4b0eabf5",
+ "format": 1
+ },
+ {
"name": "tests/utils/shippable/sanity.sh",
"ftype": "file",
"chksum_type": "sha256",
@@ -6717,7 +6626,14 @@
"name": "tests/requirements.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bd88d210dd7925cf3eb92089130a1b224d03d9b5819460d8f5c2730e36b660b2",
+ "chksum_sha256": "2cc0597c9b37871d09d40b2bb2621a9a283c77bf7ff156aab15b9e7d2eb3c1c0",
+ "format": 1
+ },
+ {
+ "name": ".ansible-lint",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "33235ea099dc7bd2061e0271afcef60424799834d3023d14652b6296e3f133c2",
"format": 1
},
{
@@ -6738,7 +6654,7 @@
"name": "CHANGELOG.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d7402c38ff658706bd14d6c7db15c7b50fbcafad51d03d4ef81ea4c2094cf20c",
+ "chksum_sha256": "c19e618b935eb0588c50cf40f93359070055ef669fbcbfdc94a339cca07c4258",
"format": 1
},
{
@@ -6752,7 +6668,7 @@
"name": "README.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d41e4c3d8b7699c6d9770a9824f75094b45c3cf933a76fcdfa1d6736ba33a3d3",
+ "chksum_sha256": "98b212d39e176b17d4495994075de095d518680b0c61300404878f9c040c7712",
"format": 1
}
],
diff --git a/ansible_collections/community/windows/MANIFEST.json b/ansible_collections/community/windows/MANIFEST.json
index 9ccb7a7c3..d70dd8520 100644
--- a/ansible_collections/community/windows/MANIFEST.json
+++ b/ansible_collections/community/windows/MANIFEST.json
@@ -2,7 +2,7 @@
"collection_info": {
"namespace": "community",
"name": "windows",
- "version": "1.13.0",
+ "version": "2.2.0",
"authors": [
"Jordan Borean @jborean93",
"Matt Davis @nitzmahone"
@@ -15,7 +15,7 @@
"license": [],
"license_file": "COPYING",
"dependencies": {
- "ansible.windows": ">=0.0.0,<2.0.0"
+ "ansible.windows": ">=1.0.0,<3.0.0"
},
"repository": "https://github.com/ansible-collections/community.windows",
"documentation": "https://docs.ansible.com/ansible/devel/collections/community/windows",
@@ -26,7 +26,7 @@
"name": "FILES.json",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3052b173ce376c2ede2b3307a6074b34d1bf10f772e8941fca335477e66958b8",
+ "chksum_sha256": "0c430f767a4fe9b34435d4387118a1ba094819990922437b39aa7a95673f1367",
"format": 1
},
"format": 1
diff --git a/ansible_collections/community/windows/README.md b/ansible_collections/community/windows/README.md
index 895999ee2..489e2b836 100644
--- a/ansible_collections/community/windows/README.md
+++ b/ansible_collections/community/windows/README.md
@@ -8,7 +8,7 @@ The `community.windows` collection includes the community plugins supported by A
## Ansible version compatibility
-This collection has been tested against following Ansible versions: **>=2.12**.
+This collection has been tested against following Ansible versions: **>=2.14**.
Plugins and modules within a collection may be tested with only specific Ansible versions.
A collection may contain metadata that identifies these versions.
diff --git a/ansible_collections/community/windows/changelogs/changelog.yaml b/ansible_collections/community/windows/changelogs/changelog.yaml
index d64c61b79..58d105a3b 100644
--- a/ansible_collections/community/windows/changelogs/changelog.yaml
+++ b/ansible_collections/community/windows/changelogs/changelog.yaml
@@ -462,3 +462,97 @@ releases:
- 347_win_iis_virtualdirectory.yml
- release-2.9.0.yml
release_date: '2021-12-21'
+ 2.0.0:
+ changes:
+ bugfixes:
+ - win_psmodule - fix requireLicenseAcceptance test so that it is no longer always
+ true
+ deprecated_features:
+ - win_domain_computer - Module is deprecated in favour of the ``microsoft.ad.computer``
+ module, the ``community.windows.win_domain_computer`` module will be removed
+ in the ``3.0.0`` release of this collection.
+ - win_domain_group - Module is deprecated in favour of the ``microsoft.ad.group``
+ module, the ``community.windows.win_domain_group`` module will be removed
+ in the ``3.0.0`` release of this collection.
+ - win_domain_group_membership - Module is deprecated in favour of the ``microsoft.ad.group``
+ module, the ``community.windows.win_domain_group_membership`` module will
+ be removed in the ``3.0.0`` release of this collection.
+ - win_domain_object_info - Module is deprecated in favour of the ``microsoft.ad.object_info``
+ module, the ``community.windows.win_domain_object_info`` module will be removed
+ in the ``3.0.0`` release of this collection.
+ - win_domain_ou - Module is deprecated in favour of the ``microsoft.ad.ou``
+ module, the ``community.windows.win_domain_ou`` module will be removed in
+ the ``3.0.0`` release of this collection.
+ - win_domain_user - Module is deprecated in favour of the ``microsoft.ad.user``
+ module, the ``community.windows.win_domain_user`` module will be removed in
+ the ``3.0.0`` release of this collection.
+ minor_changes:
+ - win_dns_record - Added ``zone_scope`` option to manage a record in a specific
+ zone scope
+ release_summary: Version ``2.0.0`` is a major release of the ``community.windows``
+ collection that removes some deprecated features. Please review the changelog
+ to see what deprecated features have been removed in this release.
+ removed_features:
+ - Removed testing for Server 2012 and Server 2012 R2 as they are reaching End
+ of Life status from Microsoft. These OS versions may continue to work but
+ will not be tested in CI.
+ - win_nssm - Removed the deprecated module option ``app_parameters``, use ``arguments``
+ instead.
+ - win_psmodule - Removed the deprecated module option ``url``, use ``community.windows.win_psrepository``
+ to manage repositories instead
+ - 'win_psmodule - Will no longer remove the ``repository`` specified when ``state:
+ absent``, use ``community.windows.win_psrepository`` to manage repositories
+ instead'
+ - win_scheduled_tasks - Removed support for a trigger ``repetition`` to be defined
+ as a list of dictionary entries. Specify the ``repetition`` as a dictionary
+ value rather than a list of dictionaries.
+ fragments:
+ - 522-win_psmodule-requirelicenseacceptance.yml
+ - microsoft-ad-deprecations.yml
+ - release_summary.yml
+ - server2012.yml
+ - win_dns_record-zone-scope.yml
+ - win_nssm-removed-features.yml
+ - win_psmodule-removed-features.yml
+ - win_scheduled_task-removed-features.yml
+ release_date: '2023-06-14'
+ 2.1.0:
+ changes:
+ bugfixes:
+ - Remove some code which is no longer valid for dotnet 5+
+ - community.windows.win_psmodule_info - exception thrown when host has no Installed
+ Module. Fix now checks that variable $installedModules is not null before
+ calling the .Contains(..) function on it.
+ - win_rabbitmq_plugin - Avoid using ``Invoke-Expression`` when running external
+ commands
+ - win_rds_rap - The module crashed when creating a RAP with Gateway Managed
+ Computer Group (https://github.com/ansible-collections/community.windows/issues/184).
+ minor_changes:
+ - Set minimum supported Ansible version to 2.14 to align with the versions still
+ supported by Ansible.
+ release_summary: Release summary for v2.1.0
+ fragments:
+ - 534-rds-rap-fix-gw-managed-comp-groups.yml
+ - ansible_support.yml
+ - dotnet-preparation.yml
+ - release_summary.yml
+ - win_psmodule_info.yml
+ - win_rabbitmq_plugin_iex.yml
+ release_date: '2023-11-16'
+ 2.2.0:
+ changes:
+ bugfixes:
+ - win_format, win_partition - Add support for Windows failover cluster disks
+ - win_psmodule - Fix up error message with ``state=latest``
+ - win_robocopy - Fix up ``cmd`` return value to include the executable ``robocopy``
+ minor_changes:
+ - win_regmerge - Add content 'content' parameter for specifying registry file
+ contents directly
+ release_summary: Release summary for v2.2.0
+ fragments:
+ - 543-support_for_failover_cluster.yaml
+ - 546-win_regmerge-add_content_parameter.yaml
+ - release-summary.yml
+ - win_psmodule-error.yml
+ - win_robocopy-cmd.yml
+ release_date: '2024-03-20'
diff --git a/ansible_collections/community/windows/changelogs/config.yaml b/ansible_collections/community/windows/changelogs/config.yaml
index 78e36a2b4..92ae1e2b8 100644
--- a/ansible_collections/community/windows/changelogs/config.yaml
+++ b/ansible_collections/community/windows/changelogs/config.yaml
@@ -9,21 +9,21 @@ notesdir: fragments
prelude_section_name: release_summary
prelude_section_title: Release Summary
sections:
-- - major_changes
- - Major Changes
-- - minor_changes
- - Minor Changes
-- - breaking_changes
- - Breaking Changes / Porting Guide
-- - deprecated_features
- - Deprecated Features
-- - removed_features
- - Removed Features (previously deprecated)
-- - security_fixes
- - Security Fixes
-- - bugfixes
- - Bugfixes
-- - known_issues
- - Known Issues
+ - - major_changes
+ - Major Changes
+ - - minor_changes
+ - Minor Changes
+ - - breaking_changes
+ - Breaking Changes / Porting Guide
+ - - deprecated_features
+ - Deprecated Features
+ - - removed_features
+ - Removed Features (previously deprecated)
+ - - security_fixes
+ - Security Fixes
+ - - bugfixes
+ - Bugfixes
+ - - known_issues
+ - Known Issues
title: Community Windows
trivial_section_name: trivial
diff --git a/ansible_collections/community/windows/meta/runtime.yml b/ansible_collections/community/windows/meta/runtime.yml
index 1f0649152..34003e06c 100644
--- a/ansible_collections/community/windows/meta/runtime.yml
+++ b/ansible_collections/community/windows/meta/runtime.yml
@@ -1 +1,27 @@
-requires_ansible: '>=2.12'
+requires_ansible: '>=2.14'
+plugin_routing:
+ modules:
+ win_domain_computer:
+ deprecation:
+ removal_version: 3.0.0
+ warning_text: Use microsoft.ad.computer instead.
+ win_domain_group_membership:
+ deprecation:
+ removal_version: 3.0.0
+ warning_text: Use microsoft.ad.group instead.
+ win_domain_group:
+ deprecation:
+ removal_version: 3.0.0
+ warning_text: Use microsoft.ad.group instead.
+ win_domain_object_info:
+ deprecation:
+ removal_version: 3.0.0
+ warning_text: Use microsoft.ad.object_info instead.
+ win_domain_ou:
+ deprecation:
+ removal_version: 3.0.0
+ warning_text: Use microsoft.ad.ou instead.
+ win_domain_user:
+ deprecation:
+ removal_version: 3.0.0
+ warning_text: Use microsoft.ad.user instead. \ No newline at end of file
diff --git a/ansible_collections/community/windows/plugins/modules/psexec.py b/ansible_collections/community/windows/plugins/modules/psexec.py
index 36541ca67..c2d96f293 100644
--- a/ansible_collections/community/windows/plugins/modules/psexec.py
+++ b/ansible_collections/community/windows/plugins/modules/psexec.py
@@ -283,7 +283,7 @@ EXAMPLES = r'''
$sec_protocols = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::SystemDefault
$sec_protocols = $sec_protocols -bor [Net.SecurityProtocolType]::Tls12
[Net.ServicePointManager]::SecurityProtocol = $sec_protocols
- $url = "https://github.com/ansible/ansible/raw/devel/examples/scripts/ConfigureRemotingForAnsible.ps1"
+ $url = "https://github.com/ansible/ansible-documentation/raw/devel/examples/scripts/ConfigureRemotingForAnsible.ps1"
Invoke-Expression ((New-Object Net.WebClient).DownloadString($url))
exit
delegate_to: localhost
diff --git a/ansible_collections/community/windows/plugins/modules/win_auto_logon.ps1 b/ansible_collections/community/windows/plugins/modules/win_auto_logon.ps1
index 66a20dd9e..ee76c4f7a 100644
--- a/ansible_collections/community/windows/plugins/modules/win_auto_logon.ps1
+++ b/ansible_collections/community/windows/plugins/modules/win_auto_logon.ps1
@@ -53,7 +53,6 @@ if ($state -eq 'absent') {
Add-CSharpType -AnsibleModule $module -References @'
using Microsoft.Win32.SafeHandles;
using System;
-using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Text;
@@ -154,8 +153,6 @@ namespace Ansible.WinAutoLogon
{
internal SafeLsaMemory() : base(true) { }
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
-
protected override bool ReleaseHandle()
{
return NativeMethods.LsaFreeMemory(handle) == 0;
@@ -171,8 +168,6 @@ namespace Ansible.WinAutoLogon
base.SetHandle(ptr);
}
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
-
protected override bool ReleaseHandle()
{
if (handle != IntPtr.Zero)
@@ -185,8 +180,6 @@ namespace Ansible.WinAutoLogon
{
internal SafeLsaHandle() : base(true) { }
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
-
protected override bool ReleaseHandle()
{
return NativeMethods.LsaClose(handle) == 0;
diff --git a/ansible_collections/community/windows/plugins/modules/win_credential.ps1 b/ansible_collections/community/windows/plugins/modules/win_credential.ps1
index b39bff57e..72fd6960c 100644
--- a/ansible_collections/community/windows/plugins/modules/win_credential.ps1
+++ b/ansible_collections/community/windows/plugins/modules/win_credential.ps1
@@ -60,7 +60,6 @@ using Microsoft.Win32.SafeHandles;
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Text;
@@ -223,7 +222,6 @@ namespace Ansible.CredentialManager
{
public SafeCredentialBuffer() : base(true) { }
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
protected override bool ReleaseHandle()
{
NativeMethods.CredFree(handle);
@@ -242,7 +240,6 @@ namespace Ansible.CredentialManager
{
base.SetHandle(handle);
}
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
protected override bool ReleaseHandle()
{
Marshal.FreeHGlobal(handle);
diff --git a/ansible_collections/community/windows/plugins/modules/win_credential.py b/ansible_collections/community/windows/plugins/modules/win_credential.py
index fd605f0d0..ca942d926 100644
--- a/ansible_collections/community/windows/plugins/modules/win_credential.py
+++ b/ansible_collections/community/windows/plugins/modules/win_credential.py
@@ -97,7 +97,7 @@ options:
- When C(absent), the credential specified by I(name) and I(type) is
removed.
- When C(present), the credential specified by I(name) and I(type) is
- removed.
+ added.
type: str
choices: [ absent, present ]
default: present
diff --git a/ansible_collections/community/windows/plugins/modules/win_dns_record.ps1 b/ansible_collections/community/windows/plugins/modules/win_dns_record.ps1
index f19d9d3c4..5212d1ace 100644
--- a/ansible_collections/community/windows/plugins/modules/win_dns_record.ps1
+++ b/ansible_collections/community/windows/plugins/modules/win_dns_record.ps1
@@ -17,6 +17,7 @@ $spec = @{
value = @{ type = "list"; elements = "str"; default = @() ; aliases = @( 'values' ) }
weight = @{ type = "int" }
zone = @{ type = "str"; required = $true }
+ zone_scope = @{ type = "str" }
computer_name = @{ type = "str" }
}
required_if = @(, @("type", "SRV", @("port", "priority", "weight")))
@@ -34,6 +35,7 @@ $type = $module.Params.type
$values = $module.Params.value
$weight = $module.Params.weight
$zone = $module.Params.zone
+$zone_scope = $module.Params.zone_scope
$dns_computer_name = $module.Params.computer_name
$extra_args = @{}
@@ -42,6 +44,9 @@ $extra_args_new_records = @{}
if ($null -ne $dns_computer_name) {
$extra_args.ComputerName = $dns_computer_name
}
+if ($null -ne $zone_scope) {
+ $extra_args.ZoneScope = $zone_scope
+}
if ($aging -eq $true) {
$extra_args_new_records.AgeRecord = $true
}
@@ -118,7 +123,8 @@ if ($null -ne $records) {
$record_value = $record.RecordData.$(Get-DnsServerResourceRecordDataPropertyName).ToString()
if ((-Not $required_values.ContainsKey($record_value)) -Or (-Not $record_aging_old -eq $aging)) {
$record | Remove-DnsServerResourceRecord -ZoneName $zone -Force -WhatIf:$module.CheckMode @extra_args
- $changes.before += "[$zone] $($record.HostName) $($record.TimeToLive.TotalSeconds) IN $type $record_value`n"
+ $changes.before += "[$zone{0}] $($record.HostName) $($record.TimeToLive.TotalSeconds) IN $type $record_value`n" `
+ -f ("", "/$zone_scope")[$null -ne $zone_scope]
$module.Result.changed = $true
}
else {
@@ -136,10 +142,12 @@ if ($null -ne $records) {
Set-DnsServerResourceRecord -ZoneName $zone -OldInputObject $record -NewInputObject $new_record -WhatIf:$module.CheckMode @extra_args
$changes.before += -join @(
- "[$zone] $($record.HostName) $($record.TimeToLive.TotalSeconds) IN "
+ "[$zone{0}] $($record.HostName) $($record.TimeToLive.TotalSeconds) IN " `
+ -f ("", "/$zone_scope")[$null -ne $zone_scope]
"$type $record_value $record_port_old $record_weight_old $record_priority_old`n"
)
- $changes.after += "[$zone] $($record.HostName) $($ttl.TotalSeconds) IN $type $record_value $port $weight $priority`n"
+ $changes.after += "[$zone{0}] $($record.HostName) $($ttl.TotalSeconds) IN $type $record_value $port $weight $priority`n" `
+ -f ("", "/$zone_scope")[$null -ne $zone_scope]
$module.Result.changed = $true
}
}
@@ -149,8 +157,10 @@ if ($null -ne $records) {
$new_record = $record.Clone()
$new_record.TimeToLive = $ttl
Set-DnsServerResourceRecord -ZoneName $zone -OldInputObject $record -NewInputObject $new_record -WhatIf:$module.CheckMode @extra_args
- $changes.before += "[$zone] $($record.HostName) $($record.TimeToLive.TotalSeconds) IN $type $record_value`n"
- $changes.after += "[$zone] $($record.HostName) $($ttl.TotalSeconds) IN $type $record_value`n"
+ $changes.before += "[$zone{0}] $($record.HostName) $($record.TimeToLive.TotalSeconds) IN $type $record_value`n" `
+ -f ("", "/$zone_scope")[$null -ne $zone_scope]
+ $changes.after += "[$zone{0}] $($record.HostName) $($ttl.TotalSeconds) IN $type $record_value`n" `
+ -f ("", "/$zone_scope")[$null -ne $zone_scope]
$module.Result.changed = $true
}
}
@@ -184,7 +194,8 @@ if ($null -ne $values -and $values.Count -gt 0) {
catch {
$module.FailJson("Error adding DNS $type resource $name in zone $zone with value $value", $_)
}
- $changes.after += "[$zone] $name $($ttl.TotalSeconds) IN $type $value`n"
+ $changes.after += "[$zone{0}] $name $($ttl.TotalSeconds) IN $type $value`n" `
+ -f ("", "/$zone_scope")[$null -ne $zone_scope]
}
$module.Result.changed = $true
}
@@ -199,12 +210,14 @@ else {
$records_end = Get-DnsServerResourceRecord -ZoneName $zone -Name $name -RRType $type -Node -ErrorAction:Ignore @extra_args | Sort-Object
$module.Diff.before = @(
$records | ForEach-Object {
- "[$zone] $($_.HostName) $($_.TimeToLive.TotalSeconds) IN $type $($_.RecordData.$(Get-DnsServerResourceRecordDataPropertyName).ToString())`n"
+ "[$zone{0}] $($_.HostName) $($_.TimeToLive.TotalSeconds) IN $type $($_.RecordData.$(Get-DnsServerResourceRecordDataPropertyName).ToString())`n" `
+ -f ("", "/$zone_scope")[$null -ne $zone_scope]
}
) -join ''
$module.Diff.after = @(
$records_end | ForEach-Object {
- "[$zone] $($_.HostName) $($_.TimeToLive.TotalSeconds) IN $type $($_.RecordData.$(Get-DnsServerResourceRecordDataPropertyName).ToString())`n"
+ "[$zone{0}] $($_.HostName) $($_.TimeToLive.TotalSeconds) IN $type $($_.RecordData.$(Get-DnsServerResourceRecordDataPropertyName).ToString())`n" `
+ -f ("", "/$zone_scope")[$null -ne $zone_scope]
}
) -join ''
}
diff --git a/ansible_collections/community/windows/plugins/modules/win_dns_record.py b/ansible_collections/community/windows/plugins/modules/win_dns_record.py
index 38692e311..97242c949 100644
--- a/ansible_collections/community/windows/plugins/modules/win_dns_record.py
+++ b/ansible_collections/community/windows/plugins/modules/win_dns_record.py
@@ -91,6 +91,13 @@ options:
- The zone must already exist.
required: yes
type: str
+ zone_scope:
+ description:
+ - The name of the zone scope to manage (eg C(ScopeAZ)).
+ - The zone must already exist.
+ required: no
+ type: str
+ version_added: 2.0.0
computer_name:
description:
- Specifies a DNS server.
@@ -193,6 +200,16 @@ EXAMPLES = r'''
type: "TXT"
value: "justavalue"
zone: "example.com"
+
+# Demostrate creating a A record to Zone Scope
+
+- name: Create database server record
+ community.windows.win_dns_record:
+ name: "cgyl1404p.amer.example.com"
+ type: "A"
+ value: "10.1.1.1"
+ zone: "amer.example.com"
+ zone_scope: "external"
'''
RETURN = r'''
diff --git a/ansible_collections/community/windows/plugins/modules/win_domain_computer.py b/ansible_collections/community/windows/plugins/modules/win_domain_computer.py
index aff0f4687..b19b0760e 100644
--- a/ansible_collections/community/windows/plugins/modules/win_domain_computer.py
+++ b/ansible_collections/community/windows/plugins/modules/win_domain_computer.py
@@ -13,6 +13,10 @@ description:
- Create, read, update and delete computers in Active Directory using a
windows bridge computer to launch New-ADComputer, Get-ADComputer,
Set-ADComputer, Remove-ADComputer and Move-ADObject powershell commands.
+deprecated:
+ removed_in: 3.0.0
+ why: This module has been moved into the C(microsoft.ad) collection.
+ alternative: Use the M(microsoft.ad.computer) module instead.
options:
name:
description:
diff --git a/ansible_collections/community/windows/plugins/modules/win_domain_group.py b/ansible_collections/community/windows/plugins/modules/win_domain_group.py
index b761055e8..729f6f6f7 100644
--- a/ansible_collections/community/windows/plugins/modules/win_domain_group.py
+++ b/ansible_collections/community/windows/plugins/modules/win_domain_group.py
@@ -11,6 +11,10 @@ short_description: Creates, modifies or removes domain groups
description:
- Creates, modifies or removes groups in Active Directory.
- For local groups, use the M(ansible.windows.win_group) module instead.
+deprecated:
+ removed_in: 3.0.0
+ why: This module has been moved into the C(microsoft.ad) collection.
+ alternative: Use the M(microsoft.ad.group) module instead.
options:
attributes:
description:
diff --git a/ansible_collections/community/windows/plugins/modules/win_domain_group_membership.py b/ansible_collections/community/windows/plugins/modules/win_domain_group_membership.py
index 5e10ac3b2..d3e0901f9 100644
--- a/ansible_collections/community/windows/plugins/modules/win_domain_group_membership.py
+++ b/ansible_collections/community/windows/plugins/modules/win_domain_group_membership.py
@@ -11,6 +11,10 @@ short_description: Manage Windows domain group membership
description:
- Allows the addition and removal of domain users
and domain groups from/to a domain group.
+deprecated:
+ removed_in: 3.0.0
+ why: This module has been moved into the C(microsoft.ad) collection.
+ alternative: Use the M(microsoft.ad.group) module instead.
options:
name:
description:
diff --git a/ansible_collections/community/windows/plugins/modules/win_domain_object_info.py b/ansible_collections/community/windows/plugins/modules/win_domain_object_info.py
index c7efac7fe..ddd0ab2d0 100644
--- a/ansible_collections/community/windows/plugins/modules/win_domain_object_info.py
+++ b/ansible_collections/community/windows/plugins/modules/win_domain_object_info.py
@@ -10,6 +10,10 @@ module: win_domain_object_info
short_description: Gather information an Active Directory object
description:
- Gather information about multiple Active Directory object(s).
+deprecated:
+ removed_in: 3.0.0
+ why: This module has been moved into the C(microsoft.ad) collection.
+ alternative: Use the M(microsoft.ad.object_info) module instead.
options:
domain_password:
description:
diff --git a/ansible_collections/community/windows/plugins/modules/win_domain_ou.py b/ansible_collections/community/windows/plugins/modules/win_domain_ou.py
index e144b8373..30ad0ed86 100644
--- a/ansible_collections/community/windows/plugins/modules/win_domain_ou.py
+++ b/ansible_collections/community/windows/plugins/modules/win_domain_ou.py
@@ -18,6 +18,10 @@ description:
- Manage Active Directory Organizational Units
- Adds, Removes and Modifies Active Directory Organizational Units
- Task should be delegated to a Windows Active Directory Domain Controller
+deprecated:
+ removed_in: 3.0.0
+ why: This module has been moved into the C(microsoft.ad) collection.
+ alternative: Use the M(microsoft.ad.ou) module instead.
options:
name:
description:
diff --git a/ansible_collections/community/windows/plugins/modules/win_domain_user.py b/ansible_collections/community/windows/plugins/modules/win_domain_user.py
index aee5efd0a..3e7290fff 100644
--- a/ansible_collections/community/windows/plugins/modules/win_domain_user.py
+++ b/ansible_collections/community/windows/plugins/modules/win_domain_user.py
@@ -9,6 +9,10 @@ module: win_domain_user
short_description: Manages Windows Active Directory user accounts
description:
- Manages Windows Active Directory user accounts.
+deprecated:
+ removed_in: 3.0.0
+ why: This module has been moved into the C(microsoft.ad) collection.
+ alternative: Use the M(microsoft.ad.user) module instead.
options:
name:
description:
diff --git a/ansible_collections/community/windows/plugins/modules/win_format.ps1 b/ansible_collections/community/windows/plugins/modules/win_format.ps1
index 0746fbe47..86d918e0b 100644
--- a/ansible_collections/community/windows/plugins/modules/win_format.ps1
+++ b/ansible_collections/community/windows/plugins/modules/win_format.ps1
@@ -74,7 +74,13 @@ function Get-AnsibleVolume {
if ($null -ne $DriveLetter) {
try {
- $volume = Get-Volume -DriveLetter $DriveLetter
+ # This needs to be a two step process so that we can support Windows failover cluster disks.
+ # With Windows failover cluster disks every node sees every disk participating in that cluster.
+ # For example a clustered disk in a three node cluster will show up three times.
+ # Fortunatly we can differentiate local from remote disk as only local disk will ever have a disk number.
+ # So with that we just ignore all disk without a number which will result in a local disk being picked.
+ $partition = Get-Partition -DriveLetter $DriveLetter | Where-Object { $null -ne $_.DiskNumber }
+ $volume = Get-Volume -Partition $partition
}
catch {
$module.FailJson("There was an error retrieving the volume using drive_letter $($DriveLetter): $($_.Exception.Message)", $_)
diff --git a/ansible_collections/community/windows/plugins/modules/win_iis_webapppool.py b/ansible_collections/community/windows/plugins/modules/win_iis_webapppool.py
index 7cca2e3bf..5397b9df5 100644
--- a/ansible_collections/community/windows/plugins/modules/win_iis_webapppool.py
+++ b/ansible_collections/community/windows/plugins/modules/win_iis_webapppool.py
@@ -94,6 +94,14 @@ EXAMPLES = r'''
managedRuntimeVersion: v4.0
autoStart: no
+- name: Creates an application pool with "No Managed Code" for .Net compatibility
+ community.windows.win_iis_webapppool:
+ name: AnotherAppPool
+ state: started
+ attributes:
+ managedRuntimeVersion: ''
+ autoStart: false
+
# In the below example we are setting attributes in child element processModel
# https://www.iis.net/configreference/system.applicationhost/applicationpools/add/processmodel
- name: Manage child element and set identity of application pool
diff --git a/ansible_collections/community/windows/plugins/modules/win_inet_proxy.ps1 b/ansible_collections/community/windows/plugins/modules/win_inet_proxy.ps1
index 769a8f725..e210057c9 100644
--- a/ansible_collections/community/windows/plugins/modules/win_inet_proxy.ps1
+++ b/ansible_collections/community/windows/plugins/modules/win_inet_proxy.ps1
@@ -68,7 +68,6 @@ $win_inet_invoke = @'
using Microsoft.Win32.SafeHandles;
using System;
using System.Collections.Generic;
-using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
namespace Ansible.WinINetProxy
@@ -197,7 +196,6 @@ namespace Ansible.WinINetProxy
base.SetHandle(handle);
}
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
protected override bool ReleaseHandle()
{
Marshal.FreeHGlobal(handle);
diff --git a/ansible_collections/community/windows/plugins/modules/win_mapped_drive.ps1 b/ansible_collections/community/windows/plugins/modules/win_mapped_drive.ps1
index 210ae223a..ff1898884 100644
--- a/ansible_collections/community/windows/plugins/modules/win_mapped_drive.ps1
+++ b/ansible_collections/community/windows/plugins/modules/win_mapped_drive.ps1
@@ -41,7 +41,6 @@ Add-CSharpType -AnsibleModule $module -References @'
using Microsoft.Win32.SafeHandles;
using System;
using System.Collections.Generic;
-using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
namespace Ansible.MappedDrive
@@ -160,7 +159,6 @@ namespace Ansible.MappedDrive
base.SetHandle(handle);
}
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
protected override bool ReleaseHandle()
{
Marshal.FreeHGlobal(handle);
diff --git a/ansible_collections/community/windows/plugins/modules/win_nssm.ps1 b/ansible_collections/community/windows/plugins/modules/win_nssm.ps1
index 3b951cf19..966780552 100644
--- a/ansible_collections/community/windows/plugins/modules/win_nssm.ps1
+++ b/ansible_collections/community/windows/plugins/modules/win_nssm.ps1
@@ -31,7 +31,6 @@ $description = Get-AnsibleParam -obj $params -name 'description' -type 'str'
$application = Get-AnsibleParam -obj $params -name "application" -type "path"
$appDirectory = Get-AnsibleParam -obj $params -name "working_directory" -aliases "app_directory", "chdir" -type "path"
-$appParameters = Get-AnsibleParam -obj $params -name "app_parameters"
$appArguments = Get-AnsibleParam -obj $params -name "arguments" -aliases "app_parameters_free_form"
$stdoutFile = Get-AnsibleParam -obj $params -name "stdout_file" -type "path"
@@ -46,7 +45,6 @@ $app_rotate_online = Get-AnsibleParam -obj $params -name "app_rotate_online" -ty
$app_stop_method_console = Get-AnsibleParam -obj $params -name "app_stop_method_console" -type "int"
$app_stop_method_skip = Get-AnsibleParam -obj $params -name "app_stop_method_skip" -type "int" -validateset 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
-# Deprecated options, will be removed in a major release after 2021-07-01.
$startMode = Get-AnsibleParam -obj $params -name "start_mode" -type "str" -default "auto" -validateset $start_modes_map.Keys -resultobj $result
$dependencies = Get-AnsibleParam -obj $params -name "dependencies" -type "list"
$user = Get-AnsibleParam -obj $params -name "username" -type "str" -aliases "user"
@@ -297,27 +295,6 @@ function Stop-NssmService {
}
}
-function Add-DepByDate {
- [CmdletBinding()]
- param(
- [Parameter(Mandatory = $true)]
- [String]$Message,
-
- [Parameter(Mandatory = $true)]
- [String]$Date
- )
-
- # Legacy doesn't natively support deprecate by date, need to do this manually until we use Ansible.Basic
- if (-not $result.ContainsKey('deprecations')) {
- $result.deprecations = @()
- }
- $result.deprecations += @{
- msg = $Message
- date = $Date
- collection_name = "community.windows"
- }
-}
-
Function ConvertTo-NormalizedUser {
[CmdletBinding()]
param (
@@ -380,38 +357,6 @@ Function ConvertTo-NormalizedUser {
}
}
-if (($null -ne $appParameters) -and ($null -ne $appArguments)) {
- Fail-Json $result "'app_parameters' and 'arguments' are mutually exclusive but have both been set."
-}
-
-# Backward compatibility for old parameters style. Remove the block bellow in 2.12
-if ($null -ne $appParameters) {
- $dep = @{
- Message = "The parameter 'app_parameters' will be removed soon, use 'arguments' instead"
- Date = "2022-07-01"
- }
- Add-DepByDate @dep
-
- if ($appParameters -isnot [string]) {
- Fail-Json -obj $result -message "The app_parameters parameter must be a string representing a dictionary."
- }
-
- # Convert dict-as-string form to list
- $escapedAppParameters = $appParameters.TrimStart("@").TrimStart("{").TrimEnd("}").Replace("; ", "`n").Replace("\", "\\")
- $appParametersHash = ConvertFrom-StringData -StringData $escapedAppParameters
-
- $appParamsArray = @()
- $appParametersHash.GetEnumerator() | Foreach-Object {
- if ($_.Name -ne "_") {
- $appParamsArray += $_.Name
- }
- $appParamsArray += $_.Value
- }
- $appArguments = @($appParamsArray)
-
- # The rest of the code should use only the new $appArguments variable
-}
-
if ($state -ne 'absent') {
if ($null -eq $application) {
Fail-Json -obj $result -message "The application parameter must be defined when the state is not absent."
diff --git a/ansible_collections/community/windows/plugins/modules/win_nssm.py b/ansible_collections/community/windows/plugins/modules/win_nssm.py
index d79f638b8..8cc434a5a 100644
--- a/ansible_collections/community/windows/plugins/modules/win_nssm.py
+++ b/ansible_collections/community/windows/plugins/modules/win_nssm.py
@@ -56,17 +56,10 @@ options:
description:
- Path to receive error output.
type: path
- app_parameters:
- description:
- - A string representing a dictionary of parameters to be passed to the application when it starts.
- - DEPRECATED since v2.8, please use I(arguments) instead.
- - This is mutually exclusive with I(arguments).
- type: str
arguments:
description:
- Parameters to be passed to the application when it starts.
- This can be either a simple string or a list.
- - This is mutually exclusive with I(app_parameters).
aliases: [ app_parameters_free_form ]
type: str
dependencies:
diff --git a/ansible_collections/community/windows/plugins/modules/win_partition.ps1 b/ansible_collections/community/windows/plugins/modules/win_partition.ps1
index 6e4517690..a6ce1d5c4 100644
--- a/ansible_collections/community/windows/plugins/modules/win_partition.ps1
+++ b/ansible_collections/community/windows/plugins/modules/win_partition.ps1
@@ -100,7 +100,12 @@ if ($null -ne $disk_number -and $null -ne $partition_number) {
# Check if drive_letter is either auto-assigned or a character from A-Z
elseif ($drive_letter -and $drive_letter -ne "auto" -and -not ($disk_number -and $partition_number)) {
if ($drive_letter -match "^[a-zA-Z]$") {
- $ansible_partition = Get-Partition -DriveLetter $drive_letter -ErrorAction SilentlyContinue
+ # This step need to be a bit more complex so that we can support Windows failover cluster disks.
+ # With Windows failover cluster disks every node sees every disk participating in that cluster.
+ # For example a clustered disk in a three node cluster will show up three times.
+ # Fortunatly we can differentiate local from remote disk as only local disk will ever have a disk number.
+ # So with that we just ignore all disk without a number which will result in a local disk being picked.
+ $ansible_partition = Get-Partition -DriveLetter $drive_letter -ErrorAction SilentlyContinue | Where-Object { $null -ne $_.DiskNumber }
}
else {
$module.FailJson("Incorrect usage of drive_letter: specify a drive letter from A-Z or use 'auto' to automatically assign a drive letter")
diff --git a/ansible_collections/community/windows/plugins/modules/win_psmodule.ps1 b/ansible_collections/community/windows/plugins/modules/win_psmodule.ps1
index f755e8dda..788519143 100644
--- a/ansible_collections/community/windows/plugins/modules/win_psmodule.ps1
+++ b/ansible_collections/community/windows/plugins/modules/win_psmodule.ps1
@@ -18,7 +18,6 @@ $maximum_version = Get-AnsibleParam -obj $params -name "maximum_version" -type "
$repo = Get-AnsibleParam -obj $params -name "repository" -type "str"
$repo_user = Get-AnsibleParam -obj $params -name "username" -type "str"
$repo_pass = Get-AnsibleParam -obj $params -name "password" -type "str"
-$url = Get-AnsibleParam -obj $params -name "url" -type str
$state = Get-AnsibleParam -obj $params -name "state" -type "str" -default "present" -validateset "present", "absent", "latest"
$allow_clobber = Get-AnsibleParam -obj $params -name "allow_clobber" -type "bool" -default $false
$skip_publisher_check = Get-AnsibleParam -obj $params -name "skip_publisher_check" -type "bool" -default $false
@@ -255,8 +254,11 @@ Function Install-PsModule {
"Repository", "Credential")
$ht = Add-DefinedParameter -Hashtable $ht -ParametersNames $ParametersNames
- # When module require License Acceptance, `-Force` is mandatory to skip interactive prompt
- if ((Find-Module @ht).AdditionalMetadata.requireLicenseAcceptance) {
+ # When module require License Acceptance, or repository is Untrusted.
+ # `-Force` is mandatory to skip interactive prompt
+ $psgetModuleInfo = Find-Module @ht
+ if (($psgetModuleInfo.AdditionalMetadata.requireLicenseAcceptance -eq "True") -or
+ ((Get-PSRepository -Name $psgetModuleInfo.Repository).InstallationPolicy -eq "Untrusted")) {
$ht["Force"] = $true
}
else {
@@ -363,82 +365,6 @@ Function Find-LatestPsModule {
$LatestModuleVersion
}
-Function Install-Repository {
- Param(
- [Parameter(Mandatory = $true)]
- [string]$Name,
- [Parameter(Mandatory = $true)]
- [string]$Url,
- [bool]$CheckMode
- )
- # Legacy doesn't natively support deprecate by date, need to do this manually until we use Ansible.Basic
- if (-not $result.ContainsKey('deprecations')) {
- $result.deprecations = @()
- }
- $msg = -join @(
- "Adding a repo with this module is deprecated, the repository parameter should only be used to select a repo. "
- "Use community.windows.win_psrepository to manage repos"
- )
- $result.deprecations += @{
- msg = $msg
- date = "2021-07-01"
- collection_name = "community.windows"
- }
- # Install NuGet provider if needed.
- Install-NugetProvider -CheckMode $CheckMode
-
- $Repos = (Get-PSRepository).SourceLocation
-
- # If repository isn't already present, try to register it as trusted.
- if ($Repos -notcontains $Url) {
- try {
- if ( -not ($CheckMode) ) {
- Register-PSRepository -Name $Name -SourceLocation $Url -InstallationPolicy Trusted -ErrorAction Stop
- }
- $result.changed = $true
- $result.repository_changed = $true
- }
- catch {
- $ErrorMessage = "Problems registering $($Name) repository: $($_.Exception.Message)"
- Fail-Json $result $ErrorMessage
- }
- }
-}
-
-Function Remove-Repository {
- Param(
- [Parameter(Mandatory = $true)]
- [string]$Name,
- [bool]$CheckMode
- )
- # Legacy doesn't natively support deprecate by date, need to do this manually until we use Ansible.Basic
- if (-not $result.ContainsKey('deprecations')) {
- $result.deprecations = @()
- }
- $result.deprecations += @{
- msg = "Removing a repo with this module is deprecated, use community.windows.win_psrepository to manage repos"
- date = "2021-07-01"
- collection_name = "community.windows"
- }
-
- $Repo = (Get-PSRepository).Name
-
- # Try to remove the repository
- if ($Repo -contains $Name) {
- try {
- if ( -not ($CheckMode) ) {
- Unregister-PSRepository -Name $Name -ErrorAction Stop
- }
- $result.changed = $true
- $result.repository_changed = $true
- }
- catch [ System.Exception ] {
- $ErrorMessage = "Problems unregistering $($Name)repository: $($_.Exception.Message)"
- Fail-Json $result $ErrorMessage
- }
- }
-}
-
# Check PowerShell version, fail if < 5.0 and required modules are not installed
$PsVersion = $PSVersionTable.PSVersion
if ($PsVersion.Major -lt 5 ) {
@@ -469,11 +395,11 @@ if ( $allow_prerelease -and $state -eq "absent" ) {
if ( ($state -eq "latest") -and
( $required_version -or $minimum_version -or $maximum_version ) ) {
- $ErrorMessage = "When the parameter state is equal 'latest' you can use any of required_version, minimum_version, maximum_version."
+ $ErrorMessage = "When the parameter state is equal to 'latest' you can't use any of required_version, minimum_version, maximum_version."
Fail-Json $result $ErrorMessage
}
-if ( $repo -and (-not $url) ) {
+if ( $repo ) {
$RepositoryExists = Get-PSRepository -Name $repo -ErrorAction SilentlyContinue
if ( $null -eq $RepositoryExists) {
$ErrorMessage = "The repository $repo doesn't exist."
@@ -498,13 +424,6 @@ if ( ($allow_clobber -or $allow_prerelease -or $skip_publisher_check -or
Import-Module -Name PackageManagement, PowerShellGet -Force
if ($state -eq "present") {
- if (($repo) -and ($url)) {
- Install-Repository -Name $repo -Url $url -CheckMode $check_mode
- }
- else {
- $ErrorMessage = "Repository Name and Url are mandatory if you want to add a new repository"
- }
-
if ($name) {
$ht = @{
Name = $name
@@ -524,10 +443,6 @@ if ($state -eq "present") {
}
}
elseif ($state -eq "absent") {
- if ($repo) {
- Remove-Repository -Name $repo -CheckMode $check_mode
- }
-
if ($name) {
$ht = @{
Name = $Name
diff --git a/ansible_collections/community/windows/plugins/modules/win_psmodule.py b/ansible_collections/community/windows/plugins/modules/win_psmodule.py
index ce2053aad..c3b3cbb5e 100644
--- a/ansible_collections/community/windows/plugins/modules/win_psmodule.py
+++ b/ansible_collections/community/windows/plugins/modules/win_psmodule.py
@@ -95,12 +95,6 @@ options:
required: no
default: false
version_added: '1.13.0'
- url:
- description:
- - URL of the custom repository to register.
- - DEPRECATED, will be removed in a major release after C(2021-07-01), please use the
- M(community.windows.win_psrepository) module instead.
- type: str
notes:
- PowerShell modules needed
- PowerShellGet >= 1.6.0
diff --git a/ansible_collections/community/windows/plugins/modules/win_psmodule_info.ps1 b/ansible_collections/community/windows/plugins/modules/win_psmodule_info.ps1
index b0932a79c..080949af2 100644
--- a/ansible_collections/community/windows/plugins/modules/win_psmodule_info.ps1
+++ b/ansible_collections/community/windows/plugins/modules/win_psmodule_info.ps1
@@ -263,7 +263,7 @@ function Add-ModuleRepositoryInfo {
Process {
$moduleName = $InputObject.Name
- $installed = if ($installedModules.Contains($moduleName)) {
+ $installed = if ($installedModules -and $installedModules.Contains($moduleName)) {
# we know at least one version of this module was installed from PowerShellGet
# if the version of this local modle matches what we got it in the initial installed module list
# use it
diff --git a/ansible_collections/community/windows/plugins/modules/win_rabbitmq_plugin.ps1 b/ansible_collections/community/windows/plugins/modules/win_rabbitmq_plugin.ps1
index f4ac711c6..dbe914042 100644
--- a/ansible_collections/community/windows/plugins/modules/win_rabbitmq_plugin.ps1
+++ b/ansible_collections/community/windows/plugins/modules/win_rabbitmq_plugin.ps1
@@ -6,33 +6,30 @@
#Requires -Module Ansible.ModuleUtils.Legacy
function Get-EnabledPlugin($rabbitmq_plugins_cmd) {
- $list_plugins_cmd = "$rabbitmq_plugins_cmd list -E -m"
try {
- $enabled_plugins = @(Invoke-Expression "& $list_plugins_cmd" | Where-Object { $_ })
+ $enabled_plugins = @(& $rabbitmq_plugins_cmd list -E -m | Where-Object { $_ })
return , $enabled_plugins
}
catch {
- Fail-Json -obj $result -message "Can't execute `"$($list_plugins_cmd)`": $($_.Exception.Message)"
+ Fail-Json -obj $result -message "Can't execute '$rabbitmq_plugins_cmd list -E -m': $($_.Exception.Message)"
}
}
function Enable-Plugin($rabbitmq_plugins_cmd, $plugin_name) {
- $enable_plugin_cmd = "$rabbitmq_plugins_cmd enable $plugin_name"
try {
- Invoke-Expression "& $enable_plugin_cmd"
+ & $rabbitmq_plugins_cmd enable $plugin_name
}
catch {
- Fail-Json -obj $result -message "Can't execute `"$($enable_plugin_cmd)`": $($_.Exception.Message)"
+ Fail-Json -obj $result -message "Can't execute '$rabbitmq_plugins_cmd enable $plugin_name': $($_.Exception.Message)"
}
}
function Disable-Plugin($rabbitmq_plugins_cmd, $plugin_name) {
- $enable_plugin_cmd = "$rabbitmq_plugins_cmd disable $plugin_name"
try {
- Invoke-Expression "& $enable_plugin_cmd"
+ & $rabbitmq_plugins_cmd disable $plugin_name
}
catch {
- Fail-Json -obj $result -message "Can't execute `"$($enable_plugin_cmd)`": $($_.Exception.Message)"
+ Fail-Json -obj $result -message "Can't execute '$rabbitmq_plugins_cmd disable $plugin_name': $($_.Exception.Message)"
}
}
diff --git a/ansible_collections/community/windows/plugins/modules/win_rds_rap.ps1 b/ansible_collections/community/windows/plugins/modules/win_rds_rap.ps1
index 956a812dd..2c4bb65bc 100644
--- a/ansible_collections/community/windows/plugins/modules/win_rds_rap.ps1
+++ b/ansible_collections/community/windows/plugins/modules/win_rds_rap.ps1
@@ -140,6 +140,11 @@ if ($null -ne $user_groups) {
$user_groups = @($user_groups)
}
+# Ensure RemoteDesktopServices module is loaded
+if ($null -eq (Get-Module -Name RemoteDesktopServices -ErrorAction SilentlyContinue)) {
+ Import-Module -Name RemoteDesktopServices
+}
+
# Validate computer group parameter
if ($computer_group_type -eq "allow_any" -and $null -ne $computer_group) {
Add-Warning -obj $result -message "Parameter 'computer_group' ignored because the computer_group_type is set to allow_any."
@@ -165,11 +170,6 @@ if ($null -ne $allowed_ports) {
}
}
-# Ensure RemoteDesktopServices module is loaded
-if ($null -eq (Get-Module -Name RemoteDesktopServices -ErrorAction SilentlyContinue)) {
- Import-Module -Name RemoteDesktopServices
-}
-
# Check if a RAP with the given name already exists
$rap_exist = Test-Path -LiteralPath "RDS:\GatewayServer\RAP\$name"
diff --git a/ansible_collections/community/windows/plugins/modules/win_region.ps1 b/ansible_collections/community/windows/plugins/modules/win_region.ps1
index 90713c12e..796854051 100644
--- a/ansible_collections/community/windows/plugins/modules/win_region.ps1
+++ b/ansible_collections/community/windows/plugins/modules/win_region.ps1
@@ -186,7 +186,11 @@ Function Get-UserLocaleName {
return $user_locale
}
-Function Get-ValidGeoId($cultures) {
+Function Get-ValidGeoId {
+ [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingEmptyCatchBlock', '',
+ Justification = 'We dont care about the error here')]
+ param($cultures)
+
$geo_ids = @()
foreach ($culture in $cultures) {
try {
diff --git a/ansible_collections/community/windows/plugins/modules/win_regmerge.ps1 b/ansible_collections/community/windows/plugins/modules/win_regmerge.ps1
index 8d511cc20..20942ba0e 100644
--- a/ansible_collections/community/windows/plugins/modules/win_regmerge.ps1
+++ b/ansible_collections/community/windows/plugins/modules/win_regmerge.ps1
@@ -7,6 +7,10 @@
#Requires -Module Ansible.ModuleUtils.CommandUtil
#Requires -Module Ansible.ModuleUtils.Legacy
+[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSCustomUseLiteralPath', '',
+ Justification = 'This module has supported wildcard comparison since it was created')]
+param()
+
Function Convert-RegistryPath {
Param (
[parameter(Mandatory = $True)]
@@ -24,17 +28,34 @@ $result = @{
}
$params = Parse-Args $args
-$path = Get-AnsibleParam -obj $params -name "path" -type "path" -failifempty $true -resultobj $result
+$path = Get-AnsibleParam -obj $params -name "path" -type "path" -resultobj $result
+$content = Get-AnsibleParam -obj $params -name "content" -type "str" -resultobj $result
$compare_to = Get-AnsibleParam -obj $params -name "compare_to" -type "str" -resultobj $result
+if ( !$path -and !$content ) {
+ Fail-Json -obj $result -message "Missing required arguments: path or content. At lease one must be provided."
+}
+
+if ( $path -and $content ) {
+ Fail-Json -obj $result -message "Extra arguments: path or content. Only one must be provided."
+}
+
+if ( $content ) {
+ $path = [System.IO.Path]::GetTempFileName()
+
+ Set-Content -LiteralPath $path -Value $content
+
+ $remove_path = $True
+}
+
# check it looks like a reg key, warn if key not present - will happen first time
# only accepting PS-Drive style key names (starting with HKLM etc, not HKEY_LOCAL_MACHINE etc)
$do_comparison = $False
-If ($compare_to) {
+If ( $compare_to ) {
$compare_to_key = $params.compare_to.ToString()
- If (Test-Path $compare_to_key -pathType container ) {
+ If (Test-Path $compare_to_key -PathType container ) {
$do_comparison = $True
}
Else {
@@ -96,4 +117,8 @@ Else {
$result.compared = $false
}
+if ( $remove_path ) {
+ Remove-Item $path
+}
+
Exit-Json $result
diff --git a/ansible_collections/community/windows/plugins/modules/win_regmerge.py b/ansible_collections/community/windows/plugins/modules/win_regmerge.py
index 073f54c9a..62c9be08c 100644
--- a/ansible_collections/community/windows/plugins/modules/win_regmerge.py
+++ b/ansible_collections/community/windows/plugins/modules/win_regmerge.py
@@ -21,8 +21,12 @@ options:
description:
- The full path including file name to the registry file on the remote machine to be merged
type: path
- required: yes
- compare_key:
+ content:
+ description:
+ - When used instead of O(path), merges the value specified into the Windows registry. It must not include the Byte Order Mark.
+ type: str
+ version_added: 2.2.0
+ compare_to:
description:
- The parent key to use when comparing the contents of the registry to the contents of the file. Needs to be in HKLM or HKCU part of registry.
Use a PS-Drive style path for example HKLM:\SOFTWARE not HKEY_LOCAL_MACHINE\SOFTWARE
@@ -53,6 +57,23 @@ EXAMPLES = r'''
community.windows.win_regmerge:
path: C:\autodeploy\myCompany-settings.reg
compare_to: HKLM:\SOFTWARE\myCompany
+
+- name: Merge in a registry file specified as content without comparing to current registry
+ community.windows.win_regmerge:
+ content: |
+ Windows Registry Editor Version 5.00
+
+ [HKEY_LOCAL_MACHINE\SOFTWARE\myCompany]
+ "ExampleKey"=dword:00000001
+
+- name: Compare and merge registry file specified as content
+ community.windows.win_regmerge:
+ content: |
+ Windows Registry Editor Version 5.00
+
+ [HKEY_LOCAL_MACHINE\SOFTWARE\myCompany]
+ "ExampleKey"=dword:00000001
+ compare_to: HKLM:\SOFTWARE\myCompany
'''
RETURN = r'''
diff --git a/ansible_collections/community/windows/plugins/modules/win_robocopy.ps1 b/ansible_collections/community/windows/plugins/modules/win_robocopy.ps1
index 2d3e05805..4975d2566 100644
--- a/ansible_collections/community/windows/plugins/modules/win_robocopy.ps1
+++ b/ansible_collections/community/windows/plugins/modules/win_robocopy.ps1
@@ -5,6 +5,10 @@
#Requires -Module Ansible.ModuleUtils.Legacy
+[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSCustomUseLiteralPath', '',
+ Justification = 'This module has supported wildcard comparison since it was created')]
+param()
+
$params = Parse-Args $args -supports_check_mode $true
$check_mode = Get-AnsibleParam -obj $params -name "_ansible_check_mode" -type "bool" -default $false
@@ -33,12 +37,12 @@ Function SearchForError($cmd_output, $default_msg) {
}
if ($separator_count -ne 3) {
- if (Select-String -InputObject $line -pattern "^(\s+)?(\-+)(\s+)?$") {
+ if (Select-String -InputObject $line -Pattern "^(\s+)?(\-+)(\s+)?$") {
$separator_count += 1
}
}
else {
- if (Select-String -InputObject $line -pattern "error") {
+ if (Select-String -InputObject $line -Pattern "error") {
$error_msg = $line
break
}
@@ -75,7 +79,7 @@ else {
}
$result.flags = $flags
-$result.cmd = "$robocopy $robocopy_opts"
+$result.cmd = "robocopy $robocopy_opts"
Try {
$robocopy_output = &robocopy $robocopy_opts
diff --git a/ansible_collections/community/windows/plugins/modules/win_scheduled_task.ps1 b/ansible_collections/community/windows/plugins/modules/win_scheduled_task.ps1
index 02cd012f8..fd1f52135 100644
--- a/ansible_collections/community/windows/plugins/modules/win_scheduled_task.ps1
+++ b/ansible_collections/community/windows/plugins/modules/win_scheduled_task.ps1
@@ -814,19 +814,6 @@ for ($i = 0; $i -lt $triggers.Count; $i++) {
}
if ($trigger.ContainsKey("repetition")) {
- if ($trigger.repetition -is [Array]) {
- # Legacy doesn't natively support deprecate by date, need to do this manually until we use Ansible.Basic
- if (-not $result.ContainsKey('deprecations')) {
- $result.deprecations = @()
- }
- $result.deprecations += @{
- msg = "repetition is a list, should be defined as a dict"
- date = "2021-07-01"
- collection_name = "community.windows"
- }
- $trigger.repetition = $trigger.repetition[0]
- }
-
$interval_timespan = $null
if ($trigger.repetition.ContainsKey("interval") -and $null -ne $trigger.repetition.interval) {
$interval_timespan = Test-XmlDurationFormat -key "interval" -value $trigger.repetition.interval
diff --git a/ansible_collections/community/windows/tests/integration/targets/setup_win_device/library/win_device.ps1 b/ansible_collections/community/windows/tests/integration/targets/setup_win_device/library/win_device.ps1
index 77fac9086..6674ddb26 100644
--- a/ansible_collections/community/windows/tests/integration/targets/setup_win_device/library/win_device.ps1
+++ b/ansible_collections/community/windows/tests/integration/targets/setup_win_device/library/win_device.ps1
@@ -30,7 +30,6 @@ Add-CSharpType -References @'
using Microsoft.Win32.SafeHandles;
using System;
using System.ComponentModel;
-using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Text;
@@ -246,7 +245,6 @@ namespace Ansible.Device
{
public SafeDeviceInfoSet() : base(true) { }
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
protected override bool ReleaseHandle()
{
return NativeMethods.SetupDiDestroyDeviceInfoList(handle);
@@ -271,7 +269,6 @@ namespace Ansible.Device
base.SetHandle(Marshal.StringToHGlobalUni(sz));
}
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
protected override bool ReleaseHandle()
{
Marshal.FreeHGlobal(handle);
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_audit_rule/library/test_get_audit_rule.ps1 b/ansible_collections/community/windows/tests/integration/targets/win_audit_rule/library/test_get_audit_rule.ps1
index 37096c21a..ab113356f 100644
--- a/ansible_collections/community/windows/tests/integration/targets/win_audit_rule/library/test_get_audit_rule.ps1
+++ b/ansible_collections/community/windows/tests/integration/targets/win_audit_rule/library/test_get_audit_rule.ps1
@@ -6,6 +6,10 @@
#Requires -Module Ansible.ModuleUtils.Legacy
#Requires -Module Ansible.ModuleUtils.SID
+[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSCustomUseLiteralPath', '',
+ Justification = 'LiteralPath with Get-Acl is problematic')]
+param()
+
$params = Parse-Args -arguments $args -supports_check_mode $true
# these are your module parameters
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_auto_logon/library/test_autologon_info.ps1 b/ansible_collections/community/windows/tests/integration/targets/win_auto_logon/library/test_autologon_info.ps1
index 2819151ff..d352f2ff7 100644
--- a/ansible_collections/community/windows/tests/integration/targets/win_auto_logon/library/test_autologon_info.ps1
+++ b/ansible_collections/community/windows/tests/integration/targets/win_auto_logon/library/test_autologon_info.ps1
@@ -8,7 +8,6 @@ $module = [Ansible.Basic.AnsibleModule]::Create($args, @{})
Add-CSharpType -AnsibleModule $module -References @'
using Microsoft.Win32.SafeHandles;
using System;
-using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Text;
@@ -103,8 +102,6 @@ namespace Ansible.TestAutoLogonInfo
{
internal SafeLsaMemory() : base(true) { }
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
-
protected override bool ReleaseHandle()
{
return NativeMethods.LsaFreeMemory(handle) == 0;
@@ -120,8 +117,6 @@ namespace Ansible.TestAutoLogonInfo
base.SetHandle(ptr);
}
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
-
protected override bool ReleaseHandle()
{
if (handle != IntPtr.Zero)
@@ -134,8 +129,6 @@ namespace Ansible.TestAutoLogonInfo
{
internal SafeLsaHandle() : base(true) { }
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
-
protected override bool ReleaseHandle()
{
return NativeMethods.LsaClose(handle) == 0;
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_credential/library/test_cred_facts.ps1 b/ansible_collections/community/windows/tests/integration/targets/win_credential/library/test_cred_facts.ps1
index 59206638f..fc2721f05 100644
--- a/ansible_collections/community/windows/tests/integration/targets/win_credential/library/test_cred_facts.ps1
+++ b/ansible_collections/community/windows/tests/integration/targets/win_credential/library/test_cred_facts.ps1
@@ -24,7 +24,6 @@ using Microsoft.Win32.SafeHandles;
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Text;
@@ -187,7 +186,6 @@ namespace Ansible.CredentialManager
{
public SafeCredentialBuffer() : base(true) { }
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
protected override bool ReleaseHandle()
{
NativeMethods.CredFree(handle);
@@ -206,7 +204,6 @@ namespace Ansible.CredentialManager
{
base.SetHandle(handle);
}
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
protected override bool ReleaseHandle()
{
Marshal.FreeHGlobal(handle);
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/aliases b/ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/aliases
index 2a4f8cc66..3cf5b97e8 100644
--- a/ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/aliases
+++ b/ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/aliases
@@ -1,2 +1 @@
shippable/windows/group3
-skip/windows/2012
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/tasks/main.yml
index ae6be90ec..83c7197c6 100644
--- a/ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/tasks/main.yml
+++ b/ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/tasks/main.yml
@@ -1,2 +1,2 @@
---
-- include: pre_test.yml
+- import_tasks: pre_test.yml
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/tasks/pre_test.yml b/ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/tasks/pre_test.yml
index d63468990..8028cb17b 100644
--- a/ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/tasks/pre_test.yml
+++ b/ansible_collections/community/windows/tests/integration/targets/win_data_deduplication/tasks/pre_test.yml
@@ -34,7 +34,7 @@
- name: Run tests
block:
- - include: tests.yml
+ - import_tasks: tests.yml
always:
- name: Detach disk
ansible.windows.win_command: diskpart.exe /s {{ remote_tmp_dir }}\partition_deletion_script.txt
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_disk_facts/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_disk_facts/tasks/main.yml
index f1873efa7..d55a7221c 100644
--- a/ansible_collections/community/windows/tests/integration/targets/win_disk_facts/tasks/main.yml
+++ b/ansible_collections/community/windows/tests/integration/targets/win_disk_facts/tasks/main.yml
@@ -10,4 +10,4 @@
block:
- name: Test in normal mode
- include: tests.yml
+ import_tasks: tests.yml
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/main.yml
index 9b06a65b0..32f754d08 100644
--- a/ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/main.yml
+++ b/ansible_collections/community/windows/tests/integration/targets/win_dns_record/tasks/main.yml
@@ -8,5 +8,5 @@
register: os_supported
- name: run tests on supported hosts
- include: tests.yml
+ import_tasks: tests.yml
when: os_supported.stdout | trim | bool
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_dns_zone/aliases b/ansible_collections/community/windows/tests/integration/targets/win_dns_zone/aliases
index df7c2d121..4cd27b3cb 100644
--- a/ansible_collections/community/windows/tests/integration/targets/win_dns_zone/aliases
+++ b/ansible_collections/community/windows/tests/integration/targets/win_dns_zone/aliases
@@ -1,2 +1 @@
shippable/windows/group1
-skip/windows/2012 \ No newline at end of file
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_domain_ou/aliases b/ansible_collections/community/windows/tests/integration/targets/win_domain_ou/aliases
index 22f581bfd..423ce3910 100644
--- a/ansible_collections/community/windows/tests/integration/targets/win_domain_ou/aliases
+++ b/ansible_collections/community/windows/tests/integration/targets/win_domain_ou/aliases
@@ -1,2 +1 @@
shippable/windows/group2
-skip/windows/2012
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_domain_user/aliases b/ansible_collections/community/windows/tests/integration/targets/win_domain_user/aliases
index 22f581bfd..423ce3910 100644
--- a/ansible_collections/community/windows/tests/integration/targets/win_domain_user/aliases
+++ b/ansible_collections/community/windows/tests/integration/targets/win_domain_user/aliases
@@ -1,2 +1 @@
shippable/windows/group2
-skip/windows/2012
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_firewall/aliases b/ansible_collections/community/windows/tests/integration/targets/win_firewall/aliases
index c8fd90a1f..4f4664b68 100644
--- a/ansible_collections/community/windows/tests/integration/targets/win_firewall/aliases
+++ b/ansible_collections/community/windows/tests/integration/targets/win_firewall/aliases
@@ -1,3 +1 @@
shippable/windows/group5
-skip/windows/2012
-skip/windows/2012-R2
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_format/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_format/tasks/main.yml
index 5ea27a6f0..71b897aac 100644
--- a/ansible_collections/community/windows/tests/integration/targets/win_format/tasks/main.yml
+++ b/ansible_collections/community/windows/tests/integration/targets/win_format/tasks/main.yml
@@ -3,5 +3,5 @@
ansible.windows.win_shell: if (Get-Command -Name Format-Volume -ErrorAction SilentlyContinue) { $true } else { $false }
register: module_present
-- include: pre_test.yml
+- include_tasks: pre_test.yml
when: module_present.stdout | trim | bool
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_format/tasks/pre_test.yml b/ansible_collections/community/windows/tests/integration/targets/win_format/tasks/pre_test.yml
index a29a47bbe..0fce957ef 100644
--- a/ansible_collections/community/windows/tests/integration/targets/win_format/tasks/pre_test.yml
+++ b/ansible_collections/community/windows/tests/integration/targets/win_format/tasks/pre_test.yml
@@ -15,7 +15,7 @@
- name: Run tests
block:
- - include: tests.yml
+ - import_tasks: tests.yml
always:
- name: Detach disk
ansible.windows.win_command: diskpart.exe /s {{ remote_tmp_dir }}\partition_deletion_script.txt
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_inet_proxy/library/win_inet_proxy_info.ps1 b/ansible_collections/community/windows/tests/integration/targets/win_inet_proxy/library/win_inet_proxy_info.ps1
index 76bf03ec9..810c8ba97 100644
--- a/ansible_collections/community/windows/tests/integration/targets/win_inet_proxy/library/win_inet_proxy_info.ps1
+++ b/ansible_collections/community/windows/tests/integration/targets/win_inet_proxy/library/win_inet_proxy_info.ps1
@@ -22,7 +22,6 @@ using Microsoft.Win32.SafeHandles;
using System;
using System.Collections.Generic;
using System.ComponentModel;
-using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
namespace Ansible.WinINetProxyInfo
@@ -138,7 +137,6 @@ namespace Ansible.WinINetProxyInfo
base.SetHandle(handle);
}
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
protected override bool ReleaseHandle()
{
Marshal.FreeHGlobal(handle);
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_initialize_disk/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_initialize_disk/tasks/main.yml
index b752a7913..303723e9e 100644
--- a/ansible_collections/community/windows/tests/integration/targets/win_initialize_disk/tasks/main.yml
+++ b/ansible_collections/community/windows/tests/integration/targets/win_initialize_disk/tasks/main.yml
@@ -17,7 +17,7 @@
- name: Run tests
block:
- - include: tests.yml
+ - import_tasks: tests.yml
always:
- name: Detach disk
ansible.windows.win_command: diskpart.exe /s C:\win_initialize_disk_tests\vhdx_deletion_script.txt
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_nssm/tasks/tests.yml b/ansible_collections/community/windows/tests/integration/targets/win_nssm/tasks/tests.yml
index cf8f0cfbe..b4ed06efd 100644
--- a/ansible_collections/community/windows/tests/integration/targets/win_nssm/tasks/tests.yml
+++ b/ansible_collections/community/windows/tests/integration/targets/win_nssm/tasks/tests.yml
@@ -401,52 +401,6 @@
- install_service_reset_appenv.changed == true
- install_service_reset_appenv_actual.stdout == '\r\n'
-# deprecated in 2.12
-- name: install service with dict-as-string parameters
- win_nssm:
- name: '{{ test_service_name }}'
- application: C:\Windows\System32\cmd.exe
- app_parameters: foo=true; -file.out=output.bat; -path=C:\with space\; -str=test"quotes; _=bar
- register: mixed_params
-
-# deprecated in 2.12
-- name: get result of install service with dict-as-string parameters
- ansible.windows.win_shell: '$service = ''{{ test_service_name }}''; {{ test_service_cmd }}'
- register: mixed_params_actual
-
-# deprecated in 2.12
-- name: assert results of install service with dict-as-string parameters
- assert:
- that:
- - mixed_params.changed == true
- - (mixed_params_actual.stdout|from_json).Exists == true
- - (mixed_params_actual.stdout|from_json).Parameters.Application == "C:\Windows\System32\cmd.exe"
- # Expected value: bar -file.out output.bat -str "test\"quotes" foo true -path "C:\with space\\" (backslashes doubled for jinja)
- - (mixed_params_actual.stdout|from_json).Parameters.AppParameters == 'bar -file.out output.bat -str "test\\"quotes" foo true -path "C:\\with space\\\\"'
-
-# deprecated in 2.12
-- name: install service with dict-as-string parameters (idempotent)
- win_nssm:
- name: '{{ test_service_name }}'
- application: C:\Windows\System32\cmd.exe
- app_parameters: foo=true; -file.out=output.bat; -path=C:\with space\; -str=test"quotes; _=bar
- register: mixed_params_again
-
-# deprecated in 2.12
-- name: get result of install service with dict-as-string parameters (idempotent)
- ansible.windows.win_shell: '$service = ''{{ test_service_name }}''; {{ test_service_cmd }}'
- register: mixed_params_again_actual
-
-# deprecated in 2.12
-- name: assert results of install service with dict-as-string parameters (idempotent)
- assert:
- that:
- - mixed_params_again.changed == false
- - (mixed_params_again_actual.stdout|from_json).Exists == true
- - (mixed_params_again_actual.stdout|from_json).Parameters.Application == "C:\Windows\System32\cmd.exe"
- # Expected value: bar -file.out output.bat -str "test\"quotes" foo true -path "C:\with space\\" (backslashes doubled for jinja)
- - (mixed_params_again_actual.stdout|from_json).Parameters.AppParameters == 'bar -file.out output.bat -str "test\\"quotes" foo true -path "C:\\with space\\\\"'
-
- name: install service with list of parameters
win_nssm:
name: '{{ test_service_name }}'
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_partition/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_partition/tasks/main.yml
index 50d086ae1..54e7f8a9d 100644
--- a/ansible_collections/community/windows/tests/integration/targets/win_partition/tasks/main.yml
+++ b/ansible_collections/community/windows/tests/integration/targets/win_partition/tasks/main.yml
@@ -12,7 +12,7 @@
- name: Run tests
block:
- - include: tests.yml
+ - import_tasks: tests.yml
always:
- name: Detach disk
ansible.windows.win_command: diskpart.exe /s "{{ remote_tmp_dir }}\vhdx_deletion_script.txt"
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/module/template.psd1 b/ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/module/template.psd1
index cd6709722..f4441fd87 100644
--- a/ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/module/template.psd1
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/module/template.psd1
@@ -10,8 +10,6 @@
"--- FUNCTION ---"
)
PrivateData = @{
- PSData = @{
---- PS_DATA ---
- }
+ PSData = @{}
}
}
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/module/template.psm1 b/ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/module/template.psm1
index ac38fb5ed..3f76721d3 100644
--- a/ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/module/template.psm1
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/module/template.psm1
@@ -1,4 +1,17 @@
-Function --- FUNCTION --- {
+Function Get-Function {
+ <#
+ .SYNOPSIS
+ Help for Get-Function
+
+ .DESCRIPTION
+ Description for Get-Function
+
+ .EXAMPLE
+ Get-Function
+
+ .NOTES
+ Notes for Get-Function
+ #>
return [PSCustomObject]@{
Name = "--- NAME ---"
Version = "--- VERSION ---"
@@ -6,5 +19,5 @@ Function --- FUNCTION --- {
}
}
-Export-ModuleMember -Function --- FUNCTION ---
+Export-ModuleMember -Function Get-Function
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/setup_certs.sh b/ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/setup_certs.sh
index 258567316..fcae5f0e6 100644..100755
--- a/ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/setup_certs.sh
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/setup_certs.sh
@@ -16,4 +16,8 @@ openssl req -new -key sign.key -out sign.csr -subj "/CN=Ansible Sign" -config op
openssl x509 -req -in sign.csr -CA ca.pem -CAkey ca.key -CAcreateserial -out sign.pem -days 365 -extfile openssl.conf -extensions req_sign -passin pass:password
# Create pfx that includes signing cert and cert with the pass 'password'
-openssl pkcs12 -export -out sign.pfx -inkey sign.key -in sign.pem -passin pass:password -passout pass:password
+pfx_args=()
+if [ "${1}" == "-use-legacy" ]; then
+ pfx_args=("-certpbe" "PBE-SHA1-3DES" "-keypbe" "PBE-SHA1-3DES" "-macalg" "SHA1")
+fi
+openssl pkcs12 -export -out sign.pfx -inkey sign.key -in sign.pem -passin pass:password -passout pass:password "${pfx_args[@]}"
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/setup_modules.ps1 b/ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/setup_modules.ps1
index 48d55b574..b08aca8b2 100644
--- a/ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/setup_modules.ps1
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psmodule/files/setup_modules.ps1
@@ -28,8 +28,8 @@ $packages = @(
foreach ($package in $packages) {
$tmp_dir = Join-Path -Path $template_path -ChildPath $package.name
- if (Test-Path -Path $tmp_dir) {
- Remove-Item -Path $tmp_dir -Force -Recurse
+ if (Test-Path -LiteralPath $tmp_dir) {
+ Remove-Item -LiteralPath $tmp_dir -Force -Recurse
}
New-Item -Path $tmp_dir -ItemType Directory > $null
@@ -50,15 +50,15 @@ foreach ($package in $packages) {
$manifest = $manifest.Replace('--- NAME ---', $package.name).Replace('--- VERSION ---', $package.version)
$manifest = $manifest.Replace('--- GUID ---', [Guid]::NewGuid()).Replace('--- FUNCTION ---', $package.function)
- $manifest = $manifest.Replace('--- PS_DATA ---', $ps_data -join "`n")
+ $manifest = $manifest.Replace('PSData = @{}', "PSData = @{`n$($ps_data -join "`n")`n}")
$manifest_path = Join-Path -Path $tmp_dir -ChildPath "$($package.name).psd1"
- Set-Content -Path $manifest_path -Value $manifest
+ Set-Content -LiteralPath $manifest_path -Value $manifest
$script = [System.IO.File]::ReadAllText($template_script)
$script = $script.Replace('--- NAME ---', $package.name).Replace('--- VERSION ---', $package.version)
- $script = $script.Replace('--- REPO ---', $package.repo).Replace('--- FUNCTION ---', $package.function)
+ $script = $script.Replace('--- REPO ---', $package.repo).Replace('Get-Function', $package.function)
$script_path = Join-Path -Path $tmp_dir -ChildPath "$($package.name).psm1"
- Set-Content -Path $script_path -Value $script
+ Set-Content -LiteralPath $script_path -Value $script
$signed = if ($package.ContainsKey("signed")) { $package.signed } else { $true }
if ($signed) {
@@ -74,16 +74,16 @@ foreach ($package in $packages) {
$nuspec = $nuspec.Replace('--- NAME ---', $package.name).Replace('--- VERSION ---', $nuget_version)
$nuspec = $nuspec.Replace('--- FUNCTION ---', $package.function)
$nuspec = $nuspec.Replace('--- LICACC ---', ($package.require_license -as [bool]).ToString().ToLower())
- Set-Content -Path (Join-Path -Path $tmp_dir -ChildPath "$($package.name).nuspec") -Value $nuspec
+ Set-Content -LiteralPath (Join-Path -Path $tmp_dir -ChildPath "$($package.name).nuspec") -Value $nuspec
&$nuget_exe pack "$tmp_dir\$($package.name).nuspec" -outputdirectory $tmp_dir
$repo_path = Join-Path -Path $template_path -ChildPath $package.repo
$nupkg_filename = "$($package.name).$($nuget_version).nupkg"
- Copy-Item -Path (Join-Path -Path $tmp_dir -ChildPath $nupkg_filename) `
+ Copy-Item -LiteralPath (Join-Path -Path $tmp_dir -ChildPath $nupkg_filename) `
-Destination (Join-Path -Path $repo_path -ChildPath $nupkg_filename)
}
finally {
- Remove-Item -Path $tmp_dir -Force -Recurse
+ Remove-Item -LiteralPath $tmp_dir -Force -Recurse
}
}
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psmodule/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_psmodule/tasks/main.yml
index ffe1a0978..fe264cc0e 100644
--- a/ansible_collections/community/windows/tests/integration/targets/win_psmodule/tasks/main.yml
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psmodule/tasks/main.yml
@@ -6,25 +6,6 @@
- name: setup test repos and modules
import_tasks: setup.yml
-# Remove the below task in Ansible 2.12
-- name: ensure warning is fired when adding a repo
- win_psmodule:
- name: ansible-test1
- repository: some repo
- url: '{{ remote_tmp_dir }}'
- state: present
- register: dep_repo_add
- ignore_errors: yes # will fail because this repo doesn't actually have this module
- check_mode: yes
-
-- name: assert warning is fired when adding a repo
- assert:
- that:
- - dep_repo_add is changed
- - dep_repo_add.deprecations|length == 1
- - dep_repo_add.deprecations[0].msg == 'Adding a repo with this module is deprecated, the repository parameter should only be used to select a repo. Use community.windows.win_psrepository to manage repos'
- - dep_repo_add.deprecations[0].date == '2021-07-01'
-
### licensed module checks
# it is not known in check mode that a module requires
# license acceptance, so we don't do check mode tests
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_psmodule/tasks/setup.yml b/ansible_collections/community/windows/tests/integration/targets/win_psmodule/tasks/setup.yml
index 42049a3e3..14b591fcd 100644
--- a/ansible_collections/community/windows/tests/integration/targets/win_psmodule/tasks/setup.yml
+++ b/ansible_collections/community/windows/tests/integration/targets/win_psmodule/tasks/setup.yml
@@ -66,8 +66,16 @@
delegate_to: localhost
register: output_dir_abs
+- name: check if we can use the default AES encryption
+ ansible.windows.win_powershell:
+ script: |
+ $osVersion = [Version](Get-Item -LiteralPath "$env:SystemRoot\System32\kernel32.dll").VersionInfo.ProductVersion
+ $osVersion -ge [Version]"10.0.17763"
+ changed_when: false
+ register: aes256_support
+
- name: create certificates for code signing
- script: setup_certs.sh
+ script: setup_certs.sh {{ '' if aes256_support.output[0] else '-use-legacy' }}
args:
chdir: '{{ output_dir_abs.stdout }}'
delegate_to: localhost
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_regmerge/files/settings1c.reg b/ansible_collections/community/windows/tests/integration/targets/win_regmerge/files/settings1c.reg
new file mode 100644
index 000000000..26208be0c
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_regmerge/files/settings1c.reg
@@ -0,0 +1,4 @@
+Windows Registry Editor Version 5.00
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Cow Corp\Moosic\ILikeToMooveIt]
+"WorkingDirectory"="C:\\Program Files (x86)\\Cow Corp\\MadeUpFolder\\"
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_regmerge/files/settings3c.reg b/ansible_collections/community/windows/tests/integration/targets/win_regmerge/files/settings3c.reg
new file mode 100644
index 000000000..a3ae31ba2
--- /dev/null
+++ b/ansible_collections/community/windows/tests/integration/targets/win_regmerge/files/settings3c.reg
@@ -0,0 +1,30 @@
+Windows Registry Editor Version 5.00
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Cow Corp\Moo Monitor]
+"BIGCAT_HOME"="C:\\Bigcat97"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Cow Corp\Moo Monitor\Tasks]
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Cow Corp\Moo Monitor\Tasks\FishTank]
+"ComponentID"=dword:00000000
+"Name"="Bigcat7"
+"Version"=""
+"Archive"=""
+"InstallDate"=hex:00,00,00,00,00,00,00,00
+"Product"="FishTank"
+"IsBusStopOnly"=dword:00000000
+"MaxEggCount"=dword:00000005
+"MaxEggDuration"=dword:00000001
+"StopTimeout"=dword:00001388
+"IsService"=dword:00000001
+"IsDCOMService"=dword:00000000
+"Command"=""
+"NumberOfMoos"=dword:00000000
+"StatusOnShutdown"=hex:02,00,00,00
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Cow Corp\Moo Monitor\Tasks\FishTank\Counters]
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Cow Corp\Moo Monitor\Tasks\FishTank\Udders]
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Cow Corp\Moo Monitor\Tasks\FishTank\Hooves]
+
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_regmerge/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_regmerge/tasks/main.yml
index af640eb93..e3a171ed6 100644
--- a/ansible_collections/community/windows/tests/integration/targets/win_regmerge/tasks/main.yml
+++ b/ansible_collections/community/windows/tests/integration/targets/win_regmerge/tasks/main.yml
@@ -130,4 +130,103 @@
- settings2.reg
- settings3.reg
+# re-run all tests above using 'content' parameter instead of 'path' using similar reg files but without the BOM
+
+# clear the area of the registry we are using for tests
+- name: remove setting
+ ansible.windows.win_regedit:
+ key: 'HKLM:\SOFTWARE\Wow6432Node\Cow Corp'
+ state: absent
+
+# test 1 - basic test of changed behaviour
+# merge in REG_SZ
+- name: test 1 merge in a setting using 'content'
+ win_regmerge:
+ content: "{{ lookup('file', 'settings1c.reg') }}"
+ register: merge11_result
+
+- assert:
+ that:
+ - "merge11_result.changed == true"
+
+# re run the merge
+- name: test 1 merge in the setting again using 'content'
+ win_regmerge:
+ content: "{{ lookup('file', 'settings1c.reg') }}"
+ register: merge12_result
+
+# without a compare to key, should always report changed
+- assert:
+ that:
+ - "merge12_result.changed == true"
+# assert changed false
+
+# prune reg key
+- name: test 1 remove setting
+ ansible.windows.win_regedit:
+ key: 'HKLM:\SOFTWARE\Wow6432Node\Cow Corp'
+ state: absent
+
+#
+# test 2, observe behaviour when compare_to param is set
+#
+- name: test 2 merge in a setting using 'content'
+ win_regmerge:
+ content: "{{ lookup('file', 'settings1c.reg') }}"
+ compare_to: 'HKLM:\SOFTWARE\Wow6432Node\Cow Corp\Moosic\ILikeToMooveIt'
+ register: merge21_result
+
+- assert:
+ that:
+ - "merge21_result.changed == true"
+
+# re run the merge
+- name: test 2 merge in the setting again but with compare_key using 'content'
+ win_regmerge:
+ content: "{{ lookup('file', 'settings1c.reg') }}"
+ compare_to: 'HKLM:\SOFTWARE\Wow6432Node\Cow Corp\Moosic\ILikeToMooveIt'
+ register: merge22_result
+
+# with a compare to key, should now report not changed
+- assert:
+ that:
+ - "merge22_result.changed == false"
+# assert changed false
+
+# prune the contents of the registry from the parent of the compare key downwards
+- name: test 2 clean up remove setting
+ ansible.windows.win_regedit:
+ key: 'HKLM:\SOFTWARE\Wow6432Node\Cow Corp'
+ state: absent
+
+# test 3 merge in more complex settings
+- name: test 3 merge in a setting using 'content'
+ win_regmerge:
+ content: "{{ lookup('file', 'settings3c.reg') }}"
+ compare_to: 'HKLM:\SOFTWARE\Wow6432Node\Cow Corp\Moo Monitor'
+ register: merge31_result
+
+- assert:
+ that:
+ - "merge31_result.changed == true"
+
+# re run the merge
+- name: test 3 merge in the setting again but with compare_key check using 'content'
+ win_regmerge:
+ content: "{{ lookup('file', 'settings3c.reg') }}"
+ compare_to: 'HKLM:\SOFTWARE\Wow6432Node\Cow Corp\Moo Monitor'
+ register: merge32_result
+
+# with a compare to key, should now report not changed
+- assert:
+ that:
+ - "merge32_result.changed == false"
+# assert changed false
+
+# prune the contents of the registry from the compare key downwards
+- name: test 3 clean up remove setting
+ ansible.windows.win_regedit:
+ key: 'HKLM:\SOFTWARE\Wow6432Node\Cow Corp'
+ state: absent
+
# END OF win_regmerge tests
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_route/tasks/main.yml b/ansible_collections/community/windows/tests/integration/targets/win_route/tasks/main.yml
index 4bbdee5b5..5e5a01adc 100644
--- a/ansible_collections/community/windows/tests/integration/targets/win_route/tasks/main.yml
+++ b/ansible_collections/community/windows/tests/integration/targets/win_route/tasks/main.yml
@@ -22,8 +22,6 @@
ansible.windows.win_shell: '[Environment]::OSVersion.Version -ge [Version]"6.3"'
register: os
-- name: Perform with os Windows 2012R2 or newer
+- name: run all tasks
+ include_tasks: tests.yml
when: os.stdout_lines[0] == "True"
- block:
- - name: run all tasks
- include: tests.yml
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_scheduled_task/tasks/triggers.yml b/ansible_collections/community/windows/tests/integration/targets/win_scheduled_task/tasks/triggers.yml
index eae42c98a..5055e107a 100644
--- a/ansible_collections/community/windows/tests/integration/targets/win_scheduled_task/tasks/triggers.yml
+++ b/ansible_collections/community/windows/tests/integration/targets/win_scheduled_task/tasks/triggers.yml
@@ -305,8 +305,7 @@
triggers:
- type: registration
repetition:
- # TODO: change to dict in 2.12 as a list format is deprecated
- - interval: PT1M
+ interval: PT1M
duration: PT5M
stop_at_duration_end: yes
register: create_trigger_repetition_check
@@ -322,9 +321,6 @@
assert:
that:
- create_trigger_repetition_check is changed
- - create_trigger_repetition_check.deprecations|count == 1
- - create_trigger_repetition_check.deprecations[0].date == "2021-07-01"
- - create_trigger_repetition_check.deprecations[0].msg == "repetition is a list, should be defined as a dict"
- create_trigger_repetition_result_check.task_exists == True
- create_trigger_repetition_result_check.triggers|count == 1
- create_trigger_repetition_result_check.triggers[0].type == "TASK_TRIGGER_MONTHLYDOW"
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_scoop/aliases b/ansible_collections/community/windows/tests/integration/targets/win_scoop/aliases
index e2eacc2b6..3cf5b97e8 100644
--- a/ansible_collections/community/windows/tests/integration/targets/win_scoop/aliases
+++ b/ansible_collections/community/windows/tests/integration/targets/win_scoop/aliases
@@ -1,3 +1 @@
shippable/windows/group3
-skip/windows/2012 # Need pwsh 5+
-skip/windows/2012-R2 # Need pwsh 5+
diff --git a/ansible_collections/community/windows/tests/integration/targets/win_scoop_bucket/aliases b/ansible_collections/community/windows/tests/integration/targets/win_scoop_bucket/aliases
index 9a9d0737d..423ce3910 100644
--- a/ansible_collections/community/windows/tests/integration/targets/win_scoop_bucket/aliases
+++ b/ansible_collections/community/windows/tests/integration/targets/win_scoop_bucket/aliases
@@ -1,3 +1 @@
shippable/windows/group2
-skip/windows/2012 # Need pwsh 5+
-skip/windows/2012-R2 # Need pwsh 5+
diff --git a/ansible_collections/community/windows/tests/requirements.yml b/ansible_collections/community/windows/tests/requirements.yml
index 4f4960ebd..d3c5aea88 100644
--- a/ansible_collections/community/windows/tests/requirements.yml
+++ b/ansible_collections/community/windows/tests/requirements.yml
@@ -1,6 +1,6 @@
collections:
-- name: ansible.windows
-- name: chocolatey.chocolatey
- # Chocolatey 1.3.0 broke compatibiltiy wtih WinPS 3 and 4 so we are stuck with 1.2.0
- # https://github.com/chocolatey/chocolatey-ansible/issues/96
- version: <1.3.0 \ No newline at end of file
+ - name: ansible.windows
+ - name: chocolatey.chocolatey
+ # Chocolatey 1.3.0 broke compatibiltiy wtih WinPS 3 and 4 so we are stuck with 1.2.0
+ # https://github.com/chocolatey/chocolatey-ansible/issues/96
+ version: <1.3.0
diff --git a/ansible_collections/community/windows/tests/sanity/ignore-2.12.txt b/ansible_collections/community/windows/tests/sanity/ignore-2.12.txt
deleted file mode 100644
index 84d7bb121..000000000
--- a/ansible_collections/community/windows/tests/sanity/ignore-2.12.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-plugins/modules/win_audit_rule.ps1 pslint:PSCustomUseLiteralPath
-plugins/modules/win_rabbitmq_plugin.ps1 pslint:PSAvoidUsingInvokeExpression
-plugins/modules/win_region.ps1 pslint:PSAvoidUsingEmptyCatchBlock # Keep
-plugins/modules/win_regmerge.ps1 pslint:PSCustomUseLiteralPath
-plugins/modules/win_robocopy.ps1 pslint:PSCustomUseLiteralPath
-tests/integration/targets/win_audit_rule/library/test_get_audit_rule.ps1 pslint:PSCustomUseLiteralPath
-tests/integration/targets/win_lineinfile/files/expectations/23_utf8_bom.txt shebang
-tests/integration/targets/win_lineinfile/files/expectations/24_utf8_bom_line_added.txt shebang
-tests/integration/targets/win_lineinfile/files/expectations/30_linebreaks_checksum_bad.txt line-endings
-tests/integration/targets/win_psmodule/files/module/template.psd1 pslint!skip
-tests/integration/targets/win_psmodule/files/module/template.psm1 pslint!skip
-tests/integration/targets/win_psmodule/files/setup_modules.ps1 pslint:PSCustomUseLiteralPath
-tests/integration/targets/win_regmerge/templates/win_line_ending.j2 line-endings
diff --git a/ansible_collections/community/windows/tests/sanity/ignore-2.13.txt b/ansible_collections/community/windows/tests/sanity/ignore-2.13.txt
deleted file mode 100644
index 84d7bb121..000000000
--- a/ansible_collections/community/windows/tests/sanity/ignore-2.13.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-plugins/modules/win_audit_rule.ps1 pslint:PSCustomUseLiteralPath
-plugins/modules/win_rabbitmq_plugin.ps1 pslint:PSAvoidUsingInvokeExpression
-plugins/modules/win_region.ps1 pslint:PSAvoidUsingEmptyCatchBlock # Keep
-plugins/modules/win_regmerge.ps1 pslint:PSCustomUseLiteralPath
-plugins/modules/win_robocopy.ps1 pslint:PSCustomUseLiteralPath
-tests/integration/targets/win_audit_rule/library/test_get_audit_rule.ps1 pslint:PSCustomUseLiteralPath
-tests/integration/targets/win_lineinfile/files/expectations/23_utf8_bom.txt shebang
-tests/integration/targets/win_lineinfile/files/expectations/24_utf8_bom_line_added.txt shebang
-tests/integration/targets/win_lineinfile/files/expectations/30_linebreaks_checksum_bad.txt line-endings
-tests/integration/targets/win_psmodule/files/module/template.psd1 pslint!skip
-tests/integration/targets/win_psmodule/files/module/template.psm1 pslint!skip
-tests/integration/targets/win_psmodule/files/setup_modules.ps1 pslint:PSCustomUseLiteralPath
-tests/integration/targets/win_regmerge/templates/win_line_ending.j2 line-endings
diff --git a/ansible_collections/community/windows/tests/sanity/ignore-2.14.txt b/ansible_collections/community/windows/tests/sanity/ignore-2.14.txt
index 84d7bb121..82f6c2fac 100644
--- a/ansible_collections/community/windows/tests/sanity/ignore-2.14.txt
+++ b/ansible_collections/community/windows/tests/sanity/ignore-2.14.txt
@@ -1,13 +1,5 @@
-plugins/modules/win_audit_rule.ps1 pslint:PSCustomUseLiteralPath
-plugins/modules/win_rabbitmq_plugin.ps1 pslint:PSAvoidUsingInvokeExpression
-plugins/modules/win_region.ps1 pslint:PSAvoidUsingEmptyCatchBlock # Keep
-plugins/modules/win_regmerge.ps1 pslint:PSCustomUseLiteralPath
-plugins/modules/win_robocopy.ps1 pslint:PSCustomUseLiteralPath
-tests/integration/targets/win_audit_rule/library/test_get_audit_rule.ps1 pslint:PSCustomUseLiteralPath
+plugins/modules/win_audit_rule.ps1 pslint:PSCustomUseLiteralPath # Unsure if we can fix this or not so keep ignoring for now
tests/integration/targets/win_lineinfile/files/expectations/23_utf8_bom.txt shebang
tests/integration/targets/win_lineinfile/files/expectations/24_utf8_bom_line_added.txt shebang
tests/integration/targets/win_lineinfile/files/expectations/30_linebreaks_checksum_bad.txt line-endings
-tests/integration/targets/win_psmodule/files/module/template.psd1 pslint!skip
-tests/integration/targets/win_psmodule/files/module/template.psm1 pslint!skip
-tests/integration/targets/win_psmodule/files/setup_modules.ps1 pslint:PSCustomUseLiteralPath
tests/integration/targets/win_regmerge/templates/win_line_ending.j2 line-endings
diff --git a/ansible_collections/community/windows/tests/sanity/ignore-2.15.txt b/ansible_collections/community/windows/tests/sanity/ignore-2.15.txt
index 84d7bb121..82f6c2fac 100644
--- a/ansible_collections/community/windows/tests/sanity/ignore-2.15.txt
+++ b/ansible_collections/community/windows/tests/sanity/ignore-2.15.txt
@@ -1,13 +1,5 @@
-plugins/modules/win_audit_rule.ps1 pslint:PSCustomUseLiteralPath
-plugins/modules/win_rabbitmq_plugin.ps1 pslint:PSAvoidUsingInvokeExpression
-plugins/modules/win_region.ps1 pslint:PSAvoidUsingEmptyCatchBlock # Keep
-plugins/modules/win_regmerge.ps1 pslint:PSCustomUseLiteralPath
-plugins/modules/win_robocopy.ps1 pslint:PSCustomUseLiteralPath
-tests/integration/targets/win_audit_rule/library/test_get_audit_rule.ps1 pslint:PSCustomUseLiteralPath
+plugins/modules/win_audit_rule.ps1 pslint:PSCustomUseLiteralPath # Unsure if we can fix this or not so keep ignoring for now
tests/integration/targets/win_lineinfile/files/expectations/23_utf8_bom.txt shebang
tests/integration/targets/win_lineinfile/files/expectations/24_utf8_bom_line_added.txt shebang
tests/integration/targets/win_lineinfile/files/expectations/30_linebreaks_checksum_bad.txt line-endings
-tests/integration/targets/win_psmodule/files/module/template.psd1 pslint!skip
-tests/integration/targets/win_psmodule/files/module/template.psm1 pslint!skip
-tests/integration/targets/win_psmodule/files/setup_modules.ps1 pslint:PSCustomUseLiteralPath
tests/integration/targets/win_regmerge/templates/win_line_ending.j2 line-endings
diff --git a/ansible_collections/community/windows/tests/sanity/ignore-2.16.txt b/ansible_collections/community/windows/tests/sanity/ignore-2.16.txt
index 84d7bb121..82f6c2fac 100644
--- a/ansible_collections/community/windows/tests/sanity/ignore-2.16.txt
+++ b/ansible_collections/community/windows/tests/sanity/ignore-2.16.txt
@@ -1,13 +1,5 @@
-plugins/modules/win_audit_rule.ps1 pslint:PSCustomUseLiteralPath
-plugins/modules/win_rabbitmq_plugin.ps1 pslint:PSAvoidUsingInvokeExpression
-plugins/modules/win_region.ps1 pslint:PSAvoidUsingEmptyCatchBlock # Keep
-plugins/modules/win_regmerge.ps1 pslint:PSCustomUseLiteralPath
-plugins/modules/win_robocopy.ps1 pslint:PSCustomUseLiteralPath
-tests/integration/targets/win_audit_rule/library/test_get_audit_rule.ps1 pslint:PSCustomUseLiteralPath
+plugins/modules/win_audit_rule.ps1 pslint:PSCustomUseLiteralPath # Unsure if we can fix this or not so keep ignoring for now
tests/integration/targets/win_lineinfile/files/expectations/23_utf8_bom.txt shebang
tests/integration/targets/win_lineinfile/files/expectations/24_utf8_bom_line_added.txt shebang
tests/integration/targets/win_lineinfile/files/expectations/30_linebreaks_checksum_bad.txt line-endings
-tests/integration/targets/win_psmodule/files/module/template.psd1 pslint!skip
-tests/integration/targets/win_psmodule/files/module/template.psm1 pslint!skip
-tests/integration/targets/win_psmodule/files/setup_modules.ps1 pslint:PSCustomUseLiteralPath
tests/integration/targets/win_regmerge/templates/win_line_ending.j2 line-endings
diff --git a/ansible_collections/community/windows/tests/sanity/ignore-2.17.txt b/ansible_collections/community/windows/tests/sanity/ignore-2.17.txt
new file mode 100644
index 000000000..82f6c2fac
--- /dev/null
+++ b/ansible_collections/community/windows/tests/sanity/ignore-2.17.txt
@@ -0,0 +1,5 @@
+plugins/modules/win_audit_rule.ps1 pslint:PSCustomUseLiteralPath # Unsure if we can fix this or not so keep ignoring for now
+tests/integration/targets/win_lineinfile/files/expectations/23_utf8_bom.txt shebang
+tests/integration/targets/win_lineinfile/files/expectations/24_utf8_bom_line_added.txt shebang
+tests/integration/targets/win_lineinfile/files/expectations/30_linebreaks_checksum_bad.txt line-endings
+tests/integration/targets/win_regmerge/templates/win_line_ending.j2 line-endings
diff --git a/ansible_collections/community/windows/tests/unit/compat/__init__.py b/ansible_collections/community/windows/tests/unit/compat/__init__.py
deleted file mode 100644
index e69de29bb..000000000
--- a/ansible_collections/community/windows/tests/unit/compat/__init__.py
+++ /dev/null
diff --git a/ansible_collections/community/windows/tests/unit/compat/mock.py b/ansible_collections/community/windows/tests/unit/compat/mock.py
deleted file mode 100644
index 3dcd2687f..000000000
--- a/ansible_collections/community/windows/tests/unit/compat/mock.py
+++ /dev/null
@@ -1,42 +0,0 @@
-# (c) 2014, Toshio Kuratomi <tkuratomi@ansible.com>
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-'''
-Compat module for Python3.x's unittest.mock module
-'''
-
-# Python 2.7
-
-# Note: Could use the pypi mock library on python3.x as well as python2.x. It
-# is the same as the python3 stdlib mock library
-
-try:
- # Allow wildcard import because we really do want to import all of mock's
- # symbols into this compat shim
- # pylint: disable=wildcard-import,unused-wildcard-import
- from unittest.mock import *
-except ImportError:
- # Python 2
- # pylint: disable=wildcard-import,unused-wildcard-import
- try:
- from mock import *
- except ImportError:
- print('You need the mock library installed on python2.x to run tests')
diff --git a/ansible_collections/community/windows/tests/unit/mock/__init__.py b/ansible_collections/community/windows/tests/unit/mock/__init__.py
deleted file mode 100644
index e69de29bb..000000000
--- a/ansible_collections/community/windows/tests/unit/mock/__init__.py
+++ /dev/null
diff --git a/ansible_collections/community/windows/tests/unit/mock/loader.py b/ansible_collections/community/windows/tests/unit/mock/loader.py
deleted file mode 100644
index e5dff78c1..000000000
--- a/ansible_collections/community/windows/tests/unit/mock/loader.py
+++ /dev/null
@@ -1,116 +0,0 @@
-# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import os
-
-from ansible.errors import AnsibleParserError
-from ansible.parsing.dataloader import DataLoader
-from ansible.module_utils._text import to_bytes, to_text
-
-
-class DictDataLoader(DataLoader):
-
- def __init__(self, file_mapping=None):
- file_mapping = {} if file_mapping is None else file_mapping
- assert type(file_mapping) == dict
-
- super(DictDataLoader, self).__init__()
-
- self._file_mapping = file_mapping
- self._build_known_directories()
- self._vault_secrets = None
-
- def load_from_file(self, path, cache=True, unsafe=False):
- path = to_text(path)
- if path in self._file_mapping:
- return self.load(self._file_mapping[path], path)
- return None
-
- # TODO: the real _get_file_contents returns a bytestring, so we actually convert the
- # unicode/text it's created with to utf-8
- def _get_file_contents(self, file_name):
- path = to_text(file_name)
- if path in self._file_mapping:
- return (to_bytes(self._file_mapping[path]), False)
- else:
- raise AnsibleParserError("file not found: %s" % path)
-
- def path_exists(self, path):
- path = to_text(path)
- return path in self._file_mapping or path in self._known_directories
-
- def is_file(self, path):
- path = to_text(path)
- return path in self._file_mapping
-
- def is_directory(self, path):
- path = to_text(path)
- return path in self._known_directories
-
- def list_directory(self, path):
- ret = []
- path = to_text(path)
- for x in (list(self._file_mapping.keys()) + self._known_directories):
- if x.startswith(path):
- if os.path.dirname(x) == path:
- ret.append(os.path.basename(x))
- return ret
-
- def is_executable(self, path):
- # FIXME: figure out a way to make paths return true for this
- return False
-
- def _add_known_directory(self, directory):
- if directory not in self._known_directories:
- self._known_directories.append(directory)
-
- def _build_known_directories(self):
- self._known_directories = []
- for path in self._file_mapping:
- dirname = os.path.dirname(path)
- while dirname not in ('/', ''):
- self._add_known_directory(dirname)
- dirname = os.path.dirname(dirname)
-
- def push(self, path, content):
- rebuild_dirs = False
- if path not in self._file_mapping:
- rebuild_dirs = True
-
- self._file_mapping[path] = content
-
- if rebuild_dirs:
- self._build_known_directories()
-
- def pop(self, path):
- if path in self._file_mapping:
- del self._file_mapping[path]
- self._build_known_directories()
-
- def clear(self):
- self._file_mapping = dict()
- self._known_directories = []
-
- def get_basedir(self):
- return os.getcwd()
-
- def set_vault_secrets(self, vault_secrets):
- self._vault_secrets = vault_secrets
diff --git a/ansible_collections/community/windows/tests/unit/mock/path.py b/ansible_collections/community/windows/tests/unit/mock/path.py
deleted file mode 100644
index 54858b13d..000000000
--- a/ansible_collections/community/windows/tests/unit/mock/path.py
+++ /dev/null
@@ -1,8 +0,0 @@
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-from ansible_collections.ansible.windows.tests.unit.compat.mock import MagicMock
-from ansible.utils.path import unfrackpath
-
-
-mock_unfrackpath_noop = MagicMock(spec_set=unfrackpath, side_effect=lambda x, *args, **kwargs: x)
diff --git a/ansible_collections/community/windows/tests/unit/mock/procenv.py b/ansible_collections/community/windows/tests/unit/mock/procenv.py
deleted file mode 100644
index 3cb1b5b2f..000000000
--- a/ansible_collections/community/windows/tests/unit/mock/procenv.py
+++ /dev/null
@@ -1,90 +0,0 @@
-# (c) 2016, Matt Davis <mdavis@ansible.com>
-# (c) 2016, Toshio Kuratomi <tkuratomi@ansible.com>
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import sys
-import json
-
-from contextlib import contextmanager
-from io import BytesIO, StringIO
-from ansible_collections.community.windows.tests.unit.compat import unittest
-from ansible.module_utils.six import PY3
-from ansible.module_utils._text import to_bytes
-
-
-@contextmanager
-def swap_stdin_and_argv(stdin_data='', argv_data=tuple()):
- """
- context manager that temporarily masks the test runner's values for stdin and argv
- """
- real_stdin = sys.stdin
- real_argv = sys.argv
-
- if PY3:
- fake_stream = StringIO(stdin_data)
- fake_stream.buffer = BytesIO(to_bytes(stdin_data))
- else:
- fake_stream = BytesIO(to_bytes(stdin_data))
-
- try:
- sys.stdin = fake_stream
- sys.argv = argv_data
-
- yield
- finally:
- sys.stdin = real_stdin
- sys.argv = real_argv
-
-
-@contextmanager
-def swap_stdout():
- """
- context manager that temporarily replaces stdout for tests that need to verify output
- """
- old_stdout = sys.stdout
-
- if PY3:
- fake_stream = StringIO()
- else:
- fake_stream = BytesIO()
-
- try:
- sys.stdout = fake_stream
-
- yield fake_stream
- finally:
- sys.stdout = old_stdout
-
-
-class ModuleTestCase(unittest.TestCase):
- def setUp(self, module_args=None):
- if module_args is None:
- module_args = {'_ansible_remote_tmp': '/tmp', '_ansible_keep_remote_files': False}
-
- args = json.dumps(dict(ANSIBLE_MODULE_ARGS=module_args))
-
- # unittest doesn't have a clean place to use a context manager, so we have to enter/exit manually
- self.stdin_swap = swap_stdin_and_argv(stdin_data=args)
- self.stdin_swap.__enter__()
-
- def tearDown(self):
- # unittest doesn't have a clean place to use a context manager, so we have to enter/exit manually
- self.stdin_swap.__exit__(None, None, None)
diff --git a/ansible_collections/community/windows/tests/unit/mock/vault_helper.py b/ansible_collections/community/windows/tests/unit/mock/vault_helper.py
deleted file mode 100644
index dcce9c784..000000000
--- a/ansible_collections/community/windows/tests/unit/mock/vault_helper.py
+++ /dev/null
@@ -1,39 +0,0 @@
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-from ansible.module_utils._text import to_bytes
-
-from ansible.parsing.vault import VaultSecret
-
-
-class TextVaultSecret(VaultSecret):
- '''A secret piece of text. ie, a password. Tracks text encoding.
-
- The text encoding of the text may not be the default text encoding so
- we keep track of the encoding so we encode it to the same bytes.'''
-
- def __init__(self, text, encoding=None, errors=None, _bytes=None):
- super(TextVaultSecret, self).__init__()
- self.text = text
- self.encoding = encoding or 'utf-8'
- self._bytes = _bytes
- self.errors = errors or 'strict'
-
- @property
- def bytes(self):
- '''The text encoded with encoding, unless we specifically set _bytes.'''
- return self._bytes or to_bytes(self.text, encoding=self.encoding, errors=self.errors)
diff --git a/ansible_collections/community/windows/tests/unit/mock/yaml_helper.py b/ansible_collections/community/windows/tests/unit/mock/yaml_helper.py
deleted file mode 100644
index 1ef172159..000000000
--- a/ansible_collections/community/windows/tests/unit/mock/yaml_helper.py
+++ /dev/null
@@ -1,124 +0,0 @@
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import io
-import yaml
-
-from ansible.module_utils.six import PY3
-from ansible.parsing.yaml.loader import AnsibleLoader
-from ansible.parsing.yaml.dumper import AnsibleDumper
-
-
-class YamlTestUtils(object):
- """Mixin class to combine with a unittest.TestCase subclass."""
- def _loader(self, stream):
- """Vault related tests will want to override this.
-
- Vault cases should setup a AnsibleLoader that has the vault password."""
- return AnsibleLoader(stream)
-
- def _dump_stream(self, obj, stream, dumper=None):
- """Dump to a py2-unicode or py3-string stream."""
- if PY3:
- return yaml.dump(obj, stream, Dumper=dumper)
- else:
- return yaml.dump(obj, stream, Dumper=dumper, encoding=None)
-
- def _dump_string(self, obj, dumper=None):
- """Dump to a py2-unicode or py3-string"""
- if PY3:
- return yaml.dump(obj, Dumper=dumper)
- else:
- return yaml.dump(obj, Dumper=dumper, encoding=None)
-
- def _dump_load_cycle(self, obj):
- # Each pass though a dump or load revs the 'generation'
- # obj to yaml string
- string_from_object_dump = self._dump_string(obj, dumper=AnsibleDumper)
-
- # wrap a stream/file like StringIO around that yaml
- stream_from_object_dump = io.StringIO(string_from_object_dump)
- loader = self._loader(stream_from_object_dump)
- # load the yaml stream to create a new instance of the object (gen 2)
- obj_2 = loader.get_data()
-
- # dump the gen 2 objects directory to strings
- string_from_object_dump_2 = self._dump_string(obj_2,
- dumper=AnsibleDumper)
-
- # The gen 1 and gen 2 yaml strings
- self.assertEqual(string_from_object_dump, string_from_object_dump_2)
- # the gen 1 (orig) and gen 2 py object
- self.assertEqual(obj, obj_2)
-
- # again! gen 3... load strings into py objects
- stream_3 = io.StringIO(string_from_object_dump_2)
- loader_3 = self._loader(stream_3)
- obj_3 = loader_3.get_data()
-
- string_from_object_dump_3 = self._dump_string(obj_3, dumper=AnsibleDumper)
-
- self.assertEqual(obj, obj_3)
- # should be transitive, but...
- self.assertEqual(obj_2, obj_3)
- self.assertEqual(string_from_object_dump, string_from_object_dump_3)
-
- def _old_dump_load_cycle(self, obj):
- '''Dump the passed in object to yaml, load it back up, dump again, compare.'''
- stream = io.StringIO()
-
- yaml_string = self._dump_string(obj, dumper=AnsibleDumper)
- self._dump_stream(obj, stream, dumper=AnsibleDumper)
-
- yaml_string_from_stream = stream.getvalue()
-
- # reset stream
- stream.seek(0)
-
- loader = self._loader(stream)
- # loader = AnsibleLoader(stream, vault_password=self.vault_password)
- obj_from_stream = loader.get_data()
-
- stream_from_string = io.StringIO(yaml_string)
- loader2 = self._loader(stream_from_string)
- # loader2 = AnsibleLoader(stream_from_string, vault_password=self.vault_password)
- obj_from_string = loader2.get_data()
-
- stream_obj_from_stream = io.StringIO()
- stream_obj_from_string = io.StringIO()
-
- if PY3:
- yaml.dump(obj_from_stream, stream_obj_from_stream, Dumper=AnsibleDumper)
- yaml.dump(obj_from_stream, stream_obj_from_string, Dumper=AnsibleDumper)
- else:
- yaml.dump(obj_from_stream, stream_obj_from_stream, Dumper=AnsibleDumper, encoding=None)
- yaml.dump(obj_from_stream, stream_obj_from_string, Dumper=AnsibleDumper, encoding=None)
-
- yaml_string_stream_obj_from_stream = stream_obj_from_stream.getvalue()
- yaml_string_stream_obj_from_string = stream_obj_from_string.getvalue()
-
- stream_obj_from_stream.seek(0)
- stream_obj_from_string.seek(0)
-
- if PY3:
- yaml_string_obj_from_stream = yaml.dump(obj_from_stream, Dumper=AnsibleDumper)
- yaml_string_obj_from_string = yaml.dump(obj_from_string, Dumper=AnsibleDumper)
- else:
- yaml_string_obj_from_stream = yaml.dump(obj_from_stream, Dumper=AnsibleDumper, encoding=None)
- yaml_string_obj_from_string = yaml.dump(obj_from_string, Dumper=AnsibleDumper, encoding=None)
-
- assert yaml_string == yaml_string_obj_from_stream
- assert yaml_string == yaml_string_obj_from_stream == yaml_string_obj_from_string
- assert (yaml_string == yaml_string_obj_from_stream == yaml_string_obj_from_string == yaml_string_stream_obj_from_stream ==
- yaml_string_stream_obj_from_string)
- assert obj == obj_from_stream
- assert obj == obj_from_string
- assert obj == yaml_string_obj_from_stream
- assert obj == yaml_string_obj_from_string
- assert obj == obj_from_stream == obj_from_string == yaml_string_obj_from_stream == yaml_string_obj_from_string
- return {'obj': obj,
- 'yaml_string': yaml_string,
- 'yaml_string_from_stream': yaml_string_from_stream,
- 'obj_from_stream': obj_from_stream,
- 'obj_from_string': obj_from_string,
- 'yaml_string_obj_from_string': yaml_string_obj_from_string}
diff --git a/ansible_collections/community/windows/tests/unit/modules/__init__.py b/ansible_collections/community/windows/tests/unit/modules/__init__.py
deleted file mode 100644
index e69de29bb..000000000
--- a/ansible_collections/community/windows/tests/unit/modules/__init__.py
+++ /dev/null
diff --git a/ansible_collections/community/windows/tests/unit/modules/utils.py b/ansible_collections/community/windows/tests/unit/modules/utils.py
deleted file mode 100644
index bc627df64..000000000
--- a/ansible_collections/community/windows/tests/unit/modules/utils.py
+++ /dev/null
@@ -1,50 +0,0 @@
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import json
-
-from ansible_collections.community.windows.tests.unit.compat import unittest
-from ansible_collections.community.windows.tests.unit.compat.mock import patch
-from ansible.module_utils import basic
-from ansible.module_utils._text import to_bytes
-
-
-def set_module_args(args):
- if '_ansible_remote_tmp' not in args:
- args['_ansible_remote_tmp'] = '/tmp'
- if '_ansible_keep_remote_files' not in args:
- args['_ansible_keep_remote_files'] = False
-
- args = json.dumps({'ANSIBLE_MODULE_ARGS': args})
- basic._ANSIBLE_ARGS = to_bytes(args)
-
-
-class AnsibleExitJson(Exception):
- pass
-
-
-class AnsibleFailJson(Exception):
- pass
-
-
-def exit_json(*args, **kwargs):
- if 'changed' not in kwargs:
- kwargs['changed'] = False
- raise AnsibleExitJson(kwargs)
-
-
-def fail_json(*args, **kwargs):
- kwargs['failed'] = True
- raise AnsibleFailJson(kwargs)
-
-
-class ModuleTestCase(unittest.TestCase):
-
- def setUp(self):
- self.mock_module = patch.multiple(basic.AnsibleModule, exit_json=exit_json, fail_json=fail_json)
- self.mock_module.start()
- self.mock_sleep = patch('time.sleep')
- self.mock_sleep.start()
- set_module_args({})
- self.addCleanup(self.mock_module.stop)
- self.addCleanup(self.mock_sleep.stop)
diff --git a/ansible_collections/community/windows/tests/unit/plugins/lookup/fixtures/avi.json b/ansible_collections/community/windows/tests/unit/plugins/lookup/fixtures/avi.json
deleted file mode 100644
index ae89ca689..000000000
--- a/ansible_collections/community/windows/tests/unit/plugins/lookup/fixtures/avi.json
+++ /dev/null
@@ -1,104 +0,0 @@
-{
- "mock_single_obj": {
- "_last_modified": "",
- "cloud_ref": "https://192.0.2.132/api/cloud/cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
- "dhcp_enabled": true,
- "exclude_discovered_subnets": false,
- "name": "PG-123",
- "synced_from_se": true,
- "tenant_ref": "https://192.0.2.132/api/tenant/admin",
- "url": "https://192.0.2.132/api/network/dvportgroup-2084-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
- "uuid": "dvportgroup-2084-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
- "vcenter_dvs": true,
- "vimgrnw_ref": "https://192.0.2.132/api/vimgrnwruntime/dvportgroup-2084-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
- "vrf_context_ref": "https://192.0.2.132/api/vrfcontext/vrfcontext-31f1b55f-319c-44eb-862f-69d79ffdf295"
- },
- "mock_multiple_obj": {
- "results": [
- {
- "_last_modified": "",
- "cloud_ref": "https://192.0.2.132/api/cloud/cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
- "dhcp_enabled": true,
- "exclude_discovered_subnets": false,
- "name": "J-PG-0682",
- "synced_from_se": true,
- "tenant_ref": "https://192.0.2.132/api/tenant/admin",
- "url": "https://192.0.2.132/api/network/dvportgroup-2084-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
- "uuid": "dvportgroup-2084-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
- "vcenter_dvs": true,
- "vimgrnw_ref": "https://192.0.2.132/api/vimgrnwruntime/dvportgroup-2084-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
- "vrf_context_ref": "https://192.0.2.132/api/vrfcontext/vrfcontext-31f1b55f-319c-44eb-862f-69d79ffdf295"
- },
- {
- "_last_modified": "",
- "cloud_ref": "https://192.0.2.132/api/cloud/cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
- "dhcp_enabled": true,
- "exclude_discovered_subnets": false,
- "name": "J-PG-0231",
- "synced_from_se": true,
- "tenant_ref": "https://192.0.2.132/api/tenant/admin",
- "url": "https://192.0.2.132/api/network/dvportgroup-1627-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
- "uuid": "dvportgroup-1627-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
- "vcenter_dvs": true,
- "vimgrnw_ref": "https://192.0.2.132/api/vimgrnwruntime/dvportgroup-1627-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
- "vrf_context_ref": "https://192.0.2.132/api/vrfcontext/vrfcontext-31f1b55f-319c-44eb-862f-69d79ffdf295"
- },
- {
- "_last_modified": "",
- "cloud_ref": "https://192.0.2.132/api/cloud/cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
- "dhcp_enabled": true,
- "exclude_discovered_subnets": false,
- "name": "J-PG-0535",
- "synced_from_se": true,
- "tenant_ref": "https://192.0.2.132/api/tenant/admin",
- "url": "https://192.0.2.132/api/network/dvportgroup-1934-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
- "uuid": "dvportgroup-1934-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
- "vcenter_dvs": true,
- "vimgrnw_ref": "https://192.0.2.132/api/vimgrnwruntime/dvportgroup-1934-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
- "vrf_context_ref": "https://192.0.2.132/api/vrfcontext/vrfcontext-31f1b55f-319c-44eb-862f-69d79ffdf295"
- },
- {
- "_last_modified": "",
- "cloud_ref": "https://192.0.2.132/api/cloud/cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
- "dhcp_enabled": true,
- "exclude_discovered_subnets": false,
- "name": "J-PG-0094",
- "synced_from_se": true,
- "tenant_ref": "https://192.0.2.132/api/tenant/admin",
- "url": "https://192.0.2.132/api/network/dvportgroup-1458-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
- "uuid": "dvportgroup-1458-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
- "vcenter_dvs": true,
- "vimgrnw_ref": "https://192.0.2.132/api/vimgrnwruntime/dvportgroup-1458-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
- "vrf_context_ref": "https://192.0.2.132/api/vrfcontext/vrfcontext-31f1b55f-319c-44eb-862f-69d79ffdf295"
- },
- {
- "_last_modified": "",
- "cloud_ref": "https://192.0.2.132/api/cloud/cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
- "dhcp_enabled": true,
- "exclude_discovered_subnets": false,
- "name": "J-PG-0437",
- "synced_from_se": true,
- "tenant_ref": "https://192.0.2.132/api/tenant/admin",
- "url": "https://192.0.2.132/api/network/dvportgroup-1836-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
- "uuid": "dvportgroup-1836-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
- "vcenter_dvs": true,
- "vimgrnw_ref": "https://192.0.2.132/api/vimgrnwruntime/dvportgroup-1836-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
- "vrf_context_ref": "https://192.0.2.132/api/vrfcontext/vrfcontext-31f1b55f-319c-44eb-862f-69d79ffdf295"
- },
- {
- "_last_modified": "",
- "cloud_ref": "https://192.0.2.132/api/cloud/cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
- "dhcp_enabled": true,
- "exclude_discovered_subnets": false,
- "name": "J-PG-0673",
- "synced_from_se": true,
- "tenant_ref": "https://192.0.2.132/api/tenant/admin",
- "url": "https://192.0.2.132/api/network/dvportgroup-2075-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
- "uuid": "dvportgroup-2075-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
- "vcenter_dvs": true,
- "vimgrnw_ref": "https://192.0.2.132/api/vimgrnwruntime/dvportgroup-2075-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
- "vrf_context_ref": "https://192.0.2.132/api/vrfcontext/vrfcontext-31f1b55f-319c-44eb-862f-69d79ffdf295"
- }
- ]
- }
-}
diff --git a/ansible_collections/community/windows/tests/unit/plugins/lookup/test_laps_password.py b/ansible_collections/community/windows/tests/unit/plugins/lookup/test_laps_password.py
index 29e2b938a..d15fc109f 100644
--- a/ansible_collections/community/windows/tests/unit/plugins/lookup/test_laps_password.py
+++ b/ansible_collections/community/windows/tests/unit/plugins/lookup/test_laps_password.py
@@ -10,8 +10,8 @@ import os
import platform
import pytest
import sys
+from unittest.mock import MagicMock
-from ansible_collections.community.windows.tests.unit.compat.mock import MagicMock
from ansible.errors import AnsibleLookupError
from ansible.plugins.loader import lookup_loader
diff --git a/ansible_collections/community/windows/tests/utils/shippable/lint.sh b/ansible_collections/community/windows/tests/utils/shippable/lint.sh
new file mode 100755
index 000000000..12b5b4cd2
--- /dev/null
+++ b/ansible_collections/community/windows/tests/utils/shippable/lint.sh
@@ -0,0 +1,10 @@
+#!/usr/bin/env bash
+
+set -o pipefail -eux
+
+# This is aligned with the galaxy-importer used by AH
+# https://github.com/ansible/galaxy-importer/blob/d4b5e6d12088ba452f129f4824bd049be5543358/setup.cfg#L22C4-L22C33
+python -m pip install \
+ 'ansible-lint>=6.2.2,<=6.14.3'
+
+ansible-lint
diff --git a/ansible_collections/community/zabbix/.github/workflows/agent.yml b/ansible_collections/community/zabbix/.github/workflows/agent.yml
index 86e377eaf..ca04f5843 100644
--- a/ansible_collections/community/zabbix/.github/workflows/agent.yml
+++ b/ansible_collections/community/zabbix/.github/workflows/agent.yml
@@ -15,46 +15,38 @@ on:
- ".github/workflows/agent.yml"
jobs:
molecule:
- runs-on: ubuntu-18.04
+ runs-on: ubuntu-20.04
strategy:
fail-fast: false
matrix:
- molecule_distro:
- - container: centos8
- image: geerlingguy/docker-rockylinux8-ansible:latest
- - container: centos7
- image: geerlingguy/docker-centos7-ansible:latest
- - container: fedora32
- image: geerlingguy/docker-fedora32-ansible:latest
- - container: ubuntu2004
- image: geerlingguy/docker-ubuntu2004-ansible
- - container: pgsql-ubuntu1804
- image: geerlingguy/docker-ubuntu1804-ansible
- - container: debian11
- image: geerlingguy/docker-debian11-ansible
- - container: debian10
- image: geerlingguy/docker-debian10-ansible
- - container: debian9
- image: geerlingguy/docker-debian9-ansible
+ container:
+ - rockylinux9
+ - rockylinux8
+ - ubuntu2204
+ - ubuntu2004
+ - ubuntu1804
+ - debian12
+ - debian11
+ - debian10
+ version:
+ - v64
+ - v62
+ - v60
scenario_name:
- default
- autopsk
- agent2
- agent2autopsk
- exclude: # zabbix-agent2 is not supported on debian8
- - molecule_distro:
- container: debian8
- scenario_name: agent2
- - molecule_distro:
- container: debian8
- scenario_name: agent2autopsk
+ exclude:
+ - container: debian12
+ version: v62
steps:
- name: Check out code
- uses: actions/checkout@v1
+ uses: actions/checkout@v4
- name: Set up Python 3.9
- uses: actions/setup-python@v1
+ uses: actions/setup-python@v4
with:
python-version: 3.9
@@ -77,7 +69,8 @@ jobs:
- name: Run role tests
working-directory: molecule/zabbix_agent_tests
run: >-
- MY_MOLECULE_CONTAINER=${{ matrix.molecule_distro.container }}
- MY_MOLECULE_IMAGE=${{ matrix.molecule_distro.image }}
- MY_MOLECULE_DOCKER_COMMAND=${{ matrix.molecule_distro.command }}
- molecule -c common/molecule.yml test -s ${{ matrix.scenario_name }}
+ MY_MOLECULE_CONTAINER=${{ matrix.container }}
+ MY_MOLECULE_IMAGE=${{ matrix.container }}
+ MY_MOLECULE_VERSION=${{ matrix.version }}
+ MY_MOLECULE_DOCKER_COMMAND=${{ matrix.command }}
+ molecule -c common/molecule.yml test -s ${{ matrix.scenario_name }} \ No newline at end of file
diff --git a/ansible_collections/community/zabbix/.github/workflows/javagateway.yml b/ansible_collections/community/zabbix/.github/workflows/javagateway.yml
index 2c84dcf1f..bd6885ef7 100644
--- a/ansible_collections/community/zabbix/.github/workflows/javagateway.yml
+++ b/ansible_collections/community/zabbix/.github/workflows/javagateway.yml
@@ -3,37 +3,51 @@ name: "community.zabbix.zabbix_javagateway"
on:
push:
paths:
- - 'roles/zabbix_javagateway/**'
- - 'molecule/zabbix_javagateway/**'
- - 'molecule/requirements.txt'
- - '.github/workflows/javagateway.yml'
+ - "roles/zabbix_javagateway/**"
+ - "molecule/zabbix_javagateway/**"
+ - "molecule/requirements.txt"
+ - ".github/workflows/javagateway.yml"
pull_request:
paths:
- - 'roles/zabbix_javagateway/**'
- - 'molecule/zabbix_javagateway/**'
- - 'molecule/requirements.txt'
- - '.github/workflows/javagateway.yml'
+ - "roles/zabbix_javagateway/**"
+ - "molecule/zabbix_javagateway/**"
+ - "molecule/requirements.txt"
+ - ".github/workflows/javagateway.yml"
jobs:
molecule:
- runs-on: ubuntu-18.04
+ runs-on: ubuntu-20.04
strategy:
fail-fast: false
matrix:
- molecule_distro:
- - container: centos
- image: geerlingguy/docker-centos8-ansible:latest
- - container: ubuntu
- image: geerlingguy/docker-ubuntu2004-ansible
- - container: debian
- image: geerlingguy/docker-debian10-ansible
+ container:
+ - rockylinux9
+ - rockylinux8
+ - centos7
+ - ubuntu2204
+ - ubuntu2004
+ - ubuntu1804
+ - debian12
+ - debian11
+ - debian10
+ version:
+ - v64
+ - v62
+ - v60
+ include:
+ - interpreter: python3
+ - interpreter: python
+ container: centos7
+ exclude:
+ - container: debian12
+ version: v62
collection_role:
- zabbix_javagateway
steps:
- name: Check out code
- uses: actions/checkout@v1
+ uses: actions/checkout@v4
- name: Set up Python 3.9
- uses: actions/setup-python@v1
+ uses: actions/setup-python@v4
with:
python-version: 3.9
@@ -50,10 +64,11 @@ jobs:
- name: Install the collection
run: ansible-galaxy collection install $COLLECTION_FILE
- - name: Run role tests
+ - name: Run server role tests
run: >-
- MY_MOLECULE_CONTAINER=${{ matrix.molecule_distro.container }}
- MY_MOLECULE_IMAGE=${{ matrix.molecule_distro.image }}
- MY_MOLECULE_GROUP=${{ matrix.molecule_distro.group }}
- MY_MOLECULE_DOCKER_COMMAND=${{ matrix.molecule_distro.command }}
+ MY_MOLECULE_CONTAINER=${{ matrix.container }}
+ MY_MOLECULE_IMAGE=${{ matrix.container }}
+ MY_MOLECULE_VERSION=${{ matrix.version }}
+ MY_MOLECULE_DOCKER_COMMAND=${{ matrix.command }}
+ MY_MOLECULE_INTERPRETER=${{ matrix.interpreter }}
molecule test -s ${{ matrix.collection_role }}
diff --git a/ansible_collections/community/zabbix/.github/workflows/plugins-integration.yml b/ansible_collections/community/zabbix/.github/workflows/plugins-integration.yml
index 4e4dd0a30..f23071a1b 100644
--- a/ansible_collections/community/zabbix/.github/workflows/plugins-integration.yml
+++ b/ansible_collections/community/zabbix/.github/workflows/plugins-integration.yml
@@ -20,9 +20,6 @@ jobs:
fail-fast: false
matrix:
zabbix_container:
- - version: "4.0"
- - version: "5.0"
- # - version: "5.4" # only activate after basic compatibility
- version: "6.0"
- version: "6.2"
- version: "6.4"
@@ -31,37 +28,37 @@ jobs:
- stable-2.12
- stable-2.13
- stable-2.14
+ - stable-2.15
+ - stable-2.16
- devel
python:
- - 3.9
+ - '3.10'
steps:
- name: Check out code
- uses: actions/checkout@v2
+ uses: actions/checkout@v4
with:
path: ansible_collections/community/zabbix
- name: Set up Python ${{ matrix.python }}
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python }}
- name: Install ansible-base (${{ matrix.ansible }})
run: pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz --disable-pip-version-check
- - name: Install dependencies
- run: pip install docker-compose zabbix-api
-
- name: Install ansible.netcommon collection
- run: ansible-galaxy collection install ansible.netcommon -p /home/runner/work/community.zabbix/community.zabbix
+ run: ansible-galaxy collection install ansible.netcommon -p $GITHUB_WORKSPACE
working-directory: ./ansible_collections/community/zabbix
# For Zabbix integration tests we need to test against different versions of
# the Zabbix server. To do this we spin up a Docker container using the `matrix`
# of version and ports specified earlier.
- name: Zabbix container server provisioning
- run: docker-compose up -d
- working-directory: ./ansible_collections/community/zabbix
+ uses: isbang/compose-action@v1.5.0
+ with:
+ compose-file: "./ansible_collections/community/zabbix/docker-compose.yml"
env:
zabbix_version: ${{ matrix.zabbix_container.version }}
@@ -78,6 +75,6 @@ jobs:
working-directory: ./ansible_collections/community/zabbix
# See the repots at https://codecov.io/gh/ansible-collections/community.zabbix
- - uses: codecov/codecov-action@v1
+ - uses: codecov/codecov-action@v3
with:
fail_ci_if_error: false
diff --git a/ansible_collections/community/zabbix/.github/workflows/proxy.yml b/ansible_collections/community/zabbix/.github/workflows/proxy.yml
index c13634afc..985bb8ceb 100644
--- a/ansible_collections/community/zabbix/.github/workflows/proxy.yml
+++ b/ansible_collections/community/zabbix/.github/workflows/proxy.yml
@@ -15,48 +15,43 @@ on:
- ".github/workflows/proxy.yml"
jobs:
molecule:
- runs-on: ubuntu-18.04
+ runs-on: ubuntu-20.04
strategy:
fail-fast: false
matrix:
- molecule_distro:
- - container: mysql-centos
- image: geerlingguy/docker-rockylinux8-ansible:latest
- group: mysql
- - container: pgsql-centos
- image: geerlingguy/docker-rockylinux8-ansible:latest
- group: postgresql
- - container: sqlite-centos
- image: geerlingguy/docker-rockylinux8-ansible:latest
- group: sqlite3
- - container: mysql-ubuntu
- image: geerlingguy/docker-ubuntu2004-ansible
- group: mysql
- - container: pgsql-ubuntu
- image: geerlingguy/docker-ubuntu2004-ansible
- group: postgresql
- command: /sbin/init
- - container: sqlite-ubuntu
- image: geerlingguy/docker-ubuntu2004-ansible
- group: sqlite3
- command: /sbin/init
- - container: mysql-debian
- image: geerlingguy/docker-debian11-ansible
- group: mysql
- - container: pgsql-debian
- image: geerlingguy/docker-debian11-ansible
- group: postgresql
- - container: sqlite-debian
- image: geerlingguy/docker-debian11-ansible
- group: sqlite3
+ container:
+ - rockylinux9
+ - rockylinux8
+ - centos7
+ - ubuntu2204
+ - ubuntu2004
+ - ubuntu1804
+ - debian12
+ - debian11
+ - debian10
collection_role:
- zabbix_proxy
+ database:
+ - mysql
+ - pgsql
+ - sqlite3
+ version:
+ - v64
+ - v62
+ - v60
+ include:
+ - interpreter: python3
+ - interpreter: python
+ container: centos7
+ exclude:
+ - container: debian12
+ version: v62
steps:
- name: Check out code
- uses: actions/checkout@v1
+ uses: actions/checkout@v4
- name: Set up Python 3.9
- uses: actions/setup-python@v1
+ uses: actions/setup-python@v4
with:
python-version: 3.9
@@ -75,8 +70,10 @@ jobs:
- name: Run role tests
run: >-
- MY_MOLECULE_CONTAINER=${{ matrix.molecule_distro.container }}
- MY_MOLECULE_IMAGE=${{ matrix.molecule_distro.image }}
- MY_MOLECULE_GROUP=${{ matrix.molecule_distro.group }}
- MY_MOLECULE_DOCKER_COMMAND=${{ matrix.molecule_distro.command }}
+ MY_MOLECULE_CONTAINER=${{ matrix.container }}
+ MY_MOLECULE_IMAGE=${{ matrix.container }}
+ MY_MOLECULE_VERSION=${{ matrix.version }}
+ MY_MOLECULE_DATABASE=${{ matrix.database }}
+ MY_MOLECULE_INTERPRETER=${{ matrix.interpreter }}
+ MY_MOLECULE_DOCKER_COMMAND=${{ matrix.command }}
molecule test -s ${{ matrix.collection_role }}
diff --git a/ansible_collections/community/zabbix/.github/workflows/repo-sanity.yml b/ansible_collections/community/zabbix/.github/workflows/repo-sanity.yml
index 98954a82f..499d2f1ae 100644
--- a/ansible_collections/community/zabbix/.github/workflows/repo-sanity.yml
+++ b/ansible_collections/community/zabbix/.github/workflows/repo-sanity.yml
@@ -10,16 +10,16 @@ jobs:
strategy:
matrix:
python:
- - 3.9
+ - '3.10'
runs-on: ubuntu-latest
steps:
- name: Check out code
- uses: actions/checkout@v2
+ uses: actions/checkout@v4
with:
path: ansible_collections/community/zabbix
- name: Set up Python ${{ matrix.python }}
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python }}
@@ -29,7 +29,6 @@ jobs:
- name: Run lint test for py3
run: tox -elinters-py3 -vv
working-directory: ./ansible_collections/community/zabbix
- if: matrix.python != '2.7'
sanity:
name: Sanity (Ⓐ${{ matrix.ansible }}+py${{ matrix.python }})
@@ -43,21 +42,23 @@ jobs:
- stable-2.12
- stable-2.13
- stable-2.14
+ - stable-2.15
+ - stable-2.16
- devel
python:
- - 3.9
+ - '3.10'
runs-on: ubuntu-latest
steps:
# ansible-test requires the collection to be in a directory in the form
# .../ansible_collections/NAMESPACE/COLLECTION_NAME/
- name: Check out code
- uses: actions/checkout@v2
+ uses: actions/checkout@v4
with:
path: ansible_collections/community/zabbix
- name: Set up Python ${{ matrix.ansible }}
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python }}
diff --git a/ansible_collections/community/zabbix/.github/workflows/server.yml b/ansible_collections/community/zabbix/.github/workflows/server.yml
index 8a8930e02..b169aa9f1 100644
--- a/ansible_collections/community/zabbix/.github/workflows/server.yml
+++ b/ansible_collections/community/zabbix/.github/workflows/server.yml
@@ -15,38 +15,47 @@ on:
- ".github/workflows/server.yml"
jobs:
molecule:
- runs-on: ubuntu-18.04
+ runs-on: ubuntu-20.04
strategy:
fail-fast: false
matrix:
- molecule_distro:
- - container: mysql-centos
- image: geerlingguy/docker-rockylinux8-ansible:latest
- group: mysql
- - container: pgsql-centos
- image: geerlingguy/docker-rockylinux8-ansible:latest
- group: postgresql
- - container: mysql-ubuntu
- image: geerlingguy/docker-ubuntu2004-ansible
- group: mysql
- - container: pgsql-ubuntu
- image: geerlingguy/docker-ubuntu2004-ansible
- group: postgresql
- command: /sbin/init
- - container: mysql-debian
- image: geerlingguy/docker-debian11-ansible
- group: mysql
- - container: pgsql-debian
- image: geerlingguy/docker-debian11-ansible
- group: postgresql
+ container:
+ - rockylinux9
+ - rockylinux8
+ - ubuntu2204
+ - ubuntu2004
+ - ubuntu1804
+ - debian12
+ - debian11
+ - debian10
collection_role:
- zabbix_server
+ database:
+ - mysql
+ - pgsql
+ version:
+ - v64
+ - v62
+ - v60
+ include:
+ - interpreter: python3
+ exclude:
+ - container: debian12
+ version: v62
+ - container: debian10
+ version: v62
+ - container: ubuntu1804
+ version: v62
+ - container: ubuntu1804
+ version: v64
+ - container: debian10
+ version: v64
steps:
- name: Check out code
- uses: actions/checkout@v1
+ uses: actions/checkout@v4
- name: Set up Python 3.9
- uses: actions/setup-python@v1
+ uses: actions/setup-python@v4
with:
python-version: 3.9
@@ -63,10 +72,12 @@ jobs:
- name: Install the collection
run: ansible-galaxy collection install $COLLECTION_FILE
- - name: Run role tests
+ - name: Run server role tests
run: >-
- MY_MOLECULE_CONTAINER=${{ matrix.molecule_distro.container }}
- MY_MOLECULE_IMAGE=${{ matrix.molecule_distro.image }}
- MY_MOLECULE_GROUP=${{ matrix.molecule_distro.group }}
- MY_MOLECULE_DOCKER_COMMAND=${{ matrix.molecule_distro.command }}
+ MY_MOLECULE_CONTAINER=${{ matrix.container }}
+ MY_MOLECULE_IMAGE=${{ matrix.container }}
+ MY_MOLECULE_VERSION=${{ matrix.version }}
+ MY_MOLECULE_DATABASE=${{ matrix.database }}
+ MY_MOLECULE_INTERPRETER=${{ matrix.interpreter }}
+ MY_MOLECULE_DOCKER_COMMAND=${{ matrix.command }}
molecule test -s ${{ matrix.collection_role }}
diff --git a/ansible_collections/community/zabbix/.github/workflows/web.yml b/ansible_collections/community/zabbix/.github/workflows/web.yml
index 81c506082..79b7beb11 100644
--- a/ansible_collections/community/zabbix/.github/workflows/web.yml
+++ b/ansible_collections/community/zabbix/.github/workflows/web.yml
@@ -15,37 +15,49 @@ on:
- ".github/workflows/web.yml"
jobs:
molecule:
- runs-on: ubuntu-18.04
+ runs-on: ubuntu-20.04
strategy:
fail-fast: false
matrix:
- molecule_distro:
- - container: mysql-centos8
- image: geerlingguy/docker-rockylinux8-ansible:latest
- group: mysql
- - container: pgsql-centos8
- image: geerlingguy/docker-rockylinux8-ansible:latest
- group: postgresql
- - container: mysql-ubuntu18
- image: geerlingguy/docker-ubuntu1804-ansible
- group: mysql
- - container: pgsql-ubuntu20
- image: geerlingguy/docker-ubuntu2004-ansible
- group: postgresql
- - container: mysql-debian
- image: geerlingguy/docker-debian11-ansible
- group: mysql
- - container: pgsql-debian
- image: geerlingguy/docker-debian11-ansible
- group: postgresql
+ container:
+ - rockylinux9
+ - rockylinux8
+ - ubuntu2204
+ - ubuntu2004
+ - ubuntu1804
+ - debian12
+ - debian11
+ - debian10
collection_role:
- zabbix_web
+ database:
+ - mysql
+ - pgsql
+ web_server:
+ - nginx
+ version:
+ - v64
+ - v62
+ - v60
+ include:
+ - interpreter: python3
+ exclude:
+ - container: debian10
+ version: v62
+ - container: ubuntu1804
+ version: v62
+ - container: debian10
+ version: v64
+ - container: ubuntu1804
+ version: v64
+ - container: debian12
+ version: v62
steps:
- name: Check out code
- uses: actions/checkout@v1
+ uses: actions/checkout@v4
- name: Set up Python 3.9
- uses: actions/setup-python@v1
+ uses: actions/setup-python@v4
with:
python-version: 3.9
@@ -64,8 +76,11 @@ jobs:
- name: Run role tests
run: >-
- MY_MOLECULE_CONTAINER=${{ matrix.molecule_distro.container }}
- MY_MOLECULE_IMAGE=${{ matrix.molecule_distro.image }}
- MY_MOLECULE_GROUP=${{ matrix.molecule_distro.group }}
- MY_MOLECULE_DOCKER_COMMAND=${{ matrix.molecule_distro.command }}
+ MY_MOLECULE_CONTAINER=${{ matrix.container }}
+ MY_MOLECULE_IMAGE=${{ matrix.container }}
+ MY_MOLECULE_VERSION=${{ matrix.version }}
+ MY_MOLECULE_DATABASE=${{ matrix.database }}
+ MY_MOLECULE_WEB_SERVER=${{ matrix.web_server }}
+ MY_MOLECULE_INTERPRETER=${{ matrix.interpreter }}
+ MY_MOLECULE_DOCKER_COMMAND=${{ matrix.command }}
molecule test -s ${{ matrix.collection_role }}
diff --git a/ansible_collections/community/zabbix/.gitignore b/ansible_collections/community/zabbix/.gitignore
index a27e8241a..43399c126 100644
--- a/ansible_collections/community/zabbix/.gitignore
+++ b/ansible_collections/community/zabbix/.gitignore
@@ -20,3 +20,4 @@ venv.bak/
# ignore dev stuff
.devcontainer
local_play.yml
+antsibull-env
diff --git a/ansible_collections/community/zabbix/CHANGELOG.rst b/ansible_collections/community/zabbix/CHANGELOG.rst
index cf83e116c..e6b53e476 100644
--- a/ansible_collections/community/zabbix/CHANGELOG.rst
+++ b/ansible_collections/community/zabbix/CHANGELOG.rst
@@ -5,6 +5,163 @@ community.zabbix Release Notes
.. contents:: Topics
+v2.3.1
+======
+
+Bugfixes
+--------
+
+- Avoid to update user-directory configuration in dry run.
+
+v2.3.0
+======
+
+Minor Changes
+-------------
+
+- api_requests - Handled error from depricated CertificateError class
+- multiple roles - Removed unneeded Apt Clean commands.
+- proxy role - Updated MariaDB version for Centos 7 to 10.11
+- zabbix web - Allowed the independent configuration of php-fpm without creating vhost.
+- zabbix_host_info - added ability to get all the hosts configured in Zabbix
+- zabbix_proxy role - Add variable zabbix_proxy_dbpassword_hash_method to control whether you want postgresql user password to be hashed with md5 or want to use db default. When zabbix_proxy_dbpassword_hash_method is set to anything other than md5 then do not hash the password with md5 so you could use postgresql scram-sha-256 hashing method.
+- zabbix_server role - Add variable zabbix_server_dbpassword_hash_method to control whether you want postgresql user password to be hashed with md5 or want to use db default. When zabbix_server_dbpassword_hash_method is set to anything other than md5 then do not hash the password with md5 so you could use postgresql scram-sha-256 hashing method.
+- zabbix_templategroup module added
+
+Bugfixes
+--------
+
+- api module - Fixed certificiate errors
+- proxy and server roles - Defaulted location of fping and fping6 based on OS.
+- proxy role - Removed requirement for mysql group definition.
+- server role - typo in configuration var StasAllowedIP to StatsAllowedIP
+- zabbix-{agent, javagateway, proxy, server, web} - support raspberry pi without repository url specification
+
+v2.2.0
+======
+
+Minor Changes
+-------------
+
+- Added zabbix_group_events_info module
+- action module - Added notify_if_canceled property
+- agent and proxy roles - Set default `zabbix_api_server_port` to 80 or 443 based on `zabbix_api_use_ssl`
+- agent role - Removed duplicative Windows agent task
+- agent role - Standardized default yum priority to 99
+- all roles - Re-added ability to override Debian repo source
+- all roles - Updated Debian repository format to 822 standard
+- various - updated testing modules
+- various - updated to fully qualified module names
+- zabbix agent - Added capability to add additional configuration includes
+- zabbix_api_info module added
+- zabbix_user module - add current_passwd optional parameter to enable password updating of the currently logged in user (https://www.zabbix.com/documentation/6.4/en/manual/api/reference/user/update)
+
+Bugfixes
+--------
+
+- zabbix_inventory - fixed handeling of add_zabbix_groups option
+- zabbix_template - fix template export when template's content has "error" word
+- zabbix_web role - fix variable naming issues (undefined) to zabbix_web_version and zabbix_web_apt_repository
+
+v2.1.0
+======
+
+Minor Changes
+-------------
+
+- Multiple Roles - Replaced depricated 'include' statements with 'include_tasks'
+- Update action_groups variable in runtime.yml
+- all roles - Added support for Debian 12 (Bookworm)
+- all roles - Delete gpg ids variable.
+- all roles - Modified to allow a non-root user to run the role.
+- all roles - Updated testing to account for the correct version of Zabbix
+- zabbix_hostmacro module - Add description property for Host macro creation/update. Allow to set/update description of Zabbix host macros.
+- zabbix_proxy - Added installation of PyMySQL pip package
+- zabbix_proxy - Modified installation of Centos 7 MySQL client
+- zabbix_proxy - Standardized MySQL client installed on Debian and Ubuntu
+- zabbix_regexp module added
+- zabbix_settings module added
+- zabbix_token module added
+
+Bugfixes
+--------
+
+- agent role - Added missing become statement to allow run to role as nonroot
+- zabbix_host module - fix updating hosts that were discovered via LLD
+- zabbix_proxy role - failed at version validation. Fix adds cast of zabbix_proxy_version to float, similarly to the other roles.
+- zabbix_proxy role - undefined vars at updating proxy definition. Fix adds null defaults for zabbix_proxy_tlsaccept and zabbix_proxy_tlsconnect.
+- zabbix_web role - removed 'ssl on;' nginx configuration, which is no longer supported since nginx version 1.25.1.
+
+New Modules
+-----------
+
+- community.zabbix.zabbix_regexp - Create/update/delete Zabbix regular expression
+- community.zabbix.zabbix_settings - Update Zabbix global settings.
+- community.zabbix.zabbix_token - Create/Update/Generate/Delete Zabbix token.
+
+v2.0.1
+======
+
+Bugfixes
+--------
+
+- Proxy and Agent Roles - Added `zabbix_api_use_ssl` variable to allow secure API connections
+- Web Role - Added defaults and documentation for `zabbix_apache_custom_includes`
+- agent - Handled undefined variable error for Windows default versions
+- all roles - Added option to selectively disable a repo on Redhat installs
+
+v2.0.0
+======
+
+Minor Changes
+-------------
+
+- Replaced usage of deprecated apt key management in Debian based distros - See https://wiki.debian.org/DebianRepository/UseThirdParty
+- Standardized tags across all roles.
+- Updated all roles to default to version 6.4 for install.
+- all roles - removed unused variables from defaults
+- all roles - standardized testing matrix to check all supported versions and operating systems.
+- all roles - temporarily disable epel repo on zabbix installation tasks
+- all roles - updated documentation.
+- inventory plugin - switched from using zabbix-api to custom implementation adding authentication with tokens
+- inventory script - re-coded to stop using zabbix-api. API tokens support added.
+- web role - removed support for htpasswd
+
+Breaking Changes / Porting Guide
+--------------------------------
+
+- agent role - removed support for Darwin, Amazon, Fedora, XCP-ng, Suse, Mint, and Sangoma operating systems
+- agent role - removed support for zabbix_create_host and replaced it with zabbix_agent_host_state
+- agent role - removed support for zabbix_create_hostgroup and replaced it with zabbix_agent_hostgroups_state
+- agent role - removed support for zabbix_http_password, zabbix_api_http_password, zabbix_api_pass, and zabbix_api_login_pass and replaced it with zabbix_api_login_pass
+- agent role - removed support for zabbix_http_user, zabbix_api_http_user, zabbix_api_user, and zabbix_api_login_user and replaced it with zabbix_api_login_user
+- agent role - removed support for zabbix_inventory_mode and replaced it with zabbix_agent_inventory_mode
+- agent role - removed support for zabbix_link_templates adn replaced it with zabbix_agent_link_templates
+- agent role - removed support for zabbix_macros and replaced it with zabbix_agent_macros
+- agent role - removed support for zabbix_proxy and replaced it with zabbix_agent_proxy
+- agent role - removed support for zabbix_update_host and replaced it with zabbix_agent_host_update
+- all modules - dropped support of Zabbix versions < 6.0
+- all roles - removed support for the zabbix_version variable.
+- all roles - removed support for all versions of Zabbix < 6.0.
+- all roles - removed support for installation from epel and non-standard repositories
+- dropped support of zabbix-api to make REST API calls to Zabbix
+- proxy role - removed support for zabbix_database_creation and replaced it with zabbix_proxy_database_creation
+- proxy role - removed support for zabbix_database_sqlload and replaced it with zabbix_proxy_database_sqlload
+- proxy role - removed support for zabbix_selinux and replaced it with zabbix_proxy_selinux
+- server role - removed support for zabbix_server_mysql_login_password and replaced with zabbix_server_dbpassword
+- server role - removed support for zabbix_server_mysql_login_user and replaced with zabbix_server_dbuser
+- stopped supporting Ansible < 2.12
+- stopped supporting Python < 3.9
+- zabbix_action - message parameter renamed to op_message
+- zabbix_group_facts module - removed in favour of zabbix_group_info
+- zabbix_host_facts module - removed in favour of zabbix_host_info
+
+Removed Features (previously deprecated)
+----------------------------------------
+
+- agent role - removed support to configure firewall
+- web role - removed installation of apache, debian, and php
+
v1.9.3
======
diff --git a/ansible_collections/community/zabbix/CONTRIBUTING.md b/ansible_collections/community/zabbix/CONTRIBUTING.md
index df591ef1c..b11725793 100644
--- a/ansible_collections/community/zabbix/CONTRIBUTING.md
+++ b/ansible_collections/community/zabbix/CONTRIBUTING.md
@@ -59,7 +59,6 @@ These rules are required for any contributions proposing a new Zabbix module or
* In `DOCUMENTATION` block via `extends_documentation_fragment` keyword.
* In module `argument_spec` as a set of module parameters.
* Implement proper logout mechanism as other modules do.
-* Use the same version of `zabbix-api` library as defined in collection requirements.
* Comply with [Ansible module best practices](https://docs.ansible.com/ansible/devel/dev_guide/developing_modules_best_practices.html).
## Testing and Development
diff --git a/ansible_collections/community/zabbix/FILES.json b/ansible_collections/community/zabbix/FILES.json
index 80415b832..d8e8b2611 100644
--- a/ansible_collections/community/zabbix/FILES.json
+++ b/ansible_collections/community/zabbix/FILES.json
@@ -46,49 +46,49 @@
"name": ".github/workflows/agent.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7f6609467d2f142f82e08d9a3675286695188b1f96eae451c5a92f9fc92ad880",
+ "chksum_sha256": "1f4eaa1cf578bb1ac84173e292873c14483a3e9b0218badf5f99b949b1d19f75",
"format": 1
},
{
"name": ".github/workflows/javagateway.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4768caf2de9e672c21e17389ed2e8ae19009198270cd37fc73f3b2ee745da85f",
+ "chksum_sha256": "282c567de319fd40b888e0bea2b8340418acaf3e1360b1f4cd2fcec845580c4d",
"format": 1
},
{
"name": ".github/workflows/plugins-integration.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c15c0360234358038f7f2d9835eedfc2f90aaf5fec5fccc95d0ac8c99c0c453a",
+ "chksum_sha256": "c8ab5f2a2482938905571a63bc80edb9bc421a7356526adff54978f158c998be",
"format": 1
},
{
"name": ".github/workflows/proxy.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9d6b75380b849fb9e88a2484c599cf52206242f7caf1bb964e1a3431836be0c0",
+ "chksum_sha256": "0b93f36762cb804aa12a46d2e15ec2b0cf4ec61198db451fb5e8d60601c4e2c7",
"format": 1
},
{
"name": ".github/workflows/repo-sanity.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "547ff5f443f05cba80f3a80180f7418b1df7e015701ebb8125b1fb6151a9cb77",
+ "chksum_sha256": "7df59ea87533f81dea79e8869b8a4074e0caafa171b62d07d24fc53ae4447af2",
"format": 1
},
{
"name": ".github/workflows/server.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "db95b5b85610665607a70cfc1dd50eed1224ededa3c3513b56601385964d9c9a",
+ "chksum_sha256": "20f9e0d9de9e0b5fba678c672628e0bf2900794a61e7a9b4414e16dd10eda3b3",
"format": 1
},
{
"name": ".github/workflows/web.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1530135054b317b5605a4fbe8680faa74e87007080ae0f59f111ba1fa4e2a5b0",
+ "chksum_sha256": "c5e042f11aeabebedb326853b6a5712c3ef02fbc884329b26c4b38d3d942861a",
"format": 1
},
{
@@ -116,14 +116,14 @@
"name": "changelogs/.plugin-cache.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0b56a72dcc4aae26837ecd516b88b5889b0fbf0085367125e47a1eb0d79fe4cc",
+ "chksum_sha256": "d64872f24dbd6423bc177cc30e44f48f8f2c008fb83d98320c86507e52bc4fd2",
"format": 1
},
{
"name": "changelogs/changelog.yaml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4c0e5e697fb8f013a1a392689a23d91da029b6b9b321c49b218b6cb69d51dec0",
+ "chksum_sha256": "7ec8214d899a562092105e8650db5a80d38065ac6f21e8eba77ce6b31c1be9b9",
"format": 1
},
{
@@ -134,13 +134,6 @@
"format": 1
},
{
- "name": "changelogs/roles_zabbix64.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "f4d624707b0cf06c6b382891d2c759289219e03ea633da90622623082c1bafb6",
- "format": 1
- },
- {
"name": "docs",
"ftype": "dir",
"chksum_type": null,
@@ -151,7 +144,7 @@
"name": "docs/PUBLISHING_TO_GALAXY.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "df53d35672848c736b9cf780b968936413631d41c9abbad1c3da9d7782d7955d",
+ "chksum_sha256": "53c357be0c9e0bda0ef2a04dad6c85df28ea33b20c7c4b33aa4ce0ad30171eaf",
"format": 1
},
{
@@ -162,45 +155,38 @@
"format": 1
},
{
- "name": "docs/UPGRADE.md",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "e4e1d4fa54395501c71f8c70b369c16aa4b4edf15b5a65a1746cb727d98f51f0",
- "format": 1
- },
- {
"name": "docs/ZABBIX_AGENT_ROLE.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ee2a165aac204d9df3bca010af9f662e99b3442bc10da941d00d87285d51bbca",
+ "chksum_sha256": "426cdb2833f6b41fae8e6d3eceb45e5d7e53bb64fda20238a4843e1f23ce6bc5",
"format": 1
},
{
"name": "docs/ZABBIX_JAVAGATEWAY_ROLE.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b4182c4262079bb61943eabdd08dce46e0240d30dc3b61494fe1fdba11dca828",
+ "chksum_sha256": "950880306b5d99f842830620bcb03e3a67d487ab62b60c650421027b620824c9",
"format": 1
},
{
"name": "docs/ZABBIX_PROXY_ROLE.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ac111a4c75c45c1c320381b8f1032e52be9822bf1b7c5713591f8077d3223b56",
+ "chksum_sha256": "137aa537b0643a8aba1e3b94965bd33d91a53a780a8873a398e07620a1c64ec4",
"format": 1
},
{
"name": "docs/ZABBIX_SERVER_ROLE.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d9e5f1ebef97ef13cd79fa70e4d2e1fbbd48090e239a13be019edd2a179f45d0",
+ "chksum_sha256": "434d9e12ff1d20c7f2e1891e2518628eea9f8497502a5032a7f83ea488477665",
"format": 1
},
{
"name": "docs/ZABBIX_WEB_ROLE.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5aad816040102389cc79090e613ff22231337424f20bfe9626d022b153023ac5",
+ "chksum_sha256": "228030e059e30b229a82e7c31b609d5d122d710338557ebd74ee151eda79c0fb",
"format": 1
},
{
@@ -214,7 +200,7 @@
"name": "meta/runtime.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "50679314811f43a872bd27d00dcdce7ae167a1612307c3bd16dc63aa17dddb42",
+ "chksum_sha256": "ae56876a44f1225a766a414ae93397720a4df40db4ab38ba6c32e0373c2ffe38",
"format": 1
},
{
@@ -256,7 +242,7 @@
"name": "molecule/zabbix_agent_tests/common/playbooks/prepare.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5ae566f4f24a278f50574ebff1b64c60dfb7aae0a587ec54e8ad35a75a7e6ea3",
+ "chksum_sha256": "eebc4f8c272317fba0f96c482780a2850b9474b2b992b3a80d2f3d59c3db9a52",
"format": 1
},
{
@@ -305,7 +291,7 @@
"name": "molecule/zabbix_agent_tests/common/tests/common/test_agent.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "047aa3486e4c15a37be84128d3072a8c25c2488f8755141d686e29611483cb9a",
+ "chksum_sha256": "6e7673ac6c547d5f6f8c3958037fef7c3e0be5596909f50c6b17c1da86e0c735",
"format": 1
},
{
@@ -333,7 +319,7 @@
"name": "molecule/zabbix_agent_tests/common/molecule.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2e9bf77259593522020af1a6b70b85ecd0d1f02b0c8807801b4bb63ab2f886ef",
+ "chksum_sha256": "9ce9330c02c7d06dca39d7b31e1683ffd552bb341f35603fbb42659e3915a0ac",
"format": 1
},
{
@@ -557,14 +543,14 @@
"name": "molecule/zabbix_javagateway/molecule.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "403c27814ef8c997cd3c483c48337f5e2ce6384a799bb1cdab54c3ac01b1016c",
+ "chksum_sha256": "8e5003cb9d8bcd490b46fe8358affc9cc4c7f60b582c2f42a4713c7fd001768a",
"format": 1
},
{
"name": "molecule/zabbix_javagateway/prepare.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1b6c9f53dce0f4a63df8d386fc1aa264335af706dd00943f8ff66dd735250e22",
+ "chksum_sha256": "5c2130a175978fd0ae2cdf25dd7fb4247f04fce7d9610435d5047a5fa963009f",
"format": 1
},
{
@@ -585,7 +571,7 @@
"name": "molecule/zabbix_proxy/tests/test_default.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "48e48563e12a400b8e24268456f3534f0887217baf48e5fae587c5ec9f59ba39",
+ "chksum_sha256": "057875f1f4a9953622125fd03d150886b763f8ed4b7776fbf30cc4ac0e462713",
"format": 1
},
{
@@ -606,14 +592,14 @@
"name": "molecule/zabbix_proxy/molecule.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "780d05e996542297e40e112566587ba18cbea58becb58c298a94a6c65a7c2c18",
+ "chksum_sha256": "59ff07c357b6c9d01f0337b6c6b5878c90efb396132faec46b37628680bce34d",
"format": 1
},
{
"name": "molecule/zabbix_proxy/prepare.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "37c3e8879e3a5fb94115a8745f19e4fdd6eca693b852d048ad881c2de3e13f9d",
+ "chksum_sha256": "d3fde6e25ce3b39d5c70324f7db1ac9aed31e0a3106c51dc77c3be7293f55a19",
"format": 1
},
{
@@ -634,7 +620,7 @@
"name": "molecule/zabbix_server/tests/test_default.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "23f62965273df247d7ae99c4a171ef2f22b352d63e7af18eb617b3aebf0a1840",
+ "chksum_sha256": "32f8fe869c639ee0fdaab4f8a82a1726ac3a28ac91e1a3095f9b970ad4455894",
"format": 1
},
{
@@ -655,14 +641,14 @@
"name": "molecule/zabbix_server/molecule.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "25b8acf6faf7dffa24083bae88ae7b9b4044741e8cd85083ce48cdd5c6a1b39c",
+ "chksum_sha256": "eb8ff715881d9046a2aa6d4b0ec64f68c59e7cf48bff7644236e44399570bb53",
"format": 1
},
{
"name": "molecule/zabbix_server/prepare.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "01f51c7913635ba28f9fc720a540a2b59c7b71123c51e3b9e6bd4493b2bb5de8",
+ "chksum_sha256": "34346df48a4e44910398adcea6030e76735f03464ea0b0415160b2c8b86297d7",
"format": 1
},
{
@@ -683,7 +669,7 @@
"name": "molecule/zabbix_web/tests/test_default.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "81f986130198995bbaeb722b7659e214830e1cc91e00313e87b3e6cbca38b6c1",
+ "chksum_sha256": "d078bd5d704618add6913f1bcd75aa8b4ebf6b71e46b43299d58dbef4a6c21de",
"format": 1
},
{
@@ -704,14 +690,14 @@
"name": "molecule/zabbix_web/molecule.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cec08cba46b8c5f66fe3b9f018014a7c506fa145ca90a02472942f955c4c2910",
+ "chksum_sha256": "160ca8984b2f48f84e64e2d928ef1ab8a807f5cfb6c36d1c37d7920ca284efca",
"format": 1
},
{
"name": "molecule/zabbix_web/prepare.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e42cb66ee3a4f8a6149adc9d85538e73d66d7fd43f9b5af95335ca4d186a0c20",
+ "chksum_sha256": "46f227d436fbf62c6a18677746e4b3b2f6854473ea58ea889781d60a5d86acaa",
"format": 1
},
{
@@ -725,7 +711,7 @@
"name": "molecule/requirements.txt",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5da70582c0669065d3948183fd74a508a2ecb80f683e4499050b39415931858b",
+ "chksum_sha256": "274a2a68c3bac9fefa051ff068179fce63df05424461ff973dd44473c890382b",
"format": 1
},
{
@@ -743,17 +729,10 @@
"format": 1
},
{
- "name": "plugins/doc_fragments/connection_persistent.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "b3d6dc35fc7752bd61b55722c5ae88ae02170b93fb85960b7b1430c2bb7146df",
- "format": 1
- },
- {
"name": "plugins/doc_fragments/zabbix.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "64d6a3931787f894153e068ae4e91fddfe8127ed7e61ea903a45a60269b1406b",
+ "chksum_sha256": "2f57fd09f9be79cba82c211dcab2e423a54d27228bc2afd57b578a4a6b95dfbb",
"format": 1
},
{
@@ -767,7 +746,7 @@
"name": "plugins/httpapi/zabbix.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "65146ad205a7cc5d5d5d08b5f4172582878ceb8a9c01f26b36447f18fac996ce",
+ "chksum_sha256": "bef450e3b5700be1a1cc35981b229a53522a35a0e1d13f1ba715922f3ee79d2c",
"format": 1
},
{
@@ -781,7 +760,7 @@
"name": "plugins/inventory/zabbix_inventory.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bc0ec92bd5b83af4f840d8dfc0c6ec1da5f88093a75a57ad0456cc3fc7690959",
+ "chksum_sha256": "5bf212295bcf22a955fbc9c8b2ffd2395ba948e68ace593098ffbe2391247c3a",
"format": 1
},
{
@@ -809,28 +788,21 @@
"name": "plugins/module_utils/api_request.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a1a0b0b8fc8189a3dc6facd77621cb14e99511319a0b082a7803fb0976d8d080",
+ "chksum_sha256": "add8f4adc48b8104914edb4c5a6200d78c89e02d3a6c01fa54c3142954ae3498",
"format": 1
},
{
"name": "plugins/module_utils/base.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "54657e0efada7dc5e77dca6546721031478f8bdd298f690509076b17e15e9af4",
+ "chksum_sha256": "d2437b6f8ce0f700c801869ca310b2a70589046a1994ad06962ba70b2f448d30",
"format": 1
},
{
"name": "plugins/module_utils/helpers.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2eaf8c62644252eb35908db596c4226df48ba3340bfadc95bf6102aeabf851f5",
- "format": 1
- },
- {
- "name": "plugins/module_utils/wrappers.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "b592fdc7a1a516f00d256702a24530507bb9e63acee9469f78776a6066429b55",
+ "chksum_sha256": "42ec390b1f0ee4fa92aa19c33b84963267d994c221d74e7ea2fce1635f951fc9",
"format": 1
},
{
@@ -841,220 +813,241 @@
"format": 1
},
{
- "name": "plugins/modules/zabbix_group_facts.py",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "72829e189f762da9a094b5a2d6d79783abb09311fef0ca321e4bc6ca8cf6f308",
- "format": 1
- },
- {
- "name": "plugins/modules/zabbix_host_facts.py",
+ "name": "plugins/modules/__init__.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9d0341ced4e1d0c2d36276d1d0fe7271a530b89b5f751541a5cf7a32012f6847",
+ "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"format": 1
},
{
- "name": "plugins/modules/__init__.py",
+ "name": "plugins/modules/zabbix_action.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ "chksum_sha256": "a3dace3d7ea72cf09dde768f2896094335a3c7e11f6bfc8507a288530ae9401f",
"format": 1
},
{
- "name": "plugins/modules/zabbix_action.py",
+ "name": "plugins/modules/zabbix_api_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f2eeb69c809b3aba15df826b79233b43209a6de279d8bbd3b5e09cd7cd016aa1",
+ "chksum_sha256": "c9b579e945d2c5029acbd05006f18a97fa4ec8324128693a4712c7a05ee804bf",
"format": 1
},
{
"name": "plugins/modules/zabbix_authentication.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "04357311ce1b7345a774bb630ab4b76f8a2fa02e766e9053cf92777bedac0659",
+ "chksum_sha256": "1afb95c8c1e4921ed4397da4fd3c978863e909c99c0de087720480d4d616ff68",
"format": 1
},
{
"name": "plugins/modules/zabbix_autoregister.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a21144832a5d33b502beea5c30eef7117822ebdb2e2829b541151c5deee6d65a",
+ "chksum_sha256": "8ef9941a5854ecf03895cace6e59b1c19aed74f8c13d385a68c1d2231a39f8ac",
"format": 1
},
{
"name": "plugins/modules/zabbix_discovery_rule.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ed9c604f7ed63e7f9021a6fcfe5a42998e27bcc59ef118593d7bd32810be0adf",
+ "chksum_sha256": "49277e61440825a7feb15162ffb6c38e40a81a021abdbecf9bd7db748bb4730d",
"format": 1
},
{
"name": "plugins/modules/zabbix_globalmacro.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "93a2dff2fdec0e4c9270951f851a6b705fd83097579c6dfa224da75a70c9fd3d",
+ "chksum_sha256": "b7f5f0f0b9abe2d49246945e70555bd63490659526ff4013677c420b0b3b4d2c",
"format": 1
},
{
"name": "plugins/modules/zabbix_group.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8c4997b0b63820066e3804edaf37e6c595566e1bdcb747e2a2b4ac7d8329e0cd",
+ "chksum_sha256": "2f2d7202edcd8d02e353eeb45292a9076abcdc520c86585ae7d849f4a0919a26",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/zabbix_group_events_info.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "c0af2025b1df634ed14b1ffbee3947e7ec438b4e4d9e8cfe41a4da54c614e384",
"format": 1
},
{
"name": "plugins/modules/zabbix_group_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "72829e189f762da9a094b5a2d6d79783abb09311fef0ca321e4bc6ca8cf6f308",
+ "chksum_sha256": "1880c246619a51b3603ff55b4ad71a79c23198a9e3b823f30c1d1078c73b649d",
"format": 1
},
{
"name": "plugins/modules/zabbix_host.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f73e0a24b2fdfe72d83a0a2453431a847aec7bde7dd544ad214322bbb60599ce",
+ "chksum_sha256": "ce0879953bfeaac236d6329b08fd19f7573a9a172ef4fa777489d6f9f1fd6609",
"format": 1
},
{
"name": "plugins/modules/zabbix_host_events_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "488889c8ca3f4b6e9acbb27c9c26b92d8180de9a600c0b676996bb4797208813",
+ "chksum_sha256": "4d8d7767314f3dfc8c32f1cb3aa4c056fc9c81023e09b121db99018c06533660",
"format": 1
},
{
"name": "plugins/modules/zabbix_host_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9d0341ced4e1d0c2d36276d1d0fe7271a530b89b5f751541a5cf7a32012f6847",
+ "chksum_sha256": "91b4a19126c54b4142b60f309e9fda96daa4d5b5974292eff07ddec4c0a86ef8",
"format": 1
},
{
"name": "plugins/modules/zabbix_hostmacro.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9f477dc001793c78a94dbd141e700d56423e56fed515035080647829b7c7e4a3",
+ "chksum_sha256": "c55f33c57e6c8401d5588c469c714869ba79631b401df40838e9566b37a9a274",
"format": 1
},
{
"name": "plugins/modules/zabbix_housekeeping.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c4b26c8caa59756d48ba0e5b95776829982502f3d8870d71c93cea9107315d8d",
+ "chksum_sha256": "e0313bb629d34231bd549ad8fe2170be157f38ca5d14563a1eb7008c27a961af",
"format": 1
},
{
"name": "plugins/modules/zabbix_maintenance.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "364f6004001d05fa7750e254de4732674978abb28fb2e1cc11172275be9c84d5",
+ "chksum_sha256": "baa73f10a75adbfc09a93d5624492aa9b2e174bf089641cfbd37e329865fe313",
"format": 1
},
{
"name": "plugins/modules/zabbix_map.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d5dc24b8b8ef92874326de6fdab300bdeb2f6a71545fea10ee64a0a1d9ab18d4",
+ "chksum_sha256": "16f772207be532d4c79c219bb14b9b927d356a45bd467271956560e33da58c7a",
"format": 1
},
{
"name": "plugins/modules/zabbix_mediatype.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6a0b555e69e815d00fbdb7e37041e0f216a6c621a1abd7b67b228b14d7294821",
+ "chksum_sha256": "555d924fcf31e673c17917fc5f7abf1d6d8f1de17d87386f5a2626549cdab7f3",
"format": 1
},
{
"name": "plugins/modules/zabbix_proxy.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f442459b52bab35073f9366dfe0bc16afd219ad505d91b6b681734f563884ae4",
+ "chksum_sha256": "97e129e170b7e0208c5b8b48160f1853da0b47f491c83b70ee4a0d06b47e37d1",
"format": 1
},
{
"name": "plugins/modules/zabbix_proxy_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e02f116191199752c9087cd867cc4ad0bacd19338a36978c740f408548e2c312",
+ "chksum_sha256": "599e78d0839a31712f21dedf223aec64502be89188a71ea725a83827fbd1f70e",
"format": 1
},
{
- "name": "plugins/modules/zabbix_screen.py",
+ "name": "plugins/modules/zabbix_regexp.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1f74721c60d1db5e8aa8031876db2d88e2192aee39851c9bf1a6e219fad99fee",
+ "chksum_sha256": "0e9fd757dbdc521abbc9bbdf90144486f0f1b61d4d5412923ea4839d099a10cd",
"format": 1
},
{
"name": "plugins/modules/zabbix_script.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a4dc1c9b646b8586121a5d89d382c4e8162c0ee9072d659e5cb68e7c895d9ea3",
+ "chksum_sha256": "3fd732f7f929a0dbe91dbaa4ce1d2c7fcd86b0c5199ee9ca5d9db8e3f471b613",
"format": 1
},
{
"name": "plugins/modules/zabbix_service.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "07c6a4604e5d780165daaa43cf304bbc858fee747c30dc7561ddc00643db23f8",
+ "chksum_sha256": "24ea8aa83ee4a248bbd58c9bb06808233bd416e7cee835453b39e161b0f3733a",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/zabbix_settings.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ace8dc0e8c72c74a086b72749865531a95bfd04a6efcdf76eec7045ae9a1cdf5",
"format": 1
},
{
"name": "plugins/modules/zabbix_template.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b57132f5e62c804acc1828b459a2e70efa49945201ceedbcf71951b4594f50ef",
+ "chksum_sha256": "d08d3ff4e10193b5a69e3bb515c1ee00157526ab702dc4ffadca8b4adb1c2b1c",
"format": 1
},
{
"name": "plugins/modules/zabbix_template_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "910e1b679b257e0b64d807d4162e85d29fb6d6b8f05c2fb9ec9f0d51eb85fc8e",
+ "chksum_sha256": "9a81416d70353d40edf7917a65076a580cf89885f24313e4192cfa794fe4ac46",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/zabbix_templategroup.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "9c8ca31207e2894422502cf15cf3e3774ce2f944e4bc403c87ab5978f360b236",
+ "format": 1
+ },
+ {
+ "name": "plugins/modules/zabbix_token.py",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "87cfdee6888e77b0a0032f9ed7fb203cb2f94dd6d302367001bfaa874d5be197",
"format": 1
},
{
"name": "plugins/modules/zabbix_user.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2397b8173b49107a3238de5ecaf0509bcd1842c55e1329fe765f2f6d902caaa2",
+ "chksum_sha256": "f980a6933f2fa41e09f5d7103d0aff75b1aeb51ca244d49eba80743a0713b175",
"format": 1
},
{
"name": "plugins/modules/zabbix_user_directory.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "821641cedc3d4a5cfa669f063b434dc0b07b4fb5b128392d96c4c24c25e5d126",
+ "chksum_sha256": "6a5692e2db9ea9dff204b36dea634478aa9eeff7c8b9c18c419b1db35cd53f09",
"format": 1
},
{
"name": "plugins/modules/zabbix_user_info.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5073676377f2089d55e17f23c86bfe5b4a7c5014b2aa52a05242b7d49251a65d",
+ "chksum_sha256": "eb5041f792858b49d48d52f7d50107e0dc0dd49e905370a6b4d6fdb5e46975b3",
"format": 1
},
{
"name": "plugins/modules/zabbix_user_role.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b5cc955ca1ac15ba0d15b2159387facb6e12590865e63c9d9b2061f603ee37ac",
+ "chksum_sha256": "b3355345e85e6ab21c3afdc882f400d584c45fe581b6e065b9051e43ecd84994",
"format": 1
},
{
"name": "plugins/modules/zabbix_usergroup.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a7f908ac23ad94f1f3f5916e8fa48cb864e5401d00126532a4668c14681e605b",
+ "chksum_sha256": "aef8772084635607bc5b371f4d5425029bce045156b7415e4ea6205ddf99afe8",
"format": 1
},
{
"name": "plugins/modules/zabbix_valuemap.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "285b6b71d55ac7d8844f79a6d8c100bd899279aaa7ee35bea78d10ea810615e6",
+ "chksum_sha256": "3540592c87e41e55de5f3acd2e13585cb18c11d8615c98c63dc9ffadd59a8935",
"format": 1
},
{
@@ -1075,7 +1068,7 @@
"name": "roles/zabbix_agent/README.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ee2a165aac204d9df3bca010af9f662e99b3442bc10da941d00d87285d51bbca",
+ "chksum_sha256": "426cdb2833f6b41fae8e6d3eceb45e5d7e53bb64fda20238a4843e1f23ce6bc5",
"format": 1
},
{
@@ -1089,7 +1082,7 @@
"name": "roles/zabbix_agent/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "12b9fc863285e0cdd2d5be2f81bfbd62e68d8ebe11dbb66b18a5ed50347b9a21",
+ "chksum_sha256": "e86a6de88e4fb31fd47d9268557e10f71e42988e4dca09a6228497be99c1c225",
"format": 1
},
{
@@ -1131,7 +1124,7 @@
"name": "roles/zabbix_agent/handlers/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "acad5ae4f8591346fcea52d1682ab85ffbd5b9f43595da6f68003755eddf81c5",
+ "chksum_sha256": "261c79c8d62b86e2ad0cefc77641fe9c1794e3a8ccf81e3c6db75a5fa4c56f88",
"format": 1
},
{
@@ -1201,21 +1194,21 @@
"name": "roles/zabbix_agent/molecule/with-server/molecule.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3c886d4bca694a6b19e3d15909f5738b771e6ef9eab31987ef6e63eb480d62e5",
+ "chksum_sha256": "9ffbe5738cb02c6327a778b585a6e931f9cc12a2ec7c271fb340d2e683e12ac2",
"format": 1
},
{
"name": "roles/zabbix_agent/molecule/with-server/playbook.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7acb20ce65dd661f2a8f2ff1492cd385a7d603d7e946f2331e3be0f64f7c2c60",
+ "chksum_sha256": "e92cdcacf5dfc00fc317fc870f231e9ee0ba924298e2878c74338191e6d6b435",
"format": 1
},
{
"name": "roles/zabbix_agent/molecule/with-server/prepare.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "03966cfb5f1589ae0177403025b7cf62bb94bc8e4a551e14fbb87c2a73f8c208",
+ "chksum_sha256": "091c8043ef580658ab2b4c93020888562cd5b3ca5a32d78f7c43892696e0f118",
"format": 1
},
{
@@ -1233,164 +1226,143 @@
"format": 1
},
{
- "name": "roles/zabbix_agent/tasks/Darwin.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "1761047e511995d4aeda5eeda1db4133b2f6f3e18193027a4351bfeee6bada76",
- "format": 1
- },
- {
"name": "roles/zabbix_agent/tasks/Debian.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cacac2625d62892a4da290bc4ac8e36ca7f83c84f5ddf4145cf17a73dfbd70f9",
+ "chksum_sha256": "6d5e5886e18c5774d89567b311e2fbd2dc4aad0b1950af22bb88fafe152a3b78",
"format": 1
},
{
"name": "roles/zabbix_agent/tasks/Docker.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7406219975281823e907acb14e0cfebef02496bc5b85e89380b0c446f9e95ec4",
+ "chksum_sha256": "3be4cf14a566fe855c2c54a126db5b0b33ad3beca3490339351e5d4c03e62f0e",
"format": 1
},
{
"name": "roles/zabbix_agent/tasks/Linux.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "95bcf03c9ac71b4825684bedf69d4069d549c18a13c5943b1f6f89775acf495e",
+ "chksum_sha256": "4cbe916769cde150073a71e1ac8b5e9a3a531ba6a17782944e4e758433877ff8",
"format": 1
},
{
"name": "roles/zabbix_agent/tasks/RedHat.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5cb57a73eed1d8f5152b3b1ad8cb15c8cd0297158b96c27ee42e7629c52aeeda",
- "format": 1
- },
- {
- "name": "roles/zabbix_agent/tasks/Suse.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "71a60660c5dc62b42d22a8798464af1533f364ed28a2fa0bd14cf8fc33f0c66c",
+ "chksum_sha256": "00589dec36032603720fe426db2ed7b5a165037e9d129e42e5679689c89a2009",
"format": 1
},
{
"name": "roles/zabbix_agent/tasks/Windows.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "aa1070768c380a56084c56b4b786be3d5319d8758f0315d41f9bb2ec1a37d760",
+ "chksum_sha256": "709a0466886c5bf5ed5f560b987cf68d268fff906a6dd26b667c25654d37fe81",
"format": 1
},
{
"name": "roles/zabbix_agent/tasks/Windows_conf.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9b90e2b63ab6910636900c305044e67c540ddf2fa3a359a0744f5d73ecf35b3f",
+ "chksum_sha256": "ba0da2675127cf58cfa66ba4e977f15f2f856654fb7583826865276fa10c6262",
"format": 1
},
{
"name": "roles/zabbix_agent/tasks/api.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7ebe1e547cd1ee30e82ebdf6927c050d61733e938955abb28284542e5ceca8da",
- "format": 1
- },
- {
- "name": "roles/zabbix_agent/tasks/firewall.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "8b74b8d9c33d31c6bd972f96187a8ebe407ed7b4e8d4f56c32563ad9a88f5e03",
+ "chksum_sha256": "8201b0dc1b00dd86383f272dd81f06e792f8bab1951aee62c03a46791ca5b4bb",
"format": 1
},
{
"name": "roles/zabbix_agent/tasks/macOS.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "07214cf9e01f2d1b382dee5fa8af5a592f91b64a327d10379c5f50e977bf771b",
+ "chksum_sha256": "519abb365aaf15c992a9a16615ab397e7d08f7f7b3b908557a178ee42d49cf4f",
"format": 1
},
{
"name": "roles/zabbix_agent/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cf4a07124914b3173aa8f2cfa25aa3b575dd0bd6e8ab15ddc4377699b980bbf9",
+ "chksum_sha256": "978ae5731bb64fc79a4c404185da1f915480550e0a79ab8cdcc94475dc0ff86e",
"format": 1
},
{
"name": "roles/zabbix_agent/tasks/remove.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1a19cc7cd1fca702c9d88b573bf8ecdf062396aaf45ad6f6abd4fe4bb1a57d9a",
+ "chksum_sha256": "a61614e0f51ef087ef82eb2319b8546f213c22aff785afdf56f007c442b6cb2c",
"format": 1
},
{
"name": "roles/zabbix_agent/tasks/selinux.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a22d30b558ddcbf9251868fe7accd96208bb813a9fe3878536184f68be55cd19",
+ "chksum_sha256": "5b48575676d826c5e6321daddab3713fbbd76ba575400f29eeafc277017b9fe2",
"format": 1
},
{
"name": "roles/zabbix_agent/tasks/tlspsk_auto.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "107052aaa9b9e206e09a0991f160996b2b390101f71e06ab3f3a8ba7afee5dea",
+ "chksum_sha256": "bcf8266fdd6b7d01d5a6bb97a3f4c1982ca7dc099dedcaa407390c69bbeaa7e6",
"format": 1
},
{
"name": "roles/zabbix_agent/tasks/tlspsk_auto_agent2.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "db9d50614a7bc0247fd8aeefb53cc94fb083f4af5780c9b349acd05b0a9d7ae7",
+ "chksum_sha256": "1d0eafd6fefb287832c5b42c80c37c2b2e049b937aa50f44d7040ce56d81db86",
"format": 1
},
{
"name": "roles/zabbix_agent/tasks/tlspsk_auto_agent2_common.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "89a391fe07d61221c3d1fad2b217c3ce917d929d0c93a6872febb4b38fc9ed16",
+ "chksum_sha256": "3f194c4720b68b5eb4003effe148b6c379a650f91d5325147d3e43485d37ba7b",
"format": 1
},
{
"name": "roles/zabbix_agent/tasks/tlspsk_auto_agent2_linux.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6887ed6b41bbb92b719848be16779655fee4a6bcd4b09d6acca293c25801e24a",
+ "chksum_sha256": "3d651d820f7be9fd52d0b752f6ad07fc3e41a7ba52f178ae1221e1e2419980d9",
"format": 1
},
{
"name": "roles/zabbix_agent/tasks/tlspsk_auto_agent2_windows.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c2d7c59ef98c62873349927d0ca6856375bab84f3b80f5c77365d8599a64d4e3",
+ "chksum_sha256": "416c701d66781d97032e1104e5c25abe4157740f517fdcc5ffea5f5bb14fc9cf",
"format": 1
},
{
"name": "roles/zabbix_agent/tasks/tlspsk_auto_common.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4f214f550557b61a8dd48d05a10a6b507e6ad66b6f40665d6eee762929e7e1d3",
+ "chksum_sha256": "4be3dadd8bfa5cc2aae3de2b975040f6352fee46127b7ccba2b746f11cfdd39a",
"format": 1
},
{
"name": "roles/zabbix_agent/tasks/tlspsk_auto_linux.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "238105b3e8d92db2f70ed8a724c8e317e943138b52c1d98e169614589563ec0d",
+ "chksum_sha256": "1b494062174c84263883f71ed50842255bc270246afbe12f8573bc2e81ea10a9",
"format": 1
},
{
"name": "roles/zabbix_agent/tasks/tlspsk_auto_windows.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d6ef817e770cc8b55b174aa9f02196f68084856945d2bbf9edc79fb4adaa98d8",
+ "chksum_sha256": "bf3c3976e28fb3846de16e0a0e01eae0184d2cf57b79da0a342a5d5b35b187d8",
"format": 1
},
{
"name": "roles/zabbix_agent/tasks/userparameter.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "eb96d45277305e0ce2e5b3bfe264614791ffd4ff9fbaa61f88bc780ac18ea86a",
+ "chksum_sha256": "5248b27e7d45f14a3abdd5d93bf80e416f6e6f084f54f1cceeeba0f1ab08b9dd",
"format": 1
},
{
@@ -1425,14 +1397,14 @@
"name": "roles/zabbix_agent/templates/zabbix_agent2.conf.j2",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "313aa178efad06ed5e47570ad86b65a1fe434131afe275bb7c2515ffa09f211f",
+ "chksum_sha256": "123866b68a1511d56e14a523035583e6a3adcf8d234abd086f4b7ba0e322df4b",
"format": 1
},
{
"name": "roles/zabbix_agent/templates/zabbix_agentd.conf.j2",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c724b3b877eaf83a2c083bb69aca3e946be294ff4308f0abaf5294e29164cf36",
+ "chksum_sha256": "d3c56ebbe34908eaa981e1838ee17ab90729814dce584c1b3e66ab2455ac6f0f",
"format": 1
},
{
@@ -1443,45 +1415,24 @@
"format": 1
},
{
- "name": "roles/zabbix_agent/vars/Darwin.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "db7f6b6b2dd80ddaf2e8d281c78f350a4849b74deda63ef63338b7699527fa20",
- "format": 1
- },
- {
"name": "roles/zabbix_agent/vars/Debian.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "37e4c7f331e4c1e92a79fa3d17ec2e4adc06b83d23a3e644f0ac74e294437217",
+ "chksum_sha256": "a5da93f0d2b1f52521b40c0434ebbb78c7c13dfd63b1948689e104e86fc81a6c",
"format": 1
},
{
"name": "roles/zabbix_agent/vars/RedHat.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0f9fb95f6406336aa72a9736463d118362cde397991129391db58038c1897ab0",
- "format": 1
- },
- {
- "name": "roles/zabbix_agent/vars/Sangoma.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "6b0b76e02ac840a2cb89b691d4ae0e6a55e441fa81bd0cc6a9487b0f1bc02019",
- "format": 1
- },
- {
- "name": "roles/zabbix_agent/vars/Suse.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "a0cc3ac65514ccdbd0f6035eb823aa916d7ea8dda1d0b3d9c4a7f783529bc290",
+ "chksum_sha256": "587c2d75417faa8978fdcc729a4b940b4530c5a02df59a049985ab684742e90c",
"format": 1
},
{
"name": "roles/zabbix_agent/vars/Windows.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "af541365edb39dd0d046a3ae36770b01f6f7881001587f68c707e2d171662f6b",
+ "chksum_sha256": "90fd4ff9797beb10be3a9649da827ccb76b83633da33116fc014d6d4984a5f6f",
"format": 1
},
{
@@ -1492,13 +1443,6 @@
"format": 1
},
{
- "name": "roles/zabbix_agent/vars/zabbix.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "2f18e3250d44f4cba423e73e08e1bfff9be95645e559837588901f3e137e5886",
- "format": 1
- },
- {
"name": "roles/zabbix_javagateway",
"ftype": "dir",
"chksum_type": null,
@@ -1509,7 +1453,7 @@
"name": "roles/zabbix_javagateway/README.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b4182c4262079bb61943eabdd08dce46e0240d30dc3b61494fe1fdba11dca828",
+ "chksum_sha256": "950880306b5d99f842830620bcb03e3a67d487ab62b60c650421027b620824c9",
"format": 1
},
{
@@ -1523,7 +1467,7 @@
"name": "roles/zabbix_javagateway/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "87b1aed24ee0aca58a4c4c97bef77b339bb9810816476187310d0ff93e118833",
+ "chksum_sha256": "72237d44a0cfac809b0432db46974f2bb48d1a61260d80491d1c7bde73f1bf47",
"format": 1
},
{
@@ -1551,7 +1495,7 @@
"name": "roles/zabbix_javagateway/handlers/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "9ad072b7d35f1d0e200857c59e5cc8b3c6417427c313bbbdff78fedd95354310",
+ "chksum_sha256": "cca5cb24d36359ed053c7baee07f0fb17f15a93a7ebb8a8b25cf0f150171851b",
"format": 1
},
{
@@ -1579,21 +1523,21 @@
"name": "roles/zabbix_javagateway/tasks/Debian.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cf47a37619f9b6665ee00315c0855d6a1ec9b5840caf651808f66d6c9bf3a099",
+ "chksum_sha256": "1cf7aeabb650158552dcc993e72c3aee3dd54c9d160d95ac4e603eec39d3c763",
"format": 1
},
{
"name": "roles/zabbix_javagateway/tasks/RedHat.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2146cb8284148aa9d5397cbd34d42b8ecb726c53468923fb38e9a4c7328d9d63",
+ "chksum_sha256": "a07992953e92b787c8011a629e5525c8c0e3c3c91b7ff910da3835488e4f23eb",
"format": 1
},
{
"name": "roles/zabbix_javagateway/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "944ef7efad86d6facb498db0ef23de2524ba271973b2f7c3f5e89b1f6aa630ac",
+ "chksum_sha256": "67e5a9cd03529caca8af75622431ec4fe54bc256b14ad7568bedaedfd0f9206a",
"format": 1
},
{
@@ -1607,7 +1551,7 @@
"name": "roles/zabbix_javagateway/templates/zabbix_java_gateway.conf.j2",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "7d2324bdb590456ae36fe2efd638307dd1e9b22279fdeb8483689a5316842875",
+ "chksum_sha256": "66ff3664fd8264f4d3d6cfa11ddf0f1d571dbeba776b2c7f08ca34a53e1deaee",
"format": 1
},
{
@@ -1621,14 +1565,14 @@
"name": "roles/zabbix_javagateway/vars/Debian.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f4eb8a4a848b0eae37caae62c36ae4d1e35dabe5aab2357203f1427b5ad55491",
+ "chksum_sha256": "f6a87b8863fc8b0cf5dec159ecbe788b8cb1963c11d3dfcfddb6f64d3dfce77e",
"format": 1
},
{
"name": "roles/zabbix_javagateway/vars/RedHat.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ee454bd3e000b6cb6bf752ecbd4a29f6a10a2773a148f945220ea91076450493",
+ "chksum_sha256": "15190bbcec0481429596bf843003ba1f7c3267e997f502a988304b757e3c9b55",
"format": 1
},
{
@@ -1639,13 +1583,6 @@
"format": 1
},
{
- "name": "roles/zabbix_javagateway/vars/zabbix.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "2257dcb583cc09be9a13c17c9966b63aa7e14d39cd39d8557eccc0734ff0e9ae",
- "format": 1
- },
- {
"name": "roles/zabbix_proxy",
"ftype": "dir",
"chksum_type": null,
@@ -1656,7 +1593,7 @@
"name": "roles/zabbix_proxy/README.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ac111a4c75c45c1c320381b8f1032e52be9822bf1b7c5713591f8077d3223b56",
+ "chksum_sha256": "137aa537b0643a8aba1e3b94965bd33d91a53a780a8873a398e07620a1c64ec4",
"format": 1
},
{
@@ -1670,7 +1607,7 @@
"name": "roles/zabbix_proxy/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c16dd23a720096fd637c8657a49d8081e2b50f86ed22d0b2b3557991ff23e086",
+ "chksum_sha256": "f3cc7cde32ae9908078b20eb97d7f25baaccbbd2f0ea4678296ae36a3fb10087",
"format": 1
},
{
@@ -1698,7 +1635,7 @@
"name": "roles/zabbix_proxy/handlers/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "02effc86ecae774f9c4e208da774604bc32a1aa263225d77b817a501d2d3df7d",
+ "chksum_sha256": "6768668411203f0cd315b10510ef61515960d0dcde185c22e03d7e9f1937ec25",
"format": 1
},
{
@@ -1726,49 +1663,49 @@
"name": "roles/zabbix_proxy/tasks/Debian.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8a35de709c48c4224dece469ca5f45bf81671482294251194c17ffd7a4c488c5",
+ "chksum_sha256": "62d366a97ff9d7a6b6f5ec20bde13cb22b447b0271f7e2e432dcad6c9b771712",
"format": 1
},
{
"name": "roles/zabbix_proxy/tasks/RedHat.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b770f37ceb3ae2f48a8fe8b21b3d305f973c07574ad9079e28a7685179b47978",
+ "chksum_sha256": "4b521fd4998782a7fd2e5e8c4bea84d5436dd9e63b0732a0590034181e5c6329",
"format": 1
},
{
"name": "roles/zabbix_proxy/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "12a3f45c5eb455cb937e1b48f524991a3eacfd53461cb5f71358a3a79ba75afb",
+ "chksum_sha256": "45ee561d3bf7df8a5067ccb625a15546b2572e202f75614b57af7143766cf63a",
"format": 1
},
{
"name": "roles/zabbix_proxy/tasks/mysql.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "3f3d72cc83e4c5cbe9cedd034359ead81c09567126b75240e4ebe284c45d44a4",
+ "chksum_sha256": "ea5c5f6380e122e9b658d4acd5e8a382fa6c564673ec37c947a92f95f0b24ec5",
"format": 1
},
{
"name": "roles/zabbix_proxy/tasks/postgresql.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0e29dc6547af5aab28881b169743a468447a8a2e43f81e93f039b72f12a1c724",
+ "chksum_sha256": "1b97ce83bb12d6f435c0363e4f39888c87d0be53db6561168771add354fdd41f",
"format": 1
},
{
"name": "roles/zabbix_proxy/tasks/selinux.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "09b879efd086b9b6b85323dfcc9880366001e6766a376ffe0a3d7debf74dcd8b",
+ "chksum_sha256": "5fcaf2583198e89e108cc2b2a7b777fa6e2dac1a2a1efd88a6c44308d79a6362",
"format": 1
},
{
"name": "roles/zabbix_proxy/tasks/sqlite3.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "62e88f189a7a692fffcfc5fe245d725c6c5685778e7b83155abaae89727ce737",
+ "chksum_sha256": "4c3b276cddc6afa88a48224fa274ca8ea7b7b59d74655197bddec0545a38309d",
"format": 1
},
{
@@ -1782,7 +1719,7 @@
"name": "roles/zabbix_proxy/templates/zabbix_proxy.conf.j2",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e47e91ec1f3da19270f6d5091b18b6b04af7a43761052f10582a151fa973be99",
+ "chksum_sha256": "8133d6ef95a09b0e435324b3005c524745eb0e194cfa591cb3d6f4c36a312590",
"format": 1
},
{
@@ -1793,38 +1730,24 @@
"format": 1
},
{
- "name": "roles/zabbix_proxy/vars/Amazon.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "7d87cd61d18e6d90032bfe0a42d18cb1bf651001280e06ac60a7850e7be5e733",
- "format": 1
- },
- {
"name": "roles/zabbix_proxy/vars/Debian.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0b725e04160bcf663d6d88baa8b99d90500e2026def7a5b157fa6d582c5836a6",
+ "chksum_sha256": "66a3826d949a04140ff1fda9f008f8ef657050cb854677b4cf5c07c69a546346",
"format": 1
},
{
"name": "roles/zabbix_proxy/vars/RedHat.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "262daf894cef6d121f54caf8b14dc627f1c2a438c28448235c7fa8d288e59f9d",
+ "chksum_sha256": "50f4bb5b1ab62a8f1128dde98e820349b164ef4c1583e6f78d61279d19e56c48",
"format": 1
},
{
"name": "roles/zabbix_proxy/vars/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2a54870b52848a1bdf2dcbcd7e86f46509f868c02c51ca4f315457282b5a9c78",
- "format": 1
- },
- {
- "name": "roles/zabbix_proxy/vars/zabbix.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "52df6b43e568fd07f963c088f523b2ffcc903da18bc1037fed1952e7dc86f384",
+ "chksum_sha256": "599afb847ce1287ea279d2f5864a6fc6eb240323ef2b92a408e11c8472b08189",
"format": 1
},
{
@@ -1845,7 +1768,7 @@
"name": "roles/zabbix_server/README.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d9e5f1ebef97ef13cd79fa70e4d2e1fbbd48090e239a13be019edd2a179f45d0",
+ "chksum_sha256": "434d9e12ff1d20c7f2e1891e2518628eea9f8497502a5032a7f83ea488477665",
"format": 1
},
{
@@ -1859,7 +1782,7 @@
"name": "roles/zabbix_server/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "95107b5a298c2a5733353856c52973332cc89945cbabf376f6b5e62265cfb244",
+ "chksum_sha256": "024b79ba5eb85cb58403e606c0914e5e606a26e085795e7e7bccbf4f57d8ff66",
"format": 1
},
{
@@ -1887,7 +1810,7 @@
"name": "roles/zabbix_server/handlers/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ffb85ad6d8b0d9e5b40d855e11940f1b1907ed58c8345f1d8121d02f4472a70a",
+ "chksum_sha256": "d93e81e28cda85d6a15c386ce28a05c359a1191fe7dfca79bdfbe9e4dd725f0d",
"format": 1
},
{
@@ -1915,49 +1838,49 @@
"name": "roles/zabbix_server/tasks/Debian.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "99fc338cab1bee724ad370677868d5ca78cf401697698fe99862218d138eefd9",
+ "chksum_sha256": "c174231cd483409e026d4b82e987ce3f2e2b30405b71ab15dab333b7c37e2f7c",
"format": 1
},
{
"name": "roles/zabbix_server/tasks/RedHat.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6c15f6cd24f0bcee1131194568127733889d3ed546d68f4f4bef4dfa0575a2cd",
+ "chksum_sha256": "99bc6623e1018b3c5565d97670385a0ff3b205d3b9dccc5da0d3082f05f6f305",
"format": 1
},
{
"name": "roles/zabbix_server/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c6a7a3b01e6eea7d6bf89126d2157e9dca2d7fa0ca0ba24f1defbc0e38364d04",
+ "chksum_sha256": "a56f05203c959669058d2172d90f11dca5bd024c85651a75ecde52db2148f991",
"format": 1
},
{
"name": "roles/zabbix_server/tasks/mysql.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ea1cf201defad2ed9e7e5e8b28e178a762ff283e6c3ef22a7bd59fa6ba7ecd9c",
+ "chksum_sha256": "aa11fd9cfc1662112ed5f321bd06ccde126f65ee7531267c4357f6e82cab540e",
"format": 1
},
{
"name": "roles/zabbix_server/tasks/postgresql.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "21872ed7e12aabd0ea72bca9c68fa1247c370302ea7c4a702f3b102058dae41d",
+ "chksum_sha256": "44146c8e7329cb92aa907a64d7c646700b8125b93dbcbbeb50716ad01f434c53",
"format": 1
},
{
"name": "roles/zabbix_server/tasks/scripts.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ae57630fcbe0bbb4c702a2a173bc0e8f746c5d2ab5ff107074ee86c8329b56d2",
+ "chksum_sha256": "8981bf214f6fddf8fc7a3d771baadeff8a028231fac0eb23c848ed5c2a83152f",
"format": 1
},
{
"name": "roles/zabbix_server/tasks/selinux.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "f2fc0f9f1a0c932873d0095d4ebaeb90cdc7160c7789949c0c1f4e1199e7d2c9",
+ "chksum_sha256": "b2d30030efe386cfb08fc3f45cd4a4c1efc17c41df031f31deaf9d683f4d6a27",
"format": 1
},
{
@@ -1971,7 +1894,7 @@
"name": "roles/zabbix_server/templates/zabbix_server.conf.j2",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "aedb97e7c1166029b2f0078cf1aabc90b2932c658a2b08ad4b14eafcab2a411d",
+ "chksum_sha256": "7f1d839829f4ac53b994c691efbcbcb98615f7dba76af7793248636e209a131b",
"format": 1
},
{
@@ -1985,14 +1908,14 @@
"name": "roles/zabbix_server/vars/Debian.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b2d7348d3930df0cefb747be395295f54adb0ed5920df21f174fadc786b1168a",
+ "chksum_sha256": "67cb0847a5e96afd2b05a9e4db7f8383d6d0376cc4f93db206dc80c7778310eb",
"format": 1
},
{
"name": "roles/zabbix_server/vars/RedHat.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ec10a5fd9114e8c195f4f11344b6e48241fa1a98eb3bff9da0219185d424b9c0",
+ "chksum_sha256": "c27f0472596d51fd438b8d6f1c9b3bb788d7865b0c818d58c1b1456b3ec62185",
"format": 1
},
{
@@ -2003,13 +1926,6 @@
"format": 1
},
{
- "name": "roles/zabbix_server/vars/zabbix.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "78d5ef518d81987451e5e05ba5465a90bfb3471aff4f6ababe8dbbd3e0d8d132",
- "format": 1
- },
- {
"name": "roles/zabbix_server/requirements.yml",
"ftype": "file",
"chksum_type": "sha256",
@@ -2027,7 +1943,7 @@
"name": "roles/zabbix_web/README.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5aad816040102389cc79090e613ff22231337424f20bfe9626d022b153023ac5",
+ "chksum_sha256": "228030e059e30b229a82e7c31b609d5d122d710338557ebd74ee151eda79c0fb",
"format": 1
},
{
@@ -2041,7 +1957,7 @@
"name": "roles/zabbix_web/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "646af635c64aa409be510450ea21b66fac15f000193b2675cb8bba34dc7add9b",
+ "chksum_sha256": "136689b650ad54e8046ca7f1f7f24cc8d528dfcde385b1027f2aa7b64ca3c26c",
"format": 1
},
{
@@ -2055,7 +1971,7 @@
"name": "roles/zabbix_web/handlers/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "17914993fcbae9e8c40f256e0ab37de2f9f858161d578d5aea092fa655491581",
+ "chksum_sha256": "2f4d778c7db1d00c48dc43e5ea74d78746f6669e57b1337d3a784324606f9e6e",
"format": 1
},
{
@@ -2083,70 +1999,42 @@
"name": "roles/zabbix_web/tasks/Debian.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "32b9873fb6312b16ba6af8332db19144f5c02e1f7e8c997302d10fe241f3aa57",
+ "chksum_sha256": "7c7426b9d16b6868f72eea3aa28c390217c51f5ba9aaa9afcf41caffb8072808",
"format": 1
},
{
"name": "roles/zabbix_web/tasks/RedHat.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8abf1ccc3ba445542f0318f1e7473c3d7d82aaab16d1502cdf78def689ed716b",
- "format": 1
- },
- {
- "name": "roles/zabbix_web/tasks/access.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "7949a75447930d99585497abe2dd063b8b309bd1d1215d95458fd8fe7842d491",
+ "chksum_sha256": "b2a875ae0deaf4facd16416db665771c03395e90879c3691e2430cf24e2f7331",
"format": 1
},
{
"name": "roles/zabbix_web/tasks/apache.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8d7c2f668004c83b3244f819a9fe152d2f76cc232719f4b2dc0ab8ba0ae22c2d",
- "format": 1
- },
- {
- "name": "roles/zabbix_web/tasks/apache_Debian.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "fb94333d3a7055e24d6bf7fb9da89dbc294160e8025e7ec902c7168be47b3346",
- "format": 1
- },
- {
- "name": "roles/zabbix_web/tasks/apache_RedHat.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "dae8aa03b819ae47f82db8805c1c4e47c29db5e8f2dba1aead94e74899e231c6",
+ "chksum_sha256": "81ce423aa0f4cd24876a81f452eefac27a1a3a20ea6e56082a3c5bb5e7615864",
"format": 1
},
{
"name": "roles/zabbix_web/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b7ce3a35777bffe7fe7ee0564307b2d6d5c5842c6b8e1e9d4a01d5933b90c83c",
+ "chksum_sha256": "9961406bcd8733eb9a504a8a4d2766148fdcb43ca2d5e27d007e2c041cccc4a5",
"format": 1
},
{
"name": "roles/zabbix_web/tasks/nginx.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b7de6c00cae54176d63d8d21dab85070b22a95cb919dcca711a3588a733054d6",
- "format": 1
- },
- {
- "name": "roles/zabbix_web/tasks/php_Debian.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "135f474e5db359bc75a288ac4fcc76b79af1c804b3b2b8e34ae758c06f395bb9",
+ "chksum_sha256": "0e6cda68ac6b8d16c64770477575119f248aa5933a91b206f8a1468b529459aa",
"format": 1
},
{
"name": "roles/zabbix_web/tasks/selinux.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "cc983ba894c3b7e9759722a13dc20ffa6814306d69a8f8f53003aa87496e5f64",
+ "chksum_sha256": "5b696169bbd552cba7f54fb7bc9f8fba7b885e0d2048cd4c56f2de57a3c560cd",
"format": 1
},
{
@@ -2160,28 +2048,28 @@
"name": "roles/zabbix_web/templates/apache_vhost.conf.j2",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "04ed070405b18a24cd9b8788d1e7ad6c11b6c3f28033056bf4d38d3dc36906f4",
+ "chksum_sha256": "d907bae4235f286ce0f5cf5cb4e0f3fc619741bcc0dc38ec3f6825086eaf5739",
"format": 1
},
{
"name": "roles/zabbix_web/templates/nginx_vhost.conf.j2",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bc02f95677b2d1fce3f74bf8bd778a73a2702256743595551976711333ab0c3e",
+ "chksum_sha256": "4b66f5e157d4d15419a4d3e5e8580b2f50d5413ed092f026902ebed50bb431f4",
"format": 1
},
{
"name": "roles/zabbix_web/templates/php-fpm.conf.j2",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "908ec55fb71d004f7745b4cd1788e005a32c96b0f46cb8295ad8bfa4eb247cc3",
+ "chksum_sha256": "d81d68fe5d62c8199e5d360be16bf1b1f27d72c4a3926d1e45abe720bb458cb8",
"format": 1
},
{
"name": "roles/zabbix_web/templates/zabbix.conf.php.j2",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5cf7a3042220dd33ebc0593d0a2a55d035419768db41fc33b02b0f4226f62715",
+ "chksum_sha256": "75abd8891071e4270a973c4b3fb72323046d577d84d277c41630dafeb06db9a2",
"format": 1
},
{
@@ -2192,94 +2080,17 @@
"format": 1
},
{
- "name": "roles/zabbix_web/vars/Debian-10.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "b22f4fb2ddd44a45a5196bfdc2eb488aa0f20fc50182dad5801fcb7d9100373b",
- "format": 1
- },
- {
- "name": "roles/zabbix_web/vars/Debian-11.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "a80f687d7a145445cc9d3ece5f075047ad0b8419c162dee68d4d7e1d64c97b7c",
- "format": 1
- },
- {
- "name": "roles/zabbix_web/vars/Debian-8.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "329443560941bda266833e38ba4139ac070b477db817db61728ed18817b8131d",
- "format": 1
- },
- {
- "name": "roles/zabbix_web/vars/Debian-9.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "a80f687d7a145445cc9d3ece5f075047ad0b8419c162dee68d4d7e1d64c97b7c",
- "format": 1
- },
- {
"name": "roles/zabbix_web/vars/Debian.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "62372051217390f4891cb03268c9d8e4588e13bed6877a8cc0b88231f6e9ef8a",
- "format": 1
- },
- {
- "name": "roles/zabbix_web/vars/RedHat-7.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "a0083ec5ca4323c00334ef0591d67d036630bc3cbdc6e0301bc8c351eda6e2d0",
- "format": 1
- },
- {
- "name": "roles/zabbix_web/vars/RedHat-8.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "3aab6d6cccbefb155a14f035b05e558dbe9b76a620a15d467351d94c61c8483c",
- "format": 1
- },
- {
- "name": "roles/zabbix_web/vars/RedHat-9.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "f0dc3ae984a19e65ec9b7fbf9b9cdd6236aa15d34997dade35bcb79057807b78",
+ "chksum_sha256": "61d4c2a23a9261eeeb511a5ba6e3e9d2d46856c69a390a4ff9f8fbfaad57ec50",
"format": 1
},
{
"name": "roles/zabbix_web/vars/RedHat.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fbf732fe22f313440135a050db0d865f18fa43dd457b6723eb8e4c116849e5b0",
- "format": 1
- },
- {
- "name": "roles/zabbix_web/vars/Ubuntu-18.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "b22f4fb2ddd44a45a5196bfdc2eb488aa0f20fc50182dad5801fcb7d9100373b",
- "format": 1
- },
- {
- "name": "roles/zabbix_web/vars/Ubuntu-20.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "a80f687d7a145445cc9d3ece5f075047ad0b8419c162dee68d4d7e1d64c97b7c",
- "format": 1
- },
- {
- "name": "roles/zabbix_web/vars/Ubuntu-22.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "0c50f32893fb2fcdec448107ddee75b0c5f600771df5c3e1299d28a705f736c7",
- "format": 1
- },
- {
- "name": "roles/zabbix_web/vars/zabbix.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "a853c154c0da014fc883ed968e2f13c8e6792ffcd104d5e7a41bebc9f8519288",
+ "chksum_sha256": "610b148857b38209584b0810afa2e801a540699be35d46a0ca1cb347fcecf844",
"format": 1
},
{
@@ -2300,14 +2111,14 @@
"name": "scripts/inventory/zabbix.ini",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "be08243c8bdc7c88f8fef16108e10face4d04d03764cb569718a241c181c5515",
+ "chksum_sha256": "f8be31ca0869d4833a65704df06b1f36256203544e19a9507f864280f2d8f2a7",
"format": 1
},
{
"name": "scripts/inventory/zabbix.py",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "dd78405dee6d2fb6c7280691c6feb0b2b26e89987cf58f8ec3c2acc0598a15bb",
+ "chksum_sha256": "7a180e1f289e5762abcfe3f4cd8fc36001d5a96b4a218fdffa0b649c7bde338f",
"format": 1
},
{
@@ -2363,7 +2174,7 @@
"name": "tests/integration/targets/setup_zabbix/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "eaf72c686373517bd17032b53d62728d24f16590591f88d3092d13ef3585ee1b",
+ "chksum_sha256": "0cbad8e6269bc7e51b8907ad540ad42b105a5eb3721d111f04bbc16d78ed3f8a",
"format": 1
},
{
@@ -2398,7 +2209,42 @@
"name": "tests/integration/targets/test_zabbix_action/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ebd7a2249b07d828e4da440a2524c02c8765f424a921e905ead81ef771cd2327",
+ "chksum_sha256": "f32f82c954cda026edf42d5ad382323c5ad47573f2c29346276985217419dace",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/test_zabbix_api_info",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/test_zabbix_api_info/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/test_zabbix_api_info/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "63ae23343a8854777c0e014be5fdd33db6a6b78f96d22a889ad78556dc0ffa81",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/test_zabbix_api_info/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/test_zabbix_api_info/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "ea19033eb14256ef8712af58d65d41d65cc68222dcbfb760accb11a417936b05",
"format": 1
},
{
@@ -2433,14 +2279,14 @@
"name": "tests/integration/targets/test_zabbix_authentication/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "a66e69e3d84f449a4be7d1d5f4eaaa92897b1b85a48f97287bcd09f7dd645395",
+ "chksum_sha256": "87eeea307fd5844bfd04f91bce4987875a874adfed431dd2ab38e866edea44ae",
"format": 1
},
{
"name": "tests/integration/targets/test_zabbix_authentication/tasks/zabbix_authentication_tests.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "60cac0799f832fea3d3ce6dee90ecb51227d4faf9420df902d2a2d033aac850c",
+ "chksum_sha256": "78351492a6846efd7a338e9642687a5cafbd16ea8a14eab665072c2e0c2d89ba",
"format": 1
},
{
@@ -2475,7 +2321,7 @@
"name": "tests/integration/targets/test_zabbix_autoregister/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "27a337939722af1c7eeacad529d54bf69af98fff68d52675e465c353716d166a",
+ "chksum_sha256": "6841293c9119357ac71dc59c70a9fd44efa6dd421ebe94b42ac5f9638da65e96",
"format": 1
},
{
@@ -2510,7 +2356,7 @@
"name": "tests/integration/targets/test_zabbix_discovery_rule/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "32f946e351919a3759ad3b2c32f5b8a1f5fff35ce8591c18eef78dfd9296a3a1",
+ "chksum_sha256": "8d727c86332b13746bb8b77cdd1f01ed882731efd7ab694c9ceb8197200ef2ce",
"format": 1
},
{
@@ -2545,7 +2391,7 @@
"name": "tests/integration/targets/test_zabbix_globalmacro/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "437c3e9253e968a944d82dab70bb0495dff0724c74d5ee2322f2d816d50cf4ea",
+ "chksum_sha256": "000a00d1991875483136e3ae1b25f4e950f5a753a517ba83885ac177a464ac00",
"format": 1
},
{
@@ -2580,7 +2426,56 @@
"name": "tests/integration/targets/test_zabbix_group/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e2712df59c9db85ad1fd37e6a2c7af620d38d06c755d5064db8143c76a1fc870",
+ "chksum_sha256": "5f06ea6c2bce11d9455d97b126705539c5d6bc72e92a9c76ce8f89d08d69ccca",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/test_zabbix_group_events_info",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/test_zabbix_group_events_info/files",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/test_zabbix_group_events_info/files/trigger_testing.json",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "47c19f92b8b79701c2cfdfc0ea58244cde2098f2dc2241285f828c51b39b37c8",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/test_zabbix_group_events_info/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/test_zabbix_group_events_info/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "63ae23343a8854777c0e014be5fdd33db6a6b78f96d22a889ad78556dc0ffa81",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/test_zabbix_group_events_info/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/test_zabbix_group_events_info/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "516670cd486261337e04d2278d6cac450b49ed02333df3f439d489a20207914b",
"format": 1
},
{
@@ -2615,7 +2510,7 @@
"name": "tests/integration/targets/test_zabbix_group_info/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "0782df463b5143e4882d0381761bf73248007f49d22fbf3699e4d046d8903a58",
+ "chksum_sha256": "dea03a83f03e91c687d3872d826b3ea711f43495c821679b40bd3b728405c49b",
"format": 1
},
{
@@ -2650,35 +2545,35 @@
"name": "tests/integration/targets/test_zabbix_host/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2d4ee657d0794ad05e89d7f25cd3ff21e29d4dbc183db05e448d3bb65bfb2145",
+ "chksum_sha256": "de37bc2fb49c071c211dcca967c123f96a29738fa17be9cffd645500e779d335",
"format": 1
},
{
"name": "tests/integration/targets/test_zabbix_host/tasks/zabbix_host_doc.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6bb205e8b50e693df53d03542b086d9072b9bf32b552e57a3fc148593b304e3e",
+ "chksum_sha256": "cc7e8a293774e6588f7d73b88456442f11f19be4c8be0c08c4edddab319eb542",
"format": 1
},
{
"name": "tests/integration/targets/test_zabbix_host/tasks/zabbix_host_setup.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c86cd33bccf27eef9fdf7521774a375d01b59d3faa610c9f5aa7f382aa85fb62",
+ "chksum_sha256": "4923b09121222416ea70a65cd1cafdbc07907bf34da6de98d2547737cd4d54dc",
"format": 1
},
{
"name": "tests/integration/targets/test_zabbix_host/tasks/zabbix_host_teardown.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "46d1b84b5802e4489b5093335da4b04900665b987c6d7c2990918af8cf550dd3",
+ "chksum_sha256": "1be60e6469bed7b8c3dec775d91120b9a8c5257085c89fc6b50e9887fd0af136",
"format": 1
},
{
"name": "tests/integration/targets/test_zabbix_host/tasks/zabbix_host_tests.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "5aaf98c089043b50e8c57cfc965bc059682ab2e12c032c100b2fb40fba0dba43",
+ "chksum_sha256": "10fdc4850cbc5a8c135b6010af276b1f5384d617f746ee3ef001e2f34b3cf289",
"format": 1
},
{
@@ -2713,7 +2608,7 @@
"name": "tests/integration/targets/test_zabbix_host_info/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "2f47878f8a650cb631f463d86b7cd9fcd34b8c3b00980157929047102d43a0d9",
+ "chksum_sha256": "4cf9e484bf6c13686b1bef5e8c0aed88f5d0216ccc0e5ba4c9914e68f38dc648",
"format": 1
},
{
@@ -2748,7 +2643,7 @@
"name": "tests/integration/targets/test_zabbix_hostmacro/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "836f37cd9c40daee414510261d881e43f31187b2a84c101f03f3e5e045fb4a9b",
+ "chksum_sha256": "f9fdc04e680cdd72015b0e1940926443f7ffcc55731e1b897bf4c99da56ef8b3",
"format": 1
},
{
@@ -2783,7 +2678,7 @@
"name": "tests/integration/targets/test_zabbix_housekeeping/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "bca231a73ba8b7b845c263b641f3deadbc059d35aa5a56ace74a7ca51d438a71",
+ "chksum_sha256": "c2a203ee87bffecd4ec3492c023e8ca9650fe9876019508682d6e802be5efb2b",
"format": 1
},
{
@@ -2818,7 +2713,7 @@
"name": "tests/integration/targets/test_zabbix_maintenance/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "59b1762e359119c49345f90512cf419f12d6108ce81672005620b54848897585",
+ "chksum_sha256": "1e3c539311dc4f4c55b85931338f0693121ff1814cbc4d199fe02a689c5d298b",
"format": 1
},
{
@@ -2853,7 +2748,7 @@
"name": "tests/integration/targets/test_zabbix_mediatype/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "56ea6ef6bc6ed6ad2d03ea203999b1faa60745c20d1a359434c7b564a138620b",
+ "chksum_sha256": "c7a4f5cecfef03f695f94a47e7c663a3acb582757df2951e8af77279b2a2e797",
"format": 1
},
{
@@ -2888,7 +2783,7 @@
"name": "tests/integration/targets/test_zabbix_module_defaults_group/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d00ba227df2acf39ebabd71a7126ab8ccb8344f0b200cd0938a3aaad944f06dc",
+ "chksum_sha256": "1d0c912b6630f73d38bba77d03f5967a7cc8bdc8c512f98d75aa2b88e76ccfb1",
"format": 1
},
{
@@ -2923,7 +2818,7 @@
"name": "tests/integration/targets/test_zabbix_proxy/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "d3fc86b4ac8240ea44fdb3225d5c97b4b45dc55603fe3116a490717fb78b2c95",
+ "chksum_sha256": "e3996b91dc22e9c5178211f3a5767686b6a14e706531c9bf0b1346ef202d2b69",
"format": 1
},
{
@@ -2958,42 +2853,42 @@
"name": "tests/integration/targets/test_zabbix_proxy_info/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "c0069278d407546960e2fbabb73aba0481ec28c0353a6218c3c3c12a3cbc9d61",
+ "chksum_sha256": "efc13acdf9c15fd62232c8880d48a43349469338176fcbee18ff71c2c0bafbfe",
"format": 1
},
{
- "name": "tests/integration/targets/test_zabbix_screen",
+ "name": "tests/integration/targets/test_zabbix_regexp",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/test_zabbix_screen/meta",
+ "name": "tests/integration/targets/test_zabbix_regexp/meta",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/test_zabbix_screen/meta/main.yml",
+ "name": "tests/integration/targets/test_zabbix_regexp/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "63ae23343a8854777c0e014be5fdd33db6a6b78f96d22a889ad78556dc0ffa81",
"format": 1
},
{
- "name": "tests/integration/targets/test_zabbix_screen/tasks",
+ "name": "tests/integration/targets/test_zabbix_regexp/tasks",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/test_zabbix_screen/tasks/main.yml",
+ "name": "tests/integration/targets/test_zabbix_regexp/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "67b46ec9773624ff4840804a82a4e39cc039e22c7e52186e5c24d82845b5d8f4",
+ "chksum_sha256": "940deab9a2f7dde970db42566da1c543d1873bfe0c38449d3add7cf10b331119",
"format": 1
},
{
@@ -3028,7 +2923,7 @@
"name": "tests/integration/targets/test_zabbix_script/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "88ce48d121b448cc5d7104eb887fc5ce437409b29d8bbf66e0423355af8a9e73",
+ "chksum_sha256": "093d0f5afd1351f69e87e65474f6ab1742faa58d0c09a14d97b45a7e572027f7",
"format": 1
},
{
@@ -3077,7 +2972,42 @@
"name": "tests/integration/targets/test_zabbix_service/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "b8c83f814b46f17b42353ad57c506249df2f0f9a84d5050efca3bc83e754df4b",
+ "chksum_sha256": "6fc45d5e053c66aae6ac99624189d0350535dd689519cf4da65401ce99d4fd1c",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/test_zabbix_settings",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/test_zabbix_settings/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/test_zabbix_settings/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "63ae23343a8854777c0e014be5fdd33db6a6b78f96d22a889ad78556dc0ffa81",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/test_zabbix_settings/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/test_zabbix_settings/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "3beca76d07dbe9c59e1b4ab8bf3758adca1a79dc7b2a8b1d1de01882255f701c",
"format": 1
},
{
@@ -3130,13 +3060,6 @@
"format": 1
},
{
- "name": "tests/integration/targets/test_zabbix_template/files/template2_50_lower.xml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "3f17ebb04e5f380f8486ca6444bfe7269fb70275c7aa5e1110724e8f37289b5a",
- "format": 1
- },
- {
"name": "tests/integration/targets/test_zabbix_template/files/template3-changed_54_higher.json",
"ftype": "file",
"chksum_type": "sha256",
@@ -3179,24 +3102,10 @@
"format": 1
},
{
- "name": "tests/integration/targets/test_zabbix_template/tasks/import_54_higher.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "b022be250062c840f5f6bc6b60d90d52c08d3b4f85a34f0f6f48153300e04b80",
- "format": 1
- },
- {
- "name": "tests/integration/targets/test_zabbix_template/tasks/import_54_lower.yml",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "da7627d6dfe9cbc0230ee0609493b9783198a7df59208ededec1831db8476e26",
- "format": 1
- },
- {
"name": "tests/integration/targets/test_zabbix_template/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ecd0bb5df803e40f683226ae38126faf7f64cb140e792283c658854a166fc211",
+ "chksum_sha256": "235eb7982d8a11e0e6fd68b53693d49daa89db486f91230e74497f75a0f8d2dc",
"format": 1
},
{
@@ -3245,56 +3154,112 @@
"name": "tests/integration/targets/test_zabbix_template_info/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "fcbb64754d966c9d86a7d87260231caa3c53e2a55901f3b3bde72aca5cd751a2",
+ "chksum_sha256": "5ba11ff3f667dfff0cd0bcf40fab0798d220bdf124d4d32ecaa361d8e148ad6f",
"format": 1
},
{
- "name": "tests/integration/targets/test_zabbix_user",
+ "name": "tests/integration/targets/test_zabbix_templategroup",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/test_zabbix_user/meta",
+ "name": "tests/integration/targets/test_zabbix_templategroup/meta",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/test_zabbix_user/meta/main.yml",
+ "name": "tests/integration/targets/test_zabbix_templategroup/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "63ae23343a8854777c0e014be5fdd33db6a6b78f96d22a889ad78556dc0ffa81",
"format": 1
},
{
- "name": "tests/integration/targets/test_zabbix_user/tasks",
+ "name": "tests/integration/targets/test_zabbix_templategroup/tasks",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
- "name": "tests/integration/targets/test_zabbix_user/tasks/for_zabbix_50_lower.yml",
+ "name": "tests/integration/targets/test_zabbix_templategroup/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "960a32c864695d7b54d7ca3ebbd6362f75f68f743814c807daa6c3a25d6ac1f3",
+ "chksum_sha256": "662a2a5ceb86492f24dcc84b4a1574458f7dc91d6fccce89a5332e10b598c357",
"format": 1
},
{
- "name": "tests/integration/targets/test_zabbix_user/tasks/for_zabbix_54_higher.yml",
+ "name": "tests/integration/targets/test_zabbix_token",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/test_zabbix_token/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/test_zabbix_token/meta/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "8429bc7fe7d6eb2c2995bf0ba11f86a5a372b8f69d85e2c6e201c3fb7e89ef2d",
+ "chksum_sha256": "63ae23343a8854777c0e014be5fdd33db6a6b78f96d22a889ad78556dc0ffa81",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/test_zabbix_token/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/test_zabbix_token/tasks/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "2e599a1030312d0e3f6d1ee00d11f7ab37d01e027d72920af79217d850ef5d62",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/test_zabbix_user",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/test_zabbix_user/meta",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/test_zabbix_user/meta/main.yml",
+ "ftype": "file",
+ "chksum_type": "sha256",
+ "chksum_sha256": "63ae23343a8854777c0e014be5fdd33db6a6b78f96d22a889ad78556dc0ffa81",
+ "format": 1
+ },
+ {
+ "name": "tests/integration/targets/test_zabbix_user/tasks",
+ "ftype": "dir",
+ "chksum_type": null,
+ "chksum_sha256": null,
"format": 1
},
{
"name": "tests/integration/targets/test_zabbix_user/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "4d358b1fcd45a8d856b9cc09907e6b9067be79fd28b06d0b5f405858b8d50432",
+ "chksum_sha256": "6498f5e2a9997a379df9ea0cffd014d0ffe641c97e100d8131caa212bf17357a",
"format": 1
},
{
@@ -3329,14 +3294,14 @@
"name": "tests/integration/targets/test_zabbix_user_directory/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "afa7e354768d1130b16aed9d20fa8d0a380862b09aeb8d2b2a1dfe26da7c459b",
+ "chksum_sha256": "c21b05f92bd9124c347dda31aba1c1d3fa83bb913d143b5f9559bc21dfdad659",
"format": 1
},
{
"name": "tests/integration/targets/test_zabbix_user_directory/tasks/zabbix_user_directory_tests.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "59b6b651e26c5446ee51ca5d8a13303e984f3e07cb48c1582191c60c3fbf42ca",
+ "chksum_sha256": "4e00e6a07ca59e6c3069ee133736fa73349ceb15e7068fa0f309ed98683ab05c",
"format": 1
},
{
@@ -3371,7 +3336,7 @@
"name": "tests/integration/targets/test_zabbix_user_info/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "6ee6a2f0426d77871f9ca6050be5199982f6207777f29d978802ea308d52d32a",
+ "chksum_sha256": "4ed2dfa6079ec2bb75e8dae4428fa9782e712c334669b3d7d590b7495e77513e",
"format": 1
},
{
@@ -3406,7 +3371,7 @@
"name": "tests/integration/targets/test_zabbix_user_role/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "291ef542c12c0fc5733ed61244f28fd19de5c5243afb3f3e8633a0311d93cbf9",
+ "chksum_sha256": "a62abe29a82864a1553a383c0be1df01739da70fc3818ca5ad005eed733a5dc3",
"format": 1
},
{
@@ -3441,63 +3406,7 @@
"name": "tests/integration/targets/test_zabbix_usergroup/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "701e889a652a7969c946234c571539d820bcd13fc7011650e858e42bcb0e8f09",
- "format": 1
- },
- {
- "name": "tests/sanity",
- "ftype": "dir",
- "chksum_type": null,
- "chksum_sha256": null,
- "format": 1
- },
- {
- "name": "tests/sanity/ignore-2.10.txt",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "3fc63c84b6cef2e284d1e5aaa1c4f564e6b27d7ed7961626cbbb8495bdc105b3",
- "format": 1
- },
- {
- "name": "tests/sanity/ignore-2.11.txt",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "3fc63c84b6cef2e284d1e5aaa1c4f564e6b27d7ed7961626cbbb8495bdc105b3",
- "format": 1
- },
- {
- "name": "tests/sanity/ignore-2.12.txt",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "4ba3e638c5c97cf697071ccf1c64d3e1f44ca092e9c3a25f85e9af032edd679d",
- "format": 1
- },
- {
- "name": "tests/sanity/ignore-2.13.txt",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "4ba3e638c5c97cf697071ccf1c64d3e1f44ca092e9c3a25f85e9af032edd679d",
- "format": 1
- },
- {
- "name": "tests/sanity/ignore-2.14.txt",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "4ba3e638c5c97cf697071ccf1c64d3e1f44ca092e9c3a25f85e9af032edd679d",
- "format": 1
- },
- {
- "name": "tests/sanity/ignore-2.15.txt",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "4ba3e638c5c97cf697071ccf1c64d3e1f44ca092e9c3a25f85e9af032edd679d",
- "format": 1
- },
- {
- "name": "tests/sanity/ignore-2.9.txt",
- "ftype": "file",
- "chksum_type": "sha256",
- "chksum_sha256": "b4e32eab851387385a480a7d46bf2d81335209f52cf1c671b2ea98a452a4f3d2",
+ "chksum_sha256": "2a5b4a1177a9dee238d5a1996912340563a30a4ebfc347e86572cfa4dde31170",
"format": 1
},
{
@@ -3511,7 +3420,7 @@
"name": ".gitignore",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "1a10d9ab655f99e50b057fe85f896dae304c1bcb8e59c793cc88c61321e2713f",
+ "chksum_sha256": "d59ffed224790089369e13daac9f696d47de6e02428ee81f01c491ad4ace9d82",
"format": 1
},
{
@@ -3525,7 +3434,7 @@
"name": "CHANGELOG.rst",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "ec873a72b857853deae0579634953269e2ebe7b8ff95522446a8b4172ecf7123",
+ "chksum_sha256": "f963b76b08f69f8aac6b8daf732d95ce00e1670316f7e8f7bcb674f8d2e3aa6c",
"format": 1
},
{
@@ -3539,7 +3448,7 @@
"name": "CONTRIBUTING.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "51891b42027e0b07b423a132022fb03a93a696bc00f1347af29754fb545a8a72",
+ "chksum_sha256": "c2b1b3f7d408b098332b41c93a6a57bbd3ab05cad66b0f94b5245a908af1e155",
"format": 1
},
{
@@ -3567,7 +3476,7 @@
"name": "README.md",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e59ef9030664aba9bfff75bee58c59a9f33e9154b988508b7a1d1a4542d4d0fa",
+ "chksum_sha256": "e47ca851f19b23497aa052424107b157400ef0d16cc745b1151fcff933ca2b86",
"format": 1
},
{
diff --git a/ansible_collections/community/zabbix/MANIFEST.json b/ansible_collections/community/zabbix/MANIFEST.json
index a54e80845..37c48a609 100644
--- a/ansible_collections/community/zabbix/MANIFEST.json
+++ b/ansible_collections/community/zabbix/MANIFEST.json
@@ -2,11 +2,13 @@
"collection_info": {
"namespace": "community",
"name": "zabbix",
- "version": "1.9.3",
+ "version": "2.3.1",
"authors": [
"Dusan Matejka (@D3DeFi)",
"sky-joker (@sky-joker)",
- "Werner Dijkerman (@dj-wasabi)"
+ "Werner Dijkerman (@dj-wasabi)",
+ "Troy Ward (@pyrodie18)",
+ "Evgeny Yurchenko (@BGmot)"
],
"readme": "README.md",
"tags": [
@@ -18,7 +20,7 @@
"license_file": "LICENSE",
"dependencies": {
"ansible.windows": "*",
- "ansible.netcommon": "*",
+ "ansible.netcommon": ">=3.1.1",
"ansible.posix": "*",
"community.general": "*",
"community.mysql": "*",
@@ -33,7 +35,7 @@
"name": "FILES.json",
"ftype": "file",
"chksum_type": "sha256",
- "chksum_sha256": "e476cd027a2477b8d6417c251a409f4c2b040c9ee9a78ce6facf099912452868",
+ "chksum_sha256": "ed1fe1d72e38eb5978be766233f7389e444c2dcaded74877d323c41ac9712a46",
"format": 1
},
"format": 1
diff --git a/ansible_collections/community/zabbix/README.md b/ansible_collections/community/zabbix/README.md
index ca0f79717..be268fc4a 100644
--- a/ansible_collections/community/zabbix/README.md
+++ b/ansible_collections/community/zabbix/README.md
@@ -43,6 +43,7 @@ Click on the name of a plugin or module to view that content's documentation:
- [zabbix_discovery_rule](https://docs.ansible.com/ansible/latest/collections/community/zabbix/zabbix_discovery_rule_module.html)
- [zabbix_globalmacro](https://docs.ansible.com/ansible/latest/collections/community/zabbix/zabbix_globalmacro_module.html)
- [zabbix_group_info](https://docs.ansible.com/ansible/latest/collections/community/zabbix/zabbix_group_info_module.html)
+ - [zabbix_group_events_info](https://docs.ansible.com/ansible/latest/collections/community/zabbix/zabbix_group_events_info_module.html)
- [zabbix_group](https://docs.ansible.com/ansible/latest/collections/community/zabbix/zabbix_group_module.html)
- [zabbix_host_events_info](https://docs.ansible.com/ansible/latest/collections/community/zabbix/zabbix_host_events_info_module.html)
- [zabbix_host_info](https://docs.ansible.com/ansible/latest/collections/community/zabbix/zabbix_host_info_module.html)
@@ -80,9 +81,6 @@ This is especially important for some of the Zabbix roles that require you to **
For the majority of modules, however, you can get away with just:
-```bash
-pip install zabbix-api
-```
#### Ansible 2.10 and higher
With the release of Ansible 2.10, modules have been moved into collections. With the exception of ansible.builtin modules, this means additonal collections must be installed in order to use modules such as seboolean (now ansible.posix.seboolean). The following collections are now frequently required: `ansible.posix` and `community.general`. Installing the collections:
@@ -106,7 +104,7 @@ You can also include it in a `requirements.yml` file along with other required c
---
collections:
- name: community.zabbix
- version: 1.9.3
+ version: 2.3.1
- name: ansible.posix
version: 1.3.0
- name: community.general
@@ -133,7 +131,7 @@ To use a module or role from this collection, reference them with their Fully Qu
...
- name: If Zabbix WebUI runs on non-default (zabbix) path, e.g. http://<FQDN>/zabbixeu
- set_fact:
+ ansible.builtin.set_fact:
ansible_zabbix_url_path: 'zabbixeu'
- name: Using Zabbix collection to manage Zabbix Server's elements with username/password
@@ -206,7 +204,7 @@ Or you include collection name `community.zabbix` in the playbook's `collections
ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895
tasks:
- name: Ensure host is monitored by Zabbix
- zabbix_host:
+ community.zabbix.zabbix_host:
...
```
@@ -220,8 +218,6 @@ zabbix_api_http_password: "password"
Main priority is to support Zabbix releases which have official full support from Zabbix LLC. Please checkout the versions at [Zabbix Life Cycle & Release Policy](https://www.zabbix.com/life_cycle_and_release_policy) page.
-> We aim to cover at least two LTS releases. For example, currently we support LTS 4.0 + 5.0 and with LTS 6.0 we will drop 4.0. But we do our best to also include the latest point releases - for example currently this is 5.4 which should be supperseeded by 6.2 then.
-
Support for Zabbix LTS versions will be dropped with Major releases of the collection and mostly affect modules. Each role is following its unique support matrix. You should always consult documentation of roles in *docs/* directory.
If you find any inconsistencies with the version of Zabbix you are using, feel free to open a pull request or an issue and we will try to address it as soon as possible. In case of pull requests, please make sure that your changes will not break any existing functionality for currently supported Zabbix releases.
diff --git a/ansible_collections/community/zabbix/changelogs/.plugin-cache.yaml b/ansible_collections/community/zabbix/changelogs/.plugin-cache.yaml
index afdd4fd6c..9ea52adc2 100644
--- a/ansible_collections/community/zabbix/changelogs/.plugin-cache.yaml
+++ b/ansible_collections/community/zabbix/changelogs/.plugin-cache.yaml
@@ -1,10 +1,12 @@
-objects: {}
+objects:
+ role: {}
plugins:
become: {}
cache: {}
callback: {}
cliconf: {}
connection: {}
+ filter: {}
httpapi:
zabbix:
description: HttpApi Plugin for Zabbix
@@ -22,6 +24,11 @@ plugins:
name: zabbix_action
namespace: ''
version_added: null
+ zabbix_api_info:
+ description: Retrieve Zabbix API info
+ name: zabbix_api_info
+ namespace: ''
+ version_added: 2.1.0
zabbix_authentication:
description: Update Zabbix authentication
name: zabbix_authentication
@@ -47,6 +54,11 @@ plugins:
name: zabbix_group
namespace: ''
version_added: null
+ zabbix_group_events_info:
+ description: Get all triggers about a Zabbix group
+ name: zabbix_group_events_info
+ namespace: ''
+ version_added: null
zabbix_group_info:
description: Gather information about Zabbix hostgroup
name: zabbix_group_info
@@ -102,11 +114,11 @@ plugins:
name: zabbix_proxy_info
namespace: ''
version_added: 1.5.0
- zabbix_screen:
- description: Create/update/delete Zabbix screens
- name: zabbix_screen
+ zabbix_regexp:
+ description: Create/update/delete Zabbix regular expression
+ name: zabbix_regexp
namespace: ''
- version_added: null
+ version_added: 2.1.0
zabbix_script:
description: Create/update/delete Zabbix scripts
name: zabbix_script
@@ -117,8 +129,13 @@ plugins:
name: zabbix_service
namespace: ''
version_added: null
+ zabbix_settings:
+ description: Update Zabbix global settings.
+ name: zabbix_settings
+ namespace: ''
+ version_added: 2.1.0
zabbix_template:
- description: Create/update/delete/dump Zabbix template
+ description: Create/update/delete Zabbix template
name: zabbix_template
namespace: ''
version_added: null
@@ -127,6 +144,16 @@ plugins:
name: zabbix_template_info
namespace: ''
version_added: null
+ zabbix_templategroup:
+ description: Create/delete Zabbix template groups
+ name: zabbix_templategroup
+ namespace: ''
+ version_added: null
+ zabbix_token:
+ description: Create/Update/Generate/Delete Zabbix token.
+ name: zabbix_token
+ namespace: ''
+ version_added: 2.1.0
zabbix_user:
description: Create/update/delete Zabbix users
name: zabbix_user
@@ -160,5 +187,6 @@ plugins:
netconf: {}
shell: {}
strategy: {}
+ test: {}
vars: {}
-version: 1.9.3
+version: 2.3.1
diff --git a/ansible_collections/community/zabbix/changelogs/changelog.yaml b/ansible_collections/community/zabbix/changelogs/changelog.yaml
index dc62a39eb..600e0ab78 100644
--- a/ansible_collections/community/zabbix/changelogs/changelog.yaml
+++ b/ansible_collections/community/zabbix/changelogs/changelog.yaml
@@ -876,3 +876,219 @@ releases:
- zabbix_user_media_mailto.yml
- zabbix_user_sendto.yaml
release_date: '2023-04-03'
+ 2.0.0:
+ changes:
+ breaking_changes:
+ - agent role - removed support for Darwin, Amazon, Fedora, XCP-ng, Suse, Mint,
+ and Sangoma operating systems
+ - agent role - removed support for zabbix_create_host and replaced it with zabbix_agent_host_state
+ - agent role - removed support for zabbix_create_hostgroup and replaced it with
+ zabbix_agent_hostgroups_state
+ - agent role - removed support for zabbix_http_password, zabbix_api_http_password,
+ zabbix_api_pass, and zabbix_api_login_pass and replaced it with zabbix_api_login_pass
+ - agent role - removed support for zabbix_http_user, zabbix_api_http_user, zabbix_api_user,
+ and zabbix_api_login_user and replaced it with zabbix_api_login_user
+ - agent role - removed support for zabbix_inventory_mode and replaced it with
+ zabbix_agent_inventory_mode
+ - agent role - removed support for zabbix_link_templates adn replaced it with
+ zabbix_agent_link_templates
+ - agent role - removed support for zabbix_macros and replaced it with zabbix_agent_macros
+ - agent role - removed support for zabbix_proxy and replaced it with zabbix_agent_proxy
+ - agent role - removed support for zabbix_update_host and replaced it with zabbix_agent_host_update
+ - all modules - dropped support of Zabbix versions < 6.0
+ - all roles - removed support for the zabbix_version variable.
+ - all roles - removed support for all versions of Zabbix < 6.0.
+ - all roles - removed support for installation from epel and non-standard repositories
+ - dropped support of zabbix-api to make REST API calls to Zabbix
+ - proxy role - removed support for zabbix_database_creation and replaced it
+ with zabbix_proxy_database_creation
+ - proxy role - removed support for zabbix_database_sqlload and replaced it
+ with zabbix_proxy_database_sqlload
+ - proxy role - removed support for zabbix_selinux and replaced it with zabbix_proxy_selinux
+ - server role - removed support for zabbix_server_mysql_login_password and replaced
+ with zabbix_server_dbpassword
+ - server role - removed support for zabbix_server_mysql_login_user and replaced
+ with zabbix_server_dbuser
+ - stopped supporting Ansible < 2.12
+ - stopped supporting Python < 3.9
+ - zabbix_action - message parameter renamed to op_message
+ - zabbix_group_facts module - removed in favour of zabbix_group_info
+ - zabbix_host_facts module - removed in favour of zabbix_host_info
+ minor_changes:
+ - Replaced usage of deprecated apt key management in Debian based distros -
+ See https://wiki.debian.org/DebianRepository/UseThirdParty
+ - Standardized tags across all roles.
+ - Updated all roles to default to version 6.4 for install.
+ - all roles - removed unused variables from defaults
+ - all roles - standardized testing matrix to check all supported versions and
+ operating systems.
+ - all roles - temporarily disable epel repo on zabbix installation tasks
+ - all roles - updated documentation.
+ - inventory plugin - switched from using zabbix-api to custom implementation
+ adding authentication with tokens
+ - inventory script - re-coded to stop using zabbix-api. API tokens support added.
+ - web role - removed support for htpasswd
+ removed_features:
+ - agent role - removed support to configure firewall
+ - web role - removed installation of apache, debian, and php
+ fragments:
+ - 2_0_update.yml
+ - 941_github_runner.yml
+ - 963-drop-zabbix-api.yml
+ - 964_tag_cleanup.yml
+ - 969_replace_apt_key.yml
+ - 976_old_zabbix_versions_removal.yml
+ - default_ver.yml
+ - inventory_script.yml
+ - python-ansible.yml
+ release_date: '2023-05-04'
+ 2.0.1:
+ changes:
+ bugfixes:
+ - Proxy and Agent Roles - Added `zabbix_api_use_ssl` variable to allow secure
+ API connections
+ - Web Role - Added defaults and documentation for `zabbix_apache_custom_includes`
+ - agent - Handled undefined variable error for Windows default versions
+ - all roles - Added option to selectively disable a repo on Redhat installs
+ fragments:
+ - 986.yml
+ - 990.yml
+ - api_ssl.yml
+ - disable_repo.yml
+ release_date: '2023-05-26'
+ 2.1.0:
+ changes:
+ bugfixes:
+ - agent role - Added missing become statement to allow run to role as nonroot
+ - zabbix_host module - fix updating hosts that were discovered via LLD
+ - zabbix_proxy role - failed at version validation. Fix adds cast of zabbix_proxy_version
+ to float, similarly to the other roles.
+ - zabbix_proxy role - undefined vars at updating proxy definition. Fix adds
+ null defaults for zabbix_proxy_tlsaccept and zabbix_proxy_tlsconnect.
+ - zabbix_web role - removed 'ssl on;' nginx configuration, which is no longer
+ supported since nginx version 1.25.1.
+ minor_changes:
+ - Multiple Roles - Replaced depricated 'include' statements with 'include_tasks'
+ - Update action_groups variable in runtime.yml
+ - all roles - Added support for Debian 12 (Bookworm)
+ - all roles - Delete gpg ids variable.
+ - all roles - Modified to allow a non-root user to run the role.
+ - all roles - Updated testing to account for the correct version of Zabbix
+ - zabbix_hostmacro module - Add description property for Host macro creation/update.
+ Allow to set/update description of Zabbix host macros.
+ - zabbix_proxy - Added installation of PyMySQL pip package
+ - zabbix_proxy - Modified installation of Centos 7 MySQL client
+ - zabbix_proxy - Standardized MySQL client installed on Debian and Ubuntu
+ - zabbix_regexp module added
+ - zabbix_settings module added
+ - zabbix_token module added
+ fragments:
+ - 1025-delete_vars_zabbix.yml
+ - 1029-update_action_groups.yml
+ - 732-zabbix-regexp.yml
+ - 991-zabbix-token.yml
+ - 993-zabbix-settings.yml
+ - agent_become.yml
+ - debian12.yml
+ - discovered_hosts_update.yml
+ - hostmacro_modules.yml
+ - include_tasks.yml
+ - missing.yml
+ - nginx_ssl_fix.yml
+ - non_root.yml
+ - proxy_role_fix.yml
+ modules:
+ - description: Create/update/delete Zabbix regular expression
+ name: zabbix_regexp
+ namespace: ''
+ - description: Update Zabbix global settings.
+ name: zabbix_settings
+ namespace: ''
+ - description: Create/Update/Generate/Delete Zabbix token.
+ name: zabbix_token
+ namespace: ''
+ release_date: '2023-06-01'
+ 2.2.0:
+ changes:
+ bugfixes:
+ - zabbix_inventory - fixed handeling of add_zabbix_groups option
+ - zabbix_template - fix template export when template's content has "error"
+ word
+ - zabbix_web role - fix variable naming issues (undefined) to zabbix_web_version
+ and zabbix_web_apt_repository
+ minor_changes:
+ - Added zabbix_group_events_info module
+ - action module - Added notify_if_canceled property
+ - agent and proxy roles - Set default `zabbix_api_server_port` to 80 or 443
+ based on `zabbix_api_use_ssl`
+ - agent role - Removed duplicative Windows agent task
+ - agent role - Standardized default yum priority to 99
+ - all roles - Re-added ability to override Debian repo source
+ - all roles - Updated Debian repository format to 822 standard
+ - various - updated testing modules
+ - various - updated to fully qualified module names
+ - zabbix agent - Added capability to add additional configuration includes
+ - zabbix_api_info module added
+ - zabbix_user module - add current_passwd optional parameter to enable password
+ updating of the currently logged in user (https://www.zabbix.com/documentation/6.4/en/manual/api/reference/user/update)
+ fragments:
+ - 1058-zabbix_template_corner_case.yml
+ - 1081_fqmn.yml
+ - 733-zabbix-api_info.yml
+ - 921-action_notify_if_cancled.yml
+ - additional_includes.yml
+ - api-port.yml
+ - current_passwd_user_module.yml
+ - deb822.yml
+ - duplicate-windows-agent.yml
+ - module_group_events_info.yml
+ - web_role_vars_fix.yml
+ - yum-priority.yml
+ release_date: '2023-10-06'
+ 2.3.0:
+ changes:
+ bugfixes:
+ - api module - Fixed certificiate errors
+ - proxy and server roles - Defaulted location of fping and fping6 based on OS.
+ - proxy role - Removed requirement for mysql group definition.
+ - server role - typo in configuration var StasAllowedIP to StatsAllowedIP
+ - zabbix-{agent, javagateway, proxy, server, web} - support raspberry pi without
+ repository url specification
+ minor_changes:
+ - api_requests - Handled error from depricated CertificateError class
+ - multiple roles - Removed unneeded Apt Clean commands.
+ - proxy role - Updated MariaDB version for Centos 7 to 10.11
+ - zabbix web - Allowed the independent configuration of php-fpm without creating
+ vhost.
+ - zabbix_host_info - added ability to get all the hosts configured in Zabbix
+ - zabbix_proxy role - Add variable zabbix_proxy_dbpassword_hash_method to control
+ whether you want postgresql user password to be hashed with md5 or want to
+ use db default. When zabbix_proxy_dbpassword_hash_method is set to anything
+ other than md5 then do not hash the password with md5 so you could use postgresql
+ scram-sha-256 hashing method.
+ - zabbix_server role - Add variable zabbix_server_dbpassword_hash_method to
+ control whether you want postgresql user password to be hashed with md5 or
+ want to use db default. When zabbix_server_dbpassword_hash_method is set to
+ anything other than md5 then do not hash the password with md5 so you could
+ use postgresql scram-sha-256 hashing method.
+ - zabbix_templategroup module added
+ fragments:
+ - 1134.yml
+ - 1136.yml
+ - 1142.yml
+ - fping.yml
+ - host_info_all_hosts.yml
+ - php_fpm_config.yml
+ - pr_1104.yml
+ - pr_647.yml
+ - proxy_mysql.yml
+ - pymysql.yml
+ - raspberrypi.yml
+ release_date: '2024-01-02'
+ 2.3.1:
+ changes:
+ bugfixes:
+ - Avoid to update user-directory configuration in dry run.
+ fragments:
+ - 1156-bugfix_zabbix_user_directory_dryrun.yml
+ release_date: '2024-01-10'
diff --git a/ansible_collections/community/zabbix/changelogs/roles_zabbix64.yml b/ansible_collections/community/zabbix/changelogs/roles_zabbix64.yml
deleted file mode 100644
index d9b8eb397..000000000
--- a/ansible_collections/community/zabbix/changelogs/roles_zabbix64.yml
+++ /dev/null
@@ -1,2 +0,0 @@
-minor_changes:
- - all roles - updated to support Zabbix 6.4.
diff --git a/ansible_collections/community/zabbix/docs/PUBLISHING_TO_GALAXY.md b/ansible_collections/community/zabbix/docs/PUBLISHING_TO_GALAXY.md
index 7258bf6c8..7272f1006 100644
--- a/ansible_collections/community/zabbix/docs/PUBLISHING_TO_GALAXY.md
+++ b/ansible_collections/community/zabbix/docs/PUBLISHING_TO_GALAXY.md
@@ -26,16 +26,19 @@
git push origin X.Y.Z
```
-2. Create new Release pointing to new X.Y.Z tag https://github.com/ansible-collections/community.zabbix/releases
+2. All community.* collections are usually published by Zuul, which works by you having to push a tag, and Zuul will build the collection from that tag (with the version in galaxy.yml set to the tag's version) and publish it. It's usually a good idea to take a look at [Zuul](https://ansible.softwarefactory-project.io/zuul/status) when pushing a tag and watch the release process to see whether it succeeds or not (and afterwards check on [Galaxy](https://galaxy.ansible.com/community/zabbix) whether the newest version shows up - note that it can make a few seconds after publishing finished until it actually shows up; that's new with the new Galaxy).
-Additional manual steps are required when automatic publish to Ansible Galaxy is not enabled in the repository. This
-requires a user who has access to the `community.zabbix` namespace on Ansible Galaxy to publish the build artifact.
+ If there is an error in building and it seems to be on Zuul side, the best thing is to re-push the tag to trigger the publish step another time. For that, assuming the remote for github.com/ansible-collections/community.zabbix is called upstream, you can do
-3. Run the following commands to build and release the new version on Galaxy:
- ```
- ansible-galaxy collection build
- ansible-galaxy collection publish ./community-zabbix-$VERSION_HERE.tar.gz
- ```
+ ```
+ git push upstream :2.3.0 # to delete the tag
+ git push --tags upstream # to re-push all tags
+ ```
+ That should delete and re-create the tag, and thus trigger Zuul again to publish the collection.
+
+3. If still having problems in step 2. then create a post in "Get Help" section of [Ansible forum](https://forum.ansible.com/c/help/6/none) so somebody from admins can take a look and see/fix why new version has not been published to Galaxy (e.g. https://forum.ansible.com/t/access-to-collection/2295/4).
+
+4. Create new Release pointing to new X.Y.Z tag https://github.com/ansible-collections/community.zabbix/releases
+
-After the version is published, verify it exists on the [Zabbix Collection Galaxy page](https://galaxy.ansible.com/community/zabbix).
diff --git a/ansible_collections/community/zabbix/docs/UPGRADE.md b/ansible_collections/community/zabbix/docs/UPGRADE.md
deleted file mode 100644
index 7784f5842..000000000
--- a/ansible_collections/community/zabbix/docs/UPGRADE.md
+++ /dev/null
@@ -1,194 +0,0 @@
-__Upgrade__
-
-Table of content
-
-- [1.0.0](#100)
- * [Roles](#roles)
- + [Proxy](#proxy)
- + [Java Gateway](#java-gateway)
-- [0.2.0](#020)
- * [Roles](#roles-1)
- + [Agent](#agent)
- + [Server](#server)
- + [Proxy](#proxy-1)
- + [Web](#web)
- + [Java Gateway](#java-gateway-1)
-
-This document provides an overview of all the changes that are needed to be applied to have a correctly working environment per version. If a version is not part of this document, then there are no changes needed to apply.
-
-## 1.5.0
-
-### Roles
-
-#### Agent
-
-The following properties are added in the `zabbix_agent` role.
-
-* `zabbix_api_timeout = 30`
-* `zabbix_agent_tls_subject = "{{ zabbix_agent_tlsservercertsubject }}"`
-* `zabbix_agent2_server = "{{ zabbix_agent_server }}"`
-* `zabbix_agent2_serveractive = "{{ zabbix_agent_serveractive }}"`
-* `zabbix_agent2_allow_key = "{{ zabbix_agent_allow_key }}"`
-* `zabbix_agent2_deny_key = "{{ zabbix_agent_deny_key }}"`
-* `zabbix_agent2_tls_subject = "{{ zabbix_agent2_tlsservercertsubject }}"`
-
-NOTE: The original properties can still be used but it's suggested to update to
-use the new ones.
-
-The following properties are renamed in the `zabbix_agent` role.
-
-| From | To |
-|-------------------------------|-------------------------------|
-| zabbix_url | zabbix_api_server_url |
-| zabbix_agent_server_url | zabbix_api_server_url |
-| zabbix_http_user | zabbix_api_http_user |
-| zabbix_http_password | zabbix_api_http_password |
-| zabbix_api_user | zabbix_api_login_user |
-| zabbix_api_pass | zabbix_api_login_pass |
-| zabbix_validate_certs | zabbix_api_validate_certs |
-| zabbix_create_hostgroup | zabbix_agent_hostgroups_state |
-| zabbix_macros | zabbix_agent_macros |
-| zabbix_inventory_mode | zabbix_agent_inventory_mode |
-| zabbix_link_templates | zabbix_agent_link_templates |
-| zabbix_proxy | zabbix_agent_proxy |
-| zabbix_update_host | zabbix_agent_host_update |
-| zabbix_create_host | zabbix_agent_host_state |
-| zabbix_visible_hostname | zabbix_agent_visible_hostname |
-
-NOTE: the old parameters are still valid but it's suggested to update to use the
-new ones.
-
-#### Proxy
-
-The following properties are added in the `zabbix_proxy` role.
-
-* `zabbix_api_timeout = 30`
-* `zabbix_proxy_tls_subject = "{{ zabbix_proxy_tlsservercertsubject }}"`
-
-The following properties are renamed in the `zabbix_proxy` role.
-
-| From | To |
-|----------------------------|---------------------------------|
-| zabbix_server_host | zabbix_proxy_server |
-| zabbix_server_port | zabbix_proxy_serverport |
-| zabbix_proxy_localbuffer | zabbix_proxy_proxylocalbuffer |
-| zabbix_proxy_offlinebuffer | zabbix_proxy_proxyofflinebuffer |
-| zabbix_create_proxy | zabbix_proxy_state |
-| zabbix_url | zabbix_api_server_url |
-| zabbix_http_user | zabbix_api_http_user |
-| zabbix_http_password | zabbix_api_http_password |
-| zabbix_api_user | zabbix_api_login_user |
-| zabbix_api_pass | zabbix_api_login_pass |
-| zabbix_validate_certs | zabbix_api_validate_certs |
-
-NOTE: the old parameters are still valid but it's suggested to update to use the
-new ones.
-
-## 1.0.0
-
-### Roles
-
-#### Proxy
-
-The following property is renamed in the `zabbix_proxy` role.
-
-|From|To|
-|----|--|
-|`zabbix_version`|`zabbix_proxy_version`|
-
-NOTE: The `zabbix_version` can still be used, but will be deprecated in later releases.
-
-#### Java Gateway
-
-The following properties are renamed in the `zabbix_javagateway` role.
-
-|From|To|
-|----|--|
-|`zabbix_version`|`zabbix_javagateway_version`|
-|`javagateway_package_state`|`zabbix_javagateway_package_state`|
-|`javagateway_pidfile`|`zabbix_javagateway_pidfile`|
-|`javagateway_listenip`|`zabbix_javagateway_listenip`|
-|`javagateway_listenport`|`zabbix_javagateway_listenport`|
-|`javagateway_startpollers`|`zabbix_javagateway_startpollers`|
-
-NOTE: The `zabbix_version` can still be used, but will be deprecated in later releases.
-
-## 0.2.0
-
-### Roles
-
-#### Agent
-
-A 1-on-1 copy of the Ansible role `dj-wasabi.zabbix-agent` to this collection. Due to naming of roles as part of a collection, some characters (Like the `-`) are not allowed anymore. This role is therefore renamed from `zabbix-agent` to `zabbix_agent`.
-
-Example of using the role in this collection:
-```yaml
-- hosts: all
- roles:
- - role: community.zabbix.zabbix_agent
- zabbix_agent_server: 192.168.33.30
- zabbix_agent_serveractive: 192.168.33.30
-```
-
-#### Server
-
-A 1-on-1 copy of the Ansible role `dj-wasabi.zabbix-server` to this collection. Due to naming of roles as part of a collection, some characters (Like the `-`) are not allowed anymore. This role is therefore renamed from `zabbix-server` to `zabbix_server`.
-
-Example of using the role in this collection::
-```yaml
-- hosts: zabbix-server
- roles:
- - role: community.zabbix.zabbix_server
- zabbix_server_database: mysql
- zabbix_server_database_long: mysql
- zabbix_server_dbport: 3306
-```
-
-#### Proxy
-
-A 1-on-1 copy of the Ansible role `dj-wasabi.zabbix-proxy` to this collection. Due to naming of roles as part of a collection, some characters (Like the `-`) are not allowed anymore. This role is therefore renamed from `zabbix-proxy` to `zabbix_proxy`.
-
-Example of using the role in this collection::
-```yaml
-- hosts: zabbix-proxy
- roles:
- - role: community.zabbix.zabbix_proxy
- zabbix_proxy_server: 192.168.1.1
- zabbix_server_database: mysql
- zabbix_server_database_long: mysql
- zabbix_server_dbport: 3306
-```
-
-#### Web
-
-A 1-on-1 copy of the Ansible role `dj-wasabi.zabbix-web` to this collection. Due to naming of roles as part of a collection, some characters (Like the `-`) are not allowed anymore. This role is therefore renamed from `zabbix-web` to `zabbix_web`.
-
-Example of using the role in this collection::
-```yaml
-- hosts: zabbix-web
- become: yes
- roles:
- - role: geerlingguy.apache
- - role: community.zabbix.zabbix_web
- zabbix_url: zabbix.mydomain.com
- zabbix_server_hostname: zabbix-server
- zabbix_server_database: mysql
- zabbix_server_database_long: mysql
- zabbix_server_dbport: 3306
-```
-
-#### Java Gateway
-
-A 1-on-1 copy of the Ansible role `dj-wasabi.zabbix-javagateway` to this collection. Due to naming of roles as part of a collection, some characters (Like the `-`) are not allowed anymore. This role is therefore renamed from `zabbix-javagateway` to `zabbix_javagateway`.
-
-Example of using the role in this collection::
-```yaml
-- hosts: zabbix-server
- roles:
- - role: community.zabbix.zabbix_server
- zabbix_server_database: mysql
- zabbix_server_database_long: mysql
- zabbix_server_dbport: 3306
- zabbix_server_javagateway: 192.168.1.1
- - role: community.zabbix.zabbix_javagateway
-```
diff --git a/ansible_collections/community/zabbix/docs/ZABBIX_AGENT_ROLE.md b/ansible_collections/community/zabbix/docs/ZABBIX_AGENT_ROLE.md
index f3fe06c9d..aa73fab3a 100644
--- a/ansible_collections/community/zabbix/docs/ZABBIX_AGENT_ROLE.md
+++ b/ansible_collections/community/zabbix/docs/ZABBIX_AGENT_ROLE.md
@@ -44,15 +44,10 @@
This role will work on the following operating systems:
* Red Hat
- * Fedora
* Debian
* Ubuntu
- * opensuse
* Windows (Best effort)
- * macOS
-
-So, you'll need one of those operating systems.. :-)
-Please send Pull Requests or suggestions when you want to use this role for other Operating systems.
+ * macOS (Best effort)
## Ansible 2.10 and higher
@@ -62,7 +57,7 @@ With the release of Ansible 2.10, modules have been moved into collections. Wit
ansible-galaxy collection install ansible.posix
ansible-galaxy collection install community.general
```
-If you are willing to create host_groups and hosts in Zabbix via API as a part of this role execution then you need to install `ansible.netcommon` collection too:
+If you are wanting to create host_groups and hosts in Zabbix via API as a part of this role execution then you need to install `ansible.netcommon` collection too:
```
ansible-galaxy collection install ansible.netcommon
@@ -95,24 +90,18 @@ To successfully complete the install the role requires `python-netaddr` on the c
See the following list of supported Operating systems with the Zabbix releases:
-| Zabbix | 6.4 | 6.2 | 6.0 | 5.4 | 5.2 | 5.0 (LTS)| 4.4 | 4.0 (LTS) | 3.0 (LTS) |
-|---------------------|-----|-----|-----|-----|-----|----------|-----|-----------|-----------|
-| Red Hat Fam 9 | V | V | V | | | | | | |
-| Red Hat Fam 8 | V | V | V | V | V | V | V | | |
-| Red Hat Fam 7 | V | V | V | V | V | V | V | V | V |
-| Red Hat Fam 6 | V | V | V | V | V | V | | | V |
-| Red Hat Fam 5 | | | V | V | V | V | | | V |
-| Fedora | | | | | | | V | V | |
-| Ubuntu 20.04 focal | V | V | V | V | V | V | | V | |
-| Ubuntu 18.04 bionic | V | V | V | V | V | V | V | V | |
-| Ubuntu 16.04 xenial | V | V | V | V | V | V | V | V | |
-| Ubuntu 14.04 trusty | V | V | V | V | V | V | V | V | V |
-| Debian 10 buster | V | V | V | V | V | V | V | | |
-| Debian 9 stretch | V | V | | V | V | V | V | V | |
-| Debian 8 jessie | | | | | V | V | V | V | V |
-| Debian 7 wheezy | | | | | | | | V | V |
-| macOS 10.15 | | | | | | | V | V | |
-| macOS 10.14 | | | | | | | V | V | |
+| Zabbix | 6.4 | 6.2 | 6.0 |
+|---------------------|-----|-----|-----|
+| Red Hat Fam 9 | V | V | V |
+| Red Hat Fam 8 | V | V | V |
+| Red Hat Fam 7 | V | V | V |
+| Ubuntu 22.04 jammy | V | V | V |
+| Ubuntu 20.04 focal | V | V | V |
+| Ubuntu 18.04 bionic | V | V | V |
+| Debian 12 bookworm | V | V | V |
+| Debian 11 bullseye | V | V | V |
+| Debian 10 buster | V | V | V |
+
# Getting started
@@ -124,7 +113,7 @@ In order to get the Zabbix Agent running, you'll have to define the following pr
* `zabbix_agent(2)_server`
* `zabbix_agent(2)_serveractive` (When using active checks)
-The `zabbix_agent_version` is optional. The latest available major.minor version of Zabbix will be installed on the host(s). If you want to use an older version, please specify this in the major.minor format. Example: `zabbix_agent_version: 4.0`, `zabbix_agent_version: 3.4` or `zabbix_agent_version: 2.2`.
+The `zabbix_agent_version` is optional. The latest available major.minor version of Zabbix will be installed on the host(s). If you want to use an older version, please specify this in the major.minor format. Example: `zabbix_agent_version: 6.0`.
The `zabbix_agent(2)_server` (and `zabbix_agent(2)_serveractive`) should contain the ip or fqdn of the host running the Zabbix Server.
@@ -140,16 +129,13 @@ The following is an overview of all available configuration default for this rol
### Overall Zabbix
-* `zabbix_agent_version`: This is the version of zabbix. Default: The highest supported version for the operating system. Can be overridden to 6.2, 6.0, 5.4, 5.2 5.0, 4.4, 4.0, 3.4, 3.2, 3.0, 2.4, or 2.2. Previously the variable `zabbix_version` was used directly but it could cause [some inconvenience](https://github.com/dj-wasabi/ansible-zabbix-agent/pull/303). That variable is maintained by retrocompativility.
+* `zabbix_agent_version`: This is the version of zabbix. Default: The highest supported version for the operating system. Can be overridden to 6.4, 6.2, or 6.0
* `zabbix_agent_version_minor`: When you want to specify a minor version to be installed. Is also used for `zabbix_sender` and `zabbix_get`. RedHat only. Default set to: `*` (latest available)
-* `zabbix_repo`: Default: `zabbix`
- * `epel`: install agent from EPEL repo
- * `zabbix`: (default) install agent from Zabbix repo
- * `other`: install agent from pre-existing or other repo
* `zabbix_repo_yum`: A list with Yum repository configuration.
* `zabbix_repo_yum_schema`: Default: `https`. Option to change the web schema for the yum repository(http/https)
-* `zabbix_repo_yum_disabled`: A string with repository names that should be disabled when installing Zabbix component specific packages. Is only used when `zabbix_repo_yum_enabled` contains 1 or more repositories. Default `*`.
-* `zabbix_repo_yum_enabled`: A list with repository names that should be enabled when installing Zabbix component specific packages.
+* `zabbix_agent_disable_repo`: A list of repos to disable during install. Default `epel`.
+* `zabbix_repo_deb_url`: The URL to the Zabbix repository. Default `http://repo.zabbix.com/zabbix/{{ zabbix_agent_version }}/{{ ansible_distribution.lower() }}`
+* `zabbix_repo_deb_component`: The repository component for Debian installs. Default `main`.
### SElinux
@@ -158,7 +144,7 @@ The following is an overview of all available configuration default for this rol
### Zabbix Agent
* `zabbix_agent_ip`: The IP address of the host. When not provided, it will be determined via the `ansible_default_ipv4` fact.
-* `zabbix_agent2`: Default: `False`. When you want to install the `Zabbix Agent2` instead of the "old" `Zabbix Agent`.
+* `zabbix_agent2`: Default: `False`. When you want to install the `Zabbix Agent2` instead of the "old" `Zabbix Agent`.zabbix_agent_version
* `zabbix_agent_listeninterface`: Interface zabbix-agent listens on. Leave blank for all.
* `zabbix_agent_package_remove`: If `zabbix_agent2: True` and you want to remove the old installation. Default: `False`.
* `zabbix_agent_package`: The name of the zabbix-agent package. Default: `zabbix-agent`. In case for EPEL, it is automatically renamed.
@@ -174,7 +160,6 @@ The following is an overview of all available configuration default for this rol
* `zabbix_agent_userparameters_scripts_src`: indicates the relative path (from `files/`) where userparameter scripts are searched
* `zabbix_agent_runas_user`: Drop privileges to a specific, existing user on the system. Only has effect if run as 'root' and AllowRoot is disabled.
* `zabbix_agent_become_on_localhost`: Default: `True`. Set to `False` if you don't need to elevate privileges on localhost to install packages locally with pip.
-* `zabbix_install_pip_packages`: Default: `True`. Set to `False` if you don't want to install the required pip packages. Useful when you control your environment completely.
* `zabbix_agent_apt_priority`: Add a weight (`Pin-Priority`) for the APT repository.
* `zabbix_agent_conf_mode`: Default: `0644`. The "mode" for the Zabbix configuration file.
* `zabbix_agent_dont_detect_ip`: Default `false`. When set to `true`, it won't detect available ip addresses on the host and no need for the Python module `netaddr` to be installed.
@@ -193,6 +178,7 @@ Otherwise it just for the Zabbix Agent or for the Zabbix Agent 2.
* `zabbix_agent(2)_pidfile`: name of pid file.
* `zabbix_agent(2)_logfile`: name of log file.
* `zabbix_agent(2)_logfilesize`: maximum size of log file in mb.
+* `zabbix_agent(2)_additional_include`: A list of additional complete paths to include in configuration
* `zabbix_agent(2)_logtype`: Specifies where log messages are written to
* `zabbix_agent(2)_debuglevel`: specifies debug level
* `zabbix_agent(2)_sourceip`: source ip address for outgoing connections.
@@ -261,16 +247,17 @@ These variables need to be overridden when you want to make use of the Zabbix AP
Host encryption configuration will be set to match agent configuration.
-* `zabbix_api_http_user`: The http user to access zabbix url with Basic Auth.
-* `zabbix_api_http_password`: The http password to access zabbix url with Basic Auth.
-* `zabbix_api_create_hosts`: Default: `False`. When you want to enable the Zabbix API to create/delete the host. This has to be set to `True` if you want to make use of `zabbix_agent_host_state`.
-* `zabbix_api_create_hostgroup`: When you want to enable the Zabbix API to create/delete the hostgroups. This has to be set to `True` if you want to make use of `zabbix_agent_hostgroups_state`.Default: `False`
* `zabbix_api_server_host`: The IP or hostname/FQDN of Zabbix server. Example: zabbix.example.com
-* `zabbix_api_server_port`: TCP port to use to connect to Zabbix server. Example: 8080
-* `zabbix_api_use_ssl`: yes (Default) if we need to connect to Zabbix server over HTTPS
-* `zabbix_api_validate_certs` : yes (Default) if we need to validate tls certificates of the API. Use `no` in case self-signed certificates are used
+* `zabbix_api_use_ssl`: Is SSL required to connect to the Zabbix API server? Default: `false`
+* `zabbix_api_server_port`: 80 if `zabbix_api_use_ssl` is `false` and 443 if `true` (Default) TCP port to use to connect to Zabbix server. Example: 8080
* `zabbix_api_login_user`: Username of user which has API access.
* `zabbix_api_login_pass`: Password for the user which has API access.
+* `zabbix_api_http_user`: The http user to access zabbix url with Basic Auth (if your Zabbix is behind a proxy with HTTP Basic Auth).
+* `zabbix_api_http_password`: The http password to access zabbix url with Basic Auth (if your Zabbix is behind a proxy with HTTP Basic Auth).
+* `zabbix_api_validate_certs`: yes (Default) if we need to validate tls certificates of the API. Use `no` in case self-signed certificates are used.
+* `zabbix_api_timeout`: How many seconds to wait for API response (default 30s).
+* `zabbix_api_create_hosts`: Default: `False`. When you want to enable the Zabbix API to create/delete the host. This has to be set to `True` if you want to make use of `zabbix_agent_host_state`.
+* `zabbix_api_create_hostgroup`: When you want to enable the Zabbix API to create/delete the hostgroups. This has to be set to `True` if you want to make use of `zabbix_agent_hostgroups_state`.Default: `False`
* `ansible_zabbix_url_path`: URL path if Zabbix WebUI running on non-default (zabbix) path, e.g. if http://<FQDN>/zabbixeu then set to `zabbixeu`
* `zabbix_agent_hostgroups_state`: present (Default) if the hostgroup needs to be created or absent if you want to delete it. This only works when `zabbix_api_create_hostgroup` is set to `True`.
* `zabbix_host_status`: enabled (Default) when host in monitored, disabled when host is disabled for monitoring.
@@ -290,7 +277,7 @@ Host encryption configuration will be set to match agent configuration.
**NOTE**
-_Supporting Windows is a best effort (I don't have the possibility to either test/verify changes on the various amount of available Windows instances). PRs specific to Windows will almost immediately be merged, unless someone is able to provide a Windows test mechanism via Travis for Pull Requests._
+_Supporting Windows is a best effort (We don't have the possibility to either test/verify changes on the various amount of available Windows instances). PRs specific to Windows will almost immediately be merged, unless someone is able to provide a Windows test mechanism via Travis for Pull Requests._
When `(2)` is used in the name of the property, like `zabbix_agent(2)_win_logfile`, it will show that you can configure `zabbix_agent_win_logfile` for the Zabbix Agent configuration file and `zabbix_agent2_win_logfile` for the Zabbix Agent 2 configuration file.
Otherwise it just for the Zabbix Agent or for the Zabbix Agent 2.
@@ -308,6 +295,10 @@ Otherwise it just for the Zabbix Agent or for the Zabbix Agent 2.
## macOS Variables
+**NOTE**
+
+_Supporting Windows is a best effort (We don't have the possibility to either test/verify changes on the various amount of available Windows instances). PRs specific to Windows will almost immediately be merged, unless someone is able to provide a Windows test mechanism via Travis for Pull Requests._
+
* `zabbix_version_long`: The long (major.minor.patch) version of the Zabbix Agent. This will be used to generate the `zabbix_mac_download_link` link.
* `zabbix_mac_download_link`: The download url to the `pkg` file.
@@ -344,17 +335,6 @@ Keep in mind that using the Zabbix Agent in a Container requires changes to the
* `zabbix_agent_docker_volumes`: A list with all directories that needs to be available in the Container.
* `zabbix_agent_docker_env`: A dict with all environment variables that needs to be set for the Container.
-## FirewallD/Iptables
-
-* `zabbix_agent_firewall_enable`: If IPtables needs to be updated by opening an TCP port for port configured in `zabbix_agent_listenport`.
-* `zabbix_agent_firewall_source`: When provided, IPtables will be configuring to only allow traffic from this IP address/range.
-* `zabbix_agent_firewalld_enable`: If firewalld needs to be updated by opening an TCP port for port configured in `zabbix_agent_listenport` and `zabbix_agent_jmx_listenport` if defined.
-* `zabbix_agent_firewalld_source`: When provided, firewalld will be configuring to only allow traffic for IP configured in `zabbix_agent_server`.
-* `zabbix_agent_firewalld_zone`: When provided, the firewalld rule will be attached to this zone (only if zabbix_agent_firewalld_enable is set to true). The default behavior is to use the default zone define by the remote host firewalld configuration.
-* `zabbix_agent_firewall_action`: Default: `insert`. When to `insert` the rule or to `append` to IPTables.
-* `zabbix_agent_firewall_chain`: Default `INPUT`. Which `chain` to add the rule to IPTables.
-
-
## IPMI variables
* `zabbix_agent_ipmi_authtype`: IPMI authentication algorithm. Possible values are 1 (callback), 2 (user), 3 (operator), 4 (admin), 5 (OEM), with 2 being the API default.
@@ -369,6 +349,17 @@ When the target host does not have access to the internet, but you do have a pro
* `zabbix_http_proxy`
* `zabbix_https_proxy`
+## Tags
+
+The majority of tasks within this role are tagged as follows:
+
+* `install`: Tasks associated with the installation of software.
+* `dependencies`: Installation tasks related to dependencies that aren't part of the core zabbix installation.
+* `database`: Tasks associated with the installation or configuration of the database.
+* `api`: Tasks associated with using the Zabbix API to connect and modify the Zabbix server.
+* `config`: Tasks associated with the configuration of Zabbix or a supporting service.
+* `service`: Tasks associated with managing a service.
+
# Dependencies
There are no dependencies on other roles.
@@ -440,10 +431,11 @@ Including an example of how to use your role (for instance, with variables passe
- role: community.zabbix.zabbix_agent
zabbix_agent_server: 192.168.33.30
zabbix_agent_serveractive: 192.168.33.30
- zabbix_api_server_url: http://zabbix.example.com
- zabbix_api_use: true # use zabbix_api_create_hosts and/or zabbix_api_create_hostgroup from 0.8.0
+ zabbix_api_server_host: zabbix.example.com
zabbix_api_login_user: Admin
zabbix_api_login_pass: zabbix
+ zabbix_api_create_hostgroup: true
+ zabbix_api_create_hosts: true
zabbix_agent_host_state: present
zabbix_host_groups:
- Linux Servers
@@ -465,10 +457,11 @@ You can also use the group_vars or the host_vars files for setting the variables
```yaml
zabbix_agent_server: 192.168.33.30
zabbix_agent_serveractive: 192.168.33.30
- zabbix_api_server_url: http://zabbix.example.com
- zabbix_api_use: true # use zabbix_api_create_hosts and/or zabbix_api_create_hostgroup from 0.8.0
+ zabbix_api_server_host: zabbix.example.com
zabbix_api_login_user: Admin
zabbix_api_login_pass: zabbix
+ zabbix_api_create_hostgroup: true
+ zabbix_api_create_hosts: true
zabbix_agent_host_state: present
zabbix_host_groups:
- Linux Servers
diff --git a/ansible_collections/community/zabbix/docs/ZABBIX_JAVAGATEWAY_ROLE.md b/ansible_collections/community/zabbix/docs/ZABBIX_JAVAGATEWAY_ROLE.md
index 70427d97c..1761c7f8b 100644
--- a/ansible_collections/community/zabbix/docs/ZABBIX_JAVAGATEWAY_ROLE.md
+++ b/ansible_collections/community/zabbix/docs/ZABBIX_JAVAGATEWAY_ROLE.md
@@ -29,29 +29,22 @@ This role will work on the following operating systems:
* Ubuntu
So, you'll need one of those operating systems.. :-)
-Please send Pull Requests or suggestions when you want to use this role for other Operating systems.
## Zabbix Versions
See the following list of supported Operating systems with the Zabbix releases.
-| Zabbix | 6.4 | 6.2 | 6.0 (LTS) | 5.2 | 5.0 | 4.4 | 4.0 (LTS) | 3.0 (LTS) |
-|---------------------|-----|-----|-----------|-----|-----|-----|-----------|-----------|
-| Red Hat Fam 8 | V | V | V | V | V | V | | |
-| Red Hat Fam 7 | | | | V | V | V | V | V |
-| Red Hat Fam 6 | | | | V | V | | | V |
-| Red Hat Fam 5 | | | | V | V | | | V |
-| Fedora | | | | | | V | V | |
-| Ubuntu 20.04 focal | V | V | V | V | V | | V | |
-| Ubuntu 18.04 bionic | | | | V | V | V | V | |
-| Ubuntu 16.04 xenial | | | | V | V | V | V | |
-| Ubuntu 14.04 trusty | | | | V | V | V | V | V |
-| Debian 10 buster | V | V | V | V | V | V | | |
-| Debian 9 stretch | | | | V | V | V | V | |
-| Debian 8 jessie | | | | V | V | V | V | V |
-| Debian 7 wheezy | | | | | | | V | V |
-| macOS 10.15 | | | | | | V | V | |
-| macOS 10.14 | | | | | | V | V | |
+| Zabbix | 6.4 | 6.2 | 6.0 |
+|---------------------|-----|-----|-----|
+| Red Hat Fam 9 | V | V | V |
+| Red Hat Fam 8 | V | V | V |
+| Red Hat Fam 7 | V | V | V |
+| Ubuntu 22.04 jammy | V | V | V |
+| Ubuntu 20.04 focal | V | V | V |
+| Ubuntu 18.04 bionic | V | V | V |
+| Debian 12 bookworm | V | | V |
+| Debian 11 bullseye | V | V | V |
+| Debian 10 buster | V | V | V |
# Role Variables
@@ -61,17 +54,14 @@ The following is an overview of all available configuration default for this rol
### Overall Zabbix
-* `zabbix_javagateway_version`: This is the version of zabbix. Default: 5.2. Can be overridden to 5.0, 4.4, 4.0, 3.4, 3.2, 3.0, 2.4, or 2.2. Previously the variable `zabbix_version` was used directly but it could cause [some inconvenience](https://github.com/dj-wasabi/ansible-zabbix-agent/pull/303). That variable is maintained by retrocompativility.
-* `zabbix_repo`: Default: `zabbix`
- * `epel`: install agent from EPEL repo
- * `zabbix`: (default) install agent from Zabbix repo
- * `other`: install agent from pre-existing or other repo
+The `zabbix_javagateway_version` is optional. The latest available major.minor version of Zabbix will be installed on the host(s). If you want to use an older version, please specify this in the major.minor format. Example: `zabbix_javagateway_version: 6.0`.
* `zabbix_repo_yum`: A list with Yum repository configuration.
* `zabbix_repo_yum_schema`: Default: `https`. Option to change the web schema for the yum repository(http/https)
-* `zabbix_repo_yum_disabled`: A string with repository names that should be disabled when installing Zabbix component specific packages. Is only used when `zabbix_repo_yum_enabled` contains 1 or more repositories. Default `*`.
-* `zabbix_repo_yum_enabled`: A list with repository names that should be enabled when installing Zabbix component specific packages.
+* `zabbix_javagateway_disable_repo`: A list of repos to disable during install. Default `epel`.
* `zabbix_javagateway_package_state`: Default: `present`. Can be overridden to `latest` to update packages when needed.
* `zabbix_javagateway_conf_mode`: Default: `0644`. The "mode" for the Zabbix configuration file.
+* `zabbix_repo_deb_url`: The URL to the Zabbix repository. Default `http://repo.zabbix.com/zabbix/{{ zabbix_agent_version }}/{{ ansible_distribution.lower() }}`
+* `zabbix_repo_deb_component`: The repository component for Debian installs. Default `main`.
### Java Gatewaty
@@ -106,6 +96,17 @@ or when using the zabbix-proxy:
zabbix_proxy_javagateway: 192.168.1.2
```
+## Tags
+
+The majority of tasks within this role are tagged as follows:
+
+* `install`: Tasks associated with the installation of software.
+* `dependencies`: Installation tasks related to dependencies that aren't part of the core zabbix installation.
+* `database`: Tasks associated with the installation or configuration of the database.
+* `api`: Tasks associated with using the Zabbix API to connect and modify the Zabbix server.
+* `config`: Tasks associated with the configuration of Zabbix or a supporting service.
+* `service`: Tasks associated with managing a service.
+
# Example Playbook
Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
diff --git a/ansible_collections/community/zabbix/docs/ZABBIX_PROXY_ROLE.md b/ansible_collections/community/zabbix/docs/ZABBIX_PROXY_ROLE.md
index 6682f6c18..baec42155 100644
--- a/ansible_collections/community/zabbix/docs/ZABBIX_PROXY_ROLE.md
+++ b/ansible_collections/community/zabbix/docs/ZABBIX_PROXY_ROLE.md
@@ -77,24 +77,17 @@ ansible-galaxy collection install community.postgresql
See the following list of supported Operating systems with the Zabbix releases.
-| Zabbix | 6.4 | 6.2 | 6.0 | 5.4 | 5.2 | 5.0 (LTS)| 4.4 | 4.0 (LTS) | 3.0 (LTS) |
-|---------------------|-----|-----|-----|-----|-----|-----------|-----|-----------|-----------|
-| Red Hat Fam 9 | V | V | V | | | | | | |
-| Red Hat Fam 8 | V | V | V | V | V | V | V | | |
-| Red Hat Fam 7 | V | V | V | V | V | V | V | V | V |
-| Red Hat Fam 6 | | | | | V | V | | | V |
-| Red Hat Fam 5 | | | | | V | V | | | V |
-| Fedora | | | | | | | V | V | |
-| Ubuntu 20.04 focal | V | V | V | V | V | V | | V | |
-| Ubuntu 18.04 bionic | | | V | V | V | V | V | V | |
-| Ubuntu 16.04 xenial | | | | | V | V | V | V | |
-| Ubuntu 14.04 trusty | | | | | V | V | V | V | V |
-| Debian 10 buster | V | | V | V | V | V | V | | |
-| Debian 9 stretch | V | | V | V | V | V | V | V | |
-| Debian 8 jessie | | | | | V | V | V | V | V |
-| Debian 7 wheezy | | | | | | | | V | V |
-| macOS 10.15 | | | | | | | V | V | |
-| macOS 10.14 | | | | | | | V | V | |
+| Zabbix | 6.4 | 6.2 | 6.0 |
+|---------------------|-----|-----|-----|
+| Red Hat Fam 9 | V | V | V |
+| Red Hat Fam 8 | V | V | V |
+| Red Hat Fam 7 | V | V | V |
+| Ubuntu 22.04 jammy | V | V | V |
+| Ubuntu 20.04 focal | V | V | V |
+| Ubuntu 18.04 bionic | V | V | V |
+| Debian 12 bookworm | V | | V |
+| Debian 11 bullseye | V | V | V |
+| Debian 10 buster | V | V | V |
# Role Variables
@@ -102,104 +95,49 @@ See the following list of supported Operating systems with the Zabbix releases.
The following is an overview of all available configuration default for this role.
-### Overall Zabbix
-
-* `zabbix_proxy_version`: This is the version of zabbix. Default: The highest supported version for the operating system. Can be overridden to 6.2, 6.0, 5.4, 5.2, 5.0, 4.4, 4.0, 3.4, 3.2, 3.0, 2.4, or 2.2. Previously the variable `zabbix_version` was used directly but it could cause [some inconvenience](https://github.com/dj-wasabi/ansible-zabbix-agent/pull/303). That variable is maintained by retrocompativility.
-* `zabbix_proxy_version_minor`: When you want to specify a minor version to be installed. RedHat only. Default set to: `*` (latest available)
-* `zabbix_repo`: Default: `zabbix`
- * `epel`: install agent from EPEL repo
- * `zabbix`: (default) install agent from Zabbix repo
- * `other`: install agent from pre-existing or other repo
-* `zabbix_repo_yum`: A list with Yum repository configuration.
-* `zabbix_repo_yum_schema`: Default: `https`. Option to change the web schema for the yum repository(http/https)
-* `zabbix_repo_yum_disabled`: A string with repository names that should be disabled when installing Zabbix component specific packages. Is only used when `zabbix_repo_yum_enabled` contains 1 or more repositories. Default `*`.
-* `zabbix_repo_yum_enabled`: A list with repository names that should be enabled when installing Zabbix component specific packages.
-
-### SElinux
-
-* `zabbix_selinux`: Default: `False`. Enables an SELinux policy so that the Proxy will run.
-
### Zabbix Proxy
+* `zabbix_proxy_version`: Optional. The latest available major.minor version of Zabbix will be installed on the host(s). If you want to use an older version, please specify this in the major.minor format. Example: `zabbix_proxy_version: 6.0`.
+* `zabbix_proxy_version_minor`: When you want to specify a minor version to be installed. RedHat only. Default set to: `*` (latest available)
* `zabbix_proxy_ip`: The IP address of the host. When not provided, it will be determined via the `ansible_default_ipv4` fact.
* `zabbix_proxy_server`: The ip or dns name for the zabbix-server machine.
-* `zabbix_proxy_serverport`: The port on which the zabbix-server is running. Default: 10051
-* `*zabbix_proxy_package_state`: Default: `present`. Can be overridden to `latest` to update packages
* `zabbix_proxy_install_database_client`: Default: `True`. False does not install database client.
-* `zabbix_proxy_become_on_localhost`: Default: `True`. Set to `False` if you don't need to elevate privileges on localhost to install packages locally with pip.
* `zabbix_proxy_manage_service`: Default: `True`. When you run multiple Zabbix proxies in a High Available cluster setup (e.g. pacemaker), you don't want Ansible to manage the zabbix-proxy service, because Pacemaker is in control of zabbix-proxy service.
-* `zabbix_install_pip_packages`: Default: `True`. Set to `False` if you don't want to install the required pip packages. Useful when you control your environment completely.
-* `zabbix_proxy_startpreprocessors`: Number of pre-forked instances of preprocessing workers. The preprocessing manager process is automatically started when a preprocessor worker is started.This parameter is supported since Zabbix 4.2.0.
-* `zabbix_proxy_username`: Default: `zabbix`. The name of the account on the host. Will only be used when `zabbix_repo: epel` is used.
-* `zabbix_proxy_logtype`: Specifies where log messages are written to: system, file, console.
-* `zabbix_proxy_logfile`: Name of log file.
-* `zabbix_proxy_userid`: The UID of the account on the host. Will only be used when `zabbix_repo: epel` is used.
-* `zabbix_proxy_groupname`: Default: `zabbix`. The name of the group of the user on the host. Will only be used when `zabbix_repo: epel` is used.
-* `zabbix_proxy_groupid`: The GID of the group on the host. Will only be used when `zabbix_repo: epel` is used.
* `zabbix_proxy_include_mode`: Default: `0755`. The "mode" for the directory configured with `zabbix_proxy_include`.
* `zabbix_proxy_conf_mode`: Default: `0644`. The "mode" for the Zabbix configuration file.
-* `zabbix_proxy_statsallowedip`: Default: `127.0.0.1`. Allowed IP foe remote gathering of the ZabbixPorixy internal metrics.
-* `zabbix_proxy_vaulttoken`: Vault authentication token that should have been generated exclusively for Zabbix server with read only permission
-* `zabbix_proxy_vaulturl`: Vault server HTTP[S] URL. System-wide CA certificates directory will be used if SSLCALocation is not specified.
-* `zabbix_proxy_vaultdbpath`: Vault path from where credentials for database will be retrieved by keys 'password' and 'username'.
-* `zabbix_proxy_listenbacklog`: The maximum number of pending connections in the queue.
### Database specific
* `zabbix_proxy_dbhost_run_install`: Default: `True`. When set to `True`, sql files will be executed on the host running the database.
* `zabbix_proxy_database`: Default: `mysql`. The type of database used. Can be: `mysql`, `pgsql` or `sqlite3`
-* `zabbix_proxy_database_long`: Default: `mysql`. The type of database used, but long name. Can be: `mysql`, `postgresql` or `sqlite3`
-* `zabbix_proxy_dbhost`: The hostname on which the database is running. Will be ignored when `sqlite3` is used as database.
+* `zabbix_proxy_dbhost`: Default: localhost. The hostname on which the database is running. Will be ignored when `sqlite3` is used as database.
* `zabbix_proxy_real_dbhost`: The hostname of the dbhost that is running behind a loadbalancer/VIP (loadbalancers doesn't accept ssh connections) Will be ignored when `sqlite3` is used as database.
-* `zabbix_proxy_dbname`: The database name which is used by the Zabbix Proxy.
-* `zabbix_proxy_dbuser`: The database username which is used by the Zabbix Proxy. Will be ignored when `sqlite3` is used as database.
-* `zabbix_proxy_dbpassword`: The database user password which is used by the Zabbix Proxy. Will be ignored when `sqlite3` is used as database.
+* `zabbix_proxy_dbname`: Default: zabbix_proxy. The database name which is used by the Zabbix Proxy.
+* `zabbix_proxy_dbuser`: Default: zabbix_proxy. The database username which is used by the Zabbix Proxy. Will be ignored when `sqlite3` is used as database.
+* `zabbix_proxy_dbpassword`: Default: zabbix_proxy. The database user password which is used by the Zabbix Proxy. Will be ignored when `sqlite3` is used as database.
+* `zabbix_proxy_dbpassword_hash_method`: Default: `md5`. Allow switching postgresql user password creation to `scram-sha-256`, when anything other than `md5` is used then ansible won't hash the password with `md5`.
* `zabbix_proxy_dbport`: The database port which is used by the Zabbix Proxy. Will be ignored when `sqlite3` is used as database.
-* `zabbix_database_creation`: Default: `True`. When you don't want to create the database including user, you can set it to False.
+* `zabbix_proxy_database_creation`: Default: `True`. When you don't want to create the database including user, you can set it to False.
* `zabbix_proxy_install_database_client`: Default: `True`. False does not install database client. Default true
-* `zabbix_database_sqlload`:True / False. When you don't want to load the sql files into the database, you can set it to False.
+* `zabbix_proxy_database_sqlload`:True / False. When you don't want to load the sql files into the database, you can set it to False.
* `zabbix_proxy_dbencoding`: Default: `utf8`. The encoding for the MySQL database.
* `zabbix_proxy_dbcollation`: Default: `utf8_bin`. The collation for the MySQL database.zabbix_proxy_
-* `zabbix_server_allowunsupporteddbversions`: Allow proxy to work with unsupported database versions.
-* `zabbix_proxy_dbpassword_hash_method`: Default: `md5`. Allow switching postgresql user password creation to `scram-sha-256`, when anything other than `md5` is used then ansible won't hash the password with `md5`.
-### TLS Specific configuration
-
-These variables are specific for Zabbix 3.0 and higher:
-
-* `zabbix_proxy_tlsconnect`: How the agent should connect to server or proxy. Used for active checks.
- Possible values:
- * unencrypted
- * psk
- * cert
-* `zabbix_proxy_tlsaccept`: What incoming connections to accept.
- Possible values:
- * unencrypted
- * psk
- * cert
-* `zabbix_proxy_tlscafile`: Full pathname of a file containing the top-level CA(s) certificates for peer certificate verification.
-* `zabbix_proxy_tlscrlfile`: Full pathname of a file containing revoked certificates.
-* `zabbix_proxy_tlsservercertissuer`: Allowed server certificate issuer.
-* `zabbix_proxy_tlsservercertsubject`: Allowed server certificate subject.
-* `zabbix_proxy_tlscertfile`: Full pathname of a file containing the agent certificate or certificate chain.
-* `zabbix_proxy_tlskeyfile`: Full pathname of a file containing the agent private key.
-* `zabbix_proxy_dbtlsconnect`: Setting this option enforces to use TLS connection to database:
-
-`required` - connect using TLS
-`verify_ca` - connect using TLS and verify certificate
-`verify_full` - connect using TLS, verify certificate and verify that database identity specified by DBHost matches its certificate
-
-On `MySQL` starting from 5.7.11 and `PostgreSQL` the following values are supported: `required`, `verify`, `verify_full`. On MariaDB starting from version 10.2.6 `required` and `verify_full` values are supported.
-By default not set to any option and the behaviour depends on database configuration.
-This parameter is supported since Zabbix 5.0.0.
-
-* `zabbix_proxy_dbtlscafile`: Full pathname of a file containing the top-level CA(s) certificates for database certificate verification. This parameter is supported since Zabbix 5.0.0.
-* `zabbix_proxy_dbtlscertfile`: Full pathname of file containing Zabbix Proxy certificate for authenticating to database. This parameter is supported since Zabbix 5.0.0.
-* `zabbix_proxy_dbtlskeyfile`: Full pathname of file containing the private key for authenticating to database. This parameter is supported since Zabbix 5.0.0.
-* `zabbix_proxy_dbtlscipher`: The list of encryption ciphers that Zabbix Proxy permits for TLS protocols up through TLSv1.2. Supported only for MySQL.This parameter is supported since Zabbix 5.0.0.
-* `zabbix_proxy_dbtlscipher13`: The list of encryption ciphersuites that Zabbix Proxy permits for TLSv1.3 protocol. Supported only for MySQL, starting from version 8.0.16. This parameter is supported since Zabbix 5.0.0.
-
-## proxy
+
+### Yum/APT
+* `zabbix_repo_yum`: A list with Yum repository configuration.
+* `zabbix_repo_yum_schema`: Default: `https`. Option to change the web schema for the yum repository(http/https)
+* `zabbix_repo_yum_gpgcheck`: Default: `0`. Should yum perform a GPG check on the repository
+* `zabbix_proxy_disable_repo`: A list of repos to disable during install. Default `epel`.
+* `zabbix_proxy_apt_priority`: APT priority for the zabbix repository
+* `*zabbix_proxy_package_state`: Default: `present`. Can be overridden to `latest` to update packages
+* `zabbix_repo_deb_url`: The URL to the Zabbix repository. Default `http://repo.zabbix.com/zabbix/{{ zabbix_proxy_version }}/{{ ansible_distribution.lower() }}`
+* `zabbix_repo_deb_component`: The repository component for Debian installs. Default `main`.
+### SElinux
+
+* `zabbix_proxy_selinux`: Default: `False`. Enables an SELinux policy so that the Proxy will run.
+
+## Proxy
When the target host does not have access to the internet, but you do have a proxy available then the following properties needs to be set to download the packages via the proxy:
@@ -210,9 +148,9 @@ When the target host does not have access to the internet, but you do have a pro
With Zabbix Proxy you can make use of 2 different databases:
-* `mysql`
-* `postgresql`
-* `SQLite3`
+* MySQL
+* PostgreSQL
+* SQLite3
In the following paragraphs we dive into both setups.
@@ -232,12 +170,12 @@ We need to have the following dependencies met:
```yaml
zabbix_proxy_database: mysql
-zabbix_proxy_database_long: mysql
zabbix_proxy_dbport: 3306
zabbix_proxy_dbpassword: <SOME_SECRET_STRING>
```
Please generate a value for the `zabbix_proxy_dbpassword` property (Maybe use `ansible-vault` for this). The zabbix-proxy role will create an database and username (With the provided value for the password) in `MySQL`.
+
3. Execute the role by running the Ansible playbook that calls this role. At the end of this run, the Zabbix Proxy with `MySQL` will be running.
#### Separate Setup
@@ -249,7 +187,6 @@ We need to have the following dependencies met:
```yaml
zabbix_proxy_database: mysql
-zabbix_proxy_database_long: mysql
zabbix_proxy_dbport: 3306
zabbix_proxy_dbhost: mysql-host
zabbix_proxy_dbhost_run_install: false
@@ -283,7 +220,6 @@ We need to have the following dependencies met:
```yaml
zabbix_proxy_database: pgsql
-zabbix_proxy_database_long: postgresql
zabbix_proxy_dbport: 5432
zabbix_proxy_dbpassword: <SOME_SECRET_STRING>
```
@@ -300,7 +236,6 @@ We need to have the following dependencies met:
```yaml
zabbix_proxy_database: pgsql
-zabbix_proxy_database_long: postgresql
zabbix_proxy_dbport: 5432
zabbix_proxy_dbhost: pgsql-host
zabbix_proxy_dbhost_run_install: false
@@ -326,7 +261,6 @@ The following properties needs to be set when using `SQLite3` as the database:
```yaml
zabbix_proxy_database: sqlite3
-zabbix_proxy_database_long: sqlite3
zabbix_proxy_dbname: /path/to/sqlite3.db
```
@@ -336,20 +270,140 @@ NOTE: When using `zabbix_proxy_dbname: zabbix_proxy` (Which is default with this
These variables need to be overridden when you want to make use of the Zabbix API for automatically creating and or updating proxies, i.e. when `zabbix_api_create_proxy` is set to `True`.
-* `zabbix_api_http_user`: The http user to access zabbix url with Basic Auth.
-* `zabbix_api_http_password`: The http password to access zabbix url with Basic Auth.
* `zabbix_api_server_host`: The IP or hostname/FQDN of Zabbix server. Example: zabbix.example.com
-* `zabbix_api_server_port`: TCP port to use to connect to Zabbix server. Example: 8080
-* `zabbix_api_use_ssl`: yes (Default) if we need to connect to Zabbix server over HTTPS
-* `zabbix_api_validate_certs` : yes (Default) if we need to validate tls certificates of the API. Use `no` in case self-signed certificates are used
+* `zabbix_api_use_ssl`: Is SSL required to connect to the Zabbix API server? Default: `false`
+* `zabbix_api_server_port`: 80 if `zabbix_api_use_ssl` is `false` and 443 if `true` (Default) TCP port to use to connect to Zabbix server. Example: 8080
* `zabbix_api_login_user`: Username of user which has API access.
* `zabbix_api_login_pass`: Password for the user which has API access.
+* `zabbix_api_http_user`: The http user to access zabbix url with Basic Auth (if your Zabbix is behind a proxy with HTTP Basic Auth).
+* `zabbix_api_http_password`: The http password to access zabbix url with Basic Auth (if your Zabbix is behind a proxy with HTTP Basic Auth).
+* `zabbix_api_validate_certs`: yes (Default) if we need to validate tls certificates of the API. Use `no` in case self-signed certificates are used.
+* `zabbix_api_timeout`: timeout for API calls (default to 30 seconds)
* `ansible_zabbix_url_path`: URL path if Zabbix WebUI running on non-default (zabbix) path, e.g. if http://<FQDN>/zabbixeu then set to `zabbixeu`
* `zabbix_api_create_proxy`: When you want to enable the Zabbix API to create/delete the proxy. This has to be set to `True` if you want to make use of `zabbix_proxy_state`. Default: `False`
* `zabbix_proxy_name`: name of the Zabbix proxy as it is seen by Zabbix server
* `zabbix_proxy_state`: present (Default) if the proxy needs to be created or absent if you want to delete it. This only works when `zabbix_api_create_proxy` is set to `True`.
* `zabbix_proxy_status`: active (Default) if the proxy needs to be active or passive.
-* `zabbix_api_timeout`: timeout for API calls (default to 30 seconds)
+
+## Configuration Variables
+
+The following table lists all variables that are exposed to modify the configuration of the zabbix_proxy.conf file. Specific details of each variable can be found in the Zabbix documentation.
+
+**NOTE**: Only variables with a default value appear in the defaults file, all others must be added.
+
+| Zabbix Name | Variable Name | Default Value |Notes |
+|-----------|------------------|--------|--------|
+| AllowRoot | zabbix_proxy_allowroot |0| |
+| AllowUnsupportedDBVersions | zabbix_proxy_allowunsupporteddbversions |0| |
+| CacheSize | zabbix_proxy_cachesize | 8M| |
+| ConfigFrequency | zabbix_proxy_configfrequency |3600| |
+| DataSenderFrequency | zabbix_proxy_datasenderfrequency |1| |
+| DBHost | zabbix_proxy_dbhost | localhost| |
+| DBName | zabbix_proxy_dbname | zabbix_proxy| |
+| DBPassword | zabbix_proxy_dbpassword | zabbix_proxy| |
+| DBSchema | zabbix_proxy_dbschema || |
+| DBSocket | zabbix_proxy_dbsocket || |
+| DBTLSCAFile | zabbix_proxy_dbtlscafile || |
+| DBTLSCertFile | zabbix_proxy_dbtlscertfile || |
+| DBTLSCipher | zabbix_proxy_dbtlscipher || |
+| DBTLSCipher13 | zabbix_proxy_dbtlscipher13 || |
+| DBTLSConnect | zabbix_proxy_dbtlsconnect || |
+| DBTLSKeyFile | zabbix_proxy_dbtlskeyfile || |
+| DBUser | zabbix_proxy_dbuser | zabbix_proxy| |
+| DebugLevel | zabbix_proxy_debuglevel |3| |
+| EnableRemoteCommands | zabbix_proxy_enableremotecommands |0| |
+| ExternalScripts | zabbix_proxy_externalscripts | /usr/lib/zabbix/externalscripts| |
+| Fping6Location | zabbix_proxy_fping6location | OS Specific Value | |
+| FpingLocation | zabbix_proxy_fpinglocation | OS Specific Value | |
+| HeartbeatFrequency | zabbix_proxy_heartbeatfrequency |60| Version 6.2 or Lower|
+| HistoryCacheSize | zabbix_proxy_historycachesize | 8M| |
+| HistoryIndexCacheSize | zabbix_proxy_historyindexcachesize | 4M| |
+| Hostname | zabbix_proxy_hostname | "{{ inventory_hostname }}"| |
+| HostnameItem | zabbix_proxy_hostnameitem || |
+| HousekeepingFrequency | zabbix_proxy_housekeepingfrequency |1| |
+| Include | zabbix_proxy_include | /etc/zabbix/zabbix_proxy.conf.d| |
+| JavaGateway | zabbix_proxy_javagateway || |
+| JavaGatewayPort | zabbix_proxy_javagatewayport |10052| |
+| ListenBacklog | zabbix_proxy_listenbacklog || |
+| ListenIP | zabbix_proxy_listenip || |
+| ListenPort | zabbix_proxy_listenport |10051| |
+| LoadModule | zabbix_proxy_loadmodule || |
+| LoadModulePath | zabbix_proxy_loadmodulepath | /usr/lib/zabbix/modules| |
+| LogFile | zabbix_proxy_logfile | /var/log/zabbix/zabbix_proxy.log| |
+| LogFileSize | zabbix_proxy_logfilesize |10| |
+| LogRemoteCommands | zabbix_proxy_logremotecommands || |
+| LogSlowQueries | zabbix_proxy_logslowqueries || |
+| LogType | zabbix_proxy_logtype | file| |
+| PidFile | zabbix_proxy_pidfile | /var/run/zabbix/zabbix_proxy.pid| |
+| ProxyLocalBuffer | zabbix_proxy_proxylocalbuffer |0| |
+| ProxyMode | zabbix_proxy_proxymode || |
+| ProxyOfflineBuffer | zabbix_proxy_proxyofflinebuffer |1| |
+| Server | zabbix_proxy_server | 192.168.1.1| |
+| SNMPTrapperFile | zabbix_proxy_snmptrapperfile | /tmp/zabbix_traps.tmp| |
+| SocketDir | zabbix_proxy_socketdir | /var/run/zabbix| |
+| SourceIP | zabbix_proxy_sourceip || |
+| SSHKeyLocation | zabbix_proxy_sshkeylocation || |
+| SSLCALocation | zabbix_proxy_sslcalocation || |
+| SSLCertLocation | zabbix_proxy_sslcertlocation || |
+| SSLKeyLocation | zabbix_proxy_sslkeylocation || |
+| StartDBSyncers | zabbix_proxy_startdbsyncers |4| |
+| StartDiscoverers | zabbix_proxy_startdiscoverers |1| |
+| StartHTTPPollers | zabbix_proxy_starthttppollers |1| |
+| StartIPMIPollers | zabbix_proxy_startipmipollers |0| |
+| StartJavaPollers | zabbix_proxy_startjavapollers || |
+| StartODBCPollers | zabbix_proxy_startodbcpollers |1| |
+| StartPingers | zabbix_proxy_startpingers |1| |
+| StartPollers | zabbix_proxy_startpollers |5| |
+| StartPollersUnreachable | zabbix_proxy_startpollersunreachable |1| |
+| StartPreprocessors | zabbix_proxy_startpreprocessors |3| |
+| StartSNMPTrapper | zabbix_proxy_startsnmptrapper || |
+| StartTrappers | zabbix_proxy_starttrappers |5| |
+| StartVMwareCollectors | zabbix_proxy_startvmwarecollectors || |
+| StatsAllowedIP | zabbix_proxy_statsallowedip | "127.0.0.1"| |
+| Timeout | zabbix_proxy_timeout |3| |
+| TLSAccept | zabbix_proxy_tlsaccept || |
+| TLSCAFile | zabbix_proxy_tlscafile || |
+| TLSCertFile | zabbix_proxy_tlscertfile || |
+| TLSCipherAll | zabbix_proxy_tlscipherall || |
+| TLSCipherAll13 | zabbix_proxy_tlscipherall13 || |
+| TLSCipherCert | zabbix_proxy_tlsciphercert || |
+| TLSCipherCert13 | zabbix_proxy_tlsciphercert13 || |
+| TLSCipherPSK | zabbix_proxy_tlscipherpsk || |
+| TLSCipherPSK13 | zabbix_proxy_tlscipherpsk13 || |
+| TLSConnect | zabbix_proxy_tlsconnect || |
+| TLSCRLFile | zabbix_proxy_tlscrlfile || |
+| TLSKeyFile | zabbix_proxy_tlskeyfile || |
+| TLSPSKFile | zabbix_proxy_tlspskfile || |
+| TLSPSKIdentity | zabbix_proxy_tlspskidentity || |
+| TLSServerCertIssuer | zabbix_proxy_tlsservercertissuer || |
+| TLSServerCertSubject | zabbix_proxy_tlsservercertsubject || |
+| TmpDir | zabbix_proxy_tmpdir | /tmp| |
+| TrapperTimeout | zabbix_proxy_trappertimeout |300| |
+| UnavailableDelay | zabbix_proxy_unavailabledelay || |
+| UnreachableDelay | zabbix_proxy_unreachabledelay || |
+| UnreachablePeriod | zabbix_proxy_unreachableperiod |45| |
+| User | zabbix_proxy_user || |
+| Vault | zabbix_proxy_vault || Version 6.2 or Greater |
+| VaultDBPath | zabbix_proxy_vaultdbpath || |
+| VaultTLSCertFile | zabbix_proxy_vaulttlscertfile || Version 6.2 or Greater |
+| VaultTLSKeyFile | zabbix_proxy_vaulttlskeyfile || Version 6.2 or Greater |
+| VaultToken | zabbix_proxy_vaulttoken || |
+| VaultURL | zabbix_proxy_vaulturl |https://127.0.0.1:8200| |
+| VMwareCacheSize | zabbix_proxy_vmwarecachesize | 8M| |
+| VMwareFrequency | zabbix_proxy_vmwarefrequency |60| |
+| VMwarePerfFrequency | zabbix_proxy_vmwareperffrequency | | |
+| VMwareTimeout | zabbix_proxy_vmwaretimeout | | |
+
+## Tags
+
+The majority of tasks within this role are tagged as follows:
+
+* `install`: Tasks associated with the installation of software.
+* `dependencies`: Installation tasks related to dependencies that aren't part of the core zabbix installation.
+* `database`: Tasks associated with the installation or configuration of the database.
+* `api`: Tasks associated with using the Zabbix API to connect and modify the Zabbix server.
+* `config`: Tasks associated with the configuration of Zabbix or a supporting service.
+* `service`: Tasks associated with managing a service.
# Example Playbook
@@ -361,7 +415,6 @@ Including an example of how to use your role (for instance, with variables passe
- role: community.zabbix.zabbix_proxy
zabbix_proxy_server: 192.168.1.1
zabbix_proxy_database: mysql
- zabbix_proxy_database_long: mysql
```
# Molecule
@@ -385,3 +438,4 @@ See LICENCE to see the full text.
Please send suggestion or pull requests to make this role better. Also let us know if you encounter any issues installing or using this role.
Github: https://github.com/ansible-collections/community.zabbix
+
diff --git a/ansible_collections/community/zabbix/docs/ZABBIX_SERVER_ROLE.md b/ansible_collections/community/zabbix/docs/ZABBIX_SERVER_ROLE.md
index 4643fbc3f..f154f4951 100644
--- a/ansible_collections/community/zabbix/docs/ZABBIX_SERVER_ROLE.md
+++ b/ansible_collections/community/zabbix/docs/ZABBIX_SERVER_ROLE.md
@@ -75,26 +75,16 @@ ansible-galaxy collection install community.postgresql
See the following list of supported Operating systems with the Zabbix releases:
-| Zabbix | 6.4 | 6.2 | 6.0 | 5.4 | 5.2 | 5.0 (LTS) | 4.4 | 4.0 (LTS) | 3.0 (LTS) |
-|---------------------|-----|-----|-----|-----|-----|-----------|-----|-----------|-----------|
-| Red Hat Fam 9 | V | V | V | | | | | | |
-| Red Hat Fam 8 | V | V | V | V | V | V | V | | |
-| Red Hat Fam 7 | | | | | | V | V | V | V |
-| Red Hat Fam 6 | | | | | V | V | | | V |
-| Red Hat Fam 5 | | | | | V | V | | | V |
-| Fedora | | | | | | | V | V | |
-| Ubuntu 20.04 focal | V | V | V | V | V | V | | V | |
-| Ubuntu 18.04 bionic | | | V | V | V | V | V | V | |
-| Ubuntu 16.04 xenial | | | | | V | V | V | V | |
-| Ubuntu 14.04 trusty | | | | | V | V | V | V | V |
-| Debian 10 buster | | | V | V | V | V | V | | |
-| Debian 9 stretch | | | V | V | V | V | V | V | |
-| Debian 8 jessie | | | | | V | V | V | V | V |
-| Debian 7 wheezy | | | | | | | | V | V |
-| macOS 10.15 | | | | | | | V | V | |
-| macOS 10.14 | | | | | | | V | V | |
-
-See https://support.zabbix.com/browse/ZBX-18790 why RHEL7 is not supported anymore.
+| Zabbix | 6.4 | 6.2 | 6.0 |
+|---------------------|-----|-----|-----|
+| Red Hat Fam 9 | V | V | V |
+| Red Hat Fam 8 | V | V | V |
+| Ubuntu 22.04 jammy | V | V | V |
+| Ubuntu 20.04 focal | V | V | V |
+| Ubuntu 18.04 bionic | | | V |
+| Debian 12 bookworm | V | | V |
+| Debian 11 bullseye | V | V | V |
+| Debian 10 buster | | | V |
# Installation
@@ -110,112 +100,48 @@ The following is an overview of all available configuration default for this rol
### Overall Zabbix
-* `zabbix_server_version`: This is the version of zabbix. Default: The highest supported version for the operating system. Can be overridden to 6.2, 6.0, 5.4, 5.2, 5.0, 4.4, 4.0, 3.4, 3.2, 3.0, 2.4, or 2.2. Previously the variable `zabbix_version` was used directly but it could cause [some inconvenience](https://github.com/dj-wasabi/ansible-zabbix-agent/pull/303). That variable is maintained by retrocompativility.
+* `zabbix_server_version`: Optional. The latest available major.minor version of Zabbix will be installed on the host(s). If you want to use an older version, please specify this in the major.minor format. Example: `zabbix_server_version: 6.0`.
* `zabbix_server_version_minor`: When you want to specify a minor version to be installed. RedHat only. Default set to: `*` (latest available)
-* `zabbix_repo`: Default: `zabbix`
- * `epel`: install agent from EPEL repo
- * `zabbix`: (default) install agent from Zabbix repo
- * `other`: install agent from pre-existing or other repo
* `zabbix_repo_yum`: A list with Yum repository configuration.
* `zabbix_repo_yum_schema`: Default: `https`. Option to change the web schema for the yum repository(http/https)
-* `zabbix_repo_yum_disabled`: A string with repository names that should be disabled when installing Zabbix component specific packages. Is only used when `zabbix_repo_yum_enabled` contains 1 or more repositories. Default `*`.
-* `zabbix_repo_yum_enabled`: A list with repository names that should be enabled when installing Zabbix component specific packages.
+* `zabbix_server_disable_repo`: A list of repos to disable during install. Default `epel`.
* `zabbix_service_state`: Default: `started`. Can be overridden to stopped if needed
* `zabbix_service_enabled`: Default: `True` Can be overridden to `False` if needed
+* `zabbix_repo_deb_url`: The URL to the Zabbix repository. Default `http://repo.zabbix.com/zabbix/{{ zabbix_server_version }}/{{ ansible_distribution.lower() }}`
+* `zabbix_repo_deb_component`: The repository component for Debian installs. Default `main`.
### SElinux
-* `zabbix_selinux`: Default: `False`. Enables an SELinux policy so that the server will run.
+* `zabbix_server_selinux`: Default: `False`. Enables an SELinux policy so that the server will run.
* `selinux_allow_zabbix_can_network`: Default: `False`.
* `selinux_allow_zabbix_can_http`: Default: `False`.
### Zabbix Server
* `zabbix_server_package_state`: Default: `present`. Can be overridden to `latest` to update packages when needed.
-* `zabbix_server_listenport`: Default: `10051`. On which port the Zabbix Server is available.
* `zabbix_server_install_recommends`: Default: `True`. `False` does not install the recommended packages that come with the zabbix-server install.
* `zabbix_server_manage_service`: Default: `True`. When you run multiple Zabbix servers in a High Available cluster setup (e.g. pacemaker), you don't want Ansible to manage the zabbix-server service, because Pacemaker is in control of zabbix-server service and in this case, it needs to be set to `False`.
-* `zabbix_proxy_startpreprocessors`: Number of pre-forked instances of preprocessing workers. The preprocessing manager process is automatically started when a preprocessor worker is started. This parameter is supported since Zabbix 4.2.0.
-* `zabbix_server_username`: Default: `zabbix`. The name of the account on the host. Will only be used when `zabbix_repo: epel` is used.
-* `zabbix_server_userid`: The UID of the account on the host. Will only be used when `zabbix_repo: epel` is used.
-* `zabbix_server_groupname`: Default: `zabbix`. The name of the group of the user on the host. Will only be used when `zabbix_repo: epel` is used.
-* `zabbix_server_groupid`: The GID of the group on the host. Will only be used when `zabbix_repo: epel` is used.
* `zabbix_server_include_mode`: Default: `0755`. The "mode" for the directory configured with `zabbix_server_include`.
* `zabbix_server_conf_mode`: Default: `0640`. The "mode" for the Zabbix configuration file.
-* `zabbix_server_listenbacklog`: The maximum number of pending connections in the queue.
-* `zabbix_server_trendcachesize`: Size of trend cache, in bytes.
-* `zabbix_server_trendfunctioncachesize`: Size of trend function cache, in bytes.
-* `zabbix_server_vaulttoken`: Vault authentication token that should have been generated exclusively for Zabbix server with read only permission
-* `zabbix_server_vaulturl`: Vault server HTTP[S] URL. System-wide CA certificates directory will be used if SSLCALocation is not specified.
-* `zabbix_server_vaultdbpath`: Vault path from where credentials for database will be retrieved by keys 'password' and 'username'.
-* `zabbix_server_startreportwriters`: Number of pre-forked report writer instances.
-* `zabbix_server_webserviceurl`: URL to Zabbix web service, used to perform web related tasks.
-* `zabbix_server_servicemanagersyncfrequency`: How often Zabbix will synchronize configuration of a service manager (in seconds).
-* `zabbix_server_problemhousekeepingfrequency`: How often Zabbix will delete problems for deleted triggers (in seconds).
-* `zabbix_server_connectors`: Number of pre-forked instances of preprocessing workers.
-
-### High Availability
-
-These variables are specific for Zabbix 6.0 and higher:
-
-* `zabbix_server_hanodename`: The high availability cluster node name. When empty, server is working in standalone mode; a node with empty name is registered with address for the frontend to connect to. (Default: empty)
-* `zabbix_server_nodeaddress`: IP or hostname with optional port to specify how frontend should connect to the server.
### Database specific
* `zabbix_server_dbhost_run_install`: Default: `True`. When set to `True`, sql files will be executed on the host running the database.
* `zabbix_server_database`: Default: `pgsql`. The type of database used. Can be: `mysql` or `pgsql`
-* `zabbix_server_database_long`: Default: `postgresql`. The type of database used, but long name. Can be: `mysql` or `postgresql`
* `zabbix_server_dbhost`: The hostname on which the database is running.
* `zabbix_server_real_dbhost`: The hostname of the dbhost that is running behind a loadbalancer/VIP (loadbalancers doesn't accept ssh connections)
* `zabbix_server_dbname`: The database name which is used by the Zabbix Server.
* `zabbix_server_dbuser`: The database username which is used by the Zabbix Server.
* `zabbix_server_dbpassword`: The database user password which is used by the Zabbix Server.
+* `zabbix_server_dbpassword_hash_method`: Default: `md5`. Allow switching postgresql user password creation to `scram-sha-256`, when anything other than `md5` is used then ansible won't hash the password with `md5`.
* `zabbix_server_dbport`: The database port which is used by the Zabbix Server.
* `zabbix_server_dbpassword_hash_method`: Default: `md5`. Allow switching postgresql user password creation to `scram-sha-256`, when anything other than `md5` is used then ansible won't hash the password with `md5`.
-* `zabbix_database_creation`: Default: `True`. When you don't want to create the database including user, you can set it to False.
+* `zabbix_server_database_creation`: Default: `True`. When you don't want to create the database including user, you can set it to False.
* `zabbix_server_install_database_client`: Default: `True`. False does not install database client. Default true
-* `zabbix_database_sqlload`:True / False. When you don't want to load the sql files into the database, you can set it to False.
-* `zabbix_database_timescaledb`:False / True. When you want to use timescaledb extension into the database, you can set it to True (this option only works for postgreSQL database).
+* `zabbix_server_database_sqlload`:True / False. When you don't want to load the sql files into the database, you can set it to False.
+* `zabbix_server_database_timescaledb`:False / True. When you want to use timescaledb extension into the database, you can set it to True (this option only works for postgreSQL database).
* `zabbix_server_dbencoding`: Default: `utf8`. The encoding for the MySQL database.
* `zabbix_server_dbcollation`: Default: `utf8_bin`. The collation for the MySQL database.
-* `zabbix_server_allowunsupporteddbversions`: Allow server to work with unsupported database versions.
-
-### TLS Specific configuration
-
-These variables are specific for Zabbix 3.0 and higher:
-
-* `zabbix_server_tlsconnect`: How the agent should connect to server or proxy. Used for active checks.
- Possible values:
- * unencrypted
- * psk
- * cert
-* `zabbix_server_tlsaccept`: What incoming connections to accept.
- Possible values:
- * unencrypted
- * psk
- * cert
-* `zabbix_server_tlscafile`: Full pathname of a file containing the top-level CA(s) certificates for peer certificate verification.
-* `zabbix_server_tlscrlfile`: Full pathname of a file containing revoked certificates.
-* `zabbix_server_tlsservercertissuer`: Allowed server certificate issuer.
-* `zabbix_server_tlsservercertsubject`: Allowed server certificate subject.
-* `zabbix_server_tlscertfile`: Full pathname of a file containing the agent certificate or certificate chain.
-* `zabbix_server_tlskeyfile`: Full pathname of a file containing the agent private key.
-* `zabbix_server_dbtlsconnect`: Setting this option enforces to use TLS connection to database:
-
-`required` - connect using TLS
-`verify_ca` - connect using TLS and verify certificate
-`verify_full` - connect using TLS, verify certificate and verify that database identity specified by DBHost matches its certificate
-
-On `MySQL` starting from 5.7.11 and `PostgreSQL` the following values are supported: `required`, `verify`, `verify_full`. On MariaDB starting from version 10.2.6 `required` and `verify_full` values are supported.
-By default not set to any option and the behaviour depends on database configuration.
-This parameter is supported since Zabbix 5.0.0.
-
-* `zabbix_server_dbtlscafile`: Full pathname of a file containing the top-level CA(s) certificates for database certificate verification. This parameter is supported since Zabbix 5.0.0.
-* `zabbix_server_dbtlscertfile`: Full pathname of file containing Zabbix server certificate for authenticating to database. This parameter is supported since Zabbix 5.0.0.
-* `zabbix_server_dbtlskeyfile`: Full pathname of file containing the private key for authenticating to database. This parameter is supported since Zabbix 5.0.0.
-* `zabbix_server_dbtlscipher`: The list of encryption ciphers that Zabbix server permits for TLS protocols up through TLSv1.2. Supported only for MySQL.This parameter is supported since Zabbix 5.0.0.
-* `zabbix_server_dbtlscipher13`: The list of encryption ciphersuites that Zabbix server permits for TLSv1.3 protocol. Supported only for MySQL, starting from version 8.0.16. This parameter is supported since Zabbix 5.0.0.
### Custom Zabbix Scripts
@@ -350,6 +276,135 @@ The `zabbix_server_privileged_host` can be set to the hostname/ip of the host ru
3. Execute the role by running the Ansible playbook that calls this role. At the end of this run, the Zabbix Server with `PgSQL` on a different host will be running.
+## Configuration Variables
+
+The following table lists all variables that are exposed to modify the configuration of the zabbix_server.conf file. Specific details of each variable can be found in the Zabbix documentation.
+
+**NOTE**: Only variables with a default value appear in the defaults file, all others must be added.
+
+| Zabbix Name | Variable Name | Default Value |Notes |
+|-----------|------------------|--------|--------|
+|AlertScriptsPath | zabbix_server_alertscriptspath | /usr/lib/zabbix/alertscripts | |
+|AllowRoot | zabbix_server_allowroot | 0 | |
+|AllowUnsupportedDBVersions | zabbix_server_allowunsupporteddbversions |0 | |
+|CacheSize | zabbix_server_cachesize | | |
+|CacheUpdateFrequency | zabbix_server_cacheupdatefrequency | | |
+|DBHost | zabbix_server_dbhost | localhost | |
+|DBName | zabbix_server_dbname | zabbix-server | |
+|DBPassword | zabbix_server_dbpassword | zabbix-server | |
+|DBPort | zabbix_server_dbport | 5432 | |
+|DBSchema | zabbix_server_dbschema | | |
+|DBSocket | zabbix_server_dbsocket | | |
+|DBTLSCAFile | zabbix_server_dbtlscafile | | |
+|DBTLSCertFile | zabbix_server_dbtlscertfile | | |
+|DBTLSCipher | zabbix_server_dbtlscipher | | |
+|DBTLSCipher13 | zabbix_server_dbtlscipher13 | | |
+|DBTLSConnect | zabbix_server_dbtlsconnect | | |
+|DBTLSKeyFile | zabbix_server_dbtlskeyfile | | |
+|DBUser | zabbix_server_dbuser | zabbix-server | |
+|DebugLevel | zabbix_server_debuglevel | 3 | |
+|ExportDir | zabbix_server_exportdir | | |
+|ExportFileSize | zabbix_server_exportfilesize | 1G | |
+|ExportType | zabbix_server_exporttype | | |
+|ExternalScripts | zabbix_server_externalscriptspath | /usr/lib/zabbix/externalscripts | |
+|Fping6Location | zabbix_server_fping6location | OS Specific Value | |
+|FpingLocation | zabbix_server_fpinglocation | OS Specific Value | |
+|HANodeName | zabbix_server_hanodename | | |
+|HistoryCacheSize | zabbix_server_historycachesize | | |
+|HistoryIndexCacheSize | zabbix_server_historyindexcachesize | | |
+|HistoryStorageDateIndex | zabbix_server_historystoragedateindex | 0 | |
+|HistoryStorageTypes | zabbix_server_historystoragetypes | uint,dbl,str,log,text | |
+|HistoryStorageURL | zabbix_server_historystorageurl | | |
+|HousekeepingFrequency | zabbix_server_housekeepingfrequency | 1 | |
+|Include | zabbix_server_include | /etc/zabbix/zabbix_server.conf.d | |
+|JavaGateway | zabbix_server_javagateway | | |
+|JavaGatewayPort | zabbix_server_javagatewayport | 10052 | |
+|ListenBacklog | zabbix_server_listenbacklog | | |
+|ListenIP | zabbix_server_listenip | | |
+|ListenPort | zabbix_server_listenport | 10051 | |
+|LoadModule | zabbix_server_loadmodule | | |
+|LoadModulePath | zabbix_server_loadmodulepath | ${libdir}/modules | |
+|LogFile | zabbix_server_logfile | /var/log/zabbix/zabbix_server.log | |
+|LogFileSize | zabbix_server_logfilesize | 10 | |
+|LogSlowQueries | zabbix_server_logslowqueries | 0 | |
+|LogType | zabbix_server_logtype | file | |
+|MaxHousekeeperDelete | zabbix_server_maxhousekeeperdelete | 500 | |
+|NodeAddress | zabbix_server_nodeaddress | | |
+|PidFile | zabbix_server_pidfile | /var/run/zabbix/zabbix_server.pid | |
+|ProxyConfigFrequency | zabbix_server_proxyconfigfrequency | | |
+|ProxyDataFrequency | zabbix_server_proxydatafrequency | 1 | |
+|SNMPTrapperFile | zabbix_server_snmptrapperfile | | |
+|SocketDir | zabbix_server_socketdir | /var/run/zabbix | |
+|SourceIP | zabbix_server_sourceip | | |
+|SSHKeyLocation | zabbix_server_sshkeylocation | | |
+|SSLCALocation | zabbix_server_sslcalocation | | |
+|SSLCertLocation | zabbix_server_sslcertlocation | ${datadir}/zabbix/ssl/certs | |
+|SSLKeyLocation | zabbix_server_sslkeylocation | ${datadir}/zabbix/ssl/keys | |
+|StartAlerters | zabbix_server_startalerters | | |
+|StartConnectors | zabbix_server_connectors | | Version 6.4 or later |
+|StartDBSyncers | zabbix_server_startdbsyncers | 4 | |
+|StartDiscoverers | zabbix_server_startdiscoverers | 1 | |
+|StartEscalators | zabbix_server_startescalators | 1 | |
+|StartHistoryPollers | zabbix_server_starthistorypollers | | |
+|StartHTTPPollers | zabbix_server_starthttppollers | 1 | |
+|StartIPMIPollers | zabbix_server_startipmipollers | 0 | |
+|StartJavaPollers | zabbix_server_startjavapollers | 0 | |
+|StartLLDProcessors | zabbix_server_startlldprocessors | | |
+|StartODBCPollers | zabbix_server_startodbcpollers | | |
+|StartPingers | zabbix_server_startpingers | 1 | |
+|StartPollers | zabbix_server_startpollers | 5 | |
+|StartPollersUnreachable | zabbix_server_startpollersunreachable | 1 | |
+|StartPreprocessors | zabbix_server_startpreprocessors | | |
+|StartProxyPollers | zabbix_server_startproxypollers | | |
+|StartReportWriters | zabbix_server_startreportwriters | 0 | |
+|StartSNMPTrapper | zabbix_server_startsnmptrapper | 0 | |
+|StartTimers | zabbix_server_starttimers | 1 | |
+|StartTrappers | zabbix_server_starttrappers | 5 | |
+|StartVMwareCollectors | zabbix_server_startvmwarecollectors | 0 | |
+|StasAllowedIP | zabbix_server_statsallowedip | | |
+|Timeout | zabbix_server_timeout | 3 | |
+|TLSCAFile | zabbix_server_tlscafile | | |
+|TLSCertFile | zabbix_server_tlscertfile | | |
+|TLSCipherAll | zabbix_server_tlscipherall | | |
+|TLSCipherAll13 | zabbix_server_tlscipherall13 | | |
+|TLSCipherCert | zabbix_server_tlsciphercert | | |
+|TLSCipherCert13 | zabbix_server_tlsciphercert13 | | |
+|TLSCipherPSK | zabbix_server_tlscipherpsk | | |
+|TLSCipherPSK13 | zabbix_server_tlscipherpsk13 | | |
+|TLSCRLFile | zabbix_server_tlscrlfile | | |
+|TLSKeyFile | zabbix_server_tlskeyfile | | |
+|TmpDir | zabbix_server_tmpdir | /tmp | |
+|TrapperTimeout | zabbix_server_trappertimeout | 300 | |
+|TrendCacheSize | zabbix_server_trendcachesize | | |
+|TrendFunctionCacheSize | zabbix_server_trendfunctioncachesize | | |
+|UnavailableDelay | zabbix_server_unavailabledelay | 60 | |
+|UnreachableDelay | zabbix_server_unreachabledelay | 15 | |
+|UnreachablePeriod | zabbix_server_unreachableperiod | 45 | |
+|User | zabbix_server_user | zabbix | |
+|ValueCacheSize | zabbix_server_valuecachesize | | |
+|Vault | zabbix_server_vault | | Version 6.2 or later |
+|VaultDBPath | zabbix_server_vaultdbpath | | |
+|VaultTLSKeyFile | zabbix_server_vaulttlskeyfile | | Version 6.2 or later |
+|VaultTLSCertFile | zabbix_server_vaulttlscertfile | | Version 6.2 or later |
+|VaultToken | zabbix_server_vaulttoken | | |
+|VaultURL | zabbix_server_vaulturl | https://127.0.0.1:8200 | |
+|VMwareCacheSize | zabbix_server_vmwarecachesize | | |
+|VMwareFrequency | zabbix_server_vmwarefrequency | 60 | |
+|VMwarePerfFrequency | zabbix_server_vmwareperffrequency | 60 | |
+|VMwareTimeout | zabbix_server_vmwaretimeout | 10 | |
+|WebServiceURL | zabbix_server_webserviceurl | | |
+
+## Tags
+
+The majority of tasks within this role are tagged as follows:
+
+* `install`: Tasks associated with the installation of software.
+* `dependencies`: Installation tasks related to dependencies that aren't part of the core zabbix installation.
+* `database`: Tasks associated with the installation or configuration of the database.
+* `api`: Tasks associated with using the Zabbix API to connect and modify the Zabbix server.
+* `config`: Tasks associated with the configuration of Zabbix or a supporting service.
+* `service`: Tasks associated with managing a service.
+
# Example Playbook
Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
diff --git a/ansible_collections/community/zabbix/docs/ZABBIX_WEB_ROLE.md b/ansible_collections/community/zabbix/docs/ZABBIX_WEB_ROLE.md
index cef5d62e7..5904f8288 100644
--- a/ansible_collections/community/zabbix/docs/ZABBIX_WEB_ROLE.md
+++ b/ansible_collections/community/zabbix/docs/ZABBIX_WEB_ROLE.md
@@ -43,7 +43,7 @@ Please send Pull Requests or suggestions when you want to use this role for othe
## Ansible 2.10 and higher
-With the release of Ansible 2.10, modules have been moved into collections. With the exception of ansible.builtin modules, this means additonal collections must be installed in order to use modules such as seboolean (now ansible.posix.seboolean). The following collections are now required: `ansible.posix`. The `community.general` collection is required when defining the `zabbix_web_htpasswd` variable (see variable section below). Installing the collections:
+With the release of Ansible 2.10, modules have been moved into collections. With the exception of ansible.builtin modules, this means additonal collections must be installed in order to use modules such as seboolean (now ansible.posix.seboolean). The following collections are now required: `ansible.posix`. Installing the collections:
```sh
ansible-galaxy collection install ansible.posix
@@ -54,25 +54,16 @@ ansible-galaxy collection install community.general
See the following list of supported Operating Systems with the Zabbix releases.
-| Zabbix | 6.4 | 6.2 | 6.0 (LTS) | 5.4 | 5.2 | 5.0 (LTS) | 4.4 | 4.0 (LTS) | 3.0 (LTS) |
-|---------------------|-----|-----|-----------|-----|-----|------------|-----|-----------|-----------|
-| Red Hat Fam 9 | V | V | V | | | | | | |
-| Red Hat Fam 8 | V | V | V | V | V | V | V | | |
-| Red Hat Fam 7 | | V | V | V | V | V | V | V | V |
-| Red Hat Fam 6 | | | | | V | V | | | V |
-| Red Hat Fam 5 | | | | | V | V | | | V |
-| Fedora | | | | | | | V | V | |
-| Ubuntu 22.04 jammy | V | V | V | | | | | | |
-| Ubuntu 20.04 focal | V | V | V | V | V | V | V | | |
-| Ubuntu 18.04 bionic | | | V | V | V | V | V | V | |
-| Ubuntu 16.04 xenial | | | | | V | V | V | V | |
-| Ubuntu 14.04 trusty | | | | | V | V | V | V | V |
-| Debian 10 buster | V | V | V | V | V | V | V | | |
-| Debian 9 stretch | | | V | V | V | V | V | V | |
-| Debian 8 jessie | | | | | V | V | V | V | V |
-| Debian 7 wheezy | | | | | | | | V | V |
-| macOS 10.15 | | | | | | | V | V | |
-| macOS 10.14 | | | | | | | V | V | |
+| Zabbix | 6.4 | 6.2 | 6.0 |
+|---------------------|-----|-----|-----|
+| Red Hat Fam 9 | V | V | V |
+| Red Hat Fam 8 | V | V | V |
+| Ubuntu 22.04 jammy | V | V | V |
+| Ubuntu 20.04 focal | V | V | V |
+| Ubuntu 18.04 bionic | | | V |
+| Debian 12 bookworm | V | | V |
+| Debian 11 bullseye | V | V | V |
+| Debian 10 buster | | | V |
# Installation
@@ -93,107 +84,77 @@ The following is an overview of all available configuration defaults for this ro
### Overall Zabbix
-* `zabbix_web_version`: This is the version of zabbix. Default: The highest supported version for the operating system. Can be overridden to 6.2, 6.0, 5.4, 5.2, 5.0, 4.4, 4.0, 3.4, 3.2, 3.0, 2.4, or 2.2. Previously the variable `zabbix_version` was used directly but it could cause [some inconvenience](https://github.com/dj-wasabi/ansible-zabbix-agent/pull/303). That variable is maintained by retrocompativility.
+* `zabbix_web_version`: Optional. The latest available major.minor version of Zabbix will be installed on the host(s). If you want to use an older version, please specify this in the major.minor format. Example: `zabbix_web_version: 6.0`.
* `zabbix_web_version_minor`: When you want to specify a minor version to be installed. RedHat only. Default set to: `*` (latest available)
-* `zabbix_repo`: Default: `zabbix`
- * `epel`: install agent from EPEL repo
- * `zabbix`: (default) install agent from Zabbix repo
- * `other`: install agent from pre-existing or other repo
* `zabbix_repo_yum`: A list with Yum repository configuration.
* `zabbix_repo_yum_schema`: Default: `https`. Option to change the web schema for the yum repository(http/https)
-* `zabbix_repo_yum_disabled`: A string with repository names that should be disabled when installing Zabbix component specific packages. Is only used when `zabbix_repo_yum_enabled` contains 1 or more repositories. Default `*`.
-* `zabbix_repo_yum_enabled`: A list with repository names that should be enabled when installing Zabbix component specific packages.
-
+* `zabbix_web_disable_repo`: A list of repos to disable during install. Default `epel`.
* `zabbix_web_package_state`: Default: `present`. Can be overridden to `latest` to update packages when needed.
-* `zabbix_web_centos_release`: Default: True. When the `centos-release-scl` repository needs to be enabled. This is required when using Zabbix 5.0 due to installation of a recent version of `PHP`.
-* `zabbix_web_rhel_release`: Default: True. When the `scl-utils` repository needs to be enabled. This is required when using Zabbix 5.0 due to installation of a recent version of `PHP`.
* `zabbix_web_doubleprecision`: Default: `False`. For upgraded installations, please read database [upgrade notes](https://www.zabbix.com/documentation/current/manual/installation/upgrade_notes_500) (Paragraph "Enabling extended range of numeric (float) values") before enabling this option.
* `zabbix_web_conf_mode`: Default: `0644`. The "mode" for the Zabbix configuration file.
+* `zabbix_repo_deb_url`: The URL to the Zabbix repository. Default `http://repo.zabbix.com/zabbix/{{ zabbix_web_version }}/{{ ansible_distribution.lower() }}`
+* `zabbix_repo_deb_component`: The repository component for Debian installs. Default `main`.
### Zabbix Web specific
* `zabbix_api_server_url`: This is the url on which the zabbix web interface is available. Default is zabbix.example.com, you should override it. For example, see "Example Playbook"
+* `zabbix_web_http_server`: Which web server is in use. Valid values are 'apache' and 'nginx'. Default is `apache`
* `zabbix_url_aliases`: A list with Aliases for the Apache Virtual Host configuration.
* `zabbix_timezone`: Default: `Europe/Amsterdam`. This is the timezone. The Apache Virtual Host needs this parameter.
-* `zabbix_vhost`: Default: `true`. When you don't want to create an Apache Virtual Host configuration, you can set it to False.
+* `zabbix_web_create_vhost`: Default: `true`. When you don't want to create an Apache Virtual Host configuration, you can set it to False.
+* `zabbix_web_create_php_fpm`: Configure php-fpm (Debian hosts only). Default is to use the same value as `zabbix_web_create_vhost`.
* `zabbix_web_env`: (Optional) A Dictionary of PHP Environments settings.
-* `zabbix_web_conf_web_user`: When provided, the user (which should already exist on the host) will be used for ownership for web/php related processes. (Default set to either `apache` (`www-data` for Debian) or `nginx`).
-* `zabbix_web_conf_web_group`: When provided, the group (which should already exist on the host) will be used for ownership for web/php related processes. (Default set to either `apache` (`www-data` for Debian) or `nginx`).
-* `zabbix_web_htpasswd`: (Optional) Allow HTTP authentication at the webserver level via a htpasswd file.
-* `zabbix_web_htpasswd_file`: Default: `/etc/zabbix/web/htpasswd`. Allows the change the default path to the htpasswd file.
-* `zabbix_web_htpasswd_users`: (Optional) Dictionary for creating users via `htpasswd_user` and passphrases via `htpasswd_pass` in htpasswd file.
-* `zabbix_web_allowlist_ips`: (Optional) Allow web access at webserver level to a list of defined IPs or CIDR.
+* `zabbix_web_user`: When provided, the user (which should already exist on the host) will be used for ownership for web/php related processes. (Default set to either `apache` (`www-data` for Debian) or `nginx`).
+* `zabbix_web_group`: When provided, the group (which should already exist on the host) will be used for ownership for web/php related processes. (Default set to either `apache` (`www-data` for Debian) or `nginx`).
* `zabbix_web_connect_ha_backend`: (Optional) Default: `false`. When set to `true` values for Zabbix server will not be written and frontend gets values from database to connect to active cluster node. Set `true` when operating Zabbix servers in a cluste (only >=6.0).
* `zabbix_saml_idp_crt`: (Optional) The path to the certificate of the Identity Provider used for SAML authentication
* `zabbix_saml_sp_crt`: (Optional) The path to the public certificate of Zabbix as Service Provider
* `zabbix_saml_sp_key`: (Optional) The path to the private certificate of Zabbix as Service Provider
-#### Apache configuration
+#### Apache/Nginx Configuration
-* `zabbix_apache_vhost_port`: The port on which Zabbix HTTP vhost is running.
-* `zabbix_apache_vhost_tls_port`: The port on which Zabbix HTTPS vhost is running.
-* `zabbix_apache_vhost_listen_ip`: On which interface the Apache Virtual Host is available.
+* `zabbix_web_vhost_port`: The port on which Zabbix HTTP vhost is running.
+* `zabbix_web_vhost_tls_port`: The port on which Zabbix HTTPS vhost is running.
+* `zabbix_web_vhost_listen_ip`: On which interface the Apache Virtual Host is available.
* `zabbix_apache_can_connect_ldap`: Default: `false`. Set SELinux boolean to allow httpd to connect to LDAP.
-* `zabbix_php_install`: Default: `true`. True / False. Switch for extra install of packages for PHP, currently on for Debian/Ubuntu.
-* `zabbix_web_max_execution_time`:
-* `zabbix_web_memory_limit`:
-* `zabbix_web_post_max_size`:
-* `zabbix_web_upload_max_filesize`:
+* `zabbix_web_max_execution_time`: PHP max execution time
+* `zabbix_web_memory_limit`: PHP memory limit
+* `zabbix_web_post_max_size`: PHP maximum post size
+* `zabbix_web_upload_max_filesize`: PHP maximum file size
* `zabbix_web_max_input_time`:
-* `zabbix_apache_include_custom_fragment`: Default: `true`. Includes php_value vars max_execution_time, memory_limit, post_max_size, upload_max_filesize, max_input_time and date.timezone in vhost file.. place those in php-fpm configuration.
-* `zabbix_apache_tls`: If the Apache vhost should be configured with TLS encryption or not.
-* `zabbix_apache_redirect`: If a redirect should take place from HTTP to HTTPS
-* `zabbix_apache_tls_crt`: The path to the TLS certificate file.
-* `zabbix_apache_tls_key`: The path to the TLS key file.
-* `zabbix_apache_tls_chain`: The path to the TLS certificate chain file.
-* `zabbix_apache_SSLPassPhraseDialog`: Type of pass phrase dialog for encrypted private keys.
-* `zabbix_apache_SSLSessionCache`: Type of the global/inter-process SSL Session Cache
-* `zabbix_apache_SSLSessionCacheTimeout`: Number of seconds before an SSL session expires in the Session Cache
-* `zabbix_apache_SSLCryptoDevice`: Enable use of a cryptographic hardware accelerator
+* `zabbix_web_tls`: If the Apache vhost should be configured with TLS encryption or not.
+* `zabbix_web_redirect`: If a redirect should take place from HTTP to HTTPS
+* `zabbix_web_tls_crt`: The path to the TLS certificate file.
+* `zabbix_web_tls_key`: The path to the TLS key file.
+* `zabbix_web_tls_chain`: The path to the TLS certificate chain file.
+* `zabbix_web_SSLPassPhraseDialog`: Type of pass phrase dialog for encrypted private keys.
+* `zabbix_web_SSLSessionCache`: Type of the global/inter-process SSL Session Cache
+* `zabbix_web_SSLSessionCacheTimeout`: Number of seconds before an SSL session expires in the Session Cache
+* `zabbix_web_SSLCryptoDevice`: Enable use of a cryptographic hardware accelerator
* `zabbix_apache_custom_includes`: Configure custom includes. Default: `[]`
-When `zabbix_apache_tls_crt`, `zabbix_apache_tls_key` and/or `zabbix_apache_tls_chain` are used, make sure that these files exists before executing this role. The Zabbix-Web role will not install the mentioned files.
+When `zabbix_web_tls_crt`, `zabbix_web_tls_key` and/or `zabbix_web_tls_chain` are used, make sure that these files exists before executing this role. The Zabbix-Web role will not install the mentioned files.
See https://httpd.apache.org/docs/current/mod/mod_ssl.html for SSL* configuration options for Apache HTTPD.
#### Nginx configuration
-* `zabbix_nginx_vhost_port`: The port on which Zabbix HTTP vhost is running.
-* `zabbix_nginx_vhost_tls_port`: The port on which Zabbix HTTPS vhost is running.
-* `zabbix_nginx_tls`: If the Nginx vhost should be configured with TLS encryption or not.
-* `zabbix_nginx_tls_crt`: The path to the TLS certificate file.
-* `zabbix_nginx_tls_key`: The path to the TLS key file.
-* `zabbix_nginx_tls_dhparam`: The path to the TLS DHParam file.
-* `zabbix_nginx_tls_session_cache`: Type of the global/inter-process SSL Session Cache
-* `zabbix_nginx_tls_session_timeout`:
-* `zabbix_nginx_tls_session_tickets`:
-* `zabbix_nginx_tls_protocols`: The TLS Protocols to accept.
-* `zabbix_nginx_tls_ciphers`: The TLS Ciphers to be allowed.
-
-When `zabbix_nginx_tls_crt` and `zabbix_nginx_tls_key` are used, make sure that these files exists before executing this role. The Zabbix-Web role will not install the mentioned files.
#### PHP-FPM
The following properties are specific to Zabbix 5.0 and for the PHP(-FPM) configuration:
-* `zabbix_php_version`: Either `7.3` or `7.4` (Based on the OS Family). When you want to override the PHP Version.
* `zabbix_php_fpm_session`: The directory where sessions will be stored. If none are provided, defaults are used.
* `zabbix_php_fpm_listen`: The path to a socket file or ipaddress:port combination on which PHP-FPM needs to listen. If none are provided, defaults are used.
* `zabbix_php_fpm_conf_listen`: Default: `true`. If we want to configure the `zabbix_php_fpm_listen` in the PHP-FPM configuration file.
* `zabbix_php_fpm_conf_user`: The owner of the socket file (When `zabbix_php_fpm_listen` contains a patch to a socket file).
-* `zabbix_php_fpm_conf_enable_user`: Default: `true`. If we want to configure the owner of the `zabbix_php_fpm_listen` in the PHP-FPM configuration file.
+
* `zabbix_php_fpm_conf_group`: The group of the owner of the socket file (When `zabbix_php_fpm_listen` contains a patch to a socket file).
-* `zabbix_php_fpm_conf_enable_group`: Default: `true`. If we want to configure the group of the `zabbix_php_fpm_listen` in the PHP-FPM configuration file.
-* `zabbix_php_fpm_conf_mode`: The mode for the socket file (When `zabbix_php_fpm_listen` contains a patch to a socket file).
-* `zabbix_php_fpm_conf_enable_mode`: Default: `true`. If we want to configure the mode of the `zabbix_php_fpm_listen` in the PHP-FPM configuration file.
-* `zabbix_php_fpm_dir_etc`: etc HOME root directory of PHP-FPM setup.
-* `zabbix_php_fpm_dir_var`: Var HOME root directory of PHP-FPM setup.
### Zabbix Server
* `zabbix_server_name`: The name of the Zabbix Server.
* `zabbix_server_database`: The type of database used. Can be: mysql or pgsql
-* `zabbix_server_database_long`: The type of database used, but long name. Can be: mysql or postgresql
* `zabbix_server_hostname`: The hostname on which the zabbix-server is running. Default set to: {{ inventory_hostname }}
* `zabbix_server_listenport`: On which port the Zabbix Server is available. Default: 10051
* `zabbix_server_dbhost`: The hostname on which the database is running.
@@ -201,6 +162,7 @@ The following properties are specific to Zabbix 5.0 and for the PHP(-FPM) config
* `zabbix_server_dbuser`: The database username which is used by the Zabbix Server.
* `zabbix_server_dbpassword`: The database user password which is used by the Zabbix Server.
* `zabbix_server_dbport`: The database port which is used by the Zabbix Server.
+* `zabbix_server_dbencryption`: Use encryption with the database connection
The following properties are related when using Elasticsearch for history storage:
@@ -218,6 +180,17 @@ When the target host does not have access to the internet, but you do have a pro
* `zabbix_http_proxy`
* `zabbix_https_proxy`
+## Tags
+
+The majority of tasks within this role are tagged as follows:
+
+* `install`: Tasks associated with the installation of software.
+* `dependencies`: Installation tasks related to dependencies that aren't part of the core zabbix installation.
+* `database`: Tasks associated with the installation or configuration of the database.
+* `api`: Tasks associated with using the Zabbix API to connect and modify the Zabbix server.
+* `config`: Tasks associated with the configuration of Zabbix or a supporting service.
+* `service`: Tasks associated with managing a service.
+
# Example Playbook
There are two ways of using the zabbix-web:
@@ -237,12 +210,12 @@ When there is one host running both Zabbix Server and the Zabbix Web (Running My
- role: geerlingguy.php
- role: community.zabbix.zabbix_server
zabbix_server_database: mysql
- zabbix_server_database_long: mysql
+ zabbix_db_type_long: mysql
zabbix_server_dbport: 3306
- role: community.zabbix.zabbix_web
zabbix_api_server_url: zabbix.mydomain.com
zabbix_server_database: mysql
- zabbix_server_database_long: mysql
+ zabbix_db_type_long: mysql
zabbix_server_dbport: 3306
```
@@ -256,7 +229,7 @@ This is a two host setup. On one host (Named: "zabbix-server") the Zabbix Server
roles:
- role: community.zabbix.zabbix_server
zabbix_server_database: mysql
- zabbix_server_database_long: mysql
+ zabbix_db_type_long: mysql
zabbix_server_dbport: 3306
- hosts: zabbix-web
@@ -268,7 +241,7 @@ This is a two host setup. On one host (Named: "zabbix-server") the Zabbix Server
zabbix_api_server_url: zabbix.mydomain.com
zabbix_server_hostname: zabbix-server
zabbix_server_database: mysql
- zabbix_server_database_long: mysql
+ zabbix_db_type_long: mysql
zabbix_server_dbport: 3306
```
@@ -289,13 +262,13 @@ zabbix.conf.php, for example to add LDAP CA certificates. To do this add a `zabb
php_packages:
- php
- php-fpm
- - php-acpu
+ - php-apcu
- role: geerlingguy.apache-php-fpm
- role: community.zabbix.zabbix_web
zabbix_api_server_url: zabbix.mydomain.com
zabbix_server_hostname: zabbix-server
zabbix_server_database: mysql
- zabbix_server_database_long: mysql
+ zabbix_db_type_long: mysql
zabbix_server_dbport: 3306
zabbix_web_env:
LDAPTLS_CACERT: /etc/ssl/certs/ourcert.pem
diff --git a/ansible_collections/community/zabbix/meta/runtime.yml b/ansible_collections/community/zabbix/meta/runtime.yml
index 3e4fe8b79..fc8aee37e 100644
--- a/ansible_collections/community/zabbix/meta/runtime.yml
+++ b/ansible_collections/community/zabbix/meta/runtime.yml
@@ -1,17 +1,16 @@
---
-requires_ansible: '>=2.9.10'
+requires_ansible: '>=2.12'
action_groups:
zabbix:
- zabbix_action
+ - zabbix_api_info
- zabbix_authentication
- zabbix_autoregister
- zabbix_discovery_rule
- zabbix_globalmacro
- - zabbix_group_facts
- zabbix_group_info
- zabbix_group
- zabbix_host_events_info
- - zabbix_host_facts
- zabbix_host_info
- zabbix_hostmacro
- zabbix_host
@@ -21,11 +20,13 @@ action_groups:
- zabbix_mediatype
- zabbix_proxy_info
- zabbix_proxy
- - zabbix_screen
+ - zabbix_regexp
- zabbix_script
- zabbix_service
+ - zabbix_settings
- zabbix_template_info
- zabbix_template
+ - zabbix_token
- zabbix_user_directory
- zabbix_usergroup
- zabbix_user_info
diff --git a/ansible_collections/community/zabbix/molecule/requirements.txt b/ansible_collections/community/zabbix/molecule/requirements.txt
index bec205a0a..b7cbb1138 100644
--- a/ansible_collections/community/zabbix/molecule/requirements.txt
+++ b/ansible_collections/community/zabbix/molecule/requirements.txt
@@ -1,11 +1,13 @@
# Install CI dependencies for the Zabbix Roles
ansible==7.0.0
-ansible-compat==0.5.0
+ansible-compat==3.0.0
ansible-core==2.14.2
-docker==5.0.2
-molecule==3.5.1
-molecule-docker==1.0.2
+docker==6.1.3
+molecule==4.0.4
+molecule-docker==2.1.0
netaddr==0.8.0
-pytest-testinfra==6.1.0
+pytest==7.2.1
+pytest-testinfra==7.0.0
ipaddr==2.2.0
ipaddress==1.0.23
+requests==2.31.0
diff --git a/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/common/molecule.yml b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/common/molecule.yml
index a0222246f..a48b6ae60 100644
--- a/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/common/molecule.yml
+++ b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/common/molecule.yml
@@ -4,8 +4,8 @@ driver:
platforms:
- name: zabbix-agent-${MY_MOLECULE_CONTAINER:-centos}
- image: ${MY_MOLECULE_IMAGE:-"geerlingguy/docker-centos8-ansible"}
- command: ${MY_MOLECULE_DOCKER_COMMAND:-""}
+ image: geerlingguy/docker-${MY_MOLECULE_IMAGE:-rockylinux8}-ansible:latest
+ command: ${MOLECULE_DOCKER_COMMAND:-""}
privileged: true
pre_build_image: true
networks:
@@ -14,11 +14,10 @@ platforms:
- /sys/fs/cgroup:/sys/fs/cgroup:ro
groups:
- agent
+ - ${MY_MOLECULE_VERSION:-v64}
provisioner:
name: ansible
- lint:
- name: ansible-lint
playbooks:
prepare: ../../common/playbooks/prepare.yml
converge: ../../common/playbooks/converge.yml
@@ -36,11 +35,15 @@ provisioner:
zabbix_agent_listenip: 0.0.0.0
zabbix_agent_tlsconnect: psk
zabbix_agent_tlsaccept: psk
-
+ v64:
+ zabbix_agent_version: 6.4
+ v62:
+ zabbix_agent_version: 6.2
+ v60:
+ zabbix_agent_version: 6.0
scenario:
test_sequence:
- dependency
- - lint
- cleanup
- destroy
- syntax
@@ -54,5 +57,3 @@ scenario:
- destroy
verifier:
name: testinfra
- lint:
- name: flake8
diff --git a/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/common/playbooks/prepare.yml b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/common/playbooks/prepare.yml
index 3ce015db6..cf1100aab 100644
--- a/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/common/playbooks/prepare.yml
+++ b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/common/playbooks/prepare.yml
@@ -3,7 +3,7 @@
hosts: all
tasks:
- name: "Installing packages on CentOS family"
- package:
+ ansible.builtin.package:
pkg:
- net-tools
- which
@@ -14,7 +14,7 @@
- ansible_os_family == 'RedHat'
- name: "Installing packages on CentOS (Sangoma) family"
- package:
+ ansible.builtin.package:
pkg:
- net-tools
- which
@@ -25,7 +25,7 @@
- ansible_os_family == 'Sangoma'
- name: "Installing packages on Debian family"
- apt:
+ ansible.builtin.apt:
name:
- "{{ 'net-tools' if ansible_distribution_major_version not in ['10','18', '20'] else 'iproute2' }}"
state: present
@@ -36,7 +36,7 @@
- ansible_os_family == 'Debian'
- name: "Installing packages on Suse family"
- shell: zypper install -y python-xml python-libxml2 net-tools which
+ ansible.builtin.shell: zypper install -y python-xml python-libxml2 net-tools which
register: zabbix_agent_prepare_packages_install
until: zabbix_agent_prepare_packages_install is succeeded
when: ansible_os_family == 'Suse'
@@ -47,7 +47,7 @@
hosts: docker
tasks:
- name: "Download Docker CE repo file"
- get_url:
+ ansible.builtin.get_url:
url: https://download.docker.com/linux/centos/docker-ce.repo
dest: /etc/yum.repos.d/docker-ce.repo
mode: 0644
@@ -55,7 +55,7 @@
until: zabbix_agent_prepare_docker_repo is succeeded
- name: "Installing Epel"
- package:
+ ansible.builtin.package:
pkg:
- epel-release
state: present
@@ -63,7 +63,7 @@
until: zabbix_agent_prepare_docker_install is succeeded
- name: "Installing Docker"
- package:
+ ansible.builtin.package:
pkg:
- docker-ce
- python-pip
@@ -73,7 +73,7 @@
until: zabbix_agent_prepare_docker_install is succeeded
- name: "Installing Docker Python"
- pip:
+ ansible.builtin.pip:
name:
- docker
state: present
@@ -81,6 +81,6 @@
until: zabbix_agent_prepare_docker_install is succeeded
- name: "Starting Docker service"
- service:
+ ansible.builtin.service:
name: docker
state: started
diff --git a/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/common/tests/common/test_agent.py b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/common/tests/common/test_agent.py
index 96d4a1716..43d9fe244 100644
--- a/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/common/tests/common/test_agent.py
+++ b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/common/tests/common/test_agent.py
@@ -37,13 +37,13 @@ def test_socket(host):
assert host.socket("tcp://0.0.0.0:10050").is_listening
-def test_zabbix_package(host, zabbix_agent_package):
- assert zabbix_agent_package.is_installed
-
- if host.system_info.distribution == "debian":
- if host.system_info.codename in ["bullseye", "focal"]:
- assert zabbix_agent_package.version.startswith("1:6.4")
- else:
- assert zabbix_agent_package.version.startswith("1:6.0")
- if host.system_info.distribution == "centos":
- assert zabbix_agent_package.version.startswith("6.4")
+# def test_zabbix_package(host, zabbix_agent_package):
+# assert zabbix_agent_package.is_installed
+
+# if host.system_info.distribution == "debian":
+# if host.system_info.codename in ["bullseye", "focal"]:
+# assert zabbix_agent_package.version.startswith("1:6.4")
+# else:
+# assert zabbix_agent_package.version.startswith("1:6.0")
+# if host.system_info.distribution == "centos":
+# assert zabbix_agent_package.version.startswith("6.4")
diff --git a/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/agent2/tests/common/test_agent.py b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/agent2/tests/common/test_agent.py
index 96d4a1716..43d9fe244 100644
--- a/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/agent2/tests/common/test_agent.py
+++ b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/agent2/tests/common/test_agent.py
@@ -37,13 +37,13 @@ def test_socket(host):
assert host.socket("tcp://0.0.0.0:10050").is_listening
-def test_zabbix_package(host, zabbix_agent_package):
- assert zabbix_agent_package.is_installed
-
- if host.system_info.distribution == "debian":
- if host.system_info.codename in ["bullseye", "focal"]:
- assert zabbix_agent_package.version.startswith("1:6.4")
- else:
- assert zabbix_agent_package.version.startswith("1:6.0")
- if host.system_info.distribution == "centos":
- assert zabbix_agent_package.version.startswith("6.4")
+# def test_zabbix_package(host, zabbix_agent_package):
+# assert zabbix_agent_package.is_installed
+
+# if host.system_info.distribution == "debian":
+# if host.system_info.codename in ["bullseye", "focal"]:
+# assert zabbix_agent_package.version.startswith("1:6.4")
+# else:
+# assert zabbix_agent_package.version.startswith("1:6.0")
+# if host.system_info.distribution == "centos":
+# assert zabbix_agent_package.version.startswith("6.4")
diff --git a/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/agent2autopsk/tests/common/test_agent.py b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/agent2autopsk/tests/common/test_agent.py
index 96d4a1716..43d9fe244 100644
--- a/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/agent2autopsk/tests/common/test_agent.py
+++ b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/agent2autopsk/tests/common/test_agent.py
@@ -37,13 +37,13 @@ def test_socket(host):
assert host.socket("tcp://0.0.0.0:10050").is_listening
-def test_zabbix_package(host, zabbix_agent_package):
- assert zabbix_agent_package.is_installed
-
- if host.system_info.distribution == "debian":
- if host.system_info.codename in ["bullseye", "focal"]:
- assert zabbix_agent_package.version.startswith("1:6.4")
- else:
- assert zabbix_agent_package.version.startswith("1:6.0")
- if host.system_info.distribution == "centos":
- assert zabbix_agent_package.version.startswith("6.4")
+# def test_zabbix_package(host, zabbix_agent_package):
+# assert zabbix_agent_package.is_installed
+
+# if host.system_info.distribution == "debian":
+# if host.system_info.codename in ["bullseye", "focal"]:
+# assert zabbix_agent_package.version.startswith("1:6.4")
+# else:
+# assert zabbix_agent_package.version.startswith("1:6.0")
+# if host.system_info.distribution == "centos":
+# assert zabbix_agent_package.version.startswith("6.4")
diff --git a/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/autopsk/tests/common/test_agent.py b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/autopsk/tests/common/test_agent.py
index 96d4a1716..43d9fe244 100644
--- a/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/autopsk/tests/common/test_agent.py
+++ b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/autopsk/tests/common/test_agent.py
@@ -37,13 +37,13 @@ def test_socket(host):
assert host.socket("tcp://0.0.0.0:10050").is_listening
-def test_zabbix_package(host, zabbix_agent_package):
- assert zabbix_agent_package.is_installed
-
- if host.system_info.distribution == "debian":
- if host.system_info.codename in ["bullseye", "focal"]:
- assert zabbix_agent_package.version.startswith("1:6.4")
- else:
- assert zabbix_agent_package.version.startswith("1:6.0")
- if host.system_info.distribution == "centos":
- assert zabbix_agent_package.version.startswith("6.4")
+# def test_zabbix_package(host, zabbix_agent_package):
+# assert zabbix_agent_package.is_installed
+
+# if host.system_info.distribution == "debian":
+# if host.system_info.codename in ["bullseye", "focal"]:
+# assert zabbix_agent_package.version.startswith("1:6.4")
+# else:
+# assert zabbix_agent_package.version.startswith("1:6.0")
+# if host.system_info.distribution == "centos":
+# assert zabbix_agent_package.version.startswith("6.4")
diff --git a/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/default/tests/common/test_agent.py b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/default/tests/common/test_agent.py
index 96d4a1716..43d9fe244 100644
--- a/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/default/tests/common/test_agent.py
+++ b/ansible_collections/community/zabbix/molecule/zabbix_agent_tests/molecule/default/tests/common/test_agent.py
@@ -37,13 +37,13 @@ def test_socket(host):
assert host.socket("tcp://0.0.0.0:10050").is_listening
-def test_zabbix_package(host, zabbix_agent_package):
- assert zabbix_agent_package.is_installed
-
- if host.system_info.distribution == "debian":
- if host.system_info.codename in ["bullseye", "focal"]:
- assert zabbix_agent_package.version.startswith("1:6.4")
- else:
- assert zabbix_agent_package.version.startswith("1:6.0")
- if host.system_info.distribution == "centos":
- assert zabbix_agent_package.version.startswith("6.4")
+# def test_zabbix_package(host, zabbix_agent_package):
+# assert zabbix_agent_package.is_installed
+
+# if host.system_info.distribution == "debian":
+# if host.system_info.codename in ["bullseye", "focal"]:
+# assert zabbix_agent_package.version.startswith("1:6.4")
+# else:
+# assert zabbix_agent_package.version.startswith("1:6.0")
+# if host.system_info.distribution == "centos":
+# assert zabbix_agent_package.version.startswith("6.4")
diff --git a/ansible_collections/community/zabbix/molecule/zabbix_javagateway/molecule.yml b/ansible_collections/community/zabbix/molecule/zabbix_javagateway/molecule.yml
index f56745b9b..ee072707d 100644
--- a/ansible_collections/community/zabbix/molecule/zabbix_javagateway/molecule.yml
+++ b/ansible_collections/community/zabbix/molecule/zabbix_javagateway/molecule.yml
@@ -3,25 +3,35 @@ driver:
name: docker
platforms:
- - name: zabbix-javagateway-${MY_MOLECULE_CONTAINER:-centos}
- image: ${MY_MOLECULE_IMAGE:-"geerlingguy/docker-centos8-ansible"}
- command: ${MY_MOLECULE_DOCKER_COMMAND:-""}
+ - name: zabbix-server-${MY_MOLECULE_CONTAINER:-centos}
+ image: geerlingguy/docker-${MY_MOLECULE_IMAGE:-rockylinux8}-ansible:latest
privileged: true
pre_build_image: true
+ command: ${MOLECULE_DOCKER_COMMAND:-""}
networks:
- name: zabbix
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup:ro
-
+ groups:
+ - ${MY_MOLECULE_VERSION:-v64}
+ - ${MY_MOLECULE_INTERPRETER:-python3}
provisioner:
name: ansible
- lint:
- name: ansible-lint
env:
ANSIBLE_COLLECTIONS_PATHS: $HOME/.ansible/collections/ansible_collections/community/zabbix
ANSIBLE_ROLES_PATH: $HOME/.ansible/collections/ansible_collections/community/zabbix/roles
+ inventory:
+ group_vars:
+ python3:
+ ansible_python_interpreter: /usr/bin/python3
+ python:
+ ansible_python_interpreter: /usr/bin/python
+ v64:
+ zabbix_javagateway_version: 6.4
+ v62:
+ zabbix_javagateway_version: 6.2
+ v60:
+ zabbix_javagateway_version: 6.0
verifier:
name: testinfra
- lint:
- name: flake8
diff --git a/ansible_collections/community/zabbix/molecule/zabbix_javagateway/prepare.yml b/ansible_collections/community/zabbix/molecule/zabbix_javagateway/prepare.yml
index 9d24c9f7e..3e3db6a1b 100644
--- a/ansible_collections/community/zabbix/molecule/zabbix_javagateway/prepare.yml
+++ b/ansible_collections/community/zabbix/molecule/zabbix_javagateway/prepare.yml
@@ -2,13 +2,12 @@
- name: Prepare
hosts: all
pre_tasks:
-
- name: "Set short version name"
- set_fact:
+ ansible.builtin.set_fact:
zabbix_python_prefix: "python{% if ansible_python_version is version('3', '>=') %}3{% endif %}"
- name: "Installing packages on CentOS"
- yum:
+ ansible.builtin.yum:
name:
- net-tools
- which
@@ -20,21 +19,21 @@
- ansible_os_family == 'RedHat'
- name: "Make sure the docs can be installed. (Debian)"
- lineinfile:
+ ansible.builtin.lineinfile:
path: /etc/dpkg/dpkg.cfg.d/excludes
state: absent
- regexp: 'path-exclude=/usr/share/doc/*'
+ regexp: "path-exclude=/usr/share/doc/*"
when:
- ansible_os_family != 'RedHat'
- name: Check if warn parameter can be used for shell module
- set_fact:
+ ansible.builtin.set_fact:
produce_warn: False
when: ansible_version.full is version("2.14", "<")
# https://github.com/geerlingguy/ansible-role-java/issues/64
- name: "Apt update"
- shell: "apt-get update && mkdir -p /usr/share/man/man1"
+ ansible.builtin.shell: "apt-get update && mkdir -p /usr/share/man/man1"
args:
warn: "{{ produce_warn | default(omit) }}"
register: installation_dependencies
@@ -43,7 +42,7 @@
- ansible_os_family != 'RedHat'
- name: "Installing packages on NON-CentOS"
- apt:
+ ansible.builtin.apt:
name:
- net-tools
- apt-utils
@@ -53,7 +52,6 @@
- "{{ zabbix_python_prefix }}-apt"
- sudo
- software-properties-common
- - openjdk-11-jdk
update_cache: true
state: present
register: installation_dependencies
diff --git a/ansible_collections/community/zabbix/molecule/zabbix_proxy/molecule.yml b/ansible_collections/community/zabbix/molecule/zabbix_proxy/molecule.yml
index 21ab813c4..4eb173acf 100644
--- a/ansible_collections/community/zabbix/molecule/zabbix_proxy/molecule.yml
+++ b/ansible_collections/community/zabbix/molecule/zabbix_proxy/molecule.yml
@@ -1,43 +1,51 @@
---
-
driver:
name: docker
platforms:
- - name: zabbix-proxy-${MY_MOLECULE_CONTAINER:-mysql-centos}
- image: ${MY_MOLECULE_IMAGE:-"geerlingguy/docker-centos8-ansible"}
- command: ${MY_MOLECULE_DOCKER_COMMAND:-""}
+ - name: zabbix-proxy-${MY_MOLECULE_CONTAINER:-centos}
+ image: geerlingguy/docker-${MY_MOLECULE_IMAGE:-rockylinux8}-ansible:latest
privileged: true
pre_build_image: true
+ command: ${MOLECULE_DOCKER_COMMAND:-""}
networks:
- name: zabbix
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup:ro
groups:
- - ${MY_MOLECULE_GROUP:-mysql}
+ - ${MY_MOLECULE_DATABASE:-mysql}
+ - ${MY_MOLECULE_VERSION:-v64}
provisioner:
name: ansible
- lint:
- name: ansible-lint
env:
ANSIBLE_COLLECTIONS_PATHS: $HOME/.ansible/collections/ansible_collections/community/zabbix
ANSIBLE_ROLES_PATH: $HOME/.ansible/collections/ansible_collections/community/zabbix/roles
inventory:
group_vars:
+ python3:
+ ansible_python_interpreter: /usr/bin/python3
+ python:
+ ansible_python_interpreter: /usr/bin/python
+ v64:
+ zabbix_proxy_version: 6.4
+ v62:
+ zabbix_proxy_version: 6.2
+ v60:
+ zabbix_proxy_version: 6.0
mysql:
+ zabbix_proxy_dbname: zabbix
+ zabbix_proxy_dbuser: zabbix-dbuser
zabbix_proxy_database: mysql
- zabbix_proxy_database_long: mysql
zabbix_proxy_dbport: 3306
zabbix_proxy_dbhost: mysql-host
zabbix_proxy_dbhost_run_install: false
- zabbix_proxy_privileged_host: '%'
+ zabbix_proxy_privileged_host: "%"
zabbix_proxy_mysql_login_host: mysql-host
zabbix_proxy_mysql_login_user: root
zabbix_proxy_mysql_login_password: changeme
zabbix_proxy_mysql_login_port: 3306
- postgresql:
+ pgsql:
zabbix_proxy_database: pgsql
- zabbix_proxy_database_long: postgresql
zabbix_proxy_dbport: 5432
zabbix_proxy_dbhost: postgresql-host
zabbix_proxy_dbhost_run_install: false
@@ -49,8 +57,5 @@ provisioner:
zabbix_proxy_database: sqlite3
zabbix_proxy_database_long: sqlite3
zabbix_proxy_dbname: /path/to/sqlite3.db
-
verifier:
name: testinfra
- lint:
- name: flake8
diff --git a/ansible_collections/community/zabbix/molecule/zabbix_proxy/prepare.yml b/ansible_collections/community/zabbix/molecule/zabbix_proxy/prepare.yml
index 0fc4ef320..c5e3b9e45 100644
--- a/ansible_collections/community/zabbix/molecule/zabbix_proxy/prepare.yml
+++ b/ansible_collections/community/zabbix/molecule/zabbix_proxy/prepare.yml
@@ -3,7 +3,6 @@
hosts: localhost
connection: local
pre_tasks:
-
- name: "Create MySQL Container"
docker_container:
name: mysql-host
@@ -32,14 +31,13 @@
no_log: true
with_items: "{{ molecule_yml.platforms }}"
when:
- - '"postgresql" in item.groups'
+ - '"pgsql" in item.groups'
- name: Prepare
hosts: all
tasks:
-
- name: "Set short version name"
- set_fact:
+ ansible.builtin.set_fact:
zabbix_python_prefix: "python{% if ansible_python_version is version('3', '>=') %}3{% endif %}"
- name: "Create group for imaginary host"
@@ -51,7 +49,7 @@
changed_when: false
- name: "Installing packages on CentOS"
- yum:
+ ansible.builtin.yum:
name:
- net-tools
- which
@@ -62,24 +60,13 @@
when:
- ansible_os_family == 'RedHat'
- - name: "Installing packages on CentOS"
- yum:
- name:
- - mysql
- state: present
- register: installation_dependencies
- until: installation_dependencies is succeeded
- when:
- - ansible_os_family == 'RedHat'
- - inventory_hostname in groups['mysql']
-
- name: Check if warn parameter can be used for shell module
- set_fact:
+ ansible.builtin.set_fact:
produce_warn: False
when: ansible_version.full is version("2.14", "<")
- name: "Apt update"
- shell: "apt-get update && echo exit 0 > /usr/sbin/policy-rc.d"
+ ansible.builtin.shell: "apt-get update && echo exit 0 > /usr/sbin/policy-rc.d"
args:
warn: "{{ produce_warn | default(omit) }}"
register: installation_dependencies
@@ -88,7 +75,7 @@
- ansible_os_family != 'RedHat'
- name: "Installing packages on NON-CentOS"
- apt:
+ ansible.builtin.apt:
name:
- net-tools
- apt-utils
@@ -104,13 +91,13 @@
- ansible_os_family != 'RedHat'
- name: "Configure SUDO."
- lineinfile:
+ ansible.builtin.lineinfile:
dest: /etc/sudoers
line: "Defaults !requiretty"
state: present
- name: "Make sure the docs can be installed. (RedHat)"
- lineinfile:
+ ansible.builtin.lineinfile:
dest: /etc/yum.conf
line: "tsflags=nodocs"
state: absent
@@ -118,17 +105,9 @@
- ansible_os_family == 'RedHat'
- name: "Make sure the docs can be installed. (Debian)"
- lineinfile:
+ ansible.builtin.lineinfile:
path: /etc/dpkg/dpkg.cfg.d/excludes
state: absent
- regexp: 'path-exclude=/usr/share/doc/*'
+ regexp: "path-exclude=/usr/share/doc/*"
when:
- ansible_os_family != 'RedHat'
-
- - name: PyMySQL
- pip:
- name: PyMySQL
- register: installation_dependencies
- until: installation_dependencies is succeeded
- when:
- - inventory_hostname in groups['mysql']
diff --git a/ansible_collections/community/zabbix/molecule/zabbix_proxy/tests/test_default.py b/ansible_collections/community/zabbix/molecule/zabbix_proxy/tests/test_default.py
index 4ccbfeb4e..f96874740 100644
--- a/ansible_collections/community/zabbix/molecule/zabbix_proxy/tests/test_default.py
+++ b/ansible_collections/community/zabbix/molecule/zabbix_proxy/tests/test_default.py
@@ -17,28 +17,18 @@ def test_zabbixproxy_running_and_enabled(host):
assert zabbix.is_running
-@pytest.mark.parametrize(
- "proxy", [("zabbix-proxy-pgsql"), ("zabbix-proxy-mysql"), ("zabbix-proxy-sqlite3")]
-)
-def test_zabbix_package(host, proxy):
+def test_zabbix_package(host):
ansible_data = host.ansible.get_variables()
- zabbixhost = ansible_data["inventory_hostname"]
+ version = ansible_data['zabbix_proxy_version']
+ database = ansible_data['zabbix_proxy_database']
- zabbixhost = zabbixhost.replace("-centos", "")
- zabbixhost = zabbixhost.replace("-debian", "")
- zabbixhost = zabbixhost.replace("-ubuntu", "")
-
- if zabbixhost == proxy:
- zabbix_proxy = host.package(proxy)
- if host.system_info.distribution in ["debian", "ubuntu"]:
- assert zabbix_proxy.version.startswith("1:6.4")
- elif host.system_info.distribution == "centos":
- assert zabbix_proxy.version.startswith("6.4")
- assert zabbix_proxy.is_installed
+ zabbix_proxy = host.package(f'zabbix-proxy-%s' % database)
+ assert str(version) in zabbix_proxy.version
def test_zabbix_proxy_dot_conf(host):
zabbix_proxy_conf = host.file("/etc/zabbix/zabbix_proxy.conf")
+ assert zabbix_proxy_conf.exists
assert zabbix_proxy_conf.user == "zabbix"
assert zabbix_proxy_conf.group == "zabbix"
assert zabbix_proxy_conf.mode == 0o644
@@ -52,13 +42,13 @@ def test_zabbix_include_dir(host):
assert zabbix_include_dir.is_directory
assert zabbix_include_dir.user == "zabbix"
assert zabbix_include_dir.group == "zabbix"
- # assert zabbix_include_dir.mode == 0o644
def test_zabbix_proxy_logfile(host):
zabbix_logfile = host.file("/var/log/zabbix/zabbix_proxy.log")
-
+ assert zabbix_logfile.exists
assert not zabbix_logfile.contains("Access denied for user")
assert not zabbix_logfile.contains("database is down: reconnecting")
+ assert not zabbix_logfile.contains("Both are missing in the system.") # Missing fping
assert zabbix_logfile.contains("current database version")
assert zabbix_logfile.contains(r"proxy #0 started \[main process\]")
diff --git a/ansible_collections/community/zabbix/molecule/zabbix_server/molecule.yml b/ansible_collections/community/zabbix/molecule/zabbix_server/molecule.yml
index 4fa0a8daa..2424455f4 100644
--- a/ansible_collections/community/zabbix/molecule/zabbix_server/molecule.yml
+++ b/ansible_collections/community/zabbix/molecule/zabbix_server/molecule.yml
@@ -1,43 +1,54 @@
---
-
driver:
name: docker
platforms:
- - name: zabbix-server-${MY_MOLECULE_CONTAINER:-mysql-centos}
- image: ${MY_MOLECULE_IMAGE:-"geerlingguy/docker-centos8-ansible"}
- command: ${MY_MOLECULE_DOCKER_COMMAND:-""}
+ - name: zabbix-server-${MY_MOLECULE_CONTAINER:-centos}
+ image: geerlingguy/docker-${MY_MOLECULE_IMAGE:-rockylinux8}-ansible:latest
privileged: true
pre_build_image: true
+ command: ${MOLECULE_DOCKER_COMMAND:-""}
networks:
- name: zabbix
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup:ro
groups:
- - ${MY_MOLECULE_GROUP:-mysql}
+ - ${MY_MOLECULE_DATABASE:-mysql}
+ - ${MY_MOLECULE_VERSION:-v64}
+ - ${MY_MOLECULE_INTERPRETER:-python3}
provisioner:
name: ansible
- lint:
- name: ansible-lint
env:
ANSIBLE_COLLECTIONS_PATHS: $HOME/.ansible/collections/ansible_collections/community/zabbix
ANSIBLE_ROLES_PATH: $HOME/.ansible/collections/ansible_collections/community/zabbix/roles
inventory:
group_vars:
+ python3:
+ ansible_python_interpreter: /usr/bin/python3
+ python:
+ ansible_python_interpreter: /usr/bin/python
+ v64:
+ zabbix_server_version: 6.4
+ v62:
+ zabbix_server_version: 6.2
+ v60:
+ zabbix_server_version: 6.0
+ v50:
+ zabbix_server_version: 5.0
mysql:
+ zabbix_server_dbname: zabbix
+ zabbix_server_dbuser: zabbix-dbuser
zabbix_server_database: mysql
- zabbix_server_database_long: mysql
zabbix_server_dbport: 3306
zabbix_server_dbhost: mysql-host
zabbix_server_dbhost_run_install: false
- zabbix_server_privileged_host: '%'
+ zabbix_server_privileged_host: "%"
zabbix_server_mysql_login_host: mysql-host
zabbix_server_mysql_login_user: root
zabbix_server_mysql_login_password: changeme
zabbix_server_mysql_login_port: 3306
- postgresql:
+ pgsql:
zabbix_server_database: pgsql
- zabbix_server_database_long: postgresql
zabbix_server_dbport: 5432
zabbix_server_dbhost: postgresql-host
zabbix_server_dbhost_run_install: false
@@ -48,5 +59,3 @@ provisioner:
verifier:
name: testinfra
- lint:
- name: flake8
diff --git a/ansible_collections/community/zabbix/molecule/zabbix_server/prepare.yml b/ansible_collections/community/zabbix/molecule/zabbix_server/prepare.yml
index 51945c066..922b33753 100644
--- a/ansible_collections/community/zabbix/molecule/zabbix_server/prepare.yml
+++ b/ansible_collections/community/zabbix/molecule/zabbix_server/prepare.yml
@@ -3,11 +3,10 @@
hosts: localhost
connection: local
pre_tasks:
-
- name: "Create MySQL Container"
docker_container:
name: mysql-host
- image: mysql:8.0
+ image: mysql:8.0.32
state: started
recreate: true
networks:
@@ -32,12 +31,11 @@
no_log: true
with_items: "{{ molecule_yml.platforms }}"
when:
- - '"postgresql" in item.groups'
+ - '"pgsql" in item.groups'
- name: Prepare
hosts: all
tasks:
-
- name: "Create group for imaginary host"
add_host:
name: imaginary-host
@@ -47,7 +45,7 @@
changed_when: false
- name: "Installing packages on CentOS"
- yum:
+ ansible.builtin.yum:
name:
- net-tools
- which
@@ -59,7 +57,7 @@
- ansible_os_family == 'RedHat'
- name: "Installing packages on CentOS"
- yum:
+ ansible.builtin.yum:
name:
- mysql
state: present
@@ -70,12 +68,12 @@
- inventory_hostname in groups['mysql']
- name: Check if warn parameter can be used for shell module
- set_fact:
- produce_warn: False
+ ansible.builtin.set_fact:
+ produce_warn: false
when: ansible_version.full is version("2.14", "<")
- name: "Apt update"
- shell: "apt-get update && echo exit 0 > /usr/sbin/policy-rc.d"
+ ansible.builtin.shell: "apt-get update && echo exit 0 > /usr/sbin/policy-rc.d"
args:
warn: "{{ produce_warn | default(omit) }}"
register: installation_dependencies
@@ -84,7 +82,7 @@
- ansible_os_family != 'RedHat'
- name: "Installing packages on NON-CentOS"
- apt:
+ ansible.builtin.apt:
name:
- net-tools
- apt-utils
@@ -99,13 +97,13 @@
- ansible_os_family != 'RedHat'
- name: "Configure SUDO."
- lineinfile:
+ ansible.builtin.lineinfile:
dest: /etc/sudoers
line: "Defaults !requiretty"
state: present
- name: "Make sure the docs are installed."
- lineinfile:
+ ansible.builtin.lineinfile:
dest: /etc/yum.conf
line: "tsflags=nodocs"
state: absent
@@ -113,7 +111,7 @@
- ansible_os_family == 'RedHat'
- name: PyMySQL
- pip:
+ ansible.builtin.pip:
name: PyMySQL
register: installation_dependencies
until: installation_dependencies is succeeded
diff --git a/ansible_collections/community/zabbix/molecule/zabbix_server/tests/test_default.py b/ansible_collections/community/zabbix/molecule/zabbix_server/tests/test_default.py
index 9a119d5ac..ee43ad2a3 100644
--- a/ansible_collections/community/zabbix/molecule/zabbix_server/tests/test_default.py
+++ b/ansible_collections/community/zabbix/molecule/zabbix_server/tests/test_default.py
@@ -1,5 +1,7 @@
import os
import pytest
+from pathlib import Path
+
import testinfra.utils.ansible_runner
@@ -17,26 +19,18 @@ def test_zabbiserver_running_and_enabled(host):
assert zabbix.is_running
-@pytest.mark.parametrize("server", [("zabbix-server-pgsql"), ("zabbix-server-mysql")])
-def test_zabbix_package(host, server):
+def test_zabbix_package(host):
ansible_data = host.ansible.get_variables()
- zabbixhost = ansible_data["inventory_hostname"]
-
- zabbixhost = zabbixhost.replace("-centos", "")
- zabbixhost = zabbixhost.replace("-debian", "")
- zabbixhost = zabbixhost.replace("-ubuntu", "")
+ version = ansible_data['zabbix_server_version']
+ database = ansible_data['zabbix_server_database']
- if zabbixhost == server:
- zabbix_server = host.package(server)
- if host.system_info.distribution in ["debian", "ubuntu"]:
- assert zabbix_server.version.startswith("1:6.4")
- elif host.system_info.distribution == "centos":
- assert zabbix_server.version.startswith("6.4")
- assert zabbix_server.is_installed
+ zabbix_server = host.package(f'zabbix-server-%s' % database)
+ assert str(version) in zabbix_server.version
def test_zabbix_server_dot_conf(host):
zabbix_server_conf = host.file("/etc/zabbix/zabbix_server.conf")
+ assert zabbix_server_conf.exists
assert zabbix_server_conf.user == "zabbix"
assert zabbix_server_conf.group == "zabbix"
assert zabbix_server_conf.mode == 0o640
@@ -50,13 +44,13 @@ def test_zabbix_include_dir(host):
assert zabbix_include_dir.is_directory
assert zabbix_include_dir.user == "zabbix"
assert zabbix_include_dir.group == "zabbix"
- # assert zabbix_include_dir.mode == 0o644
def test_zabbix_server_logfile(host):
zabbix_logfile = host.file("/var/log/zabbix/zabbix_server.log")
-
+ assert zabbix_logfile.exists
assert not zabbix_logfile.contains("Access denied for user")
assert not zabbix_logfile.contains("database is down: reconnecting")
+ assert not zabbix_logfile.contains("Both are missing in the system.") # Missing fping
assert zabbix_logfile.contains("current database version")
assert zabbix_logfile.contains(r"server #0 started \[main process\]")
diff --git a/ansible_collections/community/zabbix/molecule/zabbix_web/molecule.yml b/ansible_collections/community/zabbix/molecule/zabbix_web/molecule.yml
index baffecc47..0aa3ab800 100644
--- a/ansible_collections/community/zabbix/molecule/zabbix_web/molecule.yml
+++ b/ansible_collections/community/zabbix/molecule/zabbix_web/molecule.yml
@@ -10,30 +10,45 @@ dependency:
driver:
name: docker
platforms:
- - name: zabbix-web-${MY_MOLECULE_CONTAINER:-mysql-centos8}
- image: ${MY_MOLECULE_IMAGE:-"geerlingguy/docker-centos8-ansible"}
- command: ${MY_MOLECULE_DOCKER_COMMAND:-""}
+ - name: zabbix-web-${MY_MOLECULE_CONTAINER:-centos}
+ image: geerlingguy/docker-${MY_MOLECULE_IMAGE:-rockylinux8}-ansible:latest
privileged: true
pre_build_image: true
+ command: ${MOLECULE_DOCKER_COMMAND:-""}
networks:
- name: zabbix
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup:ro
groups:
- - ${MY_MOLECULE_GROUP:-mysql}
+ - ${MY_MOLECULE_DATABASE:-mysql}
+ - ${MY_MOLECULE_VERSION:-v64}
+ - ${MY_MOLECULE_INTERPRETER:-python3}
+ - ${MY_MOLECULE_WEB_SERVER:-apache}
provisioner:
name: ansible
- lint:
- name: ansible-lint
env:
ANSIBLE_COLLECTIONS_PATHS: $HOME/.ansible/collections/ansible_collections/community/zabbix
ANSIBLE_ROLES_PATH: $HOME/.ansible/collections/ansible_collections/community/zabbix/roles
inventory:
group_vars:
+ all:
+ zabbix_api_server_url: zabbix-web-${MY_MOLECULE_CONTAINER:-centos}
+ python3:
+ ansible_python_interpreter: /usr/bin/python3
+ python:
+ ansible_python_interpreter: /usr/bin/python
+ v64:
+ zabbix_server_version: 6.4
+ zabbix_web_version: 6.4
+ v62:
+ zabbix_server_version: 6.2
+ zabbix_web_version: 6.2
+ v60:
+ zabbix_server_version: 6.0
+ zabbix_web_version: 6.0
mysql:
zabbix_server_database: mysql
- zabbix_server_database_long: mysql
zabbix_server_dbport: 3306
zabbix_server_dbhost: mysql-host
zabbix_server_dbhost_run_install: false
@@ -42,9 +57,8 @@ provisioner:
zabbix_server_mysql_login_user: root
zabbix_server_mysql_login_password: changeme
zabbix_server_mysql_login_port: 3306
- postgresql:
+ pgsql:
zabbix_server_database: pgsql
- zabbix_server_database_long: postgresql
zabbix_server_dbport: 5432
zabbix_server_dbhost: postgresql-host
zabbix_server_dbhost_run_install: false
@@ -52,44 +66,11 @@ provisioner:
zabbix_server_pgsql_login_user: postgres
zabbix_server_pgsql_login_password: changeme
zabbix_server_pgsql_login_port: 5432
- host_vars:
- zabbix-web-pgsql-debian:
- zabbix_websrv: apache
- zabbix_php_fpm_conf_listen: false
- zabbix_api_server_url: zabbix-web-pgsql-debian
- zabbix_websrv_servername: zabbix-web-pgsql-debian
- zabbix-web-mysql-debian:
- zabbix_websrv: apache
- zabbix_php_fpm_conf_listen: false
- zabbix_api_server_url: zabbix-web-mysql-debian
- zabbix_websrv_servername: zabbix-web-mysql-debian
- zabbix-web-pgsql-centos8:
- ansible_rhn_repo_disable_gpg_check: true
- zabbix_websrv: apache
- zabbix_php_fpm_conf_listen: false
- zabbix_api_server_url: zabbix-web-pgsql-centos8
- zabbix_websrv_servername: zabbix-web-pgsql-centos8
- zabbix-web-mysql-centos8:
- ansible_rhn_repo_disable_gpg_check: true
- php_fpm_pool_user: nginx
- php_fpm_pool_group: nginx
- zabbix_websrv: nginx
- zabbix_php_fpm_conf_listen: false
- zabbix_api_server_url: zabbix-web-mysql-centos8
- zabbix_websrv_servername: zabbix-web-mysql-centos8
- zabbix-web-mysql-ubuntu18:
- zabbix_websrv: nginx
- zabbix_php_fpm_conf_listen: false
- zabbix_api_server_url: zabbix-web-mysql-ubuntu18
- zabbix_websrv_servername: zabbix-web-mysql-ubuntu18
+ apache:
+ zabbix_web_http_server: apache
+ nginx:
+ zabbix_web_http_server: nginx
php_webserver_daemon: nginx
- zabbix-web-pgsql-ubuntu20:
- zabbix_php_fpm_conf_listen: false
- zabbix_websrv: apache
- zabbix_api_server_url: zabbix-web-pgsql-ubuntu20
- zabbix_websrv_servername: zabbix-web-pgsql-ubuntu20
verifier:
name: testinfra
- lint:
- name: flake8
diff --git a/ansible_collections/community/zabbix/molecule/zabbix_web/prepare.yml b/ansible_collections/community/zabbix/molecule/zabbix_web/prepare.yml
index 3c0c6db86..204eb8f56 100644
--- a/ansible_collections/community/zabbix/molecule/zabbix_web/prepare.yml
+++ b/ansible_collections/community/zabbix/molecule/zabbix_web/prepare.yml
@@ -31,7 +31,7 @@
no_log: true
with_items: "{{ molecule_yml.platforms }}"
when:
- - '"postgresql" in item.groups'
+ - '"pgsql" in item.groups'
- name: Prepare
hosts: all
@@ -45,14 +45,11 @@
changed_when: false
- name: "Installing packages on CentOS"
- yum:
+ ansible.builtin.yum:
name:
- net-tools
- which
- - curl
- sudo
- - "{{ 'python3-pip' if ansible_distribution_major_version == '8' else 'python-pip' }}"
- - "{{ 'python3-libselinux' if ansible_distribution_major_version == '8' else 'libselinux-python' }}"
state: present
register: installation_dependencies
until: installation_dependencies is succeeded
@@ -60,7 +57,7 @@
- ansible_os_family == 'RedHat'
- name: "Installing packages (CentOS7)"
- yum:
+ ansible.builtin.yum:
name:
- centos-release-scl
state: present
@@ -70,7 +67,7 @@
- ansible_distribution_major_version == '7'
- name: "Installing MySQL on CentOS"
- yum:
+ ansible.builtin.yum:
name:
- mysql
state: present
@@ -80,20 +77,29 @@
- ansible_os_family == 'RedHat'
- inventory_hostname in groups['mysql']
+ - name: Check if warn parameter can be used for shell module
+ ansible.builtin.set_fact:
+ produce_warn: false
+ when: ansible_version.full is version("2.14", "<")
+
+ - name: "Apt update"
+ ansible.builtin.shell: "apt-get update && echo exit 0 > /usr/sbin/policy-rc.d"
+ args:
+ warn: "{{ produce_warn | default(omit) }}"
+ register: installation_dependencies
+ until: installation_dependencies is succeeded
+ when:
+ - ansible_os_family != 'RedHat'
+
- name: "Installing packages on NON-CentOS"
- apt:
+ ansible.builtin.apt:
name:
- net-tools
- - curl
- apt-utils
- - apt-transport-https
- - ca-certificates
- - gnupg2
+ - python3-pip
- gpg-agent
- sudo
- - vim
- - "{{ 'python3-apt' if ansible_distribution_major_version in ['10', '11', '18', '20'] else 'python-apt' }}"
- - "{{ 'python3-pip' if ansible_distribution_major_version in ['10', '11', '18', '20'] else 'python-pip' }}"
+ - curl
update_cache: true
state: present
register: installation_dependencies
@@ -102,13 +108,13 @@
- ansible_os_family != 'RedHat'
- name: "Configure SUDO."
- lineinfile:
+ ansible.builtin.lineinfile:
dest: /etc/sudoers
line: "Defaults !requiretty"
state: present
- name: "Make sure the docs are installed."
- lineinfile:
+ ansible.builtin.lineinfile:
dest: /etc/yum.conf
line: "tsflags=nodocs"
state: absent
@@ -116,7 +122,7 @@
- ansible_os_family == 'RedHat'
- name: PyMySQL
- pip:
+ ansible.builtin.pip:
name: PyMySQL
register: installation_dependencies
until: installation_dependencies is succeeded
@@ -124,26 +130,72 @@
- inventory_hostname in groups['mysql']
- name: Enabeling PHP 7.4
- command: dnf module enable php:7.4 -y
+ ansible.builtin.command: dnf module enable php:7.4 -y
when:
- ansible_os_family == 'RedHat'
- ansible_distribution_major_version == "8"
+ - name: Set PHP packages (Centos 8+)
+ ansible.builtin.set_fact:
+ php_packages:
+ - php
+ - php-cli
+ - php-common
+ - php-devel
+ - php-fpm
+ - php-gd
+ - php-ldap
+ - php-mbstring
+ - php-opcache
+ - php-pdo
+ - php-pear
+ - php-pecl-apcu
+ - php-xml
+ when:
+ - ansible_distribution_major_version >= '8'
+ - ansible_os_family == "RedHat"
+
+ - name: Set PHP Version (Ubuntu 2204)
+ ansible.builtin.set_fact:
+ __php_default_version_debian: "8.1"
+ when:
+ - ansible_distribution_major_version >= '22'
+ - ansible_os_family == "Debian"
+
+ - name: Set PHP packages (Ubuntu 2204)
+ ansible.builtin.set_fact:
+ __php_packages:
+ - php{{ __php_default_version_debian }}-common
+ - php{{ __php_default_version_debian }}-cli
+ - php{{ __php_default_version_debian }}-dev
+ - php{{ __php_default_version_debian }}-fpm
+ - libpcre3-dev
+ - php{{ __php_default_version_debian }}-gd
+ - php{{ __php_default_version_debian }}-curl
+ - php{{ __php_default_version_debian }}-imap
+ - php-json
+ - php{{ __php_default_version_debian }}-opcache
+ - php{{ __php_default_version_debian }}-xml
+ - php{{ __php_default_version_debian }}-mbstring
+ - php{{ __php_default_version_debian }}-apcu
+ - php{{ __php_default_version_debian }}-sqlite3
+ when:
+ - ansible_distribution_major_version >= '22'
+ - ansible_os_family == "Debian"
+
roles:
- role: geerlingguy.apache
when:
- - zabbix_websrv == "apache"
+ - zabbix_web_http_server == "apache"
- role: geerlingguy.nginx
when:
- - zabbix_websrv == "nginx"
+ - zabbix_web_http_server == "nginx"
- role: geerlingguy.php
- when:
- - ansible_os_family != 'RedHat' or (ansible_os_family == 'RedHat' and ansible_distribution_major_version == "8")
- role: zabbix_server
post_tasks:
- name: "Remove file"
- file:
+ ansible.builtin.file:
path: "{{ item }}"
state: absent
with_items:
diff --git a/ansible_collections/community/zabbix/molecule/zabbix_web/tests/test_default.py b/ansible_collections/community/zabbix/molecule/zabbix_web/tests/test_default.py
index a6f7527b0..f4882b97b 100644
--- a/ansible_collections/community/zabbix/molecule/zabbix_web/tests/test_default.py
+++ b/ansible_collections/community/zabbix/molecule/zabbix_web/tests/test_default.py
@@ -8,34 +8,19 @@ testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
).get_hosts("all")
-@pytest.mark.parametrize(
- "server, redhat, debian",
- [
- ("zabbix-server-pgsql", "zabbix-web-pgsql", "zabbix-frontend-php"),
- ("zabbix-server-mysql", "zabbix-web-mysql", "zabbix-frontend-php"),
- ],
-)
-def test_zabbix_package(host, server, redhat, debian):
- host = host.backend.get_hostname()
- host = host.replace("-centos7", "")
- host = host.replace("-centos8", "")
- host = host.replace("-debian", "")
- host = host.replace("-ubuntu", "")
+def test_zabbix_package(host):
+ ansible_data = host.ansible.get_variables()
+ version = ansible_data['zabbix_web_version']
+ webserver = ansible_data['zabbix_web_http_server']
- if host == server:
- if host.system_info.distribution in ["debian", "ubuntu"]:
- zabbix_web = host.package(debian)
- assert zabbix_web.version.startswith("1:6.4")
- elif host.system_info.distribution == "centos":
- zabbix_web = host.package(redhat)
- assert zabbix_web.version.startswith("6.4")
- assert zabbix_web.is_installed
+ zabbix_web = host.package(f'zabbix-%s-conf' % webserver)
+ assert str(version) in zabbix_web.version
def test_zabbix_web(host):
zabbix_web = host.file("/etc/zabbix/web/zabbix.conf.php")
ansible_variables = host.ansible.get_variables()
- zabbix_websrv = str(ansible_variables["zabbix_websrv"])
+ zabbix_websrv = str(ansible_variables["zabbix_web_http_server"])
if host.system_info.distribution in ["debian", "ubuntu"]:
assert zabbix_web.user == "www-data"
@@ -47,7 +32,7 @@ def test_zabbix_web(host):
elif zabbix_websrv == "nginx":
assert zabbix_web.user == "nginx"
assert zabbix_web.group == "nginx"
- assert zabbix_web.mode == 0o640
+ assert zabbix_web.mode == 0o644
def test_zabbix_api(host):
diff --git a/ansible_collections/community/zabbix/plugins/doc_fragments/connection_persistent.py b/ansible_collections/community/zabbix/plugins/doc_fragments/connection_persistent.py
deleted file mode 100644
index 6d9a82a8e..000000000
--- a/ansible_collections/community/zabbix/plugins/doc_fragments/connection_persistent.py
+++ /dev/null
@@ -1,59 +0,0 @@
-# -*- coding: utf-8 -*-
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-
-__metaclass__ = type
-
-
-class ModuleDocFragment(object):
-
- # Standard files documentation fragment
- DOCUMENTATION = r"""
-options:
- persistent_connect_timeout:
- type: int
- description:
- - Configures, in seconds, the amount of time to wait when trying to initially
- establish a persistent connection. If this value expires before the connection
- to the remote device is completed, the connection will fail.
- default: 30
- ini:
- - section: persistent_connection
- key: connect_timeout
- env:
- - name: ANSIBLE_PERSISTENT_CONNECT_TIMEOUT
- vars:
- - name: ansible_connect_timeout
- persistent_command_timeout:
- type: int
- description:
- - Configures, in seconds, the amount of time to wait for a command to
- return from the remote device. If this timer is exceeded before the
- command returns, the connection plugin will raise an exception and
- close.
- default: 30
- ini:
- - section: persistent_connection
- key: command_timeout
- env:
- - name: ANSIBLE_PERSISTENT_COMMAND_TIMEOUT
- vars:
- - name: ansible_command_timeout
- persistent_log_messages:
- type: boolean
- description:
- - This flag will enable logging the command executed and response received from
- target device in the ansible log file. For this option to work 'log_path' ansible
- configuration option is required to be set to a file path with write access.
- - Be sure to fully understand the security implications of enabling this
- option as it could create a security vulnerability by logging sensitive information in log file.
- default: False
- ini:
- - section: persistent_connection
- key: log_messages
- env:
- - name: ANSIBLE_PERSISTENT_LOG_MESSAGES
- vars:
- - name: ansible_persistent_log_messages
-"""
diff --git a/ansible_collections/community/zabbix/plugins/doc_fragments/zabbix.py b/ansible_collections/community/zabbix/plugins/doc_fragments/zabbix.py
index 2cd64b00f..5cb7fcd54 100644
--- a/ansible_collections/community/zabbix/plugins/doc_fragments/zabbix.py
+++ b/ansible_collections/community/zabbix/plugins/doc_fragments/zabbix.py
@@ -7,31 +7,8 @@
class ModuleDocFragment(object):
# Standard documentation fragment
- DOCUMENTATION = r'''
+ DOCUMENTATION = r"""
options:
- server_url:
- description:
- - URL of Zabbix server, with protocol (http or https).
- C(url) is an alias for C(server_url).
- - If not set the environment variable C(ZABBIX_SERVER) will be used.
- - This option is deprecated with the move to httpapi connection and will be removed in the next release
- required: false
- type: str
- aliases: [ url ]
- login_user:
- description:
- - Zabbix user name.
- - If not set the environment variable C(ZABBIX_USERNAME) will be used.
- - This option is deprecated with the move to httpapi connection and will be removed in the next release
- type: str
- required: false
- login_password:
- description:
- - Zabbix user password.
- - If not set the environment variable C(ZABBIX_PASSWORD) will be used.
- - This option is deprecated with the move to httpapi connection and will be removed in the next release
- type: str
- required: false
http_login_user:
description:
- Basic Auth login
@@ -42,20 +19,4 @@ options:
- Basic Auth password
type: str
required: false
- timeout:
- description:
- - The timeout of API request (seconds).
- - This option is deprecated with the move to httpapi connection and will be removed in the next release
- - The default value is C(10)
- type: int
- validate_certs:
- description:
- - If set to False, SSL certificates will not be validated. This should only be used on personally controlled sites using self-signed certificates.
- - If not set the environment variable C(ZABBIX_VALIDATE_CERTS) will be used.
- - This option is deprecated with the move to httpapi connection and will be removed in the next release
- - The default value is C(true)
- type: bool
-notes:
- - If you use I(login_password=zabbix), the word "zabbix" is replaced by "********" in all module output, because I(login_password) uses C(no_log).
- See L(this FAQ,https://docs.ansible.com/ansible/latest/network/user_guide/faq.html#why-is-my-output-sometimes-replaced-with) for more information.
-'''
+ """
diff --git a/ansible_collections/community/zabbix/plugins/httpapi/zabbix.py b/ansible_collections/community/zabbix/plugins/httpapi/zabbix.py
index 3db65532c..56ba0356d 100644
--- a/ansible_collections/community/zabbix/plugins/httpapi/zabbix.py
+++ b/ansible_collections/community/zabbix/plugins/httpapi/zabbix.py
@@ -165,12 +165,16 @@ class HttpApi(HttpApiBase):
try:
json_data = json.loads(value) if value else {}
- if "result" in json_data:
- json_data = json_data["result"]
# JSONDecodeError only available on Python 3.5+
except ValueError:
raise ConnectionError("Invalid JSON response: %s" % value)
+ if "error" in json_data:
+ raise ConnectionError("REST API returned %s when sending %s" % (json_data["error"], data))
+
+ if "result" in json_data:
+ json_data = json_data["result"]
+
try:
# Some methods return bool not a dict in "result"
iter(json_data)
@@ -178,9 +182,6 @@ class HttpApi(HttpApiBase):
# Do not try to find "error" if it is not a dict
return response.getcode(), json_data
- if "error" in json_data:
- raise ConnectionError("REST API returned %s when sending %s" % (json_data["error"], data))
-
return response.getcode(), json_data
except AnsibleConnectionFailure as e:
self.connection.queue_message("vvv", "AnsibleConnectionFailure: %s" % e)
diff --git a/ansible_collections/community/zabbix/plugins/inventory/zabbix_inventory.py b/ansible_collections/community/zabbix/plugins/inventory/zabbix_inventory.py
index 437d34227..8e4be416b 100644
--- a/ansible_collections/community/zabbix/plugins/inventory/zabbix_inventory.py
+++ b/ansible_collections/community/zabbix/plugins/inventory/zabbix_inventory.py
@@ -1,8 +1,9 @@
#
# Copyright: (c), Ansible Project
#
-# (c) 2013, Greg Buehler
+# (c) 2023, Alexandre Georges
# (c) 2018, Filippo Ferrazini
+# (c) 2013, Greg Buehler
# (c) 2021, Timothy Test
# Modified from ServiceNow Inventory Plugin and Zabbix inventory Script
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
@@ -10,7 +11,7 @@
from __future__ import absolute_import, division, print_function
__metaclass__ = type
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
name: zabbix_inventory
author:
- Timothy Test (@ttestscripting)
@@ -20,8 +21,7 @@ description:
- Zabbix Inventory plugin
- All vars from zabbix are prefixed with zbx_
requirements:
- - "python >= 2.6"
- - "zabbix-api >= 0.5.4"
+ - "python >= 3.9"
options:
server_url:
description:
@@ -35,7 +35,7 @@ options:
proxy:
description: Proxy server to use for reaching zabbix API
type: string
- default: ''
+ default: ""
host_zapi_query:
description:
- API query for hosts - see zabbix documentation for more details U(https://www.zabbix.com/documentation/current/manual/api/reference/host/get)
@@ -47,9 +47,9 @@ options:
description:
- query
- Return an applications property with host applications.
- - To return all values specify 'extend'
- - Can be limited to different fields for example setting the vaule to ['name'] will only return the name
- - Additional fields can be specified by comma seperated value ['name', 'field2']
+ - To return all values specify "extend"
+ - Can be limited to different fields for example setting the vaule to ["name"] will only return the name
+ - Additional fields can be specified by comma seperated value ["name", "field2"]
- Please see U(https://www.zabbix.com/documentation/current/manual/api/reference/application/object) for more details on field names
selectDiscoveries:
type: str
@@ -200,6 +200,12 @@ options:
required: true
env:
- name: ZABBIX_PASSWORD
+ auth_token:
+ description:
+ - Zabbix authentication token (see https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/users/api_tokens)
+ - If provided then C(login_user) and C(login_password) are ignored
+ type: str
+ required: false
http_login_user:
description:
- Basic Auth login
@@ -228,9 +234,9 @@ options:
extends_documentation_fragment:
- constructed
- inventory_cache
-'''
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
# Simple Inventory Plugin example
# This will create an inventory with details from zabbix such as applications name, applicaitonids, Parent Template Name, and group membership name
#It will also create 2 ansible inventory groups for enabled and disabled hosts in zabbix based on the status field.
@@ -286,27 +292,34 @@ validate_certs: false
compose:
zbx_testvar: zbx_status.replace("1", "Disabled")
+#Using auth token instead of username/password
+plugin: community.zabbix.zabbix_inventory
+server_url: https://zabbix.com
+auth_token: 3bc3dc85e13e2431812e7a32fa8341cbcf378e5101356c015fdf2e35fd511b06
+validate_certs: false
-'''
+"""
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable, Cacheable, to_safe_group_name
import os
import atexit
-import traceback
-
-try:
- from zabbix_api import ZabbixAPI
- HAS_ZABBIX_API = True
-except ImportError:
- ZBX_IMP_ERR = traceback.format_exc()
- HAS_ZABBIX_API = False
+import json
+from ansible.module_utils.urls import Request
+from ansible.module_utils.six.moves.urllib.error import URLError, HTTPError
+from ansible.module_utils.compat.version import LooseVersion
+from ansible.errors import AnsibleParserError
class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
NAME = 'community.zabbix.zabbix_inventory'
- def login_zabbix(self):
+ def __init__(self):
+ super().__init__()
+ self.auth = ''
+ self.zabbix_verion = ''
+
+ def api_request(self, method, params=None):
# set proxy information if required
proxy = self.get_option('proxy')
os.environ['http_proxy'] = proxy
@@ -315,24 +328,74 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
os.environ['HTTPS_PROXY'] = proxy
server_url = self.get_option('server_url')
- http_login_user = self.get_option('login_user')
- http_login_password = self.get_option('login_password')
validate_certs = self.get_option('validate_certs')
timeout = self.get_option('timeout')
- self._zapi = ZabbixAPI(server_url, timeout=timeout, user=http_login_user, passwd=http_login_password, validate_certs=validate_certs)
- self.login()
- self._zbx_api_version = self._zapi.api_version()[:5]
-
- def login(self):
- # check if api already logged in
- if not self._zapi.auth != '':
- try:
- login_user = self.get_option('login_user')
- login_password = self.get_option('login_password')
- self._zapi.login(login_user, login_password)
- atexit.register(self._zapi.logout)
- except Exception as e:
- self.display.vvv(msg="Failed to connect to Zabbix server: %s" % e)
+
+ headers = {'Content-Type': 'application/json-rpc'}
+ payload = {
+ 'jsonrpc': '2.0',
+ 'method': method,
+ 'id': '1'
+ }
+ if params is None:
+ payload['params'] = {}
+ else:
+ payload['params'] = params
+
+ if self.auth != '':
+ if (LooseVersion(self.zabbix_version) >= LooseVersion('6.4')):
+ headers['Authorization'] = 'Bearer ' + self.auth
+ else:
+ payload['auth'] = self.auth
+
+ api_url = server_url + '/api_jsonrpc.php'
+ req = Request(
+ headers=headers,
+ timeout=timeout,
+ validate_certs=validate_certs
+ )
+ try:
+ self.display.vvv("Sending request to {0}".format(api_url))
+ response = req.post(api_url, data=json.dumps(payload))
+ except ValueError:
+ raise AnsibleParserError("something went wrong with JSON loading")
+ except (URLError, HTTPError) as error:
+ raise AnsibleParserError(error)
+
+ return response
+
+ def get_version(self):
+ response = self.api_request(
+ 'apiinfo.version'
+ )
+ res = json.load(response)
+ self.zabbix_version = res['result']
+
+ def logout_zabbix(self):
+ self.api_request(
+ 'user.logout',
+ []
+ )
+
+ def login_zabbix(self):
+ auth_token = self.get_option('auth_token')
+ if auth_token:
+ self.auth = auth_token
+ return
+
+ atexit.register(self.logout_zabbix)
+
+ login_user = self.get_option('login_user')
+ login_password = self.get_option('login_password')
+ response = self.api_request(
+ 'user.login',
+ {
+ "username": login_user,
+ "password": login_password
+ }
+ )
+ res = json.load(response)
+ self.auth = res["result"]
def verify_file(self, path):
valid = False
@@ -354,9 +417,15 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
self.use_cache = self.get_option('cache') and cache
self.update_cache = self.get_option('cache') and not cache
+ self.get_version()
self.login_zabbix()
zapi_query = self.get_option('host_zapi_query')
- content = self._zapi.host.get(zapi_query)
+ response = self.api_request(
+ 'host.get',
+ zapi_query
+ )
+ res = json.load(response)
+ content = res['result']
strict = self.get_option('strict')
@@ -377,7 +446,16 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
# organize inventory by zabbix groups
if self.get_option('add_zabbix_groups'):
- content = self._zapi.host.get({'selectGroups': ['name']})
+
+ response = self.api_request(
+ 'host.get',
+ {
+ 'selectGroups': ['name']
+ }
+ )
+ res = json.load(response)
+ content = res['result']
+
for record in content:
host_name = record['host']
if len(record['groups']) >= 1:
diff --git a/ansible_collections/community/zabbix/plugins/module_utils/api_request.py b/ansible_collections/community/zabbix/plugins/module_utils/api_request.py
index a29f492de..18b588e17 100644
--- a/ansible_collections/community/zabbix/plugins/module_utils/api_request.py
+++ b/ansible_collections/community/zabbix/plugins/module_utils/api_request.py
@@ -12,7 +12,7 @@ __metaclass__ = type
from uuid import uuid4
-from ansible.module_utils.urls import CertificateError
+from ssl import CertificateError
from ansible.module_utils.connection import ConnectionError
from ansible.module_utils.connection import Connection
from ansible.module_utils._text import to_text
diff --git a/ansible_collections/community/zabbix/plugins/module_utils/base.py b/ansible_collections/community/zabbix/plugins/module_utils/base.py
index 8858a02e1..a1c73291e 100644
--- a/ansible_collections/community/zabbix/plugins/module_utils/base.py
+++ b/ansible_collections/community/zabbix/plugins/module_utils/base.py
@@ -7,7 +7,6 @@
from __future__ import absolute_import, division, print_function
__metaclass__ = type
-from ansible_collections.community.zabbix.plugins.module_utils.wrappers import ZapiWrapper
from ansible_collections.community.zabbix.plugins.module_utils.api_request import ZabbixApiRequest
@@ -17,17 +16,5 @@ class ZabbixBase(object):
"""
def __init__(self, module, zbx=None, zapi_wrapper=None):
self._module = module
-
- if module._socket_path is None:
- # ansible_connection = local
- if zapi_wrapper is None:
- self._zapi_wrapper = ZapiWrapper(module, zbx)
- else:
- self._zapi_wrapper = zapi_wrapper
-
- self._zapi = self._zapi_wrapper._zapi
- self._zbx_api_version = self._zapi_wrapper._zbx_api_version
- else:
- # ansible_connection = httpapi
- self._zapi = ZabbixApiRequest(module)
- self._zbx_api_version = self._zapi.api_version()
+ self._zapi = ZabbixApiRequest(module)
+ self._zbx_api_version = self._zapi.api_version()
diff --git a/ansible_collections/community/zabbix/plugins/module_utils/helpers.py b/ansible_collections/community/zabbix/plugins/module_utils/helpers.py
index 6c9c0fca5..87e0c0925 100644
--- a/ansible_collections/community/zabbix/plugins/module_utils/helpers.py
+++ b/ansible_collections/community/zabbix/plugins/module_utils/helpers.py
@@ -7,15 +7,6 @@
from __future__ import absolute_import, division, print_function
__metaclass__ = type
-from ansible.module_utils.basic import env_fallback
-
-
-def require_creds_params(module):
- if module._socket_path is None:
- # ansible_connection = local
- if ((not module.params.get('server_url', None)) or (not module.params.get('login_user', None)) or (not module.params.get('login_password', None))):
- module.fail_json(msg="server_url, login_user, login_password are mandatory parameters when httpapi connection is not used")
-
def zabbix_common_argument_spec():
"""
@@ -23,22 +14,6 @@ def zabbix_common_argument_spec():
The options are commonly used by most of Zabbix modules.
"""
return dict(
- server_url=dict(
- type='str',
- required=False,
- aliases=['url'],
- fallback=(env_fallback, ['ZABBIX_SERVER'])
- ),
- login_user=dict(
- type='str', required=False,
- fallback=(env_fallback, ['ZABBIX_USERNAME'])
- ),
- login_password=dict(
- type='str',
- required=False,
- no_log=True,
- fallback=(env_fallback, ['ZABBIX_PASSWORD'])
- ),
http_login_user=dict(
type='str',
required=False,
@@ -49,15 +24,7 @@ def zabbix_common_argument_spec():
required=False,
default=None,
no_log=True
- ),
- timeout=dict(
- type='int'
- ),
- validate_certs=dict(
- type='bool',
- required=False,
- fallback=(env_fallback, ['ZABBIX_VALIDATE_CERTS'])
- ),
+ )
)
diff --git a/ansible_collections/community/zabbix/plugins/module_utils/wrappers.py b/ansible_collections/community/zabbix/plugins/module_utils/wrappers.py
deleted file mode 100644
index a982108f8..000000000
--- a/ansible_collections/community/zabbix/plugins/module_utils/wrappers.py
+++ /dev/null
@@ -1,84 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-import atexit
-import traceback
-
-from ansible.module_utils.basic import missing_required_lib
-
-try:
- from zabbix_api import ZabbixAPI, Already_Exists, ZabbixAPIException
-
- HAS_ZABBIX_API = True
- ZBX_IMP_ERR = Exception()
-except ImportError:
- ZBX_IMP_ERR = traceback.format_exc()
- HAS_ZABBIX_API = False
-
-
-class ZapiWrapper(object):
- """
- A simple wrapper over the Zabbix API
- """
- def __init__(self, module, zbx=None):
- self._module = module
-
- if not HAS_ZABBIX_API:
- module.fail_json(msg=missing_required_lib('zabbix-api', url='https://pypi.org/project/zabbix-api/'), exception=ZBX_IMP_ERR)
-
- # check if zbx is already instantiated or not
- if zbx is not None and isinstance(zbx, ZabbixAPI):
- self._zapi = zbx
- else:
- server_url = module.params['server_url']
-
- if module.params['validate_certs'] is None:
- validate_certs = True
- else:
- validate_certs = module.params['validate_certs']
-
- if module.params['timeout'] is None:
- timeout = 10
- else:
- timeout = module.params['timeout']
-
- self._zapi = ZabbixAPI(server_url, timeout=timeout, validate_certs=validate_certs)
-
- self.login()
-
- self._zbx_api_version = self._zapi.api_version()
-
- def login(self):
- # check if api already logged in
- if not self._zapi.auth != '':
- try:
- login_user = self._module.params['login_user']
- login_password = self._module.params['login_password']
- self._zapi.login(login_user, login_password)
- atexit.register(self._zapi.logout)
- except Exception as e:
- self._module.fail_json(msg="Failed to connect to Zabbix server: %s" % e)
-
-
-class ScreenItem(object):
- @staticmethod
- def create(zapi_wrapper, data, ignoreExists=False):
- try:
- zapi_wrapper._zapi.screenitem.create(data)
- except Already_Exists as ex:
- if not ignoreExists:
- raise ex
-
- @staticmethod
- def delete(zapi_wrapper, id_list=None):
- try:
- if id_list is None:
- id_list = []
- zapi_wrapper._zapi.screenitem.delete(id_list)
- except ZabbixAPIException as ex:
- raise ex
diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_action.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_action.py
index 8e130de69..c0123ae1f 100644
--- a/ansible_collections/community/zabbix/plugins/modules/zabbix_action.py
+++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_action.py
@@ -8,7 +8,7 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type
-DOCUMENTATION = '''
+DOCUMENTATION = """
---
module: zabbix_action
@@ -23,41 +23,51 @@ author:
- Ruben Harutyunov (@K-DOT)
requirements:
- - "python >= 2.6"
+ - "python >= 3.9"
options:
name:
+ type: str
description:
- Name of the action
required: true
event_source:
+ type: str
description:
- Type of events that the action will handle.
- Required when C(state=present).
required: false
- choices: ['trigger', 'discovery', 'auto_registration', 'internal']
+ choices: ["trigger", "discovery", "auto_registration", "internal"]
state:
+ type: str
description:
- State of the action.
- On C(present), it will create an action if it does not exist or update the action if the associated data is different.
- On C(absent), it will remove the action if it exists.
- choices: ['present', 'absent']
- default: 'present'
+ choices: ["present", "absent"]
+ default: "present"
status:
+ type: str
description:
- Status of the action.
- choices: ['enabled', 'disabled']
- default: 'enabled'
+ choices: ["enabled", "disabled"]
+ default: "enabled"
pause_in_maintenance:
description:
- Whether to pause escalation during maintenance periods or not.
- Can be used when I(event_source=trigger).
- type: 'bool'
+ type: "bool"
+ default: true
+ notify_if_canceled:
+ description:
+ - Weather to notify when escalation is canceled.
+ - Can be used when I(event_source=trigger).
+ type: "bool"
default: true
esc_period:
+ type: str
description:
- Default operation step duration. Must be greater than 60 seconds.
- - Accepts only seconds in int for <= Zabbix 3.2
- Accepts seconds, time unit with suffix and user macro since => Zabbix 3.4
- Required when C(state=present).
required: false
@@ -68,112 +78,123 @@ options:
- List of conditions to use for filtering results.
- For more information about suboptions of this option please
check out Zabbix API documentation U(https://www.zabbix.com/documentation/5.0/manual/api/reference/action/object#action_filter_condition)
+ default: []
suboptions:
type:
+ type: str
description:
- Type (label) of the condition.
- - C(application) is available only with <= Zabbix 5.2.
- - 'Possible values when I(event_source=trigger):'
- - ' - C(host_group)'
- - ' - C(host)'
- - ' - C(trigger)'
- - ' - C(trigger_name)'
- - ' - C(trigger_severity)'
- - ' - C(time_period)'
- - ' - C(host_template)'
- - ' - C(application)'
- - ' - C(maintenance_status) known in Zabbix 4.0 and above as "Problem is suppressed"'
- - ' - C(event_tag)'
- - ' - C(event_tag_value)'
- - 'Possible values when I(event_source=discovery):'
- - ' - C(host_IP)'
- - ' - C(discovered_service_type)'
- - ' - C(discovered_service_port)'
- - ' - C(discovery_status)'
- - ' - C(uptime_or_downtime_duration)'
- - ' - C(received_value)'
- - ' - C(discovery_rule)'
- - ' - C(discovery_check)'
- - ' - C(proxy)'
- - ' - C(discovery_object)'
- - 'Possible values when I(event_source=auto_registration):'
- - ' - C(proxy)'
- - ' - C(host_name)'
- - ' - C(host_metadata)'
- - 'Possible values when I(event_source=internal):'
- - ' - C(host_group)'
- - ' - C(host)'
- - ' - C(host_template)'
- - ' - C(application)'
- - ' - C(event_type)'
+ - "Possible values when I(event_source=trigger):"
+ - " - C(host_group)"
+ - " - C(host)"
+ - " - C(trigger)"
+ - " - C(trigger_name)"
+ - " - C(trigger_severity)"
+ - " - C(time_period)"
+ - " - C(host_template)"
+ - " - C(maintenance_status) known in Zabbix 4.0 and above as 'Problem is suppressed'"
+ - " - C(event_tag)"
+ - " - C(event_tag_value)"
+ - "Possible values when I(event_source=discovery):"
+ - " - C(host_IP)"
+ - " - C(discovered_service_type)"
+ - " - C(discovered_service_port)"
+ - " - C(discovery_status)"
+ - " - C(uptime_or_downtime_duration)"
+ - " - C(received_value)"
+ - " - C(discovery_rule)"
+ - " - C(discovery_check)"
+ - " - C(proxy)"
+ - " - C(discovery_object)"
+ - "Possible values when I(event_source=auto_registration):"
+ - " - C(proxy)"
+ - " - C(host_name)"
+ - " - C(host_metadata)"
+ - "Possible values when I(event_source=internal):"
+ - " - C(host_group)"
+ - " - C(host)"
+ - " - C(host_template)"
+ - " - C(event_type)"
+ required: true
value:
+ type: str
description:
- Value to compare with.
- - 'When I(type=discovery_status), the choices are:'
- - ' - C(up)'
- - ' - C(down)'
- - ' - C(discovered)'
- - ' - C(lost)'
- - 'When I(type=discovery_object), the choices are:'
- - ' - C(host)'
- - ' - C(service)'
- - 'When I(type=event_type), the choices are:'
- - ' - C(item in not supported state)'
- - ' - C(item in normal state)'
- - ' - C(LLD rule in not supported state)'
- - ' - C(LLD rule in normal state)'
- - ' - C(trigger in unknown state)'
- - ' - C(trigger in normal state)'
- - 'When I(type=trigger_severity), the choices are (case-insensitive):'
- - ' - C(not classified)'
- - ' - C(information)'
- - ' - C(warning)'
- - ' - C(average)'
- - ' - C(high)'
- - ' - C(disaster)'
+ - "When I(type=discovery_status), the choices are:"
+ - " - C(up)"
+ - " - C(down)"
+ - " - C(discovered)"
+ - " - C(lost)"
+ - "When I(type=discovery_object), the choices are:"
+ - " - C(host)"
+ - " - C(service)"
+ - "When I(type=event_type), the choices are:"
+ - " - C(item in not supported state)"
+ - " - C(item in normal state)"
+ - " - C(LLD rule in not supported state)"
+ - " - C(LLD rule in normal state)"
+ - " - C(trigger in unknown state)"
+ - " - C(trigger in normal state)"
+ - "When I(type=trigger_severity), the choices are (case-insensitive):"
+ - " - C(not classified)"
+ - " - C(information)"
+ - " - C(warning)"
+ - " - C(average)"
+ - " - C(high)"
+ - " - C(disaster)"
- Irrespective of user-visible names being changed in Zabbix. Defaults to C(not classified) if omitted.
- Besides the above options, this is usually either the name
of the object or a string to compare with.
value2:
+ type: str
description:
- Secondary value to compare with.
- Required for trigger actions when condition I(type=event_tag_value).
operator:
+ type: str
description:
- Condition operator.
- When I(type) is set to C(time_period), the choices are C(in), C(not in).
- - C(matches), C(does not match), C(Yes) and C(No) condition operators work only with >= Zabbix 4.0
- - When I(type) is set to C(maintenance_status), the choices are C(Yes) and C(No) for Zabbix >= 6.0
choices:
- - C(equals) or C(=)
- - C(does not equal) or C(<>)
- - C(contains) or C(like)
- - C(does not contain) or C(not like)
- - C(in)
- - C(is greater than or equals) or C(>=)
- - C(is less than or equals) or C(<=)
- - C(not in)
- - C(matches)
- - C(does not match)
- - C(Yes)
- - C(No)
+ - "equals"
+ - "="
+ - "does not equal"
+ - "<>"
+ - "contains"
+ - "like"
+ - "does not contain"
+ - "not like"
+ - "in"
+ - "is greater than or equals"
+ - ">="
+ - "is less than or equals"
+ - "<="
+ - "not in"
+ - "matches"
+ - "does not match"
+ - "Yes"
+ - "No"
+ required: true
formulaid:
+ type: str
description:
- Arbitrary unique ID that is used to reference the condition from a custom expression.
- Can only contain upper-case letters.
- Required for custom expression filters and ignored otherwise.
eval_type:
+ type: str
description:
- Filter condition evaluation method.
- Defaults to C(andor) if conditions are less then 2 or if
I(formula) is not specified.
- Defaults to C(custom_expression) when formula is specified.
choices:
- - 'andor'
- - 'and'
- - 'or'
- - 'custom_expression'
+ - "andor"
+ - "and"
+ - "or"
+ - "custom_expression"
formula:
+ type: str
description:
- User-defined expression to be used for evaluating conditions with a custom expression.
- The expression must contain IDs that reference each condition by its formulaid.
@@ -182,48 +203,21 @@ options:
- Required when I(eval_type=custom_expression).
- Use sequential IDs that start at "A". If non-sequential IDs are used, Zabbix re-indexes them.
This makes each module run notice the difference in IDs and update the action.
- default_message:
- description:
- - Problem message default text.
- - With >= Zabbix 5.0 this field is removed from the API and is dropped silently by module.
- - Works only with < Zabbix 5.0
- default_subject:
- description:
- - Problem message default subject.
- - With >= Zabbix 5.0 this field is removed from the API and is dropped silently by module.
- - Works only with < Zabbix 5.0
- recovery_default_message:
- description:
- - Recovery message text.
- - With >= Zabbix 5.0 this field is removed from the API and is dropped silently by module.
- - Works only with >= Zabbix 3.2 and < Zabbix 5.0
- recovery_default_subject:
- description:
- - Recovery message subject.
- - With >= Zabbix 5.0 this field is removed from the API and is dropped silently by module.
- - Works only with >= Zabbix 3.2 and < Zabbix 5.0
- acknowledge_default_message:
- description:
- - Update operation (known as "Acknowledge operation" before Zabbix 4.0) message text.
- - With >= Zabbix 5.0 this field is removed from the API and is dropped silently by module.
- - Works only with >= Zabbix 3.4 and < Zabbix 5.0
- acknowledge_default_subject:
- description:
- - Update operation (known as "Acknowledge operation" before Zabbix 4.0) message subject.
- - With >= Zabbix 5.0 this field is removed from the API and is dropped silently by module.
- - Works only with >= Zabbix 3.4 and < Zabbix 5.0
operations:
type: list
+ elements: dict
description:
- List of action operations
+ default: []
suboptions:
type:
+ type: str
description:
- Type of operation.
- - 'Valid choices when setting type for I(recovery_operations) and I(acknowledge_operations):'
- - ' - C(send_message)'
- - ' - C(remote_command)'
- - ' - C(notify_all_involved)'
+ - "Valid choices when setting type for I(recovery_operations) and I(acknowledge_operations):"
+ - " - C(send_message)"
+ - " - C(remote_command)"
+ - " - C(notify_all_involved)"
- Choice C(notify_all_involved) only supported in I(recovery_operations) and I(acknowledge_operations).
choices:
- send_message
@@ -238,47 +232,55 @@ options:
- disable_host
- set_host_inventory_mode
- notify_all_involved
+ required: true
esc_period:
+ type: str
description:
- Duration of an escalation step in seconds.
- Must be greater than 60 seconds.
- - Accepts only seconds in int for <= Zabbix 3.2
- - Accepts seconds, time unit with suffix and user macro since => Zabbix 3.4
+ - Accepts seconds, time unit with suffix and user macro.
- If set to 0 or 0s, the default action escalation period will be used.
default: 0s
esc_step_from:
+ type: int
description:
- Step to start escalation from.
default: 1
esc_step_to:
+ type: int
description:
- Step to end escalation at.
- Specify 0 for infinitely.
default: 1
send_to_groups:
type: list
+ elements: str
description:
- User groups to send messages to.
send_to_users:
type: list
+ elements: str
description:
- Users (usernames or aliases) to send messages to.
- message:
+ op_message:
+ type: str
description:
- Operation message text.
- - Will check the 'default message' and use the text from I(default_message) if this and I(default_subject) are not specified
+ - If I(op_message) and I(subject) not defined then "default message" from media type will be used
subject:
+ type: str
description:
- Operation message subject.
- - Will check the 'default message' and use the text from I(default_subject) if this and I(default_subject) are not specified
+ - If I(op_message) and I(subject) not defined then "default message" from media type will be used
media_type:
+ type: str
description:
- Media type that will be used to send the message.
- Can be used with I(type=send_message) or I(type=notify_all_involved) inside I(acknowledge_operations).
- Set to C(all) for all media types
- default: 'all'
+ default: "all"
operation_condition:
- type: 'str'
+ type: "str"
description:
- The action operation condition object defines a condition that must be met to perform the current operation.
choices:
@@ -286,15 +288,18 @@ options:
- not_acknowledged
host_groups:
type: list
+ elements: str
description:
- List of host groups host should be added to.
- Required when I(type=add_to_host_group) or I(type=remove_from_host_group).
templates:
type: list
+ elements: str
description:
- List of templates host should be linked to.
- Required when I(type=link_to_template) or I(type=unlink_from_template).
inventory:
+ type: str
description:
- Host inventory mode.
- Required when I(type=set_host_inventory_mode).
@@ -302,6 +307,7 @@ options:
- manual
- automatic
command_type:
+ type: str
description:
- Type of operation command.
- Required when I(type=remote_command).
@@ -312,10 +318,12 @@ options:
- telnet
- global_script
command:
+ type: str
description:
- Command to run.
- Required when I(type=remote_command) and I(command_type!=global_script).
execute_on:
+ type: str
description:
- Target on which the custom script operation command will be executed.
- Required when I(type=remote_command) and I(command_type=custom_script).
@@ -324,15 +332,20 @@ options:
- server
- proxy
run_on_groups:
+ type: list
+ elements: str
description:
- Host groups to run remote commands on.
- Required when I(type=remote_command) and I(run_on_hosts) is not set.
run_on_hosts:
+ type: list
+ elements: str
description:
- Hosts to run remote commands on.
- Required when I(type=remote_command) and I(run_on_groups) is not set.
- If set to 0 the command will be run on the current host.
ssh_auth_type:
+ type: str
description:
- Authentication method used for SSH commands.
- Required when I(type=remote_command) and I(command_type=ssh).
@@ -340,48 +353,292 @@ options:
- password
- public_key
ssh_privatekey_file:
+ type: str
description:
- Name of the private key file used for SSH commands with public key authentication.
- Required when I(ssh_auth_type=public_key).
- Can be used when I(type=remote_command).
ssh_publickey_file:
+ type: str
description:
- Name of the public key file used for SSH commands with public key authentication.
- Required when I(ssh_auth_type=public_key).
- Can be used when I(type=remote_command).
username:
+ type: str
description:
- User name used for authentication.
- Required when I(ssh_auth_type in [public_key, password]) or I(command_type=telnet).
- Can be used when I(type=remote_command).
password:
+ type: str
description:
- Password used for authentication.
- Required when I(ssh_auth_type=password) or I(command_type=telnet).
- Can be used when I(type=remote_command).
port:
+ type: int
description:
- Port number used for authentication.
- Can be used when I(command_type in [ssh, telnet]) and I(type=remote_command).
script_name:
+ type: str
description:
- The name of script used for global script commands.
- Required when I(command_type=global_script).
- Can be used when I(type=remote_command).
recovery_operations:
type: list
+ elements: dict
description:
- List of recovery operations.
- C(Suboptions) are the same as for I(operations).
- - Works only with >= Zabbix 3.2
+ default: []
+ suboptions:
+ type:
+ type: str
+ description:
+ - Type of operation.
+ choices:
+ - send_message
+ - remote_command
+ - notify_all_involved
+ required: true
+ command_type:
+ type: str
+ required: false
+ description:
+ - Type of operation command.
+ choices:
+ - custom_script
+ - ipmi
+ - ssh
+ - telnet
+ - global_script
+ command:
+ type: str
+ required: false
+ description:
+ - Command to run.
+ execute_on:
+ type: str
+ required: false
+ description:
+ - Target on which the custom script operation command will be executed.
+ choices:
+ - agent
+ - server
+ - proxy
+ ssh_auth_type:
+ type: str
+ description:
+ - Authentication method used for SSH commands.
+ - Required when I(type=remote_command) and I(command_type=ssh).
+ choices:
+ - password
+ - public_key
+ ssh_privatekey_file:
+ type: str
+ description:
+ - Name of the private key file used for SSH commands with public key authentication.
+ - Required when I(ssh_auth_type=public_key).
+ - Can be used when I(type=remote_command).
+ ssh_publickey_file:
+ type: str
+ description:
+ - Name of the public key file used for SSH commands with public key authentication.
+ - Required when I(ssh_auth_type=public_key).
+ - Can be used when I(type=remote_command).
+ run_on_groups:
+ type: list
+ elements: str
+ description:
+ - Host groups to run remote commands on.
+ - Required when I(type=remote_command) and I(run_on_hosts) is not set.
+ run_on_hosts:
+ type: list
+ elements: str
+ description:
+ - Hosts to run remote commands on.
+ - Required when I(type=remote_command) and I(run_on_groups) is not set.
+ - If set to 0 the command will be run on the current host.
+ send_to_groups:
+ type: list
+ elements: str
+ description:
+ - User groups to send messages to.
+ send_to_users:
+ type: list
+ elements: str
+ description:
+ - Users (usernames or aliases) to send messages to.
+ media_type:
+ type: str
+ description:
+ - Media type that will be used to send the message.
+ - Can be used with I(type=send_message) or I(type=notify_all_involved) inside I(acknowledge_operations).
+ - Set to C(all) for all media types
+ default: "all"
+ op_message:
+ type: str
+ description:
+ - Operation message text.
+ - If I(op_message) and I(subject) not defined then "default message" from media type will be used
+ subject:
+ type: str
+ description:
+ - Operation message subject.
+ - If I(op_message) and I(subject) not defined then "default message" from media type will be used
+ username:
+ type: str
+ description:
+ - User name used for authentication.
+ - Required when I(ssh_auth_type in [public_key, password]) or I(command_type=telnet).
+ - Can be used when I(type=remote_command).
+ password:
+ type: str
+ description:
+ - Password used for authentication.
+ - Required when I(ssh_auth_type=password) or I(command_type=telnet).
+ - Can be used when I(type=remote_command).
+ port:
+ type: int
+ description:
+ - Port number used for authentication.
+ - Can be used when I(command_type in [ssh, telnet]) and I(type=remote_command).
+ script_name:
+ type: str
+ description:
+ - The name of script used for global script commands.
+ - Required when I(command_type=global_script).
+ - Can be used when I(type=remote_command).
acknowledge_operations:
type: list
+ elements: dict
description:
- List of acknowledge operations.
- Action acknowledge operations are known as update operations since Zabbix 4.0.
- C(Suboptions) are the same as for I(operations).
- - Works only with >= Zabbix 3.4
+ suboptions:
+ type:
+ type: str
+ description:
+ - Type of operation.
+ choices:
+ - send_message
+ - remote_command
+ - notify_all_involved
+ required: true
+ command_type:
+ type: str
+ description:
+ - Type of operation command.
+ required: false
+ choices:
+ - custom_script
+ - ipmi
+ - ssh
+ - telnet
+ - global_script
+ execute_on:
+ type: str
+ required: false
+ description:
+ - Target on which the custom script operation command will be executed.
+ choices:
+ - agent
+ - server
+ - proxy
+ command:
+ type: str
+ required: false
+ description:
+ - Command to run.
+ ssh_auth_type:
+ type: str
+ description:
+ - Authentication method used for SSH commands.
+ - Required when I(type=remote_command) and I(command_type=ssh).
+ choices:
+ - password
+ - public_key
+ ssh_privatekey_file:
+ type: str
+ description:
+ - Name of the private key file used for SSH commands with public key authentication.
+ - Required when I(ssh_auth_type=public_key).
+ - Can be used when I(type=remote_command).
+ ssh_publickey_file:
+ type: str
+ description:
+ - Name of the public key file used for SSH commands with public key authentication.
+ - Required when I(ssh_auth_type=public_key).
+ - Can be used when I(type=remote_command).
+ run_on_groups:
+ type: list
+ elements: str
+ description:
+ - Host groups to run remote commands on.
+ - Required when I(type=remote_command) and I(run_on_hosts) is not set.
+ run_on_hosts:
+ type: list
+ elements: str
+ description:
+ - Hosts to run remote commands on.
+ - Required when I(type=remote_command) and I(run_on_groups) is not set.
+ - If set to 0 the command will be run on the current host.
+ send_to_groups:
+ type: list
+ elements: str
+ description:
+ - User groups to send messages to.
+ send_to_users:
+ type: list
+ elements: str
+ description:
+ - Users (usernames or aliases) to send messages to.
+ media_type:
+ type: str
+ description:
+ - Media type that will be used to send the message.
+ - Can be used with I(type=send_message) or I(type=notify_all_involved) inside I(acknowledge_operations).
+ - Set to C(all) for all media types
+ default: "all"
+ op_message:
+ type: str
+ description:
+ - Operation message text.
+ - If I(op_message) and I(subject) not defined then "default message" from media type will be used
+ subject:
+ type: str
+ description:
+ - Operation message subject.
+ - If I(op_message) and I(subject) not defined then "default message" from media type will be used
+ username:
+ type: str
+ description:
+ - User name used for authentication.
+ - Required when I(ssh_auth_type in [public_key, password]) or I(command_type=telnet).
+ - Can be used when I(type=remote_command).
+ password:
+ type: str
+ description:
+ - Password used for authentication.
+ - Required when I(ssh_auth_type=password) or I(command_type=telnet).
+ - Can be used when I(type=remote_command).
+ port:
+ type: int
+ description:
+ - Port number used for authentication.
+ - Can be used when I(command_type in [ssh, telnet]) and I(type=remote_command).
+ script_name:
+ type: str
+ description:
+ - The name of script used for global script commands.
+ - Required when I(command_type=global_script).
+ - Can be used when I(type=remote_command).
aliases: [ update_operations ]
+ default: []
pause_symptoms:
type: bool
description:
@@ -390,26 +647,23 @@ options:
- Works only with >= Zabbix 6.4
default: true
-notes:
- - Only Zabbix >= 3.0 is supported.
-
extends_documentation_fragment:
- community.zabbix.zabbix
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = """
# If you want to use Username and Password to be authenticated by Zabbix Server
- name: Set credentials to access Zabbix Server API
- set_fact:
+ ansible.builtin.set_fact:
ansible_user: Admin
ansible_httpapi_pass: zabbix
# If you want to use API token to be authenticated by Zabbix Server
# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens
- name: Set API token
- set_fact:
+ ansible.builtin.set_fact:
ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895
# Trigger action with only one condition
@@ -421,25 +675,25 @@ EXAMPLES = '''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_action:
name: "Send alerts to Admin"
- event_source: 'trigger'
+ event_source: "trigger"
state: present
status: enabled
esc_period: 60
conditions:
- - type: 'trigger_severity'
- operator: '>='
- value: 'Information'
+ - type: "trigger_severity"
+ operator: ">="
+ value: "Information"
operations:
- type: send_message
subject: "Something bad is happening"
- message: "Come on, guys do something"
- media_type: 'Email'
+ op_message: "Come on, guys do something"
+ media_type: "Email"
send_to_users:
- - 'Admin'
+ - "Admin"
# Trigger action with multiple conditions and operations
- name: Deploy trigger action
@@ -450,31 +704,31 @@ EXAMPLES = '''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_action:
name: "Send alerts to Admin"
- event_source: 'trigger'
+ event_source: "trigger"
state: present
status: enabled
esc_period: 1m
conditions:
- - type: 'trigger_name'
- operator: 'like'
- value: 'Zabbix agent is unreachable'
+ - type: "trigger_name"
+ operator: "like"
+ value: "Zabbix agent is unreachable"
formulaid: A
- - type: 'trigger_severity'
- operator: '>='
- value: 'disaster'
+ - type: "trigger_severity"
+ operator: ">="
+ value: "disaster"
formulaid: B
formula: A or B
operations:
- type: send_message
- media_type: 'Email'
+ media_type: "Email"
send_to_users:
- - 'Admin'
+ - "Admin"
- type: remote_command
- command: 'systemctl restart zabbix-agent'
+ command: "systemctl restart zabbix-agent"
command_type: custom_script
execute_on: server
run_on_hosts:
@@ -489,46 +743,46 @@ EXAMPLES = '''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_action:
name: "Send alerts to Admin"
- event_source: 'trigger'
+ event_source: "trigger"
state: present
status: enabled
esc_period: 1h
conditions:
- - type: 'trigger_severity'
- operator: '>='
- value: 'Information'
+ - type: "trigger_severity"
+ operator: ">="
+ value: "Information"
operations:
- type: send_message
subject: "Something bad is happening"
- message: "Come on, guys do something"
- media_type: 'Email'
+ op_message: "Come on, guys do something"
+ media_type: "Email"
send_to_users:
- - 'Admin'
+ - "Admin"
recovery_operations:
- type: send_message
subject: "Host is down"
- message: "Come on, guys do something"
- media_type: 'Email'
+ op_message: "Come on, guys do something"
+ media_type: "Email"
send_to_users:
- - 'Admin'
+ - "Admin"
acknowledge_operations:
- type: send_message
- media_type: 'Email'
+ media_type: "Email"
send_to_users:
- - 'Admin'
-'''
+ - "Admin"
+"""
-RETURN = '''
+RETURN = """
msg:
description: The result of the operation
returned: success
type: str
- sample: 'Action Deleted: Register webservers, ID: 0001'
-'''
+ sample: "Action Deleted: Register webservers, ID: 0001"
+"""
from ansible.module_utils.basic import AnsibleModule
@@ -558,16 +812,11 @@ class Zapi(ZabbixBase):
_params = {
"selectOperations": "extend",
"selectRecoveryOperations": "extend",
- "selectAcknowledgeOperations": "extend",
+ "selectUpdateOperations": "extend",
"selectFilter": "extend",
- 'filter': {'name': [name]}
+ "filter": {"name": [name]}
}
- if LooseVersion(self._zbx_api_version) >= LooseVersion('6.0'):
- _params['selectUpdateOperations'] = _params.pop('selectAcknowledgeOperations', 'extend')
_action = self._zapi.action.get(_params)
- if len(_action) > 0 and LooseVersion(self._zbx_api_version) < LooseVersion('6.0'):
- _action[0]['recovery_operations'] = _action[0].pop('recoveryOperations', [])
- _action[0]['acknowledge_operations'] = _action[0].pop('acknowledgeOperations', [])
return _action
except Exception as e:
self._module.fail_json(msg="Failed to check if action '%s' exists: %s" % (name, e))
@@ -584,8 +833,8 @@ class Zapi(ZabbixBase):
"""
try:
action_list = self._zapi.action.get({
- 'output': 'extend',
- 'filter': {'name': [name]}
+ "output": "extend",
+ "filter": {"name": [name]}
})
if len(action_list) < 1:
self._module.fail_json(msg="Action not found: %s" % name)
@@ -606,9 +855,9 @@ class Zapi(ZabbixBase):
"""
try:
host_list = self._zapi.host.get({
- 'output': 'extend',
- 'selectInventory': 'extend',
- 'filter': {'host': [host_name]}
+ "output": "extend",
+ "selectInventory": "extend",
+ "filter": {"host": [host_name]}
})
if len(host_list) < 1:
self._module.fail_json(msg="Host not found: %s" % host_name)
@@ -629,8 +878,8 @@ class Zapi(ZabbixBase):
"""
try:
hostgroup_list = self._zapi.hostgroup.get({
- 'output': 'extend',
- 'filter': {'name': [hostgroup_name]}
+ "output": "extend",
+ "filter": {"name": [hostgroup_name]}
})
if len(hostgroup_list) < 1:
self._module.fail_json(msg="Host group not found: %s" % hostgroup_name)
@@ -651,8 +900,8 @@ class Zapi(ZabbixBase):
"""
try:
template_list = self._zapi.template.get({
- 'output': 'extend',
- 'filter': {'host': [template_name]}
+ "output": "extend",
+ "filter": {"host": [template_name]}
})
if len(template_list) < 1:
self._module.fail_json(msg="Template not found: %s" % template_name)
@@ -673,8 +922,8 @@ class Zapi(ZabbixBase):
"""
try:
trigger_list = self._zapi.trigger.get({
- 'output': 'extend',
- 'filter': {'description': [trigger_name]}
+ "output": "extend",
+ "filter": {"description": [trigger_name]}
})
if len(trigger_list) < 1:
self._module.fail_json(msg="Trigger not found: %s" % trigger_name)
@@ -695,8 +944,8 @@ class Zapi(ZabbixBase):
"""
try:
discovery_rule_list = self._zapi.drule.get({
- 'output': 'extend',
- 'filter': {'name': [discovery_rule_name]}
+ "output": "extend",
+ "filter": {"name": [discovery_rule_name]}
})
if len(discovery_rule_list) < 1:
self._module.fail_json(msg="Discovery rule not found: %s" % discovery_rule_name)
@@ -716,38 +965,38 @@ class Zapi(ZabbixBase):
"""
try:
- discovery_rule_name, dcheck_type = discovery_check_name.split(': ')
+ discovery_rule_name, dcheck_type = discovery_check_name.split(": ")
dcheck_type_to_number = {
- 'SSH': '0',
- 'LDAP': '1',
- 'SMTP': '2',
- 'FTP': '3',
- 'HTTP': '4',
- 'POP': '5',
- 'NNTP': '6',
- 'IMAP': '7',
- 'TCP': '8',
- 'Zabbix agent': '9',
- 'SNMPv1 agent': '10',
- 'SNMPv2 agent': '11',
- 'ICMP ping': '12',
- 'SNMPv3 agent': '13',
- 'HTTPS': '14',
- 'Telnet': '15'
+ "SSH": "0",
+ "LDAP": "1",
+ "SMTP": "2",
+ "FTP": "3",
+ "HTTP": "4",
+ "POP": "5",
+ "NNTP": "6",
+ "IMAP": "7",
+ "TCP": "8",
+ "Zabbix agent": "9",
+ "SNMPv1 agent": "10",
+ "SNMPv2 agent": "11",
+ "ICMP ping": "12",
+ "SNMPv3 agent": "13",
+ "HTTPS": "14",
+ "Telnet": "15"
}
if dcheck_type not in dcheck_type_to_number:
self._module.fail_json(msg="Discovery check type: %s does not exist" % dcheck_type)
discovery_rule_list = self._zapi.drule.get({
- 'output': ['dchecks'],
- 'filter': {'name': [discovery_rule_name]},
- 'selectDChecks': 'extend'
+ "output": ["dchecks"],
+ "filter": {"name": [discovery_rule_name]},
+ "selectDChecks": "extend"
})
if len(discovery_rule_list) < 1:
self._module.fail_json(msg="Discovery check not found: %s" % discovery_check_name)
- for dcheck in discovery_rule_list[0]['dchecks']:
- if dcheck_type_to_number[dcheck_type] == dcheck['type']:
+ for dcheck in discovery_rule_list[0]["dchecks"]:
+ if dcheck_type_to_number[dcheck_type] == dcheck["type"]:
return dcheck
self._module.fail_json(msg="Discovery check not found: %s" % discovery_check_name)
except Exception as e:
@@ -765,8 +1014,8 @@ class Zapi(ZabbixBase):
"""
try:
proxy_list = self._zapi.proxy.get({
- 'output': 'extend',
- 'filter': {'host': [proxy_name]}
+ "output": "extend",
+ "filter": {"host": [proxy_name]}
})
if len(proxy_list) < 1:
self._module.fail_json(msg="Proxy not found: %s" % proxy_name)
@@ -785,22 +1034,19 @@ class Zapi(ZabbixBase):
mediatype matching mediatype name
"""
- if LooseVersion(self._zbx_api_version) >= LooseVersion('4.4'):
- filter = {'name': [mediatype_name]}
- else:
- filter = {'description': [mediatype_name]}
+ filter = {"name": [mediatype_name]}
try:
- if str(mediatype_name).lower() == 'all':
- return '0'
+ if str(mediatype_name).lower() == "all":
+ return "0"
mediatype_list = self._zapi.mediatype.get({
- 'output': 'extend',
- 'filter': filter
+ "output": "extend",
+ "filter": filter
})
if len(mediatype_list) < 1:
self._module.fail_json(msg="Media type not found: %s" % mediatype_name)
else:
- return mediatype_list[0]['mediatypeid']
+ return mediatype_list[0]["mediatypeid"]
except Exception as e:
self._module.fail_json(msg="Failed to get mediatype '%s': %s" % (mediatype_name, e))
@@ -815,13 +1061,10 @@ class Zapi(ZabbixBase):
"""
try:
- if LooseVersion(self._zbx_api_version) >= LooseVersion('5.4'):
- filter = {'username': [user_name]}
- else:
- filter = {'alias': [user_name]}
+ filter = {"username": [user_name]}
user_list = self._zapi.user.get({
- 'output': 'extend',
- 'filter': filter,
+ "output": "extend",
+ "filter": filter,
})
if len(user_list) < 1:
self._module.fail_json(msg="User not found: %s" % user_name)
@@ -842,8 +1085,8 @@ class Zapi(ZabbixBase):
"""
try:
usergroup_list = self._zapi.usergroup.get({
- 'output': 'extend',
- 'filter': {'name': [usergroup_name]}
+ "output": "extend",
+ "filter": {"name": [usergroup_name]}
})
if len(usergroup_list) < 1:
self._module.fail_json(msg="User group not found: %s" % usergroup_name)
@@ -867,8 +1110,8 @@ class Zapi(ZabbixBase):
if script_name is None:
return {}
script_list = self._zapi.script.get({
- 'output': 'extend',
- 'filter': {'name': [script_name]}
+ "output": "extend",
+ "filter": {"name": [script_name]}
})
if len(script_list) < 1:
self._module.fail_json(msg="Script not found: %s" % script_name)
@@ -894,72 +1137,50 @@ class Action(Zapi):
"""
_params = {
- 'name': kwargs['name'],
- 'eventsource': zabbix_utils.helper_to_numeric_value([
- 'trigger',
- 'discovery',
- 'auto_registration',
- 'internal'], kwargs['event_source']),
- 'esc_period': kwargs.get('esc_period'),
- 'filter': kwargs['conditions'],
- 'def_longdata': kwargs['default_message'],
- 'def_shortdata': kwargs['default_subject'],
- 'r_longdata': kwargs['recovery_default_message'],
- 'r_shortdata': kwargs['recovery_default_subject'],
- 'ack_longdata': kwargs['acknowledge_default_message'],
- 'ack_shortdata': kwargs['acknowledge_default_subject'],
- 'operations': kwargs['operations'],
- 'recovery_operations': kwargs.get('recovery_operations'),
- 'acknowledge_operations': kwargs.get('acknowledge_operations'),
- 'status': zabbix_utils.helper_to_numeric_value([
- 'enabled',
- 'disabled'], kwargs['status'])
+ "name": kwargs["name"],
+ "eventsource": zabbix_utils.helper_to_numeric_value([
+ "trigger",
+ "discovery",
+ "auto_registration",
+ "internal"], kwargs["event_source"]),
+ "esc_period": kwargs.get("esc_period"),
+ "filter": kwargs["conditions"],
+ "operations": kwargs["operations"],
+ "recovery_operations": kwargs.get("recovery_operations"),
+ "acknowledge_operations": kwargs.get("acknowledge_operations"),
+ "status": zabbix_utils.helper_to_numeric_value([
+ "enabled",
+ "disabled"], kwargs["status"])
}
- if kwargs['event_source'] == 'trigger':
- if LooseVersion(self._zbx_api_version) >= LooseVersion('4.0'):
- _params['pause_suppressed'] = '1' if kwargs['pause_in_maintenance'] else '0'
- else:
- _params['maintenance_mode'] = '1' if kwargs['pause_in_maintenance'] else '0'
- if LooseVersion(self._zbx_api_version) >= LooseVersion('6.4'):
- _params['pause_symptoms'] = '1' if kwargs['pause_symptoms'] else '0'
-
- if LooseVersion(self._zbx_api_version) >= LooseVersion('5.0'):
- # remove some fields regarding
- # https://www.zabbix.com/documentation/5.0/manual/api/reference/action/object
- _params.pop('def_longdata', None)
- _params.pop('def_shortdata', None)
- _params.pop('r_longdata', None)
- _params.pop('r_shortdata', None)
-
- if (LooseVersion(self._zbx_api_version) < LooseVersion('3.4')
- or LooseVersion(self._zbx_api_version) >= LooseVersion('5.0')):
- _params.pop('ack_longdata', None)
- _params.pop('ack_shortdata', None)
-
- if LooseVersion(self._zbx_api_version) >= LooseVersion('6.0'):
- _params['update_operations'] = kwargs.get('update_operations')
- if 'update_operations' in _params and not isinstance(_params.get('update_operations', None), type(None)):
- _params.pop('acknowledge_operations', None)
- elif isinstance(_params.get('acknowledge_operations', None), list):
- _params['update_operations'] = _params.pop('acknowledge_operations', [])
- else:
- _params['update_operations'] = []
- _params.pop('acknowledge_operations', None)
+ if kwargs["event_source"] == "trigger":
+ _params["pause_suppressed"] = "1" if kwargs["pause_in_maintenance"] else "0"
+ if LooseVersion(self._zbx_api_version) >= LooseVersion("6.4"):
+ _params["pause_symptoms"] = "1" if kwargs["pause_symptoms"] else "0"
+ _params["notify_if_canceled"] = "1" if kwargs["notify_if_canceled"] else "0"
+
+ _params["update_operations"] = kwargs.get("update_operations")
+ if "update_operations" in _params and not isinstance(_params.get("update_operations", None), type(None)):
+ _params.pop("acknowledge_operations", None)
+ elif isinstance(_params.get("acknowledge_operations", None), list):
+ _params["update_operations"] = _params.pop("acknowledge_operations", [])
+ else:
+ _params["update_operations"] = []
+ _params.pop("acknowledge_operations", None)
- if 'esc_period' in _params and isinstance(_params.get('esc_period', None), type(None)):
- _params.pop('esc_period')
+ if "esc_period" in _params and isinstance(_params.get("esc_period", None), type(None)):
+ _params.pop("esc_period")
- if 'recovery_operations' in _params:
- if isinstance(_params.get('recovery_operations', None), type(None)) or len(_params.get('recovery_operations', [])) == 0:
- _params.pop('recovery_operations')
+ if "recovery_operations" in _params:
+ if isinstance(_params.get("recovery_operations", None), type(None)) or len(_params.get("recovery_operations", [])) == 0:
+ _params.pop("recovery_operations")
- if 'update_operations' in _params:
- if isinstance(_params.get('update_operations', None), type(None)) or len(_params.get('update_operations', [])) == 0:
- _params.pop('update_operations')
+ if "update_operations" in _params:
+ if isinstance(_params.get("update_operations", None), type(None)) or len(_params.get("update_operations", [])) == 0:
+ _params.pop("update_operations")
- if _params['eventsource'] not in [0, 3]:
- _params.pop('esc_period')
+ if _params["eventsource"] not in [0, 3]:
+ _params.pop("esc_period")
return _params
@@ -972,7 +1193,7 @@ class Action(Zapi):
Returns:
dict: dictionary of differences
"""
- existing_action = zabbix_utils.helper_convert_unicode_to_str(self.check_if_action_exists(kwargs['name'])[0])
+ existing_action = zabbix_utils.helper_convert_unicode_to_str(self.check_if_action_exists(kwargs["name"])[0])
parameters = zabbix_utils.helper_convert_unicode_to_str(self._construct_parameters(**kwargs))
change_parameters = {}
_diff = zabbix_utils.helper_cleanup_data(zabbix_utils.helper_compare_dictionaries(parameters, existing_action, change_parameters))
@@ -990,10 +1211,10 @@ class Action(Zapi):
try:
if self._module.check_mode:
self._module.exit_json(msg="Action would be updated if check mode was not specified: %s" % kwargs, changed=True)
- kwargs['actionid'] = kwargs.pop('action_id')
+ kwargs["actionid"] = kwargs.pop("action_id")
return self._zapi.action.update(kwargs)
except Exception as e:
- self._module.fail_json(msg="Failed to update action '%s': %s" % (kwargs['actionid'], e))
+ self._module.fail_json(msg="Failed to update action '%s': %s" % (kwargs["actionid"], e))
def add_action(self, **kwargs):
"""Add action.
@@ -1009,9 +1230,9 @@ class Action(Zapi):
self._module.exit_json(msg="Action would be added if check mode was not specified", changed=True)
parameters = self._construct_parameters(**kwargs)
action_list = self._zapi.action.create(parameters)
- return action_list['actionids'][0]
+ return action_list["actionids"][0]
except Exception as e:
- self._module.fail_json(msg="Failed to create action '%s': %s" % (kwargs['name'], e))
+ self._module.fail_json(msg="Failed to create action '%s': %s" % (kwargs["name"], e))
def delete_action(self, action_id):
"""Delete action.
@@ -1052,10 +1273,11 @@ class Operations(Zapi):
"unlink_from_template",
"enable_host",
"disable_host",
- "set_host_inventory_mode"], operation['type']
+ "set_host_inventory_mode"],
+ operation["type"]
)
except Exception:
- self._module.fail_json(msg="Unsupported value '%s' for operation type." % operation['type'])
+ self._module.fail_json(msg="Unsupported value '%s' for operation type." % operation["type"])
def _construct_opmessage(self, operation):
"""Construct operation message.
@@ -1068,12 +1290,12 @@ class Operations(Zapi):
"""
try:
return {
- 'default_msg': '0' if operation.get('message') is not None or operation.get('subject') is not None else '1',
- 'mediatypeid': self._zapi_wrapper.get_mediatype_by_mediatype_name(
- operation.get('media_type')
- ) if operation.get('media_type') is not None else '0',
- 'message': operation.get('message'),
- 'subject': operation.get('subject'),
+ "default_msg": "0" if operation.get("op_message") is not None or operation.get("subject") is not None else "1",
+ "mediatypeid": self._zapi_wrapper.get_mediatype_by_mediatype_name(
+ operation.get("media_type")
+ ) if operation.get("media_type") is not None else "0",
+ "message": operation.get("op_message"),
+ "subject": operation.get("subject"),
}
except Exception as e:
self._module.fail_json(msg="Failed to construct operation message. The error was: %s" % e)
@@ -1087,11 +1309,11 @@ class Operations(Zapi):
Returns:
list: constructed operation message user or None if operation not found
"""
- if operation.get('send_to_users') is None:
+ if operation.get("send_to_users") is None:
return None
return [{
- 'userid': self._zapi_wrapper.get_user_by_user_name(_user)['userid']
- } for _user in operation.get('send_to_users')]
+ "userid": self._zapi_wrapper.get_user_by_user_name(_user)["userid"]
+ } for _user in operation.get("send_to_users")]
def _construct_opmessage_grp(self, operation):
"""Construct operation message group.
@@ -1102,11 +1324,11 @@ class Operations(Zapi):
Returns:
list: constructed operation message group or None if operation not found
"""
- if operation.get('send_to_groups') is None:
+ if operation.get("send_to_groups") is None:
return None
return [{
- 'usrgrpid': self._zapi_wrapper.get_usergroup_by_usergroup_name(_group)['usrgrpid']
- } for _group in operation.get('send_to_groups')]
+ "usrgrpid": self._zapi_wrapper.get_usergroup_by_usergroup_name(_group)["usrgrpid"]
+ } for _group in operation.get("send_to_groups")]
def _construct_opcommand(self, operation):
"""Construct operation command.
@@ -1118,39 +1340,11 @@ class Operations(Zapi):
list: constructed operation command
"""
try:
- if LooseVersion(self._zbx_api_version) < LooseVersion('6.0'):
- opcommand = {
- 'type': zabbix_utils.helper_to_numeric_value([
- 'custom_script',
- 'ipmi',
- 'ssh',
- 'telnet',
- 'global_script'], operation.get('command_type', 'custom_script')),
- 'command': operation.get('command'),
- 'execute_on': zabbix_utils.helper_to_numeric_value([
- 'agent',
- 'server',
- 'proxy'], operation.get('execute_on', 'server')),
- 'scriptid': self._zapi_wrapper.get_script_by_script_name(
- operation.get('script_name')
- ).get('scriptid'),
- 'authtype': zabbix_utils.helper_to_numeric_value([
- 'password',
- 'public_key'
- ], operation.get('ssh_auth_type')),
- 'privatekey': operation.get('ssh_privatekey_file'),
- 'publickey': operation.get('ssh_publickey_file'),
- 'username': operation.get('username'),
- 'password': operation.get('password'),
- 'port': operation.get('port')
- }
- else:
- # In 6.0 opcommand is an opbject with just one key 'scriptid'
- opcommand = {
- 'scriptid': self._zapi_wrapper.get_script_by_script_name(
- operation.get('script_name')
- ).get('scriptid')
- }
+ opcommand = {
+ "scriptid": self._zapi_wrapper.get_script_by_script_name(
+ operation.get("script_name")
+ ).get("scriptid")
+ }
return opcommand
@@ -1166,11 +1360,11 @@ class Operations(Zapi):
Returns:
list: constructed operation command host
"""
- if operation.get('run_on_hosts') is None:
+ if operation.get("run_on_hosts") is None:
return None
return [{
- 'hostid': self._zapi_wrapper.get_host_by_host_name(_host)['hostid']
- } if str(_host) != '0' else {'hostid': '0'} for _host in operation.get('run_on_hosts')]
+ "hostid": self._zapi_wrapper.get_host_by_host_name(_host)["hostid"]
+ } if str(_host) != "0" else {"hostid": "0"} for _host in operation.get("run_on_hosts")]
def _construct_opcommand_grp(self, operation):
"""Construct operation command group.
@@ -1181,11 +1375,11 @@ class Operations(Zapi):
Returns:
list: constructed operation command group
"""
- if operation.get('run_on_groups') is None:
+ if operation.get("run_on_groups") is None:
return None
return [{
- 'groupid': self._zapi_wrapper.get_hostgroup_by_hostgroup_name(_group)['groupid']
- } for _group in operation.get('run_on_groups')]
+ "groupid": self._zapi_wrapper.get_hostgroup_by_hostgroup_name(_group)["groupid"]
+ } for _group in operation.get("run_on_groups")]
def _construct_opgroup(self, operation):
"""Construct operation group.
@@ -1197,8 +1391,8 @@ class Operations(Zapi):
list: constructed operation group
"""
return [{
- 'groupid': self._zapi_wrapper.get_hostgroup_by_hostgroup_name(_group)['groupid']
- } for _group in operation.get('host_groups', [])]
+ "groupid": self._zapi_wrapper.get_hostgroup_by_hostgroup_name(_group)["groupid"]
+ } for _group in operation.get("host_groups", [])]
def _construct_optemplate(self, operation):
"""Construct operation template.
@@ -1210,8 +1404,8 @@ class Operations(Zapi):
list: constructed operation template
"""
return [{
- 'templateid': self._zapi_wrapper.get_template_by_template_name(_template)['templateid']
- } for _template in operation.get('templates', [])]
+ "templateid": self._zapi_wrapper.get_template_by_template_name(_template)["templateid"]
+ } for _template in operation.get("templates", [])]
def _construct_opinventory(self, operation):
"""Construct operation inventory.
@@ -1223,10 +1417,10 @@ class Operations(Zapi):
dict: constructed operation inventory
"""
return {
- 'inventory_mode': zabbix_utils.helper_to_numeric_value([
- 'manual',
- 'automatic'
- ], operation.get('inventory'))
+ "inventory_mode": zabbix_utils.helper_to_numeric_value([
+ "manual",
+ "automatic"
+ ], operation.get("inventory"))
}
def _construct_opconditions(self, operation):
@@ -1238,16 +1432,16 @@ class Operations(Zapi):
Returns:
list: constructed operation conditions
"""
- _opcond = operation.get('operation_condition')
+ _opcond = operation.get("operation_condition")
if _opcond is not None:
- if _opcond == 'acknowledged':
- _value = '1'
- elif _opcond == 'not_acknowledged':
- _value = '0'
+ if _opcond == "acknowledged":
+ _value = "1"
+ elif _opcond == "not_acknowledged":
+ _value = "0"
return [{
- 'conditiontype': '14',
- 'operator': '0',
- 'value': _value
+ "conditiontype": "14",
+ "operator": "0",
+ "value": _value
}]
return []
@@ -1264,49 +1458,49 @@ class Operations(Zapi):
for op in operations:
operation_type = self._construct_operationtype(op)
constructed_operation = {
- 'operationtype': operation_type,
- 'esc_period': op.get('esc_period'),
- 'esc_step_from': op.get('esc_step_from'),
- 'esc_step_to': op.get('esc_step_to')
+ "operationtype": operation_type,
+ "esc_period": op.get("esc_period"),
+ "esc_step_from": op.get("esc_step_from"),
+ "esc_step_to": op.get("esc_step_to")
}
# Send Message type
- if constructed_operation['operationtype'] == 0:
- constructed_operation['opmessage'] = self._construct_opmessage(op)
- constructed_operation['opmessage_usr'] = self._construct_opmessage_usr(op)
- constructed_operation['opmessage_grp'] = self._construct_opmessage_grp(op)
- if event_source == 'trigger':
- # opconditions valid only for 'trigger' action
- constructed_operation['opconditions'] = self._construct_opconditions(op)
+ if constructed_operation["operationtype"] == 0:
+ constructed_operation["opmessage"] = self._construct_opmessage(op)
+ constructed_operation["opmessage_usr"] = self._construct_opmessage_usr(op)
+ constructed_operation["opmessage_grp"] = self._construct_opmessage_grp(op)
+ if event_source == "trigger":
+ # opconditions valid only for "trigger" action
+ constructed_operation["opconditions"] = self._construct_opconditions(op)
# Send Command type
- if constructed_operation['operationtype'] == 1:
- constructed_operation['opcommand'] = self._construct_opcommand(op)
- constructed_operation['opcommand_hst'] = self._construct_opcommand_hst(op)
- constructed_operation['opcommand_grp'] = self._construct_opcommand_grp(op)
- if event_source == 'trigger':
- # opconditions valid only for 'trigger' action
- constructed_operation['opconditions'] = self._construct_opconditions(op)
+ if constructed_operation["operationtype"] == 1:
+ constructed_operation["opcommand"] = self._construct_opcommand(op)
+ constructed_operation["opcommand_hst"] = self._construct_opcommand_hst(op)
+ constructed_operation["opcommand_grp"] = self._construct_opcommand_grp(op)
+ if event_source == "trigger":
+ # opconditions valid only for "trigger" action
+ constructed_operation["opconditions"] = self._construct_opconditions(op)
# Add to/Remove from host group
- if constructed_operation['operationtype'] in (4, 5):
- constructed_operation['opgroup'] = self._construct_opgroup(op)
+ if constructed_operation["operationtype"] in (4, 5):
+ constructed_operation["opgroup"] = self._construct_opgroup(op)
# Link/Unlink template
- if constructed_operation['operationtype'] in (6, 7):
- constructed_operation['optemplate'] = self._construct_optemplate(op)
+ if constructed_operation["operationtype"] in (6, 7):
+ constructed_operation["optemplate"] = self._construct_optemplate(op)
# Set inventory mode
- if constructed_operation['operationtype'] == 10:
- constructed_operation['opinventory'] = self._construct_opinventory(op)
+ if constructed_operation["operationtype"] == 10:
+ constructed_operation["opinventory"] = self._construct_opinventory(op)
# Remove escalation params when for event sources where they are not applicable
- if event_source in ['trigger', 'internal']:
- if isinstance(constructed_operation.get('esc_period'), type(None)):
- constructed_operation['esc_period'] = 0
+ if event_source in ["trigger", "internal"]:
+ if isinstance(constructed_operation.get("esc_period"), type(None)):
+ constructed_operation["esc_period"] = 0
else:
- constructed_operation.pop('esc_period')
- constructed_operation.pop('esc_step_from')
- constructed_operation.pop('esc_step_to')
+ constructed_operation.pop("esc_period")
+ constructed_operation.pop("esc_step_from")
+ constructed_operation.pop("esc_step_to")
constructed_data.append(constructed_operation)
@@ -1317,6 +1511,7 @@ class RecoveryOperations(Operations):
"""
Restructures the user defined recovery operations data to fit the Zabbix API requirements
"""
+
def _construct_operationtype(self, operation):
"""Construct operation type.
@@ -1339,10 +1534,10 @@ class RecoveryOperations(Operations):
None,
None,
None,
- "notify_all_involved"], operation['type']
+ "notify_all_involved"], operation["type"]
)
except Exception:
- self._module.fail_json(msg="Unsupported value '%s' for recovery operation type." % operation['type'])
+ self._module.fail_json(msg="Unsupported value '%s' for recovery operation type." % operation["type"])
def construct_the_data(self, operations):
"""Construct the recovery operations data using helper methods.
@@ -1357,25 +1552,24 @@ class RecoveryOperations(Operations):
for op in operations:
operation_type = self._construct_operationtype(op)
constructed_operation = {
- 'operationtype': operation_type,
+ "operationtype": operation_type,
}
# Send Message type
- if constructed_operation['operationtype'] == 0:
- constructed_operation['opmessage'] = self._construct_opmessage(op)
- constructed_operation['opmessage_usr'] = self._construct_opmessage_usr(op)
- constructed_operation['opmessage_grp'] = self._construct_opmessage_grp(op)
+ if constructed_operation["operationtype"] == 0:
+ constructed_operation["opmessage"] = self._construct_opmessage(op)
+ constructed_operation["opmessage_usr"] = self._construct_opmessage_usr(op)
+ constructed_operation["opmessage_grp"] = self._construct_opmessage_grp(op)
- if constructed_operation['operationtype'] == 11:
- constructed_operation['opmessage'] = self._construct_opmessage(op)
- if LooseVersion(self._zbx_api_version) >= LooseVersion('6.0'):
- constructed_operation['opmessage'].pop('mediatypeid')
+ if constructed_operation["operationtype"] == 11:
+ constructed_operation["opmessage"] = self._construct_opmessage(op)
+ constructed_operation["opmessage"].pop("mediatypeid")
# Send Command type
- if constructed_operation['operationtype'] == 1:
- constructed_operation['opcommand'] = self._construct_opcommand(op)
- constructed_operation['opcommand_hst'] = self._construct_opcommand_hst(op)
- constructed_operation['opcommand_grp'] = self._construct_opcommand_grp(op)
+ if constructed_operation["operationtype"] == 1:
+ constructed_operation["opcommand"] = self._construct_opcommand(op)
+ constructed_operation["opcommand_hst"] = self._construct_opcommand_hst(op)
+ constructed_operation["opcommand_grp"] = self._construct_opcommand_grp(op)
constructed_data.append(constructed_operation)
@@ -1386,6 +1580,7 @@ class AcknowledgeOperations(Operations):
"""
Restructures the user defined acknowledge operations data to fit the Zabbix API requirements
"""
+
def _construct_operationtype(self, operation):
"""Construct operation type.
@@ -1409,10 +1604,10 @@ class AcknowledgeOperations(Operations):
None,
None,
None,
- "notify_all_involved"], operation['type']
+ "notify_all_involved"], operation["type"]
)
except Exception:
- self._module.fail_json(msg="Unsupported value '%s' for acknowledge operation type." % operation['type'])
+ self._module.fail_json(msg="Unsupported value '%s' for acknowledge operation type." % operation["type"])
def construct_the_data(self, operations):
"""Construct the acknowledge operations data using helper methods.
@@ -1427,25 +1622,24 @@ class AcknowledgeOperations(Operations):
for op in operations:
operation_type = self._construct_operationtype(op)
constructed_operation = {
- 'operationtype': operation_type,
+ "operationtype": operation_type,
}
# Send Message type
- if constructed_operation['operationtype'] == 0:
- constructed_operation['opmessage'] = self._construct_opmessage(op)
- constructed_operation['opmessage_usr'] = self._construct_opmessage_usr(op)
- constructed_operation['opmessage_grp'] = self._construct_opmessage_grp(op)
+ if constructed_operation["operationtype"] == 0:
+ constructed_operation["opmessage"] = self._construct_opmessage(op)
+ constructed_operation["opmessage_usr"] = self._construct_opmessage_usr(op)
+ constructed_operation["opmessage_grp"] = self._construct_opmessage_grp(op)
- if constructed_operation['operationtype'] == 12:
- constructed_operation['opmessage'] = self._construct_opmessage(op)
- if LooseVersion(self._zbx_api_version) >= LooseVersion('6.0'):
- constructed_operation['opmessage'].pop('mediatypeid')
+ if constructed_operation["operationtype"] == 12:
+ constructed_operation["opmessage"] = self._construct_opmessage(op)
+ constructed_operation["opmessage"].pop("mediatypeid")
# Send Command type
- if constructed_operation['operationtype'] == 1:
- constructed_operation['opcommand'] = self._construct_opcommand(op)
- constructed_operation['opcommand_hst'] = self._construct_opcommand_hst(op)
- constructed_operation['opcommand_grp'] = self._construct_opcommand_grp(op)
+ if constructed_operation["operationtype"] == 1:
+ constructed_operation["opcommand"] = self._construct_opcommand(op)
+ constructed_operation["opcommand_hst"] = self._construct_opcommand_hst(op)
+ constructed_operation["opcommand_grp"] = self._construct_opcommand_grp(op)
constructed_data.append(constructed_operation)
@@ -1465,40 +1659,40 @@ class Filter(Zapi):
"""
if len(_conditions) <= 1:
return {
- 'evaltype': '0',
- 'formula': None
+ "evaltype": "0",
+ "formula": None
}
- if _eval_type == 'andor':
+ if _eval_type == "andor":
return {
- 'evaltype': '0',
- 'formula': None
+ "evaltype": "0",
+ "formula": None
}
- if _eval_type == 'and':
+ if _eval_type == "and":
return {
- 'evaltype': '1',
- 'formula': None
+ "evaltype": "1",
+ "formula": None
}
- if _eval_type == 'or':
+ if _eval_type == "or":
return {
- 'evaltype': '2',
- 'formula': None
+ "evaltype": "2",
+ "formula": None
}
- if _eval_type == 'custom_expression':
+ if _eval_type == "custom_expression":
if _formula is not None:
return {
- 'evaltype': '3',
- 'formula': _formula
+ "evaltype": "3",
+ "formula": _formula
}
else:
self._module.fail_json(msg="'formula' is required when 'eval_type' is set to 'custom_expression'")
if _formula is not None:
return {
- 'evaltype': '3',
- 'formula': _formula
+ "evaltype": "3",
+ "formula": _formula
}
return {
- 'evaltype': '0',
- 'formula': None
+ "evaltype": "0",
+ "formula": None
}
def _construct_conditiontype(self, _condition):
@@ -1510,11 +1704,6 @@ class Filter(Zapi):
Returns:
str: constructed condition type data
"""
- # application is disabled is disabled for condition type since 5.4 version.
- if (LooseVersion(self._zbx_api_version) >= LooseVersion('5.4')
- and _condition['type'] == 'application'):
- self._module.fail_json(msg="'%s' is disabled for condition type since 5.4 version." % _condition['type'])
-
try:
return zabbix_utils.helper_to_numeric_value([
"host_group",
@@ -1532,7 +1721,7 @@ class Filter(Zapi):
"received_value",
"host_template",
None,
- "application",
+ None,
"maintenance_status",
None,
"discovery_rule",
@@ -1543,10 +1732,10 @@ class Filter(Zapi):
"event_type",
"host_metadata",
"event_tag",
- "event_tag_value"], _condition['type']
+ "event_tag_value"], _condition["type"]
)
except Exception:
- self._module.fail_json(msg="Unsupported value '%s' for condition type." % _condition['type'])
+ self._module.fail_json(msg="Unsupported value '%s' for condition type." % _condition["type"])
def _construct_operator(self, _condition):
"""Construct operator
@@ -1570,10 +1759,10 @@ class Filter(Zapi):
"matches",
"does not match",
"Yes",
- "No"], _condition['operator']
+ "No"], _condition["operator"]
)
except Exception:
- self._module.fail_json(msg="Unsupported value '%s' for operator." % _condition['operator'])
+ self._module.fail_json(msg="Unsupported value '%s' for operator." % _condition["operator"])
def _construct_value(self, conditiontype, value):
"""Construct operator
@@ -1588,13 +1777,13 @@ class Filter(Zapi):
try:
# Host group
if conditiontype == 0:
- return self._zapi_wrapper.get_hostgroup_by_hostgroup_name(value)['groupid']
+ return self._zapi_wrapper.get_hostgroup_by_hostgroup_name(value)["groupid"]
# Host
if conditiontype == 1:
- return self._zapi_wrapper.get_host_by_host_name(value)['hostid']
+ return self._zapi_wrapper.get_host_by_host_name(value)["hostid"]
# Trigger
if conditiontype == 2:
- return self._zapi_wrapper.get_trigger_by_trigger_name(value)['triggerid']
+ return self._zapi_wrapper.get_trigger_by_trigger_name(value)["triggerid"]
# Trigger name: return as is
# Trigger severity
if conditiontype == 4:
@@ -1645,20 +1834,19 @@ class Filter(Zapi):
"lost"], value
)
if conditiontype == 13:
- return self._zapi_wrapper.get_template_by_template_name(value)['templateid']
- if LooseVersion(self._zapi_wrapper._zbx_api_version) >= LooseVersion('6.0'):
- # maintenance_status
- if conditiontype == 16:
- return zabbix_utils.helper_to_numeric_value([
- "Yes",
- "No"], value
- )
+ return self._zapi_wrapper.get_template_by_template_name(value)["templateid"]
+ # maintenance_status
+ if conditiontype == 16:
+ return zabbix_utils.helper_to_numeric_value([
+ "Yes",
+ "No"], value
+ )
if conditiontype == 18:
- return self._zapi_wrapper.get_discovery_rule_by_discovery_rule_name(value)['druleid']
+ return self._zapi_wrapper.get_discovery_rule_by_discovery_rule_name(value)["druleid"]
if conditiontype == 19:
- return self._zapi_wrapper.get_discovery_check_by_discovery_check_name(value)['dcheckid']
+ return self._zapi_wrapper.get_discovery_check_by_discovery_check_name(value)["dcheckid"]
if conditiontype == 20:
- return self._zapi_wrapper.get_proxy_by_proxy_name(value)['proxyid']
+ return self._zapi_wrapper.get_proxy_by_proxy_name(value)["proxyid"]
if conditiontype == 21:
return zabbix_utils.helper_to_numeric_value([
"pchldrfor0",
@@ -1697,10 +1885,10 @@ class Filter(Zapi):
if _conditions is None:
return None
constructed_data = {}
- constructed_data['conditions'] = []
+ constructed_data["conditions"] = []
for cond in _conditions:
condition_type = self._construct_conditiontype(cond)
- constructed_data['conditions'].append({
+ constructed_data["conditions"].append({
"conditiontype": condition_type,
"value": self._construct_value(condition_type, cond.get("value")),
"value2": cond.get("value2"),
@@ -1710,10 +1898,10 @@ class Filter(Zapi):
_constructed_evaltype = self._construct_evaltype(
_eval_type,
_formula,
- constructed_data['conditions']
+ constructed_data["conditions"]
)
- constructed_data['evaltype'] = _constructed_evaltype['evaltype']
- constructed_data['formula'] = _constructed_evaltype['formula']
+ constructed_data["evaltype"] = _constructed_evaltype["evaltype"]
+ constructed_data["formula"] = _constructed_evaltype["formula"]
return zabbix_utils.helper_cleanup_data(constructed_data)
@@ -1723,300 +1911,308 @@ def main():
argument_spec = zabbix_utils.zabbix_common_argument_spec()
argument_spec.update(dict(
- esc_period=dict(type='str', required=False),
- name=dict(type='str', required=True),
- event_source=dict(type='str', required=False, choices=['trigger', 'discovery', 'auto_registration', 'internal']),
- state=dict(type='str', required=False, default='present', choices=['present', 'absent']),
- status=dict(type='str', required=False, default='enabled', choices=['enabled', 'disabled']),
- pause_in_maintenance=dict(type='bool', required=False, default=True),
- default_message=dict(type='str', required=False, default=''),
- default_subject=dict(type='str', required=False, default=''),
- recovery_default_message=dict(type='str', required=False, default=''),
- recovery_default_subject=dict(type='str', required=False, default=''),
- acknowledge_default_message=dict(type='str', required=False, default=''),
- acknowledge_default_subject=dict(type='str', required=False, default=''),
+ esc_period=dict(type="str", required=False),
+ name=dict(type="str", required=True),
+ event_source=dict(type="str", required=False, choices=["trigger", "discovery", "auto_registration", "internal"]),
+ state=dict(type="str", required=False, default="present", choices=["present", "absent"]),
+ status=dict(type="str", required=False, default="enabled", choices=["enabled", "disabled"]),
+ pause_in_maintenance=dict(type="bool", required=False, default=True),
conditions=dict(
- type='list',
+ type="list",
required=False,
default=[],
- elements='dict',
+ elements="dict",
options=dict(
- formulaid=dict(type='str', required=False),
- operator=dict(type='str', required=True),
- type=dict(type='str', required=True),
- value=dict(type='str', required=False),
- value2=dict(type='str', required=False)
+ formulaid=dict(type="str", required=False),
+ operator=dict(
+ type="str",
+ required=True,
+ choices=[
+ "equals",
+ "=",
+ "does not equal",
+ "<>",
+ "contains",
+ "like",
+ "does not contain",
+ "not like",
+ "in",
+ "is greater than or equals",
+ ">=",
+ "is less than or equals",
+ "<=",
+ "not in",
+ "matches",
+ "does not match",
+ "Yes",
+ "No"
+ ]
+ ),
+ type=dict(type="str", required=True),
+ value=dict(type="str", required=False),
+ value2=dict(type="str", required=False)
),
required_if=[
- ['type', 'event_tag_value', ['value2']],
+ ["type", "event_tag_value", ["value2"]],
]
),
- formula=dict(type='str', required=False, default=None),
- eval_type=dict(type='str', required=False, default=None, choices=['andor', 'and', 'or', 'custom_expression']),
+ formula=dict(type="str", required=False, default=None),
+ eval_type=dict(type="str", required=False, default=None, choices=["andor", "and", "or", "custom_expression"]),
operations=dict(
- type='list',
+ type="list",
required=False,
default=[],
- elements='dict',
+ elements="dict",
options=dict(
type=dict(
- type='str',
+ type="str",
required=True,
choices=[
- 'send_message',
- 'remote_command',
- 'add_host',
- 'remove_host',
- 'add_to_host_group',
- 'remove_from_host_group',
- 'link_to_template',
- 'unlink_from_template',
- 'enable_host',
- 'disable_host',
- 'set_host_inventory_mode',
+ "send_message",
+ "remote_command",
+ "add_host",
+ "remove_host",
+ "add_to_host_group",
+ "remove_from_host_group",
+ "link_to_template",
+ "unlink_from_template",
+ "enable_host",
+ "disable_host",
+ "set_host_inventory_mode",
+ "notify_all_involved"
]
),
- esc_period=dict(type='str', required=False),
- esc_step_from=dict(type='int', required=False, default=1),
- esc_step_to=dict(type='int', required=False, default=1),
+ esc_period=dict(type="str", required=False, default="0s"),
+ esc_step_from=dict(type="int", required=False, default=1),
+ esc_step_to=dict(type="int", required=False, default=1),
operation_condition=dict(
- type='str',
+ type="str",
required=False,
default=None,
- choices=['acknowledged', 'not_acknowledged']
+ choices=["acknowledged", "not_acknowledged"]
),
# when type is remote_command
command_type=dict(
- type='str',
+ type="str",
required=False,
choices=[
- 'custom_script',
- 'ipmi',
- 'ssh',
- 'telnet',
- 'global_script'
+ "custom_script",
+ "ipmi",
+ "ssh",
+ "telnet",
+ "global_script"
]
),
- command=dict(type='str', required=False),
+ command=dict(type="str", required=False),
execute_on=dict(
- type='str',
+ type="str",
required=False,
- choices=['agent', 'server', 'proxy']
+ choices=["agent", "server", "proxy"]
),
- password=dict(type='str', required=False, no_log=True),
- port=dict(type='int', required=False),
- run_on_groups=dict(type='list', required=False),
- run_on_hosts=dict(type='list', required=False),
- script_name=dict(type='str', required=False),
- ssh_auth_type=dict(type='str', required=False, choices=['password', 'public_key']),
- ssh_privatekey_file=dict(type='str', required=False),
- ssh_publickey_file=dict(type='str', required=False),
- username=dict(type='str', required=False),
+ password=dict(type="str", required=False, no_log=True),
+ port=dict(type="int", required=False),
+ run_on_groups=dict(type="list", required=False, elements="str"),
+ run_on_hosts=dict(type="list", required=False, elements="str"),
+ script_name=dict(type="str", required=False),
+ ssh_auth_type=dict(type="str", required=False, choices=["password", "public_key"]),
+ ssh_privatekey_file=dict(type="str", required=False),
+ ssh_publickey_file=dict(type="str", required=False),
+ username=dict(type="str", required=False),
# when type is send_message
- media_type=dict(type='str', required=False),
- subject=dict(type='str', required=False),
- message=dict(type='str', required=False),
- send_to_groups=dict(type='list', required=False),
- send_to_users=dict(type='list', required=False),
+ media_type=dict(type="str", required=False, default="all"),
+ subject=dict(type="str", required=False),
+ op_message=dict(type="str", required=False),
+ send_to_groups=dict(type="list", required=False, elements="str"),
+ send_to_users=dict(type="list", required=False, elements="str"),
# when type is add_to_host_group or remove_from_host_group
- host_groups=dict(type='list', required=False),
+ host_groups=dict(type="list", required=False, elements="str"),
# when type is set_host_inventory_mode
- inventory=dict(type='str', required=False, choices=['manual', 'automatic']),
+ inventory=dict(type="str", required=False, choices=["manual", "automatic"]),
# when type is link_to_template or unlink_from_template
- templates=dict(type='list', required=False)
+ templates=dict(type="list", required=False, elements="str")
),
required_if=[
- ['type', 'remote_command', ['command_type']],
- ['type', 'remote_command', ['run_on_groups', 'run_on_hosts'], True],
- ['command_type', 'custom_script', ['command', 'execute_on']],
- ['command_type', 'ipmi', ['command']],
- ['command_type', 'ssh', ['command', 'ssh_auth_type']],
- ['ssh_auth_type', 'password', ['username', 'password']],
- ['ssh_auth_type', 'public_key', ['username', 'ssh_privatekey_file', 'ssh_publickey_file']],
- ['command_type', 'telnet', ['command', 'username', 'password']],
- ['command_type', 'global_script', ['script_name']],
- ['type', 'add_to_host_group', ['host_groups']],
- ['type', 'remove_from_host_group', ['host_groups']],
- ['type', 'link_to_template', ['templates']],
- ['type', 'unlink_from_template', ['templates']],
- ['type', 'set_host_inventory_mode', ['inventory']],
- ['type', 'send_message', ['send_to_users', 'send_to_groups'], True]
+ ["type", "remote_command", ["command_type"]],
+ ["type", "remote_command", ["run_on_groups", "run_on_hosts"], True],
+ ["command_type", "custom_script", ["command", "execute_on"]],
+ ["command_type", "ipmi", ["command"]],
+ ["command_type", "ssh", ["command", "ssh_auth_type"]],
+ ["ssh_auth_type", "password", ["username", "password"]],
+ ["ssh_auth_type", "public_key", ["username", "ssh_privatekey_file", "ssh_publickey_file"]],
+ ["command_type", "telnet", ["command", "username", "password"]],
+ ["command_type", "global_script", ["script_name"]],
+ ["type", "add_to_host_group", ["host_groups"]],
+ ["type", "remove_from_host_group", ["host_groups"]],
+ ["type", "link_to_template", ["templates"]],
+ ["type", "unlink_from_template", ["templates"]],
+ ["type", "set_host_inventory_mode", ["inventory"]],
+ ["type", "send_message", ["send_to_users", "send_to_groups"], True]
]
),
recovery_operations=dict(
- type='list',
+ type="list",
required=False,
default=[],
- elements='dict',
+ elements="dict",
options=dict(
type=dict(
- type='str',
+ type="str",
required=True,
choices=[
- 'send_message',
- 'remote_command',
- 'notify_all_involved'
+ "send_message",
+ "remote_command",
+ "notify_all_involved"
]
),
# when type is remote_command
command_type=dict(
- type='str',
+ type="str",
required=False,
choices=[
- 'custom_script',
- 'ipmi',
- 'ssh',
- 'telnet',
- 'global_script'
+ "custom_script",
+ "ipmi",
+ "ssh",
+ "telnet",
+ "global_script"
]
),
- command=dict(type='str', required=False),
+ command=dict(type="str", required=False),
execute_on=dict(
- type='str',
+ type="str",
required=False,
- choices=['agent', 'server', 'proxy']
+ choices=["agent", "server", "proxy"]
),
- password=dict(type='str', required=False, no_log=True),
- port=dict(type='int', required=False),
- run_on_groups=dict(type='list', required=False),
- run_on_hosts=dict(type='list', required=False),
- script_name=dict(type='str', required=False),
- ssh_auth_type=dict(type='str', required=False, choices=['password', 'public_key']),
- ssh_privatekey_file=dict(type='str', required=False),
- ssh_publickey_file=dict(type='str', required=False),
- username=dict(type='str', required=False),
+ password=dict(type="str", required=False, no_log=True),
+ port=dict(type="int", required=False),
+ run_on_groups=dict(type="list", required=False, elements="str"),
+ run_on_hosts=dict(type="list", required=False, elements="str"),
+ script_name=dict(type="str", required=False),
+ ssh_auth_type=dict(type="str", required=False, choices=["password", "public_key"]),
+ ssh_privatekey_file=dict(type="str", required=False),
+ ssh_publickey_file=dict(type="str", required=False),
+ username=dict(type="str", required=False),
# when type is send_message
- media_type=dict(type='str', required=False),
- subject=dict(type='str', required=False),
- message=dict(type='str', required=False),
- send_to_groups=dict(type='list', required=False),
- send_to_users=dict(type='list', required=False),
+ media_type=dict(type="str", required=False, default="all"),
+ subject=dict(type="str", required=False),
+ op_message=dict(type="str", required=False),
+ send_to_groups=dict(type="list", required=False, elements="str"),
+ send_to_users=dict(type="list", required=False, elements="str"),
),
required_if=[
- ['type', 'remote_command', ['command_type']],
- ['type', 'remote_command', [
- 'run_on_groups',
- 'run_on_hosts'
+ ["type", "remote_command", ["command_type"]],
+ ["type", "remote_command", [
+ "run_on_groups",
+ "run_on_hosts"
], True],
- ['command_type', 'custom_script', [
- 'command',
- 'execute_on'
+ ["command_type", "custom_script", [
+ "command",
+ "execute_on"
]],
- ['command_type', 'ipmi', ['command']],
- ['command_type', 'ssh', ['command', 'ssh_auth_type']],
- ['ssh_auth_type', 'password', ['username', 'password']],
- ['ssh_auth_type', 'public_key', ['username', 'ssh_privatekey_file', 'ssh_publickey_file']],
- ['command_type', 'telnet', ['command', 'username', 'password']],
- ['command_type', 'global_script', ['script_name']],
- ['type', 'send_message', ['send_to_users', 'send_to_groups'], True]
+ ["command_type", "ipmi", ["command"]],
+ ["command_type", "ssh", ["command", "ssh_auth_type"]],
+ ["ssh_auth_type", "password", ["username", "password"]],
+ ["ssh_auth_type", "public_key", ["username", "ssh_privatekey_file", "ssh_publickey_file"]],
+ ["command_type", "telnet", ["command", "username", "password"]],
+ ["command_type", "global_script", ["script_name"]],
+ ["type", "send_message", ["send_to_users", "send_to_groups"], True]
]
),
acknowledge_operations=dict(
- type='list',
+ type="list",
required=False,
default=[],
- elements='dict',
- aliases=['update_operations'],
+ elements="dict",
+ aliases=["update_operations"],
options=dict(
type=dict(
- type='str',
+ type="str",
required=True,
choices=[
- 'send_message',
- 'remote_command',
- 'notify_all_involved'
+ "send_message",
+ "remote_command",
+ "notify_all_involved"
]
),
# when type is remote_command
command_type=dict(
- type='str',
+ type="str",
required=False,
choices=[
- 'custom_script',
- 'ipmi',
- 'ssh',
- 'telnet',
- 'global_script'
+ "custom_script",
+ "ipmi",
+ "ssh",
+ "telnet",
+ "global_script"
]
),
- command=dict(type='str', required=False),
+ command=dict(type="str", required=False),
execute_on=dict(
- type='str',
+ type="str",
required=False,
- choices=['agent', 'server', 'proxy']
+ choices=["agent", "server", "proxy"]
),
- password=dict(type='str', required=False, no_log=True),
- port=dict(type='int', required=False),
- run_on_groups=dict(type='list', required=False),
- run_on_hosts=dict(type='list', required=False),
- script_name=dict(type='str', required=False),
- ssh_auth_type=dict(type='str', required=False, choices=['password', 'public_key']),
- ssh_privatekey_file=dict(type='str', required=False),
- ssh_publickey_file=dict(type='str', required=False),
- username=dict(type='str', required=False),
+ password=dict(type="str", required=False, no_log=True),
+ port=dict(type="int", required=False),
+ run_on_groups=dict(type="list", required=False, elements="str"),
+ run_on_hosts=dict(type="list", required=False, elements="str"),
+ script_name=dict(type="str", required=False),
+ ssh_auth_type=dict(type="str", required=False, choices=["password", "public_key"]),
+ ssh_privatekey_file=dict(type="str", required=False),
+ ssh_publickey_file=dict(type="str", required=False),
+ username=dict(type="str", required=False),
# when type is send_message
- media_type=dict(type='str', required=False),
- subject=dict(type='str', required=False),
- message=dict(type='str', required=False),
- send_to_groups=dict(type='list', required=False),
- send_to_users=dict(type='list', required=False),
+ media_type=dict(type="str", required=False, default="all"),
+ subject=dict(type="str", required=False),
+ op_message=dict(type="str", required=False),
+ send_to_groups=dict(type="list", required=False, elements="str"),
+ send_to_users=dict(type="list", required=False, elements="str"),
),
required_if=[
- ['type', 'remote_command', ['command_type']],
- ['type', 'remote_command', [
- 'run_on_groups',
- 'run_on_hosts'
+ ["type", "remote_command", ["command_type"]],
+ ["type", "remote_command", [
+ "run_on_groups",
+ "run_on_hosts"
], True],
- ['command_type', 'custom_script', [
- 'command',
- 'execute_on'
+ ["command_type", "custom_script", [
+ "command",
+ "execute_on"
]],
- ['command_type', 'ipmi', ['command']],
- ['command_type', 'ssh', ['command', 'ssh_auth_type']],
- ['ssh_auth_type', 'password', ['username', 'password']],
- ['ssh_auth_type', 'public_key', ['username', 'ssh_privatekey_file', 'ssh_publickey_file']],
- ['command_type', 'telnet', ['command', 'username', 'password']],
- ['command_type', 'global_script', ['script_name']],
- ['type', 'send_message', ['send_to_users', 'send_to_groups'], True]
+ ["command_type", "ipmi", ["command"]],
+ ["command_type", "ssh", ["command", "ssh_auth_type"]],
+ ["ssh_auth_type", "password", ["username", "password"]],
+ ["ssh_auth_type", "public_key", ["username", "ssh_privatekey_file", "ssh_publickey_file"]],
+ ["command_type", "telnet", ["command", "username", "password"]],
+ ["command_type", "global_script", ["script_name"]],
+ ["type", "send_message", ["send_to_users", "send_to_groups"], True]
]
),
- pause_symptoms=dict(type='bool', required=False, default=True)
+ pause_symptoms=dict(type="bool", required=False, default=True),
+ notify_if_canceled=dict(type="bool", required=False, default=True)
))
module = AnsibleModule(
argument_spec=argument_spec,
required_if=[
- ['state', 'present', [
- 'event_source'
+ ["state", "present", [
+ "event_source"
]]
],
supports_check_mode=True
)
- zabbix_utils.require_creds_params(module)
-
- for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']:
- if p in module.params and not module.params[p] is None:
- module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p)
-
- name = module.params['name']
- esc_period = module.params['esc_period']
- event_source = module.params['event_source']
- state = module.params['state']
- status = module.params['status']
- pause_in_maintenance = module.params['pause_in_maintenance']
- default_message = module.params['default_message']
- default_subject = module.params['default_subject']
- recovery_default_message = module.params['recovery_default_message']
- recovery_default_subject = module.params['recovery_default_subject']
- acknowledge_default_message = module.params['acknowledge_default_message']
- acknowledge_default_subject = module.params['acknowledge_default_subject']
- conditions = module.params['conditions']
- formula = module.params['formula']
- eval_type = module.params['eval_type']
- operations = module.params['operations']
- recovery_operations = module.params['recovery_operations']
- acknowledge_operations = module.params['acknowledge_operations']
- pause_symptoms = module.params['pause_symptoms']
+ name = module.params["name"]
+ esc_period = module.params["esc_period"]
+ event_source = module.params["event_source"]
+ state = module.params["state"]
+ status = module.params["status"]
+ pause_in_maintenance = module.params["pause_in_maintenance"]
+ conditions = module.params["conditions"]
+ formula = module.params["formula"]
+ eval_type = module.params["eval_type"]
+ operations = module.params["operations"]
+ recovery_operations = module.params["recovery_operations"]
+ acknowledge_operations = module.params["acknowledge_operations"]
+ pause_symptoms = module.params["pause_symptoms"]
+ notify_if_canceled = module.params["notify_if_canceled"]
zapi_wrapper = Zapi(module)
action = Action(module)
@@ -2028,7 +2224,7 @@ def main():
fltr = Filter(module, zapi_wrapper)
if action_exists:
- action_id = zapi_wrapper.get_action_by_name(name)['actionid']
+ action_id = zapi_wrapper.get_action_by_name(name)["actionid"]
if state == "absent":
result = action.delete_action(action_id)
module.exit_json(changed=True, msg="Action Deleted: %s, ID: %s" % (name, result))
@@ -2040,24 +2236,16 @@ def main():
esc_period=esc_period,
status=status,
pause_in_maintenance=pause_in_maintenance,
- default_message=default_message,
- default_subject=default_subject,
- recovery_default_message=recovery_default_message,
- recovery_default_subject=recovery_default_subject,
- acknowledge_default_message=acknowledge_default_message,
- acknowledge_default_subject=acknowledge_default_subject,
operations=ops.construct_the_data(operations, event_source),
recovery_operations=recovery_ops.construct_the_data(recovery_operations),
- conditions=fltr.construct_the_data(eval_type, formula, conditions)
+ conditions=fltr.construct_the_data(eval_type, formula, conditions),
+ notify_if_canceled=notify_if_canceled
)
- if LooseVersion(zapi_wrapper._zbx_api_version) >= LooseVersion('6.4'):
- kwargs['pause_symptoms'] = pause_symptoms
+ if LooseVersion(zapi_wrapper._zbx_api_version) >= LooseVersion("6.4"):
+ kwargs["pause_symptoms"] = pause_symptoms
- if LooseVersion(zapi_wrapper._zbx_api_version) >= LooseVersion('6.0'):
- kwargs[argument_spec['acknowledge_operations']['aliases'][0]] = acknowledge_ops.construct_the_data(acknowledge_operations)
- else:
- kwargs['acknowledge_operations'] = acknowledge_ops.construct_the_data(acknowledge_operations)
+ kwargs[argument_spec["acknowledge_operations"]["aliases"][0]] = acknowledge_ops.construct_the_data(acknowledge_operations)
difference = action.check_difference(**kwargs)
@@ -2079,28 +2267,20 @@ def main():
esc_period=esc_period,
status=status,
pause_in_maintenance=pause_in_maintenance,
- default_message=default_message,
- default_subject=default_subject,
- recovery_default_message=recovery_default_message,
- recovery_default_subject=recovery_default_subject,
- acknowledge_default_message=acknowledge_default_message,
- acknowledge_default_subject=acknowledge_default_subject,
operations=ops.construct_the_data(operations, event_source),
recovery_operations=recovery_ops.construct_the_data(recovery_operations),
- conditions=fltr.construct_the_data(eval_type, formula, conditions)
+ conditions=fltr.construct_the_data(eval_type, formula, conditions),
+ notify_if_canceled=notify_if_canceled
)
- if LooseVersion(zapi_wrapper._zbx_api_version) >= LooseVersion('6.0'):
- kwargs[argument_spec['acknowledge_operations']['aliases'][0]] = acknowledge_ops.construct_the_data(acknowledge_operations)
- else:
- kwargs['acknowledge_operations'] = acknowledge_ops.construct_the_data(acknowledge_operations)
+ kwargs[argument_spec["acknowledge_operations"]["aliases"][0]] = acknowledge_ops.construct_the_data(acknowledge_operations)
- if LooseVersion(zapi_wrapper._zbx_api_version) >= LooseVersion('6.4'):
- kwargs['pause_symptoms'] = pause_symptoms
+ if LooseVersion(zapi_wrapper._zbx_api_version) >= LooseVersion("6.4"):
+ kwargs["pause_symptoms"] = pause_symptoms
action_id = action.add_action(**kwargs)
module.exit_json(changed=True, msg="Action created: %s, ID: %s" % (name, action_id))
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_api_info.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_api_info.py
new file mode 100644
index 000000000..5941408e9
--- /dev/null
+++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_api_info.py
@@ -0,0 +1,108 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright: (c) 2022, ONODERA Masaru <masaru-onodera@ieee.org>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+
+DOCUMENTATION = '''
+---
+module: zabbix_api_info
+
+short_description: Retrieve Zabbix API info
+
+description:
+ - This module allows you to retrieve Zabbix api info.
+
+author:
+ - ONODERA Masaru(@masa-orca)
+
+requirements:
+ - "python >= 3.9"
+
+version_added: 2.1.0
+
+extends_documentation_fragment:
+ - community.zabbix.zabbix
+'''
+
+EXAMPLES = '''
+# If you want to use Username and Password to be authenticated by Zabbix Server
+- name: Set credentials to access Zabbix Server API
+ ansible.builtin.set_fact:
+ ansible_user: Admin
+ ansible_httpapi_pass: zabbix
+
+# If you want to use API token to be authenticated by Zabbix Server
+# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens
+- name: Set API token
+ ansible.builtin.set_fact:
+ ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895
+
+- name: Retrieve API information
+ # set task level variables as we change ansible_connection plugin here
+ vars:
+ ansible_network_os: community.zabbix.zabbix
+ ansible_connection: httpapi
+ ansible_httpapi_port: 443
+ ansible_httpapi_use_ssl: true
+ ansible_httpapi_validate_certs: false
+ ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_host: zabbix-example-fqdn.org
+ community.zabbix.zabbix_api_info:
+ register: zbx_api_info
+'''
+
+RETURN = '''
+api:
+ description: Summaries of Zabbix API info
+ returned: success
+ type: dict
+ contains:
+ version:
+ description: API version
+ type: str
+ sample: 6.0.18
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.compat.version import LooseVersion
+
+from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase
+import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils
+
+
+class ApiInfo(ZabbixBase):
+ def __init__(self, module, zbx=None, zapi_wrapper=None):
+ super(ApiInfo, self).__init__(module, zbx, zapi_wrapper)
+ if LooseVersion(self._zbx_api_version) < LooseVersion('2.2.0'):
+ module.fail_json(msg="This module doesn't support Zabbix versions lower than 2.2.0")
+
+ def get_api_info(self):
+ if self._module.check_mode:
+ self._module.exit_json(changed=False)
+ try:
+ api = {
+ 'version': self._zbx_api_version
+ }
+ self._module.exit_json(api=api)
+ except Exception as e:
+ self._module.fail_json(msg="Failed to retrieve API info: %s" % e)
+
+
+def main():
+ argument_spec = zabbix_utils.zabbix_common_argument_spec()
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True
+ )
+
+ api_info = ApiInfo(module)
+ api_info.get_api_info()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_authentication.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_authentication.py
index 51fb3e5b9..f8eaf8e19 100644
--- a/ansible_collections/community/zabbix/plugins/modules/zabbix_authentication.py
+++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_authentication.py
@@ -5,10 +5,11 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
-DOCUMENTATION = '''
+DOCUMENTATION = """
---
module: zabbix_authentication
@@ -21,7 +22,7 @@ author:
- ONODERA Masaru(@masa-orca)
requirements:
- - "python >= 2.6"
+ - "python >= 3.9"
version_added: 1.6.0
@@ -257,24 +258,21 @@ options:
type: list
elements: str
-notes:
- - Zabbix 5.4 version and higher are supported.
-
extends_documentation_fragment:
- community.zabbix.zabbix
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = """
# If you want to use Username and Password to be authenticated by Zabbix Server
- name: Set credentials to access Zabbix Server API
- set_fact:
+ ansible.builtin.set_fact:
ansible_user: Admin
ansible_httpapi_pass: zabbix
# If you want to use API token to be authenticated by Zabbix Server
# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens
- name: Set API token
- set_fact:
+ ansible.builtin.set_fact:
ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895
- name: Update all authentication setting (Zabbix <= 6.0)
@@ -285,9 +283,9 @@ EXAMPLES = '''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
- zabbix_authentication:
+ community.zabbix.zabbix_authentication:
authentication_type: internal
http_auth_enabled: true
http_login_form: zabbix_login_form
@@ -296,20 +294,20 @@ EXAMPLES = '''
- any
http_case_sensitive: true
ldap_configured: true
- ldap_host: 'ldap://localhost'
+ ldap_host: "ldap://localhost"
ldap_port: 389
- ldap_base_dn: 'ou=Users,ou=system'
- ldap_search_attribute: 'uid'
- ldap_bind_dn: 'uid=ldap_search,ou=system'
+ ldap_base_dn: "ou=Users,ou=system"
+ ldap_search_attribute: "uid"
+ ldap_bind_dn: "uid=ldap_search,ou=system"
ldap_case_sensitive: true
- ldap_bind_password: 'password'
+ ldap_bind_password: "password"
saml_auth_enabled: true
- saml_idp_entityid: ''
- saml_sso_url: 'https://localhost/SAML2/SSO'
- saml_slo_url: 'https://localhost/SAML2/SLO'
- saml_username_attribute: 'uid'
- saml_sp_entityid: 'https://localhost'
- saml_nameid_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:entity'
+ saml_idp_entityid: ""
+ saml_sso_url: "https://localhost/SAML2/SSO"
+ saml_slo_url: "https://localhost/SAML2/SLO"
+ saml_username_attribute: "uid"
+ saml_sp_entityid: "https://localhost"
+ saml_nameid_format: "urn:oasis:names:tc:SAML:2.0:nameid-format:entity"
saml_sign_messages: true
saml_sign_assertions: true
saml_sign_authn_requests: true
@@ -333,9 +331,9 @@ EXAMPLES = '''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
- zabbix_authentication:
+ community.zabbix.zabbix_authentication:
authentication_type: internal
http_auth_enabled: true
http_login_form: zabbix_login_form
@@ -346,12 +344,12 @@ EXAMPLES = '''
ldap_configured: true
ldap_case_sensitive: true
saml_auth_enabled: true
- saml_idp_entityid: ''
- saml_sso_url: 'https://localhost/SAML2/SSO'
- saml_slo_url: 'https://localhost/SAML2/SLO'
- saml_username_attribute: 'uid'
- saml_sp_entityid: 'https://localhost'
- saml_nameid_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:entity'
+ saml_idp_entityid: ""
+ saml_sso_url: "https://localhost/SAML2/SSO"
+ saml_slo_url: "https://localhost/SAML2/SLO"
+ saml_username_attribute: "uid"
+ saml_sp_entityid: "https://localhost"
+ saml_nameid_format: "urn:oasis:names:tc:SAML:2.0:nameid-format:entity"
saml_sign_messages: true
saml_sign_assertions: true
saml_sign_authn_requests: true
@@ -375,9 +373,9 @@ EXAMPLES = '''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
- zabbix_authentication:
+ community.zabbix.zabbix_authentication:
authentication_type: internal
http_auth_enabled: true
http_login_form: zabbix_login_form
@@ -386,6 +384,7 @@ EXAMPLES = '''
- any
http_case_sensitive: true
ldap_auth_enabled: true
+ ldap_userdirectory: TestUserDirectory
ldap_case_sensitive: true
saml_auth_enabled: true
saml_case_sensitive: true
@@ -399,15 +398,15 @@ EXAMPLES = '''
- contain_digits
- contain_special_characters
- avoid_easy_to_guess
-'''
+"""
-RETURN = '''
+RETURN = """
msg:
description: The result of the operation
returned: success
type: str
- sample: 'Successfully update authentication setting'
-'''
+ sample: "Successfully update authentication setting"
+"""
from ansible.module_utils.basic import AnsibleModule
@@ -417,251 +416,291 @@ import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabb
class Authentication(ZabbixBase):
- def __init__(self, module, zbx=None, zapi_wrapper=None):
- super(Authentication, self).__init__(module, zbx, zapi_wrapper)
- if LooseVersion(self._zbx_api_version) < LooseVersion('5.4.0'):
- module.fail_json(msg="This module doesn't support Zabbix versions lower than 5.4.0")
# get authentication setting
def get_authentication(self):
try:
- return self._zapi.authentication.get({'output': 'extend'})
+ return self._zapi.authentication.get({"output": "extend"})
except Exception as e:
self._module.fail_json(msg="Failed to get authentication setting: %s" % e)
# update authentication setting
def update_authentication(
- self,
- current_authentication,
- authentication_type,
- http_auth_enabled,
- http_login_form,
- http_strip_domains,
- http_case_sensitive,
- ldap_configured,
- ldap_auth_enabled,
- ldap_host,
- ldap_port,
- ldap_base_dn,
- ldap_search_attribute,
- ldap_bind_dn,
- ldap_case_sensitive,
- ldap_bind_password,
- ldap_userdirectory,
- saml_auth_enabled,
- saml_idp_entityid,
- saml_sso_url,
- saml_slo_url,
- saml_username_attribute,
- saml_sp_entityid,
- saml_nameid_format,
- saml_sign_messages,
- saml_sign_assertions,
- saml_sign_authn_requests,
- saml_sign_logout_requests,
- saml_sign_logout_responses,
- saml_encrypt_nameid,
- saml_encrypt_assertions,
- saml_case_sensitive,
- passwd_min_length,
- passwd_check_rules,
- ldap_jit_status,
- saml_jit_status,
- jit_provision_interval,
- disabled_usrgroup):
+ self,
+ current_authentication,
+ authentication_type,
+ http_auth_enabled,
+ http_login_form,
+ http_strip_domains,
+ http_case_sensitive,
+ ldap_configured,
+ ldap_auth_enabled,
+ ldap_host,
+ ldap_port,
+ ldap_base_dn,
+ ldap_search_attribute,
+ ldap_bind_dn,
+ ldap_case_sensitive,
+ ldap_bind_password,
+ ldap_userdirectory,
+ saml_auth_enabled,
+ saml_idp_entityid,
+ saml_sso_url,
+ saml_slo_url,
+ saml_username_attribute,
+ saml_sp_entityid,
+ saml_nameid_format,
+ saml_sign_messages,
+ saml_sign_assertions,
+ saml_sign_authn_requests,
+ saml_sign_logout_requests,
+ saml_sign_logout_responses,
+ saml_encrypt_nameid,
+ saml_encrypt_assertions,
+ saml_case_sensitive,
+ passwd_min_length,
+ passwd_check_rules,
+ ldap_jit_status,
+ saml_jit_status,
+ jit_provision_interval,
+ disabled_usrgroup,
+ ):
try:
params = {}
if authentication_type:
- params['authentication_type'] = str(zabbix_utils.helper_to_numeric_value(
- ['internal', 'ldap'],
- authentication_type
- ))
+ params["authentication_type"] = str(
+ zabbix_utils.helper_to_numeric_value(
+ ["internal", "ldap"], authentication_type
+ )
+ )
if isinstance(http_auth_enabled, bool):
- params['http_auth_enabled'] = str(int(http_auth_enabled))
+ params["http_auth_enabled"] = str(int(http_auth_enabled))
if http_login_form:
- params['http_login_form'] = str(zabbix_utils.helper_to_numeric_value(
- ['zabbix_login_form', 'http_login_form'],
- http_login_form
- ))
+ params["http_login_form"] = str(
+ zabbix_utils.helper_to_numeric_value(
+ ["zabbix_login_form", "http_login_form"], http_login_form
+ )
+ )
if http_strip_domains:
- params['http_strip_domains'] = ','.join(http_strip_domains)
+ params["http_strip_domains"] = ",".join(http_strip_domains)
if isinstance(http_case_sensitive, bool):
- params['http_case_sensitive'] = str(int(http_case_sensitive))
+ params["http_case_sensitive"] = str(int(http_case_sensitive))
- if LooseVersion(self._zbx_api_version) < LooseVersion('6.4'):
+ if LooseVersion(self._zbx_api_version) < LooseVersion("6.4"):
if isinstance(ldap_configured, bool):
- params['ldap_configured'] = str(int(ldap_configured))
+ params["ldap_configured"] = str(int(ldap_configured))
else:
if isinstance(ldap_auth_enabled, bool):
- params['ldap_auth_enabled'] = str(int(ldap_auth_enabled))
+ params["ldap_auth_enabled"] = str(int(ldap_auth_enabled))
- if LooseVersion(self._zbx_api_version) < LooseVersion('6.2.0'):
+ if LooseVersion(self._zbx_api_version) < LooseVersion("6.2"):
if ldap_host:
- params['ldap_host'] = ldap_host
+ params["ldap_host"] = ldap_host
if ldap_port:
- params['ldap_port'] = str(ldap_port)
+ params["ldap_port"] = str(ldap_port)
if ldap_base_dn:
- params['ldap_base_dn'] = ldap_base_dn
+ params["ldap_base_dn"] = ldap_base_dn
if ldap_search_attribute:
- params['ldap_search_attribute'] = ldap_search_attribute
+ params["ldap_search_attribute"] = ldap_search_attribute
if ldap_bind_dn:
- params['ldap_bind_dn'] = ldap_bind_dn
+ params["ldap_bind_dn"] = ldap_bind_dn
if ldap_bind_password:
- params['ldap_bind_password'] = ldap_bind_password
+ params["ldap_bind_password"] = ldap_bind_password
else:
if ldap_userdirectory:
- directory = self._zapi.userdirectory.get({'search': {'name': ldap_userdirectory}})
+ directory = self._zapi.userdirectory.get(
+ {"search": {"name": ldap_userdirectory}}
+ )
if not directory:
- self._module.fail_json(msg="Canot find user directory with name: %s" % ldap_userdirectory)
- params['ldap_userdirectoryid'] = directory[0]['userdirectoryid']
+ self._module.fail_json(
+ msg="Canot find user directory with name: %s"
+ % ldap_userdirectory
+ )
+ params["ldap_userdirectoryid"] = directory[0]["userdirectoryid"]
if isinstance(ldap_case_sensitive, bool):
- params['ldap_case_sensitive'] = str(int(ldap_case_sensitive))
+ params["ldap_case_sensitive"] = str(int(ldap_case_sensitive))
if isinstance(saml_auth_enabled, bool):
- params['saml_auth_enabled'] = str(int(saml_auth_enabled))
+ params["saml_auth_enabled"] = str(int(saml_auth_enabled))
- if LooseVersion(self._zbx_api_version) < LooseVersion('6.4'):
+ if LooseVersion(self._zbx_api_version) < LooseVersion("6.4"):
if saml_idp_entityid:
- params['saml_idp_entityid'] = saml_idp_entityid
+ params["saml_idp_entityid"] = saml_idp_entityid
if saml_sso_url:
- params['saml_sso_url'] = saml_sso_url
+ params["saml_sso_url"] = saml_sso_url
if saml_slo_url:
- params['saml_slo_url'] = saml_slo_url
+ params["saml_slo_url"] = saml_slo_url
if saml_username_attribute:
- params['saml_username_attribute'] = saml_username_attribute
+ params["saml_username_attribute"] = saml_username_attribute
if saml_sp_entityid:
- params['saml_sp_entityid'] = saml_sp_entityid
+ params["saml_sp_entityid"] = saml_sp_entityid
if saml_nameid_format:
- params['saml_nameid_format'] = saml_nameid_format
+ params["saml_nameid_format"] = saml_nameid_format
if isinstance(saml_sign_messages, bool):
- params['saml_sign_messages'] = str(int(saml_sign_messages))
+ params["saml_sign_messages"] = str(int(saml_sign_messages))
if isinstance(saml_sign_assertions, bool):
- params['saml_sign_assertions'] = str(int(saml_sign_assertions))
+ params["saml_sign_assertions"] = str(int(saml_sign_assertions))
if isinstance(saml_sign_authn_requests, bool):
- params['saml_sign_authn_requests'] = str(int(saml_sign_authn_requests))
+ params["saml_sign_authn_requests"] = str(
+ int(saml_sign_authn_requests)
+ )
if isinstance(saml_sign_logout_requests, bool):
- params['saml_sign_logout_requests'] = str(int(saml_sign_logout_requests))
+ params["saml_sign_logout_requests"] = str(
+ int(saml_sign_logout_requests)
+ )
if isinstance(saml_sign_logout_responses, bool):
- params['saml_sign_logout_responses'] = str(int(saml_sign_logout_responses))
+ params["saml_sign_logout_responses"] = str(
+ int(saml_sign_logout_responses)
+ )
if isinstance(saml_encrypt_nameid, bool):
- params['saml_encrypt_nameid'] = str(int(saml_encrypt_nameid))
+ params["saml_encrypt_nameid"] = str(int(saml_encrypt_nameid))
if isinstance(saml_encrypt_assertions, bool):
- params['saml_encrypt_assertions'] = str(int(saml_encrypt_assertions))
+ params["saml_encrypt_assertions"] = str(
+ int(saml_encrypt_assertions)
+ )
if isinstance(saml_case_sensitive, bool):
- params['saml_case_sensitive'] = str(int(saml_case_sensitive))
+ params["saml_case_sensitive"] = str(int(saml_case_sensitive))
else:
if isinstance(ldap_jit_status, bool):
- params['ldap_jit_status'] = str(int(ldap_jit_status))
+ params["ldap_jit_status"] = str(int(ldap_jit_status))
if isinstance(saml_jit_status, bool):
- params['saml_jit_status'] = str(int(saml_jit_status))
+ params["saml_jit_status"] = str(int(saml_jit_status))
if isinstance(jit_provision_interval, str):
- params['jit_provision_interval'] = jit_provision_interval
+ params["jit_provision_interval"] = jit_provision_interval
if isinstance(disabled_usrgroup, str):
- usrgrpids = self._zapi.usergroup.get({'filter': {'name': disabled_usrgroup}})
+ usrgrpids = self._zapi.usergroup.get(
+ {"filter": {"name": disabled_usrgroup}}
+ )
if not usrgrpids:
- self._module.fail_json('User group "%s" cannot be found' % disabled_usrgroup)
- params['disabled_usrgrpid'] = str(int(usrgrpids[0]['usrgrpid']))
+ self._module.fail_json(
+ "User group '%s' cannot be found" % disabled_usrgroup
+ )
+ params["disabled_usrgrpid"] = str(int(usrgrpids[0]["usrgrpid"]))
if (ldap_jit_status or saml_jit_status) and not disabled_usrgroup:
- self._module.fail_json('"disabled_usrgroup" must be provided if "ldap_jit_status" or "saml_jit_status" enabled')
+ self._module.fail_json(
+ "'disabled_usrgroup' must be provided if 'ldap_jit_status' or 'saml_jit_status' enabled"
+ )
if passwd_min_length:
- if LooseVersion(self._zbx_api_version) < LooseVersion('6.0'):
- self._module.warn('passwd_min_length is ignored with Zabbix 5.4.')
- elif passwd_min_length < 1 or passwd_min_length > 70:
+ if passwd_min_length < 1 or passwd_min_length > 70:
self._module.fail_json(msg="Please set 0-70 to passwd_min_length.")
else:
- params['passwd_min_length'] = str(passwd_min_length)
+ params["passwd_min_length"] = str(passwd_min_length)
if passwd_check_rules:
- if LooseVersion(self._zbx_api_version) < LooseVersion('6.0'):
- self._module.warn('passwd_check_rules is ignored with Zabbix 5.4.')
- else:
- passwd_check_rules_values = [
- 'contain_uppercase_and_lowercase_letters',
- 'contain_digits',
- 'contain_special_characters',
- 'avoid_easy_to_guess'
- ]
- params['passwd_check_rules'] = 0
- if isinstance(passwd_check_rules, str):
- if passwd_check_rules not in passwd_check_rules_values:
- self._module.fail_json(msg="%s is invalid value for passwd_check_rules." % passwd_check_rules)
- params['passwd_check_rules'] += 2 ** zabbix_utils.helper_to_numeric_value(
- passwd_check_rules_values, passwd_check_rules
+ passwd_check_rules_values = [
+ "contain_uppercase_and_lowercase_letters",
+ "contain_digits",
+ "contain_special_characters",
+ "avoid_easy_to_guess",
+ ]
+ params["passwd_check_rules"] = 0
+ if isinstance(passwd_check_rules, str):
+ if passwd_check_rules not in passwd_check_rules_values:
+ self._module.fail_json(
+ msg="%s is invalid value for passwd_check_rules."
+ % passwd_check_rules
)
- elif isinstance(passwd_check_rules, list):
- for _passwd_check_rules_value in passwd_check_rules:
- if _passwd_check_rules_value not in passwd_check_rules_values:
- self._module.fail_json(msg="%s is invalid value for passwd_check_rules." % _passwd_check_rules_value)
- params['passwd_check_rules'] += 2 ** zabbix_utils.helper_to_numeric_value(
+ params[
+ "passwd_check_rules"
+ ] += 2 ** zabbix_utils.helper_to_numeric_value(
+ passwd_check_rules_values, passwd_check_rules
+ )
+ elif isinstance(passwd_check_rules, list):
+ for _passwd_check_rules_value in passwd_check_rules:
+ if (
+ _passwd_check_rules_value
+ not in passwd_check_rules_values
+ ):
+ self._module.fail_json(
+ msg="%s is invalid value for passwd_check_rules."
+ % _passwd_check_rules_value
+ )
+ params[
+ "passwd_check_rules"
+ ] += 2 ** zabbix_utils.helper_to_numeric_value(
passwd_check_rules_values, _passwd_check_rules_value
)
- params['passwd_check_rules'] = str(params['passwd_check_rules'])
+ params["passwd_check_rules"] = str(params["passwd_check_rules"])
future_authentication = current_authentication.copy()
future_authentication.update(params)
- if LooseVersion(self._zbx_api_version) < LooseVersion('6.4'):
- if (current_authentication['ldap_configured'] == '0'
- and future_authentication['ldap_configured'] == '1'):
- if LooseVersion(self._zbx_api_version) < LooseVersion('6.2.0'):
- if (not ldap_host
- or not ldap_port
- or not ldap_search_attribute
- or not ldap_base_dn):
+ if LooseVersion(self._zbx_api_version) < LooseVersion("6.4"):
+ if (
+ current_authentication["ldap_configured"] == "0"
+ and future_authentication["ldap_configured"] == "1"
+ ):
+ if LooseVersion(self._zbx_api_version) < LooseVersion("6.2"):
+ if (
+ not ldap_host
+ or not ldap_port
+ or not ldap_search_attribute
+ or not ldap_base_dn
+ ):
self._module.fail_json(
msg="Please set ldap_host, ldap_search_attribute and ldap_base_dn when you change a value of ldap_configured to true."
)
else:
if not ldap_userdirectory:
- self._module.fail_json(msg="Please set ldap_userdirectory when you change a value of ldap_configured to true.")
+ self._module.fail_json(
+ msg="Please set ldap_userdirectory when you change a value of ldap_configured to true."
+ )
else:
- if (current_authentication['ldap_auth_enabled'] == "0"
- and future_authentication['ldap_auth_enabled'] == "1"):
+ if (
+ current_authentication["ldap_auth_enabled"] == "0"
+ and future_authentication["ldap_auth_enabled"] == "1"
+ ):
if not ldap_userdirectory:
- self._module.fail_json(msg="Please set ldap_userdirectory when you change a value of ldap_auth_enabled to true.")
-
- if LooseVersion(self._zbx_api_version) < LooseVersion('6.4'):
- if (current_authentication['saml_auth_enabled'] == '0'
- and future_authentication['saml_auth_enabled'] == '1'
- and not saml_idp_entityid
- and not saml_sso_url
- and not saml_username_attribute
- and not saml_sp_entityid):
+ self._module.fail_json(
+ msg="Please set ldap_userdirectory when you change a value of ldap_auth_enabled to true."
+ )
+
+ if LooseVersion(self._zbx_api_version) < LooseVersion("6.4"):
+ if (
+ current_authentication["saml_auth_enabled"] == "0"
+ and future_authentication["saml_auth_enabled"] == "1"
+ and not saml_idp_entityid
+ and not saml_sso_url
+ and not saml_username_attribute
+ and not saml_sp_entityid
+ ):
self._module.fail_json(
- msg=' '.join([
- "Please set saml_idp_entityid, saml_sso_url, saml_username_attribute and saml_sp_entityid",
- "when you change a value of saml_auth_enabled to true."
- ])
+ msg=" ".join(
+ [
+ "Please set saml_idp_entityid, saml_sso_url, saml_username_attribute and saml_sp_entityid",
+ "when you change a value of saml_auth_enabled to true.",
+ ]
+ )
)
if future_authentication != current_authentication:
@@ -669,100 +708,101 @@ class Authentication(ZabbixBase):
self._module.exit_json(changed=True)
self._zapi.authentication.update(params)
- self._module.exit_json(changed=True, result="Successfully update authentication setting")
+ self._module.exit_json(
+ changed=True, result="Successfully update authentication setting"
+ )
else:
- self._module.exit_json(changed=False, result="Authentication setting is already up to date")
+ self._module.exit_json(
+ changed=False, result="Authentication setting is already up to date"
+ )
except Exception as e:
- self._module.fail_json(msg="Failed to update authentication setting, Exception: %s" % e)
+ self._module.fail_json(
+ msg="Failed to update authentication setting, Exception: %s" % e
+ )
def main():
argument_spec = zabbix_utils.zabbix_common_argument_spec()
- argument_spec.update(dict(
- authentication_type=dict(type='str', choices=['internal', 'ldap']),
- http_auth_enabled=dict(type='bool'),
- http_login_form=dict(type='str', choices=['zabbix_login_form', 'http_login_form']),
- http_strip_domains=dict(type='list', elements='str'),
- http_case_sensitive=dict(type='bool'),
- ldap_configured=dict(type='bool'),
- ldap_auth_enabled=dict(type='bool'),
- ldap_host=dict(type='str'),
- ldap_port=dict(type='int'),
- ldap_base_dn=dict(type='str'),
- ldap_search_attribute=dict(type='str'),
- ldap_bind_dn=dict(type='str'),
- ldap_case_sensitive=dict(type='bool'),
- ldap_bind_password=dict(type='str', no_log=True),
- ldap_userdirectory=dict(type='str'),
- ldap_jit_status=dict(type='bool'),
- saml_auth_enabled=dict(type='bool'),
- saml_idp_entityid=dict(type='str'),
- saml_sso_url=dict(type='str'),
- saml_slo_url=dict(type='str'),
- saml_username_attribute=dict(type='str'),
- saml_sp_entityid=dict(type='str'),
- saml_nameid_format=dict(type='str'),
- saml_sign_messages=dict(type='bool'),
- saml_sign_assertions=dict(type='bool'),
- saml_sign_authn_requests=dict(type='bool'),
- saml_sign_logout_requests=dict(type='bool'),
- saml_sign_logout_responses=dict(type='bool'),
- saml_encrypt_nameid=dict(type='bool'),
- saml_encrypt_assertions=dict(type='bool'),
- saml_case_sensitive=dict(type='bool'),
- saml_jit_status=dict(type='bool'),
- jit_provision_interval=dict(type='str', default='1h'),
- disabled_usrgroup=dict(type='str'),
- passwd_min_length=dict(type='int', no_log=False),
- passwd_check_rules=dict(type='list', elements='str', no_log=False)
- ))
- module = AnsibleModule(
- argument_spec=argument_spec,
- supports_check_mode=True
+ argument_spec.update(
+ dict(
+ authentication_type=dict(type="str", choices=["internal", "ldap"]),
+ http_auth_enabled=dict(type="bool"),
+ http_login_form=dict(
+ type="str", choices=["zabbix_login_form", "http_login_form"]
+ ),
+ http_strip_domains=dict(type="list", elements="str"),
+ http_case_sensitive=dict(type="bool"),
+ ldap_configured=dict(type="bool"),
+ ldap_auth_enabled=dict(type="bool"),
+ ldap_host=dict(type="str"),
+ ldap_port=dict(type="int"),
+ ldap_base_dn=dict(type="str"),
+ ldap_search_attribute=dict(type="str"),
+ ldap_bind_dn=dict(type="str"),
+ ldap_case_sensitive=dict(type="bool"),
+ ldap_bind_password=dict(type="str", no_log=True),
+ ldap_userdirectory=dict(type="str"),
+ ldap_jit_status=dict(type="bool"),
+ saml_auth_enabled=dict(type="bool"),
+ saml_idp_entityid=dict(type="str"),
+ saml_sso_url=dict(type="str"),
+ saml_slo_url=dict(type="str"),
+ saml_username_attribute=dict(type="str"),
+ saml_sp_entityid=dict(type="str"),
+ saml_nameid_format=dict(type="str"),
+ saml_sign_messages=dict(type="bool"),
+ saml_sign_assertions=dict(type="bool"),
+ saml_sign_authn_requests=dict(type="bool"),
+ saml_sign_logout_requests=dict(type="bool"),
+ saml_sign_logout_responses=dict(type="bool"),
+ saml_encrypt_nameid=dict(type="bool"),
+ saml_encrypt_assertions=dict(type="bool"),
+ saml_case_sensitive=dict(type="bool"),
+ saml_jit_status=dict(type="bool"),
+ jit_provision_interval=dict(type="str", default="1h"),
+ disabled_usrgroup=dict(type="str"),
+ passwd_min_length=dict(type="int", no_log=False),
+ passwd_check_rules=dict(type="list", elements="str", no_log=False),
+ )
)
-
- zabbix_utils.require_creds_params(module)
-
- for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']:
- if p in module.params and not module.params[p] is None:
- module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p)
-
- authentication_type = module.params['authentication_type']
- http_auth_enabled = module.params['http_auth_enabled']
- http_login_form = module.params['http_login_form']
- http_strip_domains = module.params['http_strip_domains']
- http_case_sensitive = module.params['http_case_sensitive']
- ldap_configured = module.params['ldap_configured']
- ldap_auth_enabled = module.params['ldap_auth_enabled']
- ldap_host = module.params['ldap_host']
- ldap_port = module.params['ldap_port']
- ldap_base_dn = module.params['ldap_base_dn']
- ldap_search_attribute = module.params['ldap_search_attribute']
- ldap_bind_dn = module.params['ldap_bind_dn']
- ldap_case_sensitive = module.params['ldap_case_sensitive']
- ldap_bind_password = module.params['ldap_bind_password']
- ldap_userdirectory = module.params['ldap_userdirectory']
- saml_auth_enabled = module.params['saml_auth_enabled']
- saml_idp_entityid = module.params['saml_idp_entityid']
- saml_sso_url = module.params['saml_sso_url']
- saml_slo_url = module.params['saml_slo_url']
- saml_username_attribute = module.params['saml_username_attribute']
- saml_sp_entityid = module.params['saml_sp_entityid']
- saml_nameid_format = module.params['saml_nameid_format']
- saml_sign_messages = module.params['saml_sign_messages']
- saml_sign_assertions = module.params['saml_sign_assertions']
- saml_sign_authn_requests = module.params['saml_sign_authn_requests']
- saml_sign_logout_requests = module.params['saml_sign_logout_requests']
- saml_sign_logout_responses = module.params['saml_sign_logout_responses']
- saml_encrypt_nameid = module.params['saml_encrypt_nameid']
- saml_encrypt_assertions = module.params['saml_encrypt_assertions']
- saml_case_sensitive = module.params['saml_case_sensitive']
- passwd_min_length = module.params['passwd_min_length']
- passwd_check_rules = module.params['passwd_check_rules']
- ldap_jit_status = module.params['ldap_jit_status']
- saml_jit_status = module.params['saml_jit_status']
- jit_provision_interval = module.params['jit_provision_interval']
- disabled_usrgroup = module.params['disabled_usrgroup']
+ module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)
+
+ authentication_type = module.params["authentication_type"]
+ http_auth_enabled = module.params["http_auth_enabled"]
+ http_login_form = module.params["http_login_form"]
+ http_strip_domains = module.params["http_strip_domains"]
+ http_case_sensitive = module.params["http_case_sensitive"]
+ ldap_configured = module.params["ldap_configured"]
+ ldap_auth_enabled = module.params["ldap_auth_enabled"]
+ ldap_host = module.params["ldap_host"]
+ ldap_port = module.params["ldap_port"]
+ ldap_base_dn = module.params["ldap_base_dn"]
+ ldap_search_attribute = module.params["ldap_search_attribute"]
+ ldap_bind_dn = module.params["ldap_bind_dn"]
+ ldap_case_sensitive = module.params["ldap_case_sensitive"]
+ ldap_bind_password = module.params["ldap_bind_password"]
+ ldap_userdirectory = module.params["ldap_userdirectory"]
+ saml_auth_enabled = module.params["saml_auth_enabled"]
+ saml_idp_entityid = module.params["saml_idp_entityid"]
+ saml_sso_url = module.params["saml_sso_url"]
+ saml_slo_url = module.params["saml_slo_url"]
+ saml_username_attribute = module.params["saml_username_attribute"]
+ saml_sp_entityid = module.params["saml_sp_entityid"]
+ saml_nameid_format = module.params["saml_nameid_format"]
+ saml_sign_messages = module.params["saml_sign_messages"]
+ saml_sign_assertions = module.params["saml_sign_assertions"]
+ saml_sign_authn_requests = module.params["saml_sign_authn_requests"]
+ saml_sign_logout_requests = module.params["saml_sign_logout_requests"]
+ saml_sign_logout_responses = module.params["saml_sign_logout_responses"]
+ saml_encrypt_nameid = module.params["saml_encrypt_nameid"]
+ saml_encrypt_assertions = module.params["saml_encrypt_assertions"]
+ saml_case_sensitive = module.params["saml_case_sensitive"]
+ passwd_min_length = module.params["passwd_min_length"]
+ passwd_check_rules = module.params["passwd_check_rules"]
+ ldap_jit_status = module.params["ldap_jit_status"]
+ saml_jit_status = module.params["saml_jit_status"]
+ jit_provision_interval = module.params["jit_provision_interval"]
+ disabled_usrgroup = module.params["disabled_usrgroup"]
authentication = Authentication(module)
@@ -804,9 +844,9 @@ def main():
ldap_jit_status,
saml_jit_status,
jit_provision_interval,
- disabled_usrgroup
+ disabled_usrgroup,
)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_autoregister.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_autoregister.py
index c8bf35538..c00f52cbe 100644
--- a/ansible_collections/community/zabbix/plugins/modules/zabbix_autoregister.py
+++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_autoregister.py
@@ -8,7 +8,7 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type
-DOCUMENTATION = '''
+DOCUMENTATION = """
---
module: zabbix_autoregister
@@ -22,7 +22,7 @@ author:
- ONODERA Masaru(@masa-orca)
requirements:
- - "python >= 2.6"
+ - "python >= 3.9"
version_added: 1.6.0
@@ -47,7 +47,6 @@ options:
type: str
notes:
- - Only Zabbix >= 4.4 is supported.
- This module returns changed=true when any value is set in I(tls_psk_identity) or I(tls_psk) as Zabbix API
will not return any sensitive information back for module to compare.
- Please note that this module configures B(global Zabbix Server settings).
@@ -57,19 +56,19 @@ notes:
extends_documentation_fragment:
- community.zabbix.zabbix
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = """
# If you want to use Username and Password to be authenticated by Zabbix Server
- name: Set credentials to access Zabbix Server API
- set_fact:
+ ansible.builtin.set_fact:
ansible_user: Admin
ansible_httpapi_pass: zabbix
# If you want to use API token to be authenticated by Zabbix Server
# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens
- name: Set API token
- set_fact:
+ ansible.builtin.set_fact:
ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895
- name: Update autoregistration
@@ -80,16 +79,13 @@ EXAMPLES = '''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_autoregister:
- server_url: "http://zabbix.example.com/zabbix/"
- login_user: Admin
- login_password: secret
tls_accept:
- unsecure
- tls_with_psk
- tls_psk_identity: 'PSK 001'
+ tls_psk_identity: "PSK 001"
tls_psk: "11111595725ac58dd977beef14b97461a7c1045b9a1c923453302c5473193478"
- name: Set unsecure to tls_accept
@@ -100,42 +96,32 @@ EXAMPLES = '''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_autoregister:
- server_url: "http://zabbix.example.com/zabbix/"
- login_user: Admin
- login_password: secret
tls_accept: unsecure
-'''
+"""
-RETURN = '''
+RETURN = """
msg:
description: The result of the operation
returned: success
type: str
- sample: 'Successfully updated global autoregistration setting'
-'''
+ sample: "Successfully updated global autoregistration setting"
+"""
from ansible.module_utils.basic import AnsibleModule
-
from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase
-from ansible.module_utils.compat.version import LooseVersion
-
import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils
class Autoregistration(ZabbixBase):
- def __init__(self, module, zbx=None, zapi_wrapper=None):
- super(Autoregistration, self).__init__(module, zbx, zapi_wrapper)
- if LooseVersion(self._zbx_api_version) < LooseVersion('4.4.0'):
- module.fail_json(msg="This module doesn't support Zabbix versions lower than 4.4.0")
# get autoregistration
def get_autoregistration(self):
try:
- return self._zapi.autoregistration.get({"output": 'extend'})
+ return self._zapi.autoregistration.get({"output": "extend"})
except Exception as e:
self._module.fail_json(msg="Failed to get autoregistration: %s" % e)
@@ -143,38 +129,38 @@ class Autoregistration(ZabbixBase):
def update_autoregistration(self, current_setting, tls_accept, tls_psk_identity, tls_psk):
tls_accept_values = [
None,
- 'unsecure',
- 'tls_with_psk'
+ "unsecure",
+ "tls_with_psk"
]
params = {}
try:
if isinstance(tls_accept, str):
- params['tls_accept'] = zabbix_utils.helper_to_numeric_value(
+ params["tls_accept"] = zabbix_utils.helper_to_numeric_value(
tls_accept_values, tls_accept
)
elif isinstance(tls_accept, list):
- params['tls_accept'] = 0
+ params["tls_accept"] = 0
for _tls_accept_value in tls_accept:
- params['tls_accept'] += zabbix_utils.helper_to_numeric_value(
+ params["tls_accept"] += zabbix_utils.helper_to_numeric_value(
tls_accept_values, _tls_accept_value
)
else:
self._module.fail_json(msg="Value of tls_accept must be list or string.")
if tls_psk_identity:
- params['tls_psk_identity'] = tls_psk_identity
+ params["tls_psk_identity"] = tls_psk_identity
if tls_psk:
- params['tls_psk'] = tls_psk
+ params["tls_psk"] = tls_psk
- current_tls_accept = int(current_setting['tls_accept'])
- if (current_tls_accept == tls_accept_values.index('unsecure')
- and params['tls_accept'] >= tls_accept_values.index('tls_with_psk')):
+ current_tls_accept = int(current_setting["tls_accept"])
+ if (current_tls_accept == tls_accept_values.index("unsecure")
+ and params["tls_accept"] >= tls_accept_values.index("tls_with_psk")):
if not tls_psk_identity or not tls_psk:
self._module.fail_json(msg="Please set tls_psk_identity and tls_psk.")
if (not tls_psk_identity and not tls_psk
- and params['tls_accept'] == current_tls_accept):
+ and params["tls_accept"] == current_tls_accept):
self._module.exit_json(changed=False, result="Autoregistration is already up to date")
if self._module.check_mode:
@@ -192,32 +178,26 @@ def main():
argument_spec = zabbix_utils.zabbix_common_argument_spec()
argument_spec.update(dict(
tls_accept=dict(
- type='list',
- elements='str',
+ type="list",
+ elements="str",
required=True
),
- tls_psk_identity=dict(type='str', required=False, no_log=True),
- tls_psk=dict(type='str', required=False, no_log=True),
+ tls_psk_identity=dict(type="str", required=False, no_log=True),
+ tls_psk=dict(type="str", required=False, no_log=True),
))
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True
)
- zabbix_utils.require_creds_params(module)
-
- for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']:
- if p in module.params and not module.params[p] is None:
- module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p)
-
- tls_accept = module.params['tls_accept']
- tls_psk_identity = module.params['tls_psk_identity']
- tls_psk = module.params['tls_psk']
+ tls_accept = module.params["tls_accept"]
+ tls_psk_identity = module.params["tls_psk_identity"]
+ tls_psk = module.params["tls_psk"]
autoregistration_class_obj = Autoregistration(module)
current_setting = autoregistration_class_obj.get_autoregistration()
autoregistration_class_obj.update_autoregistration(current_setting, tls_accept, tls_psk_identity, tls_psk)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_discovery_rule.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_discovery_rule.py
index 11b2f7c7f..2296f3db8 100644
--- a/ansible_collections/community/zabbix/plugins/modules/zabbix_discovery_rule.py
+++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_discovery_rule.py
@@ -7,7 +7,7 @@
from __future__ import absolute_import, division, print_function
__metaclass__ = type
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: zabbix_discovery_rule
short_description: Create/delete/update Zabbix discovery rules
@@ -18,7 +18,7 @@ description:
author:
- "Tobias Birkefeld (@tcraxs)"
requirements:
- - "python >= 2.6"
+ - "python >= 3.9"
options:
state:
description:
@@ -46,22 +46,22 @@ options:
description:
- Type of check.
type: str
- choices: ['SSH',
- 'LDAP',
- 'SMTP',
- 'FTP',
- 'HTTP',
- 'POP',
- 'NNTP',
- 'IMAP',
- 'TCP',
- 'Zabbix',
- 'SNMPv1',
- 'SNMPv2',
- 'ICMP',
- 'SNMPv3',
- 'HTTPS',
- 'Telnet']
+ choices: ["SSH",
+ "LDAP",
+ "SMTP",
+ "FTP",
+ "HTTP",
+ "POP",
+ "NNTP",
+ "IMAP",
+ "TCP",
+ "Zabbix",
+ "SNMPv1",
+ "SNMPv2",
+ "ICMP",
+ "SNMPv3",
+ "HTTPS",
+ "Telnet"]
ports:
description:
- One or several port ranges to check separated by commas. Used for all checks except for ICMP.
@@ -173,23 +173,22 @@ options:
type: str
default: "enabled"
choices: ["enabled", "disabled"]
-notes:
- - Only Zabbix >= 4.0 is supported.
+
extends_documentation_fragment:
- community.zabbix.zabbix
-'''
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
# If you want to use Username and Password to be authenticated by Zabbix Server
- name: Set credentials to access Zabbix Server API
- set_fact:
+ ansible.builtin.set_fact:
ansible_user: Admin
ansible_httpapi_pass: zabbix
# If you want to use API token to be authenticated by Zabbix Server
# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens
- name: Set API token
- set_fact:
+ ansible.builtin.set_fact:
ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895
# Base create discovery rule example
@@ -201,7 +200,7 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_discovery_rule:
name: ACME
@@ -224,7 +223,7 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_discovery_rule:
name: ACME
@@ -255,35 +254,35 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_discovery_rule:
name: ACME
state: absent
-'''
+"""
-RETURN = r'''
+RETURN = r"""
state:
description: Discovery rule state at the end of execution.
returned: on success
type: str
- sample: 'present'
+ sample: "present"
drule:
description: Discovery rule name.
returned: on success
type: str
- sample: 'ACME'
+ sample: "ACME"
druleid:
description: Discovery rule id.
returned: on success
type: str
- sample: '42'
+ sample: "42"
msg:
description: The result of the operation
returned: always
type: str
- sample: 'Discovery rule created: ACME, ID: 42'
-'''
+ sample: "Discovery rule created: ACME, ID: 42"
+"""
from ansible.module_utils.basic import AnsibleModule
@@ -312,72 +311,71 @@ class Dchecks(ZabbixBase):
constructed_data = []
for check in _dchecks:
constructed_check = {
- 'type': zabbix_utils.helper_to_numeric_value([
- 'SSH',
- 'LDAP',
- 'SMTP',
- 'FTP',
- 'HTTP',
- 'POP',
- 'NNTP',
- 'IMAP',
- 'TCP',
- 'Zabbix',
- 'SNMPv1',
- 'SNMPv2',
- 'ICMP',
- 'SNMPv3',
- 'HTTPS',
- 'Telnet'], check.get('type')
+ "type": zabbix_utils.helper_to_numeric_value([
+ "SSH",
+ "LDAP",
+ "SMTP",
+ "FTP",
+ "HTTP",
+ "POP",
+ "NNTP",
+ "IMAP",
+ "TCP",
+ "Zabbix",
+ "SNMPv1",
+ "SNMPv2",
+ "ICMP",
+ "SNMPv3",
+ "HTTPS",
+ "Telnet"], check.get("type")
),
- 'uniq': int(check.get('uniq'))
+ "uniq": int(check.get("uniq"))
}
- if LooseVersion(self._zbx_api_version) >= LooseVersion('4.4'):
- constructed_check.update({
- 'host_source': zabbix_utils.helper_to_numeric_value([
- 'None',
- 'DNS',
- 'IP',
- 'discovery'], check.get('host_source')
- ),
- 'name_source': zabbix_utils.helper_to_numeric_value([
- 'None',
- 'DNS',
- 'IP',
- 'discovery'], check.get('name_source')
- )
- })
- if constructed_check['type'] in (0, 1, 2, 3, 4, 5, 6, 7, 8, 14, 15):
- constructed_check['ports'] = check.get('ports')
- if constructed_check['type'] == 9:
- constructed_check['ports'] = check.get('ports')
- constructed_check['key_'] = check.get('key')
- if constructed_check['type'] in (10, 11):
- constructed_check['ports'] = check.get('ports')
- constructed_check['snmp_community'] = check.get('snmp_community')
- constructed_check['key_'] = check.get('key')
- if constructed_check['type'] == 13:
- constructed_check['ports'] = check.get('ports')
- constructed_check['key_'] = check.get('key')
- constructed_check['snmpv3_contextname'] = check.get('snmpv3_contextname')
- constructed_check['snmpv3_securityname'] = check.get('snmpv3_securityname')
- constructed_check['snmpv3_securitylevel'] = zabbix_utils.helper_to_numeric_value([
- 'noAuthNoPriv',
- 'authNoPriv',
- 'authPriv'], check.get('snmpv3_securitylevel')
+ constructed_check.update({
+ "host_source": zabbix_utils.helper_to_numeric_value([
+ "None",
+ "DNS",
+ "IP",
+ "discovery"], check.get("host_source")
+ ),
+ "name_source": zabbix_utils.helper_to_numeric_value([
+ "None",
+ "DNS",
+ "IP",
+ "discovery"], check.get("name_source")
+ )
+ })
+ if constructed_check["type"] in (0, 1, 2, 3, 4, 5, 6, 7, 8, 14, 15):
+ constructed_check["ports"] = check.get("ports")
+ if constructed_check["type"] == 9:
+ constructed_check["ports"] = check.get("ports")
+ constructed_check["key_"] = check.get("key")
+ if constructed_check["type"] in (10, 11):
+ constructed_check["ports"] = check.get("ports")
+ constructed_check["snmp_community"] = check.get("snmp_community")
+ constructed_check["key_"] = check.get("key")
+ if constructed_check["type"] == 13:
+ constructed_check["ports"] = check.get("ports")
+ constructed_check["key_"] = check.get("key")
+ constructed_check["snmpv3_contextname"] = check.get("snmpv3_contextname")
+ constructed_check["snmpv3_securityname"] = check.get("snmpv3_securityname")
+ constructed_check["snmpv3_securitylevel"] = zabbix_utils.helper_to_numeric_value([
+ "noAuthNoPriv",
+ "authNoPriv",
+ "authPriv"], check.get("snmpv3_securitylevel")
)
- if constructed_check['snmpv3_securitylevel'] in (1, 2):
- constructed_check['snmpv3_authprotocol'] = zabbix_utils.helper_to_numeric_value([
- 'MD5',
- 'SHA'], check.get('snmpv3_authprotocol')
+ if constructed_check["snmpv3_securitylevel"] in (1, 2):
+ constructed_check["snmpv3_authprotocol"] = zabbix_utils.helper_to_numeric_value([
+ "MD5",
+ "SHA"], check.get("snmpv3_authprotocol")
)
- constructed_check['snmpv3_authpassphrase'] = check.get('snmpv3_authpassphrase')
- if constructed_check['snmpv3_securitylevel'] == 2:
- constructed_check['snmpv3_privprotocol'] = zabbix_utils.helper_to_numeric_value([
- 'DES',
- 'AES'], check.get('snmpv3_privprotocol')
+ constructed_check["snmpv3_authpassphrase"] = check.get("snmpv3_authpassphrase")
+ if constructed_check["snmpv3_securitylevel"] == 2:
+ constructed_check["snmpv3_privprotocol"] = zabbix_utils.helper_to_numeric_value([
+ "DES",
+ "AES"], check.get("snmpv3_privprotocol")
)
- constructed_check['snmpv3_privpassphrase'] = check.get('snmpv3_privpassphrase')
+ constructed_check["snmpv3_privpassphrase"] = check.get("snmpv3_privpassphrase")
constructed_data.append(constructed_check)
return zabbix_utils.helper_cleanup_data(constructed_data)
@@ -392,9 +390,9 @@ class DiscoveryRule(ZabbixBase):
"""
try:
_drule = self._zapi.drule.get({
- 'output': 'extend',
- 'selectDChecks': 'extend',
- 'filter': {'name': [name]}
+ "output": "extend",
+ "selectDChecks": "extend",
+ "filter": {"name": [name]}
})
if len(_drule) > 0:
return _drule
@@ -411,9 +409,9 @@ class DiscoveryRule(ZabbixBase):
"""
try:
drule_list = self._zapi.drule.get({
- 'output': 'extend',
- 'selectDChecks': 'extend',
- 'filter': {'name': [name]}
+ "output": "extend",
+ "selectDChecks": "extend",
+ "filter": {"name": [name]}
})
if len(drule_list) < 1:
self._module.fail_json(msg="Discovery rule not found: %s" % name)
@@ -431,9 +429,9 @@ class DiscoveryRule(ZabbixBase):
"""
try:
proxy_list = self._zapi.proxy.get({
- 'output': 'extend',
- 'selectInterface': 'extend',
- 'filter': {'host': [proxy_name]}
+ "output": "extend",
+ "selectInterface": "extend",
+ "filter": {"host": [proxy_name]}
})
if len(proxy_list) < 1:
self._module.fail_json(msg="Proxy not found: %s" % proxy_name)
@@ -450,17 +448,17 @@ class DiscoveryRule(ZabbixBase):
dict: dictionary of specified parameters
"""
_params = {
- 'name': kwargs['name'],
- 'iprange': ','.join(kwargs['iprange']),
- 'delay': kwargs['delay'],
- 'status': zabbix_utils.helper_to_numeric_value([
- 'enabled',
- 'disabled'], kwargs['status']
+ "name": kwargs["name"],
+ "iprange": ",".join(kwargs["iprange"]),
+ "delay": kwargs["delay"],
+ "status": zabbix_utils.helper_to_numeric_value([
+ "enabled",
+ "disabled"], kwargs["status"]
),
- 'dchecks': kwargs['dchecks']
+ "dchecks": kwargs["dchecks"]
}
- if kwargs['proxy']:
- _params['proxy_hostid'] = self.get_proxy_by_proxy_name(kwargs['proxy'])['proxyid']
+ if kwargs["proxy"]:
+ _params["proxy_hostid"] = self.get_proxy_by_proxy_name(kwargs["proxy"])["proxyid"]
return _params
def check_difference(self, **kwargs):
@@ -470,13 +468,13 @@ class DiscoveryRule(ZabbixBase):
Returns:
dict: dictionary of differences
"""
- existing_drule = zabbix_utils.helper_convert_unicode_to_str(self.check_if_drule_exists(kwargs['name'])[0])
+ existing_drule = zabbix_utils.helper_convert_unicode_to_str(self.check_if_drule_exists(kwargs["name"])[0])
parameters = zabbix_utils.helper_convert_unicode_to_str(self._construct_parameters(**kwargs))
change_parameters = {}
- if LooseVersion(self._zbx_api_version) < LooseVersion('6.4'):
- if existing_drule['nextcheck']:
- existing_drule.pop('nextcheck')
- _diff = zabbix_utils.helper_cleanup_data(compare_dictionaries(parameters, existing_drule, change_parameters))
+ if LooseVersion(self._zbx_api_version) < LooseVersion("6.4"):
+ if existing_drule["nextcheck"]:
+ existing_drule.pop("nextcheck")
+ _diff = zabbix_utils.helper_cleanup_data(zabbix_utils.helper_compare_dictionaries(parameters, existing_drule, change_parameters))
return _diff
def update_drule(self, **kwargs):
@@ -488,11 +486,11 @@ class DiscoveryRule(ZabbixBase):
"""
try:
if self._module.check_mode:
- self._module.exit_json(msg="Discovery rule would be updated if check mode was not specified: ID %s" % kwargs['drule_id'], changed=True)
- kwargs['druleid'] = kwargs.pop('drule_id')
+ self._module.exit_json(msg="Discovery rule would be updated if check mode was not specified: ID %s" % kwargs["drule_id"], changed=True)
+ kwargs["druleid"] = kwargs.pop("drule_id")
return self._zapi.drule.update(kwargs)
except Exception as e:
- self._module.fail_json(msg="Failed to update discovery rule ID '%s': %s" % (kwargs['drule_id'], e))
+ self._module.fail_json(msg="Failed to update discovery rule ID '%s': %s" % (kwargs["drule_id"], e))
def add_drule(self, **kwargs):
"""Add discovery rule
@@ -506,9 +504,9 @@ class DiscoveryRule(ZabbixBase):
self._module.exit_json(msg="Discovery rule would be added if check mode was not specified", changed=True)
parameters = self._construct_parameters(**kwargs)
drule_list = self._zapi.drule.create(parameters)
- return drule_list['druleids'][0]
+ return drule_list["druleids"][0]
except Exception as e:
- self._module.fail_json(msg="Failed to create discovery rule %s: %s" % (kwargs['name'], e))
+ self._module.fail_json(msg="Failed to create discovery rule %s: %s" % (kwargs["name"], e))
def delete_drule(self, drule_id):
"""Delete discovery rule.
@@ -525,159 +523,90 @@ class DiscoveryRule(ZabbixBase):
self._module.fail_json(msg="Failed to delete discovery rule '%s': %s" % (drule_id, e))
-def compare_lists(l1, l2, diff_dict):
- """
- Compares l1 and l2 lists and adds the items that are different
- to the diff_dict dictionary.
- Used in recursion with compare_dictionaries() function.
- Args:
- l1: first list to compare
- l2: second list to compare
- diff_dict: dictionary to store the difference
- Returns:
- dict: items that are different
- """
- if len(l1) != len(l2):
- diff_dict.append(l1)
- return diff_dict
- for i, item in enumerate(l1):
- if isinstance(item, dict):
- diff_dict.insert(i, {})
- diff_dict[i] = compare_dictionaries(item, l2[i], diff_dict[i])
- else:
- if item != l2[i]:
- diff_dict.append(item)
- while {} in diff_dict:
- diff_dict.remove({})
- return diff_dict
-
-
-def compare_dictionaries(d1, d2, diff_dict):
- """
- Compares d1 and d2 dictionaries and adds the items that are different
- to the diff_dict dictionary.
- Used in recursion with compare_lists() function.
- Args:
- d1: first dictionary to compare
- d2: second dictionary to compare
- diff_dict: dictionary to store the difference
- Returns:
- dict: items that are different
- """
- for k, v in d1.items():
- if k not in d2:
- diff_dict[k] = v
- continue
- if isinstance(v, dict):
- diff_dict[k] = {}
- compare_dictionaries(v, d2[k], diff_dict[k])
- if diff_dict[k] == {}:
- del diff_dict[k]
- else:
- diff_dict[k] = v
- elif isinstance(v, list):
- diff_dict[k] = []
- compare_lists(v, d2[k], diff_dict[k])
- if diff_dict[k] == []:
- del diff_dict[k]
- else:
- diff_dict[k] = v
- else:
- if v != d2[k]:
- diff_dict[k] = v
- return diff_dict
-
-
def main():
argument_spec = zabbix_utils.zabbix_common_argument_spec()
argument_spec.update(
- name=dict(type='str', required=True),
- iprange=dict(type='list', required=False, elements='str'),
+ name=dict(type="str", required=True),
+ iprange=dict(type="list", required=False, elements="str"),
dchecks=dict(
- type='list',
+ type="list",
required=False,
- aliases=['dcheck'],
- elements='dict',
+ aliases=["dcheck"],
+ elements="dict",
options=dict(
- type=dict(type='str', choices=[
- 'SSH',
- 'LDAP',
- 'SMTP',
- 'FTP',
- 'HTTP',
- 'POP',
- 'NNTP',
- 'IMAP',
- 'TCP',
- 'Zabbix',
- 'SNMPv1',
- 'SNMPv2',
- 'ICMP',
- 'SNMPv3',
- 'HTTPS',
- 'Telnet']
+ type=dict(type="str", choices=[
+ "SSH",
+ "LDAP",
+ "SMTP",
+ "FTP",
+ "HTTP",
+ "POP",
+ "NNTP",
+ "IMAP",
+ "TCP",
+ "Zabbix",
+ "SNMPv1",
+ "SNMPv2",
+ "ICMP",
+ "SNMPv3",
+ "HTTPS",
+ "Telnet"]
),
- ports=dict(type='str'),
- key=dict(type='str', no_log=False),
- snmp_community=dict(type='str'),
- snmpv3_authpassphrase=dict(type='str', no_log=True),
- snmpv3_authprotocol=dict(type='str', choices=['MD5', 'SHA']),
- snmpv3_contextname=dict(type='str'),
- snmpv3_privpassphrase=dict(type='str', no_log=True),
- snmpv3_privprotocol=dict(type='str', choices=['DES', 'AES']),
- snmpv3_securitylevel=dict(type='str', choices=['noAuthNoPriv', 'authNoPriv', 'authPriv']),
- snmpv3_securityname=dict(type='str'),
- uniq=dict(type='bool', default=False),
- host_source=dict(type='str', choices=['DNS', 'IP', 'discovery'], default='DNS'),
- name_source=dict(type='str', choices=['None', 'DNS', 'IP', 'discovery'], default='None')
+ ports=dict(type="str"),
+ key=dict(type="str", no_log=False),
+ snmp_community=dict(type="str"),
+ snmpv3_authpassphrase=dict(type="str", no_log=True),
+ snmpv3_authprotocol=dict(type="str", choices=["MD5", "SHA"]),
+ snmpv3_contextname=dict(type="str"),
+ snmpv3_privpassphrase=dict(type="str", no_log=True),
+ snmpv3_privprotocol=dict(type="str", choices=["DES", "AES"]),
+ snmpv3_securitylevel=dict(type="str", choices=["noAuthNoPriv", "authNoPriv", "authPriv"]),
+ snmpv3_securityname=dict(type="str"),
+ uniq=dict(type="bool", default=False),
+ host_source=dict(type="str", choices=["DNS", "IP", "discovery"], default="DNS"),
+ name_source=dict(type="str", choices=["None", "DNS", "IP", "discovery"], default="None")
),
required_if=[
- ['type', 'SSH', ['ports']],
- ['type', 'LDAP', ['ports']],
- ['type', 'SMTP', ['ports']],
- ['type', 'FTP', ['ports']],
- ['type', 'HTTP', ['ports']],
- ['type', 'POP', ['ports']],
- ['type', 'NNTP', ['ports']],
- ['type', 'IMAP', ['ports']],
- ['type', 'TCP', ['ports']],
- ['type', 'Zabbix', ['ports', 'key']],
- ['type', 'SNMPv1', ['ports', 'key', 'snmp_community']],
- ['type', 'SNMPv2', ['ports', 'key', 'snmp_community']],
- ['type', 'SNMPv3', ['ports', 'key']],
- ['type', 'HTTPS', ['ports']],
- ['type', 'Telnet', ['ports']],
- ['snmpv3_securitylevel', 'authPriv', ['snmpv3_privpassphrase']]
+ ["type", "SSH", ["ports"]],
+ ["type", "LDAP", ["ports"]],
+ ["type", "SMTP", ["ports"]],
+ ["type", "FTP", ["ports"]],
+ ["type", "HTTP", ["ports"]],
+ ["type", "POP", ["ports"]],
+ ["type", "NNTP", ["ports"]],
+ ["type", "IMAP", ["ports"]],
+ ["type", "TCP", ["ports"]],
+ ["type", "Zabbix", ["ports", "key"]],
+ ["type", "SNMPv1", ["ports", "key", "snmp_community"]],
+ ["type", "SNMPv2", ["ports", "key", "snmp_community"]],
+ ["type", "SNMPv3", ["ports", "key"]],
+ ["type", "HTTPS", ["ports"]],
+ ["type", "Telnet", ["ports"]],
+ ["snmpv3_securitylevel", "authPriv", ["snmpv3_privpassphrase"]]
]
),
- delay=dict(type='str', required=False, default='1h'),
- proxy=dict(type='str', required=False, default=None),
- status=dict(type='str', default="enabled", choices=["enabled", "disabled"]),
- state=dict(type='str', default='present', choices=['present', 'absent'])
+ delay=dict(type="str", required=False, default="1h"),
+ proxy=dict(type="str", required=False, default=None),
+ status=dict(type="str", default="enabled", choices=["enabled", "disabled"]),
+ state=dict(type="str", default="present", choices=["present", "absent"])
)
module = AnsibleModule(
argument_spec=argument_spec,
required_if=[
- ['state', 'present', ['name', 'iprange', 'dchecks']],
- ['state', 'absent', ['name']],
+ ["state", "present", ["name", "iprange", "dchecks"]],
+ ["state", "absent", ["name"]],
],
supports_check_mode=True
)
- zabbix_utils.require_creds_params(module)
-
- for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']:
- if p in module.params and not module.params[p] is None:
- module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p)
-
- state = module.params['state']
- name = module.params['name']
- iprange = module.params['iprange']
- dchecks = module.params['dchecks']
- delay = module.params['delay']
- proxy = module.params['proxy']
- status = module.params['status']
+ state = module.params["state"]
+ name = module.params["name"]
+ iprange = module.params["iprange"]
+ dchecks = module.params["dchecks"]
+ delay = module.params["delay"]
+ proxy = module.params["proxy"]
+ status = module.params["status"]
drule = DiscoveryRule(module)
zbx = drule._zapi
@@ -686,7 +615,7 @@ def main():
drule_exists = drule.check_if_drule_exists(name)
if drule_exists:
- drule_id = drule.get_drule_by_drule_name(name)['druleid']
+ drule_id = drule.get_drule_by_drule_name(name)["druleid"]
if state == "absent":
drule.delete_drule(drule_id)
module.exit_json(changed=True, state=state, drule=name, druleid=drule_id, msg="Discovery Rule deleted: %s, ID: %s" % (name, drule_id))
@@ -724,5 +653,5 @@ def main():
module.exit_json(changed=True, state=state, drule=name, druleid=drule_id, msg="Discovery Rule created: %s, ID: %s" % (name, drule_id))
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_globalmacro.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_globalmacro.py
index d0221223b..111c80c55 100644
--- a/ansible_collections/community/zabbix/plugins/modules/zabbix_globalmacro.py
+++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_globalmacro.py
@@ -8,7 +8,7 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: zabbix_globalmacro
short_description: Create/update/delete Zabbix Global macros
@@ -21,7 +21,7 @@ author:
- Dean Hailin Song (!UNKNOWN)
- Timothy Test (@ttestscripting)
requirements:
- - "python >= 2.6"
+ - "python >= 3.9"
options:
macro_name:
description:
@@ -46,42 +46,41 @@ options:
macro_description:
description:
- Text Description of the global macro.
- - Works only with Zabbix >= 4.4 and is silently ignored in lower versions
type: str
- default: ''
+ default: ""
state:
description:
- State of the macro.
- On C(present), it will create if macro does not exist or update the macro if the associated data is different.
- On C(absent) will remove a macro if it exists.
required: false
- choices: ['present', 'absent']
+ choices: ["present", "absent"]
type: str
default: "present"
force:
description:
- Only updates an existing macro if set to C(yes).
- default: 'yes'
+ default: "yes"
type: bool
notes:
- - This module returns changed=true when I(macro_type=secret) with Zabbix >= 5.0.
+ - This module returns changed=true when I(macro_type=secret).
extends_documentation_fragment:
- community.zabbix.zabbix
-'''
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
# If you want to use Username and Password to be authenticated by Zabbix Server
- name: Set credentials to access Zabbix Server API
- set_fact:
+ ansible.builtin.set_fact:
ansible_user: Admin
ansible_httpapi_pass: zabbix
# If you want to use API token to be authenticated by Zabbix Server
# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens
- name: Set API token
- set_fact:
+ ansible.builtin.set_fact:
ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895
- name: Create new global macro or update an existing macro's value
@@ -92,7 +91,7 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_globalmacro:
macro_name: EXAMPLE.MACRO
@@ -109,7 +108,7 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_globalmacro:
macro_name: "{$EXAMPLE.MACRO}"
@@ -121,7 +120,7 @@ EXAMPLES = r'''
community.zabbix.zabbix_globalmacro:
macro_name: "{$EXAMPLE.MACRO}"
state: absent
-'''
+"""
RETURN = r"""
"""
@@ -130,7 +129,6 @@ RETURN = r"""
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase
-from ansible.module_utils.compat.version import LooseVersion
import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils
@@ -139,8 +137,8 @@ class GlobalMacro(ZabbixBase):
# get global macro
def get_global_macro(self, macro_name):
try:
- all_global_macro_list = self._zapi.usermacro.get({"globalmacro": 'true'})
- global_macro_list = [d for d in all_global_macro_list if d['macro'] == macro_name]
+ all_global_macro_list = self._zapi.usermacro.get({"globalmacro": "true"})
+ global_macro_list = [d for d in all_global_macro_list if d["macro"] == macro_name]
if len(global_macro_list) > 0:
return global_macro_list[0]
return None
@@ -152,61 +150,30 @@ class GlobalMacro(ZabbixBase):
try:
if self._module.check_mode:
self._module.exit_json(changed=True)
- if LooseVersion(self._zbx_api_version) < LooseVersion('4.4.0'):
- self._zapi.usermacro.createglobal({'macro': macro_name, 'value': macro_value})
- self._module.exit_json(changed=True, result="Successfully added global macro %s" % macro_name)
- if LooseVersion(self._zbx_api_version) >= LooseVersion('4.4.0'):
- if LooseVersion(self._zbx_api_version) >= LooseVersion('5.0.0'):
- if LooseVersion(self._zbx_api_version) < LooseVersion('5.2.0'):
- if macro_type == '2':
- macro_type = '0'
- self._zapi.usermacro.createglobal({'macro': macro_name, 'value': macro_value, 'type': macro_type, 'description': macro_description})
- self._module.exit_json(changed=True, result="Successfully added global macro %s" % macro_name)
- else:
- self._zapi.usermacro.createglobal({'macro': macro_name, 'value': macro_value, 'description': macro_description})
- self._module.exit_json(changed=True, result="Successfully added global macro %s" % macro_name)
+ self._zapi.usermacro.createglobal({"macro": macro_name, "value": macro_value, "type": macro_type, "description": macro_description})
+ self._module.exit_json(changed=True, result="Successfully added global macro %s" % macro_name)
except Exception as e:
self._module.fail_json(msg="Failed to create global macro %s: %s" % (macro_name, e))
# update global macro
def update_global_macro(self, global_macro_obj, macro_name, macro_value, macro_type, macro_description):
- global_macro_id = global_macro_obj['globalmacroid']
+ global_macro_id = global_macro_obj["globalmacroid"]
try:
- if LooseVersion(self._zbx_api_version) < LooseVersion('4.4.0'):
- if global_macro_obj['macro'] == macro_name and global_macro_obj['value'] == macro_value:
+ if global_macro_obj["type"] == "0" or global_macro_obj["type"] == "2":
+ if (global_macro_obj["macro"] == macro_name and global_macro_obj["value"] == macro_value
+ and global_macro_obj["type"] == macro_type and global_macro_obj["description"] == macro_description):
self._module.exit_json(changed=False, result="Global macro %s already up to date" % macro_name)
- if self._module.check_mode:
- self._module.exit_json(changed=True)
- self._zapi.usermacro.updateglobal({'globalmacroid': global_macro_id, 'macro': macro_name, 'value': macro_value})
- self._module.exit_json(changed=True, result="Successfully updated global macro %s" % macro_name)
- elif LooseVersion(self._zbx_api_version) >= LooseVersion('5.0.0'):
- if LooseVersion(self._zbx_api_version) < LooseVersion('5.2.0'):
- if macro_type == '2':
- macro_type = '0'
- if global_macro_obj['type'] == '0' or global_macro_obj['type'] == '2':
- if (global_macro_obj['macro'] == macro_name and global_macro_obj['value'] == macro_value
- and global_macro_obj['type'] == macro_type and global_macro_obj['description'] == macro_description):
- self._module.exit_json(changed=False, result="Global macro %s already up to date" % macro_name)
- if self._module.check_mode:
- self._module.exit_json(changed=True)
- self._zapi.usermacro.updateglobal({'globalmacroid': global_macro_id, 'macro': macro_name,
- 'value': macro_value, 'type': macro_type, 'description': macro_description})
- self._module.exit_json(changed=True, result="Successfully updated global macro %s" % macro_name)
- else:
- if (global_macro_obj['macro'] == macro_name and global_macro_obj['value'] == macro_value
- and global_macro_obj['description'] == macro_description):
- self._module.exit_json(changed=False, result="Global macro %s already up to date" % macro_name)
- if self._module.check_mode:
- self._module.exit_json(changed=True)
- self._zapi.usermacro.updateglobal({'globalmacroid': global_macro_id, 'macro': macro_name,
- 'value': macro_value, 'description': macro_description})
- self._module.exit_json(changed=True, result="Successfully updated global macro %s" % macro_name)
+ if self._module.check_mode:
+ self._module.exit_json(changed=True)
+ self._zapi.usermacro.updateglobal({"globalmacroid": global_macro_id, "macro": macro_name,
+ "value": macro_value, "type": macro_type, "description": macro_description})
+ self._module.exit_json(changed=True, result="Successfully updated global macro %s" % macro_name)
except Exception as e:
self._module.fail_json(msg="Failed to update global macro %s: %s" % (macro_name, e))
# delete global macro
def delete_global_macro(self, global_macro_obj, macro_name):
- global_macro_id = global_macro_obj['globalmacroid']
+ global_macro_id = global_macro_obj["globalmacroid"]
try:
if self._module.check_mode:
self._module.exit_json(changed=True)
@@ -218,16 +185,16 @@ class GlobalMacro(ZabbixBase):
def normalize_macro_name(macro_name):
# Zabbix handles macro names in upper case characters
- if ':' in macro_name:
- macro_name = ':'.join([macro_name.split(':')[0].upper(), ':'.join(macro_name.split(':')[1:])])
+ if ":" in macro_name:
+ macro_name = ":".join([macro_name.split(":")[0].upper(), ":".join(macro_name.split(":")[1:])])
else:
macro_name = macro_name.upper()
# Valid format for macro is {$MACRO}
- if not macro_name.startswith('{$'):
- macro_name = '{$' + macro_name
- if not macro_name.endswith('}'):
- macro_name = macro_name + '}'
+ if not macro_name.startswith("{$"):
+ macro_name = "{$" + macro_name
+ if not macro_name.endswith("}"):
+ macro_name = macro_name + "}"
return macro_name
@@ -235,48 +202,42 @@ def normalize_macro_name(macro_name):
def main():
argument_spec = zabbix_utils.zabbix_common_argument_spec()
argument_spec.update(dict(
- macro_name=dict(type='str', required=True),
- macro_value=dict(type='str', required=False, no_log=True),
- macro_type=dict(type='str', default='text', choices=['text', 'secret', 'vault']),
- macro_description=dict(type='str', default=''),
- state=dict(type='str', default='present', choices=['present', 'absent']),
- force=dict(type='bool', default=True)
+ macro_name=dict(type="str", required=True),
+ macro_value=dict(type="str", required=False, no_log=True),
+ macro_type=dict(type="str", default="text", choices=["text", "secret", "vault"]),
+ macro_description=dict(type="str", default=""),
+ state=dict(type="str", default="present", choices=["present", "absent"]),
+ force=dict(type="bool", default=True)
))
module = AnsibleModule(
argument_spec=argument_spec,
required_if=[
- ['state', 'present', ['macro_value']]
+ ["state", "present", ["macro_value"]]
],
supports_check_mode=True
)
- zabbix_utils.require_creds_params(module)
-
- for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']:
- if p in module.params and not module.params[p] is None:
- module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p)
-
- macro_name = normalize_macro_name(module.params['macro_name'])
- macro_value = module.params['macro_value']
- macro_type = module.params['macro_type']
- macro_value = module.params['macro_value']
- macro_description = module.params['macro_description']
- state = module.params['state']
- force = module.params['force']
-
- if macro_type == 'text':
- macro_type = '0'
- elif macro_type == 'secret':
- macro_type = '1'
- elif macro_type == 'vault':
- macro_type = '2'
+ macro_name = normalize_macro_name(module.params["macro_name"])
+ macro_value = module.params["macro_value"]
+ macro_type = module.params["macro_type"]
+ macro_value = module.params["macro_value"]
+ macro_description = module.params["macro_description"]
+ state = module.params["state"]
+ force = module.params["force"]
+
+ if macro_type == "text":
+ macro_type = "0"
+ elif macro_type == "secret":
+ macro_type = "1"
+ elif macro_type == "vault":
+ macro_type = "2"
global_macro_class_obj = GlobalMacro(module)
if macro_name:
global_macro_obj = global_macro_class_obj.get_global_macro(macro_name)
- if state == 'absent':
+ if state == "absent":
if not global_macro_obj:
module.exit_json(changed=False, msg="Global Macro %s does not exist" % macro_name)
else:
@@ -293,5 +254,5 @@ def main():
module.exit_json(changed=False, result="Global macro %s already exists and force is set to no" % macro_name)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_group.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_group.py
index 0426f9336..3eb39ab24 100644
--- a/ansible_collections/community/zabbix/plugins/modules/zabbix_group.py
+++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_group.py
@@ -47,14 +47,14 @@ notes:
EXAMPLES = r'''
# If you want to use Username and Password to be authenticated by Zabbix Server
- name: Set credentials to access Zabbix Server API
- set_fact:
+ ansible.builtin.set_fact:
ansible_user: Admin
ansible_httpapi_pass: zabbix
# If you want to use API token to be authenticated by Zabbix Server
# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens
- name: Set API token
- set_fact:
+ ansible.builtin.set_fact:
ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895
# Base create host groups example
@@ -94,17 +94,6 @@ EXAMPLES = r'''
'''
-import traceback
-
-try:
- from zabbix_api import Already_Exists
-
- HAS_ZABBIX_API = True
- ZBX_IMP_ERR = Exception()
-except ImportError:
- ZBX_IMP_ERR = traceback.format_exc()
- HAS_ZABBIX_API = False
-
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase
@@ -119,13 +108,10 @@ class HostGroup(ZabbixBase):
for group_name in group_names:
result = self._zapi.hostgroup.get({'filter': {'name': group_name}})
if not result:
- try:
- if self._module.check_mode:
- self._module.exit_json(changed=True)
- self._zapi.hostgroup.create({'name': group_name})
- group_add_list.append(group_name)
- except Already_Exists:
- return group_add_list
+ if self._module.check_mode:
+ self._module.exit_json(changed=True)
+ self._zapi.hostgroup.create({'name': group_name})
+ group_add_list.append(group_name)
return group_add_list
except Exception as e:
self._module.fail_json(msg="Failed to create host group(s): %s" % e)
@@ -153,7 +139,7 @@ class HostGroup(ZabbixBase):
def main():
argument_spec = zabbix_utils.zabbix_common_argument_spec()
argument_spec.update(dict(
- host_groups=dict(type='list', required=True, aliases=['host_group']),
+ host_groups=dict(type='list', required=True, aliases=['host_group'], elements='str'),
state=dict(type='str', default="present", choices=['present', 'absent']),
))
module = AnsibleModule(
@@ -161,12 +147,6 @@ def main():
supports_check_mode=True
)
- zabbix_utils.require_creds_params(module)
-
- for p in ['server_url', 'login_user', 'login_password']:
- if p in module.params and module.params[p] and module.params[p]:
- module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p)
-
host_groups = module.params['host_groups']
state = module.params['state']
diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_group_events_info.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_group_events_info.py
new file mode 100644
index 000000000..e41cab26f
--- /dev/null
+++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_group_events_info.py
@@ -0,0 +1,283 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# built by Martin Eiswirth (@meis4h) on top of the work by Stéphane Travassac (@stravassac) on zabbix_host_events_info.py
+# and Michael Miko (@RedWhiteMiko) on zabbix_group_info.py
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+
+from __future__ import (absolute_import, division, print_function)
+
+__metaclass__ = type
+
+RETURN = """
+---
+triggers_ok:
+ description: Zabbix Triggers in OK state
+ returned: On success
+ type: complex
+ contains:
+ comments:
+ description: Additional description of the trigger
+ type: str
+ description:
+ description: Name of the trigger
+ type: str
+ error:
+ description: Error text if there have been any problems when updating the state of the trigger
+ type: str
+ expression:
+ description: Reduced trigger expression
+ type: str
+ flags:
+ description: Origin of the trigger
+ type: int
+ lastchange:
+ description: Time when the trigger last changed its state (timestamp)
+ type: int
+ priority:
+ description: Severity of the trigger
+ type: int
+ state:
+ description: State of the trigger
+ type: int
+ status:
+ description: Whether the trigger is enabled or disabled
+ type: int
+ templateid:
+ description: ID of the parent template trigger
+ type: int
+ triggerid:
+ description: ID of the trigger
+ type: int
+ type:
+ description: Whether the trigger can generate multiple problem events
+ type: int
+ url:
+ description: URL associated with the trigger
+ type: str
+ value:
+ description: Whether the trigger is in OK or problem state
+ type: int
+triggers_problem:
+ description: Zabbix Triggers in problem state. See trigger and event objects in API documentation of your zabbix version for more
+ returned: On success
+ type: complex
+ contains:
+ comments:
+ description: Additional description of the trigger
+ type: str
+ description:
+ description: Name of the trigger
+ type: str
+ error:
+ description: Error text if there have been any problems when updating the state of the trigger
+ type: str
+ expression:
+ description: Reduced trigger expression
+ type: str
+ flags:
+ description: Origin of the trigger
+ type: int
+ last_event:
+ description: last event informations
+ type: complex
+ contains:
+ acknowledged:
+ description: If set to true return only acknowledged events
+ type: int
+ acknowledges:
+ description: acknowledges informations
+ type: complex
+ contains:
+ alias:
+ description: Account who acknowledge
+ type: str
+ clock:
+ description: Time when the event was created (timestamp)
+ type: int
+ message:
+ description: Text of the acknowledgement message
+ type: str
+ clock:
+ description: Time when the event was created (timestamp)
+ type: int
+ eventid:
+ description: ID of the event
+ type: int
+ value:
+ description: State of the related object
+ type: int
+ lastchange:
+ description: Time when the trigger last changed its state (timestamp)
+ type: int
+ priority:
+ description: Severity of the trigger
+ type: int
+ state:
+ description: State of the trigger
+ type: int
+ status:
+ description: Whether the trigger is enabled or disabled
+ type: int
+ templateid:
+ description: ID of the parent template trigger
+ type: int
+ triggerid:
+ description: ID of the trigger
+ type: int
+ type:
+ description: Whether the trigger can generate multiple problem events
+ type: int
+ url:
+ description: URL associated with the trigger
+ type: str
+ value:
+ description: Whether the trigger is in OK or problem state
+ type: int
+"""
+
+DOCUMENTATION = """
+---
+module: zabbix_group_events_info
+short_description: Get all triggers about a Zabbix group
+description:
+ - This module allows you to check the state of triggers of all hosts in a Zabbix hostgroup.
+author:
+ - "Martin Eiswirth (@meis4h)"
+requirements:
+ - "python >= 3.9"
+options:
+ hostgroup_name:
+ description:
+ - Name of the hostgroup in Zabbix.
+ required: true
+ type: list
+ elements: str
+ trigger_severity:
+ description:
+ - Zabbix severity for search filter
+ default: average
+ required: false
+ choices:
+ - not_classified
+ - information
+ - warning
+ - average
+ - high
+ - disaster
+ type: str
+extends_documentation_fragment:
+- community.zabbix.zabbix
+
+"""
+
+EXAMPLES = """
+# If you want to use Username and Password to be authenticated by Zabbix Server
+- name: Set credentials to access Zabbix Server API
+ set_fact:
+ ansible_user: Admin
+ ansible_httpapi_pass: zabbix
+
+# If you want to use API token to be authenticated by Zabbix Server
+# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens
+- name: Set API token
+ set_fact:
+ ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895
+
+- name: Fail if alert active in hostgroup
+ # set task level variables as we change ansible_connection plugin here
+ vars:
+ ansible_network_os: community.zabbix.zabbix
+ ansible_connection: httpapi
+ ansible_httpapi_port: 443
+ ansible_httpapi_use_ssl: true
+ ansible_httpapi_validate_certs: false
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_host: zabbix-example-fqdn.org
+ community.zabbix.zabbix_group_events_info:
+ hostgroup_name: "{{ inventory_hostname }}"
+ register: zbx_hostgroup
+ delegate_to: localhost
+- fail:
+ msg: "Active alert in zabbix"
+ when: zbx_hostgroup["triggers_problem"] | length > 0
+"""
+
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase
+import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils
+
+
+class Host(ZabbixBase):
+ def get_group_ids_by_group_names(self, group_names):
+ group_list = self._zapi.hostgroup.get({"output": "extend", "filter": {"name": group_names}})
+ if len(group_list) < 1:
+ self._module.fail_json(msg="Hostgroup not found: %s" % group_names)
+ return group_list
+
+ def get_triggers_by_group_id_in_problem_state(self, group_id, trigger_severity):
+ """ Get triggers in problem state from a groupid"""
+ output = "extend"
+ triggers_list = self._zapi.trigger.get({"output": output, "groupids": group_id,
+ "min_severity": trigger_severity})
+ return triggers_list
+
+ def get_last_event_by_trigger_id(self, triggers_id):
+ """ Get the last event from triggerid"""
+ output = ["eventid", "clock", "acknowledged", "value"]
+ select_acknowledges = ["clock", "alias", "message"]
+ event = self._zapi.event.get({"output": output, "objectids": triggers_id,
+ "select_acknowledges": select_acknowledges, "limit": 1, "sortfield": "clock",
+ "sortorder": "DESC"})
+ return event[0]
+
+
+def main():
+ argument_spec = zabbix_utils.zabbix_common_argument_spec()
+ argument_spec.update(dict(
+ hostgroup_name=dict(type="list", required=True, elements="str"),
+ trigger_severity=dict(
+ type="str",
+ required=False,
+ default="average",
+ choices=["not_classified", "information", "warning", "average", "high", "disaster"]),
+ ))
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True
+ )
+
+ trigger_severity_map = {"not_classified": 0, "information": 1, "warning": 2, "average": 3, "high": 4, "disaster": 5}
+ trigger_severity = trigger_severity_map[module.params["trigger_severity"]]
+
+ hostgroup_name = module.params["hostgroup_name"]
+
+ host = Host(module)
+ host_groups = host.get_group_ids_by_group_names(hostgroup_name)
+ triggers = []
+
+ for host_group in host_groups:
+ host_group_id = host_group["groupid"]
+ host_group_triggers = host.get_triggers_by_group_id_in_problem_state(host_group_id, trigger_severity)
+ triggers = triggers + host_group_triggers
+
+ triggers_ok = []
+ triggers_problem = []
+ for trigger in triggers:
+ # tGet last event for trigger with problem value = 1
+ # https://www.zabbix.com/documentation/3.4/manual/api/reference/trigger/object
+ if int(trigger["value"]) == 1:
+ event = host.get_last_event_by_trigger_id(trigger["triggerid"])
+ trigger["last_event"] = event
+ triggers_problem.append(trigger)
+ else:
+ triggers_ok.append(trigger)
+
+ module.exit_json(ok=True, host_groups=host_groups, triggers_ok=triggers_ok, triggers_problem=triggers_problem)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_group_facts.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_group_facts.py
deleted file mode 100644
index b3f693052..000000000
--- a/ansible_collections/community/zabbix/plugins/modules/zabbix_group_facts.py
+++ /dev/null
@@ -1,115 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# (c) me@mimiko.me
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-RETURN = r'''
----
-host_groups:
- description: List of Zabbix groups.
- returned: success
- type: dict
- sample: [ { "flags": "0", "groupid": "33", "internal": "0", "name": "Hostgruup A" } ]
-'''
-
-DOCUMENTATION = r'''
----
-module: zabbix_group_info
-short_description: Gather information about Zabbix hostgroup
-description:
- - This module allows you to search for Zabbix hostgroup entries.
- - This module was called C(zabbix_group_facts) before Ansible 2.9. The usage did not change.
-author:
- - "Michael Miko (@RedWhiteMiko)"
-requirements:
- - "python >= 2.6"
-options:
- hostgroup_name:
- description:
- - Name of the hostgroup in Zabbix.
- - hostgroup is the unique identifier used and cannot be updated using this module.
- required: true
- type: list
- elements: str
-
-extends_documentation_fragment:
-- community.zabbix.zabbix
-'''
-
-EXAMPLES = r'''
-# If you want to use Username and Password to be authenticated by Zabbix Server
-- name: Set credentials to access Zabbix Server API
- set_fact:
- ansible_user: Admin
- ansible_httpapi_pass: zabbix
-
-# If you want to use API token to be authenticated by Zabbix Server
-# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens
-- name: Set API token
- set_fact:
- ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895
-
-- name: Get hostgroup info
- # set task level variables as we change ansible_connection plugin here
- vars:
- ansible_network_os: community.zabbix.zabbix
- ansible_connection: httpapi
- ansible_httpapi_port: 443
- ansible_httpapi_use_ssl: true
- ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
- ansible_host: zabbix-example-fqdn.org
- community.zabbix.zabbix_group_info:
- hostgroup_name:
- - ExampleHostgroup
- timeout: 10
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-
-from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase
-import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils
-
-
-class Host(ZabbixBase):
- def get_group_ids_by_group_names(self, group_names):
- group_list = self._zapi.hostgroup.get({'output': 'extend', 'filter': {'name': group_names}})
- if len(group_list) < 1:
- self._module.fail_json(msg="Hostgroup not found: %s" % group_names)
- return group_list
-
-
-def main():
- argument_spec = zabbix_utils.zabbix_common_argument_spec()
- argument_spec.update(dict(
- hostgroup_name=dict(type='list', required=True),
- ))
- module = AnsibleModule(
- argument_spec=argument_spec,
- supports_check_mode=True
- )
-
- zabbix_utils.require_creds_params(module)
-
- for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']:
- if p in module.params and not module.params[p] is None:
- module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p)
-
- if module._name == 'zabbix_group_facts':
- module.deprecate("The 'zabbix_group_facts' module has been renamed to 'zabbix_group_info'",
- collection_name="community.zabbix", version='2.0.0') # was 2.13
-
- hostgroup_name = module.params['hostgroup_name']
-
- host = Host(module)
- host_groups = host.get_group_ids_by_group_names(hostgroup_name)
- module.exit_json(host_groups=host_groups)
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_group_info.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_group_info.py
index b3f693052..02784c366 100644
--- a/ansible_collections/community/zabbix/plugins/modules/zabbix_group_info.py
+++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_group_info.py
@@ -8,16 +8,16 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type
-RETURN = r'''
+RETURN = r"""
---
host_groups:
description: List of Zabbix groups.
returned: success
type: dict
sample: [ { "flags": "0", "groupid": "33", "internal": "0", "name": "Hostgruup A" } ]
-'''
+"""
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: zabbix_group_info
short_description: Gather information about Zabbix hostgroup
@@ -27,7 +27,7 @@ description:
author:
- "Michael Miko (@RedWhiteMiko)"
requirements:
- - "python >= 2.6"
+ - "python >= 3.9"
options:
hostgroup_name:
description:
@@ -39,19 +39,19 @@ options:
extends_documentation_fragment:
- community.zabbix.zabbix
-'''
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
# If you want to use Username and Password to be authenticated by Zabbix Server
- name: Set credentials to access Zabbix Server API
- set_fact:
+ ansible.builtin.set_fact:
ansible_user: Admin
ansible_httpapi_pass: zabbix
# If you want to use API token to be authenticated by Zabbix Server
# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens
- name: Set API token
- set_fact:
+ ansible.builtin.set_fact:
ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895
- name: Get hostgroup info
@@ -62,13 +62,12 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_group_info:
hostgroup_name:
- ExampleHostgroup
- timeout: 10
-'''
+"""
from ansible.module_utils.basic import AnsibleModule
@@ -78,7 +77,7 @@ import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabb
class Host(ZabbixBase):
def get_group_ids_by_group_names(self, group_names):
- group_list = self._zapi.hostgroup.get({'output': 'extend', 'filter': {'name': group_names}})
+ group_list = self._zapi.hostgroup.get({"output": "extend", "filter": {"name": group_names}})
if len(group_list) < 1:
self._module.fail_json(msg="Hostgroup not found: %s" % group_names)
return group_list
@@ -87,29 +86,19 @@ class Host(ZabbixBase):
def main():
argument_spec = zabbix_utils.zabbix_common_argument_spec()
argument_spec.update(dict(
- hostgroup_name=dict(type='list', required=True),
+ hostgroup_name=dict(type="list", required=True, elements="str"),
))
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True
)
- zabbix_utils.require_creds_params(module)
-
- for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']:
- if p in module.params and not module.params[p] is None:
- module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p)
-
- if module._name == 'zabbix_group_facts':
- module.deprecate("The 'zabbix_group_facts' module has been renamed to 'zabbix_group_info'",
- collection_name="community.zabbix", version='2.0.0') # was 2.13
-
- hostgroup_name = module.params['hostgroup_name']
+ hostgroup_name = module.params["hostgroup_name"]
host = Host(module)
host_groups = host.get_group_ids_by_group_names(hostgroup_name)
module.exit_json(host_groups=host_groups)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_host.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_host.py
index c43742378..22e14d17d 100644
--- a/ansible_collections/community/zabbix/plugins/modules/zabbix_host.py
+++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_host.py
@@ -8,7 +8,7 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: zabbix_host
short_description: Create/update/delete Zabbix hosts
@@ -21,7 +21,7 @@ author:
- Werner Dijkerman (@dj-wasabi)
- Eike Frost (@eikef)
requirements:
- - "python >= 2.6"
+ - "python >= 3.9"
options:
host_name:
description:
@@ -51,27 +51,27 @@ options:
inventory_mode:
description:
- Configure the inventory mode.
- choices: ['automatic', 'manual', 'disabled']
+ choices: ["automatic", "manual", "disabled"]
type: str
inventory_zabbix:
description:
- Add Facts for a zabbix inventory (e.g. Tag) (see example below).
- Please review the interface documentation for more information on the supported properties
- - U(https://www.zabbix.com/documentation/3.2/manual/api/reference/host/object#host_inventory)
+ - U(https://www.zabbix.com/documentation/current/en/manual/api/reference/host/object#host-inventory)
type: dict
status:
description:
- Monitoring status of the host.
- choices: ['enabled', 'disabled']
- default: 'enabled'
+ choices: ["enabled", "disabled"]
+ default: "enabled"
type: str
state:
description:
- State of the host.
- On C(present), it will create if host does not exist or update the host if the associated data is different.
- On C(absent) will remove a host if it exists.
- choices: ['present', 'absent']
- default: 'present'
+ choices: ["present", "absent"]
+ default: "present"
type: str
proxy:
description:
@@ -83,7 +83,7 @@ options:
description:
- List of interfaces to be created for the host (see example below).
- For more information, review host interface documentation at
- - U(https://www.zabbix.com/documentation/4.0/manual/api/reference/hostinterface/object)
+ - U(https://www.zabbix.com/documentation/current/en/manual/api/reference/hostinterface/object#host-interface)
default: []
suboptions:
type:
@@ -95,7 +95,7 @@ options:
- 2 = snmp
- 3 = ipmi
- 4 = jmx
- choices: ['agent', '1', 'snmp', '2', 'ipmi', '3', 'jmx', '4']
+ choices: ["agent", "1", "snmp", "2", "ipmi", "3", "jmx", "4"]
required: true
main:
type: int
@@ -127,26 +127,15 @@ options:
description:
- Port used by host interface.
- If not specified, default port for each type of interface is used
- - 10050 if I(type='agent')
- - 161 if I(type='snmp')
- - 623 if I(type='ipmi')
- - 12345 if I(type='jmx')
- bulk:
- type: int
- description:
- - Whether to use bulk SNMP requests.
- - Only valid when interface I(type='snmp').
- - 0 (don't use bulk requests), 1 (use bulk requests)
- - Works only with Zabbix <= 4.4 and is silently ignored in higher versions.
- - Use I(details) with Zabbix >= 5.0.
- choices: [0, 1]
- default: 1
+ - 10050 if I(type="agent")
+ - 161 if I(type="snmp")
+ - 623 if I(type="ipmi")
+ - 12345 if I(type="jmx")
details:
type: dict
description:
- Additional details for SNMP host interfaces.
- - Required when I(type='snmp').
- - Works only with Zabbix >= 5.0.
+ - Required when I(type="snmp").
default: {}
suboptions:
version:
@@ -168,17 +157,17 @@ options:
description:
- SNMPv1 and SNMPv2 community string.
- Required when I(version=1) or I(version=2).
- default: ''
+ default: ""
securityname:
type: str
description:
- SNMPv3 security name.
- default: ''
+ default: ""
contextname:
type: str
description:
- SNMPv3 context name.
- default: ''
+ default: ""
securitylevel:
type: int
description:
@@ -200,7 +189,7 @@ options:
description:
- SNMPv3 authentication passphrase.
- Used when I(securitylevel=1)(authNoPriv) or I(securitylevel=2)(AuthPriv).
- default: ''
+ default: ""
privprotocol:
type: int
description:
@@ -215,12 +204,11 @@ options:
description:
- SNMPv3 privacy passphrase.
- Used when I(securitylevel=2)(AuthPriv).
- default: ''
+ default: ""
tls_connect:
description:
- Specifies what encryption to use for outgoing connections.
- Possible values, 1 (no encryption), 2 (PSK), 4 (certificate).
- - Works only with >= Zabbix 3.0
type: int
tls_accept:
description:
@@ -228,7 +216,6 @@ options:
- The tls_accept parameter accepts values of 1 to 7
- Possible values, 1 (no encryption), 2 (PSK), 4 (certificate).
- Values can be combined.
- - Works only with >= Zabbix 3.0
type: int
tls_psk_identity:
description:
@@ -241,25 +228,22 @@ options:
description:
- PSK value is a hard to guess string of hexadecimal digits.
- The preshared key, at least 32 hex digits. Required if either I(tls_connect) or I(tls_accept) has PSK enabled.
- - Works only with >= Zabbix 3.0
- - Using this parameter with Zabbix >= 5.4 makes this module non-idempotent.
+ - Using this parameter makes this module non-idempotent.
type: str
ca_cert:
description:
- Required certificate issuer.
- - Works only with >= Zabbix 3.0
aliases: [ tls_issuer ]
type: str
tls_subject:
description:
- Required certificate subject.
- - Works only with >= Zabbix 3.0
type: str
ipmi_authtype:
description:
- IPMI authentication algorithm.
- Please review the Host object documentation for more information on the supported properties
- - 'https://www.zabbix.com/documentation/3.4/manual/api/reference/host/object'
+ - "https://www.zabbix.com/documentation/3.4/manual/api/reference/host/object"
- Possible values are, C(0) (none), C(1) (MD2), C(2) (MD5), C(4) (straight), C(5) (OEM), C(6) (RMCP+),
with -1 being the API default.
- Please note that the Zabbix API will treat absent settings as default when updating
@@ -270,7 +254,7 @@ options:
description:
- IPMI privilege level.
- Please review the Host object documentation for more information on the supported properties
- - 'https://www.zabbix.com/documentation/3.4/manual/api/reference/host/object'
+ - "https://www.zabbix.com/documentation/3.4/manual/api/reference/host/object"
- Possible values are C(1) (callback), C(2) (user), C(3) (operator), C(4) (admin), C(5) (OEM), with C(2)
being the API default.
- also see the last note in the I(ipmi_authtype) documentation
@@ -289,7 +273,7 @@ options:
description:
- Overwrite the host configuration, even if already present.
type: bool
- default: 'yes'
+ default: "yes"
macros:
description:
- List of user macros to assign to the zabbix host.
@@ -311,14 +295,12 @@ options:
description:
description:
- Description of the user macro.
- - Works only with >= Zabbix 4.4.
type: str
required: false
- default: ''
+ default: ""
type:
description:
- Type of the macro.
- - Works only with >= Zabbix 5.0.
- Since value is not returned by API for secret macros, there is no reliable way to
detect changes in the content of secret macro value.
- To update secret macro value, please update description alongside it so it passes
@@ -331,7 +313,6 @@ options:
tags:
description:
- List of host tags to assign to the zabbix host.
- - Works only with >= Zabbix 4.2.
- Providing I(tags=[]) with I(force=yes) will clean all of the tags from the host.
type: list
elements: dict
@@ -345,25 +326,25 @@ options:
description:
- Value of the host tag.
type: str
- default: ''
+ default: ""
aliases: [ host_tags ]
extends_documentation_fragment:
- community.zabbix.zabbix
-'''
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
# If you want to use Username and Password to be authenticated by Zabbix Server
- name: Set credentials to access Zabbix Server API
- set_fact:
+ ansible.builtin.set_fact:
ansible_user: Admin
ansible_httpapi_pass: zabbix
# If you want to use API token to be authenticated by Zabbix Server
# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens
- name: Set API token
- set_fact:
+ ansible.builtin.set_fact:
ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895
- name: Create a new host or rewrite an existing host's info
@@ -374,7 +355,7 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
become: false
delegate_to: zabbix-example-fqdn.org# you can use delegate_to or task level ansible_host like next example
community.zabbix.zabbix_host:
@@ -417,7 +398,7 @@ EXAMPLES = r'''
port: "12345"
proxy: a.zabbix.proxy
macros:
- - macro: '{$EXAMPLEMACRO}'
+ - macro: "{$EXAMPLEMACRO}"
value: ExampleMacroValue
- macro: EXAMPLEMACRO2
value: ExampleMacroValue2
@@ -435,7 +416,7 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org # you can use task level ansible_host or delegate_to like in previous example
become: false
community.zabbix.zabbix_host:
@@ -447,7 +428,7 @@ EXAMPLES = r'''
tls_connect: 2
tls_psk: 123456789abcdef123456789abcdef12
force: false
-'''
+"""
import copy
@@ -455,7 +436,6 @@ import copy
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase
-from ansible.module_utils.compat.version import LooseVersion
import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils
@@ -463,13 +443,13 @@ import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabb
class Host(ZabbixBase):
# exist host
def is_host_exist(self, host_name):
- result = self._zapi.host.get({'filter': {'host': host_name}})
+ result = self._zapi.host.get({"filter": {"host": host_name}})
return result
# check if host group exists
def check_host_group_exist(self, group_names):
for group_name in group_names:
- result = self._zapi.hostgroup.get({'filter': {'name': group_name}})
+ result = self._zapi.hostgroup.get({"filter": {"name": group_name}})
if not result:
self._module.fail_json(msg="Hostgroup not found: %s" % group_name)
return True
@@ -479,11 +459,11 @@ class Host(ZabbixBase):
if template_list is None or len(template_list) == 0:
return template_ids
for template in template_list:
- template_list = self._zapi.template.get({'output': 'extend', 'filter': {'host': template}})
+ template_list = self._zapi.template.get({"output": "extend", "filter": {"host": template}})
if len(template_list) < 1:
self._module.fail_json(msg="Template not found: %s" % template)
else:
- template_id = template_list[0]['templateid']
+ template_id = template_list[0]["templateid"]
template_ids.append(template_id)
return template_ids
@@ -493,83 +473,88 @@ class Host(ZabbixBase):
try:
if self._module.check_mode:
self._module.exit_json(changed=True)
- parameters = {'host': host_name, 'interfaces': interfaces, 'groups': group_ids, 'status': status}
+ parameters = {"host": host_name, "interfaces": interfaces, "groups": group_ids, "status": status}
if proxy_id:
- parameters['proxy_hostid'] = proxy_id
+ parameters["proxy_hostid"] = proxy_id
if visible_name:
- parameters['name'] = visible_name
+ parameters["name"] = visible_name
if tls_connect:
- parameters['tls_connect'] = tls_connect
+ parameters["tls_connect"] = tls_connect
if tls_accept:
- parameters['tls_accept'] = tls_accept
+ parameters["tls_accept"] = tls_accept
if tls_psk_identity is not None:
- parameters['tls_psk_identity'] = tls_psk_identity
+ parameters["tls_psk_identity"] = tls_psk_identity
if tls_psk is not None:
- parameters['tls_psk'] = tls_psk
+ parameters["tls_psk"] = tls_psk
if tls_issuer is not None:
- parameters['tls_issuer'] = tls_issuer
+ parameters["tls_issuer"] = tls_issuer
if tls_subject is not None:
- parameters['tls_subject'] = tls_subject
+ parameters["tls_subject"] = tls_subject
if description:
- parameters['description'] = description
+ parameters["description"] = description
if ipmi_authtype is not None:
- parameters['ipmi_authtype'] = ipmi_authtype
+ parameters["ipmi_authtype"] = ipmi_authtype
if ipmi_privilege is not None:
- parameters['ipmi_privilege'] = ipmi_privilege
+ parameters["ipmi_privilege"] = ipmi_privilege
if ipmi_username is not None:
- parameters['ipmi_username'] = ipmi_username
+ parameters["ipmi_username"] = ipmi_username
if ipmi_password is not None:
- parameters['ipmi_password'] = ipmi_password
+ parameters["ipmi_password"] = ipmi_password
if macros is not None:
- parameters['macros'] = macros
+ parameters["macros"] = macros
if tags is not None:
- parameters['tags'] = tags
+ parameters["tags"] = tags
host_list = self._zapi.host.create(parameters)
if len(host_list) >= 1:
- return host_list['hostids'][0]
+ return host_list["hostids"][0]
except Exception as e:
self._module.fail_json(msg="Failed to create host %s: %s" % (host_name, e))
def update_host(self, host_name, group_ids, status, host_id, interfaces, exist_interface_list, proxy_id,
visible_name, description, tls_connect, tls_accept, tls_psk_identity, tls_psk, tls_issuer,
- tls_subject, ipmi_authtype, ipmi_privilege, ipmi_username, ipmi_password, macros, tags):
+ tls_subject, ipmi_authtype, ipmi_privilege, ipmi_username, ipmi_password, macros, tags, discovered_host):
try:
if self._module.check_mode:
self._module.exit_json(changed=True)
- parameters = {'hostid': host_id, 'groups': group_ids, 'status': status}
- if proxy_id >= 0:
- parameters['proxy_hostid'] = proxy_id
- if visible_name:
- parameters['name'] = visible_name
- if tls_connect:
- parameters['tls_connect'] = tls_connect
- if tls_accept:
- parameters['tls_accept'] = tls_accept
- if tls_psk_identity:
- parameters['tls_psk_identity'] = tls_psk_identity
- if tls_psk:
- parameters['tls_psk'] = tls_psk
- if tls_issuer:
- parameters['tls_issuer'] = tls_issuer
- if tls_subject:
- parameters['tls_subject'] = tls_subject
- if description:
- parameters['description'] = description
- if ipmi_authtype:
- parameters['ipmi_authtype'] = ipmi_authtype
- if ipmi_privilege:
- parameters['ipmi_privilege'] = ipmi_privilege
- if ipmi_username:
- parameters['ipmi_username'] = ipmi_username
- if ipmi_password:
- parameters['ipmi_password'] = ipmi_password
+ if discovered_host:
+ # The host was discovered via Discovery Rule
+ parameters = {"hostid": host_id, "status": status}
+ else:
+ # A "plain" host
+ parameters = {"hostid": host_id, "groups": group_ids, "status": status}
+ if proxy_id >= 0:
+ parameters["proxy_hostid"] = proxy_id
+ if visible_name:
+ parameters["name"] = visible_name
+ if tls_connect:
+ parameters["tls_connect"] = tls_connect
+ if tls_accept:
+ parameters["tls_accept"] = tls_accept
+ if tls_psk_identity:
+ parameters["tls_psk_identity"] = tls_psk_identity
+ if tls_psk:
+ parameters["tls_psk"] = tls_psk
+ if tls_issuer:
+ parameters["tls_issuer"] = tls_issuer
+ if tls_subject:
+ parameters["tls_subject"] = tls_subject
+ if description:
+ parameters["description"] = description
+ if ipmi_authtype:
+ parameters["ipmi_authtype"] = ipmi_authtype
+ if ipmi_privilege:
+ parameters["ipmi_privilege"] = ipmi_privilege
+ if ipmi_username:
+ parameters["ipmi_username"] = ipmi_username
+ if ipmi_password:
+ parameters["ipmi_password"] = ipmi_password
+ if interfaces:
+ parameters["interfaces"] = interfaces
if macros is not None:
- parameters['macros'] = macros
+ parameters["macros"] = macros
if tags is not None:
- parameters['tags'] = tags
- if interfaces:
- parameters['interfaces'] = interfaces
+ parameters["tags"] = tags
self._zapi.host.update(parameters)
except Exception as e:
@@ -586,49 +571,42 @@ class Host(ZabbixBase):
# get host by host name
def get_host_by_host_name(self, host_name):
params = {
- 'output': 'extend',
- 'selectInventory': 'extend',
- 'selectMacros': 'extend',
- 'filter': {
- 'host': [host_name]
+ "output": [
+ "inventory_mode",
+ "hostid",
+ "proxy_hostid",
+ "host",
+ "status",
+ "lastaccess",
+ "ipmi_authtype",
+ "ipmi_privilege",
+ "ipmi_username",
+ "ipmi_password",
+ "maintenanceid",
+ "maintenance_status",
+ "maintenance_type",
+ "maintenance_from",
+ "name",
+ "flags",
+ "templateid",
+ "description",
+ "tls_connect",
+ "tls_accept",
+ "tls_issuer",
+ "tls_subject",
+ "proxy_address",
+ "auto_compress",
+ "custom_interfaces",
+ "uuid"
+ ],
+ "selectInventory": "extend",
+ "selectMacros": "extend",
+ "selectTags": ["tag", "value"],
+ "filter": {
+ "host": [host_name]
}
}
- if LooseVersion(self._zbx_api_version) >= LooseVersion('4.2.0'):
- params.update({'selectTags': ['tag', 'value']})
-
- if LooseVersion(self._zbx_api_version) >= LooseVersion('5.4.0'):
- params.update({
- 'output': [
- "inventory_mode",
- "hostid",
- "proxy_hostid",
- "host",
- "status",
- "lastaccess",
- "ipmi_authtype",
- "ipmi_privilege",
- "ipmi_username",
- "ipmi_password",
- "maintenanceid",
- "maintenance_status",
- "maintenance_type",
- "maintenance_from",
- "name",
- "flags",
- "templateid",
- "description",
- "tls_connect",
- "tls_accept",
- "tls_issuer",
- "tls_subject",
- "proxy_address",
- "auto_compress",
- "custom_interfaces",
- "uuid"
- ]
- })
-
host_list = self._zapi.host.get(params)
if len(host_list) < 1:
self._module.fail_json(msg="Host not found: %s" % host_name)
@@ -637,27 +615,27 @@ class Host(ZabbixBase):
# get proxyid by proxy name
def get_proxyid_by_proxy_name(self, proxy_name):
- proxy_list = self._zapi.proxy.get({'output': 'extend', 'filter': {'host': [proxy_name]}})
+ proxy_list = self._zapi.proxy.get({"output": "extend", "filter": {"host": [proxy_name]}})
if len(proxy_list) < 1:
self._module.fail_json(msg="Proxy not found: %s" % proxy_name)
else:
- return int(proxy_list[0]['proxyid'])
+ return int(proxy_list[0]["proxyid"])
# get group ids by group names
def get_group_ids_by_group_names(self, group_names):
if self.check_host_group_exist(group_names):
- return self._zapi.hostgroup.get({'output': 'extend', 'filter': {'name': group_names}})
+ return self._zapi.hostgroup.get({"output": "extend", "filter": {"name": group_names}})
# get host groups ids by host id
def get_group_ids_by_host_id(self, host_id):
- return self._zapi.hostgroup.get({'output': 'extend', 'hostids': host_id})
+ return self._zapi.hostgroup.get({"output": "extend", "hostids": host_id})
# get host templates by host id
def get_host_templates_by_host_id(self, host_id):
template_ids = []
- template_list = self._zapi.template.get({'output': 'extend', 'hostids': host_id})
+ template_list = self._zapi.template.get({"output": "extend", "hostids": host_id})
for template in template_list:
- template_ids.append(template['templateid'])
+ template_ids.append(template["templateid"])
return template_ids
def construct_host_interfaces(self, interfaces):
@@ -671,45 +649,40 @@ class Host(ZabbixBase):
and ip is any IP address found on interface of type agent (printing purposes only).
"""
ip = ""
- interface_types = {'agent': 1, 'snmp': 2, 'ipmi': 3, 'jmx': 4}
- type_to_port = {1: '10050', 2: '161', 3: '623', 4: '12345'}
+ interface_types = {"agent": 1, "snmp": 2, "ipmi": 3, "jmx": 4}
+ type_to_port = {1: "10050", 2: "161", 3: "623", 4: "12345"}
for interface in interfaces:
- if interface['type'] in list(interface_types.keys()):
- interface['type'] = interface_types[interface['type']]
+ if interface["type"] in list(interface_types.keys()):
+ interface["type"] = interface_types[interface["type"]]
else:
- interface['type'] = int(interface['type'])
+ interface["type"] = int(interface["type"])
- if interface['type'] == 1:
- ip = interface.get('ip', '')
+ if interface["type"] == 1:
+ ip = interface.get("ip", "")
- for key in ['ip', 'dns']:
+ for key in ["ip", "dns"]:
if key not in interface or interface[key] is None:
- interface[key] = ''
-
- if 'port' not in interface or interface['port'] is None:
- interface['port'] = type_to_port.get(interface['type'], '')
+ interface[key] = ""
- if LooseVersion(self._zbx_api_version) >= LooseVersion('5.0.0'):
- if 'bulk' in interface:
- del interface['bulk']
+ if "port" not in interface or interface["port"] is None:
+ interface["port"] = type_to_port.get(interface["type"], "")
- # Not handled in argument_spec with required_if since only SNMP interfaces are using details
- if interface['type'] == 2:
- if not interface['details']:
- self._module.fail_json(msg='Option "details" required for SNMP interface {0}'.format(interface))
+ if "bulk" in interface:
+ del interface["bulk"]
- i_details = interface['details']
- if i_details['version'] < 3 and not i_details.get('community', False):
- self._module.fail_json(
- msg='Option "community" is required in "details" for SNMP interface {0}'.format(interface))
+ # Not handled in argument_spec with required_if since only SNMP interfaces are using details
+ if interface["type"] == 2:
+ if not interface["details"]:
+ self._module.fail_json(msg="Option 'details' required for SNMP interface {0}".format(interface))
- else:
- interface['details'] = {}
+ i_details = interface["details"]
+ if i_details["version"] < 3 and not i_details.get("community", False):
+ self._module.fail_json(
+ msg="Option 'community' is required in 'details' for SNMP interface {0}".format(interface))
else:
- if 'details' in interface:
- del interface['details']
+ interface["details"] = {}
return (interfaces, ip)
@@ -735,7 +708,7 @@ class Host(ZabbixBase):
# get the status of host by host
def get_host_status_by_host(self, host):
- return host['status']
+ return host["status"]
# check all the properties before link or clear template
def check_all_properties(self, host_id, group_ids, status, interfaces, template_ids,
@@ -744,8 +717,8 @@ class Host(ZabbixBase):
tls_issuer, tls_subject, tls_connect, ipmi_authtype, ipmi_privilege,
ipmi_username, ipmi_password, macros, tags):
# get the existing host's groups
- exist_host_groups = sorted(self.get_group_ids_by_host_id(host_id), key=lambda k: k['groupid'])
- if sorted(group_ids, key=lambda k: k['groupid']) != exist_host_groups:
+ exist_host_groups = sorted(self.get_group_ids_by_host_id(host_id), key=lambda k: k["groupid"])
+ if sorted(group_ids, key=lambda k: k["groupid"]) != exist_host_groups:
return True
# get the existing status
@@ -762,97 +735,82 @@ class Host(ZabbixBase):
if set(list(template_ids)) != set(exist_template_ids):
return True
- if int(host['proxy_hostid']) != int(proxy_id):
+ if int(host["proxy_hostid"]) != int(proxy_id):
return True
# Check whether the visible_name has changed; Zabbix defaults to the technical hostname if not set.
if visible_name:
- if host['name'] != visible_name:
+ if host["name"] != visible_name:
return True
# Only compare description if it is given as a module parameter
if description:
- if host['description'] != description:
+ if host["description"] != description:
return True
if inventory_mode:
- if LooseVersion(self._zbx_api_version) <= LooseVersion('4.4.0'):
- if host['inventory']:
- if int(host['inventory']['inventory_mode']) != self.inventory_mode_numeric(inventory_mode):
- return True
- elif inventory_mode != 'disabled':
- return True
- else:
- if int(host['inventory_mode']) != self.inventory_mode_numeric(inventory_mode):
- return True
+ if int(host["inventory_mode"]) != self.inventory_mode_numeric(inventory_mode):
+ return True
if inventory_zabbix:
- proposed_inventory = copy.deepcopy(host['inventory'])
+ proposed_inventory = copy.deepcopy(host["inventory"])
proposed_inventory.update(inventory_zabbix)
- if proposed_inventory != host['inventory']:
+ if proposed_inventory != host["inventory"]:
return True
- if tls_accept is not None and 'tls_accept' in host:
- if int(host['tls_accept']) != tls_accept:
+ if tls_accept is not None and "tls_accept" in host:
+ if int(host["tls_accept"]) != tls_accept:
return True
- if LooseVersion(self._zbx_api_version) < LooseVersion('5.4'):
- if tls_psk_identity is not None and 'tls_psk_identity' in host:
- if host['tls_psk_identity'] != tls_psk_identity:
- return True
- if tls_psk is not None and 'tls_psk' in host:
- if host['tls_psk'] != tls_psk:
- return True
- else:
- # in Zabbix >= 5.4 these parameters are write-only and are not returned in host.get response
- if tls_psk_identity is not None or tls_psk is not None:
- return True
+ # in Zabbix >= 5.4 these parameters are write-only and are not returned in host.get response
+ if tls_psk_identity is not None or tls_psk is not None:
+ return True
- if tls_issuer is not None and 'tls_issuer' in host:
- if host['tls_issuer'] != tls_issuer:
+ if tls_issuer is not None and "tls_issuer" in host:
+ if host["tls_issuer"] != tls_issuer:
return True
- if tls_subject is not None and 'tls_subject' in host:
- if host['tls_subject'] != tls_subject:
+ if tls_subject is not None and "tls_subject" in host:
+ if host["tls_subject"] != tls_subject:
return True
- if tls_connect is not None and 'tls_connect' in host:
- if int(host['tls_connect']) != tls_connect:
+ if tls_connect is not None and "tls_connect" in host:
+ if int(host["tls_connect"]) != tls_connect:
return True
if ipmi_authtype is not None:
- if int(host['ipmi_authtype']) != ipmi_authtype:
+ if int(host["ipmi_authtype"]) != ipmi_authtype:
return True
if ipmi_privilege is not None:
- if int(host['ipmi_privilege']) != ipmi_privilege:
+ if int(host["ipmi_privilege"]) != ipmi_privilege:
return True
if ipmi_username is not None:
- if host['ipmi_username'] != ipmi_username:
+ if host["ipmi_username"] != ipmi_username:
return True
if ipmi_password is not None:
- if host['ipmi_password'] != ipmi_password:
+ if host["ipmi_password"] != ipmi_password:
return True
- # hostmacroid and hostid are present in every item of host['macros'] and need to be removed
- if macros is not None and 'macros' in host:
+ # hostmacroid and hostid are present in every item of host["macros"] and need to be removed
+ if macros is not None and "macros" in host:
t_macros = copy.deepcopy(macros) # make copy to prevent change in original data
- for macro in host['macros']:
- macro.pop('hostid', False)
- macro.pop('hostmacroid', False)
+ for macro in host["macros"]:
+ macro.pop("hostid", False)
+ macro.pop("hostmacroid", False)
diff = []
- zabbix_utils.helper_compare_lists(t_macros, host['macros'], diff)
+ zabbix_utils.helper_compare_lists(t_macros, host["macros"], diff)
if diff != []:
return True
- if tags is not None and 'tags' in host:
- if sorted(tags, key=lambda k: k['tag']) != sorted(host['tags'], key=lambda k: k['tag']):
+ if tags is not None and "tags" in host:
+ if sorted(tags, key=lambda k: k["tag"]) != sorted(host["tags"], key=lambda k: k["tag"]):
return True
return False
# link or clear template of the host
def link_or_clear_template(self, host_id, template_id_list, tls_connect, tls_accept, tls_psk_identity, tls_psk,
- tls_issuer, tls_subject, ipmi_authtype, ipmi_privilege, ipmi_username, ipmi_password):
+ tls_issuer, tls_subject, ipmi_authtype, ipmi_privilege, ipmi_username, ipmi_password, discovered_host):
# get host's exist template ids
exist_template_id_list = self.get_host_templates_by_host_id(host_id)
@@ -863,20 +821,25 @@ class Host(ZabbixBase):
# get unlink and clear templates
templates_clear = exist_template_ids.difference(template_ids)
templates_clear_list = list(templates_clear)
- request_str = {'hostid': host_id, 'templates': template_id_list, 'templates_clear': templates_clear_list,
- 'ipmi_authtype': ipmi_authtype, 'ipmi_privilege': ipmi_privilege, 'ipmi_username': ipmi_username, 'ipmi_password': ipmi_password}
- if tls_connect:
- request_str['tls_connect'] = tls_connect
- if tls_accept:
- request_str['tls_accept'] = tls_accept
- if tls_psk_identity is not None:
- request_str['tls_psk_identity'] = tls_psk_identity
- if tls_psk is not None:
- request_str['tls_psk'] = tls_psk
- if tls_issuer is not None:
- request_str['tls_issuer'] = tls_issuer
- if tls_subject is not None:
- request_str['tls_subject'] = tls_subject
+ if discovered_host:
+ # The host was discovered via Discovery Rule
+ request_str = {"hostid": host_id, "templates": template_id_list, "templates_clear": templates_clear_list}
+ else:
+ # A "plain" host
+ request_str = {"hostid": host_id, "templates": template_id_list, "templates_clear": templates_clear_list,
+ "ipmi_authtype": ipmi_authtype, "ipmi_privilege": ipmi_privilege, "ipmi_username": ipmi_username, "ipmi_password": ipmi_password}
+ if tls_connect:
+ request_str["tls_connect"] = tls_connect
+ if tls_accept:
+ request_str["tls_accept"] = tls_accept
+ if tls_psk_identity is not None:
+ request_str["tls_psk_identity"] = tls_psk_identity
+ if tls_psk is not None:
+ request_str["tls_psk"] = tls_psk
+ if tls_issuer is not None:
+ request_str["tls_issuer"] = tls_issuer
+ if tls_subject is not None:
+ request_str["tls_subject"] = tls_subject
try:
if self._module.check_mode:
self._module.exit_json(changed=True)
@@ -903,7 +866,7 @@ class Host(ZabbixBase):
inventory_mode = self.inventory_mode_numeric(inventory_mode)
# watch for - https://support.zabbix.com/browse/ZBX-6033
- request_str = {'hostid': host_id, 'inventory_mode': inventory_mode}
+ request_str = {"hostid": host_id, "inventory_mode": inventory_mode}
try:
if self._module.check_mode:
self._module.exit_json(changed=True)
@@ -916,7 +879,7 @@ class Host(ZabbixBase):
if not inventory:
return
- request_str = {'hostid': host_id, 'inventory': inventory}
+ request_str = {"hostid": host_id, "inventory": inventory}
try:
if self._module.check_mode:
self._module.exit_json(changed=True)
@@ -930,30 +893,30 @@ def update_exist_interfaces_with_defaults(exist_interfaces):
new_exist_interfaces = []
default_interface = {
- 'main': '0',
- 'useip': '0',
- 'ip': '',
- 'dns': '',
- 'port': ''
+ "main": "0",
+ "useip": "0",
+ "ip": "",
+ "dns": "",
+ "port": ""
}
default_interface_details = {
- 'version': 2,
- 'bulk': 1,
- 'community': '',
- 'securityname': '',
- 'contextname': '',
- 'securitylevel': 0,
- 'authprotocol': 0,
- 'authpassphrase': '',
- 'privprotocol': 0,
- 'privpassphrase': ''
+ "version": 2,
+ "bulk": 1,
+ "community": "",
+ "securityname": "",
+ "contextname": "",
+ "securitylevel": 0,
+ "authprotocol": 0,
+ "authpassphrase": "",
+ "privprotocol": 0,
+ "privpassphrase": ""
}
for interface in exist_interfaces:
new_interface = default_interface.copy()
new_interface.update(interface)
- new_interface['details'] = default_interface_details.copy()
- if 'details' in interface:
- new_interface['details'].update(interface['details'])
+ new_interface["details"] = default_interface_details.copy()
+ if "details" in interface:
+ new_interface["details"].update(interface["details"])
new_exist_interfaces.append(new_interface)
return new_exist_interfaces
@@ -961,16 +924,16 @@ def update_exist_interfaces_with_defaults(exist_interfaces):
def normalize_macro_name(macro_name):
# Zabbix handles macro names in upper case characters
- if ':' in macro_name:
- macro_name = ':'.join([macro_name.split(':')[0].upper(), ':'.join(macro_name.split(':')[1:])])
+ if ":" in macro_name:
+ macro_name = ":".join([macro_name.split(":")[0].upper(), ":".join(macro_name.split(":")[1:])])
else:
macro_name = macro_name.upper()
# Valid format for macro is {$MACRO}
- if not macro_name.startswith('{$'):
- macro_name = '{$' + macro_name
- if not macro_name.endswith('}'):
- macro_name = macro_name + '}'
+ if not macro_name.startswith("{$"):
+ macro_name = "{$" + macro_name
+ if not macro_name.endswith("}"):
+ macro_name = macro_name + "}"
return macro_name
@@ -978,79 +941,78 @@ def normalize_macro_name(macro_name):
def main():
argument_spec = zabbix_utils.zabbix_common_argument_spec()
argument_spec.update(dict(
- host_name=dict(type='str', required=True),
- host_groups=dict(type='list', required=False),
- link_templates=dict(type='list', required=False),
- status=dict(type='str', default="enabled", choices=['enabled', 'disabled']),
- state=dict(type='str', default="present", choices=['present', 'absent']),
- inventory_mode=dict(type='str', required=False, choices=['automatic', 'manual', 'disabled']),
- ipmi_authtype=dict(type='int', default=None),
- ipmi_privilege=dict(type='int', default=None),
- ipmi_username=dict(type='str', required=False, default=None),
- ipmi_password=dict(type='str', required=False, default=None, no_log=True),
- tls_connect=dict(type='int', required=False),
- tls_accept=dict(type='int', required=False),
- tls_psk_identity=dict(type='str', required=False),
- tls_psk=dict(type='str', required=False, no_log=True),
- ca_cert=dict(type='str', required=False, aliases=['tls_issuer']),
- tls_subject=dict(type='str', required=False),
- inventory_zabbix=dict(type='dict', required=False),
+ host_name=dict(type="str", required=True),
+ host_groups=dict(type="list", required=False, elements="str"),
+ link_templates=dict(type="list", required=False, elements="str"),
+ status=dict(type="str", default="enabled", choices=["enabled", "disabled"]),
+ state=dict(type="str", default="present", choices=["present", "absent"]),
+ inventory_mode=dict(type="str", required=False, choices=["automatic", "manual", "disabled"]),
+ ipmi_authtype=dict(type="int", default=None),
+ ipmi_privilege=dict(type="int", default=None),
+ ipmi_username=dict(type="str", required=False, default=None),
+ ipmi_password=dict(type="str", required=False, default=None, no_log=True),
+ tls_connect=dict(type="int", required=False),
+ tls_accept=dict(type="int", required=False),
+ tls_psk_identity=dict(type="str", required=False),
+ tls_psk=dict(type="str", required=False, no_log=True),
+ ca_cert=dict(type="str", required=False, aliases=["tls_issuer"]),
+ tls_subject=dict(type="str", required=False),
+ inventory_zabbix=dict(type="dict", required=False),
interfaces=dict(
- type='list',
- elements='dict',
+ type="list",
+ elements="dict",
default=[],
options=dict(
- type=dict(type='str', required=True, choices=['agent', '1', 'snmp', '2', 'ipmi', '3', 'jmx', '4']),
- main=dict(type='int', choices=[0, 1], default=0),
- useip=dict(type='int', choices=[0, 1], default=0),
- ip=dict(type='str'),
- dns=dict(type='str'),
- port=dict(type='str'),
- bulk=dict(type='int', choices=[0, 1], default=1),
+ type=dict(type="str", required=True, choices=["agent", "1", "snmp", "2", "ipmi", "3", "jmx", "4"]),
+ main=dict(type="int", choices=[0, 1], default=0),
+ useip=dict(type="int", choices=[0, 1], default=0),
+ ip=dict(type="str"),
+ dns=dict(type="str"),
+ port=dict(type="str"),
details=dict(
- type='dict',
+ type="dict",
default={},
options=dict(
- version=dict(type='int', choices=[1, 2, 3], default=2),
- bulk=dict(type='int', choices=[0, 1], default=1),
- community=dict(type='str', default=''),
- securityname=dict(type='str', default=''),
- contextname=dict(type='str', default=''),
- securitylevel=dict(type='int', choices=[0, 1, 2], default=0),
- authprotocol=dict(type='int', choices=[0, 1, 2, 3, 4, 5], default=0),
- authpassphrase=dict(type='str', default='', no_log=True),
- privprotocol=dict(type='int', choices=[0, 1, 2, 3, 4, 5], default=0),
- privpassphrase=dict(type='str', default='', no_log=True)
+ version=dict(type="int", choices=[1, 2, 3], default=2),
+ bulk=dict(type="int", choices=[0, 1], default=1),
+ community=dict(type="str", default=""),
+ securityname=dict(type="str", default=""),
+ contextname=dict(type="str", default=""),
+ securitylevel=dict(type="int", choices=[0, 1, 2], default=0),
+ authprotocol=dict(type="int", choices=[0, 1, 2, 3, 4, 5], default=0),
+ authpassphrase=dict(type="str", default="", no_log=True),
+ privprotocol=dict(type="int", choices=[0, 1, 2, 3, 4, 5], default=0),
+ privpassphrase=dict(type="str", default="", no_log=True)
)
)
),
required_if=[
- ['useip', 0, ['dns']],
- ['useip', 1, ['ip']]
+ ["useip", 0, ["dns"]],
+ ["useip", 1, ["ip"]]
]
),
- force=dict(type='bool', default=True),
- proxy=dict(type='str', required=False),
- visible_name=dict(type='str', required=False),
- description=dict(type='str', required=False),
+ force=dict(type="bool", default=True),
+ proxy=dict(type="str", required=False),
+ visible_name=dict(type="str", required=False),
+ description=dict(type="str", required=False),
macros=dict(
- type='list',
- elements='dict',
- aliases=['user_macros'],
+ type="list",
+ elements="dict",
+ aliases=["user_macros"],
options=dict(
- macro=dict(type='str', required=True),
- value=dict(type='str', required=True),
- description=dict(type='str', default=''),
- type=dict(type='str', default='text', choices=['text', 'secret'])
+ macro=dict(type="str", required=True),
+ value=dict(type="str", required=True),
+ description=dict(type="str", default=""),
+ type=dict(type="str", default="text", choices=["text", "secret"])
)
),
tags=dict(
- type='list',
- elements='dict',
- aliases=['host_tags'],
+ type="list",
+ elements="dict",
+ aliases=["host_tags"],
options=dict(
- tag=dict(type='str', required=True),
- value=dict(type='str', default='')
+ tag=dict(type="str", required=True),
+ value=dict(type="str", default="")
)
)
))
@@ -1059,36 +1021,30 @@ def main():
supports_check_mode=True
)
- zabbix_utils.require_creds_params(module)
-
- for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']:
- if p in module.params and not module.params[p] is None:
- module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p)
-
- host_name = module.params['host_name']
- visible_name = module.params['visible_name']
- description = module.params['description']
- host_groups = module.params['host_groups']
- link_templates = module.params['link_templates']
- inventory_mode = module.params['inventory_mode']
- ipmi_authtype = module.params['ipmi_authtype']
- ipmi_privilege = module.params['ipmi_privilege']
- ipmi_username = module.params['ipmi_username']
- ipmi_password = module.params['ipmi_password']
- tls_connect = module.params['tls_connect']
- tls_accept = module.params['tls_accept']
- tls_psk_identity = module.params['tls_psk_identity']
- tls_psk = module.params['tls_psk']
- tls_issuer = module.params['ca_cert']
- tls_subject = module.params['tls_subject']
- inventory_zabbix = module.params['inventory_zabbix']
- status = module.params['status']
- state = module.params['state']
- interfaces = module.params['interfaces']
- force = module.params['force']
- proxy = module.params['proxy']
- macros = module.params['macros']
- tags = module.params['tags']
+ host_name = module.params["host_name"]
+ visible_name = module.params["visible_name"]
+ description = module.params["description"]
+ host_groups = module.params["host_groups"]
+ link_templates = module.params["link_templates"]
+ inventory_mode = module.params["inventory_mode"]
+ ipmi_authtype = module.params["ipmi_authtype"]
+ ipmi_privilege = module.params["ipmi_privilege"]
+ ipmi_username = module.params["ipmi_username"]
+ ipmi_password = module.params["ipmi_password"]
+ tls_connect = module.params["tls_connect"]
+ tls_accept = module.params["tls_accept"]
+ tls_psk_identity = module.params["tls_psk_identity"]
+ tls_psk = module.params["tls_psk"]
+ tls_issuer = module.params["ca_cert"]
+ tls_subject = module.params["tls_subject"]
+ inventory_zabbix = module.params["inventory_zabbix"]
+ status = module.params["status"]
+ state = module.params["state"]
+ interfaces = module.params["interfaces"]
+ force = module.params["force"]
+ proxy = module.params["proxy"]
+ macros = module.params["macros"]
+ tags = module.params["tags"]
# convert enabled to 0; disabled to 1
status = 1 if status == "disabled" else 0
@@ -1109,20 +1065,13 @@ def main():
if macros:
# convert macros to zabbix native format - {$MACRO}
for macro in macros:
- macro['macro'] = normalize_macro_name(macro['macro'])
+ macro["macro"] = normalize_macro_name(macro["macro"])
- if LooseVersion(host._zbx_api_version) <= LooseVersion('4.4.0'):
- if 'description' in macro:
- macro.pop('description', False)
-
- if 'type' in macro:
- if LooseVersion(host._zbx_api_version) < LooseVersion('5.0.0'):
- macro.pop('type')
- else:
- if macro['type'] == 'text':
- macro['type'] = '0'
- elif macro['type'] == 'secret':
- macro['type'] = '1'
+ if "type" in macro:
+ if macro["type"] == "text":
+ macro["type"] = "0"
+ elif macro["type"] == "secret":
+ macro["type"] = "1"
# Use proxy specified, or set to 0
if proxy:
@@ -1136,11 +1085,12 @@ def main():
if is_host_exist:
# get host id by host name
zabbix_host_obj = host.get_host_by_host_name(host_name)
- host_id = zabbix_host_obj['hostid']
+ host_id = zabbix_host_obj["hostid"]
+ discovered_host = zabbix_host_obj["flags"] == '4'
# If proxy is not specified as a module parameter, use the existing setting
if proxy is None:
- proxy_id = int(zabbix_host_obj['proxy_hostid'])
+ proxy_id = int(zabbix_host_obj["proxy_hostid"])
if state == "absent":
# remove host
@@ -1153,29 +1103,29 @@ def main():
group_ids = host.get_group_ids_by_host_id(host_id)
# get existing host's interfaces
- exist_interfaces = host._zapi.hostinterface.get({'output': 'extend', 'hostids': host_id})
- exist_interfaces.sort(key=lambda x: int(x['interfaceid']))
+ exist_interfaces = host._zapi.hostinterface.get({"output": "extend", "hostids": host_id})
+ exist_interfaces.sort(key=lambda x: int(x["interfaceid"]))
exist_interfaces = update_exist_interfaces_with_defaults(exist_interfaces)
# Convert integer parameters from strings to ints
for idx, interface in enumerate(copy.deepcopy(exist_interfaces)):
for key in tuple(interface.keys()):
# fix values for properties
- if key in ['useip', 'main', 'type', 'bulk']:
+ if key in ["useip", "main", "type", "bulk"]:
exist_interfaces[idx][key] = int(interface[key])
- elif key == 'details':
+ elif key == "details":
if not interface[key]:
exist_interfaces[idx][key] = {}
else:
for d_key in interface[key].keys():
- if d_key in ['version', 'bulk', 'securitylevel', 'authprotocol', 'privprotocol']:
+ if d_key in ["version", "bulk", "securitylevel", "authprotocol", "privprotocol"]:
exist_interfaces[idx][key][d_key] = int(interface[key][d_key])
interfaces_copy = copy.deepcopy(interfaces)
found_in_interfaces = []
for idx, interface in enumerate(copy.deepcopy(exist_interfaces)):
- interfaceid = interface['interfaceid']
- hostid = interface['hostid']
+ interfaceid = interface["interfaceid"]
+ hostid = interface["hostid"]
if not interfaces_copy:
# Whe no interfaces specified, copy existing interfaces
@@ -1183,8 +1133,8 @@ def main():
continue
# Find already configured interfaces in requested interfaces and compile final list of
- # interfaces in 'interfaces' variable. Every element of the list defines one interface.
- # If an element has 'interfaceid' field then Zabbix will update existing interface otherwise
+ # interfaces in "interfaces" variable. Every element of the list defines one interface.
+ # If an element has "interfaceid" field then Zabbix will update existing interface otherwise
# a new interface will be added.
found = False
for idx1, iface in enumerate(interfaces_copy):
@@ -1193,8 +1143,8 @@ def main():
if diff_dict == {}:
found = True
found_in_interfaces.append(iface)
- interfaces[idx1]['interfaceid'] = interfaceid
- interfaces[idx1]['hostid'] = hostid
+ interfaces[idx1]["interfaceid"] = interfaceid
+ interfaces[idx1]["hostid"] = hostid
break
if not found:
@@ -1203,10 +1153,10 @@ def main():
else:
# if force == True overwrite existing interfaces with provided interfaces with the same type
for idx1, iface in enumerate(interfaces_copy):
- if interface['type'] == iface['type'] and iface not in found_in_interfaces:
+ if interface["type"] == iface["type"] and iface not in found_in_interfaces:
found_in_interfaces.append(iface)
- interfaces[idx1]['interfaceid'] = interfaceid
- interfaces[idx1]['hostid'] = hostid
+ interfaces[idx1]["interfaceid"] = interfaceid
+ interfaces[idx1]["hostid"] = hostid
break
if not force or link_templates is None:
@@ -1218,12 +1168,12 @@ def main():
group_ids.append(group_id)
# Macros not present in host.update will be removed if we dont copy them when force=no
- if macros is not None and 'macros' in zabbix_host_obj.keys():
- existing_macros = zabbix_host_obj['macros']
+ if macros is not None and "macros" in zabbix_host_obj.keys():
+ existing_macros = zabbix_host_obj["macros"]
for macro in existing_macros:
- macro.pop('hostmacroid', None)
- macro.pop('hostid', None)
- macro.pop('automatic', None)
+ macro.pop("hostmacroid", None)
+ macro.pop("hostid", None)
+ macro.pop("automatic", None)
found = False
for idx1, prov_macro in enumerate(macros):
diff_dict = {}
@@ -1237,11 +1187,11 @@ def main():
macros.append(macro)
# Tags not present in host.update will be removed if we dont copy them when force=no
- if tags is not None and 'tags' in zabbix_host_obj.keys():
- provided_tags = [t['tag'] for t in tags]
- existing_tags = zabbix_host_obj['tags']
+ if tags is not None and "tags" in zabbix_host_obj.keys():
+ provided_tags = [t["tag"] for t in tags]
+ existing_tags = zabbix_host_obj["tags"]
for tag in existing_tags:
- if tag['tag'] not in provided_tags:
+ if tag["tag"] not in provided_tags:
tags.append(tag)
# update host
@@ -1254,11 +1204,11 @@ def main():
host.update_host(
host_name, group_ids, status, host_id, interfaces, exist_interfaces, proxy_id, visible_name,
description, tls_connect, tls_accept, tls_psk_identity, tls_psk, tls_issuer, tls_subject,
- ipmi_authtype, ipmi_privilege, ipmi_username, ipmi_password, macros, tags)
+ ipmi_authtype, ipmi_privilege, ipmi_username, ipmi_password, macros, tags, discovered_host)
host.link_or_clear_template(
host_id, template_ids, tls_connect, tls_accept, tls_psk_identity, tls_psk, tls_issuer,
- tls_subject, ipmi_authtype, ipmi_privilege, ipmi_username, ipmi_password)
+ tls_subject, ipmi_authtype, ipmi_privilege, ipmi_username, ipmi_password, discovered_host)
host.update_inventory_mode(host_id, inventory_mode)
host.update_inventory_zabbix(host_id, inventory_zabbix)
@@ -1270,6 +1220,8 @@ def main():
module.exit_json(changed=False)
else:
+ discovered_host = False
+
if state == "absent":
# the host is already deleted.
module.exit_json(changed=False)
@@ -1277,10 +1229,6 @@ def main():
if not group_ids:
module.fail_json(msg="Specify at least one group for creating host '%s'." % host_name)
- if not interfaces or (interfaces and len(interfaces) == 0):
- if LooseVersion(host._zbx_api_version) < LooseVersion('5.2.0'):
- module.fail_json(msg="Specify at least one interface for creating host '%s'." % host_name)
-
# create host
host_id = host.add_host(
host_name, group_ids, status, interfaces, proxy_id, visible_name, description, tls_connect, tls_accept,
@@ -1289,7 +1237,7 @@ def main():
host.link_or_clear_template(
host_id, template_ids, tls_connect, tls_accept, tls_psk_identity, tls_psk, tls_issuer, tls_subject,
- ipmi_authtype, ipmi_privilege, ipmi_username, ipmi_password)
+ ipmi_authtype, ipmi_privilege, ipmi_username, ipmi_password, discovered_host)
host.update_inventory_mode(host_id, inventory_mode)
host.update_inventory_zabbix(host_id, inventory_zabbix)
@@ -1298,5 +1246,5 @@ def main():
host_name, ip, link_templates))
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_host_events_info.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_host_events_info.py
index eb22ce23c..fde86bc12 100644
--- a/ansible_collections/community/zabbix/plugins/modules/zabbix_host_events_info.py
+++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_host_events_info.py
@@ -9,7 +9,7 @@ from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
-RETURN = '''
+RETURN = """
---
triggers_ok:
description: Host Zabbix Triggers in OK state
@@ -134,20 +134,20 @@ triggers_problem:
value:
description: Whether the trigger is in OK or problem state
type: int
-'''
+"""
-DOCUMENTATION = '''
+DOCUMENTATION = """
---
module: zabbix_host_events_info
short_description: Get all triggers about a Zabbix host
description:
- This module allows you to see if a Zabbix host have no active alert to make actions on it.
- For this case use module Ansible 'fail' to exclude host in trouble.
+ For this case use module Ansible "fail" to exclude host in trouble.
- Length of "triggers_ok" allow if template's triggers exist for Zabbix Host
author:
- "Stéphane Travassac (@stravassac)"
requirements:
- - "python >= 2.7"
+ - "python >= 3.9"
options:
host_identifier:
description:
@@ -180,19 +180,19 @@ options:
extends_documentation_fragment:
- community.zabbix.zabbix
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = """
# If you want to use Username and Password to be authenticated by Zabbix Server
- name: Set credentials to access Zabbix Server API
- set_fact:
+ ansible.builtin.set_fact:
ansible_user: Admin
ansible_httpapi_pass: zabbix
# If you want to use API token to be authenticated by Zabbix Server
# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens
- name: Set API token
- set_fact:
+ ansible.builtin.set_fact:
ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895
- name: exclude machine if alert active on it
@@ -203,18 +203,17 @@ EXAMPLES = '''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_host_events_info:
host_identifier: "{{inventory_hostname}}"
host_id_type: "hostname"
- timeout: 120
register: zbx_host
delegate_to: localhost
- fail:
msg: "machine alert in zabbix"
- when: zbx_host['triggers_problem']|length > 0
-'''
+ when: zbx_host["triggers_problem"]|length > 0
+"""
from ansible.module_utils.basic import AnsibleModule
@@ -227,8 +226,8 @@ class Host(ZabbixBase):
def get_host(self, host_identifier, host_inventory, search_key):
""" Get host by hostname|visible_name|hostid """
host = self._zapi.host.get(
- {'output': 'extend', 'selectParentTemplates': ['name'], 'filter': {search_key: host_identifier},
- 'selectInventory': host_inventory})
+ {"output": "extend", "selectParentTemplates": ["name"], "filter": {search_key: host_identifier},
+ "selectInventory": host_inventory})
if len(host) < 1:
self._module.fail_json(msg="Host not found: %s" % host_identifier)
else:
@@ -236,18 +235,17 @@ class Host(ZabbixBase):
def get_triggers_by_host_id_in_problem_state(self, host_id, trigger_severity):
""" Get triggers in problem state from a hostid"""
- # https://www.zabbix.com/documentation/3.4/manual/api/reference/trigger/get
- output = 'extend'
- triggers_list = self._zapi.trigger.get({'output': output, 'hostids': host_id,
- 'min_severity': trigger_severity})
+ output = "extend"
+ triggers_list = self._zapi.trigger.get({"output": output, "hostids": host_id,
+ "min_severity": trigger_severity})
return triggers_list
def get_last_event_by_trigger_id(self, triggers_id):
""" Get the last event from triggerid"""
- output = ['eventid', 'clock', 'acknowledged', 'value']
- select_acknowledges = ['clock', 'alias', 'message']
- event = self._zapi.event.get({'output': output, 'objectids': triggers_id,
- 'select_acknowledges': select_acknowledges, "limit": 1, "sortfield": "clock",
+ output = ["eventid", "clock", "acknowledged", "value"]
+ select_acknowledges = ["clock", "alias", "message"]
+ event = self._zapi.event.get({"output": output, "objectids": triggers_id,
+ "select_acknowledges": select_acknowledges, "limit": 1, "sortfield": "clock",
"sortorder": "DESC"})
return event[0]
@@ -255,48 +253,42 @@ class Host(ZabbixBase):
def main():
argument_spec = zabbix_utils.zabbix_common_argument_spec()
argument_spec.update(dict(
- host_identifier=dict(type='str', required=True),
+ host_identifier=dict(type="str", required=True),
host_id_type=dict(
- default='hostname',
- type='str',
- choices=['hostname', 'visible_name', 'hostid']),
+ default="hostname",
+ type="str",
+ choices=["hostname", "visible_name", "hostid"]),
trigger_severity=dict(
- type='str',
+ type="str",
required=False,
- default='average',
- choices=['not_classified', 'information', 'warning', 'average', 'high', 'disaster']),
+ default="average",
+ choices=["not_classified", "information", "warning", "average", "high", "disaster"]),
))
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True
)
- zabbix_utils.require_creds_params(module)
+ trigger_severity_map = {"not_classified": 0, "information": 1, "warning": 2, "average": 3, "high": 4, "disaster": 5}
+ host_id = module.params["host_identifier"]
+ host_id_type = module.params["host_id_type"]
+ trigger_severity = trigger_severity_map[module.params["trigger_severity"]]
- for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']:
- if p in module.params and not module.params[p] is None:
- module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p)
-
- trigger_severity_map = {'not_classified': 0, 'information': 1, 'warning': 2, 'average': 3, 'high': 4, 'disaster': 5}
- host_id = module.params['host_identifier']
- host_id_type = module.params['host_id_type']
- trigger_severity = trigger_severity_map[module.params['trigger_severity']]
-
- host_inventory = 'hostid'
+ host_inventory = "hostid"
host = Host(module)
- if host_id_type == 'hostname':
- zabbix_host = host.get_host(host_id, host_inventory, 'host')
- host_id = zabbix_host['hostid']
+ if host_id_type == "hostname":
+ zabbix_host = host.get_host(host_id, host_inventory, "host")
+ host_id = zabbix_host["hostid"]
- elif host_id_type == 'visible_name':
- zabbix_host = host.get_host(host_id, host_inventory, 'name')
- host_id = zabbix_host['hostid']
+ elif host_id_type == "visible_name":
+ zabbix_host = host.get_host(host_id, host_inventory, "name")
+ host_id = zabbix_host["hostid"]
- elif host_id_type == 'hostid':
- ''' check hostid exist'''
- zabbix_host = host.get_host(host_id, host_inventory, 'hostid')
+ elif host_id_type == "hostid":
+ # check hostid exist
+ zabbix_host = host.get_host(host_id, host_inventory, "hostid")
triggers = host.get_triggers_by_host_id_in_problem_state(host_id, trigger_severity)
@@ -305,9 +297,9 @@ def main():
for trigger in triggers:
# tGet last event for trigger with problem value = 1
# https://www.zabbix.com/documentation/3.4/manual/api/reference/trigger/object
- if int(trigger['value']) == 1:
- event = host.get_last_event_by_trigger_id(trigger['triggerid'])
- trigger['last_event'] = event
+ if int(trigger["value"]) == 1:
+ event = host.get_last_event_by_trigger_id(trigger["triggerid"])
+ trigger["last_event"] = event
triggers_problem.append(trigger)
else:
triggers_ok.append(trigger)
@@ -315,5 +307,5 @@ def main():
module.exit_json(ok=True, triggers_ok=triggers_ok, triggers_problem=triggers_problem)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_host_facts.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_host_facts.py
deleted file mode 100644
index 58e3343ab..000000000
--- a/ansible_collections/community/zabbix/plugins/modules/zabbix_host_facts.py
+++ /dev/null
@@ -1,239 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# (c) me@mimiko.me
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-RETURN = r'''
----
-hosts:
- description: List of Zabbix hosts. See https://www.zabbix.com/documentation/4.0/manual/api/reference/host/get for list of host values.
- returned: success
- type: dict
- sample: [ { "available": "1", "description": "", "disable_until": "0", "error": "", "flags": "0", "groups": ["1"], "host": "Host A", ... } ]
-'''
-
-DOCUMENTATION = r'''
----
-module: zabbix_host_info
-short_description: Gather information about Zabbix host
-description:
- - This module allows you to search for Zabbix host entries.
- - This module was called C(zabbix_host_facts) before Ansible 2.9. The usage did not change.
-author:
- - "Michael Miko (@RedWhiteMiko)"
-requirements:
- - "python >= 2.6"
-options:
- host_name:
- description:
- - Name of the host in Zabbix.
- - host_name is the unique identifier used and cannot be updated using this module.
- - Required when I(host_ip) is not used.
- required: false
- type: str
- default: ''
- host_ip:
- description:
- - Host interface IP of the host in Zabbix.
- - Required when I(host_name) is not used.
- required: false
- type: list
- elements: str
- default: []
- exact_match:
- description:
- - Find the exact match
- type: bool
- default: no
- remove_duplicate:
- description:
- - Remove duplicate host from host result
- type: bool
- default: yes
- host_inventory:
- description:
- - List of host inventory keys to display in result.
- - Whole host inventory is retrieved if keys are not specified.
- type: list
- elements: str
- required: false
- default: []
-extends_documentation_fragment:
-- community.zabbix.zabbix
-
-'''
-
-EXAMPLES = r'''
-# If you want to use Username and Password to be authenticated by Zabbix Server
-- name: Set credentials to access Zabbix Server API
- set_fact:
- ansible_user: Admin
- ansible_httpapi_pass: zabbix
-
-# If you want to use API token to be authenticated by Zabbix Server
-# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens
-- name: Set API token
- set_fact:
- ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895
-
-- name: Get host info
- # set task level variables as we change ansible_connection plugin here
- vars:
- ansible_network_os: community.zabbix.zabbix
- ansible_connection: httpapi
- ansible_httpapi_port: 443
- ansible_httpapi_use_ssl: true
- ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
- ansible_host: zabbix-example-fqdn.org
- community.zabbix.zabbix_host_info:
- host_name: ExampleHost
- host_ip: 127.0.0.1
- timeout: 10
- exact_match: no
- remove_duplicate: yes
-
-- name: Reduce host inventory information to provided keys
- # set task level variables as we change ansible_connection plugin here
- vars:
- ansible_network_os: community.zabbix.zabbix
- ansible_connection: httpapi
- ansible_httpapi_port: 443
- ansible_httpapi_use_ssl: true
- ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
- ansible_host: zabbix-example-fqdn.org
- community.zabbix.zabbix_host_info:
- host_name: ExampleHost
- host_inventory:
- - os
- - tag
- host_ip: 127.0.0.1
- timeout: 10
- exact_match: no
- remove_duplicate: yes
-'''
-
-
-from ansible.module_utils.basic import AnsibleModule
-
-from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase
-import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils
-
-
-class Host(ZabbixBase):
- def get_hosts_by_host_name(self, host_name, exact_match, host_inventory):
- """ Get host by host name """
- search_key = 'search'
- if exact_match:
- search_key = 'filter'
- host_list = self._zapi.host.get({
- 'output': 'extend',
- 'selectParentTemplates': ['name'],
- search_key: {'host': [host_name]},
- 'selectInventory': host_inventory,
- 'selectGroups': 'extend',
- 'selectTags': 'extend',
- 'selectMacros': 'extend'
- })
- if len(host_list) < 1:
- self._module.fail_json(msg="Host not found: %s" % host_name)
- else:
- return host_list
-
- def get_hosts_by_ip(self, host_ips, host_inventory):
- """ Get host by host ip(s) """
- hostinterfaces = self._zapi.hostinterface.get({
- 'output': 'extend',
- 'filter': {
- 'ip': host_ips
- }
- })
- if len(hostinterfaces) < 1:
- self._module.fail_json(msg="Host not found: %s" % host_ips)
- host_list = []
- for hostinterface in hostinterfaces:
- host = self._zapi.host.get({
- 'output': 'extend',
- 'selectGroups': 'extend',
- 'selectParentTemplates': ['name'],
- 'hostids': hostinterface['hostid'],
- 'selectInventory': host_inventory,
- 'selectTags': 'extend',
- 'selectMacros': 'extend'
- })
- host[0]['hostinterfaces'] = hostinterface
- host_list.append(host[0])
- return host_list
-
- def delete_duplicate_hosts(self, hosts):
- """ Delete duplicated hosts """
- unique_hosts = []
- listed_hostnames = []
- for zabbix_host in hosts:
- if zabbix_host['name'] in listed_hostnames:
- continue
- unique_hosts.append(zabbix_host)
- listed_hostnames.append(zabbix_host['name'])
- return unique_hosts
-
-
-def main():
- argument_spec = zabbix_utils.zabbix_common_argument_spec()
- argument_spec.update(dict(
- host_name=dict(type='str', default='', required=False),
- host_ip=dict(type='list', default=[], required=False),
- exact_match=dict(type='bool', required=False, default=False),
- remove_duplicate=dict(type='bool', required=False, default=True),
- host_inventory=dict(type='list', default=[], required=False)
- ))
- module = AnsibleModule(
- argument_spec=argument_spec,
- supports_check_mode=True
- )
- if module._name == 'zabbix_host_facts':
- module.deprecate("The 'zabbix_host_facts' module has been renamed to 'zabbix_host_info'",
- collection_name="community.zabbix", version='2.0.0') # was 2.13
-
- zabbix_utils.require_creds_params(module)
-
- host_name = module.params['host_name']
- host_ips = module.params['host_ip']
- exact_match = module.params['exact_match']
- is_remove_duplicate = module.params['remove_duplicate']
- host_inventory = module.params['host_inventory']
-
- if not host_inventory:
- host_inventory = 'extend'
-
- host = Host(module)
-
- if host_name:
- hosts = host.get_hosts_by_host_name(host_name, exact_match, host_inventory)
- if is_remove_duplicate:
- hosts = host.delete_duplicate_hosts(hosts)
- extended_hosts = []
- for zabbix_host in hosts:
- zabbix_host['hostinterfaces'] = host._zapi.hostinterface.get({
- 'output': 'extend', 'hostids': zabbix_host['hostid']
- })
- extended_hosts.append(zabbix_host)
- module.exit_json(ok=True, hosts=extended_hosts)
-
- elif host_ips:
- extended_hosts = host.get_hosts_by_ip(host_ips, host_inventory)
- if is_remove_duplicate:
- hosts = host.delete_duplicate_hosts(extended_hosts)
- module.exit_json(ok=True, hosts=extended_hosts)
- else:
- module.exit_json(ok=False, hosts=[], result="No Host present")
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_host_info.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_host_info.py
index 58e3343ab..92c185227 100644
--- a/ansible_collections/community/zabbix/plugins/modules/zabbix_host_info.py
+++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_host_info.py
@@ -9,16 +9,16 @@ from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
-RETURN = r'''
+RETURN = r"""
---
hosts:
description: List of Zabbix hosts. See https://www.zabbix.com/documentation/4.0/manual/api/reference/host/get for list of host values.
returned: success
type: dict
sample: [ { "available": "1", "description": "", "disable_until": "0", "error": "", "flags": "0", "groups": ["1"], "host": "Host A", ... } ]
-'''
+"""
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: zabbix_host_info
short_description: Gather information about Zabbix host
@@ -28,16 +28,17 @@ description:
author:
- "Michael Miko (@RedWhiteMiko)"
requirements:
- - "python >= 2.6"
+ - "python >= 3.9"
options:
host_name:
description:
- Name of the host in Zabbix.
- host_name is the unique identifier used and cannot be updated using this module.
- Required when I(host_ip) is not used.
+ - If neither host_name nor host_ip specified then all the hosts configured in Zabbix returned.
required: false
type: str
- default: ''
+ default: ""
host_ip:
description:
- Host interface IP of the host in Zabbix.
@@ -67,19 +68,19 @@ options:
extends_documentation_fragment:
- community.zabbix.zabbix
-'''
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
# If you want to use Username and Password to be authenticated by Zabbix Server
- name: Set credentials to access Zabbix Server API
- set_fact:
+ ansible.builtin.set_fact:
ansible_user: Admin
ansible_httpapi_pass: zabbix
# If you want to use API token to be authenticated by Zabbix Server
# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens
- name: Set API token
- set_fact:
+ ansible.builtin.set_fact:
ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895
- name: Get host info
@@ -90,12 +91,11 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_host_info:
host_name: ExampleHost
host_ip: 127.0.0.1
- timeout: 10
exact_match: no
remove_duplicate: yes
@@ -107,7 +107,7 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_host_info:
host_name: ExampleHost
@@ -115,10 +115,9 @@ EXAMPLES = r'''
- os
- tag
host_ip: 127.0.0.1
- timeout: 10
exact_match: no
remove_duplicate: yes
-'''
+"""
from ansible.module_utils.basic import AnsibleModule
@@ -130,17 +129,17 @@ import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabb
class Host(ZabbixBase):
def get_hosts_by_host_name(self, host_name, exact_match, host_inventory):
""" Get host by host name """
- search_key = 'search'
+ search_key = "search"
if exact_match:
- search_key = 'filter'
+ search_key = "filter"
host_list = self._zapi.host.get({
- 'output': 'extend',
- 'selectParentTemplates': ['name'],
- search_key: {'host': [host_name]},
- 'selectInventory': host_inventory,
- 'selectGroups': 'extend',
- 'selectTags': 'extend',
- 'selectMacros': 'extend'
+ "output": "extend",
+ "selectParentTemplates": ["name"],
+ search_key: {"host": [host_name]},
+ "selectInventory": host_inventory,
+ "selectGroups": "extend",
+ "selectTags": "extend",
+ "selectMacros": "extend"
})
if len(host_list) < 1:
self._module.fail_json(msg="Host not found: %s" % host_name)
@@ -150,9 +149,9 @@ class Host(ZabbixBase):
def get_hosts_by_ip(self, host_ips, host_inventory):
""" Get host by host ip(s) """
hostinterfaces = self._zapi.hostinterface.get({
- 'output': 'extend',
- 'filter': {
- 'ip': host_ips
+ "output": "extend",
+ "filter": {
+ "ip": host_ips
}
})
if len(hostinterfaces) < 1:
@@ -160,15 +159,15 @@ class Host(ZabbixBase):
host_list = []
for hostinterface in hostinterfaces:
host = self._zapi.host.get({
- 'output': 'extend',
- 'selectGroups': 'extend',
- 'selectParentTemplates': ['name'],
- 'hostids': hostinterface['hostid'],
- 'selectInventory': host_inventory,
- 'selectTags': 'extend',
- 'selectMacros': 'extend'
+ "output": "extend",
+ "selectGroups": "extend",
+ "selectParentTemplates": ["name"],
+ "hostids": hostinterface["hostid"],
+ "selectInventory": host_inventory,
+ "selectTags": "extend",
+ "selectMacros": "extend"
})
- host[0]['hostinterfaces'] = hostinterface
+ host[0]["hostinterfaces"] = hostinterface
host_list.append(host[0])
return host_list
@@ -177,51 +176,46 @@ class Host(ZabbixBase):
unique_hosts = []
listed_hostnames = []
for zabbix_host in hosts:
- if zabbix_host['name'] in listed_hostnames:
+ if zabbix_host["name"] in listed_hostnames:
continue
unique_hosts.append(zabbix_host)
- listed_hostnames.append(zabbix_host['name'])
+ listed_hostnames.append(zabbix_host["name"])
return unique_hosts
def main():
argument_spec = zabbix_utils.zabbix_common_argument_spec()
argument_spec.update(dict(
- host_name=dict(type='str', default='', required=False),
- host_ip=dict(type='list', default=[], required=False),
- exact_match=dict(type='bool', required=False, default=False),
- remove_duplicate=dict(type='bool', required=False, default=True),
- host_inventory=dict(type='list', default=[], required=False)
+ host_name=dict(type="str", default="", required=False),
+ host_ip=dict(type="list", default=[], required=False, elements="str"),
+ exact_match=dict(type="bool", required=False, default=False),
+ remove_duplicate=dict(type="bool", required=False, default=True),
+ host_inventory=dict(type="list", default=[], required=False, elements="str")
))
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True
)
- if module._name == 'zabbix_host_facts':
- module.deprecate("The 'zabbix_host_facts' module has been renamed to 'zabbix_host_info'",
- collection_name="community.zabbix", version='2.0.0') # was 2.13
- zabbix_utils.require_creds_params(module)
-
- host_name = module.params['host_name']
- host_ips = module.params['host_ip']
- exact_match = module.params['exact_match']
- is_remove_duplicate = module.params['remove_duplicate']
- host_inventory = module.params['host_inventory']
+ host_name = module.params["host_name"]
+ host_ips = module.params["host_ip"]
+ exact_match = module.params["exact_match"]
+ is_remove_duplicate = module.params["remove_duplicate"]
+ host_inventory = module.params["host_inventory"]
if not host_inventory:
- host_inventory = 'extend'
+ host_inventory = "extend"
host = Host(module)
- if host_name:
+ if host_name != "" or (host_name == "" and len(host_ips) == 0):
hosts = host.get_hosts_by_host_name(host_name, exact_match, host_inventory)
if is_remove_duplicate:
hosts = host.delete_duplicate_hosts(hosts)
extended_hosts = []
for zabbix_host in hosts:
- zabbix_host['hostinterfaces'] = host._zapi.hostinterface.get({
- 'output': 'extend', 'hostids': zabbix_host['hostid']
+ zabbix_host["hostinterfaces"] = host._zapi.hostinterface.get({
+ "output": "extend", "hostids": zabbix_host["hostid"]
})
extended_hosts.append(zabbix_host)
module.exit_json(ok=True, hosts=extended_hosts)
@@ -235,5 +229,5 @@ def main():
module.exit_json(ok=False, hosts=[], result="No Host present")
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_hostmacro.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_hostmacro.py
index 1fed5d889..802a00559 100644
--- a/ansible_collections/community/zabbix/plugins/modules/zabbix_hostmacro.py
+++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_hostmacro.py
@@ -8,7 +8,7 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: zabbix_hostmacro
short_description: Create/update/delete Zabbix host macros
@@ -18,7 +18,7 @@ author:
- "Cove (@cove)"
- Dean Hailin Song (!UNKNOWN)
requirements:
- - "python >= 2.6"
+ - "python >= 3.9"
options:
host_name:
description:
@@ -40,42 +40,45 @@ options:
description:
- Type of the host macro.
- text (default)
- - secret (Works only with Zabbix >= 5.0)
- - vault (Works only with Zabbix >= 5.2)
required: false
- choices: ['text', 'secret', 'vault']
- default: 'text'
+ choices: ["text", "secret", "vault"]
+ default: "text"
+ macro_description:
+ description:
+ - Text Description of the global macro.
+ type: str
+ default: ""
state:
description:
- State of the macro.
- On C(present), it will create if macro does not exist or update the macro if the associated data is different.
- On C(absent) will remove a macro if it exists.
required: false
- choices: ['present', 'absent']
+ choices: ["present", "absent"]
type: str
default: "present"
force:
description:
- Only updates an existing macro if set to C(yes).
- default: 'yes'
+ default: "yes"
type: bool
extends_documentation_fragment:
- community.zabbix.zabbix
-'''
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
# If you want to use Username and Password to be authenticated by Zabbix Server
- name: Set credentials to access Zabbix Server API
- set_fact:
+ ansible.builtin.set_fact:
ansible_user: Admin
ansible_httpapi_pass: zabbix
# If you want to use API token to be authenticated by Zabbix Server
# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens
- name: Set API token
- set_fact:
+ ansible.builtin.set_fact:
ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895
- name: Create new host macro or update an existing macro's value
@@ -86,12 +89,13 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_hostmacro:
host_name: ExampleHost
macro_name: EXAMPLE.MACRO
macro_value: Example value
+ macro_description: Example description
state: present
# Values with curly brackets need to be quoted otherwise they will be interpreted as a dictionary
@@ -103,12 +107,13 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_hostmacro:
host_name: ExampleHost
macro_name: "{$EXAMPLE.MACRO}"
macro_value: Example value
+ macro_description: Example description
state: present
- name: Delete existing host macro
@@ -119,19 +124,18 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_hostmacro:
host_name: ExampleHost
macro_name: "{$EXAMPLE.MACRO}"
state: absent
-'''
+"""
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase
-from ansible.module_utils.compat.version import LooseVersion
import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils
@@ -140,11 +144,11 @@ class HostMacro(ZabbixBase):
# get host id by host name
def get_host_id(self, host_name):
try:
- host_list = self._zapi.host.get({'output': 'extend', 'filter': {'host': host_name}})
+ host_list = self._zapi.host.get({"output": "extend", "filter": {"host": host_name}})
if len(host_list) < 1:
self._module.fail_json(msg="Host not found: %s" % host_name)
else:
- host_id = host_list[0]['hostid']
+ host_id = host_list[0]["hostid"]
return host_id
except Exception as e:
self._module.fail_json(msg="Failed to get the host %s id: %s." % (host_name, e))
@@ -153,7 +157,7 @@ class HostMacro(ZabbixBase):
def get_host_macro(self, macro_name, host_id):
try:
host_macro_list = self._zapi.usermacro.get(
- {"output": "extend", "selectSteps": "extend", 'hostids': [host_id], 'filter': {'macro': macro_name}})
+ {"output": "extend", "selectSteps": "extend", "hostids": [host_id], "filter": {"macro": macro_name}})
if len(host_macro_list) > 0:
return host_macro_list[0]
return None
@@ -161,43 +165,34 @@ class HostMacro(ZabbixBase):
self._module.fail_json(msg="Failed to get host macro %s: %s" % (macro_name, e))
# create host macro
- def create_host_macro(self, macro_name, macro_value, macro_type, host_id):
+ def create_host_macro(self, macro_name, macro_value, macro_type, macro_description, host_id):
try:
if self._module.check_mode:
self._module.exit_json(changed=True)
- if LooseVersion(self._zbx_api_version) >= LooseVersion('5.0'):
- self._zapi.usermacro.create({'hostid': host_id, 'macro': macro_name, 'value': macro_value, 'type': macro_type})
- else:
- self._zapi.usermacro.create({'hostid': host_id, 'macro': macro_name, 'value': macro_value})
+ self._zapi.usermacro.create({"hostid": host_id, "macro": macro_name, "value": macro_value, "type": macro_type, "description": macro_description})
self._module.exit_json(changed=True, result="Successfully added host macro %s" % macro_name)
except Exception as e:
self._module.fail_json(msg="Failed to create host macro %s: %s" % (macro_name, e))
# update host macro
- def update_host_macro(self, host_macro_obj, macro_name, macro_value, macro_type):
- host_macro_id = host_macro_obj['hostmacroid']
- if host_macro_obj['macro'] == macro_name:
- if LooseVersion(self._zbx_api_version) >= LooseVersion('5.0'):
- # no change only when macro type == 0. when type = 1 or 2 zabbix will not output value of it.
- if host_macro_obj['type'] == '0' and macro_type == '0' and host_macro_obj['value'] == macro_value:
- self._module.exit_json(changed=False, result="Host macro %s already up to date" % macro_name)
- else:
- if host_macro_obj['value'] == macro_value:
- self._module.exit_json(changed=False, result="Host macro %s already up to date" % macro_name)
+ def update_host_macro(self, host_macro_obj, macro_name, macro_value, macro_type, macro_description):
+ host_macro_id = host_macro_obj["hostmacroid"]
+ if host_macro_obj["macro"] == macro_name:
+ # no change only when macro type == 0. when type = 1 or 2 zabbix will not output value of it.
+ if (host_macro_obj["type"] == "0" and macro_type == "0" and host_macro_obj["value"] == macro_value
+ and host_macro_obj["description"] == macro_description):
+ self._module.exit_json(changed=False, result="Host macro %s already up to date" % macro_name)
try:
if self._module.check_mode:
self._module.exit_json(changed=True)
- if LooseVersion(self._zbx_api_version) >= LooseVersion('5.0'):
- self._zapi.usermacro.update({'hostmacroid': host_macro_id, 'value': macro_value, 'type': macro_type})
- else:
- self._zapi.usermacro.update({'hostmacroid': host_macro_id, 'value': macro_value})
+ self._zapi.usermacro.update({"hostmacroid": host_macro_id, "value": macro_value, "type": macro_type, "description": macro_description})
self._module.exit_json(changed=True, result="Successfully updated host macro %s" % macro_name)
except Exception as e:
self._module.fail_json(msg="Failed to update host macro %s: %s" % (macro_name, e))
# delete host macro
def delete_host_macro(self, host_macro_obj, macro_name):
- host_macro_id = host_macro_obj['hostmacroid']
+ host_macro_id = host_macro_obj["hostmacroid"]
try:
if self._module.check_mode:
self._module.exit_json(changed=True)
@@ -209,16 +204,16 @@ class HostMacro(ZabbixBase):
def normalize_macro_name(macro_name):
# Zabbix handles macro names in upper case characters
- if ':' in macro_name:
- macro_name = ':'.join([macro_name.split(':')[0].upper(), ':'.join(macro_name.split(':')[1:])])
+ if ":" in macro_name:
+ macro_name = ":".join([macro_name.split(":")[0].upper(), ":".join(macro_name.split(":")[1:])])
else:
macro_name = macro_name.upper()
# Valid format for macro is {$MACRO}
- if not macro_name.startswith('{$'):
- macro_name = '{$' + macro_name
- if not macro_name.endswith('}'):
- macro_name = macro_name + '}'
+ if not macro_name.startswith("{$"):
+ macro_name = "{$" + macro_name
+ if not macro_name.endswith("}"):
+ macro_name = macro_name + "}"
return macro_name
@@ -226,38 +221,34 @@ def normalize_macro_name(macro_name):
def main():
argument_spec = zabbix_utils.zabbix_common_argument_spec()
argument_spec.update(dict(
- host_name=dict(type='str', required=True),
- macro_name=dict(type='str', required=True),
- macro_value=dict(type='str', required=False),
- macro_type=dict(type='str', default='text', choices=['text', 'secret', 'vault']),
- state=dict(type='str', default='present', choices=['present', 'absent']),
- force=dict(type='bool', default=True)
+ host_name=dict(type="str", required=True),
+ macro_name=dict(type="str", required=True),
+ macro_value=dict(type="str", required=False),
+ macro_type=dict(type="str", default="text", choices=["text", "secret", "vault"]),
+ macro_description=dict(type="str", default=""),
+ state=dict(type="str", default="present", choices=["present", "absent"]),
+ force=dict(type="bool", default=True)
))
module = AnsibleModule(
argument_spec=argument_spec,
required_if=[
- ['state', 'present', ['macro_value']]
+ ["state", "present", ["macro_value"]]
],
supports_check_mode=True
)
- zabbix_utils.require_creds_params(module)
-
- for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']:
- if p in module.params and not module.params[p] is None:
- module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p)
-
- host_name = module.params['host_name']
- macro_name = normalize_macro_name(module.params['macro_name'])
- macro_value = module.params['macro_value']
- state = module.params['state']
- force = module.params['force']
- if module.params['macro_type'] == 'secret':
- macro_type = '1'
- elif module.params['macro_type'] == 'vault':
- macro_type = '2'
+ host_name = module.params["host_name"]
+ macro_name = normalize_macro_name(module.params["macro_name"])
+ macro_value = module.params["macro_value"]
+ macro_description = module.params["macro_description"]
+ state = module.params["state"]
+ force = module.params["force"]
+ if module.params["macro_type"] == "secret":
+ macro_type = "1"
+ elif module.params["macro_type"] == "vault":
+ macro_type = "2"
else:
- macro_type = '0'
+ macro_type = "0"
host_macro_class_obj = HostMacro(module)
@@ -265,7 +256,7 @@ def main():
host_id = host_macro_class_obj.get_host_id(host_name)
host_macro_obj = host_macro_class_obj.get_host_macro(macro_name, host_id)
- if state == 'absent':
+ if state == "absent":
if not host_macro_obj:
module.exit_json(changed=False, msg="Host Macro %s does not exist" % macro_name)
else:
@@ -274,13 +265,13 @@ def main():
else:
if not host_macro_obj:
# create host macro
- host_macro_class_obj.create_host_macro(macro_name, macro_value, macro_type, host_id)
+ host_macro_class_obj.create_host_macro(macro_name, macro_value, macro_type, macro_description, host_id)
elif force:
# update host macro
- host_macro_class_obj.update_host_macro(host_macro_obj, macro_name, macro_value, macro_type)
+ host_macro_class_obj.update_host_macro(host_macro_obj, macro_name, macro_value, macro_type, macro_description)
else:
module.exit_json(changed=False, result="Host macro %s already exists and force is set to no" % macro_name)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_housekeeping.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_housekeeping.py
index 901ff965a..3f6e5d733 100644
--- a/ansible_collections/community/zabbix/plugins/modules/zabbix_housekeeping.py
+++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_housekeeping.py
@@ -8,7 +8,7 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type
-DOCUMENTATION = '''
+DOCUMENTATION = """
---
module: zabbix_housekeeping
@@ -21,7 +21,7 @@ author:
- ONODERA Masaru(@masa-orca)
requirements:
- - "python >= 2.6"
+ - "python >= 3.9"
version_added: 1.6.0
@@ -39,7 +39,6 @@ options:
hk_events_service:
description:
- Storage period of service data (e.g. 365d).
- - This parameter is available since Zabbix 6.0.
required: false
type: str
hk_events_internal:
@@ -128,24 +127,21 @@ options:
required: false
type: str
-notes:
- - Zabbix 5.2 version and higher are supported.
-
extends_documentation_fragment:
- community.zabbix.zabbix
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = """
# If you want to use Username and Password to be authenticated by Zabbix Server
- name: Set credentials to access Zabbix Server API
- set_fact:
+ ansible.builtin.set_fact:
ansible_user: Admin
ansible_httpapi_pass: zabbix
# If you want to use API token to be authenticated by Zabbix Server
# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens
- name: Set API token
- set_fact:
+ ansible.builtin.set_fact:
ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895
- name: Update housekeeping all parameter
@@ -156,7 +152,7 @@ EXAMPLES = '''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_housekeeping:
login_user: Admin
@@ -181,35 +177,29 @@ EXAMPLES = '''
hk_trends: 365d
compression_status: off
compress_older: 7d
-'''
+"""
-RETURN = '''
+RETURN = """
msg:
description: The result of the operation
returned: success
type: str
- sample: 'Successfully update housekeeping setting'
-'''
+ sample: "Successfully update housekeeping setting"
+"""
import re
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase
-from ansible.module_utils.compat.version import LooseVersion
import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils
class Housekeeping(ZabbixBase):
- def __init__(self, module, zbx=None, zapi_wrapper=None):
- super(Housekeeping, self).__init__(module, zbx, zapi_wrapper)
- if LooseVersion(self._zbx_api_version) < LooseVersion('5.2.0'):
- module.fail_json(msg="This module doesn't support Zabbix versions lower than 5.2.0")
-
# get housekeeping setting
def get_housekeeping(self):
try:
- return self._zapi.housekeeping.get({'output': 'extend'})
+ return self._zapi.housekeeping.get({"output": "extend"})
except Exception as e:
self._module.fail_json(msg="Failed to get housekeeping setting: %s" % e)
@@ -247,78 +237,75 @@ class Housekeeping(ZabbixBase):
params = {}
if isinstance(hk_events_mode, bool):
- params['hk_events_mode'] = str(int(hk_events_mode))
+ params["hk_events_mode"] = str(int(hk_events_mode))
if hk_events_trigger:
- self.check_time_parameter('hk_events_trigger', hk_events_trigger)
- params['hk_events_trigger'] = hk_events_trigger
+ self.check_time_parameter("hk_events_trigger", hk_events_trigger)
+ params["hk_events_trigger"] = hk_events_trigger
if hk_events_service:
- if LooseVersion(self._zbx_api_version) < LooseVersion('6.0'):
- self._module.warn('hk_events_service is ignored with <= Zabbix 5.4.')
- else:
- self.check_time_parameter('hk_events_service', hk_events_service)
- params['hk_events_service'] = hk_events_service
+ self.check_time_parameter("hk_events_service", hk_events_service)
+ params["hk_events_service"] = hk_events_service
if hk_events_internal:
- self.check_time_parameter('hk_events_internal', hk_events_internal)
- params['hk_events_internal'] = hk_events_internal
+ self.check_time_parameter("hk_events_internal", hk_events_internal)
+ params["hk_events_internal"] = hk_events_internal
if hk_events_discovery:
- self.check_time_parameter('hk_events_discovery', hk_events_discovery)
- params['hk_events_discovery'] = hk_events_discovery
+ self.check_time_parameter("hk_events_discovery", hk_events_discovery)
+ params["hk_events_discovery"] = hk_events_discovery
if hk_events_autoreg:
- self.check_time_parameter('hk_events_autoreg', hk_events_autoreg)
- params['hk_events_autoreg'] = hk_events_autoreg
+ self.check_time_parameter("hk_events_autoreg", hk_events_autoreg)
+ params["hk_events_autoreg"] = hk_events_autoreg
if isinstance(hk_services_mode, bool):
- params['hk_services_mode'] = str(int(hk_services_mode))
+ params["hk_services_mode"] = str(int(hk_services_mode))
if hk_services:
- self.check_time_parameter('hk_services', hk_services)
- params['hk_services'] = hk_services
+ self.check_time_parameter("hk_services", hk_services)
+ params["hk_services"] = hk_services
if isinstance(hk_audit_mode, bool):
- params['hk_audit_mode'] = str(int(hk_audit_mode))
+ params["hk_audit_mode"] = str(int(hk_audit_mode))
if hk_audit:
- self.check_time_parameter('hk_audit', hk_audit)
- params['hk_audit'] = hk_audit
+ self.check_time_parameter("hk_audit", hk_audit)
+ params["hk_audit"] = hk_audit
if isinstance(hk_sessions_mode, bool):
- params['hk_sessions_mode'] = str(int(hk_sessions_mode))
+ params["hk_sessions_mode"] = str(int(hk_sessions_mode))
if hk_sessions:
- self.check_time_parameter('hk_sessions', hk_sessions)
- params['hk_sessions'] = hk_sessions
+ self.check_time_parameter("hk_sessions", hk_sessions)
+ params["hk_sessions"] = hk_sessions
if isinstance(hk_history_mode, bool):
- params['hk_history_mode'] = str(int(hk_history_mode))
+ params["hk_history_mode"] = str(int(hk_history_mode))
if isinstance(hk_history_global, bool):
- params['hk_history_global'] = str(int(hk_history_global))
+ params["hk_history_global"] = str(int(hk_history_global))
if hk_history:
- self.check_time_parameter('hk_history', hk_history)
- params['hk_history'] = hk_history
+ self.check_time_parameter("hk_history", hk_history)
+ params["hk_history"] = hk_history
if isinstance(hk_trends_mode, bool):
- params['hk_trends_mode'] = str(int(hk_trends_mode))
+ params["hk_trends_mode"] = str(int(hk_trends_mode))
if isinstance(hk_trends_global, bool):
- params['hk_trends_global'] = str(int(hk_trends_global))
+ params["hk_trends_global"] = str(int(hk_trends_global))
if hk_trends:
- self.check_time_parameter('hk_trends', hk_trends)
- params['hk_trends'] = hk_trends
+ self.check_time_parameter("hk_trends", hk_trends)
+ params["hk_trends"] = hk_trends
if isinstance(compression_status, bool):
- params['compression_status'] = str(int(compression_status))
+ params["compression_status"] = str(int(compression_status))
if compress_older:
- self.check_time_parameter('compress_older', compress_older)
- params['compress_older'] = compress_older
+ self.check_time_parameter("compress_older", compress_older)
+ params["compress_older"] = compress_older
future_housekeeping = current_housekeeping.copy()
future_housekeeping.update(params)
@@ -338,58 +325,52 @@ class Housekeeping(ZabbixBase):
def main():
argument_spec = zabbix_utils.zabbix_common_argument_spec()
argument_spec.update(dict(
- hk_events_mode=dict(type='bool'),
- hk_events_trigger=dict(type='str'),
- hk_events_service=dict(type='str'),
- hk_events_internal=dict(type='str'),
- hk_events_discovery=dict(type='str'),
- hk_events_autoreg=dict(type='str'),
- hk_services_mode=dict(type='bool'),
- hk_services=dict(type='str'),
- hk_audit_mode=dict(type='bool'),
- hk_audit=dict(type='str'),
- hk_sessions_mode=dict(type='bool'),
- hk_sessions=dict(type='str'),
- hk_history_mode=dict(type='bool'),
- hk_history_global=dict(type='bool'),
- hk_history=dict(type='str'),
- hk_trends_mode=dict(type='bool'),
- hk_trends_global=dict(type='bool'),
- hk_trends=dict(type='str'),
- compression_status=dict(type='bool'),
- compress_older=dict(type='str')
+ hk_events_mode=dict(type="bool"),
+ hk_events_trigger=dict(type="str"),
+ hk_events_service=dict(type="str"),
+ hk_events_internal=dict(type="str"),
+ hk_events_discovery=dict(type="str"),
+ hk_events_autoreg=dict(type="str"),
+ hk_services_mode=dict(type="bool"),
+ hk_services=dict(type="str"),
+ hk_audit_mode=dict(type="bool"),
+ hk_audit=dict(type="str"),
+ hk_sessions_mode=dict(type="bool"),
+ hk_sessions=dict(type="str"),
+ hk_history_mode=dict(type="bool"),
+ hk_history_global=dict(type="bool"),
+ hk_history=dict(type="str"),
+ hk_trends_mode=dict(type="bool"),
+ hk_trends_global=dict(type="bool"),
+ hk_trends=dict(type="str"),
+ compression_status=dict(type="bool"),
+ compress_older=dict(type="str")
))
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True
)
- zabbix_utils.require_creds_params(module)
-
- for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']:
- if p in module.params and not module.params[p] is None:
- module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p)
-
- hk_events_mode = module.params['hk_events_mode']
- hk_events_trigger = module.params['hk_events_trigger']
- hk_events_service = module.params['hk_events_service']
- hk_events_internal = module.params['hk_events_internal']
- hk_events_discovery = module.params['hk_events_discovery']
- hk_events_autoreg = module.params['hk_events_autoreg']
- hk_services_mode = module.params['hk_services_mode']
- hk_services = module.params['hk_services']
- hk_audit_mode = module.params['hk_audit_mode']
- hk_audit = module.params['hk_audit']
- hk_sessions_mode = module.params['hk_sessions_mode']
- hk_sessions = module.params['hk_sessions']
- hk_history_mode = module.params['hk_history_mode']
- hk_history_global = module.params['hk_history_global']
- hk_history = module.params['hk_history']
- hk_trends_mode = module.params['hk_trends_mode']
- hk_trends_global = module.params['hk_trends_global']
- hk_trends = module.params['hk_trends']
- compression_status = module.params['compression_status']
- compress_older = module.params['compress_older']
+ hk_events_mode = module.params["hk_events_mode"]
+ hk_events_trigger = module.params["hk_events_trigger"]
+ hk_events_service = module.params["hk_events_service"]
+ hk_events_internal = module.params["hk_events_internal"]
+ hk_events_discovery = module.params["hk_events_discovery"]
+ hk_events_autoreg = module.params["hk_events_autoreg"]
+ hk_services_mode = module.params["hk_services_mode"]
+ hk_services = module.params["hk_services"]
+ hk_audit_mode = module.params["hk_audit_mode"]
+ hk_audit = module.params["hk_audit"]
+ hk_sessions_mode = module.params["hk_sessions_mode"]
+ hk_sessions = module.params["hk_sessions"]
+ hk_history_mode = module.params["hk_history_mode"]
+ hk_history_global = module.params["hk_history_global"]
+ hk_history = module.params["hk_history"]
+ hk_trends_mode = module.params["hk_trends_mode"]
+ hk_trends_global = module.params["hk_trends_global"]
+ hk_trends = module.params["hk_trends"]
+ compression_status = module.params["compression_status"]
+ compress_older = module.params["compress_older"]
housekeeping = Housekeeping(module)
@@ -419,5 +400,5 @@ def main():
)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_maintenance.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_maintenance.py
index 139db5057..a2c635eb0 100644
--- a/ansible_collections/community/zabbix/plugins/modules/zabbix_maintenance.py
+++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_maintenance.py
@@ -8,7 +8,7 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: zabbix_maintenance
short_description: Create Zabbix maintenance windows
@@ -16,7 +16,7 @@ description:
- This module will let you create Zabbix maintenance windows.
author: "Alexander Bulimov (@abulimov)"
requirements:
- - "python >= 2.6"
+ - "python >= 3.9"
options:
state:
description:
@@ -57,14 +57,13 @@ options:
description:
- Type of maintenance. With data collection, or without.
type: bool
- default: 'yes'
+ default: "yes"
visible_name:
description:
- Type of zabbix host name to use for identifying hosts to include in the maintenance.
- I(visible_name=yes) to search by visible name, I(visible_name=no) to search by technical name.
type: bool
- default: 'yes'
- version_added: '2.0.0'
+ default: "yes"
tags:
description:
- List of tags to assign to the hosts in maintenance.
@@ -81,7 +80,7 @@ options:
description:
- Value of the tag.
type: str
- default: ''
+ default: ""
operator:
description:
- Condition operator.
@@ -101,19 +100,19 @@ notes:
- Module creates maintenance window from now() to now() + minutes,
so if Zabbix server's time and host's time are not synchronized,
you will get strange results.
-'''
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
# If you want to use Username and Password to be authenticated by Zabbix Server
- name: Set credentials to access Zabbix Server API
- set_fact:
+ ansible.builtin.set_fact:
ansible_user: Admin
ansible_httpapi_pass: zabbix
# If you want to use API token to be authenticated by Zabbix Server
# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens
- name: Set API token
- set_fact:
+ ansible.builtin.set_fact:
ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895
- name: Create a named maintenance window for host www1 for 90 minutes
@@ -124,7 +123,7 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_maintenance:
name: Update of www1
@@ -140,7 +139,7 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_maintenance:
name: Update of www1
@@ -165,7 +164,7 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_maintenance:
name: update
@@ -183,12 +182,12 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_maintenance:
name: Test1
state: absent
-'''
+"""
import datetime
import time
@@ -197,81 +196,65 @@ from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase
import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils
-from ansible.module_utils.compat.version import LooseVersion
class MaintenanceModule(ZabbixBase):
def create_maintenance(self, group_ids, host_ids, start_time,
maintenance_type, period, name, desc, tags):
end_time = start_time + period
- try:
- parameters = {
- "groupids": group_ids,
- "hostids": host_ids,
- "name": name,
- "maintenance_type": maintenance_type,
- "active_since": str(start_time),
- "active_till": str(end_time),
- "description": desc,
- "timeperiods": [{
- "timeperiod_type": "0",
- "start_date": str(start_time),
- "period": str(period),
- }]
- }
- if tags is not None:
- parameters['tags'] = tags
- self._zapi.maintenance.create(parameters)
- # zabbix_api can call sys.exit() so we need to catch SystemExit here
- except (Exception, SystemExit) as e:
- return 1, None, str(e)
+ parameters = {
+ "groupids": group_ids,
+ "hostids": host_ids,
+ "name": name,
+ "maintenance_type": maintenance_type,
+ "active_since": str(start_time),
+ "active_till": str(end_time),
+ "description": desc,
+ "timeperiods": [{
+ "timeperiod_type": "0",
+ "start_date": str(start_time),
+ "period": str(period),
+ }]
+ }
+ if tags is not None:
+ parameters["tags"] = tags
+ self._zapi.maintenance.create(parameters)
return 0, None, None
def update_maintenance(self, maintenance_id, group_ids, host_ids,
start_time, maintenance_type, period, desc, tags):
end_time = start_time + period
- try:
- parameters = {
- "maintenanceid": maintenance_id,
- "groupids": group_ids,
- "hostids": host_ids,
- "maintenance_type": maintenance_type,
- "active_since": str(start_time),
- "active_till": str(end_time),
- "description": desc,
- "timeperiods": [{
- "timeperiod_type": "0",
- "start_date": str(start_time),
- "period": str(period),
- }]
- }
- if tags is not None:
- parameters['tags'] = tags
- else:
- if LooseVersion(self._zbx_api_version) < LooseVersion('6.0'):
- parameters['tags'] = []
- self._zapi.maintenance.update(parameters)
- # zabbix_api can call sys.exit() so we need to catch SystemExit here
- except (Exception, SystemExit) as e:
- return 1, None, str(e)
+ parameters = {
+ "maintenanceid": maintenance_id,
+ "groupids": group_ids,
+ "hostids": host_ids,
+ "maintenance_type": maintenance_type,
+ "active_since": str(start_time),
+ "active_till": str(end_time),
+ "description": desc,
+ "timeperiods": [{
+ "timeperiod_type": "0",
+ "start_date": str(start_time),
+ "period": str(period),
+ }]
+ }
+ if tags is not None:
+ parameters["tags"] = tags
+ self._zapi.maintenance.update(parameters)
return 0, None, None
def get_maintenance(self, name):
- try:
- maintenances = self._zapi.maintenance.get(
+ maintenances = self._zapi.maintenance.get(
+ {
+ "filter":
{
- "filter":
- {
- "name": name,
- },
- "selectGroups": "extend",
- "selectHosts": "extend",
- "selectTags": "extend"
- }
- )
- # zabbix_api can call sys.exit() so we need to catch SystemExit here
- except (Exception, SystemExit) as e:
- return 1, None, str(e)
+ "name": name,
+ },
+ "selectGroups": "extend",
+ "selectHosts": "extend",
+ "selectTags": "extend"
+ }
+ )
for maintenance in maintenances:
maintenance["groupids"] = [group["groupid"] for group
@@ -283,29 +266,21 @@ class MaintenanceModule(ZabbixBase):
return 0, None, None
def delete_maintenance(self, maintenance_id):
- try:
- self._zapi.maintenance.delete([maintenance_id])
- # zabbix_api can call sys.exit() so we need to catch SystemExit here
- except (Exception, SystemExit) as e:
- return 1, None, str(e)
+ self._zapi.maintenance.delete([maintenance_id])
return 0, None, None
def get_group_ids(self, host_groups):
group_ids = []
for group in host_groups:
- try:
- result = self._zapi.hostgroup.get(
+ result = self._zapi.hostgroup.get(
+ {
+ "output": "extend",
+ "filter":
{
- "output": "extend",
- "filter":
- {
- "name": group
- }
+ "name": group
}
- )
- # zabbix_api can call sys.exit() so we need to catch SystemExit here
- except (Exception, SystemExit) as e:
- return 1, None, str(e)
+ }
+ )
if not result:
return 1, None, "Group id for group %s not found" % group
@@ -317,19 +292,15 @@ class MaintenanceModule(ZabbixBase):
def get_host_ids(self, host_names, zabbix_host):
host_ids = []
for host in host_names:
- try:
- result = self._zapi.host.get(
+ result = self._zapi.host.get(
+ {
+ "output": "extend",
+ "filter":
{
- "output": "extend",
- "filter":
- {
- zabbix_host: host
- }
+ zabbix_host: host
}
- )
- # zabbix_api can call sys.exit() so we need to catch SystemExit here
- except (Exception, SystemExit) as e:
- return 1, None, str(e)
+ }
+ )
if not result:
return 1, None, "Host id for host %s not found" % host
@@ -350,35 +321,35 @@ class MaintenanceModule(ZabbixBase):
return True
if str(int(start_time + period)) != maintenance["active_till"]:
return True
- if str(desc) != maintenance['description']:
+ if str(desc) != maintenance["description"]:
return True
- if tags is not None and 'tags' in maintenance:
- if sorted(tags, key=lambda k: k['tag']) != sorted(maintenance['tags'], key=lambda k: k['tag']):
+ if tags is not None and "tags" in maintenance:
+ if sorted(tags, key=lambda k: k["tag"]) != sorted(maintenance["tags"], key=lambda k: k["tag"]):
return True
def main():
argument_spec = zabbix_utils.zabbix_common_argument_spec()
argument_spec.update(dict(
- state=dict(type='str', required=False, default='present',
- choices=['present', 'absent']),
- host_names=dict(type='list', required=False,
- default=None, aliases=['host_name']),
- minutes=dict(type='int', required=False, default=10),
- host_groups=dict(type='list', required=False,
- default=None, aliases=['host_group']),
- name=dict(type='str', required=True),
- desc=dict(type='str', required=False, default="Created by Ansible"),
- collect_data=dict(type='bool', required=False, default=True),
- visible_name=dict(type='bool', required=False, default=True),
+ state=dict(type="str", required=False, default="present",
+ choices=["present", "absent"]),
+ host_names=dict(type="list", required=False,
+ default=None, aliases=["host_name"], elements="str"),
+ minutes=dict(type="int", required=False, default=10),
+ host_groups=dict(type="list", required=False,
+ default=None, aliases=["host_group"], elements="str"),
+ name=dict(type="str", required=True),
+ desc=dict(type="str", required=False, default="Created by Ansible"),
+ collect_data=dict(type="bool", required=False, default=True),
+ visible_name=dict(type="bool", required=False, default=True),
tags=dict(
- type='list',
- elements='dict',
+ type="list",
+ elements="dict",
required=False,
options=dict(
- tag=dict(type='str', required=True),
- operator=dict(type='int', default=2),
- value=dict(type='str', default='')
+ tag=dict(type="str", required=True),
+ operator=dict(type="int", default=2),
+ value=dict(type="str", default="")
)
)
))
@@ -387,23 +358,17 @@ def main():
supports_check_mode=True
)
- zabbix_utils.require_creds_params(module)
-
- for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']:
- if p in module.params and not module.params[p] is None:
- module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p)
-
maint = MaintenanceModule(module)
- host_names = module.params['host_names']
- host_groups = module.params['host_groups']
- state = module.params['state']
- minutes = module.params['minutes']
- name = module.params['name']
- desc = module.params['desc']
- collect_data = module.params['collect_data']
- visible_name = module.params['visible_name']
- tags = module.params['tags']
+ host_names = module.params["host_names"]
+ host_groups = module.params["host_groups"]
+ state = module.params["state"]
+ minutes = module.params["minutes"]
+ name = module.params["name"]
+ desc = module.params["desc"]
+ collect_data = module.params["collect_data"]
+ visible_name = module.params["visible_name"]
+ tags = module.params["tags"]
if collect_data:
maintenance_type = 0
@@ -494,5 +459,5 @@ def main():
module.exit_json(changed=changed)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_map.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_map.py
index 175b96df6..a0f3cc655 100644
--- a/ansible_collections/community/zabbix/plugins/modules/zabbix_map.py
+++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_map.py
@@ -7,7 +7,7 @@
from __future__ import absolute_import, division, print_function
__metaclass__ = type
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: zabbix_map
author:
@@ -37,7 +37,7 @@ description:
C(zbx_trigger_color) contains indicator color specified either as CSS3 name or as a hexadecimal code starting with C(#).
C(zbx_trigger_draw_style) contains indicator draw style. Possible values are the same as for C(zbx_draw_style)."
requirements:
- - "python >= 2.6"
+ - "python >= 3.9"
- pydotplus
- webcolors
- Pillow
@@ -61,7 +61,7 @@ options:
- On C(present), it will create if map does not exist or update the map if the associated data is different.
- On C(absent) will remove the map if it exists.
required: false
- choices: ['present', 'absent']
+ choices: ["present", "absent"]
default: "present"
type: str
width:
@@ -98,7 +98,7 @@ options:
description:
- Map element label type.
required: false
- choices: ['label', 'ip', 'name', 'status', 'nothing', 'custom']
+ choices: ["label", "ip", "name", "status", "nothing", "custom"]
default: "name"
type: str
default_image:
@@ -111,21 +111,21 @@ options:
extends_documentation_fragment:
- community.zabbix.zabbix
-'''
+"""
-RETURN = r''' # '''
+RETURN = r""" # """
-EXAMPLES = r'''
+EXAMPLES = r"""
# If you want to use Username and Password to be authenticated by Zabbix Server
- name: Set credentials to access Zabbix Server API
- set_fact:
+ ansible.builtin.set_fact:
ansible_user: Admin
ansible_httpapi_pass: zabbix
# If you want to use API token to be authenticated by Zabbix Server
# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens
- name: Set API token
- set_fact:
+ ansible.builtin.set_fact:
ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895
###
@@ -139,7 +139,7 @@ EXAMPLES = r'''
###
### Each inventory host is present in Zabbix with a matching name.
###
-### Contents of 'map.j2':
+### Contents of "map.j2":
# digraph G {
# graph [layout=dot splines=false overlap=scale]
# INTERNET [zbx_url="Google:https://google.com" zbx_image="Cloud_(96)"]
@@ -168,7 +168,7 @@ EXAMPLES = r'''
# }
# }
###
-### Create Zabbix map "Demo Map" made of template 'map.j2'
+### Create Zabbix map "Demo Map" made of template "map.j2"
- name: Create Zabbix map
# set task level variables as we change ansible_connection plugin here
vars:
@@ -177,7 +177,7 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_map:
name: Demo map
@@ -189,7 +189,7 @@ EXAMPLES = r'''
label_type: label
delegate_to: localhost
run_once: yes
-'''
+"""
import base64
@@ -201,7 +201,6 @@ from operator import itemgetter
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase
-from ansible.module_utils.compat.version import LooseVersion
import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils
@@ -234,17 +233,17 @@ except ImportError:
class Map(ZabbixBase):
def __init__(self, module, zbx=None, zapi_wrapper=None):
super(Map, self).__init__(module, zbx, zapi_wrapper)
- self.map_name = module.params['name']
- self.dot_data = module.params['data']
- self.width = module.params['width']
- self.height = module.params['height']
- self.state = module.params['state']
- self.default_image = module.params['default_image']
+ self.map_name = module.params["name"]
+ self.dot_data = module.params["data"]
+ self.width = module.params["width"]
+ self.height = module.params["height"]
+ self.state = module.params["state"]
+ self.default_image = module.params["default_image"]
self.map_id = self._get_sysmap_id(self.map_name)
- self.margin = module.params['margin']
- self.expand_problem = module.params['expand_problem']
- self.highlight = module.params['highlight']
- self.label_type = module.params['label_type']
+ self.margin = module.params["margin"]
+ self.expand_problem = module.params["expand_problem"]
+ self.highlight = module.params["highlight"]
+ self.label_type = module.params["label_type"]
self.selements_sort_keys = self._get_selements_sort_keys()
def _build_graph(self):
@@ -265,25 +264,25 @@ class Map(ZabbixBase):
edges = self._get_graph_edges(graph)
icon_ids = self._get_icon_ids()
map_config = {
- 'name': self.map_name,
- 'label_type': self._get_label_type_id(self.label_type),
- 'expandproblem': int(self.expand_problem),
- 'highlight': int(self.highlight),
- 'width': self.width,
- 'height': self.height,
- 'selements': self._get_selements(graph, nodes, icon_ids),
- 'links': self._get_links(nodes, edges),
+ "name": self.map_name,
+ "label_type": self._get_label_type_id(self.label_type),
+ "expandproblem": int(self.expand_problem),
+ "highlight": int(self.highlight),
+ "width": self.width,
+ "height": self.height,
+ "selements": self._get_selements(graph, nodes, icon_ids),
+ "links": self._get_links(nodes, edges),
}
return map_config
def _get_label_type_id(self, label_type):
label_type_ids = {
- 'label': 0,
- 'ip': 1,
- 'name': 2,
- 'status': 3,
- 'nothing': 4,
- 'custom': 5,
+ "label": 0,
+ "ip": 1,
+ "name": 2,
+ "status": 3,
+ "nothing": 4,
+ "custom": 5,
}
try:
label_type_id = label_type_ids[label_type]
@@ -294,82 +293,73 @@ class Map(ZabbixBase):
def _get_images_info(self, data, icon_ids):
images = [
{
- 'dot_tag': 'zbx_image',
- 'zbx_property': 'iconid_off',
- 'mandatory': True
+ "dot_tag": "zbx_image",
+ "zbx_property": "iconid_off",
+ "mandatory": True
},
{
- 'dot_tag': 'zbx_image_disabled',
- 'zbx_property': 'iconid_disabled',
- 'mandatory': False
+ "dot_tag": "zbx_image_disabled",
+ "zbx_property": "iconid_disabled",
+ "mandatory": False
},
{
- 'dot_tag': 'zbx_image_maintenance',
- 'zbx_property': 'iconid_maintenance',
- 'mandatory': False
+ "dot_tag": "zbx_image_maintenance",
+ "zbx_property": "iconid_maintenance",
+ "mandatory": False
},
{
- 'dot_tag': 'zbx_image_problem',
- 'zbx_property': 'iconid_on',
- 'mandatory': False
+ "dot_tag": "zbx_image_problem",
+ "zbx_property": "iconid_on",
+ "mandatory": False
}
]
images_info = {}
default_image = self.default_image if self.default_image else sorted(icon_ids.items())[0][0]
for image in images:
- image_name = data.get(image['dot_tag'], None)
+ image_name = data.get(image["dot_tag"], None)
if not image_name:
- if image['mandatory']:
+ if image["mandatory"]:
image_name = default_image
else:
continue
image_name = remove_quotes(image_name)
if image_name in icon_ids:
- images_info[image['zbx_property']] = icon_ids[image_name]
- if not image['mandatory']:
- images_info['use_iconmap'] = 0
+ images_info[image["zbx_property"]] = icon_ids[image_name]
+ if not image["mandatory"]:
+ images_info["use_iconmap"] = 0
else:
self._module.fail_json(msg="Failed to find id for image '%s'" % image_name)
return images_info
def _get_element_type(self, data):
types = {
- 'host': 0,
- 'sysmap': 1,
- 'trigger': 2,
- 'group': 3,
- 'image': 4
+ "host": 0,
+ "sysmap": 1,
+ "trigger": 2,
+ "group": 3,
+ "image": 4
}
element_type = {
- 'elementtype': types['image'],
+ "elementtype": types["image"],
}
- if LooseVersion(self._zbx_api_version) < LooseVersion('3.4'):
- element_type.update({
- 'elementid': "0",
- })
for type_name, type_id in sorted(types.items()):
- field_name = 'zbx_' + type_name
+ field_name = "zbx_" + type_name
if field_name in data:
- method_name = '_get_' + type_name + '_id'
+ method_name = "_get_" + type_name + "_id"
element_name = remove_quotes(data[field_name])
get_element_id = getattr(self, method_name, None)
if get_element_id:
elementid = get_element_id(element_name)
if elementid and int(elementid) > 0:
element_type.update({
- 'elementtype': type_id,
- 'label': element_name
+ "elementtype": type_id,
+ "label": element_name
+ })
+ element_type.update({
+ "elements": [{
+ type_name + "id": elementid,
+ }],
})
- if LooseVersion(self._zbx_api_version) < LooseVersion('3.4'):
- element_type.update({
- 'elementid': elementid,
- })
- else:
- element_type.update({
- 'elements': [{
- type_name + 'id': elementid,
- }],
- })
break
else:
self._module.fail_json(msg="Failed to find id for %s '%s'" % (type_name, element_name))
@@ -382,30 +372,30 @@ class Map(ZabbixBase):
scales = self._get_scales(graph)
for selementid, (node, data) in enumerate(nodes.items(), start=1):
selement = {
- 'selementid': selementid
+ "selementid": selementid
}
- data['selementid'] = selementid
+ data["selementid"] = selementid
images_info = self._get_images_info(data, icon_ids)
selement.update(images_info)
- image_id = images_info['iconid_off']
+ image_id = images_info["iconid_off"]
if image_id not in icon_sizes:
icon_sizes[image_id] = self._get_icon_size(image_id)
- pos = self._convert_coordinates(data['pos'], scales, icon_sizes[image_id])
+ pos = self._convert_coordinates(data["pos"], scales, icon_sizes[image_id])
selement.update(pos)
- selement['label'] = remove_quotes(node)
+ selement["label"] = remove_quotes(node)
element_type = self._get_element_type(data)
selement.update(element_type)
label = self._get_label(data)
if label:
- selement['label'] = label
+ selement["label"] = label
urls = self._get_urls(data)
if urls:
- selement['urls'] = urls
+ selement["urls"] = urls
selements.append(selement)
return selements
@@ -413,35 +403,35 @@ class Map(ZabbixBase):
def _get_links(self, nodes, edges):
links = {}
for edge in edges:
- link_id = tuple(sorted(edge.obj_dict['points']))
+ link_id = tuple(sorted(edge.obj_dict["points"]))
node1, node2 = link_id
- data = edge.obj_dict['attributes']
+ data = edge.obj_dict["attributes"]
- if "style" in data and data['style'] == "invis":
+ if "style" in data and data["style"] == "invis":
continue
if link_id not in links:
links[link_id] = {
- 'selementid1': min(nodes[node1]['selementid'], nodes[node2]['selementid']),
- 'selementid2': max(nodes[node1]['selementid'], nodes[node2]['selementid']),
+ "selementid1": min(nodes[node1]["selementid"], nodes[node2]["selementid"]),
+ "selementid2": max(nodes[node1]["selementid"], nodes[node2]["selementid"]),
}
link = links[link_id]
if "color" not in link:
- link['color'] = self._get_color_hex(remove_quotes(data.get('color', 'green')))
+ link["color"] = self._get_color_hex(remove_quotes(data.get("color", "green")))
if "zbx_draw_style" not in link:
- link['drawtype'] = self._get_link_draw_style_id(remove_quotes(data.get('zbx_draw_style', 'line')))
+ link["drawtype"] = self._get_link_draw_style_id(remove_quotes(data.get("zbx_draw_style", "line")))
label = self._get_label(data)
if label and "label" not in link:
- link['label'] = label
+ link["label"] = label
triggers = self._get_triggers(data)
if triggers:
if "linktriggers" not in link:
- link['linktriggers'] = []
- link['linktriggers'] += triggers
+ link["linktriggers"] = []
+ link["linktriggers"] += triggers
return list(links.values())
@@ -449,12 +439,12 @@ class Map(ZabbixBase):
urls = []
for url_raw in [remove_quotes(value) for key, value in data.items() if key.startswith("zbx_url")]:
try:
- name, url = url_raw.split(':', 1)
+ name, url = url_raw.split(":", 1)
except Exception as e:
self._module.fail_json(msg="Failed to parse zbx_url='%s': %s" % (url_raw, e))
urls.append({
- 'name': name,
- 'url': url,
+ "name": name,
+ "url": url,
})
return urls
@@ -464,9 +454,9 @@ class Map(ZabbixBase):
triggerid = self._get_trigger_id(trigger_definition)
if triggerid:
triggers.append({
- 'triggerid': triggerid,
- 'color': self._get_color_hex(remove_quotes(data.get('zbx_trigger_color', 'red'))),
- 'drawtype': self._get_link_draw_style_id(remove_quotes(data.get('zbx_trigger_draw_style', 'bold'))),
+ "triggerid": triggerid,
+ "color": self._get_color_hex(remove_quotes(data.get("zbx_trigger_color", "red"))),
+ "drawtype": self._get_link_draw_style_id(remove_quotes(data.get("zbx_trigger_draw_style", "bold"))),
})
else:
self._module.fail_json(msg="Failed to find trigger '%s'" % (trigger_definition))
@@ -475,23 +465,23 @@ class Map(ZabbixBase):
@staticmethod
def _get_label(data, default=None):
if "zbx_label" in data:
- label = remove_quotes(data['zbx_label']).replace('\\n', '\n')
+ label = remove_quotes(data["zbx_label"]).replace("\\n", "\n")
elif "label" in data:
- label = remove_quotes(data['label'])
+ label = remove_quotes(data["label"])
else:
label = default
return label
def _get_sysmap_id(self, map_name):
- exist_map = self._zapi.map.get({'filter': {'name': map_name}})
+ exist_map = self._zapi.map.get({"filter": {"name": map_name}})
if exist_map:
- return exist_map[0]['sysmapid']
+ return exist_map[0]["sysmapid"]
return None
def _get_group_id(self, group_name):
- exist_group = self._zapi.hostgroup.get({'filter': {'name': group_name}})
+ exist_group = self._zapi.hostgroup.get({"filter": {"name": group_name}})
if exist_group:
- return exist_group[0]['groupid']
+ return exist_group[0]["groupid"]
return None
def map_exists(self):
@@ -513,7 +503,7 @@ class Map(ZabbixBase):
try:
if self._module.check_mode:
self._module.exit_json(changed=True)
- map_config['sysmapid'] = self.map_id
+ map_config["sysmapid"] = self.map_id
result = self._zapi.map.update(map_config)
if result:
return result
@@ -532,24 +522,22 @@ class Map(ZabbixBase):
def is_exist_map_correct(self, generated_map_config):
exist_map_configs = self._zapi.map.get({
- 'sysmapids': self.map_id,
- 'selectLinks': 'extend',
- 'selectSelements': 'extend'
+ "sysmapids": self.map_id,
+ "selectLinks": "extend",
+ "selectSelements": "extend"
})
exist_map_config = exist_map_configs[0]
if not self._is_dicts_equal(generated_map_config, exist_map_config):
return False
- if not self._is_selements_equal(generated_map_config['selements'], exist_map_config['selements']):
+ if not self._is_selements_equal(generated_map_config["selements"], exist_map_config["selements"]):
return False
self._update_ids(generated_map_config, exist_map_config)
- if not self._is_links_equal(generated_map_config['links'], exist_map_config['links']):
+ if not self._is_links_equal(generated_map_config["links"], exist_map_config["links"]):
return False
return True
def _get_selements_sort_keys(self):
- keys_to_sort = ['label']
- if LooseVersion(self._zbx_api_version) < LooseVersion('3.4'):
- keys_to_sort.insert(0, 'elementid')
+ keys_to_sort = ["label"]
return keys_to_sort
def _is_selements_equal(self, generated_selements, exist_selements):
@@ -558,22 +546,21 @@ class Map(ZabbixBase):
generated_selements_sorted = sorted(generated_selements, key=itemgetter(*self.selements_sort_keys))
exist_selements_sorted = sorted(exist_selements, key=itemgetter(*self.selements_sort_keys))
for (generated_selement, exist_selement) in zip(generated_selements_sorted, exist_selements_sorted):
- if LooseVersion(self._zbx_api_version) >= LooseVersion('3.4'):
- if not self._is_elements_equal(generated_selement.get('elements', []), exist_selement.get('elements', [])):
- return False
- if not self._is_dicts_equal(generated_selement, exist_selement, ['selementid']):
+ if not self._is_elements_equal(generated_selement.get("elements", []), exist_selement.get("elements", [])):
return False
- if not self._is_urls_equal(generated_selement.get('urls', []), exist_selement.get('urls', [])):
+ if not self._is_dicts_equal(generated_selement, exist_selement, ["selementid"]):
+ return False
+ if not self._is_urls_equal(generated_selement.get("urls", []), exist_selement.get("urls", [])):
return False
return True
def _is_urls_equal(self, generated_urls, exist_urls):
if len(generated_urls) != len(exist_urls):
return False
- generated_urls_sorted = sorted(generated_urls, key=itemgetter('name', 'url'))
- exist_urls_sorted = sorted(exist_urls, key=itemgetter('name', 'url'))
+ generated_urls_sorted = sorted(generated_urls, key=itemgetter("name", "url"))
+ exist_urls_sorted = sorted(exist_urls, key=itemgetter("name", "url"))
for (generated_url, exist_url) in zip(generated_urls_sorted, exist_urls_sorted):
- if not self._is_dicts_equal(generated_url, exist_url, ['selementid']):
+ if not self._is_dicts_equal(generated_url, exist_url, ["selementid"]):
return False
return True
@@ -583,40 +570,40 @@ class Map(ZabbixBase):
generated_elements_sorted = sorted(generated_elements, key=lambda k: k.values()[0])
exist_elements_sorted = sorted(exist_elements, key=lambda k: k.values()[0])
for (generated_element, exist_element) in zip(generated_elements_sorted, exist_elements_sorted):
- if not self._is_dicts_equal(generated_element, exist_element, ['selementid']):
+ if not self._is_dicts_equal(generated_element, exist_element, ["selementid"]):
return False
return True
# since generated IDs differ from real Zabbix ones, make real IDs match generated ones
def _update_ids(self, generated_map_config, exist_map_config):
- generated_selements_sorted = sorted(generated_map_config['selements'], key=itemgetter(*self.selements_sort_keys))
- exist_selements_sorted = sorted(exist_map_config['selements'], key=itemgetter(*self.selements_sort_keys))
+ generated_selements_sorted = sorted(generated_map_config["selements"], key=itemgetter(*self.selements_sort_keys))
+ exist_selements_sorted = sorted(exist_map_config["selements"], key=itemgetter(*self.selements_sort_keys))
id_mapping = {}
for (generated_selement, exist_selement) in zip(generated_selements_sorted, exist_selements_sorted):
- id_mapping[exist_selement['selementid']] = generated_selement['selementid']
- for link in exist_map_config['links']:
- link['selementid1'] = id_mapping[link['selementid1']]
- link['selementid2'] = id_mapping[link['selementid2']]
- if link['selementid2'] < link['selementid1']:
- link['selementid1'], link['selementid2'] = link['selementid2'], link['selementid1']
+ id_mapping[exist_selement["selementid"]] = generated_selement["selementid"]
+ for link in exist_map_config["links"]:
+ link["selementid1"] = id_mapping[link["selementid1"]]
+ link["selementid2"] = id_mapping[link["selementid2"]]
+ if link["selementid2"] < link["selementid1"]:
+ link["selementid1"], link["selementid2"] = link["selementid2"], link["selementid1"]
def _is_links_equal(self, generated_links, exist_links):
if len(generated_links) != len(exist_links):
return False
- generated_links_sorted = sorted(generated_links, key=itemgetter('selementid1', 'selementid2', 'color', 'drawtype'))
- exist_links_sorted = sorted(exist_links, key=itemgetter('selementid1', 'selementid2', 'color', 'drawtype'))
+ generated_links_sorted = sorted(generated_links, key=itemgetter("selementid1", "selementid2", "color", "drawtype"))
+ exist_links_sorted = sorted(exist_links, key=itemgetter("selementid1", "selementid2", "color", "drawtype"))
for (generated_link, exist_link) in zip(generated_links_sorted, exist_links_sorted):
- if not self._is_dicts_equal(generated_link, exist_link, ['selementid1', 'selementid2']):
+ if not self._is_dicts_equal(generated_link, exist_link, ["selementid1", "selementid2"]):
return False
- if not self._is_triggers_equal(generated_link.get('linktriggers', []), exist_link.get('linktriggers', [])):
+ if not self._is_triggers_equal(generated_link.get("linktriggers", []), exist_link.get("linktriggers", [])):
return False
return True
def _is_triggers_equal(self, generated_triggers, exist_triggers):
if len(generated_triggers) != len(exist_triggers):
return False
- generated_triggers_sorted = sorted(generated_triggers, key=itemgetter('triggerid'))
- exist_triggers_sorted = sorted(exist_triggers, key=itemgetter('triggerid'))
+ generated_triggers_sorted = sorted(generated_triggers, key=itemgetter("triggerid"))
+ exist_triggers_sorted = sorted(exist_triggers, key=itemgetter("triggerid"))
for (generated_trigger, exist_trigger) in zip(generated_triggers_sorted, exist_triggers_sorted):
if not self._is_dicts_equal(generated_trigger, exist_trigger):
return False
@@ -637,40 +624,40 @@ class Map(ZabbixBase):
return True
def _get_host_id(self, hostname):
- hostid = self._zapi.host.get({'filter': {'host': hostname}})
+ hostid = self._zapi.host.get({"filter": {"host": hostname}})
if hostid:
- return str(hostid[0]['hostid'])
+ return str(hostid[0]["hostid"])
def _get_trigger_id(self, trigger_definition):
try:
- host, trigger = trigger_definition.split(':', 1)
+ host, trigger = trigger_definition.split(":", 1)
except Exception as e:
self._module.fail_json(msg="Failed to parse zbx_trigger='%s': %s" % (trigger_definition, e))
triggerid = self._zapi.trigger.get({
- 'host': host,
- 'filter': {
- 'description': trigger
+ "host": host,
+ "filter": {
+ "description": trigger
}
})
if triggerid:
- return str(triggerid[0]['triggerid'])
+ return str(triggerid[0]["triggerid"])
def _get_icon_ids(self):
icons_list = self._zapi.image.get({})
icon_ids = {}
for icon in icons_list:
- icon_ids[icon['name']] = icon['imageid']
+ icon_ids[icon["name"]] = icon["imageid"]
return icon_ids
def _get_icon_size(self, icon_id):
icons_list = self._zapi.image.get({
- 'imageids': [
+ "imageids": [
icon_id
],
- 'select_image': True
+ "select_image": True
})
if len(icons_list) > 0:
- icon_base64 = icons_list[0]['image']
+ icon_base64 = icons_list[0]["image"]
else:
self._module.fail_json(msg="Failed to find image with id %s" % icon_id)
image = Image.open(BytesIO(base64.b64decode(icon_base64)))
@@ -681,19 +668,19 @@ class Map(ZabbixBase):
def _get_node_attributes(node):
attr = {}
if "attributes" in node.obj_dict:
- attr.update(node.obj_dict['attributes'])
+ attr.update(node.obj_dict["attributes"])
pos = node.get_pos()
if pos is not None:
pos = remove_quotes(pos)
xx, yy = pos.split(",")
- attr['pos'] = (float(xx), float(yy))
+ attr["pos"] = (float(xx), float(yy))
return attr
def _get_graph_nodes(self, parent):
nodes = {}
for node in parent.get_nodes():
node_name = node.get_name()
- if node_name in ('node', 'graph', 'edge'):
+ if node_name in ("node", "graph", "edge"):
continue
nodes[node_name] = self._get_node_attributes(node)
for subgraph in parent.get_subgraphs():
@@ -714,38 +701,38 @@ class Map(ZabbixBase):
scale_x = (self.width - self.margin * 2) / (float(max_x) - float(min_x)) if float(max_x) != float(min_x) else 0
scale_y = (self.height - self.margin * 2) / (float(max_y) - float(min_y)) if float(max_y) != float(min_y) else 0
return {
- 'min_x': float(min_x),
- 'min_y': float(min_y),
- 'max_x': float(max_x),
- 'max_y': float(max_y),
- 'scale_x': float(scale_x),
- 'scale_y': float(scale_y),
+ "min_x": float(min_x),
+ "min_y": float(min_y),
+ "max_x": float(max_x),
+ "max_y": float(max_y),
+ "scale_x": float(scale_x),
+ "scale_y": float(scale_y),
}
# transform Graphviz coordinates to Zabbix's ones
def _convert_coordinates(self, pos, scales, icon_size):
return {
- 'x': int((pos[0] - scales['min_x']) * scales['scale_x'] - icon_size[0] / 2 + self.margin),
- 'y': int((scales['max_y'] - pos[1] + scales['min_y']) * scales['scale_y'] - icon_size[1] / 2 + self.margin),
+ "x": int((pos[0] - scales["min_x"]) * scales["scale_x"] - icon_size[0] / 2 + self.margin),
+ "y": int((scales["max_y"] - pos[1] + scales["min_y"]) * scales["scale_y"] - icon_size[1] / 2 + self.margin),
}
def _get_color_hex(self, color_name):
- if color_name.startswith('#'):
+ if color_name.startswith("#"):
color_hex = color_name
else:
try:
color_hex = webcolors.name_to_hex(color_name)
except Exception as e:
self._module.fail_json(msg="Failed to get RGB hex for color '%s': %s" % (color_name, e))
- color_hex = color_hex.strip('#').upper()
+ color_hex = color_hex.strip("#").upper()
return color_hex
def _get_link_draw_style_id(self, draw_style):
draw_style_ids = {
- 'line': 0,
- 'bold': 2,
- 'dotted': 3,
- 'dashed': 4
+ "line": 0,
+ "bold": 2,
+ "dotted": 3,
+ "dashed": 4
}
try:
draw_style_id = draw_style_ids[draw_style]
@@ -764,34 +751,28 @@ def remove_quotes(s):
def main():
argument_spec = zabbix_utils.zabbix_common_argument_spec()
argument_spec.update(dict(
- name=dict(type='str', required=True, aliases=['map_name']),
- data=dict(type='str', required=False, aliases=['dot_data']),
- width=dict(type='int', default=800),
- height=dict(type='int', default=600),
- state=dict(type='str', default="present", choices=['present', 'absent']),
- default_image=dict(type='str', required=False, aliases=['image']),
- margin=dict(type='int', default=40),
- expand_problem=dict(type='bool', default=True),
- highlight=dict(type='bool', default=True),
- label_type=dict(type='str', default='name', choices=['label', 'ip', 'name', 'status', 'nothing', 'custom']),
+ name=dict(type="str", required=True, aliases=["map_name"]),
+ data=dict(type="str", required=False, aliases=["dot_data"]),
+ width=dict(type="int", default=800),
+ height=dict(type="int", default=600),
+ state=dict(type="str", default="present", choices=["present", "absent"]),
+ default_image=dict(type="str", required=False, aliases=["image"]),
+ margin=dict(type="int", default=40),
+ expand_problem=dict(type="bool", default=True),
+ highlight=dict(type="bool", default=True),
+ label_type=dict(type="str", default="name", choices=["label", "ip", "name", "status", "nothing", "custom"]),
))
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True
)
- zabbix_utils.require_creds_params(module)
-
- for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']:
- if p in module.params and not module.params[p] is None:
- module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p)
-
if not HAS_PYDOTPLUS:
- module.fail_json(msg=missing_required_lib('pydotplus', url='https://pypi.org/project/pydotplus/'), exception=PYDOT_IMP_ERR)
+ module.fail_json(msg=missing_required_lib("pydotplus", url="https://pypi.org/project/pydotplus/"), exception=PYDOT_IMP_ERR)
if not HAS_WEBCOLORS:
- module.fail_json(msg=missing_required_lib('webcolors', url='https://pypi.org/project/webcolors/'), exception=WEBCOLORS_IMP_ERR)
+ module.fail_json(msg=missing_required_lib("webcolors", url="https://pypi.org/project/webcolors/"), exception=WEBCOLORS_IMP_ERR)
if not HAS_PIL:
- module.fail_json(msg=missing_required_lib('Pillow', url='https://pypi.org/project/Pillow/'), exception=PIL_IMP_ERR)
+ module.fail_json(msg=missing_required_lib("Pillow", url="https://pypi.org/project/Pillow/"), exception=PIL_IMP_ERR)
sysmap = Map(module)
@@ -814,5 +795,5 @@ def main():
module.exit_json(changed=True, result="Successfully created map: %s" % sysmap.map_name)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_mediatype.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_mediatype.py
index c5693f467..1e2514bf3 100644
--- a/ansible_collections/community/zabbix/plugins/modules/zabbix_mediatype.py
+++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_mediatype.py
@@ -7,7 +7,7 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: zabbix_mediatype
short_description: Create/Update/Delete Zabbix media types
@@ -16,22 +16,21 @@ description:
author:
- Ruben Tsirunyan (@rubentsirunyan)
requirements:
- - "python >= 2.6"
+ - "python >= 3.9"
options:
name:
- type: 'str'
+ type: "str"
description:
- Name of the media type.
required: true
description:
- type: 'str'
+ type: "str"
description:
- Description of the media type.
- - Works only with Zabbix versions 4.4 or newer.
- default: ''
+ default: ""
state:
- type: 'str'
+ type: "str"
description:
- Desired state of the mediatype.
- On C(present), it will create a mediatype if it does not exist or update the mediatype if the associated data is different.
@@ -39,13 +38,12 @@ options:
choices:
- present
- absent
- default: 'present'
+ default: "present"
type:
- type: 'str'
+ type: "str"
description:
- Type of the media type.
- Media types I(jabber) and I(ez_texting) works only with Zabbix versions 4.2 or older.
- - Media type I(webhook) works only with Zabbix versions 4.4 or newer.
choices:
- email
- script
@@ -55,93 +53,90 @@ options:
- ez_texting
required: true
status:
- type: 'str'
+ type: "str"
description:
- Whether the media type is enabled or no.
choices:
- enabled
- disabled
- default: 'enabled'
+ default: "enabled"
max_sessions:
- type: 'int'
+ type: "int"
description:
- The maximum number of alerts that can be processed in parallel.
- Possible value is 1 when I(type=sms) and 0-100 otherwise.
- - Works only with Zabbix versions 3.4 or newer.
default: 1
max_attempts:
- type: 'int'
+ type: "int"
description:
- The maximum number of attempts to send an alert.
- Possible range is 0-10.
- - Works only with Zabbix versions 3.4 or newer.
default: 3
attempt_interval:
- type: 'str'
+ type: "str"
description:
- The interval between retry attempts.
- - Possible range is 0-60s in Zabbix < 5.0 or 0-1h in Zabbix >= 5.0.
- - Works only with Zabbix versions 3.4 or newer.
+ - Possible range is 0-1h.
default: 10s
script_name:
- type: 'str'
+ type: "str"
description:
- The name of the executed script.
- Required when I(type=script).
script_params:
- type: 'list'
+ type: "list"
elements: str
description:
- List of script parameters.
- Required when I(type=script).
gsm_modem:
- type: 'str'
+ type: "str"
description:
- Serial device name of the gsm modem.
- Required when I(type=sms).
username:
- type: 'str'
+ type: "str"
description:
- Username or Jabber identifier.
- Required when I(type=jabber) or I(type=ez_texting).
- Required when I(type=email) and I(smtp_authentication=true).
password:
- type: 'str'
+ type: "str"
description:
- Authentication password.
- Required when I(type=jabber) or I(type=ez_texting).
- Required when I(type=email) and I(smtp_authentication=true).
smtp_server:
- type: 'str'
+ type: "str"
description:
- SMTP server host.
- Required when I(type=email).
- default: 'localhost'
+ default: "localhost"
smtp_server_port:
- type: 'int'
+ type: "int"
description:
- SMTP server port.
- Required when I(type=email).
default: 25
smtp_helo:
- type: 'str'
+ type: "str"
description:
- SMTP HELO.
- Required when I(type=email).
- default: 'localhost'
+ default: "localhost"
smtp_email:
- type: 'str'
+ type: "str"
description:
- Email address from which notifications will be sent.
- Required when I(type=email).
smtp_authentication:
- type: 'bool'
+ type: "bool"
description:
- Whether SMTP authentication with username and password should be enabled or not.
- If set to C(true), C(username) and C(password) should be specified.
default: false
smtp_security:
- type: 'str'
+ type: "str"
description:
- SMTP connection security level to use.
choices:
@@ -149,19 +144,19 @@ options:
- STARTTLS
- SSL/TLS
smtp_verify_host:
- type: 'bool'
+ type: "bool"
description:
- SSL verify host for SMTP.
- Can be specified when I(smtp_security=STARTTLS) or I(smtp_security=SSL/TLS)
default: false
smtp_verify_peer:
- type: 'bool'
+ type: "bool"
description:
- SSL verify peer for SMTP.
- Can be specified when I(smtp_security=STARTTLS) or I(smtp_security=SSL/TLS)
default: false
message_text_limit:
- type: 'str'
+ type: "str"
description:
- The message text limit.
- Required when I(type=ez_texting).
@@ -170,74 +165,72 @@ options:
- USA
- Canada
webhook_script:
- type: 'str'
+ type: "str"
description:
- Required when I(type=webhook).
- JavaScript code that will perform webhook operation.
- This code has access to all parameters in I(webhook_params).
- It may perform HTTP GET, POST, PUT and DELETE requests and has control over HTTP headers and request body.
- It may return OK status along with an optional list of tags and tag values or an error string.
- - Works only with Zabbix versions 4.4 or newer.
webhook_timeout:
- type: 'str'
+ type: "str"
description:
- Can be used when I(type=webhook).
- Execution timeout for JavaScript code in I(webhook_script).
- Possible values are 1-60s.
default: 30s
process_tags:
- type: 'bool'
+ type: "bool"
description:
- Can be used when I(type=webhook).
- Process returned JSON property values as tags.
- These tags are added to the already existing (if any) problem event tags in Zabbix.
default: false
event_menu:
- type: 'bool'
+ type: "bool"
description:
- Can be used when I(type=webhook).
- Includes entry in Event menu with link to created external ticket.
default: false
event_menu_url:
- type: 'str'
+ type: "str"
description:
- Requred when I(event_menu=true).
- Event menu entry underlying URL.
event_menu_name:
- type: 'str'
+ type: "str"
description:
- Requred when I(event_menu=true).
- Event menu entry name.
webhook_params:
- type: 'list'
- elements: 'dict'
+ type: "list"
+ elements: "dict"
description:
- Can be used when I(type=webhook).
- Webhook variables that are passed to webhook script when executed.
default: []
suboptions:
name:
- type: 'str'
+ type: "str"
description:
- Name of the parameter.
required: true
value:
- type: 'str'
+ type: "str"
description:
- Value of the parameter.
- All macros that are supported in problem notifications are supported in the parameters.
- Values are URL-encoded automatically. Values from macros are resolved and then URL-encoded automatically.
- default: ''
+ default: ""
message_templates:
- type: 'list'
- elements: 'dict'
+ type: "list"
+ elements: "dict"
description:
- Default notification messages for the event types.
- - Works only with Zabbix versions 5.0 or newer.
default: []
suboptions:
eventsource:
- type: 'str'
+ type: "str"
description:
- Event source.
- Required when I(recovery) is used.
@@ -247,7 +240,7 @@ options:
- autoregistration
- internal
recovery:
- type: 'str'
+ type: "str"
description:
- Operation mode.
- Required when I(eventsource) is used.
@@ -256,40 +249,40 @@ options:
- recovery_operations
- update_operations
subject:
- type: 'str'
+ type: "str"
description:
- Subject of the default message.
- May contain macros and is limited to 255 characters.
- default: ''
+ default: ""
body:
- type: 'str'
+ type: "str"
description:
- Body of the default message.
- May contain macros.
- default: ''
+ default: ""
extends_documentation_fragment:
- community.zabbix.zabbix
-'''
+"""
-RETURN = r''' # '''
+RETURN = r""" # """
-EXAMPLES = r'''
+EXAMPLES = r"""
# If you want to use Username and Password to be authenticated by Zabbix Server
- name: Set credentials to access Zabbix Server API
- set_fact:
+ ansible.builtin.set_fact:
ansible_user: Admin
ansible_httpapi_pass: zabbix
# If you want to use API token to be authenticated by Zabbix Server
# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens
- name: Set API token
- set_fact:
+ ansible.builtin.set_fact:
ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895
-- name: 'Create an email mediatype with SMTP authentication'
+- name: "Create an email mediatype with SMTP authentication"
# set task level variables as we change ansible_connection plugin here
vars:
ansible_network_os: community.zabbix.zabbix
@@ -297,19 +290,19 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_mediatype:
name: "Ops email"
- type: 'email'
- smtp_server: 'example.com'
+ type: "email"
+ smtp_server: "example.com"
smtp_server_port: 2000
- smtp_email: 'ops@example.com'
+ smtp_email: "ops@example.com"
smtp_authentication: true
- username: 'smtp_user'
- password: 'smtp_pass'
+ username: "smtp_user"
+ password: "smtp_pass"
-- name: 'Create a script mediatype'
+- name: "Create a script mediatype"
# set task level variables as we change ansible_connection plugin here
vars:
ansible_network_os: community.zabbix.zabbix
@@ -317,17 +310,17 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_mediatype:
name: "my script"
- type: 'script'
- script_name: 'my_script.py'
+ type: "script"
+ script_name: "my_script.py"
script_params:
- - 'arg1'
- - 'arg2'
+ - "arg1"
+ - "arg2"
-- name: 'Create a jabber mediatype'
+- name: "Create a jabber mediatype"
# set task level variables as we change ansible_connection plugin here
vars:
ansible_network_os: community.zabbix.zabbix
@@ -335,15 +328,15 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_mediatype:
name: "My jabber"
- type: 'jabber'
- username: 'jabber_id'
- password: 'jabber_pass'
+ type: "jabber"
+ username: "jabber_id"
+ password: "jabber_pass"
-- name: 'Create a SMS mediatype'
+- name: "Create a SMS mediatype"
# set task level variables as we change ansible_connection plugin here
vars:
ansible_network_os: community.zabbix.zabbix
@@ -351,15 +344,14 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_mediatype:
name: "My SMS Mediatype"
- type: 'sms'
- gsm_modem: '/dev/ttyS0'
+ type: "sms"
+ gsm_modem: "/dev/ttyS0"
-# Supported since Zabbix 4.4
-- name: 'Create a webhook mediatype'
+- name: "Create a webhook mediatype"
# set task level variables as we change ansible_connection plugin here
vars:
ansible_network_os: community.zabbix.zabbix
@@ -367,24 +359,23 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_mediatype:
name: "My webhook Mediatype"
- type: 'webhook'
+ type: "webhook"
webhook_script: "{{ lookup('file', 'slack.js') }}"
webhook_params:
- name: alert_message
- value: '{ALERT.MESSAGE}'
+ value: "{ALERT.MESSAGE}"
- name: zabbix_url
- value: '{$ZABBIX.URL}'
+ value: "{$ZABBIX.URL}"
process_tags: true
event_menu: true
event_menu_name: "Open in Slack: '{EVENT.TAGS.__channel_name}'"
- event_menu_url: '{EVENT.TAGS.__message_link}'
+ event_menu_url: "{EVENT.TAGS.__message_link}"
-# Supported since Zabbix 5.0
-- name: 'Create an email mediatype with message templates'
+- name: "Create an email mediatype with message templates"
# set task level variables as we change ansible_connection plugin here
vars:
ansible_network_os: community.zabbix.zabbix
@@ -392,12 +383,12 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_mediatype:
name: "Ops email"
- type: 'email'
- smtp_email: 'ops@example.com'
+ type: "email"
+ smtp_email: "ops@example.com"
message_templates:
- eventsource: triggers
recovery: operations
@@ -419,7 +410,7 @@ EXAMPLES = r'''
recovery: operations
subject: "Autoregistration: {HOST.HOST}"
body: "Host name: {HOST.HOST}\r\nHost IP: {HOST.IP}\r\nAgent port: {HOST.PORT}"
-'''
+"""
from ansible.module_utils.basic import AnsibleModule
@@ -446,10 +437,10 @@ def diff(existing, new):
for key in new:
before[key] = existing[key]
if new[key] is None:
- after[key] = ''
+ after[key] = ""
else:
after[key] = new[key]
- return {'before': before, 'after': after}
+ return {"before": before, "after": after}
class MediaTypeModule(ZabbixBase):
@@ -462,20 +453,18 @@ class MediaTypeModule(ZabbixBase):
Returns:
Tuple of (True, `id of the mediatype`) if mediatype exists, (False, None) otherwise
"""
- filter_key_name = 'description'
- if LooseVersion(self._zbx_api_version) >= LooseVersion('4.4'):
- # description key changed to name key from zabbix 4.4
- filter_key_name = 'name'
+ filter_key_name = "description"
+ filter_key_name = "name"
try:
mediatype_list = self._zapi.mediatype.get({
- 'output': 'extend',
- 'filter': {filter_key_name: [name]}
+ "output": "extend",
+ "filter": {filter_key_name: [name]}
})
if len(mediatype_list) < 1:
return False, None
else:
- return True, mediatype_list[0]['mediatypeid']
+ return True, mediatype_list[0]["mediatypeid"]
except Exception as e:
self._module.fail_json(msg="Failed to get ID of the mediatype '{name}': {e}".format(name=name, e=e))
@@ -487,127 +476,104 @@ class MediaTypeModule(ZabbixBase):
A dictionary of arguments that are related to transport type,
and are in a format that is understandable by Zabbix API.
"""
- truths = {'False': '0', 'True': '1'}
+ truths = {"False": "0", "True": "1"}
parameters = dict(
- status='0' if self._module.params['status'] == 'enabled' else '1',
+ status="0" if self._module.params["status"] == "enabled" else "1",
type={
- 'email': '0',
- 'script': '1',
- 'sms': '2',
- 'jabber': '3',
- 'webhook': '4',
- 'ez_texting': '100'
- }.get(self._module.params['type']),
+ "email": "0",
+ "script": "1",
+ "sms": "2",
+ "jabber": "3",
+ "webhook": "4",
+ "ez_texting": "100"
+ }.get(self._module.params["type"]),
)
- if LooseVersion(self._zbx_api_version) >= LooseVersion('4.4'):
- parameters.update(dict(
- name=self._module.params['name'],
- description=self._module.params['description'],
- ))
- else:
- parameters.update(dict(description=self._module.params['name']))
+ parameters.update(dict(
+ name=self._module.params["name"],
+ description=self._module.params["description"],
+ maxsessions=str(self._module.params["max_sessions"]),
+ maxattempts=str(self._module.params["max_attempts"]),
+ attempt_interval=str(self._module.params["attempt_interval"])
+ ))
- if LooseVersion(self._zbx_api_version) >= LooseVersion('3.4'):
- parameters.update(dict(
- maxsessions=str(self._module.params['max_sessions']),
- maxattempts=str(self._module.params['max_attempts']),
- attempt_interval=str(self._module.params['attempt_interval'])
- ))
-
- if self._module.params['message_templates'] and LooseVersion(self._zbx_api_version) >= LooseVersion('5.0'):
+ if self._module.params["message_templates"]:
msg_templates = []
- for template in self._module.params['message_templates']:
+ for template in self._module.params["message_templates"]:
msg_templates.append(dict(
eventsource={
- 'triggers': '0',
- 'discovery': '1',
- 'autoregistration': '2',
- 'internal': '3'}.get(template['eventsource']),
+ "triggers": "0",
+ "discovery": "1",
+ "autoregistration": "2",
+ "internal": "3"}.get(template["eventsource"]),
recovery={
- 'operations': '0',
- 'recovery_operations': '1',
- 'update_operations': '2'}.get(template['recovery']),
- subject=template['subject'],
- message=template['body']
+ "operations": "0",
+ "recovery_operations": "1",
+ "update_operations": "2"}.get(template["recovery"]),
+ subject=template["subject"],
+ message=template["body"]
))
parameters.update(dict(message_templates=msg_templates))
- if self._module.params['type'] == 'email':
+ if self._module.params["type"] == "email":
parameters.update(dict(
- smtp_server=self._module.params['smtp_server'],
- smtp_port=str(self._module.params['smtp_server_port']),
- smtp_helo=self._module.params['smtp_helo'],
- smtp_email=self._module.params['smtp_email'],
- smtp_security={'None': '0', 'STARTTLS': '1', 'SSL/TLS': '2'}.get(str(self._module.params['smtp_security'])),
- smtp_authentication=truths.get(str(self._module.params['smtp_authentication'])),
- smtp_verify_host=truths.get(str(self._module.params['smtp_verify_host'])),
- smtp_verify_peer=truths.get(str(self._module.params['smtp_verify_peer'])),
- username=self._module.params['username'],
- passwd=self._module.params['password']
+ smtp_server=self._module.params["smtp_server"],
+ smtp_port=str(self._module.params["smtp_server_port"]),
+ smtp_helo=self._module.params["smtp_helo"],
+ smtp_email=self._module.params["smtp_email"],
+ smtp_security={"None": "0", "STARTTLS": "1", "SSL/TLS": "2"}.get(str(self._module.params["smtp_security"])),
+ smtp_authentication=truths.get(str(self._module.params["smtp_authentication"])),
+ smtp_verify_host=truths.get(str(self._module.params["smtp_verify_host"])),
+ smtp_verify_peer=truths.get(str(self._module.params["smtp_verify_peer"])),
+ username=self._module.params["username"],
+ passwd=self._module.params["password"]
))
- if LooseVersion(self._zbx_api_version) >= LooseVersion('6.0'):
- if parameters['smtp_authentication'] == '0':
- parameters.pop('username')
- parameters.pop('passwd')
+ if parameters["smtp_authentication"] == "0":
+ parameters.pop("username")
+ parameters.pop("passwd")
return parameters
- elif self._module.params['type'] == 'script':
- if LooseVersion(self._zbx_api_version) < LooseVersion('6.4'):
- if self._module.params['script_params'] is None:
- _script_params = '' # ZBX-15706
+ elif self._module.params["type"] == "script":
+ if LooseVersion(self._zbx_api_version) < LooseVersion("6.4"):
+ if self._module.params["script_params"] is None:
+ _script_params = "" # ZBX-15706
else:
- _script_params = '\n'.join(str(i) for i in self._module.params['script_params']) + '\n'
+ _script_params = "\n".join(str(i) for i in self._module.params["script_params"]) + "\n"
parameters.update(dict(
- exec_path=self._module.params['script_name'],
+ exec_path=self._module.params["script_name"],
exec_params=_script_params
))
else:
_script_params = []
- if self._module.params['script_params']:
- for i, val in enumerate(self._module.params['script_params']):
- _script_params.append({'sortorder': str(i), 'value': val})
+ if self._module.params["script_params"]:
+ for i, val in enumerate(self._module.params["script_params"]):
+ _script_params.append({"sortorder": str(i), "value": val})
parameters.update(dict(
- exec_path=self._module.params['script_name'],
+ exec_path=self._module.params["script_name"],
parameters=_script_params
))
return parameters
- elif self._module.params['type'] == 'sms':
- parameters.update(dict(gsm_modem=self._module.params['gsm_modem']))
+ elif self._module.params["type"] == "sms":
+ parameters.update(dict(gsm_modem=self._module.params["gsm_modem"]))
return parameters
- elif self._module.params['type'] == 'webhook' and LooseVersion(self._zbx_api_version) >= LooseVersion('4.4'):
+ elif self._module.params["type"] == "webhook":
parameters.update(dict(
- script=self._module.params['webhook_script'],
- timeout=self._module.params['webhook_timeout'],
- process_tags=truths.get(str(self._module.params['process_tags'])),
- show_event_menu=truths.get(str(self._module.params['event_menu'])),
- parameters=self._module.params['webhook_params']
+ script=self._module.params["webhook_script"],
+ timeout=self._module.params["webhook_timeout"],
+ process_tags=truths.get(str(self._module.params["process_tags"])),
+ show_event_menu=truths.get(str(self._module.params["event_menu"])),
+ parameters=self._module.params["webhook_params"]
))
- if self._module.params['event_menu']:
+ if self._module.params["event_menu"]:
parameters.update(dict(
- event_menu_url=self._module.params['event_menu_url'],
- event_menu_name=self._module.params['event_menu_name']
+ event_menu_url=self._module.params["event_menu_url"],
+ event_menu_name=self._module.params["event_menu_name"]
))
return parameters
- elif self._module.params['type'] == 'jabber' and LooseVersion(self._zbx_api_version) <= LooseVersion('4.2'):
- parameters.update(dict(
- username=self._module.params['username'],
- passwd=self._module.params['password']
- ))
- return parameters
-
- elif self._module.params['type'] == 'ez_texting' and LooseVersion(self._zbx_api_version) <= LooseVersion('4.2'):
- parameters.update(dict(
- username=self._module.params['username'],
- passwd=self._module.params['password'],
- exec_path={'USA': '0', 'Canada': '1'}.get(self._module.params['message_text_limit']),
- ))
- return parameters
-
- self._module.fail_json(msg="%s is unsupported for Zabbix version %s" % (parameters['unsupported_parameter'], parameters['zbx_api_version']))
+ self._module.fail_json(msg="%s is unsupported for Zabbix version %s" % (self._module.params["type"], self._zbx_api_version))
def validate_params(self, params):
"""Validates arguments that are required together.
@@ -629,7 +595,7 @@ class MediaTypeModule(ZabbixBase):
msg="Following arguments are required when {key} is {value}: {arguments}".format(
key=param[0],
value=param[1],
- arguments=', '.join(param[2])
+ arguments=", ".join(param[2])
)
)
@@ -646,35 +612,37 @@ class MediaTypeModule(ZabbixBase):
returned by diff() function with
existing mediatype data and new params passed to it.
"""
- get_params = {'output': 'extend', 'mediatypeids': [mediatype_id]}
- if LooseVersion(self._zbx_api_version) >= LooseVersion('5.0'):
- get_params.update({'selectMessageTemplates': 'extend'})
+ get_params = {
+ "output": "extend",
+ "mediatypeids": [mediatype_id],
+ "selectMessageTemplates": "extend"
+ }
existing_mediatype = self._zapi.mediatype.get(get_params)[0]
- if existing_mediatype['type'] != kwargs['type']:
+ if existing_mediatype["type"] != kwargs["type"]:
return kwargs, diff(existing_mediatype, kwargs)
else:
params_to_update = {}
for key in kwargs:
# sort list of parameters to prevent mismatch due to reordering
- if key == 'parameters' and (kwargs[key] != [] or existing_mediatype[key] != []):
- if LooseVersion(self._zbx_api_version) < LooseVersion('6.4'):
- kwargs[key] = sorted(kwargs[key], key=lambda x: x['name'])
- existing_mediatype[key] = sorted(existing_mediatype[key], key=lambda x: x['name'])
+ if key == "parameters" and (kwargs[key] != [] or existing_mediatype[key] != []):
+ if LooseVersion(self._zbx_api_version) < LooseVersion("6.4"):
+ kwargs[key] = sorted(kwargs[key], key=lambda x: x["name"])
+ existing_mediatype[key] = sorted(existing_mediatype[key], key=lambda x: x["name"])
else:
- if kwargs['type'] == '1': # script
- kwargs[key] = sorted(kwargs[key], key=lambda x: x['sortorder'])
- existing_mediatype[key] = sorted(existing_mediatype[key], key=lambda x: x['sortorder'])
- elif kwargs['type'] == '4': # webhook
- kwargs[key] = sorted(kwargs[key], key=lambda x: x['name'])
- existing_mediatype[key] = sorted(existing_mediatype[key], key=lambda x: x['name'])
-
- if key == 'message_templates' and (kwargs[key] != [] or existing_mediatype[key] != []):
- kwargs[key] = sorted(kwargs[key], key=lambda x: x['subject'])
- existing_mediatype[key] = sorted(existing_mediatype[key], key=lambda x: x['subject'])
-
- if (not (kwargs[key] is None and existing_mediatype[key] == '')) and kwargs[key] != existing_mediatype[key]:
+ if kwargs["type"] == "1": # script
+ kwargs[key] = sorted(kwargs[key], key=lambda x: x["sortorder"])
+ existing_mediatype[key] = sorted(existing_mediatype[key], key=lambda x: x["sortorder"])
+ elif kwargs["type"] == "4": # webhook
+ kwargs[key] = sorted(kwargs[key], key=lambda x: x["name"])
+ existing_mediatype[key] = sorted(existing_mediatype[key], key=lambda x: x["name"])
+
+ if key == "message_templates" and (kwargs[key] != [] or existing_mediatype[key] != []):
+ kwargs[key] = sorted(kwargs[key], key=lambda x: x["subject"])
+ existing_mediatype[key] = sorted(existing_mediatype[key], key=lambda x: x["subject"])
+
+ if (not (kwargs[key] is None and existing_mediatype[key] == "")) and kwargs[key] != existing_mediatype[key]:
params_to_update[key] = kwargs[key]
return params_to_update, diff(existing_mediatype, kwargs)
@@ -688,89 +656,89 @@ class MediaTypeModule(ZabbixBase):
try:
self._zapi.mediatype.update(kwargs)
except Exception as e:
- self._module.fail_json(msg="Failed to update mediatype '{_id}': {e}".format(_id=kwargs['mediatypeid'], e=e))
+ self._module.fail_json(msg="Failed to update mediatype '{_id}': {e}".format(_id=kwargs["mediatypeid"], e=e))
def create_mediatype(self, **kwargs):
try:
self._zapi.mediatype.create(kwargs)
except Exception as e:
- self._module.fail_json(msg="Failed to create mediatype '{name}': {e}".format(name=kwargs['name'], e=e))
+ self._module.fail_json(msg="Failed to create mediatype '{name}': {e}".format(name=kwargs["name"], e=e))
def main():
argument_spec = zabbix_utils.zabbix_common_argument_spec()
argument_spec.update(dict(
- name=dict(type='str', required=True),
- description=dict(type='str', required=False, default=''),
- state=dict(type='str', default='present', choices=['present', 'absent']),
- type=dict(type='str', choices=['email', 'script', 'sms', 'webhook', 'jabber', 'ez_texting'], required=True),
- status=dict(type='str', default='enabled', choices=['enabled', 'disabled'], required=False),
- max_sessions=dict(type='int', default=1, required=False),
- max_attempts=dict(type='int', default=3, required=False),
- attempt_interval=dict(type='str', default='10s', required=False),
+ name=dict(type="str", required=True),
+ description=dict(type="str", required=False, default=""),
+ state=dict(type="str", default="present", choices=["present", "absent"]),
+ type=dict(type="str", choices=["email", "script", "sms", "webhook", "jabber", "ez_texting"], required=True),
+ status=dict(type="str", default="enabled", choices=["enabled", "disabled"], required=False),
+ max_sessions=dict(type="int", default=1, required=False),
+ max_attempts=dict(type="int", default=3, required=False),
+ attempt_interval=dict(type="str", default="10s", required=False),
# Script
- script_name=dict(type='str', required=False),
- script_params=dict(type='list', required=False),
+ script_name=dict(type="str", required=False),
+ script_params=dict(type="list", required=False, elements="str"),
# SMS
- gsm_modem=dict(type='str', required=False),
+ gsm_modem=dict(type="str", required=False),
# Jabber
- username=dict(type='str', required=False),
- password=dict(type='str', required=False, no_log=True),
+ username=dict(type="str", required=False),
+ password=dict(type="str", required=False, no_log=True),
# Email
- smtp_server=dict(type='str', default='localhost', required=False),
- smtp_server_port=dict(type='int', default=25, required=False),
- smtp_helo=dict(type='str', default='localhost', required=False),
- smtp_email=dict(type='str', required=False),
- smtp_security=dict(type='str', required=False, choices=['None', 'STARTTLS', 'SSL/TLS']),
- smtp_authentication=dict(type='bool', default=False, required=False),
- smtp_verify_host=dict(type='bool', default=False, required=False),
- smtp_verify_peer=dict(type='bool', default=False, required=False),
+ smtp_server=dict(type="str", default="localhost", required=False),
+ smtp_server_port=dict(type="int", default=25, required=False),
+ smtp_helo=dict(type="str", default="localhost", required=False),
+ smtp_email=dict(type="str", required=False),
+ smtp_security=dict(type="str", required=False, choices=["None", "STARTTLS", "SSL/TLS"]),
+ smtp_authentication=dict(type="bool", default=False, required=False),
+ smtp_verify_host=dict(type="bool", default=False, required=False),
+ smtp_verify_peer=dict(type="bool", default=False, required=False),
# EZ Text
- message_text_limit=dict(type='str', required=False, choices=['USA', 'Canada']),
+ message_text_limit=dict(type="str", required=False, choices=["USA", "Canada"]),
# Webhook
- webhook_script=dict(type='str'),
- webhook_timeout=dict(type='str', default='30s'),
- process_tags=dict(type='bool', default=False),
- event_menu=dict(type='bool', default=False),
- event_menu_url=dict(type='str'),
- event_menu_name=dict(type='str'),
+ webhook_script=dict(type="str"),
+ webhook_timeout=dict(type="str", default="30s"),
+ process_tags=dict(type="bool", default=False),
+ event_menu=dict(type="bool", default=False),
+ event_menu_url=dict(type="str"),
+ event_menu_name=dict(type="str"),
webhook_params=dict(
- type='list',
- elements='dict',
+ type="list",
+ elements="dict",
default=[],
required=False,
options=dict(
- name=dict(type='str', required=True),
- value=dict(type='str', default='')
+ name=dict(type="str", required=True),
+ value=dict(type="str", default="")
)
),
message_templates=dict(
- type='list',
- elements='dict',
+ type="list",
+ elements="dict",
default=[],
required=False,
options=dict(
- eventsource=dict(type='str', choices=['triggers', 'discovery', 'autoregistration', 'internal']),
- recovery=dict(type='str', choices=['operations', 'recovery_operations', 'update_operations']),
- subject=dict(type='str', default=''),
- body=dict(type='str', default='')
+ eventsource=dict(type="str", choices=["triggers", "discovery", "autoregistration", "internal"]),
+ recovery=dict(type="str", choices=["operations", "recovery_operations", "update_operations"]),
+ subject=dict(type="str", default=""),
+ body=dict(type="str", default="")
),
required_together=[
- ['eventsource', 'recovery']
+ ["eventsource", "recovery"]
],
)
))
# this is used to simulate `required_if` of `AnsibleModule`, but only when state=present
required_params = [
- ['type', 'email', ['smtp_email']],
- ['type', 'script', ['script_name']],
- ['type', 'sms', ['gsm_modem']],
- ['type', 'jabber', ['username', 'password']],
- ['type', 'ez_texting', ['username', 'password', 'message_text_limit']],
- ['type', 'webhook', ['webhook_script']],
- ['event_menu', True, ['event_menu_url', 'event_menu_name']],
- ['smtp_authentication', True, ['username', 'password']]
+ ["type", "email", ["smtp_email"]],
+ ["type", "script", ["script_name"]],
+ ["type", "sms", ["gsm_modem"]],
+ ["type", "jabber", ["username", "password"]],
+ ["type", "ez_texting", ["username", "password", "message_text_limit"]],
+ ["type", "webhook", ["webhook_script"]],
+ ["event_menu", True, ["event_menu_url", "event_menu_name"]],
+ ["smtp_authentication", True, ["username", "password"]]
]
module = AnsibleModule(
@@ -778,24 +746,18 @@ def main():
supports_check_mode=True
)
- zabbix_utils.require_creds_params(module)
-
- for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']:
- if p in module.params and not module.params[p] is None:
- module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p)
-
- state = module.params['state']
- name = module.params['name']
+ state = module.params["state"]
+ name = module.params["name"]
mediatype = MediaTypeModule(module)
- if module.params['state'] == 'present':
+ if module.params["state"] == "present":
mediatype.validate_params(required_params)
mediatype_exists, mediatype_id = mediatype.check_if_mediatype_exists(name)
parameters = mediatype.construct_parameters()
if mediatype_exists:
- if state == 'absent':
+ if state == "absent":
if module.check_mode:
module.exit_json(
changed=True,
@@ -860,5 +822,5 @@ def main():
)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_proxy.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_proxy.py
index 3fdfe42c1..a5ddbe137 100644
--- a/ansible_collections/community/zabbix/plugins/modules/zabbix_proxy.py
+++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_proxy.py
@@ -22,7 +22,7 @@ from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: zabbix_proxy
short_description: Create/delete/get/update Zabbix proxies
@@ -31,7 +31,7 @@ description:
author:
- "Alen Komic (@akomic)"
requirements:
- - "python >= 2.6"
+ - "python >= 3.9"
options:
proxy_name:
description:
@@ -42,7 +42,6 @@ options:
description:
- Comma-delimited list of IP/CIDR addresses or DNS names to accept active proxy requests from.
- Requires I(status=active).
- - Works only with >= Zabbix 4.0. ( remove option for <= 4.0 )
required: false
type: str
description:
@@ -54,22 +53,22 @@ options:
description:
- Type of proxy. (4 - active, 5 - passive)
required: false
- choices: ['active', 'passive']
+ choices: ["active", "passive"]
default: "active"
type: str
tls_connect:
description:
- Connections to proxy.
required: false
- choices: ['no_encryption','PSK','certificate']
- default: 'no_encryption'
+ choices: ["no_encryption","PSK","certificate"]
+ default: "no_encryption"
type: str
tls_accept:
description:
- Connections from proxy.
required: false
- choices: ['no_encryption','PSK','certificate']
- default: 'no_encryption'
+ choices: ["no_encryption","PSK","certificate"]
+ default: "no_encryption"
type: str
ca_cert:
description:
@@ -98,14 +97,14 @@ options:
- On C(present), it will create if proxy does not exist or update the proxy if the associated data is different.
- On C(absent) will remove a proxy if it exists.
required: false
- choices: ['present', 'absent']
+ choices: ["present", "absent"]
default: "present"
type: str
interface:
description:
- Dictionary with params for the interface when proxy is in passive mode.
- For more information, review proxy interface documentation at
- - U(https://www.zabbix.com/documentation/4.0/manual/api/reference/proxy/object#proxy_interface).
+ - U(https://www.zabbix.com/documentation/current/en/manual/api/reference/proxy/object#proxy-interface).
required: false
suboptions:
useip:
@@ -120,53 +119,37 @@ options:
description:
- IP address used by proxy interface.
- Required if I(useip=1).
- default: ''
+ default: ""
dns:
type: str
description:
- DNS name of the proxy interface.
- Required if I(useip=0).
- default: ''
+ default: ""
port:
type: str
description:
- Port used by proxy interface.
- default: '10051'
- type:
- type: int
- description:
- - Interface type to add.
- - This suboption is currently ignored for Zabbix proxy.
- - This suboption is deprecated since Ansible 2.10 and will eventually be removed in 2.14.
- required: false
- default: 0
- main:
- type: int
- description:
- - Whether the interface is used as default.
- - This suboption is currently ignored for Zabbix proxy.
- - This suboption is deprecated since Ansible 2.10 and will eventually be removed in 2.14.
- required: false
- default: 0
+ default: "10051"
default: {}
type: dict
extends_documentation_fragment:
- community.zabbix.zabbix
-'''
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
# If you want to use Username and Password to be authenticated by Zabbix Server
- name: Set credentials to access Zabbix Server API
- set_fact:
+ ansible.builtin.set_fact:
ansible_user: Admin
ansible_httpapi_pass: zabbix
# If you want to use API token to be authenticated by Zabbix Server
# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens
- name: Set API token
- set_fact:
+ ansible.builtin.set_fact:
ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895
- name: Create or update a proxy with proxy type active
@@ -177,7 +160,7 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_proxy:
proxy_name: ExampleProxy
@@ -194,7 +177,7 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_proxy:
proxy_name: ExampleProxy
@@ -214,7 +197,7 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_proxy:
proxy_name: ExampleProxy
@@ -224,15 +207,14 @@ EXAMPLES = r'''
interface:
dns: proxy.example.com
port: 10051
-'''
+"""
-RETURN = r''' # '''
+RETURN = r""" # """
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase
-from ansible.module_utils.compat.version import LooseVersion
import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils
@@ -243,13 +225,13 @@ class Proxy(ZabbixBase):
self.existing_data = None
def proxy_exists(self, proxy_name):
- result = self._zapi.proxy.get({'output': 'extend',
- 'selectInterface': 'extend',
- 'filter': {'host': proxy_name}})
+ result = self._zapi.proxy.get({"output": "extend",
+ "selectInterface": "extend",
+ "filter": {"host": proxy_name}})
- if len(result) > 0 and 'proxyid' in result[0]:
+ if len(result) > 0 and "proxyid" in result[0]:
self.existing_data = result[0]
- return result[0]['proxyid']
+ return result[0]["proxyid"]
else:
return result
@@ -263,23 +245,19 @@ class Proxy(ZabbixBase):
if data[item]:
parameters[item] = data[item]
- if 'proxy_address' in data and data['status'] != '5':
- parameters.pop('proxy_address', False)
+ if "proxy_address" in data and data["status"] != "5":
+ parameters.pop("proxy_address", False)
- if 'interface' in data and data['status'] != '6':
- parameters.pop('interface', False)
- else:
- if LooseVersion(self._zbx_api_version) >= LooseVersion('6.0'):
- parameters['interface'].pop('type')
- parameters['interface'].pop('main')
+ if "interface" in data and data["status"] != "6":
+ parameters.pop("interface", False)
proxy_ids_list = self._zapi.proxy.create(parameters)
self._module.exit_json(changed=True,
- result="Successfully added proxy %s (%s)" % (data['host'], data['status']))
+ result="Successfully added proxy %s (%s)" % (data["host"], data["status"]))
if len(proxy_ids_list) >= 1:
- return proxy_ids_list['proxyids'][0]
+ return proxy_ids_list["proxyids"][0]
except Exception as e:
- self._module.fail_json(msg="Failed to create proxy %s: %s" % (data['host'], e))
+ self._module.fail_json(msg="Failed to create proxy %s: %s" % (data["host"], e))
def delete_proxy(self, proxy_id, proxy_name):
try:
@@ -299,33 +277,22 @@ class Proxy(ZabbixBase):
for key in data:
if data[key]:
parameters[key] = data[key]
- if 'interface' in parameters:
- if parameters['status'] == '5':
+ if "interface" in parameters:
+ if parameters["status"] == "5":
# Active proxy
- parameters.pop('interface', False)
+ parameters.pop("interface", False)
else:
# Passive proxy
- parameters['interface']['useip'] = str(parameters['interface']['useip'])
- if LooseVersion(self._zbx_api_version) >= LooseVersion('6.0.0'):
- parameters['interface'].pop('type', False)
- parameters['interface'].pop('main', False)
- else:
- parameters['interface']['type'] = '0'
- parameters['interface']['main'] = '1'
- if ('interface' in self.existing_data
- and isinstance(self.existing_data['interface'], dict)):
- new_interface = self.existing_data['interface'].copy()
- new_interface.update(parameters['interface'])
- parameters['interface'] = new_interface
-
- if parameters['status'] == '5':
+ parameters["interface"]["useip"] = str(parameters["interface"]["useip"])
+
+ if parameters["status"] == "5":
# Active proxy
- parameters.pop('tls_connect', False)
+ parameters.pop("tls_connect", False)
else:
# Passive proxy
- parameters.pop('tls_accept', False)
+ parameters.pop("tls_accept", False)
- parameters['proxyid'] = proxy_id
+ parameters["proxyid"] = proxy_id
change_parameters = {}
difference = zabbix_utils.helper_cleanup_data(zabbix_utils.helper_compare_dictionaries(parameters, self.existing_data, change_parameters))
@@ -333,43 +300,41 @@ class Proxy(ZabbixBase):
if difference == {}:
self._module.exit_json(changed=False)
else:
- difference['proxyid'] = proxy_id
+ difference["proxyid"] = proxy_id
self._zapi.proxy.update(parameters)
self._module.exit_json(
changed=True,
result="Successfully updated proxy %s (%s)" %
- (data['host'], proxy_id)
+ (data["host"], proxy_id)
)
except Exception as e:
self._module.fail_json(msg="Failed to update proxy %s: %s" %
- (data['host'], e))
+ (data["host"], e))
def main():
argument_spec = zabbix_utils.zabbix_common_argument_spec()
argument_spec.update(dict(
- proxy_name=dict(type='str', required=True),
- proxy_address=dict(type='str', required=False),
- status=dict(type='str', default="active", choices=['active', 'passive']),
- state=dict(type='str', default="present", choices=['present', 'absent']),
- description=dict(type='str', required=False),
- tls_connect=dict(type='str', default='no_encryption', choices=['no_encryption', 'PSK', 'certificate']),
- tls_accept=dict(type='str', default='no_encryption', choices=['no_encryption', 'PSK', 'certificate']),
- ca_cert=dict(type='str', required=False, default=None, aliases=['tls_issuer']),
- tls_subject=dict(type='str', required=False, default=None),
- tls_psk_identity=dict(type='str', required=False, default=None),
- tls_psk=dict(type='str', required=False, default=None, no_log=True),
+ proxy_name=dict(type="str", required=True),
+ proxy_address=dict(type="str", required=False),
+ status=dict(type="str", default="active", choices=["active", "passive"]),
+ state=dict(type="str", default="present", choices=["present", "absent"]),
+ description=dict(type="str", required=False),
+ tls_connect=dict(type="str", default="no_encryption", choices=["no_encryption", "PSK", "certificate"]),
+ tls_accept=dict(type="str", default="no_encryption", choices=["no_encryption", "PSK", "certificate"]),
+ ca_cert=dict(type="str", required=False, default=None, aliases=["tls_issuer"]),
+ tls_subject=dict(type="str", required=False, default=None),
+ tls_psk_identity=dict(type="str", required=False, default=None),
+ tls_psk=dict(type="str", required=False, default=None, no_log=True),
interface=dict(
- type='dict',
+ type="dict",
required=False,
default={},
options=dict(
- useip=dict(type='int', choices=[0, 1], default=0),
- ip=dict(type='str', default=''),
- dns=dict(type='str', default=''),
- port=dict(type='str', default='10051'),
- type=dict(type='int', default=0, removed_in_version="3.0.0", removed_from_collection='community.zabbix'), # was Ansible 2.14
- main=dict(type='int', default=0, removed_in_version="3.0.0", removed_from_collection='community.zabbix'), # was Ansible 2.14
+ useip=dict(type="int", choices=[0, 1], default=0),
+ ip=dict(type="str", default=""),
+ dns=dict(type="str", default=""),
+ port=dict(type="str", default="10051")
),
)
))
@@ -378,38 +343,32 @@ def main():
supports_check_mode=True
)
- zabbix_utils.require_creds_params(module)
-
- for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']:
- if p in module.params and not module.params[p] is None:
- module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p)
-
- proxy_name = module.params['proxy_name']
- proxy_address = module.params['proxy_address']
- description = module.params['description']
- status = module.params['status']
- tls_connect = module.params['tls_connect']
- tls_accept = module.params['tls_accept']
- tls_issuer = module.params['ca_cert']
- tls_subject = module.params['tls_subject']
- tls_psk_identity = module.params['tls_psk_identity']
- tls_psk = module.params['tls_psk']
- state = module.params['state']
- interface = module.params['interface']
+ proxy_name = module.params["proxy_name"]
+ proxy_address = module.params["proxy_address"]
+ description = module.params["description"]
+ status = module.params["status"]
+ tls_connect = module.params["tls_connect"]
+ tls_accept = module.params["tls_accept"]
+ tls_issuer = module.params["ca_cert"]
+ tls_subject = module.params["tls_subject"]
+ tls_psk_identity = module.params["tls_psk_identity"]
+ tls_psk = module.params["tls_psk"]
+ state = module.params["state"]
+ interface = module.params["interface"]
# convert enabled to 0; disabled to 1
status = 6 if status == "passive" else 5
- if tls_connect == 'certificate':
+ if tls_connect == "certificate":
tls_connect = 4
- elif tls_connect == 'PSK':
+ elif tls_connect == "PSK":
tls_connect = 2
else:
tls_connect = 1
- if tls_accept == 'certificate':
+ if tls_accept == "certificate":
tls_accept = 4
- elif tls_accept == 'PSK':
+ elif tls_accept == "PSK":
tls_accept = 2
else:
tls_accept = 1
@@ -425,17 +384,17 @@ def main():
proxy.delete_proxy(proxy_id, proxy_name)
else:
proxy.update_proxy(proxy_id, {
- 'host': proxy_name,
- 'description': description,
- 'status': str(status),
- 'tls_connect': str(tls_connect),
- 'tls_accept': str(tls_accept),
- 'tls_issuer': tls_issuer,
- 'tls_subject': tls_subject,
- 'tls_psk_identity': tls_psk_identity,
- 'tls_psk': tls_psk,
- 'interface': interface,
- 'proxy_address': proxy_address
+ "host": proxy_name,
+ "description": description,
+ "status": str(status),
+ "tls_connect": str(tls_connect),
+ "tls_accept": str(tls_accept),
+ "tls_issuer": tls_issuer,
+ "tls_subject": tls_subject,
+ "tls_psk_identity": tls_psk_identity,
+ "tls_psk": tls_psk,
+ "interface": interface,
+ "proxy_address": proxy_address
})
else:
if state == "absent":
@@ -443,19 +402,19 @@ def main():
module.exit_json(changed=False)
proxy_id = proxy.add_proxy(data={
- 'host': proxy_name,
- 'description': description,
- 'status': str(status),
- 'tls_connect': str(tls_connect),
- 'tls_accept': str(tls_accept),
- 'tls_issuer': tls_issuer,
- 'tls_subject': tls_subject,
- 'tls_psk_identity': tls_psk_identity,
- 'tls_psk': tls_psk,
- 'interface': interface,
- 'proxy_address': proxy_address
+ "host": proxy_name,
+ "description": description,
+ "status": str(status),
+ "tls_connect": str(tls_connect),
+ "tls_accept": str(tls_accept),
+ "tls_issuer": tls_issuer,
+ "tls_subject": tls_subject,
+ "tls_psk_identity": tls_psk_identity,
+ "tls_psk": tls_psk,
+ "interface": interface,
+ "proxy_address": proxy_address
})
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_proxy_info.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_proxy_info.py
index b40022883..c82112609 100644
--- a/ansible_collections/community/zabbix/plugins/modules/zabbix_proxy_info.py
+++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_proxy_info.py
@@ -8,7 +8,7 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type
-DOCUMENTATION = '''
+DOCUMENTATION = """
module: zabbix_proxy_info
short_description: Gather information about Zabbix proxy
version_added: 1.5.0
@@ -17,7 +17,7 @@ author:
description:
- This module allows you to obtain detailed information about configured zabbix proxies.
requirements:
- - "python >= 2.6"
+ - "python >= 3.9"
options:
proxy_name:
description:
@@ -33,19 +33,19 @@ options:
extends_documentation_fragment:
- community.zabbix.zabbix
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = """
# If you want to use Username and Password to be authenticated by Zabbix Server
- name: Set credentials to access Zabbix Server API
- set_fact:
+ ansible.builtin.set_fact:
ansible_user: Admin
ansible_httpapi_pass: zabbix
# If you want to use API token to be authenticated by Zabbix Server
# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens
- name: Set API token
- set_fact:
+ ansible.builtin.set_fact:
ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895
- name: Get zabbix proxy info alongside the list of hosts monitored by the proxy
@@ -56,17 +56,14 @@ EXAMPLES = '''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_proxy_info:
- server_url: "http://zabbix.example.com/zabbix/"
- login_user: admin
- login_password: secret
proxy_name: zbx01.example.com
proxy_hosts: true
-'''
+"""
-RETURN = '''
+RETURN = """
zabbix_proxy:
description: example
returned: always
@@ -120,7 +117,7 @@ zabbix_proxy:
"tls_subject": "",
"uuid": ""
}
-'''
+"""
from ansible.module_utils.basic import AnsibleModule
@@ -134,15 +131,15 @@ class Proxy(ZabbixBase):
def get_proxy(self, name, hosts=False):
result = {}
params = {
- 'filter': {
- 'host': name
+ "filter": {
+ "host": name
},
- 'output': 'extend',
- 'selectInterface': 'extend',
+ "output": "extend",
+ "selectInterface": "extend",
}
if hosts:
- params['selectHosts'] = ['host', 'hostid']
+ params["selectHosts"] = ["host", "hostid"]
try:
result = self._zapi.proxy.get(params)
@@ -155,8 +152,8 @@ class Proxy(ZabbixBase):
def main():
argument_spec = zabbix_utils.zabbix_common_argument_spec()
argument_spec.update(dict(
- proxy_name=dict(type='str', required=True),
- proxy_hosts=dict(type='bool', required=False, default=False),
+ proxy_name=dict(type="str", required=True),
+ proxy_hosts=dict(type="bool", required=False, default=False),
))
module = AnsibleModule(
@@ -164,14 +161,8 @@ def main():
supports_check_mode=True
)
- zabbix_utils.require_creds_params(module)
-
- for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']:
- if p in module.params and not module.params[p] is None:
- module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p)
-
- name = module.params['proxy_name']
- hosts = module.params['proxy_hosts']
+ name = module.params["proxy_name"]
+ hosts = module.params["proxy_hosts"]
proxy = Proxy(module)
result = proxy.get_proxy(name, hosts)
diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_regexp.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_regexp.py
new file mode 100644
index 000000000..fc3ccedee
--- /dev/null
+++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_regexp.py
@@ -0,0 +1,345 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright: (c) 2022, ONODERA Masaru <masaru-onodera@ieee.org>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+---
+module: zabbix_regexp
+
+short_description: Create/update/delete Zabbix regular expression
+
+
+description:
+ - This module allows you to create, update and delete Zabbix regular expression.
+
+author:
+ - ONODERA Masaru(@masa-orca)
+
+requirements:
+ - "python >= 3.9"
+
+version_added: 2.1.0
+
+options:
+ name:
+ description:
+ - Name of this regular expression
+ type: str
+ required: true
+ test_string:
+ description:
+ - A test string for this regular expression
+ type: str
+ expressions:
+ description:
+ - List of expressions.
+ - The regular expression returns true when all expressions return true.
+ - Required when C(state=present).
+ type: list
+ elements: dict
+ suboptions:
+ expression:
+ description:
+ - A expression string
+ type: str
+ required: true
+ expression_type:
+ description:
+ - A expression string
+ type: str
+ required: true
+ choices:
+ - "character_string_included"
+ - "any_character_string_included"
+ - "character_string_not_included"
+ - "result_is_true"
+ - "result_is_false"
+ exp_delimiter:
+ description:
+ - Delimiter for expression.
+ - Used if expression_type is C(any_character_string_included).
+ - Default values is C(,)
+ type: str
+ choices: [",", ".", "/"]
+ case_sensitive:
+ description:
+ - If true, the expression will be case sensitive.
+ type: bool
+ default: false
+ state:
+ description:
+ - State of the regular expression.
+ type: str
+ choices: ['present', 'absent']
+ default: 'present'
+
+
+notes:
+ - Only Zabbix >= 6.0 is supported.
+
+extends_documentation_fragment:
+ - community.zabbix.zabbix
+
+"""
+
+EXAMPLES = """
+# If you want to use Username and Password to be authenticated by Zabbix Server
+- name: Set credentials to access Zabbix Server API
+ ansible.builtin.set_fact:
+ ansible_user: Admin
+ ansible_httpapi_pass: zabbix
+
+# If you want to use API token to be authenticated by Zabbix Server
+# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens
+- name: Set API token
+ ansible.builtin.set_fact:
+ ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895
+
+- name: Update regexp of 'File systems for discovery'
+ # set task level variables as we change ansible_connection plugin here
+ vars:
+ ansible_network_os: community.zabbix.zabbix
+ ansible_connection: httpapi
+ ansible_httpapi_port: 443
+ ansible_httpapi_use_ssl: true
+ ansible_httpapi_validate_certs: false
+ ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_host: zabbix-example-fqdn.org
+ community.zabbix.zabbix_regexp:
+ name: File systems for discovery
+ test_string: ext2
+ expressions:
+ - expression: "^(btrfs|ext2|ext3|ext4|reiser|xfs|ffs|ufs|jfs|jfs2|vxfs|hfs|apfs|refs|ntfs|fat32|zfs)$"
+ expression_type: result_is_true
+"""
+
+RETURN = """
+msg:
+ description: The result of the operation
+ returned: success
+ type: str
+ sample: 'Successfully updated regular expression setting'
+"""
+
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase
+from ansible.module_utils.compat.version import LooseVersion
+
+import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils
+
+
+class RegularExpression(ZabbixBase):
+ def __init__(self, module, zbx=None, zapi_wrapper=None):
+ super(RegularExpression, self).__init__(module, zbx, zapi_wrapper)
+ if LooseVersion(self._zbx_api_version) < LooseVersion("6.0"):
+ module.fail_json(
+ msg="This module doesn't support Zabbix versions lower than 6.0"
+ )
+
+ def get_regexps(self, regexp_name):
+ try:
+ regexps = self._zapi.regexp.get(
+ {
+ "output": "extend",
+ "selectExpressions": [
+ "expression",
+ "expression_type",
+ "exp_delimiter",
+ "case_sensitive",
+ ],
+ "filter": {"name": regexp_name},
+ }
+ )
+ if len(regexps) >= 2:
+ self._module.fail_json("Too many regexps are matched.")
+ return regexps
+ except Exception as e:
+ self._module.fail_json(
+ msg="Failed to get regular expression setting: %s" % e
+ )
+
+ def delete_regexp(self, regexp):
+ try:
+ parameter = [regexp["regexpid"]]
+ if self._module.check_mode:
+ self._module.exit_json(changed=True)
+ self._zapi.regexp.delete(parameter)
+ self._module.exit_json(
+ changed=True, msg="Successfully deleted regular expression setting."
+ )
+ except Exception as e:
+ self._module.fail_json(
+ msg="Failed to delete regular expression setting: %s" % e
+ )
+
+ def _convert_expressions_to_json(self, expressions):
+ expression_type_values = [
+ "character_string_included",
+ "any_character_string_included",
+ "character_string_not_included",
+ "result_is_true",
+ "result_is_false",
+ ]
+
+ expression_jsons = []
+ for expression in expressions:
+ expression_json = {}
+
+ expression_json["expression"] = expression["expression"]
+ expression_type = zabbix_utils.helper_to_numeric_value(
+ expression_type_values, expression["expression_type"]
+ )
+ expression_json["expression_type"] = str(expression_type)
+ if expression["expression_type"] == "any_character_string_included":
+ if expression["exp_delimiter"]:
+ expression_json["exp_delimiter"] = expression["exp_delimiter"]
+ else:
+ expression_json["exp_delimiter"] = ","
+ elif expression["exp_delimiter"]:
+ self._module.warn(
+ "A value of exp_delimiter will be ignored because expression_type is not 'any_character_string_included'."
+ )
+ case_sensitive = "0"
+ if expression["case_sensitive"]:
+ case_sensitive = "1"
+ expression_json["case_sensitive"] = case_sensitive
+
+ expression_jsons.append(expression_json)
+ return expression_jsons
+
+ def create_regexp(self, name, test_string, expressions):
+ try:
+ if self._module.check_mode:
+ self._module.exit_json(changed=True)
+ self._zapi.regexp.create(
+ {
+ "name": name,
+ "test_string": test_string,
+ "expressions": self._convert_expressions_to_json(expressions),
+ }
+ )
+ self._module.exit_json(
+ changed=True, msg="Successfully created regular expression setting."
+ )
+ except Exception as e:
+ self._module.fail_json(
+ msg="Failed to create regular expression setting: %s" % e
+ )
+
+ def update_regexp(self, current_regexp, name, test_string, expressions):
+ try:
+ current_expressions = []
+ for expression in current_regexp["expressions"]:
+ if expression["expression_type"] != "1":
+ expression = zabbix_utils.helper_normalize_data(
+ expression, del_keys=["exp_delimiter"]
+ )[0]
+ current_expressions.append(expression)
+ future_expressions = self._convert_expressions_to_json(expressions)
+ diff_expressions = []
+ zabbix_utils.helper_compare_lists(
+ current_expressions, future_expressions, diff_expressions
+ )
+ if (
+ current_regexp["name"] == name
+ and current_regexp["test_string"] == test_string
+ and len(diff_expressions) == 0
+ ):
+ self._module.exit_json(changed=False)
+ else:
+ if self._module.check_mode:
+ self._module.exit_json(changed=True)
+ self._zapi.regexp.update(
+ {
+ "regexpid": current_regexp["regexpid"],
+ "name": name,
+ "test_string": test_string,
+ "expressions": future_expressions,
+ }
+ )
+ self._module.exit_json(
+ changed=True, msg="Successfully updated regular expression setting."
+ )
+ except Exception as e:
+ self._module.fail_json(
+ msg="Failed to update regular expression setting: %s" % e
+ )
+
+
+def main():
+ """Main ansible module function"""
+
+ argument_spec = zabbix_utils.zabbix_common_argument_spec()
+ argument_spec.update(
+ dict(
+ name=dict(type="str", required=True),
+ test_string=dict(
+ type="str",
+ ),
+ expressions=dict(
+ type="list",
+ elements="dict",
+ options=dict(
+ expression=dict(type="str", required=True),
+ expression_type=dict(
+ type="str",
+ required=True,
+ choices=[
+ "character_string_included",
+ "any_character_string_included",
+ "character_string_not_included",
+ "result_is_true",
+ "result_is_false",
+ ],
+ ),
+ exp_delimiter=dict(type="str", choices=[",", ".", "/"]),
+ case_sensitive=dict(type="bool", default=False),
+ ),
+ ),
+ state=dict(
+ type="str",
+ required=False,
+ default="present",
+ choices=["present", "absent"],
+ ),
+ )
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_if=[["state", "present", ["expressions"]]],
+ supports_check_mode=True,
+ )
+
+ name = module.params["name"]
+ test_string = module.params["test_string"]
+ expressions = module.params["expressions"]
+ state = module.params["state"]
+
+ regexp_class_obj = RegularExpression(module)
+ regexps = regexp_class_obj.get_regexps(name)
+
+ if state == "absent":
+ if len(regexps) == 1:
+ regexp_class_obj.delete_regexp(regexps[0])
+ else:
+ module.exit_json(changed=False)
+ else:
+ if len(regexps) == 1:
+ regexp_class_obj.update_regexp(regexps[0], name, test_string, expressions)
+ else:
+ regexp_class_obj.create_regexp(name, test_string, expressions)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_screen.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_screen.py
deleted file mode 100644
index 5e350fc80..000000000
--- a/ansible_collections/community/zabbix/plugins/modules/zabbix_screen.py
+++ /dev/null
@@ -1,496 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# (c) 2013-2014, Epic Games, Inc.
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = r'''
----
-module: zabbix_screen
-short_description: Create/update/delete Zabbix screens
-description:
- - This module allows you to create, modify and delete Zabbix screens and associated graph data.
-author:
- - "Cove (@cove)"
- - "Tony Minfei Ding (!UNKNOWN)"
- - "Harrison Gu (@harrisongu)"
-requirements:
- - "python >= 2.6"
- - "Zabbix <= 5.2"
-options:
- screens:
- description:
- - List of screens to be created/updated/deleted (see example).
- type: list
- elements: dict
- required: true
- suboptions:
- screen_name:
- description:
- - Screen name will be used.
- - If a screen has already been added, the screen name won't be updated.
- type: str
- required: true
- host_group:
- description:
- - Host group(s) will be used for searching hosts.
- - Required if I(state=present).
- type: list
- elements: str
- aliases: [ 'host_groups' ]
- state:
- description:
- - I(present) - Create a screen if it doesn't exist. If the screen already exists, the screen will be updated as needed.
- - I(absent) - If a screen exists, the screen will be deleted.
- type: str
- default: present
- choices:
- - absent
- - present
- graph_names:
- description:
- - Graph names will be added to a screen. Case insensitive.
- - Required if I(state=present).
- type: list
- elements: str
- graph_width:
- description:
- - Graph width will be set in graph settings.
- type: int
- graph_height:
- description:
- - Graph height will be set in graph settings.
- type: int
- graphs_in_row:
- description:
- - Limit columns of a screen and make multiple rows.
- type: int
- default: 3
- sort:
- description:
- - Sort hosts alphabetically.
- - If there are numbers in hostnames, leading zero should be used.
- type: bool
- default: no
-
-extends_documentation_fragment:
-- community.zabbix.zabbix
-
-
-notes:
- - Too many concurrent updates to the same screen may cause Zabbix to return errors, see examples for a workaround if needed.
- - Screens where removed from Zabbix with Version 5.4
-'''
-
-EXAMPLES = r'''
-# If you want to use Username and Password to be authenticated by Zabbix Server
-- name: Set credentials to access Zabbix Server API
- set_fact:
- ansible_user: Admin
- ansible_httpapi_pass: zabbix
-
-# If you want to use API token to be authenticated by Zabbix Server
-# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens
-- name: Set API token
- set_fact:
- ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895
-
-# Screens where removed from Zabbix with Version 5.4
-
-# Create/update a screen.
-- name: Create a new screen or update an existing screen's items 5 in a row
- # set task level variables as we change ansible_connection plugin here
- vars:
- ansible_network_os: community.zabbix.zabbix
- ansible_connection: httpapi
- ansible_httpapi_port: 443
- ansible_httpapi_use_ssl: true
- ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
- ansible_host: zabbix-example-fqdn.org
- community.zabbix.zabbix_screen:
- screens:
- - screen_name: ExampleScreen1
- host_group: Example group1
- state: present
- graph_names:
- - Example graph1
- - Example graph2
- graph_width: 200
- graph_height: 100
- graphs_in_row: 5
-
-# Create/update multi-screen
-- name: Create two of new screens or update the existing screens' items
- # set task level variables as we change ansible_connection plugin here
- vars:
- ansible_network_os: community.zabbix.zabbix
- ansible_connection: httpapi
- ansible_httpapi_port: 443
- ansible_httpapi_use_ssl: true
- ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
- ansible_host: zabbix-example-fqdn.org
- community.zabbix.zabbix_screen:
- screens:
- - screen_name: ExampleScreen1
- host_group: Example group1
- state: present
- graph_names:
- - Example graph1
- - Example graph2
- graph_width: 200
- graph_height: 100
- - screen_name: ExampleScreen2
- host_group: Example group2
- state: present
- graph_names:
- - Example graph1
- - Example graph2
- graph_width: 200
- graph_height: 100
-
-# Limit the Zabbix screen creations to one host since Zabbix can return an error when doing concurrent updates
-- name: Create a new screen or update an existing screen's items
- # set task level variables as we change ansible_connection plugin here
- vars:
- ansible_network_os: community.zabbix.zabbix
- ansible_connection: httpapi
- ansible_httpapi_port: 443
- ansible_httpapi_use_ssl: true
- ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
- ansible_host: zabbix-example-fqdn.org
- community.zabbix.zabbix_screen:
- state: present
- screens:
- - screen_name: ExampleScreen
- host_group: Example group
- state: present
- graph_names:
- - Example graph1
- - Example graph2
- graph_width: 200
- graph_height: 100
- when: inventory_hostname==groups['group_name'][0]
-
-# Create/update using multiple hosts_groups. Hosts NOT present in all listed host_groups will be skipped.
-- name: Create new screen or update the existing screen's items for hosts in both given groups
- # set task level variables as we change ansible_connection plugin here
- vars:
- ansible_network_os: community.zabbix.zabbix
- ansible_connection: httpapi
- ansible_httpapi_port: 443
- ansible_httpapi_use_ssl: true
- ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
- ansible_host: zabbix-example-fqdn.org
- community.zabbix.zabbix_screen:
- screens:
- - screen_name: ExampleScreen1
- host_group:
- - Example group1
- - Example group2
- state: present
- graph_names:
- - Example graph1
- - Example graph2
- graph_width: 200
- graph_height: 100
-'''
-
-
-from ansible.module_utils.basic import AnsibleModule
-
-from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase
-from ansible_collections.community.zabbix.plugins.module_utils.wrappers import ScreenItem
-from ansible.module_utils.compat.version import LooseVersion
-
-import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils
-
-
-class Screen(ZabbixBase):
- # get list of group ids by list of group names
- def get_host_group_ids(self, group_names):
- if not group_names:
- self._module.fail_json(msg="group_name is required")
- hostGroup_list = self._zapi.hostgroup.get({'output': 'extend', 'filter': {'name': group_names}})
- if not hostGroup_list:
- self._module.fail_json(msg="Host group not found: {0}".format(group_names))
- else:
- hostGroup_ids = [g['groupid'] for g in hostGroup_list]
- return hostGroup_ids
-
- # get monitored host_ids by host_group_ids
- # (the hosts belonging to all given groups)
- def get_host_ids_by_group_ids(self, group_ids, sort):
- host_list = self._zapi.host.get({'output': 'extend', 'selectGroups': 'groupid', 'groupids': group_ids, 'monitored_hosts': 1})
- if not host_list:
- self._module.fail_json(msg="No hosts in the all group(s) with ids {0}".format(group_ids))
- else:
- if sort:
- host_list = sorted(host_list, key=lambda name: name['name'])
- host_ids = []
- for host in host_list:
- host_group_ids = [g['groupid'] for g in host['groups']]
- # Check if all search group ids are in hosts group ids
- if set(group_ids).issubset(host_group_ids):
- host_id = host['hostid']
- host_ids.append(host_id)
- return host_ids
-
- # get screen
- def get_screen_id(self, screen_name):
- if screen_name == "":
- self._module.fail_json(msg="screen_name is required")
- try:
- screen_id_list = self._zapi.screen.get({'output': 'extend', 'search': {"name": screen_name}})
- if len(screen_id_list) >= 1:
- screen_id = screen_id_list[0]['screenid']
- return screen_id
- return None
- except Exception as e:
- self._module.fail_json(msg="Failed to get screen %s from Zabbix: %s" % (screen_name, e))
-
- # create screen
- def create_screen(self, screen_name, h_size, v_size):
- try:
- if self._module.check_mode:
- self._module.exit_json(changed=True)
- screen = self._zapi.screen.create({'name': screen_name, 'hsize': h_size, 'vsize': v_size})
- return screen['screenids'][0]
- except Exception as e:
- self._module.fail_json(msg="Failed to create screen %s: %s" % (screen_name, e))
-
- # update screen
- def update_screen(self, screen_id, screen_name, h_size, v_size):
- try:
- if self._module.check_mode:
- self._module.exit_json(changed=True)
- self._zapi.screen.update({'screenid': screen_id, 'hsize': h_size, 'vsize': v_size})
- except Exception as e:
- self._module.fail_json(msg="Failed to update screen %s: %s" % (screen_name, e))
-
- # delete screen
- def delete_screen(self, screen_id, screen_name):
- try:
- if self._module.check_mode:
- self._module.exit_json(changed=True)
- self._zapi.screen.delete([screen_id])
- except Exception as e:
- self._module.fail_json(msg="Failed to delete screen %s: %s" % (screen_name, e))
-
- # get graph ids
- def get_graph_ids(self, hosts, graph_name_list):
- graph_id_lists = []
- vsize = 1
- for host in hosts:
- graph_id_list = self.get_graphs_by_host_id(graph_name_list, host)
- size = len(graph_id_list)
- if size > 0:
- graph_id_lists.extend(graph_id_list)
- if vsize < size:
- vsize = size
- return graph_id_lists, vsize
-
- # getGraphs
- def get_graphs_by_host_id(self, graph_name_list, host_id):
- graph_ids = []
- for graph_name in graph_name_list:
- graphs_list = self._zapi.graph.get({'output': 'extend', 'search': {'name': graph_name}, 'hostids': host_id})
- graph_id_list = []
- if len(graphs_list) > 0:
- for graph in graphs_list:
- graph_id = graph['graphid']
- graph_id_list.append(graph_id)
- if len(graph_id_list) > 0:
- graph_ids.extend(graph_id_list)
- return graph_ids
-
- # get screen items
- def get_screen_items(self, screen_id):
- screen_item_list = self._zapi.screenitem.get({'output': 'extend', 'screenids': screen_id})
- return screen_item_list
-
- # delete screen items
- def delete_screen_items(self, screen_id, screen_item_id_list):
- if len(screen_item_id_list) == 0:
- return True
- screen_item_list = self.get_screen_items(screen_id)
- if len(screen_item_list) > 0:
- if self._module.check_mode:
- self._module.exit_json(changed=True)
- ScreenItem.delete(self, screen_item_id_list)
- return True
- return False
-
- # get screen's hsize and vsize
- def get_hsize_vsize(self, hosts, v_size, graphs_in_row):
- h_size = len(hosts)
- # when there is only one host, put all graphs in a row
- if h_size == 1:
- if v_size <= graphs_in_row:
- h_size = v_size
- else:
- h_size = graphs_in_row
- v_size = (v_size - 1) // h_size + 1
- # when len(hosts) is more then graphs_in_row
- elif len(hosts) > graphs_in_row:
- h_size = graphs_in_row
- v_size = (len(hosts) // graphs_in_row + 1) * v_size
-
- return h_size, v_size
-
- # create screen_items
- def create_screen_items(self, screen_id, hosts, graph_name_list, width, height, h_size, graphs_in_row):
- if len(hosts) < 4:
- if width is None or width < 0:
- width = 500
- else:
- if width is None or width < 0:
- width = 200
- if height is None or height < 0:
- height = 100
-
- # when there're only one host, only one row is not good.
- if len(hosts) == 1:
- graph_id_list = self.get_graphs_by_host_id(graph_name_list, hosts[0])
- for i, graph_id in enumerate(graph_id_list):
- if graph_id is not None:
- ScreenItem.create(self, ignoreExists=True, data={'screenid': screen_id, 'resourcetype': 0, 'resourceid': graph_id,
- 'width': width, 'height': height,
- 'x': i % h_size, 'y': i // h_size, 'colspan': 1, 'rowspan': 1,
- 'elements': 0, 'valign': 0, 'halign': 0,
- 'style': 0, 'dynamic': 0, 'sort_triggers': 0})
- else:
- for i, host in enumerate(hosts):
- graph_id_list = self.get_graphs_by_host_id(graph_name_list, host)
- for j, graph_id in enumerate(graph_id_list):
- if graph_id is not None:
- ScreenItem.create(self, ignoreExists=True, data={'screenid': screen_id, 'resourcetype': 0, 'resourceid': graph_id,
- 'width': width, 'height': height,
- 'x': i % graphs_in_row, 'y': len(graph_id_list) * (i // graphs_in_row) + j,
- 'colspan': 1, 'rowspan': 1,
- 'elements': 0, 'valign': 0, 'halign': 0,
- 'style': 0, 'dynamic': 0, 'sort_triggers': 0})
-
-
-def main():
- argument_spec = zabbix_utils.zabbix_common_argument_spec()
- argument_spec.update(dict(
- screens=dict(
- type='list',
- elements='dict',
- required=True,
- options=dict(
- screen_name=dict(type='str', required=True),
- host_group=dict(type='list', aliases=['host_groups'], elements='str'),
- state=dict(type='str', default='present', choices=['absent', 'present']),
- graph_names=dict(type='list', elements='str'),
- graph_width=dict(type='int', default=None),
- graph_height=dict(type='int', default=None),
- graphs_in_row=dict(type='int', default=3),
- sort=dict(default=False, type='bool'),
- ),
- required_if=[
- ['state', 'present', ['host_group']]
- ]
- )
- ))
- module = AnsibleModule(
- argument_spec=argument_spec,
- supports_check_mode=True
- )
-
- zabbix_utils.require_creds_params(module)
-
- for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']:
- if p in module.params and not module.params[p] is None:
- module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p)
-
- screens = module.params['screens']
-
- screen = Screen(module)
- if LooseVersion(screen._zbx_api_version) >= LooseVersion('5.4'):
- module.fail_json(msg="Zabbix 5.4 removed the Screens feature see (%s)." % (
- "https://www.zabbix.com/documentation/current/en/manual/api/changes_5.2_-_5.4"
- ))
-
- created_screens = []
- changed_screens = []
- deleted_screens = []
-
- for zabbix_screen in screens:
- screen_name = zabbix_screen['screen_name']
- screen_id = screen.get_screen_id(screen_name)
- state = zabbix_screen['state']
- sort = zabbix_screen['sort']
-
- if state == "absent":
- if screen_id:
- screen_item_list = screen.get_screen_items(screen_id)
- screen_item_id_list = []
- for screen_item in screen_item_list:
- screen_item_id = screen_item['screenitemid']
- screen_item_id_list.append(screen_item_id)
- screen.delete_screen_items(screen_id, screen_item_id_list)
- screen.delete_screen(screen_id, screen_name)
-
- deleted_screens.append(screen_name)
- else:
- host_group = zabbix_screen['host_group']
- graph_names = zabbix_screen['graph_names']
- graphs_in_row = zabbix_screen['graphs_in_row']
- graph_width = zabbix_screen['graph_width']
- graph_height = zabbix_screen['graph_height']
- host_group_ids = screen.get_host_group_ids(host_group)
- hosts = screen.get_host_ids_by_group_ids(host_group_ids, sort)
- if not hosts:
- module.fail_json(msg="No hosts found belongin to all given groups: %s" % host_group)
- screen_item_id_list = []
- resource_id_list = []
-
- graph_ids, v_size = screen.get_graph_ids(hosts, graph_names)
- h_size, v_size = screen.get_hsize_vsize(hosts, v_size, graphs_in_row)
-
- if not screen_id:
- # create screen
- screen_id = screen.create_screen(screen_name, h_size, v_size)
- screen.create_screen_items(screen_id, hosts, graph_names, graph_width, graph_height, h_size, graphs_in_row)
- created_screens.append(screen_name)
- else:
- screen_item_list = screen.get_screen_items(screen_id)
-
- for screen_item in screen_item_list:
- screen_item_id = screen_item['screenitemid']
- resource_id = screen_item['resourceid']
- screen_item_id_list.append(screen_item_id)
- resource_id_list.append(resource_id)
-
- # when the screen items changed, then update
- if graph_ids != resource_id_list:
- deleted = screen.delete_screen_items(screen_id, screen_item_id_list)
- if deleted:
- screen.update_screen(screen_id, screen_name, h_size, v_size)
- screen.create_screen_items(screen_id, hosts, graph_names, graph_width, graph_height, h_size, graphs_in_row)
- changed_screens.append(screen_name)
-
- if created_screens and changed_screens:
- module.exit_json(changed=True, result="Successfully created screen(s): %s, and updated screen(s): %s" % (",".join(created_screens),
- ",".join(changed_screens)))
- elif created_screens:
- module.exit_json(changed=True, result="Successfully created screen(s): %s" % ",".join(created_screens))
- elif changed_screens:
- module.exit_json(changed=True, result="Successfully updated screen(s): %s" % ",".join(changed_screens))
- elif deleted_screens:
- module.exit_json(changed=True, result="Successfully deleted screen(s): %s" % ",".join(deleted_screens))
- else:
- module.exit_json(changed=False)
-
-
-if __name__ == '__main__':
- main()
diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_script.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_script.py
index 15277b0fa..643851885 100644
--- a/ansible_collections/community/zabbix/plugins/modules/zabbix_script.py
+++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_script.py
@@ -8,7 +8,7 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type
-DOCUMENTATION = '''
+DOCUMENTATION = """
module: zabbix_script
short_description: Create/update/delete Zabbix scripts
version_added: 1.7.0
@@ -17,7 +17,7 @@ author:
description:
- This module allows you to create, update and delete scripts.
requirements:
- - "python >= 2.6"
+ - "python >= 3.9"
options:
name:
description:
@@ -27,10 +27,9 @@ options:
script_type:
description:
- Script type.
- - Types C(ssh), C(telnet) and C(webhook) works only with Zabbix >= 5.4.
type: str
required: true
- choices: ['script', 'ipmi', 'ssh', 'telnet', 'webhook']
+ choices: ["script", "ipmi", "ssh", "telnet", "webhook"]
command:
description:
- Command to run.
@@ -39,24 +38,22 @@ options:
scope:
description:
- Script scope.
- - Works only with Zabbix >= 5.4. For lower versions is silently ignored which is equivalent of C(manual_host_action).
type: str
required: false
- choices: ['action_operation', 'manual_host_action', 'manual_event_action']
- default: 'action_operation'
+ choices: ["action_operation", "manual_host_action", "manual_event_action"]
+ default: "action_operation"
execute_on:
description:
- Where to run the script.
- Used if type is C(script).
type: str
required: false
- choices: ['zabbix_agent', 'zabbix_server', 'zabbix_server_proxy']
- default: 'zabbix_server_proxy'
+ choices: ["zabbix_agent", "zabbix_server", "zabbix_server_proxy"]
+ default: "zabbix_server_proxy"
menu_path:
description:
- Folders separated by slash that form a menu like navigation in frontend when clicked on host or event.
- Used if scope is C(manual_host_action) or C(manual_event_action).
- - Works only with Zabbix >= 5.4. For lower versions is silently ignored. Prepend menu path to name instead.
type: str
required: false
authtype:
@@ -65,7 +62,7 @@ options:
- Used if type is C(ssh).
type: str
required: false
- choices: ['password', 'public_key']
+ choices: ["password", "public_key"]
username:
description:
- User name used for authentication.
@@ -98,25 +95,25 @@ options:
required: false
host_group:
description:
- - host group name that the script can be run on. If set to 'all', the script will be available on all host groups.
+ - host group name that the script can be run on. If set to "all", the script will be available on all host groups.
type: str
required: false
- default: 'all'
+ default: "all"
user_group:
description:
- - user group name that will be allowed to run the script. If set to 'all', the script will be available for all user groups.
+ - user group name that will be allowed to run the script. If set to "all", the script will be available for all user groups.
- Used if scope is C(manual_host_action) or C(manual_event_action).
type: str
required: false
- default: 'all'
+ default: "all"
host_access:
description:
- Host permissions needed to run the script.
- Used if scope is C(manual_host_action) or C(manual_event_action).
type: str
required: false
- choices: ['read', 'write']
- default: 'read'
+ choices: ["read", "write"]
+ default: "read"
confirmation:
description:
- Confirmation pop up text. The pop up will appear when trying to run the script from the Zabbix frontend.
@@ -127,9 +124,9 @@ options:
description:
- Webhook script execution timeout in seconds. Time suffixes are supported, e.g. 30s, 1m.
- Required if type is C(webhook).
- - 'Possible values: 1-60s.'
+ - "Possible values: 1-60s."
type: str
- default: '30s'
+ default: "30s"
required: false
parameters:
description:
@@ -148,7 +145,7 @@ options:
- Parameter value. Supports macros.
type: str
required: false
- default: ''
+ default: ""
description:
description:
- Description of the script.
@@ -159,24 +156,24 @@ options:
- State of the script.
type: str
required: false
- choices: ['present', 'absent']
- default: 'present'
+ choices: ["present", "absent"]
+ default: "present"
extends_documentation_fragment:
- community.zabbix.zabbix
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = """
# If you want to use Username and Password to be authenticated by Zabbix Server
- name: Set credentials to access Zabbix Server API
- set_fact:
+ ansible.builtin.set_fact:
ansible_user: Admin
ansible_httpapi_pass: zabbix
# If you want to use API token to be authenticated by Zabbix Server
# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens
- name: Set API token
- set_fact:
+ ansible.builtin.set_fact:
ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895
- name: test - Create new action operation script to execute webhook
@@ -187,34 +184,33 @@ EXAMPLES = '''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
- zabbix_script:
+ community.zabbix.zabbix_script:
name: Test action operation script
scope: action_operation
script_type: webhook
- command: 'return 0'
+ command: "return 0"
description: "Test action operation script"
state: present
-'''
+"""
-RETURN = '''
-'''
+RETURN = """
+"""
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase
-from ansible.module_utils.compat.version import LooseVersion
import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils
class Script(ZabbixBase):
def get_script_ids(self, script_name):
script_ids = []
- scripts = self._zapi.script.get({'filter': {'name': script_name}})
+ scripts = self._zapi.script.get({"filter": {"name": script_name}})
for script in scripts:
- script_ids.append(script['scriptid'])
+ script_ids.append(script["scriptid"])
return script_ids
def create_script(self, name, script_type, command, scope, execute_on, menu_path, authtype, username, password,
@@ -233,103 +229,95 @@ class Script(ZabbixBase):
def generate_script_config(self, name, script_type, command, scope, execute_on, menu_path, authtype, username, password,
publickey, privatekey, port, host_group, user_group, host_access, confirmation, script_timeout, parameters, description):
- if host_group == 'all':
- groupid = '0'
+ if host_group == "all":
+ groupid = "0"
else:
- groups = self._zapi.hostgroup.get({'filter': {'name': host_group}})
+ groups = self._zapi.hostgroup.get({"filter": {"name": host_group}})
if not groups:
- self._module.fail_json(changed=False, msg='Host group "%s" not found' % host_group)
- groupid = groups[0]['groupid']
+ self._module.fail_json(changed=False, msg="Host group '%s' not found" % host_group)
+ groupid = groups[0]["groupid"]
- if user_group == 'all':
- usrgrpid = '0'
+ if user_group == "all":
+ usrgrpid = "0"
else:
- user_groups = self._zapi.usergroup.get({'filter': {'name': user_group}})
+ user_groups = self._zapi.usergroup.get({"filter": {"name": user_group}})
if not user_groups:
- self._module.fail_json(changed=False, msg='User group "%s" not found' % user_group)
- usrgrpid = user_groups[0]['usrgrpid']
+ self._module.fail_json(changed=False, msg="User group '%s' not found" % user_group)
+ usrgrpid = user_groups[0]["usrgrpid"]
request = {
- 'name': name,
- 'type': str(zabbix_utils.helper_to_numeric_value([
- 'script',
- 'ipmi',
- 'ssh',
- 'telnet',
- '',
- 'webhook'], script_type)),
- 'command': command,
- 'scope': str(zabbix_utils.helper_to_numeric_value([
- '',
- 'action_operation',
- 'manual_host_action',
- '',
- 'manual_event_action'], scope)),
- 'groupid': groupid
+ "name": name,
+ "type": str(zabbix_utils.helper_to_numeric_value([
+ "script",
+ "ipmi",
+ "ssh",
+ "telnet",
+ "",
+ "webhook"], script_type)),
+ "command": command,
+ "scope": str(zabbix_utils.helper_to_numeric_value([
+ "",
+ "action_operation",
+ "manual_host_action",
+ "",
+ "manual_event_action"], scope)),
+ "groupid": groupid
}
if description is not None:
- request['description'] = description
+ request["description"] = description
- if script_type == 'script':
+ if script_type == "script":
if execute_on is None:
- execute_on = 'zabbix_server_proxy'
- request['execute_on'] = str(zabbix_utils.helper_to_numeric_value([
- 'zabbix_agent',
- 'zabbix_server',
- 'zabbix_server_proxy'], execute_on))
+ execute_on = "zabbix_server_proxy"
+ request["execute_on"] = str(zabbix_utils.helper_to_numeric_value([
+ "zabbix_agent",
+ "zabbix_server",
+ "zabbix_server_proxy"], execute_on))
- if scope in ['manual_host_action', 'manual_event_action']:
+ if scope in ["manual_host_action", "manual_event_action"]:
if menu_path is None:
- request['menu_path'] = ''
+ request["menu_path"] = ""
else:
- request['menu_path'] = menu_path
- request['usrgrpid'] = usrgrpid
- request['host_access'] = str(zabbix_utils.helper_to_numeric_value([
- '',
- '',
- 'read',
- 'write'], host_access))
+ request["menu_path"] = menu_path
+ request["usrgrpid"] = usrgrpid
+ request["host_access"] = str(zabbix_utils.helper_to_numeric_value([
+ "",
+ "",
+ "read",
+ "write"], host_access))
if confirmation is None:
- request['confirmation'] = ''
+ request["confirmation"] = ""
else:
- request['confirmation'] = confirmation
+ request["confirmation"] = confirmation
- if script_type == 'ssh':
+ if script_type == "ssh":
if authtype is None:
- self._module.fail_json(changed=False, msg='authtype must be provided for ssh script type')
- request['authtype'] = str(zabbix_utils.helper_to_numeric_value([
- 'password',
- 'public_key'], authtype))
- if authtype == 'public_key':
+ self._module.fail_json(changed=False, msg="authtype must be provided for ssh script type")
+ request["authtype"] = str(zabbix_utils.helper_to_numeric_value([
+ "password",
+ "public_key"], authtype))
+ if authtype == "public_key":
if publickey is None or privatekey is None:
- self._module.fail_json(changed=False, msg='publickey and privatekey must be provided for ssh script type with publickey authtype')
- request['publickey'] = publickey
- request['privatekey'] = privatekey
+ self._module.fail_json(changed=False, msg="publickey and privatekey must be provided for ssh script type with publickey authtype")
+ request["publickey"] = publickey
+ request["privatekey"] = privatekey
- if script_type in ['ssh', 'telnet']:
+ if script_type in ["ssh", "telnet"]:
if username is None:
- self._module.fail_json(changed=False, msg='username must be provided for "ssh" and "telnet" script types')
- request['username'] = username
- if (script_type == 'ssh' and authtype == 'password') or script_type == 'telnet':
+ self._module.fail_json(changed=False, msg="username must be provided for 'ssh' and 'telnet' script types")
+ request["username"] = username
+ if (script_type == "ssh" and authtype == "password") or script_type == "telnet":
if password is None:
- self._module.fail_json(changed=False, msg='password must be provided for telnet script type or ssh script type with password autheype')
- request['password'] = password
+ self._module.fail_json(changed=False, msg="password must be provided for telnet script type or ssh script type with password autheype")
+ request["password"] = password
if port is not None:
- request['port'] = port
+ request["port"] = port
- if script_type == 'webhook':
- request['timeout'] = script_timeout
+ if script_type == "webhook":
+ request["timeout"] = script_timeout
if parameters:
- request['parameters'] = parameters
-
- if LooseVersion(self._zbx_api_version) < LooseVersion('5.4'):
- if script_type not in ['script', 'ipmi']:
- self._module.fail_json(changed=False, msg='script_type must be script or ipmi in version <5.4')
- if 'scope' in request:
- del request['scope']
- if 'menu_path' in request:
- del request['menu_path']
+ request["parameters"] = parameters
return request
@@ -338,7 +326,7 @@ class Script(ZabbixBase):
generated_config = self.generate_script_config(name, script_type, command, scope, execute_on, menu_path, authtype, username,
password, publickey, privatekey, port, host_group, user_group, host_access,
confirmation, script_timeout, parameters, description)
- live_config = self._zapi.script.get({'filter': {'name': name}})[0]
+ live_config = self._zapi.script.get({"filter": {"name": name}})[0]
change_parameters = {}
difference = zabbix_utils.helper_cleanup_data(zabbix_utils.helper_compare_dictionaries(generated_config, live_config, change_parameters))
@@ -348,7 +336,7 @@ class Script(ZabbixBase):
if self._module.check_mode:
self._module.exit_json(changed=True)
- generated_config['scriptid'] = live_config['scriptid']
+ generated_config["scriptid"] = live_config["scriptid"]
self._zapi.script.update(generated_config)
self._module.exit_json(changed=True, msg="Script %s updated" % name)
@@ -356,55 +344,55 @@ class Script(ZabbixBase):
def main():
argument_spec = zabbix_utils.zabbix_common_argument_spec()
argument_spec.update(dict(
- name=dict(type='str', required=True),
+ name=dict(type="str", required=True),
script_type=dict(
- type='str',
+ type="str",
required=True,
- choices=['script', 'ipmi', 'ssh', 'telnet', 'webhook']),
- command=dict(type='str', required=True),
+ choices=["script", "ipmi", "ssh", "telnet", "webhook"]),
+ command=dict(type="str", required=True),
scope=dict(
- type='str',
+ type="str",
required=False,
- choices=['action_operation', 'manual_host_action', 'manual_event_action'],
- default='action_operation'),
+ choices=["action_operation", "manual_host_action", "manual_event_action"],
+ default="action_operation"),
execute_on=dict(
- type='str',
+ type="str",
required=False,
- choices=['zabbix_agent', 'zabbix_server', 'zabbix_server_proxy'],
- default='zabbix_server_proxy'),
- menu_path=dict(type='str', required=False),
+ choices=["zabbix_agent", "zabbix_server", "zabbix_server_proxy"],
+ default="zabbix_server_proxy"),
+ menu_path=dict(type="str", required=False),
authtype=dict(
- type='str',
+ type="str",
required=False,
- choices=['password', 'public_key']),
- username=dict(type='str', required=False),
- password=dict(type='str', required=False, no_log=True),
- publickey=dict(type='str', required=False),
- privatekey=dict(type='str', required=False, no_log=True),
- port=dict(type='str', required=False),
- host_group=dict(type='str', required=False, default='all'),
- user_group=dict(type='str', required=False, default='all'),
+ choices=["password", "public_key"]),
+ username=dict(type="str", required=False),
+ password=dict(type="str", required=False, no_log=True),
+ publickey=dict(type="str", required=False),
+ privatekey=dict(type="str", required=False, no_log=True),
+ port=dict(type="str", required=False),
+ host_group=dict(type="str", required=False, default="all"),
+ user_group=dict(type="str", required=False, default="all"),
host_access=dict(
- type='str',
+ type="str",
required=False,
- choices=['read', 'write'],
- default='read'),
- confirmation=dict(type='str', required=False),
- script_timeout=dict(type='str', default='30s', required=False),
+ choices=["read", "write"],
+ default="read"),
+ confirmation=dict(type="str", required=False),
+ script_timeout=dict(type="str", default="30s", required=False),
parameters=dict(
- type='list',
- elements='dict',
+ type="list",
+ elements="dict",
options=dict(
- name=dict(type='str', required=True),
- value=dict(type='str', required=False, default='')
+ name=dict(type="str", required=True),
+ value=dict(type="str", required=False, default="")
)
),
- description=dict(type='str', required=False),
+ description=dict(type="str", required=False),
state=dict(
- type='str',
+ type="str",
required=False,
- default='present',
- choices=['present', 'absent'])
+ default="present",
+ choices=["present", "absent"])
))
module = AnsibleModule(
@@ -412,32 +400,26 @@ def main():
supports_check_mode=True
)
- zabbix_utils.require_creds_params(module)
-
- for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']:
- if p in module.params and not module.params[p] is None:
- module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p)
-
- name = module.params['name']
- script_type = module.params['script_type']
- command = module.params['command']
- scope = module.params['scope']
- execute_on = module.params['execute_on']
- menu_path = module.params['menu_path']
- authtype = module.params['authtype']
- username = module.params['username']
- password = module.params['password']
- publickey = module.params['publickey']
- privatekey = module.params['privatekey']
- port = module.params['port']
- host_group = module.params['host_group']
- user_group = module.params['user_group']
- host_access = module.params['host_access']
- confirmation = module.params['confirmation']
- script_timeout = module.params['script_timeout']
- parameters = module.params['parameters']
- description = module.params['description']
- state = module.params['state']
+ name = module.params["name"]
+ script_type = module.params["script_type"]
+ command = module.params["command"]
+ scope = module.params["scope"]
+ execute_on = module.params["execute_on"]
+ menu_path = module.params["menu_path"]
+ authtype = module.params["authtype"]
+ username = module.params["username"]
+ password = module.params["password"]
+ publickey = module.params["publickey"]
+ privatekey = module.params["privatekey"]
+ port = module.params["port"]
+ host_group = module.params["host_group"]
+ user_group = module.params["user_group"]
+ host_access = module.params["host_access"]
+ confirmation = module.params["confirmation"]
+ script_timeout = module.params["script_timeout"]
+ parameters = module.params["parameters"]
+ description = module.params["description"]
+ state = module.params["state"]
script = Script(module)
script_ids = script.get_script_ids(name)
diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_service.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_service.py
index 9468ee49a..8a7b9b605 100644
--- a/ansible_collections/community/zabbix/plugins/modules/zabbix_service.py
+++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_service.py
@@ -8,7 +8,7 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type
-DOCUMENTATION = '''
+DOCUMENTATION = """
---
module: zabbix_service
short_description: Create/update/delete Zabbix service
@@ -18,61 +18,26 @@ author:
- "Emmanuel Riviere (@emriver)"
- "Evgeny Yurchenko (@BGmot)"
requirements:
- - "python >= 2.7"
+ - "python >= 3.9"
options:
name:
description:
- Name of Zabbix service
required: true
type: str
- parent:
- description:
- - Name of Zabbix service parent
- - With >= Zabbix 6.0 this field is removed from the API and is dropped silently by module.
- required: false
- type: str
- sla:
- description:
- - Sla value (i.e 99.99), goodsla in Zabbix API
- - With >= Zabbix 6.0 this field is removed from the API and is dropped silently by module.
- required: false
- type: float
- calculate_sla:
- description:
- - If yes, calculate the SLA value for this service, showsla in Zabbix API
- - With >= Zabbix 6.0 this field is removed from the API and is dropped silently by module.
- required: false
- default: false
- type: bool
algorithm:
description:
- - Algorithm used to calculate the sla with < Zabbix 6.0
- - ' - C(no), sla is not calculated'
- - ' - C(one_child), problem if at least one child has a problem'
- - ' - C(all_children), problem if all children have problems'
- - Status calculation rule. Only applicable if child services exists with >= Zabbix 6.0
- - ' - C(status_to_ok), set status to OK with'
- - ' - C(most_crit_if_all_children), most critical if all children have problems'
- - ' - C(most_crit_of_child_serv), most critical of child services with'
- required: false
- type: str
- choices: ["no", "one_child", "all_children", "status_to_ok", "most_crit_if_all_children", "most_crit_of_child_serv"]
- default: one_child
- trigger_name:
- description:
- - Name of trigger linked to the service.
- - With >= Zabbix 6.0 this field is removed from the API and is dropped silently by module.
- required: false
- type: str
- trigger_host:
- description:
- - Name of host linked to the service.
- - With >= Zabbix 6.0 this field is removed from the API and is dropped silently by module.
+ - Status calculation rule. Only applicable if child services exists.
+ - " - C(status_to_ok), set status to OK with"
+ - " - C(most_crit_if_all_children), most critical if all children have problems"
+ - " - C(most_crit_of_child_serv), most critical of child services with"
required: false
type: str
+ choices: ["status_to_ok", "most_crit_if_all_children", "most_crit_of_child_serv"]
+ default: status_to_ok
state:
description:
- - 'State: present - create/update service; absent - delete service.'
+ - "State: present - create/update service; absent - delete service."
required: false
choices: [present, absent]
default: "present"
@@ -85,20 +50,17 @@ options:
weight:
description:
- Service weight.
- - New field with >= Zabbix 6.0.
required: false
- default: '0'
+ default: "0"
type: str
description:
description:
- Description of the service.
- - New field with >= Zabbix 6.0.
required: false
type: str
tags:
description:
- Service tags to be created for the service.
- - New field with >= Zabbix 6.0.
required: false
type: list
elements: dict
@@ -116,7 +78,6 @@ options:
problem_tags:
description:
- Problem tags to be created for the service.
- - New field with >= Zabbix 6.0.
required: false
type: list
elements: dict
@@ -131,7 +92,7 @@ options:
- Mapping condition operator.
- C(equals)
- C(like)
- choices: ['equals', 'like']
+ choices: ["equals", "like"]
required: false
default: "equals"
type: str
@@ -144,21 +105,18 @@ options:
parents:
description:
- Parent services to be linked to the service.
- - New field with >= Zabbix 6.0.
required: false
type: list
elements: str
children:
description:
- Child services to be linked to the service.
- - New field with >= Zabbix 6.0.
required: false
type: list
elements: str
propagation_rule:
description:
- Status propagation value. Must be set together with propagation_rule.
- - New field with >= Zabbix 6.0.
- C(as_is) propagate service status as is - without any changes
- C(increase) increase the propagated status by a given propagation_value (by 1 to 5 severities)
- C(decrease) decrease the propagated status by a given propagation_value (by 1 to 5 severities)
@@ -171,30 +129,28 @@ options:
propagation_value:
description:
- Status propagation value. Must be set together with propagation_rule.
- - New field with >= Zabbix 6.0.
- - 'Possible values when I(propagation_rule=as_is or ignore):'
- - ' - C(not_classified)'
- - 'Possible values when I(propagation_rule=increase or decrease):'
- - ' - C(information)'
- - ' - C(warning)'
- - ' - C(average)'
- - ' - C(high)'
- - ' - C(disaster)'
- - 'Possible values when I(propagation_rule=fixed):'
- - ' - C(ok)'
- - ' - C(not_classified)'
- - ' - C(information)'
- - ' - C(warning)'
- - ' - C(average)'
- - ' - C(high)'
- - ' - C(disaster)'
+ - "Possible values when I(propagation_rule=as_is or ignore):"
+ - " - C(not_classified)"
+ - "Possible values when I(propagation_rule=increase or decrease):"
+ - " - C(information)"
+ - " - C(warning)"
+ - " - C(average)"
+ - " - C(high)"
+ - " - C(disaster)"
+ - "Possible values when I(propagation_rule=fixed):"
+ - " - C(ok)"
+ - " - C(not_classified)"
+ - " - C(information)"
+ - " - C(warning)"
+ - " - C(average)"
+ - " - C(high)"
+ - " - C(disaster)"
- Required with C(propagation_rule)
required: false
type: str
status_rules:
description:
- Status rules for the service.
- - New field with >= Zabbix 6.0.
required: false
type: list
elements: dict
@@ -214,8 +170,8 @@ options:
type: str
limit_value:
description:
- - 'Limit value: N, N% or W'
- - 'Possible values: 1-100000 for N and W, 1-100 for N%'
+ - "Limit value: N, N% or W"
+ - "Possible values: 1-100000 for N and W, 1-100 for N%"
required: true
type: int
limit_status:
@@ -245,43 +201,23 @@ options:
extends_documentation_fragment:
- community.zabbix.zabbix
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = """
---
# If you want to use Username and Password to be authenticated by Zabbix Server
- name: Set credentials to access Zabbix Server API
- set_fact:
+ ansible.builtin.set_fact:
ansible_user: Admin
ansible_httpapi_pass: zabbix
# If you want to use API token to be authenticated by Zabbix Server
# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens
- name: Set API token
- set_fact:
+ ansible.builtin.set_fact:
ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895
-# Creates a new Zabbix service with Zabbix < 6.0
-- name: Manage services
- # set task level variables
- vars:
- ansible_network_os: community.zabbix.zabbix
- ansible_connection: httpapi
- ansible_httpapi_port: 443
- ansible_httpapi_use_ssl: true
- ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
- ansible_host: zabbix-example-fqdn.org
- community.zabbix.zabbix_service:
- name: apache2 service
- sla: 99.99
- calculate_sla: yes
- algorithm: one_child
- trigger_name: apache2 service status
- trigger_host: webserver01
- state: present
-
-# Creates a new Zabbix service with Zabbix >= 6.0
+# Creates a new Zabbix service
- name: Create Zabbix service monitoring Apache2 in DCs in Toronto area
# set task level variables
vars:
@@ -290,10 +226,10 @@ EXAMPLES = '''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_service:
- name: 'apache2 service Toronto'
+ name: "apache2 service Toronto"
description: Apache2 services in Toronto area
sortorder: 0
propagation_rule: increase
@@ -325,7 +261,7 @@ EXAMPLES = '''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_service:
name: apache2 service
@@ -336,27 +272,26 @@ EXAMPLES = '''
- tag: area
value: global
children:
- - 'apache2 service Toronto'
-'''
+ - "apache2 service Toronto"
+"""
-RETURN = '''
+RETURN = """
---
-'''
+"""
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase
import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils
-from ansible.module_utils.compat.version import LooseVersion
class Service(ZabbixBase):
def get_service_ids(self, service_name):
service_ids = []
- services = self._zapi.service.get({'filter': {'name': service_name}})
+ services = self._zapi.service.get({"filter": {"name": service_name}})
for service in services:
- service_ids.append(service['serviceid'])
+ service_ids.append(service["serviceid"])
return service_ids
def delete_service(self, service_ids):
@@ -365,208 +300,160 @@ class Service(ZabbixBase):
self._zapi.service.delete(service_ids)
def dump_services(self, service_ids):
- if LooseVersion(self._zbx_api_version) < LooseVersion('6.0'):
- services = self._zapi.service.get({'output': 'extend', 'filter': {'serviceid': service_ids}, 'selectParent': '1'})
- else:
- services = self._zapi.service.get({'output': 'extend', 'filter': {'serviceid': service_ids}, 'selectParents': 'extend',
- 'selectTags': 'extend', 'selectProblemTags': 'extend', 'selectChildren': 'extend',
- 'selectStatusRules': 'extend'})
+ services = self._zapi.service.get({"output": "extend", "filter": {"serviceid": service_ids}, "selectParents": "extend",
+ "selectTags": "extend", "selectProblemTags": "extend", "selectChildren": "extend",
+ "selectStatusRules": "extend"})
return services
- def generate_service_config(self, name, parent, sla, calculate_sla, trigger_name, trigger_host, sortorder, weight,
+ def generate_service_config(self, name, sortorder, weight,
algorithm, description, tags, problem_tags, parents, children, propagation_rule, propagation_value, status_rules):
- algorithms = {'no': '0', 'one_child': '1', 'all_children': '2',
- 'status_to_ok': '0', 'most_crit_if_all_children': '1', 'most_crit_of_child_serv': '2'}
+ algorithms = {"status_to_ok": "0", "most_crit_if_all_children": "1", "most_crit_of_child_serv": "2"}
algorithm = algorithms[algorithm]
- if LooseVersion(self._zbx_api_version) < LooseVersion('6.0'):
- if calculate_sla:
- calculate_sla = 1
- else:
- calculate_sla = 0
- else:
- sla = 0 # Parameter does not exist in >= 6.0 but we needed for format() function constructing request
-
- # Zabbix api return when no trigger
- trigger_id = 0
- if trigger_host and trigger_name:
- # Retrieving the host to get the trigger
- hosts = self._zapi.host.get({'filter': {'host': trigger_host}})
- if not hosts:
- self._module.fail_json(msg="Target host %s not found" % trigger_host)
- host_id = hosts[0]['hostid']
-
- triggers = self._zapi.trigger.get({'filter': {'description': trigger_name}, 'hostids': [host_id]})
- if not triggers:
- self._module.fail_json(msg="Trigger %s not found on host %s" % (trigger_name, trigger_host))
- trigger_id = triggers[0]['triggerid']
-
request = {
- 'name': name,
- 'algorithm': algorithm,
- 'showsla': str(calculate_sla),
- 'sortorder': sortorder,
- 'goodsla': format(sla, '.4f'), # Sla has 4 decimals
- 'triggerid': str(trigger_id)
+ "name": name,
+ "algorithm": algorithm,
+ "sortorder": sortorder,
+ "description": description,
+ "weight": weight
}
- if LooseVersion(self._zbx_api_version) >= LooseVersion('6.0'):
- request.pop('showsla')
- request.pop('triggerid')
- request.pop('goodsla')
- request['description'] = description
- request['weight'] = weight
+ if tags:
+ request["tags"] = tags
+ else:
+ request["tags"] = []
+
+ request["problem_tags"] = []
+ if problem_tags:
+ p_operators = {"equals": "0", "like": "2"}
+ for p_tag in problem_tags:
+ pt = {"tag": p_tag["tag"], "operator": "0", "value": ""}
+ if "operator" in p_tag:
+ pt["operator"] = p_operators[p_tag["operator"]]
+ if "value" in p_tag:
+ pt["value"] = p_tag["value"]
+ request["problem_tags"].append(pt)
+
+ if parents:
+ p_service_ids = []
+ p_services = self._zapi.service.get({"filter": {"name": parents}})
+ for p_service in p_services:
+ p_service_ids.append({"serviceid": p_service["serviceid"]})
+ request["parents"] = p_service_ids
+ else:
+ request["parents"] = []
+
+ if children:
+ c_service_ids = []
+ c_services = self._zapi.service.get({"filter": {"name": children}})
+ for c_service in c_services:
+ c_service_ids.append({"serviceid": c_service["serviceid"]})
+ request["children"] = c_service_ids
+ else:
+ request["children"] = []
+
+ request["status_rules"] = []
+ if status_rules:
+ for s_rule in status_rules:
+ status_rule = {}
+ if "type" in s_rule:
+ sr_type_map = {"at_least_n_child_services_have_status_or_above": "0",
+ "at_least_npct_child_services_have_status_or_above": "1",
+ "less_than_n_child_services_have_status_or_below": "2",
+ "less_than_npct_child_services_have_status_or_below": "3",
+ "weight_child_services_with_status_or_above_at_least_w": "4",
+ "weight_child_services_with_status_or_above_at_least_npct": "5",
+ "weight_child_services_with_status_or_below_less_w": "6",
+ "weight_child_services_with_status_or_below_less_npct": "7"}
+ if s_rule["type"] not in sr_type_map:
+ self._module.fail_json(msg="Wrong value for 'type' parameter in status rule.")
+ status_rule["type"] = sr_type_map[s_rule["type"]]
+ else:
+ self._module.fail_json(msg="'type' is mandatory paremeter for status rule.")
- if tags:
- request['tags'] = tags
- else:
- request['tags'] = []
-
- request['problem_tags'] = []
- if problem_tags:
- p_operators = {'equals': '0', 'like': '2'}
- for p_tag in problem_tags:
- pt = {'tag': p_tag['tag'], 'operator': '0', 'value': ''}
- if 'operator' in p_tag:
- pt['operator'] = p_operators[p_tag['operator']]
- if 'value' in p_tag:
- pt['value'] = p_tag['value']
- request['problem_tags'].append(pt)
-
- if parents:
- p_service_ids = []
- p_services = self._zapi.service.get({'filter': {'name': parents}})
- for p_service in p_services:
- p_service_ids.append({'serviceid': p_service['serviceid']})
- request['parents'] = p_service_ids
- else:
- request['parents'] = []
-
- if children:
- c_service_ids = []
- c_services = self._zapi.service.get({'filter': {'name': children}})
- for c_service in c_services:
- c_service_ids.append({'serviceid': c_service['serviceid']})
- request['children'] = c_service_ids
- else:
- request['children'] = []
-
- request['status_rules'] = []
- if status_rules:
- for s_rule in status_rules:
- status_rule = {}
- if 'type' in s_rule:
- sr_type_map = {'at_least_n_child_services_have_status_or_above': '0',
- 'at_least_npct_child_services_have_status_or_above': '1',
- 'less_than_n_child_services_have_status_or_below': '2',
- 'less_than_npct_child_services_have_status_or_below': '3',
- 'weight_child_services_with_status_or_above_at_least_w': '4',
- 'weight_child_services_with_status_or_above_at_least_npct': '5',
- 'weight_child_services_with_status_or_below_less_w': '6',
- 'weight_child_services_with_status_or_below_less_npct': '7'}
- if s_rule['type'] not in sr_type_map:
- self._module.fail_json(msg="Wrong value for 'type' parameter in status rule.")
- status_rule['type'] = sr_type_map[s_rule['type']]
- else:
- self._module.fail_json(msg="'type' is mandatory paremeter for status rule.")
-
- if 'limit_value' in s_rule:
- lv = s_rule['limit_value']
- if status_rule['type'] in ['0', '2', '4', '6']:
- if int(lv) < 1 or int(lv) > 100000:
- self._module.fail_json(msg="'limit_value' for N and W must be between 1 and 100000 but provided %s" % lv)
- else:
- if int(lv) < 1 or int(lv) > 100:
- self._module.fail_json(msg="'limit_value' for N%% must be between 1 and 100 but provided %s" % lv)
- status_rule['limit_value'] = str(lv)
- else:
- self._module.fail_json(msg="'limit_value' is mandatory paremeter for status rule.")
-
- if 'limit_status' in s_rule:
- sr_ls_map = {'ok': '-1', 'not_classified': '0', 'information': '1', 'warning': '2',
- 'average': '3', 'high': '4', 'disaster': 5}
- if s_rule['limit_status'] not in sr_ls_map:
- self._module.fail_json(msg="Wrong value for 'limit_status' parameter in status rule.")
- status_rule['limit_status'] = sr_ls_map[s_rule['limit_status']]
+ if "limit_value" in s_rule:
+ lv = s_rule["limit_value"]
+ if status_rule["type"] in ["0", "2", "4", "6"]:
+ if int(lv) < 1 or int(lv) > 100000:
+ self._module.fail_json(msg="'limit_value' for N and W must be between 1 and 100000 but provided %s" % lv)
else:
- self._module.fail_json(msg="'limit_status' is mandatory paremeter for status rule.")
-
- if 'new_status' in s_rule:
- sr_ns_map = {'not_classified': '0', 'information': '1', 'warning': '2',
- 'average': '3', 'high': '4', 'disaster': '5'}
- if s_rule['new_status'] not in sr_ns_map:
- self._module.fail_json(msg="Wrong value for 'new_status' parameter in status rule.")
- status_rule['new_status'] = sr_ns_map[s_rule['new_status']]
- else:
- self._module.fail_json(msg="'new_status' is mandatory paremeter for status rule.")
-
- request['status_rules'].append(status_rule)
-
- request['propagation_rule'] = '0'
- if propagation_rule:
- if propagation_value is None:
- self._module.fail_json(msg="If 'propagation_rule' is provided then 'propagation_value' must be provided too.")
- pr_map = {'as_is': '0', 'increase': '1', 'decrease': '2', 'ignore': '3', 'fixed': '4'}
- if propagation_rule not in pr_map:
- self._module.fail_json(msg="Wrong value for 'propagation_rule' parameter.")
+ if int(lv) < 1 or int(lv) > 100:
+ self._module.fail_json(msg="'limit_value' for N%% must be between 1 and 100 but provided %s" % lv)
+ status_rule["limit_value"] = str(lv)
else:
- request['propagation_rule'] = pr_map[propagation_rule]
-
- request['propagation_value'] = '0'
- if propagation_value:
- if propagation_rule is None:
- self._module.fail_json(msg="If 'propagation_value' is provided then 'propagation_rule' must be provided too.")
- pv_map = {'ok': '-1', 'not_classified': '0', 'information': '1', 'warning': '2',
- 'average': '3', 'high': '4', 'disaster': '5'}
- if propagation_value not in pv_map:
- self._module.fail_json(msg="Wrong value for 'propagation_value' parameter.")
+ self._module.fail_json(msg="'limit_value' is mandatory paremeter for status rule.")
+
+ if "limit_status" in s_rule:
+ sr_ls_map = {"ok": "-1", "not_classified": "0", "information": "1", "warning": "2",
+ "average": "3", "high": "4", "disaster": 5}
+ if s_rule["limit_status"] not in sr_ls_map:
+ self._module.fail_json(msg="Wrong value for 'limit_status' parameter in status rule.")
+ status_rule["limit_status"] = sr_ls_map[s_rule["limit_status"]]
else:
- request['propagation_value'] = pv_map[propagation_value]
- else:
- if parent:
- parent_ids = self.get_service_ids(parent)
- if not parent_ids:
- self._module.fail_json(msg="Parent %s not found" % parent)
- request['parentid'] = parent_ids[0]
+ self._module.fail_json(msg="'limit_status' is mandatory paremeter for status rule.")
+
+ if "new_status" in s_rule:
+ sr_ns_map = {"not_classified": "0", "information": "1", "warning": "2",
+ "average": "3", "high": "4", "disaster": "5"}
+ if s_rule["new_status"] not in sr_ns_map:
+ self._module.fail_json(msg="Wrong value for 'new_status' parameter in status rule.")
+ status_rule["new_status"] = sr_ns_map[s_rule["new_status"]]
+ else:
+ self._module.fail_json(msg="'new_status' is mandatory paremeter for status rule.")
+
+ request["status_rules"].append(status_rule)
+
+ request["propagation_rule"] = "0"
+ if propagation_rule:
+ if propagation_value is None:
+ self._module.fail_json(msg="If 'propagation_rule' is provided then 'propagation_value' must be provided too.")
+ pr_map = {"as_is": "0", "increase": "1", "decrease": "2", "ignore": "3", "fixed": "4"}
+ if propagation_rule not in pr_map:
+ self._module.fail_json(msg="Wrong value for 'propagation_rule' parameter.")
+ else:
+ request["propagation_rule"] = pr_map[propagation_rule]
+
+ request["propagation_value"] = "0"
+ if propagation_value:
+ if propagation_rule is None:
+ self._module.fail_json(msg="If 'propagation_value' is provided then 'propagation_rule' must be provided too.")
+ pv_map = {"ok": "-1", "not_classified": "0", "information": "1", "warning": "2",
+ "average": "3", "high": "4", "disaster": "5"}
+ if propagation_value not in pv_map:
+ self._module.fail_json(msg="Wrong value for 'propagation_value' parameter.")
+ else:
+ request["propagation_value"] = pv_map[propagation_value]
+
return request
- def create_service(self, name, parent, sla, calculate_sla, trigger_name, trigger_host, sortorder, weight, algorithm,
+ def create_service(self, name, sortorder, weight, algorithm,
description, tags, problem_tags, parents, children, propagation_rule, propagation_value, status_rules):
if self._module.check_mode:
self._module.exit_json(changed=True)
- self._zapi.service.create(self.generate_service_config(name, parent, sla, calculate_sla, trigger_name, trigger_host, sortorder, weight,
+ self._zapi.service.create(self.generate_service_config(name, sortorder, weight,
algorithm, description, tags, problem_tags, parents, children, propagation_rule, propagation_value, status_rules))
- def update_service(self, service_id, name, parent, sla, calculate_sla, trigger_name, trigger_host, sortorder, weight, algorithm,
+ def update_service(self, service_id, name, sortorder, weight, algorithm,
description, tags, problem_tags, parents, children, propagation_rule, propagation_value, status_rules):
- generated_config = self.generate_service_config(name, parent, sla, calculate_sla, trigger_name, trigger_host, sortorder, weight, algorithm,
+ generated_config = self.generate_service_config(name, sortorder, weight, algorithm,
description, tags, problem_tags, parents, children, propagation_rule, propagation_value, status_rules)
live_config = self.dump_services(service_id)[0]
- if LooseVersion(self._zbx_api_version) >= LooseVersion('6.0'):
- if len(live_config['parents']) > 0:
- # Need to rewrite parents list to only service ids
- new_parents = []
- for parent in live_config['parents']:
- new_parents.append({'serviceid': parent['serviceid']})
- live_config['parents'] = new_parents
-
- if len(live_config['children']) > 0:
- # Need to rewrite children list to only service ids
- new_children = []
- for child in live_config['children']:
- new_children.append({'serviceid': child['serviceid']})
- live_config['children'] = new_children
-
- else:
- if 'goodsla' in live_config:
- live_config['goodsla'] = format(float(live_config['goodsla']), '.4f')
+ if len(live_config["parents"]) > 0:
+ # Need to rewrite parents list to only service ids
+ new_parents = []
+ for parent in live_config["parents"]:
+ new_parents.append({"serviceid": parent["serviceid"]})
+ live_config["parents"] = new_parents
- if 'parentid' in generated_config:
- if 'serviceid' in live_config['parent']:
- live_config['parentid'] = live_config['parent']['serviceid']
+ if len(live_config["children"]) > 0:
+ # Need to rewrite children list to only service ids
+ new_children = []
+ for child in live_config["children"]:
+ new_children.append({"serviceid": child["serviceid"]})
+ live_config["children"] = new_children
change_parameters = {}
difference = zabbix_utils.helper_cleanup_data(zabbix_utils.helper_compare_dictionaries(generated_config, live_config, change_parameters))
@@ -576,7 +463,7 @@ class Service(ZabbixBase):
if self._module.check_mode:
self._module.exit_json(changed=True)
- generated_config['serviceid'] = service_id
+ generated_config["serviceid"] = service_id
self._zapi.service.update(generated_config)
self._module.exit_json(changed=True, msg="Service %s updated" % name)
@@ -584,81 +471,75 @@ class Service(ZabbixBase):
def main():
argument_spec = zabbix_utils.zabbix_common_argument_spec()
argument_spec.update(dict(
- name=dict(type='str', required=True),
- parent=dict(type='str', required=False),
- sla=dict(type='float', required=False),
- calculate_sla=dict(type='bool', required=False, default=False),
- algorithm=dict(default='one_child', required=False, choices=['no', 'one_child', 'all_children',
- 'status_to_ok', 'most_crit_if_all_children', 'most_crit_of_child_serv']),
- trigger_name=dict(type='str', required=False),
- trigger_host=dict(type='str', required=False),
- sortorder=dict(type='str', required=True),
- weight=dict(default='0', type='str', required=False),
- state=dict(default="present", choices=['present', 'absent']),
- description=dict(type='str', required=False),
+ name=dict(type="str", required=True),
+ algorithm=dict(default="status_to_ok", required=False, choices=["status_to_ok", "most_crit_if_all_children", "most_crit_of_child_serv"]),
+ sortorder=dict(type="str", required=True),
+ weight=dict(default="0", type="str", required=False),
+ state=dict(default="present", choices=["present", "absent"]),
+ description=dict(type="str", required=False),
tags=dict(
- type='list',
+ type="list",
required=False,
- elements='dict',
+ elements="dict",
options=dict(
tag=dict(
- type='str',
+ type="str",
required=True
),
value=dict(
- type='str',
+ type="str",
required=False
)
)
),
problem_tags=dict(
- type='list',
+ type="list",
required=False,
- elements='dict',
+ elements="dict",
options=dict(
tag=dict(
- type='str',
+ type="str",
required=True
),
operator=dict(
- type='str',
+ type="str",
required=False,
choices=[
- 'equals',
- 'like'
+ "equals",
+ "like"
],
- default='equals'
+ default="equals"
),
value=dict(
- type='str',
+ type="str",
required=False,
- default=''
+ default=""
)
)
),
- parents=dict(type='list', required=False, elements='str'),
- children=dict(type='list', required=False, elements='str'),
- propagation_rule=dict(default='as_is', type='str', required=False),
- propagation_value=dict(type='str', required=False),
+ parents=dict(type="list", required=False, elements="str"),
+ children=dict(type="list", required=False, elements="str"),
+ propagation_rule=dict(default="as_is", type="str", required=False),
+ propagation_value=dict(type="str", required=False),
status_rules=dict(
- type='list',
+ type="list",
required=False,
- elements='dict',
+ elements="dict",
options=dict(
type=dict(
- type='str',
+ type="str",
required=True
),
limit_value=dict(
- type='int',
+ type="int",
required=True
),
limit_status=dict(
- type='str',
+ type="str",
required=True
),
new_status=dict(
- type='str',
+ type="str",
required=True
)
)
@@ -669,30 +550,19 @@ def main():
supports_check_mode=True
)
- zabbix_utils.require_creds_params(module)
-
- for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']:
- if p in module.params and not module.params[p] is None:
- module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p)
-
- name = module.params['name']
- parent = module.params['parent']
- sla = module.params['sla']
- calculate_sla = module.params['calculate_sla']
- algorithm = module.params['algorithm']
- trigger_name = module.params['trigger_name']
- trigger_host = module.params['trigger_host']
- sortorder = module.params['sortorder']
- weight = module.params['weight']
- state = module.params['state']
- description = module.params['description']
- tags = module.params['tags']
- problem_tags = module.params['problem_tags']
- parents = module.params['parents']
- children = module.params['children']
- propagation_rule = module.params['propagation_rule']
- propagation_value = module.params['propagation_value']
- status_rules = module.params['status_rules']
+ name = module.params["name"]
+ algorithm = module.params["algorithm"]
+ sortorder = module.params["sortorder"]
+ weight = module.params["weight"]
+ state = module.params["state"]
+ description = module.params["description"]
+ tags = module.params["tags"]
+ problem_tags = module.params["problem_tags"]
+ parents = module.params["parents"]
+ children = module.params["children"]
+ propagation_rule = module.params["propagation_rule"]
+ propagation_value = module.params["propagation_value"]
+ status_rules = module.params["status_rules"]
# Load service module
service = Service(module)
@@ -706,18 +576,16 @@ def main():
module.exit_json(changed=True, result="Successfully deleted service(s) %s" % name)
elif state == "present":
- if (trigger_name and not trigger_host) or (trigger_host and not trigger_name):
- module.fail_json(msg="Specify either both trigger_host and trigger_name or none to create or update a service")
# Does not exists going to create it
if not service_ids:
- service.create_service(name, parent, sla, calculate_sla, trigger_name, trigger_host, sortorder, weight, algorithm, description,
+ service.create_service(name, sortorder, weight, algorithm, description,
tags, problem_tags, parents, children, propagation_rule, propagation_value, status_rules)
module.exit_json(changed=True, msg="Service %s created" % name)
# Else we update it if needed
else:
- service.update_service(service_ids[0], name, parent, sla, calculate_sla, trigger_name, trigger_host, sortorder, weight,
+ service.update_service(service_ids[0], name, sortorder, weight,
algorithm, description, tags, problem_tags, parents, children, propagation_rule, propagation_value, status_rules)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_settings.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_settings.py
new file mode 100644
index 000000000..de8ec6886
--- /dev/null
+++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_settings.py
@@ -0,0 +1,1112 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright: (c) 2023, ONODERA Masaru <masaru-onodera@ieee.org>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+---
+module: zabbix_settings
+
+short_description: Update Zabbix global settings.
+
+description:
+ - This module allows you to update Zabbix global settings.
+
+author:
+ - ONODERA Masaru(@masa-orca)
+
+requirements:
+ - "python >= 3.9"
+
+version_added: 2.1.0
+
+options:
+ default_lang:
+ description:
+ - Default language for users.
+ required: false
+ type: str
+ default_timezone:
+ description:
+ - Default time zone for users.
+ - Please set C(system) if you want to use system time zone.
+ required: false
+ type: str
+ default_theme:
+ description:
+ - Default theme for users.
+ required: false
+ type: str
+ choices:
+ - blue-theme
+ - dark-theme
+ - hc-light
+ - hc-dark
+ search_limit:
+ description:
+ - A number of search and filter results limit.
+ required: false
+ type: int
+ max_overview_table_size:
+ description:
+ - Max number of columns and rows in overview tables
+ required: false
+ type: int
+ max_in_table:
+ description:
+ - Max count of elements to show inside table cell
+ required: false
+ type: int
+ server_check_interval:
+ description:
+ - The Zabbix shows "Zabbix server is down" warning if C(true).
+ required: false
+ type: bool
+ work_period:
+ description:
+ - Working time setting.
+ - U(https://www.zabbix.com/documentation/current/en/manual/appendix/time_period)
+ required: false
+ type: str
+ show_technical_errors:
+ description:
+ - The Zabbix shows PHP and SQL technical errors to users who are non-Super admin or belong to user groups with debug mode not enabled if C(true).
+ required: false
+ type: bool
+ history_period:
+ description:
+ - Max period of displaying history data.
+ - Accepts seconds and time unit with suffix (e.g. 24h).
+ required: false
+ type: str
+ period_default:
+ description:
+ - Default period value for time filter.
+ - Accepts seconds and time unit with suffix (e.g. 1h).
+ required: false
+ type: str
+ max_period:
+ description:
+ - Max period for time filter.
+ - Accepts seconds and time unit with suffix (e.g. 1y).
+ required: false
+ type: str
+ severity_color_0:
+ description:
+ - A custom color for not classified severity.
+ - Please set hexadecimal color code (e.g. 00FF00).
+ required: false
+ type: str
+ severity_color_1:
+ description:
+ - A custom color for information severity.
+ - Please set hexadecimal color code (e.g. 00FF00).
+ required: false
+ type: str
+ severity_color_2:
+ description:
+ - A custom color for warning severity.
+ - Please set hexadecimal color code (e.g. 00FF00).
+ required: false
+ type: str
+ severity_color_3:
+ description:
+ - A custom color for average severity.
+ - Please set hexadecimal color code (e.g. 00FF00).
+ required: false
+ type: str
+ severity_color_4:
+ description:
+ - A custom color for high severity.
+ - Please set hexadecimal color code (e.g. 00FF00).
+ required: false
+ type: str
+ severity_color_5:
+ description:
+ - A custom color for disaster severity.
+ - Please set hexadecimal color code (e.g. 00FF00).
+ required: false
+ type: str
+ severity_name_0:
+ description:
+ - A custom name for not classified severity.
+ required: false
+ type: str
+ severity_name_1:
+ description:
+ - A custom name for information severity.
+ required: false
+ type: str
+ severity_name_2:
+ description:
+ - A custom name for warning severity.
+ required: false
+ type: str
+ severity_name_3:
+ description:
+ - A custom name for average severity.
+ required: false
+ type: str
+ severity_name_4:
+ description:
+ - A custom name for high severity.
+ required: false
+ type: str
+ severity_name_5:
+ description:
+ - A custom name for disaster severity.
+ required: false
+ type: str
+ custom_color:
+ description:
+ - Custom event color settings will be activated if C(true).
+ required: false
+ type: bool
+ ok_period:
+ description:
+ - A time of period for displaying OK triggers.
+ - Accepts seconds and time unit with suffix (e.g. 5m).
+ required: false
+ type: str
+ blink_period:
+ description:
+ - A time of period for blinking status changed triggers.
+ - Accepts seconds and time unit with suffix (e.g. 5m).
+ required: false
+ type: str
+ problem_unack_color:
+ description:
+ - A custom color for unacknowledged PROBLEM events.
+ - This setting will be activated if I(custom_color=true).
+ - Please set hexadecimal color code (e.g. 00FF00).
+ required: false
+ type: str
+ problem_ack_color:
+ description:
+ - A custom color for acknowledged PROBLEM events.
+ - This setting will be activated if I(custom_color=true).
+ - Please set hexadecimal color code (e.g. 00FF00).
+ required: false
+ type: str
+ ok_unack_color:
+ description:
+ - A custom color for unacknowledged RESOLVED events.
+ - This setting will be activated if I(custom_color=true).
+ - Please set hexadecimal color code (e.g. 00FF00).
+ required: false
+ type: str
+ ok_ack_color:
+ description:
+ - A custom color for acknowledged RESOLVED events.
+ - This setting will be activated if I(custom_color=true).
+ - Please set hexadecimal color code (e.g. 00FF00).
+ required: false
+ type: str
+ problem_unack_style:
+ description:
+ - Unacknowledged PROBLEM events blink if C(true).
+ required: false
+ type: bool
+ problem_ack_style:
+ description:
+ - Acknowledged PROBLEM events blink if C(true).
+ required: false
+ type: bool
+ ok_unack_style:
+ description:
+ - Unacknowledged RESOLVED events blink if C(true).
+ required: false
+ type: bool
+ ok_ack_style:
+ description:
+ - Acknowledged RESOLVED events blink if C(true).
+ required: false
+ type: bool
+ frontend_url:
+ description:
+ - A URL of frontend.
+ - This parameter is used for url parameter of settings API.
+ required: false
+ type: str
+ discovery_group:
+ description:
+ - A hostgroup which discovered hosts will belong to.
+ required: false
+ type: str
+ default_inventory_mode:
+ description:
+ - A default value for host inventory mode.
+ required: false
+ type: str
+ choices:
+ - disabled
+ - manual
+ - automatic
+ alert_usrgrp:
+ description:
+ - A name of user group which user belongs to receive an alerm message when database down.
+ required: false
+ type: str
+ snmptrap_logging:
+ description:
+ - Logging unmatched SNMP traps will be ebabled if C(true).
+ required: false
+ type: bool
+ login_attempts:
+ description:
+ - A number of login attempts you can try with non blocked.
+ required: false
+ type: int
+ login_block:
+ description:
+ - A time of interval to reset login attempts when the user is blocked.
+ - Accepts seconds and time unit with suffix (e.g. 5m).
+ required: false
+ type: str
+ validate_uri_schemes:
+ description:
+ - Validate URI schemes if C(true).
+ required: false
+ type: bool
+ uri_valid_schemes:
+ description:
+ - A list of valid URI scheme.
+ required: false
+ type: list
+ elements: str
+ x_frame_options:
+ description:
+ - A text of X-Frame-Options of HTTP header.
+ required: false
+ type: str
+ iframe_sandboxing_enabled:
+ description:
+ - The Zabbix uses iframe sandboxing if C(true).
+ required: false
+ type: bool
+ iframe_sandboxing_exceptions:
+ description:
+ - A text of iframe sandboxing exceptions.
+ required: false
+ type: str
+ connect_timeout:
+ description:
+ - A time of connection timeout with Zabbix server.
+ required: false
+ type: str
+ socket_timeout:
+ description:
+ - A time of network default timeout.
+ required: false
+ type: str
+ media_type_test_timeout:
+ description:
+ - A time of network timeout for media type test.
+ required: false
+ type: str
+ item_test_timeout:
+ description:
+ - A time of network timeout for item tests.
+ required: false
+ type: str
+ script_timeout:
+ description:
+ - A time of network timeout for script execution.
+ required: false
+ type: str
+ report_test_timeout:
+ description:
+ - A time of network timeout for scheduled report test.
+ required: false
+ type: str
+ auditlog_enabled:
+ description:
+ - Enable audit logging if C(true).
+ required: false
+ type: bool
+ geomaps_tile_provider:
+ description:
+ - A provider of Geomap tile.
+ - Please set C(another) if you want use non default provider
+ required: false
+ type: str
+ choices:
+ - OpenStreetMap.Mapnik
+ - OpenTopoMap
+ - Stamen.TonerLite
+ - Stamen.Terrain
+ - USGS.USTopo
+ - USGS.USImagery
+ - another
+ geomaps_tile_url:
+ description:
+ - A URL of geomap tile.
+ required: false
+ type: str
+ geomaps_max_zoom:
+ description:
+ - Max zoom level of geomap.
+ required: false
+ type: str
+ geomaps_attribution:
+ description:
+ - A text of Geomap attribution.
+ required: false
+ type: str
+ vault_provider:
+ description:
+ - A name of vault provider.
+ - This parameter is available since Zabbix 6.2.
+ required: false
+ type: str
+ choices:
+ - HashiCorp_Vault
+ - CyberArk_Vault
+
+notes:
+ - This module manages settings related with settings api except ha_failover_delay.
+
+extends_documentation_fragment:
+ - community.zabbix.zabbix
+"""
+
+EXAMPLES = """
+# If you want to use Username and Password to be authenticated by Zabbix Server
+- name: Set credentials to access Zabbix Server API
+ ansible.builtin.set_fact:
+ ansible_user: Admin
+ ansible_httpapi_pass: zabbix
+
+# If you want to use API token to be authenticated by Zabbix Server
+# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens
+- name: Set API token
+ ansible.builtin.set_fact:
+ ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895
+
+- name: Update settings
+ # set task level variables as we change ansible_connection plugin here
+ vars:
+ ansible_network_os: community.zabbix.zabbix
+ ansible_connection: httpapi
+ ansible_httpapi_port: 443
+ ansible_httpapi_use_ssl: true
+ ansible_httpapi_validate_certs: false
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_host: zabbix-example-fqdn.org
+ community.zabbix.zabbix_settings:
+ alert_usrgrp: "0"
+ auditlog_enabled: false
+ blink_period: "10m"
+ connect_timeout: "30s"
+ custom_color: false
+ default_inventory_mode: automatic
+"""
+
+RETURN = """
+msg:
+ description: The result of the operation
+ returned: success
+ type: str
+ sample: "Successfully update global settings"
+"""
+
+import re
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase
+from ansible.module_utils.compat.version import LooseVersion
+import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils
+
+
+class Settings(ZabbixBase):
+ # get setting setting
+ def get_settings(self):
+ try:
+ return self._zapi.settings.get({"output": "extend"})
+ except Exception as e:
+ self._module.fail_json(msg="Failed to get settings: %s" % e)
+
+ def _is_time(self, time):
+ pattern = re.compile(r"^(\d+)([smhdwMy]?)$")
+ search_result = pattern.search(time)
+ if search_result is None:
+ self._module.fail_json(msg="{0} is invalid value.".format(time))
+ return True
+
+ def _is_color(self, color):
+ pattern = re.compile(r"^[0-9a-fA-F]{6}$")
+ search_result = pattern.search(color)
+ if search_result is None:
+ self._module.fail_json(msg="{0} is invalid value.".format(color))
+ return True
+
+ def get_usrgrpid_from_name(self, usrgrp):
+ usrgrpids = self._zapi.usergroup.get({"filter": {"name": usrgrp}})
+ if not usrgrpids or len(usrgrpids) > 1:
+ self._module.fail_json("User group '%s' cannot be found" % usrgrp)
+ return usrgrpids[0]["usrgrpid"]
+
+ def get_groupid_from_name(self, hostgroup):
+ groupid = self._zapi.hostgroup.get({"filter": {"name": hostgroup}})
+ if not groupid or len(groupid) > 1:
+ self._module.fail_json("Host group '%s' cannot be found" % hostgroup)
+ return groupid[0]["groupid"]
+
+ def update_settings(
+ self,
+ current_settings,
+ default_lang,
+ default_timezone,
+ default_theme,
+ search_limit,
+ max_overview_table_size,
+ max_in_table,
+ server_check_interval,
+ work_period,
+ show_technical_errors,
+ history_period,
+ period_default,
+ max_period,
+ severity_color_0,
+ severity_color_1,
+ severity_color_2,
+ severity_color_3,
+ severity_color_4,
+ severity_color_5,
+ severity_name_0,
+ severity_name_1,
+ severity_name_2,
+ severity_name_3,
+ severity_name_4,
+ severity_name_5,
+ custom_color,
+ ok_period,
+ blink_period,
+ problem_unack_color,
+ problem_ack_color,
+ ok_unack_color,
+ ok_ack_color,
+ problem_unack_style,
+ problem_ack_style,
+ ok_unack_style,
+ ok_ack_style,
+ frontend_url,
+ discovery_group,
+ default_inventory_mode,
+ alert_usrgrp,
+ snmptrap_logging,
+ login_attempts,
+ login_block,
+ validate_uri_schemes,
+ uri_valid_schemes,
+ x_frame_options,
+ iframe_sandboxing_enabled,
+ iframe_sandboxing_exceptions,
+ connect_timeout,
+ socket_timeout,
+ media_type_test_timeout,
+ item_test_timeout,
+ script_timeout,
+ report_test_timeout,
+ auditlog_enabled,
+ geomaps_tile_provider,
+ geomaps_tile_url,
+ geomaps_max_zoom,
+ geomaps_attribution,
+ vault_provider,
+ ):
+ try:
+ params = {}
+
+ if isinstance(default_lang, str):
+ if default_lang != current_settings["default_lang"]:
+ params["default_lang"] = default_lang
+
+ if isinstance(default_timezone, str):
+ if default_timezone != current_settings["default_timezone"]:
+ params["default_timezone"] = default_timezone
+
+ if isinstance(default_theme, str):
+ if default_theme != current_settings["default_theme"]:
+ params["default_theme"] = default_theme
+
+ if isinstance(search_limit, int):
+ if str(search_limit) != current_settings["search_limit"]:
+ params["search_limit"] = str(search_limit)
+
+ if isinstance(max_overview_table_size, int):
+ if (
+ str(max_overview_table_size)
+ != current_settings["max_overview_table_size"]
+ ):
+ params["max_overview_table_size"] = str(max_overview_table_size)
+
+ if isinstance(max_in_table, int):
+ if str(max_in_table) != current_settings["max_in_table"]:
+ params["max_in_table"] = str(max_in_table)
+
+ if isinstance(server_check_interval, bool):
+ if server_check_interval:
+ if current_settings["server_check_interval"] != "10":
+ params["server_check_interval"] = "10"
+ else:
+ if current_settings["server_check_interval"] != "0":
+ params["server_check_interval"] = "0"
+
+ if isinstance(work_period, str):
+ if work_period != current_settings["work_period"]:
+ params["work_period"] = work_period
+
+ if isinstance(show_technical_errors, bool):
+ if show_technical_errors:
+ if current_settings["show_technical_errors"] != "1":
+ params["show_technical_errors"] = "1"
+ else:
+ if current_settings["show_technical_errors"] != "0":
+ params["show_technical_errors"] = "0"
+
+ if isinstance(history_period, str):
+ if self._is_time(history_period):
+ if history_period != current_settings["history_period"]:
+ params["history_period"] = history_period
+
+ if isinstance(period_default, str):
+ if self._is_time(period_default):
+ if period_default != current_settings["period_default"]:
+ params["period_default"] = period_default
+
+ if isinstance(max_period, str):
+ if self._is_time(max_period):
+ if max_period != current_settings["max_period"]:
+ params["max_period"] = max_period
+
+ if isinstance(severity_color_0, str):
+ if self._is_color(severity_color_0):
+ if severity_color_0 != current_settings["severity_color_0"]:
+ params["severity_color_0"] = severity_color_0
+
+ if isinstance(severity_color_1, str):
+ if self._is_color(severity_color_1):
+ if severity_color_1 != current_settings["severity_color_1"]:
+ params["severity_color_1"] = severity_color_1
+
+ if isinstance(severity_color_2, str):
+ if self._is_color(severity_color_2):
+ if severity_color_2 != current_settings["severity_color_2"]:
+ params["severity_color_2"] = severity_color_2
+
+ if isinstance(severity_color_3, str):
+ if self._is_color(severity_color_3):
+ if severity_color_3 != current_settings["severity_color_3"]:
+ params["severity_color_3"] = severity_color_3
+
+ if isinstance(severity_color_4, str):
+ if self._is_color(severity_color_4):
+ if severity_color_4 != current_settings["severity_color_4"]:
+ params["severity_color_4"] = severity_color_4
+
+ if isinstance(severity_color_5, str):
+ if self._is_color(severity_color_5):
+ if severity_color_5 != current_settings["severity_color_5"]:
+ params["severity_color_5"] = severity_color_5
+
+ if isinstance(severity_name_0, str):
+ if severity_name_0 != current_settings["severity_name_0"]:
+ params["severity_name_0"] = severity_name_0
+
+ if isinstance(severity_name_1, str):
+ if severity_name_1 != current_settings["severity_name_1"]:
+ params["severity_name_1"] = severity_name_1
+
+ if isinstance(severity_name_2, str):
+ if severity_name_2 != current_settings["severity_name_2"]:
+ params["severity_name_2"] = severity_name_2
+
+ if isinstance(severity_name_3, str):
+ if severity_name_3 != current_settings["severity_name_3"]:
+ params["severity_name_3"] = severity_name_3
+
+ if isinstance(severity_name_4, str):
+ if severity_name_4 != current_settings["severity_name_4"]:
+ params["severity_name_4"] = severity_name_4
+
+ if isinstance(severity_name_5, str):
+ if severity_name_5 != current_settings["severity_name_5"]:
+ params["severity_name_5"] = severity_name_5
+
+ if isinstance(custom_color, bool):
+ if custom_color:
+ if current_settings["custom_color"] != "1":
+ params["custom_color"] = "1"
+ else:
+ if current_settings["custom_color"] != "0":
+ params["custom_color"] = "0"
+
+ if isinstance(ok_period, str):
+ if self._is_time(ok_period):
+ if ok_period != current_settings["ok_period"]:
+ params["ok_period"] = ok_period
+
+ if isinstance(blink_period, str):
+ if self._is_time(blink_period):
+ if blink_period != current_settings["blink_period"]:
+ params["blink_period"] = blink_period
+
+ if isinstance(problem_unack_color, str):
+ if self._is_color(problem_unack_color):
+ if problem_unack_color != current_settings["problem_unack_color"]:
+ params["problem_unack_color"] = problem_unack_color
+
+ if isinstance(problem_ack_color, str):
+ if self._is_color(problem_ack_color):
+ if problem_ack_color != current_settings["problem_ack_color"]:
+ params["problem_ack_color"] = problem_ack_color
+
+ if isinstance(ok_unack_color, str):
+ if self._is_color(ok_unack_color):
+ if ok_unack_color != current_settings["ok_unack_color"]:
+ params["ok_unack_color"] = ok_unack_color
+
+ if isinstance(ok_ack_color, str):
+ if self._is_color(ok_ack_color):
+ if ok_ack_color != current_settings["ok_ack_color"]:
+ params["ok_ack_color"] = ok_ack_color
+
+ if isinstance(problem_unack_style, bool):
+ if problem_unack_style:
+ if current_settings["problem_unack_style"] != "1":
+ params["problem_unack_style"] = "1"
+ else:
+ if current_settings["problem_unack_style"] != "0":
+ params["problem_unack_style"] = "0"
+
+ if isinstance(problem_ack_style, bool):
+ if problem_ack_style:
+ if current_settings["problem_ack_style"] != "1":
+ params["problem_ack_style"] = "1"
+ else:
+ if current_settings["problem_ack_style"] != "0":
+ params["problem_ack_style"] = "0"
+
+ if isinstance(ok_unack_style, bool):
+ if ok_unack_style:
+ if current_settings["ok_unack_style"] != "1":
+ params["ok_unack_style"] = "1"
+ else:
+ if current_settings["ok_unack_style"] != "0":
+ params["ok_unack_style"] = "0"
+
+ if isinstance(ok_ack_style, bool):
+ if ok_ack_style:
+ if current_settings["ok_ack_style"] != "1":
+ params["ok_ack_style"] = "1"
+ else:
+ if current_settings["ok_ack_style"] != "0":
+ params["ok_ack_style"] = "0"
+
+ if isinstance(frontend_url, str):
+ if frontend_url != current_settings["url"]:
+ params["url"] = frontend_url
+
+ if isinstance(discovery_group, str):
+ discovery_groupid = self.get_groupid_from_name(discovery_group)
+ if current_settings["discovery_groupid"] != discovery_groupid:
+ params["discovery_groupid"] = discovery_groupid
+
+ if isinstance(default_inventory_mode, str):
+ _default_inventory_mode = str(
+ zabbix_utils.helper_to_numeric_value(
+ ["disabled", "manual", "automatic"], default_inventory_mode
+ )
+ - 1
+ )
+ if (
+ _default_inventory_mode
+ != current_settings["default_inventory_mode"]
+ ):
+ params["default_inventory_mode"] = _default_inventory_mode
+
+ if isinstance(alert_usrgrp, str):
+ if alert_usrgrp != "0":
+ alert_usrgrpid = self.get_usrgrpid_from_name(alert_usrgrp)
+ else:
+ alert_usrgrpid = alert_usrgrp
+ if current_settings["alert_usrgrpid"] != alert_usrgrpid:
+ params["alert_usrgrpid"] = alert_usrgrpid
+
+ if isinstance(snmptrap_logging, bool):
+ if snmptrap_logging:
+ if current_settings["snmptrap_logging"] != "1":
+ params["snmptrap_logging"] = "1"
+ else:
+ if current_settings["snmptrap_logging"] != "0":
+ params["snmptrap_logging"] = "0"
+
+ if isinstance(login_attempts, int):
+ if str(login_attempts) != current_settings["login_attempts"]:
+ params["login_attempts"] = str(login_attempts)
+
+ if isinstance(login_block, str):
+ if self._is_time(login_block):
+ if login_block != current_settings["login_block"]:
+ params["login_block"] = login_block
+
+ if isinstance(validate_uri_schemes, bool):
+ if validate_uri_schemes:
+ if current_settings["validate_uri_schemes"] != "1":
+ params["validate_uri_schemes"] = "1"
+ else:
+ if current_settings["validate_uri_schemes"] != "0":
+ params["validate_uri_schemes"] = "0"
+
+ if isinstance(uri_valid_schemes, list):
+ current_uri_valid_schemes = current_settings["uri_valid_schemes"].split(
+ ","
+ )
+ uri_valid_schemes.sort()
+ current_uri_valid_schemes.sort()
+ compare_result = []
+ zabbix_utils.helper_compare_lists(
+ uri_valid_schemes, current_uri_valid_schemes, compare_result
+ )
+ if len(compare_result) != 0:
+ params["uri_valid_schemes"] = ",".join(uri_valid_schemes)
+
+ if isinstance(x_frame_options, str):
+ if x_frame_options != current_settings["x_frame_options"]:
+ params["x_frame_options"] = x_frame_options
+
+ if isinstance(iframe_sandboxing_enabled, bool):
+ if iframe_sandboxing_enabled:
+ if current_settings["iframe_sandboxing_enabled"] != "1":
+ params["iframe_sandboxing_enabled"] = "1"
+ else:
+ if current_settings["iframe_sandboxing_enabled"] != "0":
+ params["iframe_sandboxing_enabled"] = "0"
+
+ if isinstance(iframe_sandboxing_exceptions, str):
+ if (
+ iframe_sandboxing_exceptions
+ != current_settings["iframe_sandboxing_exceptions"]
+ ):
+ params[
+ "iframe_sandboxing_exceptions"
+ ] = iframe_sandboxing_exceptions
+
+ if isinstance(connect_timeout, str):
+ if self._is_time(connect_timeout):
+ if connect_timeout != current_settings["connect_timeout"]:
+ params["connect_timeout"] = connect_timeout
+
+ if isinstance(socket_timeout, str):
+ if self._is_time(socket_timeout):
+ if socket_timeout != current_settings["socket_timeout"]:
+ params["socket_timeout"] = socket_timeout
+
+ if isinstance(media_type_test_timeout, str):
+ if self._is_time(media_type_test_timeout):
+ if (
+ media_type_test_timeout
+ != current_settings["media_type_test_timeout"]
+ ):
+ params["media_type_test_timeout"] = media_type_test_timeout
+
+ if isinstance(item_test_timeout, str):
+ if self._is_time(item_test_timeout):
+ if item_test_timeout != current_settings["item_test_timeout"]:
+ params["item_test_timeout"] = item_test_timeout
+
+ if isinstance(script_timeout, str):
+ if self._is_time(script_timeout):
+ if script_timeout != current_settings["script_timeout"]:
+ params["script_timeout"] = script_timeout
+
+ if isinstance(report_test_timeout, str):
+ if self._is_time(report_test_timeout):
+ if report_test_timeout != current_settings["report_test_timeout"]:
+ params["report_test_timeout"] = report_test_timeout
+
+ if isinstance(auditlog_enabled, bool):
+ if auditlog_enabled:
+ if current_settings["auditlog_enabled"] != "1":
+ params["auditlog_enabled"] = "1"
+ else:
+ if current_settings["auditlog_enabled"] != "0":
+ params["auditlog_enabled"] = "0"
+
+ if isinstance(geomaps_tile_provider, str):
+ _geomaps_tile_provider = geomaps_tile_provider
+ if geomaps_tile_provider == "another":
+ _geomaps_tile_provider = ""
+ if _geomaps_tile_provider != current_settings["geomaps_tile_provider"]:
+ params["geomaps_tile_provider"] = _geomaps_tile_provider
+
+ if isinstance(geomaps_tile_url, str):
+ if geomaps_tile_url != current_settings["geomaps_tile_url"]:
+ params["geomaps_tile_url"] = geomaps_tile_url
+
+ if isinstance(geomaps_max_zoom, int):
+ if str(geomaps_max_zoom) != current_settings["geomaps_max_zoom"]:
+ params["geomaps_max_zoom"] = str(geomaps_max_zoom)
+
+ if isinstance(geomaps_attribution, str):
+ if geomaps_attribution != current_settings["geomaps_attribution"]:
+ params["geomaps_attribution"] = geomaps_attribution
+
+ if LooseVersion("6.2") <= LooseVersion(self._zbx_api_version):
+ if isinstance(vault_provider, str):
+ _vault_provider = str(
+ zabbix_utils.helper_to_numeric_value(
+ ["HashiCorp_Vault", "CyberArk_Vault"], vault_provider
+ )
+ )
+ if _vault_provider != current_settings["vault_provider"]:
+ params["vault_provider"] = _vault_provider
+
+ if params != {}:
+ if self._module.check_mode:
+ self._module.exit_json(changed=True)
+ self._zapi.settings.update(params)
+ self._module.exit_json(
+ changed=True, result="Successfully updated global settings"
+ )
+ else:
+ if self._module.check_mode:
+ self._module.exit_json(changed=False)
+ self._module.exit_json(
+ changed=False, result="Settings are already up to date"
+ )
+ except Exception as e:
+ self._module.fail_json(msg="Failed to update global settings: %s" % e)
+
+
+def main():
+ argument_spec = zabbix_utils.zabbix_common_argument_spec()
+ argument_spec.update(
+ dict(
+ default_lang=dict(type="str"),
+ default_timezone=dict(type="str"),
+ default_theme=dict(
+ type="str", choices=["blue-theme", "dark-theme", "hc-light", "hc-dark"]
+ ),
+ search_limit=dict(type="int"),
+ max_overview_table_size=dict(type="int"),
+ max_in_table=dict(type="int"),
+ server_check_interval=dict(type="bool"),
+ work_period=dict(type="str"),
+ show_technical_errors=dict(type="bool"),
+ history_period=dict(type="str"),
+ period_default=dict(type="str"),
+ max_period=dict(type="str"),
+ severity_color_0=dict(type="str"),
+ severity_color_1=dict(type="str"),
+ severity_color_2=dict(type="str"),
+ severity_color_3=dict(type="str"),
+ severity_color_4=dict(type="str"),
+ severity_color_5=dict(type="str"),
+ severity_name_0=dict(type="str"),
+ severity_name_1=dict(type="str"),
+ severity_name_2=dict(type="str"),
+ severity_name_3=dict(type="str"),
+ severity_name_4=dict(type="str"),
+ severity_name_5=dict(type="str"),
+ custom_color=dict(type="bool"),
+ ok_period=dict(type="str"),
+ blink_period=dict(type="str"),
+ problem_unack_color=dict(type="str"),
+ problem_ack_color=dict(type="str"),
+ ok_unack_color=dict(type="str"),
+ ok_ack_color=dict(type="str"),
+ problem_unack_style=dict(type="bool"),
+ problem_ack_style=dict(type="bool"),
+ ok_unack_style=dict(type="bool"),
+ ok_ack_style=dict(type="bool"),
+ frontend_url=dict(type="str"),
+ discovery_group=dict(type="str"),
+ default_inventory_mode=dict(
+ type="str", choices=["disabled", "manual", "automatic"]
+ ),
+ alert_usrgrp=dict(type="str"),
+ snmptrap_logging=dict(type="bool"),
+ login_attempts=dict(type="int"),
+ login_block=dict(type="str"),
+ validate_uri_schemes=dict(type="bool"),
+ uri_valid_schemes=dict(type="list", elements="str"),
+ x_frame_options=dict(type="str"),
+ iframe_sandboxing_enabled=dict(type="bool"),
+ iframe_sandboxing_exceptions=dict(type="str"),
+ connect_timeout=dict(type="str"),
+ socket_timeout=dict(type="str"),
+ media_type_test_timeout=dict(type="str"),
+ item_test_timeout=dict(type="str"),
+ script_timeout=dict(type="str"),
+ report_test_timeout=dict(type="str"),
+ auditlog_enabled=dict(type="bool"),
+ geomaps_tile_provider=dict(
+ type="str",
+ choices=[
+ "OpenStreetMap.Mapnik",
+ "OpenTopoMap",
+ "Stamen.TonerLite",
+ "Stamen.Terrain",
+ "USGS.USTopo",
+ "USGS.USImagery",
+ "another",
+ ],
+ ),
+ geomaps_tile_url=dict(type="str"),
+ geomaps_max_zoom=dict(type="str"),
+ geomaps_attribution=dict(type="str"),
+ vault_provider=dict(
+ type="str", choices=["HashiCorp_Vault", "CyberArk_Vault"]
+ ),
+ )
+ )
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_if=[
+ [
+ "geomaps_tile_provider",
+ "another",
+ ["geomaps_tile_url", "geomaps_max_zoom", "geomaps_attribution"],
+ ],
+ ],
+ supports_check_mode=True,
+ )
+
+ default_lang = module.params["default_lang"]
+ default_timezone = module.params["default_timezone"]
+ default_theme = module.params["default_theme"]
+ search_limit = module.params["search_limit"]
+ max_overview_table_size = module.params["max_overview_table_size"]
+ max_in_table = module.params["max_in_table"]
+ server_check_interval = module.params["server_check_interval"]
+ work_period = module.params["work_period"]
+ show_technical_errors = module.params["show_technical_errors"]
+ history_period = module.params["history_period"]
+ period_default = module.params["period_default"]
+ max_period = module.params["max_period"]
+ severity_color_0 = module.params["severity_color_0"]
+ severity_color_1 = module.params["severity_color_1"]
+ severity_color_2 = module.params["severity_color_2"]
+ severity_color_3 = module.params["severity_color_3"]
+ severity_color_4 = module.params["severity_color_4"]
+ severity_color_5 = module.params["severity_color_5"]
+ severity_name_0 = module.params["severity_name_0"]
+ severity_name_1 = module.params["severity_name_1"]
+ severity_name_2 = module.params["severity_name_2"]
+ severity_name_3 = module.params["severity_name_3"]
+ severity_name_4 = module.params["severity_name_4"]
+ severity_name_5 = module.params["severity_name_5"]
+ custom_color = module.params["custom_color"]
+ ok_period = module.params["ok_period"]
+ blink_period = module.params["blink_period"]
+ problem_unack_color = module.params["problem_unack_color"]
+ problem_ack_color = module.params["problem_ack_color"]
+ ok_unack_color = module.params["ok_unack_color"]
+ ok_ack_color = module.params["ok_ack_color"]
+ problem_unack_style = module.params["problem_unack_style"]
+ problem_ack_style = module.params["problem_ack_style"]
+ ok_unack_style = module.params["ok_unack_style"]
+ ok_ack_style = module.params["ok_ack_style"]
+ frontend_url = module.params["frontend_url"]
+ discovery_group = module.params["discovery_group"]
+ default_inventory_mode = module.params["default_inventory_mode"]
+ alert_usrgrp = module.params["alert_usrgrp"]
+ snmptrap_logging = module.params["snmptrap_logging"]
+ login_attempts = module.params["login_attempts"]
+ login_block = module.params["login_block"]
+ validate_uri_schemes = module.params["validate_uri_schemes"]
+ uri_valid_schemes = module.params["uri_valid_schemes"]
+ x_frame_options = module.params["x_frame_options"]
+ iframe_sandboxing_enabled = module.params["iframe_sandboxing_enabled"]
+ iframe_sandboxing_exceptions = module.params["iframe_sandboxing_exceptions"]
+ connect_timeout = module.params["connect_timeout"]
+ socket_timeout = module.params["socket_timeout"]
+ media_type_test_timeout = module.params["media_type_test_timeout"]
+ item_test_timeout = module.params["item_test_timeout"]
+ script_timeout = module.params["script_timeout"]
+ report_test_timeout = module.params["report_test_timeout"]
+ auditlog_enabled = module.params["auditlog_enabled"]
+ geomaps_tile_provider = module.params["geomaps_tile_provider"]
+ geomaps_tile_url = module.params["geomaps_tile_url"]
+ geomaps_max_zoom = module.params["geomaps_max_zoom"]
+ geomaps_attribution = module.params["geomaps_attribution"]
+ vault_provider = module.params["vault_provider"]
+
+ settings = Settings(module)
+
+ current_settings = settings.get_settings()
+ settings.update_settings(
+ current_settings,
+ default_lang,
+ default_timezone,
+ default_theme,
+ search_limit,
+ max_overview_table_size,
+ max_in_table,
+ server_check_interval,
+ work_period,
+ show_technical_errors,
+ history_period,
+ period_default,
+ max_period,
+ severity_color_0,
+ severity_color_1,
+ severity_color_2,
+ severity_color_3,
+ severity_color_4,
+ severity_color_5,
+ severity_name_0,
+ severity_name_1,
+ severity_name_2,
+ severity_name_3,
+ severity_name_4,
+ severity_name_5,
+ custom_color,
+ ok_period,
+ blink_period,
+ problem_unack_color,
+ problem_ack_color,
+ ok_unack_color,
+ ok_ack_color,
+ problem_unack_style,
+ problem_ack_style,
+ ok_unack_style,
+ ok_ack_style,
+ frontend_url,
+ discovery_group,
+ default_inventory_mode,
+ alert_usrgrp,
+ snmptrap_logging,
+ login_attempts,
+ login_block,
+ validate_uri_schemes,
+ uri_valid_schemes,
+ x_frame_options,
+ iframe_sandboxing_enabled,
+ iframe_sandboxing_exceptions,
+ connect_timeout,
+ socket_timeout,
+ media_type_test_timeout,
+ item_test_timeout,
+ script_timeout,
+ report_test_timeout,
+ auditlog_enabled,
+ geomaps_tile_provider,
+ geomaps_tile_url,
+ geomaps_max_zoom,
+ geomaps_attribution,
+ vault_provider,
+ )
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_template.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_template.py
index 7c4c098af..a773790aa 100644
--- a/ansible_collections/community/zabbix/plugins/modules/zabbix_template.py
+++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_template.py
@@ -8,19 +8,19 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: zabbix_template
-short_description: Create/update/delete/dump Zabbix template
+short_description: Create/update/delete Zabbix template
description:
- - This module allows you to create, modify, delete and dump Zabbix templates.
+ - This module allows you to create, modify and delete Zabbix templates.
- Multiple templates can be created or modified at once if passing JSON or XML to module.
author:
- "sookido (@sookido)"
- "Logan Vig (@logan2211)"
- "Dusan Matejka (@D3DeFi)"
requirements:
- - "python >= 2.6"
+ - "python >= 3.9"
options:
template_name:
description:
@@ -93,7 +93,6 @@ options:
tags:
description:
- List of tags to assign to the template.
- - Works only with >= Zabbix 4.2.
- Providing I(tags=[]) with I(force=yes) will clean all of the tags from the template.
required: false
type: list
@@ -108,54 +107,34 @@ options:
description:
- Value of the template tag.
type: str
- default: ''
- dump_format:
- description:
- - Format to use when dumping template with C(state=dump).
- - This option is deprecated and will eventually be removed in 2.14.
- required: false
- choices: [json, xml]
- default: "json"
- type: str
- omit_date:
- description:
- - Removes the date field for the exported/dumped template
- - Requires C(state=dump)
- required: false
- type: bool
- default: false
+ default: ""
state:
description:
- Required state of the template.
- On C(state=present) template will be created/imported or updated depending if it is already present.
- - On C(state=dump) template content will get dumped into required format specified in I(dump_format).
- On C(state=absent) template will be deleted.
- - The C(state=dump) is deprecated and will be removed in 2.14. The M(community.zabbix.zabbix_template_info) module should be used instead.
required: false
- choices: [present, absent, dump]
+ choices: [present, absent]
default: "present"
type: str
extends_documentation_fragment:
- community.zabbix.zabbix
+"""
-notes:
-- there where breaking changes in the Zabbix API with version 5.4 onwards (especially UUIDs) which may
- require you to export the templates again (see version tag >= 5.4 in the resulting file/data).
-'''
-EXAMPLES = r'''
+EXAMPLES = r"""
---
# If you want to use Username and Password to be authenticated by Zabbix Server
- name: Set credentials to access Zabbix Server API
- set_fact:
+ ansible.builtin.set_fact:
ansible_user: Admin
ansible_httpapi_pass: zabbix
# If you want to use API token to be authenticated by Zabbix Server
# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens
- name: Set API token
- set_fact:
+ ansible.builtin.set_fact:
ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895
- name: Create a new Zabbix template linked to groups, macros and templates
@@ -166,7 +145,7 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_template:
template_name: ExampleHost
@@ -177,12 +156,12 @@ EXAMPLES = r'''
- Example template1
- Example template2
macros:
- - macro: '{$EXAMPLE_MACRO1}'
+ - macro: "{$EXAMPLE_MACRO1}"
value: 30000
- - macro: '{$EXAMPLE_MACRO2}'
+ - macro: "{$EXAMPLE_MACRO2}"
value: 3
- - macro: '{$EXAMPLE_MACRO3}'
- value: 'Example'
+ - macro: "{$EXAMPLE_MACRO3}"
+ value: "Example"
state: present
- name: Unlink and clear templates from the existing Zabbix template
@@ -193,7 +172,7 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_template:
template_name: ExampleHost
@@ -210,7 +189,7 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_template:
template_json: "{{ lookup('file', 'zabbix_apache2.json') }}"
@@ -224,7 +203,7 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_template:
template_xml: "{{ lookup('file', 'zabbix_apache2.xml') }}"
@@ -238,20 +217,18 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_template:
template_json:
zabbix_export:
- version: '3.2'
+ version: "3.2"
templates:
- name: Template for Testing
- description: 'Testing template import'
+ description: "Testing template import"
template: Test Template
groups:
- name: Templates
- applications:
- - name: Test Application
state: present
- name: Configure macros on the existing Zabbix template
@@ -262,13 +239,13 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_template:
template_name: Template
macros:
- - macro: '{$TEST_MACRO}'
- value: 'Example'
+ - macro: "{$TEST_MACRO}"
+ value: "Example"
state: present
- name: Add tags to the existing Zabbix template
@@ -279,7 +256,7 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_template:
template_name: Template
@@ -296,110 +273,16 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_template:
template_name: Template
state: absent
+"""
-- name: Dump Zabbix template as JSON
- # set task level variables as we change ansible_connection plugin here
- vars:
- ansible_network_os: community.zabbix.zabbix
- ansible_connection: httpapi
- ansible_httpapi_port: 443
- ansible_httpapi_use_ssl: true
- ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
- ansible_host: zabbix-example-fqdn.org
- community.zabbix.zabbix_template:
- template_name: Template
- omit_date: yes
- state: dump
- register: template_dump
-
-- name: Dump Zabbix template as XML
- # set task level variables as we change ansible_connection plugin here
- vars:
- ansible_network_os: community.zabbix.zabbix
- ansible_connection: httpapi
- ansible_httpapi_port: 443
- ansible_httpapi_use_ssl: true
- ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
- ansible_host: zabbix-example-fqdn.org
- community.zabbix.zabbix_template:
- template_name: Template
- dump_format: xml
- omit_date: false
- state: dump
- register: template_dump
-'''
-
-RETURN = r'''
+RETURN = r"""
---
-template_json:
- description: The JSON dump of the template
- returned: when state is dump and omit_date is no
- type: str
- sample: {
- "zabbix_export":{
- "date":"2017-11-29T16:37:24Z",
- "templates":[{
- "templates":[],
- "description":"",
- "httptests":[],
- "screens":[],
- "applications":[],
- "discovery_rules":[],
- "groups":[{"name":"Templates"}],
- "name":"Test Template",
- "items":[],
- "macros":[],
- "template":"test"
- }],
- "version":"3.2",
- "groups":[{
- "name":"Templates"
- }]
- }
- }
-
-template_xml:
- description: dump of the template in XML representation
- returned: when state is dump, dump_format is xml and omit_date is yes
- type: str
- sample: |-
- <?xml version="1.0" ?>
- <zabbix_export>
- <version>4.2</version>
- <groups>
- <group>
- <name>Templates</name>
- </group>
- </groups>
- <templates>
- <template>
- <template>test</template>
- <name>Test Template</name>
- <description/>
- <groups>
- <group>
- <name>Templates</name>
- </group>
- </groups>
- <applications/>
- <items/>
- <discovery_rules/>
- <httptests/>
- <macros/>
- <templates/>
- <screens/>
- <tags/>
- </template>
- </templates>
- </zabbix_export>
-'''
+"""
import json
@@ -422,12 +305,12 @@ class Template(ZabbixBase):
def get_group_ids_by_group_names(self, group_names):
group_ids = []
for group_name in group_names:
- if LooseVersion(self._zbx_api_version) >= LooseVersion('6.2'):
- group = self._zapi.templategroup.get({'output': ['groupid'], 'filter': {'name': group_name}})
+ if LooseVersion(self._zbx_api_version) >= LooseVersion("6.2"):
+ group = self._zapi.templategroup.get({"output": ["groupid"], "filter": {"name": group_name}})
else:
- group = self._zapi.hostgroup.get({'output': ['groupid'], 'filter': {'name': group_name}})
+ group = self._zapi.hostgroup.get({"output": ["groupid"], "filter": {"name": group_name}})
if group:
- group_ids.append({'groupid': group[0]['groupid']})
+ group_ids.append({"groupid": group[0]["groupid"]})
else:
self._module.fail_json(msg="Template group not found: %s" % group_name)
return group_ids
@@ -437,25 +320,25 @@ class Template(ZabbixBase):
if template_list is None or len(template_list) == 0:
return template_ids
for template in template_list:
- template_list = self._zapi.template.get({'output': 'extend', 'filter': {'host': template}})
+ template_list = self._zapi.template.get({"output": "extend", "filter": {"host": template}})
if len(template_list) < 1:
continue
else:
- template_id = template_list[0]['templateid']
- template_ids.append({'templateid': template_id})
+ template_id = template_list[0]["templateid"]
+ template_ids.append({"templateid": template_id})
return template_ids
def add_template(self, template_name, group_ids, link_template_ids, macros, tags):
if self._module.check_mode:
self._module.exit_json(changed=True)
- new_template = {'host': template_name, 'groups': group_ids, 'templates': link_template_ids, 'macros': macros, 'tags': tags}
+ new_template = {"host": template_name, "groups": group_ids, "templates": link_template_ids, "macros": macros, "tags": tags}
if macros is None:
- new_template.update({'macros': []})
+ new_template.update({"macros": []})
if tags is None:
- new_template.update({'tags': []})
+ new_template.update({"tags": []})
if link_template_ids is None:
- new_template.update({'templates': []})
+ new_template.update({"templates": []})
self._zapi.template.create(new_template)
@@ -470,17 +353,17 @@ class Template(ZabbixBase):
changed = False
# Compare filtered and formatted XMLs strings for any changes. It is expected that provided
# XML has same structure as Zabbix uses (e.g. it was optimally exported via Zabbix GUI or API)
- if template_content is not None and template_type == 'xml':
- existing_template = self.dump_template(template_ids, template_type='xml')
+ if template_content is not None and template_type == "xml":
+ existing_template = self.dump_template(template_ids, template_type="xml")
if self.filter_xml_template(template_content) != self.filter_xml_template(existing_template):
changed = True
return changed
- existing_template = self.dump_template(template_ids, template_type='json')
+ existing_template = self.dump_template(template_ids, template_type="json")
# Compare JSON objects as deep sorted python dictionaries
- if template_content is not None and template_type == 'json':
+ if template_content is not None and template_type == "json":
parsed_template_json = self.load_json_template(template_content)
if self.diff_template(parsed_template_json, existing_template):
changed = True
@@ -489,19 +372,19 @@ class Template(ZabbixBase):
# If neither template_json or template_xml were used, user provided all parameters via module options
if template_groups is not None:
- if LooseVersion(self._zbx_api_version) >= LooseVersion('6.2'):
- existing_groups = [g['name'] for g in existing_template['zabbix_export']['template_groups']]
+ if LooseVersion(self._zbx_api_version) >= LooseVersion("6.2"):
+ existing_groups = [g["name"] for g in existing_template["zabbix_export"]["template_groups"]]
else:
- existing_groups = [g['name'] for g in existing_template['zabbix_export']['groups']]
+ existing_groups = [g["name"] for g in existing_template["zabbix_export"]["groups"]]
if set(template_groups) != set(existing_groups):
changed = True
- if 'templates' not in existing_template['zabbix_export']['templates'][0]:
- existing_template['zabbix_export']['templates'][0]['templates'] = []
+ if "templates" not in existing_template["zabbix_export"]["templates"][0]:
+ existing_template["zabbix_export"]["templates"][0]["templates"] = []
# Check if any new templates would be linked or any existing would be unlinked
- exist_child_templates = [t['name'] for t in existing_template['zabbix_export']['templates'][0]['templates']]
+ exist_child_templates = [t["name"] for t in existing_template["zabbix_export"]["templates"][0]["templates"]]
if link_templates is not None:
if set(link_templates) != set(exist_child_templates):
changed = True
@@ -516,46 +399,45 @@ class Template(ZabbixBase):
changed = True
break
- if 'macros' not in existing_template['zabbix_export']['templates'][0]:
- existing_template['zabbix_export']['templates'][0]['macros'] = []
+ if "macros" not in existing_template["zabbix_export"]["templates"][0]:
+ existing_template["zabbix_export"]["templates"][0]["macros"] = []
if template_macros is not None:
- existing_macros = existing_template['zabbix_export']['templates'][0]['macros']
+ existing_macros = existing_template["zabbix_export"]["templates"][0]["macros"]
if template_macros != existing_macros:
changed = True
- if LooseVersion(self._zbx_api_version) >= LooseVersion('4.2'):
- if 'tags' not in existing_template['zabbix_export']['templates'][0]:
- existing_template['zabbix_export']['templates'][0]['tags'] = []
- if template_tags is not None:
- existing_tags = existing_template['zabbix_export']['templates'][0]['tags']
- if template_tags != existing_tags:
- changed = True
+ if "tags" not in existing_template["zabbix_export"]["templates"][0]:
+ existing_template["zabbix_export"]["templates"][0]["tags"] = []
+ if template_tags is not None:
+ existing_tags = existing_template["zabbix_export"]["templates"][0]["tags"]
+ if template_tags != existing_tags:
+ changed = True
return changed
def update_template(self, template_ids, group_ids, link_template_ids, clear_template_ids, template_macros, template_tags):
template_changes = {}
if group_ids is not None:
- template_changes.update({'groups': group_ids})
+ template_changes.update({"groups": group_ids})
if link_template_ids is not None:
- template_changes.update({'templates': link_template_ids})
+ template_changes.update({"templates": link_template_ids})
else:
- template_changes.update({'templates': []})
+ template_changes.update({"templates": []})
if clear_template_ids is not None:
- template_changes.update({'templates_clear': clear_template_ids})
+ template_changes.update({"templates_clear": clear_template_ids})
if template_macros is not None:
- template_changes.update({'macros': template_macros})
+ template_changes.update({"macros": template_macros})
else:
- template_changes.update({'macros': []})
+ template_changes.update({"macros": []})
if template_tags is not None:
- template_changes.update({'tags': template_tags})
+ template_changes.update({"tags": template_tags})
else:
- template_changes.update({'tags': []})
+ template_changes.update({"tags": []})
if template_changes:
# If we got here we know that only one template was provided via template_name
@@ -566,7 +448,7 @@ class Template(ZabbixBase):
if self._module.check_mode:
self._module.exit_json(changed=True)
- templateids_list = [t.get('templateid') for t in templateids]
+ templateids_list = [t.get("templateid") for t in templateids]
self._zapi.template.delete(templateids_list)
def ordered_json(self, obj):
@@ -578,26 +460,21 @@ class Template(ZabbixBase):
else:
return obj
- def dump_template(self, template_ids, template_type='json', omit_date=False):
- template_ids_list = [t.get('templateid') for t in template_ids]
+ def dump_template(self, template_ids, template_type="json"):
+ template_ids_list = [t.get("templateid") for t in template_ids]
try:
- dump = self._zapi.configuration.export({'format': template_type, 'options': {'templates': template_ids_list}})
- if template_type == 'xml':
- xmlroot = ET.fromstring(dump.encode('utf-8'))
- # remove date field if requested
- if omit_date:
- date = xmlroot.find(".date")
- if date is not None:
- xmlroot.remove(date)
+ dump = self._zapi.configuration.export({"format": template_type, "options": {"templates": template_ids_list}})
+ if template_type == "xml":
+ xmlroot = ET.fromstring(dump.encode("utf-8"))
if PY2:
- return str(ET.tostring(xmlroot, encoding='utf-8'))
+ return str(ET.tostring(xmlroot, encoding="utf-8"))
else:
- return str(ET.tostring(xmlroot, encoding='utf-8').decode('utf-8'))
+ return str(ET.tostring(xmlroot, encoding="utf-8").decode("utf-8"))
else:
- return self.load_json_template(dump, omit_date=omit_date)
+ return self.load_json_template(dump)
except Exception as e:
- self._module.fail_json(msg='Unable to export template: %s' % e)
+ self._module.fail_json(msg="Unable to export template: %s" % e)
def diff_template(self, template_json_a, template_json_b):
# Compare 2 zabbix templates and return True if they differ.
@@ -609,20 +486,18 @@ class Template(ZabbixBase):
def filter_template(self, template_json):
# Filter the template json to contain only the keys we will update
- keep_keys = set(['graphs', 'templates', 'triggers', 'value_maps'])
- unwanted_keys = set(template_json['zabbix_export']) - keep_keys
+ keep_keys = set(["graphs", "templates", "triggers", "value_maps"])
+ unwanted_keys = set(template_json["zabbix_export"]) - keep_keys
for unwanted_key in unwanted_keys:
- del template_json['zabbix_export'][unwanted_key]
+ del template_json["zabbix_export"][unwanted_key]
# Versions older than 2.4 do not support description field within template
desc_not_supported = False
- if LooseVersion(self._zbx_api_version) < LooseVersion('2.4'):
- desc_not_supported = True
# Filter empty attributes from template object to allow accurate comparison
- for template in template_json['zabbix_export']['templates']:
+ for template in template_json["zabbix_export"]["templates"]:
for key in list(template.keys()):
- if not template[key] or (key == 'description' and desc_not_supported):
+ if not template[key] or (key == "description" and desc_not_supported):
template.pop(key)
return template_json
@@ -634,7 +509,7 @@ class Template(ZabbixBase):
It is advised that provided XML template exactly matches XML structure used by Zabbix"""
# Strip last new line and convert string to ElementTree
parsed_xml_root = self.load_xml_template(template_xml.strip())
- keep_keys = ['graphs', 'templates', 'triggers', 'value_maps']
+ keep_keys = ["graphs", "templates", "triggers", "value_maps"]
# Remove unwanted XML nodes
for node in list(parsed_xml_root):
@@ -642,209 +517,174 @@ class Template(ZabbixBase):
parsed_xml_root.remove(node)
# Filter empty attributes from template objects to allow accurate comparison
- for template in list(parsed_xml_root.find('templates')):
+ for template in list(parsed_xml_root.find("templates")):
for element in list(template):
if element.text is None and len(list(element)) == 0:
template.remove(element)
# Filter new lines and indentation
- xml_root_text = list(line.strip() for line in ET.tostring(parsed_xml_root, encoding='utf8', method='xml').decode().split('\n'))
- return ''.join(xml_root_text)
+ xml_root_text = list(line.strip() for line in ET.tostring(parsed_xml_root, encoding="utf8", method="xml").decode().split("\n"))
+ return "".join(xml_root_text)
- def load_json_template(self, template_json, omit_date=False):
+ def load_json_template(self, template_json):
try:
jsondoc = json.loads(template_json)
- if omit_date and 'date' in jsondoc['zabbix_export']:
- del jsondoc['zabbix_export']['date']
return jsondoc
except ValueError as e:
- self._module.fail_json(msg='Invalid JSON provided', details=to_native(e), exception=traceback.format_exc())
+ self._module.fail_json(msg="Invalid JSON provided", details=to_native(e), exception=traceback.format_exc())
def load_xml_template(self, template_xml):
try:
return ET.fromstring(template_xml)
except ET.ParseError as e:
- self._module.fail_json(msg='Invalid XML provided', details=to_native(e), exception=traceback.format_exc())
+ self._module.fail_json(msg="Invalid XML provided", details=to_native(e), exception=traceback.format_exc())
- def import_template(self, template_content, template_type='json'):
+ def import_template(self, template_content, template_type="json"):
if self._module.check_mode:
self._module.exit_json(changed=True)
# rules schema latest version
update_rules = {
- 'applications': {
- 'createMissing': True,
- 'deleteMissing': True
+ "discoveryRules": {
+ "createMissing": True,
+ "updateExisting": True,
+ "deleteMissing": True
},
- 'discoveryRules': {
- 'createMissing': True,
- 'updateExisting': True,
- 'deleteMissing': True
+ "graphs": {
+ "createMissing": True,
+ "updateExisting": True,
+ "deleteMissing": True
},
- 'graphs': {
- 'createMissing': True,
- 'updateExisting': True,
- 'deleteMissing': True
+ "host_groups": {
+ "createMissing": True
},
- 'host_groups': {
- 'createMissing': True
+ "httptests": {
+ "createMissing": True,
+ "updateExisting": True,
+ "deleteMissing": True
},
- 'httptests': {
- 'createMissing': True,
- 'updateExisting': True,
- 'deleteMissing': True
+ "items": {
+ "createMissing": True,
+ "updateExisting": True,
+ "deleteMissing": True
},
- 'items': {
- 'createMissing': True,
- 'updateExisting': True,
- 'deleteMissing': True
+ "templates": {
+ "createMissing": True,
+ "updateExisting": True
},
- 'templates': {
- 'createMissing': True,
- 'updateExisting': True
+ "template_groups": {
+ "createMissing": True
},
- 'template_groups': {
- 'createMissing': True
+ "templateLinkage": {
+ "createMissing": True
},
- 'templateLinkage': {
- 'createMissing': True
+ "templateScreens": {
+ "createMissing": True,
+ "updateExisting": True,
+ "deleteMissing": True
},
- 'templateScreens': {
- 'createMissing': True,
- 'updateExisting': True,
- 'deleteMissing': True
+ "triggers": {
+ "createMissing": True,
+ "updateExisting": True,
+ "deleteMissing": True
},
- 'triggers': {
- 'createMissing': True,
- 'updateExisting': True,
- 'deleteMissing': True
- },
- 'valueMaps': {
- 'createMissing': True,
- 'updateExisting': True
+ "valueMaps": {
+ "createMissing": True,
+ "updateExisting": True
}
}
try:
- # updateExisting for application removed from zabbix api after 3.2
- if LooseVersion(self._zbx_api_version) <= LooseVersion('3.2'):
- update_rules['applications']['updateExisting'] = True
-
- # templateLinkage.deleteMissing only available in 4.0 branch higher .16 and higher 4.4.4
- # it's not available in 4.2 branches or lower 4.0.16
- if LooseVersion(self._zbx_api_version).version[:2] == LooseVersion('4.0').version and \
- LooseVersion(self._zbx_api_version).version[:3] >= LooseVersion('4.0.16').version:
- update_rules['templateLinkage']['deleteMissing'] = True
- if LooseVersion(self._zbx_api_version) >= LooseVersion('4.4.4'):
- update_rules['templateLinkage']['deleteMissing'] = True
-
- # templateScreens is named templateDashboards in zabbix >= 5.2
- # https://support.zabbix.com/browse/ZBX-18677
- if LooseVersion(self._zbx_api_version) >= LooseVersion('5.2'):
- update_rules["templateDashboards"] = update_rules.pop("templateScreens")
-
- # Zabbix 5.4 no longer supports applications
- if LooseVersion(self._zbx_api_version) >= LooseVersion('5.4'):
- update_rules.pop('applications', None)
+ update_rules["templateLinkage"]["deleteMissing"] = True
+ update_rules["templateDashboards"] = update_rules.pop("templateScreens")
# before Zabbix 6.2 host_groups and template_group are joined into groups parameter
- if LooseVersion(self._zbx_api_version) < LooseVersion('6.2'):
- update_rules['groups'] = {'createMissing': True}
- update_rules.pop('host_groups', None)
- update_rules.pop('template_groups', None)
+ if LooseVersion(self._zbx_api_version) < LooseVersion("6.2"):
+ update_rules["groups"] = {"createMissing": True}
+ update_rules.pop("host_groups", None)
+ update_rules.pop("template_groups", None)
# The loaded unicode slash of multibyte as a string is escaped when parsing JSON by json.loads in Python2.
# So, it is imported in the unicode string into Zabbix.
# The following processing is removing the unnecessary slash in escaped for decoding correctly to the multibyte string.
# https://github.com/ansible-collections/community.zabbix/issues/314
if PY2:
- template_content = re.sub(r'\\\\u([0-9a-z]{,4})', r'\\u\1', template_content)
+ template_content = re.sub(r"\\\\u([0-9a-z]{,4})", r"\\u\1", template_content)
- import_data = {'format': template_type, 'source': template_content, 'rules': update_rules}
+ import_data = {"format": template_type, "source": template_content, "rules": update_rules}
self._zapi.configuration.import_(import_data)
except Exception as e:
- self._module.fail_json(msg='Unable to import template', details=to_native(e),
+ self._module.fail_json(msg="Unable to import template", details=to_native(e),
exception=traceback.format_exc())
def main():
argument_spec = zabbix_utils.zabbix_common_argument_spec()
argument_spec.update(dict(
- template_name=dict(type='str', required=False),
- template_json=dict(type='json', required=False),
- template_xml=dict(type='str', required=False),
- template_groups=dict(type='list', required=False),
- link_templates=dict(type='list', required=False),
- clear_templates=dict(type='list', required=False),
+ template_name=dict(type="str", required=False),
+ template_json=dict(type="json", required=False),
+ template_xml=dict(type="str", required=False),
+ template_groups=dict(type="list", required=False, elements="str"),
+ link_templates=dict(type="list", required=False, elements="str"),
+ clear_templates=dict(type="list", required=False, elements="str"),
macros=dict(
- type='list',
- elements='dict',
+ type="list",
+ elements="dict",
options=dict(
- macro=dict(type='str', required=True),
- value=dict(type='str', required=True)
+ macro=dict(type="str", required=True),
+ value=dict(type="str", required=True)
)
),
tags=dict(
- type='list',
- elements='dict',
+ type="list",
+ elements="dict",
options=dict(
- tag=dict(type='str', required=True),
- value=dict(type='str', default='')
+ tag=dict(type="str", required=True),
+ value=dict(type="str", default="")
)
),
- omit_date=dict(type='bool', required=False, default=False),
- dump_format=dict(type='str', required=False, default='json', choices=['json', 'xml']),
- state=dict(type='str', default="present", choices=['present', 'absent', 'dump']),
+ state=dict(type="str", default="present", choices=["present", "absent"]),
))
module = AnsibleModule(
argument_spec=argument_spec,
required_one_of=[
- ['template_name', 'template_json', 'template_xml']
+ ["template_name", "template_json", "template_xml"]
],
mutually_exclusive=[
- ['template_name', 'template_json', 'template_xml']
+ ["template_name", "template_json", "template_xml"]
],
required_if=[
- ['state', 'absent', ['template_name']],
- ['state', 'dump', ['template_name']]
+ ["state", "absent", ["template_name"]]
],
supports_check_mode=True
)
- zabbix_utils.require_creds_params(module)
-
- for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']:
- if p in module.params and not module.params[p] is None:
- module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p)
-
- template_name = module.params['template_name']
- template_json = module.params['template_json']
- template_xml = module.params['template_xml']
- template_groups = module.params['template_groups']
- link_templates = module.params['link_templates']
- clear_templates = module.params['clear_templates']
- template_macros = module.params['macros']
- template_tags = module.params['tags']
- omit_date = module.params['omit_date']
- dump_format = module.params['dump_format']
- state = module.params['state']
+ template_name = module.params["template_name"]
+ template_json = module.params["template_json"]
+ template_xml = module.params["template_xml"]
+ template_groups = module.params["template_groups"]
+ link_templates = module.params["link_templates"]
+ clear_templates = module.params["clear_templates"]
+ template_macros = module.params["macros"]
+ template_tags = module.params["tags"]
+ state = module.params["state"]
template = Template(module)
# Identify template names for IDs retrieval
- # Template names are expected to reside in ['zabbix_export']['templates'][*]['template'] for both data types
+ # Template names are expected to reside in ["zabbix_export"]["templates"][*]["template"] for both data types
template_content, template_type = None, None
if template_json is not None:
- template_type = 'json'
+ template_type = "json"
template_content = template_json
json_parsed = template.load_json_template(template_content)
- template_names = list(t['template'] for t in json_parsed['zabbix_export']['templates'])
+ template_names = list(t["template"] for t in json_parsed["zabbix_export"]["templates"])
elif template_xml is not None:
- template_type = 'xml'
+ template_type = "xml"
template_content = template_xml
xml_parsed = template.load_xml_template(template_content)
- template_names = list(t.find('template').text for t in list(xml_parsed.find('templates')))
+ template_names = list(t.find("template").text for t in list(xml_parsed.find("templates")))
else:
template_names = [template_name]
@@ -858,17 +698,6 @@ def main():
template.delete_template(template_ids)
module.exit_json(changed=True, result="Successfully deleted template %s" % template_name)
- elif state == "dump":
- module.deprecate("The 'dump' state has been deprecated and will be removed, use 'zabbix_template_info' module instead.",
- collection_name="community.zabbix", version='3.0.0') # was 2.14
- if not template_ids:
- module.fail_json(msg='Template not found: %s' % template_name)
-
- if dump_format == 'json':
- module.exit_json(changed=False, template_json=template.dump_template(template_ids, template_type='json', omit_date=omit_date))
- elif dump_format == 'xml':
- module.exit_json(changed=False, template_xml=template.dump_template(template_ids, template_type='xml', omit_date=omit_date))
-
elif state == "present":
# Load all subelements for template that were provided by user
group_ids = None
@@ -895,14 +724,14 @@ def main():
tagitem[key] = str(tagitem[key])
if not template_ids:
- # Assume new templates are being added when no ID's were found
+ # Assume new templates are being added when no ID"s were found
if template_content is not None:
template.import_template(template_content, template_type)
module.exit_json(changed=True, result="Template import successful")
else:
if group_ids is None:
- module.fail_json(msg='template_groups are required when creating a new Zabbix template')
+ module.fail_json(msg="template_groups are required when creating a new Zabbix template")
template.add_template(template_name, group_ids, link_template_ids, template_macros, template_tags)
module.exit_json(changed=True, result="Successfully added template: %s" % template_name)
@@ -924,5 +753,5 @@ def main():
module.exit_json(changed=changed, result="Template successfully updated")
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_template_info.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_template_info.py
index acd5b5055..140233e1a 100644
--- a/ansible_collections/community/zabbix/plugins/modules/zabbix_template_info.py
+++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_template_info.py
@@ -8,7 +8,7 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type
-DOCUMENTATION = '''
+DOCUMENTATION = """
module: zabbix_template_info
short_description: Gather information about Zabbix template
author:
@@ -16,7 +16,7 @@ author:
description:
- This module allows you to search for Zabbix template.
requirements:
- - "python >= 2.6"
+ - "python >= 3.9"
options:
template_name:
description:
@@ -26,8 +26,7 @@ options:
format:
description:
- Format to use when dumping template.
- - C(yaml) works only with Zabbix >= 5.2.
- choices: ['json', 'xml', 'yaml', 'none']
+ choices: ["json", "xml", "yaml", "none"]
default: json
type: str
omit_date:
@@ -38,23 +37,19 @@ options:
default: false
extends_documentation_fragment:
- community.zabbix.zabbix
+"""
-notes:
-- there where breaking changes in the Zabbix API with version 5.4 onwards (especially UUIDs) which may
- require you to export the templates again (see version tag >= 5.4 in the resulting file/data).
-'''
-
-EXAMPLES = '''
+EXAMPLES = """
# If you want to use Username and Password to be authenticated by Zabbix Server
- name: Set credentials to access Zabbix Server API
- set_fact:
+ ansible.builtin.set_fact:
ansible_user: Admin
ansible_httpapi_pass: zabbix
# If you want to use API token to be authenticated by Zabbix Server
# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens
- name: Set API token
- set_fact:
+ ansible.builtin.set_fact:
ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895
- name: Get Zabbix template as JSON
@@ -65,7 +60,7 @@ EXAMPLES = '''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_template_info:
template_name: Template
@@ -81,7 +76,7 @@ EXAMPLES = '''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_template_info:
template_name: Template
@@ -97,7 +92,7 @@ EXAMPLES = '''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_template_info:
template_name: Template
@@ -113,15 +108,15 @@ EXAMPLES = '''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_template_info:
template_name: Template
format: none
register: template
-'''
+"""
-RETURN = '''
+RETURN = """
---
template_id:
description: The ID of the template
@@ -133,38 +128,33 @@ template_json:
returned: when format is json and omit_date is true
type: str
sample: {
+ "changed": false,
+ "failed": false,
+ "template_id": "10529",
+ "template_json": {
"zabbix_export": {
- "version": "4.0",
- "groups": [
- {
- "name": "Templates"
- }
- ],
- "templates": [
- {
- "template": "Test Template",
- "name": "Template for Testing",
- "description": "Testing template import",
- "groups": [
+ "groups": [
{
- "name": "Templates"
+ "name": "Templates",
+ "uuid": "7df96b18c230490a9a0a9e2307226338"
}
- ],
- "applications": [
+ ],
+ "templates": [
{
- "name": "Test Application"
+ "groups": [
+ {
+ "name": "Templates"
+ }
+ ],
+ "name": "ExampleTemplateForTempleteInfoModule",
+ "template": "ExampleTemplateForTempleteInfoModule",
+ "uuid": "615e9b0662bb4399a2503a9aaa743517"
}
- ],
- "items": [],
- "discovery_rules": [],
- "httptests": [],
- "macros": [],
- "templates": [],
- "screens": []
- }
- ]
+ ],
+ "version": "6.0"
}
- }
+ }
+ }
template_xml:
description: The XML of the template
@@ -172,34 +162,23 @@ template_xml:
type: str
sample: >-
<zabbix_export>
- <version>4.0</version>
- <date>2019-10-27T14:49:57Z</date>
+ <version>6.0</version>
<groups>
<group>
+ <uuid>7df96b18c230490a9a0a9e2307226338</uuid>
<name>Templates</name>
</group>
</groups>
<templates>
<template>
- <template>Test Template</template>
- <name>Template for Testing</name>
- <description>Testing template import</description>
+ <uuid>9a83162273f74032a1005fdb13943038</uuid>
+ <template>ExampleTemplateForTempleteInfoModule</template>
+ <name>ExampleTemplateForTempleteInfoModule</name>
<groups>
<group>
<name>Templates</name>
</group>
</groups>
- <applications>
- <application>
- <name>Test Application</name>
- </application>
- </applications>
- <items />
- <discovery_rules />
- <httptests />
- <macros />
- <templates />
- <screens />
</template>
</templates>
</zabbix_export>
@@ -210,22 +189,20 @@ template_yaml:
type: str
sample: >-
zabbix_export:
- version: '6.0'
- date: '2022-07-09T13:25:18Z'
+ version: "6.0"
groups:
-
uuid: 7df96b18c230490a9a0a9e2307226338
name: Templates
- templates:
- -
- uuid: 88a9ad240f924f669eb7d4eed736320c
- template: 'Test Template'
- name: 'Template for Testing'
- description: 'Testing template import'
- groups:
+ templates:
-
- name: Templates
-'''
+ uuid: 67b075276bf047d3aeb8f7d5c2121c6a
+ template: ExampleTemplateForTempleteInfoModule
+ name: ExampleTemplateForTempleteInfoModule
+ groups:
+ -
+ name: Templatesn
+"""
import traceback
@@ -244,13 +221,13 @@ class TemplateInfo(ZabbixBase):
def get_template_id(self, template_name):
template_id = []
try:
- template_list = self._zapi.template.get({'output': ['templateid'],
- 'filter': {'host': template_name}})
+ template_list = self._zapi.template.get({"output": ["templateid"],
+ "filter": {"host": template_name}})
except Exception as e:
- self._module.fail_json(msg='Failed to get template: %s' % e)
+ self._module.fail_json(msg="Failed to get template: %s" % e)
if template_list:
- template_id.append(template_list[0]['templateid'])
+ template_id.append(template_list[0]["templateid"])
return template_id
@@ -258,92 +235,86 @@ class TemplateInfo(ZabbixBase):
try:
jsondoc = json.loads(template_json)
# remove date field if requested
- if omit_date and 'date' in jsondoc['zabbix_export']:
- del jsondoc['zabbix_export']['date']
+ if omit_date and "date" in jsondoc["zabbix_export"]:
+ del jsondoc["zabbix_export"]["date"]
return jsondoc
except ValueError as e:
- self._module.fail_json(msg='Invalid JSON provided', details=to_native(e), exception=traceback.format_exc())
+ self._module.fail_json(msg="Invalid JSON provided", details=to_native(e), exception=traceback.format_exc())
def load_yaml_template(self, template_yaml, omit_date=False):
if omit_date:
yaml_lines = template_yaml.splitlines(True)
for index, line in enumerate(yaml_lines):
- if 'date:' in line:
+ if "date:" in line:
del yaml_lines[index]
- return ''.join(yaml_lines)
+ return "".join(yaml_lines)
else:
return template_yaml
- def dump_template(self, template_id, template_type='json', omit_date=False):
+ def dump_template(self, template_id, template_type="json", omit_date=False):
try:
- dump = self._zapi.configuration.export({'format': template_type, 'options': {'templates': template_id}})
- if template_type == 'xml':
- xmlroot = ET.fromstring(dump.encode('utf-8'))
+ dump = self._zapi.configuration.export({"format": template_type, "options": {"templates": template_id}})
+ if template_type == "xml":
+ xmlroot = ET.fromstring(dump.encode("utf-8"))
# remove date field if requested
if omit_date:
date = xmlroot.find(".date")
if date is not None:
xmlroot.remove(date)
if PY2:
- return str(ET.tostring(xmlroot, encoding='utf-8'))
+ return str(ET.tostring(xmlroot, encoding="utf-8"))
else:
- return str(ET.tostring(xmlroot, encoding='utf-8').decode('utf-8'))
- elif template_type == 'yaml':
+ return str(ET.tostring(xmlroot, encoding="utf-8").decode("utf-8"))
+ elif template_type == "yaml":
return self.load_yaml_template(dump, omit_date)
else:
return self.load_json_template(dump, omit_date)
except Exception as e:
- self._module.fail_json(msg='Unable to export template: %s' % e)
+ self._module.fail_json(msg="Unable to export template: %s" % e)
def main():
argument_spec = zabbix_utils.zabbix_common_argument_spec()
argument_spec.update(dict(
- template_name=dict(type='str', required=True),
- omit_date=dict(type='bool', required=False, default=False),
- format=dict(type='str', choices=['json', 'xml', 'yaml', 'none'], default='json')
+ template_name=dict(type="str", required=True),
+ omit_date=dict(type="bool", required=False, default=False),
+ format=dict(type="str", choices=["json", "xml", "yaml", "none"], default="json")
))
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True
)
- zabbix_utils.require_creds_params(module)
-
- for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']:
- if p in module.params and not module.params[p] is None:
- module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p)
-
- template_name = module.params['template_name']
- omit_date = module.params['omit_date']
- format = module.params['format']
+ template_name = module.params["template_name"]
+ omit_date = module.params["omit_date"]
+ format = module.params["format"]
template_info = TemplateInfo(module)
template_id = template_info.get_template_id(template_name)
if not template_id:
- module.fail_json(msg='Template not found: %s' % template_name)
+ module.fail_json(msg="Template not found: %s" % template_name)
- if format == 'json':
+ if format == "json":
module.exit_json(
changed=False,
template_id=template_id[0],
- template_json=template_info.dump_template(template_id, template_type='json', omit_date=omit_date)
+ template_json=template_info.dump_template(template_id, template_type="json", omit_date=omit_date)
)
- elif format == 'xml':
+ elif format == "xml":
module.exit_json(
changed=False,
template_id=template_id[0],
- template_xml=template_info.dump_template(template_id, template_type='xml', omit_date=omit_date)
+ template_xml=template_info.dump_template(template_id, template_type="xml", omit_date=omit_date)
)
- elif format == 'yaml':
+ elif format == "yaml":
module.exit_json(
changed=False,
template_id=template_id[0],
- template_yaml=template_info.dump_template(template_id, template_type='yaml', omit_date=omit_date)
+ template_yaml=template_info.dump_template(template_id, template_type="yaml", omit_date=omit_date)
)
- elif format == 'none':
+ elif format == "none":
module.exit_json(changed=False, template_id=template_id[0])
diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_templategroup.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_templategroup.py
new file mode 100644
index 000000000..7ab39d8fc
--- /dev/null
+++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_templategroup.py
@@ -0,0 +1,180 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+
+DOCUMENTATION = r'''
+---
+module: zabbix_templategroup
+short_description: Create/delete Zabbix template groups
+description:
+ - Create template groups if they do not exist.
+ - Delete existing template groups if they exist.
+author:
+ - "Cove (@cove)"
+ - "Tony Minfei Ding (!UNKNOWN)"
+ - "Harrison Gu (@harrisongu)"
+requirements:
+ - "python >= 2.6"
+options:
+ state:
+ description:
+ - Create or delete template group.
+ required: false
+ type: str
+ default: "present"
+ choices: [ "present", "absent" ]
+ template_groups:
+ description:
+ - List of template groups to create or delete.
+ required: true
+ type: list
+ elements: str
+ aliases: [ "template_group" ]
+
+extends_documentation_fragment:
+- community.zabbix.zabbix
+
+notes:
+ - Too many concurrent updates to the same group may cause Zabbix to return errors, see examples for a workaround if needed.
+'''
+
+EXAMPLES = r'''
+# If you want to use Username and Password to be authenticated by Zabbix Server
+- name: Set credentials to access Zabbix Server API
+ ansible.builtin.set_fact:
+ ansible_user: Admin
+ ansible_httpapi_pass: zabbix
+
+# If you want to use API token to be authenticated by Zabbix Server
+# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens
+- name: Set API token
+ ansible.builtin.set_fact:
+ ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895
+
+# Base create template groups example
+- name: Create template groups
+ # set task level variables as we change ansible_connection plugin here
+ vars:
+ ansible_network_os: community.zabbix.zabbix
+ ansible_connection: httpapi
+ ansible_httpapi_port: 443
+ ansible_httpapi_use_ssl: true
+ ansible_httpapi_validate_certs: false
+ ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_host: zabbix-example-fqdn.org
+ community.zabbix.zabbix_group:
+ state: present
+ template_groups:
+ - Example group1
+ - Example group2
+
+# Limit the Zabbix group creations to one template since Zabbix can return an error when doing concurrent updates
+- name: Create template groups
+ # set task level variables as we change ansible_connection plugin here
+ vars:
+ ansible_network_os: community.zabbix.zabbix
+ ansible_connection: httpapi
+ ansible_httpapi_port: 443
+ ansible_httpapi_use_ssl: true
+ ansible_httpapi_validate_certs: false
+ ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_host: zabbix-example-fqdn.org
+ community.zabbix.zabbix_group:
+ state: present
+ template_groups:
+ - Example group1
+ - Example group2
+ when: inventory_hostname==groups['group_name'][0]
+'''
+
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase
+import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils
+
+
+class TemplateGroup(ZabbixBase):
+ # create template group(s) if not exists
+ def create_template_group(self, group_names):
+ try:
+ group_add_list = []
+ for group_name in group_names:
+ result = self._zapi.templategroup.get({'filter': {'name': group_name}})
+ if not result:
+ if self._module.check_mode:
+ self._module.exit_json(changed=True)
+ self._zapi.templategroup.create({'name': group_name})
+ group_add_list.append(group_name)
+ return group_add_list
+ except Exception as e:
+ self._module.fail_json(msg="Failed to create template group(s): %s" % e)
+
+ # delete template group(s)
+ def delete_template_group(self, group_ids):
+ try:
+ if self._module.check_mode:
+ self._module.exit_json(changed=True)
+ self._zapi.templategroup.delete(group_ids)
+ except Exception as e:
+ self._module.fail_json(msg="Failed to delete template group(s), Exception: %s" % e)
+
+ # get group ids by name
+ def get_group_ids(self, template_groups):
+ group_ids = []
+
+ group_list = self._zapi.templategroup.get({'output': 'extend', 'filter': {'name': template_groups}})
+ for group in group_list:
+ group_id = group['groupid']
+ group_ids.append(group_id)
+ return group_ids, group_list
+
+
+def main():
+ argument_spec = zabbix_utils.zabbix_common_argument_spec()
+ argument_spec.update(dict(
+ template_groups=dict(type='list', required=True, aliases=['template_group'], elements='str'),
+ state=dict(type='str', default="present", choices=['present', 'absent']),
+ ))
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True
+ )
+
+ template_groups = module.params['template_groups']
+ state = module.params['state']
+
+ templateGroup = TemplateGroup(module)
+
+ group_ids = []
+ group_list = []
+ if template_groups:
+ group_ids, group_list = templateGroup.get_group_ids(template_groups)
+
+ if state == "absent":
+ # delete template groups
+ if group_ids:
+ delete_group_names = []
+ templateGroup.delete_template_group(group_ids)
+ for group in group_list:
+ delete_group_names.append(group['name'])
+ module.exit_json(changed=True,
+ result="Successfully deleted template group(s): %s." % ",".join(delete_group_names))
+ else:
+ module.exit_json(changed=False, result="No template group(s) to delete.")
+ else:
+ # create template groups
+ group_add_list = templateGroup.create_template_group(template_groups)
+ if len(group_add_list) > 0:
+ module.exit_json(changed=True, result="Successfully created template group(s): %s" % group_add_list)
+ else:
+ module.exit_json(changed=False)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_token.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_token.py
new file mode 100644
index 000000000..fc4d4c791
--- /dev/null
+++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_token.py
@@ -0,0 +1,288 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright: (c) 2023, ONODERA Masaru <masaru-onodera@ieee.org>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+---
+module: zabbix_token
+
+short_description: Create/Update/Generate/Delete Zabbix token.
+
+description:
+ - This module allows you to create, update, generate and delete Zabbix token.
+
+author:
+ - ONODERA Masaru(@masa-orca)
+
+requirements:
+ - "python >= 3.9"
+
+version_added: 2.1.0
+
+options:
+ name:
+ description:
+ - Name of the token.
+ required: true
+ type: str
+ description:
+ description:
+ - Description of the token.
+ required: false
+ type: str
+ username:
+ description:
+ - Name of user who is the token assinged to.
+ required: true
+ type: str
+ status:
+ description:
+ - Status of the token.
+ required: false
+ type: bool
+ expires_at:
+ description:
+ - A timestamp of the token will be expired.
+ - The token will never expire if C(0)
+ required: false
+ type: int
+ generate_token:
+ description:
+ - New token string will be generated if C(true).
+ required: false
+ type: bool
+ default: false
+ state:
+ description:
+ - Create or delete token.
+ type: str
+ default: present
+ choices:
+ - present
+ - absent
+
+extends_documentation_fragment:
+ - community.zabbix.zabbix
+"""
+
+EXAMPLES = """
+# If you want to use Username and Password to be authenticated by Zabbix Server
+- name: Set credentials to access Zabbix Server API
+ ansible.builtin.set_fact:
+ ansible_user: Admin
+ ansible_httpapi_pass: zabbix
+
+# If you want to use API token to be authenticated by Zabbix Server
+# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens
+- name: Set API token
+ ansible.builtin.set_fact:
+ ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895
+
+- name: Create Zabbix token and generate token string
+ # set task level variables as we change ansible_connection plugin here
+ vars:
+ ansible_network_os: community.zabbix.zabbix
+ ansible_connection: httpapi
+ ansible_httpapi_port: 443
+ ansible_httpapi_use_ssl: true
+ ansible_httpapi_validate_certs: false
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_host: zabbix-example-fqdn.org
+ community.zabbix.zabbix_token:
+ name: test token
+ description: Admin test token
+ username: Admin
+ status: true
+ expires_at: 1700000000
+ generate_token: true
+ state: present
+"""
+
+RETURN = """
+msg:
+ description: The result of the operation
+ returned: success
+ type: str
+ sample: "Successfully created token"
+token:
+ description: Generated token string
+ returned: I(generate_token=true)
+ type: str
+ sample: "8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895"
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase
+import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils
+
+
+class Token(ZabbixBase):
+ def get_userid_from_name(self, username):
+ try:
+ userids = self._zapi.user.get(
+ {"output": "userid", "filter": {"username": username}}
+ )
+ if not userids or len(userids) > 1:
+ self._module.fail_json("User '%s' cannot be found" % username)
+ return userids[0]["userid"]
+ except Exception as e:
+ self._module.fail_json(msg="Failed to get userid: %s" % e)
+
+ # get token
+ def get_token(self, name, userid):
+ try:
+ return self._zapi.token.get(
+ {"output": "extend", "userids": [userid], "filter": {"name": name}}
+ )
+ except Exception as e:
+ self._module.fail_json(msg="Failed to get token: %s" % e)
+
+ def create_token(
+ self, name, description, userid, status, expires_at, generate_token
+ ):
+ try:
+ params = {}
+ params["name"] = name
+ if isinstance(description, str):
+ params["description"] = description
+
+ params["userid"] = userid
+
+ if isinstance(status, bool):
+ if status:
+ params["status"] = "1"
+ else:
+ params["status"] = "0"
+
+ if isinstance(expires_at, str):
+ params["expires_at"] = str(expires_at)
+
+ if self._module.check_mode:
+ self._module.exit_json(changed=True)
+ result = self._zapi.token.create(params)
+
+ if generate_token:
+ generated_tokens = self._zapi.token.generate(result["tokenids"])
+ self._module.exit_json(
+ changed=True,
+ msg="Successfully created token.",
+ token=generated_tokens[0]["token"],
+ )
+ else:
+ self._module.exit_json(changed=True, msg="Successfully created token.")
+
+ except Exception as e:
+ self._module.fail_json(msg="Failed to create token: %s" % e)
+
+ def update_token(
+ self, token, name, description, status, expires_at, generate_token
+ ):
+ try:
+ params = {}
+ params["tokenid"] = token["tokenid"]
+ params["name"] = name
+ if isinstance(description, str) and description != token["description"]:
+ params["description"] = description
+
+ if isinstance(status, bool):
+ if status:
+ if token["status"] != "0":
+ params["status"] = "0"
+ else:
+ if token["status"] != "1":
+ params["status"] = "1"
+
+ if isinstance(expires_at, int) and str(expires_at) != token["expires_at"]:
+ params["expires_at"] = str(expires_at)
+
+ # If params does not have any parameter except tokenid and name, no need to update.
+ if len(params.keys()) == 2:
+ if not generate_token:
+ self._module.exit_json(changed=False)
+ elif self._module.check_mode:
+ self._module.exit_json(changed=True)
+ else:
+ if self._module.check_mode:
+ self._module.exit_json(changed=True)
+ self._zapi.token.update(params)
+
+ if generate_token:
+ generated_tokens = self._zapi.token.generate([token["tokenid"]])
+ self._module.exit_json(
+ changed=True,
+ msg="Successfully updated token.",
+ token=generated_tokens[0]["token"],
+ )
+ else:
+ self._module.exit_json(changed=True, msg="Successfully updated token.")
+
+ except Exception as e:
+ self._module.fail_json(msg="Failed to update token: %s" % e)
+
+ # delete token
+ def delete_token(self, token):
+ try:
+ tokenid = token["tokenid"]
+ if self._module.check_mode:
+ self._module.exit_json(changed=True)
+ self._zapi.token.delete([tokenid])
+ self._module.exit_json(changed=True, msg="Successfully deleted token.")
+ except Exception as e:
+ self._module.fail_json(msg="Failed to delete token: %s" % e)
+
+
+def main():
+ argument_spec = zabbix_utils.zabbix_common_argument_spec()
+ argument_spec.update(
+ dict(
+ name=dict(type="str", required=True),
+ description=dict(type="str"),
+ username=dict(type="str", required=True),
+ status=dict(type="bool"),
+ expires_at=dict(type="int"),
+ generate_token=dict(type="bool", default=False),
+ state=dict(type="str", choices=["present", "absent"], default="present"),
+ )
+ )
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
+
+ name = module.params["name"]
+ description = module.params["description"]
+ username = module.params["username"]
+ status = module.params["status"]
+ expires_at = module.params["expires_at"]
+ generate_token = module.params["generate_token"]
+ state = module.params["state"]
+
+ token_class_obj = Token(module)
+ userid = token_class_obj.get_userid_from_name(username)
+ tokens = token_class_obj.get_token(name, userid)
+ if state == "absent":
+ if len(tokens) == 1:
+ token_class_obj.delete_token(tokens[0])
+ else:
+ module.exit_json(changed=False)
+ else:
+ if len(tokens) == 1:
+ token_class_obj.update_token(
+ tokens[0], name, description, status, expires_at, generate_token
+ )
+ else:
+ token_class_obj.create_token(
+ name, description, userid, status, expires_at, generate_token
+ )
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_user.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_user.py
index 3c655ffe8..92f04b989 100644
--- a/ansible_collections/community/zabbix/plugins/modules/zabbix_user.py
+++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_user.py
@@ -6,9 +6,10 @@
from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
module: zabbix_user
short_description: Create/update/delete Zabbix users
author:
@@ -16,14 +17,12 @@ author:
description:
- This module allows you to create, modify and delete Zabbix users.
requirements:
- - "python >= 2.6"
+ - "python >= 3.9"
options:
username:
description:
- - Name of the user alias in Zabbix.
+ - Username.
- username is the unique identifier used and cannot be updated using this module.
- - alias must be replaced with username since Zabbix 6.4.
- aliases: [ alias ]
required: true
type: str
name:
@@ -45,7 +44,6 @@ options:
description:
- User's password.
- Required unless all of the I(usrgrps) are set to use LDAP as frontend access.
- - Always required for Zabbix versions lower than 4.0.
required: false
type: str
override_passwd:
@@ -54,37 +52,43 @@ options:
- Password will not be updated on subsequent runs without setting this value to yes.
default: no
type: bool
+ current_passwd:
+ description:
+ - Current password for the user when overriding its password.
+ - Required when overriding the logged in user's password.
+ - https://www.zabbix.com/documentation/6.4/en/manual/api/reference/user/update
+ required: false
+ type: str
lang:
description:
- Language code of the user's language.
- - C(default) can be used with Zabbix version 5.2 or higher.
choices:
- - 'en_GB'
- - 'en_US'
- - 'zh_CN'
- - 'cs_CZ'
- - 'fr_FR'
- - 'he_IL'
- - 'it_IT'
- - 'ko_KR'
- - 'ja_JP'
- - 'nb_NO'
- - 'pl_PL'
- - 'pt_BR'
- - 'pt_PT'
- - 'ru_RU'
- - 'sk_SK'
- - 'tr_TR'
- - 'uk_UA'
- - 'default'
+ - "en_GB"
+ - "en_US"
+ - "zh_CN"
+ - "cs_CZ"
+ - "fr_FR"
+ - "he_IL"
+ - "it_IT"
+ - "ko_KR"
+ - "ja_JP"
+ - "nb_NO"
+ - "pl_PL"
+ - "pt_BR"
+ - "pt_PT"
+ - "ru_RU"
+ - "sk_SK"
+ - "tr_TR"
+ - "uk_UA"
+ - "default"
type: str
theme:
description:
- User's theme.
choices:
- - 'default'
- - 'blue-theme'
- - 'dark-theme'
+ - "default"
+ - "blue-theme"
+ - "dark-theme"
type: str
autologin:
description:
@@ -116,7 +120,7 @@ options:
mediatype:
description:
- Media type name to set.
- default: 'Email'
+ default: "Email"
type: str
sendto:
description:
@@ -128,8 +132,8 @@ options:
description:
- Time when the notifications can be sent as a time period or user macros separated by a semicolon.
- Please review the documentation for more information on the supported time period.
- - https://www.zabbix.com/documentation/4.0/manual/appendix/time_period
- default: '1-7,00:00-24:00'
+ - https://www.zabbix.com/documentation/current/en/manual/appendix/time_period
+ default: "1-7,00:00-24:00"
type: str
severity:
description:
@@ -180,26 +184,15 @@ options:
type: bool
type: list
elements: dict
- type:
- description:
- - Type of the user.
- - I(type) can be used when Zabbix version is 5.0 or lower.
- choices:
- - 'Zabbix user'
- - 'Zabbix admin'
- - 'Zabbix super admin'
- type: str
timezone:
description:
- User's time zone.
- - I(timezone) can be used with Zabbix version 5.2 or higher.
- For the full list of supported time zones please refer to U(https://www.php.net/manual/en/timezones.php)
type: str
version_added: 1.2.0
role_name:
description:
- User's role.
- - I(role_name) can be used when Zabbix version is 5.2 or higher.
- Default is C(User role) when creating a new user.
- The default value will be removed at the version 2.0.0.
type: str
@@ -209,25 +202,25 @@ options:
- State of the user.
- On C(present), it will create if user does not exist or update the user if the associated data is different.
- On C(absent) will remove a user if it exists.
- default: 'present'
- choices: ['present', 'absent']
+ default: "present"
+ choices: ["present", "absent"]
type: str
extends_documentation_fragment:
- community.zabbix.zabbix
-'''
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
# If you want to use Username and Password to be authenticated by Zabbix Server
- name: Set credentials to access Zabbix Server API
- set_fact:
+ ansible.builtin.set_fact:
ansible_user: Admin
ansible_httpapi_pass: zabbix
# If you want to use API token to be authenticated by Zabbix Server
# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens
- name: Set API token
- set_fact:
+ ansible.builtin.set_fact:
ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895
- name: create a new zabbix user.
@@ -238,7 +231,7 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_user:
username: example
@@ -251,10 +244,10 @@ EXAMPLES = r'''
lang: en_GB
theme: blue-theme
autologin: no
- autologout: '0'
- refresh: '30'
- rows_per_page: '200'
- after_login_url: ''
+ autologout: "0"
+ refresh: "30"
+ rows_per_page: "200"
+ after_login_url: ""
user_medias:
- mediatype: Email
sendto:
@@ -269,7 +262,6 @@ EXAMPLES = r'''
high: yes
disaster: yes
active: no
- type: Zabbix super admin
state: present
- name: delete existing zabbix user.
@@ -280,20 +272,20 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_user:
username: example
state: absent
-'''
+"""
-RETURN = r'''
+RETURN = r"""
user_ids:
description: User id created or changed
returned: success
type: dict
sample: { "userids": [ "5" ] }
-'''
+"""
import copy
@@ -301,44 +293,40 @@ import copy
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase
-from ansible_collections.community.zabbix.plugins.module_utils.helpers import helper_normalize_data
+from ansible_collections.community.zabbix.plugins.module_utils.helpers import (
+ helper_normalize_data,
+)
from ansible.module_utils.compat.version import LooseVersion
import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils
class User(ZabbixBase):
-
- def username_key(self):
- """ Returns the key name for 'username', which was 'alias'
- before Zabbix 5.4.
- """
- if LooseVersion(self._zbx_api_version) < LooseVersion('5.4'):
- return 'alias'
- return 'username'
-
def get_default_authentication(self):
- auth = self._zapi.authentication.get({'output': 'extend'})
+ auth = self._zapi.authentication.get({"output": "extend"})
try:
if auth["authentication_type"] == "0":
return "internal"
elif auth["authentication_type"] == "1":
return "LDAP"
else:
- self._module.fail_json(msg="Failed to query authentication type. Unknown authentication type %s" % auth)
+ self._module.fail_json(
+ msg="Failed to query authentication type. Unknown authentication type %s"
+ % auth
+ )
except Exception as e:
- self._module.fail_json(msg="Unhandled error while querying authentication type. %s" % (e))
+ self._module.fail_json(
+ msg="Unhandled error while querying authentication type. %s" % (e)
+ )
def get_usergroups_by_name(self, usrgrps):
params = {
- 'output': ['usrgrpid', 'name', 'gui_access'],
- 'filter': {
- 'name': usrgrps
- }
+ "output": ["usrgrpid", "name", "gui_access"],
+ "filter": {"name": usrgrps},
}
res = self._zapi.usergroup.get(params)
if res:
- ids = [{'usrgrpid': g['usrgrpid']} for g in res]
+ ids = [{"usrgrpid": g["usrgrpid"]} for g in res]
# User can be created password-less only when all groups are of non-internal
# authentication types
# 0 = use system default authentication method
@@ -346,199 +334,248 @@ class User(ZabbixBase):
# 2 = use LDAP authentication
# 3 = disable access to the frontend
- if bool([g for g in res if g['gui_access'] == '1']):
+ if bool([g for g in res if g["gui_access"] == "1"]):
require_password = True
- elif bool([g for g in res if g['gui_access'] == '2' or g['gui_access'] == '3']):
+ elif bool(
+ [g for g in res if g["gui_access"] == "2" or g["gui_access"] == "3"]
+ ):
require_password = False
- elif bool([g for g in res if g['gui_access'] == '0']):
+ elif bool([g for g in res if g["gui_access"] == "0"]):
# Zabbix API for versions < 5.2 does not have a way to query the default auth type
# so we must assume its set to internal
- if LooseVersion(self._zbx_api_version) >= LooseVersion('5.2'):
- default_authentication = self.get_default_authentication()
- require_password = True if default_authentication == 'internal' else False
- else:
- default_authentication = "internal"
- require_password = True
+ default_authentication = self.get_default_authentication()
+ require_password = (
+ True if default_authentication == "internal" else False
+ )
- not_found_groups = set(usrgrps) - set([g['name'] for g in res])
+ not_found_groups = set(usrgrps) - set([g["name"] for g in res])
if not_found_groups:
- self._module.fail_json(msg='User groups not found: %s' % not_found_groups)
+ self._module.fail_json(
+ msg="User groups not found: %s" % not_found_groups
+ )
return ids, require_password
else:
- self._module.fail_json(msg='No user groups found')
+ self._module.fail_json(msg="No user groups found")
def check_user_exist(self, username):
- zbx_user = self._zapi.user.get({'output': 'extend', 'filter': {self.username_key(): username},
- 'getAccess': True, 'selectMedias': 'extend',
- 'selectUsrgrps': 'extend'})
+ zbx_user = self._zapi.user.get(
+ {
+ "output": "extend",
+ "filter": {"username": username},
+ "getAccess": True,
+ "selectMedias": "extend",
+ "selectUsrgrps": "extend",
+ }
+ )
return zbx_user
def convert_user_medias_parameter_types(self, user_medias):
copy_user_medias = copy.deepcopy(user_medias)
for user_media in copy_user_medias:
- media_types = self._zapi.mediatype.get({'output': 'extend'})
+ media_types = self._zapi.mediatype.get({"output": "extend"})
for media_type in media_types:
- if LooseVersion(self._zbx_api_version) < LooseVersion('4.4'):
- if media_type['description'] == user_media['mediatype']:
- user_media['mediatypeid'] = media_type['mediatypeid']
- user_media['mediatype'] = media_type['type']
- break
- else:
- if media_type['name'] == user_media['mediatype']:
- user_media['mediatypeid'] = media_type['mediatypeid']
- user_media['mediatype'] = media_type['type']
- break
- if 'mediatypeid' not in user_media:
- self._module.fail_json(msg="Media type not found: %s" % user_media['mediatype'])
+ if media_type["name"] == user_media["mediatype"]:
+ user_media["mediatypeid"] = media_type["mediatypeid"]
+ user_media["mediatype"] = media_type["type"]
+ break
+ if "mediatypeid" not in user_media:
+ self._module.fail_json(
+ msg="Media type not found: %s" % user_media["mediatype"]
+ )
else:
- if user_media['mediatype'] == '0': # E-Mail
+ if user_media["mediatype"] == "0": # E-Mail
# Because user media sendto parameter is raw in parameters specs perform explicit check on type
- if not (isinstance(user_media['sendto'], list) or isinstance(user_media['sendto'], str)):
- self._module.fail_json('For Email media type sendto parameter must be of type list or str.')
- if isinstance(user_media['sendto'], str):
+ if not (
+ isinstance(user_media["sendto"], list)
+ or isinstance(user_media["sendto"], str)
+ ):
+ self._module.fail_json(
+ "For Email media type sendto parameter must be of type list or str."
+ )
+ if isinstance(user_media["sendto"], str):
# sendto should be a list for Email media type
- user_media['sendto'] = [user_media['sendto']]
+ user_media["sendto"] = [user_media["sendto"]]
else:
- if not isinstance(user_media['sendto'], str):
- self._module.fail_json(user_media)
- self._module.fail_json('For any other than Email media type sendto parameter must be of type str.')
- del user_media['mediatype']
-
- severity_binary_number = ''
- for severity_key in 'disaster', 'high', 'average', 'warning', 'information', 'not_classified':
- if user_media['severity'][severity_key]:
- severity_binary_number = severity_binary_number + '1'
+ if not isinstance(user_media["sendto"], str):
+ self._module.fail_json(
+ "For any other than Email media type sendto parameter must be of type str."
+ )
+ del user_media["mediatype"]
+
+ severity_binary_number = ""
+ for severity_key in (
+ "disaster",
+ "high",
+ "average",
+ "warning",
+ "information",
+ "not_classified",
+ ):
+ if user_media["severity"][severity_key]:
+ severity_binary_number = severity_binary_number + "1"
else:
- severity_binary_number = severity_binary_number + '0'
- user_media['severity'] = str(int(severity_binary_number, 2))
+ severity_binary_number = severity_binary_number + "0"
+ user_media["severity"] = str(int(severity_binary_number, 2))
- if user_media['active']:
- user_media['active'] = '0'
+ if user_media["active"]:
+ user_media["active"] = "0"
else:
- user_media['active'] = '1'
+ user_media["active"] = "1"
return copy_user_medias
def get_roleid_by_name(self, role_name):
- roles = self._zapi.role.get({'output': 'extend'})
+ roles = self._zapi.role.get({"output": "extend"})
for role in roles:
- if role['name'] == role_name:
- return role['roleid']
+ if role["name"] == role_name:
+ return role["roleid"]
self._module.fail_json(msg="Role not found: %s" % role_name)
- def user_parameter_difference_check(self, zbx_user, username, name, surname, user_group_ids, passwd, lang, theme,
- autologin, autologout, refresh, rows_per_page, url, user_medias, user_type,
- timezone, role_name, override_passwd):
+ def user_parameter_difference_check(
+ self,
+ zbx_user,
+ username,
+ name,
+ surname,
+ user_group_ids,
+ passwd,
+ lang,
+ theme,
+ autologin,
+ autologout,
+ refresh,
+ rows_per_page,
+ url,
+ user_medias,
+ timezone,
+ role_name,
+ override_passwd,
+ ):
# existing data
existing_data = copy.deepcopy(zbx_user[0])
usrgrpids = []
- for usrgrp in existing_data['usrgrps']:
- usrgrpids.append({'usrgrpid': usrgrp['usrgrpid']})
- existing_data['usrgrps'] = sorted(usrgrpids, key=lambda x: x['usrgrpid'])
- existing_data['user_medias'] = existing_data['medias']
- for del_key in ['medias', 'attempt_clock', 'attempt_failed', 'attempt_ip', 'debug_mode', 'users_status',
- 'gui_access']:
+ for usrgrp in existing_data["usrgrps"]:
+ usrgrpids.append({"usrgrpid": usrgrp["usrgrpid"]})
+ existing_data["usrgrps"] = sorted(usrgrpids, key=lambda x: x["usrgrpid"])
+ existing_data["user_medias"] = existing_data["medias"]
+ for del_key in [
+ "medias",
+ "attempt_clock",
+ "attempt_failed",
+ "attempt_ip",
+ "debug_mode",
+ "users_status",
+ "gui_access",
+ ]:
del existing_data[del_key]
- if 'user_medias' in existing_data and existing_data['user_medias']:
- for user_media in existing_data['user_medias']:
- for del_key in ['mediaid', 'userid']:
+ if "user_medias" in existing_data and existing_data["user_medias"]:
+ for user_media in existing_data["user_medias"]:
+ for del_key in ["mediaid", "userid"]:
del user_media[del_key]
# request data
request_data = {
- 'userid': zbx_user[0]['userid'],
- self.username_key(): username,
- 'name': name,
- 'surname': surname,
- 'usrgrps': sorted(user_group_ids, key=lambda x: x['usrgrpid']),
- 'lang': lang,
- 'theme': theme,
- 'autologin': autologin,
- 'autologout': autologout,
- 'refresh': refresh,
- 'rows_per_page': rows_per_page,
- 'url': url,
+ "userid": zbx_user[0]["userid"],
+ "username": username,
+ "name": name,
+ "surname": surname,
+ "usrgrps": sorted(user_group_ids, key=lambda x: x["usrgrpid"]),
+ "lang": lang,
+ "theme": theme,
+ "autologin": autologin,
+ "autologout": autologout,
+ "refresh": refresh,
+ "rows_per_page": rows_per_page,
+ "url": url,
}
if user_medias:
- request_data['user_medias'] = user_medias
+ request_data["user_medias"] = user_medias
else:
- if 'user_medias' in existing_data and existing_data['user_medias']:
- del existing_data['user_medias']
+ if "user_medias" in existing_data and existing_data["user_medias"]:
+ del existing_data["user_medias"]
if override_passwd:
- request_data['passwd'] = passwd
+ request_data["passwd"] = passwd
- # The type key has changed to roleid key since Zabbix 5.2
- if LooseVersion(self._zbx_api_version) < LooseVersion('5.2'):
- request_data['type'] = user_type
- else:
- request_data['roleid'] = self.get_roleid_by_name(role_name) if role_name else None
- request_data['timezone'] = timezone
+ request_data["roleid"] = (
+ self.get_roleid_by_name(role_name) if role_name else None
+ )
+ request_data["timezone"] = timezone
request_data, del_keys = helper_normalize_data(request_data)
existing_data, _del_keys = helper_normalize_data(existing_data, del_keys)
user_parameter_difference_check_result = True
diff_dict = {}
- if not zabbix_utils.helper_compare_dictionaries(request_data, existing_data, diff_dict):
+ if not zabbix_utils.helper_compare_dictionaries(
+ request_data, existing_data, diff_dict
+ ):
user_parameter_difference_check_result = False
- if LooseVersion(self._zbx_api_version) >= LooseVersion('6.4'):
+ if LooseVersion(self._zbx_api_version) >= LooseVersion("6.4"):
if user_medias:
- request_data['medias'] = user_medias
- del request_data['user_medias']
+ request_data["medias"] = user_medias
+ del request_data["user_medias"]
- diff_params = {
- "before": existing_data,
- "after": request_data
- }
+ diff_params = {"before": existing_data, "after": request_data}
return user_parameter_difference_check_result, diff_params
- def add_user(self, username, name, surname, user_group_ids, passwd, lang, theme, autologin, autologout, refresh,
- rows_per_page, url, user_medias, user_type, require_password, timezone, role_name):
-
- if role_name is None and LooseVersion(self._zbx_api_version) >= LooseVersion('5.2'):
- # This variable is to set the default value because the module must have a backward-compatible.
- # The default value will be removed at the version 2.0.0.
- # https://github.com/ansible-collections/community.zabbix/pull/382
+ def add_user(
+ self,
+ username,
+ name,
+ surname,
+ user_group_ids,
+ passwd,
+ lang,
+ theme,
+ autologin,
+ autologout,
+ refresh,
+ rows_per_page,
+ url,
+ user_medias,
+ require_password,
+ timezone,
+ role_name,
+ ):
+
+ if role_name is None:
role_name = "User role"
user_ids = {}
request_data = {
- self.username_key(): username,
- 'name': name,
- 'surname': surname,
- 'usrgrps': user_group_ids,
- 'lang': lang,
- 'theme': theme,
- 'autologin': autologin,
- 'autologout': autologout,
- 'refresh': refresh,
- 'rows_per_page': rows_per_page,
- 'url': url,
+ "username": username,
+ "name": name,
+ "surname": surname,
+ "usrgrps": user_group_ids,
+ "lang": lang,
+ "theme": theme,
+ "autologin": autologin,
+ "autologout": autologout,
+ "refresh": refresh,
+ "rows_per_page": rows_per_page,
+ "url": url,
}
if user_medias:
- if LooseVersion(self._zbx_api_version) <= LooseVersion('6.2'):
- request_data['user_medias'] = user_medias
+ if LooseVersion(self._zbx_api_version) <= LooseVersion("6.2"):
+ request_data["user_medias"] = user_medias
else:
- request_data['medias'] = user_medias
+ request_data["medias"] = user_medias
- if LooseVersion(self._zbx_api_version) < LooseVersion('4.0') or require_password:
- request_data['passwd'] = passwd
+ if (require_password):
+ request_data["passwd"] = passwd
# The type key has changed to roleid key since Zabbix 5.2
- if LooseVersion(self._zbx_api_version) < LooseVersion('5.2'):
- request_data['type'] = user_type
- else:
- request_data['roleid'] = self.get_roleid_by_name(role_name)
- request_data['timezone'] = timezone
+ request_data["roleid"] = self.get_roleid_by_name(role_name)
+ request_data["timezone"] = timezone
request_data, _del_keys = helper_normalize_data(request_data)
@@ -547,79 +584,84 @@ class User(ZabbixBase):
try:
user_ids = self._zapi.user.create(request_data)
except Exception as e:
- self._module.fail_json(msg="Failed to create user %s: %s" % (username, e))
+ self._module.fail_json(
+ msg="Failed to create user %s: %s" % (username, e)
+ )
else:
- diff_params = {
- "before": "",
- "after": request_data
- }
+ diff_params = {"before": "", "after": request_data}
return user_ids, diff_params
- def update_user(self, zbx_user, username, name, surname, user_group_ids, passwd, lang, theme, autologin, autologout,
- refresh, rows_per_page, url, user_medias, user_type, timezone, role_name, override_passwd):
+ def update_user(
+ self,
+ zbx_user,
+ username,
+ name,
+ surname,
+ user_group_ids,
+ passwd,
+ lang,
+ theme,
+ autologin,
+ autologout,
+ refresh,
+ rows_per_page,
+ url,
+ user_medias,
+ timezone,
+ role_name,
+ override_passwd,
+ current_passwd,
+ ):
user_ids = {}
request_data = {
- 'userid': zbx_user[0]['userid'],
- self.username_key(): username,
- 'name': name,
- 'surname': surname,
- 'usrgrps': user_group_ids,
- 'lang': lang,
- 'theme': theme,
- 'autologin': autologin,
- 'autologout': autologout,
- 'refresh': refresh,
- 'rows_per_page': rows_per_page,
- 'url': url,
+ "userid": zbx_user[0]["userid"],
+ "username": username,
+ "name": name,
+ "surname": surname,
+ "usrgrps": user_group_ids,
+ "lang": lang,
+ "theme": theme,
+ "autologin": autologin,
+ "autologout": autologout,
+ "refresh": refresh,
+ "rows_per_page": rows_per_page,
+ "url": url,
}
if override_passwd:
- request_data['passwd'] = passwd
+ request_data["passwd"] = passwd
+ if current_passwd:
+ request_data["current_passwd"] = current_passwd
- # The type key has changed to roleid key since Zabbix 5.2
- if LooseVersion(self._zbx_api_version) < LooseVersion('5.2'):
- request_data['type'] = user_type
- else:
- request_data['roleid'] = self.get_roleid_by_name(role_name) if role_name else None
- request_data['timezone'] = timezone
+ request_data["roleid"] = (
+ self.get_roleid_by_name(role_name) if role_name else None
+ )
+ request_data["timezone"] = timezone
request_data, _del_keys = helper_normalize_data(request_data)
- # In the case of zabbix 3.2 or less, it is necessary to use updatemedia method to update media.
- if LooseVersion(self._zbx_api_version) <= LooseVersion('3.2'):
- try:
- user_ids = self._zapi.user.update(request_data)
- except Exception as e:
- self._module.fail_json(msg="Failed to update user %s: %s" % (username, e))
-
+ if LooseVersion(self._zbx_api_version) < LooseVersion("6.4"):
try:
if user_medias:
- user_ids = self._zapi.user.updatemedia({
- 'users': [{'userid': zbx_user[0]['userid']}],
- 'medias': user_medias
- })
- except Exception as e:
- self._module.fail_json(msg="Failed to update user medias %s: %s" % (username, e))
-
- if (LooseVersion(self._zbx_api_version) >= LooseVersion('3.4')
- and LooseVersion(self._zbx_api_version) < LooseVersion('6.4')):
- try:
- if user_medias:
- request_data['user_medias'] = user_medias
+ request_data["user_medias"] = user_medias
user_ids = self._zapi.user.update(request_data)
except Exception as e:
- self._module.fail_json(msg="Failed to update user %s: %s" % (username, e))
+ self._module.fail_json(
+ msg="Failed to update user %s: %s" % (username, e)
+ )
- if LooseVersion(self._zbx_api_version) >= LooseVersion('6.4'):
+ if LooseVersion(self._zbx_api_version) >= LooseVersion("6.4"):
try:
if user_medias:
- request_data['medias'] = user_medias
+ request_data["medias"] = user_medias
user_ids = self._zapi.user.update(request_data)
except Exception as e:
- self._module.fail_json(msg="Failed to update user %s: %s" % (username, e))
+ self._module.fail_json(
+ msg="Failed to update user %s: %s" % (username, e)
+ )
return user_ids
@@ -629,107 +671,123 @@ class User(ZabbixBase):
if not self._module.check_mode:
try:
- user_ids = self._zapi.user.delete([zbx_user[0]['userid']])
+ user_ids = self._zapi.user.delete([zbx_user[0]["userid"]])
except Exception as e:
- self._module.fail_json(msg="Failed to delete user %s: %s" % (username, e))
+ self._module.fail_json(
+ msg="Failed to delete user %s: %s" % (username, e)
+ )
else:
- diff_params = {
- "before": zbx_user[0],
- "after": ""
- }
+ diff_params = {"before": zbx_user[0], "after": ""}
return user_ids, diff_params
def main():
argument_spec = zabbix_utils.zabbix_common_argument_spec()
- argument_spec.update(dict(
- username=dict(type='str', required=True, aliases=['alias']),
- name=dict(type='str'),
- surname=dict(type='str'),
- usrgrps=dict(type='list'),
- passwd=dict(type='str', required=False, no_log=True),
- override_passwd=dict(type='bool', required=False, default=False, no_log=False),
- lang=dict(type='str', choices=['en_GB', 'en_US', 'zh_CN', 'cs_CZ', 'fr_FR',
- 'he_IL', 'it_IT', 'ko_KR', 'ja_JP', 'nb_NO',
- 'pl_PL', 'pt_BR', 'pt_PT', 'ru_RU', 'sk_SK',
- 'tr_TR', 'uk_UA', 'default']),
- theme=dict(type='str', choices=['default', 'blue-theme', 'dark-theme']),
- autologin=dict(type='bool'),
- autologout=dict(type='str'),
- refresh=dict(type='str'),
- rows_per_page=dict(type='str'),
- after_login_url=dict(type='str'),
- user_medias=dict(type='list', elements='dict',
- options=dict(mediatype=dict(type='str', default='Email'),
- sendto=dict(type='raw', required=True),
- period=dict(type='str', default='1-7,00:00-24:00'),
- severity=dict(type='dict',
- options=dict(
- not_classified=dict(type='bool', default=True),
- information=dict(type='bool', default=True),
- warning=dict(type='bool', default=True),
- average=dict(type='bool', default=True),
- high=dict(type='bool', default=True),
- disaster=dict(type='bool', default=True)),
- default=dict(
- not_classified=True,
- information=True,
- warning=True,
- average=True,
- high=True,
- disaster=True)),
- active=dict(type='bool', default=True))),
- timezone=dict(type='str'),
- role_name=dict(type='str'),
- type=dict(type='str', choices=['Zabbix user', 'Zabbix admin', 'Zabbix super admin']),
- state=dict(type='str', default="present", choices=['present', 'absent'])
- ))
+ argument_spec.update(
+ dict(
+ username=dict(type="str", required=True),
+ name=dict(type="str"),
+ surname=dict(type="str"),
+ usrgrps=dict(type="list", elements="str"),
+ passwd=dict(type="str", required=False, no_log=True),
+ override_passwd=dict(
+ type="bool", required=False, default=False, no_log=False
+ ),
+ current_passwd=dict(type="str", required=False, no_log=True),
+ lang=dict(
+ type="str",
+ choices=[
+ "en_GB",
+ "en_US",
+ "zh_CN",
+ "cs_CZ",
+ "fr_FR",
+ "he_IL",
+ "it_IT",
+ "ko_KR",
+ "ja_JP",
+ "nb_NO",
+ "pl_PL",
+ "pt_BR",
+ "pt_PT",
+ "ru_RU",
+ "sk_SK",
+ "tr_TR",
+ "uk_UA",
+ "default",
+ ],
+ ),
+ theme=dict(type="str", choices=["default", "blue-theme", "dark-theme"]),
+ autologin=dict(type="bool"),
+ autologout=dict(type="str"),
+ refresh=dict(type="str"),
+ rows_per_page=dict(type="str"),
+ after_login_url=dict(type="str"),
+ user_medias=dict(
+ type="list",
+ elements="dict",
+ options=dict(
+ mediatype=dict(type="str", default="Email"),
+ sendto=dict(type="raw", required=True),
+ period=dict(type="str", default="1-7,00:00-24:00"),
+ severity=dict(
+ type="dict",
+ options=dict(
+ not_classified=dict(type="bool", default=True),
+ information=dict(type="bool", default=True),
+ warning=dict(type="bool", default=True),
+ average=dict(type="bool", default=True),
+ high=dict(type="bool", default=True),
+ disaster=dict(type="bool", default=True),
+ ),
+ default=dict(
+ not_classified=True,
+ information=True,
+ warning=True,
+ average=True,
+ high=True,
+ disaster=True,
+ ),
+ ),
+ active=dict(type="bool", default=True),
+ ),
+ ),
+ timezone=dict(type="str"),
+ role_name=dict(type="str"),
+ state=dict(type="str", default="present", choices=["present", "absent"]),
+ )
+ )
module = AnsibleModule(
argument_spec=argument_spec,
- required_if=[
- ['state', 'present', ['usrgrps']]
- ],
- supports_check_mode=True
+ required_if=[["state", "present", ["usrgrps"]]],
+ supports_check_mode=True,
)
- zabbix_utils.require_creds_params(module)
-
- for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']:
- if p in module.params and not module.params[p] is None:
- module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p)
-
- username = module.params['username']
- name = module.params['name']
- surname = module.params['surname']
- usrgrps = module.params['usrgrps']
- passwd = module.params['passwd']
- override_passwd = module.params['override_passwd']
- lang = module.params['lang']
- theme = module.params['theme']
- autologin = module.params['autologin']
- autologout = module.params['autologout']
- refresh = module.params['refresh']
- rows_per_page = module.params['rows_per_page']
- after_login_url = module.params['after_login_url']
- user_medias = module.params['user_medias']
- user_type = module.params['type']
- timezone = module.params['timezone']
- role_name = module.params['role_name']
- state = module.params['state']
+ username = module.params["username"]
+ name = module.params["name"]
+ surname = module.params["surname"]
+ usrgrps = module.params["usrgrps"]
+ passwd = module.params["passwd"]
+ override_passwd = module.params["override_passwd"]
+ current_passwd = module.params["current_passwd"]
+ lang = module.params["lang"]
+ theme = module.params["theme"]
+ autologin = module.params["autologin"]
+ autologout = module.params["autologout"]
+ refresh = module.params["refresh"]
+ rows_per_page = module.params["rows_per_page"]
+ after_login_url = module.params["after_login_url"]
+ user_medias = module.params["user_medias"]
+ timezone = module.params["timezone"]
+ role_name = module.params["role_name"]
+ state = module.params["state"]
if autologin is not None:
if autologin:
- autologin = '1'
+ autologin = "1"
else:
- autologin = '0'
-
- user_type_dict = {
- 'Zabbix user': '1',
- 'Zabbix admin': '2',
- 'Zabbix super admin': '3'
- }
- user_type = user_type_dict[user_type] if user_type else None
+ autologin = "0"
user = User(module)
@@ -738,31 +796,78 @@ def main():
user_ids = {}
zbx_user = user.check_user_exist(username)
- if state == 'present':
+ if state == "present":
user_group_ids, require_password = user.get_usergroups_by_name(usrgrps)
- if LooseVersion(user._zbx_api_version) < LooseVersion('4.0') or require_password:
+ if (require_password):
if passwd is None:
- module.fail_json(msg='User password is required. One or more groups are not LDAP based.')
+ module.fail_json(
+ msg="User password is required. One or more groups are not LDAP based."
+ )
if zbx_user:
- diff_check_result, diff_params = user.user_parameter_difference_check(zbx_user, username, name, surname,
- user_group_ids, passwd, lang, theme,
- autologin, autologout, refresh,
- rows_per_page, after_login_url,
- user_medias, user_type, timezone,
- role_name, override_passwd)
+ diff_check_result, diff_params = user.user_parameter_difference_check(
+ zbx_user,
+ username,
+ name,
+ surname,
+ user_group_ids,
+ passwd,
+ lang,
+ theme,
+ autologin,
+ autologout,
+ refresh,
+ rows_per_page,
+ after_login_url,
+ user_medias,
+ timezone,
+ role_name,
+ override_passwd,
+ )
if not module.check_mode and diff_check_result:
- user_ids = user.update_user(zbx_user, username, name, surname, user_group_ids, passwd, lang,
- theme, autologin, autologout, refresh, rows_per_page, after_login_url,
- user_medias, user_type, timezone, role_name, override_passwd)
+ user_ids = user.update_user(
+ zbx_user,
+ username,
+ name,
+ surname,
+ user_group_ids,
+ passwd,
+ lang,
+ theme,
+ autologin,
+ autologout,
+ refresh,
+ rows_per_page,
+ after_login_url,
+ user_medias,
+ timezone,
+ role_name,
+ override_passwd,
+ current_passwd,
+ )
else:
diff_check_result = True
- user_ids, diff_params = user.add_user(username, name, surname, user_group_ids, passwd, lang, theme, autologin,
- autologout, refresh, rows_per_page, after_login_url, user_medias,
- user_type, require_password, timezone, role_name)
-
- if state == 'absent':
+ user_ids, diff_params = user.add_user(
+ username,
+ name,
+ surname,
+ user_group_ids,
+ passwd,
+ lang,
+ theme,
+ autologin,
+ autologout,
+ refresh,
+ rows_per_page,
+ after_login_url,
+ user_medias,
+ require_password,
+ timezone,
+ role_name,
+ )
+
+ if state == "absent":
if zbx_user:
diff_check_result = True
user_ids, diff_params = user.delete_user(zbx_user, username)
diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_user_directory.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_user_directory.py
index 818fe98c0..b383fcdcf 100644
--- a/ansible_collections/community/zabbix/plugins/modules/zabbix_user_directory.py
+++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_user_directory.py
@@ -4,10 +4,11 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: zabbix_user_directory
short_description: Create/update/delete Zabbix user directories
@@ -29,7 +30,7 @@ options:
- This parameter is available since Zabbix 6.4.
required: false
type: str
- choices: ['ldap', 'saml']
+ choices: ["ldap", "saml"]
provision_status:
description:
- User directory provisioning status.
@@ -63,7 +64,7 @@ options:
- User directory description.
required: false
type: str
- default: ''
+ default: ""
group_membership:
description:
- LDAP property containing groups of user. E.g. I(memberOf)
@@ -150,7 +151,7 @@ options:
- LDAP bind distinguished name string. Can be empty for anonymous binding.
required: false
type: str
- default: ''
+ default: ""
idp_entityid:
description:
- SAML URI that identifies the IdP in SAML messages.
@@ -167,7 +168,7 @@ options:
type: str
sso_url:
description:
- - SAML URL of the IdP's SAML SSO service, to which Zabbix will send SAML authentication requests.
+ - SAML URL of the IdP"s SAML SSO service, to which Zabbix will send SAML authentication requests.
- required if C(idp_type) is set to I(saml).
- This parameter is available since Zabbix 6.4.
required: false
@@ -302,27 +303,27 @@ options:
- State of the user directory.
- On C(present), it will create if user directory does not exist or update it if the associated data is different.
- On C(absent) will remove the user directory if it exists.
- choices: ['present', 'absent']
- default: 'present'
+ choices: ["present", "absent"]
+ default: "present"
type: str
extends_documentation_fragment:
- community.zabbix.zabbix
-'''
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
---
# If you want to use Username and Password to be authenticated by Zabbix Server
- name: Set credentials to access Zabbix Server API
- set_fact:
+ ansible.builtin.set_fact:
ansible_user: Admin
ansible_httpapi_pass: zabbix
# If you want to use API token to be authenticated by Zabbix Server
# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens
- name: Set API token
- set_fact:
+ ansible.builtin.set_fact:
ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895
- name: Create new user directory or update existing info (Zabbix <= 6.2)
@@ -333,18 +334,18 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_user_directory:
state: present
name: TestUserDirectory
- host: 'test.com'
+ host: "test.com"
port: 389
- base_dn: 'ou=Users,dc=example,dc=org'
- search_attribute: 'uid'
- bind_dn: 'cn=ldap_search,dc=example,dc=org'
- description: 'Test user directory'
- search_filter: '(%{attr}=test_user)'
+ base_dn: "ou=Users,dc=example,dc=org"
+ search_attribute: "uid"
+ bind_dn: "cn=ldap_search,dc=example,dc=org"
+ description: "Test user directory"
+ search_filter: "(%{attr}=test_user)"
start_tls: 0
- name: Create new user directory with LDAP IDP or update existing info (Zabbix >= 6.4)
@@ -355,22 +356,22 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_user_directory:
state: present
name: TestUserDirectory
idp_type: ldap
- host: 'test.ca'
+ host: "test.ca"
port: 389
- base_dn: 'ou=Users,dc=example,dc=org'
- search_attribute: 'uid'
+ base_dn: "ou=Users,dc=example,dc=org"
+ search_attribute: "uid"
provision_status: true
group_name: cn
group_basedn: ou=Group,dc=example,dc=org
group_member: member
user_ref_attr: uid
- group_filter: '(member=uid=%{ref},ou=Users,dc=example,dc=com)'
+ group_filter: "(member=uid=%{ref},ou=Users,dc=example,dc=com)"
user_username: first_name
user_lastname: last_name
provision_media:
@@ -391,7 +392,7 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_user_directory:
state: present
@@ -414,7 +415,7 @@ EXAMPLES = r'''
role: Guest role
user_groups:
- Guests
-'''
+"""
from ansible.module_utils.basic import AnsibleModule
@@ -426,220 +427,305 @@ import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabb
def main():
argument_spec = zabbix_utils.zabbix_common_argument_spec()
- argument_spec.update(dict(
- name=dict(type='str', required=True),
- idp_type=dict(type='str', required=False, choices=['ldap', 'saml']),
- host=dict(type='str', required=False),
- port=dict(type='int', required=False),
- base_dn=dict(type='str', required=False),
- search_attribute=dict(type='str', required=False),
- bind_dn=dict(type='str', required=False, default=''),
- bind_password=dict(type='str', required=False, no_log=True),
- description=dict(type='str', required=False, default=''),
- search_filter=dict(type='str', default='(%{attr}=%{user})', required=False),
- start_tls=dict(type='int', required=False, choices=[0, 1], default=0),
- idp_entityid=dict(type='str', required=False),
- sp_entityid=dict(type='str', required=False),
- sso_url=dict(type='str', required=False),
- slo_url=dict(type='str', required=False),
- username_attribute=dict(type='str', required=False),
- nameid_format=dict(type='str', required=False),
- scim_status=dict(type='bool', required=False, default=False),
- encrypt_nameid=dict(type='bool', required=False, default=False),
- encrypt_assertions=dict(type='bool', required=False, default=False),
- sign_messages=dict(type='bool', required=False, default=False),
- sign_assertions=dict(type='bool', required=False, default=False),
- sign_authn_requests=dict(type='bool', required=False, default=False),
- sign_logout_requests=dict(type='bool', required=False, default=False),
- sign_logout_responses=dict(type='bool', required=False, default=False),
- provision_status=dict(type='bool', required=False, default=False),
- group_basedn=dict(type='str', required=False),
- group_filter=dict(type='str', required=False),
- group_member=dict(type='str', required=False),
- group_membership=dict(type='str', required=False),
- group_name=dict(type='str', required=False),
- user_lastname=dict(type='str', required=False),
- user_ref_attr=dict(type='str', required=False),
- user_username=dict(type='str', required=False),
- provision_media=dict(
- type='list',
- required=False,
- elements='dict',
- options=dict(
- name=dict(type='str', required=True),
- mediatype=dict(type='str', required=True),
- attribute=dict(type='str', required=True)
- )
- ),
- provision_groups=dict(
- type='list',
- required=False,
- elements='dict',
- options=dict(
- name=dict(type='str', required=True),
- role=dict(type='str', required=True),
- user_groups=dict(type='list', elements='str', required=True)
- )
- ),
- state=dict(type='str', default='present', choices=['present', 'absent'])
- ))
-
- module = AnsibleModule(
- argument_spec=argument_spec,
- supports_check_mode=True
+ argument_spec.update(
+ dict(
+ name=dict(type="str", required=True),
+ idp_type=dict(type="str", required=False, choices=["ldap", "saml"]),
+ host=dict(type="str", required=False),
+ port=dict(type="int", required=False),
+ base_dn=dict(type="str", required=False),
+ search_attribute=dict(type="str", required=False),
+ bind_dn=dict(type="str", required=False, default=""),
+ bind_password=dict(type="str", required=False, no_log=True),
+ description=dict(type="str", required=False, default=""),
+ search_filter=dict(type="str", default="(%{attr}=%{user})", required=False),
+ start_tls=dict(type="int", required=False, choices=[0, 1], default=0),
+ idp_entityid=dict(type="str", required=False),
+ sp_entityid=dict(type="str", required=False),
+ sso_url=dict(type="str", required=False),
+ slo_url=dict(type="str", required=False),
+ username_attribute=dict(type="str", required=False),
+ nameid_format=dict(type="str", required=False),
+ scim_status=dict(type="bool", required=False, default=False),
+ encrypt_nameid=dict(type="bool", required=False, default=False),
+ encrypt_assertions=dict(type="bool", required=False, default=False),
+ sign_messages=dict(type="bool", required=False, default=False),
+ sign_assertions=dict(type="bool", required=False, default=False),
+ sign_authn_requests=dict(type="bool", required=False, default=False),
+ sign_logout_requests=dict(type="bool", required=False, default=False),
+ sign_logout_responses=dict(type="bool", required=False, default=False),
+ provision_status=dict(type="bool", required=False, default=False),
+ group_basedn=dict(type="str", required=False),
+ group_filter=dict(type="str", required=False),
+ group_member=dict(type="str", required=False),
+ group_membership=dict(type="str", required=False),
+ group_name=dict(type="str", required=False),
+ user_lastname=dict(type="str", required=False),
+ user_ref_attr=dict(type="str", required=False),
+ user_username=dict(type="str", required=False),
+ provision_media=dict(
+ type="list",
+ required=False,
+ elements="dict",
+ options=dict(
+ name=dict(type="str", required=True),
+ mediatype=dict(type="str", required=True),
+ attribute=dict(type="str", required=True),
+ ),
+ ),
+ provision_groups=dict(
+ type="list",
+ required=False,
+ elements="dict",
+ options=dict(
+ name=dict(type="str", required=True),
+ role=dict(type="str", required=True),
+ user_groups=dict(type="list", elements="str", required=True),
+ ),
+ ),
+ state=dict(type="str", default="present", choices=["present", "absent"]),
+ )
)
- ''' For future when < 6.4 disappears we should use this, now we cannot do this as at this point Zabbix version is unknown
+
+ module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)
+ """ For future when < 6.4 disappears we should use this, now we cannot do this as at this point Zabbix version is unknown
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
- ('state', 'present', ('idp_type',)),
- ('idp_type', 'ldap', ('host', 'port', 'base_dn', 'search_attribute'), False),
- ('idp_type', 'saml', ('idp_entityid', 'sp_entityid', 'sso_url', 'username_attribute'), False),
- ('provision_status', 'true', ('provision_groups'))
+ ("state", "present", ("idp_type",)),
+ ("idp_type", "ldap", ("host", "port", "base_dn", "search_attribute"), False),
+ ("idp_type", "saml", ("idp_entityid", "sp_entityid", "sso_url", "username_attribute"), False),
+ ("provision_status", "true", ("provision_groups"))
]
)
- '''
-
- zabbix_utils.require_creds_params(module)
-
- for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']:
- if p in module.params and not module.params[p] is None:
- module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p)
-
- parameters = {
- 'name': module.params['name']
- }
- for p in ['host', 'port', 'base_dn', 'search_attribute', 'bind_dn', 'bind_password', 'description', 'start_tls']:
+ """
+
+ parameters = {"name": module.params["name"]}
+ for p in [
+ "host",
+ "port",
+ "base_dn",
+ "search_attribute",
+ "bind_dn",
+ "bind_password",
+ "description",
+ "start_tls",
+ ]:
if module.params[p]:
- if p in ['port', 'start_tls']:
+ if p in ["port", "start_tls"]:
parameters[p] = str(module.params[p])
else:
parameters[p] = module.params[p]
- state = module.params['state']
+ state = module.params["state"]
user_directory = ZabbixBase(module)
- if LooseVersion(user_directory._zbx_api_version) < LooseVersion('6.2'):
- module.fail_json(msg='Zabbix < 6.2 does not support user directories.')
+ if LooseVersion(user_directory._zbx_api_version) < LooseVersion("6.2"):
+ module.fail_json(msg="Zabbix < 6.2 does not support user directories.")
- if LooseVersion(user_directory._zbx_api_version) < LooseVersion('6.4'):
- parameters['search_filter'] = module.params['search_filter']
- directory = user_directory._zapi.userdirectory.get({'filter': {'name': parameters['name']}})
+ if LooseVersion(user_directory._zbx_api_version) < LooseVersion("6.4"):
+ parameters["search_filter"] = module.params["search_filter"]
+ directory = user_directory._zapi.userdirectory.get(
+ {"filter": {"name": parameters["name"]}}
+ )
else:
# Zabbix >= 6.4
# Mandatory parameters check
- if state == 'present' and not module.params['idp_type']:
- module.fail_json('"idp_type" parameter must be provided when state is "present"')
- if module.params['idp_type']:
- if (module.params['idp_type'] == 'ldap'
- and (not module.params['host'] or not module.params['port'] or not module.params['base_dn'] or not module.params['search_attribute'])):
- module.fail_json('"host", "port", "base_dn", "search_attribute" must be provided when idp_type is "ldap"')
- if (module.params['idp_type'] == 'saml'
- and (not module.params['idp_entityid'] or not module.params['sp_entityid']
- or not module.params['sso_url'] or not module.params['username_attribute'])):
- module.fail_json('"idp_entityid", "sp_entityid", "sso_url", "username_attribute" must be provided when idp_type is "ldap"')
+ if state == "present" and not module.params["idp_type"]:
+ module.fail_json(
+ "'idp_type' parameter must be provided when state is 'present'"
+ )
+ if module.params["idp_type"]:
+ if module.params["idp_type"] == "ldap" and (
+ not module.params["host"]
+ or not module.params["port"]
+ or not module.params["base_dn"]
+ or not module.params["search_attribute"]
+ ):
+ module.fail_json(
+ "'host', 'port', 'base_dn', 'search_attribute' must be provided when idp_type is 'ldap'"
+ )
+ if module.params["idp_type"] == "saml" and (
+ not module.params["idp_entityid"]
+ or not module.params["sp_entityid"]
+ or not module.params["sso_url"]
+ or not module.params["username_attribute"]
+ ):
+ module.fail_json(
+ "'idp_entityid', 'sp_entityid', 'sso_url', 'username_attribute' must be provided when idp_type is 'ldap'"
+ )
directory = user_directory._zapi.userdirectory.get(
{
- 'search': {'name': parameters['name']},
- 'selectProvisionMedia': 'extend',
- 'selectProvisionGroups': 'extend'
- })
- parameters['idp_type'] = str(zabbix_utils.helper_to_numeric_value(['', 'ldap', 'saml'], module.params['idp_type']))
- if parameters['idp_type'] == '1':
+ "search": {"name": parameters["name"]},
+ "selectProvisionMedia": "extend",
+ "selectProvisionGroups": "extend",
+ }
+ )
+ parameters["idp_type"] = str(
+ zabbix_utils.helper_to_numeric_value(
+ ["", "ldap", "saml"], module.params["idp_type"]
+ )
+ )
+ if parameters["idp_type"] == "1":
# idp_type is ldap
- parameters['search_filter'] = module.params['search_filter']
- elif parameters['idp_type'] == '2':
+ parameters["search_filter"] = module.params["search_filter"]
+ elif parameters["idp_type"] == "2":
# idp_type is saml
- for p in ['idp_entityid', 'sso_url', 'username_attribute', 'sp_entityid', 'slo_url', 'nameid_format']:
+ for p in [
+ "idp_entityid",
+ "sso_url",
+ "username_attribute",
+ "sp_entityid",
+ "slo_url",
+ "nameid_format",
+ ]:
# str parameters
if module.params[p]:
parameters[p] = module.params[p]
- for p in ['scim_status', 'encrypt_nameid', 'encrypt_assertions', 'sign_messages', 'sign_assertions',
- 'sign_authn_requests', 'sign_logout_requests', 'sign_logout_responses']:
+ for p in [
+ "scim_status",
+ "encrypt_nameid",
+ "encrypt_assertions",
+ "sign_messages",
+ "sign_assertions",
+ "sign_authn_requests",
+ "sign_logout_requests",
+ "sign_logout_responses",
+ ]:
# boolean parameters
if module.params[p]:
parameters[p] = str(int(module.params[p]))
- if module.params['provision_status']:
- parameters['provision_status'] = int(module.params['provision_status'])
+ if module.params["provision_status"]:
+ parameters["provision_status"] = int(module.params["provision_status"])
- if module.params['provision_media']:
- if 'provision_status' not in parameters or not parameters['provision_status']:
- module.fail_json('"provision_status" must be True to define "provision_media"')
- parameters['provision_media'] = []
- for media in module.params['provision_media']:
- media_type_name = media['mediatype']
- media_type_ids = user_directory._zapi.mediatype.get({'filter': {'name': media_type_name}})
+ if module.params["provision_media"]:
+ if (
+ "provision_status" not in parameters
+ or not parameters["provision_status"]
+ ):
+ module.fail_json(
+ "'provision_status' must be True to define 'provision_media'"
+ )
+ parameters["provision_media"] = []
+ for media in module.params["provision_media"]:
+ media_type_name = media["mediatype"]
+ media_type_ids = user_directory._zapi.mediatype.get(
+ {"filter": {"name": media_type_name}}
+ )
if not media_type_ids:
- module.fail_json('Mediatype "%s" cannot be found' % media_type_name)
- parameters['provision_media'].append(
+ module.fail_json("Mediatype '%s' cannot be found" % media_type_name)
+ parameters["provision_media"].append(
{
- 'name': media['name'],
- 'mediatypeid': media_type_ids[0]['mediatypeid'],
- 'attribute': media['attribute']
+ "name": media["name"],
+ "mediatypeid": media_type_ids[0]["mediatypeid"],
+ "attribute": media["attribute"],
}
)
- if module.params['provision_groups']:
- if 'provision_status' not in parameters or not parameters['provision_status']:
- module.fail_json('"provision_status" must be True to define "provision_groups"')
- parameters['provision_groups'] = []
- for group in module.params['provision_groups']:
- role_name = group['role']
- role_ids = user_directory._zapi.role.get({'filter': {'name': role_name}})
+ if module.params["provision_groups"]:
+ if (
+ "provision_status" not in parameters
+ or not parameters["provision_status"]
+ ):
+ module.fail_json(
+ "'provision_status' must be True to define 'provision_groups'"
+ )
+ parameters["provision_groups"] = []
+ for group in module.params["provision_groups"]:
+ role_name = group["role"]
+ role_ids = user_directory._zapi.role.get(
+ {"filter": {"name": role_name}}
+ )
if not role_ids:
- module.fail_json('Role "%s" cannot be found' % role_name)
+ module.fail_json("Role '%s' cannot be found" % role_name)
user_groups = []
- for user_group in group['user_groups']:
- ug_ids = user_directory._zapi.usergroup.get({'filter': {'name': user_group}})
+ for user_group in group["user_groups"]:
+ ug_ids = user_directory._zapi.usergroup.get(
+ {"filter": {"name": user_group}}
+ )
if not ug_ids:
- module.fail_json('User group "%s" cannot be found' % user_group)
- user_groups.append({'usrgrpid': ug_ids[0]['usrgrpid']})
- parameters['provision_groups'].append(
+ module.fail_json("User group '%s' cannot be found" % user_group)
+ user_groups.append({"usrgrpid": ug_ids[0]["usrgrpid"]})
+ parameters["provision_groups"].append(
{
- 'name': group['name'],
- 'roleid': role_ids[0]['roleid'],
- 'user_groups': user_groups
+ "name": group["name"],
+ "roleid": role_ids[0]["roleid"],
+ "user_groups": user_groups,
}
)
- for p in ['group_basedn', 'group_filter', 'group_member', 'group_membership', 'group_name', 'group_name',
- 'user_lastname', 'user_ref_attr', 'user_username']:
+ for p in [
+ "group_basedn",
+ "group_filter",
+ "group_member",
+ "group_membership",
+ "group_name",
+ "group_name",
+ "user_lastname",
+ "user_ref_attr",
+ "user_username",
+ ]:
if module.params[p]:
parameters[p] = module.params[p]
if not directory:
# No User Directory found with given name
- if state == 'absent':
- module.exit_json(changed=False, msg='User directory not found. Not changed: %s' % parameters['name'])
+ if state == "absent":
+ module.exit_json(
+ changed=False,
+ msg="User directory not found. Not changed: %s" % parameters["name"],
+ )
- elif state == 'present':
+ elif state == "present":
if module.check_mode:
module.exit_json(changed=True)
else:
user_directory._zapi.userdirectory.create(parameters)
- module.exit_json(changed=True, result='Successfully added user directory %s' % parameters['name'])
+ module.exit_json(
+ changed=True,
+ result="Successfully added user directory %s" % parameters["name"],
+ )
else:
# User Directory with given name exists
- if state == 'absent':
- user_directory._zapi.userdirectory.delete([directory[0]['userdirectoryid']])
- module.exit_json(changed=True, result='Successfully deleted user directory %s' % parameters['name'])
- elif state == 'present':
+ if state == "absent":
+ if module.check_mode:
+ module.exit_json(changed=True)
+ user_directory._zapi.userdirectory.delete([directory[0]["userdirectoryid"]])
+ module.exit_json(
+ changed=True,
+ result="Successfully deleted user directory %s" % parameters["name"],
+ )
+ elif state == "present":
diff_dict = {}
- if 'provision_status' in directory[0]:
+ if "provision_status" in directory[0]:
# Zabbix API returns provision_status as str we need it as int to correctly compare
- directory[0]['provision_status'] = int(directory[0]['provision_status'])
- if zabbix_utils.helper_compare_dictionaries(parameters, directory[0], diff_dict):
- parameters['userdirectoryid'] = directory[0]['userdirectoryid']
+ directory[0]["provision_status"] = int(directory[0]["provision_status"])
+ if zabbix_utils.helper_compare_dictionaries(
+ parameters, directory[0], diff_dict
+ ):
+ parameters["userdirectoryid"] = directory[0]["userdirectoryid"]
+ if module.check_mode:
+ module.exit_json(changed=True)
user_directory._zapi.userdirectory.update(parameters)
- module.exit_json(changed=True, result='Successfully updated user directory %s' % parameters['name'])
+ module.exit_json(
+ changed=True,
+ result="Successfully updated user directory %s"
+ % parameters["name"],
+ )
else:
- module.exit_json(changed=False, result='User directory %s is up-to date' % parameters['name'])
+ module.exit_json(
+ changed=False,
+ result="User directory %s is up-to date" % parameters["name"],
+ )
- module.exit_json(changed=False, result='User directory %s is up-to date' % parameters['name'])
+ module.exit_json(
+ changed=False,
+ result="User directory %s is up-to date" % parameters["name"],
+ )
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_user_info.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_user_info.py
index 8fd0323c4..c71479532 100644
--- a/ansible_collections/community/zabbix/plugins/modules/zabbix_user_info.py
+++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_user_info.py
@@ -8,7 +8,7 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type
-DOCUMENTATION = '''
+DOCUMENTATION = """
module: zabbix_user_info
short_description: Gather information about Zabbix user
author:
@@ -16,32 +16,30 @@ author:
description:
- This module allows you to search for Zabbix user entries.
requirements:
- - "python >= 2.6"
+ - "python >= 3.9"
options:
username:
description:
- - Name of the user alias in Zabbix.
- - username is the unique identifier used and cannot be updated using this module.
- - alias should be replaced with username
- aliases: [ alias ]
+ - User name.
+ - sername is the unique identifier used and cannot be updated using this module.
required: true
type: str
extends_documentation_fragment:
- community.zabbix.zabbix
-'''
+"""
-EXAMPLES = '''
+EXAMPLES = """
# If you want to use Username and Password to be authenticated by Zabbix Server
- name: Set credentials to access Zabbix Server API
- set_fact:
+ ansible.builtin.set_fact:
ansible_user: Admin
ansible_httpapi_pass: zabbix
# If you want to use API token to be authenticated by Zabbix Server
# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens
- name: Set API token
- set_fact:
+ ansible.builtin.set_fact:
ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895
- name: Get zabbix user info
@@ -52,13 +50,13 @@ EXAMPLES = '''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_user_info:
username: example
-'''
+"""
-RETURN = '''
+RETURN = """
zabbix_user:
description: example
returned: always
@@ -103,11 +101,10 @@ zabbix_user:
}
]
}
-'''
+"""
from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.compat.version import LooseVersion
from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase
import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils
@@ -117,13 +114,10 @@ class User(ZabbixBase):
def get_user_by_user_username(self, username):
zabbix_user = ""
try:
- data = {'output': 'extend', 'filter': {},
- 'getAccess': True, 'selectMedias': 'extend',
- 'selectUsrgrps': 'extend'}
- if LooseVersion(self._zbx_api_version) >= LooseVersion('5.4'):
- data['filter']['username'] = username
- else:
- data['filter']['alias'] = username
+ data = {"output": "extend", "filter": {},
+ "getAccess": True, "selectMedias": "extend",
+ "selectUsrgrps": "extend"}
+ data["filter"]["username"] = username
zabbix_user = self._zapi.user.get(data)
except Exception as e:
@@ -141,20 +135,14 @@ class User(ZabbixBase):
def main():
argument_spec = zabbix_utils.zabbix_common_argument_spec()
argument_spec.update(dict(
- username=dict(type='str', required=True, aliases=['alias']),
+ username=dict(type="str", required=True),
))
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True
)
- zabbix_utils.require_creds_params(module)
-
- for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']:
- if p in module.params and not module.params[p] is None:
- module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p)
-
- username = module.params['username']
+ username = module.params["username"]
user = User(module)
zabbix_user = user.get_user_by_user_username(username)
diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_user_role.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_user_role.py
index 596ef5570..3495f39e1 100644
--- a/ansible_collections/community/zabbix/plugins/modules/zabbix_user_role.py
+++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_user_role.py
@@ -8,7 +8,7 @@
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
module: zabbix_user_role
short_description: Adds or removes zabbix roles
author:
@@ -16,15 +16,15 @@ author:
description:
- This module adds or removes zabbix roles
requirements:
- - "python >= 2.6"
+ - "python >= 3.9"
options:
state:
description:
- State of the user_role.
- On C(present), it will create if user_role does not exist or update the user_role if the associated data is different.
- On C(absent) will remove a user_role if it exists.
- default: 'present'
- choices: ['present', 'absent']
+ default: "present"
+ choices: ["present", "absent"]
type: str
required: false
name:
@@ -47,19 +47,19 @@ options:
required: false
extends_documentation_fragment:
- community.zabbix.zabbix
-'''
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
# If you want to use Username and Password to be authenticated by Zabbix Server
- name: Set credentials to access Zabbix Server API
- set_fact:
+ ansible.builtin.set_fact:
ansible_user: Admin
ansible_httpapi_pass: zabbix
# If you want to use API token to be authenticated by Zabbix Server
# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens
- name: Set API token
- set_fact:
+ ansible.builtin.set_fact:
ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895
# Create user role Operators with ui elements monitoring.hosts
@@ -73,7 +73,7 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_user_role:
state: present
@@ -86,21 +86,21 @@ EXAMPLES = r'''
status: 0
- name: "monitoring.maps"
status: 1
-'''
+"""
-RETURN = r'''
+RETURN = r"""
# Return values
msg:
description: The result of the action
type: str
returned: always
- sample: 'No action'
+ sample: "No action"
changed:
description: The consequence of the action
type: bool
returned: always
sample: false
-'''
+"""
from ansible.module_utils.basic import AnsibleModule
@@ -135,7 +135,7 @@ class UserRole(ZabbixBase):
verdict = True
for rule, value in inp.items():
if not isinstance(value, list):
- verdict = verdict and self.__find_val(out.get(rule, ''), value)
+ verdict = verdict and self.__find_val(out.get(rule, ""), value)
else:
if len(value):
if not isinstance(value[0], dict):
@@ -162,10 +162,10 @@ def main():
argument_spec = zabbix_utils.zabbix_common_argument_spec()
argument_spec.update(dict(
- state=dict(type='str', required=False, default='present', choices=['present', 'absent']),
- name=dict(type='str', required=True),
- type=dict(type='str', required=False, choices=["User", "Admin", "Super Admin"], default='User'),
- rules=dict(type='dict', required=False, default={}),
+ state=dict(type="str", required=False, default="present", choices=["present", "absent"]),
+ name=dict(type="str", required=True),
+ type=dict(type="str", required=False, choices=["User", "Admin", "Super Admin"], default="User"),
+ rules=dict(type="dict", required=False, default={}),
))
# the AnsibleModule object
@@ -174,19 +174,12 @@ def main():
supports_check_mode=False
)
- zabbix_utils.require_creds_params(module)
-
- for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']:
- if p in module.params and not module.params[p] is None:
- module.warn('Option "%s" is deprecated with the move to httpapi connection '
- 'and will be removed in the next release' % p)
-
- state = module.params['state']
- name = module.params['name']
+ state = module.params["state"]
+ name = module.params["name"]
type = zabbix_utils.helper_to_numeric_value(
- ['', 'user', 'admin', 'super admin'], module.params['type'].lower()
+ ["", "user", "admin", "super admin"], module.params["type"].lower()
)
- rules = module.params['rules']
+ rules = module.params["rules"]
user_role = UserRole(module)
@@ -194,19 +187,19 @@ def main():
if result:
if len(result) == 1:
role = result[0]
- if role['readonly'] != 1:
- roleid = role['roleid']
- if state == 'absent':
+ if role["readonly"] != 1:
+ roleid = role["roleid"]
+ if state == "absent":
result = user_role._zapi.role.delete([f"{roleid}"])
changed = True
msg = "Role deleted"
else:
- if not user_role.is_part_of(rules, role['rules']):
+ if not user_role.is_part_of(rules, role["rules"]):
result = user_role._zapi.role.update({"roleid": roleid, "rules": rules})
changed = True
msg = "Role updated"
else:
- module.fail_json(msg='Too many role matches')
+ module.fail_json(msg="Too many role matches")
else:
user_role._zapi.role.create({
"name": name,
@@ -219,5 +212,5 @@ def main():
module.exit_json(msg=msg, changed=changed)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_usergroup.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_usergroup.py
index b2a341472..14539d932 100644
--- a/ansible_collections/community/zabbix/plugins/modules/zabbix_usergroup.py
+++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_usergroup.py
@@ -5,9 +5,10 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: zabbix_usergroup
short_description: Create/delete/update Zabbix user groups
@@ -18,7 +19,7 @@ description:
author:
- "Tobias Birkefeld (@tcraxs)"
requirements:
- - "python >= 2.6"
+ - "python >= 3.9"
options:
name:
description:
@@ -126,13 +127,13 @@ options:
- Tag name.
required: false
type: str
- default: ''
+ default: ""
value:
description:
- Tag value.
required: false
type: str
- default: ''
+ default: ""
userdirectory:
description:
- Authentication user directory when gui_access set to LDAP or System default.
@@ -148,23 +149,22 @@ options:
type: str
default: "present"
choices: [ "present", "absent" ]
-notes:
- - Only Zabbix >= 4.0 is supported.
+
extends_documentation_fragment:
- community.zabbix.zabbix
-'''
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
# If you want to use Username and Password to be authenticated by Zabbix Server
- name: Set credentials to access Zabbix Server API
- set_fact:
+ ansible.builtin.set_fact:
ansible_user: Admin
ansible_httpapi_pass: zabbix
# If you want to use API token to be authenticated by Zabbix Server
# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens
- name: Set API token
- set_fact:
+ ansible.builtin.set_fact:
ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895
# Base create user group example
@@ -176,10 +176,11 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_usergroup:
name: ACME
+ userdirectory: LDAP infra 1
state: present
# Base create user group with selected user directory for LDAP authentication
@@ -191,7 +192,7 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_usergroup:
name: ACME
@@ -207,7 +208,7 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_usergroup:
name: ACME
@@ -222,7 +223,7 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_usergroup:
name: ACME
@@ -242,7 +243,7 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_usergroup:
name: ACME
@@ -267,7 +268,7 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_usergroup:
name: ACME
@@ -289,35 +290,35 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_usergroup:
name: ACME
state: absent
-'''
+"""
-RETURN = r'''
+RETURN = r"""
state:
description: User group state at the end of execution.
returned: on success
type: str
- sample: 'present'
+ sample: "present"
usergroup:
description: User group name.
returned: on success
type: str
- sample: 'ACME'
+ sample: "ACME"
usrgrpid:
description: User group id, if created, changed or deleted.
returned: on success
type: str
- sample: '42'
+ sample: "42"
msg:
description: The result of the operation
returned: always
type: str
- sample: 'User group created: ACME, ID: 42'
-'''
+ sample: "User group created: ACME, ID: 42"
+"""
from ansible.module_utils.basic import AnsibleModule
@@ -341,16 +342,15 @@ class Rights(ZabbixBase):
host group matching host group name.
"""
try:
- _hostgroup = self._zapi.hostgroup.get({
- 'output': 'extend',
- 'filter': {'name': [name]}
- })
+ _hostgroup = self._zapi.hostgroup.get(
+ {"output": "extend", "filter": {"name": [name]}}
+ )
if len(_hostgroup) < 1:
- self._module.fail_json(msg='Host group not found: %s' % name)
+ self._module.fail_json(msg="Host group not found: %s" % name)
else:
return _hostgroup[0]
except Exception as e:
- self._module.fail_json(msg='Failed to get host group "%s": %s' % (name, e))
+ self._module.fail_json(msg="Failed to get host group '%s': %s" % (name, e))
def construct_the_data(self, _rights):
"""Construct the user defined rights to fit the Zabbix API requirements
@@ -366,13 +366,12 @@ class Rights(ZabbixBase):
constructed_data = []
for right in _rights:
constructed_right = {
- 'id': self.get_hostgroup_by_hostgroup_name(right.get('host_group'))['groupid'],
- 'permission': zabbix_utils.helper_to_numeric_value([
- 'denied',
- None,
- 'read-only',
- 'read-write'], right.get('permission')
- )
+ "id": self.get_hostgroup_by_hostgroup_name(right.get("host_group"))[
+ "groupid"
+ ],
+ "permission": zabbix_utils.helper_to_numeric_value(
+ ["denied", None, "read-only", "read-write"], right.get("permission")
+ ),
}
constructed_data.append(constructed_right)
return zabbix_utils.helper_cleanup_data(constructed_data)
@@ -394,15 +393,15 @@ class HostgroupRights(ZabbixBase):
"""
try:
_hostgroup = self._zapi.hostgroup.get({
- 'output': 'extend',
- 'filter': {'name': [name]}
+ "output": "extend",
+ "filter": {"name": [name]}
})
if len(_hostgroup) < 1:
- self._module.fail_json(msg='Host group not found: %s' % name)
+ self._module.fail_json(msg="Host group not found: %s" % name)
else:
return _hostgroup[0]
except Exception as e:
- self._module.fail_json(msg='Failed to get host group "%s": %s' % (name, e))
+ self._module.fail_json(msg="Failed to get host group '%s': %s" % (name, e))
def construct_the_data(self, _rights):
"""Construct the user defined host group rights to fit the Zabbix API requirements
@@ -418,12 +417,12 @@ class HostgroupRights(ZabbixBase):
constructed_data = []
for right in _rights:
constructed_right = {
- 'id': self.get_hostgroup_by_hostgroup_name(right.get('host_group'))['groupid'],
- 'permission': zabbix_utils.helper_to_numeric_value([
- 'denied',
+ "id": self.get_hostgroup_by_hostgroup_name(right.get("host_group"))["groupid"],
+ "permission": zabbix_utils.helper_to_numeric_value([
+ "denied",
None,
- 'read-only',
- 'read-write'], right.get('permission')
+ "read-only",
+ "read-write"], right.get("permission")
)
}
constructed_data.append(constructed_right)
@@ -446,15 +445,15 @@ class TemplategroupRights(ZabbixBase):
"""
try:
_templategroup = self._zapi.templategroup.get({
- 'output': 'extend',
- 'filter': {'name': [name]}
+ "output": "extend",
+ "filter": {"name": [name]}
})
if len(_templategroup) < 1:
- self._module.fail_json(msg='Template group not found: %s' % name)
+ self._module.fail_json(msg="Template group not found: %s" % name)
else:
return _templategroup[0]
except Exception as e:
- self._module.fail_json(msg='Failed to get template group "%s": %s' % (name, e))
+ self._module.fail_json(msg="Failed to get template group '%s': %s" % (name, e))
def construct_the_data(self, _rights):
"""Construct the user defined template rights to fit the Zabbix API requirements
@@ -470,12 +469,12 @@ class TemplategroupRights(ZabbixBase):
constructed_data = []
for right in _rights:
constructed_right = {
- 'id': self.get_templategroup_by_templategroup_name(right.get('template_group'))['groupid'],
- 'permission': zabbix_utils.helper_to_numeric_value([
- 'denied',
+ "id": self.get_templategroup_by_templategroup_name(right.get("template_group"))["groupid"],
+ "permission": zabbix_utils.helper_to_numeric_value([
+ "denied",
None,
- 'read-only',
- 'read-write'], right.get('permission')
+ "read-only",
+ "read-write"], right.get("permission")
)
}
constructed_data.append(constructed_right)
@@ -501,9 +500,11 @@ class TagFilters(Rights):
constructed_data = []
for tag_filter in _tag_filters:
constructed_tag_filter = {
- 'groupid': self.get_hostgroup_by_hostgroup_name(tag_filter.get('host_group'))['groupid'],
- 'tag': tag_filter.get('tag'),
- 'value': tag_filter.get('value')
+ "groupid": self.get_hostgroup_by_hostgroup_name(
+ tag_filter.get("host_group")
+ )["groupid"],
+ "tag": tag_filter.get("tag"),
+ "value": tag_filter.get("value"),
}
constructed_data.append(constructed_tag_filter)
return zabbix_utils.helper_cleanup_data(constructed_data)
@@ -520,46 +521,50 @@ class UserGroup(ZabbixBase):
dict: dictionary of specified parameters
"""
_params = {
- 'name': kwargs['name'],
- 'gui_access': zabbix_utils.helper_to_numeric_value([
- 'default',
- 'internal',
- 'LDAP',
- 'disable'], kwargs['gui_access']
+ "name": kwargs["name"],
+ "gui_access": zabbix_utils.helper_to_numeric_value(
+ ["default", "internal", "LDAP", "disable"], kwargs["gui_access"]
),
- 'debug_mode': zabbix_utils.helper_to_numeric_value([
- 'disabled',
- 'enabled'], kwargs['debug_mode']
+ "debug_mode": zabbix_utils.helper_to_numeric_value(
+ ["disabled", "enabled"], kwargs["debug_mode"]
),
- 'users_status': zabbix_utils.helper_to_numeric_value([
- 'enabled',
- 'disabled'], kwargs['status']
+ "users_status": zabbix_utils.helper_to_numeric_value(
+ ["enabled", "disabled"], kwargs["status"]
),
- 'tag_filters': kwargs['tag_filters']
+ "tag_filters": kwargs["tag_filters"],
}
- if LooseVersion(self._zbx_api_version) < LooseVersion('6.2'):
- _params['rights'] = kwargs['rights']
+ if LooseVersion(self._zbx_api_version) < LooseVersion("6.2"):
+ _params["rights"] = kwargs["rights"]
else:
- _params['hostgroup_rights'] = kwargs['hostgroup_rights']
- _params['templategroup_rights'] = kwargs['templategroup_rights']
+ _params["hostgroup_rights"] = kwargs["hostgroup_rights"]
+ _params["templategroup_rights"] = kwargs["templategroup_rights"]
- if kwargs['userdirectory']:
+ if kwargs["userdirectory"]:
try:
- if LooseVersion(self._zbx_api_version) <= LooseVersion('6.2'):
- _userdir = self._zapi.userdirectory.get({
- 'output': 'extend',
- 'filter': {'name': [kwargs['userdirectory']]}
- })
+ if LooseVersion(self._zbx_api_version) <= LooseVersion("6.2"):
+ _userdir = self._zapi.userdirectory.get(
+ {
+ "output": "extend",
+ "filter": {"name": [kwargs["userdirectory"]]},
+ }
+ )
else:
- _userdir = self._zapi.userdirectory.get({
- 'output': 'extend',
- 'search': {'name': [kwargs['userdirectory']]}
- })
+ _userdir = self._zapi.userdirectory.get(
+ {
+ "output": "extend",
+ "search": {"name": [kwargs["userdirectory"]]},
+ }
+ )
except Exception as e:
- self._module.fail_json(msg='Failed to get user directory "%s": %s' % (kwargs['userdirectory'], e))
+ self._module.fail_json(
+ msg="Failed to get user directory '%s': %s"
+ % (kwargs["userdirectory"], e)
+ )
if len(_userdir) == 0:
- self._module.fail_json(msg='User directory "%s" not found' % kwargs['userdirectory'])
- _params['userdirectoryid'] = _userdir[0]['userdirectoryid']
+ self._module.fail_json(
+ msg="User directory '%s' not found" % kwargs["userdirectory"]
+ )
+ _params["userdirectoryid"] = _userdir[0]["userdirectoryid"]
return _params
@@ -573,14 +578,15 @@ class UserGroup(ZabbixBase):
The return value. True for success, False otherwise.
"""
try:
- _usergroup = self._zapi.usergroup.get({
- 'output': 'extend',
- 'filter': {'name': [name]}
- })
+ _usergroup = self._zapi.usergroup.get(
+ {"output": "extend", "filter": {"name": [name]}}
+ )
if len(_usergroup) > 0:
return _usergroup
except Exception as e:
- self._module.fail_json(msg='Failed to check if user group "%s" exists: %s' % (name, e))
+ self._module.fail_json(
+ msg="Failed to check if user group '%s' exists: %s" % (name, e)
+ )
def get_usergroup_by_usergroup_name(self, name):
"""Get user group by user group name.
@@ -592,28 +598,32 @@ class UserGroup(ZabbixBase):
User group matching user group name.
"""
try:
- if LooseVersion(self._zbx_api_version) < LooseVersion('6.2'):
- _usergroup = self._zapi.usergroup.get({
- 'output': 'extend',
- 'selectTagFilters': 'extend',
- 'selectRights': 'extend',
- 'filter': {'name': [name]}
- })
+ if LooseVersion(self._zbx_api_version) < LooseVersion("6.2"):
+ _usergroup = self._zapi.usergroup.get(
+ {
+ "output": "extend",
+ "selectTagFilters": "extend",
+ "selectRights": "extend",
+ "filter": {"name": [name]},
+ }
+ )
else:
- _usergroup = self._zapi.usergroup.get({
- 'output': 'extend',
- 'selectTagFilters': 'extend',
- 'selectHostGroupRights': 'extend',
- 'selectTemplateGroupRights': 'extend',
- 'filter': {'name': [name]}
- })
+ _usergroup = self._zapi.usergroup.get(
+ {
+ "output": "extend",
+ "selectTagFilters": "extend",
+ "selectHostGroupRights": "extend",
+ "selectTemplateGroupRights": "extend",
+ "filter": {"name": [name]},
+ }
+ )
if len(_usergroup) < 1:
- self._module.fail_json(msg='User group not found: %s' % name)
+ self._module.fail_json(msg="User group not found: %s" % name)
else:
return _usergroup[0]
except Exception as e:
- self._module.fail_json(msg='Failed to get user group "%s": %s' % (name, e))
+ self._module.fail_json(msg="Failed to get user group '%s': %s" % (name, e))
def check_difference(self, **kwargs):
"""Check difference between user group and user specified parameters.
@@ -624,10 +634,16 @@ class UserGroup(ZabbixBase):
Returns:
dict: dictionary of differences
"""
- existing_usergroup = zabbix_utils.helper_convert_unicode_to_str(self.get_usergroup_by_usergroup_name(kwargs['name']))
- parameters = zabbix_utils.helper_convert_unicode_to_str(self._construct_parameters(**kwargs))
+ existing_usergroup = zabbix_utils.helper_convert_unicode_to_str(
+ self.get_usergroup_by_usergroup_name(kwargs["name"])
+ )
+ parameters = zabbix_utils.helper_convert_unicode_to_str(
+ self._construct_parameters(**kwargs)
+ )
change_parameters = {}
- _diff = zabbix_utils.helper_compare_dictionaries(parameters, existing_usergroup, change_parameters)
+ _diff = zabbix_utils.helper_compare_dictionaries(
+ parameters, existing_usergroup, change_parameters
+ )
return _diff
def update(self, **kwargs):
@@ -644,7 +660,9 @@ class UserGroup(ZabbixBase):
self._module.exit_json(changed=True)
return self._zapi.usergroup.update(kwargs)
except Exception as e:
- self._module.fail_json(msg='Failed to update user group "%s": %s' % (kwargs['usrgrpid'], e))
+ self._module.fail_json(
+ msg="Failed to update user group '%s': %s" % (kwargs["usrgrpid"], e)
+ )
def add(self, **kwargs):
"""Add user group.
@@ -660,9 +678,11 @@ class UserGroup(ZabbixBase):
self._module.exit_json(changed=True)
parameters = self._construct_parameters(**kwargs)
usergroup = self._zapi.usergroup.create(parameters)
- return usergroup['usrgrpids'][0]
+ return usergroup["usrgrpids"][0]
except Exception as e:
- self._module.fail_json(msg='Failed to create user group "%s": %s' % (kwargs['name'], e))
+ self._module.fail_json(
+ msg="Failed to create user group '%s': %s" % (kwargs["name"], e)
+ )
def delete(self, usrgrpid):
"""Delete user group.
@@ -679,62 +699,102 @@ class UserGroup(ZabbixBase):
else:
return self._zapi.usergroup.delete([usrgrpid])
except Exception as e:
- self._module.fail_json(msg='Failed to delete user group "%s": %s' % (usrgrpid, e))
+ self._module.fail_json(
+ msg="Failed to delete user group '%s': %s" % (usrgrpid, e)
+ )
def main():
argument_spec = zabbix_utils.zabbix_common_argument_spec()
argument_spec.update(
- name=dict(type='str', required=True, aliases=['user_group']),
- gui_access=dict(type='str', required=False, default='default', choices=['default', 'internal', 'LDAP', 'disable']),
- debug_mode=dict(type='str', required=False, default='disabled', choices=['disabled', 'enabled']),
- status=dict(type='str', required=False, default='enabled', choices=['enabled', 'disabled']),
- rights=dict(type='list', elements='dict', required=False, options=dict(
- host_group=dict(type='str', required=True),
- permission=dict(type='str', required=True, choices=['denied', 'read-only', 'read-write'])
- )),
- hostgroup_rights=dict(type='list', elements='dict', required=False, options=dict(
- host_group=dict(type='str', required=True),
- permission=dict(type='str', required=True, choices=['denied', 'read-only', 'read-write'])
- )),
- templategroup_rights=dict(type='list', elements='dict', required=False, options=dict(
- template_group=dict(type='str', required=True),
- permission=dict(type='str', required=True, choices=['denied', 'read-only', 'read-write'])
- )),
- tag_filters=dict(type='list', elements='dict', required=False, options=dict(
- host_group=dict(type='str', required=True),
- tag=dict(type='str', default=''),
- value=dict(type='str', default='')
- )),
- userdirectory=dict(type='str', required=False),
- state=dict(type='str', default='present', choices=['present', 'absent'])
- )
-
- module = AnsibleModule(
- argument_spec=argument_spec,
- supports_check_mode=True
+ name=dict(type="str", required=True, aliases=["user_group"]),
+ gui_access=dict(
+ type="str",
+ required=False,
+ default="default",
+ choices=["default", "internal", "LDAP", "disable"],
+ ),
+ debug_mode=dict(
+ type="str",
+ required=False,
+ default="disabled",
+ choices=["disabled", "enabled"],
+ ),
+ status=dict(
+ type="str",
+ required=False,
+ default="enabled",
+ choices=["enabled", "disabled"],
+ ),
+ rights=dict(
+ type="list",
+ elements="dict",
+ required=False,
+ options=dict(
+ host_group=dict(type="str", required=True),
+ permission=dict(
+ type="str",
+ required=True,
+ choices=["denied", "read-only", "read-write"],
+ ),
+ ),
+ ),
+ hostgroup_rights=dict(
+ type="list",
+ elements="dict",
+ required=False,
+ options=dict(
+ host_group=dict(type="str", required=True),
+ permission=dict(
+ type="str",
+ required=True,
+ choices=["denied", "read-only", "read-write"],
+ ),
+ ),
+ ),
+ templategroup_rights=dict(
+ type="list",
+ elements="dict",
+ required=False,
+ options=dict(
+ template_group=dict(type="str", required=True),
+ permission=dict(
+ type="str",
+ required=True,
+ choices=["denied", "read-only", "read-write"],
+ ),
+ ),
+ ),
+ tag_filters=dict(
+ type="list",
+ elements="dict",
+ required=False,
+ options=dict(
+ host_group=dict(type="str", required=True),
+ tag=dict(type="str", default=""),
+ value=dict(type="str", default=""),
+ ),
+ ),
+ userdirectory=dict(type="str", required=False),
+ state=dict(type="str", default="present", choices=["present", "absent"]),
)
- zabbix_utils.require_creds_params(module)
+ module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)
- for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']:
- if p in module.params and not module.params[p] is None:
- module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p)
-
- name = module.params['name']
- gui_access = module.params['gui_access']
- debug_mode = module.params['debug_mode']
- status = module.params['status']
- rights = module.params['rights']
- hostgroup_rights = module.params['hostgroup_rights']
- templategroup_rights = module.params['templategroup_rights']
- tag_filters = module.params['tag_filters']
- userdirectory = module.params['userdirectory']
- state = module.params['state']
+ name = module.params["name"]
+ gui_access = module.params["gui_access"]
+ debug_mode = module.params["debug_mode"]
+ status = module.params["status"]
+ rights = module.params["rights"]
+ hostgroup_rights = module.params["hostgroup_rights"]
+ templategroup_rights = module.params["templategroup_rights"]
+ tag_filters = module.params["tag_filters"]
+ userdirectory = module.params["userdirectory"]
+ state = module.params["state"]
userGroup = UserGroup(module)
zbx = userGroup._zapi
- if LooseVersion(userGroup._zbx_api_version) < LooseVersion('6.2'):
+ if LooseVersion(userGroup._zbx_api_version) < LooseVersion("6.2"):
rgts = Rights(module, zbx)
else:
hostgroup_rgts = HostgroupRights(module, zbx)
@@ -744,12 +804,18 @@ def main():
usergroup_exists = userGroup.check_if_usergroup_exists(name)
if usergroup_exists:
- usrgrpid = userGroup.get_usergroup_by_usergroup_name(name)['usrgrpid']
- if state == 'absent':
+ usrgrpid = userGroup.get_usergroup_by_usergroup_name(name)["usrgrpid"]
+ if state == "absent":
userGroup.delete(usrgrpid)
- module.exit_json(changed=True, state=state, usergroup=name, usrgrpid=usrgrpid, msg='User group deleted: %s, ID: %s' % (name, usrgrpid))
+ module.exit_json(
+ changed=True,
+ state=state,
+ usergroup=name,
+ usrgrpid=usrgrpid,
+ msg="User group deleted: %s, ID: %s" % (name, usrgrpid),
+ )
else:
- if LooseVersion(userGroup._zbx_api_version) < LooseVersion('6.2'):
+ if LooseVersion(userGroup._zbx_api_version) < LooseVersion("6.2"):
difference = userGroup.check_difference(
usrgrpid=usrgrpid,
name=name,
@@ -757,7 +823,7 @@ def main():
debug_mode=debug_mode,
status=status,
rights=rgts.construct_the_data(rights),
- tag_filters=tgflts.construct_the_data(tag_filters)
+ tag_filters=tgflts.construct_the_data(tag_filters),
)
else:
difference = userGroup.check_difference(
@@ -766,31 +832,49 @@ def main():
gui_access=gui_access,
debug_mode=debug_mode,
status=status,
- hostgroup_rights=hostgroup_rgts.construct_the_data(hostgroup_rights),
- templategroup_rights=templategroup_rgts.construct_the_data(templategroup_rights),
+ hostgroup_rights=hostgroup_rgts.construct_the_data(
+ hostgroup_rights
+ ),
+ templategroup_rights=templategroup_rgts.construct_the_data(
+ templategroup_rights
+ ),
tag_filters=tgflts.construct_the_data(tag_filters),
- userdirectory=userdirectory
+ userdirectory=userdirectory,
)
if difference == {}:
- module.exit_json(changed=False, state=state, usergroup=name, usrgrpid=usrgrpid, msg='User group is up to date: %s' % name)
+ module.exit_json(
+ changed=False,
+ state=state,
+ usergroup=name,
+ usrgrpid=usrgrpid,
+ msg="User group is up to date: %s" % name,
+ )
else:
- userGroup.update(
+ userGroup.update(usrgrpid=usrgrpid, **difference)
+ module.exit_json(
+ changed=True,
+ state=state,
+ usergroup=name,
usrgrpid=usrgrpid,
- **difference
+ msg="User group updated: %s, ID: %s" % (name, usrgrpid),
)
- module.exit_json(changed=True, state=state, usergroup=name, usrgrpid=usrgrpid, msg='User group updated: %s, ID: %s' % (name, usrgrpid))
else:
- if state == 'absent':
- module.exit_json(changed=False, state=state, usergroup=name, msg='User group %s does not exists, nothing to delete' % name)
+ if state == "absent":
+ module.exit_json(
+ changed=False,
+ state=state,
+ usergroup=name,
+ msg="User group %s does not exists, nothing to delete" % name,
+ )
else:
- if LooseVersion(userGroup._zbx_api_version) < LooseVersion('6.2'):
+ if LooseVersion(userGroup._zbx_api_version) < LooseVersion("6.2"):
usrgrpid = userGroup.add(
name=name,
gui_access=gui_access,
debug_mode=debug_mode,
status=status,
rights=rgts.construct_the_data(rights),
- tag_filters=tgflts.construct_the_data(tag_filters)
+ tag_filters=tgflts.construct_the_data(tag_filters),
)
else:
usrgrpid = userGroup.add(
@@ -798,13 +882,23 @@ def main():
gui_access=gui_access,
debug_mode=debug_mode,
status=status,
- hostgroup_rights=hostgroup_rgts.construct_the_data(hostgroup_rights),
- templategroup_rights=templategroup_rgts.construct_the_data(templategroup_rights),
+ hostgroup_rights=hostgroup_rgts.construct_the_data(
+ hostgroup_rights
+ ),
+ templategroup_rights=templategroup_rgts.construct_the_data(
+ templategroup_rights
+ ),
tag_filters=tgflts.construct_the_data(tag_filters),
- userdirectory=userdirectory
+ userdirectory=userdirectory,
)
- module.exit_json(changed=True, state=state, usergroup=name, usrgrpid=usrgrpid, msg='User group created: %s, ID: %s' % (name, usrgrpid))
+ module.exit_json(
+ changed=True,
+ state=state,
+ usergroup=name,
+ usrgrpid=usrgrpid,
+ msg="User group created: %s, ID: %s" % (name, usrgrpid),
+ )
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/zabbix/plugins/modules/zabbix_valuemap.py b/ansible_collections/community/zabbix/plugins/modules/zabbix_valuemap.py
index 196f8ff7e..3d9a64954 100644
--- a/ansible_collections/community/zabbix/plugins/modules/zabbix_valuemap.py
+++ b/ansible_collections/community/zabbix/plugins/modules/zabbix_valuemap.py
@@ -8,7 +8,7 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type
-DOCUMENTATION = r'''
+DOCUMENTATION = r"""
---
module: zabbix_valuemap
short_description: Create/update/delete Zabbix value maps
@@ -17,56 +17,56 @@ description:
author:
- "Ruben Tsirunyan (@rubentsirunyan)"
requirements:
- - "python >= 2.6"
+ - "python >= 3.9"
options:
name:
- type: 'str'
+ type: "str"
description:
- Name of the value map.
required: true
state:
- type: 'str'
+ type: "str"
description:
- State of the value map.
- On C(present), it will create a value map if it does not exist or update the value map if the associated data is different.
- On C(absent), it will remove the value map if it exists.
- choices: ['present', 'absent']
- default: 'present'
+ choices: ["present", "absent"]
+ default: "present"
mappings:
- type: 'list'
+ type: "list"
elements: dict
description:
- List of value mappings for the value map.
- Required when I(state=present).
suboptions:
value:
- type: 'str'
+ type: "str"
description: Original value.
required: true
map_to:
- type: 'str'
+ type: "str"
description: Value to which the original value is mapped to.
required: true
extends_documentation_fragment:
- community.zabbix.zabbix
-'''
+"""
-RETURN = r'''
-'''
+RETURN = r"""
+"""
-EXAMPLES = r'''
+EXAMPLES = r"""
# If you want to use Username and Password to be authenticated by Zabbix Server
- name: Set credentials to access Zabbix Server API
- set_fact:
+ ansible.builtin.set_fact:
ansible_user: Admin
ansible_httpapi_pass: zabbix
# If you want to use API token to be authenticated by Zabbix Server
# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens
- name: Set API token
- set_fact:
+ ansible.builtin.set_fact:
ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895
- name: Create a value map
@@ -77,7 +77,7 @@ EXAMPLES = r'''
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
- ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
+ ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http://<FQDN>/zabbixeu
ansible_host: zabbix-example-fqdn.org
community.zabbix.zabbix_valuemap:
name: Numbers
@@ -87,7 +87,7 @@ EXAMPLES = r'''
- value: 2
map_to: two
state: present
-'''
+"""
from ansible.module_utils.basic import AnsibleModule
@@ -104,31 +104,31 @@ def construct_parameters(**kwargs):
Returns:
A dictionary of arguments in a format that is understandable by Zabbix API.
"""
- if kwargs['mappings'] is None:
+ if kwargs["mappings"] is None:
return dict(
- name=kwargs['name']
+ name=kwargs["name"]
)
return dict(
- name=kwargs['name'],
+ name=kwargs["name"],
mappings=[
dict(
- value=mapping['value'],
- newvalue=mapping['map_to']
- ) for mapping in kwargs['mappings']
+ value=mapping["value"],
+ newvalue=mapping["map_to"]
+ ) for mapping in kwargs["mappings"]
]
)
def diff(existing, new):
- """Constructs the diff for Ansible's --diff option.
+ """Constructs the diff for Ansible"s --diff option.
Args:
existing (dict): Existing valuemap data.
new (dict): New valuemap data.
Returns:
- A dictionary like {'before': existing, 'after': new}
+ A dictionary like {"before": existing, "after": new}
with filtered empty values.
"""
before = {}
@@ -136,11 +136,11 @@ def diff(existing, new):
for key in new:
before[key] = existing[key]
if new[key] is None:
- after[key] = ''
+ after[key] = ""
else:
after[key] = new[key]
- return {'before': before, 'after': after}
+ return {"before": before, "after": after}
def get_update_params(existing_valuemap, **kwargs):
@@ -158,8 +158,8 @@ def get_update_params(existing_valuemap, **kwargs):
"""
params_to_update = {}
- if sorted(existing_valuemap['mappings'], key=lambda k: k['value']) != sorted(kwargs['mappings'], key=lambda k: k['value']):
- params_to_update['mappings'] = kwargs['mappings']
+ if sorted(existing_valuemap["mappings"], key=lambda k: k["value"]) != sorted(kwargs["mappings"], key=lambda k: k["value"]):
+ params_to_update["mappings"] = kwargs["mappings"]
return params_to_update, diff(existing_valuemap, kwargs)
@@ -176,9 +176,9 @@ class ValuemapModule(ZabbixBase):
"""
try:
valuemap_list = self._zapi.valuemap.get({
- 'output': 'extend',
- 'selectMappings': 'extend',
- 'filter': {'name': [name]}
+ "output": "extend",
+ "selectMappings": "extend",
+ "filter": {"name": [name]}
})
if len(valuemap_list) < 1:
return False, None
@@ -197,26 +197,26 @@ class ValuemapModule(ZabbixBase):
try:
self._zapi.valuemap.update(kwargs)
except Exception as e:
- self._module.fail_json(msg="Failed to update valuemap '{_id}': {e}".format(_id=kwargs['valuemapid'], e=e))
+ self._module.fail_json(msg="Failed to update valuemap '{_id}': {e}".format(_id=kwargs["valuemapid"], e=e))
def create(self, **kwargs):
try:
self._zapi.valuemap.create(kwargs)
except Exception as e:
- self._module.fail_json(msg="Failed to create valuemap '{name}': {e}".format(name=kwargs['description'], e=e))
+ self._module.fail_json(msg="Failed to create valuemap '{name}': {e}".format(name=kwargs["description"], e=e))
def main():
argument_spec = zabbix_utils.zabbix_common_argument_spec()
argument_spec.update(dict(
- name=dict(type='str', required=True),
- state=dict(type='str', default='present', choices=['present', 'absent']),
+ name=dict(type="str", required=True),
+ state=dict(type="str", default="present", choices=["present", "absent"]),
mappings=dict(
- type='list',
- elements='dict',
+ type="list",
+ elements="dict",
options=dict(
- value=dict(type='str', required=True),
- map_to=dict(type='str', required=True)
+ value=dict(type="str", required=True),
+ map_to=dict(type="str", required=True)
)
)
))
@@ -224,20 +224,15 @@ def main():
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
- ['state', 'present', ['mappings']],
+ ["state", "present", ["mappings"]],
]
)
- zabbix_utils.require_creds_params(module)
-
- for p in ['server_url', 'login_user', 'login_password', 'timeout', 'validate_certs']:
- if p in module.params and not module.params[p] is None:
- module.warn('Option "%s" is deprecated with the move to httpapi connection and will be removed in the next release' % p)
vm = ValuemapModule(module)
- name = module.params['name']
- state = module.params['state']
- mappings = module.params['mappings']
+ name = module.params["name"]
+ state = module.params["state"]
+ mappings = module.params["mappings"]
valuemap_exists, valuemap_object = vm.check_if_valuemap_exists(name)
@@ -247,8 +242,8 @@ def main():
)
if valuemap_exists:
- valuemap_id = valuemap_object['valuemapid']
- if state == 'absent':
+ valuemap_id = valuemap_object["valuemapid"]
+ if state == "absent":
if module.check_mode:
module.exit_json(
changed=True,
@@ -313,5 +308,5 @@ def main():
)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/README.md b/ansible_collections/community/zabbix/roles/zabbix_agent/README.md
index f3fe06c9d..aa73fab3a 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_agent/README.md
+++ b/ansible_collections/community/zabbix/roles/zabbix_agent/README.md
@@ -44,15 +44,10 @@
This role will work on the following operating systems:
* Red Hat
- * Fedora
* Debian
* Ubuntu
- * opensuse
* Windows (Best effort)
- * macOS
-
-So, you'll need one of those operating systems.. :-)
-Please send Pull Requests or suggestions when you want to use this role for other Operating systems.
+ * macOS (Best effort)
## Ansible 2.10 and higher
@@ -62,7 +57,7 @@ With the release of Ansible 2.10, modules have been moved into collections. Wit
ansible-galaxy collection install ansible.posix
ansible-galaxy collection install community.general
```
-If you are willing to create host_groups and hosts in Zabbix via API as a part of this role execution then you need to install `ansible.netcommon` collection too:
+If you are wanting to create host_groups and hosts in Zabbix via API as a part of this role execution then you need to install `ansible.netcommon` collection too:
```
ansible-galaxy collection install ansible.netcommon
@@ -95,24 +90,18 @@ To successfully complete the install the role requires `python-netaddr` on the c
See the following list of supported Operating systems with the Zabbix releases:
-| Zabbix | 6.4 | 6.2 | 6.0 | 5.4 | 5.2 | 5.0 (LTS)| 4.4 | 4.0 (LTS) | 3.0 (LTS) |
-|---------------------|-----|-----|-----|-----|-----|----------|-----|-----------|-----------|
-| Red Hat Fam 9 | V | V | V | | | | | | |
-| Red Hat Fam 8 | V | V | V | V | V | V | V | | |
-| Red Hat Fam 7 | V | V | V | V | V | V | V | V | V |
-| Red Hat Fam 6 | V | V | V | V | V | V | | | V |
-| Red Hat Fam 5 | | | V | V | V | V | | | V |
-| Fedora | | | | | | | V | V | |
-| Ubuntu 20.04 focal | V | V | V | V | V | V | | V | |
-| Ubuntu 18.04 bionic | V | V | V | V | V | V | V | V | |
-| Ubuntu 16.04 xenial | V | V | V | V | V | V | V | V | |
-| Ubuntu 14.04 trusty | V | V | V | V | V | V | V | V | V |
-| Debian 10 buster | V | V | V | V | V | V | V | | |
-| Debian 9 stretch | V | V | | V | V | V | V | V | |
-| Debian 8 jessie | | | | | V | V | V | V | V |
-| Debian 7 wheezy | | | | | | | | V | V |
-| macOS 10.15 | | | | | | | V | V | |
-| macOS 10.14 | | | | | | | V | V | |
+| Zabbix | 6.4 | 6.2 | 6.0 |
+|---------------------|-----|-----|-----|
+| Red Hat Fam 9 | V | V | V |
+| Red Hat Fam 8 | V | V | V |
+| Red Hat Fam 7 | V | V | V |
+| Ubuntu 22.04 jammy | V | V | V |
+| Ubuntu 20.04 focal | V | V | V |
+| Ubuntu 18.04 bionic | V | V | V |
+| Debian 12 bookworm | V | V | V |
+| Debian 11 bullseye | V | V | V |
+| Debian 10 buster | V | V | V |
+
# Getting started
@@ -124,7 +113,7 @@ In order to get the Zabbix Agent running, you'll have to define the following pr
* `zabbix_agent(2)_server`
* `zabbix_agent(2)_serveractive` (When using active checks)
-The `zabbix_agent_version` is optional. The latest available major.minor version of Zabbix will be installed on the host(s). If you want to use an older version, please specify this in the major.minor format. Example: `zabbix_agent_version: 4.0`, `zabbix_agent_version: 3.4` or `zabbix_agent_version: 2.2`.
+The `zabbix_agent_version` is optional. The latest available major.minor version of Zabbix will be installed on the host(s). If you want to use an older version, please specify this in the major.minor format. Example: `zabbix_agent_version: 6.0`.
The `zabbix_agent(2)_server` (and `zabbix_agent(2)_serveractive`) should contain the ip or fqdn of the host running the Zabbix Server.
@@ -140,16 +129,13 @@ The following is an overview of all available configuration default for this rol
### Overall Zabbix
-* `zabbix_agent_version`: This is the version of zabbix. Default: The highest supported version for the operating system. Can be overridden to 6.2, 6.0, 5.4, 5.2 5.0, 4.4, 4.0, 3.4, 3.2, 3.0, 2.4, or 2.2. Previously the variable `zabbix_version` was used directly but it could cause [some inconvenience](https://github.com/dj-wasabi/ansible-zabbix-agent/pull/303). That variable is maintained by retrocompativility.
+* `zabbix_agent_version`: This is the version of zabbix. Default: The highest supported version for the operating system. Can be overridden to 6.4, 6.2, or 6.0
* `zabbix_agent_version_minor`: When you want to specify a minor version to be installed. Is also used for `zabbix_sender` and `zabbix_get`. RedHat only. Default set to: `*` (latest available)
-* `zabbix_repo`: Default: `zabbix`
- * `epel`: install agent from EPEL repo
- * `zabbix`: (default) install agent from Zabbix repo
- * `other`: install agent from pre-existing or other repo
* `zabbix_repo_yum`: A list with Yum repository configuration.
* `zabbix_repo_yum_schema`: Default: `https`. Option to change the web schema for the yum repository(http/https)
-* `zabbix_repo_yum_disabled`: A string with repository names that should be disabled when installing Zabbix component specific packages. Is only used when `zabbix_repo_yum_enabled` contains 1 or more repositories. Default `*`.
-* `zabbix_repo_yum_enabled`: A list with repository names that should be enabled when installing Zabbix component specific packages.
+* `zabbix_agent_disable_repo`: A list of repos to disable during install. Default `epel`.
+* `zabbix_repo_deb_url`: The URL to the Zabbix repository. Default `http://repo.zabbix.com/zabbix/{{ zabbix_agent_version }}/{{ ansible_distribution.lower() }}`
+* `zabbix_repo_deb_component`: The repository component for Debian installs. Default `main`.
### SElinux
@@ -158,7 +144,7 @@ The following is an overview of all available configuration default for this rol
### Zabbix Agent
* `zabbix_agent_ip`: The IP address of the host. When not provided, it will be determined via the `ansible_default_ipv4` fact.
-* `zabbix_agent2`: Default: `False`. When you want to install the `Zabbix Agent2` instead of the "old" `Zabbix Agent`.
+* `zabbix_agent2`: Default: `False`. When you want to install the `Zabbix Agent2` instead of the "old" `Zabbix Agent`.zabbix_agent_version
* `zabbix_agent_listeninterface`: Interface zabbix-agent listens on. Leave blank for all.
* `zabbix_agent_package_remove`: If `zabbix_agent2: True` and you want to remove the old installation. Default: `False`.
* `zabbix_agent_package`: The name of the zabbix-agent package. Default: `zabbix-agent`. In case for EPEL, it is automatically renamed.
@@ -174,7 +160,6 @@ The following is an overview of all available configuration default for this rol
* `zabbix_agent_userparameters_scripts_src`: indicates the relative path (from `files/`) where userparameter scripts are searched
* `zabbix_agent_runas_user`: Drop privileges to a specific, existing user on the system. Only has effect if run as 'root' and AllowRoot is disabled.
* `zabbix_agent_become_on_localhost`: Default: `True`. Set to `False` if you don't need to elevate privileges on localhost to install packages locally with pip.
-* `zabbix_install_pip_packages`: Default: `True`. Set to `False` if you don't want to install the required pip packages. Useful when you control your environment completely.
* `zabbix_agent_apt_priority`: Add a weight (`Pin-Priority`) for the APT repository.
* `zabbix_agent_conf_mode`: Default: `0644`. The "mode" for the Zabbix configuration file.
* `zabbix_agent_dont_detect_ip`: Default `false`. When set to `true`, it won't detect available ip addresses on the host and no need for the Python module `netaddr` to be installed.
@@ -193,6 +178,7 @@ Otherwise it just for the Zabbix Agent or for the Zabbix Agent 2.
* `zabbix_agent(2)_pidfile`: name of pid file.
* `zabbix_agent(2)_logfile`: name of log file.
* `zabbix_agent(2)_logfilesize`: maximum size of log file in mb.
+* `zabbix_agent(2)_additional_include`: A list of additional complete paths to include in configuration
* `zabbix_agent(2)_logtype`: Specifies where log messages are written to
* `zabbix_agent(2)_debuglevel`: specifies debug level
* `zabbix_agent(2)_sourceip`: source ip address for outgoing connections.
@@ -261,16 +247,17 @@ These variables need to be overridden when you want to make use of the Zabbix AP
Host encryption configuration will be set to match agent configuration.
-* `zabbix_api_http_user`: The http user to access zabbix url with Basic Auth.
-* `zabbix_api_http_password`: The http password to access zabbix url with Basic Auth.
-* `zabbix_api_create_hosts`: Default: `False`. When you want to enable the Zabbix API to create/delete the host. This has to be set to `True` if you want to make use of `zabbix_agent_host_state`.
-* `zabbix_api_create_hostgroup`: When you want to enable the Zabbix API to create/delete the hostgroups. This has to be set to `True` if you want to make use of `zabbix_agent_hostgroups_state`.Default: `False`
* `zabbix_api_server_host`: The IP or hostname/FQDN of Zabbix server. Example: zabbix.example.com
-* `zabbix_api_server_port`: TCP port to use to connect to Zabbix server. Example: 8080
-* `zabbix_api_use_ssl`: yes (Default) if we need to connect to Zabbix server over HTTPS
-* `zabbix_api_validate_certs` : yes (Default) if we need to validate tls certificates of the API. Use `no` in case self-signed certificates are used
+* `zabbix_api_use_ssl`: Is SSL required to connect to the Zabbix API server? Default: `false`
+* `zabbix_api_server_port`: 80 if `zabbix_api_use_ssl` is `false` and 443 if `true` (Default) TCP port to use to connect to Zabbix server. Example: 8080
* `zabbix_api_login_user`: Username of user which has API access.
* `zabbix_api_login_pass`: Password for the user which has API access.
+* `zabbix_api_http_user`: The http user to access zabbix url with Basic Auth (if your Zabbix is behind a proxy with HTTP Basic Auth).
+* `zabbix_api_http_password`: The http password to access zabbix url with Basic Auth (if your Zabbix is behind a proxy with HTTP Basic Auth).
+* `zabbix_api_validate_certs`: yes (Default) if we need to validate tls certificates of the API. Use `no` in case self-signed certificates are used.
+* `zabbix_api_timeout`: How many seconds to wait for API response (default 30s).
+* `zabbix_api_create_hosts`: Default: `False`. When you want to enable the Zabbix API to create/delete the host. This has to be set to `True` if you want to make use of `zabbix_agent_host_state`.
+* `zabbix_api_create_hostgroup`: When you want to enable the Zabbix API to create/delete the hostgroups. This has to be set to `True` if you want to make use of `zabbix_agent_hostgroups_state`.Default: `False`
* `ansible_zabbix_url_path`: URL path if Zabbix WebUI running on non-default (zabbix) path, e.g. if http://<FQDN>/zabbixeu then set to `zabbixeu`
* `zabbix_agent_hostgroups_state`: present (Default) if the hostgroup needs to be created or absent if you want to delete it. This only works when `zabbix_api_create_hostgroup` is set to `True`.
* `zabbix_host_status`: enabled (Default) when host in monitored, disabled when host is disabled for monitoring.
@@ -290,7 +277,7 @@ Host encryption configuration will be set to match agent configuration.
**NOTE**
-_Supporting Windows is a best effort (I don't have the possibility to either test/verify changes on the various amount of available Windows instances). PRs specific to Windows will almost immediately be merged, unless someone is able to provide a Windows test mechanism via Travis for Pull Requests._
+_Supporting Windows is a best effort (We don't have the possibility to either test/verify changes on the various amount of available Windows instances). PRs specific to Windows will almost immediately be merged, unless someone is able to provide a Windows test mechanism via Travis for Pull Requests._
When `(2)` is used in the name of the property, like `zabbix_agent(2)_win_logfile`, it will show that you can configure `zabbix_agent_win_logfile` for the Zabbix Agent configuration file and `zabbix_agent2_win_logfile` for the Zabbix Agent 2 configuration file.
Otherwise it just for the Zabbix Agent or for the Zabbix Agent 2.
@@ -308,6 +295,10 @@ Otherwise it just for the Zabbix Agent or for the Zabbix Agent 2.
## macOS Variables
+**NOTE**
+
+_Supporting Windows is a best effort (We don't have the possibility to either test/verify changes on the various amount of available Windows instances). PRs specific to Windows will almost immediately be merged, unless someone is able to provide a Windows test mechanism via Travis for Pull Requests._
+
* `zabbix_version_long`: The long (major.minor.patch) version of the Zabbix Agent. This will be used to generate the `zabbix_mac_download_link` link.
* `zabbix_mac_download_link`: The download url to the `pkg` file.
@@ -344,17 +335,6 @@ Keep in mind that using the Zabbix Agent in a Container requires changes to the
* `zabbix_agent_docker_volumes`: A list with all directories that needs to be available in the Container.
* `zabbix_agent_docker_env`: A dict with all environment variables that needs to be set for the Container.
-## FirewallD/Iptables
-
-* `zabbix_agent_firewall_enable`: If IPtables needs to be updated by opening an TCP port for port configured in `zabbix_agent_listenport`.
-* `zabbix_agent_firewall_source`: When provided, IPtables will be configuring to only allow traffic from this IP address/range.
-* `zabbix_agent_firewalld_enable`: If firewalld needs to be updated by opening an TCP port for port configured in `zabbix_agent_listenport` and `zabbix_agent_jmx_listenport` if defined.
-* `zabbix_agent_firewalld_source`: When provided, firewalld will be configuring to only allow traffic for IP configured in `zabbix_agent_server`.
-* `zabbix_agent_firewalld_zone`: When provided, the firewalld rule will be attached to this zone (only if zabbix_agent_firewalld_enable is set to true). The default behavior is to use the default zone define by the remote host firewalld configuration.
-* `zabbix_agent_firewall_action`: Default: `insert`. When to `insert` the rule or to `append` to IPTables.
-* `zabbix_agent_firewall_chain`: Default `INPUT`. Which `chain` to add the rule to IPTables.
-
-
## IPMI variables
* `zabbix_agent_ipmi_authtype`: IPMI authentication algorithm. Possible values are 1 (callback), 2 (user), 3 (operator), 4 (admin), 5 (OEM), with 2 being the API default.
@@ -369,6 +349,17 @@ When the target host does not have access to the internet, but you do have a pro
* `zabbix_http_proxy`
* `zabbix_https_proxy`
+## Tags
+
+The majority of tasks within this role are tagged as follows:
+
+* `install`: Tasks associated with the installation of software.
+* `dependencies`: Installation tasks related to dependencies that aren't part of the core zabbix installation.
+* `database`: Tasks associated with the installation or configuration of the database.
+* `api`: Tasks associated with using the Zabbix API to connect and modify the Zabbix server.
+* `config`: Tasks associated with the configuration of Zabbix or a supporting service.
+* `service`: Tasks associated with managing a service.
+
# Dependencies
There are no dependencies on other roles.
@@ -440,10 +431,11 @@ Including an example of how to use your role (for instance, with variables passe
- role: community.zabbix.zabbix_agent
zabbix_agent_server: 192.168.33.30
zabbix_agent_serveractive: 192.168.33.30
- zabbix_api_server_url: http://zabbix.example.com
- zabbix_api_use: true # use zabbix_api_create_hosts and/or zabbix_api_create_hostgroup from 0.8.0
+ zabbix_api_server_host: zabbix.example.com
zabbix_api_login_user: Admin
zabbix_api_login_pass: zabbix
+ zabbix_api_create_hostgroup: true
+ zabbix_api_create_hosts: true
zabbix_agent_host_state: present
zabbix_host_groups:
- Linux Servers
@@ -465,10 +457,11 @@ You can also use the group_vars or the host_vars files for setting the variables
```yaml
zabbix_agent_server: 192.168.33.30
zabbix_agent_serveractive: 192.168.33.30
- zabbix_api_server_url: http://zabbix.example.com
- zabbix_api_use: true # use zabbix_api_create_hosts and/or zabbix_api_create_hostgroup from 0.8.0
+ zabbix_api_server_host: zabbix.example.com
zabbix_api_login_user: Admin
zabbix_api_login_pass: zabbix
+ zabbix_api_create_hostgroup: true
+ zabbix_api_create_hosts: true
zabbix_agent_host_state: present
zabbix_host_groups:
- Linux Servers
diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/defaults/main.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/defaults/main.yml
index 5fc96071a..dbd5db5db 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_agent/defaults/main.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_agent/defaults/main.yml
@@ -2,11 +2,9 @@
# defaults file for zabbix_agent
zabbix_agent2: false
-# zabbix_agent_version: 6.0
+# zabbix_agent_version: 6.4
zabbix_agent_version_minor: "*"
-zabbix_version: "{{ zabbix_agent_version }}"
zabbix_version_patch: 0
-zabbix_repo: zabbix
zabbix_agent_package_remove: false
zabbix_agent_package: zabbix-agent
zabbix_sender_package: zabbix-sender
@@ -17,7 +15,6 @@ zabbix_agent_serveractive:
zabbix_agent2_server: "{{ zabbix_agent_server }}"
zabbix_agent2_serveractive: "{{ zabbix_agent_serveractive }}"
zabbix_selinux: false
-zabbix_agent_src_reinstall: false
zabbix_agent_apt_priority:
zabbix_agent_conf_mode: "0644"
zabbix_agent_dont_detect_ip: false
@@ -36,22 +33,20 @@ zabbix_agent_packages:
- "{{ zabbix_get_package }}"
# Zabbix role related vars
-zabbix_install_pip_packages: true
zabbix_apt_force_apt_get: true
zabbix_apt_install_recommends: false
# Override Ansible specific facts
zabbix_agent_distribution_major_version: "{{ ansible_distribution_major_version }}"
zabbix_agent_distribution_release: "{{ ansible_distribution_release }}"
-zabbix_agent_os_family: "{{ ansible_os_family }}"
zabbix_repo_yum_gpgcheck: 0
zabbix_repo_yum_schema: https
-zabbix_repo_yum_disabled: "*"
-zabbix_repo_yum_enabled: []
+zabbix_agent_disable_repo:
+ - epel
zabbix_repo_yum:
- name: zabbix
description: Zabbix Official Repository - $basearch
- baseurl: "{{ zabbix_repo_yum_schema }}://repo.zabbix.com/zabbix/{{ zabbix_version }}/rhel/{{ zabbix_agent_distribution_major_version }}/$basearch/"
+ baseurl: "{{ zabbix_repo_yum_schema }}://repo.zabbix.com/zabbix/{{ zabbix_agent_version }}/rhel/{{ zabbix_agent_distribution_major_version }}/$basearch/"
mode: "0644"
gpgcheck: "{{ zabbix_repo_yum_gpgcheck }}"
gpgkey: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ZABBIX
@@ -71,48 +66,32 @@ zabbix_repo_yum:
gpgkey: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ZABBIX
state: present
+zabbix_repo_deb_component: main
+
# Zabbix API stuff
-zabbix_validate_certs: true # Will be deprecated in 2.0.0
-zabbix_api_validate_certs: "{{ zabbix_validate_certs }}"
-zabbix_agent_server_url: http://localhost # Will be deprecated in 2.0.0
-zabbix_url: "{{ zabbix_agent_server_url }}" # Will be deprecated in 2.0.0
-zabbix_api_server_url: "{{ zabbix_agent_server_url }}"
-zabbix_api_server_host: "{{ zabbix_api_server_url | urlsplit('hostname') }}"
-zabbix_api_port_from_url: "{{ zabbix_api_server_port | default(zabbix_api_server_url | urlsplit('port')) }}"
-zabbix_api_scheme_from_url: "{{ zabbix_api_server_url | urlsplit('scheme') }}"
-zabbix_api_port_from_shema: "{{ (zabbix_api_scheme_from_url == 'https') | ternary(443, 80) }}"
-# zabbix_http_user: admin # Will be deprecated in 2.0.0
-# zabbix_http_password: admin # Will be deprecated in 2.0.0
-# zabbix_api_http_user: admin
-# zabbix_api_http_password: admin
-zabbix_api_user: Admin # Will be deprecated in 2.0.0
-zabbix_api_pass: !unsafe zabbix # Will be deprecated in 2.0.0
-zabbix_api_login_user: "{{ zabbix_api_user }}"
-zabbix_api_login_pass: "{{ zabbix_api_pass }}"
+zabbix_api_server_host: localhost
+# zabbix_api_server_port: 80
+zabbix_api_login_user: Admin
+zabbix_api_use_ssl: false
+zabbix_api_login_pass: !unsafe zabbix
+zabbix_api_validate_certs: false
ansible_httpapi_pass: "{{ zabbix_api_login_pass }}"
-ansible_httpapi_port: "{{ (zabbix_api_port_from_url == '') | ternary(zabbix_api_port_from_shema, zabbix_api_port_from_url) }}"
-ansible_httpapi_use_ssl: "{{ zabbix_api_use_ssl | default((zabbix_api_scheme_from_url == 'https') | ternary(true, false)) }}"
+ansible_httpapi_port: "{{ zabbix_api_server_port }}"
ansible_httpapi_validate_certs: "{{ zabbix_api_validate_certs }}"
+zabbix_api_timeout: 30
zabbix_api_create_hostgroup: false
zabbix_api_create_hosts: false
-zabbix_api_timeout: 30
-zabbix_create_hostgroup: present # or absent # Will be deprecated in 2.0.0
-zabbix_agent_hostgroups_state: "{{ zabbix_create_hostgroup }}"
-zabbix_create_host: present # or absent # Will be deprecated in 2.0.0
-zabbix_agent_host_state: "{{ zabbix_create_host }}"
-zabbix_update_host: true # Will be deprecated in 2.0.0
-zabbix_agent_host_update: "{{ zabbix_update_host }}"
+zabbix_agent_hostgroups_state: present # or absent
+zabbix_agent_host_state: present # or absent
+zabbix_agent_host_update: true
zabbix_host_status: enabled # or disabled
-zabbix_proxy: null # Will be deprecated in 2.0.0
-zabbix_agent_proxy: "{{ zabbix_proxy }}"
-zabbix_inventory_mode: disabled # Will be deprecated in 2.0.0
-zabbix_agent_inventory_mode: "{{ zabbix_inventory_mode }}"
+zabbix_agent_proxy: null
+zabbix_agent_inventory_mode: disabled
zabbix_useuip: 1
zabbix_host_groups:
- Linux servers
-zabbix_link_templates: # Will be deprecated in 2.0.0
+zabbix_agent_link_templates:
- Template Linux by Zabbix agent
-zabbix_agent_link_templates: "{{ zabbix_link_templates }}"
zabbix_agent_interfaces:
- type: 1
@@ -122,14 +101,6 @@ zabbix_agent_interfaces:
dns: "{{ ansible_fqdn }}"
port: "{{ (zabbix_agent2 == True) | ternary(zabbix_agent2_listenport, zabbix_agent_listenport) }}"
-zabbix_agent_firewall_enable: false
-zabbix_agent_firewalld_enable: false
-zabbix_agent_firewalld_source: "{{ zabbix_agent_server }}"
-zabbix_agent_firewall_action: insert
-zabbix_agent_firewall_chain: INPUT
-
-# By default, a null zone will trigger the use of the default zone on the remote host
-zabbix_agent_firewalld_zone:
# Zabbix configuration variables
zabbix_agent_pidfile: /var/run/zabbix/zabbix_agentd.pid
zabbix_agent_logtype: file
@@ -171,8 +142,7 @@ zabbix_agent_become_on_localhost: true
zabbix_agent_description:
zabbix_agent_inventory_zabbix: {}
zabbix_agent_heartbeatfrequency: 60
-zabbix_macros: [] # Will be deprecated in 2.0.0
-zabbix_agent_macros: "{{ zabbix_macros }}"
+zabbix_agent_macros: []
zabbix_agent_tags: []
zabbix_agent_chassis: false
@@ -272,7 +242,7 @@ zabbix_agent_docker: false
zabbix_agent_docker_state: started
zabbix_agent_docker_name: zabbix-agent
zabbix_agent_docker_image: "zabbix/zabbix-agent"
-zabbix_agent_docker_image_tag: "ubuntu-{{ zabbix_version }}.{{ zabbix_version_patch }}"
+zabbix_agent_docker_image_tag: "ubuntu-{{ zabbix_agent_version }}.{{ zabbix_version_patch }}"
zabbix_agent_docker_user_gid: 101
zabbix_agent_docker_user_uid: 101
zabbix_agent_docker_network_mode: host
diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/handlers/main.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/handlers/main.yml
index cd0f9d932..9f04b1a9b 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_agent/handlers/main.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_agent/handlers/main.yml
@@ -2,17 +2,17 @@
# handlers file for zabbix-agent
- name: restart zabbix-agent
- service:
+ ansible.builtin.service:
name: "{{ zabbix_agent_service }}"
state: restarted
enabled: true
become: true
when:
- not zabbix_agent_docker
- - zabbix_agent_os_family != "Windows" and zabbix_agent_os_family != "Darwin"
+ - ansible_os_family != "Windows" and ansible_os_family != "Darwin"
- name: firewalld-reload
- command: "firewall-cmd --reload"
+ ansible.builtin.command: "firewall-cmd --reload"
become: true
when:
- ansible_facts.services["firewalld"] is defined
@@ -23,17 +23,17 @@
name: "{{ zabbix_win_svc_name }}"
state: restarted
when:
- - zabbix_agent_os_family == "Windows"
+ - ansible_os_family == "Windows"
- name: restart mac zabbix agent
- command: "launchctl kickstart -k system/{{ zabbix_agent_service }}"
+ ansible.builtin.command: "launchctl kickstart -k system/{{ zabbix_agent_service }}"
become: true
when:
- not zabbix_agent_docker
- - zabbix_agent_os_family == "Darwin"
+ - ansible_os_family == "Darwin"
- name: "clean repo files from proxy creds"
- shell: ls /etc/yum.repos.d/zabbix* && sed -i 's/^proxy =.*//' /etc/yum.repos.d/zabbix* || true
+ ansible.builtin.shell: ls /etc/yum.repos.d/zabbix* && sed -i 's/^proxy =.*//' /etc/yum.repos.d/zabbix* || true
become: true
when:
- ansible_os_family == 'RedHat'
diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/molecule/with-server/molecule.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/molecule/with-server/molecule.yml
index e7b8e06ae..137eac314 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_agent/molecule/with-server/molecule.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_agent/molecule/with-server/molecule.yml
@@ -3,9 +3,6 @@ dependency:
name: galaxy
driver:
name: docker
-lint:
- name: yamllint
-
platforms:
- name: zabbix-server-centos
image: milcom/centos7-systemd:latest
@@ -46,12 +43,9 @@ provisioner:
docker:
create: ../default/create.yml
destroy: ../default/destroy.yml
- lint:
- name: ansible-lint
inventory:
group_vars:
all:
- zabbix_agent_src_reinstall: false
zabbix_api_create_hosts: true
zabbix_api_create_hostgroup: true
zabbix_api_server_url: http://zabbix-server-centos
@@ -77,5 +71,3 @@ scenario:
verifier:
name: testinfra
- lint:
- name: flake8
diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/molecule/with-server/playbook.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/molecule/with-server/playbook.yml
index e1bb7d8d4..2f0795448 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_agent/molecule/with-server/playbook.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_agent/molecule/with-server/playbook.yml
@@ -3,7 +3,7 @@
hosts: all:!zabbix_server
pre_tasks:
- name: "Get IP Server"
- shell: grep $(hostname) /etc/hosts | awk '{ print $1 }' | tail -n 1
+ ansible.builtin.shell: grep $(hostname) /etc/hosts | awk '{ print $1 }' | tail -n 1
register: ip_address
delegate_to: zabbix-server-centos
changed_when: false
@@ -11,7 +11,7 @@
- skip_ansible_lint
- name: "Get IP hosts"
- shell: grep $(hostname) /etc/hosts | awk '{ print $1 }' | tail -n 1
+ ansible.builtin.shell: grep $(hostname) /etc/hosts | awk '{ print $1 }' | tail -n 1
register: ip_address_host
changed_when: false
tags:
diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/molecule/with-server/prepare.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/molecule/with-server/prepare.yml
index 6722e5fea..582006d4e 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_agent/molecule/with-server/prepare.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_agent/molecule/with-server/prepare.yml
@@ -3,14 +3,14 @@
hosts: zabbix_server
pre_tasks:
- name: "Installing EPEL"
- yum:
+ ansible.builtin.yum:
name:
- epel-release
state: present
when: ansible_distribution == 'CentOS'
- name: "Installing packages"
- yum:
+ ansible.builtin.yum:
name:
- net-tools
- which
@@ -21,7 +21,7 @@
when: ansible_distribution == 'CentOS'
- name: "Installing which on NON-CentOS"
- apt:
+ ansible.builtin.apt:
name:
- net-tools
- python-pip
@@ -30,19 +30,19 @@
when: ansible_distribution != 'CentOS'
- name: "Configure SUDO."
- lineinfile:
+ ansible.builtin.lineinfile:
dest: /etc/sudoers
line: "Defaults !requiretty"
state: present
- name: "Make sure the docs are installed."
- lineinfile:
+ ansible.builtin.lineinfile:
dest: /etc/yum.conf
line: "tsflags=nodocs"
state: absent
- name: "Installing some python dependencies"
- pip:
+ ansible.builtin.pip:
name: py-zabbix
state: present
@@ -55,7 +55,7 @@
hosts: all:!zabbix_server:!docker
tasks:
- name: "Installing packages on CentOS family"
- yum:
+ ansible.builtin.yum:
name:
- net-tools
- which
@@ -64,7 +64,7 @@
- ansible_os_family == 'RedHat'
- name: "Installing packages on Debian family"
- apt:
+ ansible.builtin.apt:
name:
- net-tools
state: present
@@ -75,7 +75,7 @@
hosts: docker
tasks:
- name: "Download Docker CE repo file"
- get_url:
+ ansible.builtin.get_url:
url: https://download.docker.com/linux/centos/docker-ce.repo
dest: /etc/yum.repos.d/docker-ce.repo
mode: 0644
@@ -83,7 +83,7 @@
until: zabbix_agent_prepare_docker_repo is succeeded
- name: "Installing Epel"
- package:
+ ansible.builtin.package:
pkg:
- epel-release
state: present
@@ -91,7 +91,7 @@
until: zabbix_agent_prepare_docker_install is succeeded
- name: "Installing Docker"
- package:
+ ansible.builtin.package:
pkg:
- docker-ce
- python-pip
@@ -101,7 +101,7 @@
until: zabbix_agent_prepare_docker_install is succeeded
- name: "Installing Docker Python"
- pip:
+ ansible.builtin.pip:
name:
- docker
state: present
@@ -109,6 +109,6 @@
until: zabbix_agent_prepare_docker_install is succeeded
- name: "Starting Docker service"
- service:
+ ansible.builtin.service:
name: docker
state: started
diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Darwin.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Darwin.yml
deleted file mode 100644
index e98576f61..000000000
--- a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Darwin.yml
+++ /dev/null
@@ -1,177 +0,0 @@
----
-
-- name: "Set default ip address for zabbix_agent_ip"
- set_fact:
- zabbix_agent_ip: "{{ hostvars[inventory_hostname]['ansible_default_ipv4'].address }}"
- when:
- - zabbix_agent_ip is not defined
- - "'ansible_default_ipv4' in hostvars[inventory_hostname]"
-
-- name: "Get Total Private IP Addresses"
- set_fact:
- total_private_ip_addresses: "{{ ansible_all_ipv4_addresses | ansible.netcommon.ipaddr('private') | length }}"
- when:
- - ansible_all_ipv4_addresses is defined
-
-- name: "Set first public ip address for zabbix_agent_ip"
- set_fact:
- zabbix_agent_ip: "{{ ansible_all_ipv4_addresses | ansible.netcommon.ipaddr('public') | first }}"
- zabbix_agent_server: "{{ zabbix_agent_server_public_ip | default(zabbix_agent_server) }}"
- zabbix_agent_serveractive: "{{ zabbix_agent_serveractive_public_ip | default(zabbix_agent_serveractive) }}"
- zabbix_agent2_server: "{{ zabbix_agent_server_public_ip | default(zabbix_agent2_server) }}"
- zabbix_agent2_serveractive: "{{ zabbix_agent_serveractive_public_ip | default(zabbix_agent2_serveractive) }}"
- when:
- - zabbix_agent_ip is not defined
- - total_private_ip_addresses is defined
- - total_private_ip_addresses == '0'
-
-- name: "Set first private ip address for zabbix_agent_ip"
- set_fact:
- zabbix_agent_ip: "{{ ansible_all_ipv4_addresses | ansible.netcommon.ipaddr('private') | first }}"
- when:
- - zabbix_agent_ip is not defined
- - total_private_ip_addresses is defined
- - total_private_ip_addresses != '0'
-
-- name: "Fail invalid specified agent_listeninterface"
- fail:
- msg: "The specified network interface does not exist"
- when:
- - zabbix_agent_listeninterface
- - (zabbix_agent_listeninterface not in ansible_all_ipv4_addresses)
- tags:
- - zabbix-agent
- - config
-
-- name: "Set network interface"
- set_fact:
- network_interface: ansible_{{ zabbix_agent_listeninterface }}
- when:
- - zabbix_agent_listeninterface
- - not zabbix_agent_listenip
-
-- name: "Get IP of agent_listeninterface when no agent_listenip specified"
- set_fact:
- zabbix_agent_listenip: "{{ hostvars[inventory_hostname][network_interface]['ipv4'].address | default('0.0.0.0') }}"
- zabbix_agent_ip: "{{ hostvars[inventory_hostname][network_interface]['ipv4'].address | default('0.0.0.0') }}"
- when:
- - zabbix_agent_listeninterface
- - not zabbix_agent_listenip
- tags:
- - zabbix-agent
- - config
- - api
-
-- name: "Default agent_listenip to all when not specified"
- set_fact:
- zabbix_agent_listenip: '0.0.0.0'
- when:
- - not zabbix_agent_listenip
- tags:
- - zabbix-agent
- - config
-
-- name: "Fail invalid specified agent_listenip"
- fail:
- msg: "The agent_listenip does not exist"
- when:
- - zabbix_agent_listenip != '0.0.0.0'
- - zabbix_agent_listenip != '127.0.0.1'
- - (zabbix_agent_listenip not in ansible_all_ipv4_addresses)
- tags:
- - zabbix-agent
- - config
-
-- name: "Installing Agent"
- include_tasks: macOS.yml
- tags:
- - always
-
-- name: "Configure zabbix-agent"
- template:
- src: zabbix_agentd.conf.j2
- dest: "/usr/local/etc/zabbix/{{ zabbix_agent_conf }}"
- owner: zabbix
- group: wheel
- mode: 0644
- notify:
- - restart mac zabbix agent
- become: true
- when:
- - not (zabbix_agent_docker | bool)
- tags:
- - zabbix-agent
- - config
- - init
-
-- name: "Create directory for PSK file if not exist."
- file:
- path: "{{ zabbix_agent_tlspskfile | dirname }}"
- mode: 0755
- state: directory
- become: true
- when:
- - zabbix_agent_tlspskfile is defined
-
-- name: "Place TLS PSK File"
- copy:
- dest: "{{ zabbix_agent_tlspskfile }}"
- content: "{{ zabbix_agent_tlspsk_secret }}"
- owner: zabbix
- group: zabbix
- mode: 0400
- become: true
- when:
- - zabbix_agent_tlspskfile is defined
- - zabbix_agent_tlspsk_secret is defined
- notify:
- - restart mac zabbix agent
-
-- name: "Create include dir zabbix-agent"
- file:
- path: "{{ zabbix_agent_include }}"
- owner: zabbix
- group: zabbix
- mode: 0750
- state: directory
- become: true
- tags:
- - config
- - include
-
-- name: "Create pid file directory for zabbix-agent"
- file:
- path: /var/run/zabbix
- state: directory
- owner: zabbix
- group: zabbix
- mode: 0755
- become: true
-
-- name: "Install the Docker container"
- include_tasks: Docker.yml
- when:
- - zabbix_agent_docker | bool
-
-- name: "Check if zabbix-agent service is running"
- shell: |
- set -o pipefail
- launchctl list | grep com.zabbix.zabbix_agentd | awk '{print $1}'
- register: launchctl_pid
- check_mode: false
- changed_when: false
- failed_when: launchctl_pid.rc == 2
- become: true
- tags:
- - init
- - service
-
-- name: "Make sure the zabbix-agent service is running"
- command: launchctl start com.zabbix.zabbix_agentd
- become: true
- when:
- - not (zabbix_agent_docker | bool)
- - launchctl_pid.stdout == "-"
- tags:
- - init
- - service
diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Debian.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Debian.yml
index ec4a01879..6ded0ba03 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Debian.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Debian.yml
@@ -1,17 +1,16 @@
---
# Tasks specific for Debian/Ubuntu Systems
-- name: "Include Zabbix gpg ids"
- include_vars: zabbix.yml
-
-- name: "Set short version name"
- set_fact:
- zabbix_short_version: "{{ zabbix_version | regex_replace('\\.', '') }}"
- zabbix_underscore_version: "{{ zabbix_version | regex_replace('\\.', '_') }}"
+- name: "Debian | Set some variables"
+ ansible.builtin.set_fact:
+ zabbix_short_version: "{{ zabbix_agent_version | regex_replace('\\.', '') }}"
+ zabbix_underscore_version: "{{ zabbix_agent_version | regex_replace('\\.', '_') }}"
+ tags:
+ - always
-- name: "Debian | Installing gnupg"
- apt:
- pkg: gnupg
+- name: "Debian | Installing lsb-release"
+ ansible.builtin.apt:
+ pkg: lsb-release
update_cache: true
cache_valid_time: 3600
force: true
@@ -19,174 +18,111 @@
environment:
http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
- register: gnupg_installed
- until: gnupg_installed is succeeded
- become: true
-
-- name: "Debian | Install gpg key"
- apt_key:
- id: "{{ sign_keys[zabbix_short_version][zabbix_agent_distribution_release]['sign_key'] }}"
- url: http://repo.zabbix.com/zabbix-official-repo.key
- environment:
- http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
- https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
- when:
- - zabbix_repo == "zabbix"
become: true
tags:
- - zabbix-agent
- - init
+ - install
-- name: "Debian | Check for zabbix repositories"
- find:
- paths: /etc/apt/sources.list.d
- patterns: repo_zabbix_com_zabbix*.list
- excludes: "repo_zabbix_com_zabbix_{{ zabbix_underscore_version }}_ubuntu.list"
- register: repositories
- become: true
- when:
- - ansible_distribution in ['Ubuntu', 'Debian']
- - zabbix_repo == "zabbix"
- tags:
- - zabbix-agent
- - init
+- name: "Debian | Update ansible_lsb fact"
+ ansible.builtin.setup:
+ gather_subset:
+ - lsb
-- name: "Debian | Remove unecessary zabbix repositories"
- file:
- path: "{{ item.path }}"
- state: absent
- loop: "{{ repositories.files }}"
+- name: "Debian | Repo URL"
+ ansible.builtin.set_fact:
+ zabbix_repo_deb_url: "{{ _zabbix_repo_deb_url }}/{{ ansible_lsb.id.lower() }}{{ '-arm64' if ansible_machine == 'aarch64' and ansible_lsb.id == 'debian' else ''}}"
when:
- - ansible_distribution in ['Ubuntu', 'Debian']
- - zabbix_repo == "zabbix"
- - zabbix_agent_src_reinstall
- become: true
+ - zabbix_repo_deb_url is undefined
tags:
- - zabbix-agent
- - init
+ - always
-- name: "Debian | Installing deb-src repository Debian"
- apt_repository:
- repo: "deb-src http://repo.zabbix.com/zabbix/{{ zabbix_version }}/debian/ {{ zabbix_agent_distribution_release }} main"
- state: present
- environment:
- http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
- https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
- when:
- - ansible_distribution == "Debian"
- - zabbix_repo == "zabbix"
- become: true
- tags:
- - zabbix-agent
- - init
-
-- name: "Debian | Installing deb repository Debian"
- apt_repository:
- repo: "deb http://repo.zabbix.com/zabbix/{{ zabbix_version }}/debian/ {{ zabbix_agent_distribution_release }} main"
+- name: "Debian | Installing gnupg"
+ ansible.builtin.apt:
+ pkg: gnupg
+ update_cache: true
+ cache_valid_time: 3600
+ force: true
state: present
environment:
http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
- when:
- - ansible_distribution == "Debian"
- - zabbix_repo == "zabbix"
+ register: gnupg_installed
+ until: gnupg_installed is succeeded
become: true
tags:
- - zabbix-agent
- - init
-
-- name: "Debian | Installing deb-src repository Ubuntu Arm64"
- apt_repository:
- repo: "deb-src http://repo.zabbix.com/zabbix/{{ zabbix_version }}/ubuntu-arm64/ {{ zabbix_agent_distribution_release }} main"
- state: present
- environment:
- http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
- https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
- when:
- - ansible_distribution == "Ubuntu"
- - ansible_machine == "aarch64"
- - zabbix_repo == "zabbix"
+ - install
+
+# In releases older than Debian 12 and Ubuntu 22.04, /etc/apt/keyrings does not exist by default.
+# It SHOULD be created with permissions 0755 if it is needed and does not already exist.
+# See: https://wiki.debian.org/DebianRepository/UseThirdParty
+- name: "Debian | Create /etc/apt/keyrings/ on older versions"
+ ansible.builtin.file:
+ path: /etc/apt/keyrings/
+ state: directory
+ mode: "0755"
become: true
- tags:
- - zabbix-agent
- - init
-
-- name: "Debian | Installing deb repository Ubuntu Arm64"
- apt_repository:
- repo: "deb http://repo.zabbix.com/zabbix/{{ zabbix_version }}/ubuntu-arm64/ {{ zabbix_agent_distribution_release }} main"
- state: present
- environment:
- http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
- https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
when:
- - ansible_distribution == "Ubuntu"
- - ansible_machine == "aarch64"
- - zabbix_repo == "zabbix"
- become: true
- tags:
- - zabbix-agent
- - init
+ - (ansible_distribution == "Ubuntu" and ansible_distribution_major_version < "22") or
+ (ansible_distribution == "Debian" and ansible_distribution_major_version < "12")
-- name: "Debian | Installing deb-src repository Ubuntu"
- apt_repository:
- repo: "deb-src http://repo.zabbix.com/zabbix/{{ zabbix_version }}/ubuntu/ {{ zabbix_agent_distribution_release }} main"
- state: present
+- name: "Debian | Download gpg key"
+ ansible.builtin.get_url:
+ url: http://repo.zabbix.com/zabbix-official-repo.key
+ dest: "{{ zabbix_gpg_key }}"
+ mode: "0644"
+ force: true
environment:
http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
- when:
- - ansible_distribution == "Ubuntu"
- - ansible_machine != "aarch64"
- - zabbix_repo == "zabbix"
become: true
tags:
- - zabbix-agent
- - init
+ - install
-- name: "Debian | Installing deb repository Ubuntu"
- apt_repository:
- repo: "deb http://repo.zabbix.com/zabbix/{{ zabbix_version }}/ubuntu/ {{ zabbix_agent_distribution_release }} main"
- state: present
- environment:
- http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
- https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
- when:
- - ansible_distribution == "Ubuntu"
- - ansible_machine != "aarch64"
- - zabbix_repo == "zabbix"
+- name: "Debian | Installing repository {{ ansible_distribution }}"
+ ansible.builtin.copy:
+ dest: /etc/apt/sources.list.d/zabbix.sources
+ owner: root
+ group: root
+ mode: 0644
+ content: |
+ Types: deb deb-src
+ Enabled: yes
+ URIs: {{ zabbix_repo_deb_url }}
+ Suites: {{ ansible_distribution_release }}
+ Components: {{ zabbix_repo_deb_component }}
+ Architectures: {{ 'amd64' if ansible_machine != 'aarch64' else 'arm64'}}
+ Signed-By: {{ zabbix_gpg_key }}
become: true
tags:
- - zabbix-agent
- - init
+ - install
- name: "Debian | Create /etc/apt/preferences.d/"
- file:
+ ansible.builtin.file:
path: /etc/apt/preferences.d/
state: directory
- mode: '0755'
+ mode: "0755"
when:
- zabbix_agent_apt_priority | int
become: true
+ tags:
+ - install
- name: "Debian | Configuring the weight for APT"
- copy:
+ ansible.builtin.copy:
dest: "/etc/apt/preferences.d/zabbix-agent-{{ zabbix_underscore_version }}"
content: |
Package: {{ zabbix_agent_package }}
Pin: origin repo.zabbix.com
Pin-Priority: {{ zabbix_agent_apt_priority | int }}
owner: root
- mode: '0644'
+ mode: "0644"
when:
- zabbix_agent_apt_priority | int
become: true
+ tags:
+ - install
-# Note: set cache_valid_time=0 to ensure that an apt-get update after the added repo-key
-# else you often get 'WARNING: The following packages cannot be authenticated!
-# See also:
-# http://askubuntu.com/questions/75565/why-am-i-getting-authentication-errors-for-packages-from-an-ubuntu-repository
- name: "Debian | Installing zabbix-agent"
- apt:
+ ansible.builtin.apt:
pkg: "{{ zabbix_agent_package }}"
state: "{{ zabbix_agent_package_state }}"
update_cache: true
@@ -196,16 +132,14 @@
environment:
http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
- when: ansible_distribution in ['Ubuntu', 'Debian']
register: zabbix_agent_package_installed
until: zabbix_agent_package_installed is succeeded
become: true
tags:
- - zabbix-agent
- - init
+ - install
- name: "Debian | Installing zabbix-{sender,get}"
- apt:
+ ansible.builtin.apt:
pkg:
- "{{ zabbix_sender_package }}"
- "{{ zabbix_get_package }}"
@@ -218,42 +152,19 @@
http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
when:
- - ansible_distribution in ['Ubuntu', 'Debian']
- not zabbix_agent_install_agent_only
register: zabbix_agent_package_installed
until: zabbix_agent_package_installed is succeeded
become: true
check_mode: false
tags:
- - zabbix-agent
- - init
-
-- name: "Mint | Installing zabbix-agent"
- apt:
- pkg: "zabbix-agent"
- state: "{{ zabbix_agent_package_state }}"
- update_cache: true
- cache_valid_time: 0
- force_apt_get: "{{ zabbix_apt_force_apt_get }}"
- install_recommends: "{{ zabbix_apt_install_recommends }}"
- environment:
- http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
- https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
- when: ansible_distribution not in ['Ubuntu', 'Debian']
- register: zabbix_agent_package_installed
- until: zabbix_agent_package_installed is succeeded
- become: true
- tags:
- - zabbix-agent
- - init
+ - install
- name: "Debian | Enable the service"
- service:
+ ansible.builtin.service:
name: "{{ zabbix_agent_service }}"
enabled: true
use: service
become: true
tags:
- - zabbix-agent
- - init
- service
diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Docker.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Docker.yml
index cbbef204d..031a5fe61 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Docker.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Docker.yml
@@ -1,7 +1,6 @@
---
-
- name: "Create volume mount string"
- set_fact:
+ ansible.builtin.set_fact:
volume_mount: "{{ zabbix_agent_tlspskfile }}:/var/lib/zabbix/enc/tlspskfile"
tls_key:
ZBX_TLSPSKFILE: tlspskfile
@@ -9,7 +8,7 @@
- zabbix_agent_tlspskfile is defined
- name: "Add zabbix_agent_tlspskfile to volume mount"
- set_fact:
+ ansible.builtin.set_fact:
zabbix_agent_docker_volumes: "{{ zabbix_agent_docker_volumes + [ volume_mount ] }}"
zabbix_agent_docker_env: "{{ zabbix_agent_docker_env | combine(tls_key) }}"
when:
diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Linux.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Linux.yml
index d2c0ba82c..c4c8fc401 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Linux.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Linux.yml
@@ -1,21 +1,24 @@
---
-
- name: "Set default ip address for zabbix_agent_ip"
- set_fact:
+ ansible.builtin.set_fact:
zabbix_agent_ip: "{{ hostvars[inventory_hostname]['ansible_default_ipv4'].address }}"
when:
- zabbix_agent_ip is not defined
- "'ansible_default_ipv4' in hostvars[inventory_hostname]"
+ tags:
+ - config
- name: "Get Total Private IP Addresses"
- set_fact:
+ ansible.builtin.set_fact:
total_private_ip_addresses: "{{ ansible_all_ipv4_addresses | ansible.utils.ipaddr('private') | length }}"
when:
- ansible_all_ipv4_addresses is defined
- not (zabbix_agent_dont_detect_ip)
+ tags:
+ - config
- name: "Set first public ip address for zabbix_agent_ip"
- set_fact:
+ ansible.builtin.set_fact:
zabbix_agent_ip: "{{ ansible_all_ipv4_addresses | ansible.netcommon.ipaddr('public') | first }}"
zabbix_agent_server: "{{ zabbix_agent_server_public_ip | default(zabbix_agent_server) }}"
zabbix_agent_serveractive: "{{ zabbix_agent_serveractive_public_ip | default(zabbix_agent_serveractive) }}"
@@ -25,79 +28,83 @@
- zabbix_agent_ip is not defined
- total_private_ip_addresses is defined
- total_private_ip_addresses == '0'
+ tags:
+ - config
- name: "Set first private ip address for zabbix_agent_ip"
- set_fact:
+ ansible.builtin.set_fact:
zabbix_agent_ip: "{{ ansible_all_ipv4_addresses | ansible.netcommon.ipaddr('private') | first }}"
when:
- zabbix_agent_ip is not defined
- total_private_ip_addresses is defined
- total_private_ip_addresses != '0'
+ tags:
+ - config
- name: "Fail invalid specified agent_listeninterface"
- fail:
+ ansible.builtin.fail:
msg: "The specified network interface does not exist"
when:
- (zabbix_agent_listeninterface)
- (zabbix_agent_listeninterface not in ansible_interfaces)
tags:
- - zabbix-agent
- config
- name: "Set network interface"
- set_fact:
+ ansible.builtin.set_fact:
network_interface: ansible_{{ zabbix_agent_listeninterface }}
when:
- (zabbix_agent_listeninterface)
- not zabbix_agent_listenip
+ tags:
+ - config
- name: "Get IP of agent_listeninterface when no agent_listenip specified"
- set_fact:
+ ansible.builtin.set_fact:
zabbix_agent_listenip: "{{ hostvars[inventory_hostname][network_interface]['ipv4'].address | default('0.0.0.0') }}"
when:
- (zabbix_agent_listeninterface)
- not zabbix_agent_listenip
tags:
- - zabbix-agent
- config
- api
- name: "Default agent_listenip to all when not specified"
- set_fact:
- zabbix_agent_listenip: '0.0.0.0'
+ ansible.builtin.set_fact:
+ zabbix_agent_listenip: "0.0.0.0"
when:
- not (zabbix_agent_listenip)
tags:
- - zabbix-agent
- config
- name: "Fail invalid specified agent_listenip"
- fail:
+ ansible.builtin.fail:
msg: "The agent_listenip does not exist"
when:
- zabbix_agent_listenip != '0.0.0.0'
- zabbix_agent_listenip != '127.0.0.1'
- (zabbix_agent_listenip not in ansible_all_ipv4_addresses)
tags:
- - zabbix-agent
- config
- name: "Configure SELinux when enabled"
- include_tasks: selinux.yml
+ ansible.builtin.include_tasks: selinux.yml
when:
- zabbix_selinux | bool
- name: "Adding zabbix group"
- group:
+ ansible.builtin.group:
name: zabbix
state: present
gid: "{{ zabbix_agent_docker_user_gid | default(omit) }}"
become: true
when:
- zabbix_agent_docker | bool
+ tags:
+ - config
- name: "Adding zabbix user"
- user:
+ ansible.builtin.user:
name: zabbix
group: zabbix
state: present
@@ -108,9 +115,11 @@
become: true
when:
- zabbix_agent_docker | bool
+ tags:
+ - config
- name: "Configure zabbix-agent"
- template:
+ ansible.builtin.template:
src: "{{ 'zabbix_agentd.conf.j2' if not zabbix_agent2 else 'zabbix_agent2.conf.j2' }}"
dest: "/etc/zabbix/{{ zabbix_agent_conf if not zabbix_agent2 else zabbix_agent2_conf }}"
owner: root
@@ -122,34 +131,36 @@
when:
- not (zabbix_agent_docker | bool)
tags:
- - zabbix-agent
- config
- - init
- name: "Create directory for PSK file if not exist."
- file:
+ ansible.builtin.file:
path: "{{ zabbix_agent_tlspskfile | dirname }}"
mode: 0755
state: directory
become: true
when:
- zabbix_agent_tlspskfile is defined
- - zabbix_agent_tlspskfile # https://github.com/ansible-collections/community.zabbix/issues/680
+ - zabbix_agent_tlspskfile # https://github.com/ansible-collections/community.zabbix/issues/680
- not (zabbix_agent2 | bool)
+ tags:
+ - config
- name: "Create directory for PSK file if not exist (zabbix-agent2)"
- file:
+ ansible.builtin.file:
path: "{{ zabbix_agent2_tlspskfile | dirname }}"
mode: 0755
state: directory
become: true
when:
- zabbix_agent2_tlspskfile is defined
- - zabbix_agent2_tlspskfile # https://github.com/ansible-collections/community.zabbix/issues/680
+ - zabbix_agent2_tlspskfile # https://github.com/ansible-collections/community.zabbix/issues/680
- zabbix_agent2 | bool
+ tags:
+ - config
- name: "Place TLS PSK File"
- copy:
+ ansible.builtin.copy:
dest: "{{ zabbix_agent_tlspskfile }}"
content: "{{ zabbix_agent_tlspsk_secret }}"
owner: zabbix
@@ -158,14 +169,16 @@
become: true
when:
- zabbix_agent_tlspskfile is defined
- - zabbix_agent_tlspskfile # https://github.com/ansible-collections/community.zabbix/issues/680
+ - zabbix_agent_tlspskfile # https://github.com/ansible-collections/community.zabbix/issues/680
- zabbix_agent_tlspsk_secret is defined
- not (zabbix_agent2 | bool)
notify:
- restart zabbix-agent
+ tags:
+ - config
- name: "Place TLS PSK File (zabbix-agent2)"
- copy:
+ ansible.builtin.copy:
dest: "{{ zabbix_agent2_tlspskfile }}"
content: "{{ zabbix_agent2_tlspsk_secret }}"
owner: zabbix
@@ -174,14 +187,16 @@
become: true
when:
- zabbix_agent2_tlspskfile is defined
- - zabbix_agent2_tlspskfile # https://github.com/ansible-collections/community.zabbix/issues/680
+ - zabbix_agent2_tlspskfile # https://github.com/ansible-collections/community.zabbix/issues/680
- zabbix_agent2_tlspsk_secret is defined
- zabbix_agent2 | bool
notify:
- restart zabbix-agent
+ tags:
+ - config
- name: "Create include dir zabbix-agent"
- file:
+ ansible.builtin.file:
path: "{{ zabbix_agent_include if not zabbix_agent2 else zabbix_agent2_include }}"
owner: root
group: zabbix
@@ -190,26 +205,20 @@
become: true
tags:
- config
- - include
- name: "Install the Docker container"
- include_tasks: Docker.yml
+ ansible.builtin.include_tasks: Docker.yml
when:
- zabbix_agent_docker | bool
-- name: "Configure the firewall(d|iptables)"
- include_tasks: firewall.yml
- when:
- - (zabbix_agent_firewall_enable | bool) or (zabbix_agent_firewalld_enable | bool)
-
- name: "Remove zabbix-agent installation when zabbix-agent2 is used."
- include_tasks: remove.yml
+ ansible.builtin.include_tasks: remove.yml
when:
- zabbix_agent2 | bool
- zabbix_agent_package_remove
- name: "Make sure the zabbix-agent service is running"
- service:
+ ansible.builtin.service:
name: "{{ zabbix_agent_service }}"
state: started
enabled: true
@@ -217,12 +226,14 @@
when:
- not (zabbix_agent_docker | bool)
tags:
- - init
- service
- name: "Give zabbix-agent access to system.hw.chassis info"
- file:
+ ansible.builtin.file:
path: /sys/firmware/dmi/tables/DMI
owner: root
group: zabbix
+ become: true
when: zabbix_agent_chassis | bool
+ tags:
+ - config
diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/RedHat.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/RedHat.yml
index ef8cfaf09..f23cb46ad 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/RedHat.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/RedHat.yml
@@ -1,133 +1,53 @@
---
# Tasks specific for RedHat systems
-- name: "RedHat | Use EPEL package name"
- set_fact:
- zabbix_agent_package: "zabbix{{ zabbix_version | regex_replace('\\.', '') }}-agent"
- zabbix_sender_package: "zabbix{{ zabbix_version | regex_replace('\\.', '') }}-sender"
- zabbix_get_package: "zabbix{{ zabbix_version | regex_replace('\\.', '') }}-get"
- when:
- - zabbix_repo == "epel"
- tags:
- - zabbix-agent
- - init
-
-- name: "RedHat | Set zabbix_agent_distribution_major_version to 6 when Amazon"
- set_fact:
- zabbix_agent_distribution_major_version: 6
- when:
- - ansible_distribution == "Amazon"
- - ansible_distribution_major_version == "NA"
-
-- name: "RedHat | Set zabbix_agent_distribution_major_version to 6 when Major Version is 2018.03"
- set_fact:
- zabbix_agent_distribution_major_version: 6
- when:
- - ansible_distribution == "Amazon"
- - ansible_distribution_major_version == "2018"
-
-- name: "RedHat | Set zabbix_agent_distribution_major_version to 7 when Amazon 2"
- set_fact:
- zabbix_agent_distribution_major_version: 7
- when:
- - ansible_distribution == "Amazon"
- - ansible_distribution_major_version == "2"
-
-- name: "Fedora | Override zabbix_agent_distribution_major_version for Fedora <= 27"
- set_fact:
- zabbix_agent_distribution_major_version: 7
- when:
- - ansible_distribution == "Fedora"
- - ansible_distribution_major_version <= "27"
-
-- name: "Fedora | Override zabbix_agent_distribution_major_version for Fedora >= 27"
- set_fact:
- zabbix_agent_distribution_major_version: 8
- when:
- - ansible_distribution == "Fedora"
- - ansible_distribution_major_version >= "27"
-
-- name: "XCP-ng | Override zabbix_agent_distribution_major_version for XCP-ng"
- set_fact:
- zabbix_agent_distribution_major_version: 7
- when:
- - ansible_distribution == "XCP-ng"
-
- name: "RedHat | Install basic repo file"
- yum_repository:
+ ansible.builtin.yum_repository:
name: "{{ item.name }}"
description: "{{ item.description }}"
baseurl: "{{ item.baseurl }}"
gpgcheck: "{{ item.gpgcheck }}"
gpgkey: "{{ item.gpgkey }}"
mode: "{{ item.mode | default('0644') }}"
- priority: "{{ item.priority | default('98') }}"
+ priority: "{{ item.priority | default('99') }}"
state: "{{ item.state | default('present') }}"
proxy: "{{ zabbix_http_proxy | default(omit) }}"
with_items: "{{ zabbix_repo_yum }}"
register: yum_repo_installed
become: true
- when:
- zabbix_repo == "zabbix"
notify:
- "clean repo files from proxy creds"
tags:
- - zabbix-agent
+ - install
- name: Check if warn parameter can be used for shell module
- set_fact:
+ ansible.builtin.set_fact:
produce_warn: False
when: ansible_version.full is version("2.14", "<")
-
-- name: "Do a yum clean"
- shell: yum clean all
- args:
- warn: "{{ produce_warn | default(omit) }}"
- when: yum_repo_installed.changed
- become: true
tags:
- - skip_ansible_lint
+ - always
- name: "RedHat | Installing zabbix-agent"
- package:
+ ansible.builtin.package:
pkg:
- "{{ zabbix_agent_package }}-{{ zabbix_agent_version }}.{{ zabbix_agent_version_minor }}"
- disablerepo: "{{ '*' if (zabbix_repo_yum_enabled | length>0) else omit }}"
- enablerepo: "{{ zabbix_repo_yum_enabled if zabbix_repo_yum_enabled is iterable and (zabbix_repo_yum_enabled | length>0) else omit }}"
+ disablerepo: "{{ zabbix_agent_disable_repo | default(omit) }}"
state: "{{ zabbix_agent_package_state }}"
environment:
http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
register: zabbix_agent_package_installed
until: zabbix_agent_package_installed is succeeded
- when:
- zabbix_repo != "other"
become: true
tags:
- - init
- - zabbix-agent
-
-- name: "RedHat | Installing zabbix-agent (When zabbix_repo == other)"
- package:
- pkg:
- - "{{ zabbix_agent_package }}-{{ zabbix_agent_version }}.{{ zabbix_agent_version_minor }}"
- state: "{{ zabbix_agent_package_state }}"
- register: zabbix_agent_package_installed
- until: zabbix_agent_package_installed is succeeded
- when:
- zabbix_repo == "other"
- become: true
- tags:
- - init
- - zabbix-agent
+ - install
- name: "RedHat | Installing zabbix-{sender,get}"
- package:
+ ansible.builtin.package:
pkg:
- "{{ zabbix_sender_package }}-{{ zabbix_agent_version }}.{{ zabbix_agent_version_minor }}"
- "{{ zabbix_get_package }}-{{ zabbix_agent_version }}.{{ zabbix_agent_version_minor }}"
- disablerepo: "{{ '*' if (zabbix_repo_yum_enabled | length>0) else omit }}"
- enablerepo: "{{ zabbix_repo_yum_enabled if zabbix_repo_yum_enabled is iterable and (zabbix_repo_yum_enabled | length>0) else omit }}"
+ disablerepo: "{{ zabbix_agent_disable_repo | default(omit) }}"
state: "{{ zabbix_agent_package_state }}"
environment:
http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
@@ -135,36 +55,16 @@
register: zabbix_agent_package_installed
until: zabbix_agent_package_installed is succeeded
when:
- - zabbix_repo not in ['epel', 'other']
- - not zabbix_agent_install_agent_only
- become: true
- tags:
- - init
- - zabbix-agent
-
-- name: "RedHat | Installing zabbix-{sender,get} (When zabbix_repo == other)"
- package:
- pkg:
- - "{{ zabbix_sender_package }}-{{ zabbix_agent_version }}.{{ zabbix_agent_version_minor }}"
- - "{{ zabbix_get_package }}-{{ zabbix_agent_version }}.{{ zabbix_agent_version_minor }}"
- state: "{{ zabbix_agent_package_state }}"
- register: zabbix_agent_package_installed
- until: zabbix_agent_package_installed is succeeded
- when:
- - zabbix_repo == "other"
- not zabbix_agent_install_agent_only
become: true
tags:
- - init
- - zabbix-agent
+ - install
- name: "RedHat | Enable the service"
- service:
+ ansible.builtin.service:
name: "{{ zabbix_agent_service }}"
enabled: true
use: service
become: true
tags:
- - zabbix-agent
- - init
- service
diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Suse.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Suse.yml
deleted file mode 100644
index 82dc3ce7d..000000000
--- a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Suse.yml
+++ /dev/null
@@ -1,55 +0,0 @@
----
-# Tasks specific for OpenSuse Systems
-
-- name: "Include Zabbix gpg ids"
- include_vars: zabbix.yml
-
-- name: "Install zypper repo dependency"
- community.general.zypper:
- name:
- - python-xml
- - "{{ suse[ansible_distribution][zabbix_agent_distribution_major_version]['python_libxml2_package'] }}"
- state: present
- environment:
- http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
- https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
- become: true
- register: zabbix_agent_package_dependency
- until: zabbix_agent_package_dependency is succeeded
-
-- name: "Suse | Install basic repo file"
- community.general.zypper_repository:
- repo: "{{ suse[ansible_distribution][zabbix_agent_distribution_major_version]['url'] }}"
- name: "{{ suse[ansible_distribution][zabbix_agent_distribution_major_version]['name'] }}"
- state: present
- environment:
- http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
- https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
- when:
- - zabbix_repo == "zabbix"
- become: true
- tags:
- - zabbix-agent
- - init
-
-- name: "Only install the Zabbix Agent"
- set_fact:
- zabbix_agent_packages:
- - "{{ zabbix_agent_package }}"
- when:
- - zabbix_agent_install_agent_only
-
-- name: "Suse | Install zabbix-agent"
- community.general.zypper:
- name: "{{ zabbix_agent_packages }}"
- state: "{{ zabbix_agent_package_state }}"
- disable_gpg_check: true
- environment:
- http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
- https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
- register: zabbix_agent_package_installed
- until: zabbix_agent_package_installed is succeeded
- become: true
- tags:
- - zabbix-agent
- - init
diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Windows.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Windows.yml
index 61e12361e..9b7501d9a 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Windows.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Windows.yml
@@ -1,36 +1,44 @@
---
- name: "Windows | Set default architecture"
- set_fact:
+ ansible.builtin.set_fact:
windows_arch: 32
+ tags:
+ - always
- name: "Windows | Override architecture if 64-bit"
- set_fact:
+ ansible.builtin.set_fact:
windows_arch: 64
when:
- ansible_architecture == "64-bit"
+ tags:
+ - always
- name: "Windows | Set path to zabbix.exe"
- set_fact:
+ ansible.builtin.set_fact:
zabbix_win_exe_path: '{{ zabbix_win_install_dir }}\bin\win{{ windows_arch }}\zabbix_agentd.exe'
+ tags:
+ - always
-- name: "Windows | Set variables specific to Zabbix >= 4"
- set_fact:
+- name: "Windows | Set variables specific to Zabbix"
+ ansible.builtin.set_fact:
zabbix_win_svc_name: Zabbix Agent
zabbix_win_exe_path: '{{ zabbix_win_install_dir }}\bin\zabbix_agentd.exe'
- zabbix_win_config_name: 'zabbix_agentd.conf'
+ zabbix_win_config_name: "zabbix_agentd.conf"
zabbix2_win_svc_name: Zabbix Agent 2
zabbix2_win_exe_path: '{{ zabbix_win_install_dir }}\bin\zabbix_agent2.exe'
- zabbix2_win_config_name: 'zabbix_agent2.conf'
- when:
- - zabbix_version_long is version('4.0.0', '>=')
+ zabbix2_win_config_name: "zabbix_agent2.conf"
+ tags:
+ - always
- name: "Windows | Check if Zabbix agent is present"
ansible.windows.win_stat:
- path: '{{ item }}'
+ path: "{{ item }}"
with_items:
- "{{ zabbix_win_exe_path }}"
- "{{ zabbix2_win_exe_path }}"
register: agent_file_info
+ tags:
+ - always
- name: "Windows | Get Installed Zabbix Agent Version"
community.windows.win_file_version:
@@ -39,9 +47,11 @@
when:
- item.stat.exists | bool
with_items: "{{ agent_file_info.results }}"
+ tags:
+ - always
- name: "Windows | Set facts current zabbix agent installation"
- set_fact:
+ ansible.builtin.set_fact:
zabbix_agent_1_binary_exist: true
zabbix_agent_1_version: zabbix_win_exe_info.results[0].win_file_version.product_version
when:
@@ -49,9 +59,11 @@
- zabbix_win_exe_info.results[0].item.stat.exists
- zabbix_win_exe_info.results[0].item.stat.path == zabbix_win_exe_path
- zabbix_win_exe_info.results[0].win_file_version.product_version
+ tags:
+ - always
- name: "Windows | Set facts current zabbix agent installation (agent 2)"
- set_fact:
+ ansible.builtin.set_fact:
zabbix_agent_2_binary_exist: true
zabbix_agent_2_version: zabbix_win_exe_info.results[1].win_file_version.product_version
when:
@@ -59,6 +71,8 @@
- zabbix_win_exe_info.results[1].item.stat.exists
- zabbix_win_exe_info.results[1].item.stat.path == zabbix2_win_exe_path
- zabbix_win_exe_info.results[1].win_file_version.product_version
+ tags:
+ - always
- name: "Windows | Check Zabbix service"
ansible.windows.win_service:
@@ -66,25 +80,31 @@
register: zabbix_service_info
when: item.item.stat.exists
with_items: "{{ zabbix_win_exe_info.results }}"
+ tags:
+ - always
- name: "Windows | Set facts about current zabbix agent service state"
- set_fact:
+ ansible.builtin.set_fact:
zabbix_agent_1_service_exist: true
when:
- zabbix_service_info.results[0].exists is defined
- zabbix_service_info.results[0].exists
- zabbix_service_info.results[0].display_name == zabbix_win_svc_name
+ tags:
+ - always
- name: "Windows | Set facts about current zabbix agent service state (agent 2)"
- set_fact:
+ ansible.builtin.set_fact:
zabbix_agent_2_service_exist: true
when:
- zabbix_service_info.results[1].exists is defined
- zabbix_service_info.results[1].exists
- zabbix_service_info.results[1].display_name == zabbix2_win_svc_name
+ tags:
+ - always
- name: "Windows | Set fact about version change requirement"
- set_fact:
+ ansible.builtin.set_fact:
zabbix_agent_version_change: true
when: >
(zabbix_agent_1_binary_exist | default(false) and
@@ -94,6 +114,8 @@
zabbix_win_exe_info.results[1].win_file_version.product_version is version(zabbix_version_long, '<>'))
or (zabbix_agent_1_binary_exist | default(false) and zabbix_agent2)
or (zabbix_agent_2_binary_exist | default(false) and not zabbix_agent2)
+ tags:
+ - always
##################
# delete section #
@@ -131,10 +153,11 @@
- name: "Windows | Removing Zabbix Directory"
ansible.windows.win_file:
- path: '{{ zabbix_win_install_dir }}'
+ path: "{{ zabbix_win_install_dir }}"
state: absent
- when: ((zabbix_agent_version_change | default(false) or zabbix_agent2) and zabbix_agent_1_binary_exist | default(false)) or
- ((zabbix_agent_version_change | default(false) or not zabbix_agent2) and zabbix_agent_2_binary_exist | default(false))
+ when:
+ ((zabbix_agent_version_change | default(false) or zabbix_agent2) and zabbix_agent_1_binary_exist | default(false)) or
+ ((zabbix_agent_version_change | default(false) or not zabbix_agent2) and zabbix_agent_2_binary_exist | default(false))
###################
# install section #
@@ -146,6 +169,8 @@
state: directory
with_items:
- "{{ zabbix_win_install_dir }}"
+ tags:
+ - install
- name: "Windows | Create directory structure, includes"
ansible.windows.win_file:
@@ -155,25 +180,33 @@
- "{{ zabbix_agent_win_include }}"
when:
- ('.conf' not in zabbix_agent_win_include)
+ tags:
+ - install
- name: "Windows | Set installation settings (agent 2)"
- set_fact:
+ ansible.builtin.set_fact:
zabbix_win_package: "{{ zabbix2_win_package }}"
zabbix_win_download_link: "{{ zabbix2_win_download_link }}"
zabbix_win_exe_path: "{{ zabbix2_win_exe_path }}"
zabbix_win_config_name: "{{ zabbix2_win_config_name }}"
zabbix_win_svc_name: "{{ zabbix2_win_svc_name }}"
when: zabbix_agent2 | bool
+ tags:
+ - install
- name: "Windows | Check if agent file is already downloaded"
ansible.windows.win_stat:
path: '{{ zabbix_win_install_dir }}\{{ zabbix_win_package }}'
register: file_info
+ tags:
+ - install
- name: "Windows | Check if agent binaries in place"
ansible.windows.win_stat:
path: "{{ zabbix_win_exe_path }}"
register: zabbix_windows_binaries
+ tags:
+ - install
- name: "Windows | Download Zabbix Agent Zip file"
ansible.windows.win_get_url:
@@ -192,12 +225,16 @@
register: zabbix_agent_win_download_zip
until: zabbix_agent_win_download_zip is succeeded
throttle: "{{ zabbix_download_throttle | default(5) | int }}"
+ tags:
+ - install
- name: "Windows | Unzip file"
community.windows.win_unzip:
src: '{{ zabbix_win_install_dir }}\{{ zabbix_win_package }}'
dest: "{{ zabbix_win_install_dir }}"
creates: "{{ zabbix_win_exe_path }}"
+ tags:
+ - install
- name: "Windows | Cleanup downloaded Zabbix Agent Zip file"
ansible.windows.win_file:
@@ -205,6 +242,8 @@
state: absent
when:
- zabbix_agent_win_download_zip.changed
+ tags:
+ - install
- name: "Windows | Copy binary files to expected location"
ansible.windows.win_copy:
@@ -217,6 +256,8 @@
when:
- zabbix_win_install_dir_bin is defined
- not (zabbix_agent2 | bool)
+ tags:
+ - install
- name: "Windows | Copy binary files to expected location (zabbix-agent2)"
ansible.windows.win_copy:
@@ -228,39 +269,49 @@
when:
- zabbix_win_install_dir_bin is defined
- zabbix_agent2 | bool
+ tags:
+ - install
- set_fact:
zabbix_win_exe_path: "{{ zabbix_win_install_dir_bin }}\\zabbix_agentd.exe"
when:
- zabbix_win_install_dir_bin is defined
- not (zabbix_agent2 | bool)
+ tags:
+ - install
- set_fact:
zabbix_win_exe_path: "{{ zabbix_win_install_dir_bin }}\\zabbix_agent2.exe"
when:
- zabbix_win_install_dir_bin is defined
- zabbix_agent2 | bool
+ tags:
+ - install
- name: "Create directory for PSK file if not exist."
- win_file:
+ ansible.windows.win_file:
path: "{{ zabbix_agent_tlspskfile | win_dirname }}"
state: directory
when:
- zabbix_agent_tlspskfile is defined
- zabbix_agent_tlspskfile
- not (zabbix_agent2 | bool)
+ tags:
+ - config
- name: "Create directory for PSK file if not exist (zabbix-agent2)"
- win_file:
+ ansible.windows.win_file:
path: "{{ zabbix_agent2_tlspskfile | win_dirname }}"
state: directory
when:
- zabbix_agent2_tlspskfile is defined
- zabbix_agent2_tlspskfile
- zabbix_agent2 | bool
+ tags:
+ - config
- name: "Place TLS PSK File"
- win_copy:
+ ansible.windows.win_copy:
dest: "{{ zabbix_agent_tlspskfile }}"
content: "{{ zabbix_agent_tlspsk_secret }}"
when:
@@ -270,9 +321,11 @@
- not (zabbix_agent2 | bool)
notify:
- restart win zabbix agent
+ tags:
+ - config
- name: "Place TLS PSK File (zabbix-agent2)"
- win_copy:
+ ansible.windows.win_copy:
dest: "{{ zabbix_agent2_tlspskfile }}"
content: "{{ zabbix_agent2_tlspsk_secret }}"
when:
@@ -282,25 +335,18 @@
- zabbix_agent2 | bool
notify:
- restart win zabbix agent
+ tags:
+ - config
- name: "Windows | Check if windows service exist"
ansible.windows.win_service:
name: "{{ zabbix_win_svc_name }}"
register: zabbix_windows_service
+ tags:
+ - service
- name: "Windows | Register Service"
ansible.windows.win_command: '"{{ zabbix_win_exe_path }}" --config "{{ zabbix_win_install_dir_conf }}\{{ zabbix_win_config_name }}" --install'
when: not zabbix_windows_service.exists
-
-- name: "Windows | Set service startup mode to auto, ensure it is started and set auto-recovery"
- ansible.windows.win_service:
- name: "{{ zabbix_win_svc_name }}"
- start_mode: auto
- failure_actions:
- - type: restart
- delay_ms: 5000
- - type: restart
- delay_ms: 10000
- - type: restart
- delay_ms: 20000
- failure_reset_period_sec: 86400
+ tags:
+ - service
diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Windows_conf.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Windows_conf.yml
index f6c5c331e..72dee230f 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Windows_conf.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/Windows_conf.yml
@@ -1,17 +1,20 @@
---
-
- name: "Set default ip address for zabbix_agent_ip"
- set_fact:
+ ansible.builtin.set_fact:
zabbix_agent_ip: "{{ hostvars[inventory_hostname]['ansible_ip_addresses'] | ansible.utils.ipv4 | first }}"
when:
- zabbix_agent_ip is not defined
- "'ansible_ip_addresses' in hostvars[inventory_hostname]"
+ tags:
+ - config
- name: "Windows | Configure zabbix-agent"
ansible.windows.win_template:
src: "{{ zabbix_win_config_name }}.j2"
dest: "{{ zabbix_win_install_dir_conf }}\\{{ zabbix_win_config_name }}"
notify: restart win zabbix agent
+ tags:
+ - config
- name: "Windows | Set service startup mode to auto, ensure it is started and set auto-recovery"
ansible.windows.win_service:
@@ -19,19 +22,23 @@
start_mode: auto
state: started
failure_actions:
- - type: restart
- delay_ms: 5000
- - type: restart
- delay_ms: 10000
- - type: restart
- delay_ms: 20000
+ - type: restart
+ delay_ms: 5000
+ - type: restart
+ delay_ms: 10000
+ - type: restart
+ delay_ms: 20000
failure_reset_period_sec: 86400
+ tags:
+ - config
- name: "Windows | Check firewall service"
ansible.windows.win_service_info:
name: MpsSvc
register: firewall_info
when: zabbix_win_firewall_management
+ tags:
+ - config
- name: "Windows | Firewall rule"
community.windows.win_firewall_rule:
@@ -45,3 +52,5 @@
when:
- zabbix_win_firewall_management
- firewall_info.services[0].state == 'started' or firewall_info.services[0].start_mode == 'auto'
+ tags:
+ - config
diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/api.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/api.yml
index 13f734edc..4de342645 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/api.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/api.yml
@@ -3,14 +3,11 @@
community.zabbix.zabbix_group:
host_group: "{{ zabbix_host_groups }}"
state: "{{ zabbix_agent_hostgroups_state }}"
- validate_certs: "{{ zabbix_api_validate_certs|default(omit) }}"
- timeout: "{{ zabbix_api_timeout }}"
when:
- zabbix_api_create_hostgroup | bool
register: zabbix_api_hostgroup_created
until: zabbix_api_hostgroup_created is succeeded
delegate_to: "{{ zabbix_api_server_host }}"
- become: false
tags:
- api
@@ -32,8 +29,6 @@
tls_subject: "{{ zabbix_agent_tls_subject | default(omit) }}"
tls_accept: "{{ zabbix_agent_tls_config[zabbix_agent_tlsaccept if zabbix_agent_tlsaccept else 'unencrypted'] }}"
tls_connect: "{{ zabbix_agent_tls_config[zabbix_agent_tlsconnect if zabbix_agent_tlsconnect else 'unencrypted'] }}"
- validate_certs: "{{ zabbix_api_validate_certs | default(omit) }}"
- timeout: "{{ zabbix_api_timeout }}"
description: "{{ zabbix_agent_description | default(omit) }}"
inventory_zabbix: "{{ zabbix_agent_inventory_zabbix | default({}) }}"
ipmi_authtype: "{{ zabbix_agent_ipmi_authtype | default(omit) }}"
@@ -46,7 +41,6 @@
register: zabbix_api_host_created
until: zabbix_api_host_created is succeeded
delegate_to: "{{ zabbix_api_server_host }}"
- become: false
changed_when: false
tags:
- api
@@ -69,8 +63,6 @@
tls_subject: "{{ zabbix_agent2_tls_subject | default(omit) }}"
tls_accept: "{{ zabbix_agent_tls_config[zabbix_agent2_tlsaccept if zabbix_agent2_tlsaccept else 'unencrypted'] }}"
tls_connect: "{{ zabbix_agent_tls_config[zabbix_agent2_tlsconnect if zabbix_agent2_tlsconnect else 'unencrypted'] }}"
- validate_certs: "{{ zabbix_api_validate_certs | default(omit) }}"
- timeout: "{{ zabbix_api_timeout }}"
description: "{{ zabbix_agent_description | default(omit) }}"
inventory_zabbix: "{{ zabbix_agent_inventory_zabbix | default({}) }}"
ipmi_authtype: "{{ zabbix_agent_ipmi_authtype | default(omit) }}"
@@ -83,7 +75,6 @@
register: zabbix_api_host_created
until: zabbix_api_host_created is succeeded
delegate_to: "{{ zabbix_api_server_host }}"
- become: false
changed_when: false
tags:
- api
@@ -94,8 +85,6 @@
macro_name: "{{ item.macro_key }}"
macro_value: "{{ item.macro_value }}"
macro_type: "{{ item.macro_type|default('text') }}"
- validate_certs: "{{ zabbix_api_validate_certs | default(omit) }}"
- timeout: "{{ zabbix_api_timeout }}"
with_items: "{{ zabbix_agent_macros | default([]) }}"
when:
- zabbix_agent_macros is defined
@@ -103,6 +92,5 @@
register: zabbix_api_hostmarcro_created
until: zabbix_api_hostmarcro_created is succeeded
delegate_to: "{{ zabbix_api_server_host }}"
- become: false
tags:
- api
diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/firewall.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/firewall.yml
deleted file mode 100644
index 24ba96cb0..000000000
--- a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/firewall.yml
+++ /dev/null
@@ -1,55 +0,0 @@
----
-
-- name: "Firewall | Configure IPTables (zabbix_agent_listenport)"
- iptables:
- action: "{{ zabbix_agent_firewall_action }}"
- destination_port: "{{ zabbix_agent_listenport | string }}"
- source: "{{ zabbix_agent_firewall_source | default(omit) }}"
- protocol: tcp
- chain: "{{ zabbix_agent_firewall_chain }}"
- jump: ACCEPT
- become: true
- when:
- - zabbix_agent_firewall_enable | bool
-
-- name: "Firewall | Configure IPTables (zabbix_agent_jmx_listenport)"
- iptables:
- action: "{{ zabbix_agent_firewall_action }}"
- destination_port: "{{ zabbix_agent_listenport | string }}"
- source: "{{ zabbix_agent_firewall_source | default(omit) }}"
- protocol: tcp
- chain: "{{ zabbix_agent_firewall_chain }}"
- jump: ACCEPT
- become: true
- when:
- - zabbix_agent_firewall_enable | bool
- - zabbix_agent_jmx_listenport | bool
-
-- name: "Firewall | Configure firewalld (zabbix_agent_listenport)"
- ansible.posix.firewalld:
- rich_rule: 'rule family="ipv4" source address="{{ zabbix_agent_firewalld_source }}" port protocol="tcp" port="{{ zabbix_agent_listenport }}" accept'
- zone: "{{ zabbix_agent_firewalld_zone }}"
- permanent: true
- immediate: true
- state: enabled
- become: true
- when:
- - zabbix_agent_firewalld_enable | bool
- notify:
- - firewalld-reload
- tags: zabbix_agent_firewalld_enable
-
-- name: "Firewall | Configure firewalld (zabbix_agent_jmx_listenport)"
- ansible.posix.firewalld:
- rich_rule: 'rule family="ipv4" source address="{{ zabbix_agent_firewalld_source }}" port protocol="tcp" port="{{ zabbix_agent_jmx_listenport }}" accept'
- zone: "{{ zabbix_agent_firewalld_zone }}"
- permanent: true
- immediate: true
- state: enabled
- become: true
- when:
- - zabbix_agent_firewalld_enable | bool
- - zabbix_agent_jmx_listenport | bool
- notify:
- - firewalld-reload
- tags: zabbix_agent_firewalld_enable
diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/macOS.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/macOS.yml
index 0904c39f1..7bcdd6fe3 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/macOS.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/macOS.yml
@@ -1,7 +1,7 @@
---
# Tasks specific for macOS
- name: "macOS | Check installed package version"
- shell: |
+ ansible.builtin.shell: |
set -o pipefail
pkgutil --pkg-info 'com.zabbix.pkg.ZabbixAgent' | grep 'version:' | cut -d ' ' -f 2
register: pkgutil_version
@@ -10,15 +10,13 @@
failed_when: pkgutil_version.rc == 2
- name: "macOS | Download the Zabbix package"
- get_url:
+ ansible.builtin.get_url:
url: "{{ zabbix_mac_download_link }}"
dest: "/tmp/{{ zabbix_mac_package }}"
mode: 0644
when: pkgutil_version.stdout != zabbix_version_long
- name: "macOS | Install the Zabbix package"
- command: installer -pkg "/tmp/{{ zabbix_mac_package }}" -target /
+ ansible.builtin.command: installer -pkg "/tmp/{{ zabbix_mac_package }}" -target /
become: true
when: pkgutil_version.stdout != zabbix_version_long
- tags:
- - zabbix-agent
diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/main.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/main.yml
index 5ce427ce4..f5f87d18f 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/main.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/main.yml
@@ -1,90 +1,52 @@
---
# tasks file for zabbix_agent
-
-- name: "Set variables specific for Zabbix Agent 2"
- set_fact:
- zabbix_agent_service: zabbix-agent2
- zabbix_agent_package: zabbix-agent2
- when:
- - zabbix_agent2 is defined
- - zabbix_agent2
+- name: "Include OS-specific variables"
+ ansible.builtin.include_vars: "{{ ansible_os_family }}.yml"
tags:
- always
-- name: "Fix facts for linuxmint - distribution release"
- set_fact:
- zabbix_agent_distribution_release: xenial
- when:
- - ansible_os_family == "Linuxmint"
- - ansible_distribution_release == "sonya" or ansible_distribution_release == "serena"
+- name: Determine Latest Supported Zabbix Version
+ ansible.builtin.set_fact:
+ zabbix_agent_version: "{{ zabbix_valid_agent_versions[ansible_distribution_major_version][0] | default(6.4) }}"
+ when: zabbix_agent_version is not defined or zabbix_agent_version is none
tags:
- always
-- name: "Fix facts for linuxmint - family"
- set_fact:
- zabbix_agent_os_family: Debian
- when:
- - ansible_os_family == "Linuxmint"
+- name: Set More Variables
+ ansible.builtin.set_fact:
+ zabbix_valid_version: "{{ zabbix_agent_version|float in zabbix_valid_agent_versions[ansible_distribution_major_version] }}"
tags:
- always
-- name: "Fix facts for XCP-ng - family"
- set_fact:
- zabbix_agent_os_family: RedHat
- when:
- - ansible_os_family == "XCP-ng"
-
-- name: "Include OS-specific variables"
- include_vars: "{{ zabbix_agent_os_family }}.yml"
+- name: Stopping Install of Invalid Version
+ ansible.builtin.fail:
+ msg: Zabbix version {{ zabbix_agent_version }} is not supported on {{ ansible_distribution }} {{ ansible_distribution_major_version }}
+ when: not zabbix_valid_version
tags:
- always
-- name: Determine Latest Supported Zabbix Version
- set_fact:
- zabbix_agent_version: "{{ zabbix_valid_agent_versions[ansible_distribution_major_version][0] | default(6.0) }}"
- when: zabbix_agent_version is not defined
+- name: Setting Zabbix API Server Port
+ ansible.builtin.set_fact:
+ zabbix_api_server_port: "{{ '443' if zabbix_api_use_ssl|bool else '80' }}"
+ when: zabbix_api_server_port is undefined
-- name: "Reset zabbix_agent_version for Ubuntu 22.04 to 6.0"
- # README https://support.zabbix.com/browse/ZBXNEXT-7624
- set_fact:
- zabbix_version: 6.0
- zabbix_agent_version: 6.0
- when:
- - ansible_distribution_release is defined
- - ansible_distribution_release == "jammy"
- - ( zabbix_agent_version is version ('6.0','lt') or
- zabbix_version is version ('6.0','lt') )
-
-- name: "Install the correct repository"
- include_tasks: "{{ zabbix_agent_os_family if (zabbix_agent_os_family not in ['Sangoma']) else 'RedHat' }}.yml"
+- name: "Set variables specific for Zabbix Agent 2"
+ ansible.builtin.set_fact:
+ zabbix_agent_service: zabbix-agent2
+ zabbix_agent_package: zabbix-agent2
when:
- - not (zabbix_agent_docker | bool)
+ - zabbix_agent2 is defined
+ - zabbix_agent2
tags:
- always
-- name: "Set the 'ansible_python_interpreter' to the one we use for running this playbook."
- set_fact:
- ansible_python_interpreter: "{{ ansible_playbook_python }}"
- delegate_to: localhost
- delegate_facts: true
- when:
- - (zabbix_install_pip_packages | bool) or (zabbix_api_create_hostgroup | bool) or (zabbix_api_create_hosts | bool)
-
-- name: "Install local python-netaddr package"
- pip:
- name: netaddr
- state: present
- register: zabbix_python_netaddr_package_installed
- until: zabbix_python_netaddr_package_installed is succeeded
- delegate_to: localhost
- run_once: true
- become: "{{ zabbix_agent_become_on_localhost }}"
+- name: "Install the correct repository"
+ ansible.builtin.include_tasks: "{{ ansible_os_family }}.yml"
when:
- - zabbix_install_pip_packages | bool
- - ansible_all_ipv4_addresses is defined or (zabbix_agent_ip is not defined and total_private_ip_addresses is defined)
+ - not (zabbix_agent_docker | bool)
- name: "Encrypt with TLS PSK auto management"
- include_tasks: tlspsk_auto.yml
+ ansible.builtin.include_tasks: tlspsk_auto.yml
when:
- not zabbix_agent2
- zabbix_agent_tlspsk_auto | bool
@@ -92,7 +54,7 @@
- (zabbix_agent_tlspsk_secret is undefined) or (zabbix_agent_tlspsk_secret | length == '0')
- name: "Encrypt with TLS PSK auto management"
- include_tasks: tlspsk_auto_agent2.yml
+ ansible.builtin.include_tasks: tlspsk_auto_agent2.yml
when:
- zabbix_agent2 | bool
- zabbix_agent2_tlspsk_auto | bool
@@ -100,44 +62,33 @@
- (zabbix_agent2_tlspsk_secret is undefined) or (zabbix_agent2_tlspsk_secret | length == '0')
- name: "Configure Agent"
- include_tasks: Windows_conf.yml
+ ansible.builtin.include_tasks: Windows_conf.yml
when:
- - zabbix_agent_os_family == "Windows"
- tags:
- - always
+ - ansible_os_family == "Windows"
- name: "Configure Agent"
- include_tasks: Darwin.yml
+ ansible.builtin.include_tasks: Linux.yml
when:
- - zabbix_agent_os_family == "Darwin"
- tags:
- - always
-
-- name: "Configure Agent"
- include_tasks: Linux.yml
- when:
- - (zabbix_agent_os_family != "Windows" and zabbix_agent_os_family != "Darwin") or (zabbix_agent_docker | bool)
- tags:
- - always
+ - (ansible_os_family != "Windows" and ansible_os_family != "Darwin") or (zabbix_agent_docker | bool)
- name: "Run the API calls to Zabbix Server"
vars:
gather_facts: false
ansible_user: "{{ zabbix_api_login_user }}"
+ ansible_httpapi_use_ssl: "{{ zabbix_api_use_ssl }}"
ansible_network_os: community.zabbix.zabbix
ansible_connection: httpapi
# Can't think of a way to make http_login_* vars be undefined -(
- http_login_user: "{{ zabbix_api_http_user | default(zabbix_http_user | default(-42)) }}"
- http_login_password: "{{ zabbix_api_http_password | default(zabbix_http_password | default(-42)) }}"
- include_tasks: api.yml
+ http_login_user: "{{ zabbix_api_http_user | default(-42) }}"
+ http_login_password: "{{ zabbix_api_http_password | default(-42) }}"
+ ansible.builtin.include_tasks: api.yml
when:
- (zabbix_api_create_hostgroup | bool) or (zabbix_api_create_hosts | bool)
tags:
- api
- name: "Including userparameters"
- include_tasks: "userparameter.yml"
+ ansible.builtin.include_tasks: "userparameter.yml"
when: zabbix_agent_userparameters|length > 0
tags:
- - zabbix-agent
- - userparameter
+ - config
diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/remove.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/remove.yml
index 57968146c..181329a32 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/remove.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/remove.yml
@@ -1,9 +1,9 @@
---
- name: Pull service facts
- service_facts:
+ ansible.builtin.service_facts:
-- name: "Remove | Make sure the \"old\" zabbix-agent service stopped"
- service:
+- name: 'Remove | Make sure the "old" zabbix-agent service stopped'
+ ansible.builtin.service:
name: "zabbix-agent"
state: stopped
enabled: false
@@ -13,13 +13,13 @@
ansible_facts.services["zabbix-agent"] is defined
- name: "Remove | Package removal"
- package:
+ ansible.builtin.package:
name: "zabbix-agent"
state: absent
become: true
- name: "Remove | Remove the agent-include-dir"
- file:
+ ansible.builtin.file:
path: "{{ zabbix_agent_include }}"
state: absent
become: true
diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/selinux.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/selinux.yml
index b7ec69e7b..2b11d1a47 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/selinux.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/selinux.yml
@@ -1,7 +1,6 @@
---
-
- name: "SELinux | Debian | Install policycoreutils-python"
- apt:
+ ansible.builtin.apt:
pkg: policycoreutils-python-utils
state: present
update_cache: true
@@ -15,10 +14,12 @@
until: zabbix_agent_package_installed is succeeded
become: true
when:
- - zabbix_agent_os_family == "Debian"
+ - ansible_os_family == "Debian"
+ tags:
+ - install
- name: "SELinux | RedHat | Install policycoreutils-python"
- package:
+ ansible.builtin.package:
name: policycoreutils-python
state: installed
environment:
@@ -27,15 +28,14 @@
register: zabbix_agent_policycoreutils_installed
until: zabbix_agent_policycoreutils_installed is succeeded
when:
- - zabbix_agent_os_family == "RedHat"
+ - ansible_os_family == "RedHat"
- (zabbix_agent_distribution_major_version == "6" or zabbix_agent_distribution_major_version == "7")
become: true
tags:
- - init
- - zabbix-agent
+ - install
- name: "SELinux | RedHat | Install python3-policycoreutils on RHEL8"
- package:
+ ansible.builtin.package:
name: python3-policycoreutils
state: installed
environment:
@@ -44,59 +44,67 @@
register: zabbix_agent_policycoreutils_installed
until: zabbix_agent_policycoreutils_installed is succeeded
when:
- - zabbix_agent_os_family == "RedHat"
+ - ansible_os_family == "RedHat"
- ansible_distribution_major_version == "8"
become: true
tags:
- - init
- - zabbix-agent
+ - install
- name: "SELinux | RedHat | Install selinux-policy-targeted"
- package:
+ ansible.builtin.package:
name: selinux-policy-targeted
state: installed
register: zabbix_agent_selinuxpolicytargeted_installed
until: zabbix_agent_selinuxpolicytargeted_installed is succeeded
when:
- - zabbix_agent_os_family == "RedHat"
+ - ansible_os_family == "RedHat"
become: true
tags:
- - init
- - zabbix-agent
+ - install
# straight to getenforce binary , workaround for missing python_selinux library
- name: "SELinux | Get getenforce binary"
- stat:
+ ansible.builtin.stat:
path: /usr/sbin/getenforce
register: getenforce_bin
become: true
+ tags:
+ - always
- name: "SELinux | Collect getenforce output"
- command: /usr/sbin/getenforce
+ ansible.builtin.command: /usr/sbin/getenforce
register: sestatus
- when: 'getenforce_bin.stat.exists'
+ when: "getenforce_bin.stat.exists"
changed_when: false
become: true
check_mode: false
+ tags:
+ - always
- name: "SELinux | Set zabbix_selinux to true if getenforce returns Enforcing or Permissive"
- set_fact:
+ ansible.builtin.set_fact:
zabbix_selinux: "{{ true }}"
when:
- 'getenforce_bin.stat.exists and ("Enforcing" in sestatus.stdout or "Permissive" in sestatus.stdout)'
+ tags:
+ - always
- name: "SELinux | Allow zabbix_agent to start (SELinux)"
community.general.selinux_permissive:
name: zabbix_agent_t
permissive: true
become: true
+ tags:
+ - config
- name: "SELinux | Allow zabbix to run sudo commands (SELinux)"
ansible.posix.seboolean:
name: zabbix_run_sudo
persistent: true
state: true
+ become: true
when:
- ansible_selinux.status == "enabled"
- selinux_allow_zabbix_run_sudo|bool
- tags: selinux
+ tags:
+ - config
diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto.yml
index aaa733872..ad7d49aa3 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto.yml
@@ -1,12 +1,14 @@
---
-- include_tasks: tlspsk_auto_linux.yml
- when: (zabbix_agent_os_family != "Windows") or (zabbix_agent_docker | bool)
+- ansible.builtin.include_tasks: tlspsk_auto_linux.yml
+ when: (ansible_os_family != "Windows") or (zabbix_agent_docker | bool)
-- include_tasks: tlspsk_auto_windows.yml
- when: zabbix_agent_os_family == "Windows"
+- ansible.builtin.include_tasks: tlspsk_auto_windows.yml
+ when: ansible_os_family == "Windows"
- name: AutoPSK | Default tlsaccept and tlsconnect to enforce PSK
- set_fact:
+ ansible.builtin.set_fact:
zabbix_agent_tlsaccept: psk
zabbix_agent_tlsconnect: psk
when: zabbix_api_create_hosts
+ tags:
+ - config
diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_agent2.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_agent2.yml
index 77eafc878..6e5f8dc4d 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_agent2.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_agent2.yml
@@ -1,12 +1,14 @@
---
- include_tasks: tlspsk_auto_agent2_linux.yml
- when: (zabbix_agent_os_family != "Windows") or (zabbix_agent_docker | bool)
+ when: (ansible_os_family != "Windows") or (zabbix_agent_docker | bool)
- include_tasks: tlspsk_auto_agent2_windows.yml
- when: zabbix_agent_os_family == "Windows"
+ when: ansible_os_family == "Windows"
- name: AutoPSK | Default tlsaccept and tlsconnect to enforce PSK
- set_fact:
+ ansible.builtin.set_fact:
zabbix_agent2_tlsaccept: psk
zabbix_agent2_tlsconnect: psk
when: zabbix_api_create_hosts
+ tags:
+ - config
diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_agent2_common.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_agent2_common.yml
index 4a7b897ae..3f6e0d2cd 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_agent2_common.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_agent2_common.yml
@@ -1,38 +1,45 @@
---
-# Process PSK Secret
+# Process PSK Secret
- name: AutoPSK | Save existing TLS PSK secret
- set_fact:
+ ansible.builtin.set_fact:
zabbix_agent2_tlspsk_read: "{{ zabbix_agent2_tlspsk_base64['content'] | b64decode | trim }}"
when: zabbix_agent2_tlspskcheck.stat.exists
no_log: "{{ ansible_verbosity < 3 }}"
+ tags:
+ - config
- name: AutoPSK | Use existing TLS PSK secret
- set_fact:
+ ansible.builtin.set_fact:
zabbix_agent2_tlspsk_secret: "{{ zabbix_agent2_tlspsk_read }}"
- when:
- - zabbix_agent2_tlspskcheck.stat.exists
+ when:
+ - zabbix_agent2_tlspskcheck.stat.exists
- zabbix_agent2_tlspsk_read|length >= 32
no_log: "{{ ansible_verbosity < 3 }}"
+ tags:
+ - config
- name: AutoPSK | Generate new TLS PSK secret
- set_fact:
+ ansible.builtin.set_fact:
zabbix_agent2_tlspsk_secret: "{{ lookup('password', '/dev/null chars=hexdigits length=64') }}"
when:
- not zabbix_agent2_tlspskcheck.stat.exists
- (zabbix_agent2_tlspsk_read is not defined) or (zabbix_agent2_tlspsk_read|length < 32)
no_log: "{{ ansible_verbosity < 3 }}"
-
+ tags:
+ - config
# Process PSK Identity
- name: AutoPSK | Use existing TLS PSK identity
- set_fact:
+ ansible.builtin.set_fact:
zabbix_agent2_tlspskidentity: "{{ zabbix_agent2_tlspskidentity_base64['content'] | b64decode | trim }}"
- when:
+ when:
- zabbix_agent2_tlspskidentity_check.stat.exists
no_log: "{{ ansible_verbosity < 3 }}"
+ tags:
+ - config
- name: AutoPSK | Generate new TLS PSK identity
- set_fact:
+ ansible.builtin.set_fact:
zabbix_agent2_tlspskidentity: >-
{{
zabbix_agent_visible_hostname
@@ -42,3 +49,5 @@
}}
when: not zabbix_agent2_tlspskidentity_check.stat.exists
no_log: "{{ ansible_verbosity < 3 }}"
+ tags:
+ - config
diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_agent2_linux.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_agent2_linux.yml
index 721f1cb86..aaff36128 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_agent2_linux.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_agent2_linux.yml
@@ -1,42 +1,52 @@
---
- name: AutoPSK | Set default path variables (Linux)
- set_fact:
+ ansible.builtin.set_fact:
zabbix_agent2_tlspskfile: "/etc/zabbix/tls_psk_auto.secret"
zabbix_agent2_tlspskidentity_file: "/etc/zabbix/tls_psk_auto.identity"
+ tags:
+ - config
- name: AutoPSK | Check for existing TLS PSK file (Linux)
- stat:
+ ansible.builtin.stat:
path: "{{ zabbix_agent2_tlspskfile }}"
register: zabbix_agent2_tlspskcheck
become: true
+ tags:
+ - config
- name: AutoPSK | Check for existing TLS PSK identity (Linux)
- stat:
+ ansible.builtin.stat:
path: "{{ zabbix_agent2_tlspskidentity_file }}"
register: zabbix_agent2_tlspskidentity_check
become: true
+ tags:
+ - config
- name: AutoPSK | read existing TLS PSK file (Linux)
- slurp:
+ ansible.builtin.slurp:
src: "{{ zabbix_agent2_tlspskfile }}"
register: zabbix_agent2_tlspsk_base64
become: true
- when:
+ when:
- zabbix_agent2_tlspskcheck.stat.exists
no_log: "{{ ansible_verbosity < 3 }}"
+ tags:
+ - config
- name: AutoPSK | Read existing TLS PSK identity file (Linux)
- slurp:
+ ansible.builtin.slurp:
src: "{{ zabbix_agent2_tlspskidentity_file }}"
register: zabbix_agent2_tlspskidentity_base64
become: true
when: zabbix_agent2_tlspskidentity_check.stat.exists
no_log: "{{ ansible_verbosity < 3 }}"
+ tags:
+ - config
- include_tasks: tlspsk_auto_agent2_common.yml
- name: AutoPSK | Template TLS PSK identity in file (Linux)
- copy:
+ ansible.builtin.copy:
dest: "{{ zabbix_agent2_tlspskidentity_file }}"
content: "{{ zabbix_agent2_tlspskidentity }}"
owner: zabbix
@@ -49,9 +59,11 @@
notify:
- restart zabbix-agent
- restart mac zabbix agent
-
+ tags:
+ - config
+
- name: AutoPSK | Template TLS PSK secret in file (Linux)
- copy:
+ ansible.builtin.copy:
dest: "{{ zabbix_agent2_tlspskfile }}"
content: "{{ zabbix_agent2_tlspsk_secret }}"
owner: zabbix
@@ -64,3 +76,5 @@
notify:
- restart zabbix-agent
- restart mac zabbix agent
+ tags:
+ - config
diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_agent2_windows.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_agent2_windows.yml
index 770d60776..3e1529e6b 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_agent2_windows.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_agent2_windows.yml
@@ -1,38 +1,48 @@
---
- name: AutoPSK | Set default path variables for Windows
- set_fact:
+ ansible.builtin.set_fact:
zabbix_agent2_tlspskfile: "{{ zabbix_win_install_dir }}\\tls_psk_auto.secret.txt"
zabbix_agent2_tlspskidentity_file: "{{ zabbix_win_install_dir }}\\tls_psk_auto.identity.txt"
+ tags:
+ - config
- name: AutoPSK | Check for existing TLS PSK file (Windows)
ansible.windows.win_stat:
path: "{{ zabbix_agent2_tlspskfile }}"
register: zabbix_agent2_tlspskcheck
+ tags:
+ - config
- name: AutoPSK | Check for existing TLS PSK identity (Windows)
ansible.windows.win_stat:
path: "{{ zabbix_agent2_tlspskidentity_file }}"
register: zabbix_agent2_tlspskidentity_check
+ tags:
+ - config
- name: AutoPSK | read existing TLS PSK file (Windows)
- slurp:
+ ansible.builtin.slurp:
src: "{{ zabbix_agent2_tlspskfile }}"
register: zabbix_agent2_tlspsk_base64
- when:
+ when:
- zabbix_agent2_tlspskcheck.stat.exists
no_log: "{{ ansible_verbosity < 3 }}"
+ tags:
+ - config
- name: AutoPSK | Read existing TLS PSK identity file (Windows)
- slurp:
+ ansible.builtin.slurp:
src: "{{ zabbix_agent2_tlspskidentity_file }}"
register: zabbix_agent2_tlspskidentity_base64
when: zabbix_agent2_tlspskidentity_check.stat.exists
no_log: "{{ ansible_verbosity < 3 }}"
+ tags:
+ - config
-- include_tasks: tlspsk_auto_agent2_common.yml
+- ansible.builtin.include_tasks: tlspsk_auto_agent2_common.yml
- name: Windows | AutoPSK | Template TLS PSK identity in file (Windows)
- win_copy:
+ ansible.windows.win_copy:
dest: "{{ zabbix_agent2_tlspskidentity_file }}"
content: "{{ zabbix_agent2_tlspskidentity }}"
when:
@@ -40,9 +50,11 @@
- zabbix_agent2_tlspskidentity is defined
notify:
- restart win zabbix agent
-
+ tags:
+ - config
+
- name: AutoPSK | Template TLS PSK secret in file (Windows)
- win_copy:
+ ansible.windows.win_copy:
dest: "{{ zabbix_agent2_tlspskfile }}"
content: "{{ zabbix_agent2_tlspsk_secret }}"
when:
@@ -50,3 +62,5 @@
- zabbix_agent2_tlspsk_secret is defined
notify:
- restart win zabbix agent
+ tags:
+ - config
diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_common.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_common.yml
index 4b02fafb6..05ef24d0e 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_common.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_common.yml
@@ -1,37 +1,44 @@
---
# Process PSK Secret
- name: AutoPSK | Save existing TLS PSK secret
- set_fact:
+ ansible.builtin.set_fact:
zabbix_agent_tlspsk_read: "{{ zabbix_agent_tlspsk_base64['content'] | b64decode | trim }}"
when: zabbix_agent_tlspskcheck.stat.exists
no_log: "{{ ansible_verbosity < 3 }}"
+ tags:
+ - config
- name: AutoPSK | Use existing TLS PSK secret
- set_fact:
+ ansible.builtin.set_fact:
zabbix_agent_tlspsk_secret: "{{ zabbix_agent_tlspsk_read }}"
when:
- zabbix_agent_tlspskcheck.stat.exists
- zabbix_agent_tlspsk_read|length >= 32
no_log: "{{ ansible_verbosity < 3 }}"
+ tags:
+ - config
- name: AutoPSK | Generate new TLS PSK secret
- set_fact:
+ ansible.builtin.set_fact:
zabbix_agent_tlspsk_secret: "{{ lookup('password', '/dev/null chars=hexdigits length=64') }}"
when:
- (not zabbix_agent_tlspskcheck.stat.exists) or (zabbix_agent_tlspsk_read|length < 32)
no_log: "{{ ansible_verbosity < 3 }}"
-
+ tags:
+ - config
# Process PSK Identity
- name: AutoPSK | Use existing TLS PSK identity
- set_fact:
+ ansible.builtin.set_fact:
zabbix_agent_tlspskidentity: "{{ zabbix_agent_tlspskidentity_base64['content'] | b64decode | trim }}"
when:
- zabbix_agent_tlspskidentity_check.stat.exists
no_log: "{{ ansible_verbosity < 3 }}"
+ tags:
+ - config
- name: AutoPSK | Generate new TLS PSK identity
- set_fact:
+ ansible.builtin.set_fact:
zabbix_agent_tlspskidentity: >-
{{
zabbix_agent_visible_hostname
@@ -41,3 +48,5 @@
}}
when: not zabbix_agent_tlspskidentity_check.stat.exists
no_log: "{{ ansible_verbosity < 3 }}"
+ tags:
+ - config
diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_linux.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_linux.yml
index 1dbea4082..8cc711fcb 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_linux.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_linux.yml
@@ -1,42 +1,52 @@
---
- name: AutoPSK | Set default path variables (Linux)
- set_fact:
+ ansible.builtin.set_fact:
zabbix_agent_tlspskfile: "/etc/zabbix/tls_psk_auto.secret"
zabbix_agent_tlspskidentity_file: "/etc/zabbix/tls_psk_auto.identity"
+ tags:
+ - config
- name: AutoPSK | Check for existing TLS PSK file (Linux)
- stat:
+ ansible.builtin.stat:
path: "{{ zabbix_agent_tlspskfile }}"
register: zabbix_agent_tlspskcheck
become: true
+ tags:
+ - config
- name: AutoPSK | Check for existing TLS PSK identity (Linux)
- stat:
+ ansible.builtin.stat:
path: "{{ zabbix_agent_tlspskidentity_file }}"
register: zabbix_agent_tlspskidentity_check
become: true
+ tags:
+ - config
- name: AutoPSK | read existing TLS PSK file (Linux)
- slurp:
+ ansible.builtin.slurp:
src: "{{ zabbix_agent_tlspskfile }}"
register: zabbix_agent_tlspsk_base64
become: true
- when:
+ when:
- zabbix_agent_tlspskcheck.stat.exists
no_log: "{{ ansible_verbosity < 3 }}"
+ tags:
+ - config
- name: AutoPSK | Read existing TLS PSK identity file (Linux)
- slurp:
+ ansible.builtin.slurp:
src: "{{ zabbix_agent_tlspskidentity_file }}"
register: zabbix_agent_tlspskidentity_base64
become: true
when: zabbix_agent_tlspskidentity_check.stat.exists
no_log: "{{ ansible_verbosity < 3 }}"
+ tags:
+ - config
- include_tasks: tlspsk_auto_common.yml
- name: AutoPSK | Template TLS PSK identity in file (Linux)
- copy:
+ ansible.builtin.copy:
dest: "{{ zabbix_agent_tlspskidentity_file }}"
content: "{{ zabbix_agent_tlspskidentity }}"
owner: zabbix
@@ -49,9 +59,11 @@
notify:
- restart zabbix-agent
- restart mac zabbix agent
-
+ tags:
+ - config
+
- name: AutoPSK | Template TLS PSK secret in file (Linux)
- copy:
+ ansible.builtin.copy:
dest: "{{ zabbix_agent_tlspskfile }}"
content: "{{ zabbix_agent_tlspsk_secret }}"
owner: zabbix
@@ -64,3 +76,5 @@
notify:
- restart zabbix-agent
- restart mac zabbix agent
+ tags:
+ - config
diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_windows.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_windows.yml
index 146cfd457..b9289ac49 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_windows.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/tlspsk_auto_windows.yml
@@ -1,38 +1,48 @@
---
- name: AutoPSK | Set default path variables for Windows
- set_fact:
+ ansible.builtin.set_fact:
zabbix_agent_tlspskfile: "{{ zabbix_win_install_dir }}\\tls_psk_auto.secret.txt"
zabbix_agent_tlspskidentity_file: "{{ zabbix_win_install_dir }}\\tls_psk_auto.identity.txt"
+ tags:
+ - config
- name: AutoPSK | Check for existing TLS PSK file (Windows)
ansible.windows.win_stat:
path: "{{ zabbix_agent_tlspskfile }}"
register: zabbix_agent_tlspskcheck
+ tags:
+ - config
- name: AutoPSK | Check for existing TLS PSK identity (Windows)
ansible.windows.win_stat:
path: "{{ zabbix_agent_tlspskidentity_file }}"
register: zabbix_agent_tlspskidentity_check
+ tags:
+ - config
- name: AutoPSK | read existing TLS PSK file (Windows)
- slurp:
+ ansible.builtin.slurp:
src: "{{ zabbix_agent_tlspskfile }}"
register: zabbix_agent_tlspsk_base64
- when:
+ when:
- zabbix_agent_tlspskcheck.stat.exists
no_log: "{{ ansible_verbosity < 3 }}"
+ tags:
+ - config
- name: AutoPSK | Read existing TLS PSK identity file (Windows)
- slurp:
+ ansible.builtin.slurp:
src: "{{ zabbix_agent_tlspskidentity_file }}"
register: zabbix_agent_tlspskidentity_base64
when: zabbix_agent_tlspskidentity_check.stat.exists
no_log: "{{ ansible_verbosity < 3 }}"
+ tags:
+ - config
- include_tasks: tlspsk_auto_common.yml
- name: AutoPSK | Template TLS PSK identity in file (Windows)
- win_copy:
+ ansible.windows.win_copy:
dest: "{{ zabbix_agent_tlspskidentity_file }}"
content: "{{ zabbix_agent_tlspskidentity }}"
when:
@@ -40,14 +50,18 @@
- zabbix_agent_tlspskidentity is defined
notify:
- restart win zabbix agent
-
+ tags:
+ - config
+
- name: AutoPSK | Template TLS PSK secret in file (Windows)
- win_copy:
+ ansible.windows.win_copy:
dest: "{{ zabbix_agent_tlspskfile }}"
content: "{{ zabbix_agent_tlspsk_secret }}"
when:
- zabbix_agent_tlspskfile is defined
- zabbix_agent_tlspsk_secret is defined
- - zabbix_agent_os_family == "Windows"
+ - ansible_os_family == "Windows"
notify:
- restart win zabbix agent
+ tags:
+ - config
diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/userparameter.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/userparameter.yml
index 9a86b536a..a80be1736 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/userparameter.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_agent/tasks/userparameter.yml
@@ -1,85 +1,87 @@
---
- block:
- - name: "Windows | Installing user-defined userparameters"
- ansible.windows.win_template:
- src: "{{ zabbix_agent_userparameters_templates_src }}/{{ item.name }}.j2"
- dest: '{{ zabbix_agent_win_include }}\{{ item.name }}.conf'
- notify:
- - restart win zabbix agent
- with_items: "{{ zabbix_agent_userparameters }}"
-
- - name: "Windows | Installing user-defined scripts"
- ansible.windows.win_copy:
- src: "{{ zabbix_agent_userparameters_scripts_src }}/{{ item.scripts_dir }}"
- dest: '{{ zabbix_win_install_dir }}\scripts\'
- notify:
- - restart win zabbix agent
- with_items: "{{ zabbix_agent_userparameters }}"
- when: item.scripts_dir is defined
-
- when: zabbix_agent_os_family == "Windows"
+ - name: "Windows | Installing user-defined userparameters"
+ ansible.windows.win_template:
+ src: "{{ zabbix_agent_userparameters_templates_src }}/{{ item.name }}.j2"
+ dest: '{{ zabbix_agent_win_include }}\{{ item.name }}.conf'
+ notify:
+ - restart win zabbix agent
+ with_items: "{{ zabbix_agent_userparameters }}"
+ - name: "Windows | Installing user-defined scripts"
+ ansible.windows.win_copy:
+ src: "{{ zabbix_agent_userparameters_scripts_src }}/{{ item.scripts_dir }}"
+ dest: '{{ zabbix_win_install_dir }}\scripts\'
+ notify:
+ - restart win zabbix agent
+ with_items: "{{ zabbix_agent_userparameters }}"
+ when: item.scripts_dir is defined
+ when: ansible_os_family == "Windows"
+ tags:
+ - config
- block:
- - name: "Installing user-defined userparameters"
- template:
- src: "{{ zabbix_agent_userparameters_templates_src }}/{{ item.name }}.j2"
- dest: "{{ zabbix_agent_include }}/userparameter_{{ item.name }}.conf"
- owner: zabbix
- group: zabbix
- mode: 0644
- notify:
- - restart zabbix-agent
- - restart mac zabbix agent
- become: true
- with_items: "{{ zabbix_agent_userparameters }}"
-
- - name: "Installing user-defined scripts"
- copy:
- src: "{{ zabbix_agent_userparameters_scripts_src }}/{{ item.scripts_dir }}"
- dest: "/etc/zabbix/scripts/"
- owner: zabbix
- group: zabbix
- mode: 0755
- notify:
- - restart zabbix-agent
- - restart mac zabbix agent
- become: true
- with_items: "{{ zabbix_agent_userparameters }}"
- when: item.scripts_dir is defined
+ - name: "Installing user-defined userparameters"
+ ansible.builtin.template:
+ src: "{{ zabbix_agent_userparameters_templates_src }}/{{ item.name }}.j2"
+ dest: "{{ zabbix_agent_include }}/userparameter_{{ item.name }}.conf"
+ owner: zabbix
+ group: zabbix
+ mode: 0644
+ notify:
+ - restart zabbix-agent
+ - restart mac zabbix agent
+ become: true
+ with_items: "{{ zabbix_agent_userparameters }}"
+ - name: "Installing user-defined scripts"
+ ansible.builtin.copy:
+ src: "{{ zabbix_agent_userparameters_scripts_src }}/{{ item.scripts_dir }}"
+ dest: "/etc/zabbix/scripts/"
+ owner: zabbix
+ group: zabbix
+ mode: 0755
+ notify:
+ - restart zabbix-agent
+ - restart mac zabbix agent
+ become: true
+ with_items: "{{ zabbix_agent_userparameters }}"
+ when: item.scripts_dir is defined
when:
- - zabbix_agent_os_family != "Windows"
+ - ansible_os_family != "Windows"
- not zabbix_agent2
+ tags:
+ - config
- block:
- - name: "Installing user-defined userparameters"
- template:
- src: "{{ zabbix_agent_userparameters_templates_src }}/{{ item.name }}.j2"
- dest: "{{ zabbix_agent2_include }}/userparameter_{{ item.name }}.conf"
- owner: zabbix
- group: zabbix
- mode: 0644
- notify:
- - restart zabbix-agent
- - restart mac zabbix agent
- become: true
- with_items: "{{ zabbix_agent_userparameters }}"
-
- - name: "Installing user-defined scripts"
- copy:
- src: "{{ zabbix_agent_userparameters_scripts_src }}/{{ item.scripts_dir }}"
- dest: "/etc/zabbix/scripts/"
- owner: zabbix
- group: zabbix
- mode: 0755
- notify:
- - restart zabbix-agent
- - restart mac zabbix agent
- become: true
- with_items: "{{ zabbix_agent_userparameters }}"
- when: item.scripts_dir is defined
+ - name: "Installing user-defined userparameters"
+ ansible.builtin.template:
+ src: "{{ zabbix_agent_userparameters_templates_src }}/{{ item.name }}.j2"
+ dest: "{{ zabbix_agent2_include }}/userparameter_{{ item.name }}.conf"
+ owner: zabbix
+ group: zabbix
+ mode: 0644
+ notify:
+ - restart zabbix-agent
+ - restart mac zabbix agent
+ become: true
+ with_items: "{{ zabbix_agent_userparameters }}"
+ - name: "Installing user-defined scripts"
+ ansible.builtin.copy:
+ src: "{{ zabbix_agent_userparameters_scripts_src }}/{{ item.scripts_dir }}"
+ dest: "/etc/zabbix/scripts/"
+ owner: zabbix
+ group: zabbix
+ mode: 0755
+ notify:
+ - restart zabbix-agent
+ - restart mac zabbix agent
+ become: true
+ with_items: "{{ zabbix_agent_userparameters }}"
+ when: item.scripts_dir is defined
when:
- - zabbix_agent_os_family != "Windows"
+ - ansible_os_family != "Windows"
- zabbix_agent2
+ tags:
+ - config
diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/templates/zabbix_agent2.conf.j2 b/ansible_collections/community/zabbix/roles/zabbix_agent/templates/zabbix_agent2.conf.j2
index 39829abc3..ea60d032e 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_agent/templates/zabbix_agent2.conf.j2
+++ b/ansible_collections/community/zabbix/roles/zabbix_agent/templates/zabbix_agent2.conf.j2
@@ -4,13 +4,13 @@
# This configuration file is "minimalized", which means all the original comments
# are removed. The full documentation for your Zabbix Agent 2 can be found here:
-# https://www.zabbix.com/documentation/{{ zabbix_version }}/en/manual/appendix/config/zabbix_agent2{{ "_win" if zabbix_agent_os_family == "Windows" else "" }}
+# https://www.zabbix.com/documentation/{{ zabbix_agent_version }}/en/manual/appendix/config/zabbix_agent2{{ "_win" if ansible_os_family == "Windows" else "" }}
-{% if zabbix_agent_os_family != "Windows" %}
+{% if ansible_os_family != "Windows" %}
PidFile={{ zabbix_agent2_pidfile }}
{% endif %}
LogType={{ zabbix_agent2_logtype }}
-{% if zabbix_agent_os_family == "Windows" %}
+{% if ansible_os_family == "Windows" %}
LogFile={{ zabbix_agent2_win_logfile }}
{% else %}
LogFile={{ zabbix_agent2_logfile }}
@@ -79,13 +79,18 @@ Alias={{ item }}
{% endif %}
{% endif %}
Timeout={{ zabbix_agent2_timeout }}
-{% if zabbix_agent_os_family == "Windows" %}
+{% if ansible_os_family == "Windows" %}
Include={{ zabbix_agent_win_include }}
{% else %}
Include={{ zabbix_agent2_include }}/{{ zabbix_agent2_include_pattern }}
{% endif %}
+{% if zabbix_agent2_additional_include is defined and zabbix_agent2_additional_include is iterable and zabbix_agent2_additional_include is not string %}
+{% for include in zabbix_agent2_additional_include %}
+Include={{ include }}
+{% endfor %}
+{% endif %}
UnsafeUserParameters={{ zabbix_agent2_unsafeuserparameters }}
-{% if zabbix_agent_os_family != "Windows" %}
+{% if ansible_os_family != "Windows" %}
ControlSocket={{ zabbix_agent2_controlsocket }}
{% endif %}
{% if zabbix_agent2_tlsconnect is defined and zabbix_agent2_tlsconnect %}
@@ -128,7 +133,7 @@ Plugins.{{ my_name }}.{{ param }}={{ value }}
{% endfor %}
{% endfor %}
{% endif %}
-{% if zabbix_version is version('6.0', '>=') %}
+{% if zabbix_agent_version is version('6.0', '>=') %}
{% if zabbix_agent2_listenbacklog is defined and zabbix_agent2_listenbacklog %}
ListenBacklog={{ zabbix_agent2_listenbacklog }}
{% endif %}
diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/templates/zabbix_agentd.conf.j2 b/ansible_collections/community/zabbix/roles/zabbix_agent/templates/zabbix_agentd.conf.j2
index 5e5d31d9b..24af45bc3 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_agent/templates/zabbix_agentd.conf.j2
+++ b/ansible_collections/community/zabbix/roles/zabbix_agent/templates/zabbix_agentd.conf.j2
@@ -4,15 +4,15 @@
# This configuration file is "minimalized", which means all the original comments
# are removed. The full documentation for your Zabbix Agent can be found here:
-# https://www.zabbix.com/documentation/{{ zabbix_version }}/en/manual/appendix/config/zabbix_agentd{{ "_win" if zabbix_agent_os_family == "Windows" else "" }}
+# https://www.zabbix.com/documentation/{{ zabbix_agent_version }}/en/manual/appendix/config/zabbix_agentd{{ "_win" if ansible_os_family == "Windows" else "" }}
-{% if zabbix_agent_os_family != "Windows" %}
+{% if ansible_os_family != "Windows" %}
PidFile={{ zabbix_agent_pidfile }}
{% endif %}
{% if zabbix_agent_version is version('3.0', '>=') %}
LogType={{ zabbix_agent_logtype }}
{% endif %}
-{% if zabbix_agent_os_family == "Windows" %}
+{% if ansible_os_family == "Windows" %}
LogFile={{ zabbix_agent_win_logfile }}
{% else %}
LogFile={{ zabbix_agent_logfile }}
@@ -66,7 +66,7 @@ RefreshActiveChecks={{ zabbix_agent_refreshactivechecks }}
BufferSend={{ zabbix_agent_buffersend }}
BufferSize={{ zabbix_agent_buffersize }}
MaxLinesPerSecond={{ zabbix_agent_maxlinespersecond }}
-{% if zabbix_version is version_compare('6.2', '>=') %}
+{% if zabbix_agent_version is version_compare('6.2', '>=') %}
HeartbeatFrequency={{ zabbix_agent_heartbeatfrequency }}
{% endif %}
{% if zabbix_agent_zabbix_alias is defined and zabbix_agent_zabbix_alias %}
@@ -79,20 +79,25 @@ Alias={{ item }}
{% endif %}
{% endif %}
Timeout={{ zabbix_agent_timeout }}
-{% if zabbix_agent_os_family != "Windows" %}
+{% if ansible_os_family != "Windows" %}
AllowRoot={{ zabbix_agent_allowroot }}
{% endif %}
{% if zabbix_agent_runas_user is defined and zabbix_agent_runas_user %}
User={{ zabbix_agent_runas_user }}
{% endif %}
-{% if zabbix_agent_os_family == "Windows" %}
+{% if ansible_os_family == "Windows" %}
Include={{ zabbix_agent_win_include }}
{% else %}
Include={{ zabbix_agent_include }}/{{ zabbix_agent_include_pattern }}
{% endif %}
+{% if zabbix_agent_additional_include is defined and zabbix_agent_additional_include is iterable and zabbix_agent_additional_include is not string %}
+{% for include in zabbix_agent_additional_include %}
+Include={{ include }}
+{% endfor %}
+{% endif %}
UnsafeUserParameters={{ zabbix_agent_unsafeuserparameters }}
-{% if zabbix_version is version_compare('2.2', '>=') %}
-{% if zabbix_agent_os_family != "Windows" %}
+{% if zabbix_agent_version is version_compare('2.2', '>=') %}
+{% if ansible_os_family != "Windows" %}
LoadModulePath={{ zabbix_agent_loadmodulepath }}
{% endif %}
{% endif %}
@@ -105,7 +110,7 @@ LoadModule={{ module }}
{% endfor %}
{% endif %}
{% endif %}
-{% if zabbix_version is version_compare('3.0', '>=') %}
+{% if zabbix_agent_version is version_compare('3.0', '>=') %}
{% if zabbix_agent_tlsconnect is defined and zabbix_agent_tlsconnect %}
TLSConnect={{ zabbix_agent_tlsconnect }}
{% endif %}
@@ -137,7 +142,7 @@ TLSPSKIdentity={{ zabbix_agent_tlspskidentity }}
TLSPSKFile={{ zabbix_agent_tlspskfile }}
{% endif %}
{% endif %}
-{% if zabbix_version is version('6.0', '>=') %}
+{% if zabbix_agent_version is version('6.0', '>=') %}
{% if zabbix_agent_listenbacklog is defined and zabbix_agent_listenbacklog %}
ListenBacklog={{ zabbix_agent_listenbacklog }}
{% endif %}
diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/vars/Darwin.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/vars/Darwin.yml
deleted file mode 100644
index 164b02460..000000000
--- a/ansible_collections/community/zabbix/roles/zabbix_agent/vars/Darwin.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
-# vars file for zabbix_agent (Debian)
-
-zabbix_agent: zabbix-agent
-zabbix_agent_service: com.zabbix.zabbix_agentd
-zabbix_agent_conf: zabbix_agentd.conf
diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/vars/Debian.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/vars/Debian.yml
index 3100ca957..4a65dfbeb 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_agent/vars/Debian.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_agent/vars/Debian.yml
@@ -8,31 +8,41 @@ zabbix_agent2_conf: zabbix_agent2.conf
zabbix_valid_agent_versions:
# Debian
+ "12":
+ - 6.4
+ - 6.2
+ - 6.0
+
"11":
- 6.4
+ - 6.2
- 6.0
- - 5.0
- - 4.0
+
"10":
+ - 6.4
+ - 6.2
- 6.0
- - 5.0
- - 4.0
+
"9":
+ - 6.4
+ - 6.2
- 6.0
- - 5.0
- - 4.0
# Ubuntu
"22":
- 6.4
+ - 6.2
- 6.0
- - 5.0
- - 4.0
+
"20":
- 6.4
+ - 6.2
- 6.0
- - 5.0
- - 4.0
+
"18":
+ - 6.4
+ - 6.2
- 6.0
- - 5.0
- - 4.0
+
+debian_keyring_path: /etc/apt/keyrings/
+zabbix_gpg_key: "{{ debian_keyring_path }}/zabbix-official-repo.asc"
+_zabbix_repo_deb_url: "http://repo.zabbix.com/zabbix/{{ zabbix_agent_version }}"
diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/vars/RedHat.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/vars/RedHat.yml
index b9f2378dd..50f0b01ec 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_agent/vars/RedHat.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_agent/vars/RedHat.yml
@@ -9,16 +9,13 @@ zabbix_agent2_conf: zabbix_agent2.conf
zabbix_valid_agent_versions:
"9":
- 6.4
+ - 6.2
- 6.0
- - 5.0
- - 4.0
"8":
- 6.4
+ - 6.2
- 6.0
- - 5.0
- - 4.0
"7":
- 6.4
+ - 6.2
- 6.0
- - 5.0
- - 4.0
diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/vars/Sangoma.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/vars/Sangoma.yml
deleted file mode 100644
index 5bcc846ab..000000000
--- a/ansible_collections/community/zabbix/roles/zabbix_agent/vars/Sangoma.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-# vars file for zabbix_agent (Sangola)
-
-zabbix_agent: zabbix-agent
-zabbix_agent_service: zabbix-agent
-zabbix_agent_conf: zabbix_agentd.conf
-zabbix_agent2_conf: zabbix_agent2.conf
diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/vars/Suse.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/vars/Suse.yml
deleted file mode 100644
index abecd9c23..000000000
--- a/ansible_collections/community/zabbix/roles/zabbix_agent/vars/Suse.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-# vars file for zabbix_agent (Suse)
-
-zabbix_agent: zabbix-agentd
-zabbix_agent_service: zabbix_agentd
-zabbix_agent_conf: zabbix_agentd.conf
-zabbix_agent2_conf: zabbix-agent2.conf
diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/vars/Windows.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/vars/Windows.yml
index 8add26238..4dd64ba02 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_agent/vars/Windows.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_agent/vars/Windows.yml
@@ -1,2 +1,7 @@
---
# vars file for zabbix_agent (Windows)
+zabbix_valid_agent_versions:
+ "10":
+ - 6.4
+ - 6.2
+ - 6.0
diff --git a/ansible_collections/community/zabbix/roles/zabbix_agent/vars/zabbix.yml b/ansible_collections/community/zabbix/roles/zabbix_agent/vars/zabbix.yml
deleted file mode 100644
index c78d3a76e..000000000
--- a/ansible_collections/community/zabbix/roles/zabbix_agent/vars/zabbix.yml
+++ /dev/null
@@ -1,285 +0,0 @@
----
-sign_keys:
- "64":
- bullseye:
- sign_key: E709712C
- buster:
- sign_key: E709712C
- stretch:
- sign_key: E709712C
- focal:
- sign_key: E709712C
- bionic:
- sign_key: E709712C
- xenial:
- sign_key: E709712C
- trusty:
- sign_key: E709712C
- jammy:
- sign_key: E709712C
- "62":
- bullseye:
- sign_key: E709712C
- buster:
- sign_key: E709712C
- stretch:
- sign_key: E709712C
- focal:
- sign_key: E709712C
- bionic:
- sign_key: E709712C
- xenial:
- sign_key: E709712C
- trusty:
- sign_key: E709712C
- jammy:
- sign_key: E709712C
- "60":
- bullseye:
- sign_key: E709712C
- buster:
- sign_key: E709712C
- stretch:
- sign_key: E709712C
- jammy:
- sign_key: E709712C
- focal:
- sign_key: E709712C
- bionic:
- sign_key: E709712C
- xenial:
- sign_key: E709712C
- trusty:
- sign_key: E709712C
- "54":
- bullseye:
- sign_key: E709712C
- buster:
- sign_key: E709712C
- jessie:
- sign_key: E709712C
- stretch:
- sign_key: E709712C
- jammy:
- sign_key: E709712C
- focal:
- sign_key: E709712C
- bionic:
- sign_key: E709712C
- xenial:
- sign_key: E709712C
- trusty:
- sign_key: E709712C
- tricia:
- sign_key: E709712C
- "52":
- # bullseye: not available upstream
- buster:
- sign_key: E709712C
- jessie:
- sign_key: E709712C
- stretch:
- sign_key: E709712C
- jammy:
- sign_key: E709712C
- focal:
- sign_key: E709712C
- bionic:
- sign_key: E709712C
- xenial:
- sign_key: E709712C
- trusty:
- sign_key: E709712C
- tricia:
- sign_key: E709712C
- "50":
- bullseye:
- sign_key: E709712C
- buster:
- sign_key: E709712C
- jessie:
- sign_key: E709712C
- stretch:
- sign_key: E709712C
- jammy:
- sign_key: E709712C
- focal:
- sign_key: E709712C
- bionic:
- sign_key: E709712C
- xenial:
- sign_key: E709712C
- trusty:
- sign_key: E709712C
- tricia:
- sign_key: E709712C
- "44":
- buster:
- sign_key: A14FE591
- jessie:
- sign_key: 79EA5ED4
- stretch:
- sign_key: A14FE591
- focal:
- sign_key: A14FE591
- eoan:
- sign_key: A14FE591
- cosmic:
- sign_key: A14FE591
- bionic:
- sign_key: A14FE591
- sonya:
- sign_key: A14FE591
- serena:
- sign_key: A14FE591
- trusty:
- sign_key: 79EA5ED4
- xenial:
- sign_key: E709712C
- "42":
- buster:
- sign_key: A14FE591
- jessie:
- sign_key: 79EA5ED4
- stretch:
- sign_key: A14FE591
- eoan:
- sign_key: A14FE591
- cosmic:
- sign_key: A14FE591
- bionic:
- sign_key: A14FE591
- sonya:
- sign_key: A14FE591
- serena:
- sign_key: A14FE591
- trusty:
- sign_key: 79EA5ED4
- xenial:
- sign_key: E709712C
- "40":
- bullseye:
- sign_key: A14FE591
- buster:
- sign_key: A14FE591
- jessie:
- sign_key: 79EA5ED4
- stretch:
- sign_key: A14FE591
- focal:
- sign_key: A14FE591
- bionic:
- sign_key: A14FE591
- sonya:
- sign_key: A14FE591
- serena:
- sign_key: A14FE591
- trusty:
- sign_key: 79EA5ED4
- xenial:
- sign_key: E709712C
- "34":
- jessie:
- sign_key: 79EA5ED4
- stretch:
- sign_key: A14FE591
- wheezy:
- sign_key: A14FE591
- bionic:
- sign_key: A14FE591
- sonya:
- sign_key: A14FE591
- serena:
- sign_key: A14FE591
- trusty:
- sign_key: 79EA5ED4
- xenial:
- sign_key: E709712C
- "32":
- stretch:
- sign_key: A14FE591
- wheezy:
- sign_key: 79EA5ED4
- bionic:
- sign_key: A14FE591
- sonya:
- sign_key: 79EA5ED4
- serena:
- sign_key: 79EA5ED4
- trusty:
- sign_key: 79EA5ED4
- xenial:
- sign_key: E709712C
- "30":
- buster:
- sign_key: A14FE591
- jessie:
- sign_key: 79EA5ED4
- stretch:
- sign_key: A14FE591
- wheezy:
- sign_key: 79EA5ED4
- bionic:
- sign_key: A14FE591
- trusty:
- sign_key: 79EA5ED4
- xenial:
- sign_key: E709712C
- "24":
- jessie:
- sign_key: 79EA5ED4
- wheezy:
- sign_key: 79EA5ED4
- precise:
- sign_key: 79EA5ED4
- trusty:
- sign_key: 79EA5ED4
- "22":
- squeeze:
- sign_key: 79EA5ED4
- wheezy:
- sign_key: 79EA5ED4
- precise:
- sign_key: 79EA5ED4
- trusty:
- sign_key: 79EA5ED4
- lucid:
- sign_key: 79EA5ED4
-
-suse:
- "openSUSE Leap":
- "42":
- name: server:monitoring
- url: http://download.opensuse.org/repositories/server:/monitoring/openSUSE_Leap_{{ ansible_distribution_version }}/
- python_libxml2_package: python-libxml2
- "openSUSE":
- "12":
- name: server_monitoring
- url: http://download.opensuse.org/repositories/server:/monitoring/openSUSE_{{ ansible_distribution_version }}
- python_libxml2_package: python-libxml2
- "SLES":
- "11":
- name: server_monitoring
- url: http://download.opensuse.org/repositories/server:/monitoring/SLE_11_SP3/
- python_libxml2_package: python-libxml2
- "12":
- name: server_monitoring
- url: http://download.opensuse.org/repositories/server:/monitoring/SLE_12_SP5/
- python_libxml2_package: python-libxml2
- "15":
- name: server_monitoring
- url: http://download.opensuse.org/repositories/server:/monitoring/SLE_15_SP3/
- python_libxml2_package: python3-libxml2-python
- "SLES_SAP": # SAP specific version of SLES
- "11":
- name: server_monitoring
- url: http://download.opensuse.org/repositories/server:/monitoring/SLE_11_SP3/
- python_libxml2_package: python-libxml2
- "12":
- name: server_monitoring
- url: http://download.opensuse.org/repositories/server:/monitoring/SLE_12_SP5/
- python_libxml2_package: python-libxml2
- "15":
- name: server_monitoring
- url: http://download.opensuse.org/repositories/server:/monitoring/SLE_15_SP3/
- python_libxml2_package: python3-libxml2-python
diff --git a/ansible_collections/community/zabbix/roles/zabbix_javagateway/README.md b/ansible_collections/community/zabbix/roles/zabbix_javagateway/README.md
index 70427d97c..1761c7f8b 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_javagateway/README.md
+++ b/ansible_collections/community/zabbix/roles/zabbix_javagateway/README.md
@@ -29,29 +29,22 @@ This role will work on the following operating systems:
* Ubuntu
So, you'll need one of those operating systems.. :-)
-Please send Pull Requests or suggestions when you want to use this role for other Operating systems.
## Zabbix Versions
See the following list of supported Operating systems with the Zabbix releases.
-| Zabbix | 6.4 | 6.2 | 6.0 (LTS) | 5.2 | 5.0 | 4.4 | 4.0 (LTS) | 3.0 (LTS) |
-|---------------------|-----|-----|-----------|-----|-----|-----|-----------|-----------|
-| Red Hat Fam 8 | V | V | V | V | V | V | | |
-| Red Hat Fam 7 | | | | V | V | V | V | V |
-| Red Hat Fam 6 | | | | V | V | | | V |
-| Red Hat Fam 5 | | | | V | V | | | V |
-| Fedora | | | | | | V | V | |
-| Ubuntu 20.04 focal | V | V | V | V | V | | V | |
-| Ubuntu 18.04 bionic | | | | V | V | V | V | |
-| Ubuntu 16.04 xenial | | | | V | V | V | V | |
-| Ubuntu 14.04 trusty | | | | V | V | V | V | V |
-| Debian 10 buster | V | V | V | V | V | V | | |
-| Debian 9 stretch | | | | V | V | V | V | |
-| Debian 8 jessie | | | | V | V | V | V | V |
-| Debian 7 wheezy | | | | | | | V | V |
-| macOS 10.15 | | | | | | V | V | |
-| macOS 10.14 | | | | | | V | V | |
+| Zabbix | 6.4 | 6.2 | 6.0 |
+|---------------------|-----|-----|-----|
+| Red Hat Fam 9 | V | V | V |
+| Red Hat Fam 8 | V | V | V |
+| Red Hat Fam 7 | V | V | V |
+| Ubuntu 22.04 jammy | V | V | V |
+| Ubuntu 20.04 focal | V | V | V |
+| Ubuntu 18.04 bionic | V | V | V |
+| Debian 12 bookworm | V | | V |
+| Debian 11 bullseye | V | V | V |
+| Debian 10 buster | V | V | V |
# Role Variables
@@ -61,17 +54,14 @@ The following is an overview of all available configuration default for this rol
### Overall Zabbix
-* `zabbix_javagateway_version`: This is the version of zabbix. Default: 5.2. Can be overridden to 5.0, 4.4, 4.0, 3.4, 3.2, 3.0, 2.4, or 2.2. Previously the variable `zabbix_version` was used directly but it could cause [some inconvenience](https://github.com/dj-wasabi/ansible-zabbix-agent/pull/303). That variable is maintained by retrocompativility.
-* `zabbix_repo`: Default: `zabbix`
- * `epel`: install agent from EPEL repo
- * `zabbix`: (default) install agent from Zabbix repo
- * `other`: install agent from pre-existing or other repo
+The `zabbix_javagateway_version` is optional. The latest available major.minor version of Zabbix will be installed on the host(s). If you want to use an older version, please specify this in the major.minor format. Example: `zabbix_javagateway_version: 6.0`.
* `zabbix_repo_yum`: A list with Yum repository configuration.
* `zabbix_repo_yum_schema`: Default: `https`. Option to change the web schema for the yum repository(http/https)
-* `zabbix_repo_yum_disabled`: A string with repository names that should be disabled when installing Zabbix component specific packages. Is only used when `zabbix_repo_yum_enabled` contains 1 or more repositories. Default `*`.
-* `zabbix_repo_yum_enabled`: A list with repository names that should be enabled when installing Zabbix component specific packages.
+* `zabbix_javagateway_disable_repo`: A list of repos to disable during install. Default `epel`.
* `zabbix_javagateway_package_state`: Default: `present`. Can be overridden to `latest` to update packages when needed.
* `zabbix_javagateway_conf_mode`: Default: `0644`. The "mode" for the Zabbix configuration file.
+* `zabbix_repo_deb_url`: The URL to the Zabbix repository. Default `http://repo.zabbix.com/zabbix/{{ zabbix_agent_version }}/{{ ansible_distribution.lower() }}`
+* `zabbix_repo_deb_component`: The repository component for Debian installs. Default `main`.
### Java Gatewaty
@@ -106,6 +96,17 @@ or when using the zabbix-proxy:
zabbix_proxy_javagateway: 192.168.1.2
```
+## Tags
+
+The majority of tasks within this role are tagged as follows:
+
+* `install`: Tasks associated with the installation of software.
+* `dependencies`: Installation tasks related to dependencies that aren't part of the core zabbix installation.
+* `database`: Tasks associated with the installation or configuration of the database.
+* `api`: Tasks associated with using the Zabbix API to connect and modify the Zabbix server.
+* `config`: Tasks associated with the configuration of Zabbix or a supporting service.
+* `service`: Tasks associated with managing a service.
+
# Example Playbook
Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
diff --git a/ansible_collections/community/zabbix/roles/zabbix_javagateway/defaults/main.yml b/ansible_collections/community/zabbix/roles/zabbix_javagateway/defaults/main.yml
index a34046616..4356f61a4 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_javagateway/defaults/main.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_javagateway/defaults/main.yml
@@ -1,17 +1,14 @@
---
# defaults file for zabbix_javagateway
-zabbix_javagateway_version: 6.4
-zabbix_version: "{{ zabbix_javagateway_version }}"
+#zabbix_javagateway_version:6.4
zabbix_javagateway_package_state: present
-zabbix_selinux: false
-zabbix_repo: zabbix
zabbix_repo_yum_schema: https
zabbix_java_gateway_conf_mode: "0644"
zabbix_repo_yum_gpgcheck: 0
-zabbix_repo_yum_disabled: "*"
-zabbix_repo_yum_enabled: []
+zabbix_javagateway_disable_repo:
+ - epel
zabbix_repo_yum:
- name: zabbix
description: Zabbix Official Repository - $basearch
@@ -28,6 +25,8 @@ zabbix_repo_yum:
gpgkey: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ZABBIX
state: present
+zabbix_repo_deb_component: main
+
zabbix_javagateway_pidfile: /run/zabbix/zabbix_java_gateway.pid
zabbix_javagateway_listenip: 0.0.0.0
zabbix_javagateway_listenport: 10052
diff --git a/ansible_collections/community/zabbix/roles/zabbix_javagateway/handlers/main.yml b/ansible_collections/community/zabbix/roles/zabbix_javagateway/handlers/main.yml
index c7034aa7d..9b6ed50c1 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_javagateway/handlers/main.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_javagateway/handlers/main.yml
@@ -2,14 +2,14 @@
# handlers file for zabbix-javagateway
- name: zabbix-java-gateway restarted
- service:
+ ansible.builtin.service:
name: zabbix-java-gateway
state: restarted
enabled: true
become: true
- name: "clean repo files from proxy creds"
- shell: ls /etc/yum.repos.d/zabbix* && sed -i 's/^proxy =.*//' /etc/yum.repos.d/zabbix* || true
+ ansible.builtin.shell: ls /etc/yum.repos.d/zabbix* && sed -i 's/^proxy =.*//' /etc/yum.repos.d/zabbix* || true
become: true
when:
- ansible_os_family == 'RedHat'
diff --git a/ansible_collections/community/zabbix/roles/zabbix_javagateway/tasks/Debian.yml b/ansible_collections/community/zabbix/roles/zabbix_javagateway/tasks/Debian.yml
index d025e6ca8..4c4cff06d 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_javagateway/tasks/Debian.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_javagateway/tasks/Debian.yml
@@ -1,80 +1,80 @@
---
-
-- name: "Include Zabbix gpg ids"
- include_vars: zabbix.yml
-
-- name: "Set some variables"
- set_fact:
+- name: "Debian | Set some variables"
+ ansible.builtin.set_fact:
zabbix_short_version: "{{ zabbix_javagateway_version | regex_replace('\\.', '') }}"
+ tags:
+ - always
-- name: "Debian | Install gpg key"
- apt_key:
- id: "{{ sign_keys[zabbix_short_version][ansible_distribution_release]['sign_key'] }}"
- url: http://repo.zabbix.com/zabbix-official-repo.key
- become: true
-
-- name: "Debian | Installing repository Debian"
- apt_repository:
- repo: "deb http://repo.zabbix.com/zabbix/{{ zabbix_javagateway_version }}/debian/ {{ ansible_distribution_release }} main"
+- name: "Debian | Installing lsb-release"
+ ansible.builtin.apt:
+ pkg: lsb-release
+ update_cache: true
+ cache_valid_time: 3600
+ force: true
state: present
+ environment:
+ http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
+ https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
become: true
- when:
- - ansible_distribution == "Debian"
- - zabbix_repo == "zabbix"
+ tags:
+ - install
-- name: "Debian | Installing repository Debian"
- apt_repository:
- repo: "deb-src http://repo.zabbix.com/zabbix/{{ zabbix_javagateway_version }}/debian/ {{ ansible_distribution_release }} main"
- state: present
- become: true
- when:
- - ansible_distribution == "Debian"
- - ansible_machine == "aarch64"
- - zabbix_repo == "zabbix"
+- name: "Debian | Update ansible_lsb fact"
+ ansible.builtin.setup:
+ gather_subset:
+ - lsb
-- name: "Debian | Installing repository Ubuntu"
- apt_repository:
- repo: "deb http://repo.zabbix.com/zabbix/{{ zabbix_javagateway_version }}/ubuntu-arm64/ {{ ansible_distribution_release }} main"
- state: present
- become: true
+- name: "Debian | Repo URL"
+ ansible.builtin.set_fact:
+ zabbix_repo_deb_url: "{{ _zabbix_repo_deb_url }}/{{ ansible_lsb.id.lower() }}{{ '-arm64' if ansible_machine == 'aarch64' and ansible_lsb.id == 'debian' else ''}}"
when:
- - ansible_distribution == "Ubuntu"
- - ansible_machine == "aarch64"
- - zabbix_repo == "zabbix"
-
+ - zabbix_repo_deb_url is undefined
+ tags:
+ - always
-- name: "Debian | Installing repository Ubuntu"
- apt_repository:
- repo: "deb http://repo.zabbix.com/zabbix/{{ zabbix_javagateway_version }}/ubuntu/ {{ ansible_distribution_release }} main"
- state: present
+# In releases older than Debian 12 and Ubuntu 22.04, /etc/apt/keyrings does not exist by default.
+# It SHOULD be created with permissions 0755 if it is needed and does not already exist.
+# See: https://wiki.debian.org/DebianRepository/UseThirdParty
+- name: "Debian | Create /etc/apt/keyrings/ on older versions"
+ ansible.builtin.file:
+ path: /etc/apt/keyrings/
+ state: directory
+ mode: "0755"
become: true
when:
- - ansible_distribution == "Ubuntu"
- - ansible_machine != "aarch64"
- - zabbix_repo == "zabbix"
+ - (ansible_distribution == "Ubuntu" and ansible_distribution_major_version < "22") or
+ (ansible_distribution == "Debian" and ansible_distribution_major_version < "12")
-- name: "Debian | Installing repository Ubuntu"
- apt_repository:
- repo: "deb-src http://repo.zabbix.com/zabbix/{{ zabbix_javagateway_version }}/ubuntu-arm64/ {{ ansible_distribution_release }} main"
- state: present
+- name: "Debian | Download gpg key"
+ ansible.builtin.get_url:
+ url: http://repo.zabbix.com/zabbix-official-repo.key
+ dest: "{{ zabbix_gpg_key }}"
+ mode: "0644"
+ force: true
become: true
- when:
- - ansible_distribution == "Ubuntu"
- - ansible_machine == "aarch64"
- - zabbix_repo == "zabbix"
-
+ tags:
+ - install
-- name: "Debian | Installing repository Ubuntu"
- apt_repository:
- repo: "deb-src http://repo.zabbix.com/zabbix/{{ zabbix_javagateway_version }}/ubuntu/ {{ ansible_distribution_release }} main"
- state: present
+- name: "Debian | Installing repository {{ ansible_distribution }}"
+ ansible.builtin.copy:
+ dest: /etc/apt/sources.list.d/zabbix.sources
+ owner: root
+ group: root
+ mode: 0644
+ content: |
+ Types: deb deb-src
+ Enabled: yes
+ URIs: {{ zabbix_repo_deb_url }}
+ Suites: {{ ansible_distribution_release }}
+ Components: {{ zabbix_repo_deb_component }}
+ Architectures: {{ 'amd64' if ansible_machine != 'aarch64' else 'arm64'}}
+ Signed-By: {{ zabbix_gpg_key }}
become: true
- when:
- - ansible_distribution == "Ubuntu"
- - zabbix_repo == "zabbix"
+ tags:
+ - install
- name: "Debian | Installing zabbix-java-gateway"
- apt:
+ ansible.builtin.apt:
pkg: zabbix-java-gateway
state: "{{ zabbix_javagateway_package_state }}"
update_cache: true
@@ -86,12 +86,17 @@
register: zabbix_java_gateway_install
until: zabbix_java_gateway_install is succeeded
become: true
+ tags:
+ - install
-- name: "Make sure Zabbix Java Gateway is not yet running"
- systemd:
+- name: "Debian | Make sure Zabbix Java Gateway is not yet running"
+ ansible.builtin.systemd:
name: zabbix-java-gateway
state: stopped
enabled: true
daemon_reload: true
+ become: true
when:
- zabbix_java_gateway_install.changed
+ tags:
+ - service
diff --git a/ansible_collections/community/zabbix/roles/zabbix_javagateway/tasks/RedHat.yml b/ansible_collections/community/zabbix/roles/zabbix_javagateway/tasks/RedHat.yml
index 877628381..96d9d3928 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_javagateway/tasks/RedHat.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_javagateway/tasks/RedHat.yml
@@ -2,33 +2,34 @@
# Tasks specific for RedHat systems
- name: "RedHat | Install basic repo file"
- yum_repository:
+ ansible.builtin.yum_repository:
name: "{{ item.name }}"
description: "{{ item.description }}"
baseurl: "{{ item.baseurl }}"
gpgcheck: "{{ item.gpgcheck }}"
gpgkey: "{{ item.gpgkey }}"
mode: "{{ item.mode | default('0644') }}"
- priority: "{{ item.priority | default('98') }}"
+ priority: "{{ item.priority | default('99') }}"
state: "{{ item.state | default('present') }}"
proxy: "{{ zabbix_http_proxy | default(omit) }}"
with_items: "{{ zabbix_repo_yum }}"
register: yum_repo_installed
become: true
- when:
- zabbix_repo == "zabbix"
notify:
- "clean repo files from proxy creds"
+ tags:
+ - install
- name: "RedHat | Installing zabbix-java-gateway"
- package:
+ ansible.builtin.package:
pkg: zabbix-java-gateway
state: "{{ zabbix_javagateway_package_state }}"
- disablerepo: "{{ '*' if (zabbix_repo_yum_enabled | length>0) else omit }}"
- enablerepo: "{{ zabbix_repo_yum_enabled if zabbix_repo_yum_enabled is iterable and (zabbix_repo_yum_enabled | length>0) else omit }}"
+ disablerepo: "{{ zabbix_agent_disable_repo | default(omit) }}"
environment:
http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
register: zabbix_java_gateway_install
until: zabbix_java_gateway_install is succeeded
become: true
+ tags:
+ - install
diff --git a/ansible_collections/community/zabbix/roles/zabbix_javagateway/tasks/main.yml b/ansible_collections/community/zabbix/roles/zabbix_javagateway/tasks/main.yml
index b95322426..6b56d43d3 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_javagateway/tasks/main.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_javagateway/tasks/main.yml
@@ -1,46 +1,53 @@
---
-# tasks file for zabbix_proxy
+# tasks file for zabbix_javagateway
-- name: "Install the correct repository"
- include_tasks: "RedHat.yml"
- when:
- - ansible_os_family == "RedHat"
+- name: Include OS-specific variables
+ ansible.builtin.include_vars: "{{ ansible_os_family }}.yml"
+ tags:
+ - always
-- name: "Install the correct repository"
- include_tasks: "Debian.yml"
- when:
- - ansible_os_family == "Debian"
+- name: Determine Latest Supported Zabbix Version
+ ansible.builtin.set_fact:
+ zabbix_javagateway_version: "{{ zabbix_valid_javagateway_versions[ansible_distribution_major_version][0] | default(6.4) }}"
+ when: zabbix_javagateway_version is not defined
+ tags:
+ - always
-- name: "Place systemd unit file"
- copy:
- src: systemd.service
- dest: /etc/systemd/system/zabbix-java-gateway.service
- mode: '0644'
- register: systemd_state
- when:
- - zabbix_version is version('5.4', '<')
+- name: Set More Variables
+ ansible.builtin.set_fact:
+ zabbix_valid_version: "{{ zabbix_javagateway_version|float in zabbix_valid_javagateway_versions[ansible_distribution_major_version] }}"
+ tags:
+ - always
-- name: "Reload systemd"
- shell: systemctl daemon-reload
- when:
- - zabbix_version is version('5.4', '<')
- - systemd_state.changed
+- name: Stopping Install of Invalid Version
+ ansible.builtin.fail:
+ msg: Zabbix version {{ zabbix_javagateway_version }} is not supported on {{ ansible_distribution }} {{ ansible_distribution_major_version }}
+ when: not zabbix_valid_version
tags:
- - skip_ansible_lint
+ - always
+
+- name: "Install the correct repository"
+ ansible.builtin.include_tasks: "{{ ansible_os_family }}.yml"
- name: "Configure zabbix-proxy"
- template:
+ ansible.builtin.template:
src: zabbix_java_gateway.conf.j2
dest: /etc/zabbix/zabbix_java_gateway.conf
owner: zabbix
group: zabbix
mode: "{{ zabbix_java_gateway_conf_mode }}"
+ become: true
notify:
- zabbix-java-gateway restarted
+ tags:
+ - config
- name: "Make sure Zabbix Java Gateway is running"
- systemd:
+ ansible.builtin.systemd:
name: zabbix-java-gateway
state: started
enabled: true
daemon_reload: true
+ become: true
+ tags:
+ - service
diff --git a/ansible_collections/community/zabbix/roles/zabbix_javagateway/templates/zabbix_java_gateway.conf.j2 b/ansible_collections/community/zabbix/roles/zabbix_javagateway/templates/zabbix_java_gateway.conf.j2
index 9b197600d..7c697cd3b 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_javagateway/templates/zabbix_java_gateway.conf.j2
+++ b/ansible_collections/community/zabbix/roles/zabbix_javagateway/templates/zabbix_java_gateway.conf.j2
@@ -4,7 +4,7 @@
# This configuration file is "minimalized", which means all the original comments
# are removed. The full documentation for your Zabbix Java Gateway can be found here:
-# https://www.zabbix.com/documentation/{{ zabbix_version }}/en/manual/concepts/java
+# https://www.zabbix.com/documentation/{{ zabbix_javagateway_version }}/en/manual/concepts/java
LISTEN_IP={{ zabbix_javagateway_listenip }}
LISTEN_PORT={{ zabbix_javagateway_listenport }}
diff --git a/ansible_collections/community/zabbix/roles/zabbix_javagateway/vars/Debian.yml b/ansible_collections/community/zabbix/roles/zabbix_javagateway/vars/Debian.yml
index 1eecc3170..2253f5b7b 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_javagateway/vars/Debian.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_javagateway/vars/Debian.yml
@@ -1,6 +1,30 @@
----
-apache_user: www-data
-apache_group: www-data
-apache_log: apache2
+zabbix_valid_javagateway_versions:
+ # Debian
+ "12":
+ - 6.4
+ - 6.0
+ "11":
+ - 6.4
+ - 6.2
+ - 6.0
+ "10":
+ - 6.4
+ - 6.2
+ - 6.0
+ # Ubuntu
+ "22":
+ - 6.4
+ - 6.2
+ - 6.0
+ "20":
+ - 6.4
+ - 6.2
+ - 6.0
+ "18":
+ - 6.4
+ - 6.2
+ - 6.0
-mysql_create_dir: ''
+debian_keyring_path: /etc/apt/keyrings/
+zabbix_gpg_key: "{{ debian_keyring_path }}/zabbix-official-repo.asc"
+_zabbix_repo_deb_url: "http://repo.zabbix.com/zabbix/{{ zabbix_javagateway_version }}"
diff --git a/ansible_collections/community/zabbix/roles/zabbix_javagateway/vars/RedHat.yml b/ansible_collections/community/zabbix/roles/zabbix_javagateway/vars/RedHat.yml
index 8c1997706..62af028ff 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_javagateway/vars/RedHat.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_javagateway/vars/RedHat.yml
@@ -1,6 +1,14 @@
---
-apache_user: apache
-apache_group: apache
-apache_log: httpd
-
-mysql_create_dir: create/
+zabbix_valid_javagateway_versions:
+ "9":
+ - 6.4
+ - 6.2
+ - 6.0
+ "8":
+ - 6.4
+ - 6.2
+ - 6.0
+ "7":
+ - 6.4
+ - 6.2
+ - 6.0
diff --git a/ansible_collections/community/zabbix/roles/zabbix_javagateway/vars/zabbix.yml b/ansible_collections/community/zabbix/roles/zabbix_javagateway/vars/zabbix.yml
deleted file mode 100644
index bd960deba..000000000
--- a/ansible_collections/community/zabbix/roles/zabbix_javagateway/vars/zabbix.yml
+++ /dev/null
@@ -1,258 +0,0 @@
----
-sign_keys:
- "64":
- bullseye:
- sign_key: E709712C
- buster:
- sign_key: E709712C
- stretch:
- sign_key: E709712C
- focal:
- sign_key: E709712C
- jammy:
- sign_key: E709712C
- bionic:
- sign_key: E709712C
- xenial:
- sign_key: E709712C
- trusty:
- sign_key: E709712C
- "62":
- bullseye:
- sign_key: E709712C
- buster:
- sign_key: E709712C
- stretch:
- sign_key: E709712C
- focal:
- sign_key: E709712C
- jammy:
- sign_key: E709712C
- bionic:
- sign_key: E709712C
- xenial:
- sign_key: E709712C
- trusty:
- sign_key: E709712C
- "60":
- bullseye:
- sign_key: E709712C
- buster:
- sign_key: E709712C
- stretch:
- sign_key: E709712C
- focal:
- sign_key: E709712C
- jammy:
- sign_key: E709712C
- bionic:
- sign_key: E709712C
- xenial:
- sign_key: E709712C
- trusty:
- sign_key: E709712C
- "54":
- bullseye:
- sign_key: E709712C
- buster:
- sign_key: E709712C
- jessie:
- sign_key: E709712C
- stretch:
- sign_key: E709712C
- focal:
- sign_key: E709712C
- bionic:
- sign_key: E709712C
- xenial:
- sign_key: E709712C
- trusty:
- sign_key: E709712C
- tricia:
- sign_key: E709712C
- "52":
- # bullseye: not available upstream
- buster:
- sign_key: E709712C
- jessie:
- sign_key: E709712C
- stretch:
- sign_key: E709712C
- focal:
- sign_key: E709712C
- bionic:
- sign_key: E709712C
- xenial:
- sign_key: E709712C
- trusty:
- sign_key: E709712C
- tricia:
- sign_key: E709712C
- "50":
- bullseye:
- sign_key: E709712C
- buster:
- sign_key: E709712C
- jessie:
- sign_key: E709712C
- stretch:
- sign_key: E709712C
- focal:
- sign_key: E709712C
- bionic:
- sign_key: E709712C
- xenial:
- sign_key: E709712C
- trusty:
- sign_key: E709712C
- tricia:
- sign_key: E709712C
- "44":
- buster:
- sign_key: A14FE591
- jessie:
- sign_key: 79EA5ED4
- stretch:
- sign_key: A14FE591
- focal:
- sign_key: A14FE591
- eoan:
- sign_key: A14FE591
- cosmic:
- sign_key: A14FE591
- bionic:
- sign_key: A14FE591
- sonya:
- sign_key: A14FE591
- serena:
- sign_key: A14FE591
- trusty:
- sign_key: 79EA5ED4
- xenial:
- sign_key: E709712C
- "42":
- buster:
- sign_key: A14FE591
- jessie:
- sign_key: 79EA5ED4
- stretch:
- sign_key: A14FE591
- eoan:
- sign_key: A14FE591
- cosmic:
- sign_key: A14FE591
- bionic:
- sign_key: A14FE591
- sonya:
- sign_key: A14FE591
- serena:
- sign_key: A14FE591
- trusty:
- sign_key: 79EA5ED4
- xenial:
- sign_key: E709712C
- "40":
- bullseye:
- sign_key: A14FE591
- buster:
- sign_key: A14FE591
- jessie:
- sign_key: 79EA5ED4
- stretch:
- sign_key: A14FE591
- focal:
- sign_key: A14FE591
- bionic:
- sign_key: A14FE591
- sonya:
- sign_key: A14FE591
- serena:
- sign_key: A14FE591
- trusty:
- sign_key: 79EA5ED4
- xenial:
- sign_key: E709712C
- "34":
- jessie:
- sign_key: 79EA5ED4
- stretch:
- sign_key: A14FE591
- wheezy:
- sign_key: A14FE591
- bionic:
- sign_key: A14FE591
- sonya:
- sign_key: A14FE591
- serena:
- sign_key: A14FE591
- trusty:
- sign_key: 79EA5ED4
- xenial:
- sign_key: E709712C
- "32":
- stretch:
- sign_key: A14FE591
- wheezy:
- sign_key: 79EA5ED4
- bionic:
- sign_key: A14FE591
- sonya:
- sign_key: 79EA5ED4
- serena:
- sign_key: 79EA5ED4
- trusty:
- sign_key: 79EA5ED4
- xenial:
- sign_key: E709712C
- "30":
- buster:
- sign_key: A14FE591
- jessie:
- sign_key: 79EA5ED4
- stretch:
- sign_key: A14FE591
- wheezy:
- sign_key: 79EA5ED4
- bionic:
- sign_key: A14FE591
- trusty:
- sign_key: 79EA5ED4
- xenial:
- sign_key: E709712C
- "24":
- jessie:
- sign_key: 79EA5ED4
- wheezy:
- sign_key: 79EA5ED4
- precise:
- sign_key: 79EA5ED4
- trusty:
- sign_key: 79EA5ED4
- "22":
- squeeze:
- sign_key: 79EA5ED4
- wheezy:
- sign_key: 79EA5ED4
- precise:
- sign_key: 79EA5ED4
- trusty:
- sign_key: 79EA5ED4
- lucid:
- sign_key: 79EA5ED4
-
-suse:
- "openSUSE Leap":
- "42":
- name: server:monitoring
- url: http://download.opensuse.org/repositories/server:/monitoring/openSUSE_Leap_{{ ansible_distribution_version }}/
- "openSUSE":
- "12":
- name: server_monitoring
- url: http://download.opensuse.org/repositories/server:/monitoring/openSUSE_{{ ansible_distribution_version }}
- "SLES":
- "11":
- name: server_monitoring
- url: http://download.opensuse.org/repositories/server:/monitoring/SLE_11_SP3/
- "12":
- name: server_monitoring
- url: http://download.opensuse.org/repositories/server:/monitoring/SLE_12_SP3/
diff --git a/ansible_collections/community/zabbix/roles/zabbix_proxy/README.md b/ansible_collections/community/zabbix/roles/zabbix_proxy/README.md
index 6682f6c18..baec42155 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_proxy/README.md
+++ b/ansible_collections/community/zabbix/roles/zabbix_proxy/README.md
@@ -77,24 +77,17 @@ ansible-galaxy collection install community.postgresql
See the following list of supported Operating systems with the Zabbix releases.
-| Zabbix | 6.4 | 6.2 | 6.0 | 5.4 | 5.2 | 5.0 (LTS)| 4.4 | 4.0 (LTS) | 3.0 (LTS) |
-|---------------------|-----|-----|-----|-----|-----|-----------|-----|-----------|-----------|
-| Red Hat Fam 9 | V | V | V | | | | | | |
-| Red Hat Fam 8 | V | V | V | V | V | V | V | | |
-| Red Hat Fam 7 | V | V | V | V | V | V | V | V | V |
-| Red Hat Fam 6 | | | | | V | V | | | V |
-| Red Hat Fam 5 | | | | | V | V | | | V |
-| Fedora | | | | | | | V | V | |
-| Ubuntu 20.04 focal | V | V | V | V | V | V | | V | |
-| Ubuntu 18.04 bionic | | | V | V | V | V | V | V | |
-| Ubuntu 16.04 xenial | | | | | V | V | V | V | |
-| Ubuntu 14.04 trusty | | | | | V | V | V | V | V |
-| Debian 10 buster | V | | V | V | V | V | V | | |
-| Debian 9 stretch | V | | V | V | V | V | V | V | |
-| Debian 8 jessie | | | | | V | V | V | V | V |
-| Debian 7 wheezy | | | | | | | | V | V |
-| macOS 10.15 | | | | | | | V | V | |
-| macOS 10.14 | | | | | | | V | V | |
+| Zabbix | 6.4 | 6.2 | 6.0 |
+|---------------------|-----|-----|-----|
+| Red Hat Fam 9 | V | V | V |
+| Red Hat Fam 8 | V | V | V |
+| Red Hat Fam 7 | V | V | V |
+| Ubuntu 22.04 jammy | V | V | V |
+| Ubuntu 20.04 focal | V | V | V |
+| Ubuntu 18.04 bionic | V | V | V |
+| Debian 12 bookworm | V | | V |
+| Debian 11 bullseye | V | V | V |
+| Debian 10 buster | V | V | V |
# Role Variables
@@ -102,104 +95,49 @@ See the following list of supported Operating systems with the Zabbix releases.
The following is an overview of all available configuration default for this role.
-### Overall Zabbix
-
-* `zabbix_proxy_version`: This is the version of zabbix. Default: The highest supported version for the operating system. Can be overridden to 6.2, 6.0, 5.4, 5.2, 5.0, 4.4, 4.0, 3.4, 3.2, 3.0, 2.4, or 2.2. Previously the variable `zabbix_version` was used directly but it could cause [some inconvenience](https://github.com/dj-wasabi/ansible-zabbix-agent/pull/303). That variable is maintained by retrocompativility.
-* `zabbix_proxy_version_minor`: When you want to specify a minor version to be installed. RedHat only. Default set to: `*` (latest available)
-* `zabbix_repo`: Default: `zabbix`
- * `epel`: install agent from EPEL repo
- * `zabbix`: (default) install agent from Zabbix repo
- * `other`: install agent from pre-existing or other repo
-* `zabbix_repo_yum`: A list with Yum repository configuration.
-* `zabbix_repo_yum_schema`: Default: `https`. Option to change the web schema for the yum repository(http/https)
-* `zabbix_repo_yum_disabled`: A string with repository names that should be disabled when installing Zabbix component specific packages. Is only used when `zabbix_repo_yum_enabled` contains 1 or more repositories. Default `*`.
-* `zabbix_repo_yum_enabled`: A list with repository names that should be enabled when installing Zabbix component specific packages.
-
-### SElinux
-
-* `zabbix_selinux`: Default: `False`. Enables an SELinux policy so that the Proxy will run.
-
### Zabbix Proxy
+* `zabbix_proxy_version`: Optional. The latest available major.minor version of Zabbix will be installed on the host(s). If you want to use an older version, please specify this in the major.minor format. Example: `zabbix_proxy_version: 6.0`.
+* `zabbix_proxy_version_minor`: When you want to specify a minor version to be installed. RedHat only. Default set to: `*` (latest available)
* `zabbix_proxy_ip`: The IP address of the host. When not provided, it will be determined via the `ansible_default_ipv4` fact.
* `zabbix_proxy_server`: The ip or dns name for the zabbix-server machine.
-* `zabbix_proxy_serverport`: The port on which the zabbix-server is running. Default: 10051
-* `*zabbix_proxy_package_state`: Default: `present`. Can be overridden to `latest` to update packages
* `zabbix_proxy_install_database_client`: Default: `True`. False does not install database client.
-* `zabbix_proxy_become_on_localhost`: Default: `True`. Set to `False` if you don't need to elevate privileges on localhost to install packages locally with pip.
* `zabbix_proxy_manage_service`: Default: `True`. When you run multiple Zabbix proxies in a High Available cluster setup (e.g. pacemaker), you don't want Ansible to manage the zabbix-proxy service, because Pacemaker is in control of zabbix-proxy service.
-* `zabbix_install_pip_packages`: Default: `True`. Set to `False` if you don't want to install the required pip packages. Useful when you control your environment completely.
-* `zabbix_proxy_startpreprocessors`: Number of pre-forked instances of preprocessing workers. The preprocessing manager process is automatically started when a preprocessor worker is started.This parameter is supported since Zabbix 4.2.0.
-* `zabbix_proxy_username`: Default: `zabbix`. The name of the account on the host. Will only be used when `zabbix_repo: epel` is used.
-* `zabbix_proxy_logtype`: Specifies where log messages are written to: system, file, console.
-* `zabbix_proxy_logfile`: Name of log file.
-* `zabbix_proxy_userid`: The UID of the account on the host. Will only be used when `zabbix_repo: epel` is used.
-* `zabbix_proxy_groupname`: Default: `zabbix`. The name of the group of the user on the host. Will only be used when `zabbix_repo: epel` is used.
-* `zabbix_proxy_groupid`: The GID of the group on the host. Will only be used when `zabbix_repo: epel` is used.
* `zabbix_proxy_include_mode`: Default: `0755`. The "mode" for the directory configured with `zabbix_proxy_include`.
* `zabbix_proxy_conf_mode`: Default: `0644`. The "mode" for the Zabbix configuration file.
-* `zabbix_proxy_statsallowedip`: Default: `127.0.0.1`. Allowed IP foe remote gathering of the ZabbixPorixy internal metrics.
-* `zabbix_proxy_vaulttoken`: Vault authentication token that should have been generated exclusively for Zabbix server with read only permission
-* `zabbix_proxy_vaulturl`: Vault server HTTP[S] URL. System-wide CA certificates directory will be used if SSLCALocation is not specified.
-* `zabbix_proxy_vaultdbpath`: Vault path from where credentials for database will be retrieved by keys 'password' and 'username'.
-* `zabbix_proxy_listenbacklog`: The maximum number of pending connections in the queue.
### Database specific
* `zabbix_proxy_dbhost_run_install`: Default: `True`. When set to `True`, sql files will be executed on the host running the database.
* `zabbix_proxy_database`: Default: `mysql`. The type of database used. Can be: `mysql`, `pgsql` or `sqlite3`
-* `zabbix_proxy_database_long`: Default: `mysql`. The type of database used, but long name. Can be: `mysql`, `postgresql` or `sqlite3`
-* `zabbix_proxy_dbhost`: The hostname on which the database is running. Will be ignored when `sqlite3` is used as database.
+* `zabbix_proxy_dbhost`: Default: localhost. The hostname on which the database is running. Will be ignored when `sqlite3` is used as database.
* `zabbix_proxy_real_dbhost`: The hostname of the dbhost that is running behind a loadbalancer/VIP (loadbalancers doesn't accept ssh connections) Will be ignored when `sqlite3` is used as database.
-* `zabbix_proxy_dbname`: The database name which is used by the Zabbix Proxy.
-* `zabbix_proxy_dbuser`: The database username which is used by the Zabbix Proxy. Will be ignored when `sqlite3` is used as database.
-* `zabbix_proxy_dbpassword`: The database user password which is used by the Zabbix Proxy. Will be ignored when `sqlite3` is used as database.
+* `zabbix_proxy_dbname`: Default: zabbix_proxy. The database name which is used by the Zabbix Proxy.
+* `zabbix_proxy_dbuser`: Default: zabbix_proxy. The database username which is used by the Zabbix Proxy. Will be ignored when `sqlite3` is used as database.
+* `zabbix_proxy_dbpassword`: Default: zabbix_proxy. The database user password which is used by the Zabbix Proxy. Will be ignored when `sqlite3` is used as database.
+* `zabbix_proxy_dbpassword_hash_method`: Default: `md5`. Allow switching postgresql user password creation to `scram-sha-256`, when anything other than `md5` is used then ansible won't hash the password with `md5`.
* `zabbix_proxy_dbport`: The database port which is used by the Zabbix Proxy. Will be ignored when `sqlite3` is used as database.
-* `zabbix_database_creation`: Default: `True`. When you don't want to create the database including user, you can set it to False.
+* `zabbix_proxy_database_creation`: Default: `True`. When you don't want to create the database including user, you can set it to False.
* `zabbix_proxy_install_database_client`: Default: `True`. False does not install database client. Default true
-* `zabbix_database_sqlload`:True / False. When you don't want to load the sql files into the database, you can set it to False.
+* `zabbix_proxy_database_sqlload`:True / False. When you don't want to load the sql files into the database, you can set it to False.
* `zabbix_proxy_dbencoding`: Default: `utf8`. The encoding for the MySQL database.
* `zabbix_proxy_dbcollation`: Default: `utf8_bin`. The collation for the MySQL database.zabbix_proxy_
-* `zabbix_server_allowunsupporteddbversions`: Allow proxy to work with unsupported database versions.
-* `zabbix_proxy_dbpassword_hash_method`: Default: `md5`. Allow switching postgresql user password creation to `scram-sha-256`, when anything other than `md5` is used then ansible won't hash the password with `md5`.
-### TLS Specific configuration
-
-These variables are specific for Zabbix 3.0 and higher:
-
-* `zabbix_proxy_tlsconnect`: How the agent should connect to server or proxy. Used for active checks.
- Possible values:
- * unencrypted
- * psk
- * cert
-* `zabbix_proxy_tlsaccept`: What incoming connections to accept.
- Possible values:
- * unencrypted
- * psk
- * cert
-* `zabbix_proxy_tlscafile`: Full pathname of a file containing the top-level CA(s) certificates for peer certificate verification.
-* `zabbix_proxy_tlscrlfile`: Full pathname of a file containing revoked certificates.
-* `zabbix_proxy_tlsservercertissuer`: Allowed server certificate issuer.
-* `zabbix_proxy_tlsservercertsubject`: Allowed server certificate subject.
-* `zabbix_proxy_tlscertfile`: Full pathname of a file containing the agent certificate or certificate chain.
-* `zabbix_proxy_tlskeyfile`: Full pathname of a file containing the agent private key.
-* `zabbix_proxy_dbtlsconnect`: Setting this option enforces to use TLS connection to database:
-
-`required` - connect using TLS
-`verify_ca` - connect using TLS and verify certificate
-`verify_full` - connect using TLS, verify certificate and verify that database identity specified by DBHost matches its certificate
-
-On `MySQL` starting from 5.7.11 and `PostgreSQL` the following values are supported: `required`, `verify`, `verify_full`. On MariaDB starting from version 10.2.6 `required` and `verify_full` values are supported.
-By default not set to any option and the behaviour depends on database configuration.
-This parameter is supported since Zabbix 5.0.0.
-
-* `zabbix_proxy_dbtlscafile`: Full pathname of a file containing the top-level CA(s) certificates for database certificate verification. This parameter is supported since Zabbix 5.0.0.
-* `zabbix_proxy_dbtlscertfile`: Full pathname of file containing Zabbix Proxy certificate for authenticating to database. This parameter is supported since Zabbix 5.0.0.
-* `zabbix_proxy_dbtlskeyfile`: Full pathname of file containing the private key for authenticating to database. This parameter is supported since Zabbix 5.0.0.
-* `zabbix_proxy_dbtlscipher`: The list of encryption ciphers that Zabbix Proxy permits for TLS protocols up through TLSv1.2. Supported only for MySQL.This parameter is supported since Zabbix 5.0.0.
-* `zabbix_proxy_dbtlscipher13`: The list of encryption ciphersuites that Zabbix Proxy permits for TLSv1.3 protocol. Supported only for MySQL, starting from version 8.0.16. This parameter is supported since Zabbix 5.0.0.
-
-## proxy
+
+### Yum/APT
+* `zabbix_repo_yum`: A list with Yum repository configuration.
+* `zabbix_repo_yum_schema`: Default: `https`. Option to change the web schema for the yum repository(http/https)
+* `zabbix_repo_yum_gpgcheck`: Default: `0`. Should yum perform a GPG check on the repository
+* `zabbix_proxy_disable_repo`: A list of repos to disable during install. Default `epel`.
+* `zabbix_proxy_apt_priority`: APT priority for the zabbix repository
+* `*zabbix_proxy_package_state`: Default: `present`. Can be overridden to `latest` to update packages
+* `zabbix_repo_deb_url`: The URL to the Zabbix repository. Default `http://repo.zabbix.com/zabbix/{{ zabbix_proxy_version }}/{{ ansible_distribution.lower() }}`
+* `zabbix_repo_deb_component`: The repository component for Debian installs. Default `main`.
+### SElinux
+
+* `zabbix_proxy_selinux`: Default: `False`. Enables an SELinux policy so that the Proxy will run.
+
+## Proxy
When the target host does not have access to the internet, but you do have a proxy available then the following properties needs to be set to download the packages via the proxy:
@@ -210,9 +148,9 @@ When the target host does not have access to the internet, but you do have a pro
With Zabbix Proxy you can make use of 2 different databases:
-* `mysql`
-* `postgresql`
-* `SQLite3`
+* MySQL
+* PostgreSQL
+* SQLite3
In the following paragraphs we dive into both setups.
@@ -232,12 +170,12 @@ We need to have the following dependencies met:
```yaml
zabbix_proxy_database: mysql
-zabbix_proxy_database_long: mysql
zabbix_proxy_dbport: 3306
zabbix_proxy_dbpassword: <SOME_SECRET_STRING>
```
Please generate a value for the `zabbix_proxy_dbpassword` property (Maybe use `ansible-vault` for this). The zabbix-proxy role will create an database and username (With the provided value for the password) in `MySQL`.
+
3. Execute the role by running the Ansible playbook that calls this role. At the end of this run, the Zabbix Proxy with `MySQL` will be running.
#### Separate Setup
@@ -249,7 +187,6 @@ We need to have the following dependencies met:
```yaml
zabbix_proxy_database: mysql
-zabbix_proxy_database_long: mysql
zabbix_proxy_dbport: 3306
zabbix_proxy_dbhost: mysql-host
zabbix_proxy_dbhost_run_install: false
@@ -283,7 +220,6 @@ We need to have the following dependencies met:
```yaml
zabbix_proxy_database: pgsql
-zabbix_proxy_database_long: postgresql
zabbix_proxy_dbport: 5432
zabbix_proxy_dbpassword: <SOME_SECRET_STRING>
```
@@ -300,7 +236,6 @@ We need to have the following dependencies met:
```yaml
zabbix_proxy_database: pgsql
-zabbix_proxy_database_long: postgresql
zabbix_proxy_dbport: 5432
zabbix_proxy_dbhost: pgsql-host
zabbix_proxy_dbhost_run_install: false
@@ -326,7 +261,6 @@ The following properties needs to be set when using `SQLite3` as the database:
```yaml
zabbix_proxy_database: sqlite3
-zabbix_proxy_database_long: sqlite3
zabbix_proxy_dbname: /path/to/sqlite3.db
```
@@ -336,20 +270,140 @@ NOTE: When using `zabbix_proxy_dbname: zabbix_proxy` (Which is default with this
These variables need to be overridden when you want to make use of the Zabbix API for automatically creating and or updating proxies, i.e. when `zabbix_api_create_proxy` is set to `True`.
-* `zabbix_api_http_user`: The http user to access zabbix url with Basic Auth.
-* `zabbix_api_http_password`: The http password to access zabbix url with Basic Auth.
* `zabbix_api_server_host`: The IP or hostname/FQDN of Zabbix server. Example: zabbix.example.com
-* `zabbix_api_server_port`: TCP port to use to connect to Zabbix server. Example: 8080
-* `zabbix_api_use_ssl`: yes (Default) if we need to connect to Zabbix server over HTTPS
-* `zabbix_api_validate_certs` : yes (Default) if we need to validate tls certificates of the API. Use `no` in case self-signed certificates are used
+* `zabbix_api_use_ssl`: Is SSL required to connect to the Zabbix API server? Default: `false`
+* `zabbix_api_server_port`: 80 if `zabbix_api_use_ssl` is `false` and 443 if `true` (Default) TCP port to use to connect to Zabbix server. Example: 8080
* `zabbix_api_login_user`: Username of user which has API access.
* `zabbix_api_login_pass`: Password for the user which has API access.
+* `zabbix_api_http_user`: The http user to access zabbix url with Basic Auth (if your Zabbix is behind a proxy with HTTP Basic Auth).
+* `zabbix_api_http_password`: The http password to access zabbix url with Basic Auth (if your Zabbix is behind a proxy with HTTP Basic Auth).
+* `zabbix_api_validate_certs`: yes (Default) if we need to validate tls certificates of the API. Use `no` in case self-signed certificates are used.
+* `zabbix_api_timeout`: timeout for API calls (default to 30 seconds)
* `ansible_zabbix_url_path`: URL path if Zabbix WebUI running on non-default (zabbix) path, e.g. if http://<FQDN>/zabbixeu then set to `zabbixeu`
* `zabbix_api_create_proxy`: When you want to enable the Zabbix API to create/delete the proxy. This has to be set to `True` if you want to make use of `zabbix_proxy_state`. Default: `False`
* `zabbix_proxy_name`: name of the Zabbix proxy as it is seen by Zabbix server
* `zabbix_proxy_state`: present (Default) if the proxy needs to be created or absent if you want to delete it. This only works when `zabbix_api_create_proxy` is set to `True`.
* `zabbix_proxy_status`: active (Default) if the proxy needs to be active or passive.
-* `zabbix_api_timeout`: timeout for API calls (default to 30 seconds)
+
+## Configuration Variables
+
+The following table lists all variables that are exposed to modify the configuration of the zabbix_proxy.conf file. Specific details of each variable can be found in the Zabbix documentation.
+
+**NOTE**: Only variables with a default value appear in the defaults file, all others must be added.
+
+| Zabbix Name | Variable Name | Default Value |Notes |
+|-----------|------------------|--------|--------|
+| AllowRoot | zabbix_proxy_allowroot |0| |
+| AllowUnsupportedDBVersions | zabbix_proxy_allowunsupporteddbversions |0| |
+| CacheSize | zabbix_proxy_cachesize | 8M| |
+| ConfigFrequency | zabbix_proxy_configfrequency |3600| |
+| DataSenderFrequency | zabbix_proxy_datasenderfrequency |1| |
+| DBHost | zabbix_proxy_dbhost | localhost| |
+| DBName | zabbix_proxy_dbname | zabbix_proxy| |
+| DBPassword | zabbix_proxy_dbpassword | zabbix_proxy| |
+| DBSchema | zabbix_proxy_dbschema || |
+| DBSocket | zabbix_proxy_dbsocket || |
+| DBTLSCAFile | zabbix_proxy_dbtlscafile || |
+| DBTLSCertFile | zabbix_proxy_dbtlscertfile || |
+| DBTLSCipher | zabbix_proxy_dbtlscipher || |
+| DBTLSCipher13 | zabbix_proxy_dbtlscipher13 || |
+| DBTLSConnect | zabbix_proxy_dbtlsconnect || |
+| DBTLSKeyFile | zabbix_proxy_dbtlskeyfile || |
+| DBUser | zabbix_proxy_dbuser | zabbix_proxy| |
+| DebugLevel | zabbix_proxy_debuglevel |3| |
+| EnableRemoteCommands | zabbix_proxy_enableremotecommands |0| |
+| ExternalScripts | zabbix_proxy_externalscripts | /usr/lib/zabbix/externalscripts| |
+| Fping6Location | zabbix_proxy_fping6location | OS Specific Value | |
+| FpingLocation | zabbix_proxy_fpinglocation | OS Specific Value | |
+| HeartbeatFrequency | zabbix_proxy_heartbeatfrequency |60| Version 6.2 or Lower|
+| HistoryCacheSize | zabbix_proxy_historycachesize | 8M| |
+| HistoryIndexCacheSize | zabbix_proxy_historyindexcachesize | 4M| |
+| Hostname | zabbix_proxy_hostname | "{{ inventory_hostname }}"| |
+| HostnameItem | zabbix_proxy_hostnameitem || |
+| HousekeepingFrequency | zabbix_proxy_housekeepingfrequency |1| |
+| Include | zabbix_proxy_include | /etc/zabbix/zabbix_proxy.conf.d| |
+| JavaGateway | zabbix_proxy_javagateway || |
+| JavaGatewayPort | zabbix_proxy_javagatewayport |10052| |
+| ListenBacklog | zabbix_proxy_listenbacklog || |
+| ListenIP | zabbix_proxy_listenip || |
+| ListenPort | zabbix_proxy_listenport |10051| |
+| LoadModule | zabbix_proxy_loadmodule || |
+| LoadModulePath | zabbix_proxy_loadmodulepath | /usr/lib/zabbix/modules| |
+| LogFile | zabbix_proxy_logfile | /var/log/zabbix/zabbix_proxy.log| |
+| LogFileSize | zabbix_proxy_logfilesize |10| |
+| LogRemoteCommands | zabbix_proxy_logremotecommands || |
+| LogSlowQueries | zabbix_proxy_logslowqueries || |
+| LogType | zabbix_proxy_logtype | file| |
+| PidFile | zabbix_proxy_pidfile | /var/run/zabbix/zabbix_proxy.pid| |
+| ProxyLocalBuffer | zabbix_proxy_proxylocalbuffer |0| |
+| ProxyMode | zabbix_proxy_proxymode || |
+| ProxyOfflineBuffer | zabbix_proxy_proxyofflinebuffer |1| |
+| Server | zabbix_proxy_server | 192.168.1.1| |
+| SNMPTrapperFile | zabbix_proxy_snmptrapperfile | /tmp/zabbix_traps.tmp| |
+| SocketDir | zabbix_proxy_socketdir | /var/run/zabbix| |
+| SourceIP | zabbix_proxy_sourceip || |
+| SSHKeyLocation | zabbix_proxy_sshkeylocation || |
+| SSLCALocation | zabbix_proxy_sslcalocation || |
+| SSLCertLocation | zabbix_proxy_sslcertlocation || |
+| SSLKeyLocation | zabbix_proxy_sslkeylocation || |
+| StartDBSyncers | zabbix_proxy_startdbsyncers |4| |
+| StartDiscoverers | zabbix_proxy_startdiscoverers |1| |
+| StartHTTPPollers | zabbix_proxy_starthttppollers |1| |
+| StartIPMIPollers | zabbix_proxy_startipmipollers |0| |
+| StartJavaPollers | zabbix_proxy_startjavapollers || |
+| StartODBCPollers | zabbix_proxy_startodbcpollers |1| |
+| StartPingers | zabbix_proxy_startpingers |1| |
+| StartPollers | zabbix_proxy_startpollers |5| |
+| StartPollersUnreachable | zabbix_proxy_startpollersunreachable |1| |
+| StartPreprocessors | zabbix_proxy_startpreprocessors |3| |
+| StartSNMPTrapper | zabbix_proxy_startsnmptrapper || |
+| StartTrappers | zabbix_proxy_starttrappers |5| |
+| StartVMwareCollectors | zabbix_proxy_startvmwarecollectors || |
+| StatsAllowedIP | zabbix_proxy_statsallowedip | "127.0.0.1"| |
+| Timeout | zabbix_proxy_timeout |3| |
+| TLSAccept | zabbix_proxy_tlsaccept || |
+| TLSCAFile | zabbix_proxy_tlscafile || |
+| TLSCertFile | zabbix_proxy_tlscertfile || |
+| TLSCipherAll | zabbix_proxy_tlscipherall || |
+| TLSCipherAll13 | zabbix_proxy_tlscipherall13 || |
+| TLSCipherCert | zabbix_proxy_tlsciphercert || |
+| TLSCipherCert13 | zabbix_proxy_tlsciphercert13 || |
+| TLSCipherPSK | zabbix_proxy_tlscipherpsk || |
+| TLSCipherPSK13 | zabbix_proxy_tlscipherpsk13 || |
+| TLSConnect | zabbix_proxy_tlsconnect || |
+| TLSCRLFile | zabbix_proxy_tlscrlfile || |
+| TLSKeyFile | zabbix_proxy_tlskeyfile || |
+| TLSPSKFile | zabbix_proxy_tlspskfile || |
+| TLSPSKIdentity | zabbix_proxy_tlspskidentity || |
+| TLSServerCertIssuer | zabbix_proxy_tlsservercertissuer || |
+| TLSServerCertSubject | zabbix_proxy_tlsservercertsubject || |
+| TmpDir | zabbix_proxy_tmpdir | /tmp| |
+| TrapperTimeout | zabbix_proxy_trappertimeout |300| |
+| UnavailableDelay | zabbix_proxy_unavailabledelay || |
+| UnreachableDelay | zabbix_proxy_unreachabledelay || |
+| UnreachablePeriod | zabbix_proxy_unreachableperiod |45| |
+| User | zabbix_proxy_user || |
+| Vault | zabbix_proxy_vault || Version 6.2 or Greater |
+| VaultDBPath | zabbix_proxy_vaultdbpath || |
+| VaultTLSCertFile | zabbix_proxy_vaulttlscertfile || Version 6.2 or Greater |
+| VaultTLSKeyFile | zabbix_proxy_vaulttlskeyfile || Version 6.2 or Greater |
+| VaultToken | zabbix_proxy_vaulttoken || |
+| VaultURL | zabbix_proxy_vaulturl |https://127.0.0.1:8200| |
+| VMwareCacheSize | zabbix_proxy_vmwarecachesize | 8M| |
+| VMwareFrequency | zabbix_proxy_vmwarefrequency |60| |
+| VMwarePerfFrequency | zabbix_proxy_vmwareperffrequency | | |
+| VMwareTimeout | zabbix_proxy_vmwaretimeout | | |
+
+## Tags
+
+The majority of tasks within this role are tagged as follows:
+
+* `install`: Tasks associated with the installation of software.
+* `dependencies`: Installation tasks related to dependencies that aren't part of the core zabbix installation.
+* `database`: Tasks associated with the installation or configuration of the database.
+* `api`: Tasks associated with using the Zabbix API to connect and modify the Zabbix server.
+* `config`: Tasks associated with the configuration of Zabbix or a supporting service.
+* `service`: Tasks associated with managing a service.
# Example Playbook
@@ -361,7 +415,6 @@ Including an example of how to use your role (for instance, with variables passe
- role: community.zabbix.zabbix_proxy
zabbix_proxy_server: 192.168.1.1
zabbix_proxy_database: mysql
- zabbix_proxy_database_long: mysql
```
# Molecule
@@ -385,3 +438,4 @@ See LICENCE to see the full text.
Please send suggestion or pull requests to make this role better. Also let us know if you encounter any issues installing or using this role.
Github: https://github.com/ansible-collections/community.zabbix
+
diff --git a/ansible_collections/community/zabbix/roles/zabbix_proxy/defaults/main.yml b/ansible_collections/community/zabbix/roles/zabbix_proxy/defaults/main.yml
index 82a70cb09..f46c9c64e 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_proxy/defaults/main.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_proxy/defaults/main.yml
@@ -1,32 +1,53 @@
---
# defaults file for zabbix_proxy
+# zabbix_proxy_version: 6.4
+zabbix_os_user: zabbix
+zabbix_proxy_selinux: false
+zabbix_proxy_interface:
+ useip: "{{ zabbix_useuip }}"
+ ip: "{{ zabbix_proxy_ip }}"
+ dns: "{{ ansible_fqdn }}"
+ port: "{{ zabbix_proxy_listenport }}"
+zabbix_useuip: 1
-# zabbix_proxy_version: 6.0
-zabbix_proxy_version_minor: "*"
-zabbix_version: "{{ zabbix_proxy_version }}"
-zabbix_selinux: false
-
-# These variables are optional. They specify the version of Zabbix proxy package.
+# Database
+zabbix_proxy_database: mysql
+zabbix_proxy_database_creation: true
+zabbix_proxy_database_sqlload: true
+zabbix_proxy_dbhost_run_install: true
+zabbix_proxy_dbcollation: utf8_bin
+zabbix_proxy_dbencoding: utf8
+zabbix_proxy_dbhost: localhost
+zabbix_proxy_dbname: zabbix_proxy
+zabbix_proxy_dbpassword: zabbix_proxy
+zabbix_proxy_dbpassword_hash_method: md5
+zabbix_proxy_dbuser: zabbix_proxy
+zabbix_proxy_install_database_client: true
-# zabbix_proxy_rhel_version: 4.4.4
-# zabbix_proxy_debian_version: 1:4.4.4-1+stretch
-# zabbix_proxy_ubuntu_version: 1:4.4.4-1+xenial
+# Misc.
+zabbix_proxy_cat_cmd: cat
+zabbix_proxy_conf_mode: "0644"
+zabbix_proxy_config: /etc/zabbix/zabbix_proxy.conf
+zabbix_proxy_include_mode: "0755"
+zabbix_proxy_manage_service: true
+zabbix_proxy_privileged_host: localhost
+zabbix_proxy_server: 192.168.1.1
+zabbix_proxy_tls_config:
+ no_encryption: "no_encryption"
+ psk: "PSK"
+ cert: "certificate"
+zabbix_proxy_version_minor: "*"
-zabbix_repo: zabbix
-zabbix_proxy_apt_priority:
-zabbix_proxy_package_state: present
-zabbix_proxy_install_recommends: true
-zabbix_proxy_install_database_client: true
-zabbix_install_pip_packages: true
+# Yum/APT Variables
zabbix_repo_yum_schema: https
-zabbix_proxy_conf_mode: "0644"
zabbix_repo_yum_gpgcheck: 0
-zabbix_repo_yum_disabled: "*"
-zabbix_repo_yum_enabled: []
+zabbix_repo_deb_component: main
+zabbix_proxy_disable_repo:
+ - epel
zabbix_repo_yum:
- name: zabbix
description: Zabbix Official Repository - $basearch
- baseurl: "{{ zabbix_repo_yum_schema }}://repo.zabbix.com/zabbix/{{ zabbix_version | regex_search('^[0-9]+.[0-9]+') }}/rhel/{{ ansible_distribution_major_version }}/$basearch/"
+ baseurl: "{{ zabbix_repo_yum_schema }}://repo.zabbix.com/zabbix/{{ zabbix_proxy_version | regex_search('^[0-9]+.[0-9]+') }}/rhel/{{ ansible_distribution_major_version }}/$basearch/"
gpgcheck: "{{ zabbix_repo_yum_gpgcheck }}"
mode: "0644"
gpgkey: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ZABBIX
@@ -38,159 +59,71 @@ zabbix_repo_yum:
gpgcheck: "{{ zabbix_repo_yum_gpgcheck }}"
gpgkey: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ZABBIX
state: present
+zabbix_proxy_apt_priority:
+zabbix_proxy_package_state: present
-# User (EPEL specific)
-zabbix_proxy_username: zabbix
-zabbix_proxy_groupname: zabbix
-
-zabbix_server_host: 192.168.1.1 # Will be deprecated in 2.0.0
-zabbix_proxy_server: "{{ zabbix_server_host }}"
-zabbix_server_port: 10051 # Will be deprecated in 2.0.0
-zabbix_proxy_serverport: "{{ zabbix_server_port }}"
-zabbix_database_creation: true
-zabbix_database_sqlload: true
-zabbix_proxy_dbtlsconnect:
-zabbix_proxy_dbtlscafile:
-zabbix_proxy_dbtlscertfile:
-zabbix_proxy_dbtlskeyfile:
-zabbix_proxy_dbtlscipher:
-zabbix_proxy_dbtlscipher13:
+# Proxy Configuration Variables (Only ones with role provided defaults)
+zabbix_proxy_allowroot: 0
zabbix_proxy_allowunsupporteddbversions: 0
-
-# Some role specific vars
-zabbix_proxy_database: mysql
-zabbix_proxy_database_long: mysql
-# zabbix_proxy_database: pgsql
-# zabbix_proxy_database_long: postgresql
-# zabbix_proxy_database: sqlite3
-# zabbix_proxy_database_long: sqlite3
-
-# zabbix-proxy specific vars
-zabbix_proxy_mode: 0
+zabbix_proxy_cachesize: 8M
+zabbix_proxy_configfrequency: 3600
+zabbix_proxy_datasenderfrequency: 1
+zabbix_proxy_dbport: 5432
+zabbix_proxy_debuglevel: 3
+zabbix_proxy_enableremotecommands: 0
+zabbix_proxy_externalscripts: /usr/lib/zabbix/externalscripts
+zabbix_proxy_heartbeatfrequency: 60
+zabbix_proxy_historycachesize: 8M
+zabbix_proxy_historyindexcachesize: 4M
zabbix_proxy_hostname: "{{ inventory_hostname }}"
+zabbix_proxy_housekeepingfrequency: 1
+zabbix_proxy_include: /etc/zabbix/zabbix_proxy.conf.d
+zabbix_proxy_javagatewayport: 10052
+zabbix_proxy_libdir: /usr/lib/zabbix
zabbix_proxy_listenport: 10051
-zabbix_proxy_sourceip:
-zabbix_proxy_logtype: file
+zabbix_proxy_loadmodulepath: "{{ zabbix_proxy_libdir }}/modules"
zabbix_proxy_logfile: /var/log/zabbix/zabbix_proxy.log
zabbix_proxy_logfilesize: 10
-zabbix_proxy_enableremotecommands: 0
-zabbix_proxy_debuglevel: 3
+zabbix_proxy_logtype: file
zabbix_proxy_pidfile: /var/run/zabbix/zabbix_proxy.pid
+zabbix_proxy_proxylocalbuffer: 0
+zabbix_proxy_proxyofflinebuffer: 1
+zabbix_proxy_snmptrapperfile: /tmp/zabbix_traps.tmp
zabbix_proxy_socketdir: /var/run/zabbix
-zabbix_proxy_dbencoding: utf8
-zabbix_proxy_dbcollation: utf8_bin
-zabbix_proxy_dbhost: localhost
-zabbix_proxy_dbname: zabbix_proxy
-zabbix_proxy_dbschema:
-zabbix_proxy_dbuser: zabbix_proxy
-zabbix_proxy_dbpassword: zabbix_proxy
-zabbix_proxy_dbsocket:
-zabbix_proxy_dbport: 5432
-zabbix_proxy_dbpassword_hash_method: md5
+zabbix_proxy_startdbsyncers: 4
+zabbix_proxy_startdiscoverers: 1
+zabbix_proxy_starthttppollers: 1
+zabbix_proxy_startipmipollers: 0
zabbix_proxy_startodbcpollers: 1
-zabbix_proxy_dbhost_run_install: true
-zabbix_proxy_privileged_host: localhost
-zabbix_proxy_localbuffer: 0 # Will be deprecated in 2.0.0
-zabbix_proxy_proxylocalbuffer: "{{ zabbix_proxy_localbuffer }}"
-zabbix_proxy_offlinebuffer: 1 # Will be deprecated in 2.0.0
-zabbix_proxy_proxyofflinebuffer: "{{ zabbix_proxy_offlinebuffer }}"
-zabbix_proxy_heartbeatfrequency: 60
-zabbix_proxy_configfrequency: 3600
-zabbix_proxy_datasenderfrequency: 1
+zabbix_proxy_startpingers: 1
zabbix_proxy_startpollers: 5
-zabbix_proxy_startipmipollers: 0
zabbix_proxy_startpollersunreachable: 1
-zabbix_proxy_starttrappers: 5
-zabbix_proxy_startpingers: 1
-zabbix_proxy_startdiscoverers: 1
-zabbix_proxy_starthttppollers: 1
zabbix_proxy_startpreprocessors: 3
-zabbix_proxy_javagateway:
-zabbix_proxy_javagatewayport: 10052
-zabbix_proxy_startjavapollers: 5
-zabbix_proxy_startvmwarecollector: 0
-zabbix_proxy_vmwarefrequency: 60
-zabbix_proxy_vmwarecachesize: 8
-zabbix_proxy_snmptrapperfile: /tmp/zabbix_traps.tmp
-zabbix_proxy_snmptrapper: 0
-zabbix_proxy_listenip:
-zabbix_proxy_housekeepingfrequency: 1
-zabbix_proxy_cachesize: 8
-zabbix_proxy_startdbsyncers: 4
-zabbix_proxy_historycachesize: 8
-zabbix_proxy_historyindexcachesize: 4
-zabbix_proxy_historytextcachesize: 16
+zabbix_proxy_starttrappers: 5
+zabbix_proxy_statsallowedip: "127.0.0.1"
zabbix_proxy_timeout: 3
+zabbix_proxy_tmpdir: /tmp
zabbix_proxy_trappertimeout: 300
zabbix_proxy_unreachableperiod: 45
-zabbix_proxy_unavaliabledelay: 60
-zabbix_proxy_unreachabedelay: 15
-zabbix_proxy_externalscripts: /usr/lib/zabbix/externalscripts
-zabbix_proxy_fpinglocation: /usr/sbin/fping
-zabbix_proxy_fping6location: /usr/sbin/fping6
-zabbix_proxy_sshkeylocation:
-zabbix_proxy_loglowqueries: 0
-zabbix_proxy_tmpdir: /tmp
-zabbix_proxy_allowroot: 0
-zabbix_proxy_include: /etc/zabbix/zabbix_proxy.conf.d
-zabbix_proxy_include_mode: "0755"
-zabbix_proxy_libdir: /usr/lib/zabbix
-zabbix_proxy_loadmodulepath: "{{ zabbix_proxy_libdir }}/modules"
-zabbix_proxy_manage_service: true
-zabbix_proxy_statsallowedip: "127.0.0.1"
-zabbix_proxy_vaulttoken:
zabbix_proxy_vaulturl: https://127.0.0.1:8200
-zabbix_proxy_vaultdbpath:
-zabbix_proxy_listenbacklog:
-
-# TLS settings
-zabbix_proxy_tlsconnect:
-zabbix_proxy_tlsaccept:
-zabbix_proxy_tlscafile:
-zabbix_proxy_tlscrlfile:
-zabbix_proxy_tlsservercertissuer:
-zabbix_proxy_tlsservercertsubject:
-zabbix_proxy_tls_subject: "{{ zabbix_proxy_tlsservercertsubject }}" # FIXME this is not correct and should be removed with 2.0.0, here only to prevent regression
-zabbix_proxy_tlscertfile:
-zabbix_proxy_tlskeyfile:
-zabbix_proxy_tlspskidentity:
-
-zabbix_proxy_tls_config:
- no_encryption: "no_encryption"
- psk: "PSK"
- cert: "certificate"
+zabbix_proxy_vmwarecachesize: 8M
+zabbix_proxy_vmwarefrequency: 60
# Zabbix API stuff
-zabbix_validate_certs: true # Will be deprecated in 2.0.0
-zabbix_api_validate_certs: "{{ zabbix_validate_certs }}"
-zabbix_url: http://localhost # Will be deprecated in 2.0.0
-zabbix_api_server_url: "{{ zabbix_url }}"
-zabbix_api_server_host: "{{ zabbix_api_server_url | urlsplit('hostname') }}"
-zabbix_api_port_from_url: "{{ zabbix_api_server_port | default(zabbix_api_server_url | urlsplit('port')) }}"
-zabbix_api_scheme_from_url: "{{ zabbix_api_server_url | urlsplit('scheme') }}"
-zabbix_api_port_from_shema: "{{ (zabbix_api_scheme_from_url == 'https') | ternary(443, 80) }}"
-# zabbix_http_user: admin # Will be deprecated in 2.0.0
-# zabbix_http_password: admin # Will be deprecated in 2.0.0
-# zabbix_api_http_user: admin
-# zabbix_api_http_password: admin
-zabbix_api_user: Admin # Will be deprecated in 2.0.0
-zabbix_api_pass: !unsafe zabbix # Will be deprecated in 2.0.0
-zabbix_api_login_user: "{{ zabbix_api_user }}"
-zabbix_api_login_pass: "{{ zabbix_api_pass }}"
+zabbix_api_server_host: localhost
+zabbix_api_use_ssl: false
+# zabbix_api_server_port: 80
+zabbix_api_login_user: Admin
+zabbix_api_login_pass: !unsafe zabbix
+zabbix_api_validate_certs: false
ansible_httpapi_pass: "{{ zabbix_api_login_pass }}"
-ansible_httpapi_port: "{{ (zabbix_api_port_from_url == '') | ternary(zabbix_api_port_from_shema, zabbix_api_port_from_url) }}"
-ansible_httpapi_use_ssl: "{{ zabbix_api_use_ssl | default((zabbix_api_scheme_from_url == 'https') | ternary(true, false)) }}"
+ansible_httpapi_port: "{{ zabbix_api_server_port }}"
ansible_httpapi_validate_certs: "{{ zabbix_api_validate_certs }}"
-zabbix_api_create_proxy: false
zabbix_api_timeout: 30
-zabbix_create_proxy: present # or absent # Will be deprecated in 2.0.0
-zabbix_proxy_state: "{{ zabbix_create_proxy }}"
+zabbix_api_create_proxy: false
+zabbix_proxy_state: present
zabbix_proxy_status: active # or passive
-zabbix_useuip: 1
-zabbix_proxy_become_on_localhost: true
-zabbix_proxy_interface:
- useip: "{{ zabbix_useuip }}"
- ip: "{{ zabbix_proxy_ip }}"
- dns: "{{ ansible_fqdn }}"
- port: "{{ zabbix_proxy_listenport }}"
+# TLS setttings
+zabbix_proxy_tlsaccept:
+zabbix_proxy_tlsconnect:
diff --git a/ansible_collections/community/zabbix/roles/zabbix_proxy/handlers/main.yml b/ansible_collections/community/zabbix/roles/zabbix_proxy/handlers/main.yml
index 8f42133be..9d5b88ee3 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_proxy/handlers/main.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_proxy/handlers/main.yml
@@ -2,27 +2,16 @@
# handlers file for zabbix-proxy
- name: restart zabbix-proxy
- service:
+ ansible.builtin.service:
name: zabbix-proxy
state: restarted
enabled: true
become: true
when:
- zabbix_proxy_manage_service | bool
- - zabbix_repo != 'epel'
-
-- name: restart zabbix-proxy
- service:
- name: zabbix-proxy-mysql{{ zabbix_proxy_database_long }}
- state: restarted
- enabled: true
- become: true
- when:
- - zabbix_proxy_manage_service | bool
- - zabbix_repo == 'epel'
- name: "clean repo files from proxy creds"
- shell: ls /etc/yum.repos.d/zabbix* && sed -i 's/^proxy =.*//' /etc/yum.repos.d/zabbix* || true
+ ansible.builtin.shell: ls /etc/yum.repos.d/zabbix* && sed -i 's/^proxy =.*//' /etc/yum.repos.d/zabbix* || true
become: true
when:
- ansible_os_family == 'RedHat'
diff --git a/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/Debian.yml b/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/Debian.yml
index fae6b5b96..8e27e7d27 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/Debian.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/Debian.yml
@@ -1,76 +1,48 @@
---
-- name: "Include Zabbix gpg ids"
- include_vars: zabbix.yml
-
-- name: "Set some variables"
- set_fact:
- zabbix_short_version: "{{ zabbix_version | regex_replace('\\.', '') }}"
- zabbix_proxy_apt_repository:
- - "http://repo.zabbix.com/zabbix/{{ zabbix_version }}/{{ ansible_distribution.lower() }}/"
- - "{{ ansible_distribution_release }}"
- - "main"
- zabbix_underscore_version: "{{ zabbix_version | regex_replace('\\.', '_') }}"
- zabbix_python_prefix: "python{% if ansible_python_version is version('3', '>=') %}3{% endif %}"
- when:
- - ansible_machine != "aarch64"
-
-- name: "Set some variables"
- set_fact:
- zabbix_short_version: "{{ zabbix_version | regex_replace('\\.', '') }}"
- zabbix_proxy_apt_repository:
- - "http://repo.zabbix.com/zabbix/{{ zabbix_version }}/{{ ansible_distribution.lower() }}-arm64/"
- - "{{ ansible_distribution_release }}"
- - "main"
- zabbix_underscore_version: "{{ zabbix_version | regex_replace('\\.', '_') }}"
+- name: "Debian | Set short version name"
+ ansible.builtin.set_fact:
+ zabbix_short_version: "{{ zabbix_proxy_version | regex_replace('\\.', '') }}"
zabbix_python_prefix: "python{% if ansible_python_version is version('3', '>=') %}3{% endif %}"
- when:
- - ansible_machine == "aarch64"
-
-- name: "Debian | Set some facts"
- set_fact:
- apache_log: apache2
- datafiles_path: "/usr/share/zabbix-proxy-{{ zabbix_proxy_database }}"
- when:
- - zabbix_version is version_compare('3.0', '<')
+ zabbix_underscore_version: "{{ zabbix_proxy_version | regex_replace('\\.', '_') }}"
tags:
- - zabbix-proxy
- - init
- - config
+ - always
-- name: "Debian | Set some facts for Zabbix >= 3.0 && < 5.4"
- set_fact:
- apache_log: apache2
- datafiles_path: /usr/share/doc/zabbix-proxy-{{ zabbix_proxy_database }}
- when:
- - zabbix_version is version('3.0', '>=')
- - zabbix_version is version('5.4', '<')
+- name: "Debian | Installing lsb-release"
+ ansible.builtin.apt:
+ pkg: lsb-release
+ update_cache: true
+ cache_valid_time: 3600
+ force: true
+ state: present
+ environment:
+ http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
+ https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
+ become: true
tags:
- - zabbix-proxy
- - init
- - config
+ - install
-- name: "Debian | Set some facts for Zabbix == 5.4"
- set_fact:
- datafiles_path: /usr/share/doc/zabbix-sql-scripts/{{ zabbix_proxy_database_long }}
+- name: "Debian | Update ansible_lsb fact"
+ ansible.builtin.setup:
+ gather_subset:
+ - lsb
+
+- name: "Debian | Repo URL"
+ ansible.builtin.set_fact:
+ zabbix_repo_deb_url: "{{ _zabbix_repo_deb_url }}/{{ ansible_lsb.id.lower() }}{{ '-arm64' if ansible_machine == 'aarch64' and ansible_lsb.id == 'debian' else ''}}"
when:
- - zabbix_version is version('5.4', '==')
+ - zabbix_repo_deb_url is undefined
tags:
- - zabbix-proxy
- - init
- - config
+ - always
-- name: "Debian | Set some facts for Zabbix >= 6.0"
- set_fact:
- datafiles_path: /usr/share/zabbix-sql-scripts/{{ zabbix_proxy_database_long }}
- when:
- - zabbix_version is version('6.0', '>=')
+- name: "Debian | Set some facts for Zabbix"
+ ansible.builtin.set_fact:
+ datafiles_path: /usr/share/doc/zabbix-sql-scripts/{{ zabbix_proxy_db_long }}
tags:
- - zabbix-proxy
- - init
+ - install
- config
- name: "Debian | Installing gnupg"
- apt:
+ ansible.builtin.apt:
pkg: gnupg
update_cache: true
cache_valid_time: 3600
@@ -82,108 +54,97 @@
register: gnupg_installed
until: gnupg_installed is succeeded
become: true
+ tags:
+ - install
+
+# In releases older than Debian 12 and Ubuntu 22.04, /etc/apt/keyrings does not exist by default.
+# It SHOULD be created with permissions 0755 if it is needed and does not already exist.
+# See: https://wiki.debian.org/DebianRepository/UseThirdParty
+- name: "Debian | Create /etc/apt/keyrings/ on older versions"
+ ansible.builtin.file:
+ path: /etc/apt/keyrings/
+ state: directory
+ mode: "0755"
+ become: true
+ when:
+ - (ansible_distribution == "Ubuntu" and ansible_distribution_major_version < "22") or
+ (ansible_distribution == "Debian" and ansible_distribution_major_version < "12")
-- name: "Debian | Install gpg key"
- apt_key:
- id: "{{ sign_keys[zabbix_short_version][ansible_distribution_release]['sign_key'] }}"
+- name: "Debian | Download gpg key"
+ ansible.builtin.get_url:
url: http://repo.zabbix.com/zabbix-official-repo.key
+ dest: "{{ zabbix_gpg_key }}"
+ mode: "0644"
+ force: true
register: are_zabbix_proxy_dependency_packages_installed
until: are_zabbix_proxy_dependency_packages_installed is succeeded
- when:
- - zabbix_repo == "zabbix"
become: true
tags:
- - zabbix-proxy
- - init
+ - install
- name: "Debian | Installing repository {{ ansible_distribution }}"
- apt_repository:
- repo: "{{ item }} {{ zabbix_proxy_apt_repository | join(' ') }}"
- state: present
- when: zabbix_repo == "zabbix"
+ ansible.builtin.copy:
+ dest: /etc/apt/sources.list.d/zabbix.sources
+ owner: root
+ group: root
+ mode: 0644
+ content: |
+ Types: deb deb-src
+ Enabled: yes
+ URIs: {{ zabbix_repo_deb_url }}
+ Suites: {{ ansible_distribution_release }}
+ Components: {{ zabbix_repo_deb_component }}
+ Architectures: {{ 'amd64' if ansible_machine != 'aarch64' else 'arm64'}}
+ Signed-By: {{ zabbix_gpg_key }}
become: true
- with_items:
- - deb-src
- - deb
tags:
- - zabbix-proxy
- - init
-
+ - install
+
- name: "Debian | Create /etc/apt/preferences.d/"
- file:
+ ansible.builtin.file:
path: /etc/apt/preferences.d/
state: directory
- mode: '0755'
+ mode: "0755"
when:
- zabbix_proxy_apt_priority | int
become: true
-
+ tags:
+ - install
+
- name: "Debian | Configuring the weight for APT"
- copy:
+ ansible.builtin.copy:
dest: "/etc/apt/preferences.d/zabbix-proxy-{{ zabbix_proxy_database }}"
content: |
Package: zabbix-proxy-{{ zabbix_proxy_database }}
Pin: origin repo.zabbix.com
Pin-Priority: {{ zabbix_proxy_apt_priority }}
owner: root
- mode: '0644'
+ mode: "0644"
when:
- zabbix_proxy_apt_priority | int
become: true
-
-- name: Check if warn parameter can be used for shell module
- set_fact:
- produce_warn: False
- when: ansible_version.full is version("2.14", "<")
-
-- name: apt-get clean
- shell: apt-get clean; apt-get update
- args:
- warn: "{{ produce_warn | default(omit) }}"
- changed_when: false
- become: true
tags:
- - skip_ansible_lint
-
-# On certain 18.04 images, such as docker or lxc, dpkg is configured not to
-# install files into paths /usr/share/doc/*
-# Since this is where Zabbix installs its database schemas, we need to allow
-# files to be installed to /usr/share/doc/zabbix*
-- name: Check for the dpkg exclude line
- command: grep -F 'path-exclude=/usr/share/doc/*' /etc/dpkg/dpkg.cfg.d/excludes
- register: dpkg_exclude_line
- failed_when: false
- changed_when: false
- check_mode: false
-
-- name: Allow Zabbix dpkg installs to /usr/share/doc/zabbix*
- lineinfile:
- path: /etc/dpkg/dpkg.cfg.d/excludes
- line: 'path-include=/usr/share/doc/zabbix*'
- become: true
- when:
- - dpkg_exclude_line.rc == 0
+ - install
- name: "Debian | Installing zabbix-proxy-{{ zabbix_proxy_database }}"
- apt:
- pkg: zabbix-proxy-{{ zabbix_proxy_database }}
- state: "{{ zabbix_proxy_package_state }}"
+ ansible.builtin.apt:
+ pkg: "zabbix-proxy-{{ zabbix_proxy_database }}"
update_cache: true
cache_valid_time: 0
- install_recommends: "{{ zabbix_proxy_install_recommends }}"
+ force: true
+ state: "{{ zabbix_proxy_package_state }}"
default_release: "{{ ansible_distribution_release }}"
environment:
http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
- register: zabbix_proxy_package_installed
- until: zabbix_proxy_package_installed is succeeded
+ register: is_zabbix_proxy_package_installed
+ until: is_zabbix_proxy_package_installed is succeeded
become: true
tags:
- - zabbix-proxy
- - init
+ - install
- name: "Debian | Installing zabbix-sql-scripts"
- apt:
+ ansible.builtin.apt:
pkg: zabbix-sql-scripts
state: "{{ zabbix_proxy_package_state }}"
update_cache: true
@@ -195,14 +156,13 @@
register: zabbix_proxy_package_sql_installed
until: zabbix_proxy_package_sql_installed is succeeded
when:
- - zabbix_version is version('5.4', '>=')
+ - zabbix_proxy_version is version('6.0', '>=')
become: true
tags:
- - zabbix-proxy
- - init
+ - install
- name: "Debian | Install Ansible module dependencies"
- apt:
+ ansible.builtin.apt:
name: "{{ zabbix_python_prefix }}-psycopg2"
state: present
environment:
@@ -212,16 +172,14 @@
until: zabbix_proxy_dependencies_installed is succeeded
become: true
when:
- - zabbix_database_creation
+ - zabbix_proxy_database_creation
tags:
- - zabbix-proxy
- - init
+ - install
+ - dependencies
- name: "Debian | Install Mysql Client package"
- apt:
- name:
- - default-mysql-client
- - "{{ zabbix_python_prefix }}-mysqldb"
+ ansible.builtin.apt:
+ name: "{{ mysql_client_pkgs[ansible_distribution_major_version] }}"
state: present
environment:
http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
@@ -232,35 +190,13 @@
when:
- zabbix_proxy_database == 'mysql'
- zabbix_proxy_install_database_client
- - ansible_distribution_release != "buster"
tags:
- - zabbix-proxy
- - init
- - database
-
-- name: "Debian 10 | Install Mysql Client package"
- apt:
- name:
- - mariadb-client
- - "{{ zabbix_python_prefix }}-mysqldb"
- state: present
- environment:
- http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
- https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
- register: zabbix_proxy_dependencies_installed
- until: zabbix_proxy_dependencies_installed is succeeded
- become: true
- when:
- - zabbix_proxy_database == 'mysql'
- - zabbix_proxy_install_database_client
- - ansible_distribution_release == "buster"
- tags:
- - zabbix-proxy
- - init
+ - install
+ - dependencies
- database
- name: "Debian | Install PostgreSQL Client package"
- apt:
+ ansible.builtin.apt:
name: postgresql-client
state: present
environment:
@@ -270,16 +206,16 @@
until: are_zabbix_proxy_dependency_packages_installed is succeeded
become: true
when:
- - zabbix_database_creation or zabbix_database_sqlload
+ - zabbix_proxy_database_creation or zabbix_proxy_database_sqlload
- zabbix_proxy_database == 'pgsql'
- zabbix_proxy_install_database_client
tags:
- - zabbix-proxy
- - init
+ - install
+ - dependencies
- database
- name: "Debian | Install sqlite3"
- apt:
+ ansible.builtin.apt:
name: sqlite3
state: present
environment:
@@ -291,4 +227,6 @@
when:
- zabbix_proxy_database == 'sqlite3'
tags:
- - zabbix-proxy
+ - install
+ - dependencies
+ - database
diff --git a/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/RedHat.yml b/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/RedHat.yml
index 34a40396e..f35b3c7b3 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/RedHat.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/RedHat.yml
@@ -1,323 +1,147 @@
---
# Tasks specific for RedHat systems
-- name: "Set short version name"
- set_fact:
- zabbix_short_version: "{{ zabbix_version | regex_replace('\\.', '') }}"
-
-- name: "RedHat | Use EPEL package name"
- set_fact:
- zabbix_proxy_package: "zabbix{{ zabbix_version | regex_replace('\\.', '') }}-proxy"
- when:
- - zabbix_repo == "epel"
+- name: "RedHat | Set short version name"
+ ansible.builtin.set_fact:
+ zabbix_short_version: "{{ zabbix_proxy_version | regex_replace('\\.', '') }}"
tags:
- - zabbix-proxy
- - init
-
-- name: "RedHat | Define package with version"
- set_fact:
- zabbix_proxy_package: "zabbix{{ zabbix_short_version }}-proxy-{{ zabbix_proxy_database }}"
- cacheable: true
- when:
- - zabbix_proxy_rhel_version is defined
- - zabbix_repo != "epel"
+ - always
- name: "RedHat | Define package without version"
- set_fact:
+ ansible.builtin.set_fact:
zabbix_proxy_package: "zabbix-proxy-{{ zabbix_proxy_database }}"
cacheable: true
- when:
- - zabbix_proxy_rhel_version is not defined
- - zabbix_repo != "epel"
-
-- name: "RedHat | Set some facts Zabbix < 3.0"
- set_fact:
- apache_log: httpd
- datafiles_path: "/usr/share/doc/zabbix-proxy-{{ zabbix_proxy_database }}-{{ zabbix_version }}*/create"
- when:
- - zabbix_version is version('3.0', '<')
- tags:
- - zabbix-proxy
-
-- name: "RedHat | Set facts for Zabbix >= 3.0 && < 5.4"
- set_fact:
- apache_log: httpd
- datafiles_path: "/usr/share/doc/zabbix-proxy-{{ zabbix_proxy_database }}-{{ zabbix_version }}*"
- when:
- - zabbix_version is version('3.0', '>=')
- - zabbix_version is version('5.4', '<')
tags:
- - zabbix-proxy
+ - always
-- name: "RedHat | Set facts for Zabbix == 5.4"
- set_fact:
- datafiles_path: "/usr/share/doc/zabbix-sql-scripts/{{ zabbix_proxy_database_long }}"
- when:
- - zabbix_version is version('5.4', '==')
+- name: "RedHat | Set facts for Zabbix"
+ ansible.builtin.set_fact:
+ datafiles_path: "/usr/share/doc/zabbix-sql-scripts/{{ zabbix_proxy_db_long }}"
tags:
- - zabbix-server
-
-- name: "RedHat | Set facts for Zabbix >= 6.0"
- set_fact:
- datafiles_path: "/usr/share/zabbix-sql-scripts/{{ zabbix_proxy_database_long }}"
- when:
- - zabbix_version is version('6.0', '>=')
- tags:
- - zabbix-server
-
-- name: "RedHat | Set facts for Zabbix >= 3.0 and RedHat 8"
- set_fact:
- apache_log: httpd
- datafiles_path: "/usr/share/doc/zabbix-proxy-{{ zabbix_proxy_database }}"
- when:
- - zabbix_version is version('3.0', '>=')
- - zabbix_version is version('5.4', '<')
- - ansible_distribution_major_version == '8'
- tags:
- - zabbix-proxy
-
-- name: "RedHat | Set some facts EPEL"
- set_fact:
- datafiles_path: "/usr/share/zabbix-{{ zabbix_proxy_database_long }}"
- when:
- - zabbix_repo == "epel"
- tags:
- - zabbix-server
-
-- name: "RedHat | Create 'zabbix' group (EPEL)"
- group:
- name: "{{ zabbix_proxy_groupname | default('zabbix') }}"
- gid: "{{ zabbix_proxy_groupid | default(omit) }}"
- state: present
- become: true
- when:
- - zabbix_repo == "epel"
+ - always
-- name: "RedHat | Create 'zabbix' user (EPEL)"
- user:
- name: "{{ zabbix_proxy_username | default('zabbix') }}"
- comment: Zabbix Monitoring System
- uid: "{{ zabbix_proxy_userid | default(omit) }}"
- group: zabbix
- become: true
- when:
- - zabbix_repo == "epel"
-
-- name: "Make sure old file is absent"
- file:
+- name: "RedHat | Make sure old file is absent"
+ ansible.builtin.file:
path: /etc/yum.repos.d/zabbix-supported.repo
state: absent
become: true
+ tags:
+ - install
- name: "RedHat | Install basic repo file"
- yum_repository:
+ ansible.builtin.yum_repository:
name: "{{ item.name }}"
description: "{{ item.description }}"
baseurl: "{{ item.baseurl }}"
gpgcheck: "{{ item.gpgcheck }}"
gpgkey: "{{ item.gpgkey }}"
mode: "{{ item.mode | default('0644') }}"
- priority: "{{ item.priority | default('98') }}"
+ priority: "{{ item.priority | default('99') }}"
state: "{{ item.state | default('present') }}"
proxy: "{{ zabbix_http_proxy | default(omit) }}"
with_items: "{{ zabbix_repo_yum }}"
register: yum_repo_installed
become: true
- when:
- - zabbix_repo == "zabbix"
notify:
- "clean repo files from proxy creds"
tags:
- - zabbix-agent
-
-- name: "RedHat | Installing zabbix-proxy-{{ zabbix_proxy_database }}"
- package:
- pkg: "{{ zabbix_proxy_package }}-{{ zabbix_proxy_version }}.{{ zabbix_proxy_version_minor }}"
- state: "{{ zabbix_proxy_package_state }}"
- disablerepo: "{{ '*' if (zabbix_repo_yum_enabled | length>0) else omit }}"
- enablerepo: "{{ zabbix_repo_yum_enabled if zabbix_repo_yum_enabled is iterable and (zabbix_repo_yum_enabled | length>0) else omit }}"
- environment:
- http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
- https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
- become: true
- when:
- zabbix_repo != "other"
- register: is_zabbix_proxy_package_installed
- until: is_zabbix_proxy_package_installed is succeeded
-
-- name: "RedHat | Installing zabbix-proxy-{{ zabbix_proxy_database }} (When zabbix_repo == other)"
- package:
- pkg: "{{ zabbix_proxy_package }}-{{ zabbix_proxy_version }}.{{ zabbix_proxy_version_minor }}"
- state: "{{ zabbix_proxy_package_state }}"
- become: true
- when:
- zabbix_repo == "other"
- register: is_zabbix_proxy_package_installed
- until: is_zabbix_proxy_package_installed is succeeded
-
-- name: "RedHat | Installing zabbix-sql-scripts"
- package:
- pkg: "zabbix-sql-scripts-{{ zabbix_proxy_version }}.{{ zabbix_proxy_version_minor }}"
- state: "{{ zabbix_proxy_package_state }}"
- disablerepo: "{{ '*' if (zabbix_repo_yum_enabled | length>0) else omit }}"
- enablerepo: "{{ zabbix_repo_yum_enabled if zabbix_repo_yum_enabled is iterable and (zabbix_repo_yum_enabled | length>0) else omit }}"
- environment:
- http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
- https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
- register: zabbix_proxy_sql_package_installed
- until: zabbix_proxy_sql_package_installed is succeeded
- when:
- - zabbix_version is version('5.4', '>=')
- - zabbix_repo != "other"
- become: true
- tags:
- - zabbix-server
-
-- name: "RedHat | Installing zabbix-sql-scripts (When zabbix_repo == other)"
- package:
- pkg: "zabbix-sql-scripts-{{ zabbix_proxy_version }}.{{ zabbix_proxy_version_minor }}"
- state: "{{ zabbix_proxy_package_state }}"
- register: zabbix_proxy_sql_package_installed
- until: zabbix_proxy_sql_package_installed is succeeded
- when:
- - zabbix_version is version('5.4', '>=')
- - zabbix_repo == "other"
- become: true
- tags:
- - zabbix-server
-
-- name: "RedHat | Install Ansible PostgreSQL module dependencies"
- yum:
- name: python-psycopg2
+ - install
+
+- name: Install packages for Zabbix Repository
+ block:
+ - name: "RedHat | Installing zabbix-proxy-{{ zabbix_proxy_database }}"
+ ansible.builtin.yum:
+ pkg: "{{ zabbix_proxy_package }}-{{ zabbix_proxy_version }}.{{ zabbix_proxy_version_minor }}"
+ state: "{{ zabbix_proxy_package_state }}"
+ disablerepo: "{{ zabbix_proxy_disable_repo | default(omit) }}"
+ environment:
+ http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
+ https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
+ become: true
+ register: is_zabbix_proxy_package_installed
+ until: is_zabbix_proxy_package_installed is succeeded
+
+ - name: "RedHat | Installing zabbix-sql-scripts"
+ ansible.builtin.yum:
+ pkg: "zabbix-sql-scripts-{{ zabbix_proxy_version }}.{{ zabbix_proxy_version_minor }}"
+ state: "{{ zabbix_proxy_package_state }}"
+ disablerepo: "{{ zabbix_proxy_disable_repo | default(omit) }}"
+ environment:
+ http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
+ https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
+ register: zabbix_proxy_sql_package_installed
+ until: zabbix_proxy_sql_package_installed is succeeded
+ become: true
+ tags:
+ - install
+
+- name: "RedHat | Install Ansible PostgreSQL Client package"
+ ansible.builtin.yum:
+ name: "{{ pgsql_depenencies[ansible_distribution_major_version] }}"
state: present
environment:
http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
become: true
- register: are_zabbix_proxy_dependency_packages_installed
- until: are_zabbix_proxy_dependency_packages_installed is succeeded
+ register: are_zabbix_proxy_pgsql_packages_installed
+ until: are_zabbix_proxy_pgsql_packages_installed is succeeded
when:
- - zabbix_database_creation or zabbix_database_sqlload
+ - zabbix_proxy_database_creation or zabbix_proxy_database_sqlload
- zabbix_proxy_database == 'pgsql'
- - ansible_distribution_major_version == "7" or ansible_distribution_major_version == "6"
- tags:
- - zabbix-proxy
- - init
-
-- name: "RedHat | Install Ansible module dependencies on RHEL9 or RHEL8"
- yum:
- name: python3-psycopg2
- state: present
- environment:
- http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
- https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
- register: zabbix_proxy_dependencies_installed
- until: zabbix_proxy_dependencies_installed is succeeded
- become: true
- when:
- - zabbix_database_creation
- - zabbix_proxy_database == 'pgsql'
- - ansible_distribution_major_version|int >= 8
- tags:
- - zabbix-server
-
-- name: "RedHat | Install Mysql Client package RHEL7"
- yum:
- name:
- - mariadb
- - MySQL-python
- state: installed
- environment:
- http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
- https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
- become: true
- register: are_zabbix_proxy_dependency_packages_installed
- until: are_zabbix_proxy_dependency_packages_installed is succeeded
- when:
- - zabbix_database_creation or zabbix_database_sqlload
- - zabbix_proxy_database == 'mysql'
- - ansible_distribution_major_version == '7'
- tags:
- - zabbix-proxy
- - init
-
-- name: "RedHat | Install Mysql Client packages RHEL9 or RHEL8"
- yum:
- name:
- - mysql
- - python3-PyMySQL
- state: present
- environment:
- http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
- https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
- register: zabbix_proxy_dependencies_installed
- until: zabbix_proxy_dependencies_installed is succeeded
- become: true
- when:
- - zabbix_proxy_database == 'mysql'
- - ansible_distribution_major_version|int >= 8
tags:
- - zabbix-proxy
- - init
-
-- name: "RedHat | Install Mysql Client package RHEL5 - 6"
- yum:
- name:
- - mysql
- - MySQL-python
- state: present
- environment:
- http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
- https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
- become: true
- register: are_zabbix_proxy_dependency_packages_installed
- until: are_zabbix_proxy_dependency_packages_installed is succeeded
- when:
- - zabbix_database_creation or zabbix_database_sqlload
- - zabbix_proxy_database == 'mysql'
- - ansible_distribution_major_version == "6" or ansible_distribution_major_version == "5"
- - zabbix_proxy_install_database_client
- tags:
- - zabbix-proxy
- - init
+ - install
- database
-
-- name: "RedHat | Install PostgreSQL client package"
- yum:
- name: postgresql
- state: present
- environment:
- http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
- https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
- become: true
- register: are_zabbix_proxy_dependency_packages_installed
- until: are_zabbix_proxy_dependency_packages_installed is succeeded
- when:
- - zabbix_database_creation or zabbix_database_sqlload
- - zabbix_proxy_database == 'pgsql'
+ - dependencies
+
+- name: "RedHat | Install Mysql Client Package"
+ block:
+ - name: "RedHat | Add Mysql Repo (Centos 7 Only)"
+ ansible.builtin.yum_repository:
+ name: mariadb
+ description: MariaDB 10.8 CentOS repository list
+ file: mariadb
+ baseurl: "https://mirror.rackspace.com/mariadb/yum/10.11/centos{{ ansible_distribution_major_version }}-amd64"
+ gpgcheck: no
+ when: ansible_distribution_major_version == '7'
+
+ - name: "RedHat | Install Mysql Client package"
+ ansible.builtin.yum:
+ name: "{{ mysql_client_pkgs[ansible_distribution_major_version] }}"
+ state: installed
+ environment:
+ http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
+ https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
+ become: true
+ register: are_zabbix_proxy_mysql_packages_installed
+ until: are_zabbix_proxy_mysql_packages_installed is succeeded
+ when:
+ - zabbix_proxy_database_creation or zabbix_proxy_database_sqlload
- zabbix_proxy_install_database_client
+ - zabbix_proxy_database == 'mysql'
tags:
- - zabbix-proxy
- - init
+ - install
- database
+ - dependencies
- name: "RedHat | Install sqlite3"
- yum:
+ ansible.builtin.yum:
name:
- sqlite
state: present
environment:
http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
- register: zabbix_proxy_dependencies_installed
- until: zabbix_proxy_dependencies_installed is succeeded
+ register: zabbix_proxy_sqlite_packages_installed
+ until: zabbix_proxy_sqlite_packages_installed is succeeded
become: true
when:
- zabbix_proxy_database == 'sqlite3'
tags:
- - zabbix-proxy
+ - install
+ - database
+ - dependencies
- name: "Configure SELinux when enabled"
- include_tasks: selinux.yml
+ ansible.builtin.include_tasks: selinux.yml
when:
- - zabbix_selinux | bool
+ - zabbix_proxy_selinux | bool
diff --git a/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/main.yml b/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/main.yml
index bd39b5b8a..f564635b1 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/main.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/main.yml
@@ -1,71 +1,114 @@
---
# tasks file for zabbix_proxy
- name: "Include OS-specific variables"
- include_vars: "{{ ansible_os_family }}.yml"
+ ansible.builtin.include_vars: "{{ ansible_os_family }}.yml"
+ tags:
+ - always
- name: Determine Latest Supported Zabbix Version
- set_fact:
- zabbix_proxy_version: "{{ zabbix_valid_proxy_versions[ansible_distribution_major_version][0] | default(6.0) }}"
- when: zabbix_proxy_version is not defined
+ ansible.builtin.set_fact:
+ zabbix_proxy_version: "{{ zabbix_valid_proxy_versions[ansible_distribution_major_version][0] | default(6.4) }}"
+ when: zabbix_proxy_version is not defined or zabbix_proxy_version is none
+ tags:
+ - always
-- name: "Replace Sangoma with RedHat task"
- set_fact:
- ansible_os_family: "RedHat"
- when:
- - ansible_os_family == 'Sangoma'
+- name: Set More Variables
+ ansible.builtin.set_fact:
+ zabbix_proxy_db_long: "{{ 'postgresql' if zabbix_proxy_database == 'pgsql' else zabbix_proxy_database }}"
+ zabbix_valid_version: "{{ zabbix_proxy_version|float in zabbix_valid_proxy_versions[ansible_distribution_major_version] }}"
+ zabbix_short_version: "{{ zabbix_proxy_version | regex_replace('\\.', '') }}"
+ zabbix_proxy_fpinglocation: "{{ zabbix_proxy_fpinglocation if zabbix_proxy_fpinglocation is defined else _zabbix_proxy_fpinglocation}}"
+ zabbix_proxy_fping6location: "{{ zabbix_proxy_fping6location if zabbix_proxy_fping6location is defined else _zabbix_proxy_fping6location}}"
+ tags:
+ - always
+
+- name: Stopping Install of Invalid Version
+ ansible.builtin.fail:
+ msg: Zabbix version {{ zabbix_proxy_version }} is not supported on {{ ansible_distribution }} {{ ansible_distribution_major_version }}
+ when: not zabbix_valid_version
+ tags:
+ - always
+
+- name: Setting Zabbix API Server Port
+ ansible.builtin.set_fact:
+ zabbix_api_server_port: "{{ '443' if zabbix_api_use_ssl|bool else '80' }}"
+ when: zabbix_api_server_port is undefined
+
+- name: Set Path to SQL File
+ ansible.builtin.set_fact:
+ datafile_path: "{{ db_file_path[zabbix_short_version] }}"
+ tags:
+ - install
+ - config
- name: "Set default ip address for zabbix_proxy_ip"
- set_fact:
+ ansible.builtin.set_fact:
zabbix_proxy_ip: "{{ hostvars[inventory_hostname]['ansible_default_ipv4'].address }}"
when:
- zabbix_proxy_ip is not defined
- "'ansible_default_ipv4' in hostvars[inventory_hostname]"
+ tags:
+ - install
+ - config
+ - api
-- name: "Set OS dependent variables"
- include_vars: "{{ item }}"
- with_first_found:
- - "../vars/{{ ansible_distribution }}.yml"
- - "../vars/main.yml"
+- name: "Complete OS Specific Tasks"
+ ansible.builtin.include_tasks: "{{ ansible_os_family }}.yml"
-- name: "Install the correct repository"
- include_tasks: "{{ ansible_os_family }}.yml"
+- name: "Get the file for database schema"
+ ansible.builtin.shell: ls -1 {{ db_file_path[zabbix_short_version] }}
+ changed_when: false
+ become: true
+ when:
+ - zabbix_proxy_database_sqlload
+ register: ls_output_schema
+ tags:
+ - database
-- name: "Installing the {{ zabbix_proxy_database_long }} database"
- include_tasks: "{{ zabbix_proxy_database_long }}.yml"
+- name: "Installing the database"
+ ansible.builtin.include_tasks: "{{ zabbix_proxy_db_long }}.yml"
- name: "Create include dir zabbix-proxy"
- file:
+ ansible.builtin.file:
path: "{{ zabbix_proxy_include }}"
- owner: zabbix
- group: zabbix
+ owner: "{{ zabbix_os_user }}"
+ group: "{{ zabbix_os_user }}"
mode: "{{ zabbix_proxy_include_mode }}"
state: directory
become: true
+ tags:
+ - install
+ - config
- name: "Create module dir zabbix-proxy"
- file:
+ ansible.builtin.file:
path: "{{ zabbix_proxy_loadmodulepath }}"
- owner: zabbix
- group: zabbix
+ owner: "{{ zabbix_os_user }}"
+ group: "{{ zabbix_os_user }}"
state: directory
mode: "0755"
become: true
+ tags:
+ - install
+ - config
- name: "Create directory for PSK file if not exist."
- file:
+ ansible.builtin.file:
path: "{{ zabbix_proxy_tlspskfile | dirname }}"
mode: 0755
state: directory
become: true
when:
- zabbix_proxy_tlspskfile is defined
+ tags:
+ - config
- name: "Place TLS PSK File"
- copy:
+ ansible.builtin.copy:
dest: "{{ zabbix_proxy_tlspskfile }}"
content: "{{ zabbix_proxy_tlspsk_secret }}"
- owner: zabbix
- group: zabbix
+ owner: "{{ zabbix_os_user }}"
+ group: "{{ zabbix_os_user }}"
mode: 0400
become: true
when:
@@ -73,34 +116,20 @@
- zabbix_proxy_tlspsk_secret is defined
notify:
- restart zabbix-proxy
-
-- name: "Allow zabbix-proxy to open connections (SELinux)"
- ansible.posix.seboolean:
- name: zabbix_can_network
- persistent: true
- state: true
- become: true
- when: ansible_selinux.status == "enabled"
- tags: selinux
-
-- name: "Allow zabbix-proxy to connect to zabbix_proxy_preprocessing.sock (SELinux)"
- ansible.posix.seboolean:
- name: daemons_enable_cluster_mode
- persistent: true
- state: true
- become: true
- when: ansible_selinux.status == "enabled"
- tags: selinux
+ tags:
+ - config
- name: "Configure zabbix-proxy"
- template:
+ ansible.builtin.template:
src: zabbix_proxy.conf.j2
- dest: /etc/zabbix/zabbix_proxy.conf
- owner: zabbix
- group: zabbix
+ dest: "{{ zabbix_proxy_config }}"
+ owner: "{{ zabbix_os_user }}"
+ group: "{{ zabbix_os_user }}"
mode: "{{ zabbix_proxy_conf_mode }}"
notify: restart zabbix-proxy
become: true
+ tags:
+ - config
- name: Ensure proxy definition is up-to-date (added/updated/removed)
vars:
@@ -108,9 +137,9 @@
ansible_user: "{{ zabbix_api_login_user }}"
ansible_network_os: community.zabbix.zabbix
ansible_connection: httpapi
- # Can't think of a way to make http_login_* vars be undefined -(
- http_login_user: "{{ zabbix_api_http_user | default(zabbix_http_user | default(-42)) }}"
- http_login_password: "{{ zabbix_api_http_password | default(zabbix_http_password | default(-42)) }}"
+ ansible_httpapi_use_ssl: "{{ zabbix_api_use_ssl }}"
+ http_login_user: "{{ zabbix_api_http_user | default(-42) }}"
+ http_login_password: "{{ zabbix_api_http_password | default(-42) }}"
community.zabbix.zabbix_proxy:
state: "{{ zabbix_proxy_state }}"
status: "{{ zabbix_proxy_status }}"
@@ -125,14 +154,15 @@
when:
- zabbix_api_create_proxy | bool
delegate_to: "{{ zabbix_api_server_host }}"
- become: false
tags:
- api
- name: "zabbix-proxy started"
- service:
+ ansible.builtin.service:
name: zabbix-proxy
state: started
enabled: true
become: true
when: zabbix_proxy_manage_service | bool
+ tags:
+ - service
diff --git a/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/mysql.yml b/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/mysql.yml
index 6d699ea83..dde847a53 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/mysql.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/mysql.yml
@@ -1,21 +1,35 @@
---
# task file for mysql
-- name: "Set the correct delegated_dbhost (to support MySQL db deployment on a remote dbhost)"
- set_fact:
+- name: "MySQL | Set the correct delegated_dbhost (to support MySQL db deployment on a remote dbhost)"
+ ansible.builtin.set_fact:
delegated_dbhost: "{{ zabbix_proxy_dbhost if (zabbix_proxy_dbhost != 'localhost') else inventory_hostname }}"
when:
- zabbix_proxy_dbhost_run_install
+ tags:
+ - database
-- name: "Set the correct delegated_dbhost (to support MySQL db deployment on a remote dbhost)"
- set_fact:
+- name: "MySQL | Set the correct delegated_dbhost (to support MySQL db deployment on a remote dbhost)"
+ ansible.builtin.set_fact:
delegated_dbhost: "{{ inventory_hostname }}"
when:
- not zabbix_proxy_dbhost_run_install
+ tags:
+ - database
-- name: "Override delegated_dbhost with real dbhost when dbhost is behind loadbalancer"
- set_fact:
+- name: "MySQL | Override delegated_dbhost with real dbhost when dbhost is behind loadbalancer"
+ ansible.builtin.set_fact:
delegated_dbhost: "{{ zabbix_proxy_real_dbhost }}"
when: zabbix_proxy_real_dbhost | default(false)
+ tags:
+ - database
+
+- name: PyMySQL
+ ansible.builtin.pip:
+ name: PyMySQL
+ register: installation_dependencies
+ until: installation_dependencies is succeeded
+ tags:
+ - database
- name: "MySQL | Create database"
community.mysql.mysql_db:
@@ -28,11 +42,10 @@
login_port: "{{ zabbix_proxy_mysql_login_port | default(omit) }}"
login_unix_socket: "{{ zabbix_proxy_mysql_login_unix_socket | default(omit) }}"
state: present
- when: zabbix_database_creation
+ when: zabbix_proxy_database_creation
register: zabbix_database_created
delegate_to: "{{ delegated_dbhost }}"
tags:
- - zabbix-proxy
- database
- skip_ansible_lint
@@ -47,31 +60,22 @@
password: "{{ zabbix_proxy_dbpassword }}"
priv: "{{ zabbix_proxy_dbname }}.*:ALL"
host: "{{ zabbix_proxy_privileged_host }}"
+ plugin: "{{ 'mysql_native_password' if (ansible_os_family == 'RedHat' and ansible_distribution_major_version == '7') else omit }}"
state: present
- when: zabbix_database_creation
+ when: zabbix_proxy_database_creation
delegate_to: "{{ delegated_dbhost }}"
tags:
- - zabbix-proxy
- database
-- name: "Get the file for schema.sql"
- shell: ls -1 {{ datafiles_path }}/{{ 'schema' if zabbix_version is version('6.0', '<') else 'proxy' }}.sq*
- changed_when: false
- when:
- - zabbix_database_sqlload
- - zabbix_repo != "epel"
- register: ls_output_create
- tags:
- - zabbix-proxy
- - database
-
-- name: "Check if we have done files"
- stat:
+- name: "MySQL | Check if we have done files"
+ ansible.builtin.stat:
path: /etc/zabbix/schema.done
register: done_file
+ become: true
when:
- - zabbix_database_sqlload
- - zabbix_repo != "epel"
+ - zabbix_proxy_database_sqlload
+ tags:
+ - database
- name: "MySQL | Get version_comment"
community.mysql.mysql_variables:
@@ -84,7 +88,6 @@
delegate_to: "{{ delegated_dbhost }}"
register: install_mysql_version
tags:
- - zabbix-proxy
- database
- name: "MySQL | Get current value for innodb_default_row_format"
@@ -100,7 +103,6 @@
when:
- install_mysql_version.msg is version('5.6', '>=')
tags:
- - zabbix-proxy
- database
- name: "MySQL | Set innodb_default_row_format to dynamic"
@@ -113,15 +115,12 @@
login_port: "{{ zabbix_proxy_mysql_login_port | default(omit) }}"
login_unix_socket: "{{ zabbix_proxy_mysql_login_unix_socket | default(omit) }}"
when:
- - zabbix_version is version('3.0', '>=')
- - zabbix_database_sqlload | bool
- - zabbix_repo != "epel"
+ - zabbix_proxy_database_sqlload | bool
- not done_file.stat.exists
- install_mysql_version.msg is version('5.6', '>=')
- mysql_innodb_default_row_format.msg != 'dynamic'
delegate_to: "{{ delegated_dbhost }}"
tags:
- - zabbix-proxy
- database
- name: "MySQL | Create database and import file"
@@ -135,42 +134,39 @@
encoding: "{{ zabbix_proxy_dbencoding }}"
collation: "{{ zabbix_proxy_dbcollation }}"
state: import
- target: "{{ ls_output_create.stdout }}"
+ target: "{{ ls_output_schema.stdout }}"
when:
- - zabbix_database_sqlload
- - zabbix_repo != "epel"
+ - zabbix_proxy_database_sqlload
- not done_file.stat.exists
delegate_to: "{{ delegated_dbhost }}"
tags:
- - zabbix-proxy
- database
- name: "MySQL | Revert innodb_default_row_format to previous value"
community.mysql.mysql_variables:
variable: innodb_default_row_format
- value: '{{ mysql_innodb_default_row_format.msg }}'
+ value: "{{ mysql_innodb_default_row_format.msg }}"
login_host: "{{ zabbix_proxy_mysql_login_host | default(omit) }}"
login_user: "{{ zabbix_proxy_mysql_login_user | default(omit) }}"
login_password: "{{ zabbix_proxy_mysql_login_password | default(omit) }}"
login_port: "{{ zabbix_proxy_mysql_login_port | default(omit) }}"
login_unix_socket: "{{ zabbix_proxy_mysql_login_unix_socket | default(omit) }}"
when:
- - zabbix_version is version('3.0', '>=')
- - zabbix_database_sqlload | bool
- - zabbix_repo != "epel"
+ - zabbix_proxy_database_sqlload | bool
- not done_file.stat.exists
- mysql_innodb_default_row_format.msg != 'dynamic'
delegate_to: "{{ delegated_dbhost }}"
tags:
- - zabbix-proxy
- database
-- name: "Create done file"
- file:
+- name: "MySQL | Create done file"
+ ansible.builtin.file:
path: /etc/zabbix/schema.done
state: touch
- mode: '0644'
+ mode: "0644"
+ become: true
when:
- - zabbix_database_sqlload
- - zabbix_repo != "epel"
+ - zabbix_proxy_database_sqlload
- not done_file.stat.exists
+ tags:
+ - database
diff --git a/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/postgresql.yml b/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/postgresql.yml
index f32618d94..e71af9aba 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/postgresql.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/postgresql.yml
@@ -1,17 +1,21 @@
---
# task file for postgresql
-- name: "Set the correct delegated_dbhost (to support postgres db deployment on a remote dbhost)"
- set_fact:
+- name: "PostgreSQL | Set the correct delegated_dbhost (to support postgres db deployment on a remote dbhost)"
+ ansible.builtin.set_fact:
delegated_dbhost: "{{ zabbix_proxy_dbhost if (zabbix_proxy_dbhost != 'localhost') else inventory_hostname }}"
when:
- zabbix_proxy_dbhost_run_install
+ tags:
+ - database
-- name: "Set the correct delegated_dbhost (to support postgres db deployment on a remote dbhost)"
- set_fact:
+- name: "PostgreSQL | Set the correct delegated_dbhost (to support postgres db deployment on a remote dbhost)"
+ ansible.builtin.set_fact:
delegated_dbhost: "{{ inventory_hostname }}"
when:
- not zabbix_proxy_dbhost_run_install
+ tags:
+ - database
- name: "PostgreSQL | Delegated"
block:
@@ -20,8 +24,9 @@
name: "{{ zabbix_proxy_dbname }}"
port: "{{ zabbix_proxy_dbport }}"
state: present
+
- name: "PostgreSQL | Delegated | Create database user"
- postgresql_user:
+ community.postgresql.postgresql_user:
db: "{{ zabbix_proxy_dbname }}"
name: "{{ zabbix_proxy_dbuser }}"
password: "{{ ('md5' + (zabbix_proxy_dbpassword + zabbix_proxy_dbuser)|hash('md5')) if zabbix_proxy_dbpassword_hash_method == 'md5' else zabbix_proxy_dbpassword }}"
@@ -33,10 +38,9 @@
become_user: postgres
delegate_to: "{{ delegated_dbhost }}"
when:
- - zabbix_database_creation
+ - zabbix_proxy_database_creation
- zabbix_proxy_pgsql_login_host is not defined
tags:
- - zabbix-proxy
- database
- name: "PostgreSQL | Remote"
@@ -51,7 +55,7 @@
port: "{{ zabbix_proxy_dbport }}"
state: present
- name: "PostgreSQL | Remote | Create database user"
- postgresql_user:
+ community.postgresql.postgresql_user:
login_host: "{{ zabbix_proxy_pgsql_login_host | default(omit) }}"
login_user: "{{ zabbix_proxy_pgsql_login_user | default(omit) }}"
login_password: "{{ zabbix_proxy_pgsql_login_password | default(omit) }}"
@@ -63,30 +67,30 @@
state: present
encrypted: true
when:
- - zabbix_database_creation
+ - zabbix_proxy_database_creation
- zabbix_proxy_pgsql_login_host is defined
tags:
- - zabbix-proxy
+ - database
+
+- name: "PostgreSQL | Handle Compressed Schema File"
+ ansible.builtin.set_fact:
+ zabbix_proxy_cat_cmd: zcat
+ when: "'.gz' in ls_output_schema.stdout"
+ tags:
- database
- name: "PostgreSQL | Importing schema file"
- shell: |
+ ansible.builtin.shell: |
set -euxo pipefail
- FILE={{ 'schema.sql' if zabbix_version is version('6.0', '<') else 'proxy.sql' }}
- cd {{ datafiles_path }}
- if [ -f ${FILE}.gz ]
- then zcat ${FILE}.gz > /tmp/schema.sql
- else
- cp ${FILE} /tmp/schema.sql
- fi
- cat /tmp/schema.sql | psql -h '{{ zabbix_proxy_dbhost }}' -U '{{ zabbix_proxy_dbuser }}' \
- -d '{{ zabbix_proxy_dbname }}'
+ {{ zabbix_proxy_cat_cmd }} {{ ls_output_schema.stdout }} | psql -h '{{ zabbix_proxy_dbhost }}' -U '{{ zabbix_proxy_dbuser }}' -d '{{ zabbix_proxy_dbname }}'
touch /etc/zabbix/schema.done
- rm -f /tmp/schema.sql
args:
creates: /etc/zabbix/schema.done
executable: /bin/bash
environment:
- PGPASSWORD: '{{ zabbix_proxy_dbpassword }}'
+ PGPASSWORD: "{{ zabbix_proxy_dbpassword }}"
+ become: true
when:
- - zabbix_database_creation
+ - zabbix_proxy_database_creation
+ tags:
+ - database
diff --git a/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/selinux.yml b/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/selinux.yml
index 02fb4ebaf..0dca77c52 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/selinux.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/selinux.yml
@@ -1,11 +1,7 @@
---
-
- name: "SELinux | RedHat | Install related SELinux package to fix issues"
- yum:
- name:
- - policycoreutils-python
- - libsemanage-python
- - checkpolicy
+ ansible.builtin.yum:
+ name: "{{ selinux_pkgs[ansible_distribution_major_version] }}"
state: present
environment:
http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
@@ -13,38 +9,32 @@
register: zabbix_proxy_dependencies_installed
until: zabbix_proxy_dependencies_installed is succeeded
become: true
- when:
- - ansible_os_family == "RedHat"
- - ansible_distribution_major_version == "7" or ansible_distribution_major_version == "6"
- tags:
- - zabbix-proxy
-
-- name: "SELinux | RedHat | Install related SELinux package to fix issues on RHEL8"
- yum:
- name:
- - policycoreutils
- - checkpolicy
- - python3-libsemanage
- state: present
- environment:
- http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
- https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
- register: zabbix_proxy_dependencies_installed
- until: zabbix_proxy_dependencies_installed is succeeded
- become: true
- when:
- - ansible_os_family == "RedHat"
- - ansible_distribution_major_version|int >= 8
tags:
- zabbix-proxy
- name: "SELinux | RedHat | Add SEmodule to fix SELinux issue: zabbix_proxy_alerter.sock"
- script:
+ ansible.builtin.script:
cmd: files/install_semodule.bsx
args:
creates: /etc/selinux/targeted/active/modules/400/zabbix_proxy_add/cil
become: true
- when:
- - ansible_os_family == "RedHat"
tags:
- zabbix-proxy
+
+- name: "Allow zabbix-proxy to open connections (SELinux)"
+ ansible.posix.seboolean:
+ name: zabbix_can_network
+ persistent: true
+ state: true
+ become: true
+ when: ansible_selinux.status == "enabled"
+ tags: selinux
+
+- name: "Allow zabbix-proxy to connect to zabbix_proxy_preprocessing.sock (SELinux)"
+ ansible.posix.seboolean:
+ name: daemons_enable_cluster_mode
+ persistent: true
+ state: true
+ become: true
+ when: ansible_selinux.status == "enabled"
+ tags: selinux
diff --git a/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/sqlite3.yml b/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/sqlite3.yml
index 03fbf6fb3..3d74b73e7 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/sqlite3.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_proxy/tasks/sqlite3.yml
@@ -2,49 +2,54 @@
# task file for sqlite3
- name: "Sqlite3 | Default Database Path"
- set_fact:
+ ansible.builtin.set_fact:
zabbix_proxy_dbname: /var/lib/zabbix/zabbix_proxy.db
when:
- zabbix_proxy_dbname == "zabbix_proxy"
+ tags:
+ - database
- name: "Sqlite3 | Create database"
- file:
+ ansible.builtin.file:
name: "{{ zabbix_proxy_dbname | dirname }}"
mode: 0744
- owner: zabbix
- group: zabbix
+ owner: "{{ zabbix_os_user }}"
+ group: "{{ zabbix_os_user }}"
seuser: system_u
serole: object_r
setype: zabbix_var_lib_t
state: directory
become: true
when:
- - zabbix_database_creation
+ - zabbix_proxy_database_creation
+ tags:
+ - database
+
+- name: "Sqlite3 | Handle Compressed Schema File"
+ ansible.builtin.set_fact:
+ zabbix_proxy_cat_cmd: zcat
+ when: "'.gz' in ls_output_schema.stdout"
+ tags:
+ - database
- name: "Sqlite3 | Importing schema file"
become: true
- become_user: zabbix
- shell: |
- set -o pipefail
- FILE={{ 'schema.sql' if zabbix_version is version('6.0', '<') else 'proxy.sql' }}
- cd {{ datafiles_path }}
- if [ -f ${FILE}.gz ]
- then zcat ${FILE}.gz > /tmp/schema.sql
- else
- cp ${FILE} /tmp/schema.sql
- fi
- cat /tmp/schema.sql | sqlite3 {{ zabbix_proxy_dbname }}
- rm -f /tmp/schema.sql
+ become_user: "{{ zabbix_os_user }}"
+ ansible.builtin.shell: |
+ set -euxo pipefail
+ {{ zabbix_proxy_cat_cmd }} {{ ls_output_schema.stdout }} | sqlite3 {{ zabbix_proxy_dbname }}
args:
creates: "{{ zabbix_proxy_dbname }}"
executable: /bin/bash
environment:
- PGPASSWORD: '{{ zabbix_proxy_dbpassword }}'
+ PGPASSWORD: "{{ zabbix_proxy_dbpassword }}"
when:
- - zabbix_database_creation
+ - zabbix_proxy_database_creation
+ tags:
+ - database
-- name: "Fix zabbix db file permission (SELinux)"
- file:
+- name: "Sqlite3 | Fix zabbix db file permission (SELinux)"
+ ansible.builtin.file:
path: "{{ zabbix_proxy_dbname }}"
state: file
seuser: system_u
@@ -53,5 +58,6 @@
become: true
when:
- ansible_selinux.status == "enabled"
- - zabbix_database_creation
- tags: selinux
+ - zabbix_proxy_database_creation
+ tags:
+ - database
diff --git a/ansible_collections/community/zabbix/roles/zabbix_proxy/templates/zabbix_proxy.conf.j2 b/ansible_collections/community/zabbix/roles/zabbix_proxy/templates/zabbix_proxy.conf.j2
index b61842d12..60ae3f0a5 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_proxy/templates/zabbix_proxy.conf.j2
+++ b/ansible_collections/community/zabbix/roles/zabbix_proxy/templates/zabbix_proxy.conf.j2
@@ -4,197 +4,116 @@
# This configuration file is "minimalized", which means all the original comments
# are removed. The full documentation for your Zabbix Proxy can be found here:
-# https://www.zabbix.com/documentation/{{ zabbix_version }}/en/manual/appendix/config/zabbix_proxy
+# https://www.zabbix.com/documentation/{{ zabbix_proxy_version }}/en/manual/appendix/config/zabbix_proxy
-ProxyMode={{ zabbix_proxy_mode }}
-Server={{ zabbix_proxy_server }}
-{% if zabbix_version is version('6.0', '<') %}
-ServerPort={{ zabbix_proxy_serverport }}
-{% endif %}
-{% if zabbix_proxy_hostname is defined and zabbix_proxy_hostname %}
-Hostname={{ zabbix_proxy_hostname }}
-{% endif %}
-{% if zabbix_proxy_hostnameitem is defined and zabbix_proxy_hostnameitem %}
-HostnameItem={{ zabbix_proxy_hostnameitem }}
-{% endif %}
-ListenPort={{ zabbix_proxy_listenport }}
-{% if zabbix_proxy_sourceip is defined and zabbix_proxy_sourceip %}
-SourceIP={{ zabbix_proxy_sourceip }}
-{% endif %}
-{% if zabbix_version is version('6.0', '>=') %}
-LogType={{ zabbix_proxy_logtype }}
-{% endif %}
-LogFile={{ zabbix_proxy_logfile }}
-LogFileSize={{ zabbix_proxy_logfilesize }}
-EnableRemoteCommands={{ zabbix_proxy_enableremotecommands }}
-DebugLevel={{ zabbix_proxy_debuglevel }}
-PidFile={{ zabbix_proxy_pidfile }}
-{% if zabbix_version is version('3.2', '>') %}
-SocketDir={{ zabbix_proxy_socketdir }}
-{% endif %}
-DBHost={{ zabbix_proxy_dbhost }}
-DBName={{ zabbix_proxy_dbname }}
-{% if zabbix_proxy_dbschema is defined and zabbix_proxy_dbschema %}
-DBSchema={{ zabbix_proxy_dbschema }}
-{% endif %}
-DBUser={{ zabbix_proxy_dbuser }}
-DBPassword={{ zabbix_proxy_dbpassword }}
-DBPort={{ zabbix_proxy_dbport }}
-{% if zabbix_version is version('6.0', '>=') %}
-AllowUnsupportedDBVersions={{ zabbix_proxy_allowunsupporteddbversions }}
-{% endif %}
-ProxyLocalBuffer={{ zabbix_proxy_proxylocalbuffer }}
-ProxyOfflineBuffer={{ zabbix_proxy_proxyofflinebuffer }}
-{% if zabbix_version is version('6.4', '<') %}
-HeartbeatFrequency={{ zabbix_proxy_heartbeatfrequency }}
-{% endif %}
-{% if zabbix_proxy_configfrequency is defined and zabbix_proxy_configfrequency is not none %}
-{% if zabbix_version is version('6.4', '<') %}
-ConfigFrequency={{ zabbix_proxy_configfrequency }}
-{% else %}
-ProxyConfigFrequency={{ zabbix_proxy_configfrequency }}
-{% endif %}
-{% else %}
-{% if zabbix_version is version('6.2', '<') %}
-ConfigFrequency=3600
-{% elif zabbix_version is version('6.4', '<') %}
-ConfigFrequency=300
-{% else %}
-ProxyConfigFrequency=10
-{% endif %}
-{% endif %}
-DataSenderFrequency={{ zabbix_proxy_datasenderfrequency }}
-StartPollers={{ zabbix_proxy_startpollers }}
-StartIPMIPollers={{ zabbix_proxy_startipmipollers }}
-{% if zabbix_version is version('4.2', '>=') %}
-StartPreprocessors={{ zabbix_proxy_startpreprocessors }}
-{% endif %}
-StartPollersUnreachable={{ zabbix_proxy_startpollersunreachable }}
-StartTrappers={{ zabbix_proxy_starttrappers }}
-StartPingers={{ zabbix_proxy_startpingers }}
-StartDiscoverers={{ zabbix_proxy_startdiscoverers }}
-StartHTTPPollers={{ zabbix_proxy_starthttppollers }}
-{% if zabbix_proxy_javagateway is defined and zabbix_proxy_javagateway %}
-JavaGateway={{ zabbix_proxy_javagateway }}
-JavaGatewayPort={{ zabbix_proxy_javagatewayport }}
-StartJavaPollers={{ zabbix_proxy_startjavapollers }}
-{% endif %}
-{% if zabbix_version is version_compare('2.4', '>=') %}
-StartVMwareCollectors={{ zabbix_proxy_startvmwarecollector }}
-VMwareFrequency={{ zabbix_proxy_vmwarefrequency }}
-VMwareCacheSize={{ zabbix_proxy_vmwarecachesize -}}M
-{% endif %}
-SNMPTrapperFile={{ zabbix_proxy_snmptrapperfile }}
-StartSNMPTrapper={{ zabbix_proxy_snmptrapper }}
-{% if zabbix_proxy_listenip is defined and zabbix_proxy_listenip %}
-ListenIP={{ zabbix_proxy_listenip }}
-{% endif %}
-HousekeepingFrequency={{ zabbix_proxy_housekeepingfrequency }}
-CacheSize={{ zabbix_proxy_cachesize -}}M
-StartDBSyncers={{ zabbix_proxy_startdbsyncers }}
-HistoryCacheSize={{ zabbix_proxy_historycachesize -}}M
-{% if zabbix_version is version_compare('3.2', '>=') %}
-HistoryIndexCacheSize={{ zabbix_proxy_historyindexcachesize -}}M
-{% endif %}
-{% if zabbix_version is version_compare('2.4', '<') %}
-HistoryTextCacheSize={{ zabbix_proxy_historytextcachesize -}}M
-{% endif %}
-Timeout={{ zabbix_proxy_timeout }}
-TrapperTimeout={{ zabbix_proxy_trappertimeout }}
-UnreachablePeriod={{ zabbix_proxy_unreachableperiod }}
-UnavailableDelay={{ zabbix_proxy_unavaliabledelay }}
-UnreachableDelay={{ zabbix_proxy_unreachabedelay }}
-{% if zabbix_version is version_compare('6.2', '>=') %}
-StartODBCPollers={{ zabbix_proxy_startodbcpollers }}
-{% endif %}
-ExternalScripts={{ zabbix_proxy_externalscripts }}
-FpingLocation={{ zabbix_proxy_fpinglocation }}
-Fping6Location={{ zabbix_proxy_fping6location }}
-{% if zabbix_proxy_sshkeylocation is defined and zabbix_proxy_sshkeylocation %}
-SSHKeyLocation={{ zabbix_proxy_sshkeylocation }}
-{% endif %}
-LogSlowQueries={{ zabbix_proxy_loglowqueries }}
-TmpDir={{ zabbix_proxy_tmpdir }}
-{% if zabbix_version is version_compare('2.4', '<') %}
-AllowRoot={{ zabbix_proxy_allowroot }}
-{% endif %}
-Include={{ zabbix_proxy_include }}
-{% if zabbix_version is version_compare('3.0', '<') %}
-LoadModulePath={{ zabbix_proxy_loadmodulepath }}
-{% endif %}
-{% if zabbix_proxy_loadmodule is defined and zabbix_proxy_loadmodule %}
-LoadModule={{ zabbix_proxy_loadmodule }}
-{% endif %}
-{% if zabbix_version is version_compare('4.0', '>=') %}
-StatsAllowedIP={{ zabbix_proxy_statsallowedip }}
-{% endif %}
-{% if zabbix_version is version_compare('3.0', '>=') %}
-{% if zabbix_proxy_tlsconnect is defined and zabbix_proxy_tlsconnect %}
-TLSConnect={{ zabbix_proxy_tlsconnect }}
-{% endif %}
-{% if zabbix_proxy_tlsaccept is defined and zabbix_proxy_tlsaccept %}
-TLSAccept={{ zabbix_proxy_tlsaccept }}
-{% endif %}
-{% if zabbix_proxy_tlscafile is defined and zabbix_proxy_tlscafile %}
-TLSCAFile={{ zabbix_proxy_tlscafile }}
-{% endif %}
-{% if zabbix_proxy_tlscrlfile is defined and zabbix_proxy_tlscrlfile %}
-TLSCRLFile={{ zabbix_proxy_tlscrlfile }}
-{% endif %}
-{% if zabbix_proxy_tlsservercertissuer is defined and zabbix_proxy_tlsservercertissuer %}
-TLSServerCertIssuer={{ zabbix_proxy_tlsservercertissuer }}
-{% endif %}
-{% if zabbix_proxy_tlsservercertsubject is defined and zabbix_proxy_tlsservercertsubject %}
-TLSServerCertSubject={{ zabbix_proxy_tlsservercertsubject }}
-{% endif %}
-{% if zabbix_proxy_tlscertfile is defined and zabbix_proxy_tlscertfile %}
-TLSCertFile={{ zabbix_proxy_tlscertfile }}
-{% endif %}
-{% if zabbix_proxy_tlskeyfile is defined and zabbix_proxy_tlskeyfile %}
-TLSKeyFile={{ zabbix_proxy_tlskeyfile }}
-{% endif %}
-{% if zabbix_proxy_tlspskidentity is defined and zabbix_proxy_tlspskidentity %}
-TLSPSKIdentity={{ zabbix_proxy_tlspskidentity }}
-{% endif %}
-{% if zabbix_proxy_tlspskfile is defined and zabbix_proxy_tlspskfile %}
-TLSPSKFile={{ zabbix_proxy_tlspskfile }}
-{% endif %}
-{% endif %}
-{% if zabbix_proxy_dbtlsconnect is defined and zabbix_proxy_dbtlsconnect is not none %}
-DBTLSConnect={{ zabbix_proxy_dbtlsconnect }}
-{% endif %}
-{% if zabbix_proxy_dbtlscafile is defined and zabbix_proxy_dbtlscafile is not none %}
-DBTLSCAFile={{ zabbix_proxy_dbtlscafile }}
-{% endif %}
-{% if zabbix_proxy_dbtlscertfile is defined and zabbix_proxy_dbtlscertfile is not none %}
-DBTLSCertFile={{ zabbix_proxy_dbtlscertfile }}
-{% endif %}
-{% if zabbix_proxy_dbtlskeyfile is defined and zabbix_proxy_dbtlskeyfile is not none %}
-DBTLSKeyFile={{ zabbix_proxy_dbtlskeyfile }}
-{% endif %}
-{% if zabbix_proxy_dbtlscipher is defined and zabbix_proxy_dbtlscipher is not none %}
-DBTLSCipher={{ zabbix_proxy_dbtlscipher }}
-{% endif %}
-{% if zabbix_proxy_dbtlscipher13 is defined and zabbix_proxy_dbtlscipher13 is not none %}
-DBTLSCipher13={{ zabbix_proxy_dbtlscipher13 }}
-{% endif %}
-{% if zabbix_version is version('6.0', '>=') %}
-{% if zabbix_proxy_vaulttoken is defined and zabbix_proxy_vaulttoken is not none %}
-VaultToken={{ zabbix_proxy_vaulttoken }}
-{% endif %}
-{% if zabbix_proxy_vaulturl is defined and zabbix_proxy_vaulturl is not none %}
-VaultURL={{ zabbix_proxy_vaulturl }}
-{% endif %}
-{% if zabbix_proxy_vaultdbpath is defined and zabbix_proxy_vaultdbpath is not none %}
-VaultDBPath={{ zabbix_proxy_vaultdbpath }}
-{% endif %}
-{% if zabbix_proxy_vaulttlscertfile is defined and zabbix_proxy_vaulttlscertfile is not none %}
-VaultTLSKeyFile={{ zabbix_proxy_vaulttlscertfile }}
-{% endif %}
-{% if zabbix_proxy_vaulttlskeyfile is defined and zabbix_proxy_vaulttlskeyfile is not none %}
-VaultTLSCertFile={{ zabbix_proxy_vaulttlskeyfile }}
-{% endif %}
-{% if zabbix_proxy_listenbacklog is defined and zabbix_proxy_listenbacklog is not none %}
-ListenBacklog={{ zabbix_proxy_listenbacklog }}
-{% endif %}
-{% endif %}
+{{ (zabbix_proxy_allowroot is defined and zabbix_proxy_allowroot is not none) | ternary('','# ') }}AllowRoot={{ zabbix_proxy_allowroot | default('') }}
+{% if zabbix_proxy_version is version('6.0', '>=') %}
+{{ (zabbix_proxy_allowunsupporteddbversions is defined and zabbix_proxy_allowunsupporteddbversions is not none) | ternary('','# ') }}AllowUnsupportedDBVersions={{ zabbix_proxy_allowunsupporteddbversions | default('') }}
+{% endif %}
+{{ (zabbix_proxy_cachesize is defined and zabbix_proxy_cachesize is not none) | ternary('','# ') }}CacheSize={{ zabbix_proxy_cachesize | default('') }}
+{{ (zabbix_proxy_configfrequency is defined and zabbix_proxy_configfrequency is not none) | ternary('','# ') }}ConfigFrequency={{ zabbix_proxy_configfrequency | default('') }}
+{{ (zabbix_proxy_datasenderfrequency is defined and zabbix_proxy_datasenderfrequency is not none) | ternary('','# ') }}DataSenderFrequency={{ zabbix_proxy_datasenderfrequency | default('') }}
+{{ (zabbix_proxy_dbhost is defined and zabbix_proxy_dbhost is not none) | ternary('','# ') }}DBHost={{ zabbix_proxy_dbhost | default('') }}
+{{ (zabbix_proxy_dbname is defined and zabbix_proxy_dbname is not none) | ternary('','# ') }}DBName={{ zabbix_proxy_dbname | default('') }}
+{{ (zabbix_proxy_dbpassword is defined and zabbix_proxy_dbpassword is not none) | ternary('','# ') }}DBPassword={{ zabbix_proxy_dbpassword | default('') }}
+{{ (zabbix_proxy_dbschema is defined and zabbix_proxy_dbschema is not none) | ternary('','# ') }}DBSchema={{ zabbix_proxy_dbschema | default('') }}
+{{ (zabbix_proxy_dbsocket is defined and zabbix_proxy_dbsocket is not none) | ternary('','# ') }}DBSocket={{ zabbix_proxy_dbsocket | default('') }}
+{{ (zabbix_proxy_dbtlscafile is defined and zabbix_proxy_dbtlscafile is not none) | ternary('','# ') }}DBTLSCAFile={{ zabbix_proxy_dbtlscafile | default('') }}
+{{ (zabbix_proxy_dbtlscertfile is defined and zabbix_proxy_dbtlscertfile is not none) | ternary('','# ') }}DBTLSCertFile={{ zabbix_proxy_dbtlscertfile | default('') }}
+{{ (zabbix_proxy_dbtlscipher is defined and zabbix_proxy_dbtlscipher is not none) | ternary('','# ') }}DBTLSCipher={{ zabbix_proxy_dbtlscipher | default('') }}
+{{ (zabbix_proxy_dbtlscipher13 is defined and zabbix_proxy_dbtlscipher13 is not none) | ternary('','# ') }}DBTLSCipher13={{ zabbix_proxy_dbtlscipher13 | default('') }}
+{{ (zabbix_proxy_dbtlsconnect is defined and zabbix_proxy_dbtlsconnect is not none) | ternary('','# ') }}DBTLSConnect={{ zabbix_proxy_dbtlsconnect | default('') }}
+{{ (zabbix_proxy_dbtlskeyfile is defined and zabbix_proxy_dbtlskeyfile is not none) | ternary('','# ') }}DBTLSKeyFile={{ zabbix_proxy_dbtlskeyfile | default('') }}
+{{ (zabbix_proxy_dbuser is defined and zabbix_proxy_dbuser is not none) | ternary('','# ') }}DBUser={{ zabbix_proxy_dbuser | default('') }}
+{{ (zabbix_proxy_debuglevel is defined and zabbix_proxy_debuglevel is not none) | ternary('','# ') }}DebugLevel={{ zabbix_proxy_debuglevel | default('') }}
+{{ (zabbix_proxy_enableremotecommands is defined and zabbix_proxy_enableremotecommands is not none) | ternary('','# ') }}EnableRemoteCommands={{ zabbix_proxy_enableremotecommands | default('') }}
+{{ (zabbix_proxy_externalscripts is defined and zabbix_proxy_externalscripts is not none) | ternary('','# ') }}ExternalScripts={{ zabbix_proxy_externalscripts | default('') }}
+{{ (zabbix_proxy_fping6location is defined and zabbix_proxy_fping6location is not none) | ternary('','# ') }}Fping6Location={{ zabbix_proxy_fping6location | default('') }}
+{{ (zabbix_proxy_fpinglocation is defined and zabbix_proxy_fpinglocation is not none) | ternary('','# ') }}FpingLocation={{ zabbix_proxy_fpinglocation | default('') }}
+{% if zabbix_proxy_version is version('6.4', '<') %}
+{{ (zabbix_proxy_heartbeatfrequency is defined and zabbix_proxy_heartbeatfrequency is not none) | ternary('','# ') }}HeartbeatFrequency={{ zabbix_proxy_heartbeatfrequency | default('') }}
+{% endif %}
+{{ (zabbix_proxy_historycachesize is defined and zabbix_proxy_historycachesize is not none) | ternary('','# ') }}HistoryCacheSize={{ zabbix_proxy_historycachesize | default('') }}
+{{ (zabbix_proxy_historyindexcachesize is defined and zabbix_proxy_historyindexcachesize is not none) | ternary('','# ') }}HistoryIndexCacheSize={{ zabbix_proxy_historyindexcachesize | default('') }}
+{{ (zabbix_proxy_hostname is defined and zabbix_proxy_hostname is not none) | ternary('','# ') }}Hostname={{ zabbix_proxy_hostname | default('') }}
+{{ (zabbix_proxy_hostnameitem is defined and zabbix_proxy_hostnameitem is not none) | ternary('','# ') }}HostnameItem={{ zabbix_proxy_hostnameitem | default('') }}
+{{ (zabbix_proxy_housekeepingfrequency is defined and zabbix_proxy_housekeepingfrequency is not none) | ternary('','# ') }}HousekeepingFrequency={{ zabbix_proxy_housekeepingfrequency | default('') }}
+{{ (zabbix_proxy_include is defined and zabbix_proxy_include is not none) | ternary('','# ') }}Include={{ zabbix_proxy_include | default('') }}
+{{ (zabbix_proxy_javagateway is defined and zabbix_proxy_javagateway is not none) | ternary('','# ') }}JavaGateway={{ zabbix_proxy_javagateway | default('') }}
+{{ (zabbix_proxy_javagatewayport is defined and zabbix_proxy_javagatewayport is not none) | ternary('','# ') }}JavaGatewayPort={{ zabbix_proxy_javagatewayport | default('') }}
+{{ (zabbix_proxy_listenbacklog is defined and zabbix_proxy_listenbacklog is not none) | ternary('','# ') }}ListenBacklog={{ zabbix_proxy_listenbacklog | default('') }}
+{{ (zabbix_proxy_listenip is defined and zabbix_proxy_listenip is not none) | ternary('','# ') }}ListenIP={{ zabbix_proxy_listenip | default('') }}
+{{ (zabbix_proxy_listenport is defined and zabbix_proxy_listenport is not none) | ternary('','# ') }}ListenPort={{ zabbix_proxy_listenport | default('') }}
+{{ (zabbix_proxy_loadmodule is defined and zabbix_proxy_loadmodule is not none) | ternary('','# ') }}LoadModule={{ zabbix_proxy_loadmodule | default('') }}
+{{ (zabbix_proxy_loadmodulepath is defined and zabbix_proxy_loadmodulepath is not none) | ternary('','# ') }}LoadModulePath={{ zabbix_proxy_loadmodulepath | default('') }}
+{{ (zabbix_proxy_logfile is defined and zabbix_proxy_logfile is not none) | ternary('','# ') }}LogFile={{ zabbix_proxy_logfile | default('') }}
+{{ (zabbix_proxy_logfilesize is defined and zabbix_proxy_logfilesize is not none) | ternary('','# ') }}LogFileSize={{ zabbix_proxy_logfilesize | default('') }}
+{{ (zabbix_proxy_logremotecommands is defined and zabbix_proxy_logremotecommands is not none) | ternary('','# ') }}LogRemoteCommands={{ zabbix_proxy_logremotecommands | default('') }}
+{{ (zabbix_proxy_logslowqueries is defined and zabbix_proxy_logslowqueries is not none) | ternary('','# ') }}LogSlowQueries={{ zabbix_proxy_logslowqueries | default('') }}
+{{ (zabbix_proxy_logtype is defined and zabbix_proxy_logtype is not none) | ternary('','# ') }}LogType={{ zabbix_proxy_logtype | default('') }}
+{{ (zabbix_proxy_pidfile is defined and zabbix_proxy_pidfile is not none) | ternary('','# ') }}PidFile={{ zabbix_proxy_pidfile | default('') }}
+{{ (zabbix_proxy_proxylocalbuffer is defined and zabbix_proxy_proxylocalbuffer is not none) | ternary('','# ') }}ProxyLocalBuffer={{ zabbix_proxy_proxylocalbuffer | default('') }}
+{{ (zabbix_proxy_proxymode is defined and zabbix_proxy_proxymode is not none) | ternary('','# ') }}ProxyMode={{ zabbix_proxy_proxymode | default('') }}
+{{ (zabbix_proxy_proxyofflinebuffer is defined and zabbix_proxy_proxyofflinebuffer is not none) | ternary('','# ') }}ProxyOfflineBuffer={{ zabbix_proxy_proxyofflinebuffer | default('') }}
+{{ (zabbix_proxy_server is defined and zabbix_proxy_server is not none) | ternary('','# ') }}Server={{ zabbix_proxy_server | default('') }}
+{{ (zabbix_proxy_snmptrapperfile is defined and zabbix_proxy_snmptrapperfile is not none) | ternary('','# ') }}SNMPTrapperFile={{ zabbix_proxy_snmptrapperfile | default('') }}
+{{ (zabbix_proxy_socketdir is defined and zabbix_proxy_socketdir is not none) | ternary('','# ') }}SocketDir={{ zabbix_proxy_socketdir | default('') }}
+{{ (zabbix_proxy_sourceip is defined and zabbix_proxy_sourceip is not none) | ternary('','# ') }}SourceIP={{ zabbix_proxy_sourceip | default('') }}
+{{ (zabbix_proxy_sshkeylocation is defined and zabbix_proxy_sshkeylocation is not none) | ternary('','# ') }}SSHKeyLocation={{ zabbix_proxy_sshkeylocation | default('') }}
+{{ (zabbix_proxy_sslcalocation is defined and zabbix_proxy_sslcalocation is not none) | ternary('','# ') }}SSLCALocation={{ zabbix_proxy_sslcalocation | default('') }}
+{{ (zabbix_proxy_sslcertlocation is defined and zabbix_proxy_sslcertlocation is not none) | ternary('','# ') }}SSLCertLocation={{ zabbix_proxy_sslcertlocation | default('') }}
+{{ (zabbix_proxy_sslkeylocation is defined and zabbix_proxy_sslkeylocation is not none) | ternary('','# ') }}SSLKeyLocation={{ zabbix_proxy_sslkeylocation | default('') }}
+{{ (zabbix_proxy_startdbsyncers is defined and zabbix_proxy_startdbsyncers is not none) | ternary('','# ') }}StartDBSyncers={{ zabbix_proxy_startdbsyncers | default('') }}
+{{ (zabbix_proxy_startdiscoverers is defined and zabbix_proxy_startdiscoverers is not none) | ternary('','# ') }}StartDiscoverers={{ zabbix_proxy_startdiscoverers | default('') }}
+{% if zabbix_proxy_version is version('6.0', '==') %}
+{{ (zabbix_proxy_starthistorypollers is defined and zabbix_proxy_starthistorypollers is not none) | ternary('','# ') }}={{ zabbix_proxy_starthistorypollers | default('') }}
+{% endif %}
+{{ (zabbix_proxy_starthttppollers is defined and zabbix_proxy_starthttppollers is not none) | ternary('','# ') }}StartHTTPPollers={{ zabbix_proxy_starthttppollers | default('') }}
+{{ (zabbix_proxy_startipmipollers is defined and zabbix_proxy_startipmipollers is not none) | ternary('','# ') }}StartIPMIPollers={{ zabbix_proxy_startipmipollers | default('') }}
+{{ (zabbix_proxy_startjavapollers is defined and zabbix_proxy_startjavapollers is not none) | ternary('','# ') }}StartJavaPollers={{ zabbix_proxy_startjavapollers | default('') }}
+{{ (zabbix_proxy_startodbcpollers is defined and zabbix_proxy_startodbcpollers is not none) | ternary('','# ') }}StartODBCPollers={{ zabbix_proxy_startodbcpollers | default('') }}
+{{ (zabbix_proxy_startpingers is defined and zabbix_proxy_startpingers is not none) | ternary('','# ') }}StartPingers={{ zabbix_proxy_startpingers | default('') }}
+{{ (zabbix_proxy_startpollers is defined and zabbix_proxy_startpollers is not none) | ternary('','# ') }}StartPollers={{ zabbix_proxy_startpollers | default('') }}
+{{ (zabbix_proxy_startpollersunreachable is defined and zabbix_proxy_startpollersunreachable is not none) | ternary('','# ') }}StartPollersUnreachable={{ zabbix_proxy_startpollersunreachable | default('') }}
+{{ (zabbix_proxy_startpreprocessors is defined and zabbix_proxy_startpreprocessors is not none) | ternary('','# ') }}StartPreprocessors={{ zabbix_proxy_startpreprocessors | default('') }}
+{{ (zabbix_proxy_startsnmptrapper is defined and zabbix_proxy_startsnmptrapper is not none) | ternary('','# ') }}StartSNMPTrapper={{ zabbix_proxy_startsnmptrapper | default('') }}
+{{ (zabbix_proxy_starttrappers is defined and zabbix_proxy_starttrappers is not none) | ternary('','# ') }}StartTrappers={{ zabbix_proxy_starttrappers | default('') }}
+{{ (zabbix_proxy_startvmwarecollectors is defined and zabbix_proxy_startvmwarecollectors is not none) | ternary('','# ') }}StartVMwareCollectors={{ zabbix_proxy_startvmwarecollectors | default('') }}
+{{ (zabbix_proxy_statsallowedip is defined and zabbix_proxy_statsallowedip is not none) | ternary('','# ') }}StatsAllowedIP={{ zabbix_proxy_statsallowedip | default('') }}
+{{ (zabbix_proxy_timeout is defined and zabbix_proxy_timeout is not none) | ternary('','# ') }}Timeout={{ zabbix_proxy_timeout | default('') }}
+{{ (zabbix_proxy_tlsaccept is defined and zabbix_proxy_tlsaccept is not none) | ternary('','# ') }}TLSAccept={{ zabbix_proxy_tlsaccept | default('') }}
+{{ (zabbix_proxy_tlscafile is defined and zabbix_proxy_tlscafile is not none) | ternary('','# ') }}TLSCAFile={{ zabbix_proxy_tlscafile | default('') }}
+{{ (zabbix_proxy_tlscertfile is defined and zabbix_proxy_tlscertfile is not none) | ternary('','# ') }}TLSCertFile={{ zabbix_proxy_tlscertfile | default('') }}
+{{ (zabbix_proxy_tlscipherall is defined and zabbix_proxy_tlscipherall is not none) | ternary('','# ') }}TLSCipherAll={{ zabbix_proxy_tlscipherall | default('') }}
+{{ (zabbix_proxy_tlscipherall13 is defined and zabbix_proxy_tlscipherall13 is not none) | ternary('','# ') }}TLSCipherAll13={{ zabbix_proxy_tlscipherall13 | default('') }}
+{{ (zabbix_proxy_tlsciphercert is defined and zabbix_proxy_tlsciphercert is not none) | ternary('','# ') }}TLSCipherCert={{ zabbix_proxy_tlsciphercert | default('') }}
+{{ (zabbix_proxy_tlsciphercert13 is defined and zabbix_proxy_tlsciphercert13 is not none) | ternary('','# ') }}TLSCipherCert13={{ zabbix_proxy_tlsciphercert13 | default('') }}
+{{ (zabbix_proxy_tlscipherpsk is defined and zabbix_proxy_tlscipherpsk is not none) | ternary('','# ') }}TLSCipherPSK={{ zabbix_proxy_tlscipherpsk | default('') }}
+{{ (zabbix_proxy_tlscipherpsk13 is defined and zabbix_proxy_tlscipherpsk13 is not none) | ternary('','# ') }}TLSCipherPSK13={{ zabbix_proxy_tlscipherpsk13 | default('') }}
+{{ (zabbix_proxy_tlsconnect is defined and zabbix_proxy_tlsconnect is not none) | ternary('','# ') }}TLSConnect={{ zabbix_proxy_tlsconnect | default('') }}
+{{ (zabbix_proxy_tlscrlfile is defined and zabbix_proxy_tlscrlfile is not none) | ternary('','# ') }}TLSCRLFile={{ zabbix_proxy_tlscrlfile | default('') }}
+{{ (zabbix_proxy_tlskeyfile is defined and zabbix_proxy_tlskeyfile is not none) | ternary('','# ') }}TLSKeyFile={{ zabbix_proxy_tlskeyfile | default('') }}
+{{ (zabbix_proxy_tlspskfile is defined and zabbix_proxy_tlspskfile is not none) | ternary('','# ') }}TLSPSKFile={{ zabbix_proxy_tlspskfile | default('') }}
+{{ (zabbix_proxy_tlspskidentity is defined and zabbix_proxy_tlspskidentity is not none) | ternary('','# ') }}TLSPSKIdentity={{ zabbix_proxy_tlspskidentity | default('') }}
+{{ (zabbix_proxy_tlsservercertissuer is defined and zabbix_proxy_tlsservercertissuer is not none) | ternary('','# ') }}TLSServerCertIssuer={{ zabbix_proxy_tlsservercertissuer | default('') }}
+{{ (zabbix_proxy_tlsservercertsubject is defined and zabbix_proxy_tlsservercertsubject is not none) | ternary('','# ') }}TLSServerCertSubject={{ zabbix_proxy_tlsservercertsubject | default('') }}
+{{ (zabbix_proxy_tmpdir is defined and zabbix_proxy_tmpdir is not none) | ternary('','# ') }}TmpDir={{ zabbix_proxy_tmpdir | default('') }}
+{{ (zabbix_proxy_trappertimeout is defined and zabbix_proxy_trappertimeout is not none) | ternary('','# ') }}TrapperTimeout={{ zabbix_proxy_trappertimeout | default('') }}
+{{ (zabbix_proxy_unavailabledelay is defined and zabbix_proxy_unavailabledelay is not none) | ternary('','# ') }}UnavailableDelay={{ zabbix_proxy_unavailabledelay | default('') }}
+{{ (zabbix_proxy_unreachabledelay is defined and zabbix_proxy_unreachabledelay is not none) | ternary('','# ') }}UnreachableDelay={{ zabbix_proxy_unreachabledelay | default('') }}
+{{ (zabbix_proxy_unreachableperiod is defined and zabbix_proxy_unreachableperiod is not none) | ternary('','# ') }}UnreachablePeriod={{ zabbix_proxy_unreachableperiod | default('') }}
+{{ (zabbix_proxy_user is defined and zabbix_proxy_user is not none) | ternary('','# ') }}User={{ zabbix_proxy_user | default('') }}
+{% if zabbix_proxy_version is version('6.2', '>=') %}
+{{ (zabbix_proxy_vault is defined and zabbix_proxy_vault is not none) | ternary('','# ') }}Vault={{ zabbix_proxy_vault | default('') }}
+{% endif %}
+{{ (zabbix_proxy_vaultdbpath is defined and zabbix_proxy_vaultdbpath is not none) | ternary('','# ') }}VaultDBPath={{ zabbix_proxy_vaultdbpath | default('') }}
+{% if zabbix_proxy_version is version('6.2', '>=') %}
+{{ (zabbix_proxy_vaulttlscertfile is defined and zabbix_proxy_vaulttlscertfile is not none) | ternary('','# ') }}VaultTLSCertFile={{ zabbix_proxy_vaulttlscertfile | default('') }}
+{{ (zabbix_proxy_vaulttlskeyfile is defined and zabbix_proxy_vaulttlskeyfile is not none) | ternary('','# ') }}VaultTLSKeyFile={{ zabbix_proxy_vaulttlskeyfile | default('') }}
+{% endif %}
+{{ (zabbix_proxy_vaulttoken is defined and zabbix_proxy_vaulttoken is not none) | ternary('','# ') }}VaultToken={{ zabbix_proxy_vaulttoken | default('') }}
+{{ (zabbix_proxy_vaulturl is defined and zabbix_proxy_vaulturl is not none) | ternary('','# ') }}VaultURL={{ zabbix_proxy_vaulturl | default('') }}
+{{ (zabbix_proxy_vmwarecachesize is defined and zabbix_proxy_vmwarecachesize is not none) | ternary('','# ') }}VMwareCacheSize={{ zabbix_proxy_vmwarecachesize | default('') }}
+{{ (zabbix_proxy_vmwarefrequency is defined and zabbix_proxy_vmwarefrequency is not none) | ternary('','# ') }}VMwareFrequency={{ zabbix_proxy_vmwarefrequency | default('') }}
+{{ (zabbix_proxy_vmwareperffrequency is defined and zabbix_proxy_vmwareperffrequency is not none) | ternary('','# ') }}VMwarePerfFrequency={{ zabbix_proxy_vmwareperffrequency | default('') }}
+{{ (zabbix_proxy_vmwaretimeout is defined and zabbix_proxy_vmwaretimeout is not none) | ternary('','# ') }}VMwareTimeout={{ zabbix_proxy_vmwaretimeout | default('') }}
diff --git a/ansible_collections/community/zabbix/roles/zabbix_proxy/vars/Amazon.yml b/ansible_collections/community/zabbix/roles/zabbix_proxy/vars/Amazon.yml
deleted file mode 100644
index 605be3896..000000000
--- a/ansible_collections/community/zabbix/roles/zabbix_proxy/vars/Amazon.yml
+++ /dev/null
@@ -1,2 +0,0 @@
----
-ansible_distribution_major_version: "6"
diff --git a/ansible_collections/community/zabbix/roles/zabbix_proxy/vars/Debian.yml b/ansible_collections/community/zabbix/roles/zabbix_proxy/vars/Debian.yml
index 2c87e2d61..cd9527eb2 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_proxy/vars/Debian.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_proxy/vars/Debian.yml
@@ -1,26 +1,57 @@
zabbix_valid_proxy_versions:
# Debian
+ "12":
+ - 6.4
+ - 6.0
"11":
- 6.4
+ - 6.2
- 6.0
- - 5.0
- - 4.0
"10":
+ - 6.4
+ - 6.2
- 6.0
- - 5.0
- - 4.0
- "9":
- - 4.0
- # Ubuntu
"22":
- 6.4
+ - 6.2
- 6.0
"20":
- 6.4
+ - 6.2
- 6.0
- - 5.0
- - 4.0
"18":
+ - 6.4
+ - 6.2
- 6.0
- - 5.0
- - 4.0
+
+mysql_client_pkgs:
+ # Debian
+ "12":
+ - default-mysql-client
+ - "{{ zabbix_python_prefix }}-mysqldb"
+ "11":
+ - default-mysql-client
+ - "{{ zabbix_python_prefix }}-mysqldb"
+ "10":
+ - mariadb-client
+ - "{{ zabbix_python_prefix }}-mysqldb"
+ # Ubuntu
+ "22":
+ - default-mysql-client
+ - "{{ zabbix_python_prefix }}-mysqldb"
+ "20":
+ - default-mysql-client
+ - "{{ zabbix_python_prefix }}-mysqldb"
+ "18":
+ - default-mysql-client
+ - "{{ zabbix_python_prefix }}-mysqldb"
+
+mysql_plugin:
+ "18": mysql_native_password
+ "10": mysql_native_password
+
+debian_keyring_path: /etc/apt/keyrings/
+zabbix_gpg_key: "{{ debian_keyring_path }}/zabbix-official-repo.asc"
+_zabbix_repo_deb_url: "http://repo.zabbix.com/zabbix/{{ zabbix_proxy_version }}"
+_zabbix_proxy_fping6location: /usr/bin/fping6
+_zabbix_proxy_fpinglocation: /usr/bin/fping
diff --git a/ansible_collections/community/zabbix/roles/zabbix_proxy/vars/RedHat.yml b/ansible_collections/community/zabbix/roles/zabbix_proxy/vars/RedHat.yml
index 31da6800f..e8ee7e2ae 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_proxy/vars/RedHat.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_proxy/vars/RedHat.yml
@@ -1,12 +1,55 @@
zabbix_valid_proxy_versions:
"9":
- 6.4
+ - 6.2
- 6.0
"8":
- 6.4
+ - 6.2
- 6.0
- - 5.0
- - 4.0
"7":
- - 5.0
- - 4.0
+ - 6.4
+ - 6.2
+ - 6.0
+
+pgsql_depenencies:
+ "9":
+ - python3-psycopg2
+ - postgresql
+ "8":
+ - python3-psycopg2
+ - postgresql
+ "7":
+ - python-psycopg2
+ - postgresql
+
+mysql_client_pkgs:
+ "9":
+ - mysql
+ - python3-PyMySQL
+ "8":
+ - mysql
+ - python3-PyMySQL
+ "7":
+ - MariaDB-client
+ - MySQL-python
+
+selinux_pkgs:
+ "9":
+ - policycoreutils
+ - checkpolicy
+ - python3-libsemanage
+ "8":
+ - policycoreutils
+ - checkpolicy
+ - python3-libsemanage
+ "7":
+ - policycoreutils-python
+ - libsemanage-python
+ - checkpolicy
+
+mysql_plugin:
+ "7": mysql_native_password
+
+_zabbix_proxy_fping6location: /usr/sbin/fping6
+_zabbix_proxy_fpinglocation: /usr/sbin/fping
diff --git a/ansible_collections/community/zabbix/roles/zabbix_proxy/vars/main.yml b/ansible_collections/community/zabbix/roles/zabbix_proxy/vars/main.yml
index ea434bdc4..90779c270 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_proxy/vars/main.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_proxy/vars/main.yml
@@ -1,2 +1,7 @@
---
# vars file for zabbix_proxy
+db_file_path:
+ "62": "/usr/share/zabbix-sql-scripts/{{ zabbix_proxy_db_long }}/proxy.sql"
+ "64": "/usr/share/zabbix-sql-scripts/{{ zabbix_proxy_db_long }}/proxy.sql"
+ "60": "/usr/share/zabbix-sql-scripts/{{ zabbix_proxy_db_long }}/proxy.sql"
+ "50": "/usr/share/doc/zabbix-proxy-{{ zabbix_proxy_database }}*/schema.sql.gz"
diff --git a/ansible_collections/community/zabbix/roles/zabbix_proxy/vars/zabbix.yml b/ansible_collections/community/zabbix/roles/zabbix_proxy/vars/zabbix.yml
deleted file mode 100644
index 7ac7dc354..000000000
--- a/ansible_collections/community/zabbix/roles/zabbix_proxy/vars/zabbix.yml
+++ /dev/null
@@ -1,255 +0,0 @@
----
-sign_keys:
- "64":
- bullseye:
- sign_key: E709712C
- buster:
- sign_key: E709712C
- stretch:
- sign_key: E709712C
- focal:
- sign_key: E709712C
- bionic:
- sign_key: E709712C
- xenial:
- sign_key: E709712C
- trusty:
- sign_key: E709712C
- jammy:
- sign_key: E709712C
- "62":
- bullseye:
- sign_key: E709712C
- buster:
- sign_key: E709712C
- stretch:
- sign_key: E709712C
- focal:
- sign_key: E709712C
- bionic:
- sign_key: E709712C
- xenial:
- sign_key: E709712C
- trusty:
- sign_key: E709712C
- jammy:
- sign_key: E709712C
- "60":
- bullseye:
- sign_key: E709712C
- buster:
- sign_key: E709712C
- stretch:
- sign_key: E709712C
- focal:
- sign_key: E709712C
- bionic:
- sign_key: E709712C
- xenial:
- sign_key: E709712C
- trusty:
- sign_key: E709712C
- jammy:
- sign_key: E709712C
- "54":
- bullseye:
- sign_key: E709712C
- buster:
- sign_key: E709712C
- jessie:
- sign_key: E709712C
- stretch:
- sign_key: E709712C
- focal:
- sign_key: E709712C
- bionic:
- sign_key: E709712C
- xenial:
- sign_key: E709712C
- trusty:
- sign_key: E709712C
- tricia:
- sign_key: E709712C
- "52":
- # bullseye: not available upstream
- buster:
- sign_key: E709712C
- jessie:
- sign_key: E709712C
- stretch:
- sign_key: E709712C
- focal:
- sign_key: E709712C
- bionic:
- sign_key: E709712C
- xenial:
- sign_key: E709712C
- trusty:
- sign_key: E709712C
- tricia:
- sign_key: E709712C
- "50":
- bullseye:
- sign_key: E709712C
- buster:
- sign_key: E709712C
- jessie:
- sign_key: E709712C
- stretch:
- sign_key: E709712C
- focal:
- sign_key: E709712C
- bionic:
- sign_key: E709712C
- xenial:
- sign_key: E709712C
- trusty:
- sign_key: E709712C
- tricia:
- sign_key: E709712C
- "44":
- buster:
- sign_key: A14FE591
- jessie:
- sign_key: 79EA5ED4
- stretch:
- sign_key: A14FE591
- focal:
- sign_key: A14FE591
- eoan:
- sign_key: A14FE591
- cosmic:
- sign_key: A14FE591
- bionic:
- sign_key: A14FE591
- sonya:
- sign_key: A14FE591
- serena:
- sign_key: A14FE591
- trusty:
- sign_key: 79EA5ED4
- xenial:
- sign_key: E709712C
- "42":
- buster:
- sign_key: A14FE591
- jessie:
- sign_key: 79EA5ED4
- stretch:
- sign_key: A14FE591
- eoan:
- sign_key: A14FE591
- cosmic:
- sign_key: A14FE591
- bionic:
- sign_key: A14FE591
- sonya:
- sign_key: A14FE591
- serena:
- sign_key: A14FE591
- trusty:
- sign_key: 79EA5ED4
- xenial:
- sign_key: E709712C
- "40":
- bullseye:
- sign_key: A14FE591
- buster:
- sign_key: A14FE591
- jessie:
- sign_key: 79EA5ED4
- stretch:
- sign_key: A14FE591
- focal:
- sign_key: A14FE591
- bionic:
- sign_key: A14FE591
- sonya:
- sign_key: A14FE591
- serena:
- sign_key: A14FE591
- trusty:
- sign_key: 79EA5ED4
- xenial:
- sign_key: E709712C
- "34":
- jessie:
- sign_key: 79EA5ED4
- stretch:
- sign_key: A14FE591
- wheezy:
- sign_key: A14FE591
- bionic:
- sign_key: A14FE591
- sonya:
- sign_key: A14FE591
- serena:
- sign_key: A14FE591
- trusty:
- sign_key: 79EA5ED4
- xenial:
- sign_key: E709712C
- "32":
- stretch:
- sign_key: A14FE591
- wheezy:
- sign_key: 79EA5ED4
- bionic:
- sign_key: A14FE591
- sonya:
- sign_key: 79EA5ED4
- serena:
- sign_key: 79EA5ED4
- trusty:
- sign_key: 79EA5ED4
- xenial:
- sign_key: E709712C
- "30":
- buster:
- sign_key: A14FE591
- jessie:
- sign_key: 79EA5ED4
- stretch:
- sign_key: A14FE591
- wheezy:
- sign_key: 79EA5ED4
- bionic:
- sign_key: A14FE591
- trusty:
- sign_key: 79EA5ED4
- xenial:
- sign_key: E709712C
- "24":
- jessie:
- sign_key: 79EA5ED4
- wheezy:
- sign_key: 79EA5ED4
- precise:
- sign_key: 79EA5ED4
- trusty:
- sign_key: 79EA5ED4
- "22":
- squeeze:
- sign_key: 79EA5ED4
- wheezy:
- sign_key: 79EA5ED4
- precise:
- sign_key: 79EA5ED4
- trusty:
- sign_key: 79EA5ED4
- lucid:
- sign_key: 79EA5ED4
-
-suse:
- "openSUSE Leap":
- "42":
- name: server:monitoring
- url: http://download.opensuse.org/repositories/server:/monitoring/openSUSE_Leap_{{ ansible_distribution_version }}/
- "openSUSE":
- "12":
- name: server_monitoring
- url: http://download.opensuse.org/repositories/server:/monitoring/openSUSE_{{ ansible_distribution_version }}
- "SLES":
- "11":
- name: server_monitoring
- url: http://download.opensuse.org/repositories/server:/monitoring/SLE_11_SP3/
diff --git a/ansible_collections/community/zabbix/roles/zabbix_server/README.md b/ansible_collections/community/zabbix/roles/zabbix_server/README.md
index 4643fbc3f..f154f4951 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_server/README.md
+++ b/ansible_collections/community/zabbix/roles/zabbix_server/README.md
@@ -75,26 +75,16 @@ ansible-galaxy collection install community.postgresql
See the following list of supported Operating systems with the Zabbix releases:
-| Zabbix | 6.4 | 6.2 | 6.0 | 5.4 | 5.2 | 5.0 (LTS) | 4.4 | 4.0 (LTS) | 3.0 (LTS) |
-|---------------------|-----|-----|-----|-----|-----|-----------|-----|-----------|-----------|
-| Red Hat Fam 9 | V | V | V | | | | | | |
-| Red Hat Fam 8 | V | V | V | V | V | V | V | | |
-| Red Hat Fam 7 | | | | | | V | V | V | V |
-| Red Hat Fam 6 | | | | | V | V | | | V |
-| Red Hat Fam 5 | | | | | V | V | | | V |
-| Fedora | | | | | | | V | V | |
-| Ubuntu 20.04 focal | V | V | V | V | V | V | | V | |
-| Ubuntu 18.04 bionic | | | V | V | V | V | V | V | |
-| Ubuntu 16.04 xenial | | | | | V | V | V | V | |
-| Ubuntu 14.04 trusty | | | | | V | V | V | V | V |
-| Debian 10 buster | | | V | V | V | V | V | | |
-| Debian 9 stretch | | | V | V | V | V | V | V | |
-| Debian 8 jessie | | | | | V | V | V | V | V |
-| Debian 7 wheezy | | | | | | | | V | V |
-| macOS 10.15 | | | | | | | V | V | |
-| macOS 10.14 | | | | | | | V | V | |
-
-See https://support.zabbix.com/browse/ZBX-18790 why RHEL7 is not supported anymore.
+| Zabbix | 6.4 | 6.2 | 6.0 |
+|---------------------|-----|-----|-----|
+| Red Hat Fam 9 | V | V | V |
+| Red Hat Fam 8 | V | V | V |
+| Ubuntu 22.04 jammy | V | V | V |
+| Ubuntu 20.04 focal | V | V | V |
+| Ubuntu 18.04 bionic | | | V |
+| Debian 12 bookworm | V | | V |
+| Debian 11 bullseye | V | V | V |
+| Debian 10 buster | | | V |
# Installation
@@ -110,112 +100,48 @@ The following is an overview of all available configuration default for this rol
### Overall Zabbix
-* `zabbix_server_version`: This is the version of zabbix. Default: The highest supported version for the operating system. Can be overridden to 6.2, 6.0, 5.4, 5.2, 5.0, 4.4, 4.0, 3.4, 3.2, 3.0, 2.4, or 2.2. Previously the variable `zabbix_version` was used directly but it could cause [some inconvenience](https://github.com/dj-wasabi/ansible-zabbix-agent/pull/303). That variable is maintained by retrocompativility.
+* `zabbix_server_version`: Optional. The latest available major.minor version of Zabbix will be installed on the host(s). If you want to use an older version, please specify this in the major.minor format. Example: `zabbix_server_version: 6.0`.
* `zabbix_server_version_minor`: When you want to specify a minor version to be installed. RedHat only. Default set to: `*` (latest available)
-* `zabbix_repo`: Default: `zabbix`
- * `epel`: install agent from EPEL repo
- * `zabbix`: (default) install agent from Zabbix repo
- * `other`: install agent from pre-existing or other repo
* `zabbix_repo_yum`: A list with Yum repository configuration.
* `zabbix_repo_yum_schema`: Default: `https`. Option to change the web schema for the yum repository(http/https)
-* `zabbix_repo_yum_disabled`: A string with repository names that should be disabled when installing Zabbix component specific packages. Is only used when `zabbix_repo_yum_enabled` contains 1 or more repositories. Default `*`.
-* `zabbix_repo_yum_enabled`: A list with repository names that should be enabled when installing Zabbix component specific packages.
+* `zabbix_server_disable_repo`: A list of repos to disable during install. Default `epel`.
* `zabbix_service_state`: Default: `started`. Can be overridden to stopped if needed
* `zabbix_service_enabled`: Default: `True` Can be overridden to `False` if needed
+* `zabbix_repo_deb_url`: The URL to the Zabbix repository. Default `http://repo.zabbix.com/zabbix/{{ zabbix_server_version }}/{{ ansible_distribution.lower() }}`
+* `zabbix_repo_deb_component`: The repository component for Debian installs. Default `main`.
### SElinux
-* `zabbix_selinux`: Default: `False`. Enables an SELinux policy so that the server will run.
+* `zabbix_server_selinux`: Default: `False`. Enables an SELinux policy so that the server will run.
* `selinux_allow_zabbix_can_network`: Default: `False`.
* `selinux_allow_zabbix_can_http`: Default: `False`.
### Zabbix Server
* `zabbix_server_package_state`: Default: `present`. Can be overridden to `latest` to update packages when needed.
-* `zabbix_server_listenport`: Default: `10051`. On which port the Zabbix Server is available.
* `zabbix_server_install_recommends`: Default: `True`. `False` does not install the recommended packages that come with the zabbix-server install.
* `zabbix_server_manage_service`: Default: `True`. When you run multiple Zabbix servers in a High Available cluster setup (e.g. pacemaker), you don't want Ansible to manage the zabbix-server service, because Pacemaker is in control of zabbix-server service and in this case, it needs to be set to `False`.
-* `zabbix_proxy_startpreprocessors`: Number of pre-forked instances of preprocessing workers. The preprocessing manager process is automatically started when a preprocessor worker is started. This parameter is supported since Zabbix 4.2.0.
-* `zabbix_server_username`: Default: `zabbix`. The name of the account on the host. Will only be used when `zabbix_repo: epel` is used.
-* `zabbix_server_userid`: The UID of the account on the host. Will only be used when `zabbix_repo: epel` is used.
-* `zabbix_server_groupname`: Default: `zabbix`. The name of the group of the user on the host. Will only be used when `zabbix_repo: epel` is used.
-* `zabbix_server_groupid`: The GID of the group on the host. Will only be used when `zabbix_repo: epel` is used.
* `zabbix_server_include_mode`: Default: `0755`. The "mode" for the directory configured with `zabbix_server_include`.
* `zabbix_server_conf_mode`: Default: `0640`. The "mode" for the Zabbix configuration file.
-* `zabbix_server_listenbacklog`: The maximum number of pending connections in the queue.
-* `zabbix_server_trendcachesize`: Size of trend cache, in bytes.
-* `zabbix_server_trendfunctioncachesize`: Size of trend function cache, in bytes.
-* `zabbix_server_vaulttoken`: Vault authentication token that should have been generated exclusively for Zabbix server with read only permission
-* `zabbix_server_vaulturl`: Vault server HTTP[S] URL. System-wide CA certificates directory will be used if SSLCALocation is not specified.
-* `zabbix_server_vaultdbpath`: Vault path from where credentials for database will be retrieved by keys 'password' and 'username'.
-* `zabbix_server_startreportwriters`: Number of pre-forked report writer instances.
-* `zabbix_server_webserviceurl`: URL to Zabbix web service, used to perform web related tasks.
-* `zabbix_server_servicemanagersyncfrequency`: How often Zabbix will synchronize configuration of a service manager (in seconds).
-* `zabbix_server_problemhousekeepingfrequency`: How often Zabbix will delete problems for deleted triggers (in seconds).
-* `zabbix_server_connectors`: Number of pre-forked instances of preprocessing workers.
-
-### High Availability
-
-These variables are specific for Zabbix 6.0 and higher:
-
-* `zabbix_server_hanodename`: The high availability cluster node name. When empty, server is working in standalone mode; a node with empty name is registered with address for the frontend to connect to. (Default: empty)
-* `zabbix_server_nodeaddress`: IP or hostname with optional port to specify how frontend should connect to the server.
### Database specific
* `zabbix_server_dbhost_run_install`: Default: `True`. When set to `True`, sql files will be executed on the host running the database.
* `zabbix_server_database`: Default: `pgsql`. The type of database used. Can be: `mysql` or `pgsql`
-* `zabbix_server_database_long`: Default: `postgresql`. The type of database used, but long name. Can be: `mysql` or `postgresql`
* `zabbix_server_dbhost`: The hostname on which the database is running.
* `zabbix_server_real_dbhost`: The hostname of the dbhost that is running behind a loadbalancer/VIP (loadbalancers doesn't accept ssh connections)
* `zabbix_server_dbname`: The database name which is used by the Zabbix Server.
* `zabbix_server_dbuser`: The database username which is used by the Zabbix Server.
* `zabbix_server_dbpassword`: The database user password which is used by the Zabbix Server.
+* `zabbix_server_dbpassword_hash_method`: Default: `md5`. Allow switching postgresql user password creation to `scram-sha-256`, when anything other than `md5` is used then ansible won't hash the password with `md5`.
* `zabbix_server_dbport`: The database port which is used by the Zabbix Server.
* `zabbix_server_dbpassword_hash_method`: Default: `md5`. Allow switching postgresql user password creation to `scram-sha-256`, when anything other than `md5` is used then ansible won't hash the password with `md5`.
-* `zabbix_database_creation`: Default: `True`. When you don't want to create the database including user, you can set it to False.
+* `zabbix_server_database_creation`: Default: `True`. When you don't want to create the database including user, you can set it to False.
* `zabbix_server_install_database_client`: Default: `True`. False does not install database client. Default true
-* `zabbix_database_sqlload`:True / False. When you don't want to load the sql files into the database, you can set it to False.
-* `zabbix_database_timescaledb`:False / True. When you want to use timescaledb extension into the database, you can set it to True (this option only works for postgreSQL database).
+* `zabbix_server_database_sqlload`:True / False. When you don't want to load the sql files into the database, you can set it to False.
+* `zabbix_server_database_timescaledb`:False / True. When you want to use timescaledb extension into the database, you can set it to True (this option only works for postgreSQL database).
* `zabbix_server_dbencoding`: Default: `utf8`. The encoding for the MySQL database.
* `zabbix_server_dbcollation`: Default: `utf8_bin`. The collation for the MySQL database.
-* `zabbix_server_allowunsupporteddbversions`: Allow server to work with unsupported database versions.
-
-### TLS Specific configuration
-
-These variables are specific for Zabbix 3.0 and higher:
-
-* `zabbix_server_tlsconnect`: How the agent should connect to server or proxy. Used for active checks.
- Possible values:
- * unencrypted
- * psk
- * cert
-* `zabbix_server_tlsaccept`: What incoming connections to accept.
- Possible values:
- * unencrypted
- * psk
- * cert
-* `zabbix_server_tlscafile`: Full pathname of a file containing the top-level CA(s) certificates for peer certificate verification.
-* `zabbix_server_tlscrlfile`: Full pathname of a file containing revoked certificates.
-* `zabbix_server_tlsservercertissuer`: Allowed server certificate issuer.
-* `zabbix_server_tlsservercertsubject`: Allowed server certificate subject.
-* `zabbix_server_tlscertfile`: Full pathname of a file containing the agent certificate or certificate chain.
-* `zabbix_server_tlskeyfile`: Full pathname of a file containing the agent private key.
-* `zabbix_server_dbtlsconnect`: Setting this option enforces to use TLS connection to database:
-
-`required` - connect using TLS
-`verify_ca` - connect using TLS and verify certificate
-`verify_full` - connect using TLS, verify certificate and verify that database identity specified by DBHost matches its certificate
-
-On `MySQL` starting from 5.7.11 and `PostgreSQL` the following values are supported: `required`, `verify`, `verify_full`. On MariaDB starting from version 10.2.6 `required` and `verify_full` values are supported.
-By default not set to any option and the behaviour depends on database configuration.
-This parameter is supported since Zabbix 5.0.0.
-
-* `zabbix_server_dbtlscafile`: Full pathname of a file containing the top-level CA(s) certificates for database certificate verification. This parameter is supported since Zabbix 5.0.0.
-* `zabbix_server_dbtlscertfile`: Full pathname of file containing Zabbix server certificate for authenticating to database. This parameter is supported since Zabbix 5.0.0.
-* `zabbix_server_dbtlskeyfile`: Full pathname of file containing the private key for authenticating to database. This parameter is supported since Zabbix 5.0.0.
-* `zabbix_server_dbtlscipher`: The list of encryption ciphers that Zabbix server permits for TLS protocols up through TLSv1.2. Supported only for MySQL.This parameter is supported since Zabbix 5.0.0.
-* `zabbix_server_dbtlscipher13`: The list of encryption ciphersuites that Zabbix server permits for TLSv1.3 protocol. Supported only for MySQL, starting from version 8.0.16. This parameter is supported since Zabbix 5.0.0.
### Custom Zabbix Scripts
@@ -350,6 +276,135 @@ The `zabbix_server_privileged_host` can be set to the hostname/ip of the host ru
3. Execute the role by running the Ansible playbook that calls this role. At the end of this run, the Zabbix Server with `PgSQL` on a different host will be running.
+## Configuration Variables
+
+The following table lists all variables that are exposed to modify the configuration of the zabbix_server.conf file. Specific details of each variable can be found in the Zabbix documentation.
+
+**NOTE**: Only variables with a default value appear in the defaults file, all others must be added.
+
+| Zabbix Name | Variable Name | Default Value |Notes |
+|-----------|------------------|--------|--------|
+|AlertScriptsPath | zabbix_server_alertscriptspath | /usr/lib/zabbix/alertscripts | |
+|AllowRoot | zabbix_server_allowroot | 0 | |
+|AllowUnsupportedDBVersions | zabbix_server_allowunsupporteddbversions |0 | |
+|CacheSize | zabbix_server_cachesize | | |
+|CacheUpdateFrequency | zabbix_server_cacheupdatefrequency | | |
+|DBHost | zabbix_server_dbhost | localhost | |
+|DBName | zabbix_server_dbname | zabbix-server | |
+|DBPassword | zabbix_server_dbpassword | zabbix-server | |
+|DBPort | zabbix_server_dbport | 5432 | |
+|DBSchema | zabbix_server_dbschema | | |
+|DBSocket | zabbix_server_dbsocket | | |
+|DBTLSCAFile | zabbix_server_dbtlscafile | | |
+|DBTLSCertFile | zabbix_server_dbtlscertfile | | |
+|DBTLSCipher | zabbix_server_dbtlscipher | | |
+|DBTLSCipher13 | zabbix_server_dbtlscipher13 | | |
+|DBTLSConnect | zabbix_server_dbtlsconnect | | |
+|DBTLSKeyFile | zabbix_server_dbtlskeyfile | | |
+|DBUser | zabbix_server_dbuser | zabbix-server | |
+|DebugLevel | zabbix_server_debuglevel | 3 | |
+|ExportDir | zabbix_server_exportdir | | |
+|ExportFileSize | zabbix_server_exportfilesize | 1G | |
+|ExportType | zabbix_server_exporttype | | |
+|ExternalScripts | zabbix_server_externalscriptspath | /usr/lib/zabbix/externalscripts | |
+|Fping6Location | zabbix_server_fping6location | OS Specific Value | |
+|FpingLocation | zabbix_server_fpinglocation | OS Specific Value | |
+|HANodeName | zabbix_server_hanodename | | |
+|HistoryCacheSize | zabbix_server_historycachesize | | |
+|HistoryIndexCacheSize | zabbix_server_historyindexcachesize | | |
+|HistoryStorageDateIndex | zabbix_server_historystoragedateindex | 0 | |
+|HistoryStorageTypes | zabbix_server_historystoragetypes | uint,dbl,str,log,text | |
+|HistoryStorageURL | zabbix_server_historystorageurl | | |
+|HousekeepingFrequency | zabbix_server_housekeepingfrequency | 1 | |
+|Include | zabbix_server_include | /etc/zabbix/zabbix_server.conf.d | |
+|JavaGateway | zabbix_server_javagateway | | |
+|JavaGatewayPort | zabbix_server_javagatewayport | 10052 | |
+|ListenBacklog | zabbix_server_listenbacklog | | |
+|ListenIP | zabbix_server_listenip | | |
+|ListenPort | zabbix_server_listenport | 10051 | |
+|LoadModule | zabbix_server_loadmodule | | |
+|LoadModulePath | zabbix_server_loadmodulepath | ${libdir}/modules | |
+|LogFile | zabbix_server_logfile | /var/log/zabbix/zabbix_server.log | |
+|LogFileSize | zabbix_server_logfilesize | 10 | |
+|LogSlowQueries | zabbix_server_logslowqueries | 0 | |
+|LogType | zabbix_server_logtype | file | |
+|MaxHousekeeperDelete | zabbix_server_maxhousekeeperdelete | 500 | |
+|NodeAddress | zabbix_server_nodeaddress | | |
+|PidFile | zabbix_server_pidfile | /var/run/zabbix/zabbix_server.pid | |
+|ProxyConfigFrequency | zabbix_server_proxyconfigfrequency | | |
+|ProxyDataFrequency | zabbix_server_proxydatafrequency | 1 | |
+|SNMPTrapperFile | zabbix_server_snmptrapperfile | | |
+|SocketDir | zabbix_server_socketdir | /var/run/zabbix | |
+|SourceIP | zabbix_server_sourceip | | |
+|SSHKeyLocation | zabbix_server_sshkeylocation | | |
+|SSLCALocation | zabbix_server_sslcalocation | | |
+|SSLCertLocation | zabbix_server_sslcertlocation | ${datadir}/zabbix/ssl/certs | |
+|SSLKeyLocation | zabbix_server_sslkeylocation | ${datadir}/zabbix/ssl/keys | |
+|StartAlerters | zabbix_server_startalerters | | |
+|StartConnectors | zabbix_server_connectors | | Version 6.4 or later |
+|StartDBSyncers | zabbix_server_startdbsyncers | 4 | |
+|StartDiscoverers | zabbix_server_startdiscoverers | 1 | |
+|StartEscalators | zabbix_server_startescalators | 1 | |
+|StartHistoryPollers | zabbix_server_starthistorypollers | | |
+|StartHTTPPollers | zabbix_server_starthttppollers | 1 | |
+|StartIPMIPollers | zabbix_server_startipmipollers | 0 | |
+|StartJavaPollers | zabbix_server_startjavapollers | 0 | |
+|StartLLDProcessors | zabbix_server_startlldprocessors | | |
+|StartODBCPollers | zabbix_server_startodbcpollers | | |
+|StartPingers | zabbix_server_startpingers | 1 | |
+|StartPollers | zabbix_server_startpollers | 5 | |
+|StartPollersUnreachable | zabbix_server_startpollersunreachable | 1 | |
+|StartPreprocessors | zabbix_server_startpreprocessors | | |
+|StartProxyPollers | zabbix_server_startproxypollers | | |
+|StartReportWriters | zabbix_server_startreportwriters | 0 | |
+|StartSNMPTrapper | zabbix_server_startsnmptrapper | 0 | |
+|StartTimers | zabbix_server_starttimers | 1 | |
+|StartTrappers | zabbix_server_starttrappers | 5 | |
+|StartVMwareCollectors | zabbix_server_startvmwarecollectors | 0 | |
+|StasAllowedIP | zabbix_server_statsallowedip | | |
+|Timeout | zabbix_server_timeout | 3 | |
+|TLSCAFile | zabbix_server_tlscafile | | |
+|TLSCertFile | zabbix_server_tlscertfile | | |
+|TLSCipherAll | zabbix_server_tlscipherall | | |
+|TLSCipherAll13 | zabbix_server_tlscipherall13 | | |
+|TLSCipherCert | zabbix_server_tlsciphercert | | |
+|TLSCipherCert13 | zabbix_server_tlsciphercert13 | | |
+|TLSCipherPSK | zabbix_server_tlscipherpsk | | |
+|TLSCipherPSK13 | zabbix_server_tlscipherpsk13 | | |
+|TLSCRLFile | zabbix_server_tlscrlfile | | |
+|TLSKeyFile | zabbix_server_tlskeyfile | | |
+|TmpDir | zabbix_server_tmpdir | /tmp | |
+|TrapperTimeout | zabbix_server_trappertimeout | 300 | |
+|TrendCacheSize | zabbix_server_trendcachesize | | |
+|TrendFunctionCacheSize | zabbix_server_trendfunctioncachesize | | |
+|UnavailableDelay | zabbix_server_unavailabledelay | 60 | |
+|UnreachableDelay | zabbix_server_unreachabledelay | 15 | |
+|UnreachablePeriod | zabbix_server_unreachableperiod | 45 | |
+|User | zabbix_server_user | zabbix | |
+|ValueCacheSize | zabbix_server_valuecachesize | | |
+|Vault | zabbix_server_vault | | Version 6.2 or later |
+|VaultDBPath | zabbix_server_vaultdbpath | | |
+|VaultTLSKeyFile | zabbix_server_vaulttlskeyfile | | Version 6.2 or later |
+|VaultTLSCertFile | zabbix_server_vaulttlscertfile | | Version 6.2 or later |
+|VaultToken | zabbix_server_vaulttoken | | |
+|VaultURL | zabbix_server_vaulturl | https://127.0.0.1:8200 | |
+|VMwareCacheSize | zabbix_server_vmwarecachesize | | |
+|VMwareFrequency | zabbix_server_vmwarefrequency | 60 | |
+|VMwarePerfFrequency | zabbix_server_vmwareperffrequency | 60 | |
+|VMwareTimeout | zabbix_server_vmwaretimeout | 10 | |
+|WebServiceURL | zabbix_server_webserviceurl | | |
+
+## Tags
+
+The majority of tasks within this role are tagged as follows:
+
+* `install`: Tasks associated with the installation of software.
+* `dependencies`: Installation tasks related to dependencies that aren't part of the core zabbix installation.
+* `database`: Tasks associated with the installation or configuration of the database.
+* `api`: Tasks associated with using the Zabbix API to connect and modify the Zabbix server.
+* `config`: Tasks associated with the configuration of Zabbix or a supporting service.
+* `service`: Tasks associated with managing a service.
+
# Example Playbook
Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
diff --git a/ansible_collections/community/zabbix/roles/zabbix_server/defaults/main.yml b/ansible_collections/community/zabbix/roles/zabbix_server/defaults/main.yml
index e9b837c99..6aec202dd 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_server/defaults/main.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_server/defaults/main.yml
@@ -1,28 +1,52 @@
---
# defaults file for zabbix_server
+# zabbix_server_version:
+zabbix_os_user: zabbix
+zabbix_service_enabled: true
+zabbix_server_manage_service: true
-# zabbix_server_version: 6.0
-zabbix_server_version_minor: "*"
-zabbix_version: "{{ zabbix_server_version }}"
-zabbix_repo: zabbix
-
-zabbix_server_apt_priority:
-zabbix_server_package_state: present
-zabbix_server_install_recommends: true
+# Database
+zabbix_server_database_sqlload: true
+zabbix_server_database_timescaledb: false
+zabbix_server_real_dbhost:
+zabbix_server_dbhost: localhost
+zabbix_server_dbname: zabbix-server
+zabbix_server_privileged_host: localhost
+zabbix_server_dbencoding: utf8
+zabbix_server_dbcollation: utf8_bin
+zabbix_server_dbschema:
+zabbix_server_dbuser: zabbix-server
+zabbix_server_dbpassword: zabbix-server
+zabbix_server_dbpassword_hash_method: md5
+zabbix_server_dbsocket:
+zabbix_server_dbport: 5432
+zabbix_server_dbhost_run_install: true
+zabbix_server_database: pgsql
+zabbix_server_database_creation: true
zabbix_server_install_database_client: true
-zabbix_server_conf_mode: 0640
+# SELinux specific
+zabbix_server_selinux: false
+selinux_allow_zabbix_can_network: false
+selinux_allow_zabbix_can_http: false
+
+#Misc.
+zabbix_server_include_mode: "0755"
+zabbix_server_config: /etc/zabbix/zabbix_server.conf
zabbix_service_state: started
-zabbix_service_enabled: true
+# Yum/APT Variables
+zabbix_server_version_minor: "*"
+zabbix_server_package_state: present
zabbix_repo_yum_gpgcheck: 0
zabbix_repo_yum_schema: https
-zabbix_repo_yum_disabled: "*"
-zabbix_repo_yum_enabled: []
+zabbix_repo_deb_component: main
+zabbix_server_disable_repo:
+ - epel
zabbix_repo_yum:
- name: zabbix
description: Zabbix Official Repository - $basearch
- baseurl: "{{ zabbix_repo_yum_schema }}://repo.zabbix.com/zabbix/{{ zabbix_version | regex_search('^[0-9]+.[0-9]+') }}/rhel/{{ ansible_distribution_major_version }}/$basearch/"
+ baseurl: "{{ zabbix_repo_yum_schema }}://repo.zabbix.com/zabbix/{{ zabbix_server_version | regex_search('^[0-9]+.[0-9]+') }}/rhel/{{ ansible_distribution_major_version }}/$basearch/"
gpgcheck: "{{ zabbix_repo_yum_gpgcheck }}"
mode: "0644"
gpgkey: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ZABBIX
@@ -34,128 +58,58 @@ zabbix_repo_yum:
gpgcheck: "{{ zabbix_repo_yum_gpgcheck }}"
gpgkey: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ZABBIX
state: present
+zabbix_server_apt_priority:
+zabbix_server_install_recommends: true
+zabbix_server_conf_mode: 0640
-# User (EPEL specific)
-zabbix_server_username: zabbix
-zabbix_server_groupname: zabbix
-
-# Database
-zabbix_server_database: pgsql
-zabbix_server_database_long: postgresql
-zabbix_database_creation: true
-zabbix_database_sqlload: true
-zabbix_database_timescaledb: false
-zabbix_server_dbtlsconnect:
-zabbix_server_dbtlscafile:
-zabbix_server_dbtlscertfile:
-zabbix_server_dbtlskeyfile:
-zabbix_server_dbtlscipher:
-zabbix_server_dbtlscipher13:
-
-# zabbix-server specific vars
+# Server Configuration Variables (Only ones with role provided defaults)
+zabbix_server_alertscriptspath: /usr/lib/zabbix/alertscripts
+zabbix_server_allowroot: 0
+zabbix_server_allowunsupporteddbversions: 0
+zabbix_server_debuglevel: 3
+zabbix_server_exportfilesize: 1G
+zabbix_server_externalscriptspath: /usr/lib/zabbix/externalscripts
+zabbix_server_historystoragedateindex: 0
+zabbix_server_historystoragetypes: uint,dbl,str,log,text
+zabbix_server_housekeepingfrequency: 1
+zabbix_server_include: /etc/zabbix/zabbix_server.conf.d
+zabbix_server_javagatewayport: 10052
zabbix_server_listenport: 10051
-zabbix_server_sourceip:
-zabbix_server_logtype: file
+zabbix_server_loadmodulepath: ${libdir}/modules
zabbix_server_logfile: /var/log/zabbix/zabbix_server.log
zabbix_server_logfilesize: 10
-zabbix_server_debuglevel: 3
+zabbix_server_logslowqueries: 0
+zabbix_server_logtype: file
+zabbix_server_maxhousekeeperdelete: 500
zabbix_server_pidfile: /var/run/zabbix/zabbix_server.pid
+zabbix_server_proxydatafrequency: 1
+zabbix_server_snmptrapperfile: /tmp/zabbix_traps.tmp
zabbix_server_socketdir: /var/run/zabbix
-zabbix_server_real_dbhost:
-zabbix_server_dbhost: localhost
-zabbix_server_dbname: zabbix-server
-zabbix_server_dbencoding: utf8
-zabbix_server_dbcollation: utf8_bin
-zabbix_server_dbschema:
-zabbix_server_dbuser: zabbix-server
-zabbix_server_dbpassword: zabbix-server
-zabbix_server_dbsocket:
-zabbix_server_dbport: 5432
-zabbix_server_dbhost_run_install: true
-zabbix_server_dbpassword_hash_method: md5
-zabbix_server_allowunsupporteddbversions: 0
-zabbix_server_privileged_host: localhost
-zabbix_server_historystorageurl:
-zabbix_server_historystoragetypes: uint,dbl,str,log,text
-zabbix_server_historystoragedateindex: 0
-zabbix_server_exportdir:
-zabbix_server_exportfilesize: 1G
-zabbix_server_startpollers: 5
-zabbix_server_startlldprocessors: 2
-zabbix_server_startipmipollers: 0
-zabbix_server_startpollersunreachable: 1
-zabbix_server_starttrappers: 5
-zabbix_server_startpingers: 1
+zabbix_server_sslcertlocation: ${datadir}/zabbix/ssl/certs
+zabbix_server_sslkeylocation: ${datadir}/zabbix/ssl/keys
+zabbix_server_startdbsyncers: 4
zabbix_server_startdiscoverers: 1
+zabbix_server_startescalators: 1
zabbix_server_starthttppollers: 1
-zabbix_server_startpreprocessors: 3
-zabbix_server_connectors: 0
-zabbix_server_startodbcpollers: 1
+zabbix_server_startipmipollers: 0
+zabbix_server_startjavapollers: 0
+zabbix_server_startpingers: 1
+zabbix_server_startpollers: 5
+zabbix_server_startpollersunreachable: 1
+zabbix_server_startproxypollers: 1
+zabbix_server_startreportwriters: 0
+zabbix_server_startsnmptrapper: 0
zabbix_server_starttimers: 1
-zabbix_server_starthistorypollers: 5
-zabbix_server_javagateway:
-zabbix_server_javagatewayport: 10052
-zabbix_server_startjavapollers: 5
+zabbix_server_starttrappers: 5
zabbix_server_startvmwarecollectors: 0
-zabbix_server_vmwarefrequency: 60
-zabbix_server_vmwarecachesize: 8M
-zabbix_server_snmptrapperfile: /tmp/zabbix_traps.tmp
-zabbix_server_startsnmptrapper: 0
-zabbix_server_listenip:
-zabbix_server_housekeepingfrequency: 1
-zabbix_server_maxhousekeeperdelete: 500
-zabbix_server_senderfrequency: 30
-zabbix_server_cachesize: 32M
-zabbix_server_startdbsyncers: 4
-zabbix_server_historycachesize: 16M
-zabbix_server_historyindexcachesize: 4M
-zabbix_server_trendcachesize: 4M
-zabbix_server_trendfunctioncachesize: 4M
-zabbix_server_historytextcachesize: 16M
-zabbix_server_valuecachesize: 8M
-zabbix_server_nodenoevents: 0
-zabbix_server_nodenohistory: 0
zabbix_server_timeout: 3
+zabbix_server_tmpdir: /tmp
zabbix_server_trappertimeout: 300
-zabbix_server_unreachableperiod: 45
zabbix_server_unavailabledelay: 60
zabbix_server_unreachabledelay: 15
-zabbix_server_alertscriptspath: /usr/lib/zabbix/alertscripts
-zabbix_server_externalscriptspath: /usr/lib/zabbix/externalscripts
-zabbix_server_sshkeylocation:
-zabbix_server_logslowqueries: 0
-zabbix_server_tmpdir: /tmp
-zabbix_server_startproxypollers: 1
-zabbix_server_proxydatafrequency: 1
-zabbix_server_allowroot: 0
+zabbix_server_unreachableperiod: 45
zabbix_server_user: zabbix
-zabbix_server_include: /etc/zabbix/zabbix_server.conf.d
-zabbix_server_include_mode: "0755"
-zabbix_server_sslcertlocation: ${datadir}/zabbix/ssl/certs
-zabbix_server_sslkeylocation: ${datadir}/zabbix/ssl/keys
-zabbix_server_sslcalocation:
-zabbix_server_loadmodulepath: ${libdir}/modules
-zabbix_server_loadmodule:
-zabbix_server_tlscafile:
-zabbix_server_tlscrlfile:
-zabbix_server_tlscertfile:
-zabbix_server_tlskeyfile:
-zabbix_server_startescalators: 1
+zabbix_server_vaulturl: https://127.0.0.1:8200
+zabbix_server_vmwarefrequency: 60
zabbix_server_vmwareperffrequency: 60
zabbix_server_vmwaretimeout: 10
-zabbix_server_manage_service: true
-zabbix_server_vaulttoken:
-zabbix_server_vaulturl: https://127.0.0.1:8200
-zabbix_server_vaultdbpath:
-zabbix_server_startreportwriters: 0
-zabbix_server_webserviceurl:
-zabbix_server_servicemanagersyncfrequency: 60
-zabbix_server_problemhousekeepingfrequency: 60
-zabbix_server_listenbacklog:
-zabbix_server_hanodename:
-zabbix_server_nodeaddress:
-
-# SELinux specific
-zabbix_selinux: false
-selinux_allow_zabbix_can_network: false
-selinux_allow_zabbix_can_http: false
diff --git a/ansible_collections/community/zabbix/roles/zabbix_server/handlers/main.yml b/ansible_collections/community/zabbix/roles/zabbix_server/handlers/main.yml
index 74b15bdc5..b0e272e2d 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_server/handlers/main.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_server/handlers/main.yml
@@ -2,7 +2,7 @@
# handlers file for wdijkerman.zabbix
- name: zabbix-server restarted
- service:
+ ansible.builtin.service:
name: zabbix-server
state: restarted
enabled: true
@@ -10,20 +10,9 @@
become: true
when:
- zabbix_server_manage_service | bool
- - zabbix_repo != 'epel'
-
-- name: zabbix-server restarted
- service:
- name: zabbix-proxy-mysql{{ zabbix_proxy_database_long }}
- state: restarted
- enabled: true
- become: true
- when:
- - zabbix_proxy_manage_service | bool
- - zabbix_repo == 'epel'
- name: "clean repo files from proxy creds"
- shell: ls /etc/yum.repos.d/zabbix* && sed -i 's/^proxy =.*//' /etc/yum.repos.d/zabbix* || true
+ ansible.builtin.shell: ls /etc/yum.repos.d/zabbix* && sed -i 's/^proxy =.*//' /etc/yum.repos.d/zabbix* || true
become: true
when:
- ansible_os_family == 'RedHat'
diff --git a/ansible_collections/community/zabbix/roles/zabbix_server/tasks/Debian.yml b/ansible_collections/community/zabbix/roles/zabbix_server/tasks/Debian.yml
index d7d9a08e3..ccfe6f121 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_server/tasks/Debian.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_server/tasks/Debian.yml
@@ -1,76 +1,47 @@
---
-
-- name: "Include Zabbix gpg ids"
- include_vars: zabbix.yml
-
-- name: "Set some variables"
- set_fact:
- zabbix_short_version: "{{ zabbix_version | regex_replace('\\.', '') }}"
- zabbix_server_apt_repository:
- - "http://repo.zabbix.com/zabbix/{{ zabbix_version }}/{{ ansible_distribution.lower() }}/"
- - "{{ ansible_distribution_release }}"
- - "main"
- zabbix_underscore_version: "{{ zabbix_version | regex_replace('\\.', '_') }}"
- zabbix_python_prefix: "python{% if ansible_python_version is version('3', '>=') %}3{% endif %}"
- when:
- - ansible_machine != "aarch64"
-
-- name: "Set some variables"
- set_fact:
- zabbix_short_version: "{{ zabbix_version | regex_replace('\\.', '') }}"
- zabbix_server_apt_repository:
- - "http://repo.zabbix.com/zabbix/{{ zabbix_version }}/{{ ansible_distribution.lower() }}-arm64/"
- - "{{ ansible_distribution_release }}"
- - "main"
- zabbix_underscore_version: "{{ zabbix_version | regex_replace('\\.', '_') }}"
+- name: "Debian | Set some variables"
+ ansible.builtin.set_fact:
+ zabbix_short_version: "{{ zabbix_server_version | regex_replace('\\.', '') }}"
+ zabbix_underscore_version: "{{ zabbix_server_version | regex_replace('\\.', '_') }}"
zabbix_python_prefix: "python{% if ansible_python_version is version('3', '>=') %}3{% endif %}"
- when:
- - ansible_machine == "aarch64"
-
-
-- name: "Debian | Set some facts"
- set_fact:
- datafiles_path: /usr/share/zabbix-server-{{ zabbix_server_database }}
- when:
- - zabbix_version is version('3.0', '<')
tags:
- - zabbix-server
- - init
- - config
+ - always
-- name: "Debian | Set some facts for Zabbix >= 3.0 && < 5.4"
- set_fact:
- datafiles_path: /usr/share/doc/zabbix-server-{{ zabbix_server_database }}
- when:
- - zabbix_version is version('3.0', '>=')
- - zabbix_version is version('5.4', '<')
+- name: "Debian | Installing lsb-release"
+ ansible.builtin.apt:
+ pkg: lsb-release
+ update_cache: true
+ cache_valid_time: 3600
+ force: true
+ state: present
+ environment:
+ http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
+ https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
+ become: true
tags:
- - zabbix-server
- - init
- - config
+ - install
-- name: "Debian | Set some facts for Zabbix == 5.4"
- set_fact:
- datafiles_path: /usr/share/doc/zabbix-sql-scripts/{{ zabbix_server_database_long }}
+- name: "Debian | Update ansible_lsb fact"
+ ansible.builtin.setup:
+ gather_subset:
+ - lsb
+
+- name: "Debian | Repo URL"
+ ansible.builtin.set_fact:
+ zabbix_repo_deb_url: "{{ _zabbix_repo_deb_url }}/{{ ansible_lsb.id.lower() }}{{ '-arm64' if ansible_machine == 'aarch64' and ansible_lsb.id == 'debian' else ''}}"
when:
- - zabbix_version is version('5.4', '==')
+ - zabbix_repo_deb_url is undefined
tags:
- - zabbix-server
- - init
- - config
+ - always
-- name: "Debian | Set some facts for Zabbix >= 6.0"
- set_fact:
- datafiles_path: /usr/share/zabbix-sql-scripts/{{ zabbix_server_database_long }}
- when:
- - zabbix_version is version('6.0', '>=')
+- name: "Debian | Set some facts for Zabbix"
+ ansible.builtin.set_fact:
+ datafiles_path: /usr/share/zabbix-sql-scripts/{{ 'postgresql' if zabbix_server_database == 'pgsql' else 'mysql' }}
tags:
- - zabbix-server
- - init
- - config
+ - always
- name: "Debian | Installing gnupg"
- apt:
+ ansible.builtin.apt:
pkg: gnupg
update_cache: true
cache_valid_time: 3600
@@ -82,90 +53,104 @@
register: gnupg_installed
until: gnupg_installed is succeeded
become: true
+ tags:
+ - install
+
+# In releases older than Debian 12 and Ubuntu 22.04, /etc/apt/keyrings does not exist by default.
+# It SHOULD be created with permissions 0755 if it is needed and does not already exist.
+# See: https://wiki.debian.org/DebianRepository/UseThirdParty
+- name: "Debian | Create /etc/apt/keyrings/ on older versions"
+ ansible.builtin.file:
+ path: /etc/apt/keyrings/
+ state: directory
+ mode: "0755"
+ become: true
+ when:
+ - (ansible_distribution == "Ubuntu" and ansible_distribution_major_version < "22") or
+ (ansible_distribution == "Debian" and ansible_distribution_major_version < "12")
-- name: "Debian | Install gpg key"
- apt_key:
- id: "{{ sign_keys[zabbix_short_version][ansible_distribution_release]['sign_key'] }}"
+- name: "Debian | Download gpg key"
+ ansible.builtin.get_url:
url: http://repo.zabbix.com/zabbix-official-repo.key
+ dest: "{{ zabbix_gpg_key }}"
+ mode: "0644"
+ force: true
register: zabbix_server_repo_files_installed
until: zabbix_server_repo_files_installed is succeeded
- when:
- - zabbix_repo == "zabbix"
become: true
tags:
- - zabbix-server
- - init
+ - install
- name: "Debian | Installing repository {{ ansible_distribution }}"
- apt_repository:
- repo: "{{ item }} {{ zabbix_server_apt_repository | join(' ') }}"
- state: present
- when: zabbix_repo == "zabbix"
+ ansible.builtin.copy:
+ dest: /etc/apt/sources.list.d/zabbix.sources
+ owner: root
+ group: root
+ mode: 0644
+ content: |
+ Types: deb deb-src
+ Enabled: yes
+ URIs: {{ zabbix_repo_deb_url }}
+ Suites: {{ ansible_distribution_release }}
+ Components: {{ zabbix_repo_deb_component }}
+ Architectures: {{ 'amd64' if ansible_machine != 'aarch64' else 'arm64'}}
+ Signed-By: {{ zabbix_gpg_key }}
become: true
- with_items:
- - deb-src
- - deb
tags:
- - zabbix-server
- - init
+ - install
- name: "Debian | Create /etc/apt/preferences.d/"
- file:
+ ansible.builtin.file:
path: /etc/apt/preferences.d/
state: directory
- mode: '0755'
+ mode: "0755"
when:
- zabbix_server_apt_priority | int
become: true
+ tags:
+ - install
- name: "Debian | Configuring the weight for APT"
- copy:
+ ansible.builtin.copy:
dest: "/etc/apt/preferences.d/zabbix_server-{{ zabbix_proxy_database }}"
content: |
Package: zabbix_server-{{ zabbix_proxy_database }}
Pin: origin repo.zabbix.com
Pin-Priority: {{ zabbix_server_apt_priority }}
owner: root
- mode: '0644'
+ mode: "0644"
when:
- zabbix_server_apt_priority | int
become: true
-
-- name: Check if warn parameter can be used for shell module
- set_fact:
- produce_warn: False
- when: ansible_version.full is version("2.14", "<")
-
-- name: apt-get clean
- shell: apt-get clean; apt-get update
- args:
- warn: "{{ produce_warn | default(omit) }}"
- changed_when: false
- become: true
tags:
- - skip_ansible_lint
+ - install
# On certain 18.04 images, such as docker or lxc, dpkg is configured not to
# install files into paths /usr/share/doc/*
# Since this is where Zabbix installs its database schemas, we need to allow
# files to be installed to /usr/share/doc/zabbix*
-- name: Check for the dpkg exclude line
- command: grep -F 'path-exclude=/usr/share/doc/*' /etc/dpkg/dpkg.cfg.d/excludes
+- name: "Debian | Check for the dpkg exclude line"
+ ansible.builtin.command: grep -F 'path-exclude=/usr/share/doc/*' /etc/dpkg/dpkg.cfg.d/excludes
register: dpkg_exclude_line
failed_when: false
changed_when: false
check_mode: false
+ become: true
+ tags:
+ - install
-- name: Allow Zabbix dpkg installs to /usr/share/doc/zabbix*
- lineinfile:
+- name: "Debian | Allow Zabbix dpkg installs to /usr/share/doc/zabbix*"
+ ansible.builtin.lineinfile:
path: /etc/dpkg/dpkg.cfg.d/excludes
- line: 'path-include=/usr/share/doc/zabbix*'
+ line: "path-include=/usr/share/doc/zabbix*"
become: true
when:
- dpkg_exclude_line.rc == 0
+ tags:
+ - install
- name: "Debian | Installing zabbix-server-{{ zabbix_server_database }}"
- apt:
+ ansible.builtin.apt:
pkg: zabbix-server-{{ zabbix_server_database }}
state: "{{ zabbix_server_package_state }}"
update_cache: true
@@ -179,11 +164,10 @@
until: zabbix_server_package_installed is succeeded
become: true
tags:
- - zabbix-server
- - init
+ - install
- name: "Debian | Installing zabbix-sql-scripts"
- apt:
+ ansible.builtin.apt:
pkg: zabbix-sql-scripts
state: "{{ zabbix_server_package_state }}"
update_cache: true
@@ -196,84 +180,61 @@
register: zabbix_server_package_sql_installed
until: zabbix_server_package_sql_installed is succeeded
when:
- - zabbix_version is version('5.4', '>=')
- become: true
- tags:
- - zabbix-server
- - init
-
-- name: "Debian | Install Ansible module dependencies"
- apt:
- name: "{{ zabbix_python_prefix }}-psycopg2"
- state: present
- environment:
- http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
- https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
- register: zabbix_server_dependencies_installed
- until: zabbix_server_dependencies_installed is succeeded
- become: true
- when:
- - zabbix_database_creation
- tags:
- - zabbix-server
- - init
-
-- name: "Debian | Install Mysql Client package"
- apt:
- name:
- - default-mysql-client
- - "{{ zabbix_python_prefix }}-mysqldb"
- state: present
- environment:
- http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
- https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
- register: zabbix_server_dependencies_installed
- until: zabbix_server_dependencies_installed is succeeded
+ - zabbix_server_version is version('5.4', '>=')
become: true
- when:
- - zabbix_server_database == 'mysql'
- - zabbix_server_install_database_client
- - ansible_distribution_release != "buster"
tags:
- - zabbix-server
- - init
- - database
-
-- name: "Debian 10 | Install Mysql Client package"
- apt:
- name:
- - mariadb-client
- - "{{ zabbix_python_prefix }}-mysqldb"
- state: present
- environment:
- http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
- https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
- register: zabbix_server_dependencies_installed
- until: zabbix_server_dependencies_installed is succeeded
- become: true
- when:
- - zabbix_server_database == 'mysql'
- - zabbix_server_install_database_client
- - ansible_distribution_release == "buster"
- tags:
- - zabbix-server
- - init
- - database
-
-- name: "Debian | Install PostgreSQL Client package"
- apt:
- name: postgresql-client
- state: present
- environment:
- http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
- https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
- register: zabbix_server_dependencies_installed
- until: zabbix_server_dependencies_installed is succeeded
- become: true
- when:
- - zabbix_server_database == 'pgsql'
- - zabbix_server_install_database_client
+ - install
+
+- name: "Debian | Install Database Client Package"
+ block:
+ - name: "Debian | Install Mysql Client package"
+ ansible.builtin.apt:
+ name:
+ - default-mysql-client
+ - "{{ zabbix_python_prefix }}-mysqldb"
+ state: present
+ environment:
+ http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
+ https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
+ register: zabbix_server_dependencies_installed
+ until: zabbix_server_dependencies_installed is succeeded
+ become: true
+ when:
+ - zabbix_server_database == 'mysql'
+ - ansible_distribution_release != "buster"
+
+ - name: "Debian 10 | Install Mysql Client package"
+ ansible.builtin.apt:
+ name:
+ - mariadb-client
+ - "{{ zabbix_python_prefix }}-mysqldb"
+ state: present
+ environment:
+ http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
+ https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
+ register: zabbix_server_dependencies_installed
+ until: zabbix_server_dependencies_installed is succeeded
+ become: true
+ when:
+ - zabbix_server_database == 'mysql'
+ - ansible_distribution_release == "buster"
+
+ - name: "Debian | Install PostgreSQL Client package"
+ ansible.builtin.apt:
+ name:
+ - postgresql-client
+ - "{{ zabbix_python_prefix }}-psycopg2"
+ state: present
+ environment:
+ http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
+ https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
+ register: zabbix_server_dependencies_installed
+ until: zabbix_server_dependencies_installed is succeeded
+ become: true
+ when:
+ - zabbix_server_database == 'pgsql'
+ when: zabbix_server_install_database_client
tags:
- - zabbix-server
- - init
+ - install
- database
+ - dependencies
diff --git a/ansible_collections/community/zabbix/roles/zabbix_server/tasks/RedHat.yml b/ansible_collections/community/zabbix/roles/zabbix_server/tasks/RedHat.yml
index 5d6c33b31..fefd7e86c 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_server/tasks/RedHat.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_server/tasks/RedHat.yml
@@ -1,191 +1,84 @@
---
# Tasks specific for RedHat systems
-- name: "Set short version name"
- set_fact:
- zabbix_short_version: "{{ zabbix_version | regex_replace('\\.', '') }}"
+- name: "RedHat | Set short version name"
+ ansible.builtin.set_fact:
+ zabbix_short_version: "{{ zabbix_server_version | regex_replace('\\.', '') }}"
+ tags:
+ - always
- name: "RedHat | Use Zabbix package name"
- set_fact:
+ ansible.builtin.set_fact:
zabbix_server_package: "zabbix-server-{{ zabbix_server_database }}"
- when:
- - zabbix_repo == "zabbix" or zabbix_repo == "other"
- tags:
- - zabbix-server
-
-- name: "RedHat | Use EPEL package name"
- set_fact:
- zabbix_server_package: "zabbix{{ zabbix_short_version }}-server-{{ zabbix_server_database }}"
- when:
- - zabbix_repo == "epel"
- tags:
- - zabbix-server
-
-- name: "RedHat | Set some facts Zabbix <= 3.2"
- set_fact:
- datafiles_path: "/usr/share/doc/zabbix-server-{{ zabbix_server_database }}-{{ zabbix_version }}*"
- when:
- - zabbix_version is version('3.2', '<=')
tags:
- - zabbix-server
+ - always
-- name: "RedHat | Set facts for Zabbix > 3.2 && < 5.4"
- set_fact:
- datafiles_path: "/usr/share/doc/zabbix-server-{{ zabbix_server_database }}*"
- when:
- - zabbix_version is version('3.2', '>')
- - zabbix_version is version('5.4', '<')
+- name: "RedHat | Set facts for Zabbix"
+ ansible.builtin.set_fact:
+ datafiles_path: "/usr/share/zabbix-sql-scripts/{{ 'postgresql' if zabbix_server_database == 'pgsql' else 'mysql' }}"
tags:
- - zabbix-server
+ - always
-- name: "RedHat | Set facts for Zabbix == 5.4"
- set_fact:
- datafiles_path: "/usr/share/doc/zabbix-sql-scripts/{{ zabbix_server_database_long }}"
- when:
- - zabbix_version is version('5.4', '==')
- tags:
- - zabbix-server
-
-- name: "RedHat | Set facts for Zabbix >= 6.0"
- set_fact:
- datafiles_path: "/usr/share/zabbix-sql-scripts/{{ zabbix_server_database_long }}"
- when:
- - zabbix_version is version('6.0', '>=')
- tags:
- - zabbix-server
-
-- name: "RedHat | Set facts for RHEL8"
- set_fact:
- datafiles_path: "/usr/share/doc/zabbix-server-{{ zabbix_server_database }}"
- when:
- - ansible_distribution_major_version == "8"
- - zabbix_version is version('5.4', '<')
- tags:
- - zabbix-server
-
-- name: "RedHat | Set some facts EPEL"
- set_fact:
- datafiles_path: "/usr/share/zabbix-{{ zabbix_server_database_long }}"
- when:
- - zabbix_repo == "epel"
- tags:
- - zabbix-server
-
-- name: "RedHat | Create 'zabbix' group (EPEL)"
- group:
- name: "{{ zabbix_server_groupname | default('zabbix') }}"
- gid: "{{ zabbix_server_groupid | default(omit) }}"
- state: present
- become: true
- when:
- - zabbix_repo == "epel"
-
-- name: "RedHat | Create 'zabbix' user (EPEL)"
- user:
- name: "{{ zabbix_server_username | default('zabbix') }}"
- comment: Zabbix Monitoring System
- uid: "{{ zabbix_server_userid | default(omit) }}"
- group: zabbix
- become: true
- when:
- - zabbix_repo == "epel"
-
-- name: "Make sure old file is absent"
- file:
+- name: "RedHat | Make sure old file is absent"
+ ansible.builtin.file:
path: /etc/yum.repos.d/zabbix-supported.repo
state: absent
become: true
+ tags:
+ - install
- name: "RedHat | Install basic repo file"
- yum_repository:
+ ansible.builtin.yum_repository:
name: "{{ item.name }}"
description: "{{ item.description }}"
baseurl: "{{ item.baseurl }}"
gpgcheck: "{{ item.gpgcheck }}"
gpgkey: "{{ item.gpgkey }}"
mode: "{{ item.mode | default('0644') }}"
- priority: "{{ item.priority | default('98') }}"
+ priority: "{{ item.priority | default('99') }}"
state: "{{ item.state | default('present') }}"
proxy: "{{ zabbix_http_proxy | default(omit) }}"
with_items: "{{ zabbix_repo_yum }}"
register: yum_repo_installed
become: true
- when:
- zabbix_repo == "zabbix"
notify:
- "clean repo files from proxy creds"
tags:
- - zabbix-server
+ - install
- name: "RedHat | Installing zabbix-server-{{ zabbix_server_database }}"
- package:
+ ansible.builtin.package:
pkg: "{{ zabbix_server_package }}-{{ zabbix_server_version }}.{{ zabbix_server_version_minor }}"
state: "{{ zabbix_server_package_state }}"
- disablerepo: "{{ '*' if (zabbix_repo_yum_enabled | length>0) else omit }}"
- enablerepo: "{{ zabbix_repo_yum_enabled if zabbix_repo_yum_enabled is iterable and (zabbix_repo_yum_enabled | length>0) else omit }}"
+ disablerepo: "{{ zabbix_server_disable_repo | default(omit) }}"
environment:
http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
register: zabbix_server_package_installed
until: zabbix_server_package_installed is succeeded
- when:
- zabbix_repo != "other"
become: true
tags:
- - zabbix-server
-
-- name: "RedHat | Installing zabbix-server-{{ zabbix_server_database }} (When zabbix_repo == other)"
- package:
- pkg: "{{ zabbix_server_package }}-{{ zabbix_server_version }}.{{ zabbix_server_version_minor }}"
- state: "{{ zabbix_server_package_state }}"
- register: zabbix_server_package_installed
- until: zabbix_server_package_installed is succeeded
- when:
- zabbix_repo == "other"
- become: true
- tags:
- - zabbix-server
+ - install
- name: "RedHat | Installing zabbix-sql-scripts"
- package:
- pkg: "zabbix-sql-scripts-{{ zabbix_server_version }}.{{ zabbix_server_version_minor }}"
- state: "{{ zabbix_server_package_state }}"
- disablerepo: "{{ '*' if (zabbix_repo_yum_enabled | length>0) else omit }}"
- enablerepo: "{{ zabbix_repo_yum_enabled if zabbix_repo_yum_enabled is iterable and (zabbix_repo_yum_enabled | length>0) else omit }}"
- environment:
- http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
- https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
- register: zabbix_server_sql_package_installed
- until: zabbix_server_sql_package_installed is succeeded
- when:
- - zabbix_version is version('5.4', '>=')
- - zabbix_repo != "other"
- become: true
- tags:
- - zabbix-server
-
-
-- name: "RedHat | Installing zabbix-sql-scripts (When zabbix_repo == other)"
- package:
+ ansible.builtin.package:
pkg: "zabbix-sql-scripts-{{ zabbix_server_version }}.{{ zabbix_server_version_minor }}"
state: "{{ zabbix_server_package_state }}"
- disablerepo: "{{ '*' if (zabbix_repo_yum_enabled | length>0) else omit }}"
- enablerepo: "{{ zabbix_repo_yum_enabled if zabbix_repo_yum_enabled is iterable and (zabbix_repo_yum_enabled | length>0) else omit }}"
+ disablerepo: "{{ zabbix_server_disable_repo | default(omit) }}"
environment:
http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
register: zabbix_server_sql_package_installed
until: zabbix_server_sql_package_installed is succeeded
when:
- - zabbix_version is version('5.4', '>=')
- - zabbix_repo == "other"
+ - zabbix_server_version is version('6.0', '>=')
become: true
tags:
- - zabbix-server
+ - install
- name: "RedHat | Install Ansible module dependencies"
- yum:
- name: python-psycopg2
+ ansible.builtin.yum:
+ name: "{{ pgsql_depenencies[ansible_distribution_major_version] }}"
state: present
environment:
http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
@@ -194,103 +87,46 @@
until: zabbix_server_dependencies_installed is succeeded
become: true
when:
- - zabbix_database_creation
+ - zabbix_server_database_creation
- zabbix_server_database == 'pgsql'
- - ansible_distribution_major_version == "7" or ansible_distribution_major_version == "6"
tags:
- - zabbix-server
-
-- name: "RedHat | Install Ansible module dependencies on RHEL9 or RHEL8"
- yum:
- name: python3-psycopg2
- state: present
- environment:
- http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
- https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
- register: zabbix_server_dependencies_installed
- until: zabbix_server_dependencies_installed is succeeded
- become: true
- when:
- - zabbix_database_creation
- - zabbix_server_database == 'pgsql'
- - ansible_distribution_major_version|int >= 8
- tags:
- - zabbix-server
-
-- name: "RedHat | Install Mysql Client packages RHEL9 or RHEL8"
- yum:
- name:
- - mysql
- - python3-PyMySQL
- state: present
- environment:
- http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
- https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
- register: zabbix_server_dependencies_installed
- until: zabbix_server_dependencies_installed is succeeded
- become: true
- when:
- - zabbix_server_database == 'mysql'
- - zabbix_server_install_database_client
- - ansible_distribution_major_version|int >= 8
- tags:
- - zabbix-server
-
-- name: "RedHat | Install Mysql Client package RHEL7"
- yum:
- name:
- - mariadb
- - MySQL-python
- state: present
- environment:
- http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
- https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
- register: zabbix_server_dependencies_installed
- until: zabbix_server_dependencies_installed is succeeded
- become: true
- when:
- - zabbix_server_database == 'mysql'
- - zabbix_server_install_database_client
- - ansible_distribution_major_version == "7"
- tags:
- - zabbix-server
-
-- name: "RedHat | Install Mysql Client package RHEL5 - 6"
- yum:
- name:
- - mysql
- - MySQL-python
- state: present
- environment:
- http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
- https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
- register: zabbix_server_dependencies_installed
- until: zabbix_server_dependencies_installed is succeeded
- become: true
- when:
- - zabbix_server_database == 'mysql'
- - zabbix_server_install_database_client
- - ansible_distribution_major_version == "6" or ansible_distribution_major_version == "5"
- tags:
- - zabbix-server
-
-- name: "RedHat | Install PostgreSQL client package"
- yum:
- name: postgresql
- state: present
- environment:
- http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
- https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
- register: zabbix_server_dependencies_installed
- until: zabbix_server_dependencies_installed is succeeded
- become: true
- when:
- - zabbix_server_database == 'pgsql'
- - zabbix_server_install_database_client
- tags:
- - zabbix-server
-
-- name: "Configure SELinux when enabled"
- include_tasks: selinux.yml
- when:
- - zabbix_selinux | bool
+ - install
+ - dependencies
+
+- name: RedHat | Install Database Client Package
+ block:
+ - name: "RedHat | Install Mysql Client packages"
+ ansible.builtin.yum:
+ name: "{{ mysql_client_pkgs[ansible_distribution_major_version] }}"
+ state: present
+ environment:
+ http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
+ https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
+ register: zabbix_server_dependencies_installed
+ until: zabbix_server_dependencies_installed is succeeded
+ become: true
+ when:
+ - zabbix_server_database == 'mysql'
+
+ - name: "RedHat | Install PostgreSQL client package"
+ ansible.builtin.yum:
+ name: postgresql
+ state: present
+ environment:
+ http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
+ https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
+ register: zabbix_server_dependencies_installed
+ until: zabbix_server_dependencies_installed is succeeded
+ become: true
+ when:
+ - zabbix_server_database == 'pgsql'
+ when: zabbix_server_install_database_client
+ tags:
+ - install
+ - dependencies
+ - database
+
+- name: "RedHat | Configure SELinux when enabled"
+ ansible.builtin.include_tasks: selinux.yml
+ when:
+ - zabbix_server_selinux | bool
diff --git a/ansible_collections/community/zabbix/roles/zabbix_server/tasks/main.yml b/ansible_collections/community/zabbix/roles/zabbix_server/tasks/main.yml
index d3264883d..62674a7ff 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_server/tasks/main.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_server/tasks/main.yml
@@ -1,56 +1,74 @@
---
-# tasks file for wdijkerman.zabbix
-
-- name: "Include OS-specific variables"
- include_vars: "{{ ansible_os_family }}.yml"
+- name: Include OS-specific variables
+ ansible.builtin.include_vars: "{{ ansible_os_family }}.yml"
+ tags:
+ - always
- name: Determine Latest Supported Zabbix Version
- set_fact:
- zabbix_server_version: "{{ zabbix_valid_server_versions[ansible_distribution_major_version][0] | default(6.0) }}"
+ ansible.builtin.set_fact:
+ zabbix_server_version: "{{ zabbix_valid_server_versions[ansible_distribution_major_version][0] | default(6.4) }}"
when: zabbix_server_version is not defined
+ tags:
+ - always
+
+- name: Set More Variables
+ ansible.builtin.set_fact:
+ zabbix_db_type_long: "{{ 'postgresql' if zabbix_server_database == 'pgsql' else 'mysql' }}"
+ zabbix_valid_version: "{{ zabbix_server_version|float in zabbix_valid_server_versions[ansible_distribution_major_version] }}"
+ zabbix_server_fpinglocation: "{{ zabbix_server_fpinglocation if zabbix_server_fpinglocation is defined else _zabbix_server_fpinglocation}}"
+ zabbix_server_fping6location: "{{ zabbix_server_fping6location if zabbix_server_fping6location is defined else _zabbix_server_fping6location}}"
+ tags:
+ - always
+
+- name: Stopping Install of Invalid Version
+ ansible.builtin.fail:
+ msg: Zabbix version {{ zabbix_server_version }} is not supported on {{ ansible_distribution }} {{ ansible_distribution_major_version }}
+ when: not zabbix_valid_version
+ tags:
+ - always
-- name: "Install the correct repository"
- include_tasks: "{{ ansible_os_family }}.yml"
+- name: Install the correct repository
+ ansible.builtin.include_tasks: "{{ ansible_os_family }}.yml"
-- name: "Installing the {{ zabbix_server_database_long }} database"
- include_tasks: "{{ zabbix_server_database_long }}.yml"
+- name: Installing the {{ zabbix_db_type_long }} database
+ ansible.builtin.include_tasks: "{{ zabbix_db_type_long }}.yml"
- name: "Configure zabbix-server"
- template:
+ ansible.builtin.template:
src: zabbix_server.conf.j2
- dest: /etc/zabbix/zabbix_server.conf
- owner: zabbix
- group: zabbix
+ dest: "{{ zabbix_server_config }}"
+ owner: "{{ zabbix_os_user }}"
+ group: "{{ zabbix_os_user }}"
mode: "{{ zabbix_server_conf_mode }}"
+ become: true
notify:
- zabbix-server restarted
tags:
- - zabbix-server
- - init
- config
- name: "Create include dir zabbix-server"
- file:
+ ansible.builtin.file:
path: "{{ zabbix_server_include }}"
- owner: zabbix
- group: zabbix
+ owner: "{{ zabbix_os_user }}"
+ group: "{{ zabbix_os_user }}"
state: directory
mode: "{{ zabbix_server_include_mode }}"
+ become: true
tags:
- - zabbix-server
- - init
+ - install
- config
- name: "Add zabbix-server scripts"
- include_tasks: "scripts.yml"
+ ansible.builtin.include_tasks: "scripts.yml"
when: ( zabbix_server_alertscripts is defined ) or
( zabbix_server_externalscripts is defined )
- name: "Zabbix-server started"
- service:
+ ansible.builtin.service:
name: zabbix-server
state: "{{ zabbix_service_state }}"
enabled: "{{ zabbix_service_enabled }}"
+ become: true
tags:
- - zabbix-server
+ - service
when: zabbix_server_manage_service | bool
diff --git a/ansible_collections/community/zabbix/roles/zabbix_server/tasks/mysql.yml b/ansible_collections/community/zabbix/roles/zabbix_server/tasks/mysql.yml
index 9e419b125..aad009816 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_server/tasks/mysql.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_server/tasks/mysql.yml
@@ -1,21 +1,28 @@
---
# task file for mysql
-- name: "Set the correct delegated_dbhost (to support MySQL db deployment on a remote dbhost)"
- set_fact:
+
+- name: "MySQL | Set the correct delegated_dbhost (to support MySQL db deployment on a remote dbhost)"
+ ansible.builtin.set_fact:
delegated_dbhost: "{{ zabbix_server_dbhost if (zabbix_server_dbhost != 'localhost') else inventory_hostname }}"
when:
- zabbix_server_dbhost_run_install
+ tags:
+ - database
-- name: "Set the correct delegated_dbhost (to support MySQL db deployment on a remote dbhost)"
- set_fact:
+- name: "MySQL | Set the correct delegated_dbhost (to support MySQL db deployment on a remote dbhost)"
+ ansible.builtin.set_fact:
delegated_dbhost: "{{ inventory_hostname }}"
when:
- not zabbix_server_dbhost_run_install
+ tags:
+ - database
-- name: "Override delegated_dbhost with real dbhost when dbhost is behind loadbalancer"
- set_fact:
+- name: "MySQL | Override delegated_dbhost with real dbhost when dbhost is behind loadbalancer"
+ ansible.builtin.set_fact:
delegated_dbhost: "{{ zabbix_server_real_dbhost }}"
when: zabbix_server_real_dbhost | default(false)
+ tags:
+ - database
- name: "MySQL | Create database"
community.mysql.mysql_db:
@@ -28,11 +35,10 @@
login_port: "{{ zabbix_server_mysql_login_port | default(omit) }}"
login_unix_socket: "{{ zabbix_server_mysql_login_unix_socket | default(omit) }}"
state: present
- when: zabbix_database_creation
+ when: zabbix_server_database_creation
register: zabbix_database_created
delegate_to: "{{ delegated_dbhost }}"
tags:
- - zabbix-server
- database
- skip_ansible_lint
@@ -45,57 +51,44 @@
login_unix_socket: "{{ zabbix_server_mysql_login_unix_socket | default(omit) }}"
name: "{{ zabbix_server_dbuser }}"
password: "{{ zabbix_server_dbpassword }}"
+ plugin: "{{ 'mysql_native_password' if (ansible_os_family == 'RedHat' and ansible_distribution_major_version == '7') else omit }}"
priv: "{{ zabbix_server_dbname }}.*:ALL"
host: "{{ zabbix_server_privileged_host }}"
state: present
- when: zabbix_database_creation
+ when: zabbix_server_database_creation
delegate_to: "{{ delegated_dbhost }}"
tags:
- - zabbix-server
- database
-- name: "Get the file for create.sql >= 3.0"
- shell: ls -1 {{ datafiles_path }}/{{ 'create' if zabbix_version is version('6.0', '<') else 'server' }}.sq*
+- name: "MySQL | Get the file for create.sql"
+ ansible.builtin.shell: ls -1 {{ datafiles_path }}/{{ 'create' if zabbix_server_version is version('6.0', '<') else 'server' }}.sq*
changed_when: false
+ become: true
when:
- - zabbix_version is version('3.0', '>=')
- - zabbix_database_sqlload | bool
- - zabbix_repo != "epel"
+ - zabbix_server_database_sqlload | bool
register: ls_output_create
tags:
- - zabbix-server
- database
- name: MySQL | Get current database version
- shell: |
+ ansible.builtin.shell: |
mysql -h {{ zabbix_server_dbhost }} -u{{ zabbix_server_dbuser }} \
-p'{{ zabbix_server_dbpassword }}' -D '{{ zabbix_server_dbname }}' \
-e 'SELECT mandatory FROM dbversion;'
register: mysql_db_version
+ become: true
changed_when: false
ignore_errors: true
+ tags:
+ - database
# If the above check failed, then there was no dbversion table in the database.
# We'll create it, below. Otherwise, we can access the database version in
# `mysql_db_version["stdout_lines"][1]`, for example 5000000 for Zabbix 5.0.
- name: MySQL | Check if database needs to be populated
- set_fact:
+ ansible.builtin.set_fact:
mysql_schema_empty: "{{ mysql_db_version is failed }}"
-- name: "MySQL | Get version_comment"
- community.mysql.mysql_variables:
- variable: version
- login_host: "{{ zabbix_server_mysql_login_host | default(omit) }}"
- login_user: "{{ zabbix_server_mysql_login_user | default(omit) }}"
- login_password: "{{ zabbix_server_mysql_login_password | default(omit) }}"
- login_port: "{{ zabbix_server_mysql_login_port | default(omit) }}"
- login_unix_socket: "{{ zabbix_server_mysql_login_unix_socket | default(omit) }}"
- delegate_to: "{{ delegated_dbhost }}"
- register: install_mysql_version
- tags:
- - zabbix-server
- - database
-
- name: "MySQL | Get current value for innodb_default_row_format"
community.mysql.mysql_variables:
variable: innodb_default_row_format
@@ -106,11 +99,7 @@
login_unix_socket: "{{ zabbix_server_mysql_login_unix_socket | default(omit) }}"
delegate_to: "{{ delegated_dbhost }}"
register: mysql_innodb_default_row_format
- when:
- - not ansible_check_mode
- - install_mysql_version.msg is version('5.6', '>=')
tags:
- - zabbix-server
- database
- name: "MySQL | Set innodb_default_row_format to dynamic"
@@ -123,15 +112,11 @@
login_port: "{{ zabbix_server_mysql_login_port | default(omit) }}"
login_unix_socket: "{{ zabbix_server_mysql_login_unix_socket | default(omit) }}"
when:
- - zabbix_version is version('3.0', '>=')
- - zabbix_database_sqlload | bool
- - zabbix_repo != "epel"
+ - zabbix_server_database_sqlload | bool
- mysql_schema_empty
- - install_mysql_version.msg is version('5.6', '>=')
- mysql_innodb_default_row_format.msg != 'dynamic'
delegate_to: "{{ delegated_dbhost }}"
tags:
- - zabbix-server
- database
- name: "MySQL | Disable InnoDB Strict Mode"
@@ -144,45 +129,45 @@
login_port: "{{ zabbix_server_mysql_login_port | default(omit) }}"
login_unix_socket: "{{ zabbix_server_mysql_login_unix_socket | default(omit) }}"
when:
- - zabbix_version is version('3.0', '>=')
- - zabbix_database_sqlload | bool
- - zabbix_repo != "epel"
+ - zabbix_server_database_sqlload | bool
- mysql_schema_empty
- - install_mysql_version.msg is version('5.6', '>=')
- ansible_distribution_release == "buster"
delegate_to: "{{ delegated_dbhost }}"
tags:
- - zabbix-server
- database
-- name: "Fetch sql create file"
+- name: "MySQL | Fetch sql create file"
fetch:
src: "{{ ls_output_create.stdout }}"
dest: /tmp/{{ role_name }}/
flat: true
+ become: true
when:
- delegated_dbhost != inventory_hostname
- - zabbix_database_sqlload | bool
- - zabbix_repo != "epel"
+ - zabbix_server_database_sqlload | bool
- mysql_schema_empty
+ tags:
+ - database
-- name: "Copy sql create file"
- copy:
+- name: "MySQL | Copy sql create file"
+ ansible.builtin.copy:
src: /tmp/{{ role_name }}/
dest: "{{ ls_output_create.stdout | dirname }}"
- mode: '0640'
+ mode: "0640"
delegate_to: "{{ delegated_dbhost }}"
+ become: true
when:
- delegated_dbhost != inventory_hostname
- - zabbix_database_sqlload | bool
- - zabbix_repo != "epel"
+ - zabbix_server_database_sqlload | bool
- mysql_schema_empty
+ tags:
+ - database
-- name: "MySQL | Create database and import file >= 3.0"
+- name: "MySQL | Create database and import file"
community.mysql.mysql_db:
login_host: "{{ zabbix_server_mysql_login_host | default(omit) }}"
- login_user: "{{ zabbix_server_mysql_login_user | default(omit) }}"
- login_password: "{{ zabbix_server_mysql_login_password | default(omit) }}"
+ login_user: "{{ zabbix_server_dbuser if (ansible_os_family == 'RedHat' and ansible_distribution_major_version == '7') else zabbix_server_mysql_login_user }}"
+ login_password: "{{ zabbix_server_dbpassword if (ansible_os_family == 'RedHat' and ansible_distribution_major_version == '7') else zabbix_server_mysql_login_password }}"
login_port: "{{ zabbix_server_mysql_login_port | default(omit) }}"
login_unix_socket: "{{ zabbix_server_mysql_login_unix_socket | default(omit) }}"
name: "{{ zabbix_server_dbname }}"
@@ -190,118 +175,39 @@
collation: "{{ zabbix_server_dbcollation }}"
state: import
target: "{{ ls_output_create.stdout }}"
+ use_shell: "{{ true if zabbix_server_version is version('5.0', '==') else false }}"
when:
- - zabbix_version is version('3.0', '>=')
- - zabbix_database_sqlload | bool
- - zabbix_repo != "epel"
+ - zabbix_server_database_sqlload | bool
- mysql_schema_empty
delegate_to: "{{ delegated_dbhost }}"
tags:
- - zabbix-server
- database
- name: "MySQL | Revert innodb_default_row_format to previous value"
community.mysql.mysql_variables:
variable: innodb_default_row_format
- value: '{{ mysql_innodb_default_row_format.msg }}'
+ value: "{{ mysql_innodb_default_row_format.msg }}"
login_host: "{{ zabbix_server_mysql_login_host | default(omit) }}"
login_user: "{{ zabbix_server_mysql_login_user | default(omit) }}"
login_password: "{{ zabbix_server_mysql_login_password | default(omit) }}"
login_port: "{{ zabbix_server_mysql_login_port | default(omit) }}"
login_unix_socket: "{{ zabbix_server_mysql_login_unix_socket | default(omit) }}"
when:
- - zabbix_version is version('3.0', '>=')
- - zabbix_database_sqlload | bool
- - zabbix_repo != "epel"
+ - zabbix_server_database_sqlload | bool
- mysql_schema_empty
- mysql_innodb_default_row_format.msg != 'dynamic'
delegate_to: "{{ delegated_dbhost }}"
tags:
- - zabbix-server
- database
-- name: "Check if we have sql_done files >= 3.0"
- file:
+- name: "MySQL | Check if we have sql_done files"
+ ansible.builtin.file:
path: /etc/zabbix/create.done
state: touch
- mode: '0644'
+ mode: "0644"
+ become: true
when:
- - zabbix_version is version('3.0', '>=')
- - zabbix_database_sqlload | bool
- - zabbix_repo != "epel"
+ - zabbix_server_database_sqlload | bool
- mysql_schema_empty
-
-- name: "Get the correct path for the SQL files < 3.0"
- shell: ls -1 {{ datafiles_path }}/{{ mysql_create_dir }}{{ item }}.sql*
- changed_when: false
- register: ls_output_schema
- with_items:
- - schema
- - images
- - data
- when:
- - zabbix_version is version('3.0', '<')
- - zabbix_database_sqlload | bool
- tags:
- - zabbix-server
- - database
-
-- name: "Check if we have done files < 3.0"
- stat:
- path: /etc/zabbix/{{ item }}.done
- register: done_files
- with_items:
- - schema
- - images
- - data
- when:
- - zabbix_version is version('3.0', '<')
- - zabbix_database_sqlload | bool
- tags:
- - zabbix-server
- - database
-
-- name: "Create fact if sql_done files exists"
- set_fact:
- sql_files_executed: "{{ sql_files_executed | default({}) | combine({item.item: item.stat}) }}"
- with_items: "{{ done_files.results }}"
- when:
- - zabbix_version is version('3.0', '<')
- - zabbix_database_sqlload | bool
- tags:
- - zabbix-server
- - database
-
-- name: "MySQL | Create database and import files < 3.0"
- community.mysql.mysql_db:
- name: "{{ zabbix_server_dbname }}"
- encoding: "{{ zabbix_server_dbencoding }}"
- collation: "{{ zabbix_server_dbcollation }}"
- state: import
- target: "{{ item.stdout }}"
- with_items: "{{ ls_output_schema.results }}"
- when:
- - zabbix_version is version('3.0', '<')
- - zabbix_database_sqlload | bool
- - not sql_files_executed[item.item].exists
- delegate_to: "{{ delegated_dbhost }}"
- tags:
- - zabbix-server
- - database
-
-- name: "Check if we have sql_done files < 3.0"
- file:
- path: /etc/zabbix/{{ item }}.done
- state: touch
- mode: '0644'
- with_items:
- - schema
- - images
- - data
- when:
- - zabbix_version is version('3.0', '<')
- - zabbix_database_sqlload | bool
- - not sql_files_executed[item].exists
tags:
- - zabbix-server
- database
diff --git a/ansible_collections/community/zabbix/roles/zabbix_server/tasks/postgresql.yml b/ansible_collections/community/zabbix/roles/zabbix_server/tasks/postgresql.yml
index 77e300c01..5177a55be 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_server/tasks/postgresql.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_server/tasks/postgresql.yml
@@ -1,17 +1,21 @@
---
# task file for postgresql
-- name: "Set the correct delegated_dbhost (to support postgres db deployment on a remote dbhost)"
- set_fact:
+- name: "PostgreSQL | Set the correct delegated_dbhost (to support postgres db deployment on a remote dbhost)"
+ ansible.builtin.set_fact:
delegated_dbhost: "{{ zabbix_server_dbhost if (zabbix_server_dbhost != 'localhost') else inventory_hostname }}"
when:
- zabbix_server_dbhost_run_install
+ tags:
+ - database
-- name: "Set the correct delegated_dbhost (to support postgres db deployment on a remote dbhost)"
- set_fact:
+- name: "PostgreSQL | Set the correct delegated_dbhost (to support postgres db deployment on a remote dbhost)"
+ ansible.builtin.set_fact:
delegated_dbhost: "{{ inventory_hostname }}"
when:
- not zabbix_server_dbhost_run_install
+ tags:
+ - database
- name: "PostgreSQL | Delegated"
block:
@@ -20,6 +24,7 @@
name: "{{ zabbix_server_dbname }}"
port: "{{ zabbix_server_dbport }}"
state: present
+
- name: "PostgreSQL | Delegated | Create database user"
community.postgresql.postgresql_user:
db: "{{ zabbix_server_dbname }}"
@@ -29,19 +34,19 @@
priv: ALL
state: present
encrypted: true
+
- name: "PostgreSQL | Delegated | Create timescaledb extension"
community.postgresql.postgresql_ext:
db: "{{ zabbix_server_dbname }}"
name: timescaledb
- when: zabbix_database_timescaledb
+ when: zabbix_server_database_timescaledb
become: true
become_user: postgres
delegate_to: "{{ delegated_dbhost }}"
when:
- - zabbix_database_creation
+ - zabbix_server_database_creation
- zabbix_server_pgsql_login_host is not defined
tags:
- - zabbix-server
- database
- name: "PostgreSQL | Remote"
@@ -55,6 +60,7 @@
name: "{{ zabbix_server_dbname }}"
port: "{{ zabbix_server_dbport }}"
state: present
+
- name: "PostgreSQL | Remote | Create database user"
community.postgresql.postgresql_user:
login_host: "{{ zabbix_server_pgsql_login_host | default(omit) }}"
@@ -67,6 +73,7 @@
priv: ALL
state: present
encrypted: true
+
- name: "PostgreSQL | Remote | Create timescaledb extension"
community.postgresql.postgresql_ext:
login_host: "{{ zabbix_server_pgsql_login_host | default(omit) }}"
@@ -75,23 +82,17 @@
login_unix_socket: "{{ zabbix_server_pgsql_login_unix_socket | default(omit) }}"
db: "{{ zabbix_server_dbname }}"
name: timescaledb
- when: zabbix_database_timescaledb
+ when: zabbix_server_database_timescaledb
when:
- - zabbix_database_creation
+ - zabbix_server_database_creation
- zabbix_server_pgsql_login_host is defined
tags:
- - zabbix-server
- database
-- name: Check if warn parameter can be used for shell module
- set_fact:
- produce_warn: False
- when: ansible_version.full is version("2.14", "<")
-
- name: "PostgreSQL | Create schema"
- shell: |
+ ansible.builtin.shell: |
set -euxo pipefail
- FILE={{ 'create.sql' if zabbix_version is version('6.0', '<') else 'server.sql' }}
+ FILE={{ 'create.sql' if zabbix_server_version is version('6.0', '<') else 'server.sql' }}
cd {{ datafiles_path }}
if [ -f ${FILE}.gz ]
then zcat ${FILE}.gz > /tmp/create.sql
@@ -110,15 +111,14 @@
warn: "{{ produce_warn | default(omit) }}"
environment:
PGPASSWORD: "{{ zabbix_server_dbpassword }}"
+ become: true
when:
- - zabbix_version is version('3.0', '>=')
- - zabbix_database_sqlload
+ - zabbix_server_database_sqlload
tags:
- - zabbix-server
- database
- name: "PostgreSQL | Create TimescaleDB hypertables"
- shell: |
+ ansible.builtin.shell: |
set -euxo pipefail
cd {{ datafiles_path }} &&
if [ -f timescaledb.sql.gz ]; then zcat timescaledb.sql.gz > /etc/timescaledb.sql ; else cp -p timescaledb.sql /etc/timescaledb.sql ; fi
@@ -134,92 +134,8 @@
warn: "{{ produce_warn | default(omit) }}"
environment:
PGPASSWORD: "{{ zabbix_server_dbpassword }}"
+ become: true
when:
- - zabbix_version is version('3.0', '>=')
- - zabbix_database_timescaledb
- tags:
- - zabbix-server
- - database
-
-- name: "Get complete path"
- shell: ls -d {{ datafiles_path }}
- register: datafiles_path_full
- changed_when: false
- when:
- - (zabbix_version is version('3.0', '<') and zabbix_database_sqlload) or (zabbix_repo == "epel" and zabbix_database_sqlload)
- tags:
- - skip_ansible_lint
-
-- name: "Check if we have a create dir"
- stat:
- path: "{{ datafiles_path_full.stdout }}/create"
- register: create_dir_or_not
- when:
- - (zabbix_version is version('3.0', '<') and zabbix_database_sqlload) or (zabbix_repo == "epel" and zabbix_database_sqlload)
-
-- name: "Set fact"
- set_fact:
- datafiles_path: "{{ datafiles_path }}/create"
- when:
- - (zabbix_version is version('3.0', '<') and zabbix_database_sqlload) or (zabbix_repo == "epel" and zabbix_database_sqlload)
- - create_dir_or_not.stat.isdir is defined and create_dir_or_not.stat.isdir
- - create_dir_or_not.stat.exists
-
-- name: "PostgreSQL | Importing schema file"
- shell: |
- set -euxo pipefail
- cd {{ datafiles_path }}
- if [ -f schema.sql.gz ]; then zcat schema.sql.gz > /tmp/schema.sql ; else cp -p schema.sql /tmp/schema.sql ;fi
- cat /tmp/schema.sql | psql -h '{{ zabbix_server_dbhost }}' \
- -U '{{ zabbix_server_dbuser }}' \
- -d '{{ zabbix_server_dbname }}' \
- -p '{{ zabbix_server_dbport }}'
- touch /etc/zabbix/schema.done
- rm -f /etc/schema.sql
- args:
- creates: /etc/zabbix/schema.done
- executable: /bin/bash
- warn: "{{ produce_warn | default(omit) }}"
- environment:
- PGPASSWORD: "{{ zabbix_server_dbpassword }}"
- when:
- - (zabbix_version is version('3.0', '<') and zabbix_database_sqlload) or (zabbix_repo == "epel" and zabbix_database_sqlload)
- tags:
- - zabbix-server
- - database
-
-- name: "PostgreSQL | Importing images file"
- shell: >
- cd {{ datafiles_path }} &&
- psql -h '{{ zabbix_server_dbhost }}'
- -U '{{ zabbix_server_dbuser }}'
- -d '{{ zabbix_server_dbname }}'
- -p '{{ zabbix_server_dbport }}'
- -f images.sql && touch /etc/zabbix/images.done
- args:
- creates: /etc/zabbix/images.done
- warn: "{{ produce_warn | default(omit) }}"
- environment:
- PGPASSWORD: "{{ zabbix_server_dbpassword }}"
- when: (zabbix_version is version('3.0', '<') and zabbix_database_sqlload) or (zabbix_repo == "epel" and zabbix_database_sqlload)
- tags:
- - zabbix-server
- - database
-
-- name: "PostgreSQL | Importing data file"
- shell: >
- cd {{ datafiles_path }} &&
- psql -h '{{ zabbix_server_dbhost }}'
- -U '{{ zabbix_server_dbuser }}'
- -d '{{ zabbix_server_dbname }}'
- -p '{{ zabbix_server_dbport }}'
- -f data.sql && touch /etc/zabbix/data.done
- args:
- creates: /etc/zabbix/data.done
- warn: "{{ produce_warn | default(omit) }}"
- environment:
- PGPASSWORD: "{{ zabbix_server_dbpassword }}"
- when: (zabbix_version is version('3.0', '<') and zabbix_database_sqlload) or (zabbix_repo == "epel" and zabbix_database_sqlload)
+ - zabbix_server_database_timescaledb
tags:
- - zabbix-server
- database
diff --git a/ansible_collections/community/zabbix/roles/zabbix_server/tasks/scripts.yml b/ansible_collections/community/zabbix/roles/zabbix_server/tasks/scripts.yml
index 418436128..b253f325a 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_server/tasks/scripts.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_server/tasks/scripts.yml
@@ -1,20 +1,26 @@
---
- name: "Configure zabbix-server alertscripts"
- template:
+ ansible.builtin.template:
src: "{{ item.path }}"
dest: "{{ zabbix_server_alertscriptspath }}/{{ item.name }}"
- owner: zabbix
- group: zabbix
+ owner: "{{ zabbix_os_user }}"
+ group: "{{ zabbix_os_user }}"
mode: 0755
with_items: "{{ zabbix_server_alertscripts }}"
+ become: true
when: zabbix_server_alertscripts is defined
+ tags:
+ - config
- name: "Configure zabbix-server externalscripts"
- template:
+ ansible.builtin.template:
src: "{{ item.path }}"
dest: "{{ zabbix_server_externalscriptspath }}/{{ item.name }}"
- owner: zabbix
- group: zabbix
+ owner: "{{ zabbix_os_user }}"
+ group: "{{ zabbix_os_user }}"
mode: 0755
with_items: "{{ zabbix_server_externalscripts }}"
+ become: true
when: zabbix_server_externalscripts is defined
+ tags:
+ - config
diff --git a/ansible_collections/community/zabbix/roles/zabbix_server/tasks/selinux.yml b/ansible_collections/community/zabbix/roles/zabbix_server/tasks/selinux.yml
index 38a8d85fe..fe203aed1 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_server/tasks/selinux.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_server/tasks/selinux.yml
@@ -1,27 +1,32 @@
---
-
# straight to getenforce binary , workaround for missing python_selinux library
-- name: "Get getenforce binary"
- stat:
+- name: "SELinux | Get getenforce binary"
+ ansible.builtin.stat:
path: /usr/sbin/getenforce
register: getenforce_bin
become: true
+ tags:
+ - always
-- name: "Collect getenforce output"
- command: getenforce
+- name: "SELinux | Collect getenforce output"
+ ansible.builtin.command: getenforce
register: sestatus
- when: 'getenforce_bin.stat.exists'
+ when: "getenforce_bin.stat.exists"
changed_when: false
become: true
check_mode: false
+ tags:
+ - always
-- name: "Set zabbix_selinux to true if getenforce returns Enforcing or Permissive"
- set_fact:
- zabbix_selinux: "{{ true }}"
+- name: "Set zabbix_server_selinux to true if getenforce returns Enforcing or Permissive"
+ ansible.builtin.set_fact:
+ zabbix_server_selinux: "{{ true }}"
when: 'getenforce_bin.stat.exists and ("Enforcing" in sestatus.stdout or "Permissive" in sestatus.stdout)'
+ tags:
+ - config
- name: "SELinux | RedHat | Install related SELinux package"
- yum:
+ ansible.builtin.yum:
name:
- libsemanage-python
- policycoreutils
@@ -38,10 +43,10 @@
- selinux_allow_zabbix_can_network
- ansible_distribution_major_version == "7" or ansible_distribution_major_version == "6"
tags:
- - zabbix-server
+ - install
-- name: "SELinux | RedHat | Install related SELinux package on RHEL9 and RHEL8"
- yum:
+- name: "SELinux | RedHat | Install related SELinux package on RHEL8"
+ ansible.builtin.yum:
name:
- python3-libsemanage
state: present
@@ -54,9 +59,9 @@
when:
- ansible_os_family == "RedHat"
- selinux_allow_zabbix_can_network
- - ansible_distribution_major_version|int >= 8
+ - ansible_distribution_major_version == "8"
tags:
- - zabbix-server
+ - install
- name: "SELinux | RedHat | Enable httpd_can_connect_zabbix SELinux boolean"
ansible.posix.seboolean:
@@ -67,7 +72,7 @@
when:
- selinux_allow_zabbix_can_http
tags:
- - zabbix-server
+ - config
- name: "SELinux | RedHat | Enable zabbix_can_network SELinux boolean"
ansible.posix.seboolean:
@@ -78,10 +83,10 @@
when:
- selinux_allow_zabbix_can_network
tags:
- - zabbix-server
+ - config
- name: "SELinux | RedHat | Install related SELinux package to fix issues"
- yum:
+ ansible.builtin.yum:
name:
- policycoreutils-python
state: present
@@ -95,10 +100,10 @@
- ansible_os_family == "RedHat"
- ansible_distribution_major_version == "7" or ansible_distribution_major_version == "6"
tags:
- - zabbix-server
+ - install
-- name: "SELinux | RedHat | Install related SELinux package on RHEL9 and RHEL8"
- yum:
+- name: "SELinux | RedHat | Install related SELinux package to fix issues on RHEL8"
+ ansible.builtin.yum:
name:
- policycoreutils
- checkpolicy
@@ -112,13 +117,15 @@
become: true
when:
- ansible_os_family == "RedHat"
- - ansible_distribution_major_version|int >= 8
+ - ansible_distribution_major_version == "8"
tags:
- - zabbix-server
+ - install
- name: "SELinux | RedHat | Add SEmodule to fix SELinux issue: zabbix_server_alerter.sock"
- script:
+ ansible.builtin.script:
cmd: files/install_semodule.bsx
args:
creates: /etc/selinux/targeted/active/modules/400/zabbix_server_add/cil
become: true
+ tags:
+ - config
diff --git a/ansible_collections/community/zabbix/roles/zabbix_server/templates/zabbix_server.conf.j2 b/ansible_collections/community/zabbix/roles/zabbix_server/templates/zabbix_server.conf.j2
index 19c99aa33..489e9c9f5 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_server/templates/zabbix_server.conf.j2
+++ b/ansible_collections/community/zabbix/roles/zabbix_server/templates/zabbix_server.conf.j2
@@ -4,261 +4,120 @@
# This configuration file is "minimalized", which means all the original comments
# are removed. The full documentation for your Zabbix Server can be found here:
-# https://www.zabbix.com/documentation/{{ zabbix_version }}/en/manual/appendix/config/zabbix_server
+# https://www.zabbix.com/documentation/{{ zabbix_server_version }}/en/manual/appendix/config/zabbix_server
-ListenPort={{ zabbix_server_listenport }}
-{% if zabbix_server_sourceip is defined and zabbix_server_sourceip %}
-SourceIP={{ zabbix_server_sourceip }}
-{% endif %}
-{% if zabbix_version is version('3.0', '>=') %}
-LogType={{ zabbix_server_logtype }}
-{% endif %}
-LogFile={{ zabbix_server_logfile }}
-LogFileSize={{ zabbix_server_logfilesize }}
-DebugLevel={{ zabbix_server_debuglevel }}
-{% if zabbix_version is version('3.4', '>=') %}
-SocketDir={{ zabbix_server_socketdir }}
-{% endif %}
-PidFile={{ zabbix_server_pidfile }}
-DBHost={{ zabbix_server_dbhost }}
-DBName={{ zabbix_server_dbname }}
-{% if zabbix_server_dbschema is defined and zabbix_server_dbschema %}
-DBSchema={{ zabbix_server_dbschema }}
-{% endif %}
-DBUser={{ zabbix_server_dbuser }}
-DBPassword={{ zabbix_server_dbpassword }}
-{% if zabbix_server_dbsocket is defined and zabbix_server_dbsocket %}
-DBSocket={{ zabbix_server_dbsocket }}
-{% endif %}
-{% if zabbix_server_dbport is defined and zabbix_server_dbport %}
-DBPort={{ zabbix_server_dbport }}
-{% endif %}
-{% if zabbix_version is version('6.0', '>=') %}
-AllowUnsupportedDBVersions={{ zabbix_server_allowunsupporteddbversions }}
-{% endif %}
-{% if zabbix_server_historystorageurl is defined and zabbix_server_historystorageurl %}
-HistoryStorageURL={{ zabbix_server_historystorageurl }}
-{% endif %}
-{% if zabbix_version is version('3.4', '>=') %}
-HistoryStorageTypes={{ zabbix_server_historystoragetypes }}
-{% endif %}
-{% if zabbix_version is version('4.0', '>=') %}
-HistoryStorageDateIndex={{ zabbix_server_historystoragedateindex }}
-{% endif %}
-{% if zabbix_version is version('4.0', '>=') %}
-{% if zabbix_server_exportdir is defined and zabbix_server_exportdir %}
-ExportDir={{ zabbix_server_exportdir }}
-{% endif %}
-{% endif %}
-{% if zabbix_version is version('4.0', '>=') %}
-ExportFileSize={{ zabbix_server_exportfilesize }}
-{% endif %}
-StartPollers={{ zabbix_server_startpollers }}
-StartIPMIPollers={{ zabbix_server_startipmipollers }}
-{% if zabbix_version is version('4.2', '>=') %}
-StartLLDProcessors={{ zabbix_server_startlldprocessors }}
-{% endif %}
-{% if zabbix_version is version('4.2', '>=') %}
-StartPreprocessors={{ zabbix_server_startpreprocessors }}
-{% endif %}
-StartPollersUnreachable={{ zabbix_server_startpollersunreachable }}
-{% if zabbix_version is version('6.4', '>=') %}
-StartConnectors={{ zabbix_server_connectors }}
-{% endif %}
-{% if zabbix_version is version('6.2', '>=') %}
-StartHistoryPollers={{ zabbix_server_starthistorypollers }}
-{% endif %}
-StartTrappers={{ zabbix_server_starttrappers }}
-StartPingers={{ zabbix_server_startpingers }}
-StartDiscoverers={{ zabbix_server_startdiscoverers }}
-StartHTTPPollers={{ zabbix_server_starthttppollers }}
-{% if zabbix_version is version('2.0', '>=') %}
-StartTimers={{ zabbix_server_starttimers }}
-{% endif %}
-{% if zabbix_version is version('3.0', '>=') %}
-StartEscalators={{ zabbix_server_startescalators }}
-{% endif %}
-{% if zabbix_server_javagateway is defined and zabbix_server_javagateway %}
-JavaGateway={{ zabbix_server_javagateway }}
-JavaGatewayPort={{ zabbix_server_javagatewayport }}
-StartJavaPollers={{ zabbix_server_startjavapollers }}
-{% endif %}
-{% if zabbix_version is version('2.2', '>=') %}
-StartVMwareCollectors={{ zabbix_server_startvmwarecollectors }}
-VMwareFrequency={{ zabbix_server_vmwarefrequency }}
-{% if zabbix_version is version('3.0', '>=') %}
-VMwarePerfFrequency={{ zabbix_server_vmwareperffrequency }}
-{% endif %}
-VMwareCacheSize={{ zabbix_server_vmwarecachesize }}
-{% endif %}
-{% if zabbix_version is version('3.0', '>=') %}
-VMwareTimeout={{ zabbix_server_vmwaretimeout }}
-{% endif %}
-SNMPTrapperFile={{ zabbix_server_snmptrapperfile }}
-StartSNMPTrapper={{ zabbix_server_startsnmptrapper }}
-{% if zabbix_server_listenip is defined and zabbix_server_listenip %}
-ListenIP={{ zabbix_server_listenip }}
-{% endif %}
-HousekeepingFrequency={{ zabbix_server_housekeepingfrequency }}
-MaxHousekeeperDelete={{ zabbix_server_maxhousekeeperdelete }}
-{% if zabbix_version is version('3.2', '<=') %}
-SenderFrequency={{ zabbix_server_senderfrequency }}
-{% endif %}
-{% if zabbix_server_cachesize is defined and zabbix_server_cachesize is not none %}
-CacheSize={{ zabbix_server_cachesize }}
-{% else %}
-{% if zabbix_version is version('6.2', '<') %}
-CacheSize=8M
-{% else %}
-CacheSize=32M
-{% endif %}
-{% endif %}
-{% if zabbix_server_cacheupdatefrequency is defined and zabbix_server_cacheupdatefrequency is not none %}
-CacheUpdateFrequency={{ zabbix_server_cacheupdatefrequency }}
-{% else %}
-{% if zabbix_version is version('6.4', '<') %}
-CacheUpdateFrequency=60
-{% else %}
-CacheUpdateFrequency=10
-{%endif %}
-{%endif %}
-StartDBSyncers={{ zabbix_server_startdbsyncers }}
-HistoryCacheSize={{ zabbix_server_historycachesize }}
-{% if zabbix_version is version('3.0', '>=') %}
-HistoryIndexCacheSize={{ zabbix_server_historyindexcachesize }}
-{% endif %}
-TrendCacheSize={{ zabbix_server_trendcachesize }}
-{% if zabbix_version is version('6.0', '>=') %}
-TrendFunctionCacheSize={{ zabbix_server_trendfunctioncachesize }}
-{% endif %}
-{% if zabbix_version is version('3.0', '<') %}
- ### option: historytextcachesize
-HistoryTextCacheSize={{ zabbix_server_historytextcachesize }}
-{% endif %}
-{% if zabbix_version is version('2.2', '>=') %}
-ValueCacheSize={{ zabbix_server_valuecachesize }}
-{% endif %}
-{% if zabbix_version is version('2.4', '<') %}
-NodeNoEvents={{ zabbix_server_nodenoevents }}
-NodeNoHistory={{ zabbix_server_nodenohistory }}
-{% endif %}
-Timeout={{ zabbix_server_timeout }}
-TrapperTimeout={{ zabbix_server_trappertimeout }}
-UnreachablePeriod={{ zabbix_server_unreachableperiod }}
-UnavailableDelay={{ zabbix_server_unavailabledelay }}
-UnreachableDelay={{ zabbix_server_unreachabledelay }}
-AlertScriptsPath={{ zabbix_server_alertscriptspath }}
-ExternalScripts={{ zabbix_server_externalscriptspath }}
-FpingLocation={{ zabbix_server_fpinglocation }}
-Fping6Location={{ zabbix_server_fping6location }}
-{% if zabbix_server_sshkeylocation is defined and zabbix_server_sshkeylocation %}
-SSHKeyLocation={{ zabbix_server_sshkeylocation }}
-{% endif %}
-LogSlowQueries={{ zabbix_server_logslowqueries }}
-TmpDir={{ zabbix_server_tmpdir }}
-StartProxyPollers={{ zabbix_server_startproxypollers }}
-{% if zabbix_server_proxyconfigfrequency is defined and zabbix_server_proxyconfigfrequency is not none %}
-ProxyConfigFrequency={{ zabbix_server_proxyconfigfrequency }}
-{% else %}
-{% if zabbix_version is version('6.2', '<') %}
-ProxyConfigFrequency=3600
-{% elif zabbix_version is version('6.4', '<') %}
-ProxyConfigFrequency=300
-{% else %}
-ProxyConfigFrequency=10
-{% endif %}
-{% endif %}
-ProxyDataFrequency={{ zabbix_server_proxydatafrequency }}
-{% if zabbix_version is version('2.2', '>=') %}
-AllowRoot={{ zabbix_server_allowroot }}
-{% endif %}
-{% if zabbix_version is version('3.0', '>=') %}
-User={{ zabbix_server_user }}
-{% endif %}
-Include={{ zabbix_server_include }}
-{% if zabbix_version is version('3.0', '>=') %}
-SSLCertLocation={{ zabbix_server_sslcertlocation }}
-SSLKeyLocation={{ zabbix_server_sslkeylocation }}
-{% if zabbix_server_sslcalocation is defined and zabbix_server_sslcalocation is not none %}
-SSLCALocation={{ zabbix_server_sslcalocation }}
-{% endif %}
-{% endif %}
-{% if zabbix_version is version('2.2', '>=') %}
-LoadModulePath={{ zabbix_server_loadmodulepath }}
-{% endif %}
-{% if zabbix_server_loadmodule is defined and zabbix_server_loadmodule %}
-LoadModule = {{ zabbix_server_loadmodule }}
-{% endif %}
-{% if zabbix_version is version('3.0', '>=') %}
-{% if zabbix_server_tlscafile is defined and zabbix_server_tlscafile is not none %}
-TLSCAFile={{ zabbix_server_tlscafile }}
-{% endif %}
-{% if zabbix_server_tlscrlfile is defined and zabbix_server_tlscrlfile is not none %}
-TLSCRLFile={{ zabbix_server_tlscrlfile }}
-{% endif %}
-{% if zabbix_server_tlscertfile is defined and zabbix_server_tlscertfile is not none %}
-TLSCertFile={{ zabbix_server_tlscertfile }}
-{% endif %}
-{% if zabbix_server_tlskeyfile is defined and zabbix_server_tlskeyfile is not none %}
-TLSKeyFile={{ zabbix_server_tlskeyfile }}
-{% endif %}
-{% endif %}
-{% if zabbix_server_dbtlsconnect is defined and zabbix_server_dbtlsconnect is not none %}
-DBTLSConnect={{ zabbix_server_dbtlsconnect }}
-{% endif %}
-{% if zabbix_server_dbtlscafile is defined and zabbix_server_dbtlscafile is not none %}
-DBTLSCAFile={{ zabbix_server_dbtlscafile }}
-{% endif %}
-{% if zabbix_server_dbtlscertfile is defined and zabbix_server_dbtlscertfile is not none %}
-DBTLSCertFile={{ zabbix_server_dbtlscertfile }}
-{% endif %}
-{% if zabbix_server_dbtlskeyfile is defined and zabbix_server_dbtlskeyfile is not none %}
-DBTLSKeyFile={{ zabbix_server_dbtlskeyfile }}
-{% endif %}
-{% if zabbix_server_dbtlscipher is defined and zabbix_server_dbtlscipher is not none %}
-DBTLSCipher={{ zabbix_server_dbtlscipher }}
-{% endif %}
-{% if zabbix_server_dbtlscipher13 is defined and zabbix_server_dbtlscipher13 is not none %}
-DBTLSCipher13={{ zabbix_server_dbtlscipher13 }}
-{% endif %}
-{% if zabbix_version is version('6.0', '>=') %}
-{% if zabbix_server_vaulttoken is defined and zabbix_server_vaulttoken is not none %}
-VaultToken={{ zabbix_server_vaulttoken }}
-{% endif %}
-{% if zabbix_server_vaulturl is defined and zabbix_server_vaulturl is not none %}
-VaultURL={{ zabbix_server_vaulturl }}
-{% endif %}
-{% if zabbix_server_vaultdbpath is defined and zabbix_server_vaultdbpath is not none %}
-VaultDBPath={{ zabbix_server_vaultdbpath }}
-{% endif %}
-{% if zabbix_server_vaulttlscertfile is defined and zabbix_server_vaulttlscertfile is not none %}
-VaultTLSKeyFile={{ zabbix_server_vaulttlscertfile }}
-{% endif %}
-{% if zabbix_server_vaulttlskeyfile is defined and zabbix_server_vaulttlskeyfile is not none %}
-VaultTLSCertFile={{ zabbix_server_vaulttlskeyfile }}
-{% endif %}
-{% if zabbix_server_startreportwriters is defined and zabbix_server_startreportwriters is not none %}
-StartReportWriters={{ zabbix_server_startreportwriters }}
-{% endif %}
-{% if zabbix_server_webserviceurl is defined and zabbix_server_webserviceurl is not none %}
-WebServiceURL={{ zabbix_server_webserviceurl }}
-{% endif %}
-{% if zabbix_server_servicemanagersyncfrequency is defined and zabbix_server_servicemanagersyncfrequency is not none %}
-ServiceManagerSyncFrequency={{ zabbix_server_servicemanagersyncfrequency }}
-{% endif %}
-{% if zabbix_server_problemhousekeepingfrequency is defined and zabbix_server_problemhousekeepingfrequency is not none %}
-ProblemHousekeepingFrequency={{ zabbix_server_problemhousekeepingfrequency }}
-{% endif %}
-{% if zabbix_version is version('6.2', '>=') %}
-StartODBCPollers={{ zabbix_server_startodbcpollers }}
-{% endif %}
-{% if zabbix_server_listenbacklog is defined and zabbix_server_listenbacklog is not none %}
-ListenBacklog={{ zabbix_server_listenbacklog }}
-{% endif %}
-{% if zabbix_server_hanodename is defined and zabbix_server_hanodename is not none %}
-HANodeName={{ zabbix_server_hanodename }}
-{% endif %}
-{% if zabbix_server_nodeaddress is defined and zabbix_server_nodeaddress is not none %}
-NodeAddress={{ zabbix_server_nodeaddress }}
-{% endif %}
-{% endif %}
+{{ (zabbix_server_alertscriptspath is defined and zabbix_server_alertscriptspath is not none) | ternary('', '# ') }}AlertScriptsPath={{ zabbix_server_alertscriptspath | default('') }}
+{{ (zabbix_server_allowroot is defined and zabbix_server_allowroot is not none) | ternary('', '# ') }}AllowRoot={{ zabbix_server_allowroot | default('') }}
+{{ (zabbix_server_allowunsupporteddbversions is defined and zabbix_server_allowunsupporteddbversions is not none) | ternary('', '# ') }}AllowUnsupportedDBVersions={{ zabbix_server_allowunsupporteddbversions | default('') }}
+{{ (zabbix_server_cachesize is defined and zabbix_server_cachesize is not none) | ternary('', '# ') }}CacheSize={{ zabbix_server_cachesize | default('') }}
+{{ (zabbix_server_cacheupdatefrequency is defined and zabbix_server_cacheupdatefrequency is not none) | ternary('', '# ') }}CacheUpdateFrequency={{ zabbix_server_cacheupdatefrequency | default('') }}
+{{ (zabbix_server_dbhost is defined and zabbix_server_dbhost is not none) | ternary('', '# ') }}DBHost={{ zabbix_server_dbhost | default('') }}
+{{ (zabbix_server_dbname is defined and zabbix_server_dbname is not none) | ternary('', '# ') }}DBName={{ zabbix_server_dbname | default('') }}
+{{ (zabbix_server_dbpassword is defined and zabbix_server_dbpassword is not none) | ternary('', '# ') }}DBPassword={{ zabbix_server_dbpassword | default('') }}
+{{ (zabbix_server_dbport is defined and zabbix_server_dbport is not none) | ternary('', '# ') }}DBPort={{ zabbix_server_dbport | default('') }}
+{{ (zabbix_server_dbschema is defined and zabbix_server_dbschema is not none) | ternary('', '# ') }}DBSchema={{ zabbix_server_dbschema | default('') }}
+{{ (zabbix_server_dbsocket is defined and zabbix_server_dbsocket is not none) | ternary('', '# ') }}DBSocket={{ zabbix_server_dbsocket | default('') }}
+{{ (zabbix_server_dbtlscafile is defined and zabbix_server_dbtlscafile is not none) | ternary('', '# ') }}DBTLSCAFile={{ zabbix_server_dbtlscafile | default('') }}
+{{ (zabbix_server_dbtlscertfile is defined and zabbix_server_dbtlscertfile is not none) | ternary('', '# ') }}DBTLSCertFile={{ zabbix_server_dbtlscertfile | default('') }}
+{{ (zabbix_server_dbtlscipher is defined and zabbix_server_dbtlscipher is not none) | ternary('', '# ') }}DBTLSCipher={{ zabbix_server_dbtlscipher | default('') }}
+{{ (zabbix_server_dbtlscipher13 is defined and zabbix_server_dbtlscipher13 is not none) | ternary('', '# ') }}DBTLSCipher13={{ zabbix_server_dbtlscipher13 | default('') }}
+{{ (zabbix_server_dbtlsconnect is defined and zabbix_server_dbtlsconnect is not none) | ternary('', '# ') }}DBTLSConnect={{ zabbix_server_dbtlsconnect | default('') }}
+{{ (zabbix_server_dbtlskeyfile is defined and zabbix_server_dbtlskeyfile is not none) | ternary('', '# ') }}DBTLSKeyFile={{ zabbix_server_dbtlskeyfile | default('') }}
+{{ (zabbix_server_dbuser is defined and zabbix_server_dbuser is not none) | ternary('', '# ') }}DBUser={{ zabbix_server_dbuser | default('') }}
+{{ (zabbix_server_debuglevel is defined and zabbix_server_debuglevel is not none) | ternary('', '# ') }}DebugLevel={{ zabbix_server_debuglevel | default('') }}
+{{ (zabbix_server_exportdir is defined and zabbix_server_exportdir is not none) | ternary('', '# ') }}ExportDir={{ zabbix_server_exportdir | default('') }}
+{{ (zabbix_server_exportfilesize is defined and zabbix_server_exportfilesize is not none) | ternary('', '# ') }}ExportFileSize={{ zabbix_server_exportfilesize | default('') }}
+{{ (zabbix_server_exporttype is defined and zabbix_server_exporttype is not none) | ternary('', '# ') }}ExportType={{ zabbix_server_exporttype | default('') }}
+{{ (zabbix_server_externalscriptspath is defined and zabbix_server_externalscriptspath is not none) | ternary('', '# ') }}ExternalScripts={{ zabbix_server_externalscriptspath | default('') }}
+{{ (zabbix_server_fping6location is defined and zabbix_server_fping6location is not none) | ternary('', '# ') }}Fping6Location={{ zabbix_server_fping6location | default('') }}
+{{ (zabbix_server_fpinglocation is defined and zabbix_server_fpinglocation is not none) | ternary('', '# ') }}FpingLocation={{ zabbix_server_fpinglocation | default('') }}
+{{ (zabbix_server_hanodename is defined and zabbix_server_hanodename is not none) | ternary('', '# ') }}HANodeName={{ zabbix_server_hanodename | default('') }}
+{{ (zabbix_server_historycachesize is defined and zabbix_server_historycachesize is not none) | ternary('', '# ') }}HistoryCacheSize={{ zabbix_server_historycachesize | default('') }}
+{{ (zabbix_server_historyindexcachesize is defined and zabbix_server_historyindexcachesize is not none) | ternary('', '# ') }}HistoryIndexCacheSize={{ zabbix_server_historyindexcachesize | default('') }}
+{{ (zabbix_server_historystoragedateindex is defined and zabbix_server_historystoragedateindex is not none) | ternary('', '# ') }}HistoryStorageDateIndex={{ zabbix_server_historystoragedateindex | default('') }}
+{{ (zabbix_server_historystoragetypes is defined and zabbix_server_historystoragetypes is not none) | ternary('', '# ') }}HistoryStorageTypes={{ zabbix_server_historystoragetypes | default('') }}
+{{ (zabbix_server_historystorageurl is defined and zabbix_server_historystorageurl is not none) | ternary('', '# ') }}HistoryStorageURL={{ zabbix_server_historystorageurl | default('') }}
+{{ (zabbix_server_housekeepingfrequency is defined and zabbix_server_housekeepingfrequency is not none) | ternary('', '# ') }}HousekeepingFrequency={{ zabbix_server_housekeepingfrequency | default('') }}
+{{ (zabbix_server_include is defined and zabbix_server_include is not none) | ternary('', '# ') }}Include={{ zabbix_server_include | default('') }}
+{{ (zabbix_server_javagateway is defined and zabbix_server_javagateway is not none) | ternary('', '# ') }}JavaGateway={{ zabbix_server_javagateway | default('') }}
+{{ (zabbix_server_javagatewayport is defined and zabbix_server_javagatewayport is not none) | ternary('', '# ') }}JavaGatewayPort={{ zabbix_server_javagatewayport | default('') }}
+{{ (zabbix_server_listenbacklog is defined and zabbix_server_listenbacklog is not none) | ternary('', '# ') }}ListenBacklog={{ zabbix_server_listenbacklog | default('') }}
+{{ (zabbix_server_listenip is defined and zabbix_server_listenip is not none) | ternary('', '# ') }}ListenIP={{ zabbix_server_listenip | default('') }}
+{{ (zabbix_server_listenport is defined and zabbix_server_listenport is not none) | ternary('', '# ') }}ListenPort={{ zabbix_server_listenport | default('') }}
+{{ (zabbix_server_loadmodule is defined and zabbix_server_loadmodule is not none) | ternary('', '# ') }}LoadModule={{ zabbix_server_loadmodule | default('') }}
+{{ (zabbix_server_loadmodulepath is defined and zabbix_server_loadmodulepath is not none) | ternary('', '# ') }}LoadModulePath={{ zabbix_server_loadmodulepath | default('') }}
+{{ (zabbix_server_logfile is defined and zabbix_server_logfile is not none) | ternary('', '# ') }}LogFile={{ zabbix_server_logfile | default('') }}
+{{ (zabbix_server_logfilesize is defined and zabbix_server_logfilesize is not none) | ternary('', '# ') }}LogFileSize={{ zabbix_server_logfilesize | default('') }}
+{{ (zabbix_server_logslowqueries is defined and zabbix_server_logslowqueries is not none) | ternary('', '# ') }}LogSlowQueries={{ zabbix_server_logslowqueries | default('') }}
+{{ (zabbix_server_logtype is defined and zabbix_server_logtype is not none) | ternary('', '# ') }}LogType={{ zabbix_server_logtype | default('') }}
+{{ (zabbix_server_maxhousekeeperdelete is defined and zabbix_server_maxhousekeeperdelete is not none) | ternary('', '# ') }}MaxHousekeeperDelete={{ zabbix_server_maxhousekeeperdelete | default('') }}
+{{ (zabbix_server_nodeaddress is defined and zabbix_server_nodeaddress is not none) | ternary('', '# ') }}NodeAddress={{ zabbix_server_nodeaddress | default('') }}
+{{ (zabbix_server_pidfile is defined and zabbix_server_pidfile is not none) | ternary('', '# ') }}PidFile={{ zabbix_server_pidfile | default('') }}
+{{ (zabbix_server_proxyconfigfrequency is defined and zabbix_server_proxyconfigfrequency is not none) | ternary('', '# ') }}ProxyConfigFrequency={{ zabbix_server_proxyconfigfrequency | default('') }}
+{{ (zabbix_server_proxydatafrequency is defined and zabbix_server_proxydatafrequency is not none) | ternary('', '# ') }}ProxyDataFrequency={{ zabbix_server_proxydatafrequency | default('') }}
+{{ (zabbix_server_snmptrapperfile is defined and zabbix_server_snmptrapperfile is not none) | ternary('', '# ') }}SNMPTrapperFile={{ zabbix_server_snmptrapperfile | default('') }}
+{{ (zabbix_server_socketdir is defined and zabbix_server_socketdir is not none) | ternary('', '# ') }}SocketDir={{ zabbix_server_socketdir | default('') }}
+{{ (zabbix_server_sourceip is defined and zabbix_server_sourceip is not none) | ternary('', '# ') }}SourceIP={{ zabbix_server_sourceip | default('') }}
+{{ (zabbix_server_sshkeylocation is defined and zabbix_server_sshkeylocation is not none) | ternary('', '# ') }}SSHKeyLocation={{ zabbix_server_sshkeylocation | default('') }}
+{{ (zabbix_server_sslcalocation is defined and zabbix_server_sslcalocation is not none) | ternary('', '# ') }}SSLCALocation={{ zabbix_server_sslcalocation | default('') }}
+{{ (zabbix_server_sslcertlocation is defined and zabbix_server_sslcertlocation is not none) | ternary('', '# ') }}SSLCertLocation={{ zabbix_server_sslcertlocation | default('') }}
+{{ (zabbix_server_sslkeylocation is defined and zabbix_server_sslkeylocation is not none) | ternary('', '# ') }}SSLKeyLocation={{ zabbix_server_sslkeylocation | default('') }}
+{{ (zabbix_server_startalerters is defined and zabbix_server_startalerters is not none) | ternary('', '# ') }}StartAlerters={{ zabbix_server_startalerters | default('') }}
+{{ (zabbix_server_startdbsyncers is defined and zabbix_server_startdbsyncers is not none) | ternary('', '# ') }}StartDBSyncers={{ zabbix_server_startdbsyncers | default('') }}
+{{ (zabbix_server_startdiscoverers is defined and zabbix_server_startdiscoverers is not none) | ternary('', '# ') }}StartDiscoverers={{ zabbix_server_startdiscoverers | default('') }}
+{{ (zabbix_server_startescalators is defined and zabbix_server_startescalators is not none) | ternary('', '# ') }}StartEscalators={{ zabbix_server_startescalators | default('') }}
+{{ (zabbix_server_starthistorypollers is defined and zabbix_server_starthistorypollers is not none) | ternary('', '# ') }}StartHistoryPollers={{ zabbix_server_starthistorypollers | default('') }}
+{{ (zabbix_server_starthttppollers is defined and zabbix_server_starthttppollers is not none) | ternary('', '# ') }}StartHTTPPollers={{ zabbix_server_starthttppollers | default('') }}
+{{ (zabbix_server_startipmipollers is defined and zabbix_server_startipmipollers is not none) | ternary('', '# ') }}StartIPMIPollers={{ zabbix_server_startipmipollers | default('') }}
+{{ (zabbix_server_startjavapollers is defined and zabbix_server_startjavapollers is not none) | ternary('', '# ') }}StartJavaPollers={{ zabbix_server_startjavapollers | default('') }}
+{{ (zabbix_server_startlldprocessors is defined and zabbix_server_startlldprocessors is not none) | ternary('', '# ') }}StartLLDProcessors={{ zabbix_server_startlldprocessors | default('') }}
+{{ (zabbix_server_startodbcpollers is defined and zabbix_server_startodbcpollers is not none) | ternary('', '# ', '# ') }}StartODBCPollers={{ zabbix_server_startodbcpollers | default('') }}
+{{ (zabbix_server_startpingers is defined and zabbix_server_startpingers is not none) | ternary('', '# ') }}StartPingers={{ zabbix_server_startpingers | default('') }}
+{{ (zabbix_server_startpollers is defined and zabbix_server_startpollers is not none) | ternary('', '# ') }}StartPollers={{ zabbix_server_startpollers | default('') }}
+{{ (zabbix_server_startpollersunreachable is defined and zabbix_server_startpollersunreachable is not none) | ternary('', '# ') }}StartPollersUnreachable={{ zabbix_server_startpollersunreachable | default('') }}
+{{ (zabbix_server_startpreprocessors is defined and zabbix_server_startpreprocessors is not none) | ternary('', '# ') }}StartPreprocessors={{ zabbix_server_startpreprocessors | default('') }}
+{{ (zabbix_server_startproxypollers is defined and zabbix_server_startproxypollers is not none) | ternary('', '# ') }}StartProxyPollers={{ zabbix_server_startproxypollers | default('') }}
+{{ (zabbix_server_startreportwriters is defined and zabbix_server_startreportwriters is not none) | ternary('', '# ') }}StartReportWriters={{ zabbix_server_startreportwriters | default('') }}
+{{ (zabbix_server_startsnmptrapper is defined and zabbix_server_startsnmptrapper is not none) | ternary('', '# ') }}StartSNMPTrapper={{ zabbix_server_startsnmptrapper | default('') }}
+{{ (zabbix_server_starttimers is defined and zabbix_server_starttimers is not none) | ternary('', '# ') }}StartTimers={{ zabbix_server_starttimers | default('') }}
+{{ (zabbix_server_starttrappers is defined and zabbix_server_starttrappers is not none) | ternary('', '# ') }}StartTrappers={{ zabbix_server_starttrappers | default('') }}
+{{ (zabbix_server_startvmwarecollectors is defined and zabbix_server_startvmwarecollectors is not none) | ternary('', '# ') }}StartVMwareCollectors={{ zabbix_server_startvmwarecollectors | default('') }}
+{{ (zabbix_server_statsallowedip is defined and zabbix_server_statsallowedip is not none) | ternary('', '# ') }}StatsAllowedIP={{ zabbix_server_statsallowedip | default('') }}
+{{ (zabbix_server_timeout is defined and zabbix_server_timeout is not none) | ternary('', '# ') }}Timeout={{ zabbix_server_timeout | default('') }}
+{{ (zabbix_server_tlscafile is defined and zabbix_server_tlscafile is not none) | ternary('', '# ') }}TLSCAFile={{ zabbix_server_tlscafile | default('') }}
+{{ (zabbix_server_tlscertfile is defined and zabbix_server_tlscertfile is not none) | ternary('', '# ') }}TLSCertFile={{ zabbix_server_tlscertfile | default('') }}
+{{ (zabbix_server_tlscipherall is defined and zabbix_server_tlscipherall is not none) | ternary('', '# ') }}TLSCipherAll={{ zabbix_server_tlscipherall | default('') }}
+{{ (zabbix_server_tlscipherall13 is defined and zabbix_server_tlscipherall13 is not none) | ternary('', '# ') }}TLSCipherAll13={{ zabbix_server_tlscipherall13 | default('') }}
+{{ (zabbix_server_tlsciphercert is defined and zabbix_server_tlsciphercert is not none) | ternary('', '# ') }}TLSCipherCert={{ zabbix_server_tlsciphercert | default('') }}
+{{ (zabbix_server_tlsciphercert13 is defined and zabbix_server_tlsciphercert13 is not none) | ternary('', '# ') }}TLSCipherCert13={{ zabbix_server_tlsciphercert13 | default('') }}
+{{ (zabbix_server_tlscipherpsk is defined and zabbix_server_tlscipherpsk is not none) | ternary('', '# ') }}TLSCipherPSK={{ zabbix_server_tlscipherpsk | default('') }}
+{{ (zabbix_server_tlscipherpsk13 is defined and zabbix_server_tlscipherpsk13 is not none) | ternary('', '# ') }}TLSCipherPSK13={{ zabbix_server_tlscipherpsk13 | default('') }}
+{{ (zabbix_server_tlscrlfile is defined and zabbix_server_tlscrlfile is not none) | ternary('', '# ') }}TLSCRLFile={{ zabbix_server_tlscrlfile | default('') }}
+{{ (zabbix_server_tlskeyfile is defined and zabbix_server_tlskeyfile is not none) | ternary('', '# ') }}TLSKeyFile={{ zabbix_server_tlskeyfile | default('') }}
+{{ (zabbix_server_tmpdir is defined and zabbix_server_tmpdir is not none) | ternary('', '# ') }}TmpDir={{ zabbix_server_tmpdir | default('') }}
+{{ (zabbix_server_trappertimeout is defined and zabbix_server_trappertimeout is not none) | ternary('', '# ') }}TrapperTimeout={{ zabbix_server_trappertimeout | default('') }}
+{{ (zabbix_server_trendcachesize is defined and zabbix_server_trendcachesize is not none) | ternary('', '# ') }}TrendCacheSize={{ zabbix_server_trendcachesize | default('') }}
+{{ (zabbix_server_trendfunctioncachesize is defined and zabbix_server_trendfunctioncachesize is not none) | ternary('', '# ') }}TrendFunctionCacheSize={{ zabbix_server_trendfunctioncachesize | default('') }}
+{{ (zabbix_server_unavailabledelay is defined and zabbix_server_unavailabledelay is not none) | ternary('', '# ') }}UnavailableDelay={{ zabbix_server_unavailabledelay | default('') }}
+{{ (zabbix_server_unreachabledelay is defined and zabbix_server_unreachabledelay is not none) | ternary('', '# ') }}UnreachableDelay={{ zabbix_server_unreachabledelay | default('') }}
+{{ (zabbix_server_unreachableperiod is defined and zabbix_server_unreachableperiod is not none) | ternary('', '# ') }}UnreachablePeriod={{ zabbix_server_unreachableperiod | default('') }}
+{{ (zabbix_server_user is defined and zabbix_server_user is not none) | ternary('', '# ') }}User={{ zabbix_server_user | default('') }}
+{{ (zabbix_server_valuecachesize is defined and zabbix_server_valuecachesize is not none) | ternary('', '# ') }}ValueCacheSize={{ zabbix_server_valuecachesize | default('') }}
+{% if zabbix_server_version is version('6.2', '>=') %}
+{{ (zabbix_server_vault is defined and zabbix_server_vault is not none) | ternary('', '# ') }}Vault={{ zabbix_server_vault | default('') }}
+{% endif %}
+{% if zabbix_server_version is version('6.4', '>=') %}
+{{ (zabbix_server_connectors is defined and zabbix_server_connectors is not none) | ternary('', '# ') }}StartConnectors={{ zabbix_server_connectors | default('') }}
+{% endif %}
+{{ (zabbix_server_vaultdbpath is defined and zabbix_server_vaultdbpath is not none) | ternary('', '# ') }}VaultDBPath={{ zabbix_server_vaultdbpath | default('') }}
+{% if zabbix_server_version is version('6.2', '>=') %}
+{{ (zabbix_server_vaulttlskeyfile is defined and zabbix_server_vaulttlskeyfile is not none) | ternary('', '# ') }}VaultTLSKeyFile={{ zabbix_server_vaulttlskeyfile | default('') }}
+{{ (zabbix_server_vaulttlscertfile is defined and zabbix_server_vaulttlscertfile is not none) | ternary('', '# ') }}VaultTLSCertFile={{ zabbix_server_vaulttlscertfile | default('') }}
+{% endif %}
+{{ (zabbix_server_vaulttoken is defined and zabbix_server_vaulttoken is not none) | ternary('', '# ') }}VaultToken={{ zabbix_server_vaulttoken | default('') }}
+{{ (zabbix_server_vaulturl is defined and zabbix_server_vaulturl is not none) | ternary('', '# ') }}VaultURL={{ zabbix_server_vaulturl | default('') }}
+{{ (zabbix_server_vmwarecachesize is defined and zabbix_server_vmwarecachesize is not none) | ternary('', '# ') }}VMwareCacheSize={{ zabbix_server_vmwarecachesize | default('') }}
+{{ (zabbix_server_vmwarefrequency is defined and zabbix_server_vmwarefrequency is not none) | ternary('', '# ') }}VMwareFrequency={{ zabbix_server_vmwarefrequency | default('') }}
+{{ (zabbix_server_vmwareperffrequency is defined and zabbix_server_vmwareperffrequency is not none) | ternary('', '# ') }}VMwarePerfFrequency={{ zabbix_server_vmwareperffrequency | default('') }}
+{{ (zabbix_server_vmwaretimeout is defined and zabbix_server_vmwaretimeout is not none) | ternary('', '# ') }}VMwareTimeout={{ zabbix_server_vmwaretimeout | default('') }}
+{{ (zabbix_server_webserviceurl is defined and zabbix_server_webserviceurl is not none) | ternary('', '# ') }}WebServiceURL={{ zabbix_server_webserviceurl | default('') }}
diff --git a/ansible_collections/community/zabbix/roles/zabbix_server/vars/Debian.yml b/ansible_collections/community/zabbix/roles/zabbix_server/vars/Debian.yml
index 1639e94b3..4074869e6 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_server/vars/Debian.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_server/vars/Debian.yml
@@ -7,30 +7,29 @@ mysql_create_dir: ""
zabbix_valid_server_versions:
# Debian
+ "12":
+ - 6.4
+ - 6.0
"11":
- 6.4
+ - 6.2
- 6.0
- - 5.0
- - 4.0
"10":
- 6.0
- - 5.0
- - 4.0
- "9":
- - 4.0
# Ubuntu
"22":
- 6.4
+ - 6.2
- 6.0
"20":
- 6.4
+ - 6.2
- 6.0
- - 5.0
- - 4.0
"18":
- 6.0
- - 5.0
- - 4.0
-zabbix_server_fpinglocation: /usr/bin/fping
-zabbix_server_fping6location: /usr/bin/fping6
+debian_keyring_path: /etc/apt/keyrings/
+zabbix_gpg_key: "{{ debian_keyring_path }}/zabbix-official-repo.asc"
+_zabbix_repo_deb_url: "http://repo.zabbix.com/zabbix/{{ zabbix_server_version }}"
+_zabbix_server_fping6location: /usr/bin/fping6
+_zabbix_server_fpinglocation: /usr/bin/fping
diff --git a/ansible_collections/community/zabbix/roles/zabbix_server/vars/RedHat.yml b/ansible_collections/community/zabbix/roles/zabbix_server/vars/RedHat.yml
index 016eae514..c2e0f14f3 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_server/vars/RedHat.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_server/vars/RedHat.yml
@@ -5,18 +5,32 @@ apache_log: httpd
mysql_create_dir: create/
+__epel_repo:
+ - epel
+
zabbix_valid_server_versions:
"9":
- 6.4
+ - 6.2
- 6.0
"8":
- 6.4
+ - 6.2
- 6.0
- - 5.0
- - 4.0
- "7":
- - 5.0
- - 4.0
-zabbix_server_fpinglocation: /usr/sbin/fping
-zabbix_server_fping6location: /usr/sbin/fping6
+pgsql_depenencies:
+ "9":
+ - python3-psycopg2
+ "8":
+ - python3-psycopg2
+
+mysql_client_pkgs:
+ "9":
+ - mysql
+ - python3-PyMySQL
+ "8":
+ - mysql
+ - python3-PyMySQL
+
+_zabbix_server_fping6location: /usr/sbin/fping6
+_zabbix_server_fpinglocation: /usr/sbin/fping
diff --git a/ansible_collections/community/zabbix/roles/zabbix_server/vars/zabbix.yml b/ansible_collections/community/zabbix/roles/zabbix_server/vars/zabbix.yml
deleted file mode 100644
index 7a642c9d6..000000000
--- a/ansible_collections/community/zabbix/roles/zabbix_server/vars/zabbix.yml
+++ /dev/null
@@ -1,261 +0,0 @@
----
-sign_keys:
- "64":
- bullseye:
- sign_key: E709712C
- buster:
- sign_key: E709712C
- stretch:
- sign_key: E709712C
- focal:
- sign_key: E709712C
- bionic:
- sign_key: E709712C
- xenial:
- sign_key: E709712C
- trusty:
- sign_key: E709712C
- jammy:
- sign_key: E709712C
- "62":
- bullseye:
- sign_key: E709712C
- buster:
- sign_key: E709712C
- stretch:
- sign_key: E709712C
- focal:
- sign_key: E709712C
- bionic:
- sign_key: E709712C
- xenial:
- sign_key: E709712C
- trusty:
- sign_key: E709712C
- jammy:
- sign_key: E709712C
- "60":
- bullseye:
- sign_key: E709712C
- buster:
- sign_key: E709712C
- stretch:
- sign_key: E709712C
- focal:
- sign_key: E709712C
- bionic:
- sign_key: E709712C
- xenial:
- sign_key: E709712C
- trusty:
- sign_key: E709712C
- jammy:
- sign_key: E709712C
- "54":
- bullseye:
- sign_key: E709712C
- buster:
- sign_key: E709712C
- stretch:
- sign_key: E709712C
- jessie:
- sign_key: E709712C
- focal:
- sign_key: E709712C
- bionic:
- sign_key: E709712C
- xenial:
- sign_key: E709712C
- trusty:
- sign_key: E709712C
- tricia:
- sign_key: E709712C
- "52":
- buster:
- sign_key: E709712C
- stretch:
- sign_key: E709712C
- jessie:
- sign_key: E709712C
- focal:
- sign_key: E709712C
- bionic:
- sign_key: E709712C
- xenial:
- sign_key: E709712C
- trusty:
- sign_key: E709712C
- tricia:
- sign_key: E709712C
- "50":
- buster:
- sign_key: E709712C
- stretch:
- sign_key: E709712C
- jessie:
- sign_key: E709712C
- focal:
- sign_key: E709712C
- bionic:
- sign_key: E709712C
- xenial:
- sign_key: E709712C
- trusty:
- sign_key: E709712C
- tricia:
- sign_key: E709712C
- "44":
- focal:
- sign_key: A14FE591
- eoan:
- sign_key: A14FE591
- cosmic:
- sign_key: A14FE591
- bionic:
- sign_key: A14FE591
- sonya:
- sign_key: A14FE591
- serena:
- sign_key: A14FE591
- buster:
- sign_key: A14FE591
- stretch:
- sign_key: A14FE591
- wheezy:
- sign_key: A14FE591
- jessie:
- sign_key: 79EA5ED4
- trusty:
- sign_key: 79EA5ED4
- xenial:
- sign_key: E709712C
- "42":
- eoan:
- sign_key: A14FE591
- cosmic:
- sign_key: A14FE591
- bionic:
- sign_key: A14FE591
- sonya:
- sign_key: A14FE591
- serena:
- sign_key: A14FE591
- buster:
- sign_key: A14FE591
- stretch:
- sign_key: A14FE591
- wheezy:
- sign_key: A14FE591
- jessie:
- sign_key: 79EA5ED4
- trusty:
- sign_key: 79EA5ED4
- xenial:
- sign_key: E709712C
- "40":
- focal:
- sign_key: A14FE591
- bionic:
- sign_key: A14FE591
- sonya:
- sign_key: A14FE591
- serena:
- sign_key: A14FE591
- buster:
- sign_key: A14FE591
- stretch:
- sign_key: A14FE591
- wheezy:
- sign_key: A14FE591
- jessie:
- sign_key: 79EA5ED4
- trusty:
- sign_key: 79EA5ED4
- xenial:
- sign_key: E709712C
- "34":
- bionic:
- sign_key: A14FE591
- sonya:
- sign_key: A14FE591
- serena:
- sign_key: A14FE591
- stretch:
- sign_key: A14FE591
- wheezy:
- sign_key: A14FE591
- jessie:
- sign_key: 79EA5ED4
- trusty:
- sign_key: 79EA5ED4
- xenial:
- sign_key: E709712C
- "32":
- bionic:
- sign_key: A14FE591
- sonya:
- sign_key: 79EA5ED4
- serena:
- sign_key: 79EA5ED4
- stretch:
- sign_key: A14FE591
- wheezy:
- sign_key: 79EA5ED4
- jessie:
- sign_key: 79EA5ED4
- trusty:
- sign_key: 79EA5ED4
- xenial:
- sign_key: E709712C
- "30":
- bionic:
- sign_key: A14FE591
- wheezy:
- sign_key: 79EA5ED4
- jessie:
- sign_key: 79EA5ED4
- stretch:
- sign_key: A14FE591
- buster:
- sign_key: A14FE591
- trusty:
- sign_key: 79EA5ED4
- xenial:
- sign_key: E709712C
- "24":
- wheezy:
- sign_key: 79EA5ED4
- jessie:
- sign_key: 79EA5ED4
- precise:
- sign_key: 79EA5ED4
- trusty:
- sign_key: 79EA5ED4
- "22":
- squeeze:
- sign_key: 79EA5ED4
- jessie:
- sign_key: 79EA5ED4
- precise:
- sign_key: 79EA5ED4
- trusty:
- sign_key: 79EA5ED4
- lucid:
- sign_key: 79EA5ED4
-
-suse:
- "openSUSE Leap":
- "42":
- name: server:monitoring
- url: http://download.opensuse.org/repositories/server:/monitoring/openSUSE_Leap_{{ ansible_distribution_version }}/
- "openSUSE":
- "12":
- name: server_monitoring
- url: http://download.opensuse.org/repositories/server:/monitoring/openSUSE_{{ ansible_distribution_version }}
- "SLES":
- "11":
- name: server_monitoring
- url: http://download.opensuse.org/repositories/server:/monitoring/SLE_11_SP3/
- "12":
- name: server_monitoring
- url: http://download.opensuse.org/repositories/server:/monitoring/SLE_12_SP3/
diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/README.md b/ansible_collections/community/zabbix/roles/zabbix_web/README.md
index cef5d62e7..5904f8288 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_web/README.md
+++ b/ansible_collections/community/zabbix/roles/zabbix_web/README.md
@@ -43,7 +43,7 @@ Please send Pull Requests or suggestions when you want to use this role for othe
## Ansible 2.10 and higher
-With the release of Ansible 2.10, modules have been moved into collections. With the exception of ansible.builtin modules, this means additonal collections must be installed in order to use modules such as seboolean (now ansible.posix.seboolean). The following collections are now required: `ansible.posix`. The `community.general` collection is required when defining the `zabbix_web_htpasswd` variable (see variable section below). Installing the collections:
+With the release of Ansible 2.10, modules have been moved into collections. With the exception of ansible.builtin modules, this means additonal collections must be installed in order to use modules such as seboolean (now ansible.posix.seboolean). The following collections are now required: `ansible.posix`. Installing the collections:
```sh
ansible-galaxy collection install ansible.posix
@@ -54,25 +54,16 @@ ansible-galaxy collection install community.general
See the following list of supported Operating Systems with the Zabbix releases.
-| Zabbix | 6.4 | 6.2 | 6.0 (LTS) | 5.4 | 5.2 | 5.0 (LTS) | 4.4 | 4.0 (LTS) | 3.0 (LTS) |
-|---------------------|-----|-----|-----------|-----|-----|------------|-----|-----------|-----------|
-| Red Hat Fam 9 | V | V | V | | | | | | |
-| Red Hat Fam 8 | V | V | V | V | V | V | V | | |
-| Red Hat Fam 7 | | V | V | V | V | V | V | V | V |
-| Red Hat Fam 6 | | | | | V | V | | | V |
-| Red Hat Fam 5 | | | | | V | V | | | V |
-| Fedora | | | | | | | V | V | |
-| Ubuntu 22.04 jammy | V | V | V | | | | | | |
-| Ubuntu 20.04 focal | V | V | V | V | V | V | V | | |
-| Ubuntu 18.04 bionic | | | V | V | V | V | V | V | |
-| Ubuntu 16.04 xenial | | | | | V | V | V | V | |
-| Ubuntu 14.04 trusty | | | | | V | V | V | V | V |
-| Debian 10 buster | V | V | V | V | V | V | V | | |
-| Debian 9 stretch | | | V | V | V | V | V | V | |
-| Debian 8 jessie | | | | | V | V | V | V | V |
-| Debian 7 wheezy | | | | | | | | V | V |
-| macOS 10.15 | | | | | | | V | V | |
-| macOS 10.14 | | | | | | | V | V | |
+| Zabbix | 6.4 | 6.2 | 6.0 |
+|---------------------|-----|-----|-----|
+| Red Hat Fam 9 | V | V | V |
+| Red Hat Fam 8 | V | V | V |
+| Ubuntu 22.04 jammy | V | V | V |
+| Ubuntu 20.04 focal | V | V | V |
+| Ubuntu 18.04 bionic | | | V |
+| Debian 12 bookworm | V | | V |
+| Debian 11 bullseye | V | V | V |
+| Debian 10 buster | | | V |
# Installation
@@ -93,107 +84,77 @@ The following is an overview of all available configuration defaults for this ro
### Overall Zabbix
-* `zabbix_web_version`: This is the version of zabbix. Default: The highest supported version for the operating system. Can be overridden to 6.2, 6.0, 5.4, 5.2, 5.0, 4.4, 4.0, 3.4, 3.2, 3.0, 2.4, or 2.2. Previously the variable `zabbix_version` was used directly but it could cause [some inconvenience](https://github.com/dj-wasabi/ansible-zabbix-agent/pull/303). That variable is maintained by retrocompativility.
+* `zabbix_web_version`: Optional. The latest available major.minor version of Zabbix will be installed on the host(s). If you want to use an older version, please specify this in the major.minor format. Example: `zabbix_web_version: 6.0`.
* `zabbix_web_version_minor`: When you want to specify a minor version to be installed. RedHat only. Default set to: `*` (latest available)
-* `zabbix_repo`: Default: `zabbix`
- * `epel`: install agent from EPEL repo
- * `zabbix`: (default) install agent from Zabbix repo
- * `other`: install agent from pre-existing or other repo
* `zabbix_repo_yum`: A list with Yum repository configuration.
* `zabbix_repo_yum_schema`: Default: `https`. Option to change the web schema for the yum repository(http/https)
-* `zabbix_repo_yum_disabled`: A string with repository names that should be disabled when installing Zabbix component specific packages. Is only used when `zabbix_repo_yum_enabled` contains 1 or more repositories. Default `*`.
-* `zabbix_repo_yum_enabled`: A list with repository names that should be enabled when installing Zabbix component specific packages.
-
+* `zabbix_web_disable_repo`: A list of repos to disable during install. Default `epel`.
* `zabbix_web_package_state`: Default: `present`. Can be overridden to `latest` to update packages when needed.
-* `zabbix_web_centos_release`: Default: True. When the `centos-release-scl` repository needs to be enabled. This is required when using Zabbix 5.0 due to installation of a recent version of `PHP`.
-* `zabbix_web_rhel_release`: Default: True. When the `scl-utils` repository needs to be enabled. This is required when using Zabbix 5.0 due to installation of a recent version of `PHP`.
* `zabbix_web_doubleprecision`: Default: `False`. For upgraded installations, please read database [upgrade notes](https://www.zabbix.com/documentation/current/manual/installation/upgrade_notes_500) (Paragraph "Enabling extended range of numeric (float) values") before enabling this option.
* `zabbix_web_conf_mode`: Default: `0644`. The "mode" for the Zabbix configuration file.
+* `zabbix_repo_deb_url`: The URL to the Zabbix repository. Default `http://repo.zabbix.com/zabbix/{{ zabbix_web_version }}/{{ ansible_distribution.lower() }}`
+* `zabbix_repo_deb_component`: The repository component for Debian installs. Default `main`.
### Zabbix Web specific
* `zabbix_api_server_url`: This is the url on which the zabbix web interface is available. Default is zabbix.example.com, you should override it. For example, see "Example Playbook"
+* `zabbix_web_http_server`: Which web server is in use. Valid values are 'apache' and 'nginx'. Default is `apache`
* `zabbix_url_aliases`: A list with Aliases for the Apache Virtual Host configuration.
* `zabbix_timezone`: Default: `Europe/Amsterdam`. This is the timezone. The Apache Virtual Host needs this parameter.
-* `zabbix_vhost`: Default: `true`. When you don't want to create an Apache Virtual Host configuration, you can set it to False.
+* `zabbix_web_create_vhost`: Default: `true`. When you don't want to create an Apache Virtual Host configuration, you can set it to False.
+* `zabbix_web_create_php_fpm`: Configure php-fpm (Debian hosts only). Default is to use the same value as `zabbix_web_create_vhost`.
* `zabbix_web_env`: (Optional) A Dictionary of PHP Environments settings.
-* `zabbix_web_conf_web_user`: When provided, the user (which should already exist on the host) will be used for ownership for web/php related processes. (Default set to either `apache` (`www-data` for Debian) or `nginx`).
-* `zabbix_web_conf_web_group`: When provided, the group (which should already exist on the host) will be used for ownership for web/php related processes. (Default set to either `apache` (`www-data` for Debian) or `nginx`).
-* `zabbix_web_htpasswd`: (Optional) Allow HTTP authentication at the webserver level via a htpasswd file.
-* `zabbix_web_htpasswd_file`: Default: `/etc/zabbix/web/htpasswd`. Allows the change the default path to the htpasswd file.
-* `zabbix_web_htpasswd_users`: (Optional) Dictionary for creating users via `htpasswd_user` and passphrases via `htpasswd_pass` in htpasswd file.
-* `zabbix_web_allowlist_ips`: (Optional) Allow web access at webserver level to a list of defined IPs or CIDR.
+* `zabbix_web_user`: When provided, the user (which should already exist on the host) will be used for ownership for web/php related processes. (Default set to either `apache` (`www-data` for Debian) or `nginx`).
+* `zabbix_web_group`: When provided, the group (which should already exist on the host) will be used for ownership for web/php related processes. (Default set to either `apache` (`www-data` for Debian) or `nginx`).
* `zabbix_web_connect_ha_backend`: (Optional) Default: `false`. When set to `true` values for Zabbix server will not be written and frontend gets values from database to connect to active cluster node. Set `true` when operating Zabbix servers in a cluste (only >=6.0).
* `zabbix_saml_idp_crt`: (Optional) The path to the certificate of the Identity Provider used for SAML authentication
* `zabbix_saml_sp_crt`: (Optional) The path to the public certificate of Zabbix as Service Provider
* `zabbix_saml_sp_key`: (Optional) The path to the private certificate of Zabbix as Service Provider
-#### Apache configuration
+#### Apache/Nginx Configuration
-* `zabbix_apache_vhost_port`: The port on which Zabbix HTTP vhost is running.
-* `zabbix_apache_vhost_tls_port`: The port on which Zabbix HTTPS vhost is running.
-* `zabbix_apache_vhost_listen_ip`: On which interface the Apache Virtual Host is available.
+* `zabbix_web_vhost_port`: The port on which Zabbix HTTP vhost is running.
+* `zabbix_web_vhost_tls_port`: The port on which Zabbix HTTPS vhost is running.
+* `zabbix_web_vhost_listen_ip`: On which interface the Apache Virtual Host is available.
* `zabbix_apache_can_connect_ldap`: Default: `false`. Set SELinux boolean to allow httpd to connect to LDAP.
-* `zabbix_php_install`: Default: `true`. True / False. Switch for extra install of packages for PHP, currently on for Debian/Ubuntu.
-* `zabbix_web_max_execution_time`:
-* `zabbix_web_memory_limit`:
-* `zabbix_web_post_max_size`:
-* `zabbix_web_upload_max_filesize`:
+* `zabbix_web_max_execution_time`: PHP max execution time
+* `zabbix_web_memory_limit`: PHP memory limit
+* `zabbix_web_post_max_size`: PHP maximum post size
+* `zabbix_web_upload_max_filesize`: PHP maximum file size
* `zabbix_web_max_input_time`:
-* `zabbix_apache_include_custom_fragment`: Default: `true`. Includes php_value vars max_execution_time, memory_limit, post_max_size, upload_max_filesize, max_input_time and date.timezone in vhost file.. place those in php-fpm configuration.
-* `zabbix_apache_tls`: If the Apache vhost should be configured with TLS encryption or not.
-* `zabbix_apache_redirect`: If a redirect should take place from HTTP to HTTPS
-* `zabbix_apache_tls_crt`: The path to the TLS certificate file.
-* `zabbix_apache_tls_key`: The path to the TLS key file.
-* `zabbix_apache_tls_chain`: The path to the TLS certificate chain file.
-* `zabbix_apache_SSLPassPhraseDialog`: Type of pass phrase dialog for encrypted private keys.
-* `zabbix_apache_SSLSessionCache`: Type of the global/inter-process SSL Session Cache
-* `zabbix_apache_SSLSessionCacheTimeout`: Number of seconds before an SSL session expires in the Session Cache
-* `zabbix_apache_SSLCryptoDevice`: Enable use of a cryptographic hardware accelerator
+* `zabbix_web_tls`: If the Apache vhost should be configured with TLS encryption or not.
+* `zabbix_web_redirect`: If a redirect should take place from HTTP to HTTPS
+* `zabbix_web_tls_crt`: The path to the TLS certificate file.
+* `zabbix_web_tls_key`: The path to the TLS key file.
+* `zabbix_web_tls_chain`: The path to the TLS certificate chain file.
+* `zabbix_web_SSLPassPhraseDialog`: Type of pass phrase dialog for encrypted private keys.
+* `zabbix_web_SSLSessionCache`: Type of the global/inter-process SSL Session Cache
+* `zabbix_web_SSLSessionCacheTimeout`: Number of seconds before an SSL session expires in the Session Cache
+* `zabbix_web_SSLCryptoDevice`: Enable use of a cryptographic hardware accelerator
* `zabbix_apache_custom_includes`: Configure custom includes. Default: `[]`
-When `zabbix_apache_tls_crt`, `zabbix_apache_tls_key` and/or `zabbix_apache_tls_chain` are used, make sure that these files exists before executing this role. The Zabbix-Web role will not install the mentioned files.
+When `zabbix_web_tls_crt`, `zabbix_web_tls_key` and/or `zabbix_web_tls_chain` are used, make sure that these files exists before executing this role. The Zabbix-Web role will not install the mentioned files.
See https://httpd.apache.org/docs/current/mod/mod_ssl.html for SSL* configuration options for Apache HTTPD.
#### Nginx configuration
-* `zabbix_nginx_vhost_port`: The port on which Zabbix HTTP vhost is running.
-* `zabbix_nginx_vhost_tls_port`: The port on which Zabbix HTTPS vhost is running.
-* `zabbix_nginx_tls`: If the Nginx vhost should be configured with TLS encryption or not.
-* `zabbix_nginx_tls_crt`: The path to the TLS certificate file.
-* `zabbix_nginx_tls_key`: The path to the TLS key file.
-* `zabbix_nginx_tls_dhparam`: The path to the TLS DHParam file.
-* `zabbix_nginx_tls_session_cache`: Type of the global/inter-process SSL Session Cache
-* `zabbix_nginx_tls_session_timeout`:
-* `zabbix_nginx_tls_session_tickets`:
-* `zabbix_nginx_tls_protocols`: The TLS Protocols to accept.
-* `zabbix_nginx_tls_ciphers`: The TLS Ciphers to be allowed.
-
-When `zabbix_nginx_tls_crt` and `zabbix_nginx_tls_key` are used, make sure that these files exists before executing this role. The Zabbix-Web role will not install the mentioned files.
#### PHP-FPM
The following properties are specific to Zabbix 5.0 and for the PHP(-FPM) configuration:
-* `zabbix_php_version`: Either `7.3` or `7.4` (Based on the OS Family). When you want to override the PHP Version.
* `zabbix_php_fpm_session`: The directory where sessions will be stored. If none are provided, defaults are used.
* `zabbix_php_fpm_listen`: The path to a socket file or ipaddress:port combination on which PHP-FPM needs to listen. If none are provided, defaults are used.
* `zabbix_php_fpm_conf_listen`: Default: `true`. If we want to configure the `zabbix_php_fpm_listen` in the PHP-FPM configuration file.
* `zabbix_php_fpm_conf_user`: The owner of the socket file (When `zabbix_php_fpm_listen` contains a patch to a socket file).
-* `zabbix_php_fpm_conf_enable_user`: Default: `true`. If we want to configure the owner of the `zabbix_php_fpm_listen` in the PHP-FPM configuration file.
+
* `zabbix_php_fpm_conf_group`: The group of the owner of the socket file (When `zabbix_php_fpm_listen` contains a patch to a socket file).
-* `zabbix_php_fpm_conf_enable_group`: Default: `true`. If we want to configure the group of the `zabbix_php_fpm_listen` in the PHP-FPM configuration file.
-* `zabbix_php_fpm_conf_mode`: The mode for the socket file (When `zabbix_php_fpm_listen` contains a patch to a socket file).
-* `zabbix_php_fpm_conf_enable_mode`: Default: `true`. If we want to configure the mode of the `zabbix_php_fpm_listen` in the PHP-FPM configuration file.
-* `zabbix_php_fpm_dir_etc`: etc HOME root directory of PHP-FPM setup.
-* `zabbix_php_fpm_dir_var`: Var HOME root directory of PHP-FPM setup.
### Zabbix Server
* `zabbix_server_name`: The name of the Zabbix Server.
* `zabbix_server_database`: The type of database used. Can be: mysql or pgsql
-* `zabbix_server_database_long`: The type of database used, but long name. Can be: mysql or postgresql
* `zabbix_server_hostname`: The hostname on which the zabbix-server is running. Default set to: {{ inventory_hostname }}
* `zabbix_server_listenport`: On which port the Zabbix Server is available. Default: 10051
* `zabbix_server_dbhost`: The hostname on which the database is running.
@@ -201,6 +162,7 @@ The following properties are specific to Zabbix 5.0 and for the PHP(-FPM) config
* `zabbix_server_dbuser`: The database username which is used by the Zabbix Server.
* `zabbix_server_dbpassword`: The database user password which is used by the Zabbix Server.
* `zabbix_server_dbport`: The database port which is used by the Zabbix Server.
+* `zabbix_server_dbencryption`: Use encryption with the database connection
The following properties are related when using Elasticsearch for history storage:
@@ -218,6 +180,17 @@ When the target host does not have access to the internet, but you do have a pro
* `zabbix_http_proxy`
* `zabbix_https_proxy`
+## Tags
+
+The majority of tasks within this role are tagged as follows:
+
+* `install`: Tasks associated with the installation of software.
+* `dependencies`: Installation tasks related to dependencies that aren't part of the core zabbix installation.
+* `database`: Tasks associated with the installation or configuration of the database.
+* `api`: Tasks associated with using the Zabbix API to connect and modify the Zabbix server.
+* `config`: Tasks associated with the configuration of Zabbix or a supporting service.
+* `service`: Tasks associated with managing a service.
+
# Example Playbook
There are two ways of using the zabbix-web:
@@ -237,12 +210,12 @@ When there is one host running both Zabbix Server and the Zabbix Web (Running My
- role: geerlingguy.php
- role: community.zabbix.zabbix_server
zabbix_server_database: mysql
- zabbix_server_database_long: mysql
+ zabbix_db_type_long: mysql
zabbix_server_dbport: 3306
- role: community.zabbix.zabbix_web
zabbix_api_server_url: zabbix.mydomain.com
zabbix_server_database: mysql
- zabbix_server_database_long: mysql
+ zabbix_db_type_long: mysql
zabbix_server_dbport: 3306
```
@@ -256,7 +229,7 @@ This is a two host setup. On one host (Named: "zabbix-server") the Zabbix Server
roles:
- role: community.zabbix.zabbix_server
zabbix_server_database: mysql
- zabbix_server_database_long: mysql
+ zabbix_db_type_long: mysql
zabbix_server_dbport: 3306
- hosts: zabbix-web
@@ -268,7 +241,7 @@ This is a two host setup. On one host (Named: "zabbix-server") the Zabbix Server
zabbix_api_server_url: zabbix.mydomain.com
zabbix_server_hostname: zabbix-server
zabbix_server_database: mysql
- zabbix_server_database_long: mysql
+ zabbix_db_type_long: mysql
zabbix_server_dbport: 3306
```
@@ -289,13 +262,13 @@ zabbix.conf.php, for example to add LDAP CA certificates. To do this add a `zabb
php_packages:
- php
- php-fpm
- - php-acpu
+ - php-apcu
- role: geerlingguy.apache-php-fpm
- role: community.zabbix.zabbix_web
zabbix_api_server_url: zabbix.mydomain.com
zabbix_server_hostname: zabbix-server
zabbix_server_database: mysql
- zabbix_server_database_long: mysql
+ zabbix_db_type_long: mysql
zabbix_server_dbport: 3306
zabbix_web_env:
LDAPTLS_CACERT: /etc/ssl/certs/ourcert.pem
diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/defaults/main.yml b/ansible_collections/community/zabbix/roles/zabbix_web/defaults/main.yml
index 6e326461e..f37bb07da 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_web/defaults/main.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_web/defaults/main.yml
@@ -1,79 +1,66 @@
---
# defaults file for zabbix-web
-# zabbix_web_version: 6.0
-zabbix_web_version_minor: "*"
-zabbix_version: "{{ zabbix_web_version }}"
-zabbix_repo: zabbix
+# zabbix_web_version: 6.4
zabbix_web_package_state: present
-zabbix_web_centos_release: true
-zabbix_web_rhel_release: true
-zabbix_selinux: false
zabbix_web_doubleprecision: false
-zabbix_web_conf_mode: "0640"
+zabbix_web_conf_mode: "0644"
zabbix_web_connect_ha_backend: false
-
-zabbix_url: zabbix.example.com # Will be deprecated in 2.0.0
-zabbix_api_server_url: "{{ zabbix_url }}"
-zabbix_websrv: apache
-zabbix_websrv_servername: "{{ zabbix_api_server_url | regex_findall('(?:https?\\://)?([\\w\\-\\.]+)') | first }}"
+zabbix_api_server_url: zabbix.example.com
+zabbix_web_http_server: apache
zabbix_url_aliases: []
-zabbix_web_htpasswd: false
-zabbix_web_htpasswd_file: /etc/zabbix/web/htpasswd
-zabbix_timezone: Europe/Amsterdam
-zabbix_vhost: true
+zabbix_web_create_vhost: true
+zabbix_web_create_php_fpm: "{{ zabbix_web_create_vhost }}"
-zabbix_php_install: true
-zabbix_php_frontend_deprecated: false
-zabbix_php_fpm: false
-zabbix_php_fpm_dir_etc: /etc/opt/rh/rh-php72/
-zabbix_php_fpm_dir_var: /var/opt/rh/rh-php72/
-zabbix_php_fpm_conf_listen: true
-zabbix_php_fpm_conf_enable_user: true
-zabbix_php_fpm_conf_enable_group: true
-zabbix_php_fpm_conf_mode: "0664"
-zabbix_php_fpm_conf_enable_mode: true
-zabbix_php_install_state: present
+zabbix_server_name: "{{ inventory_hostname }}"
+zabbix_server_hostname: "{{ inventory_hostname }}"
+zabbix_server_listenport: 10051
-zabbix_apache_vhost_port: 80
-zabbix_apache_vhost_tls_port: 443
-zabbix_apache_vhost_listen_ip: "*"
-zabbix_apache_tls: false
-zabbix_apache_redirect: false
-zabbix_apache_tls_crt: /etc/pki/server.crt
-zabbix_apache_tls_key: /etc/pki/server.key
-zabbix_apache_tls_chain:
-zabbix_apache_can_connect_ldap: false
-zabbix_apache_include_custom_fragment: true
-zabbix_apache_SSLPassPhraseDialog: exec:/usr/libexec/httpd-ssl-pass-dialog
-zabbix_apache_SSLSessionCache: shmcb:/run/httpd/sslcache(512000)
-zabbix_apache_SSLSessionCacheTimeout: 300
-zabbix_apache_SSLCryptoDevice: builtin
+zabbix_web_vhost_port: 80
+zabbix_web_vhost_tls_port: 443
+zabbix_web_vhost_listen_ip: "*"
+zabbix_web_tls: false
+zabbix_timezone: Europe/Amsterdam
+zabbix_php_fpm_conf_listen: true
+# zabbix_web_tls_crt: /etc/pki/server.crt
+# zabbix_web_tls_key: /etc/pki/server.key
+# zabbix_web_tls_chain:
+# zabbix_web_SSLPassPhraseDialog: exec:/usr/libexec/httpd-ssl-pass-dialog
+# zabbix_web_SSLSessionCache: shmcb:/run/httpd/sslcache(512000)
+# zabbix_web_SSLSessionCacheTimeout: 300
+# zabbix_web_SSLCryptoDevice: builtin
+# zabbix_web_max_execution_time: 300
+# zabbix_web_memory_limit: 128M
+# zabbix_web_post_max_size: 16M
+# zabbix_web_upload_max_filesize: 2M
+# zabbix_web_max_input_time: 300
+# zabbix_web_max_input_vars: 10000
zabbix_apache_custom_includes: []
-zabbix_nginx_vhost_port: 80
-zabbix_nginx_vhost_tls_port: 443
-zabbix_nginx_tls: false
-zabbix_nginx_redirect: false
-zabbix_nginx_tls_session_timeout: 1d
-zabbix_nginx_tls_session_cache: shared:MySSL:10m
-zabbix_nginx_tls_session_tickets: !!str off
-zabbix_nginx_tls_protocols: TLSv1.2
-zabbix_nginx_tls_ciphers: ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
-
-zabbix_letsencrypt: false
-zabbix_letsencrypt_webroot_path: /var/www/letsencrypt
-zabbix_letsencrypt_webroot_mode: 0755
+# Database
+zabbix_server_database: pgsql
+zabbix_server_dbhost: localhost
+zabbix_server_dbname: zabbix-server
+zabbix_server_dbuser: zabbix-server
+zabbix_server_dbpassword: zabbix-server
+zabbix_server_dbport: 5432
+zabbix_server_dbencryption: false
+zabbix_server_dbverifyhost: false
+zabbix_server_dbschema:
+# Yum/APT Variables
+zabbix_web_apt_priority:
+zabbix_web_version_minor: "*"
zabbix_repo_yum_gpgcheck: 0
zabbix_repo_yum_schema: https
-zabbix_repo_yum_disabled: "*"
-zabbix_repo_yum_enabled: []
+zabbix_repo_deb_component: main
+zabbix_web_disable_repo:
+ - epel
zabbix_repo_yum:
- name: zabbix
description: Zabbix Official Repository - $basearch
- baseurl: "{{ zabbix_repo_yum_schema }}://repo.zabbix.com/zabbix/{{ zabbix_version | regex_search('^[0-9]+.[0-9]+') }}/rhel/{{ ansible_distribution_major_version }}/$basearch/"
- gpgcheck: "{{ zabbix_repo_yum_gpgcheck }}"
+ baseurl: "{{ zabbix_repo_yum_schema }}://repo.zabbix.com/zabbix/{{ zabbix_web_version | regex_search('^[0-9]+.[0-9]+') }}/rhel/{{ ansible_distribution_major_version }}/$basearch/"
+ gpgcheck: "{{ zabbix_repo_yum_gpgcheck | default('0') }}"
mode: "0644"
gpgkey: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ZABBIX
state: present
@@ -81,41 +68,10 @@ zabbix_repo_yum:
description: Zabbix Official Repository non-supported - $basearch
baseurl: "{{ zabbix_repo_yum_schema }}://repo.zabbix.com/non-supported/rhel/{{ ansible_distribution_major_version }}/$basearch/"
mode: "0644"
- gpgcheck: "{{ zabbix_repo_yum_gpgcheck }}"
+ gpgcheck: "{{ zabbix_repo_yum_gpgcheck | default('0') }}"
gpgkey: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ZABBIX
state: present
-zabbix_5_repo_yum:
- - name: zabbix-frontend
- description: Zabbix Official Repository - $basearch
- baseurl: "{{ zabbix_repo_yum_schema }}://repo.zabbix.com/zabbix/{{ zabbix_version | regex_search('^[0-9]+.[0-9]+') }}/rhel/{{ ansible_distribution_major_version }}/$basearch/frontend/"
- mode: "0644"
- gpgcheck: "{{ zabbix_repo_yum_gpgcheck }}"
- gpgkey: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ZABBIX
- state: present
-
-zabbix_web_max_execution_time: 300
-zabbix_web_memory_limit: 128M
-zabbix_web_post_max_size: 16M
-zabbix_web_upload_max_filesize: 2M
-zabbix_web_max_input_time: 300
-zabbix_web_max_input_vars: 10000
-
-# Database
-zabbix_server_database: pgsql
-zabbix_server_database_long: postgresql
-zabbix_server_name: "{{ inventory_hostname }}"
-zabbix_server_hostname: "{{ inventory_hostname }}"
-zabbix_server_listenport: 10051
-zabbix_server_dbhost: localhost
-zabbix_server_dbname: zabbix-server
-zabbix_server_dbuser: zabbix-server
-zabbix_server_dbpassword: zabbix-server
-zabbix_server_dbport: 5432
-zabbix_server_dbencryption: false
-zabbix_server_dbverifyhost: false
-zabbix_server_dbschema:
-
# Elasticsearch
# zabbix_server_history_url:
# - "'uint' => 'http://localhost:9200'"
@@ -130,15 +86,13 @@ zabbix_server_history_types:
- "uint"
- "dbl"
-selinux_allow_zabbix_can_network: false
-_zabbix_web_apache_php_addition: false
+zabbix_selinux: false
+# selinux_allow_zabbix_can_network: false
+# zabbix_apache_can_connect_ldap: false
# SAML certificates
# zabbix_saml_idp_crt:
# zabbix_saml_sp_crt:
# zabbix_saml_sp_key:
-# When the `geerlingguys apache role` is not provided, we have some defaults.
-apache_ssl_cipher_suite: ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
-apache_ssl_protocol: all -SSLv3 -TLSv1 -TLSv1.1
-apache_vhosts_version: "2.4"
+# zabbix_web_ssl_cipher_suite: ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/handlers/main.yml b/ansible_collections/community/zabbix/roles/zabbix_web/handlers/main.yml
index 0d0974632..e97787b12 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_web/handlers/main.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_web/handlers/main.yml
@@ -1,53 +1,43 @@
---
-
- name: restart apache
- service:
+ ansible.builtin.service:
name: "{{ _apache_service }}"
state: restarted
enabled: true
become: true
when:
- - zabbix_websrv == 'apache'
+ - zabbix_web_http_server == 'apache'
- name: test nginx config
listen: restart nginx
- command: nginx -t
+ ansible.builtin.command: nginx -t
register: zabbix_nginx_cfg_check
notify: restart nginx tested
become: true
when:
- - zabbix_websrv == 'nginx'
+ - zabbix_web_http_server == 'nginx'
- name: restart nginx tested
- service:
+ ansible.builtin.service:
name: nginx
state: restarted
enabled: true
become: true
when:
- - zabbix_websrv == 'nginx'
+ - zabbix_web_http_server == 'nginx'
- zabbix_nginx_cfg_check.rc == 0
-- name: restart redhat-php-fpm
- service:
- name: "{{ 'rh-php72-php-fpm' if zabbix_php_fpm else 'php-fpm' }}"
- state: restarted
- enabled: true
- become: true
- when:
- - zabbix_version is version('5.0', '>=')
-
- name: restart php-fpm-version
- service:
- name: php{{ zabbix_php_version }}-fpm
+ ansible.builtin.service:
+ name: php{{ zabbix_web_php_installed_version }}-fpm
state: restarted
enabled: true
become: true
when:
- - zabbix_version is version('5.0', '>=')
+ - zabbix_web_version is version('5.0', '>=')
- name: "clean repo files from proxy creds"
- shell: ls /etc/yum.repos.d/zabbix* && sed -i 's/^proxy =.*//' /etc/yum.repos.d/zabbix* || true
+ ansible.builtin.shell: ls /etc/yum.repos.d/zabbix* && sed -i 's/^proxy =.*//' /etc/yum.repos.d/zabbix* || true
become: true
when:
- ansible_os_family == 'RedHat'
diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/tasks/Debian.yml b/ansible_collections/community/zabbix/roles/zabbix_web/tasks/Debian.yml
index 8a27b841c..ae1c7de26 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_web/tasks/Debian.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_web/tasks/Debian.yml
@@ -1,63 +1,149 @@
---
+- name: "Debian | Set PHP Dependencies"
+ ansible.builtin.set_fact:
+ zabbix_web_php_dependencies: "{{ _apache_php_dependencies if zabbix_web_http_server == 'apache' else _nginx_php_dependencies }}"
+ tags:
+ - config
-- name: "Include Zabbix gpg ids"
- include_vars: zabbix.yml
+- name: "Debian | Set some variables"
+ ansible.builtin.set_fact:
+ zabbix_short_version: "{{ zabbix_web_version | regex_replace('\\.', '') }}"
+ zabbix_underscore_version: "{{ zabbix_web_version | regex_replace('\\.', '_') }}"
+ zabbix_python_prefix: "python{% if ansible_python_version is version('3', '>=') %}3{% endif %}"
+ tags:
+ - always
-- name: "Set short version name"
- set_fact:
- zabbix_short_version: "{{ zabbix_version | regex_replace('\\.', '') }}"
+- name: "Debian | Update ansible_lsb fact"
+ ansible.builtin.setup:
+ gather_subset:
+ - lsb
-- name: "Debian | Install gpg key"
- apt_key:
- id: "{{ sign_keys[zabbix_short_version][ansible_distribution_release]['sign_key'] }}"
- url: http://repo.zabbix.com/zabbix-official-repo.key
+- name: "Debian | Installing lsb-release"
+ ansible.builtin.apt:
+ pkg: lsb-release
+ update_cache: true
+ cache_valid_time: 3600
+ force: true
+ state: present
+ environment:
+ http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
+ https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
+ become: true
+ tags:
+ - install
+
+- name: "Debian | Repo URL"
+ ansible.builtin.set_fact:
+ zabbix_repo_deb_url: "{{ _zabbix_repo_deb_url }}/{{ ansible_lsb.id.lower() }}{{ '-arm64' if ansible_machine == 'aarch64' and ansible_lsb.id == 'debian' else ''}}"
when:
- - zabbix_repo == "zabbix"
+ - zabbix_repo_deb_url is undefined
+ tags:
+ - always
+
+- name: "Debian | Install PHP Dependencies"
+ ansible.builtin.apt:
+ pkg: "{{ zabbix_web_php_dependencies }}"
+ state: "present"
+ update_cache: true
+ cache_valid_time: 0
+ environment:
+ http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
+ https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
+ register: zabbix_web_php_dependencies_install
+ until: zabbix_web_php_dependencies_install is succeeded
become: true
tags:
- - zabbix-web
- - init
- - config
+ - install
+ - dependencies
-- name: "Debian | Installing repository {{ ansible_distribution }}"
- apt_repository:
- repo: "{{ item }} http://repo.zabbix.com/zabbix/{{ zabbix_version }}/{{ ansible_distribution.lower() }}/ {{ ansible_distribution_release }} main"
- state: present
+- name: "Debian | Install PgSQL Dependencies"
+ ansible.builtin.apt:
+ pkg: "php{{ zabbix_web_php_installed_version }}-pgsql"
+ state: "present"
+ update_cache: true
+ cache_valid_time: 0
+ environment:
+ http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
+ https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
+ register: zabbix_web_php_dependencies_install
+ until: zabbix_web_php_dependencies_install is succeeded
+ become: true
+ when: zabbix_server_database == 'pgsql'
+ tags:
+ - install
+ - dependencies
+ - database
+
+# In releases older than Debian 12 and Ubuntu 22.04, /etc/apt/keyrings does not exist by default.
+# It SHOULD be created with permissions 0755 if it is needed and does not already exist.
+# See: https://wiki.debian.org/DebianRepository/UseThirdParty
+- name: "Debian | Create /etc/apt/keyrings/ on older versions"
+ ansible.builtin.file:
+ path: /etc/apt/keyrings/
+ state: directory
+ mode: "0755"
become: true
when:
- - zabbix_repo == "zabbix"
- - ansible_machine != "aarch64"
- with_items:
- - deb-src
- - deb
+ - (ansible_distribution == "Ubuntu" and ansible_distribution_major_version < "22") or
+ (ansible_distribution == "Debian" and ansible_distribution_major_version < "12")
+
+- name: "Debian | Download gpg key"
+ ansible.builtin.get_url:
+ url: http://repo.zabbix.com/zabbix-official-repo.key
+ dest: "{{ zabbix_gpg_key }}"
+ mode: "0644"
+ force: true
+ become: true
tags:
- - zabbix-web
- - init
- - config
+ - install
- name: "Debian | Installing repository {{ ansible_distribution }}"
- apt_repository:
- repo: "{{ item }} http://repo.zabbix.com/zabbix/{{ zabbix_version }}/{{ ansible_distribution.lower() }}-arm64/ {{ ansible_distribution_release }} main"
- state: present
+ ansible.builtin.copy:
+ dest: /etc/apt/sources.list.d/zabbix.sources
+ owner: root
+ group: root
+ mode: 0644
+ content: |
+ Types: deb deb-src
+ Enabled: yes
+ URIs: {{ zabbix_repo_deb_url }}
+ Suites: {{ ansible_distribution_release }}
+ Components: {{ zabbix_repo_deb_component }}
+ Architectures: {{ 'amd64' if ansible_machine != 'aarch64' else 'arm64'}}
+ Signed-By: {{ zabbix_gpg_key }}
become: true
+ tags:
+ - install
+
+- name: "Debian | Create /etc/apt/preferences.d/"
+ ansible.builtin.file:
+ path: /etc/apt/preferences.d/
+ state: directory
+ mode: "0755"
when:
- - zabbix_repo == "zabbix"
- - ansible_machine == "aarch64"
- with_items:
- - deb-src
- - deb
+ - zabbix_web_apt_priority | int
+ become: true
tags:
- - zabbix-web
- - init
- - config
+ - install
-- name: "Debian | Install PHP apart from zabbix-frontend-php deps"
- include_tasks: "php_Debian.yml"
- when: zabbix_php_install
+- name: "Debian | Configuring the weight for APT"
+ ansible.builtin.copy:
+ dest: "/etc/apt/preferences.d/zabbix_server-{{ zabbix_proxy_database }}"
+ content: |
+ Package: zabbix_server-{{ zabbix_proxy_database }}
+ Pin: origin repo.zabbix.com
+ Pin-Priority: {{ zabbix_web_apt_priority }}
+ owner: root
+ mode: "0644"
+ when:
+ - zabbix_web_apt_priority | int
+ become: true
+ tags:
+ - install
- name: "Debian | Install zabbix-web"
- apt:
- pkg: "zabbix-frontend-php{{ '-deprecated' if zabbix_php_frontend_deprecated else '' }}"
+ ansible.builtin.apt:
+ pkg: "zabbix-frontend-php"
state: "{{ zabbix_web_package_state }}"
update_cache: true
cache_valid_time: 0
@@ -68,41 +154,13 @@
until: zabbix_web_package_install is succeeded
become: true
tags:
- - zabbix-web
- - init
- - config
+ - install
- name: "Debian | Link graphfont.ttf (workaround ZBX-10467)"
- file:
- src: '/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf'
- path: '/usr/share/zabbix/fonts/graphfont.ttf'
+ ansible.builtin.file:
+ src: "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"
+ path: "/usr/share/zabbix/fonts/graphfont.ttf"
state: link
- tags:
- - zabbix-web
- - init
- - config
-
-- name: "Debian | Install PHP"
- template:
- src: php-fpm.conf.j2
- dest: "{{ zabbix_php_fpm_dir }}/zabbix.conf"
- owner: "{{ _apache_user }}"
- group: "{{ _apache_group }}"
- mode: 0644
become: true
- when:
- - zabbix_vhost
- notify:
- - restart php-fpm-version
-
-- name: "Including Apache Configuration"
- include_tasks: apache_Debian.yml
- vars:
- zabbix_apache_servername: "{{ zabbix_websrv_servername }}"
- when:
- - zabbix_websrv == 'apache'
-
-- name: "Configure SELinux when enabled"
- include_tasks: selinux.yml
- when:
- - zabbix_selinux | bool
+ tags:
+ - install
diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/tasks/RedHat.yml b/ansible_collections/community/zabbix/roles/zabbix_web/tasks/RedHat.yml
index bcd4dd666..30871017e 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_web/tasks/RedHat.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_web/tasks/RedHat.yml
@@ -1,183 +1,59 @@
----
-# Tasks specific for RedHat systems
+- name: "RedHat | Setting Short PHP Version"
+ ansible.builtin.set_fact:
+ zabbix_web_php_installed_version: "{{ zabbix_web_php_installed_version | regex_replace('\\.', '') }}"
+ tags:
+ - always
- name: "RedHat | Install basic repo file"
- yum_repository:
+ ansible.builtin.yum_repository:
name: "{{ item.name }}"
- description: "{{ item.description }}"
+ description: "{{ item.description | default(omit) }}"
baseurl: "{{ item.baseurl }}"
- gpgcheck: "{{ item.gpgcheck }}"
- gpgkey: "{{ item.gpgkey }}"
+ gpgcheck: "{{ item.gpgcheck | default(omit) }}"
+ gpgkey: "{{ item.gpgkey | default(omit) }}"
mode: "{{ item.mode | default('0644') }}"
- priority: "{{ item.priority | default('98') }}"
+ priority: "{{ item.priority | default('99') }}"
state: "{{ item.state | default('present') }}"
proxy: "{{ zabbix_http_proxy | default(omit) }}"
with_items: "{{ zabbix_repo_yum }}"
register: yum_repo_installed
become: true
- when:
- zabbix_repo == "zabbix"
- notify:
- - "clean repo files from proxy creds"
- tags:
- - zabbix-web
-
-- name: "RedHat | Install basic repo file (Zabbix 5.x)"
- yum_repository:
- name: "{{ item.name }}"
- description: "{{ item.description }}"
- baseurl: "{{ item.baseurl }}"
- gpgcheck: "{{ item.gpgcheck }}"
- gpgkey: "{{ item.gpgkey }}"
- mode: "{{ item.mode | default('0644') }}"
- priority: "{{ item.priority | default('98') }}"
- state: "{{ item.state | default('present') }}"
- proxy: "{{ zabbix_http_proxy | default(omit) }}"
- with_items: "{{ zabbix_5_repo_yum }}"
- become: true
- when:
- - zabbix_repo == "zabbix"
- - zabbix_version is version('5.0', '>=')
- - ansible_distribution_major_version != '8'
- - ansible_distribution_major_version != '9'
notify:
- "clean repo files from proxy creds"
tags:
- - zabbix-web
-
-- name: "RedHat | Install zabbix-web dependency (Zabbix 5.x) (CentOS)"
- yum:
- pkg:
- - centos-release-scl
- state: "{{ zabbix_web_package_state }}"
- update_cache: true
- disablerepo: "{{ '*' if (zabbix_repo_yum_enabled | length>0) else omit }}"
- enablerepo: "{{ zabbix_repo_yum_enabled if zabbix_repo_yum_enabled is iterable and (zabbix_repo_yum_enabled | length>0) else omit }}"
- environment:
- http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
- https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
- register: zabbix_web_dependency_package_install
- until: zabbix_web_dependency_package_install is succeeded
- become: true
- when:
- - zabbix_version is version('5.0', '>=')
- - zabbix_web_centos_release
- - ansible_distribution_major_version != '9'
- - ansible_distribution_major_version != '8'
- - ansible_distribution == "CentOS"
- tags:
- - zabbix-web
-
-- name: "RedHat | Install zabbix-web dependency (Zabbix 5.x) (RHEL)"
- yum:
- pkg:
- - scl-utils
- - scl-utils-build
- state: "{{ zabbix_web_package_state }}"
- update_cache: true
- disablerepo: "{{ '*' if (zabbix_repo_yum_enabled | length>0) else omit }}"
- enablerepo: "{{ zabbix_repo_yum_enabled if zabbix_repo_yum_enabled is iterable and (zabbix_repo_yum_enabled | length>0) else omit }}"
- environment:
- http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
- https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
- register: zabbix_web_dependency_package_install
- until: zabbix_web_dependency_package_install is succeeded
- become: true
- when:
- - zabbix_version is version('5.0', '>=')
- - zabbix_web_centos_release
- - ansible_distribution_major_version != '9'
- - ansible_distribution_major_version != '8'
- - ansible_distribution == "RedHat"
- tags:
- - zabbix-web
+ - install
-- name: "RedHat | Install zabbix-web (Zabbix 5.x)"
- yum:
- pkg:
- - zabbix-apache-conf-scl-{{ zabbix_web_version }}.{{ zabbix_web_version_minor }}
+- name: "RedHat | Install zabbix-web-{{ zabbix_server_database }}"
+ ansible.builtin.yum:
+ name:
+ - "zabbix-web-{{ zabbix_server_database }}"
state: "{{ zabbix_web_package_state }}"
update_cache: true
- disablerepo: "{{ '*' if (zabbix_repo_yum_enabled | length>0) else omit }}"
- enablerepo: "{{ zabbix_repo_yum_enabled if zabbix_repo_yum_enabled is iterable and (zabbix_repo_yum_enabled | length>0) else omit }}"
+ disablerepo: "{{ zabbix_web_disable_repo | default(omit) }}"
environment:
http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
register: zabbix_web_package_install
until: zabbix_web_package_install is succeeded
become: true
- when:
- - zabbix_version is version('5.0', '>=')
- - ansible_distribution_major_version != '9'
- - ansible_distribution_major_version != '8'
- - zabbix_websrv == 'apache'
tags:
- - zabbix-web
+ - install
-- name: "RedHat | Install zabbix-web-{{ zabbix_server_database }}"
- yum:
- pkg: zabbix-web-{{ zabbix_server_database }}{{ '-scl' if zabbix_version is version('5.0', '>=') and ansible_distribution_major_version|int < 8 else '' }}-{{ zabbix_web_version }}.{{ zabbix_web_version_minor }}
+- name: "RedHat | Install zabbix-web-configuration"
+ ansible.builtin.yum:
+ name:
+ - "zabbix-{{ zabbix_web_http_server }}-conf"
state: "{{ zabbix_web_package_state }}"
update_cache: true
- disablerepo: "{{ '*' if (zabbix_repo_yum_enabled | length>0) else omit }}"
- enablerepo: "{{ zabbix_repo_yum_enabled if zabbix_repo_yum_enabled is iterable and (zabbix_repo_yum_enabled | length>0) else omit }}"
+ disablerepo: "{{ zabbix_web_disable_repo | default(omit) }}"
environment:
http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
register: zabbix_web_package_install
until: zabbix_web_package_install is succeeded
become: true
- tags:
- - zabbix-web
-
-- name: RedHat 9 | Install PHP"
- package:
- name: php
- state: "{{ zabbix_php_install_state }}"
when:
- - zabbix_version is version('6.0', '>=')
+ - zabbix_web_version is version('6.0', '!=')
- ansible_distribution_major_version == '9'
- - zabbix_vhost
-
-- name: "RedHat | Install PHP"
- template:
- src: php-fpm.conf.j2
- dest: "{{ zabbix_php_fpm_dir }}/zabbix.conf"
- owner: "{{ zabbix_web_conf_web_user }}"
- group: "{{ zabbix_web_conf_web_group }}"
- mode: 0644
- become: true
- when:
- - zabbix_vhost
- notify:
- - restart redhat-php-fpm
-
-- include_tasks: apache_RedHat.yml
- vars:
- zabbix_apache_servername: "{{ zabbix_websrv_servername }}"
- when:
- - zabbix_websrv == 'apache'
-
-- name: "RedHat | Install Nginx vhost"
- template:
- src: nginx_vhost.conf.j2
- dest: /etc/nginx/conf.d/zabbix.conf
- owner: root
- group: root
- mode: 0644
- when:
- - zabbix_vhost
- - zabbix_websrv == 'nginx'
- become: true
- notify:
- - restart nginx
tags:
- - zabbix-web
- - init
- - config
- - nginx
-
-- name: "Configure SELinux when enabled"
- include_tasks: selinux.yml
- when:
- - zabbix_selinux | bool
+ - install
diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/tasks/access.yml b/ansible_collections/community/zabbix/roles/zabbix_web/tasks/access.yml
deleted file mode 100644
index f02a6ebe4..000000000
--- a/ansible_collections/community/zabbix/roles/zabbix_web/tasks/access.yml
+++ /dev/null
@@ -1,32 +0,0 @@
----
-- name: "htpasswd | check Python version to set prefix variable"
- set_fact:
- zabbix_python_prefix: "python{% if ansible_python_version is version_compare('3', '>=') %}3{% endif %}"
- when:
- - zabbix_web_htpasswd is defined
- - zabbix_web_htpasswd
- - zabbix_web_htpasswd_users is defined
-
-- name: "htpasswd | install passlib for Python interpreter"
- package:
- name: "{{ zabbix_python_prefix }}-passlib"
- state: present
- when:
- - zabbix_web_htpasswd is defined
- - zabbix_web_htpasswd
- - zabbix_web_htpasswd_users is defined
-
-- name: "htpasswd | manage HTTP authentication controls"
- community.general.htpasswd:
- path: "{{ zabbix_web_htpasswd_file }}"
- name: "{{ item.value.htpasswd_user }}"
- password: "{{ item.value.htpasswd_pass }}"
- group: www-data
- state: present
- loop_control:
- label: "{{ item.value.htpasswd_user }}"
- with_dict: "{{ zabbix_web_htpasswd_users }}"
- when:
- - zabbix_web_htpasswd is defined
- - zabbix_web_htpasswd
- - zabbix_web_htpasswd_users is defined
diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/tasks/apache.yml b/ansible_collections/community/zabbix/roles/zabbix_web/tasks/apache.yml
index f33b9b765..7e55fe3e9 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_web/tasks/apache.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_web/tasks/apache.yml
@@ -1,6 +1,47 @@
---
+- name: Setting Web Server Facts
+ ansible.builtin.set_fact:
+ zabbix_web_user: "{{ zabbix_web_user if zabbix_web_user is defined else _apache_user }}"
+ zabbix_web_group: "{{ zabbix_web_group if zabbix_web_group is defined else _apache_group }}"
+ zabbix_web_vhost_location: "{{ zabbix_web_vhost_location if zabbix_web_vhost_location is defined else _apache_vhost_location }}"
+ tags:
+ - always
+
+- name: "Apache | Installing Zabbix Apache Conf"
+ block:
+ - name: "Debian | Install zabbix-apache-conf"
+ ansible.builtin.apt:
+ pkg: "zabbix-apache-conf"
+ state: "{{ zabbix_web_package_state }}"
+ update_cache: true
+ cache_valid_time: 0
+ environment:
+ http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
+ https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
+ register: zabbix_apache_conf_install
+ until: zabbix_apache_conf_install is succeeded
+ become: true
+ when: ansible_os_family == "Debian"
+
+ - name: "RedHat | Install zabbix-apache-conf"
+ ansible.builtin.yum:
+ name:
+ - "zabbix-apache-conf-{{ zabbix_web_version }}.{{ zabbix_web_version_minor }}"
+ state: "{{ zabbix_web_package_state }}"
+ update_cache: true
+ disablerepo: "{{ zabbix_agent_disable_repo | default(omit) }}"
+ environment:
+ http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
+ https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
+ register: zabbix_apache_conf_install
+ until: zabbix_apache_conf_install is succeeded
+ become: true
+ when: ansible_os_family == "RedHat"
+ tags:
+ - install
+
- name: "Apache | Get Apache version"
- shell: |
+ ansible.builtin.shell: |
PATH=/usr/sbin:$PATH
set -o pipefail
apachectl -v | grep 'version' | awk -F '/' '{ print $2 }'| awk '{ print $1 }' | cut -c 1-3
@@ -10,26 +51,37 @@
args:
executable: /bin/bash
tags:
- - zabbix-web
+ - config
- name: "Apache | Set correct apache_version"
- set_fact:
+ ansible.builtin.set_fact:
apache_version: "{{ apachectl_version.stdout }}"
tags:
- - zabbix-web
+ - config
-- name: "Set some"
- set_fact:
- _zabbix_web_apache_php_addition: true
- when:
- - zabbix_version is version('4.4', '<=')
+- name: "Apache | Install apache vhost"
+ ansible.builtin.template:
+ src: apache_vhost.conf.j2
+ dest: "{{ zabbix_web_vhost_location }}"
+ owner: "{{ zabbix_web_user }}"
+ group: "{{ zabbix_web_group }}"
+ mode: 0644
+ when: zabbix_web_create_vhost
+ become: true
+ notify:
+ - restart apache
tags:
- - zabbix-web
+ - config
-- name: "Set some"
- set_fact:
- _zabbix_web_apache_php_addition: true
- when:
- - ansible_os_family == "Debian"
+- name: "Apache | Enable Site (Debian Only)"
+ ansible.builtin.file:
+ src: "{{ zabbix_web_vhost_location }}"
+ dest: /etc/apache2/sites-enabled/zabbix.conf
+ state: link
+ owner: "{{ zabbix_web_user }}"
+ group: "{{ zabbix_web_group }}"
+ mode: 0644
+ become: true
+ when: ansible_os_family == "Debian" and zabbix_web_create_vhost
tags:
- - zabbix-web
+ - config
diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/tasks/apache_Debian.yml b/ansible_collections/community/zabbix/roles/zabbix_web/tasks/apache_Debian.yml
deleted file mode 100644
index 732feaea9..000000000
--- a/ansible_collections/community/zabbix/roles/zabbix_web/tasks/apache_Debian.yml
+++ /dev/null
@@ -1,54 +0,0 @@
----
-
-- name: "Debian | Install legacy PHP integration for Apache"
- apt:
- state: present
- update_cache: true
- cache_valid_time: 3600
- name:
- - libapache2-mod-php
- become: true
-
-- name: "Debian | install apache vhost"
- template:
- src: apache_vhost.conf.j2
- dest: /etc/apache2/sites-available/zabbix.conf
- owner: "{{ zabbix_web_conf_web_user }}"
- group: "{{ zabbix_web_conf_web_group }}"
- mode: 0644
- when: zabbix_vhost
- become: true
- notify:
- - restart apache
- tags:
- - zabbix-web
- - init
- - config
- - apache
-
-- name: "Debian | Remove provided zabbix.conf files"
- file:
- path: "{{ item }}"
- state: absent
- when: zabbix_vhost
- become: true
- with_items:
- - /etc/apache2/conf-available/zabbix.conf
- - /etc/apache2/conf-enabled/zabbix.conf
-
-- name: "Debian | enable apache vhost"
- file:
- src: /etc/apache2/sites-available/zabbix.conf
- dest: /etc/apache2/sites-enabled/zabbix.conf
- owner: "{{ zabbix_web_conf_web_user }}"
- group: "{{ zabbix_web_conf_web_group }}"
- state: link
- when: zabbix_vhost
- become: true
- notify:
- - restart apache
- tags:
- - zabbix-server
- - init
- - config
- - apache
diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/tasks/apache_RedHat.yml b/ansible_collections/community/zabbix/roles/zabbix_web/tasks/apache_RedHat.yml
deleted file mode 100644
index 3a271331d..000000000
--- a/ansible_collections/community/zabbix/roles/zabbix_web/tasks/apache_RedHat.yml
+++ /dev/null
@@ -1,17 +0,0 @@
----
-
-- include_tasks: apache.yml
-
-- name: "RedHat | Install apache vhost"
- template:
- src: apache_vhost.conf.j2
- dest: /etc/httpd/conf.d/zabbix.conf
- owner: "{{ zabbix_web_conf_web_user }}"
- group: "{{ zabbix_web_conf_web_group }}"
- mode: 0644
- when: zabbix_vhost
- become: true
- notify:
- - restart apache
- tags:
- - zabbix-server
diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/tasks/main.yml b/ansible_collections/community/zabbix/roles/zabbix_web/tasks/main.yml
index fad607b1d..b82d8486b 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_web/tasks/main.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_web/tasks/main.yml
@@ -1,103 +1,97 @@
---
-# tasks file for wdijkerman.zabbix-web
-
- name: "Include OS-specific variables"
- include_vars: "{{ ansible_os_family }}.yml"
+ ansible.builtin.include_vars: "{{ ansible_os_family }}.yml"
tags:
- always
- name: Determine Latest Supported Zabbix Version
- set_fact:
- zabbix_web_version: "{{ zabbix_valid_web_versions[ansible_distribution_major_version][0] | default(6.0) }}"
+ ansible.builtin.set_fact:
+ zabbix_web_version: "{{ zabbix_valid_web_versions[ansible_distribution_major_version][0] | default(6.4) }}"
when: zabbix_web_version is not defined
-
-- name: "Include distribution and version-specific vars"
- include_vars: "{{ item }}"
- with_first_found:
- - files:
- - "{{ ansible_distribution }}-{{ ansible_distribution_major_version }}.yml"
- - "{{ ansible_os_family }}-{{ ansible_distribution_major_version }}.yml"
tags:
- always
-- name: "Set some versions"
- set_fact:
- zabbix_short_version: "{{ zabbix_version | regex_replace('\\.', '') }}"
- zabbix_php_version: "{{ zabbix_php_version if zabbix_php_version is defined else _zabbix_php_version }}"
- _zabbix_php_package_prefix: ""
+- name: Set More Variables
+ ansible.builtin.set_fact:
+ zabbix_valid_version: "{{ zabbix_web_version|float in zabbix_valid_web_versions[ansible_distribution_major_version] }}"
+ zabbix_db_type_long: "{{ 'postgresql' if zabbix_server_database == 'pgsql' else 'mysql' }}"
tags:
- always
-- name: "Set default PHP-FPM variables"
- set_fact:
- zabbix_php_fpm_dir: "{{ zabbix_php_fpm_dir if zabbix_php_fpm_dir is defined else _php_fpm_dir }}"
- zabbix_php_fpm_session: "{{ zabbix_php_fpm_session if zabbix_php_fpm_session is defined else _php_fpm_session }}"
- zabbix_php_fpm_listen: "{{ zabbix_php_fpm_listen if zabbix_php_fpm_listen is defined else _php_fpm_listen }}"
- when:
- - not zabbix_php_fpm
-
-- name: "Set default PHP-FPM variables specific RH provided"
- set_fact:
- zabbix_php_fpm_dir: "{{ zabbix_php_fpm_dir if zabbix_php_fpm_dir is defined else _php_fpm_dir }}"
- zabbix_php_fpm_session: "{{ zabbix_php_fpm_session if zabbix_php_fpm_session is defined else _zabbix_php_fpm_session }}"
- zabbix_php_fpm_listen: "{{ zabbix_php_fpm_listen if zabbix_php_fpm_listen is defined else _zabbix_php_fpm_listen }}"
- when:
- - zabbix_php_fpm
- - ansible_os_family == "RedHat"
-
-- name: "Set websrv specific variables (Apache)"
- set_fact:
- zabbix_web_conf_web_user: "{{ zabbix_web_conf_web_user if zabbix_web_conf_web_user is defined else _apache_user }}"
- zabbix_web_conf_web_group: "{{ zabbix_web_conf_web_group if zabbix_web_conf_web_group is defined else _apache_group }}"
- when:
- - zabbix_websrv == 'apache'
+- name: Stopping Install of Invalid Version
+ ansible.builtin.fail:
+ msg: Zabbix version {{ zabbix_web_version }} is not supported on {{ ansible_distribution }} {{ ansible_distribution_major_version }}
+ when: not zabbix_valid_version
+ tags:
+ - always
-- include_tasks: nginx.yml
- when:
- - zabbix_websrv == 'nginx'
+- name: Determine PHP Version
+ ansible.builtin.shell: php --version | head -1 | awk '{ print $2 }' | awk -F '.' '{print $1"."$2}'
+ register: _zabbix_web_php_installed_version
+ changed_when: false
+ tags:
+ - config
+ - install
-- name: "Install the correct repository"
- include_tasks: "RedHat.yml"
- when: ansible_os_family == "RedHat"
+- name: Set PHP Version
+ ansible.builtin.set_fact:
+ zabbix_web_php_installed_version: "{{ _zabbix_web_php_installed_version.stdout }}"
tags:
- - zabbix-web
+ - config
+ - install
-- name: "Install the correct repository"
- include_tasks: "Debian.yml"
- when: ansible_os_family == "Debian"
+- name: Set PHP Variables
+ ansible.builtin.set_fact:
+ zabbix_php_fpm_listen: "{{ zabbix_php_fpm_listen if zabbix_php_fpm_listen is defined else _zabbix_php_fpm_listen }}"
+ zabbix_php_fpm_dir: "{{ zabbix_php_fpm_dir if zabbix_php_fpm_dir is defined else _php_fpm_dir }}"
+ zabbix_php_fpm_session: "{{ zabbix_php_fpm_session if zabbix_php_fpm_session is defined else _php_fpm_session }}"
tags:
- - zabbix-web
+ - config
+ - install
+
+- name: Include OS Specific Tasks
+ ansible.builtin.include_tasks: "{{ ansible_os_family }}.yml"
+
+- name: "Install the web server specific tasks"
+ ansible.builtin.include_tasks: "{{ zabbix_web_http_server }}.yml"
- name: "Create zabbix-web directory"
- file:
+ ansible.builtin.file:
path: /etc/zabbix/web
- owner: "{{ zabbix_web_conf_web_user }}"
- group: "{{ zabbix_web_conf_web_group }}"
+ owner: "{{ zabbix_web_user }}"
+ group: "{{ zabbix_web_group }}"
state: directory
mode: 0755
+ become: true
tags:
- - zabbix-web
- - init
+ - install
- config
- name: "Configure zabbix-web"
- template:
+ ansible.builtin.template:
src: zabbix.conf.php.j2
dest: /etc/zabbix/web/zabbix.conf.php
- owner: "{{ zabbix_web_conf_web_user }}"
- group: "{{ zabbix_web_conf_web_group }}"
+ owner: "{{ zabbix_web_user }}"
+ group: "{{ zabbix_web_group }}"
mode: "{{ zabbix_web_conf_mode }}"
+ become: true
notify:
- - restart apache
+ - "restart {{ zabbix_web_http_server }}"
tags:
- - zabbix-web
- - init
- config
-- include_tasks: access.yml
+- name: "Debian | Install PHP"
+ ansible.builtin.template:
+ src: php-fpm.conf.j2
+ dest: "{{ zabbix_php_fpm_dir }}/zabbix.conf"
+ owner: "{{ zabbix_web_user }}"
+ group: "{{ zabbix_web_group }}"
+ mode: 0644
+ become: true
when:
- - zabbix_web_htpasswd
+ - zabbix_web_create_php_fpm
+ - ansible_os_family == "Debian"
+ notify:
+ - restart php-fpm-version
tags:
- - zabbix-web
- - init
- config
diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/tasks/nginx.yml b/ansible_collections/community/zabbix/roles/zabbix_web/tasks/nginx.yml
index 9e4ec41f1..1f50263ca 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_web/tasks/nginx.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_web/tasks/nginx.yml
@@ -1,153 +1,59 @@
---
- name: "Nginx | Set websrv specific variables"
- set_fact:
- zabbix_web_conf_web_user: "{{ zabbix_web_conf_web_user if zabbix_web_conf_web_user is defined else _nginx_user }}"
- zabbix_web_conf_web_group: "{{ zabbix_web_conf_web_group if zabbix_web_conf_web_group is defined else _nginx_group }}"
- zabbix_nginx_config_path: "{{ zabbix_nginx_config_path if zabbix_nginx_config_path is defined else _nginx_config_path }}"
+ ansible.builtin.set_fact:
+ zabbix_web_user: "{{ zabbix_web_user if zabbix_web_user is defined else _nginx_user }}"
+ zabbix_web_group: "{{ zabbix_web_group if zabbix_web_group is defined else _nginx_group }}"
+ zabbix_web_vhost_location: "{{ zabbix_web_vhost_location if zabbix_web_vhost_location is defined else _nginx_vhost_location }}"
zabbix_nginx_log_path: "{{ zabbix_nginx_log_path if zabbix_nginx_log_path is defined else _nginx_log_path }}"
zabbix_nginx_service: "{{ zabbix_nginx_service if zabbix_nginx_service is defined else _nginx_service }}"
- zabbix_nginx_tls_crt: "{{ zabbix_nginx_tls_crt if zabbix_nginx_tls_crt is defined else _nginx_tls_crt }}"
- zabbix_nginx_tls_key: "{{ zabbix_nginx_tls_key if zabbix_nginx_tls_key is defined else _nginx_tls_key }}"
- zabbix_nginx_tls_dhparam: "{{ zabbix_nginx_tls_dhparam if zabbix_nginx_tls_dhparam is defined else _nginx_tls_dhparam }}"
- zabbix_apache_service: "{{ zabbix_apache_service if zabbix_apache_service is defined else _apache_service }}"
-
-- name: "Nginx | Check Apache service if same ports"
- command: systemctl status "{{ zabbix_apache_service }}"
- failed_when: false
- register: zabbix_apache_service_check
- changed_when: zabbix_apache_service_check.rc == 0
- check_mode: false
- when:
- - zabbix_apache_vhost_port == zabbix_nginx_vhost_port
- - zabbix_apache_vhost_tls_port == zabbix_nginx_vhost_tls_port
-
-- name: "Nginx | Stop Apache running on same ports"
- service:
- name: "{{ zabbix_apache_service }}"
- state: stopped
- enabled: false
tags:
- - zabbix-web
- when:
- - zabbix_apache_vhost_port == zabbix_nginx_vhost_port
- - zabbix_apache_vhost_tls_port == zabbix_nginx_vhost_tls_port
- - zabbix_apache_service_check.rc == 0
-
-- name: "Nginx | Debian | Install Nginx and ssl-cert packages"
- # README don't go for HTTP2 with nginx-full yet due to:
- # https://support.zabbix.com/browse/ZBXNEXT-4670
- apt:
- state: present
- name:
- - nginx-light
- - ssl-cert
- when: ansible_os_family == "Debian"
-
-- name: "Nginx | RedHat | Install Nginx packages"
- yum:
- state: present
- name:
- - nginx
- when: ansible_os_family == "RedHat"
-
-- name: "Nginx | Start and enable service"
- service:
- name: "{{ zabbix_nginx_service }}"
- state: started
- enabled: true
-
-- name: "Nginx | Install OpenSSL package for DH parameters"
- package:
- name: openssl
- state: present
-
-- name: "Nginx | Generate SSL DH parameters"
- command: "openssl dhparam -out {{ zabbix_nginx_tls_dhparam }} {{ zabbix_nginx_tls_dhparam_bits | default('2048') }}"
- args:
- creates: "{{ zabbix_nginx_tls_dhparam }}"
-
-- name: "Let's Encrypt | check for certificate created by certbot"
- stat:
- path: "/etc/letsencrypt/live/{{ zabbix_websrv_servername }}/fullchain.pem"
- register: zabbix_letsencrypt_cert
- failed_when: false
- when: zabbix_letsencrypt
-
-- name: "Let's Encrypt | Create directory for certbot webroot if not exist"
- file:
- path: "{{ zabbix_letsencrypt_webroot_path }}"
- mode: "{{ zabbix_letsencrypt_webroot_mode }}"
- state: directory
- when:
- - zabbix_letsencrypt
- become: true
+ - config
+ - install
+
+- name: "Nginx | Installing Zabbix Nginx Conf"
+ block:
+ - name: "Debian | Install zabbix-nginx-conf"
+ ansible.builtin.apt:
+ pkg: "zabbix-nginx-conf"
+ state: "{{ zabbix_web_package_state }}"
+ update_cache: true
+ cache_valid_time: 0
+ environment:
+ http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
+ https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
+ register: zabbix_apache_conf_install
+ until: zabbix_apache_conf_install is succeeded
+ become: true
+ when: ansible_os_family == "Debian"
+
+ - name: "RedHat | Install zabbix-nginx-conf"
+ ansible.builtin.yum:
+ name:
+ - "zabbix-nginx-conf"
+ state: "{{ zabbix_web_package_state }}"
+ update_cache: true
+ disablerepo: "{{ zabbix_agent_disable_repo | default(omit) }}"
+ environment:
+ http_proxy: "{{ zabbix_http_proxy | default(None) | default(omit) }}"
+ https_proxy: "{{ zabbix_https_proxy | default(None) | default(omit) }}"
+ register: zabbix_apache_conf_install
+ until: zabbix_apache_conf_install is succeeded
+ become: true
+ when: ansible_os_family == "RedHat"
+ tags:
+ - install
- name: "Nginx | Install vhost in conf.d"
- template:
+ ansible.builtin.template:
src: nginx_vhost.conf.j2
- dest: "{{ zabbix_nginx_config_path }}/zabbix.conf"
- owner: root
- group: root
+ dest: "{{ zabbix_web_vhost_location }}"
+ owner: "{{ zabbix_web_user }}"
+ group: "{{ zabbix_web_group }}"
mode: 0644
when:
- - zabbix_vhost
- become: true
- notify:
- - restart nginx
-
-- name: "Let's Encrypt | Check if zabbix_websrv_servername is resolvable"
- set_fact:
- zabbix_websrv_servername_ip: "{{ lookup('dig', 'qtype=A', zabbix_websrv_servername) }}"
- changed_when: zabbix_websrv_servername_ip != ansible_default_ipv4.address
- register: zabbix_letsencrypt_resolve
- when: zabbix_letsencrypt
-
-- name: "Let's Encrypt | check if certbot CLI is present"
- shell: "certbot --version"
- register: zabbix_cerbot_check
- changed_when: zabbix_cerbot_check.rc != 0
- check_mode: false
- when: zabbix_letsencrypt
-
-- name: "Let's Encrypt | flash all handlers before certbot"
- meta: flush_handlers
- when:
- - zabbix_letsencrypt
- - zabbix_letsencrypt_resolve is not changed
- - zabbix_cerbot_check.rc == 0
-
-- name: "Let's Encrypt | generate certs with certbot CLI"
- command: >
- certbot --non-interactive certonly --expand
- -a webroot --webroot-path={{ zabbix_letsencrypt_webroot_path }}
- --email {{ zabbix_letsencrypt_account_email }} --agree-tos
- --cert-name {{ zabbix_websrv_servername }}
- -d {{ zabbix_websrv_servername }}
- args:
- creates: "/etc/letsencrypt/live/{{ zabbix_websrv_servername }}/fullchain.pem"
- when:
- - zabbix_letsencrypt
- - zabbix_letsencrypt_resolve is not changed
- - zabbix_cerbot_check.rc == 0
-
-- name: "Let's Encrypt | Check for certificate created by certbot"
- stat:
- path: "/etc/letsencrypt/live/{{ zabbix_websrv_servername }}/fullchain.pem"
- register: zabbix_letsencrypt_cert
- failed_when: false
- when: zabbix_letsencrypt
-
-- name: "Let's Encrypt | Reinstall Nginx vhost"
- template:
- src: nginx_vhost.conf.j2
- dest: /etc/nginx/conf.d/zabbix.conf
- owner: root
- group: root
- mode: 0644
- when:
- - zabbix_letsencrypt
- - zabbix_letsencrypt_resolve is not changed
- - zabbix_cerbot_check.rc == 0
+ - zabbix_web_create_vhost
become: true
notify:
- restart nginx
+ tags:
+ - config
diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/tasks/php_Debian.yml b/ansible_collections/community/zabbix/roles/zabbix_web/tasks/php_Debian.yml
deleted file mode 100644
index 6a2f329b6..000000000
--- a/ansible_collections/community/zabbix/roles/zabbix_web/tasks/php_Debian.yml
+++ /dev/null
@@ -1,43 +0,0 @@
----
-
-- include_tasks: apache.yml
- when:
- - zabbix_websrv == 'apache'
-
-# This obviously needs to have some improvements.. :)
-
-- name: "Debian | Determine php prefix for packages installations (legacy php5)"
- set_fact:
- _zabbix_php_package_prefix: 5
- when:
- - ansible_distribution == 'Ubuntu' and ansible_distribution_version is version_compare('16.04', '<')
- or ansible_distribution == 'Debian' and ansible_distribution_version is version_compare('9', '<')
-
-- name: "Debian | Determine php prefix for packages installations (Current distros)"
- set_fact:
- _zabbix_php_package_prefix: "{{ zabbix_php_version }}"
- when:
- - ansible_distribution == 'Ubuntu' and ansible_distribution_version is version_compare('16.04', '>=') or
- ansible_distribution == 'Debian' and ansible_distribution_version is version_compare('9', '>=')
- - zabbix_version is version_compare('5.0', '>=')
- - not _zabbix_web_apache_php_addition
-
-- name: "Debian | Install php packages"
- apt:
- state: present
- update_cache: true
- cache_valid_time: 3600
- name:
- - php{{ _zabbix_php_package_prefix }}-{{ zabbix_server_database }}
- - php{{ _zabbix_php_package_prefix }}-bcmath
- - php{{ _zabbix_php_package_prefix }}-mbstring
- - php{{ _zabbix_php_package_prefix }}-ldap
- - php{{ _zabbix_php_package_prefix }}-xml
- - php{{ _zabbix_php_package_prefix }}-gd
- - php{{ _zabbix_php_package_prefix }}-fpm
- register: zabbix_web_php_dependency_install
- until: zabbix_web_php_dependency_install is succeeded
- become: true
- tags:
- - zabbix-web
- - init
diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/tasks/selinux.yml b/ansible_collections/community/zabbix/roles/zabbix_web/tasks/selinux.yml
index df8936eb1..56e2ae05e 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_web/tasks/selinux.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_web/tasks/selinux.yml
@@ -1,7 +1,6 @@
---
-
- name: "SELinux | RedHat | Install related SELinux package"
- yum:
+ ansible.builtin.yum:
name:
- libsemanage-python
state: present
@@ -16,10 +15,10 @@
- selinux_allow_zabbix_can_network
- ansible_distribution_major_version == "7" or ansible_distribution_major_version == "6"
tags:
- - zabbix-web
+ - install
- name: "SELinux | RedHat | Install related SELinux package on RHEL9 and RHEL8"
- yum:
+ ansible.builtin.yum:
name:
- python3-libsemanage
state: present
@@ -34,7 +33,7 @@
- selinux_allow_zabbix_can_network
- ansible_distribution_major_version|int >= 8
tags:
- - zabbix-web
+ - install
- name: "SELinux | RedHat | Enable zabbix_can_network SELinux boolean"
ansible.posix.seboolean:
@@ -46,7 +45,7 @@
- ansible_os_family == "RedHat"
- selinux_allow_zabbix_can_network
tags:
- - zabbix-web
+ - config
- name: "SELinux | Allow httpd to connect to db (SELinux)"
ansible.posix.seboolean:
@@ -57,7 +56,8 @@
when:
- ansible_selinux.status == "enabled"
- selinux_allow_zabbix_can_network
- tags: selinux
+ tags:
+ - config
- name: "SELinux | Allow httpd to connect to zabbix (SELinux)"
ansible.posix.seboolean:
@@ -68,7 +68,8 @@
when:
- ansible_selinux.status == "enabled"
- selinux_allow_zabbix_can_network
- tags: selinux
+ tags:
+ - config
- name: "SELinux | Allow httpd to connect to ldap (SELinux)"
ansible.posix.seboolean:
@@ -79,4 +80,5 @@
when:
- ansible_selinux.status == "enabled"
- zabbix_apache_can_connect_ldap | bool
- tags: selinux
+ tags:
+ - config
diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/templates/apache_vhost.conf.j2 b/ansible_collections/community/zabbix/roles/zabbix_web/templates/apache_vhost.conf.j2
index 4149c43fa..334861d9b 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_web/templates/apache_vhost.conf.j2
+++ b/ansible_collections/community/zabbix/roles/zabbix_web/templates/apache_vhost.conf.j2
@@ -1,5 +1,5 @@
-<VirtualHost {{ zabbix_apache_vhost_listen_ip }}:{{ zabbix_apache_vhost_port }}>
- ServerName {{ zabbix_apache_servername }}
+<VirtualHost {{ zabbix_web_vhost_listen_ip }}:{{ zabbix_web_vhost_port }}>
+ ServerName {{ zabbix_api_server_url }}
{% for alias in zabbix_url_aliases %}
ServerAlias {{ alias }}
{% endfor %}
@@ -13,7 +13,7 @@
{% endfor %}
{% endif %}
-{% if zabbix_apache_redirect and zabbix_apache_tls %}
+{% if zabbix_web_redirect|default(false) and zabbix_web_tls|default(false) %}
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R,L]
@@ -57,50 +57,27 @@
{% endfor %}
## Logging
- ErrorLog "/var/log/{{ _apache_log }}/{{ zabbix_apache_servername }}_error.log"
+ ErrorLog "/var/log/{{ _apache_log }}/{{ zabbix_api_server_url }}_error.log"
ServerSignature Off
- CustomLog "/var/log/{{ _apache_log }}/{{ zabbix_apache_servername }}_access.log" combined
+ CustomLog "/var/log/{{ _apache_log }}/{{ zabbix_api_server_url }}_access.log" combined
## Rewrite rules
RewriteEngine On
RewriteRule ^$ /index.php [L]
-
-{% if _zabbix_web_apache_php_addition | default(false) %}
-{% if zabbix_apache_include_custom_fragment | default(true) %}
- ## Custom fragment
- {% if zabbix_php_fpm %}
- ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/usr/share/zabbix/$1
- ProxyTimeout 1800
- {% else %}
- php_value max_execution_time {{ zabbix_web_max_execution_time | default('300') }}
- php_value memory_limit {{ zabbix_web_memory_limit | default('128M') }}
- php_value post_max_size {{ zabbix_web_post_max_size | default('16M') }}
- php_value upload_max_filesize {{ zabbix_web_upload_max_filesize | default('2M') }}
- php_value max_input_time {{ zabbix_web_max_input_time | default('300') }}
-
- {% if zabbix_version is version('5.0', '>=') %}
- php_value max_input_vars {{ zabbix_web_max_input_vars | default('10000') }}
- {% endif %}
-
- # Set correct timezone.
- php_value date.timezone {{ zabbix_timezone }}
- {% endif %}
-{% endif %}
-{% endif %}
</VirtualHost>
{# Set up TLS vhosts #}
-{% if zabbix_apache_tls and zabbix_apache_vhost_tls_port %}
+{% if zabbix_web_tls and zabbix_web_vhost_tls_port %}
-SSLPassPhraseDialog {{ zabbix_apache_SSLPassPhraseDialog }}
-SSLSessionCache {{ zabbix_apache_SSLSessionCache }}
-SSLSessionCacheTimeout {{ zabbix_apache_SSLSessionCacheTimeout }}
+{{ (zabbix_web_SSLPassPhraseDialog is defined and zabbix_web_SSLPassPhraseDialog is not none) | ternary('', '# ') }}SSLPassPhraseDialog {{ zabbix_web_SSLPassPhraseDialog | default('') }}
+{{ (zabbix_web_SSLSessionCache is defined and zabbix_web_SSLSessionCache is not none) | ternary('', '# ') }}SSLSessionCache {{ zabbix_web_SSLSessionCache | default('') }}
+{{ (zabbix_web_SSLSessionCacheTimeout is defined and zabbix_web_SSLSessionCacheTimeout is not none) | ternary('', '# ') }}SSLSessionCacheTimeout {{ zabbix_web_SSLSessionCacheTimeout | default('') }}
+{{ (zabbix_web_SSLCryptoDevice is defined and zabbix_web_SSLCryptoDevice is not none) | ternary('', '# ') }}SSLCryptoDevice {{ zabbix_web_SSLCryptoDevice | default('') }}
SSLRandomSeed startup file:/dev/urandom 256
SSLRandomSeed connect builtin
-SSLCryptoDevice {{ zabbix_apache_SSLCryptoDevice }}
-<VirtualHost _default_:{{ zabbix_apache_vhost_tls_port }}>
- ServerName {{ zabbix_apache_servername }}
+<VirtualHost {{ zabbix_web_vhost_listen_ip }}:{{ zabbix_web_vhost_tls_port }}>
+ ServerName {{ zabbix_api_server_url }}
{% for alias in zabbix_url_aliases %}
ServerAlias {{ alias }}
{% endfor %}
@@ -115,17 +92,14 @@ SSLCryptoDevice {{ zabbix_apache_SSLCryptoDevice }}
{% endif %}
SSLEngine on
- SSLCipherSuite {{ apache_ssl_cipher_suite }}
- SSLProtocol {{ apache_ssl_protocol }}
- SSLHonorCipherOrder On
-{% if apache_vhosts_version == "2.4" %}
+ {{ (zabbix_web_ssl_cipher_suite is defined and zabbix_web_ssl_cipher_suite is not none) | ternary('', '# ') }}SSLCipherSuite {{ zabbix_web_ssl_cipher_suite | default('') }}
+ {{ (zabbix_web_ssl_cipher_suite is defined and zabbix_web_ssl_cipher_suite is not none) | ternary('', '# ') }}SSLHonorCipherOrder On
+{% if apache_version|string() == '2.4' %}
SSLCompression off
{% endif %}
- SSLCertificateFile {{ zabbix_apache_tls_crt }}
- SSLCertificateKeyFile {{ zabbix_apache_tls_key }}
-{% if zabbix_apache_tls_chain %}
- SSLCertificateChainFile {{ zabbix_apache_tls_chain }}
-{% endif %}
+ SSLCertificateFile {{ zabbix_web_tls_crt }}
+ SSLCertificateKeyFile {{ zabbix_web_tls_key }}
+ {{ (zabbix_web_tls_chain is defined and zabbix_web_tls_chain is not none) | ternary('', '# ') }}SSLCertificateChainFile {{ zabbix_web_tls_chain | default('') }}
{% set directory_paths = ['/usr/share/zabbix/conf', '/usr/share/zabbix/app', '/usr/share/zabbix/include', '/usr/share/zabbix/include/classes'] %}
@@ -165,35 +139,13 @@ SSLCryptoDevice {{ zabbix_apache_SSLCryptoDevice }}
{% endfor %}
## Logging
- ErrorLog "/var/log/{{ _apache_log }}/{{ zabbix_apache_servername }}_tls_error.log"
+ ErrorLog "/var/log/{{ _apache_log }}/{{ zabbix_api_server_url }}_tls_error.log"
ServerSignature Off
- CustomLog "/var/log/{{ _apache_log }}/{{ zabbix_apache_servername }}_tls_access.log" combined
+ CustomLog "/var/log/{{ _apache_log }}/{{ zabbix_api_server_url }}_tls_access.log" combined
## Rewrite rules
RewriteEngine On
RewriteRule ^$ /index.php [L]
-{% if _zabbix_web_apache_php_addition | default(false) %}
-{% if zabbix_apache_include_custom_fragment | default(true) %}
- ## Custom fragment
- {% if zabbix_php_fpm %}
- ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/usr/share/zabbix/$1
- ProxyTimeout 1800
- {% else %}
- php_value max_execution_time {{ zabbix_web_max_execution_time | default('300') }}
- php_value memory_limit {{ zabbix_web_memory_limit | default('128M') }}
- php_value post_max_size {{ zabbix_web_post_max_size | default('16M') }}
- php_value upload_max_filesize {{ zabbix_web_upload_max_filesize | default('2M') }}
- php_value max_input_time {{ zabbix_web_max_input_time | default('300') }}
-
- {% if zabbix_version is version('5.0', '>=') %}
- php_value max_input_vars {{ zabbix_web_max_input_vars | default('10000') }}
- {% endif %}
-
- # Set correct timezone.
- php_value date.timezone {{ zabbix_timezone }}
- {% endif %}
-{% endif %}
-{% endif %}
</VirtualHost>
{% endif %}
diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/templates/nginx_vhost.conf.j2 b/ansible_collections/community/zabbix/roles/zabbix_web/templates/nginx_vhost.conf.j2
index 49671984c..7854b83ce 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_web/templates/nginx_vhost.conf.j2
+++ b/ansible_collections/community/zabbix/roles/zabbix_web/templates/nginx_vhost.conf.j2
@@ -1,61 +1,78 @@
# Nginx configuration for Zabbix Web
server {
-{% if not zabbix_nginx_tls %}
- listen {{ zabbix_nginx_vhost_port }};
-{% else %}
-{% if zabbix_letsencrypt %}
- listen 80;
+ listen {{ zabbix_web_vhost_port }};
server_tokens off;
- server_name {{ zabbix_websrv_servername }} {% for alias in zabbix_url_aliases -%}{{ alias -}} {% endfor %};
- location ^~ /.well-known/acme-challenge {
- root {{ zabbix_letsencrypt_webroot_path | default('/var/www/letsencrypt') }};
- # disables IP restrictions and HTTP auth
- allow all;
- default_type text/plain;
- try_files $uri =404;
+ server_name {{ zabbix_api_server_url }} {% for alias in zabbix_url_aliases -%}{{ alias -}} {% endfor %};
+
+ {% if zabbix_web_redirect|default(false) and zabbix_web_tls|default(false) %}
+ return 301 https://{{ zabbix_api_server_url }}$request_uri;
+ {% else %}
+ root /usr/share/zabbix;
+
+ index index.php;
+
+ location = /favicon.ico {
+ log_not_found off;
}
- location / { return 301 https://$host:{{ zabbix_nginx_vhost_tls_port }}$request_uri; }
-}
-server {
-{% endif %}
- listen {{ zabbix_nginx_vhost_tls_port }} ssl;
-{% if zabbix_letsencrypt and zabbix_letsencrypt_cert.stat.exists %}
- ssl_certificate /etc/letsencrypt/live/{{ zabbix_websrv_servername }}/fullchain.pem;
- ssl_certificate_key /etc/letsencrypt/live/{{ zabbix_websrv_servername }}/privkey.pem;
-{% else %}
- ssl_certificate {{ zabbix_nginx_tls_crt }};
- ssl_certificate_key {{ zabbix_nginx_tls_key }};
-{% endif %}
- ssl_session_timeout {{ zabbix_nginx_tls_session_timeout }};
- ssl_session_cache {{ zabbix_nginx_tls_session_cache }};
- ssl_session_tickets {{ zabbix_nginx_tls_session_tickets }};
- ssl_dhparam {{ zabbix_nginx_tls_dhparam }};
+ location / {
+ try_files $uri $uri/ =404;
+ }
- ssl_protocols {{ zabbix_nginx_tls_protocols }};
- ssl_ciphers {{ zabbix_nginx_tls_ciphers }};
- ssl_prefer_server_ciphers off;
+ location /assets {
+ access_log off;
+ expires 10d;
+ }
-{% endif %}
- server_tokens off;
- server_name {{ zabbix_websrv_servername }} {% for alias in zabbix_url_aliases -%}{{ alias -}} {% endfor %};
+ location ~ /\.ht {
+ deny all;
+ }
-{% if zabbix_web_allowlist_ips is defined and zabbix_web_allowlist_ips %}
- # Allow list IPs via zabbix_web_allowlist_ips
- satisfy any;
-{% for ip in zabbix_web_allowlist_ips | ansible.netcommon.ipaddr %}
- allow {{ ip }};
-{% endfor %}
- deny all;
+ location ~ /(api\/|conf[^\.]|include|locale) {
+ deny all;
+ return 404;
+ }
-{% endif %}
-{% if zabbix_web_htpasswd is defined and zabbix_web_htpasswd %}
- # HTTP authentication via zabbix_web_htpasswd
- auth_basic "Restricted";
- auth_basic_user_file {{ zabbix_web_htpasswd_file }};
+ location ~ [^/]\.php(/|$) {
+ fastcgi_pass unix:{{ zabbix_php_fpm_listen }};
+ fastcgi_split_path_info ^(.+\.php)(/.+)$;
+ fastcgi_index index.php;
-{% endif %}
+ fastcgi_param DOCUMENT_ROOT /usr/share/zabbix;
+ fastcgi_param SCRIPT_FILENAME /usr/share/zabbix$fastcgi_script_name;
+ fastcgi_param PATH_TRANSLATED /usr/share/zabbix$fastcgi_script_name;
+
+ include fastcgi_params;
+ fastcgi_param QUERY_STRING $query_string;
+ fastcgi_param REQUEST_METHOD $request_method;
+ fastcgi_param CONTENT_TYPE $content_type;
+ fastcgi_param CONTENT_LENGTH $content_length;
+
+ fastcgi_intercept_errors on;
+ fastcgi_ignore_client_abort off;
+ fastcgi_connect_timeout 60;
+ fastcgi_send_timeout 180;
+ fastcgi_read_timeout 180;
+ fastcgi_buffer_size 128k;
+ fastcgi_buffers 4 256k;
+ fastcgi_busy_buffers_size 256k;
+ fastcgi_temp_file_write_size 256k;
+ }
+ {% endif %}
+}
+
+{% if zabbix_web_tls|default(false) %}
+server {
+ listen {{ zabbix_web_vhost_tls_port }} ssl;
+ server_tokens off;
+ server_name {{ zabbix_api_server_url }} {% for alias in zabbix_url_aliases -%}{{ alias -}} {% endfor %};
+
+ ssl_certificate {{ zabbix_web_tls_crt }};
+ ssl_certificate_key {{ zabbix_web_tls_key }};
+ {{ (zabbix_web_ssl_cipher_suite is defined and zabbix_web_ssl_cipher_suite is not none) | ternary('', '# ') }}ssl_ciphers {{ zabbix_web_ssl_cipher_suite | default('') }}
+ {{ (zabbix_web_SSLSessionCache is defined and zabbix_web_SSLSessionCache is not none) | ternary('', '# ') }}ssl_session_cache {{ zabbix_web_SSLSessionCache | default('') }}
+ {{ (zabbix_web_SSLSessionCacheTimeout is defined and zabbix_web_SSLSessionCacheTimeout is not none) | ternary('', '# ') }}ssl_session_timeout {{ zabbix_web_SSLSessionCacheTimeout | default('') }}
root /usr/share/zabbix;
index index.php;
@@ -108,3 +125,4 @@ server {
fastcgi_temp_file_write_size 256k;
}
}
+{% endif %}
diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/templates/php-fpm.conf.j2 b/ansible_collections/community/zabbix/roles/zabbix_web/templates/php-fpm.conf.j2
index bf2faef7a..e6b02cc9e 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_web/templates/php-fpm.conf.j2
+++ b/ansible_collections/community/zabbix/roles/zabbix_web/templates/php-fpm.conf.j2
@@ -1,20 +1,14 @@
[zabbix]
-user = {{ zabbix_php_fpm_conf_user if zabbix_php_fpm_conf_user is defined else zabbix_web_conf_web_user }}
-group = {{ zabbix_php_fpm_conf_group if zabbix_php_fpm_conf_group is defined else zabbix_web_conf_web_group }}
+user = {{ zabbix_php_fpm_conf_user if zabbix_php_fpm_conf_user is defined else zabbix_web_user }}
+group = {{ zabbix_php_fpm_conf_group if zabbix_php_fpm_conf_group is defined else zabbix_web_group }}
listen = {{ zabbix_php_fpm_listen }}
{% if zabbix_php_fpm_conf_listen and ansible_os_family != 'Debian' %}
-listen.acl_users = {{ zabbix_php_fpm_conf_user if zabbix_php_fpm_conf_user is defined else zabbix_web_conf_web_user }}
-{% endif %}
-{% if zabbix_php_fpm_conf_enable_user is defined %}
-listen.owner = {{ zabbix_php_fpm_conf_user if zabbix_php_fpm_conf_user is defined else zabbix_web_conf_web_user }}
-{% endif %}
-{% if zabbix_php_fpm_conf_enable_group %}
-listen.group = {{ _nginx_group if zabbix_websrv=='nginx' else _apache_group }}
-{% endif %}
-{% if zabbix_php_fpm_conf_enable_mode %}
-listen.mode = {{ zabbix_php_fpm_conf_mode }}
+listen.acl_users = {{ zabbix_php_fpm_conf_user if zabbix_php_fpm_conf_user is defined else zabbix_web_user }}
{% endif %}
+listen.owner = {{ zabbix_php_fpm_conf_user if zabbix_php_fpm_conf_user is defined else zabbix_web_user }}
+listen.group = {{ _nginx_group if zabbix_web_http_server=='nginx' else _apache_group }}
+listen.mode = 0644
listen.allowed_clients = 127.0.0.1
pm = dynamic
diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/templates/zabbix.conf.php.j2 b/ansible_collections/community/zabbix/roles/zabbix_web/templates/zabbix.conf.php.j2
index 880ed36f0..79ff73b15 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_web/templates/zabbix.conf.php.j2
+++ b/ansible_collections/community/zabbix/roles/zabbix_web/templates/zabbix.conf.php.j2
@@ -6,7 +6,7 @@ global $DB, $HISTORY;
global $DB;
{% endif %}
-$DB['TYPE'] = '{{ zabbix_server_database_long | upper() }}';
+$DB['TYPE'] = '{{ zabbix_db_type_long | upper() }}';
$DB['SERVER'] = '{{ zabbix_server_dbhost }}';
$DB['PORT'] = '{{ zabbix_server_dbport }}';
$DB['DATABASE'] = '{{ zabbix_server_dbname }}';
diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/vars/Debian-10.yml b/ansible_collections/community/zabbix/roles/zabbix_web/vars/Debian-10.yml
deleted file mode 100644
index 8ed439680..000000000
--- a/ansible_collections/community/zabbix/roles/zabbix_web/vars/Debian-10.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-
-_zabbix_php_version: 7.2
diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/vars/Debian-11.yml b/ansible_collections/community/zabbix/roles/zabbix_web/vars/Debian-11.yml
deleted file mode 100644
index 9d28ef9e3..000000000
--- a/ansible_collections/community/zabbix/roles/zabbix_web/vars/Debian-11.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-
-_zabbix_php_version: 7.4
diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/vars/Debian-8.yml b/ansible_collections/community/zabbix/roles/zabbix_web/vars/Debian-8.yml
deleted file mode 100644
index b4537abdf..000000000
--- a/ansible_collections/community/zabbix/roles/zabbix_web/vars/Debian-8.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-
-_zabbix_php_version: 7.3
diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/vars/Debian-9.yml b/ansible_collections/community/zabbix/roles/zabbix_web/vars/Debian-9.yml
deleted file mode 100644
index 9d28ef9e3..000000000
--- a/ansible_collections/community/zabbix/roles/zabbix_web/vars/Debian-9.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-
-_zabbix_php_version: 7.4
diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/vars/Debian.yml b/ansible_collections/community/zabbix/roles/zabbix_web/vars/Debian.yml
index 9840e6505..7b60c70bd 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_web/vars/Debian.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_web/vars/Debian.yml
@@ -3,16 +3,20 @@ _apache_user: www-data
_apache_group: www-data
_apache_log: apache2
_apache_service: apache2
+_apache_vhost_location: /etc/apache2/sites-available/zabbix.conf
-_php_fpm_dir: /etc/php/{{ _zabbix_php_version }}/fpm/pool.d
+_php_fpm_dir: /etc/php/{{ zabbix_web_php_installed_version }}/fpm/pool.d
_php_fpm_session: /tmp
-_php_fpm_listen: /run/php/zabbix.sock
+_zabbix_php_fpm_listen: /run/php/zabbix.sock
_zabbix_php_fpm_mode: "0666"
_zabbix_php_fpm_allowed_clients: 127.0.0.1
+_apache_php_dependencies: libapache2-mod-php{{ zabbix_web_php_installed_version }}
+_nginx_php_dependencies: []
+
_nginx_user: www-data
_nginx_group: www-data
-_nginx_config_path: /etc/nginx/conf.d
+_nginx_vhost_location: /etc/nginx/conf.d/zabbix.conf
_nginx_log_path: /var/log/nginx
_nginx_service: nginx
_nginx_tls_crt: /etc/ssl/certs/ssl-cert-snakeoil.pem
@@ -21,27 +25,27 @@ _nginx_tls_dhparam: /etc/ssl/private/dhparams.pem
zabbix_valid_web_versions:
# Debian
+ "12":
+ - 6.4
+ - 6.0
"11":
- 6.4
+ - 6.2
- 6.0
- - 5.0
- - 4.0
"10":
- 6.0
- - 5.0
- - 4.0
- "9":
- - 4.0
# Ubuntu
"22":
- 6.4
+ - 6.2
- 6.0
"20":
- 6.4
+ - 6.2
- 6.0
- - 5.0
- - 4.0
"18":
- 6.0
- - 5.0
- - 4.0
+
+debian_keyring_path: /etc/apt/keyrings/
+zabbix_gpg_key: "{{ debian_keyring_path }}/zabbix-official-repo.asc"
+_zabbix_repo_deb_url: "http://repo.zabbix.com/zabbix/{{ zabbix_web_version }}"
diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/vars/RedHat-7.yml b/ansible_collections/community/zabbix/roles/zabbix_web/vars/RedHat-7.yml
deleted file mode 100644
index 5109c4793..000000000
--- a/ansible_collections/community/zabbix/roles/zabbix_web/vars/RedHat-7.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-_php_fpm_dir: /etc/opt/rh/rh-php72/php-fpm.d/
-_php_fpm_session: /var/lib/php/session
-_php_fpm_listen: "/run/php-fpm/zabbix.sock"
-
-_zabbix_php_version: 7.2
-_zabbix_php_fpm_session: /var/opt/rh/rh-php72/lib/php/session/
-_zabbix_php_fpm_listen: /var/opt/rh/rh-php72/run/php-fpm/zabbix.sock
diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/vars/RedHat-8.yml b/ansible_collections/community/zabbix/roles/zabbix_web/vars/RedHat-8.yml
deleted file mode 100644
index 72022a460..000000000
--- a/ansible_collections/community/zabbix/roles/zabbix_web/vars/RedHat-8.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-_php_fpm_dir: /etc/php-fpm.d
-_php_fpm_session: /var/lib/php/session
-_php_fpm_listen: "/run/php-fpm/zabbix.sock"
-
-_zabbix_php_version: 7.4
-_zabbix_php_fpm_session: /var/opt/rh/rh-php72/lib/php/session/
-_zabbix_php_fpm_listen: /var/opt/rh/rh-php72/run/php-fpm/zabbix.sock
diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/vars/RedHat-9.yml b/ansible_collections/community/zabbix/roles/zabbix_web/vars/RedHat-9.yml
deleted file mode 100644
index bfcca82d3..000000000
--- a/ansible_collections/community/zabbix/roles/zabbix_web/vars/RedHat-9.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-_php_fpm_dir: /etc/php-fpm.d
-_php_fpm_session: /var/lib/php/session
-_php_fpm_listen: "/run/php-fpm/zabbix.sock"
-
-_zabbix_php_version: 8.0
-_zabbix_php_fpm_session: /var/lib/php/session
-_zabbix_php_fpm_listen: /run/php-fpm/zabbix.sock
diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/vars/RedHat.yml b/ansible_collections/community/zabbix/roles/zabbix_web/vars/RedHat.yml
index 89a950683..785c18c99 100644
--- a/ansible_collections/community/zabbix/roles/zabbix_web/vars/RedHat.yml
+++ b/ansible_collections/community/zabbix/roles/zabbix_web/vars/RedHat.yml
@@ -3,29 +3,41 @@ _apache_user: apache
_apache_group: apache
_apache_log: httpd
_apache_service: httpd
+_apache_vhost_location: /etc/httpd/conf.d/zabbix.conf
_php_fpm_dir: /etc/php-fpm.d
-_php_fpm_session: /var/opt/rh/rh-php72/lib/php/session/
-_php_fpm_listen: /run/php-fpm/zabbix.sock
+_php_fpm_session: /var/lib/php/session
+_zabbix_php_fpm_listen: /run/php-fpm/zabbix.sock
_nginx_user: nginx
_nginx_group: nginx
-_nginx_config_path: /etc/nginx/conf.d
+_nginx_vhost_location: /etc/nginx/conf.d/zabbix.conf
_nginx_log_path: /var/log/nginx
_nginx_service: nginx
-_nginx_tls_crt: /etc/pki/server.crt
-_nginx_tls_key: /etc/pki/server.key
-_nginx_tls_dhparam: /etc/pki/dhparam-server.pem
+
+__epel_repo:
+ - epel
zabbix_valid_web_versions:
"9":
- 6.4
+ - 6.2
- 6.0
"8":
- 6.4
+ - 6.2
- 6.0
- - 5.0
- - 4.0
- "7":
- - 5.0
- - 4.0
+
+zabbix_web_php_dependencies:
+ - "php-gd"
+ - "php-bcmath"
+ - "php-xml"
+ - "php-mbstring"
+ - "php-ldap"
+ - "php-{{ 'pgsql' if zabbix_server_database == 'pgsql' else 'mysqlnd' }}"
+
+zabbix_selinux_dependencies:
+ "9":
+ - python3-libsemanage
+ "8":
+ - python3-libsemanage
diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/vars/Ubuntu-18.yml b/ansible_collections/community/zabbix/roles/zabbix_web/vars/Ubuntu-18.yml
deleted file mode 100644
index 8ed439680..000000000
--- a/ansible_collections/community/zabbix/roles/zabbix_web/vars/Ubuntu-18.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-
-_zabbix_php_version: 7.2
diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/vars/Ubuntu-20.yml b/ansible_collections/community/zabbix/roles/zabbix_web/vars/Ubuntu-20.yml
deleted file mode 100644
index 9d28ef9e3..000000000
--- a/ansible_collections/community/zabbix/roles/zabbix_web/vars/Ubuntu-20.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-
-_zabbix_php_version: 7.4
diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/vars/Ubuntu-22.yml b/ansible_collections/community/zabbix/roles/zabbix_web/vars/Ubuntu-22.yml
deleted file mode 100644
index 39525f373..000000000
--- a/ansible_collections/community/zabbix/roles/zabbix_web/vars/Ubuntu-22.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-
-_zabbix_php_version: 8.1
diff --git a/ansible_collections/community/zabbix/roles/zabbix_web/vars/zabbix.yml b/ansible_collections/community/zabbix/roles/zabbix_web/vars/zabbix.yml
deleted file mode 100644
index 6de493b2e..000000000
--- a/ansible_collections/community/zabbix/roles/zabbix_web/vars/zabbix.yml
+++ /dev/null
@@ -1,258 +0,0 @@
----
-sign_keys:
- "64":
- bullseye:
- sign_key: E709712C
- buster:
- sign_key: E709712C
- stretch:
- sign_key: E709712C
- focal:
- sign_key: E709712C
- bionic:
- sign_key: E709712C
- xenial:
- sign_key: E709712C
- trusty:
- sign_key: E709712C
- jammy:
- sign_key: E709712C
- "62":
- bullseye:
- sign_key: E709712C
- buster:
- sign_key: E709712C
- stretch:
- sign_key: E709712C
- focal:
- sign_key: E709712C
- bionic:
- sign_key: E709712C
- xenial:
- sign_key: E709712C
- trusty:
- sign_key: E709712C
- jammy:
- sign_key: E709712C
- "60":
- bullseye:
- sign_key: E709712C
- buster:
- sign_key: E709712C
- stretch:
- sign_key: E709712C
- focal:
- sign_key: E709712C
- bionic:
- sign_key: E709712C
- xenial:
- sign_key: E709712C
- trusty:
- sign_key: E709712C
- jammy:
- sign_key: E709712C
- "54":
- bullseye:
- sign_key: E709712C
- buster:
- sign_key: E709712C
- jessie:
- sign_key: E709712C
- stretch:
- sign_key: E709712C
- focal:
- sign_key: E709712C
- bionic:
- sign_key: E709712C
- xenial:
- sign_key: E709712C
- trusty:
- sign_key: E709712C
- tricia:
- sign_key: E709712C
- "52":
- # bullseye: not available upstream
- buster:
- sign_key: E709712C
- jessie:
- sign_key: E709712C
- stretch:
- sign_key: E709712C
- focal:
- sign_key: E709712C
- bionic:
- sign_key: E709712C
- xenial:
- sign_key: E709712C
- trusty:
- sign_key: E709712C
- tricia:
- sign_key: E709712C
- "50":
- bullseye:
- sign_key: E709712C
- buster:
- sign_key: E709712C
- jessie:
- sign_key: E709712C
- stretch:
- sign_key: E709712C
- focal:
- sign_key: E709712C
- bionic:
- sign_key: E709712C
- xenial:
- sign_key: E709712C
- trusty:
- sign_key: E709712C
- tricia:
- sign_key: E709712C
- "44":
- buster:
- sign_key: A14FE591
- jessie:
- sign_key: 79EA5ED4
- stretch:
- sign_key: A14FE591
- focal:
- sign_key: A14FE591
- eoan:
- sign_key: A14FE591
- cosmic:
- sign_key: A14FE591
- bionic:
- sign_key: A14FE591
- sonya:
- sign_key: A14FE591
- serena:
- sign_key: A14FE591
- trusty:
- sign_key: 79EA5ED4
- xenial:
- sign_key: E709712C
- "42":
- buster:
- sign_key: A14FE591
- jessie:
- sign_key: 79EA5ED4
- stretch:
- sign_key: A14FE591
- eoan:
- sign_key: A14FE591
- cosmic:
- sign_key: A14FE591
- bionic:
- sign_key: A14FE591
- sonya:
- sign_key: A14FE591
- serena:
- sign_key: A14FE591
- trusty:
- sign_key: 79EA5ED4
- xenial:
- sign_key: E709712C
- "40":
- bullseye:
- sign_key: A14FE591
- buster:
- sign_key: A14FE591
- jessie:
- sign_key: 79EA5ED4
- stretch:
- sign_key: A14FE591
- focal:
- sign_key: A14FE591
- bionic:
- sign_key: A14FE591
- sonya:
- sign_key: A14FE591
- serena:
- sign_key: A14FE591
- trusty:
- sign_key: 79EA5ED4
- xenial:
- sign_key: E709712C
- "34":
- jessie:
- sign_key: 79EA5ED4
- stretch:
- sign_key: A14FE591
- wheezy:
- sign_key: A14FE591
- bionic:
- sign_key: A14FE591
- sonya:
- sign_key: A14FE591
- serena:
- sign_key: A14FE591
- trusty:
- sign_key: 79EA5ED4
- xenial:
- sign_key: E709712C
- "32":
- stretch:
- sign_key: A14FE591
- wheezy:
- sign_key: 79EA5ED4
- bionic:
- sign_key: A14FE591
- sonya:
- sign_key: 79EA5ED4
- serena:
- sign_key: 79EA5ED4
- trusty:
- sign_key: 79EA5ED4
- xenial:
- sign_key: E709712C
- "30":
- buster:
- sign_key: A14FE591
- jessie:
- sign_key: 79EA5ED4
- stretch:
- sign_key: A14FE591
- wheezy:
- sign_key: 79EA5ED4
- bionic:
- sign_key: A14FE591
- trusty:
- sign_key: 79EA5ED4
- xenial:
- sign_key: E709712C
- "24":
- jessie:
- sign_key: 79EA5ED4
- wheezy:
- sign_key: 79EA5ED4
- precise:
- sign_key: 79EA5ED4
- trusty:
- sign_key: 79EA5ED4
- "22":
- squeeze:
- sign_key: 79EA5ED4
- wheezy:
- sign_key: 79EA5ED4
- precise:
- sign_key: 79EA5ED4
- trusty:
- sign_key: 79EA5ED4
- lucid:
- sign_key: 79EA5ED4
-
-suse:
- "openSUSE Leap":
- "42":
- name: server:monitoring
- url: http://download.opensuse.org/repositories/server:/monitoring/openSUSE_Leap_{{ ansible_distribution_version }}/
- "openSUSE":
- "12":
- name: server_monitoring
- url: http://download.opensuse.org/repositories/server:/monitoring/openSUSE_{{ ansible_distribution_version }}
- "SLES":
- "11":
- name: server_monitoring
- url: http://download.opensuse.org/repositories/server:/monitoring/SLE_11_SP3/
- "12":
- name: server_monitoring
- url: http://download.opensuse.org/repositories/server:/monitoring/SLE_12_SP3/
diff --git a/ansible_collections/community/zabbix/scripts/inventory/zabbix.ini b/ansible_collections/community/zabbix/scripts/inventory/zabbix.ini
index ead19b62d..0d6bcab8d 100644
--- a/ansible_collections/community/zabbix/scripts/inventory/zabbix.ini
+++ b/ansible_collections/community/zabbix/scripts/inventory/zabbix.ini
@@ -7,14 +7,20 @@
server = http://zabbix.example.com/zabbix
# Login
-username = admin
+username = Admin
password = zabbix
+# Authentication token, if empty then username/password used to authenticate
+auth_token =
+
# Verify the server's SSL certificate
validate_certs = True
+# Time to wait for API response
+tiemout = 30
+
# Read zabbix inventory per host
read_host_inventory = True
# Set ansible_ssh_host based on first interface settings
-use_host_interface = True \ No newline at end of file
+use_host_interface = True
diff --git a/ansible_collections/community/zabbix/scripts/inventory/zabbix.py b/ansible_collections/community/zabbix/scripts/inventory/zabbix.py
index 767012848..29ac11b93 100644
--- a/ansible_collections/community/zabbix/scripts/inventory/zabbix.py
+++ b/ansible_collections/community/zabbix/scripts/inventory/zabbix.py
@@ -38,134 +38,209 @@ from __future__ import print_function
import os
import sys
import argparse
-from ansible.module_utils.six.moves import configparser
-
-try:
- from zabbix_api import ZabbixAPI
-except Exception:
- print("Error: Zabbix API library must be installed: pip install zabbix-api.",
- file=sys.stderr)
- sys.exit(1)
-
import json
+import atexit
+from ansible.module_utils.six.moves import configparser
+from ansible.module_utils.compat.version import LooseVersion
+from ansible.module_utils.urls import Request
+from ansible.module_utils.six.moves.urllib.error import URLError, HTTPError
class ZabbixInventory(object):
def read_settings(self):
config = configparser.ConfigParser()
- conf_path = './zabbix.ini'
+ conf_path = "./zabbix.ini"
if not os.path.exists(conf_path):
- conf_path = os.path.dirname(os.path.realpath(__file__)) + '/zabbix.ini'
+ conf_path = os.path.dirname(os.path.realpath(__file__)) + "/zabbix.ini"
if os.path.exists(conf_path):
config.read(conf_path)
# server
- if config.has_option('zabbix', 'server'):
- self.zabbix_server = config.get('zabbix', 'server')
+ if config.has_option("zabbix", "server"):
+ self.zabbix_server = config.get("zabbix", "server")
# login
- if config.has_option('zabbix', 'username'):
- self.zabbix_username = config.get('zabbix', 'username')
- if config.has_option('zabbix', 'password'):
- self.zabbix_password = config.get('zabbix', 'password')
+ if config.has_option("zabbix", "username"):
+ self.zabbix_username = config.get("zabbix", "username")
+ if config.has_option("zabbix", "password"):
+ self.zabbix_password = config.get("zabbix", "password")
+ if config.has_option("zabbix", "auth_token"):
+ self.auth_token = config.get("zabbix", "auth_token")
# ssl certs
- if config.has_option('zabbix', 'validate_certs'):
- if config.get('zabbix', 'validate_certs') in ['false', 'False', False]:
+ if config.has_option("zabbix", "validate_certs"):
+ if config.get("zabbix", "validate_certs") in ["false", "False", False]:
self.validate_certs = False
+ # timeout
+ if config.has_option("zabbix", "timeout"):
+ self.timeout = config.get("zabbix", "timeout")
# host inventory
- if config.has_option('zabbix', 'read_host_inventory'):
- if config.get('zabbix', 'read_host_inventory') in ['true', 'True', True]:
+ if config.has_option("zabbix", "read_host_inventory"):
+ if config.get("zabbix", "read_host_inventory") in ["true", "True", True]:
self.read_host_inventory = True
# host interface
- if config.has_option('zabbix', 'use_host_interface'):
- if config.get('zabbix', 'use_host_interface') in ['false', 'False', False]:
+ if config.has_option("zabbix", "use_host_interface"):
+ if config.get("zabbix", "use_host_interface") in ["false", "False", False]:
self.use_host_interface = False
def read_cli(self):
parser = argparse.ArgumentParser()
- parser.add_argument('--host')
- parser.add_argument('--list', action='store_true')
+ parser.add_argument("--host")
+ parser.add_argument("--list", action="store_true")
self.options = parser.parse_args()
def hoststub(self):
return {
- 'hosts': []
+ "hosts": []
+ }
+
+ def api_request(self, method, params=None):
+ server_url = self.zabbix_server
+ validate_certs = self.validate_certs
+ timeout = self.timeout
+
+ headers = {"Content-Type": "application/json-rpc"}
+ payload = {
+ "jsonrpc": "2.0",
+ "method": method,
+ "id": "1"
}
+ if params is None:
+ payload["params"] = {}
+ else:
+ payload["params"] = params
- def get_host(self, api, name):
- api_query = {'output': 'extend', 'selectGroups': 'extend', "filter": {"host": [name]}}
+ if self.auth != "":
+ if (LooseVersion(self.zabbix_version) >= LooseVersion("6.4")):
+ headers["Authorization"] = "Bearer " + self.auth
+ else:
+ payload["auth"] = self.auth
+
+ api_url = server_url + "/api_jsonrpc.php"
+ req = Request(
+ headers=headers,
+ timeout=timeout,
+ validate_certs=validate_certs
+ )
+ try:
+ response = req.post(api_url, data=json.dumps(payload))
+ except ValueError:
+ print("Error: Something went wrong with JSON loading.", file=sys.stderr)
+ sys.exit(1)
+ except (URLError, HTTPError) as error:
+ print(error, file=sys.stderr)
+
+ return response
+
+ def get_version(self):
+ response = self.api_request(
+ "apiinfo.version"
+ )
+ res = json.load(response)
+ self.zabbix_version = res["result"]
+
+ def login_zabbix(self):
+ auth_token = self.auth_token
+ if auth_token:
+ self.auth = auth_token
+ return
+
+ atexit.register(self.logout_zabbix)
+
+ login_user = self.zabbix_username
+ login_password = self.zabbix_password
+ response = self.api_request(
+ "user.login",
+ {
+ "username": login_user,
+ "password": login_password
+ }
+ )
+ res = json.load(response)
+ self.auth = res["result"]
+
+ def logout_zabbix(self):
+ self.api_request(
+ "user.logout",
+ []
+ )
+
+ def get_host(self, name):
+ api_query = {"output": "extend", "selectGroups": "extend", "filter": {"host": [name]}}
if self.use_host_interface:
- api_query['selectInterfaces'] = ['useip', 'ip', 'dns']
+ api_query["selectInterfaces"] = ["useip", "ip", "dns"]
if self.read_host_inventory:
- api_query['selectInventory'] = "extend"
+ api_query["selectInventory"] = "extend"
- data = {'ansible_ssh_host': name}
+ data = {"ansible_ssh_host": name}
if self.use_host_interface or self.read_host_inventory:
- try:
- hosts_data = api.host.get(api_query)[0]
- # check if zabbix api returned a interfaces element
- if 'interfaces' in hosts_data:
+ response = self.api_request("host.get", api_query)
+ response_obj = json.load(response)
+ if len(response_obj['result']) > 0:
+ host_data = response_obj['result'][0]
+ # check if zabbix api returned interfaces element
+ if "interfaces" in host_data:
# check for a interfaces list that contains at least interface
- if len(hosts_data['interfaces']) >= 1:
+ if len(host_data["interfaces"]) >= 1:
# use first interface only
- if hosts_data['interfaces'][0]['useip'] == 0:
- data['ansible_ssh_host'] = hosts_data['interfaces'][0]['dns']
+ if host_data["interfaces"][0]["useip"] == '0':
+ data["ansible_ssh_host"] = host_data["interfaces"][0]["dns"]
else:
- data['ansible_ssh_host'] = hosts_data['interfaces'][0]['ip']
- if ('inventory' in hosts_data) and (hosts_data['inventory']):
- data.update(hosts_data['inventory'])
- except IndexError:
- # Host not found in zabbix
- pass
+ data["ansible_ssh_host"] = host_data["interfaces"][0]["ip"]
+ if ("inventory" in host_data) and (host_data["inventory"]):
+ data.update(host_data["inventory"])
return data
- def get_list(self, api):
- api_query = {'output': 'extend', 'selectGroups': 'extend'}
+ def get_list(self):
+ api_query = {"output": "extend", "selectGroups": "extend"}
if self.use_host_interface:
- api_query['selectInterfaces'] = ['useip', 'ip', 'dns']
+ api_query["selectInterfaces"] = ["useip", "ip", "dns"]
if self.read_host_inventory:
- api_query['selectInventory'] = "extend"
-
- hosts_data = api.host.get(api_query)
- data = {'_meta': {'hostvars': {}}}
+ api_query["selectInventory"] = "extend"
+ response = self.api_request("host.get", api_query)
+ hosts_data = json.load(response)["result"]
+ data = {"_meta": {"hostvars": {}}}
data[self.defaultgroup] = self.hoststub()
for host in hosts_data:
- hostname = host['name']
+ hostname = host["name"]
hostvars = dict()
- data[self.defaultgroup]['hosts'].append(hostname)
+ data[self.defaultgroup]["hosts"].append(hostname)
- for group in host['groups']:
- groupname = group['name']
+ for group in host["groups"]:
+ groupname = group["name"]
if groupname not in data:
data[groupname] = self.hoststub()
- data[groupname]['hosts'].append(hostname)
+ data[groupname]["hosts"].append(hostname)
# check if zabbix api returned a interfaces element
- if 'interfaces' in host:
+ if "interfaces" in host:
# check for a interfaces list that contains at least interface
- if len(host['interfaces']) >= 1:
+ if len(host["interfaces"]) >= 1:
# use first interface only
- if host['interfaces'][0]['useip'] == 0:
- hostvars['ansible_ssh_host'] = host['interfaces'][0]['dns']
+ if host["interfaces"][0]["useip"] == 0:
+ hostvars["ansible_ssh_host"] = host["interfaces"][0]["dns"]
else:
- hostvars['ansible_ssh_host'] = host['interfaces'][0]['ip']
- if ('inventory' in host) and (host['inventory']):
- hostvars.update(host['inventory'])
- data['_meta']['hostvars'][hostname] = hostvars
+ hostvars["ansible_ssh_host"] = host["interfaces"][0]["ip"]
+ if ("inventory" in host) and (host["inventory"]):
+ hostvars.update(host["inventory"])
+ data["_meta"]["hostvars"][hostname] = hostvars
return data
def __init__(self):
- self.defaultgroup = 'group_all'
+ self.defaultgroup = "group_all"
self.zabbix_server = None
self.zabbix_username = None
self.zabbix_password = None
+ self.auth_token = None
+ self.auth = ""
self.validate_certs = True
+ self.timeout = 30
self.read_host_inventory = False
self.use_host_interface = True
+ self.zabbix_version = ""
self.meta = {}
@@ -174,20 +249,20 @@ class ZabbixInventory(object):
if self.zabbix_server and self.zabbix_username:
try:
- api = ZabbixAPI(server=self.zabbix_server, validate_certs=self.validate_certs)
- api.login(user=self.zabbix_username, password=self.zabbix_password)
+ self.get_version()
+ self.login_zabbix()
# zabbix_api tries to exit if it cannot parse what the zabbix server returned
# so we have to use SystemExit here
except (Exception, SystemExit) as e:
- print("Error: Could not login to Zabbix server. Check your zabbix.ini.", file=sys.stderr)
+ print("Error: got the exception '%s'. Check your zabbix.ini." % e, file=sys.stderr)
sys.exit(1)
if self.options.host:
- data = self.get_host(api, self.options.host)
+ data = self.get_host(self.options.host)
print(json.dumps(data, indent=2))
elif self.options.list:
- data = self.get_list(api)
+ data = self.get_list()
print(json.dumps(data, indent=2))
else:
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/setup_zabbix/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/setup_zabbix/tasks/main.yml
index ba4c30311..fd7f6a700 100644
--- a/ansible_collections/community/zabbix/tests/integration/targets/setup_zabbix/tasks/main.yml
+++ b/ansible_collections/community/zabbix/tests/integration/targets/setup_zabbix/tasks/main.yml
@@ -1,6 +1,6 @@
---
- name: get zabbix version
- uri:
+ ansible.builtin.uri:
url: "{{ zabbix_api_server_url }}/api_jsonrpc.php"
method: POST
body:
@@ -16,7 +16,7 @@
register: zabbix_version_result
- name: set zabbix_version variable
- set_fact:
+ ansible.builtin.set_fact:
zabbix_version: >-
{{ [0,1]
| map('extract', zabbix_version_result.json.result.split('.'))
@@ -27,7 +27,7 @@
ansible_connection: httpapi
# ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895
ansible_host: 127.0.0.1
- ansible_zabbix_url_path: ''
+ ansible_zabbix_url_path: ""
ansible_httpapi_port: 8080
ansible_httpapi_use_ssl: false
ansible_httpapi_validate_certs: false
@@ -36,7 +36,7 @@
- debug: var=zabbix_version
- name: check login to zabbix for Zabbix < 6.4
- uri:
+ ansible.builtin.uri:
url: "{{ zabbix_api_server_url }}/api_jsonrpc.php"
method: POST
body:
@@ -55,7 +55,7 @@
when: zabbix_version is version('6.4', '<')
- name: check login to zabbix for Zabbix >= 6.4
- uri:
+ ansible.builtin.uri:
url: "{{ zabbix_api_server_url }}/api_jsonrpc.php"
method: POST
body:
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_action/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_action/tasks/main.yml
index 6893dfd56..446f7cd3b 100644
--- a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_action/tasks/main.yml
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_action/tasks/main.yml
@@ -1,13 +1,6 @@
---
-- name: test - do not run tests for Zabbix 3.0
- meta: end_play
- when: zabbix_version is version('3.0', '=')
-
- name: test - prepare example template for zabbix_action module
- zabbix_template:
- server_url: "{{ zabbix_api_server_url }} "
- login_user: "{{ zabbix_api_login_user }}"
- login_password: "{{ zabbix_api_login_pass }}"
+ community.zabbix.zabbix_template:
template_name: ExampleTemplateForActionModule
template_groups:
- Templates
@@ -15,10 +8,7 @@
register: zbxaction_prep_template
- name: test - prepare example mediatype for zabbix_action module
- zabbix_mediatype:
- server_url: "{{ zabbix_api_server_url }} "
- login_user: "{{ zabbix_api_login_user }}"
- login_password: "{{ zabbix_api_login_pass }}"
+ community.zabbix.zabbix_mediatype:
name: ExampleMediaTypeForActionModule
smtp_email: zabbix@example.com
type: email
@@ -32,223 +22,139 @@
status: enabled
name: ExampleTriggerAction
event_source: trigger
+ notify_if_canceled: true
esc_period: 60
conditions:
- type: trigger_severity
- operator: '>='
+ operator: ">="
value: Information
operations:
- type: send_message
subject: ExampleSubject
- message: ExampleMessage
+ op_message: ExampleMessage
media_type: ExampleMediaTypeForActionModule
send_to_users:
- Admin
block:
- - name: test - create new action
- zabbix_action:
- register: zbxaction_new
+ - name: test - create new action
+ community.zabbix.zabbix_action:
+ register: zbxaction_new
- - assert:
- that: zbxaction_new.changed is sameas True
+ - ansible.builtin.assert:
+ that: zbxaction_new.changed is sameas True
- - name: test - create new action (again)
- zabbix_action:
- register: zbxaction_new
+ - name: test - create new action (again)
+ community.zabbix.zabbix_action:
+ register: zbxaction_new
- - assert:
- that: zbxaction_new.changed is sameas False
+ - ansible.builtin.assert:
+ that: zbxaction_new.changed is sameas False
- - when: zabbix_version is version('3.4', '>=')
- block:
- name: test - update action with esc_period as string
- zabbix_action:
+ community.zabbix.zabbix_action:
esc_period: 2m
register: zbxaction_escperiod_str
- - assert:
+ - ansible.builtin.assert:
that: zbxaction_escperiod_str.changed is sameas True
- name: test - update action with esc_period as string (again)
- zabbix_action:
+ community.zabbix.zabbix_action:
esc_period: 2m
register: zbxaction_escperiod_str
- - assert:
+ - ansible.builtin.assert:
that: zbxaction_escperiod_str.changed is sameas False
- name: test - update action with esc_period as macro
- zabbix_action:
- esc_period: '{$MYMACRO}'
+ community.zabbix.zabbix_action:
+ esc_period: "{$MYMACRO}"
register: zbxaction_escperiod_macro
- - assert:
+ - ansible.builtin.assert:
that: zbxaction_escperiod_macro.changed is sameas True
- name: test - update action with esc_period as macro (again)
- zabbix_action:
- esc_period: '{$MYMACRO}'
+ community.zabbix.zabbix_action:
+ esc_period: "{$MYMACRO}"
register: zbxaction_escperiod_macro
- - assert:
+ - ansible.builtin.assert:
that: zbxaction_escperiod_macro.changed is sameas False
- - name: test - update action with esc_period
- zabbix_action:
- esc_period: 120
- register: zbxaction_escperiod
-
- - assert:
- that: zbxaction_escperiod.changed is sameas True
-
- - name: test - update action with esc_period (again)
- zabbix_action:
- esc_period: 120
- register: zbxaction_escperiod
-
- - assert:
- that: zbxaction_escperiod.changed is sameas False
-
- - name: test - update action with pause_in_maintenance
- zabbix_action:
- esc_period: 120
- pause_in_maintenance: false
- register: zbxaction_maintpause
-
- - assert:
- that: zbxaction_maintpause.changed is sameas True
-
- - name: test - update action with pause_in_maintenance (again)
- zabbix_action:
- esc_period: 120
- pause_in_maintenance: false
- register: zbxaction_maintpause
-
- - assert:
- that: zbxaction_maintpause.changed is sameas False
-
- - name: test - reset action to default
- zabbix_action:
- register: zbxaction_reset
-
- - assert:
- that: zbxaction_reset.changed is sameas True
-
- - when: zabbix_version is version('5.0', '<')
- block:
- - name: test - update action with default_subject and default_message
- zabbix_action:
- default_subject: Example default subject
- default_message: Example default message
- register: zbxaction_def_msgsubj
-
- - assert:
- that: zbxaction_def_msgsubj.changed is sameas True
-
- - name: test - update action with default_subject and default_message (again)
- zabbix_action:
- default_subject: Example default subject
- default_message: Example default message
- register: zbxaction_def_msgsubj
-
- - assert:
- that: zbxaction_def_msgsubj.changed is sameas False
-
- - when:
- - zabbix_version is version('3.2', '>=')
- - zabbix_version is version('5.0', '<')
- block:
- - name: test - update action with recovery_default_subject and recovery_default_message
- zabbix_action:
- default_subject: Example default subject
- default_message: Example default message
- recovery_default_subject: Example recovery subject
- recovery_default_message: Example recovery message
- register: zbxaction_rec_msgsubj
-
- - assert:
- that: zbxaction_rec_msgsubj.changed is sameas True
-
- - name: test - update action with recovery_default_subject and recovery_default_message (again)
- zabbix_action:
- default_subject: Example default subject
- default_message: Example default message
- recovery_default_subject: Example recovery subject
- recovery_default_message: Example recovery message
- register: zbxaction_rec_msgsubj
-
- - assert:
- that: zbxaction_rec_msgsubj.changed is sameas False
-
- - when:
- - zabbix_version is version('3.4', '>=')
- - zabbix_version is version('5.0', '<')
- block:
- - name: test - update action with acknowledge_default_subject and acknowledge_default_message
- zabbix_action:
- default_subject: Example default subject
- default_message: Example default message
- recovery_default_subject: Example recovery subject
- recovery_default_message: Example recovery message
- acknowledge_default_subject: Example acknowledge subject
- acknowledge_default_message: Example acknowledge message
- register: zbxaction_ack_msgsubj
-
- - assert:
- that: zbxaction_ack_msgsubj.changed is sameas True
-
- - name: test - update action with acknowledge_default_subject and acknowledge_default_message (again)
- zabbix_action:
- default_subject: Example default subject
- default_message: Example default message
- recovery_default_subject: Example recovery subject
- recovery_default_message: Example recovery message
- acknowledge_default_subject: Example acknowledge subject
- acknowledge_default_message: Example acknowledge message
- register: zbxaction_ack_msgsubj
-
- - assert:
- that: zbxaction_ack_msgsubj.changed is sameas False
+ - name: test - update action with esc_period
+ community.zabbix.zabbix_action:
+ esc_period: 120
+ register: zbxaction_escperiod
+
+ - ansible.builtin.assert:
+ that: zbxaction_escperiod.changed is sameas True
+
+ - name: test - update action with esc_period (again)
+ community.zabbix.zabbix_action:
+ esc_period: 120
+ register: zbxaction_escperiod
+
+ - ansible.builtin.assert:
+ that: zbxaction_escperiod.changed is sameas False
+
+ - name: test - update action with pause_in_maintenance
+ community.zabbix.zabbix_action:
+ esc_period: 120
+ pause_in_maintenance: false
+ register: zbxaction_maintpause
+
+ - ansible.builtin.assert:
+ that: zbxaction_maintpause.changed is sameas True
+
+ - name: test - update action with pause_in_maintenance (again)
+ community.zabbix.zabbix_action:
+ esc_period: 120
+ pause_in_maintenance: false
+ register: zbxaction_maintpause
+
+ - ansible.builtin.assert:
+ that: zbxaction_maintpause.changed is sameas False
- name: test - reset action to default
- zabbix_action:
+ community.zabbix.zabbix_action:
register: zbxaction_reset
- - assert:
+ - ansible.builtin.assert:
that: zbxaction_reset.changed is sameas True
- - name: test - disable action
- zabbix_action:
- status: disabled
- register: zbxaction_disable
+ - name: test - disable action
+ community.zabbix.zabbix_action:
+ status: disabled
+ register: zbxaction_disable
- - assert:
- that: zbxaction_disable.changed is sameas True
+ - ansible.builtin.assert:
+ that: zbxaction_disable.changed is sameas True
- - name: test - disable action (again)
- zabbix_action:
- status: disabled
- register: zbxaction_disable
+ - name: test - disable action (again)
+ community.zabbix.zabbix_action:
+ status: disabled
+ register: zbxaction_disable
- - assert:
- that: zbxaction_disable.changed is sameas False
+ - ansible.builtin.assert:
+ that: zbxaction_disable.changed is sameas False
- - name: test - delete action
- zabbix_action:
- state: absent
- register: zbxaction_delete
+ - name: test - delete action
+ community.zabbix.zabbix_action:
+ state: absent
+ register: zbxaction_delete
- - assert:
- that: zbxaction_delete.changed is sameas True
+ - ansible.builtin.assert:
+ that: zbxaction_delete.changed is sameas True
- - name: test - delete action (again)
- zabbix_action:
- state: absent
- register: zbxaction_delete
+ - name: test - delete action (again)
+ community.zabbix.zabbix_action:
+ state: absent
+ register: zbxaction_delete
- - assert:
- that: zbxaction_delete.changed is sameas False
+ - ansible.builtin.assert:
+ that: zbxaction_delete.changed is sameas False
- name: test - trigger actions with conditions
module_defaults:
@@ -257,244 +163,245 @@
status: enabled
name: ExampleTriggerActionConditions
event_source: trigger
+ notify_if_canceled: true
esc_period: 60
operations:
- type: send_message
subject: ExampleSubject
- message: ExampleMessage
+ op_message: ExampleMessage
media_type: ExampleMediaTypeForActionModule
send_to_users:
- Admin
block:
- - name: test - create new action with multiple conditions
- zabbix_action:
- conditions:
- - type: host_group
- operator: '='
- value: Linux servers
- - type: trigger_severity
- operator: '>='
- value: Average
- - type: event_tag_value
- value: MyTag
- operator: '='
- value2: MyTagValue
- - type: time_period
- operator: not in
- value: 6-7,00:00-24:00
- register: zbxaction_conditions
-
- - assert:
- that: zbxaction_conditions.changed is sameas True
-
- - name: test - create new action with multiple conditions (again)
- zabbix_action:
- conditions:
- - type: host_group
- operator: '='
- value: Linux servers
- - type: trigger_severity
- operator: '>='
- value: Average
- - type: event_tag_value
- value: MyTag
- operator: '='
- value2: MyTagValue
- - type: time_period
- operator: not in
- value: 6-7,00:00-24:00
- register: zbxaction_conditions
-
- - assert:
- that: zbxaction_conditions.changed is sameas False
-
- - name: test - create new action with multiple conditions (reorder)
- zabbix_action:
- conditions:
- - type: host_group
- operator: '='
- value: Linux servers
- - type: event_tag_value
- value: MyTag
- operator: '='
- value2: MyTagValue
- - type: trigger_severity
- operator: '>='
- value: Average
- - type: time_period
- operator: not in
- value: 6-7,00:00-24:00
- register: zbxaction_conditions_reorder
-
- - assert:
- that: zbxaction_conditions_reorder.changed is sameas False
-
- - name: test - update action with multiple conditions by removing one condition
- zabbix_action:
- conditions:
- - type: host_group
- operator: '='
- value: Linux servers
- - type: event_tag_value
- value: MyTag
- operator: '='
- value2: MyTagValue
- - type: trigger_severity
- operator: '>='
- value: Average
- register: zbxaction_conditions_delone
-
- - assert:
- that: zbxaction_conditions_delone.changed is sameas True
-
- - name: test - update action with multiple conditions by changing operators
- zabbix_action:
- conditions:
- - type: host_group
- operator: '<>'
- value: Linux servers
- - type: event_tag_value
- value: MyTag
- operator: '<>'
- value2: MyTagValue
- - type: trigger_severity
- operator: '<='
- value: Average
- register: zbxaction_conditions_operators
-
- - assert:
- that: zbxaction_conditions_operators.changed is sameas True
-
- - name: test - update action with multiple conditions with operator aliases
- zabbix_action:
- conditions:
- - type: host_group
- operator: does not equal
- value: Linux servers
- - type: event_tag_value
- value: MyTag
- operator: contains
- value2: MyTagValue
- - type: trigger_severity
- operator: is less than or equals
- value: Average
- register: zbxaction_conditions_operator_aliases
-
- - assert:
- that: zbxaction_conditions_operator_aliases.changed is sameas True
-
- - name: test - update action with multiple conditions and evaltype
- zabbix_action:
- conditions:
- - type: host_group
- operator: '<>'
- value: Linux servers
- - type: event_tag_value
- value: MyTag
- operator: '<>'
- value2: MyTagValue
- - type: trigger_severity
- operator: '<='
- value: Average
- eval_type: and
- register: zbxaction_conditions_eval
-
- - assert:
- that: zbxaction_conditions_eval.changed is sameas True
-
- - name: test - update action with multiple conditions and evaltype (again)
- zabbix_action:
- conditions:
- - type: host_group
- operator: '<>'
- value: Linux servers
- - type: event_tag_value
- value: MyTag
- operator: '<>'
- value2: MyTagValue
- - type: trigger_severity
- operator: '<='
- value: Average
- eval_type: and
- register: zbxaction_conditions_eval
-
- - assert:
- that: zbxaction_conditions_eval.changed is sameas False
-
- - name: test - update action with reduced conditions and formula
- zabbix_action:
- conditions:
- - type: host_group
- operator: '='
- value: Linux servers
- formulaid: A
- - type: trigger_severity
- operator: '>='
- value: Average
- formulaid: B
- - type: event_tag_value
- value: MyTag
- operator: '<>'
- value2: MyTagValue
- formulaid: C
- formula: A and (B or C)
- register: zbxaction_conditions_formula
-
- - assert:
- that: zbxaction_conditions_formula.changed is sameas True
-
- - name: test - update formula used in action with reduced conditions
- zabbix_action:
- conditions:
- - type: host_group
- operator: '='
- value: Linux servers
- formulaid: A
- - type: trigger_severity
- operator: '>='
- value: Average
- formulaid: B
- - type: event_tag_value
- value: MyTag
- operator: '<>'
- value2: MyTagValue
- formulaid: C
- formula: (A or B) or C
- register: zbxaction_conditions_formula
-
- - assert:
- that: zbxaction_conditions_formula.changed is sameas True
-
- - name: test - update formula used in action with reduced conditions (again)
- zabbix_action:
- conditions:
- - type: host_group
- operator: '='
- value: Linux servers
- formulaid: A
- - type: trigger_severity
- operator: '>='
- value: Average
- formulaid: B
- - type: event_tag_value
- value: MyTag
- operator: '<>'
- value2: MyTagValue
- formulaid: C
- formula: (A or B) or C
- register: zbxaction_conditions_formula
-
- - assert:
- that: zbxaction_conditions_formula.changed is sameas False
-
- - name: test - delete action
- zabbix_action:
- state: absent
- register: zbxaction_delete
-
- - assert:
- that: zbxaction_delete.changed is sameas True
+ - name: test - create new action with multiple conditions
+ community.zabbix.zabbix_action:
+ conditions:
+ - type: host_group
+ operator: "="
+ value: Linux servers
+ - type: trigger_severity
+ operator: ">="
+ value: Average
+ - type: event_tag_value
+ value: MyTag
+ operator: "="
+ value2: MyTagValue
+ - type: time_period
+ operator: not in
+ value: 6-7,00:00-24:00
+ register: zbxaction_conditions
+
+ - ansible.builtin.assert:
+ that: zbxaction_conditions.changed is sameas True
+
+ - name: test - create new action with multiple conditions (again)
+ community.zabbix.zabbix_action:
+ conditions:
+ - type: host_group
+ operator: "="
+ value: Linux servers
+ - type: trigger_severity
+ operator: ">="
+ value: Average
+ - type: event_tag_value
+ value: MyTag
+ operator: "="
+ value2: MyTagValue
+ - type: time_period
+ operator: not in
+ value: 6-7,00:00-24:00
+ register: zbxaction_conditions
+
+ - ansible.builtin.assert:
+ that: zbxaction_conditions.changed is sameas False
+
+ - name: test - create new action with multiple conditions (reorder)
+ community.zabbix.zabbix_action:
+ conditions:
+ - type: host_group
+ operator: "="
+ value: Linux servers
+ - type: event_tag_value
+ value: MyTag
+ operator: "="
+ value2: MyTagValue
+ - type: trigger_severity
+ operator: ">="
+ value: Average
+ - type: time_period
+ operator: not in
+ value: 6-7,00:00-24:00
+ register: zbxaction_conditions_reorder
+
+ - ansible.builtin.assert:
+ that: zbxaction_conditions_reorder.changed is sameas False
+
+ - name: test - update action with multiple conditions by removing one condition
+ community.zabbix.zabbix_action:
+ conditions:
+ - type: host_group
+ operator: "="
+ value: Linux servers
+ - type: event_tag_value
+ value: MyTag
+ operator: "="
+ value2: MyTagValue
+ - type: trigger_severity
+ operator: ">="
+ value: Average
+ register: zbxaction_conditions_delone
+
+ - ansible.builtin.assert:
+ that: zbxaction_conditions_delone.changed is sameas True
+
+ - name: test - update action with multiple conditions by changing operators
+ community.zabbix.zabbix_action:
+ conditions:
+ - type: host_group
+ operator: "<>"
+ value: Linux servers
+ - type: event_tag_value
+ value: MyTag
+ operator: "<>"
+ value2: MyTagValue
+ - type: trigger_severity
+ operator: "<="
+ value: Average
+ register: zbxaction_conditions_operators
+
+ - ansible.builtin.assert:
+ that: zbxaction_conditions_operators.changed is sameas True
+
+ - name: test - update action with multiple conditions with operator aliases
+ community.zabbix.zabbix_action:
+ conditions:
+ - type: host_group
+ operator: does not equal
+ value: Linux servers
+ - type: event_tag_value
+ value: MyTag
+ operator: contains
+ value2: MyTagValue
+ - type: trigger_severity
+ operator: is less than or equals
+ value: Average
+ register: zbxaction_conditions_operator_aliases
+
+ - ansible.builtin.assert:
+ that: zbxaction_conditions_operator_aliases.changed is sameas True
+
+ - name: test - update action with multiple conditions and evaltype
+ community.zabbix.zabbix_action:
+ conditions:
+ - type: host_group
+ operator: "<>"
+ value: Linux servers
+ - type: event_tag_value
+ value: MyTag
+ operator: "<>"
+ value2: MyTagValue
+ - type: trigger_severity
+ operator: "<="
+ value: Average
+ eval_type: and
+ register: zbxaction_conditions_eval
+
+ - ansible.builtin.assert:
+ that: zbxaction_conditions_eval.changed is sameas True
+
+ - name: test - update action with multiple conditions and evaltype (again)
+ community.zabbix.zabbix_action:
+ conditions:
+ - type: host_group
+ operator: "<>"
+ value: Linux servers
+ - type: event_tag_value
+ value: MyTag
+ operator: "<>"
+ value2: MyTagValue
+ - type: trigger_severity
+ operator: "<="
+ value: Average
+ eval_type: and
+ register: zbxaction_conditions_eval
+
+ - ansible.builtin.assert:
+ that: zbxaction_conditions_eval.changed is sameas False
+
+ - name: test - update action with reduced conditions and formula
+ community.zabbix.zabbix_action:
+ conditions:
+ - type: host_group
+ operator: "="
+ value: Linux servers
+ formulaid: A
+ - type: trigger_severity
+ operator: ">="
+ value: Average
+ formulaid: B
+ - type: event_tag_value
+ value: MyTag
+ operator: "<>"
+ value2: MyTagValue
+ formulaid: C
+ formula: A and (B or C)
+ register: zbxaction_conditions_formula
+
+ - ansible.builtin.assert:
+ that: zbxaction_conditions_formula.changed is sameas True
+
+ - name: test - update formula used in action with reduced conditions
+ community.zabbix.zabbix_action:
+ conditions:
+ - type: host_group
+ operator: "="
+ value: Linux servers
+ formulaid: A
+ - type: trigger_severity
+ operator: ">="
+ value: Average
+ formulaid: B
+ - type: event_tag_value
+ value: MyTag
+ operator: "<>"
+ value2: MyTagValue
+ formulaid: C
+ formula: (A or B) or C
+ register: zbxaction_conditions_formula
+
+ - ansible.builtin.assert:
+ that: zbxaction_conditions_formula.changed is sameas True
+
+ - name: test - update formula used in action with reduced conditions (again)
+ community.zabbix.zabbix_action:
+ conditions:
+ - type: host_group
+ operator: "="
+ value: Linux servers
+ formulaid: A
+ - type: trigger_severity
+ operator: ">="
+ value: Average
+ formulaid: B
+ - type: event_tag_value
+ value: MyTag
+ operator: "<>"
+ value2: MyTagValue
+ formulaid: C
+ formula: (A or B) or C
+ register: zbxaction_conditions_formula
+
+ - ansible.builtin.assert:
+ that: zbxaction_conditions_formula.changed is sameas False
+
+ - name: test - delete action
+ community.zabbix.zabbix_action:
+ state: absent
+ register: zbxaction_delete
+
+ - ansible.builtin.assert:
+ that: zbxaction_delete.changed is sameas True
- name: test - trigger actions with message operations
module_defaults:
@@ -503,234 +410,139 @@
status: enabled
name: ExampleTriggerActionOperations
event_source: trigger
+ notify_if_canceled: true
esc_period: 60
conditions:
- type: trigger_severity
- operator: '>='
+ operator: ">="
value: Average
block:
- - name: test - create new action with send_message operations
- zabbix_action:
- operations:
- - type: send_message
- send_to_users:
- - Admin
- subject: test_subject
- message: test_message
- media_type: ExampleMediaTypeForActionModule
- operation_condition: not_acknowledged
- esc_step_from: 1
- esc_step_to: 2
- - type: send_message
- send_to_users:
- - Admin
- subject: test_subject
- message: test_message
- media_type: SMS
- operation_condition: not_acknowledged
- esc_step_from: 2
- esc_step_to: 0
- esc_period: 300
- register: zbxaction_ops
-
- - assert:
- that: zbxaction_ops.changed is sameas True
-
- - name: test - create new action with send_message operations (again)
- zabbix_action:
- operations:
- - type: send_message
- send_to_users:
- - Admin
- subject: test_subject
- message: test_message
- media_type: ExampleMediaTypeForActionModule
- operation_condition: not_acknowledged
- esc_step_from: 1
- esc_step_to: 2
- - type: send_message
- send_to_users:
- - Admin
- subject: test_subject
- message: test_message
- media_type: SMS
- operation_condition: not_acknowledged
- esc_step_from: 2
- esc_step_to: 0
- esc_period: 300
- register: zbxaction_ops
-
- - assert:
- that: zbxaction_ops.changed is sameas False
-
- - name: test - delete action
- zabbix_action:
- state: absent
- register: zbxaction_delete
-
- - assert:
- that: zbxaction_delete.changed is sameas True
-
- - name: test - create new action with escalation steps 1-1
- zabbix_action:
- operations:
- - type: send_message
- send_to_users:
- - Admin
- media_type: ExampleMediaTypeForActionModule
- esc_step_from: 1
- esc_step_to: 1
- register: zbxaction_esc11
+ - name: test - create new action with send_message operations
+ community.zabbix.zabbix_action:
+ operations:
+ - type: send_message
+ send_to_users:
+ - Admin
+ subject: test_subject
+ op_message: test_message
+ media_type: ExampleMediaTypeForActionModule
+ operation_condition: not_acknowledged
+ esc_step_from: 1
+ esc_step_to: 2
+ - type: send_message
+ send_to_users:
+ - Admin
+ subject: test_subject
+ op_message: test_message
+ media_type: SMS
+ operation_condition: not_acknowledged
+ esc_step_from: 2
+ esc_step_to: 0
+ esc_period: 300
+ register: zbxaction_ops
+
+ - ansible.builtin.assert:
+ that: zbxaction_ops.changed is sameas True
+
+ - name: test - create new action with send_message operations (again)
+ community.zabbix.zabbix_action:
+ operations:
+ - type: send_message
+ send_to_users:
+ - Admin
+ subject: test_subject
+ op_message: test_message
+ media_type: ExampleMediaTypeForActionModule
+ operation_condition: not_acknowledged
+ esc_step_from: 1
+ esc_step_to: 2
+ - type: send_message
+ send_to_users:
+ - Admin
+ subject: test_subject
+ op_message: test_message
+ media_type: SMS
+ operation_condition: not_acknowledged
+ esc_step_from: 2
+ esc_step_to: 0
+ esc_period: 300
+ register: zbxaction_ops
+
+ - ansible.builtin.assert:
+ that: zbxaction_ops.changed is sameas False
+
+ - name: test - delete action
+ community.zabbix.zabbix_action:
+ state: absent
+ register: zbxaction_delete
+
+ - ansible.builtin.assert:
+ that: zbxaction_delete.changed is sameas True
+
+ - name: test - create new action with escalation steps 1-1
+ community.zabbix.zabbix_action:
+ operations:
+ - type: send_message
+ send_to_users:
+ - Admin
+ media_type: ExampleMediaTypeForActionModule
+ esc_step_from: 1
+ esc_step_to: 1
+ register: zbxaction_esc11
- - assert:
- that: zbxaction_esc11.changed is sameas True
+ - ansible.builtin.assert:
+ that: zbxaction_esc11.changed is sameas True
- - name: test - create new action with escalation steps 1-1 (again)
- zabbix_action:
- operations:
- - type: send_message
- send_to_users:
- - Admin
- media_type: ExampleMediaTypeForActionModule
- esc_step_from: 1
- esc_step_to: 1
- register: zbxaction_esc11_again
+ - name: test - create new action with escalation steps 1-1 (again)
+ community.zabbix.zabbix_action:
+ operations:
+ - type: send_message
+ send_to_users:
+ - Admin
+ media_type: ExampleMediaTypeForActionModule
+ esc_step_from: 1
+ esc_step_to: 1
+ register: zbxaction_esc11_again
- - assert:
- that: zbxaction_esc11_again.changed is sameas False
+ - ansible.builtin.assert:
+ that: zbxaction_esc11_again.changed is sameas False
+ - name: test - update action with escalation steps 2-2
+ community.zabbix.zabbix_action:
+ operations:
+ - type: send_message
+ send_to_users:
+ - Admin
+ media_type: ExampleMediaTypeForActionModule
+ esc_step_from: 2
+ esc_step_to: 2
+ register: zbxaction_esc22
- - name: test - update action with escalation steps 2-2
- zabbix_action:
- operations:
- - type: send_message
- send_to_users:
- - Admin
- media_type: ExampleMediaTypeForActionModule
- esc_step_from: 2
- esc_step_to: 2
- register: zbxaction_esc22
+ - ansible.builtin.assert:
+ that: zbxaction_esc22.changed is sameas True
- - assert:
- that: zbxaction_esc22.changed is sameas True
+ - name: test - create new action with escalation steps 2-2 (again)
+ community.zabbix.zabbix_action:
+ operations:
+ - type: send_message
+ send_to_users:
+ - Admin
+ media_type: ExampleMediaTypeForActionModule
+ esc_step_from: 2
+ esc_step_to: 2
+ register: zbxaction_esc22_again
- - name: test - create new action with escalation steps 2-2 (again)
- zabbix_action:
- operations:
- - type: send_message
- send_to_users:
- - Admin
- media_type: ExampleMediaTypeForActionModule
- esc_step_from: 2
- esc_step_to: 2
- register: zbxaction_esc22_again
-
- - assert:
- that: zbxaction_esc11_again.changed is sameas False
-
- - name: test - delete action
- zabbix_action:
- state: absent
- register: zbxaction_delete
-
- - assert:
- that: zbxaction_delete.changed is sameas True
-- name: test - trigger actions with remote_script operations with < Zabbix 6.0
- when: zabbix_version is version('6.0', '<')
- module_defaults:
- community.zabbix.zabbix_action:
- state: present
- status: enabled
- name: ExampleTriggerActionOperations
- event_source: trigger
- esc_period: 60
- conditions:
- - type: trigger_severity
- operator: '>='
- value: Average
+ - ansible.builtin.assert:
+ that: zbxaction_esc11_again.changed is sameas False
- block:
- - name: test - create new action with remote_command operations
- zabbix_action:
- operations:
- - type: remote_command
- command_type: custom_script
- command: /usr/local/bin/do_something.sh
- execute_on: agent
- run_on_hosts: 0
- - type: remote_command
- command_type: ssh
- command: /usr/local/bin/do_something.sh
- run_on_hosts: 0
- ssh_auth_type: password
- username: root
- password: zabbix
- - type: remote_command
- command_type: global_script
- script_name: Ping
- run_on_hosts: 0
- register: zbxaction_rmtcmd
-
- - assert:
- that: zbxaction_rmtcmd.changed is sameas True
-
- - name: test - create new action with remote_command operations (again)
- zabbix_action:
- operations:
- - type: remote_command
- command_type: custom_script
- command: /usr/local/bin/do_something.sh
- execute_on: agent
- run_on_hosts: 0
- - type: remote_command
- command_type: ssh
- command: /usr/local/bin/do_something.sh
- run_on_hosts: 0
- ssh_auth_type: password
- username: root
- password: zabbix
- - type: remote_command
- command_type: global_script
- script_name: Ping
- run_on_hosts: 0
- register: zbxaction_rmtcmd
-
- - assert:
- that: zbxaction_rmtcmd.changed is sameas False
-
- - name: test - update ssh remote_command auth in action with remote_command operations
- zabbix_action:
- operations:
- - type: remote_command
- command_type: custom_script
- command: /usr/local/bin/do_something.sh
- execute_on: agent
- run_on_hosts: 0
- - type: remote_command
- command_type: ssh
- command: /usr/local/bin/do_something.sh
- run_on_hosts: 0
- ssh_auth_type: public_key
- username: root
- ssh_privatekey_file: /etc/zabbix/.ssh/id_test
- ssh_publickey_file: /etc/zabbix/.ssh/id_test.pub
- - type: remote_command
- command_type: global_script
- script_name: Ping
- run_on_hosts: 0
- register: zbxaction_rmtcmd
-
- - assert:
- that: zbxaction_rmtcmd.changed is sameas True
-
- - name: test - delete action
- zabbix_action:
- state: absent
- register: zbxaction_delete
-
- - assert:
- that: zbxaction_delete.changed is sameas True
+ - name: test - delete action
+ community.zabbix.zabbix_action:
+ state: absent
+ register: zbxaction_delete
+
+ - ansible.builtin.assert:
+ that: zbxaction_delete.changed is sameas True
- name: test - discovery actions
module_defaults:
@@ -742,153 +554,153 @@
esc_period: 60
block:
- - name: test - create new discovery action
- zabbix_action:
- conditions:
- - type: host_IP
- operator: '='
- value: '192.168.0.1-127'
- - type: discovery_object
- operator: '='
- value: host
- - type: discovery_status
- operator: '='
- value: 'discovered'
- - type: uptime_or_downtime_duration
- operator: '>='
- value: 1800
- operations:
- - type: add_host
- - type: add_to_host_group
- host_groups:
- - Linux servers
- - type: link_to_template
- templates:
- - ExampleTemplateForActionModule
- - type: enable_host
- - type: set_host_inventory_mode
- inventory: automatic
- register: zbxaction_discovery
-
- - assert:
- that: zbxaction_discovery.changed is sameas True
-
- - name: test - create new discovery action (again)
- zabbix_action:
- conditions:
- - type: host_IP
- operator: '='
- value: '192.168.0.1-127'
- - type: discovery_object
- operator: '='
- value: host
- - type: discovery_status
- operator: '='
- value: 'discovered'
- - type: uptime_or_downtime_duration
- operator: '>='
- value: 1800
- operations:
- - type: add_host
- - type: add_to_host_group
- host_groups:
- - Linux servers
- - type: link_to_template
- templates:
- - ExampleTemplateForActionModule
- - type: enable_host
- - type: set_host_inventory_mode
- inventory: automatic
- register: zbxaction_discovery
-
- - assert:
- that: zbxaction_discovery.changed is sameas False
-
- - name: test - update discovery action conditions and operations
- zabbix_action:
- conditions:
- - type: host_IP
- operator: '='
- value: '192.168.1.1-127'
- - type: discovery_object
- operator: '='
- value: host
- - type: discovery_status
- operator: '='
- value: 'discovered'
- - type: uptime_or_downtime_duration
- operator: '>='
- value: 2200
- operations:
- - type: add_host
- - type: add_to_host_group
- host_groups:
- - Linux servers
- - Discovered hosts
- - type: link_to_template
- templates:
- - ExampleTemplateForActionModule
- - type: enable_host
- - type: send_message
- send_to_users:
- - Admin
- subject: test_subject
- message: test_message
- media_type: ExampleMediaTypeForActionModule
- operation_condition: not_acknowledged
- esc_step_from: 1
- esc_step_to: 2
- register: zbxaction_discovery_update
-
- - assert:
- that: zbxaction_discovery_update.changed is sameas True
-
- - name: test - update discovery action conditions and operations (again)
- zabbix_action:
- conditions:
- - type: host_IP
- operator: '='
- value: '192.168.1.1-127'
- - type: discovery_object
- operator: '='
- value: host
- - type: discovery_status
- operator: '='
- value: 'discovered'
- - type: uptime_or_downtime_duration
- operator: '>='
- value: 2200
- operations:
- - type: add_host
- - type: add_to_host_group
- host_groups:
- - Linux servers
- - Discovered hosts
- - type: link_to_template
- templates:
- - ExampleTemplateForActionModule
- - type: enable_host
- - type: send_message
- send_to_users:
- - Admin
- subject: test_subject
- message: test_message
- media_type: ExampleMediaTypeForActionModule
- operation_condition: not_acknowledged
- esc_step_from: 1
- esc_step_to: 2
- register: zbxaction_discovery_update
+ - name: test - create new discovery action
+ community.zabbix.zabbix_action:
+ conditions:
+ - type: host_IP
+ operator: "="
+ value: "192.168.0.1-127"
+ - type: discovery_object
+ operator: "="
+ value: host
+ - type: discovery_status
+ operator: "="
+ value: "discovered"
+ - type: uptime_or_downtime_duration
+ operator: ">="
+ value: 1800
+ operations:
+ - type: add_host
+ - type: add_to_host_group
+ host_groups:
+ - Linux servers
+ - type: link_to_template
+ templates:
+ - ExampleTemplateForActionModule
+ - type: enable_host
+ - type: set_host_inventory_mode
+ inventory: automatic
+ register: zbxaction_discovery
+
+ - ansible.builtin.assert:
+ that: zbxaction_discovery.changed is sameas True
+
+ - name: test - create new discovery action (again)
+ community.zabbix.zabbix_action:
+ conditions:
+ - type: host_IP
+ operator: "="
+ value: "192.168.0.1-127"
+ - type: discovery_object
+ operator: "="
+ value: host
+ - type: discovery_status
+ operator: "="
+ value: "discovered"
+ - type: uptime_or_downtime_duration
+ operator: ">="
+ value: 1800
+ operations:
+ - type: add_host
+ - type: add_to_host_group
+ host_groups:
+ - Linux servers
+ - type: link_to_template
+ templates:
+ - ExampleTemplateForActionModule
+ - type: enable_host
+ - type: set_host_inventory_mode
+ inventory: automatic
+ register: zbxaction_discovery
+
+ - ansible.builtin.assert:
+ that: zbxaction_discovery.changed is sameas False
+
+ - name: test - update discovery action conditions and operations
+ community.zabbix.zabbix_action:
+ conditions:
+ - type: host_IP
+ operator: "="
+ value: "192.168.1.1-127"
+ - type: discovery_object
+ operator: "="
+ value: host
+ - type: discovery_status
+ operator: "="
+ value: "discovered"
+ - type: uptime_or_downtime_duration
+ operator: ">="
+ value: 2200
+ operations:
+ - type: add_host
+ - type: add_to_host_group
+ host_groups:
+ - Linux servers
+ - Discovered hosts
+ - type: link_to_template
+ templates:
+ - ExampleTemplateForActionModule
+ - type: enable_host
+ - type: send_message
+ send_to_users:
+ - Admin
+ subject: test_subject
+ op_message: test_message
+ media_type: ExampleMediaTypeForActionModule
+ operation_condition: not_acknowledged
+ esc_step_from: 1
+ esc_step_to: 2
+ register: zbxaction_discovery_update
+
+ - ansible.builtin.assert:
+ that: zbxaction_discovery_update.changed is sameas True
+
+ - name: test - update discovery action conditions and operations (again)
+ community.zabbix.zabbix_action:
+ conditions:
+ - type: host_IP
+ operator: "="
+ value: "192.168.1.1-127"
+ - type: discovery_object
+ operator: "="
+ value: host
+ - type: discovery_status
+ operator: "="
+ value: "discovered"
+ - type: uptime_or_downtime_duration
+ operator: ">="
+ value: 2200
+ operations:
+ - type: add_host
+ - type: add_to_host_group
+ host_groups:
+ - Linux servers
+ - Discovered hosts
+ - type: link_to_template
+ templates:
+ - ExampleTemplateForActionModule
+ - type: enable_host
+ - type: send_message
+ send_to_users:
+ - Admin
+ subject: test_subject
+ op_message: test_message
+ media_type: ExampleMediaTypeForActionModule
+ operation_condition: not_acknowledged
+ esc_step_from: 1
+ esc_step_to: 2
+ register: zbxaction_discovery_update
- - assert:
- that: zbxaction_discovery_update.changed is sameas False
+ - ansible.builtin.assert:
+ that: zbxaction_discovery_update.changed is sameas False
- - name: test - delete action
- zabbix_action:
- state: absent
- register: zbxaction_delete
+ - name: test - delete action
+ community.zabbix.zabbix_action:
+ state: absent
+ register: zbxaction_delete
- - assert:
- that: zbxaction_delete.changed is sameas True
+ - ansible.builtin.assert:
+ that: zbxaction_delete.changed is sameas True
- name: test - auto registration actions
module_defaults:
@@ -900,83 +712,83 @@
esc_period: 60
block:
- - name: test - create new auto registration action
- zabbix_action:
- conditions:
- - type: host_name
- operator: like
- value: zabbix
- - type: host_metadata
- operator: not like
- value: somemetadata
- operations:
- - type: add_host
- register: zbxaction_autoreg
-
- - assert:
- that: zbxaction_autoreg.changed is sameas True
-
- - name: test - create new auto registration action (again)
- zabbix_action:
- conditions:
- - type: host_name
- operator: like
- value: zabbix
- - type: host_metadata
- operator: not like
- value: somemetadata
- operations:
- - type: add_host
- register: zbxaction_autoreg
-
- - assert:
- that: zbxaction_autoreg.changed is sameas False
-
- - name: test - update auto registration action
- zabbix_action:
- conditions:
- - type: host_name
- operator: like
- value: zabbix
- - type: host_metadata
- operator: not like
- value: somemetadata
- - type: host_metadata
- operator: like
- value: somemetadata2
- operations:
- - type: add_host
- register: zbxaction_autoreg_update
-
- - assert:
- that: zbxaction_autoreg_update.changed is sameas True
-
- - name: test - update auto registration action (again)
- zabbix_action:
- conditions:
- - type: host_name
- operator: like
- value: zabbix
- - type: host_metadata
- operator: not like
- value: somemetadata
- - type: host_metadata
- operator: like
- value: somemetadata2
- operations:
- - type: add_host
- register: zbxaction_autoreg_update
-
- - assert:
- that: zbxaction_autoreg_update.changed is sameas False
-
- - name: test - delete action
- zabbix_action:
- state: absent
- register: zbxaction_delete
-
- - assert:
- that: zbxaction_delete.changed is sameas True
+ - name: test - create new auto registration action
+ community.zabbix.zabbix_action:
+ conditions:
+ - type: host_name
+ operator: like
+ value: zabbix
+ - type: host_metadata
+ operator: not like
+ value: somemetadata
+ operations:
+ - type: add_host
+ register: zbxaction_autoreg
+
+ - ansible.builtin.assert:
+ that: zbxaction_autoreg.changed is sameas True
+
+ - name: test - create new auto registration action (again)
+ community.zabbix.zabbix_action:
+ conditions:
+ - type: host_name
+ operator: like
+ value: zabbix
+ - type: host_metadata
+ operator: not like
+ value: somemetadata
+ operations:
+ - type: add_host
+ register: zbxaction_autoreg
+
+ - ansible.builtin.assert:
+ that: zbxaction_autoreg.changed is sameas False
+
+ - name: test - update auto registration action
+ community.zabbix.zabbix_action:
+ conditions:
+ - type: host_name
+ operator: like
+ value: zabbix
+ - type: host_metadata
+ operator: not like
+ value: somemetadata
+ - type: host_metadata
+ operator: like
+ value: somemetadata2
+ operations:
+ - type: add_host
+ register: zbxaction_autoreg_update
+
+ - ansible.builtin.assert:
+ that: zbxaction_autoreg_update.changed is sameas True
+
+ - name: test - update auto registration action (again)
+ community.zabbix.zabbix_action:
+ conditions:
+ - type: host_name
+ operator: like
+ value: zabbix
+ - type: host_metadata
+ operator: not like
+ value: somemetadata
+ - type: host_metadata
+ operator: like
+ value: somemetadata2
+ operations:
+ - type: add_host
+ register: zbxaction_autoreg_update
+
+ - ansible.builtin.assert:
+ that: zbxaction_autoreg_update.changed is sameas False
+
+ - name: test - delete action
+ community.zabbix.zabbix_action:
+ state: absent
+ register: zbxaction_delete
+
+ - ansible.builtin.assert:
+ that: zbxaction_delete.changed is sameas True
- name: test - internal actions
module_defaults:
@@ -991,387 +803,224 @@
send_to_users:
- Admin
subject: test_subject
- message: test_message
- media_type: ExampleMediaTypeForActionModule
-
- block:
- - name: test - create new internal action
- zabbix_action:
- conditions:
- - type: host_template
- operator: '='
- value: ExampleTemplateForActionModule
- - type: event_type
- operator: '='
- value: item in not supported state
- register: zbxaction_internal
-
- - assert:
- that: zbxaction_internal.changed is sameas True
-
- - name: test - create new internal action (again)
- zabbix_action:
- conditions:
- - type: host_template
- operator: '='
- value: ExampleTemplateForActionModule
- - type: event_type
- operator: '='
- value: item in not supported state
- register: zbxaction_internal
-
- - assert:
- that: zbxaction_internal.changed is sameas False
-
- - name: test - update internal action conditions
- zabbix_action:
- conditions:
- - type: host_template
- operator: '='
- value: ExampleTemplateForActionModule
- - type: event_type
- operator: '='
- value: item in not supported state
- - type: event_type
- operator: '='
- value: trigger in unknown state
- register: zbxaction_internal_update
-
- - assert:
- that: zbxaction_internal_update.changed is sameas True
-
- - name: test - update internal action conditions (again)
- zabbix_action:
- conditions:
- - type: host_template
- operator: '='
- value: ExampleTemplateForActionModule
- - type: event_type
- operator: '='
- value: item in not supported state
- - type: event_type
- operator: '='
- value: trigger in unknown state
- register: zbxaction_internal_update
-
- - assert:
- that: zbxaction_internal_update.changed is sameas False
-
- - name: test - delete action
- zabbix_action:
- state: absent
- register: zbxaction_delete
-
- - assert:
- that: zbxaction_delete.changed is sameas True
-
-- name: test - actions with recovery and acknowledge operations with < Zabbix 6.0
- when:
- - zabbix_version is version('3.4', '>=')
- - zabbix_version is version('6.0', '<')
- module_defaults:
- community.zabbix.zabbix_action:
- state: present
- status: enabled
- name: ExampleTriggerActionRecAckOps
- event_source: trigger
- esc_period: 60
- conditions:
- - type: trigger_severity
- operator: '>='
- value: Information
- operations:
- - type: send_message
- subject: ExampleSubject
- message: ExampleMessage
+ op_message: test_message
media_type: ExampleMediaTypeForActionModule
- send_to_users:
- - Admin
block:
- - name: test - create new action with recovery and acknowledge operations
- zabbix_action:
- recovery_operations:
- - type: send_message
- subject: ExampleSubject
- message: ExampleMessage
- media_type: ExampleMediaTypeForActionModule
- send_to_users:
- - Admin
- - type: remote_command
- command_type: custom_script
- command: /usr/local/bin/do_something.sh
- execute_on: agent
- run_on_hosts: 0
- - type: remote_command
- command_type: ssh
- command: /usr/local/bin/do_something.sh
- run_on_hosts: 0
- ssh_auth_type: password
- username: root
- password: zabbix
- - type: notify_all_involved
- subject: RecoverySubject
- message: RecoveryMessage
- acknowledge_operations:
- - type: send_message
- subject: ExampleSubject
- message: ExampleMessage
- media_type: ExampleMediaTypeForActionModule
- send_to_users:
- - Admin
- - type: remote_command
- command_type: ssh
- command: /usr/local/bin/do_something.sh
- run_on_hosts: 0
- ssh_auth_type: public_key
- username: root
- ssh_privatekey_file: /etc/zabbix/.ssh/id_test
- ssh_publickey_file: /etc/zabbix/.ssh/id_test.pub
- - type: remote_command
- command_type: global_script
- script_name: Ping
- run_on_hosts: 0
- - type: notify_all_involved
- subject: RecoverySubject
- message: RecoveryMessage
- media_type: ExampleMediaTypeForActionModule
- register: zbxaction_recack_new
-
- - assert:
- that: zbxaction_recack_new.changed is sameas True
-
- - name: test - create new action with recovery and acknowledge operations (again)
- zabbix_action:
- recovery_operations:
- - type: send_message
- subject: ExampleSubject
- message: ExampleMessage
- media_type: ExampleMediaTypeForActionModule
- send_to_users:
- - Admin
- - type: remote_command
- command_type: custom_script
- command: /usr/local/bin/do_something.sh
- execute_on: agent
- run_on_hosts: 0
- - type: remote_command
- command_type: ssh
- command: /usr/local/bin/do_something.sh
- run_on_hosts: 0
- ssh_auth_type: password
- username: root
- password: zabbix
- - type: notify_all_involved
- subject: RecoverySubject
- message: RecoveryMessage
- acknowledge_operations:
- - type: send_message
- subject: ExampleSubject
- message: ExampleMessage
- media_type: ExampleMediaTypeForActionModule
- send_to_users:
- - Admin
- - type: remote_command
- command_type: ssh
- command: /usr/local/bin/do_something.sh
- run_on_hosts: 0
- ssh_auth_type: public_key
- username: root
- ssh_privatekey_file: /etc/zabbix/.ssh/id_test
- ssh_publickey_file: /etc/zabbix/.ssh/id_test.pub
- - type: remote_command
- command_type: global_script
- script_name: Ping
- run_on_hosts: 0
- - type: notify_all_involved
- subject: RecoverySubject
- message: RecoveryMessage
- media_type: ExampleMediaTypeForActionModule
- register: zbxaction_recack_new
-
- - assert:
- that: zbxaction_recack_new.changed is sameas False
-
- - name: test - delete action
- zabbix_action:
- state: absent
- register: zbxaction_delete
-
- - assert:
- that: zbxaction_delete.changed is sameas True
-
-- name: test - actions with recovery and acknowledge operations with >= Zabbx 6.0
- when:
- - zabbix_version is version('6.0', '>=')
- module_defaults:
+ - name: test - create new internal action
+ community.zabbix.zabbix_action:
+ conditions:
+ - type: host_template
+ operator: "="
+ value: ExampleTemplateForActionModule
+ - type: event_type
+ operator: "="
+ value: item in not supported state
+ register: zbxaction_internal
+
+ - ansible.builtin.assert:
+ that: zbxaction_internal.changed is sameas True
+
+ - name: test - create new internal action (again)
+ community.zabbix.zabbix_action:
+ conditions:
+ - type: host_template
+ operator: "="
+ value: ExampleTemplateForActionModule
+ - type: event_type
+ operator: "="
+ value: item in not supported state
+ register: zbxaction_internal
+
+ - ansible.builtin.assert:
+ that: zbxaction_internal.changed is sameas False
+
+ - name: test - update internal action conditions
+ community.zabbix.zabbix_action:
+ conditions:
+ - type: host_template
+ operator: "="
+ value: ExampleTemplateForActionModule
+ - type: event_type
+ operator: "="
+ value: item in not supported state
+ - type: event_type
+ operator: "="
+ value: trigger in unknown state
+ register: zbxaction_internal_update
+
+ - ansible.builtin.assert:
+ that: zbxaction_internal_update.changed is sameas True
+
+ - name: test - update internal action conditions (again)
+ community.zabbix.zabbix_action:
+ conditions:
+ - type: host_template
+ operator: "="
+ value: ExampleTemplateForActionModule
+ - type: event_type
+ operator: "="
+ value: item in not supported state
+ - type: event_type
+ operator: "="
+ value: trigger in unknown state
+ register: zbxaction_internal_update
+
+ - ansible.builtin.assert:
+ that: zbxaction_internal_update.changed is sameas False
+
+ - name: test - delete action
+ community.zabbix.zabbix_action:
+ state: absent
+ register: zbxaction_delete
+
+ - ansible.builtin.assert:
+ that: zbxaction_delete.changed is sameas True
+
+- module_defaults:
community.zabbix.zabbix_action:
state: present
status: enabled
name: ExampleTriggerActionRecAckOps
event_source: trigger
+ notify_if_canceled: true
esc_period: 60
conditions:
- type: trigger_severity
- operator: '>='
+ operator: ">="
value: Information
operations:
- type: send_message
subject: ExampleSubject
- message: ExampleMessage
+ op_message: ExampleMessage
media_type: ExampleMediaTypeForActionModule
send_to_users:
- Admin
block:
- - name: test - create new action with recovery and acknowledge operations
- zabbix_action:
- recovery_operations:
- - type: send_message
- subject: ExampleSubject
- message: ExampleMessage
- media_type: ExampleMediaTypeForActionModule
- send_to_users:
- - Admin
- - type: notify_all_involved
- subject: RecoverySubject
- message: RecoveryMessage
- acknowledge_operations:
- - type: send_message
- subject: ExampleSubject
- message: ExampleMessage
- media_type: ExampleMediaTypeForActionModule
- send_to_users:
- - Admin
- - type: notify_all_involved
- subject: RecoverySubject
- message: RecoveryMessage
- media_type: ExampleMediaTypeForActionModule
- register: zbxaction_recack_new
-
- - assert:
- that: zbxaction_recack_new.changed is sameas True
-
- - name: test - create new action with recovery and acknowledge operations (again)
- zabbix_action:
- recovery_operations:
- - type: send_message
- subject: ExampleSubject
- message: ExampleMessage
- media_type: ExampleMediaTypeForActionModule
- send_to_users:
- - Admin
- - type: notify_all_involved
- subject: RecoverySubject
- message: RecoveryMessage
- acknowledge_operations:
- - type: send_message
- subject: ExampleSubject
- message: ExampleMessage
- media_type: ExampleMediaTypeForActionModule
- send_to_users:
- - Admin
- - type: notify_all_involved
- subject: RecoverySubject
- message: RecoveryMessage
- media_type: ExampleMediaTypeForActionModule
- register: zbxaction_recack_new
-
- - assert:
- that: zbxaction_recack_new.changed is sameas False
-
- - when: zabbix_version is version('6.4', '>=')
- block:
- - name: test - update action with pause_symptoms off
- zabbix_action:
+ - name: test - create new action with recovery and acknowledge operations
+ community.zabbix.zabbix_action:
recovery_operations:
- type: send_message
subject: ExampleSubject
- message: ExampleMessage
+ op_message: ExampleMessage
media_type: ExampleMediaTypeForActionModule
send_to_users:
- Admin
- type: notify_all_involved
subject: RecoverySubject
- message: RecoveryMessage
+ op_message: RecoveryMessage
acknowledge_operations:
- type: send_message
subject: ExampleSubject
- message: ExampleMessage
+ op_message: ExampleMessage
media_type: ExampleMediaTypeForActionModule
send_to_users:
- Admin
- type: notify_all_involved
subject: RecoverySubject
- message: RecoveryMessage
+ op_message: RecoveryMessage
media_type: ExampleMediaTypeForActionModule
- pause_symptoms: False
- register: zbxaction_pause_symptoms
+ register: zbxaction_recack_new
- - assert:
- that: zbxaction_pause_symptoms.changed is sameas True
+ - ansible.builtin.assert:
+ that: zbxaction_recack_new.changed is sameas True
- - name: test - update action with pause_symptoms off (again)
- zabbix_action:
+ - name: test - create new action with recovery and acknowledge operations (again)
+ community.zabbix.zabbix_action:
recovery_operations:
- type: send_message
subject: ExampleSubject
- message: ExampleMessage
+ op_message: ExampleMessage
media_type: ExampleMediaTypeForActionModule
send_to_users:
- Admin
- type: notify_all_involved
subject: RecoverySubject
- message: RecoveryMessage
+ op_message: RecoveryMessage
acknowledge_operations:
- type: send_message
subject: ExampleSubject
- message: ExampleMessage
+ op_message: ExampleMessage
media_type: ExampleMediaTypeForActionModule
send_to_users:
- Admin
- type: notify_all_involved
subject: RecoverySubject
- message: RecoveryMessage
+ op_message: RecoveryMessage
media_type: ExampleMediaTypeForActionModule
- pause_symptoms: False
- register: zbxaction_pause_symptoms
-
- - assert:
- that: zbxaction_pause_symptoms.changed is sameas False
-
- - name: test - delete action
- zabbix_action:
- state: absent
- register: zbxaction_delete
-
- - assert:
- that: zbxaction_delete.changed is sameas True
-
-- name: test - Output error message when user sets application to conditions with >= Zabbix 5.4
- community.zabbix.zabbix_action:
- name: ExampleApplicationAction
- event_source: trigger
- esc_period: 60
- conditions:
- - type: application
- operator: like
- value: AnsibleTest
- operations:
- - type: send_message
- subject: ExampleSubject
- message: ExampleMessage
- media_type: ExampleMediaTypeForActionModule
- send_to_users:
- - Admin
- ignore_errors: true
- register: zbxaction_application
-
-- assert:
- that:
- - zbxaction_application.failed is sameas True
- - zbxaction_application.msg == "'application' is disabled for condition type since 5.4 version."
- when: zabbix_version is version('5.4', '>=')
+ register: zbxaction_recack_new
+
+ - ansible.builtin.assert:
+ that: zbxaction_recack_new.changed is sameas False
+
+ - when: zabbix_version is version('6.4', '>=')
+ block:
+ - name: test - update action with pause_symptoms off
+ community.zabbix.zabbix_action:
+ recovery_operations:
+ - type: send_message
+ subject: ExampleSubject
+ op_message: ExampleMessage
+ media_type: ExampleMediaTypeForActionModule
+ send_to_users:
+ - Admin
+ - type: notify_all_involved
+ subject: RecoverySubject
+ op_message: RecoveryMessage
+ acknowledge_operations:
+ - type: send_message
+ subject: ExampleSubject
+ op_message: ExampleMessage
+ media_type: ExampleMediaTypeForActionModule
+ send_to_users:
+ - Admin
+ - type: notify_all_involved
+ subject: RecoverySubject
+ op_message: RecoveryMessage
+ media_type: ExampleMediaTypeForActionModule
+ pause_symptoms: False
+ register: zbxaction_pause_symptoms
+
+ - ansible.builtin.assert:
+ that: zbxaction_pause_symptoms.changed is sameas True
+
+ - name: test - update action with pause_symptoms off (again)
+ community.zabbix.zabbix_action:
+ recovery_operations:
+ - type: send_message
+ subject: ExampleSubject
+ op_message: ExampleMessage
+ media_type: ExampleMediaTypeForActionModule
+ send_to_users:
+ - Admin
+ - type: notify_all_involved
+ subject: RecoverySubject
+ op_message: RecoveryMessage
+ acknowledge_operations:
+ - type: send_message
+ subject: ExampleSubject
+ op_message: ExampleMessage
+ media_type: ExampleMediaTypeForActionModule
+ send_to_users:
+ - Admin
+ - type: notify_all_involved
+ subject: RecoverySubject
+ op_message: RecoveryMessage
+ media_type: ExampleMediaTypeForActionModule
+ pause_symptoms: False
+ register: zbxaction_pause_symptoms
+
+ - ansible.builtin.assert:
+ that: zbxaction_pause_symptoms.changed is sameas False
+
+ - name: test - delete action
+ community.zabbix.zabbix_action:
+ state: absent
+ register: zbxaction_delete
+
+ - ansible.builtin.assert:
+ that: zbxaction_delete.changed is sameas True
- name: delete ExampleApplicationAction action
community.zabbix.zabbix_action:
@@ -1379,14 +1028,13 @@
state: absent
- name: test - cleanup example template for zabbix_action module
- zabbix_template:
+ community.zabbix.zabbix_template:
template_name: ExampleTemplateForActionModule
- timeout: 20
state: absent
register: zbxaction_prep_template
- name: test - cleanup example mediatype for zabbix_action module
- zabbix_mediatype:
+ community.zabbix.zabbix_mediatype:
name: ExampleMediaTypeForActionModule
type: email
state: absent
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_screen/meta/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_api_info/meta/main.yml
index acdb704c8..acdb704c8 100644
--- a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_screen/meta/main.yml
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_api_info/meta/main.yml
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_api_info/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_api_info/tasks/main.yml
new file mode 100644
index 000000000..cb28929a4
--- /dev/null
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_api_info/tasks/main.yml
@@ -0,0 +1,9 @@
+---
+- name: Retrieve API information
+ community.zabbix.zabbix_api_info:
+ register: zbxapiinfo_get
+
+- ansible.builtin.assert:
+ that:
+ - zbxapiinfo_get.failed is sameas False
+ - zbxapiinfo_get.api.version is version(zabbix_version, '>=')
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_authentication/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_authentication/tasks/main.yml
index f6364f35a..37b1d2c9a 100644
--- a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_authentication/tasks/main.yml
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_authentication/tasks/main.yml
@@ -1,10 +1,10 @@
---
- block:
- - include_tasks: zabbix_authentication_tests.yml
+ - include_tasks: zabbix_authentication_tests.yml
always:
- - name: Cleanup
- zabbix_user_directory:
- name: TestUserDirectory
- state: absent
- ignore_errors: true
+ - name: Cleanup
+ community.zabbix.zabbix_user_directory:
+ name: TestUserDirectory
+ state: absent
+ ignore_errors: true
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_authentication/tasks/zabbix_authentication_tests.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_authentication/tasks/zabbix_authentication_tests.yml
index effc1b900..90b8b7868 100644
--- a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_authentication/tasks/zabbix_authentication_tests.yml
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_authentication/tasks/zabbix_authentication_tests.yml
@@ -1,71 +1,53 @@
---
-- name: test - do not run tests with < Zabbix 4.0
- meta: end_play
- when: zabbix_version is version('4.0', '<')
-
-- when: zabbix_version is version('5.4', '<')
- name: Unsupport Zabbix version (<5.4)
- block:
- - name: test - fail to update authentication setting
- zabbix_authentication:
- authentication_type: internal
- ignore_errors: true
- register: zbxauth_update
-
- - assert:
- that: zbxauth_update.failed is sameas True
-
-- when:
- - zabbix_version is version('5.4', '>=')
- - zabbix_version is version('6.0', '<=')
- name: support Zabbix version (>=5.4 <=6.0)
+- when: zabbix_version is version('6.0', '=')
+ name: support Zabbix version (=6.0)
block:
- - name: test - update ldap_configured without mandatory paramters
- zabbix_authentication:
+ - name: test - update ldap_configured without mandatory paramters
+ community.zabbix.zabbix_authentication:
ldap_configured: true
ignore_errors: true
register: zbxauth_update
- name: assert that authentication was NOT updated
- assert:
+ ansible.builtin.assert:
that:
- zbxauth_update.failed is sameas True
- zbxauth_update.msg == "Please set ldap_host, ldap_search_attribute and ldap_base_dn when you change a value of ldap_configured to true."
- - name: test - update saml_auth_enabled without mandatory paramters
- zabbix_authentication:
+ - name: test - update saml_auth_enabled without mandatory paramters
+ community.zabbix.zabbix_authentication:
saml_auth_enabled: true
ignore_errors: true
register: zbxauth_update
- name: assert that authentication was NOT updated
- assert:
+ ansible.builtin.assert:
that:
- zbxauth_update.failed is sameas True
- zbxauth_update.msg == "Please set saml_idp_entityid, saml_sso_url, saml_username_attribute and saml_sp_entityid when you change a value of saml_auth_enabled to true."
- name: test - update all authentication setting
- zabbix_authentication:
+ community.zabbix.zabbix_authentication:
authentication_type: internal
http_auth_enabled: true
http_login_form: zabbix_login_form
- http_strip_domains: 'comp,any'
+ http_strip_domains: "comp,any"
http_case_sensitive: true
ldap_configured: true
- ldap_host: 'ldap://localhost'
+ ldap_host: "ldap://localhost"
ldap_port: 389
- ldap_base_dn: 'ou=Users,ou=system'
- ldap_search_attribute: 'uid'
- ldap_bind_dn: 'uid=ldap_search,ou=system'
+ ldap_base_dn: "ou=Users,ou=system"
+ ldap_search_attribute: "uid"
+ ldap_bind_dn: "uid=ldap_search,ou=system"
ldap_case_sensitive: true
- ldap_bind_password: 'password'
+ ldap_bind_password: "password"
saml_auth_enabled: true
- saml_idp_entityid: ''
- saml_sso_url: 'https://localhost/SAML2/SSO'
- saml_slo_url: 'https://localhost/SAML2/SLO'
- saml_username_attribute: 'uid'
- saml_sp_entityid: 'https://localhost'
- saml_nameid_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:entity'
+ saml_idp_entityid: ""
+ saml_sso_url: "https://localhost/SAML2/SSO"
+ saml_slo_url: "https://localhost/SAML2/SLO"
+ saml_username_attribute: "uid"
+ saml_sp_entityid: "https://localhost"
+ saml_nameid_format: "urn:oasis:names:tc:SAML:2.0:nameid-format:entity"
saml_sign_messages: true
saml_sign_assertions: true
saml_sign_authn_requests: true
@@ -83,11 +65,11 @@
register: zbxauth_update
- name: assert that authentication was updated
- assert:
+ ansible.builtin.assert:
that: zbxauth_update.changed is sameas True
- name: test - update all authentication setting (again)
- zabbix_authentication:
+ community.zabbix.zabbix_authentication:
authentication_type: internal
http_auth_enabled: true
http_login_form: zabbix_login_form
@@ -96,20 +78,20 @@
- any
http_case_sensitive: true
ldap_configured: true
- ldap_host: 'ldap://localhost'
+ ldap_host: "ldap://localhost"
ldap_port: 389
- ldap_base_dn: 'ou=Users,ou=system'
- ldap_search_attribute: 'uid'
- ldap_bind_dn: 'uid=ldap_search,ou=system'
+ ldap_base_dn: "ou=Users,ou=system"
+ ldap_search_attribute: "uid"
+ ldap_bind_dn: "uid=ldap_search,ou=system"
ldap_case_sensitive: true
- ldap_bind_password: 'password'
+ ldap_bind_password: "password"
saml_auth_enabled: true
- saml_idp_entityid: ''
- saml_sso_url: 'https://localhost/SAML2/SSO'
- saml_slo_url: 'https://localhost/SAML2/SLO'
- saml_username_attribute: 'uid'
- saml_sp_entityid: 'https://localhost'
- saml_nameid_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:entity'
+ saml_idp_entityid: ""
+ saml_sso_url: "https://localhost/SAML2/SSO"
+ saml_slo_url: "https://localhost/SAML2/SLO"
+ saml_username_attribute: "uid"
+ saml_sp_entityid: "https://localhost"
+ saml_nameid_format: "urn:oasis:names:tc:SAML:2.0:nameid-format:entity"
saml_sign_messages: true
saml_sign_assertions: true
saml_sign_authn_requests: true
@@ -127,31 +109,31 @@
register: zbxauth_update
- name: assert that authentication was NOT updated
- assert:
+ ansible.builtin.assert:
that: zbxauth_update.changed is sameas False
- name: test - initialize all authentication setting
- zabbix_authentication:
+ community.zabbix.zabbix_authentication:
authentication_type: internal
http_auth_enabled: false
http_login_form: zabbix_login_form
http_strip_domains: []
http_case_sensitive: true
ldap_configured: false
- ldap_host: ''
+ ldap_host: ""
ldap_port: 389
- ldap_base_dn: ''
- ldap_search_attribute: ''
- ldap_bind_dn: ''
+ ldap_base_dn: ""
+ ldap_search_attribute: ""
+ ldap_bind_dn: ""
ldap_case_sensitive: true
- ldap_bind_password: ''
+ ldap_bind_password: ""
saml_auth_enabled: false
- saml_idp_entityid: ''
- saml_sso_url: ''
- saml_slo_url: ''
- saml_username_attribute: ''
- saml_sp_entityid: ''
- saml_nameid_format: ''
+ saml_idp_entityid: ""
+ saml_sso_url: ""
+ saml_slo_url: ""
+ saml_username_attribute: ""
+ saml_sp_entityid: ""
+ saml_nameid_format: ""
saml_sign_messages: false
saml_sign_assertions: false
saml_sign_authn_requests: false
@@ -166,62 +148,61 @@
register: zbxauth_update
- name: assert that authentication was updated
- assert:
+ ansible.builtin.assert:
that: zbxauth_update.changed is sameas True
-- when:
- - zabbix_version is version('6.2', '=')
+- when: zabbix_version is version('6.2', '=')
name: support Zabbix version (=6.2)
block:
- name: test - create user directory
- zabbix_user_directory:
+ community.zabbix.zabbix_user_directory:
name: TestUserDirectory
- host: 'test.com'
+ host: "test.com"
port: 389
- base_dn: 'ou=Users,dc=example,dc=org'
- search_attribute: 'uid'
-
- - name: test - update ldap_configured without mandatory paramters
- zabbix_authentication:
+ base_dn: "ou=Users,dc=example,dc=org"
+ search_attribute: "uid"
+
+ - name: test - update ldap_configured without mandatory paramters
+ community.zabbix.zabbix_authentication:
ldap_configured: true
ignore_errors: true
register: zbxauth_update
- name: assert that authentication was NOT updated
- assert:
+ ansible.builtin.assert:
that:
- zbxauth_update.failed is sameas True
- zbxauth_update.msg == "Please set ldap_userdirectory when you change a value of ldap_configured to true."
- - name: test - update saml_auth_enabled without mandatory paramters
- zabbix_authentication:
+ - name: test - update saml_auth_enabled without mandatory paramters
+ community.zabbix.zabbix_authentication:
saml_auth_enabled: true
ignore_errors: true
register: zbxauth_update
- name: assert that authentication was NOT updated
- assert:
+ ansible.builtin.assert:
that:
- zbxauth_update.failed is sameas True
- zbxauth_update.msg == "Please set saml_idp_entityid, saml_sso_url, saml_username_attribute and saml_sp_entityid when you change a value of saml_auth_enabled to true."
- name: test - update all authentication setting
- zabbix_authentication:
+ community.zabbix.zabbix_authentication:
authentication_type: internal
http_auth_enabled: true
http_login_form: zabbix_login_form
- http_strip_domains: 'comp,any'
+ http_strip_domains: "comp,any"
http_case_sensitive: true
ldap_configured: true
ldap_case_sensitive: true
ldap_userdirectory: TestUserDirectory
saml_auth_enabled: true
- saml_idp_entityid: ''
- saml_sso_url: 'https://localhost/SAML2/SSO'
- saml_slo_url: 'https://localhost/SAML2/SLO'
- saml_username_attribute: 'uid'
- saml_sp_entityid: 'https://localhost'
- saml_nameid_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:entity'
+ saml_idp_entityid: ""
+ saml_sso_url: "https://localhost/SAML2/SSO"
+ saml_slo_url: "https://localhost/SAML2/SLO"
+ saml_username_attribute: "uid"
+ saml_sp_entityid: "https://localhost"
+ saml_nameid_format: "urn:oasis:names:tc:SAML:2.0:nameid-format:entity"
saml_sign_messages: true
saml_sign_assertions: true
saml_sign_authn_requests: true
@@ -239,11 +220,11 @@
register: zbxauth_update
- name: assert that authentication was updated
- assert:
+ ansible.builtin.assert:
that: zbxauth_update.changed is sameas True
- name: test - update all authentication setting (again)
- zabbix_authentication:
+ community.zabbix.zabbix_authentication:
authentication_type: internal
http_auth_enabled: true
http_login_form: zabbix_login_form
@@ -255,12 +236,12 @@
ldap_case_sensitive: true
ldap_userdirectory: TestUserDirectory
saml_auth_enabled: true
- saml_idp_entityid: ''
- saml_sso_url: 'https://localhost/SAML2/SSO'
- saml_slo_url: 'https://localhost/SAML2/SLO'
- saml_username_attribute: 'uid'
- saml_sp_entityid: 'https://localhost'
- saml_nameid_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:entity'
+ saml_idp_entityid: ""
+ saml_sso_url: "https://localhost/SAML2/SSO"
+ saml_slo_url: "https://localhost/SAML2/SLO"
+ saml_username_attribute: "uid"
+ saml_sp_entityid: "https://localhost"
+ saml_nameid_format: "urn:oasis:names:tc:SAML:2.0:nameid-format:entity"
saml_sign_messages: true
saml_sign_assertions: true
saml_sign_authn_requests: true
@@ -278,11 +259,11 @@
register: zbxauth_update
- name: assert that authentication was NOT updated
- assert:
+ ansible.builtin.assert:
that: zbxauth_update.changed is sameas False
- name: test - initialize all authentication setting
- zabbix_authentication:
+ community.zabbix.zabbix_authentication:
authentication_type: internal
http_auth_enabled: false
http_login_form: zabbix_login_form
@@ -291,12 +272,12 @@
ldap_configured: false
ldap_case_sensitive: true
saml_auth_enabled: false
- saml_idp_entityid: ''
- saml_sso_url: ''
- saml_slo_url: ''
- saml_username_attribute: ''
- saml_sp_entityid: ''
- saml_nameid_format: ''
+ saml_idp_entityid: ""
+ saml_sso_url: ""
+ saml_slo_url: ""
+ saml_username_attribute: ""
+ saml_sp_entityid: ""
+ saml_nameid_format: ""
saml_sign_messages: false
saml_sign_assertions: false
saml_sign_authn_requests: false
@@ -311,43 +292,43 @@
register: zbxauth_update
- name: assert that authentication was updated
- assert:
+ ansible.builtin.assert:
that: zbxauth_update.changed is sameas True
- name: test - delete user directory
- zabbix_user_directory:
+ community.zabbix.zabbix_user_directory:
name: TestUserDirectory
state: absent
- when: zabbix_version is version('6.4', '>=')
name: support Zabbix version (>=6.4)
block:
- - name: test - update ldap_configured without mandatory paramters
- zabbix_authentication:
+ - name: test - update ldap_configured without mandatory paramters
+ community.zabbix.zabbix_authentication:
ldap_auth_enabled: true
ignore_errors: true
register: zbxauth_update
- name: assert that authentication was NOT updated
- assert:
+ ansible.builtin.assert:
that:
- zbxauth_update.failed is sameas True
- zbxauth_update.msg == "Please set ldap_userdirectory when you change a value of ldap_auth_enabled to true."
- name: test - create LDAP user directory
- zabbix_user_directory:
+ community.zabbix.zabbix_user_directory:
name: TestUserDirectory
idp_type: ldap
- host: 'test.ca'
+ host: "test.ca"
port: 389
- base_dn: 'ou=Users,dc=example,dc=org'
- search_attribute: 'uid'
+ base_dn: "ou=Users,dc=example,dc=org"
+ search_attribute: "uid"
provision_status: True
group_name: cn
group_basedn: ou=Group,dc=example,dc=org
group_member: member
user_ref_attr: uid
- group_filter: '(member=uid=%{ref},ou=Users,dc=example,dc=com)'
+ group_filter: "(member=uid=%{ref},ou=Users,dc=example,dc=com)"
user_username: first_name
user_lastname: last_name
provision_media:
@@ -361,11 +342,11 @@
- Guests
- name: test - update all authentication setting
- zabbix_authentication:
+ community.zabbix.zabbix_authentication:
authentication_type: internal
http_auth_enabled: true
http_login_form: zabbix_login_form
- http_strip_domains: 'comp,any'
+ http_strip_domains: "comp,any"
http_case_sensitive: true
ldap_auth_enabled: true
ldap_case_sensitive: true
@@ -385,15 +366,15 @@
register: zbxauth_update
- name: assert that authentication was updated
- assert:
+ ansible.builtin.assert:
that: zbxauth_update.changed is sameas True
- name: test - update all authentication setting (again)
- zabbix_authentication:
+ community.zabbix.zabbix_authentication:
authentication_type: internal
http_auth_enabled: true
http_login_form: zabbix_login_form
- http_strip_domains: 'comp,any'
+ http_strip_domains: "comp,any"
http_case_sensitive: true
ldap_auth_enabled: true
ldap_case_sensitive: true
@@ -413,11 +394,11 @@
register: zbxauth_update
- name: assert that authentication was NOT updated
- assert:
+ ansible.builtin.assert:
that: zbxauth_update.changed is sameas False
- name: test - initialize all authentication setting
- zabbix_authentication:
+ community.zabbix.zabbix_authentication:
authentication_type: internal
http_auth_enabled: false
http_login_form: zabbix_login_form
@@ -435,5 +416,5 @@
register: zbxauth_update
- name: assert that authentication was updated
- assert:
+ ansible.builtin.assert:
that: zbxauth_update.changed is sameas True
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_autoregister/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_autoregister/tasks/main.yml
index 3dcf93dbe..797ad2c2c 100644
--- a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_autoregister/tasks/main.yml
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_autoregister/tasks/main.yml
@@ -1,108 +1,87 @@
---
-- name: test - do not run tests with < Zabbix 4.0
- meta: end_play
- when: zabbix_version is version('4.0', '<')
-
-- when: zabbix_version is version('4.4', '<')
- name: Unsupport Zabbix version (<4.4)
- block:
- - name: test fail to update autoregistration
- community.zabbix.zabbix_autoregister:
- tls_accept: "tls_with_psk"
- tls_psk_identity: 'PSK 001'
- tls_psk: "11111595725ac58dd977beef14b97461a7c1045b9a1c923453302c5473193478"
- register: zbxautoregister_update_result
- ignore_errors: true
-
- - assert:
- that: zbxautoregister_update_result.failed is sameas True
-
-- when: zabbix_version is version('4.4', '>=')
- name: Support Zabbix version (>=4.4)
- block:
- - name: test update autoregistration with no parameter
- community.zabbix.zabbix_autoregister:
- register: zbxautoregister_update_result
- ignore_errors: true
-
- - assert:
- that: zbxautoregister_update_result.failed is sameas True
-
- - name: test update autoregistration with all parameters
- community.zabbix.zabbix_autoregister:
- tls_accept:
- - unsecure
- - tls_with_psk
- tls_psk_identity: 'PSK 001'
- tls_psk: "11111595725ac58dd977beef14b97461a7c1045b9a1c923453302c5473193478"
- register: zbxautoregister_update_result
-
- - assert:
- that: zbxautoregister_update_result.changed is sameas True
-
- - name: test update autoregistration with all parameters (again)
- community.zabbix.zabbix_autoregister:
- tls_accept:
- - unsecure
- - tls_with_psk
- tls_psk_identity: 'PSK 001'
- tls_psk: "11111595725ac58dd977beef14b97461a7c1045b9a1c923453302c5473193478"
- register: zbxautoregister_update_result
-
- - assert:
- that: zbxautoregister_update_result.changed is sameas True
-
- - name: test update autoregistration with only tls_accept
- community.zabbix.zabbix_autoregister:
- tls_accept: "tls_with_psk"
- register: zbxautoregister_update_result
-
- - assert:
- that: zbxautoregister_update_result.changed is sameas True
-
- - name: test update autoregistration with only tls_accept (again)
- community.zabbix.zabbix_autoregister:
- tls_accept:
- - tls_with_psk
- register: zbxautoregister_update_result
-
- - assert:
- that: zbxautoregister_update_result.changed is sameas False
-
- - name: test update autoregistration with only tls_accept (unsecure)
- community.zabbix.zabbix_autoregister:
- tls_accept:
- - unsecure
- register: zbxautoregister_update_result
-
- - assert:
- that: zbxautoregister_update_result.changed is sameas True
-
- - name: test fail to update autoregistration with only tls_accept (tls_with_psk)
- community.zabbix.zabbix_autoregister:
- tls_accept: "tls_with_psk"
- register: zbxautoregister_update_result
- ignore_errors: true
-
- - assert:
- that: zbxautoregister_update_result.failed is sameas True
-
- - name: test fail to update autoregistration with only tls_accept and tls_psk_identity (tls_with_psk)
- community.zabbix.zabbix_autoregister:
- tls_accept: "tls_with_psk"
- tls_psk_identity: 'PSK 001'
- register: zbxautoregister_update_result
- ignore_errors: true
-
- - assert:
- that: zbxautoregister_update_result.failed is sameas True
-
- - name: test fail to update autoregistration with only tls_accept and tls_psk (tls_with_psk)
- community.zabbix.zabbix_autoregister:
- tls_accept: "tls_with_psk"
- tls_psk: "11111595725ac58dd977beef14b97461a7c1045b9a1c923453302c5473193478"
- register: zbxautoregister_update_result
- ignore_errors: true
-
- - assert:
- that: zbxautoregister_update_result.failed is sameas True
+- name: test update autoregistration with no parameter
+ community.zabbix.zabbix_autoregister:
+ register: zbxautoregister_update_result
+ ignore_errors: true
+
+- ansible.builtin.assert:
+ that: zbxautoregister_update_result.failed is sameas True
+
+- name: test update autoregistration with all parameters
+ community.zabbix.zabbix_autoregister:
+ tls_accept:
+ - unsecure
+ - tls_with_psk
+ tls_psk_identity: "PSK 001"
+ tls_psk: "11111595725ac58dd977beef14b97461a7c1045b9a1c923453302c5473193478"
+ register: zbxautoregister_update_result
+
+- ansible.builtin.assert:
+ that: zbxautoregister_update_result.changed is sameas True
+
+- name: test update autoregistration with all parameters (again)
+ community.zabbix.zabbix_autoregister:
+ tls_accept:
+ - unsecure
+ - tls_with_psk
+ tls_psk_identity: "PSK 001"
+ tls_psk: "11111595725ac58dd977beef14b97461a7c1045b9a1c923453302c5473193478"
+ register: zbxautoregister_update_result
+
+- ansible.builtin.assert:
+ that: zbxautoregister_update_result.changed is sameas True
+
+- name: test update autoregistration with only tls_accept
+ community.zabbix.zabbix_autoregister:
+ tls_accept: "tls_with_psk"
+ register: zbxautoregister_update_result
+
+- ansible.builtin.assert:
+ that: zbxautoregister_update_result.changed is sameas True
+
+- name: test update autoregistration with only tls_accept (again)
+ community.zabbix.zabbix_autoregister:
+ tls_accept:
+ - tls_with_psk
+ register: zbxautoregister_update_result
+
+- ansible.builtin.assert:
+ that: zbxautoregister_update_result.changed is sameas False
+
+- name: test update autoregistration with only tls_accept (unsecure)
+ community.zabbix.zabbix_autoregister:
+ tls_accept:
+ - unsecure
+ register: zbxautoregister_update_result
+
+- ansible.builtin.assert:
+ that: zbxautoregister_update_result.changed is sameas True
+
+- name: test fail to update autoregistration with only tls_accept (tls_with_psk)
+ community.zabbix.zabbix_autoregister:
+ tls_accept: "tls_with_psk"
+ register: zbxautoregister_update_result
+ ignore_errors: true
+
+- ansible.builtin.assert:
+ that: zbxautoregister_update_result.failed is sameas True
+
+- name: test fail to update autoregistration with only tls_accept and tls_psk_identity (tls_with_psk)
+ community.zabbix.zabbix_autoregister:
+ tls_accept: "tls_with_psk"
+ tls_psk_identity: "PSK 001"
+ register: zbxautoregister_update_result
+ ignore_errors: true
+
+- ansible.builtin.assert:
+ that: zbxautoregister_update_result.failed is sameas True
+
+- name: test fail to update autoregistration with only tls_accept and tls_psk (tls_with_psk)
+ community.zabbix.zabbix_autoregister:
+ tls_accept: "tls_with_psk"
+ tls_psk: "11111595725ac58dd977beef14b97461a7c1045b9a1c923453302c5473193478"
+ register: zbxautoregister_update_result
+ ignore_errors: true
+
+- ansible.builtin.assert:
+ that: zbxautoregister_update_result.failed is sameas True
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_discovery_rule/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_discovery_rule/tasks/main.yml
index 16062a52e..cbf13b391 100644
--- a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_discovery_rule/tasks/main.yml
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_discovery_rule/tasks/main.yml
@@ -1,8 +1,4 @@
---
-- name: test - do not run tests for Zabbix 3.0
- meta: end_play
- when: zabbix_version is version('3.0', '=')
-
- name: test - Zabbix discovery rule
module_defaults:
community.zabbix.zabbix_discovery_rule:
@@ -11,270 +7,269 @@
iprange: 192.168.1.1-255
dchecks:
- type: ICMP
- delay: "{{ 3600 if zabbix_version is version('3.4', '<=') else omit }}"
block:
- - name: test - create new Zabbix discovery rule (checkmode)
- zabbix_discovery_rule:
- check_mode: true
- register: drule_new_checkmode
-
- - name: assert that drule will be created (checkmode)
- assert:
- that: drule_new_checkmode is changed
-
- - name: test - create new Zabbix discovery rule
- zabbix_discovery_rule:
- register: drule_new
-
- - name: assert that drule was created
- assert:
- that: drule_new is changed
-
- - name: test - create same Zabbix discovery rule
- zabbix_discovery_rule:
- register: drule_exists
-
- - name: assert that nothing has been changed
- assert:
- that: not drule_exists is changed
-
- - name: test - update Zabbix discovery rule iprange (checkmode)
- zabbix_discovery_rule:
- iprange:
- - 192.168.1.1-255
- - 10.0.0.1-255
- check_mode: true
- register: drule_iprange_update_checkmode
-
- - name: assert that iprange will be changed
- assert:
- that: drule_iprange_update_checkmode is changed
-
- - name: test - update Zabbix discovery rule iprange
- zabbix_discovery_rule:
- iprange:
- - 192.168.1.1-255
- - 10.0.0.1-255
- register: drule_iprange_update
-
- - name: assert that iprange has been changed
- assert:
- that: drule_iprange_update is changed
-
- - name: test - reset Zabbix discovery rule to default
- zabbix_discovery_rule:
- register: drule_reset
-
- - name: assert that iprange has been changed
- assert:
- that: drule_reset is changed
-
- - name: test - update Zabbix discovery rule status
- zabbix_discovery_rule:
- status: disabled
- register: drule_status_update
-
- - name: assert that iprange has been changed
- assert:
- that: drule_status_update is changed
-
- - name: test - reset Zabbix discovery rule to default
- zabbix_discovery_rule:
- register: drule_reset
-
- - name: assert that iprange has been changed
- assert:
- that: drule_reset is changed
-
- - name: test - update Zabbix discovery rule dchecks
- zabbix_discovery_rule:
- dchecks:
- - type: ICMP
- - type: Zabbix
- key: "system.hostname"
- ports: "10050"
- uniq: true
- host_source: discovery
- register: drule_dchecks_update
-
- - name: assert that dcheck has been changed
- assert:
- that: drule_dchecks_update is changed
-
- - name: test - update Zabbix discovery rule dchecks ssh
- zabbix_discovery_rule:
- dchecks:
- - type: ICMP
- - type: SSH
- ports: "22"
- register: drule_dchecks_ssh_update
-
- - name: assert that dcheck has been changed
- assert:
- that: drule_dchecks_ssh_update is changed
-
- - name: test - update Zabbix discovery rule dchecks ldap
- zabbix_discovery_rule:
- dchecks:
- - type: ICMP
- - type: SSH
- ports: "22"
- - type: LDAP
- ports: "389"
- register: drule_dchecks_ldap_update
-
- - name: assert that dcheck has been changed
- assert:
- that: drule_dchecks_ldap_update is changed
-
- - name: test - update Zabbix discovery rule dchecks smtp
- zabbix_discovery_rule:
- dchecks:
- - type: ICMP
- - type: SSH
- ports: "22"
- - type: LDAP
- ports: "389"
- - type: SMTP
- ports: 25,465,587
- register: drule_dchecks_smtp_update
-
- - name: assert that dcheck has been changed
- assert:
- that: drule_dchecks_smtp_update is changed
-
- - name: test - update Zabbix discovery rule dchecks http
- zabbix_discovery_rule:
- dchecks:
- - type: ICMP
- - type: SSH
- ports: "22"
- - type: LDAP
- ports: "389"
- - type: SMTP
- ports: 25,465,587
- - type: HTTP
- ports: 80,8080
- register: drule_dchecks_http_update
-
- - name: assert that dcheck has been changed
- assert:
- that: drule_dchecks_http_update is changed
-
- - name: test - remove Zabbix discovery rule dchecks
- zabbix_discovery_rule:
- dchecks:
- - type: ICMP
- register: drule_dchecks_remove_update
-
- - name: assert that dcheck has been changed
- assert:
- that: drule_dchecks_remove_update is changed
-
- - name: test - update Zabbix discovery rule snmp dcheck
- zabbix_discovery_rule:
- dchecks:
- - type: SNMPv2
- snmp_community: CUSTOMER@snmp-readonly
- ports: "161"
- key: iso.3.6.1.2.1.1.1.0
- uniq: false
- host_source: discovery
- name_source: discovery
- register: drule_snmp_update
-
- - name: assert that snmp dcheck has been changed
- assert:
- that: drule_snmp_update is changed
-
- - name: test - update Zabbix discovery rule snmp3 dcheck
- zabbix_discovery_rule:
- dchecks:
- - type: SNMPv3
- snmp_community: CUSTOMER@snmp3-readonly
- ports: "161"
- key: iso.3.6.1.2.1.1.1.0
- snmpv3_contextname: "ContextName"
- snmpv3_securityname: "SecurityName"
- snmpv3_securitylevel: authPriv
- snmpv3_authprotocol: SHA
- snmpv3_authpassphrase: "SeCrEt"
- snmpv3_privprotocol: AES
- snmpv3_privpassphrase: "TopSecret"
- uniq: false
- host_source: DNS
- name_source: None
- register: drule_snmp3_update
-
- - name: assert that snmp3 dcheck has been changed
- assert:
- that: drule_snmp3_update is changed
-
- - name: test - reset Zabbix discovery rule to default
- zabbix_discovery_rule:
- register: drule_reset
-
- - name: assert that iprange has been changed
- assert:
- that: drule_reset is changed
-
- - name: test - create new active Zabbix proxy server
- zabbix_proxy:
- proxy_name: ACME_proxy
- status: active
- state: present
- register: zbxproxy_active
-
- - name: assert that proxy was created
- assert:
- that: zbxproxy_active is changed
-
- - name: test - update Zabbix discovery rule proxy
- zabbix_discovery_rule:
- proxy: ACME_proxy
- register: drule_proxy_update
-
- - name: assert that proxy has been changed
- assert:
- that: drule_proxy_update is changed
-
- - name: test - update Zabbix discovery rule proxy (again)
- zabbix_discovery_rule:
- proxy: ACME_proxy
- register: drule_proxy_update_again
-
- - name: assert that nothing has been changed
- assert:
- that: not drule_proxy_update_again is changed
+ - name: test - create new Zabbix discovery rule (checkmode)
+ community.zabbix.zabbix_discovery_rule:
+ check_mode: true
+ register: drule_new_checkmode
+
+ - name: assert that drule will be created (checkmode)
+ ansible.builtin.assert:
+ that: drule_new_checkmode is changed
+
+ - name: test - create new Zabbix discovery rule
+ community.zabbix.zabbix_discovery_rule:
+ register: drule_new
+
+ - name: assert that drule was created
+ ansible.builtin.assert:
+ that: drule_new is changed
+
+ - name: test - create same Zabbix discovery rule
+ community.zabbix.zabbix_discovery_rule:
+ register: drule_exists
+
+ - name: assert that nothing has been changed
+ ansible.builtin.assert:
+ that: not drule_exists is changed
+
+ - name: test - update Zabbix discovery rule iprange (checkmode)
+ community.zabbix.zabbix_discovery_rule:
+ iprange:
+ - 192.168.1.1-255
+ - 10.0.0.1-255
+ check_mode: true
+ register: drule_iprange_update_checkmode
+
+ - name: assert that iprange will be changed
+ ansible.builtin.assert:
+ that: drule_iprange_update_checkmode is changed
+
+ - name: test - update Zabbix discovery rule iprange
+ community.zabbix.zabbix_discovery_rule:
+ iprange:
+ - 192.168.1.1-255
+ - 10.0.0.1-255
+ register: drule_iprange_update
+
+ - name: assert that iprange has been changed
+ ansible.builtin.assert:
+ that: drule_iprange_update is changed
+
+ - name: test - reset Zabbix discovery rule to default
+ community.zabbix.zabbix_discovery_rule:
+ register: drule_reset
+
+ - name: assert that iprange has been changed
+ ansible.builtin.assert:
+ that: drule_reset is changed
+
+ - name: test - update Zabbix discovery rule status
+ community.zabbix.zabbix_discovery_rule:
+ status: disabled
+ register: drule_status_update
+
+ - name: assert that iprange has been changed
+ ansible.builtin.assert:
+ that: drule_status_update is changed
+
+ - name: test - reset Zabbix discovery rule to default
+ community.zabbix.zabbix_discovery_rule:
+ register: drule_reset
+
+ - name: assert that iprange has been changed
+ ansible.builtin.assert:
+ that: drule_reset is changed
+
+ - name: test - update Zabbix discovery rule dchecks
+ community.zabbix.zabbix_discovery_rule:
+ dchecks:
+ - type: ICMP
+ - type: Zabbix
+ key: "system.hostname"
+ ports: "10050"
+ uniq: true
+ host_source: discovery
+ register: drule_dchecks_update
+
+ - name: assert that dcheck has been changed
+ ansible.builtin.assert:
+ that: drule_dchecks_update is changed
+
+ - name: test - update Zabbix discovery rule dchecks ssh
+ community.zabbix.zabbix_discovery_rule:
+ dchecks:
+ - type: ICMP
+ - type: SSH
+ ports: "22"
+ register: drule_dchecks_ssh_update
+
+ - name: assert that dcheck has been changed
+ ansible.builtin.assert:
+ that: drule_dchecks_ssh_update is changed
+
+ - name: test - update Zabbix discovery rule dchecks ldap
+ community.zabbix.zabbix_discovery_rule:
+ dchecks:
+ - type: ICMP
+ - type: SSH
+ ports: "22"
+ - type: LDAP
+ ports: "389"
+ register: drule_dchecks_ldap_update
+
+ - name: assert that dcheck has been changed
+ ansible.builtin.assert:
+ that: drule_dchecks_ldap_update is changed
+
+ - name: test - update Zabbix discovery rule dchecks smtp
+ community.zabbix.zabbix_discovery_rule:
+ dchecks:
+ - type: ICMP
+ - type: SSH
+ ports: "22"
+ - type: LDAP
+ ports: "389"
+ - type: SMTP
+ ports: 25,465,587
+ register: drule_dchecks_smtp_update
+
+ - name: assert that dcheck has been changed
+ ansible.builtin.assert:
+ that: drule_dchecks_smtp_update is changed
+
+ - name: test - update Zabbix discovery rule dchecks http
+ community.zabbix.zabbix_discovery_rule:
+ dchecks:
+ - type: ICMP
+ - type: SSH
+ ports: "22"
+ - type: LDAP
+ ports: "389"
+ - type: SMTP
+ ports: 25,465,587
+ - type: HTTP
+ ports: 80,8080
+ register: drule_dchecks_http_update
+
+ - name: assert that dcheck has been changed
+ ansible.builtin.assert:
+ that: drule_dchecks_http_update is changed
+
+ - name: test - remove Zabbix discovery rule dchecks
+ community.zabbix.zabbix_discovery_rule:
+ dchecks:
+ - type: ICMP
+ register: drule_dchecks_remove_update
+
+ - name: assert that dcheck has been changed
+ ansible.builtin.assert:
+ that: drule_dchecks_remove_update is changed
+
+ - name: test - update Zabbix discovery rule snmp dcheck
+ community.zabbix.zabbix_discovery_rule:
+ dchecks:
+ - type: SNMPv2
+ snmp_community: CUSTOMER@snmp-readonly
+ ports: "161"
+ key: iso.3.6.1.2.1.1.1.0
+ uniq: false
+ host_source: discovery
+ name_source: discovery
+ register: drule_snmp_update
+
+ - name: assert that snmp dcheck has been changed
+ ansible.builtin.assert:
+ that: drule_snmp_update is changed
+
+ - name: test - update Zabbix discovery rule snmp3 dcheck
+ community.zabbix.zabbix_discovery_rule:
+ dchecks:
+ - type: SNMPv3
+ snmp_community: CUSTOMER@snmp3-readonly
+ ports: "161"
+ key: iso.3.6.1.2.1.1.1.0
+ snmpv3_contextname: "ContextName"
+ snmpv3_securityname: "SecurityName"
+ snmpv3_securitylevel: authPriv
+ snmpv3_authprotocol: SHA
+ snmpv3_authpassphrase: "SeCrEt"
+ snmpv3_privprotocol: AES
+ snmpv3_privpassphrase: "TopSecret"
+ uniq: false
+ host_source: DNS
+ name_source: None
+ register: drule_snmp3_update
+
+ - name: assert that snmp3 dcheck has been changed
+ ansible.builtin.assert:
+ that: drule_snmp3_update is changed
+
+ - name: test - reset Zabbix discovery rule to default
+ community.zabbix.zabbix_discovery_rule:
+ register: drule_reset
+
+ - name: assert that iprange has been changed
+ ansible.builtin.assert:
+ that: drule_reset is changed
+
+ - name: test - create new active Zabbix proxy server
+ community.zabbix.zabbix_proxy:
+ proxy_name: ACME_proxy
+ status: active
+ state: present
+ register: zbxproxy_active
+
+ - name: assert that proxy was created
+ ansible.builtin.assert:
+ that: zbxproxy_active is changed
+
+ - name: test - update Zabbix discovery rule proxy
+ community.zabbix.zabbix_discovery_rule:
+ proxy: ACME_proxy
+ register: drule_proxy_update
+
+ - name: assert that proxy has been changed
+ ansible.builtin.assert:
+ that: drule_proxy_update is changed
+
+ - name: test - update Zabbix discovery rule proxy (again)
+ community.zabbix.zabbix_discovery_rule:
+ proxy: ACME_proxy
+ register: drule_proxy_update_again
+
+ - name: assert that nothing has been changed
+ ansible.builtin.assert:
+ that: not drule_proxy_update_again is changed
- name: test - delete Zabbix discovery rule
- zabbix_discovery_rule:
+ community.zabbix.zabbix_discovery_rule:
name: ACME
state: absent
register: drule_delete
- name: assert that proxy has been deleted
- assert:
+ ansible.builtin.assert:
that: drule_delete is changed
- name: test - delete Zabbix discovery rule (again)
- zabbix_discovery_rule:
+ community.zabbix.zabbix_discovery_rule:
name: ACME
state: absent
register: drule_delete_again
- name: assert that nothing has been changed
- assert:
+ ansible.builtin.assert:
that: not drule_delete_again is changed
# Cleanup
- name: delete active Zabbix proxy server
- zabbix_proxy:
+ community.zabbix.zabbix_proxy:
proxy_name: ACME_proxy
state: absent
register: zbxproxy_delete
- name: assert that proxy has been deleted
- assert:
+ ansible.builtin.assert:
that: zbxproxy_delete is changed
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_globalmacro/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_globalmacro/tasks/main.yml
index ce49f0f86..bc15fec2c 100644
--- a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_globalmacro/tasks/main.yml
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_globalmacro/tasks/main.yml
@@ -1,6 +1,6 @@
---
- name: test - attempt to create new global macro
- zabbix_globalmacro:
+ community.zabbix.zabbix_globalmacro:
macro_name: zbxgmacro_test01
macro_value: 123
macro_type: text
@@ -8,11 +8,11 @@
register: zbxgmacro_new
- name: assert that macro was created
- assert:
+ ansible.builtin.assert:
that: zbxgmacro_new is changed
- name: test - attempt to create same global macro
- zabbix_globalmacro:
+ community.zabbix.zabbix_globalmacro:
macro_name: zbxgmacro_test01
macro_value: 123
macro_type: text
@@ -20,11 +20,11 @@
register: zbxgmacro_existing
- name: assert that nothing has been changed
- assert:
+ ansible.builtin.assert:
that: not zbxgmacro_existing is changed
- name: test - attempt to create same global macro in zabbix native format
- zabbix_globalmacro:
+ community.zabbix.zabbix_globalmacro:
macro_name: "{$zbxgmacro_test01}"
macro_value: 123
macro_type: text
@@ -32,22 +32,22 @@
register: zbxgmacro_existing_native
- name: assert that nothing has been changed
- assert:
+ ansible.builtin.assert:
that: not zbxgmacro_existing_native is changed
- name: test - attempt to create new global macro in zabbix native format
- zabbix_globalmacro:
+ community.zabbix.zabbix_globalmacro:
macro_name: "{$ZBXGMACRO_TEST02}"
macro_value: abcd
macro_type: text
register: zbxgmacro_new_native
- name: assert that nothing macro was created
- assert:
+ ansible.builtin.assert:
that: zbxgmacro_new_native is changed
- name: test - attempt to update global macro with string value while force=no
- zabbix_globalmacro:
+ community.zabbix.zabbix_globalmacro:
macro_name: zbxgmacro_test01
macro_value: abc
macro_type: text
@@ -55,44 +55,44 @@
register: zbxgmacro_update_noforce
- name: assert that nothing has been changed
- assert:
+ ansible.builtin.assert:
that: not zbxgmacro_update_noforce is changed
- name: test - attempt to update global macro with string value
- zabbix_globalmacro:
+ community.zabbix.zabbix_globalmacro:
macro_name: zbxgmacro_test01
macro_value: abc
macro_type: text
register: zbxgmacro_update
- name: assert that global macro was updated
- assert:
+ ansible.builtin.assert:
that: zbxgmacro_update is changed
- name: test - attempt to create global macro with context
- zabbix_globalmacro:
+ community.zabbix.zabbix_globalmacro:
macro_name: low_space_limit:/home
macro_value: 10
macro_type: text
register: zbxgmacro_context_new
- name: assert that macro was created
- assert:
+ ansible.builtin.assert:
that: zbxgmacro_context_new is changed
- name: test - attempt to create same global macro with context and verify that it was converted to uppercase
- zabbix_globalmacro:
+ community.zabbix.zabbix_globalmacro:
macro_name: LOW_SPACE_LIMIT:/home
macro_value: 10
macro_type: text
register: zbxgmacro_context_existing
- name: assert that nothing has been changed
- assert:
+ ansible.builtin.assert:
that: not zbxgmacro_context_existing is changed
- name: test - attempt to delete all global macros
- zabbix_globalmacro:
+ community.zabbix.zabbix_globalmacro:
macro_name: "{{ item }}"
state: absent
loop:
@@ -102,71 +102,66 @@
register: zbxgmacro_delete_existing
- name: assert that all macros have been deleted
- assert:
+ ansible.builtin.assert:
that: item.changed is sameas True
loop: "{{ zbxgmacro_delete_existing.results }}"
- name: test - attempt to delete non-existing global macro
- zabbix_globalmacro:
+ community.zabbix.zabbix_globalmacro:
macro_name: zbxgmacro_test01
state: absent
register: zbxgmacro_delete_missing
- name: assert that nothing has been changed
- assert:
+ ansible.builtin.assert:
that: not zbxgmacro_delete_missing is changed
- name: test - attempt to create secret global macro
- zabbix_globalmacro:
+ community.zabbix.zabbix_globalmacro:
macro_name: zbxgmacro_test_secret
macro_value: 123
macro_type: secret
macro_description: Global Macro description
register: zbxgmacro_secret
-- assert:
+- ansible.builtin.assert:
that: zbxgmacro_secret.changed is sameas True
- name: test - attempt to create same global macro
- zabbix_globalmacro:
+ community.zabbix.zabbix_globalmacro:
macro_name: zbxgmacro_test_secret
macro_value: 123
macro_type: secret
macro_description: Global Macro description
register: zbxgmacro_secret
-- assert:
+- ansible.builtin.assert:
that: zbxgmacro_secret.changed is sameas True
- when: zabbix_version is version('5.0', '>=')
-
-- assert:
- that: zbxgmacro_secret.changed is sameas False
- when: zabbix_version is version('5.0', '<')
- name: test - attempt to create vault global macro
- zabbix_globalmacro:
+ community.zabbix.zabbix_globalmacro:
macro_name: zbxgmacro_test_vault
macro_value: path/to/vault:zabbix
macro_type: vault
macro_description: Global Macro description
register: zbxgmacro_vault
-- assert:
+- ansible.builtin.assert:
that: zbxgmacro_vault.changed is sameas True
- name: test - attempt to create same global macro
- zabbix_globalmacro:
+ community.zabbix.zabbix_globalmacro:
macro_name: zbxgmacro_test_vault
macro_value: path/to/vault:zabbix
macro_type: vault
macro_description: Global Macro description
register: zbxgmacro_vault
-- assert:
+- ansible.builtin.assert:
that: zbxgmacro_vault.changed is sameas False
- name: delete all global macros
- zabbix_globalmacro:
+ community.zabbix.zabbix_globalmacro:
macro_name: "{{ item }}"
state: absent
loop:
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_group/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_group/tasks/main.yml
index 0f099d7c1..b45711a25 100644
--- a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_group/tasks/main.yml
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_group/tasks/main.yml
@@ -1,17 +1,17 @@
---
- name: test - create new Zabbix group
- zabbix_group:
+ community.zabbix.zabbix_group:
host_groups:
- zbxgrp_example_group01
state: present
register: zbxgrp_new
- name: assert that group was created
- assert:
+ ansible.builtin.assert:
that: zbxgrp_new is changed
- name: test - create simple zabbix host to assign to group
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: zbxgrp_example_host01
host_groups:
- zbxgrp_example_group01
@@ -23,33 +23,33 @@
register: zbxgrp_host_assignement
- name: assert that host was assigned successfully
- assert:
+ ansible.builtin.assert:
that: zbxgrp_host_assignement is changed
- name: test - create same Zabbix group once again
- zabbix_group:
+ community.zabbix.zabbix_group:
host_groups:
- zbxgrp_example_group01
state: present
register: zbxgrp_existing
- name: assert that nothing has been changed
- assert:
+ ansible.builtin.assert:
that: not zbxgrp_existing is changed
- name: test - attempt to create new Zabbix group matching name of default Zabbix group
- zabbix_group:
+ community.zabbix.zabbix_group:
host_groups:
- Linux servers
state: present
register: zbxgrp_default_existing
- name: assert that nothing has been changed
- assert:
+ ansible.builtin.assert:
that: not zbxgrp_default_existing is changed
- name: test - attempt to delete host group while its only group host has assigned
- zabbix_group:
+ community.zabbix.zabbix_group:
host_groups:
- zbxgrp_example_group01
state: absent
@@ -57,32 +57,32 @@
ignore_errors: true
- name: assert that group deletion failed
- assert:
+ ansible.builtin.assert:
that: zbxgrp_existing_delete_failed is failed
- name: delete helper zabbix host
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: zbxgrp_example_host01
state: absent
- name: test - attempt to delete previously created zabbix group
- zabbix_group:
+ community.zabbix.zabbix_group:
host_groups:
- zbxgrp_example_group01
state: absent
register: zbxgrp_existing_delete
- name: assert that group was deleted
- assert:
+ ansible.builtin.assert:
that: zbxgrp_existing_delete is changed
- name: test - attempt to delete non-existing zabbix group
- zabbix_group:
+ community.zabbix.zabbix_group:
host_groups:
- zbxgrp_example_group01
state: absent
register: zbxgrp_missing_delete
- name: assert that nothing has been changed
- assert:
+ ansible.builtin.assert:
that: not zbxgrp_missing_delete is changed
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_group_events_info/files/trigger_testing.json b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_group_events_info/files/trigger_testing.json
new file mode 100644
index 000000000..a642483f4
--- /dev/null
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_group_events_info/files/trigger_testing.json
@@ -0,0 +1,48 @@
+{
+ "zabbix_export": {
+ "version": "6.0",
+ "date": "2023-09-05T13:58:23Z",
+ "groups": [
+ {
+ "uuid": "6932cc6c283949ee8d4c316e2f30af5f",
+ "name": "Templates"
+ }
+ ],
+ "templates": [
+ {
+ "uuid": "641c10c5445245edb59050c3518e76a0",
+ "template": "Trigger testing",
+ "name": "Trigger testing",
+ "groups": [
+ {
+ "name": "Templates"
+ }
+ ],
+ "items": [
+ {
+ "uuid": "0dce402f6f0c44cfb7796c1ea6c4bb86",
+ "name": "Test Item",
+ "type": "CALCULATED",
+ "key": "test",
+ "delay": "10s",
+ "params": "1",
+ "triggers": [
+ {
+ "uuid": "11b2645a369946dcaa00b6edc578089f",
+ "expression": "last(/Trigger testing/test)=0",
+ "name": "Ok Trigger",
+ "priority": "AVERAGE"
+ },
+ {
+ "uuid": "f17f4b4f7fe444dfb856bc9d6366d0fe",
+ "expression": "last(/Trigger testing/test)=1",
+ "name": "Problem Trigger",
+ "priority": "AVERAGE"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_group_events_info/meta/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_group_events_info/meta/main.yml
new file mode 100644
index 000000000..acdb704c8
--- /dev/null
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_group_events_info/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - setup_zabbix
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_group_events_info/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_group_events_info/tasks/main.yml
new file mode 100644
index 000000000..601f5421f
--- /dev/null
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_group_events_info/tasks/main.yml
@@ -0,0 +1,58 @@
+---
+- name: Import trigger test template
+ zabbix_template:
+ template_json: "{{ lookup('file', 'trigger_testing.json') }}"
+ state: present
+
+- name: Create host group
+ zabbix_group:
+ state: present
+ host_groups:
+ - Example group
+
+- name: Create new host with template
+ zabbix_host:
+ host_name: Example host
+ link_templates:
+ - Trigger testing
+ host_groups:
+ - Example group
+
+- name: Wait a minute to ensure triggers are firing
+ ansible.builtin.wait_for:
+ timeout: 60
+
+- name: Get hostgroup events
+ zabbix_group_events_info:
+ hostgroup_name: Example group
+ trigger_severity: not_classified
+ register: hostgroup_events_results
+
+- name: Assert that trigger results are as expected
+ ansible.builtin.assert:
+ that:
+ - hostgroup_events_results.triggers_ok[0].description == "Ok Trigger"
+ - hostgroup_events_results.triggers_ok[0].value == "0"
+ - hostgroup_events_results.triggers_ok[0].status == "0"
+ # TODO: Need to figure out why this periodically fails for no reason. False Alarm
+ # - hostgroup_events_results.triggers_problem[0].description == "Problem Trigger"
+ # - hostgroup_events_results.triggers_problem[0].value == "1"
+ # - hostgroup_events_results.triggers_problem[0].status == "0"
+ # - hostgroup_events_results.triggers_problem[0].last_event.acknowledged == "0"
+ # - hostgroup_events_results.triggers_problem[0].last_event.value == "1"
+
+- name: Clean up host
+ zabbix_host:
+ host_name: Example host
+ state: absent
+
+- name: Clean up host group
+ zabbix_group:
+ host_groups:
+ - Example group
+ state: absent
+
+- name: Clean up template
+ zabbix_template:
+ template_name: "Trigger testing"
+ state: absent
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_group_info/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_group_info/tasks/main.yml
index 624679603..51c03af3b 100644
--- a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_group_info/tasks/main.yml
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_group_info/tasks/main.yml
@@ -1,6 +1,6 @@
---
- name: test - create new Zabbix group
- zabbix_group:
+ community.zabbix.zabbix_group:
host_groups:
- zbxgrp_example_group01
- zbxgrp_example_group02
@@ -8,7 +8,7 @@
register: zbxgrp_new
- name: assert that group was created
- assert:
+ ansible.builtin.assert:
that: zbxgrp_new is changed
- name: test - get one hostgroup info
@@ -18,7 +18,7 @@
register: get_hostgorup_info_result
- name: assert that one group was get
- assert:
+ ansible.builtin.assert:
that:
- get_hostgorup_info_result.host_groups | length == 1
- get_hostgorup_info_result.host_groups.0.name == 'zbxgrp_example_group01'
@@ -31,14 +31,14 @@
register: get_hostgorup_info_result
- name: assert that two group was get
- assert:
+ ansible.builtin.assert:
that:
- get_hostgorup_info_result.host_groups | length == 2
- get_hostgorup_info_result.host_groups.0.name == 'zbxgrp_example_group01'
- get_hostgorup_info_result.host_groups.1.name == 'zbxgrp_example_group02'
- name: test - delete Zabbix group
- zabbix_group:
+ community.zabbix.zabbix_group:
host_groups:
- zbxgrp_example_group01
- zbxgrp_example_group02
@@ -46,5 +46,5 @@
register: delete_zbxgrp
- name: assert that group was deleted
- assert:
+ ansible.builtin.assert:
that: delete_zbxgrp is changed
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/tasks/main.yml
index 20755061f..c4675797f 100644
--- a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/tasks/main.yml
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/tasks/main.yml
@@ -12,8 +12,12 @@
# tear down stuff set up earlier
- include_tasks: zabbix_host_teardown.yml
always:
- - name: "cleanup if tests failed"
- zabbix_host:
- host_name: ExampleHost
- state: absent
- ignore_errors: true
+ - name: "cleanup if tests failed"
+ community.zabbix.zabbix_host:
+ host_name: "{{ item }}"
+ state: absent
+ ignore_errors: true
+ with_items:
+ - ExampleHost
+ - ExampleHost1
+ - ExampleHost2
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/tasks/zabbix_host_doc.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/tasks/zabbix_host_doc.yml
index 4415e2ca1..c84050dcf 100644
--- a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/tasks/zabbix_host_doc.yml
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/tasks/zabbix_host_doc.yml
@@ -2,7 +2,7 @@
# These two tests are close to documentation example
- name: Create a new host or update an existing host's info
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost1
visible_name: ExampleName
description: My ExampleHost Description
@@ -10,8 +10,8 @@
- Linux servers
- Zabbix servers
link_templates:
- - "{{ 'IMAP Service' if zabbix_version | float >= 5.2 else 'Template App IMAP Service' }}"
- - "{{ 'NTP Service' if zabbix_version | float >= 5.2 else 'Template App NTP Service' }}"
+ - "IMAP Service"
+ - "NTP Service"
status: enabled
state: present
inventory_mode: manual
@@ -41,11 +41,11 @@
dns: ""
port: "12345"
macros:
- - macro: '{$EXAMPLEMACRO}'
+ - macro: "{$EXAMPLEMACRO}"
value: ExampleMacroValue
- macro: EXAMPLEMACRO2
value: ExampleMacroValue2
- description: Example desc that work only with Zabbix 4.4 and higher
+ description: Example desc
tags:
- tag: ExampleHostsTag
- tag: ExampleHostsTag2
@@ -53,7 +53,7 @@
register: zabbix_host1
- name: Update an existing host's tls settings
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost2
visible_name: ExampleName2
interfaces:
@@ -71,7 +71,7 @@
register: zabbix_host2
- name: expect both to succeed
- assert:
+ ansible.builtin.assert:
that:
- "zabbix_host1 is changed"
- "zabbix_host2 is changed"
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/tasks/zabbix_host_setup.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/tasks/zabbix_host_setup.yml
index 15e3e2fa5..924119467 100644
--- a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/tasks/zabbix_host_setup.yml
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/tasks/zabbix_host_setup.yml
@@ -2,14 +2,12 @@
# set up a zabbix proxy to test zabbix_host with
- name: Create a new proxy
- zabbix_proxy:
+ community.zabbix.zabbix_proxy:
proxy_name: ExampleProxy
description: ExampleProxy
status: active
state: present
interface:
- type: 0
- main: 1
useip: 1
ip: 10.5.6.7
dns: ""
@@ -17,7 +15,7 @@
register: zabbix_proxy
- name: Create Templates
- zabbix_template:
+ community.zabbix.zabbix_template:
template_name: "{{ item }}"
template_groups:
- Templates
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/tasks/zabbix_host_teardown.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/tasks/zabbix_host_teardown.yml
index 7eedcf12d..1617f449f 100644
--- a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/tasks/zabbix_host_teardown.yml
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/tasks/zabbix_host_teardown.yml
@@ -2,12 +2,12 @@
# remove zabbix_proxy (hopefully) created earlier
- name: remove proxy
- zabbix_proxy:
+ community.zabbix.zabbix_proxy:
proxy_name: ExampleProxy
state: absent
- name: remove Templates
- zabbix_template:
+ community.zabbix.zabbix_template:
template_name: "{{ item }}"
state: absent
with_items:
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/tasks/zabbix_host_tests.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/tasks/zabbix_host_tests.yml
index d72dbe318..a4829a051 100644
--- a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/tasks/zabbix_host_tests.yml
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host/tasks/zabbix_host_tests.yml
@@ -1,7 +1,6 @@
---
- name: "test: create host with many options set"
- zabbix_host:
- timeout: 30 # slower with py2.7
+ community.zabbix.zabbix_host:
host_name: ExampleHost
visible_name: ExampleName
description: My ExampleHost Description
@@ -9,8 +8,8 @@
- Linux servers
- Zabbix servers
link_templates:
- - "{{ 'IMAP Service' if zabbix_version | float >= 5.2 else 'Template App IMAP Service' }}"
- - "{{ 'NTP Service' if zabbix_version | float >= 5.2 else 'Template App NTP Service' }}"
+ - "IMAP Service"
+ - "NTP Service"
status: enabled
state: present
inventory_mode: manual
@@ -45,7 +44,7 @@
macros:
- macro: MACRO1
value: test1
- - macro: '{$MACRO2}'
+ - macro: "{$MACRO2}"
value: test2
tags:
- tag: Tag1
@@ -54,13 +53,12 @@
register: zabbix_host1
- name: expect to succeed and that things changed
- assert:
+ ansible.builtin.assert:
that:
- "zabbix_host1 is changed"
- name: "test: try to create the same host with the same settings"
- zabbix_host:
- timeout: 30 # slower with py2.7
+ community.zabbix.zabbix_host:
host_name: ExampleHost
visible_name: ExampleName
description: My ExampleHost Description
@@ -68,8 +66,8 @@
- Linux servers
- Zabbix servers
link_templates:
- - "{{ 'IMAP Service' if zabbix_version | float >= 5.2 else 'Template App IMAP Service' }}"
- - "{{ 'NTP Service' if zabbix_version | float >= 5.2 else 'Template App NTP Service' }}"
+ - "IMAP Service"
+ - "NTP Service"
status: enabled
state: present
inventory_mode: manual
@@ -104,7 +102,7 @@
macros:
- macro: MACRO1
value: test1
- - macro: '{$MACRO2}'
+ - macro: "{$MACRO2}"
value: test2
tags:
- tag: Tag1
@@ -113,14 +111,13 @@
register: zabbix_host1
- name: updating with same values should be idempotent
- assert:
+ ansible.builtin.assert:
that:
- "not zabbix_host1 is changed"
- name: "test: try to create the same host with the same settings and force false"
- zabbix_host:
+ community.zabbix.zabbix_host:
force: false
- timeout: 30 # slower with py2.7
host_name: ExampleHost
visible_name: ExampleName
description: My ExampleHost Description
@@ -128,8 +125,8 @@
- Linux servers
- Zabbix servers
link_templates:
- - "{{ 'IMAP Service' if zabbix_version | float >= 5.2 else 'Template App IMAP Service' }}"
- - "{{ 'NTP Service' if zabbix_version | float >= 5.2 else 'Template App NTP Service' }}"
+ - "IMAP Service"
+ - "NTP Service"
status: enabled
state: present
inventory_mode: manual
@@ -164,14 +161,13 @@
register: zabbix_host1
- name: updating with same values and force false should be idempotent
- assert:
+ ansible.builtin.assert:
that:
- "not zabbix_host1 is changed"
- name: "test: try to create the same host changing one parameter in the inventory with force false"
- zabbix_host:
+ community.zabbix.zabbix_host:
force: false
- timeout: 30 # slower with py2.7
host_name: ExampleHost
visible_name: ExampleName
description: My ExampleHost Description
@@ -179,8 +175,8 @@
- Linux servers
- Zabbix servers
link_templates:
- - "{{ 'IMAP Service' if zabbix_version | float >= 5.2 else 'Template App IMAP Service' }}"
- - "{{ 'NTP Service' if zabbix_version | float >= 5.2 else 'Template App NTP Service' }}"
+ - "IMAP Service"
+ - "NTP Service"
status: enabled
state: present
inventory_mode: manual
@@ -215,56 +211,56 @@
register: zabbix_host1
- name: changing the value of an already defined inventory should work and mark task as changed
- assert:
+ ansible.builtin.assert:
that:
- "zabbix_host1 is changed"
- name: "test: change visible_name"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
visible_name: "ExampleName Changed"
register: zabbix_host1
- name: expect to succeed and that things changed
- assert:
+ ansible.builtin.assert:
that:
- "zabbix_host1 is changed"
- name: "test: change visible_name (again)"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
visible_name: "ExampleName Changed"
register: zabbix_host1
- name: updating with same values should be idempotent
- assert:
+ ansible.builtin.assert:
that:
- "not zabbix_host1 is changed"
- name: "test: change description"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
description: "My ExampleHost Description Changed"
register: zabbix_host1
- name: expect to succeed and that things changed
- assert:
+ ansible.builtin.assert:
that:
- "zabbix_host1 is changed"
- name: "test: change description (again)"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
description: "My ExampleHost Description Changed"
register: zabbix_host1
- name: updating with same values should be idempotent
- assert:
+ ansible.builtin.assert:
that:
- "not zabbix_host1 is changed"
- name: "test: change host groups (adding one group)"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
host_groups:
- Linux servers
@@ -273,12 +269,12 @@
register: zabbix_host1
- name: expect to succeed and that things changed
- assert:
+ ansible.builtin.assert:
that:
- "zabbix_host1 is changed"
- name: "test: change host groups (remove one group)"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
host_groups:
- Linux servers
@@ -286,12 +282,12 @@
register: zabbix_host1
- name: expect to succeed and that things changed
- assert:
+ ansible.builtin.assert:
that:
- "zabbix_host1 is changed"
- name: "test: change host groups (add one group using force=no)"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
host_groups:
- Virtual machines
@@ -299,13 +295,12 @@
register: zabbix_host1
- name: expect to succeed and that things changed
- assert:
+ ansible.builtin.assert:
that:
- "zabbix_host1 is changed"
-
- name: "test: change host groups (check whether we are at three groups)"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
host_groups:
- Linux servers
@@ -314,12 +309,12 @@
register: zabbix_host1
- name: expect to succeed and that things have not changed
- assert:
+ ansible.builtin.assert:
that:
- "not zabbix_host1 is changed"
- name: "test: change host groups (attempt to remove all host groups)"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
# list with empty value, expected:
host_groups:
@@ -328,136 +323,133 @@
ignore_errors: true
- name: expect to fail
- assert:
+ ansible.builtin.assert:
that:
- "zabbix_host1 is failed"
- name: "test: change host linked templates (same as before)"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
link_templates:
- - "{{ 'IMAP Service' if zabbix_version | float >= 5.2 else 'Template App IMAP Service' }}"
- - "{{ 'NTP Service' if zabbix_version | float >= 5.2 else 'Template App NTP Service' }}"
+ - "IMAP Service"
+ - "NTP Service"
register: zabbix_host1
- name: expect to succeed and that things have not changed
- assert:
+ ansible.builtin.assert:
that:
- "not zabbix_host1 is changed"
- name: "test: change host linked templates (add one template)"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
link_templates:
- - "{{ 'IMAP Service' if zabbix_version | float >= 5.2 else 'Template App IMAP Service' }}"
- - "{{ 'NTP Service' if zabbix_version | float >= 5.2 else 'Template App NTP Service' }}"
- - "{{ 'HTTP Service' if zabbix_version | float >= 5.2 else 'Template App HTTP Service' }}"
+ - "IMAP Service"
+ - "NTP Service"
+ - "HTTP Service"
register: zabbix_host1
- name: expect to succeed and that things have changed
- assert:
+ ansible.builtin.assert:
that:
- "zabbix_host1 is changed"
- name: "test: change host linked templates (add one template, using force=no)"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
link_templates:
- - "{{ 'LDAP Service' if zabbix_version | float >= 5.2 else 'Template App LDAP Service' }}"
+ - "LDAP Service"
force: false
register: zabbix_host1
- name: expect to succeed and that things have changed
- assert:
+ ansible.builtin.assert:
that:
- "zabbix_host1 is changed"
- name: "test: change host linked templates (make sure we are at 4 templates)"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
link_templates:
- - "{{ 'IMAP Service' if zabbix_version | float >= 5.2 else 'Template App IMAP Service' }}"
- - "{{ 'NTP Service' if zabbix_version | float >= 5.2 else 'Template App NTP Service' }}"
- - "{{ 'HTTP Service' if zabbix_version | float >= 5.2 else 'Template App HTTP Service' }}"
- - "{{ 'LDAP Service' if zabbix_version | float >= 5.2 else 'Template App LDAP Service' }}"
+ - "IMAP Service"
+ - "NTP Service"
+ - "HTTP Service"
+ - "LDAP Service"
register: zabbix_host1
- name: expect to succeed and that things have not changed
- assert:
+ ansible.builtin.assert:
that:
- "not zabbix_host1 is changed"
- name: "test: change host linked templates (remove all templates)"
- zabbix_host:
- timeout: 60 # slower with py2.7
+ community.zabbix.zabbix_host:
host_name: ExampleHost
- link_templates:
- -
+ link_templates: []
register: zabbix_host1
- name: expect to succeed and that things have changed
- assert:
+ ansible.builtin.assert:
that:
- "zabbix_host1 is changed"
- name: "test: change host linked templates (check we have no templates left)"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
- link_templates:
- -
+ link_templates: []
register: zabbix_host1
- name: expect to succeed and that things have not changed
- assert:
+ ansible.builtin.assert:
that:
- "not zabbix_host1 is changed"
- name: "test: change host status"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
status: disabled
register: zabbix_host1
- name: expect to succeed and that things have changed
- assert:
+ ansible.builtin.assert:
that:
- "zabbix_host1 is changed"
- name: "test: change host status (again)"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
status: disabled
register: zabbix_host1
- name: expect to succeed and that things have not changed
- assert:
+ ansible.builtin.assert:
that:
- "not zabbix_host1 is changed"
- name: "test: change host inventory mode"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
inventory_mode: automatic
register: zabbix_host1
- name: expect to succeed and that things have changed
- assert:
+ ansible.builtin.assert:
that:
- "zabbix_host1 is changed"
- name: "test: change host inventory mode"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
inventory_mode: automatic
register: zabbix_host1
- name: expect to succeed and that things have not changed
- assert:
+ ansible.builtin.assert:
that:
- "not zabbix_host1 is changed"
- name: "test: change host inventory data (one field)"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
inventory_zabbix:
tag: test-tag-two
@@ -470,12 +462,12 @@
register: zabbix_host1
- name: expect to succeed and that things have changed
- assert:
+ ansible.builtin.assert:
that:
- "zabbix_host1 is changed"
- name: "test: change host inventory data (again)"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
inventory_zabbix:
tag: test-tag-two
@@ -488,45 +480,45 @@
register: zabbix_host1
- name: expect to succeed and that things have not changed
- assert:
+ ansible.builtin.assert:
that:
- "not zabbix_host1 is changed"
- name: "test: remove host proxy"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
- proxy: ''
+ proxy: ""
register: zabbix_host1
- name: expect to succeed and that things have changed
- assert:
+ ansible.builtin.assert:
that:
- "zabbix_host1 is changed"
- name: "test: add host proxy"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
proxy: ExampleProxy
register: zabbix_host1
- name: expect to succeed and that things have changed
- assert:
+ ansible.builtin.assert:
that:
- "zabbix_host1 is changed"
- name: "test: add host proxy (again)"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
proxy: ExampleProxy
register: zabbix_host1
- name: expect to succeed and that things have not changed
- assert:
+ ansible.builtin.assert:
that:
- "not zabbix_host1 is changed"
- name: "test: change tls certificate settings"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
tls_connect: 4
tls_accept: 4
@@ -535,12 +527,12 @@
register: zabbix_host1
- name: expect to succeed and that things have changed
- assert:
+ ansible.builtin.assert:
that:
- "zabbix_host1 is changed"
- name: "test: change tls certificate settings (again)"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
tls_connect: 4
tls_accept: 4
@@ -549,12 +541,12 @@
register: zabbix_host1
- name: expect to succeed and that things have not changed
- assert:
+ ansible.builtin.assert:
that:
- "not zabbix_host1 is changed"
- name: "test: change tls psk (write-only) settings"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
tls_connect: 2
tls_accept: 2
@@ -563,11 +555,11 @@
register: zabbix_host1
- name: expect to succeed and that things have changed
- assert:
+ ansible.builtin.assert:
that: zabbix_host1 is changed
- name: "test: change tls psk (write-only) settings (again)"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
tls_connect: 2
tls_accept: 2
@@ -576,17 +568,11 @@
register: zabbix_host1
- name: expect to succeed and that things have changed (tls_psk makes module non-idempotent)
- assert:
+ ansible.builtin.assert:
that: zabbix_host1 is changed
- when: zabbix_version is version('5.4', '>=')
-
-- name: expect to succeed and that things have not changed
- assert:
- that: zabbix_host1 is not changed
- when: zabbix_version is version('5.4', '<')
- name: "test: change interface settings (remove one)"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
interfaces:
- type: 1
@@ -598,12 +584,12 @@
register: zabbix_host1
- name: expect to succeed and that things have changed
- assert:
+ ansible.builtin.assert:
that:
- "zabbix_host1 is changed"
- name: "test: change interface settings (again)"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
interfaces:
- type: 1
@@ -615,12 +601,12 @@
register: zabbix_host1
- name: expect to succeed and that things have not changed
- assert:
+ ansible.builtin.assert:
that:
- "not zabbix_host1 is changed"
- name: "test: change interface settings (add one interface using force=no)"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
interfaces:
- type: 4
@@ -633,12 +619,12 @@
register: zabbix_host1
- name: expect to succeed and that things have changed
- assert:
+ ansible.builtin.assert:
that:
- "zabbix_host1 is changed"
- name: "test: change interface settings (verify that we are at two interfaces)"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
interfaces:
- type: 1
@@ -656,12 +642,12 @@
register: zabbix_host1
- name: expect to succeed and that things have not changed
- assert:
+ ansible.builtin.assert:
that:
- "not zabbix_host1 is changed"
- name: "test: configure interface to useip=1 but provide no ip"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
interfaces:
- type: 1
@@ -677,12 +663,12 @@
ignore_errors: true
- name: expect to fail
- assert:
+ ansible.builtin.assert:
that:
- "zabbix_host1 is failed"
- name: "test: configure interface to useip=0 but provide no dns"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
interfaces:
- type: 1
@@ -699,217 +685,214 @@
ignore_errors: true
- name: expect to fail
- assert:
+ ansible.builtin.assert:
+ that:
+ - "zabbix_host1 is failed"
+
+- name: "test: configure SNMPv2 interface without details (fail)"
+ community.zabbix.zabbix_host:
+ host_name: ExampleHost
+ interfaces:
+ - type: 1
+ main: 1
+ useip: 1
+ ip: 10.1.1.1
+ port: "10050"
+ - type: 2
+ main: 1
+ useip: 1
+ ip: 10.1.1.1
+ port: "161"
+ register: zabbix_host1
+ ignore_errors: true
+
+- name: expect to fail
+ ansible.builtin.assert:
that:
- "zabbix_host1 is failed"
-- when: zabbix_version is version("5.0", ">=")
- block:
- - name: "test: configure SNMPv2 interface without details (fail)"
- zabbix_host:
- host_name: ExampleHost
- interfaces:
- - type: 1
- main: 1
- useip: 1
- ip: 10.1.1.1
- port: "10050"
- - type: 2
- main: 1
- useip: 1
- ip: 10.1.1.1
- port: "161"
- register: zabbix_host1
- ignore_errors: true
-
- - name: expect to fail
- assert:
- that:
- - "zabbix_host1 is failed"
-
- - name: "test: configure details for SNMPv2 interface"
- zabbix_host:
- host_name: ExampleHost
- interfaces:
- - type: 1
- main: 1
- useip: 1
- ip: 10.1.1.1
- port: "10050"
- - type: 2
- main: 1
- useip: 1
- ip: 10.1.1.1
- port: "161"
- details:
- version: 2
- community: Community String
- register: zabbix_host1
-
- - name: expect to succeed and that things have changed
- assert:
- that:
- - "zabbix_host1 is changed"
-
- - name: "test: configure details for SNMPv2 interface (again)"
- zabbix_host:
- host_name: ExampleHost
- interfaces:
- - type: 1
- main: 1
- useip: 1
- ip: 10.1.1.1
- port: "10050"
- - type: 2
- main: 1
- useip: 1
- ip: 10.1.1.1
- port: "161"
- details:
- version: 2
- community: Community String
- register: zabbix_host1
-
- - name: expect to succeed and that things have not changed
- assert:
- that:
- - "zabbix_host1 is not changed"
-
- - name: "test: configure SNMPv2 interface with the same options and force=False "
- zabbix_host:
- host_name: ExampleHost
- force: False
- interfaces:
- - type: 1
- main: 1
- useip: 1
- ip: 10.1.1.1
- port: "10050"
- - type: 2
- main: 1
- useip: 1
- ip: 10.1.1.1
- port: "161"
- details:
- version: 2
- community: Community String
- register: zabbix_host1
-
- - name: expect to succeed and that things have not changed
- assert:
- that:
- - "zabbix_host1 is not changed"
-
- - name: "test: update details for SNMPv2 interface with bulk sub option"
- zabbix_host:
- host_name: ExampleHost
- interfaces:
- - type: 1
- main: 1
- useip: 1
- ip: 10.1.1.1
- port: "10050"
- - type: 2
- main: 1
- useip: 1
- ip: 10.1.1.1
- port: "161"
- details:
- version: 2
- community: Community String
- bulk: 0
- register: zabbix_host1
-
- - name: expect to succeed and that things have changed
- assert:
- that:
- - "zabbix_host1 is changed"
-
- - name: "test: configure details for SNMPv3 interface"
- zabbix_host:
- host_name: ExampleHost
- interfaces:
- - type: 1
- main: 1
- useip: 1
- ip: 10.1.1.1
- port: "10050"
- - type: 2
- main: 1
- useip: 1
- ip: 10.1.1.1
- port: "161"
- details:
- version: 3
- contextname: snmp_context
- securityname: SNMP3 sec name
- securitylevel: 0
- register: zabbix_host1
-
- - name: expect to succeed and that things have changed
- assert:
- that:
- - "zabbix_host1 is changed"
-
- - name: "test: configure details for SNMPv3 interface (again)"
- zabbix_host:
- host_name: ExampleHost
- interfaces:
- - type: 1
- main: 1
- useip: 1
- ip: 10.1.1.1
- port: "10050"
- - type: 2
- main: 1
- useip: 1
- ip: 10.1.1.1
- port: "161"
- details:
- version: 3
- contextname: snmp_context
- securityname: SNMP3 sec name
- securitylevel: 0
- register: zabbix_host1
-
- - name: expect to succeed and that things have not changed
- assert:
- that:
- - "zabbix_host1 is not changed"
-
- - name: "test: update details for SNMPv3 interface"
- zabbix_host:
- host_name: ExampleHost
- interfaces:
- - type: 1
- main: 1
- useip: 1
- ip: 10.1.1.1
- port: "10050"
- - type: 2
- main: 1
- useip: 1
- ip: 10.1.1.1
- port: "161"
- details:
- version: 3
- contextname: snmp_context
- securityname: SNMP3 sec name
- securitylevel: 2
- authprotocol: "{{ 2 if zabbix_version | float >= 5.4 else 0 }}"
- authpassphrase: secret_auth_passphrase
- privprotocol: "{{ 2 if zabbix_version | float >= 5.4 else 0 }}"
- privpassphrase: secret_priv_passphrase
- register: zabbix_host1
-
- - name: expect to succeed and that things have changed
- assert:
- that:
- - "zabbix_host1 is changed"
-
-# https://github.com/ansible-collections/community.zabbix/pull/391
+- name: "test: configure details for SNMPv2 interface"
+ community.zabbix.zabbix_host:
+ host_name: ExampleHost
+ interfaces:
+ - type: 1
+ main: 1
+ useip: 1
+ ip: 10.1.1.1
+ port: "10050"
+ - type: 2
+ main: 1
+ useip: 1
+ ip: 10.1.1.1
+ port: "161"
+ details:
+ version: 2
+ community: Community String
+ register: zabbix_host1
+
+- name: expect to succeed and that things have changed
+ ansible.builtin.assert:
+ that:
+ - "zabbix_host1 is changed"
+
+- name: "test: configure details for SNMPv2 interface (again)"
+ community.zabbix.zabbix_host:
+ host_name: ExampleHost
+ interfaces:
+ - type: 1
+ main: 1
+ useip: 1
+ ip: 10.1.1.1
+ port: "10050"
+ - type: 2
+ main: 1
+ useip: 1
+ ip: 10.1.1.1
+ port: "161"
+ details:
+ version: 2
+ community: Community String
+ register: zabbix_host1
+
+- name: expect to succeed and that things have not changed
+ ansible.builtin.assert:
+ that:
+ - "zabbix_host1 is not changed"
+
+- name: "test: configure SNMPv2 interface with the same options and force=False "
+ community.zabbix.zabbix_host:
+ host_name: ExampleHost
+ force: False
+ interfaces:
+ - type: 1
+ main: 1
+ useip: 1
+ ip: 10.1.1.1
+ port: "10050"
+ - type: 2
+ main: 1
+ useip: 1
+ ip: 10.1.1.1
+ port: "161"
+ details:
+ version: 2
+ community: Community String
+ register: zabbix_host1
+
+- name: expect to succeed and that things have not changed
+ ansible.builtin.assert:
+ that:
+ - "zabbix_host1 is not changed"
+
+- name: "test: update details for SNMPv2 interface with bulk sub option"
+ community.zabbix.zabbix_host:
+ host_name: ExampleHost
+ interfaces:
+ - type: 1
+ main: 1
+ useip: 1
+ ip: 10.1.1.1
+ port: "10050"
+ - type: 2
+ main: 1
+ useip: 1
+ ip: 10.1.1.1
+ port: "161"
+ details:
+ version: 2
+ community: Community String
+ bulk: 0
+ register: zabbix_host1
+
+- name: expect to succeed and that things have changed
+ ansible.builtin.assert:
+ that:
+ - "zabbix_host1 is changed"
+
+- name: "test: configure details for SNMPv3 interface"
+ community.zabbix.zabbix_host:
+ host_name: ExampleHost
+ interfaces:
+ - type: 1
+ main: 1
+ useip: 1
+ ip: 10.1.1.1
+ port: "10050"
+ - type: 2
+ main: 1
+ useip: 1
+ ip: 10.1.1.1
+ port: "161"
+ details:
+ version: 3
+ contextname: snmp_context
+ securityname: SNMP3 sec name
+ securitylevel: 0
+ register: zabbix_host1
+
+- name: expect to succeed and that things have changed
+ ansible.builtin.assert:
+ that:
+ - "zabbix_host1 is changed"
+
+- name: "test: configure details for SNMPv3 interface (again)"
+ community.zabbix.zabbix_host:
+ host_name: ExampleHost
+ interfaces:
+ - type: 1
+ main: 1
+ useip: 1
+ ip: 10.1.1.1
+ port: "10050"
+ - type: 2
+ main: 1
+ useip: 1
+ ip: 10.1.1.1
+ port: "161"
+ details:
+ version: 3
+ contextname: snmp_context
+ securityname: SNMP3 sec name
+ securitylevel: 0
+ register: zabbix_host1
+
+- name: expect to succeed and that things have not changed
+ ansible.builtin.assert:
+ that:
+ - "zabbix_host1 is not changed"
+
+- name: "test: update details for SNMPv3 interface"
+ community.zabbix.zabbix_host:
+ host_name: ExampleHost
+ interfaces:
+ - type: 1
+ main: 1
+ useip: 1
+ ip: 10.1.1.1
+ port: "10050"
+ - type: 2
+ main: 1
+ useip: 1
+ ip: 10.1.1.1
+ port: "161"
+ details:
+ version: 3
+ contextname: snmp_context
+ securityname: SNMP3 sec name
+ securitylevel: 2
+ authprotocol: "{{ 2 if zabbix_version | float >= 5.4 else 0 }}"
+ authpassphrase: secret_auth_passphrase
+ privprotocol: "{{ 2 if zabbix_version | float >= 5.4 else 0 }}"
+ privpassphrase: secret_priv_passphrase
+ register: zabbix_host1
+
+- name: expect to succeed and that things have changed
+ ansible.builtin.assert:
+ that:
+ - "zabbix_host1 is changed"
+
- name: "reset interfaces to two of the same type"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
interfaces:
- type: "1"
@@ -922,12 +905,12 @@
register: zabbix_host1
- name: expect to succeed and that things have changed
- assert:
+ ansible.builtin.assert:
that:
- "zabbix_host1 is changed"
- name: "reset interfaces to two of the same type (again)"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
interfaces:
- type: "1"
@@ -940,12 +923,12 @@
register: zabbix_host1
- name: expect to succeed and that things have not changed
- assert:
+ ansible.builtin.assert:
that:
- "zabbix_host1 is not changed"
- name: "test: add IPMI settings"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
ipmi_authtype: 2
ipmi_privilege: 4
@@ -954,12 +937,12 @@
register: zabbix_host1
- name: expect to succeed and that things have changed
- assert:
+ ansible.builtin.assert:
that:
- "zabbix_host1 is changed"
- name: "test: add IPMI settings again"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
ipmi_authtype: 2
ipmi_privilege: 4
@@ -968,22 +951,22 @@
register: zabbix_host1
- name: expect to succeed and that things have not changed
- assert:
+ ansible.builtin.assert:
that:
- "zabbix_host1 is not changed"
- name: "test: verify that an empty change is idempotent"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
register: zabbix_host1
- name: expect to succeed and that things have not changed
- assert:
+ ansible.builtin.assert:
that:
- "zabbix_host1 is not changed"
- name: "test: IPMI set default values"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
ipmi_authtype: -1
ipmi_privilege: 2
@@ -992,12 +975,12 @@
register: zabbix_host1
- name: expect to succeed and that things have changed
- assert:
+ ansible.builtin.assert:
that:
- "zabbix_host1 is changed"
- name: "test: IPMI set default values (again)"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
ipmi_authtype: -1
ipmi_privilege: 2
@@ -1006,380 +989,366 @@
register: zabbix_host1
- name: expect to succeed and that things have not changed
- assert:
+ ansible.builtin.assert:
that:
- "zabbix_host1 is not changed"
- name: "test: change host inventory mode to disabled"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
inventory_mode: disabled
register: zabbix_host1
- name: expect to succeed and that things have changed
- assert:
+ ansible.builtin.assert:
that:
- "zabbix_host1 is changed"
- name: "test: change host inventory mode to manual"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
inventory_mode: manual
register: zabbix_host1
- name: expect to succeed and that things have changed
- assert:
+ ansible.builtin.assert:
that:
- "zabbix_host1 is changed"
- name: "test: add new set of user macros to the host"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
macros:
- - macro: '{$NEWMACRO1}'
+ - macro: "{$NEWMACRO1}"
value: test123
- macro: NEWMACRO2
value: abc
register: zabbix_host1
- name: expect to succeed and that things have changed
- assert:
+ ansible.builtin.assert:
that:
- "zabbix_host1 is changed"
- name: "test: add new set of user macros to the host (again - lowercase)"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
macros:
- - macro: '{$newmacro1}'
+ - macro: "{$newmacro1}"
value: test123
- macro: newmacro2
value: abc
register: zabbix_host1
- name: expect to succeed and that things have not changed
- assert:
+ ansible.builtin.assert:
that:
- "zabbix_host1 is not changed"
- name: "test: update one of the user macros present on the host"
- zabbix_host:
+ community.zabbix.zabbix_host:
+ host_name: ExampleHost
+ macros:
+ - macro: "{$NEWMACRO1}"
+ value: test1234
+ - macro: NEWMACRO2
+ value: abc
+ register: zabbix_host1
+
+- name: expect to succeed and that things have changed
+ ansible.builtin.assert:
+ that:
+ - "zabbix_host1 is changed"
+
+- name: "test: update one of the user macros with description"
+ community.zabbix.zabbix_host:
host_name: ExampleHost
macros:
- - macro: '{$NEWMACRO1}'
+ - macro: "{$NEWMACRO1}"
value: test1234
+ description: Example Description
- macro: NEWMACRO2
value: abc
register: zabbix_host1
- name: expect to succeed and that things have changed
- assert:
+ ansible.builtin.assert:
that:
- "zabbix_host1 is changed"
-# The description of tag is available since Zabbix version 4.4
-- when: zabbix_version is version("4.4", ">=")
- block:
- - name: "test: update one of the user macros with description"
- zabbix_host:
- host_name: ExampleHost
- macros:
- - macro: '{$NEWMACRO1}'
- value: test1234
- description: Example Description
- - macro: NEWMACRO2
- value: abc
- register: zabbix_host1
-
- - name: expect to succeed and that things have changed
- assert:
- that:
- - "zabbix_host1 is changed"
-
- - name: "test: update one of the user macros with description (again)"
- zabbix_host:
- host_name: ExampleHost
- macros:
- - macro: '{$NEWMACRO1}'
- value: test1234
- description: Example Description
- - macro: NEWMACRO2
- value: abc
- register: zabbix_host1
-
- - name: expect to succeed and that things have not changed
- assert:
- that:
- - "zabbix_host1 is not changed"
-
- - name: "test: update one of the user macros by removing description"
- zabbix_host:
- host_name: ExampleHost
- macros:
- - macro: '{$NEWMACRO1}'
- value: test1234
- - macro: NEWMACRO2
- value: abc
- register: zabbix_host1
-
- - name: expect to succeed and that things have changed
- assert:
- that:
- - "zabbix_host1 is changed"
+- name: "test: update one of the user macros with description (again)"
+ community.zabbix.zabbix_host:
+ host_name: ExampleHost
+ macros:
+ - macro: "{$NEWMACRO1}"
+ value: test1234
+ description: Example Description
+ - macro: NEWMACRO2
+ value: abc
+ register: zabbix_host1
+
+- name: expect to succeed and that things have not changed
+ ansible.builtin.assert:
+ that:
+ - "zabbix_host1 is not changed"
+
+- name: "test: update one of the user macros by removing description"
+ community.zabbix.zabbix_host:
+ host_name: ExampleHost
+ macros:
+ - macro: "{$NEWMACRO1}"
+ value: test1234
+ - macro: NEWMACRO2
+ value: abc
+ register: zabbix_host1
+
+- name: expect to succeed and that things have changed
+ ansible.builtin.assert:
+ that:
+ - "zabbix_host1 is changed"
- name: "test: add user macro while keeping previous ones with force=no"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
force: false
macros:
- - macro: '{$NEWMACRO3}'
+ - macro: "{$NEWMACRO3}"
value: testing
register: zabbix_host1
- name: expect to succeed and that things have changed
- assert:
+ ansible.builtin.assert:
that:
- "zabbix_host1 is changed"
- name: "test: add user macro while keeping previous ones with force=no (again)"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
force: false
macros:
- - macro: '{$NEWMACRO3}'
+ - macro: "{$NEWMACRO3}"
value: testing
register: zabbix_host1
- name: expect to succeed and that things have not changed
- assert:
+ ansible.builtin.assert:
that:
- "zabbix_host1 is not changed"
- name: "test: add the same user macros (again)"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
macros:
- - macro: '{$NEWMACRO1}'
+ - macro: "{$NEWMACRO1}"
value: test1234
- macro: NEWMACRO2
value: abc
- - macro: '{$NEWMACRO3}'
+ - macro: "{$NEWMACRO3}"
value: testing
register: zabbix_host1
- name: expect to succeed and that things have not changed
- assert:
+ ansible.builtin.assert:
that:
- "zabbix_host1 is not changed"
-# type for macros added in 5.0
-- when: zabbix_version is version("5.0", ">=")
- block:
- - name: "test: add new user macro with type secret"
- zabbix_host:
- host_name: ExampleHost
- macros:
- - macro: '{$NEWMACROSECRET}'
- value: secretvalue
- type: secret
- register: zabbix_host1
-
- - name: expect to succeed and that things have changed
- assert:
- that:
- - "zabbix_host1 is changed"
-
- - name: "test: add new user macro with type secret (again)"
- zabbix_host:
- host_name: ExampleHost
- macros:
- - macro: '{$NEWMACROSECRET}'
- value: secretvalue
- type: secret
- register: zabbix_host1
-
- - name: expect to succeed and that things have changed as it has secret value
- assert:
- that:
- - "zabbix_host1 is changed"
+- name: "test: add new user macro with type secret"
+ community.zabbix.zabbix_host:
+ host_name: ExampleHost
+ macros:
+ - macro: "{$NEWMACROSECRET}"
+ value: secretvalue
+ type: secret
+ register: zabbix_host1
+
+- name: expect to succeed and that things have changed
+ ansible.builtin.assert:
+ that:
+ - "zabbix_host1 is changed"
+
+- name: "test: add new user macro with type secret (again)"
+ community.zabbix.zabbix_host:
+ host_name: ExampleHost
+ macros:
+ - macro: "{$NEWMACROSECRET}"
+ value: secretvalue
+ type: secret
+ register: zabbix_host1
+
+- name: expect to succeed and that things have changed as it has secret value
+ ansible.builtin.assert:
+ that:
+ - "zabbix_host1 is changed"
- name: "test: wipe out all of the user macros"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
macros: []
register: zabbix_host1
- name: expect to succeed and that things have changed
- assert:
+ ansible.builtin.assert:
that:
- "zabbix_host1 is changed"
- name: "test: wipe out all of the user macros (again)"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
macros: []
register: zabbix_host1
- name: expect to succeed and that things have not changed
- assert:
+ ansible.builtin.assert:
that:
- "zabbix_host1 is not changed"
-# The tag function is available since Zabbix version 4.4
-- when: zabbix_version is version("4.4", ">=")
- block:
- - name: "test: add new set of tags to the host"
- zabbix_host:
- host_name: ExampleHost
- tags:
- - tag: NEWTAG1
- - tag: NewTag2
- value: abc
- register: zabbix_host1
-
- - name: expect to succeed and that things have changed
- assert:
- that:
- - "zabbix_host1 is changed"
-
- - name: "test: add new set of tags to the host (again)"
- zabbix_host:
- host_name: ExampleHost
- tags:
- - tag: NEWTAG1
- - tag: NewTag2
- value: abc
- register: zabbix_host1
-
- - name: expect to succeed and that things have not changed
- assert:
- that:
- - "zabbix_host1 is not changed"
-
- - name: "test: update one of the tags present on the host"
- zabbix_host:
- host_name: ExampleHost
- tags:
- - tag: NEWTAG1
- - tag: NewTag2
- value: abcd
- register: zabbix_host1
-
- - name: expect to succeed and that things have changed
- assert:
- that:
- - "zabbix_host1 is changed"
-
- - name: "test: add tag while keeping previous ones with force=no"
- zabbix_host:
- host_name: ExampleHost
- force: false
- tags:
- - tag: newtag3
- value: testing
- register: zabbix_host1
-
- - name: expect to succeed and that things have changed
- assert:
- that:
- - "zabbix_host1 is changed"
-
- - name: "test: add the same tags (again)"
- zabbix_host:
- host_name: ExampleHost
- tags:
- - tag: NEWTAG1
- - tag: NewTag2
- value: abcd
- - tag: newtag3
- value: testing
- register: zabbix_host1
-
- - name: expect to succeed and that things have not changed
- assert:
- that:
- - "zabbix_host1 is not changed"
-
- - name: "test: wipe out all of the tags"
- zabbix_host:
- host_name: ExampleHost
- tags: []
- register: zabbix_host1
-
- - name: expect to succeed and that things have changed
- assert:
- that:
- - "zabbix_host1 is changed"
+- name: "test: add new set of tags to the host"
+ community.zabbix.zabbix_host:
+ host_name: ExampleHost
+ tags:
+ - tag: NEWTAG1
+ - tag: NewTag2
+ value: abc
+ register: zabbix_host1
+
+- name: expect to succeed and that things have changed
+ ansible.builtin.assert:
+ that:
+ - "zabbix_host1 is changed"
+
+- name: "test: add new set of tags to the host (again)"
+ community.zabbix.zabbix_host:
+ host_name: ExampleHost
+ tags:
+ - tag: NEWTAG1
+ - tag: NewTag2
+ value: abc
+ register: zabbix_host1
+
+- name: expect to succeed and that things have not changed
+ ansible.builtin.assert:
+ that:
+ - "zabbix_host1 is not changed"
+
+- name: "test: update one of the tags present on the host"
+ community.zabbix.zabbix_host:
+ host_name: ExampleHost
+ tags:
+ - tag: NEWTAG1
+ - tag: NewTag2
+ value: abcd
+ register: zabbix_host1
+
+- name: expect to succeed and that things have changed
+ ansible.builtin.assert:
+ that:
+ - "zabbix_host1 is changed"
+
+- name: "test: add tag while keeping previous ones with force=no"
+ community.zabbix.zabbix_host:
+ host_name: ExampleHost
+ force: false
+ tags:
+ - tag: newtag3
+ value: testing
+ register: zabbix_host1
+
+- name: expect to succeed and that things have changed
+ ansible.builtin.assert:
+ that:
+ - "zabbix_host1 is changed"
+
+- name: "test: add the same tags (again)"
+ community.zabbix.zabbix_host:
+ host_name: ExampleHost
+ tags:
+ - tag: NEWTAG1
+ - tag: NewTag2
+ value: abcd
+ - tag: newtag3
+ value: testing
+ register: zabbix_host1
+
+- name: expect to succeed and that things have not changed
+ ansible.builtin.assert:
+ that:
+ - "zabbix_host1 is not changed"
+
+- name: "test: wipe out all of the tags"
+ community.zabbix.zabbix_host:
+ host_name: ExampleHost
+ tags: []
+ register: zabbix_host1
+
+- name: expect to succeed and that things have changed
+ ansible.builtin.assert:
+ that:
+ - "zabbix_host1 is changed"
- name: "test: wipe out all of the tags (again)"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
tags: []
register: zabbix_host1
- name: expect to succeed and that things have not changed
- assert:
+ ansible.builtin.assert:
that:
- "zabbix_host1 is not changed"
- name: "test: attempt to delete host created earlier"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
state: absent
register: zabbix_host1
- name: deleting a host is a change, right?
- assert:
+ ansible.builtin.assert:
that:
- "zabbix_host1 is changed"
- name: "test: attempt deleting a non-existant host"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHost
state: absent
register: zabbix_host1
- name: deleting a non-existant host is not a change, right?
- assert:
+ ansible.builtin.assert:
that:
- "not zabbix_host1 is changed"
-- when: zabbix_version is version('5.2', '>=')
- block:
- - name: "test: create host without host interfaces"
- zabbix_host:
- host_name: ExampleHost
- visible_name: ExampleName
- description: My ExampleHost Description
- host_groups:
- - Linux servers
- status: disabled
- state: present
- register: zbx_host_create_interfaceless
-
- - name: verify host was created without interfaces
- assert:
- that: zbx_host_create_interfaceless is changed
-
- - name: "test: create host without host interfaces (again)"
- zabbix_host:
- server_url: "{{ zabbix_api_server_url }}"
- login_user: "{{ zabbix_api_login_user }}"
- login_password: "{{ zabbix_api_login_pass }}"
- host_name: ExampleHost
- visible_name: ExampleName
- description: My ExampleHost Description
- host_groups:
- - Linux servers
- status: disabled
- state: present
- register: zbx_host_create_interfaceless
-
- - name: expect to succeed and that things have not changed
- assert:
- that: zbx_host_create_interfaceless is not changed
-
- - name: "cleanup"
- zabbix_host:
- host_name: ExampleHost
- state: absent
+- name: "test: create host without host interfaces"
+ community.zabbix.zabbix_host:
+ host_name: ExampleHost
+ visible_name: ExampleName
+ description: My ExampleHost Description
+ host_groups:
+ - Linux servers
+ status: disabled
+ state: present
+ register: zbx_host_create_interfaceless
+
+- name: verify host was created without interfaces
+ ansible.builtin.assert:
+ that: zbx_host_create_interfaceless is changed
+
+- name: "test: create host without host interfaces (again)"
+ community.zabbix.zabbix_host:
+ host_name: ExampleHost
+ visible_name: ExampleName
+ description: My ExampleHost Description
+ host_groups:
+ - Linux servers
+ status: disabled
+ state: present
+ register: zbx_host_create_interfaceless
+
+- name: expect to succeed and that things have not changed
+ ansible.builtin.assert:
+ that: zbx_host_create_interfaceless is not changed
+
+- name: "cleanup"
+ community.zabbix.zabbix_host:
+ host_name: ExampleHost
+ state: absent
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host_info/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host_info/tasks/main.yml
index dfcaf097d..72c2f6364 100644
--- a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host_info/tasks/main.yml
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_host_info/tasks/main.yml
@@ -1,6 +1,6 @@
---
- name: "test - Prepare host for zabbix_host_info module"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: ExampleHostForHostInfoModule
visible_name: ExampleHostForHostInfoModuleName
description: Test Host
@@ -8,7 +8,7 @@
- Linux servers
- Hypervisors
link_templates:
- - "{{ 'Zabbix server health' if zabbix_version | float >= 5.4 else 'Template App Zabbix Server' }}"
+ - Zabbix server health
status: enabled
inventory_mode: manual
inventory_zabbix:
@@ -24,7 +24,7 @@
state: present
register: prepare_host_result
-- assert:
+- ansible.builtin.assert:
that:
- prepare_host_result.changed is sameas true
@@ -35,7 +35,7 @@
environment:
ZABBIX_VALIDATE_CERTS: false
-- assert:
+- ansible.builtin.assert:
that:
- env_vars_usage.hosts[0].name == "ExampleHostForHostInfoModuleName"
@@ -46,53 +46,11 @@
block:
- name: "test - Gather all facts of zabbix host"
- zabbix_host_info:
+ community.zabbix.zabbix_host_info:
register: gather_all_facts_result
- - when: zabbix_version is version('4.0', '<=')
- assert:
- that:
- - gather_all_facts_result.hosts | length == 1
- - gather_all_facts_result.hosts.0.host == "ExampleHostForHostInfoModule"
- - gather_all_facts_result.hosts.0.name == "ExampleHostForHostInfoModuleName"
- - gather_all_facts_result.hosts.0.description == "Test Host"
- - gather_all_facts_result.hosts.0.groups.0.name == "Linux servers"
- - gather_all_facts_result.hosts.0.groups.1.name == "Hypervisors"
- - gather_all_facts_result.hosts.0.parentTemplates.0.name == "Template App Zabbix Server"
- - gather_all_facts_result.hosts.0.status == "0"
- - gather_all_facts_result.hosts.0.inventory.inventory_mode == "0"
- - gather_all_facts_result.hosts.0.inventory.tag == "tag1"
- - gather_all_facts_result.hosts.0.inventory.os == "Linux"
- - gather_all_facts_result.hosts.0.hostinterfaces.0.dns == ""
- - gather_all_facts_result.hosts.0.hostinterfaces.0.ip == "192.168.0.1"
- - gather_all_facts_result.hosts.0.hostinterfaces.0.main == "1"
- - gather_all_facts_result.hosts.0.hostinterfaces.0.port == "10050"
- - gather_all_facts_result.hosts.0.hostinterfaces.0.type == "1"
- - gather_all_facts_result.hosts.0.hostinterfaces.0.useip == "1"
-
- - when: zabbix_version is version('4.4', '>=') and zabbix_version is version('5.0', '<=')
- assert:
- that:
- - gather_all_facts_result.hosts | length == 1
- - gather_all_facts_result.hosts.0.host == "ExampleHostForHostInfoModule"
- - gather_all_facts_result.hosts.0.name == "ExampleHostForHostInfoModuleName"
- - gather_all_facts_result.hosts.0.description == "Test Host"
- - gather_all_facts_result.hosts.0.groups.0.name == "Linux servers"
- - gather_all_facts_result.hosts.0.groups.1.name == "Hypervisors"
- - gather_all_facts_result.hosts.0.parentTemplates.0.name == "Template App Zabbix Server"
- - gather_all_facts_result.hosts.0.status == "0"
- - gather_all_facts_result.hosts.0.inventory_mode == "0"
- - gather_all_facts_result.hosts.0.inventory.tag == "tag1"
- - gather_all_facts_result.hosts.0.inventory.os == "Linux"
- - gather_all_facts_result.hosts.0.hostinterfaces.0.dns == ""
- - gather_all_facts_result.hosts.0.hostinterfaces.0.ip == "192.168.0.1"
- - gather_all_facts_result.hosts.0.hostinterfaces.0.main == "1"
- - gather_all_facts_result.hosts.0.hostinterfaces.0.port == "10050"
- - gather_all_facts_result.hosts.0.hostinterfaces.0.type == "1"
- - gather_all_facts_result.hosts.0.hostinterfaces.0.useip == "1"
-
- when: zabbix_version is version('5.4', '>=') and zabbix_version is version('6.2', '<')
- assert:
+ ansible.builtin.assert:
that:
- gather_all_facts_result.hosts | length == 1
- gather_all_facts_result.hosts.0.host == "ExampleHostForHostInfoModule"
@@ -113,7 +71,7 @@
- gather_all_facts_result.hosts.0.hostinterfaces.0.useip == "1"
- when: zabbix_version is version('6.2', '>=')
- assert:
+ ansible.builtin.assert:
that:
- gather_all_facts_result.hosts | length == 1
- gather_all_facts_result.hosts.0.host == "ExampleHostForHostInfoModule"
@@ -134,52 +92,57 @@
- gather_all_facts_result.hosts.0.hostinterfaces.0.useip == "1"
- name: "test - Gather facts of zabbix host with host_inventory"
- zabbix_host_info:
+ community.zabbix.zabbix_host_info:
host_inventory:
- tag
- os
register: gather_facts_with_host_inventory_result
- - when: zabbix_version is version('3.4', '<=')
- assert:
- that:
- - gather_facts_with_host_inventory_result.hosts.0.inventory | length == 3
- - gather_facts_with_host_inventory_result.hosts.0.inventory.tag == "tag1"
- - gather_facts_with_host_inventory_result.hosts.0.inventory.os == "Linux"
-
- - when: zabbix_version is version('4.0', '>=')
- assert:
+ - ansible.builtin.assert:
that:
- gather_facts_with_host_inventory_result.hosts.0.inventory | length == 2
- gather_facts_with_host_inventory_result.hosts.0.inventory.tag == "tag1"
- gather_facts_with_host_inventory_result.hosts.0.inventory.os == "Linux"
- name: "test - Partial match of zabbix host name"
- zabbix_host_info:
+ community.zabbix.zabbix_host_info:
host_name: HostForHostInfo
exact_match: false
register: partial_match_result
- - assert:
+ - ansible.builtin.assert:
that:
- partial_match_result.hosts | length == 1
- name: "test - Exact match of zabbix host name"
- zabbix_host_info:
+ community.zabbix.zabbix_host_info:
exact_match: true
register: exact_match_result
- - assert:
+ - ansible.builtin.assert:
that:
- exact_match_result.hosts | length == 1
- name: "test - Exact match of zabbix host name(expectations - host not found)"
- zabbix_host_info:
+ community.zabbix.zabbix_host_info:
host_name: HostForHostInfo
exact_match: true
register: exact_match_host_not_found_result
ignore_errors: true
- - assert:
+ - ansible.builtin.assert:
that:
- exact_match_host_not_found_result.failed is sameas true
+
+- name: Get all hosts
+ community.zabbix.zabbix_host_info:
+ register: get_all_hosts_result
+
+- ansible.builtin.assert:
+ that:
+ - get_all_hosts_result.hosts | length == 2
+
+- name: Clean up test host
+ community.zabbix.zabbix_host:
+ host_name: ExampleHostForHostInfoModule
+ state: absent
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_hostmacro/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_hostmacro/tasks/main.yml
index 1a9d81eff..adc4d0402 100644
--- a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_hostmacro/tasks/main.yml
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_hostmacro/tasks/main.yml
@@ -1,6 +1,6 @@
---
- name: create helper zabbix host
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: zbx_hmacro_host01
host_groups:
- Linux servers
@@ -10,97 +10,105 @@
dns: zbx_hmacro_host01
- name: test - attempt to create new host macro
- zabbix_hostmacro:
+ community.zabbix.zabbix_hostmacro:
host_name: zbx_hmacro_host01
macro_name: zbxhmacro_test01
macro_value: 123
+ macro_description: Global Macro description
register: zbxhmacro_new
- name: assert that macro was created
- assert:
+ ansible.builtin.assert:
that: zbxhmacro_new is changed
- name: test - attempt to create same host macro
- zabbix_hostmacro:
+ community.zabbix.zabbix_hostmacro:
host_name: zbx_hmacro_host01
macro_name: zbxhmacro_test01
macro_value: 123
+ macro_description: Global Macro description
register: zbxhmacro_existing
- name: assert that nothing has been changed
- assert:
+ ansible.builtin.assert:
that: not zbxhmacro_existing is changed
- name: test - attempt to create same host macro in zabbix native format
- zabbix_hostmacro:
+ community.zabbix.zabbix_hostmacro:
host_name: zbx_hmacro_host01
macro_name: "{$ZBXHMACRO_TEST01}"
macro_value: 123
+ macro_description: Global Macro description
register: zbxhmacro_existing_native
- name: assert that nothing has been changed
- assert:
+ ansible.builtin.assert:
that: not zbxhmacro_existing_native is changed
- name: test - attempt to create new host macro in zabbix native format
- zabbix_hostmacro:
+ community.zabbix.zabbix_hostmacro:
host_name: zbx_hmacro_host01
macro_name: "{$ZBXHMACRO_TEST02}"
macro_value: abcd
+ macro_description: Global Macro description
register: zbxhmacro_new_native
- name: assert that nothing macro was created
- assert:
+ ansible.builtin.assert:
that: zbxhmacro_new_native is changed
- name: test - attempt to update host macro with string value while force=no
- zabbix_hostmacro:
+ community.zabbix.zabbix_hostmacro:
host_name: zbx_hmacro_host01
macro_name: zbxhmacro_test01
macro_value: abc
+ macro_description: Global Macro description
force: false
register: zbxhmacro_update_noforce
- name: assert that nothing has been changed
- assert:
+ ansible.builtin.assert:
that: not zbxhmacro_update_noforce is changed
- name: test - attempt to update host macro with string value
- zabbix_hostmacro:
+ community.zabbix.zabbix_hostmacro:
host_name: zbx_hmacro_host01
macro_name: zbxhmacro_test01
macro_value: abc
+ macro_description: Global Macro description
register: zbxhmacro_update
ignore_errors: true
- name: assert that host macro was updated
- assert:
+ ansible.builtin.assert:
that: zbxhmacro_update is changed
- name: test - attempt to create host macro with context
- zabbix_hostmacro:
+ community.zabbix.zabbix_hostmacro:
host_name: zbx_hmacro_host01
macro_name: low_space_limit:/home
macro_value: 10
+ macro_description: Global Macro description
register: zbxhmacro_context_new
- name: assert that macro was created
- assert:
+ ansible.builtin.assert:
that: zbxhmacro_context_new is changed
- name: test - attempt to create same host macro with context and verify that it was converted to uppercase
- zabbix_hostmacro:
+ community.zabbix.zabbix_hostmacro:
host_name: zbx_hmacro_host01
macro_name: LOW_SPACE_LIMIT:/home
macro_value: 10
+ macro_description: Global Macro description
register: zbxhmacro_context_existing
- name: assert that nothing has been changed
- assert:
+ ansible.builtin.assert:
that: not zbxhmacro_context_existing is changed
- name: test - attempt to delete all host macros
- zabbix_hostmacro:
+ community.zabbix.zabbix_hostmacro:
host_name: zbx_hmacro_host01
macro_name: "{{ item }}"
state: absent
@@ -111,53 +119,51 @@
register: zbxhmacro_delete_existing
- name: assert that all macros have been deleted
- assert:
+ ansible.builtin.assert:
that: item.changed is sameas True
loop: "{{ zbxhmacro_delete_existing.results }}"
- name: test - attempt to delete non-existing host macro
- zabbix_hostmacro:
+ community.zabbix.zabbix_hostmacro:
host_name: zbx_hmacro_host01
macro_name: zbxhmacro_test01
state: absent
register: zbxhmacro_delete_missing
- name: assert that nothing has been changed
- assert:
+ ansible.builtin.assert:
that: not zbxhmacro_delete_missing is changed
-- name: test - do not run host macro secret tests for Zabbix < 5.0
- meta: end_play
- when: zabbix_version is version('5.0', '<')
-
- name: test - attempt to create host macro with type secret
- zabbix_hostmacro:
+ community.zabbix.zabbix_hostmacro:
host_name: zbx_hmacro_host01
macro_name: zbxhmacro_test03
macro_value: abcd
macro_type: secret
+ macro_description: Global Macro description
register: zbxhmacro_update
ignore_errors: true
- name: assert that host macro was updated
- assert:
+ ansible.builtin.assert:
that: zbxhmacro_update is changed
- name: test - attempt to update host macro with type secret with same value
- zabbix_hostmacro:
+ community.zabbix.zabbix_hostmacro:
host_name: zbx_hmacro_host01
macro_name: zbxhmacro_test03
macro_value: abcd
macro_type: secret
+ macro_description: Global Macro description
register: zbxhmacro_update
ignore_errors: true
- name: assert that host macro was updated
- assert:
+ ansible.builtin.assert:
that: zbxhmacro_update is changed
- name: test - attempt to delete host macros type secret
- zabbix_hostmacro:
+ community.zabbix.zabbix_hostmacro:
host_name: zbx_hmacro_host01
macro_name: "{{ item }}"
state: absent
@@ -166,6 +172,6 @@
register: zbxhmacro_delete_existing
- name: assert that all macros have been deleted
- assert:
+ ansible.builtin.assert:
that: item.changed is sameas True
loop: "{{ zbxhmacro_delete_existing.results }}"
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_housekeeping/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_housekeeping/tasks/main.yml
index 6189c1d77..242b11927 100644
--- a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_housekeeping/tasks/main.yml
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_housekeeping/tasks/main.yml
@@ -1,96 +1,77 @@
---
-- name: test - do not run tests with < Zabbix 4.0
- meta: end_play
- when: zabbix_version is version('4.0', '<')
+- name: test update housekeeping parameters.
+ community.zabbix.zabbix_housekeeping:
+ hk_events_mode: yes
+ hk_events_trigger: 365d
+ hk_events_service: 1w
+ hk_events_internal: 86400s
+ hk_events_discovery: 48h
+ hk_events_autoreg: 1440m
+ hk_services_mode: yes
+ hk_services: 365d
+ hk_audit_mode: yes
+ hk_audit: 365d
+ hk_sessions_mode: yes
+ hk_sessions: 365d
+ hk_history_mode: yes
+ hk_history_global: yes
+ hk_history: 365d
+ hk_trends_mode: yes
+ hk_trends_global: yes
+ hk_trends: 365d
+ compression_status: off
+ compress_older: 7d
+ register: zbxhk_update_result
-- when: zabbix_version is version('5.2', '<')
- name: Unsupport Zabbix version (<5.2)
- block:
- - name: test fail to update housekeeping
- community.zabbix.zabbix_housekeeping:
- hk_events_mode: true
- register: zbxhk_update_result
- ignore_errors: true
+- ansible.builtin.assert:
+ that: zbxhk_update_result.changed is sameas True
- - assert:
- that: zbxhk_update_result.failed is sameas True
+- name: test update housekeeping parameters (again).
+ community.zabbix.zabbix_housekeeping:
+ hk_events_mode: yes
+ hk_events_trigger: 365d
+ hk_events_service: 1w
+ hk_events_internal: 86400s
+ hk_events_discovery: 48h
+ hk_events_autoreg: 1440m
+ hk_services_mode: yes
+ hk_services: 365d
+ hk_audit_mode: yes
+ hk_audit: 365d
+ hk_sessions_mode: yes
+ hk_sessions: 365d
+ hk_history_mode: yes
+ hk_history_global: yes
+ hk_history: 365d
+ hk_trends_mode: yes
+ hk_trends_global: yes
+ hk_trends: 365d
+ compression_status: off
+ compress_older: 7d
+ register: zbxhk_update_result
-- when: zabbix_version is version('5.2', '>=')
- name: Support Zabbix version (>=5.2)
- block:
- - name: test update housekeeping parameters.
- community.zabbix.zabbix_housekeeping:
- hk_events_mode: yes
- hk_events_trigger: 365d
- hk_events_service: 1w
- hk_events_internal: 86400s
- hk_events_discovery: 48h
- hk_events_autoreg: 1440m
- hk_services_mode: yes
- hk_services: 365d
- hk_audit_mode: yes
- hk_audit: 365d
- hk_sessions_mode: yes
- hk_sessions: 365d
- hk_history_mode: yes
- hk_history_global: yes
- hk_history: 365d
- hk_trends_mode: yes
- hk_trends_global: yes
- hk_trends: 365d
- compression_status: off
- compress_older: 7d
- register: zbxhk_update_result
+- ansible.builtin.assert:
+ that: zbxhk_update_result.changed is sameas False
- - assert:
- that: zbxhk_update_result.changed is sameas True
-
- - name: test update housekeeping parameters (again).
- community.zabbix.zabbix_housekeeping:
- hk_events_mode: yes
- hk_events_trigger: 365d
- hk_events_service: 1w
- hk_events_internal: 86400s
- hk_events_discovery: 48h
- hk_events_autoreg: 1440m
- hk_services_mode: yes
- hk_services: 365d
- hk_audit_mode: yes
- hk_audit: 365d
- hk_sessions_mode: yes
- hk_sessions: 365d
- hk_history_mode: yes
- hk_history_global: yes
- hk_history: 365d
- hk_trends_mode: yes
- hk_trends_global: yes
- hk_trends: 365d
- compression_status: off
- compress_older: 7d
- register: zbxhk_update_result
-
- - assert:
- that: zbxhk_update_result.changed is sameas False
-
- - name: initialize housekeeping setting.
- community.zabbix.zabbix_housekeeping:
- hk_events_mode: yes
- hk_events_trigger: 365d
- hk_events_service: 1d
- hk_events_internal: 1d
- hk_events_discovery: 1d
- hk_events_autoreg: 1d
- hk_services_mode: yes
- hk_services: 365d
- hk_audit_mode: yes
- hk_audit: 365d
- hk_sessions_mode: yes
- hk_sessions: 365d
- hk_history_mode: yes
- hk_history_global: no
- hk_history: 365d
- hk_trends_mode: yes
- hk_trends_global: no
- hk_trends: 365d
- compression_status: off
- compress_older: 7d
+- name: initialize housekeeping setting.
+ community.zabbix.zabbix_housekeeping:
+ hk_events_mode: yes
+ hk_events_trigger: 365d
+ hk_events_service: 1d
+ hk_events_internal: 1d
+ hk_events_discovery: 1d
+ hk_events_autoreg: 1d
+ hk_services_mode: yes
+ hk_services: 365d
+ hk_audit_mode: yes
+ hk_audit: 365d
+ hk_sessions_mode: yes
+ hk_sessions: 365d
+ hk_history_mode: yes
+ hk_history_global: no
+ hk_history: 365d
+ hk_trends_mode: yes
+ hk_trends_global: no
+ hk_trends: 365d
+ compression_status: off
+ compress_older: 7d
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_maintenance/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_maintenance/tasks/main.yml
index 0daca8d13..1b9c6f6bd 100644
--- a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_maintenance/tasks/main.yml
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_maintenance/tasks/main.yml
@@ -1,7 +1,7 @@
---
# New host create test from here
- name: "test - Create a new host"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: example
host_groups:
- Linux servers
@@ -14,24 +14,24 @@
port: 10050
register: create_host_result
-- assert:
+- ansible.builtin.assert:
that:
- create_host_result.changed is sameas true
- name: "test - Create maintenance with a host_name param"
- zabbix_maintenance:
+ community.zabbix.zabbix_maintenance:
name: maintenance
host_name: example
state: present
register: create_maintenance_host_name_result
-- assert:
+- ansible.builtin.assert:
that:
- create_maintenance_host_name_result.changed is sameas true
# This check doesn't modify maintenace object and thus will be changed=false unless there are hosts without visible name defined
- name: "test - Create maintenance with a host_name param and disabled visible_name"
- zabbix_maintenance:
+ community.zabbix.zabbix_maintenance:
name: maintenance
host_name: example
visible_name: false
@@ -40,12 +40,12 @@
# BUGGED: sometimes when test "lags" and some time passes since previous tasks,
# maintenance_start will not match and be updated, thus resulting in changed
-# - assert:
+# - ansible.builtin.assert:
# that:
# - create_maintenance_host_name_result.changed is sameas false
- name: "test - Create maintenance with a host_name param(again - expectations: false change will occur)"
- zabbix_maintenance:
+ community.zabbix.zabbix_maintenance:
name: maintenance
host_name: example
state: present
@@ -53,12 +53,12 @@
# BUGGED: sometimes when test "lags" and some time passes since previous tasks,
# maintenance_start will not match and be updated, thus resulting in changed
-# - assert:
+# - ansible.builtin.assert:
# that:
# - create_maintenance_host_name_again_result.changed is sameas false
- name: "test - Update maintenance with a desc param"
- zabbix_maintenance:
+ community.zabbix.zabbix_maintenance:
name: maintenance
host_name: example
desc: "test description"
@@ -67,12 +67,12 @@
- debug: msg="{{ update_maintenance_desc_result }}"
-- assert:
+- ansible.builtin.assert:
that:
- update_maintenance_desc_result.changed is sameas true
- name: "test - Update maintenance with a desc param(again - expectations: no change will occur)"
- zabbix_maintenance:
+ community.zabbix.zabbix_maintenance:
name: maintenance
host_name: example
desc: "test description"
@@ -81,12 +81,12 @@
# BUGGED: sometimes when test "lags" and some time passes since previous tasks,
# maintenance_start will not match and be updated, thus resulting in changed
-# - assert:
+# - ansible.builtin.assert:
# that:
# - update_maintenance_desc_again_result.changed is sameas false
- name: "test - Update maintenance with a collect_data"
- zabbix_maintenance:
+ community.zabbix.zabbix_maintenance:
name: maintenance
host_name: example
desc: "test description"
@@ -94,12 +94,12 @@
state: present
register: update_maintenance_collect_data_result
-- assert:
+- ansible.builtin.assert:
that:
- update_maintenance_collect_data_result.changed is sameas true
- name: "test - Update maintenance with a collect_data(again - expectations: no change will occur)"
- zabbix_maintenance:
+ community.zabbix.zabbix_maintenance:
name: maintenance
host_name: example
desc: "test description"
@@ -109,12 +109,12 @@
# BUGGED: sometimes when test "lags" and some time passes since previous tasks,
# maintenance_start will not match and be updated, thus resulting in changed
-# - assert:
+# - ansible.builtin.assert:
# that:
# - update_maintenance_collect_data_again_result.changed is sameas false
- name: "test - Update maintenance with a minutes param"
- zabbix_maintenance:
+ community.zabbix.zabbix_maintenance:
name: maintenance
host_name: example
desc: "test description"
@@ -123,12 +123,12 @@
state: present
register: update_maintenance_minutes_result
-- assert:
+- ansible.builtin.assert:
that:
- update_maintenance_minutes_result.changed is sameas true
- name: "test - Update maintenance with a minutes param(again - expectations: no change will occur)"
- zabbix_maintenance:
+ community.zabbix.zabbix_maintenance:
name: maintenance
host_name: example
desc: "test description"
@@ -139,12 +139,12 @@
# BUGGED: sometimes when test "lags" and some time passes since previous tasks,
# maintenance_start will not match and be updated, thus resulting in changed
-# - assert:
+# - ansible.builtin.assert:
# that:
# - update_maintenance_minutes_again_result.changed is sameas false
- name: "test - Update maintenance with a host_groups param"
- zabbix_maintenance:
+ community.zabbix.zabbix_maintenance:
name: maintenance
host_name: example
host_groups:
@@ -156,12 +156,12 @@
state: present
register: update_maintenance_host_groups_result
-- assert:
+- ansible.builtin.assert:
that:
- update_maintenance_host_groups_result.changed is sameas true
- name: "test - Update maintenance with a host_groups param(again - expectations: no change will occur)"
- zabbix_maintenance:
+ community.zabbix.zabbix_maintenance:
name: maintenance
host_name: example
host_groups:
@@ -175,12 +175,12 @@
# BUGGED: sometimes when test "lags" and some time passes since previous tasks,
# maintenance_start will not match and be updated, thus resulting in changed
-# - assert:
+# - ansible.builtin.assert:
# that:
# - update_maintenance_host_groups_again_result.changed is sameas false
- name: "test - Update maintenance with change host_name to host_names param"
- zabbix_maintenance:
+ community.zabbix.zabbix_maintenance:
name: maintenance
host_names:
- example
@@ -194,12 +194,12 @@
state: present
register: update_maintenance_host_names_result
-- assert:
+- ansible.builtin.assert:
that:
- update_maintenance_host_names_result.changed is sameas true
- name: "test - Update maintenance with change host_name to host_names param(again - expectations: no change will occur)"
- zabbix_maintenance:
+ community.zabbix.zabbix_maintenance:
name: maintenance
host_names:
- example
@@ -215,12 +215,12 @@
# BUGGED: sometimes when test "lags" and some time passes since previous tasks,
# maintenance_start will not match and be updated, thus resulting in changed
-# - assert:
+# - ansible.builtin.assert:
# that:
# - update_maintenance_host_names_again_result.changed is sameas false
- name: "test - Update maintenance with tags"
- zabbix_maintenance:
+ community.zabbix.zabbix_maintenance:
name: maintenance
host_names:
- example
@@ -229,7 +229,7 @@
- Linux servers
- Hypervisors
desc: "test description"
- collect_data: yes # required for tags
+ collect_data: yes # required for tags
minutes: 90
state: present
tags:
@@ -241,12 +241,12 @@
operator: 0
register: update_maintenance_host_tags
-- assert:
+- ansible.builtin.assert:
that:
- update_maintenance_host_tags.changed is sameas true
- name: "test - Update maintenance with tags (again)"
- zabbix_maintenance:
+ community.zabbix.zabbix_maintenance:
name: maintenance
host_names:
- example
@@ -269,12 +269,12 @@
# BUGGED: sometimes when test "lags" and some time passes since previous tasks,
# maintenance_start will not match and be updated, thus resulting in changed
-#- assert:
+#- ansible.builtin.assert:
# that:
# - update_maintenance_host_tags.changed is sameas false
- name: "test - Delete maintenance"
- zabbix_maintenance:
+ community.zabbix.zabbix_maintenance:
name: maintenance
host_name: example
state: absent
@@ -282,23 +282,23 @@
tags:
- cleanup
-- assert:
+- ansible.builtin.assert:
that:
- delete_maintenance_result.changed is sameas true
- name: "test - Delete maintenance(again - expectations: no change will occur)"
- zabbix_maintenance:
+ community.zabbix.zabbix_maintenance:
name: maintenance
host_name: example
state: absent
register: delete_maintenance_again_result
-- assert:
+- ansible.builtin.assert:
that:
- delete_maintenance_again_result.changed is sameas false
- name: "test - Delete testing host"
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: example
state: absent
tags:
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_mediatype/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_mediatype/tasks/main.yml
index 4daffebdd..a49166d37 100644
--- a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_mediatype/tasks/main.yml
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_mediatype/tasks/main.yml
@@ -8,156 +8,152 @@
smtp_email: zabbix@example.com
block:
- - name: test - create new email mediatype without authentication
- zabbix_mediatype:
- register: zbxmediatype_new
-
- - assert:
- that: zbxmediatype_new.changed is sameas True
-
- - name: test - create new email mediatype without authentication (again)
- zabbix_mediatype:
- register: zbxmediatype_new
-
- - assert:
- that: zbxmediatype_new.changed is sameas False
-
- - name: test - update email mediatype smtp information
- zabbix_mediatype:
- smtp_helo: example.com
- smtp_server: mail.example.com
- smtp_server_port: 465
- register: zbxmediatype_smtp
-
- - assert:
- that: zbxmediatype_smtp.changed is sameas True
-
- - name: test - update email mediatype smtp information (again)
- zabbix_mediatype:
- smtp_helo: example.com
- smtp_server: mail.example.com
- smtp_server_port: 465
- register: zbxmediatype_smtp
-
- - assert:
- that: zbxmediatype_smtp.changed is sameas False
-
- - name: test - reset email mediatype smtp information to default
- zabbix_mediatype:
- register: zbxmediatype_reset
-
- - assert:
- that: zbxmediatype_reset.changed is sameas True
-
- - name: test - update email mediatype with authentication without credentials (fail)
- zabbix_mediatype:
- smtp_authentication: true
- smtp_security: STARTTLS
- register: zbxmediatype_auth_fail
- ignore_errors: true
-
- - assert:
- that: zbxmediatype_auth_fail.failed is sameas True
-
- - name: test - update email mediatype with authentication
- zabbix_mediatype:
- smtp_authentication: true
- smtp_security: STARTTLS
- username: zabbix
- password: Ex4mP!3
- register: zbxmediatype_auth
-
- - assert:
- that: zbxmediatype_auth.changed is sameas True
-
- - name: test - update email mediatype with authentication (again)
- zabbix_mediatype:
- smtp_authentication: true
- smtp_security: STARTTLS
- username: zabbix
- password: Ex4mP!3
- register: zbxmediatype_auth
-
- - assert:
- that: zbxmediatype_auth.changed is sameas False
-
- - name: test - update email mediatype with SSL/TLS and host/peer verification
- zabbix_mediatype:
- smtp_authentication: true
- smtp_security: SSL/TLS
- smtp_verify_host: true
- smtp_verify_peer: true
- username: zabbix
- password: Ex4mP!3
- register: zbxmediatype_verif
-
- - assert:
- that: zbxmediatype_verif.changed is sameas True
-
- - name: test - update email mediatype with SSL/TLS and host/peer verification (again)
- zabbix_mediatype:
- smtp_authentication: true
- smtp_security: SSL/TLS
- smtp_verify_host: true
- smtp_verify_peer: true
- username: zabbix
- password: Ex4mP!3
- register: zbxmediatype_verif
-
- - assert:
- that: zbxmediatype_verif.changed is sameas False
-
- - when: zabbix_version is version('3.4', '>=')
- block:
+ - name: test - create new email mediatype without authentication
+ community.zabbix.zabbix_mediatype:
+ register: zbxmediatype_new
+
+ - ansible.builtin.assert:
+ that: zbxmediatype_new.changed is sameas True
+
+ - name: test - create new email mediatype without authentication (again)
+ community.zabbix.zabbix_mediatype:
+ register: zbxmediatype_new
+
+ - ansible.builtin.assert:
+ that: zbxmediatype_new.changed is sameas False
+
+ - name: test - update email mediatype smtp information
+ community.zabbix.zabbix_mediatype:
+ smtp_helo: example.com
+ smtp_server: mail.example.com
+ smtp_server_port: 465
+ register: zbxmediatype_smtp
+
+ - ansible.builtin.assert:
+ that: zbxmediatype_smtp.changed is sameas True
+
+ - name: test - update email mediatype smtp information (again)
+ community.zabbix.zabbix_mediatype:
+ smtp_helo: example.com
+ smtp_server: mail.example.com
+ smtp_server_port: 465
+ register: zbxmediatype_smtp
+
+ - ansible.builtin.assert:
+ that: zbxmediatype_smtp.changed is sameas False
+
+ - name: test - reset email mediatype smtp information to default
+ community.zabbix.zabbix_mediatype:
+ register: zbxmediatype_reset
+
+ - ansible.builtin.assert:
+ that: zbxmediatype_reset.changed is sameas True
+
+ - name: test - update email mediatype with authentication without credentials (fail)
+ community.zabbix.zabbix_mediatype:
+ smtp_authentication: true
+ smtp_security: STARTTLS
+ register: zbxmediatype_auth_fail
+ ignore_errors: true
+
+ - ansible.builtin.assert:
+ that: zbxmediatype_auth_fail.failed is sameas True
+
+ - name: test - update email mediatype with authentication
+ community.zabbix.zabbix_mediatype:
+ smtp_authentication: true
+ smtp_security: STARTTLS
+ username: zabbix
+ password: Ex4mP!3
+ register: zbxmediatype_auth
+
+ - ansible.builtin.assert:
+ that: zbxmediatype_auth.changed is sameas True
+
+ - name: test - update email mediatype with authentication (again)
+ community.zabbix.zabbix_mediatype:
+ smtp_authentication: true
+ smtp_security: STARTTLS
+ username: zabbix
+ password: Ex4mP!3
+ register: zbxmediatype_auth
+
+ - ansible.builtin.assert:
+ that: zbxmediatype_auth.changed is sameas False
+
+ - name: test - update email mediatype with SSL/TLS and host/peer verification
+ community.zabbix.zabbix_mediatype:
+ smtp_authentication: true
+ smtp_security: SSL/TLS
+ smtp_verify_host: true
+ smtp_verify_peer: true
+ username: zabbix
+ password: Ex4mP!3
+ register: zbxmediatype_verif
+
+ - ansible.builtin.assert:
+ that: zbxmediatype_verif.changed is sameas True
+
+ - name: test - update email mediatype with SSL/TLS and host/peer verification (again)
+ community.zabbix.zabbix_mediatype:
+ smtp_authentication: true
+ smtp_security: SSL/TLS
+ smtp_verify_host: true
+ smtp_verify_peer: true
+ username: zabbix
+ password: Ex4mP!3
+ register: zbxmediatype_verif
+
+ - ansible.builtin.assert:
+ that: zbxmediatype_verif.changed is sameas False
+
- name: test - reset email mediatype smtp information to default
- zabbix_mediatype:
+ community.zabbix.zabbix_mediatype:
register: zbxmediatype_reset
- - assert:
+ - ansible.builtin.assert:
that: zbxmediatype_reset.changed is sameas True
- name: test - update email mediatype concurrent settings
- zabbix_mediatype:
+ community.zabbix.zabbix_mediatype:
max_sessions: 99
max_attempts: 10
attempt_interval: 30s
register: zbxmediatype_concur
- - assert:
+ - ansible.builtin.assert:
that: zbxmediatype_concur.changed is sameas True
- name: test - update email mediatype concurrent settings (again)
- zabbix_mediatype:
+ community.zabbix.zabbix_mediatype:
max_sessions: 99
max_attempts: 10
attempt_interval: 30s
register: zbxmediatype_concur
- - assert:
+ - ansible.builtin.assert:
that: zbxmediatype_concur.changed is sameas False
- name: test - update email mediatype concurrent settings above range (fail)
- zabbix_mediatype:
+ community.zabbix.zabbix_mediatype:
max_sessions: 102
max_attempts: 101
attempt_interval: 61m
register: zbxmediatype_concur_fail
ignore_errors: true
- - assert:
+ - ansible.builtin.assert:
that: zbxmediatype_concur_fail.failed is sameas True
- - when: zabbix_version is version('5.0', '>=')
- block:
- name: test - reset email mediatype smtp information to default
- zabbix_mediatype:
+ community.zabbix.zabbix_mediatype:
register: zbxmediatype_reset
- - assert:
+ - ansible.builtin.assert:
that: zbxmediatype_reset.changed is sameas True
- name: test - update email mediatype with message templates
- zabbix_mediatype:
+ community.zabbix.zabbix_mediatype:
message_templates:
- eventsource: triggers
recovery: operations
@@ -177,11 +173,11 @@
body: "Internal event started at {EVEN.TIME} on {EVENT.DATE}\r\nEvent name: {EVENT.NAME}\r\n"
register: zbxmediatype_msg_templates
- - assert:
+ - ansible.builtin.assert:
that: zbxmediatype_msg_templates.changed is sameas True
- name: test - update email mediatype with message templates (again)
- zabbix_mediatype:
+ community.zabbix.zabbix_mediatype:
message_templates:
- eventsource: triggers
recovery: operations
@@ -201,11 +197,11 @@
body: "Internal event started at {EVEN.TIME} on {EVENT.DATE}\r\nEvent name: {EVENT.NAME}\r\n"
register: zbxmediatype_msg_templates
- - assert:
+ - ansible.builtin.assert:
that: zbxmediatype_msg_templates.changed is sameas False
- name: test - update subject of message template in email mediatype
- zabbix_mediatype:
+ community.zabbix.zabbix_mediatype:
message_templates:
- eventsource: triggers
recovery: operations
@@ -225,11 +221,11 @@
body: "Internal event started at {EVEN.TIME} on {EVENT.DATE}\r\nEvent name: {EVENT.NAME}\r\n"
register: zbxmediatype_msg_templates
- - assert:
+ - ansible.builtin.assert:
that: zbxmediatype_msg_templates.changed is sameas True
- name: test - update message of message template in email mediatype
- zabbix_mediatype:
+ community.zabbix.zabbix_mediatype:
message_templates:
- eventsource: triggers
recovery: operations
@@ -249,11 +245,11 @@
body: "Internal event started at {EVEN.TIME} on {EVENT.DATE}\r\nEvent name: {EVENT.NAME}\r\n"
register: zbxmediatype_msg_templates
- - assert:
+ - ansible.builtin.assert:
that: zbxmediatype_msg_templates.changed is sameas True
- name: test - update subject and message of message template in email mediatype (again)
- zabbix_mediatype:
+ community.zabbix.zabbix_mediatype:
message_templates:
- eventsource: triggers
recovery: operations
@@ -273,40 +269,40 @@
body: "Internal event started at {EVEN.TIME} on {EVENT.DATE}\r\nEvent name: {EVENT.NAME}\r\n"
register: zbxmediatype_msg_templates
- - assert:
+ - ansible.builtin.assert:
that: zbxmediatype_msg_templates.changed is sameas False
- - name: test - disable email mediatype
- zabbix_mediatype:
- status: disabled
- register: zbxmediatype_disable
+ - name: test - disable email mediatype
+ community.zabbix.zabbix_mediatype:
+ status: disabled
+ register: zbxmediatype_disable
- - assert:
- that: zbxmediatype_disable.changed is sameas True
+ - ansible.builtin.assert:
+ that: zbxmediatype_disable.changed is sameas True
- - name: test - disable email mediatype (again)
- zabbix_mediatype:
- status: disabled
- register: zbxmediatype_disable
+ - name: test - disable email mediatype (again)
+ community.zabbix.zabbix_mediatype:
+ status: disabled
+ register: zbxmediatype_disable
- - assert:
- that: zbxmediatype_disable.changed is sameas False
+ - ansible.builtin.assert:
+ that: zbxmediatype_disable.changed is sameas False
- - name: test - delete email mediatype
- zabbix_mediatype:
- state: absent
- register: zbxmediatype_delete
+ - name: test - delete email mediatype
+ community.zabbix.zabbix_mediatype:
+ state: absent
+ register: zbxmediatype_delete
- - assert:
- that: zbxmediatype_delete.changed is sameas True
+ - ansible.builtin.assert:
+ that: zbxmediatype_delete.changed is sameas True
- - name: test - delete email mediatype (again)
- zabbix_mediatype:
- state: absent
- register: zbxmediatype_delete
+ - name: test - delete email mediatype (again)
+ community.zabbix.zabbix_mediatype:
+ state: absent
+ register: zbxmediatype_delete
- - assert:
- that: zbxmediatype_delete.changed is sameas False
+ - ansible.builtin.assert:
+ that: zbxmediatype_delete.changed is sameas False
- name: test - script mediatypes
module_defaults:
@@ -316,59 +312,59 @@
type: script
block:
- - name: test - create new script mediatype
- zabbix_mediatype:
- script_name: /usr/local/bin/script.sh
- register: zbxmediatype_script_new
-
- - assert:
- that: zbxmediatype_script_new.changed is sameas True
-
- - name: test - create new script mediatype (again)
- zabbix_mediatype:
- script_name: /usr/local/bin/script.sh
- register: zbxmediatype_script_new
-
- - assert:
- that: zbxmediatype_script_new.changed is sameas False
-
- - name: test - update script mediatype with script parameters
- zabbix_mediatype:
- script_name: /usr/local/bin/script.sh
- script_params:
- - '-p test'
- - '-q'
- register: zbxmediatype_script_params
-
- - assert:
- that: zbxmediatype_script_params.changed is sameas True
-
- - name: test - update script mediatype with script parameters (again)
- zabbix_mediatype:
- script_name: /usr/local/bin/script.sh
- script_params:
- - '-p test'
- - '-q'
- register: zbxmediatype_script_params
-
- - assert:
- that: zbxmediatype_script_params.changed is sameas False
-
- - name: test - remove script mediatype parameters
- zabbix_mediatype:
- script_name: /usr/local/bin/script.sh
- register: zbxmediatype_script_params_rev
-
- - assert:
- that: zbxmediatype_script_params_rev.changed is sameas True
-
- - name: test - delete script mediatype
- zabbix_mediatype:
- state: absent
- register: zbxmediatype_delete
-
- - assert:
- that: zbxmediatype_delete.changed is sameas True
+ - name: test - create new script mediatype
+ community.zabbix.zabbix_mediatype:
+ script_name: /usr/local/bin/script.sh
+ register: zbxmediatype_script_new
+
+ - ansible.builtin.assert:
+ that: zbxmediatype_script_new.changed is sameas True
+
+ - name: test - create new script mediatype (again)
+ community.zabbix.zabbix_mediatype:
+ script_name: /usr/local/bin/script.sh
+ register: zbxmediatype_script_new
+
+ - ansible.builtin.assert:
+ that: zbxmediatype_script_new.changed is sameas False
+
+ - name: test - update script mediatype with script parameters
+ community.zabbix.zabbix_mediatype:
+ script_name: /usr/local/bin/script.sh
+ script_params:
+ - "-p test"
+ - "-q"
+ register: zbxmediatype_script_params
+
+ - ansible.builtin.assert:
+ that: zbxmediatype_script_params.changed is sameas True
+
+ - name: test - update script mediatype with script parameters (again)
+ community.zabbix.zabbix_mediatype:
+ script_name: /usr/local/bin/script.sh
+ script_params:
+ - "-p test"
+ - "-q"
+ register: zbxmediatype_script_params
+
+ - ansible.builtin.assert:
+ that: zbxmediatype_script_params.changed is sameas False
+
+ - name: test - remove script mediatype parameters
+ community.zabbix.zabbix_mediatype:
+ script_name: /usr/local/bin/script.sh
+ register: zbxmediatype_script_params_rev
+
+ - ansible.builtin.assert:
+ that: zbxmediatype_script_params_rev.changed is sameas True
+
+ - name: test - delete script mediatype
+ community.zabbix.zabbix_mediatype:
+ state: absent
+ register: zbxmediatype_delete
+
+ - ansible.builtin.assert:
+ that: zbxmediatype_delete.changed is sameas True
- name: test - sms mediatypes
module_defaults:
@@ -378,148 +374,63 @@
type: sms
block:
- - name: test - create new sms mediatype
- zabbix_mediatype:
- gsm_modem: /dev/ttyS0
- register: zbxmediatype_sms_new
+ - name: test - create new sms mediatype
+ community.zabbix.zabbix_mediatype:
+ gsm_modem: /dev/ttyS0
+ register: zbxmediatype_sms_new
- - assert:
- that: zbxmediatype_sms_new.changed is sameas True
+ - ansible.builtin.assert:
+ that: zbxmediatype_sms_new.changed is sameas True
- - name: test - create new sms mediatype (again)
- zabbix_mediatype:
- gsm_modem: /dev/ttyS0
- register: zbxmediatype_sms_new
+ - name: test - create new sms mediatype (again)
+ community.zabbix.zabbix_mediatype:
+ gsm_modem: /dev/ttyS0
+ register: zbxmediatype_sms_new
- - assert:
- that: zbxmediatype_sms_new.changed is sameas False
+ - ansible.builtin.assert:
+ that: zbxmediatype_sms_new.changed is sameas False
- - when: zabbix_version is version('3.4', '>=')
- block:
- name: test - update sms mediatype with concurrent settings
- zabbix_mediatype:
+ community.zabbix.zabbix_mediatype:
gsm_modem: /dev/ttyS0
max_sessions: 1
max_attempts: 3
attempt_interval: 30
register: zbxmediatype_sms_concur
- - assert:
+ - ansible.builtin.assert:
that: zbxmediatype_sms_concur.changed is sameas True
- name: test - update sms mediatype with concurrent settings (again)
- zabbix_mediatype:
+ community.zabbix.zabbix_mediatype:
gsm_modem: /dev/ttyS0
max_sessions: 1
max_attempts: 3
attempt_interval: 30
register: zbxmediatype_sms_concur
- - assert:
+ - ansible.builtin.assert:
that: zbxmediatype_sms_concur.changed is sameas False
- name: test - update sms mediatype with invalid max sessions (fail)
- zabbix_mediatype:
+ community.zabbix.zabbix_mediatype:
gsm_modem: /dev/ttyS0
max_sessions: 2
register: zbxmediatype_sms_fail
ignore_errors: true
- - assert:
+ - ansible.builtin.assert:
that: zbxmediatype_sms_fail.failed is sameas True
- - name: test - delete sms mediatype
- zabbix_mediatype:
- state: absent
- register: zbxmediatype_delete
+ - name: test - delete sms mediatype
+ community.zabbix.zabbix_mediatype:
+ state: absent
+ register: zbxmediatype_delete
- - assert:
- that: zbxmediatype_delete.changed is sameas True
-
-- name: test - jabber mediatypes
- when: zabbix_version is version('4.2', '<=')
- module_defaults:
- community.zabbix.zabbix_mediatype:
- state: present
- name: Example jabber
- type: jabber
-
- block:
- - name: test - create new jabber mediatype
- zabbix_mediatype:
- username: zabbix
- password: Ex4mP!3
- register: zbxmediatype_jabber_new
-
- - assert:
- that: zbxmediatype_jabber_new.changed is sameas True
-
- - name: test - create new jabber mediatype (again)
- zabbix_mediatype:
- username: zabbix
- password: Ex4mP!3
- register: zbxmediatype_jabber_new
-
- - assert:
- that: zbxmediatype_jabber_new.changed is sameas False
-
- - name: test - delete jabber mediatype
- zabbix_mediatype:
- state: absent
- register: zbxmediatype_delete
-
- - assert:
- that: zbxmediatype_delete.changed is sameas True
-
-- name: test - ez_texting mediatypes
- when: zabbix_version is version('4.2', '<=')
- module_defaults:
- community.zabbix.zabbix_mediatype:
- state: present
- name: Example ez_texting
- type: ez_texting
-
- block:
- - name: test - create new ez_texting mediatype
- zabbix_mediatype:
- username: zabbix
- password: Ex4mP!3
- message_text_limit: USA
- register: zbxmediatype_ez_texting_new
-
- - assert:
- that: zbxmediatype_ez_texting_new.changed is sameas True
-
- - name: test - create new ez_texting mediatype (again)
- zabbix_mediatype:
- username: zabbix
- password: Ex4mP!3
- message_text_limit: USA
- register: zbxmediatype_ez_texting_new
-
- - assert:
- that: zbxmediatype_ez_texting_new.changed is sameas False
-
- - name: test - update ez_texting mediatype with text limit
- zabbix_mediatype:
- username: zabbix
- password: Ex4mP!3
- message_text_limit: Canada
- register: zbxmediatype_ez_texting_update
-
- - assert:
- that: zbxmediatype_ez_texting_update.changed is sameas True
-
- - name: test - delete ez_texting mediatype
- zabbix_mediatype:
- state: absent
- register: zbxmediatype_delete
-
- - assert:
- that: zbxmediatype_delete.changed is sameas True
+ - ansible.builtin.assert:
+ that: zbxmediatype_delete.changed is sameas True
- name: test - email mediatypes
- when: zabbix_version is version('4.4', '>=')
module_defaults:
community.zabbix.zabbix_mediatype:
state: present
@@ -528,151 +439,150 @@
webhook_script: "return 'Hello, world!';"
block:
- - name: test - create new webhook mediatype
- zabbix_mediatype:
- register: zbxmediatype_webhook_new
-
- - assert:
- that: zbxmediatype_webhook_new.changed is sameas True
-
- - name: test - create new webhook mediatype (again)
- zabbix_mediatype:
- register: zbxmediatype_webhook_new
-
- - assert:
- that: zbxmediatype_webhook_new.changed is sameas False
-
- - name: test - update webhook mediatype with process_tags
- zabbix_mediatype:
- process_tags: true
- register: zbxmediatype_webhook_tags
-
- - assert:
- that: zbxmediatype_webhook_tags.changed is sameas True
-
- - name: test - update webhook mediatype with process_tags (again)
- zabbix_mediatype:
- process_tags: true
- register: zbxmediatype_webhook_tags
-
- - assert:
- that: zbxmediatype_webhook_tags.changed is sameas False
-
- # supported since 4.4
- - name: test - update webhook mediatype with description
- zabbix_mediatype:
- process_tags: true
- description: My custom webhook mediatype
- register: zbxmediatype_webhook_desc
-
- - assert:
- that: zbxmediatype_webhook_desc.changed is sameas True
-
- - name: test - update webhook mediatype with description (again)
- zabbix_mediatype:
- process_tags: true
- description: My custom webhook mediatype
- register: zbxmediatype_webhook_desc
-
- - assert:
- that: zbxmediatype_webhook_desc.changed is sameas False
-
- - name: test - update webhook mediatype with event_menu without name and url (fail)
- zabbix_mediatype:
- process_tags: true
- description: My custom webhook mediatype
- event_menu: true
- register: zbxmediatype_webhook_eventmenu
- ignore_errors: true
-
- - assert:
- that: zbxmediatype_webhook_eventmenu.failed is sameas True
-
- - name: test - update webhook mediatype with event_menu
- zabbix_mediatype:
- process_tags: true
- description: My custom webhook mediatype
- event_menu: true
- event_menu_name: Example entry name
- event_menu_url: '{EVENT.TAGS.__message_link}'
- register: zbxmediatype_webhook_eventmenu
-
- - assert:
- that: zbxmediatype_webhook_eventmenu.changed is sameas True
-
- - name: test - update webhook mediatype with event_menu (again)
- zabbix_mediatype:
- process_tags: true
- description: My custom webhook mediatype
- event_menu: true
- event_menu_name: Example entry name
- event_menu_url: '{EVENT.TAGS.__message_link}'
- register: zbxmediatype_webhook_eventmenu
-
- - assert:
- that: zbxmediatype_webhook_eventmenu.changed is sameas False
-
- - name: test - reset webhook mediatype to default
- zabbix_mediatype:
- register: zbxmediatype_reset
-
- - assert:
- that: zbxmediatype_reset.changed is sameas True
-
- - name: test - update webhook mediatype with webhook_params
- zabbix_mediatype:
- webhook_params:
- - name: param1
- value: value1
- register: zbxmediatype_webhook_params
-
- - assert:
- that: zbxmediatype_webhook_params.changed is sameas True
-
- - name: test - update webhook mediatype with webhook_params (again)
- zabbix_mediatype:
- webhook_params:
- - name: param1
- value: value1
- register: zbxmediatype_webhook_params
-
- - assert:
- that: zbxmediatype_webhook_params.changed is sameas False
-
- - name: test - update webhook mediatype with webhook_params (reorder)
- zabbix_mediatype:
- webhook_params:
- - name: z.param2
- value: xyz
- - name: param1
- value: value1
- - name: b.param3
- - name: a.param4
- value: abc
- register: zbxmediatype_webhook_params
-
- - assert:
- that: zbxmediatype_webhook_params.changed is sameas True
-
- - name: test - update webhook mediatype with webhook_params (reorder again)
- zabbix_mediatype:
- webhook_params:
- - name: param1
- value: value1
- - name: a.param4
- value: abc
- - name: b.param3
- - name: z.param2
- value: xyz
- register: zbxmediatype_webhook_params
-
- - assert:
- that: zbxmediatype_webhook_params.changed is sameas False
-
- - name: test - delete webhook mediatype
- zabbix_mediatype:
- state: absent
- register: zbxmediatype_delete
-
- - assert:
- that: zbxmediatype_delete.changed is sameas True
+ - name: test - create new webhook mediatype
+ community.zabbix.zabbix_mediatype:
+ register: zbxmediatype_webhook_new
+
+ - ansible.builtin.assert:
+ that: zbxmediatype_webhook_new.changed is sameas True
+
+ - name: test - create new webhook mediatype (again)
+ community.zabbix.zabbix_mediatype:
+ register: zbxmediatype_webhook_new
+
+ - ansible.builtin.assert:
+ that: zbxmediatype_webhook_new.changed is sameas False
+
+ - name: test - update webhook mediatype with process_tags
+ community.zabbix.zabbix_mediatype:
+ process_tags: true
+ register: zbxmediatype_webhook_tags
+
+ - ansible.builtin.assert:
+ that: zbxmediatype_webhook_tags.changed is sameas True
+
+ - name: test - update webhook mediatype with process_tags (again)
+ community.zabbix.zabbix_mediatype:
+ process_tags: true
+ register: zbxmediatype_webhook_tags
+
+ - ansible.builtin.assert:
+ that: zbxmediatype_webhook_tags.changed is sameas False
+
+ - name: test - update webhook mediatype with description
+ community.zabbix.zabbix_mediatype:
+ process_tags: true
+ description: My custom webhook mediatype
+ register: zbxmediatype_webhook_desc
+
+ - ansible.builtin.assert:
+ that: zbxmediatype_webhook_desc.changed is sameas True
+
+ - name: test - update webhook mediatype with description (again)
+ community.zabbix.zabbix_mediatype:
+ process_tags: true
+ description: My custom webhook mediatype
+ register: zbxmediatype_webhook_desc
+
+ - ansible.builtin.assert:
+ that: zbxmediatype_webhook_desc.changed is sameas False
+
+ - name: test - update webhook mediatype with event_menu without name and url (fail)
+ community.zabbix.zabbix_mediatype:
+ process_tags: true
+ description: My custom webhook mediatype
+ event_menu: true
+ register: zbxmediatype_webhook_eventmenu
+ ignore_errors: true
+
+ - ansible.builtin.assert:
+ that: zbxmediatype_webhook_eventmenu.failed is sameas True
+
+ - name: test - update webhook mediatype with event_menu
+ community.zabbix.zabbix_mediatype:
+ process_tags: true
+ description: My custom webhook mediatype
+ event_menu: true
+ event_menu_name: Example entry name
+ event_menu_url: "{EVENT.TAGS.__message_link}"
+ register: zbxmediatype_webhook_eventmenu
+
+ - ansible.builtin.assert:
+ that: zbxmediatype_webhook_eventmenu.changed is sameas True
+
+ - name: test - update webhook mediatype with event_menu (again)
+ community.zabbix.zabbix_mediatype:
+ process_tags: true
+ description: My custom webhook mediatype
+ event_menu: true
+ event_menu_name: Example entry name
+ event_menu_url: "{EVENT.TAGS.__message_link}"
+ register: zbxmediatype_webhook_eventmenu
+
+ - ansible.builtin.assert:
+ that: zbxmediatype_webhook_eventmenu.changed is sameas False
+
+ - name: test - reset webhook mediatype to default
+ community.zabbix.zabbix_mediatype:
+ register: zbxmediatype_reset
+
+ - ansible.builtin.assert:
+ that: zbxmediatype_reset.changed is sameas True
+
+ - name: test - update webhook mediatype with webhook_params
+ community.zabbix.zabbix_mediatype:
+ webhook_params:
+ - name: param1
+ value: value1
+ register: zbxmediatype_webhook_params
+
+ - ansible.builtin.assert:
+ that: zbxmediatype_webhook_params.changed is sameas True
+
+ - name: test - update webhook mediatype with webhook_params (again)
+ community.zabbix.zabbix_mediatype:
+ webhook_params:
+ - name: param1
+ value: value1
+ register: zbxmediatype_webhook_params
+
+ - ansible.builtin.assert:
+ that: zbxmediatype_webhook_params.changed is sameas False
+
+ - name: test - update webhook mediatype with webhook_params (reorder)
+ community.zabbix.zabbix_mediatype:
+ webhook_params:
+ - name: z.param2
+ value: xyz
+ - name: param1
+ value: value1
+ - name: b.param3
+ - name: a.param4
+ value: abc
+ register: zbxmediatype_webhook_params
+
+ - ansible.builtin.assert:
+ that: zbxmediatype_webhook_params.changed is sameas True
+
+ - name: test - update webhook mediatype with webhook_params (reorder again)
+ community.zabbix.zabbix_mediatype:
+ webhook_params:
+ - name: param1
+ value: value1
+ - name: a.param4
+ value: abc
+ - name: b.param3
+ - name: z.param2
+ value: xyz
+ register: zbxmediatype_webhook_params
+
+ - ansible.builtin.assert:
+ that: zbxmediatype_webhook_params.changed is sameas False
+
+ - name: test - delete webhook mediatype
+ community.zabbix.zabbix_mediatype:
+ state: absent
+ register: zbxmediatype_delete
+
+ - ansible.builtin.assert:
+ that: zbxmediatype_delete.changed is sameas True
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_module_defaults_group/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_module_defaults_group/tasks/main.yml
index 5b861810a..04b19f2d4 100644
--- a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_module_defaults_group/tasks/main.yml
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_module_defaults_group/tasks/main.yml
@@ -7,11 +7,11 @@
state: present
block:
- name: Create host group
- zabbix_group:
+ community.zabbix.zabbix_group:
register: _grp
- name: Create host
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: Example Host
interfaces:
- type: agent
@@ -20,7 +20,7 @@
register: _host
- name: Assert that resources were correctly created
- assert:
+ ansible.builtin.assert:
that:
- _grp is changed
- _host is changed
@@ -33,16 +33,16 @@
state: absent
block:
- name: Delete host
- zabbix_host:
+ community.zabbix.zabbix_host:
host_name: Example Host
register: _host
- name: Delete host group
- zabbix_group:
+ community.zabbix.zabbix_group:
register: _grp
- name: Assert that resources were correctly deleted
- assert:
+ ansible.builtin.assert:
that:
- _grp is changed
- _host is changed
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_proxy/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_proxy/tasks/main.yml
index ee96e6e80..86ece24f3 100644
--- a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_proxy/tasks/main.yml
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_proxy/tasks/main.yml
@@ -1,6 +1,6 @@
---
- name: test - create new passive Zabbix proxy server
- zabbix_proxy:
+ community.zabbix.zabbix_proxy:
proxy_name: zbxproxy_example01
description: Example Zabbix Proxy
state: present
@@ -13,11 +13,11 @@
register: zbxproxy_new
- name: assert that proxy was created
- assert:
+ ansible.builtin.assert:
that: zbxproxy_new is changed
- name: test - create same passive Zabbix proxy server
- zabbix_proxy:
+ community.zabbix.zabbix_proxy:
proxy_name: zbxproxy_example01
description: Example Zabbix Proxy
state: present
@@ -30,11 +30,11 @@
register: zbxproxy_existing
- name: assert that nothing has been changed
- assert:
+ ansible.builtin.assert:
that: not zbxproxy_existing is changed
- name: test - update Zabbix proxy server description
- zabbix_proxy:
+ community.zabbix.zabbix_proxy:
proxy_name: zbxproxy_example01
description: Example Zabbix Proxy desc
state: present
@@ -47,11 +47,11 @@
register: zbxproxy_desc_update
- name: assert that description has been updated
- assert:
+ ansible.builtin.assert:
that: zbxproxy_desc_update is changed
- name: test - update Zabbix proxy server interface
- zabbix_proxy:
+ community.zabbix.zabbix_proxy:
proxy_name: zbxproxy_example01
description: Example Zabbix Proxy desc
state: present
@@ -64,11 +64,11 @@
register: zbxproxy_interface_update
- name: assert that interface has been updated
- assert:
+ ansible.builtin.assert:
that: zbxproxy_interface_update is changed
- name: test - update Zabbix proxy server description & interface (again)
- zabbix_proxy:
+ community.zabbix.zabbix_proxy:
proxy_name: zbxproxy_example01
description: Example Zabbix Proxy desc
state: present
@@ -81,11 +81,11 @@
register: zbxproxy_desc_interface_update
- name: assert that nothing has been changed
- assert:
+ ansible.builtin.assert:
that: not zbxproxy_desc_interface_update is changed
- name: test - update Zabbix proxy server interface to use only ip
- zabbix_proxy:
+ community.zabbix.zabbix_proxy:
proxy_name: zbxproxy_example01
description: Example Zabbix Proxy desc
state: present
@@ -97,11 +97,11 @@
register: zbxproxy_interface_onlyip
- name: assert that interface has been updated
- assert:
+ ansible.builtin.assert:
that: zbxproxy_interface_onlyip is changed
- name: test - update Zabbix proxy server interface to use only ip again
- zabbix_proxy:
+ community.zabbix.zabbix_proxy:
proxy_name: zbxproxy_example01
description: Example Zabbix Proxy desc
state: present
@@ -113,11 +113,11 @@
register: zbxproxy_interface_onlyip_again
- name: assert that nothing has been changed
- assert:
+ ansible.builtin.assert:
that: not zbxproxy_interface_onlyip_again is changed
- name: test - update Zabbix proxy server interface to use only dns
- zabbix_proxy:
+ community.zabbix.zabbix_proxy:
proxy_name: zbxproxy_example01
description: Example Zabbix Proxy desc
state: present
@@ -129,11 +129,11 @@
register: zbxproxy_interface_onlydns
- name: assert that interface has been updated
- assert:
+ ansible.builtin.assert:
that: zbxproxy_interface_onlydns is changed
- name: test - update Zabbix proxy server interface to use only dns again
- zabbix_proxy:
+ community.zabbix.zabbix_proxy:
proxy_name: zbxproxy_example01
description: Example Zabbix Proxy desc
state: present
@@ -145,11 +145,11 @@
register: zbxproxy_interface_onlydns_again
- name: assert that nothing has been changed
- assert:
+ ansible.builtin.assert:
that: not zbxproxy_interface_onlydns_again is changed
- name: test - update Zabbix proxy server interface to fail
- zabbix_proxy:
+ community.zabbix.zabbix_proxy:
proxy_name: zbxproxy_example01
description: Example Zabbix Proxy desc
state: present
@@ -162,11 +162,11 @@
ignore_errors: true
- name: assert that module has failed
- assert:
+ ansible.builtin.assert:
that: zbxproxy_interface_fail is failed
- name: test - update Zabbix proxy server to be active
- zabbix_proxy:
+ community.zabbix.zabbix_proxy:
proxy_name: zbxproxy_example01
description: Example Zabbix Proxy
state: present
@@ -174,11 +174,11 @@
register: zbxproxy_active_update
- name: assert that proxy was updated
- assert:
+ ansible.builtin.assert:
that: zbxproxy_active_update is changed
- name: test - update Zabbix proxy server to be active (again)
- zabbix_proxy:
+ community.zabbix.zabbix_proxy:
proxy_name: zbxproxy_example01
description: Example Zabbix Proxy
state: present
@@ -186,41 +186,37 @@
register: zbxproxy_active_update_again
- name: assert that nothing has been changed
- assert:
+ ansible.builtin.assert:
that: not zbxproxy_active_update_again is changed
-# proxy_address available on zabbix 4.0 and above
-- block:
- - name: test - update Zabbix proxy server to be active and use proxy_address
- zabbix_proxy:
- proxy_name: zbxproxy_example01
- description: Example Zabbix Proxy
- state: present
- status: active
- proxy_address: 10.1.1.0/24,zabbix.example.com
- register: zbxproxy_active_proxyaddress
-
- - name: assert that proxy was updated
- assert:
- that: zbxproxy_active_proxyaddress is changed
-
- - name: test - update Zabbix proxy server to be active use proxy_address (again)
- zabbix_proxy:
- proxy_name: zbxproxy_example01
- description: Example Zabbix Proxy
- state: present
- status: active
- proxy_address: 10.1.1.0/24,zabbix.example.com
- register: zbxproxy_active_proxyaddress_again
-
- - name: assert that nothing has been changed
- assert:
- that: not zbxproxy_active_proxyaddress_again is changed
-
- when: zabbix_version != "3.0"
+- name: test - update Zabbix proxy server to be active and use proxy_address
+ community.zabbix.zabbix_proxy:
+ proxy_name: zbxproxy_example01
+ description: Example Zabbix Proxy
+ state: present
+ status: active
+ proxy_address: 10.1.1.0/24,zabbix.example.com
+ register: zbxproxy_active_proxyaddress
+
+- name: assert that proxy was updated
+ ansible.builtin.assert:
+ that: zbxproxy_active_proxyaddress is changed
+
+- name: test - update Zabbix proxy server to be active use proxy_address (again)
+ community.zabbix.zabbix_proxy:
+ proxy_name: zbxproxy_example01
+ description: Example Zabbix Proxy
+ state: present
+ status: active
+ proxy_address: 10.1.1.0/24,zabbix.example.com
+ register: zbxproxy_active_proxyaddress_again
+
+- name: assert that nothing has been changed
+ ansible.builtin.assert:
+ that: not zbxproxy_active_proxyaddress_again is changed
- name: test - update Zabbix proxy server to use encryption
- zabbix_proxy:
+ community.zabbix.zabbix_proxy:
proxy_name: zbxproxy_example01
description: Example Zabbix Proxy
state: present
@@ -232,11 +228,11 @@
register: zbxproxy_encryption
- name: assert that encryption has been enabled
- assert:
+ ansible.builtin.assert:
that: zbxproxy_encryption is changed
- name: test - update Zabbix proxy server to use encryption (again)
- zabbix_proxy:
+ community.zabbix.zabbix_proxy:
proxy_name: zbxproxy_example01
description: Example Zabbix Proxy
state: present
@@ -248,19 +244,11 @@
register: zbxproxy_encryption_again
- name: assert that nothing has been changed
- assert:
- that: not zbxproxy_encryption_again is changed
- when: zabbix_version < "6.0"
-
-# With Zabbix >= 6.0 tls_psk and tls_psk_identity cannot be read
-# thus there is no way to check idempotency
-- name: assert that nothing has been changed
- assert:
+ ansible.builtin.assert:
that: zbxproxy_encryption_again is changed
- when: zabbix_version >= "6.0"
- name: test - update Zabbix proxy server encryption settings
- zabbix_proxy:
+ community.zabbix.zabbix_proxy:
proxy_name: zbxproxy_example01
description: Example Zabbix Proxy
state: present
@@ -272,11 +260,11 @@
register: zbxproxy_encryption_update
- name: assert that encryption has been updated
- assert:
+ ansible.builtin.assert:
that: zbxproxy_encryption_update is changed
- name: test - update Zabbix proxy server back to being passive
- zabbix_proxy:
+ community.zabbix.zabbix_proxy:
proxy_name: zbxproxy_example01
description: Example Zabbix Proxy
state: present
@@ -289,25 +277,25 @@
register: zbxproxy_passive_update
- name: assert that proxy was updated
- assert:
+ ansible.builtin.assert:
that: zbxproxy_passive_update is changed
- name: test - delete Zabbix proxy server
- zabbix_proxy:
+ community.zabbix.zabbix_proxy:
proxy_name: zbxproxy_example01
state: absent
register: zbxproxy_delete
- name: assert that proxy has been deleted
- assert:
+ ansible.builtin.assert:
that: zbxproxy_delete is changed
- name: test - delete Zabbix proxy server (again)
- zabbix_proxy:
+ community.zabbix.zabbix_proxy:
proxy_name: zbxproxy_example01
state: absent
register: zbxproxy_delete_again
- name: assert that nothing has been changed
- assert:
+ ansible.builtin.assert:
that: not zbxproxy_delete_again is changed
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_proxy_info/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_proxy_info/tasks/main.yml
index a5feb2731..ddd101850 100644
--- a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_proxy_info/tasks/main.yml
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_proxy_info/tasks/main.yml
@@ -1,6 +1,6 @@
---
- name: test - Create new Zabbix proxy
- zabbix_proxy:
+ community.zabbix.zabbix_proxy:
state: present
proxy_name: ExampleProxy
description: ExampleProxy
@@ -12,12 +12,12 @@
dns: ExampleProxy.local
register: create_proxy_result
-- assert:
+- ansible.builtin.assert:
that:
- create_proxy_result.changed is sameas true
- name: test - Create new Zabbix host monitored by the proxy
- zabbix_host:
+ community.zabbix.zabbix_host:
state: present
host_name: ExampleHost
host_groups:
@@ -33,33 +33,33 @@
port: "10050"
register: create_host_result
-- assert:
+- ansible.builtin.assert:
that:
- create_host_result.changed is sameas true
- name: test - Get zabbix proxy information
- zabbix_proxy_info:
+ community.zabbix.zabbix_proxy_info:
proxy_name: ExampleProxy
proxy_hosts: true
register: get_proxy_info_result
-- assert:
+- ansible.builtin.assert:
that:
- - get_proxy_info_result["zabbix_proxy"].host == "ExampleProxy"
- - get_proxy_info_result["zabbix_proxy"].hosts | length > 0
- - get_proxy_info_result["zabbix_proxy"].hosts[0].host == "ExampleHost"
- - get_proxy_info_result["zabbix_proxy"].interface | length > 0
- - get_proxy_info_result["zabbix_proxy"].interface.ip == "10.1.1.2"
- - get_proxy_info_result["zabbix_proxy"].interface.useip == "1"
- - get_proxy_info_result["zabbix_proxy"].interface.port == "10051"
- - get_proxy_info_result["zabbix_proxy"].interface.dns == "ExampleProxy.local"
+ - get_proxy_info_result["zabbix_proxy"].host == "ExampleProxy"
+ - get_proxy_info_result["zabbix_proxy"].hosts | length > 0
+ - get_proxy_info_result["zabbix_proxy"].hosts[0].host == "ExampleHost"
+ - get_proxy_info_result["zabbix_proxy"].interface | length > 0
+ - get_proxy_info_result["zabbix_proxy"].interface.ip == "10.1.1.2"
+ - get_proxy_info_result["zabbix_proxy"].interface.useip == "1"
+ - get_proxy_info_result["zabbix_proxy"].interface.port == "10051"
+ - get_proxy_info_result["zabbix_proxy"].interface.dns == "ExampleProxy.local"
- name: test - cleanup test Zabbix host
- zabbix_host:
+ community.zabbix.zabbix_host:
state: absent
host_name: ExampleHost
- name: test - cleanup test Zabbix proxy
- zabbix_proxy:
+ community.zabbix.zabbix_proxy:
state: absent
proxy_name: ExampleProxy
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_regexp/meta/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_regexp/meta/main.yml
new file mode 100644
index 000000000..acdb704c8
--- /dev/null
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_regexp/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - setup_zabbix
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_regexp/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_regexp/tasks/main.yml
new file mode 100644
index 000000000..8e2afc02d
--- /dev/null
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_regexp/tasks/main.yml
@@ -0,0 +1,113 @@
+---
+- name: test - do not run tests with < Zabbix 4.0
+ meta: end_play
+ when: zabbix_version is version('4.0', '<')
+
+- when: zabbix_version is version('6.0', '<')
+ name: Unsupport Zabbix version (<6.0)
+ block:
+ - name: test - fail to update regexp setting
+ community.zabbix.zabbix_regexp:
+ name: File systems for discovery
+ test_string: ext3
+ expressions:
+ - expression: "^(btrfs|ext2|ext3|ext4|reiser|xfs|ffs|ufs|jfs|jfs2|vxfs|hfs|apfs|refs|ntfs|fat32|zfs)$"
+ - expression_type: result_is_true
+ ignore_errors: true
+ register: zbxauth_update
+
+ - ansible.builtin.assert:
+ that: zbxauth_update.failed is sameas True
+
+- when: zabbix_version is version('6.0', '>=')
+ name: support Zabbix version (>=6.0)
+ block:
+ - name: test - try to update regexp (present)
+ community.zabbix.zabbix_regexp:
+ name: File systems for discovery
+ test_string: ext3
+ expressions:
+ - expression: "^(btrfs|ext2|ext3|ext4|reiser|xfs|ffs|ufs|jfs|jfs2|vxfs|hfs|apfs|refs|ntfs|fat32|zfs)$"
+ expression_type: result_is_true
+ register: zbxregexp_update
+
+ - name: assert that regexp was NOT updated
+ ansible.builtin.assert:
+ that:
+ - zbxregexp_update.changed is sameas False
+
+ - name: test - try to delete regexp
+ community.zabbix.zabbix_regexp:
+ name: File systems for discovery
+ state: absent
+ register: zbxregexp_update
+
+ - name: assert that regexp was deleted
+ ansible.builtin.assert:
+ that:
+ - zbxregexp_update.changed is sameas True
+ - zbxregexp_update.msg == "Successfully deleted regular expression setting."
+
+ - name: test - try to create regexp
+ community.zabbix.zabbix_regexp:
+ name: File systems for discovery
+ test_string: ext3
+ expressions:
+ - expression: "^(btrfs|ext2|ext3|ext4|reiser|xfs|ffs|ufs|jfs|jfs2|vxfs|hfs|apfs|refs|ntfs|fat32|zfs)$"
+ expression_type: result_is_true
+ register: zbxregexp_update
+
+ - name: assert that regexp was created
+ ansible.builtin.assert:
+ that:
+ - zbxregexp_update.changed is sameas True
+ - zbxregexp_update.msg == "Successfully created regular expression setting."
+
+ - name: test - try to update regexp
+ community.zabbix.zabbix_regexp:
+ name: File systems for discovery
+ test_string: ext3
+ expressions:
+ - expression: "create"
+ expression_type: character_string_included
+ - expression: "update/delete"
+ expression_type: any_character_string_included
+ case_sensitive: true
+ exp_delimiter: "/"
+ - expression: "failed"
+ expression_type: character_string_not_included
+ - expression: "^(btrfs|ext2|ext3|ext4|reiser|xfs|ffs|ufs|jfs|jfs2|vxfs|hfs|apfs|refs|ntfs|fat32|zfs)$"
+ expression_type: result_is_true
+ - expression: "regexp"
+ expression_type: result_is_false
+ register: zbxregexp_update
+
+ - name: assert that regexp was updated
+ ansible.builtin.assert:
+ that:
+ - zbxregexp_update.changed is sameas True
+ - zbxregexp_update.msg == "Successfully updated regular expression setting."
+
+ - name: test - try to update regexp (will not update)
+ community.zabbix.zabbix_regexp:
+ name: File systems for discovery
+ test_string: ext3
+ expressions:
+ - expression: "update/delete"
+ expression_type: any_character_string_included
+ case_sensitive: true
+ exp_delimiter: "/"
+ - expression: "create"
+ expression_type: character_string_included
+ - expression: "failed"
+ expression_type: character_string_not_included
+ - expression: "^(btrfs|ext2|ext3|ext4|reiser|xfs|ffs|ufs|jfs|jfs2|vxfs|hfs|apfs|refs|ntfs|fat32|zfs)$"
+ expression_type: result_is_true
+ - expression: "regexp"
+ expression_type: result_is_false
+ register: zbxregexp_update
+
+ - name: assert that regexp was updated
+ ansible.builtin.assert:
+ that:
+ - zbxregexp_update.changed is sameas False
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_screen/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_screen/tasks/main.yml
deleted file mode 100644
index 82d1e5f0e..000000000
--- a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_screen/tasks/main.yml
+++ /dev/null
@@ -1,149 +0,0 @@
----
-
-- name: ensure zabbix server is being monitored
- community.zabbix.zabbix_host:
- host_name: Zabbix server
- status: enabled
-
-- name: "Screen got removed with 5.4"
- block:
- - name: test - Check if screen fails on Zabbix >= 5.4
- community.zabbix.zabbix_screen:
- screens:
- - screen_name: TestScreenFail54
- host_group: Zabbix servers
- state: present
- graph_names:
- - 'Zabbix cache usage, % used'
- - 'Zabbix internal process busy %'
- graph_width: 200
- graph_height: 100
- graphs_in_row: 5
- register: result
- ignore_errors: true
- when: zabbix_version is version('5.4', '>=')
-
- - name: expect to fail
- assert:
- that:
- - "result is failed"
- when: zabbix_version is version('5.4', '>=')
-
- - name: End play if Zabbix >= 5.4
- meta: end_play
- when: zabbix_version is version('5.4', '>=')
-
-- name: test - delete the screen again
- community.zabbix.zabbix_screen:
- screens:
- - screen_name: TestScreen1
- state: absent
-
-# #################################################
-# Test screen creation
-# #################################################
-
-- name: test - Create a new screen
- community.zabbix.zabbix_screen:
- screens:
- - screen_name: TestScreen1
- host_group: Zabbix servers
- state: present
- graph_names:
- - 'Zabbix cache usage, % used'
- - 'Zabbix internal process busy %'
- graph_width: 200
- graph_height: 100
- graphs_in_row: 5
- register: result
-
-- assert:
- that:
- - result.changed
-
-- name: test - Create a new screen again
- community.zabbix.zabbix_screen:
- screens:
- - screen_name: TestScreen1
- host_group: Zabbix servers
- state: present
- graph_names:
- - 'Zabbix cache usage, % used'
- - 'Zabbix internal process busy %'
- graph_width: 200
- graph_height: 100
- graphs_in_row: 5
- register: result
-
-- assert:
- that:
- - not result.changed
-
-# #################################################
-# Test screen editing
-# #################################################
-
-- name: test - Adding new graph
- community.zabbix.zabbix_screen:
- screens:
- - screen_name: TestScreen1
- host_group: Zabbix servers
- state: present
- graph_names:
- - 'Zabbix cache usage, % used'
- - 'Zabbix internal process busy %'
- - 'Zabbix internal queues'
- - 'Zabbix server performance'
- - 'Zabbix data gathering process busy %'
- graph_width: 200
- graph_height: 100
- graphs_in_row: 5
- register: result
-
-- assert:
- that:
- - result.changed
-
-- name: test - Removing graph
- community.zabbix.zabbix_screen:
- screens:
- - screen_name: TestScreen1
- host_group: Zabbix servers
- state: present
- graph_names:
- - 'Zabbix cache usage, % used'
- - 'Zabbix internal queues'
- graph_width: 200
- graph_height: 100
- graphs_in_row: 5
- register: result
-
-- assert:
- that:
- - result.changed
-
-# #################################################
-# Test screen deletion
-# #################################################
-
-- name: test - delete the screen
- community.zabbix.zabbix_screen:
- screens:
- - screen_name: TestScreen1
- state: absent
- register: result
-
-- assert:
- that:
- - result.changed
-
-- name: test - delete the screen again
- community.zabbix.zabbix_screen:
- screens:
- - screen_name: TestScreen1
- state: absent
- register: result
-
-- assert:
- that:
- - not result.changed
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_script/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_script/tasks/main.yml
index fe5c40519..4c5ea8a4c 100644
--- a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_script/tasks/main.yml
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_script/tasks/main.yml
@@ -1,347 +1,343 @@
---
-- name: test - do not run tests for Zabbix < 6.0
- meta: end_play
- when: zabbix_version is version('6.0', '<')
-
- name: test - Test action operation script
module_defaults:
community.zabbix.zabbix_script:
name: Test action operation script
scope: action_operation
script_type: webhook
- command: 'return 0'
+ command: "return 0"
description: "Test action operation script"
state: present
block:
- - name: test - Create new action operation script to execute webhook check mode
- zabbix_script:
- check_mode: true
- register: create_action_check_mode_result
-
- - assert:
- that:
- - create_action_check_mode_result.changed is sameas true
-
- - name: test - Create new action operation script to execute webhook
- zabbix_script:
- register: create_action_result
-
- - assert:
- that:
- - create_action_result.changed is sameas true
-
- - name: test - Create new action operation script to execute webhook again
- zabbix_script:
- register: create_action_again_result
-
- - assert:
- that:
- - create_action_again_result.changed is sameas false
-
- - name: test - Update action operation script to execute webhook with host group
- zabbix_script:
- host_group: 'Discovered hosts'
- register: update_action_host_group_result
-
- - assert:
- that:
- - update_action_host_group_result.changed is sameas true
-
- - name: test - Update action operation script to execute webhook with host group again
- zabbix_script:
- host_group: 'Discovered hosts'
- register: update_action_host_group_again_result
-
- - assert:
- that:
- - update_action_host_group_again_result.changed is sameas false
-
- - name: test - Update action operation script to execute webhook with parameters
- zabbix_script:
- host_group: 'Discovered hosts'
- parameters:
- - name: param_name1
- register: update_action_param_result
-
- - assert:
- that:
- - update_action_param_result.changed is sameas true
-
- - name: test - Update action operation script to execute webhook with parameters again
- zabbix_script:
- host_group: 'Discovered hosts'
- parameters:
- - name: param_name1
- register: update_action_param_again_result
-
- - assert:
- that:
- - update_action_param_again_result.changed is sameas false
-
- - name: test - Update action operation script to execute webhook with parameters and value
- zabbix_script:
- host_group: 'Discovered hosts'
- parameters:
- - name: param_name1
- - name: param_name2
- value: value2
- register: update_action_param_value_result
-
- - assert:
- that:
- - update_action_param_value_result.changed is sameas true
-
- - name: test - Update action operation script to execute webhook with parameters and value again
- zabbix_script:
- host_group: 'Discovered hosts'
- parameters:
- - name: param_name1
- - name: param_name2
- value: value2
- register: update_action_param_value_again_result
-
- - assert:
- that:
- - update_action_param_value_again_result.changed is sameas false
-
- - name: test - Update action operation script remove host group
- zabbix_script:
- parameters:
- - name: param_name1
- - name: param_name2
- value: value2
- register: update_action_no_host_group_result
-
- - assert:
- that:
- - update_action_no_host_group_result.changed is sameas true
-
- - name: test - Update action operation script remove host group again
- zabbix_script:
- parameters:
- - name: param_name1
- - name: param_name2
- value: value2
- register: update_action_no_host_group_again_result
-
- - assert:
- that:
- - update_action_no_host_group_again_result.changed is sameas false
-
- - name: test - Update action operation script to type Script
- zabbix_script:
- script_type: script
- execute_on: zabbix_agent
- command: echo 1
- register: update_action_script_result
-
- - assert:
- that:
- - update_action_script_result.changed is sameas true
-
- - name: test - Update action operation script to type Script again
- zabbix_script:
- script_type: script
- execute_on: zabbix_agent
- command: echo 1
- register: update_action_script_again_result
-
- - assert:
- that:
- - update_action_script_again_result.changed is sameas false
-
- - name: test - Update action operation script to execute on server
- zabbix_script:
- script_type: script
- execute_on: zabbix_server
- command: echo 1
- register: update_action_script_server_result
-
- - assert:
- that:
- - update_action_script_server_result.changed is sameas true
-
- - name: test - Update action operation script to execute on server again
- zabbix_script:
- script_type: script
- execute_on: zabbix_server
- command: echo 1
- register: update_action_script_server_again_result
-
- - assert:
- that:
- - update_action_script_server_again_result.changed is sameas false
-
- - name: test - Update action operation script to execute on server or proxy
- zabbix_script:
- script_type: script
- execute_on: zabbix_server_proxy
- command: echo 1
- register: update_action_script_server_proxy_result
-
- - assert:
- that:
- - update_action_script_server_proxy_result.changed is sameas true
-
- - name: test - Update action operation script to execute on server or proxy again
- zabbix_script:
- script_type: script
- execute_on: zabbix_server_proxy
- command: echo 1
- register: update_action_script_server_proxy_again_result
-
- - assert:
- that:
- - update_action_script_server_proxy_again_result.changed is sameas false
-
- - name: test - Update action operation script to type SSH
- zabbix_script:
- script_type: ssh
- authtype: password
- username: bla
- password: blabla
- command: echo 2
- register: update_action_script_ssh_result
-
- - assert:
- that:
- - update_action_script_ssh_result.changed is sameas true
-
- - name: test - Update action operation script to type SSH again
- zabbix_script:
- script_type: ssh
- authtype: password
- username: bla
- password: blabla
- command: echo 2
- register: update_action_script_ssh_again_result
-
- - assert:
- that:
- - update_action_script_ssh_again_result.changed is sameas false
-
- - name: test - Update action operation script type SSH key auth
- zabbix_script:
- script_type: ssh
- authtype: public_key
- username: bla
- publickey: blabla
- privatekey: blablabla
- command: echo 3
- register: update_action_script_ssh_authkey_result
-
- - assert:
- that:
- - update_action_script_ssh_authkey_result.changed is sameas true
-
- - name: test - Update action operation script type SSH key auth again
- zabbix_script:
- script_type: ssh
- authtype: public_key
- username: bla
- publickey: blabla
- privatekey: blablabla
- command: echo 3
- register: update_action_script_ssh_authkey_again_result
-
- - assert:
- that:
- - update_action_script_ssh_authkey_again_result.changed is sameas false
-
- - name: test - Update action operation script type SSH add port
- zabbix_script:
- script_type: ssh
- authtype: public_key
- username: bla
- publickey: blabla
- privatekey: blablabla
- command: echo 3
- port: 222
- register: update_action_script_ssh_port_result
-
- - assert:
- that:
- - update_action_script_ssh_port_result.changed is sameas true
-
- - name: test - Update action operation script type SSH add port again
- zabbix_script:
- script_type: ssh
- authtype: public_key
- username: bla
- publickey: blabla
- privatekey: blablabla
- command: echo 3
- port: 222
- register: update_action_script_ssh_port_again_result
-
- - assert:
- that:
- - update_action_script_ssh_port_again_result.changed is sameas false
-
- - name: test - Update action operation script to type Telnet
- zabbix_script:
- script_type: telnet
- username: bla1
- password: blabla1
- command: echo 4
- port: 223
- register: update_action_script_telnet_result
-
- - assert:
- that:
- - update_action_script_telnet_result.changed is sameas true
-
- - name: test - Update action operation script to type Telnet again
- zabbix_script:
- script_type: telnet
- username: bla1
- password: blabla1
- command: echo 4
- port: 223
- register: update_action_script_telnet_again_result
-
- - assert:
- that:
- - update_action_script_telnet_again_result.changed is sameas false
-
- - name: test - Update action operation script to type IPMI
- zabbix_script:
- script_type: ipmi
- command: echo 5
- register: update_action_script_ipmi_result
-
- - assert:
- that:
- - update_action_script_ipmi_result.changed is sameas true
-
- - name: test - Update action operation script to type IPMI again
- zabbix_script:
- script_type: ipmi
- command: echo 5
- register: update_action_script_ipmi_again_result
-
- - assert:
- that:
- - update_action_script_ipmi_again_result.changed is sameas false
-
- - name: test - Delete action operation script
- zabbix_script:
- state: absent
- register: delete_action_result
-
- - assert:
- that:
- - delete_action_result.changed is sameas true
-
- - name: test - Delete action operation script again
- zabbix_script:
- state: absent
- register: delete_action_again_result
-
- - assert:
- that:
- - delete_action_again_result.changed is sameas false
+ - name: test - Create new action operation script to execute webhook check mode
+ zabbix_script:
+ check_mode: true
+ register: create_action_check_mode_result
+
+ - assert:
+ that:
+ - create_action_check_mode_result.changed is sameas true
+
+ - name: test - Create new action operation script to execute webhook
+ zabbix_script:
+ register: create_action_result
+
+ - assert:
+ that:
+ - create_action_result.changed is sameas true
+
+ - name: test - Create new action operation script to execute webhook again
+ zabbix_script:
+ register: create_action_again_result
+
+ - assert:
+ that:
+ - create_action_again_result.changed is sameas false
+
+ - name: test - Update action operation script to execute webhook with host group
+ zabbix_script:
+ host_group: "Discovered hosts"
+ register: update_action_host_group_result
+
+ - assert:
+ that:
+ - update_action_host_group_result.changed is sameas true
+
+ - name: test - Update action operation script to execute webhook with host group again
+ zabbix_script:
+ host_group: "Discovered hosts"
+ register: update_action_host_group_again_result
+
+ - assert:
+ that:
+ - update_action_host_group_again_result.changed is sameas false
+
+ - name: test - Update action operation script to execute webhook with parameters
+ zabbix_script:
+ host_group: "Discovered hosts"
+ parameters:
+ - name: param_name1
+ register: update_action_param_result
+
+ - assert:
+ that:
+ - update_action_param_result.changed is sameas true
+
+ - name: test - Update action operation script to execute webhook with parameters again
+ zabbix_script:
+ host_group: "Discovered hosts"
+ parameters:
+ - name: param_name1
+ register: update_action_param_again_result
+
+ - assert:
+ that:
+ - update_action_param_again_result.changed is sameas false
+
+ - name: test - Update action operation script to execute webhook with parameters and value
+ zabbix_script:
+ host_group: "Discovered hosts"
+ parameters:
+ - name: param_name1
+ - name: param_name2
+ value: value2
+ register: update_action_param_value_result
+
+ - assert:
+ that:
+ - update_action_param_value_result.changed is sameas true
+
+ - name: test - Update action operation script to execute webhook with parameters and value again
+ zabbix_script:
+ host_group: "Discovered hosts"
+ parameters:
+ - name: param_name1
+ - name: param_name2
+ value: value2
+ register: update_action_param_value_again_result
+
+ - assert:
+ that:
+ - update_action_param_value_again_result.changed is sameas false
+
+ - name: test - Update action operation script remove host group
+ zabbix_script:
+ parameters:
+ - name: param_name1
+ - name: param_name2
+ value: value2
+ register: update_action_no_host_group_result
+
+ - assert:
+ that:
+ - update_action_no_host_group_result.changed is sameas true
+
+ - name: test - Update action operation script remove host group again
+ zabbix_script:
+ parameters:
+ - name: param_name1
+ - name: param_name2
+ value: value2
+ register: update_action_no_host_group_again_result
+
+ - assert:
+ that:
+ - update_action_no_host_group_again_result.changed is sameas false
+
+ - name: test - Update action operation script to type Script
+ zabbix_script:
+ script_type: script
+ execute_on: zabbix_agent
+ command: echo 1
+ register: update_action_script_result
+
+ - assert:
+ that:
+ - update_action_script_result.changed is sameas true
+
+ - name: test - Update action operation script to type Script again
+ zabbix_script:
+ script_type: script
+ execute_on: zabbix_agent
+ command: echo 1
+ register: update_action_script_again_result
+
+ - assert:
+ that:
+ - update_action_script_again_result.changed is sameas false
+
+ - name: test - Update action operation script to execute on server
+ zabbix_script:
+ script_type: script
+ execute_on: zabbix_server
+ command: echo 1
+ register: update_action_script_server_result
+
+ - assert:
+ that:
+ - update_action_script_server_result.changed is sameas true
+
+ - name: test - Update action operation script to execute on server again
+ zabbix_script:
+ script_type: script
+ execute_on: zabbix_server
+ command: echo 1
+ register: update_action_script_server_again_result
+
+ - assert:
+ that:
+ - update_action_script_server_again_result.changed is sameas false
+
+ - name: test - Update action operation script to execute on server or proxy
+ zabbix_script:
+ script_type: script
+ execute_on: zabbix_server_proxy
+ command: echo 1
+ register: update_action_script_server_proxy_result
+
+ - assert:
+ that:
+ - update_action_script_server_proxy_result.changed is sameas true
+
+ - name: test - Update action operation script to execute on server or proxy again
+ zabbix_script:
+ script_type: script
+ execute_on: zabbix_server_proxy
+ command: echo 1
+ register: update_action_script_server_proxy_again_result
+
+ - assert:
+ that:
+ - update_action_script_server_proxy_again_result.changed is sameas false
+
+ - name: test - Update action operation script to type SSH
+ zabbix_script:
+ script_type: ssh
+ authtype: password
+ username: bla
+ password: blabla
+ command: echo 2
+ register: update_action_script_ssh_result
+
+ - assert:
+ that:
+ - update_action_script_ssh_result.changed is sameas true
+
+ - name: test - Update action operation script to type SSH again
+ zabbix_script:
+ script_type: ssh
+ authtype: password
+ username: bla
+ password: blabla
+ command: echo 2
+ register: update_action_script_ssh_again_result
+
+ - assert:
+ that:
+ - update_action_script_ssh_again_result.changed is sameas false
+
+ - name: test - Update action operation script type SSH key auth
+ zabbix_script:
+ script_type: ssh
+ authtype: public_key
+ username: bla
+ publickey: blabla
+ privatekey: blablabla
+ command: echo 3
+ register: update_action_script_ssh_authkey_result
+
+ - assert:
+ that:
+ - update_action_script_ssh_authkey_result.changed is sameas true
+
+ - name: test - Update action operation script type SSH key auth again
+ zabbix_script:
+ script_type: ssh
+ authtype: public_key
+ username: bla
+ publickey: blabla
+ privatekey: blablabla
+ command: echo 3
+ register: update_action_script_ssh_authkey_again_result
+
+ - assert:
+ that:
+ - update_action_script_ssh_authkey_again_result.changed is sameas false
+
+ - name: test - Update action operation script type SSH add port
+ zabbix_script:
+ script_type: ssh
+ authtype: public_key
+ username: bla
+ publickey: blabla
+ privatekey: blablabla
+ command: echo 3
+ port: 222
+ register: update_action_script_ssh_port_result
+
+ - assert:
+ that:
+ - update_action_script_ssh_port_result.changed is sameas true
+
+ - name: test - Update action operation script type SSH add port again
+ zabbix_script:
+ script_type: ssh
+ authtype: public_key
+ username: bla
+ publickey: blabla
+ privatekey: blablabla
+ command: echo 3
+ port: 222
+ register: update_action_script_ssh_port_again_result
+
+ - assert:
+ that:
+ - update_action_script_ssh_port_again_result.changed is sameas false
+
+ - name: test - Update action operation script to type Telnet
+ zabbix_script:
+ script_type: telnet
+ username: bla1
+ password: blabla1
+ command: echo 4
+ port: 223
+ register: update_action_script_telnet_result
+
+ - assert:
+ that:
+ - update_action_script_telnet_result.changed is sameas true
+
+ - name: test - Update action operation script to type Telnet again
+ zabbix_script:
+ script_type: telnet
+ username: bla1
+ password: blabla1
+ command: echo 4
+ port: 223
+ register: update_action_script_telnet_again_result
+
+ - assert:
+ that:
+ - update_action_script_telnet_again_result.changed is sameas false
+
+ - name: test - Update action operation script to type IPMI
+ zabbix_script:
+ script_type: ipmi
+ command: echo 5
+ register: update_action_script_ipmi_result
+
+ - assert:
+ that:
+ - update_action_script_ipmi_result.changed is sameas true
+
+ - name: test - Update action operation script to type IPMI again
+ zabbix_script:
+ script_type: ipmi
+ command: echo 5
+ register: update_action_script_ipmi_again_result
+
+ - assert:
+ that:
+ - update_action_script_ipmi_again_result.changed is sameas false
+
+ - name: test - Delete action operation script
+ zabbix_script:
+ state: absent
+ register: delete_action_result
+
+ - assert:
+ that:
+ - delete_action_result.changed is sameas true
+
+ - name: test - Delete action operation script again
+ zabbix_script:
+ state: absent
+ register: delete_action_again_result
+
+ - assert:
+ that:
+ - delete_action_again_result.changed is sameas false
- name: test - Test manual host action script
module_defaults:
@@ -349,125 +345,125 @@
name: Test manual host action script
scope: manual_host_action
script_type: webhook
- command: 'return 0'
+ command: "return 0"
description: "Test manual host action script"
state: present
block:
- - name: test - Create new manual host action script to execute webhook check mode
- zabbix_script:
- parameters:
- - name: param_name1
- - name: param_name2
- value: value2
- check_mode: true
- register: create_action_check_mode_result
-
- - assert:
- that:
- - create_action_check_mode_result.changed is sameas true
-
- - name: test - Create new manual host action script to execute webhook
- zabbix_script:
- parameters:
- - name: param_name1
- - name: param_name2
- value: value2
- register: create_action_result
-
- - assert:
- that:
- - create_action_result.changed is sameas true
-
- - name: test - Create new manual host action script to execute webhook again
- zabbix_script:
- parameters:
- - name: param_name1
- - name: param_name2
- value: value2
- register: create_action_again_result
-
- - assert:
- that:
- - create_action_again_result.changed is sameas false
-
- - name: test - Update manual host action script with menu path
- zabbix_script:
- menu_path: menu/submenu
- register: update_action_result
-
- - assert:
- that:
- - update_action_result.changed is sameas true
-
- - name: test - Update manual host action script with menu path again
- zabbix_script:
- menu_path: menu/submenu
- register: update_action_again_result
-
- - assert:
- that:
- - update_action_again_result.changed is sameas false
-
- - name: test - Update manual host action script with user group
- zabbix_script:
- menu_path: menu/submenu
- user_group: Guests
- register: update_action_usrgrp_result
-
- - assert:
- that:
- - update_action_usrgrp_result.changed is sameas true
-
- - name: test - Update manual host action script with user group again
- zabbix_script:
- menu_path: menu/submenu
- user_group: Guests
- register: update_action_usrgrp_again_result
-
- - assert:
- that:
- - update_action_usrgrp_again_result.changed is sameas false
-
- - name: test - Update manual host action script with Write permissions
- zabbix_script:
- host_access: write
- register: update_action_host_perms_result
-
- - assert:
- that:
- - update_action_host_perms_result.changed is sameas true
-
- - name: test - Update manual host action script with Write permissions again
- zabbix_script:
- host_access: write
- register: update_action_host_perms_again_result
-
- - assert:
- that:
- - update_action_host_perms_again_result.changed is sameas false
-
- - name: test - Update manual host action script with confirmation
- zabbix_script:
- confirmation: 'Are you sure?'
- register: update_action_host_confirm_result
-
- - assert:
- that:
- - update_action_host_confirm_result.changed is sameas true
-
- - name: test - Update manual host action script with confirmation again
- zabbix_script:
- confirmation: 'Are you sure?'
- register: update_action_host_confirm_again_result
-
- - assert:
- that:
- - update_action_host_confirm_again_result.changed is sameas false
-
- - name: test - Delete manual host action script
- zabbix_script:
- state: absent
+ - name: test - Create new manual host action script to execute webhook check mode
+ zabbix_script:
+ parameters:
+ - name: param_name1
+ - name: param_name2
+ value: value2
+ check_mode: true
+ register: create_action_check_mode_result
+
+ - assert:
+ that:
+ - create_action_check_mode_result.changed is sameas true
+
+ - name: test - Create new manual host action script to execute webhook
+ zabbix_script:
+ parameters:
+ - name: param_name1
+ - name: param_name2
+ value: value2
+ register: create_action_result
+
+ - assert:
+ that:
+ - create_action_result.changed is sameas true
+
+ - name: test - Create new manual host action script to execute webhook again
+ zabbix_script:
+ parameters:
+ - name: param_name1
+ - name: param_name2
+ value: value2
+ register: create_action_again_result
+
+ - assert:
+ that:
+ - create_action_again_result.changed is sameas false
+
+ - name: test - Update manual host action script with menu path
+ zabbix_script:
+ menu_path: menu/submenu
+ register: update_action_result
+
+ - assert:
+ that:
+ - update_action_result.changed is sameas true
+
+ - name: test - Update manual host action script with menu path again
+ zabbix_script:
+ menu_path: menu/submenu
+ register: update_action_again_result
+
+ - assert:
+ that:
+ - update_action_again_result.changed is sameas false
+
+ - name: test - Update manual host action script with user group
+ zabbix_script:
+ menu_path: menu/submenu
+ user_group: Guests
+ register: update_action_usrgrp_result
+
+ - assert:
+ that:
+ - update_action_usrgrp_result.changed is sameas true
+
+ - name: test - Update manual host action script with user group again
+ zabbix_script:
+ menu_path: menu/submenu
+ user_group: Guests
+ register: update_action_usrgrp_again_result
+
+ - assert:
+ that:
+ - update_action_usrgrp_again_result.changed is sameas false
+
+ - name: test - Update manual host action script with Write permissions
+ zabbix_script:
+ host_access: write
+ register: update_action_host_perms_result
+
+ - assert:
+ that:
+ - update_action_host_perms_result.changed is sameas true
+
+ - name: test - Update manual host action script with Write permissions again
+ zabbix_script:
+ host_access: write
+ register: update_action_host_perms_again_result
+
+ - assert:
+ that:
+ - update_action_host_perms_again_result.changed is sameas false
+
+ - name: test - Update manual host action script with confirmation
+ zabbix_script:
+ confirmation: "Are you sure?"
+ register: update_action_host_confirm_result
+
+ - assert:
+ that:
+ - update_action_host_confirm_result.changed is sameas true
+
+ - name: test - Update manual host action script with confirmation again
+ zabbix_script:
+ confirmation: "Are you sure?"
+ register: update_action_host_confirm_again_result
+
+ - assert:
+ that:
+ - update_action_host_confirm_again_result.changed is sameas false
+
+ - name: test - Delete manual host action script
+ zabbix_script:
+ state: absent
- name: test - Test manual event action script
module_defaults:
@@ -475,49 +471,49 @@
name: Test manual event action script
scope: manual_event_action
script_type: webhook
- command: 'return 0'
+ command: "return 0"
description: "Test manual event action script"
state: present
block:
- - name: test - Create new manual event action script to execute webhook check mode
- zabbix_script:
- parameters:
- - name: param_name1
- - name: param_name2
- value: value2
- check_mode: true
- register: create_action_check_mode_result
-
- - assert:
- that:
- - create_action_check_mode_result.changed is sameas true
-
- - name: test - Create new manual event action script to execute webhook
- zabbix_script:
- parameters:
- - name: param_name1
- - name: param_name2
- value: value2
- register: create_action_result
-
- - assert:
- that:
- - create_action_result.changed is sameas true
-
- - name: test - Create new manual event action script to execute webhook again
- zabbix_script:
- parameters:
- - name: param_name1
- - name: param_name2
- value: value2
- diff: true
- register: create_action_again_result
-
- - assert:
- that:
- - create_action_again_result.changed is sameas false
-
- - name: test - Delete manual host action script
- zabbix_script:
- state: absent
+ - name: test - Create new manual event action script to execute webhook check mode
+ zabbix_script:
+ parameters:
+ - name: param_name1
+ - name: param_name2
+ value: value2
+ check_mode: true
+ register: create_action_check_mode_result
+
+ - assert:
+ that:
+ - create_action_check_mode_result.changed is sameas true
+
+ - name: test - Create new manual event action script to execute webhook
+ zabbix_script:
+ parameters:
+ - name: param_name1
+ - name: param_name2
+ value: value2
+ register: create_action_result
+
+ - assert:
+ that:
+ - create_action_result.changed is sameas true
+
+ - name: test - Create new manual event action script to execute webhook again
+ zabbix_script:
+ parameters:
+ - name: param_name1
+ - name: param_name2
+ value: value2
+ diff: true
+ register: create_action_again_result
+
+ - assert:
+ that:
+ - create_action_again_result.changed is sameas false
+
+ - name: test - Delete manual host action script
+ zabbix_script:
+ state: absent
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_service/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_service/tasks/main.yml
index f4fc761b1..03501a43b 100644
--- a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_service/tasks/main.yml
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_service/tasks/main.yml
@@ -1,305 +1,5 @@
---
-- when: zabbix_version is version('6.0', '<')
- module_defaults:
- community.zabbix.zabbix_service:
- name: ExampleServiceForServiceModule
- sla: 99.99
- sortorder: 0
- state: present
-
- block:
- - name: "test - Create a new service with check_mode"
- zabbix_service:
- check_mode: true
- register: create_service_check_mode_result
-
- - assert:
- that:
- - create_service_check_mode_result.changed is sameas true
-
- - name: "test - Create a new service"
- zabbix_service:
- register: create_service_result
-
- - assert:
- that:
- - create_service_result.changed is sameas true
-
- - name: "test - Create a new service (idempotency check)"
- zabbix_service:
- register: create_service_idempotency_check_result
-
- - assert:
- that:
- - create_service_idempotency_check_result.changed is sameas false
-
- - name: "test - Update a sla with check_mode"
- zabbix_service:
- sla: 99.999
- check_mode: true
- register: update_sla_check_mode_result
-
- - assert:
- that:
- - update_sla_check_mode_result.changed is sameas true
-
- - name: "test - Update a sla"
- zabbix_service:
- sla: 99.999
- register: update_sla_result
-
- - assert:
- that:
- - update_sla_result.changed is sameas true
-
- - name: "test - Update a sla (idempotency check)"
- zabbix_service:
- sla: 99.999
- register: update_sla_idempotency_check_result
-
- - assert:
- that:
- - update_sla_idempotency_check_result.changed is sameas false
-
- - name: "test - Update a calculate_sla with check_mode"
- zabbix_service:
- sla: 99.999
- calculate_sla: true
- check_mode: true
- register: update_calculate_sla_check_mode_result
-
- - assert:
- that:
- - update_calculate_sla_check_mode_result.changed is sameas true
-
- - name: "test - Update a calculate_sla"
- zabbix_service:
- sla: 99.999
- calculate_sla: true
- register: update_calculate_sla_result
-
- - assert:
- that:
- - update_calculate_sla_result.changed is sameas true
-
- - name: "test - Update a calculate_sla (idempotency check)"
- zabbix_service:
- sla: 99.999
- calculate_sla: true
- register: update_calculate_sla_idempotency_check_result
-
- - assert:
- that:
- - update_calculate_sla_idempotency_check_result.changed is sameas false
-
- - name: "Override trigger_name for different version of Zabbix"
- set_fact:
- service_example_trigger: "Zabbix server: Utilization of http poller processes over 75%"
- when: zabbix_version is version("5.0", "==")
-
- - name: "test - Update trigger_host and trigger_name with check_mode"
- zabbix_service:
- sla: 99.999
- calculate_sla: true
- trigger_host: "Zabbix server"
- trigger_name: "{{ service_example_trigger }}"
- check_mode: true
- register: update_trigger_name_check_mode_result
-
- - assert:
- that:
- - update_trigger_name_check_mode_result.changed is sameas true
-
- - name: "test - Update trigger_host and trigger_name"
- zabbix_service:
- sla: 99.999
- calculate_sla: true
- trigger_host: "Zabbix server"
- trigger_name: "{{ service_example_trigger }}"
- register: update_trigger_name_result
-
- - assert:
- that:
- - update_trigger_name_result.changed is sameas true
-
- - name: "test - Update trigger_host and trigger_name (idempotency check)"
- zabbix_service:
- sla: 99.999
- calculate_sla: true
- trigger_host: "Zabbix server"
- trigger_name: "{{ service_example_trigger }}"
- register: update_trigger_name_idempotency_check_result
-
- - assert:
- that:
- - update_trigger_name_idempotency_check_result.changed is sameas false
-
- - name: "test - Update a algorithm of service with check_mode"
- zabbix_service:
- sla: 99.999
- calculate_sla: true
- trigger_host: "Zabbix server"
- trigger_name: "{{ service_example_trigger }}"
- algorithm: all_children
- check_mode: true
- register: update_algorithm_check_mode_result
-
- - assert:
- that:
- - update_algorithm_check_mode_result.changed is sameas true
-
- - name: "test - Update a algorithm of service"
- zabbix_service:
- sla: 99.999
- calculate_sla: true
- trigger_host: "Zabbix server"
- trigger_name: "{{ service_example_trigger }}"
- algorithm: all_children
- register: update_algorithm_result
-
- - assert:
- that:
- - update_algorithm_result.changed is sameas true
-
- - name: "test - Update a algorithm of service (idempotency check)"
- zabbix_service:
- sla: 99.999
- calculate_sla: true
- trigger_host: "Zabbix server"
- trigger_name: "{{ service_example_trigger }}"
- algorithm: all_children
- register: update_algorithm_idempotency_check_result
-
- - assert:
- that:
- - update_algorithm_idempotency_check_result.changed is sameas false
-
- - name: "test - Create a new root service for parent test"
- zabbix_service:
- name: ExampleServiceForServiceModuleRoot
- sla: 99.99
- register: create_child_service_result
-
- - assert:
- that:
- - create_child_service_result.changed is sameas true
-
- - name: "test - Update a parent of child service with check_mode"
- zabbix_service:
- name: ExampleServiceForServiceModule
- sla: 99.999
- calculate_sla: true
- trigger_host: "Zabbix server"
- trigger_name: "{{ service_example_trigger }}"
- algorithm: all_children
- parent: ExampleServiceForServiceModuleRoot
- check_mode: true
- register: create_parent_child_service_check_mode_result
-
- - assert:
- that:
- - create_parent_child_service_check_mode_result.changed is sameas true
-
- - name: "test - Update a parent of child service"
- zabbix_service:
- name: ExampleServiceForServiceModule
- sla: 99.999
- calculate_sla: true
- trigger_host: "Zabbix server"
- trigger_name: "{{ service_example_trigger }}"
- algorithm: all_children
- parent: ExampleServiceForServiceModuleRoot
- register: create_parent_child_service_result
-
- - assert:
- that:
- - create_parent_child_service_result.changed is sameas true
-
- - name: "test - Update a parent of child service (idempotency check)"
- zabbix_service:
- name: ExampleServiceForServiceModule
- sla: 99.999
- calculate_sla: true
- trigger_host: "Zabbix server"
- trigger_name: "{{ service_example_trigger }}"
- algorithm: all_children
- parent: ExampleServiceForServiceModuleRoot
- register: create_parent_child_service_idempotency_check_result
-
- - assert:
- that:
- - create_parent_child_service_idempotency_check_result.changed is sameas false
-
- - name: "test - Remove ExampleServiceForServiceModule service with check_mode"
- zabbix_service:
- name: ExampleServiceForServiceModule
- sla: 99.999
- state: absent
- check_mode: true
- register: remove_service_with_check_mode_result
-
- - assert:
- that:
- - remove_service_with_check_mode_result.changed is sameas true
-
- - name: "test - Remove ExampleServiceForServiceModule service"
- zabbix_service:
- name: ExampleServiceForServiceModule
- sla: 99.999
- state: absent
- register: remove_service_result
-
- - assert:
- that:
- - remove_service_result.changed is sameas true
-
- - name: "test - Remove ExampleServiceForServiceModule service (idempotency check)"
- zabbix_service:
- name: ExampleServiceForServiceModule
- sla: 99.999
- state: absent
- register: remove_service_idempotency_check_result
-
- - assert:
- that:
- - remove_service_idempotency_check_result.changed is sameas false
-
- - name: "test - Remove ExampleServiceForServiceModuleRoot service with check_mode"
- zabbix_service:
- name: ExampleServiceForServiceModuleRoot
- sla: 99.999
- state: absent
- check_mode: true
- register: remove_root_service_with_check_mode_result
-
- - assert:
- that:
- - remove_root_service_with_check_mode_result.changed is sameas true
-
- - name: "test - Remove ExampleServiceForServiceModuleRoot service"
- zabbix_service:
- name: ExampleServiceForServiceModuleRoot
- sla: 99.999
- state: absent
- register: remove_root_service_result
-
- - assert:
- that:
- - remove_root_service_result.changed is sameas true
-
- - name: "test - Remove ExampleServiceForServiceModuleRoot service (idempotency check)"
- zabbix_service:
- name: ExampleServiceForServiceModuleRoot
- sla: 99.999
- state: absent
- register: remove_root_service_idempotency_check_result
-
- - assert:
- that:
- - remove_root_service_idempotency_check_result.changed is sameas false
-
-- name: test - service for Zabbix >= 6.0
- when: zabbix_version is version('6.0', '>=')
+- name: test - service
module_defaults:
community.zabbix.zabbix_service:
description: "Example Service for Service Module"
@@ -310,59 +10,59 @@
block:
- name: "test - Create a new service with check_mode"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleServiceForServiceModule
check_mode: true
register: create_service_check_mode_result
- - assert:
+ - ansible.builtin.assert:
that:
- create_service_check_mode_result.changed is sameas true
- name: "test - Create a new service"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleServiceForServiceModule
register: create_service_result
- - assert:
+ - ansible.builtin.assert:
that:
- create_service_result.changed is sameas true
- name: "test - Create a new service (idempotency check)"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleServiceForServiceModule
register: create_service_idempotency_check_result
- - assert:
+ - ansible.builtin.assert:
that:
- create_service_idempotency_check_result.changed is sameas false
- name: "test - Update service add service tags"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleServiceForServiceModule
tags:
- tag: TagName1
value: TagValue1
register: update_service_stags_result
- - assert:
+ - ansible.builtin.assert:
that:
- update_service_stags_result.changed is sameas true
- name: "test - Update service with service tags (idempotency check)"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleServiceForServiceModule
tags:
- tag: TagName1
value: TagValue1
register: update_service_stags_idempotency_check_result
- - assert:
+ - ansible.builtin.assert:
that:
- update_service_stags_idempotency_check_result.changed is sameas false
- name: "test - Update service add more service tags"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleServiceForServiceModule
tags:
- tag: TagName1
@@ -371,12 +71,12 @@
value: TagValue2
register: update_service_more_stags_result
- - assert:
+ - ansible.builtin.assert:
that:
- update_service_more_stags_result.changed is sameas true
- name: "test - Update service add more service tags (idempotency check)"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleServiceForServiceModule
tags:
- tag: TagName1
@@ -385,41 +85,41 @@
value: TagValue2
register: update_service_more_stags_idempotency_check_result
- - assert:
+ - ansible.builtin.assert:
that:
- update_service_more_stags_idempotency_check_result.changed is sameas false
- name: "test - Update service remove service tags"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleServiceForServiceModule
tags:
- tag: TagName2
value: TagValue2
register: update_service_less_stags_result
- - assert:
+ - ansible.builtin.assert:
that:
- update_service_less_stags_result.changed is sameas true
- name: "test - Update service remove service tags (idempotency check)"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleServiceForServiceModule
tags:
- tag: TagName2
value: TagValue2
register: update_service_less_stags_idempotency_check_result
- - assert:
+ - ansible.builtin.assert:
that:
- update_service_less_stags_idempotency_check_result.changed is sameas false
- name: "test - Delete service"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleServiceForServiceModule
state: absent
- name: "test - Create service with one problem tag"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleServiceForServiceModule
problem_tags:
- tag: TagName1
@@ -427,12 +127,12 @@
value: TagValue1
register: create_service_with_ptag_result
- - assert:
+ - ansible.builtin.assert:
that:
- create_service_with_ptag_result.changed is sameas true
- name: "test - Create service with one problem tag (idempotency check)"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleServiceForServiceModule
problem_tags:
- tag: TagName1
@@ -441,7 +141,7 @@
register: create_service_with_ptag_idempotency_check_result
- name: "test - Update service with problem tag without operator"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleServiceForServiceModule
problem_tags:
- tag: TagName1
@@ -451,12 +151,12 @@
value: TagValue2
register: update_service_with_ptag_woop_result
- - assert:
+ - ansible.builtin.assert:
that:
- update_service_with_ptag_woop_result.changed is sameas true
- name: "test - Update service with problem tag without operator (idempotency check)"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleServiceForServiceModule
problem_tags:
- tag: TagName1
@@ -466,12 +166,12 @@
value: TagValue2
register: update_service_with_ptag_woop_idempotency_check_result
- - assert:
+ - ansible.builtin.assert:
that:
- update_service_with_ptag_woop_idempotency_check_result.changed is sameas false
- name: "test - Update service with problem tag with like operator"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleServiceForServiceModule
problem_tags:
- tag: TagName1
@@ -484,12 +184,12 @@
value: TagValue3
register: update_service_with_ptag_wlikeop_result
- - assert:
+ - ansible.builtin.assert:
that:
- update_service_with_ptag_wlikeop_result.changed is sameas true
- name: "test - Update service with problem tag with like operator (idempotency check)"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleServiceForServiceModule
problem_tags:
- tag: TagName1
@@ -502,12 +202,12 @@
value: TagValue3
register: update_service_with_ptag_wlikeop_idempotency_check_result
- - assert:
+ - ansible.builtin.assert:
that:
- update_service_with_ptag_wlikeop_idempotency_check_result.changed is sameas false
- name: "test - Update service with problem tag without operator and without value"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleServiceForServiceModule
problem_tags:
- tag: TagName1
@@ -521,12 +221,12 @@
- tag: TagName4
register: update_service_with_ptag_woov_result
- - assert:
+ - ansible.builtin.assert:
that:
- update_service_with_ptag_woov_result.changed is sameas true
- name: "test - Update service with problem tag without operator and without value (idempotency check)"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleServiceForServiceModule
problem_tags:
- tag: TagName1
@@ -540,12 +240,12 @@
- tag: TagName4
register: update_service_with_ptag_woov_idempotency_check_result
- - assert:
+ - ansible.builtin.assert:
that:
- update_service_with_ptag_woov_idempotency_check_result.changed is sameas false
- name: "test - Update service remove problem tags"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleServiceForServiceModule
problem_tags:
- tag: TagName1
@@ -556,12 +256,12 @@
value: TagValue3
register: update_service_remove_tags_result
- - assert:
+ - ansible.builtin.assert:
that:
- update_service_remove_tags_result.changed is sameas true
- name: "test - Update service remove problem tags (idempotency check)"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleServiceForServiceModule
problem_tags:
- tag: TagName1
@@ -572,237 +272,237 @@
value: TagValue3
register: update_service_remove_tags_idempotency_check_result
- - assert:
+ - ansible.builtin.assert:
that:
- update_service_remove_tags_idempotency_check_result.changed is sameas false
- name: "test - Update service remove all problem tags"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleServiceForServiceModule
register: update_service_remove_all_tags_result
- - assert:
+ - ansible.builtin.assert:
that:
- update_service_remove_all_tags_result.changed is sameas true
- name: "test - Update service remove all problem tags (idempotency check)"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleServiceForServiceModule
register: update_service_remove_all_tags_idempotency_check_result
- - assert:
+ - ansible.builtin.assert:
that:
- update_service_remove_all_tags_idempotency_check_result.changed is sameas false
- name: "test - Create a new child service"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleChildServiceForServiceModule
sortorder: 10
parents:
- ExampleServiceForServiceModule
register: create_child_service_result
- - assert:
+ - ansible.builtin.assert:
that:
- create_child_service_result.changed is sameas true
- name: "test - Create a new child service (idempotency check)"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleChildServiceForServiceModule
sortorder: 10
parents:
- ExampleServiceForServiceModule
register: create_child_service_idempotency_check_result
- - assert:
+ - ansible.builtin.assert:
that:
- create_child_service_idempotency_check_result.changed is sameas false
- name: "test - Update child service to remove parent"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleChildServiceForServiceModule
parents: []
register: update_child_service_delete_parent_result
- - assert:
+ - ansible.builtin.assert:
that:
- update_child_service_delete_parent_result.changed is sameas true
- name: "test - Create a new parent service"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleParentServiceForServiceModule
- name: "test - Delete child service"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleChildServiceForServiceModule
state: absent
- name: "test - Create a new child service with two parents"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleChildServiceForServiceModule
parents:
- ExampleServiceForServiceModule
- ExampleParentServiceForServiceModule
register: create_child_service_two_parents_result
- - assert:
+ - ansible.builtin.assert:
that:
- create_child_service_two_parents_result.changed is sameas true
- name: "test - Create a new child service with two parents (idempotency check)"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleChildServiceForServiceModule
parents:
- ExampleServiceForServiceModule
- ExampleParentServiceForServiceModule
register: create_child_service_two_parents_idempotency_check_result
- - assert:
+ - ansible.builtin.assert:
that:
- create_child_service_two_parents_idempotency_check_result.changed is sameas false
- name: "test - Remove one parent from new child service"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleChildServiceForServiceModule
parents:
- ExampleParentServiceForServiceModule
register: update_child_service_remove_parent_result
- - assert:
+ - ansible.builtin.assert:
that:
- update_child_service_remove_parent_result.changed is sameas true
- name: "test - Remove one parent from new child service (idempotency check)"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleChildServiceForServiceModule
parents:
- ExampleParentServiceForServiceModule
register: update_child_service_remove_parent_idempotency_check_result
- - assert:
+ - ansible.builtin.assert:
that:
- update_child_service_remove_parent_idempotency_check_result.changed is sameas false
- name: "test - Delete parent service 2"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleParentServiceForServiceModule
state: absent
- name: "test - Create parent service with child service"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleParentServiceForServiceModule
children:
- ExampleChildServiceForServiceModule
register: create_parent_service_with_child_result
- - assert:
+ - ansible.builtin.assert:
that:
- create_parent_service_with_child_result.changed is sameas true
- name: "test - Create parent service with child service (idempotency check)"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleParentServiceForServiceModule
children:
- ExampleChildServiceForServiceModule
register: create_parent_service_with_child_result_idempotency_check_result
- - assert:
+ - ansible.builtin.assert:
that:
- create_parent_service_with_child_result_idempotency_check_result.changed is sameas false
- name: "test - Create second chile service"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleChildServiceForServiceModule2
- name: "test - Update parent service with the second child service"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleParentServiceForServiceModule
children:
- ExampleChildServiceForServiceModule
- ExampleChildServiceForServiceModule2
register: update_parent_service_with_second_child_result
- - assert:
+ - ansible.builtin.assert:
that:
- update_parent_service_with_second_child_result.changed is sameas true
- name: "test - Update parent service with the second child service (idempotency check)"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleParentServiceForServiceModule
children:
- ExampleChildServiceForServiceModule
- ExampleChildServiceForServiceModule2
register: update_parent_service_with_second_child_result_idempotency_check_result
- - assert:
+ - ansible.builtin.assert:
that:
- update_parent_service_with_second_child_result_idempotency_check_result.changed is sameas false
- name: "test - Delete parent service"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleParentServiceForServiceModule
state: absent
- name: "test - Create parent service with two child services"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleParentServiceForServiceModule
children:
- ExampleChildServiceForServiceModule
- ExampleChildServiceForServiceModule2
register: create_parent_service_with_two_children_result
- - assert:
+ - ansible.builtin.assert:
that:
- create_parent_service_with_two_children_result.changed is sameas true
- name: "test - Create parent service with child services (idempotency check)"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleParentServiceForServiceModule
children:
- ExampleChildServiceForServiceModule
- ExampleChildServiceForServiceModule2
register: create_parent_service_with_two_children_idempotency_check_result
- - assert:
+ - ansible.builtin.assert:
that:
- create_parent_service_with_two_children_idempotency_check_result.changed is sameas false
- name: "test - Delete parent service"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleParentServiceForServiceModule
state: absent
- name: "test - Delete child service"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleChildServiceForServiceModule
state: absent
- name: "test - Delete child servicei 2"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleChildServiceForServiceModule2
state: absent
- name: "test - Delete new service"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleServiceForServiceModule
state: absent
register: delete_service_result
- - assert:
+ - ansible.builtin.assert:
that:
- delete_service_result.changed is sameas true
- name: "test - Delete new service (idempotency check)"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleServiceForServiceModule
state: absent
register: delete_service_idempotency_check_result
- - assert:
+ - ansible.builtin.assert:
that:
- delete_service_idempotency_check_result.changed is sameas false
- name: "test - Create a new service with status rule"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleServiceForServiceModule
status_rules:
- type: at_least_n_child_services_have_status_or_above
@@ -811,12 +511,12 @@
new_status: not_classified
register: create_service_sr_result
- - assert:
+ - ansible.builtin.assert:
that:
- create_service_sr_result.changed is sameas true
- name: "test - Create a new service with status rule (idempotency check)"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleServiceForServiceModule
status_rules:
- type: at_least_n_child_services_have_status_or_above
@@ -825,12 +525,12 @@
new_status: not_classified
register: create_service_sr_idempotency_check_result
- - assert:
+ - ansible.builtin.assert:
that:
- create_service_sr_idempotency_check_result.changed is sameas false
- name: "test - Update service with the second status rule"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleServiceForServiceModule
status_rules:
- type: at_least_n_child_services_have_status_or_above
@@ -843,12 +543,12 @@
new_status: warning
register: update_service_add_sr_result
- - assert:
+ - ansible.builtin.assert:
that:
- update_service_add_sr_result.changed is sameas true
- name: "test - Update service with the second status rule (idempotency check)"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleServiceForServiceModule
status_rules:
- type: at_least_n_child_services_have_status_or_above
@@ -861,12 +561,12 @@
new_status: warning
register: update_service_add_sr_idempotency_check_result
- - assert:
+ - ansible.builtin.assert:
that:
- update_service_add_sr_idempotency_check_result.changed is sameas false
- name: "test - Update service remove status rule"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleServiceForServiceModule
status_rules:
- type: at_least_npct_child_services_have_status_or_above
@@ -875,12 +575,12 @@
new_status: warning
register: update_service_remove_sr_result
- - assert:
+ - ansible.builtin.assert:
that:
- update_service_remove_sr_result.changed is sameas true
- name: "test - Update service remove status rule (idempotency check)"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleServiceForServiceModule
status_rules:
- type: at_least_npct_child_services_have_status_or_above
@@ -889,12 +589,12 @@
new_status: warning
register: update_service_remove_sr_idempotency_check_result
- - assert:
+ - ansible.builtin.assert:
that:
- update_service_remove_sr_idempotency_check_result.changed is sameas false
- name: "test - Delete new service"
- zabbix_service:
+ community.zabbix.zabbix_service:
name: ExampleServiceForServiceModule
state: absent
register: delete_service_result
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_settings/meta/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_settings/meta/main.yml
new file mode 100644
index 000000000..acdb704c8
--- /dev/null
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_settings/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - setup_zabbix
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_settings/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_settings/tasks/main.yml
new file mode 100644
index 000000000..7be88158e
--- /dev/null
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_settings/tasks/main.yml
@@ -0,0 +1,332 @@
+---
+- name: test - Update zabbix settings (same as default)
+ community.zabbix.zabbix_settings:
+ alert_usrgrp: "Zabbix administrators"
+ auditlog_enabled: true
+ blink_period: "2m"
+ connect_timeout: "3s"
+ custom_color: false
+ default_inventory_mode: disabled
+ default_lang: en_US
+ default_theme: blue-theme
+ default_timezone: system
+ discovery_group: "Discovered hosts"
+ geomaps_attribution: ""
+ geomaps_max_zoom: false
+ geomaps_tile_provider: "OpenStreetMap.Mapnik"
+ geomaps_tile_url: ""
+ history_period: "24h"
+ iframe_sandboxing_enabled: true
+ iframe_sandboxing_exceptions: ""
+ item_test_timeout: "60s"
+ login_attempts: 5
+ login_block: "30s"
+ max_in_table: 50
+ max_overview_table_size: 50
+ max_period: "2y"
+ media_type_test_timeout: "65s"
+ ok_ack_color: "009900"
+ ok_ack_style: true
+ ok_period: "5m"
+ ok_unack_color: "009900"
+ ok_unack_style: true
+ period_default: "1h"
+ problem_ack_color: "CC0000"
+ problem_ack_style: true
+ problem_unack_color: "CC0000"
+ problem_unack_style: true
+ report_test_timeout: "60s"
+ script_timeout: "60s"
+ search_limit: 1000
+ server_check_interval: true
+ severity_color_0: "97AAB3"
+ severity_color_1: "7499FF"
+ severity_color_2: "FFC859"
+ severity_color_3: "FFA059"
+ severity_color_4: "E97659"
+ severity_color_5: "E45959"
+ severity_name_0: "Not classified"
+ severity_name_1: "Information"
+ severity_name_2: "Warning"
+ severity_name_3: "Average"
+ severity_name_4: "High"
+ severity_name_5: "Disaster"
+ show_technical_errors: false
+ snmptrap_logging: true
+ socket_timeout: "3s"
+ uri_valid_schemes:
+ - http
+ - https
+ - ftp
+ - file
+ - mailto
+ - tel
+ - ssh
+ frontend_url: ""
+ validate_uri_schemes: true
+ work_period: "1-5,09:00-18:00"
+ x_frame_options: "SAMEORIGIN"
+ register: zbx_settings
+
+- name: assert that settings was NOT updated
+ ansible.builtin.assert:
+ that:
+ - zbx_settings.changed is sameas False
+
+- when: zabbix_version is version('6.2', '>=')
+ name: support Zabbix version (>=6.2)
+ block:
+ - name: test - Zabbix settings (same as default)
+ community.zabbix.zabbix_settings:
+ vault_provider: HashiCorp_Vault
+ register: zbx_settings
+
+ - name: assert that settings was NOT updated
+ ansible.builtin.assert:
+ that:
+ - zbx_settings.changed is sameas False
+
+ - name: test - Update zabbix settings
+ community.zabbix.zabbix_settings:
+ vault_provider: CyberArk_Vault
+ register: zbx_settings
+
+ - name: assert that settings was updated
+ ansible.builtin.assert:
+ that:
+ - zbx_settings.changed is sameas True
+
+- name: test - Update zabbix settings
+ community.zabbix.zabbix_settings:
+ alert_usrgrp: "0"
+ auditlog_enabled: false
+ blink_period: "10m"
+ connect_timeout: "30s"
+ custom_color: false
+ default_inventory_mode: automatic
+ default_lang: en_GB
+ default_theme: hc-dark
+ default_timezone: Asia/Tokyo
+ discovery_group: "Hypervisors"
+ geomaps_attribution: "hogehoge"
+ geomaps_max_zoom: true
+ geomaps_tile_provider: "another"
+ geomaps_tile_url: ""
+ history_period: "1w"
+ iframe_sandboxing_enabled: false
+ iframe_sandboxing_exceptions: "hogehoge"
+ item_test_timeout: "5m"
+ login_attempts: 30
+ login_block: "5m"
+ max_in_table: 1000
+ max_overview_table_size: 1000
+ max_period: "1y"
+ media_type_test_timeout: "1m"
+ ok_ack_color: "0099AA"
+ ok_ack_style: false
+ ok_period: "10m"
+ ok_unack_color: "0099BB"
+ ok_unack_style: false
+ period_default: "2h"
+ problem_ack_color: "CC0000"
+ problem_ack_style: false
+ problem_unack_color: "CC0000"
+ problem_unack_style: false
+ report_test_timeout: "2m"
+ script_timeout: "2m"
+ search_limit: 10000
+ server_check_interval: false
+ severity_color_0: "97AAAA"
+ severity_color_1: "7499BB"
+ severity_color_2: "FFC8CC"
+ severity_color_3: "FFA0DD"
+ severity_color_4: "E976EE"
+ severity_color_5: "E459FF"
+ severity_name_0: "Not classified(test)"
+ severity_name_1: "Information(test)"
+ severity_name_2: "Warning(test)"
+ severity_name_3: "Average(test)"
+ severity_name_4: "High(test)"
+ severity_name_5: "Disaster(test)"
+ show_technical_errors: true
+ snmptrap_logging: false
+ socket_timeout: "30s"
+ uri_valid_schemes:
+ - https
+ - ftp
+ - file
+ - mailto
+ - tel
+ - ssh
+ frontend_url: "https://www.zabbix.com/"
+ validate_uri_schemes: false
+ work_period: "1-5,09:00-18:00;1-5,22:00-23:00"
+ x_frame_options: "SAMEORIGIN(TEST)"
+ register: zbx_settings
+
+- name: assert that settings was updated
+ ansible.builtin.assert:
+ that:
+ - zbx_settings.changed is sameas True
+
+- name: test - Update zabbix settings (same setting)
+ community.zabbix.zabbix_settings:
+ alert_usrgrp: "0"
+ auditlog_enabled: false
+ blink_period: "10m"
+ connect_timeout: "30s"
+ custom_color: false
+ default_inventory_mode: automatic
+ default_lang: en_GB
+ default_theme: hc-dark
+ default_timezone: Asia/Tokyo
+ discovery_group: "Hypervisors"
+ geomaps_attribution: "hogehoge"
+ geomaps_max_zoom: true
+ geomaps_tile_provider: "another"
+ geomaps_tile_url: ""
+ history_period: "1w"
+ iframe_sandboxing_enabled: false
+ iframe_sandboxing_exceptions: "hogehoge"
+ item_test_timeout: "5m"
+ login_attempts: 30
+ login_block: "5m"
+ max_in_table: 1000
+ max_overview_table_size: 1000
+ max_period: "1y"
+ media_type_test_timeout: "1m"
+ ok_ack_color: "0099AA"
+ ok_ack_style: false
+ ok_period: "10m"
+ ok_unack_color: "0099BB"
+ ok_unack_style: false
+ period_default: "2h"
+ problem_ack_color: "CC0000"
+ problem_ack_style: false
+ problem_unack_color: "CC0000"
+ problem_unack_style: false
+ report_test_timeout: "2m"
+ script_timeout: "2m"
+ search_limit: 10000
+ server_check_interval: false
+ severity_color_0: "97AAAA"
+ severity_color_1: "7499BB"
+ severity_color_2: "FFC8CC"
+ severity_color_3: "FFA0DD"
+ severity_color_4: "E976EE"
+ severity_color_5: "E459FF"
+ severity_name_0: "Not classified(test)"
+ severity_name_1: "Information(test)"
+ severity_name_2: "Warning(test)"
+ severity_name_3: "Average(test)"
+ severity_name_4: "High(test)"
+ severity_name_5: "Disaster(test)"
+ show_technical_errors: true
+ snmptrap_logging: false
+ socket_timeout: "30s"
+ uri_valid_schemes:
+ - https
+ - ftp
+ - file
+ - mailto
+ - tel
+ - ssh
+ frontend_url: "https://www.zabbix.com/"
+ validate_uri_schemes: false
+ work_period: "1-5,09:00-18:00;1-5,22:00-23:00"
+ x_frame_options: "SAMEORIGIN(TEST)"
+ register: zbx_settings
+
+- name: assert that settings was NOT updated
+ ansible.builtin.assert:
+ that:
+ - zbx_settings.changed is sameas False
+
+- name: test - Update zabbix alert_usrgrp setting
+ community.zabbix.zabbix_settings:
+ alert_usrgrp: "No access to the frontend"
+ register: zbx_settings
+
+- name: assert that setting was updated
+ ansible.builtin.assert:
+ that:
+ - zbx_settings.changed is sameas True
+
+- name: test - Update zabbix alert_usrgrp setting (same parameter)
+ community.zabbix.zabbix_settings:
+ alert_usrgrp: "No access to the frontend"
+ register: zbx_settings
+
+- name: assert that settings was NOT updated
+ ansible.builtin.assert:
+ that:
+ - zbx_settings.changed is sameas False
+
+- name: test - Update zabbix settings (same as default)
+ community.zabbix.zabbix_settings:
+ alert_usrgrp: "Zabbix administrators"
+ auditlog_enabled: true
+ blink_period: "2m"
+ connect_timeout: "3s"
+ custom_color: false
+ default_inventory_mode: disabled
+ default_lang: en_US
+ default_theme: blue-theme
+ default_timezone: system
+ discovery_group: "Discovered hosts"
+ geomaps_attribution: ""
+ geomaps_max_zoom: false
+ geomaps_tile_provider: "OpenStreetMap.Mapnik"
+ geomaps_tile_url: ""
+ history_period: "24h"
+ iframe_sandboxing_enabled: true
+ iframe_sandboxing_exceptions: ""
+ item_test_timeout: "60s"
+ login_attempts: 5
+ login_block: "30s"
+ max_in_table: 50
+ max_overview_table_size: 50
+ max_period: "2y"
+ media_type_test_timeout: "65s"
+ ok_ack_color: "009900"
+ ok_ack_style: true
+ ok_period: "5m"
+ ok_unack_color: "009900"
+ ok_unack_style: true
+ period_default: "1h"
+ problem_ack_color: "CC0000"
+ problem_ack_style: true
+ problem_unack_color: "CC0000"
+ problem_unack_style: true
+ report_test_timeout: "60s"
+ script_timeout: "60s"
+ search_limit: 1000
+ server_check_interval: true
+ severity_color_0: "97AAB3"
+ severity_color_1: "7499FF"
+ severity_color_2: "FFC859"
+ severity_color_3: "FFA059"
+ severity_color_4: "E97659"
+ severity_color_5: "E45959"
+ severity_name_0: "Not classified"
+ severity_name_1: "Information"
+ severity_name_2: "Warning"
+ severity_name_3: "Average"
+ severity_name_4: "High"
+ severity_name_5: "Disaster"
+ show_technical_errors: false
+ snmptrap_logging: true
+ socket_timeout: "3s"
+ uri_valid_schemes:
+ - http
+ - https
+ - ftp
+ - file
+ - mailto
+ - tel
+ - ssh
+ frontend_url: ""
+ validate_uri_schemes: true
+ work_period: "1-5,09:00-18:00"
+ x_frame_options: "SAMEORIGIN"
+ register: zbx_settings
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/files/template2_50_lower.xml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/files/template2_50_lower.xml
deleted file mode 100644
index 93a32f0c5..000000000
--- a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/files/template2_50_lower.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<zabbix_export>
- <date>2020-05-29T15:22:11Z</date>
- <templates>
- <template>
- <template>ExampleHost</template>
- <name>ExampleHost</name>
- <description></description>
- <groups>
- <group>
- <name>Templates</name>
- </group>
- <group>
- <name>Templates/Applications</name>
- </group>
- </groups>
- <macros>
- <macro>
- <macro>{$EXAMPLE_MACRO1}</macro>
- <value>1000</value>
- </macro>
- <macro>
- <macro>{$EXAMPLE_MACRO2}</macro>
- <value>text</value>
- </macro>
- <macro>
- <macro>{$EXAMPLE_MACRO3}</macro>
- <value>text2</value>
- </macro>
- </macros>
- <templates>
- <template>
- <name>Template App FTP Service</name>
- </template>
- <template>
- <name>Template App Zabbix Proxy</name>
- </template>
- <template>
- <name>Template App HTTP Service</name>
- </template>
- </templates>
- </template>
- </templates>
- <version>3.0</version>
- <groups>
- <group>
- <name>Templates</name>
- </group>
- <group>
- <name>Templates/Applications</name>
- </group>
- </groups>
-</zabbix_export>
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/tasks/import_54_higher.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/tasks/import_54_higher.yml
deleted file mode 100644
index 8ce7a51e1..000000000
--- a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/tasks/import_54_higher.yml
+++ /dev/null
@@ -1,126 +0,0 @@
----
-
-#
-# For Zabbix lower than 5.4 we test against the ExampleHost which was created in the
-# main.yml tests. Due to changes in the Zabbix API (mainly because UUIDs) this is
-# not possible for 5.4 onwards - so there we first delete the example hosts.
-#
-
-- name: Delete Zabbix template.
- zabbix_template:
- template_name: ExampleHost
- state: absent
- register: delete_zabbix_template_result
-
-- assert:
- that:
- - delete_zabbix_template_result.changed is sameas true
-
-- name: Delete Zabbix template (idempotency check).
- zabbix_template:
- template_name: ExampleHost
- state: absent
- register: delete_zabbix_template_result
-
-- assert:
- that:
- - delete_zabbix_template_result.changed is sameas false
-
-#
-# JSON Tests
-#
-
-- block:
- - name: Import Zabbix template from JSON file (idempotency check) - >= Zabbix 5.4.
- zabbix_template:
- template_json: "{{ lookup('file', 'template3_54_higher.json') }}"
- state: present
- register: import_template_json
-
- - name: Assert Zabbix template from JSON file (idempotency check) - >= Zabbix 5.4.
- assert:
- that:
- - import_template_json.changed is sameas true
-
- - name: Import Zabbix template from JSON file with matching values (idempotency check) - >= Zabbix 5.4.
- zabbix_template:
- template_json: "{{ lookup('file', 'template3_54_higher.json') }}"
- state: present
- register: import_template_json
-
- - name: Assert Zabbix template from JSON file with matching values (idempotency check) - >= Zabbix 5.4.
- assert:
- that:
- - import_template_json.changed is sameas false
-
-- name: Gather Zabbix template infomation.
- zabbix_template_info:
- template_name: ExampleHost
- format: json
- register: gather_template_result
-
-- block:
- - assert:
- that:
- - gather_template_result.template_json[template_export_key][template_groups_key].0.name == 'Templates'
- - gather_template_result.template_json[template_export_key][template_groups_key].1.name == 'Templates/Applications'
- - gather_template_result.template_json[template_export_key].templates.0.templates.0.name == 'FTP Service'
- - gather_template_result.template_json[template_export_key].templates.0.templates.1.name == 'Zabbix proxy health'
- - gather_template_result.template_json[template_export_key].templates.0.macros.0.macro == '{$EXAMPLE_MACRO1}'
- - gather_template_result.template_json[template_export_key].templates.0.macros.0.value == '1000'
- - gather_template_result.template_json[template_export_key].templates.0.macros.1.macro == '{$EXAMPLE_MACRO2}'
- - gather_template_result.template_json[template_export_key].templates.0.macros.1.value == 'text'
-
-- block:
- - name: Import Zabbix template from JSON file with updated values.
- zabbix_template:
- template_json: "{{ lookup('file', 'template3-changed_54_higher.json') }}"
- state: present
- register: import_template_json
-
- - assert:
- that:
- - import_template_json.changed is sameas true
-
-- name: Gather Zabbix template infomation.
- zabbix_template_info:
- template_name: ExampleHost
- format: json
- register: gather_template_result
-
-- assert:
- that:
- - gather_template_result.template_json[template_export_key].templates.0.macros.0.macro == '{$EXAMPLE_MACRO1}'
- - gather_template_result.template_json[template_export_key].templates.0.macros.0.value == '1000'
- - gather_template_result.template_json[template_export_key].templates.0.macros.1.macro == '{$EXAMPLE_MACRO2}'
- - gather_template_result.template_json[template_export_key].templates.0.macros.1.value == 'text'
- - gather_template_result.template_json[template_export_key].templates.0.macros.2.macro == '{$EXAMPLE_MACRO3}'
- - gather_template_result.template_json[template_export_key].templates.0.macros.2.value == 'text2'
-
-#
-# xml
-#
-
-- block:
- - name: Import Zabbix template from XML file with updated values.
- zabbix_template:
- template_xml: "{{ lookup('file', 'template3_54_higher.xml') }}"
- state: present
- register: import_template_xml
-
- - assert:
- that:
- - import_template_xml.changed is sameas true
-
-- name: Gather Zabbix template infomation.
- zabbix_template_info:
- template_name: ExampleHost
- format: json
- register: gather_template_result
-
-# zabbix returns values sorted alphabetically so HTTP Service template comes before Zabbix Proxy template
-- block:
- - assert:
- that:
- - gather_template_result.template_json[template_export_key].templates.0.templates.0.name == 'FTP Service'
- - gather_template_result.template_json[template_export_key].templates.0.templates.1.name == 'Zabbix proxy health'
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/tasks/import_54_lower.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/tasks/import_54_lower.yml
deleted file mode 100644
index 48d180210..000000000
--- a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/tasks/import_54_lower.yml
+++ /dev/null
@@ -1,120 +0,0 @@
----
-
-#
-# For Zabbix lower than 5.4 we test against the ExampleHost which was created in the
-# main.yml tests. Due to changes in the Zabbix API (mainly because UUIDs) this is
-# not possible for 5.4 onwards - so there we first delete the Example host.
-#
-
-#
-# JSON Tests
-#
-
-- name: Gather Zabbix template infomation.
- zabbix_template_info:
- template_name: ExampleHost
- format: json
- register: gather_template_result
-
-- block:
- - assert:
- that:
- - gather_template_result.template_json[template_export_key].groups.0.name == 'Templates'
- - gather_template_result.template_json[template_export_key].groups.1.name == 'Templates/Applications'
- - gather_template_result.template_json[template_export_key].templates.0.templates.0.name == 'Template App FTP Service'
- - gather_template_result.template_json[template_export_key].templates.0.templates.1.name == 'Template App Zabbix Proxy'
- - gather_template_result.template_json[template_export_key].templates.0.macros.0.macro == '{$EXAMPLE_MACRO1}'
- - gather_template_result.template_json[template_export_key].templates.0.macros.0.value == '1000'
- - gather_template_result.template_json[template_export_key].templates.0.macros.1.macro == '{$EXAMPLE_MACRO2}'
- - gather_template_result.template_json[template_export_key].templates.0.macros.1.value == 'text'
-
-- block:
- - name: Import Zabbix template from JSON file with matching values (idempotency check) - < Zabbix 5.4.
- zabbix_template:
- template_json: "{{ lookup('file', 'template1_50_lower.json') }}"
- state: present
- register: import_template_json
-
- - name: Assert Zabbix template from JSON file with matching values (idempotency check) - < Zabbix 5.4.
- assert:
- that:
- - import_template_json.changed is sameas false
-
-- block:
- - name: Import Zabbix template from JSON file with updated values.
- zabbix_template:
- template_json: "{{ lookup('file', 'template1-changed_50_lower.json') }}"
- state: present
- register: import_template_json
-
- - assert:
- that:
- - import_template_json.changed is sameas true
-
-- name: Gather Zabbix template infomation.
- zabbix_template_info:
- template_name: ExampleHost
- format: json
- register: gather_template_result
-
-- assert:
- that:
- - gather_template_result.template_json[template_export_key].templates.0.macros.0.macro == '{$EXAMPLE_MACRO1}'
- - gather_template_result.template_json[template_export_key].templates.0.macros.0.value == '1000'
- - gather_template_result.template_json[template_export_key].templates.0.macros.1.macro == '{$EXAMPLE_MACRO2}'
- - gather_template_result.template_json[template_export_key].templates.0.macros.1.value == 'text'
- - gather_template_result.template_json[template_export_key].templates.0.macros.2.macro == '{$EXAMPLE_MACRO3}'
- - gather_template_result.template_json[template_export_key].templates.0.macros.2.value == 'text2'
-
-- name: Dump Zabbix template to JSON format.
- zabbix_template:
- template_name: ExampleHost
- dump_format: json
- state: dump
- register: template_dump_result
-
-- assert:
- that:
- - template_dump_result.deprecations is defined
- - template_dump_result.deprecations.0.version == '3.0.0'
-
-#
-# XML Tests
-#
-
-- block:
- - name: Import Zabbix template from XML file with updated values.
- zabbix_template:
- template_xml: "{{ lookup('file', 'template2_50_lower.xml') }}"
- state: present
- register: import_template_xml
-
- - assert:
- that:
- - import_template_xml.changed is sameas true
-
-- name: Gather Zabbix template infomation.
- zabbix_template_info:
- template_name: ExampleHost
- format: json
- register: gather_template_result
-
-# zabbix returns values sorted alphabetically so HTTP Service template comes before Zabbix Proxy template
-- block:
- - assert:
- that:
- - gather_template_result.template_json[template_export_key].templates.0.templates.0.name == 'Template App FTP Service'
- - gather_template_result.template_json[template_export_key].templates.0.templates.1.name == 'Template App HTTP Service'
- - gather_template_result.template_json[template_export_key].templates.0.templates.2.name == 'Template App Zabbix Proxy'
-
-- name: Dump Zabbix template to XML format.
- zabbix_template:
- template_name: ExampleHost
- dump_format: xml
- state: dump
- register: template_dump_result
-
-- assert:
- that:
- - template_dump_result.deprecations is defined
- - template_dump_result.deprecations.0.version == '3.0.0'
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/tasks/main.yml
index 66505f9a7..69aabe6b0 100644
--- a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/tasks/main.yml
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template/tasks/main.yml
@@ -1,197 +1,186 @@
---
- name: Create FTP Service Template
- zabbix_template:
+ community.zabbix.zabbix_template:
template_name: FTP Service
template_groups:
- - 'Templates'
+ - "Templates"
state: present
- name: Create a new Zabbix template (check mode).
- zabbix_template:
+ community.zabbix.zabbix_template:
template_name: ExampleHost
template_groups:
- - 'Templates'
- - 'Templates/Applications'
+ - "Templates"
+ - "Templates/Applications"
state: present
register: create_zabbix_template_result
check_mode: true
-- assert:
+- ansible.builtin.assert:
that:
- create_zabbix_template_result.changed is sameas true
- name: Create a new Zabbix template.
- zabbix_template:
+ community.zabbix.zabbix_template:
template_name: ExampleHost
template_groups:
- - 'Templates'
- - 'Templates/Applications'
+ - "Templates"
+ - "Templates/Applications"
state: present
register: create_zabbix_template_result
-- assert:
+- ansible.builtin.assert:
that:
- create_zabbix_template_result.changed is sameas true
- name: Create a new Zabbix template (idempotency check).
- zabbix_template:
+ community.zabbix.zabbix_template:
template_name: ExampleHost
template_groups:
- - 'Templates'
- - 'Templates/Applications'
+ - "Templates"
+ - "Templates/Applications"
state: present
register: create_zabbix_template_result
-- assert:
+- ansible.builtin.assert:
that:
- create_zabbix_template_result.changed is sameas false
- name: Create a new Zabbix template with linked templates.
- zabbix_template:
+ community.zabbix.zabbix_template:
template_name: ExampleHostWithLinked
template_groups:
- - 'Templates'
- - 'Templates/Applications'
+ - "Templates"
+ - "Templates/Applications"
link_templates:
- - "{{ 'Zabbix proxy health' if zabbix_version | float >= 5.4 else 'Template App Zabbix Proxy' }}"
- - "{{ 'FTP Service' if zabbix_version | float >= 5.4 else 'Template App FTP Service' }}"
+ - "Zabbix proxy health"
+ - "FTP Service"
state: present
register: create_zabbix_template_linked_result
-- assert:
+- ansible.builtin.assert:
that:
- create_zabbix_template_linked_result.changed is sameas true
- name: Gather Zabbix template infomation.
- zabbix_template_info:
+ community.zabbix.zabbix_template_info:
template_name: ExampleHost
format: json
register: gather_template_result
- name: "test - Set key to template_export_key variable(This deals with the key being masked)"
- set_fact:
+ ansible.builtin.set_fact:
template_export_key: "{{ item }}"
loop: "{{ gather_template_result.template_json.keys() | list }}"
when:
- item | regex_search('_export')
-- assert:
+- ansible.builtin.assert:
that:
- gather_template_result.template_json[template_export_key][template_groups_key].0.name == 'Templates'
- gather_template_result.template_json[template_export_key][template_groups_key].1.name == 'Templates/Applications'
- name: Add link_templates to Zabbix template.
- zabbix_template:
+ community.zabbix.zabbix_template:
template_name: ExampleHost
template_groups:
- - 'Templates'
- - 'Templates/Applications'
+ - "Templates"
+ - "Templates/Applications"
link_templates:
- - "{{ 'Zabbix proxy health' if zabbix_version | float >= 5.4 else 'Template App Zabbix Proxy' }}"
- - "{{ 'FTP Service' if zabbix_version | float >= 5.4 else 'Template App FTP Service' }}"
+ - "Zabbix proxy health"
+ - "FTP Service"
state: present
register: update_zabbix_template_result
-- assert:
+- ansible.builtin.assert:
that:
- update_zabbix_template_result.changed is sameas true
- name: Add link_templates to Zabbix template (idempotency check).
- zabbix_template:
+ community.zabbix.zabbix_template:
template_name: ExampleHost
template_groups:
- - 'Templates'
- - 'Templates/Applications'
+ - "Templates"
+ - "Templates/Applications"
link_templates:
- - "{{ 'Zabbix proxy health' if zabbix_version | float >= 5.4 else 'Template App Zabbix Proxy' }}"
- - "{{ 'FTP Service' if zabbix_version | float >= 5.4 else 'Template App FTP Service' }}"
+ - "Zabbix proxy health"
+ - "FTP Service"
state: present
register: update_zabbix_template_result
-- assert:
+- ansible.builtin.assert:
that:
- update_zabbix_template_result.changed is sameas false
- name: Gather Zabbix template infomation.
- zabbix_template_info:
+ community.zabbix.zabbix_template_info:
template_name: ExampleHost
format: json
register: gather_template_result
-- when: zabbix_version is version('5.4', '<')
- block:
- - assert:
- that:
- - gather_template_result.template_json[template_export_key].groups.0.name == 'Templates'
- - gather_template_result.template_json[template_export_key].groups.1.name == 'Templates/Applications'
- - gather_template_result.template_json[template_export_key].templates.0.templates.0.name == 'Template App FTP Service'
- - gather_template_result.template_json[template_export_key].templates.0.templates.1.name == 'Template App Zabbix Proxy'
-
-- when: zabbix_version is version('5.4', '>=')
- block:
- - assert:
- that:
- - gather_template_result.template_json[template_export_key][template_groups_key].0.name == 'Templates'
- - gather_template_result.template_json[template_export_key][template_groups_key].1.name == 'Templates/Applications'
- - gather_template_result.template_json[template_export_key].templates.0.templates.0.name == 'FTP Service'
- - gather_template_result.template_json[template_export_key].templates.0.templates.1.name == 'Zabbix proxy health'
+- ansible.builtin.assert:
+ that:
+ - gather_template_result.template_json[template_export_key][template_groups_key].0.name == 'Templates'
+ - gather_template_result.template_json[template_export_key][template_groups_key].1.name == 'Templates/Applications'
+ - gather_template_result.template_json[template_export_key].templates.0.templates.0.name == 'FTP Service'
+ - gather_template_result.template_json[template_export_key].templates.0.templates.1.name == 'Zabbix proxy health'
- name: Add macros to Zabbix template.
- zabbix_template:
+ community.zabbix.zabbix_template:
template_name: ExampleHost
template_groups:
- - 'Templates'
- - 'Templates/Applications'
+ - "Templates"
+ - "Templates/Applications"
link_templates:
- - "{{ 'Zabbix proxy health' if zabbix_version | float >= 5.4 else 'Template App Zabbix Proxy' }}"
- - "{{ 'FTP Service' if zabbix_version | float >= 5.4 else 'Template App FTP Service' }}"
+ - "Zabbix proxy health"
+ - "FTP Service"
macros:
- - macro: '{$EXAMPLE_MACRO1}'
+ - macro: "{$EXAMPLE_MACRO1}"
value: 1000
- - macro: '{$EXAMPLE_MACRO2}'
- value: 'text'
+ - macro: "{$EXAMPLE_MACRO2}"
+ value: "text"
state: present
register: update_zabbix_template_result
-- assert:
+- ansible.builtin.assert:
that:
- update_zabbix_template_result.changed is sameas true
- name: Add macros to Zabbix template (idempotency check).
- zabbix_template:
+ community.zabbix.zabbix_template:
template_name: ExampleHost
template_groups:
- - 'Templates'
- - 'Templates/Applications'
+ - "Templates"
+ - "Templates/Applications"
link_templates:
- - "{{ 'Zabbix proxy health' if zabbix_version | float >= 5.4 else 'Template App Zabbix Proxy' }}"
- - "{{ 'FTP Service' if zabbix_version | float >= 5.4 else 'Template App FTP Service' }}"
+ - "Zabbix proxy health"
+ - "FTP Service"
macros:
- - macro: '{$EXAMPLE_MACRO1}'
+ - macro: "{$EXAMPLE_MACRO1}"
value: 1000
- - macro: '{$EXAMPLE_MACRO2}'
- value: 'text'
+ - macro: "{$EXAMPLE_MACRO2}"
+ value: "text"
state: present
register: update_zabbix_template_result
-- assert:
+- ansible.builtin.assert:
that:
- update_zabbix_template_result.changed is sameas false
- name: Add tags to Zabbix template.
- zabbix_template:
+ community.zabbix.zabbix_template:
template_name: ExampleHost
template_groups:
- - 'Templates'
- - 'Templates/Applications'
+ - "Templates"
+ - "Templates/Applications"
link_templates:
- - "{{ 'Zabbix proxy health' if zabbix_version | float >= 5.4 else 'Template App Zabbix Proxy' }}"
- - "{{ 'FTP Service' if zabbix_version | float >= 5.4 else 'Template App FTP Service' }}"
+ - "Zabbix proxy health"
+ - "FTP Service"
macros:
- - macro: '{$EXAMPLE_MACRO1}'
+ - macro: "{$EXAMPLE_MACRO1}"
value: 1000
- - macro: '{$EXAMPLE_MACRO2}'
- value: 'text'
+ - macro: "{$EXAMPLE_MACRO2}"
+ value: "text"
tags:
- tag: tag1
value: 1000
@@ -199,26 +188,24 @@
value: text
state: present
register: update_zabbix_template_result
- when: zabbix_version is version('4.2', '>=')
-- assert:
+- ansible.builtin.assert:
that: update_zabbix_template_result is changed
- when: zabbix_version is version('4.2', '>=')
- name: Add tags to Zabbix template (idempotency check).
- zabbix_template:
+ community.zabbix.zabbix_template:
template_name: ExampleHost
template_groups:
- - 'Templates'
- - 'Templates/Applications'
+ - "Templates"
+ - "Templates/Applications"
link_templates:
- - "{{ 'Zabbix proxy health' if zabbix_version | float >= 5.4 else 'Template App Zabbix Proxy' }}"
- - "{{ 'FTP Service' if zabbix_version | float >= 5.4 else 'Template App FTP Service' }}"
+ - "Zabbix proxy health"
+ - "FTP Service"
macros:
- - macro: '{$EXAMPLE_MACRO1}'
+ - macro: "{$EXAMPLE_MACRO1}"
value: 1000
- - macro: '{$EXAMPLE_MACRO2}'
- value: 'text'
+ - macro: "{$EXAMPLE_MACRO2}"
+ value: "text"
tags:
- tag: tag1
value: 1000
@@ -226,66 +213,159 @@
value: text
state: present
register: update_zabbix_template_result
- when: zabbix_version is version('4.2', '>=')
-- assert:
+- ansible.builtin.assert:
that: update_zabbix_template_result is not changed
- when: zabbix_version is version('4.2', '>=')
- name: Remove tags from Zabbix template.
- zabbix_template:
+ community.zabbix.zabbix_template:
template_name: ExampleHost
template_groups:
- - 'Templates'
- - 'Templates/Applications'
+ - "Templates"
+ - "Templates/Applications"
link_templates:
- - "{{ 'Zabbix proxy health' if zabbix_version | float >= 5.4 else 'Template App Zabbix Proxy' }}"
- - "{{ 'FTP Service' if zabbix_version | float >= 5.4 else 'Template App FTP Service' }}"
+ - "Zabbix proxy health"
+ - "FTP Service"
macros:
- - macro: '{$EXAMPLE_MACRO1}'
+ - macro: "{$EXAMPLE_MACRO1}"
value: 1000
- - macro: '{$EXAMPLE_MACRO2}'
- value: 'text'
+ - macro: "{$EXAMPLE_MACRO2}"
+ value: "text"
tags: []
state: present
register: update_zabbix_template_result
- when: zabbix_version is version('4.2', '>=')
-- assert:
+- ansible.builtin.assert:
that: update_zabbix_template_result is changed
- when: zabbix_version is version('4.2', '>=')
-# ####
-# Import template tests
-# ####
+- name: Delete Zabbix template.
+ community.zabbix.zabbix_template:
+ template_name: ExampleHost
+ state: absent
+ register: delete_zabbix_template_result
+
+- ansible.builtin.assert:
+ that:
+ - delete_zabbix_template_result.changed is sameas true
+
+#
+# JSON Tests
+#
+
+- name: Import Zabbix template from JSON file (idempotency check).
+ community.zabbix.zabbix_template:
+ template_json: "{{ lookup('file', 'template3_54_higher.json') }}"
+ state: present
+ register: import_template_json
-- include_tasks: import_54_lower.yml
- when: zabbix_version is version('5.4', '<')
+- name: Assert Zabbix template from JSON file (idempotency check).
+ ansible.builtin.assert:
+ that:
+ - import_template_json.changed is sameas true
+
+- name: Import Zabbix template from JSON file with matching values (idempotency check).
+ community.zabbix.zabbix_template:
+ template_json: "{{ lookup('file', 'template3_54_higher.json') }}"
+ state: present
+ register: import_template_json
-- include_tasks: import_54_higher.yml
- when: zabbix_version is version('5.4', '>=')
+- name: Assert Zabbix template from JSON file with matching values (idempotency check).
+ ansible.builtin.assert:
+ that:
+ - import_template_json.changed is sameas false
+
+- name: Gather Zabbix template infomation.
+ community.zabbix.zabbix_template_info:
+ template_name: ExampleHost
+ format: json
+ register: gather_template_result
+
+- block:
+ - ansible.builtin.assert:
+ that:
+ - gather_template_result.template_json[template_export_key][template_groups_key].0.name == 'Templates'
+ - gather_template_result.template_json[template_export_key][template_groups_key].1.name == 'Templates/Applications'
+ - gather_template_result.template_json[template_export_key].templates.0.templates.0.name == 'FTP Service'
+ - gather_template_result.template_json[template_export_key].templates.0.templates.1.name == 'Zabbix proxy health'
+ - gather_template_result.template_json[template_export_key].templates.0.macros.0.macro == '{$EXAMPLE_MACRO1}'
+ - gather_template_result.template_json[template_export_key].templates.0.macros.0.value == '1000'
+ - gather_template_result.template_json[template_export_key].templates.0.macros.1.macro == '{$EXAMPLE_MACRO2}'
+ - gather_template_result.template_json[template_export_key].templates.0.macros.1.value == 'text'
+
+- name: Import Zabbix template from JSON file with updated values.
+ community.zabbix.zabbix_template:
+ template_json: "{{ lookup('file', 'template3-changed_54_higher.json') }}"
+ state: present
+ register: import_template_json
+
+- ansible.builtin.assert:
+ that:
+ - import_template_json.changed is sameas true
+
+- name: Gather Zabbix template infomation.
+ community.zabbix.zabbix_template_info:
+ template_name: ExampleHost
+ format: json
+ register: gather_template_result
+
+- ansible.builtin.assert:
+ that:
+ - gather_template_result.template_json[template_export_key].templates.0.macros.0.macro == '{$EXAMPLE_MACRO1}'
+ - gather_template_result.template_json[template_export_key].templates.0.macros.0.value == '1000'
+ - gather_template_result.template_json[template_export_key].templates.0.macros.1.macro == '{$EXAMPLE_MACRO2}'
+ - gather_template_result.template_json[template_export_key].templates.0.macros.1.value == 'text'
+ - gather_template_result.template_json[template_export_key].templates.0.macros.2.macro == '{$EXAMPLE_MACRO3}'
+ - gather_template_result.template_json[template_export_key].templates.0.macros.2.value == 'text2'
+
+#
+# xml
+#
+
+- block:
+ - name: Import Zabbix template from XML file with updated values.
+ community.zabbix.zabbix_template:
+ template_xml: "{{ lookup('file', 'template3_54_higher.xml') }}"
+ state: present
+ register: import_template_xml
+
+ - ansible.builtin.assert:
+ that:
+ - import_template_xml.changed is sameas true
+
+- name: Gather Zabbix template infomation.
+ community.zabbix.zabbix_template_info:
+ template_name: ExampleHost
+ format: json
+ register: gather_template_result
+
+# zabbix returns values sorted alphabetically so HTTP Service template comes before Zabbix Proxy template
+- block:
+ - ansible.builtin.assert:
+ that:
+ - gather_template_result.template_json[template_export_key].templates.0.templates.0.name == 'FTP Service'
+ - gather_template_result.template_json[template_export_key].templates.0.templates.1.name == 'Zabbix proxy health'
#
# Cleanup again
#
- name: Delete Zabbix template.
- zabbix_template:
+ community.zabbix.zabbix_template:
template_name: ExampleHost
state: absent
register: delete_zabbix_template_result
-- assert:
+- ansible.builtin.assert:
that:
- delete_zabbix_template_result.changed is sameas true
- name: Delete Zabbix template (idempotency check).
- zabbix_template:
+ community.zabbix.zabbix_template:
template_name: ExampleHost
state: absent
register: delete_zabbix_template_result
-- assert:
+- ansible.builtin.assert:
that:
- delete_zabbix_template_result.changed is sameas false
@@ -293,38 +373,36 @@
# Unicode stuff
#
-- when: zabbix_version is version('5.0', '>=')
- block:
- # The test if decode Unicode correctly and to be imported the template.
- # https://github.com/ansible-collections/community.zabbix/issues/314
- - name: Import Zabbix template from JSON file with unicode.
- zabbix_template:
- template_json: "{{ lookup('file', 'template1_50_higher_decode_unicode.json') }}"
- state: present
- register: import_template_json
+# The test if decode Unicode correctly and to be imported the template.
+# https://github.com/ansible-collections/community.zabbix/issues/314
+- name: Import Zabbix template from JSON file with unicode.
+ community.zabbix.zabbix_template:
+ template_json: "{{ lookup('file', 'template1_50_higher_decode_unicode.json') }}"
+ state: present
+ register: import_template_json
- - name: Gather Zabbix template infomation.
- zabbix_template_info:
- template_name: ExampleTemplate314
- format: json
- register: gather_template_result
+- name: Gather Zabbix template infomation.
+ community.zabbix.zabbix_template_info:
+ template_name: ExampleTemplate314
+ format: json
+ register: gather_template_result
- - assert:
- that:
- - import_template_json.changed is sameas true
- - gather_template_result.template_json.zabbix_export.templates.0.description == "\u30c6\u30b9\u30c8\u30b3\u30e1\u30f3\u30c8"
+- ansible.builtin.assert:
+ that:
+ - import_template_json.changed is sameas true
+ - gather_template_result.template_json.zabbix_export.templates.0.description == "\u30c6\u30b9\u30c8\u30b3\u30e1\u30f3\u30c8"
- - name: Delete Zabbix template.
- zabbix_template:
- template_name: ExampleTemplate314
- state: absent
- register: delete_zabbix_template_result
+- name: Delete Zabbix template.
+ community.zabbix.zabbix_template:
+ template_name: ExampleTemplate314
+ state: absent
+ register: delete_zabbix_template_result
- - assert:
- that:
- - delete_zabbix_template_result.changed is sameas true
+- ansible.builtin.assert:
+ that:
+ - delete_zabbix_template_result.changed is sameas true
- name: Clean up ExampleHostWithLinked template
- zabbix_template:
+ community.zabbix.zabbix_template:
template_name: ExampleHostWithLinked
state: absent
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template_info/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template_info/tasks/main.yml
index 3146c04b3..ae790f1f9 100644
--- a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template_info/tasks/main.yml
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_template_info/tasks/main.yml
@@ -1,48 +1,48 @@
---
- name: "test - Prepare integration tests for zabbix_template_info module"
- zabbix_template:
+ community.zabbix.zabbix_template:
template_name: ExampleTemplateForTempleteInfoModule
template_groups:
- Templates
state: present
register: prepare_result
-- assert:
+- ansible.builtin.assert:
that:
- prepare_result.changed is sameas true
- name: "test - Fetch template info as a JSON format from Zabbix Server"
- zabbix_template_info:
+ community.zabbix.zabbix_template_info:
template_name: ExampleTemplateForTempleteInfoModule
format: json
register: fetch_template_json_format_result
- name: "test - Set key to template_export_key variable(This deals with the key being masked)"
- set_fact:
+ ansible.builtin.set_fact:
template_export_key: "{{ item }}"
loop: "{{ fetch_template_json_format_result.template_json.keys() | list }}"
when:
- item | regex_search('_export')
-- assert:
+- ansible.builtin.assert:
that:
- fetch_template_json_format_result.template_json[template_export_key].date is defined
when: zabbix_version is version('6.2', '<=')
-- assert:
+- ansible.builtin.assert:
that:
- fetch_template_json_format_result.template_json[template_export_key][template_groups_key].0.name == "Templates"
- fetch_template_json_format_result.template_json[template_export_key].templates.0.name == "ExampleTemplateForTempleteInfoModule"
- fetch_template_json_format_result.template_json[template_export_key].templates.0.template == "ExampleTemplateForTempleteInfoModule"
- name: "test - Fetch template info as a JSON format with omit_date parameter from Zabbix Server"
- zabbix_template_info:
+ community.zabbix.zabbix_template_info:
template_name: ExampleTemplateForTempleteInfoModule
format: json
omit_date: true
register: fetch_template_json_format_omit_date_result
-- assert:
+- ansible.builtin.assert:
that:
- fetch_template_json_format_omit_date_result.template_json[template_export_key].date is not defined
- fetch_template_json_format_omit_date_result.template_json[template_export_key][template_groups_key].0.name == "Templates"
@@ -50,66 +50,62 @@
- fetch_template_json_format_omit_date_result.template_json[template_export_key].templates.0.template == "ExampleTemplateForTempleteInfoModule"
- name: "test - Fetch template info as a XML format from Zabbix Server"
- zabbix_template_info:
+ community.zabbix.zabbix_template_info:
template_name: ExampleTemplateForTempleteInfoModule
format: xml
register: fetch_template_xml_format_result
-- assert:
+- ansible.builtin.assert:
that:
- fetch_template_xml_format_result.template_xml | regex_search('<date>.*</date>') is defined
- fetch_template_xml_format_result.template_xml | regex_search('</date><groups><group><name>Templates</name></group></groups><templates>') is defined
- fetch_template_xml_format_result.template_xml | regex_search('<templates><template><template>ExampleTemplateForTempleteInfoModule</template><name>ExampleTemplateForTempleteInfoModule</name><groups><group><name>Templates</name></group></groups></template></templates>') is defined
- name: "test - Fetch template info as a XML format with omit_date parameter from Zabbix Server"
- zabbix_template_info:
+ community.zabbix.zabbix_template_info:
template_name: ExampleTemplateForTempleteInfoModule
format: xml
omit_date: true
register: fetch_template_xml_format_omit_date_result
-- assert:
+- ansible.builtin.assert:
that:
- fetch_template_xml_format_omit_date_result.template_xml | regex_search('<date>.*</date>') is none
- fetch_template_xml_format_omit_date_result.template_xml | regex_search('</date><groups><group><name>Templates</name></group></groups><templates>') is defined
- fetch_template_xml_format_omit_date_result.template_xml | regex_search('<templates><template><template>ExampleTemplateForTempleteInfoModule</template><name>ExampleTemplateForTempleteInfoModule</name><groups><group><name>Templates</name></group></groups></template></templates>') is defined
- name: "test - Fetch template info as a YAML format from Zabbix Server"
- zabbix_template_info:
+ community.zabbix.zabbix_template_info:
template_name: ExampleTemplateForTempleteInfoModule
format: yaml
register: fetch_template_yaml_format_result
- when: zabbix_version is version('5.2', '>=')
-- assert:
+- ansible.builtin.assert:
that:
- fetch_template_yaml_format_result.template_yaml | regex_search('date: .+') is defined
- fetch_template_yaml_format_result.template_yaml | regex_search('name: Templates') is defined
- fetch_template_yaml_format_result.template_yaml | regex_search('template: ExampleTemplateForTempleteInfoModule') is defined
- when: zabbix_version is version('5.2', '>=')
- name: "test - Fetch template info as a YAML format with omit_date parameter from Zabbix Server"
- zabbix_template_info:
+ community.zabbix.zabbix_template_info:
template_name: ExampleTemplateForTempleteInfoModule
format: yaml
omit_date: true
register: fetch_template_yaml_format_omit_date_result
- when: zabbix_version is version('5.2', '>=')
-- assert:
+- ansible.builtin.assert:
that:
- fetch_template_yaml_format_result.template_yaml | regex_search('date: .+') is not defined
- fetch_template_yaml_format_result.template_yaml | regex_search('name: Templates') is defined
- fetch_template_yaml_format_result.template_yaml | regex_search('template: ExampleTemplateForTempleteInfoModule') is defined
- when: zabbix_version is version('5.2', '>=')
- name: "test - Fetch template info with none format from Zabbix Server"
- zabbix_template_info:
+ community.zabbix.zabbix_template_info:
template_name: ExampleTemplateForTempleteInfoModule
format: none
register: fetch_template_none_format_result
-- assert:
+- ansible.builtin.assert:
that:
- fetch_template_none_format_result.template_id is defined
- fetch_template_none_format_result.template_json is not defined
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_templategroup/meta/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_templategroup/meta/main.yml
new file mode 100644
index 000000000..acdb704c8
--- /dev/null
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_templategroup/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - setup_zabbix
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_templategroup/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_templategroup/tasks/main.yml
new file mode 100644
index 000000000..c04c20497
--- /dev/null
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_templategroup/tasks/main.yml
@@ -0,0 +1,59 @@
+---
+- name: test - do not run tests for Zabbix < 6.2
+ meta: end_play
+ when: zabbix_version is version('6.2', '<')
+
+- name: test - create new Zabbix template group
+ community.zabbix.zabbix_templategroup:
+ template_groups:
+ - zbxtempgrp_example_group01
+ state: present
+ register: zbxtempgrp_new
+
+- name: assert that group was created
+ ansible.builtin.assert:
+ that: zbxtempgrp_new is changed
+
+- name: test - create same Zabbix template group once again
+ community.zabbix.zabbix_templategroup:
+ template_groups:
+ - zbxtempgrp_example_group01
+ state: present
+ register: zbxtempgrp_existing
+
+- name: assert that nothing has been changed
+ ansible.builtin.assert:
+ that: not zbxtempgrp_existing is changed
+
+- name: test - attempt to create new Zabbix template group matching name of default Zabbix template group
+ community.zabbix.zabbix_templategroup:
+ template_groups:
+ - Templates
+ state: present
+ register: zbxtempgrp_default_existing
+
+- name: assert that nothing has been changed
+ ansible.builtin.assert:
+ that: not zbxtempgrp_default_existing is changed
+
+- name: test - attempt to delete previously created zabbix template group
+ community.zabbix.zabbix_templategroup:
+ template_groups:
+ - zbxtempgrp_example_group01
+ state: absent
+ register: zbxtempgrp_existing_delete
+
+- name: assert that group was deleted
+ ansible.builtin.assert:
+ that: zbxtempgrp_existing_delete is changed
+
+- name: test - attempt to delete non-existing zabbix template group
+ community.zabbix.zabbix_templategroup:
+ template_groups:
+ - zbxtempgrp_example_group01
+ state: absent
+ register: zbxtempgrp_missing_delete
+
+- name: assert that nothing has been changed
+ ansible.builtin.assert:
+ that: not zbxtempgrp_missing_delete is changed
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_token/meta/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_token/meta/main.yml
new file mode 100644
index 000000000..acdb704c8
--- /dev/null
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_token/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - setup_zabbix
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_token/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_token/tasks/main.yml
new file mode 100644
index 000000000..59b87b0f4
--- /dev/null
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_token/tasks/main.yml
@@ -0,0 +1,99 @@
+---
+- name: Create token
+ community.zabbix.zabbix_token:
+ name: test token
+ description: Admin test token
+ username: Admin
+ status: true
+ expires_at: 1700000000
+ state: present
+ register: zbx_token
+
+- name: assert that token was created
+ ansible.builtin.assert:
+ that:
+ - zbx_token is changed
+
+- name: Update token
+ community.zabbix.zabbix_token:
+ name: test token
+ description: Admin test token (Updated)
+ username: Admin
+ status: false
+ expires_at: 0
+ register: zbx_token
+
+- name: assert that token was updated
+ ansible.builtin.assert:
+ that:
+ - zbx_token is changed
+
+- name: Update token (not changes)
+ community.zabbix.zabbix_token:
+ name: test token
+ description: Admin test token (Updated)
+ username: Admin
+ status: false
+ expires_at: 0
+ register: zbx_token
+
+- name: assert that token was NOT updated
+ ansible.builtin.assert:
+ that:
+ - not zbx_token is changed
+
+- name: Delete token
+ community.zabbix.zabbix_token:
+ name: test token
+ username: Admin
+ state: absent
+ register: zbx_token
+
+- name: assert that token was deleted
+ ansible.builtin.assert:
+ that:
+ - zbx_token is changed
+
+- name: Delete token (already deleted)
+ community.zabbix.zabbix_token:
+ name: test token
+ username: Admin
+ state: absent
+ register: zbx_token
+
+- name: assert that token was not deleted
+ ansible.builtin.assert:
+ that:
+ - not zbx_token is changed
+
+- name: Create token with generating token
+ community.zabbix.zabbix_token:
+ name: test token
+ username: Admin
+ generate_token: true
+ register: zbx_token
+
+- name: assert that token was created
+ ansible.builtin.assert:
+ that:
+ - zbx_token is changed
+
+- name: Re-generate token
+ community.zabbix.zabbix_token:
+ name: test token
+ username: Admin
+ generate_token: true
+ register: zbx_new_token
+
+- name: assert that token was updated
+ ansible.builtin.assert:
+ that:
+ - zbx_token is changed
+ - zbx_token.token != zbx_new_token.token
+
+- name: Delete token
+ community.zabbix.zabbix_token:
+ name: test token
+ username: Admin
+ state: absent
+ register: zbx_token
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user/tasks/for_zabbix_50_lower.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user/tasks/for_zabbix_50_lower.yml
deleted file mode 100644
index b658e970a..000000000
--- a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user/tasks/for_zabbix_50_lower.yml
+++ /dev/null
@@ -1,1044 +0,0 @@
----
-# New user create test from here
-- name: test - Create a new Zabbix user with check_mode and diff
- zabbix_user:
- alias: example1
- name: example
- surname: test
- usrgrps:
- - Guests
- passwd: password
- check_mode: true
- diff: true
- register: create_zabbix_user_result
-
-- assert:
- that:
- - create_zabbix_user_result.changed is sameas true
-
-- name: test - Create a new Zabbix user
- zabbix_user:
- alias: example1
- name: example
- surname: test
- usrgrps:
- - Guests
- passwd: password
- register: create_zabbix_user_result
-
-- assert:
- that:
- - create_zabbix_user_result.changed is sameas true
-
-- name: test - Create a new Zabbix user(again)
- zabbix_user:
- alias: example1
- name: example
- surname: test
- usrgrps:
- - Guests
- passwd: password
- register: create_zabbix_user_result
-
-- assert:
- that:
- - not create_zabbix_user_result.changed is sameas true
-
-# Parameter add test from here to existing user
-- name: test - Add user group to existing user
- zabbix_user:
- alias: example1
- name: example
- surname: test
- usrgrps:
- - Guests
- - Zabbix administrators
- passwd: password
- register: add_usergroup_to_existing_user_result
-
-- assert:
- that:
- - add_usergroup_to_existing_user_result.changed is sameas true
-
-- name: test - Add user medias(Email) to existing user
- zabbix_user:
- alias: example1
- name: example
- surname: test
- usrgrps:
- - Guests
- - Zabbix administrators
- passwd: password
- user_medias:
- - mediatype: Email
- sendto: example@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- register: add_user_medias_to_existing_user_result
-
-- assert:
- that:
- - add_user_medias_to_existing_user_result.changed is sameas true
-
-- name: test - Add multiple user medias(Email and SMS) to existing user
- zabbix_user:
- alias: example1
- name: example
- surname: test
- usrgrps:
- - Guests
- - Zabbix administrators
- passwd: password
- user_medias:
- - mediatype: Email
- sendto: example@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- - mediatype: SMS
- sendto: example@example.com
- period: 1-5,01:00-23:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: false
- high: true
- disaster: true
- active: true
- register: add_user_medias_to_existing_user_result
-
-- assert:
- that:
- - add_user_medias_to_existing_user_result.changed is sameas true
-
-# Existing parameter updates test from here
-- name: test - Update password parameter for existing user
- zabbix_user:
- alias: example1
- name: example
- surname: test
- usrgrps:
- - Guests
- - Zabbix administrators
- passwd: update_password
- override_passwd: true
- user_medias:
- - mediatype: Email
- sendto: example@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- - mediatype: SMS
- sendto: example@example.com
- period: 1-5,01:00-23:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: false
- high: true
- disaster: true
- active: true
- register: update_password_parameter_existing_user_result
-
-- assert:
- that:
- - update_password_parameter_existing_user_result.changed is sameas true
-
-- name: test - Update autologin parameter for existing user
- zabbix_user:
- alias: example1
- name: example
- surname: test
- usrgrps:
- - Guests
- - Zabbix administrators
- passwd: update_password
- autologin: true
- user_medias:
- - mediatype: Email
- sendto: example@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- - mediatype: SMS
- sendto: example@example.com
- period: 1-5,01:00-23:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: false
- high: true
- disaster: true
- active: true
- register: update_autologin_parameter_existing_user_result
-
-- assert:
- that:
- - update_autologin_parameter_existing_user_result.changed is sameas true
-
-- name: test - Update autologout parameter for existing user
- zabbix_user:
- alias: example1
- name: example
- surname: test
- usrgrps:
- - Guests
- - Zabbix administrators
- passwd: update_password
- autologout: 500
- user_medias:
- - mediatype: Email
- sendto: example@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- - mediatype: SMS
- sendto: example@example.com
- period: 1-5,01:00-23:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: false
- high: true
- disaster: true
- active: true
- register: update_autologout_parameter_existing_user_result
-
-- assert:
- that:
- - update_autologout_parameter_existing_user_result.changed is sameas true
-
-- name: test - Update refresh parameter for existing user
- zabbix_user:
- alias: example1
- name: example
- surname: test
- usrgrps:
- - Guests
- - Zabbix administrators
- passwd: update_password
- autologout: 500
- refresh: 60
- user_medias:
- - mediatype: Email
- sendto: example@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- - mediatype: SMS
- sendto: example@example.com
- period: 1-5,01:00-23:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: false
- high: true
- disaster: true
- active: true
- register: update_refresh_parameter_existing_user_result
-
-- assert:
- that:
- - update_refresh_parameter_existing_user_result.changed is sameas true
-
-- name: test - Update rows_per_page parameter for existing user
- zabbix_user:
- alias: example1
- name: example
- surname: test
- usrgrps:
- - Guests
- - Zabbix administrators
- passwd: update_password
- autologout: 500
- refresh: 60
- rows_per_page: 300
- user_medias:
- - mediatype: Email
- sendto: example@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- - mediatype: SMS
- sendto: example@example.com
- period: 1-5,01:00-23:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: false
- high: true
- disaster: true
- active: true
- register: update_rows_per_page_parameter_existing_user_result
-
-- assert:
- that:
- - update_rows_per_page_parameter_existing_user_result.changed is sameas true
-
-- name: test - Update after_login_url parameter for existing user
- zabbix_user:
- alias: example1
- name: example
- surname: test
- usrgrps:
- - Guests
- - Zabbix administrators
- passwd: update_password
- autologout: 500
- refresh: 60
- rows_per_page: 300
- after_login_url: http://example.com
- user_medias:
- - mediatype: Email
- sendto: example@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- - mediatype: SMS
- sendto: example@example.com
- period: 1-5,01:00-23:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: false
- high: true
- disaster: true
- active: true
- register: update_after_login_url_parameter_existing_user_result
-
-- assert:
- that:
- - update_after_login_url_parameter_existing_user_result.changed is sameas true
-
-- name: test - Update theme parameter for existing user
- zabbix_user:
- alias: example1
- name: example
- surname: test
- usrgrps:
- - Guests
- - Zabbix administrators
- passwd: update_password
- autologout: 500
- refresh: 60
- rows_per_page: 300
- after_login_url: http://example.com
- theme: "{{ item }}"
- user_medias:
- - mediatype: Email
- sendto: example@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- - mediatype: SMS
- sendto: example@example.com
- period: 1-5,01:00-23:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: false
- high: true
- disaster: true
- active: true
- loop:
- - blue-theme
- - dark-theme
- register: update_theme_parameter_existing_user_result
-
-- assert:
- that:
- - item.changed is sameas true
- loop: "{{ update_theme_parameter_existing_user_result.results }}"
-
-- name: test - Update type parameter for existing user
- zabbix_user:
- alias: example1
- name: example
- surname: test
- usrgrps:
- - Guests
- - Zabbix administrators
- passwd: update_password
- autologout: 500
- refresh: 60
- rows_per_page: 300
- after_login_url: http://example.com
- theme: dark-theme
- type: "{{ item }}"
- user_medias:
- - mediatype: Email
- sendto: example@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- - mediatype: SMS
- sendto: example@example.com
- period: 1-5,01:00-23:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: false
- high: true
- disaster: true
- active: true
- loop:
- - Zabbix admin
- - Zabbix super admin
- register: update_type_parameter_existing_user_result
-
-- assert:
- that:
- - item.changed is sameas true
- loop: "{{ update_type_parameter_existing_user_result.results }}"
-
-- name: test - Update lang parameter for existing user
- zabbix_user:
- alias: example1
- name: example
- surname: test
- usrgrps:
- - Guests
- - Zabbix administrators
- passwd: update_password
- autologout: 500
- refresh: 60
- rows_per_page: 300
- after_login_url: http://example.com
- theme: dark-theme
- type: Zabbix super admin
- lang: en_US
- user_medias:
- - mediatype: Email
- sendto: example@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- - mediatype: SMS
- sendto: example@example.com
- period: 1-5,01:00-23:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: false
- high: true
- disaster: true
- active: true
- register: update_lang_parameter_existing_user_result
-
-- assert:
- that:
- - update_lang_parameter_existing_user_result.changed is sameas true
-
-- name: test - Update name and surname parameter for existing user
- zabbix_user:
- alias: example1
- name: example2
- surname: test2
- usrgrps:
- - Guests
- - Zabbix administrators
- passwd: update_password
- autologout: 500
- refresh: 60
- rows_per_page: 300
- after_login_url: http://example.com
- theme: dark-theme
- type: Zabbix super admin
- lang: en_US
- user_medias:
- - mediatype: Email
- sendto: example@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- - mediatype: SMS
- sendto: example@example.com
- period: 1-5,01:00-23:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: false
- high: true
- disaster: true
- active: true
- register: update_name_and_surname_parameter_existing_user_result
-
-- assert:
- that:
- - update_name_and_surname_parameter_existing_user_result.changed is sameas true
-
-- name: test - Update lang parameter for existing user with check_mode and diff
- zabbix_user:
- alias: example1
- name: example2
- surname: test2
- usrgrps:
- - Guests
- - Zabbix administrators
- passwd: update_password
- autologout: 500
- refresh: 60
- rows_per_page: 300
- after_login_url: http://example.com
- theme: dark-theme
- type: Zabbix super admin
- lang: en_GB
- user_medias:
- - mediatype: Email
- sendto: example@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- - mediatype: SMS
- sendto: example@example.com
- period: 1-5,01:00-23:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: false
- high: true
- disaster: true
- active: true
- check_mode: true
- diff: true
- register: update_lang_parameter_existing_user_with_check_mode_diff_result
-
-- assert:
- that:
- - update_lang_parameter_existing_user_with_check_mode_diff_result.changed is sameas true
-
-- name: test - Update lang parameter for existing user
- zabbix_user:
- alias: example1
- name: example2
- surname: test2
- usrgrps:
- - Guests
- - Zabbix administrators
- passwd: update_password
- autologout: 500
- refresh: 60
- rows_per_page: 300
- after_login_url: http://example.com
- theme: dark-theme
- type: Zabbix super admin
- lang: en_GB
- user_medias:
- - mediatype: Email
- sendto: example@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- - mediatype: SMS
- sendto: example@example.com
- period: 1-5,01:00-23:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: false
- high: true
- disaster: true
- active: true
- register: update_lang_parameter_existing_user_result
-
-- assert:
- that:
- - update_lang_parameter_existing_user_result.changed is sameas true
-
-- name: test - Update lang parameter for existing user(again)
- zabbix_user:
- alias: example1
- name: example2
- surname: test2
- usrgrps:
- - Guests
- - Zabbix administrators
- passwd: update_password
- autologout: 500
- refresh: 60
- rows_per_page: 300
- after_login_url: http://example.com
- theme: dark-theme
- type: Zabbix super admin
- lang: en_GB
- user_medias:
- - mediatype: Email
- sendto: example@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- - mediatype: SMS
- sendto: example@example.com
- period: 1-5,01:00-23:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: false
- high: true
- disaster: true
- active: true
- register: update_lang_parameter_existing_user_result
-
-- assert:
- that:
- - not update_lang_parameter_existing_user_result.changed is sameas true
-
-# Parameter delete test from here from existing user
-- name: test - Delete user medias(SMS) for existing user with check_mode and diff
- zabbix_user:
- alias: example1
- name: example2
- surname: test2
- usrgrps:
- - Guests
- - Zabbix administrators
- passwd: update_password
- autologout: 500
- refresh: 60
- rows_per_page: 300
- after_login_url: http://example.com
- theme: dark-theme
- type: Zabbix super admin
- lang: en_GB
- user_medias:
- - mediatype: Email
- sendto: example@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- check_mode: true
- diff: true
- register: delete_user_medias_existing_user_result
-
-- assert:
- that:
- - delete_user_medias_existing_user_result.changed is sameas true
-
-- name: test - Delete user medias(SMS) for existing user
- zabbix_user:
- alias: example1
- name: example2
- surname: test2
- usrgrps:
- - Guests
- - Zabbix administrators
- passwd: update_password
- autologout: 500
- refresh: 60
- rows_per_page: 300
- after_login_url: http://example.com
- theme: dark-theme
- type: Zabbix super admin
- lang: en_GB
- user_medias:
- - mediatype: Email
- sendto: example@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- register: delete_user_medias_existing_user_result
-
-- assert:
- that:
- - delete_user_medias_existing_user_result.changed is sameas true
-
-- name: test - Delete user group for existing user
- zabbix_user:
- alias: example1
- name: example2
- surname: test2
- usrgrps:
- - Zabbix administrators
- passwd: update_password
- autologout: 500
- refresh: 60
- rows_per_page: 300
- after_login_url: http://example.com
- theme: dark-theme
- type: Zabbix super admin
- lang: en_GB
- user_medias:
- - mediatype: Email
- sendto: example@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- register: delete_user_group_existing_user_result
-
-- assert:
- that:
- - delete_user_group_existing_user_result.changed is sameas true
-
-- name: test - optional user_medias
- zabbix_user:
- alias: example1
- name: example2
- surname: test2
- usrgrps:
- - Zabbix administrators
- passwd: update_password
- autologout: 500
- refresh: 60
- rows_per_page: 300
- after_login_url: http://example.com
- theme: dark-theme
- type: Zabbix super admin
- lang: en_GB
- register: update_user_optional_user_medias_existing_user_result
-
-- assert:
- that:
- - update_user_optional_user_medias_existing_user_result.changed is sameas False
-
-- name: test - Delete existing user with check_mode and diff
- zabbix_user:
- alias: example1
- state: absent
- check_mode: true
- diff: true
- register: delete_existing_user_result
-
-- assert:
- that:
- - delete_existing_user_result.changed is sameas true
-
-- name: test - Delete existing user
- zabbix_user:
- alias: example1
- state: absent
- register: delete_existing_user_result
-
-- assert:
- that:
- - delete_existing_user_result.changed is sameas true
-
-- name: test - Delete existing user(again)
- zabbix_user:
- alias: example1
- state: absent
- register: delete_existing_user_result
-
-- assert:
- that:
- - not delete_existing_user_result.changed is sameas true
-
-- when: zabbix_version is version('4.0', '<')
- block:
- - name: test - Create new password-less user without LDAP group (fail, <4.0)
- zabbix_user:
- alias: example2alias
- name: example2
- surname: testldap
- usrgrps:
- - Guests
- register: create_zabbix_user_ldap_fail
- ignore_errors: true
-
- - assert:
- that:
- - create_zabbix_user_ldap_fail.failed is sameas True
-
-- when: zabbix_version is version('4.0', '>=')
- block:
- - name: test prepare - Create LDAP user group
- zabbix_usergroup:
- name: testLDAPgrp
- gui_access: LDAP
- register: zbxuser_create_ldap_group
-
- - assert:
- that:
- - zbxuser_create_ldap_group.changed is sameas True
-
- - name: test - Create new password-less user without LDAP group (fail)
- zabbix_user:
- alias: example2alias
- name: example2
- surname: testldap
- usrgrps:
- - Guests
- register: create_zabbix_user_ldap_fail
- ignore_errors: true
-
- - assert:
- that:
- - create_zabbix_user_ldap_fail.failed is sameas True
-
- - name: test - Create new password-less user as member in LDAP group
- zabbix_user:
- alias: example2alias
- name: example2
- surname: testldap
- usrgrps:
- - testLDAPgrp
- register: create_zabbix_user_ldap_result
-
- - assert:
- that:
- - create_zabbix_user_ldap_result.changed is sameas True
-
- - name: test - Create new password-less user as member in LDAP group (again)
- zabbix_user:
- alias: example2alias
- name: example2
- surname: testldap
- usrgrps:
- - testLDAPgrp
- register: create_zabbix_user_ldap_result
-
- - assert:
- that:
- - create_zabbix_user_ldap_result.changed is sameas False
-
- - name: test - Delete existing user
- zabbix_user:
- alias: example2alias
- state: absent
- register: delete_existing_user_result
-
- - assert:
- that:
- - delete_existing_user_result.changed is sameas true
-
-# The tests are to check the patch for PR hasn't a problem.
-# https://github.com/ansible-collections/community.zabbix/pull/382
-- name: test - Create a zabbix user with minimum parameters
- zabbix_user:
- alias: example2
- usrgrps:
- - Guests
- passwd: password
- register: create_zabbix_user_with_minimum_params_result
-
-- assert:
- that:
- - create_zabbix_user_with_minimum_params_result.changed is sameas true
-
-- name: test - Create a zabbix user with minimum parameters(again)
- zabbix_user:
- alias: example2
- usrgrps:
- - Guests
- passwd: password
- register: create_zabbix_user_with_minimum_params_result
-
-- assert:
- that:
- - create_zabbix_user_with_minimum_params_result.changed is sameas false
-
-- name: test - Update the parameters without role_name
- zabbix_user:
- alias: example2
- name: example2
- surname: test
- usrgrps:
- - Guests
- passwd: password
- register: update_params_without_role_name_result
-
-- assert:
- that:
- - update_params_without_role_name_result.changed is sameas true
-
-- name: test - Update the parameters without role_name(again)
- zabbix_user:
- alias: example2
- name: example2
- surname: test
- usrgrps:
- - Guests
- passwd: password
- register: update_params_without_role_name_result
-
-- assert:
- that:
- - update_params_without_role_name_result.changed is sameas false
-
-- name: test - Add user medias(Email) as list to existing user
- zabbix_user:
- alias: example2
- name: example2
- surname: test
- usrgrps:
- - Guests
- passwd: G$jd_79!jw
- user_medias:
- - mediatype: Email
- sendto:
- - example@example.com
- - example1@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- register: add_user_email_media_as_list_to_existing_user_result
-
-- assert:
- that:
- - add_user_email_media_as_list_to_existing_user_result.changed is sameas true
-
-- name: test - Add user medias(Email) as list to existing user(again)
- zabbix_user:
- alias: example2
- name: example2
- surname: test
- usrgrps:
- - Guests
- passwd: G$jd_79!jw
- user_medias:
- - mediatype: Email
- sendto:
- - example@example.com
- - example1@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- register: add_user_email_media_as_list_to_existing_user_result
-
-- assert:
- that:
- - add_user_email_media_as_list_to_existing_user_result.changed is sameas false
-
-- name: test - Delete existing user
- zabbix_user:
- alias: example2
- state: absent
-
-- name: test prepare - Delete LDAP user group
- zabbix_usergroup:
- name: testLDAPgrp
- state: absent
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user/tasks/for_zabbix_54_higher.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user/tasks/for_zabbix_54_higher.yml
deleted file mode 100644
index 9d3d913ce..000000000
--- a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user/tasks/for_zabbix_54_higher.yml
+++ /dev/null
@@ -1,1100 +0,0 @@
----
-# New user create test from here
-- name: test - Create a new Zabbix user with check_mode and diff
- zabbix_user:
- alias: example1
- name: example
- surname: test
- usrgrps:
- - Guests
- passwd: G$jd_79!jw
- check_mode: true
- diff: true
- register: create_zabbix_user_result
-
-- assert:
- that:
- - create_zabbix_user_result.changed is sameas true
-
-- name: test - Create a new Zabbix user
- zabbix_user:
- alias: example1
- name: example
- surname: test
- usrgrps:
- - Guests
- passwd: G$jd_79!jw
- register: create_zabbix_user_result
-
-- assert:
- that:
- - create_zabbix_user_result.changed is sameas true
-
-- name: test - Create a new Zabbix user(again)
- zabbix_user:
- alias: example1
- name: example
- surname: test
- usrgrps:
- - Guests
- passwd: G$jd_79!jw
- register: create_zabbix_user_result
-
-- assert:
- that:
- - not create_zabbix_user_result.changed is sameas true
-
-# Parameter add test from here to existing user
-- name: test - Add user group to existing user
- zabbix_user:
- alias: example1
- name: example
- surname: test
- usrgrps:
- - Guests
- - Zabbix administrators
- passwd: G$jd_79!jw
- register: add_usergroup_to_existing_user_result
-
-- assert:
- that:
- - add_usergroup_to_existing_user_result.changed is sameas true
-
-- name: test - Add user medias(Email) to existing user
- zabbix_user:
- alias: example1
- name: example
- surname: test
- usrgrps:
- - Guests
- - Zabbix administrators
- passwd: G$jd_79!jw
- user_medias:
- - mediatype: Email
- sendto: example@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- register: add_user_medias_to_existing_user_result
-
-- assert:
- that:
- - add_user_medias_to_existing_user_result.changed is sameas true
-
-- name: test - Add multiple user medias(Email and SMS) to existing user
- zabbix_user:
- alias: example1
- name: example
- surname: test
- usrgrps:
- - Guests
- - Zabbix administrators
- passwd: G$jd_79!jw
- user_medias:
- - mediatype: Email
- sendto: example@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- - mediatype: SMS
- sendto: example@example.com
- period: 1-5,01:00-23:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: false
- high: true
- disaster: true
- active: true
- register: add_user_medias_to_existing_user_result
-
-- assert:
- that:
- - add_user_medias_to_existing_user_result.changed is sameas true
-
-# Existing parameter updates test from here
-- name: test - Update password parameter for existing user
- zabbix_user:
- alias: example1
- name: example
- surname: test
- usrgrps:
- - Guests
- - Zabbix administrators
- passwd: update_password
- override_passwd: true
- user_medias:
- - mediatype: Email
- sendto: example@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- - mediatype: SMS
- sendto: example@example.com
- period: 1-5,01:00-23:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: false
- high: true
- disaster: true
- active: true
- register: update_password_parameter_existing_user_result
-
-- assert:
- that:
- - update_password_parameter_existing_user_result.changed is sameas true
-
-- name: test - Update autologin parameter for existing user
- zabbix_user:
- alias: example1
- name: example
- surname: test
- usrgrps:
- - Guests
- - Zabbix administrators
- passwd: update_password
- autologin: true
- user_medias:
- - mediatype: Email
- sendto: example@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- - mediatype: SMS
- sendto: example@example.com
- period: 1-5,01:00-23:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: false
- high: true
- disaster: true
- active: true
- register: update_autologin_parameter_existing_user_result
-
-- assert:
- that:
- - update_autologin_parameter_existing_user_result.changed is sameas true
-
-- name: test - Update autologout parameter for existing user
- zabbix_user:
- alias: example1
- name: example
- surname: test
- usrgrps:
- - Guests
- - Zabbix administrators
- passwd: update_password
- autologout: 500
- user_medias:
- - mediatype: Email
- sendto: example@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- - mediatype: SMS
- sendto: example@example.com
- period: 1-5,01:00-23:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: false
- high: true
- disaster: true
- active: true
- register: update_autologout_parameter_existing_user_result
-
-- assert:
- that:
- - update_autologout_parameter_existing_user_result.changed is sameas true
-
-- name: test - Update refresh parameter for existing user
- zabbix_user:
- alias: example1
- name: example
- surname: test
- usrgrps:
- - Guests
- - Zabbix administrators
- passwd: update_password
- autologout: 500
- refresh: 60
- user_medias:
- - mediatype: Email
- sendto: example@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- - mediatype: SMS
- sendto: example@example.com
- period: 1-5,01:00-23:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: false
- high: true
- disaster: true
- active: true
- register: update_refresh_parameter_existing_user_result
-
-- assert:
- that:
- - update_refresh_parameter_existing_user_result.changed is sameas true
-
-- name: test - Update rows_per_page parameter for existing user
- zabbix_user:
- alias: example1
- name: example
- surname: test
- usrgrps:
- - Guests
- - Zabbix administrators
- passwd: update_password
- autologout: 500
- refresh: 60
- rows_per_page: 300
- user_medias:
- - mediatype: Email
- sendto: example@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- - mediatype: SMS
- sendto: example@example.com
- period: 1-5,01:00-23:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: false
- high: true
- disaster: true
- active: true
- register: update_rows_per_page_parameter_existing_user_result
-
-- assert:
- that:
- - update_rows_per_page_parameter_existing_user_result.changed is sameas true
-
-- name: test - Update after_login_url parameter for existing user
- zabbix_user:
- alias: example1
- name: example
- surname: test
- usrgrps:
- - Guests
- - Zabbix administrators
- passwd: update_password
- autologout: 500
- refresh: 60
- rows_per_page: 300
- after_login_url: http://example.com
- user_medias:
- - mediatype: Email
- sendto: example@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- - mediatype: SMS
- sendto: example@example.com
- period: 1-5,01:00-23:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: false
- high: true
- disaster: true
- active: true
- register: update_after_login_url_parameter_existing_user_result
-
-- assert:
- that:
- - update_after_login_url_parameter_existing_user_result.changed is sameas true
-
-- name: test - Update theme parameter for existing user
- zabbix_user:
- alias: example1
- name: example
- surname: test
- usrgrps:
- - Guests
- - Zabbix administrators
- passwd: update_password
- autologout: 500
- refresh: 60
- rows_per_page: 300
- after_login_url: http://example.com
- theme: "{{ item }}"
- user_medias:
- - mediatype: Email
- sendto: example@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- - mediatype: SMS
- sendto: example@example.com
- period: 1-5,01:00-23:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: false
- high: true
- disaster: true
- active: true
- loop:
- - blue-theme
- - dark-theme
- register: update_theme_parameter_existing_user_result
-
-- assert:
- that:
- - item.changed is sameas true
- loop: "{{ update_theme_parameter_existing_user_result.results }}"
-
-- name: test - Update role_name parameter for existing user
- zabbix_user:
- alias: example1
- name: example
- surname: test
- usrgrps:
- - Guests
- - Zabbix administrators
- passwd: update_password
- autologout: 500
- refresh: 60
- rows_per_page: 300
- after_login_url: http://example.com
- theme: dark-theme
- role_name: "{{ item }}"
- user_medias:
- - mediatype: Email
- sendto: example@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- - mediatype: SMS
- sendto: example@example.com
- period: 1-5,01:00-23:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: false
- high: true
- disaster: true
- active: true
- loop:
- - Guest role
- - Admin role
- register: update_type_parameter_existing_user_result
-
-- assert:
- that:
- - item.changed is sameas true
- loop: "{{ update_type_parameter_existing_user_result.results }}"
-
-- name: test - Update lang parameter for existing user
- zabbix_user:
- alias: example1
- name: example
- surname: test
- usrgrps:
- - Guests
- - Zabbix administrators
- passwd: update_password
- autologout: 500
- refresh: 60
- rows_per_page: 300
- after_login_url: http://example.com
- theme: dark-theme
- role_name: Admin role
- lang: en_US
- user_medias:
- - mediatype: Email
- sendto: example@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- - mediatype: SMS
- sendto: example@example.com
- period: 1-5,01:00-23:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: false
- high: true
- disaster: true
- active: true
- register: update_lang_parameter_existing_user_result
-
-- assert:
- that:
- - update_lang_parameter_existing_user_result.changed is sameas true
-
-- name: test - Update timezone parameter for existing user
- zabbix_user:
- alias: example1
- name: example
- surname: test
- usrgrps:
- - Guests
- - Zabbix administrators
- passwd: update_password
- autologout: 500
- refresh: 60
- rows_per_page: 300
- after_login_url: http://example.com
- theme: dark-theme
- role_name: Admin role
- timezone: Asia/Tokyo
- lang: en_US
- user_medias:
- - mediatype: Email
- sendto: example@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- - mediatype: SMS
- sendto: example@example.com
- period: 1-5,01:00-23:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: false
- high: true
- disaster: true
- active: true
- register: update_timezone_parameter_existing_user_result
-
-- assert:
- that:
- - update_timezone_parameter_existing_user_result.changed is sameas true
-
-- name: test - Update name and surname parameter for existing user
- zabbix_user:
- alias: example1
- name: example2
- surname: test2
- usrgrps:
- - Guests
- - Zabbix administrators
- passwd: update_password
- autologout: 500
- refresh: 60
- rows_per_page: 300
- after_login_url: http://example.com
- theme: dark-theme
- role_name: Admin role
- timezone: Asia/Tokyo
- lang: en_US
- user_medias:
- - mediatype: Email
- sendto: example@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- - mediatype: SMS
- sendto: example@example.com
- period: 1-5,01:00-23:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: false
- high: true
- disaster: true
- active: true
- register: update_name_and_surname_parameter_existing_user_result
-
-- assert:
- that:
- - update_name_and_surname_parameter_existing_user_result.changed is sameas true
-
-- name: test - Update lang parameter for existing user with check_mode and diff
- zabbix_user:
- alias: example1
- name: example2
- surname: test2
- usrgrps:
- - Guests
- - Zabbix administrators
- passwd: update_password
- autologout: 500
- refresh: 60
- rows_per_page: 300
- after_login_url: http://example.com
- theme: dark-theme
- role_name: Admin role
- timezone: Asia/Tokyo
- lang: fr_FR
- user_medias:
- - mediatype: Email
- sendto: example@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- - mediatype: SMS
- sendto: example@example.com
- period: 1-5,01:00-23:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: false
- high: true
- disaster: true
- active: true
- check_mode: true
- diff: true
- register: update_lang_parameter_existing_user_with_check_mode_diff_result
-
-- assert:
- that:
- - update_lang_parameter_existing_user_with_check_mode_diff_result.changed is sameas true
-
-- name: test - Update lang parameter for existing user
- zabbix_user:
- alias: example1
- name: example2
- surname: test2
- usrgrps:
- - Guests
- - Zabbix administrators
- passwd: update_password
- autologout: 500
- refresh: 60
- rows_per_page: 300
- after_login_url: http://example.com
- theme: dark-theme
- role_name: Admin role
- timezone: Asia/Tokyo
- lang: fr_FR
- user_medias:
- - mediatype: Email
- sendto: example@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- - mediatype: SMS
- sendto: example@example.com
- period: 1-5,01:00-23:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: false
- high: true
- disaster: true
- active: true
- register: update_lang_parameter_existing_user_result
-
-- assert:
- that:
- - update_lang_parameter_existing_user_result.changed is sameas true
-
-- name: test - Update lang parameter for existing user(again)
- zabbix_user:
- alias: example1
- name: example2
- surname: test2
- usrgrps:
- - Guests
- - Zabbix administrators
- passwd: update_password
- autologout: 500
- refresh: 60
- rows_per_page: 300
- after_login_url: http://example.com
- theme: dark-theme
- role_name: Admin role
- timezone: Asia/Tokyo
- lang: fr_FR
- user_medias:
- - mediatype: Email
- sendto: example@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- - mediatype: SMS
- sendto: example@example.com
- period: 1-5,01:00-23:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: false
- high: true
- disaster: true
- active: true
- register: update_lang_parameter_existing_user_result
-
-- assert:
- that:
- - not update_lang_parameter_existing_user_result.changed is sameas true
-
-# Parameter delete test from here from existing user
-- name: test - Delete user medias(SMS) for existing user with check_mode and diff
- zabbix_user:
- alias: example1
- name: example2
- surname: test2
- usrgrps:
- - Guests
- - Zabbix administrators
- passwd: update_password
- autologout: 500
- refresh: 60
- rows_per_page: 300
- after_login_url: http://example.com
- theme: dark-theme
- role_name: Admin role
- timezone: Asia/Tokyo
- lang: fr_FR
- user_medias:
- - mediatype: Email
- sendto: example@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- check_mode: true
- diff: true
- register: delete_user_medias_existing_user_result
-
-- assert:
- that:
- - delete_user_medias_existing_user_result.changed is sameas true
-
-- name: test - Delete user medias(SMS) for existing user
- zabbix_user:
- alias: example1
- name: example2
- surname: test2
- usrgrps:
- - Guests
- - Zabbix administrators
- passwd: update_password
- autologout: 500
- refresh: 60
- rows_per_page: 300
- after_login_url: http://example.com
- theme: dark-theme
- role_name: Admin role
- timezone: Asia/Tokyo
- lang: fr_FR
- user_medias:
- - mediatype: Email
- sendto: example@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- register: delete_user_medias_existing_user_result
-
-- assert:
- that:
- - delete_user_medias_existing_user_result.changed is sameas true
-
-- name: test - Delete user group for existing user
- zabbix_user:
- alias: example1
- name: example2
- surname: test2
- usrgrps:
- - Zabbix administrators
- passwd: update_password
- autologout: 500
- refresh: 60
- rows_per_page: 300
- after_login_url: http://example.com
- theme: dark-theme
- role_name: Admin role
- timezone: Asia/Tokyo
- lang: fr_FR
- user_medias:
- - mediatype: Email
- sendto: example@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- register: delete_user_group_existing_user_result
-
-- assert:
- that:
- - delete_user_group_existing_user_result.changed is sameas true
-
-- name: test - optional user_medias
- zabbix_user:
- alias: example1
- name: example2
- surname: test2
- usrgrps:
- - Zabbix administrators
- passwd: update_password
- autologout: 500
- refresh: 60
- rows_per_page: 300
- after_login_url: http://example.com
- theme: dark-theme
- role_name: Admin role
- timezone: Asia/Tokyo
- lang: fr_FR
- register: update_user_optional_user_medias_existing_user_result
-
-- assert:
- that:
- - update_user_optional_user_medias_existing_user_result.changed is sameas False
-
-- name: test - Delete existing user with check_mode and diff
- zabbix_user:
- alias: example1
- state: absent
- check_mode: true
- diff: true
- register: delete_existing_user_result
-
-- assert:
- that:
- - delete_existing_user_result.changed is sameas true
-
-- name: test - Delete existing user
- zabbix_user:
- alias: example1
- state: absent
- register: delete_existing_user_result
-
-- assert:
- that:
- - delete_existing_user_result.changed is sameas true
-
-- name: test - Delete existing user(again)
- zabbix_user:
- alias: example1
- state: absent
- register: delete_existing_user_result
-
-- assert:
- that:
- - not delete_existing_user_result.changed is sameas true
-
-- when: zabbix_version is version('4.0', '<')
- block:
- - name: test - Create new password-less user without LDAP group (fail, <4.0)
- zabbix_user:
- alias: example2alias
- name: example2
- surname: testldap
- usrgrps:
- - Guests
- register: create_zabbix_user_ldap_fail
- ignore_errors: true
-
- - assert:
- that:
- - create_zabbix_user_ldap_fail.failed is sameas True
-
-- when: zabbix_version is version('4.0', '>=')
- block:
- - name: test prepare - Create LDAP user group
- zabbix_usergroup:
- name: testLDAPgrp
- gui_access: LDAP
- register: zbxuser_create_ldap_group
-
- - assert:
- that:
- - zbxuser_create_ldap_group.changed is sameas True
-
- - name: test - Create new password-less user without LDAP group (fail)
- zabbix_user:
- alias: example2alias
- name: example2
- surname: testldap
- usrgrps:
- - Guests
- register: create_zabbix_user_ldap_fail
- ignore_errors: true
-
- - assert:
- that:
- - create_zabbix_user_ldap_fail.failed is sameas True
-
- - name: test - Create new password-less user as member in LDAP group
- zabbix_user:
- alias: example2alias
- name: example2
- surname: testldap
- usrgrps:
- - testLDAPgrp
- register: create_zabbix_user_ldap_result
-
- - assert:
- that:
- - create_zabbix_user_ldap_result.changed is sameas True
-
- - name: test - Create new password-less user as member in LDAP group (again)
- zabbix_user:
- alias: example2alias
- name: example2
- surname: testldap
- usrgrps:
- - testLDAPgrp
- register: create_zabbix_user_ldap_result
-
- - assert:
- that:
- - create_zabbix_user_ldap_result.changed is sameas False
-
- - name: test - Delete existing user
- zabbix_user:
- alias: example2alias
- state: absent
- register: delete_existing_user_result
-
- - assert:
- that:
- - delete_existing_user_result.changed is sameas true
-
-# The tests are to check the patch for PR hasn't a problem.
-# https://github.com/ansible-collections/community.zabbix/pull/382
-- name: test - Create a zabbix user with minimum parameters
- zabbix_user:
- alias: example2
- usrgrps:
- - Guests
- passwd: G$jd_79!jw
- role_name: "User role"
- register: create_zabbix_user_with_minimum_params_result
-
-- assert:
- that:
- - create_zabbix_user_with_minimum_params_result.changed is sameas true
-
-- name: test - Create a zabbix user with minimum parameters(again)
- zabbix_user:
- alias: example2
- usrgrps:
- - Guests
- passwd: G$jd_79!jw
- role_name: "User role"
- register: create_zabbix_user_with_minimum_params_result
-
-- assert:
- that:
- - create_zabbix_user_with_minimum_params_result.changed is sameas false
-
-- name: test - Update the parameters without role_name
- zabbix_user:
- alias: example2
- name: example2
- surname: test
- usrgrps:
- - Guests
- passwd: G$jd_79!jw
- register: update_params_without_role_name_result
-
-- assert:
- that:
- - update_params_without_role_name_result.changed is sameas true
-
-- name: test - Update the parameters without role_name(again)
- zabbix_user:
- alias: example2
- name: example2
- surname: test
- usrgrps:
- - Guests
- passwd: G$jd_79!jw
- register: update_params_without_role_name_result
-
-- assert:
- that:
- - update_params_without_role_name_result.changed is sameas false
-
-- name: test - Add user medias(Email) as list to existing user
- zabbix_user:
- alias: example2
- name: example2
- surname: test
- usrgrps:
- - Guests
- passwd: G$jd_79!jw
- user_medias:
- - mediatype: Email
- sendto:
- - example@example.com
- - example1@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- register: add_user_email_media_as_list_to_existing_user_result
-
-- assert:
- that:
- - add_user_email_media_as_list_to_existing_user_result.changed is sameas true
-
-- name: test - Add user medias(Email) as list to existing user(again)
- zabbix_user:
- alias: example2
- name: example2
- surname: test
- usrgrps:
- - Guests
- passwd: G$jd_79!jw
- user_medias:
- - mediatype: Email
- sendto:
- - example@example.com
- - example1@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: true
- register: add_user_email_media_as_list_to_existing_user_result
-
-- assert:
- that:
- - add_user_email_media_as_list_to_existing_user_result.changed is sameas false
-
-- name: test - Delete existing user
- zabbix_user:
- alias: example2
- state: absent
-
-- name: test prepare - Delete LDAP user group
- zabbix_usergroup:
- name: testLDAPgrp
- state: absent
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user/tasks/main.yml
index f762591cf..29163436f 100644
--- a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user/tasks/main.yml
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user/tasks/main.yml
@@ -1,10 +1,1082 @@
---
-- name: Execute the integration test for Zabbix 5.0 and lower
- include_tasks: for_zabbix_50_lower.yml
- when:
- - zabbix_version | float <= 5.0
-
-- name: Execute the integration test for Zabbix 5.4 and higher
- include_tasks: for_zabbix_54_higher.yml
- when:
- - zabbix_version | float >= 5.4
+# New user create test from here
+- name: test - Create a new Zabbix user with check_mode and diff
+ community.zabbix.zabbix_user:
+ username: example1
+ name: example
+ surname: test
+ usrgrps:
+ - Guests
+ passwd: G$jd_79!jw
+ check_mode: true
+ diff: true
+ register: create_zabbix_user_result
+
+- ansible.builtin.assert:
+ that:
+ - create_zabbix_user_result.changed is sameas true
+
+- name: test - Create a new Zabbix user
+ community.zabbix.zabbix_user:
+ username: example1
+ name: example
+ surname: test
+ usrgrps:
+ - Guests
+ passwd: G$jd_79!jw
+ register: create_zabbix_user_result
+
+- ansible.builtin.assert:
+ that:
+ - create_zabbix_user_result.changed is sameas true
+
+- name: test - Create a new Zabbix user(again)
+ community.zabbix.zabbix_user:
+ username: example1
+ name: example
+ surname: test
+ usrgrps:
+ - Guests
+ passwd: G$jd_79!jw
+ register: create_zabbix_user_result
+
+- ansible.builtin.assert:
+ that:
+ - not create_zabbix_user_result.changed is sameas true
+
+# Parameter add test from here to existing user
+- name: test - Add user group to existing user
+ community.zabbix.zabbix_user:
+ username: example1
+ name: example
+ surname: test
+ usrgrps:
+ - Guests
+ - Zabbix administrators
+ passwd: G$jd_79!jw
+ register: add_usergroup_to_existing_user_result
+
+- ansible.builtin.assert:
+ that:
+ - add_usergroup_to_existing_user_result.changed is sameas true
+
+- name: test - Add user medias(Email) to existing user
+ community.zabbix.zabbix_user:
+ username: example1
+ name: example
+ surname: test
+ usrgrps:
+ - Guests
+ - Zabbix administrators
+ passwd: G$jd_79!jw
+ user_medias:
+ - mediatype: Email
+ sendto: example@example.com
+ period: 1-7,00:00-24:00
+ severity:
+ not_classified: false
+ information: true
+ warning: true
+ average: true
+ high: true
+ disaster: true
+ active: true
+ register: add_user_medias_to_existing_user_result
+
+- ansible.builtin.assert:
+ that:
+ - add_user_medias_to_existing_user_result.changed is sameas true
+
+- name: test - Add multiple user medias(Email and SMS) to existing user
+ community.zabbix.zabbix_user:
+ username: example1
+ name: example
+ surname: test
+ usrgrps:
+ - Guests
+ - Zabbix administrators
+ passwd: G$jd_79!jw
+ user_medias:
+ - mediatype: Email
+ sendto: example@example.com
+ period: 1-7,00:00-24:00
+ severity:
+ not_classified: false
+ information: true
+ warning: true
+ average: true
+ high: true
+ disaster: true
+ active: true
+ - mediatype: SMS
+ sendto: example@example.com
+ period: 1-5,01:00-23:00
+ severity:
+ not_classified: false
+ information: true
+ warning: true
+ average: false
+ high: true
+ disaster: true
+ active: true
+ register: add_user_medias_to_existing_user_result
+
+- ansible.builtin.assert:
+ that:
+ - add_user_medias_to_existing_user_result.changed is sameas true
+
+# Existing parameter updates test from here
+- name: test - Update password parameter for existing user
+ community.zabbix.zabbix_user:
+ username: example1
+ name: example
+ surname: test
+ usrgrps:
+ - Guests
+ - Zabbix administrators
+ passwd: update_password
+ override_passwd: true
+ user_medias:
+ - mediatype: Email
+ sendto: example@example.com
+ period: 1-7,00:00-24:00
+ severity:
+ not_classified: false
+ information: true
+ warning: true
+ average: true
+ high: true
+ disaster: true
+ active: true
+ - mediatype: SMS
+ sendto: example@example.com
+ period: 1-5,01:00-23:00
+ severity:
+ not_classified: false
+ information: true
+ warning: true
+ average: false
+ high: true
+ disaster: true
+ active: true
+ register: update_password_parameter_existing_user_result
+
+- ansible.builtin.assert:
+ that:
+ - update_password_parameter_existing_user_result.changed is sameas true
+
+- name: test - Update autologin parameter for existing user
+ community.zabbix.zabbix_user:
+ username: example1
+ name: example
+ surname: test
+ usrgrps:
+ - Guests
+ - Zabbix administrators
+ passwd: update_password
+ autologin: true
+ user_medias:
+ - mediatype: Email
+ sendto: example@example.com
+ period: 1-7,00:00-24:00
+ severity:
+ not_classified: false
+ information: true
+ warning: true
+ average: true
+ high: true
+ disaster: true
+ active: true
+ - mediatype: SMS
+ sendto: example@example.com
+ period: 1-5,01:00-23:00
+ severity:
+ not_classified: false
+ information: true
+ warning: true
+ average: false
+ high: true
+ disaster: true
+ active: true
+ register: update_autologin_parameter_existing_user_result
+
+- ansible.builtin.assert:
+ that:
+ - update_autologin_parameter_existing_user_result.changed is sameas true
+
+- name: test - Update autologout parameter for existing user
+ community.zabbix.zabbix_user:
+ username: example1
+ name: example
+ surname: test
+ usrgrps:
+ - Guests
+ - Zabbix administrators
+ passwd: update_password
+ autologout: 500
+ user_medias:
+ - mediatype: Email
+ sendto: example@example.com
+ period: 1-7,00:00-24:00
+ severity:
+ not_classified: false
+ information: true
+ warning: true
+ average: true
+ high: true
+ disaster: true
+ active: true
+ - mediatype: SMS
+ sendto: example@example.com
+ period: 1-5,01:00-23:00
+ severity:
+ not_classified: false
+ information: true
+ warning: true
+ average: false
+ high: true
+ disaster: true
+ active: true
+ register: update_autologout_parameter_existing_user_result
+
+- ansible.builtin.assert:
+ that:
+ - update_autologout_parameter_existing_user_result.changed is sameas true
+
+- name: test - Update refresh parameter for existing user
+ community.zabbix.zabbix_user:
+ username: example1
+ name: example
+ surname: test
+ usrgrps:
+ - Guests
+ - Zabbix administrators
+ passwd: update_password
+ autologout: 500
+ refresh: 60
+ user_medias:
+ - mediatype: Email
+ sendto: example@example.com
+ period: 1-7,00:00-24:00
+ severity:
+ not_classified: false
+ information: true
+ warning: true
+ average: true
+ high: true
+ disaster: true
+ active: true
+ - mediatype: SMS
+ sendto: example@example.com
+ period: 1-5,01:00-23:00
+ severity:
+ not_classified: false
+ information: true
+ warning: true
+ average: false
+ high: true
+ disaster: true
+ active: true
+ register: update_refresh_parameter_existing_user_result
+
+- ansible.builtin.assert:
+ that:
+ - update_refresh_parameter_existing_user_result.changed is sameas true
+
+- name: test - Update rows_per_page parameter for existing user
+ community.zabbix.zabbix_user:
+ username: example1
+ name: example
+ surname: test
+ usrgrps:
+ - Guests
+ - Zabbix administrators
+ passwd: update_password
+ autologout: 500
+ refresh: 60
+ rows_per_page: 300
+ user_medias:
+ - mediatype: Email
+ sendto: example@example.com
+ period: 1-7,00:00-24:00
+ severity:
+ not_classified: false
+ information: true
+ warning: true
+ average: true
+ high: true
+ disaster: true
+ active: true
+ - mediatype: SMS
+ sendto: example@example.com
+ period: 1-5,01:00-23:00
+ severity:
+ not_classified: false
+ information: true
+ warning: true
+ average: false
+ high: true
+ disaster: true
+ active: true
+ register: update_rows_per_page_parameter_existing_user_result
+
+- ansible.builtin.assert:
+ that:
+ - update_rows_per_page_parameter_existing_user_result.changed is sameas true
+
+- name: test - Update after_login_url parameter for existing user
+ community.zabbix.zabbix_user:
+ username: example1
+ name: example
+ surname: test
+ usrgrps:
+ - Guests
+ - Zabbix administrators
+ passwd: update_password
+ autologout: 500
+ refresh: 60
+ rows_per_page: 300
+ after_login_url: http://example.com
+ user_medias:
+ - mediatype: Email
+ sendto: example@example.com
+ period: 1-7,00:00-24:00
+ severity:
+ not_classified: false
+ information: true
+ warning: true
+ average: true
+ high: true
+ disaster: true
+ active: true
+ - mediatype: SMS
+ sendto: example@example.com
+ period: 1-5,01:00-23:00
+ severity:
+ not_classified: false
+ information: true
+ warning: true
+ average: false
+ high: true
+ disaster: true
+ active: true
+ register: update_after_login_url_parameter_existing_user_result
+
+- ansible.builtin.assert:
+ that:
+ - update_after_login_url_parameter_existing_user_result.changed is sameas true
+
+- name: test - Update theme parameter for existing user
+ community.zabbix.zabbix_user:
+ username: example1
+ name: example
+ surname: test
+ usrgrps:
+ - Guests
+ - Zabbix administrators
+ passwd: update_password
+ autologout: 500
+ refresh: 60
+ rows_per_page: 300
+ after_login_url: http://example.com
+ theme: "{{ item }}"
+ user_medias:
+ - mediatype: Email
+ sendto: example@example.com
+ period: 1-7,00:00-24:00
+ severity:
+ not_classified: false
+ information: true
+ warning: true
+ average: true
+ high: true
+ disaster: true
+ active: true
+ - mediatype: SMS
+ sendto: example@example.com
+ period: 1-5,01:00-23:00
+ severity:
+ not_classified: false
+ information: true
+ warning: true
+ average: false
+ high: true
+ disaster: true
+ active: true
+ loop:
+ - blue-theme
+ - dark-theme
+ register: update_theme_parameter_existing_user_result
+
+- ansible.builtin.assert:
+ that:
+ - item.changed is sameas true
+ loop: "{{ update_theme_parameter_existing_user_result.results }}"
+
+- name: test - Update role_name parameter for existing user
+ community.zabbix.zabbix_user:
+ username: example1
+ name: example
+ surname: test
+ usrgrps:
+ - Guests
+ - Zabbix administrators
+ passwd: update_password
+ autologout: 500
+ refresh: 60
+ rows_per_page: 300
+ after_login_url: http://example.com
+ theme: dark-theme
+ role_name: "{{ item }}"
+ user_medias:
+ - mediatype: Email
+ sendto: example@example.com
+ period: 1-7,00:00-24:00
+ severity:
+ not_classified: false
+ information: true
+ warning: true
+ average: true
+ high: true
+ disaster: true
+ active: true
+ - mediatype: SMS
+ sendto: example@example.com
+ period: 1-5,01:00-23:00
+ severity:
+ not_classified: false
+ information: true
+ warning: true
+ average: false
+ high: true
+ disaster: true
+ active: true
+ loop:
+ - Guest role
+ - Admin role
+ register: update_type_parameter_existing_user_result
+
+- ansible.builtin.assert:
+ that:
+ - item.changed is sameas true
+ loop: "{{ update_type_parameter_existing_user_result.results }}"
+
+- name: test - Update lang parameter for existing user
+ community.zabbix.zabbix_user:
+ username: example1
+ name: example
+ surname: test
+ usrgrps:
+ - Guests
+ - Zabbix administrators
+ passwd: update_password
+ autologout: 500
+ refresh: 60
+ rows_per_page: 300
+ after_login_url: http://example.com
+ theme: dark-theme
+ role_name: Admin role
+ lang: en_US
+ user_medias:
+ - mediatype: Email
+ sendto: example@example.com
+ period: 1-7,00:00-24:00
+ severity:
+ not_classified: false
+ information: true
+ warning: true
+ average: true
+ high: true
+ disaster: true
+ active: true
+ - mediatype: SMS
+ sendto: example@example.com
+ period: 1-5,01:00-23:00
+ severity:
+ not_classified: false
+ information: true
+ warning: true
+ average: false
+ high: true
+ disaster: true
+ active: true
+ register: update_lang_parameter_existing_user_result
+
+- ansible.builtin.assert:
+ that:
+ - update_lang_parameter_existing_user_result.changed is sameas true
+
+- name: test - Update timezone parameter for existing user
+ community.zabbix.zabbix_user:
+ username: example1
+ name: example
+ surname: test
+ usrgrps:
+ - Guests
+ - Zabbix administrators
+ passwd: update_password
+ autologout: 500
+ refresh: 60
+ rows_per_page: 300
+ after_login_url: http://example.com
+ theme: dark-theme
+ role_name: Admin role
+ timezone: Asia/Tokyo
+ lang: en_US
+ user_medias:
+ - mediatype: Email
+ sendto: example@example.com
+ period: 1-7,00:00-24:00
+ severity:
+ not_classified: false
+ information: true
+ warning: true
+ average: true
+ high: true
+ disaster: true
+ active: true
+ - mediatype: SMS
+ sendto: example@example.com
+ period: 1-5,01:00-23:00
+ severity:
+ not_classified: false
+ information: true
+ warning: true
+ average: false
+ high: true
+ disaster: true
+ active: true
+ register: update_timezone_parameter_existing_user_result
+
+- ansible.builtin.assert:
+ that:
+ - update_timezone_parameter_existing_user_result.changed is sameas true
+
+- name: test - Update name and surname parameter for existing user
+ community.zabbix.zabbix_user:
+ username: example1
+ name: example2
+ surname: test2
+ usrgrps:
+ - Guests
+ - Zabbix administrators
+ passwd: update_password
+ autologout: 500
+ refresh: 60
+ rows_per_page: 300
+ after_login_url: http://example.com
+ theme: dark-theme
+ role_name: Admin role
+ timezone: Asia/Tokyo
+ lang: en_US
+ user_medias:
+ - mediatype: Email
+ sendto: example@example.com
+ period: 1-7,00:00-24:00
+ severity:
+ not_classified: false
+ information: true
+ warning: true
+ average: true
+ high: true
+ disaster: true
+ active: true
+ - mediatype: SMS
+ sendto: example@example.com
+ period: 1-5,01:00-23:00
+ severity:
+ not_classified: false
+ information: true
+ warning: true
+ average: false
+ high: true
+ disaster: true
+ active: true
+ register: update_name_and_surname_parameter_existing_user_result
+
+- ansible.builtin.assert:
+ that:
+ - update_name_and_surname_parameter_existing_user_result.changed is sameas true
+
+- name: test - Update lang parameter for existing user with check_mode and diff
+ community.zabbix.zabbix_user:
+ username: example1
+ name: example2
+ surname: test2
+ usrgrps:
+ - Guests
+ - Zabbix administrators
+ passwd: update_password
+ autologout: 500
+ refresh: 60
+ rows_per_page: 300
+ after_login_url: http://example.com
+ theme: dark-theme
+ role_name: Admin role
+ timezone: Asia/Tokyo
+ lang: fr_FR
+ user_medias:
+ - mediatype: Email
+ sendto: example@example.com
+ period: 1-7,00:00-24:00
+ severity:
+ not_classified: false
+ information: true
+ warning: true
+ average: true
+ high: true
+ disaster: true
+ active: true
+ - mediatype: SMS
+ sendto: example@example.com
+ period: 1-5,01:00-23:00
+ severity:
+ not_classified: false
+ information: true
+ warning: true
+ average: false
+ high: true
+ disaster: true
+ active: true
+ check_mode: true
+ diff: true
+ register: update_lang_parameter_existing_user_with_check_mode_diff_result
+
+- ansible.builtin.assert:
+ that:
+ - update_lang_parameter_existing_user_with_check_mode_diff_result.changed is sameas true
+
+- name: test - Update lang parameter for existing user
+ community.zabbix.zabbix_user:
+ username: example1
+ name: example2
+ surname: test2
+ usrgrps:
+ - Guests
+ - Zabbix administrators
+ passwd: update_password
+ autologout: 500
+ refresh: 60
+ rows_per_page: 300
+ after_login_url: http://example.com
+ theme: dark-theme
+ role_name: Admin role
+ timezone: Asia/Tokyo
+ lang: fr_FR
+ user_medias:
+ - mediatype: Email
+ sendto: example@example.com
+ period: 1-7,00:00-24:00
+ severity:
+ not_classified: false
+ information: true
+ warning: true
+ average: true
+ high: true
+ disaster: true
+ active: true
+ - mediatype: SMS
+ sendto: example@example.com
+ period: 1-5,01:00-23:00
+ severity:
+ not_classified: false
+ information: true
+ warning: true
+ average: false
+ high: true
+ disaster: true
+ active: true
+ register: update_lang_parameter_existing_user_result
+
+- ansible.builtin.assert:
+ that:
+ - update_lang_parameter_existing_user_result.changed is sameas true
+
+- name: test - Update lang parameter for existing user(again)
+ community.zabbix.zabbix_user:
+ username: example1
+ name: example2
+ surname: test2
+ usrgrps:
+ - Guests
+ - Zabbix administrators
+ passwd: update_password
+ autologout: 500
+ refresh: 60
+ rows_per_page: 300
+ after_login_url: http://example.com
+ theme: dark-theme
+ role_name: Admin role
+ timezone: Asia/Tokyo
+ lang: fr_FR
+ user_medias:
+ - mediatype: Email
+ sendto: example@example.com
+ period: 1-7,00:00-24:00
+ severity:
+ not_classified: false
+ information: true
+ warning: true
+ average: true
+ high: true
+ disaster: true
+ active: true
+ - mediatype: SMS
+ sendto: example@example.com
+ period: 1-5,01:00-23:00
+ severity:
+ not_classified: false
+ information: true
+ warning: true
+ average: false
+ high: true
+ disaster: true
+ active: true
+ register: update_lang_parameter_existing_user_result
+
+- ansible.builtin.assert:
+ that:
+ - not update_lang_parameter_existing_user_result.changed is sameas true
+
+# Parameter delete test from here from existing user
+- name: test - Delete user medias(SMS) for existing user with check_mode and diff
+ community.zabbix.zabbix_user:
+ username: example1
+ name: example2
+ surname: test2
+ usrgrps:
+ - Guests
+ - Zabbix administrators
+ passwd: update_password
+ autologout: 500
+ refresh: 60
+ rows_per_page: 300
+ after_login_url: http://example.com
+ theme: dark-theme
+ role_name: Admin role
+ timezone: Asia/Tokyo
+ lang: fr_FR
+ user_medias:
+ - mediatype: Email
+ sendto: example@example.com
+ period: 1-7,00:00-24:00
+ severity:
+ not_classified: false
+ information: true
+ warning: true
+ average: true
+ high: true
+ disaster: true
+ active: true
+ check_mode: true
+ diff: true
+ register: delete_user_medias_existing_user_result
+
+- ansible.builtin.assert:
+ that:
+ - delete_user_medias_existing_user_result.changed is sameas true
+
+- name: test - Delete user medias(SMS) for existing user
+ community.zabbix.zabbix_user:
+ username: example1
+ name: example2
+ surname: test2
+ usrgrps:
+ - Guests
+ - Zabbix administrators
+ passwd: update_password
+ autologout: 500
+ refresh: 60
+ rows_per_page: 300
+ after_login_url: http://example.com
+ theme: dark-theme
+ role_name: Admin role
+ timezone: Asia/Tokyo
+ lang: fr_FR
+ user_medias:
+ - mediatype: Email
+ sendto: example@example.com
+ period: 1-7,00:00-24:00
+ severity:
+ not_classified: false
+ information: true
+ warning: true
+ average: true
+ high: true
+ disaster: true
+ active: true
+ register: delete_user_medias_existing_user_result
+
+- ansible.builtin.assert:
+ that:
+ - delete_user_medias_existing_user_result.changed is sameas true
+
+- name: test - Delete user group for existing user
+ community.zabbix.zabbix_user:
+ username: example1
+ name: example2
+ surname: test2
+ usrgrps:
+ - Zabbix administrators
+ passwd: update_password
+ autologout: 500
+ refresh: 60
+ rows_per_page: 300
+ after_login_url: http://example.com
+ theme: dark-theme
+ role_name: Admin role
+ timezone: Asia/Tokyo
+ lang: fr_FR
+ user_medias:
+ - mediatype: Email
+ sendto: example@example.com
+ period: 1-7,00:00-24:00
+ severity:
+ not_classified: false
+ information: true
+ warning: true
+ average: true
+ high: true
+ disaster: true
+ active: true
+ register: delete_user_group_existing_user_result
+
+- ansible.builtin.assert:
+ that:
+ - delete_user_group_existing_user_result.changed is sameas true
+
+- name: test - optional user_medias
+ community.zabbix.zabbix_user:
+ username: example1
+ name: example2
+ surname: test2
+ usrgrps:
+ - Zabbix administrators
+ passwd: update_password
+ autologout: 500
+ refresh: 60
+ rows_per_page: 300
+ after_login_url: http://example.com
+ theme: dark-theme
+ role_name: Admin role
+ timezone: Asia/Tokyo
+ lang: fr_FR
+ register: update_user_optional_user_medias_existing_user_result
+
+- ansible.builtin.assert:
+ that:
+ - update_user_optional_user_medias_existing_user_result.changed is sameas False
+
+- name: test - Delete existing user with check_mode and diff
+ community.zabbix.zabbix_user:
+ username: example1
+ state: absent
+ check_mode: true
+ diff: true
+ register: delete_existing_user_result
+
+- ansible.builtin.assert:
+ that:
+ - delete_existing_user_result.changed is sameas true
+
+- name: test - Delete existing user
+ community.zabbix.zabbix_user:
+ username: example1
+ state: absent
+ register: delete_existing_user_result
+
+- ansible.builtin.assert:
+ that:
+ - delete_existing_user_result.changed is sameas true
+
+- name: test - Delete existing user(again)
+ community.zabbix.zabbix_user:
+ username: example1
+ state: absent
+ register: delete_existing_user_result
+
+- ansible.builtin.assert:
+ that:
+ - not delete_existing_user_result.changed is sameas true
+
+- name: test prepare - Create LDAP user group
+ community.zabbix.zabbix_usergroup:
+ name: testLDAPgrp
+ gui_access: LDAP
+ register: zbxuser_create_ldap_group
+
+- ansible.builtin.assert:
+ that:
+ - zbxuser_create_ldap_group.changed is sameas True
+
+- name: test - Create new password-less user without LDAP group (fail)
+ community.zabbix.zabbix_user:
+ username: example2username
+ name: example2
+ surname: testldap
+ usrgrps:
+ - Guests
+ register: create_zabbix_user_ldap_fail
+ ignore_errors: true
+
+- ansible.builtin.assert:
+ that:
+ - create_zabbix_user_ldap_fail.failed is sameas True
+
+- name: test - Create new password-less user as member in LDAP group
+ community.zabbix.zabbix_user:
+ username: example2username
+ name: example2
+ surname: testldap
+ usrgrps:
+ - testLDAPgrp
+ register: create_zabbix_user_ldap_result
+
+- ansible.builtin.assert:
+ that:
+ - create_zabbix_user_ldap_result.changed is sameas True
+
+- name: test - Create new password-less user as member in LDAP group (again)
+ community.zabbix.zabbix_user:
+ username: example2username
+ name: example2
+ surname: testldap
+ usrgrps:
+ - testLDAPgrp
+ register: create_zabbix_user_ldap_result
+
+- ansible.builtin.assert:
+ that:
+ - create_zabbix_user_ldap_result.changed is sameas False
+
+- name: test - Delete existing user
+ community.zabbix.zabbix_user:
+ username: example2username
+ state: absent
+ register: delete_existing_user_result
+
+- ansible.builtin.assert:
+ that:
+ - delete_existing_user_result.changed is sameas true
+
+# The tests are to check the patch for PR hasn't a problem.
+# https://github.com/ansible-collections/community.zabbix/pull/382
+- name: test - Create a zabbix user with minimum parameters
+ community.zabbix.zabbix_user:
+ username: example2
+ usrgrps:
+ - Guests
+ passwd: G$jd_79!jw
+ role_name: "User role"
+ register: create_zabbix_user_with_minimum_params_result
+
+- ansible.builtin.assert:
+ that:
+ - create_zabbix_user_with_minimum_params_result.changed is sameas true
+
+- name: test - Create a zabbix user with minimum parameters(again)
+ community.zabbix.zabbix_user:
+ username: example2
+ usrgrps:
+ - Guests
+ passwd: G$jd_79!jw
+ role_name: "User role"
+ register: create_zabbix_user_with_minimum_params_result
+
+- ansible.builtin.assert:
+ that:
+ - create_zabbix_user_with_minimum_params_result.changed is sameas false
+
+- name: test - Update the parameters without role_name
+ community.zabbix.zabbix_user:
+ username: example2
+ name: example2
+ surname: test
+ usrgrps:
+ - Guests
+ passwd: G$jd_79!jw
+ register: update_params_without_role_name_result
+
+- ansible.builtin.assert:
+ that:
+ - update_params_without_role_name_result.changed is sameas true
+
+- name: test - Update the parameters without role_name(again)
+ community.zabbix.zabbix_user:
+ username: example2
+ name: example2
+ surname: test
+ usrgrps:
+ - Guests
+ passwd: G$jd_79!jw
+ register: update_params_without_role_name_result
+
+- ansible.builtin.assert:
+ that:
+ - update_params_without_role_name_result.changed is sameas false
+
+- name: test - Add user medias(Email) as list to existing user
+ community.zabbix.zabbix_user:
+ username: example2
+ name: example2
+ surname: test
+ usrgrps:
+ - Guests
+ passwd: G$jd_79!jw
+ user_medias:
+ - mediatype: Email
+ sendto:
+ - example@example.com
+ - example1@example.com
+ period: 1-7,00:00-24:00
+ severity:
+ not_classified: false
+ information: true
+ warning: true
+ average: true
+ high: true
+ disaster: true
+ active: true
+ register: add_user_email_media_as_list_to_existing_user_result
+
+- ansible.builtin.assert:
+ that:
+ - add_user_email_media_as_list_to_existing_user_result.changed is sameas true
+
+- name: test - Add user medias(Email) as list to existing user(again)
+ community.zabbix.zabbix_user:
+ username: example2
+ name: example2
+ surname: test
+ usrgrps:
+ - Guests
+ passwd: G$jd_79!jw
+ user_medias:
+ - mediatype: Email
+ sendto:
+ - example@example.com
+ - example1@example.com
+ period: 1-7,00:00-24:00
+ severity:
+ not_classified: false
+ information: true
+ warning: true
+ average: true
+ high: true
+ disaster: true
+ active: true
+ register: add_user_email_media_as_list_to_existing_user_result
+
+- ansible.builtin.assert:
+ that:
+ - add_user_email_media_as_list_to_existing_user_result.changed is sameas false
+
+- name: test - Delete existing user
+ community.zabbix.zabbix_user:
+ username: example2
+ state: absent
+
+- name: test prepare - Delete LDAP user group
+ community.zabbix.zabbix_usergroup:
+ name: testLDAPgrp
+ state: absent
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_directory/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_directory/tasks/main.yml
index 6c697a2e5..e4cc87d28 100644
--- a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_directory/tasks/main.yml
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_directory/tasks/main.yml
@@ -3,8 +3,8 @@
- include_tasks: zabbix_user_directory_tests.yml
always:
- - name: Cleanup
- zabbix_user_directory:
- name: TestUserDirectory
- state: absent
- ignore_errors: true
+ - name: Cleanup
+ community.zabbix.zabbix_user_directory:
+ name: TestUserDirectory
+ state: absent
+ ignore_errors: true
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_directory/tasks/zabbix_user_directory_tests.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_directory/tasks/zabbix_user_directory_tests.yml
index db057a5d0..6488b80e5 100644
--- a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_directory/tasks/zabbix_user_directory_tests.yml
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_directory/tasks/zabbix_user_directory_tests.yml
@@ -10,97 +10,97 @@
name: TestUserDirectory
block:
- - name: test - create new user directory in check mode
- zabbix_user_directory:
- host: 'test.com'
- port: 389
- base_dn: 'ou=Users,dc=example,dc=org'
- search_attribute: 'uid'
- check_mode: true
- register: directory_check_result
-
- - assert:
- that: directory_check_result.changed is sameas True
-
- - name: test - attempt to create new user directory with not all mandatory parameters
- zabbix_user_directory:
- host: 'test.com'
- port: 389
- ignore_errors: true
- register: directory_expect_fail_result
-
- - assert:
- that: directory_expect_fail_result.failed is sameas True
-
- - name: test - create new user directory withoud bind_password
- zabbix_user_directory:
- host: 'test.com'
- port: 389
- base_dn: 'ou=Users,dc=example,dc=org'
- search_attribute: 'uid'
- register: directory_result
-
- - assert:
- that: directory_result.changed is sameas True
-
- - name: test - create new user directory without bind_password again
- zabbix_user_directory:
- host: 'test.com'
- port: 389
- base_dn: 'ou=Users,dc=example,dc=org'
- search_attribute: 'uid'
- register: directory_again_result
-
- - assert:
- that: directory_again_result.changed is sameas False
-
- - name: test - delete user directory
- zabbix_user_directory:
- state: absent
- register: directory_delete_result
-
- - assert:
- that: directory_delete_result.changed is sameas True
-
- - name: test - create new user directory with bind_password
- zabbix_user_directory:
- host: 'test.com'
- port: 389
- base_dn: 'ou=Users,dc=example,dc=org'
- search_attribute: 'uid'
- bind_password: 'password'
- register: directory_result
-
- - assert:
- that: directory_result.changed is sameas True
-
- - name: test - create new user directory with bind_password again
- zabbix_user_directory:
- host: 'test.com'
- port: 389
- base_dn: 'ou=Users,dc=example,dc=org'
- search_attribute: 'uid'
- bind_password: 'password'
- register: directory_again_result
-
- - assert:
- that: directory_again_result.changed is sameas True
-
- - name: test - update only host parameter in user directory
- zabbix_user_directory:
- host: 'test.ca'
- register: directory_update_result
-
- - assert:
- that: directory_update_result.changed is sameas True
-
- - name: test - update only host parameter in user directory again
- zabbix_user_directory:
- host: 'test.ca'
- register: directory_update_again_result
-
- - assert:
- that: directory_update_again_result.changed is sameas False
+ - name: test - create new user directory in check mode
+ community.zabbix.zabbix_user_directory:
+ host: "test.com"
+ port: 389
+ base_dn: "ou=Users,dc=example,dc=org"
+ search_attribute: "uid"
+ check_mode: true
+ register: directory_check_result
+
+ - ansible.builtin.assert:
+ that: directory_check_result.changed is sameas True
+
+ - name: test - attempt to create new user directory with not all mandatory parameters
+ community.zabbix.zabbix_user_directory:
+ host: "test.com"
+ port: 389
+ ignore_errors: true
+ register: directory_expect_fail_result
+
+ - ansible.builtin.assert:
+ that: directory_expect_fail_result.failed is sameas True
+
+ - name: test - create new user directory withoud bind_password
+ community.zabbix.zabbix_user_directory:
+ host: "test.com"
+ port: 389
+ base_dn: "ou=Users,dc=example,dc=org"
+ search_attribute: "uid"
+ register: directory_result
+
+ - ansible.builtin.assert:
+ that: directory_result.changed is sameas True
+
+ - name: test - create new user directory without bind_password again
+ community.zabbix.zabbix_user_directory:
+ host: "test.com"
+ port: 389
+ base_dn: "ou=Users,dc=example,dc=org"
+ search_attribute: "uid"
+ register: directory_again_result
+
+ - ansible.builtin.assert:
+ that: directory_again_result.changed is sameas False
+
+ - name: test - delete user directory
+ community.zabbix.zabbix_user_directory:
+ state: absent
+ register: directory_delete_result
+
+ - ansible.builtin.assert:
+ that: directory_delete_result.changed is sameas True
+
+ - name: test - create new user directory with bind_password
+ community.zabbix.zabbix_user_directory:
+ host: "test.com"
+ port: 389
+ base_dn: "ou=Users,dc=example,dc=org"
+ search_attribute: "uid"
+ bind_password: "password"
+ register: directory_result
+
+ - ansible.builtin.assert:
+ that: directory_result.changed is sameas True
+
+ - name: test - create new user directory with bind_password again
+ community.zabbix.zabbix_user_directory:
+ host: "test.com"
+ port: 389
+ base_dn: "ou=Users,dc=example,dc=org"
+ search_attribute: "uid"
+ bind_password: "password"
+ register: directory_again_result
+
+ - ansible.builtin.assert:
+ that: directory_again_result.changed is sameas True
+
+ - name: test - update only host parameter in user directory
+ community.zabbix.zabbix_user_directory:
+ host: "test.ca"
+ register: directory_update_result
+
+ - ansible.builtin.assert:
+ that: directory_update_result.changed is sameas True
+
+ - name: test - update only host parameter in user directory again
+ community.zabbix.zabbix_user_directory:
+ host: "test.ca"
+ register: directory_update_again_result
+
+ - ansible.builtin.assert:
+ that: directory_update_again_result.changed is sameas False
when: zabbix_version is version('6.4', '<')
@@ -111,327 +111,327 @@
name: TestUserDirectory
block:
- - name: test - create new LDAP user directory in check mode
- zabbix_user_directory:
- idp_type: ldap
- host: 'test.com'
- port: 389
- base_dn: 'ou=Users,dc=example,dc=org'
- search_attribute: 'uid'
- check_mode: true
- register: directory_check_result
-
- - assert:
- that: directory_check_result.changed is sameas True
-
- - name: test - attempt to create new LDAP user directory with not all mandatory parameters
- zabbix_user_directory:
- idp_type: ldap
- host: 'test.com'
- port: 389
- ignore_errors: true
- register: directory_expect_fail_result
-
- - assert:
- that: directory_expect_fail_result.failed is sameas True
-
- - name: test - create new LDAP user directory withoud bind_password
- zabbix_user_directory:
- idp_type: ldap
- host: 'test.com'
- port: 389
- base_dn: 'ou=Users,dc=example,dc=org'
- search_attribute: 'uid'
- register: directory_result
-
- - assert:
- that: directory_result.changed is sameas True
-
- - name: test - create new LDAP user directory without bind_password again
- zabbix_user_directory:
- idp_type: ldap
- host: 'test.com'
- port: 389
- base_dn: 'ou=Users,dc=example,dc=org'
- search_attribute: 'uid'
- register: directory_again_result
-
- - assert:
- that: directory_again_result.changed is sameas False
-
- - name: test - delete LDAP user directory
- zabbix_user_directory:
- state: absent
- register: directory_delete_result
-
- - assert:
- that: directory_delete_result.changed is sameas True
-
- - name: test - create new LDAP user directory with bind_password
- zabbix_user_directory:
- idp_type: ldap
- host: 'test.com'
- port: 389
- base_dn: 'ou=Users,dc=example,dc=org'
- search_attribute: 'uid'
- bind_password: 'password'
- register: directory_result
-
- - assert:
- that: directory_result.changed is sameas True
-
- - name: test - create new LDAP user directory with bind_password again
- zabbix_user_directory:
- idp_type: ldap
- host: 'test.com'
- port: 389
- base_dn: 'ou=Users,dc=example,dc=org'
- search_attribute: 'uid'
- bind_password: 'password'
- register: directory_again_result
-
- - assert:
- that: directory_again_result.changed is sameas True
-
- - name: test - update host parameter in LDAP user directory
- zabbix_user_directory:
- idp_type: ldap
- host: 'test.ca'
- port: 389
- base_dn: 'ou=Users,dc=example,dc=org'
- search_attribute: 'uid'
- register: directory_update_result
-
- - assert:
- that: directory_update_result.changed is sameas True
-
- - name: test - update host parameter in LDAP user directory again
- zabbix_user_directory:
- idp_type: ldap
- host: 'test.ca'
- port: 389
- base_dn: 'ou=Users,dc=example,dc=org'
- search_attribute: 'uid'
- register: directory_update_again_result
-
- - assert:
- that: directory_update_again_result.changed is sameas False
-
- - name: test - add media type mapping with non-existing media type
- zabbix_user_directory:
- idp_type: ldap
- host: 'test.ca'
- port: 389
- base_dn: 'ou=Users,dc=example,dc=org'
- search_attribute: 'uid'
- provision_status: True
- provision_media:
- - name: Media1
- mediatype: EmailX
- attribute: email
- provision_groups:
- - name: idpname1
- role: Guest role
- user_groups:
- - Guests
- ignore_errors: True
- register: directory_update_media_fail_result
-
- - assert:
- that: directory_update_media_fail_result.failed is sameas True
-
- - name: test - add mappings
- zabbix_user_directory:
- idp_type: ldap
- host: 'test.ca'
- port: 389
- base_dn: 'ou=Users,dc=example,dc=org'
- search_attribute: 'uid'
- provision_status: True
- group_name: cn
- group_basedn: ou=Group,dc=example,dc=org
- group_member: member
- user_ref_attr: uid
- group_filter: '(member=uid=%{ref},ou=Users,dc=example,dc=com)'
- user_username: first_name
- user_lastname: last_name
- provision_media:
- - name: Media1
- mediatype: Email
- attribute: email1
- provision_groups:
- - name: idpname1
- role: Guest role
- user_groups:
- - Guests
- register: directory_update_media_result
-
- - assert:
- that: directory_update_media_result.changed is sameas True
-
- - name: test - add mappings again
- zabbix_user_directory:
- idp_type: ldap
- host: 'test.ca'
- port: 389
- base_dn: 'ou=Users,dc=example,dc=org'
- search_attribute: 'uid'
- provision_status: True
- group_name: cn
- group_basedn: ou=Group,dc=example,dc=org
- group_member: member
- user_ref_attr: uid
- group_filter: '(member=uid=%{ref},ou=Users,dc=example,dc=com)'
- user_username: first_name
- user_lastname: last_name
- provision_media:
- - name: Media1
- mediatype: Email
- attribute: email1
- provision_groups:
- - name: idpname1
- role: Guest role
- user_groups:
- - Guests
- register: directory_update_media_again_result
-
- - assert:
- that: directory_update_media_again_result.changed is sameas False
-
- - name: test - delete LDAP user directory
- zabbix_user_directory:
- state: absent
-
- - name: test - create new SAML user directory in check mode
- zabbix_user_directory:
- idp_type: saml
- idp_entityid: http://okta.com/xxxxx
- sp_entityid: zabbix
- sso_url: http://xxxx.okta.com/app/xxxxxx_123dhu8o3
- username_attribute: usrEmail
- check_mode: true
- register: directory_check_result
-
- - assert:
- that: directory_check_result.changed is sameas True
-
- - name: test - attempt to create new SAML user directory with not all mandatory parameters
- zabbix_user_directory:
- idp_type: saml
- ignore_errors: true
- register: directory_expect_fail_result
-
- - assert:
- that: directory_expect_fail_result.failed is sameas True
-
- - name: test - create new SAML user directory
- zabbix_user_directory:
- idp_type: saml
- idp_entityid: http://okta.com/xxxxx
- sp_entityid: zabbix
- sso_url: http://xxxx.okta.com/app/xxxxxx_123dhu8o3
- username_attribute: usrEmail
- register: directory_create_result
-
- - assert:
- that: directory_create_result.changed is sameas True
-
- - name: test - update SAML user directory with all optional parameters
- zabbix_user_directory:
- idp_type: saml
- idp_entityid: http://okta.com/xxxxx
- sp_entityid: zabbix
- sso_url: http://xxxx.okta.com/app/xxxxxx_123dhu8o3
- username_attribute: usrEmail
- slo_url: http://yyyy.okta.com
- nameid_format: 'urn:oasis'
- scim_status: true
- encrypt_nameid: true
- encrypt_assertions: true
- sign_messages: true
- sign_assertions: true
- sign_authn_requests: true
- sign_logout_requests: true
- sign_logout_responses: true
- register: directory_create_all_result
-
- - assert:
- that: directory_create_all_result.changed is sameas True
-
- - name: test - update SAML user directory with all optional parameters again
- zabbix_user_directory:
- idp_type: saml
- idp_entityid: http://okta.com/xxxxx
- sp_entityid: zabbix
- sso_url: http://xxxx.okta.com/app/xxxxxx_123dhu8o3
- username_attribute: usrEmail
- slo_url: http://yyyy.okta.com
- nameid_format: 'urn:oasis'
- scim_status: true
- encrypt_nameid: true
- encrypt_assertions: true
- sign_messages: true
- sign_assertions: true
- sign_authn_requests: true
- sign_logout_requests: true
- sign_logout_responses: true
- register: directory_create_all_again_result
-
- - assert:
- that: directory_create_all_again_result.changed is sameas False
-
- - name: test - delete SAML user directory
- zabbix_user_directory:
- state: absent
-
- - name: test - create new SAML user directory with mappings
- zabbix_user_directory:
- idp_type: saml
- idp_entityid: http://okta.com/xxxxx
- sp_entityid: zabbix
- sso_url: http://xxxx.okta.com/app/xxxxxx_123dhu8o3
- username_attribute: usrEmail
- provision_status: True
- group_name: cn
- user_username: first_name
- user_lastname: last_name
- provision_media:
- - name: Media1
- mediatype: Email
- attribute: email1
- provision_groups:
- - name: idpname1
- role: Guest role
- user_groups:
- - Guests
- register: directory_create_mappings_result
-
- - assert:
- that: directory_create_mappings_result.changed is sameas True
-
- - name: test - create new SAML user directory with mappings again
- zabbix_user_directory:
- idp_type: saml
- idp_entityid: http://okta.com/xxxxx
- sp_entityid: zabbix
- sso_url: http://xxxx.okta.com/app/xxxxxx_123dhu8o3
- username_attribute: usrEmail
- provision_status: True
- group_name: cn
- user_username: first_name
- user_lastname: last_name
- provision_media:
- - name: Media1
- mediatype: Email
- attribute: email1
- provision_groups:
- - name: idpname1
- role: Guest role
- user_groups:
- - Guests
- register: directory_create_mappings_again_result
-
- - assert:
- that: directory_create_mappings_again_result.changed is sameas False
+ - name: test - create new LDAP user directory in check mode
+ community.zabbix.zabbix_user_directory:
+ idp_type: ldap
+ host: "test.com"
+ port: 389
+ base_dn: "ou=Users,dc=example,dc=org"
+ search_attribute: "uid"
+ check_mode: true
+ register: directory_check_result
+
+ - ansible.builtin.assert:
+ that: directory_check_result.changed is sameas True
+
+ - name: test - attempt to create new LDAP user directory with not all mandatory parameters
+ community.zabbix.zabbix_user_directory:
+ idp_type: ldap
+ host: "test.com"
+ port: 389
+ ignore_errors: true
+ register: directory_expect_fail_result
+
+ - ansible.builtin.assert:
+ that: directory_expect_fail_result.failed is sameas True
+
+ - name: test - create new LDAP user directory withoud bind_password
+ community.zabbix.zabbix_user_directory:
+ idp_type: ldap
+ host: "test.com"
+ port: 389
+ base_dn: "ou=Users,dc=example,dc=org"
+ search_attribute: "uid"
+ register: directory_result
+
+ - ansible.builtin.assert:
+ that: directory_result.changed is sameas True
+
+ - name: test - create new LDAP user directory without bind_password again
+ community.zabbix.zabbix_user_directory:
+ idp_type: ldap
+ host: "test.com"
+ port: 389
+ base_dn: "ou=Users,dc=example,dc=org"
+ search_attribute: "uid"
+ register: directory_again_result
+
+ - ansible.builtin.assert:
+ that: directory_again_result.changed is sameas False
+
+ - name: test - delete LDAP user directory
+ community.zabbix.zabbix_user_directory:
+ state: absent
+ register: directory_delete_result
+
+ - ansible.builtin.assert:
+ that: directory_delete_result.changed is sameas True
+
+ - name: test - create new LDAP user directory with bind_password
+ community.zabbix.zabbix_user_directory:
+ idp_type: ldap
+ host: "test.com"
+ port: 389
+ base_dn: "ou=Users,dc=example,dc=org"
+ search_attribute: "uid"
+ bind_password: "password"
+ register: directory_result
+
+ - ansible.builtin.assert:
+ that: directory_result.changed is sameas True
+
+ - name: test - create new LDAP user directory with bind_password again
+ community.zabbix.zabbix_user_directory:
+ idp_type: ldap
+ host: "test.com"
+ port: 389
+ base_dn: "ou=Users,dc=example,dc=org"
+ search_attribute: "uid"
+ bind_password: "password"
+ register: directory_again_result
+
+ - ansible.builtin.assert:
+ that: directory_again_result.changed is sameas True
+
+ - name: test - update host parameter in LDAP user directory
+ community.zabbix.zabbix_user_directory:
+ idp_type: ldap
+ host: "test.ca"
+ port: 389
+ base_dn: "ou=Users,dc=example,dc=org"
+ search_attribute: "uid"
+ register: directory_update_result
+
+ - ansible.builtin.assert:
+ that: directory_update_result.changed is sameas True
+
+ - name: test - update host parameter in LDAP user directory again
+ community.zabbix.zabbix_user_directory:
+ idp_type: ldap
+ host: "test.ca"
+ port: 389
+ base_dn: "ou=Users,dc=example,dc=org"
+ search_attribute: "uid"
+ register: directory_update_again_result
+
+ - ansible.builtin.assert:
+ that: directory_update_again_result.changed is sameas False
+
+ - name: test - add media type mapping with non-existing media type
+ community.zabbix.zabbix_user_directory:
+ idp_type: ldap
+ host: "test.ca"
+ port: 389
+ base_dn: "ou=Users,dc=example,dc=org"
+ search_attribute: "uid"
+ provision_status: True
+ provision_media:
+ - name: Media1
+ mediatype: EmailX
+ attribute: email
+ provision_groups:
+ - name: idpname1
+ role: Guest role
+ user_groups:
+ - Guests
+ ignore_errors: True
+ register: directory_update_media_fail_result
+
+ - ansible.builtin.assert:
+ that: directory_update_media_fail_result.failed is sameas True
+
+ - name: test - add mappings
+ community.zabbix.zabbix_user_directory:
+ idp_type: ldap
+ host: "test.ca"
+ port: 389
+ base_dn: "ou=Users,dc=example,dc=org"
+ search_attribute: "uid"
+ provision_status: True
+ group_name: cn
+ group_basedn: ou=Group,dc=example,dc=org
+ group_member: member
+ user_ref_attr: uid
+ group_filter: "(member=uid=%{ref},ou=Users,dc=example,dc=com)"
+ user_username: first_name
+ user_lastname: last_name
+ provision_media:
+ - name: Media1
+ mediatype: Email
+ attribute: email1
+ provision_groups:
+ - name: idpname1
+ role: Guest role
+ user_groups:
+ - Guests
+ register: directory_update_media_result
+
+ - ansible.builtin.assert:
+ that: directory_update_media_result.changed is sameas True
+
+ - name: test - add mappings again
+ community.zabbix.zabbix_user_directory:
+ idp_type: ldap
+ host: "test.ca"
+ port: 389
+ base_dn: "ou=Users,dc=example,dc=org"
+ search_attribute: "uid"
+ provision_status: True
+ group_name: cn
+ group_basedn: ou=Group,dc=example,dc=org
+ group_member: member
+ user_ref_attr: uid
+ group_filter: "(member=uid=%{ref},ou=Users,dc=example,dc=com)"
+ user_username: first_name
+ user_lastname: last_name
+ provision_media:
+ - name: Media1
+ mediatype: Email
+ attribute: email1
+ provision_groups:
+ - name: idpname1
+ role: Guest role
+ user_groups:
+ - Guests
+ register: directory_update_media_again_result
+
+ - ansible.builtin.assert:
+ that: directory_update_media_again_result.changed is sameas False
+
+ - name: test - delete LDAP user directory
+ community.zabbix.zabbix_user_directory:
+ state: absent
+
+ - name: test - create new SAML user directory in check mode
+ community.zabbix.zabbix_user_directory:
+ idp_type: saml
+ idp_entityid: http://okta.com/xxxxx
+ sp_entityid: zabbix
+ sso_url: http://xxxx.okta.com/app/xxxxxx_123dhu8o3
+ username_attribute: usrEmail
+ check_mode: true
+ register: directory_check_result
+
+ - ansible.builtin.assert:
+ that: directory_check_result.changed is sameas True
+
+ - name: test - attempt to create new SAML user directory with not all mandatory parameters
+ community.zabbix.zabbix_user_directory:
+ idp_type: saml
+ ignore_errors: true
+ register: directory_expect_fail_result
+
+ - ansible.builtin.assert:
+ that: directory_expect_fail_result.failed is sameas True
+
+ - name: test - create new SAML user directory
+ community.zabbix.zabbix_user_directory:
+ idp_type: saml
+ idp_entityid: http://okta.com/xxxxx
+ sp_entityid: zabbix
+ sso_url: http://xxxx.okta.com/app/xxxxxx_123dhu8o3
+ username_attribute: usrEmail
+ register: directory_create_result
+
+ - ansible.builtin.assert:
+ that: directory_create_result.changed is sameas True
+
+ - name: test - update SAML user directory with all optional parameters
+ community.zabbix.zabbix_user_directory:
+ idp_type: saml
+ idp_entityid: http://okta.com/xxxxx
+ sp_entityid: zabbix
+ sso_url: http://xxxx.okta.com/app/xxxxxx_123dhu8o3
+ username_attribute: usrEmail
+ slo_url: http://yyyy.okta.com
+ nameid_format: "urn:oasis"
+ scim_status: true
+ encrypt_nameid: true
+ encrypt_assertions: true
+ sign_messages: true
+ sign_assertions: true
+ sign_authn_requests: true
+ sign_logout_requests: true
+ sign_logout_responses: true
+ register: directory_create_all_result
+
+ - ansible.builtin.assert:
+ that: directory_create_all_result.changed is sameas True
+
+ - name: test - update SAML user directory with all optional parameters again
+ community.zabbix.zabbix_user_directory:
+ idp_type: saml
+ idp_entityid: http://okta.com/xxxxx
+ sp_entityid: zabbix
+ sso_url: http://xxxx.okta.com/app/xxxxxx_123dhu8o3
+ username_attribute: usrEmail
+ slo_url: http://yyyy.okta.com
+ nameid_format: "urn:oasis"
+ scim_status: true
+ encrypt_nameid: true
+ encrypt_assertions: true
+ sign_messages: true
+ sign_assertions: true
+ sign_authn_requests: true
+ sign_logout_requests: true
+ sign_logout_responses: true
+ register: directory_create_all_again_result
+
+ - ansible.builtin.assert:
+ that: directory_create_all_again_result.changed is sameas False
+
+ - name: test - delete SAML user directory
+ community.zabbix.zabbix_user_directory:
+ state: absent
+
+ - name: test - create new SAML user directory with mappings
+ community.zabbix.zabbix_user_directory:
+ idp_type: saml
+ idp_entityid: http://okta.com/xxxxx
+ sp_entityid: zabbix
+ sso_url: http://xxxx.okta.com/app/xxxxxx_123dhu8o3
+ username_attribute: usrEmail
+ provision_status: True
+ group_name: cn
+ user_username: first_name
+ user_lastname: last_name
+ provision_media:
+ - name: Media1
+ mediatype: Email
+ attribute: email1
+ provision_groups:
+ - name: idpname1
+ role: Guest role
+ user_groups:
+ - Guests
+ register: directory_create_mappings_result
+
+ - ansible.builtin.assert:
+ that: directory_create_mappings_result.changed is sameas True
+
+ - name: test - create new SAML user directory with mappings again
+ community.zabbix.zabbix_user_directory:
+ idp_type: saml
+ idp_entityid: http://okta.com/xxxxx
+ sp_entityid: zabbix
+ sso_url: http://xxxx.okta.com/app/xxxxxx_123dhu8o3
+ username_attribute: usrEmail
+ provision_status: True
+ group_name: cn
+ user_username: first_name
+ user_lastname: last_name
+ provision_media:
+ - name: Media1
+ mediatype: Email
+ attribute: email1
+ provision_groups:
+ - name: idpname1
+ role: Guest role
+ user_groups:
+ - Guests
+ register: directory_create_mappings_again_result
+
+ - ansible.builtin.assert:
+ that: directory_create_mappings_again_result.changed is sameas False
when: zabbix_version is version('6.4', '>=')
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_info/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_info/tasks/main.yml
index 7228e12eb..1f1862586 100644
--- a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_info/tasks/main.yml
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_info/tasks/main.yml
@@ -1,170 +1,94 @@
---
-# New user create test from here
-- when: zabbix_version is version('5.4', '<')
- block:
- - name: test - Create a new Zabbix user
- zabbix_user:
- alias: example
- name: user name
- surname: user surname
- usrgrps:
- - Guests
- - Disabled
- passwd: G$jd_79!jw
- lang: en_US
- theme: blue-theme
- autologin: false
- autologout: '0'
- refresh: '30'
- rows_per_page: '200'
- after_login_url: ''
- user_medias:
- - mediatype: Email
- sendto: example@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: false
- type: Zabbix super admin
- state: present
- register: create_zabbix_user_result
-
- - assert:
- that:
- - create_zabbix_user_result.changed is sameas true
-
- - name: test - Set definition_of_results variable of Zabbix 5.0 and lower
- set_fact:
- definition_of_results:
- - get_user_info_result[user_info_key].alias == "example"
- - get_user_info_result[user_info_key].autologin is defined
- - get_user_info_result[user_info_key].autologout is defined
- - get_user_info_result[user_info_key].lang is defined
- - get_user_info_result[user_info_key].medias.0.active is defined
- - get_user_info_result[user_info_key].medias.0.mediaid is defined
- - get_user_info_result[user_info_key].medias.0.period is defined
- - get_user_info_result[user_info_key].medias.0.sendto is defined
- - get_user_info_result[user_info_key].medias.0.severity is defined
- - get_user_info_result[user_info_key].medias.0.userid is defined
- - get_user_info_result[user_info_key].name is defined
- - get_user_info_result[user_info_key].refresh is defined
- - get_user_info_result[user_info_key].rows_per_page is defined
- - get_user_info_result[user_info_key].surname is defined
- - get_user_info_result[user_info_key].theme is defined
- - get_user_info_result[user_info_key].type is defined
- - get_user_info_result[user_info_key].url is defined
- - get_user_info_result[user_info_key].userid is defined
- - get_user_info_result[user_info_key].users_status is defined
- - get_user_info_result[user_info_key].usrgrps | length == 2
- - get_user_info_result[user_info_key].usrgrps.0.debug_mode is defined
- - get_user_info_result[user_info_key].usrgrps.0.gui_access is defined
- - get_user_info_result[user_info_key].usrgrps.0.name is defined
- - get_user_info_result[user_info_key].usrgrps.0.users_status is defined
- - get_user_info_result[user_info_key].usrgrps.0.usrgrpid is defined
- - get_user_info_result[user_info_key].usrgrps.1.debug_mode is defined
- - get_user_info_result[user_info_key].usrgrps.1.gui_access is defined
- - get_user_info_result[user_info_key].usrgrps.1.name is defined
- - get_user_info_result[user_info_key].usrgrps.1.users_status is defined
- - get_user_info_result[user_info_key].usrgrps.1.usrgrpid is defined
-
-- when: zabbix_version is version('5.4', '>=')
- block:
- - name: test - Create a new Zabbix user
- zabbix_user:
- alias: example
- name: user name
- surname: user surname
- usrgrps:
- - Guests
- - Disabled
- passwd: G$jd_79!jw
- lang: en_US
- theme: blue-theme
- autologin: false
- autologout: '0'
- refresh: '30'
- rows_per_page: '200'
- after_login_url: ''
- user_medias:
- - mediatype: Email
- sendto: example@example.com
- period: 1-7,00:00-24:00
- severity:
- not_classified: false
- information: true
- warning: true
- average: true
- high: true
- disaster: true
- active: false
- role_name: Super admin role
- timezone: Asia/Tokyo
- state: present
- register: create_zabbix_user_result
+- name: test - Create a new Zabbix user
+ community.zabbix.zabbix_user:
+ username: example
+ name: user name
+ surname: user surname
+ usrgrps:
+ - Guests
+ - Disabled
+ passwd: G$jd_79!jw
+ lang: en_US
+ theme: blue-theme
+ autologin: false
+ autologout: "0"
+ refresh: "30"
+ rows_per_page: "200"
+ after_login_url: ""
+ user_medias:
+ - mediatype: Email
+ sendto: example@example.com
+ period: 1-7,00:00-24:00
+ severity:
+ not_classified: false
+ information: true
+ warning: true
+ average: true
+ high: true
+ disaster: true
+ active: false
+ role_name: Super admin role
+ timezone: Asia/Tokyo
+ state: present
+ register: create_zabbix_user_result
- - assert:
- that:
- - create_zabbix_user_result.changed is sameas true
+- ansible.builtin.assert:
+ that:
+ - create_zabbix_user_result.changed is sameas true
- - name: test - Set definition_of_results variable of Zabbix 5.4 and higher
- set_fact:
- definition_of_results:
- - get_user_info_result[user_info_key].alias == "example"
- - get_user_info_result[user_info_key].autologin is defined
- - get_user_info_result[user_info_key].autologout is defined
- - get_user_info_result[user_info_key].lang is defined
- - get_user_info_result[user_info_key].medias.0.active is defined
- - get_user_info_result[user_info_key].medias.0.mediaid is defined
- - get_user_info_result[user_info_key].medias.0.period is defined
- - get_user_info_result[user_info_key].medias.0.sendto is defined
- - get_user_info_result[user_info_key].medias.0.severity is defined
- - get_user_info_result[user_info_key].medias.0.userid is defined
- - get_user_info_result[user_info_key].name is defined
- - get_user_info_result[user_info_key].refresh is defined
- - get_user_info_result[user_info_key].rows_per_page is defined
- - get_user_info_result[user_info_key].surname is defined
- - get_user_info_result[user_info_key].theme is defined
- - get_user_info_result[user_info_key].roleid is defined
- - get_user_info_result[user_info_key].url is defined
- - get_user_info_result[user_info_key].userid is defined
- - get_user_info_result[user_info_key].users_status is defined
- - get_user_info_result[user_info_key].timezone is defined
- - get_user_info_result[user_info_key].usrgrps | length == 2
- - get_user_info_result[user_info_key].usrgrps.0.debug_mode is defined
- - get_user_info_result[user_info_key].usrgrps.0.gui_access is defined
- - get_user_info_result[user_info_key].usrgrps.0.name is defined
- - get_user_info_result[user_info_key].usrgrps.0.users_status is defined
- - get_user_info_result[user_info_key].usrgrps.0.usrgrpid is defined
- - get_user_info_result[user_info_key].usrgrps.1.debug_mode is defined
- - get_user_info_result[user_info_key].usrgrps.1.gui_access is defined
- - get_user_info_result[user_info_key].usrgrps.1.name is defined
- - get_user_info_result[user_info_key].usrgrps.1.users_status is defined
- - get_user_info_result[user_info_key].usrgrps.1.usrgrpid is defined
+- name: test - Set definition_of_results variable
+ ansible.builtin.set_fact:
+ definition_of_results:
+ - get_user_info_result[user_info_key].username == "example"
+ - get_user_info_result[user_info_key].autologin is defined
+ - get_user_info_result[user_info_key].autologout is defined
+ - get_user_info_result[user_info_key].lang is defined
+ - get_user_info_result[user_info_key].medias.0.active is defined
+ - get_user_info_result[user_info_key].medias.0.mediaid is defined
+ - get_user_info_result[user_info_key].medias.0.period is defined
+ - get_user_info_result[user_info_key].medias.0.sendto is defined
+ - get_user_info_result[user_info_key].medias.0.severity is defined
+ - get_user_info_result[user_info_key].medias.0.userid is defined
+ - get_user_info_result[user_info_key].name is defined
+ - get_user_info_result[user_info_key].refresh is defined
+ - get_user_info_result[user_info_key].rows_per_page is defined
+ - get_user_info_result[user_info_key].surname is defined
+ - get_user_info_result[user_info_key].theme is defined
+ - get_user_info_result[user_info_key].roleid is defined
+ - get_user_info_result[user_info_key].url is defined
+ - get_user_info_result[user_info_key].userid is defined
+ - get_user_info_result[user_info_key].users_status is defined
+ - get_user_info_result[user_info_key].timezone is defined
+ - get_user_info_result[user_info_key].usrgrps | length == 2
+ - get_user_info_result[user_info_key].usrgrps.0.debug_mode is defined
+ - get_user_info_result[user_info_key].usrgrps.0.gui_access is defined
+ - get_user_info_result[user_info_key].usrgrps.0.name is defined
+ - get_user_info_result[user_info_key].usrgrps.0.users_status is defined
+ - get_user_info_result[user_info_key].usrgrps.0.usrgrpid is defined
+ - get_user_info_result[user_info_key].usrgrps.1.debug_mode is defined
+ - get_user_info_result[user_info_key].usrgrps.1.gui_access is defined
+ - get_user_info_result[user_info_key].usrgrps.1.name is defined
+ - get_user_info_result[user_info_key].usrgrps.1.users_status is defined
+ - get_user_info_result[user_info_key].usrgrps.1.usrgrpid is defined
- name: "test - Get a zabbix user information"
- zabbix_user_info:
- alias: example
+ community.zabbix.zabbix_user_info:
+ username: example
register: get_user_info_result
- name: "test - Set key to user_info_key variable(This deals with the key being masked)"
- set_fact:
+ ansible.builtin.set_fact:
user_info_key: "{{ item }}"
loop: "{{ get_user_info_result.keys() | list }}"
when:
- item | regex_search('_user')
-- assert:
+- ansible.builtin.assert:
that: definition_of_results
-
- name: test - Create a new Zabbix user
- zabbix_user:
- alias: example2
+ community.zabbix.zabbix_user:
+ username: example2
usrgrps:
- Guests
- Disabled
@@ -172,28 +96,22 @@
state: present
register: create_zabbix_user_result2
-- assert:
+- ansible.builtin.assert:
that:
- create_zabbix_user_result2.changed is sameas true
- name: "test - Get a zabbix user information"
- zabbix_user_info:
- alias: example2
+ community.zabbix.zabbix_user_info:
+ username: example2
register: get_user_info_result2
- name: "test - Set key to user_info_key variable(This deals with the key being masked)"
- set_fact:
+ ansible.builtin.set_fact:
user_info_key: "{{ item }}"
loop: "{{ get_user_info_result2.keys() | list }}"
when:
- item | regex_search('_user')
-- assert:
- that:
- - get_user_info_result2[user_info_key].alias == "example2"
- when: zabbix_version is version('5.4', '<')
-
-- assert:
+- ansible.builtin.assert:
that:
- get_user_info_result2[user_info_key].username == "example2"
- when: zabbix_version is version('5.4', '>=')
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_role/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_role/tasks/main.yml
index 799bef30b..53e57a043 100644
--- a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_role/tasks/main.yml
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_user_role/tasks/main.yml
@@ -1,106 +1,103 @@
---
-# New user role create test from here, only 6.0 and higher
-- when: zabbix_version is version('6.0', '>=')
- block:
- - name: test - Create a new Zabbix role
- zabbix_user_role:
- state: present
- name: Operators
- type: User
- rules:
- ui.default_access: 0
- ui:
- - name: "monitoring.hosts"
- status: 0
- - name: "monitoring.maps"
- status: 1
- register: create_zabbix_user_role_result
+- name: test - Create a new Zabbix role
+ community.zabbix.zabbix_user_role:
+ state: present
+ name: Operators
+ type: User
+ rules:
+ ui.default_access: 0
+ ui:
+ - name: "monitoring.hosts"
+ status: 0
+ - name: "monitoring.maps"
+ status: 1
+ register: create_zabbix_user_role_result
- - assert:
- that:
- - create_zabbix_user_role_result.changed is sameas true
+- ansible.builtin.assert:
+ that:
+ - create_zabbix_user_role_result.changed is sameas true
- # Check user role idempotency
- - name: test - Update a Zabbix role with same rules
- zabbix_user_role:
- state: present
- name: Operators
- type: User
- rules:
- ui.default_access: 0
- ui:
- - name: "monitoring.hosts"
- status: 0
- - name: "monitoring.maps"
- status: 1
- register: create_zabbix_user_role_result
+# Check user role idempotency
+- name: test - Update a Zabbix role with same rules
+ community.zabbix.zabbix_user_role:
+ state: present
+ name: Operators
+ type: User
+ rules:
+ ui.default_access: 0
+ ui:
+ - name: "monitoring.hosts"
+ status: 0
+ - name: "monitoring.maps"
+ status: 1
+ register: create_zabbix_user_role_result
- - assert:
- that:
- - create_zabbix_user_role_result.changed is sameas false
+- ansible.builtin.assert:
+ that:
+ - create_zabbix_user_role_result.changed is sameas false
- # Check user role change
- - name: test - Update a Zabbix role with new rules
- zabbix_user_role:
- state: present
- name: Operators
- type: User
- rules:
- ui.default_access: 0
- ui:
- - name: "monitoring.hosts"
- status: 1
- - name: "monitoring.maps"
- status: 0
- register: create_zabbix_user_role_result
+# Check user role change
+- name: test - Update a Zabbix role with new rules
+ community.zabbix.zabbix_user_role:
+ state: present
+ name: Operators
+ type: User
+ rules:
+ ui.default_access: 0
+ ui:
+ - name: "monitoring.hosts"
+ status: 1
+ - name: "monitoring.maps"
+ status: 0
+ register: create_zabbix_user_role_result
- - assert:
- that:
- - create_zabbix_user_role_result.changed is sameas true
+- ansible.builtin.assert:
+ that:
+ - create_zabbix_user_role_result.changed is sameas true
- # Check user role remove
- - name: test - Remove Zabbix role
- zabbix_user_role:
- state: absent
- name: Operators
- register: create_zabbix_user_role_result
+# Check user role remove
+- name: test - Remove Zabbix role
+ community.zabbix.zabbix_user_role:
+ state: absent
+ name: Operators
+ register: create_zabbix_user_role_result
- - assert:
- that:
- - create_zabbix_user_role_result.changed is sameas true
+- ansible.builtin.assert:
+ that:
+ - create_zabbix_user_role_result.changed is sameas true
- - name: test - Create a new Zabbix role type Admin
- zabbix_user_role:
- state: present
- name: Admins
- type: Admin
- rules:
- ui.default_access: 0
- register: create_zabbix_user_role_admin_result
+- name: test - Create a new Zabbix role type Admin
+ community.zabbix.zabbix_user_role:
+ state: present
+ name: Admins
+ type: Admin
+ rules:
+ ui.default_access: 0
+ register: create_zabbix_user_role_admin_result
- - assert:
- that:
- - create_zabbix_user_role_admin_result.changed is sameas true
+- ansible.builtin.assert:
+ that:
+ - create_zabbix_user_role_admin_result.changed is sameas true
- - name: test - Remove Zabbix role type Admin
- zabbix_user_role:
- state: absent
- name: Admins
+- name: test - Remove Zabbix role type Admin
+ community.zabbix.zabbix_user_role:
+ state: absent
+ name: Admins
- - name: test - Create a new Zabbix role type Super Admin
- zabbix_user_role:
- state: present
- name: Super Admins
- type: Super Admin
- rules:
- ui.default_access: 0
- register: create_zabbix_user_role_super_admin_result
+- name: test - Create a new Zabbix role type Super Admin
+ community.zabbix.zabbix_user_role:
+ state: present
+ name: Super Admins
+ type: Super Admin
+ rules:
+ ui.default_access: 0
+ register: create_zabbix_user_role_super_admin_result
- - assert:
- that:
- - create_zabbix_user_role_super_admin_result.changed is sameas true
+- ansible.builtin.assert:
+ that:
+ - create_zabbix_user_role_super_admin_result.changed is sameas true
- - name: test - Remove Zabbix role type Super Admin
- zabbix_user_role:
- state: absent
- name: Super Admins
+- name: test - Remove Zabbix role type Super Admin
+ community.zabbix.zabbix_user_role:
+ state: absent
+ name: Super Admins
diff --git a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_usergroup/tasks/main.yml b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_usergroup/tasks/main.yml
index f7a6aa60e..d1922315b 100644
--- a/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_usergroup/tasks/main.yml
+++ b/ansible_collections/community/zabbix/tests/integration/targets/test_zabbix_usergroup/tasks/main.yml
@@ -1,278 +1,273 @@
---
-- name: test - do not run tests for Zabbix 3.0
- meta: end_play
- when: zabbix_version is version('3.0', '=')
-
- name: test - Zabbix user group
module_defaults:
community.zabbix.zabbix_usergroup:
name: ACME
block:
- - name: test - create new Zabbix user group
- zabbix_usergroup:
- state: present
- register: usergroup_new
-
- - name: assert that user group was created
- assert:
- that: usergroup_new is changed
-
- - name: test - create new Zabbix user group (again)
- zabbix_usergroup:
- state: present
- register: usergroup_again
-
- - name: assert that user group was created
- assert:
- that: not usergroup_again is changed
-
- - name: test - update Zabbix user group with disabled gui_access
- zabbix_usergroup:
- gui_access: disable
- register: usergroup_updated
-
- - name: assert that user group was updated
- assert:
- that: usergroup_updated is changed
-
- - name: test - update Zabbix user group with disabled gui_access (again)
- zabbix_usergroup:
- gui_access: disable
- register: usergroup_updated_again
-
- - name: assert that user group was updated
- assert:
- that: not usergroup_updated_again is changed
-
- - name: test - reset Zabbix user group to default
- zabbix_usergroup:
- register: usergroup_reset
-
- - name: assert that user group was created
- assert:
- that: usergroup_reset is changed
-
- - when: zabbix_version is version('6.2', '<')
- block:
- - name: test - update Zabbix user group with one right
- zabbix_usergroup:
- rights:
- - host_group: Discovered hosts
- permission: read-only
- register: usergroup_updated_right
+ - name: test - create new Zabbix user group
+ community.zabbix.zabbix_usergroup:
+ state: present
+ register: usergroup_new
- - name: assert that user group was updated
- assert:
- that: usergroup_updated_right is changed
+ - name: assert that user group was created
+ ansible.builtin.assert:
+ that: usergroup_new is changed
- - name: test - update Zabbix user group with multiple rights
- zabbix_usergroup:
- rights:
- - host_group: Discovered hosts
- permission: read-only
- - host_group: Zabbix servers
- permission: read-write
- register: usergroup_updated_rights
+ - name: test - create new Zabbix user group (again)
+ community.zabbix.zabbix_usergroup:
+ state: present
+ register: usergroup_again
- - name: assert that user group was updated
- assert:
- that: usergroup_updated_rights is changed
+ - name: assert that user group was created
+ ansible.builtin.assert:
+ that: not usergroup_again is changed
- - name: test - update Zabbix user group with multiple rights (again)
- zabbix_usergroup:
- rights:
- - host_group: Discovered hosts
- permission: read-only
- - host_group: Zabbix servers
- permission: read-write
- register: usergroup_updated_rights_again
-
- - name: assert that user group was not updated
- assert:
- that: not usergroup_updated_rights_again is changed
-
- - when: zabbix_version is version('6.2', '>=')
- block:
- - name: test - update Zabbix user group with one hostgroup right
- zabbix_usergroup:
- hostgroup_rights:
- - host_group: Discovered hosts
- permission: read-only
- register: usergroup_updated_hostgroup_right
+ - name: test - update Zabbix user group with disabled gui_access
+ community.zabbix.zabbix_usergroup:
+ gui_access: disable
+ register: usergroup_updated
- name: assert that user group was updated
- assert:
- that: usergroup_updated_hostgroup_right is changed
+ ansible.builtin.assert:
+ that: usergroup_updated is changed
- - name: test - update Zabbix user group with multiple hostgroup rights
- zabbix_usergroup:
- hostgroup_rights:
- - host_group: Discovered hosts
- permission: read-only
- - host_group: Zabbix servers
- permission: read-write
- register: usergroup_updated_hostgroup_rights
+ - name: test - update Zabbix user group with disabled gui_access (again)
+ community.zabbix.zabbix_usergroup:
+ gui_access: disable
+ register: usergroup_updated_again
- name: assert that user group was updated
- assert:
- that: usergroup_updated_hostgroup_rights is changed
-
- - name: test - update Zabbix user group with multiple hostgroup rights (again)
- zabbix_usergroup:
- hostgroup_rights:
- - host_group: Discovered hosts
- permission: read-only
- - host_group: Zabbix servers
- permission: read-write
- register: usergroup_updated_hostgroup_rights_again
-
- - name: assert that user group was not updated
- assert:
- that: not usergroup_updated_hostgroup_rights_again is changed
-
- - name: test - update Zabbix user group with one template group right
- zabbix_usergroup:
- hostgroup_rights:
+ ansible.builtin.assert:
+ that: not usergroup_updated_again is changed
+
+ - name: test - reset Zabbix user group to default
+ community.zabbix.zabbix_usergroup:
+ register: usergroup_reset
+
+ - name: assert that user group was created
+ ansible.builtin.assert:
+ that: usergroup_reset is changed
+
+ - when: zabbix_version is version('6.2', '<')
+ block:
+ - name: test - update Zabbix user group with one right
+ community.zabbix.zabbix_usergroup:
+ rights:
+ - host_group: Discovered hosts
+ permission: read-only
+ register: usergroup_updated_right
+
+ - name: assert that user group was updated
+ ansible.builtin.assert:
+ that: usergroup_updated_right is changed
+
+ - name: test - update Zabbix user group with multiple rights
+ community.zabbix.zabbix_usergroup:
+ rights:
+ - host_group: Discovered hosts
+ permission: read-only
+ - host_group: Zabbix servers
+ permission: read-write
+ register: usergroup_updated_rights
+
+ - name: assert that user group was updated
+ ansible.builtin.assert:
+ that: usergroup_updated_rights is changed
+
+ - name: test - update Zabbix user group with multiple rights (again)
+ community.zabbix.zabbix_usergroup:
+ rights:
+ - host_group: Discovered hosts
+ permission: read-only
+ - host_group: Zabbix servers
+ permission: read-write
+ register: usergroup_updated_rights_again
+
+ - name: assert that user group was not updated
+ ansible.builtin.assert:
+ that: not usergroup_updated_rights_again is changed
+
+ - when: zabbix_version is version('6.2', '>=')
+ block:
+ - name: test - update Zabbix user group with one hostgroup right
+ community.zabbix.zabbix_usergroup:
+ hostgroup_rights:
+ - host_group: Discovered hosts
+ permission: read-only
+ register: usergroup_updated_hostgroup_right
+
+ - name: assert that user group was updated
+ ansible.builtin.assert:
+ that: usergroup_updated_hostgroup_right is changed
+
+ - name: test - update Zabbix user group with multiple hostgroup rights
+ community.zabbix.zabbix_usergroup:
+ hostgroup_rights:
+ - host_group: Discovered hosts
+ permission: read-only
+ - host_group: Zabbix servers
+ permission: read-write
+ register: usergroup_updated_hostgroup_rights
+
+ - name: assert that user group was updated
+ ansible.builtin.assert:
+ that: usergroup_updated_hostgroup_rights is changed
+
+ - name: test - update Zabbix user group with multiple hostgroup rights (again)
+ community.zabbix.zabbix_usergroup:
+ hostgroup_rights:
+ - host_group: Discovered hosts
+ permission: read-only
+ - host_group: Zabbix servers
+ permission: read-write
+ register: usergroup_updated_hostgroup_rights_again
+
+ - name: assert that user group was not updated
+ ansible.builtin.assert:
+ that: not usergroup_updated_hostgroup_rights_again is changed
+
+ - name: test - update Zabbix user group with one template group right
+ community.zabbix.zabbix_usergroup:
+ hostgroup_rights:
+ - host_group: Discovered hosts
+ permission: read-only
+ - host_group: Zabbix servers
+ permission: read-write
+ templategroup_rights:
+ - template_group: Templates
+ permission: read-only
+ register: usergroup_updated_templategroup_right
+
+ - name: assert that user group was updated
+ ansible.builtin.assert:
+ that: usergroup_updated_templategroup_right is changed
+
+ - name: test - update Zabbix user group with multiple template group rights
+ community.zabbix.zabbix_usergroup:
+ hostgroup_rights:
+ - host_group: Discovered hosts
+ permission: read-only
+ - host_group: Zabbix servers
+ permission: read-write
+ templategroup_rights:
+ - template_group: Templates
+ permission: read-only
+ - template_group: Templates/Applications
+ permission: read-write
+ register: usergroup_updated_templategroup_rights
+
+ - name: assert that user group was updated
+ ansible.builtin.assert:
+ that: usergroup_updated_templategroup_right is changed
+
+ - name: test - update Zabbix user group with multiple template group rights (again)
+ community.zabbix.zabbix_usergroup:
+ hostgroup_rights:
+ - host_group: Discovered hosts
+ permission: read-only
+ - host_group: Zabbix servers
+ permission: read-write
+ templategroup_rights:
+ - template_group: Templates
+ permission: read-only
+ - template_group: Templates/Applications
+ permission: read-write
+ register: usergroup_updated_templategroup_rights_again
+
+ - name: assert that user group was not updated
+ ansible.builtin.assert:
+ that: not usergroup_updated_templategroup_rights_again is changed
+
+ - name: test - reset Zabbix user group to default
+ community.zabbix.zabbix_usergroup:
+ register: usergroup_reset
+
+ - name: assert that user group was created
+ ansible.builtin.assert:
+ that: usergroup_reset is changed
+
+ - name: test - update Zabbix user group with one tag_filter
+ community.zabbix.zabbix_usergroup:
+ tag_filters:
- host_group: Discovered hosts
- permission: read-only
- - host_group: Zabbix servers
- permission: read-write
- templategroup_rights:
- - template_group: Templates
- permission: read-only
- register: usergroup_updated_templategroup_right
+ tag: Service
+ value: JIRA
+ register: usergroup_updated_tag_filter
- name: assert that user group was updated
- assert:
- that: usergroup_updated_templategroup_right is changed
+ ansible.builtin.assert:
+ that: usergroup_updated_tag_filter is changed
- - name: test - update Zabbix user group with multiple template group rights
- zabbix_usergroup:
- hostgroup_rights:
+ - name: test - update Zabbix user group with multiple tag_filters
+ community.zabbix.zabbix_usergroup:
+ tag_filters:
- host_group: Discovered hosts
- permission: read-only
- - host_group: Zabbix servers
- permission: read-write
- templategroup_rights:
- - template_group: Templates
- permission: read-only
- - template_group: Templates/Applications
- permission: read-write
- register: usergroup_updated_templategroup_rights
-
- - name: assert that user group was updated
- assert:
- that: usergroup_updated_templategroup_right is changed
-
- - name: test - update Zabbix user group with multiple template group rights (again)
- zabbix_usergroup:
- hostgroup_rights:
+ tag: Service
+ value: JIRA
- host_group: Discovered hosts
- permission: read-only
- - host_group: Zabbix servers
- permission: read-write
- templategroup_rights:
- - template_group: Templates
- permission: read-only
- - template_group: Templates/Applications
- permission: read-write
- register: usergroup_updated_templategroup_rights_again
-
- - name: assert that user group was not updated
- assert:
- that: not usergroup_updated_templategroup_rights_again is changed
-
- - name: test - reset Zabbix user group to default
- zabbix_usergroup:
- register: usergroup_reset
-
- - name: assert that user group was created
- assert:
- that: usergroup_reset is changed
-
- - name: test - update Zabbix user group with one tag_filter
- zabbix_usergroup:
- tag_filters:
- - host_group: Discovered hosts
- tag: Service
- value: JIRA
- register: usergroup_updated_tag_filter
-
- - name: assert that user group was updated
- assert:
- that: usergroup_updated_tag_filter is changed
-
- - name: test - update Zabbix user group with multiple tag_filters
- zabbix_usergroup:
- tag_filters:
- - host_group: Discovered hosts
- tag: Service
- value: JIRA
- - host_group: Discovered hosts
- tag: Service
- value: Zabbix
- register: usergroup_updated_tag_filters
-
- - name: assert that user group was updated
- assert:
- that: usergroup_updated_tag_filters is changed
-
- - name: test - reset Zabbix user group to default
- zabbix_usergroup:
-
- - when: zabbix_version is version('6.2', '>=')
- block:
- - name: test - create new user directory
- zabbix_user_directory:
- name: LDAP infra 1
- host: 'test.com'
- port: 389
- base_dn: 'ou=Users,dc=example,dc=org'
- search_attribute: 'uid'
- when: zabbix_version is version('6.4', '<')
-
- - name: test - create new user directory
- zabbix_user_directory:
- name: LDAP infra 1
- idp_type: ldap
- host: 'test.com'
- port: 389
- base_dn: 'ou=Users,dc=example,dc=org'
- search_attribute: 'uid'
- when: zabbix_version is version('6.4', '>=')
-
- - name: test - update Zabbix user group with user directory
- zabbix_usergroup:
- userdirectory: LDAP infra 1
- register: usergroup_create_userdir
+ tag: Service
+ value: Zabbix
+ register: usergroup_updated_tag_filters
- name: assert that user group was updated
- assert:
- that: usergroup_create_userdir is changed
-
- - name: test - update Zabbix user group with user directory (again)
- zabbix_usergroup:
- userdirectory: LDAP infra 1
- register: usergroup_create_userdir_again
-
- - name: assert that user group was not updated
- assert:
- that: not usergroup_create_userdir_again is changed
-
- - name: test - delete Zabbix user group
- zabbix_usergroup:
- state: absent
- register: usergroup_delete
-
- - name: assert that Zabbix user group has been deleted
- assert:
- that: usergroup_delete is changed
-
-
- - name: test - delete user directory
- zabbix_user_directory:
- name: LDAP infra 1
- host: 'test.com'
- state: absent
- when: zabbix_version is version('6.2', '>=')
+ ansible.builtin.assert:
+ that: usergroup_updated_tag_filters is changed
+
+ - name: test - reset Zabbix user group to default
+ community.zabbix.zabbix_usergroup:
+
+ - when: zabbix_version is version('6.2', '>=')
+ block:
+ - name: test - create new user directory
+ community.zabbix.zabbix_user_directory:
+ name: LDAP infra 1
+ host: "test.com"
+ port: 389
+ base_dn: "ou=Users,dc=example,dc=org"
+ search_attribute: "uid"
+ when: zabbix_version is version('6.4', '<')
+
+ - name: test - create new user directory
+ community.zabbix.zabbix_user_directory:
+ name: LDAP infra 1
+ idp_type: ldap
+ host: "test.com"
+ port: 389
+ base_dn: "ou=Users,dc=example,dc=org"
+ search_attribute: "uid"
+ when: zabbix_version is version('6.4', '>=')
+
+ - name: test - update Zabbix user group with user directory
+ community.zabbix.zabbix_usergroup:
+ userdirectory: LDAP infra 1
+ register: usergroup_create_userdir
+
+ - name: assert that user group was updated
+ ansible.builtin.assert:
+ that: usergroup_create_userdir is changed
+
+ - name: test - update Zabbix user group with user directory (again)
+ community.zabbix.zabbix_usergroup:
+ userdirectory: LDAP infra 1
+ register: usergroup_create_userdir_again
+
+ - name: assert that user group was not updated
+ ansible.builtin.assert:
+ that: not usergroup_create_userdir_again is changed
+
+ - name: test - delete Zabbix user group
+ community.zabbix.zabbix_usergroup:
+ state: absent
+ register: usergroup_delete
+
+ - name: assert that Zabbix user group has been deleted
+ ansible.builtin.assert:
+ that: usergroup_delete is changed
+
+ - name: test - delete user directory
+ community.zabbix.zabbix_user_directory:
+ name: LDAP infra 1
+ host: "test.com"
+ state: absent
+ when: zabbix_version is version('6.2', '>=')
diff --git a/ansible_collections/community/zabbix/tests/sanity/ignore-2.10.txt b/ansible_collections/community/zabbix/tests/sanity/ignore-2.10.txt
deleted file mode 100644
index 8854fcd2d..000000000
--- a/ansible_collections/community/zabbix/tests/sanity/ignore-2.10.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-scripts/inventory/zabbix.py future-import-boilerplate
-scripts/inventory/zabbix.py metaclass-boilerplate
-plugins/modules/zabbix_action.py validate-modules:doc-choices-do-not-match-spec
-plugins/modules/zabbix_action.py validate-modules:doc-default-does-not-match-spec
-plugins/modules/zabbix_action.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_action.py validate-modules:doc-required-mismatch
-plugins/modules/zabbix_action.py validate-modules:invalid-argument-name
-plugins/modules/zabbix_action.py validate-modules:missing-suboption-docs
-plugins/modules/zabbix_action.py validate-modules:nonexistent-parameter-documented
-plugins/modules/zabbix_action.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_action.py validate-modules:parameter-type-not-in-doc
-plugins/modules/zabbix_action.py validate-modules:undocumented-parameter
-plugins/modules/zabbix_group.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_group.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_group_info.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_group_info.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_host.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_host.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_host_info.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_host_info.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_maintenance.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_maintenance.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_mediatype.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_mediatype.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_template.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_template.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_user.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_user.py validate-modules:parameter-list-no-elements
-plugins/doc_fragments/zabbix.py future-import-boilerplate
-plugins/doc_fragments/zabbix.py metaclass-boilerplate
-roles/zabbix_agent/molecule/with-server/tests/test_agent.py future-import-boilerplate
-roles/zabbix_agent/molecule/with-server/tests/test_default.py future-import-boilerplate
-roles/zabbix_agent/molecule/with-server/tests/test_agent.py metaclass-boilerplate
-roles/zabbix_agent/molecule/with-server/tests/test_default.py metaclass-boilerplate \ No newline at end of file
diff --git a/ansible_collections/community/zabbix/tests/sanity/ignore-2.11.txt b/ansible_collections/community/zabbix/tests/sanity/ignore-2.11.txt
deleted file mode 100644
index 8854fcd2d..000000000
--- a/ansible_collections/community/zabbix/tests/sanity/ignore-2.11.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-scripts/inventory/zabbix.py future-import-boilerplate
-scripts/inventory/zabbix.py metaclass-boilerplate
-plugins/modules/zabbix_action.py validate-modules:doc-choices-do-not-match-spec
-plugins/modules/zabbix_action.py validate-modules:doc-default-does-not-match-spec
-plugins/modules/zabbix_action.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_action.py validate-modules:doc-required-mismatch
-plugins/modules/zabbix_action.py validate-modules:invalid-argument-name
-plugins/modules/zabbix_action.py validate-modules:missing-suboption-docs
-plugins/modules/zabbix_action.py validate-modules:nonexistent-parameter-documented
-plugins/modules/zabbix_action.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_action.py validate-modules:parameter-type-not-in-doc
-plugins/modules/zabbix_action.py validate-modules:undocumented-parameter
-plugins/modules/zabbix_group.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_group.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_group_info.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_group_info.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_host.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_host.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_host_info.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_host_info.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_maintenance.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_maintenance.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_mediatype.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_mediatype.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_template.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_template.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_user.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_user.py validate-modules:parameter-list-no-elements
-plugins/doc_fragments/zabbix.py future-import-boilerplate
-plugins/doc_fragments/zabbix.py metaclass-boilerplate
-roles/zabbix_agent/molecule/with-server/tests/test_agent.py future-import-boilerplate
-roles/zabbix_agent/molecule/with-server/tests/test_default.py future-import-boilerplate
-roles/zabbix_agent/molecule/with-server/tests/test_agent.py metaclass-boilerplate
-roles/zabbix_agent/molecule/with-server/tests/test_default.py metaclass-boilerplate \ No newline at end of file
diff --git a/ansible_collections/community/zabbix/tests/sanity/ignore-2.12.txt b/ansible_collections/community/zabbix/tests/sanity/ignore-2.12.txt
deleted file mode 100644
index 628f32ff1..000000000
--- a/ansible_collections/community/zabbix/tests/sanity/ignore-2.12.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-plugins/modules/zabbix_action.py validate-modules:doc-choices-do-not-match-spec
-plugins/modules/zabbix_action.py validate-modules:doc-default-does-not-match-spec
-plugins/modules/zabbix_action.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_action.py validate-modules:doc-required-mismatch
-plugins/modules/zabbix_action.py validate-modules:invalid-argument-name
-plugins/modules/zabbix_action.py validate-modules:missing-suboption-docs
-plugins/modules/zabbix_action.py validate-modules:nonexistent-parameter-documented
-plugins/modules/zabbix_action.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_action.py validate-modules:parameter-type-not-in-doc
-plugins/modules/zabbix_action.py validate-modules:undocumented-parameter
-plugins/modules/zabbix_group.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_group.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_group_info.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_group_info.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_host.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_host.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_host_info.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_host_info.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_maintenance.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_maintenance.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_mediatype.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_mediatype.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_template.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_template.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_user.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_user.py validate-modules:parameter-list-no-elements \ No newline at end of file
diff --git a/ansible_collections/community/zabbix/tests/sanity/ignore-2.13.txt b/ansible_collections/community/zabbix/tests/sanity/ignore-2.13.txt
deleted file mode 100644
index 628f32ff1..000000000
--- a/ansible_collections/community/zabbix/tests/sanity/ignore-2.13.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-plugins/modules/zabbix_action.py validate-modules:doc-choices-do-not-match-spec
-plugins/modules/zabbix_action.py validate-modules:doc-default-does-not-match-spec
-plugins/modules/zabbix_action.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_action.py validate-modules:doc-required-mismatch
-plugins/modules/zabbix_action.py validate-modules:invalid-argument-name
-plugins/modules/zabbix_action.py validate-modules:missing-suboption-docs
-plugins/modules/zabbix_action.py validate-modules:nonexistent-parameter-documented
-plugins/modules/zabbix_action.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_action.py validate-modules:parameter-type-not-in-doc
-plugins/modules/zabbix_action.py validate-modules:undocumented-parameter
-plugins/modules/zabbix_group.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_group.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_group_info.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_group_info.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_host.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_host.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_host_info.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_host_info.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_maintenance.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_maintenance.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_mediatype.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_mediatype.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_template.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_template.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_user.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_user.py validate-modules:parameter-list-no-elements \ No newline at end of file
diff --git a/ansible_collections/community/zabbix/tests/sanity/ignore-2.14.txt b/ansible_collections/community/zabbix/tests/sanity/ignore-2.14.txt
deleted file mode 100644
index 628f32ff1..000000000
--- a/ansible_collections/community/zabbix/tests/sanity/ignore-2.14.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-plugins/modules/zabbix_action.py validate-modules:doc-choices-do-not-match-spec
-plugins/modules/zabbix_action.py validate-modules:doc-default-does-not-match-spec
-plugins/modules/zabbix_action.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_action.py validate-modules:doc-required-mismatch
-plugins/modules/zabbix_action.py validate-modules:invalid-argument-name
-plugins/modules/zabbix_action.py validate-modules:missing-suboption-docs
-plugins/modules/zabbix_action.py validate-modules:nonexistent-parameter-documented
-plugins/modules/zabbix_action.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_action.py validate-modules:parameter-type-not-in-doc
-plugins/modules/zabbix_action.py validate-modules:undocumented-parameter
-plugins/modules/zabbix_group.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_group.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_group_info.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_group_info.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_host.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_host.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_host_info.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_host_info.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_maintenance.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_maintenance.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_mediatype.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_mediatype.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_template.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_template.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_user.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_user.py validate-modules:parameter-list-no-elements \ No newline at end of file
diff --git a/ansible_collections/community/zabbix/tests/sanity/ignore-2.15.txt b/ansible_collections/community/zabbix/tests/sanity/ignore-2.15.txt
deleted file mode 100644
index 628f32ff1..000000000
--- a/ansible_collections/community/zabbix/tests/sanity/ignore-2.15.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-plugins/modules/zabbix_action.py validate-modules:doc-choices-do-not-match-spec
-plugins/modules/zabbix_action.py validate-modules:doc-default-does-not-match-spec
-plugins/modules/zabbix_action.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_action.py validate-modules:doc-required-mismatch
-plugins/modules/zabbix_action.py validate-modules:invalid-argument-name
-plugins/modules/zabbix_action.py validate-modules:missing-suboption-docs
-plugins/modules/zabbix_action.py validate-modules:nonexistent-parameter-documented
-plugins/modules/zabbix_action.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_action.py validate-modules:parameter-type-not-in-doc
-plugins/modules/zabbix_action.py validate-modules:undocumented-parameter
-plugins/modules/zabbix_group.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_group.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_group_info.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_group_info.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_host.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_host.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_host_info.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_host_info.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_maintenance.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_maintenance.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_mediatype.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_mediatype.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_template.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_template.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_user.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_user.py validate-modules:parameter-list-no-elements \ No newline at end of file
diff --git a/ansible_collections/community/zabbix/tests/sanity/ignore-2.9.txt b/ansible_collections/community/zabbix/tests/sanity/ignore-2.9.txt
deleted file mode 100644
index 0b5abb56b..000000000
--- a/ansible_collections/community/zabbix/tests/sanity/ignore-2.9.txt
+++ /dev/null
@@ -1,30 +0,0 @@
-scripts/inventory/zabbix.py future-import-boilerplate
-scripts/inventory/zabbix.py metaclass-boilerplate
-plugins/modules/zabbix_action.py validate-modules:doc-choices-do-not-match-spec
-plugins/modules/zabbix_action.py validate-modules:doc-default-does-not-match-spec
-plugins/modules/zabbix_action.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_action.py validate-modules:doc-required-mismatch
-plugins/modules/zabbix_action.py validate-modules:invalid-argument-name
-plugins/modules/zabbix_action.py validate-modules:missing-suboption-docs
-plugins/modules/zabbix_action.py validate-modules:nonexistent-parameter-documented
-plugins/modules/zabbix_action.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_action.py validate-modules:parameter-type-not-in-doc
-plugins/modules/zabbix_action.py validate-modules:undocumented-parameter
-plugins/modules/zabbix_group.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_group.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_group_info.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_group_info.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_host.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_host.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_host_info.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_host_info.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_maintenance.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_maintenance.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_mediatype.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_mediatype.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_template.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_template.py validate-modules:parameter-list-no-elements
-plugins/modules/zabbix_user.py validate-modules:doc-elements-mismatch
-plugins/modules/zabbix_user.py validate-modules:parameter-list-no-elements
-plugins/doc_fragments/zabbix.py future-import-boilerplate
-plugins/doc_fragments/zabbix.py metaclass-boilerplate \ No newline at end of file